[hibernate-commits] Hibernate SVN: r11563 - in trunk/Hibernate3: cache-ehcache and 438 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Fri May 25 16:19:36 EDT 2007


Author: steve.ebersole at jboss.com
Date: 2007-05-25 16:19:29 -0400 (Fri, 25 May 2007)
New Revision: 11563

Added:
   trunk/Hibernate3/cache-ehcache/
   trunk/Hibernate3/cache-ehcache/pom.xml
   trunk/Hibernate3/cache-ehcache/src/
   trunk/Hibernate3/cache-ehcache/src/main/
   trunk/Hibernate3/cache-ehcache/src/main/java/
   trunk/Hibernate3/cache-ehcache/src/main/java/org/
   trunk/Hibernate3/cache-ehcache/src/main/java/org/hibernate/
   trunk/Hibernate3/cache-ehcache/src/main/java/org/hibernate/cache/
   trunk/Hibernate3/cache-ehcache/src/main/java/org/hibernate/cache/EhCache.java
   trunk/Hibernate3/cache-ehcache/src/main/java/org/hibernate/cache/EhCacheProvider.java
   trunk/Hibernate3/cache-jbosscache/
   trunk/Hibernate3/cache-jbosscache/pom.xml
   trunk/Hibernate3/cache-jbosscache/src/
   trunk/Hibernate3/cache-jbosscache/src/main/
   trunk/Hibernate3/cache-jbosscache/src/main/java/
   trunk/Hibernate3/cache-jbosscache/src/main/java/org/
   trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/
   trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/
   trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/JndiBoundTreeCacheProvider.java
   trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/OptimisticTreeCache.java
   trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/OptimisticTreeCacheProvider.java
   trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/TreeCache.java
   trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/TreeCacheProvider.java
   trunk/Hibernate3/cache-jbosscache2/
   trunk/Hibernate3/cache-jbosscache2/pom.xml
   trunk/Hibernate3/cache-jbosscache2/src/
   trunk/Hibernate3/cache-jbosscache2/src/main/
   trunk/Hibernate3/cache-jbosscache2/src/main/java/
   trunk/Hibernate3/cache-jbosscache2/src/main/resources/
   trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/
   trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/
   trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/cache/
   trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc/
   trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc/TransactionManagerLookupAdaptor.java
   trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc/TreeCacheRegionAdapter.java
   trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc/TreeCacheRegionFactory.java
   trunk/Hibernate3/cache-oscache/
   trunk/Hibernate3/cache-oscache/pom.xml
   trunk/Hibernate3/cache-oscache/src/
   trunk/Hibernate3/cache-oscache/src/main/
   trunk/Hibernate3/cache-oscache/src/main/java/
   trunk/Hibernate3/cache-oscache/src/main/java/org/
   trunk/Hibernate3/cache-oscache/src/main/java/org/hibernate/
   trunk/Hibernate3/cache-oscache/src/main/java/org/hibernate/cache/
   trunk/Hibernate3/cache-oscache/src/main/java/org/hibernate/cache/OSCache.java
   trunk/Hibernate3/cache-oscache/src/main/java/org/hibernate/cache/OSCacheProvider.java
   trunk/Hibernate3/cache-swarmcache/
   trunk/Hibernate3/cache-swarmcache/pom.xml
   trunk/Hibernate3/cache-swarmcache/src/
   trunk/Hibernate3/cache-swarmcache/src/main/
   trunk/Hibernate3/cache-swarmcache/src/main/java/
   trunk/Hibernate3/cache-swarmcache/src/main/java/org/
   trunk/Hibernate3/cache-swarmcache/src/main/java/org/hibernate/
   trunk/Hibernate3/cache-swarmcache/src/main/java/org/hibernate/cache/
   trunk/Hibernate3/cache-swarmcache/src/main/java/org/hibernate/cache/SwarmCache.java
   trunk/Hibernate3/cache-swarmcache/src/main/java/org/hibernate/cache/SwarmCacheProvider.java
   trunk/Hibernate3/connection-c3p0/
   trunk/Hibernate3/connection-c3p0/pom.xml
   trunk/Hibernate3/connection-c3p0/src/
   trunk/Hibernate3/connection-c3p0/src/main/
   trunk/Hibernate3/connection-c3p0/src/main/java/
   trunk/Hibernate3/connection-c3p0/src/main/java/org/
   trunk/Hibernate3/connection-c3p0/src/main/java/org/hibernate/
   trunk/Hibernate3/connection-c3p0/src/main/java/org/hibernate/connection/
   trunk/Hibernate3/connection-c3p0/src/main/java/org/hibernate/connection/C3P0ConnectionProvider.java
   trunk/Hibernate3/connection-proxool/
   trunk/Hibernate3/connection-proxool/pom.xml
   trunk/Hibernate3/connection-proxool/src/
   trunk/Hibernate3/connection-proxool/src/main/
   trunk/Hibernate3/connection-proxool/src/main/java/
   trunk/Hibernate3/connection-proxool/src/main/java/org/
   trunk/Hibernate3/connection-proxool/src/main/java/org/hibernate/
   trunk/Hibernate3/connection-proxool/src/main/java/org/hibernate/connection/
   trunk/Hibernate3/connection-proxool/src/main/java/org/hibernate/connection/ProxoolConnectionProvider.java
   trunk/Hibernate3/core/
   trunk/Hibernate3/core/pom.xml
   trunk/Hibernate3/core/src/
   trunk/Hibernate3/core/src/main/
   trunk/Hibernate3/core/src/main/antlr/
   trunk/Hibernate3/core/src/main/antlr/hql-sql.g
   trunk/Hibernate3/core/src/main/antlr/hql.g
   trunk/Hibernate3/core/src/main/antlr/sql-gen.g
   trunk/Hibernate3/core/src/main/java/
   trunk/Hibernate3/core/src/main/java/org/
   trunk/Hibernate3/core/src/main/java/org/hibernate/
   trunk/Hibernate3/core/src/main/java/org/hibernate/AssertionFailure.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/CacheMode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/CallbackException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/ConnectionReleaseMode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/Criteria.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/DuplicateMappingException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/EmptyInterceptor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/EntityMode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/FetchMode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/Filter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/FlushMode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/Hibernate.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/HibernateException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/InstantiationException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/Interceptor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/InvalidMappingException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/JDBCException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/LazyInitializationException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/LockMode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/MappingException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/MappingNotFoundException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/NonUniqueObjectException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/NonUniqueResultException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/ObjectDeletedException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/ObjectNotFoundException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/PersistentObjectException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/PropertyAccessException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/PropertyNotFoundException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/PropertyValueException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/Query.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/QueryException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/QueryParameterException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/ReplicationMode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/SQLQuery.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/ScrollMode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/ScrollableResults.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/Session.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/SessionException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/SessionFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/StaleObjectStateException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/StaleStateException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/StatelessSession.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/Transaction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/TransactionException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/TransientObjectException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/TypeMismatchException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/UnresolvableObjectException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/WrongClassException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/action/
   trunk/Hibernate3/core/src/main/java/org/hibernate/action/BulkOperationCleanupAction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionAction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionRecreateAction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionRemoveAction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionUpdateAction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/action/DelayedPostInsertIdentifier.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityAction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityDeleteAction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityIdentityInsertAction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityInsertAction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityUpdateAction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/action/Executable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/action/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/AbstractClassTransformerImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/BasicProxyFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/BytecodeProvider.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/ClassTransformer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/InstrumentedClassLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/ProxyFactoryFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/ReflectionOptimizer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/AccessOptimizerAdapter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/CglibClassTransformer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/InstantiationOptimizerAdapter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/ProxyFactoryFactoryImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/ReflectionOptimizerImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/AccessOptimizerAdapter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BulkAccessor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BulkAccessorException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BulkAccessorFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FastClass.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldFilter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldHandled.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldHandler.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldTransformer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/InstantiationOptimizerAdapter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/JavassistClassTransformer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/ProxyFactoryFactoryImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/ReflectionOptimizerImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/TransformingClassLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/BasicClassFilter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/ByteCodeHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/ClassDescriptor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/ClassFilter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/FieldFilter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/AbstractJndiBoundCacheProvider.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/Cache.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheConcurrencyStrategy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheDataDescription.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheKey.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheProvider.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CollectionRegion.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/EntityRegion.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/FilterKey.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/GeneralDataRegion.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/HashtableCache.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/HashtableCacheProvider.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/NoCacheProvider.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/NoCachingEnabledException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/NonstrictReadWriteCache.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/OptimisticCache.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/OptimisticCacheSource.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryCache.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryCacheFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryKey.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryResultsRegion.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/ReadOnlyCache.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/ReadWriteCache.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/Region.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/RegionFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/StandardQueryCache.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/StandardQueryCacheFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/Timestamper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/TimestampsRegion.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/TransactionalCache.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/TransactionalDataRegion.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/UpdateTimestampsCache.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/AccessType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/CollectionRegionAccessStrategy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/EntityRegionAccessStrategy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/SoftLock.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/CacheEntry.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/CacheEntryStructure.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/CollectionCacheEntry.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredCacheEntry.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredCollectionCacheEntry.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredMapCacheEntry.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/UnstructuredCacheEntry.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/CacheDataDescriptionImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/NoCachingRegionFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/BaseGeneralDataRegionAdapter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/BaseRegionAdapter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/BaseTransactionalDataRegionAdapter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/CollectionAccessStrategyAdapter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/CollectionRegionAdapter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/EntityAccessStrategyAdapter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/EntityRegionAdapter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/OptimisticCacheSourceAdapter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/QueryResultsRegionAdapter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/RegionFactoryCacheProviderBridge.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/TimestampsRegionAdapter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cache/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/CollectionSecondPass.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Configuration.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/DefaultNamingStrategy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Environment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ExtendsQueueEntry.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/HbmBinder.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ImprovedNamingStrategy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Mappings.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/NamedSQLQuerySecondPass.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/NamingStrategy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/QuerySecondPass.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ResultSetMappingBinder.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ResultSetMappingSecondPass.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/SecondPass.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Settings.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/SettingsFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/classic/
   trunk/Hibernate3/core/src/main/java/org/hibernate/classic/Lifecycle.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/classic/Session.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/classic/Validatable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/classic/ValidationFailure.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/classic/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/AbstractPersistentCollection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentArrayHolder.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentBag.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentCollection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentElementHolder.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentIdentifierBag.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentIndexedElementHolder.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentList.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentListElementHolder.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentMap.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentMapElementHolder.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentSet.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentSortedMap.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentSortedSet.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/collection/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/connection/
   trunk/Hibernate3/core/src/main/java/org/hibernate/connection/ConnectionProvider.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/connection/ConnectionProviderFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/connection/DatasourceConnectionProvider.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/connection/DriverManagerConnectionProvider.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/connection/UserSuppliedConnectionProvider.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/connection/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/context/
   trunk/Hibernate3/core/src/main/java/org/hibernate/context/CurrentSessionContext.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/context/JTASessionContext.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/context/ManagedSessionContext.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/context/ThreadLocalSessionContext.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AbstractEmptinessExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AggregateProjection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AliasedProjection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AvgProjection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/BetweenExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Conjunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CountProjection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CriteriaQuery.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CriteriaSpecification.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Criterion.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/DetachedCriteria.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Disjunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Distinct.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/EmptyExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Example.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/ExistsSubqueryExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Expression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/IdentifierEqExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/IdentifierProjection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/IlikeExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/InExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Junction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/LikeExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/LogicalExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/MatchMode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NaturalIdentifier.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NotEmptyExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NotExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NotNullExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NullExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Order.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Projection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/ProjectionList.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Projections.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Property.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/PropertyExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/PropertyProjection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/PropertySubqueryExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Restrictions.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/RowCountProjection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SQLCriterion.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SQLProjection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SimpleExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SimpleProjection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SimpleSubqueryExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SizeExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Subqueries.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SubqueryExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Cache71Dialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DB2390Dialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DB2400Dialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DB2Dialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DataDirectOracle9Dialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DerbyDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Dialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DialectFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/FirebirdDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/FrontBaseDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/H2Dialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/HSQLDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/InformixDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/IngresDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/InterbaseDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/JDataStoreDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MckoiDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MimerSQLDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQL5Dialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQL5InnoDBDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQLDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQLInnoDBDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQLMyISAMDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Oracle9Dialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/OracleDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/PointbaseDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/ProgressDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/RDMSOS2200Dialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/ResultColumnReferenceStrategy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SAPDBDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SQLServerDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Sybase11Dialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SybaseAnywhereDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SybaseDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/TeradataDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/TimesTenDialect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/TypeNames.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/AnsiTrimEmulationFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/CastFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/CharIndexFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ClassicAvgFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ClassicCountFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ClassicSumFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ConditionalParenthesisFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ConvertFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/NoArgSQLFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/NvlFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/PositionSubstringFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/SQLFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/SQLFunctionRegistry.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/SQLFunctionTemplate.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/StandardJDBCEscapeFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/StandardSQLFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/VarArgsSQLFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/lock/
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/lock/LockingStrategy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/lock/SelectLockingStrategy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/lock/UpdateLockingStrategy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ActionQueue.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/AssociationKey.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/BatchFetchQueue.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Cascade.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CascadeStyle.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CascadingAction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CollectionEntry.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CollectionKey.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Collections.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/EntityEntry.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/EntityKey.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/EntityUniqueKey.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ExecuteUpdateResultCheckStyle.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/FilterDefinition.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ForeignKeys.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/HibernateIterator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/IdentifierValue.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/JoinHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/JoinSequence.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Mapping.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/NamedQueryDefinition.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/NamedSQLQueryDefinition.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Nullability.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ParameterBinder.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/PersistenceContext.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/QueryParameters.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ResultSetMappingDefinition.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/RowSelection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/SessionFactoryImplementor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/SessionImplementor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Status.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/SubselectFetch.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/TransactionHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/TwoPhaseLoad.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/TypedValue.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/UnsavedValueFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ValueInclusion.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/VersionValue.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Versioning.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/CollectionLoadContext.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/EntityLoadContext.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/LoadContexts.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/LoadingCollectionEntry.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/FilterQueryPlan.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/HQLQueryPlan.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/NamedParameterDescriptor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/NativeSQLQueryPlan.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/OrdinalParameterDescriptor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ParamLocationRecognizer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ParameterMetadata.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ParameterParser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/QueryMetadata.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/QueryPlanCache.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ReturnMetadata.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryCollectionReturn.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryJoinReturn.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryNonScalarReturn.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryReturn.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryRootReturn.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryScalarReturn.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQuerySpecification.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/transaction/
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/transaction/IsolatedWork.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/engine/transaction/Isolater.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/AbstractEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/AutoFlushEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/AutoFlushEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/DeleteEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/DeleteEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/DirtyCheckEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/DirtyCheckEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/EventListeners.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/EventSource.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/EvictEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/EvictEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEntityEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEntityEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/Initializable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/InitializeCollectionEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/InitializeCollectionEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/LoadEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/LoadEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/LockEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/LockEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/MergeEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/MergeEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PersistEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PersistEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostDeleteEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostDeleteEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostInsertEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostInsertEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostLoadEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostLoadEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostUpdateEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostUpdateEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreDeleteEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreDeleteEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreInsertEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreInsertEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreLoadEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreLoadEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreUpdateEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreUpdateEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/RefreshEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/RefreshEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/ReplicateEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/ReplicateEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/SaveOrUpdateEvent.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/SaveOrUpdateEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractFlushingEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractLockUpgradeEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractReassociateEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractSaveEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractVisitor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultAutoFlushEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultDeleteEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultDirtyCheckEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultEvictEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultFlushEntityEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultFlushEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultInitializeCollectionEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultLockEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultMergeEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPersistEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPersistOnFlushEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPostLoadEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPreLoadEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultRefreshEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultReplicateEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultSaveEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultSaveOrUpdateCopyEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultSaveOrUpdateEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultUpdateEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DirtyCollectionSearchVisitor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/EvictVisitor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/FlushVisitor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/OnLockVisitor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/OnReplicateVisitor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/OnUpdateVisitor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/ProxyVisitor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/ReattachVisitor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/WrapVisitor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/event/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/CacheSQLStateConverter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/Configurable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/ConstraintViolationException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/DataException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/ExceptionUtils.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/GenericJDBCException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/JDBCConnectionException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/JDBCExceptionHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/LockAcquisitionException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/Nestable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/NestableDelegate.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/NestableException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/NestableRuntimeException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLExceptionConverter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLExceptionConverterFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLGrammarException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLStateConverter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/TemplatedViolatedConstraintNameExtracter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/ViolatedConstraintNameExtracter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/exception/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/CollectionProperties.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/CollectionSubqueryFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/FilterTranslator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/HolderInstantiator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/NameGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ParameterTranslations.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QueryExecutionRequestException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QuerySplitter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QueryTranslator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QueryTranslatorFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/antlr/
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/antlr/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ASTQueryTranslatorFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/DetailedSemanticException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ErrorCounter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ErrorReporter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlASTFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlLexer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlParser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlSqlWalker.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlToken.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/InvalidPathException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/InvalidWithClauseException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ParameterTranslationsImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ParseErrorHandler.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/QuerySyntaxException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/QueryTranslatorImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/SqlASTFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/SqlGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/AbstractStatementExecutor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/BasicExecutor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/MultiTableDeleteExecutor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/MultiTableUpdateExecutor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/StatementExecutor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AbstractRestrictableStatement.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AbstractSelectExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AbstractStatement.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AggregateNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AssignmentSpecification.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BetweenOperatorNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BinaryArithmeticOperatorNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BinaryOperatorNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BooleanLiteralNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/Case2Node.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/CaseNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/CollectionFunction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ConstructorNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/CountNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/DeleteStatement.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/DisplayableNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/DotNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ExpectedTypeAwareNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromClause.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromElement.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromElementFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromElementType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromReferenceNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/HqlSqlWalkerNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/IdentNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ImpliedFromElement.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/InLogicOperatorNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/IndexNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/InitializeableNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/InsertStatement.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/IntoClause.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/JavaConstantNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/LiteralNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/MethodNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/Node.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/OperatorNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/OrderByClause.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ParameterNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/PathNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/QueryNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ResolvableNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/RestrictableStatement.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectClause.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpression.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpressionImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpressionList.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SessionFactoryAwareNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SqlFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SqlNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/Statement.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UnaryArithmeticNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UnaryLogicOperatorNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UnaryOperatorNode.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UpdateStatement.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTAppender.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTIterator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTParentsFirstIterator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTPrinter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTUtil.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/AliasGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ColumnHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/JoinProcessor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/LiteralProcessor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/NodeTraverser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/PathHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/SessionFactoryHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/SyntheticAndFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/ClassicQueryTranslatorFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/ClauseParser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/FromParser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/FromPathExpressionParser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/GroupByParser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/HavingParser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/OrderByParser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/Parser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/ParserHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/PathExpressionParser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/PreprocessingParser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/QueryTranslatorImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/SelectParser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/SelectPathExpressionParser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/WhereParser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/hql/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/AbstractPostInsertGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/AbstractUUIDGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/Assigned.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/Configurable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/ForeignGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/GUIDGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentifierGenerationException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentifierGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentifierGeneratorFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentityGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/IncrementGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/PostInsertIdentifierGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/PostInsertIdentityPersister.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/SelectGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/SequenceGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/SequenceIdentityGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/TableGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/TableHiLoGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/UUIDHexGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/AccessCallback.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/Optimizer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/TableStructure.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/AbstractReturningDelegate.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/AbstractSelectingDelegate.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/Binder.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/IdentifierGeneratingInsert.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/InsertGeneratedIdentifierDelegate.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/InsertSelectIdentityInsert.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/id/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/AbstractQueryImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/AbstractScrollableResults.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/AbstractSessionImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/CollectionFilterImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/CriteriaImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/FetchingScrollableResultsImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/FilterImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/IteratorImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/QueryImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SQLQueryImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/ScrollableResultsImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SessionFactoryObjectFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SessionImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/impl/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/
   trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/AbstractFieldInterceptor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/FieldInterceptionHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/FieldInterceptor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/LazyPropertyInitializer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/cglib/
   trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/cglib/CGLIBHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/cglib/FieldInterceptorImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/javassist/
   trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/javassist/FieldInterceptorImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/javassist/JavassistHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/AbstractBatcher.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchFailedException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchedTooManyRowsAffectedException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/Batcher.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatcherFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchingBatcher.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchingBatcherFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BorrowedConnectionProxy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ColumnNameCache.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ConnectionManager.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ConnectionWrapper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/Expectation.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/Expectations.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/JDBCContext.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/NonBatchingBatcher.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/NonBatchingBatcherFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ResultSetWrapper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/TooManyRowsAffectedException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/BasicLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/CollectionAliases.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/ColumnEntityAliases.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/DefaultEntityAliases.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/EntityAliases.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/GeneratedCollectionAliases.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/JoinWalker.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/Loader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/OuterJoinLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/OuterJoinableAssociation.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/BasicCollectionJoinWalker.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/BasicCollectionLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/BatchingCollectionInitializer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/CollectionInitializer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/CollectionJoinWalker.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/CollectionLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/OneToManyJoinWalker.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/OneToManyLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/SubselectCollectionLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/SubselectOneToManyLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/CriteriaJoinWalker.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/CriteriaLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/CriteriaQueryTranslator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CollectionFetchReturn.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CollectionReturn.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/ColumnCollectionAliases.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CustomLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CustomQuery.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/EntityFetchReturn.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/FetchReturn.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/NonScalarReturn.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/Return.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/RootReturn.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/ScalarReturn.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/SQLCustomQuery.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/SQLQueryParser.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/SQLQueryReturnProcessor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/BatchingEntityLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CascadeEntityJoinWalker.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CascadeEntityLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CollectionElementLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/EntityJoinWalker.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/EntityLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/UniqueEntityLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/hql/
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/hql/QueryLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/hql/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/loader/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/lob/
   trunk/Hibernate3/core/src/main/java/org/hibernate/lob/BlobImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/lob/ClobImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/lob/ReaderInputStream.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/lob/SerializableBlob.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/lob/SerializableClob.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/lob/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/AbstractAuxiliaryDatabaseObject.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Any.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Array.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/AuxiliaryDatabaseObject.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Backref.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Bag.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Collection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Column.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Component.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Constraint.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/DenormalizedTable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/DependantValue.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Fetchable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Filterable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ForeignKey.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Formula.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IdentifierBag.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IdentifierCollection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Index.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IndexBackref.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IndexedCollection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Join.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/JoinedSubclass.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/KeyValue.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/List.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ManyToOne.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Map.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/MetaAttributable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/MetaAttribute.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/OneToMany.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/OneToOne.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PersistentClass.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PersistentClassVisitor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PrimaryKey.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PrimitiveArray.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Property.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PropertyGeneration.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/RelationalModel.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/RootClass.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Selectable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Set.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/SimpleAuxiliaryDatabaseObject.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/SimpleValue.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/SingleTableSubclass.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Subclass.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Table.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/TableOwner.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ToOne.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/TypeDef.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/UnionSubclass.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/UniqueKey.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Value.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ValueVisitor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/metadata/
   trunk/Hibernate3/core/src/main/java/org/hibernate/metadata/ClassMetadata.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/metadata/CollectionMetadata.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/metadata/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/param/
   trunk/Hibernate3/core/src/main/java/org/hibernate/param/AbstractExplicitParameterSpecification.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/param/CollectionFilterKeyParameterSpecification.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/param/DynamicFilterParameterSpecification.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/param/ExplicitParameterSpecification.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/param/NamedParameterSpecification.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/param/ParameterSpecification.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/param/PositionalParameterSpecification.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/param/VersionTypeSeedParameterSpecification.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/PersisterFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CollectionPropertyMapping.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CollectionPropertyNames.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CompositeElementPropertyMapping.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/ElementPropertyMapping.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/NamedQueryCollectionInitializer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/QueryableCollection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/SQLLoadableCollection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/AbstractPropertyMapping.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/BasicEntityPropertyMapping.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/EntityPersister.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Joinable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Loadable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Lockable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/NamedQueryLoader.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/OuterJoinLoadable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/PropertyMapping.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Queryable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/SQLLoadable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/UniqueKeyLoadable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/persister/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/
   trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/DDLFormatter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/Formatter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/MessageHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/Printer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/BackrefPropertyAccessor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/BasicPropertyAccessor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/ChainedPropertyAccessor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/DirectPropertyAccessor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/Dom4jAccessor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/EmbeddedPropertyAccessor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/Getter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/IndexPropertyAccessor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/MapAccessor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/NoopAccessor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/PropertyAccessor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/PropertyAccessorFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/Setter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/property/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/EntityNotFoundDelegate.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/HibernateProxy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/HibernateProxyHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/LazyInitializer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/ProxyFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/dom4j/
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/dom4j/Dom4jLazyInitializer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/dom4j/Dom4jProxy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/dom4j/Dom4jProxyFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/map/
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/map/MapLazyInitializer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/map/MapProxy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/map/MapProxyFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/BasicLazyInitializer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/cglib/
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/cglib/CGLIBLazyInitializer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/cglib/CGLIBProxyFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/cglib/SerializableProxy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/javassist/
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistProxyFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/javassist/SerializableProxy.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/secure/
   trunk/Hibernate3/core/src/main/java/org/hibernate/secure/HibernatePermission.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCConfiguration.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPermissions.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreDeleteEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreInsertEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreLoadEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreUpdateEventListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCSecurityListener.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/secure/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ANSICaseFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ANSIJoinFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Alias.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/CacheJoinFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/CaseFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ConditionFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/DecodeCaseFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Delete.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/DerbyCaseFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/DisjunctionFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ForUpdateFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/HSQLCaseFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/InFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Insert.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/InsertSelect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/JoinFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/MckoiCaseFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/OracleJoinFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/QueryJoinFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/QuerySelect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Select.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/SelectFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/SimpleSelect.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Sybase11JoinFragment.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Template.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Update.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/sql/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/stat/
   trunk/Hibernate3/core/src/main/java/org/hibernate/stat/CategorizedStatistics.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/stat/CollectionStatistics.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/stat/EntityStatistics.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/stat/QueryStatistics.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SecondLevelCacheStatistics.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SessionStatistics.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SessionStatisticsImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/stat/Statistics.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/stat/StatisticsImpl.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/stat/StatisticsImplementor.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/stat/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ColumnMetadata.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ConnectionHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/DatabaseMetadata.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ForeignKeyMetadata.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/IndexMetadata.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ManagedProviderConnectionHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExportTask.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdateTask.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidatorTask.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SuppliedConnectionHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SuppliedConnectionProviderConnectionHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/TableMetadata.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/BasicInstrumentationTask.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/cglib/
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/cglib/InstrumentTask.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/javassist/
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/javassist/InstrumentTask.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/BESTransactionManagerLookup.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/CMTTransaction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/CMTTransactionFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/CacheSynchronization.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JBossTransactionManagerLookup.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JDBCTransaction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JDBCTransactionFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JNDITransactionManagerLookup.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JOTMTransactionManagerLookup.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JOnASTransactionManagerLookup.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JRun4TransactionManagerLookup.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JTATransaction.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JTATransactionFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/OC4JTransactionManagerLookup.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/OrionTransactionManagerLookup.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/ResinTransactionManagerLookup.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/SunONETransactionManagerLookup.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionFactoryFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionManagerLookup.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionManagerLookupFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/WebSphereExtendedJTATransactionLookup.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/WebSphereTransactionManagerLookup.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/WeblogicTransactionManagerLookup.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/transform/
   trunk/Hibernate3/core/src/main/java/org/hibernate/transform/AliasToBeanConstructorResultTransformer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transform/AliasToBeanResultTransformer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transform/AliasToEntityMapResultTransformer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transform/DistinctRootEntityResultTransformer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transform/PassThroughResultTransformer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transform/ResultTransformer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transform/RootEntityResultTransformer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transform/ToListResultTransformer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transform/Transformers.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/transform/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Dom4jInstantiator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/DynamicMapInstantiator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/ElementWrapper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/EntityModeToTuplizerMapping.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/IdentifierProperty.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Instantiator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/PojoInstantiator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Property.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/PropertyFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/StandardProperty.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Tuplizer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/VersionProperty.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/AbstractComponentTuplizer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/ComponentEntityModeToTuplizerMapping.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/ComponentMetamodel.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/ComponentTuplizer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/Dom4jComponentTuplizer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/DynamicMapComponentTuplizer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/Dom4jEntityTuplizer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/EntityEntityModeToTuplizerMapping.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractBynaryType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractCharArrayType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractComponentType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/AdaptedImmutableType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/AnyType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/ArrayType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/AssociationType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/BagType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/BigDecimalType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/BigIntegerType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/BinaryType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/BlobType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/BooleanType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/ByteType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/CalendarDateType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/CalendarType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharArrayType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharBooleanType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharacterArrayType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharacterType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/ClassType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/ClobType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/CollectionType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/ComponentType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/CompositeCustomType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/CurrencyType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/CustomCollectionType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/CustomType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/DateType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/DbTimestampType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/DiscriminatorType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/DoubleType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/EmbeddedComponentType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/EntityType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/FloatType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/ForeignKeyDirection.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/IdentifierBagType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/IdentifierType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/ImmutableType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/IntegerType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/ListType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/LiteralType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/LocaleType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/LongType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/ManyToOneType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/MapType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/MetaType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/MutableType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/NullableType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/OneToOneType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/OrderedMapType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/OrderedSetType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/PrimitiveType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/SerializableType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/SerializationException.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/SetType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/ShortType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/SortedMapType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/SortedSetType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/SpecialOneToOneType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/StringType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/TextType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/TimeType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/TimeZoneType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/TimestampType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/TrueFalseType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/Type.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/TypeFactory.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/VersionType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/WrapperBinaryType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/YesNoType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/type/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/
   trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/CompositeUserType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/EnhancedUserType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/LoggableUserType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/ParameterizedType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/UserCollectionType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/UserType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/UserVersionType.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/package.html
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/ArrayHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/BytesHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/CalendarComparator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/Cloneable.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/CollectionHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/ComparableComparator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/ConfigHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/DTDEntityResolver.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/EmptyIterator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/EqualsHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/ExternalSessionFactoryConfig.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/FastHashMap.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/FilterHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/GetGeneratedKeysHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/IdentityMap.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/IdentitySet.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/JDBCExceptionReporter.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/JTAHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/JoinedIterator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/LazyIterator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/LinkedHashCollectionHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/MarkerObject.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/NamedGeneratedKeysHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/NamingHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/PropertiesHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/Range.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/ReflectHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/SerializationHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/SimpleMRUCache.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/SingletonIterator.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/SoftLimitMRUCache.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/StringHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/XMLHelper.java
   trunk/Hibernate3/core/src/main/java/org/hibernate/util/package.html
   trunk/Hibernate3/core/src/main/javadoc/
   trunk/Hibernate3/core/src/main/javadoc/package.html
   trunk/Hibernate3/core/src/main/resources/
   trunk/Hibernate3/core/src/main/resources/org/
   trunk/Hibernate3/core/src/main/resources/org/hibernate/
   trunk/Hibernate3/core/src/main/resources/org/hibernate/checkstyle_checks.xml
   trunk/Hibernate3/core/src/main/resources/org/hibernate/hibernate-configuration-3.0.dtd
   trunk/Hibernate3/core/src/main/resources/org/hibernate/hibernate-mapping-3.0.dtd
   trunk/Hibernate3/documentation/
   trunk/Hibernate3/documentation/manual/
   trunk/Hibernate3/documentation/manual/README
   trunk/Hibernate3/documentation/manual/en-US/
   trunk/Hibernate3/documentation/manual/en-US/pom.xml
   trunk/Hibernate3/documentation/manual/en-US/src/
   trunk/Hibernate3/documentation/manual/en-US/src/main/
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/master.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/architecture.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/association_mapping.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/basic_mapping.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/batch.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/best_practices.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/collection_mapping.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/component_mapping.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/configuration.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/events.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/example_mappings.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/example_parentchild.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/example_weblog.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/filters.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/inheritance_mapping.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/performance.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/persistent_classes.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/query_criteria.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/query_hql.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/query_sql.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/session_api.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/toolset_guide.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/transactions.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/tutorial.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/xml.xml
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/css/
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/css/html.css
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/AuthorWork.gif
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/AuthorWork.zargo
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/CustomerOrderProduct.gif
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/CustomerOrderProduct.zargo
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/EmployerEmployee.gif
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/EmployerEmployee.zargo
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/full_cream.gif
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/full_cream.svg
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/hibernate_logo_a.png
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/lite.gif
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/lite.svg
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/overview.gif
   trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/overview.svg
   trunk/Hibernate3/documentation/manual/es-ES/
   trunk/Hibernate3/documentation/manual/es-ES/pom.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/
   trunk/Hibernate3/documentation/manual/es-ES/src/main/
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/master.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/architecture.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/association_mapping.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/basic_mapping.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/batch.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/best_practices.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/collection_mapping.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/component_mapping.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/configuration.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/events.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/example_mappings.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/example_parentchild.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/example_weblog.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/filters.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/inheritance_mapping.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/performance.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/persistent_classes.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/query_criteria.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/query_hql.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/query_sql.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/quickstart.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/session_api.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/toolset_guide.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/transactions.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/tutorial.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/xml.xml
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/css/
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/css/html.css
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/AuthorWork.gif
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/AuthorWork.zargo
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/CustomerOrderProduct.gif
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/CustomerOrderProduct.zargo
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/EmployerEmployee.gif
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/EmployerEmployee.zargo
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/full_cream.gif
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/full_cream.svg
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/hibernate_logo_a.png
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/lite.gif
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/lite.svg
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/overview.gif
   trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/overview.svg
   trunk/Hibernate3/documentation/manual/fr-FR/
   trunk/Hibernate3/documentation/manual/fr-FR/pom.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/master.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/architecture.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/association_mapping.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/basic_mapping.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/batch.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/best_practices.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/collection_mapping.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/component_mapping.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/configuration.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/events.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/example_mappings.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/example_parentchild.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/example_weblog.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/filters.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/inheritance_mapping.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/performance.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/persistent_classes.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/query_criteria.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/query_hql.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/query_sql.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/session_api.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/toolset_guide.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/transactions.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/tutorial.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/xml.xml
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/css/
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/css/html.css
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/AuthorWork.gif
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/AuthorWork.zargo
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/CustomerOrderProduct.gif
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/CustomerOrderProduct.zargo
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/EmployerEmployee.gif
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/EmployerEmployee.zargo
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/full_cream.gif
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/full_cream.svg
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/hibernate_logo_a.png
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/lite.gif
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/lite.svg
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/overview.gif
   trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/overview.svg
   trunk/Hibernate3/documentation/manual/ja-JP/
   trunk/Hibernate3/documentation/manual/ja-JP/pom.xml
   trunk/Hibernate3/documentation/manual/ja-JP/readme_ja.txt
   trunk/Hibernate3/documentation/manual/ja-JP/src/
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/master.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/architecture.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/association_mapping.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/basic_mapping.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/batch.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/best_practices.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/collection_mapping.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/component_mapping.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/configuration.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/events.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/example_mappings.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/example_parentchild.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/example_weblog.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/filters.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/inheritance_mapping.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/performance.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/persistent_classes.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/query_criteria.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/query_hql.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/query_sql.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/session_api.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/toolset_guide.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/transactions.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/tutorial.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/xml.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/css/
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/css/html.css
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/AuthorWork.gif
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/AuthorWork.zargo
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/CustomerOrderProduct.gif
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/CustomerOrderProduct.zargo
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/EmployerEmployee.gif
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/EmployerEmployee.zargo
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/full_cream.gif
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/full_cream.svg
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/hibernate_logo_a.png
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/lite.gif
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/lite.svg
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/overview.gif
   trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/overview.svg
   trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/
   trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/
   trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/sazanami-gothic.ttf
   trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/sazanami-gothic.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/sazanami-mincho.ttf
   trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/sazanami-mincho.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/userconfig.xml
   trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/styles/
   trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/styles/fopdf.xsl
   trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/styles/html.xsl
   trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/styles/html_chunk.xsl
   trunk/Hibernate3/documentation/manual/ko-KR/
   trunk/Hibernate3/documentation/manual/ko-KR/README-KO.txt
   trunk/Hibernate3/documentation/manual/ko-KR/pom.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/master.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/architecture.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/association_mapping.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/basic_mapping.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/batch.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/best_practices.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/collection_mapping.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/component_mapping.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/configuration.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/events.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/example_mappings.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/example_parentchild.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/example_weblog.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/filters.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/inheritance_mapping.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/performance.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/persistent_classes.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/query_criteria.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/query_hql.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/query_sql.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/quickstart.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/session_api.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/toolset_guide.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/transactions.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/tutorial.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/xml.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/css/
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/css/html.css
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/AuthorWork.gif
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/AuthorWork.zargo
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/CustomerOrderProduct.gif
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/CustomerOrderProduct.zargo
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/EmployerEmployee.gif
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/EmployerEmployee.zargo
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/full_cream.gif
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/full_cream.svg
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/hibernate_logo_a.png
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/lite.gif
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/lite.svg
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/overview.gif
   trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/overview.svg
   trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/
   trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/
   trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/Bangwool.ttf
   trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/Bangwool.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/Hankc.ttf
   trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/Hankc.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/userconfig.xml
   trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/styles/
   trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/styles/fopdf.xsl
   trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/styles/html.xsl
   trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/styles/html_chunk.xsl
   trunk/Hibernate3/documentation/manual/pom.xml
   trunk/Hibernate3/documentation/manual/pt-BR/
   trunk/Hibernate3/documentation/manual/pt-BR/pom.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/master.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/architecture.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/association_mapping.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/basic_mapping.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/batch.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/best_practices.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/collection_mapping.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/component_mapping.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/configuration.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/events.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_mappings.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_parentchild.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_weblog.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/filters.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/inheritance_mapping.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/performance.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/persistent_classes.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_criteria.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_hql.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_sql.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/session_api.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/toolset_guide.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/transactions.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/tutorial.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/tutorial1.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/xml.xml
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/css/
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/css/html.css
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/AuthorWork.gif
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/AuthorWork.zargo
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/CustomerOrderProduct.gif
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/CustomerOrderProduct.zargo
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/EmployerEmployee.gif
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/EmployerEmployee.zargo
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/full_cream.gif
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/full_cream.svg
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/hibernate_logo_a.png
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/lite.gif
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/lite.svg
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/overview.gif
   trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/overview.svg
   trunk/Hibernate3/documentation/manual/zh-CN/
   trunk/Hibernate3/documentation/manual/zh-CN/README_CHINESE_FONT.txt
   trunk/Hibernate3/documentation/manual/zh-CN/pom.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/glossary.txt
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/master.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/architecture.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/association_mapping.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/basic_mapping.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/batch.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/best_practices.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/collection_mapping.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/component_mapping.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/configuration.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/events.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/example_mappings.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/example_parentchild.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/example_weblog.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/filters.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/inheritance_mapping.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/kicken.pl
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/performance.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/persistent_classes.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/query_criteria.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/query_hql.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/query_sql.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/quickstart.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/session_api.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/toolset_guide.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/transactions.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/tutorial.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/xml.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/css/
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/css/html.css
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/AuthorWork.gif
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/AuthorWork.zargo
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/CustomerOrderProduct.gif
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/CustomerOrderProduct.zargo
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/EmployerEmployee.gif
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/EmployerEmployee.zargo
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/full_cream.gif
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/full_cream.svg
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/hibernate_logo_a.png
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/lite.gif
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/lite.svg
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/overview.gif
   trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/overview.svg
   trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/
   trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/fop/
   trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/fop/simhei.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/fop/simsun.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/fop/userconfig.xml
   trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/
   trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/fopdf.xsl
   trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/html.css
   trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/html.xsl
   trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/html_chunk.xsl
   trunk/Hibernate3/documentation/pom.xml
   trunk/Hibernate3/documentation/tutorial/
   trunk/Hibernate3/documentation/tutorial/pom.xml
   trunk/Hibernate3/documentation/tutorial/src/
   trunk/Hibernate3/documentation/tutorial/src/main/
   trunk/Hibernate3/documentation/tutorial/src/main/java/
   trunk/Hibernate3/documentation/tutorial/src/main/java/events/
   trunk/Hibernate3/documentation/tutorial/src/main/java/events/Event.hbm.xml
   trunk/Hibernate3/documentation/tutorial/src/main/java/events/Event.java
   trunk/Hibernate3/documentation/tutorial/src/main/java/events/EventManager.java
   trunk/Hibernate3/documentation/tutorial/src/main/java/events/EventManagerServlet.java
   trunk/Hibernate3/documentation/tutorial/src/main/java/events/Person.hbm.xml
   trunk/Hibernate3/documentation/tutorial/src/main/java/events/Person.java
   trunk/Hibernate3/documentation/tutorial/src/main/java/util/
   trunk/Hibernate3/documentation/tutorial/src/main/java/util/HibernateUtil.java
   trunk/Hibernate3/documentation/tutorial/src/main/resources/
   trunk/Hibernate3/documentation/tutorial/src/main/resources/hibernate.cfg.xml
   trunk/Hibernate3/documentation/tutorial/src/main/resources/log4j.properties
   trunk/Hibernate3/documentation/tutorial/src/main/scripts/
   trunk/Hibernate3/documentation/tutorial/src/main/scripts/runCleanDatabase.sh
   trunk/Hibernate3/documentation/tutorial/src/main/webapp/
   trunk/Hibernate3/documentation/tutorial/src/main/webapp/WEB-INF/
   trunk/Hibernate3/documentation/tutorial/src/main/webapp/WEB-INF/web.xml
   trunk/Hibernate3/eg/pom.xml
   trunk/Hibernate3/eg/src/
   trunk/Hibernate3/eg/src/main/
   trunk/Hibernate3/eg/src/main/java/
   trunk/Hibernate3/eg/src/main/java/org/
   trunk/Hibernate3/eg/src/main/java/org/hibernate/
   trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/
   trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/AuctionInfo.java
   trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/AuctionItem.hbm.xml
   trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/AuctionItem.java
   trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Bid.hbm.xml
   trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Bid.java
   trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/BuyNow.java
   trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Main.java
   trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Name.java
   trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Persistent.java
   trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/User.hbm.xml
   trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/User.java
   trunk/Hibernate3/eg/src/main/resources/
   trunk/Hibernate3/eg/src/main/resources/org/
   trunk/Hibernate3/eg/src/main/resources/org/hibernate/
   trunk/Hibernate3/eg/src/main/resources/org/hibernate/auction/
   trunk/Hibernate3/eg/src/main/resources/org/hibernate/auction/AuctionItem.hbm.xml
   trunk/Hibernate3/eg/src/main/resources/org/hibernate/auction/Bid.hbm.xml
   trunk/Hibernate3/eg/src/main/resources/org/hibernate/auction/User.hbm.xml
   trunk/Hibernate3/jmx/
   trunk/Hibernate3/jmx/pom.xml
   trunk/Hibernate3/jmx/src/
   trunk/Hibernate3/jmx/src/main/
   trunk/Hibernate3/jmx/src/main/java/
   trunk/Hibernate3/jmx/src/main/java/org/
   trunk/Hibernate3/jmx/src/main/java/org/hibernate/
   trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/
   trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/HibernateService.java
   trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/HibernateServiceMBean.java
   trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/SessionFactoryStub.java
   trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/StatisticsService.java
   trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/StatisticsServiceMBean.java
   trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/package.html
   trunk/Hibernate3/testing/
   trunk/Hibernate3/testing/pom.xml
   trunk/Hibernate3/testing/src/
   trunk/Hibernate3/testing/src/main/
   trunk/Hibernate3/testing/src/main/java/
   trunk/Hibernate3/testing/src/main/java/org/
   trunk/Hibernate3/testing/src/main/java/org/hibernate/
   trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/
   trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/AbstractClassLoaderIsolatedTestCase.java
   trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/SkipLog.java
   trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/TestSuiteVisitor.java
   trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/UnitTestCase.java
   trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/
   trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/DatabaseSpecificFunctionalTestCase.java
   trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/ExecutionEnvironment.java
   trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/FunctionalTestCase.java
   trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/FunctionalTestClassTestSuite.java
   trunk/Hibernate3/testsuite/
   trunk/Hibernate3/testsuite/pom.xml
   trunk/Hibernate3/testsuite/src/
   trunk/Hibernate3/testsuite/src/test/
   trunk/Hibernate3/testsuite/src/test/java/
   trunk/Hibernate3/testsuite/src/test/java/org/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/AllTests.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/FailureExpectedCollector.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/TestCase.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/TestSelector.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/AbstractCompositeIdTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/MyInterface.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/MyInterfaceImpl.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/AbstractComponentPropertyRefTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/AddressImpl.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/Server.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/ServerImpl.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/AnyTypeTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/ComplexPropertyValue.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/IntegerPropertyValue.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Properties.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/PropertySet.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/PropertyValue.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/StringPropertyValue.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/A.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/A.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/ArrayTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/B.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ast/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ast/ASTIteratorTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ast/ASTUtilTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/BatchTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/DataPoint.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/DataPoint.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/BatchFetchTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/Model.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/ProductLine.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/ProductLine.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction2.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/AuctionTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/AuctionTest2.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Bid.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/Bean.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/Bean.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/BeanReflectionHelper.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/BytecodeSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/ProxyBean.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/cglib/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/cglib/CGLIBThreadLocalTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/cglib/InvocationTargetExceptionTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/cglib/ReflectionOptimizerTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/javassist/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/javassist/InvocationTargetExceptionTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/javassist/ReflectionOptimizerTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/BaseCacheProviderTestCase.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/CacheSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/Item.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/Item.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/VersionedItem.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/ehcache/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/ehcache/EhCacheTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/ehcache/ehcache.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/optimistic/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/optimistic/OptimisticTreeCacheTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/optimistic/treecache.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/pessimistic/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/pessimistic/TreeCacheTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/pessimistic/treecache.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/Job.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/Job.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/JobBatch.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/JobBatch.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/RefreshTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cfg/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cfg/Cacheable.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cfg/CacheableFileTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/CompositeIdTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Customer.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/LineItem.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/LineItem.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Order.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Order.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Product.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Product.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/CollectionSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/bag/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/bag/BagOwner.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/bag/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/bag/PersistentBagTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/idbag/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/idbag/IdbagOwner.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/idbag/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/idbag/PersistentIdBagTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/list/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/list/ListOwner.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/list/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/list/PersistentListTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/Child.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/Parent.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/PersistentMapTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/CollectionTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/Email.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/Permission.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/UserPermissions.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/Child.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/Parent.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/PersistentSetTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/ComponentSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/ComponentTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/Employee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/User.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/CascadeToComponentCollectionTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/Definition.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/LocalizedStrings.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/Value.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/CascadeToComponentAssociationTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/Document.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/PersonalInfo.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Child.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/CompositeElementTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Parent.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Parent.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/AggressiveReleaseTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/BasicConnectionProviderTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/ConnectionManagementTestCase.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/ConnectionsSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/CurrentSessionConnectionTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/Other.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/Silly.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/Silly.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/SuppliedConnectionTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/ThreadLocalCurrentSessionTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Course.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Enrolment.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Enrolment.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Student.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/StudentDTO.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Account.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/CompositePropertyRefTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/CompositeUserTypeTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/MonetoryAmount.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/MonetoryAmountUserType.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/Transaction.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/Transaction.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/types.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/DeleteTransientEntityTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/DialectFunctionalTestsSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/cache/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/cache/SQLFunctionsInterSystemsTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/cache/TestInterSystemsFunctionsClass.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/cache/TestInterSystemsFunctionsClass.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/DialectUnitTestsSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/lockhint/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/lockhint/AbstractLockHintTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/lockhint/SQLServerLockHintsTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/lockhint/SybaseLockHintsTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/DiscriminatorTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Employee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Company.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/DataProxyHandler.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/DynamicEntitySuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/ProxyHelper.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/interceptor/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/interceptor/Customer.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/interceptor/InterceptorDynamicEntityTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/interceptor/ProxyInterceptor.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/package.html
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/Customer.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/EntityNameInterceptor.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/MyEntityInstantiator.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/MyEntityTuplizer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/TuplizerDynamicEntityTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/Course.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/Course.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/EmbeddedCompositeIdTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/UniversityCourse.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/EntityModeSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/Dom4jSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/accessors/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/accessors/Dom4jAccessorTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/AB.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Account.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Dom4jTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Employer.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Car.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Car.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/CarPart.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/CarType.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Dom4jManyToOneTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/MapSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/basic/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/basic/DynamicClassTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/basic/ProductLine.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/MultiRepresentationTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Stock.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Stock.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Valuation.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Valuation.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/Group.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/Group.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/SQLExceptionConversionTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/User.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Customer.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Employee.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Employee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/ExtendsTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/allinone.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/allseparateinone.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/entitynames.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/packageentitynames.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/unionsubclass.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/Document.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/ExtraLazyTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/Group.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/SessionAttribute.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/UserGroup.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Category.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Category.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Department.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Department.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/DynamicFilterTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/LineItem.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/LineItem.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Order.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Order.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Product.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Product.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Salesperson.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Salesperson.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/defs.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Detail.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/FormulaJoinTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Master.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Master.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/AbstractGeneratedPropertyTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/ComponentOwner.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/ComponentOwner.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/GeneratedPropertyEntity.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/GeneratedPropertyEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/GeneratedPropertySuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/MSSQLGeneratedPropertyEntity.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/PartiallyGeneratedComponentTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/TimestampGeneratedValuesWithCachingTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/TriggerGeneratedValuesWithCachingTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/TriggerGeneratedValuesWithoutCachingTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/GeneratedKeysSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/IdentityGeneratedKeysTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MyChild.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MyEntity.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MyEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MySibling.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/select/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/select/MyEntity.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/select/MyEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/select/SelectGeneratorTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/seqidentity/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/seqidentity/MyEntity.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/seqidentity/MyEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/seqidentity/SequenceIdentityTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ASTQueryTranslatorTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Animal.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Animal.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/BooleanLiteralEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Car.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Cat.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ClassicTranslatorTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Classification.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ClassificationType.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ComponentContainer.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ComponentContainer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CrazyCompositeKey.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CrazyIdFieldNames.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CriteriaClassicAggregationReturnTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Dog.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/DomesticAnimal.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/EJBQLTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/EntityWithCrazyCompositeKey.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/EntityWithCrazyCompositeKey.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/FooBarCopy.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HQLSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HQLTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HeresAnotherCrazyIdFieldName.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HqlParserTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Human.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/IntegerVersioned.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Joiner.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/KeyManyToOneEntity.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/KeyManyToOneEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/KeyManyToOneKeyEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Lizard.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Mammal.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/MoreCrazyIdFieldNameStuffEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Name.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/PettingZoo.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Pickup.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/QueryTranslatorTestCase.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Reptile.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SUV.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ScrollableCollectionFetchingTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SimpleAssociatedEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SimpleEntityWithAssociation.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SimpleEntityWithAssociation.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/StateProvince.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/TimestampVersioned.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Truck.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Vehicle.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Vehicle.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Versions.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/WithClauseTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Zoo.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Car.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Car.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/MultipleHiLoPerTableGeneratorTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Plane.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Plane.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Product.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Product.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Radio.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Radio.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/UseIdentifierRollbackTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/Group.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/IdBagTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/UserGroup.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/Customer.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/CustomerId.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/FavoriteCustomer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/IdClassTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/IdGenSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/Basic.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/BasicForcedTableSequenceTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/Entity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/HiLo.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/HiLoForcedTableSequenceTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/Pooled.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/PooledForcedTableSequenceTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/Basic.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/Entity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLo.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/Pooled.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/Basic.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/Entity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/HiLo.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/Pooled.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/LineItem.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/LineItemPK.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/Mapping.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/Order.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/Contract.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ContractVariation.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ContractVariation.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ImmutableTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/Group.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/InsertOrderingTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/Mapping.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/Membership.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/buildtime/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/buildtime/InstrumentTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/AbstractExecutable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/Executable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestDirtyCheckExecutable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestFetchAllExecutable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestInjectFieldInterceptorExecutable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestIsPropertyInitializedExecutable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestLazyExecutable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestLazyManyToOneExecutable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestLazyPropertyCustomTypeExecutable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestManyToOneProxyExecutable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/CustomBlobType.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Document.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Documents.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Entity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Folder.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Owner.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Problematic.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Problematic.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/runtime/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/runtime/CGLIBInstrumentationTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/runtime/JavassistInstrumentationTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/CollectionInterceptor.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/Image.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/Image.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/InterceptorTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/Log.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/PropertyInterceptor.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/StatefulInterceptor.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/User.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Document.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/DocumentImpl.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/DocumentInterceptor.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Folder.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/FolderImpl.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/InterfaceProxyTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Item.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Item.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/ItemImpl.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/SecureDocument.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/SecureDocumentImpl.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/Item.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/Item.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/IterateTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Employee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/JoinTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Employee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/JoinedSubclassTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Bid.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Category.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Comment.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Group.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Item.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/ItemBid.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/JoinFetchTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/UserGroup.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/AbstractJPATest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Item.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Item.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/JPAComplianceSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/MyEntity.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/MyEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/MySubclassEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Part.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Part.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/CascadeTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/Child.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ChildAssigned.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ChildInfo.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ChildInfoAssigned.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/Other.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/OtherAssigned.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/Parent.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentAssigned.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentChild.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentInfo.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentInfoAssigned.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/FetchingTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/Stay.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/lock/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/lock/JPALockTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/lock/RepeatableReadTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/package.html
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/proxy/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/proxy/JPAProxyTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/ql/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/ql/JPAQLComplianceTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/ql/NativeQueryTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/removed/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/removed/RemovedEntityTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/KeyManyToOneSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/EagerKeyManyToOneTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/EagerMapping.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/LazyKeyManyToOneTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/LazyMapping.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/Order.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/KeyManyToOneTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/Mapping.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/Order.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/Document.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/Documents.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/InstrumentCacheTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/InstrumentCacheTest2.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Employee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Employment.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/LazyOneToOneTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/.cvsignore
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/A.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABC.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCExtends.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCProxy.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCProxyTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Abstract.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/AbstractProxy.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/AltSimple.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Assignable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/B.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Bar.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/BarProxy.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/BasicNameable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Baz.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Baz.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Blobber.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Blobber.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Broken.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Broken.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/C1.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/C2.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CacheTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Category.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Category.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Child.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Circular.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Circular.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Commento.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Company.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Component.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentCollection.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNull.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNullMaster.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNullMaster.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNullTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Componentizable.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Componentizable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CompositeElement.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CompositeIdId.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CompositeIdId.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ConfigurationPerformanceTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Contained.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Container.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Container.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Custom.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Custom.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CustomPersister.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CustomSQL.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CustomSQLTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/D.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Detail.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/DoubleStringType.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Down.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Drug.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/E.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Eye.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Eye.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fee.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fixed.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fo.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fo.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Foo.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooBar.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooBarTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooComponent.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooProxy.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fum.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fum.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FumCompositeID.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FumTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fumm.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fumm.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Glarch.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Glarch.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/GlarchProxy.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Holder.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Holder.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/I.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJ.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJ2.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJ2Test.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Immutable.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Immutable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Inner.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/InnerKey.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Intervention.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/J.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Jay.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/K.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/LegacyTestCase.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Location.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Location.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Lower.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MainObject.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MainObject.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Many.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Many.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Map.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MapTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Marelo.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Master.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MasterDetail.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MasterDetailTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Medication.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Middle.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Middle.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MiddleKey.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Mono.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MoreStuff.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Multi.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Multi.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MultiExtends.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MultiTableTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Multiplicity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MultiplicityType.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Nameable.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Nameable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Named.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NestingComponent.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NewPerformanceTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NewerPerformanceTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NonReflectiveBinderTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Object2.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Object2.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/One.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/One.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/OneToOneCacheTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Outer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/OuterKey.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Parent.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ParentChild.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ParentChildTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Part.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Party.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/PerformanceTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Po.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/QueryByExampleTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Qux.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Qux.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Resource.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Result.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ReverseComparator.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Role.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/S.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SQLFunctionsTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SQLLoaderTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Several.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Simple.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Simple.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Single.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SingleSeveral.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Sortable.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/StatisticsTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/StringComparator.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Stuff.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Stuff.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SubComponent.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SubDetail.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SubMulti.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Super.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Top.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Trivial.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/TrivialClass.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Up.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/UpDown.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Vetoer.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Vetoer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/W.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/WZ.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Wicked.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/X.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/XY.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Y.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Z.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/BlobTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/ClobTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/LobHolder.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/LobMappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/LobSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/MaterializedBlobType.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/SerializableData.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/SerializableTypeTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/Group.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ManyToManyTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/UserGroup.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/Group.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/OrderedManyToManyTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/UserGroup.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/Group.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/MapIndexFormulaTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/SessionAttribute.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/UserGroup.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Item.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/MapCompositeElementTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Part.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Product.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/ProductPart.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/Group.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/MapElementFormulaTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/UserGroup.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapping/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapping/PersistentClassVisitorTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapping/ValueVisitorTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/InvalidMapping.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/InvalidMapping.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/MappingExceptionTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/User.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Document.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/DocumentInterceptor.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Folder.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Item.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Item.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/MixedTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/SecureDocument.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/NaturalIdTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/User.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Employee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/OnDeleteTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Salesperson.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Child.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/OneToManyTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Parent.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Parent.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/OneToOneSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/OneToOneFormulaTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Entity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/JoinedSubclassOneToOneTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Org.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Employee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/OneToOneLinkTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/nopojo/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/nopojo/DynamicMapOneToOneTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/nopojo/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Entity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/OptionalOneToOneTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Org.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/DiscrimSubclassOneToOneTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Entity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Org.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/AbstractOperationTestCase.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Competition.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Competition.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Competitor.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/CreateTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/DeleteTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Employee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Employer.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Employer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/GetLoadTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/MergeTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Node.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Node.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/NumberedNode.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/OneToOne.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/OpsSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/OptLockEntity.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/PersonalDetails.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/SaveOrUpdateTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/TimestampedEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/VersionedEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/Document.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/Document.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/OptimisticLockTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/PublicationDate.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/OrderByTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/Search.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/Search.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Mail.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Mail.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/OrphanSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/OrphanTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Part.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Product.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Product.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/PropertyRefTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/User.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/DataPoint.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/DataPoint.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/PaginationTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pretty/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pretty/SQLFormatterTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/PropertyRefSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Account.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Group.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/PropertyRefTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Account.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/CompleteComponentPropertyRefTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Identity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Mapping.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Account.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Identity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Mapping.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/PartialComponentPropertyRefTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Account.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/SubclassPropertyRefTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/Account.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/BankAccount.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/JoinedSubclassPropertyRefTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Account.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/UnionSubclassPropertyRefTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/Container.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/DataPoint.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/DataPoint.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/Info.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/Owner.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/ProxyTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/Item.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/Item.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/QueryCacheTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/Child.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/CollectionReattachmentTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/Parent.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/ProxyReattachmentTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/ReattachmentSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/Point.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/Point.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/RowIdTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/RowIdType.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/1_Version.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/2_Version.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/MigrationTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/Version.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/Search.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/Search.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/SortTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/NativeSqlSupportSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/CheckSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/ExceptionCheckingEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/OracleCheckStyleTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/ParamCheckingEntity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/ResultCheckStyleTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/oracle-mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Dimension.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Employment.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/MonetaryAmount.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/MonetaryAmountUserType.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Order.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Organization.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Product.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/SpaceShip.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Speech.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/CustomSQLTestSupport.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/CustomStoredProcTestSupport.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/datadirect/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/datadirect/oracle/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/datadirect/oracle/DataDirectOracleCustomSQLTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/datadirect/oracle/StoredProcedures.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/db2/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/db2/DB2CustomSQLTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/db2/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/mysql/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/mysql/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/mysql/MySQLCustomSQLTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/oracle/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/oracle/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/oracle/OracleCustomSQLTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/oracle/StoredProcedures.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/sybase/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/sybase/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/sybase/SybaseCustomSQLTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/identity/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/identity/CustomInsertSQLWithIdentityColumnTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/identity/Mappings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/query/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/query/NativeSQLQueries.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/query/NativeSQLQueriesTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/Document.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/Document.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/Paper.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/StatelessSessionTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Continent.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Continent.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Continent2.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Country.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Locality.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Province.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/SessionStatsTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/State.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/StatsTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/DiscrimSubclassFilterTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/Employee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/JoinedSubclassFilterTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/UnionSubclassFilterTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/discrim-subclass.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/joined-subclass.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/union-subclass.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Alien.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Being.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Beings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Human.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/SubselectTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/Child.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/Parent.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/ParentChild.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/SubselectFetchTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Employee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Site.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Ternary.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/TernaryTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/TimestampTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/User.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/CMTTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyConnectionProvider.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyJTAStyleTransationFactory.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransaction.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransactionManager.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransactionManagerLookup.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/Item.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tool/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tool/Team.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tool/Team.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tool/TestSchemaTools.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/AddressId.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Customer.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/TypedManyToOneTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/AddressId.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Customer.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/TypedOneToOneTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/DefaultValueIntegerType.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/TypeParameterTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/Typedef.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/Widget.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/Widget.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Employee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/UnconstrainedTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/BackrefTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/Child.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/Parent.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/ParentChild.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Alien.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Being.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Beings.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Employee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Hive.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Human.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Location.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Thing.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/UnionSubclassTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Address.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Customer.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Employee.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Person.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/UnionSubclassTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/UserCollectionTypeSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/Email.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/IMyList.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/MyList.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/MyListType.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/PersistentMyList.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/UserCollectionTypeTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/UserPermissions.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/DefaultableList.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/DefaultableListImpl.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/DefaultableListType.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/Entity.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/Mapping.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/ParameterizedUserCollectionTypeTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/PersistentDefaultableList.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/PropertiesHelperTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/StringHelperTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/UtilSuite.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/Child.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/EntityResolverTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/Parent.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/Parent.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/child.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Person.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/PersonThing.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Task.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Thing.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/VersionTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/DbVersionTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/Group.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/Permission.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/User.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/Group.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/Permission.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/SybaseTimestampVersioningTest.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/User.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/User.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/File.hbm.xml
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/File.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/NumericTrueFalseType.java
   trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/WhereTest.java
Removed:
   trunk/Hibernate3/build.bat
   trunk/Hibernate3/build.sh
   trunk/Hibernate3/build.xml
   trunk/Hibernate3/checkstyle_checks.xml
   trunk/Hibernate3/doc/
   trunk/Hibernate3/eg/org/
   trunk/Hibernate3/grammar/
   trunk/Hibernate3/indent.py
   trunk/Hibernate3/jdbc/
   trunk/Hibernate3/lib/
   trunk/Hibernate3/src/
   trunk/Hibernate3/test/
Log:
maven migration

Deleted: trunk/Hibernate3/build.bat
===================================================================
--- trunk/Hibernate3/build.bat	2007-05-24 19:06:06 UTC (rev 11562)
+++ trunk/Hibernate3/build.bat	2007-05-25 20:19:29 UTC (rev 11563)
@@ -1 +0,0 @@
-java -cp "lib/ant-launcher-1.6.5.jar" org.apache.tools.ant.launch.Launcher -lib lib %1 %2 %3 %4 %5

Deleted: trunk/Hibernate3/build.sh
===================================================================
--- trunk/Hibernate3/build.sh	2007-05-24 19:06:06 UTC (rev 11562)
+++ trunk/Hibernate3/build.sh	2007-05-25 20:19:29 UTC (rev 11563)
@@ -1,2 +0,0 @@
-#!/bin/sh
-java -cp "lib/ant-launcher-1.6.5.jar" org.apache.tools.ant.launch.Launcher -lib lib "$@"

Deleted: trunk/Hibernate3/build.xml
===================================================================
--- trunk/Hibernate3/build.xml	2007-05-24 19:06:06 UTC (rev 11562)
+++ trunk/Hibernate3/build.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -1,782 +0,0 @@
-<!--
-
-	Hibernate ANT build script.
-
-	(Originally contributed by Fabricio Goncalves)
-
--->
-
-<project name="Hibernate3" default="jar" basedir=".">
-
-    <!-- ################################################################## -->
-    <!-- ################## Property definitions ########################## -->
-    <!-- ################################################################## -->
-
-    <!-- Give user a chance to override without editing this file or typing -D -->
-	<property file="build.properties"/>
-	<property file="${user.home}/.ant.properties"/>
-
-	<!-- Name of project and version, used to create filenames -->
-	<property name="Name" value="Hibernate"/>
-	<property name="name" value="hibernate"/>
-	<property name="name2" value="hibernate3"/>
-	<property name="version.major" value="3"/>
-	<property name="version.minor" value="2"/>
-	<property name="version.micro" value="0"/>
-    <property name="version.qualifier" value="cr3"/>
-    <property name="version.full" value="${version.major}.${version.minor}.${version.micro}.${version.qualifier}"/>
-    <property name="version.major_minor" value="${version.major}.${version.minor}"/>
-    <property name="fullname" value="${name}-${version.full}"/>
-
-    <!-- Various SCM-controlled directories -->
-    <property name="dir.src" value="src" />
-    <property name="dir.test" value="test" />
-    <property name="dir.grammar" value="grammar" />
-    <property name="dir.etc" value="etc" />
-    <property name="dir.lib" value="lib" />
-    <property name="dir.jdbc" value="jdbc" />
-	<property name="dir.doc" value="doc"/>
-	<property name="dir.doc.api" value="${dir.doc}/api"/>
-	<property name="dir.doc.ref" value="${dir.doc}/reference"/>
-	<property name="dir.eg" value="eg"/>
-    <property name="dir.props" value="${dir.etc}" />
-
-    <!-- Define the build directory layout -->
-    <property name="dir.build" value="build" />
-    <property name="dir.out.classes" value="${dir.build}/classes" />
-    <property name="dir.out.test-classes" value="${dir.build}/testclasses" />
-    <property name="dir.out.generated-source" value="${dir.build}/gensrc" />
-    <property name="dir.out.antlr-package" value="${dir.out.generated-source}/org/hibernate/hql/antlr" />
-    <property name="dir.out.junit" value="${dir.build}/testout" />
-    <property name="dir.out.junit-reports" value="${dir.build}/test-reports" />
-    <property name="dir.out.perf-test" value="${dir.build}/testout-perf" />
-	<property name="dir.out.clover" value="${dir.build}/cloverout" />
-	<property name="dir.out.dist" value="${dir.build}/cloverout" />
-    <property name="dir.out.db" value="${dir.build}/db" />
-    <property name="dir.out.doc" value="${dir.build}/doc" />
-    <property name="dir.out.eg" value="${dir.build}/eg" />
-    <property name="dir.dist" value="${dir.build}/dist" />
-
-    <!-- Define various operational options -->
-	<property name="javadoc.url.jse" value="http://java.sun.com/j2se/1.3/docs/api"/>
-	<property name="javac.debug" value="on"/>
-	<property name="javac.optimize" value="off"/>
-	<property name="javac.target" value="1.4"/>
-	<property name="javac.source" value="1.4"/>
-	<property name="jar.driver" value="${dir.jdbc}/hsqldb.jar"/>
-	<property name="jar.clover" value="${ant.home}/lib/clover.jar"/>
-
-    <!-- JAR and dist file names -->
-    <property name="jar.name" value="${name2}"/>
-
-    <property name="hibernate.test.validatefailureexpected" value="false"/>
-
-    <!-- fileset definition for the lib directory -->
-    <fileset id="fs.lib" dir="${dir.lib}">
-        <include name="**/*.jar" />
-    </fileset>
-    <path id="path.lib">
-        <fileset refid="fs.lib" />
-	</path>
-
-    <!-- path definition for the JDBC driver(s) -->
-    <path id="path.jdbc">
-        <!-- By default include everything in the ${dir.jdbc} directory -->
-        <fileset dir="${dir.jdbc}">
-            <include name="**/*.jar" />
-            <include name="**/*.zip" />
-        </fileset>
-        <!-- And the explicitly defined jar.driver property (used by the CC scripts) -->
-        <pathelement path="${jar.driver}"/>
-    </path>
-    <!-- allows external definition of the JDBC classpath fragment -->
-    <property name="hibernate.test.jdbc.fs.importFile" value="doNotImport" />
-    <import file="${hibernate.test.jdbc.fs.importFile}" optional="true" />
-
-    <!-- patternset for insturmentation-eligible resources -->
-	<patternset id="ps.instrument.domain">
-		<include name="org/hibernate/test/instrument/domain/*" />
-        <exclude name="**/*.hbm.xml" />
-    </patternset>
-
-
-    <!-- ################################################################## -->
-    <!-- ############################# Tasks ############################## -->
-    <!-- ################################################################## -->
-
-    <taskdef name="splash" classname="org.apache.tools.ant.taskdefs.optional.splash.SplashTask">
-        <classpath refid="path.lib"/>
-    </taskdef>
-
-	<taskdef name="junit" classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask">
-		<classpath refid="path.lib"/>
-	</taskdef>
-
-	<taskdef name="junitreport" classname="org.apache.tools.ant.taskdefs.optional.junit.XMLResultAggregator">
-		<classpath refid="path.lib"/>
-	</taskdef>
-
-	<taskdef resource="clovertasks"/>
-
-
-    <!-- ################################################################## -->
-    <!-- ############################ Targets ############################# -->
-    <!-- ################################################################## -->
-
-    <!-- Various 'preparation targets -->
-
-    <target name="splash" unless="nosplash" description="Display the logo">
-		<property name="splash.dir" location="."/>
-		<splash imageurl="file:${splash.dir}/hibernate_logo.gif" showduration="0"/>
-	</target>
-
-	<target name="init" depends="splash" description="Initialize the build">
-		<tstamp>
-			<format property="now" pattern="yyyy-MM-dd hh:mm:ss"/>
-		</tstamp>
-		<echo message="Build ${Name}-${version.full} (${now})"/>
-		<echo message="JDK version: ${ant.java.version}"/>
-	</target>
-
-
-    <!-- Various 'clean' targets -->
-
-    <target name="clean" depends="init" description="Cleans up build directories">
-		<delete dir="${dir.build}"/>
-	</target>
-
-	<target name="cleantestdb" depends="init" description="Clean up the test file-based database directories">
-		<delete dir="${dir.out.db}" />
-	</target>
-
-
-    <!-- The ANTLR related targets -->
-
-    <target name="init.antlr" depends="init" description="Check ANTLR dependencies.">
-        <uptodate property="antlr.isUpToDate" targetfile="${dir.out.antlr-package}/.antlr_run">
-			<srcfiles dir="${dir.grammar}" includes="*.g"/>
-		</uptodate>
-	</target>
-
-	<target name="antlr" depends="init.antlr" unless="antlr.isUpToDate" description="Generate ANTLR parsers.">
-        <taskdef name="antlrtask" classname="org.apache.tools.ant.taskdefs.optional.ANTLR">
-            <classpath>
-                <fileset dir="${dir.lib}">
-                    <include name="ant-antlr-*.jar"/>
-                    <include name="antlr-*.jar"/>
-                </fileset>
-            </classpath>
-        </taskdef>
-        <mkdir dir="${dir.out.antlr-package}" />
-		<antlrtask target="${dir.grammar}/hql.g" outputdirectory="${dir.out.antlr-package}" />
-		<antlrtask target="${dir.grammar}/hql-sql.g" outputdirectory="${dir.out.antlr-package}" />
-		<antlrtask target="${dir.grammar}/sql-gen.g" outputdirectory="${dir.out.antlr-package}" />
-		<touch file="${dir.out.antlr-package}/.antlr_run"/>
-	</target>
-
-	<target name="cleanantlr" depends="init" description="Clean up the generated ANTLR parsers.">
-		<delete dir="${dir.out.antlr-package}"/>
-	</target>
-
-	<target name="antlr.regen" depends="init,cleanantlr,antlr" description="Regenerate all ANTLR generated code." />
-
-    <target name="antlr.bnf" depends="init" description="Generate BNF diagram for HQL">
-       <mkdir dir="${dir.out.doc}/other"/>
-       <property name="bnf.grammar" location="${dir.grammar}/hql.g"/>
-
-       <java dir="${dir.out.doc}/other" classname="net.mark_malakanov.sdg2.Main" classpathref="path.lib" fork="true">
-           <jvmarg line="-Xmx512M"/>
-           <arg line="-blind"/>
-           <arg line="-savehtml hql-bnf.html"/>
-           <arg line="-savehtmltitle Hibernate ${version.full} HQL"/>
-           <arg line="${bnf.grammar}"/>
-       </java>
-    </target>
-
-
-    <!-- Compilation targets -->
-
-    <target name="compile" depends="init,antlr" description="Compile the Java source code">
-		<mkdir dir="${dir.out.classes}"/>
-		<available classname="org.eclipse.core.launcher.Main" property="build.compiler"
-                   value="org.eclipse.jdt.core.JDTCompilerAdapter" classpath="${java.class.path}"/>
-		<javac destdir="${dir.out.classes}"
-               classpathref="path.lib"
-               debug="${javac.debug}"
-               optimize="${javac.optimize}"
-               target="${javac.target}"
-               source="${javac.source}"
-               nowarn="on">
-            <src path="${dir.src}"/>
-			<src path="${dir.out.generated-source}"/>
-		</javac>
-		<copy todir="${dir.out.classes}">
-			<fileset dir="${dir.src}">
-                <include name="**/*.dtd" />
-                <include name="**/*.xml" />
-                <include name="**/*.xslt" />
-			</fileset>
-		</copy>
-	</target>
-
-	<target name="compiletest" depends="compile" description="Compile the tests">
-		<mkdir dir="${dir.out.test-classes}"/>
-		<available classname="org.eclipse.core.launcher.Main" property="build.compiler"
-                   value="org.eclipse.jdt.core.JDTCompilerAdapter" classpath="${java.class.path}"/>
-		<javac destdir="${dir.out.test-classes}"
-               debug="${javac.debug}"
-               optimize="${javac.optimize}"
-               target="${javac.target}"
-               source="${javac.source}"
-               nowarn="on">
-			<classpath>
-				<path refid="path.lib" />
-				<pathelement path="${dir.out.classes}" />
-			</classpath>
-            <src path="${dir.test}" />
-        </javac>
-		<copy todir="${dir.out.test-classes}">
-			<fileset dir="${dir.test}">
-                <include name="**/*.xml" />
-                <include name="**/*.properties" />
-			</fileset>
-		</copy>
-	</target>
-
-
-    <!-- testsuite targets -->
-
-	<target name="junitreport" depends="splash,junit" description="Run tests and create JUnit report (requires driver.jar property)">
-        <delete dir="${dir.out.junit-reports}" />
-        <mkdir dir="${dir.out.junit-reports}" />
-        <junitreport todir="${dir.out.junit-reports}">
-			<fileset dir="${dir.out.junit}">
-				<include name="TEST-*.xml"/>
-			</fileset>
-			<report format="frames" todir="${dir.out.junit-reports}"/>
-		</junitreport>
-	</target>
-
-    <target name="junit" depends="junit.prepare">
-        <sequential>
-            <antcall target="junit.standard" />
-            <antcall target="junit.instrument.cglib" />
-            <antcall target="junit.instrument.javassist" />
-        </sequential>
-    </target>
-
-    <target name="junit.prepare" depends="cleantestdb,compiletest">
-        <delete dir="${dir.out.junit}"/>
-        <mkdir dir="${dir.out.junit}"/>
-    </target>
-
-    <target name="junit.standard" depends="junit.prepare" description="Run the test suite (requires driver.jar property)">
-        <path id="selector.classpath">
-            <!--
-                the selector needs all of this because it actually gets the suite
-                from AllTests and then performs the filtering based on that
-            -->
-            <fileset refid="fs.lib" />
-            <path refid="path.jdbc" />
-            <pathelement path="${dir.out.classes}"/>
-            <pathelement path="${dir.out.test-classes}"/>
-            <pathelement path="${dir.props}"/>
-        </path>
-
-        <junit printsummary="yes" dir="${basedir}" maxmemory="256M" fork="yes" forkmode="perBatch">
-            <jvmarg value="-Dhibernate.test.validatefailureexpected=${hibernate.test.validatefailureexpected}"/>
-			<classpath>
-                <fileset refid="fs.lib" />
-                <path refid="path.jdbc" />
-                <pathelement path="${dir.props}"/>
-                <pathelement path="${dir.out.classes}"/>
-                <pathelement path="${dir.out.test-classes}"/>
-				<pathelement path="${jar.clover}"/>
-			</classpath>
-			<formatter type="plain"/>
-			<formatter type="xml"/>
-            <batchtest todir="${dir.out.junit}" haltonfailure="no">
-                <fileset dir="${dir.out.test-classes}">
-                    <include name="org/hibernate/test/**/*Test.class" />
-                    <!-- exclude the build-time instrumentation tasks as we will be running them manually shortly -->
-                    <exclude name="org/hibernate/test/instrument/buildtime/*" />
-                    <!--custom selector to make sure only those tests in the AllTests suite get picked up here -->
-                    <custom classname="org.hibernate.test.TestSelector" classpathref="selector.classpath" />
-				</fileset>
-			</batchtest>
-		</junit>
-    </target>
-
-    <target name="junit.instrument" depends="junit.prepare,junit.instrument.cglib,junit.instrument.javassist" />
-
-    <target name="junit.instrument.cglib" depends="instrument.cglib">
-        <mkdir dir="${dir.out.junit}"/>
-		<junit printsummary="yes" maxmemory="256M" fork="yes">
-			<jvmarg value="-Dhibernate.test.validatefailureexpected=${hibernate.test.validatefailureexpected}"/>
-			<classpath>
-                <fileset refid="fs.lib" />
-                <path refid="path.jdbc" />
-                <pathelement path="${dir.out.classes}"/>
-                <pathelement path="${dir.out.test-classes}"/>
-                <pathelement path="${dir.props}"/>
-				<pathelement path="${jar.clover}"/>
-			</classpath>
-			<formatter type="plain"/>
-			<formatter type="xml"/>
-            <test name="org.hibernate.test.instrument.buildtime.InstrumentTest"
-                    outfile="TEST-CGLIB-org.hibernate.test.instrument.buildtime.InstrumentTest"
-                    todir="${dir.out.junit}"
-                    haltonerror="false"
-                    haltonfailure="false" />
-		</junit>
-    </target>
-
-    <target name="junit.instrument.javassist" depends="instrument.javassist">
-        <mkdir dir="${dir.out.junit}"/>
-		<junit printsummary="yes" maxmemory="256M" fork="yes">
-			<jvmarg value="-Dhibernate.test.validatefailureexpected=${hibernate.test.validatefailureexpected}"/>
-			<classpath>
-                <fileset refid="fs.lib" />
-                <path refid="path.jdbc" />
-                <pathelement path="${dir.out.classes}"/>
-                <pathelement path="${dir.out.test-classes}"/>
-                <pathelement path="${dir.props}"/>
-				<pathelement path="${jar.clover}"/>
-			</classpath>
-			<formatter type="plain"/>
-			<formatter type="xml"/>
-            <test name="org.hibernate.test.instrument.buildtime.InstrumentTest"
-                    outfile="TEST-JAVASSIST-org.hibernate.test.instrument.buildtime.InstrumentTest"
-                    todir="${dir.out.junit}"
-                    haltonerror="false"
-                    haltonfailure="false" />
-		</junit>
-    </target>
-
-    <!-- Run a single unit test. -->
-	<target name="junitsingle" depends="cleantestdb,compiletest" description="Run a single test suite (requires testname and jar.driver properties)">
-        <delete dir="${dir.out.junit}"/>
-        <mkdir dir="${dir.out.junit}"/>
-        <junit printsummary="yes" fork="yes" haltonfailure="yes" dir="${basedir}">
-			<classpath>
-                <fileset refid="fs.lib" />
-                <path refid="path.jdbc" />
-                <pathelement path="${dir.out.classes}"/>
-                <pathelement path="${dir.out.test-classes}"/>
-                <pathelement path="${dir.props}"/>
-                <pathelement path="${jar.clover}"/>
-            </classpath>
-            <!-- support for JDWP debug 
-            <jvmarg value="-Xdebug"/>
-            <jvmarg value="-Xnoagent"/>
-            <jvmarg value="-Djava.compiler=NONE"/>
-            <jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=localhost:5005"/>
-            -->
-			<formatter type="plain"/>
-			<formatter type="xml"/>
-			<test fork="yes" todir="${dir.out.junit}" haltonfailure="no" name="${testname}"/>
-		</junit>
-	</target>
-
-    <target name="perf" depends="cleantestdb,compiletest" description="Run the performance tests">
-        <delete dir="${dir.out.perf-test}"/>
-        <mkdir dir="${dir.out.perf-test}"/>
-		<junit printsummary="yes" maxmemory="256M" fork="yes" haltonfailure="yes" dir="${basedir}">
-			<jvmarg value="-Dhibernate.test.validatefailureexpected=${hibernate.test.validatefailureexpected}"/>
-			<classpath>
-                <fileset refid="fs.lib" />
-                <path refid="path.jdbc" />
-                <pathelement path="${dir.out.classes}"/>
-                <pathelement path="${dir.out.test-classes}"/>
-                <pathelement path="${dir.props}"/>
-				<pathelement path="${jar.clover}"/>
-			</classpath>
-			<formatter type="plain"/>
-			<test name="org.hibernate.test.NewPerformanceTest" todir="${dir.out.perf-test}" haltonfailure="no"/>
-			<test name="org.hibernate.test.NewerPerformanceTest" todir="${dir.out.perf-test}" haltonfailure="no"/>
-			<test name="org.hibernate.test.PerformanceTest" todir="${dir.out.perf-test}" haltonfailure="no"/>
-		</junit>
-	</target>
-
-	<target name="eg" description="Compile and run the simple example">
-		<!-- works only in distribution, not in CVS tree; see 'eg.inline' target -->
-        <mkdir dir="${dir.out.eg}" />
-
-        <available classname="org.eclipse.core.launcher.Main"
-			    property="build.compiler"
-			    value="org.eclipse.jdt.core.JDTCompilerAdapter"
-			    classpath="${java.class.path}"/>
-		<javac  srcdir="${dir.eg}"
-			    destdir="${dir.out.eg}"
-			    debug="${javac.debug}"
-			    optimize="${javac.optimize}"
-                target="${javac.target}"
-                source="${javac.source}"
-			    nowarn="on">
-			<classpath>
-				<pathelement path="${dir.build}/${jar.name}.jar"/>
-                <fileset refid="fs.lib" />
-			</classpath>
-		</javac>
-
-        <copy todir="${dir.out.eg}">
-            <fileset dir="${dir.eg}">
-                <include name="**/*.xml" />
-            </fileset>
-        </copy>
-
-		<echo message="remember to place your JDBC driver in the lib directory"/>
-        <java classname="org.hibernate.auction.Main" fork="true" failonerror="true">
-			<classpath>
-                <fileset refid="fs.lib" />
-				<pathelement path="${dir.out.eg}" />
-				<pathelement path="${dir.build}/${jar.name}.jar"/>
-				<pathelement path="${dir.etc}" />
-			</classpath>
-		</java>
-
-        <echo message="Please follow the Getting Started road map: http://www.hibernate.org/152.html"/>
-	</target>
-
-    <target name="eg.inline" depends="jar" description="Compile and run the simple example utilizing the build structure">
-        <mkdir dir="${dir.out.eg}" />
-
-        <available classname="org.eclipse.core.launcher.Main"
-			    property="build.compiler"
-			    value="org.eclipse.jdt.core.JDTCompilerAdapter"
-			    classpath="${java.class.path}"/>
-		<javac  srcdir="${dir.eg}"
-			    destdir="${dir.out.eg}"
-			    debug="${javac.debug}"
-			    optimize="${javac.optimize}"
-                target="${javac.target}"
-                source="${javac.source}"
-			    nowarn="on">
-			<classpath>
-				<pathelement path="${dir.build}/${jar.name}.jar"/>
-                <fileset refid="fs.lib" />
-			</classpath>
-		</javac>
-
-        <copy todir="${dir.out.eg}">
-            <fileset dir="${dir.eg}">
-                <include name="**/*.xml" />
-            </fileset>
-        </copy>
-
-		<java classname="org.hibernate.auction.Main" fork="true" failonerror="true">
-			<classpath>
-                <fileset refid="fs.lib" />
-                <path refid="path.jdbc" />
-				<pathelement path="${dir.out.eg}" />
-				<pathelement path="${dir.build}/${jar.name}.jar"/>
-				<pathelement path="${dir.props}" />
-			</classpath>
-		</java>
-    </target>
-
-
-    <!-- Instrumentation tasks -->
-
-    <target name="instrument.prepare">
-        <delete>
-            <fileset dir="${dir.out.test-classes}">
-                <patternset refid="ps.instrument.domain" />
-            </fileset>
-        </delete>
-    </target>
-
-    <target name="instrument.cglib" depends="instrument.prepare,compiletest" description="Performs cglib-based instrumentation">
-		<taskdef name="instrument" classname="org.hibernate.tool.instrument.cglib.InstrumentTask">
-			<classpath path="${dir.out.classes}"/>
-			<classpath refid="path.lib"/>
-		</taskdef>
-
-		<available classname="org.eclipse.core.launcher.Main" property="build.compiler"
-                   value="org.eclipse.jdt.core.JDTCompilerAdapter" classpath="${java.class.path}"/>
-		<javac destdir="${dir.out.test-classes}"
-               debug="${javac.debug}"
-               optimize="${javac.optimize}"
-               target="${javac.target}"
-               source="${javac.source}"
-               nowarn="on">
-			<classpath>
-				<path refid="path.lib" />
-				<pathelement path="${dir.out.classes}" />
-			</classpath>
-            <src path="${dir.test}" />
-            <patternset refid="ps.instrument.domain" />
-        </javac>
-
-        <instrument verbose="true">
-            <fileset dir="${dir.out.test-classes}">
-                <patternset refid="ps.instrument.domain" />
-            </fileset>
-        </instrument>
-    </target>
-
-    <target name="instrument.javassist" depends="instrument.prepare,compiletest" description="Performs javassist-based instrumentation">
-		<taskdef name="instrument" classname="org.hibernate.tool.instrument.javassist.InstrumentTask">
-			<classpath path="${dir.out.classes}"/>
-			<classpath refid="path.lib"/>
-		</taskdef>
-
-		<available classname="org.eclipse.core.launcher.Main" property="build.compiler"
-                   value="org.eclipse.jdt.core.JDTCompilerAdapter" classpath="${java.class.path}"/>
-		<javac destdir="${dir.out.test-classes}"
-               debug="${javac.debug}"
-               optimize="${javac.optimize}"
-               target="${javac.target}"
-               source="${javac.source}"
-               nowarn="on">
-			<classpath>
-				<path refid="path.lib" />
-				<pathelement path="${dir.out.classes}" />
-			</classpath>
-            <src path="${dir.test}" />
-            <patternset refid="ps.instrument.domain" />
-        </javac>
-
-        <instrument verbose="true">
-            <fileset dir="${dir.out.test-classes}">
-                <patternset refid="ps.instrument.domain" />
-            </fileset>
-        </instrument>
-    </target>
-
-
-    <!-- Distribution related targets -->
-
-	<target name="versioncheck" description="Check version.properties up against lib directory">
-        <!-- If versioncheck fails two things can be "out-of-sync":
-
-            1) '<libraryname> not found in fileset of libraries!' means that version.properties
-            defines a library, but this library is not in the lib directory.  Resolution: add
-            the library to the lib directory or remove the definiton from version.properties
-
-            2) '<filename> not listed in version.properties' means a file was found in the lib
-            directory, but not in version.properties; Resolution: add the library to the
-            version.properties or remove the library from the libraries.
-         -->
-		<taskdef classname="versioncheck.VersionCheckTask" classpath="${dir.lib}/versioncheck.jar" name="versioncheck"/>
-		<mkdir dir="${dir.build}/versioncheck" />
-		<versioncheck versionfile="${dir.lib}/version.properties" output="${dir.build}/versioncheck/_README.txt">
-			<fileset dir="${dir.lib}">
-				<include name="**/*.zip" />
-				<include name="**/*.jar" />
-			</fileset>
-		</versioncheck>
-	</target>
-
-	<target name="jar" depends="compile" description="Build the distribution .jar file">
-		<mkdir dir="${dir.build}"/>
-
-        <jar jarfile="${dir.build}/${jar.name}.jar" basedir="${dir.out.classes}">
-			<include name="org/hibernate/**/*.class" />
-            <include name="org/hibernate/*.dtd"/>
-			<manifest>
-                <attribute name="Implementation-Title" value="Hibernate3"/>
-                <attribute name="Implementation-Version" value="${version.full}"/>
-                <attribute name="Implementation-Vendor" value="hibernate.org"/>
-                <attribute name="Hibernate-Version" value="${version.full}"/>
-			</manifest>
-		</jar>
-
-        <!-- currently for testing *only* -->
-        <jar jarfile="${dir.build}/hibernate3-client.jar">
-            <zipfileset src="${dir.build}/${jar.name}.jar">
-                <include name="org/hibernate/AssertionFailure.class"/>
-                <include name="org/hibernate/**/*Exception.class"/>
-                <include name="org/hibernate/collection/**"/>
-                <include name="org/hibernate/exception/Nestable*.class"/>
-                <include name="org/hibernate/exception/ExceptionUtils.class"/>
-                <include name="org/hibernate/engine/SessionImplementor.class"/>
-                <include name="org/hibernate/loader/CollectionAliases.class"/>
-                <include name="org/hibernate/persister/collection/**"/>
-                <include name="org/hibernate/pretty/MessageHelper.class"/>
-                <include name="org/hibernate/type/Type.class"/>
-                <include name="org/hibernate/EntityMode.class"/>
-                <include name="org/hibernate/util/**"/>
-                <include name="org/hibernate/proxy/**"/>
-            </zipfileset>
-			<manifest>
-                <attribute name="Implementation-Title" value="Hibernate3 Client"/>
-                <attribute name="Implementation-Version" value="${version.full}"/>
-                <attribute name="Implementation-Vendor" value="hibernate.org"/>
-                <attribute name="Hibernate-Version" value="${version.full}"/>
-			</manifest>
-        </jar>
-    </target>
-
-	<target name="dist" depends="init,versioncheck,jar,javadoc,refdoc,antlr.bnf"
-            description="Build everything and package">
-        <mkdir dir="${dir.dist}" />
-
-        <!-- prepare build.xml -->
-		<copy file="${basedir}/build.xml" todir="${dir.dist}"/>
-		<replace file="${dir.dist}/build.xml">
-			<replacetoken><![CDATA[../${name}-${version}]]></replacetoken>
-			<replacevalue><![CDATA[../${name}]]></replacevalue>
-		</replace>
-		<replace file="${dir.dist}/build.xml">
-			<replacetoken><![CDATA[name="dir.jdbc" value="jdbc"]]></replacetoken>
-			<replacevalue><![CDATA[name="dir.jdbc" value="lib"]]></replacevalue>
-		</replace>
-
-        <zip zipfile="${dir.dist}/${fullname}.zip">
-            <zipfileset prefix="${name}-${version.major_minor}/doc/reference" dir="${dir.doc.ref}/build" />
-            <zipfileset prefix="${name}-${version.major_minor}/doc/tutorial" dir="${dir.doc.ref}/tutorial" >
-				<include name="src/**" />
-				<include name="lib/**" />
-				<include name="build.xml" />
-				<include name="runCleanDatabase.sh" />
-				<include name="web.xml" />
-            </zipfileset>
-		    <zipfileset prefix="${name}-${version.major_minor}/doc/other" dir="${dir.doc}/other" />
-            <zipfileset prefix="${name}-${version.major_minor}/doc" dir="${dir.out.doc}" />
-            <zipfileset prefix="${name}-${version.major_minor}/eg" dir="${dir.eg}"/>
-			<zipfileset prefix="${name}-${version.major_minor}/etc" dir="${dir.etc}"/>
-			<zipfileset prefix="${name}-${version.major_minor}/grammar" dir="${dir.grammar}"/>
-			<zipfileset prefix="${name}-${version.major_minor}/lib" dir="${dir.lib}"/>
-			<zipfileset prefix="${name}-${version.major_minor}/lib" dir="${dir.build}/versioncheck"/>
-			<zipfileset prefix="${name}-${version.major_minor}/src" dir="${dir.src}"/>
-			<zipfileset prefix="${name}-${version.major_minor}/test" dir="${dir.test}"/>
-            <zipfileset prefix="${name}-${version.major_minor}" file="${basedir}/readme.txt" />
-            <zipfileset prefix="${name}-${version.major_minor}" file="${basedir}/lgpl.txt" />
-            <zipfileset prefix="${name}-${version.major_minor}" file="${basedir}/changelog.txt" />
-            <zipfileset prefix="${name}-${version.major_minor}" file="${basedir}/build.bat" />
-            <zipfileset prefix="${name}-${version.major_minor}" file="${basedir}/build.sh" />
-            <zipfileset prefix="${name}-${version.major_minor}" file="${basedir}/hibernate_logo.gif" />
-            <zipfileset prefix="${name}-${version.major_minor}" file="${dir.dist}/build.xml" />
-            <zipfileset prefix="${name}-${version.major_minor}" file="${dir.build}/${jar.name}.jar" />
-        </zip>
-        <checksum file="${dir.dist}/${fullname}.zip" algorithm="MD5" fileext=".md5.txt"/>
-
-        <tar tarfile="${dir.dist}/${fullname}.tar">
-            <tarfileset prefix="${name}-${version.major_minor}/doc/reference" dir="${dir.doc.ref}/build" />
-            <tarfileset prefix="${name}-${version.major_minor}/doc/tutorial" dir="${dir.doc.ref}/tutorial" >
-				<include name="src/**" />
-				<include name="lib/**" />
-				<include name="build.xml" />
-				<include name="runCleanDatabase.sh" />
-            </tarfileset>
-		    <tarfileset prefix="${name}-${version.major_minor}/doc/other" dir="${dir.doc}/other" />
-            <tarfileset prefix="${name}-${version.major_minor}/doc" dir="${dir.out.doc}" />
-            <tarfileset prefix="${name}-${version.major_minor}/eg" dir="${dir.eg}"/>
-			<tarfileset prefix="${name}-${version.major_minor}/etc" dir="${dir.etc}"/>
-			<tarfileset prefix="${name}-${version.major_minor}/grammar" dir="${dir.grammar}"/>
-			<tarfileset prefix="${name}-${version.major_minor}/lib" dir="${dir.lib}"/>
-			<tarfileset prefix="${name}-${version.major_minor}/lib" dir="${dir.build}/versioncheck"/>
-			<tarfileset prefix="${name}-${version.major_minor}/src" dir="${dir.src}"/>
-			<tarfileset prefix="${name}-${version.major_minor}/test" dir="${dir.test}"/>
-            <tarfileset prefix="${name}-${version.major_minor}" file="${basedir}/readme.txt" />
-            <tarfileset prefix="${name}-${version.major_minor}" file="${basedir}/lgpl.txt" />
-            <tarfileset prefix="${name}-${version.major_minor}" file="${basedir}/changelog.txt" />
-            <tarfileset prefix="${name}-${version.major_minor}" file="${basedir}/build.bat" />
-            <tarfileset prefix="${name}-${version.major_minor}" file="${basedir}/build.sh" />
-            <tarfileset prefix="${name}-${version.major_minor}" file="${basedir}/hibernate_logo.gif" />
-            <tarfileset prefix="${name}-${version.major_minor}" file="${dir.dist}/build.xml" />
-            <tarfileset prefix="${name}-${version.major_minor}" file="${dir.build}/${jar.name}.jar" />
-		</tar>
-		<gzip src="${dir.dist}/${fullname}.tar" zipfile="${dir.dist}/${fullname}.tar.gz"/>
-        <checksum file="${dir.dist}/${fullname}.tar.gz" algorithm="MD5" fileext=".md5.txt"/>
-
-        <delete file="${dir.dist}/${fullname}.tar"/>
-        <delete file="${dir.dist}/build.xml"/>
-    </target>
-
-    <target name="dist.complete" depends="init,versioncheck,jar,javadoc,refdoc,antlr.bnf"
-            description="Build and package everything, and run test suite and eg example">
-
-        <!-- perform a call to the junit target -->
-        <antcall target="junitreport" />
-
-        <!-- perform a call to the eg.inline target -->
-        <antcall target="eg.inline" />
-
-        <antcall target="dist" />
-    </target>
-
-
-    <!-- Documentation related targets -->
-
-    <target name="javadoc" description="Compile the Javadoc API documentation to dist dir" depends="splash,antlr">
-		<mkdir dir="${dir.out.doc}/api"/>
-		<javadoc classpathref="path.lib"
-                destdir="${dir.out.doc}/api"
-                use="true"
-                protected="true"
-                version="true"
-                doctitle="${Name} API Documentation (${version.full})"
-                windowtitle="${Name} API Documentation"
-                Overview="${dir.doc.api}/package.html"
-                stylesheetfile="${dir.doc.api}/jdstyle.css"
-                link="${javadoc.url.jse}">
-			<packageset dir="${dir.out.generated-source}" defaultexcludes="yes">
-				<include name="org/hibernate/**" />
-			</packageset>
-			<packageset dir="${dir.src}" defaultexcludes="yes">
-				<include name="org/hibernate/**" />
-			</packageset>
-			<group title="Core API"
-				packages="org.hibernate:org.hibernate.classic:org.hibernate.criterion:org.hibernate.metadata:org.hibernate.cfg:org.hibernate.usertype"/>
-			<group title="Extension API"
-				packages="org.hibernate.id:org.hibernate.connection:org.hibernate.transaction:org.hibernate.type:org.hibernate.dialect*:org.hibernate.cache*:org.hibernate.event*:org.hibernate.action:org.hibernate.property:org.hibernate.loader*:org.hibernate.persister*:org.hibernate.proxy:org.hibernate.tuple:org.hibernate.transform:org.hibernate.collection:org.hibernate.jdbc"/>
-			<group title="Miscellaneous API"
-				packages="org.hibernate.stat:org.hibernate.tool.hbm2ddl:org.hibernate.jmx:org.hibernate.mapping:org.hibernate.tool.instrument"/>
-			<group title="Internal Implementation"
-				packages="org.hibernate.engine:org.hibernate.impl:org.hibernate.sql:org.hibernate.lob:org.hibernate.util:org.hibernate.exception:org.hibernate.hql:org.hibernate.hql.ast:org.hibernate.hql.antlr:org.hibernate.hql.classic:org.hibernate.intercept:org.hibernate.secure:org.hibernate.pretty"/>
-		</javadoc>
-		<copy file="${dir.doc.api}/package.html" todir="${dir.out.doc}/api"/>
-	</target>
-
-	<target name="refdoc" depends="splash" description="Generate and copy reference documentation">
-		<ant dir="${dir.doc.ref}" inheritall="false" target="all.doc"/>
-	</target>
-
-
-    <!-- miscellaneous targets -->
-
-	<target name="checkstyle" description="Check coding style">
-        <taskdef resource="checkstyletask.properties">
-            <classpath refid="path.lib"/>
-        </taskdef>
-		<checkstyle config="checkstyle_checks.xml">
-			<fileset dir="${src.dir}">
-				<include name="**/*.java"/>
-			</fileset>
-			<formatter type="plain"/>
-		</checkstyle>
-	</target>
-
-	<target name="with.clover">
-		<clover-setup initString="clover_coverage.db"/>
-	</target>
-
-	<target name="cloverreport.html" depends="with.clover" description="Generate a clover report from the current clover database.">
-		<clover-report>
-			<current outfile="${clover.out.dir}">
-				<format type="html"/>
-			</current>
-		</clover-report>
-	</target>
-
-	<target name="cloverreport"
-            depends="with.clover,junitreport,cloverreport.html"
-            description="Run the tests and generate a clover report" />
-
-    <target name="prepare-dir-up" depends="jar">
-        <!-- for backwards compatibility with where the tools expect to find the jar and libs -->
-    	<property name="targetdir" value="../${name}-${version.major_minor}"/>
-        <mkdir dir="${targetdir}" />
-        <mkdir dir="${targetdir}/lib" />
-
-        <copy todir="${targetdir}" file="${dir.build}/${jar.name}.jar" />
-        <copy todir="${targetdir}/lib">
-            <fileset dir="${dir.lib}" />
-        </copy>
-
-    	<copy todir="${targetdir}/doc/api" file="${dir.doc.api}/jdstyle.css"/>
-    </target>
-
-</project>

Added: trunk/Hibernate3/cache-ehcache/pom.xml
===================================================================
--- trunk/Hibernate3/cache-ehcache/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/cache-ehcache/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.hibernate</groupId>
+    <artifactId>hibernate-ehcache</artifactId>
+    <packaging>jar</packaging>
+    <name>Hibernate Ehcache integration</name>
+    <description>Integration of Hibernate with Ehcache</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>net.sf.ehcache</groupId>
+            <artifactId>ehcache</artifactId>
+            <version>1.2.3</version>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

Added: trunk/Hibernate3/cache-ehcache/src/main/java/org/hibernate/cache/EhCache.java
===================================================================
--- trunk/Hibernate3/cache-ehcache/src/main/java/org/hibernate/cache/EhCache.java	                        (rev 0)
+++ trunk/Hibernate3/cache-ehcache/src/main/java/org/hibernate/cache/EhCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,275 @@
+//$Id: EhCache.java 10717 2006-11-03 19:05:21Z max.andersen at jboss.com $
+/**
+ *  Copyright 2003-2006 Greg Luck, Jboss Inc
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.hibernate.cache;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Element;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * EHCache plugin for Hibernate
+ * <p/>
+ * EHCache uses a {@link net.sf.ehcache.store.MemoryStore} and a
+ * {@link net.sf.ehcache.store.DiskStore}.
+ * The {@link net.sf.ehcache.store.DiskStore} requires that both keys and values be {@link java.io.Serializable}.
+ * However the MemoryStore does not and in ehcache-1.2 nonSerializable Objects are permitted. They are discarded
+ * if an attempt it made to overflow them to Disk or to replicate them to remote cache peers.
+ *
+ * @author Greg Luck
+ * @author Emmanuel Bernard
+ */
+public class EhCache implements Cache {
+	private static final Log log = LogFactory.getLog( EhCache.class );
+
+	private static final int SIXTY_THOUSAND_MS = 60000;
+
+	private net.sf.ehcache.Cache cache;
+
+	/**
+	 * Creates a new Hibernate pluggable cache based on a cache name.
+	 * <p/>
+	 *
+	 * @param cache The underlying EhCache instance to use.
+	 */
+	public EhCache(net.sf.ehcache.Cache cache) {
+		this.cache = cache;
+	}
+
+	/**
+	 * Gets a value of an element which matches the given key.
+	 *
+	 * @param key the key of the element to return.
+	 * @return The value placed into the cache with an earlier put, or null if not found or expired
+	 * @throws CacheException
+	 */
+	public Object get(Object key) throws CacheException {
+		try {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "key: " + key );
+			}
+			if ( key == null ) {
+				return null;
+			}
+			else {
+				Element element = cache.get( key );
+				if ( element == null ) {
+					if ( log.isDebugEnabled() ) {
+						log.debug( "Element for " + key + " is null" );
+					}
+					return null;
+				}
+				else {
+					return element.getObjectValue();
+				}
+			}
+		}
+		catch (net.sf.ehcache.CacheException e) {
+			throw new CacheException( e );
+		}
+	}
+
+	public Object read(Object key) throws CacheException {
+		return get( key );
+	}
+
+
+	/**
+	 * Puts an object into the cache.
+	 *
+	 * @param key   a key
+	 * @param value a value
+	 * @throws CacheException if the {@link CacheManager}
+	 *                        is shutdown or another {@link Exception} occurs.
+	 */
+	public void update(Object key, Object value) throws CacheException {
+		put( key, value );
+	}
+
+	/**
+	 * Puts an object into the cache.
+	 *
+	 * @param key   a key
+	 * @param value a value
+	 * @throws CacheException if the {@link CacheManager}
+	 *                        is shutdown or another {@link Exception} occurs.
+	 */
+	public void put(Object key, Object value) throws CacheException {
+		try {
+			Element element = new Element( key, value );
+			cache.put( element );
+		}
+		catch (IllegalArgumentException e) {
+			throw new CacheException( e );
+		}
+		catch (IllegalStateException e) {
+			throw new CacheException( e );
+		}
+		catch (net.sf.ehcache.CacheException e) {
+			throw new CacheException( e );
+		}
+
+	}
+
+	/**
+	 * Removes the element which matches the key.
+	 * <p/>
+	 * If no element matches, nothing is removed and no Exception is thrown.
+	 *
+	 * @param key the key of the element to remove
+	 * @throws CacheException
+	 */
+	public void remove(Object key) throws CacheException {
+		try {
+			cache.remove( key );
+		}
+		catch (ClassCastException e) {
+			throw new CacheException( e );
+		}
+		catch (IllegalStateException e) {
+			throw new CacheException( e );
+		}
+		catch (net.sf.ehcache.CacheException e) {
+			throw new CacheException( e );
+		}
+	}
+
+	/**
+	 * Remove all elements in the cache, but leave the cache
+	 * in a useable state.
+	 *
+	 * @throws CacheException
+	 */
+	public void clear() throws CacheException {
+		try {
+			cache.removeAll();
+		}
+		catch (IllegalStateException e) {
+			throw new CacheException( e );
+		}
+		catch (net.sf.ehcache.CacheException e) {
+			throw new CacheException( e );
+		}
+	}
+
+	/**
+	 * Remove the cache and make it unuseable.
+	 *
+	 * @throws CacheException
+	 */
+	public void destroy() throws CacheException {
+		try {
+			cache.getCacheManager().removeCache( cache.getName() );
+		}
+		catch (IllegalStateException e) {
+			throw new CacheException( e );
+		}
+		catch (net.sf.ehcache.CacheException e) {
+			throw new CacheException( e );
+		}
+	}
+
+	/**
+	 * Calls to this method should perform there own synchronization.
+	 * It is provided for distributed caches. Because EHCache is not distributed
+	 * this method does nothing.
+	 */
+	public void lock(Object key) throws CacheException {
+	}
+
+	/**
+	 * Calls to this method should perform there own synchronization.
+	 * It is provided for distributed caches. Because EHCache is not distributed
+	 * this method does nothing.
+	 */
+	public void unlock(Object key) throws CacheException {
+	}
+
+	/**
+	 * Gets the next timestamp;
+	 */
+	public long nextTimestamp() {
+		return Timestamper.next();
+	}
+
+	/**
+	 * Returns the lock timeout for this cache.
+	 */
+	public int getTimeout() {
+		// 60 second lock timeout
+		return Timestamper.ONE_MS * SIXTY_THOUSAND_MS;
+	}
+
+	public String getRegionName() {
+		return cache.getName();
+	}
+
+	/**
+	 * Warning: This method can be very expensive to run. Allow approximately 1 second
+	 * per 1MB of entries. Running this method could create liveness problems
+	 * because the object lock is held for a long period
+	 * <p/>
+	 *
+	 * @return the approximate size of memory ehcache is using for the MemoryStore for this cache
+	 */
+	public long getSizeInMemory() {
+		try {
+			return cache.calculateInMemorySize();
+		}
+		catch (Throwable t) {
+			return -1;
+		}
+	}
+
+	public long getElementCountInMemory() {
+		try {
+			return cache.getMemoryStoreSize();
+		}
+		catch (net.sf.ehcache.CacheException ce) {
+			throw new CacheException( ce );
+		}
+	}
+
+	public long getElementCountOnDisk() {
+		return cache.getDiskStoreSize();
+	}
+
+	public Map toMap() {
+		try {
+			Map result = new HashMap();
+			Iterator iter = cache.getKeys().iterator();
+			while ( iter.hasNext() ) {
+				Object key = iter.next();
+				result.put( key, cache.get( key ).getObjectValue() );
+			}
+			return result;
+		}
+		catch (Exception e) {
+			throw new CacheException( e );
+		}
+	}
+
+	public String toString() {
+		return "EHCache(" + getRegionName() + ')';
+	}
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/cache-ehcache/src/main/java/org/hibernate/cache/EhCacheProvider.java
===================================================================
--- trunk/Hibernate3/cache-ehcache/src/main/java/org/hibernate/cache/EhCacheProvider.java	                        (rev 0)
+++ trunk/Hibernate3/cache-ehcache/src/main/java/org/hibernate/cache/EhCacheProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,167 @@
+//$Id: EhCacheProvider.java 9964 2006-05-30 15:40:54Z epbernard $
+/**
+ *  Copyright 2003-2006 Greg Luck, Jboss Inc
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.hibernate.cache;
+
+import java.util.Properties;
+import java.net.URL;
+
+import net.sf.ehcache.CacheManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.cfg.Environment;
+import org.hibernate.util.StringHelper;
+import org.hibernate.util.ConfigHelper;
+
+/**
+ * Cache Provider plugin for Hibernate
+ *
+ * Use <code>hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider</code>
+ * in Hibernate 3.x or later
+ * 
+ * Taken from EhCache 0.9 distribution
+ * @author Greg Luck
+ * @author Emmanuel Bernard
+ */
+/**
+ * Cache Provider plugin for ehcache-1.2. New in this provider are ehcache support for multiple
+ * Hibernate session factories, each with its own ehcache configuration, and non Serializable keys and values.
+ * Ehcache-1.2 also has many other features such as cluster support and listeners, which can be used seamlessly simply
+ * by configurion in ehcache.xml.
+ * <p/>
+ * Use <code>hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider</code> in the Hibernate configuration
+ * to enable this provider for Hibernate's second level cache.
+ * <p/>
+ * When configuring multiple ehcache CacheManagers, as you would where you have multiple Hibernate Configurations and
+ * multiple SessionFactories, specify in each Hibernate configuration the ehcache configuration using
+ * the property <code>hibernate.cache.provider_configuration_file_resource_path</code> An example to set an ehcache configuration
+ * called ehcache-2.xml would be <code>hibernate.cache.provider_configuration_file_resource_path=/ehcache-2.xml</code>. If the leading
+ * slash is not there one will be added. The configuration file will be looked for in the root of the classpath.
+ * <p/>
+ * Updated for ehcache-1.2. Note this provider requires ehcache-1.2.jar. Make sure ehcache-1.1.jar or earlier
+ * is not in the classpath or it will not work.
+ * <p/>
+ * See http://ehcache.sf.net for documentation on ehcache
+ * <p/>
+ *
+ * @author Greg Luck
+ * @author Emmanuel Bernard
+ */
+public class EhCacheProvider implements CacheProvider {
+
+    private static final Log log = LogFactory.getLog(EhCacheProvider.class);
+
+	private CacheManager manager;
+
+    /**
+     * Builds a Cache.
+     * <p>
+     * Even though this method provides properties, they are not used.
+     * Properties for EHCache are specified in the ehcache.xml file.
+     * Configuration will be read from ehcache.xml for a cache declaration
+     * where the name attribute matches the name parameter in this builder.
+     *
+     * @param name the name of the cache. Must match a cache configured in ehcache.xml
+     * @param properties not used
+     * @return a newly built cache will be built and initialised
+     * @throws CacheException inter alia, if a cache of the same name already exists
+     */
+    public Cache buildCache(String name, Properties properties) throws CacheException {
+	    try {
+            net.sf.ehcache.Cache cache = manager.getCache(name);
+            if (cache == null) {
+                log.warn("Could not find configuration [" + name + "]; using defaults.");
+                manager.addCache(name);
+                cache = manager.getCache(name);
+                log.debug("started EHCache region: " + name);
+            }
+            return new EhCache(cache);
+	    }
+        catch (net.sf.ehcache.CacheException e) {
+            throw new CacheException(e);
+        }
+    }
+
+    /**
+     * Returns the next timestamp.
+     */
+    public long nextTimestamp() {
+        return Timestamper.next();
+    }
+
+	/**
+	 * Callback to perform any necessary initialization of the underlying cache implementation
+	 * during SessionFactory construction.
+	 *
+	 * @param properties current configuration settings.
+	 */
+	public void start(Properties properties) throws CacheException {
+		if (manager != null) {
+            log.warn("Attempt to restart an already started EhCacheProvider. Use sessionFactory.close() " +
+                    " between repeated calls to buildSessionFactory. Using previously created EhCacheProvider." +
+                    " If this behaviour is required, consider using net.sf.ehcache.hibernate.SingletonEhCacheProvider.");
+            return;
+        }
+        try {
+            String configurationResourceName = null;
+            if (properties != null) {
+                configurationResourceName = (String) properties.get( Environment.CACHE_PROVIDER_CONFIG );
+            }
+            if ( StringHelper.isEmpty( configurationResourceName ) ) {
+                manager = new CacheManager();
+            } else {
+                URL url = loadResource(configurationResourceName);
+                manager = new CacheManager(url);
+            }
+        } catch (net.sf.ehcache.CacheException e) {
+			//yukky! Don't you have subclasses for that!
+			//TODO race conditions can happen here
+			if (e.getMessage().startsWith("Cannot parseConfiguration CacheManager. Attempt to create a new instance of " +
+                    "CacheManager using the diskStorePath")) {
+                throw new CacheException("Attempt to restart an already started EhCacheProvider. Use sessionFactory.close() " +
+                    " between repeated calls to buildSessionFactory. Consider using net.sf.ehcache.hibernate.SingletonEhCacheProvider."
+						, e );
+            } else {
+                throw e;
+            }
+        }
+	}
+
+	private URL loadResource(String configurationResourceName) {
+		URL url = ConfigHelper.locateConfig( configurationResourceName );
+        if (log.isDebugEnabled()) {
+            log.debug("Creating EhCacheProvider from a specified resource: "
+                    + configurationResourceName + " Resolved to URL: " + url);
+        }
+        return url;
+    }
+
+	/**
+	 * Callback to perform any necessary cleanup of the underlying cache implementation
+	 * during SessionFactory.close().
+	 */
+	public void stop() {
+		if (manager != null) {
+            manager.shutdown();
+            manager = null;
+        }
+	}
+
+	public boolean isMinimalPutsEnabledByDefault() {
+		return false;
+	}
+
+}

Added: trunk/Hibernate3/cache-jbosscache/pom.xml
===================================================================
--- trunk/Hibernate3/cache-jbosscache/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/cache-jbosscache/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.hibernate</groupId>
+    <artifactId>hibernate-jbosscache</artifactId>
+    <packaging>jar</packaging>
+    <name>Hibernate JBossCache integration</name>
+    <description>Integration of Hibernate with JBossCache (based on JBossCache1.x APIs)</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>${groupId}</groupId>
+            <artifactId>hibernate-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>jboss</groupId>
+            <artifactId>jboss-cache</artifactId>
+            <version>1.4.1.GA</version>
+        </dependency>
+        <!-- jboss-cache (the one from the jboss repo, anyway) does not properly define its dependencies -->
+        <dependency>
+            <groupId>jboss</groupId>
+            <artifactId>jboss-system</artifactId>
+            <version>4.0.2</version>
+        </dependency>
+        <dependency>
+            <groupId>jboss</groupId>
+            <artifactId>jboss-common</artifactId>
+            <version>4.0.2</version>
+        </dependency>
+        <dependency>
+            <groupId>jboss</groupId>
+            <artifactId>jboss-minimal</artifactId>
+            <version>4.0.2</version>
+        </dependency>
+        <dependency>
+            <groupId>jboss</groupId>
+            <artifactId>jboss-j2se</artifactId>
+            <version>200504122039</version>
+        </dependency>
+        <dependency>
+            <groupId>concurrent</groupId>
+            <artifactId>concurrent</artifactId>
+            <version>1.3.4</version>
+        </dependency>
+        <dependency>
+            <groupId>jgroups</groupId>
+            <artifactId>jgroups-all</artifactId>
+            <version>2.2.7</version>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

Added: trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/JndiBoundTreeCacheProvider.java
===================================================================
--- trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/JndiBoundTreeCacheProvider.java	                        (rev 0)
+++ trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/JndiBoundTreeCacheProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+// $Id: JndiBoundTreeCacheProvider.java 6079 2005-03-16 06:01:18Z oneovthafew $
+package org.hibernate.cache;
+
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+
+import org.hibernate.transaction.TransactionManagerLookup;
+import org.hibernate.transaction.TransactionManagerLookupFactory;
+
+/**
+ * Support for JBossCache (TreeCache), where the cache instance is available
+ * via JNDI lookup.
+ *
+ * @author Steve Ebersole
+ */
+public class JndiBoundTreeCacheProvider extends AbstractJndiBoundCacheProvider {
+
+	private TransactionManager transactionManager;
+
+	/**
+	 * Construct a Cache representing the "region" within in the underlying cache
+	 * provider.
+	 *
+	 * @param regionName the name of the cache region
+	 * @param properties configuration settings
+	 *
+	 * @throws CacheException
+	 */
+	public Cache buildCache(String regionName, Properties properties) throws CacheException {
+		return new TreeCache( getTreeCacheInstance(), regionName, transactionManager );
+	}
+
+	public void prepare(Properties properties) throws CacheException {
+		TransactionManagerLookup transactionManagerLookup = TransactionManagerLookupFactory.getTransactionManagerLookup(properties);
+		if (transactionManagerLookup!=null) {
+			transactionManager = transactionManagerLookup.getTransactionManager(properties);
+		}
+	}
+	/**
+	 * Generate a timestamp
+	 */
+	public long nextTimestamp() {
+		return System.currentTimeMillis() / 100;
+	}
+
+	/**
+	 * By default, should minimal-puts mode be enabled when using this cache.
+	 * <p/>
+	 * Since TreeCache is a clusterable cache and we are only getting a
+	 * reference the instance from JNDI, safest to assume a clustered
+	 * setup and return true here.
+	 *
+	 * @return True.
+	 */
+	public boolean isMinimalPutsEnabledByDefault() {
+		return true;
+	}
+
+	public org.jboss.cache.TreeCache getTreeCacheInstance() {
+		return ( org.jboss.cache.TreeCache ) super.getCache();
+	}
+}

Added: trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/OptimisticTreeCache.java
===================================================================
--- trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/OptimisticTreeCache.java	                        (rev 0)
+++ trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/OptimisticTreeCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,329 @@
+//$Id: OptimisticTreeCache.java 10118 2006-07-13 21:38:41Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.Comparator;
+
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.lock.TimeoutException;
+
+/**
+ * Represents a particular region within the given JBossCache TreeCache
+ * utilizing TreeCache's optimistic locking capabilities.
+ *
+ * @see OptimisticTreeCacheProvider for more details
+ *
+ * @author Steve Ebersole
+ */
+public class OptimisticTreeCache implements OptimisticCache {
+
+	// todo : eventually merge this with TreeCache and just add optional opt-lock support there.
+
+	private static final Log log = LogFactory.getLog( OptimisticTreeCache.class);
+
+	private static final String ITEM = "item";
+
+	private org.jboss.cache.TreeCache cache;
+	private final String regionName;
+	private final Fqn regionFqn;
+	private OptimisticCacheSource source;
+
+	public OptimisticTreeCache(org.jboss.cache.TreeCache cache, String regionName)
+	throws CacheException {
+		this.cache = cache;
+		this.regionName = regionName;
+		this.regionFqn = Fqn.fromString( regionName.replace( '.', '/' ) );
+	}
+
+
+	// OptimisticCache impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void setSource(OptimisticCacheSource source) {
+		this.source = source;
+	}
+
+	public void writeInsert(Object key, Object value, Object currentVersion) {
+		writeUpdate( key, value, currentVersion, null );
+	}
+
+	public void writeUpdate(Object key, Object value, Object currentVersion, Object previousVersion) {
+		try {
+			Option option = new Option();
+			DataVersion dv = ( source != null && source.isVersioned() )
+			                 ? new DataVersionAdapter( currentVersion, previousVersion, source.getVersionComparator(), source.toString() )
+			                 : NonLockingDataVersion.INSTANCE;
+			option.setDataVersion( dv );
+			cache.put( new Fqn( regionFqn, key ), ITEM, value, option );
+		}
+		catch ( Exception e ) {
+			throw new CacheException( e );
+		}
+	}
+
+	public void writeLoad(Object key, Object value, Object currentVersion) {
+		try {
+			Option option = new Option();
+			option.setFailSilently( true );
+			option.setDataVersion( NonLockingDataVersion.INSTANCE );
+			cache.remove( new Fqn( regionFqn, key ), "ITEM", option );
+
+			option = new Option();
+			option.setFailSilently( true );
+			DataVersion dv = ( source != null && source.isVersioned() )
+			                 ? new DataVersionAdapter( currentVersion, currentVersion, source.getVersionComparator(), source.toString() )
+			                 : NonLockingDataVersion.INSTANCE;
+			option.setDataVersion( dv );
+			cache.put( new Fqn( regionFqn, key ), ITEM, value, option );
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+
+	// Cache impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public Object get(Object key) throws CacheException {
+		try {
+			Option option = new Option();
+			option.setFailSilently( true );
+//			option.setDataVersion( NonLockingDataVersion.INSTANCE );
+			return cache.get( new Fqn( regionFqn, key ), ITEM, option );
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public Object read(Object key) throws CacheException {
+		try {
+			return cache.get( new Fqn( regionFqn, key ), ITEM );
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public void update(Object key, Object value) throws CacheException {
+		try {
+			Option option = new Option();
+			option.setDataVersion( NonLockingDataVersion.INSTANCE );
+			cache.put( new Fqn( regionFqn, key ), ITEM, value, option );
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public void put(Object key, Object value) throws CacheException {
+		try {
+			log.trace( "performing put() into region [" + regionName + "]" );
+			// do the put outside the scope of the JTA txn
+			Option option = new Option();
+			option.setFailSilently( true );
+			option.setDataVersion( NonLockingDataVersion.INSTANCE );
+			cache.put( new Fqn( regionFqn, key ), ITEM, value, option );
+		}
+		catch (TimeoutException te) {
+			//ignore!
+			log.debug("ignoring write lock acquisition failure");
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public void remove(Object key) throws CacheException {
+		try {
+			// tree cache in optimistic mode seems to have as very difficult
+			// time with remove calls on non-existent nodes (NPEs)...
+			if ( cache.get( new Fqn( regionFqn, key ), ITEM ) != null ) {
+				Option option = new Option();
+				option.setDataVersion( NonLockingDataVersion.INSTANCE );
+				cache.remove( new Fqn( regionFqn, key ), option );
+			}
+			else {
+				log.trace( "skipping remove() call as the underlying node did not seem to exist" );
+			}
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public void clear() throws CacheException {
+		try {
+			Option option = new Option();
+			option.setDataVersion( NonLockingDataVersion.INSTANCE );
+			cache.remove( regionFqn, option );
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public void destroy() throws CacheException {
+		try {
+			Option option = new Option();
+			option.setCacheModeLocal( true );
+			option.setFailSilently( true );
+			option.setDataVersion( NonLockingDataVersion.INSTANCE );
+			cache.remove( regionFqn, option );
+		}
+		catch( Exception e ) {
+			throw new CacheException( e );
+		}
+	}
+
+	public void lock(Object key) throws CacheException {
+		throw new UnsupportedOperationException( "TreeCache is a fully transactional cache" + regionName );
+	}
+
+	public void unlock(Object key) throws CacheException {
+		throw new UnsupportedOperationException( "TreeCache is a fully transactional cache: " + regionName );
+	}
+
+	public long nextTimestamp() {
+		return System.currentTimeMillis() / 100;
+	}
+
+	public int getTimeout() {
+		return 600; //60 seconds
+	}
+
+	public String getRegionName() {
+		return regionName;
+	}
+
+	public long getSizeInMemory() {
+		return -1;
+	}
+
+	public long getElementCountInMemory() {
+		try {
+			Set children = cache.getChildrenNames( regionFqn );
+			return children == null ? 0 : children.size();
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public long getElementCountOnDisk() {
+		return 0;
+	}
+
+	public Map toMap() {
+		try {
+			Map result = new HashMap();
+			Set childrenNames = cache.getChildrenNames( regionFqn );
+			if (childrenNames != null) {
+				Iterator iter = childrenNames.iterator();
+				while ( iter.hasNext() ) {
+					Object key = iter.next();
+					result.put(
+							key,
+					        cache.get( new Fqn( regionFqn, key ), ITEM )
+						);
+				}
+			}
+			return result;
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public String toString() {
+		return "OptimisticTreeCache(" + regionName + ')';
+	}
+
+	public static class DataVersionAdapter implements DataVersion {
+		private final Object currentVersion;
+		private final Object previousVersion;
+		private final Comparator versionComparator;
+		private final String sourceIdentifer;
+
+		public DataVersionAdapter(Object currentVersion, Object previousVersion, Comparator versionComparator, String sourceIdentifer) {
+			this.currentVersion = currentVersion;
+			this.previousVersion = previousVersion;
+			this.versionComparator = versionComparator;
+			this.sourceIdentifer = sourceIdentifer;
+			log.trace( "created " + this );
+		}
+
+		/**
+		 * newerThan() call is dispatched against the DataVersion currently
+		 * associated with the node; the passed dataVersion param is the
+		 * DataVersion associated with the data we are trying to put into
+		 * the node.
+		 * <p/>
+		 * we are expected to return true in the case where we (the current
+		 * node DataVersion) are newer that then incoming value.  Returning
+		 * true here essentially means that a optimistic lock failure has
+		 * occured (because conversely, the value we are trying to put into
+		 * the node is "older than" the value already there...)
+		 */
+		public boolean newerThan(DataVersion dataVersion) {
+			log.trace( "checking [" + this + "] against [" + dataVersion + "]" );
+			if ( dataVersion instanceof CircumventChecksDataVersion ) {
+				log.trace( "skipping lock checks..." );
+				return false;
+			}
+			else if ( dataVersion instanceof NonLockingDataVersion ) {
+				// can happen because of the multiple ways Cache.remove()
+				// can be invoked :(
+				log.trace( "skipping lock checks..." );
+				return false;
+			}
+			DataVersionAdapter other = ( DataVersionAdapter ) dataVersion;
+			if ( other.previousVersion == null ) {
+				log.warn( "Unexpected optimistic lock check on inserting data" );
+				// work around the "feature" where tree cache is validating the
+				// inserted node during the next transaction.  no idea...
+				if ( this == dataVersion ) {
+					log.trace( "skipping lock checks due to same DV instance" );
+					return false;
+				}
+			}
+			return versionComparator.compare( currentVersion, other.previousVersion ) >= 1;
+		}
+
+		public String toString() {
+			return super.toString() + " [current=" + currentVersion + ", previous=" + previousVersion + ", src=" + sourceIdentifer + "]";
+		}
+	}
+
+	/**
+	 * Used in regions where no locking should ever occur.  This includes query-caches,
+	 * update-timestamps caches, collection caches, and entity caches where the entity
+	 * is not versioned.
+	 */
+	public static class NonLockingDataVersion implements DataVersion {
+		public static final DataVersion INSTANCE = new NonLockingDataVersion();
+		public boolean newerThan(DataVersion dataVersion) {
+			log.trace( "non locking lock check...");
+			return false;
+		}
+	}
+
+	/**
+	 * Used to signal to a DataVersionAdapter to simply not perform any checks.  This
+	 * is currently needed for proper handling of remove() calls for entity cache regions
+	 * (we do not know the version info...).
+	 */
+	public static class CircumventChecksDataVersion implements DataVersion {
+		public static final DataVersion INSTANCE = new CircumventChecksDataVersion();
+		public boolean newerThan(DataVersion dataVersion) {
+			throw new CacheException( "optimistic locking checks should never happen on CircumventChecksDataVersion" );
+		}
+	}
+}

Added: trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/OptimisticTreeCacheProvider.java
===================================================================
--- trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/OptimisticTreeCacheProvider.java	                        (rev 0)
+++ trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/OptimisticTreeCacheProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,130 @@
+//$Id: OptimisticTreeCacheProvider.java 9895 2006-05-05 19:27:17Z epbernard $
+package org.hibernate.cache;
+
+import java.util.Properties;
+import javax.transaction.TransactionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.cfg.Environment;
+import org.hibernate.transaction.TransactionManagerLookup;
+import org.hibernate.transaction.TransactionManagerLookupFactory;
+import org.jboss.cache.PropertyConfigurator;
+
+/**
+ * Support for a standalone JBossCache TreeCache instance utilizing TreeCache's
+ * optimistic locking capabilities.  This capability was added in JBossCache
+ * version 1.3.0; as such this provider will only work with that version or
+ * higher.
+ * <p/>
+ * The TreeCache instance is configured via a local config resource.  The
+ * resource to be used for configuration can be controlled by specifying a value
+ * for the {@link #CONFIG_RESOURCE} config property.
+ *
+ * @author Steve Ebersole
+ */
+public class OptimisticTreeCacheProvider implements CacheProvider {
+
+	/**
+	 * @deprecated use {@link Environment.CACHE_PROVIDER_CONFIG}
+	 */
+	public static final String CONFIG_RESOURCE = "hibernate.cache.opt_tree_cache.config";
+	public static final String DEFAULT_CONFIG = "treecache.xml";
+
+	private static final String NODE_LOCKING_SCHEME = "OPTIMISTIC";
+	private static final Log log = LogFactory.getLog( OptimisticTreeCacheProvider.class );
+
+	private org.jboss.cache.TreeCache cache;
+
+	/**
+	 * Construct and configure the Cache representation of a named cache region.
+	 *
+	 * @param regionName the name of the cache region
+	 * @param properties configuration settings
+	 * @return The Cache representation of the named cache region.
+	 * @throws CacheException
+	 *          Indicates an error building the cache region.
+	 */
+	public Cache buildCache(String regionName, Properties properties) throws CacheException {
+		return new OptimisticTreeCache( cache, regionName );
+	}
+
+	public long nextTimestamp() {
+		return System.currentTimeMillis() / 100;
+	}
+
+	/**
+	 * Prepare the underlying JBossCache TreeCache instance.
+	 *
+	 * @param properties All current config settings.
+	 * @throws CacheException
+	 *          Indicates a problem preparing cache for use.
+	 */
+	public void start(Properties properties) {
+		String resource = properties.getProperty( Environment.CACHE_PROVIDER_CONFIG );
+		if (resource == null) {
+			resource = properties.getProperty( CONFIG_RESOURCE );
+		}
+		if ( resource == null ) {
+			resource = DEFAULT_CONFIG;
+		}
+		log.debug( "Configuring TreeCache from resource [" + resource + "]" );
+		try {
+			cache = new org.jboss.cache.TreeCache();
+			PropertyConfigurator config = new PropertyConfigurator();
+			config.configure( cache, resource );
+			TransactionManagerLookup transactionManagerLookup =
+					TransactionManagerLookupFactory.getTransactionManagerLookup( properties );
+			if ( transactionManagerLookup == null ) {
+				throw new CacheException(
+						"JBossCache only supports optimisitc locking with a configured " +
+						"TransactionManagerLookup (" + Environment.TRANSACTION_MANAGER_STRATEGY + ")"
+				);
+			}
+			cache.setTransactionManagerLookup(
+					new TransactionManagerLookupAdaptor(
+							transactionManagerLookup,
+							properties
+					)
+			);
+			if ( ! NODE_LOCKING_SCHEME.equalsIgnoreCase( cache.getNodeLockingScheme() ) ) {
+				log.info( "Overriding node-locking-scheme to : " + NODE_LOCKING_SCHEME );
+				cache.setNodeLockingScheme( NODE_LOCKING_SCHEME );
+			}
+			cache.start();
+		}
+		catch ( Exception e ) {
+			throw new CacheException( e );
+		}
+	}
+
+	public void stop() {
+		if ( cache != null ) {
+			cache.stop();
+			cache.destroy();
+			cache = null;
+		}
+	}
+
+	public boolean isMinimalPutsEnabledByDefault() {
+		return true;
+	}
+
+	static final class TransactionManagerLookupAdaptor implements org.jboss.cache.TransactionManagerLookup {
+		private final TransactionManagerLookup tml;
+		private final Properties props;
+
+		TransactionManagerLookupAdaptor(TransactionManagerLookup tml, Properties props) {
+			this.tml = tml;
+			this.props = props;
+		}
+
+		public TransactionManager getTransactionManager() throws Exception {
+			return tml.getTransactionManager( props );
+		}
+	}
+
+	public org.jboss.cache.TreeCache getUnderlyingCache() {
+		return cache;
+	}
+}

Added: trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/TreeCache.java
===================================================================
--- trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/TreeCache.java	                        (rev 0)
+++ trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/TreeCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,205 @@
+//$Id: TreeCache.java 9965 2006-05-30 18:00:28Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.lock.TimeoutException;
+
+/**
+ * Represents a particular region within the given JBossCache TreeCache.
+ *
+ * @author Gavin King
+ */
+public class TreeCache implements Cache {
+	
+	private static final Log log = LogFactory.getLog(TreeCache.class);
+
+	private static final String ITEM = "item";
+
+	private org.jboss.cache.TreeCache cache;
+	private final String regionName;
+	private final Fqn regionFqn;
+	private final TransactionManager transactionManager;
+
+	public TreeCache(org.jboss.cache.TreeCache cache, String regionName, TransactionManager transactionManager) 
+	throws CacheException {
+		this.cache = cache;
+		this.regionName = regionName;
+		this.regionFqn = Fqn.fromString( regionName.replace( '.', '/' ) );
+		this.transactionManager = transactionManager;
+	}
+
+	public Object get(Object key) throws CacheException {
+		Transaction tx = suspend();
+		try {
+			return read(key);
+		}
+		finally {
+			resume( tx );
+		}
+	}
+	
+	public Object read(Object key) throws CacheException {
+		try {
+			return cache.get( new Fqn( regionFqn, key ), ITEM );
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public void update(Object key, Object value) throws CacheException {
+		try {
+			cache.put( new Fqn( regionFqn, key ), ITEM, value );
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public void put(Object key, Object value) throws CacheException {
+		Transaction tx = suspend();
+		try {
+			//do the failfast put outside the scope of the JTA txn
+			cache.putFailFast( new Fqn( regionFqn, key ), ITEM, value, 0 );
+		}
+		catch (TimeoutException te) {
+			//ignore!
+			log.debug("ignoring write lock acquisition failure");
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+		finally {
+			resume( tx );
+		}
+	}
+
+	private void resume(Transaction tx) {
+		try {
+			if (tx!=null) transactionManager.resume(tx);
+		}
+		catch (Exception e) {
+			throw new CacheException("Could not resume transaction", e);
+		}
+	}
+
+	private Transaction suspend() {
+		Transaction tx = null;
+		try {
+			if ( transactionManager!=null ) {
+				tx = transactionManager.suspend();
+			}
+		}
+		catch (SystemException se) {
+			throw new CacheException("Could not suspend transaction", se);
+		}
+		return tx;
+	}
+
+	public void remove(Object key) throws CacheException {
+		try {
+			cache.remove( new Fqn( regionFqn, key ) );
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public void clear() throws CacheException {
+		try {
+			cache.remove( regionFqn );
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public void destroy() throws CacheException {
+		try {
+			// NOTE : evict() operates locally only (i.e., does not propogate
+			// to any other nodes in the potential cluster).  This is
+			// exactly what is needed when we destroy() here; destroy() is used
+			// as part of the process of shutting down a SessionFactory; thus
+			// these removals should not be propogated
+			cache.evict( regionFqn );
+		}
+		catch( Exception e ) {
+			throw new CacheException( e );
+		}
+	}
+
+	public void lock(Object key) throws CacheException {
+		throw new UnsupportedOperationException( "TreeCache is a fully transactional cache" + regionName );
+	}
+
+	public void unlock(Object key) throws CacheException {
+		throw new UnsupportedOperationException( "TreeCache is a fully transactional cache: " + regionName );
+	}
+
+	public long nextTimestamp() {
+		return System.currentTimeMillis() / 100;
+	}
+
+	public int getTimeout() {
+		return 600; //60 seconds
+	}
+
+	public String getRegionName() {
+		return regionName;
+	}
+
+	public long getSizeInMemory() {
+		return -1;
+	}
+
+	public long getElementCountInMemory() {
+		try {
+			Set children = cache.getChildrenNames( regionFqn );
+			return children == null ? 0 : children.size();
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public long getElementCountOnDisk() {
+		return 0;
+	}
+	
+	public Map toMap() {
+		try {
+			Map result = new HashMap();
+			Set childrenNames = cache.getChildrenNames( regionFqn );
+			if (childrenNames != null) {
+				Iterator iter = childrenNames.iterator();
+				while ( iter.hasNext() ) {
+					Object key = iter.next();
+					result.put( 
+							key, 
+							cache.get( new Fqn( regionFqn, key ), ITEM )
+						);
+				}
+			}
+			return result;
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+	
+	public String toString() {
+		return "TreeCache(" + regionName + ')';
+	}
+	
+}

Added: trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/TreeCacheProvider.java
===================================================================
--- trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/TreeCacheProvider.java	                        (rev 0)
+++ trunk/Hibernate3/cache-jbosscache/src/main/java/org/hibernate/cache/TreeCacheProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,109 @@
+//$Id: TreeCacheProvider.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import java.util.Properties;
+import javax.transaction.TransactionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.transaction.TransactionManagerLookup;
+import org.hibernate.transaction.TransactionManagerLookupFactory;
+import org.hibernate.cfg.Environment;
+import org.jboss.cache.PropertyConfigurator;
+
+/**
+ * Support for a standalone JBossCache (TreeCache) instance.  The JBossCache is configured
+ * via a local config resource.
+ *
+ * @author Gavin King
+ */
+public class TreeCacheProvider implements CacheProvider {
+
+	/**
+	 * @deprecated use {@link org.hibernate.cfg.Environment#CACHE_PROVIDER_CONFIG}
+	 */
+	public static final String CONFIG_RESOURCE = "hibernate.cache.tree_cache.config";
+	public static final String DEFAULT_CONFIG = "treecache.xml";
+
+	private static final Log log = LogFactory.getLog( TreeCacheProvider.class );
+
+	private org.jboss.cache.TreeCache cache;
+	private TransactionManager transactionManager;
+
+	/**
+	 * Construct and configure the Cache representation of a named cache region.
+	 *
+	 * @param regionName the name of the cache region
+	 * @param properties configuration settings
+	 * @return The Cache representation of the named cache region.
+	 * @throws CacheException Indicates an error building the cache region.
+	 */
+	public Cache buildCache(String regionName, Properties properties) throws CacheException {
+		return new TreeCache(cache, regionName, transactionManager);
+	}
+
+	public long nextTimestamp() {
+		return System.currentTimeMillis() / 100;
+	}
+
+	/**
+	 * Prepare the underlying JBossCache TreeCache instance.
+	 *
+	 * @param properties All current config settings.
+	 *
+	 * @throws CacheException Indicates a problem preparing cache for use.
+	 */
+	public void start(Properties properties) {
+		String resource = properties.getProperty( Environment.CACHE_PROVIDER_CONFIG );
+
+		if ( resource == null ) {
+			resource = properties.getProperty( CONFIG_RESOURCE );
+		}
+		if ( resource == null ) {
+			resource = DEFAULT_CONFIG;
+		}
+		log.debug( "Configuring TreeCache from resource [" + resource + "]" );
+		try {
+			cache = new org.jboss.cache.TreeCache();
+			PropertyConfigurator config = new PropertyConfigurator();
+			config.configure( cache, resource );
+			TransactionManagerLookup transactionManagerLookup = TransactionManagerLookupFactory.getTransactionManagerLookup(properties);
+			if (transactionManagerLookup!=null) {
+				cache.setTransactionManagerLookup( new TransactionManagerLookupAdaptor(transactionManagerLookup, properties) );
+				transactionManager = transactionManagerLookup.getTransactionManager(properties);
+			}
+			cache.start();
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public void stop() {
+		if (cache!=null) {
+			cache.stop();
+			cache.destroy();
+			cache=null;
+		}
+	}
+	
+	public boolean isMinimalPutsEnabledByDefault() {
+		return true;
+	}
+
+	static final class TransactionManagerLookupAdaptor implements org.jboss.cache.TransactionManagerLookup {
+		private final TransactionManagerLookup tml;
+		private final Properties props;
+		TransactionManagerLookupAdaptor(TransactionManagerLookup tml, Properties props) {
+			this.tml=tml;
+			this.props=props;
+		}
+		public TransactionManager getTransactionManager() throws Exception {
+			return tml.getTransactionManager(props);
+		}
+	}
+
+	public org.jboss.cache.TreeCache getUnderlyingCache() {
+		return cache;
+	}
+}

Added: trunk/Hibernate3/cache-jbosscache2/pom.xml
===================================================================
--- trunk/Hibernate3/cache-jbosscache2/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/cache-jbosscache2/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,58 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.hibernate</groupId>
+    <artifactId>hibernate-jbosscache2</artifactId>
+    <packaging>jar</packaging>
+    <name>Hibernate JBossCache2.x integration</name>
+    <description>Integration of Hibernate with JBossCache (based on JBossCache2.x APIs)</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>${groupId}</groupId>
+            <artifactId>hibernate-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>jboss</groupId>
+            <artifactId>jboss-cache</artifactId>
+            <!-- does not work with idea plugin :(
+            <version>[2.0.0.BETA2,)</version>
+            -->
+            <version>2.0.0.BETA2</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-idea-plugin</artifactId>
+                <configuration>
+                    <jdkName>1.5</jdkName>
+                    <jdkLevel>5.0</jdkLevel>
+                    <!-- why this isnt the default I have no clue -->
+                    <linkModules>true</linkModules>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.5</source>
+                    <target>1.5</target>
+                </configuration>
+              </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file

Added: trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc/TransactionManagerLookupAdaptor.java
===================================================================
--- trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc/TransactionManagerLookupAdaptor.java	                        (rev 0)
+++ trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc/TransactionManagerLookupAdaptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+package org.hibernate.cache.impl.jbc;
+
+import java.util.Properties;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.transaction.TransactionManagerLookup;
+
+/**
+ * An adapter between JBossCache's notion of a TM lookup and Hibernate's.
+ *
+ * @author Steve Ebersole
+ */
+public class TransactionManagerLookupAdaptor implements org.jboss.cache.transaction.TransactionManagerLookup {
+	private final TransactionManagerLookup tml;
+	private final Properties props;
+
+	TransactionManagerLookupAdaptor(TransactionManagerLookup tml, Properties props) {
+		this.tml = tml;
+		this.props = props;
+	}
+
+	public TransactionManager getTransactionManager() throws Exception {
+		return tml.getTransactionManager( props );
+	}
+}

Added: trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc/TreeCacheRegionAdapter.java
===================================================================
--- trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc/TreeCacheRegionAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc/TreeCacheRegionAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,105 @@
+package org.hibernate.cache.impl.jbc;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Cache;
+import org.jboss.cache.Node;
+import org.jboss.cache.config.Option;
+
+import org.hibernate.cache.Region;
+import org.hibernate.cache.CacheException;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class TreeCacheRegionAdapter implements Region {
+	private static final String ITEM = "item";
+
+	protected final Node jbcNode;
+	protected final String regionName;
+
+	public TreeCacheRegionAdapter(Cache jbcCache, String regionName) {
+		this.regionName = regionName;
+		Fqn fqn = Fqn.fromString( regionName.replace( '.', '/' ) );
+		this.jbcNode = jbcCache.getRoot().addChild( fqn );
+	}
+
+	public String getName() {
+		return regionName;
+	}
+
+	public void destroy() throws CacheException {
+		try {
+			// NOTE : this is being used from the process of shutting down a
+			// SessionFactory.  Specific things to consider:
+			// 		(1) this clearing of the region should not propogate to
+			// 			other nodes on the cluster (if any); this is the
+			//			cache-mode-local option bit...
+			//		(2) really just trying a best effort to cleanup after
+			// 			ourselves; lock failures, etc are not critical here;
+			//			this is the fail-silently option bit...
+			Option option = new Option();
+			option.setCacheModeLocal( true );
+			option.setFailSilently( true );
+			jbcNode.
+			jbcTreeCache.remove( regionFqn, option );
+		}
+		catch( Exception e ) {
+			throw new CacheException( e );
+		}
+	}
+
+	public long getSizeInMemory() {
+		// not supported
+		return -1;
+	}
+
+	public long getElementCountInMemory() {
+		try {
+			Set children = jbcTreeCache.getChildrenNames( regionFqn );
+			return children == null ? 0 : children.size();
+		}
+		catch ( Exception e ) {
+			throw new CacheException( e );
+		}
+	}
+
+	public long getElementCountOnDisk() {
+		return -1;
+	}
+
+	public Map toMap() {
+		try {
+			Map result = new HashMap();
+			Set childrenNames = jbcTreeCache.getChildrenNames( regionFqn );
+			if (childrenNames != null) {
+				Iterator iter = childrenNames.iterator();
+				while ( iter.hasNext() ) {
+					Object key = iter.next();
+					result.put(
+							key,
+					        jbcTreeCache.get( new Fqn( regionFqn, key ), ITEM )
+						);
+				}
+			}
+			return result;
+		}
+		catch (Exception e) {
+			throw new CacheException(e);
+		}
+	}
+
+	public long nextTimestamp() {
+		return System.currentTimeMillis() / 100;
+	}
+
+	public int getTimeout() {
+		return 600; //60 seconds
+	}
+}

Added: trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc/TreeCacheRegionFactory.java
===================================================================
--- trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc/TreeCacheRegionFactory.java	                        (rev 0)
+++ trunk/Hibernate3/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc/TreeCacheRegionFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,226 @@
+package org.hibernate.cache.impl.jbc;
+
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.Cache;
+import org.jboss.cache.DefaultCacheFactory;
+
+import org.hibernate.cache.RegionFactory;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.EntityRegion;
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.cache.CollectionRegion;
+import org.hibernate.cache.QueryResultsRegion;
+import org.hibernate.cache.TimestampsRegion;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cache.access.AccessType;
+import org.hibernate.cfg.Settings;
+import org.hibernate.util.PropertiesHelper;
+
+/**
+ * A factory for building regions based on a JBossCache
+ * {@link org.jboss.cache.Node}.  Here we are utilizing the
+ * same underlying {@link org.jboss.cache.Node} instance for each jbcTreeCache region.
+ *
+ * @author Steve Ebersole
+ */
+public class TreeCacheRegionFactory implements RegionFactory {
+	public static final String ENTITY_CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc.cfg.entity";
+	public static final String COLL_CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc.cfg.collection";
+	public static final String TS_CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc.cfg.ts";
+	public static final String QUERY_CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc.cfg.query";
+
+	public static final String DEF_ENTITY_RESOURCE = "entity-cache.xml";
+	public static final String DEF_COLL_RESOURCE = "collection-cache.xml";
+	public static final String DEF_TS_RESOURCE = "ts-cache.xml";
+	public static final String DEF_QUERY_RESOURCE = "query-cache.xml";
+
+	public static final String OPTIMISTIC_LOCKING_SCHEME = "OPTIMISTIC";
+
+	private static final Log log = LogFactory.getLog( TreeCacheRegionFactory.class );
+
+	private Cache jbcEntityCache;
+	private Cache jbcCollectionCache;
+	private Cache jbcTsCache;
+	private Cache jbcQueryCache;
+	private boolean useOptimisticLocking;
+
+	public void start(Settings settings, Properties properties) throws CacheException {
+		try {
+			TransactionManager tm = settings.getTransactionManagerLookup() == null
+					? null
+					: settings.getTransactionManagerLookup().getTransactionManager( properties );
+			if ( settings.isSecondLevelCacheEnabled() ) {
+				jbcEntityCache = buildEntityRegionCacheInstance( properties );
+				jbcCollectionCache = buildCollectionRegionCacheInstance( properties );
+				if ( tm != null ) {
+					jbcEntityCache.getConfiguration().getRuntimeConfig().setTransactionManager( tm );
+					jbcCollectionCache.getConfiguration().getRuntimeConfig().setTransactionManager( tm );
+				}
+			}
+			if ( settings.isQueryCacheEnabled() ) {
+				jbcTsCache = buildTsRegionCacheInstance( properties );
+				jbcQueryCache = buildQueryRegionCacheInstance( properties );
+			}
+		}
+		catch( CacheException ce ) {
+			throw ce;
+		}
+		catch( Throwable t ) {
+			throw new CacheException( "Unable to start region factory", t );
+		}
+//		String resource = PropertiesHelper.getString( Environment.CACHE_PROVIDER_CONFIG, properties, DEFAULT_CONFIG );
+//		log.debug( "Configuring basic TreeCache RegionFactory from resource [" + resource + "]" );
+//		try {
+//			jbcTreeCache = new TreeCache();
+//			PropertyConfigurator config = new PropertyConfigurator();
+//			config.configure( jbcTreeCache, resource );
+//			TransactionManagerLookup transactionManagerLookup = settings.getTransactionManagerLookup();
+//			if ( transactionManagerLookup != null ) {
+//				jbcTreeCache.setTransactionManagerLookup(
+//						new TransactionManagerLookupAdaptor( transactionManagerLookup, properties )
+//				);
+//			}
+//			jbcTreeCache.start();
+//			useOptimisticLocking = OPTIMISTIC_LOCKING_SCHEME.equalsIgnoreCase( jbcTreeCache.getNodeLockingScheme() );
+//		}
+//		catch ( Exception e ) {
+//			throw new CacheException( e );
+//		}
+	}
+
+	protected Cache buildEntityRegionCacheInstance(Properties properties) {
+		try {
+			String configResource = PropertiesHelper.getString( ENTITY_CACHE_RESOURCE_PROP, properties, DEF_ENTITY_RESOURCE );
+			return DefaultCacheFactory.getInstance().createCache( configResource );
+		}
+		catch( Throwable t ) {
+			throw new CacheException( "unable to build entity region cache instance", t );
+		}
+	}
+
+	protected Cache buildCollectionRegionCacheInstance(Properties properties) {
+		try {
+			String configResource = PropertiesHelper.getString( COLL_CACHE_RESOURCE_PROP, properties, DEF_COLL_RESOURCE );
+			return DefaultCacheFactory.getInstance().createCache( configResource );
+		}
+		catch( Throwable t ) {
+			throw new CacheException( "unable to build collection region cache instance", t );
+		}
+	}
+
+	protected Cache buildTsRegionCacheInstance(Properties properties) {
+		try {
+			String configResource = PropertiesHelper.getString( TS_CACHE_RESOURCE_PROP, properties, DEF_TS_RESOURCE );
+			return DefaultCacheFactory.getInstance().createCache( configResource );
+		}
+		catch( Throwable t ) {
+			throw new CacheException( "unable to build timestamps region cache instance", t );
+		}
+	}
+
+	protected Cache buildQueryRegionCacheInstance(Properties properties) {
+		try {
+			String configResource = PropertiesHelper.getString( QUERY_CACHE_RESOURCE_PROP, properties, DEF_QUERY_RESOURCE );
+			return DefaultCacheFactory.getInstance().createCache( configResource );
+		}
+		catch( Throwable t ) {
+			throw new CacheException( "unable to build query region cache instance", t );
+		}
+	}
+
+	public void stop() {
+		if ( jbcEntityCache != null ) {
+			try {
+				jbcEntityCache.stop();
+			}
+			catch( Throwable t ) {
+				log.info( "Unable to stop entity cache instance", t );
+			}
+		}
+		if ( jbcCollectionCache != null ) {
+			try {
+				jbcCollectionCache.stop();
+			}
+			catch( Throwable t ) {
+				log.info( "Unable to stop collection cache instance", t );
+			}
+		}
+		if ( jbcTsCache != null ) {
+			try {
+				jbcTsCache.stop();
+			}
+			catch( Throwable t ) {
+				log.info( "Unable to stop timestamp cache instance", t );
+			}
+		}
+		if ( jbcQueryCache != null ) {
+			try {
+				jbcQueryCache.stop();
+			}
+			catch( Throwable t ) {
+				log.info( "Unable to stop query cache instance", t );
+			}
+		}
+	}
+
+	public boolean isMinimalPutsEnabledByDefault() {
+		return true;
+	}
+
+	public long nextTimestamp() {
+		return System.currentTimeMillis() / 100;
+	}
+
+	public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata) {
+		if ( useOptimisticLocking && !metadata.isVersioned() ) {
+			log.warn( "JBossCache configured to use optimistic locking, but entity to be cached is not versioned [" + regionName + "]" );
+		}
+		else if ( !useOptimisticLocking && metadata.isVersioned() ) {
+			log.info( "Caching versioned entity without optimisitic locking; consider optimistic locking if all cached entities are versioned" );
+		}
+		return new EntityRegionAdapter( regionName, metadata );
+	}
+
+	public CollectionRegion buildCollectionRegion(String regionName, Properties properties, CacheDataDescription metadata)
+			throws CacheException {
+		return null;
+	}
+
+	public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException {
+		return null;
+	}
+
+	public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException {
+		return null;
+	}
+
+	private class EntityRegionAdapter extends TreeCacheRegionAdapter implements EntityRegion {
+		private final CacheDataDescription metadata;
+
+		public EntityRegionAdapter(String regionName, CacheDataDescription metadata) {
+			super( TreeCacheRegionFactory.this.jbcTreeCache, regionName );
+			this.metadata = metadata;
+		}
+
+		public boolean isTransactionAware() {
+			return jbcTreeCache.getTransactionManager() != null;
+		}
+
+		public CacheDataDescription getCacheDataDescription() {
+			return metadata;
+		}
+
+		public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
+			if ( ! ( AccessType.READ_ONLY.equals( accessType ) || AccessType.TRANSACTIONAL.equals( accessType ) ) ) {
+				throw new CacheException( "TreeCacheRegionFactory only supports ( " + AccessType.READ_ONLY.getName() + " | " + AccessType.TRANSACTIONAL + " ) access strategies [" + accessType.getName() + "]" );
+			}
+			// todo : implement :)
+			return null;
+		}
+	}
+}

Added: trunk/Hibernate3/cache-oscache/pom.xml
===================================================================
--- trunk/Hibernate3/cache-oscache/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/cache-oscache/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.hibernate</groupId>
+    <artifactId>hibernate-oscache</artifactId>
+    <packaging>jar</packaging>
+    <name>Hibernate OSCache integration</name>
+    <description>Integration of Hibernate with OSCache</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>opensymphony</groupId>
+            <artifactId>oscache</artifactId>
+            <version>2.1</version>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

Added: trunk/Hibernate3/cache-oscache/src/main/java/org/hibernate/cache/OSCache.java
===================================================================
--- trunk/Hibernate3/cache-oscache/src/main/java/org/hibernate/cache/OSCache.java	                        (rev 0)
+++ trunk/Hibernate3/cache-oscache/src/main/java/org/hibernate/cache/OSCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,111 @@
+//$Id: OSCache.java 6478 2005-04-21 07:57:19Z oneovthafew $
+package org.hibernate.cache;
+
+import java.util.Map;
+
+import com.opensymphony.oscache.base.NeedsRefreshException;
+import com.opensymphony.oscache.general.GeneralCacheAdministrator;
+
+/**
+ * @author <a href="mailto:m.bogaert at intrasoft.be">Mathias Bogaert</a>
+ */
+public class OSCache implements Cache {
+
+	/** 
+	 * The OSCache 2.0 cache administrator. 
+	 */
+	private GeneralCacheAdministrator cache = new GeneralCacheAdministrator();
+
+	private final int refreshPeriod;
+	private final String cron;
+	private final String regionName;
+	
+	private String toString(Object key) {
+		return String.valueOf(key) + '.' + regionName;
+	}
+
+	public OSCache(int refreshPeriod, String cron, String region) {
+		this.refreshPeriod = refreshPeriod;
+		this.cron = cron;
+		this.regionName = region;
+	}
+
+	public void setCacheCapacity(int cacheCapacity) {
+		cache.setCacheCapacity(cacheCapacity);
+	}
+
+	public Object get(Object key) throws CacheException {
+		try {
+			return cache.getFromCache( toString(key), refreshPeriod, cron );
+		}
+		catch (NeedsRefreshException e) {
+			cache.cancelUpdate( toString(key) );
+			return null;
+		}
+	}
+
+	public Object read(Object key) throws CacheException {
+		return get(key);
+	}
+	
+	public void update(Object key, Object value) throws CacheException {
+		put(key, value);
+	}
+	
+	public void put(Object key, Object value) throws CacheException {
+		cache.putInCache( toString(key), value );
+	}
+
+	public void remove(Object key) throws CacheException {
+		cache.flushEntry( toString(key) );
+	}
+
+	public void clear() throws CacheException {
+		cache.flushAll();
+	}
+
+	public void destroy() throws CacheException {
+		cache.destroy();
+	}
+
+	public void lock(Object key) throws CacheException {
+		// local cache, so we use synchronization
+	}
+
+	public void unlock(Object key) throws CacheException {
+		// local cache, so we use synchronization
+	}
+
+	public long nextTimestamp() {
+		return Timestamper.next();
+	}
+
+	public int getTimeout() {
+		return Timestamper.ONE_MS * 60000; //ie. 60 seconds
+	}
+
+	public String getRegionName() {
+		return regionName;
+	}
+
+	public long getSizeInMemory() {
+		return -1;
+	}
+
+	public long getElementCountInMemory() {
+		return -1;
+	}
+
+	public long getElementCountOnDisk() {
+		return -1;
+	}
+
+	public Map toMap() {
+		throw new UnsupportedOperationException();
+	}
+
+	public String toString() {
+		return "OSCache(" + regionName + ')';
+	}
+
+}

Added: trunk/Hibernate3/cache-oscache/src/main/java/org/hibernate/cache/OSCacheProvider.java
===================================================================
--- trunk/Hibernate3/cache-oscache/src/main/java/org/hibernate/cache/OSCacheProvider.java	                        (rev 0)
+++ trunk/Hibernate3/cache-oscache/src/main/java/org/hibernate/cache/OSCacheProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,87 @@
+//$Id: OSCacheProvider.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.cache;
+
+import java.util.Properties;
+
+import org.hibernate.util.PropertiesHelper;
+import org.hibernate.util.StringHelper;
+
+import com.opensymphony.oscache.base.CacheEntry;
+import com.opensymphony.oscache.base.Config;
+
+/**
+ * Support for OpenSymphony OSCache. This implementation assumes
+ * that identifiers have well-behaved <tt>toString()</tt> methods.
+ *
+ * @author <a href="mailto:m.bogaert at intrasoft.be">Mathias Bogaert</a>
+ */
+public class OSCacheProvider implements CacheProvider {
+
+	/**
+	 * The <tt>OSCache</tt> refresh period property suffix.
+	 */
+	public static final String OSCACHE_REFRESH_PERIOD = "refresh.period";
+	/**
+	 * The <tt>OSCache</tt> CRON expression property suffix.
+	 */
+	public static final String OSCACHE_CRON = "cron";
+	/**
+	 * The <tt>OSCache</tt> cache capacity property suffix.
+	 */
+	public static final String OSCACHE_CAPACITY = "capacity";
+
+	private static final Properties OSCACHE_PROPERTIES = new Config().getProperties();
+
+	/**
+	 * Builds a new {@link Cache} instance, and gets it's properties from the OSCache {@link Config}
+	 * which reads the properties file (<code>oscache.properties</code>) from the classpath.
+	 * If the file cannot be found or loaded, an the defaults are used.
+	 *
+	 * @param region
+	 * @param properties
+	 * @return
+	 * @throws CacheException
+	 */
+	public Cache buildCache(String region, Properties properties) throws CacheException {
+
+		int refreshPeriod = PropertiesHelper.getInt(
+			StringHelper.qualify(region, OSCACHE_REFRESH_PERIOD),
+			OSCACHE_PROPERTIES,
+			CacheEntry.INDEFINITE_EXPIRY
+		);
+		String cron = OSCACHE_PROPERTIES.getProperty( StringHelper.qualify(region, OSCACHE_CRON) );
+
+		// construct the cache
+		final OSCache cache = new OSCache(refreshPeriod, cron, region);
+
+		Integer capacity = PropertiesHelper.getInteger( StringHelper.qualify(region, OSCACHE_CAPACITY), OSCACHE_PROPERTIES );
+		if ( capacity!=null ) cache.setCacheCapacity( capacity.intValue() );
+
+		return cache;
+	}
+
+	public long nextTimestamp() {
+		return Timestamper.next();
+	}
+
+	/**
+	 * Callback to perform any necessary initialization of the underlying cache implementation
+	 * during SessionFactory construction.
+	 *
+	 * @param properties current configuration settings.
+	 */
+	public void start(Properties properties) throws CacheException {
+	}
+
+	/**
+	 * Callback to perform any necessary cleanup of the underlying cache implementation
+	 * during SessionFactory.close().
+	 */
+	public void stop() {
+	}
+
+	public boolean isMinimalPutsEnabledByDefault() {
+		return false;
+	}
+
+}

Added: trunk/Hibernate3/cache-swarmcache/pom.xml
===================================================================
--- trunk/Hibernate3/cache-swarmcache/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/cache-swarmcache/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.hibernate</groupId>
+    <artifactId>hibernate-swarmcache</artifactId>
+    <packaging>jar</packaging>
+    <name>Hibernate SwarmCache integration</name>
+    <description>Integration of Hibernate with SwarmCache</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>swarmcache</groupId>
+            <artifactId>swarmcache</artifactId>
+            <version>1.0RC2</version>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

Added: trunk/Hibernate3/cache-swarmcache/src/main/java/org/hibernate/cache/SwarmCache.java
===================================================================
--- trunk/Hibernate3/cache-swarmcache/src/main/java/org/hibernate/cache/SwarmCache.java	                        (rev 0)
+++ trunk/Hibernate3/cache-swarmcache/src/main/java/org/hibernate/cache/SwarmCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,144 @@
+//$Id: SwarmCache.java 6478 2005-04-21 07:57:19Z oneovthafew $
+package org.hibernate.cache;
+
+import net.sf.swarmcache.ObjectCache;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * @author Jason Carreira, Gavin King
+ */
+public class SwarmCache implements Cache {
+	
+    private final ObjectCache cache;
+    private final String regionName;
+    
+    public SwarmCache(ObjectCache cache, String regionName) {
+        this.cache = cache;
+        this.regionName = regionName;
+    }
+
+    /**
+     * Get an item from the cache
+     * @param key
+     * @return the cached object or <tt>null</tt>
+     * @throws CacheException
+     */
+    public Object get(Object key) throws CacheException {
+        if (key instanceof Serializable) {
+            return cache.get( (Serializable) key );
+        } 
+        else {
+            throw new CacheException("Keys must implement Serializable");
+        }
+    }
+
+    public Object read(Object key) throws CacheException {
+		return get(key);
+    }
+	
+    /**
+     * Add an item to the cache
+     * @param key
+     * @param value
+     * @throws CacheException
+     */
+    public void update(Object key, Object value) throws CacheException {
+		put(key, value);
+	}
+	
+    /**
+     * Add an item to the cache
+     * @param key
+     * @param value
+     * @throws CacheException
+     */
+	public void put(Object key, Object value) throws CacheException {
+        if (key instanceof Serializable) {
+            cache.put( (Serializable) key, value );
+        } 
+        else {
+            throw new CacheException("Keys must implement Serializable");
+        }
+    }
+
+    /**
+     * Remove an item from the cache
+     */
+    public void remove(Object key) throws CacheException {
+        if (key instanceof Serializable) {
+            cache.clear( (Serializable) key );
+        } 
+        else {
+            throw new CacheException("Keys must implement Serializable");
+        }
+    }
+
+    /**
+     * Clear the cache
+     */
+    public void clear() throws CacheException {
+        cache.clearAll();
+    }
+
+    /**
+     * Clean up
+     */
+    public void destroy() throws CacheException {
+        cache.clearAll();
+    }
+
+    /**
+     * If this is a clustered cache, lock the item
+     */
+    public void lock(Object key) throws CacheException {
+        throw new UnsupportedOperationException("SwarmCache does not support locking (use nonstrict-read-write)");
+    }
+
+    /**
+     * If this is a clustered cache, unlock the item
+     */
+    public void unlock(Object key) throws CacheException {
+		throw new UnsupportedOperationException("SwarmCache does not support locking (use nonstrict-read-write)");
+    }
+
+    /**
+     * Generate a (coarse) timestamp
+     */
+    public long nextTimestamp() {
+    	return System.currentTimeMillis() / 100;
+    }
+
+    /**
+     * Get a reasonable "lock timeout"
+     */
+    public int getTimeout() {
+		return 600;
+    }
+
+	public String getRegionName() {
+		return regionName;
+	}
+
+	public long getSizeInMemory() {
+		return -1;
+	}
+
+	public long getElementCountInMemory() {
+		return -1;
+	}
+
+	public long getElementCountOnDisk() {
+		return -1;
+	}
+	
+	public Map toMap() {
+		throw new UnsupportedOperationException();
+	}
+
+	public String toString() {
+		return "SwarmCache(" + regionName + ')';
+	}
+
+}

Added: trunk/Hibernate3/cache-swarmcache/src/main/java/org/hibernate/cache/SwarmCacheProvider.java
===================================================================
--- trunk/Hibernate3/cache-swarmcache/src/main/java/org/hibernate/cache/SwarmCacheProvider.java	                        (rev 0)
+++ trunk/Hibernate3/cache-swarmcache/src/main/java/org/hibernate/cache/SwarmCacheProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,58 @@
+//$Id: SwarmCacheProvider.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.cache;
+
+import net.sf.swarmcache.CacheConfiguration;
+import net.sf.swarmcache.CacheConfigurationManager;
+import net.sf.swarmcache.CacheFactory;
+import net.sf.swarmcache.ObjectCache;
+
+import java.util.Properties;
+
+/**
+ * Support for SwarmCache replicated cache. SwarmCache does not support
+ * locking, so strict "read-write" semantics are unsupported.
+ * @author Jason Carreira
+ */
+public class SwarmCacheProvider implements CacheProvider {
+
+	private CacheFactory factory;
+
+    public Cache buildCache(String regionName, Properties properties) throws CacheException {
+        ObjectCache cache = factory.createCache(regionName);
+        if (cache==null) {
+	        throw new CacheException("SwarmCache did not create a cache: " + regionName);
+        }
+        return new SwarmCache(cache, regionName);
+    }
+
+    public long nextTimestamp() {
+        return System.currentTimeMillis() / 100;
+    }
+
+	/**
+	 * Callback to perform any necessary initialization of the underlying cache implementation
+	 * during SessionFactory construction.
+	 *
+	 * @param properties current configuration settings.
+	 */
+	public void start(Properties properties) throws CacheException {
+        CacheConfiguration config = CacheConfigurationManager.getConfig(properties);
+        factory = new CacheFactory(config);
+	}
+
+	/**
+	 * Callback to perform any necessary cleanup of the underlying cache implementation
+	 * during SessionFactory.close().
+	 */
+	public void stop() {
+		if (factory != null) {
+			factory.shutdown();
+			factory = null;
+		}
+	}
+
+	public boolean isMinimalPutsEnabledByDefault() {
+		return true;
+	}
+
+}

Deleted: trunk/Hibernate3/checkstyle_checks.xml
===================================================================
--- trunk/Hibernate3/checkstyle_checks.xml	2007-05-24 19:06:06 UTC (rev 11562)
+++ trunk/Hibernate3/checkstyle_checks.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -1,115 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.1//EN" "http://www.puppycrawl.com/dtds/configuration_1_1.dtd">
-<module name="Checker">
-    <module name="TreeWalker">
-        <module name="com.puppycrawl.tools.checkstyle.checks.blocks.AvoidNestedBlocksCheck">
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.imports.AvoidStarImportCheck">
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.naming.ConstantNameCheck">
-            <property name="format" value="^[A-Z](_?[A-Z0-9]+)*$|log"/>
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.coding.EmptyStatementCheck">
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.coding.EqualsHashCodeCheck">
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.design.FinalClassCheck">
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.GenericIllegalRegexpCheck">
-            <property name="format" value="\(\(|\)\)"/>
-            <property name="ignoreCase" value="false"/>
-            <property name="message" value="stacked parentheses"/>
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck">
-            <property name="severity" value="warning"/>
-            <property name="tokens" value="VARIABLE_DEF"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.design.HideUtilityClassConstructorCheck">
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.coding.IllegalInstantiationCheck">
-            <property name="classes" value="{}"/>
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.coding.InnerAssignmentCheck">
-            <property name="severity" value="warning"/>
-            <property name="tokens" value="ASSIGN, BAND_ASSIGN, BOR_ASSIGN, BSR_ASSIGN, BXOR_ASSIGN, DIV_ASSIGN, MINUS_ASSIGN, MOD_ASSIGN, PLUS_ASSIGN, SL_ASSIGN, SR_ASSIGN, STAR_ASSIGN"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.design.InterfaceIsTypeCheck">
-            <property name="allowMarkerInterfaces" value="true"/>
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.blocks.LeftCurlyCheck">
-            <property name="maxLineLength" value="80"/>
-            <property name="option" value="eol"/>
-            <property name="severity" value="warning"/>
-            <property name="tokens" value="CLASS_DEF, CTOR_DEF, INTERFACE_DEF, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, METHOD_DEF"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.naming.LocalFinalVariableNameCheck">
-            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck">
-            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.naming.MemberNameCheck">
-            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.naming.MethodNameCheck">
-            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.ModifierOrderCheck">
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.blocks.NeedBracesCheck">
-            <property name="severity" value="warning"/>
-            <property name="tokens" value="LITERAL_DO, LITERAL_ELSE"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.naming.PackageNameCheck">
-            <property name="format" value="^[a-z]+(\.[a-zA-Z_][a-zA-Z0-9_]*)*$"/>
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.imports.RedundantImportCheck">
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.blocks.RightCurlyCheck">
-            <property name="option" value="alone"/>
-            <property name="severity" value="warning"/>
-            <property name="tokens" value="LITERAL_CATCH, LITERAL_ELSE, LITERAL_TRY"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.coding.SimplifyBooleanExpressionCheck">
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.coding.SimplifyBooleanReturnCheck">
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.naming.StaticVariableNameCheck">
-            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.naming.TypeNameCheck">
-            <property name="format" value="^[A-Z][a-zA-Z0-9]*$"/>
-            <property name="severity" value="warning"/>
-            <property name="tokens" value="CLASS_DEF, INTERFACE_DEF"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.imports.UnusedImportsCheck">
-            <property name="severity" value="warning"/>
-        </module>
-        <module name="com.puppycrawl.tools.checkstyle.checks.design.VisibilityModifierCheck">
-            <property name="packageAllowed" value="true"/>
-            <property name="protectedAllowed" value="true"/>
-            <property name="publicMemberPattern" value="^serialVersionUID"/>
-            <property name="severity" value="warning"/>
-        </module>
-    </module>
-</module>

Added: trunk/Hibernate3/connection-c3p0/pom.xml
===================================================================
--- trunk/Hibernate3/connection-c3p0/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/connection-c3p0/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.hibernate</groupId>
+    <artifactId>hibernate-c3p0</artifactId>
+    <packaging>jar</packaging>
+    <name>Hibernate C3P0 ConnectionProvider</name>
+    <description>C3P0-based implementation of the Hibernate ConnectionProvder contract</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>c3p0</groupId>
+            <artifactId>c3p0</artifactId>
+            <version>0.9.1</version>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

Added: trunk/Hibernate3/connection-c3p0/src/main/java/org/hibernate/connection/C3P0ConnectionProvider.java
===================================================================
--- trunk/Hibernate3/connection-c3p0/src/main/java/org/hibernate/connection/C3P0ConnectionProvider.java	                        (rev 0)
+++ trunk/Hibernate3/connection-c3p0/src/main/java/org/hibernate/connection/C3P0ConnectionProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,218 @@
+//$Id: C3P0ConnectionProvider.java 11066 2007-01-19 15:14:31Z steve.ebersole at jboss.com $
+package org.hibernate.connection;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Iterator;
+import java.util.Properties;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.mchange.v2.c3p0.DataSources;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.util.PropertiesHelper;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * A connection provider that uses a C3P0 connection pool. Hibernate will use this by
+ * default if the <tt>hibernate.c3p0.*</tt> properties are set.
+ *
+ * @author various people
+ * @see ConnectionProvider
+ */
+public class C3P0ConnectionProvider implements ConnectionProvider {
+
+	private static final Log log = LogFactory.getLog( C3P0ConnectionProvider.class );
+
+	//swaldman 2006-08-28: define c3p0-style configuration parameters for properties with
+	//                     hibernate-specific overrides to detect and warn about conflicting
+	//                     declarations
+	private final static String C3P0_STYLE_MIN_POOL_SIZE = "c3p0.minPoolSize";
+	private final static String C3P0_STYLE_MAX_POOL_SIZE = "c3p0.maxPoolSize";
+	private final static String C3P0_STYLE_MAX_IDLE_TIME = "c3p0.maxIdleTime";
+	private final static String C3P0_STYLE_MAX_STATEMENTS = "c3p0.maxStatements";
+	private final static String C3P0_STYLE_ACQUIRE_INCREMENT = "c3p0.acquireIncrement";
+	private final static String C3P0_STYLE_IDLE_CONNECTION_TEST_PERIOD = "c3p0.idleConnectionTestPeriod";
+	private final static String C3P0_STYLE_TEST_CONNECTION_ON_CHECKOUT = "c3p0.testConnectionOnCheckout";
+
+	//swaldman 2006-08-28: define c3p0-style configuration parameters for initialPoolSize, which
+	//                     hibernate sensibly lets default to minPoolSize, but we'll let users
+	//                     override it with the c3p0-style property if they want.
+	private final static String C3P0_STYLE_INITIAL_POOL_SIZE = "c3p0.initialPoolSize";
+
+	private DataSource ds;
+	private Integer isolation;
+	private boolean autocommit;
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Connection getConnection() throws SQLException {
+		final Connection c = ds.getConnection();
+		if ( isolation != null ) {
+			c.setTransactionIsolation( isolation.intValue() );
+		}
+		if ( c.getAutoCommit() != autocommit ) {
+			c.setAutoCommit( autocommit );
+		}
+		return c;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public void closeConnection(Connection conn) throws SQLException {
+		conn.close();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public void configure(Properties props) throws HibernateException {
+		String jdbcDriverClass = props.getProperty( Environment.DRIVER );
+		String jdbcUrl = props.getProperty( Environment.URL );
+		Properties connectionProps = ConnectionProviderFactory.getConnectionProperties( props );
+
+		log.info( "C3P0 using driver: " + jdbcDriverClass + " at URL: " + jdbcUrl );
+		log.info( "Connection properties: " + PropertiesHelper.maskOut( connectionProps, "password" ) );
+
+		autocommit = PropertiesHelper.getBoolean( Environment.AUTOCOMMIT, props );
+		log.info( "autocommit mode: " + autocommit );
+
+		if ( jdbcDriverClass == null ) {
+			log.warn( "No JDBC Driver class was specified by property " + Environment.DRIVER );
+		}
+		else {
+			try {
+				Class.forName( jdbcDriverClass );
+			}
+			catch ( ClassNotFoundException cnfe ) {
+				try {
+					ReflectHelper.classForName( jdbcDriverClass );
+				}
+				catch ( ClassNotFoundException e ) {
+					String msg = "JDBC Driver class not found: " + jdbcDriverClass;
+					log.fatal( msg, e );
+					throw new HibernateException( msg, e );
+				}
+			}
+		}
+
+		try {
+
+			//swaldman 2004-02-07: modify to allow null values to signify fall through to c3p0 PoolConfig defaults
+			Integer minPoolSize = PropertiesHelper.getInteger( Environment.C3P0_MIN_SIZE, props );
+			Integer maxPoolSize = PropertiesHelper.getInteger( Environment.C3P0_MAX_SIZE, props );
+			Integer maxIdleTime = PropertiesHelper.getInteger( Environment.C3P0_TIMEOUT, props );
+			Integer maxStatements = PropertiesHelper.getInteger( Environment.C3P0_MAX_STATEMENTS, props );
+			Integer acquireIncrement = PropertiesHelper.getInteger( Environment.C3P0_ACQUIRE_INCREMENT, props );
+			Integer idleTestPeriod = PropertiesHelper.getInteger( Environment.C3P0_IDLE_TEST_PERIOD, props );
+
+			Properties c3props = new Properties();
+
+			// turn hibernate.c3p0.* into c3p0.*, so c3p0
+			// gets a chance to see all hibernate.c3p0.*
+			for ( Iterator ii = props.keySet().iterator(); ii.hasNext(); ) {
+				String key = ( String ) ii.next();
+				if ( key.startsWith( "hibernate.c3p0." ) ) {
+					String newKey = key.substring( 10 );
+					if ( props.containsKey( newKey ) ) {
+						warnPropertyConflict( key, newKey );
+					}
+					c3props.put( newKey, props.get( key ) );
+				}
+			}
+
+			setOverwriteProperty( Environment.C3P0_MIN_SIZE, C3P0_STYLE_MIN_POOL_SIZE, props, c3props, minPoolSize );
+			setOverwriteProperty( Environment.C3P0_MAX_SIZE, C3P0_STYLE_MAX_POOL_SIZE, props, c3props, maxPoolSize );
+			setOverwriteProperty( Environment.C3P0_TIMEOUT, C3P0_STYLE_MAX_IDLE_TIME, props, c3props, maxIdleTime );
+			setOverwriteProperty(
+					Environment.C3P0_MAX_STATEMENTS, C3P0_STYLE_MAX_STATEMENTS, props, c3props, maxStatements
+			);
+			setOverwriteProperty(
+					Environment.C3P0_ACQUIRE_INCREMENT, C3P0_STYLE_ACQUIRE_INCREMENT, props, c3props, acquireIncrement
+			);
+			setOverwriteProperty(
+					Environment.C3P0_IDLE_TEST_PERIOD, C3P0_STYLE_IDLE_CONNECTION_TEST_PERIOD, props, c3props, idleTestPeriod
+			);
+
+			// revert to traditional hibernate behavior of setting initialPoolSize to minPoolSize
+			// unless otherwise specified with a c3p0.*-style parameter.
+			Integer initialPoolSize = PropertiesHelper.getInteger( C3P0_STYLE_INITIAL_POOL_SIZE, props );
+			if ( initialPoolSize == null && minPoolSize != null ) {
+				c3props.put( C3P0_STYLE_INITIAL_POOL_SIZE, String.valueOf( minPoolSize ).trim() );
+			}
+
+			/*DataSource unpooled = DataSources.unpooledDataSource(
+				jdbcUrl, props.getProperty(Environment.USER), props.getProperty(Environment.PASS)
+			);*/
+			DataSource unpooled = DataSources.unpooledDataSource( jdbcUrl, connectionProps );
+
+			Properties allProps = ( Properties ) props.clone();
+			allProps.putAll( c3props );
+
+			ds = DataSources.pooledDataSource( unpooled, allProps );
+		}
+		catch ( Exception e ) {
+			log.fatal( "could not instantiate C3P0 connection pool", e );
+			throw new HibernateException( "Could not instantiate C3P0 connection pool", e );
+		}
+
+		String i = props.getProperty( Environment.ISOLATION );
+		if ( i == null ) {
+			isolation = null;
+		}
+		else {
+			isolation = new Integer( i );
+			log.info( "JDBC isolation level: " + Environment.isolationLevelToString( isolation.intValue() ) );
+		}
+
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public void close() {
+		try {
+			DataSources.destroy( ds );
+		}
+		catch ( SQLException sqle ) {
+			log.warn( "could not destroy C3P0 connection pool", sqle );
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public boolean supportsAggressiveRelease() {
+		return false;
+	}
+
+	private void setOverwriteProperty(String hibernateStyleKey, String c3p0StyleKey, Properties hibp, Properties c3p, Integer value) {
+		if ( value != null ) {
+			c3p.put( c3p0StyleKey, String.valueOf( value ).trim() );
+			if ( hibp.getProperty( c3p0StyleKey ) != null ) {
+				warnPropertyConflict( hibernateStyleKey, c3p0StyleKey );
+			}
+			String longC3p0StyleKey = "hibernate." + c3p0StyleKey;
+			if ( hibp.getProperty( longC3p0StyleKey ) != null ) {
+				warnPropertyConflict( hibernateStyleKey, longC3p0StyleKey );
+			}
+		}
+	}
+
+	private void warnPropertyConflict(String hibernateStyle, String c3p0Style) {
+		log.warn(
+				"Both hibernate-style property '" + hibernateStyle +
+						"' and c3p0-style property '" + c3p0Style +
+						"' have been set in hibernate.properties. " +
+						"Hibernate-style property '" + hibernateStyle + "' will be used " +
+						"and c3p0-style property '" + c3p0Style + "' will be ignored!"
+		);
+	}
+}

Added: trunk/Hibernate3/connection-proxool/pom.xml
===================================================================
--- trunk/Hibernate3/connection-proxool/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/connection-proxool/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.hibernate</groupId>
+    <artifactId>hibernate-proxool</artifactId>
+    <packaging>jar</packaging>
+    <name>Hibernate Proxool ConnectionProvider</name>
+    <description>Proxool-based implementation of the Hibernate ConnectionProvder contract</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>proxool</groupId>
+            <artifactId>proxool</artifactId>
+            <version>0.8.3</version>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

Added: trunk/Hibernate3/connection-proxool/src/main/java/org/hibernate/connection/ProxoolConnectionProvider.java
===================================================================
--- trunk/Hibernate3/connection-proxool/src/main/java/org/hibernate/connection/ProxoolConnectionProvider.java	                        (rev 0)
+++ trunk/Hibernate3/connection-proxool/src/main/java/org/hibernate/connection/ProxoolConnectionProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,199 @@
+//$Id: ProxoolConnectionProvider.java 6463 2005-04-19 15:39:07Z steveebersole $
+package org.hibernate.connection;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.util.PropertiesHelper;
+import org.hibernate.util.StringHelper;
+import org.hibernate.util.ConfigHelper;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.logicalcobwebs.proxool.ProxoolException;
+import org.logicalcobwebs.proxool.ProxoolFacade;
+import org.logicalcobwebs.proxool.configuration.JAXPConfigurator;
+import org.logicalcobwebs.proxool.configuration.PropertyConfigurator;
+
+/**
+ * A connection provider that uses a Proxool connection pool. Hibernate will use this by
+ * default if the <tt>hibernate.proxool.*</tt> properties are set.
+ * @see ConnectionProvider
+ */
+public class ProxoolConnectionProvider implements ConnectionProvider {
+
+
+	private static final String PROXOOL_JDBC_STEM = "proxool.";
+
+	private static final Log log = LogFactory.getLog(ProxoolConnectionProvider.class);
+
+	private String proxoolAlias;
+
+	// TRUE if the pool is borrowed from the outside, FALSE if we used to create it
+	private boolean existingPool;
+
+	// Not null if the Isolation level has been specified in the configuration file.
+	// Otherwise, it is left to the Driver's default value.
+	private Integer isolation;
+	
+	private boolean autocommit;
+
+	/**
+	 * Grab a connection
+	 * @return a JDBC connection
+	 * @throws SQLException
+	 */
+	public Connection getConnection() throws SQLException {
+	    // get a connection from the pool (thru DriverManager, cfr. Proxool doc)
+		Connection c = DriverManager.getConnection(proxoolAlias);
+
+		// set the Transaction Isolation if defined
+		if (isolation!=null) c.setTransactionIsolation( isolation.intValue() );
+
+		// toggle autoCommit to false if set
+		if ( c.getAutoCommit()!=autocommit ) c.setAutoCommit(autocommit);
+
+		// return the connection
+		return c;
+	}
+
+	/**
+	 * Dispose of a used connection.
+	 * @param conn a JDBC connection
+	 * @throws SQLException
+	 */
+	public void closeConnection(Connection conn) throws SQLException {
+		conn.close();
+	}
+
+	/**
+	 * Initialize the connection provider from given properties.
+	 * @param props <tt>SessionFactory</tt> properties
+	 */
+	public void configure(Properties props) throws HibernateException {
+
+		// Get the configurator files (if available)
+		String jaxpFile = props.getProperty(Environment.PROXOOL_XML);
+		String propFile = props.getProperty(Environment.PROXOOL_PROPERTIES);
+		String externalConfig = props.getProperty(Environment.PROXOOL_EXISTING_POOL);
+
+		// Default the Proxool alias setting
+		proxoolAlias = props.getProperty(Environment.PROXOOL_POOL_ALIAS);
+
+		// Configured outside of Hibernate (i.e. Servlet container, or Java Bean Container
+		// already has Proxool pools running, and this provider is to just borrow one of these
+		if ( "true".equals(externalConfig) ) {
+
+			// Validate that an alias name was provided to determine which pool to use
+			if ( !StringHelper.isNotEmpty(proxoolAlias) ) {
+				String msg = "Cannot configure Proxool Provider to use an existing in memory pool without the " + Environment.PROXOOL_POOL_ALIAS + " property set.";
+				log.fatal(msg);
+				throw new HibernateException(msg);
+			}
+			// Append the stem to the proxool pool alias
+			proxoolAlias = PROXOOL_JDBC_STEM + proxoolAlias;
+
+			// Set the existing pool flag to true
+			existingPool = true;
+
+			log.info("Configuring Proxool Provider using existing pool in memory: " + proxoolAlias);
+
+			// Configured using the JAXP Configurator
+		}
+		else if ( StringHelper.isNotEmpty(jaxpFile) ) {
+
+			log.info("Configuring Proxool Provider using JAXPConfigurator: " + jaxpFile);
+
+			// Validate that an alias name was provided to determine which pool to use
+			if ( !StringHelper.isNotEmpty(proxoolAlias) ) {
+				String msg = "Cannot configure Proxool Provider to use JAXP without the " + Environment.PROXOOL_POOL_ALIAS + " property set.";
+				log.fatal(msg);
+				throw new HibernateException(msg);
+			}
+
+			try {
+				JAXPConfigurator.configure( ConfigHelper.getConfigStreamReader(jaxpFile), false );
+			}
+			catch (ProxoolException e) {
+				String msg = "Proxool Provider unable to load JAXP configurator file: " + jaxpFile;
+				log.fatal(msg, e);
+				throw new HibernateException(msg, e);
+			}
+
+			// Append the stem to the proxool pool alias
+			proxoolAlias = PROXOOL_JDBC_STEM + proxoolAlias;
+			log.info("Configuring Proxool Provider to use pool alias: " + proxoolAlias);
+
+			// Configured using the Properties File Configurator
+		}
+		else if ( StringHelper.isNotEmpty(propFile) ) {
+
+			log.info("Configuring Proxool Provider using Properties File: " + propFile);
+
+			// Validate that an alias name was provided to determine which pool to use
+			if ( !StringHelper.isNotEmpty(proxoolAlias) ) {
+				String msg = "Cannot configure Proxool Provider to use Properties File without the " + Environment.PROXOOL_POOL_ALIAS + " property set.";
+				log.fatal(msg);
+				throw new HibernateException(msg);
+			}
+
+			try {
+				PropertyConfigurator.configure( ConfigHelper.getConfigProperties(propFile) );
+			}
+			catch (ProxoolException e) {
+				String msg = "Proxool Provider unable to load load Property configurator file: " + propFile;
+				log.fatal(msg, e);
+				throw new HibernateException(msg, e);
+			}
+
+			// Append the stem to the proxool pool alias
+			proxoolAlias = PROXOOL_JDBC_STEM + proxoolAlias;
+			log.info("Configuring Proxool Provider to use pool alias: " + proxoolAlias);
+		}
+
+		// Remember Isolation level
+		isolation = PropertiesHelper.getInteger(Environment.ISOLATION, props);
+		if (isolation!=null) {
+		    log.info("JDBC isolation level: " + Environment.isolationLevelToString( isolation.intValue() ) );
+		}
+		
+		autocommit = PropertiesHelper.getBoolean(Environment.AUTOCOMMIT, props);
+		log.info("autocommit mode: " + autocommit);
+	}
+
+	/**
+	 * Release all resources held by this provider. JavaDoc requires a second sentence.
+	 * @throws HibernateException
+	 */
+	public void close() throws HibernateException {
+
+		// If the provider was leeching off an existing pool don't close it
+		if (existingPool) {
+			return;
+		}
+
+		// We have created the pool ourselves, so shut it down
+		try {
+	        ProxoolFacade.shutdown(0);
+		}
+		catch (Exception e) {
+			// If you're closing down the ConnectionProvider chances are an
+			// is not a real big deal, just warn
+			log.warn("Exception occured when closing the Proxool pool", e);
+			throw new HibernateException("Exception occured when closing the Proxool pool", e);
+		}
+	}
+
+	/**
+	 * @see ConnectionProvider#supportsAggressiveRelease()
+	 */
+	public boolean supportsAggressiveRelease() {
+		return false;
+	}
+
+}

Added: trunk/Hibernate3/core/pom.xml
===================================================================
--- trunk/Hibernate3/core/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/core/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,149 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.hibernate</groupId>
+    <artifactId>hibernate-core</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Hibernate Core</name>
+    <description>The core functionality of Hibernate</description>
+
+    <url>http://hibernate.org</url>
+
+    <dependencies>
+        <dependency>
+            <groupId>antlr</groupId>
+            <artifactId>antlr</artifactId>
+            <version>2.7.6</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-collections</groupId>
+            <artifactId>commons-collections</artifactId>
+            <version>3.1</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+            <version>1.0.4</version>
+        </dependency>
+        <dependency>
+            <groupId>dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+            <version>1.6.1</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.transaction</groupId>
+            <artifactId>jta</artifactId>
+            <version>1.1</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.security</groupId>
+            <artifactId>jaas</artifactId>
+            <version>1.0.01</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.security</groupId>
+            <artifactId>jacc</artifactId>
+            <version>1.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>ant</groupId>
+            <artifactId>ant</artifactId>
+            <version>1.6.5</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- optional deps for bytecode providers until those are finally properly scoped -->
+        <dependency>
+            <groupId>javassist</groupId>
+            <artifactId>javassist</artifactId>
+            <version>3.4.GA</version>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>cglib</groupId>
+            <artifactId>cglib</artifactId>
+            <version>2.1_3</version>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>asm</groupId>
+            <artifactId>asm-attrs</artifactId>
+            <version>1.5.3</version>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antlr-plugin</artifactId>
+                <configuration>
+                    <grammars>hql.g,hql-sql.g,sql-gen.g</grammars>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antlr-plugin</artifactId>
+                <configuration>
+                    <!-- eventually should be based on the second phase grammar -->
+                    <grammars>hql.g</grammars>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <configuration>
+                    <!-- 
+                    for the time being, gonna ignore the custom stylesheet (what did it do anyway???) 
+                    <stylesheetfile>xyz</stylesheetfile>
+                    -->
+                    <groups>
+			<group>
+                            <title>Core API</title>
+                            <packages>org.hibernate:org.hibernate.classic:org.hibernate.criterion:org.hibernate.metadata:org.hibernate.cfg:org.hibernate.usertype</packages>
+                        </group>
+			<group>
+                            <title>Extension API</title>
+                            <packages>org.hibernate.id:org.hibernate.connection:org.hibernate.transaction:org.hibernate.type:org.hibernate.dialect*:org.hibernate.cache*:org.hibernate.event*:org.hibernate.action:org.hibernate.property:org.hibernate.loader*:org.hibernate.persister*:org.hibernate.proxy:org.hibernate.tuple:org.hibernate.transform:org.hibernate.collection:org.hibernate.jdbc</packages>
+                        </group>
+                        <group>
+                            <title>Miscellaneous API</title>
+                            <packages>org.hibernate.stat:org.hibernate.tool.hbm2ddl:org.hibernate.jmx:org.hibernate.mapping:org.hibernate.tool.instrument</packages>
+                        </group>
+			<group>
+                            <title>Internal Implementation</title>
+			    <packages>org.hibernate.engine:org.hibernate.impl:org.hibernate.sql:org.hibernate.lob:org.hibernate.util:org.hibernate.exception:org.hibernate.hql:org.hibernate.hql.ast:org.hibernate.hql.antlr:org.hibernate.hql.classic:org.hibernate.intercept:org.hibernate.secure:org.hibernate.pretty</[packages>
+                        </group>
+                    </groups>
+                </configuration>
+            </plugin>
+        </plugins>
+    </reporting>
+
+</project>

Added: trunk/Hibernate3/core/src/main/antlr/hql-sql.g
===================================================================
--- trunk/Hibernate3/core/src/main/antlr/hql-sql.g	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/antlr/hql-sql.g	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,699 @@
+header
+{
+// $Id: hql-sql.g 10001 2006-06-08 21:08:04Z steve.ebersole at jboss.com $
+package org.hibernate.hql.antlr;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+}
+
+/**
+ * Hibernate Query Language to SQL Tree Transform.<br>
+ * This is a tree grammar that transforms an HQL AST into a intermediate SQL AST
+ * with bindings to Hibernate interfaces (Queryable, etc.).  The Hibernate specific methods
+ * are all implemented in the HqlSqlWalker subclass, allowing the ANTLR-generated class
+ * to have only the minimum dependencies on the Hibernate code base.   This will also allow
+ * the sub-class to be easily edited using an IDE (most IDE's don't support ANTLR).
+ * <br>
+ * <i>NOTE:</i> The java class is generated from hql-sql.g by ANTLR.
+ * <i>DO NOT EDIT THE GENERATED JAVA SOURCE CODE.</i>
+ * @author Joshua Davis (joshua at hibernate.org)
+ */
+class HqlSqlBaseWalker extends TreeParser;
+
+options
+{
+	// Note: importVocab and exportVocab cause ANTLR to share the token type numbers between the
+	// two grammars.  This means that the token type constants from the source tree are the same
+	// as those in the target tree.  If this is not the case, tree translation can result in
+	// token types from the *source* tree being present in the target tree.
+	importVocab=Hql;        // import definitions from "Hql"
+	exportVocab=HqlSql;     // Call the resulting definitions "HqlSql"
+	buildAST=true;
+}
+
+tokens
+{
+	FROM_FRAGMENT;	// A fragment of SQL that represents a table reference in a FROM clause.
+	IMPLIED_FROM;	// An implied FROM element.
+	JOIN_FRAGMENT;	// A JOIN fragment.
+	SELECT_CLAUSE;
+	LEFT_OUTER;
+	RIGHT_OUTER;
+	ALIAS_REF;      // An IDENT that is a reference to an entity via it's alias.
+	PROPERTY_REF;   // A DOT that is a reference to a property in an entity.
+	SQL_TOKEN;      // A chunk of SQL that is 'rendered' already.
+	SELECT_COLUMNS; // A chunk of SQL representing a bunch of select columns.
+	SELECT_EXPR;    // A select expression, generated from a FROM element.
+	THETA_JOINS;	// Root of theta join condition subtree.
+	FILTERS;		// Root of the filters condition subtree.
+	METHOD_NAME;    // An IDENT that is a method name.
+	NAMED_PARAM;    // A named parameter (:foo).
+	BOGUS;          // Used for error state detection, etc.
+}
+
+// -- Declarations --
+{
+	private static Log log = LogFactory.getLog( HqlSqlBaseWalker.class );
+
+	private int level = 0;
+	private boolean inSelect = false;
+	private boolean inFunctionCall = false;
+	private boolean inCase = false;
+	private boolean inFrom = false;
+	private int statementType;
+	private String statementTypeName;
+	// Note: currentClauseType tracks the current clause within the current
+	// statement, regardless of level; currentTopLevelClauseType, on the other
+	// hand, tracks the current clause within the top (or primary) statement.
+	// Thus, currentTopLevelClauseType ignores the clauses from any subqueries.
+	private int currentClauseType;
+	private int currentTopLevelClauseType;
+	private int currentStatementType;
+
+	public final boolean isSubQuery() {
+		return level > 1;
+	}
+
+	public final boolean isInFrom() {
+		return inFrom;
+	}
+
+	public final boolean isInFunctionCall() {
+		return inFunctionCall;
+	}
+	
+	public final boolean isInSelect() {
+		return inSelect;
+	}
+
+	public final boolean isInCase() {
+		return inCase;
+	}
+
+	public final int getStatementType() {
+		return statementType;
+	}
+
+	public final int getCurrentClauseType() {
+		return currentClauseType;
+	}
+
+	public final int getCurrentTopLevelClauseType() {
+		return currentTopLevelClauseType;
+	}
+
+	public final int getCurrentStatementType() {
+		return currentStatementType;
+	}
+
+	public final boolean isComparativeExpressionClause() {
+		// Note: once we add support for "JOIN ... ON ...",
+		// the ON clause needs to get included here
+	    return getCurrentClauseType() == WHERE ||
+	            getCurrentClauseType() == WITH ||
+	            isInCase();
+	}
+
+	public final boolean isSelectStatement() {
+		return statementType == SELECT;
+	}
+
+	private void beforeStatement(String statementName, int statementType) {
+		inFunctionCall = false;
+		level++;
+		if ( level == 1 ) {
+			this.statementTypeName = statementName;
+			this.statementType = statementType;
+		}
+		currentStatementType = statementType;
+		if ( log.isDebugEnabled() ) {
+			log.debug( statementName + " << begin [level=" + level + ", statement=" + this.statementTypeName + "]" );
+		}
+	}
+
+	private void beforeStatementCompletion(String statementName) {
+		if ( log.isDebugEnabled() ) {
+			log.debug( statementName + " : finishing up [level=" + level + ", statement=" + statementTypeName + "]" );
+		}
+	}
+
+	private void afterStatementCompletion(String statementName) {
+		if ( log.isDebugEnabled() ) {
+			log.debug( statementName + " >> end [level=" + level + ", statement=" + statementTypeName + "]" );
+		}
+		level--;
+	}
+
+	private void handleClauseStart(int clauseType) {
+		currentClauseType = clauseType;
+		if ( level == 1 ) {
+			currentTopLevelClauseType = clauseType;
+		}
+	}
+
+	///////////////////////////////////////////////////////////////////////////
+	// NOTE: The real implementations for the following are in the subclass.
+
+	protected void evaluateAssignment(AST eq) throws SemanticException { }
+	
+	/** Pre-process the from clause input tree. **/
+	protected void prepareFromClauseInputTree(AST fromClauseInput) {}
+
+	/** Sets the current 'FROM' context. **/
+	protected void pushFromClause(AST fromClause,AST inputFromNode) {}
+
+	protected AST createFromElement(String path,AST alias,AST propertyFetch) throws SemanticException {
+		return null;
+	}
+
+	protected void createFromJoinElement(AST path,AST alias,int joinType,AST fetch,AST propertyFetch,AST with) throws SemanticException {}
+
+	protected AST createFromFilterElement(AST filterEntity,AST alias) throws SemanticException	{
+		return null;
+	}
+
+	protected void processQuery(AST select,AST query) throws SemanticException { }
+
+	protected void postProcessUpdate(AST update) throws SemanticException { }
+
+	protected void postProcessDelete(AST delete) throws SemanticException { }
+
+	protected void postProcessInsert(AST insert) throws SemanticException { }
+
+	protected void beforeSelectClause() throws SemanticException { }
+
+	protected void processIndex(AST indexOp) throws SemanticException { }
+
+	protected void processConstant(AST constant) throws SemanticException { }
+
+	protected void processBoolean(AST constant) throws SemanticException { }
+
+	protected void processNumericLiteral(AST literal) throws SemanticException { }
+
+	protected void resolve(AST node) throws SemanticException { }
+
+	protected void resolveSelectExpression(AST dotNode) throws SemanticException { }
+
+	protected void processFunction(AST functionCall,boolean inSelect) throws SemanticException { }
+
+	protected void processConstructor(AST constructor) throws SemanticException { }
+
+	protected AST generateNamedParameter(AST delimiterNode, AST nameNode) throws SemanticException {
+		return #( [NAMED_PARAM, nameNode.getText()] );
+	}
+
+	protected AST generatePositionalParameter(AST inputNode) throws SemanticException {
+		return #( [PARAM, "?"] );
+	}
+
+	protected void lookupAlias(AST ident) throws SemanticException { }
+
+    protected void setAlias(AST selectExpr, AST ident) { }
+
+	protected AST lookupProperty(AST dot,boolean root,boolean inSelect) throws SemanticException {
+		return dot;
+	}
+
+	protected boolean isNonQualifiedPropertyRef(AST ident) { return false; }
+
+	protected AST lookupNonQualifiedProperty(AST property) throws SemanticException { return property; }
+
+	protected void setImpliedJoinType(int joinType) { }
+
+	protected AST createIntoClause(String path, AST propertySpec) throws SemanticException {
+		return null;
+	};
+
+	protected void prepareVersioned(AST updateNode, AST versionedNode) throws SemanticException {}
+
+	protected void prepareLogicOperator(AST operator) throws SemanticException { }
+
+	protected void prepareArithmeticOperator(AST operator) throws SemanticException { }
+}
+
+// The main statement rule.
+statement
+	: selectStatement | updateStatement | deleteStatement | insertStatement
+	;
+
+selectStatement
+	: query
+	;
+
+// Cannot use just the fromElement rule here in the update and delete queries
+// because fromElement essentially relies on a FromClause already having been
+// built :(
+updateStatement!
+	: #( u:UPDATE { beforeStatement( "update", UPDATE ); } (v:VERSIONED)? f:fromClause s:setClause (w:whereClause)? ) {
+		#updateStatement = #(#u, #f, #s, #w);
+		beforeStatementCompletion( "update" );
+		prepareVersioned( #updateStatement, #v );
+		postProcessUpdate( #updateStatement );
+		afterStatementCompletion( "update" );
+	}
+	;
+
+deleteStatement
+	: #( DELETE { beforeStatement( "delete", DELETE ); } fromClause (whereClause)? ) {
+		beforeStatementCompletion( "delete" );
+		postProcessDelete( #deleteStatement );
+		afterStatementCompletion( "delete" );
+	}
+	;
+
+insertStatement
+	// currently only "INSERT ... SELECT ..." statements supported;
+	// do we also need support for "INSERT ... VALUES ..."?
+	//
+	: #( INSERT { beforeStatement( "insert", INSERT ); } intoClause query ) {
+		beforeStatementCompletion( "insert" );
+		postProcessInsert( #insertStatement );
+		afterStatementCompletion( "insert" );
+	}
+	;
+
+intoClause! {
+		String p = null;
+	}
+	: #( INTO { handleClauseStart( INTO ); } (p=path) ps:insertablePropertySpec ) {
+		#intoClause = createIntoClause(p, ps);
+	}
+	;
+
+insertablePropertySpec
+	: #( RANGE (IDENT)+ )
+	;
+
+setClause
+	: #( SET { handleClauseStart( SET ); } (assignment)* )
+	;
+
+assignment
+	// Note: the propertyRef here needs to be resolved
+	// *before* we evaluate the newValue rule...
+	: #( EQ (p:propertyRef) { resolve(#p); } (newValue) ) {
+		evaluateAssignment( #assignment );
+	}
+	;
+
+// For now, just use expr.  Revisit after ejb3 solidifies this.
+newValue
+	: expr | query
+	;
+
+// The query / subquery rule. Pops the current 'from node' context 
+// (list of aliases).
+query!
+	: #( QUERY { beforeStatement( "select", SELECT ); }
+			// The first phase places the FROM first to make processing the SELECT simpler.
+			#(SELECT_FROM
+				f:fromClause
+				(s:selectClause)?
+			)
+			(w:whereClause)?
+			(g:groupClause)?
+			(o:orderClause)?
+		) {
+		// Antlr note: #x_in refers to the input AST, #x refers to the output AST
+		#query = #([SELECT,"SELECT"], #s, #f, #w, #g, #o);
+		beforeStatementCompletion( "select" );
+		processQuery( #s, #query );
+		afterStatementCompletion( "select" );
+	}
+	;
+
+orderClause
+	: #(ORDER { handleClauseStart( ORDER ); } orderExprs)
+	;
+
+orderExprs
+	: expr ( ASCENDING | DESCENDING )? (orderExprs)?
+	;
+
+groupClause
+	: #(GROUP { handleClauseStart( GROUP ); } (expr)+ ( #(HAVING logicalExpr) )? )
+	;
+
+selectClause!
+	: #(SELECT { handleClauseStart( SELECT ); beforeSelectClause(); } (d:DISTINCT)? x:selectExprList ) {
+		#selectClause = #([SELECT_CLAUSE,"{select clause}"], #d, #x);
+	}
+	;
+
+selectExprList {
+		boolean oldInSelect = inSelect;
+		inSelect = true;
+	}
+	: ( selectExpr | aliasedSelectExpr )+ {
+		inSelect = oldInSelect;
+	}
+	;
+
+aliasedSelectExpr!
+	: #(AS se:selectExpr i:identifier) {
+	    setAlias(#se,#i);
+		#aliasedSelectExpr = #se;
+	}
+	;
+
+selectExpr
+	: p:propertyRef					{ resolveSelectExpression(#p); }
+	| #(ALL ar2:aliasRef) 			{ resolveSelectExpression(#ar2); #selectExpr = #ar2; }
+	| #(OBJECT ar3:aliasRef)		{ resolveSelectExpression(#ar3); #selectExpr = #ar3; }
+	| con:constructor 				{ processConstructor(#con); }
+	| functionCall
+	| count
+	| collectionFunction			// elements() or indices()
+	| literal
+	| arithmeticExpr
+	| query
+	;
+
+count
+	: #(COUNT ( DISTINCT | ALL )? ( aggregateExpr | ROW_STAR ) )
+	;
+
+constructor
+	{ String className = null; }
+	: #(CONSTRUCTOR className=path ( selectExpr | aliasedSelectExpr )* )
+	;
+
+aggregateExpr
+	: expr //p:propertyRef { resolve(#p); }
+	| collectionFunction
+	;
+
+// Establishes the list of aliases being used by this query.
+fromClause {
+		// NOTE: This references the INPUT AST! (see http://www.antlr.org/doc/trees.html#Action%20Translation)
+		// the ouput AST (#fromClause) has not been built yet.
+		prepareFromClauseInputTree(#fromClause_in);
+	}
+	: #(f:FROM { pushFromClause(#fromClause,f); handleClauseStart( FROM ); } fromElementList )
+	;
+
+fromElementList {
+		boolean oldInFrom = inFrom;
+		inFrom = true;
+		}
+	: (fromElement)+ {
+		inFrom = oldInFrom;
+		}
+	;
+
+fromElement! {
+	String p = null;
+	}
+	// A simple class name, alias element.
+	: #(RANGE p=path (a:ALIAS)? (pf:FETCH)? ) {
+		#fromElement = createFromElement(p,a, pf);
+	}
+	| je:joinElement {
+		#fromElement = #je;
+	}
+	// A from element created due to filter compilation
+	| fe:FILTER_ENTITY a3:ALIAS {
+		#fromElement = createFromFilterElement(fe,a3);
+	}
+	;
+
+joinElement! {
+		int j = INNER;
+	}
+	// A from element with a join.  This time, the 'path' should be treated as an AST
+	// and resolved (like any path in a WHERE clause).   Make sure all implied joins
+	// generated by the property ref use the join type, if it was specified.
+	: #(JOIN (j=joinType { setImpliedJoinType(j); } )? (f:FETCH)? ref:propertyRef (a:ALIAS)? (pf:FETCH)? (with:WITH)? ) {
+		//createFromJoinElement(#ref,a,j,f, pf);
+		createFromJoinElement(#ref,a,j,f, pf, with);
+		setImpliedJoinType(INNER);	// Reset the implied join type.
+	}
+	;
+
+// Returns an node type integer that represents the join type
+// tokens.
+joinType returns [int j] {
+	j = INNER;
+	}
+	: ( (left:LEFT | right:RIGHT) (outer:OUTER)? ) {
+		if (left != null)       j = LEFT_OUTER;
+		else if (right != null) j = RIGHT_OUTER;
+		else if (outer != null) j = RIGHT_OUTER;
+	}
+	| FULL {
+		j = FULL;
+	}
+	| INNER {
+		j = INNER;
+	}
+	;
+
+// Matches a path and returns the normalized string for the path (usually
+// fully qualified a class name).
+path returns [String p] {
+	p = "???";
+	String x = "?x?";
+	}
+	: a:identifier { p = a.getText(); }
+	| #(DOT x=path y:identifier) {
+			StringBuffer buf = new StringBuffer();
+			buf.append(x).append(".").append(y.getText());
+			p = buf.toString();
+		}
+	;
+
+// Returns a path as a single identifier node.
+pathAsIdent {
+    String text = "?text?";
+    }
+    : text=path {
+        #pathAsIdent = #([IDENT,text]);
+    }
+    ;
+
+withClause
+	// Note : this is used internally from the HqlSqlWalker to
+	// parse the node recognized with the with keyword earlier.
+	// Done this way because it relies on the join it "qualifies"
+	// already having been processed, which would not be the case
+	// if withClause was simply referenced from the joinElement
+	// rule during recognition...
+	: #(w:WITH { handleClauseStart( WITH ); } b:logicalExpr ) {
+		#withClause = #(w , #b);
+	}
+	;
+
+whereClause
+	: #(w:WHERE { handleClauseStart( WHERE ); } b:logicalExpr ) {
+		// Use the *output* AST for the boolean expression!
+		#whereClause = #(w , #b);
+	}
+	;
+
+logicalExpr
+	: #(AND logicalExpr logicalExpr)
+	| #(OR logicalExpr logicalExpr)
+	| #(NOT logicalExpr)
+	| comparisonExpr
+	;
+
+// TODO: Add any other comparison operators here.
+comparisonExpr
+	:
+	( #(EQ exprOrSubquery exprOrSubquery)
+	| #(NE exprOrSubquery exprOrSubquery)
+	| #(LT exprOrSubquery exprOrSubquery)
+	| #(GT exprOrSubquery exprOrSubquery)
+	| #(LE exprOrSubquery exprOrSubquery)
+	| #(GE exprOrSubquery exprOrSubquery)
+	| #(LIKE exprOrSubquery expr ( #(ESCAPE expr) )? )
+	| #(NOT_LIKE exprOrSubquery expr ( #(ESCAPE expr) )? )
+	| #(BETWEEN exprOrSubquery exprOrSubquery exprOrSubquery)
+	| #(NOT_BETWEEN exprOrSubquery exprOrSubquery exprOrSubquery)
+	| #(IN exprOrSubquery inRhs )
+	| #(NOT_IN exprOrSubquery inRhs )
+	| #(IS_NULL exprOrSubquery)
+	| #(IS_NOT_NULL exprOrSubquery)
+//	| #(IS_TRUE expr)
+//	| #(IS_FALSE expr)
+	| #(EXISTS ( expr | collectionFunctionOrSubselect ) )
+	) {
+	    prepareLogicOperator( #comparisonExpr );
+	}
+	;
+
+inRhs
+	: #(IN_LIST ( collectionFunctionOrSubselect | ( (expr)* ) ) )
+	;
+
+exprOrSubquery
+	: expr
+	| query
+	| #(ANY collectionFunctionOrSubselect)
+	| #(ALL collectionFunctionOrSubselect)
+	| #(SOME collectionFunctionOrSubselect)
+	;
+	
+collectionFunctionOrSubselect
+	: collectionFunction
+	| query
+	;
+	
+expr
+	: ae:addrExpr [ true ] { resolve(#ae); }	// Resolve the top level 'address expression'
+	| #( VECTOR_EXPR (expr)* )
+	| constant
+	| arithmeticExpr
+	| functionCall							// Function call, not in the SELECT clause.
+	| parameter
+	| count										// Count, not in the SELECT clause.
+	;
+
+arithmeticExpr
+	: #(PLUS expr expr)         { prepareArithmeticOperator( #arithmeticExpr ); }
+	| #(MINUS expr expr)        { prepareArithmeticOperator( #arithmeticExpr ); }
+	| #(DIV expr expr)          { prepareArithmeticOperator( #arithmeticExpr ); }
+	| #(STAR expr expr)         { prepareArithmeticOperator( #arithmeticExpr ); }
+//	| #(CONCAT expr (expr)+ )   { prepareArithmeticOperator( #arithmeticExpr ); }
+	| #(UNARY_MINUS expr)       { prepareArithmeticOperator( #arithmeticExpr ); }
+	| caseExpr
+	;
+
+caseExpr
+	: #(CASE { inCase = true; } (#(WHEN logicalExpr expr))+ (#(ELSE expr))?) { inCase = false; }
+	| #(CASE2 { inCase = true; } expr (#(WHEN expr expr))+ (#(ELSE expr))?) { inCase = false; }
+	;
+
+//TODO: I don't think we need this anymore .. how is it different to 
+//      maxelements, etc, which are handled by functionCall
+collectionFunction
+	: #(e:ELEMENTS {inFunctionCall=true;} p1:propertyRef { resolve(#p1); } ) 
+		{ processFunction(#e,inSelect); } {inFunctionCall=false;}
+	| #(i:INDICES {inFunctionCall=true;} p2:propertyRef { resolve(#p2); } ) 
+		{ processFunction(#i,inSelect); } {inFunctionCall=false;}
+	;
+
+functionCall
+	: #(METHOD_CALL  {inFunctionCall=true;} pathAsIdent ( #(EXPR_LIST (expr)* ) )? )
+		{ processFunction(#functionCall,inSelect); } {inFunctionCall=false;}
+	| #(AGGREGATE aggregateExpr )
+	;
+
+constant
+	: literal
+	| NULL
+	| TRUE { processBoolean(#constant); } 
+	| FALSE { processBoolean(#constant); }
+	| JAVA_CONSTANT
+	;
+
+literal
+	: NUM_INT { processNumericLiteral( #literal ); }
+	| NUM_LONG { processNumericLiteral( #literal ); }
+	| NUM_FLOAT { processNumericLiteral( #literal ); }
+	| NUM_DOUBLE { processNumericLiteral( #literal ); }
+	| QUOTED_STRING
+	;
+
+identifier
+	: (IDENT | WEIRD_IDENT)
+	;
+
+addrExpr! [ boolean root ]
+	: #(d:DOT lhs:addrExprLhs rhs:propertyName )	{
+		// This gives lookupProperty() a chance to transform the tree 
+		// to process collection properties (.elements, etc).
+		#addrExpr = #(#d, #lhs, #rhs);
+		#addrExpr = lookupProperty(#addrExpr,root,false);
+	}
+	| #(i:INDEX_OP lhs2:addrExprLhs rhs2:expr)	{
+		#addrExpr = #(#i, #lhs2, #rhs2);
+		processIndex(#addrExpr);
+	}
+	| p:identifier {
+//		#addrExpr = #p;
+//		resolve(#addrExpr);
+		// In many cases, things other than property-refs are recognized
+		// by this addrExpr rule.  Some of those I have seen:
+		//  1) select-clause from-aliases
+		//  2) sql-functions
+		if ( isNonQualifiedPropertyRef(#p) ) {
+			#addrExpr = lookupNonQualifiedProperty(#p);
+		}
+		else {
+			resolve(#p);
+			#addrExpr = #p;
+		}
+	}
+	;
+
+addrExprLhs
+	: addrExpr [ false ]
+	;
+
+propertyName
+	: identifier
+	| CLASS
+	| ELEMENTS
+	| INDICES
+	;
+
+propertyRef!
+	: #(d:DOT lhs:propertyRefLhs rhs:propertyName )	{
+		// This gives lookupProperty() a chance to transform the tree to process collection properties (.elements, etc).
+		#propertyRef = #(#d, #lhs, #rhs);
+		#propertyRef = lookupProperty(#propertyRef,false,true);
+	}
+	|
+	p:identifier {
+		// In many cases, things other than property-refs are recognized
+		// by this propertyRef rule.  Some of those I have seen:
+		//  1) select-clause from-aliases
+		//  2) sql-functions
+		if ( isNonQualifiedPropertyRef(#p) ) {
+			#propertyRef = lookupNonQualifiedProperty(#p);
+		}
+		else {
+			resolve(#p);
+			#propertyRef = #p;
+		}
+	}
+	;
+
+propertyRefLhs
+	: propertyRef
+	;
+
+aliasRef!
+	: i:identifier {
+		#aliasRef = #([ALIAS_REF,i.getText()]);	// Create an ALIAS_REF node instead of an IDENT node.
+		lookupAlias(#aliasRef);
+		}
+	;
+
+parameter!
+	: #(c:COLON a:identifier) {
+			// Create a NAMED_PARAM node instead of (COLON IDENT).
+			#parameter = generateNamedParameter( c, a );
+//			#parameter = #([NAMED_PARAM,a.getText()]);
+//			namedParameter(#parameter);
+		}
+	| #(p:PARAM (n:NUM_INT)?) {
+			if ( n != null ) {
+				// An ejb3-style "positional parameter", which we handle internally as a named-param
+				#parameter = generateNamedParameter( p, n );
+//				#parameter = #([NAMED_PARAM,n.getText()]);
+//				namedParameter(#parameter);
+			}
+			else {
+				#parameter = generatePositionalParameter( p );
+//				#parameter = #([PARAM,"?"]);
+//				positionalParameter(#parameter);
+			}
+		}
+	;
+
+numericInteger
+	: NUM_INT
+	;
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/antlr/hql.g
===================================================================
--- trunk/Hibernate3/core/src/main/antlr/hql.g	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/antlr/hql.g	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,883 @@
+header
+{
+//   $Id: hql.g 10163 2006-07-26 15:07:50Z steve.ebersole at jboss.com $
+
+package org.hibernate.hql.antlr;
+
+import org.hibernate.hql.ast.*;
+import org.hibernate.hql.ast.util.*;
+
+}
+/**
+ * Hibernate Query Language Grammar
+ * <br>
+ * This grammar parses the query language for Hibernate (an Open Source, Object-Relational
+ * mapping library).  A partial BNF grammar description is available for reference here:
+ * http://www.hibernate.org/Documentation/HQLBNF
+ *
+ * Text from the original reference BNF is prefixed with '//##'.
+ * @author Joshua Davis (pgmjsd at sourceforge.net)
+ */
+class HqlBaseParser extends Parser;
+
+options
+{
+	exportVocab=Hql;
+	buildAST=true;
+	k=3;    // For 'not like', 'not in', etc.
+}
+
+tokens
+{
+	// -- HQL Keyword tokens --
+	ALL="all";
+	ANY="any";
+	AND="and";
+	AS="as";
+	ASCENDING="asc";
+	AVG="avg";
+	BETWEEN="between";
+	CLASS="class";
+	COUNT="count";
+	DELETE="delete";
+	DESCENDING="desc";
+	DOT;
+	DISTINCT="distinct";
+	ELEMENTS="elements";
+	ESCAPE="escape";
+	EXISTS="exists";
+	FALSE="false";
+	FETCH="fetch";
+	FROM="from";
+	FULL="full";
+	GROUP="group";
+	HAVING="having";
+	IN="in";
+	INDICES="indices";
+	INNER="inner";
+	INSERT="insert";
+	INTO="into";
+	IS="is";
+	JOIN="join";
+	LEFT="left";
+	LIKE="like";
+	MAX="max";
+	MIN="min";
+	NEW="new";
+	NOT="not";
+	NULL="null";
+	OR="or";
+	ORDER="order";
+	OUTER="outer";
+	PROPERTIES="properties";
+	RIGHT="right";
+	SELECT="select";
+	SET="set";
+	SOME="some";
+	SUM="sum";
+	TRUE="true";
+	UNION="union";
+	UPDATE="update";
+	VERSIONED="versioned";
+	WHERE="where";
+
+	// -- SQL tokens --
+	// These aren't part of HQL, but the SQL fragment parser uses the HQL lexer, so they need to be declared here.
+	CASE="case";
+	END="end";
+	ELSE="else";
+	THEN="then";
+	WHEN="when";
+	ON="on";
+	WITH="with";
+
+	// -- EJBQL tokens --
+	BOTH="both";
+	EMPTY="empty";
+	LEADING="leading";
+	MEMBER="member";
+	OBJECT="object";
+	OF="of";
+	TRAILING="trailing";
+
+	// -- Synthetic token types --
+	AGGREGATE;		// One of the aggregate functions (e.g. min, max, avg)
+	ALIAS;
+	CONSTRUCTOR;
+	CASE2;
+	EXPR_LIST;
+	FILTER_ENTITY;		// FROM element injected because of a filter expression (happens during compilation phase 2)
+	IN_LIST;
+	INDEX_OP;
+	IS_NOT_NULL;
+	IS_NULL;			// Unary 'is null' operator.
+	METHOD_CALL;
+	NOT_BETWEEN;
+	NOT_IN;
+	NOT_LIKE;
+	ORDER_ELEMENT;
+	QUERY;
+	RANGE;
+	ROW_STAR;
+	SELECT_FROM;
+	UNARY_MINUS;
+	UNARY_PLUS;
+	VECTOR_EXPR;		// ( x, y, z )
+	WEIRD_IDENT;		// Identifiers that were keywords when they came in.
+
+	// Literal tokens.
+	CONSTANT;
+	NUM_DOUBLE;
+	NUM_FLOAT;
+	NUM_LONG;
+	JAVA_CONSTANT;
+}
+
+{
+    /** True if this is a filter query (allow no FROM clause). **/
+	private boolean filter = false;
+
+	/**
+	 * Sets the filter flag.
+	 * @param f True for a filter query, false for a normal query.
+	 */
+	public void setFilter(boolean f) {
+		filter = f;
+	}
+
+	/**
+	 * Returns true if this is a filter query, false if not.
+	 * @return true if this is a filter query, false if not.
+	 */
+	public boolean isFilter() {
+		return filter;
+	}
+
+	/**
+	 * This method is overriden in the sub class in order to provide the
+	 * 'keyword as identifier' hack.
+	 * @param token The token to retry as an identifier.
+	 * @param ex The exception to throw if it cannot be retried as an identifier.
+	 */
+	public AST handleIdentifierError(Token token,RecognitionException ex) throws RecognitionException, TokenStreamException {
+		// Base implementation: Just re-throw the exception.
+		throw ex;
+	}
+
+    /**
+     * This method looks ahead and converts . <token> into . IDENT when
+     * appropriate.
+     */
+    public void handleDotIdent() throws TokenStreamException {
+    }
+
+	/**
+	 * Returns the negated equivalent of the expression.
+	 * @param x The expression to negate.
+	 */
+	public AST negateNode(AST x) {
+		// Just create a 'not' parent for the default behavior.
+		return ASTUtil.createParent(astFactory, NOT, "not", x);
+	}
+
+	/**
+	 * Returns the 'cleaned up' version of a comparison operator sub-tree.
+	 * @param x The comparison operator to clean up.
+	 */
+	public AST processEqualityExpression(AST x) throws RecognitionException {
+		return x;
+	}
+
+	public void weakKeywords() throws TokenStreamException { }
+
+	public void processMemberOf(Token n,AST p,ASTPair currentAST) { }
+
+}
+
+statement
+	: ( updateStatement | deleteStatement | selectStatement | insertStatement )
+	;
+
+updateStatement
+	: UPDATE^ (VERSIONED)?
+		optionalFromTokenFromClause
+		setClause
+		(whereClause)?
+	;
+
+setClause
+	: (SET^ assignment (COMMA! assignment)*)
+	;
+
+assignment
+	: stateField EQ^ newValue
+	;
+
+// "state_field" is the term used in the EJB3 sample grammar; used here for easy reference.
+// it is basically a property ref
+stateField
+	: path
+	;
+
+// this still needs to be defined in the ejb3 spec; additiveExpression is currently just a best guess,
+// although it is highly likely I would think that the spec may limit this even more tightly.
+newValue
+	: concatenation
+	;
+
+deleteStatement
+	: DELETE^
+		(optionalFromTokenFromClause)
+		(whereClause)?
+	;
+
+optionalFromTokenFromClause!
+	: (FROM!)? f:path (a:asAlias)? {
+		AST #range = #([RANGE, "RANGE"], #f, #a);
+		#optionalFromTokenFromClause = #([FROM, "FROM"], #range);
+	}
+	;
+
+selectStatement
+	: queryRule {
+		#selectStatement = #([QUERY,"query"], #selectStatement);
+	}
+	;
+
+insertStatement
+	// Would be nice if we could abstract the FromClause/FromElement logic
+	// out such that it could be reused here; something analogous to
+	// a "table" rule in sql-grammars
+	: INSERT^ intoClause selectStatement
+	;
+
+intoClause
+	: INTO^ path { weakKeywords(); } insertablePropertySpec
+	;
+
+insertablePropertySpec
+	: OPEN! primaryExpression ( COMMA! primaryExpression )* CLOSE! {
+		// Just need *something* to distinguish this on the hql-sql.g side
+		#insertablePropertySpec = #([RANGE, "column-spec"], #insertablePropertySpec);
+	}
+	;
+
+union
+	: queryRule (UNION queryRule)*
+	;
+
+//## query:
+//##     [selectClause] fromClause [whereClause] [groupByClause] [havingClause] [orderByClause];
+
+queryRule
+	: selectFrom
+		(whereClause)?
+		(groupByClause)?
+		(orderByClause)?
+		;
+
+selectFrom!
+	:  (s:selectClause)? (f:fromClause)? {
+		// If there was no FROM clause and this is a filter query, create a from clause.  Otherwise, throw
+		// an exception because non-filter queries must have a FROM clause.
+		if (#f == null) {
+			if (filter) {
+				#f = #([FROM,"{filter-implied FROM}"]);
+			}
+			else
+				throw new SemanticException("FROM expected (non-filter queries must contain a FROM clause)");
+		}
+			
+		// Create an artificial token so the 'FROM' can be placed
+		// before the SELECT in the tree to make tree processing
+		// simpler.
+		#selectFrom = #([SELECT_FROM,"SELECT_FROM"],f,s);
+	}
+	;
+
+//## selectClause:
+//##     SELECT DISTINCT? selectedPropertiesList | ( NEW className OPEN selectedPropertiesList CLOSE );
+
+selectClause
+	: SELECT^	// NOTE: The '^' after a token causes the corresponding AST node to be the root of the sub-tree.
+		{ weakKeywords(); }	// Weak keywords can appear immediately after a SELECT token.
+		(DISTINCT)? ( selectedPropertiesList | newExpression | selectObject )
+	;
+
+newExpression
+	: (NEW! path) op:OPEN^ {#op.setType(CONSTRUCTOR);} selectedPropertiesList CLOSE!
+	;
+
+selectObject
+   : OBJECT^ OPEN! identifier CLOSE!
+   ;
+
+//## fromClause:
+//##    FROM className AS? identifier (  ( COMMA className AS? identifier ) | ( joinType path AS? identifier ) )*;
+
+// NOTE: This *must* begin with the "FROM" token, otherwise the sub-query rule will be ambiguous
+// with the expression rule.
+// Also note: after a comma weak keywords are allowed and should be treated as identifiers.
+
+fromClause
+	: FROM^ { weakKeywords(); } fromRange ( fromJoin | COMMA! { weakKeywords(); } fromRange )*
+	;
+
+//## joinType:
+//##     ( ( 'left'|'right' 'outer'? ) | 'full' | 'inner' )? JOIN FETCH?;
+
+fromJoin
+	: ( ( ( LEFT | RIGHT ) (OUTER)? ) | FULL | INNER )? JOIN^ (FETCH)? 
+	  path (asAlias)? (propertyFetch)? (withClause)?
+	;
+
+withClause
+	: WITH^ logicalExpression
+	;
+
+fromRange
+	: fromClassOrOuterQueryPath
+	| inClassDeclaration
+	| inCollectionDeclaration
+	| inCollectionElementsDeclaration
+	;
+	
+fromClassOrOuterQueryPath!
+	: c:path { weakKeywords(); } (a:asAlias)? (p:propertyFetch)? {
+		#fromClassOrOuterQueryPath = #([RANGE, "RANGE"], #c, #a, #p);
+	}
+	;
+
+inClassDeclaration!
+	: a:alias IN! CLASS! c:path {
+		#inClassDeclaration = #([RANGE, "RANGE"], #c, #a);
+	}
+	;
+
+inCollectionDeclaration!
+    : IN! OPEN! p:path CLOSE! a:alias {
+        #inCollectionDeclaration = #([JOIN, "join"], [INNER, "inner"], #p, #a);
+	}
+    ;
+
+inCollectionElementsDeclaration!
+	: a:alias IN! ELEMENTS! OPEN! p:path CLOSE! {
+        #inCollectionElementsDeclaration = #([JOIN, "join"], [INNER, "inner"], #p, #a);
+	}
+    ;
+
+// Alias rule - Parses the optional 'as' token and forces an AST identifier node.
+asAlias
+	: (AS!)? alias
+	;
+
+alias
+	: a:identifier { #a.setType(ALIAS); }
+    ;
+    
+propertyFetch
+	: FETCH ALL! PROPERTIES!
+	;
+
+//## groupByClause:
+//##     GROUP_BY path ( COMMA path )*;
+
+groupByClause
+	: GROUP^ 
+		"by"! expression ( COMMA! expression )*
+		(havingClause)?
+	;
+
+//## orderByClause:
+//##     ORDER_BY selectedPropertiesList;
+
+orderByClause
+	: ORDER^ "by"! orderElement ( COMMA! orderElement )*
+	;
+
+orderElement
+	: expression ( ascendingOrDescending )?
+	;
+
+ascendingOrDescending
+	: ( "asc" | "ascending" )	{ #ascendingOrDescending.setType(ASCENDING); }
+	| ( "desc" | "descending") 	{ #ascendingOrDescending.setType(DESCENDING); }
+	;
+
+//## havingClause:
+//##     HAVING logicalExpression;
+
+havingClause
+	: HAVING^ logicalExpression
+	;
+
+//## whereClause:
+//##     WHERE logicalExpression;
+
+whereClause
+	: WHERE^ logicalExpression
+	;
+
+//## selectedPropertiesList:
+//##     ( path | aggregate ) ( COMMA path | aggregate )*;
+
+selectedPropertiesList
+	: aliasedExpression ( COMMA! aliasedExpression )*
+	;
+	
+aliasedExpression
+	: expression ( AS^ identifier )?
+	;
+
+// expressions
+// Note that most of these expressions follow the pattern
+//   thisLevelExpression :
+//       nextHigherPrecedenceExpression
+//           (OPERATOR nextHigherPrecedenceExpression)*
+// which is a standard recursive definition for a parsing an expression.
+//
+// Operator precedence in HQL
+// lowest  --> ( 7)  OR
+//             ( 6)  AND, NOT
+//             ( 5)  equality: ==, <>, !=, is
+//             ( 4)  relational: <, <=, >, >=,
+//                   LIKE, NOT LIKE, BETWEEN, NOT BETWEEN, IN, NOT IN
+//             ( 3)  addition and subtraction: +(binary) -(binary)
+//             ( 2)  multiplication: * / %, concatenate: ||
+// highest --> ( 1)  +(unary) -(unary)
+//                   []   () (method call)  . (dot -- identifier qualification)
+//                   aggregate function
+//                   ()  (explicit parenthesis)
+//
+// Note that the above precedence levels map to the rules below...
+// Once you have a precedence chart, writing the appropriate rules as below
+// is usually very straightfoward
+
+logicalExpression
+	: expression
+	;
+
+// Main expression rule
+expression
+	: logicalOrExpression
+	;
+
+// level 7 - OR
+logicalOrExpression
+	: logicalAndExpression ( OR^ logicalAndExpression )*
+	;
+
+// level 6 - AND, NOT
+logicalAndExpression
+	: negatedExpression ( AND^ negatedExpression )*
+	;
+
+// NOT nodes aren't generated.  Instead, the operator in the sub-tree will be
+// negated, if possible.   Expressions without a NOT parent are passed through.
+negatedExpression!
+{ weakKeywords(); } // Weak keywords can appear in an expression, so look ahead.
+	: NOT^ x:negatedExpression { #negatedExpression = negateNode(#x); }
+	| y:equalityExpression { #negatedExpression = #y; }
+	;
+
+//## OP: EQ | LT | GT | LE | GE | NE | SQL_NE | LIKE;
+
+// level 5 - EQ, NE
+equalityExpression
+	: x:relationalExpression (
+		( EQ^
+		| is:IS^	{ #is.setType(EQ); } (NOT! { #is.setType(NE); } )?
+		| NE^
+		| ne:SQL_NE^	{ #ne.setType(NE); }
+		) y:relationalExpression)* {
+			// Post process the equality expression to clean up 'is null', etc.
+			#equalityExpression = processEqualityExpression(#equalityExpression);
+		}
+	;
+
+// level 4 - LT, GT, LE, GE, LIKE, NOT LIKE, BETWEEN, NOT BETWEEN
+// NOTE: The NOT prefix for LIKE and BETWEEN will be represented in the
+// token type.  When traversing the AST, use the token type, and not the
+// token text to interpret the semantics of these nodes.
+relationalExpression
+	: concatenation (
+		( ( ( LT^ | GT^ | LE^ | GE^ ) additiveExpression )* )
+		// Disable node production for the optional 'not'.
+		| (n:NOT!)? (
+			// Represent the optional NOT prefix using the token type by
+			// testing 'n' and setting the token type accordingly.
+			(i:IN^ {
+					#i.setType( (n == null) ? IN : NOT_IN);
+					#i.setText( (n == null) ? "in" : "not in");
+				}
+				inList)
+			| (b:BETWEEN^ {
+					#b.setType( (n == null) ? BETWEEN : NOT_BETWEEN);
+					#b.setText( (n == null) ? "between" : "not between");
+				}
+				betweenList )
+			| (l:LIKE^ {
+					#l.setType( (n == null) ? LIKE : NOT_LIKE);
+					#l.setText( (n == null) ? "like" : "not like");
+				}
+				concatenation likeEscape)
+			| (MEMBER! (OF!)? p:path! {
+				processMemberOf(n,#p,currentAST);
+			  } ) )
+		)
+	;
+
+likeEscape
+	: (ESCAPE^ concatenation)?
+	;
+
+inList
+	: x:compoundExpr
+	{ #inList = #([IN_LIST,"inList"], #inList); }
+	;
+
+betweenList
+	: concatenation AND! concatenation
+	;
+
+//level 4 - string concatenation
+concatenation
+	: additiveExpression 
+	( c:CONCAT^ { #c.setType(EXPR_LIST); #c.setText("concatList"); } 
+	  additiveExpression
+	  ( CONCAT! additiveExpression )* 
+	  { #concatenation = #([METHOD_CALL, "||"], #([IDENT, "concat"]), #c ); } )?
+	;
+
+// level 3 - binary plus and minus
+additiveExpression
+	: multiplyExpression ( ( PLUS^ | MINUS^ ) multiplyExpression )*
+	;
+
+// level 2 - binary multiply and divide
+multiplyExpression
+	: unaryExpression ( ( STAR^ | DIV^ ) unaryExpression )*
+	;
+	
+// level 1 - unary minus, unary plus, not
+unaryExpression
+	: MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression
+	| PLUS^ {#PLUS.setType(UNARY_PLUS);} unaryExpression
+	| caseExpression
+	| quantifiedExpression
+	| atom
+	;
+	
+caseExpression
+	: CASE^ (whenClause)+ (elseClause)? END! 
+	| CASE^ { #CASE.setType(CASE2); } unaryExpression (altWhenClause)+ (elseClause)? END!
+	;
+	
+whenClause
+	: (WHEN^ logicalExpression THEN! unaryExpression)
+	;
+	
+altWhenClause
+	: (WHEN^ unaryExpression THEN! unaryExpression)
+	;
+	
+elseClause
+	: (ELSE^ unaryExpression)
+	;
+	
+quantifiedExpression
+	: ( SOME^ | EXISTS^ | ALL^ | ANY^ ) 
+	( identifier | collectionExpr | (OPEN! ( subQuery ) CLOSE!) )
+	;
+
+// level 0 - expression atom
+// ident qualifier ('.' ident ), array index ( [ expr ] ),
+// method call ( '.' ident '(' exprList ') )
+atom
+	 : primaryExpression
+		(
+			DOT^ identifier
+				( options { greedy=true; } :
+					( op:OPEN^ {#op.setType(METHOD_CALL);} exprList CLOSE! ) )?
+		|	lb:OPEN_BRACKET^ {#lb.setType(INDEX_OP);} expression CLOSE_BRACKET!
+		)*
+	;
+
+// level 0 - the basic element of an expression
+primaryExpression
+	:   identPrimary ( options {greedy=true;} : DOT^ "class" )?
+	|   constant
+	|   COLON^ identifier
+	// TODO: Add parens to the tree so the user can control the operator evaluation order.
+	|   OPEN! (expressionOrVector | subQuery) CLOSE!
+	|   PARAM^ (NUM_INT)?
+	;
+
+// This parses normal expression and a list of expressions separated by commas.  If a comma is encountered
+// a parent VECTOR_EXPR node will be created for the list.
+expressionOrVector!
+	: e:expression ( v:vectorExpr )? {
+		// If this is a vector expression, create a parent node for it.
+		if (#v != null)
+			#expressionOrVector = #([VECTOR_EXPR,"{vector}"], #e, #v);
+		else
+			#expressionOrVector = #e;
+	}
+	;
+
+vectorExpr
+	: COMMA! expression (COMMA! expression)*
+	;
+
+// identifier, followed by member refs (dot ident), or method calls.
+// NOTE: handleDotIdent() is called immediately after the first IDENT is recognized because
+// the method looks a head to find keywords after DOT and turns them into identifiers.
+identPrimary
+	: identifier { handleDotIdent(); }
+			( options { greedy=true; } : DOT^ ( identifier | ELEMENTS | o:OBJECT { #o.setType(IDENT); } ) )*
+			( options { greedy=true; } :
+				( op:OPEN^ { #op.setType(METHOD_CALL);} exprList CLOSE! )
+			)?
+	// Also allow special 'aggregate functions' such as count(), avg(), etc.
+	| aggregate
+	;
+
+//## aggregate:
+//##     ( aggregateFunction OPEN path CLOSE ) | ( COUNT OPEN STAR CLOSE ) | ( COUNT OPEN (DISTINCT | ALL) path CLOSE );
+
+//## aggregateFunction:
+//##     COUNT | 'sum' | 'avg' | 'max' | 'min';
+
+aggregate
+	: ( SUM^ | AVG^ | MAX^ | MIN^ ) OPEN! additiveExpression CLOSE! { #aggregate.setType(AGGREGATE); }
+	// Special case for count - It's 'parameters' can be keywords.
+	|  COUNT^ OPEN! ( STAR { #STAR.setType(ROW_STAR); } | ( ( DISTINCT | ALL )? ( path | collectionExpr ) ) ) CLOSE!
+	|  collectionExpr
+	;
+
+//## collection: ( OPEN query CLOSE ) | ( 'elements'|'indices' OPEN path CLOSE );
+
+collectionExpr
+	: (ELEMENTS^ | INDICES^) OPEN! path CLOSE!
+	;
+                                           
+// NOTE: compoundExpr can be a 'path' where the last token in the path is '.elements' or '.indicies'
+compoundExpr
+	: collectionExpr
+	| path
+	| (OPEN! ( (expression (COMMA! expression)*) | subQuery ) CLOSE!)
+	;
+
+subQuery
+	: union
+	{ #subQuery = #([QUERY,"query"], #subQuery); }
+	;
+
+exprList
+{
+   AST trimSpec = null;
+}
+	: (t:TRAILING {#trimSpec = #t;} | l:LEADING {#trimSpec = #l;} | b:BOTH {#trimSpec = #b;})?
+	  		{ if(#trimSpec != null) #trimSpec.setType(IDENT); }
+	  ( 
+	  		expression ( (COMMA! expression)+ | FROM { #FROM.setType(IDENT); } expression | AS! identifier )? 
+	  		| FROM { #FROM.setType(IDENT); } expression
+	  )?
+			{ #exprList = #([EXPR_LIST,"exprList"], #exprList); }
+	;
+
+constant
+	: NUM_INT
+	| NUM_FLOAT
+	| NUM_LONG
+	| NUM_DOUBLE
+	| QUOTED_STRING
+	| NULL
+	| TRUE
+	| FALSE
+	| EMPTY
+	;
+
+//## quantifiedExpression: 'exists' | ( expression 'in' ) | ( expression OP 'any' | 'some' ) collection;
+
+//## compoundPath: path ( OPEN_BRACKET expression CLOSE_BRACKET ( '.' path )? )*;
+
+//## path: identifier ( '.' identifier )*;
+
+path
+	: identifier ( DOT^ { weakKeywords(); } identifier )*
+	;
+
+// Wraps the IDENT token from the lexer, in order to provide
+// 'keyword as identifier' trickery.
+identifier
+	: IDENT
+	exception
+	catch [RecognitionException ex]
+	{
+		identifier_AST = handleIdentifierError(LT(1),ex);
+	}
+	;
+
+// **** LEXER ******************************************************************
+
+/**
+ * Hibernate Query Language Lexer
+ * <br>
+ * This lexer provides the HQL parser with tokens.
+ * @author Joshua Davis (pgmjsd at sourceforge.net)
+ */
+class HqlBaseLexer extends Lexer;
+
+options {
+	exportVocab=Hql;      // call the vocabulary "Hql"
+	testLiterals = false;
+	k=2; // needed for newline, and to distinguish '>' from '>='.
+	// HHH-241 : Quoted strings don't allow unicode chars - This should fix it.
+	charVocabulary='\u0000'..'\uFFFE';	// Allow any char but \uFFFF (16 bit -1, ANTLR's EOF character)
+	caseSensitive = false;
+	caseSensitiveLiterals = false;
+}
+
+// -- Declarations --
+{
+	// NOTE: The real implementations are in the subclass.
+	protected void setPossibleID(boolean possibleID) {}
+}
+
+// -- Keywords --
+
+EQ: '=';
+LT: '<';
+GT: '>';
+SQL_NE: "<>";
+NE: "!=" | "^=";
+LE: "<=";
+GE: ">=";
+
+COMMA: ',';
+
+OPEN: '(';
+CLOSE: ')';
+OPEN_BRACKET: '[';
+CLOSE_BRACKET: ']';
+
+CONCAT: "||";
+PLUS: '+';
+MINUS: '-';
+STAR: '*';
+DIV: '/';
+COLON: ':';
+PARAM: '?';
+
+IDENT options { testLiterals=true; }
+	: ID_START_LETTER ( ID_LETTER )*
+		{
+    		// Setting this flag allows the grammar to use keywords as identifiers, if necessary.
+			setPossibleID(true);
+		}
+	;
+
+protected
+ID_START_LETTER
+    :    '_'
+    |    '$'
+    |    'a'..'z'
+    |    '\u0080'..'\ufffe'       // HHH-558 : Allow unicode chars in identifiers
+    ;
+
+protected
+ID_LETTER
+    :    ID_START_LETTER
+    |    '0'..'9'
+    ;
+
+QUOTED_STRING
+	  : '\'' ( (ESCqs)=> ESCqs | ~'\'' )* '\''
+	;
+
+protected
+ESCqs
+	:
+		'\'' '\''
+	;
+
+WS  :   (   ' '
+		|   '\t'
+		|   '\r' '\n' { newline(); }
+		|   '\n'      { newline(); }
+		|   '\r'      { newline(); }
+		)
+		{$setType(Token.SKIP);} //ignore this token
+	;
+
+//--- From the Java example grammar ---
+// a numeric literal
+NUM_INT
+	{boolean isDecimal=false; Token t=null;}
+	:   '.' {_ttype = DOT;}
+			(	('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
+				{
+					if (t != null && t.getText().toUpperCase().indexOf('F')>=0)
+					{
+						_ttype = NUM_FLOAT;
+					}
+					else
+					{
+						_ttype = NUM_DOUBLE; // assume double
+					}
+				}
+			)?
+	|	(	'0' {isDecimal = true;} // special case for just '0'
+			(	('x')
+				(											// hex
+					// the 'e'|'E' and float suffix stuff look
+					// like hex digits, hence the (...)+ doesn't
+					// know when to stop: ambig.  ANTLR resolves
+					// it correctly by matching immediately.  It
+					// is therefore ok to hush warning.
+					options { warnWhenFollowAmbig=false; }
+				:	HEX_DIGIT
+				)+
+			|	('0'..'7')+									// octal
+			)?
+		|	('1'..'9') ('0'..'9')*  {isDecimal=true;}		// non-zero decimal
+		)
+		(	('l') { _ttype = NUM_LONG; }
+
+		// only check to see if it's a float if looks like decimal so far
+		|	{isDecimal}?
+			(   '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
+			|   EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
+			|   f4:FLOAT_SUFFIX {t=f4;}
+			)
+			{
+				if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0)
+				{
+					_ttype = NUM_FLOAT;
+				}
+				else
+				{
+					_ttype = NUM_DOUBLE; // assume double
+				}
+			}
+		)?
+	;
+
+// hexadecimal digit (again, note it's protected!)
+protected
+HEX_DIGIT
+	:	('0'..'9'|'a'..'f')
+	;
+
+// a couple protected methods to assist in matching floating point numbers
+protected
+EXPONENT
+	:	('e') ('+'|'-')? ('0'..'9')+
+	;
+
+protected
+FLOAT_SUFFIX
+	:	'f'|'d'
+	;
+

Added: trunk/Hibernate3/core/src/main/antlr/sql-gen.g
===================================================================
--- trunk/Hibernate3/core/src/main/antlr/sql-gen.g	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/antlr/sql-gen.g	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,427 @@
+header
+{
+//   $Id: sql-gen.g 10001 2006-06-08 21:08:04Z steve.ebersole at jboss.com $
+package org.hibernate.hql.antlr;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+}
+/**
+ * SQL Generator Tree Parser, providing SQL rendering of SQL ASTs produced by the previous phase, HqlSqlWalker.  All
+ * syntax decoration such as extra spaces, lack of spaces, extra parens, etc. should be added by this class.
+ * <br>
+ * This grammar processes the HQL/SQL AST and produces an SQL string.  The intent is to move dialect-specific
+ * code into a sub-class that will override some of the methods, just like the other two grammars in this system.
+ * @author Joshua Davis (joshua at hibernate.org)
+ */
+class SqlGeneratorBase extends TreeParser;
+
+options {
+	// Note: importVocab and exportVocab cause ANTLR to share the token type numbers between the
+	// two grammars.  This means that the token type constants from the source tree are the same
+	// as those in the target tree.  If this is not the case, tree translation can result in
+	// token types from the *source* tree being present in the target tree.
+	importVocab=HqlSql;         // import definitions from "HqlSql"
+	exportVocab=Sql;            // Call the resulting definitions "Sql"
+	buildAST=false;             // Don't build an AST.
+}
+
+{
+	private static Log log = LogFactory.getLog(SqlGeneratorBase.class);
+
+   /** the buffer resulting SQL statement is written to */
+	private StringBuffer buf = new StringBuffer();
+
+	protected void out(String s) {
+		buf.append(s);
+	}
+
+	/**
+	 * Returns the last character written to the output, or -1 if there isn't one.
+	 */
+	protected int getLastChar() {
+		int len = buf.length();
+		if ( len == 0 )
+			return -1;
+		else
+			return buf.charAt( len - 1 );
+	}
+
+	/**
+	 * Add a aspace if the previous token was not a space or a parenthesis.
+	 */
+	protected void optionalSpace() {
+		// Implemented in the sub-class.
+	}
+
+	protected void out(AST n) {
+		out(n.getText());
+	}
+
+	protected void separator(AST n, String sep) {
+		if (n.getNextSibling() != null)
+			out(sep);
+	}
+
+	protected boolean hasText(AST a) {
+		String t = a.getText();
+		return t != null && t.length() > 0;
+	}
+
+	protected void fromFragmentSeparator(AST a) {
+		// moved this impl into the subclass...
+	}
+
+	protected void nestedFromFragment(AST d,AST parent) {
+		// moved this impl into the subclass...
+	}
+
+	protected StringBuffer getStringBuffer() {
+		return buf;
+	}
+
+	protected void nyi(AST n) {
+		throw new UnsupportedOperationException("Unsupported node: " + n);
+	}
+
+	protected void beginFunctionTemplate(AST m,AST i) {
+		// if template is null we just write the function out as it appears in the hql statement
+		out(i);
+		out("(");
+	}
+
+	protected void endFunctionTemplate(AST m) {
+	      out(")");
+	}
+
+	protected void commaBetweenParameters(String comma) {
+		out(comma);
+	}
+}
+
+statement
+	: selectStatement
+	| updateStatement
+	| deleteStatement
+	| insertStatement
+	;
+
+selectStatement
+	: #(SELECT { out("select "); }
+		selectClause
+		from
+		( #(WHERE { out(" where "); } whereExpr ) )?
+		( #(GROUP { out(" group by "); } groupExprs ( #(HAVING { out(" having "); } booleanExpr[false]) )? ) )?
+		( #(ORDER { out(" order by "); } orderExprs ) )?
+	)
+	;
+
+// Note: eats the FROM token node, as it is not valid in an update statement.
+// It's outlived its usefulness after analysis phase :)
+// TODO : needed to use conditionList directly here and deleteStatement, as whereExprs no longer works for this stuff
+updateStatement
+	: #(UPDATE { out("update "); }
+		#( FROM fromTable )
+		setClause
+		(whereClause)?
+	)
+	;
+
+deleteStatement
+	// Note: not space needed at end of "delete" because the from rule included one before the "from" it outputs
+	: #(DELETE { out("delete"); }
+		from
+		(whereClause)?
+	)
+	;
+
+insertStatement
+	: #(INSERT { out( "insert " ); }
+		i:INTO { out( i ); out( " " ); }
+		selectStatement
+	)
+	;
+
+setClause
+	// Simply re-use comparisionExpr, because it already correctly defines the EQ rule the
+	// way it is needed here; not the most aptly named, but ah
+	: #( SET { out(" set "); } comparisonExpr[false] ( { out(", "); } comparisonExpr[false] )* )
+	;
+
+whereClause
+	: #(WHERE { out(" where "); } whereClauseExpr )
+	;
+
+whereClauseExpr
+	: (SQL_TOKEN) => conditionList
+	| booleanExpr[ false ]
+	;
+
+orderExprs
+	// TODO: remove goofy space before the comma when we don't have to regression test anymore.
+	: ( expr ) (dir:orderDirection { out(" "); out(dir); })? ( {out(", "); } orderExprs)?
+	;
+
+groupExprs
+	// TODO: remove goofy space before the comma when we don't have to regression test anymore.
+	: expr ( {out(" , "); } groupExprs)?
+	;
+
+orderDirection
+	: ASCENDING
+	| DESCENDING
+	;
+
+whereExpr
+	// Expect the filter subtree, followed by the theta join subtree, followed by the HQL condition subtree.
+	// Might need parens around the HQL condition if there is more than one subtree.
+	// Put 'and' between each subtree.
+	: filters
+		( { out(" and "); } thetaJoins )?
+		( { out(" and "); } booleanExpr [ true ] )?
+	| thetaJoins
+		( { out(" and "); } booleanExpr [ true ] )? 
+	| booleanExpr[false]
+	;
+
+filters
+	: #(FILTERS conditionList )
+	;
+
+thetaJoins
+	: #(THETA_JOINS conditionList )
+	;
+
+conditionList
+	: sqlToken ( { out(" and "); } conditionList )?
+	;
+
+selectClause
+	: #(SELECT_CLAUSE (distinctOrAll)? ( selectColumn )+ )
+	;
+
+selectColumn
+	: p:selectExpr (sc:SELECT_COLUMNS { out(sc); } )? { separator( (sc != null) ? sc : p,", "); }
+	;
+
+selectExpr
+	: e:selectAtom { out(e); }
+	| count
+	| #(CONSTRUCTOR (DOT | IDENT) ( selectColumn )+ )
+	| methodCall
+	| aggregate
+	| c:constant { out(c); }
+	| arithmeticExpr
+	| PARAM { out("?"); }
+	| sn:SQL_NODE { out(sn); }
+	| { out("("); } selectStatement { out(")"); }
+	;
+
+count
+	: #(COUNT { out("count("); }  ( distinctOrAll ) ? countExpr { out(")"); } )
+	;
+
+distinctOrAll
+	: DISTINCT { out("distinct "); }
+	| ALL { out("all "); }
+	;
+
+countExpr
+	// Syntacitic predicate resolves star all by itself, avoiding a conflict with STAR in expr.
+	: ROW_STAR { out("*"); }
+	| simpleExpr
+	;
+
+selectAtom
+	: DOT
+	| SQL_TOKEN
+	| ALIAS_REF
+	| SELECT_EXPR
+	;
+
+// The from-clause piece is all goofed up.  Currently, nodes of type FROM_FRAGMENT
+// and JOIN_FRAGMENT can occur at any level in the FromClause sub-tree. We really
+// should come back and clean this up at some point; which I think will require
+// a post-HqlSqlWalker phase to "re-align" the FromElements in a more sensible
+// manner.
+from
+	: #(f:FROM { out(" from "); }
+		(fromTable)* )
+	;
+
+fromTable
+	// Write the table node (from fragment) and all the join fragments associated with it.
+	: #( a:FROM_FRAGMENT  { out(a); } (tableJoin [ a ])* { fromFragmentSeparator(a); } )
+	| #( b:JOIN_FRAGMENT  { out(b); } (tableJoin [ b ])* { fromFragmentSeparator(b); } )
+	;
+
+tableJoin [ AST parent ]
+	: #( c:JOIN_FRAGMENT { out(" "); out(c); } (tableJoin [ c ] )* )
+	| #( d:FROM_FRAGMENT { nestedFromFragment(d,parent); } (tableJoin [ d ] )* )
+	;
+
+booleanOp[ boolean parens ]
+	: #(AND booleanExpr[true] { out(" and "); } booleanExpr[true])
+	| #(OR { if (parens) out("("); } booleanExpr[false] { out(" or "); } booleanExpr[false] { if (parens) out(")"); })
+	| #(NOT { out(" not ("); } booleanExpr[false] { out(")"); } )
+	;
+
+booleanExpr[ boolean parens ]
+	: booleanOp [ parens ]
+	| comparisonExpr [ parens ]
+	| st:SQL_TOKEN { out(st); } // solely for the purpose of mapping-defined where-fragments
+	;
+	
+comparisonExpr[ boolean parens ]
+	: binaryComparisonExpression
+	| { if (parens) out("("); } exoticComparisonExpression { if (parens) out(")"); }
+	;
+	
+binaryComparisonExpression
+	: #(EQ expr { out("="); } expr)
+	| #(NE expr { out("<>"); } expr)
+	| #(GT expr { out(">"); } expr)
+	| #(GE expr { out(">="); } expr)
+	| #(LT expr { out("<"); } expr)
+	| #(LE expr { out("<="); } expr)
+	;
+	
+exoticComparisonExpression
+	: #(LIKE expr { out(" like "); } expr likeEscape )
+	| #(NOT_LIKE expr { out(" not like "); } expr likeEscape)
+	| #(BETWEEN expr { out(" between "); } expr { out(" and "); } expr)
+	| #(NOT_BETWEEN expr { out(" not between "); } expr { out(" and "); } expr)
+	| #(IN expr { out(" in"); } inList )
+	| #(NOT_IN expr { out(" not in "); } inList )
+	| #(EXISTS { optionalSpace(); out("exists "); } quantified )
+	| #(IS_NULL expr) { out(" is null"); }
+	| #(IS_NOT_NULL expr) { out(" is not null"); }
+	;
+
+likeEscape
+	: ( #(ESCAPE { out(" escape "); } expr) )?
+	;
+
+inList
+	: #(IN_LIST { out(" "); } ( parenSelect | simpleExprList ) )
+	;
+	
+simpleExprList
+	: { out("("); } (e:simpleExpr { separator(e," , "); } )* { out(")"); }
+	;
+
+// A simple expression, or a sub-select with parens around it.
+expr
+	: simpleExpr
+	| #( VECTOR_EXPR { out("("); } (e:expr { separator(e," , "); } )*  { out(")"); } )
+	| parenSelect
+	| #(ANY { out("any "); } quantified )
+	| #(ALL { out("all "); } quantified )
+	| #(SOME { out("some "); } quantified )
+	;
+	
+quantified
+	: { out("("); } ( sqlToken | selectStatement ) { out(")"); } 
+	;
+	
+parenSelect
+	: { out("("); } selectStatement { out(")"); }
+	;
+	
+simpleExpr
+	: c:constant { out(c); }
+	| NULL { out("null"); }
+	| addrExpr
+	| sqlToken
+	| aggregate
+	| methodCall
+	| count
+	| parameter
+	| arithmeticExpr
+	;
+	
+constant
+	: NUM_DOUBLE
+	| NUM_FLOAT
+	| NUM_INT
+	| NUM_LONG
+	| QUOTED_STRING
+	| CONSTANT
+	| JAVA_CONSTANT
+	| TRUE
+	| FALSE
+	| IDENT
+	;
+	
+arithmeticExpr
+	: additiveExpr
+	| multiplicativeExpr
+//	| #(CONCAT { out("("); } expr ( { out("||"); } expr )+ { out(")"); } )
+	| #(UNARY_MINUS { out("-"); } expr)
+	| caseExpr
+	;
+
+additiveExpr
+	: #(PLUS expr { out("+"); } expr)
+	| #(MINUS expr { out("-"); } nestedExprAfterMinusDiv)
+	;
+
+multiplicativeExpr
+	: #(STAR nestedExpr { out("*"); } nestedExpr)
+	| #(DIV nestedExpr { out("/"); } nestedExprAfterMinusDiv)
+	;
+
+nestedExpr
+	// Generate parens around nested additive expressions, use a syntactic predicate to avoid conflicts with 'expr'.
+	: (additiveExpr) => { out("("); } additiveExpr { out(")"); }
+	| expr
+	;
+	
+nestedExprAfterMinusDiv
+	// Generate parens around nested arithmetic expressions, use a syntactic predicate to avoid conflicts with 'expr'.
+	: (arithmeticExpr) => { out("("); } arithmeticExpr { out(")"); }
+	| expr
+	;
+
+caseExpr
+	: #(CASE { out("case"); } 
+		( #(WHEN { out( " when "); } booleanExpr[false] { out(" then "); } expr) )+ 
+		( #(ELSE { out(" else "); } expr) )?
+		{ out(" end"); } )
+	| #(CASE2 { out("case "); } expr
+		( #(WHEN { out( " when "); } expr { out(" then "); } expr) )+ 
+		( #(ELSE { out(" else "); } expr) )?
+		{ out(" end"); } )
+	;
+
+aggregate
+	: #(a:AGGREGATE { out(a); out("("); }  expr { out(")"); } )
+	;
+
+
+methodCall
+	: #(m:METHOD_CALL i:METHOD_NAME { beginFunctionTemplate(m,i); }
+	 ( #(EXPR_LIST (arguments)? ) )?
+	 { endFunctionTemplate(m); } )
+	;
+
+arguments
+	: expr ( { commaBetweenParameters(", "); } expr )*
+	;
+
+parameter
+	: n:NAMED_PARAM { out(n); }
+	| p:PARAM { out(p); }
+	;
+
+addrExpr
+	: #(r:DOT . .) { out(r); }
+	| i:ALIAS_REF { out(i); }
+	| j:INDEX_OP { out(j); }
+	;
+
+sqlToken
+	: t:SQL_TOKEN { out(t); }
+	;
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/AssertionFailure.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/AssertionFailure.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/AssertionFailure.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+//$Id: AssertionFailure.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate;
+
+import org.hibernate.exception.NestableRuntimeException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Indicates failure of an assertion: a possible bug in Hibernate.
+ *
+ * @author Gavin King
+ */
+
+public class AssertionFailure extends NestableRuntimeException {
+
+	private static final Log log = LogFactory.getLog(AssertionFailure.class);
+
+	private static final String MESSAGE = "an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)";
+
+	public AssertionFailure(String s) {
+		super(s);
+		log.error(MESSAGE, this);
+	}
+
+	public AssertionFailure(String s, Throwable t) {
+		super(s, t);
+		log.error(MESSAGE, t);
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/CacheMode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/CacheMode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/CacheMode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+//$Id: CacheMode.java 9194 2006-02-01 19:59:07Z steveebersole $
+package org.hibernate;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Controls how the session interacts with the second-level
+ * cache and query cache.
+ *
+ * @see Session#setCacheMode(CacheMode)
+ * @author Gavin King
+ */
+public final class CacheMode implements Serializable {
+	private final String name;
+	private final boolean isPutEnabled;
+	private final boolean isGetEnabled;
+	private static final Map INSTANCES = new HashMap();
+
+	private CacheMode(String name, boolean isPutEnabled, boolean isGetEnabled) {
+		this.name=name;
+		this.isPutEnabled = isPutEnabled;
+		this.isGetEnabled = isGetEnabled;
+	}
+	public String toString() {
+		return name;
+	}
+	public boolean isPutEnabled() {
+		return isPutEnabled;
+	}
+	public boolean isGetEnabled() {
+		return isGetEnabled;
+	}
+	/**
+	 * The session may read items from the cache, and add items to the cache
+	 */
+	public static final CacheMode NORMAL = new CacheMode("NORMAL", true, true);
+	/**
+	 * The session will never interact with the cache, except to invalidate
+	 * cache items when updates occur
+	 */
+	public static final CacheMode IGNORE = new CacheMode("IGNORE", false, false);
+	/**
+	 * The session may read items from the cache, but will not add items, 
+	 * except to invalidate items when updates occur
+	 */
+	public static final CacheMode GET = new CacheMode("GET", false, true);
+	/**
+	 * The session will never read items from the cache, but will add items
+	 * to the cache as it reads them from the database.
+	 */
+	public static final CacheMode PUT = new CacheMode("PUT", true, false);
+	
+	/**
+	 * The session will never read items from the cache, but will add items
+	 * to the cache as it reads them from the database. In this mode, the
+	 * effect of <tt>hibernate.cache.use_minimal_puts</tt> is bypassed, in
+	 * order to <em>force</em> a cache refresh
+	 */
+	public static final CacheMode REFRESH = new CacheMode("REFRESH", true, false);
+	
+	static {
+		INSTANCES.put( NORMAL.name, NORMAL );
+		INSTANCES.put( IGNORE.name, IGNORE );
+		INSTANCES.put( GET.name, GET );
+		INSTANCES.put( PUT.name, PUT );
+		INSTANCES.put( REFRESH.name, REFRESH );
+	}
+
+	private Object readResolve() {
+		return INSTANCES.get( name );
+	}
+
+	public static CacheMode parse(String name) {
+		return ( CacheMode ) INSTANCES.get( name );
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/CacheMode.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/CallbackException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/CallbackException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/CallbackException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+//$Id: CallbackException.java 4242 2004-08-11 09:10:45Z oneovthafew $
+package org.hibernate;
+
+
+/**
+ * Should be thrown by persistent objects from <tt>Lifecycle</tt>
+ * or <tt>Interceptor</tt> callbacks.
+ *
+ * @see Lifecycle
+ * @see Interceptor
+ * @author Gavin King
+ */
+
+public class CallbackException extends HibernateException {
+
+	public CallbackException(Exception root) {
+		super("An exception occurred in a callback", root);
+	}
+
+	public CallbackException(String message) {
+		super(message);
+	}
+
+	public CallbackException(String message, Exception e) {
+		super(message, e);
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/ConnectionReleaseMode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/ConnectionReleaseMode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/ConnectionReleaseMode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,77 @@
+// $Id: ConnectionReleaseMode.java 8409 2005-10-14 20:28:18Z steveebersole $
+package org.hibernate;
+
+import java.io.Serializable;
+
+/**
+ * Defines the various policies by which Hibernate might release its underlying
+ * JDBC connection.
+ *
+ * @author Steve Ebersole
+ */
+public class ConnectionReleaseMode  implements Serializable {
+
+	/**
+	 * Indicates that JDBC connection should be aggressively released after each 
+	 * SQL statement is executed. In this mode, the application <em>must</em>
+	 * explicitly close all iterators and scrollable results. This mode may
+	 * only be used with a JTA datasource.
+	 */
+	public static final ConnectionReleaseMode AFTER_STATEMENT = new ConnectionReleaseMode( "after_statement" );
+
+	/**
+	 * Indicates that JDBC connections should be released after each transaction 
+	 * ends (works with both JTA-registered synch and HibernateTransaction API).
+	 * This mode may not be used with an application server JTA datasource.
+	 * <p/>
+	 * This is the default mode starting in 3.1; was previously {@link #ON_CLOSE}.
+	 */
+	public static final ConnectionReleaseMode AFTER_TRANSACTION = new ConnectionReleaseMode( "after_transaction" );
+
+	/**
+	 * Indicates that connections should only be released when the Session is explicitly closed 
+	 * or disconnected; this is the legacy (Hibernate2 and pre-3.1) behavior.
+	 */
+	public static final ConnectionReleaseMode ON_CLOSE = new ConnectionReleaseMode( "on_close" );
+
+
+	private String name;
+
+	private ConnectionReleaseMode(String name) {
+		this.name = name;
+	}
+
+	/**
+	 * Override of Object.toString().  Returns the release mode name.
+	 *
+	 * @return The release mode name.
+	 */
+	public String toString() {
+		return name;
+	}
+
+	/**
+	 * Determine the correct ConnectionReleaseMode instance based on the given
+	 * name.
+	 *
+	 * @param modeName The release mode name.
+	 * @return The appropriate ConnectionReleaseMode instance
+	 * @throws HibernateException Indicates the modeName param did not match any known modes.
+	 */
+	public static ConnectionReleaseMode parse(String modeName) throws HibernateException {
+		if ( AFTER_STATEMENT.name.equals( modeName ) ) {
+			return AFTER_STATEMENT;
+		}
+		else if ( AFTER_TRANSACTION.name.equals( modeName ) ) {
+			return AFTER_TRANSACTION;
+		}
+		else if ( ON_CLOSE.name.equals( modeName ) ) {
+			return ON_CLOSE;
+		}
+		throw new HibernateException( "could not determine appropriate connection release mode [" + modeName + "]" );
+	}
+
+	private Object readResolve() {
+		return parse( name );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/Criteria.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/Criteria.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/Criteria.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,338 @@
+//$Id: Criteria.java 9116 2006-01-23 21:21:01Z steveebersole $
+package org.hibernate;
+
+import java.util.List;
+
+import org.hibernate.criterion.CriteriaSpecification;
+import org.hibernate.criterion.Criterion;
+import org.hibernate.criterion.Order;
+import org.hibernate.criterion.Projection;
+import org.hibernate.transform.ResultTransformer;
+
+/**
+ * <tt>Criteria</tt> is a simplified API for retrieving entities
+ * by composing <tt>Criterion</tt> objects. This is a very
+ * convenient approach for functionality like "search" screens
+ * where there is a variable number of conditions to be placed
+ * upon the result set.<br>
+ * <br>
+ * The <tt>Session</tt> is a factory for <tt>Criteria</tt>.
+ * <tt>Criterion</tt> instances are usually obtained via
+ * the factory methods on <tt>Restrictions</tt>. eg.
+ * <pre>
+ * List cats = session.createCriteria(Cat.class)
+ *     .add( Restrictions.like("name", "Iz%") )
+ *     .add( Restrictions.gt( "weight", new Float(minWeight) ) )
+ *     .addOrder( Order.asc("age") )
+ *     .list();
+ * </pre>
+ * You may navigate associations using <tt>createAlias()</tt> or
+ * <tt>createCriteria()</tt>.
+ * <pre>
+ * List cats = session.createCriteria(Cat.class)
+ *     .createCriteria("kittens")
+ *         .add( Restrictions.like("name", "Iz%") )
+ *     .list();
+ * </pre>
+ * <pre>
+ * List cats = session.createCriteria(Cat.class)
+ *     .createAlias("kittens", "kit")
+ *     .add( Restrictions.like("kit.name", "Iz%") )
+ *     .list();
+ * </pre>
+ * You may specify projection and aggregation using <tt>Projection</tt>
+ * instances obtained via the factory methods on <tt>Projections</tt>.
+ * <pre>
+ * List cats = session.createCriteria(Cat.class)
+ *     .setProjection( Projections.projectionList()
+ *         .add( Projections.rowCount() )
+ *         .add( Projections.avg("weight") )
+ *         .add( Projections.max("weight") )
+ *         .add( Projections.min("weight") )
+ *         .add( Projections.groupProperty("color") )
+ *     )
+ *     .addOrder( Order.asc("color") )
+ *     .list();
+ * </pre>
+ *
+ * @see Session#createCriteria(java.lang.Class)
+ * @see org.hibernate.criterion.Restrictions
+ * @see org.hibernate.criterion.Projections
+ * @see org.hibernate.criterion.Order
+ * @see org.hibernate.criterion.Criterion
+ * @see org.hibernate.criterion.Projection
+ * @see org.hibernate.criterion.DetachedCriteria a disconnected version of this API
+ * @author Gavin King
+ */
+public interface Criteria extends CriteriaSpecification {
+
+	/**
+	 * Get the alias of the entity encapsulated by this criteria instance.
+	 *
+	 * @return The alias for the encapsulated entity.
+	 */
+	public String getAlias();
+
+	/**
+	 * Used to specify that the query results will be a projection (scalar in
+	 * nature).  Implicitly specifies the {@link #PROJECTION} result transformer.
+	 * <p/>
+	 * The individual components contained within the given
+	 * {@link Projection projection} determines the overall "shape" of the
+	 * query result.
+	 *
+	 * @param projection The projection representing the overall "shape" of the
+	 * query results.
+	 * @return this (for method chaining)
+	 */
+	public Criteria setProjection(Projection projection);
+
+	/**
+	 * Add a {@link Criterion restriction} to constrain the results to be
+	 * retrieved.
+	 *
+	 * @param criterion The {@link Criterion criterion} object representing the
+	 * restriction to be applied.
+	 * @return this (for method chaining)
+	 */
+	public Criteria add(Criterion criterion);
+	
+	/**
+	 * Add an {@link Order ordering} to the result set.
+	 *
+	 * @param order The {@link Order order} object representing an ordering
+	 * to be applied to the results.
+	 * @return this (for method chaining)
+	 */
+	public Criteria addOrder(Order order);
+
+	/**
+	 * Specify an association fetching strategy for an association or a
+	 * collection of values.
+	 *
+	 * @param associationPath a dot seperated property path
+	 * @param mode The fetch mode for the referenced association
+	 * @return this (for method chaining)
+	 */
+	public Criteria setFetchMode(String associationPath, FetchMode mode) throws HibernateException;
+
+	/**
+	 * Set the lock mode of the current entity
+	 *
+	 * @param lockMode The lock mode to be applied
+	 * @return this (for method chaining)
+	 */
+	public Criteria setLockMode(LockMode lockMode);
+
+	/**
+	 * Set the lock mode of the aliased entity
+	 *
+	 * @param alias The previously assigned alias representing the entity to
+	 * which the given lock mode should apply.
+	 * @param lockMode The lock mode to be applied
+	 * @return this (for method chaining)
+	 */
+	public Criteria setLockMode(String alias, LockMode lockMode);
+
+	/**
+	 * Join an association, assigning an alias to the joined association.
+	 * <p/>
+	 * Functionally equivalent to {@link #createAlias(String, String, int)} using
+	 * {@link #INNER_JOIN} for the joinType.
+	 *
+	 * @param associationPath A dot-seperated property path
+	 * @param alias The alias to assign to the joined association (for later reference).
+	 * @return this (for method chaining)
+	 */
+	public Criteria createAlias(String associationPath, String alias) throws HibernateException;
+
+	/**
+	 * Join an association using the specified join-type, assigning an alias
+	 * to the joined association.
+	 * <p/>
+	 * The joinType is expected to be one of {@link #INNER_JOIN} (the default),
+	 * {@link #FULL_JOIN}, or {@link #LEFT_JOIN}.
+	 *
+	 * @param associationPath A dot-seperated property path
+	 * @param alias The alias to assign to the joined association (for later reference).
+	 * @param joinType The type of join to use.
+	 * @return this (for method chaining)
+	 */
+	public Criteria createAlias(String associationPath, String alias, int joinType) throws HibernateException;
+
+	/**
+	 * Create a new <tt>Criteria</tt>, "rooted" at the associated entity.
+	 * <p/>
+	 * Functionally equivalent to {@link #createCriteria(String, int)} using
+	 * {@link #INNER_JOIN} for the joinType.
+	 *
+	 * @param associationPath A dot-seperated property path
+	 * @return the created "sub criteria"
+	 */
+	public Criteria createCriteria(String associationPath) throws HibernateException;
+
+	/**
+	 * Create a new <tt>Criteria</tt>, "rooted" at the associated entity, using the
+	 * specified join type.
+	 *
+	 * @param associationPath A dot-seperated property path
+	 * @param joinType The type of join to use.
+	 * @return the created "sub criteria"
+	 */
+	public Criteria createCriteria(String associationPath, int joinType) throws HibernateException;
+
+	/**
+	 * Create a new <tt>Criteria</tt>, "rooted" at the associated entity,
+	 * assigning the given alias.
+	 * <p/>
+	 * Functionally equivalent to {@link #createCriteria(String, String, int)} using
+	 * {@link #INNER_JOIN} for the joinType.
+	 *
+	 * @param associationPath A dot-seperated property path
+	 * @param alias The alias to assign to the joined association (for later reference).
+	 * @return the created "sub criteria"
+	 */
+	public Criteria createCriteria(String associationPath, String alias) throws HibernateException;
+
+	/**
+	 * Create a new <tt>Criteria</tt>, "rooted" at the associated entity,
+	 * assigning the given alias and using the specified join type.
+	 *
+	 * @param associationPath A dot-seperated property path
+	 * @param alias The alias to assign to the joined association (for later reference).
+	 * @param joinType The type of join to use.
+	 * @return the created "sub criteria"
+	 */
+	public Criteria createCriteria(String associationPath, String alias, int joinType) throws HibernateException;
+
+	/**
+	 * Set a strategy for handling the query results. This determines the
+	 * "shape" of the query result.
+	 *
+	 * @param resultTransformer The transformer to apply
+	 * @return this (for method chaining)
+	 *
+	 * @see #ROOT_ENTITY
+	 * @see #DISTINCT_ROOT_ENTITY
+	 * @see #ALIAS_TO_ENTITY_MAP
+	 * @see #PROJECTION
+	 */
+	public Criteria setResultTransformer(ResultTransformer resultTransformer);
+
+	/**
+	 * Set a limit upon the number of objects to be retrieved.
+	 *
+	 * @param maxResults the maximum number of results
+	 * @return this (for method chaining)
+	 */
+	public Criteria setMaxResults(int maxResults);
+	
+	/**
+	 * Set the first result to be retrieved.
+	 *
+	 * @param firstResult the first result to retrieve, numbered from <tt>0</tt>
+	 * @return this (for method chaining)
+	 */
+	public Criteria setFirstResult(int firstResult);
+	
+	/**
+	 * Set a fetch size for the underlying JDBC query.
+	 *
+	 * @param fetchSize the fetch size
+	 * @return this (for method chaining)
+	 *
+	 * @see java.sql.Statement#setFetchSize
+	 */
+	public Criteria setFetchSize(int fetchSize);
+
+	/**
+	 * Set a timeout for the underlying JDBC query.
+	 *
+	 * @param timeout The timeout value to apply.
+	 * @return this (for method chaining)
+	 *
+	 * @see java.sql.Statement#setQueryTimeout
+	 */
+	public Criteria setTimeout(int timeout);
+
+	/**
+	 * Enable caching of this query result, provided query caching is enabled
+	 * for the underlying session factory.
+	 *
+	 * @param cacheable Should the result be considered cacheable; default is
+	 * to not cache (false).
+	 * @return this (for method chaining)
+	 */
+	public Criteria setCacheable(boolean cacheable);
+
+	/**
+	 * Set the name of the cache region to use for query result caching.
+	 *
+	 * @param cacheRegion the name of a query cache region, or <tt>null</tt>
+	 * for the default query cache
+	 * @return this (for method chaining)
+	 *
+	 * @see #setCacheable
+	 */
+	public Criteria setCacheRegion(String cacheRegion);
+
+	/**
+	 * Add a comment to the generated SQL.
+	 *
+	 * @param comment a human-readable string
+	 * @return this (for method chaining)
+	 */
+	public Criteria setComment(String comment);
+
+	/**
+	 * Override the flush mode for this particular query.
+	 *
+	 * @param flushMode The flush mode to use.
+	 * @return this (for method chaining)
+	 */
+	public Criteria setFlushMode(FlushMode flushMode);
+
+	/**
+	 * Override the cache mode for this particular query.
+	 *
+	 * @param cacheMode The cache mode to use.
+	 * @return this (for method chaining)
+	 */
+	public Criteria setCacheMode(CacheMode cacheMode);
+
+	/**
+	 * Get the results.
+	 *
+	 * @return The list of matched query results.
+	 */
+	public List list() throws HibernateException;
+	
+	/**
+	 * Get the results as an instance of {@link ScrollableResults}
+	 *
+	 * @return The {@link ScrollableResults} representing the matched
+	 * query results.
+	 */
+	public ScrollableResults scroll() throws HibernateException;
+
+	/**
+	 * Get the results as an instance of {@link ScrollableResults} based on the
+	 * given scroll mode.
+	 *
+	 * @param scrollMode Indicates the type of underlying database cursor to
+	 * request.
+	 * @return The {@link ScrollableResults} representing the matched
+	 * query results.
+	 */
+	public ScrollableResults scroll(ScrollMode scrollMode) throws HibernateException;
+
+	/**
+	 * Convenience method to return a single instance that matches
+	 * the query, or null if the query returns no results.
+	 *
+	 * @return the single result or <tt>null</tt>
+	 * @throws HibernateException if there is more than one matching result
+	 */
+	public Object uniqueResult() throws HibernateException;
+	
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/DuplicateMappingException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/DuplicateMappingException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/DuplicateMappingException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+package org.hibernate;
+
+/**
+ * Raised whenever a duplicate for a certain type occurs.
+ * Duplicate class, table, property name etc.
+ * 
+ * @author Max Rydahl Andersen
+ *
+ */
+public class DuplicateMappingException extends MappingException {
+
+	private final String name;
+	private final String type;
+
+	public DuplicateMappingException(String customMessage, String type, String name) {
+		super(customMessage);
+		this.type=type;
+		this.name=name;
+	}
+	
+	public DuplicateMappingException(String type, String name) {
+		this("Duplicate " + type + " mapping " + name, type, name);
+	}
+
+	public String getType() {
+		return type;
+	}
+	
+	public String getName() {
+		return name;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/EmptyInterceptor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/EmptyInterceptor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/EmptyInterceptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,98 @@
+//$Id: EmptyInterceptor.java 7859 2005-08-11 21:57:33Z oneovthafew $
+package org.hibernate;
+
+import java.io.Serializable;
+import java.util.Iterator;
+
+import org.hibernate.type.Type;
+
+/**
+ * An interceptor that does nothing. May be used as a base class
+ * for application-defined custom interceptors.
+ * 
+ * @author Gavin King
+ */
+public class EmptyInterceptor implements Interceptor, Serializable {
+	
+	public static final Interceptor INSTANCE = new EmptyInterceptor();
+	
+	protected EmptyInterceptor() {}
+
+	public void onDelete(
+			Object entity, 
+			Serializable id, 
+			Object[] state, 
+			String[] propertyNames, 
+			Type[] types) {}
+
+	public boolean onFlushDirty(
+			Object entity, 
+			Serializable id, 
+			Object[] currentState, 
+			Object[] previousState, 
+			String[] propertyNames, 
+			Type[] types) {
+		return false;
+	}
+
+	public boolean onLoad(
+			Object entity, 
+			Serializable id, 
+			Object[] state, 
+			String[] propertyNames, 
+			Type[] types) {
+		return false;
+	}
+
+	public boolean onSave(
+			Object entity, 
+			Serializable id, 
+			Object[] state, 
+			String[] propertyNames, 
+			Type[] types) {
+		return false;
+	}
+
+	public void postFlush(Iterator entities) {}
+	public void preFlush(Iterator entities) {}
+
+	public Boolean isTransient(Object entity) {
+		return null;
+	}
+
+	public Object instantiate(String entityName, EntityMode entityMode, Serializable id) {
+		return null;
+	}
+
+	public int[] findDirty(Object entity,
+			Serializable id,
+			Object[] currentState,
+			Object[] previousState,
+			String[] propertyNames,
+			Type[] types) {
+		return null;
+	}
+
+	public String getEntityName(Object object) {
+		return null;
+	}
+
+	public Object getEntity(String entityName, Serializable id) {
+		return null;
+	}
+
+	public void afterTransactionBegin(Transaction tx) {}
+	public void afterTransactionCompletion(Transaction tx) {}
+	public void beforeTransactionCompletion(Transaction tx) {}
+
+	public String onPrepareStatement(String sql) {
+		return sql;
+	}
+
+	public void onCollectionRemove(Object collection, Serializable key) throws CallbackException {}
+
+	public void onCollectionRecreate(Object collection, Serializable key) throws CallbackException {}
+
+	public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException {}
+	
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/EmptyInterceptor.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/EntityMode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/EntityMode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/EntityMode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+// $Id: EntityMode.java 8697 2005-11-29 14:29:24Z steveebersole $
+package org.hibernate;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.io.Serializable;
+
+/**
+ * Defines the representation modes available for entities.
+ *
+ * @author Steve Ebersole
+ */
+public class EntityMode implements Serializable {
+
+	private static final Map INSTANCES = new HashMap();
+
+	public static final EntityMode POJO = new EntityMode( "pojo" );
+	public static final EntityMode DOM4J = new EntityMode( "dom4j" );
+	public static final EntityMode MAP = new EntityMode( "dynamic-map" );
+
+	static {
+		INSTANCES.put( POJO.name, POJO );
+		INSTANCES.put( DOM4J.name, DOM4J );
+		INSTANCES.put( MAP.name, MAP );
+	}
+
+	private final String name;
+
+	public EntityMode(String name) {
+		this.name = name;
+	}
+
+	public String toString() {
+		return name;
+	}
+
+	private Object readResolve() {
+		return INSTANCES.get( name );
+	}
+
+	public static EntityMode parse(String name) {
+		EntityMode rtn = ( EntityMode ) INSTANCES.get( name );
+		if ( rtn == null ) {
+			// default is POJO
+			rtn = POJO;
+		}
+		return rtn;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/FetchMode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/FetchMode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/FetchMode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,70 @@
+//$Id: FetchMode.java 5060 2004-12-24 03:11:05Z oneovthafew $
+package org.hibernate;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents an association fetching strategy. This is used
+ * together with the <tt>Criteria</tt> API to specify runtime
+ * fetching strategies.<br>
+ * <br>
+ * For HQL queries, use the <tt>FETCH</tt> keyword instead.
+ *
+ * @see Criteria#setFetchMode(java.lang.String, FetchMode)
+ * @author Gavin King
+ */
+public final class FetchMode implements Serializable {
+	private final String name;
+	private static final Map INSTANCES = new HashMap();
+
+	private FetchMode(String name) {
+		this.name=name;
+	}
+	public String toString() {
+		return name;
+	}
+	/**
+	 * Default to the setting configured in the mapping file.
+	 */
+	public static final FetchMode DEFAULT = new FetchMode("DEFAULT");
+
+	/**
+	 * Fetch using an outer join. Equivalent to <tt>fetch="join"</tt>.
+	 */
+	public static final FetchMode JOIN = new FetchMode("JOIN");
+	/**
+	 * Fetch eagerly, using a separate select. Equivalent to
+	 * <tt>fetch="select"</tt>.
+	 */
+	public static final FetchMode SELECT = new FetchMode("SELECT");
+
+	/**
+	 * Fetch lazily. Equivalent to <tt>outer-join="false"</tt>.
+	 * @deprecated use <tt>FetchMode.SELECT</tt>
+	 */
+	public static final FetchMode LAZY = SELECT;
+	/**
+	 * Fetch eagerly, using an outer join. Equivalent to
+	 * <tt>outer-join="true"</tt>.
+	 * @deprecated use <tt>FetchMode.JOIN</tt>
+	 */
+	public static final FetchMode EAGER = JOIN;
+	
+	static {
+		INSTANCES.put( JOIN.name, JOIN );
+		INSTANCES.put( SELECT.name, SELECT );
+		INSTANCES.put( DEFAULT.name, DEFAULT );
+	}
+
+	private Object readResolve() {
+		return INSTANCES.get(name);
+	}
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/Filter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/Filter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/Filter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,68 @@
+// $Id: Filter.java 8754 2005-12-05 23:36:59Z steveebersole $
+package org.hibernate;
+
+import org.hibernate.engine.FilterDefinition;
+
+import java.util.Collection;
+
+/**
+ * Type definition of Filter.  Filter defines the user's view into enabled dynamic filters,
+ * allowing them to set filter parameter values.
+ *
+ * @author Steve Ebersole
+ */
+public interface Filter {
+
+	/**
+	 * Get the name of this filter.
+	 *
+	 * @return This filter's name.
+	 */
+	public String getName();
+
+	/**
+	 * Get the filter definition containing additional information about the
+	 * filter (such as default-condition and expected parameter names/types).
+	 *
+	 * @return The filter definition
+	 */
+	public FilterDefinition getFilterDefinition();
+
+
+	/**
+	 * Set the named parameter's value for this filter.
+	 *
+	 * @param name The parameter's name.
+	 * @param value The value to be applied.
+	 * @return This FilterImpl instance (for method chaining).
+	 */
+	public Filter setParameter(String name, Object value);
+
+	/**
+	 * Set the named parameter's value list for this filter.  Used
+	 * in conjunction with IN-style filter criteria.
+	 *
+	 * @param name The parameter's name.
+	 * @param values The values to be expanded into an SQL IN list.
+	 * @return This FilterImpl instance (for method chaining).
+	 */
+	public Filter setParameterList(String name, Collection values);
+
+	/**
+	 * Set the named parameter's value list for this filter.  Used
+	 * in conjunction with IN-style filter criteria.
+	 *
+	 * @param name The parameter's name.
+	 * @param values The values to be expanded into an SQL IN list.
+	 * @return This FilterImpl instance (for method chaining).
+	 */
+	public Filter setParameterList(String name, Object[] values);
+
+	/**
+	 * Perform validation of the filter state.  This is used to verify the
+	 * state of the filter after its enablement and before its use.
+	 *
+	 * @throws HibernateException If the state is not currently valid.
+	 */
+	public void validate() throws HibernateException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/FlushMode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/FlushMode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/FlushMode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,92 @@
+//$Id: FlushMode.java 10469 2006-09-08 12:23:18Z steve.ebersole at jboss.com $
+package org.hibernate;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents a flushing strategy. The flush process synchronizes
+ * database state with session state by detecting state changes
+ * and executing SQL statements.
+ *
+ * @see Session#setFlushMode(FlushMode)
+ * @see Query#setFlushMode(FlushMode)
+ * @see Criteria#setFlushMode(FlushMode)
+ *
+ * @author Gavin King
+ */
+public final class FlushMode implements Serializable {
+	private static final Map INSTANCES = new HashMap();
+
+	private final int level;
+	private final String name;
+
+	private FlushMode(int level, String name) {
+		this.level = level;
+		this.name = name;
+	}
+
+	public String toString() {
+		return name;
+	}
+
+	/**
+	 * The {@link Session} is never flushed unless {@link Session#flush}
+	 * is explicitly called by the application. This mode is very
+	 * efficient for read only transactions.
+	 *
+	 * @deprecated use {@link #MANUAL} instead.
+	 */
+	public static final FlushMode NEVER = new FlushMode( 0, "NEVER" );
+
+	/**
+	 * The {@link Session} is only ever flushed when {@link Session#flush}
+	 * is explicitly called by the application. This mode is very
+	 * efficient for read only transactions.
+	 */
+	public static final FlushMode MANUAL = new FlushMode( 0, "MANUAL" );
+
+	/**
+	 * The {@link Session} is flushed when {@link Transaction#commit}
+	 * is called.
+	 */
+	public static final FlushMode COMMIT = new FlushMode(5, "COMMIT");
+
+	/**
+	 * The {@link Session} is sometimes flushed before query execution
+	 * in order to ensure that queries never return stale state. This
+	 * is the default flush mode.
+	 */
+	public static final FlushMode AUTO = new FlushMode(10, "AUTO");
+
+	/**
+	 * The {@link Session} is flushed before every query. This is
+	 * almost always unnecessary and inefficient.
+	 */
+	public static final FlushMode ALWAYS = new FlushMode(20, "ALWAYS");
+	
+	public boolean lessThan(FlushMode other) {
+		return this.level<other.level;
+	}
+
+	static {
+		INSTANCES.put( NEVER.name, NEVER );
+		INSTANCES.put( MANUAL.name, MANUAL );
+		INSTANCES.put( AUTO.name, AUTO );
+		INSTANCES.put( ALWAYS.name, ALWAYS );
+		INSTANCES.put( COMMIT.name, COMMIT );
+	}
+
+	public static boolean isManualFlushMode(FlushMode mode) {
+		return MANUAL.level == mode.level;
+	}
+
+	private Object readResolve() {
+		return INSTANCES.get( name );
+	}
+
+	public static FlushMode parse(String name) {
+		return ( FlushMode ) INSTANCES.get( name );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/Hibernate.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/Hibernate.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/Hibernate.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,454 @@
+//$Id: Hibernate.java 10009 2006-06-10 03:24:05Z epbernard $
+package org.hibernate;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.Serializable;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.util.Iterator;
+import java.util.Properties;
+
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.HibernateIterator;
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.intercept.FieldInterceptor;
+import org.hibernate.lob.BlobImpl;
+import org.hibernate.lob.ClobImpl;
+import org.hibernate.lob.SerializableBlob;
+import org.hibernate.lob.SerializableClob;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+import org.hibernate.type.AnyType;
+import org.hibernate.type.BigDecimalType;
+import org.hibernate.type.BigIntegerType;
+import org.hibernate.type.BinaryType;
+import org.hibernate.type.BlobType;
+import org.hibernate.type.BooleanType;
+import org.hibernate.type.ByteType;
+import org.hibernate.type.CalendarDateType;
+import org.hibernate.type.CalendarType;
+import org.hibernate.type.CharacterType;
+import org.hibernate.type.ClassType;
+import org.hibernate.type.ClobType;
+import org.hibernate.type.CompositeCustomType;
+import org.hibernate.type.CurrencyType;
+import org.hibernate.type.CustomType;
+import org.hibernate.type.DateType;
+import org.hibernate.type.DoubleType;
+import org.hibernate.type.FloatType;
+import org.hibernate.type.IntegerType;
+import org.hibernate.type.LocaleType;
+import org.hibernate.type.LongType;
+import org.hibernate.type.ManyToOneType;
+import org.hibernate.type.NullableType;
+import org.hibernate.type.SerializableType;
+import org.hibernate.type.ShortType;
+import org.hibernate.type.StringType;
+import org.hibernate.type.TextType;
+import org.hibernate.type.TimeType;
+import org.hibernate.type.TimeZoneType;
+import org.hibernate.type.TimestampType;
+import org.hibernate.type.TrueFalseType;
+import org.hibernate.type.Type;
+import org.hibernate.type.YesNoType;
+import org.hibernate.type.CharArrayType;
+import org.hibernate.type.WrapperBinaryType;
+import org.hibernate.type.CharacterArrayType;
+import org.hibernate.usertype.CompositeUserType;
+
+/**
+ * <ul>
+ * <li>Provides access to the full range of Hibernate built-in types. <tt>Type</tt>
+ * instances may be used to bind values to query parameters.
+ * <li>A factory for new <tt>Blob</tt>s and <tt>Clob</tt>s.
+ * <li>Defines static methods for manipulation of proxies.
+ * </ul>
+ *
+ * @author Gavin King
+ * @see java.sql.Clob
+ * @see java.sql.Blob
+ * @see org.hibernate.type.Type
+ */
+
+public final class Hibernate {
+
+	/**
+	 * Hibernate <tt>long</tt> type.
+	 */
+	public static final NullableType LONG = new LongType();
+	/**
+	 * Hibernate <tt>short</tt> type.
+	 */
+	public static final NullableType SHORT = new ShortType();
+	/**
+	 * Hibernate <tt>integer</tt> type.
+	 */
+	public static final NullableType INTEGER = new IntegerType();
+	/**
+	 * Hibernate <tt>byte</tt> type.
+	 */
+	public static final NullableType BYTE = new ByteType();
+	/**
+	 * Hibernate <tt>float</tt> type.
+	 */
+	public static final NullableType FLOAT = new FloatType();
+	/**
+	 * Hibernate <tt>double</tt> type.
+	 */
+	public static final NullableType DOUBLE = new DoubleType();
+	/**
+	 * Hibernate <tt>character</tt> type.
+	 */
+	public static final NullableType CHARACTER = new CharacterType();
+	/**
+	 * Hibernate <tt>string</tt> type.
+	 */
+	public static final NullableType STRING = new StringType();
+	/**
+	 * Hibernate <tt>time</tt> type.
+	 */
+	public static final NullableType TIME = new TimeType();
+	/**
+	 * Hibernate <tt>date</tt> type.
+	 */
+	public static final NullableType DATE = new DateType();
+	/**
+	 * Hibernate <tt>timestamp</tt> type.
+	 */
+	public static final NullableType TIMESTAMP = new TimestampType();
+	/**
+	 * Hibernate <tt>boolean</tt> type.
+	 */
+	public static final NullableType BOOLEAN = new BooleanType();
+	/**
+	 * Hibernate <tt>true_false</tt> type.
+	 */
+	public static final NullableType TRUE_FALSE = new TrueFalseType();
+	/**
+	 * Hibernate <tt>yes_no</tt> type.
+	 */
+	public static final NullableType YES_NO = new YesNoType();
+	/**
+	 * Hibernate <tt>big_decimal</tt> type.
+	 */
+	public static final NullableType BIG_DECIMAL = new BigDecimalType();
+	/**
+	 * Hibernate <tt>big_integer</tt> type.
+	 */
+	public static final NullableType BIG_INTEGER = new BigIntegerType();
+	/**
+	 * Hibernate <tt>binary</tt> type.
+	 */
+	public static final NullableType BINARY = new BinaryType();
+	/**
+	 * Hibernate <tt>wrapper-binary</tt> type.
+	 */
+	public static final NullableType WRAPPER_BINARY = new WrapperBinaryType();
+	/**
+	 * Hibernate char[] type.
+	 */
+	public static final NullableType CHAR_ARRAY = new CharArrayType();
+	/**
+	 * Hibernate Character[] type.
+	 */
+	public static final NullableType CHARACTER_ARRAY = new CharacterArrayType();
+	/**
+	 * Hibernate <tt>text</tt> type.
+	 */
+	public static final NullableType TEXT = new TextType();
+	/**
+	 * Hibernate <tt>blob</tt> type.
+	 */
+	public static final Type BLOB = new BlobType();
+	/**
+	 * Hibernate <tt>clob</tt> type.
+	 */
+	public static final Type CLOB = new ClobType();
+	/**
+	 * Hibernate <tt>calendar</tt> type.
+	 */
+	public static final NullableType CALENDAR = new CalendarType();
+	/**
+	 * Hibernate <tt>calendar_date</tt> type.
+	 */
+	public static final NullableType CALENDAR_DATE = new CalendarDateType();
+	/**
+	 * Hibernate <tt>locale</tt> type.
+	 */
+	public static final NullableType LOCALE = new LocaleType();
+	/**
+	 * Hibernate <tt>currency</tt> type.
+	 */
+	public static final NullableType CURRENCY = new CurrencyType();
+	/**
+	 * Hibernate <tt>timezone</tt> type.
+	 */
+	public static final NullableType TIMEZONE = new TimeZoneType();
+	/**
+	 * Hibernate <tt>class</tt> type.
+	 */
+	public static final NullableType CLASS = new ClassType();
+	/**
+	 * Hibernate <tt>serializable</tt> type.
+	 */
+	public static final NullableType SERIALIZABLE = new SerializableType( Serializable.class );
+	/**
+	 * Hibernate <tt>object</tt> type.
+	 */
+	public static final Type OBJECT = new AnyType();
+
+
+	/**
+	 * Cannot be instantiated.
+	 */
+	private Hibernate() {
+		throw new UnsupportedOperationException();
+	}
+
+	/**
+	 * A Hibernate <tt>serializable</tt> type.
+	 */
+	public static Type serializable(Class serializableClass) {
+		return new SerializableType( serializableClass );
+	}
+
+	/**
+	 * A Hibernate <tt>any</tt> type.
+	 *
+	 * @param metaType       a type mapping <tt>java.lang.Class</tt> to a single column
+	 * @param identifierType the entity identifier type
+	 * @return the Type
+	 */
+	public static Type any(Type metaType, Type identifierType) {
+		return new AnyType( metaType, identifierType );
+	}
+
+	/**
+	 * A Hibernate persistent object (entity) type.
+	 *
+	 * @param persistentClass a mapped entity class
+	 */
+	public static Type entity(Class persistentClass) {
+		// not really a many-to-one association *necessarily*
+		return new ManyToOneType( persistentClass.getName() );
+	}
+
+	/**
+	 * A Hibernate persistent object (entity) type.
+	 *
+	 * @param entityName a mapped entity class
+	 */
+	public static Type entity(String entityName) {
+		// not really a many-to-one association *necessarily*
+		return new ManyToOneType( entityName );
+	}
+
+	/**
+	 * A Hibernate custom type.
+	 *
+	 * @param userTypeClass a class that implements <tt>UserType</tt>
+	 */
+	public static Type custom(Class userTypeClass) throws HibernateException {
+		return custom( userTypeClass, null );
+	}
+
+	/**
+	 * A Hibernate parameterizable custom type.
+	 *
+	 * @param userTypeClass   a class that implements <tt>UserType and ParameterizableType</tt>
+	 * @param parameterNames  the names of the parameters passed to the type
+	 * @param parameterValues the values of the parameters passed to the type. They must match
+	 *                        up with the order and length of the parameterNames array.
+	 */
+	public static Type custom(Class userTypeClass, String[] parameterNames, String[] parameterValues)
+			throws HibernateException {
+		Properties parameters = new Properties();
+		for ( int i = 0; i < parameterNames.length; i++ ) {
+			parameters.setProperty( parameterNames[i], parameterValues[i] );
+		}
+		return custom( userTypeClass, parameters );
+	}
+
+	/**
+	 * A Hibernate parameterizable custom type.
+	 *
+	 * @param userTypeClass a class that implements <tt>UserType and ParameterizableType</tt>
+	 * @param parameters    the parameters as a collection of name/value pairs
+	 */
+	public static Type custom(Class userTypeClass, Properties parameters)
+			throws HibernateException {
+		if ( CompositeUserType.class.isAssignableFrom( userTypeClass ) ) {
+			CompositeCustomType type = new CompositeCustomType( userTypeClass, parameters );
+			return type;
+		}
+		else {
+			CustomType type = new CustomType( userTypeClass, parameters );
+			return type;
+		}
+	}
+
+	/**
+	 * Force initialization of a proxy or persistent collection.
+	 * <p/>
+	 * Note: This only ensures intialization of a proxy object or collection;
+	 * it is not guaranteed that the elements INSIDE the collection will be initialized/materialized.
+	 *
+	 * @param proxy a persistable object, proxy, persistent collection or <tt>null</tt>
+	 * @throws HibernateException if we can't initialize the proxy at this time, eg. the <tt>Session</tt> was closed
+	 */
+	public static void initialize(Object proxy) throws HibernateException {
+		if ( proxy == null ) {
+			return;
+		}
+		else if ( proxy instanceof HibernateProxy ) {
+			( ( HibernateProxy ) proxy ).getHibernateLazyInitializer().initialize();
+		}
+		else if ( proxy instanceof PersistentCollection ) {
+			( ( PersistentCollection ) proxy ).forceInitialization();
+		}
+	}
+
+	/**
+	 * Check if the proxy or persistent collection is initialized.
+	 *
+	 * @param proxy a persistable object, proxy, persistent collection or <tt>null</tt>
+	 * @return true if the argument is already initialized, or is not a proxy or collection
+	 */
+	public static boolean isInitialized(Object proxy) {
+		if ( proxy instanceof HibernateProxy ) {
+			return !( ( HibernateProxy ) proxy ).getHibernateLazyInitializer().isUninitialized();
+		}
+		else if ( proxy instanceof PersistentCollection ) {
+			return ( ( PersistentCollection ) proxy ).wasInitialized();
+		}
+		else {
+			return true;
+		}
+	}
+
+	/**
+	 * Get the true, underlying class of a proxied persistent class. This operation
+	 * will initialize a proxy by side-effect.
+	 *
+	 * @param proxy a persistable object or proxy
+	 * @return the true class of the instance
+	 * @throws HibernateException
+	 */
+	public static Class getClass(Object proxy) {
+		if ( proxy instanceof HibernateProxy ) {
+			return ( ( HibernateProxy ) proxy ).getHibernateLazyInitializer()
+					.getImplementation()
+					.getClass();
+		}
+		else {
+			return proxy.getClass();
+		}
+	}
+
+	/**
+	 * Create a new <tt>Blob</tt>. The returned object will be initially immutable.
+	 *
+	 * @param bytes a byte array
+	 * @return the Blob
+	 */
+	public static Blob createBlob(byte[] bytes) {
+		return new SerializableBlob( new BlobImpl( bytes ) );
+	}
+
+	/**
+	 * Create a new <tt>Blob</tt>. The returned object will be initially immutable.
+	 *
+	 * @param stream a binary stream
+	 * @param length the number of bytes in the stream
+	 * @return the Blob
+	 */
+	public static Blob createBlob(InputStream stream, int length) {
+		return new SerializableBlob( new BlobImpl( stream, length ) );
+	}
+
+	/**
+	 * Create a new <tt>Blob</tt>. The returned object will be initially immutable.
+	 *
+	 * @param stream a binary stream
+	 * @return the Blob
+	 * @throws IOException
+	 */
+	public static Blob createBlob(InputStream stream) throws IOException {
+		return new SerializableBlob( new BlobImpl( stream, stream.available() ) );
+	}
+
+	/**
+	 * Create a new <tt>Clob</tt>. The returned object will be initially immutable.
+	 *
+	 * @param string a <tt>String</tt>
+	 */
+	public static Clob createClob(String string) {
+		return new SerializableClob( new ClobImpl( string ) );
+	}
+
+	/**
+	 * Create a new <tt>Clob</tt>. The returned object will be initially immutable.
+	 *
+	 * @param reader a character stream
+	 * @param length the number of characters in the stream
+	 */
+	public static Clob createClob(Reader reader, int length) {
+		return new SerializableClob( new ClobImpl( reader, length ) );
+	}
+
+	/**
+	 * Close an <tt>Iterator</tt> created by <tt>iterate()</tt> immediately,
+	 * instead of waiting until the session is closed or disconnected.
+	 *
+	 * @param iterator an <tt>Iterator</tt> created by <tt>iterate()</tt>
+	 * @throws HibernateException
+	 * @see org.hibernate.Query#iterate
+	 * @see Query#iterate()
+	 */
+	public static void close(Iterator iterator) throws HibernateException {
+		if ( iterator instanceof HibernateIterator ) {
+			( ( HibernateIterator ) iterator ).close();
+		}
+		else {
+			throw new IllegalArgumentException( "not a Hibernate iterator" );
+		}
+	}
+
+	/**
+	 * Check if the property is initialized. If the named property does not exist
+	 * or is not persistent, this method always returns <tt>true</tt>.
+	 *
+	 * @param proxy The potential proxy
+	 * @param propertyName the name of a persistent attribute of the object
+	 * @return true if the named property of the object is not listed as uninitialized
+	 * @return false if the object is an uninitialized proxy, or the named property is uninitialized
+	 */
+	public static boolean isPropertyInitialized(Object proxy, String propertyName) {
+		
+		Object entity;
+		if ( proxy instanceof HibernateProxy ) {
+			LazyInitializer li = ( ( HibernateProxy ) proxy ).getHibernateLazyInitializer();
+			if ( li.isUninitialized() ) {
+				return false;
+			}
+			else {
+				entity = li.getImplementation();
+			}
+		}
+		else {
+			entity = proxy;
+		}
+
+		if ( FieldInterceptionHelper.isInstrumented( entity ) ) {
+			FieldInterceptor interceptor = FieldInterceptionHelper.extractFieldInterceptor( entity );
+			return interceptor == null || interceptor.isInitialized( propertyName );
+		}
+		else {
+			return true;
+		}
+		
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/HibernateException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/HibernateException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/HibernateException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+//$Id: HibernateException.java 5683 2005-02-12 03:09:22Z oneovthafew $
+package org.hibernate;
+
+import org.hibernate.exception.NestableRuntimeException;
+
+/**
+ * Any exception that occurs inside the persistence layer
+ * or JDBC driver. <tt>SQLException</tt>s are always wrapped
+ * by instances of <tt>JDBCException</tt>.
+ *
+ * @see JDBCException
+ * @author Gavin King
+ */
+
+public class HibernateException extends NestableRuntimeException {
+
+	public HibernateException(Throwable root) {
+		super(root);
+	}
+
+	public HibernateException(String string, Throwable root) {
+		super(string, root);
+	}
+
+	public HibernateException(String s) {
+		super(s);
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/InstantiationException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/InstantiationException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/InstantiationException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+//$Id: InstantiationException.java 6781 2005-05-14 17:27:57Z oneovthafew $
+package org.hibernate;
+
+/**
+ * Thrown if Hibernate can't instantiate an entity or component
+ * class at runtime.
+ *
+ * @author Gavin King
+ */
+
+public class InstantiationException extends HibernateException {
+
+	private final Class clazz;
+
+	public InstantiationException(String s, Class clazz, Throwable root) {
+		super(s, root);
+		this.clazz = clazz;
+	}
+
+	public InstantiationException(String s, Class clazz) {
+		super(s);
+		this.clazz = clazz;
+	}
+
+	public InstantiationException(String s, Class clazz, Exception e) {
+		super(s, e);
+		this.clazz = clazz;
+	}
+
+	public Class getPersistentClass() {
+		return clazz;
+	}
+
+	public String getMessage() {
+		return super.getMessage() + clazz.getName();
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/Interceptor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/Interceptor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/Interceptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,155 @@
+//$Id: Interceptor.java 7883 2005-08-12 20:03:07Z oneovthafew $
+package org.hibernate;
+
+import java.io.Serializable;
+import java.util.Iterator;
+
+import org.hibernate.type.Type;
+
+/**
+ * Allows user code to inspect and/or change property values.
+ * <br><br>
+ * Inspection occurs before property values are written and after they are read
+ * from the database.<br>
+ * <br>
+ * There might be a single instance of <tt>Interceptor</tt> for a <tt>SessionFactory</tt>, or a new instance
+ * might be specified for each <tt>Session</tt>. Whichever approach is used, the interceptor must be
+ * serializable if the <tt>Session</tt> is to be serializable. This means that <tt>SessionFactory</tt>-scoped
+ * interceptors should implement <tt>readResolve()</tt>.<br>
+ * <br>
+ * The <tt>Session</tt> may not be invoked from a callback (nor may a callback cause a collection or proxy to
+ * be lazily initialized).<br>
+ * <br>
+ * Instead of implementing this interface directly, it is usually better to extend <tt>EmptyInterceptor</tt>
+ * and override only the callback methods of interest.
+ *
+ * @see SessionFactory#openSession(Interceptor)
+ * @see org.hibernate.cfg.Configuration#setInterceptor(Interceptor)
+ * @see EmptyInterceptor
+ * @author Gavin King
+ */
+public interface Interceptor {
+	/**
+	 * Called just before an object is initialized. The interceptor may change the <tt>state</tt>, which will
+	 * be propagated to the persistent object. Note that when this method is called, <tt>entity</tt> will be
+	 * an empty uninitialized instance of the class.
+	 *
+	 * @return <tt>true</tt> if the user modified the <tt>state</tt> in any way.
+	 */
+	public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException;
+	/**
+	 * Called when an object is detected to be dirty, during a flush. The interceptor may modify the detected
+	 * <tt>currentState</tt>, which will be propagated to both the database and the persistent object.
+	 * Note that not all flushes end in actual synchronization with the database, in which case the
+	 * new <tt>currentState</tt> will be propagated to the object, but not necessarily (immediately) to
+	 * the database. It is strongly recommended that the interceptor <b>not</b> modify the <tt>previousState</tt>.
+	 *
+	 * @return <tt>true</tt> if the user modified the <tt>currentState</tt> in any way.
+	 */
+	public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) throws CallbackException;
+	/**
+	 * Called before an object is saved. The interceptor may modify the <tt>state</tt>, which will be used for
+	 * the SQL <tt>INSERT</tt> and propagated to the persistent object.
+	 *
+	 * @return <tt>true</tt> if the user modified the <tt>state</tt> in any way.
+	 */
+	public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException;
+	/**
+	 *  Called before an object is deleted. It is not recommended that the interceptor modify the <tt>state</tt>.
+	 */
+	public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException;
+	/**
+	 * Called before a collection is (re)created.
+	 */
+	public void onCollectionRecreate(Object collection, Serializable key) throws CallbackException;
+	/**
+	 * Called before a collection is deleted.
+	 */
+	public void onCollectionRemove(Object collection, Serializable key) throws CallbackException;
+	/**
+	 * Called before a collection is updated.
+	 */
+	public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException;
+	/**
+	 * Called before a flush
+	 */
+	public void preFlush(Iterator entities) throws CallbackException;
+	/**
+	 * Called after a flush that actually ends in execution of the SQL statements required to synchronize
+	 * in-memory state with the database.
+	 */
+	public void postFlush(Iterator entities) throws CallbackException;
+	/**
+	 * Called to distinguish between transient and detached entities. The return value determines the
+	 * state of the entity with respect to the current session.
+	 * <ul>
+	 * <li><tt>Boolean.TRUE</tt> - the entity is transient
+	 * <li><tt>Boolean.FALSE</tt> - the entity is detached
+	 * <li><tt>null</tt> - Hibernate uses the <tt>unsaved-value</tt> mapping and other heuristics to 
+	 * determine if the object is unsaved
+	 * </ul>
+	 * @param entity a transient or detached entity
+	 * @return Boolean or <tt>null</tt> to choose default behaviour
+	 */
+	public Boolean isTransient(Object entity);
+	/**
+	 * Called from <tt>flush()</tt>. The return value determines whether the entity is updated
+	 * <ul>
+	 * <li>an array of property indices - the entity is dirty
+	 * <li>an empty array - the entity is not dirty
+	 * <li><tt>null</tt> - use Hibernate's default dirty-checking algorithm
+	 * </ul>
+	 * @param entity a persistent entity
+	 * @return array of dirty property indices or <tt>null</tt> to choose default behaviour
+	 */
+	public int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types);
+	/**
+	 * Instantiate the entity class. Return <tt>null</tt> to indicate that Hibernate should use
+	 * the default constructor of the class. The identifier property of the returned instance
+	 * should be initialized with the given identifier.
+	 *
+	 * @param entityName the name of the entity
+	 * @param entityMode The type of entity instance to be returned.
+	 * @param id the identifier of the new instance
+	 * @return an instance of the class, or <tt>null</tt> to choose default behaviour
+	 */
+	public Object instantiate(String entityName, EntityMode entityMode, Serializable id) throws CallbackException;
+
+	/**
+	 * Get the entity name for a persistent or transient instance
+	 * @param object an entity instance
+	 * @return the name of the entity
+	 */
+	public String getEntityName(Object object) throws CallbackException;
+
+	/**
+	 * Get a fully loaded entity instance that is cached externally
+	 * @param entityName the name of the entity
+	 * @param id the instance identifier
+	 * @return a fully initialized entity
+	 * @throws CallbackException
+	 */
+	public Object getEntity(String entityName, Serializable id) throws CallbackException;
+	
+	/**
+	 * Called when a Hibernate transaction is begun via the Hibernate <tt>Transaction</tt> 
+	 * API. Will not be called if transactions are being controlled via some other 
+	 * mechanism (CMT, for example).
+	 */
+	public void afterTransactionBegin(Transaction tx);
+	/**
+	 * Called before a transaction is committed (but not before rollback).
+	 */
+	public void beforeTransactionCompletion(Transaction tx);
+	/**
+	 * Called after a transaction is committed or rolled back.
+	 */
+	public void afterTransactionCompletion(Transaction tx);
+
+	/**
+	 * Called when sql string is being prepared. 
+	 * @param sql sql to be prepared
+	 * @return original or modified sql
+	 */
+	public String onPrepareStatement(String sql);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/InvalidMappingException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/InvalidMappingException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/InvalidMappingException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+package org.hibernate;
+
+/**
+ * Thrown when a mapping is found to be invalid.
+ * Similar to MappingException, but this contains more info about the path and type of mapping (e.g. file, resource or url)
+ * 
+ * @author Max Rydahl Andersen
+ *
+ */
+public class InvalidMappingException extends MappingException {
+
+	private final String path;
+	private final String type;
+
+	public InvalidMappingException(String customMessage, String type, String path, Throwable cause) {
+		super(customMessage, cause);
+		this.type=type;
+		this.path=path;
+	}
+	
+	public InvalidMappingException(String customMessage, String type, String path) {
+		super(customMessage);
+		this.type=type;
+		this.path=path;
+	}
+	
+	public InvalidMappingException(String type, String path) {
+		this("Could not parse mapping document from " + type + (path==null?"":" " + path), type, path);
+	}
+
+	public InvalidMappingException(String type, String path, Throwable cause) {
+		this("Could not parse mapping document from " + type + (path==null?"":" " + path), type, path, cause);		
+	}
+
+	public String getType() {
+		return type;
+	}
+	
+	public String getPath() {
+		return path;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/JDBCException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/JDBCException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/JDBCException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+//$Id: JDBCException.java 4626 2004-09-27 15:24:38Z oneovthafew $
+package org.hibernate;
+
+import java.sql.SQLException;
+
+
+/**
+ * Wraps an <tt>SQLException</tt>. Indicates that an exception
+ * occurred during a JDBC call.
+ *
+ * @see java.sql.SQLException
+ * @author Gavin King
+ */
+public class JDBCException extends HibernateException {
+
+	private SQLException sqle;
+	private String sql;
+
+	public JDBCException(String string, SQLException root) {
+		super(string, root);
+		sqle=root;
+	}
+
+	public JDBCException(String string, SQLException root, String sql) {
+		this(string, root);
+		this.sql = sql;
+	}
+
+	/**
+	 * Get the SQLState of the underlying <tt>SQLException</tt>.
+	 * @see java.sql.SQLException
+	 * @return String
+	 */
+	public String getSQLState() {
+		return sqle.getSQLState();
+	}
+
+	/**
+	 * Get the <tt>errorCode</tt> of the underlying <tt>SQLException</tt>.
+	 * @see java.sql.SQLException
+	 * @return int the error code
+	 */
+	public int getErrorCode() {
+		return sqle.getErrorCode();
+	}
+
+	/**
+	 * Get the underlying <tt>SQLException</tt>.
+	 * @return SQLException
+	 */
+	public SQLException getSQLException() {
+		return sqle;
+	}
+	
+	/**
+	 * Get the actual SQL statement that caused the exception
+	 * (may be null)
+	 */
+	public String getSQL() {
+		return sql;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/LazyInitializationException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/LazyInitializationException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/LazyInitializationException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+//$Id: LazyInitializationException.java 4458 2004-08-29 09:59:17Z oneovthafew $
+package org.hibernate;
+
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Indicates access to unfetched data outside of a session context.
+ * For example, when an uninitialized proxy or collection is accessed 
+ * after the session was closed.
+ *
+ * @see Hibernate#initialize(java.lang.Object)
+ * @see Hibernate#isInitialized(java.lang.Object)
+ * @author Gavin King
+ */
+public class LazyInitializationException extends HibernateException {
+
+	public LazyInitializationException(String msg) {
+		super(msg);
+		LogFactory.getLog(LazyInitializationException.class).error(msg, this);
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/LockMode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/LockMode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/LockMode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,106 @@
+//$Id: LockMode.java 9581 2006-03-09 15:50:15Z epbernard $
+package org.hibernate;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Instances represent a lock mode for a row of a relational
+ * database table. It is not intended that users spend much
+ * time worrying about locking since Hibernate usually
+ * obtains exactly the right lock level automatically.
+ * Some "advanced" users may wish to explicitly specify lock
+ * levels.
+ *
+ * @see Session#lock(Object,LockMode)
+ * @author Gavin King
+ */
+public final class LockMode implements Serializable {
+	private final int level;
+	private final String name;
+	private static final Map INSTANCES = new HashMap();
+
+	private LockMode(int level, String name) {
+		this.level=level;
+		this.name=name;
+	}
+	public String toString() {
+		return name;
+	}
+	/**
+	 * Check if this lock mode is more restrictive than the given lock mode.
+	 *
+	 * @param mode LockMode to check
+	 * @return true if this lock mode is more restrictive than given lock mode
+	 */
+	public boolean greaterThan(LockMode mode) {
+		return level > mode.level;
+	}
+	/**
+	 * Check if this lock mode is less restrictive than the given lock mode.
+	 *
+	 * @param mode LockMode to check
+	 * @return true if this lock mode is less restrictive than given lock mode
+	 */
+	public boolean lessThan(LockMode mode) {
+		return level < mode.level;
+	}
+	/**
+	 * No lock required. If an object is requested with this lock
+	 * mode, a <tt>READ</tt> lock will be obtained if it is
+	 * necessary to actually read the state from the database,
+	 * rather than pull it from a cache.<br>
+	 * <br>
+	 * This is the "default" lock mode.
+	 */
+	public static final LockMode NONE = new LockMode(0, "NONE");
+	/**
+	 * A shared lock. Objects in this lock mode were read from
+	 * the database in the current transaction, rather than being
+	 * pulled from a cache.
+	 */
+	public static final LockMode READ = new LockMode(5, "READ");
+	/**
+	 * An upgrade lock. Objects loaded in this lock mode are
+	 * materialized using an SQL <tt>select ... for update</tt>.
+	 */
+	public static final LockMode UPGRADE = new LockMode(10, "UPGRADE");
+	/**
+	 * Attempt to obtain an upgrade lock, using an Oracle-style
+	 * <tt>select for update nowait</tt>. The semantics of
+	 * this lock mode, once obtained, are the same as
+	 * <tt>UPGRADE</tt>.
+	 */
+	public static final LockMode UPGRADE_NOWAIT = new LockMode(10, "UPGRADE_NOWAIT");
+	/**
+	 * A <tt>WRITE</tt> lock is obtained when an object is updated
+	 * or inserted.   This lock mode is for internal use only and is
+	 * not a valid mode for <tt>load()</tt> or <tt>lock()</tt> (both
+	 * of which throw exceptions if WRITE is specified).
+	 */
+	public static final LockMode WRITE = new LockMode(10, "WRITE");
+
+	/**
+	 * Similiar to {@link #UPGRADE} except that, for versioned entities,
+	 * it results in a forced version increment.
+	 */
+	public static final LockMode FORCE = new LockMode( 15, "FORCE" );
+
+	static {
+		INSTANCES.put( NONE.name, NONE );
+		INSTANCES.put( READ.name, READ );
+		INSTANCES.put( UPGRADE.name, UPGRADE );
+		INSTANCES.put( UPGRADE_NOWAIT.name, UPGRADE_NOWAIT );
+		INSTANCES.put( WRITE.name, WRITE );
+		INSTANCES.put( FORCE.name, FORCE );
+	}
+
+	private Object readResolve() {
+		return parse( name );
+	}
+
+	public static LockMode parse(String name) {
+		return ( LockMode ) INSTANCES.get(name);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/MappingException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/MappingException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/MappingException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+//$Id: MappingException.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate;
+
+/**
+ * An exception that usually occurs at configuration time, rather
+ * than runtime, as a result of something screwy in the O-R mappings.
+ *
+ * @author Gavin King
+ */
+
+public class MappingException extends HibernateException {
+
+	public MappingException(String msg, Throwable root) {
+		super( msg, root );
+	}
+
+	public MappingException(Throwable root) {
+		super(root);
+	}
+
+	public MappingException(String s) {
+		super(s);
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/MappingNotFoundException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/MappingNotFoundException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/MappingNotFoundException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+package org.hibernate;
+
+/**
+ * Thrown when a resource for a mapping could not be found.
+ * 
+ * @author Max Rydahl Andersen
+ *
+ */
+public class MappingNotFoundException extends MappingException {
+
+	private final String path;
+	private final String type;
+
+	public MappingNotFoundException(String customMessage, String type, String path, Throwable cause) {
+		super(customMessage, cause);
+		this.type=type;
+		this.path=path;
+	}
+	
+	public MappingNotFoundException(String customMessage, String type, String path) {
+		super(customMessage);
+		this.type=type;
+		this.path=path;
+	}
+	
+	public MappingNotFoundException(String type, String path) {
+		this(type + ": " + path + " not found", type, path);
+	}
+
+	public MappingNotFoundException(String type, String path, Throwable cause) {
+		this(type + ": " + path + " not found", type, path, cause);
+	}
+
+	public String getType() {
+		return type;
+	}
+	
+	public String getPath() {
+		return path;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/NonUniqueObjectException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/NonUniqueObjectException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/NonUniqueObjectException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+//$Id: NonUniqueObjectException.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate;
+
+import java.io.Serializable;
+
+import org.hibernate.pretty.MessageHelper;
+
+/**
+ * This exception is thrown when an operation would
+ * break session-scoped identity. This occurs if the
+ * user tries to associate two different instances of
+ * the same Java class with a particular identifier,
+ * in the scope of a single <tt>Session</tt>.
+ *
+ * @author Gavin King
+ */
+public class NonUniqueObjectException extends HibernateException {
+	private final Serializable identifier;
+	private final String entityName;
+
+	public NonUniqueObjectException(String message, Serializable id, String clazz) {
+		super(message);
+		this.entityName = clazz;
+		this.identifier = id;
+	}
+
+	public NonUniqueObjectException(Serializable id, String clazz) {
+		this("a different object with the same identifier value was already associated with the session", id, clazz);
+	}
+
+	public Serializable getIdentifier() {
+		return identifier;
+	}
+
+	public String getMessage() {
+		return super.getMessage() + ": " +
+			MessageHelper.infoString(entityName, identifier);
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/NonUniqueResultException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/NonUniqueResultException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/NonUniqueResultException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+//$Id: NonUniqueResultException.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate;
+
+/**
+ * Thrown when the application calls <tt>Query.uniqueResult()</tt> and
+ * the query returned more than one result. Unlike all other Hibernate
+ * exceptions, this one is recoverable!
+ *
+ * @author Gavin King
+ */
+public class NonUniqueResultException extends HibernateException {
+
+	public NonUniqueResultException(int resultCount) {
+		super( "query did not return a unique result: " + resultCount );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/ObjectDeletedException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/ObjectDeletedException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/ObjectDeletedException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+//$Id: ObjectDeletedException.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate;
+
+import java.io.Serializable;
+
+/**
+ * Thrown when the user tries to do something illegal with a deleted
+ * object.
+ *
+ * @author Gavin King
+ */
+public class ObjectDeletedException extends UnresolvableObjectException {
+
+	public ObjectDeletedException(String message, Serializable identifier, String clazz) {
+		super(message, identifier, clazz);
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/ObjectNotFoundException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/ObjectNotFoundException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/ObjectNotFoundException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+//$Id: ObjectNotFoundException.java 9855 2006-05-02 18:55:45Z steve.ebersole at jboss.com $
+package org.hibernate;
+
+import java.io.Serializable;
+
+/**
+ * Thrown when <tt>Session.load()</tt> fails to select a row with
+ * the given primary key (identifier value). This exception might not
+ * be thrown when <tt>load()</tt> is called, even if there was no
+ * row on the database, because <tt>load()</tt> returns a proxy if
+ * possible. Applications should use <tt>Session.get()</tt> to test if
+ * a row exists in the database.<br>
+ * <br> 
+ * Like all Hibernate exceptions, this exception is considered 
+ * unrecoverable.
+ *
+ * @author Gavin King
+ */
+public class ObjectNotFoundException extends UnresolvableObjectException {
+
+	public ObjectNotFoundException(Serializable identifier, String clazz) {
+		super(identifier, clazz);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/PersistentObjectException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/PersistentObjectException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/PersistentObjectException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+//$Id: PersistentObjectException.java 6877 2005-05-23 15:00:25Z oneovthafew $
+package org.hibernate;
+
+/**
+ * Thrown when the user passes a persistent instance to a <tt>Session</tt>
+ * method that expects a transient instance.
+ *
+ * @author Gavin King
+ */
+public class PersistentObjectException extends HibernateException {
+	
+	public PersistentObjectException(String s) {
+		super(s);
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/PropertyAccessException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/PropertyAccessException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/PropertyAccessException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+//$Id: PropertyAccessException.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate;
+
+import org.hibernate.util.StringHelper;
+
+/**
+ * A problem occurred accessing a property of an instance of a
+ * persistent class by reflection, or via CGLIB. There are a
+ * number of possible underlying causes, including
+ * <ul>
+ * <li>failure of a security check
+ * <li>an exception occurring inside the getter or setter method
+ * <li>a nullable database column was mapped to a primitive-type property
+ * <li>the Hibernate type was not castable to the property type (or vice-versa)
+ * </ul>
+ * @author Gavin King
+ */
+public class PropertyAccessException extends HibernateException {
+
+	private final Class persistentClass;
+	private final String propertyName;
+	private final boolean wasSetter;
+
+	public PropertyAccessException(Throwable root, String s, boolean wasSetter, Class persistentClass, String propertyName) {
+		super(s, root);
+		this.persistentClass = persistentClass;
+		this.wasSetter = wasSetter;
+		this.propertyName = propertyName;
+	}
+
+	public Class getPersistentClass() {
+		return persistentClass;
+	}
+
+	public String getPropertyName() {
+		return propertyName;
+	}
+
+	public String getMessage() {
+		return super.getMessage() +
+		( wasSetter ? " setter of " : " getter of ") +
+		StringHelper.qualify( persistentClass.getName(), propertyName );
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/PropertyNotFoundException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/PropertyNotFoundException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/PropertyNotFoundException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: PropertyNotFoundException.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate;
+
+/**
+ * Indicates that an expected getter or setter method could not be
+ * found on a class.
+ *
+ * @author Gavin King
+ */
+public class PropertyNotFoundException extends MappingException {
+
+	public PropertyNotFoundException(String s) {
+		super(s);
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/PropertyValueException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/PropertyValueException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/PropertyValueException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,56 @@
+//$Id: PropertyValueException.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate;
+
+import org.hibernate.util.StringHelper;
+
+/**
+ * Thrown when the (illegal) value of a property can not be persisted.
+ * There are two main causes:
+ * <ul>
+ * <li>a property declared <tt>not-null="true"</tt> is null
+ * <li>an association references an unsaved transient instance
+ * </ul>
+ * @author Gavin King
+ */
+public class PropertyValueException extends HibernateException {
+
+	private final String entityName;
+	private final String propertyName;
+
+	public PropertyValueException(String s, String entityName, String propertyName) {
+		super(s);
+		this.entityName = entityName;
+		this.propertyName = propertyName;
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public String getPropertyName() {
+		return propertyName;
+	}
+
+	public String getMessage() {
+		return super.getMessage() + ": " +
+			StringHelper.qualify(entityName, propertyName);
+	}
+
+	/**
+	 * Return a well formed property path.
+	 * Basicaly, it will return parent.child
+	 *
+	 * @param parent parent in path
+	 * @param child child in path
+	 * @return parent-child path
+	 */
+	public static String buildPropertyPath(String parent, String child) {
+		return new StringBuffer(parent).append('.').append(child).toString();
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/Query.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/Query.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/Query.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,386 @@
+//$Id: Query.java 10591 2006-10-17 08:57:26Z max.andersen at jboss.com $
+package org.hibernate;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.type.Type;
+
+/**
+ * An object-oriented representation of a Hibernate query. A <tt>Query</tt>
+ * instance is obtained by calling <tt>Session.createQuery()</tt>. This
+ * interface exposes some extra functionality beyond that provided by
+ * <tt>Session.iterate()</tt> and <tt>Session.find()</tt>:
+ * <ul>
+ * <li>a particular page of the result set may be selected by calling <tt>
+ * setMaxResults(), setFirstResult()</tt>
+ * <li>named query parameters may be used
+ * <li>the results may be returned as an instance of <tt>ScrollableResults</tt>
+ * </ul>
+ * <br>
+ * Named query parameters are tokens of the form <tt>:name</tt> in the
+ * query string. A value is bound to the <tt>integer</tt> parameter
+ * <tt>:foo</tt> by calling<br>
+ * <br>
+ * <tt>setParameter("foo", foo, Hibernate.INTEGER);</tt><br>
+ * <br>
+ * for example. A name may appear multiple times in the query string.<br>
+ * <br>
+ * JDBC-style <tt>?</tt> parameters are also supported. To bind a
+ * value to a JDBC-style parameter use a set method that accepts an
+ * <tt>int</tt> positional argument (numbered from zero, contrary
+ * to JDBC).<br>
+ * <br>
+ * You may not mix and match JDBC-style parameters and named parameters
+ * in the same query.<br>
+ * <br>
+ * Queries are executed by calling <tt>list()</tt>, <tt>scroll()</tt> or
+ * <tt>iterate()</tt>. A query may be re-executed by subsequent invocations.
+ * Its lifespan is, however, bounded by the lifespan of the <tt>Session</tt>
+ * that created it.<br>
+ * <br>
+ * Implementors are not intended to be threadsafe.
+ *
+ * @see org.hibernate.Session#createQuery(java.lang.String)
+ * @see org.hibernate.ScrollableResults
+ * @author Gavin King
+ */
+public interface Query {
+	/**
+	 * Get the query string.
+	 *
+	 * @return the query string
+	 */
+	public String getQueryString();
+	/**
+	 * Return the Hibernate types of the query result set.
+	 * @return an array of types
+	 */
+	public Type[] getReturnTypes() throws HibernateException;
+	/**
+	 * Return the HQL select clause aliases (if any)
+	 * @return an array of aliases as strings
+	 */
+	public String[] getReturnAliases() throws HibernateException;
+	/**
+	 * Return the names of all named parameters of the query.
+	 * @return the parameter names, in no particular order
+	 */
+	public String[] getNamedParameters() throws HibernateException;
+	/**
+	 * Return the query results as an <tt>Iterator</tt>. If the query
+	 * contains multiple results pre row, the results are returned in
+	 * an instance of <tt>Object[]</tt>.<br>
+	 * <br>
+	 * Entities returned as results are initialized on demand. The first
+	 * SQL query returns identifiers only.<br>
+	 *
+	 * @return the result iterator
+	 * @throws HibernateException
+	 */
+	public Iterator iterate() throws HibernateException;
+	/**
+	 * Return the query results as <tt>ScrollableResults</tt>. The
+	 * scrollability of the returned results depends upon JDBC driver
+	 * support for scrollable <tt>ResultSet</tt>s.<br>
+	 *
+	 * @see ScrollableResults
+	 * @return the result iterator
+	 * @throws HibernateException
+	 */
+	public ScrollableResults scroll() throws HibernateException;
+	/**
+	 * Return the query results as <tt>ScrollableResults</tt>. The
+	 * scrollability of the returned results depends upon JDBC driver
+	 * support for scrollable <tt>ResultSet</tt>s.<br>
+	 *
+	 * @see ScrollableResults
+	 * @see ScrollMode
+	 * @return the result iterator
+	 * @throws HibernateException
+	 */
+	public ScrollableResults scroll(ScrollMode scrollMode) throws HibernateException;
+	/**
+	 * Return the query results as a <tt>List</tt>. If the query contains
+	 * multiple results pre row, the results are returned in an instance
+	 * of <tt>Object[]</tt>.
+	 *
+	 * @return the result list
+	 * @throws HibernateException
+	 */
+	public List list() throws HibernateException;
+	/**
+	 * Convenience method to return a single instance that matches
+	 * the query, or null if the query returns no results.
+	 *
+	 * @return the single result or <tt>null</tt>
+	 * @throws NonUniqueResultException if there is more than one matching result
+	 */
+	public Object uniqueResult() throws HibernateException;
+
+	/**
+	 * Execute the update or delete statement.
+	 * </p>
+	 * The semantics are compliant with the ejb3 Query.executeUpdate()
+	 * method.
+	 *
+	 * @return The number of entities updated or deleted.
+	 * @throws HibernateException
+	 */
+	public int executeUpdate() throws HibernateException;
+
+	/**
+	 * Set the maximum number of rows to retrieve. If not set,
+	 * there is no limit to the number of rows retrieved.
+	 * @param maxResults the maximum number of rows
+	 */
+	public Query setMaxResults(int maxResults);
+	/**
+	 * Set the first row to retrieve. If not set, rows will be
+	 * retrieved beginnning from row <tt>0</tt>.
+	 * @param firstResult a row number, numbered from <tt>0</tt>
+	 */
+	public Query setFirstResult(int firstResult);
+	
+	/**
+	 * Entities retrieved by this query will be loaded in 
+	 * a read-only mode where Hibernate will never dirty-check
+	 * them or make changes persistent.
+	 *
+	 */
+	public Query setReadOnly(boolean readOnly);
+
+	/**
+	 * Enable caching of this query result set.
+	 * @param cacheable Should the query results be cacheable?
+	 */
+	public Query setCacheable(boolean cacheable);
+
+	/**
+	 * Set the name of the cache region.
+	 * @param cacheRegion the name of a query cache region, or <tt>null</tt>
+	 * for the default query cache
+	 */
+	public Query setCacheRegion(String cacheRegion);
+
+	/**
+	 * Set a timeout for the underlying JDBC query.
+	 * @param timeout the timeout in seconds
+	 */
+	public Query setTimeout(int timeout);
+	/**
+	 * Set a fetch size for the underlying JDBC query.
+	 * @param fetchSize the fetch size
+	 */
+	public Query setFetchSize(int fetchSize);
+
+	/**
+	 * Set the lockmode for the objects idententified by the
+	 * given alias that appears in the <tt>FROM</tt> clause.
+	 * @param alias a query alias, or <tt>this</tt> for a collection filter
+	 */
+	public Query setLockMode(String alias, LockMode lockMode);
+
+	/**
+	 * Add a comment to the generated SQL.
+	 * @param comment a human-readable string
+	 */
+	public Query setComment(String comment);
+	
+	/**
+	 * Override the current session flush mode, just for
+	 * this query.
+	 * @see org.hibernate.FlushMode
+	 */
+	public Query setFlushMode(FlushMode flushMode);
+
+	/**
+	 * Override the current session cache mode, just for
+	 * this query.
+	 * @see org.hibernate.CacheMode
+	 */
+	public Query setCacheMode(CacheMode cacheMode);
+
+	/**
+	 * Bind a value to a JDBC-style query parameter.
+	 * @param position the position of the parameter in the query
+	 * string, numbered from <tt>0</tt>.
+	 * @param val the possibly-null parameter value
+	 * @param type the Hibernate type
+	 */
+	public Query setParameter(int position, Object val, Type type);
+	/**
+	 * Bind a value to a named query parameter.
+	 * @param name the name of the parameter
+	 * @param val the possibly-null parameter value
+	 * @param type the Hibernate type
+	 */
+	public Query setParameter(String name, Object val, Type type);
+
+	/**
+	 * Bind a value to a JDBC-style query parameter. The Hibernate type of the parameter is
+	 * first detected via the usage/position in the query and if not sufficient secondly 
+	 * guessed from the class of the given object.
+	 * @param position the position of the parameter in the query
+	 * string, numbered from <tt>0</tt>.
+	 * @param val the non-null parameter value
+	 * @throws org.hibernate.HibernateException if no type could be determined
+	 */
+	public Query setParameter(int position, Object val) throws HibernateException;
+	/**
+	 * Bind a value to a named query parameter. The Hibernate type of the parameter is
+	 * first detected via the usage/position in the query and if not sufficient secondly 
+	 * guessed from the class of the given object.
+	 * @param name the name of the parameter
+	 * @param val the non-null parameter value
+	 * @throws org.hibernate.HibernateException if no type could be determined
+	 */
+	public Query setParameter(String name, Object val) throws HibernateException;
+	
+	/**
+	 * Bind values and types to positional parameters.
+	 */
+	public Query setParameters(Object[] values, Type[] types) throws HibernateException;
+
+	/**
+	 * Bind multiple values to a named query parameter. This is useful for binding
+	 * a list of values to an expression such as <tt>foo.bar in (:value_list)</tt>.
+	 * @param name the name of the parameter
+	 * @param vals a collection of values to list
+	 * @param type the Hibernate type of the values
+	 */
+	public Query setParameterList(String name, Collection vals, Type type) throws HibernateException;
+
+	/**
+	 * Bind multiple values to a named query parameter. The Hibernate type of the parameter is
+	 * first detected via the usage/position in the query and if not sufficient secondly 
+	 * guessed from the class of the first object in the collection. This is useful for binding a list of values
+	 * to an expression such as <tt>foo.bar in (:value_list)</tt>.
+	 * @param name the name of the parameter
+	 * @param vals a collection of values to list
+	 */
+	public Query setParameterList(String name, Collection vals) throws HibernateException;
+
+	/**
+	 * Bind multiple values to a named query parameter. This is useful for binding
+	 * a list of values to an expression such as <tt>foo.bar in (:value_list)</tt>.
+	 * @param name the name of the parameter
+	 * @param vals a collection of values to list
+	 * @param type the Hibernate type of the values
+	 */
+	public Query setParameterList(String name, Object[] vals, Type type) throws HibernateException;
+
+	/**
+	 * Bind multiple values to a named query parameter. The Hibernate type of the parameter is
+	 * first detected via the usage/position in the query and if not sufficient secondly 
+	 * guessed from the class of the first object in the array. This is useful for binding a list of values
+	 * to an expression such as <tt>foo.bar in (:value_list)</tt>.
+	 * @param name the name of the parameter
+	 * @param vals a collection of values to list
+	 */
+	public Query setParameterList(String name, Object[] vals) throws HibernateException;
+
+	/**
+	 * Bind the property values of the given bean to named parameters of the query,
+	 * matching property names with parameter names and mapping property types to
+	 * Hibernate types using hueristics.
+	 * @param bean any JavaBean or POJO
+	 */	
+	public Query setProperties(Object bean) throws HibernateException;
+	
+	/**
+	 * Bind the values of the given Map for each named parameters of the query,
+	 * matching key names with parameter names and mapping value types to
+	 * Hibernate types using hueristics.
+	 * @param bean a java.util.Map
+	 */
+	public Query setProperties(Map bean) throws HibernateException;
+
+	public Query setString(int position, String val);
+	public Query setCharacter(int position, char val);
+	public Query setBoolean(int position, boolean val);
+	public Query setByte(int position, byte val);
+	public Query setShort(int position, short val);
+	public Query setInteger(int position, int val);
+	public Query setLong(int position, long val);
+	public Query setFloat(int position, float val);
+	public Query setDouble(int position, double val);
+	public Query setBinary(int position, byte[] val);
+	public Query setText(int position, String val);
+	public Query setSerializable(int position, Serializable val);
+	public Query setLocale(int position, Locale locale);
+	public Query setBigDecimal(int position, BigDecimal number);
+	public Query setBigInteger(int position, BigInteger number);
+
+	public Query setDate(int position, Date date);
+	public Query setTime(int position, Date date);
+	public Query setTimestamp(int position, Date date);
+
+	public Query setCalendar(int position, Calendar calendar);
+	public Query setCalendarDate(int position, Calendar calendar);
+
+	public Query setString(String name, String val);
+	public Query setCharacter(String name, char val);
+	public Query setBoolean(String name, boolean val);
+	public Query setByte(String name, byte val);
+	public Query setShort(String name, short val);
+	public Query setInteger(String name, int val);
+	public Query setLong(String name, long val);
+	public Query setFloat(String name, float val);
+	public Query setDouble(String name, double val);
+	public Query setBinary(String name, byte[] val);
+	public Query setText(String name, String val);
+	public Query setSerializable(String name, Serializable val);
+	public Query setLocale(String name, Locale locale);
+	public Query setBigDecimal(String name, BigDecimal number);
+	public Query setBigInteger(String name, BigInteger number);
+
+	public Query setDate(String name, Date date);
+	public Query setTime(String name, Date date);
+	public Query setTimestamp(String name, Date date);
+
+	public Query setCalendar(String name, Calendar calendar);
+	public Query setCalendarDate(String name, Calendar calendar);
+
+	/**
+	 * Bind an instance of a mapped persistent class to a JDBC-style query parameter.
+	 * @param position the position of the parameter in the query
+	 * string, numbered from <tt>0</tt>.
+	 * @param val a non-null instance of a persistent class
+	 */
+	public Query setEntity(int position, Object val); // use setParameter for null values
+
+	/**
+	 * Bind an instance of a mapped persistent class to a named query parameter.
+	 * @param name the name of the parameter
+	 * @param val a non-null instance of a persistent class
+	 */
+	public Query setEntity(String name, Object val); // use setParameter for null values
+	
+	
+	/**
+	 * Set a strategy for handling the query results. This can be used to change
+	 * "shape" of the query result.
+	 *
+	 * @param transformer The transformer to apply
+	 * @return this (for method chaining)	
+	 */
+	public Query setResultTransformer(ResultTransformer transformer);
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/QueryException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/QueryException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/QueryException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+//$Id: QueryException.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate;
+
+/**
+ * A problem occurred translating a Hibernate query to SQL
+ * due to invalid query syntax, etc.
+ */
+public class QueryException extends HibernateException {
+
+	private String queryString;
+
+	public QueryException(String message) {
+		super(message);
+	}
+	public QueryException(String message, Throwable e) {
+		super(message, e);
+	}
+
+	public QueryException(String message, String queryString) {
+		super(message);
+		this.queryString = queryString;
+	}
+
+	public QueryException(Exception e) {
+		super(e);
+	}
+	public String getQueryString() {
+		return queryString;
+	}
+
+	public void setQueryString(String queryString) {
+		this.queryString = queryString;
+	}
+
+	public String getMessage() {
+		String msg = super.getMessage();
+		if ( queryString!=null ) msg += " [" + queryString + ']';
+		return msg;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/QueryParameterException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/QueryParameterException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/QueryParameterException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: $
+package org.hibernate;
+
+/**
+ * Parameter invalid or not found in the query
+ * 
+ * @author Emmanuel Bernard
+ */
+public class QueryParameterException extends QueryException {
+
+	public QueryParameterException(Exception e) {
+		super( e );
+	}
+
+	public QueryParameterException(String message) {
+		super( message );
+	}
+
+	public QueryParameterException(String message, Throwable e) {
+		super( message, e );
+	}
+
+	public QueryParameterException(String message, String queryString) {
+		super( message, queryString );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/ReplicationMode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/ReplicationMode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/ReplicationMode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+//$Id: ReplicationMode.java 5060 2004-12-24 03:11:05Z oneovthafew $
+package org.hibernate;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hibernate.type.VersionType;
+
+/**
+ * Represents a replication strategy.
+ *
+ * @see Session#replicate(Object, ReplicationMode)
+ * @author Gavin King
+ */
+public abstract class ReplicationMode implements Serializable {
+	private final String name;
+	private static final Map INSTANCES = new HashMap();
+
+	public ReplicationMode(String name) {
+		this.name=name;
+	}
+	public String toString() {
+		return name;
+	}
+	public abstract boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType);
+	/**
+	 * Throw an exception when a row already exists.
+	 */
+	public static final ReplicationMode EXCEPTION = new ReplicationMode("EXCEPTION") {
+		public boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType) {
+			throw new AssertionFailure("should not be called");
+		}
+	};
+	/**
+	 * Ignore replicated entities when a row already exists.
+	 */
+	public static final ReplicationMode IGNORE = new ReplicationMode("IGNORE") {
+		public boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType) {
+			return false;
+		}
+	};
+	/**
+	 * Overwrite existing rows when a row already exists.
+	 */
+	public static final ReplicationMode OVERWRITE = new ReplicationMode("OVERWRITE") {
+		public boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType) {
+			return true;
+		}
+	};
+	/**
+	 * When a row already exists, choose the latest version.
+	 */
+	public static final ReplicationMode LATEST_VERSION = new ReplicationMode("LATEST_VERSION") {
+		public boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType) {
+			if (versionType==null) return true; //always overwrite nonversioned data
+			return versionType.getComparator().compare(currentVersion, newVersion) <= 0;
+		}
+	};
+
+	static {
+		INSTANCES.put( LATEST_VERSION.name, LATEST_VERSION );
+		INSTANCES.put( IGNORE.name, IGNORE );
+		INSTANCES.put( OVERWRITE.name, OVERWRITE );
+		INSTANCES.put( EXCEPTION.name, EXCEPTION );
+	}
+
+	private Object readResolve() {
+		return INSTANCES.get(name);
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/SQLQuery.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/SQLQuery.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/SQLQuery.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,93 @@
+//$Id: SQLQuery.java 10845 2006-11-18 04:20:30Z steve.ebersole at jboss.com $
+package org.hibernate;
+
+import org.hibernate.type.Type;
+
+/**
+ * Allows the user to declare the types and select list injection
+ * points of all entities returned by the query. Also allows
+ * declaration of the type and column alias of any scalar results
+ * of the query.
+ * 
+ * @author Gavin King
+ */
+public interface SQLQuery extends Query {
+	/**
+	 * Declare a "root" entity, without specifying an alias
+	 */
+	public SQLQuery addEntity(String entityName);
+	/**
+	 * Declare a "root" entity
+	 */
+	public SQLQuery addEntity(String alias, String entityName);
+	/**
+	 * Declare a "root" entity, specifying a lock mode
+	 */
+	public SQLQuery addEntity(String alias, String entityName, LockMode lockMode);
+	/**
+	 * Declare a "root" entity, without specifying an alias
+	 */
+	public SQLQuery addEntity(Class entityClass);
+	/**
+	 * Declare a "root" entity
+	 */
+	public SQLQuery addEntity(String alias, Class entityClass);
+	/**
+	 * Declare a "root" entity, specifying a lock mode
+	 */
+	public SQLQuery addEntity(String alias, Class entityClass, LockMode lockMode);
+
+	/**
+	 * Declare a "joined" entity
+	 */
+	public SQLQuery addJoin(String alias, String path);
+	/**
+	 * Declare a "joined" entity, specifying a lock mode
+	 */
+	public SQLQuery addJoin(String alias, String path, LockMode lockMode);
+	
+	/**
+	 * Declare a scalar query result
+	 */
+	public SQLQuery addScalar(String columnAlias, Type type);
+
+	/**
+	 * Declare a scalar query. Hibernate will attempt to automatically detect the underlying type.
+	 */
+	public SQLQuery addScalar(String columnAlias);
+
+	/**
+	 * Use a predefined named ResultSetMapping
+	 */
+	public SQLQuery setResultSetMapping(String name);
+
+	/**
+	 * Adds a query space for auto-flush synchronization.
+	 *
+	 * @param querySpace The query space to be auto-flushed for this query.
+	 * @return this, for method chaning
+	 */
+	public SQLQuery addSynchronizedQuerySpace(String querySpace);
+
+	/**
+	 * Adds an entity name or auto-flush synchronization.
+	 *
+	 * @param entityName The name of the entity upon whose defined
+	 * query spaces we should additionally synchronize.
+	 * @return this, for method chaning
+	 * @throws MappingException Indicates the given entity name could not be
+	 * resolved.
+	 */
+	public SQLQuery addSynchronizedEntityName(String entityName) throws MappingException;
+
+	/**
+	 * Adds an entity name or auto-flush synchronization.
+	 *
+	 * @param entityClass The class of the entity upon whose defined
+	 * query spaces we should additionally synchronize.
+	 * @return this, for method chaning
+	 * @throws MappingException Indicates the given entity class could not be
+	 * resolved.
+	 */
+	public SQLQuery addSynchronizedEntityClass(Class entityClass) throws MappingException;
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/SQLQuery.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/ScrollMode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/ScrollMode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/ScrollMode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,74 @@
+//$Id: ScrollMode.java 4369 2004-08-18 00:28:43Z oneovthafew $
+package org.hibernate;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Specifies the type of JDBC scrollable result set to use
+ * underneath a <tt>ScrollableResults</tt>
+ *
+ * @see Query#scroll(ScrollMode)
+ * @see ScrollableResults
+ * @author Gavin King
+ */
+public final class ScrollMode implements Serializable {
+	private final int resultSetType;
+	private final String name;
+	private static final Map INSTANCES = new HashMap();
+
+	private ScrollMode(int level, String name) {
+		this.resultSetType=level;
+		this.name=name;
+	}
+	
+	public String toString() {
+		return name;
+	}
+	
+	/**
+	 * @return the JDBC result set type code
+	 */
+	public int toResultSetType() {
+		return resultSetType;
+	}
+	
+	/**
+	 * @see java.sql.ResultSet.TYPE_FORWARD_ONLY
+	 */
+	public static final ScrollMode FORWARD_ONLY = new ScrollMode(ResultSet.TYPE_FORWARD_ONLY, "FORWARD_ONLY");
+	/**
+	 * @see java.sql.ResultSet.TYPE_SCROLL_SENSITIVE
+	 */
+	public static final ScrollMode SCROLL_SENSITIVE = new ScrollMode(ResultSet.TYPE_SCROLL_SENSITIVE, "SCROLL_SENSITIVE");
+	/**
+	 * Note that since the Hibernate session acts as a cache, you
+	 * might need to expicitly evict objects, if you need to see
+	 * changes made by other transactions. 
+	 * @see java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE
+	 */
+	public static final ScrollMode SCROLL_INSENSITIVE = new ScrollMode(ResultSet.TYPE_SCROLL_INSENSITIVE, "SCROLL_INSENSITIVE");
+	
+	public boolean lessThan(ScrollMode other) {
+		return this.resultSetType<other.resultSetType;
+	}
+
+	static {
+		INSTANCES.put( FORWARD_ONLY.name, FORWARD_ONLY );
+		INSTANCES.put( SCROLL_INSENSITIVE.name, SCROLL_INSENSITIVE );
+		INSTANCES.put( SCROLL_SENSITIVE.name, SCROLL_SENSITIVE );
+	}
+
+	private Object readResolve() {
+		return INSTANCES.get(name);
+	}
+
+}
+
+
+
+
+
+


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/ScrollMode.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/ScrollableResults.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/ScrollableResults.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/ScrollableResults.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,204 @@
+//$Id: ScrollableResults.java 6411 2005-04-13 07:37:50Z oneovthafew $
+package org.hibernate;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.hibernate.type.Type;
+
+/**
+ * A result iterator that allows moving around within the results
+ * by arbitrary increments. The <tt>Query</tt> / <tt>ScrollableResults</tt>
+ * pattern is very similar to the JDBC <tt>PreparedStatement</tt>/
+ * <tt>ResultSet</tt> pattern and the semantics of methods of this interface
+ * are similar to the similarly named methods on <tt>ResultSet</tt>.<br>
+ * <br>
+ * Contrary to JDBC, columns of results are numbered from zero.
+ *
+ * @see Query#scroll()
+ * @author Gavin King
+ */
+public interface ScrollableResults {
+	/**
+	 * Advance to the next result
+	 * @return <tt>true</tt> if there is another result
+	 */
+	public boolean next() throws HibernateException;
+	/**
+	 * Retreat to the previous result
+	 * @return <tt>true</tt> if there is a previous result
+	 */
+	public boolean previous() throws HibernateException;
+	/**
+	 * Scroll an arbitrary number of locations
+	 * @param i a positive (forward) or negative (backward) number of rows
+	 * @return <tt>true</tt> if there is a result at the new location
+	 */
+	public boolean scroll(int i) throws HibernateException;
+	/**
+	 * Go to the last result
+	 * @return <tt>true</tt> if there are any results
+	 */
+	public boolean last() throws HibernateException;
+	/**
+	 * Go to the first result
+	 * @return <tt>true</tt> if there are any results
+	 */
+	public boolean first() throws HibernateException;
+	/**
+	 * Go to a location just before first result (this is the initial location)
+	 */
+	public void beforeFirst() throws HibernateException;
+	/**
+	 * Go to a location just after the last result
+	 */
+	public void afterLast() throws HibernateException;
+	/**
+	 * Is this the first result?
+	 *
+	 * @return <tt>true</tt> if this is the first row of results
+	 * @throws HibernateException
+	 */
+	public boolean isFirst() throws HibernateException;
+	/**
+	 * Is this the last result?
+	 *
+	 * @return <tt>true</tt> if this is the last row of results
+	 * @throws HibernateException
+	 */
+	public boolean isLast() throws HibernateException;
+	/**
+	 * Release resources immediately.
+	 */
+	public void close() throws HibernateException;
+	/**
+	 * Get the current row of results
+	 * @return an object or array
+	 */
+	public Object[] get() throws HibernateException;
+	/**
+	 * Get the <tt>i</tt>th object in the current row of results, without
+	 * initializing any other results in the row. This method may be used
+	 * safely, regardless of the type of the column (ie. even for scalar
+	 * results).
+	 * @param i the column, numbered from zero
+	 * @return an object of any Hibernate type or <tt>null</tt>
+	 */
+	public Object get(int i) throws HibernateException;
+
+	/**
+	 * Get the type of the <tt>i</tt>th column of results
+	 * @param i the column, numbered from zero
+	 * @return the Hibernate type
+	 */
+	public Type getType(int i);
+
+	/**
+	 * Convenience method to read an <tt>integer</tt>
+	 */
+	public Integer getInteger(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>long</tt>
+	 */
+	public Long getLong(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>float</tt>
+	 */
+	public Float getFloat(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>boolean</tt>
+	 */
+	public Boolean getBoolean(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>double</tt>
+	 */
+	public Double getDouble(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>short</tt>
+	 */
+	public Short getShort(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>byte</tt>
+	 */
+	public Byte getByte(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>character</tt>
+	 */
+	public Character getCharacter(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>binary</tt>
+	 */
+	public byte[] getBinary(int col) throws HibernateException;
+	/**
+	 * Convenience method to read <tt>text</tt>
+	 */
+	public String getText(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>blob</tt>
+	 */
+	public Blob getBlob(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>clob</tt>
+	 */
+	public Clob getClob(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>string</tt>
+	 */
+	public String getString(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>big_decimal</tt>
+	 */
+	public BigDecimal getBigDecimal(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>big_integer</tt>
+	 */
+	public BigInteger getBigInteger(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>date</tt>, <tt>time</tt> or <tt>timestamp</tt>
+	 */
+	public Date getDate(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>locale</tt>
+	 */
+	public Locale getLocale(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>calendar</tt> or <tt>calendar_date</tt>
+	 */
+	public Calendar getCalendar(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>currency</tt>
+	 */
+	//public Currency getCurrency(int col) throws HibernateException;
+	/**
+	 * Convenience method to read a <tt>timezone</tt>
+	 */
+	public TimeZone getTimeZone(int col) throws HibernateException;
+	/**
+	 * Get the current location in the result set. The first
+	 * row is number <tt>0</tt>, contrary to JDBC.
+	 * @return the row number, numbered from <tt>0</tt>, or <tt>-1</tt> if
+	 * there is no current row
+	 */
+	public int getRowNumber() throws HibernateException;
+	/**
+	 * Set the current location in the result set, numbered from either the
+	 * first row (row number <tt>0</tt>), or the last row (row
+	 * number <tt>-1</tt>).
+	 * @param rowNumber the row number, numbered from the last row, in the
+	 * case of a negative row number
+	 * @return true if there is a row at that row number
+	 */
+	public boolean setRowNumber(int rowNumber) throws HibernateException;
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/Session.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/Session.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/Session.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,783 @@
+//$Id: Session.java 11494 2007-05-09 02:00:16Z steve.ebersole at jboss.com $
+package org.hibernate;
+
+import java.io.Serializable;
+import java.sql.Connection;
+
+import org.hibernate.stat.SessionStatistics;
+
+/**
+ * The main runtime interface between a Java application and Hibernate. This is the
+ * central API class abstracting the notion of a persistence service.<br>
+ * <br>
+ * The lifecycle of a <tt>Session</tt> is bounded by the beginning and end of a logical
+ * transaction. (Long transactions might span several database transactions.)<br>
+ * <br>
+ * The main function of the <tt>Session</tt> is to offer create, read and delete operations
+ * for instances of mapped entity classes. Instances may exist in one of three states:<br>
+ * <br>
+ * <i>transient:</i> never persistent, not associated with any <tt>Session</tt><br>
+ * <i>persistent:</i> associated with a unique <tt>Session</tt><br>
+ * <i>detached:</i> previously persistent, not associated with any <tt>Session</tt><br>
+ * <br>
+ * Transient instances may be made persistent by calling <tt>save()</tt>,
+ * <tt>persist()</tt> or <tt>saveOrUpdate()</tt>. Persistent instances may be made transient
+ * by calling<tt> delete()</tt>. Any instance returned by a <tt>get()</tt> or
+ * <tt>load()</tt> method is persistent. Detached instances may be made persistent
+ * by calling <tt>update()</tt>, <tt>saveOrUpdate()</tt>, <tt>lock()</tt> or <tt>replicate()</tt>. 
+ * The state of a transient or detached instance may also be made persistent as a new
+ * persistent instance by calling <tt>merge()</tt>.<br>
+ * <br>
+ * <tt>save()</tt> and <tt>persist()</tt> result in an SQL <tt>INSERT</tt>, <tt>delete()</tt>
+ * in an SQL <tt>DELETE</tt> and <tt>update()</tt> or <tt>merge()</tt> in an SQL <tt>UPDATE</tt>. 
+ * Changes to <i>persistent</i> instances are detected at flush time and also result in an SQL
+ * <tt>UPDATE</tt>. <tt>saveOrUpdate()</tt> and <tt>replicate()</tt> result in either an
+ * <tt>INSERT</tt> or an <tt>UPDATE</tt>.<br>
+ * <br>
+ * It is not intended that implementors be threadsafe. Instead each thread/transaction
+ * should obtain its own instance from a <tt>SessionFactory</tt>.<br>
+ * <br>
+ * A <tt>Session</tt> instance is serializable if its persistent classes are serializable.<br>
+ * <br>
+ * A typical transaction should use the following idiom:
+ * <pre>
+ * Session sess = factory.openSession();
+ * Transaction tx;
+ * try {
+ *     tx = sess.beginTransaction();
+ *     //do some work
+ *     ...
+ *     tx.commit();
+ * }
+ * catch (Exception e) {
+ *     if (tx!=null) tx.rollback();
+ *     throw e;
+ * }
+ * finally {
+ *     sess.close();
+ * }
+ * </pre>
+ * <br>
+ * If the <tt>Session</tt> throws an exception, the transaction must be rolled back
+ * and the session discarded. The internal state of the <tt>Session</tt> might not
+ * be consistent with the database after the exception occurs.
+ *
+ * @see SessionFactory
+ * @author Gavin King
+ */
+public interface Session extends Serializable {
+
+	/**
+	 * Retrieve the entity mode in effect for this session.
+	 *
+	 * @return The entity mode for this session.
+	 */
+	public EntityMode getEntityMode();
+
+	/**
+	 * Starts a new Session with the given entity mode in effect. This secondary
+	 * Session inherits the connection, transaction, and other context
+	 * information from the primary Session. It doesn't need to be flushed
+	 * or closed by the developer.
+	 * 
+	 * @param entityMode The entity mode to use for the new session.
+	 * @return The new session
+	 */
+	public Session getSession(EntityMode entityMode);
+
+	/**
+	 * Force this session to flush. Must be called at the end of a
+	 * unit of work, before commiting the transaction and closing the
+	 * session (depending on {@link #setFlushMode flush-mode},
+	 * {@link Transaction#commit()} calls this method).
+	 * <p/>
+	 * <i>Flushing</i> is the process of synchronizing the underlying persistent
+	 * store with persistable state held in memory.
+	 *
+	 * @throws HibernateException Indicates problems flushing the session or
+	 * talking to the database.
+	 */
+	public void flush() throws HibernateException;
+
+	/**
+	 * Set the flush mode for this session.
+	 * <p/>
+	 * The flush mode determines the points at which the session is flushed.
+	 * <i>Flushing</i> is the process of synchronizing the underlying persistent
+	 * store with persistable state held in memory.
+	 * <p/>
+	 * For a logically "read only" session, it is reasonable to set the session's
+	 * flush mode to {@link FlushMode#MANUAL} at the start of the session (in
+	 * order to achieve some extra performance).
+	 *
+	 * @param flushMode the new flush mode
+	 * @see FlushMode
+	 */
+	public void setFlushMode(FlushMode flushMode);
+
+	/**
+	 * Get the current flush mode for this session.
+	 *
+	 * @return The flush mode
+	 */
+	public FlushMode getFlushMode();
+
+	/**
+	 * Set the cache mode.
+	 * <p/>
+	 * Cache mode determines the manner in which this session can interact with
+	 * the second level cache.
+	 *
+	 * @param cacheMode The new cache mode.
+	 */
+	public void setCacheMode(CacheMode cacheMode);
+
+	/**
+	 * Get the current cache mode.
+	 *
+	 * @return The current cache mode.
+	 */
+	public CacheMode getCacheMode();
+
+	/**
+	 * Get the session factory which created this session.
+	 *
+	 * @return The session factory.
+	 * @see SessionFactory
+
+	 */
+	public SessionFactory getSessionFactory();
+
+	/**
+	 * Get the JDBC connection of this Session.<br>
+	 * <br>
+	 * If the session is using aggressive collection release (as in a
+	 * CMT environment), it is the application's responsibility to
+	 * close the connection returned by this call. Otherwise, the
+	 * application should not close the connection.
+	 *
+	 * @return the JDBC connection in use by the <tt>Session</tt>
+	 * @throws HibernateException if the <tt>Session</tt> is disconnected
+	 * @deprecated To be replaced with a SPI for performing work against the connection; scheduled for removal in 4.x
+	 */
+	public Connection connection() throws HibernateException;
+
+	/**
+	 * End the session by releasing the JDBC connection and cleaning up.  It is
+	 * not strictly necessary to close the session but you must at least
+	 * {@link #disconnect()} it.
+	 *
+	 * @return the connection provided by the application or null.
+	 * @throws HibernateException Indicates problems cleaning up.
+	 */
+	public Connection close() throws HibernateException;
+
+	/**
+	 * Cancel the execution of the current query.
+	 * <p/>
+	 * This is the sole method on session which may be safely called from
+	 * another thread.
+	 *
+	 * @throws HibernateException There was a problem canceling the query
+	 */
+	public void cancelQuery() throws HibernateException;
+
+	/**
+	 * Check if the session is still open.
+	 *
+	 * @return boolean
+	 */
+	public boolean isOpen();
+
+	/**
+	 * Check if the session is currently connected.
+	 *
+	 * @return boolean
+	 */
+	public boolean isConnected();
+
+	/**
+	 * Does this session contain any changes which must be synchronized with
+	 * the database?  In other words, would any DML operations be executed if
+	 * we flushed this session?
+	 *
+	 * @return True if the session contains pending changes; false otherwise.
+	 * @throws HibernateException could not perform dirtying checking
+	 */
+	public boolean isDirty() throws HibernateException;
+
+	/**
+	 * Return the identifier value of the given entity as associated with this
+	 * session.  An exception is thrown if the given entity instance is transient
+	 * or detached in relation to this session.
+	 *
+	 * @param object a persistent instance
+	 * @return the identifier
+	 * @throws TransientObjectException if the instance is transient or associated with
+	 * a different session
+	 */
+	public Serializable getIdentifier(Object object) throws HibernateException;
+
+	/**
+	 * Check if this instance is associated with this <tt>Session</tt>.
+	 *
+	 * @param object an instance of a persistent class
+	 * @return true if the given instance is associated with this <tt>Session</tt>
+	 */
+	public boolean contains(Object object);
+
+	/**
+	 * Remove this instance from the session cache. Changes to the instance will
+	 * not be synchronized with the database. This operation cascades to associated
+	 * instances if the association is mapped with <tt>cascade="evict"</tt>.
+	 *
+	 * @param object a persistent instance
+	 * @throws HibernateException
+	 */
+	public void evict(Object object) throws HibernateException;
+
+	/**
+	 * Return the persistent instance of the given entity class with the given identifier,
+	 * obtaining the specified lock mode, assuming the instance exists.
+	 *
+	 * @param theClass a persistent class
+	 * @param id a valid identifier of an existing persistent instance of the class
+	 * @param lockMode the lock level
+	 * @return the persistent instance or proxy
+	 * @throws HibernateException
+	 */
+	public Object load(Class theClass, Serializable id, LockMode lockMode) throws HibernateException;
+
+	/**
+	 * Return the persistent instance of the given entity class with the given identifier,
+	 * obtaining the specified lock mode, assuming the instance exists.
+	 *
+	 * @param entityName a persistent class
+	 * @param id a valid identifier of an existing persistent instance of the class
+	 * @param lockMode the lock level
+	 * @return the persistent instance or proxy
+	 * @throws HibernateException
+	 */
+	public Object load(String entityName, Serializable id, LockMode lockMode) throws HibernateException;
+
+	/**
+	 * Return the persistent instance of the given entity class with the given identifier,
+	 * assuming that the instance exists. This method might return a proxied instance that
+	 * is initialized on-demand, when a non-identifier method is accessed.
+	 * <br><br>
+	 * You should not use this method to determine if an instance exists (use <tt>get()</tt>
+	 * instead). Use this only to retrieve an instance that you assume exists, where non-existence
+	 * would be an actual error.
+	 *
+	 * @param theClass a persistent class
+	 * @param id a valid identifier of an existing persistent instance of the class
+	 * @return the persistent instance or proxy
+	 * @throws HibernateException
+	 */
+	public Object load(Class theClass, Serializable id) throws HibernateException;
+
+	/**
+	 * Return the persistent instance of the given entity class with the given identifier,
+	 * assuming that the instance exists. This method might return a proxied instance that
+	 * is initialized on-demand, when a non-identifier method is accessed.
+	 * <br><br>
+	 * You should not use this method to determine if an instance exists (use <tt>get()</tt>
+	 * instead). Use this only to retrieve an instance that you assume exists, where non-existence
+	 * would be an actual error.
+	 *
+	 * @param entityName a persistent class
+	 * @param id a valid identifier of an existing persistent instance of the class
+	 * @return the persistent instance or proxy
+	 * @throws HibernateException
+	 */
+	public Object load(String entityName, Serializable id) throws HibernateException;
+
+	/**
+	 * Read the persistent state associated with the given identifier into the given transient
+	 * instance.
+	 *
+	 * @param object an "empty" instance of the persistent class
+	 * @param id a valid identifier of an existing persistent instance of the class
+	 * @throws HibernateException
+	 */
+	public void load(Object object, Serializable id) throws HibernateException;
+
+	/**
+	 * Persist the state of the given detached instance, reusing the current
+	 * identifier value.  This operation cascades to associated instances if
+	 * the association is mapped with <tt>cascade="replicate"</tt>.
+	 *
+	 * @param object a detached instance of a persistent class
+	 */
+	public void replicate(Object object, ReplicationMode replicationMode) throws HibernateException;
+
+	/**
+	 * Persist the state of the given detached instance, reusing the current
+	 * identifier value.  This operation cascades to associated instances if
+	 * the association is mapped with <tt>cascade="replicate"</tt>.
+	 *
+	 * @param object a detached instance of a persistent class
+	 */
+	public void replicate(String entityName, Object object, ReplicationMode replicationMode) throws HibernateException;
+
+	/**
+	 * Persist the given transient instance, first assigning a generated identifier. (Or
+	 * using the current value of the identifier property if the <tt>assigned</tt>
+	 * generator is used.) This operation cascades to associated instances if the
+	 * association is mapped with <tt>cascade="save-update"</tt>.
+	 *
+	 * @param object a transient instance of a persistent class
+	 * @return the generated identifier
+	 * @throws HibernateException
+	 */
+	public Serializable save(Object object) throws HibernateException;
+
+	/**
+	 * Persist the given transient instance, first assigning a generated identifier. (Or
+	 * using the current value of the identifier property if the <tt>assigned</tt>
+	 * generator is used.)  This operation cascades to associated instances if the
+	 * association is mapped with <tt>cascade="save-update"</tt>.
+	 *
+	 * @param object a transient instance of a persistent class
+	 * @return the generated identifier
+	 * @throws HibernateException
+	 */
+	public Serializable save(String entityName, Object object) throws HibernateException;
+
+	/**
+	 * Either {@link #save(Object)} or {@link #update(Object)} the given
+	 * instance, depending upon resolution of the unsaved-value checks (see the
+	 * manual for discussion of unsaved-value checking).
+	 * <p/>
+	 * This operation cascades to associated instances if the association is mapped
+	 * with <tt>cascade="save-update"</tt>.
+	 *
+	 * @see Session#save(java.lang.Object)
+	 * @see Session#update(Object object)
+	 * @param object a transient or detached instance containing new or updated state
+	 * @throws HibernateException
+	 */
+	public void saveOrUpdate(Object object) throws HibernateException;
+
+	/**
+	 * Either {@link #save(String, Object)} or {@link #update(String, Object)}
+	 * the given instance, depending upon resolution of the unsaved-value checks
+	 * (see the manual for discussion of unsaved-value checking).
+	 * <p/>
+	 * This operation cascades to associated instances if the association is mapped
+	 * with <tt>cascade="save-update"</tt>.
+	 *
+	 * @see Session#save(String,Object)
+	 * @see Session#update(String,Object)
+	 * @param object a transient or detached instance containing new or updated state
+	 * @throws HibernateException
+	 */
+	public void saveOrUpdate(String entityName, Object object) throws HibernateException;
+
+	/**
+	 * Update the persistent instance with the identifier of the given detached
+	 * instance. If there is a persistent instance with the same identifier,
+	 * an exception is thrown. This operation cascades to associated instances
+	 * if the association is mapped with <tt>cascade="save-update"</tt>.
+	 *
+	 * @param object a detached instance containing updated state
+	 * @throws HibernateException
+	 */
+	public void update(Object object) throws HibernateException;
+
+	/**
+	 * Update the persistent instance with the identifier of the given detached
+	 * instance. If there is a persistent instance with the same identifier,
+	 * an exception is thrown. This operation cascades to associated instances
+	 * if the association is mapped with <tt>cascade="save-update"</tt>.
+	 *
+	 * @param object a detached instance containing updated state
+	 * @throws HibernateException
+	 */
+	public void update(String entityName, Object object) throws HibernateException;
+
+	/**
+	 * Copy the state of the given object onto the persistent object with the same
+	 * identifier. If there is no persistent instance currently associated with
+	 * the session, it will be loaded. Return the persistent instance. If the
+	 * given instance is unsaved, save a copy of and return it as a newly persistent
+	 * instance. The given instance does not become associated with the session.
+	 * This operation cascades to associated instances if the association is mapped
+	 * with <tt>cascade="merge"</tt>.<br>
+	 * <br>
+	 * The semantics of this method are defined by JSR-220.
+	 *
+	 * @param object a detached instance with state to be copied
+	 * @return an updated persistent instance
+	 */
+	public Object merge(Object object) throws HibernateException;
+
+	/**
+	 * Copy the state of the given object onto the persistent object with the same
+	 * identifier. If there is no persistent instance currently associated with
+	 * the session, it will be loaded. Return the persistent instance. If the
+	 * given instance is unsaved, save a copy of and return it as a newly persistent
+	 * instance. The given instance does not become associated with the session.
+	 * This operation cascades to associated instances if the association is mapped
+	 * with <tt>cascade="merge"</tt>.<br>
+	 * <br>
+	 * The semantics of this method are defined by JSR-220.
+	 *
+	 * @param object a detached instance with state to be copied
+	 * @return an updated persistent instance
+	 */
+	public Object merge(String entityName, Object object) throws HibernateException;
+
+	/**
+	 * Make a transient instance persistent. This operation cascades to associated
+	 * instances if the association is mapped with <tt>cascade="persist"</tt>.<br>
+	 * <br>
+	 * The semantics of this method are defined by JSR-220.
+	 *
+	 * @param object a transient instance to be made persistent
+	 */
+	public void persist(Object object) throws HibernateException;
+	/**
+	 * Make a transient instance persistent. This operation cascades to associated
+	 * instances if the association is mapped with <tt>cascade="persist"</tt>.<br>
+	 * <br>
+	 * The semantics of this method are defined by JSR-220.
+	 *
+	 * @param object a transient instance to be made persistent
+	 */
+	public void persist(String entityName, Object object) throws HibernateException;
+
+	/**
+	 * Remove a persistent instance from the datastore. The argument may be
+	 * an instance associated with the receiving <tt>Session</tt> or a transient
+	 * instance with an identifier associated with existing persistent state.
+	 * This operation cascades to associated instances if the association is mapped
+	 * with <tt>cascade="delete"</tt>.
+	 *
+	 * @param object the instance to be removed
+	 * @throws HibernateException
+	 */
+	public void delete(Object object) throws HibernateException;
+
+	/**
+	 * Remove a persistent instance from the datastore. The <b>object</b> argument may be
+	 * an instance associated with the receiving <tt>Session</tt> or a transient
+	 * instance with an identifier associated with existing persistent state.
+	 * This operation cascades to associated instances if the association is mapped
+	 * with <tt>cascade="delete"</tt>.
+	 *
+	 * @param entityName The entity name for the instance to be removed.
+	 * @param object the instance to be removed
+	 * @throws HibernateException
+	 */
+	public void delete(String entityName, Object object) throws HibernateException;
+
+	/**
+	 * Obtain the specified lock level upon the given object. This may be used to
+	 * perform a version check (<tt>LockMode.READ</tt>), to upgrade to a pessimistic
+	 * lock (<tt>LockMode.UPGRADE</tt>), or to simply reassociate a transient instance
+	 * with a session (<tt>LockMode.NONE</tt>). This operation cascades to associated
+	 * instances if the association is mapped with <tt>cascade="lock"</tt>.
+	 *
+	 * @param object a persistent or transient instance
+	 * @param lockMode the lock level
+	 * @throws HibernateException
+	 */
+	public void lock(Object object, LockMode lockMode) throws HibernateException;
+
+	/**
+	 * Obtain the specified lock level upon the given object. This may be used to
+	 * perform a version check (<tt>LockMode.READ</tt>), to upgrade to a pessimistic
+	 * lock (<tt>LockMode.UPGRADE</tt>), or to simply reassociate a transient instance
+	 * with a session (<tt>LockMode.NONE</tt>). This operation cascades to associated
+	 * instances if the association is mapped with <tt>cascade="lock"</tt>.
+	 *
+	 * @param object a persistent or transient instance
+	 * @param lockMode the lock level
+	 * @throws HibernateException
+	 */
+	public void lock(String entityName, Object object, LockMode lockMode) throws HibernateException;
+
+	/**
+	 * Re-read the state of the given instance from the underlying database. It is
+	 * inadvisable to use this to implement long-running sessions that span many
+	 * business tasks. This method is, however, useful in certain special circumstances.
+	 * For example
+	 * <ul>
+	 * <li>where a database trigger alters the object state upon insert or update
+	 * <li>after executing direct SQL (eg. a mass update) in the same session
+	 * <li>after inserting a <tt>Blob</tt> or <tt>Clob</tt>
+	 * </ul>
+	 *
+	 * @param object a persistent or detached instance
+	 * @throws HibernateException
+	 */
+	public void refresh(Object object) throws HibernateException;
+
+	/**
+	 * Re-read the state of the given instance from the underlying database, with
+	 * the given <tt>LockMode</tt>. It is inadvisable to use this to implement
+	 * long-running sessions that span many business tasks. This method is, however,
+	 * useful in certain special circumstances.
+	 *
+	 * @param object a persistent or detached instance
+	 * @param lockMode the lock mode to use
+	 * @throws HibernateException
+	 */
+	public void refresh(Object object, LockMode lockMode) throws HibernateException;
+
+	/**
+	 * Determine the current lock mode of the given object.
+	 *
+	 * @param object a persistent instance
+	 * @return the current lock mode
+	 * @throws HibernateException
+	 */
+	public LockMode getCurrentLockMode(Object object) throws HibernateException;
+
+	/**
+	 * Begin a unit of work and return the associated <tt>Transaction</tt> object.
+	 * If a new underlying transaction is required, begin the transaction. Otherwise
+	 * continue the new work in the context of the existing underlying transaction.
+	 * The class of the returned <tt>Transaction</tt> object is determined by the
+	 * property <tt>hibernate.transaction_factory</tt>.
+	 *
+	 * @return a Transaction instance
+	 * @throws HibernateException
+	 * @see Transaction
+	 */
+	public Transaction beginTransaction() throws HibernateException;
+
+	/**
+	 * Get the <tt>Transaction</tt> instance associated with this session.
+	 * The class of the returned <tt>Transaction</tt> object is determined by the
+	 * property <tt>hibernate.transaction_factory</tt>.
+	 *
+	 * @return a Transaction instance
+	 * @throws HibernateException
+	 * @see Transaction
+	 */
+	public Transaction getTransaction();
+
+	/**
+	 * Create a new <tt>Criteria</tt> instance, for the given entity class,
+	 * or a superclass of an entity class.
+	 *
+	 * @param persistentClass a class, which is persistent, or has persistent subclasses
+	 * @return Criteria
+	 */
+	public Criteria createCriteria(Class persistentClass);
+
+	/**
+	 * Create a new <tt>Criteria</tt> instance, for the given entity class,
+	 * or a superclass of an entity class, with the given alias.
+	 *
+	 * @param persistentClass a class, which is persistent, or has persistent subclasses
+	 * @return Criteria
+	 */
+	public Criteria createCriteria(Class persistentClass, String alias);
+
+	/**
+	 * Create a new <tt>Criteria</tt> instance, for the given entity name.
+	 *
+	 * @param entityName
+	 * @return Criteria
+	 */
+	public Criteria createCriteria(String entityName);
+
+	/**
+	 * Create a new <tt>Criteria</tt> instance, for the given entity name,
+	 * with the given alias.
+	 *
+	 * @param entityName
+	 * @return Criteria
+	 */
+	public Criteria createCriteria(String entityName, String alias);
+
+	/**
+	 * Create a new instance of <tt>Query</tt> for the given HQL query string.
+	 *
+	 * @param queryString a HQL query
+	 * @return Query
+	 * @throws HibernateException
+	 */
+	public Query createQuery(String queryString) throws HibernateException;
+
+	/**
+	 * Create a new instance of <tt>SQLQuery</tt> for the given SQL query string.
+	 *
+	 * @param queryString a SQL query
+	 * @return SQLQuery
+	 * @throws HibernateException
+	 */
+	public SQLQuery createSQLQuery(String queryString) throws HibernateException;
+
+	/**
+	 * Create a new instance of <tt>Query</tt> for the given collection and filter string.
+	 *
+	 * @param collection a persistent collection
+	 * @param queryString a Hibernate query
+	 * @return Query
+	 * @throws HibernateException
+	 */
+	public Query createFilter(Object collection, String queryString) throws HibernateException;
+
+	/**
+	 * Obtain an instance of <tt>Query</tt> for a named query string defined in the
+	 * mapping file.
+	 *
+	 * @param queryName the name of a query defined externally
+	 * @return Query
+	 * @throws HibernateException
+	 */
+	public Query getNamedQuery(String queryName) throws HibernateException;
+
+	/**
+	 * Completely clear the session. Evict all loaded instances and cancel all pending
+	 * saves, updates and deletions. Do not close open iterators or instances of
+	 * <tt>ScrollableResults</tt>.
+	 */
+	public void clear();
+
+	/**
+	 * Return the persistent instance of the given entity class with the given identifier,
+	 * or null if there is no such persistent instance. (If the instance is already associated
+	 * with the session, return that instance. This method never returns an uninitialized instance.)
+	 * Obtain the specified lock mode if the instance exists.
+	 *
+	 * @param clazz a persistent class
+	 * @param id an identifier
+	 * @return a persistent instance or null
+	 * @throws HibernateException
+	 */
+	public Object get(Class clazz, Serializable id) throws HibernateException;
+
+	/**
+	 * Return the persistent instance of the given entity class with the given identifier,
+	 * or null if there is no such persistent instance. (If the instance is already associated
+	 * with the session, return that instance. This method never returns an uninitialized instance.)
+	 * Obtain the specified lock mode if the instance exists.
+	 *
+	 * @param clazz a persistent class
+	 * @param id an identifier
+	 * @param lockMode the lock mode
+	 * @return a persistent instance or null
+	 * @throws HibernateException
+	 */
+	public Object get(Class clazz, Serializable id, LockMode lockMode) throws HibernateException;
+
+	/**
+	 * Return the persistent instance of the given named entity with the given identifier,
+	 * or null if there is no such persistent instance. (If the instance is already associated
+	 * with the session, return that instance. This method never returns an uninitialized instance.)
+	 *
+	 * @param entityName the entity name
+	 * @param id an identifier
+	 * @return a persistent instance or null
+	 * @throws HibernateException
+	 */
+	public Object get(String entityName, Serializable id) throws HibernateException;
+
+	/**
+	 * Return the persistent instance of the given entity class with the given identifier,
+	 * or null if there is no such persistent instance. (If the instance is already associated
+	 * with the session, return that instance. This method never returns an uninitialized instance.)
+	 * Obtain the specified lock mode if the instance exists.
+	 *
+	 * @param entityName the entity name
+	 * @param id an identifier
+	 * @param lockMode the lock mode
+	 * @return a persistent instance or null
+	 * @throws HibernateException
+	 */
+	public Object get(String entityName, Serializable id, LockMode lockMode) throws HibernateException;
+
+	
+	/**
+	 * Return the entity name for a persistent entity
+	 *   
+	 * @param object a persistent entity
+	 * @return the entity name
+	 * @throws HibernateException
+	 */
+	public String getEntityName(Object object) throws HibernateException;
+
+	/**
+	 * Enable the named filter for this current session.
+	 *
+	 * @param filterName The name of the filter to be enabled.
+	 * @return The Filter instance representing the enabled fiter.
+	 */
+	public Filter enableFilter(String filterName);
+
+	/**
+	 * Retrieve a currently enabled filter by name.
+	 *
+	 * @param filterName The name of the filter to be retrieved.
+	 * @return The Filter instance representing the enabled fiter.
+	 */
+	public Filter getEnabledFilter(String filterName);
+
+	/**
+	 * Disable the named filter for the current session.
+	 *
+	 * @param filterName The name of the filter to be disabled.
+	 */
+	public void disableFilter(String filterName);
+	
+	/**
+	 * Get the statistics for this session.
+	 */
+	public SessionStatistics getStatistics();
+	
+	/**
+	 * Set an unmodified persistent object to read only mode, or a read only
+	 * object to modifiable mode. In read only mode, no snapshot is maintained
+	 * and the instance is never dirty checked.
+	 * 
+	 * @see Query#setReadOnly(boolean)
+	 */
+	public void setReadOnly(Object entity, boolean readOnly);
+
+
+
+	/**
+	 * Disconnect the <tt>Session</tt> from the current JDBC connection. If
+	 * the connection was obtained by Hibernate close it and return it to
+	 * the connection pool; otherwise, return it to the application.
+	 * <p/>
+	 * This is used by applications which supply JDBC connections to Hibernate
+	 * and which require long-sessions (or long-conversations)
+	 * <p/>
+	 * Note that disconnect() called on a session where the connection was
+	 * retrieved by Hibernate through its configured
+	 * {@link org.hibernate.connection.ConnectionProvider} has no effect,
+	 * provided {@link ConnectionReleaseMode#ON_CLOSE} is not in effect.
+	 *
+	 * @return the application-supplied connection or <tt>null</tt>
+	 * @see #reconnect(Connection)
+	 * @see #reconnect()
+	 */
+	Connection disconnect() throws HibernateException;
+
+	/**
+	 * Obtain a new JDBC connection. This is used by applications which
+	 * require long transactions and do not supply connections to the
+	 * session.
+	 *
+	 * @see #disconnect()
+	 * @deprecated Manual reconnection is only needed in the case of
+	 * application-supplied connections, in which case the
+	 * {@link #reconnect(java.sql.Connection)} for should be used.
+	 */
+	void reconnect() throws HibernateException;
+
+	/**
+	 * Reconnect to the given JDBC connection. This is used by applications
+	 * which require long transactions and use application-supplied connections.
+	 *
+	 * @param connection a JDBC connection
+	 * @see #disconnect()
+	 */
+	void reconnect(Connection connection) throws HibernateException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/SessionException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/SessionException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/SessionException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: SessionException.java 9024 2006-01-11 22:38:24Z steveebersole $
+package org.hibernate;
+
+/**
+ * Thrown when the user calls a method of a {@link Session} that is in an
+ * inappropropriate state for the given call (for example, the the session
+ * is closed or disconnected).
+ *
+ * @author Gavin King
+ */
+public class SessionException extends HibernateException {
+
+	/**
+	 * Constructs a new SessionException with the given message.
+	 *
+	 * @param message The message indicating the specific problem.
+	 */
+	public SessionException(String message) {
+		super( message );
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/SessionException.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/SessionFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/SessionFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/SessionFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,224 @@
+//$Id: SessionFactory.java 8754 2005-12-05 23:36:59Z steveebersole $
+package org.hibernate;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.util.Map;
+import java.util.Set;
+
+import javax.naming.Referenceable;
+
+import org.hibernate.metadata.ClassMetadata;
+import org.hibernate.metadata.CollectionMetadata;
+import org.hibernate.stat.Statistics;
+import org.hibernate.engine.FilterDefinition;
+
+/**
+ * Creates <tt>Session</tt>s. Usually an application has a single <tt>SessionFactory</tt>.
+ * Threads servicing client requests obtain <tt>Session</tt>s from the factory.<br>
+ * <br>
+ * Implementors must be threadsafe.<br>
+ * <br>
+ * <tt>SessionFactory</tt>s are immutable. The behaviour of a <tt>SessionFactory</tt> is
+ * controlled by properties supplied at configuration time. These properties are defined
+ * on <tt>Environment</tt>.
+ *
+ * @see Session
+ * @see org.hibernate.cfg.Environment
+ * @see org.hibernate.cfg.Configuration
+ * @see org.hibernate.connection.ConnectionProvider
+ * @see org.hibernate.transaction.TransactionFactory
+ * @author Gavin King
+ */
+public interface SessionFactory extends Referenceable, Serializable {
+
+	/**
+	 * Open a <tt>Session</tt> on the given connection.
+	 * <p>
+	 * Note that the second-level cache will be disabled if you
+	 * supply a JDBC connection. Hibernate will not be able to track
+	 * any statements you might have executed in the same transaction.
+	 * Consider implementing your own <tt>ConnectionProvider</tt>.
+	 *
+	 * @param connection a connection provided by the application.
+	 * @return Session
+	 */
+	public org.hibernate.classic.Session openSession(Connection connection);
+
+	/**
+	 * Create database connection and open a <tt>Session</tt> on it, specifying an
+	 * interceptor.
+	 *
+	 * @param interceptor a session-scoped interceptor
+	 * @return Session
+	 * @throws HibernateException
+	 */
+	public org.hibernate.classic.Session openSession(Interceptor interceptor) throws HibernateException;
+
+	/**
+	 * Open a <tt>Session</tt> on the given connection, specifying an interceptor.
+	 * <p>
+	 * Note that the second-level cache will be disabled if you
+	 * supply a JDBC connection. Hibernate will not be able to track
+	 * any statements you might have executed in the same transaction.
+	 * Consider implementing your own <tt>ConnectionProvider</tt>.
+	 *
+	 * @param connection a connection provided by the application.
+	 * @param interceptor a session-scoped interceptor
+	 * @return Session
+	 */
+	public org.hibernate.classic.Session openSession(Connection connection, Interceptor interceptor);
+
+	/**
+	 * Create database connection and open a <tt>Session</tt> on it.
+	 *
+	 * @return Session
+	 * @throws HibernateException
+	 */
+	public org.hibernate.classic.Session openSession() throws HibernateException;
+
+	/**
+	 * Obtains the current session.  The definition of what exactly "current"
+	 * means controlled by the {@link org.hibernate.context.CurrentSessionContext} impl configured
+	 * for use.
+	 * <p/>
+	 * Note that for backwards compatibility, if a {@link org.hibernate.context.CurrentSessionContext}
+	 * is not configured but a JTA {@link org.hibernate.transaction.TransactionManagerLookup}
+	 * is configured this will default to the {@link org.hibernate.context.JTASessionContext}
+	 * impl.
+	 *
+	 * @return The current session.
+	 * @throws HibernateException Indicates an issue locating a suitable current session.
+	 */
+	public org.hibernate.classic.Session getCurrentSession() throws HibernateException;
+
+	/**
+	 * Get the <tt>ClassMetadata</tt> associated with the given entity class
+	 *
+	 * @see org.hibernate.metadata.ClassMetadata
+	 */
+	public ClassMetadata getClassMetadata(Class persistentClass) throws HibernateException;
+
+	/**
+	 * Get the <tt>ClassMetadata</tt> associated with the given entity name
+	 *
+	 * @see org.hibernate.metadata.ClassMetadata
+	 * @since 3.0
+	 */
+	public ClassMetadata getClassMetadata(String entityName) throws HibernateException;
+
+	/**
+	 * Get the <tt>CollectionMetadata</tt> associated with the named collection role
+	 *
+	 * @see org.hibernate.metadata.CollectionMetadata
+	 */
+	public CollectionMetadata getCollectionMetadata(String roleName) throws HibernateException;
+
+
+	/**
+	 * Get all <tt>ClassMetadata</tt> as a <tt>Map</tt> from entityname <tt>String</tt>
+	 * to metadata object
+	 *
+	 * @see org.hibernate.metadata.ClassMetadata
+	 * @return a map from <tt>String</tt> an entity name to <tt>ClassMetaData</tt>
+	 * @since 3.0 changed key from <tt>Class</tt> to <tt>String</tt>
+	 */
+	public Map getAllClassMetadata() throws HibernateException;
+
+	/**
+	 * Get all <tt>CollectionMetadata</tt> as a <tt>Map</tt> from role name
+	 * to metadata object
+	 *
+	 * @see org.hibernate.metadata.CollectionMetadata
+	 * @return a map from <tt>String</tt> to <tt>CollectionMetadata</tt>
+	 */
+	public Map getAllCollectionMetadata() throws HibernateException;
+
+	/**
+	 * Get the statistics for this session factory
+	 */
+	public Statistics getStatistics();
+
+	/**
+	 * Destroy this <tt>SessionFactory</tt> and release all resources (caches,
+	 * connection pools, etc). It is the responsibility of the application
+	 * to ensure that there are no open <tt>Session</tt>s before calling
+	 * <tt>close()</tt>.
+	 */
+	public void close() throws HibernateException;
+
+	/**
+	 * Was this <tt>SessionFactory</tt> already closed?
+	 */
+	public boolean isClosed();
+
+	/**
+	 * Evict all entries from the second-level cache. This method occurs outside
+	 * of any transaction; it performs an immediate "hard" remove, so does not respect
+	 * any transaction isolation semantics of the usage strategy. Use with care.
+	 */
+	public void evict(Class persistentClass) throws HibernateException;
+	/**
+	 * Evict an entry from the second-level  cache. This method occurs outside
+	 * of any transaction; it performs an immediate "hard" remove, so does not respect
+	 * any transaction isolation semantics of the usage strategy. Use with care.
+	 */
+	public void evict(Class persistentClass, Serializable id) throws HibernateException;
+	/**
+	 * Evict all entries from the second-level cache. This method occurs outside
+	 * of any transaction; it performs an immediate "hard" remove, so does not respect
+	 * any transaction isolation semantics of the usage strategy. Use with care.
+	 */
+	public void evictEntity(String entityName) throws HibernateException;
+	/**
+	 * Evict an entry from the second-level  cache. This method occurs outside
+	 * of any transaction; it performs an immediate "hard" remove, so does not respect
+	 * any transaction isolation semantics of the usage strategy. Use with care.
+	 */
+	public void evictEntity(String entityName, Serializable id) throws HibernateException;
+	/**
+	 * Evict all entries from the second-level cache. This method occurs outside
+	 * of any transaction; it performs an immediate "hard" remove, so does not respect
+	 * any transaction isolation semantics of the usage strategy. Use with care.
+	 */
+	public void evictCollection(String roleName) throws HibernateException;
+	/**
+	 * Evict an entry from the second-level cache. This method occurs outside
+	 * of any transaction; it performs an immediate "hard" remove, so does not respect
+	 * any transaction isolation semantics of the usage strategy. Use with care.
+	 */
+	public void evictCollection(String roleName, Serializable id) throws HibernateException;
+
+	/**
+	 * Evict any query result sets cached in the default query cache region.
+	 */
+	public void evictQueries() throws HibernateException;
+	/**
+	 * Evict any query result sets cached in the named query cache region.
+	 */
+	public void evictQueries(String cacheRegion) throws HibernateException;
+	/**
+	 * Get a new stateless session.
+	 */
+	public StatelessSession openStatelessSession();
+	/**
+	 * Get a new stateless session for the given JDBC connection.
+	 */
+	public StatelessSession openStatelessSession(Connection connection);
+
+	/**
+	 * Obtain a set of the names of all filters defined on this SessionFactory.
+	 *
+	 * @return The set of filter names.
+	 */
+	public Set getDefinedFilterNames();
+
+	/**
+	 * Obtain the definition of a filter by name.
+	 *
+	 * @param filterName The name of the filter for which to obtain the definition.
+	 * @return The filter definition.
+	 * @throws HibernateException If no filter defined with the given name.
+	 */
+	public FilterDefinition getFilterDefinition(String filterName) throws HibernateException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/StaleObjectStateException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/StaleObjectStateException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/StaleObjectStateException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: StaleObjectStateException.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate;
+
+import java.io.Serializable;
+
+import org.hibernate.pretty.MessageHelper;
+
+/**
+ * A <tt>StaleStateException</tt> that carries information 
+ * about a particular entity instance that was the source
+ * of the failure.
+ *
+ * @author Gavin King
+ */
+public class StaleObjectStateException extends StaleStateException {
+	private final String entityName;
+	private final Serializable identifier;
+
+	public StaleObjectStateException(String persistentClass, Serializable identifier) {
+		super("Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)");
+		this.entityName = persistentClass;
+		this.identifier = identifier;
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public Serializable getIdentifier() {
+		return identifier;
+	}
+
+	public String getMessage() {
+		return super.getMessage() + ": " +
+			MessageHelper.infoString(entityName, identifier);
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/StaleStateException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/StaleStateException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/StaleStateException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+//$Id: StaleStateException.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate;
+
+/**
+ * Thrown when a version number or timestamp check failed, indicating that the
+ * <tt>Session</tt> contained stale data (when using long transactions
+ * with versioning). Also occurs if we try delete or update a row that does
+ * not exist.<br>
+ * <br>
+ * Note that this exception often indicates that the user failed to specify the
+ * correct <tt>unsaved-value</tt> strategy for a class!
+ *
+ * @see StaleObjectStateException
+ * @author Gavin King
+ */
+public class StaleStateException extends HibernateException {
+
+	public StaleStateException(String s) {
+		super(s);
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/StaleStateException.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/StatelessSession.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/StatelessSession.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/StatelessSession.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,217 @@
+//$Id: StatelessSession.java 9705 2006-03-28 19:59:31Z steve.ebersole at jboss.com $
+package org.hibernate;
+
+import java.io.Serializable;
+import java.sql.Connection;
+
+/**
+ * A command-oriented API for performing bulk operations
+ * against a database.<br>
+ * <br>
+ * A stateless session does not implement a first-level cache nor
+ * interact with any second-level cache, nor does it implement
+ * transactional write-behind or automatic dirty checking, nor do
+ * operations cascade to associated instances. Collections are
+ * ignored by a stateless session. Operations performed via a
+ * stateless session bypass Hibernate's event model and
+ * interceptors. Stateless sessions are vulnerable to data
+ * aliasing effects, due to the lack of a first-level cache.<br>
+ * <br>
+ * For certain kinds of transactions, a stateless session may
+ * perform slightly faster than a stateful session.
+ *
+ * @author Gavin King
+ */
+public interface StatelessSession extends Serializable {
+	/**
+	 * Close the stateless session and release the JDBC connection.
+	 */
+	public void close();
+
+	/**
+	 * Insert a row.
+	 *
+	 * @param entity a new transient instance
+	 */
+	public Serializable insert(Object entity);
+
+	/**
+	 * Insert a row.
+	 *
+	 * @param entityName The entityName for the entity to be inserted
+	 * @param entity a new transient instance
+	 * @return the identifier of the instance
+	 */
+	public Serializable insert(String entityName, Object entity);
+
+	/**
+	 * Update a row.
+	 *
+	 * @param entity a detached entity instance
+	 */
+	public void update(Object entity);
+
+	/**
+	 * Update a row.
+	 *
+	 * @param entityName The entityName for the entity to be updated
+	 * @param entity a detached entity instance
+	 */
+	public void update(String entityName, Object entity);
+
+	/**
+	 * Delete a row.
+	 *
+	 * @param entity a detached entity instance
+	 */
+	public void delete(Object entity);
+
+	/**
+	 * Delete a row.
+	 *
+	 * @param entityName The entityName for the entity to be deleted
+	 * @param entity a detached entity instance
+	 */
+	public void delete(String entityName, Object entity);
+
+	/**
+	 * Retrieve a row.
+	 *
+	 * @return a detached entity instance
+	 */
+	public Object get(String entityName, Serializable id);
+
+	/**
+	 * Retrieve a row.
+	 *
+	 * @return a detached entity instance
+	 */
+	public Object get(Class entityClass, Serializable id);
+
+	/**
+	 * Retrieve a row, obtaining the specified lock mode.
+	 *
+	 * @return a detached entity instance
+	 */
+	public Object get(String entityName, Serializable id, LockMode lockMode);
+
+	/**
+	 * Retrieve a row, obtaining the specified lock mode.
+	 *
+	 * @return a detached entity instance
+	 */
+	public Object get(Class entityClass, Serializable id, LockMode lockMode);
+
+	/**
+	 * Refresh the entity instance state from the database.
+	 *
+	 * @param entity The entity to be refreshed.
+	 */
+	public void refresh(Object entity);
+
+	/**
+	 * Refresh the entity instance state from the database.
+	 *
+	 * @param entityName The entityName for the entity to be refreshed.
+	 * @param entity The entity to be refreshed.
+	 */
+	public void refresh(String entityName, Object entity);
+
+	/**
+	 * Refresh the entity instance state from the database.
+	 *
+	 * @param entity The entity to be refreshed.
+	 * @param lockMode The LockMode to be applied.
+	 */
+	public void refresh(Object entity, LockMode lockMode);
+
+	/**
+	 * Refresh the entity instance state from the database.
+	 *
+	 * @param entityName The entityName for the entity to be refreshed.
+	 * @param entity The entity to be refreshed.
+	 * @param lockMode The LockMode to be applied.
+	 */
+	public void refresh(String entityName, Object entity, LockMode lockMode);
+
+	/**
+	 * Create a new instance of <tt>Query</tt> for the given HQL query string.
+	 * Entities returned by the query are detached.
+	 */
+	public Query createQuery(String queryString);
+
+	/**
+	 * Obtain an instance of <tt>Query</tt> for a named query string defined in
+	 * the mapping file. Entities returned by the query are detached.
+	 */
+	public Query getNamedQuery(String queryName);
+
+	/**
+	 * Create a new <tt>Criteria</tt> instance, for the given entity class,
+	 * or a superclass of an entity class. Entities returned by the query are
+	 * detached.
+	 *
+	 * @param persistentClass a class, which is persistent, or has persistent subclasses
+	 * @return Criteria
+	 */
+	public Criteria createCriteria(Class persistentClass);
+
+	/**
+	 * Create a new <tt>Criteria</tt> instance, for the given entity class,
+	 * or a superclass of an entity class, with the given alias.
+	 * Entities returned by the query are detached.
+	 *
+	 * @param persistentClass a class, which is persistent, or has persistent subclasses
+	 * @return Criteria
+	 */
+	public Criteria createCriteria(Class persistentClass, String alias);
+
+	/**
+	 * Create a new <tt>Criteria</tt> instance, for the given entity name.
+	 * Entities returned by the query are detached.
+	 *
+	 * @param entityName
+	 * @return Criteria
+	 */
+	public Criteria createCriteria(String entityName);
+
+	/**
+	 * Create a new <tt>Criteria</tt> instance, for the given entity name,
+	 * with the given alias. Entities returned by the query are detached.
+	 *
+	 * @param entityName
+	 * @return Criteria
+	 */
+	public Criteria createCriteria(String entityName, String alias);
+
+	/**
+	 * Create a new instance of <tt>SQLQuery</tt> for the given SQL query string.
+	 * Entities returned by the query are detached.
+	 *
+	 * @param queryString a SQL query
+	 * @return SQLQuery
+	 * @throws HibernateException
+	 */
+	public SQLQuery createSQLQuery(String queryString) throws HibernateException;
+
+	/**
+	 * Begin a Hibernate transaction.
+	 */
+	public Transaction beginTransaction();
+
+	/**
+	 * Get the current Hibernate transaction.
+	 */
+	public Transaction getTransaction();
+
+	/**
+	 * Returns the current JDBC connection associated with this
+	 * instance.<br>
+	 * <br>
+	 * If the session is using aggressive connection release (as in a
+	 * CMT environment), it is the application's responsibility to
+	 * close the connection returned by this call. Otherwise, the
+	 * application should not close the connection.
+	 */
+	public Connection connection();
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/StatelessSession.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/Transaction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/Transaction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/Transaction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,105 @@
+//$Id: Transaction.java 9595 2006-03-10 18:14:21Z steve.ebersole at jboss.com $
+package org.hibernate;
+
+import javax.transaction.Synchronization;
+
+/**
+ * Allows the application to define units of work, while
+ * maintaining abstraction from the underlying transaction
+ * implementation (eg. JTA, JDBC).<br>
+ * <br>
+ * A transaction is associated with a <tt>Session</tt> and is
+ * usually instantiated by a call to <tt>Session.beginTransaction()</tt>.
+ * A single session might span multiple transactions since
+ * the notion of a session (a conversation between the application
+ * and the datastore) is of coarser granularity than the notion of
+ * a transaction. However, it is intended that there be at most one
+ * uncommitted <tt>Transaction</tt> associated with a particular
+ * <tt>Session</tt> at any time.<br>
+ * <br>
+ * Implementors are not intended to be threadsafe.
+ *
+ * @see Session#beginTransaction()
+ * @see org.hibernate.transaction.TransactionFactory
+ * @author Anton van Straaten
+ */
+public interface Transaction {
+	
+	/**
+	 * Begin a new transaction.
+	 */
+	public void begin() throws HibernateException;
+
+	/**
+	 * Flush the associated <tt>Session</tt> and end the unit of work (unless
+	 * we are in {@link FlushMode#NEVER}.
+	 * </p>
+	 * This method will commit the underlying transaction if and only
+	 * if the underlying transaction was initiated by this object.
+	 *
+	 * @throws HibernateException
+	 */
+	public void commit() throws HibernateException;
+
+	/**
+	 * Force the underlying transaction to roll back.
+	 *
+	 * @throws HibernateException
+	 */
+	public void rollback() throws HibernateException;
+
+	/**
+	 * Was this transaction rolled back or set to rollback only?
+	 * <p/>
+	 * This only accounts for actions initiated from this local transaction.
+	 * If, for example, the underlying transaction is forced to rollback via
+	 * some other means, this method still reports false because the rollback
+	 * was not initiated from here.
+	 *
+	 * @return boolean True if the transaction was rolled back via this
+	 * local transaction; false otherwise.
+	 * @throws HibernateException
+	 */
+	public boolean wasRolledBack() throws HibernateException;
+
+	/**
+	 * Check if this transaction was successfully committed.
+	 * <p/>
+	 * This method could return <tt>false</tt> even after successful invocation
+	 * of {@link #commit}.  As an example, JTA based strategies no-op on
+	 * {@link #commit} calls if they did not start the transaction; in that case,
+	 * they also report {@link #wasCommitted} as false.
+	 *
+	 * @return boolean True if the transaction was (unequivocally) committed
+	 * via this local transaction; false otherwise.
+	 * @throws HibernateException
+	 */
+	public boolean wasCommitted() throws HibernateException;
+	
+	/**
+	 * Is this transaction still active?
+	 * <p/>
+	 * Again, this only returns information in relation to the
+	 * local transaction, not the actual underlying transaction.
+	 *
+	 * @return boolean Treu if this local transaction is still active.
+	 */
+	public boolean isActive() throws HibernateException;
+
+	/**
+	 * Register a user synchronization callback for this transaction.
+	 *
+	 * @param synchronization The Synchronization callback to register.
+	 * @throws HibernateException
+	 */
+	public void registerSynchronization(Synchronization synchronization) 
+	throws HibernateException;
+
+	/**
+	 * Set the transaction timeout for any transaction started by
+	 * a subsequent call to <tt>begin()</tt> on this instance.
+	 *
+	 * @param seconds The number of seconds before a timeout.
+	 */
+	public void setTimeout(int seconds);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/TransactionException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/TransactionException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/TransactionException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: TransactionException.java 10312 2006-08-23 12:43:54Z steve.ebersole at jboss.com $
+package org.hibernate;
+
+/**
+ * Indicates that a transaction could not be begun, committed
+ * or rolled back.
+ *
+ * @see Transaction
+ * @author Anton van Straaten
+ */
+
+public class TransactionException extends HibernateException {
+
+	public TransactionException(String message, Throwable root) {
+		super(message,root);
+	}
+
+	public TransactionException(String message) {
+		super(message);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/TransientObjectException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/TransientObjectException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/TransientObjectException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+//$Id: TransientObjectException.java 6877 2005-05-23 15:00:25Z oneovthafew $
+package org.hibernate;
+
+/**
+ * Thrown when the user passes a transient instance to a <tt>Session</tt>
+ * method that expects a persistent instance.
+ *
+ * @author Gavin King
+ */
+
+public class TransientObjectException extends HibernateException {
+
+	public TransientObjectException(String s) {
+		super(s);
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/TypeMismatchException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/TypeMismatchException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/TypeMismatchException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+//$Id: $
+package org.hibernate;
+
+/**
+ * Used when a user provided type does not match the expected one
+ *
+ * @author Emmanuel Bernard
+ */
+public class TypeMismatchException extends HibernateException {
+	public TypeMismatchException(Throwable root) {
+		super( root );
+	}
+
+	public TypeMismatchException(String s) {
+		super( s );
+	}
+
+	public TypeMismatchException(String string, Throwable root) {
+		super( string, root );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/UnresolvableObjectException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/UnresolvableObjectException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/UnresolvableObjectException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+//$Id: UnresolvableObjectException.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate;
+
+import java.io.Serializable;
+
+import org.hibernate.pretty.MessageHelper;
+
+/**
+ * Thrown when Hibernate could not resolve an object by id, especially when
+ * loading an association.
+ *
+ * @author Gavin King
+ */
+public class UnresolvableObjectException extends HibernateException {
+
+	private final Serializable identifier;
+	private final String entityName;
+
+	public UnresolvableObjectException(Serializable identifier, String clazz) {
+		this("No row with the given identifier exists", identifier, clazz);
+	}
+	UnresolvableObjectException(String message, Serializable identifier, String clazz) {
+		super(message);
+		this.identifier = identifier;
+		this.entityName = clazz;
+	}
+	public Serializable getIdentifier() {
+		return identifier;
+	}
+
+	public String getMessage() {
+		return super.getMessage() + ": " +
+			MessageHelper.infoString(entityName, identifier);
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public static void throwIfNull(Object o, Serializable id, String clazz)
+	throws UnresolvableObjectException {
+		if (o==null) throw new UnresolvableObjectException(id, clazz);
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/WrongClassException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/WrongClassException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/WrongClassException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+//$Id: WrongClassException.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate;
+
+import java.io.Serializable;
+
+/**
+ * Thrown when <tt>Session.load()</tt> selects a row with
+ * the given primary key (identifier value) but the row's
+ * discriminator value specifies a subclass that is not
+ * assignable to the class requested by the user.
+ *
+ * @author Gavin King
+ */
+public class WrongClassException extends HibernateException {
+
+	private final Serializable identifier;
+	private final String entityName;
+
+	public WrongClassException(String msg, Serializable identifier, String clazz) {
+		super(msg);
+		this.identifier = identifier;
+		this.entityName = clazz;
+	}
+	public Serializable getIdentifier() {
+		return identifier;
+	}
+
+	public String getMessage() {
+		return "Object with id: " +
+			identifier +
+			" was not of the specified subclass: " +
+			entityName +
+			" (" + super.getMessage() + ")" ;
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/action/BulkOperationCleanupAction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/action/BulkOperationCleanupAction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/action/BulkOperationCleanupAction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,146 @@
+// $Id: BulkOperationCleanupAction.java 9897 2006-05-05 20:50:27Z max.andersen at jboss.com $
+package org.hibernate.action;
+
+import org.hibernate.HibernateException;
+import org.hibernate.metadata.ClassMetadata;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Iterator;
+import java.util.HashSet;
+import java.util.ArrayList;
+
+/**
+ * Implementation of BulkOperationCleanupAction.
+ *
+ * @author Steve Ebersole
+ */
+public class BulkOperationCleanupAction implements Executable, Serializable {
+
+	private final SessionImplementor session;
+
+	private final Set affectedEntityNames = new HashSet();
+	private final Set affectedCollectionRoles = new HashSet();
+	private final Serializable[] spaces;
+
+	public BulkOperationCleanupAction(SessionImplementor session, Queryable[] affectedQueryables) {
+		this.session = session;
+		// TODO : probably better to calculate these and pass them in, as it'll be more performant
+		ArrayList tmpSpaces = new ArrayList();
+		for ( int i = 0; i < affectedQueryables.length; i++ ) {
+			if ( affectedQueryables[i].hasCache() ) {
+				affectedEntityNames.add( affectedQueryables[i].getEntityName() );
+			}
+			Set roles = session.getFactory().getCollectionRolesByEntityParticipant( affectedQueryables[i].getEntityName() );
+			if ( roles != null ) {
+				affectedCollectionRoles.addAll( roles );
+			}
+			for ( int y = 0; y < affectedQueryables[i].getQuerySpaces().length; y++ ) {
+				tmpSpaces.add( affectedQueryables[i].getQuerySpaces()[y] );
+			}
+		}
+		this.spaces = new Serializable[ tmpSpaces.size() ];
+		for ( int i = 0; i < tmpSpaces.size(); i++ ) {
+			this.spaces[i] = ( Serializable ) tmpSpaces.get( i );
+		}
+	}
+	
+	/** Create an action that will evict collection and entity regions based on queryspaces (table names).
+	 *  TODO: cache the autodetected information and pass it in instead.
+	 **/
+	public BulkOperationCleanupAction(SessionImplementor session, Set querySpaces) {
+		this.session = session;
+
+		Set tmpSpaces = new HashSet(querySpaces);
+		SessionFactoryImplementor factory = session.getFactory();
+		Iterator iterator = factory.getAllClassMetadata().entrySet().iterator();
+		while ( iterator.hasNext() ) {
+			Map.Entry entry = (Map.Entry) iterator.next();
+			String entityName = (String) entry.getKey();
+			EntityPersister persister = factory.getEntityPersister( entityName );
+			Serializable[] entitySpaces = persister.getQuerySpaces();
+
+			if (affectedEntity( querySpaces, entitySpaces )) {
+				if ( persister.hasCache() ) {
+					affectedEntityNames.add( persister.getEntityName() );
+				}
+				Set roles = session.getFactory().getCollectionRolesByEntityParticipant( persister.getEntityName() );
+				if ( roles != null ) {
+					affectedCollectionRoles.addAll( roles );
+				}
+				for ( int y = 0; y < entitySpaces.length; y++ ) {
+					tmpSpaces.add( entitySpaces[y] );
+				}
+			}
+
+		}
+		this.spaces = (Serializable[]) tmpSpaces.toArray( new Serializable[tmpSpaces.size()] );		
+	}
+
+
+	/** returns true if no queryspaces or if there are a match */
+	private boolean affectedEntity(Set querySpaces, Serializable[] entitySpaces) {
+		if(querySpaces==null || querySpaces.isEmpty()) {
+			return true;
+		}
+		
+		for ( int i = 0; i < entitySpaces.length; i++ ) {
+			if ( querySpaces.contains( entitySpaces[i] ) ) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public void init() {
+		evictEntityRegions();
+		evictCollectionRegions();
+	}
+
+	public boolean hasAfterTransactionCompletion() {
+		return true;
+	}
+
+	public void afterTransactionCompletion(boolean success) throws HibernateException {
+		evictEntityRegions();
+		evictCollectionRegions();
+	}
+
+	public Serializable[] getPropertySpaces() {
+		return spaces;
+	}
+
+	public void beforeExecutions() throws HibernateException {
+		// nothing to do
+	}
+
+	public void execute() throws HibernateException {
+		// nothing to do		
+	}
+
+	private void evictEntityRegions() {
+		if ( affectedEntityNames != null ) {
+			Iterator itr = affectedEntityNames.iterator();
+			while ( itr.hasNext() ) {
+				final String entityName = ( String ) itr.next();
+				session.getFactory().evictEntity( entityName );
+			}
+		}
+	}
+
+	private void evictCollectionRegions() {
+		if ( affectedCollectionRoles != null ) {
+			Iterator itr = affectedCollectionRoles.iterator();
+			while ( itr.hasNext() ) {
+				final String roleName = ( String ) itr.next();
+				session.getFactory().evictCollection( roleName );
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionAction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionAction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionAction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,150 @@
+//$Id: CollectionAction.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.action;
+
+import org.hibernate.cache.access.SoftLock;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.util.StringHelper;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+
+/**
+ * Any action relating to insert/update/delete of a collection
+ * @author Gavin King
+ */
+public abstract class CollectionAction implements Executable, Serializable, Comparable {
+
+	private transient CollectionPersister persister;
+	private final Serializable key;
+	private Serializable finalKey;
+	private final SessionImplementor session;
+	private SoftLock lock;
+	private final String collectionRole;
+	private final PersistentCollection collection;
+
+	public CollectionAction(
+			final CollectionPersister persister, 
+			final PersistentCollection collection, 
+			final Serializable key, 
+			final SessionImplementor session) throws CacheException {
+		this.persister = persister;
+		this.session = session;
+		this.key = key;
+		this.collectionRole = persister.getRole();
+		this.collection = collection;
+	}
+	
+	protected PersistentCollection getCollection() {
+		return collection;
+	}
+
+	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+		ois.defaultReadObject();
+		persister = session.getFactory().getCollectionPersister( collectionRole );
+	}
+
+	public void afterTransactionCompletion(boolean success) throws CacheException {
+		if ( persister.hasCache() ) {
+			final CacheKey ck = new CacheKey( 
+					key, 
+					persister.getKeyType(), 
+					persister.getRole(), 
+					session.getEntityMode(), 
+					session.getFactory() 
+				);
+			persister.getCacheAccessStrategy().unlockItem( ck, lock );
+		}
+	}
+
+	public boolean hasAfterTransactionCompletion() {
+		return persister.hasCache();
+	}
+
+	public Serializable[] getPropertySpaces() {
+		return persister.getCollectionSpaces();
+	}
+
+	protected final CollectionPersister getPersister() {
+		return persister;
+	}
+
+	protected final Serializable getKey() {
+		finalKey = key;
+		if ( key instanceof DelayedPostInsertIdentifier ) {
+			// need to look it up from the persistence-context
+			finalKey = session.getPersistenceContext().getEntry( collection.getOwner() ).getId();
+			if ( finalKey == key ) {
+				// we may be screwed here since the collection action is about to execute
+				// and we do not know the final owner key value
+			}
+		}
+		return finalKey;
+	}
+
+	protected final SessionImplementor getSession() {
+		return session;
+	}
+
+	public final void beforeExecutions() throws CacheException {
+		// we need to obtain the lock before any actions are
+		// executed, since this may be an inverse="true"
+		// bidirectional association and it is one of the
+		// earlier entity actions which actually updates
+		// the database (this action is resposible for
+		// second-level cache invalidation only)
+		if ( persister.hasCache() ) {
+			final CacheKey ck = new CacheKey( 
+					key, 
+					persister.getKeyType(), 
+					persister.getRole(), 
+					session.getEntityMode(), 
+					session.getFactory() 
+			);
+			lock = persister.getCacheAccessStrategy().lockItem( ck, null );
+		}
+	}
+
+	protected final void evict() throws CacheException {
+		if ( persister.hasCache() ) {
+			CacheKey ck = new CacheKey( 
+					key, 
+					persister.getKeyType(), 
+					persister.getRole(), 
+					session.getEntityMode(), 
+					session.getFactory() 
+				);
+			persister.getCacheAccessStrategy().remove( ck );
+		}
+	}
+
+	public String toString() {
+		return StringHelper.unqualify( getClass().getName() ) + 
+				MessageHelper.infoString( collectionRole, key );
+	}
+
+	public int compareTo(Object other) {
+		CollectionAction action = ( CollectionAction ) other;
+		//sort first by role name
+		int roleComparison = collectionRole.compareTo( action.collectionRole );
+		if ( roleComparison != 0 ) {
+			return roleComparison;
+		}
+		else {
+			//then by fk
+			return persister.getKeyType()
+					.compare( key, action.key, session.getEntityMode() );
+		}
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionRecreateAction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionRecreateAction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionRecreateAction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+//$Id: CollectionRecreateAction.java 7147 2005-06-15 13:20:13Z oneovthafew $
+package org.hibernate.action;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cache.CacheException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+
+import java.io.Serializable;
+
+public final class CollectionRecreateAction extends CollectionAction {
+
+	public CollectionRecreateAction(
+				final PersistentCollection collection, 
+				final CollectionPersister persister, 
+				final Serializable id, 
+				final SessionImplementor session)
+			throws CacheException {
+		super( persister, collection, id, session );
+	}
+
+	public void execute() throws HibernateException {
+		final PersistentCollection collection = getCollection();
+		
+		getPersister().recreate( collection, getKey(), getSession() );
+		
+		getSession().getPersistenceContext()
+				.getCollectionEntry(collection)
+				.afterAction(collection);
+		
+		evict();
+
+		if ( getSession().getFactory().getStatistics().isStatisticsEnabled() ) {
+			getSession().getFactory().getStatisticsImplementor()
+					.recreateCollection( getPersister().getRole() );
+		}
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionRemoveAction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionRemoveAction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionRemoveAction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+//$Id: CollectionRemoveAction.java 7147 2005-06-15 13:20:13Z oneovthafew $
+package org.hibernate.action;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cache.CacheException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+
+import java.io.Serializable;
+
+public final class CollectionRemoveAction extends CollectionAction {
+
+	private boolean emptySnapshot;
+
+	public CollectionRemoveAction(
+				final PersistentCollection collection,
+				final CollectionPersister persister,
+				final Serializable id, 
+				final boolean emptySnapshot, 
+				final SessionImplementor session)
+			throws CacheException {
+		super( persister, collection, id, session );
+		this.emptySnapshot = emptySnapshot;
+	}
+
+	public void execute() throws HibernateException {
+		if ( !emptySnapshot ) getPersister().remove( getKey(), getSession() );
+		
+		final PersistentCollection collection = getCollection();
+		if (collection!=null) {
+			getSession().getPersistenceContext()
+				.getCollectionEntry(collection)
+				.afterAction(collection);
+		}
+		
+		evict();
+
+		if ( getSession().getFactory().getStatistics().isStatisticsEnabled() ) {
+			getSession().getFactory().getStatisticsImplementor()
+					.removeCollection( getPersister().getRole() );
+		}
+	}
+
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionUpdateAction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionUpdateAction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/action/CollectionUpdateAction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+//$Id: CollectionUpdateAction.java 7631 2005-07-24 21:26:21Z oneovthafew $
+package org.hibernate.action;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.cache.CacheException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.pretty.MessageHelper;
+
+import java.io.Serializable;
+
+public final class CollectionUpdateAction extends CollectionAction {
+
+	private final boolean emptySnapshot;
+
+	public CollectionUpdateAction(
+				final PersistentCollection collection,
+				final CollectionPersister persister,
+				final Serializable id,
+				final boolean emptySnapshot,
+				final SessionImplementor session)
+			throws CacheException {
+		super( persister, collection, id, session );
+		this.emptySnapshot = emptySnapshot;
+	}
+
+	public void execute() throws HibernateException {
+		final Serializable id = getKey();
+		final SessionImplementor session = getSession();
+		final CollectionPersister persister = getPersister();
+		final PersistentCollection collection = getCollection();
+		boolean affectedByFilters = persister.isAffectedByEnabledFilters(session);
+
+		if ( !collection.wasInitialized() ) {
+			if ( !collection.hasQueuedOperations() ) throw new AssertionFailure( "no queued adds" );
+			//do nothing - we only need to notify the cache...
+		}
+		else if ( !affectedByFilters && collection.empty() ) {
+			if ( !emptySnapshot ) persister.remove( id, session );
+		}
+		else if ( collection.needsRecreate(persister) ) {
+			if (affectedByFilters) {
+				throw new HibernateException(
+					"cannot recreate collection while filter is enabled: " + 
+					MessageHelper.collectionInfoString( persister, id, persister.getFactory() )
+				);
+			}
+			if ( !emptySnapshot ) persister.remove( id, session );
+			persister.recreate( collection, id, session );
+		}
+		else {
+			persister.deleteRows( collection, id, session );
+			persister.updateRows( collection, id, session );
+			persister.insertRows( collection, id, session );
+		}
+
+		getSession().getPersistenceContext()
+			.getCollectionEntry(collection)
+			.afterAction(collection);
+
+		evict();
+
+		if ( getSession().getFactory().getStatistics().isStatisticsEnabled() ) {
+			getSession().getFactory().getStatisticsImplementor().
+					updateCollection( getPersister().getRole() );
+		}
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/action/DelayedPostInsertIdentifier.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/action/DelayedPostInsertIdentifier.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/action/DelayedPostInsertIdentifier.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+package org.hibernate.action;
+
+import java.io.Serializable;
+
+/**
+ * Acts as a stand-in for an entity identifier which is supposed to be
+ * generated on insert (like an IDENTITY column) where the insert needed to
+ * be delayed because we were outside a transaction when the persist
+ * occurred (save currently still performs the insert).
+ * <p/>
+ * The stand-in is only used within the {@link org.hibernate.engine.PersistenceContext}
+ * in order to distinguish one instance from another; it is never injected into
+ * the entity instance or returned to the client...
+ *
+ * @author Steve Ebersole
+ */
+public class DelayedPostInsertIdentifier implements Serializable {
+	private static long SEQUENCE = 0;
+	private final long sequence;
+
+	public DelayedPostInsertIdentifier() {
+		synchronized( DelayedPostInsertIdentifier.class ) {
+			if ( SEQUENCE == Long.MAX_VALUE ) {
+				SEQUENCE = 0;
+			}
+			this.sequence = SEQUENCE++;
+		}
+	}
+
+	public boolean equals(Object o) {
+		if ( this == o ) {
+			return true;
+		}
+		if ( o == null || getClass() != o.getClass() ) {
+			return false;
+		}
+		final DelayedPostInsertIdentifier that = ( DelayedPostInsertIdentifier ) o;
+		return sequence == that.sequence;
+	}
+
+	public int hashCode() {
+		return ( int ) ( sequence ^ ( sequence >>> 32 ) );
+	}
+
+	public String toString() {
+		return "<delayed:" + sequence + ">";
+
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityAction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityAction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityAction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,136 @@
+//$Id: EntityAction.java 11402 2007-04-11 14:24:35Z steve.ebersole at jboss.com $
+package org.hibernate.action;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.util.StringHelper;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+
+/**
+ * Base class for actions relating to insert/update/delete of an entity
+ * instance.
+ *
+ * @author Gavin King
+ */
+public abstract class EntityAction implements Executable, Serializable, Comparable {
+
+	private final String entityName;
+	private final Serializable id;
+	private final Object instance;
+	private final SessionImplementor session;
+
+	private transient EntityPersister persister;
+
+	/**
+	 * Instantiate an action.
+	 *
+	 * @param session The session from which this action is coming.
+	 * @param id The id of the entity
+	 * @param instance The entiyt instance
+	 * @param persister The entity persister
+	 */
+	protected EntityAction(SessionImplementor session, Serializable id, Object instance, EntityPersister persister) {
+		this.entityName = persister.getEntityName();
+		this.id = id;
+		this.instance = instance;
+		this.session = session;
+		this.persister = persister;
+	}
+
+	protected abstract boolean hasPostCommitEventListeners();
+
+	/**
+	 * entity name accessor
+	 *
+	 * @return The entity name
+	 */
+	public String getEntityName() {
+		return entityName;
+	}
+
+	/**
+	 * entity id accessor
+	 *
+	 * @return The entity id
+	 */
+	public final Serializable getId() {
+		if ( id instanceof DelayedPostInsertIdentifier ) {
+			return session.getPersistenceContext().getEntry( instance ).getId();
+		}
+		return id;
+	}
+
+	/**
+	 * entity instance accessor
+	 *
+	 * @return The entity instance
+	 */
+	public final Object getInstance() {
+		return instance;
+	}
+
+	/**
+	 * originating session accessor
+	 *
+	 * @return The session from which this action originated.
+	 */
+	public final SessionImplementor getSession() {
+		return session;
+	}
+
+	/**
+	 * entity persister accessor
+	 *
+	 * @return The entity persister
+	 */
+	public final EntityPersister getPersister() {
+		return persister;
+	}
+
+	public final Serializable[] getPropertySpaces() {
+		return persister.getPropertySpaces();
+	}
+
+	public void beforeExecutions() {
+		throw new AssertionFailure( "beforeExecutions() called for non-collection action" );
+	}
+
+	public boolean hasAfterTransactionCompletion() {
+		return persister.hasCache() || hasPostCommitEventListeners();
+	}
+
+	public String toString() {
+		return StringHelper.unqualify( getClass().getName() ) + MessageHelper.infoString( entityName, id );
+	}
+
+	public int compareTo(Object other) {
+		EntityAction action = ( EntityAction ) other;
+		//sort first by entity name
+		int roleComparison = entityName.compareTo( action.entityName );
+		if ( roleComparison != 0 ) {
+			return roleComparison;
+		}
+		else {
+			//then by id
+			return persister.getIdentifierType().compare( id, action.id, session.getEntityMode() );
+		}
+	}
+
+	/**
+	 * Serialization...
+	 *
+	 * @param ois Thed object stream
+	 * @throws IOException Problem performing the default stream reading
+	 * @throws ClassNotFoundException Problem performing the default stream reading
+	 */
+	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+		ois.defaultReadObject();
+		persister = session.getFactory().getEntityPersister( entityName );
+	}
+}
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityDeleteAction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityDeleteAction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityDeleteAction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,174 @@
+//$Id: EntityDeleteAction.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.action;
+
+import java.io.Serializable;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.cache.access.SoftLock;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.event.PostDeleteEvent;
+import org.hibernate.event.PostDeleteEventListener;
+import org.hibernate.event.PreDeleteEvent;
+import org.hibernate.event.PreDeleteEventListener;
+import org.hibernate.event.EventSource;
+import org.hibernate.persister.entity.EntityPersister;
+
+public final class EntityDeleteAction extends EntityAction {
+
+	private final Object version;
+	private SoftLock lock;
+	private final boolean isCascadeDeleteEnabled;
+	private final Object[] state;
+
+	public EntityDeleteAction(
+			final Serializable id,
+	        final Object[] state,
+	        final Object version,
+	        final Object instance,
+	        final EntityPersister persister,
+	        final boolean isCascadeDeleteEnabled,
+	        final SessionImplementor session) {
+		super( session, id, instance, persister );
+		this.version = version;
+		this.isCascadeDeleteEnabled = isCascadeDeleteEnabled;
+		this.state = state;
+	}
+
+	public void execute() throws HibernateException {
+		Serializable id = getId();
+		EntityPersister persister = getPersister();
+		SessionImplementor session = getSession();
+		Object instance = getInstance();
+
+		boolean veto = preDelete();
+
+		Object version = this.version;
+		if ( persister.isVersionPropertyGenerated() ) {
+			// we need to grab the version value from the entity, otherwise
+			// we have issues with generated-version entities that may have
+			// multiple actions queued during the same flush
+			version = persister.getVersion( instance, session.getEntityMode() );
+		}
+
+		final CacheKey ck;
+		if ( persister.hasCache() ) {
+			ck = new CacheKey( 
+					id, 
+					persister.getIdentifierType(), 
+					persister.getRootEntityName(), 
+					session.getEntityMode(), 
+					session.getFactory() 
+				);
+			lock = persister.getCacheAccessStrategy().lockItem( ck, version );
+		}
+		else {
+			ck = null;
+		}
+
+		if ( !isCascadeDeleteEnabled && !veto ) {
+			persister.delete( id, version, instance, session );
+		}
+		
+		//postDelete:
+		// After actually deleting a row, record the fact that the instance no longer 
+		// exists on the database (needed for identity-column key generation), and
+		// remove it from the session cache
+		final PersistenceContext persistenceContext = session.getPersistenceContext();
+		EntityEntry entry = persistenceContext.removeEntry( instance );
+		if ( entry == null ) {
+			throw new AssertionFailure( "possible nonthreadsafe access to session" );
+		}
+		entry.postDelete();
+
+		EntityKey key = new EntityKey( entry.getId(), entry.getPersister(), session.getEntityMode() );
+		persistenceContext.removeEntity(key);
+		persistenceContext.removeProxy(key);
+		
+		if ( persister.hasCache() ) persister.getCacheAccessStrategy().remove( ck );
+
+		postDelete();
+
+		if ( getSession().getFactory().getStatistics().isStatisticsEnabled() && !veto ) {
+			getSession().getFactory().getStatisticsImplementor()
+					.deleteEntity( getPersister().getEntityName() );
+		}
+	}
+
+	private boolean preDelete() {
+		PreDeleteEventListener[] preListeners = getSession().getListeners()
+				.getPreDeleteEventListeners();
+		boolean veto = false;
+		if (preListeners.length>0) {
+			PreDeleteEvent preEvent = new PreDeleteEvent( getInstance(), getId(), state, getPersister() );
+			for ( int i = 0; i < preListeners.length; i++ ) {
+				veto = preListeners[i].onPreDelete(preEvent) || veto;
+			}
+		}
+		return veto;
+	}
+
+	private void postDelete() {
+		PostDeleteEventListener[] postListeners = getSession().getListeners()
+				.getPostDeleteEventListeners();
+		if (postListeners.length>0) {
+			PostDeleteEvent postEvent = new PostDeleteEvent(
+					getInstance(),
+					getId(),
+					state,
+					getPersister(),
+					(EventSource) getSession() 
+			);
+			for ( int i = 0; i < postListeners.length; i++ ) {
+				postListeners[i].onPostDelete(postEvent);
+			}
+		}
+	}
+
+	private void postCommitDelete() {
+		PostDeleteEventListener[] postListeners = getSession().getListeners()
+				.getPostCommitDeleteEventListeners();
+		if (postListeners.length>0) {
+			PostDeleteEvent postEvent = new PostDeleteEvent(
+					getInstance(),
+					getId(),
+					state,
+					getPersister(),
+					(EventSource) getSession()
+			);
+			for ( int i = 0; i < postListeners.length; i++ ) {
+				postListeners[i].onPostDelete(postEvent);
+			}
+		}
+	}
+
+	public void afterTransactionCompletion(boolean success) throws HibernateException {
+		if ( getPersister().hasCache() ) {
+			final CacheKey ck = new CacheKey( 
+					getId(), 
+					getPersister().getIdentifierType(), 
+					getPersister().getRootEntityName(),
+					getSession().getEntityMode(), 
+					getSession().getFactory()
+				);
+			getPersister().getCacheAccessStrategy().unlockItem( ck, lock );
+		}
+		postCommitDelete();
+	}
+
+	protected boolean hasPostCommitEventListeners() {
+		return getSession().getListeners().getPostCommitDeleteEventListeners().length>0;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityIdentityInsertAction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityIdentityInsertAction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityIdentityInsertAction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,159 @@
+//$Id: EntityIdentityInsertAction.java 10680 2006-11-01 22:53:30Z epbernard $
+package org.hibernate.action;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.event.PostInsertEvent;
+import org.hibernate.event.PostInsertEventListener;
+import org.hibernate.event.PreInsertEvent;
+import org.hibernate.event.PreInsertEventListener;
+import org.hibernate.event.EventSource;
+import org.hibernate.persister.entity.EntityPersister;
+
+public final class EntityIdentityInsertAction extends EntityAction {
+	private final Object[] state;
+	private final boolean isDelayed;
+	private final EntityKey delayedEntityKey;
+	//private CacheEntry cacheEntry;
+	private Serializable generatedId;
+
+	public EntityIdentityInsertAction(
+			Object[] state,
+	        Object instance,
+	        EntityPersister persister,
+	        SessionImplementor session,
+	        boolean isDelayed) throws HibernateException {
+		super( session, null, instance, persister );
+		this.state = state;
+		this.isDelayed = isDelayed;
+		delayedEntityKey = isDelayed ? generateDelayedEntityKey() : null;
+	}
+
+	public void execute() throws HibernateException {
+		
+		final EntityPersister persister = getPersister();
+		final SessionImplementor session = getSession();
+		final Object instance = getInstance();
+		
+		boolean veto = preInsert();
+
+		// Don't need to lock the cache here, since if someone
+		// else inserted the same pk first, the insert would fail
+
+		if ( !veto ) {
+			generatedId = persister.insert( state, instance, session );
+			if ( persister.hasInsertGeneratedProperties() ) {
+				persister.processInsertGeneratedProperties( generatedId, instance, state, session );
+			}
+			//need to do that here rather than in the save event listener to let
+			//the post insert events to have a id-filled entity when IDENTITY is used (EJB3)
+			persister.setIdentifier( instance, generatedId, session.getEntityMode() );
+		}
+
+
+		//TODO: this bit actually has to be called after all cascades!
+		//      but since identity insert is called *synchronously*,
+		//      instead of asynchronously as other actions, it isn't
+		/*if ( persister.hasCache() && !persister.isCacheInvalidationRequired() ) {
+			cacheEntry = new CacheEntry(object, persister, session);
+			persister.getCache().insert(generatedId, cacheEntry);
+		}*/
+		
+		postInsert();
+
+		if ( session.getFactory().getStatistics().isStatisticsEnabled() && !veto ) {
+			session.getFactory().getStatisticsImplementor()
+					.insertEntity( getPersister().getEntityName() );
+		}
+
+	}
+
+	private void postInsert() {
+		if ( isDelayed ) {
+			getSession().getPersistenceContext().replaceDelayedEntityIdentityInsertKeys( delayedEntityKey, generatedId );
+		}
+		PostInsertEventListener[] postListeners = getSession().getListeners()
+				.getPostInsertEventListeners();
+		if (postListeners.length>0) {
+			PostInsertEvent postEvent = new PostInsertEvent(
+					getInstance(),
+					generatedId,
+					state,
+					getPersister(),
+					(EventSource) getSession()
+			);
+			for ( int i = 0; i < postListeners.length; i++ ) {
+				postListeners[i].onPostInsert(postEvent);
+			}
+		}
+	}
+
+	private void postCommitInsert() {
+		PostInsertEventListener[] postListeners = getSession().getListeners()
+				.getPostCommitInsertEventListeners();
+		if (postListeners.length>0) {
+			PostInsertEvent postEvent = new PostInsertEvent(
+					getInstance(),
+					generatedId,
+					state,
+					getPersister(),
+					(EventSource) getSession() 
+			);
+			for ( int i = 0; i < postListeners.length; i++ ) {
+				postListeners[i].onPostInsert(postEvent);
+			}
+		}
+	}
+
+	private boolean preInsert() {
+		PreInsertEventListener[] preListeners = getSession().getListeners()
+				.getPreInsertEventListeners();
+		boolean veto = false;
+		if (preListeners.length>0) {
+			PreInsertEvent preEvent = new PreInsertEvent( getInstance(), null, state, getPersister(), getSession() );
+			for ( int i = 0; i < preListeners.length; i++ ) {
+				veto = preListeners[i].onPreInsert(preEvent) || veto;
+			}
+		}
+		return veto;
+	}
+
+	//Make 100% certain that this is called before any subsequent ScheduledUpdate.afterTransactionCompletion()!!
+	public void afterTransactionCompletion(boolean success) throws HibernateException {
+		//TODO: reenable if we also fix the above todo
+		/*EntityPersister persister = getEntityPersister();
+		if ( success && persister.hasCache() && !persister.isCacheInvalidationRequired() ) {
+			persister.getCache().afterInsert( getGeneratedId(), cacheEntry );
+		}*/
+		postCommitInsert();
+	}
+
+	public boolean hasAfterTransactionCompletion() {
+		//TODO: simply remove this override
+		//      if we fix the above todos
+		return hasPostCommitEventListeners();
+	}
+
+	protected boolean hasPostCommitEventListeners() {
+		return getSession().getListeners().getPostCommitInsertEventListeners().length>0;
+	}
+	
+	public final Serializable getGeneratedId() {
+		return generatedId;
+	}
+
+	public EntityKey getDelayedEntityKey() {
+		return delayedEntityKey;
+	}
+
+	private synchronized EntityKey generateDelayedEntityKey() {
+		if ( !isDelayed ) {
+			throw new AssertionFailure( "cannot request delayed entity-key for non-delayed post-insert-id generation" );
+		}
+		return new EntityKey( new DelayedPostInsertIdentifier(), getPersister(), getSession().getEntityMode() );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityInsertAction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityInsertAction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityInsertAction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,199 @@
+//$Id: EntityInsertAction.java 11402 2007-04-11 14:24:35Z steve.ebersole at jboss.com $
+package org.hibernate.action;
+
+import java.io.Serializable;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.cache.entry.CacheEntry;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.Versioning;
+import org.hibernate.event.PostInsertEvent;
+import org.hibernate.event.PostInsertEventListener;
+import org.hibernate.event.PreInsertEvent;
+import org.hibernate.event.PreInsertEventListener;
+import org.hibernate.event.EventSource;
+import org.hibernate.persister.entity.EntityPersister;
+
+public final class EntityInsertAction extends EntityAction {
+
+	private Object[] state;
+	private Object version;
+	private Object cacheEntry;
+
+	public EntityInsertAction(
+	        Serializable id,
+	        Object[] state,
+	        Object instance,
+	        Object version,
+	        EntityPersister persister,
+	        SessionImplementor session) throws HibernateException {
+		super( session, id, instance, persister );
+		this.state = state;
+		this.version = version;
+	}
+
+	public Object[] getState() {
+		return state;
+	}
+
+	public void execute() throws HibernateException {
+		EntityPersister persister = getPersister();
+		SessionImplementor session = getSession();
+		Object instance = getInstance();
+		Serializable id = getId();
+
+		boolean veto = preInsert();
+
+		// Don't need to lock the cache here, since if someone
+		// else inserted the same pk first, the insert would fail
+
+		if ( !veto ) {
+			
+			persister.insert( id, state, instance, session );
+		
+			EntityEntry entry = session.getPersistenceContext().getEntry( instance );
+			if ( entry == null ) {
+				throw new AssertionFailure( "possible nonthreadsafe access to session" );
+			}
+			
+			entry.postInsert();
+	
+			if ( persister.hasInsertGeneratedProperties() ) {
+				persister.processInsertGeneratedProperties( id, instance, state, session );
+				if ( persister.isVersionPropertyGenerated() ) {
+					version = Versioning.getVersion(state, persister);
+				}
+				entry.postUpdate(instance, state, version);
+			}
+			
+		}
+
+		final SessionFactoryImplementor factory = getSession().getFactory();
+
+		if ( isCachePutEnabled( persister, session ) ) {
+			
+			CacheEntry ce = new CacheEntry(
+					state,
+					persister, 
+					persister.hasUninitializedLazyProperties( instance, session.getEntityMode() ),
+					version,
+					session,
+					instance
+				);
+			
+			cacheEntry = persister.getCacheEntryStructure().structure(ce);
+			final CacheKey ck = new CacheKey( 
+					id, 
+					persister.getIdentifierType(), 
+					persister.getRootEntityName(), 
+					session.getEntityMode(), 
+					session.getFactory() 
+				);
+//			boolean put = persister.getCache().insert(ck, cacheEntry);
+			boolean put = persister.getCacheAccessStrategy().insert( ck, cacheEntry, version );
+			
+			if ( put && factory.getStatistics().isStatisticsEnabled() ) {
+				factory.getStatisticsImplementor().secondLevelCachePut( getPersister().getCacheAccessStrategy().getRegion().getName() );
+			}
+			
+		}
+
+		postInsert();
+
+		if ( factory.getStatistics().isStatisticsEnabled() && !veto ) {
+			factory.getStatisticsImplementor()
+					.insertEntity( getPersister().getEntityName() );
+		}
+
+	}
+
+	private void postInsert() {
+		PostInsertEventListener[] postListeners = getSession().getListeners()
+				.getPostInsertEventListeners();
+		if ( postListeners.length > 0 ) {
+			PostInsertEvent postEvent = new PostInsertEvent(
+					getInstance(),
+					getId(),
+					state,
+					getPersister(),
+					(EventSource) getSession()
+			);
+			for ( int i = 0; i < postListeners.length; i++ ) {
+				postListeners[i].onPostInsert(postEvent);
+			}
+		}
+	}
+
+	private void postCommitInsert() {
+		PostInsertEventListener[] postListeners = getSession().getListeners()
+				.getPostCommitInsertEventListeners();
+		if ( postListeners.length > 0 ) {
+			PostInsertEvent postEvent = new PostInsertEvent(
+					getInstance(),
+					getId(),
+					state,
+					getPersister(),
+					(EventSource) getSession() 
+			);
+			for ( int i = 0; i < postListeners.length; i++ ) {
+				postListeners[i].onPostInsert(postEvent);
+			}
+		}
+	}
+
+	private boolean preInsert() {
+		PreInsertEventListener[] preListeners = getSession().getListeners()
+				.getPreInsertEventListeners();
+		boolean veto = false;
+		if (preListeners.length>0) {
+			PreInsertEvent preEvent = new PreInsertEvent( getInstance(), getId(), state, getPersister(), getSession() );
+			for ( int i = 0; i < preListeners.length; i++ ) {
+				veto = preListeners[i].onPreInsert(preEvent) || veto;
+			}
+		}
+		return veto;
+	}
+
+	//Make 100% certain that this is called before any subsequent ScheduledUpdate.afterTransactionCompletion()!!
+	public void afterTransactionCompletion(boolean success) throws HibernateException {
+		EntityPersister persister = getPersister();
+		if ( success && isCachePutEnabled( persister, getSession() ) ) {
+			final CacheKey ck = new CacheKey( 
+					getId(), 
+					persister.getIdentifierType(), 
+					persister.getRootEntityName(), 
+					getSession().getEntityMode(), 
+					getSession().getFactory() 
+				);
+			boolean put = persister.getCacheAccessStrategy().afterInsert( ck, cacheEntry, version );
+			
+			if ( put && getSession().getFactory().getStatistics().isStatisticsEnabled() ) {
+				getSession().getFactory().getStatisticsImplementor()
+						.secondLevelCachePut( getPersister().getCacheAccessStrategy().getRegion().getName() );
+			}
+		}
+		postCommitInsert();
+	}
+
+	protected boolean hasPostCommitEventListeners() {
+		return getSession().getListeners().getPostCommitInsertEventListeners().length>0;
+	}
+	
+	private boolean isCachePutEnabled(EntityPersister persister, SessionImplementor session) {
+		return persister.hasCache() && 
+				!persister.isCacheInvalidationRequired() && 
+				session.getCacheMode().isPutEnabled();
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityUpdateAction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityUpdateAction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/action/EntityUpdateAction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,257 @@
+//$Id: EntityUpdateAction.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.action;
+
+import java.io.Serializable;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.cache.access.SoftLock;
+import org.hibernate.cache.entry.CacheEntry;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.Status;
+import org.hibernate.engine.Versioning;
+import org.hibernate.event.PostUpdateEvent;
+import org.hibernate.event.PostUpdateEventListener;
+import org.hibernate.event.PreUpdateEvent;
+import org.hibernate.event.PreUpdateEventListener;
+import org.hibernate.event.EventSource;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.type.TypeFactory;
+
+public final class EntityUpdateAction extends EntityAction {
+
+	private final Object[] state;
+	private final Object[] previousState;
+	private final Object previousVersion;
+	private Object nextVersion;
+	private final int[] dirtyFields;
+	private final boolean hasDirtyCollection;
+	private final Object rowId;
+	private Object cacheEntry;
+	private SoftLock lock;
+
+	public EntityUpdateAction(
+	        final Serializable id,
+	        final Object[] state,
+	        final int[] dirtyProperties,
+	        final boolean hasDirtyCollection,
+	        final Object[] previousState,
+	        final Object previousVersion,
+	        final Object nextVersion,
+	        final Object instance,
+	        final Object rowId,
+	        final EntityPersister persister,
+	        final SessionImplementor session) throws HibernateException {
+		super( session, id, instance, persister );
+		this.state = state;
+		this.previousState = previousState;
+		this.previousVersion = previousVersion;
+		this.nextVersion = nextVersion;
+		this.dirtyFields = dirtyProperties;
+		this.hasDirtyCollection = hasDirtyCollection;
+		this.rowId = rowId;
+	}
+
+	public void execute() throws HibernateException {
+		Serializable id = getId();
+		EntityPersister persister = getPersister();
+		SessionImplementor session = getSession();
+		Object instance = getInstance();
+
+		boolean veto = preUpdate();
+
+		final SessionFactoryImplementor factory = getSession().getFactory();
+		Object previousVersion = this.previousVersion;
+		if ( persister.isVersionPropertyGenerated() ) {
+			// we need to grab the version value from the entity, otherwise
+			// we have issues with generated-version entities that may have
+			// multiple actions queued during the same flush
+			previousVersion = persister.getVersion( instance, session.getEntityMode() );
+		}
+		
+		final CacheKey ck;
+		if ( persister.hasCache() ) {
+			ck = new CacheKey( 
+					id, 
+					persister.getIdentifierType(), 
+					persister.getRootEntityName(), 
+					session.getEntityMode(), 
+					session.getFactory() 
+			);
+			lock = persister.getCacheAccessStrategy().lockItem( ck, previousVersion );
+		}
+		else {
+			ck = null;
+		}
+
+		if ( !veto ) {
+			persister.update( 
+					id, 
+					state, 
+					dirtyFields, 
+					hasDirtyCollection, 
+					previousState, 
+					previousVersion, 
+					instance, 
+					rowId, 
+					session 
+			);
+		}
+
+		EntityEntry entry = getSession().getPersistenceContext().getEntry( instance );
+		if ( entry == null ) {
+			throw new AssertionFailure( "possible nonthreadsafe access to session" );
+		}
+		
+		if ( entry.getStatus()==Status.MANAGED || persister.isVersionPropertyGenerated() ) {
+			// get the updated snapshot of the entity state by cloning current state;
+			// it is safe to copy in place, since by this time no-one else (should have)
+			// has a reference  to the array
+			TypeFactory.deepCopy(
+					state,
+					persister.getPropertyTypes(),
+					persister.getPropertyCheckability(),
+					state,
+					session
+			);
+			if ( persister.hasUpdateGeneratedProperties() ) {
+				// this entity defines proeprty generation, so process those generated
+				// values...
+				persister.processUpdateGeneratedProperties( id, instance, state, session );
+				if ( persister.isVersionPropertyGenerated() ) {
+					nextVersion = Versioning.getVersion( state, persister );
+				}
+			}
+			// have the entity entry perform post-update processing, passing it the
+			// update state and the new version (if one).
+			entry.postUpdate( instance, state, nextVersion );
+		}
+
+		if ( persister.hasCache() ) {
+			if ( persister.isCacheInvalidationRequired() || entry.getStatus()!=Status.MANAGED ) {
+				persister.getCacheAccessStrategy().remove( ck );
+			}
+			else {
+				//TODO: inefficient if that cache is just going to ignore the updated state!
+				CacheEntry ce = new CacheEntry(
+						state, 
+						persister, 
+						persister.hasUninitializedLazyProperties( instance, session.getEntityMode() ), 
+						nextVersion,
+						getSession(),
+						instance
+				);
+				cacheEntry = persister.getCacheEntryStructure().structure( ce );
+				boolean put = persister.getCacheAccessStrategy().update( ck, cacheEntry, nextVersion, previousVersion );
+				if ( put && factory.getStatistics().isStatisticsEnabled() ) {
+					factory.getStatisticsImplementor().secondLevelCachePut( getPersister().getCacheAccessStrategy().getRegion().getName() );
+				}
+			}
+		}
+
+		postUpdate();
+
+		if ( factory.getStatistics().isStatisticsEnabled() && !veto ) {
+			factory.getStatisticsImplementor()
+					.updateEntity( getPersister().getEntityName() );
+		}
+	}
+
+	private void postUpdate() {
+		PostUpdateEventListener[] postListeners = getSession().getListeners()
+				.getPostUpdateEventListeners();
+		if (postListeners.length>0) {
+			PostUpdateEvent postEvent = new PostUpdateEvent( 
+					getInstance(), 
+					getId(), 
+					state, 
+					previousState, 
+					getPersister(),
+					(EventSource) getSession() 
+				);
+			for ( int i = 0; i < postListeners.length; i++ ) {
+				postListeners[i].onPostUpdate(postEvent);
+			}
+		}
+	}
+
+	private void postCommitUpdate() {
+		PostUpdateEventListener[] postListeners = getSession().getListeners()
+				.getPostCommitUpdateEventListeners();
+		if (postListeners.length>0) {
+			PostUpdateEvent postEvent = new PostUpdateEvent( 
+					getInstance(), 
+					getId(), 
+					state, 
+					previousState, 
+					getPersister(),
+					(EventSource) getSession()
+				);
+			for ( int i = 0; i < postListeners.length; i++ ) {
+				postListeners[i].onPostUpdate(postEvent);
+			}
+		}
+	}
+
+	private boolean preUpdate() {
+		PreUpdateEventListener[] preListeners = getSession().getListeners()
+				.getPreUpdateEventListeners();
+		boolean veto = false;
+		if (preListeners.length>0) {
+			PreUpdateEvent preEvent = new PreUpdateEvent( 
+					getInstance(), 
+					getId(), 
+					state, 
+					previousState, 
+					getPersister(),
+					getSession()
+				);
+			for ( int i = 0; i < preListeners.length; i++ ) {
+				veto = preListeners[i].onPreUpdate(preEvent) || veto;
+			}
+		}
+		return veto;
+	}
+
+	public void afterTransactionCompletion(boolean success) throws CacheException {
+		EntityPersister persister = getPersister();
+		if ( persister.hasCache() ) {
+			
+			final CacheKey ck = new CacheKey( 
+					getId(), 
+					persister.getIdentifierType(), 
+					persister.getRootEntityName(), 
+					getSession().getEntityMode(), 
+					getSession().getFactory() 
+				);
+			
+			if ( success && cacheEntry!=null /*!persister.isCacheInvalidationRequired()*/ ) {
+				boolean put = persister.getCacheAccessStrategy().afterUpdate( ck, cacheEntry, nextVersion, previousVersion, lock );
+				
+				if ( put && getSession().getFactory().getStatistics().isStatisticsEnabled() ) {
+					getSession().getFactory().getStatisticsImplementor().secondLevelCachePut( getPersister().getCacheAccessStrategy().getRegion().getName() );
+				}
+			}
+			else {
+				persister.getCacheAccessStrategy().unlockItem( ck, lock );
+			}
+		}
+		postCommitUpdate();
+	}
+
+	protected boolean hasPostCommitEventListeners() {
+		return getSession().getListeners().getPostCommitUpdateEventListeners().length>0;
+	}
+	
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/action/Executable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/action/Executable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/action/Executable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+//$Id: Executable.java 6607 2005-04-29 15:26:11Z oneovthafew $
+package org.hibernate.action;
+
+import org.hibernate.HibernateException;
+
+import java.io.Serializable;
+
+/**
+ * An operation which may be scheduled for later execution.
+ * Usually, the operation is a database insert/update/delete,
+ * together with required second-level cache management.
+ * 
+ * @author Gavin King
+ */
+public interface Executable {
+	/**
+	 * Called before executing any actions
+	 */
+	public void beforeExecutions() throws HibernateException;
+	/**
+	 * Execute this action
+	 */
+	public void execute() throws HibernateException;
+	/**
+	 * Do we need to retain this instance until after the
+	 * transaction completes?
+	 * @return false if this class defines a no-op
+	 * <tt>hasAfterTransactionCompletion()</tt>
+	 */
+	public boolean hasAfterTransactionCompletion();
+	/**
+	 * Called after the transaction completes
+	 */
+	public void afterTransactionCompletion(boolean success) throws HibernateException;
+	/**
+	 * What spaces (tables) are affected by this action?
+	 */
+	public Serializable[] getPropertySpaces();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/action/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/action/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/action/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+<html>
+<head>
+</head>
+<body>
+<p>
+	This package defines "actions" that are scheduled for 
+	asycnchronous execution by the event listeners.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/action/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/AbstractClassTransformerImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/AbstractClassTransformerImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/AbstractClassTransformerImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: $
+package org.hibernate.bytecode;
+
+import org.hibernate.bytecode.util.ClassFilter;
+import org.hibernate.bytecode.util.FieldFilter;
+
+import java.security.ProtectionDomain;
+
+/**
+ * @author Emmanuel Bernard
+ * @author Steve Ebersole
+ */
+public abstract class AbstractClassTransformerImpl implements ClassTransformer {
+
+	protected final ClassFilter classFilter;
+	protected final FieldFilter fieldFilter;
+
+	protected AbstractClassTransformerImpl(ClassFilter classFilter, FieldFilter fieldFilter) {
+		this.classFilter = classFilter;
+		this.fieldFilter = fieldFilter;
+	}
+
+	public byte[] transform(
+			ClassLoader loader,
+			String className,
+			Class classBeingRedefined,
+			ProtectionDomain protectionDomain,
+			byte[] classfileBuffer) {
+		// to be safe...
+		className = className.replace( '/', '.' );
+		if ( classFilter.shouldInstrumentClass( className ) ) {
+			return doTransform( loader, className, classBeingRedefined, protectionDomain, classfileBuffer );
+		}
+		else {
+			return classfileBuffer;
+		}
+	}
+
+	protected abstract byte[] doTransform(
+			ClassLoader loader,
+			String className,
+			Class classBeingRedefined,
+			ProtectionDomain protectionDomain,
+			byte[] classfileBuffer);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/BasicProxyFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/BasicProxyFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/BasicProxyFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+package org.hibernate.bytecode;
+
+/**
+ * A proxy factory for "basic proxy" generation
+ *
+ * @author Steve Ebersole
+ */
+public interface BasicProxyFactory {
+	public Object getProxy();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/BytecodeProvider.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/BytecodeProvider.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/BytecodeProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+package org.hibernate.bytecode;
+
+import org.hibernate.bytecode.util.ClassFilter;
+import org.hibernate.bytecode.util.FieldFilter;
+
+/**
+ * Contract for providers of bytecode services to Hibernate.
+ * <p/>
+ * Bytecode requirements break down into basically 3 areas<ol>
+ * <li>proxy generation (both for runtime-lazy-loading and basic proxy generation)
+ * {@link #getProxyFactoryFactory()}
+ * <li>bean relection optimization {@link #getReflectionOptimizer}
+ * <li>field-access instumentation {@link #getTransformer}
+ * </ol>
+ *
+ * @author Steve Ebersole
+ */
+public interface BytecodeProvider {
+	/**
+	 * Retrieve the specific factory for this provider capable of
+	 * generating run-time proxies for lazy-loading purposes.
+	 *
+	 * @return The provider specifc factory.
+	 */
+	public ProxyFactoryFactory getProxyFactoryFactory();
+
+	/**
+	 * Retrieve the ReflectionOptimizer delegate for this provider
+	 * capable of generating reflection optimization components.
+	 *
+	 * @param clazz The class to be reflected upon.
+	 * @param getterNames Names of all property getters to be accessed via reflection.
+	 * @param setterNames Names of all property setters to be accessed via reflection.
+	 * @param types The types of all properties to be accessed.
+	 * @return The reflection optimization delegate.
+	 */
+	public ReflectionOptimizer getReflectionOptimizer(Class clazz, String[] getterNames, String[] setterNames, Class[] types);
+
+	/**
+	 * Generate a ClassTransformer capable of performing bytecode manipulation.
+	 *
+	 * @param classFilter filter used to limit which classes are to be instrumented
+	 * via this ClassTransformer.
+	 * @param fieldFilter filter used to limit which fields are to be instrumented
+	 * via this ClassTransformer.
+	 * @return The appropriate ClassTransformer.
+	 */
+	public ClassTransformer getTransformer(ClassFilter classFilter, FieldFilter fieldFilter);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/ClassTransformer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/ClassTransformer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/ClassTransformer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+//$Id: $
+package org.hibernate.bytecode;
+
+import java.security.ProtectionDomain;
+
+/**
+ * A persistence provider provides an instance of this interface
+ * to the PersistenceUnitInfo.addTransformer method.
+ * The supplied transformer instance will get called to transform
+ * entity class files when they are loaded and redefined.  The transformation
+ * occurs before the class is defined by the JVM
+ *
+ *
+ * @author <a href="mailto:bill at jboss.org">Bill Burke</a>
+ * @author Emmanuel Bernard
+ */
+public interface ClassTransformer
+{
+   /**
+	* Invoked when a class is being loaded or redefined to add hooks for persistence bytecode manipulation
+	*
+	* @param loader the defining class loaderof the class being transformed.  It may be null if using bootstrap loader
+	* @param classname The name of the class being transformed
+	* @param classBeingRedefined If an already loaded class is being redefined, then pass this as a parameter
+	* @param protectionDomain ProtectionDomain of the class being (re)-defined
+	* @param classfileBuffer The input byte buffer in class file format
+	* @return A well-formed class file that can be loaded
+	*/
+   public byte[] transform(ClassLoader loader,
+					String classname,
+					Class classBeingRedefined,
+					ProtectionDomain protectionDomain,
+					byte[] classfileBuffer);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/InstrumentedClassLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/InstrumentedClassLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/InstrumentedClassLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+package org.hibernate.bytecode;
+
+import org.hibernate.bytecode.util.ByteCodeHelper;
+
+import java.io.InputStream;
+
+/**
+ * A specialized classloader which performs bytecode enhancement on class
+ * definitions as they are loaded into the classloader scope.
+ *
+ * @author Emmanuel Bernard
+ * @author Steve Ebersole
+ */
+public class InstrumentedClassLoader extends ClassLoader {
+
+	private ClassTransformer classTransformer;
+
+	public InstrumentedClassLoader(ClassLoader parent, ClassTransformer classTransformer) {
+		super( parent );
+		this.classTransformer = classTransformer;
+	}
+
+	public Class loadClass(String name) throws ClassNotFoundException {
+		if ( name.startsWith( "java." ) || classTransformer == null ) {
+			return getParent().loadClass( name );
+		}
+
+		Class c = findLoadedClass( name );
+		if ( c != null ) {
+			return c;
+		}
+
+		InputStream is = this.getResourceAsStream( name.replace( '.', '/' ) + ".class" );
+		if ( is == null ) {
+			throw new ClassNotFoundException( name + " not found" );
+		}
+
+		try {
+			byte[] originalBytecode = ByteCodeHelper.readByteCode( is );
+			byte[] transformedBytecode = classTransformer.transform( getParent(), name, null, null, originalBytecode );
+			if ( originalBytecode == transformedBytecode ) {
+				// no transformations took place, so handle it as we would a
+				// non-instrumented class
+				return getParent().loadClass( name );
+			}
+			else {
+				return defineClass( name, transformedBytecode, 0, transformedBytecode.length );
+			}
+		}
+		catch( Throwable t ) {
+			throw new ClassNotFoundException( name + " not found", t );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/ProxyFactoryFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/ProxyFactoryFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/ProxyFactoryFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+package org.hibernate.bytecode;
+
+import org.hibernate.proxy.ProxyFactory;
+
+/**
+ * An interface for factories of {@link ProxyFactory proxy factory} instances.
+ * <p/>
+ * Currently used to abstract from the tupizer whether we are using CGLIB or
+ * Javassist for lazy proxy generation.
+ *
+ * @author Steve Ebersole
+ */
+public interface ProxyFactoryFactory {
+	/**
+	 * Build a proxy factory specifically for handling runtime
+	 * lazy loading.
+	 *
+	 * @return The lazy-load proxy factory.
+	 */
+	public ProxyFactory buildProxyFactory();
+
+	/**
+	 * Build a proxy factory for basic proxy concerns.  The return
+	 * should be capable of properly handling newInstance() calls.
+	 * <p/>
+	 * Should build basic proxies essentially equivalent to JDK proxies in
+	 * terms of capabilities, but should be able to deal with abstract super
+	 * classes in addition to proxy interfaces.
+	 * <p/>
+	 * Must pass in either superClass or interfaces (or both).
+	 *
+	 * @param superClass The abstract super class (or null if none).
+	 * @param interfaces Interfaces to be proxied (or null if none).
+	 * @return The proxy class
+	 */
+	public BasicProxyFactory buildBasicProxyFactory(Class superClass, Class[] interfaces);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/ReflectionOptimizer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/ReflectionOptimizer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/ReflectionOptimizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+package org.hibernate.bytecode;
+
+/**
+ * Represents reflection optimization for a particular class.
+ *
+ * @author Steve Ebersole
+ */
+public interface ReflectionOptimizer {
+
+	public InstantiationOptimizer getInstantiationOptimizer();
+	public AccessOptimizer getAccessOptimizer();
+
+	/**
+	 * Represents optimized entity instantiation.
+	 */
+	public static interface InstantiationOptimizer {
+		/**
+		 * Perform instantiation of an instance of the underlying class.
+		 *
+		 * @return The new instance.
+		 */
+		public Object newInstance();
+	}
+
+	/**
+	 * Represents optimized entity property access.
+	 *
+	 * @author Steve Ebersole
+	 */
+	public interface AccessOptimizer {
+		public String[] getPropertyNames();
+		public Object[] getPropertyValues(Object object);
+		public void setPropertyValues(Object object, Object[] values);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/AccessOptimizerAdapter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/AccessOptimizerAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/AccessOptimizerAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,102 @@
+package org.hibernate.bytecode.cglib;
+
+import org.hibernate.bytecode.ReflectionOptimizer;
+import org.hibernate.PropertyAccessException;
+import net.sf.cglib.beans.BulkBean;
+import net.sf.cglib.beans.BulkBeanException;
+import net.sf.cglib.reflect.FastClass;
+
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+
+/**
+ * The {@link ReflectionOptimizer.AccessOptimizer} implementation for CGLIB
+ * which simply acts as an adpater to the {@link BulkBean} class.
+ *
+ * @author Steve Ebersole
+ */
+public class AccessOptimizerAdapter implements ReflectionOptimizer.AccessOptimizer, Serializable {
+
+	public static final String PROPERTY_GET_EXCEPTION =
+			"exception getting property value with CGLIB (set hibernate.bytecode.use_reflection_optimizer=false for more info)";
+
+	public static final String PROPERTY_SET_EXCEPTION =
+			"exception setting property value with CGLIB (set hibernate.bytecode.use_reflection_optimizer=false for more info)";
+
+	private Class mappedClass;
+	private BulkBean bulkBean;
+
+	public AccessOptimizerAdapter(BulkBean bulkBean, Class mappedClass) {
+		this.bulkBean = bulkBean;
+		this.mappedClass = mappedClass;
+	}
+
+	public String[] getPropertyNames() {
+		return bulkBean.getGetters();
+	}
+
+	public Object[] getPropertyValues(Object object) {
+		try {
+			return bulkBean.getPropertyValues( object );
+		}
+		catch ( Throwable t ) {
+			throw new PropertyAccessException(
+					t,
+			        PROPERTY_GET_EXCEPTION,
+			        false,
+			        mappedClass,
+			        getterName( t, bulkBean )
+			);
+		}
+	}
+
+	public void setPropertyValues(Object object, Object[] values) {
+		try {
+			bulkBean.setPropertyValues( object, values );
+		}
+		catch ( Throwable t ) {
+			throw new PropertyAccessException(
+					t,
+			        PROPERTY_SET_EXCEPTION,
+			        true,
+			        mappedClass,
+			        setterName( t, bulkBean )
+			);
+		}
+	}
+
+	private static String setterName(Throwable t, BulkBean optimizer) {
+		if ( t instanceof BulkBeanException ) {
+			return optimizer.getSetters()[( ( BulkBeanException ) t ).getIndex()];
+		}
+		else {
+			return "?";
+		}
+	}
+
+	private static String getterName(Throwable t, BulkBean optimizer) {
+		if ( t instanceof BulkBeanException ) {
+			return optimizer.getGetters()[( ( BulkBeanException ) t ).getIndex()];
+		}
+		else {
+			return "?";
+		}
+	}
+
+	private void writeObject(ObjectOutputStream out) throws IOException {
+		out.writeObject( mappedClass );
+		out.writeObject( bulkBean.getGetters() );
+		out.writeObject( bulkBean.getSetters() );
+		out.writeObject( bulkBean.getPropertyTypes() );
+	}
+
+	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+		Class beanClass = ( Class ) in.readObject();
+		String[] getters = ( String[] ) in.readObject();
+		String[] setters = ( String[] ) in.readObject();
+		Class[] types = ( Class[] ) in.readObject();
+		bulkBean = BulkBean.create( beanClass, getters, setters, types );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/BytecodeProviderImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,92 @@
+package org.hibernate.bytecode.cglib;
+
+import java.lang.reflect.Modifier;
+
+import net.sf.cglib.beans.BulkBean;
+import net.sf.cglib.beans.BulkBeanException;
+import net.sf.cglib.reflect.FastClass;
+import net.sf.cglib.transform.ClassFilter;
+import net.sf.cglib.transform.ClassTransformer;
+import net.sf.cglib.transform.ClassTransformerFactory;
+import net.sf.cglib.transform.TransformingClassLoader;
+import net.sf.cglib.transform.impl.InterceptFieldFilter;
+import net.sf.cglib.transform.impl.InterceptFieldTransformer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.bytecode.BytecodeProvider;
+import org.hibernate.bytecode.ProxyFactoryFactory;
+import org.hibernate.bytecode.ReflectionOptimizer;
+import org.hibernate.bytecode.util.FieldFilter;
+import org.hibernate.util.StringHelper;
+import org.objectweb.asm.Type;
+
+/**
+ * Bytecode provider implementation for CGLIB.
+ *
+ * @author Steve Ebersole
+ */
+public class BytecodeProviderImpl implements BytecodeProvider {
+
+	private static final Log log = LogFactory.getLog( BytecodeProviderImpl.class );
+
+	public ProxyFactoryFactory getProxyFactoryFactory() {
+		return new ProxyFactoryFactoryImpl();
+	}
+
+	public ReflectionOptimizer getReflectionOptimizer(
+			Class clazz,
+	        String[] getterNames,
+	        String[] setterNames,
+	        Class[] types) {
+		FastClass fastClass;
+		BulkBean bulkBean;
+		try {
+			fastClass = FastClass.create( clazz );
+			bulkBean = BulkBean.create( clazz, getterNames, setterNames, types );
+			if ( !clazz.isInterface() && !Modifier.isAbstract( clazz.getModifiers() ) ) {
+				if ( fastClass == null ) {
+					bulkBean = null;
+				}
+				else {
+					//test out the optimizer:
+					Object instance = fastClass.newInstance();
+					bulkBean.setPropertyValues( instance, bulkBean.getPropertyValues( instance ) );
+				}
+			}
+		}
+		catch( Throwable t ) {
+			fastClass = null;
+			bulkBean = null;
+			String message = "reflection optimizer disabled for: " +
+			                 clazz.getName() +
+			                 " [" +
+			                 StringHelper.unqualify( t.getClass().getName() ) +
+			                 ": " +
+			                 t.getMessage();
+
+			if (t instanceof BulkBeanException ) {
+				int index = ( (BulkBeanException) t ).getIndex();
+				if (index >= 0) {
+					message += " (property " + setterNames[index] + ")";
+				}
+			}
+
+			log.debug( message );
+		}
+
+		if ( fastClass != null && bulkBean != null ) {
+			return new ReflectionOptimizerImpl(
+					new InstantiationOptimizerAdapter( fastClass ),
+			        new AccessOptimizerAdapter( bulkBean, clazz )
+			);
+		}
+		else {
+			return null;
+		}
+	}
+
+	public org.hibernate.bytecode.ClassTransformer getTransformer(org.hibernate.bytecode.util.ClassFilter classFilter, FieldFilter fieldFilter) {
+		return new CglibClassTransformer( classFilter, fieldFilter );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/CglibClassTransformer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/CglibClassTransformer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/CglibClassTransformer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,120 @@
+//$Id: $
+package org.hibernate.bytecode.cglib;
+
+import java.security.ProtectionDomain;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.ByteArrayOutputStream;
+
+import net.sf.cglib.transform.ClassTransformer;
+import net.sf.cglib.transform.TransformingClassGenerator;
+import net.sf.cglib.transform.ClassReaderGenerator;
+import net.sf.cglib.transform.impl.InterceptFieldEnabled;
+import net.sf.cglib.transform.impl.InterceptFieldFilter;
+import net.sf.cglib.transform.impl.InterceptFieldTransformer;
+import net.sf.cglib.core.ClassNameReader;
+import net.sf.cglib.core.DebuggingClassWriter;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.bytecode.AbstractClassTransformerImpl;
+import org.hibernate.bytecode.util.FieldFilter;
+import org.hibernate.bytecode.util.ClassFilter;
+import org.hibernate.HibernateException;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.attrs.Attributes;
+
+/**
+ * Enhance the classes allowing them to implements InterceptFieldEnabled
+ * This interface is then used by Hibernate for some optimizations.
+ *
+ * @author Emmanuel Bernard
+ */
+public class CglibClassTransformer extends AbstractClassTransformerImpl {
+
+	private static Log log = LogFactory.getLog( CglibClassTransformer.class.getName() );
+
+	public CglibClassTransformer(ClassFilter classFilter, FieldFilter fieldFilter) {
+		super( classFilter, fieldFilter );
+	}
+
+	protected byte[] doTransform(
+			ClassLoader loader,
+			String className,
+			Class classBeingRedefined,
+			ProtectionDomain protectionDomain,
+			byte[] classfileBuffer) {
+		ClassReader reader;
+		try {
+			reader = new ClassReader( new ByteArrayInputStream( classfileBuffer ) );
+		}
+		catch (IOException e) {
+			log.error( "Unable to read class", e );
+			throw new HibernateException( "Unable to read class: " + e.getMessage() );
+		}
+
+		String[] names = ClassNameReader.getClassInfo( reader );
+		ClassWriter w = new DebuggingClassWriter( true );
+		ClassTransformer t = getClassTransformer( names );
+		if ( t != null ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "Enhancing " + className );
+			}
+			ByteArrayOutputStream out;
+			byte[] result;
+			try {
+				reader = new ClassReader( new ByteArrayInputStream( classfileBuffer ) );
+				new TransformingClassGenerator(
+						new ClassReaderGenerator( reader, attributes(), skipDebug() ), t
+				).generateClass( w );
+				out = new ByteArrayOutputStream();
+				out.write( w.toByteArray() );
+				result = out.toByteArray();
+				out.close();
+			}
+			catch (Exception e) {
+				log.error( "Unable to transform class", e );
+				throw new HibernateException( "Unable to transform class: " + e.getMessage() );
+			}
+			return result;
+		}
+		return classfileBuffer;
+	}
+
+
+	private Attribute[] attributes() {
+		return Attributes.getDefaultAttributes();
+	}
+
+	private boolean skipDebug() {
+		return false;
+	}
+
+	private ClassTransformer getClassTransformer(final String[] classInfo) {
+		if ( isAlreadyInstrumented( classInfo ) ) {
+			return null;
+		}
+		return new InterceptFieldTransformer(
+				new InterceptFieldFilter() {
+					public boolean acceptRead(Type owner, String name) {
+						return fieldFilter.shouldTransformFieldAccess( classInfo[0], owner.getClassName(), name );
+					}
+
+					public boolean acceptWrite(Type owner, String name) {
+						return fieldFilter.shouldTransformFieldAccess( classInfo[0], owner.getClassName(), name );
+					}
+				}
+		);
+	}
+
+	private boolean isAlreadyInstrumented(String[] classInfo) {
+		for ( int i = 1; i < classInfo.length; i++ ) {
+			if ( InterceptFieldEnabled.class.getName().equals( classInfo[i] ) ) {
+				return true;
+			}
+		}
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/InstantiationOptimizerAdapter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/InstantiationOptimizerAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/InstantiationOptimizerAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+package org.hibernate.bytecode.cglib;
+
+import org.hibernate.bytecode.ReflectionOptimizer;
+import net.sf.cglib.reflect.FastClass;
+import org.hibernate.InstantiationException;
+
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+
+/**
+ * The {@link ReflectionOptimizer.InstantiationOptimizer} implementation for CGLIB
+ * which simply acts as an adpater to the {@link FastClass} class.
+ *
+ * @author Steve Ebersole
+ */
+public class InstantiationOptimizerAdapter implements ReflectionOptimizer.InstantiationOptimizer, Serializable {
+	private FastClass fastClass;
+
+	public InstantiationOptimizerAdapter(FastClass fastClass) {
+		this.fastClass = fastClass;
+	}
+
+	public Object newInstance() {
+		try {
+			return fastClass.newInstance();
+		}
+		catch ( Throwable t ) {
+			throw new InstantiationException(
+					"Could not instantiate entity with CGLIB optimizer: ",
+			        fastClass.getJavaClass(),
+			        t
+			);
+		}
+	}
+
+	private void writeObject(ObjectOutputStream out) throws IOException {
+		out.writeObject( fastClass.getJavaClass() );
+	}
+
+	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+		Class beanClass = ( Class ) in.readObject();
+		fastClass = FastClass.create( beanClass );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/ProxyFactoryFactoryImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/ProxyFactoryFactoryImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/ProxyFactoryFactoryImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,141 @@
+package org.hibernate.bytecode.cglib;
+
+import org.hibernate.bytecode.ProxyFactoryFactory;
+import org.hibernate.bytecode.BasicProxyFactory;
+import org.hibernate.proxy.ProxyFactory;
+import org.hibernate.proxy.pojo.cglib.CGLIBProxyFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import net.sf.cglib.proxy.Enhancer;
+import net.sf.cglib.proxy.CallbackFilter;
+import net.sf.cglib.proxy.MethodInterceptor;
+import net.sf.cglib.proxy.MethodProxy;
+import net.sf.cglib.proxy.NoOp;
+import net.sf.cglib.proxy.Callback;
+import net.sf.cglib.proxy.Factory;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
+/**
+ * A factory for CGLIB-based {@link ProxyFactory} instances.
+ *
+ * @author Steve Ebersole
+ */
+public class ProxyFactoryFactoryImpl implements ProxyFactoryFactory {
+
+	/**
+	 * Builds a CGLIB-based proxy factory.
+	 *
+	 * @return a new CGLIB-based proxy factory.
+	 */
+	public ProxyFactory buildProxyFactory() {
+		return new CGLIBProxyFactory();
+	}
+
+	public BasicProxyFactory buildBasicProxyFactory(Class superClass, Class[] interfaces) {
+		return new BasicProxyFactoryImpl( superClass, interfaces );
+	}
+
+	public static class BasicProxyFactoryImpl implements BasicProxyFactory {
+		private final Class proxyClass;
+		private final Factory factory;
+
+		public BasicProxyFactoryImpl(Class superClass, Class[] interfaces) {
+			if ( superClass == null && ( interfaces == null || interfaces.length < 1 ) ) {
+				throw new AssertionFailure( "attempting to build proxy without any superclass or interfaces" );
+			}
+
+			Enhancer en = new Enhancer();
+			en.setUseCache( false );
+			en.setInterceptDuringConstruction( false );
+			en.setUseFactory( true );
+			en.setCallbackTypes( CALLBACK_TYPES );
+			en.setCallbackFilter( FINALIZE_FILTER );
+			if ( superClass != null ) {
+				en.setSuperclass( superClass );
+			}
+			if ( interfaces != null && interfaces.length > 0 ) {
+				en.setInterfaces( interfaces );
+			}
+			proxyClass = en.createClass();
+			try {
+				factory = ( Factory ) proxyClass.newInstance();
+			}
+			catch ( Throwable t ) {
+				throw new HibernateException( "Unable to build CGLIB Factory instance" );
+			}
+		}
+
+		public Object getProxy() {
+			try {
+				return factory.newInstance(
+						new Callback[] { new PassThroughInterceptor( proxyClass.getName() ), NoOp.INSTANCE }
+				);
+			}
+			catch ( Throwable t ) {
+				throw new HibernateException( "Unable to instantiate proxy instance" );
+			}
+		}
+	}
+
+	private static final CallbackFilter FINALIZE_FILTER = new CallbackFilter() {
+		public int accept(Method method) {
+			if ( method.getParameterTypes().length == 0 && method.getName().equals("finalize") ){
+				return 1;
+			}
+			else {
+				return 0;
+			}
+		}
+	};
+
+	private static final Class[] CALLBACK_TYPES = new Class[] { MethodInterceptor.class, NoOp.class };
+
+	private static class PassThroughInterceptor implements MethodInterceptor {
+		private HashMap data = new HashMap();
+		private final String proxiedClassName;
+
+		public PassThroughInterceptor(String proxiedClassName) {
+			this.proxiedClassName = proxiedClassName;
+		}
+
+		public Object intercept(
+				Object obj,
+		        Method method,
+		        Object[] args,
+		        MethodProxy proxy) throws Throwable {
+			String name = method.getName();
+			if ( "toString".equals( name ) ) {
+				return proxiedClassName + "@" + System.identityHashCode( obj );
+			}
+			else if ( "equals".equals( name ) ) {
+				return args[0] instanceof Factory && ( ( Factory ) args[0] ).getCallback( 0 ) == this
+						? Boolean.TRUE
+			            : Boolean.FALSE;
+			}
+			else if ( "hashCode".equals( name ) ) {
+				return new Integer( System.identityHashCode( obj ) );
+			}
+			boolean hasGetterSignature = method.getParameterTypes().length == 0 && method.getReturnType() != null;
+			boolean hasSetterSignature = method.getParameterTypes().length == 1 && ( method.getReturnType() == null || method.getReturnType() == void.class );
+			if ( name.startsWith( "get" ) && hasGetterSignature ) {
+				String propName = name.substring( 3 );
+				return data.get( propName );
+			}
+			else if ( name.startsWith( "is" ) && hasGetterSignature ) {
+				String propName = name.substring( 2 );
+				return data.get( propName );
+			}
+			else if ( name.startsWith( "set" ) && hasSetterSignature) {
+				String propName = name.substring( 3 );
+				data.put( propName, args[0] );
+				return null;
+			}
+			else {
+				// todo : what else to do here?
+				return null;
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/ReflectionOptimizerImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/ReflectionOptimizerImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/cglib/ReflectionOptimizerImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+package org.hibernate.bytecode.cglib;
+
+import org.hibernate.bytecode.ReflectionOptimizer;
+
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+
+/**
+ * ReflectionOptimizer implementation for CGLIB.
+ *
+ * @author Steve Ebersole
+ */
+public class ReflectionOptimizerImpl implements ReflectionOptimizer, Serializable {
+	private transient InstantiationOptimizerAdapter instantiationOptimizer;
+	private transient AccessOptimizerAdapter accessOptimizer;
+
+	public ReflectionOptimizerImpl(
+			InstantiationOptimizerAdapter instantiationOptimizer,
+	        AccessOptimizerAdapter accessOptimizer) {
+		this.instantiationOptimizer = instantiationOptimizer;
+		this.accessOptimizer = accessOptimizer;
+	}
+
+	public InstantiationOptimizer getInstantiationOptimizer() {
+		return instantiationOptimizer;
+	}
+
+	public AccessOptimizer getAccessOptimizer() {
+		return accessOptimizer;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/AccessOptimizerAdapter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/AccessOptimizerAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/AccessOptimizerAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,81 @@
+package org.hibernate.bytecode.javassist;
+
+import org.hibernate.bytecode.ReflectionOptimizer;
+import org.hibernate.PropertyAccessException;
+
+import java.io.Serializable;
+
+/**
+ * The {@link ReflectionOptimizer.AccessOptimizer} implementation for Javassist
+ * which simply acts as an adpater to the {@link BulkAccessor} class.
+ *
+ * @author Steve Ebersole
+ */
+public class AccessOptimizerAdapter implements ReflectionOptimizer.AccessOptimizer, Serializable {
+
+	public static final String PROPERTY_GET_EXCEPTION =
+		"exception getting property value with Javassist (set hibernate.bytecode.use_reflection_optimizer=false for more info)";
+
+	public static final String PROPERTY_SET_EXCEPTION =
+		"exception setting property value with Javassist (set hibernate.bytecode.use_reflection_optimizer=false for more info)";
+
+	private final BulkAccessor bulkAccessor;
+	private final Class mappedClass;
+
+	public AccessOptimizerAdapter(BulkAccessor bulkAccessor, Class mappedClass) {
+		this.bulkAccessor = bulkAccessor;
+		this.mappedClass = mappedClass;
+	}
+
+	public String[] getPropertyNames() {
+		return bulkAccessor.getGetters();
+	}
+
+	public Object[] getPropertyValues(Object object) {
+		try {
+			return bulkAccessor.getPropertyValues( object );
+		}
+		catch ( Throwable t ) {
+			throw new PropertyAccessException(
+					t,
+			        PROPERTY_GET_EXCEPTION,
+			        false,
+			        mappedClass,
+			        getterName( t, bulkAccessor )
+				);
+		}
+	}
+
+	public void setPropertyValues(Object object, Object[] values) {
+		try {
+			bulkAccessor.setPropertyValues( object, values );
+		}
+		catch ( Throwable t ) {
+			throw new PropertyAccessException(
+					t,
+			        PROPERTY_SET_EXCEPTION,
+			        true,
+			        mappedClass,
+			        setterName( t, bulkAccessor )
+			);
+		}
+	}
+
+	private static String setterName(Throwable t, BulkAccessor accessor) {
+		if (t instanceof BulkAccessorException ) {
+			return accessor.getSetters()[ ( (BulkAccessorException) t ).getIndex() ];
+		}
+		else {
+			return "?";
+		}
+	}
+
+	private static String getterName(Throwable t, BulkAccessor accessor) {
+		if (t instanceof BulkAccessorException ) {
+			return accessor.getGetters()[ ( (BulkAccessorException) t ).getIndex() ];
+		}
+		else {
+			return "?";
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BulkAccessor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BulkAccessor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BulkAccessor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,92 @@
+package org.hibernate.bytecode.javassist;
+
+import java.io.Serializable;
+
+
+/**
+ * A JavaBean accessor.
+ * <p/>
+ * <p>This object provides methods that set/get multiple properties
+ * of a JavaBean at once.  This class and its support classes have been
+ * developed for the comaptibility with cglib
+ * (<tt>http://cglib.sourceforge.net/</tt>).
+ *
+ * @author Muga Nishizawa
+ * @author modified by Shigeru Chiba
+ */
+public abstract class BulkAccessor implements Serializable {
+	protected Class target;
+	protected String[] getters, setters;
+	protected Class[] types;
+
+	protected BulkAccessor() {
+	}
+
+	/**
+	 * Obtains the values of properties of a given bean.
+	 *
+	 * @param bean   JavaBean.
+	 * @param values the obtained values are stored in this array.
+	 */
+	public abstract void getPropertyValues(Object bean, Object[] values);
+
+	/**
+	 * Sets properties of a given bean to specified values.
+	 *
+	 * @param bean   JavaBean.
+	 * @param values the values assinged to properties.
+	 */
+	public abstract void setPropertyValues(Object bean, Object[] values);
+
+	/**
+	 * Returns the values of properties of a given bean.
+	 *
+	 * @param bean JavaBean.
+	 */
+	public Object[] getPropertyValues(Object bean) {
+		Object[] values = new Object[getters.length];
+		getPropertyValues( bean, values );
+		return values;
+	}
+
+	/**
+	 * Returns the types of properties.
+	 */
+	public Class[] getPropertyTypes() {
+		return ( Class[] ) types.clone();
+	}
+
+	/**
+	 * Returns the setter names of properties.
+	 */
+	public String[] getGetters() {
+		return ( String[] ) getters.clone();
+	}
+
+	/**
+	 * Returns the getter names of the properties.
+	 */
+	public String[] getSetters() {
+		return ( String[] ) setters.clone();
+	}
+
+	/**
+	 * Creates a new instance of <code>BulkAccessor</code>.
+	 * The created instance provides methods for setting/getting
+	 * specified properties at once.
+	 *
+	 * @param beanClass the class of the JavaBeans accessed
+	 *                  through the created object.
+	 * @param getters   the names of setter methods for specified properties.
+	 * @param setters   the names of getter methods for specified properties.
+	 * @param types     the types of specified properties.
+	 */
+	public static BulkAccessor create(
+			Class beanClass,
+	        String[] getters,
+	        String[] setters,
+	        Class[] types) {
+		BulkAccessorFactory factory = new BulkAccessorFactory( beanClass, getters, setters, types );
+		return factory.create();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BulkAccessorException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BulkAccessorException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BulkAccessorException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+package org.hibernate.bytecode.javassist;
+
+/**
+ * An exception thrown while generating a bulk accessor.
+ * 
+ * @author Muga Nishizawa
+ * @author modified by Shigeru Chiba
+ */
+public class BulkAccessorException extends RuntimeException {
+    private Throwable myCause;
+
+    /**
+     * Gets the cause of this throwable.
+     * It is for JDK 1.3 compatibility.
+     */
+    public Throwable getCause() {
+        return (myCause == this ? null : myCause);
+    }
+
+    /**
+     * Initializes the cause of this throwable.
+     * It is for JDK 1.3 compatibility.
+     */
+    public synchronized Throwable initCause(Throwable cause) {
+        myCause = cause;
+        return this;
+    }
+
+    private int index;
+
+    /**
+     * Constructs an exception.
+     */
+    public BulkAccessorException(String message) {
+        super(message);
+        index = -1;
+        initCause(null);
+    }
+
+    /**
+     * Constructs an exception.
+     *
+     * @param index     the index of the property that causes an exception.
+     */
+    public BulkAccessorException(String message, int index) {
+        this(message + ": " + index);
+        this.index = index;
+    }
+
+    /**
+     * Constructs an exception.
+     */
+    public BulkAccessorException(String message, Throwable cause) {
+        super(message);
+        index = -1;
+        initCause(cause);
+    }
+
+    /**
+     * Constructs an exception.
+     *
+     * @param index     the index of the property that causes an exception.
+     */
+    public BulkAccessorException(Throwable cause, int index) {
+        this("Property " + index);
+        this.index = index;
+        initCause(cause);
+    }
+
+    /**
+     * Returns the index of the property that causes this exception.
+     *
+     * @return -1 if the index is not specified.
+     */
+    public int getIndex() {
+        return this.index;
+    }
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BulkAccessorFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BulkAccessorFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BulkAccessorFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,388 @@
+package org.hibernate.bytecode.javassist;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.security.ProtectionDomain;
+
+import javassist.CannotCompileException;
+import javassist.bytecode.AccessFlag;
+import javassist.bytecode.Bytecode;
+import javassist.bytecode.ClassFile;
+import javassist.bytecode.ConstPool;
+import javassist.bytecode.MethodInfo;
+import javassist.bytecode.Opcode;
+import javassist.util.proxy.FactoryHelper;
+import javassist.util.proxy.RuntimeSupport;
+
+/**
+ * A factory of bulk accessors.
+ *
+ * @author Muga Nishizawa
+ * @author modified by Shigeru Chiba
+ */
+class BulkAccessorFactory {
+	private static final String PACKAGE_NAME_PREFIX = "org.javassist.tmp.";
+	private static final String BULKACESSOR_CLASS_NAME = BulkAccessor.class.getName();
+	private static final String OBJECT_CLASS_NAME = Object.class.getName();
+	private static final String GENERATED_GETTER_NAME = "getPropertyValues";
+	private static final String GENERATED_SETTER_NAME = "setPropertyValues";
+	private static final String GET_SETTER_DESC = "(Ljava/lang/Object;[Ljava/lang/Object;)V";
+	private static final String THROWABLE_CLASS_NAME = Throwable.class.getName();
+	private static final String BULKEXCEPTION_CLASS_NAME = BulkAccessorException.class.getName();
+	private static int counter = 0;
+
+	private Class targetBean;
+	private String[] getterNames;
+	private String[] setterNames;
+	private Class[] types;
+	public String writeDirectory;
+
+	BulkAccessorFactory(
+			Class target,
+	        String[] getterNames,
+	        String[] setterNames,
+	        Class[] types) {
+		this.targetBean = target;
+		this.getterNames = getterNames;
+		this.setterNames = setterNames;
+		this.types = types;
+		this.writeDirectory = null;
+	}
+
+	BulkAccessor create() {
+		Method[] getters = new Method[getterNames.length];
+		Method[] setters = new Method[setterNames.length];
+		findAccessors( targetBean, getterNames, setterNames, types, getters, setters );
+
+		Class beanClass;
+		try {
+			ClassFile classfile = make( getters, setters );
+			ClassLoader loader = this.getClassLoader();
+			if ( writeDirectory != null ) {
+				FactoryHelper.writeFile( classfile, writeDirectory );
+			}
+
+			beanClass = FactoryHelper.toClass( classfile, loader, getDomain() );
+			return ( BulkAccessor ) this.newInstance( beanClass );
+		}
+		catch ( Exception e ) {
+			throw new BulkAccessorException( e.getMessage(), e );
+		}
+	}
+
+	private ProtectionDomain getDomain() {
+		Class cl;
+		if ( this.targetBean != null ) {
+			cl = this.targetBean;
+		}
+		else {
+			cl = this.getClass();
+		}
+		return cl.getProtectionDomain();
+	}
+
+	private ClassFile make(Method[] getters, Method[] setters) throws CannotCompileException {
+		String className = targetBean.getName();
+		// set the name of bulk accessor.
+		className = className + "_$$_bulkaccess_" + counter++;
+		if ( className.startsWith( "java." ) ) {
+			className = "org.javassist.tmp." + className;
+		}
+
+		ClassFile classfile = new ClassFile( false, className, BULKACESSOR_CLASS_NAME );
+		classfile.setAccessFlags( AccessFlag.PUBLIC );
+		addDefaultConstructor( classfile );
+		addGetter( classfile, getters );
+		addSetter( classfile, setters );
+		return classfile;
+	}
+
+	private ClassLoader getClassLoader() {
+		if ( targetBean != null && targetBean.getName().equals( OBJECT_CLASS_NAME ) ) {
+			return targetBean.getClassLoader();
+		}
+		else {
+			return getClass().getClassLoader();
+		}
+	}
+
+	private Object newInstance(Class type) throws Exception {
+		BulkAccessor instance = ( BulkAccessor ) type.newInstance();
+		instance.target = targetBean;
+		int len = getterNames.length;
+		instance.getters = new String[len];
+		instance.setters = new String[len];
+		instance.types = new Class[len];
+		for ( int i = 0; i < len; i++ ) {
+			instance.getters[i] = getterNames[i];
+			instance.setters[i] = setterNames[i];
+			instance.types[i] = types[i];
+		}
+
+		return instance;
+	}
+
+	/**
+	 * Declares a constructor that takes no parameter.
+	 *
+	 * @param classfile
+	 * @throws CannotCompileException
+	 */
+	private void addDefaultConstructor(ClassFile classfile) throws CannotCompileException {
+		ConstPool cp = classfile.getConstPool();
+		String cons_desc = "()V";
+		MethodInfo mi = new MethodInfo( cp, MethodInfo.nameInit, cons_desc );
+
+		Bytecode code = new Bytecode( cp, 0, 1 );
+		// aload_0
+		code.addAload( 0 );
+		// invokespecial
+		code.addInvokespecial( BulkAccessor.class.getName(), MethodInfo.nameInit, cons_desc );
+		// return
+		code.addOpcode( Opcode.RETURN );
+
+		mi.setCodeAttribute( code.toCodeAttribute() );
+		mi.setAccessFlags( AccessFlag.PUBLIC );
+		classfile.addMethod( mi );
+	}
+
+	private void addGetter(ClassFile classfile, final Method[] getters) throws CannotCompileException {
+		ConstPool cp = classfile.getConstPool();
+		int target_type_index = cp.addClassInfo( this.targetBean.getName() );
+		String desc = GET_SETTER_DESC;
+		MethodInfo mi = new MethodInfo( cp, GENERATED_GETTER_NAME, desc );
+
+		Bytecode code = new Bytecode( cp, 6, 4 );
+		/* | this | bean | args | raw bean | */
+		if ( getters.length >= 0 ) {
+			// aload_1 // load bean
+			code.addAload( 1 );
+			// checkcast // cast bean
+			code.addCheckcast( this.targetBean.getName() );
+			// astore_3 // store bean
+			code.addAstore( 3 );
+			for ( int i = 0; i < getters.length; ++i ) {
+				if ( getters[i] != null ) {
+					Method getter = getters[i];
+					// aload_2 // args
+					code.addAload( 2 );
+					// iconst_i // continue to aastore
+					code.addIconst( i ); // growing stack is 1
+					Class returnType = getter.getReturnType();
+					int typeIndex = -1;
+					if ( returnType.isPrimitive() ) {
+						typeIndex = FactoryHelper.typeIndex( returnType );
+						// new
+						code.addNew( FactoryHelper.wrapperTypes[typeIndex] );
+						// dup
+						code.addOpcode( Opcode.DUP );
+					}
+
+					// aload_3 // load the raw bean
+					code.addAload( 3 );
+					String getter_desc = RuntimeSupport.makeDescriptor( getter );
+					String getterName = getter.getName();
+					if ( this.targetBean.isInterface() ) {
+						// invokeinterface
+						code.addInvokeinterface( target_type_index, getterName, getter_desc, 1 );
+					}
+					else {
+						// invokevirtual
+						code.addInvokevirtual( target_type_index, getterName, getter_desc );
+					}
+
+					if ( typeIndex >= 0 ) {       // is a primitive type
+						// invokespecial
+						code.addInvokespecial(
+								FactoryHelper.wrapperTypes[typeIndex],
+						        MethodInfo.nameInit,
+						        FactoryHelper.wrapperDesc[typeIndex]
+						);
+					}
+
+					// aastore // args
+					code.add( Opcode.AASTORE );
+					code.growStack( -3 );
+				}
+			}
+		}
+		// return
+		code.addOpcode( Opcode.RETURN );
+
+		mi.setCodeAttribute( code.toCodeAttribute() );
+		mi.setAccessFlags( AccessFlag.PUBLIC );
+		classfile.addMethod( mi );
+	}
+
+	private void addSetter(ClassFile classfile, final Method[] setters) throws CannotCompileException {
+		ConstPool cp = classfile.getConstPool();
+		int target_type_index = cp.addClassInfo( this.targetBean.getName() );
+		String desc = GET_SETTER_DESC;
+		MethodInfo mi = new MethodInfo( cp, GENERATED_SETTER_NAME, desc );
+
+		Bytecode code = new Bytecode( cp, 4, 6 );
+		/* | this | bean | args | i | raw bean | exception | */
+		if ( setters.length > 0 ) {
+			int start, end; // required to exception table
+			// iconst_0 // i
+			code.addIconst( 0 );
+			// istore_3 // store i
+			code.addIstore( 3 );
+			// aload_1 // load the bean
+			code.addAload( 1 );
+			// checkcast // cast the bean into a raw bean
+			code.addCheckcast( this.targetBean.getName() );
+			// astore 4 // store the raw bean
+			code.addAstore( 4 );
+			/* current stack len = 0 */
+			// start region to handling exception (BulkAccessorException)
+			start = code.currentPc();
+			int lastIndex = 0;
+			for ( int i = 0; i < setters.length; ++i ) {
+				if ( setters[i] != null ) {
+					int diff = i - lastIndex;
+					if ( diff > 0 ) {
+						// iinc 3, 1
+						code.addOpcode( Opcode.IINC );
+						code.add( 3 );
+						code.add( diff );
+						lastIndex = i;
+					}
+				}
+				/* current stack len = 0 */
+				// aload 4 // load the raw bean
+				code.addAload( 4 );
+				// aload_2 // load the args
+				code.addAload( 2 );
+				// iconst_i
+				code.addIconst( i );
+				// aaload
+				code.addOpcode( Opcode.AALOAD );
+				// checkcast
+				Class[] setterParamTypes = setters[i].getParameterTypes();
+				Class setterParamType = setterParamTypes[0];
+				if ( setterParamType.isPrimitive() ) {
+					// checkcast (case of primitive type)
+					// invokevirtual (case of primitive type)
+					this.addUnwrapper( classfile, code, setterParamType );
+				}
+				else {
+					// checkcast (case of reference type)
+					code.addCheckcast( setterParamType.getName() );
+				}
+				/* current stack len = 2 */
+				String rawSetterMethod_desc = RuntimeSupport.makeDescriptor( setters[i] );
+				if ( !this.targetBean.isInterface() ) {
+					// invokevirtual
+					code.addInvokevirtual( target_type_index, setters[i].getName(), rawSetterMethod_desc );
+				}
+				else {
+					// invokeinterface
+					Class[] params = setters[i].getParameterTypes();
+					int size;
+					if ( params[0].equals( Double.TYPE ) || params[0].equals( Long.TYPE ) ) {
+						size = 3;
+					}
+					else {
+						size = 2;
+					}
+
+					code.addInvokeinterface( target_type_index, setters[i].getName(), rawSetterMethod_desc, size );
+				}
+			}
+
+			// end region to handling exception (BulkAccessorException)
+			end = code.currentPc();
+			// return
+			code.addOpcode( Opcode.RETURN );
+			/* current stack len = 0 */
+			// register in exception table
+			int throwableType_index = cp.addClassInfo( THROWABLE_CLASS_NAME );
+			code.addExceptionHandler( start, end, code.currentPc(), throwableType_index );
+			// astore 5 // store exception
+			code.addAstore( 5 );
+			// new // BulkAccessorException
+			code.addNew( BULKEXCEPTION_CLASS_NAME );
+			// dup
+			code.addOpcode( Opcode.DUP );
+			// aload 5 // load exception
+			code.addAload( 5 );
+			// iload_3 // i
+			code.addIload( 3 );
+			// invokespecial // BulkAccessorException.<init>
+			String cons_desc = "(Ljava/lang/Throwable;I)V";
+			code.addInvokespecial( BULKEXCEPTION_CLASS_NAME, MethodInfo.nameInit, cons_desc );
+			// athrow
+			code.addOpcode( Opcode.ATHROW );
+		}
+		else {
+			// return
+			code.addOpcode( Opcode.RETURN );
+		}
+
+		mi.setCodeAttribute( code.toCodeAttribute() );
+		mi.setAccessFlags( AccessFlag.PUBLIC );
+		classfile.addMethod( mi );
+	}
+
+	private void addUnwrapper(
+			ClassFile classfile,
+	        Bytecode code,
+	        Class type) {
+		int index = FactoryHelper.typeIndex( type );
+		String wrapperType = FactoryHelper.wrapperTypes[index];
+		// checkcast
+		code.addCheckcast( wrapperType );
+		// invokevirtual
+		code.addInvokevirtual( wrapperType, FactoryHelper.unwarpMethods[index], FactoryHelper.unwrapDesc[index] );
+	}
+
+	private static void findAccessors(
+			Class clazz,
+	        String[] getterNames,
+	        String[] setterNames,
+	        Class[] types,
+	        Method[] getters,
+	        Method[] setters) {
+		int length = types.length;
+		if ( setterNames.length != length || getterNames.length != length ) {
+			throw new BulkAccessorException( "bad number of accessors" );
+		}
+
+		Class[] getParam = new Class[0];
+		Class[] setParam = new Class[1];
+		for ( int i = 0; i < length; i++ ) {
+			if ( getterNames[i] != null ) {
+				Method getter = findAccessor( clazz, getterNames[i], getParam, i );
+				if ( getter.getReturnType() != types[i] ) {
+					throw new BulkAccessorException( "wrong return type: " + getterNames[i], i );
+				}
+
+				getters[i] = getter;
+			}
+
+			if ( setterNames[i] != null ) {
+				setParam[0] = types[i];
+				setters[i] = findAccessor( clazz, setterNames[i], setParam, i );
+			}
+		}
+	}
+
+	private static Method findAccessor(
+			Class clazz,
+	        String name,
+	        Class[] params,
+	        int index) throws BulkAccessorException {
+		try {
+			Method method = clazz.getDeclaredMethod( name, params );
+			if ( Modifier.isPrivate( method.getModifiers() ) ) {
+				throw new BulkAccessorException( "private property", index );
+			}
+
+			return method;
+		}
+		catch ( NoSuchMethodException e ) {
+			throw new BulkAccessorException( "cannot find an accessor", index );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/BytecodeProviderImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,84 @@
+package org.hibernate.bytecode.javassist;
+
+import java.lang.reflect.Modifier;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.bytecode.BytecodeProvider;
+import org.hibernate.bytecode.ClassTransformer;
+import org.hibernate.bytecode.ProxyFactoryFactory;
+import org.hibernate.bytecode.ReflectionOptimizer;
+import org.hibernate.bytecode.util.ClassFilter;
+import org.hibernate.bytecode.util.FieldFilter;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Bytecode provider implementation for Javassist.
+ *
+ * @author Steve Ebersole
+ */
+public class BytecodeProviderImpl implements BytecodeProvider {
+
+	private static final Log log = LogFactory.getLog( BytecodeProviderImpl.class );
+
+	public ProxyFactoryFactory getProxyFactoryFactory() {
+		return new ProxyFactoryFactoryImpl();
+	}
+
+	public ReflectionOptimizer getReflectionOptimizer(
+			Class clazz,
+	        String[] getterNames,
+	        String[] setterNames,
+	        Class[] types) {
+		FastClass fastClass;
+		BulkAccessor bulkAccessor;
+		try {
+			fastClass = FastClass.create( clazz );
+			bulkAccessor = BulkAccessor.create( clazz, getterNames, setterNames, types );
+			if ( !clazz.isInterface() && !Modifier.isAbstract( clazz.getModifiers() ) ) {
+				if ( fastClass == null ) {
+					bulkAccessor = null;
+				}
+				else {
+					//test out the optimizer:
+					Object instance = fastClass.newInstance();
+					bulkAccessor.setPropertyValues( instance, bulkAccessor.getPropertyValues( instance ) );
+				}
+			}
+		}
+		catch ( Throwable t ) {
+			fastClass = null;
+			bulkAccessor = null;
+			String message = "reflection optimizer disabled for: " +
+			                 clazz.getName() +
+			                 " [" +
+			                 StringHelper.unqualify( t.getClass().getName() ) +
+			                 ": " +
+			                 t.getMessage();
+
+			if ( t instanceof BulkAccessorException ) {
+				int index = ( ( BulkAccessorException ) t ).getIndex();
+				if ( index >= 0 ) {
+					message += " (property " + setterNames[index] + ")";
+				}
+			}
+
+			log.debug( message );
+		}
+
+		if ( fastClass != null && bulkAccessor != null ) {
+			return new ReflectionOptimizerImpl(
+					new InstantiationOptimizerAdapter( fastClass ),
+			        new AccessOptimizerAdapter( bulkAccessor, clazz )
+			);
+		}
+		else {
+			return null;
+		}
+	}
+
+	public ClassTransformer getTransformer(ClassFilter classFilter, FieldFilter fieldFilter) {
+		return new JavassistClassTransformer( classFilter, fieldFilter );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FastClass.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FastClass.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FastClass.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,170 @@
+package org.hibernate.bytecode.javassist;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.io.Serializable;
+
+/**
+ * @author Muga Nishizawa
+ */
+public class FastClass implements Serializable {
+
+	private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
+
+	private Class type;
+
+	private FastClass() {
+	}
+
+	private FastClass(Class type) {
+		this.type = type;
+	}
+
+	public Object invoke(
+			String name,
+	        Class[] parameterTypes,
+	        Object obj,
+	        Object[] args) throws InvocationTargetException {
+		return this.invoke( this.getIndex( name, parameterTypes ), obj, args );
+	}
+
+	public Object invoke(
+			int index,
+	        Object obj,
+	        Object[] args) throws InvocationTargetException {
+		Method[] methods = this.type.getMethods();
+		try {
+			return methods[index].invoke( obj, args );
+		}
+		catch ( ArrayIndexOutOfBoundsException e ) {
+			throw new IllegalArgumentException(
+					"Cannot find matching method/constructor"
+			);
+		}
+		catch ( IllegalAccessException e ) {
+			throw new InvocationTargetException( e );
+		}
+	}
+
+	public Object newInstance() throws InvocationTargetException {
+		return this.newInstance( this.getIndex( EMPTY_CLASS_ARRAY ), null );
+	}
+
+	public Object newInstance(
+			Class[] parameterTypes,
+	        Object[] args) throws InvocationTargetException {
+		return this.newInstance( this.getIndex( parameterTypes ), args );
+	}
+
+	public Object newInstance(
+			int index,
+	        Object[] args) throws InvocationTargetException {
+		Constructor[] conss = this.type.getConstructors();
+		try {
+			return conss[index].newInstance( args );
+		}
+		catch ( ArrayIndexOutOfBoundsException e ) {
+			throw new IllegalArgumentException( "Cannot find matching method/constructor" );
+		}
+		catch ( InstantiationException e ) {
+			throw new InvocationTargetException( e );
+		}
+		catch ( IllegalAccessException e ) {
+			throw new InvocationTargetException( e );
+		}
+	}
+
+	public int getIndex(String name, Class[] parameterTypes) {
+		Method[] methods = this.type.getMethods();
+		boolean eq = true;
+		for ( int i = 0; i < methods.length; ++i ) {
+			if ( !Modifier.isPublic( methods[i].getModifiers() ) ) {
+				continue;
+			}
+			if ( !methods[i].getName().equals( name ) ) {
+				continue;
+			}
+			Class[] params = methods[i].getParameterTypes();
+			if ( params.length != parameterTypes.length ) {
+				continue;
+			}
+			eq = true;
+			for ( int j = 0; j < params.length; ++j ) {
+				if ( !params[j].equals( parameterTypes[j] ) ) {
+					eq = false;
+					break;
+				}
+			}
+			if ( eq ) {
+				return i;
+			}
+		}
+		return -1;
+	}
+
+	public int getIndex(Class[] parameterTypes) {
+		Constructor[] conss = this.type.getConstructors();
+		boolean eq = true;
+		for ( int i = 0; i < conss.length; ++i ) {
+			if ( !Modifier.isPublic( conss[i].getModifiers() ) ) {
+				continue;
+			}
+			Class[] params = conss[i].getParameterTypes();
+			if ( params.length != parameterTypes.length ) {
+				continue;
+			}
+			eq = true;
+			for ( int j = 0; j < params.length; ++j ) {
+				if ( !params[j].equals( parameterTypes[j] ) ) {
+					eq = false;
+					break;
+				}
+			}
+			if ( eq ) {
+				return i;
+			}
+		}
+		return -1;
+	}
+
+	public int getMaxIndex() {
+		Method[] methods = this.type.getMethods();
+		int count = 0;
+		for ( int i = 0; i < methods.length; ++i ) {
+			if ( Modifier.isPublic( methods[i].getModifiers() ) ) {
+				count++;
+			}
+		}
+		return count;
+	}
+
+	public String getName() {
+		return this.type.getName();
+	}
+
+	public Class getJavaClass() {
+		return this.type;
+	}
+
+	public String toString() {
+		return this.type.toString();
+	}
+
+	public int hashCode() {
+		return this.type.hashCode();
+	}
+
+	public boolean equals(Object o) {
+		if (! ( o instanceof FastClass ) ) {
+			return false;
+		}
+		return this.type.equals( ( ( FastClass ) o ).type );
+	}
+
+	public static FastClass create(Class type) {
+		FastClass fc = new FastClass( type );
+		return fc;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldFilter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldFilter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldFilter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+package org.hibernate.bytecode.javassist;
+
+/**
+ * Contract for deciding whether fields should be read and/or write intercepted.
+ *
+ * @author Muga Nishizawa
+ * @author Steve Ebersole
+ */
+public interface FieldFilter {
+	/**
+	 * Should the given field be read intercepted?
+	 *
+	 * @param desc
+	 * @param name
+	 * @return true if the given field should be read intercepted; otherwise
+	 * false.
+	 */
+	boolean handleRead(String desc, String name);
+
+	/**
+	 * Should the given field be write intercepted?
+	 *
+	 * @param desc
+	 * @param name
+	 * @return true if the given field should be write intercepted; otherwise
+	 * false.
+	 */
+	boolean handleWrite(String desc, String name);
+
+	boolean handleReadAccess(String fieldOwnerClassName, String fieldName);
+
+	boolean handleWriteAccess(String fieldOwnerClassName, String fieldName);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldHandled.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldHandled.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldHandled.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+package org.hibernate.bytecode.javassist;
+
+/**
+ * Interface introduced to the enhanced class in order to be able to
+ * inject a {@link FieldHandler} to define the interception behavior.
+ *
+ * @author Muga Nishizawa
+ */
+public interface FieldHandled {
+	/**
+	 * Inject the field interception handler to be used.
+	 *
+	 * @param handler The field interception handler.
+	 */
+	public void setFieldHandler(FieldHandler handler);
+
+	/**
+	 * Access to the current field interception handler.
+	 *
+	 * @return The current field interception handler.
+	 */
+	public FieldHandler getFieldHandler();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldHandler.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldHandler.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldHandler.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,56 @@
+package org.hibernate.bytecode.javassist;
+
+/**
+ * The interface defining how interception of a field should be handled.
+ *
+ * @author Muga Nishizawa
+ */
+public interface FieldHandler {
+
+	/**
+	 * Called to handle writing an int value to a given field.
+	 *
+	 * @param obj ?
+	 * @param name The name of the field being written
+	 * @param oldValue The old field value
+	 * @param newValue The new field value.
+	 * @return ?
+	 */
+	int writeInt(Object obj, String name, int oldValue, int newValue);
+
+	char writeChar(Object obj, String name, char oldValue, char newValue);
+
+	byte writeByte(Object obj, String name, byte oldValue, byte newValue);
+
+	boolean writeBoolean(Object obj, String name, boolean oldValue,
+			boolean newValue);
+
+	short writeShort(Object obj, String name, short oldValue, short newValue);
+
+	float writeFloat(Object obj, String name, float oldValue, float newValue);
+
+	double writeDouble(Object obj, String name, double oldValue, double newValue);
+
+	long writeLong(Object obj, String name, long oldValue, long newValue);
+
+	Object writeObject(Object obj, String name, Object oldValue, Object newValue);
+
+	int readInt(Object obj, String name, int oldValue);
+
+	char readChar(Object obj, String name, char oldValue);
+
+	byte readByte(Object obj, String name, byte oldValue);
+
+	boolean readBoolean(Object obj, String name, boolean oldValue);
+
+	short readShort(Object obj, String name, short oldValue);
+
+	float readFloat(Object obj, String name, float oldValue);
+
+	double readDouble(Object obj, String name, double oldValue);
+
+	long readLong(Object obj, String name, long oldValue);
+
+	Object readObject(Object obj, String name, Object oldValue);
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldTransformer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldTransformer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/FieldTransformer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,581 @@
+package org.hibernate.bytecode.javassist;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.util.Iterator;
+import java.util.List;
+
+import javassist.CannotCompileException;
+import javassist.bytecode.AccessFlag;
+import javassist.bytecode.BadBytecode;
+import javassist.bytecode.Bytecode;
+import javassist.bytecode.ClassFile;
+import javassist.bytecode.CodeAttribute;
+import javassist.bytecode.CodeIterator;
+import javassist.bytecode.ConstPool;
+import javassist.bytecode.Descriptor;
+import javassist.bytecode.FieldInfo;
+import javassist.bytecode.MethodInfo;
+import javassist.bytecode.Opcode;
+
+/**
+ * The thing that handles actual class enhancement in regards to
+ * intercepting field accesses.
+ *
+ * @author Muga Nishizawa
+ * @author Steve Ebersole
+ */
+public class FieldTransformer {
+
+	private static final String EACH_READ_METHOD_PREFIX = "$javassist_read_";
+
+	private static final String EACH_WRITE_METHOD_PREFIX = "$javassist_write_";
+
+	private static final String FIELD_HANDLED_TYPE_NAME = FieldHandled.class
+			.getName();
+
+	private static final String HANDLER_FIELD_NAME = "$JAVASSIST_READ_WRITE_HANDLER";
+
+	private static final String FIELD_HANDLER_TYPE_NAME = FieldHandler.class
+			.getName();
+
+	private static final String HANDLER_FIELD_DESCRIPTOR = 'L' + FIELD_HANDLER_TYPE_NAME
+			.replace('.', '/') + ';';
+
+	private static final String GETFIELDHANDLER_METHOD_NAME = "getFieldHandler";
+
+	private static final String SETFIELDHANDLER_METHOD_NAME = "setFieldHandler";
+
+	private static final String GETFIELDHANDLER_METHOD_DESCRIPTOR = "()"
+	                                                                + HANDLER_FIELD_DESCRIPTOR;
+
+	private static final String SETFIELDHANDLER_METHOD_DESCRIPTOR = "("
+	                                                                + HANDLER_FIELD_DESCRIPTOR + ")V";
+
+	private FieldFilter filter;
+
+	public FieldTransformer() {
+		this(null);
+	}
+
+	public FieldTransformer(FieldFilter f) {
+		filter = f;
+	}
+
+	public void setFieldFilter(FieldFilter f) {
+		filter = f;
+	}
+
+	public void transform(File file) throws Exception {
+		DataInputStream in = new DataInputStream(new FileInputStream(file));
+		ClassFile classfile = new ClassFile(in);
+		transform(classfile);
+		DataOutputStream out = new DataOutputStream(new FileOutputStream(file));
+		try {
+			classfile.write(out);
+		} finally {
+			out.close();
+		}
+	}
+
+	public void transform(ClassFile classfile) throws Exception {
+		if (classfile.isInterface()) {
+			return;
+		}
+		try {
+			addFieldHandlerField(classfile);
+			addGetFieldHandlerMethod(classfile);
+			addSetFieldHandlerMethod(classfile);
+			addFieldHandledInterface(classfile);
+			addReadWriteMethods(classfile);
+			transformInvokevirtualsIntoPutAndGetfields(classfile);
+		} catch (CannotCompileException e) {
+			throw new RuntimeException(e.getMessage(), e);
+		}
+	}
+
+	private void addFieldHandlerField(ClassFile classfile)
+			throws CannotCompileException {
+		ConstPool cp = classfile.getConstPool();
+		FieldInfo finfo = new FieldInfo(cp, HANDLER_FIELD_NAME,
+		                                HANDLER_FIELD_DESCRIPTOR);
+		finfo.setAccessFlags(AccessFlag.PRIVATE | AccessFlag.TRANSIENT);
+		classfile.addField(finfo);
+	}
+
+	private void addGetFieldHandlerMethod(ClassFile classfile)
+			throws CannotCompileException {
+		ConstPool cp = classfile.getConstPool();
+		int this_class_index = cp.getThisClassInfo();
+		MethodInfo minfo = new MethodInfo(cp, GETFIELDHANDLER_METHOD_NAME,
+		                                  GETFIELDHANDLER_METHOD_DESCRIPTOR);
+		/* local variable | this | */
+		Bytecode code = new Bytecode(cp, 2, 1);
+		// aload_0 // load this
+		code.addAload(0);
+		// getfield // get field "$JAVASSIST_CALLBACK" defined already
+		code.addOpcode(Opcode.GETFIELD);
+		int field_index = cp.addFieldrefInfo(this_class_index,
+		                                     HANDLER_FIELD_NAME, HANDLER_FIELD_DESCRIPTOR);
+		code.addIndex(field_index);
+		// areturn // return the value of the field
+		code.addOpcode(Opcode.ARETURN);
+		minfo.setCodeAttribute(code.toCodeAttribute());
+		minfo.setAccessFlags(AccessFlag.PUBLIC);
+		classfile.addMethod(minfo);
+	}
+
+	private void addSetFieldHandlerMethod(ClassFile classfile)
+			throws CannotCompileException {
+		ConstPool cp = classfile.getConstPool();
+		int this_class_index = cp.getThisClassInfo();
+		MethodInfo minfo = new MethodInfo(cp, SETFIELDHANDLER_METHOD_NAME,
+		                                  SETFIELDHANDLER_METHOD_DESCRIPTOR);
+		/* local variables | this | callback | */
+		Bytecode code = new Bytecode(cp, 3, 3);
+		// aload_0 // load this
+		code.addAload(0);
+		// aload_1 // load callback
+		code.addAload(1);
+		// putfield // put field "$JAVASSIST_CALLBACK" defined already
+		code.addOpcode(Opcode.PUTFIELD);
+		int field_index = cp.addFieldrefInfo(this_class_index,
+		                                     HANDLER_FIELD_NAME, HANDLER_FIELD_DESCRIPTOR);
+		code.addIndex(field_index);
+		// return
+		code.addOpcode(Opcode.RETURN);
+		minfo.setCodeAttribute(code.toCodeAttribute());
+		minfo.setAccessFlags(AccessFlag.PUBLIC);
+		classfile.addMethod(minfo);
+	}
+
+	private void addFieldHandledInterface(ClassFile classfile) {
+		String[] interfaceNames = classfile.getInterfaces();
+		String[] newInterfaceNames = new String[interfaceNames.length + 1];
+		System.arraycopy(interfaceNames, 0, newInterfaceNames, 0,
+		                 interfaceNames.length);
+		newInterfaceNames[newInterfaceNames.length - 1] = FIELD_HANDLED_TYPE_NAME;
+		classfile.setInterfaces(newInterfaceNames);
+	}
+
+	private void addReadWriteMethods(ClassFile classfile)
+			throws CannotCompileException {
+		List fields = classfile.getFields();
+		for (Iterator field_iter = fields.iterator(); field_iter.hasNext();) {
+			FieldInfo finfo = (FieldInfo) field_iter.next();
+			if ((finfo.getAccessFlags() & AccessFlag.STATIC) == 0
+			    && (!finfo.getName().equals(HANDLER_FIELD_NAME))) {
+				// case of non-static field
+				if (filter.handleRead(finfo.getDescriptor(), finfo
+						.getName())) {
+					addReadMethod(classfile, finfo);
+				}
+				if (filter.handleWrite(finfo.getDescriptor(), finfo
+						.getName())) {
+					addWriteMethod(classfile, finfo);
+				}
+			}
+		}
+	}
+
+	private void addReadMethod(ClassFile classfile, FieldInfo finfo)
+			throws CannotCompileException {
+		ConstPool cp = classfile.getConstPool();
+		int this_class_index = cp.getThisClassInfo();
+		String desc = "()" + finfo.getDescriptor();
+		MethodInfo minfo = new MethodInfo(cp, EACH_READ_METHOD_PREFIX
+		                                      + finfo.getName(), desc);
+		/* local variables | target obj | each oldvalue | */
+		Bytecode code = new Bytecode(cp, 5, 3);
+		// aload_0
+		code.addAload(0);
+		// getfield // get each field
+		code.addOpcode(Opcode.GETFIELD);
+		int base_field_index = cp.addFieldrefInfo(this_class_index, finfo
+				.getName(), finfo.getDescriptor());
+		code.addIndex(base_field_index);
+		// aload_0
+		code.addAload(0);
+		// invokeinterface // invoke Enabled.getInterceptFieldCallback()
+		int enabled_class_index = cp.addClassInfo(FIELD_HANDLED_TYPE_NAME);
+		code.addInvokeinterface(enabled_class_index,
+		                        GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR,
+		                        1);
+		// ifnonnull
+		code.addOpcode(Opcode.IFNONNULL);
+		code.addIndex(4);
+		// *return // each type
+		addTypeDependDataReturn(code, finfo.getDescriptor());
+		// *store_1 // each type
+		addTypeDependDataStore(code, finfo.getDescriptor(), 1);
+		// aload_0
+		code.addAload(0);
+		// invokeinterface // invoke Enabled.getInterceptFieldCallback()
+		code.addInvokeinterface(enabled_class_index,
+		                        GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR,
+		                        1);
+		// aload_0
+		code.addAload(0);
+		// ldc // name of the field
+		code.addLdc(finfo.getName());
+		// *load_1 // each type
+		addTypeDependDataLoad(code, finfo.getDescriptor(), 1);
+		// invokeinterface // invoke Callback.read*() // each type
+		addInvokeFieldHandlerMethod(classfile, code, finfo.getDescriptor(),
+		                            true);
+		// *return // each type
+		addTypeDependDataReturn(code, finfo.getDescriptor());
+
+		minfo.setCodeAttribute(code.toCodeAttribute());
+		minfo.setAccessFlags(AccessFlag.PUBLIC);
+		classfile.addMethod(minfo);
+	}
+
+	private void addWriteMethod(ClassFile classfile, FieldInfo finfo)
+			throws CannotCompileException {
+		ConstPool cp = classfile.getConstPool();
+		int this_class_index = cp.getThisClassInfo();
+		String desc = "(" + finfo.getDescriptor() + ")V";
+		MethodInfo minfo = new MethodInfo(cp, EACH_WRITE_METHOD_PREFIX
+		                                      + finfo.getName(), desc);
+		/* local variables | target obj | each oldvalue | */
+		Bytecode code = new Bytecode(cp, 6, 3);
+		// aload_0
+		code.addAload(0);
+		// invokeinterface // enabled.getInterceptFieldCallback()
+		int enabled_class_index = cp.addClassInfo(FIELD_HANDLED_TYPE_NAME);
+		code.addInvokeinterface(enabled_class_index,
+		                        GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR,
+		                        1);
+		// ifnonnull (label1)
+		code.addOpcode(Opcode.IFNONNULL);
+		code.addIndex(9);
+		// aload_0
+		code.addAload(0);
+		// *load_1
+		addTypeDependDataLoad(code, finfo.getDescriptor(), 1);
+		// putfield
+		code.addOpcode(Opcode.PUTFIELD);
+		int base_field_index = cp.addFieldrefInfo(this_class_index, finfo
+				.getName(), finfo.getDescriptor());
+		code.addIndex(base_field_index);
+		code.growStack(-Descriptor.dataSize(finfo.getDescriptor()));
+		// return ;
+		code.addOpcode(Opcode.RETURN);
+		// aload_0
+		code.addAload(0);
+		// dup
+		code.addOpcode(Opcode.DUP);
+		// invokeinterface // enabled.getInterceptFieldCallback()
+		code.addInvokeinterface(enabled_class_index,
+		                        GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR,
+		                        1);
+		// aload_0
+		code.addAload(0);
+		// ldc // field name
+		code.addLdc(finfo.getName());
+		// aload_0
+		code.addAload(0);
+		// getfield // old value of the field
+		code.addOpcode(Opcode.GETFIELD);
+		code.addIndex(base_field_index);
+		code.growStack(Descriptor.dataSize(finfo.getDescriptor()) - 1);
+		// *load_1
+		addTypeDependDataLoad(code, finfo.getDescriptor(), 1);
+		// invokeinterface // callback.write*(..)
+		addInvokeFieldHandlerMethod(classfile, code, finfo.getDescriptor(),
+		                            false);
+		// putfield // new value of the field
+		code.addOpcode(Opcode.PUTFIELD);
+		code.addIndex(base_field_index);
+		code.growStack(-Descriptor.dataSize(finfo.getDescriptor()));
+		// return
+		code.addOpcode(Opcode.RETURN);
+
+		minfo.setCodeAttribute(code.toCodeAttribute());
+		minfo.setAccessFlags(AccessFlag.PUBLIC);
+		classfile.addMethod(minfo);
+	}
+
+	private void transformInvokevirtualsIntoPutAndGetfields(ClassFile classfile)
+			throws CannotCompileException {
+		List methods = classfile.getMethods();
+		for (Iterator method_iter = methods.iterator(); method_iter.hasNext();) {
+			MethodInfo minfo = (MethodInfo) method_iter.next();
+			String methodName = minfo.getName();
+			if (methodName.startsWith(EACH_READ_METHOD_PREFIX)
+			    || methodName.startsWith(EACH_WRITE_METHOD_PREFIX)
+			    || methodName.equals(GETFIELDHANDLER_METHOD_NAME)
+			    || methodName.equals(SETFIELDHANDLER_METHOD_NAME)) {
+				continue;
+			}
+			CodeAttribute codeAttr = minfo.getCodeAttribute();
+			if (codeAttr == null) {
+				return;
+			}
+			CodeIterator iter = codeAttr.iterator();
+			while (iter.hasNext()) {
+				try {
+					int pos = iter.next();
+					pos = transformInvokevirtualsIntoGetfields(classfile, iter, pos);
+					pos = transformInvokevirtualsIntoPutfields(classfile, iter, pos);
+
+				} catch (BadBytecode e) {
+					throw new CannotCompileException(e);
+				}
+			}
+		}
+	}
+
+	private int transformInvokevirtualsIntoGetfields(ClassFile classfile, CodeIterator iter, int pos) {
+		ConstPool cp = classfile.getConstPool();
+		int c = iter.byteAt(pos);
+		if (c != Opcode.GETFIELD) {
+			return pos;
+		}
+		int index = iter.u16bitAt(pos + 1);
+		String fieldName = cp.getFieldrefName(index);
+		String className = cp.getFieldrefClassName(index);
+		if ( !filter.handleReadAccess( className, fieldName ) ) {
+			return pos;
+		}
+		String desc = "()" + cp.getFieldrefType( index );
+		int read_method_index = cp.addMethodrefInfo(
+				cp.getThisClassInfo(),
+				EACH_READ_METHOD_PREFIX + fieldName,
+				desc
+		);
+		iter.writeByte(Opcode.INVOKEVIRTUAL, pos);
+		iter.write16bit(read_method_index, pos + 1);
+		return pos;
+	}
+
+	private int transformInvokevirtualsIntoPutfields(
+			ClassFile classfile,
+			CodeIterator iter, int pos) {
+		ConstPool cp = classfile.getConstPool();
+		int c = iter.byteAt(pos);
+		if (c != Opcode.PUTFIELD) {
+			return pos;
+		}
+		int index = iter.u16bitAt(pos + 1);
+		String fieldName = cp.getFieldrefName(index);
+		String className = cp.getFieldrefClassName(index);
+		if ( !filter.handleWriteAccess( className, fieldName ) ) {
+			return pos;
+		}
+		String desc = "(" + cp.getFieldrefType( index ) + ")V";
+		int write_method_index = cp.addMethodrefInfo(
+				cp.getThisClassInfo(),
+				EACH_WRITE_METHOD_PREFIX + fieldName,
+				desc
+		);
+		iter.writeByte(Opcode.INVOKEVIRTUAL, pos);
+		iter.write16bit(write_method_index, pos + 1);
+		return pos;
+	}
+
+	private static void addInvokeFieldHandlerMethod(ClassFile classfile,
+	                                                Bytecode code, String typeName, boolean isReadMethod) {
+		ConstPool cp = classfile.getConstPool();
+		// invokeinterface
+		int callback_type_index = cp.addClassInfo(FIELD_HANDLER_TYPE_NAME);
+		if ((typeName.charAt(0) == 'L')
+		    && (typeName.charAt(typeName.length() - 1) == ';')
+		    || (typeName.charAt(0) == '[')) {
+			// reference type
+			int indexOfL = typeName.indexOf('L');
+			String type;
+			if (indexOfL == 0) {
+				// not array
+				type = typeName.substring(1, typeName.length() - 1);
+				type = type.replace('/', '.');
+			} else if (indexOfL == -1) {
+				// array of primitive type
+				// do nothing
+				type = typeName;
+			} else {
+				// array of reference type
+				type = typeName.replace('/', '.');
+			}
+			if (isReadMethod) {
+				code
+						.addInvokeinterface(
+								callback_type_index,
+								"readObject",
+								"(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;",
+								4);
+				// checkcast
+				code.addCheckcast(type);
+			} else {
+				code
+						.addInvokeinterface(
+								callback_type_index,
+								"writeObject",
+								"(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+								5);
+				// checkcast
+				code.addCheckcast(type);
+			}
+		} else if (typeName.equals("Z")) {
+			// boolean
+			if (isReadMethod) {
+				code.addInvokeinterface(callback_type_index, "readBoolean",
+				                        "(Ljava/lang/Object;Ljava/lang/String;Z)Z", 4);
+			} else {
+				code.addInvokeinterface(callback_type_index, "writeBoolean",
+				                        "(Ljava/lang/Object;Ljava/lang/String;ZZ)Z", 5);
+			}
+		} else if (typeName.equals("B")) {
+			// byte
+			if (isReadMethod) {
+				code.addInvokeinterface(callback_type_index, "readByte",
+				                        "(Ljava/lang/Object;Ljava/lang/String;B)B", 4);
+			} else {
+				code.addInvokeinterface(callback_type_index, "writeByte",
+				                        "(Ljava/lang/Object;Ljava/lang/String;BB)B", 5);
+			}
+		} else if (typeName.equals("C")) {
+			// char
+			if (isReadMethod) {
+				code.addInvokeinterface(callback_type_index, "readChar",
+				                        "(Ljava/lang/Object;Ljava/lang/String;C)C", 4);
+			} else {
+				code.addInvokeinterface(callback_type_index, "writeChar",
+				                        "(Ljava/lang/Object;Ljava/lang/String;CC)C", 5);
+			}
+		} else if (typeName.equals("I")) {
+			// int
+			if (isReadMethod) {
+				code.addInvokeinterface(callback_type_index, "readInt",
+				                        "(Ljava/lang/Object;Ljava/lang/String;I)I", 4);
+			} else {
+				code.addInvokeinterface(callback_type_index, "writeInt",
+				                        "(Ljava/lang/Object;Ljava/lang/String;II)I", 5);
+			}
+		} else if (typeName.equals("S")) {
+			// short
+			if (isReadMethod) {
+				code.addInvokeinterface(callback_type_index, "readShort",
+				                        "(Ljava/lang/Object;Ljava/lang/String;S)S", 4);
+			} else {
+				code.addInvokeinterface(callback_type_index, "writeShort",
+				                        "(Ljava/lang/Object;Ljava/lang/String;SS)S", 5);
+			}
+		} else if (typeName.equals("D")) {
+			// double
+			if (isReadMethod) {
+				code.addInvokeinterface(callback_type_index, "readDouble",
+				                        "(Ljava/lang/Object;Ljava/lang/String;D)D", 5);
+			} else {
+				code.addInvokeinterface(callback_type_index, "writeDouble",
+				                        "(Ljava/lang/Object;Ljava/lang/String;DD)D", 7);
+			}
+		} else if (typeName.equals("F")) {
+			// float
+			if (isReadMethod) {
+				code.addInvokeinterface(callback_type_index, "readFloat",
+				                        "(Ljava/lang/Object;Ljava/lang/String;F)F", 4);
+			} else {
+				code.addInvokeinterface(callback_type_index, "writeFloat",
+				                        "(Ljava/lang/Object;Ljava/lang/String;FF)F", 5);
+			}
+		} else if (typeName.equals("J")) {
+			// long
+			if (isReadMethod) {
+				code.addInvokeinterface(callback_type_index, "readLong",
+				                        "(Ljava/lang/Object;Ljava/lang/String;J)J", 5);
+			} else {
+				code.addInvokeinterface(callback_type_index, "writeLong",
+				                        "(Ljava/lang/Object;Ljava/lang/String;JJ)J", 7);
+			}
+		} else {
+			// bad type
+			throw new RuntimeException("bad type: " + typeName);
+		}
+	}
+
+	private static void addTypeDependDataLoad(Bytecode code, String typeName,
+	                                          int i) {
+		if ((typeName.charAt(0) == 'L')
+		    && (typeName.charAt(typeName.length() - 1) == ';')
+		    || (typeName.charAt(0) == '[')) {
+			// reference type
+			code.addAload(i);
+		} else if (typeName.equals("Z") || typeName.equals("B")
+		           || typeName.equals("C") || typeName.equals("I")
+		           || typeName.equals("S")) {
+			// boolean, byte, char, int, short
+			code.addIload(i);
+		} else if (typeName.equals("D")) {
+			// double
+			code.addDload(i);
+		} else if (typeName.equals("F")) {
+			// float
+			code.addFload(i);
+		} else if (typeName.equals("J")) {
+			// long
+			code.addLload(i);
+		} else {
+			// bad type
+			throw new RuntimeException("bad type: " + typeName);
+		}
+	}
+
+	private static void addTypeDependDataStore(Bytecode code, String typeName,
+	                                           int i) {
+		if ((typeName.charAt(0) == 'L')
+		    && (typeName.charAt(typeName.length() - 1) == ';')
+		    || (typeName.charAt(0) == '[')) {
+			// reference type
+			code.addAstore(i);
+		} else if (typeName.equals("Z") || typeName.equals("B")
+		           || typeName.equals("C") || typeName.equals("I")
+		           || typeName.equals("S")) {
+			// boolean, byte, char, int, short
+			code.addIstore(i);
+		} else if (typeName.equals("D")) {
+			// double
+			code.addDstore(i);
+		} else if (typeName.equals("F")) {
+			// float
+			code.addFstore(i);
+		} else if (typeName.equals("J")) {
+			// long
+			code.addLstore(i);
+		} else {
+			// bad type
+			throw new RuntimeException("bad type: " + typeName);
+		}
+	}
+
+	private static void addTypeDependDataReturn(Bytecode code, String typeName) {
+		if ((typeName.charAt(0) == 'L')
+		    && (typeName.charAt(typeName.length() - 1) == ';')
+		    || (typeName.charAt(0) == '[')) {
+			// reference type
+			code.addOpcode(Opcode.ARETURN);
+		} else if (typeName.equals("Z") || typeName.equals("B")
+		           || typeName.equals("C") || typeName.equals("I")
+		           || typeName.equals("S")) {
+			// boolean, byte, char, int, short
+			code.addOpcode(Opcode.IRETURN);
+		} else if (typeName.equals("D")) {
+			// double
+			code.addOpcode(Opcode.DRETURN);
+		} else if (typeName.equals("F")) {
+			// float
+			code.addOpcode(Opcode.FRETURN);
+		} else if (typeName.equals("J")) {
+			// long
+			code.addOpcode(Opcode.LRETURN);
+		} else {
+			// bad type
+			throw new RuntimeException("bad type: " + typeName);
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/InstantiationOptimizerAdapter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/InstantiationOptimizerAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/InstantiationOptimizerAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+package org.hibernate.bytecode.javassist;
+
+import org.hibernate.bytecode.ReflectionOptimizer;
+import org.hibernate.InstantiationException;
+
+import java.io.Serializable;
+
+/**
+ * The {@link ReflectionOptimizer.InstantiationOptimizer} implementation for Javassist
+ * which simply acts as an adpater to the {@link FastClass} class.
+ *
+ * @author Steve Ebersole
+ */
+public class InstantiationOptimizerAdapter implements ReflectionOptimizer.InstantiationOptimizer, Serializable {
+	private final FastClass fastClass;
+
+	public InstantiationOptimizerAdapter(FastClass fastClass) {
+		this.fastClass = fastClass;
+	}
+
+	public Object newInstance() {
+		try {
+			return fastClass.newInstance();
+		}
+		catch ( Throwable t ) {
+			throw new InstantiationException(
+					"Could not instantiate entity with Javassist optimizer: ",
+			        fastClass.getJavaClass(), t
+			);
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/JavassistClassTransformer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/JavassistClassTransformer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/JavassistClassTransformer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,111 @@
+//$Id: $
+package org.hibernate.bytecode.javassist;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.security.ProtectionDomain;
+
+import javassist.bytecode.ClassFile;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.bytecode.AbstractClassTransformerImpl;
+import org.hibernate.bytecode.util.ClassFilter;
+
+/**
+ * Enhance the classes allowing them to implements InterceptFieldEnabled
+ * This interface is then used by Hibernate for some optimizations.
+ *
+ * @author Emmanuel Bernard
+ * @author Steve Ebersole
+ */
+public class JavassistClassTransformer extends AbstractClassTransformerImpl {
+
+	private static Log log = LogFactory.getLog( JavassistClassTransformer.class.getName() );
+
+	public JavassistClassTransformer(ClassFilter classFilter, org.hibernate.bytecode.util.FieldFilter fieldFilter) {
+		super( classFilter, fieldFilter );
+	}
+
+	protected byte[] doTransform(
+			ClassLoader loader,
+			String className,
+			Class classBeingRedefined,
+			ProtectionDomain protectionDomain,
+			byte[] classfileBuffer) {
+		ClassFile classfile;
+		try {
+			// WARNING: classfile only
+			classfile = new ClassFile( new DataInputStream( new ByteArrayInputStream( classfileBuffer ) ) );
+		}
+		catch (IOException e) {
+			log.error( "Unable to build enhancement metamodel for " + className );
+			return classfileBuffer;
+		}
+		FieldTransformer transformer = getFieldTransformer( classfile );
+		if ( transformer != null ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "Enhancing " + className );
+			}
+			DataOutputStream out = null;
+			try {
+				transformer.transform( classfile );
+				ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+				out = new DataOutputStream( byteStream );
+				classfile.write( out );
+				return byteStream.toByteArray();
+			}
+			catch (Exception e) {
+				log.error( "Unable to transform class", e );
+				throw new HibernateException( "Unable to transform class: " + e.getMessage() );
+			}
+			finally {
+				try {
+					if ( out != null ) out.close();
+				}
+				catch (IOException e) {
+					//swallow
+				}
+			}
+		}
+		return classfileBuffer;
+	}
+
+	protected FieldTransformer getFieldTransformer(final ClassFile classfile) {
+		if ( alreadyInstrumented( classfile ) ) {
+			return null;
+		}
+		return new FieldTransformer(
+				new FieldFilter() {
+					public boolean handleRead(String desc, String name) {
+						return fieldFilter.shouldInstrumentField( classfile.getName(), name );
+					}
+
+					public boolean handleWrite(String desc, String name) {
+						return fieldFilter.shouldInstrumentField( classfile.getName(), name );
+					}
+
+					public boolean handleReadAccess(String fieldOwnerClassName, String fieldName) {
+						return fieldFilter.shouldTransformFieldAccess( classfile.getName(), fieldOwnerClassName, fieldName );
+					}
+
+					public boolean handleWriteAccess(String fieldOwnerClassName, String fieldName) {
+						return fieldFilter.shouldTransformFieldAccess( classfile.getName(), fieldOwnerClassName, fieldName );
+					}
+				}
+		);
+	}
+
+	private boolean alreadyInstrumented(ClassFile classfile) {
+		String[] intfs = classfile.getInterfaces();
+		for ( int i = 0; i < intfs.length; i++ ) {
+			if ( FieldHandled.class.getName().equals( intfs[i] ) ) {
+				return true;
+			}
+		}
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/ProxyFactoryFactoryImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/ProxyFactoryFactoryImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/ProxyFactoryFactoryImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,123 @@
+package org.hibernate.bytecode.javassist;
+
+import org.hibernate.bytecode.ProxyFactoryFactory;
+import org.hibernate.bytecode.BasicProxyFactory;
+import org.hibernate.proxy.ProxyFactory;
+import org.hibernate.proxy.pojo.javassist.JavassistProxyFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import javassist.util.proxy.MethodFilter;
+import javassist.util.proxy.ProxyObject;
+import javassist.util.proxy.MethodHandler;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
+/**
+ * A factory for Javassist-based {@link ProxyFactory} instances.
+ *
+ * @author Steve Ebersole
+ */
+public class ProxyFactoryFactoryImpl implements ProxyFactoryFactory {
+
+	/**
+	 * Builds a Javassist-based proxy factory.
+	 *
+	 * @return a new Javassist-based proxy factory.
+	 */
+	public ProxyFactory buildProxyFactory() {
+		return new JavassistProxyFactory();
+	}
+
+	public BasicProxyFactory buildBasicProxyFactory(Class superClass, Class[] interfaces) {
+		return new BasicProxyFactoryImpl( superClass, interfaces );
+	}
+
+	private static class BasicProxyFactoryImpl implements BasicProxyFactory {
+		private final Class proxyClass;
+
+		public BasicProxyFactoryImpl(Class superClass, Class[] interfaces) {
+			if ( superClass == null && ( interfaces == null || interfaces.length < 1 ) ) {
+				throw new AssertionFailure( "attempting to build proxy without any superclass or interfaces" );
+			}
+			javassist.util.proxy.ProxyFactory factory = new javassist.util.proxy.ProxyFactory();
+			factory.setFilter( FINALIZE_FILTER );
+			if ( superClass != null ) {
+				factory.setSuperclass( superClass );
+			}
+			if ( interfaces != null && interfaces.length > 0 ) {
+				factory.setInterfaces( interfaces );
+			}
+			proxyClass = factory.createClass();
+		}
+
+		public Object getProxy() {
+			try {
+				ProxyObject proxy = ( ProxyObject ) proxyClass.newInstance();
+				proxy.setHandler( new PassThroughHandler( proxy, proxyClass.getName() ) );
+				return proxy;
+			}
+			catch ( Throwable t ) {
+				throw new HibernateException( "Unable to instantiated proxy instance" );
+			}
+		}
+
+		public boolean isInstance(Object object) {
+			return proxyClass.isInstance( object );
+		}
+	}
+
+	private static final MethodFilter FINALIZE_FILTER = new MethodFilter() {
+		public boolean isHandled(Method m) {
+			// skip finalize methods
+			return !( m.getParameterTypes().length == 0 && m.getName().equals( "finalize" ) );
+		}
+	};
+
+	private static class PassThroughHandler implements MethodHandler {
+		private HashMap data = new HashMap();
+		private final Object proxiedObject;
+		private final String proxiedClassName;
+
+		public PassThroughHandler(Object proxiedObject, String proxiedClassName) {
+			this.proxiedObject = proxiedObject;
+			this.proxiedClassName = proxiedClassName;
+		}
+
+		public Object invoke(
+				Object object,
+		        Method method,
+		        Method method1,
+		        Object[] args) throws Exception {
+			String name = method.getName();
+			if ( "toString".equals( name ) ) {
+				return proxiedClassName + "@" + System.identityHashCode( object );
+			}
+			else if ( "equals".equals( name ) ) {
+				return proxiedObject == object ? Boolean.TRUE : Boolean.FALSE;
+			}
+			else if ( "hashCode".equals( name ) ) {
+				return new Integer( System.identityHashCode( object ) );
+			}
+			boolean hasGetterSignature = method.getParameterTypes().length == 0 && method.getReturnType() != null;
+			boolean hasSetterSignature = method.getParameterTypes().length == 1 && ( method.getReturnType() == null || method.getReturnType() == void.class );
+			if ( name.startsWith( "get" ) && hasGetterSignature ) {
+				String propName = name.substring( 3 );
+				return data.get( propName );
+			}
+			else if ( name.startsWith( "is" ) && hasGetterSignature ) {
+				String propName = name.substring( 2 );
+				return data.get( propName );
+			}
+			else if ( name.startsWith( "set" ) && hasSetterSignature) {
+				String propName = name.substring( 3 );
+				data.put( propName, args[0] );
+				return null;
+			}
+			else {
+				// todo : what else to do here?
+				return null;
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/ReflectionOptimizerImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/ReflectionOptimizerImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/ReflectionOptimizerImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+package org.hibernate.bytecode.javassist;
+
+import org.hibernate.bytecode.ReflectionOptimizer;
+
+import java.io.Serializable;
+
+/**
+ * ReflectionOptimizer implementation for Javassist.
+ *
+ * @author Steve Ebersole
+ */
+public class ReflectionOptimizerImpl implements ReflectionOptimizer, Serializable {
+
+	private final InstantiationOptimizer instantiationOptimizer;
+	private final AccessOptimizer accessOptimizer;
+
+	public ReflectionOptimizerImpl(
+			InstantiationOptimizer instantiationOptimizer,
+	        AccessOptimizer accessOptimizer) {
+		this.instantiationOptimizer = instantiationOptimizer;
+		this.accessOptimizer = accessOptimizer;
+	}
+
+	public InstantiationOptimizer getInstantiationOptimizer() {
+		return instantiationOptimizer;
+	}
+
+	public AccessOptimizer getAccessOptimizer() {
+		return accessOptimizer;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/TransformingClassLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/TransformingClassLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/javassist/TransformingClassLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+package org.hibernate.bytecode.javassist;
+
+import javassist.ClassPool;
+import javassist.NotFoundException;
+import javassist.CtClass;
+import javassist.CannotCompileException;
+import org.hibernate.HibernateException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * @author Steve Ebersole
+ */
+public class TransformingClassLoader extends ClassLoader {
+	private ClassLoader parent;
+	private ClassPool classPool;
+
+	/*package*/ TransformingClassLoader(ClassLoader parent, String[] classpath) {
+		this.parent = parent;
+		classPool = new ClassPool( true );
+		for ( int i = 0; i < classpath.length; i++ ) {
+			try {
+				classPool.appendClassPath( classpath[i] );
+			}
+			catch ( NotFoundException e ) {
+				throw new HibernateException(
+						"Unable to resolve requested classpath for transformation [" +
+						classpath[i] + "] : " + e.getMessage()
+				);
+			}
+		}
+	}
+
+	protected Class findClass(String name) throws ClassNotFoundException {
+        try {
+            CtClass cc = classPool.get( name );
+	        // todo : modify the class definition if not already transformed...
+            byte[] b = cc.toBytecode();
+            return defineClass( name, b, 0, b.length );
+        }
+        catch ( NotFoundException e ) {
+            throw new ClassNotFoundException();
+        }
+        catch ( IOException e ) {
+            throw new ClassNotFoundException();
+        }
+        catch ( CannotCompileException e ) {
+            throw new ClassNotFoundException();
+        }
+    }
+
+	public void release() {
+		classPool = null;
+		parent = null;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+<html>
+	<head></head>
+	<body>
+		<p>
+			This package defines the API for plugging in bytecode libraries
+			for usage by Hibernate.  Hibernate uses these bytecode libraries
+			in three scenarios:<ol>
+				<li>
+					<b>Reflection optimization</b> - to speed up the performance of
+					POJO entity and component conctruction and field/property access
+				</li>
+				<li>
+					<b>Proxy generation</b> - runtime building of proxies used for
+					deferred loading of lazy entities
+				</li>
+				<li>
+					<b>Field-level interception</b> - build-time instrumentation of entity
+					classes for the purpose of intercepting field-level access (read/write)
+					for both lazy loading and dirty tracking.
+				</li>
+			</ol>
+		</p>
+		<p>
+			Currently, both CGLIB and Javassist are supported out-of-the-box.
+		</p>
+		<p>
+			Note that for field-level interception, simply plugging in a new {@link BytecodeProvider}
+			is not enough for Hibernate to be able to recognize new providers.  You would additionally
+			need to make appropriate code changes to the {@link org.hibernate.intercept.Helper}
+			class.  This is because the detection of these enhanced classes is needed in a static
+			environment (i.e. outside the scope of any {@link org.hibernate.SessionFactory}.
+		</p>
+		<p>
+			Note that in the current form the ability to specify a different bytecode provider
+			is actually considered a global settings (global to the JVM).
+		</p>
+	</body>
+</html>

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/BasicClassFilter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/BasicClassFilter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/BasicClassFilter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,59 @@
+package org.hibernate.bytecode.util;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * BasicClassFilter provides class filtering based on a series of packages to
+ * be included and/or a series of explicit class names to be included.  If
+ * neither is specified, then no restrictions are applied.
+ *
+ * @author Steve Ebersole
+ */
+public class BasicClassFilter implements ClassFilter {
+	private final String[] includedPackages;
+	private final Set includedClassNames = new HashSet();
+	private final boolean isAllEmpty;
+
+	public BasicClassFilter() {
+		this( null, null );
+	}
+
+	public BasicClassFilter(String[] includedPackages, String[] includedClassNames) {
+		this.includedPackages = includedPackages;
+		if ( includedClassNames != null ) {
+			for ( int i = 0; i < includedClassNames.length; i++ ) {
+				this.includedClassNames.add( includedClassNames[i] );
+			}
+		}
+
+		isAllEmpty = ( this.includedPackages == null || this.includedPackages.length == 0 )
+		             && ( this.includedClassNames.isEmpty() );
+	}
+
+	public boolean shouldInstrumentClass(String className) {
+		if ( isAllEmpty ) {
+			return true;
+		}
+		else if ( includedClassNames.contains( className ) ) {
+			return true;
+		}
+		else if ( isInIncludedPackage( className ) ) {
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	private boolean isInIncludedPackage(String className) {
+		if ( includedPackages != null ) {
+			for ( int i = 0; i < includedPackages.length; i++ ) {
+				if ( className.startsWith( includedPackages[i] ) ) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/ByteCodeHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/ByteCodeHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/ByteCodeHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+package org.hibernate.bytecode.util;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.BufferedInputStream;
+import java.util.zip.ZipInputStream;
+
+/**
+ * A helper for reading byte code from various input sources.
+ *
+ * @author Steve Ebersole
+ */
+public class ByteCodeHelper {
+	private ByteCodeHelper() {
+	}
+
+	/**
+	 * Reads class byte array info from the given input stream.
+	 * <p/>
+	 * The stream is closed within this method!
+	 *
+	 * @param inputStream
+	 * @return
+	 * @throws IOException
+	 */
+	public static byte[] readByteCode(InputStream inputStream) throws IOException {
+		if ( inputStream == null ) {
+			throw new IOException( "null input stream" );
+		}
+
+		byte[] buffer = new byte[409600];
+		byte[] classBytes = new byte[0];
+		int r = 0;
+
+		try {
+			r = inputStream.read( buffer );
+			while ( r >= buffer.length ) {
+				byte[] temp = new byte[ classBytes.length + buffer.length ];
+				System.arraycopy( classBytes, 0, temp, 0, classBytes.length );
+				System.arraycopy( buffer, 0, temp, classBytes.length, buffer.length );
+				classBytes = temp;
+			}
+			if ( r != -1 ) {
+				byte[] temp = new byte[ classBytes.length + r ];
+				System.arraycopy( classBytes, 0, temp, 0, classBytes.length );
+				System.arraycopy( buffer, 0, temp, classBytes.length, r );
+				classBytes = temp;
+			}
+		}
+		finally {
+			try {
+				inputStream.close();
+			}
+			catch (IOException ignore) {
+				// intentionally empty
+			}
+		}
+
+		return classBytes;
+	}
+
+	public static byte[] readByteCode(File file) throws IOException {
+		return ByteCodeHelper.readByteCode( new FileInputStream( file ) );
+	}
+
+	public static byte[] readByteCode(ZipInputStream zip) throws IOException {
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        InputStream in = new BufferedInputStream( zip );
+        int b;
+        while ( ( b = in.read() ) != -1 ) {
+            bout.write( b );
+        }
+        return bout.toByteArray();
+    }
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/ClassDescriptor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/ClassDescriptor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/ClassDescriptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+package org.hibernate.bytecode.util;
+
+/**
+ * Contract describing the information Hibernate needs in terms of instrumenting
+ * a class, either via ant task or dynamic classloader.
+ *
+ * @author Steve Ebersole
+ */
+public interface ClassDescriptor {
+	/**
+	 * The name of the class.
+	 *
+	 * @return The class name.
+	 */
+	public String getName();
+
+	/**
+	 * Determine if the class is already instrumented.
+	 *
+	 * @return True if already instrumented; false otherwise.
+	 */
+	public boolean isInstrumented();
+
+	/**
+	 * The bytes making up the class' bytecode.
+	 *
+	 * @return The bytecode bytes.
+	 */
+	public byte[] getBytes();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/ClassFilter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/ClassFilter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/ClassFilter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+package org.hibernate.bytecode.util;
+
+/**
+ * Used to determine whether a class should be instrumented.
+ *
+ * @author Steve Ebersole
+ */
+public interface ClassFilter {
+		public boolean shouldInstrumentClass(String className);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/FieldFilter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/FieldFilter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/bytecode/util/FieldFilter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+package org.hibernate.bytecode.util;
+
+/**
+ * Used to determine whether a field reference should be instrumented.
+ *
+ * @author Steve Ebersole
+ */
+public interface FieldFilter {
+	/**
+	 * Should this field definition be instrumented?
+	 *
+	 * @param className The name of the class currently being processed
+	 * @param fieldName The name of the field being checked.
+	 * @return True if we should instrument this field.
+	 */
+	public boolean shouldInstrumentField(String className, String fieldName);
+
+	/**
+	 * Should we instrument *access to* the given field.  This differs from
+	 * {@link #shouldInstrumentField} in that here we are talking about a particular usage of
+	 * a field.
+	 *
+	 * @param transformingClassName The class currently being transformed.
+	 * @param fieldOwnerClassName The name of the class owning this field being checked.
+	 * @param fieldName The name of the field being checked.
+	 * @return True if this access should be transformed.
+	 */
+	public boolean shouldTransformFieldAccess(String transformingClassName, String fieldOwnerClassName, String fieldName);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/AbstractJndiBoundCacheProvider.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/AbstractJndiBoundCacheProvider.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/AbstractJndiBoundCacheProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,86 @@
+// $Id: AbstractJndiBoundCacheProvider.java 6079 2005-03-16 06:01:18Z oneovthafew $
+package org.hibernate.cache;
+
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.cfg.Environment;
+import org.hibernate.util.NamingHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Support for CacheProvider implementations which are backed by caches bound
+ * into JNDI namespace.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractJndiBoundCacheProvider implements CacheProvider {
+
+	private static final Log log = LogFactory.getLog( AbstractJndiBoundCacheProvider.class );
+	private Object cache;
+
+	protected void prepare(Properties properties) {
+		// Do nothing; subclasses may override.
+	}
+
+	protected void release() {
+		// Do nothing; subclasses may override.
+	}
+
+	/**
+	 * Callback to perform any necessary initialization of the underlying cache implementation during SessionFactory
+	 * construction.
+	 *
+	 * @param properties current configuration settings.
+	 */
+	public final void start(Properties properties) throws CacheException {
+		String jndiNamespace = properties.getProperty( Environment.CACHE_NAMESPACE );
+		if ( StringHelper.isEmpty( jndiNamespace ) ) {
+			throw new CacheException( "No JNDI namespace specified for cache" );
+		}
+		cache = locateCache( jndiNamespace, NamingHelper.getJndiProperties( properties ) );
+		prepare( properties );
+	}
+
+	/**
+	 * Callback to perform any necessary cleanup of the underlying cache
+	 * implementation during SessionFactory.close().
+	 */
+	public final void stop() {
+		release();
+		cache = null;
+	}
+
+	private Object locateCache(String jndiNamespace, Properties jndiProperties) {
+
+		Context ctx = null;
+		try {
+			ctx = new InitialContext( jndiProperties );
+			return ctx.lookup( jndiNamespace );
+		}
+		catch (NamingException ne) {
+			String msg = "Unable to retreive Cache from JNDI [" + jndiNamespace + "]";
+			log.info( msg, ne );
+			throw new CacheException( msg );
+		}
+		finally {
+			if ( ctx != null ) {
+				try {
+					ctx.close();
+				}
+				catch( NamingException ne ) {
+					log.info( "Unable to release initial context", ne );
+				}
+			}
+		}
+	}
+	
+	public Object getCache() {
+		return cache;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/Cache.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/Cache.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/Cache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,108 @@
+//$Id: Cache.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import java.util.Map;
+
+/**
+ * Implementors define a caching algorithm. All implementors
+ * <b>must</b> be threadsafe.
+ *
+ * @deprecated As of 3.3; see <a href="package.html"/> for details.
+ */
+public interface Cache {
+	/**
+	 * Get an item from the cache
+	 * @param key
+	 * @return the cached object or <tt>null</tt>
+	 * @throws CacheException
+	 */
+	public Object read(Object key) throws CacheException;
+	/**
+	 * Get an item from the cache, nontransactionally
+	 * @param key
+	 * @return the cached object or <tt>null</tt>
+	 * @throws CacheException
+	 */
+	public Object get(Object key) throws CacheException;
+	/**
+	 * Add an item to the cache, nontransactionally, with
+	 * failfast semantics
+	 * @param key
+	 * @param value
+	 * @throws CacheException
+	 */
+	public void put(Object key, Object value) throws CacheException;
+	/**
+	 * Add an item to the cache
+	 * @param key
+	 * @param value
+	 * @throws CacheException
+	 */
+	public void update(Object key, Object value) throws CacheException;
+	/**
+	 * Remove an item from the cache
+	 */
+	public void remove(Object key) throws CacheException;
+	/**
+	 * Clear the cache
+	 */
+	public void clear() throws CacheException;
+	/**
+	 * Clean up
+	 */
+	public void destroy() throws CacheException;
+	/**
+	 * If this is a clustered cache, lock the item
+	 */
+	public void lock(Object key) throws CacheException;
+	/**
+	 * If this is a clustered cache, unlock the item
+	 */
+	public void unlock(Object key) throws CacheException;
+	/**
+	 * Generate a timestamp
+	 */
+	public long nextTimestamp();
+	/**
+	 * Get a reasonable "lock timeout"
+	 */
+	public int getTimeout();
+	
+	/**
+	 * Get the name of the cache region
+	 */
+	public String getRegionName();
+
+	/**
+	 * The number of bytes is this cache region currently consuming in memory.
+	 *
+	 * @return The number of bytes consumed by this region; -1 if unknown or
+	 * unsupported.
+	 */
+	public long getSizeInMemory();
+
+	/**
+	 * The count of entries currently contained in the regions in-memory store.
+	 *
+	 * @return The count of entries in memory; -1 if unknown or unsupported.
+	 */
+	public long getElementCountInMemory();
+
+	/**
+	 * The count of entries currently contained in the regions disk store.
+	 *
+	 * @return The count of entries on disk; -1 if unknown or unsupported.
+	 */
+	public long getElementCountOnDisk();
+	
+	/**
+	 * optional operation
+	 */
+	public Map toMap();
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheConcurrencyStrategy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheConcurrencyStrategy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheConcurrencyStrategy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,174 @@
+//$Id: CacheConcurrencyStrategy.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import java.util.Comparator;
+
+import org.hibernate.cache.access.SoftLock;
+
+/**
+ * Implementors manage transactional access to cached data. Transactions
+ * pass in a timestamp indicating transaction start time. Two different
+ * implementation patterns are provided for.<ul>
+ * <li>A transaction-aware cache implementation might be wrapped by a
+ * "synchronous" concurrency strategy, where updates to the cache are written
+ * to the cache inside the transaction.</li>
+ * <li>A non transaction-aware cache would be wrapped by an "asynchronous"
+ * concurrency strategy, where items are merely "soft locked" during the 
+ * transaction and then updated during the "after transaction completion"
+ * phase; the soft lock is not an actual lock on the database row -
+ * only upon the cached representation of the item.</li>
+ * </ul>
+ * <p/>
+ * In terms of entity caches, the expected call sequences are: <ul>
+ * <li><b>DELETES</b> : {@link #lock} -> {@link #evict} -> {@link #release}</li>
+ * <li><b>UPDATES</b> : {@link #lock} -> {@link #update} -> {@link #afterUpdate}</li>
+ * <li><b>INSERTS</b> : {@link #insert} -> {@link #afterInsert}</li>
+ * </ul>
+ * <p/>
+ * In terms of collection caches, all modification actions actually just
+ * invalidate the entry(s).  The call sequence here is:
+ * {@link #lock} -> {@link #evict} -> {@link #release}
+ * <p/>
+ * Note that, for an asynchronous cache, cache invalidation must be a two 
+ * step process (lock->release, or lock-afterUpdate), since this is the only 
+ * way to guarantee consistency with the database for a nontransactional cache
+ * implementation. For a synchronous cache, cache invalidation is a single 
+ * step process (evict, or update). Hence, this interface defines a three
+ * step process, to cater for both models.
+ * <p/>
+ * Note that query result caching does not go through a concurrency strategy; they
+ * are managed directly against the underlying {@link Cache cache regions}.
+ *
+ * @deprecated As of 3.3; see <a href="package.html"/> for details.
+ */
+public interface CacheConcurrencyStrategy {
+
+	/**
+	 * Attempt to retrieve an object from the cache. Mainly used in attempting
+	 * to resolve entities/collections from the second level cache.
+	 *
+	 * @param key
+	 * @param txTimestamp a timestamp prior to the transaction start time
+	 * @return the cached object or <tt>null</tt>
+	 * @throws CacheException
+	 */
+	public Object get(Object key, long txTimestamp) throws CacheException;
+
+	/**
+	 * Attempt to cache an object, after loading from the database.
+	 *
+	 * @param key
+	 * @param value
+	 * @param txTimestamp a timestamp prior to the transaction start time
+	 * @param version the item version number
+	 * @param versionComparator a comparator used to compare version numbers
+	 * @param minimalPut indicates that the cache should avoid a put is the item is already cached
+	 * @return <tt>true</tt> if the object was successfully cached
+	 * @throws CacheException
+	 */
+	public boolean put(
+			Object key, 
+			Object value, 
+			long txTimestamp, 
+			Object version, 
+			Comparator versionComparator,
+			boolean minimalPut) 
+	throws CacheException;
+
+	/**
+	 * We are going to attempt to update/delete the keyed object. This
+	 * method is used by "asynchronous" concurrency strategies.
+	 * <p/>
+	 * The returned object must be passed back to release(), to release the
+	 * lock. Concurrency strategies which do not support client-visible
+	 * locks may silently return null.
+	 * 
+	 * @param key
+	 * @param version 
+	 * @throws CacheException
+	 */
+	public SoftLock lock(Object key, Object version) throws CacheException;
+
+	/**
+	 * Called after an item has become stale (before the transaction completes).
+	 * This method is used by "synchronous" concurrency strategies.
+	 */
+	public void evict(Object key) throws CacheException;
+
+	/**
+	 * Called after an item has been updated (before the transaction completes),
+	 * instead of calling evict().
+	 * This method is used by "synchronous" concurrency strategies.
+	 */
+	public boolean update(Object key, Object value, Object currentVersion, Object previousVersion) throws CacheException;
+
+	/**
+	 * Called after an item has been inserted (before the transaction completes),
+	 * instead of calling evict().
+	 * This method is used by "synchronous" concurrency strategies.
+	 */
+	public boolean insert(Object key, Object value, Object currentVersion) throws CacheException;
+	
+	
+	/**
+	 * Called when we have finished the attempted update/delete (which may or 
+	 * may not have been successful), after transaction completion.
+	 * This method is used by "asynchronous" concurrency strategies.
+	 * @param key
+	 * @throws CacheException
+	 */
+	public void release(Object key, SoftLock lock) throws CacheException;
+	/**
+	 * Called after an item has been updated (after the transaction completes),
+	 * instead of calling release().
+	 * This method is used by "asynchronous" concurrency strategies.
+	 */
+	public boolean afterUpdate(Object key, Object value, Object version, SoftLock lock)
+	throws CacheException;
+	/**
+	 * Called after an item has been inserted (after the transaction completes),
+	 * instead of calling release().
+	 * This method is used by "asynchronous" concurrency strategies.
+	 */
+	public boolean afterInsert(Object key, Object value, Object version) 
+	throws CacheException;
+	
+	
+	/**
+	 * Evict an item from the cache immediately (without regard for transaction
+	 * isolation).
+	 * @param key
+	 * @throws CacheException
+	 */
+	public void remove(Object key) throws CacheException;
+	/**
+	 * Evict all items from the cache immediately.
+	 * @throws CacheException
+	 */
+	public void clear() throws CacheException;
+	/**
+	 * Clean up all resources.
+	 */
+	public void destroy();
+	/**
+	 * Set the underlying cache implementation.
+	 * @param cache
+	 */
+	public void setCache(Cache cache);
+		
+	/**
+	 * Get the cache region name
+	 */
+	public String getRegionName();
+	
+	/**
+	 * Get the wrapped cache implementation
+	 */
+	public Cache getCache();
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheDataDescription.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheDataDescription.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheDataDescription.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+package org.hibernate.cache;
+
+import java.util.Comparator;
+
+/**
+ * Describes attributes regarding the type of data to be cached.
+ *
+ * @author Steve Ebersole
+ */
+public interface CacheDataDescription {
+	/**
+	 * Is the data marked as being mutable?
+	 *
+	 * @return True if the data is mutable; false otherwise.
+	 */
+	public boolean isMutable();
+
+	/**
+	 * Is the data to be cached considered versioned?
+	 * <p/>
+	 * If true, it is illegal for {@link #getVersionComparator} to return
+	 * null.
+	 *
+	 * @return True if the data is versioned; false otherwise.
+	 */
+	public boolean isVersioned();
+
+	/**
+	 * Get the comparator used to compare two different version values.
+	 * <p/>
+	 * May return null <b>if</b> {@link #isVersioned()} returns false.
+	 * @return
+	 */
+	public Comparator getVersionComparator();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+//$Id: CacheException.java 11492 2007-05-09 01:57:11Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Something went wrong in the cache
+ */
+public class CacheException extends HibernateException {
+	
+	public CacheException(String s) {
+		super(s);
+	}
+
+	public CacheException(String s, Throwable e) {
+		super(s, e);
+	}
+	
+	public CacheException(Throwable e) {
+		super(e);
+	}
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheKey.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheKey.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,72 @@
+//$Id: CacheKey.java 11499 2007-05-09 17:35:55Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import java.io.Serializable;
+
+import org.hibernate.EntityMode;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Allows multiple entity classes / collection roles to be
+ * stored in the same cache region. Also allows for composite
+ * keys which do not properly implement equals()/hashCode().
+ *
+ * @author Gavin King
+ */
+public class CacheKey implements Serializable {
+	private final Serializable key;
+	private final Type type;
+	private final String entityOrRoleName;
+	private final EntityMode entityMode;
+	private final int hashCode;
+
+	/**
+	 * Construct a new key for a collection or entity instance.
+	 * Note that an entity name should always be the root entity
+	 * name, not a subclass entity name.
+	 *
+	 * @param id The identifier associated with the cached data
+	 * @param type The Hibernate type mapping
+	 * @param entityOrRoleName The entity or collection-role name.
+	 * @param entityMode The entiyt mode of the originating session
+	 * @param factory The session factory for which we are caching
+	 */
+	public CacheKey(
+			final Serializable id,
+			final Type type,
+			final String entityOrRoleName,
+			final EntityMode entityMode,
+			final SessionFactoryImplementor factory) {
+		this.key = id;
+		this.type = type;
+		this.entityOrRoleName = entityOrRoleName;
+		this.entityMode = entityMode;
+		hashCode = type.getHashCode( key, entityMode, factory );
+	}
+
+	//Mainly for OSCache
+	public String toString() {
+		return entityOrRoleName + '#' + key.toString();//"CacheKey#" + type.toString(key, sf);
+	}
+
+	public boolean equals(Object other) {
+		if ( !(other instanceof CacheKey) ) return false;
+		CacheKey that = (CacheKey) other;
+		return entityOrRoleName.equals( that.entityOrRoleName )
+				&& type.isEqual( key, that.key, entityMode );
+	}
+
+	public int hashCode() {
+		return hashCode;
+	}
+
+	public Serializable getKey() {
+		return key;
+	}
+
+	public String getEntityOrRoleName() {
+		return entityOrRoleName;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheKey.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheProvider.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheProvider.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CacheProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+//$Id: CacheProvider.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import java.util.Properties;
+
+/**
+ * Support for pluggable caches.
+ *
+ * @author Gavin King
+ * @deprecated As of 3.3; see <a href="package.html"/> for details.
+ */
+public interface CacheProvider {
+
+	/**
+	 * Configure the cache
+	 *
+	 * @param regionName the name of the cache region
+	 * @param properties configuration settings
+	 * @throws CacheException
+	 */
+	public Cache buildCache(String regionName, Properties properties) throws CacheException;
+
+	/**
+	 * Generate a timestamp
+	 */
+	public long nextTimestamp();
+
+	/**
+	 * Callback to perform any necessary initialization of the underlying cache implementation
+	 * during SessionFactory construction.
+	 *
+	 * @param properties current configuration settings.
+	 */
+	public void start(Properties properties) throws CacheException;
+
+	/**
+	 * Callback to perform any necessary cleanup of the underlying cache implementation
+	 * during SessionFactory.close().
+	 */
+	public void stop();
+	
+	public boolean isMinimalPutsEnabledByDefault();
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CollectionRegion.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CollectionRegion.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/CollectionRegion.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+package org.hibernate.cache;
+
+import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cache.access.AccessType;
+
+/**
+ * Defines the contract for a cache region which will specifically be used to
+ * store collection data.
+ * <p/>
+ * Impl note: Hibernate always deals with changes to collections which
+ * (potentially) has its data in the L2 cache by removing that collection
+ * data; in other words it never tries to update the cached state, thereby
+ * allowing it to avoid a bunch of concurrency problems.
+ *
+ * @author Steve Ebersole
+ */
+public interface CollectionRegion extends TransactionalDataRegion {
+
+	/**
+	 * Build an access strategy for the requested access type.
+	 *
+	 * @param accessType The type of access strategy to build; never null.
+	 * @return The appropriate strategy contract for accessing this region
+	 * for the requested type of access.
+	 * @throws CacheException Usually indicates mis-configuration.
+	 */
+	public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/EntityRegion.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/EntityRegion.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/EntityRegion.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+package org.hibernate.cache;
+
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cache.access.AccessType;
+
+/**
+ * Defines the contract for a cache region which will specifically be used to
+ * store entity data.
+ *
+ * @author Steve Ebersole
+ */
+public interface EntityRegion extends TransactionalDataRegion {
+
+	/**
+	 * Build an access strategy for the requested access type.
+	 *
+	 * @param accessType The type of access strategy to build; never null.
+	 * @return The appropriate strategy contract for accessing this region
+	 * for the requested type of access.
+	 * @throws CacheException Usually indicates mis-configuration.
+	 */
+	public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/FilterKey.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/FilterKey.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/FilterKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,70 @@
+//$Id: FilterKey.java 8754 2005-12-05 23:36:59Z steveebersole $
+package org.hibernate.cache;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.EntityMode;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.impl.FilterImpl;
+import org.hibernate.type.Type;
+
+/**
+ * Allows cached queries to be keyed by enabled filters.
+ * 
+ * @author Gavin King
+ */
+public final class FilterKey implements Serializable {
+	private String filterName;
+	private Map filterParameters = new HashMap();
+	
+	public FilterKey(String name, Map params, Map types, EntityMode entityMode) {
+		filterName = name;
+		Iterator iter = params.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			Type type = (Type) types.get( me.getKey() );
+			filterParameters.put( me.getKey(), new TypedValue( type, me.getValue(), entityMode ) );
+		}
+	}
+	
+	public int hashCode() {
+		int result = 13;
+		result = 37 * result + filterName.hashCode();
+		result = 37 * result + filterParameters.hashCode();
+		return result;
+	}
+	
+	public boolean equals(Object other) {
+		if ( !(other instanceof FilterKey) ) return false;
+		FilterKey that = (FilterKey) other;
+		if ( !that.filterName.equals(filterName) ) return false;
+		if ( !that.filterParameters.equals(filterParameters) ) return false;
+		return true;
+	}
+	
+	public String toString() {
+		return "FilterKey[" + filterName + filterParameters + ']';
+	}
+	
+	public static Set createFilterKeys(Map enabledFilters, EntityMode entityMode) {
+		if ( enabledFilters.size()==0 ) return null;
+		Set result = new HashSet();
+		Iterator iter = enabledFilters.values().iterator();
+		while ( iter.hasNext() ) {
+			FilterImpl filter = (FilterImpl) iter.next();
+			FilterKey key = new FilterKey(
+					filter.getName(), 
+					filter.getParameters(), 
+					filter.getFilterDefinition().getParameterTypes(), 
+					entityMode
+				);
+			result.add(key);
+		}
+		return result;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/FilterKey.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/GeneralDataRegion.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/GeneralDataRegion.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/GeneralDataRegion.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+package org.hibernate.cache;
+
+/**
+ * Contract for general-purpose cache regions.
+ *
+ * @author Steve Ebersole
+ */
+public interface GeneralDataRegion extends Region {
+
+	/**
+	 * Get an item from the cache.
+	 *
+	 * @param key The key of the item to be retrieved.
+	 * @return the cached object or <tt>null</tt>
+	 * @throws CacheException Indicates a problem accessing the item or region.
+	 */
+	public Object get(Object key) throws CacheException;
+
+	/**
+	 * Put an item into the cache.
+	 *
+	 * @param key The key under which to cache the item.
+	 * @param value The item to cache.
+	 * @throws CacheException Indicates a problem accessing the region.
+	 */
+	public void put(Object key, Object value) throws CacheException;
+
+	/**
+	 * Evict an item from the cache immediately (without regard for transaction
+	 * isolation).
+	 *
+	 * @param key The key of the item to remove
+	 * @throws CacheException Indicates a problem accessing the item or region.
+	 */
+	public void evict(Object key) throws CacheException;
+
+	/**
+	 * Evict all contents of this particular cache region (without regard for transaction
+	 * isolation).
+	 *
+	 * @throws CacheException Indicates problem accessing the region.
+	 */
+	public void evictAll() throws CacheException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/HashtableCache.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/HashtableCache.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/HashtableCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,90 @@
+//$Id: HashtableCache.java 6478 2005-04-21 07:57:19Z oneovthafew $
+package org.hibernate.cache;
+
+import java.util.Collections;
+import java.util.Hashtable;
+
+import java.util.Map;
+
+/**
+ * A lightweight implementation of the <tt>Cache</tt> interface
+ * @author Gavin King
+ */
+public class HashtableCache implements Cache {
+	
+	private final Map hashtable = new Hashtable();
+	private final String regionName;
+	
+	public HashtableCache(String regionName) {
+		this.regionName = regionName;
+	}
+
+	public String getRegionName() {
+		return regionName;
+	}
+
+	public Object read(Object key) throws CacheException {
+		return hashtable.get(key);
+	}
+
+	public Object get(Object key) throws CacheException {
+		return hashtable.get(key);
+	}
+
+	public void update(Object key, Object value) throws CacheException {
+		put(key, value);
+	}
+	
+	public void put(Object key, Object value) throws CacheException {
+		hashtable.put(key, value);
+	}
+
+	public void remove(Object key) throws CacheException {
+		hashtable.remove(key);
+	}
+
+	public void clear() throws CacheException {
+		hashtable.clear();
+	}
+
+	public void destroy() throws CacheException {
+
+	}
+
+	public void lock(Object key) throws CacheException {
+		// local cache, so we use synchronization
+	}
+
+	public void unlock(Object key) throws CacheException {
+		// local cache, so we use synchronization
+	}
+
+	public long nextTimestamp() {
+		return Timestamper.next();
+	}
+
+	public int getTimeout() {
+		return Timestamper.ONE_MS * 60000; //ie. 60 seconds
+	}
+
+	public long getSizeInMemory() {
+		return -1;
+	}
+
+	public long getElementCountInMemory() {
+		return hashtable.size();
+	}
+
+	public long getElementCountOnDisk() {
+		return 0;
+	}
+	
+	public Map toMap() {
+		return Collections.unmodifiableMap(hashtable);
+	}
+
+	public String toString() {
+		return "HashtableCache(" + regionName + ')';
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/HashtableCacheProvider.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/HashtableCacheProvider.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/HashtableCacheProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+//$Id: HashtableCacheProvider.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.cache;
+
+import java.util.Properties;
+
+/**
+ * A simple in-memory Hashtable-based cache impl.
+ * 
+ * @author Gavin King
+ */
+public class HashtableCacheProvider implements CacheProvider {
+
+	public Cache buildCache(String regionName, Properties properties) throws CacheException {
+		return new HashtableCache( regionName );
+	}
+
+	public long nextTimestamp() {
+		return Timestamper.next();
+	}
+
+	/**
+	 * Callback to perform any necessary initialization of the underlying cache implementation
+	 * during SessionFactory construction.
+	 *
+	 * @param properties current configuration settings.
+	 */
+	public void start(Properties properties) throws CacheException {
+	}
+
+	/**
+	 * Callback to perform any necessary cleanup of the underlying cache implementation
+	 * during SessionFactory.close().
+	 */
+	public void stop() {
+	}
+
+	public boolean isMinimalPutsEnabledByDefault() {
+		return false;
+	}
+
+}
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/NoCacheProvider.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/NoCacheProvider.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/NoCacheProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,58 @@
+// $Id: NoCacheProvider.java 6433 2005-04-15 18:20:03Z steveebersole $
+package org.hibernate.cache;
+
+import java.util.Properties;
+
+/**
+ * Implementation of NoCacheProvider.
+ *
+ * @author Steve Ebersole
+ */
+public class NoCacheProvider implements CacheProvider {
+	/**
+	 * Configure the cache
+	 *
+	 * @param regionName the name of the cache region
+	 * @param properties configuration settings
+	 *
+	 * @throws CacheException
+	 */
+	public Cache buildCache(String regionName, Properties properties) throws CacheException {
+		throw new NoCachingEnabledException();
+	}
+
+	/**
+	 * Generate a timestamp
+	 */
+	public long nextTimestamp() {
+		// This, is used by SessionFactoryImpl to hand to the generated SessionImpl;
+		// was the only reason I could see that we cannot just use null as
+		// Settings.cacheProvider
+		return System.currentTimeMillis() / 100;
+	}
+
+	/**
+	 * Callback to perform any necessary initialization of the underlying cache implementation during SessionFactory
+	 * construction.
+	 *
+	 * @param properties current configuration settings.
+	 */
+	public void start(Properties properties) throws CacheException {
+		// this is called by SessionFactory irregardless; we just disregard here;
+		// could also add a check to SessionFactory to only conditionally call start
+	}
+
+	/**
+	 * Callback to perform any necessary cleanup of the underlying cache implementation during SessionFactory.close().
+	 */
+	public void stop() {
+		// this is called by SessionFactory irregardless; we just disregard here;
+		// could also add a check to SessionFactory to only conditionally call stop
+	}
+
+	public boolean isMinimalPutsEnabledByDefault() {
+		// this is called from SettingsFactory irregardless; trivial to simply disregard
+		return false;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/NoCachingEnabledException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/NoCachingEnabledException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/NoCachingEnabledException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+// $Id: NoCachingEnabledException.java 6433 2005-04-15 18:20:03Z steveebersole $
+package org.hibernate.cache;
+
+import org.hibernate.cfg.Environment;
+
+/**
+ * Implementation of NoCachingEnabledException.
+ *
+ * @author Steve Ebersole
+ */
+public class NoCachingEnabledException extends CacheException {
+	private static final String MSG =
+	        "Second-level cache is not enabled for usage [" +
+	        Environment.USE_SECOND_LEVEL_CACHE +
+	        " | " + Environment.USE_QUERY_CACHE + "]";
+
+	public NoCachingEnabledException() {
+		super( MSG );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/NonstrictReadWriteCache.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/NonstrictReadWriteCache.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/NonstrictReadWriteCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,172 @@
+//$Id: NonstrictReadWriteCache.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import java.util.Comparator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.cache.access.SoftLock;
+
+/**
+ * Caches data that is sometimes updated without ever locking the cache.
+ * If concurrent access to an item is possible, this concurrency strategy
+ * makes no guarantee that the item returned from the cache is the latest
+ * version available in the database. Configure your cache timeout accordingly!
+ * This is an "asynchronous" concurrency strategy.
+ *
+ * @author Gavin King
+ * @see ReadWriteCache for a much stricter algorithm
+ */
+public class NonstrictReadWriteCache implements CacheConcurrencyStrategy {
+
+	private Cache cache;
+
+	private static final Log log = LogFactory.getLog( NonstrictReadWriteCache.class );
+
+	public NonstrictReadWriteCache() {
+	}
+
+	public void setCache(Cache cache) {
+		this.cache = cache;
+	}
+
+	public Cache getCache() {
+		return cache;
+	}
+
+	/**
+	 * Get the most recent version, if available.
+	 */
+	public Object get(Object key, long txTimestamp) throws CacheException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Cache lookup: " + key );
+		}
+
+		Object result = cache.get( key );
+		if ( result != null ) {
+			log.debug( "Cache hit" );
+		}
+		else {
+			log.debug( "Cache miss" );
+		}
+		return result;
+	}
+
+	/**
+	 * Add an item to the cache.
+	 */
+	public boolean put(
+			Object key,
+	        Object value,
+	        long txTimestamp,
+	        Object version,
+	        Comparator versionComparator,
+	        boolean minimalPut) throws CacheException {
+		if ( minimalPut && cache.get( key ) != null ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "item already cached: " + key );
+			}
+			return false;
+		}
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Caching: " + key );
+		}
+
+		cache.put( key, value );
+		return true;
+
+	}
+
+	/**
+	 * Do nothing.
+	 *
+	 * @return null, no lock
+	 */
+	public SoftLock lock(Object key, Object version) throws CacheException {
+		return null;
+	}
+
+	public void remove(Object key) throws CacheException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Removing: " + key );
+		}
+		cache.remove( key );
+	}
+
+	public void clear() throws CacheException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Clearing" );
+		}
+		cache.clear();
+	}
+
+	public void destroy() {
+		try {
+			cache.destroy();
+		}
+		catch ( Exception e ) {
+			log.warn( "could not destroy cache", e );
+		}
+	}
+
+	/**
+	 * Invalidate the item
+	 */
+	public void evict(Object key) throws CacheException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Invalidating: " + key );
+		}
+
+		cache.remove( key );
+	}
+
+	/**
+	 * Invalidate the item
+	 */
+	public boolean insert(Object key, Object value, Object currentVersion) {
+		return false;
+	}
+
+	/**
+	 * Do nothing.
+	 */
+	public boolean update(Object key, Object value, Object currentVersion, Object previousVersion) {
+		evict( key );
+		return false;
+	}
+
+	/**
+	 * Invalidate the item (again, for safety).
+	 */
+	public void release(Object key, SoftLock lock) throws CacheException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Invalidating (again): " + key );
+		}
+
+		cache.remove( key );
+	}
+
+	/**
+	 * Invalidate the item (again, for safety).
+	 */
+	public boolean afterUpdate(Object key, Object value, Object version, SoftLock lock) throws CacheException {
+		release( key, lock );
+		return false;
+	}
+
+	/**
+	 * Do nothing.
+	 */
+	public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
+		return false;
+	}
+
+	public String getRegionName() {
+		return cache.getRegionName();
+	}
+
+	public String toString() {
+		return cache + "(nonstrict-read-write)";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/OptimisticCache.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/OptimisticCache.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/OptimisticCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+package org.hibernate.cache;
+
+/**
+ * A contract for transactional cache implementations which support
+ * optimistic locking of items within the cache.
+ * <p/>
+ * The optimisitic locking capabilities are only utilized for
+ * the entity cache regions.
+ * <p/>
+ * Unlike the methods on the {@link Cache} interface, all the methods
+ * here will only ever be called from access scenarios where versioned
+ * data is actually a possiblity (i.e., entity data).  Be sure to consult
+ * with {@link OptimisticCacheSource#isVersioned()} to determine whether
+ * versioning is actually in effect.
+ *
+ * @author Steve Ebersole
+ */
+public interface OptimisticCache extends Cache {
+	/**
+	 * Indicates the "source" of the cached data.  Currently this will
+	 * only ever represent an {@link org.hibernate.persister.entity.EntityPersister}.
+	 * <p/>
+	 * Made available to the cache so that it can access certain information
+	 * about versioning strategy.
+	 *
+	 * @param source The source.
+	 */
+	public void setSource(OptimisticCacheSource source);
+
+	/**
+	 * Called during {@link CacheConcurrencyStrategy#insert} processing for
+	 * transactional strategies.  Indicates we have just performed an insert
+	 * into the DB and now need to cache that entity's data.
+	 *
+	 * @param key The cache key.
+	 * @param value The data to be cached.
+	 * @param currentVersion The entity's version; or null if not versioned.
+	 */
+	public void writeInsert(Object key, Object value, Object currentVersion);
+
+	/**
+	 * Called during {@link CacheConcurrencyStrategy#update} processing for
+	 * transactional strategies.  Indicates we have just performed an update
+	 * against the DB and now need to cache the updated state.
+	 *
+	 * @param key The cache key.
+	 * @param value The data to be cached.
+	 * @param currentVersion The entity's current version
+	 * @param previousVersion The entity's previous version (before the update);
+	 * or null if not versioned.
+	 */
+	public void writeUpdate(Object key, Object value, Object currentVersion, Object previousVersion);
+
+	/**
+	 * Called during {@link CacheConcurrencyStrategy#put} processing for
+	 * transactional strategies.  Indicates we have just loaded an entity's
+	 * state from the database and need it cached.
+	 *
+	 * @param key The cache key.
+	 * @param value The data to be cached.
+	 * @param currentVersion The entity's version; or null if not versioned.
+	 */
+	public void writeLoad(Object key, Object value, Object currentVersion);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/OptimisticCacheSource.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/OptimisticCacheSource.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/OptimisticCacheSource.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+package org.hibernate.cache;
+
+import java.util.Comparator;
+
+/**
+ * Contract for sources of optimistically lockable data sent to the second level
+ * cache.
+ * <p/>
+ * Note currently {@link org.hibernate.persister.entity.EntityPersister}s are
+ * the only viable source.
+ *
+ * @author Steve Ebersole
+ */
+public interface OptimisticCacheSource {
+	/**
+	 * Is the data to be cached considered versioned?
+	 * <p/>
+	 * If true, it is illegal for {@link #getVersionComparator} to return
+	 * null.
+	 *
+	 * @return True if the data is versioned; false otherwise.
+	 */
+	public boolean isVersioned();
+
+	/**
+	 * Get the comparator used to compare two different version values.
+	 * <p/>
+	 * May return null <b>if</b> {@link #isVersioned()} returns false.
+	 * @return
+	 */
+	public Comparator getVersionComparator();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryCache.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryCache.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+//$Id: QueryCache.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import java.util.List;
+import java.util.Set;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Defines the contract for caches capable of storing query results.  These
+ * caches should only concern themselves with storing the matching result ids.
+ * The transactional semantics are necessarily less strict than the semantics
+ * of an item cache.
+ * 
+ * @author Gavin King
+ */
+public interface QueryCache {
+
+	public void clear() throws CacheException;
+	
+	public boolean put(QueryKey key, Type[] returnTypes, List result, boolean isNaturalKeyLookup, SessionImplementor session) throws HibernateException;
+
+	public List get(QueryKey key, Type[] returnTypes, boolean isNaturalKeyLookup, Set spaces, SessionImplementor session) throws HibernateException;
+
+	public void destroy();
+
+	public QueryResultsRegion getRegion();
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryCacheFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryCacheFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryCacheFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+// $Id: QueryCacheFactory.java 4690 2004-10-26 09:35:46Z oneovthafew $
+package org.hibernate.cache;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Settings;
+
+import java.util.Properties;
+
+/**
+ * Defines a factory for query cache instances.  These factories are responsible for
+ * creating individual QueryCache instances.
+ *
+ * @author Steve Ebersole
+ */
+public interface QueryCacheFactory {
+
+	public QueryCache getQueryCache(
+	        String regionName,
+	        UpdateTimestampsCache updateTimestampsCache,
+			Settings settings,
+	        Properties props) 
+	throws HibernateException;
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryKey.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryKey.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,117 @@
+//$Id: QueryKey.java 9636 2006-03-16 14:14:48Z max.andersen at jboss.com $
+package org.hibernate.cache;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.EntityMode;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.RowSelection;
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.type.Type;
+import org.hibernate.util.EqualsHelper;
+
+/**
+ * A key that identifies a particular query with bound parameter values
+ * @author Gavin King
+ */
+public class QueryKey implements Serializable {
+	private final String sqlQueryString;
+	private final Type[] types;
+	private final Object[] values;
+	private final Integer firstRow;
+	private final Integer maxRows;
+	private final Map namedParameters;
+	private final EntityMode entityMode;
+	private final Set filters;
+	private final int hashCode;
+	
+	// the user provided resulttransformer, not the one used with "select new". Here to avoid mangling transformed/non-transformed results.
+	private final ResultTransformer customTransformer;
+	
+	public QueryKey(String queryString, QueryParameters queryParameters, Set filters, EntityMode entityMode) {
+		this.sqlQueryString = queryString;
+		this.types = queryParameters.getPositionalParameterTypes();
+		this.values = queryParameters.getPositionalParameterValues();
+		RowSelection selection = queryParameters.getRowSelection();
+		if (selection!=null) {
+			firstRow = selection.getFirstRow();
+			maxRows = selection.getMaxRows();
+		}
+		else {
+			firstRow = null;
+			maxRows = null;
+		}
+		this.namedParameters = queryParameters.getNamedParameters();
+		this.entityMode = entityMode;
+		this.filters = filters;
+		this.customTransformer = queryParameters.getResultTransformer();
+		this.hashCode = getHashCode();
+	}
+	
+	public boolean equals(Object other) {
+		QueryKey that = (QueryKey) other;
+		if ( !sqlQueryString.equals(that.sqlQueryString) ) return false;
+		if ( !EqualsHelper.equals(firstRow, that.firstRow) || !EqualsHelper.equals(maxRows, that.maxRows) ) return false;
+		if ( !EqualsHelper.equals(customTransformer, that.customTransformer) ) return false;
+		if (types==null) {
+			if (that.types!=null) return false;
+		}
+		else {
+			if (that.types==null) return false;
+			if ( types.length!=that.types.length ) return false;
+			for ( int i=0; i<types.length; i++ ) {
+				if ( types[i].getReturnedClass() != that.types[i].getReturnedClass() ) return false;
+				if ( !types[i].isEqual( values[i], that.values[i], entityMode ) ) return false;
+			}
+		}
+		if ( !EqualsHelper.equals(filters, that.filters) ) return false;
+		if ( !EqualsHelper.equals(namedParameters, that.namedParameters) ) return false;
+		return true;
+	}
+	
+	public int hashCode() {
+		return hashCode;
+	}
+	
+	private int getHashCode() {
+		int result = 13;
+		result = 37 * result + ( firstRow==null ? 0 : firstRow.hashCode() );
+		result = 37 * result + ( maxRows==null ? 0 : maxRows.hashCode() );
+		for ( int i=0; i<values.length; i++ ) {
+			result = 37 * result + ( values[i]==null ? 0 : types[i].getHashCode( values[i], entityMode ) );
+		}
+		result = 37 * result + ( namedParameters==null ? 0 : namedParameters.hashCode() );
+		result = 37 * result + ( filters==null ? 0 : filters.hashCode() );
+		result = 37 * result + ( customTransformer==null ? 0 : customTransformer.hashCode() );
+		result = 37 * result + sqlQueryString.hashCode();
+		return result;
+	}
+
+	public String toString() {
+		StringBuffer buf = new StringBuffer()
+			.append("sql: ")
+			.append(sqlQueryString);
+		if (values!=null) {
+			buf.append("; parameters: ");
+			for (int i=0; i<values.length; i++) {
+				buf.append( values[i] )
+					.append(", ");
+			}
+		}
+		if (namedParameters!=null) {
+			buf.append("; named parameters: ")
+				.append(namedParameters);
+		}
+		if (filters!=null) {
+			buf.append("; filters: ")
+				.append(filters);
+		}
+		if (firstRow!=null) buf.append("; first row: ").append(firstRow);
+		if (maxRows!=null) buf.append("; max rows: ").append(maxRows);
+		if (customTransformer!=null) buf.append("; transformer: ").append(customTransformer);
+		return buf.toString();
+	}
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryResultsRegion.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryResultsRegion.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/QueryResultsRegion.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+package org.hibernate.cache;
+
+/**
+ * Defines the contract for a cache region which will specifically be used to
+ * store query results.
+ *
+ * @author Steve Ebersole
+ */
+public interface QueryResultsRegion extends GeneralDataRegion {
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/ReadOnlyCache.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/ReadOnlyCache.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/ReadOnlyCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,139 @@
+//$Id: ReadOnlyCache.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import java.util.Comparator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.cache.access.SoftLock;
+
+/**
+ * Caches data that is never updated.
+ * @see CacheConcurrencyStrategy
+ */
+public class ReadOnlyCache implements CacheConcurrencyStrategy {
+	
+	private Cache cache;
+	private static final Log log = LogFactory.getLog(ReadOnlyCache.class);
+	
+	public ReadOnlyCache() {}
+	
+	public void setCache(Cache cache) {
+		this.cache=cache;
+	}
+
+	public Cache getCache() {
+		return cache;
+	}
+
+	public String getRegionName() {
+		return cache.getRegionName();
+	}
+	
+	public synchronized Object get(Object key, long timestamp) throws CacheException {
+		Object result = cache.get(key);
+		if ( result!=null && log.isDebugEnabled() ) log.debug("Cache hit: " + key);
+		return result;
+	}
+	
+	/**
+	 * Unsupported!
+	 */
+	public SoftLock lock(Object key, Object version) {
+		log.error("Application attempted to edit read only item: " + key);
+		throw new UnsupportedOperationException("Can't write to a readonly object");
+	}
+	
+	public synchronized boolean put(
+			Object key, 
+			Object value, 
+			long timestamp, 
+			Object version, 
+			Comparator versionComparator,
+			boolean minimalPut) 
+	throws CacheException {
+		if ( minimalPut && cache.get(key)!=null ) {
+			if ( log.isDebugEnabled() ) log.debug("item already cached: " + key);
+			return false;
+		}
+		if ( log.isDebugEnabled() ) log.debug("Caching: " + key);
+		cache.put(key, value);
+		return true;
+	}
+	
+	/**
+	 * Unsupported!
+	 */
+	public void release(Object key, SoftLock lock) {
+		log.error("Application attempted to edit read only item: " + key);
+		//throw new UnsupportedOperationException("Can't write to a readonly object");
+	}
+	
+	public void clear() throws CacheException {
+		cache.clear();
+	}
+
+	public void remove(Object key) throws CacheException {
+		cache.remove(key);
+	}
+	
+	public void destroy() {
+		try {
+			cache.destroy();
+		}
+		catch (Exception e) {
+			log.warn("could not destroy cache", e);
+		}
+	}
+
+	/**
+	 * Unsupported!
+	 */
+	public boolean afterUpdate(Object key, Object value, Object version, SoftLock lock) throws CacheException {
+		log.error("Application attempted to edit read only item: " + key);
+		throw new UnsupportedOperationException("Can't write to a readonly object");
+	}
+
+	/**
+	 * Do nothing.
+	 */
+	public boolean afterInsert(Object key, Object value, Object version) throws CacheException {		
+		if ( log.isDebugEnabled() ) log.debug("Caching after insert: " + key);
+		cache.update(key, value);
+		return true;
+	}
+
+	/**
+	 * Do nothing.
+	 */
+	public void evict(Object key) throws CacheException {
+		// noop
+	}
+
+	/**
+	 * Do nothing.
+	 */
+	public boolean insert(Object key, Object value, Object currentVersion) {
+		return false;
+	}
+
+	/**
+	 * Unsupported!
+	 */
+	public boolean update(Object key, Object value, Object currentVersion, Object previousVersion) {
+		log.error("Application attempted to edit read only item: " + key);
+		throw new UnsupportedOperationException("Can't write to a readonly object");
+	}
+
+	public String toString() {
+		return cache + "(read-only)";
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/ReadWriteCache.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/ReadWriteCache.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/ReadWriteCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,508 @@
+//$Id: ReadWriteCache.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.cache.access.SoftLock;
+
+/**
+ * Caches data that is sometimes updated while maintaining the semantics of
+ * "read committed" isolation level. If the database is set to "repeatable
+ * read", this concurrency strategy <em>almost</em> maintains the semantics.
+ * Repeatable read isolation is compromised in the case of concurrent writes.
+ * This is an "asynchronous" concurrency strategy.<br>
+ * <br>
+ * If this strategy is used in a cluster, the underlying cache implementation
+ * must support distributed hard locks (which are held only momentarily). This
+ * strategy also assumes that the underlying cache implementation does not do
+ * asynchronous replication and that state has been fully replicated as soon
+ * as the lock is released.
+ *
+ * @see NonstrictReadWriteCache for a faster algorithm
+ * @see CacheConcurrencyStrategy
+ */
+public class ReadWriteCache implements CacheConcurrencyStrategy {
+
+	private static final Log log = LogFactory.getLog(ReadWriteCache.class);
+
+	private Cache cache;
+	private int nextLockId;
+
+	public ReadWriteCache() {}
+
+	public void setCache(Cache cache) {
+		this.cache=cache;
+	}
+
+	public Cache getCache() {
+		return cache;
+	}
+
+	public String getRegionName() {
+		return cache.getRegionName();
+	}
+	
+	/**
+	 * Generate an id for a new lock. Uniqueness per cache instance is very
+	 * desirable but not absolutely critical. Must be called from one of the
+	 * synchronized methods of this class.
+	 */
+	private int nextLockId() {
+		if (nextLockId==Integer.MAX_VALUE) nextLockId = Integer.MIN_VALUE;
+		return nextLockId++;
+	}
+
+	/**
+	 * Do not return an item whose timestamp is later than the current
+	 * transaction timestamp. (Otherwise we might compromise repeatable
+	 * read unnecessarily.) Do not return an item which is soft-locked.
+	 * Always go straight to the database instead.<br>
+	 * <br>
+	 * Note that since reading an item from that cache does not actually
+	 * go to the database, it is possible to see a kind of phantom read
+	 * due to the underlying row being updated after we have read it
+	 * from the cache. This would not be possible in a lock-based
+	 * implementation of repeatable read isolation. It is also possible
+	 * to overwrite changes made and committed by another transaction
+	 * after the current transaction read the item from the cache. This
+	 * problem would be caught by the update-time version-checking, if
+	 * the data is versioned or timestamped.
+	 */
+	public synchronized Object get(Object key, long txTimestamp) throws CacheException {
+
+		if ( log.isTraceEnabled() ) log.trace("Cache lookup: " + key);
+
+		/*try {
+			cache.lock(key);*/
+
+			Lockable lockable = (Lockable) cache.get(key);
+
+			boolean gettable = lockable!=null && lockable.isGettable(txTimestamp);
+
+			if (gettable) {
+				if ( log.isTraceEnabled() ) log.trace("Cache hit: " + key);
+				return ( (Item) lockable ).getValue();
+			}
+			else {
+				if ( log.isTraceEnabled() ) {
+					if (lockable==null) {
+						log.trace("Cache miss: " + key);
+					}
+					else {
+						log.trace("Cached item was locked: " + key);
+					}
+				}
+				return null;
+			}
+		/*}
+		finally {
+			cache.unlock(key);
+		}*/
+	}
+
+	/**
+	 * Stop any other transactions reading or writing this item to/from
+	 * the cache. Send them straight to the database instead. (The lock
+	 * does time out eventually.) This implementation tracks concurrent
+	 * locks of transactions which simultaneously attempt to write to an
+	 * item.
+	 */
+	public synchronized SoftLock lock(Object key, Object version) throws CacheException {
+		if ( log.isTraceEnabled() ) log.trace("Invalidating: " + key);
+
+		try {
+			cache.lock(key);
+
+			Lockable lockable = (Lockable) cache.get(key);
+			long timeout = cache.nextTimestamp() + cache.getTimeout();
+			final Lock lock = (lockable==null) ?
+				new Lock( timeout, nextLockId(), version ) :
+				lockable.lock( timeout, nextLockId() );
+			cache.update(key, lock);
+			return lock;
+		}
+		finally {
+			cache.unlock(key);
+		}
+
+	}
+
+	/**
+	 * Do not add an item to the cache unless the current transaction
+	 * timestamp is later than the timestamp at which the item was
+	 * invalidated. (Otherwise, a stale item might be re-added if the
+	 * database is operating in repeatable read isolation mode.)
+	 * For versioned data, don't add the item unless it is the later
+	 * version.
+	 */
+	public synchronized boolean put(
+			Object key, 
+			Object value, 
+			long txTimestamp, 
+			Object version, 
+			Comparator versionComparator,
+			boolean minimalPut) 
+	throws CacheException {
+		if ( log.isTraceEnabled() ) log.trace("Caching: " + key);
+
+		try {
+			cache.lock(key);
+
+			Lockable lockable = (Lockable) cache.get(key);
+
+			boolean puttable = lockable==null || 
+				lockable.isPuttable(txTimestamp, version, versionComparator);
+
+			if (puttable) {
+				cache.put( key, new Item( value, version, cache.nextTimestamp() ) );
+				if ( log.isTraceEnabled() ) log.trace("Cached: " + key);
+				return true;
+			}
+			else {
+				if ( log.isTraceEnabled() ) {
+					if ( lockable.isLock() ) {
+						log.trace("Item was locked: " + key);
+					}
+					else {
+						log.trace("Item was already cached: " + key);
+					}
+				}
+				return false;
+			}
+		}
+		finally {
+			cache.unlock(key);
+		}
+	}
+
+	/**
+	 * decrement a lock and put it back in the cache
+	 */
+	private void decrementLock(Object key, Lock lock) throws CacheException {
+		//decrement the lock
+		lock.unlock( cache.nextTimestamp() );
+		cache.update(key, lock);
+	}
+
+	/**
+	 * Release the soft lock on the item. Other transactions may now
+	 * re-cache the item (assuming that no other transaction holds a
+	 * simultaneous lock).
+	 */
+	public synchronized void release(Object key, SoftLock clientLock) throws CacheException {
+		if ( log.isTraceEnabled() ) log.trace("Releasing: " + key);
+
+		try {
+			cache.lock(key);
+
+			Lockable lockable = (Lockable) cache.get(key);
+			if ( isUnlockable(clientLock, lockable) ) {
+				decrementLock(key, (Lock) lockable);
+			}
+			else {
+				handleLockExpiry(key);
+			}
+		}
+		finally {
+			cache.unlock(key);
+		}
+	}
+
+	void handleLockExpiry(Object key) throws CacheException {
+		log.warn("An item was expired by the cache while it was locked (increase your cache timeout): " + key);
+		long ts = cache.nextTimestamp() + cache.getTimeout();
+		// create new lock that times out immediately
+		Lock lock = new Lock( ts, nextLockId(), null );
+		lock.unlock(ts);
+		cache.update(key, lock);
+	}
+
+	public void clear() throws CacheException {
+		cache.clear();
+	}
+
+	public void remove(Object key) throws CacheException {
+		cache.remove(key);
+	}
+
+	public void destroy() {
+		try {
+			cache.destroy();
+		}
+		catch (Exception e) {
+			log.warn("could not destroy cache", e);
+		}
+	}
+
+	/**
+	 * Re-cache the updated state, if and only if there there are
+	 * no other concurrent soft locks. Release our lock.
+	 */
+	public synchronized boolean afterUpdate(Object key, Object value, Object version, SoftLock clientLock) 
+	throws CacheException {
+		
+		if ( log.isTraceEnabled() ) log.trace("Updating: " + key);
+
+		try {
+			cache.lock(key);
+
+			Lockable lockable = (Lockable) cache.get(key);
+			if ( isUnlockable(clientLock, lockable) ) {
+				Lock lock = (Lock) lockable;
+				if ( lock.wasLockedConcurrently() ) {
+					// just decrement the lock, don't recache
+					// (we don't know which transaction won)
+					decrementLock(key, lock);
+					return false;
+				}
+				else {
+					//recache the updated state
+					cache.update( key, new Item( value, version, cache.nextTimestamp() ) );
+					if ( log.isTraceEnabled() ) log.trace("Updated: " + key);
+					return true;
+				}
+			}
+			else {
+				handleLockExpiry(key);
+				return false;
+			}
+
+		}
+		finally {
+			cache.unlock(key);
+		}
+	}
+
+	/**
+	 * Add the new item to the cache, checking that no other transaction has
+	 * accessed the item.
+	 */
+	public synchronized boolean afterInsert(Object key, Object value, Object version) 
+	throws CacheException {
+	
+		if ( log.isTraceEnabled() ) log.trace("Inserting: " + key);
+		try {
+			cache.lock(key);
+
+			Lockable lockable = (Lockable) cache.get(key);
+			if (lockable==null) {
+				cache.update( key, new Item( value, version, cache.nextTimestamp() ) );
+				if ( log.isTraceEnabled() ) log.trace("Inserted: " + key);
+				return true;
+			}
+			else {
+				return false;
+			}
+		}
+		finally {
+			cache.unlock(key);
+		}
+	}
+
+	/**
+	 * Do nothing.
+	 */
+	public void evict(Object key) throws CacheException {
+		// noop
+	}
+
+	/**
+	 * Do nothing.
+	 */
+	public boolean insert(Object key, Object value, Object currentVersion) {
+		return false;
+	}
+
+	/**
+	 * Do nothing.
+	 */
+	public boolean update(Object key, Object value, Object currentVersion, Object previousVersion) {
+		return false;
+	}
+
+	/**
+	 * Is the client's lock commensurate with the item in the cache?
+	 * If it is not, we know that the cache expired the original
+	 * lock.
+	 */
+	private boolean isUnlockable(SoftLock clientLock, Lockable myLock)
+	throws CacheException {
+		//null clientLock is remotely possible but will never happen in practice
+		return myLock!=null &&
+			myLock.isLock() &&
+			clientLock!=null &&
+			( (Lock) clientLock ).getId()==( (Lock) myLock ).getId();
+	}
+
+	public static interface Lockable {
+		public Lock lock(long timeout, int id);
+		public boolean isLock();
+		public boolean isGettable(long txTimestamp);
+		public boolean isPuttable(long txTimestamp, Object newVersion, Comparator comparator);
+	}
+
+	/**
+	 * An item of cached data, timestamped with the time it was cached,.
+	 * @see ReadWriteCache
+	 */
+	public static final class Item implements Serializable, Lockable {
+
+		private final long freshTimestamp;
+		private final Object value;
+		private final Object version;
+
+		public Item(Object value, Object version, long currentTimestamp) {
+			this.value = value;
+			this.version = version;
+			freshTimestamp = currentTimestamp;
+		}
+		/**
+		 * The timestamp on the cached data
+		 */
+		public long getFreshTimestamp() {
+			return freshTimestamp;
+		}
+		/**
+		 * The actual cached data
+		 */
+		public Object getValue() {
+			return value;
+		}
+
+		/**
+		 * Lock the item
+		 */
+		public Lock lock(long timeout, int id) {
+			return new Lock(timeout, id, version);
+		}
+		/**
+		 * Not a lock!
+		 */
+		public boolean isLock() {
+			return false;
+		}
+		/**
+		 * Is this item visible to the timestamped
+		 * transaction?
+		 */
+		public boolean isGettable(long txTimestamp) {
+			return freshTimestamp < txTimestamp;
+		}
+
+		/**
+		 * Don't overwite already cached items
+		 */
+		public boolean isPuttable(long txTimestamp, Object newVersion, Comparator comparator) {
+			// we really could refresh the item if it
+			// is not a lock, but it might be slower
+			//return freshTimestamp < txTimestamp
+			return version!=null && comparator.compare(version, newVersion) < 0;
+		}
+
+		public String toString() {
+			return "Item{version=" + version +
+				",freshTimestamp=" + freshTimestamp;
+		}
+	}
+
+	/**
+	 * A soft lock which supports concurrent locking,
+	 * timestamped with the time it was released
+	 * @author Gavin King
+	 */
+	public static final class Lock implements Serializable, Lockable, SoftLock {
+		private long unlockTimestamp = -1;
+		private int multiplicity = 1;
+		private boolean concurrentLock = false;
+		private long timeout;
+		private final int id;
+		private final Object version;
+
+		public Lock(long timeout, int id, Object version) {
+			this.timeout = timeout;
+			this.id = id;
+			this.version = version;
+		}
+
+		public long getUnlockTimestamp() {
+			return unlockTimestamp;
+		}
+		/**
+		 * Increment the lock, setting the
+		 * new lock timeout
+		 */
+		public Lock lock(long timeout, int id) {
+			concurrentLock = true;
+			multiplicity++;
+			this.timeout = timeout;
+			return this;
+		}
+		/**
+		 * Decrement the lock, setting the unlock
+		 * timestamp if now unlocked
+		 * @param currentTimestamp
+		 */
+		public void unlock(long currentTimestamp) {
+			if ( --multiplicity == 0 ) {
+				unlockTimestamp = currentTimestamp;
+			}
+		}
+
+		/**
+		 * Can the timestamped transaction re-cache this
+		 * locked item now?
+		 */
+		public boolean isPuttable(long txTimestamp, Object newVersion, Comparator comparator) {
+			if (timeout < txTimestamp) return true;
+			if (multiplicity>0) return false;
+			return version==null ? 
+				unlockTimestamp < txTimestamp :
+				comparator.compare(version, newVersion) < 0; //by requiring <, we rely on lock timeout in the case of an unsuccessful update!
+		}
+
+		/**
+		 * Was this lock held concurrently by multiple
+		 * transactions?
+		 */
+		public boolean wasLockedConcurrently() {
+			return concurrentLock;
+		}
+		/**
+		 * Yes, this is a lock
+		 */
+		public boolean isLock() {
+			return true;
+		}
+		/**
+		 * locks are not returned to the client!
+		 */
+		public boolean isGettable(long txTimestamp) {
+			return false;
+		}
+
+		public int getId() { return id; }
+
+		public String toString() {
+			return "Lock{id=" + id +
+				",version=" + version +
+				",multiplicity=" + multiplicity +
+				",unlockTimestamp=" + unlockTimestamp;
+		}
+
+	}
+
+	public String toString() {
+		return cache + "(read-write)";
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/Region.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/Region.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/Region.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+package org.hibernate.cache;
+
+import java.util.Map;
+
+/**
+ * Defines a contract for accessing a particular named region within the 
+ * underlying cache implementation.
+ *
+ * @author Steve Ebersole
+ */
+public interface Region {
+	/**
+	 * Retrieve the name of this region.
+	 *
+	 * @return The region name
+	 */
+	public String getName();
+
+	/**
+	 * The "end state" contract of the region's lifecycle.  Called
+	 * during {@link org.hibernate.SessionFactory#close()} to give
+	 * the region a chance to cleanup.
+	 *
+	 * @throws CacheException Indicates problem shutting down
+	 */
+	public void destroy() throws CacheException;
+
+	/**
+	 * The number of bytes is this cache region currently consuming in memory.
+	 *
+	 * @return The number of bytes consumed by this region; -1 if unknown or
+	 * unsupported.
+	 */
+	public long getSizeInMemory();
+
+	/**
+	 * The count of entries currently contained in the regions in-memory store.
+	 *
+	 * @return The count of entries in memory; -1 if unknown or unsupported.
+	 */
+	public long getElementCountInMemory();
+
+	/**
+	 * The count of entries currently contained in the regions disk store.
+	 *
+	 * @return The count of entries on disk; -1 if unknown or unsupported.
+	 */
+	public long getElementCountOnDisk();
+
+	/**
+	 * Get the contents of this region as a map.
+	 * <p/>
+	 * Implementors which do not support this notion
+	 * should simply return an empty map.
+	 *
+	 * @return The content map.
+	 */
+	public Map toMap();
+
+	public long nextTimestamp();
+	public int getTimeout();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/RegionFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/RegionFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/RegionFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,106 @@
+package org.hibernate.cache;
+
+import java.util.Properties;
+
+import org.hibernate.cfg.Settings;
+
+/**
+ * Contract for building second level cache regions.
+ * <p/>
+ * Implementors should define a constructor in one of two forms:<ul>
+ * <li>MyRegionFactoryImpl({@link java.util.Properties})</li>
+ * <li>MyRegionFactoryImpl()</li>
+ * </ul>
+ * Use the first when we need to read config properties prior to
+ * {@link #start} being called.  For an example, have a look at
+ * {@link org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge}
+ * where we need the properties in order to determine which legacy 
+ * {@link CacheProvider} to use so that we can answer the
+ * {@link #isMinimalPutsEnabledByDefault()} question for the
+ * {@link org.hibernate.cfg.SettingsFactory}.
+ *
+ * @author Steve Ebersole
+ */
+public interface RegionFactory {
+
+	/**
+	 * Lifecycle callback to perform any necessary initialization of the
+	 * underlying cache implementation(s).  Called exactly once during the
+	 * construction of a {@link org.hibernate.impl.SessionFactoryImpl}.
+	 *
+	 * @param settings The settings in effect.
+	 * @param properties The defined cfg properties
+	 * @throws CacheException Indicates problems starting the L2 cache impl;
+	 * considered as a sign to stop {@link org.hibernate.SessionFactory}
+	 * building.
+	 */
+	public void start(Settings settings, Properties properties) throws CacheException;
+
+	/**
+	 * Lifecycle callback to perform any necessary cleanup of the underlying
+	 * cache implementation(s).  Called exactly once during
+	 * {@link org.hibernate.SessionFactory#close}.
+	 */
+	public void stop();
+
+	/**
+	 * By default should we perform "minimal puts" when using this second
+	 * level cache implementation?
+	 *
+	 * @return True if "minimal puts" should be performed by default; false
+	 * otherwise.
+	 */
+	public boolean isMinimalPutsEnabledByDefault();
+
+	/**
+	 * Generate a timestamp.
+	 * <p/>
+	 * This is generally used for cache content locking/unlocking purposes
+	 * depending upon the access-strategy being used.
+	 *
+	 * @return The generated timestamp.
+	 */
+	public long nextTimestamp();
+
+	/**
+	 * Build a cache region specialized for storing entity data.
+	 *
+	 * @param regionName The name of the region.
+	 * @param properties Configuration properties.
+	 * @param metadata Information regarding the type of data to be cached
+	 * @return The built region
+	 * @throws CacheException Indicates problems building the region.
+	 */
+	public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata) throws CacheException;
+
+	/**
+	 * Build a cache region specialized for storing collection data.
+	 *
+	 * @param regionName The name of the region.
+	 * @param properties Configuration properties.
+	 * @param metadata Information regarding the type of data to be cached
+	 * @return The built region
+	 * @throws CacheException Indicates problems building the region.
+	 */
+	public CollectionRegion buildCollectionRegion(String regionName, Properties properties, CacheDataDescription metadata) throws CacheException;
+
+	/**
+	 * Build a cache region specialized for storing query results
+	 *
+	 * @param regionName The name of the region.
+	 * @param properties Configuration properties.
+	 * @return The built region
+	 * @throws CacheException Indicates problems building the region.
+	 */
+	public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException;
+
+	/**
+	 * Build a cache region specialized for storing update-timestamps data.
+	 *
+	 * @param regionName The name of the region.
+	 * @param properties Configuration properties.
+	 * @return The built region
+	 * @throws CacheException Indicates problems building the region.
+	 */
+	public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/StandardQueryCache.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/StandardQueryCache.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/StandardQueryCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,184 @@
+//$Id: StandardQueryCache.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.UnresolvableObjectException;
+import org.hibernate.cfg.Settings;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * The standard implementation of the Hibernate QueryCache interface.  This
+ * implementation is very good at recognizing stale query results and
+ * and re-running queries when it detects this condition, recaching the new
+ * results.
+ *
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public class StandardQueryCache implements QueryCache {
+
+	private static final Log log = LogFactory.getLog( StandardQueryCache.class );
+
+	private QueryResultsRegion cacheRegion;
+	private UpdateTimestampsCache updateTimestampsCache;
+
+	public void clear() throws CacheException {
+		cacheRegion.evictAll();
+	}
+
+	public StandardQueryCache(
+			final Settings settings,
+			final Properties props,
+			final UpdateTimestampsCache updateTimestampsCache,
+			String regionName) throws HibernateException {
+		if ( regionName == null ) {
+			regionName = StandardQueryCache.class.getName();
+		}
+		String prefix = settings.getCacheRegionPrefix();
+		if ( prefix != null ) {
+			regionName = prefix + '.' + regionName;
+		}
+		log.info( "starting query cache at region: " + regionName );
+
+		this.cacheRegion = settings.getRegionFactory().buildQueryResultsRegion( regionName, props );
+		this.updateTimestampsCache = updateTimestampsCache;
+	}
+
+	public boolean put(
+			QueryKey key,
+			Type[] returnTypes,
+			List result,
+			boolean isNaturalKeyLookup,
+			SessionImplementor session) throws HibernateException {
+		if ( isNaturalKeyLookup && result.size() == 0 ) {
+			return false;
+		}
+		else {
+			Long ts = new Long( session.getTimestamp() );
+
+			if ( log.isDebugEnabled() ) {
+				log.debug( "caching query results in region: " + cacheRegion.getName() + "; timestamp=" + ts );
+			}
+
+			List cacheable = new ArrayList( result.size() + 1 );
+			cacheable.add( ts );
+			for ( int i = 0; i < result.size(); i++ ) {
+				if ( returnTypes.length == 1 ) {
+					cacheable.add( returnTypes[0].disassemble( result.get( i ), session, null ) );
+				}
+				else {
+					cacheable.add(
+							TypeFactory.disassemble(
+									( Object[] ) result.get( i ), returnTypes, null, session, null
+							)
+					);
+				}
+			}
+
+			cacheRegion.put( key, cacheable );
+
+			return true;
+
+		}
+
+	}
+
+	public List get(
+			QueryKey key,
+			Type[] returnTypes,
+			boolean isNaturalKeyLookup,
+			Set spaces,
+			SessionImplementor session) throws HibernateException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "checking cached query results in region: " + cacheRegion.getName() );
+		}
+
+		List cacheable = ( List ) cacheRegion.get( key );
+		if ( cacheable == null ) {
+			log.debug( "query results were not found in cache" );
+			return null;
+		}
+
+		Long timestamp = ( Long ) cacheable.get( 0 );
+		if ( !isNaturalKeyLookup && !isUpToDate( spaces, timestamp ) ) {
+			log.debug( "cached query results were not up to date" );
+			return null;
+		}
+
+		log.debug( "returning cached query results" );
+		for ( int i = 1; i < cacheable.size(); i++ ) {
+			if ( returnTypes.length == 1 ) {
+				returnTypes[0].beforeAssemble( ( Serializable ) cacheable.get( i ), session );
+			}
+			else {
+				TypeFactory.beforeAssemble( ( Serializable[] ) cacheable.get( i ), returnTypes, session );
+			}
+		}
+		List result = new ArrayList( cacheable.size() - 1 );
+		for ( int i = 1; i < cacheable.size(); i++ ) {
+			try {
+				if ( returnTypes.length == 1 ) {
+					result.add( returnTypes[0].assemble( ( Serializable ) cacheable.get( i ), session, null ) );
+				}
+				else {
+					result.add(
+							TypeFactory.assemble(
+									( Serializable[] ) cacheable.get( i ), returnTypes, session, null
+							)
+					);
+				}
+			}
+			catch ( UnresolvableObjectException uoe ) {
+				if ( isNaturalKeyLookup ) {
+					//TODO: not really completely correct, since
+					//      the uoe could occur while resolving
+					//      associations, leaving the PC in an
+					//      inconsistent state
+					log.debug( "could not reassemble cached result set" );
+					cacheRegion.evict( key );
+					return null;
+				}
+				else {
+					throw uoe;
+				}
+			}
+		}
+		return result;
+	}
+
+	protected boolean isUpToDate(Set spaces, Long timestamp) {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Checking query spaces for up-to-dateness: " + spaces );
+		}
+		return updateTimestampsCache.isUpToDate( spaces, timestamp );
+	}
+
+	public void destroy() {
+		try {
+			cacheRegion.destroy();
+		}
+		catch ( Exception e ) {
+			log.warn( "could not destroy query cache: " + cacheRegion.getName(), e );
+		}
+	}
+
+	public QueryResultsRegion getRegion() {
+		return cacheRegion;
+	}
+
+	public String toString() {
+		return "StandardQueryCache(" + cacheRegion.getName() + ')';
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/StandardQueryCacheFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/StandardQueryCacheFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/StandardQueryCacheFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+// $Id: StandardQueryCacheFactory.java 4690 2004-10-26 09:35:46Z oneovthafew $
+package org.hibernate.cache;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Settings;
+
+import java.util.Properties;
+
+/**
+ * Standard Hibernate implementation of the QueryCacheFactory interface.  Returns
+ * instances of {@link StandardQueryCache}.
+ */
+public class StandardQueryCacheFactory implements QueryCacheFactory {
+
+	public QueryCache getQueryCache(
+	        final String regionName,
+	        final UpdateTimestampsCache updateTimestampsCache,
+	        final Settings settings,
+	        final Properties props) 
+	throws HibernateException {
+		return new StandardQueryCache(settings, props, updateTimestampsCache, regionName);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/Timestamper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/Timestamper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/Timestamper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: Timestamper.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.cache;
+
+/**
+ * Generates increasing identifiers (in a single VM only).
+ * Not valid across multiple VMs. Identifiers are not necessarily
+ * strictly increasing, but usually are.
+ */
+public final class Timestamper {
+	private static short counter = 0;
+	private static long time;
+	private static final int BIN_DIGITS = 12;
+	public static final short ONE_MS = 1<<BIN_DIGITS;
+	
+	public static long next() {
+		synchronized(Timestamper.class) {
+			long newTime = System.currentTimeMillis() << BIN_DIGITS;
+			if (time<newTime) {
+				time = newTime;
+				counter = 0;
+			}
+			else if (counter < ONE_MS - 1 ) {
+				counter++;
+			}
+			
+			return time + counter;
+		}
+	}
+
+	private Timestamper() {}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/TimestampsRegion.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/TimestampsRegion.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/TimestampsRegion.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+package org.hibernate.cache;
+
+/**
+ * Defines the contract for a cache region which will specifically be used to
+ * store entity "update timestamps".
+ *
+ * @author Steve Ebersole
+ */
+public interface TimestampsRegion extends GeneralDataRegion {
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/TransactionalCache.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/TransactionalCache.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/TransactionalCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,171 @@
+//$Id: TransactionalCache.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import java.util.Comparator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.cache.access.SoftLock;
+
+/**
+ * Support for fully transactional cache implementations like
+ * JBoss TreeCache. Note that this might be a less scalable
+ * concurrency strategy than <tt>ReadWriteCache</tt>. This is
+ * a "synchronous" concurrency strategy.
+ *
+ * @author Gavin King
+ */
+public class TransactionalCache implements CacheConcurrencyStrategy {
+
+	private static final Log log = LogFactory.getLog( TransactionalCache.class );
+
+	private Cache cache;
+
+	public String getRegionName() {
+		return cache.getRegionName();
+	}
+
+	public Object get(Object key, long txTimestamp) throws CacheException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "cache lookup: " + key );
+		}
+		Object result = cache.read( key );
+		if ( log.isDebugEnabled() ) {
+			log.debug( result == null ? "cache miss" : "cache hit" );
+		}
+		return result;
+	}
+
+	public boolean put(
+			Object key,
+	        Object value,
+	        long txTimestamp,
+	        Object version,
+	        Comparator versionComparator,
+	        boolean minimalPut) throws CacheException {
+		if ( minimalPut && cache.read( key ) != null ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "item already cached: " + key );
+			}
+			return false;
+		}
+		if ( log.isDebugEnabled() ) {
+			log.debug( "caching: " + key );
+		}
+		if ( cache instanceof OptimisticCache ) {
+			( ( OptimisticCache ) cache ).writeLoad( key, value, version );
+		}
+		else {
+			cache.put( key, value );
+		}
+		return true;
+	}
+
+	/**
+	 * Do nothing, returning null.
+	 */
+	public SoftLock lock(Object key, Object version) throws CacheException {
+		//noop
+		return null;
+	}
+
+	/**
+	 * Do nothing.
+	 */
+	public void release(Object key, SoftLock clientLock) throws CacheException {
+		//noop
+	}
+
+	public boolean update(
+			Object key,
+	        Object value,
+	        Object currentVersion,
+	        Object previousVersion) throws CacheException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "updating: " + key );
+		}
+		if ( cache instanceof OptimisticCache ) {
+			( ( OptimisticCache ) cache ).writeUpdate( key, value, currentVersion, previousVersion );
+		}
+		else {
+			cache.update( key, value );
+		}
+		return true;
+	}
+
+	public boolean insert(
+			Object key,
+	        Object value,
+	        Object currentVersion) throws CacheException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "inserting: " + key );
+		}
+		if ( cache instanceof OptimisticCache ) {
+			( ( OptimisticCache ) cache ).writeInsert( key, value, currentVersion );
+		}
+		else {
+			cache.update( key, value );
+		}
+		return true;
+	}
+
+	public void evict(Object key) throws CacheException {
+		cache.remove( key );
+	}
+
+	public void remove(Object key) throws CacheException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "removing: " + key );
+		}
+		cache.remove( key );
+	}
+
+	public void clear() throws CacheException {
+		log.debug( "clearing" );
+		cache.clear();
+	}
+
+	public void destroy() {
+		try {
+			cache.destroy();
+		}
+		catch ( Exception e ) {
+			log.warn( "could not destroy cache", e );
+		}
+	}
+
+	public void setCache(Cache cache) {
+		this.cache = cache;
+	}
+
+	public Cache getCache() {
+		return cache;
+	}
+
+	/**
+	 * Do nothing.
+	 */
+	public boolean afterInsert(
+			Object key,
+	        Object value,
+	        Object version) throws CacheException {
+		return false;
+	}
+
+	/**
+	 * Do nothing.
+	 */
+	public boolean afterUpdate(
+			Object key,
+	        Object value,
+	        Object version,
+	        SoftLock clientLock) throws CacheException {
+		return false;
+	}
+
+	public String toString() {
+		return cache + "(transactional)";
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/TransactionalDataRegion.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/TransactionalDataRegion.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/TransactionalDataRegion.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+package org.hibernate.cache;
+
+/**
+ * Defines contract for regions which hold transactionally-managed data.
+ * <p/>
+ * The data is not transactionally managed within the region; merely it is
+ * transactionally-managed in relation to its association with a particular
+ * {@link org.hibernate.Session}.
+ *
+ * @author Steve Ebersole
+ */
+public interface TransactionalDataRegion extends Region {
+	/**
+	 * Is the underlying cache implementation aware of (and "participating in")
+	 * ongoing JTA transactions?
+	 * <p/>
+	 * Regions which report that they are transaction-aware are considered
+	 * "synchronous", in that we assume we can immediately (i.e. synchronously)
+	 * write the changes to the cache and that the cache will properly manage
+	 * application of the written changes within the bounds of ongoing JTA
+	 * transactions.  Conversely, regions reporting false are considered
+	 * "asynchronous", where it is assumed that changes must be manually
+	 * delayed by Hibernate until we are certain that the current transaction
+	 * is successful (i.e. maintaining READ_COMMITTED isolation).
+	 *
+	 * @return True if transaction aware; false otherwise.
+	 */
+	public boolean isTransactionAware();
+
+	public CacheDataDescription getCacheDataDescription();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/UpdateTimestampsCache.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/UpdateTimestampsCache.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/UpdateTimestampsCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,110 @@
+//$Id: UpdateTimestampsCache.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.cache;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Settings;
+
+/**
+ * Tracks the timestamps of the most recent updates to particular tables. It is
+ * important that the cache timeout of the underlying cache implementation be set
+ * to a higher value than the timeouts of any of the query caches. In fact, we
+ * recommend that the the underlying cache not be configured for expiry at all.
+ * Note, in particular, that an LRU cache expiry policy is never appropriate.
+ *
+ * @author Gavin King
+ * @author Mikheil Kapanadze
+ */
+public class UpdateTimestampsCache {
+	public static final String REGION_NAME = UpdateTimestampsCache.class.getName();
+	private static final Log log = LogFactory.getLog( UpdateTimestampsCache.class );
+
+	private final TimestampsRegion region;
+
+	public UpdateTimestampsCache(Settings settings, Properties props) throws HibernateException {
+		String prefix = settings.getCacheRegionPrefix();
+		String regionName = prefix == null ? REGION_NAME : prefix + '.' + REGION_NAME;
+		log.info( "starting update timestamps cache at region: " + regionName );
+		this.region = settings.getRegionFactory().buildTimestampsRegion( regionName, props );
+	}
+
+	public synchronized void preinvalidate(Serializable[] spaces) throws CacheException {
+		//TODO: to handle concurrent writes correctly, this should return a Lock to the client
+		Long ts = new Long( region.nextTimestamp() + region.getTimeout() );
+		for ( int i=0; i<spaces.length; i++ ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "Pre-invalidating space [" + spaces[i] + "]" );
+			}
+			//put() has nowait semantics, is this really appropriate?
+			//note that it needs to be async replication, never local or sync
+			region.put( spaces[i], ts );
+		}
+		//TODO: return new Lock(ts);
+	}
+
+	 public synchronized void invalidate(Serializable[] spaces) throws CacheException {
+	 	//TODO: to handle concurrent writes correctly, the client should pass in a Lock
+		Long ts = new Long( region.nextTimestamp() );
+		//TODO: if lock.getTimestamp().equals(ts)
+		for ( int i=0; i<spaces.length; i++ ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "Invalidating space [" + spaces[i] + "], timestamp: " + ts);
+			}
+			//put() has nowait semantics, is this really appropriate?
+			//note that it needs to be async replication, never local or sync
+			region.put( spaces[i], ts );
+		}
+	}
+
+	public synchronized boolean isUpToDate(Set spaces, Long timestamp) throws HibernateException {
+		Iterator iter = spaces.iterator();
+		while ( iter.hasNext() ) {
+			Serializable space = (Serializable) iter.next();
+			Long lastUpdate = (Long) region.get(space);
+			if ( lastUpdate==null ) {
+				//the last update timestamp was lost from the cache
+				//(or there were no updates since startup!)
+				//updateTimestamps.put( space, new Long( updateTimestamps.nextTimestamp() ) );
+				//result = false; // safer
+			}
+			else {
+				if ( log.isDebugEnabled() ) {
+					log.debug("[" + space + "] last update timestamp: " + lastUpdate + ", result set timestamp: " + timestamp );
+				}
+				if ( lastUpdate.longValue() >= timestamp.longValue() ) {
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+
+	public void clear() throws CacheException {
+		region.evictAll();
+	}
+
+	public void destroy() {
+		try {
+			region.destroy();
+		}
+		catch (Exception e) {
+			log.warn("could not destroy UpdateTimestamps cache", e);
+		}
+	}
+
+	public TimestampsRegion getRegion() {
+		return region;
+	}
+	
+	public String toString() {
+		return "UpdateTimestampeCache";
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/AccessType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/AccessType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/AccessType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+package org.hibernate.cache.access;
+
+import java.io.Serializable;
+
+/**
+ * The types of access strategies available.
+ *
+ * @author Steve Ebersole
+ */
+public class AccessType implements Serializable {
+	public static final AccessType READ_ONLY = new AccessType( "read-only" );
+	public static final AccessType READ_WRITE = new AccessType( "read-write" );
+	public static final AccessType NONSTRICT_READ_WRITE = new AccessType( "nonstrict-read-write" );
+	public static final AccessType TRANSACTIONAL = new AccessType( "transactional" );
+
+	private final String name;
+
+	private AccessType(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public String toString() {
+		return "AccessType[" + name + "]";
+	}
+
+	private static AccessType resolve(String name) {
+		if ( READ_ONLY.name.equals( name ) ) {
+			return READ_ONLY;
+		}
+		else if ( READ_WRITE.name.equals( name ) ) {
+			return READ_WRITE;
+		}
+		else if ( NONSTRICT_READ_WRITE.name.equals( name ) ) {
+			return NONSTRICT_READ_WRITE;
+		}
+		else if ( TRANSACTIONAL.name.equals( name ) ) {
+			return TRANSACTIONAL;
+		}
+		else {
+			return null;
+		}
+	}
+
+	public static AccessType parse(String name) {
+		return resolve( name );
+	}
+
+	private Object readResolve() {
+		return resolve( name );
+	}
+
+	public static String getValidUsageString() {
+		return "cache usage attribute should be " + READ_ONLY.name +
+				", " + READ_WRITE.name +
+				", " + NONSTRICT_READ_WRITE.name +
+				", or " + TRANSACTIONAL.name;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/CollectionRegionAccessStrategy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/CollectionRegionAccessStrategy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/CollectionRegionAccessStrategy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,156 @@
+package org.hibernate.cache.access;
+
+import java.util.Comparator;
+
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.CollectionRegion;
+
+/**
+ * Contract for managing transactional and concurrent access to cached collection
+ * data.  For cached collection data, all modification actions actually just
+ * invalidate the entry(s).  The call sequence here is:
+ * {@link #lockItem} -> {@link #remove} -> {@link #unlockItem}
+ * <p/>
+ * There is another usage pattern that is used to invalidate entries
+ * after performing "bulk" HQL/SQL operations:
+ * {@link #lockRegion} -> {@link #removeAll} -> {@link #unlockRegion}
+ *
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public interface CollectionRegionAccessStrategy {
+
+	/**
+	 * Get the wrapped collection cache region
+	 *
+	 * @return The underlying region
+	 */
+	public CollectionRegion getRegion();
+
+	/**
+	 * Attempt to retrieve an object from the cache. Mainly used in attempting
+	 * to resolve entities/collections from the second level cache.
+	 *
+	 * @param key The key of the item to be retrieved.
+	 * @param txTimestamp a timestamp prior to the transaction start time
+	 * @return the cached object or <tt>null</tt>
+	 * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public Object get(Object key, long txTimestamp) throws CacheException;
+
+	/**
+	 * Attempt to cache an object, after loading from the database.
+	 *
+	 * @param key The item key
+	 * @param value The item
+	 * @param txTimestamp a timestamp prior to the transaction start time
+	 * @param version the item version number
+	 * @return <tt>true</tt> if the object was successfully cached
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public boolean putFromLoad(
+			Object key,
+			Object value,
+			long txTimestamp,
+			Object version) throws CacheException;
+
+	/**
+	 * Attempt to cache an object, after loading from the database, explicitly
+	 * specifying the minimalPut behavior.
+	 *
+	 * @param key The item key
+	 * @param value The item
+	 * @param txTimestamp a timestamp prior to the transaction start time
+	 * @param version the item version number
+	 * @param minimalPutOverride Explicit minimalPut flag
+	 * @return <tt>true</tt> if the object was successfully cached
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public boolean putFromLoad(
+			Object key,
+			Object value,
+			long txTimestamp,
+			Object version,
+			boolean minimalPutOverride) throws CacheException;
+
+	/**
+	 * We are going to attempt to update/delete the keyed object. This
+	 * method is used by "asynchronous" concurrency strategies.
+	 * <p/>
+	 * The returned object must be passed back to release(), to release the
+	 * lock. Concurrency strategies which do not support client-visible
+	 * locks may silently return null.
+	 *
+	 * @param key The key of the item to lock
+	 * @param version The item's current version value
+	 * @return A representation of our lock on the item; or null.
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public SoftLock lockItem(Object key, Object version) throws CacheException;
+
+	/**
+	 * Lock the entire region
+	 *
+	 * @return A representation of our lock on the item; or null.
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public SoftLock lockRegion() throws CacheException;
+
+	/**
+	 * Called when we have finished the attempted update/delete (which may or
+	 * may not have been successful), after transaction completion.  This method
+	 * is used by "asynchronous" concurrency strategies.
+	 *
+	 * @param key The item key
+	 * @param lock The lock previously obtained from {@link #lockItem}
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public void unlockItem(Object key, SoftLock lock) throws CacheException;
+
+	/**
+	 * Called after we have finished the attempted invalidation of the entire
+	 * region
+	 *
+	 * @param lock The lock previously obtained from {@link #lockRegion}
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public void unlockRegion(SoftLock lock) throws CacheException;
+
+	/**
+	 * Called after an item has become stale (before the transaction completes).
+	 * This method is used by "synchronous" concurrency strategies.
+	 *
+	 * @param key The key of the item to remove
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public void remove(Object key) throws CacheException;
+
+	/**
+	 * Called to evict data from the entire region
+	 *
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public void removeAll() throws CacheException;
+
+	/**
+	 * Forcibly evict an item from the cache immediately without regard for transaction
+	 * isolation.
+	 *
+	 * @param key The key of the item to remove
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public void evict(Object key) throws CacheException;
+
+	/**
+	 * Forcibly evict all items from the cache immediately without regard for transaction
+	 * isolation.
+	 *
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public void evictAll() throws CacheException;
+
+	/**
+	 * Clean up all resources.
+	 */
+	public void destroy();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/EntityRegionAccessStrategy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/EntityRegionAccessStrategy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/EntityRegionAccessStrategy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,211 @@
+package org.hibernate.cache.access;
+
+import org.hibernate.cache.EntityRegion;
+import org.hibernate.cache.CacheException;
+
+/**
+ * Contract for managing transactional and concurrent access to cached entity
+ * data.  The expected call sequences related to various operations are:<ul>
+ * <li><b>INSERTS</b> : {@link #insert} -> {@link #afterInsert}</li>
+ * <li><b>UPDATES</b> : {@link #lockItem} -> {@link #update} -> {@link #afterUpdate}</li>
+ * <li><b>DELETES</b> : {@link #lockItem} -> {@link #remove} -> {@link #unlockItem}</li>
+ * </ul>
+ * <p/>
+ * There is another usage pattern that is used to invalidate entries
+ * after performing "bulk" HQL/SQL operations:
+ * {@link #lockRegion} -> {@link #removeAll} -> {@link #unlockRegion}
+ *
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public interface EntityRegionAccessStrategy {
+
+	/**
+	 * Get the wrapped entity cache region
+	 *
+	 * @return The underlying region
+	 */
+	public EntityRegion getRegion();
+
+	/**
+	 * Attempt to retrieve an object from the cache. Mainly used in attempting
+	 * to resolve entities/collections from the second level cache.
+	 *
+	 * @param key The key of the item to be retrieved.
+	 * @param txTimestamp a timestamp prior to the transaction start time
+	 * @return the cached object or <tt>null</tt>
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public Object get(Object key, long txTimestamp) throws CacheException;
+
+	/**
+	 * Attempt to cache an object, after loading from the database.
+	 *
+	 * @param key The item key
+	 * @param value The item
+	 * @param txTimestamp a timestamp prior to the transaction start time
+	 * @param version the item version number
+	 * @return <tt>true</tt> if the object was successfully cached
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public boolean putFromLoad(
+			Object key,
+			Object value,
+			long txTimestamp,
+			Object version) throws CacheException;
+
+	/**
+	 * Attempt to cache an object, after loading from the database, explicitly
+	 * specifying the minimalPut behavior.
+	 *
+	 * @param key The item key
+	 * @param value The item
+	 * @param txTimestamp a timestamp prior to the transaction start time
+	 * @param version the item version number
+	 * @param minimalPutOverride Explicit minimalPut flag
+	 * @return <tt>true</tt> if the object was successfully cached
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public boolean putFromLoad(
+			Object key,
+			Object value,
+			long txTimestamp,
+			Object version,
+			boolean minimalPutOverride) throws CacheException;
+
+	/**
+	 * We are going to attempt to update/delete the keyed object. This
+	 * method is used by "asynchronous" concurrency strategies.
+	 * <p/>
+	 * The returned object must be passed back to release(), to release the
+	 * lock. Concurrency strategies which do not support client-visible
+	 * locks may silently return null.
+	 *
+	 * @param key The key of the item to lock
+	 * @param version The item's current version value
+	 * @return A representation of our lock on the item; or null.
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public SoftLock lockItem(Object key, Object version) throws CacheException;
+
+	/**
+	 * Lock the entire region
+	 *
+	 * @return A representation of our lock on the item; or null.
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public SoftLock lockRegion() throws CacheException;
+
+	/**
+	 * Called when we have finished the attempted update/delete (which may or
+	 * may not have been successful), after transaction completion.  This method
+	 * is used by "asynchronous" concurrency strategies.
+	 *
+	 * @param key The item key
+	 * @param lock The lock previously obtained from {@link #lockItem}
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public void unlockItem(Object key, SoftLock lock) throws CacheException;
+
+	/**
+	 * Called after we have finished the attempted invalidation of the entire
+	 * region
+	 *
+	 * @param lock The lock previously obtained from {@link #lockRegion}
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public void unlockRegion(SoftLock lock) throws CacheException;
+
+	/**
+	 * Called after an item has been inserted (before the transaction completes),
+	 * instead of calling evict().
+	 * This method is used by "synchronous" concurrency strategies.
+	 *
+	 * @param key The item key
+	 * @param value The item
+	 * @param version The item's version value
+	 * @return Were the contents of the cache actual changed by this operation?
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public boolean insert(Object key, Object value, Object version) throws CacheException;
+
+	/**
+	 * Called after an item has been inserted (after the transaction completes),
+	 * instead of calling release().
+	 * This method is used by "asynchronous" concurrency strategies.
+	 *
+	 * @param key The item key
+	 * @param value The item
+	 * @param version The item's version value
+	 * @return Were the contents of the cache actual changed by this operation?
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public boolean afterInsert(Object key, Object value, Object version) throws CacheException;
+
+	/**
+	 * Called after an item has been updated (before the transaction completes),
+	 * instead of calling evict(). This method is used by "synchronous" concurrency
+	 * strategies.
+	 *
+	 * @param key The item key
+	 * @param value The item
+	 * @param currentVersion The item's current version value
+	 * @param previousVersion The item's previous version value
+	 * @return Were the contents of the cache actual changed by this operation?
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public boolean update(Object key, Object value, Object currentVersion, Object previousVersion) throws CacheException;
+
+	/**
+	 * Called after an item has been updated (after the transaction completes),
+	 * instead of calling release().  This method is used by "asynchronous"
+	 * concurrency strategies.
+	 *
+	 * @param key The item key
+	 * @param value The item
+	 * @param currentVersion The item's current version value
+	 * @param previousVersion The item's previous version value
+	 * @param lock The lock previously obtained from {@link #lockItem}
+	 * @return Were the contents of the cache actual changed by this operation?
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) throws CacheException;
+
+	/**
+	 * Called after an item has become stale (before the transaction completes).
+	 * This method is used by "synchronous" concurrency strategies.
+	 *
+	 * @param key The key of the item to remove
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public void remove(Object key) throws CacheException;
+
+	/**
+	 * Called to evict data from the entire region
+	 *
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public void removeAll() throws CacheException;
+
+	/**
+	 * Forcibly evict an item from the cache immediately without regard for transaction
+	 * isolation.
+	 *
+	 * @param key The key of the item to remove
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public void evict(Object key) throws CacheException;
+
+	/**
+	 * Forcibly evict all items from the cache immediately without regard for transaction
+	 * isolation.
+	 *
+	 * @throws CacheException Propogated from underlying {@link org.hibernate.cache.Region}
+	 */
+	public void evictAll() throws CacheException;
+
+	/**
+	 * Clean up all resources.
+	 */
+	public void destroy();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/SoftLock.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/SoftLock.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/SoftLock.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+package org.hibernate.cache.access;
+
+/**
+ * Moved up from inner definition on the now deprecated
+ * {@link org.hibernate.cache.CacheConcurrencyStrategy}.
+ *
+ * @author Steve Ebersole
+ */
+public interface SoftLock {
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/access/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+<html>
+<head></head>
+<body>
+<p>
+	Defines contracts for transactional and concurrent access to cached
+    {@link org.hibernate.cache.access.EntityRegionAccessStrategy entity} and
+    {@link org.hibernate.cache.access.CollectionRegionAccessStrategy collection} data.  Transactions pass in a
+    timestamp indicating transaction start time which is then used to protect against concurrent access (exactly how
+    that occurs is based on the actual access-strategy impl used). Two different implementation patterns are provided
+    for.
+    <ul>
+        <li>
+            A transaction-aware cache implementation might be wrapped by a <i>synchronous</i> access strategy,
+            where updates to the cache are written to the cache inside the transaction.
+        </li>
+        <li>
+            A non-transaction-aware cache would be wrapped by an <i>asynchronous</i> access strategy, where items
+            are merely "soft locked" during the transaction and then updated during the "after transaction completion"
+            phase; the soft lock is not an actual lock on the database row - only upon the cached representation of the
+            item.
+        </li>
+    </ul>
+    The <i>asynchronous</i> access strategies are: {@link org.hibernate.cache.access.AccessType.READ_ONLY read-only},
+    {@link org.hibernate.cache.access.AccessType.READ_WRITE read-write} and
+    {@link org.hibernate.cache.access.AccessType.NONSTRICT_READ_WRITE nonstrict-read-write}.  The only
+    <i>synchronous</i> access strategy is {@link org.hibernate.cache.access.AccessType.TRANSACTIONAL transactional}.
+</p>
+<p>
+    Note that, for an <i>asynchronous</i> cache, cache invalidation must be a two step process (lock->unlock or
+    lock->afterUpdate), since this is the only way to guarantee consistency with the database for a nontransactional
+    cache implementation. For a <i>synchronous</i> cache, cache invalidation is a single step process (evict or update).
+    Hence, these contracts ({@link org.hibernate.cache.access.EntityRegionAcessStrategy} and
+    {@link org.hibernate.cache.access.CollectionRegionAccessStrategy}) define a three step process to cater for both 
+    models (see the individual contracts for details).
+</p>
+<p>
+    Note that query result caching does not go through an access strategy; those caches are managed directly against
+    the underlying {@link org.hibernate.cache.QueryResultsRegion}.
+</p>
+</body>
+</html>

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/CacheEntry.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/CacheEntry.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/CacheEntry.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,143 @@
+//$Id: CacheEntry.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.cache.entry;
+
+import java.io.Serializable;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.PreLoadEvent;
+import org.hibernate.event.PreLoadEventListener;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * A cached instance of a persistent class
+ *
+ * @author Gavin King
+ */
+public final class CacheEntry implements Serializable {
+
+	private final Serializable[] disassembledState;
+	private final String subclass;
+	private final boolean lazyPropertiesAreUnfetched;
+	private final Object version;
+	
+	public String getSubclass() {
+		return subclass;
+	}
+	
+	public boolean areLazyPropertiesUnfetched() {
+		return lazyPropertiesAreUnfetched;
+	}
+	
+	public CacheEntry(
+			final Object[] state, 
+			final EntityPersister persister, 
+			final boolean unfetched, 
+			final Object version,
+			final SessionImplementor session, 
+			final Object owner) 
+	throws HibernateException {
+		//disassembled state gets put in a new array (we write to cache by value!)
+		this.disassembledState = TypeFactory.disassemble( 
+				state, 
+				persister.getPropertyTypes(), 
+				persister.isLazyPropertiesCacheable() ? 
+					null : persister.getPropertyLaziness(),
+				session, 
+				owner 
+			);
+		subclass = persister.getEntityName();
+		lazyPropertiesAreUnfetched = unfetched || !persister.isLazyPropertiesCacheable();
+		this.version = version;
+	}
+	
+	public Object getVersion() {
+		return version;
+	}
+
+	CacheEntry(Serializable[] state, String subclass, boolean unfetched, Object version) {
+		this.disassembledState = state;
+		this.subclass = subclass;
+		this.lazyPropertiesAreUnfetched = unfetched;
+		this.version = version;
+	}
+
+	public Object[] assemble(
+			final Object instance, 
+			final Serializable id, 
+			final EntityPersister persister, 
+			final Interceptor interceptor, 
+			final EventSource session) 
+	throws HibernateException {
+
+		if ( !persister.getEntityName().equals(subclass) ) {
+			throw new AssertionFailure("Tried to assemble a different subclass instance");
+		}
+
+		return assemble(disassembledState, instance, id, persister, interceptor, session);
+
+	}
+
+	private static Object[] assemble(
+			final Serializable[] values, 
+			final Object result, 
+			final Serializable id, 
+			final EntityPersister persister, 
+			final Interceptor interceptor, 
+			final EventSource session) 
+	throws HibernateException {
+			
+		//assembled state gets put in a new array (we read from cache by value!)
+		Object[] assembledProps = TypeFactory.assemble( 
+				values, 
+				persister.getPropertyTypes(), 
+				session, result 
+			);
+
+		//persister.setIdentifier(result, id); //before calling interceptor, for consistency with normal load
+
+		//TODO: reuse the PreLoadEvent
+		PreLoadEvent preLoadEvent = new PreLoadEvent( session )
+				.setEntity(result)
+				.setState(assembledProps)
+				.setId(id)
+				.setPersister(persister);
+		
+		PreLoadEventListener[] listeners = session.getListeners().getPreLoadEventListeners();
+		for ( int i = 0; i < listeners.length; i++ ) {
+			listeners[i].onPreLoad(preLoadEvent);
+		}
+		
+		persister.setPropertyValues( 
+				result, 
+				assembledProps, 
+				session.getEntityMode() 
+			);
+
+		return assembledProps;
+	}
+
+    public Serializable[] getDisassembledState() {
+	    // todo: this was added to support initializing an entity's EntityEntry snapshot during reattach;
+	    // this should be refactored to instead expose a method to assemble a EntityEntry based on this
+	    // state for return.
+	    return disassembledState;
+    }
+
+	public String toString() {
+		return "CacheEntry(" + subclass + ')' + 
+				ArrayHelper.toString(disassembledState);
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/CacheEntryStructure.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/CacheEntryStructure.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/CacheEntryStructure.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,14 @@
+//$Id: CacheEntryStructure.java 5707 2005-02-13 12:47:01Z oneovthafew $
+package org.hibernate.cache.entry;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+
+
+
+/**
+ * @author Gavin King
+ */
+public interface CacheEntryStructure {
+	public Object structure(Object item);
+	public Object destructure(Object map, SessionFactoryImplementor factory);
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/CacheEntryStructure.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/CollectionCacheEntry.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/CollectionCacheEntry.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/CollectionCacheEntry.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+//$Id: CollectionCacheEntry.java 6838 2005-05-20 19:50:07Z oneovthafew $
+package org.hibernate.cache.entry;
+
+import java.io.Serializable;
+
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * @author Gavin King
+ */
+public class CollectionCacheEntry implements Serializable {
+
+	private final Serializable state;
+	
+	public Serializable[] getState() {
+		//TODO: assumes all collections disassemble to an array!
+		return (Serializable[]) state;
+	}
+
+	public CollectionCacheEntry(PersistentCollection collection, CollectionPersister persister) {
+		this.state = collection.disassemble(persister);
+	}
+	
+	CollectionCacheEntry(Serializable state) {
+		this.state = state;
+	}
+	
+	public void assemble(
+		final PersistentCollection collection, 
+		final CollectionPersister persister,
+		final Object owner
+	) {
+		collection.initializeFromCache(persister, state, owner);
+		collection.afterInitialize();
+	}
+	
+	public String toString() {
+		return "CollectionCacheEntry" + ArrayHelper.toString( getState() );
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/CollectionCacheEntry.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredCacheEntry.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredCacheEntry.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredCacheEntry.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+//$Id: StructuredCacheEntry.java 7764 2005-08-05 16:16:46Z oneovthafew $
+package org.hibernate.cache.entry;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * @author Gavin King
+ */
+public class StructuredCacheEntry implements CacheEntryStructure {
+
+	private EntityPersister persister;
+
+	public StructuredCacheEntry(EntityPersister persister) {
+		this.persister = persister;
+	}
+	
+	public Object destructure(Object item, SessionFactoryImplementor factory) {
+		Map map = (Map) item;
+		boolean lazyPropertiesUnfetched = ( (Boolean) map.get("_lazyPropertiesUnfetched") ).booleanValue();
+		String subclass = (String) map.get("_subclass");
+		Object version = map.get("_version");
+		EntityPersister subclassPersister = factory.getEntityPersister(subclass);
+		String[] names = subclassPersister.getPropertyNames();
+		Serializable[] state = new Serializable[names.length];
+		for ( int i=0; i<names.length; i++ ) {
+			state[i] = (Serializable) map.get( names[i] );
+		}
+		return new CacheEntry(state, subclass, lazyPropertiesUnfetched, version);
+	}
+
+	public Object structure(Object item) {
+		CacheEntry entry = (CacheEntry) item;
+		String[] names = persister.getPropertyNames();
+		Map map = new HashMap(names.length+2);
+		map.put( "_subclass", entry.getSubclass() );
+		map.put( "_version", entry.getVersion() );
+		map.put( "_lazyPropertiesUnfetched", entry.areLazyPropertiesUnfetched() ? Boolean.TRUE : Boolean.FALSE );
+		for ( int i=0; i<names.length; i++ ) {
+			map.put( names[i], entry.getDisassembledState()[i] );
+		}
+		return map;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredCacheEntry.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredCollectionCacheEntry.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredCollectionCacheEntry.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredCollectionCacheEntry.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+//$Id: StructuredCollectionCacheEntry.java 5707 2005-02-13 12:47:01Z oneovthafew $
+package org.hibernate.cache.entry;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.List;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * @author Gavin King
+ */
+public class StructuredCollectionCacheEntry implements CacheEntryStructure {
+
+	public Object structure(Object item) {
+		CollectionCacheEntry entry = (CollectionCacheEntry) item;
+		return Arrays.asList( entry.getState() );
+	}
+	
+	public Object destructure(Object item, SessionFactoryImplementor factory) {
+		List list = (List) item;
+		return new CollectionCacheEntry( list.toArray( new Serializable[list.size()] ) );
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredCollectionCacheEntry.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredMapCacheEntry.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredMapCacheEntry.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredMapCacheEntry.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+//$Id: StructuredMapCacheEntry.java 5707 2005-02-13 12:47:01Z oneovthafew $
+package org.hibernate.cache.entry;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * @author Gavin King
+ */
+public class StructuredMapCacheEntry implements CacheEntryStructure {
+
+	public Object structure(Object item) {
+		CollectionCacheEntry entry = (CollectionCacheEntry) item;
+		Serializable[] state = entry.getState();
+		Map map = new HashMap(state.length);
+		for ( int i=0; i<state.length; ) {
+			map.put( state[i++], state[i++] );
+		}
+		return map;
+	}
+	
+	public Object destructure(Object item, SessionFactoryImplementor factory) {
+		Map map = (Map) item;
+		Serializable[] state = new Serializable[ map.size()*2 ];
+		int i=0;
+		Iterator iter = map.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			state[i++] = (Serializable) me.getKey();
+			state[i++] = (Serializable) me.getValue();
+		}
+		return new CollectionCacheEntry(state);
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/StructuredMapCacheEntry.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/UnstructuredCacheEntry.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/UnstructuredCacheEntry.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/UnstructuredCacheEntry.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+//$Id: UnstructuredCacheEntry.java 5707 2005-02-13 12:47:01Z oneovthafew $
+package org.hibernate.cache.entry;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+
+
+/**
+ * @author Gavin King
+ */
+public class UnstructuredCacheEntry implements CacheEntryStructure {
+
+	public Object structure(Object item) {
+		return item;
+	}
+
+	public Object destructure(Object map, SessionFactoryImplementor factory) {
+		return map;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/UnstructuredCacheEntry.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+<html>
+<head>
+</head>
+<body>
+<p>
+	This package defines formats for disassembled state
+	kept in the second level cache.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/entry/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/CacheDataDescriptionImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/CacheDataDescriptionImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/CacheDataDescriptionImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+package org.hibernate.cache.impl;
+
+import java.util.Comparator;
+
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Collection;
+import org.hibernate.type.VersionType;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class CacheDataDescriptionImpl implements CacheDataDescription {
+	private final boolean mutable;
+	private final boolean versioned;
+	private final Comparator versionComparator;
+
+	public CacheDataDescriptionImpl(boolean mutable, boolean versioned, Comparator versionComparator) {
+		this.mutable = mutable;
+		this.versioned = versioned;
+		this.versionComparator = versionComparator;
+	}
+
+	public boolean isMutable() {
+		return mutable;
+	}
+
+	public boolean isVersioned() {
+		return versioned;
+	}
+
+	public Comparator getVersionComparator() {
+		return versionComparator;
+	}
+
+	public static CacheDataDescriptionImpl decode(PersistentClass model) {
+		return new CacheDataDescriptionImpl(
+				model.isMutable(),
+				model.isVersioned(),
+				model.isVersioned() ? ( ( VersionType ) model.getVersion().getType() ).getComparator() : null
+		);
+	}
+
+	public static CacheDataDescriptionImpl decode(Collection model) {
+		return new CacheDataDescriptionImpl(
+				model.isMutable(),
+				model.getOwner().isVersioned(),
+				model.getOwner().isVersioned() ? ( ( VersionType ) model.getOwner().getVersion().getType() ).getComparator() : null
+		);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/NoCachingRegionFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/NoCachingRegionFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/NoCachingRegionFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+package org.hibernate.cache.impl;
+
+import java.util.Properties;
+
+import org.hibernate.cache.RegionFactory;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.EntityRegion;
+import org.hibernate.cache.CollectionRegion;
+import org.hibernate.cache.QueryResultsRegion;
+import org.hibernate.cache.TimestampsRegion;
+import org.hibernate.cache.NoCachingEnabledException;
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.cfg.Settings;
+
+/**
+ * Factory used if no caching enabled in config...
+ *
+ * @author Steve Ebersole
+ */
+public class NoCachingRegionFactory implements RegionFactory {
+
+
+	public NoCachingRegionFactory(Properties properties) {
+	}
+
+	public void start(Settings settings, Properties properties) throws CacheException {
+	}
+
+	public void stop() {
+	}
+
+	public boolean isMinimalPutsEnabledByDefault() {
+		return false;
+	}
+
+	public long nextTimestamp() {
+		return System.currentTimeMillis() / 100;
+	}
+
+	public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata)
+			throws CacheException {
+		throw new NoCachingEnabledException();
+	}
+
+	public CollectionRegion buildCollectionRegion(String regionName, Properties properties, CacheDataDescription metadata)
+			throws CacheException {
+		throw new NoCachingEnabledException();
+	}
+
+	public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException {
+		throw new NoCachingEnabledException();
+	}
+
+	public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException {
+		throw new NoCachingEnabledException();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/BaseGeneralDataRegionAdapter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/BaseGeneralDataRegionAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/BaseGeneralDataRegionAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+package org.hibernate.cache.impl.bridge;
+
+import org.hibernate.cache.GeneralDataRegion;
+import org.hibernate.cache.Cache;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cfg.Settings;
+
+/**
+ * {@inheritDoc}
+*
+* @author Steve Ebersole
+*/
+public abstract class BaseGeneralDataRegionAdapter extends BaseRegionAdapter implements GeneralDataRegion {
+
+	protected BaseGeneralDataRegionAdapter(Cache underlyingCache, Settings settings) {
+		super( underlyingCache, settings );
+	}
+
+	public Object get(Object key) throws CacheException {
+		return underlyingCache.get( key );
+	}
+
+	public void put(Object key, Object value) throws CacheException {
+		underlyingCache.put( key, value );
+	}
+
+	public void evict(Object key) throws CacheException {
+		underlyingCache.remove( key );
+	}
+
+	public void evictAll() throws CacheException {
+		underlyingCache.clear();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/BaseRegionAdapter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/BaseRegionAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/BaseRegionAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,59 @@
+package org.hibernate.cache.impl.bridge;
+
+import java.util.Map;
+
+import org.hibernate.cache.Region;
+import org.hibernate.cache.Cache;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cfg.Settings;
+
+/**
+ * Basic adapter bridging between {@link Region} and {@link Cache}.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class BaseRegionAdapter implements Region {
+	protected final Cache underlyingCache;
+	protected final Settings settings;
+
+	protected BaseRegionAdapter(Cache underlyingCache, Settings settings) {
+		this.underlyingCache = underlyingCache;
+		this.settings = settings;
+	}
+
+	public String getName() {
+		return underlyingCache.getRegionName();
+	}
+
+	public void clear() throws CacheException {
+		underlyingCache.clear();
+	}
+
+	public void destroy() throws CacheException {
+		underlyingCache.destroy();
+	}
+
+	public long getSizeInMemory() {
+		return underlyingCache.getSizeInMemory();
+	}
+
+	public long getElementCountInMemory() {
+		return underlyingCache.getElementCountInMemory();
+	}
+
+	public long getElementCountOnDisk() {
+		return underlyingCache.getElementCountOnDisk();
+	}
+
+	public Map toMap() {
+		return underlyingCache.toMap();
+	}
+
+	public long nextTimestamp() {
+		return underlyingCache.nextTimestamp();
+	}
+
+	public int getTimeout() {
+		return underlyingCache.getTimeout();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/BaseTransactionalDataRegionAdapter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/BaseTransactionalDataRegionAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/BaseTransactionalDataRegionAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+package org.hibernate.cache.impl.bridge;
+
+import org.hibernate.cache.TransactionalDataRegion;
+import org.hibernate.cache.Cache;
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.cfg.Settings;
+
+/**
+ * {@inheritDoc}
+*
+* @author Steve Ebersole
+*/
+public abstract class BaseTransactionalDataRegionAdapter extends BaseRegionAdapter implements TransactionalDataRegion {
+
+	protected final CacheDataDescription metadata;
+
+	protected BaseTransactionalDataRegionAdapter(Cache underlyingCache, Settings settings, CacheDataDescription metadata) {
+		super( underlyingCache, settings );
+		this.metadata = metadata;
+	}
+
+	public boolean isTransactionAware() {
+		return underlyingCache instanceof org.hibernate.cache.TreeCache
+				|| underlyingCache instanceof org.hibernate.cache.OptimisticTreeCache;
+	}
+
+	public CacheDataDescription getCacheDataDescription() {
+		return metadata;
+	}
+
+//		public void lock() throws CacheException {
+//			// impl note: unfortunately this was not a capability of the original Cache contract
+//		}
+//
+//		public void unlock() throws CacheException {
+//			// impl note: unfortunately this was not a capability of the original Cache contract
+//		}
+//
+//		public void lock(Object key) throws CacheException {
+//			underlyingCache.lock( key );
+//		}
+//
+//		public void unlock(Object key) throws CacheException {
+//			underlyingCache.unlock( key );
+//		}
+//
+//		public Object get(Object key) throws CacheException {
+//			return underlyingCache.get( key );
+//		}
+//
+//		public Object read(Object key) throws CacheException {
+//			return underlyingCache.read( key );
+//		}
+//
+//		public void writeLoad(Object key, Object value, Object version) throws CacheException {
+//			if ( underlyingCache instanceof OptimisticCache ) {
+//				( ( OptimisticCache ) underlyingCache ).writeLoad( key, value, version );
+//			}
+//			else {
+//				underlyingCache.put( key, value );
+//			}
+//		}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/CollectionAccessStrategyAdapter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/CollectionAccessStrategyAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/CollectionAccessStrategyAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,91 @@
+package org.hibernate.cache.impl.bridge;
+
+import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cache.access.SoftLock;
+import org.hibernate.cache.CacheConcurrencyStrategy;
+import org.hibernate.cache.CollectionRegion;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cfg.Settings;
+
+/**
+ * Adapter specifically bridging {@link CollectionRegionAccessStrategy} to {@link CacheConcurrencyStrategy}.
+ *
+ * @author Steve Ebersole
+ */
+public class CollectionAccessStrategyAdapter implements CollectionRegionAccessStrategy {
+	private final CollectionRegion region;
+	private final CacheConcurrencyStrategy ccs;
+	private final Settings settings;
+
+	public CollectionAccessStrategyAdapter(CollectionRegion region, CacheConcurrencyStrategy ccs, Settings settings) {
+		this.region = region;
+		this.ccs = ccs;
+		this.settings = settings;
+	}
+
+	public CollectionRegion getRegion() {
+		return region;
+	}
+
+	public Object get(Object key, long txTimestamp) throws CacheException {
+		return ccs.get( key, txTimestamp );
+	}
+
+	public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
+		return putFromLoad( key, value, txTimestamp, version, settings.isMinimalPutsEnabled() );
+	}
+
+	public boolean putFromLoad(
+			Object key, 
+			Object value,
+			long txTimestamp,
+			Object version,
+			boolean minimalPutOverride) throws CacheException {
+		return ccs.put( key, value, txTimestamp, version, region.getCacheDataDescription().getVersionComparator(), minimalPutOverride );
+	}
+
+	public SoftLock lockItem(Object key, Object version) throws CacheException {
+		return ccs.lock( key, version );
+	}
+
+	public SoftLock lockRegion() throws CacheException {
+		// no-op; CCS did not have such a concept
+		return null;
+	}
+
+	public void unlockItem(Object key, SoftLock lock) throws CacheException {
+		ccs.release( key, lock );
+	}
+
+	public void unlockRegion(SoftLock lock) throws CacheException {
+		// again, CCS did not have such a concept; but a reasonable
+		// proximity is to clear the cache after transaction *as long as*
+		// the underlying cache is not JTA aware.
+		if ( !region.isTransactionAware() ) {
+			ccs.clear();
+		}
+	}
+
+	public void remove(Object key) throws CacheException {
+		ccs.evict( key );
+	}
+
+	public void removeAll() throws CacheException {
+		// again, CCS did not have such a concept; however a reasonable
+		// proximity is to clear the cache.  For non-transaction aware
+		// caches, we will also do a clear at the end of the transaction
+		ccs.clear();
+	}
+
+	public void evict(Object key) throws CacheException {
+		ccs.remove( key );
+	}
+
+	public void evictAll() throws CacheException {
+		ccs.clear();
+	}
+
+	public void destroy() {
+		ccs.destroy();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/CollectionRegionAdapter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/CollectionRegionAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/CollectionRegionAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,58 @@
+package org.hibernate.cache.impl.bridge;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.cache.CollectionRegion;
+import org.hibernate.cache.Cache;
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.cache.OptimisticCache;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.CacheConcurrencyStrategy;
+import org.hibernate.cache.TransactionalCache;
+import org.hibernate.cache.ReadWriteCache;
+import org.hibernate.cache.NonstrictReadWriteCache;
+import org.hibernate.cache.ReadOnlyCache;
+import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cache.access.AccessType;
+import org.hibernate.cfg.Settings;
+
+/**
+ * Adapter specifically bridging {@link CollectionRegion} to {@link Cache}.
+ *
+ * @author Steve Ebersole
+ */
+public class CollectionRegionAdapter extends BaseTransactionalDataRegionAdapter implements CollectionRegion {
+	private static final Log log = LogFactory.getLog( CollectionRegionAdapter.class );
+
+	public CollectionRegionAdapter(Cache underlyingCache, Settings settings, CacheDataDescription metadata) {
+		super( underlyingCache, settings, metadata );
+		if ( underlyingCache instanceof OptimisticCache ) {
+			( ( OptimisticCache ) underlyingCache ).setSource( new OptimisticCacheSourceAdapter( metadata ) );
+		}
+	}
+
+	public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
+		CacheConcurrencyStrategy ccs;
+		if ( AccessType.READ_ONLY.equals( accessType ) ) {
+			if ( metadata.isMutable() ) {
+				log.warn( "read-only cache configured for mutable collection [" + getName() + "]" );
+			}
+			ccs = new ReadOnlyCache();
+		}
+		else if ( AccessType.READ_WRITE.equals( accessType ) ) {
+			ccs = new ReadWriteCache();
+		}
+		else if ( AccessType.NONSTRICT_READ_WRITE.equals( accessType ) ) {
+			ccs = new NonstrictReadWriteCache();
+		}
+		else if ( AccessType.TRANSACTIONAL.equals( accessType ) ) {
+			ccs = new TransactionalCache();
+		}
+		else {
+			throw new IllegalArgumentException( "unrecognized access strategy type [" + accessType + "]" );
+		}
+		ccs.setCache( underlyingCache );
+		return new CollectionAccessStrategyAdapter( this, ccs, settings );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/EntityAccessStrategyAdapter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/EntityAccessStrategyAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/EntityAccessStrategyAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,109 @@
+package org.hibernate.cache.impl.bridge;
+
+import org.hibernate.cache.CacheConcurrencyStrategy;
+import org.hibernate.cache.EntityRegion;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cache.access.SoftLock;
+import org.hibernate.cfg.Settings;
+
+/**
+ * Adapter specifically bridging {@link EntityRegionAccessStrategy} to {@link CacheConcurrencyStrategy}.
+ *
+ * @author Steve Ebersole
+ */
+public class EntityAccessStrategyAdapter implements EntityRegionAccessStrategy {
+	private final EntityRegion region;
+	private final CacheConcurrencyStrategy ccs;
+	private final Settings settings;
+
+	public EntityAccessStrategyAdapter(EntityRegion region, CacheConcurrencyStrategy ccs, Settings settings) {
+		this.region = region;
+		this.ccs = ccs;
+		this.settings = settings;
+	}
+
+	public EntityRegion getRegion() {
+		return region;
+	}
+
+	public Object get(Object key, long txTimestamp) throws CacheException {
+		return ccs.get( key, txTimestamp );
+	}
+
+	public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
+		return putFromLoad( key, value, txTimestamp, version, settings.isMinimalPutsEnabled() );
+	}
+
+	public boolean putFromLoad(
+			Object key,
+			Object value,
+			long txTimestamp,
+			Object version,
+			boolean minimalPutOverride) throws CacheException {
+		return ccs.put( key, value, txTimestamp, version, region.getCacheDataDescription().getVersionComparator(), minimalPutOverride );
+	}
+
+	public SoftLock lockItem(Object key, Object version) throws CacheException {
+		return ccs.lock( key, version );
+	}
+
+	public SoftLock lockRegion() throws CacheException {
+		// no-op; CCS did not have such a concept
+		return null;
+	}
+
+	public void unlockItem(Object key, SoftLock lock) throws CacheException {
+		ccs.release( key, lock );
+	}
+
+	public void unlockRegion(SoftLock lock) throws CacheException {
+		// again, CCS did not have such a concept; but a reasonable
+		// proximity is to clear the cache after transaction *as long as*
+		// the underlying cache is not JTA aware.
+		if ( !region.isTransactionAware() ) {
+			ccs.clear();
+		}
+	}
+
+	public boolean insert(Object key, Object value, Object version) throws CacheException {
+		return ccs.insert( key, value, version );
+	}
+
+	public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
+		return ccs.afterInsert( key, value, version );
+	}
+
+	public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
+			throws CacheException {
+		return ccs.update( key, value, currentVersion, previousVersion );
+	}
+
+	public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
+			throws CacheException {
+		return ccs.afterUpdate( key, value, currentVersion, lock );
+	}
+
+	public void remove(Object key) throws CacheException {
+		ccs.evict( key );
+	}
+
+	public void removeAll() throws CacheException {
+		// again, CCS did not have such a concept; however a reasonable
+		// proximity is to clear the cache.  For non-transaction aware
+		// caches, we will also do a clear at the end of the transaction
+		ccs.clear();
+	}
+
+	public void evict(Object key) throws CacheException {
+		ccs.remove( key );
+	}
+
+	public void evictAll() throws CacheException {
+		ccs.clear();
+	}
+
+	public void destroy() {
+		ccs.destroy();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/EntityRegionAdapter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/EntityRegionAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/EntityRegionAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,59 @@
+package org.hibernate.cache.impl.bridge;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.cache.EntityRegion;
+import org.hibernate.cache.Cache;
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.cache.OptimisticCache;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.CacheConcurrencyStrategy;
+import org.hibernate.cache.ReadOnlyCache;
+import org.hibernate.cache.ReadWriteCache;
+import org.hibernate.cache.NonstrictReadWriteCache;
+import org.hibernate.cache.TransactionalCache;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cache.access.AccessType;
+import org.hibernate.cfg.Settings;
+
+/**
+ * Adapter specifically bridging {@link EntityRegion} to {@link Cache}.
+ *
+ * @author Steve Ebersole
+ */
+public class EntityRegionAdapter extends BaseTransactionalDataRegionAdapter implements EntityRegion {
+	private static final Log log = LogFactory.getLog( EntityRegionAdapter.class );
+
+	public EntityRegionAdapter(Cache underlyingCache, Settings settings, CacheDataDescription metadata) {
+		super( underlyingCache, settings, metadata );
+		if ( underlyingCache instanceof OptimisticCache ) {
+			( ( OptimisticCache ) underlyingCache ).setSource( new OptimisticCacheSourceAdapter( metadata ) );
+		}
+	}
+
+	public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
+		CacheConcurrencyStrategy ccs;
+		if ( AccessType.READ_ONLY.equals( accessType ) ) {
+			if ( metadata.isMutable() ) {
+				log.warn( "read-only cache configured for mutable entity [" + getName() + "]" );
+			}
+			ccs = new ReadOnlyCache();
+		}
+		else if ( AccessType.READ_WRITE.equals( accessType ) ) {
+			ccs = new ReadWriteCache();
+		}
+		else if ( AccessType.NONSTRICT_READ_WRITE.equals( accessType ) ) {
+			ccs = new NonstrictReadWriteCache();
+		}
+		else if ( AccessType.TRANSACTIONAL.equals( accessType ) ) {
+			ccs = new TransactionalCache();
+		}
+		else {
+			throw new IllegalArgumentException( "unrecognized access strategy type [" + accessType + "]" );
+		}
+		ccs.setCache( underlyingCache );
+		return new EntityAccessStrategyAdapter( this, ccs, settings );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/OptimisticCacheSourceAdapter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/OptimisticCacheSourceAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/OptimisticCacheSourceAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+package org.hibernate.cache.impl.bridge;
+
+import java.util.Comparator;
+
+import org.hibernate.cache.OptimisticCacheSource;
+import org.hibernate.cache.CacheDataDescription;
+
+/**
+ * {@inheritDoc}
+*
+* @author Steve Ebersole
+*/
+public class OptimisticCacheSourceAdapter implements OptimisticCacheSource {
+	private final CacheDataDescription dataDescription;
+
+	public OptimisticCacheSourceAdapter(CacheDataDescription dataDescription) {
+		this.dataDescription = dataDescription;
+	}
+
+	public boolean isVersioned() {
+		return dataDescription.isVersioned();
+	}
+
+	public Comparator getVersionComparator() {
+		return dataDescription.getVersionComparator();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/QueryResultsRegionAdapter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/QueryResultsRegionAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/QueryResultsRegionAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+package org.hibernate.cache.impl.bridge;
+
+import org.hibernate.cache.QueryResultsRegion;
+import org.hibernate.cache.Cache;
+import org.hibernate.cfg.Settings;
+
+/**
+ * Adapter specifically briding {@link QueryResultsRegion} to {@link Cache}.
+*
+* @author Steve Ebersole
+ */
+public class QueryResultsRegionAdapter extends BaseGeneralDataRegionAdapter implements QueryResultsRegion {
+	protected QueryResultsRegionAdapter(Cache underlyingCache, Settings settings) {
+		super( underlyingCache, settings );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/RegionFactoryCacheProviderBridge.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/RegionFactoryCacheProviderBridge.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/RegionFactoryCacheProviderBridge.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,91 @@
+package org.hibernate.cache.impl.bridge;
+
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.cache.RegionFactory;
+import org.hibernate.cache.CacheProvider;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.EntityRegion;
+import org.hibernate.cache.CollectionRegion;
+import org.hibernate.cache.QueryResultsRegion;
+import org.hibernate.cache.NoCacheProvider;
+import org.hibernate.cache.TimestampsRegion;
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.util.PropertiesHelper;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.Settings;
+
+/**
+ * Acts as a bridge between the {@link RegionFactory} contract and the older
+ * {@link CacheProvider} contract.
+ *
+ * @author Steve Ebersole
+ */
+public class RegionFactoryCacheProviderBridge implements RegionFactory {
+	public static final String DEF_PROVIDER = NoCacheProvider.class.getName();
+	private static final Log log = LogFactory.getLog( RegionFactoryCacheProviderBridge.class );
+
+	private CacheProvider cacheProvider;
+	private Settings settings;
+
+	public RegionFactoryCacheProviderBridge(Properties properties) {
+		String providerClassName = PropertiesHelper.getString( Environment.CACHE_PROVIDER, properties, DEF_PROVIDER );
+		log.info( "Cache provider: " + providerClassName );
+		try {
+			cacheProvider = ( CacheProvider ) ReflectHelper.classForName( providerClassName ).newInstance();
+		}
+		catch ( Exception cnfe ) {
+			throw new CacheException( "could not instantiate CacheProvider [" + providerClassName + "]", cnfe );
+		}
+	}
+
+	public void start(Settings settings, Properties properties) throws CacheException {
+		this.settings = settings;
+		cacheProvider.start( properties );
+	}
+
+	public void stop() {
+		cacheProvider.stop();
+		cacheProvider = null;
+	}
+
+	public boolean isMinimalPutsEnabledByDefault() {
+		return cacheProvider.isMinimalPutsEnabledByDefault();
+	}
+
+	public long nextTimestamp() {
+		return cacheProvider.nextTimestamp();
+	}
+
+	public CacheProvider getCacheProvider() {
+		return cacheProvider;
+	}
+
+	public EntityRegion buildEntityRegion(
+			String regionName,
+			Properties properties,
+			CacheDataDescription metadata) throws CacheException {
+		return new EntityRegionAdapter( cacheProvider.buildCache( regionName, properties ), settings, metadata );
+	}
+
+	public CollectionRegion buildCollectionRegion(
+			String regionName,
+			Properties properties,
+			CacheDataDescription metadata) throws CacheException {
+		return new CollectionRegionAdapter( cacheProvider.buildCache( regionName, properties ), settings, metadata );
+	}
+
+	public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException {
+		return new QueryResultsRegionAdapter( cacheProvider.buildCache( regionName, properties ), settings );
+	}
+
+	public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException {
+		return new TimestampsRegionAdapter( cacheProvider.buildCache( regionName, properties ), settings );
+	}
+
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/TimestampsRegionAdapter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/TimestampsRegionAdapter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/impl/bridge/TimestampsRegionAdapter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+package org.hibernate.cache.impl.bridge;
+
+import org.hibernate.cache.TimestampsRegion;
+import org.hibernate.cache.Cache;
+import org.hibernate.cfg.Settings;
+
+/**
+ * Adapter specifically briding {@link TimestampsRegion} to {@link Cache}.
+*
+* @author Steve Ebersole
+ */
+public class TimestampsRegionAdapter extends BaseGeneralDataRegionAdapter implements TimestampsRegion {
+	protected TimestampsRegionAdapter(Cache underlyingCache, Settings settings) {
+		super( underlyingCache, settings );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cache/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cache/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+<html>
+    <head>
+    </head>
+
+    <body>
+        <p>
+            This package defines APIs/SPIs and implementations for the Hibernate second-level cache.
+        </p>
+        <p>
+            The legacy (and now deprecated) approach to caching is defined by the {@link org.hibernate.cache.CacheProvider} and
+            {@link org.hibernate.cache.Cache} interfaces as well as the {@link org.hibernate.cache.CacheConcurrencyStrategy}
+            interface along with the various implementations of all these interfaces.  In that scheme, a
+            {@link org.hibernate.cache.CacheProvider} defined how to configure and perform lifecycle operations
+            in regards to a particular underlying caching library; it also defined how to build {@link org.hibernate.cache.Cache}
+            instances which in turn defined how to access the "regions" of the underlying cache instance.
+            For entity and collection data cache regions, {@link org.hibernate.cache.CacheConcurrencyStrategy} wrapped
+            access to those cache regions to apply transactional/concurrent access semantics.
+        </p>
+        <p>
+            The improved approach is based on {@link org.hibernate.cache.RegionFactory}, the various
+            {@link org.hibernate.cache.Region} specializations and the two access strategies contracts
+            ({@link org.hibernate.cache.access.EntityRegionAccessStrategy} and
+            {@link org.hibernate.cache.access.CollectionRegionAccessStrategy}).  The general approach here is that
+            {@link org.hibernate.cache.RegionFactory} defined how to configure and perform lifecycle operations
+            in regards to a particular underlying caching library (<b>or libraries</b>).
+            {@link org.hibernate.cache.RegionFactory} also defines how to build specialized
+            {@link org.hibernate.cache.Region} instances based on the type of data we will be storing in that given
+            region.  The fact that {@link org.hibernate.cache.RegionFactory} is asked to build <b>specialized</b>
+            regions (as opposed to just general access) is the first <i>improvement</i> over the legacy scheme.  The
+            second <i>improvement</i> is the fact that the regions (well the ones like entity and collection regions
+            that are responsible for storing {@link org.hibernate.cache.TransactionalDataRegion transactional} data) are
+            asked to build their own access strategies (see {@link org.hibernate.cache.EntityRegion#buildAccessStrategy}
+            and {@link org.hibernate.cache.CollectionRegion#buildAccessStrategy}).
+        </p>
+    </body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/cache/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/CollectionSecondPass.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/CollectionSecondPass.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/CollectionSecondPass.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,73 @@
+//$Id: CollectionSecondPass.java 10196 2006-08-03 07:53:27Z max.andersen at jboss.com $
+package org.hibernate.cfg;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.MappingException;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.IndexedCollection;
+import org.hibernate.mapping.OneToMany;
+import org.hibernate.mapping.Selectable;
+import org.hibernate.mapping.Value;
+
+/**
+ * Collection second pass
+ *
+ * @author Emmanuel Bernard
+ */
+public abstract class CollectionSecondPass implements SecondPass {
+	private static Log log = LogFactory.getLog( CollectionSecondPass.class );
+	Mappings mappings;
+	Collection collection;
+	private Map localInheritedMetas;
+
+	public CollectionSecondPass(Mappings mappings, Collection collection, java.util.Map inheritedMetas) {
+		this.collection = collection;
+		this.mappings = mappings;
+		this.localInheritedMetas = inheritedMetas;
+	}
+
+	public CollectionSecondPass(Mappings mappings, Collection collection) {
+		this(mappings, collection, Collections.EMPTY_MAP);
+	}
+
+	public void doSecondPass(java.util.Map persistentClasses)
+			throws MappingException {
+		if ( log.isDebugEnabled() )
+			log.debug( "Second pass for collection: " + collection.getRole() );
+
+		secondPass( persistentClasses, localInheritedMetas ); // using local since the inheritedMetas at this point is not the correct map since it is always the empty map
+		collection.createAllKeys();
+
+		if ( log.isDebugEnabled() ) {
+			String msg = "Mapped collection key: " + columns( collection.getKey() );
+			if ( collection.isIndexed() )
+				msg += ", index: " + columns( ( (IndexedCollection) collection ).getIndex() );
+			if ( collection.isOneToMany() ) {
+				msg += ", one-to-many: "
+					+ ( (OneToMany) collection.getElement() ).getReferencedEntityName();
+			}
+			else {
+				msg += ", element: " + columns( collection.getElement() );
+			}
+			log.debug( msg );
+		}
+	}
+
+	abstract public void secondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas)
+			throws MappingException;
+
+	private static String columns(Value val) {
+		StringBuffer columns = new StringBuffer();
+		Iterator iter = val.getColumnIterator();
+		while ( iter.hasNext() ) {
+			columns.append( ( (Selectable) iter.next() ).getText() );
+			if ( iter.hasNext() ) columns.append( ", " );
+		}
+		return columns.toString();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Configuration.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Configuration.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Configuration.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,2103 @@
+//$Id: Configuration.java 10841 2006-11-17 18:29:10Z max.andersen at jboss.com $
+package org.hibernate.cfg;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.io.StringReader;
+import java.lang.reflect.Array;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.dom4j.Attribute;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.InvalidMappingException;
+import org.hibernate.MappingException;
+import org.hibernate.MappingNotFoundException;
+import org.hibernate.SessionFactory;
+import org.hibernate.proxy.EntityNotFoundDelegate;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.dialect.function.SQLFunction;
+import org.hibernate.engine.FilterDefinition;
+import org.hibernate.engine.Mapping;
+import org.hibernate.event.AutoFlushEventListener;
+import org.hibernate.event.DeleteEventListener;
+import org.hibernate.event.DirtyCheckEventListener;
+import org.hibernate.event.EventListeners;
+import org.hibernate.event.EvictEventListener;
+import org.hibernate.event.FlushEntityEventListener;
+import org.hibernate.event.FlushEventListener;
+import org.hibernate.event.InitializeCollectionEventListener;
+import org.hibernate.event.LoadEventListener;
+import org.hibernate.event.LockEventListener;
+import org.hibernate.event.MergeEventListener;
+import org.hibernate.event.PersistEventListener;
+import org.hibernate.event.PostDeleteEventListener;
+import org.hibernate.event.PostInsertEventListener;
+import org.hibernate.event.PostLoadEventListener;
+import org.hibernate.event.PostUpdateEventListener;
+import org.hibernate.event.PreDeleteEventListener;
+import org.hibernate.event.PreInsertEventListener;
+import org.hibernate.event.PreLoadEventListener;
+import org.hibernate.event.PreUpdateEventListener;
+import org.hibernate.event.RefreshEventListener;
+import org.hibernate.event.ReplicateEventListener;
+import org.hibernate.event.SaveOrUpdateEventListener;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.id.PersistentIdentifierGenerator;
+import org.hibernate.impl.SessionFactoryImpl;
+import org.hibernate.mapping.AuxiliaryDatabaseObject;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.ForeignKey;
+import org.hibernate.mapping.IdentifierCollection;
+import org.hibernate.mapping.Index;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.RootClass;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.Table;
+import org.hibernate.mapping.UniqueKey;
+import org.hibernate.secure.JACCConfiguration;
+import org.hibernate.tool.hbm2ddl.DatabaseMetadata;
+import org.hibernate.tool.hbm2ddl.TableMetadata;
+import org.hibernate.type.SerializationException;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.CollectionHelper;
+import org.hibernate.util.ConfigHelper;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.SerializationHelper;
+import org.hibernate.util.StringHelper;
+import org.hibernate.util.XMLHelper;
+import org.hibernate.util.PropertiesHelper;
+import org.w3c.dom.Document;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+
+/**
+ * An instance of <tt>Configuration</tt> allows the application
+ * to specify properties and mapping documents to be used when
+ * creating a <tt>SessionFactory</tt>. Usually an application will create
+ * a single <tt>Configuration</tt>, build a single instance of
+ * <tt>SessionFactory</tt> and then instantiate <tt>Session</tt>s in
+ * threads servicing client requests. The <tt>Configuration</tt> is meant
+ * only as an initialization-time object. <tt>SessionFactory</tt>s are
+ * immutable and do not retain any association back to the
+ * <tt>Configuration</tt>.<br>
+ * <br>
+ * A new <tt>Configuration</tt> will use the properties specified in
+ * <tt>hibernate.properties</tt> by default.
+ *
+ * @author Gavin King
+ * @see org.hibernate.SessionFactory
+ */
+public class Configuration implements Serializable {
+
+	private static Log log = LogFactory.getLog( Configuration.class );
+
+	protected Map classes;
+	protected Map imports;
+	protected Map collections;
+	protected Map tables;
+	protected List auxiliaryDatabaseObjects;
+	protected Map sqlFunctions;
+	protected Map namedQueries;
+	protected Map namedSqlQueries;
+	/**
+	 * Map<String, SqlResultSetMapping> result set name, result set description
+	 */
+	protected Map sqlResultSetMappings;
+	protected Map filterDefinitions;
+	protected List secondPasses;
+	protected List propertyReferences;
+//	protected List extendsQueue;
+	protected Map extendsQueue;
+	protected Map tableNameBinding;
+	protected Map columnNameBindingPerTable;
+	private Interceptor interceptor;
+	private Properties properties;
+	private EntityResolver entityResolver;
+	private EntityNotFoundDelegate entityNotFoundDelegate;
+
+	protected transient XMLHelper xmlHelper;
+	protected transient Map typeDefs;
+
+	protected NamingStrategy namingStrategy;
+
+	private EventListeners eventListeners;
+
+	protected final SettingsFactory settingsFactory;
+
+	protected void reset() {
+		classes = new HashMap();
+		imports = new HashMap();
+		collections = new HashMap();
+		tables = new TreeMap();
+		namedQueries = new HashMap();
+		namedSqlQueries = new HashMap();
+		sqlResultSetMappings = new HashMap();
+		xmlHelper = new XMLHelper();
+		typeDefs = new HashMap();
+		propertyReferences = new ArrayList();
+		secondPasses = new ArrayList();
+		interceptor = EmptyInterceptor.INSTANCE;
+		properties = Environment.getProperties();
+		entityResolver = XMLHelper.DEFAULT_DTD_RESOLVER;
+		eventListeners = new EventListeners();
+		filterDefinitions = new HashMap();
+//		extendsQueue = new ArrayList();
+		extendsQueue = new HashMap();
+		auxiliaryDatabaseObjects = new ArrayList();
+		tableNameBinding = new HashMap();
+		columnNameBindingPerTable = new HashMap();
+		namingStrategy = DefaultNamingStrategy.INSTANCE;
+		sqlFunctions = new HashMap();
+	}
+
+	private transient Mapping mapping = buildMapping();
+
+
+
+	protected Configuration(SettingsFactory settingsFactory) {
+		this.settingsFactory = settingsFactory;
+		reset();
+	}
+
+	public Configuration() {
+		this( new SettingsFactory() );
+	}
+
+	/**
+	 * Iterate the entity mappings
+	 *
+	 * @return Iterator of the entity mappings currently contained in the configuration.
+	 */
+	public Iterator getClassMappings() {
+		return classes.values().iterator();
+	}
+
+	/**
+	 * Iterate the collection mappings
+	 *
+	 * @return Iterator of the collection mappings currently contained in the configuration.
+	 */
+	public Iterator getCollectionMappings() {
+		return collections.values().iterator();
+	}
+
+	/**
+	 * Iterate the table mappings
+	 *
+	 * @return Iterator of the table mappings currently contained in the configuration.
+	 */
+	public Iterator getTableMappings() {
+		return tables.values().iterator();
+	}
+
+	/**
+	 * Get the mapping for a particular entity
+	 *
+	 * @param entityName An entity name.
+	 * @return the entity mapping information
+	 */
+	public PersistentClass getClassMapping(String entityName) {
+		return (PersistentClass) classes.get( entityName );
+	}
+
+	/**
+	 * Get the mapping for a particular collection role
+	 *
+	 * @param role a collection role
+	 * @return The collection mapping information
+	 */
+	public Collection getCollectionMapping(String role) {
+		return (Collection) collections.get( role );
+	}
+
+	/**
+	 * Set a custom entity resolver. This entity resolver must be
+	 * set before addXXX(misc) call.
+	 * Default value is {@link org.hibernate.util.DTDEntityResolver}
+	 *
+	 * @param entityResolver entity resolver to use
+	 */
+	public void setEntityResolver(EntityResolver entityResolver) {
+		this.entityResolver = entityResolver;
+	}
+
+	public EntityResolver getEntityResolver() {
+		return entityResolver;
+	}
+
+	/**
+	 * Retrieve the user-supplied delegate to handle non-existent entity
+	 * scenarios.  May be null.
+	 *
+	 * @return The user-supplied delegate
+	 */
+	public EntityNotFoundDelegate getEntityNotFoundDelegate() {
+		return entityNotFoundDelegate;
+	}
+
+	/**
+	 * Specify a user-supplied delegate to be used to handle scenarios where an entity could not be
+	 * located by specified id.  This is mainly intended for EJB3 implementations to be able to
+	 * control how proxy initialization errors should be handled...
+	 *
+	 * @param entityNotFoundDelegate The delegate to use
+	 */
+	public void setEntityNotFoundDelegate(EntityNotFoundDelegate entityNotFoundDelegate) {
+		this.entityNotFoundDelegate = entityNotFoundDelegate;
+	}
+
+	/**
+	 * Read mappings from a particular XML file
+	 *
+	 * @param xmlFile a path to a file
+	 * @return this (for method chaining purposes)
+	 * @throws org.hibernate.MappingException Indicates inability to locate or parse
+	 * the specified mapping file.
+	 * @see #addFile(java.io.File)
+	 */
+	public Configuration addFile(String xmlFile) throws MappingException {
+		return addFile( new File( xmlFile ) );
+	}
+
+	/**
+	 * Read mappings from a particular XML file
+	 *
+	 * @param xmlFile a path to a file
+	 * @return this (for method chaining purposes)
+	 * @throws org.hibernate.MappingException Indicates inability to locate or parse
+	 * the specified mapping file.
+	 */
+	public Configuration addFile(File xmlFile) throws MappingException {
+		log.info( "Reading mappings from file: " + xmlFile.getPath() );
+		if ( !xmlFile.exists() ) {
+			throw new MappingNotFoundException( "file", xmlFile.toString() );
+		}
+		try {
+			List errors = new ArrayList();
+			org.dom4j.Document doc = xmlHelper.createSAXReader( xmlFile.toString(), errors, entityResolver ).read( xmlFile );
+			if ( errors.size() != 0 ) {
+				throw new InvalidMappingException( "file", xmlFile.toString(), ( Throwable ) errors.get( 0 ) );
+			}
+			add( doc );
+			return this;
+		}
+		catch ( InvalidMappingException e ) {
+			throw e;
+		}
+		catch  ( MappingNotFoundException e ) {
+			throw e;
+		}
+		catch ( Exception e ) {
+			throw new InvalidMappingException( "file", xmlFile.toString(), e );
+		}
+	}
+
+	/**
+	 * Add a cached mapping file.  A cached file is a serialized representation
+	 * of the DOM structure of a particular mapping.  It is saved from a previous
+	 * call as a file with the name <tt>xmlFile + ".bin"</tt> where xmlFile is
+	 * the name of the original mapping file.
+	 * </p>
+	 * If a cached <tt>xmlFile + ".bin"</tt> exists and is newer than
+	 * <tt>xmlFile</tt> the <tt>".bin"</tt> file will be read directly. Otherwise
+	 * xmlFile is read and then serialized to <tt>xmlFile + ".bin"</tt> for use
+	 * the next time.
+	 *
+	 * @param xmlFile The cacheable mapping file to be added.
+	 * @return this (for method chaining purposes)
+	 * @throws MappingException Indicates problems reading the cached file or processing
+	 * the non-cached file.
+	 */
+	public Configuration addCacheableFile(File xmlFile) throws MappingException {
+		try {
+			File cachedFile = new File( xmlFile.getAbsolutePath() + ".bin" );
+			org.dom4j.Document doc = null;
+
+			final boolean useCachedFile = xmlFile.exists() &&
+					cachedFile.exists() &&
+					xmlFile.lastModified() < cachedFile.lastModified();
+
+			if ( useCachedFile ) {
+				try {
+					log.info( "Reading mappings from cache file: " + cachedFile );
+					doc = ( org.dom4j.Document ) SerializationHelper.deserialize( new FileInputStream( cachedFile ) );
+				}
+				catch ( SerializationException e ) {
+					log.warn( "Could not deserialize cache file: " + cachedFile.getPath(), e );
+				}
+				catch ( FileNotFoundException e ) {
+					log.warn( "I/O reported cached file could not be found : " + cachedFile.getPath(), e );
+				}
+			}
+
+			// if doc is null, then for whatever reason, the cached file cannot be used...
+			if ( doc == null ) {
+				if ( !xmlFile.exists() ) {
+					throw new MappingNotFoundException( "file", xmlFile.toString() );
+				}
+
+				log.info( "Reading mappings from file: " + xmlFile );
+				List errors = new ArrayList();
+				try {
+					doc = xmlHelper.createSAXReader( xmlFile.getAbsolutePath(), errors, entityResolver ).read( xmlFile );
+					if ( errors.size() != 0 ) {
+						throw new MappingException( "invalid mapping", ( Throwable ) errors.get( 0 ) );
+					}
+				}
+				catch( DocumentException e){
+					throw new MappingException( "invalid mapping", e );
+				}
+
+				try {
+					log.debug( "Writing cache file for: " + xmlFile + " to: " + cachedFile );
+					SerializationHelper.serialize( ( Serializable ) doc, new FileOutputStream( cachedFile ) );
+				}
+				catch ( SerializationException e ) {
+					log.warn( "Could not write cached file: " + cachedFile, e );
+				}
+				catch ( FileNotFoundException e ) {
+					log.warn( "I/O reported error writing cached file : " + cachedFile.getPath(), e );
+				}
+			}
+
+			add( doc );
+			return this;
+
+		}
+		catch ( InvalidMappingException e ) {
+			throw e;
+		}
+		catch  ( MappingNotFoundException e ) {
+			throw e;
+		}
+		catch ( Exception e ) {
+			throw new InvalidMappingException( "file", xmlFile.toString(), e );
+		}
+	}
+
+	/**
+	 * Add a cacheable mapping file.
+	 *
+	 * @param xmlFile The name of the file to be added.  This must be in a form
+	 * useable to simply construct a {@link java.io.File} instance.
+	 * @return this (for method chaining purposes)
+	 * @throws MappingException Indicates problems reading the cached file or processing
+	 * the non-cached file.
+	 * @see #addCacheableFile(java.io.File)
+	 */
+	public Configuration addCacheableFile(String xmlFile) throws MappingException {
+		return addCacheableFile( new File( xmlFile ) );
+	}
+
+
+	/**
+	 * Read mappings from a <tt>String</tt>
+	 *
+	 * @param xml an XML string
+	 * @return this (for method chaining purposes)
+	 * @throws org.hibernate.MappingException Indicates problems parsing the
+	 * given XML string
+	 */
+	public Configuration addXML(String xml) throws MappingException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Mapping XML:\n" + xml );
+		}
+		try {
+			List errors = new ArrayList();
+			org.dom4j.Document doc = xmlHelper.createSAXReader( "XML String", errors, entityResolver )
+					.read( new StringReader( xml ) );
+			if ( errors.size() != 0 ) {
+				throw new MappingException( "invalid mapping", (Throwable) errors.get( 0 ) );
+			}
+			add( doc );
+		}
+		catch (DocumentException e) {
+			throw new MappingException( "Could not parse mapping document in XML string", e );
+		}
+		return this;
+	}
+
+	/**
+	 * Read mappings from a <tt>URL</tt>
+	 *
+	 * @param url The url for the mapping document to be read.
+	 * @return this (for method chaining purposes)
+	 * @throws MappingException Indicates problems reading the URL or processing
+	 * the mapping document.
+	 */
+	public Configuration addURL(URL url) throws MappingException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Reading mapping document from URL:" + url.toExternalForm() );
+		}
+		try {
+			addInputStream( url.openStream() );
+		}
+		catch ( InvalidMappingException e ) {
+			throw new InvalidMappingException( "URL", url.toExternalForm(), e.getCause() );
+		}
+		catch (Exception e) {
+			throw new InvalidMappingException( "URL", url.toExternalForm(), e );
+		}
+		return this;
+	}
+
+	/**
+	 * Read mappings from a DOM <tt>Document</tt>
+	 *
+	 * @param doc The DOM document
+	 * @return this (for method chaining purposes)
+	 * @throws MappingException Indicates problems reading the DOM or processing
+	 * the mapping document.
+	 */
+	public Configuration addDocument(Document doc) throws MappingException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Mapping document:\n" + doc );
+		}
+		add( xmlHelper.createDOMReader().read( doc ) );
+		return this;
+	}
+
+	/**
+	 * Read mappings from an {@link java.io.InputStream}.
+	 *
+	 * @param xmlInputStream The input stream containing a DOM.
+	 * @return this (for method chaining purposes)
+	 * @throws MappingException Indicates problems reading the stream, or
+	 * processing the contained mapping document.
+	 */
+	public Configuration addInputStream(InputStream xmlInputStream) throws MappingException {
+		try {
+			List errors = new ArrayList();
+			org.dom4j.Document doc = xmlHelper.createSAXReader( "XML InputStream", errors, entityResolver )
+					.read( new InputSource( xmlInputStream ) );
+			if ( errors.size() != 0 ) {
+				throw new InvalidMappingException( "invalid mapping", null, (Throwable) errors.get( 0 ) );
+			}
+			add( doc );
+			return this;
+		}
+		catch (DocumentException e) {
+			throw new InvalidMappingException( "input stream", null, e );
+		}
+		finally {
+			try {
+				xmlInputStream.close();
+			}
+			catch (IOException ioe) {
+				log.warn( "Could not close input stream", ioe );
+			}
+		}
+	}
+
+	/**
+	 * Read mappings as a application resource (i.e. classpath lookup).
+	 *
+	 * @param resourceName The resource name
+	 * @param classLoader The class loader to use.
+	 * @return this (for method chaining purposes)
+	 * @throws MappingException Indicates problems locating the resource or
+	 * processing the contained mapping document.
+	 */
+	public Configuration addResource(String resourceName, ClassLoader classLoader) throws MappingException {
+		log.info( "Reading mappings from resource: " + resourceName );
+		InputStream rsrc = classLoader.getResourceAsStream( resourceName );
+		if ( rsrc == null ) {
+			throw new MappingNotFoundException( "resource", resourceName );
+		}
+		try {
+			return addInputStream( rsrc );
+		}
+		catch (MappingException me) {
+			throw new InvalidMappingException( "resource", resourceName, me );
+		}
+	}
+
+	/**
+	 * Read mappings as a application resourceName (i.e. classpath lookup)
+	 * trying different classloaders.
+	 *
+	 * @param resourceName The resource name
+	 * @return this (for method chaining purposes)
+	 * @throws MappingException Indicates problems locating the resource or
+	 * processing the contained mapping document.
+	 */
+	public Configuration addResource(String resourceName) throws MappingException {
+		log.info( "Reading mappings from resource : " + resourceName );
+		ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+		InputStream rsrc = null;
+		if (contextClassLoader!=null) {
+			rsrc = contextClassLoader.getResourceAsStream( resourceName );
+		}
+		if ( rsrc == null ) {
+			rsrc = Environment.class.getClassLoader().getResourceAsStream( resourceName );
+		}
+		if ( rsrc == null ) {
+			throw new MappingNotFoundException( "resource", resourceName );
+		}
+		try {
+			return addInputStream( rsrc );
+		}
+		catch (MappingException me) {
+			throw new InvalidMappingException( "resource", resourceName, me );
+		}
+	}
+
+	/**
+	 * Read a mapping as an application resouurce using the convention that a class
+	 * named <tt>foo.bar.Foo</tt> is mapped by a file <tt>foo/bar/Foo.hbm.xml</tt>
+	 * which can be resolved as a classpath resource.
+	 *
+	 * @param persistentClass The mapped class
+	 * @return this (for method chaining purposes)
+	 * @throws MappingException Indicates problems locating the resource or
+	 * processing the contained mapping document.
+	 */
+	public Configuration addClass(Class persistentClass) throws MappingException {
+		String mappingResourceName = persistentClass.getName().replace( '.', '/' ) + ".hbm.xml";
+		log.info( "Reading mappings from resource: " + mappingResourceName );
+		return addResource( mappingResourceName, persistentClass.getClassLoader() );
+	}
+
+	/**
+	 * Read all mappings from a jar file
+	 * <p/>
+	 * Assumes that any file named <tt>*.hbm.xml</tt> is a mapping document.
+	 *
+	 * @param jar a jar file
+	 * @return this (for method chaining purposes)
+	 * @throws MappingException Indicates problems reading the jar file or
+	 * processing the contained mapping documents.
+	 */
+	public Configuration addJar(File jar) throws MappingException {
+		log.info( "Searching for mapping documents in jar: " + jar.getName() );
+		JarFile jarFile = null;
+		try {
+			try {
+				jarFile = new JarFile( jar );
+			}
+			catch (IOException ioe) {
+				throw new InvalidMappingException(
+						"Could not read mapping documents from jar: " + jar.getName(), "jar", jar.getName(),
+						ioe
+				);
+			}
+			Enumeration jarEntries = jarFile.entries();
+			while ( jarEntries.hasMoreElements() ) {
+				ZipEntry ze = (ZipEntry) jarEntries.nextElement();
+				if ( ze.getName().endsWith( ".hbm.xml" ) ) {
+					log.info( "Found mapping document in jar: " + ze.getName() );
+					try {
+						addInputStream( jarFile.getInputStream( ze ) );
+					}
+					catch (Exception e) {
+						throw new InvalidMappingException(
+								"Could not read mapping documents from jar: " + jar.getName(),
+								"jar",
+								jar.getName(),
+								e
+						);
+					}
+				}
+			}
+		}
+		finally {
+			try {
+				if ( jarFile != null ) {
+					jarFile.close();
+				}
+			}
+			catch (IOException ioe) {
+				log.error("could not close jar", ioe);
+			}
+		}
+
+		return this;
+	}
+
+	/**
+	 * Read all mapping documents from a directory tree.
+	 * <p/>
+	 * Assumes that any file named <tt>*.hbm.xml</tt> is a mapping document.
+	 *
+	 * @param dir The directory
+	 * @return this (for method chaining purposes)
+	 * @throws MappingException Indicates problems reading the jar file or
+	 * processing the contained mapping documents.
+	 */
+	public Configuration addDirectory(File dir) throws MappingException {
+		File[] files = dir.listFiles();
+		for ( int i = 0; i < files.length ; i++ ) {
+			if ( files[i].isDirectory() ) {
+				addDirectory( files[i] );
+			}
+			else if ( files[i].getName().endsWith( ".hbm.xml" ) ) {
+				addFile( files[i] );
+			}
+		}
+		return this;
+	}
+
+	protected void add(org.dom4j.Document doc) throws MappingException {
+		HbmBinder.bindRoot( doc, createMappings(), CollectionHelper.EMPTY_MAP );
+	}
+
+	/**
+	 * Create a new <tt>Mappings</tt> to add class and collection
+	 * mappings to.
+	 */
+	public Mappings createMappings() {
+		return new Mappings(
+				classes,
+				collections,
+				tables,
+				namedQueries,
+				namedSqlQueries,
+				sqlResultSetMappings,
+				imports,
+				secondPasses,
+				propertyReferences,
+				namingStrategy,
+				typeDefs,
+				filterDefinitions,
+				extendsQueue,
+				auxiliaryDatabaseObjects,
+				tableNameBinding,
+				columnNameBindingPerTable
+			);
+	}
+
+
+	private Iterator iterateGenerators(Dialect dialect) throws MappingException {
+
+		TreeMap generators = new TreeMap();
+		String defaultCatalog = properties.getProperty( Environment.DEFAULT_CATALOG );
+		String defaultSchema = properties.getProperty( Environment.DEFAULT_SCHEMA );
+
+		Iterator iter = classes.values().iterator();
+		while ( iter.hasNext() ) {
+			PersistentClass pc = (PersistentClass) iter.next();
+
+			if ( !pc.isInherited() ) {
+
+				IdentifierGenerator ig = pc.getIdentifier()
+						.createIdentifierGenerator(
+								dialect,
+								defaultCatalog,
+								defaultSchema,
+								(RootClass) pc
+							);
+
+				if ( ig instanceof PersistentIdentifierGenerator ) {
+					generators.put( ( (PersistentIdentifierGenerator) ig ).generatorKey(), ig );
+				}
+
+			}
+		}
+
+		iter = collections.values().iterator();
+		while ( iter.hasNext() ) {
+			Collection collection = (Collection) iter.next();
+
+			if ( collection.isIdentified() ) {
+
+				IdentifierGenerator ig = ( (IdentifierCollection) collection ).getIdentifier()
+						.createIdentifierGenerator(
+								dialect,
+								defaultCatalog,
+								defaultSchema,
+								null
+							);
+
+				if ( ig instanceof PersistentIdentifierGenerator ) {
+					generators.put( ( (PersistentIdentifierGenerator) ig ).generatorKey(), ig );
+				}
+
+			}
+		}
+
+		return generators.values().iterator();
+	}
+
+	/**
+	 * Generate DDL for dropping tables
+	 *
+	 * @see org.hibernate.tool.hbm2ddl.SchemaExport
+	 */
+	public String[] generateDropSchemaScript(Dialect dialect) throws HibernateException {
+
+		secondPassCompile();
+
+		String defaultCatalog = properties.getProperty( Environment.DEFAULT_CATALOG );
+		String defaultSchema = properties.getProperty( Environment.DEFAULT_SCHEMA );
+
+		ArrayList script = new ArrayList( 50 );
+
+		// drop them in reverse order in case db needs it done that way...
+		ListIterator itr = auxiliaryDatabaseObjects.listIterator( auxiliaryDatabaseObjects.size() );
+		while ( itr.hasPrevious() ) {
+			AuxiliaryDatabaseObject object = (AuxiliaryDatabaseObject) itr.previous();
+			if ( object.appliesToDialect( dialect ) ) {
+				script.add( object.sqlDropString( dialect, defaultCatalog, defaultSchema ) );
+			}
+		}
+
+		if ( dialect.dropConstraints() ) {
+			Iterator iter = getTableMappings();
+			while ( iter.hasNext() ) {
+				Table table = (Table) iter.next();
+				if ( table.isPhysicalTable() ) {
+					Iterator subIter = table.getForeignKeyIterator();
+					while ( subIter.hasNext() ) {
+						ForeignKey fk = (ForeignKey) subIter.next();
+						if ( fk.isPhysicalConstraint() ) {
+							script.add(
+									fk.sqlDropString(
+											dialect,
+											defaultCatalog,
+											defaultSchema
+										)
+								);
+						}
+					}
+				}
+			}
+		}
+
+
+		Iterator iter = getTableMappings();
+		while ( iter.hasNext() ) {
+
+			Table table = (Table) iter.next();
+			if ( table.isPhysicalTable() ) {
+
+				/*Iterator subIter = table.getIndexIterator();
+				while ( subIter.hasNext() ) {
+					Index index = (Index) subIter.next();
+					if ( !index.isForeignKey() || !dialect.hasImplicitIndexForForeignKey() ) {
+						script.add( index.sqlDropString(dialect) );
+					}
+				}*/
+
+				script.add(
+						table.sqlDropString(
+								dialect,
+								defaultCatalog,
+								defaultSchema
+							)
+					);
+
+			}
+
+		}
+
+		iter = iterateGenerators( dialect );
+		while ( iter.hasNext() ) {
+			String[] lines = ( (PersistentIdentifierGenerator) iter.next() ).sqlDropStrings( dialect );
+			for ( int i = 0; i < lines.length ; i++ ) {
+				script.add( lines[i] );
+			}
+		}
+
+		return ArrayHelper.toStringArray( script );
+	}
+
+	/**
+	 * Generate DDL for creating tables
+	 *
+	 * @see org.hibernate.tool.hbm2ddl.SchemaExport
+	 */
+	public String[] generateSchemaCreationScript(Dialect dialect) throws HibernateException {
+		secondPassCompile();
+
+		ArrayList script = new ArrayList( 50 );
+		String defaultCatalog = properties.getProperty( Environment.DEFAULT_CATALOG );
+		String defaultSchema = properties.getProperty( Environment.DEFAULT_SCHEMA );
+
+		Iterator iter = getTableMappings();
+		while ( iter.hasNext() ) {
+			Table table = (Table) iter.next();
+			if ( table.isPhysicalTable() ) {
+				script.add(
+						table.sqlCreateString(
+								dialect,
+								mapping,
+								defaultCatalog,
+								defaultSchema
+							)
+					);
+				Iterator comments = table.sqlCommentStrings( dialect, defaultCatalog, defaultSchema );
+				while ( comments.hasNext() ) {
+					script.add( comments.next() );
+				}
+			}
+		}
+
+		iter = getTableMappings();
+		while ( iter.hasNext() ) {
+			Table table = (Table) iter.next();
+			if ( table.isPhysicalTable() ) {
+
+				if ( !dialect.supportsUniqueConstraintInCreateAlterTable() ) {
+					Iterator subIter = table.getUniqueKeyIterator();
+					while ( subIter.hasNext() ) {
+						UniqueKey uk = (UniqueKey) subIter.next();
+						String constraintString = uk.sqlCreateString( dialect, mapping, defaultCatalog, defaultSchema );
+						if (constraintString != null) script.add( constraintString );
+					}
+				}
+
+
+				Iterator subIter = table.getIndexIterator();
+				while ( subIter.hasNext() ) {
+					Index index = (Index) subIter.next();
+					script.add(
+							index.sqlCreateString(
+									dialect,
+									mapping,
+									defaultCatalog,
+									defaultSchema
+								)
+						);
+				}
+
+				if ( dialect.hasAlterTable() ) {
+					subIter = table.getForeignKeyIterator();
+					while ( subIter.hasNext() ) {
+						ForeignKey fk = (ForeignKey) subIter.next();
+						if ( fk.isPhysicalConstraint() ) {
+							script.add(
+									fk.sqlCreateString(
+											dialect, mapping,
+											defaultCatalog,
+											defaultSchema
+										)
+								);
+						}
+					}
+				}
+
+			}
+		}
+
+		iter = iterateGenerators( dialect );
+		while ( iter.hasNext() ) {
+			String[] lines = ( (PersistentIdentifierGenerator) iter.next() ).sqlCreateStrings( dialect );
+			for ( int i = 0; i < lines.length ; i++ ) {
+				script.add( lines[i] );
+			}
+		}
+
+		Iterator itr = auxiliaryDatabaseObjects.iterator();
+		while ( itr.hasNext() ) {
+			AuxiliaryDatabaseObject object = (AuxiliaryDatabaseObject) itr.next();
+			if ( object.appliesToDialect( dialect ) ) {
+				script.add( object.sqlCreateString( dialect, mapping, defaultCatalog, defaultSchema ) );
+			}
+		}
+
+		return ArrayHelper.toStringArray( script );
+	}
+
+	/**
+	 * Generate DDL for altering tables
+	 *
+	 * @see org.hibernate.tool.hbm2ddl.SchemaUpdate
+	 */
+	public String[] generateSchemaUpdateScript(Dialect dialect, DatabaseMetadata databaseMetadata)
+			throws HibernateException {
+		secondPassCompile();
+
+		String defaultCatalog = properties.getProperty( Environment.DEFAULT_CATALOG );
+		String defaultSchema = properties.getProperty( Environment.DEFAULT_SCHEMA );
+
+		ArrayList script = new ArrayList( 50 );
+
+		Iterator iter = getTableMappings();
+		while ( iter.hasNext() ) {
+			Table table = (Table) iter.next();
+			if ( table.isPhysicalTable() ) {
+				
+				TableMetadata tableInfo = databaseMetadata.getTableMetadata(
+						table.getName(),
+						( table.getSchema() == null ) ? defaultSchema : table.getSchema(),
+						( table.getCatalog() == null ) ? defaultCatalog : table.getCatalog(),
+								table.isQuoted()
+
+					);
+				if ( tableInfo == null ) {
+					script.add(
+							table.sqlCreateString(
+									dialect,
+									mapping,
+									defaultCatalog,
+									defaultSchema
+								)
+						);
+				}
+				else {
+					Iterator subiter = table.sqlAlterStrings(
+							dialect,
+							mapping,
+							tableInfo,
+							defaultCatalog,
+							defaultSchema
+						);
+					while ( subiter.hasNext() ) {
+						script.add( subiter.next() );
+					}
+				}
+
+				Iterator comments = table.sqlCommentStrings( dialect, defaultCatalog, defaultSchema );
+				while ( comments.hasNext() ) {
+					script.add( comments.next() );
+				}
+
+			}
+		}
+
+		iter = getTableMappings();
+		while ( iter.hasNext() ) {
+			Table table = (Table) iter.next();
+			if ( table.isPhysicalTable() ) {
+
+				TableMetadata tableInfo = databaseMetadata.getTableMetadata(
+						table.getName(),
+						table.getSchema(),
+						table.getCatalog(),
+						table.isQuoted()
+					);
+
+				if ( dialect.hasAlterTable() ) {
+					Iterator subIter = table.getForeignKeyIterator();
+					while ( subIter.hasNext() ) {
+						ForeignKey fk = (ForeignKey) subIter.next();
+						if ( fk.isPhysicalConstraint() ) {
+							boolean create = tableInfo == null || (
+									tableInfo.getForeignKeyMetadata( fk.getName() ) == null && (
+											//Icky workaround for MySQL bug:
+											!( dialect instanceof MySQLDialect ) ||
+													tableInfo.getIndexMetadata( fk.getName() ) == null
+										)
+								);
+							if ( create ) {
+								script.add(
+										fk.sqlCreateString(
+												dialect,
+												mapping,
+												defaultCatalog,
+												defaultSchema
+											)
+									);
+							}
+						}
+					}
+				}
+
+			}
+
+			/*//broken, 'cos we don't generate these with names in SchemaExport
+			subIter = table.getIndexIterator();
+			while ( subIter.hasNext() ) {
+				Index index = (Index) subIter.next();
+				if ( !index.isForeignKey() || !dialect.hasImplicitIndexForForeignKey() ) {
+					if ( tableInfo==null || tableInfo.getIndexMetadata( index.getFilterName() ) == null ) {
+						script.add( index.sqlCreateString(dialect, mapping) );
+					}
+				}
+			}
+			//broken, 'cos we don't generate these with names in SchemaExport
+			subIter = table.getUniqueKeyIterator();
+			while ( subIter.hasNext() ) {
+				UniqueKey uk = (UniqueKey) subIter.next();
+				if ( tableInfo==null || tableInfo.getIndexMetadata( uk.getFilterName() ) == null ) {
+					script.add( uk.sqlCreateString(dialect, mapping) );
+				}
+			}*/
+		}
+
+		iter = iterateGenerators( dialect );
+		while ( iter.hasNext() ) {
+			PersistentIdentifierGenerator generator = (PersistentIdentifierGenerator) iter.next();
+			Object key = generator.generatorKey();
+			if ( !databaseMetadata.isSequence( key ) && !databaseMetadata.isTable( key ) ) {
+				String[] lines = generator.sqlCreateStrings( dialect );
+				for ( int i = 0; i < lines.length ; i++ ) {
+					script.add( lines[i] );
+				}
+			}
+		}
+
+		return ArrayHelper.toStringArray( script );
+	}
+
+	public void validateSchema(Dialect dialect, DatabaseMetadata databaseMetadata)
+			throws HibernateException {
+		secondPassCompile();
+
+		String defaultCatalog = properties.getProperty( Environment.DEFAULT_CATALOG );
+		String defaultSchema = properties.getProperty( Environment.DEFAULT_SCHEMA );
+		
+		Iterator iter = getTableMappings();
+		while ( iter.hasNext() ) {
+			Table table = (Table) iter.next();
+			if ( table.isPhysicalTable() ) {
+				
+
+				TableMetadata tableInfo = databaseMetadata.getTableMetadata(
+						table.getName(),
+						( table.getSchema() == null ) ? defaultSchema : table.getSchema(),
+						( table.getCatalog() == null ) ? defaultCatalog : table.getCatalog(),
+								table.isQuoted());
+				if ( tableInfo == null ) {
+					throw new HibernateException( "Missing table: " + table.getName() );
+				}
+				else {
+					table.validateColumns( dialect, mapping, tableInfo );
+				}
+
+			}
+		}
+
+		iter = iterateGenerators( dialect );
+		while ( iter.hasNext() ) {
+			PersistentIdentifierGenerator generator = (PersistentIdentifierGenerator) iter.next();
+			Object key = generator.generatorKey();
+			if ( !databaseMetadata.isSequence( key ) && !databaseMetadata.isTable( key ) ) {
+				throw new HibernateException( "Missing sequence or table: " + key );
+			}
+		}
+	}
+
+	private void validate() throws MappingException {
+		Iterator iter = classes.values().iterator();
+		while ( iter.hasNext() ) {
+			( (PersistentClass) iter.next() ).validate( mapping );
+		}
+		iter = collections.values().iterator();
+		while ( iter.hasNext() ) {
+			( (Collection) iter.next() ).validate( mapping );
+		}
+	}
+
+	/**
+	 * Call this to ensure the mappings are fully compiled/built. Usefull to ensure getting
+	 * access to all information in the metamodel when calling e.g. getClassMappings().
+	 */
+	public void buildMappings() {
+		secondPassCompile();
+	}
+
+	// This method may be called many times!!
+	protected void secondPassCompile() throws MappingException {
+		log.debug( "processing extends queue" );
+
+		processExtendsQueue();
+
+		log.debug( "processing collection mappings" );
+
+		Iterator iter = secondPasses.iterator();
+		while ( iter.hasNext() ) {
+			SecondPass sp = (SecondPass) iter.next();
+			if ( ! (sp instanceof QuerySecondPass) ) {
+				sp.doSecondPass( classes );
+				iter.remove();
+			}
+		}
+
+		log.debug( "processing native query and ResultSetMapping mappings" );
+		iter = secondPasses.iterator();
+		while ( iter.hasNext() ) {
+			SecondPass sp = (SecondPass) iter.next();
+			sp.doSecondPass( classes );
+			iter.remove();
+		}
+
+		log.debug( "processing association property references" );
+
+		iter = propertyReferences.iterator();
+		while ( iter.hasNext() ) {
+			Mappings.PropertyReference upr = (Mappings.PropertyReference) iter.next();
+
+			PersistentClass clazz = getClassMapping( upr.referencedClass );
+			if ( clazz == null ) {
+				throw new MappingException(
+						"property-ref to unmapped class: " +
+						upr.referencedClass
+					);
+			}
+
+			Property prop = clazz.getReferencedProperty( upr.propertyName );
+			if ( upr.unique ) {
+				( (SimpleValue) prop.getValue() ).setAlternateUniqueKey( true );
+			}
+		}
+
+		//TODO: Somehow add the newly created foreign keys to the internal collection
+
+		log.debug( "processing foreign key constraints" );
+
+		iter = getTableMappings();
+		Set done = new HashSet();
+		while ( iter.hasNext() ) {
+			secondPassCompileForeignKeys( (Table) iter.next(), done );
+		}
+
+	}
+
+	/**
+	 * Try to empty the extends queue.
+	 */
+	private void processExtendsQueue() {
+		// todo : would love to have this work on a notification basis
+		//    where the successful binding of an entity/subclass would
+		//    emit a notification which the extendsQueue entries could
+		//    react to...
+		org.dom4j.Document document = findPossibleExtends();
+		while ( document != null ) {
+			add( document );
+			document = findPossibleExtends();
+		}
+
+		if ( extendsQueue.size() > 0 ) {
+//			Iterator iterator = extendsQueue.iterator();
+			Iterator iterator = extendsQueue.keySet().iterator();
+			StringBuffer buf = new StringBuffer( "Following superclasses referenced in extends not found: " );
+			while ( iterator.hasNext() ) {
+				final ExtendsQueueEntry entry = ( ExtendsQueueEntry ) iterator.next();
+				buf.append( entry.getExplicitName() );
+				if ( entry.getMappingPackage() != null ) {
+					buf.append( "[" ).append( entry.getMappingPackage() ).append( "]" );
+				}
+				if ( iterator.hasNext() ) {
+					buf.append( "," );
+				}
+			}
+			throw new MappingException( buf.toString() );
+		}
+	}
+
+	/**
+	 * Find the first possible element in the queue of extends.
+	 */
+	protected org.dom4j.Document findPossibleExtends() {
+//		Iterator iter = extendsQueue.iterator();
+		Iterator iter = extendsQueue.keySet().iterator();
+		while ( iter.hasNext() ) {
+			final ExtendsQueueEntry entry = ( ExtendsQueueEntry ) iter.next();
+			if ( getClassMapping( entry.getExplicitName() ) != null ) {
+				// found
+				iter.remove();
+				return entry.getDocument();
+			}
+			else if ( getClassMapping( HbmBinder.getClassName( entry.getExplicitName(), entry.getMappingPackage() ) ) != null ) {
+				// found
+				iter.remove();
+				return entry.getDocument();
+			}
+		}
+		return null;
+	}
+
+	protected void secondPassCompileForeignKeys(Table table, Set done) throws MappingException {
+
+		table.createForeignKeys();
+
+		Iterator iter = table.getForeignKeyIterator();
+		while ( iter.hasNext() ) {
+
+			ForeignKey fk = (ForeignKey) iter.next();
+			if ( !done.contains( fk ) ) {
+				done.add( fk );
+				final String referencedEntityName = fk.getReferencedEntityName();
+				if ( referencedEntityName == null ) {
+					throw new MappingException(
+							"An association from the table " +
+							fk.getTable().getName() +
+							" does not specify the referenced entity"
+						);
+				}
+				if ( log.isDebugEnabled() ) {
+					log.debug( "resolving reference to class: " + referencedEntityName );
+				}
+				PersistentClass referencedClass = (PersistentClass) classes.get( referencedEntityName );
+				if ( referencedClass == null ) {
+					throw new MappingException(
+							"An association from the table " +
+							fk.getTable().getName() +
+							" refers to an unmapped class: " +
+							referencedEntityName
+						);
+				}
+				if ( referencedClass.isJoinedSubclass() ) {
+					secondPassCompileForeignKeys( referencedClass.getSuperclass().getTable(), done );
+				}
+				fk.setReferencedTable( referencedClass.getTable() );
+				fk.alignColumns();
+			}
+		}
+	}
+
+	/**
+	 * Get the named queries
+	 */
+	public Map getNamedQueries() {
+		return namedQueries;
+	}
+
+	/**
+	 * Instantiate a new <tt>SessionFactory</tt>, using the properties and
+	 * mappings in this configuration. The <tt>SessionFactory</tt> will be
+	 * immutable, so changes made to the <tt>Configuration</tt> after
+	 * building the <tt>SessionFactory</tt> will not affect it.
+	 *
+	 * @return a new factory for <tt>Session</tt>s
+	 * @see org.hibernate.SessionFactory
+	 */
+	public SessionFactory buildSessionFactory() throws HibernateException {
+		log.debug( "Preparing to build session factory with filters : " + filterDefinitions );
+		secondPassCompile();
+		validate();
+		Environment.verifyProperties( properties );
+		Properties copy = new Properties();
+		copy.putAll( properties );
+		PropertiesHelper.resolvePlaceHolders( copy );
+		Settings settings = buildSettings( copy );
+
+		return new SessionFactoryImpl(
+				this,
+				mapping,
+				settings,
+				getInitializedEventListeners()
+			);
+	}
+
+	private EventListeners getInitializedEventListeners() {
+		EventListeners result = (EventListeners) eventListeners.shallowCopy();
+		result.initializeListeners( this );
+		return result;
+	}
+
+	/**
+	 * Return the configured <tt>Interceptor</tt>
+	 */
+	public Interceptor getInterceptor() {
+		return interceptor;
+	}
+
+	/**
+	 * Get all properties
+	 */
+	public Properties getProperties() {
+		return properties;
+	}
+
+	/**
+	 * Configure an <tt>Interceptor</tt>
+	 */
+	public Configuration setInterceptor(Interceptor interceptor) {
+		this.interceptor = interceptor;
+		return this;
+	}
+
+	/**
+	 * Specify a completely new set of properties
+	 */
+	public Configuration setProperties(Properties properties) {
+		this.properties = properties;
+		return this;
+	}
+
+	/**
+	 * Set the given properties
+	 */
+	public Configuration addProperties(Properties extraProperties) {
+		this.properties.putAll( extraProperties );
+		return this;
+	}
+
+	/**
+	 * Adds the incoming properties to the internap properties structure,
+	 * as long as the internal structure does not already contain an
+	 * entry for the given key.
+	 *
+	 * @param properties
+	 * @return this
+	 */
+	public Configuration mergeProperties(Properties properties) {
+		Iterator itr = properties.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			final Map.Entry entry = ( Map.Entry ) itr.next();
+			if ( this.properties.containsKey( entry.getKey() ) ) {
+				continue;
+			}
+			this.properties.setProperty( ( String ) entry.getKey(), ( String ) entry.getValue() );
+		}
+		return this;
+	}
+
+	/**
+	 * Set a property
+	 */
+	public Configuration setProperty(String propertyName, String value) {
+		properties.setProperty( propertyName, value );
+		return this;
+	}
+
+	/**
+	 * Get a property
+	 */
+	public String getProperty(String propertyName) {
+		return properties.getProperty( propertyName );
+	}
+
+	private void addProperties(Element parent) {
+		Iterator iter = parent.elementIterator( "property" );
+		while ( iter.hasNext() ) {
+			Element node = (Element) iter.next();
+			String name = node.attributeValue( "name" );
+			String value = node.getText().trim();
+			log.debug( name + "=" + value );
+			properties.setProperty( name, value );
+			if ( !name.startsWith( "hibernate" ) ) {
+				properties.setProperty( "hibernate." + name, value );
+			}
+		}
+		Environment.verifyProperties( properties );
+	}
+
+	/**
+	 * Get the configuration file as an <tt>InputStream</tt>. Might be overridden
+	 * by subclasses to allow the configuration to be located by some arbitrary
+	 * mechanism.
+	 */
+	protected InputStream getConfigurationInputStream(String resource) throws HibernateException {
+
+		log.info( "Configuration resource: " + resource );
+
+		return ConfigHelper.getResourceAsStream( resource );
+
+	}
+
+	/**
+	 * Use the mappings and properties specified in an application
+	 * resource named <tt>hibernate.cfg.xml</tt>.
+	 */
+	public Configuration configure() throws HibernateException {
+		configure( "/hibernate.cfg.xml" );
+		return this;
+	}
+
+	/**
+	 * Use the mappings and properties specified in the given application
+	 * resource. The format of the resource is defined in
+	 * <tt>hibernate-configuration-3.0.dtd</tt>.
+	 * <p/>
+	 * The resource is found via <tt>getConfigurationInputStream(resource)</tt>.
+	 */
+	public Configuration configure(String resource) throws HibernateException {
+		log.info( "configuring from resource: " + resource );
+		InputStream stream = getConfigurationInputStream( resource );
+		return doConfigure( stream, resource );
+	}
+
+	/**
+	 * Use the mappings and properties specified in the given document.
+	 * The format of the document is defined in
+	 * <tt>hibernate-configuration-3.0.dtd</tt>.
+	 *
+	 * @param url URL from which you wish to load the configuration
+	 * @return A configuration configured via the file
+	 * @throws HibernateException
+	 */
+	public Configuration configure(URL url) throws HibernateException {
+		log.info( "configuring from url: " + url.toString() );
+		try {
+			return doConfigure( url.openStream(), url.toString() );
+		}
+		catch (IOException ioe) {
+			throw new HibernateException( "could not configure from URL: " + url, ioe );
+		}
+	}
+
+	/**
+	 * Use the mappings and properties specified in the given application
+	 * file. The format of the file is defined in
+	 * <tt>hibernate-configuration-3.0.dtd</tt>.
+	 *
+	 * @param configFile <tt>File</tt> from which you wish to load the configuration
+	 * @return A configuration configured via the file
+	 * @throws HibernateException
+	 */
+	public Configuration configure(File configFile) throws HibernateException {
+		log.info( "configuring from file: " + configFile.getName() );
+		try {
+			return doConfigure( new FileInputStream( configFile ), configFile.toString() );
+		}
+		catch (FileNotFoundException fnfe) {
+			throw new HibernateException( "could not find file: " + configFile, fnfe );
+		}
+	}
+
+	/**
+	 * Use the mappings and properties specified in the given application
+	 * resource. The format of the resource is defined in
+	 * <tt>hibernate-configuration-3.0.dtd</tt>.
+	 *
+	 * @param stream	   Inputstream to be read from
+	 * @param resourceName The name to use in warning/error messages
+	 * @return A configuration configured via the stream
+	 * @throws HibernateException
+	 */
+	protected Configuration doConfigure(InputStream stream, String resourceName) throws HibernateException {
+
+		org.dom4j.Document doc;
+		try {
+			List errors = new ArrayList();
+			doc = xmlHelper.createSAXReader( resourceName, errors, entityResolver )
+					.read( new InputSource( stream ) );
+			if ( errors.size() != 0 ) {
+				throw new MappingException(
+						"invalid configuration",
+						(Throwable) errors.get( 0 )
+					);
+			}
+		}
+		catch (DocumentException e) {
+			throw new HibernateException(
+					"Could not parse configuration: " + resourceName,
+					e
+				);
+		}
+		finally {
+			try {
+				stream.close();
+			}
+			catch (IOException ioe) {
+				log.warn( "could not close input stream for: " + resourceName, ioe );
+			}
+		}
+
+		return doConfigure( doc );
+
+	}
+
+	/**
+	 * Use the mappings and properties specified in the given XML document.
+	 * The format of the file is defined in
+	 * <tt>hibernate-configuration-3.0.dtd</tt>.
+	 *
+	 * @param document an XML document from which you wish to load the configuration
+	 * @return A configuration configured via the <tt>Document</tt>
+	 * @throws HibernateException if there is problem in accessing the file.
+	 */
+	public Configuration configure(Document document) throws HibernateException {
+		log.info( "configuring from XML document" );
+		return doConfigure( xmlHelper.createDOMReader().read( document ) );
+	}
+
+	protected Configuration doConfigure(org.dom4j.Document doc) throws HibernateException {
+
+		Element sfNode = doc.getRootElement().element( "session-factory" );
+		String name = sfNode.attributeValue( "name" );
+		if ( name != null ) {
+			properties.setProperty( Environment.SESSION_FACTORY_NAME, name );
+		}
+		addProperties( sfNode );
+		parseSessionFactory( sfNode, name );
+
+		Element secNode = doc.getRootElement().element( "security" );
+		if ( secNode != null ) {
+			parseSecurity( secNode );
+		}
+
+		log.info( "Configured SessionFactory: " + name );
+		log.debug( "properties: " + properties );
+
+		return this;
+
+	}
+
+
+	private void parseSessionFactory(Element sfNode, String name) {
+		Iterator elements = sfNode.elementIterator();
+		while ( elements.hasNext() ) {
+			Element subelement = (Element) elements.next();
+			String subelementName = subelement.getName();
+			if ( "mapping".equals( subelementName ) ) {
+				parseMappingElement( subelement, name );
+			}
+			else if ( "class-cache".equals( subelementName ) ) {
+				String className = subelement.attributeValue( "class" );
+				Attribute regionNode = subelement.attribute( "region" );
+				final String region = ( regionNode == null ) ? className : regionNode.getValue();
+				boolean includeLazy = !"non-lazy".equals( subelement.attributeValue( "include" ) );
+				setCacheConcurrencyStrategy( className, subelement.attributeValue( "usage" ), region, includeLazy );
+			}
+			else if ( "collection-cache".equals( subelementName ) ) {
+				String role = subelement.attributeValue( "collection" );
+				Attribute regionNode = subelement.attribute( "region" );
+				final String region = ( regionNode == null ) ? role : regionNode.getValue();
+				setCollectionCacheConcurrencyStrategy( role, subelement.attributeValue( "usage" ), region );
+			}
+			else if ( "listener".equals( subelementName ) ) {
+				parseListener( subelement );
+			}
+			else if ( "event".equals( subelementName ) ) {
+				parseEvent( subelement );
+			}
+		}
+	}
+
+	protected void parseMappingElement(Element subelement, String name) {
+		Attribute rsrc = subelement.attribute( "resource" );
+		Attribute file = subelement.attribute( "file" );
+		Attribute jar = subelement.attribute( "jar" );
+		Attribute pkg = subelement.attribute( "package" );
+		Attribute clazz = subelement.attribute( "class" );
+		if ( rsrc != null ) {
+			log.debug( name + "<-" + rsrc );
+			addResource( rsrc.getValue() );
+		}
+		else if ( jar != null ) {
+			log.debug( name + "<-" + jar );
+			addJar( new File( jar.getValue() ) );
+		}
+		else if ( pkg != null ) {
+			throw new MappingException(
+					"An AnnotationConfiguration instance is required to use <mapping package=\"" +
+					pkg.getValue() + "\"/>"
+				);
+		}
+		else if ( clazz != null ) {
+			throw new MappingException(
+					"An AnnotationConfiguration instance is required to use <mapping class=\"" +
+					clazz.getValue() + "\"/>"
+				);
+		}
+		else {
+			if ( file == null ) {
+				throw new MappingException(
+						"<mapping> element in configuration specifies no attributes"
+					);
+			}
+			log.debug( name + "<-" + file );
+			addFile( file.getValue() );
+		}
+	}
+
+	private void parseSecurity(Element secNode) {
+		String contextId = secNode.attributeValue( "context" );
+      setProperty(Environment.JACC_CONTEXTID, contextId);
+		log.info( "JACC contextID: " + contextId );
+		JACCConfiguration jcfg = new JACCConfiguration( contextId );
+		Iterator grantElements = secNode.elementIterator();
+		while ( grantElements.hasNext() ) {
+			Element grantElement = (Element) grantElements.next();
+			String elementName = grantElement.getName();
+			if ( "grant".equals( elementName ) ) {
+				jcfg.addPermission(
+						grantElement.attributeValue( "role" ),
+						grantElement.attributeValue( "entity-name" ),
+						grantElement.attributeValue( "actions" )
+					);
+			}
+		}
+	}
+
+	private void parseEvent(Element element) {
+		String type = element.attributeValue( "type" );
+		List listeners = element.elements();
+		String[] listenerClasses = new String[ listeners.size() ];
+		for ( int i = 0; i < listeners.size() ; i++ ) {
+			listenerClasses[i] = ( (Element) listeners.get( i ) ).attributeValue( "class" );
+		}
+		log.debug( "Event listeners: " + type + "=" + StringHelper.toString( listenerClasses ) );
+		setListeners( type, listenerClasses );
+	}
+
+	private void parseListener(Element element) {
+		String type = element.attributeValue( "type" );
+		if ( type == null ) {
+			throw new MappingException( "No type specified for listener" );
+		}
+		String impl = element.attributeValue( "class" );
+		log.debug( "Event listener: " + type + "=" + impl );
+		setListeners( type, new String[]{impl} );
+	}
+
+	public void setListeners(String type, String[] listenerClasses) {
+		Object[] listeners = (Object[]) Array.newInstance( eventListeners.getListenerClassFor(type), listenerClasses.length );
+		for ( int i = 0; i < listeners.length ; i++ ) {
+			try {
+				listeners[i] = ReflectHelper.classForName( listenerClasses[i] ).newInstance();
+			}
+			catch (Exception e) {
+				throw new MappingException(
+						"Unable to instantiate specified event (" + type + ") listener class: " + listenerClasses[i],
+						e
+					);
+			}
+		}
+		setListeners( type, listeners );
+	}
+
+	public void setListener(String type, Object listener) {
+		if ( listener == null ) {
+			setListener( type, null );
+		}
+		else {
+			Object[] listeners = (Object[]) Array.newInstance( eventListeners.getListenerClassFor(type), 1 );
+			listeners[0] = listener;
+			setListeners( type, listeners );
+		}
+	}
+
+	public void setListeners(String type, Object[] listeners) {
+		if ( "auto-flush".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setAutoFlushEventListeners( new AutoFlushEventListener[]{} );
+			}
+			else {
+				eventListeners.setAutoFlushEventListeners( (AutoFlushEventListener[]) listeners );
+			}
+		}
+		else if ( "merge".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setMergeEventListeners( new MergeEventListener[]{} );
+			}
+			else {
+				eventListeners.setMergeEventListeners( (MergeEventListener[]) listeners );
+			}
+		}
+		else if ( "create".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setPersistEventListeners( new PersistEventListener[]{} );
+			}
+			else {
+				eventListeners.setPersistEventListeners( (PersistEventListener[]) listeners );
+			}
+		}
+		else if ( "create-onflush".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setPersistOnFlushEventListeners( new PersistEventListener[]{} );
+			}
+			else {
+				eventListeners.setPersistOnFlushEventListeners( (PersistEventListener[]) listeners );
+			}
+		}
+		else if ( "delete".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setDeleteEventListeners( new DeleteEventListener[]{} );
+			}
+			else {
+				eventListeners.setDeleteEventListeners( (DeleteEventListener[]) listeners );
+			}
+		}
+		else if ( "dirty-check".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setDirtyCheckEventListeners( new DirtyCheckEventListener[]{} );
+			}
+			else {
+				eventListeners.setDirtyCheckEventListeners( (DirtyCheckEventListener[]) listeners );
+			}
+		}
+		else if ( "evict".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setEvictEventListeners( new EvictEventListener[]{} );
+			}
+			else {
+				eventListeners.setEvictEventListeners( (EvictEventListener[]) listeners );
+			}
+		}
+		else if ( "flush".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setFlushEventListeners( new FlushEventListener[]{} );
+			}
+			else {
+				eventListeners.setFlushEventListeners( (FlushEventListener[]) listeners );
+			}
+		}
+		else if ( "flush-entity".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setFlushEntityEventListeners( new FlushEntityEventListener[]{} );
+			}
+			else {
+				eventListeners.setFlushEntityEventListeners( (FlushEntityEventListener[]) listeners );
+			}
+		}
+		else if ( "load".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setLoadEventListeners( new LoadEventListener[]{} );
+			}
+			else {
+				eventListeners.setLoadEventListeners( (LoadEventListener[]) listeners );
+			}
+		}
+		else if ( "load-collection".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setInitializeCollectionEventListeners(
+						new InitializeCollectionEventListener[]{}
+					);
+			}
+			else {
+				eventListeners.setInitializeCollectionEventListeners(
+						(InitializeCollectionEventListener[]) listeners
+					);
+			}
+		}
+		else if ( "lock".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setLockEventListeners( new LockEventListener[]{} );
+			}
+			else {
+				eventListeners.setLockEventListeners( (LockEventListener[]) listeners );
+			}
+		}
+		else if ( "refresh".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setRefreshEventListeners( new RefreshEventListener[]{} );
+			}
+			else {
+				eventListeners.setRefreshEventListeners( (RefreshEventListener[]) listeners );
+			}
+		}
+		else if ( "replicate".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setReplicateEventListeners( new ReplicateEventListener[]{} );
+			}
+			else {
+				eventListeners.setReplicateEventListeners( (ReplicateEventListener[]) listeners );
+			}
+		}
+		else if ( "save-update".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setSaveOrUpdateEventListeners( new SaveOrUpdateEventListener[]{} );
+			}
+			else {
+				eventListeners.setSaveOrUpdateEventListeners( (SaveOrUpdateEventListener[]) listeners );
+			}
+		}
+		else if ( "save".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setSaveEventListeners( new SaveOrUpdateEventListener[]{} );
+			}
+			else {
+				eventListeners.setSaveEventListeners( (SaveOrUpdateEventListener[]) listeners );
+			}
+		}
+		else if ( "update".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setUpdateEventListeners( new SaveOrUpdateEventListener[]{} );
+			}
+			else {
+				eventListeners.setUpdateEventListeners( (SaveOrUpdateEventListener[]) listeners );
+			}
+		}
+		else if ( "pre-load".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setPreLoadEventListeners( new PreLoadEventListener[]{} );
+			}
+			else {
+				eventListeners.setPreLoadEventListeners( (PreLoadEventListener[]) listeners );
+			}
+		}
+		else if ( "pre-update".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setPreUpdateEventListeners( new PreUpdateEventListener[]{} );
+			}
+			else {
+				eventListeners.setPreUpdateEventListeners( (PreUpdateEventListener[]) listeners );
+			}
+		}
+		else if ( "pre-delete".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setPreDeleteEventListeners( new PreDeleteEventListener[]{} );
+			}
+			else {
+				eventListeners.setPreDeleteEventListeners( (PreDeleteEventListener[]) listeners );
+			}
+		}
+		else if ( "pre-insert".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setPreInsertEventListeners( new PreInsertEventListener[]{} );
+			}
+			else {
+				eventListeners.setPreInsertEventListeners( (PreInsertEventListener[]) listeners );
+			}
+		}
+		else if ( "post-load".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setPostLoadEventListeners( new PostLoadEventListener[]{} );
+			}
+			else {
+				eventListeners.setPostLoadEventListeners( (PostLoadEventListener[]) listeners );
+			}
+		}
+		else if ( "post-update".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setPostUpdateEventListeners( new PostUpdateEventListener[]{} );
+			}
+			else {
+				eventListeners.setPostUpdateEventListeners( (PostUpdateEventListener[]) listeners );
+			}
+		}
+		else if ( "post-delete".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setPostDeleteEventListeners( new PostDeleteEventListener[]{} );
+			}
+			else {
+				eventListeners.setPostDeleteEventListeners( (PostDeleteEventListener[]) listeners );
+			}
+		}
+		else if ( "post-insert".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setPostInsertEventListeners( new PostInsertEventListener[]{} );
+			}
+			else {
+				eventListeners.setPostInsertEventListeners( (PostInsertEventListener[]) listeners );
+			}
+		}
+		else if ( "post-commit-update".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setPostCommitUpdateEventListeners(
+						new PostUpdateEventListener[]{}
+					);
+			}
+			else {
+				eventListeners.setPostCommitUpdateEventListeners( (PostUpdateEventListener[]) listeners );
+			}
+		}
+		else if ( "post-commit-delete".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setPostCommitDeleteEventListeners(
+						new PostDeleteEventListener[]{}
+					);
+			}
+			else {
+				eventListeners.setPostCommitDeleteEventListeners( (PostDeleteEventListener[]) listeners );
+			}
+		}
+		else if ( "post-commit-insert".equals( type ) ) {
+			if ( listeners == null ) {
+				eventListeners.setPostCommitInsertEventListeners(
+						new PostInsertEventListener[]{}
+				);
+			}
+			else {
+				eventListeners.setPostCommitInsertEventListeners( (PostInsertEventListener[]) listeners );
+			}
+		}
+		else {
+			log.warn( "Unrecognized listener type [" + type + "]" );
+		}
+	}
+
+	public EventListeners getEventListeners() {
+		return eventListeners;
+	}
+
+	RootClass getRootClassMapping(String clazz) throws MappingException {
+		try {
+			return (RootClass) getClassMapping( clazz );
+		}
+		catch (ClassCastException cce) {
+			throw new MappingException( "You may only specify a cache for root <class> mappings" );
+		}
+	}
+
+	/**
+	 * Set up a cache for an entity class
+	 *
+	 * @param clazz
+	 * @param concurrencyStrategy
+	 * @return Configuration
+	 * @throws MappingException
+	 */
+	public Configuration setCacheConcurrencyStrategy(String clazz, String concurrencyStrategy)
+			throws MappingException {
+		setCacheConcurrencyStrategy( clazz, concurrencyStrategy, clazz );
+		return this;
+	}
+
+	public void setCacheConcurrencyStrategy(String clazz, String concurrencyStrategy, String region)
+			throws MappingException {
+		setCacheConcurrencyStrategy( clazz, concurrencyStrategy, region, true );
+	}
+
+	void setCacheConcurrencyStrategy(String clazz, String concurrencyStrategy, String region, boolean includeLazy)
+			throws MappingException {
+		RootClass rootClass = getRootClassMapping( clazz );
+		if ( rootClass == null ) {
+			throw new MappingException( "Cannot cache an unknown entity: " + clazz );
+		}
+		rootClass.setCacheConcurrencyStrategy( concurrencyStrategy );
+		rootClass.setCacheRegionName( region );
+		rootClass.setLazyPropertiesCacheable( includeLazy );
+	}
+
+	/**
+	 * Set up a cache for a collection role
+	 *
+	 * @param collectionRole
+	 * @param concurrencyStrategy
+	 * @return Configuration
+	 * @throws MappingException
+	 */
+	public Configuration setCollectionCacheConcurrencyStrategy(String collectionRole, String concurrencyStrategy)
+			throws MappingException {
+		setCollectionCacheConcurrencyStrategy( collectionRole, concurrencyStrategy, collectionRole );
+		return this;
+	}
+
+	public void setCollectionCacheConcurrencyStrategy(String collectionRole, String concurrencyStrategy, String region)
+			throws MappingException {
+		Collection collection = getCollectionMapping( collectionRole );
+		if ( collection == null ) {
+			throw new MappingException( "Cannot cache an unknown collection: " + collectionRole );
+		}
+		collection.setCacheConcurrencyStrategy( concurrencyStrategy );
+		collection.setCacheRegionName( region );
+	}
+
+	/**
+	 * Get the query language imports
+	 *
+	 * @return a mapping from "import" names to fully qualified class names
+	 */
+	public Map getImports() {
+		return imports;
+	}
+
+	/**
+	 * Create an object-oriented view of the configuration properties
+	 */
+	public Settings buildSettings() throws HibernateException {
+		Properties clone = ( Properties ) properties.clone();
+		PropertiesHelper.resolvePlaceHolders( clone );
+		return settingsFactory.buildSettings( clone );
+	}
+
+	public Settings buildSettings(Properties props) throws HibernateException {
+		return settingsFactory.buildSettings( props );
+	}
+
+	public Map getNamedSQLQueries() {
+		return namedSqlQueries;
+	}
+
+	public Map getSqlResultSetMappings() {
+		return sqlResultSetMappings;
+	}
+
+	/**
+	 * @return the NamingStrategy.
+	 */
+	public NamingStrategy getNamingStrategy() {
+		return namingStrategy;
+	}
+
+	/**
+	 * Set a custom naming strategy
+	 *
+	 * @param namingStrategy the NamingStrategy to set
+	 */
+	public Configuration setNamingStrategy(NamingStrategy namingStrategy) {
+		this.namingStrategy = namingStrategy;
+		return this;
+	}
+
+	public Mapping buildMapping() {
+		return new Mapping() {
+			/**
+			 * Returns the identifier type of a mapped class
+			 */
+			public Type getIdentifierType(String persistentClass) throws MappingException {
+				PersistentClass pc = ( (PersistentClass) classes.get( persistentClass ) );
+				if ( pc == null ) {
+					throw new MappingException( "persistent class not known: " + persistentClass );
+				}
+				return pc.getIdentifier().getType();
+			}
+
+			public String getIdentifierPropertyName(String persistentClass) throws MappingException {
+				final PersistentClass pc = (PersistentClass) classes.get( persistentClass );
+				if ( pc == null ) {
+					throw new MappingException( "persistent class not known: " + persistentClass );
+				}
+				if ( !pc.hasIdentifierProperty() ) {
+					return null;
+				}
+				return pc.getIdentifierProperty().getName();
+			}
+
+			public Type getReferencedPropertyType(String persistentClass, String propertyName) throws MappingException {
+				final PersistentClass pc = (PersistentClass) classes.get( persistentClass );
+				if ( pc == null ) {
+					throw new MappingException( "persistent class not known: " + persistentClass );
+				}
+				Property prop = pc.getReferencedProperty( propertyName );
+				if ( prop == null ) {
+					throw new MappingException(
+							"property not known: " +
+							persistentClass + '.' + propertyName
+						);
+				}
+				return prop.getType();
+			}
+		};
+	}
+
+	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+		ois.defaultReadObject();
+		this.mapping = buildMapping();
+		xmlHelper = new XMLHelper();
+	}
+
+	public Map getFilterDefinitions() {
+		return filterDefinitions;
+	}
+
+	public void addFilterDefinition(FilterDefinition definition) {
+		filterDefinitions.put( definition.getFilterName(), definition );
+	}
+
+	public void addAuxiliaryDatabaseObject(AuxiliaryDatabaseObject object) {
+		auxiliaryDatabaseObjects.add( object );
+	}
+
+	public Map getSqlFunctions() {
+		return sqlFunctions;
+	}
+
+	public void addSqlFunction(String functionName, SQLFunction function) {
+		sqlFunctions.put( functionName, function );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/DefaultNamingStrategy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/DefaultNamingStrategy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/DefaultNamingStrategy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,110 @@
+//$Id: DefaultNamingStrategy.java 9874 2006-05-04 15:10:22Z epbernard $
+package org.hibernate.cfg;
+
+import java.io.Serializable;
+
+import org.hibernate.util.StringHelper;
+import org.hibernate.AssertionFailure;
+
+/**
+ * The default <tt>NamingStrategy</tt>
+ * @see ImprovedNamingStrategy a better alternative
+ * @author Gavin King
+ */
+public class DefaultNamingStrategy implements NamingStrategy, Serializable {
+
+	/**
+	 * The singleton instance
+	 */
+	public static final NamingStrategy INSTANCE = new DefaultNamingStrategy();
+
+	/**
+	 * Return the unqualified class name
+	 */
+	public String classToTableName(String className) {
+		return StringHelper.unqualify(className);
+	}
+	/**
+	 * Return the unqualified property name
+	 */
+	public String propertyToColumnName(String propertyName) {
+		return StringHelper.unqualify(propertyName);
+	}
+	/**
+	 * Return the argument
+	 */
+	public String tableName(String tableName) {
+		return tableName;
+	}
+	/**
+	 * Return the argument
+	 */
+	public String columnName(String columnName) {
+		return columnName;
+	}
+
+	/**
+	 * Return the unqualified property name, not the best strategy but a backward compatible one
+	 */
+	public String collectionTableName(
+			String ownerEntity, String ownerEntityTable, String associatedEntity, String associatedEntityTable,
+			String propertyName
+	) {
+		//use a degenerated strategy for backward compatibility
+		return StringHelper.unqualify(propertyName);
+	}
+
+	/**
+	 * Return the argument
+	 */
+	public String joinKeyColumnName(String joinedColumn, String joinedTable) {
+		return columnName( joinedColumn );
+	}
+
+	/**
+	 * Return the property name or propertyTableName
+	 */
+	public String foreignKeyColumnName(
+			String propertyName, String propertyEntityName, String propertyTableName, String referencedColumnName
+	) {
+		String header = propertyName != null ? StringHelper.unqualify( propertyName ) : propertyTableName;
+		if (header == null) throw new AssertionFailure("NammingStrategy not properly filled");
+		return columnName( header ); //+ "_" + referencedColumnName not used for backward compatibility
+	}
+
+	/**
+	 * Return the column name or the unqualified property name
+	 */
+	public String logicalColumnName(String columnName, String propertyName) {
+		return StringHelper.isNotEmpty( columnName ) ? columnName : StringHelper.unqualify( propertyName );
+	}
+
+	/**
+	 * Returns either the table name if explicit or
+	 * if there is an associated table, the concatenation of owner entity table and associated table
+	 * otherwise the concatenation of owner entity table and the unqualified property name
+	 */
+	public String logicalCollectionTableName(String tableName,
+											 String ownerEntityTable, String associatedEntityTable, String propertyName
+	) {
+		if ( tableName != null ) {
+			return tableName;
+		}
+		else {
+			//use of a stringbuffer to workaround a JDK bug
+			return new StringBuffer(ownerEntityTable).append("_")
+					.append(
+						associatedEntityTable != null ?
+						associatedEntityTable :
+						StringHelper.unqualify( propertyName )
+					).toString();
+		}
+	}
+	/**
+	 * Return the column name if explicit or the concatenation of the property name and the referenced column
+	 *
+	 */
+	public String logicalCollectionColumnName(String columnName, String propertyName, String referencedColumn) {
+		return StringHelper.isNotEmpty( columnName ) ? columnName : propertyName + "_" + referencedColumn;
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Environment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Environment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Environment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,704 @@
+//$Id: Environment.java 11402 2007-04-11 14:24:35Z steve.ebersole at jboss.com $
+package org.hibernate.cfg;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.sql.Connection;
+import java.sql.Statement;
+import java.sql.Timestamp;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.bytecode.BytecodeProvider;
+import org.hibernate.util.ConfigHelper;
+import org.hibernate.util.PropertiesHelper;
+
+
+/**
+ * Provides access to configuration info passed in <tt>Properties</tt> objects.
+ * <br><br>
+ * Hibernate has two property scopes:
+ * <ul>
+ * <li><b>Factory-level</b> properties may be passed to the <tt>SessionFactory</tt> when it
+ * instantiated. Each instance might have different property values. If no
+ * properties are specified, the factory calls <tt>Environment.getProperties()</tt>.
+ * <li><b>System-level</b> properties are shared by all factory instances and are always
+ * determined by the <tt>Environment</tt> properties.
+ * </ul>
+ * The only system-level properties are
+ * <ul>
+ * <li><tt>hibernate.jdbc.use_streams_for_binary</tt>
+ * <li><tt>hibernate.cglib.use_reflection_optimizer</tt>
+ * </ul>
+ * <tt>Environment</tt> properties are populated by calling <tt>System.getProperties()</tt>
+ * and then from a resource named <tt>/hibernate.properties</tt> if it exists. System
+ * properties override properties specified in <tt>hibernate.properties</tt>.<br>
+ * <br>
+ * The <tt>SessionFactory</tt> is controlled by the following properties.
+ * Properties may be either be <tt>System</tt> properties, properties
+ * defined in a resource named <tt>/hibernate.properties</tt> or an instance of
+ * <tt>java.util.Properties</tt> passed to
+ * <tt>Configuration.buildSessionFactory()</tt><br>
+ * <br>
+ * <table>
+ * <tr><td><b>property</b></td><td><b>meaning</b></td></tr>
+ * <tr>
+ *   <td><tt>hibernate.dialect</tt></td>
+ *   <td>classname of <tt>org.hibernate.dialect.Dialect</tt> subclass</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.cache.provider_class</tt></td>
+ *   <td>classname of <tt>org.hibernate.cache.CacheProvider</tt>
+ *   subclass (if not specified EHCache is used)</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.connection.provider_class</tt></td>
+ *   <td>classname of <tt>org.hibernate.connection.ConnectionProvider</tt>
+ *   subclass (if not specified hueristics are used)</td>
+ * </tr>
+ * <tr><td><tt>hibernate.connection.username</tt></td><td>database username</td></tr>
+ * <tr><td><tt>hibernate.connection.password</tt></td><td>database password</td></tr>
+ * <tr>
+ *   <td><tt>hibernate.connection.url</tt></td>
+ *   <td>JDBC URL (when using <tt>java.sql.DriverManager</tt>)</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.connection.driver_class</tt></td>
+ *   <td>classname of JDBC driver</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.connection.isolation</tt></td>
+ *   <td>JDBC transaction isolation level (only when using
+ *     <tt>java.sql.DriverManager</tt>)
+ *   </td>
+ * </tr>
+ *   <td><tt>hibernate.connection.pool_size</tt></td>
+ *   <td>the maximum size of the connection pool (only when using
+ *     <tt>java.sql.DriverManager</tt>)
+ *   </td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.connection.datasource</tt></td>
+ *   <td>databasource JNDI name (when using <tt>javax.sql.Datasource</tt>)</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.jndi.url</tt></td><td>JNDI <tt>InitialContext</tt> URL</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.jndi.class</tt></td><td>JNDI <tt>InitialContext</tt> classname</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.max_fetch_depth</tt></td>
+ *   <td>maximum depth of outer join fetching</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.jdbc.batch_size</tt></td>
+ *   <td>enable use of JDBC2 batch API for drivers which support it</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.jdbc.fetch_size</tt></td>
+ *   <td>set the JDBC fetch size</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.jdbc.use_scrollable_resultset</tt></td>
+ *   <td>enable use of JDBC2 scrollable resultsets (you only need this specify
+ *   this property when using user supplied connections)</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.jdbc.use_getGeneratedKeys</tt></td>
+ *   <td>enable use of JDBC3 PreparedStatement.getGeneratedKeys() to retrieve
+ *   natively generated keys after insert. Requires JDBC3+ driver and JRE1.4+</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.hbm2ddl.auto</tt></td>
+ *   <td>enable auto DDL export</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.default_schema</tt></td>
+ *   <td>use given schema name for unqualified tables (always optional)</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.default_catalog</tt></td>
+ *   <td>use given catalog name for unqualified tables (always optional)</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.session_factory_name</tt></td>
+ *   <td>If set, the factory attempts to bind this name to itself in the
+ *   JNDI context. This name is also used to support cross JVM <tt>
+ *   Session</tt> (de)serialization.</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.transaction.manager_lookup_class</tt></td>
+ *   <td>classname of <tt>org.hibernate.transaction.TransactionManagerLookup</tt>
+ *   implementor</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.transaction.factory_class</tt></td>
+ *   <td>the factory to use for instantiating <tt>Transaction</tt>s.
+ *   (Defaults to <tt>JDBCTransactionFactory</tt>.)</td>
+ * </tr>
+ * <tr>
+ *   <td><tt>hibernate.query.substitutions</tt></td><td>query language token substitutions</td>
+ * </tr>
+ * </table>
+ *
+ * @see org.hibernate.SessionFactory
+ * @author Gavin King
+ */
+public final class Environment {
+
+	public static final String VERSION = "3.2 cr3";
+
+	/**
+	 * <tt>ConnectionProvider</tt> implementor to use when obtaining connections
+	 */
+	public static final String CONNECTION_PROVIDER ="hibernate.connection.provider_class";
+	/**
+	 * JDBC driver class
+	 */
+	public static final String DRIVER ="hibernate.connection.driver_class";
+	/**
+	 * JDBC transaction isolation level
+	 */
+	public static final String ISOLATION ="hibernate.connection.isolation";
+	/**
+	 * JDBC URL
+	 */
+	public static final String URL ="hibernate.connection.url";
+	/**
+	 * JDBC user
+	 */
+	public static final String USER ="hibernate.connection.username";
+	/**
+	 * JDBC password
+	 */
+	public static final String PASS ="hibernate.connection.password";
+	/**
+	 * JDBC autocommit mode
+	 */
+	public static final String AUTOCOMMIT ="hibernate.connection.autocommit";
+	/**
+	 * Maximum number of inactive connections for Hibernate's connection pool
+	 */
+	public static final String POOL_SIZE ="hibernate.connection.pool_size";
+	/**
+	 * <tt>java.sql.Datasource</tt> JNDI name
+	 */
+	public static final String DATASOURCE ="hibernate.connection.datasource";
+	/**
+	 * prefix for arbitrary JDBC connection properties
+	 */
+	public static final String CONNECTION_PREFIX = "hibernate.connection";
+
+	/**
+	 * JNDI initial context class, <tt>Context.INITIAL_CONTEXT_FACTORY</tt>
+	 */
+	public static final String JNDI_CLASS ="hibernate.jndi.class";
+	/**
+	 * JNDI provider URL, <tt>Context.PROVIDER_URL</tt>
+	 */
+	public static final String JNDI_URL ="hibernate.jndi.url";
+	/**
+	 * prefix for arbitrary JNDI <tt>InitialContext</tt> properties
+	 */
+	public static final String JNDI_PREFIX = "hibernate.jndi";
+	/**
+	 * JNDI name to bind to <tt>SessionFactory</tt>
+	 */
+	public static final String SESSION_FACTORY_NAME = "hibernate.session_factory_name";
+
+	/**
+	 * Hibernate SQL <tt>Dialect</tt> class
+	 */
+	public static final String DIALECT ="hibernate.dialect";
+	/**
+	 * A default database schema (owner) name to use for unqualified tablenames
+	 */
+	public static final String DEFAULT_SCHEMA = "hibernate.default_schema";
+	/**
+	 * A default database catalog name to use for unqualified tablenames
+	 */
+	public static final String DEFAULT_CATALOG = "hibernate.default_catalog";
+
+	/**
+	 * Enable logging of generated SQL to the console
+	 */
+	public static final String SHOW_SQL ="hibernate.show_sql";
+	/**
+	 * Enable formatting of SQL logged to the console
+	 */
+	public static final String FORMAT_SQL ="hibernate.format_sql";
+	/**
+	 * Add comments to the generated SQL
+	 */
+	public static final String USE_SQL_COMMENTS ="hibernate.use_sql_comments";
+	/**
+	 * Maximum depth of outer join fetching
+	 */
+	public static final String MAX_FETCH_DEPTH = "hibernate.max_fetch_depth";
+	/**
+	 * The default batch size for batch fetching
+	 */
+	public static final String DEFAULT_BATCH_FETCH_SIZE = "hibernate.default_batch_fetch_size";
+	/**
+	 * Use <tt>java.io</tt> streams to read / write binary data from / to JDBC
+	 */
+	public static final String USE_STREAMS_FOR_BINARY = "hibernate.jdbc.use_streams_for_binary";
+	/**
+	 * Use JDBC scrollable <tt>ResultSet</tt>s. This property is only necessary when there is
+	 * no <tt>ConnectionProvider</tt>, ie. the user is supplying JDBC connections.
+	 */
+	public static final String USE_SCROLLABLE_RESULTSET = "hibernate.jdbc.use_scrollable_resultset";
+	/**
+	 * Tells the JDBC driver to attempt to retrieve row Id with the JDBC 3.0 PreparedStatement.getGeneratedKeys()
+	 * method. In general, performance will be better if this property is set to true and the underlying
+	 * JDBC driver supports getGeneratedKeys().
+	 */
+	public static final String USE_GET_GENERATED_KEYS = "hibernate.jdbc.use_get_generated_keys";
+	/**
+	 * Gives the JDBC driver a hint as to the number of rows that should be fetched from the database
+	 * when more rows are needed. If <tt>0</tt>, JDBC driver default settings will be used.
+	 */
+	public static final String STATEMENT_FETCH_SIZE = "hibernate.jdbc.fetch_size";
+	/**
+	 * Maximum JDBC batch size. A nonzero value enables batch updates.
+	 */
+	public static final String STATEMENT_BATCH_SIZE = "hibernate.jdbc.batch_size";
+	/**
+	 * Select a custom batcher.
+	 */
+	public static final String BATCH_STRATEGY = "hibernate.jdbc.factory_class";
+	/**
+	 * Should versioned data be included in batching?
+	 */
+	public static final String BATCH_VERSIONED_DATA = "hibernate.jdbc.batch_versioned_data";
+	/**
+	 * An XSLT resource used to generate "custom" XML
+	 */
+	public static final String OUTPUT_STYLESHEET ="hibernate.xml.output_stylesheet";
+
+	/**
+	 * Maximum size of C3P0 connection pool
+	 */
+	public static final String C3P0_MAX_SIZE = "hibernate.c3p0.max_size";
+	/**
+	 * Minimum size of C3P0 connection pool
+	 */
+	public static final String C3P0_MIN_SIZE = "hibernate.c3p0.min_size";
+
+	/**
+	 * Maximum idle time for C3P0 connection pool
+	 */
+	public static final String C3P0_TIMEOUT = "hibernate.c3p0.timeout";
+	/**
+	 * Maximum size of C3P0 statement cache
+	 */
+	public static final String C3P0_MAX_STATEMENTS = "hibernate.c3p0.max_statements";
+	/**
+	 * Number of connections acquired when pool is exhausted
+	 */
+	public static final String C3P0_ACQUIRE_INCREMENT = "hibernate.c3p0.acquire_increment";
+	/**
+	 * Idle time before a C3P0 pooled connection is validated
+	 */
+	public static final String C3P0_IDLE_TEST_PERIOD = "hibernate.c3p0.idle_test_period";
+
+	/**
+	 * Proxool/Hibernate property prefix
+	 */
+	public static final String PROXOOL_PREFIX = "hibernate.proxool";
+	/**
+	 * Proxool property to configure the Proxool Provider using an XML (<tt>/path/to/file.xml</tt>)
+	 */
+	public static final String PROXOOL_XML = "hibernate.proxool.xml";
+	/**
+	 * Proxool property to configure the Proxool Provider  using a properties file (<tt>/path/to/proxool.properties</tt>)
+	 */
+	public static final String PROXOOL_PROPERTIES = "hibernate.proxool.properties";
+	/**
+	 * Proxool property to configure the Proxool Provider from an already existing pool (<tt>true</tt> / <tt>false</tt>)
+	 */
+	public static final String PROXOOL_EXISTING_POOL = "hibernate.proxool.existing_pool";
+	/**
+	 * Proxool property with the Proxool pool alias to use
+	 * (Required for <tt>PROXOOL_EXISTING_POOL</tt>, <tt>PROXOOL_PROPERTIES</tt>, or
+	 * <tt>PROXOOL_XML</tt>)
+	 */
+	public static final String PROXOOL_POOL_ALIAS = "hibernate.proxool.pool_alias";
+
+	/**
+	 * Enable automatic session close at end of transaction
+	 */
+	public static final String AUTO_CLOSE_SESSION = "hibernate.transaction.auto_close_session";
+	/**
+	 * Enable automatic flush during the JTA <tt>beforeCompletion()</tt> callback
+	 */
+	public static final String FLUSH_BEFORE_COMPLETION = "hibernate.transaction.flush_before_completion";
+	/**
+	 * Specifies how Hibernate should release JDBC connections.
+	 */
+	public static final String RELEASE_CONNECTIONS = "hibernate.connection.release_mode";
+	/**
+	 * Context scoping impl for {@link org.hibernate.SessionFactory#getCurrentSession()} processing.
+	 */
+	public static final String CURRENT_SESSION_CONTEXT_CLASS = "hibernate.current_session_context_class";
+	/**
+	 * <tt>TransactionFactory</tt> implementor to use for creating <tt>Transaction</tt>s
+	 */
+	public static final String TRANSACTION_STRATEGY = "hibernate.transaction.factory_class";
+	/**
+	 * <tt>TransactionManagerLookup</tt> implementor to use for obtaining the <tt>TransactionManager</tt>
+	 */
+	public static final String TRANSACTION_MANAGER_STRATEGY = "hibernate.transaction.manager_lookup_class";
+	/**
+	 * JNDI name of JTA <tt>UserTransaction</tt> object
+	 */
+	public static final String USER_TRANSACTION = "jta.UserTransaction";
+
+	/**
+	 * The <tt>CacheProvider</tt> implementation class
+	 */
+	public static final String CACHE_PROVIDER = "hibernate.cache.provider_class";
+
+	/**
+	 * The {@link org.hibernate.cache.RegionFactory} implementation class
+	 */
+	public static final String CACHE_REGION_FACTORY = "hibernate.cache.region.factory_class";
+
+	/**
+	 * The <tt>CacheProvider</tt> implementation class
+	 */
+	public static final String CACHE_PROVIDER_CONFIG = "hibernate.cache.provider_configuration_file_resource_path";
+	/**
+	 * The <tt>CacheProvider</tt> JNDI namespace, if pre-bound to JNDI.
+	 */
+	public static final String CACHE_NAMESPACE = "hibernate.cache.jndi";
+	/**
+	 * Enable the query cache (disabled by default)
+	 */
+	public static final String USE_QUERY_CACHE = "hibernate.cache.use_query_cache";
+	/**
+	 * The <tt>QueryCacheFactory</tt> implementation class.
+	 */
+	public static final String QUERY_CACHE_FACTORY = "hibernate.cache.query_cache_factory";
+	/**
+	 * Enable the second-level cache (enabled by default)
+	 */
+	public static final String USE_SECOND_LEVEL_CACHE = "hibernate.cache.use_second_level_cache";
+	/**
+	 * Optimize the cache for mimimal puts instead of minimal gets
+	 */
+	public static final String USE_MINIMAL_PUTS = "hibernate.cache.use_minimal_puts";
+	/**
+	 * The <tt>CacheProvider</tt> region name prefix
+	 */
+	public static final String CACHE_REGION_PREFIX = "hibernate.cache.region_prefix";
+	/**
+	 * Enable use of structured second-level cache entries
+	 */
+	public static final String USE_STRUCTURED_CACHE = "hibernate.cache.use_structured_entries";
+
+	/**
+	 * Enable statistics collection
+	 */
+	public static final String GENERATE_STATISTICS = "hibernate.generate_statistics";
+
+	public static final String USE_IDENTIFIER_ROLLBACK = "hibernate.use_identifier_rollback";
+
+	/**
+	 * Use bytecode libraries optimized property access
+	 */
+	public static final String USE_REFLECTION_OPTIMIZER = "hibernate.bytecode.use_reflection_optimizer";
+
+	/**
+	 * The classname of the HQL query parser factory
+	 */
+	public static final String QUERY_TRANSLATOR = "hibernate.query.factory_class";
+
+	/**
+	 * A comma-seperated list of token substitutions to use when translating a Hibernate
+	 * query to SQL
+	 */
+	public static final String QUERY_SUBSTITUTIONS = "hibernate.query.substitutions";
+
+	/**
+	 * Should named queries be checked during startup (the default is enabled).
+	 * <p/>
+	 * Mainly intended for test environments.
+	 */
+	public static final String QUERY_STARTUP_CHECKING = "hibernate.query.startup_check";
+
+	/**
+	 * Auto export/update schema using hbm2ddl tool. Valid values are <tt>update</tt>,
+	 * <tt>create</tt>, <tt>create-drop</tt> and <tt>validate</tt>.
+	 */
+	public static final String HBM2DDL_AUTO = "hibernate.hbm2ddl.auto";
+
+	/**
+	 * The {@link org.hibernate.exception.SQLExceptionConverter} to use for converting SQLExceptions
+	 * to Hibernate's JDBCException hierarchy.  The default is to use the configured
+	 * {@link org.hibernate.dialect.Dialect}'s preferred SQLExceptionConverter.
+	 */
+	public static final String SQL_EXCEPTION_CONVERTER = "hibernate.jdbc.sql_exception_converter";
+
+	/**
+	 * Enable wrapping of JDBC result sets in order to speed up column name lookups for
+	 * broken JDBC drivers
+	 */
+	public static final String WRAP_RESULT_SETS = "hibernate.jdbc.wrap_result_sets";
+
+	/**
+	 * Enable ordering of update statements by primary key value
+	 */
+	public static final String ORDER_UPDATES = "hibernate.order_updates";
+
+	/**
+	 * Enable ordering of insert statements for the purpose of more effecient JDBC batching.
+	 */
+	public static final String ORDER_INSERTS = "hibernate.order_inserts";
+
+	/**
+	 * The EntityMode in which set the Session opened from the SessionFactory.
+	 */
+    public static final String DEFAULT_ENTITY_MODE = "hibernate.default_entity_mode";
+
+    /**
+     * The jacc context id of the deployment
+     */
+    public static final String JACC_CONTEXTID = "hibernate.jacc_context_id";
+
+	public static final String BYTECODE_PROVIDER = "hibernate.bytecode.provider";
+
+	public static final String JPAQL_STRICT_COMPLIANCE= "hibernate.query.jpaql_strict_compliance";
+
+	private static final BytecodeProvider BYTECODE_PROVIDER_INSTANCE;
+	private static final boolean ENABLE_BINARY_STREAMS;
+	private static final boolean ENABLE_REFLECTION_OPTIMIZER;
+	private static final boolean JVM_SUPPORTS_LINKED_HASH_COLLECTIONS;
+	private static final boolean JVM_HAS_TIMESTAMP_BUG;
+	private static final boolean JVM_HAS_JDK14_TIMESTAMP;
+	private static final boolean JVM_SUPPORTS_GET_GENERATED_KEYS;
+
+	private static final Properties GLOBAL_PROPERTIES;
+	private static final HashMap ISOLATION_LEVELS = new HashMap();
+	private static final Map OBSOLETE_PROPERTIES = new HashMap();
+	private static final Map RENAMED_PROPERTIES = new HashMap();
+
+	private static final Log log = LogFactory.getLog(Environment.class);
+
+	/**
+	 * Issues warnings to the user when any obsolete property names are used.
+	 */
+	public static void verifyProperties(Properties props) {
+		Iterator iter = props.keySet().iterator();
+		Map propertiesToAdd = new HashMap();
+		while ( iter.hasNext() ) {
+			final Object propertyName = iter.next();
+			Object newPropertyName = OBSOLETE_PROPERTIES.get( propertyName );
+			if ( newPropertyName != null ) {
+				log.warn( "Usage of obsolete property: " + propertyName + " no longer supported, use: " + newPropertyName );
+			}
+			newPropertyName = RENAMED_PROPERTIES.get( propertyName );
+			if ( newPropertyName != null ) {
+				log.warn( "Property [" + propertyName + "] has been renamed to [" + newPropertyName + "]; update your properties appropriately" );
+				if ( ! props.containsKey( newPropertyName ) ) {
+					propertiesToAdd.put( newPropertyName, props.get( propertyName ) );
+				}
+			}
+		}
+		props.putAll(propertiesToAdd);
+	}
+
+	static {
+
+		log.info("Hibernate " + VERSION);
+
+		RENAMED_PROPERTIES.put( "hibernate.cglib.use_reflection_optimizer", USE_REFLECTION_OPTIMIZER );
+
+		ISOLATION_LEVELS.put( new Integer(Connection.TRANSACTION_NONE), "NONE" );
+		ISOLATION_LEVELS.put( new Integer(Connection.TRANSACTION_READ_UNCOMMITTED), "READ_UNCOMMITTED" );
+		ISOLATION_LEVELS.put( new Integer(Connection.TRANSACTION_READ_COMMITTED), "READ_COMMITTED" );
+		ISOLATION_LEVELS.put( new Integer(Connection.TRANSACTION_REPEATABLE_READ), "REPEATABLE_READ" );
+		ISOLATION_LEVELS.put( new Integer(Connection.TRANSACTION_SERIALIZABLE), "SERIALIZABLE" );
+
+		GLOBAL_PROPERTIES = new Properties();
+		//Set USE_REFLECTION_OPTIMIZER to false to fix HHH-227
+		GLOBAL_PROPERTIES.setProperty( USE_REFLECTION_OPTIMIZER, Boolean.FALSE.toString() );
+
+		try {
+			InputStream stream = ConfigHelper.getResourceAsStream("/hibernate.properties");
+			try {
+				GLOBAL_PROPERTIES.load(stream);
+				log.info( "loaded properties from resource hibernate.properties: " + PropertiesHelper.maskOut(GLOBAL_PROPERTIES, PASS) );
+			}
+			catch (Exception e) {
+				log.error("problem loading properties from hibernate.properties");
+			}
+			finally {
+				try{
+					stream.close();
+				}
+				catch (IOException ioe){
+					log.error("could not close stream on hibernate.properties", ioe);
+				}
+			}
+		}
+		catch (HibernateException he) {
+			log.info("hibernate.properties not found");
+		}
+
+		try {
+			GLOBAL_PROPERTIES.putAll( System.getProperties() );
+		}
+		catch (SecurityException se) {
+			log.warn("could not copy system properties, system properties will be ignored");
+		}
+
+		verifyProperties(GLOBAL_PROPERTIES);
+
+		ENABLE_BINARY_STREAMS = PropertiesHelper.getBoolean(USE_STREAMS_FOR_BINARY, GLOBAL_PROPERTIES);
+		ENABLE_REFLECTION_OPTIMIZER = PropertiesHelper.getBoolean(USE_REFLECTION_OPTIMIZER, GLOBAL_PROPERTIES);
+
+		if (ENABLE_BINARY_STREAMS) {
+			log.info("using java.io streams to persist binary types");
+		}
+		if (ENABLE_REFLECTION_OPTIMIZER) {
+			log.info("using bytecode reflection optimizer");
+		}
+		BYTECODE_PROVIDER_INSTANCE = buildBytecodeProvider( GLOBAL_PROPERTIES );
+
+		boolean getGeneratedKeysSupport;
+		try {
+			Statement.class.getMethod("getGeneratedKeys", null);
+			getGeneratedKeysSupport = true;
+		}
+		catch (NoSuchMethodException nsme) {
+			getGeneratedKeysSupport = false;
+		}
+		JVM_SUPPORTS_GET_GENERATED_KEYS = getGeneratedKeysSupport;
+		if (!JVM_SUPPORTS_GET_GENERATED_KEYS) log.info("JVM does not support Statement.getGeneratedKeys()");
+
+		boolean linkedHashSupport;
+		try {
+			Class.forName("java.util.LinkedHashSet");
+			linkedHashSupport = true;
+		}
+		catch (ClassNotFoundException cnfe) {
+			linkedHashSupport = false;
+		}
+		JVM_SUPPORTS_LINKED_HASH_COLLECTIONS = linkedHashSupport;
+		if (!JVM_SUPPORTS_LINKED_HASH_COLLECTIONS) log.info("JVM does not support LinkedHasMap, LinkedHashSet - ordered maps and sets disabled");
+
+		JVM_HAS_TIMESTAMP_BUG = new Timestamp(123456789).getTime() != 123456789;
+		if (JVM_HAS_TIMESTAMP_BUG) log.info("using workaround for JVM bug in java.sql.Timestamp");
+		Timestamp t = new Timestamp(0);
+		t.setNanos(5 * 1000000);
+		JVM_HAS_JDK14_TIMESTAMP = t.getTime() == 5;
+		if (JVM_HAS_JDK14_TIMESTAMP) {
+			log.info("using JDK 1.4 java.sql.Timestamp handling");
+		}
+		else {
+			log.info("using pre JDK 1.4 java.sql.Timestamp handling");
+		}
+	}
+
+	public static BytecodeProvider getBytecodeProvider() {
+		return BYTECODE_PROVIDER_INSTANCE;
+	}
+
+	/**
+	 * Does this JVM have the IBM JDK 1.3.1. The bug is <tt>new Timestamp(x).getTime()!=x</tt>.
+	 */
+	public static boolean jvmHasTimestampBug() {
+		return JVM_HAS_TIMESTAMP_BUG;
+	}
+
+	/**
+	 * Does this JVM handle <tt>Timestamp</tt> in the JDK 1.4 compliant way?
+	 */
+	public static boolean jvmHasJDK14Timestamp() {
+		return JVM_HAS_JDK14_TIMESTAMP;
+	}
+
+	/**
+	 * Does this JVM support <tt>LinkedHashSet</tt>, <tt>LinkedHashMap</tt>.
+	 * @see java.util.LinkedHashSet
+	 * @see java.util.LinkedHashMap
+	 */
+	public static boolean jvmSupportsLinkedHashCollections() {
+		return JVM_SUPPORTS_LINKED_HASH_COLLECTIONS;
+	}
+
+	public static boolean jvmSupportsGetGeneratedKeys() {
+		return JVM_SUPPORTS_GET_GENERATED_KEYS;
+	}
+
+	/**
+	 * Should we use streams to bind binary types to JDBC IN parameters.
+	 * Property <tt>hibernate.jdbc.use_streams_for_binary</tt>.
+	 * @see Environment#USE_STREAMS_FOR_BINARY
+	 */
+	public static boolean useStreamsForBinary() {
+		return ENABLE_BINARY_STREAMS;
+	}
+
+	/**
+	 * Should we use CGLIB reflection optimizer.
+	 * Property <tt>hibernate.jdbc.use_refection_optimizer</tt>.
+	 * @see Environment#USE_REFLECTION_OPTIMIZER
+	 */
+	public static boolean useReflectionOptimizer() {
+		return ENABLE_REFLECTION_OPTIMIZER;
+	}
+
+	private Environment() { throw new UnsupportedOperationException(); }
+
+	/**
+	 * Return <tt>System</tt> properties, extended by any properties specified
+	 * in <tt>hibernate.properties</tt>.
+	 * @return Properties
+	 */
+	public static Properties getProperties() {
+		Properties copy = new Properties();
+		copy.putAll(GLOBAL_PROPERTIES);
+		return copy;
+	}
+
+	/**
+	 * Get the name of a JDBC transaction isolation level
+	 *
+	 * @see java.sql.Connection
+	 * @param isolation as defined by <tt>java.sql.Connection</tt>
+	 * @return a human-readable name
+	 */
+	public static String isolationLevelToString(int isolation) {
+		return (String) ISOLATION_LEVELS.get( new Integer(isolation) );
+	}
+
+
+	public static BytecodeProvider buildBytecodeProvider(Properties properties) {
+		String provider = PropertiesHelper.getString( Environment.BYTECODE_PROVIDER, properties, "cglib" );
+		log.info( "Bytecode provider name : " + provider );
+		return buildBytecodeProvider( provider );
+	}
+
+	private static BytecodeProvider buildBytecodeProvider(String providerName) {
+		if ( "javassist".equals( providerName ) ) {
+			return new org.hibernate.bytecode.javassist.BytecodeProviderImpl();
+		}
+		else if ( "cglib".equals( providerName ) ) {
+			return new org.hibernate.bytecode.cglib.BytecodeProviderImpl();
+		}
+		else {
+			log.warn( "unrecognized bytecode provider [" + providerName + "], using cglib by default" );
+			return new org.hibernate.bytecode.cglib.BytecodeProviderImpl();
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ExtendsQueueEntry.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ExtendsQueueEntry.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ExtendsQueueEntry.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+package org.hibernate.cfg;
+
+import org.dom4j.Document;
+
+/**
+ * Represents a mapping queued for delayed processing to await
+ * processing of an extends entity upon which it depends.
+ *
+ * @author Steve Ebersole
+ */
+public class ExtendsQueueEntry {
+	private final String explicitName;
+	private final String mappingPackage;
+	private final Document document;
+
+	public ExtendsQueueEntry(String explicitName, String mappingPackage, Document document) {
+		this.explicitName = explicitName;
+		this.mappingPackage = mappingPackage;
+		this.document = document;
+	}
+
+	public String getExplicitName() {
+		return explicitName;
+	}
+
+	public String getMappingPackage() {
+		return mappingPackage;
+	}
+
+	public Document getDocument() {
+		return document;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/HbmBinder.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/HbmBinder.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/HbmBinder.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,3063 @@
+// $Id: HbmBinder.java 11496 2007-05-09 03:54:06Z steve.ebersole at jboss.com $
+package org.hibernate.cfg;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import org.apache.commons.collections.SequencedHashMap;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.dom4j.Attribute;
+import org.dom4j.Document;
+import org.dom4j.Element;
+import org.hibernate.CacheMode;
+import org.hibernate.EntityMode;
+import org.hibernate.FetchMode;
+import org.hibernate.FlushMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.FilterDefinition;
+import org.hibernate.engine.NamedQueryDefinition;
+import org.hibernate.engine.Versioning;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.id.PersistentIdentifierGenerator;
+import org.hibernate.mapping.Any;
+import org.hibernate.mapping.Array;
+import org.hibernate.mapping.AuxiliaryDatabaseObject;
+import org.hibernate.mapping.Backref;
+import org.hibernate.mapping.Bag;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.DependantValue;
+import org.hibernate.mapping.Fetchable;
+import org.hibernate.mapping.Filterable;
+import org.hibernate.mapping.Formula;
+import org.hibernate.mapping.IdentifierBag;
+import org.hibernate.mapping.IdentifierCollection;
+import org.hibernate.mapping.IndexBackref;
+import org.hibernate.mapping.IndexedCollection;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.JoinedSubclass;
+import org.hibernate.mapping.KeyValue;
+import org.hibernate.mapping.List;
+import org.hibernate.mapping.ManyToOne;
+import org.hibernate.mapping.Map;
+import org.hibernate.mapping.MetaAttribute;
+import org.hibernate.mapping.OneToMany;
+import org.hibernate.mapping.OneToOne;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.PrimitiveArray;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.PropertyGeneration;
+import org.hibernate.mapping.RootClass;
+import org.hibernate.mapping.Selectable;
+import org.hibernate.mapping.Set;
+import org.hibernate.mapping.SimpleAuxiliaryDatabaseObject;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.SingleTableSubclass;
+import org.hibernate.mapping.Subclass;
+import org.hibernate.mapping.Table;
+import org.hibernate.mapping.ToOne;
+import org.hibernate.mapping.TypeDef;
+import org.hibernate.mapping.UnionSubclass;
+import org.hibernate.mapping.UniqueKey;
+import org.hibernate.mapping.Value;
+import org.hibernate.persister.entity.JoinedSubclassEntityPersister;
+import org.hibernate.persister.entity.SingleTableEntityPersister;
+import org.hibernate.persister.entity.UnionSubclassEntityPersister;
+import org.hibernate.type.DiscriminatorType;
+import org.hibernate.type.ForeignKeyDirection;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.JoinedIterator;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Walks an XML mapping document and produces the Hibernate configuration-time metamodel (the
+ * classes in the <tt>mapping</tt> package)
+ *
+ * @author Gavin King
+ */
+public final class HbmBinder {
+
+	private static final Log log = LogFactory.getLog( HbmBinder.class );
+
+	/**
+	 * Private constructor to disallow instantiation.
+	 */
+	private HbmBinder() {
+	}
+
+	/**
+	 * The main contract into the hbm.xml-based binder. Performs necessary binding operations
+	 * represented by the given DOM.
+	 *
+	 * @param doc The DOM to be parsed and bound.
+	 * @param mappings Current bind state.
+	 * @param inheritedMetas Any inherited meta-tag information.
+	 * @throws MappingException
+	 */
+	public static void bindRoot(Document doc, Mappings mappings, java.util.Map inheritedMetas)
+			throws MappingException {
+
+		java.util.List names = HbmBinder.getExtendsNeeded( doc, mappings );
+		if ( !names.isEmpty() ) {
+			// classes mentioned in extends not available - so put it in queue
+			Element hmNode = doc.getRootElement();
+			Attribute packNode = hmNode.attribute( "package" );
+			String packageName = null;
+			if ( packNode != null ) {
+				packageName = packNode.getValue();
+			}
+			Iterator itr = names.iterator();
+			while ( itr.hasNext() ) {
+				String extendsName = (String) itr.next();
+				mappings.addToExtendsQueue( new ExtendsQueueEntry( extendsName, packageName, doc ) );
+			}
+			return;
+		}
+
+		Element hmNode = doc.getRootElement();
+		// get meta's from <hibernate-mapping>
+		inheritedMetas = getMetas( hmNode, inheritedMetas, true );
+		extractRootAttributes( hmNode, mappings );
+
+		Iterator rootChildren = hmNode.elementIterator();
+		while ( rootChildren.hasNext() ) {
+			final Element element = (Element) rootChildren.next();
+			final String elementName = element.getName();
+
+			if ( "filter-def".equals( elementName ) ) {
+				parseFilterDef( element, mappings );
+			}
+			else if ( "typedef".equals( elementName ) ) {
+				bindTypeDef( element, mappings );
+			}
+			else if ( "class".equals( elementName ) ) {
+				RootClass rootclass = new RootClass();
+				bindRootClass( element, rootclass, mappings, inheritedMetas );
+				mappings.addClass( rootclass );
+			}
+			else if ( "subclass".equals( elementName ) ) {
+				PersistentClass superModel = getSuperclass( mappings, element );
+				handleSubclass( superModel, mappings, element, inheritedMetas );
+			}
+			else if ( "joined-subclass".equals( elementName ) ) {
+				PersistentClass superModel = getSuperclass( mappings, element );
+				handleJoinedSubclass( superModel, mappings, element, inheritedMetas );
+			}
+			else if ( "union-subclass".equals( elementName ) ) {
+				PersistentClass superModel = getSuperclass( mappings, element );
+				handleUnionSubclass( superModel, mappings, element, inheritedMetas );
+			}
+			else if ( "query".equals( elementName ) ) {
+				bindNamedQuery( element, null, mappings );
+			}
+			else if ( "sql-query".equals( elementName ) ) {
+				bindNamedSQLQuery( element, null, mappings );
+			}
+			else if ( "resultset".equals( elementName ) ) {
+				bindResultSetMappingDefinition( element, null, mappings );
+			}
+			else if ( "import".equals( elementName ) ) {
+				bindImport( element, mappings );
+			}
+			else if ( "database-object".equals( elementName ) ) {
+				bindAuxiliaryDatabaseObject( element, mappings );
+			}
+		}
+	}
+
+	private static void bindImport(Element importNode, Mappings mappings) {
+		String className = getClassName( importNode.attribute( "class" ), mappings );
+		Attribute renameNode = importNode.attribute( "rename" );
+		String rename = ( renameNode == null ) ?
+						StringHelper.unqualify( className ) :
+						renameNode.getValue();
+		log.debug( "Import: " + rename + " -> " + className );
+		mappings.addImport( className, rename );
+	}
+
+	private static void bindTypeDef(Element typedefNode, Mappings mappings) {
+		String typeClass = typedefNode.attributeValue( "class" );
+		String typeName = typedefNode.attributeValue( "name" );
+		Iterator paramIter = typedefNode.elementIterator( "param" );
+		Properties parameters = new Properties();
+		while ( paramIter.hasNext() ) {
+			Element param = (Element) paramIter.next();
+			parameters.setProperty( param.attributeValue( "name" ), param.getTextTrim() );
+		}
+		mappings.addTypeDef( typeName, typeClass, parameters );
+	}
+
+	private static void bindAuxiliaryDatabaseObject(Element auxDbObjectNode, Mappings mappings) {
+		AuxiliaryDatabaseObject auxDbObject = null;
+		Element definitionNode = auxDbObjectNode.element( "definition" );
+		if ( definitionNode != null ) {
+			try {
+				auxDbObject = ( AuxiliaryDatabaseObject ) ReflectHelper
+						.classForName( definitionNode.attributeValue( "class" ) )
+						.newInstance();
+			}
+			catch( ClassNotFoundException e ) {
+				throw new MappingException(
+						"could not locate custom database object class [" +
+						definitionNode.attributeValue( "class" ) + "]"
+					);
+			}
+			catch( Throwable t ) {
+				throw new MappingException(
+						"could not instantiate custom database object class [" +
+						definitionNode.attributeValue( "class" ) + "]"
+					);
+			}
+		}
+		else {
+			auxDbObject = new SimpleAuxiliaryDatabaseObject(
+					auxDbObjectNode.elementTextTrim( "create" ),
+					auxDbObjectNode.elementTextTrim( "drop" )
+				);
+		}
+
+		Iterator dialectScopings = auxDbObjectNode.elementIterator( "dialect-scope" );
+		while ( dialectScopings.hasNext() ) {
+			Element dialectScoping = ( Element ) dialectScopings.next();
+			auxDbObject.addDialectScope( dialectScoping.attributeValue( "name" ) );
+		}
+
+		mappings.addAuxiliaryDatabaseObject( auxDbObject );
+	}
+
+	private static void extractRootAttributes(Element hmNode, Mappings mappings) {
+		Attribute schemaNode = hmNode.attribute( "schema" );
+		mappings.setSchemaName( ( schemaNode == null ) ? null : schemaNode.getValue() );
+
+		Attribute catalogNode = hmNode.attribute( "catalog" );
+		mappings.setCatalogName( ( catalogNode == null ) ? null : catalogNode.getValue() );
+
+		Attribute dcNode = hmNode.attribute( "default-cascade" );
+		mappings.setDefaultCascade( ( dcNode == null ) ? "none" : dcNode.getValue() );
+
+		Attribute daNode = hmNode.attribute( "default-access" );
+		mappings.setDefaultAccess( ( daNode == null ) ? "property" : daNode.getValue() );
+
+		Attribute dlNode = hmNode.attribute( "default-lazy" );
+		mappings.setDefaultLazy( dlNode == null || dlNode.getValue().equals( "true" ) );
+
+		Attribute aiNode = hmNode.attribute( "auto-import" );
+		mappings.setAutoImport( ( aiNode == null ) || "true".equals( aiNode.getValue() ) );
+
+		Attribute packNode = hmNode.attribute( "package" );
+		if ( packNode != null ) mappings.setDefaultPackage( packNode.getValue() );
+	}
+
+	/**
+	 * Responsible for perfoming the bind operation related to an &lt;class/&gt; mapping element.
+	 *
+	 * @param node The DOM Element for the &lt;class/&gt; element.
+	 * @param rootClass The mapping instance to which to bind the information.
+	 * @param mappings The current bind state.
+	 * @param inheritedMetas Any inherited meta-tag information.
+	 * @throws MappingException
+	 */
+	public static void bindRootClass(Element node, RootClass rootClass, Mappings mappings,
+			java.util.Map inheritedMetas) throws MappingException {
+		bindClass( node, rootClass, mappings, inheritedMetas );
+		inheritedMetas = getMetas( node, inheritedMetas, true ); // get meta's from <class>
+		bindRootPersistentClassCommonValues( node, inheritedMetas, mappings, rootClass );
+	}
+
+	private static void bindRootPersistentClassCommonValues(Element node,
+			java.util.Map inheritedMetas, Mappings mappings, RootClass entity)
+			throws MappingException {
+
+		// DB-OBJECTNAME
+
+		Attribute schemaNode = node.attribute( "schema" );
+		String schema = schemaNode == null ?
+				mappings.getSchemaName() : schemaNode.getValue();
+
+		Attribute catalogNode = node.attribute( "catalog" );
+		String catalog = catalogNode == null ?
+				mappings.getCatalogName() : catalogNode.getValue();
+
+		Table table = mappings.addTable(
+				schema,
+				catalog,
+				getClassTableName( entity, node, schema, catalog, null, mappings ),
+				getSubselect( node ),
+		        entity.isAbstract() != null && entity.isAbstract().booleanValue()
+			);
+		entity.setTable( table );
+		bindComment(table, node);
+
+		log.info(
+				"Mapping class: " + entity.getEntityName() +
+				" -> " + entity.getTable().getName()
+			);
+
+		// MUTABLE
+		Attribute mutableNode = node.attribute( "mutable" );
+		entity.setMutable( ( mutableNode == null ) || mutableNode.getValue().equals( "true" ) );
+
+		// WHERE
+		Attribute whereNode = node.attribute( "where" );
+		if ( whereNode != null ) entity.setWhere( whereNode.getValue() );
+
+		// CHECK
+		Attribute chNode = node.attribute( "check" );
+		if ( chNode != null ) table.addCheckConstraint( chNode.getValue() );
+
+		// POLYMORPHISM
+		Attribute polyNode = node.attribute( "polymorphism" );
+		entity.setExplicitPolymorphism( ( polyNode != null )
+			&& polyNode.getValue().equals( "explicit" ) );
+
+		// ROW ID
+		Attribute rowidNode = node.attribute( "rowid" );
+		if ( rowidNode != null ) table.setRowId( rowidNode.getValue() );
+
+		Iterator subnodes = node.elementIterator();
+		while ( subnodes.hasNext() ) {
+
+			Element subnode = (Element) subnodes.next();
+			String name = subnode.getName();
+
+			if ( "id".equals( name ) ) {
+				// ID
+				bindSimpleId( subnode, entity, mappings, inheritedMetas );
+			}
+			else if ( "composite-id".equals( name ) ) {
+				// COMPOSITE-ID
+				bindCompositeId( subnode, entity, mappings, inheritedMetas );
+			}
+			else if ( "version".equals( name ) || "timestamp".equals( name ) ) {
+				// VERSION / TIMESTAMP
+				bindVersioningProperty( table, subnode, mappings, name, entity, inheritedMetas );
+			}
+			else if ( "discriminator".equals( name ) ) {
+				// DISCRIMINATOR
+				bindDiscriminatorProperty( table, entity, subnode, mappings );
+			}
+			else if ( "cache".equals( name ) ) {
+				entity.setCacheConcurrencyStrategy( subnode.attributeValue( "usage" ) );
+				entity.setCacheRegionName( subnode.attributeValue( "region" ) );
+				entity.setLazyPropertiesCacheable( !"non-lazy".equals( subnode.attributeValue( "include" ) ) );
+			}
+
+		}
+
+		// Primary key constraint
+		entity.createPrimaryKey();
+
+		createClassProperties( node, entity, mappings, inheritedMetas );
+	}
+
+	private static void bindSimpleId(Element idNode, RootClass entity, Mappings mappings,
+			java.util.Map inheritedMetas) throws MappingException {
+		String propertyName = idNode.attributeValue( "name" );
+
+		SimpleValue id = new SimpleValue( entity.getTable() );
+		entity.setIdentifier( id );
+
+		// if ( propertyName == null || entity.getPojoRepresentation() == null ) {
+		// bindSimpleValue( idNode, id, false, RootClass.DEFAULT_IDENTIFIER_COLUMN_NAME, mappings );
+		// if ( !id.isTypeSpecified() ) {
+		// throw new MappingException( "must specify an identifier type: " + entity.getEntityName()
+		// );
+		// }
+		// }
+		// else {
+		// bindSimpleValue( idNode, id, false, propertyName, mappings );
+		// PojoRepresentation pojo = entity.getPojoRepresentation();
+		// id.setTypeUsingReflection( pojo.getClassName(), propertyName );
+		//
+		// Property prop = new Property();
+		// prop.setValue( id );
+		// bindProperty( idNode, prop, mappings, inheritedMetas );
+		// entity.setIdentifierProperty( prop );
+		// }
+
+		if ( propertyName == null ) {
+			bindSimpleValue( idNode, id, false, RootClass.DEFAULT_IDENTIFIER_COLUMN_NAME, mappings );
+		}
+		else {
+			bindSimpleValue( idNode, id, false, propertyName, mappings );
+		}
+
+		if ( propertyName == null || !entity.hasPojoRepresentation() ) {
+			if ( !id.isTypeSpecified() ) {
+				throw new MappingException( "must specify an identifier type: "
+					+ entity.getEntityName() );
+			}
+		}
+		else {
+			id.setTypeUsingReflection( entity.getClassName(), propertyName );
+		}
+
+		if ( propertyName != null ) {
+			Property prop = new Property();
+			prop.setValue( id );
+			bindProperty( idNode, prop, mappings, inheritedMetas );
+			entity.setIdentifierProperty( prop );
+		}
+
+		// TODO:
+		/*
+		 * if ( id.getHibernateType().getReturnedClass().isArray() ) throw new MappingException(
+		 * "illegal use of an array as an identifier (arrays don't reimplement equals)" );
+		 */
+		makeIdentifier( idNode, id, mappings );
+	}
+
+	private static void bindCompositeId(Element idNode, RootClass entity, Mappings mappings,
+			java.util.Map inheritedMetas) throws MappingException {
+		String propertyName = idNode.attributeValue( "name" );
+		Component id = new Component( entity );
+		entity.setIdentifier( id );
+		bindCompositeId( idNode, id, entity, propertyName, mappings, inheritedMetas );
+		if ( propertyName == null ) {
+			entity.setEmbeddedIdentifier( id.isEmbedded() );
+			if ( id.isEmbedded() ) {
+				// todo : what is the implication of this?
+				id.setDynamic( !entity.hasPojoRepresentation() );
+				/*
+				 * Property prop = new Property(); prop.setName("id");
+				 * prop.setPropertyAccessorName("embedded"); prop.setValue(id);
+				 * entity.setIdentifierProperty(prop);
+				 */
+			}
+		}
+		else {
+			Property prop = new Property();
+			prop.setValue( id );
+			bindProperty( idNode, prop, mappings, inheritedMetas );
+			entity.setIdentifierProperty( prop );
+		}
+
+		makeIdentifier( idNode, id, mappings );
+
+	}
+
+	private static void bindVersioningProperty(Table table, Element subnode, Mappings mappings,
+			String name, RootClass entity, java.util.Map inheritedMetas) {
+
+		String propertyName = subnode.attributeValue( "name" );
+		SimpleValue val = new SimpleValue( table );
+		bindSimpleValue( subnode, val, false, propertyName, mappings );
+		if ( !val.isTypeSpecified() ) {
+			// this is either a <version/> tag with no type attribute,
+			// or a <timestamp/> tag
+			if ( "version".equals( name ) ) {
+				val.setTypeName( "integer" );
+			}
+			else {
+				if ( "db".equals( subnode.attributeValue( "source" ) ) ) {
+					val.setTypeName( "dbtimestamp" );
+				}
+				else {
+					val.setTypeName( "timestamp" );
+				}
+			}
+		}
+		Property prop = new Property();
+		prop.setValue( val );
+		bindProperty( subnode, prop, mappings, inheritedMetas );
+		// for version properties marked as being generated, make sure they are "always"
+		// generated; aka, "insert" is invalid; this is dis-allowed by the DTD,
+		// but just to make sure...
+		if ( prop.getGeneration() == PropertyGeneration.INSERT ) {
+			throw new MappingException( "'generated' attribute cannot be 'insert' for versioning property" );
+		}
+		makeVersion( subnode, val );
+		entity.setVersion( prop );
+		entity.addProperty( prop );
+	}
+
+	private static void bindDiscriminatorProperty(Table table, RootClass entity, Element subnode,
+			Mappings mappings) {
+		SimpleValue discrim = new SimpleValue( table );
+		entity.setDiscriminator( discrim );
+		bindSimpleValue(
+				subnode,
+				discrim,
+				false,
+				RootClass.DEFAULT_DISCRIMINATOR_COLUMN_NAME,
+				mappings
+			);
+		if ( !discrim.isTypeSpecified() ) {
+			discrim.setTypeName( "string" );
+			// ( (Column) discrim.getColumnIterator().next() ).setType(type);
+		}
+		entity.setPolymorphic( true );
+		if ( "true".equals( subnode.attributeValue( "force" ) ) )
+			entity.setForceDiscriminator( true );
+		if ( "false".equals( subnode.attributeValue( "insert" ) ) )
+			entity.setDiscriminatorInsertable( false );
+	}
+
+	public static void bindClass(Element node, PersistentClass persistentClass, Mappings mappings,
+			java.util.Map inheritedMetas) throws MappingException {
+		// transfer an explicitly defined entity name
+		// handle the lazy attribute
+		Attribute lazyNode = node.attribute( "lazy" );
+		boolean lazy = lazyNode == null ?
+				mappings.isDefaultLazy() :
+				"true".equals( lazyNode.getValue() );
+		// go ahead and set the lazy here, since pojo.proxy can override it.
+		persistentClass.setLazy( lazy );
+
+		String entityName = node.attributeValue( "entity-name" );
+		if ( entityName == null ) entityName = getClassName( node.attribute("name"), mappings );
+		if ( entityName==null ) {
+			throw new MappingException( "Unable to determine entity name" );
+		}
+		persistentClass.setEntityName( entityName );
+
+		bindPojoRepresentation( node, persistentClass, mappings, inheritedMetas );
+		bindDom4jRepresentation( node, persistentClass, mappings, inheritedMetas );
+		bindMapRepresentation( node, persistentClass, mappings, inheritedMetas );
+
+		bindPersistentClassCommonValues( node, persistentClass, mappings, inheritedMetas );
+
+	}
+
+	private static void bindPojoRepresentation(Element node, PersistentClass entity,
+			Mappings mappings, java.util.Map metaTags) {
+
+		String className = getClassName( node.attribute( "name" ), mappings );
+		String proxyName = getClassName( node.attribute( "proxy" ), mappings );
+
+		entity.setClassName( className );
+
+		if ( proxyName != null ) {
+			entity.setProxyInterfaceName( proxyName );
+			entity.setLazy( true );
+		}
+		else if ( entity.isLazy() ) {
+			entity.setProxyInterfaceName( className );
+		}
+
+		Element tuplizer = locateTuplizerDefinition( node, EntityMode.POJO );
+		if ( tuplizer != null ) {
+			entity.addTuplizer( EntityMode.POJO, tuplizer.attributeValue( "class" ) );
+		}
+	}
+
+	private static void bindDom4jRepresentation(Element node, PersistentClass entity,
+			Mappings mappings, java.util.Map inheritedMetas) {
+		String nodeName = node.attributeValue( "node" );
+		if (nodeName==null) nodeName = StringHelper.unqualify( entity.getEntityName() );
+		entity.setNodeName(nodeName);
+
+		Element tuplizer = locateTuplizerDefinition( node, EntityMode.DOM4J );
+		if ( tuplizer != null ) {
+			entity.addTuplizer( EntityMode.DOM4J, tuplizer.attributeValue( "class" ) );
+		}
+	}
+
+	private static void bindMapRepresentation(Element node, PersistentClass entity,
+			Mappings mappings, java.util.Map inheritedMetas) {
+		Element tuplizer = locateTuplizerDefinition( node, EntityMode.MAP );
+		if ( tuplizer != null ) {
+			entity.addTuplizer( EntityMode.MAP, tuplizer.attributeValue( "class" ) );
+		}
+	}
+
+	/**
+	 * Locate any explicit tuplizer definition in the metadata, for the given entity-mode.
+	 *
+	 * @param container The containing element (representing the entity/component)
+	 * @param entityMode The entity-mode for which to locate the tuplizer element
+	 * @return The tuplizer element, or null.
+	 */
+	private static Element locateTuplizerDefinition(Element container, EntityMode entityMode) {
+		Iterator itr = container.elements( "tuplizer" ).iterator();
+		while( itr.hasNext() ) {
+			final Element tuplizerElem = ( Element ) itr.next();
+			if ( entityMode.toString().equals( tuplizerElem.attributeValue( "entity-mode") ) ) {
+				return tuplizerElem;
+			}
+		}
+		return null;
+	}
+
+	private static void bindPersistentClassCommonValues(Element node, PersistentClass entity,
+			Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+		// DISCRIMINATOR
+		Attribute discriminatorNode = node.attribute( "discriminator-value" );
+		entity.setDiscriminatorValue( ( discriminatorNode == null )
+			? entity.getEntityName()
+			: discriminatorNode.getValue() );
+
+		// DYNAMIC UPDATE
+		Attribute dynamicNode = node.attribute( "dynamic-update" );
+		entity.setDynamicUpdate(
+				dynamicNode != null && "true".equals( dynamicNode.getValue() )
+		);
+
+		// DYNAMIC INSERT
+		Attribute insertNode = node.attribute( "dynamic-insert" );
+		entity.setDynamicInsert(
+				insertNode != null && "true".equals( insertNode.getValue() )
+		);
+
+		// IMPORT
+		mappings.addImport( entity.getEntityName(), entity.getEntityName() );
+		if ( mappings.isAutoImport() && entity.getEntityName().indexOf( '.' ) > 0 ) {
+			mappings.addImport(
+					entity.getEntityName(),
+					StringHelper.unqualify( entity.getEntityName() )
+				);
+		}
+
+		// BATCH SIZE
+		Attribute batchNode = node.attribute( "batch-size" );
+		if ( batchNode != null ) entity.setBatchSize( Integer.parseInt( batchNode.getValue() ) );
+
+		// SELECT BEFORE UPDATE
+		Attribute sbuNode = node.attribute( "select-before-update" );
+		if ( sbuNode != null ) entity.setSelectBeforeUpdate( "true".equals( sbuNode.getValue() ) );
+
+		// OPTIMISTIC LOCK MODE
+		Attribute olNode = node.attribute( "optimistic-lock" );
+		entity.setOptimisticLockMode( getOptimisticLockMode( olNode ) );
+
+		entity.setMetaAttributes( getMetas( node, inheritedMetas ) );
+
+		// PERSISTER
+		Attribute persisterNode = node.attribute( "persister" );
+		if ( persisterNode == null ) {
+			// persister = SingleTableEntityPersister.class;
+		}
+		else {
+			try {
+				entity.setEntityPersisterClass( ReflectHelper.classForName( persisterNode
+					.getValue() ) );
+			}
+			catch (ClassNotFoundException cnfe) {
+				throw new MappingException( "Could not find persister class: "
+					+ persisterNode.getValue() );
+			}
+		}
+
+		// CUSTOM SQL
+		handleCustomSQL( node, entity );
+
+		Iterator tables = node.elementIterator( "synchronize" );
+		while ( tables.hasNext() ) {
+			entity.addSynchronizedTable( ( (Element) tables.next() ).attributeValue( "table" ) );
+		}
+
+		Attribute abstractNode = node.attribute( "abstract" );
+		Boolean isAbstract = abstractNode == null
+				? null
+		        : "true".equals( abstractNode.getValue() )
+						? Boolean.TRUE
+	                    : "false".equals( abstractNode.getValue() )
+								? Boolean.FALSE
+	                            : null;
+		entity.setAbstract( isAbstract );
+	}
+
+	private static void handleCustomSQL(Element node, PersistentClass model)
+			throws MappingException {
+		Element element = node.element( "sql-insert" );
+		if ( element != null ) {
+			boolean callable = isCallable( element );
+			model.setCustomSQLInsert( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
+		}
+
+		element = node.element( "sql-delete" );
+		if ( element != null ) {
+			boolean callable = isCallable( element );
+			model.setCustomSQLDelete( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
+		}
+
+		element = node.element( "sql-update" );
+		if ( element != null ) {
+			boolean callable = isCallable( element );
+			model.setCustomSQLUpdate( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
+		}
+
+		element = node.element( "loader" );
+		if ( element != null ) {
+			model.setLoaderName( element.attributeValue( "query-ref" ) );
+		}
+	}
+
+	private static void handleCustomSQL(Element node, Join model) throws MappingException {
+		Element element = node.element( "sql-insert" );
+		if ( element != null ) {
+			boolean callable = isCallable( element );
+			model.setCustomSQLInsert( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
+		}
+
+		element = node.element( "sql-delete" );
+		if ( element != null ) {
+			boolean callable = isCallable( element );
+			model.setCustomSQLDelete( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
+		}
+
+		element = node.element( "sql-update" );
+		if ( element != null ) {
+			boolean callable = isCallable( element );
+			model.setCustomSQLUpdate( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
+		}
+	}
+
+	private static void handleCustomSQL(Element node, Collection model) throws MappingException {
+		Element element = node.element( "sql-insert" );
+		if ( element != null ) {
+			boolean callable = isCallable( element, true );
+			model.setCustomSQLInsert( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
+		}
+
+		element = node.element( "sql-delete" );
+		if ( element != null ) {
+			boolean callable = isCallable( element, true );
+			model.setCustomSQLDelete( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
+		}
+
+		element = node.element( "sql-update" );
+		if ( element != null ) {
+			boolean callable = isCallable( element, true );
+			model.setCustomSQLUpdate( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
+		}
+
+		element = node.element( "sql-delete-all" );
+		if ( element != null ) {
+			boolean callable = isCallable( element, true );
+			model.setCustomSQLDeleteAll( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) );
+		}
+	}
+
+	private static boolean isCallable(Element e) throws MappingException {
+		return isCallable( e, true );
+	}
+
+	private static boolean isCallable(Element element, boolean supportsCallable)
+			throws MappingException {
+		Attribute attrib = element.attribute( "callable" );
+		if ( attrib != null && "true".equals( attrib.getValue() ) ) {
+			if ( !supportsCallable ) {
+				throw new MappingException( "callable attribute not supported yet!" );
+			}
+			return true;
+		}
+		return false;
+	}
+
+	private static ExecuteUpdateResultCheckStyle getResultCheckStyle(Element element, boolean callable) throws MappingException {
+		Attribute attr = element.attribute( "check" );
+		if ( attr == null ) {
+			// use COUNT as the default.  This mimics the old behavior, although
+			// NONE might be a better option moving forward in the case of callable
+			return ExecuteUpdateResultCheckStyle.COUNT;
+		}
+		return ExecuteUpdateResultCheckStyle.parse( attr.getValue() );
+	}
+
+	public static void bindUnionSubclass(Element node, UnionSubclass unionSubclass,
+			Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+
+		bindClass( node, unionSubclass, mappings, inheritedMetas );
+		inheritedMetas = getMetas( node, inheritedMetas, true ); // get meta's from <subclass>
+
+		if ( unionSubclass.getEntityPersisterClass() == null ) {
+			unionSubclass.getRootClass().setEntityPersisterClass(
+				UnionSubclassEntityPersister.class );
+		}
+
+		Attribute schemaNode = node.attribute( "schema" );
+		String schema = schemaNode == null ?
+				mappings.getSchemaName() : schemaNode.getValue();
+
+		Attribute catalogNode = node.attribute( "catalog" );
+		String catalog = catalogNode == null ?
+				mappings.getCatalogName() : catalogNode.getValue();
+
+		Table denormalizedSuperTable = unionSubclass.getSuperclass().getTable();
+		Table mytable = mappings.addDenormalizedTable(
+				schema,
+				catalog,
+				getClassTableName(unionSubclass, node, schema, catalog, denormalizedSuperTable, mappings ),
+		        unionSubclass.isAbstract() != null && unionSubclass.isAbstract().booleanValue(),
+				getSubselect( node ),
+				denormalizedSuperTable
+			);
+		unionSubclass.setTable( mytable );
+
+		log.info(
+				"Mapping union-subclass: " + unionSubclass.getEntityName() +
+				" -> " + unionSubclass.getTable().getName()
+			);
+
+		createClassProperties( node, unionSubclass, mappings, inheritedMetas );
+
+	}
+
+	public static void bindSubclass(Element node, Subclass subclass, Mappings mappings,
+			java.util.Map inheritedMetas) throws MappingException {
+
+		bindClass( node, subclass, mappings, inheritedMetas );
+		inheritedMetas = getMetas( node, inheritedMetas, true ); // get meta's from <subclass>
+
+		if ( subclass.getEntityPersisterClass() == null ) {
+			subclass.getRootClass()
+					.setEntityPersisterClass( SingleTableEntityPersister.class );
+		}
+
+		log.info(
+				"Mapping subclass: " + subclass.getEntityName() +
+				" -> " + subclass.getTable().getName()
+			);
+
+		// properties
+		createClassProperties( node, subclass, mappings, inheritedMetas );
+	}
+
+	private static String getClassTableName(
+			PersistentClass model, Element node, String schema, String catalog, Table denormalizedSuperTable,
+			Mappings mappings
+	) {
+		Attribute tableNameNode = node.attribute( "table" );
+		String logicalTableName;
+		String physicalTableName;
+		if ( tableNameNode == null ) {
+			logicalTableName = StringHelper.unqualify( model.getEntityName() );
+			physicalTableName = mappings.getNamingStrategy().classToTableName( model.getEntityName() );
+		}
+		else {
+			logicalTableName = tableNameNode.getValue();
+			physicalTableName = mappings.getNamingStrategy().tableName( logicalTableName );
+		}
+		mappings.addTableBinding( schema, catalog, logicalTableName, physicalTableName, denormalizedSuperTable );
+		return physicalTableName;
+	}
+
+	public static void bindJoinedSubclass(Element node, JoinedSubclass joinedSubclass,
+			Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+
+		bindClass( node, joinedSubclass, mappings, inheritedMetas );
+		inheritedMetas = getMetas( node, inheritedMetas, true ); // get meta's from
+																	// <joined-subclass>
+
+		// joined subclasses
+		if ( joinedSubclass.getEntityPersisterClass() == null ) {
+			joinedSubclass.getRootClass()
+				.setEntityPersisterClass( JoinedSubclassEntityPersister.class );
+		}
+
+		Attribute schemaNode = node.attribute( "schema" );
+		String schema = schemaNode == null ?
+				mappings.getSchemaName() : schemaNode.getValue();
+
+		Attribute catalogNode = node.attribute( "catalog" );
+		String catalog = catalogNode == null ?
+				mappings.getCatalogName() : catalogNode.getValue();
+
+		Table mytable = mappings.addTable(
+				schema,
+				catalog,
+				getClassTableName( joinedSubclass, node, schema, catalog, null, mappings ),
+				getSubselect( node ),
+				false
+			);
+		joinedSubclass.setTable( mytable );
+		bindComment(mytable, node);
+
+		log.info(
+				"Mapping joined-subclass: " + joinedSubclass.getEntityName() +
+				" -> " + joinedSubclass.getTable().getName()
+			);
+
+		// KEY
+		Element keyNode = node.element( "key" );
+		SimpleValue key = new DependantValue( mytable, joinedSubclass.getIdentifier() );
+		joinedSubclass.setKey( key );
+		key.setCascadeDeleteEnabled( "cascade".equals( keyNode.attributeValue( "on-delete" ) ) );
+		bindSimpleValue( keyNode, key, false, joinedSubclass.getEntityName(), mappings );
+
+		// model.getKey().setType( new Type( model.getIdentifier() ) );
+		joinedSubclass.createPrimaryKey();
+		joinedSubclass.createForeignKey();
+
+		// CHECK
+		Attribute chNode = node.attribute( "check" );
+		if ( chNode != null ) mytable.addCheckConstraint( chNode.getValue() );
+
+		// properties
+		createClassProperties( node, joinedSubclass, mappings, inheritedMetas );
+
+	}
+
+	private static void bindJoin(Element node, Join join, Mappings mappings,
+			java.util.Map inheritedMetas) throws MappingException {
+
+		PersistentClass persistentClass = join.getPersistentClass();
+		String path = persistentClass.getEntityName();
+
+		// TABLENAME
+
+		Attribute schemaNode = node.attribute( "schema" );
+		String schema = schemaNode == null ?
+				mappings.getSchemaName() : schemaNode.getValue();
+		Attribute catalogNode = node.attribute( "catalog" );
+		String catalog = catalogNode == null ?
+				mappings.getCatalogName() : catalogNode.getValue();
+		Table primaryTable = persistentClass.getTable();
+		Table table = mappings.addTable(
+				schema,
+				catalog,
+				getClassTableName( persistentClass, node, schema, catalog, primaryTable, mappings ),
+				getSubselect( node ),
+				false
+			);
+		join.setTable( table );
+		bindComment(table, node);
+
+		Attribute fetchNode = node.attribute( "fetch" );
+		if ( fetchNode != null ) {
+			join.setSequentialSelect( "select".equals( fetchNode.getValue() ) );
+		}
+
+		Attribute invNode = node.attribute( "inverse" );
+		if ( invNode != null ) {
+			join.setInverse( "true".equals( invNode.getValue() ) );
+		}
+
+		Attribute nullNode = node.attribute( "optional" );
+		if ( nullNode != null ) {
+			join.setOptional( "true".equals( nullNode.getValue() ) );
+		}
+
+		log.info(
+				"Mapping class join: " + persistentClass.getEntityName() +
+				" -> " + join.getTable().getName()
+			);
+
+		// KEY
+		Element keyNode = node.element( "key" );
+		SimpleValue key = new DependantValue( table, persistentClass.getIdentifier() );
+		join.setKey( key );
+		key.setCascadeDeleteEnabled( "cascade".equals( keyNode.attributeValue( "on-delete" ) ) );
+		bindSimpleValue( keyNode, key, false, persistentClass.getEntityName(), mappings );
+
+		// join.getKey().setType( new Type( lazz.getIdentifier() ) );
+		join.createPrimaryKey();
+		join.createForeignKey();
+
+		// PROPERTIES
+		Iterator iter = node.elementIterator();
+		while ( iter.hasNext() ) {
+			Element subnode = (Element) iter.next();
+			String name = subnode.getName();
+			String propertyName = subnode.attributeValue( "name" );
+
+			Value value = null;
+			if ( "many-to-one".equals( name ) ) {
+				value = new ManyToOne( table );
+				bindManyToOne( subnode, (ManyToOne) value, propertyName, true, mappings );
+			}
+			else if ( "any".equals( name ) ) {
+				value = new Any( table );
+				bindAny( subnode, (Any) value, true, mappings );
+			}
+			else if ( "property".equals( name ) ) {
+				value = new SimpleValue( table );
+				bindSimpleValue( subnode, (SimpleValue) value, true, propertyName, mappings );
+			}
+			else if ( "component".equals( name ) || "dynamic-component".equals( name ) ) {
+				String subpath = StringHelper.qualify( path, propertyName );
+				value = new Component( join );
+				bindComponent(
+						subnode,
+						(Component) value,
+						join.getPersistentClass().getClassName(),
+						propertyName,
+						subpath,
+						true,
+						false,
+						mappings,
+						inheritedMetas,
+						false
+					);
+			}
+
+			if ( value != null ) {
+				Property prop = createProperty( value, propertyName, persistentClass
+					.getEntityName(), subnode, mappings, inheritedMetas );
+				prop.setOptional( join.isOptional() );
+				join.addProperty( prop );
+			}
+
+		}
+
+		// CUSTOM SQL
+		handleCustomSQL( node, join );
+
+	}
+
+	public static void bindColumns(final Element node, final SimpleValue simpleValue,
+			final boolean isNullable, final boolean autoColumn, final String propertyPath,
+			final Mappings mappings) throws MappingException {
+
+		Table table = simpleValue.getTable();
+
+		// COLUMN(S)
+		Attribute columnAttribute = node.attribute( "column" );
+		if ( columnAttribute == null ) {
+			Iterator iter = node.elementIterator();
+			int count = 0;
+			while ( iter.hasNext() ) {
+				Element columnElement = (Element) iter.next();
+				if ( columnElement.getName().equals( "column" ) ) {
+					Column column = new Column();
+					column.setValue( simpleValue );
+					column.setTypeIndex( count++ );
+					bindColumn( columnElement, column, isNullable );
+					String logicalColumnName = mappings.getNamingStrategy().logicalColumnName(
+							columnElement.attributeValue( "name" ), propertyPath
+					);
+					column.setName( mappings.getNamingStrategy().columnName(
+						logicalColumnName ) );
+					if ( table != null ) {
+						table.addColumn( column ); // table=null -> an association
+						                           // - fill it in later
+						//TODO fill in the mappings for table == null
+						mappings.addColumnBinding( logicalColumnName, column, table );
+					}
+
+
+					simpleValue.addColumn( column );
+					// column index
+					bindIndex( columnElement.attribute( "index" ), table, column, mappings );
+					bindIndex( node.attribute( "index" ), table, column, mappings );
+					//column unique-key
+					bindUniqueKey( columnElement.attribute( "unique-key" ), table, column, mappings );
+					bindUniqueKey( node.attribute( "unique-key" ), table, column, mappings );
+				}
+				else if ( columnElement.getName().equals( "formula" ) ) {
+					Formula formula = new Formula();
+					formula.setFormula( columnElement.getText() );
+					simpleValue.addFormula( formula );
+				}
+			}
+		}
+		else {
+			if ( node.elementIterator( "column" ).hasNext() ) {
+				throw new MappingException(
+					"column attribute may not be used together with <column> subelement" );
+			}
+			if ( node.elementIterator( "formula" ).hasNext() ) {
+				throw new MappingException(
+					"column attribute may not be used together with <formula> subelement" );
+			}
+
+			Column column = new Column();
+			column.setValue( simpleValue );
+			bindColumn( node, column, isNullable );
+			String logicalColumnName = mappings.getNamingStrategy().logicalColumnName(
+					columnAttribute.getValue(), propertyPath
+			);
+			column.setName( mappings.getNamingStrategy().columnName( logicalColumnName ) );
+			if ( table != null ) {
+				table.addColumn( column ); // table=null -> an association - fill
+				                           // it in later
+				//TODO fill in the mappings for table == null
+				mappings.addColumnBinding( logicalColumnName, column, table );
+			}
+			simpleValue.addColumn( column );
+			bindIndex( node.attribute( "index" ), table, column, mappings );
+			bindUniqueKey( node.attribute( "unique-key" ), table, column, mappings );
+		}
+
+		if ( autoColumn && simpleValue.getColumnSpan() == 0 ) {
+			Column column = new Column();
+			column.setValue( simpleValue );
+			bindColumn( node, column, isNullable );
+			column.setName( mappings.getNamingStrategy().propertyToColumnName( propertyPath ) );
+			String logicalName = mappings.getNamingStrategy().logicalColumnName( null, propertyPath );
+			mappings.addColumnBinding( logicalName, column, table );
+			/* TODO: joinKeyColumnName & foreignKeyColumnName should be called either here or at a
+			 * slightly higer level in the stack (to get all the information we need)
+			 * Right now HbmBinder does not support the
+			 */
+			simpleValue.getTable().addColumn( column );
+			simpleValue.addColumn( column );
+			bindIndex( node.attribute( "index" ), table, column, mappings );
+			bindUniqueKey( node.attribute( "unique-key" ), table, column, mappings );
+		}
+
+	}
+
+	private static void bindIndex(Attribute indexAttribute, Table table, Column column, Mappings mappings) {
+		if ( indexAttribute != null && table != null ) {
+			StringTokenizer tokens = new StringTokenizer( indexAttribute.getValue(), ", " );
+			while ( tokens.hasMoreTokens() ) {
+				table.getOrCreateIndex( tokens.nextToken() ).addColumn( column );
+			}
+		}
+	}
+
+	private static void bindUniqueKey(Attribute uniqueKeyAttribute, Table table, Column column, Mappings mappings) {
+		if ( uniqueKeyAttribute != null && table != null ) {
+			StringTokenizer tokens = new StringTokenizer( uniqueKeyAttribute.getValue(), ", " );
+			while ( tokens.hasMoreTokens() ) {
+				table.getOrCreateUniqueKey( tokens.nextToken() ).addColumn( column );
+			}
+		}
+	}
+
+	// automatically makes a column with the default name if none is specifed by XML
+	public static void bindSimpleValue(Element node, SimpleValue simpleValue, boolean isNullable,
+			String path, Mappings mappings) throws MappingException {
+		bindSimpleValueType( node, simpleValue, mappings );
+
+		bindColumnsOrFormula( node, simpleValue, path, isNullable, mappings );
+
+		Attribute fkNode = node.attribute( "foreign-key" );
+		if ( fkNode != null ) simpleValue.setForeignKeyName( fkNode.getValue() );
+	}
+
+	private static void bindSimpleValueType(Element node, SimpleValue simpleValue, Mappings mappings)
+			throws MappingException {
+		String typeName = null;
+
+		Properties parameters = new Properties();
+
+		Attribute typeNode = node.attribute( "type" );
+		if ( typeNode == null ) typeNode = node.attribute( "id-type" ); // for an any
+		if ( typeNode != null ) typeName = typeNode.getValue();
+
+		Element typeChild = node.element( "type" );
+		if ( typeName == null && typeChild != null ) {
+			typeName = typeChild.attribute( "name" ).getValue();
+			Iterator typeParameters = typeChild.elementIterator( "param" );
+
+			while ( typeParameters.hasNext() ) {
+				Element paramElement = (Element) typeParameters.next();
+				parameters.setProperty(
+						paramElement.attributeValue( "name" ),
+						paramElement.getTextTrim()
+					);
+			}
+		}
+
+		TypeDef typeDef = mappings.getTypeDef( typeName );
+		if ( typeDef != null ) {
+			typeName = typeDef.getTypeClass();
+			// parameters on the property mapping should
+			// override parameters in the typedef
+			Properties allParameters = new Properties();
+			allParameters.putAll( typeDef.getParameters() );
+			allParameters.putAll( parameters );
+			parameters = allParameters;
+		}
+
+		if ( !parameters.isEmpty() ) simpleValue.setTypeParameters( parameters );
+
+		if ( typeName != null ) simpleValue.setTypeName( typeName );
+	}
+
+	public static void bindProperty(
+			Element node,
+	        Property property,
+	        Mappings mappings,
+			java.util.Map inheritedMetas) throws MappingException {
+
+		String propName = node.attributeValue( "name" );
+		property.setName( propName );
+		String nodeName = node.attributeValue( "node" );
+		if (nodeName==null) nodeName = propName;
+		property.setNodeName( nodeName );
+
+		// TODO:
+		//Type type = model.getValue().getType();
+		//if (type==null) throw new MappingException(
+		//"Could not determine a property type for: " + model.getName() );
+
+		Attribute accessNode = node.attribute( "access" );
+		if ( accessNode != null ) {
+			property.setPropertyAccessorName( accessNode.getValue() );
+		}
+		else if ( node.getName().equals( "properties" ) ) {
+			property.setPropertyAccessorName( "embedded" );
+		}
+		else {
+			property.setPropertyAccessorName( mappings.getDefaultAccess() );
+		}
+
+		Attribute cascadeNode = node.attribute( "cascade" );
+		property.setCascade( cascadeNode == null ? mappings.getDefaultCascade() : cascadeNode
+			.getValue() );
+
+		Attribute updateNode = node.attribute( "update" );
+		property.setUpdateable( updateNode == null || "true".equals( updateNode.getValue() ) );
+
+		Attribute insertNode = node.attribute( "insert" );
+		property.setInsertable( insertNode == null || "true".equals( insertNode.getValue() ) );
+
+		Attribute lockNode = node.attribute( "optimistic-lock" );
+		property.setOptimisticLocked( lockNode == null || "true".equals( lockNode.getValue() ) );
+
+		Attribute generatedNode = node.attribute( "generated" );
+        String generationName = generatedNode == null ? null : generatedNode.getValue();
+        PropertyGeneration generation = PropertyGeneration.parse( generationName );
+		property.setGeneration( generation );
+
+        if ( generation == PropertyGeneration.ALWAYS || generation == PropertyGeneration.INSERT ) {
+	        // generated properties can *never* be insertable...
+	        if ( property.isInsertable() ) {
+		        if ( insertNode == null ) {
+			        // insertable simply because that is the user did not specify
+			        // anything; just override it
+					property.setInsertable( false );
+		        }
+		        else {
+			        // the user specifically supplied insert="true",
+			        // which constitutes an illegal combo
+					throw new MappingException(
+							"cannot specify both insert=\"true\" and generated=\"" + generation.getName() +
+							"\" for property: " +
+							propName
+					);
+		        }
+	        }
+
+	        // properties generated on update can never be updateable...
+	        if ( property.isUpdateable() && generation == PropertyGeneration.ALWAYS ) {
+		        if ( updateNode == null ) {
+			        // updateable only because the user did not specify 
+			        // anything; just override it
+			        property.setUpdateable( false );
+		        }
+		        else {
+			        // the user specifically supplied update="true",
+			        // which constitutes an illegal combo
+					throw new MappingException(
+							"cannot specify both update=\"true\" and generated=\"" + generation.getName() +
+							"\" for property: " +
+							propName
+					);
+		        }
+	        }
+        }
+
+		boolean isLazyable = "property".equals( node.getName() ) ||
+				"component".equals( node.getName() ) ||
+				"many-to-one".equals( node.getName() ) ||
+				"one-to-one".equals( node.getName() ) ||
+				"any".equals( node.getName() );
+		if ( isLazyable ) {
+			Attribute lazyNode = node.attribute( "lazy" );
+			property.setLazy( lazyNode != null && "true".equals( lazyNode.getValue() ) );
+		}
+
+		if ( log.isDebugEnabled() ) {
+			String msg = "Mapped property: " + property.getName();
+			String columns = columns( property.getValue() );
+			if ( columns.length() > 0 ) msg += " -> " + columns;
+			// TODO: this fails if we run with debug on!
+			// if ( model.getType()!=null ) msg += ", type: " + model.getType().getName();
+			log.debug( msg );
+		}
+
+		property.setMetaAttributes( getMetas( node, inheritedMetas ) );
+
+	}
+
+	private static String columns(Value val) {
+		StringBuffer columns = new StringBuffer();
+		Iterator iter = val.getColumnIterator();
+		while ( iter.hasNext() ) {
+			columns.append( ( (Selectable) iter.next() ).getText() );
+			if ( iter.hasNext() ) columns.append( ", " );
+		}
+		return columns.toString();
+	}
+
+	/**
+	 * Called for all collections
+	 */
+	public static void bindCollection(Element node, Collection collection, String className,
+			String path, Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+
+		// ROLENAME
+		collection.setRole(path);
+
+		Attribute inverseNode = node.attribute( "inverse" );
+		if ( inverseNode != null ) {
+			collection.setInverse( "true".equals( inverseNode.getValue() ) );
+		}
+
+		Attribute mutableNode = node.attribute( "mutable" );
+		if ( mutableNode != null ) {
+			collection.setMutable( !"false".equals( mutableNode.getValue() ) );
+		}
+
+		Attribute olNode = node.attribute( "optimistic-lock" );
+		collection.setOptimisticLocked( olNode == null || "true".equals( olNode.getValue() ) );
+
+		Attribute orderNode = node.attribute( "order-by" );
+		if ( orderNode != null ) {
+			if ( Environment.jvmSupportsLinkedHashCollections() || ( collection instanceof Bag ) ) {
+				collection.setOrderBy( orderNode.getValue() );
+			}
+			else {
+				log.warn( "Attribute \"order-by\" ignored in JDK1.3 or less" );
+			}
+		}
+		Attribute whereNode = node.attribute( "where" );
+		if ( whereNode != null ) {
+			collection.setWhere( whereNode.getValue() );
+		}
+		Attribute batchNode = node.attribute( "batch-size" );
+		if ( batchNode != null ) {
+			collection.setBatchSize( Integer.parseInt( batchNode.getValue() ) );
+		}
+
+		String nodeName = node.attributeValue( "node" );
+		if ( nodeName == null ) nodeName = node.attributeValue( "name" );
+		collection.setNodeName( nodeName );
+		String embed = node.attributeValue( "embed-xml" );
+		collection.setEmbedded( embed==null || "true".equals(embed) );
+
+
+		// PERSISTER
+		Attribute persisterNode = node.attribute( "persister" );
+		if ( persisterNode != null ) {
+			try {
+				collection.setCollectionPersisterClass( ReflectHelper.classForName( persisterNode
+					.getValue() ) );
+			}
+			catch (ClassNotFoundException cnfe) {
+				throw new MappingException( "Could not find collection persister class: "
+					+ persisterNode.getValue() );
+			}
+		}
+
+		Attribute typeNode = node.attribute( "collection-type" );
+		if ( typeNode != null ) {
+			String typeName = typeNode.getValue();
+			TypeDef typeDef = mappings.getTypeDef( typeName );
+			if ( typeDef != null ) {
+				collection.setTypeName( typeDef.getTypeClass() );
+				collection.setTypeParameters( typeDef.getParameters() );
+			}
+			else {
+				collection.setTypeName( typeName );
+			}
+		}
+
+		// FETCH STRATEGY
+
+		initOuterJoinFetchSetting( node, collection );
+
+		if ( "subselect".equals( node.attributeValue("fetch") ) ) {
+			collection.setSubselectLoadable(true);
+			collection.getOwner().setSubselectLoadableCollections(true);
+		}
+
+		initLaziness( node, collection, mappings, "true", mappings.isDefaultLazy() );
+		//TODO: suck this into initLaziness!
+		if ( "extra".equals( node.attributeValue("lazy") ) ) {
+			collection.setLazy(true);
+			collection.setExtraLazy(true);
+		}
+
+		Element oneToManyNode = node.element( "one-to-many" );
+		if ( oneToManyNode != null ) {
+			OneToMany oneToMany = new OneToMany( collection.getOwner() );
+			collection.setElement( oneToMany );
+			bindOneToMany( oneToManyNode, oneToMany, mappings );
+			// we have to set up the table later!! yuck
+		}
+		else {
+			// TABLE
+			Attribute tableNode = node.attribute( "table" );
+			String tableName;
+			if ( tableNode != null ) {
+				tableName = mappings.getNamingStrategy().tableName( tableNode.getValue() );
+			}
+			else {
+				//tableName = mappings.getNamingStrategy().propertyToTableName( className, path );
+				Table ownerTable = collection.getOwner().getTable();
+				//TODO mappings.getLogicalTableName(ownerTable)
+				String logicalOwnerTableName = ownerTable.getName();
+				//FIXME we don't have the associated entity table name here, has to be done in a second pass
+				tableName = mappings.getNamingStrategy().collectionTableName(
+						collection.getOwner().getEntityName(),
+						logicalOwnerTableName ,
+						null,
+						null,
+						path
+				);
+			}
+			Attribute schemaNode = node.attribute( "schema" );
+			String schema = schemaNode == null ?
+					mappings.getSchemaName() : schemaNode.getValue();
+
+			Attribute catalogNode = node.attribute( "catalog" );
+			String catalog = catalogNode == null ?
+					mappings.getCatalogName() : catalogNode.getValue();
+
+			Table table = mappings.addTable(
+					schema,
+					catalog,
+					tableName,
+					getSubselect( node ),
+					false
+				);
+			collection.setCollectionTable( table );
+			bindComment(table, node);
+
+			log.info(
+					"Mapping collection: " + collection.getRole() +
+					" -> " + collection.getCollectionTable().getName()
+				);
+		}
+
+		// SORT
+		Attribute sortedAtt = node.attribute( "sort" );
+		// unsorted, natural, comparator.class.name
+		if ( sortedAtt == null || sortedAtt.getValue().equals( "unsorted" ) ) {
+			collection.setSorted( false );
+		}
+		else {
+			collection.setSorted( true );
+			String comparatorClassName = sortedAtt.getValue();
+			if ( !comparatorClassName.equals( "natural" ) ) {
+				collection.setComparatorClassName(comparatorClassName);
+			}
+		}
+
+		// ORPHAN DELETE (used for programmer error detection)
+		Attribute cascadeAtt = node.attribute( "cascade" );
+		if ( cascadeAtt != null && cascadeAtt.getValue().indexOf( "delete-orphan" ) >= 0 ) {
+			collection.setOrphanDelete( true );
+		}
+
+		// CUSTOM SQL
+		handleCustomSQL( node, collection );
+		// set up second pass
+		if ( collection instanceof List ) {
+			mappings.addSecondPass( new ListSecondPass( node, mappings, (List) collection, inheritedMetas ) );
+		}
+		else if ( collection instanceof Map ) {
+			mappings.addSecondPass( new MapSecondPass( node, mappings, (Map) collection, inheritedMetas ) );
+		}
+		else if ( collection instanceof IdentifierCollection ) {
+			mappings.addSecondPass( new IdentifierCollectionSecondPass(
+					node,
+					mappings,
+					collection,
+					inheritedMetas
+				) );
+		}
+		else {
+			mappings.addSecondPass( new CollectionSecondPass( node, mappings, collection, inheritedMetas ) );
+		}
+
+		Iterator iter = node.elementIterator( "filter" );
+		while ( iter.hasNext() ) {
+			final Element filter = (Element) iter.next();
+			parseFilter( filter, collection, mappings );
+		}
+
+		Iterator tables = node.elementIterator( "synchronize" );
+		while ( tables.hasNext() ) {
+			collection.getSynchronizedTables().add(
+				( (Element) tables.next() ).attributeValue( "table" ) );
+		}
+
+		Element element = node.element( "loader" );
+		if ( element != null ) {
+			collection.setLoaderName( element.attributeValue( "query-ref" ) );
+		}
+
+		collection.setReferencedPropertyName( node.element( "key" ).attributeValue( "property-ref" ) );
+	}
+
+	private static void initLaziness(
+			Element node,
+			Fetchable fetchable,
+			Mappings mappings,
+			String proxyVal,
+			boolean defaultLazy
+	) {
+		Attribute lazyNode = node.attribute( "lazy" );
+		boolean isLazyTrue = lazyNode == null ?
+				defaultLazy && fetchable.isLazy() : //fetch="join" overrides default laziness
+				lazyNode.getValue().equals(proxyVal); //fetch="join" overrides default laziness
+		fetchable.setLazy( isLazyTrue );
+	}
+
+	private static void initLaziness(
+			Element node,
+			ToOne fetchable,
+			Mappings mappings,
+			boolean defaultLazy
+	) {
+		if ( "no-proxy".equals( node.attributeValue( "lazy" ) ) ) {
+			fetchable.setUnwrapProxy(true);
+			fetchable.setLazy(true);
+			//TODO: better to degrade to lazy="false" if uninstrumented
+		}
+		else {
+			initLaziness(node, fetchable, mappings, "proxy", defaultLazy);
+		}
+	}
+
+	private static void bindColumnsOrFormula(Element node, SimpleValue simpleValue, String path,
+			boolean isNullable, Mappings mappings) {
+		Attribute formulaNode = node.attribute( "formula" );
+		if ( formulaNode != null ) {
+			Formula f = new Formula();
+			f.setFormula( formulaNode.getText() );
+			simpleValue.addFormula( f );
+		}
+		else {
+			bindColumns( node, simpleValue, isNullable, true, path, mappings );
+		}
+	}
+
+	private static void bindComment(Table table, Element node) {
+		Element comment = node.element("comment");
+		if (comment!=null) table.setComment( comment.getTextTrim() );
+	}
+
+	public static void bindManyToOne(Element node, ManyToOne manyToOne, String path,
+			boolean isNullable, Mappings mappings) throws MappingException {
+
+		bindColumnsOrFormula( node, manyToOne, path, isNullable, mappings );
+		initOuterJoinFetchSetting( node, manyToOne );
+		initLaziness( node, manyToOne, mappings, true );
+
+		Attribute ukName = node.attribute( "property-ref" );
+		if ( ukName != null ) {
+			manyToOne.setReferencedPropertyName( ukName.getValue() );
+		}
+
+		manyToOne.setReferencedEntityName( getEntityName( node, mappings ) );
+
+		String embed = node.attributeValue( "embed-xml" );
+		manyToOne.setEmbedded( embed == null || "true".equals( embed ) );
+
+		String notFound = node.attributeValue( "not-found" );
+		manyToOne.setIgnoreNotFound( "ignore".equals( notFound ) );
+
+		if( ukName != null && !manyToOne.isIgnoreNotFound() ) {
+			if ( !node.getName().equals("many-to-many") ) { //TODO: really bad, evil hack to fix!!!
+				mappings.addSecondPass( new ManyToOneSecondPass(manyToOne) );
+			}
+		}
+
+		Attribute fkNode = node.attribute( "foreign-key" );
+		if ( fkNode != null ) manyToOne.setForeignKeyName( fkNode.getValue() );
+
+		validateCascade( node, path );
+	}
+
+	private static void validateCascade(Element node, String path) {
+		String cascade = node.attributeValue("cascade");
+		if ( cascade!=null && cascade.indexOf("delete-orphan")>0 ) {
+			throw new MappingException("single-valued associations do not support orphan delete: " + path);
+		}
+	}
+
+	public static void bindAny(Element node, Any any, boolean isNullable, Mappings mappings)
+			throws MappingException {
+		any.setIdentifierType( getTypeFromXML( node ) );
+		Attribute metaAttribute = node.attribute( "meta-type" );
+		if ( metaAttribute != null ) {
+			any.setMetaType( metaAttribute.getValue() );
+
+			Iterator iter = node.elementIterator( "meta-value" );
+			if ( iter.hasNext() ) {
+				HashMap values = new HashMap();
+				org.hibernate.type.Type metaType = TypeFactory.heuristicType( any.getMetaType() );
+				while ( iter.hasNext() ) {
+					Element metaValue = (Element) iter.next();
+					try {
+						Object value = ( (DiscriminatorType) metaType ).stringToObject( metaValue
+							.attributeValue( "value" ) );
+						String entityName = getClassName( metaValue.attribute( "class" ), mappings );
+						values.put( value, entityName );
+					}
+					catch (ClassCastException cce) {
+						throw new MappingException( "meta-type was not a DiscriminatorType: "
+							+ metaType.getName() );
+					}
+					catch (Exception e) {
+						throw new MappingException( "could not interpret meta-value", e );
+					}
+				}
+				any.setMetaValues( values );
+			}
+
+		}
+
+		bindColumns( node, any, isNullable, false, null, mappings );
+	}
+
+	public static void bindOneToOne(Element node, OneToOne oneToOne, String path, boolean isNullable,
+			Mappings mappings) throws MappingException {
+
+		bindColumns( node, oneToOne, isNullable, false, null, mappings );
+
+		Attribute constrNode = node.attribute( "constrained" );
+		boolean constrained = constrNode != null && constrNode.getValue().equals( "true" );
+		oneToOne.setConstrained( constrained );
+
+		oneToOne.setForeignKeyType( constrained ?
+				ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT :
+				ForeignKeyDirection.FOREIGN_KEY_TO_PARENT );
+
+		initOuterJoinFetchSetting( node, oneToOne );
+		initLaziness( node, oneToOne, mappings, true );
+
+		oneToOne.setEmbedded( "true".equals( node.attributeValue( "embed-xml" ) ) );
+
+		Attribute fkNode = node.attribute( "foreign-key" );
+		if ( fkNode != null ) oneToOne.setForeignKeyName( fkNode.getValue() );
+
+		Attribute ukName = node.attribute( "property-ref" );
+		if ( ukName != null ) oneToOne.setReferencedPropertyName( ukName.getValue() );
+
+		oneToOne.setPropertyName( node.attributeValue( "name" ) );
+
+		oneToOne.setReferencedEntityName( getEntityName( node, mappings ) );
+
+		validateCascade( node, path );
+	}
+
+	public static void bindOneToMany(Element node, OneToMany oneToMany, Mappings mappings)
+			throws MappingException {
+
+		oneToMany.setReferencedEntityName( getEntityName( node, mappings ) );
+
+		String embed = node.attributeValue( "embed-xml" );
+		oneToMany.setEmbedded( embed == null || "true".equals( embed ) );
+
+		String notFound = node.attributeValue( "not-found" );
+		oneToMany.setIgnoreNotFound( "ignore".equals( notFound ) );
+
+	}
+
+	public static void bindColumn(Element node, Column column, boolean isNullable) {
+		Attribute lengthNode = node.attribute( "length" );
+		if ( lengthNode != null ) column.setLength( Integer.parseInt( lengthNode.getValue() ) );
+		Attribute scalNode = node.attribute( "scale" );
+		if ( scalNode != null ) column.setScale( Integer.parseInt( scalNode.getValue() ) );
+		Attribute precNode = node.attribute( "precision" );
+		if ( precNode != null ) column.setPrecision( Integer.parseInt( precNode.getValue() ) );
+
+		Attribute nullNode = node.attribute( "not-null" );
+		column.setNullable( nullNode == null ? isNullable : nullNode.getValue().equals( "false" ) );
+
+		Attribute unqNode = node.attribute( "unique" );
+		if ( unqNode != null ) column.setUnique( unqNode.getValue().equals( "true" ) );
+
+		column.setCheckConstraint( node.attributeValue( "check" ) );
+		column.setDefaultValue( node.attributeValue( "default" ) );
+
+		Attribute typeNode = node.attribute( "sql-type" );
+		if ( typeNode != null ) column.setSqlType( typeNode.getValue() );
+
+		Element comment = node.element("comment");
+		if (comment!=null) column.setComment( comment.getTextTrim() );
+
+	}
+
+	/**
+	 * Called for arrays and primitive arrays
+	 */
+	public static void bindArray(Element node, Array array, String prefix, String path,
+			Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+
+		bindCollection( node, array, prefix, path, mappings, inheritedMetas );
+
+		Attribute att = node.attribute( "element-class" );
+		if ( att != null ) array.setElementClassName( getClassName( att, mappings ) );
+
+	}
+
+	private static Class reflectedPropertyClass(String className, String propertyName)
+			throws MappingException {
+		if ( className == null ) return null;
+		return ReflectHelper.reflectedPropertyClass( className, propertyName );
+	}
+
+	public static void bindComposite(Element node, Component component, String path,
+			boolean isNullable, Mappings mappings, java.util.Map inheritedMetas)
+			throws MappingException {
+		bindComponent(
+				node,
+				component,
+				null,
+				null,
+				path,
+				isNullable,
+				false,
+				mappings,
+				inheritedMetas,
+				false
+			);
+	}
+
+	public static void bindCompositeId(Element node, Component component,
+			PersistentClass persistentClass, String propertyName, Mappings mappings,
+			java.util.Map inheritedMetas) throws MappingException {
+
+		component.setKey( true );
+
+		String path = StringHelper.qualify(
+				persistentClass.getEntityName(),
+				propertyName == null ? "id" : propertyName );
+
+		bindComponent(
+				node,
+				component,
+				persistentClass.getClassName(),
+				propertyName,
+				path,
+				false,
+				node.attribute( "class" ) == null
+						&& propertyName == null,
+				mappings,
+				inheritedMetas,
+				false
+			);
+
+		if ( "true".equals( node.attributeValue("mapped") ) ) {
+			if ( propertyName!=null ) {
+				throw new MappingException("cannot combine mapped=\"true\" with specified name");
+			}
+			Component mapper = new Component(persistentClass);
+			bindComponent(
+					node,
+					mapper,
+					persistentClass.getClassName(),
+					null,
+					path,
+					false,
+					true,
+					mappings,
+					inheritedMetas,
+					true
+				);
+			persistentClass.setIdentifierMapper(mapper);
+			Property property = new Property();
+			property.setName("_identifierMapper");
+			property.setNodeName("id");
+			property.setUpdateable(false);
+			property.setInsertable(false);
+			property.setValue(mapper);
+			property.setPropertyAccessorName( "embedded" );
+			persistentClass.addProperty(property);
+		}
+
+	}
+
+	public static void bindComponent(
+			Element node,
+			Component component,
+			String ownerClassName,
+			String parentProperty,
+			String path,
+			boolean isNullable,
+			boolean isEmbedded,
+			Mappings mappings,
+			java.util.Map inheritedMetas,
+			boolean isIdentifierMapper) throws MappingException {
+
+		component.setEmbedded( isEmbedded );
+		component.setRoleName( path );
+
+		inheritedMetas = getMetas( node, inheritedMetas );
+		component.setMetaAttributes( inheritedMetas );
+
+		Attribute classNode = isIdentifierMapper ? null : node.attribute( "class" );
+		if ( classNode != null ) {
+			component.setComponentClassName( getClassName( classNode, mappings ) );
+		}
+		else if ( "dynamic-component".equals( node.getName() ) ) {
+			component.setDynamic( true );
+		}
+		else if ( isEmbedded ) {
+			// an "embedded" component (composite ids and unique)
+			// note that this does not handle nested components
+			if ( component.getOwner().hasPojoRepresentation() ) {
+				component.setComponentClassName( component.getOwner().getClassName() );
+			}
+			else {
+				component.setDynamic(true);
+			}
+		}
+		else {
+			// todo : again, how *should* this work for non-pojo entities?
+			if ( component.getOwner().hasPojoRepresentation() ) {
+				Class reflectedClass = reflectedPropertyClass( ownerClassName, parentProperty );
+				if ( reflectedClass != null ) {
+					component.setComponentClassName( reflectedClass.getName() );
+				}
+			}
+			else {
+				component.setDynamic(true);
+			}
+		}
+
+		String nodeName = node.attributeValue( "node" );
+		if ( nodeName == null ) nodeName = node.attributeValue( "name" );
+		if ( nodeName == null ) nodeName = component.getOwner().getNodeName();
+		component.setNodeName( nodeName );
+
+		Iterator iter = node.elementIterator();
+		while ( iter.hasNext() ) {
+
+			Element subnode = (Element) iter.next();
+			String name = subnode.getName();
+			String propertyName = getPropertyName( subnode );
+			String subpath = propertyName == null ? null : StringHelper
+				.qualify( path, propertyName );
+
+			CollectionType collectType = CollectionType.collectionTypeFromString( name );
+			Value value = null;
+			if ( collectType != null ) {
+				Collection collection = collectType.create(
+						subnode,
+						subpath,
+						component.getOwner(),
+						mappings, inheritedMetas
+					);
+				mappings.addCollection( collection );
+				value = collection;
+			}
+			else if ( "many-to-one".equals( name ) || "key-many-to-one".equals( name ) ) {
+				value = new ManyToOne( component.getTable() );
+				String relativePath;
+				if (isEmbedded) {
+					relativePath = propertyName;
+				}
+				else {
+					relativePath = subpath.substring( component.getOwner().getEntityName().length() + 1 );
+				}
+				bindManyToOne( subnode, (ManyToOne) value, relativePath, isNullable, mappings );
+			}
+			else if ( "one-to-one".equals( name ) ) {
+				value = new OneToOne( component.getTable(), component.getOwner() );
+				String relativePath;
+				if (isEmbedded) {
+					relativePath = propertyName;
+				}
+				else {
+					relativePath = subpath.substring( component.getOwner().getEntityName().length() + 1 );
+				}
+				bindOneToOne( subnode, (OneToOne) value, relativePath, isNullable, mappings );
+			}
+			else if ( "any".equals( name ) ) {
+				value = new Any( component.getTable() );
+				bindAny( subnode, (Any) value, isNullable, mappings );
+			}
+			else if ( "property".equals( name ) || "key-property".equals( name ) ) {
+				value = new SimpleValue( component.getTable() );
+				String relativePath;
+				if (isEmbedded) {
+					relativePath = propertyName;
+				}
+				else {
+					relativePath = subpath.substring( component.getOwner().getEntityName().length() + 1 );
+				}
+				bindSimpleValue( subnode, (SimpleValue) value, isNullable, relativePath, mappings );
+			}
+			else if ( "component".equals( name )
+				|| "dynamic-component".equals( name )
+				|| "nested-composite-element".equals( name ) ) {
+				value = new Component( component ); // a nested composite element
+				bindComponent(
+						subnode,
+						(Component) value,
+						component.getComponentClassName(),
+						propertyName,
+						subpath,
+						isNullable,
+						isEmbedded,
+						mappings,
+						inheritedMetas,
+						isIdentifierMapper
+					);
+			}
+			else if ( "parent".equals( name ) ) {
+				component.setParentProperty( propertyName );
+			}
+
+			if ( value != null ) {
+				Property property = createProperty( value, propertyName, component
+					.getComponentClassName(), subnode, mappings, inheritedMetas );
+				if (isIdentifierMapper) {
+					property.setInsertable(false);
+					property.setUpdateable(false);
+				}
+				component.addProperty( property );
+			}
+		}
+
+		if ( "true".equals( node.attributeValue( "unique" ) ) ) {
+			iter = component.getColumnIterator();
+			ArrayList cols = new ArrayList();
+			while ( iter.hasNext() ) {
+				cols.add( iter.next() );
+			}
+			component.getOwner().getTable().createUniqueKey( cols );
+		}
+
+		iter = node.elementIterator( "tuplizer" );
+		while ( iter.hasNext() ) {
+			final Element tuplizerElem = ( Element ) iter.next();
+			EntityMode mode = EntityMode.parse( tuplizerElem.attributeValue( "entity-mode" ) );
+			component.addTuplizer( mode, tuplizerElem.attributeValue( "class" ) );
+		}
+	}
+
+	public static String getTypeFromXML(Element node) throws MappingException {
+		// TODO: handle TypeDefs
+		Attribute typeNode = node.attribute( "type" );
+		if ( typeNode == null ) typeNode = node.attribute( "id-type" ); // for an any
+		if ( typeNode == null ) return null; // we will have to use reflection
+		return typeNode.getValue();
+	}
+
+	private static void initOuterJoinFetchSetting(Element node, Fetchable model) {
+		Attribute fetchNode = node.attribute( "fetch" );
+		final FetchMode fetchStyle;
+		boolean lazy = true;
+		if ( fetchNode == null ) {
+			Attribute jfNode = node.attribute( "outer-join" );
+			if ( jfNode == null ) {
+				if ( "many-to-many".equals( node.getName() ) ) {
+					//NOTE SPECIAL CASE:
+					// default to join and non-lazy for the "second join"
+					// of the many-to-many
+					lazy = false;
+					fetchStyle = FetchMode.JOIN;
+				}
+				else if ( "one-to-one".equals( node.getName() ) ) {
+					//NOTE SPECIAL CASE:
+					// one-to-one constrained=false cannot be proxied,
+					// so default to join and non-lazy
+					lazy = ( (OneToOne) model ).isConstrained();
+					fetchStyle = lazy ? FetchMode.DEFAULT : FetchMode.JOIN;
+				}
+				else {
+					fetchStyle = FetchMode.DEFAULT;
+				}
+			}
+			else {
+				// use old (HB 2.1) defaults if outer-join is specified
+				String eoj = jfNode.getValue();
+				if ( "auto".equals( eoj ) ) {
+					fetchStyle = FetchMode.DEFAULT;
+				}
+				else {
+					boolean join = "true".equals( eoj );
+					fetchStyle = join ? FetchMode.JOIN : FetchMode.SELECT;
+				}
+			}
+		}
+		else {
+			boolean join = "join".equals( fetchNode.getValue() );
+			//lazy = !join;
+			fetchStyle = join ? FetchMode.JOIN : FetchMode.SELECT;
+		}
+		model.setFetchMode( fetchStyle );
+		model.setLazy(lazy);
+	}
+
+	private static void makeIdentifier(Element node, SimpleValue model, Mappings mappings) {
+
+		// GENERATOR
+		Element subnode = node.element( "generator" );
+		if ( subnode != null ) {
+			model.setIdentifierGeneratorStrategy( subnode.attributeValue( "class" ) );
+
+			Properties params = new Properties();
+
+			if ( mappings.getSchemaName() != null ) {
+				params.setProperty( PersistentIdentifierGenerator.SCHEMA, mappings.getSchemaName() );
+			}
+			if ( mappings.getCatalogName() != null ) {
+				params.setProperty( PersistentIdentifierGenerator.CATALOG, mappings.getCatalogName() );
+			}
+
+			Iterator iter = subnode.elementIterator( "param" );
+			while ( iter.hasNext() ) {
+				Element childNode = (Element) iter.next();
+				params.setProperty( childNode.attributeValue( "name" ), childNode.getText() );
+			}
+
+			model.setIdentifierGeneratorProperties( params );
+		}
+
+		model.getTable().setIdentifierValue( model );
+
+		// ID UNSAVED-VALUE
+		Attribute nullValueNode = node.attribute( "unsaved-value" );
+		if ( nullValueNode != null ) {
+			model.setNullValue( nullValueNode.getValue() );
+		}
+		else {
+			if ( "assigned".equals( model.getIdentifierGeneratorStrategy() ) ) {
+				model.setNullValue( "undefined" );
+			}
+			else {
+				model.setNullValue( null );
+			}
+		}
+	}
+
+	private static final void makeVersion(Element node, SimpleValue model) {
+
+		// VERSION UNSAVED-VALUE
+		Attribute nullValueNode = node.attribute( "unsaved-value" );
+		if ( nullValueNode != null ) {
+			model.setNullValue( nullValueNode.getValue() );
+		}
+		else {
+			model.setNullValue( "undefined" );
+		}
+
+	}
+
+	protected static void createClassProperties(Element node, PersistentClass persistentClass,
+			Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+		createClassProperties(node, persistentClass, mappings, inheritedMetas, null, true, true, false);
+	}
+
+	protected static void createClassProperties(Element node, PersistentClass persistentClass,
+			Mappings mappings, java.util.Map inheritedMetas, UniqueKey uniqueKey,
+			boolean mutable, boolean nullable, boolean naturalId) throws MappingException {
+
+		String entityName = persistentClass.getEntityName();
+		Table table = persistentClass.getTable();
+
+		Iterator iter = node.elementIterator();
+		while ( iter.hasNext() ) {
+			Element subnode = (Element) iter.next();
+			String name = subnode.getName();
+			String propertyName = subnode.attributeValue( "name" );
+
+			CollectionType collectType = CollectionType.collectionTypeFromString( name );
+			Value value = null;
+			if ( collectType != null ) {
+				Collection collection = collectType.create(
+						subnode,
+						StringHelper.qualify( entityName, propertyName ),
+						persistentClass,
+						mappings, inheritedMetas
+					);
+				mappings.addCollection( collection );
+				value = collection;
+			}
+			else if ( "many-to-one".equals( name ) ) {
+				value = new ManyToOne( table );
+				bindManyToOne( subnode, (ManyToOne) value, propertyName, nullable, mappings );
+			}
+			else if ( "any".equals( name ) ) {
+				value = new Any( table );
+				bindAny( subnode, (Any) value, nullable, mappings );
+			}
+			else if ( "one-to-one".equals( name ) ) {
+				value = new OneToOne( table, persistentClass );
+				bindOneToOne( subnode, (OneToOne) value, propertyName, true, mappings );
+			}
+			else if ( "property".equals( name ) ) {
+				value = new SimpleValue( table );
+				bindSimpleValue( subnode, (SimpleValue) value, nullable, propertyName, mappings );
+			}
+			else if ( "component".equals( name )
+				|| "dynamic-component".equals( name )
+				|| "properties".equals( name ) ) {
+				String subpath = StringHelper.qualify( entityName, propertyName );
+				value = new Component( persistentClass );
+
+				bindComponent(
+						subnode,
+						(Component) value,
+						persistentClass.getClassName(),
+						propertyName,
+						subpath,
+						true,
+						"properties".equals( name ),
+						mappings,
+						inheritedMetas,
+						false
+					);
+			}
+			else if ( "join".equals( name ) ) {
+				Join join = new Join();
+				join.setPersistentClass( persistentClass );
+				bindJoin( subnode, join, mappings, inheritedMetas );
+				persistentClass.addJoin( join );
+			}
+			else if ( "subclass".equals( name ) ) {
+				handleSubclass( persistentClass, mappings, subnode, inheritedMetas );
+			}
+			else if ( "joined-subclass".equals( name ) ) {
+				handleJoinedSubclass( persistentClass, mappings, subnode, inheritedMetas );
+			}
+			else if ( "union-subclass".equals( name ) ) {
+				handleUnionSubclass( persistentClass, mappings, subnode, inheritedMetas );
+			}
+			else if ( "filter".equals( name ) ) {
+				parseFilter( subnode, persistentClass, mappings );
+			}
+			else if ( "natural-id".equals( name ) ) {
+				UniqueKey uk = new UniqueKey();
+				uk.setName("_UniqueKey");
+				uk.setTable(table);
+				//by default, natural-ids are "immutable" (constant)
+				boolean mutableId = "true".equals( subnode.attributeValue("mutable") );
+				createClassProperties(
+						subnode,
+						persistentClass,
+						mappings,
+						inheritedMetas,
+						uk,
+						mutableId,
+						false,
+						true
+					);
+				table.addUniqueKey(uk);
+			}
+			else if ( "query".equals(name) ) {
+				bindNamedQuery(subnode, persistentClass.getEntityName(), mappings);
+			}
+			else if ( "sql-query".equals(name) ) {
+				bindNamedSQLQuery(subnode, persistentClass.getEntityName(), mappings);
+			}
+			else if ( "resultset".equals(name) ) {
+				bindResultSetMappingDefinition( subnode, persistentClass.getEntityName(), mappings );
+			}
+
+			if ( value != null ) {
+				Property property = createProperty( value, propertyName, persistentClass
+					.getClassName(), subnode, mappings, inheritedMetas );
+				if ( !mutable ) property.setUpdateable(false);
+				if ( naturalId ) property.setNaturalIdentifier(true);
+				persistentClass.addProperty( property );
+				if ( uniqueKey!=null ) uniqueKey.addColumns( property.getColumnIterator() );
+			}
+
+		}
+	}
+
+	private static Property createProperty(
+			final Value value,
+	        final String propertyName,
+			final String className,
+	        final Element subnode,
+	        final Mappings mappings,
+			java.util.Map inheritedMetas) throws MappingException {
+
+		if ( StringHelper.isEmpty( propertyName ) ) {
+			throw new MappingException( subnode.getName() + " mapping must defined a name attribute [" + className + "]" );
+		}
+
+		value.setTypeUsingReflection( className, propertyName );
+
+		// this is done here 'cos we might only know the type here (ugly!)
+		// TODO: improve this a lot:
+		if ( value instanceof ToOne ) {
+			ToOne toOne = (ToOne) value;
+			String propertyRef = toOne.getReferencedPropertyName();
+			if ( propertyRef != null ) {
+				mappings.addUniquePropertyReference( toOne.getReferencedEntityName(), propertyRef );
+			}
+		}
+		else if ( value instanceof Collection ) {
+			Collection coll = (Collection) value;
+			String propertyRef = coll.getReferencedPropertyName();
+			// not necessarily a *unique* property reference
+			if ( propertyRef != null ) {
+				mappings.addPropertyReference( coll.getOwnerEntityName(), propertyRef );
+			}
+		}
+
+		value.createForeignKey();
+		Property prop = new Property();
+		prop.setValue( value );
+		bindProperty( subnode, prop, mappings, inheritedMetas );
+		return prop;
+	}
+
+	private static void handleUnionSubclass(PersistentClass model, Mappings mappings,
+			Element subnode, java.util.Map inheritedMetas) throws MappingException {
+		UnionSubclass subclass = new UnionSubclass( model );
+		bindUnionSubclass( subnode, subclass, mappings, inheritedMetas );
+		model.addSubclass( subclass );
+		mappings.addClass( subclass );
+	}
+
+	private static void handleJoinedSubclass(PersistentClass model, Mappings mappings,
+			Element subnode, java.util.Map inheritedMetas) throws MappingException {
+		JoinedSubclass subclass = new JoinedSubclass( model );
+		bindJoinedSubclass( subnode, subclass, mappings, inheritedMetas );
+		model.addSubclass( subclass );
+		mappings.addClass( subclass );
+	}
+
+	private static void handleSubclass(PersistentClass model, Mappings mappings, Element subnode,
+			java.util.Map inheritedMetas) throws MappingException {
+		Subclass subclass = new SingleTableSubclass( model );
+		bindSubclass( subnode, subclass, mappings, inheritedMetas );
+		model.addSubclass( subclass );
+		mappings.addClass( subclass );
+	}
+
+	/**
+	 * Called for Lists, arrays, primitive arrays
+	 */
+	public static void bindListSecondPass(Element node, List list, java.util.Map classes,
+			Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+
+		bindCollectionSecondPass( node, list, classes, mappings, inheritedMetas );
+
+		Element subnode = node.element( "list-index" );
+		if ( subnode == null ) subnode = node.element( "index" );
+		SimpleValue iv = new SimpleValue( list.getCollectionTable() );
+		bindSimpleValue(
+				subnode,
+				iv,
+				list.isOneToMany(),
+				IndexedCollection.DEFAULT_INDEX_COLUMN_NAME,
+				mappings
+			);
+		iv.setTypeName( "integer" );
+		list.setIndex( iv );
+		String baseIndex = subnode.attributeValue( "base" );
+		if ( baseIndex != null ) list.setBaseIndex( Integer.parseInt( baseIndex ) );
+		list.setIndexNodeName( subnode.attributeValue("node") );
+
+		if ( list.isOneToMany() && !list.getKey().isNullable() && !list.isInverse() ) {
+			String entityName = ( (OneToMany) list.getElement() ).getReferencedEntityName();
+			PersistentClass referenced = mappings.getClass( entityName );
+			IndexBackref ib = new IndexBackref();
+			ib.setName( '_' + node.attributeValue( "name" ) + "IndexBackref" );
+			ib.setUpdateable( false );
+			ib.setSelectable( false );
+			ib.setCollectionRole( list.getRole() );
+			ib.setEntityName( list.getOwner().getEntityName() );
+			ib.setValue( list.getIndex() );
+			// ( (Column) ( (SimpleValue) ic.getIndex() ).getColumnIterator().next()
+			// ).setNullable(false);
+			referenced.addProperty( ib );
+		}
+	}
+
+	public static void bindIdentifierCollectionSecondPass(Element node,
+			IdentifierCollection collection, java.util.Map persistentClasses, Mappings mappings,
+			java.util.Map inheritedMetas) throws MappingException {
+
+		bindCollectionSecondPass( node, collection, persistentClasses, mappings, inheritedMetas );
+
+		Element subnode = node.element( "collection-id" );
+		SimpleValue id = new SimpleValue( collection.getCollectionTable() );
+		bindSimpleValue(
+				subnode,
+				id,
+				false,
+				IdentifierCollection.DEFAULT_IDENTIFIER_COLUMN_NAME,
+				mappings
+			);
+		collection.setIdentifier( id );
+		makeIdentifier( subnode, id, mappings );
+
+	}
+
+	/**
+	 * Called for Maps
+	 */
+	public static void bindMapSecondPass(Element node, Map map, java.util.Map classes,
+			Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+
+		bindCollectionSecondPass( node, map, classes, mappings, inheritedMetas );
+
+		Iterator iter = node.elementIterator();
+		while ( iter.hasNext() ) {
+			Element subnode = (Element) iter.next();
+			String name = subnode.getName();
+
+			if ( "index".equals( name ) || "map-key".equals( name ) ) {
+				SimpleValue value = new SimpleValue( map.getCollectionTable() );
+				bindSimpleValue(
+						subnode,
+						value,
+						map.isOneToMany(),
+						IndexedCollection.DEFAULT_INDEX_COLUMN_NAME,
+						mappings
+					);
+				if ( !value.isTypeSpecified() ) {
+					throw new MappingException( "map index element must specify a type: "
+						+ map.getRole() );
+				}
+				map.setIndex( value );
+				map.setIndexNodeName( subnode.attributeValue("node") );
+			}
+			else if ( "index-many-to-many".equals( name ) || "map-key-many-to-many".equals( name ) ) {
+				ManyToOne mto = new ManyToOne( map.getCollectionTable() );
+				bindManyToOne(
+						subnode,
+						mto,
+						IndexedCollection.DEFAULT_INDEX_COLUMN_NAME,
+						map.isOneToMany(),
+						mappings
+					);
+				map.setIndex( mto );
+
+			}
+			else if ( "composite-index".equals( name ) || "composite-map-key".equals( name ) ) {
+				Component component = new Component( map );
+				bindComposite(
+						subnode,
+						component,
+						map.getRole() + ".index",
+						map.isOneToMany(),
+						mappings,
+						inheritedMetas
+					);
+				map.setIndex( component );
+			}
+			else if ( "index-many-to-any".equals( name ) ) {
+				Any any = new Any( map.getCollectionTable() );
+				bindAny( subnode, any, map.isOneToMany(), mappings );
+				map.setIndex( any );
+			}
+		}
+
+		// TODO: this is a bit of copy/paste from IndexedCollection.createPrimaryKey()
+		boolean indexIsFormula = false;
+		Iterator colIter = map.getIndex().getColumnIterator();
+		while ( colIter.hasNext() ) {
+			if ( ( (Selectable) colIter.next() ).isFormula() ) indexIsFormula = true;
+		}
+
+		if ( map.isOneToMany() && !map.getKey().isNullable() && !map.isInverse() && !indexIsFormula ) {
+			String entityName = ( (OneToMany) map.getElement() ).getReferencedEntityName();
+			PersistentClass referenced = mappings.getClass( entityName );
+			IndexBackref ib = new IndexBackref();
+			ib.setName( '_' + node.attributeValue( "name" ) + "IndexBackref" );
+			ib.setUpdateable( false );
+			ib.setSelectable( false );
+			ib.setCollectionRole( map.getRole() );
+			ib.setEntityName( map.getOwner().getEntityName() );
+			ib.setValue( map.getIndex() );
+			// ( (Column) ( (SimpleValue) ic.getIndex() ).getColumnIterator().next()
+			// ).setNullable(false);
+			referenced.addProperty( ib );
+		}
+	}
+
+	/**
+	 * Called for all collections
+	 */
+	public static void bindCollectionSecondPass(Element node, Collection collection,
+			java.util.Map persistentClasses, Mappings mappings, java.util.Map inheritedMetas)
+			throws MappingException {
+
+		if ( collection.isOneToMany() ) {
+			OneToMany oneToMany = (OneToMany) collection.getElement();
+			String assocClass = oneToMany.getReferencedEntityName();
+			PersistentClass persistentClass = (PersistentClass) persistentClasses.get( assocClass );
+			if ( persistentClass == null ) {
+				throw new MappingException( "Association references unmapped class: " + assocClass );
+			}
+			oneToMany.setAssociatedClass( persistentClass );
+			collection.setCollectionTable( persistentClass.getTable() );
+
+			log.info(
+					"Mapping collection: " + collection.getRole() +
+					" -> " + collection.getCollectionTable().getName()
+				);
+		}
+
+		// CHECK
+		Attribute chNode = node.attribute( "check" );
+		if ( chNode != null ) {
+			collection.getCollectionTable().addCheckConstraint( chNode.getValue() );
+		}
+
+		// contained elements:
+		Iterator iter = node.elementIterator();
+		while ( iter.hasNext() ) {
+			Element subnode = (Element) iter.next();
+			String name = subnode.getName();
+
+			if ( "key".equals( name ) ) {
+				KeyValue keyVal;
+				String propRef = collection.getReferencedPropertyName();
+				if ( propRef == null ) {
+					keyVal = collection.getOwner().getIdentifier();
+				}
+				else {
+					keyVal = (KeyValue) collection.getOwner().getRecursiveProperty( propRef ).getValue();
+				}
+				SimpleValue key = new DependantValue( collection.getCollectionTable(), keyVal );
+				key.setCascadeDeleteEnabled( "cascade"
+					.equals( subnode.attributeValue( "on-delete" ) ) );
+				bindSimpleValue(
+						subnode,
+						key,
+						collection.isOneToMany(),
+						Collection.DEFAULT_KEY_COLUMN_NAME,
+						mappings
+					);
+				collection.setKey( key );
+
+				Attribute notNull = subnode.attribute( "not-null" );
+				( (DependantValue) key ).setNullable( notNull == null
+					|| notNull.getValue().equals( "false" ) );
+				Attribute updateable = subnode.attribute( "update" );
+				( (DependantValue) key ).setUpdateable( updateable == null
+					|| updateable.getValue().equals( "true" ) );
+
+			}
+			else if ( "element".equals( name ) ) {
+				SimpleValue elt = new SimpleValue( collection.getCollectionTable() );
+				collection.setElement( elt );
+				bindSimpleValue(
+						subnode,
+						elt,
+						true,
+						Collection.DEFAULT_ELEMENT_COLUMN_NAME,
+						mappings
+					);
+			}
+			else if ( "many-to-many".equals( name ) ) {
+				ManyToOne element = new ManyToOne( collection.getCollectionTable() );
+				collection.setElement( element );
+				bindManyToOne(
+						subnode,
+						element,
+						Collection.DEFAULT_ELEMENT_COLUMN_NAME,
+						false,
+						mappings
+					);
+				bindManyToManySubelements( collection, subnode, mappings );
+			}
+			else if ( "composite-element".equals( name ) ) {
+				Component element = new Component( collection );
+				collection.setElement( element );
+				bindComposite(
+						subnode,
+						element,
+						collection.getRole() + ".element",
+						true,
+						mappings,
+						inheritedMetas
+					);
+			}
+			else if ( "many-to-any".equals( name ) ) {
+				Any element = new Any( collection.getCollectionTable() );
+				collection.setElement( element );
+				bindAny( subnode, element, true, mappings );
+			}
+			else if ( "cache".equals( name ) ) {
+				collection.setCacheConcurrencyStrategy( subnode.attributeValue( "usage" ) );
+				collection.setCacheRegionName( subnode.attributeValue( "region" ) );
+			}
+
+			String nodeName = subnode.attributeValue( "node" );
+			if ( nodeName != null ) collection.setElementNodeName( nodeName );
+
+		}
+
+		if ( collection.isOneToMany()
+			&& !collection.isInverse()
+			&& !collection.getKey().isNullable() ) {
+			// for non-inverse one-to-many, with a not-null fk, add a backref!
+			String entityName = ( (OneToMany) collection.getElement() ).getReferencedEntityName();
+			PersistentClass referenced = mappings.getClass( entityName );
+			Backref prop = new Backref();
+			prop.setName( '_' + node.attributeValue( "name" ) + "Backref" );
+			prop.setUpdateable( false );
+			prop.setSelectable( false );
+			prop.setCollectionRole( collection.getRole() );
+			prop.setEntityName( collection.getOwner().getEntityName() );
+			prop.setValue( collection.getKey() );
+			referenced.addProperty( prop );
+		}
+	}
+
+	private static void bindManyToManySubelements(
+	        Collection collection,
+	        Element manyToManyNode,
+	        Mappings model) throws MappingException {
+		// Bind the where
+		Attribute where = manyToManyNode.attribute( "where" );
+		String whereCondition = where == null ? null : where.getValue();
+		collection.setManyToManyWhere( whereCondition );
+
+		// Bind the order-by
+		Attribute order = manyToManyNode.attribute( "order-by" );
+		String orderFragment = order == null ? null : order.getValue();
+		collection.setManyToManyOrdering( orderFragment );
+
+		// Bind the filters
+		Iterator filters = manyToManyNode.elementIterator( "filter" );
+		if ( ( filters.hasNext() || whereCondition != null ) &&
+		        collection.getFetchMode() == FetchMode.JOIN &&
+		        collection.getElement().getFetchMode() != FetchMode.JOIN ) {
+			throw new MappingException(
+			        "many-to-many defining filter or where without join fetching " +
+			        "not valid within collection using join fetching [" + collection.getRole() + "]"
+				);
+		}
+		while ( filters.hasNext() ) {
+			final Element filterElement = ( Element ) filters.next();
+			final String name = filterElement.attributeValue( "name" );
+			String condition = filterElement.getTextTrim();
+			if ( StringHelper.isEmpty(condition) ) condition = filterElement.attributeValue( "condition" );
+			if ( StringHelper.isEmpty(condition) ) {
+				condition = model.getFilterDefinition(name).getDefaultFilterCondition();
+			}
+			if ( condition==null) {
+				throw new MappingException("no filter condition found for filter: " + name);
+			}
+			log.debug(
+					"Applying many-to-many filter [" + name +
+					"] as [" + condition +
+					"] to role [" + collection.getRole() + "]"
+				);
+			collection.addManyToManyFilter( name, condition );
+		}
+	}
+
+	public static final FlushMode getFlushMode(String flushMode) {
+		if ( flushMode == null ) {
+			return null;
+		}
+		else if ( "auto".equals( flushMode ) ) {
+			return FlushMode.AUTO;
+		}
+		else if ( "commit".equals( flushMode ) ) {
+			return FlushMode.COMMIT;
+		}
+		else if ( "never".equals( flushMode ) ) {
+			return FlushMode.NEVER;
+		}
+		else if ( "manual".equals( flushMode ) ) {
+			return FlushMode.MANUAL;
+		}
+		else if ( "always".equals( flushMode ) ) {
+			return FlushMode.ALWAYS;
+		}
+		else {
+			throw new MappingException( "unknown flushmode" );
+		}
+	}
+
+	private static void bindNamedQuery(Element queryElem, String path, Mappings mappings) {
+		String queryName = queryElem.attributeValue( "name" );
+		if (path!=null) queryName = path + '.' + queryName;
+		String query = queryElem.getText();
+		log.debug( "Named query: " + queryName + " -> " + query );
+
+		boolean cacheable = "true".equals( queryElem.attributeValue( "cacheable" ) );
+		String region = queryElem.attributeValue( "cache-region" );
+		Attribute tAtt = queryElem.attribute( "timeout" );
+		Integer timeout = tAtt == null ? null : new Integer( tAtt.getValue() );
+		Attribute fsAtt = queryElem.attribute( "fetch-size" );
+		Integer fetchSize = fsAtt == null ? null : new Integer( fsAtt.getValue() );
+		Attribute roAttr = queryElem.attribute( "read-only" );
+		boolean readOnly = roAttr != null && "true".equals( roAttr.getValue() );
+		Attribute cacheModeAtt = queryElem.attribute( "cache-mode" );
+		String cacheMode = cacheModeAtt == null ? null : cacheModeAtt.getValue();
+		Attribute cmAtt = queryElem.attribute( "comment" );
+		String comment = cmAtt == null ? null : cmAtt.getValue();
+
+		NamedQueryDefinition namedQuery = new NamedQueryDefinition(
+				query,
+				cacheable,
+				region,
+				timeout,
+				fetchSize,
+				getFlushMode( queryElem.attributeValue( "flush-mode" ) ) ,
+				getCacheMode( cacheMode ),
+				readOnly,
+				comment,
+				getParameterTypes(queryElem)
+			);
+
+		mappings.addQuery( queryName, namedQuery );
+	}
+
+	public static CacheMode getCacheMode(String cacheMode) {
+		if (cacheMode == null) return null;
+		if ( "get".equals( cacheMode ) ) return CacheMode.GET;
+		if ( "ignore".equals( cacheMode ) ) return CacheMode.IGNORE;
+		if ( "normal".equals( cacheMode ) ) return CacheMode.NORMAL;
+		if ( "put".equals( cacheMode ) ) return CacheMode.PUT;
+		if ( "refresh".equals( cacheMode ) ) return CacheMode.REFRESH;
+		throw new MappingException("Unknown Cache Mode: " + cacheMode);
+	}
+
+	public static java.util.Map getParameterTypes(Element queryElem) {
+		java.util.Map result = new SequencedHashMap();
+		Iterator iter = queryElem.elementIterator("query-param");
+		while ( iter.hasNext() ) {
+			Element element = (Element) iter.next();
+			result.put(
+					element.attributeValue("name"),
+					element.attributeValue("type") 
+				);
+		}
+		return result;
+	}
+
+	private static void bindResultSetMappingDefinition(Element resultSetElem, String path, Mappings mappings) {
+		mappings.addSecondPass( new ResultSetMappingSecondPass( resultSetElem, path, mappings ) );
+	}
+
+	private static void bindNamedSQLQuery(Element queryElem, String path, Mappings mappings) {
+		mappings.addSecondPass( new NamedSQLQuerySecondPass( queryElem, path, mappings ) );
+	}
+
+	private static String getPropertyName(Element node) {
+		return node.attributeValue( "name" );
+	}
+
+	private static PersistentClass getSuperclass(Mappings mappings, Element subnode)
+			throws MappingException {
+		String extendsName = subnode.attributeValue( "extends" );
+		PersistentClass superModel = mappings.getClass( extendsName );
+		if ( superModel == null ) {
+			String qualifiedExtendsName = getClassName( extendsName, mappings );
+			superModel = mappings.getClass( qualifiedExtendsName );
+		}
+
+		if ( superModel == null ) {
+			throw new MappingException( "Cannot extend unmapped class " + extendsName );
+		}
+		return superModel;
+	}
+
+	static class CollectionSecondPass extends org.hibernate.cfg.CollectionSecondPass {
+		Element node;
+
+		CollectionSecondPass(Element node, Mappings mappings, Collection collection, java.util.Map inheritedMetas) {
+			super(mappings, collection, inheritedMetas);
+			this.node = node;
+		}
+
+		public void secondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas)
+				throws MappingException {
+			HbmBinder.bindCollectionSecondPass(
+					node,
+					collection,
+					persistentClasses,
+					mappings,
+					inheritedMetas
+				);
+		}
+	}
+
+	static class IdentifierCollectionSecondPass extends CollectionSecondPass {
+		IdentifierCollectionSecondPass(Element node, Mappings mappings, Collection collection, java.util.Map inheritedMetas) {
+			super( node, mappings, collection, inheritedMetas );
+		}
+
+		public void secondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas)
+				throws MappingException {
+			HbmBinder.bindIdentifierCollectionSecondPass(
+					node,
+					(IdentifierCollection) collection,
+					persistentClasses,
+					mappings,
+					inheritedMetas 
+				);
+		}
+
+	}
+
+	static class MapSecondPass extends CollectionSecondPass {
+		MapSecondPass(Element node, Mappings mappings, Map collection, java.util.Map inheritedMetas) {
+			super( node, mappings, collection, inheritedMetas );
+		}
+
+		public void secondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas)
+				throws MappingException {
+			HbmBinder.bindMapSecondPass(
+					node,
+					(Map) collection,
+					persistentClasses,
+					mappings,
+					inheritedMetas 
+				);
+		}
+
+	}
+
+
+	static class ManyToOneSecondPass implements SecondPass {
+		private final ManyToOne manyToOne;
+
+		ManyToOneSecondPass(ManyToOne manyToOne) {
+			this.manyToOne = manyToOne;
+		}
+
+		public void doSecondPass(java.util.Map persistentClasses) throws MappingException {
+			manyToOne.createPropertyRefConstraints(persistentClasses);
+		}
+
+	}
+	
+	static class ListSecondPass extends CollectionSecondPass {
+		ListSecondPass(Element node, Mappings mappings, List collection, java.util.Map inheritedMetas) {
+			super( node, mappings, collection, inheritedMetas );
+		}
+
+		public void secondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas)
+				throws MappingException {
+			HbmBinder.bindListSecondPass(
+					node,
+					(List) collection,
+					persistentClasses,
+					mappings,
+					inheritedMetas 
+				);
+		}
+
+	}
+
+	// This inner class implements a case statement....perhaps im being a bit over-clever here
+	abstract static class CollectionType {
+		private String xmlTag;
+
+		public abstract Collection create(Element node, String path, PersistentClass owner,
+				Mappings mappings, java.util.Map inheritedMetas) throws MappingException;
+
+		CollectionType(String xmlTag) {
+			this.xmlTag = xmlTag;
+		}
+
+		public String toString() {
+			return xmlTag;
+		}
+
+		private static final CollectionType MAP = new CollectionType( "map" ) {
+			public Collection create(Element node, String path, PersistentClass owner,
+					Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+				Map map = new Map( owner );
+				bindCollection( node, map, owner.getEntityName(), path, mappings, inheritedMetas );
+				return map;
+			}
+		};
+		private static final CollectionType SET = new CollectionType( "set" ) {
+			public Collection create(Element node, String path, PersistentClass owner,
+					Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+				Set set = new Set( owner );
+				bindCollection( node, set, owner.getEntityName(), path, mappings, inheritedMetas );
+				return set;
+			}
+		};
+		private static final CollectionType LIST = new CollectionType( "list" ) {
+			public Collection create(Element node, String path, PersistentClass owner,
+					Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+				List list = new List( owner );
+				bindCollection( node, list, owner.getEntityName(), path, mappings, inheritedMetas );
+				return list;
+			}
+		};
+		private static final CollectionType BAG = new CollectionType( "bag" ) {
+			public Collection create(Element node, String path, PersistentClass owner,
+					Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+				Bag bag = new Bag( owner );
+				bindCollection( node, bag, owner.getEntityName(), path, mappings, inheritedMetas );
+				return bag;
+			}
+		};
+		private static final CollectionType IDBAG = new CollectionType( "idbag" ) {
+			public Collection create(Element node, String path, PersistentClass owner,
+					Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+				IdentifierBag bag = new IdentifierBag( owner );
+				bindCollection( node, bag, owner.getEntityName(), path, mappings, inheritedMetas );
+				return bag;
+			}
+		};
+		private static final CollectionType ARRAY = new CollectionType( "array" ) {
+			public Collection create(Element node, String path, PersistentClass owner,
+					Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+				Array array = new Array( owner );
+				bindArray( node, array, owner.getEntityName(), path, mappings, inheritedMetas );
+				return array;
+			}
+		};
+		private static final CollectionType PRIMITIVE_ARRAY = new CollectionType( "primitive-array" ) {
+			public Collection create(Element node, String path, PersistentClass owner,
+					Mappings mappings, java.util.Map inheritedMetas) throws MappingException {
+				PrimitiveArray array = new PrimitiveArray( owner );
+				bindArray( node, array, owner.getEntityName(), path, mappings, inheritedMetas );
+				return array;
+			}
+		};
+		private static final HashMap INSTANCES = new HashMap();
+
+		static {
+			INSTANCES.put( MAP.toString(), MAP );
+			INSTANCES.put( BAG.toString(), BAG );
+			INSTANCES.put( IDBAG.toString(), IDBAG );
+			INSTANCES.put( SET.toString(), SET );
+			INSTANCES.put( LIST.toString(), LIST );
+			INSTANCES.put( ARRAY.toString(), ARRAY );
+			INSTANCES.put( PRIMITIVE_ARRAY.toString(), PRIMITIVE_ARRAY );
+		}
+
+		public static CollectionType collectionTypeFromString(String xmlTagName) {
+			return (CollectionType) INSTANCES.get( xmlTagName );
+		}
+	}
+
+	private static int getOptimisticLockMode(Attribute olAtt) throws MappingException {
+
+		if ( olAtt == null ) return Versioning.OPTIMISTIC_LOCK_VERSION;
+		String olMode = olAtt.getValue();
+		if ( olMode == null || "version".equals( olMode ) ) {
+			return Versioning.OPTIMISTIC_LOCK_VERSION;
+		}
+		else if ( "dirty".equals( olMode ) ) {
+			return Versioning.OPTIMISTIC_LOCK_DIRTY;
+		}
+		else if ( "all".equals( olMode ) ) {
+			return Versioning.OPTIMISTIC_LOCK_ALL;
+		}
+		else if ( "none".equals( olMode ) ) {
+			return Versioning.OPTIMISTIC_LOCK_NONE;
+		}
+		else {
+			throw new MappingException( "Unsupported optimistic-lock style: " + olMode );
+		}
+	}
+
+	private static final java.util.Map getMetas(Element node, java.util.Map inheritedMeta) {
+		return getMetas( node, inheritedMeta, false );
+	}
+
+	public static final java.util.Map getMetas(Element node, java.util.Map inheritedMeta,
+			boolean onlyInheritable) {
+		java.util.Map map = new HashMap();
+		map.putAll( inheritedMeta );
+
+		Iterator iter = node.elementIterator( "meta" );
+		while ( iter.hasNext() ) {
+			Element metaNode = (Element) iter.next();
+			boolean inheritable = Boolean
+				.valueOf( metaNode.attributeValue( "inherit" ) )
+				.booleanValue();
+			if ( onlyInheritable & !inheritable ) {
+				continue;
+			}
+			String name = metaNode.attributeValue( "attribute" );
+
+			MetaAttribute meta = (MetaAttribute) map.get( name );
+			MetaAttribute inheritedAttribute = (MetaAttribute) inheritedMeta.get( name );
+			if ( meta == null  ) {
+				meta = new MetaAttribute( name );
+				map.put( name, meta );
+			} else if (meta == inheritedAttribute) { // overriding inherited meta attribute. HBX-621 & HBX-793			
+				meta = new MetaAttribute( name );				
+				map.put( name, meta );				
+			}			
+			meta.addValue( metaNode.getText() );
+		}
+		return map;
+	}
+
+	public static String getEntityName(Element elem, Mappings model) {
+		String entityName = elem.attributeValue( "entity-name" );
+		return entityName == null ? getClassName( elem.attribute( "class" ), model ) : entityName;
+	}
+
+	private static String getClassName(Attribute att, Mappings model) {
+		if ( att == null ) return null;
+		return getClassName( att.getValue(), model );
+	}
+
+	public static String getClassName(String unqualifiedName, Mappings model) {
+		return getClassName( unqualifiedName, model.getDefaultPackage() );
+	}
+
+	public static String getClassName(String unqualifiedName, String defaultPackage) {
+		if ( unqualifiedName == null ) return null;
+		if ( unqualifiedName.indexOf( '.' ) < 0 && defaultPackage != null ) {
+			return defaultPackage + '.' + unqualifiedName;
+		}
+		return unqualifiedName;
+	}
+
+	private static void parseFilterDef(Element element, Mappings mappings) {
+		String name = element.attributeValue( "name" );
+		log.debug( "Parsing filter-def [" + name + "]" );
+		String defaultCondition = element.getTextTrim();
+		if ( StringHelper.isEmpty( defaultCondition ) ) {
+			defaultCondition = element.attributeValue( "condition" );
+		}
+		HashMap paramMappings = new HashMap();
+		Iterator params = element.elementIterator( "filter-param" );
+		while ( params.hasNext() ) {
+			final Element param = (Element) params.next();
+			final String paramName = param.attributeValue( "name" );
+			final String paramType = param.attributeValue( "type" );
+			log.debug( "adding filter parameter : " + paramName + " -> " + paramType );
+			final Type heuristicType = TypeFactory.heuristicType( paramType );
+			log.debug( "parameter heuristic type : " + heuristicType );
+			paramMappings.put( paramName, heuristicType );
+		}
+		log.debug( "Parsed filter-def [" + name + "]" );
+		FilterDefinition def = new FilterDefinition( name, defaultCondition, paramMappings );
+		mappings.addFilterDefinition( def );
+	}
+
+	private static void parseFilter(Element filterElement, Filterable filterable, Mappings model) {
+		final String name = filterElement.attributeValue( "name" );
+		String condition = filterElement.getTextTrim();
+		if ( StringHelper.isEmpty(condition) ) {
+			condition = filterElement.attributeValue( "condition" );
+		}
+		//TODO: bad implementation, cos it depends upon ordering of mapping doc
+		//      fixing this requires that Collection/PersistentClass gain access
+		//      to the Mappings reference from Configuration (or the filterDefinitions
+		//      map directly) sometime during Configuration.buildSessionFactory
+		//      (after all the types/filter-defs are known and before building
+		//      persisters).
+		if ( StringHelper.isEmpty(condition) ) {
+			condition = model.getFilterDefinition(name).getDefaultFilterCondition();
+		}
+		if ( condition==null) {
+			throw new MappingException("no filter condition found for filter: " + name);
+		}
+		log.debug( "Applying filter [" + name + "] as [" + condition + "]" );
+		filterable.addFilter( name, condition );
+	}
+
+	private static String getSubselect(Element element) {
+		String subselect = element.attributeValue( "subselect" );
+		if ( subselect != null ) {
+			return subselect;
+		}
+		else {
+			Element subselectElement = element.element( "subselect" );
+			return subselectElement == null ? null : subselectElement.getText();
+		}
+	}
+
+	/**
+	 * For the given document, locate all extends attributes which refer to
+	 * entities (entity-name or class-name) not defined within said document.
+	 *
+	 * @param doc The document to check
+	 * @param mappings The already processed mappings.
+	 * @return The list of unresolved extends names.
+	 */
+	public static java.util.List getExtendsNeeded(Document doc, Mappings mappings) {
+		java.util.List extendz = new ArrayList();
+		Iterator[] subclasses = new Iterator[3];
+		final Element hmNode = doc.getRootElement();
+
+		Attribute packNode = hmNode.attribute( "package" );
+		final String packageName = packNode == null ? null : packNode.getValue();
+		if ( packageName != null ) {
+			mappings.setDefaultPackage( packageName );
+		}
+
+		// first, iterate over all elements capable of defining an extends attribute
+		// collecting all found extends references if they cannot be resolved
+		// against the already processed mappings.
+		subclasses[0] = hmNode.elementIterator( "subclass" );
+		subclasses[1] = hmNode.elementIterator( "joined-subclass" );
+		subclasses[2] = hmNode.elementIterator( "union-subclass" );
+
+		Iterator iterator = new JoinedIterator( subclasses );
+		while ( iterator.hasNext() ) {
+			final Element element = (Element) iterator.next();
+			final String extendsName = element.attributeValue( "extends" );
+			// mappings might contain either the "raw" extends name (in the case of
+			// an entity-name mapping) or a FQN (in the case of a POJO mapping).
+			if ( mappings.getClass( extendsName ) == null && mappings.getClass( getClassName( extendsName, mappings ) ) == null ) {
+				extendz.add( extendsName );
+			}
+		}
+
+		if ( !extendz.isEmpty() ) {
+			// we found some extends attributes referencing entities which were
+			// not already processed.  here we need to locate all entity-names
+			// and class-names contained in this document itself, making sure
+			// that these get removed from the extendz list such that only
+			// extends names which require us to delay processing (i.e.
+			// external to this document and not yet processed) are contained
+			// in the returned result
+			final java.util.Set set = new HashSet( extendz );
+			EntityElementHandler handler = new EntityElementHandler() {
+				public void handleEntity(String entityName, String className, Mappings mappings) {
+					if ( entityName != null ) {
+						set.remove( entityName );
+					}
+					else {
+						String fqn = getClassName( className, packageName );
+						set.remove( fqn );
+						if ( packageName != null ) {
+							set.remove( StringHelper.unqualify( fqn ) );
+						}
+					}
+				}
+			};
+			recognizeEntities( mappings, hmNode, handler );
+			extendz.clear();
+			extendz.addAll( set );
+		}
+
+		return extendz;
+	}
+
+	/**
+	 * Given an entity-containing-element (startNode) recursively locate all
+	 * entity names defined within that element.
+	 *
+	 * @param mappings The already processed mappings
+	 * @param startNode The containing element
+	 * @param handler The thing that knows what to do whenever we recognize an
+	 * entity-name
+	 */
+	private static void recognizeEntities(
+			Mappings mappings,
+	        final Element startNode,
+			EntityElementHandler handler) {
+		Iterator[] classes = new Iterator[4];
+		classes[0] = startNode.elementIterator( "class" );
+		classes[1] = startNode.elementIterator( "subclass" );
+		classes[2] = startNode.elementIterator( "joined-subclass" );
+		classes[3] = startNode.elementIterator( "union-subclass" );
+
+		Iterator classIterator = new JoinedIterator( classes );
+		while ( classIterator.hasNext() ) {
+			Element element = (Element) classIterator.next();
+			handler.handleEntity(
+					element.attributeValue( "entity-name" ),
+		            element.attributeValue( "name" ),
+			        mappings
+			);
+			recognizeEntities( mappings, element, handler );
+		}
+	}
+
+	private static interface EntityElementHandler {
+		public void handleEntity(String entityName, String className, Mappings mappings);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ImprovedNamingStrategy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ImprovedNamingStrategy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ImprovedNamingStrategy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,124 @@
+//$Id: ImprovedNamingStrategy.java 9941 2006-05-22 18:28:53Z epbernard $
+package org.hibernate.cfg;
+
+import java.io.Serializable;
+
+import org.hibernate.util.StringHelper;
+import org.hibernate.AssertionFailure;
+
+/**
+ * An improved naming strategy that prefers embedded
+ * underscores to mixed case names
+ * @see DefaultNamingStrategy the default strategy
+ * @author Gavin King
+ */
+public class ImprovedNamingStrategy implements NamingStrategy, Serializable {
+
+	/**
+	 * A convenient singleton instance
+	 */
+	public static final NamingStrategy INSTANCE = new ImprovedNamingStrategy();
+
+	/**
+	 * Return the unqualified class name, mixed case converted to
+	 * underscores
+	 */
+	public String classToTableName(String className) {
+		return addUnderscores( StringHelper.unqualify(className) );
+	}
+	/**
+	 * Return the full property path with underscore seperators, mixed
+	 * case converted to underscores
+	 */
+	public String propertyToColumnName(String propertyName) {
+		return addUnderscores( StringHelper.unqualify(propertyName) );
+	}
+	/**
+	 * Convert mixed case to underscores
+	 */
+	public String tableName(String tableName) {
+		return addUnderscores(tableName);
+	}
+	/**
+	 * Convert mixed case to underscores
+	 */
+	public String columnName(String columnName) {
+		return addUnderscores(columnName);
+	}
+
+	protected static String addUnderscores(String name) {
+		StringBuffer buf = new StringBuffer( name.replace('.', '_') );
+		for (int i=1; i<buf.length()-1; i++) {
+			if (
+				Character.isLowerCase( buf.charAt(i-1) ) &&
+				Character.isUpperCase( buf.charAt(i) ) &&
+				Character.isLowerCase( buf.charAt(i+1) )
+			) {
+				buf.insert(i++, '_');
+			}
+		}
+		return buf.toString().toLowerCase();
+	}
+
+	public String collectionTableName(
+			String ownerEntity, String ownerEntityTable, String associatedEntity, String associatedEntityTable,
+			String propertyName
+	) {
+		return tableName( ownerEntityTable + '_' + propertyToColumnName(propertyName) );
+	}
+
+	/**
+	 * Return the argument
+	 */
+	public String joinKeyColumnName(String joinedColumn, String joinedTable) {
+		return columnName( joinedColumn );
+	}
+
+	/**
+	 * Return the property name or propertyTableName
+	 */
+	public String foreignKeyColumnName(
+			String propertyName, String propertyEntityName, String propertyTableName, String referencedColumnName
+	) {
+		String header = propertyName != null ? StringHelper.unqualify( propertyName ) : propertyTableName;
+		if (header == null) throw new AssertionFailure("NamingStrategy not properly filled");
+		return columnName( header ); //+ "_" + referencedColumnName not used for backward compatibility
+	}
+
+	/**
+	 * Return the column name or the unqualified property name
+	 */
+	public String logicalColumnName(String columnName, String propertyName) {
+		return StringHelper.isNotEmpty( columnName ) ? columnName : StringHelper.unqualify( propertyName );
+	}
+
+	/**
+	 * Returns either the table name if explicit or
+	 * if there is an associated table, the concatenation of owner entity table and associated table
+	 * otherwise the concatenation of owner entity table and the unqualified property name
+	 */
+	public String logicalCollectionTableName(String tableName,
+											 String ownerEntityTable, String associatedEntityTable, String propertyName
+	) {
+		if ( tableName != null ) {
+			return tableName;
+		}
+		else {
+			//use of a stringbuffer to workaround a JDK bug
+			return new StringBuffer(ownerEntityTable).append("_")
+					.append(
+						associatedEntityTable != null ?
+						associatedEntityTable :
+						StringHelper.unqualify( propertyName )
+					).toString();
+		}
+	}
+	/**
+	 * Return the column name if explicit or the concatenation of the property name and the referenced column
+	 */
+	public String logicalCollectionColumnName(String columnName, String propertyName, String referencedColumn) {
+		return StringHelper.isNotEmpty( columnName ) ?
+				columnName :
+				StringHelper.unqualify( propertyName ) + "_" + referencedColumn;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Mappings.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Mappings.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Mappings.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,542 @@
+//$Id: Mappings.java 11051 2007-01-16 23:24:17Z epbernard $
+package org.hibernate.cfg;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.HashMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.DuplicateMappingException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.FilterDefinition;
+import org.hibernate.engine.NamedQueryDefinition;
+import org.hibernate.engine.NamedSQLQueryDefinition;
+import org.hibernate.engine.ResultSetMappingDefinition;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.DenormalizedTable;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Table;
+import org.hibernate.mapping.TypeDef;
+import org.hibernate.mapping.AuxiliaryDatabaseObject;
+import org.hibernate.mapping.Column;
+import org.hibernate.util.StringHelper;
+
+/**
+ * A collection of mappings from classes and collections to
+ * relational database tables. (Represents a single
+ * <tt>&lt;hibernate-mapping&gt;</tt> element.)
+ * @author Gavin King
+ */
+public class Mappings implements Serializable {
+
+	private static final Log log = LogFactory.getLog(Mappings.class);
+
+	protected final Map classes;
+	protected final Map collections;
+	protected final Map tables;
+	protected final Map queries;
+	protected final Map sqlqueries;
+	protected final Map resultSetMappings;
+	protected final Map typeDefs;
+	protected final List secondPasses;
+	protected final Map imports;
+	protected String schemaName;
+    protected String catalogName;
+	protected String defaultCascade;
+	protected String defaultPackage;
+	protected String defaultAccess;
+	protected boolean autoImport;
+	protected boolean defaultLazy;
+	protected final List propertyReferences;
+	protected final NamingStrategy namingStrategy;
+	protected final Map filterDefinitions;
+	protected final List auxiliaryDatabaseObjects;
+
+	protected final Map extendsQueue;
+//	private final List extendsQueue;
+
+	/**
+	 * binding table between the logical column name and the name out of the naming strategy
+	 * for each table.
+	 * According that when the column name is not set, the property name is considered as such
+	 * This means that while theorically possible through the naming strategy contract, it is
+	 * forbidden to have 2 real columns having the same logical name
+	 * <Table, ColumnNames >
+	 */
+	protected final Map columnNameBindingPerTable;
+	/**
+	 * binding between logical table name and physical one (ie after the naming strategy has been applied)
+	 * <String, TableDescription>
+	 */
+	protected final Map tableNameBinding;
+
+
+	Mappings(
+			final Map classes,
+			final Map collections,
+			final Map tables,
+			final Map queries,
+			final Map sqlqueries,
+			final Map sqlResultSetMappings,
+			final Map imports,
+			final List secondPasses,
+			final List propertyReferences,
+			final NamingStrategy namingStrategy,
+			final Map typeDefs,
+			final Map filterDefinitions,
+//			final List extendsQueue,
+			final Map extendsQueue,
+			final List auxiliaryDatabaseObjects,
+			final Map tableNamebinding,
+			final Map columnNameBindingPerTable
+			) {
+		this.classes = classes;
+		this.collections = collections;
+		this.queries = queries;
+		this.sqlqueries = sqlqueries;
+		this.resultSetMappings = sqlResultSetMappings;
+		this.tables = tables;
+		this.imports = imports;
+		this.secondPasses = secondPasses;
+		this.propertyReferences = propertyReferences;
+		this.namingStrategy = namingStrategy;
+		this.typeDefs = typeDefs;
+		this.filterDefinitions = filterDefinitions;
+		this.extendsQueue = extendsQueue;
+		this.auxiliaryDatabaseObjects = auxiliaryDatabaseObjects;
+		this.tableNameBinding = tableNamebinding;
+		this.columnNameBindingPerTable = columnNameBindingPerTable;
+	}
+
+	public void addClass(PersistentClass persistentClass) throws MappingException {
+		Object old = classes.put( persistentClass.getEntityName(), persistentClass );
+		if ( old!=null ) {
+			throw new DuplicateMappingException( "class/entity", persistentClass.getEntityName() );
+		}
+	}
+	public void addCollection(Collection collection) throws MappingException {
+		Object old = collections.put( collection.getRole(), collection );
+		if ( old!=null ) {
+			throw new DuplicateMappingException( "collection role", collection.getRole() );
+		}
+	}
+	public PersistentClass getClass(String className) {
+		return (PersistentClass) classes.get(className);
+	}
+	public Collection getCollection(String role) {
+		return (Collection) collections.get(role);
+	}
+
+	public void addImport(String className, String rename) throws MappingException {
+		String existing = (String) imports.put(rename, className);
+		if ( existing!=null ) {
+			if ( existing.equals(className) ) {
+				log.info( "duplicate import: " + className + "->" + rename );
+			}
+			else {
+				throw new DuplicateMappingException(
+						"duplicate import: " + rename + 
+						" refers to both " + className + 
+						" and " + existing + 
+						" (try using auto-import=\"false\")",
+						"import",
+						rename
+					);
+			}
+		}
+	}
+
+	public Table addTable(String schema, 
+			String catalog, 
+			String name,
+			String subselect,
+			boolean isAbstract
+	) {
+        String key = subselect==null ?
+			Table.qualify(catalog, schema, name) :
+			subselect;
+		Table table = (Table) tables.get(key);
+
+		if (table == null) {
+			table = new Table();
+			table.setAbstract(isAbstract);
+			table.setName(name);
+			table.setSchema(schema);
+			table.setCatalog(catalog);
+			table.setSubselect(subselect);
+			tables.put(key, table);
+		}
+		else {
+			if (!isAbstract) table.setAbstract(false);
+		}
+
+		return table;
+	}
+
+	public Table addDenormalizedTable(
+			String schema, 
+			String catalog, 
+			String name,
+			boolean isAbstract, 
+			String subselect,
+			Table includedTable)
+	throws MappingException {
+        String key = subselect==null ?
+        		Table.qualify(catalog, schema, name) :
+        		subselect;
+		if ( tables.containsKey(key) ) {
+			throw new DuplicateMappingException("table", name);
+		}
+		
+		Table table = new DenormalizedTable(includedTable);
+		table.setAbstract(isAbstract);
+		table.setName(name);
+		table.setSchema(schema);
+		table.setCatalog(catalog);
+		table.setSubselect(subselect);
+		tables.put(key, table);
+		return table;
+	}
+
+	public Table getTable(String schema, String catalog, String name) {
+        String key = Table.qualify(catalog, schema, name);
+		return (Table) tables.get(key);
+	}
+
+	public String getSchemaName() {
+		return schemaName;
+	}
+
+    public String getCatalogName() {
+        return catalogName;
+    }
+
+	public String getDefaultCascade() {
+		return defaultCascade;
+	}
+
+	/**
+	 * Sets the schemaName.
+	 * @param schemaName The schemaName to set
+	 */
+	public void setSchemaName(String schemaName) {
+		this.schemaName = schemaName;
+	}
+
+    /**
+     * Sets the catalogName.
+     * @param catalogName The catalogName to set
+     */
+    public void setCatalogName(String catalogName) {
+        this.catalogName = catalogName;
+    }
+
+	/**
+	 * Sets the defaultCascade.
+	 * @param defaultCascade The defaultCascade to set
+	 */
+	public void setDefaultCascade(String defaultCascade) {
+		this.defaultCascade = defaultCascade;
+	}
+
+	/**
+	 * sets the default access strategy
+	 * @param defaultAccess the default access strategy.
+	 */
+	public void setDefaultAccess(String defaultAccess) {
+		this.defaultAccess = defaultAccess;
+	}
+
+	public String getDefaultAccess() {
+		return defaultAccess;
+	}
+
+	public void addQuery(String name, NamedQueryDefinition query) throws MappingException {
+		checkQueryExist(name);
+		queries.put( name.intern(), query );
+	}
+
+	public void addSQLQuery(String name, NamedSQLQueryDefinition query) throws MappingException {
+		checkQueryExist(name);
+		sqlqueries.put( name.intern(), query );
+	}
+
+	private void checkQueryExist(String name) throws MappingException {
+		if ( sqlqueries.containsKey(name) || queries.containsKey(name) ) {
+			throw new DuplicateMappingException("query", name);
+		}
+	}
+
+	public void addResultSetMapping(ResultSetMappingDefinition sqlResultSetMapping) {
+		final String name = sqlResultSetMapping.getName();
+		if ( resultSetMappings.containsKey(name) ) {
+			throw new DuplicateMappingException("resultSet",  name);
+		}
+		resultSetMappings.put(name, sqlResultSetMapping);
+	}
+
+	public ResultSetMappingDefinition getResultSetMapping(String name) {
+		return (ResultSetMappingDefinition) resultSetMappings.get(name);
+	}
+
+
+	public NamedQueryDefinition getQuery(String name) {
+		return (NamedQueryDefinition) queries.get(name);
+	}
+
+	public void addSecondPass(SecondPass sp) {
+		addSecondPass(sp, false);
+	}
+    
+    public void addSecondPass(SecondPass sp, boolean onTopOfTheQueue) {
+		if (onTopOfTheQueue) {
+			secondPasses.add(0, sp);
+		}
+		else {
+			secondPasses.add(sp);
+		}
+	}
+
+	/**
+	 * Returns the autoImport.
+	 * @return boolean
+	 */
+	public boolean isAutoImport() {
+		return autoImport;
+	}
+
+	/**
+	 * Sets the autoImport.
+	 * @param autoImport The autoImport to set
+	 */
+	public void setAutoImport(boolean autoImport) {
+		this.autoImport = autoImport;
+	}
+
+	void addUniquePropertyReference(String referencedClass, String propertyName) {
+		PropertyReference upr = new PropertyReference();
+		upr.referencedClass = referencedClass;
+		upr.propertyName = propertyName;
+		upr.unique = true;
+		propertyReferences.add(upr);
+	}
+
+	void addPropertyReference(String referencedClass, String propertyName) {
+		PropertyReference upr = new PropertyReference();
+		upr.referencedClass = referencedClass;
+		upr.propertyName = propertyName;
+		propertyReferences.add(upr);
+	}
+
+	private String buildTableNameKey(String schema, String catalog, String finalName) {
+		StringBuffer keyBuilder = new StringBuffer();
+		if (schema != null) keyBuilder.append( schema );
+		keyBuilder.append( ".");
+		if (catalog != null) keyBuilder.append( catalog );
+		keyBuilder.append( ".");
+		keyBuilder.append( finalName );
+		return keyBuilder.toString();
+	}
+
+	static final class PropertyReference implements Serializable {
+		String referencedClass;
+		String propertyName;
+		boolean unique;
+	}
+
+	/**
+	 * @return Returns the defaultPackage.
+	 */
+	public String getDefaultPackage() {
+		return defaultPackage;
+	}
+
+	/**
+	 * @param defaultPackage The defaultPackage to set.
+	 */
+	public void setDefaultPackage(String defaultPackage) {
+		this.defaultPackage = defaultPackage;
+	}
+
+	public NamingStrategy getNamingStrategy() {
+		return namingStrategy;
+	}
+
+	public void addTypeDef(String typeName, String typeClass, Properties paramMap) {
+		TypeDef def = new TypeDef(typeClass, paramMap);
+		typeDefs.put(typeName, def);
+		log.debug("Added " + typeName + " with class " + typeClass);
+	}
+
+	public TypeDef getTypeDef(String typeName) {
+		return (TypeDef) typeDefs.get(typeName);
+	}
+
+    public Iterator iterateCollections() {
+        return collections.values().iterator();
+    }
+    
+    public Iterator iterateTables() {
+    	return tables.values().iterator();
+    }
+
+	public Map getFilterDefinitions() {
+		return filterDefinitions;
+	}
+
+	public void addFilterDefinition(FilterDefinition definition) {
+		filterDefinitions.put( definition.getFilterName(), definition );
+	}
+	
+	public FilterDefinition getFilterDefinition(String name) {
+		return (FilterDefinition) filterDefinitions.get(name);
+	}
+	
+	public boolean isDefaultLazy() {
+		return defaultLazy;
+	}
+	public void setDefaultLazy(boolean defaultLazy) {
+		this.defaultLazy = defaultLazy;
+	}
+
+    public void addToExtendsQueue(ExtendsQueueEntry entry) {
+	    extendsQueue.put( entry, null );
+    }
+
+	public PersistentClass locatePersistentClassByEntityName(String entityName) {
+		PersistentClass persistentClass = ( PersistentClass ) classes.get( entityName );
+		if ( persistentClass == null ) {
+			String actualEntityName = ( String ) imports.get( entityName );
+			if ( StringHelper.isNotEmpty( actualEntityName ) ) {
+				persistentClass = ( PersistentClass ) classes.get( actualEntityName );
+			}
+		}
+		return persistentClass;
+	}
+
+	public void addAuxiliaryDatabaseObject(AuxiliaryDatabaseObject auxiliaryDatabaseObject) {
+		auxiliaryDatabaseObjects.add( auxiliaryDatabaseObject );
+	}
+
+	public void addTableBinding(
+			String schema, String catalog, String logicalName, String physicalName, Table denormalizedSuperTable
+	) {
+		String key = buildTableNameKey( schema, catalog, physicalName );
+		TableDescription tableDescription = new TableDescription(
+				logicalName, denormalizedSuperTable
+		);
+		TableDescription oldDescriptor = (TableDescription) tableNameBinding.put( key, tableDescription );
+		if ( oldDescriptor != null && ! oldDescriptor.logicalName.equals( logicalName ) ) {
+			//TODO possibly relax that
+			throw new MappingException("Same physical table name reference several logical table names: "
+					+ physicalName + " => " + "'" + oldDescriptor.logicalName + "' and '" + logicalName + "'");
+		}
+	}
+
+	public void addColumnBinding(String logicalName, Column finalColumn, Table table) {
+		ColumnNames binding = (ColumnNames) columnNameBindingPerTable.get(table);
+		if (binding == null) {
+			binding = new ColumnNames();
+			columnNameBindingPerTable.put(table, binding);
+		}
+		String oldFinalName = (String) binding.logicalToPhysical.put(
+				logicalName.toLowerCase(),
+				finalColumn.getQuotedName()
+		);
+		if ( oldFinalName != null &&
+				! ( finalColumn.isQuoted() ?
+						oldFinalName.equals( finalColumn.getQuotedName() ) :
+						oldFinalName.equalsIgnoreCase( finalColumn.getQuotedName() ) ) ) {
+			//TODO possibly relax that
+			throw new MappingException("Same logical column name referenced by different physical ones: "
+					+ table.getName() + "." + logicalName + " => '" + oldFinalName + "' and '" + finalColumn.getQuotedName() + "'" );
+		}
+		String oldLogicalName = (String) binding.physicalToLogical.put(
+				finalColumn.getQuotedName(),
+				logicalName
+		);
+		if ( oldLogicalName != null && ! oldLogicalName.equals( logicalName ) ) {
+			//TODO possibly relax that
+			throw new MappingException("Same physical column represented by different logical column names: "
+					+ table.getName() + "." + finalColumn.getQuotedName() + " => '" + oldLogicalName + "' and '" + logicalName + "'");
+		}
+	}
+
+	private String getLogicalTableName(String schema, String catalog, String physicalName) {
+		String key = buildTableNameKey( schema, catalog, physicalName );
+		TableDescription descriptor = (TableDescription) tableNameBinding.get( key );
+		if (descriptor == null) {
+			throw new MappingException( "Unable to find physical table: " + physicalName);
+		}
+		return descriptor.logicalName;
+	}
+
+	public String getPhysicalColumnName(String logicalName, Table table) {
+		logicalName = logicalName.toLowerCase();
+		String finalName = null;
+		Table currentTable = table;
+		do {
+			ColumnNames binding = (ColumnNames) columnNameBindingPerTable.get(currentTable);
+			if (binding != null) {
+				finalName = (String) binding.logicalToPhysical.get( logicalName );
+			}
+			String key = buildTableNameKey( currentTable.getSchema(), currentTable.getCatalog(), currentTable.getName() );
+			TableDescription description = (TableDescription) tableNameBinding.get(key);
+			if (description != null) currentTable = description.denormalizedSupertable;
+		}
+		while (finalName == null && currentTable != null);
+		if (finalName == null) {
+			throw new MappingException( "Unable to find column with logical name "
+					+ logicalName + " in table " + table.getName() );
+		}
+		return finalName;
+	}
+
+	public String getLogicalColumnName(String physicalName, Table table) {
+		String logical = null;
+		Table currentTable = table;
+		TableDescription description = null;
+		do {
+			ColumnNames binding = (ColumnNames) columnNameBindingPerTable.get(currentTable);
+			if (binding != null) {
+				logical = (String) binding.physicalToLogical.get( physicalName );
+			}
+			String key = buildTableNameKey( currentTable.getSchema(), currentTable.getCatalog(), currentTable.getName() );
+			description = (TableDescription) tableNameBinding.get(key);
+			if (description != null) currentTable = description.denormalizedSupertable;
+		}
+		while (logical == null && currentTable != null && description != null);
+		if (logical == null) {
+			throw new MappingException( "Unable to find logical column name from physical name "
+					+ physicalName + " in table " + table.getName() );
+		}
+		return logical;
+	}
+
+	public String getLogicalTableName(Table table) {
+		return getLogicalTableName( table.getQuotedSchema(), table.getCatalog(), table.getQuotedName() );
+	}
+
+	static public class ColumnNames implements Serializable {
+		//<String, String>
+		public Map logicalToPhysical = new HashMap();
+		//<String, String>
+		public Map physicalToLogical = new HashMap();
+		public ColumnNames() {
+		}
+	}
+
+	static public class TableDescription implements Serializable {
+		public TableDescription(String logicalName, Table denormalizedSupertable) {
+			this.logicalName = logicalName;
+			this.denormalizedSupertable = denormalizedSupertable;
+		}
+
+		public String logicalName;
+		public Table denormalizedSupertable;
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/NamedSQLQuerySecondPass.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/NamedSQLQuerySecondPass.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/NamedSQLQuerySecondPass.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,99 @@
+//$Id: NamedSQLQuerySecondPass.java 10196 2006-08-03 07:53:27Z max.andersen at jboss.com $
+package org.hibernate.cfg;
+
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.hibernate.MappingException;
+import org.hibernate.util.StringHelper;
+import org.hibernate.engine.NamedSQLQueryDefinition;
+import org.hibernate.engine.ResultSetMappingDefinition;
+import org.dom4j.Attribute;
+import org.dom4j.Element;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class NamedSQLQuerySecondPass extends ResultSetMappingBinder implements QuerySecondPass {
+	private static Log log = LogFactory.getLog( NamedSQLQuerySecondPass.class);
+	private Element queryElem;
+	private String path;
+	private Mappings mappings;
+
+	public NamedSQLQuerySecondPass(Element queryElem, String path, Mappings mappings) {
+		this.queryElem = queryElem;
+		this.path = path;
+		this.mappings = mappings;
+	}
+
+	public void doSecondPass(Map persistentClasses) throws MappingException {
+		String queryName = queryElem.attribute( "name" ).getValue();
+		if (path!=null) queryName = path + '.' + queryName;
+
+		boolean cacheable = "true".equals( queryElem.attributeValue( "cacheable" ) );
+		String region = queryElem.attributeValue( "cache-region" );
+		Attribute tAtt = queryElem.attribute( "timeout" );
+		Integer timeout = tAtt == null ? null : new Integer( tAtt.getValue() );
+		Attribute fsAtt = queryElem.attribute( "fetch-size" );
+		Integer fetchSize = fsAtt == null ? null : new Integer( fsAtt.getValue() );
+		Attribute roAttr = queryElem.attribute( "read-only" );
+		boolean readOnly = roAttr != null && "true".equals( roAttr.getValue() );
+		Attribute cacheModeAtt = queryElem.attribute( "cache-mode" );
+		String cacheMode = cacheModeAtt == null ? null : cacheModeAtt.getValue();
+		Attribute cmAtt = queryElem.attribute( "comment" );
+		String comment = cmAtt == null ? null : cmAtt.getValue();
+
+		java.util.List synchronizedTables = new ArrayList();
+		Iterator tables = queryElem.elementIterator( "synchronize" );
+		while ( tables.hasNext() ) {
+			synchronizedTables.add( ( (Element) tables.next() ).attributeValue( "table" ) );
+		}
+		boolean callable = "true".equals( queryElem.attributeValue( "callable" ) );
+
+		NamedSQLQueryDefinition namedQuery;
+		Attribute ref = queryElem.attribute( "resultset-ref" );
+		String resultSetRef = ref == null ? null : ref.getValue();
+		if ( StringHelper.isNotEmpty( resultSetRef ) ) {
+			namedQuery = new NamedSQLQueryDefinition(
+					queryElem.getText(),
+					resultSetRef,
+					synchronizedTables,
+					cacheable,
+					region,
+					timeout,
+					fetchSize,
+					HbmBinder.getFlushMode( queryElem.attributeValue( "flush-mode" ) ),
+					HbmBinder.getCacheMode( cacheMode ),
+					readOnly,
+					comment,
+					HbmBinder.getParameterTypes( queryElem ),
+					callable
+			);
+			//TODO check there is no actual definition elemnents when a ref is defined
+		}
+		else {
+			ResultSetMappingDefinition definition = buildResultSetMappingDefinition( queryElem, path, mappings );
+			namedQuery = new NamedSQLQueryDefinition(
+					queryElem.getText(),
+					definition.getQueryReturns(),
+					synchronizedTables,
+					cacheable,
+					region,
+					timeout,
+					fetchSize,
+					HbmBinder.getFlushMode( queryElem.attributeValue( "flush-mode" ) ),
+					HbmBinder.getCacheMode( cacheMode ),
+					readOnly,
+					comment,
+					HbmBinder.getParameterTypes( queryElem ),
+					callable
+			);
+		}
+
+		log.debug( "Named SQL query: " + queryName + " -> " + namedQuery.getQueryString() );
+		mappings.addSQLQuery( queryName, namedQuery );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/NamingStrategy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/NamingStrategy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/NamingStrategy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,101 @@
+//$Id: NamingStrategy.java 9874 2006-05-04 15:10:22Z epbernard $
+package org.hibernate.cfg;
+
+/**
+ * A set of rules for determining the physical column
+ * and table names given the information in the mapping
+ * document. May be used to implement project-scoped
+ * naming standards for database objects.
+ *
+ * #propertyToTableName(String, String) should be replaced by
+ * {@link #collectionTableName(String,String,String,String,String)}
+ *
+ * @see DefaultNamingStrategy
+ * @see ImprovedNamingStrategy
+ * @author Gavin King
+ * @author Emmanuel Bernard
+ */
+public interface NamingStrategy {
+	/**
+	 * Return a table name for an entity class
+	 * @param className the fully-qualified class name
+	 * @return a table name
+	 */
+	public String classToTableName(String className);
+	/**
+	 * Return a column name for a property path expression
+	 * @param propertyName a property path
+	 * @return a column name
+	 */
+	public String propertyToColumnName(String propertyName);
+	/**
+	 * Alter the table name given in the mapping document
+	 * @param tableName a table name
+	 * @return a table name
+	 */
+	public String tableName(String tableName);
+	/**
+	 * Alter the column name given in the mapping document
+	 * @param columnName a column name
+	 * @return a column name
+	 */
+	public String columnName(String columnName);
+	/**
+	 * Return a collection table name ie an association having a join table
+	 *
+	 * @param ownerEntity
+	 * @param ownerEntityTable owner side table name
+	 * @param associatedEntity
+	 * @param associatedEntityTable reverse side table name if any
+	 * @param propertyName collection role
+	 */
+	public String collectionTableName(
+			String ownerEntity, String ownerEntityTable, String associatedEntity, String associatedEntityTable,
+			String propertyName
+	);
+	/**
+	 * Return the join key column name ie a FK column used in a JOINED strategy or for a secondary table
+	 *
+	 * @param joinedColumn joined column name (logical one) used to join with
+	 * @param joinedTable joined table name (ie the referenced table) used to join with
+	 */
+	public String joinKeyColumnName(String joinedColumn, String joinedTable);
+	/**
+	 * Return the foreign key column name for the given parameters
+	 * @param propertyName the property name involved
+	 * @param propertyEntityName
+	 * @param propertyTableName the property table name involved (logical one)
+	 * @param referencedColumnName the referenced column name involved (logical one)
+	 */
+	public String foreignKeyColumnName(
+			String propertyName, String propertyEntityName, String propertyTableName, String referencedColumnName
+	);
+	/**
+	 * Return the logical column name used to refer to a column in the metadata
+	 * (like index, unique constraints etc)
+	 * A full bijection is required between logicalNames and physical ones
+	 * logicalName have to be case insersitively unique for a given table
+	 *
+	 * @param columnName given column name if any
+	 * @param propertyName property name of this column
+	 */
+	public String logicalColumnName(String columnName, String propertyName);
+	/**
+	 * Returns the logical collection table name used to refer to a table in the mapping metadata
+	 *
+	 * @param tableName the metadata explicit name
+	 * @param ownerEntityTable owner table entity table name (logical one)
+	 * @param associatedEntityTable reverse side table name if any (logical one)
+	 * @param propertyName collection role
+	 */
+	public String logicalCollectionTableName(String tableName, String ownerEntityTable, String associatedEntityTable, String propertyName);
+
+	/**
+	 * Returns the logical foreign key column name used to refer to this column in the mapping metadata
+	 *
+	 * @param columnName given column name in the metadata if any
+	 * @param propertyName property name
+	 * @param referencedColumn referenced column name (logical one) in the join
+	 */
+	public String logicalCollectionColumnName(String columnName, String propertyName, String referencedColumn);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/QuerySecondPass.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/QuerySecondPass.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/QuerySecondPass.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+//$Id: QuerySecondPass.java 9019 2006-01-11 18:50:33Z epbernard $
+package org.hibernate.cfg;
+
+/**
+ * Bind query
+ *
+ * @author Emmanuel Bernard
+ */
+public interface QuerySecondPass extends SecondPass {
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ResultSetMappingBinder.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ResultSetMappingBinder.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ResultSetMappingBinder.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,366 @@
+//$Id: ResultSetMappingBinder.java 10180 2006-07-28 20:17:01Z epbernard $
+package org.hibernate.cfg;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.dom4j.Element;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.query.sql.NativeSQLQueryCollectionReturn;
+import org.hibernate.engine.ResultSetMappingDefinition;
+import org.hibernate.engine.query.sql.NativeSQLQueryJoinReturn;
+import org.hibernate.engine.query.sql.NativeSQLQueryRootReturn;
+import org.hibernate.engine.query.sql.NativeSQLQueryScalarReturn;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Value;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.ToOne;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.CollectionHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public abstract class ResultSetMappingBinder {
+	/**
+	 * Build a ResultSetMappingDefinition given a containing element for the "return-XXX" elements
+	 *
+	 * @param resultSetElem The element containing the return definitions.
+	 * @param path No clue...
+	 * @param mappings The current processing state.
+	 * @return The description of the mappings...
+	 */
+	protected static ResultSetMappingDefinition buildResultSetMappingDefinition(Element resultSetElem, String path, Mappings mappings) {
+		String resultSetName = resultSetElem.attribute( "name" ).getValue();
+		if ( path != null ) {
+			resultSetName = path + '.' + resultSetName;
+		}
+		ResultSetMappingDefinition definition = new ResultSetMappingDefinition( resultSetName );
+
+		int cnt = 0;
+		Iterator returns = resultSetElem.elementIterator();
+		while ( returns.hasNext() ) {
+			cnt++;
+			Element returnElem = (Element) returns.next();
+			String name = returnElem.getName();
+			if ( "return-scalar".equals( name ) ) {
+				String column = returnElem.attributeValue( "column" );
+				String typeFromXML = HbmBinder.getTypeFromXML( returnElem );
+				Type type = null;
+				if(typeFromXML!=null) {
+					type = TypeFactory.heuristicType( typeFromXML );
+					if ( type == null ) {
+						throw new MappingException( "could not determine type " + type );
+					}
+				}
+				definition.addQueryReturn( new NativeSQLQueryScalarReturn( column, type ) );
+			}
+			else if ( "return".equals( name ) ) {
+				definition.addQueryReturn( bindReturn( returnElem, mappings, cnt ) );
+			}
+			else if ( "return-join".equals( name ) ) {
+				definition.addQueryReturn( bindReturnJoin( returnElem, mappings ) );
+			}
+			else if ( "load-collection".equals( name ) ) {
+				definition.addQueryReturn( bindLoadCollection( returnElem, mappings ) );
+			}
+		}
+		return definition;
+	}
+
+	private static NativeSQLQueryRootReturn bindReturn(Element returnElem, Mappings mappings, int elementCount) {
+		String alias = returnElem.attributeValue( "alias" );
+		if( StringHelper.isEmpty(alias)) {
+			alias = "alias_" + elementCount; // hack/workaround as sqlquery impl depend on having a key.
+		}
+
+		String entityName = HbmBinder.getEntityName(returnElem, mappings);
+		if(entityName==null) {
+			throw new MappingException( "<return alias='" + alias + "'> must specify either a class or entity-name");
+		}
+		LockMode lockMode = getLockMode( returnElem.attributeValue( "lock-mode" ) );
+
+		PersistentClass pc = mappings.getClass( entityName );
+		java.util.Map propertyResults = bindPropertyResults(alias, returnElem, pc, mappings );
+
+		return new NativeSQLQueryRootReturn(
+				alias,
+				entityName,
+				propertyResults,
+				lockMode
+			);
+	}
+
+	private static NativeSQLQueryJoinReturn bindReturnJoin(Element returnElem, Mappings mappings) {
+		String alias = returnElem.attributeValue( "alias" );
+		String roleAttribute = returnElem.attributeValue( "property" );
+		LockMode lockMode = getLockMode( returnElem.attributeValue( "lock-mode" ) );
+		int dot = roleAttribute.lastIndexOf( '.' );
+		if ( dot == -1 ) {
+			throw new MappingException(
+					"Role attribute for sql query return [alias=" + alias +
+					"] not formatted correctly {owningAlias.propertyName}"
+				);
+		}
+		String roleOwnerAlias = roleAttribute.substring( 0, dot );
+		String roleProperty = roleAttribute.substring( dot + 1 );
+
+		//FIXME: get the PersistentClass
+		java.util.Map propertyResults = bindPropertyResults(alias, returnElem, null, mappings );
+
+		return new NativeSQLQueryJoinReturn(
+				alias,
+				roleOwnerAlias,
+				roleProperty,
+				propertyResults, // TODO: bindpropertyresults(alias, returnElem)
+				lockMode
+			);
+	}
+
+	private static NativeSQLQueryCollectionReturn bindLoadCollection(Element returnElem, Mappings mappings) {
+		String alias = returnElem.attributeValue( "alias" );
+		String collectionAttribute = returnElem.attributeValue( "role" );
+		LockMode lockMode = getLockMode( returnElem.attributeValue( "lock-mode" ) );
+		int dot = collectionAttribute.lastIndexOf( '.' );
+		if ( dot == -1 ) {
+			throw new MappingException(
+					"Collection attribute for sql query return [alias=" + alias +
+					"] not formatted correctly {OwnerClassName.propertyName}"
+				);
+		}
+		String ownerClassName = HbmBinder.getClassName( collectionAttribute.substring( 0, dot ), mappings );
+		String ownerPropertyName = collectionAttribute.substring( dot + 1 );
+
+		//FIXME: get the PersistentClass
+		java.util.Map propertyResults = bindPropertyResults(alias, returnElem, null, mappings );
+
+		return new NativeSQLQueryCollectionReturn(
+				alias,
+				ownerClassName,
+				ownerPropertyName,
+				propertyResults,
+				lockMode
+			);
+	}
+
+	private static java.util.Map bindPropertyResults(
+			String alias, Element returnElement, PersistentClass pc, Mappings mappings
+	) {
+
+		HashMap propertyresults = new HashMap(); // maybe a concrete SQLpropertyresult type, but Map is exactly what is required at the moment
+
+		Element discriminatorResult = returnElement.element("return-discriminator");
+		if(discriminatorResult!=null) {
+			ArrayList resultColumns = getResultColumns(discriminatorResult);
+			propertyresults.put("class", ArrayHelper.toStringArray(resultColumns) );
+		}
+		Iterator iterator = returnElement.elementIterator("return-property");
+		List properties = new ArrayList();
+		List propertyNames = new ArrayList();
+		while ( iterator.hasNext() ) {
+			Element propertyresult = (Element) iterator.next();
+			String name = propertyresult.attributeValue("name");
+			if ( pc == null || name.indexOf( '.') == -1) { //if dotted and not load-collection nor return-join
+				//regular property
+				properties.add(propertyresult);
+				propertyNames.add(name);
+			}
+			else {
+				/**
+				 * Reorder properties
+				 * 1. get the parent property
+				 * 2. list all the properties following the expected one in the parent property
+				 * 3. calculate the lowest index and insert the property
+				 */
+				if (pc == null)
+					throw new MappingException("dotted notation in <return-join> or <load_collection> not yet supported");
+				int dotIndex = name.lastIndexOf( '.' );
+				String reducedName = name.substring( 0, dotIndex );
+				Value value = pc.getRecursiveProperty( reducedName ).getValue();
+				Iterator parentPropIter;
+				if ( value instanceof Component ) {
+					Component comp = (Component) value;
+					parentPropIter = comp.getPropertyIterator();
+				}
+				else if ( value instanceof ToOne ) {
+					ToOne toOne = (ToOne) value;
+					PersistentClass referencedPc = mappings.getClass( toOne.getReferencedEntityName() );
+					if ( toOne.getReferencedPropertyName() != null ) {
+						try {
+							parentPropIter = ( (Component) referencedPc.getRecursiveProperty( toOne.getReferencedPropertyName() ).getValue() ).getPropertyIterator();
+						} catch (ClassCastException e) {
+							throw new MappingException("dotted notation reference neither a component nor a many/one to one", e);
+						}
+					}
+					else {
+						try {
+							if ( referencedPc.getIdentifierMapper() == null ) {
+								parentPropIter = ( (Component) referencedPc.getIdentifierProperty().getValue() ).getPropertyIterator();
+							}
+							else {
+								parentPropIter = referencedPc.getIdentifierMapper().getPropertyIterator();
+							}
+						}
+						catch (ClassCastException e) {
+							throw new MappingException("dotted notation reference neither a component nor a many/one to one", e);
+						}
+					}
+				}
+				else {
+					throw new MappingException("dotted notation reference neither a component nor a many/one to one");
+				}
+				boolean hasFollowers = false;
+				List followers = new ArrayList();
+				while ( parentPropIter.hasNext() ) {
+					String currentPropertyName = ( (Property) parentPropIter.next() ).getName();
+					String currentName = reducedName + '.' + currentPropertyName;
+					if (hasFollowers) {
+						followers.add( currentName );
+					}
+					if ( name.equals( currentName ) ) hasFollowers = true;
+				}
+
+				int index = propertyNames.size();
+				int followersSize = followers.size();
+				for (int loop = 0 ; loop < followersSize ; loop++) {
+					String follower = (String) followers.get(loop);
+					int currentIndex = getIndexOfFirstMatchingProperty(propertyNames, follower);
+					index = currentIndex != -1 && currentIndex < index ? currentIndex : index;
+				}
+				propertyNames.add(index, name);
+				properties.add(index, propertyresult);
+			}
+		}
+
+		Set uniqueReturnProperty = new HashSet();
+		iterator = properties.iterator();
+		while ( iterator.hasNext() ) {
+			Element propertyresult = (Element) iterator.next();
+			String name = propertyresult.attributeValue("name");
+			if ( "class".equals(name) ) {
+				throw new MappingException(
+						"class is not a valid property name to use in a <return-property>, use <return-discriminator> instead"
+					);
+			}
+			//TODO: validate existing of property with the chosen name. (secondpass )
+			ArrayList allResultColumns = getResultColumns(propertyresult);
+
+			if ( allResultColumns.isEmpty() ) {
+				throw new MappingException(
+						"return-property for alias " + alias +
+						" must specify at least one column or return-column name"
+					);
+			}
+			if ( uniqueReturnProperty.contains( name ) ) {
+				throw new MappingException(
+						"duplicate return-property for property " + name +
+						" on alias " + alias
+					);
+			}
+			uniqueReturnProperty.add(name);
+
+			// the issue here is that for <return-join/> representing an entity collection,
+			// the collection element values (the property values of the associated entity)
+			// are represented as 'element.{propertyname}'.  Thus the StringHelper.root()
+			// here puts everything under 'element' (which additionally has significant
+			// meaning).  Probably what we need to do is to something like this instead:
+			//      String root = StringHelper.root( name );
+			//      String key = root; // by default
+			//      if ( !root.equals( name ) ) {
+			//	        // we had a dot
+			//          if ( !root.equals( alias ) {
+			//              // the root does not apply to the specific alias
+			//              if ( "elements".equals( root ) {
+			//                  // we specifically have a <return-join/> representing an entity collection
+			//                  // and this <return-property/> is one of that entity's properties
+			//                  key = name;
+			//              }
+			//          }
+			//      }
+			// but I am not clear enough on the intended purpose of this code block, especially
+			// in relation to the "Reorder properties" code block above... 
+//			String key = StringHelper.root( name );
+			String key = name;
+			ArrayList intermediateResults = (ArrayList) propertyresults.get( key );
+			if (intermediateResults == null) {
+				propertyresults.put( key, allResultColumns );
+			}
+			else {
+				intermediateResults.addAll( allResultColumns );
+			}
+		}
+
+		Iterator entries = propertyresults.entrySet().iterator();
+		while ( entries.hasNext() ) {
+			Map.Entry entry = (Map.Entry) entries.next();
+			if (entry.getValue() instanceof ArrayList) {
+				ArrayList list = (ArrayList) entry.getValue();
+				entry.setValue( list.toArray( new String[ list.size() ] ) );
+			}
+		}
+		return propertyresults.isEmpty() ? CollectionHelper.EMPTY_MAP : propertyresults;
+	}
+
+	private static int getIndexOfFirstMatchingProperty(List propertyNames, String follower) {
+		int propertySize = propertyNames.size();
+		for (int propIndex = 0 ; propIndex < propertySize ; propIndex++) {
+			if ( ( (String) propertyNames.get(propIndex) ).startsWith( follower ) ) {
+				return propIndex;
+			}
+		}
+		return -1;
+	}
+
+	private static ArrayList getResultColumns(Element propertyresult) {
+		String column = unquote(propertyresult.attributeValue("column"));
+		ArrayList allResultColumns = new ArrayList();
+		if(column!=null) allResultColumns.add(column);
+		Iterator resultColumns = propertyresult.elementIterator("return-column");
+		while ( resultColumns.hasNext() ) {
+			Element element = (Element) resultColumns.next();
+			allResultColumns.add( unquote(element.attributeValue("name")) );
+		}
+		return allResultColumns;
+	}
+
+	private static String unquote(String name) {
+		if (name!=null && name.charAt(0)=='`') {
+			name=name.substring( 1, name.length()-1 );
+		}
+		return name;
+	}
+
+	private static LockMode getLockMode(String lockMode) {
+		if ( lockMode == null || "read".equals( lockMode ) ) {
+			return LockMode.READ;
+		}
+		else if ( "none".equals( lockMode ) ) {
+			return LockMode.NONE;
+		}
+		else if ( "upgrade".equals( lockMode ) ) {
+			return LockMode.UPGRADE;
+		}
+		else if ( "upgrade-nowait".equals( lockMode ) ) {
+			return LockMode.UPGRADE_NOWAIT;
+		}
+		else if ( "write".equals( lockMode ) ) {
+			return LockMode.WRITE;
+		}
+		else if ( "force".equals( lockMode ) ) {
+			return LockMode.FORCE;
+		}
+		else {
+			throw new MappingException( "unknown lockmode" );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ResultSetMappingSecondPass.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ResultSetMappingSecondPass.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/ResultSetMappingSecondPass.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+//$Id: ResultSetMappingSecondPass.java 10196 2006-08-03 07:53:27Z max.andersen at jboss.com $
+package org.hibernate.cfg;
+
+import java.util.Map;
+
+import org.dom4j.Element;
+import org.hibernate.MappingException;
+import org.hibernate.engine.ResultSetMappingDefinition;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class ResultSetMappingSecondPass extends ResultSetMappingBinder implements QuerySecondPass {
+	private Element element;
+	private String path;
+	private Mappings mappings;
+
+	public ResultSetMappingSecondPass(Element element, String path, Mappings mappings) {
+		this.element = element;
+		this.path = path;
+		this.mappings = mappings;
+	}
+
+	public void doSecondPass(Map persistentClasses) throws MappingException {
+		ResultSetMappingDefinition definition = buildResultSetMappingDefinition( element, path, mappings);
+		mappings.addResultSetMapping( definition );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/SecondPass.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/SecondPass.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/SecondPass.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+//$Id: SecondPass.java 10196 2006-08-03 07:53:27Z max.andersen at jboss.com $
+package org.hibernate.cfg;
+
+import java.io.Serializable;
+
+import org.hibernate.MappingException;
+
+/**
+ * Second pass operation
+ *
+ * @author Emmanuel Bernard
+ */
+public interface SecondPass extends Serializable {
+
+	void doSecondPass(java.util.Map persistentClasses)
+				throws MappingException;
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Settings.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Settings.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/Settings.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,451 @@
+//$Id: Settings.java 11402 2007-04-11 14:24:35Z steve.ebersole at jboss.com $
+package org.hibernate.cfg;
+
+import java.util.Map;
+
+import org.hibernate.cache.QueryCacheFactory;
+import org.hibernate.cache.RegionFactory;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.hql.QueryTranslatorFactory;
+import org.hibernate.jdbc.BatcherFactory;
+import org.hibernate.transaction.TransactionFactory;
+import org.hibernate.transaction.TransactionManagerLookup;
+import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.EntityMode;
+import org.hibernate.ConnectionReleaseMode;
+
+/**
+ * Settings that affect the behaviour of Hibernate at runtime.
+ *
+ * @author Gavin King
+ */
+public final class Settings {
+
+	private boolean showSql;
+	private boolean formatSql;
+	private Integer maximumFetchDepth;
+	private Map querySubstitutions;
+	private Dialect dialect;
+	private int jdbcBatchSize;
+	private int defaultBatchFetchSize;
+	private boolean scrollableResultSetsEnabled;
+	private boolean getGeneratedKeysEnabled;
+	private String defaultSchemaName;
+	private String defaultCatalogName;
+	private Integer jdbcFetchSize;
+	private String sessionFactoryName;
+	private boolean autoCreateSchema;
+	private boolean autoDropSchema;
+	private boolean autoUpdateSchema;
+	private boolean autoValidateSchema;
+	private boolean queryCacheEnabled;
+	private boolean structuredCacheEntriesEnabled;
+	private boolean secondLevelCacheEnabled;
+	private String cacheRegionPrefix;
+	private boolean minimalPutsEnabled;
+	private boolean commentsEnabled;
+	private boolean statisticsEnabled;
+	private boolean jdbcBatchVersionedData;
+	private boolean identifierRollbackEnabled;
+	private boolean flushBeforeCompletionEnabled;
+	private boolean autoCloseSessionEnabled;
+	private ConnectionReleaseMode connectionReleaseMode;
+	private RegionFactory regionFactory;
+	private QueryCacheFactory queryCacheFactory;
+	private ConnectionProvider connectionProvider;
+	private TransactionFactory transactionFactory;
+	private TransactionManagerLookup transactionManagerLookup;
+	private BatcherFactory batcherFactory;
+	private QueryTranslatorFactory queryTranslatorFactory;
+	private SQLExceptionConverter sqlExceptionConverter;
+	private boolean wrapResultSetsEnabled;
+	private boolean orderUpdatesEnabled;
+	private boolean orderInsertsEnabled;
+	private EntityMode defaultEntityMode;
+	private boolean dataDefinitionImplicitCommit;
+	private boolean dataDefinitionInTransactionSupported;
+	private boolean strictJPAQLCompliance;
+	private boolean namedQueryStartupCheckingEnabled;
+//	private BytecodeProvider bytecodeProvider;
+
+	/**
+	 * Package protected constructor
+	 */
+	Settings() {
+	}
+
+	// public getters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public String getDefaultSchemaName() {
+		return defaultSchemaName;
+	}
+
+	public String getDefaultCatalogName() {
+		return defaultCatalogName;
+	}
+
+	public Dialect getDialect() {
+		return dialect;
+	}
+
+	public int getJdbcBatchSize() {
+		return jdbcBatchSize;
+	}
+
+	public int getDefaultBatchFetchSize() {
+		return defaultBatchFetchSize;
+	}
+
+	public Map getQuerySubstitutions() {
+		return querySubstitutions;
+	}
+
+	public boolean isShowSqlEnabled() {
+		return showSql;
+	}
+
+	public boolean isFormatSqlEnabled() {
+		return formatSql;
+	}
+
+	public boolean isIdentifierRollbackEnabled() {
+		return identifierRollbackEnabled;
+	}
+
+	public boolean isScrollableResultSetsEnabled() {
+		return scrollableResultSetsEnabled;
+	}
+
+	public boolean isGetGeneratedKeysEnabled() {
+		return getGeneratedKeysEnabled;
+	}
+
+	public boolean isMinimalPutsEnabled() {
+		return minimalPutsEnabled;
+	}
+
+	public Integer getJdbcFetchSize() {
+		return jdbcFetchSize;
+	}
+
+	public ConnectionProvider getConnectionProvider() {
+		return connectionProvider;
+	}
+
+	public TransactionFactory getTransactionFactory() {
+		return transactionFactory;
+	}
+
+	public String getSessionFactoryName() {
+		return sessionFactoryName;
+	}
+
+	public boolean isAutoCreateSchema() {
+		return autoCreateSchema;
+	}
+
+	public boolean isAutoDropSchema() {
+		return autoDropSchema;
+	}
+
+	public boolean isAutoUpdateSchema() {
+		return autoUpdateSchema;
+	}
+
+	public Integer getMaximumFetchDepth() {
+		return maximumFetchDepth;
+	}
+
+	public RegionFactory getRegionFactory() {
+		return regionFactory;
+	}
+
+	public TransactionManagerLookup getTransactionManagerLookup() {
+		return transactionManagerLookup;
+	}
+
+	public boolean isQueryCacheEnabled() {
+		return queryCacheEnabled;
+	}
+
+	public boolean isCommentsEnabled() {
+		return commentsEnabled;
+	}
+
+	public boolean isSecondLevelCacheEnabled() {
+		return secondLevelCacheEnabled;
+	}
+
+	public String getCacheRegionPrefix() {
+		return cacheRegionPrefix;
+	}
+
+	public QueryCacheFactory getQueryCacheFactory() {
+		return queryCacheFactory;
+	}
+
+	public boolean isStatisticsEnabled() {
+		return statisticsEnabled;
+	}
+
+	public boolean isJdbcBatchVersionedData() {
+		return jdbcBatchVersionedData;
+	}
+
+	public boolean isFlushBeforeCompletionEnabled() {
+		return flushBeforeCompletionEnabled;
+	}
+
+	public BatcherFactory getBatcherFactory() {
+		return batcherFactory;
+	}
+
+	public boolean isAutoCloseSessionEnabled() {
+		return autoCloseSessionEnabled;
+	}
+
+	public ConnectionReleaseMode getConnectionReleaseMode() {
+		return connectionReleaseMode;
+	}
+
+	public QueryTranslatorFactory getQueryTranslatorFactory() {
+		return queryTranslatorFactory;
+	}
+
+	public SQLExceptionConverter getSQLExceptionConverter() {
+		return sqlExceptionConverter;
+	}
+
+	public boolean isWrapResultSetsEnabled() {
+		return wrapResultSetsEnabled;
+	}
+
+	public boolean isOrderUpdatesEnabled() {
+		return orderUpdatesEnabled;
+	}
+
+	public boolean isOrderInsertsEnabled() {
+		return orderInsertsEnabled;
+	}
+
+	public boolean isStructuredCacheEntriesEnabled() {
+		return structuredCacheEntriesEnabled;
+	}
+
+	public EntityMode getDefaultEntityMode() {
+		return defaultEntityMode;
+	}
+
+	public boolean isAutoValidateSchema() {
+		return autoValidateSchema;
+	}
+
+	public boolean isDataDefinitionImplicitCommit() {
+		return dataDefinitionImplicitCommit;
+	}
+
+	public boolean isDataDefinitionInTransactionSupported() {
+		return dataDefinitionInTransactionSupported;
+	}
+
+	public boolean isStrictJPAQLCompliance() {
+		return strictJPAQLCompliance;
+	}
+
+	public boolean isNamedQueryStartupCheckingEnabled() {
+		return namedQueryStartupCheckingEnabled;
+	}
+
+
+	// package protected setters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	void setDefaultSchemaName(String string) {
+		defaultSchemaName = string;
+	}
+
+	void setDefaultCatalogName(String string) {
+		defaultCatalogName = string;
+	}
+
+	void setDialect(Dialect dialect) {
+		this.dialect = dialect;
+	}
+
+	void setJdbcBatchSize(int i) {
+		jdbcBatchSize = i;
+	}
+
+	void setDefaultBatchFetchSize(int i) {
+		defaultBatchFetchSize = i;
+	}
+
+	void setQuerySubstitutions(Map map) {
+		querySubstitutions = map;
+	}
+
+	void setShowSqlEnabled(boolean b) {
+		showSql = b;
+	}
+
+	void setFormatSqlEnabled(boolean b) {
+		formatSql = b;
+	}
+
+	void setIdentifierRollbackEnabled(boolean b) {
+		identifierRollbackEnabled = b;
+	}
+
+	void setMinimalPutsEnabled(boolean b) {
+		minimalPutsEnabled = b;
+	}
+
+	void setScrollableResultSetsEnabled(boolean b) {
+		scrollableResultSetsEnabled = b;
+	}
+
+	void setGetGeneratedKeysEnabled(boolean b) {
+		getGeneratedKeysEnabled = b;
+	}
+
+	void setJdbcFetchSize(Integer integer) {
+		jdbcFetchSize = integer;
+	}
+
+	void setConnectionProvider(ConnectionProvider provider) {
+		connectionProvider = provider;
+	}
+
+	void setTransactionFactory(TransactionFactory factory) {
+		transactionFactory = factory;
+	}
+
+	void setSessionFactoryName(String string) {
+		sessionFactoryName = string;
+	}
+
+	void setAutoCreateSchema(boolean b) {
+		autoCreateSchema = b;
+	}
+
+	void setAutoDropSchema(boolean b) {
+		autoDropSchema = b;
+	}
+
+	void setAutoUpdateSchema(boolean b) {
+		autoUpdateSchema = b;
+	}
+
+	void setMaximumFetchDepth(Integer i) {
+		maximumFetchDepth = i;
+	}
+
+	void setRegionFactory(RegionFactory regionFactory) {
+		this.regionFactory = regionFactory;
+	}
+
+	void setTransactionManagerLookup(TransactionManagerLookup lookup) {
+		transactionManagerLookup = lookup;
+	}
+
+	void setQueryCacheEnabled(boolean b) {
+		queryCacheEnabled = b;
+	}
+
+	void setCommentsEnabled(boolean commentsEnabled) {
+		this.commentsEnabled = commentsEnabled;
+	}
+
+	void setSecondLevelCacheEnabled(boolean secondLevelCacheEnabled) {
+		this.secondLevelCacheEnabled = secondLevelCacheEnabled;
+	}
+
+	void setCacheRegionPrefix(String cacheRegionPrefix) {
+		this.cacheRegionPrefix = cacheRegionPrefix;
+	}
+
+	void setQueryCacheFactory(QueryCacheFactory queryCacheFactory) {
+		this.queryCacheFactory = queryCacheFactory;
+	}
+
+	void setStatisticsEnabled(boolean statisticsEnabled) {
+		this.statisticsEnabled = statisticsEnabled;
+	}
+
+	void setJdbcBatchVersionedData(boolean jdbcBatchVersionedData) {
+		this.jdbcBatchVersionedData = jdbcBatchVersionedData;
+	}
+
+	void setFlushBeforeCompletionEnabled(boolean flushBeforeCompletionEnabled) {
+		this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled;
+	}
+
+	void setBatcherFactory(BatcherFactory batcher) {
+		this.batcherFactory = batcher;
+	}
+
+	void setAutoCloseSessionEnabled(boolean autoCloseSessionEnabled) {
+		this.autoCloseSessionEnabled = autoCloseSessionEnabled;
+	}
+
+	void setConnectionReleaseMode(ConnectionReleaseMode connectionReleaseMode) {
+		this.connectionReleaseMode = connectionReleaseMode;
+	}
+
+	void setQueryTranslatorFactory(QueryTranslatorFactory queryTranslatorFactory) {
+		this.queryTranslatorFactory = queryTranslatorFactory;
+	}
+
+	void setSQLExceptionConverter(SQLExceptionConverter sqlExceptionConverter) {
+		this.sqlExceptionConverter = sqlExceptionConverter;
+	}
+
+	void setWrapResultSetsEnabled(boolean wrapResultSetsEnabled) {
+		this.wrapResultSetsEnabled = wrapResultSetsEnabled;
+	}
+
+	void setOrderUpdatesEnabled(boolean orderUpdatesEnabled) {
+		this.orderUpdatesEnabled = orderUpdatesEnabled;
+	}
+
+	void setOrderInsertsEnabled(boolean orderInsertsEnabled) {
+		this.orderInsertsEnabled = orderInsertsEnabled;
+	}
+
+	void setStructuredCacheEntriesEnabled(boolean structuredCacheEntriesEnabled) {
+		this.structuredCacheEntriesEnabled = structuredCacheEntriesEnabled;
+	}
+
+	void setDefaultEntityMode(EntityMode defaultEntityMode) {
+		this.defaultEntityMode = defaultEntityMode;
+	}
+
+	void setAutoValidateSchema(boolean autoValidateSchema) {
+		this.autoValidateSchema = autoValidateSchema;
+	}
+
+	void setDataDefinitionImplicitCommit(boolean dataDefinitionImplicitCommit) {
+		this.dataDefinitionImplicitCommit = dataDefinitionImplicitCommit;
+	}
+
+	void setDataDefinitionInTransactionSupported(boolean dataDefinitionInTransactionSupported) {
+		this.dataDefinitionInTransactionSupported = dataDefinitionInTransactionSupported;
+	}
+
+	void setStrictJPAQLCompliance(boolean strictJPAQLCompliance) {
+		this.strictJPAQLCompliance = strictJPAQLCompliance;
+	}
+
+	void setNamedQueryStartupCheckingEnabled(boolean namedQueryStartupCheckingEnabled) {
+		this.namedQueryStartupCheckingEnabled = namedQueryStartupCheckingEnabled;
+	}
+
+
+//	public BytecodeProvider getBytecodeProvider() {
+//		return bytecodeProvider;
+//	}
+//
+//	void setBytecodeProvider(BytecodeProvider bytecodeProvider) {
+//		this.bytecodeProvider = bytecodeProvider;
+//	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/SettingsFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/SettingsFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/SettingsFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,436 @@
+//$Id: SettingsFactory.java 11402 2007-04-11 14:24:35Z steve.ebersole at jboss.com $
+package org.hibernate.cfg;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.bytecode.BytecodeProvider;
+import org.hibernate.cache.QueryCacheFactory;
+import org.hibernate.cache.RegionFactory;
+import org.hibernate.cache.impl.NoCachingRegionFactory;
+import org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.connection.ConnectionProviderFactory;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.DialectFactory;
+import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.exception.SQLExceptionConverterFactory;
+import org.hibernate.hql.QueryTranslatorFactory;
+import org.hibernate.jdbc.BatcherFactory;
+import org.hibernate.jdbc.BatchingBatcherFactory;
+import org.hibernate.jdbc.NonBatchingBatcherFactory;
+import org.hibernate.transaction.TransactionFactory;
+import org.hibernate.transaction.TransactionFactoryFactory;
+import org.hibernate.transaction.TransactionManagerLookup;
+import org.hibernate.transaction.TransactionManagerLookupFactory;
+import org.hibernate.util.PropertiesHelper;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Reads configuration properties and configures a <tt>Settings</tt> instance.
+ *
+ * @author Gavin King
+ */
+public class SettingsFactory implements Serializable {
+
+	public static final String DEF_CACHE_REG_FACTORY = NoCachingRegionFactory.class.getName();
+	private static final Log log = LogFactory.getLog(SettingsFactory.class);
+
+	protected SettingsFactory() {
+	}
+	
+	public Settings buildSettings(Properties props) {
+		Settings settings = new Settings();
+		
+		//SessionFactory name:
+		
+		String sessionFactoryName = props.getProperty(Environment.SESSION_FACTORY_NAME);
+		settings.setSessionFactoryName(sessionFactoryName);
+
+		//JDBC and connection settings:
+
+		ConnectionProvider connections = createConnectionProvider(props);
+		settings.setConnectionProvider(connections);
+
+		//Interrogate JDBC metadata
+
+		String databaseName = null;
+		int databaseMajorVersion = 0;
+		boolean metaSupportsScrollable = false;
+		boolean metaSupportsGetGeneratedKeys = false;
+		boolean metaSupportsBatchUpdates = false;
+		boolean metaReportsDDLCausesTxnCommit = false;
+		boolean metaReportsDDLInTxnSupported = true;
+
+		// 'hibernate.temp.use_jdbc_metadata_defaults' is a temporary magic value.
+		// The need for it is intended to be alleviated with 3.3 developement, thus it is
+		// not defined as an Environment constant...
+		// it is used to control whether we should consult the JDBC metadata to determine
+		// certain Settings default values; it is useful to *not* do this when the database
+		// may not be available (mainly in tools usage).
+		boolean useJdbcMetadata = PropertiesHelper.getBoolean( "hibernate.temp.use_jdbc_metadata_defaults", props, true );
+		if ( useJdbcMetadata ) {
+			try {
+				Connection conn = connections.getConnection();
+				try {
+					DatabaseMetaData meta = conn.getMetaData();
+					databaseName = meta.getDatabaseProductName();
+					databaseMajorVersion = getDatabaseMajorVersion(meta);
+					log.info("RDBMS: " + databaseName + ", version: " + meta.getDatabaseProductVersion() );
+					log.info("JDBC driver: " + meta.getDriverName() + ", version: " + meta.getDriverVersion() );
+
+					metaSupportsScrollable = meta.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE);
+					metaSupportsBatchUpdates = meta.supportsBatchUpdates();
+					metaReportsDDLCausesTxnCommit = meta.dataDefinitionCausesTransactionCommit();
+					metaReportsDDLInTxnSupported = !meta.dataDefinitionIgnoredInTransactions();
+
+					if ( Environment.jvmSupportsGetGeneratedKeys() ) {
+						try {
+							Boolean result = (Boolean) DatabaseMetaData.class.getMethod("supportsGetGeneratedKeys", null)
+								.invoke(meta, null);
+							metaSupportsGetGeneratedKeys = result.booleanValue();
+						}
+						catch (AbstractMethodError ame) {
+							metaSupportsGetGeneratedKeys = false;
+						}
+						catch (Exception e) {
+							metaSupportsGetGeneratedKeys = false;
+						}
+					}
+
+				}
+				finally {
+					connections.closeConnection(conn);
+				}
+			}
+			catch (SQLException sqle) {
+				log.warn("Could not obtain connection metadata", sqle);
+			}
+			catch (UnsupportedOperationException uoe) {
+				// user supplied JDBC connections
+			}
+		}
+		settings.setDataDefinitionImplicitCommit( metaReportsDDLCausesTxnCommit );
+		settings.setDataDefinitionInTransactionSupported( metaReportsDDLInTxnSupported );
+
+
+		//SQL Dialect:
+		Dialect dialect = determineDialect( props, databaseName, databaseMajorVersion );
+		settings.setDialect(dialect);
+		
+		//use dialect default properties
+		final Properties properties = new Properties();
+		properties.putAll( dialect.getDefaultProperties() );
+		properties.putAll(props);
+		
+		// Transaction settings:
+		
+		TransactionFactory transactionFactory = createTransactionFactory(properties);
+		settings.setTransactionFactory(transactionFactory);
+		settings.setTransactionManagerLookup( createTransactionManagerLookup(properties) );
+
+		boolean flushBeforeCompletion = PropertiesHelper.getBoolean(Environment.FLUSH_BEFORE_COMPLETION, properties);
+		log.info("Automatic flush during beforeCompletion(): " + enabledDisabled(flushBeforeCompletion) );
+		settings.setFlushBeforeCompletionEnabled(flushBeforeCompletion);
+
+		boolean autoCloseSession = PropertiesHelper.getBoolean(Environment.AUTO_CLOSE_SESSION, properties);
+		log.info("Automatic session close at end of transaction: " + enabledDisabled(autoCloseSession) );
+		settings.setAutoCloseSessionEnabled(autoCloseSession);
+
+		//JDBC and connection settings:
+
+		int batchSize = PropertiesHelper.getInt(Environment.STATEMENT_BATCH_SIZE, properties, 0);
+		if ( !metaSupportsBatchUpdates ) batchSize = 0;
+		if (batchSize>0) log.info("JDBC batch size: " + batchSize);
+		settings.setJdbcBatchSize(batchSize);
+		boolean jdbcBatchVersionedData = PropertiesHelper.getBoolean(Environment.BATCH_VERSIONED_DATA, properties, false);
+		if (batchSize>0) log.info("JDBC batch updates for versioned data: " + enabledDisabled(jdbcBatchVersionedData) );
+		settings.setJdbcBatchVersionedData(jdbcBatchVersionedData);
+		settings.setBatcherFactory( createBatcherFactory(properties, batchSize) );
+		
+		boolean useScrollableResultSets = PropertiesHelper.getBoolean(Environment.USE_SCROLLABLE_RESULTSET, properties, metaSupportsScrollable);
+		log.info("Scrollable result sets: " + enabledDisabled(useScrollableResultSets) );
+		settings.setScrollableResultSetsEnabled(useScrollableResultSets);
+
+		boolean wrapResultSets = PropertiesHelper.getBoolean(Environment.WRAP_RESULT_SETS, properties, false);
+		log.debug( "Wrap result sets: " + enabledDisabled(wrapResultSets) );
+		settings.setWrapResultSetsEnabled(wrapResultSets);
+
+		boolean useGetGeneratedKeys = PropertiesHelper.getBoolean(Environment.USE_GET_GENERATED_KEYS, properties, metaSupportsGetGeneratedKeys);
+		log.info("JDBC3 getGeneratedKeys(): " + enabledDisabled(useGetGeneratedKeys) );
+		settings.setGetGeneratedKeysEnabled(useGetGeneratedKeys);
+
+		Integer statementFetchSize = PropertiesHelper.getInteger(Environment.STATEMENT_FETCH_SIZE, properties);
+		if (statementFetchSize!=null) log.info("JDBC result set fetch size: " + statementFetchSize);
+		settings.setJdbcFetchSize(statementFetchSize);
+
+		String releaseModeName = PropertiesHelper.getString( Environment.RELEASE_CONNECTIONS, properties, "auto" );
+		log.info( "Connection release mode: " + releaseModeName );
+		ConnectionReleaseMode releaseMode;
+		if ( "auto".equals(releaseModeName) ) {
+			releaseMode = transactionFactory.getDefaultReleaseMode();
+		}
+		else {
+			releaseMode = ConnectionReleaseMode.parse( releaseModeName );
+			if ( releaseMode == ConnectionReleaseMode.AFTER_STATEMENT && !connections.supportsAggressiveRelease() ) {
+				log.warn( "Overriding release mode as connection provider does not support 'after_statement'" );
+				releaseMode = ConnectionReleaseMode.AFTER_TRANSACTION;
+			}
+		}
+		settings.setConnectionReleaseMode( releaseMode );
+
+		//SQL Generation settings:
+
+		String defaultSchema = properties.getProperty(Environment.DEFAULT_SCHEMA);
+		String defaultCatalog = properties.getProperty(Environment.DEFAULT_CATALOG);
+		if (defaultSchema!=null) log.info("Default schema: " + defaultSchema);
+		if (defaultCatalog!=null) log.info("Default catalog: " + defaultCatalog);
+		settings.setDefaultSchemaName(defaultSchema);
+		settings.setDefaultCatalogName(defaultCatalog);
+
+		Integer maxFetchDepth = PropertiesHelper.getInteger(Environment.MAX_FETCH_DEPTH, properties);
+		if (maxFetchDepth!=null) log.info("Maximum outer join fetch depth: " + maxFetchDepth);
+		settings.setMaximumFetchDepth(maxFetchDepth);
+		int batchFetchSize = PropertiesHelper.getInt(Environment.DEFAULT_BATCH_FETCH_SIZE, properties, 1);
+		log.info("Default batch fetch size: " + batchFetchSize);
+		settings.setDefaultBatchFetchSize(batchFetchSize);
+
+		boolean comments = PropertiesHelper.getBoolean(Environment.USE_SQL_COMMENTS, properties);
+		log.info( "Generate SQL with comments: " + enabledDisabled(comments) );
+		settings.setCommentsEnabled(comments);
+		
+		boolean orderUpdates = PropertiesHelper.getBoolean(Environment.ORDER_UPDATES, properties);
+		log.info( "Order SQL updates by primary key: " + enabledDisabled(orderUpdates) );
+		settings.setOrderUpdatesEnabled(orderUpdates);
+
+		boolean orderInserts = PropertiesHelper.getBoolean(Environment.ORDER_INSERTS, properties);
+		log.info( "Order SQL inserts for batching: " + enabledDisabled( orderInserts ) );
+		settings.setOrderInsertsEnabled( orderInserts );
+		
+		//Query parser settings:
+		
+		settings.setQueryTranslatorFactory( createQueryTranslatorFactory(properties) );
+
+		Map querySubstitutions = PropertiesHelper.toMap(Environment.QUERY_SUBSTITUTIONS, " ,=;:\n\t\r\f", properties);
+		log.info("Query language substitutions: " + querySubstitutions);
+		settings.setQuerySubstitutions(querySubstitutions);
+
+		boolean jpaqlCompliance = PropertiesHelper.getBoolean( Environment.JPAQL_STRICT_COMPLIANCE, properties, false );
+		settings.setStrictJPAQLCompliance( jpaqlCompliance );
+		log.info( "JPA-QL strict compliance: " + enabledDisabled( jpaqlCompliance ) );
+		
+		// Second-level / query cache:
+
+		boolean useSecondLevelCache = PropertiesHelper.getBoolean(Environment.USE_SECOND_LEVEL_CACHE, properties, true);
+		log.info( "Second-level cache: " + enabledDisabled(useSecondLevelCache) );
+		settings.setSecondLevelCacheEnabled(useSecondLevelCache);
+
+		boolean useQueryCache = PropertiesHelper.getBoolean(Environment.USE_QUERY_CACHE, properties);
+		log.info( "Query cache: " + enabledDisabled(useQueryCache) );
+		settings.setQueryCacheEnabled(useQueryCache);
+
+		// The cache provider is needed when we either have second-level cache enabled
+		// or query cache enabled.  Note that useSecondLevelCache is enabled by default
+		settings.setRegionFactory( createRegionFactory( properties, ( useSecondLevelCache || useQueryCache ) ) );
+
+		boolean useMinimalPuts = PropertiesHelper.getBoolean(
+				Environment.USE_MINIMAL_PUTS, properties, settings.getRegionFactory().isMinimalPutsEnabledByDefault()
+		);
+		log.info( "Optimize cache for minimal puts: " + enabledDisabled(useMinimalPuts) );
+		settings.setMinimalPutsEnabled(useMinimalPuts);
+
+		String prefix = properties.getProperty(Environment.CACHE_REGION_PREFIX);
+		if ( StringHelper.isEmpty(prefix) ) prefix=null;
+		if (prefix!=null) log.info("Cache region prefix: "+ prefix);
+		settings.setCacheRegionPrefix(prefix);
+
+		boolean useStructuredCacheEntries = PropertiesHelper.getBoolean(Environment.USE_STRUCTURED_CACHE, properties, false);
+		log.info( "Structured second-level cache entries: " + enabledDisabled(useStructuredCacheEntries) );
+		settings.setStructuredCacheEntriesEnabled(useStructuredCacheEntries);
+
+		if (useQueryCache) settings.setQueryCacheFactory( createQueryCacheFactory(properties) );
+		
+		//SQL Exception converter:
+		
+		SQLExceptionConverter sqlExceptionConverter;
+		try {
+			sqlExceptionConverter = SQLExceptionConverterFactory.buildSQLExceptionConverter( dialect, properties );
+		}
+		catch(HibernateException e) {
+			log.warn("Error building SQLExceptionConverter; using minimal converter");
+			sqlExceptionConverter = SQLExceptionConverterFactory.buildMinimalSQLExceptionConverter();
+		}
+		settings.setSQLExceptionConverter(sqlExceptionConverter);
+
+		//Statistics and logging:
+
+		boolean showSql = PropertiesHelper.getBoolean(Environment.SHOW_SQL, properties);
+		if (showSql) log.info("Echoing all SQL to stdout");
+		settings.setShowSqlEnabled(showSql);
+
+		boolean formatSql = PropertiesHelper.getBoolean(Environment.FORMAT_SQL, properties);
+		settings.setFormatSqlEnabled(formatSql);
+		
+		boolean useStatistics = PropertiesHelper.getBoolean(Environment.GENERATE_STATISTICS, properties);
+		log.info( "Statistics: " + enabledDisabled(useStatistics) );
+		settings.setStatisticsEnabled(useStatistics);
+		
+		boolean useIdentifierRollback = PropertiesHelper.getBoolean(Environment.USE_IDENTIFIER_ROLLBACK, properties);
+		log.info( "Deleted entity synthetic identifier rollback: " + enabledDisabled(useIdentifierRollback) );
+		settings.setIdentifierRollbackEnabled(useIdentifierRollback);
+		
+		//Schema export:
+		
+		String autoSchemaExport = properties.getProperty(Environment.HBM2DDL_AUTO);
+		if ( "validate".equals(autoSchemaExport) ) settings.setAutoValidateSchema(true);
+		if ( "update".equals(autoSchemaExport) ) settings.setAutoUpdateSchema(true);
+		if ( "create".equals(autoSchemaExport) ) settings.setAutoCreateSchema(true);
+		if ( "create-drop".equals(autoSchemaExport) ) {
+			settings.setAutoCreateSchema(true);
+			settings.setAutoDropSchema(true);
+		}
+
+		EntityMode defaultEntityMode = EntityMode.parse( properties.getProperty( Environment.DEFAULT_ENTITY_MODE ) );
+		log.info( "Default entity-mode: " + defaultEntityMode );
+		settings.setDefaultEntityMode( defaultEntityMode );
+
+		boolean namedQueryChecking = PropertiesHelper.getBoolean( Environment.QUERY_STARTUP_CHECKING, properties, true );
+		log.info( "Named query checking : " + enabledDisabled( namedQueryChecking ) );
+		settings.setNamedQueryStartupCheckingEnabled( namedQueryChecking );
+
+//		String provider = properties.getProperty( Environment.BYTECODE_PROVIDER );
+//		log.info( "Bytecode provider name : " + provider );
+//		BytecodeProvider bytecodeProvider = buildBytecodeProvider( provider );
+//		settings.setBytecodeProvider( bytecodeProvider );
+
+		return settings;
+
+	}
+
+	protected BytecodeProvider buildBytecodeProvider(String providerName) {
+		if ( "javassist".equals( providerName ) ) {
+			return new org.hibernate.bytecode.javassist.BytecodeProviderImpl();
+		}
+		else if ( "cglib".equals( providerName ) ) {
+			return new org.hibernate.bytecode.cglib.BytecodeProviderImpl();
+		}
+		else {
+			log.debug( "using cglib as bytecode provider by default" );
+			return new org.hibernate.bytecode.cglib.BytecodeProviderImpl();
+		}
+	}
+
+	private int getDatabaseMajorVersion(DatabaseMetaData meta) {
+		try {
+			Method gdbmvMethod = DatabaseMetaData.class.getMethod("getDatabaseMajorVersion", null);
+			return ( (Integer) gdbmvMethod.invoke(meta, null) ).intValue();
+		}
+		catch (NoSuchMethodException nsme) {
+			return 0;
+		}
+		catch (Throwable t) {
+			log.debug("could not get database version from JDBC metadata");
+			return 0;
+		}
+	}
+
+	private static String enabledDisabled(boolean value) {
+		return value ? "enabled" : "disabled";
+	}
+	
+	protected QueryCacheFactory createQueryCacheFactory(Properties properties) {
+		String queryCacheFactoryClassName = PropertiesHelper.getString(
+				Environment.QUERY_CACHE_FACTORY, properties, "org.hibernate.cache.StandardQueryCacheFactory"
+		);
+		log.info("Query cache factory: " + queryCacheFactoryClassName);
+		try {
+			return (QueryCacheFactory) ReflectHelper.classForName(queryCacheFactoryClassName).newInstance();
+		}
+		catch (Exception cnfe) {
+			throw new HibernateException("could not instantiate QueryCacheFactory: " + queryCacheFactoryClassName, cnfe);
+		}
+	}
+
+	protected RegionFactory createRegionFactory(Properties properties, boolean cachingEnabled) {
+		String regionFactoryClassName = PropertiesHelper.getString( Environment.CACHE_REGION_FACTORY, properties, null );
+		if ( regionFactoryClassName == null && cachingEnabled ) {
+			String providerClassName = PropertiesHelper.getString( Environment.CACHE_PROVIDER, properties, null );
+			if ( providerClassName != null ) {
+				// legacy behavior, apply the bridge...
+				regionFactoryClassName = RegionFactoryCacheProviderBridge.class.getName();
+			}
+		}
+		if ( regionFactoryClassName == null ) {
+			regionFactoryClassName = DEF_CACHE_REG_FACTORY;
+		}
+		log.info( "Cache region factory : " + regionFactoryClassName );
+		try {
+			return ( RegionFactory ) ReflectHelper.classForName( regionFactoryClassName )
+					.getConstructor( new Class[] { Properties.class } )
+					.newInstance( new Object[] { properties } );
+		}
+		catch ( Exception e ) {
+			throw new HibernateException( "could not instantiate RegionFactory [" + regionFactoryClassName + "]", e );
+		}
+	}
+	
+	protected QueryTranslatorFactory createQueryTranslatorFactory(Properties properties) {
+		String className = PropertiesHelper.getString(
+				Environment.QUERY_TRANSLATOR, properties, "org.hibernate.hql.ast.ASTQueryTranslatorFactory"
+		);
+		log.info("Query translator: " + className);
+		try {
+			return (QueryTranslatorFactory) ReflectHelper.classForName(className).newInstance();
+		}
+		catch (Exception cnfe) {
+			throw new HibernateException("could not instantiate QueryTranslatorFactory: " + className, cnfe);
+		}
+	}
+	
+	protected BatcherFactory createBatcherFactory(Properties properties, int batchSize) {
+		String batcherClass = properties.getProperty(Environment.BATCH_STRATEGY);
+		if (batcherClass==null) {
+			return batchSize==0 ?
+					(BatcherFactory) new NonBatchingBatcherFactory() :
+					(BatcherFactory) new BatchingBatcherFactory();
+		}
+		else {
+			log.info("Batcher factory: " + batcherClass);
+			try {
+				return (BatcherFactory) ReflectHelper.classForName(batcherClass).newInstance();
+			}
+			catch (Exception cnfe) {
+				throw new HibernateException("could not instantiate BatcherFactory: " + batcherClass, cnfe);
+			}
+		}
+	}
+	
+	protected ConnectionProvider createConnectionProvider(Properties properties) {
+		return ConnectionProviderFactory.newConnectionProvider(properties);
+	}
+	
+	protected TransactionFactory createTransactionFactory(Properties properties) {
+		return TransactionFactoryFactory.buildTransactionFactory(properties);
+	}
+	
+	protected TransactionManagerLookup createTransactionManagerLookup(Properties properties) {
+		return TransactionManagerLookupFactory.getTransactionManagerLookup(properties);		
+	}
+
+	private Dialect determineDialect(Properties props, String databaseName, int databaseMajorVersion) {
+		return DialectFactory.buildDialect( props, databaseName, databaseMajorVersion );
+	}
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines APIs for configuring Hibernate, and classes
+	for building the Hibernate configuration-time metamodel.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/cfg/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/classic/Lifecycle.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/classic/Lifecycle.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/classic/Lifecycle.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,94 @@
+//$Id: Lifecycle.java 7566 2005-07-20 07:16:33Z oneovthafew $
+package org.hibernate.classic;
+
+import java.io.Serializable;
+
+import org.hibernate.CallbackException;
+import org.hibernate.Session;
+
+/**
+ * Provides callbacks from the <tt>Session</tt> to the persistent object.
+ * Persistent classes <b>may</b> implement this interface but they are not
+ * required to.<br>
+ * <br>
+ * <b>onSave:</b> called just before the object is saved<br>
+ * <b>onUpdate:</b> called just before an object is updated,
+ * ie. when <tt>Session.update()</tt> is called<br>
+ * <b>onDelete:</b> called just before an object is deleted<br>
+ * <b>onLoad:</b> called just after an object is loaded<br>
+ * <br>
+ * <tt>onLoad()</tt> may be used to initialize transient properties of the
+ * object from its persistent state. It may <b>not</b> be used to load
+ * dependent objects since the <tt>Session</tt> interface may not be
+ * invoked from inside this method.<br>
+ * <br>
+ * A further intended usage of <tt>onLoad()</tt>, <tt>onSave()</tt> and
+ * <tt>onUpdate()</tt> is to store a reference to the <tt>Session</tt>
+ * for later use.<br>
+ * <br>
+ * If <tt>onSave()</tt>, <tt>onUpdate()</tt> or <tt>onDelete()</tt> return
+ * <tt>VETO</tt>, the operation is silently vetoed. If a
+ * <tt>CallbackException</tt> is thrown, the operation is vetoed and the
+ * exception is passed back to the application.<br>
+ * <br>
+ * Note that <tt>onSave()</tt> is called after an identifier is assigned
+ * to the object, except when identity column key generation is used.
+ *
+ * @see CallbackException
+ * @author Gavin King
+ */
+public interface Lifecycle {
+
+	/**
+	 * Return value to veto the action (true)
+	 */
+	public static final boolean VETO = true;
+
+	/**
+	 * Return value to accept the action (false)
+	 */
+	public static final boolean NO_VETO = false;
+
+	/**
+	 * Called when an entity is saved.
+	 * @param s the session
+	 * @return true to veto save
+	 * @throws CallbackException
+	 */
+	public boolean onSave(Session s) throws CallbackException;
+
+	/**
+	 * Called when an entity is passed to <tt>Session.update()</tt>.
+	 * This method is <em>not</em> called every time the object's
+	 * state is persisted during a flush.
+	 * @param s the session
+	 * @return true to veto update
+	 * @throws CallbackException
+	 */
+	public boolean onUpdate(Session s) throws CallbackException;
+
+	/**
+	 * Called when an entity is deleted.
+	 * @param s the session
+	 * @return true to veto delete
+	 * @throws CallbackException
+	 */
+	public boolean onDelete(Session s) throws CallbackException;
+
+	/**
+	 * Called after an entity is loaded. <em>It is illegal to
+	 * access the <tt>Session</tt> from inside this method.</em>
+	 * However, the object may keep a reference to the session
+	 * for later use.
+	 *
+	 * @param s the session
+	 * @param id the identifier
+	 */
+	public void onLoad(Session s, Serializable id);
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/classic/Session.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/classic/Session.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/classic/Session.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,352 @@
+//$Id: Session.java 9652 2006-03-17 18:59:03Z steve.ebersole at jboss.com $
+package org.hibernate.classic;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.type.Type;
+
+/**
+ * An extension of the <tt>Session</tt> API, including all
+ * deprecated methods from Hibernate2. This interface is
+ * provided to allow easier migration of existing applications.
+ * New code should use <tt>org.hibernate.Session</tt>.
+ * @author Gavin King
+ */
+public interface Session extends org.hibernate.Session {
+
+	/**
+	 * Copy the state of the given object onto the persistent object with the same
+	 * identifier. If there is no persistent instance currently associated with
+	 * the session, it will be loaded. Return the persistent instance. If the
+	 * given instance is unsaved or does not exist in the database, save it and
+	 * return it as a newly persistent instance. Otherwise, the given instance
+	 * does not become associated with the session.
+	 *
+	 * @deprecated use {@link org.hibernate.Session#merge(Object)}
+	 *
+	 * @param object a transient instance with state to be copied
+	 * @return an updated persistent instance
+	 */
+	public Object saveOrUpdateCopy(Object object) throws HibernateException;
+
+	/**
+	 * Copy the state of the given object onto the persistent object with the
+	 * given identifier. If there is no persistent instance currently associated
+	 * with the session, it will be loaded. Return the persistent instance. If
+	 * there is no database row with the given identifier, save the given instance
+	 * and return it as a newly persistent instance. Otherwise, the given instance
+	 * does not become associated with the session.
+	 *
+	 * @deprecated with no replacement
+	 *
+	 * @param object a persistent or transient instance with state to be copied
+	 * @param id the identifier of the instance to copy to
+	 * @return an updated persistent instance
+	 */
+	public Object saveOrUpdateCopy(Object object, Serializable id) throws HibernateException;
+
+	/**
+	 * Copy the state of the given object onto the persistent object with the same
+	 * identifier. If there is no persistent instance currently associated with
+	 * the session, it will be loaded. Return the persistent instance. If the
+	 * given instance is unsaved or does not exist in the database, save it and
+	 * return it as a newly persistent instance. Otherwise, the given instance
+	 * does not become associated with the session.
+	 *
+	 * @deprecated use {@link org.hibernate.Session#merge(String, Object)}
+	 *
+	 * @param object a transient instance with state to be copied
+	 * @return an updated persistent instance
+	 */
+	public Object saveOrUpdateCopy(String entityName, Object object) throws HibernateException;
+
+	/**
+	 * Copy the state of the given object onto the persistent object with the
+	 * given identifier. If there is no persistent instance currently associated
+	 * with the session, it will be loaded. Return the persistent instance. If
+	 * there is no database row with the given identifier, save the given instance
+	 * and return it as a newly persistent instance. Otherwise, the given instance
+	 * does not become associated with the session.
+	 *
+	 * @deprecated with no replacement
+	 *
+	 * @param object a persistent or transient instance with state to be copied
+	 * @param id the identifier of the instance to copy to
+	 * @return an updated persistent instance
+	 */
+	public Object saveOrUpdateCopy(String entityName, Object object, Serializable id) throws HibernateException;
+
+	/**
+	 * Execute a query.
+	 *
+	 * @deprecated use {@link #createQuery}.{@link Query#list()}
+	 *
+	 * @param query a query expressed in Hibernate's query language
+	 * @return a distinct list of instances (or arrays of instances)
+	 * @throws HibernateException
+	 */
+	public List find(String query) throws HibernateException;
+			
+	/**
+	 * Execute a query with bind parameters, binding a value to a "?" parameter
+	 * in the query string.
+	 *
+	 * @deprecated use {@link #createQuery}.setXYZ.{@link Query#list()}
+	 *
+	 * @param query the query string
+	 * @param value a value to be bound to a "?" placeholder (JDBC IN parameter).
+	 * @param type the Hibernate type of the value
+	 * @see org.hibernate.Hibernate for access to <tt>Type</tt> instances
+	 * @return a distinct list of instances (or arrays of instances)
+	 * @throws HibernateException
+	 */
+	public List find(String query, Object value, Type type) throws HibernateException;
+	
+	/**
+	 * Execute a query with bind parameters, binding an array of values to "?"
+	 * parameters in the query string.
+	 *
+	 * @deprecated use {@link #createQuery}.setXYZ.{@link Query#list()}
+	 *
+	 * @param query the query string
+	 * @param values an array of values to be bound to the "?" placeholders (JDBC IN parameters).
+	 * @param types an array of Hibernate types of the values
+	 * @see org.hibernate.Hibernate for access to <tt>Type</tt> instances
+	 * @return a distinct list of instances
+	 * @throws HibernateException
+	 */
+	public List find(String query, Object[] values, Type[] types) throws HibernateException;
+	
+	/**
+	 * Execute a query and return the results in an iterator. If the query has multiple
+	 * return values, values will be returned in an array of type <tt>Object[].</tt><br>
+	 * <br>
+	 * Entities returned as results are initialized on demand. The first SQL query returns
+	 * identifiers only. So <tt>iterate()</tt> is usually a less efficient way to retrieve
+	 * objects than <tt>find()</tt>.
+	 * 
+	 * @deprecated use {@link #createQuery}.{@link Query#iterate}
+	 *
+	 * @param query the query string
+	 * @return an iterator
+	 * @throws HibernateException
+	 */
+	public Iterator iterate(String query) throws HibernateException;
+	
+	/**
+	 * Execute a query and return the results in an iterator. Write the given value to "?"
+	 * in the query string. If the query has multiple return values, values will be returned
+	 * in an array of type <tt>Object[]</tt>.<br>
+	 * <br>
+	 * Entities returned as results are initialized on demand. The first SQL query returns
+	 * identifiers only. So <tt>iterate()</tt> is usually a less efficient way to retrieve
+	 * objects than <tt>find()</tt>.
+	 *
+	 * @deprecated use {@link #createQuery}.setXYZ.{@link Query#iterate}
+	 *
+	 * @param query the query string
+	 * @param value a value to be witten to a "?" placeholder in the query string
+	 * @param type the hibernate type of value
+	 * @return an iterator
+	 * @throws HibernateException
+	 */
+	public Iterator iterate(String query, Object value, Type type) throws HibernateException;
+	
+	/**
+	 * Execute a query and return the results in an iterator. Write the given values to "?"
+	 * in the query string. If the query has multiple return values, values will be returned
+	 * in an array of type <tt>Object[]</tt>.<br>
+	 * <br>
+	 * Entities returned as results are initialized on demand. The first SQL query returns
+	 * identifiers only. So <tt>iterate()</tt> is usually a less efficient way to retrieve
+	 * objects than <tt>find()</tt>.
+	 *
+	 * @deprecated use {@link #createQuery}.setXYZ.{@link Query#iterate}
+	 *
+	 * @param query the query string
+	 * @param values a list of values to be written to "?" placeholders in the query
+	 * @param types a list of Hibernate types of the values
+	 * @return an iterator
+	 * @throws HibernateException
+	 */
+	public Iterator iterate(String query, Object[] values, Type[] types) throws HibernateException;
+	
+	/**
+	 * Apply a filter to a persistent collection. A filter is a Hibernate query that may refer to
+	 * <tt>this</tt>, the collection element. Filters allow efficient access to very large lazy
+	 * collections. (Executing the filter does not initialize the collection.)
+	 * 
+	 * @deprecated use {@link #createFilter(Object, String)}.{@link Query#list}
+	 *
+	 * @param collection a persistent collection to filter
+	 * @param filter a filter query string
+	 * @return Collection the resulting collection
+	 * @throws HibernateException
+	 */
+	public Collection filter(Object collection, String filter) throws HibernateException;
+	
+	/**
+	 * Apply a filter to a persistent collection. A filter is a Hibernate query that may refer to
+	 * <tt>this</tt>, the collection element.
+	 *
+	 * @deprecated use {@link #createFilter(Object, String)}.setXYZ.{@link Query#list}
+	 *
+	 * @param collection a persistent collection to filter
+	 * @param filter a filter query string
+	 * @param value a value to be witten to a "?" placeholder in the query string
+	 * @param type the hibernate type of value
+	 * @return Collection
+	 * @throws HibernateException
+	 */
+	public Collection filter(Object collection, String filter, Object value, Type type) throws HibernateException;
+	
+	/**
+	 * Apply a filter to a persistent collection.
+	 *
+	 * Bind the given parameters to "?" placeholders. A filter is a Hibernate query that
+	 * may refer to <tt>this</tt>, the collection element.
+	 *
+	 * @deprecated use {@link #createFilter(Object, String)}.setXYZ.{@link Query#list}
+	 *
+	 * @param collection a persistent collection to filter
+	 * @param filter a filter query string
+	 * @param values a list of values to be written to "?" placeholders in the query
+	 * @param types a list of Hibernate types of the values
+	 * @return Collection
+	 * @throws HibernateException
+	 */
+	public Collection filter(Object collection, String filter, Object[] values, Type[] types) throws HibernateException;
+	
+	/**
+	 * Delete all objects returned by the query. Return the number of objects deleted.
+	 * <p/>
+	 * Note that this is very different from the delete-statement support added in HQL
+	 * since 3.1.  The functionality here is to actually peform the query and then iterate
+	 * the results calling {@link #delete(Object)} individually.
+	 * 
+	 * @deprecated consider using HQL delete statements
+	 *
+	 * @param query the query string
+	 * @return the number of instances deleted
+	 * @throws HibernateException
+	 */
+	public int delete(String query) throws HibernateException;
+	
+	/**
+	 * Delete all objects returned by the query. Return the number of objects deleted.
+	 * <p/>
+	 * Note that this is very different from the delete-statement support added in HQL
+	 * since 3.1.  The functionality here is to actually peform the query and then iterate
+	 * the results calling {@link #delete(Object)} individually.
+	 *
+	 * @deprecated consider using HQL delete statements
+	 *
+	 * @param query the query string
+	 * @param value a value to be witten to a "?" placeholder in the query string.
+	 * @param type the hibernate type of value.
+	 * @return the number of instances deleted
+	 * @throws HibernateException
+	 */
+	public int delete(String query, Object value, Type type) throws HibernateException;
+	
+	/**
+	 * Delete all objects returned by the query. Return the number of objects deleted.
+	 * <p/>
+	 * Note that this is very different from the delete-statement support added in HQL
+	 * since 3.1.  The functionality here is to actually peform the query and then iterate
+	 * the results calling {@link #delete(Object)} individually.
+	 *
+	 * @deprecated consider using HQL delete statements
+	 *
+	 * @param query the query string
+	 * @param values a list of values to be written to "?" placeholders in the query.
+	 * @param types a list of Hibernate types of the values
+	 * @return the number of instances deleted
+	 * @throws HibernateException
+	 */
+	public int delete(String query, Object[] values, Type[] types) throws HibernateException;
+
+
+	/**
+	 * Create a new instance of <tt>Query</tt> for the given SQL string.
+	 *
+	 * @deprecated will be replaced with a more Query like interface in later release
+	 *
+	 * @param sql a query expressed in SQL
+	 * @param returnAlias a table alias that appears inside <tt>{}</tt> in the SQL string
+	 * @param returnClass the returned persistent class
+	 */
+	public Query createSQLQuery(String sql, String returnAlias, Class returnClass);
+	
+	/**
+	 * Create a new instance of <tt>Query</tt> for the given SQL string.
+	 *
+	 * @deprecated will be replaced with a more Query like interface in later release
+	 *
+	 * @param sql a query expressed in SQL
+	 * @param returnAliases an array of table aliases that appear inside <tt>{}</tt> in the SQL string
+	 * @param returnClasses the returned persistent classes
+	 */
+	public Query createSQLQuery(String sql, String[] returnAliases, Class[] returnClasses);
+	
+	
+	/**
+	 * Persist the given transient instance, using the given identifier.  This operation 
+	 * cascades to associated instances if the association is mapped with 
+	 * <tt>cascade="save-update"</tt>.
+	 *
+	 * @deprecated declare identifier properties for all classes
+	 *
+	 * @param object a transient instance of a persistent class
+	 * @param id an unused valid identifier
+	 * @throws HibernateException
+	 */
+	public void save(Object object, Serializable id) throws HibernateException;
+
+	/**
+	 * Persist the given transient instance, using the given identifier. This operation 
+	 * cascades to associated instances if the association is mapped with 
+	 * <tt>cascade="save-update"</tt>.
+	 *
+	 * @deprecated declare identifier properties for all classes
+	 *
+	 * @param object a transient instance of a persistent class
+	 * @param id an unused valid identifier
+	 * @throws HibernateException
+	 */
+	public void save(String entityName, Object object, Serializable id) throws HibernateException;
+
+	/**
+	 * Update the persistent state associated with the given identifier. An exception
+	 * is thrown if there is a persistent instance with the same identifier in the
+	 * current session. This operation cascades to associated instances 
+	 * if the association is mapped with <tt>cascade="save-update"</tt>.
+	 *
+	 * @deprecated declare identifier properties for all classes
+	 *
+	 * @param object a detached instance containing updated state
+	 * @param id identifier of persistent instance
+	 * @throws HibernateException
+	 */
+	public void update(Object object, Serializable id) throws HibernateException;
+
+	/**
+	 * Update the persistent state associated with the given identifier. An exception
+	 * is thrown if there is a persistent instance with the same identifier in the
+	 * current session. This operation cascades to associated instances 
+	 * if the association is mapped with <tt>cascade="save-update"</tt>.
+	 * 
+	 * @deprecated declare identifier properties for all classes
+	 *
+	 * @param object a detached instance containing updated state
+	 * @param id identifier of persistent instance
+	 * @throws HibernateException
+	 */
+	public void update(String entityName, Object object, Serializable id) throws HibernateException;
+	
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/classic/Session.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/classic/Validatable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/classic/Validatable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/classic/Validatable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: Validatable.java 4112 2004-07-28 03:33:35Z oneovthafew $
+package org.hibernate.classic;
+
+
+/**
+ * Implemented by persistent classes with invariants that must
+ * be checked before inserting into or updating the database.
+ *
+ * @author Gavin King
+ */
+public interface Validatable {
+	/**
+	 * Validate the state of the object before persisting it.
+	 * If a violation occurs, throw a <tt>ValidationFailure</tt>.
+	 * This method must not change the state of the object by
+	 * side-effect.
+	 * @throws ValidationFailure if an invariant is violated
+	 */
+	public void validate() throws ValidationFailure;
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/classic/ValidationFailure.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/classic/ValidationFailure.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/classic/ValidationFailure.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+//$Id: ValidationFailure.java 4112 2004-07-28 03:33:35Z oneovthafew $
+package org.hibernate.classic;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Thrown from <tt>Validatable.validate()</tt> when an invariant
+ * was violated. Some applications might subclass this exception
+ * in order to provide more information about the violation.
+ *
+ * @author Gavin King
+ */
+public class ValidationFailure extends HibernateException {
+
+	public ValidationFailure(String message) {
+		super(message);
+	}
+
+	public ValidationFailure(String message, Exception e) {
+		super(message, e);
+	}
+
+	public ValidationFailure(Exception e) {
+		super("A validation failure occurred", e);
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/classic/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/classic/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/classic/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package implements backward-compatibility with Hibernate 2.1
+	APIs now deprecated in Hibernate3.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/classic/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/AbstractPersistentCollection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/AbstractPersistentCollection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/AbstractPersistentCollection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,943 @@
+//$Id: AbstractPersistentCollection.java 11302 2007-03-19 20:44:11Z steve.ebersole at jboss.com $
+package org.hibernate.collection;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.LazyInitializationException;
+import org.hibernate.engine.CollectionEntry;
+import org.hibernate.engine.ForeignKeys;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.type.Type;
+import org.hibernate.util.CollectionHelper;
+import org.hibernate.util.EmptyIterator;
+import org.hibernate.util.MarkerObject;
+
+/**
+ * Base class implementing <tt>PersistentCollection</tt>
+ * @see PersistentCollection
+ * @author Gavin King
+ */
+public abstract class AbstractPersistentCollection 
+	implements Serializable, PersistentCollection {
+
+	private transient SessionImplementor session;
+	private boolean initialized;
+	private transient List operationQueue;
+	private transient boolean directlyAccessible;
+	private transient boolean initializing;
+	private Object owner;
+	private int cachedSize = -1;
+	
+	private String role;
+	private Serializable key;
+	// collections detect changes made via their public interface and mark
+	// themselves as dirty as a performance optimization
+	private boolean dirty;
+	private Serializable storedSnapshot;
+
+	public final String getRole() {
+		return role;
+	}
+	
+	public final Serializable getKey() {
+		return key;
+	}
+	
+	public final boolean isUnreferenced() {
+		return role==null;
+	}
+	
+	public final boolean isDirty() {
+		return dirty;
+	}
+	
+	public final void clearDirty() {
+		dirty = false;
+	}
+	
+	public final void dirty() {
+		dirty = true;
+	}
+	
+	public final Serializable getStoredSnapshot() {
+		return storedSnapshot;
+	}
+	
+	//Careful: these methods do not initialize the collection.
+	/**
+	 * Is the initialized collection empty?
+	 */
+	public abstract boolean empty();
+	/**
+	 * Called by any read-only method of the collection interface
+	 */
+	protected final void read() {
+		initialize(false);
+	}
+	/**
+	 * Called by the <tt>size()</tt> method
+	 */
+	protected boolean readSize() {
+		if (!initialized) {
+			if ( cachedSize!=-1 && !hasQueuedOperations() ) {
+				return true;
+			}
+			else {
+				throwLazyInitializationExceptionIfNotConnected();
+				CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this);
+				CollectionPersister persister = entry.getLoadedPersister();
+				if ( persister.isExtraLazy() ) {
+					if ( hasQueuedOperations() ) {
+						session.flush();
+					}
+					cachedSize = persister.getSize( entry.getLoadedKey(), session );
+					return true;
+				}
+			}
+		}
+		read();
+		return false;
+	}
+	
+	protected Boolean readIndexExistence(Object index) {
+		if (!initialized) {
+			throwLazyInitializationExceptionIfNotConnected();
+			CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this);
+			CollectionPersister persister = entry.getLoadedPersister();
+			if ( persister.isExtraLazy() ) {
+				if ( hasQueuedOperations() ) {
+					session.flush();
+				}
+				return new Boolean( persister.indexExists( entry.getLoadedKey(), index, session ) );
+			}
+		}
+		read();
+		return null;
+		
+	}
+	
+	protected Boolean readElementExistence(Object element) {
+		if (!initialized) {
+			throwLazyInitializationExceptionIfNotConnected();
+			CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this);
+			CollectionPersister persister = entry.getLoadedPersister();
+			if ( persister.isExtraLazy() ) {
+				if ( hasQueuedOperations() ) {
+					session.flush();
+				}
+				return new Boolean( persister.elementExists( entry.getLoadedKey(), element, session ) );
+			}
+		}
+		read();
+		return null;
+		
+	}
+	
+	protected static final Object UNKNOWN = new MarkerObject("UNKNOWN");
+	
+	protected Object readElementByIndex(Object index) {
+		if (!initialized) {
+			throwLazyInitializationExceptionIfNotConnected();
+			CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this);
+			CollectionPersister persister = entry.getLoadedPersister();
+			if ( persister.isExtraLazy() ) {
+				if ( hasQueuedOperations() ) {
+					session.flush();
+				}
+				return persister.getElementByIndex( entry.getLoadedKey(), index, session, owner );
+			}
+		}
+		read();
+		return UNKNOWN;
+		
+	}
+	
+	protected int getCachedSize() {
+		return cachedSize;
+	}
+	
+	/**
+	 * Is the collection currently connected to an open session?
+	 */
+	private final boolean isConnectedToSession() {
+		return session!=null && 
+				session.isOpen() &&
+				session.getPersistenceContext().containsCollection(this);
+	}
+
+	/**
+	 * Called by any writer method of the collection interface
+	 */
+	protected final void write() {
+		initialize(true);
+		dirty();
+	}
+	/**
+	 * Is this collection in a state that would allow us to
+	 * "queue" operations?
+	 */
+	protected boolean isOperationQueueEnabled() {
+		return !initialized &&
+				isConnectedToSession() &&
+				isInverseCollection();
+	}
+	/**
+	 * Is this collection in a state that would allow us to
+	 * "queue" puts? This is a special case, because of orphan
+	 * delete.
+	 */
+	protected boolean isPutQueueEnabled() {
+		return !initialized &&
+				isConnectedToSession() &&
+				isInverseOneToManyOrNoOrphanDelete();
+	}
+	/**
+	 * Is this collection in a state that would allow us to
+	 * "queue" clear? This is a special case, because of orphan
+	 * delete.
+	 */
+	protected boolean isClearQueueEnabled() {
+		return !initialized &&
+				isConnectedToSession() &&
+				isInverseCollectionNoOrphanDelete();
+	}
+
+	/**
+	 * Is this the "inverse" end of a bidirectional association?
+	 */
+	private boolean isInverseCollection() {
+		CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this);
+		return ce != null && ce.getLoadedPersister().isInverse();
+	}
+
+	/**
+	 * Is this the "inverse" end of a bidirectional association with
+	 * no orphan delete enabled?
+	 */
+	private boolean isInverseCollectionNoOrphanDelete() {
+		CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this);
+		return ce != null && 
+				ce.getLoadedPersister().isInverse() &&
+				!ce.getLoadedPersister().hasOrphanDelete();
+	}
+
+	/**
+	 * Is this the "inverse" end of a bidirectional one-to-many, or 
+	 * of a collection with no orphan delete?
+	 */
+	private boolean isInverseOneToManyOrNoOrphanDelete() {
+		CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this);
+		return ce != null && ce.getLoadedPersister().isInverse() && (
+				ce.getLoadedPersister().isOneToMany() || 
+				!ce.getLoadedPersister().hasOrphanDelete() 
+			);
+	}
+
+	/**
+	 * Queue an addition
+	 */
+	protected final void queueOperation(Object element) {
+		if (operationQueue==null) operationQueue = new ArrayList(10);
+		operationQueue.add(element);
+		dirty = true; //needed so that we remove this collection from the second-level cache
+	}
+
+	/**
+	 * After reading all existing elements from the database,
+	 * add the queued elements to the underlying collection.
+	 */
+	protected final void performQueuedOperations() {
+		for ( int i=0; i<operationQueue.size(); i++ ) {
+			( (DelayedOperation) operationQueue.get(i) ).operate();
+		}
+	}
+
+	/**
+	 * After flushing, re-init snapshot state.
+	 */
+	public void setSnapshot(Serializable key, String role, Serializable snapshot) {
+		this.key = key;
+		this.role = role;
+		this.storedSnapshot = snapshot;
+	}
+
+	/**
+	 * After flushing, clear any "queued" additions, since the
+	 * database state is now synchronized with the memory state.
+	 */
+	public void postAction() {
+		operationQueue=null;
+		cachedSize = -1;
+		clearDirty();
+	}
+	
+	/**
+	 * Not called by Hibernate, but used by non-JDK serialization,
+	 * eg. SOAP libraries.
+	 */
+	public AbstractPersistentCollection() {}
+
+	protected AbstractPersistentCollection(SessionImplementor session) {
+		this.session = session;
+	}
+
+	/**
+	 * return the user-visible collection (or array) instance
+	 */
+	public Object getValue() {
+		return this;
+	}
+
+	/**
+	 * Called just before reading any rows from the JDBC result set
+	 */
+	public void beginRead() {
+		// override on some subclasses
+		initializing = true;
+	}
+
+	/**
+	 * Called after reading all rows from the JDBC result set
+	 */
+	public boolean endRead() {
+		//override on some subclasses
+		return afterInitialize();
+	}
+	
+	public boolean afterInitialize() {
+		setInitialized();
+		//do this bit after setting initialized to true or it will recurse
+		if (operationQueue!=null) {
+			performQueuedOperations();
+			operationQueue=null;
+			cachedSize = -1;
+			return false;
+		}
+		else {
+			return true;
+		}
+	}
+
+	/**
+	 * Initialize the collection, if possible, wrapping any exceptions
+	 * in a runtime exception
+	 * @param writing currently obsolete
+	 * @throws LazyInitializationException if we cannot initialize
+	 */
+	protected final void initialize(boolean writing) {
+		if (!initialized) {
+			if (initializing) {
+				throw new LazyInitializationException("illegal access to loading collection");
+			}
+			throwLazyInitializationExceptionIfNotConnected();
+			session.initializeCollection(this, writing);
+		}
+	}
+	
+	private void throwLazyInitializationExceptionIfNotConnected() {
+		if ( !isConnectedToSession() )  {
+			throwLazyInitializationException("no session or session was closed");
+		}
+		if ( !session.isConnected() ) {
+            throwLazyInitializationException("session is disconnected");
+		}		
+	}
+	
+	private void throwLazyInitializationException(String message) {
+		throw new LazyInitializationException(
+				"failed to lazily initialize a collection" + 
+				( role==null ?  "" : " of role: " + role ) + 
+				", " + message
+			);
+	}
+
+	protected final void setInitialized() {
+		this.initializing = false;
+		this.initialized = true;
+	}
+
+	protected final void setDirectlyAccessible(boolean directlyAccessible) {
+		this.directlyAccessible = directlyAccessible;
+	}
+
+	/**
+	 * Could the application possibly have a direct reference to
+	 * the underlying collection implementation?
+	 */
+	public boolean isDirectlyAccessible() {
+		return directlyAccessible;
+	}
+
+	/**
+	 * Disassociate this collection from the given session.
+	 * @return true if this was currently associated with the given session
+	 */
+	public final boolean unsetSession(SessionImplementor currentSession) {
+		if (currentSession==this.session) {
+			this.session=null;
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * Associate the collection with the given session.
+	 * @return false if the collection was already associated with the session
+	 * @throws HibernateException if the collection was already associated
+	 * with another open session
+	 */
+	public final boolean setCurrentSession(SessionImplementor session) throws HibernateException {
+		if (session==this.session) {
+			return false;
+		}
+		else {
+			if ( isConnectedToSession() ) {
+				CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this);
+				if (ce==null) {
+					throw new HibernateException(
+							"Illegal attempt to associate a collection with two open sessions"
+						);
+				}
+				else {
+					throw new HibernateException(
+							"Illegal attempt to associate a collection with two open sessions: " +
+							MessageHelper.collectionInfoString( 
+									ce.getLoadedPersister(), 
+									ce.getLoadedKey(), 
+									session.getFactory() 
+								)
+						);
+				}
+			}
+			else {
+				this.session = session;
+				return true;
+			}
+		}
+	}
+
+	/**
+	 * Do we need to completely recreate this collection when it changes?
+	 */
+	public boolean needsRecreate(CollectionPersister persister) {
+		return false;
+	}
+	
+	/**
+	 * To be called internally by the session, forcing
+	 * immediate initialization.
+	 */
+	public final void forceInitialization() throws HibernateException {
+		if (!initialized) {
+			if (initializing) {
+				throw new AssertionFailure("force initialize loading collection");
+			}
+			if (session==null) {
+				throw new HibernateException("collection is not associated with any session");
+			}
+			if ( !session.isConnected() ) {
+				throw new HibernateException("disconnected session");
+			}
+			session.initializeCollection(this, false);
+		}
+	}
+
+
+	/**
+	 * Get the current snapshot from the session
+	 */
+	protected final Serializable getSnapshot() {
+		return session.getPersistenceContext().getSnapshot(this);
+	}
+
+	/**
+	 * Is this instance initialized?
+	 */
+	public final boolean wasInitialized() {
+		return initialized;
+	}
+	
+	public boolean isRowUpdatePossible() {
+		return true;
+	}
+
+	/**
+	 * Does this instance have any "queued" additions?
+	 */
+	public final boolean hasQueuedOperations() {
+		return operationQueue!=null;
+	}
+	/**
+	 * Iterate the "queued" additions
+	 */
+	public final Iterator queuedAdditionIterator() {
+		if ( hasQueuedOperations() ) {
+			return new Iterator() {
+				int i = 0;
+				public Object next() {
+					return ( (DelayedOperation) operationQueue.get(i++) ).getAddedInstance();
+				}
+				public boolean hasNext() {
+					return i<operationQueue.size();
+				}
+				public void remove() {
+					throw new UnsupportedOperationException();
+				}
+			};
+		}
+		else {
+			return EmptyIterator.INSTANCE;
+		}
+	}
+	/**
+	 * Iterate the "queued" additions
+	 */
+	public final Collection getQueuedOrphans(String entityName) {
+		if ( hasQueuedOperations() ) {
+			Collection additions = new ArrayList( operationQueue.size() );
+			Collection removals = new ArrayList( operationQueue.size() );
+			for ( int i = 0; i < operationQueue.size(); i++ ) {
+				DelayedOperation op = (DelayedOperation) operationQueue.get(i);
+				additions.add( op.getAddedInstance() );
+				removals.add( op.getOrphan() );
+			}
+			return getOrphans(removals, additions, entityName, session);
+		}
+		else {
+			return CollectionHelper.EMPTY_COLLECTION;
+		}
+	}
+
+	/**
+	 * Called before inserting rows, to ensure that any surrogate keys
+	 * are fully generated
+	 */
+	public void preInsert(CollectionPersister persister) throws HibernateException {}
+	/**
+	 * Called after inserting a row, to fetch the natively generated id
+	 */
+	public void afterRowInsert(CollectionPersister persister, Object entry, int i) throws HibernateException {}
+	/**
+	 * get all "orphaned" elements
+	 */
+	public abstract Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException;
+
+	/**
+	 * Get the current session
+	 */
+	public final SessionImplementor getSession() {
+		return session;
+	}
+
+	final class IteratorProxy implements Iterator {
+		private final Iterator iter;
+		IteratorProxy(Iterator iter) {
+			this.iter=iter;
+		}
+		public boolean hasNext() {
+			return iter.hasNext();
+		}
+
+		public Object next() {
+			return iter.next();
+		}
+
+		public void remove() {
+			write();
+			iter.remove();
+		}
+
+	}
+
+	final class ListIteratorProxy implements ListIterator {
+		private final ListIterator iter;
+		ListIteratorProxy(ListIterator iter) {
+			this.iter = iter;
+		}
+		public void add(Object o) {
+			write();
+			iter.add(o);
+		}
+
+		public boolean hasNext() {
+			return iter.hasNext();
+		}
+
+		public boolean hasPrevious() {
+			return iter.hasPrevious();
+		}
+
+		public Object next() {
+			return iter.next();
+		}
+
+		public int nextIndex() {
+			return iter.nextIndex();
+		}
+
+		public Object previous() {
+			return iter.previous();
+		}
+
+		public int previousIndex() {
+			return iter.previousIndex();
+		}
+
+		public void remove() {
+			write();
+			iter.remove();
+		}
+
+		public void set(Object o) {
+			write();
+			iter.set(o);
+		}
+
+	}
+
+	class SetProxy implements java.util.Set {
+
+		final Collection set;
+
+		SetProxy(Collection set) {
+			this.set=set;
+		}
+		public boolean add(Object o) {
+			write();
+			return set.add(o);
+		}
+
+		public boolean addAll(Collection c) {
+			write();
+			return set.addAll(c);
+		}
+
+		public void clear() {
+			write();
+			set.clear();
+		}
+
+		public boolean contains(Object o) {
+			return set.contains(o);
+		}
+
+		public boolean containsAll(Collection c) {
+			return set.containsAll(c);
+		}
+
+		public boolean isEmpty() {
+			return set.isEmpty();
+		}
+
+		public Iterator iterator() {
+			return new IteratorProxy( set.iterator() );
+		}
+
+		public boolean remove(Object o) {
+			write();
+			return set.remove(o);
+		}
+
+		public boolean removeAll(Collection c) {
+			write();
+			return set.removeAll(c);
+		}
+
+		public boolean retainAll(Collection c) {
+			write();
+			return set.retainAll(c);
+		}
+
+		public int size() {
+			return set.size();
+		}
+
+		public Object[] toArray() {
+			return set.toArray();
+		}
+
+		public Object[] toArray(Object[] array) {
+			return set.toArray(array);
+		}
+
+	}
+
+	final class ListProxy implements java.util.List {
+
+		private final java.util.List list;
+
+		ListProxy(java.util.List list) {
+			this.list = list;
+		}
+
+		public void add(int index, Object value) {
+			write();
+			list.add(index, value);
+		}
+
+		/**
+		 * @see java.util.Collection#add(Object)
+		 */
+		public boolean add(Object o) {
+			write();
+			return list.add(o);
+		}
+
+		/**
+		 * @see java.util.Collection#addAll(Collection)
+		 */
+		public boolean addAll(Collection c) {
+			write();
+			return list.addAll(c);
+		}
+
+		/**
+		 * @see java.util.List#addAll(int, Collection)
+		 */
+		public boolean addAll(int i, Collection c) {
+			write();
+			return list.addAll(i, c);
+		}
+
+		/**
+		 * @see java.util.Collection#clear()
+		 */
+		public void clear() {
+			write();
+			list.clear();
+		}
+
+		/**
+		 * @see java.util.Collection#contains(Object)
+		 */
+		public boolean contains(Object o) {
+			return list.contains(o);
+		}
+
+		/**
+		 * @see java.util.Collection#containsAll(Collection)
+		 */
+		public boolean containsAll(Collection c) {
+			return list.containsAll(c);
+		}
+
+		/**
+		 * @see java.util.List#get(int)
+		 */
+		public Object get(int i) {
+			return list.get(i);
+		}
+
+		/**
+		 * @see java.util.List#indexOf(Object)
+		 */
+		public int indexOf(Object o) {
+			return list.indexOf(o);
+		}
+
+		/**
+		 * @see java.util.Collection#isEmpty()
+		 */
+		public boolean isEmpty() {
+			return list.isEmpty();
+		}
+
+		/**
+		 * @see java.util.Collection#iterator()
+		 */
+		public Iterator iterator() {
+			return new IteratorProxy( list.iterator() );
+		}
+
+		/**
+		 * @see java.util.List#lastIndexOf(Object)
+		 */
+		public int lastIndexOf(Object o) {
+			return list.lastIndexOf(o);
+		}
+
+		/**
+		 * @see java.util.List#listIterator()
+		 */
+		public ListIterator listIterator() {
+			return new ListIteratorProxy( list.listIterator() );
+		}
+
+		/**
+		 * @see java.util.List#listIterator(int)
+		 */
+		public ListIterator listIterator(int i) {
+			return new ListIteratorProxy( list.listIterator(i) );
+		}
+
+		/**
+		 * @see java.util.List#remove(int)
+		 */
+		public Object remove(int i) {
+			write();
+			return list.remove(i);
+		}
+
+		/**
+		 * @see java.util.Collection#remove(Object)
+		 */
+		public boolean remove(Object o) {
+			write();
+			return list.remove(o);
+		}
+
+		/**
+		 * @see java.util.Collection#removeAll(Collection)
+		 */
+		public boolean removeAll(Collection c) {
+			write();
+			return list.removeAll(c);
+		}
+
+		/**
+		 * @see java.util.Collection#retainAll(Collection)
+		 */
+		public boolean retainAll(Collection c) {
+			write();
+			return list.retainAll(c);
+		}
+
+		/**
+		 * @see java.util.List#set(int, Object)
+		 */
+		public Object set(int i, Object o) {
+			write();
+			return list.set(i, o);
+		}
+
+		/**
+		 * @see java.util.Collection#size()
+		 */
+		public int size() {
+			return list.size();
+		}
+
+		/**
+		 * @see java.util.List#subList(int, int)
+		 */
+		public List subList(int i, int j) {
+			return list.subList(i, j);
+		}
+
+		/**
+		 * @see java.util.Collection#toArray()
+		 */
+		public Object[] toArray() {
+			return list.toArray();
+		}
+
+		/**
+		 * @see java.util.Collection#toArray(Object[])
+		 */
+		public Object[] toArray(Object[] array) {
+			return list.toArray(array);
+		}
+
+	}
+
+
+	protected interface DelayedOperation {
+		public void operate();
+		public Object getAddedInstance();
+		public Object getOrphan();
+	}
+	
+	/**
+	 * Given a collection of entity instances that used to
+	 * belong to the collection, and a collection of instances
+	 * that currently belong, return a collection of orphans
+	 */
+	protected static Collection getOrphans(
+			Collection oldElements, 
+			Collection currentElements, 
+			String entityName, 
+			SessionImplementor session)
+	throws HibernateException {
+
+		// short-circuit(s)
+		if ( currentElements.size()==0 ) return oldElements; // no new elements, the old list contains only Orphans
+		if ( oldElements.size()==0) return oldElements; // no old elements, so no Orphans neither
+		
+		Type idType = session.getFactory().getEntityPersister(entityName).getIdentifierType();
+
+		// create the collection holding the Orphans
+		Collection res = new ArrayList();
+
+		// collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
+		java.util.Set currentIds = new HashSet();
+		for ( Iterator it=currentElements.iterator(); it.hasNext(); ) {
+			Object current = it.next();
+			if ( current!=null && ForeignKeys.isNotTransient(entityName, current, null, session) ) {
+				Serializable currentId = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, current, session);
+				currentIds.add( new TypedValue( idType, currentId, session.getEntityMode() ) );
+			}
+		}
+
+		// iterate over the *old* list
+		for ( Iterator it=oldElements.iterator(); it.hasNext(); ) {
+			Object old = it.next();
+			Serializable oldId = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, old, session);
+			if ( !currentIds.contains( new TypedValue( idType, oldId, session.getEntityMode() ) ) ) {
+				res.add(old);
+			}
+		}
+
+		return res;
+	}
+
+	static void identityRemove(
+			Collection list, 
+			Object object, 
+			String entityName, 
+			SessionImplementor session)
+	throws HibernateException {
+
+		if ( object!=null && ForeignKeys.isNotTransient(entityName, object, null, session) ) {
+			
+			Type idType = session.getFactory().getEntityPersister(entityName).getIdentifierType();
+
+			Serializable idOfCurrent = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, object, session);
+			Iterator iter = list.iterator();
+			while ( iter.hasNext() ) {
+				Serializable idOfOld = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, iter.next(), session);
+				if ( idType.isEqual( idOfCurrent, idOfOld, session.getEntityMode(), session.getFactory() ) ) {
+					iter.remove();
+					break;
+				}
+			}
+
+		}
+	}
+	
+	public Object getIdentifier(Object entry, int i) {
+		throw new UnsupportedOperationException();
+	}
+	
+	public Object getOwner() {
+		return owner;
+	}
+	
+	public void setOwner(Object owner) {
+		this.owner = owner;
+	}
+	
+}
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentArrayHolder.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentArrayHolder.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentArrayHolder.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,229 @@
+//$Id: PersistentArrayHolder.java 10086 2006-07-05 18:17:27Z steve.ebersole at jboss.com $
+package org.hibernate.collection;
+
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.Type;
+
+/**
+ * A persistent wrapper for an array. Lazy initialization
+ * is NOT supported. Use of Hibernate arrays is not really
+ * recommended.
+ *
+ * @author Gavin King
+ */
+public class PersistentArrayHolder extends AbstractPersistentCollection {
+	protected Object array;
+
+	private static final Log log = LogFactory.getLog(PersistentArrayHolder.class);
+
+	//just to help out during the load (ugly, i know)
+	private transient Class elementClass;
+	private transient java.util.List tempList;
+
+	public PersistentArrayHolder(SessionImplementor session, Object array) {
+		super(session);
+		this.array = array;
+		setInitialized();
+	}
+
+	public Serializable getSnapshot(CollectionPersister persister) throws HibernateException {
+		EntityMode entityMode = getSession().getEntityMode();
+		int length = /*(array==null) ? tempList.size() :*/ Array.getLength(array);
+		Serializable result = (Serializable) Array.newInstance( persister.getElementClass(), length );
+		for ( int i=0; i<length; i++ ) {
+			Object elt = /*(array==null) ? tempList.get(i) :*/ Array.get(array, i);
+			try {
+				Array.set( result, i, persister.getElementType().deepCopy(elt, entityMode, persister.getFactory()) );
+			}
+			catch (IllegalArgumentException iae) {
+				log.error("Array element type error", iae);
+				throw new HibernateException( "Array element type error", iae );
+			}
+		}
+		return result;
+	}
+
+	public boolean isSnapshotEmpty(Serializable snapshot) {
+		return Array.getLength( snapshot ) == 0;
+	}
+
+	public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
+		Object[] sn = (Object[]) snapshot;
+		Object[] arr = (Object[]) array;
+		ArrayList result = new ArrayList();
+		for (int i=0; i<sn.length; i++) result.add( sn[i] );
+		for (int i=0; i<sn.length; i++) identityRemove( result, arr[i], entityName, getSession() );
+		return result;
+	}
+
+	public PersistentArrayHolder(SessionImplementor session, CollectionPersister persister) throws HibernateException {
+		super(session);
+		elementClass = persister.getElementClass();
+	}
+
+	public Object getArray() {
+		return array;
+	}
+
+	public boolean isWrapper(Object collection) {
+		return array==collection;
+	}
+
+	public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
+		Type elementType = persister.getElementType();
+		Serializable snapshot = getSnapshot();
+		int xlen = Array.getLength(snapshot);
+		if ( xlen!= Array.getLength(array) ) return false;
+		for ( int i=0; i<xlen; i++) {
+			if ( elementType.isDirty( Array.get(snapshot, i), Array.get(array, i), getSession() ) ) return false;
+		}
+		return true;
+	}
+
+	public Iterator elements() {
+		//if (array==null) return tempList.iterator();
+		int length = Array.getLength(array);
+		java.util.List list = new ArrayList(length);
+		for (int i=0; i<length; i++) {
+			list.add( Array.get(array, i) );
+		}
+		return list.iterator();
+	}
+	public boolean empty() {
+		return false;
+	}
+
+	public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
+	throws HibernateException, SQLException {
+
+		Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
+		int index = ( (Integer) persister.readIndex( rs, descriptor.getSuffixedIndexAliases(), getSession() ) ).intValue();
+		for ( int i = tempList.size(); i<=index; i++) {
+			tempList.add(i, null);
+		}
+		tempList.set(index, element);
+		return element;
+	}
+
+	public Iterator entries(CollectionPersister persister) {
+		return elements();
+	}
+
+	public void beginRead() {
+		super.beginRead();
+		tempList = new ArrayList();
+	}
+	public boolean endRead() {
+		setInitialized();
+		array = Array.newInstance( elementClass, tempList.size() );
+		for ( int i=0; i<tempList.size(); i++) {
+			Array.set(array, i, tempList.get(i) );
+		}
+		tempList=null;
+		return true;
+	}
+
+	public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
+		//if (tempList==null) throw new UnsupportedOperationException("Can't lazily initialize arrays");
+	}
+
+	public boolean isDirectlyAccessible() {
+		return true;
+	}
+
+	public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
+	throws HibernateException {
+		Serializable[] cached = (Serializable[]) disassembled;
+
+		array = Array.newInstance( persister.getElementClass(), cached.length );
+
+		for ( int i=0; i<cached.length; i++ ) {
+			Array.set( array, i, persister.getElementType().assemble( cached[i], getSession(), owner ) );
+		}
+	}
+
+	public Serializable disassemble(CollectionPersister persister) throws HibernateException {
+		int length = Array.getLength(array);
+		Serializable[] result = new Serializable[length];
+		for ( int i=0; i<length; i++ ) {
+			result[i] = persister.getElementType().disassemble( Array.get(array,i), getSession(), null );
+		}
+
+		/*int length = tempList.size();
+		Serializable[] result = new Serializable[length];
+		for ( int i=0; i<length; i++ ) {
+			result[i] = persister.getElementType().disassemble( tempList.get(i), session );
+		}*/
+
+		return result;
+
+	}
+
+	public Object getValue() {
+		return array;
+	}
+
+	public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
+		java.util.List deletes = new ArrayList();
+		Serializable sn = getSnapshot();
+		int snSize = Array.getLength(sn);
+		int arraySize = Array.getLength(array);
+		int end;
+		if ( snSize > arraySize ) {
+			for ( int i=arraySize; i<snSize; i++ ) deletes.add( new Integer(i) );
+			end = arraySize;
+		}
+		else {
+			end = snSize;
+		}
+		for ( int i=0; i<end; i++ ) {
+			if ( Array.get(array, i)==null && Array.get(sn, i)!=null ) deletes.add( new Integer(i) );
+		}
+		return deletes.iterator();
+	}
+
+	public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
+		Serializable sn = getSnapshot();
+		return Array.get(array, i)!=null && ( i >= Array.getLength(sn) || Array.get(sn, i)==null );
+	}
+
+	public boolean needsUpdating(Object entry, int i, Type elemType) throws HibernateException {
+		Serializable sn = getSnapshot();
+		return i<Array.getLength(sn) &&
+				Array.get(sn, i)!=null &&
+				Array.get(array, i)!=null &&
+				elemType.isDirty( Array.get(array, i), Array.get(sn, i), getSession() );
+	}
+
+	public Object getIndex(Object entry, int i, CollectionPersister persister) {
+		return new Integer(i);
+	}
+
+	public Object getElement(Object entry) {
+		return entry;
+	}
+
+	public Object getSnapshotElement(Object entry, int i) {
+		Serializable sn = getSnapshot();
+		return Array.get(sn, i);
+	}
+
+	public boolean entryExists(Object entry, int i) {
+		return entry!=null;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentBag.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentBag.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentBag.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,548 @@
+//$Id: PersistentBag.java 10738 2006-11-06 21:56:38Z steve.ebersole at jboss.com $
+package org.hibernate.collection;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.Type;
+
+/**
+ * An unordered, unkeyed collection that can contain the same element
+ * multiple times. The Java collections API, curiously, has no <tt>Bag</tt>.
+ * Most developers seem to use <tt>List</tt>s to represent bag semantics,
+ * so Hibernate follows this practice.
+ *
+ * @author Gavin King
+ */
+public class PersistentBag extends AbstractPersistentCollection implements List {
+
+	protected List bag;
+
+	public PersistentBag(SessionImplementor session) {
+		super(session);
+	}
+
+	public PersistentBag(SessionImplementor session, Collection coll) {
+		super(session);
+		if (coll instanceof List) {
+			bag = (List) coll;
+		}
+		else {
+			bag = new ArrayList();
+			Iterator iter = coll.iterator();
+			while ( iter.hasNext() ) {
+				bag.add( iter.next() );
+			}
+		}
+		setInitialized();
+		setDirectlyAccessible(true);
+	}
+
+	public PersistentBag() {} //needed for SOAP libraries, etc
+
+	public boolean isWrapper(Object collection) {
+		return bag==collection;
+	}
+	public boolean empty() {
+		return bag.isEmpty();
+	}
+
+	public Iterator entries(CollectionPersister persister) {
+		return bag.iterator();
+	}
+
+	public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
+	throws HibernateException, SQLException {
+		// note that if we load this collection from a cartesian product
+		// the multiplicity would be broken ... so use an idbag instead
+		Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() ) ;
+		if (element!=null) bag.add(element);
+		return element;
+	}
+
+	public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
+		this.bag = ( List ) persister.getCollectionType().instantiate( anticipatedSize );
+	}
+
+	public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
+		Type elementType = persister.getElementType();
+		EntityMode entityMode = getSession().getEntityMode();
+		List sn = (List) getSnapshot();
+		if ( sn.size()!=bag.size() ) return false;
+		Iterator iter = bag.iterator();
+		while ( iter.hasNext() ) {
+			Object elt = iter.next();
+			final boolean unequal = countOccurrences(elt, bag, elementType, entityMode) !=
+				countOccurrences(elt, sn, elementType, entityMode);
+			if ( unequal ) return false;
+		}
+		return true;
+	}
+
+	public boolean isSnapshotEmpty(Serializable snapshot) {
+		return ( (Collection) snapshot ).isEmpty();
+	}
+
+	private int countOccurrences(Object element, List list, Type elementType, EntityMode entityMode)
+	throws HibernateException {
+		Iterator iter = list.iterator();
+		int result=0;
+		while ( iter.hasNext() ) {
+			if ( elementType.isSame( element, iter.next(), entityMode ) ) result++;
+		}
+		return result;
+	}
+
+	public Serializable getSnapshot(CollectionPersister persister)
+	throws HibernateException {
+		EntityMode entityMode = getSession().getEntityMode();
+		ArrayList clonedList = new ArrayList( bag.size() );
+		Iterator iter = bag.iterator();
+		while ( iter.hasNext() ) {
+			clonedList.add( persister.getElementType().deepCopy( iter.next(), entityMode, persister.getFactory() ) );
+		}
+		return clonedList;
+	}
+
+	public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
+	    List sn = (List) snapshot;
+	    return getOrphans( sn, bag, entityName, getSession() );
+	}
+
+
+	public Serializable disassemble(CollectionPersister persister)
+	throws HibernateException {
+
+		int length = bag.size();
+		Serializable[] result = new Serializable[length];
+		for ( int i=0; i<length; i++ ) {
+			result[i] = persister.getElementType().disassemble( bag.get(i), getSession(), null );
+		}
+		return result;
+	}
+
+	public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
+	throws HibernateException {
+		Serializable[] array = (Serializable[]) disassembled;
+		int size = array.length;
+		beforeInitialize( persister, size );
+		for ( int i = 0; i < size; i++ ) {
+			Object element = persister.getElementType().assemble( array[i], getSession(), owner );
+			if ( element!=null ) {
+				bag.add( element );
+			}
+		}
+	}
+
+	public boolean needsRecreate(CollectionPersister persister) {
+		return !persister.isOneToMany();
+	}
+
+
+	// For a one-to-many, a <bag> is not really a bag;
+	// it is *really* a set, since it can't contain the
+	// same element twice. It could be considered a bug
+	// in the mapping dtd that <bag> allows <one-to-many>.
+
+	// Anyway, here we implement <set> semantics for a
+	// <one-to-many> <bag>!
+
+	public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
+		//if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
+		Type elementType = persister.getElementType();
+		EntityMode entityMode = getSession().getEntityMode();
+		ArrayList deletes = new ArrayList();
+		List sn = (List) getSnapshot();
+		Iterator olditer = sn.iterator();
+		int i=0;
+		while ( olditer.hasNext() ) {
+			Object old = olditer.next();
+			Iterator newiter = bag.iterator();
+			boolean found = false;
+			if ( bag.size()>i && elementType.isSame( old, bag.get(i++), entityMode ) ) {
+			//a shortcut if its location didn't change!
+				found = true;
+			}
+			else {
+				//search for it
+				//note that this code is incorrect for other than one-to-many
+				while ( newiter.hasNext() ) {
+					if ( elementType.isSame( old, newiter.next(), entityMode ) ) {
+						found = true;
+						break;
+					}
+				}
+			}
+			if (!found) deletes.add(old);
+		}
+		return deletes.iterator();
+	}
+
+	public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
+		//if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
+		List sn = (List) getSnapshot();
+		final EntityMode entityMode = getSession().getEntityMode();
+		if ( sn.size()>i && elemType.isSame( sn.get(i), entry, entityMode ) ) {
+		//a shortcut if its location didn't change!
+			return false;
+		}
+		else {
+			//search for it
+			//note that this code is incorrect for other than one-to-many
+			Iterator olditer = sn.iterator();
+			while ( olditer.hasNext() ) {
+				Object old = olditer.next();
+				if ( elemType.isSame( old, entry, entityMode ) ) return false;
+			}
+			return true;
+		}
+	}
+
+	public boolean isRowUpdatePossible() {
+		return false;
+	}
+
+	public boolean needsUpdating(Object entry, int i, Type elemType) {
+		//if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
+		return false;
+	}
+
+	/**
+	 * @see java.util.Collection#size()
+	 */
+	public int size() {
+		return readSize() ? getCachedSize() : bag.size();
+	}
+
+	/**
+	 * @see java.util.Collection#isEmpty()
+	 */
+	public boolean isEmpty() {
+		return readSize() ? getCachedSize()==0 : bag.isEmpty();
+	}
+
+	/**
+	 * @see java.util.Collection#contains(Object)
+	 */
+	public boolean contains(Object object) {
+		Boolean exists = readElementExistence(object);
+		return exists==null ?
+				bag.contains(object) :
+				exists.booleanValue();
+	}
+
+	/**
+	 * @see java.util.Collection#iterator()
+	 */
+	public Iterator iterator() {
+		read();
+		return new IteratorProxy( bag.iterator() );
+	}
+
+	/**
+	 * @see java.util.Collection#toArray()
+	 */
+	public Object[] toArray() {
+		read();
+		return bag.toArray();
+	}
+
+	/**
+	 * @see java.util.Collection#toArray(Object[])
+	 */
+	public Object[] toArray(Object[] a) {
+		read();
+		return bag.toArray(a);
+	}
+
+	/**
+	 * @see java.util.Collection#add(Object)
+	 */
+	public boolean add(Object object) {
+		if ( !isOperationQueueEnabled() ) {
+			write();
+			return bag.add(object);
+		}
+		else {
+			queueOperation( new SimpleAdd(object) );
+			return true;
+		}
+	}
+
+	/**
+	 * @see java.util.Collection#remove(Object)
+	 */
+	public boolean remove(Object o) {
+		initialize( true );
+		if ( bag.remove( o ) ) {
+			dirty();
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * @see java.util.Collection#containsAll(Collection)
+	 */
+	public boolean containsAll(Collection c) {
+		read();
+		return bag.containsAll(c);
+	}
+
+	/**
+	 * @see java.util.Collection#addAll(Collection)
+	 */
+	public boolean addAll(Collection values) {
+		if ( values.size()==0 ) return false;
+		if ( !isOperationQueueEnabled() ) {
+			write();
+			return bag.addAll(values);
+		}
+		else {
+			Iterator iter = values.iterator();
+			while ( iter.hasNext() ) {
+				queueOperation( new SimpleAdd( iter.next() ) );
+			}
+			return values.size()>0;
+		}
+	}
+
+	/**
+	 * @see java.util.Collection#removeAll(Collection)
+	 */
+	public boolean removeAll(Collection c) {
+		if ( c.size()>0 ) {
+			initialize( true );
+			if ( bag.removeAll( c ) ) {
+				dirty();
+				return true;
+			}
+			else {
+				return false;
+			}
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * @see java.util.Collection#retainAll(Collection)
+	 */
+	public boolean retainAll(Collection c) {
+		initialize( true );
+		if ( bag.retainAll( c ) ) {
+			dirty();
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * @see java.util.Collection#clear()
+	 */
+	public void clear() {
+		if ( isClearQueueEnabled() ) {
+			queueOperation( new Clear() );
+		}
+		else {
+			initialize( true );
+			if ( ! bag.isEmpty() ) {
+				bag.clear();
+				dirty();
+			}
+		}
+	}
+
+	public Object getIndex(Object entry, int i, CollectionPersister persister) {
+		throw new UnsupportedOperationException("Bags don't have indexes");
+	}
+
+	public Object getElement(Object entry) {
+		return entry;
+	}
+
+	public Object getSnapshotElement(Object entry, int i) {
+		List sn = (List) getSnapshot();
+		return sn.get(i);
+	}
+
+	public int occurrences(Object o) {
+		read();
+		Iterator iter = bag.iterator();
+		int result=0;
+		while ( iter.hasNext() ) {
+			if ( o.equals( iter.next() ) ) result++;
+		}
+		return result;
+	}
+
+	// List OPERATIONS:
+
+	/**
+	 * @see java.util.List#add(int, Object)
+	 */
+	public void add(int i, Object o) {
+		write();
+		bag.add(i, o);
+	}
+
+	/**
+	 * @see java.util.List#addAll(int, Collection)
+	 */
+	public boolean addAll(int i, Collection c) {
+		if ( c.size()>0 ) {
+			write();
+			return bag.addAll(i, c);
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * @see java.util.List#get(int)
+	 */
+	public Object get(int i) {
+		read();
+		return bag.get(i);
+	}
+
+	/**
+	 * @see java.util.List#indexOf(Object)
+	 */
+	public int indexOf(Object o) {
+		read();
+		return bag.indexOf(o);
+	}
+
+	/**
+	 * @see java.util.List#lastIndexOf(Object)
+	 */
+	public int lastIndexOf(Object o) {
+		read();
+		return bag.lastIndexOf(o);
+	}
+
+	/**
+	 * @see java.util.List#listIterator()
+	 */
+	public ListIterator listIterator() {
+		read();
+		return new ListIteratorProxy( bag.listIterator() );
+	}
+
+	/**
+	 * @see java.util.List#listIterator(int)
+	 */
+	public ListIterator listIterator(int i) {
+		read();
+		return new ListIteratorProxy( bag.listIterator(i) );
+	}
+
+	/**
+	 * @see java.util.List#remove(int)
+	 */
+	public Object remove(int i) {
+		write();
+		return bag.remove(i);
+	}
+
+	/**
+	 * @see java.util.List#set(int, Object)
+	 */
+	public Object set(int i, Object o) {
+		write();
+		return bag.set(i, o);
+	}
+
+	/**
+	 * @see java.util.List#subList(int, int)
+	 */
+	public List subList(int start, int end) {
+		read();
+		return new ListProxy( bag.subList(start, end) );
+	}
+
+	public String toString() {
+		read();
+		return bag.toString();
+	}
+
+	/*public boolean equals(Object other) {
+		read();
+		return bag.equals(other);
+	}
+
+	public int hashCode(Object other) {
+		read();
+		return bag.hashCode();
+	}*/
+
+	public boolean entryExists(Object entry, int i) {
+		return entry!=null;
+	}
+
+	/**
+	 * Bag does not respect the collection API and do an
+	 * JVM instance comparison to do the equals.
+	 * The semantic is broken not to have to initialize a
+	 * collection for a simple equals() operation.
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	public boolean equals(Object obj) {
+		return super.equals(obj);
+	}
+
+	/**
+	 * @see java.lang.Object#hashCode()
+	 */
+	public int hashCode() {
+		return super.hashCode();
+	}
+
+	final class Clear implements DelayedOperation {
+		public void operate() {
+			bag.clear();
+		}
+		public Object getAddedInstance() {
+			return null;
+		}
+		public Object getOrphan() {
+			throw new UnsupportedOperationException("queued clear cannot be used with orphan delete");
+		}
+	}
+
+	final class SimpleAdd implements DelayedOperation {
+		private Object value;
+
+		public SimpleAdd(Object value) {
+			this.value = value;
+		}
+		public void operate() {
+			bag.add(value);
+		}
+		public Object getAddedInstance() {
+			return value;
+		}
+		public Object getOrphan() {
+			return null;
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentCollection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentCollection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentCollection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,303 @@
+//$Id: PersistentCollection.java 10086 2006-07-05 18:17:27Z steve.ebersole at jboss.com $
+package org.hibernate.collection;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.Type;
+
+/**
+ * Persistent collections are treated as value objects by Hibernate.
+ * ie. they have no independent existence beyond the object holding
+ * a reference to them. Unlike instances of entity classes, they are
+ * automatically deleted when unreferenced and automatically become
+ * persistent when held by a persistent object. Collections can be
+ * passed between different objects (change "roles") and this might
+ * cause their elements to move from one database table to another.<br>
+ * <br>
+ * Hibernate "wraps" a java collection in an instance of
+ * PersistentCollection. This mechanism is designed to support
+ * tracking of changes to the collection's persistent state and
+ * lazy instantiation of collection elements. The downside is that
+ * only certain abstract collection types are supported and any
+ * extra semantics are lost<br>
+ * <br>
+ * Applications should <em>never</em> use classes in this package
+ * directly, unless extending the "framework" here.<br>
+ * <br>
+ * Changes to <em>structure</em> of the collection are recorded by the
+ * collection calling back to the session. Changes to mutable
+ * elements (ie. composite elements) are discovered by cloning their
+ * state when the collection is initialized and comparing at flush
+ * time.
+ *
+ * @author Gavin King
+ */
+public interface PersistentCollection {
+	
+	/**
+	 * Get the owning entity. Note that the owner is only
+	 * set during the flush cycle, and when a new collection
+	 * wrapper is created while loading an entity.
+	 */
+	public Object getOwner();
+	/**
+	 * Set the reference to the owning entity
+	 */
+	public void setOwner(Object entity);
+	
+	/**
+	 * Is the collection empty? (don't try to initialize the collection)
+	 */
+	public boolean empty();
+
+	/**
+	 * After flushing, re-init snapshot state.
+	 */
+	public void setSnapshot(Serializable key, String role, Serializable snapshot);
+	
+	/**
+	 * After flushing, clear any "queued" additions, since the
+	 * database state is now synchronized with the memory state.
+	 */
+	public void postAction();
+	
+	/**
+	 * return the user-visible collection (or array) instance
+	 */
+	public Object getValue();
+
+	/**
+	 * Called just before reading any rows from the JDBC result set
+	 */
+	public void beginRead();
+
+	/**
+	 * Called after reading all rows from the JDBC result set
+	 */
+	public boolean endRead();
+	
+	/**
+	 * Called after initializing from cache
+	 */
+	public boolean afterInitialize();
+
+	/**
+	 * Could the application possibly have a direct reference to
+	 * the underlying collection implementation?
+	 */
+	public boolean isDirectlyAccessible();
+
+	/**
+	 * Disassociate this collection from the given session.
+	 * @return true if this was currently associated with the given session
+	 */
+	public boolean unsetSession(SessionImplementor currentSession);
+
+	/**
+	 * Associate the collection with the given session.
+	 * @return false if the collection was already associated with the session
+	 * @throws HibernateException if the collection was already associated
+	 * with another open session
+	 */
+	public boolean setCurrentSession(SessionImplementor session)
+			throws HibernateException;
+
+	/**
+	 * Read the state of the collection from a disassembled cached value
+	 */
+	public void initializeFromCache(CollectionPersister persister,
+			Serializable disassembled, Object owner) throws HibernateException;
+
+	/**
+	 * Iterate all collection entries, during update of the database
+	 */
+	public Iterator entries(CollectionPersister persister);
+
+	/**
+	 * Read a row from the JDBC result set
+	 */
+	public Object readFrom(ResultSet rs, CollectionPersister role, CollectionAliases descriptor, Object owner)
+			throws HibernateException, SQLException;
+
+	/**
+	 * Get the index of the given collection entry
+	 */
+	public Object getIdentifier(Object entry, int i);
+	
+	/**
+	 * Get the index of the given collection entry
+	 * @param persister it was more elegant before we added this...
+	 */
+	public Object getIndex(Object entry, int i, CollectionPersister persister);
+	
+	/**
+	 * Get the value of the given collection entry
+	 */
+	public Object getElement(Object entry);
+	
+	/**
+	 * Get the snapshot value of the given collection entry
+	 */
+	public Object getSnapshotElement(Object entry, int i);
+
+	/**
+	 * Called before any elements are read into the collection,
+	 * allowing appropriate initializations to occur.
+	 *
+	 * @param persister The underlying collection persister.
+	 * @param anticipatedSize The anticipated size of the collection after initilization is complete.
+	 */
+	public void beforeInitialize(CollectionPersister persister, int anticipatedSize);
+
+	/**
+	 * Does the current state exactly match the snapshot?
+	 */
+	public boolean equalsSnapshot(CollectionPersister persister) 
+		throws HibernateException;
+
+	/**
+	 * Is the snapshot empty?
+	 */
+	public boolean isSnapshotEmpty(Serializable snapshot);
+	
+	/**
+	 * Disassemble the collection, ready for the cache
+	 */
+	public Serializable disassemble(CollectionPersister persister)
+	throws HibernateException;
+
+	/**
+	 * Do we need to completely recreate this collection when it changes?
+	 */
+	public boolean needsRecreate(CollectionPersister persister);
+
+	/**
+	 * Return a new snapshot of the current state of the collection
+	 */
+	public Serializable getSnapshot(CollectionPersister persister)
+			throws HibernateException;
+
+	/**
+	 * To be called internally by the session, forcing
+	 * immediate initialization.
+	 */
+	public void forceInitialization() throws HibernateException;
+
+	/**
+	 * Does an element exist at this entry in the collection?
+	 */
+	public boolean entryExists(Object entry, int i); //note that i parameter is now unused (delete it?)
+
+	/**
+	 * Do we need to insert this element?
+	 */
+	public boolean needsInserting(Object entry, int i, Type elemType)
+			throws HibernateException;
+
+	/**
+	 * Do we need to update this element?
+	 */
+	public boolean needsUpdating(Object entry, int i, Type elemType)
+			throws HibernateException;
+	
+	public boolean isRowUpdatePossible();
+
+	/**
+	 * Get all the elements that need deleting
+	 */
+	public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) 
+			throws HibernateException;
+
+	/**
+	 * Is this the wrapper for the given underlying collection instance?
+	 */
+	public boolean isWrapper(Object collection);
+
+	/**
+	 * Is this instance initialized?
+	 */
+	public boolean wasInitialized();
+
+	/**
+	 * Does this instance have any "queued" additions?
+	 */
+	public boolean hasQueuedOperations();
+
+	/**
+	 * Iterate the "queued" additions
+	 */
+	public Iterator queuedAdditionIterator();
+	
+	/**
+	 * Get the "queued" orphans
+	 */
+	public Collection getQueuedOrphans(String entityName);
+	
+	/**
+	 * Get the current collection key value
+	 */
+	public Serializable getKey();
+	
+	/**
+	 * Get the current role name
+	 */
+	public String getRole();
+	
+	/**
+	 * Is the collection unreferenced?
+	 */
+	public boolean isUnreferenced();
+	
+	/**
+	 * Is the collection dirty? Note that this is only
+	 * reliable during the flush cycle, after the 
+	 * collection elements are dirty checked against
+	 * the snapshot.
+	 */
+	public boolean isDirty();
+	
+	/**
+	 * Clear the dirty flag, after flushing changes
+	 * to the database.
+	 */
+	public void clearDirty();
+	
+	/**
+	 * Get the snapshot cached by the collection
+	 * instance
+	 */
+	public Serializable getStoredSnapshot();
+	
+	/**
+	 * Mark the collection as dirty
+	 */
+	public void dirty();
+	
+	/**
+	 * Called before inserting rows, to ensure that any surrogate keys
+	 * are fully generated
+	 */
+	public void preInsert(CollectionPersister persister)
+	throws HibernateException;
+
+	/**
+	 * Called after inserting a row, to fetch the natively generated id
+	 */
+	public void afterRowInsert(CollectionPersister persister, Object entry, int i) 
+	throws HibernateException;
+
+	/**
+	 * get all "orphaned" elements
+	 */
+	public Collection getOrphans(Serializable snapshot, String entityName)
+	throws HibernateException;
+	
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentElementHolder.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentElementHolder.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentElementHolder.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,209 @@
+//$Id: PersistentElementHolder.java 10086 2006-07-05 18:17:27Z steve.ebersole at jboss.com $
+package org.hibernate.collection;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.dom4j.Element;
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.Type;
+import org.hibernate.util.CollectionHelper;
+
+/**
+ * A persistent wrapper for an XML element
+ *
+ * @author Gavin King
+ */
+public class PersistentElementHolder extends AbstractPersistentCollection {
+	protected Element element;
+	
+	public PersistentElementHolder(SessionImplementor session, Element element) {
+		super(session);
+		this.element = element;
+		setInitialized();
+	}
+
+	public Serializable getSnapshot(CollectionPersister persister) 
+	throws HibernateException {
+		
+		final Type elementType = persister.getElementType();		
+		List elements = element.elements( persister.getElementNodeName() );
+		ArrayList snapshot = new ArrayList( elements.size() );
+		for ( int i=0; i<elements.size(); i++ ) {
+			Element elem = (Element) elements.get(i);
+			Object value = elementType.fromXMLNode( elem, persister.getFactory() );
+			Object copy = elementType.deepCopy(value , getSession().getEntityMode(), persister.getFactory() );
+			snapshot.add(copy);
+		}
+		return snapshot;
+		
+	}
+
+	public Collection getOrphans(Serializable snapshot, String entityName) 
+	throws HibernateException {
+		//orphan delete not supported for EntityMode.DOM4J
+		return CollectionHelper.EMPTY_COLLECTION; 
+	}
+
+	public PersistentElementHolder(SessionImplementor session, CollectionPersister persister, Serializable key) 
+	throws HibernateException {
+		super(session);
+		Element owner = (Element) session.getPersistenceContext().getCollectionOwner(key, persister);
+		if (owner==null) throw new AssertionFailure("null owner");
+		//element = XMLHelper.generateDom4jElement( persister.getNodeName() );
+		final String nodeName = persister.getNodeName();
+		if ( ".".equals(nodeName) ) {
+			element = owner;
+		}
+		else {
+			element = owner.element( nodeName );
+			if (element==null) element = owner.addElement( nodeName );
+		}
+	}
+
+	public boolean isWrapper(Object collection) {
+		return element==collection;
+	}
+
+	public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
+		Type elementType = persister.getElementType();
+		
+		ArrayList snapshot = (ArrayList) getSnapshot();
+		List elements = element.elements( persister.getElementNodeName() );
+		if ( snapshot.size()!= elements.size() ) return false;
+		for ( int i=0; i<snapshot.size(); i++ ) {
+			Object old = snapshot.get(i);
+			Element elem = (Element) elements.get(i);
+			Object current = elementType.fromXMLNode( elem, persister.getFactory() );
+			if ( elementType.isDirty( old, current, getSession() ) ) return false;
+		}
+		return true;
+	}
+
+	public boolean isSnapshotEmpty(Serializable snapshot) {
+		return ( (Collection) snapshot ).isEmpty();
+	}
+	
+	public boolean empty() {
+		return !element.elementIterator().hasNext();
+	}
+
+	public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
+	throws HibernateException, SQLException {
+		Object object = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
+		final Type elementType = persister.getElementType();
+		Element subelement = element.addElement( persister.getElementNodeName() );
+		elementType.setToXMLNode( subelement, object, persister.getFactory() ); 
+		return object;
+	}
+
+	public Iterator entries(CollectionPersister persister) {
+		
+		final Type elementType = persister.getElementType();
+		List elements =  element.elements( persister.getElementNodeName() );
+		int length = elements.size();
+		List result = new ArrayList(length);
+		for ( int i=0; i<length; i++ ) {
+			Element elem = (Element) elements.get(i);
+			Object object = elementType.fromXMLNode( elem, persister.getFactory() );
+			result.add(object);
+		}
+		return result.iterator();
+	}
+
+	public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {}
+
+	public boolean isDirectlyAccessible() {
+		return true;
+	}
+
+	public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
+	throws HibernateException {
+		
+		Type elementType = persister.getElementType();
+		Serializable[] cached = (Serializable[]) disassembled;
+		for ( int i=0; i<cached.length; i++ ) {
+			Object object = elementType.assemble( cached[i], getSession(), owner );
+			Element subelement = element.addElement( persister.getElementNodeName() );
+			elementType.setToXMLNode( subelement, object, persister.getFactory() );
+		}
+		
+	}
+
+	public Serializable disassemble(CollectionPersister persister) throws HibernateException {
+		
+		Type elementType = persister.getElementType();
+		List elements =  element.elements( persister.getElementNodeName() );
+		int length = elements.size();
+		Serializable[] result = new Serializable[length];
+		for ( int i=0; i<length; i++ ) {
+			Element elem = (Element) elements.get(i);
+			Object object = elementType.fromXMLNode( elem, persister.getFactory() );
+			result[i] = elementType.disassemble( object, getSession(), null );
+		}
+		return result;
+	}
+
+	public Object getValue() {
+		return element;
+	}
+
+	public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) 
+	throws HibernateException {
+		
+		Type elementType = persister.getElementType();
+		ArrayList snapshot = (ArrayList) getSnapshot();
+		List elements = element.elements( persister.getElementNodeName() );
+		ArrayList result = new ArrayList();
+		for ( int i=0; i<snapshot.size(); i++ ) {
+			Object old = snapshot.get(i);
+			if ( i >= elements.size() ) {
+				result.add(old);
+			}
+			else {
+				Element elem = (Element) elements.get(i);
+				Object object = elementType.fromXMLNode( elem, persister.getFactory() );
+				if ( elementType.isDirty( old, object, getSession() ) ) result.add(old);
+			}
+		}
+		return result.iterator();
+		
+	}
+
+	public boolean needsInserting(Object entry, int i, Type elementType) 
+	throws HibernateException {
+		ArrayList snapshot = (ArrayList) getSnapshot();
+		return i>=snapshot.size() || elementType.isDirty( snapshot.get(i), entry, getSession() );
+	}
+
+	public boolean needsUpdating(Object entry, int i, Type elementType) 
+	throws HibernateException {
+		return false;
+	}
+
+	public Object getIndex(Object entry, int i, CollectionPersister persister) {
+		throw new UnsupportedOperationException();
+	}
+
+	public Object getElement(Object entry) {
+		return entry;
+	}
+
+	public Object getSnapshotElement(Object entry, int i) {
+		throw new UnsupportedOperationException();
+	}
+
+	public boolean entryExists(Object entry, int i) {
+		return entry!=null;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentElementHolder.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentIdentifierBag.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentIdentifierBag.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentIdentifierBag.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,412 @@
+//$Id: PersistentIdentifierBag.java 10738 2006-11-06 21:56:38Z steve.ebersole at jboss.com $
+package org.hibernate.collection;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.Type;
+
+/**
+ * An <tt>IdentifierBag</tt> implements "bag" semantics more efficiently than
+ * a regular <tt>Bag</tt> by adding a synthetic identifier column to the
+ * table. This identifier is unique for all rows in the table, allowing very
+ * efficient updates and deletes. The value of the identifier is never exposed
+ * to the application.<br>
+ * <br>
+ * <tt>IdentifierBag</tt>s may not be used for a many-to-one association.
+ * Furthermore, there is no reason to use <tt>inverse="true"</tt>.
+ *
+ * @author Gavin King
+ */
+public class PersistentIdentifierBag extends AbstractPersistentCollection implements List {
+
+	protected List values; //element
+	protected Map identifiers; //index -> id
+
+	public PersistentIdentifierBag(SessionImplementor session) {
+		super(session);
+	}
+
+	public PersistentIdentifierBag() {} //needed for SOAP libraries, etc
+
+	public PersistentIdentifierBag(SessionImplementor session, Collection coll) {
+		super(session);
+		if (coll instanceof List) {
+			values = (List) coll;
+		}
+		else {
+			values = new ArrayList();
+			Iterator iter = coll.iterator();
+			while ( iter.hasNext() ) {
+				values.add( iter.next() );
+			}
+		}
+		setInitialized();
+		setDirectlyAccessible(true);
+		identifiers = new HashMap();
+	}
+
+	public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
+	throws HibernateException {
+		Serializable[] array = (Serializable[]) disassembled;
+		int size = array.length;
+		beforeInitialize( persister, size );
+		for ( int i = 0; i < size; i+=2 ) {
+			identifiers.put(
+				new Integer(i/2),
+				persister.getIdentifierType().assemble( array[i], getSession(), owner )
+			);
+			values.add( persister.getElementType().assemble( array[i+1], getSession(), owner ) );
+		}
+	}
+
+	public Object getIdentifier(Object entry, int i) {
+		return identifiers.get( new Integer(i) );
+	}
+
+	public boolean isWrapper(Object collection) {
+		return values==collection;
+	}
+
+	public boolean add(Object o) {
+		write();
+		values.add(o);
+		return true;
+	}
+
+	public void clear() {
+		initialize( true );
+		if ( ! values.isEmpty() || ! identifiers.isEmpty() ) {
+			values.clear();
+			identifiers.clear();
+			dirty();
+		}
+	}
+
+	public boolean contains(Object o) {
+		read();
+		return values.contains(o);
+	}
+
+	public boolean containsAll(Collection c) {
+		read();
+		return values.containsAll(c);
+	}
+
+	public boolean isEmpty() {
+		return readSize() ? getCachedSize()==0 : values.isEmpty();
+	}
+
+	public Iterator iterator() {
+		read();
+		return new IteratorProxy( values.iterator() );
+	}
+
+	public boolean remove(Object o) {
+		initialize( true );
+		int index = values.indexOf(o);
+		if (index>=0) {
+			beforeRemove(index);
+			values.remove(index);
+			dirty();
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	public boolean removeAll(Collection c) {
+		if ( c.size() > 0 ) {
+			boolean result = false;
+			Iterator iter = c.iterator();
+			while ( iter.hasNext() ) {
+				if ( remove( iter.next() ) ) result=true;
+			}
+			return result;
+		}
+		else {
+			return false;
+		}
+	}
+
+	public boolean retainAll(Collection c) {
+		initialize( true );
+		if ( values.retainAll( c ) ) {
+			dirty();
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	public int size() {
+		return readSize() ? getCachedSize() : values.size();
+	}
+
+	public Object[] toArray() {
+		read();
+		return values.toArray();
+	}
+
+	public Object[] toArray(Object[] a) {
+		read();
+		return values.toArray(a);
+	}
+
+	public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
+		identifiers = anticipatedSize <= 0 ? new HashMap() : new HashMap( anticipatedSize + 1 + (int)( anticipatedSize * .75f ), .75f );
+		values = anticipatedSize <= 0 ? new ArrayList() : new ArrayList( anticipatedSize );
+	}
+
+	public Serializable disassemble(CollectionPersister persister)
+			throws HibernateException {
+		Serializable[] result = new Serializable[ values.size() * 2 ];
+		int i=0;
+		for (int j=0; j< values.size(); j++) {
+			Object value = values.get(j);
+			result[i++] = persister.getIdentifierType().disassemble( identifiers.get( new Integer(j) ), getSession(), null );
+			result[i++] = persister.getElementType().disassemble( value, getSession(), null );
+		}
+		return result;
+	}
+
+	public boolean empty() {
+		return values.isEmpty();
+	}
+
+	public Iterator entries(CollectionPersister persister) {
+		return values.iterator();
+	}
+
+	public boolean entryExists(Object entry, int i) {
+		return entry!=null;
+	}
+
+	public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
+		Type elementType = persister.getElementType();
+		Map snap = (Map) getSnapshot();
+		if ( snap.size()!= values.size() ) return false;
+		for ( int i=0; i<values.size(); i++ ) {
+			Object value = values.get(i);
+			Object id = identifiers.get( new Integer(i) );
+			if (id==null) return false;
+			Object old = snap.get(id);
+			if ( elementType.isDirty( old, value, getSession() ) ) return false;
+		}
+		return true;
+	}
+
+	public boolean isSnapshotEmpty(Serializable snapshot) {
+		return ( (Map) snapshot ).isEmpty();
+	}
+
+	public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
+		Map snap = (Map) getSnapshot();
+		List deletes = new ArrayList( snap.keySet() );
+		for ( int i=0; i<values.size(); i++ ) {
+			if ( values.get(i)!=null ) deletes.remove( identifiers.get( new Integer(i) ) );
+		}
+		return deletes.iterator();
+	}
+
+	public Object getIndex(Object entry, int i, CollectionPersister persister) {
+		throw new UnsupportedOperationException("Bags don't have indexes");
+	}
+
+	public Object getElement(Object entry) {
+		return entry;
+	}
+
+	public Object getSnapshotElement(Object entry, int i) {
+		Map snap = (Map) getSnapshot();
+		Object id = identifiers.get( new Integer(i) );
+		return snap.get(id);
+	}
+
+	public boolean needsInserting(Object entry, int i, Type elemType)
+		throws HibernateException {
+
+		Map snap = (Map) getSnapshot();
+		Object id = identifiers.get( new Integer(i) );
+		return entry!=null && ( id==null || snap.get(id)==null );
+	}
+
+	public boolean needsUpdating(Object entry, int i, Type elemType) throws HibernateException {
+
+		if (entry==null) return false;
+		Map snap = (Map) getSnapshot();
+		Object id = identifiers.get( new Integer(i) );
+		if (id==null) return false;
+		Object old = snap.get(id);
+		return old!=null && elemType.isDirty( old, entry, getSession() );
+	}
+
+
+	public Object readFrom(
+		ResultSet rs,
+		CollectionPersister persister,
+		CollectionAliases descriptor,
+		Object owner)
+		throws HibernateException, SQLException {
+
+		Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
+		Object old = identifiers.put(
+			new Integer( values.size() ),
+			persister.readIdentifier( rs, descriptor.getSuffixedIdentifierAlias(), getSession() )
+		);
+		if ( old==null ) values.add(element); //maintain correct duplication if loaded in a cartesian product
+		return element;
+	}
+
+	public Serializable getSnapshot(CollectionPersister persister)
+		throws HibernateException {
+
+		EntityMode entityMode = getSession().getEntityMode();
+
+		HashMap map = new HashMap( values.size() );
+		Iterator iter = values.iterator();
+		int i=0;
+		while ( iter.hasNext() ) {
+			Object value = iter.next();
+			map.put(
+				identifiers.get( new Integer(i++) ),
+				persister.getElementType().deepCopy(value, entityMode, persister.getFactory())
+			);
+		}
+		return map;
+	}
+
+	public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
+		Map sn = (Map) snapshot;
+		return getOrphans( sn.values(), values, entityName, getSession() );
+	}
+
+	public void preInsert(CollectionPersister persister) throws HibernateException {
+		Iterator iter = values.iterator();
+		int i=0;
+		while ( iter.hasNext() ) {
+			Object entry = iter.next();
+			Integer loc = new Integer(i++);
+			if ( !identifiers.containsKey(loc) ) { //TODO: native ids
+				Serializable id = persister.getIdentifierGenerator().generate( getSession(), entry );
+				identifiers.put(loc, id);
+			}
+		}
+	}
+
+	public void add(int index, Object element) {
+		write();
+		beforeAdd(index);
+		values.add(index, element);
+	}
+
+	public boolean addAll(int index, Collection c) {
+		if ( c.size() > 0 ) {
+			Iterator iter = c.iterator();
+			while ( iter.hasNext() ) {
+				add( index++, iter.next() );
+			}
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	public Object get(int index) {
+		read();
+		return values.get(index);
+	}
+
+	public int indexOf(Object o) {
+		read();
+		return values.indexOf(o);
+	}
+
+	public int lastIndexOf(Object o) {
+		read();
+		return values.lastIndexOf(o);
+	}
+
+	public ListIterator listIterator() {
+		read();
+		return new ListIteratorProxy( values.listIterator() );
+	}
+
+	public ListIterator listIterator(int index) {
+		read();
+		return new ListIteratorProxy( values.listIterator(index) );
+	}
+
+	private void beforeRemove(int index) {
+		Object removedId = identifiers.get( new Integer(index) );
+		int last = values.size()-1;
+		for ( int i=index; i<last; i++ ) {
+			Object id = identifiers.get( new Integer(i+1) );
+	        if ( id==null ) {
+				identifiers.remove( new Integer(i) );
+	        }
+	        else {
+				identifiers.put( new Integer(i), id );
+	        }
+		}
+		identifiers.put( new Integer(last), removedId );
+	}
+
+	private void beforeAdd(int index) {
+		for ( int i=index; i<values.size(); i++ ) {
+			identifiers.put( new Integer(i+1), identifiers.get( new Integer(i) ) );
+		}
+		identifiers.remove( new Integer(index) );
+	}
+
+	public Object remove(int index) {
+		write();
+		beforeRemove(index);
+		return values.remove(index);
+	}
+
+	public Object set(int index, Object element) {
+		write();
+		return values.set(index, element);
+	}
+
+	public List subList(int fromIndex, int toIndex) {
+		read();
+		return new ListProxy( values.subList(fromIndex, toIndex) );
+	}
+
+	public boolean addAll(Collection c) {
+		if ( c.size()> 0 ) {
+			write();
+			return values.addAll(c);
+		}
+		else {
+			return false;
+		}
+	}
+
+	public void afterRowInsert(
+		CollectionPersister persister,
+		Object entry,
+		int i)
+		throws HibernateException {
+		//TODO: if we are using identity columns, fetch the identifier
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentIndexedElementHolder.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentIndexedElementHolder.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentIndexedElementHolder.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,228 @@
+//$Id: PersistentIndexedElementHolder.java 10086 2006-07-05 18:17:27Z steve.ebersole at jboss.com $
+package org.hibernate.collection;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.dom4j.Element;
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.NullableType;
+import org.hibernate.type.Type;
+import org.hibernate.util.CollectionHelper;
+
+/**
+ * A persistent wrapper for an XML element
+ *
+ * @author Gavin King
+ */
+public abstract class PersistentIndexedElementHolder extends AbstractPersistentCollection {
+	protected Element element;
+	
+	public PersistentIndexedElementHolder(SessionImplementor session, Element element) {
+		super(session);
+		this.element = element;
+		setInitialized();
+	}
+	
+	public static final class IndexedValue {
+		String index;
+		Object value;
+		IndexedValue(String index, Object value) {
+			this.index = index;
+			this.value = value;
+		}
+	}
+	
+	protected static String getIndex(Element element, String indexNodeName, int i) {
+		if (indexNodeName!=null) {
+			return element.attributeValue(indexNodeName);
+		}
+		else {
+			return Integer.toString(i);
+		}
+	}
+	
+	protected static void setIndex(Element element, String indexNodeName, String index) {
+		if (indexNodeName!=null) element.addAttribute(indexNodeName, index);
+	}
+	
+	protected static String getIndexAttributeName(CollectionPersister persister) {
+		String node = persister.getIndexNodeName();
+		return node==null ? null : node.substring(1);
+	}
+	
+	public Serializable getSnapshot(CollectionPersister persister) 
+	throws HibernateException {
+		
+		final Type elementType = persister.getElementType();
+		String indexNode = getIndexAttributeName(persister);		
+		List elements = element.elements( persister.getElementNodeName() );
+		HashMap snapshot = new HashMap( elements.size() );
+		for ( int i=0; i<elements.size(); i++ ) {
+			Element elem = (Element) elements.get(i);
+			Object value = elementType.fromXMLNode( elem, persister.getFactory() );
+			Object copy = elementType.deepCopy( value, getSession().getEntityMode(), persister.getFactory() );
+			snapshot.put( getIndex(elem, indexNode, i), copy );
+		}
+		return snapshot;
+		
+	}
+
+	public Collection getOrphans(Serializable snapshot, String entityName) 
+	throws HibernateException {
+		//orphan delete not supported for EntityMode.DOM4J
+		return CollectionHelper.EMPTY_COLLECTION; 
+	}
+
+	public PersistentIndexedElementHolder(SessionImplementor session, CollectionPersister persister, Serializable key) 
+	throws HibernateException {
+		super(session);
+		Element owner = (Element) session.getPersistenceContext().getCollectionOwner(key, persister);
+		if (owner==null) throw new AssertionFailure("null owner");
+		//element = XMLHelper.generateDom4jElement( persister.getNodeName() );
+		final String nodeName = persister.getNodeName();
+		if ( ".".equals(nodeName) ) {
+			element = owner;
+		}
+		else {
+			element = owner.element( nodeName );
+			if (element==null) element = owner.addElement( nodeName );
+		}
+	}
+
+	public boolean isWrapper(Object collection) {
+		return element==collection;
+	}
+
+	public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
+		Type elementType = persister.getElementType();
+		String indexNode = getIndexAttributeName(persister);		
+		HashMap snapshot = (HashMap) getSnapshot();
+		List elements = element.elements( persister.getElementNodeName() );
+		if ( snapshot.size()!= elements.size() ) return false;
+		for ( int i=0; i<snapshot.size(); i++ ) {
+			Element elem = (Element) elements.get(i);
+			Object old = snapshot.get( getIndex(elem, indexNode, i) );
+			Object current = elementType.fromXMLNode( elem, persister.getFactory() );
+			if ( elementType.isDirty( old, current, getSession() ) ) return false;
+		}
+		return true;
+	}
+
+	public boolean isSnapshotEmpty(Serializable snapshot) {
+		return ( (HashMap) snapshot ).isEmpty();
+	}
+	
+	public boolean empty() {
+		return !element.elementIterator().hasNext();
+	}
+
+	public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
+	throws HibernateException, SQLException {
+		Object object = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
+		final Type elementType = persister.getElementType();
+		final SessionFactoryImplementor factory = persister.getFactory();
+		String indexNode = getIndexAttributeName(persister);
+
+		Element elem = element.addElement( persister.getElementNodeName() );
+		elementType.setToXMLNode( elem, object, factory ); 
+		
+		final Type indexType = persister.getIndexType();
+		final Object indexValue = persister.readIndex( rs, descriptor.getSuffixedIndexAliases(), getSession() );
+		final String index = ( (NullableType) indexType ).toXMLString( indexValue, factory );
+		setIndex(elem, indexNode, index);
+		return object;
+	}
+
+	public Iterator entries(CollectionPersister persister) {
+		
+		final Type elementType = persister.getElementType();
+		String indexNode = getIndexAttributeName(persister);
+		List elements =  element.elements( persister.getElementNodeName() );
+		int length = elements.size();
+		List result = new ArrayList(length);
+		for ( int i=0; i<length; i++ ) {
+			Element elem = (Element) elements.get(i);
+			Object object = elementType.fromXMLNode( elem, persister.getFactory() );
+			result.add( new IndexedValue( getIndex(elem, indexNode, i), object ) );
+		}
+		return result.iterator();
+	}
+
+	public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {}
+
+	public boolean isDirectlyAccessible() {
+		return true;
+	}
+
+	public Object getValue() {
+		return element;
+	}
+
+	public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) 
+	throws HibernateException {
+		
+		final Type indexType = persister.getIndexType();
+		HashMap snapshot = (HashMap) getSnapshot();
+		HashMap deletes = (HashMap) snapshot.clone();
+		deletes.keySet().removeAll( ( (HashMap) getSnapshot(persister) ).keySet() );
+		ArrayList deleteList = new ArrayList( deletes.size() );
+		Iterator iter = deletes.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			final Object object = indexIsFormula ?
+				me.getValue() :
+				( (NullableType) indexType ).fromXMLString( (String) me.getKey(), persister.getFactory() );
+			if (object!=null) deleteList.add(object);
+		}
+		
+		return deleteList.iterator();
+		
+	}
+
+	public boolean needsInserting(Object entry, int i, Type elementType) 
+	throws HibernateException {
+		HashMap snapshot = (HashMap) getSnapshot();
+		IndexedValue iv = (IndexedValue) entry;
+		return iv.value!=null && snapshot.get( iv.index )==null;
+	}
+
+	public boolean needsUpdating(Object entry, int i, Type elementType) 
+	throws HibernateException {
+		HashMap snapshot = (HashMap) getSnapshot();
+		IndexedValue iv = (IndexedValue) entry;
+		Object old = snapshot.get( iv.index );
+		return old!=null && elementType.isDirty( old, iv.value, getSession() );
+	}
+
+	public Object getIndex(Object entry, int i, CollectionPersister persister) {
+		String index = ( (IndexedValue) entry ).index;
+		final Type indexType = persister.getIndexType();
+		return ( (NullableType) indexType ).fromXMLString( index, persister.getFactory() );
+	}
+
+	public Object getElement(Object entry) {
+		return ( (IndexedValue) entry ).value;
+	}
+
+	public Object getSnapshotElement(Object entry, int i) {
+		return ( (HashMap) getSnapshot() ).get( ( (IndexedValue) entry ).index );
+	}
+
+	public boolean entryExists(Object entry, int i) {
+		return entry!=null;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentIndexedElementHolder.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentList.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentList.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentList.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,579 @@
+//$Id: PersistentList.java 10738 2006-11-06 21:56:38Z steve.ebersole at jboss.com $
+package org.hibernate.collection;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.Type;
+
+/**
+ * A persistent wrapper for a <tt>java.util.List</tt>. Underlying
+ * collection is an <tt>ArrayList</tt>.
+ *
+ * @see java.util.ArrayList
+ * @author Gavin King
+ */
+public class PersistentList extends AbstractPersistentCollection implements List {
+
+	protected List list;
+
+	public Serializable getSnapshot(CollectionPersister persister) throws HibernateException {
+
+		EntityMode entityMode = getSession().getEntityMode();
+
+		ArrayList clonedList = new ArrayList( list.size() );
+		Iterator iter = list.iterator();
+		while ( iter.hasNext() ) {
+			Object deepCopy = persister.getElementType()
+					.deepCopy( iter.next(), entityMode, persister.getFactory() );
+			clonedList.add( deepCopy );
+		}
+		return clonedList;
+	}
+
+	public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
+		List sn = (List) snapshot;
+	    return getOrphans( sn, list, entityName, getSession() );
+	}
+
+	public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
+		Type elementType = persister.getElementType();
+		List sn = (List) getSnapshot();
+		if ( sn.size()!=this.list.size() ) return false;
+		Iterator iter = list.iterator();
+		Iterator sniter = sn.iterator();
+		while ( iter.hasNext() ) {
+			if ( elementType.isDirty( iter.next(), sniter.next(), getSession() ) ) return false;
+		}
+		return true;
+	}
+
+	public boolean isSnapshotEmpty(Serializable snapshot) {
+		return ( (Collection) snapshot ).isEmpty();
+	}
+
+	public PersistentList(SessionImplementor session) {
+		super(session);
+	}
+
+	public PersistentList(SessionImplementor session, List list) {
+		super(session);
+		this.list = list;
+		setInitialized();
+		setDirectlyAccessible(true);
+	}
+
+	public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
+		this.list = ( List ) persister.getCollectionType().instantiate( anticipatedSize );
+	}
+
+	public boolean isWrapper(Object collection) {
+		return list==collection;
+	}
+
+	public PersistentList() {} //needed for SOAP libraries, etc
+
+	/**
+	 * @see java.util.List#size()
+	 */
+	public int size() {
+		return readSize() ? getCachedSize() : list.size();
+	}
+
+	/**
+	 * @see java.util.List#isEmpty()
+	 */
+	public boolean isEmpty() {
+		return readSize() ? getCachedSize()==0 : list.isEmpty();
+	}
+
+	/**
+	 * @see java.util.List#contains(Object)
+	 */
+	public boolean contains(Object object) {
+		Boolean exists = readElementExistence(object);
+		return exists==null ?
+				list.contains(object) :
+				exists.booleanValue();
+	}
+
+	/**
+	 * @see java.util.List#iterator()
+	 */
+	public Iterator iterator() {
+		read();
+		return new IteratorProxy( list.iterator() );
+	}
+
+	/**
+	 * @see java.util.List#toArray()
+	 */
+	public Object[] toArray() {
+		read();
+		return list.toArray();
+	}
+
+	/**
+	 * @see java.util.List#toArray(Object[])
+	 */
+	public Object[] toArray(Object[] array) {
+		read();
+		return list.toArray(array);
+	}
+
+	/**
+	 * @see java.util.List#add(Object)
+	 */
+	public boolean add(Object object) {
+		if ( !isOperationQueueEnabled() ) {
+			write();
+			return list.add(object);
+		}
+		else {
+			queueOperation( new SimpleAdd(object) );
+			return true;
+		}
+	}
+
+	/**
+	 * @see java.util.List#remove(Object)
+	 */
+	public boolean remove(Object value) {
+		Boolean exists = isPutQueueEnabled() ? readElementExistence(value) : null;
+		if ( exists == null ) {
+			initialize( true );
+			if ( list.remove( value ) ) {
+				dirty();
+				return true;
+			}
+			else {
+				return false;
+			}
+		}
+		else if ( exists.booleanValue() ) {
+			queueOperation( new SimpleRemove(value) );
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * @see java.util.List#containsAll(Collection)
+	 */
+	public boolean containsAll(Collection coll) {
+		read();
+		return list.containsAll(coll);
+	}
+
+	/**
+	 * @see java.util.List#addAll(Collection)
+	 */
+	public boolean addAll(Collection values) {
+		if ( values.size()==0 ) {
+			return false;
+		}
+		if ( !isOperationQueueEnabled() ) {
+			write();
+			return list.addAll(values);
+		}
+		else {
+			Iterator iter = values.iterator();
+			while ( iter.hasNext() ) {
+				queueOperation( new SimpleAdd( iter.next() ) );
+			}
+			return values.size()>0;
+		}
+	}
+
+	/**
+	 * @see java.util.List#addAll(int, Collection)
+	 */
+	public boolean addAll(int index, Collection coll) {
+		if ( coll.size()>0 ) {
+			write();
+			return list.addAll(index,  coll);
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * @see java.util.List#removeAll(Collection)
+	 */
+	public boolean removeAll(Collection coll) {
+		if ( coll.size()>0 ) {
+			initialize( true );
+			if ( list.removeAll( coll ) ) {
+				dirty();
+				return true;
+			}
+			else {
+				return false;
+			}
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * @see java.util.List#retainAll(Collection)
+	 */
+	public boolean retainAll(Collection coll) {
+		initialize( true );
+		if ( list.retainAll( coll ) ) {
+			dirty();
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * @see java.util.List#clear()
+	 */
+	public void clear() {
+		if ( isClearQueueEnabled() ) {
+			queueOperation( new Clear() );
+		}
+		else {
+			initialize( true );
+			if ( ! list.isEmpty() ) {
+				list.clear();
+				dirty();
+			}
+		}
+	}
+
+	/**
+	 * @see java.util.List#get(int)
+	 */
+	public Object get(int index) {
+		if (index<0) {
+			throw new ArrayIndexOutOfBoundsException("negative index");
+		}
+		Object result = readElementByIndex( new Integer(index) );
+		return result==UNKNOWN ? list.get(index) : result;
+	}
+
+	/**
+	 * @see java.util.List#set(int, Object)
+	 */
+	public Object set(int index, Object value) {
+		if (index<0) {
+			throw new ArrayIndexOutOfBoundsException("negative index");
+		}
+		Object old = isPutQueueEnabled() ? readElementByIndex( new Integer(index) ) : UNKNOWN;
+		if ( old==UNKNOWN ) {
+			write();
+			return list.set(index, value);
+		}
+		else {
+			queueOperation( new Set(index, value, old) );
+			return old;
+		}
+	}
+
+	/**
+	 * @see java.util.List#add(int, Object)
+	 */
+	public void add(int index, Object value) {
+		if (index<0) {
+			throw new ArrayIndexOutOfBoundsException("negative index");
+		}
+		if ( !isOperationQueueEnabled() ) {
+			write();
+			list.add(index, value);
+		}
+		else {
+			queueOperation( new Add(index, value) );
+		}
+	}
+
+	/**
+	 * @see java.util.List#remove(int)
+	 */
+	public Object remove(int index) {
+		if (index<0) {
+			throw new ArrayIndexOutOfBoundsException("negative index");
+		}
+		Object old = isPutQueueEnabled() ?
+				readElementByIndex( new Integer(index) ) : UNKNOWN;
+		if ( old==UNKNOWN ) {
+			write();
+			return list.remove(index);
+		}
+		else {
+			queueOperation( new Remove(index, old) );
+			return old;
+		}
+	}
+
+	/**
+	 * @see java.util.List#indexOf(Object)
+	 */
+	public int indexOf(Object value) {
+		read();
+		return list.indexOf(value);
+	}
+
+	/**
+	 * @see java.util.List#lastIndexOf(Object)
+	 */
+	public int lastIndexOf(Object value) {
+		read();
+		return list.lastIndexOf(value);
+	}
+
+	/**
+	 * @see java.util.List#listIterator()
+	 */
+	public ListIterator listIterator() {
+		read();
+		return new ListIteratorProxy( list.listIterator() );
+	}
+
+	/**
+	 * @see java.util.List#listIterator(int)
+	 */
+	public ListIterator listIterator(int index) {
+		read();
+		return new ListIteratorProxy( list.listIterator(index) );
+	}
+
+	/**
+	 * @see java.util.List#subList(int, int)
+	 */
+	public java.util.List subList(int from, int to) {
+		read();
+		return new ListProxy( list.subList(from, to) );
+	}
+
+	public boolean empty() {
+		return list.isEmpty();
+	}
+
+	public String toString() {
+		read();
+		return list.toString();
+	}
+
+	public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
+	throws HibernateException, SQLException {
+		Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() ) ;
+		int index = ( (Integer) persister.readIndex( rs, descriptor.getSuffixedIndexAliases(), getSession() ) ).intValue();
+
+		//pad with nulls from the current last element up to the new index
+		for ( int i = list.size(); i<=index; i++) {
+			list.add(i, null);
+		}
+
+		list.set(index, element);
+		return element;
+	}
+
+	public Iterator entries(CollectionPersister persister) {
+		return list.iterator();
+	}
+
+	public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
+	throws HibernateException {
+		Serializable[] array = ( Serializable[] ) disassembled;
+		int size = array.length;
+		beforeInitialize( persister, size );
+		for ( int i = 0; i < size; i++ ) {
+			list.add( persister.getElementType().assemble( array[i], getSession(), owner ) );
+		}
+	}
+
+	public Serializable disassemble(CollectionPersister persister)
+	throws HibernateException {
+
+		int length = list.size();
+		Serializable[] result = new Serializable[length];
+		for ( int i=0; i<length; i++ ) {
+			result[i] = persister.getElementType().disassemble( list.get(i), getSession(), null );
+		}
+		return result;
+	}
+
+
+	public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
+		List deletes = new ArrayList();
+		List sn = (List) getSnapshot();
+		int end;
+		if ( sn.size() > list.size() ) {
+			for ( int i=list.size(); i<sn.size(); i++ ) {
+				deletes.add( indexIsFormula ? sn.get(i) : new Integer(i) );
+			}
+			end = list.size();
+		}
+		else {
+			end = sn.size();
+		}
+		for ( int i=0; i<end; i++ ) {
+			if ( list.get(i)==null && sn.get(i)!=null ) {
+				deletes.add( indexIsFormula ? sn.get(i) : new Integer(i) );
+			}
+		}
+		return deletes.iterator();
+	}
+
+	public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
+		final List sn = (List) getSnapshot();
+		return list.get(i)!=null && ( i >= sn.size() || sn.get(i)==null );
+	}
+
+	public boolean needsUpdating(Object entry, int i, Type elemType) throws HibernateException {
+		final List sn = (List) getSnapshot();
+		return i<sn.size() && sn.get(i)!=null && list.get(i)!=null &&
+			elemType.isDirty( list.get(i), sn.get(i), getSession() );
+	}
+
+	public Object getIndex(Object entry, int i, CollectionPersister persister) {
+		return new Integer(i);
+	}
+
+	public Object getElement(Object entry) {
+		return entry;
+	}
+
+	public Object getSnapshotElement(Object entry, int i) {
+		final List sn = (List) getSnapshot();
+		return sn.get(i);
+	}
+
+	public boolean equals(Object other) {
+		read();
+		return list.equals(other);
+	}
+
+	public int hashCode() {
+		read();
+		return list.hashCode();
+	}
+
+	public boolean entryExists(Object entry, int i) {
+		return entry!=null;
+	}
+
+	final class Clear implements DelayedOperation {
+		public void operate() {
+			list.clear();
+		}
+		public Object getAddedInstance() {
+			return null;
+		}
+		public Object getOrphan() {
+			throw new UnsupportedOperationException("queued clear cannot be used with orphan delete");
+		}
+	}
+
+	final class SimpleAdd implements DelayedOperation {
+		private Object value;
+
+		public SimpleAdd(Object value) {
+			this.value = value;
+		}
+		public void operate() {
+			list.add(value);
+		}
+		public Object getAddedInstance() {
+			return value;
+		}
+		public Object getOrphan() {
+			return null;
+		}
+	}
+
+	final class Add implements DelayedOperation {
+		private int index;
+		private Object value;
+
+		public Add(int index, Object value) {
+			this.index = index;
+			this.value = value;
+		}
+		public void operate() {
+			list.add(index, value);
+		}
+		public Object getAddedInstance() {
+			return value;
+		}
+		public Object getOrphan() {
+			return null;
+		}
+	}
+
+	final class Set implements DelayedOperation {
+		private int index;
+		private Object value;
+		private Object old;
+
+		public Set(int index, Object value, Object old) {
+			this.index = index;
+			this.value = value;
+			this.old = old;
+		}
+		public void operate() {
+			list.set(index, value);
+		}
+		public Object getAddedInstance() {
+			return value;
+		}
+		public Object getOrphan() {
+			return old;
+		}
+	}
+
+	final class Remove implements DelayedOperation {
+		private int index;
+		private Object old;
+
+		public Remove(int index, Object old) {
+			this.index = index;
+			this.old = old;
+		}
+		public void operate() {
+			list.remove(index);
+		}
+		public Object getAddedInstance() {
+			return null;
+		}
+		public Object getOrphan() {
+			return old;
+		}
+	}
+
+	final class SimpleRemove implements DelayedOperation {
+		private Object value;
+
+		public SimpleRemove(Object value) {
+			this.value = value;
+		}
+		public void operate() {
+			list.remove(value);
+		}
+		public Object getAddedInstance() {
+			return null;
+		}
+		public Object getOrphan() {
+			return value;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentListElementHolder.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentListElementHolder.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentListElementHolder.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+//$Id: PersistentListElementHolder.java 6838 2005-05-20 19:50:07Z oneovthafew $
+package org.hibernate.collection;
+
+import java.io.Serializable;
+import java.util.List;
+
+import org.dom4j.Element;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.Type;
+
+/**
+ * @author Gavin King
+ */
+public class PersistentListElementHolder extends PersistentIndexedElementHolder {
+
+	public PersistentListElementHolder(SessionImplementor session, Element element) {
+		super( session, element );
+	}
+
+	public PersistentListElementHolder(SessionImplementor session, CollectionPersister persister,
+			Serializable key) throws HibernateException {
+		super( session, persister, key );
+	}
+
+	public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
+	throws HibernateException {
+		
+		Type elementType = persister.getElementType();
+		final String indexNodeName = getIndexAttributeName(persister);
+		Serializable[] cached = (Serializable[]) disassembled;
+		for ( int i=0; i<cached.length; i++ ) {
+			Object object = elementType.assemble( cached[i], getSession(), owner );
+			Element subelement = element.addElement( persister.getElementNodeName() );
+			elementType.setToXMLNode( subelement, object, persister.getFactory() );
+			setIndex( subelement, indexNodeName, Integer.toString(i) );
+		}
+		
+	}
+
+	public Serializable disassemble(CollectionPersister persister) throws HibernateException {
+				
+		Type elementType = persister.getElementType();
+		final String indexNodeName = getIndexAttributeName(persister);
+		List elements =  element.elements( persister.getElementNodeName() );
+		int length = elements.size();
+		Serializable[] result = new Serializable[length];
+		for ( int i=0; i<length; i++ ) {
+			Element elem = (Element) elements.get(i);
+			Object object = elementType.fromXMLNode( elem, persister.getFactory() );
+			Integer index = (Integer) Hibernate.INTEGER.fromStringValue( getIndex(elem, indexNodeName, i) );
+			result[ index.intValue() ] = elementType.disassemble( object, getSession(), null );
+		}
+		return result;
+	}
+
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentListElementHolder.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentMap.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentMap.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentMap.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,491 @@
+//$Id: PersistentMap.java 11255 2007-03-07 19:30:27Z steve.ebersole at jboss.com $
+package org.hibernate.collection;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.Type;
+
+
+/**
+ * A persistent wrapper for a <tt>java.util.Map</tt>. Underlying collection
+ * is a <tt>HashMap</tt>.
+ *
+ * @see java.util.HashMap
+ * @author Gavin King
+ */
+public class PersistentMap extends AbstractPersistentCollection implements Map {
+
+	protected Map map;
+
+	/**
+	 * Empty constructor.
+	 * <p/>
+	 * Note: this form is not ever ever ever used by Hibernate; it is, however,
+	 * needed for SOAP libraries and other such marshalling code.
+	 */
+	public PersistentMap() {
+		// intentionally empty
+	}
+
+	/**
+	 * Instantiates a lazy map (the underlying map is un-initialized).
+	 *
+	 * @param session The session to which this map will belong.
+	 */
+	public PersistentMap(SessionImplementor session) {
+		super(session);
+	}
+
+	/**
+	 * Instantiates a non-lazy map (the underlying map is constructed
+	 * from the incoming map reference).
+	 *
+	 * @param session The session to which this map will belong.
+	 * @param map The underlying map data.
+	 */
+	public PersistentMap(SessionImplementor session, Map map) {
+		super(session);
+		this.map = map;
+		setInitialized();
+		setDirectlyAccessible(true);
+	}
+
+	public Serializable getSnapshot(CollectionPersister persister) throws HibernateException {
+		EntityMode entityMode = getSession().getEntityMode();
+		HashMap clonedMap = new HashMap( map.size() );
+		Iterator iter = map.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry e = (Map.Entry) iter.next();
+			final Object copy = persister.getElementType()
+				.deepCopy( e.getValue(), entityMode, persister.getFactory() );
+			clonedMap.put( e.getKey(), copy );
+		}
+		return clonedMap;
+	}
+
+	public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
+		Map sn = (Map) snapshot;
+		return getOrphans( sn.values(), map.values(), entityName, getSession() );
+	}
+
+	public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
+		Type elementType = persister.getElementType();
+		Map xmap = (Map) getSnapshot();
+		if ( xmap.size()!=this.map.size() ) return false;
+		Iterator iter = map.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry entry = (Map.Entry) iter.next();
+			if ( elementType.isDirty( entry.getValue(), xmap.get( entry.getKey() ), getSession() ) ) return false;
+		}
+		return true;
+	}
+
+	public boolean isSnapshotEmpty(Serializable snapshot) {
+		return ( (Map) snapshot ).isEmpty();
+	}
+
+	public boolean isWrapper(Object collection) {
+		return map==collection;
+	}
+
+	public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
+		this.map = ( Map ) persister.getCollectionType().instantiate( anticipatedSize );
+	}
+
+
+	/**
+	 * @see java.util.Map#size()
+	 */
+	public int size() {
+		return readSize() ? getCachedSize() : map.size();
+	}
+
+	/**
+	 * @see java.util.Map#isEmpty()
+	 */
+	public boolean isEmpty() {
+		return readSize() ? getCachedSize()==0 : map.isEmpty();
+	}
+
+	/**
+	 * @see java.util.Map#containsKey(Object)
+	 */
+	public boolean containsKey(Object key) {
+		Boolean exists = readIndexExistence(key);
+		return exists==null ? map.containsKey(key) : exists.booleanValue();
+	}
+
+	/**
+	 * @see java.util.Map#containsValue(Object)
+	 */
+	public boolean containsValue(Object value) {
+		Boolean exists = readElementExistence(value);
+		return exists==null ? 
+				map.containsValue(value) : 
+				exists.booleanValue();
+	}
+
+	/**
+	 * @see java.util.Map#get(Object)
+	 */
+	public Object get(Object key) {
+		Object result = readElementByIndex(key);
+		return result==UNKNOWN ? map.get(key) : result;
+	}
+
+	/**
+	 * @see java.util.Map#put(Object, Object)
+	 */
+	public Object put(Object key, Object value) {
+		if ( isPutQueueEnabled() ) {
+			Object old = readElementByIndex( key );
+			if ( old != UNKNOWN ) {
+				queueOperation( new Put( key, value, old ) );
+				return old;
+			}
+		}
+		initialize( true );
+		Object old = map.put( key, value );
+		// would be better to use the element-type to determine
+		// whether the old and the new are equal here; the problem being
+		// we do not necessarily have access to the element type in all
+		// cases
+		if ( value != old ) {
+			dirty();
+		}
+		return old;
+	}
+
+	/**
+	 * @see java.util.Map#remove(Object)
+	 */
+	public Object remove(Object key) {
+		if ( isPutQueueEnabled() ) {
+			Object old = readElementByIndex( key );
+			queueOperation( new Remove( key, old ) );
+			return old;
+		}
+		else {
+			// TODO : safe to interpret "map.remove(key) == null" as non-dirty?
+			initialize( true );
+			if ( map.containsKey( key ) ) {
+				dirty();
+			}
+			return map.remove( key );
+		}
+	}
+
+	/**
+	 * @see java.util.Map#putAll(java.util.Map puts)
+	 */
+	public void putAll(Map puts) {
+		if ( puts.size()>0 ) {
+			initialize( true );
+			Iterator itr = puts.entrySet().iterator();
+			while ( itr.hasNext() ) {
+				Map.Entry entry = ( Entry ) itr.next();
+				put( entry.getKey(), entry.getValue() );
+			}
+		}
+	}
+
+	/**
+	 * @see java.util.Map#clear()
+	 */
+	public void clear() {
+		if ( isClearQueueEnabled() ) {
+			queueOperation( new Clear() );
+		}
+		else {
+			initialize( true );
+			if ( ! map.isEmpty() ) {
+				dirty();
+				map.clear();
+			}
+		}
+	}
+
+	/**
+	 * @see java.util.Map#keySet()
+	 */
+	public Set keySet() {
+		read();
+		return new SetProxy( map.keySet() );
+	}
+
+	/**
+	 * @see java.util.Map#values()
+	 */
+	public Collection values() {
+		read();
+		return new SetProxy( map.values() );
+	}
+
+	/**
+	 * @see java.util.Map#entrySet()
+	 */
+	public Set entrySet() {
+		read();
+		return new EntrySetProxy( map.entrySet() );
+	}
+
+	public boolean empty() {
+		return map.isEmpty();
+	}
+
+	public String toString() {
+		read();
+		return map.toString();
+	}
+
+	public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
+	throws HibernateException, SQLException {
+		Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
+		Object index = persister.readIndex( rs, descriptor.getSuffixedIndexAliases(), getSession() );
+		if ( element!=null ) map.put(index, element);
+		return element;
+	}
+
+	public Iterator entries(CollectionPersister persister) {
+		return map.entrySet().iterator();
+	}
+
+	/** a wrapper for Map.Entry sets */
+	class EntrySetProxy implements Set {
+		private final Set set;
+		EntrySetProxy(Set set) {
+			this.set=set;
+		}
+		public boolean add(Object entry) {
+			//write(); -- doesn't
+			return set.add(entry);
+		}
+		public boolean addAll(Collection entries) {
+			//write(); -- doesn't
+			return set.addAll(entries);
+		}
+		public void clear() {
+			write();
+			set.clear();
+		}
+		public boolean contains(Object entry) {
+			return set.contains(entry);
+		}
+		public boolean containsAll(Collection entries) {
+			return set.containsAll(entries);
+		}
+		public boolean isEmpty() {
+			return set.isEmpty();
+		}
+		public Iterator iterator() {
+			return new EntryIteratorProxy( set.iterator() );
+		}
+		public boolean remove(Object entry) {
+			write();
+			return set.remove(entry);
+		}
+		public boolean removeAll(Collection entries) {
+			write();
+			return set.removeAll(entries);
+		}
+		public boolean retainAll(Collection entries) {
+			write();
+			return set.retainAll(entries);
+		}
+		public int size() {
+			return set.size();
+		}
+		// amazingly, these two will work because AbstractCollection
+		// uses iterator() to fill the array
+		public Object[] toArray() {
+			return set.toArray();
+		}
+		public Object[] toArray(Object[] array) {
+			return set.toArray(array);
+		}
+	}
+	final class EntryIteratorProxy implements Iterator {
+		private final Iterator iter;
+		EntryIteratorProxy(Iterator iter) {
+			this.iter=iter;
+		}
+		public boolean hasNext() {
+			return iter.hasNext();
+		}
+		public Object next() {
+			return new MapEntryProxy( (Map.Entry) iter.next() );
+		}
+		public void remove() {
+			write();
+			iter.remove();
+		}
+	}
+
+	final class MapEntryProxy implements Map.Entry {
+		private final Map.Entry me;
+		MapEntryProxy( Map.Entry me ) {
+			this.me = me;
+		}
+		public Object getKey() { return me.getKey(); }
+		public Object getValue() { return me.getValue(); }
+		public boolean equals(Object o) { return me.equals(o); }
+		public int hashCode() { return me.hashCode(); }
+		// finally, what it's all about...
+		public Object setValue(Object value) {
+			write();
+			return me.setValue(value);
+		}
+	}
+
+	public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
+	throws HibernateException {
+		Serializable[] array = ( Serializable[] ) disassembled;
+		int size = array.length;
+		beforeInitialize( persister, size );
+		for ( int i = 0; i < size; i+=2 ) {
+			map.put(
+					persister.getIndexType().assemble( array[i], getSession(), owner ),
+					persister.getElementType().assemble( array[i+1], getSession(), owner )
+				);
+		}
+	}
+
+	public Serializable disassemble(CollectionPersister persister) throws HibernateException {
+
+		Serializable[] result = new Serializable[ map.size() * 2 ];
+		Iterator iter = map.entrySet().iterator();
+		int i=0;
+		while ( iter.hasNext() ) {
+			Map.Entry e = (Map.Entry) iter.next();
+			result[i++] = persister.getIndexType().disassemble( e.getKey(), getSession(), null );
+			result[i++] = persister.getElementType().disassemble( e.getValue(), getSession(), null );
+		}
+		return result;
+
+	}
+
+	public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) 
+	throws HibernateException {
+		List deletes = new ArrayList();
+		Iterator iter = ( (Map) getSnapshot() ).entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry e = (Map.Entry) iter.next();
+			Object key = e.getKey();
+			if ( e.getValue()!=null && map.get(key)==null ) {
+				deletes.add( indexIsFormula ? e.getValue() : key );
+			}
+		}
+		return deletes.iterator();
+	}
+
+	public boolean needsInserting(Object entry, int i, Type elemType) 
+	throws HibernateException {
+		final Map sn = (Map) getSnapshot();
+		Map.Entry e = (Map.Entry) entry;
+		return e.getValue()!=null && sn.get( e.getKey() )==null;
+	}
+
+	public boolean needsUpdating(Object entry, int i, Type elemType) 
+	throws HibernateException {
+		final Map sn = (Map) getSnapshot();
+		Map.Entry e = (Map.Entry) entry;
+		Object snValue = sn.get( e.getKey() );
+		return e.getValue()!=null &&
+			snValue!=null &&
+			elemType.isDirty( snValue, e.getValue(), getSession() );
+	}
+
+
+	public Object getIndex(Object entry, int i, CollectionPersister persister) {
+		return ( (Map.Entry) entry ).getKey();
+	}
+
+	public Object getElement(Object entry) {
+		return ( (Map.Entry) entry ).getValue();
+	}
+
+	public Object getSnapshotElement(Object entry, int i) {
+		final Map sn = (Map) getSnapshot();
+		return sn.get( ( (Map.Entry) entry ).getKey() );
+	}
+
+	public boolean equals(Object other) {
+		read();
+		return map.equals(other);
+	}
+
+	public int hashCode() {
+		read();
+		return map.hashCode();
+	}
+
+	public boolean entryExists(Object entry, int i) {
+		return ( (Map.Entry) entry ).getValue()!=null;
+	}
+
+	final class Clear implements DelayedOperation {
+		public void operate() {
+			map.clear();
+		}
+		public Object getAddedInstance() {
+			return null;
+		}
+		public Object getOrphan() {
+			throw new UnsupportedOperationException("queued clear cannot be used with orphan delete");
+		}
+	}
+
+	final class Put implements DelayedOperation {
+		private Object index;
+		private Object value;
+		private Object old;
+		
+		public Put(Object index, Object value, Object old) {
+			this.index = index;
+			this.value = value;
+			this.old = old;
+		}
+		public void operate() {
+			map.put(index, value);
+		}
+		public Object getAddedInstance() {
+			return value;
+		}
+		public Object getOrphan() {
+			return old;
+		}
+	}
+
+	final class Remove implements DelayedOperation {
+		private Object index;
+		private Object old;
+		
+		public Remove(Object index, Object old) {
+			this.index = index;
+			this.old = old;
+		}
+		public void operate() {
+			map.remove(index);
+		}
+		public Object getAddedInstance() {
+			return null;
+		}
+		public Object getOrphan() {
+			return old;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentMapElementHolder.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentMapElementHolder.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentMapElementHolder.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,71 @@
+//$Id: PersistentMapElementHolder.java 6838 2005-05-20 19:50:07Z oneovthafew $
+package org.hibernate.collection;
+
+import java.io.Serializable;
+import java.util.List;
+
+import org.dom4j.Element;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.NullableType;
+import org.hibernate.type.Type;
+
+/**
+ * @author Gavin King
+ */
+public class PersistentMapElementHolder extends PersistentIndexedElementHolder {
+
+	public PersistentMapElementHolder(SessionImplementor session, Element element) {
+		super( session, element );
+	}
+
+	public PersistentMapElementHolder(SessionImplementor session, CollectionPersister persister,
+			Serializable key) throws HibernateException {
+		super( session, persister, key );
+	}
+
+	public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
+	throws HibernateException {
+		
+		Type elementType = persister.getElementType();
+		Type indexType = persister.getIndexType();
+		final String indexNodeName = getIndexAttributeName(persister);
+
+		Serializable[] cached = (Serializable[]) disassembled;
+
+		for ( int i=0; i<cached.length; ) {
+			Object index = indexType.assemble( cached[i++], getSession(), owner );
+			Object object = elementType.assemble( cached[i++], getSession(), owner );
+			
+			Element subelement = element.addElement( persister.getElementNodeName() );
+			elementType.setToXMLNode( subelement, object, persister.getFactory() );
+			
+			String indexString = ( (NullableType) indexType ).toXMLString( index, persister.getFactory() );
+			setIndex( subelement, indexNodeName, indexString );
+		}
+		
+	}
+
+	public Serializable disassemble(CollectionPersister persister) throws HibernateException {
+		
+		Type elementType = persister.getElementType();
+		Type indexType = persister.getIndexType();
+		final String indexNodeName = getIndexAttributeName(persister);
+
+		List elements =  element.elements( persister.getElementNodeName() );
+		int length = elements.size();
+		Serializable[] result = new Serializable[length*2];
+		for ( int i=0; i<length*2; ) {
+			Element elem = (Element) elements.get(i/2);
+			Object object = elementType.fromXMLNode( elem, persister.getFactory() );
+			final String indexString = getIndex(elem, indexNodeName, i);
+			Object index = ( (NullableType) indexType ).fromXMLString( indexString, persister.getFactory() );
+			result[i++] = indexType.disassemble( index, getSession(), null );
+			result[i++] = elementType.disassemble( object, getSession(), null );
+		}
+		return result;
+	}
+
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentMapElementHolder.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentSet.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentSet.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentSet.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,468 @@
+//$Id: PersistentSet.java 10589 2006-10-16 15:47:37Z max.andersen at jboss.com $
+package org.hibernate.collection;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.Type;
+
+
+/**
+ * A persistent wrapper for a <tt>java.util.Set</tt>. The underlying
+ * collection is a <tt>HashSet</tt>.
+ *
+ * @see java.util.HashSet
+ * @author Gavin King
+ */
+public class PersistentSet extends AbstractPersistentCollection implements java.util.Set {
+
+	protected Set set;
+	protected transient List tempList;
+
+	/**
+	 * Empty constructor.
+	 * <p/>
+	 * Note: this form is not ever ever ever used by Hibernate; it is, however,
+	 * needed for SOAP libraries and other such marshalling code.
+	 */
+	public PersistentSet() {
+		// intentionally empty
+	}
+
+	/**
+	 * Constructor matching super.  Instantiates a lazy set (the underlying
+	 * set is un-initialized).
+	 *
+	 * @param session The session to which this set will belong.
+	 */
+	public PersistentSet(SessionImplementor session) {
+		super( session );
+	}
+
+	/**
+	 * Instantiates a non-lazy set (the underlying set is constructed
+	 * from the incoming set reference).
+	 *
+	 * @param session The session to which this set will belong.
+	 * @param set The underlying set data.
+	 */
+	public PersistentSet(SessionImplementor session, java.util.Set set) {
+		super(session);
+		// Sets can be just a view of a part of another collection.
+		// do we need to copy it to be sure it won't be changing
+		// underneath us?
+		// ie. this.set.addAll(set);
+		this.set = set;
+		setInitialized();
+		setDirectlyAccessible(true);
+	}
+
+
+	public Serializable getSnapshot(CollectionPersister persister) 
+	throws HibernateException {
+		EntityMode entityMode = getSession().getEntityMode();
+		
+		//if (set==null) return new Set(session);
+		HashMap clonedSet = new HashMap( set.size() );
+		Iterator iter = set.iterator();
+		while ( iter.hasNext() ) {
+			Object copied = persister.getElementType()
+					.deepCopy( iter.next(), entityMode, persister.getFactory() );
+			clonedSet.put(copied, copied);
+		}
+		return clonedSet;
+	}
+
+	public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
+		java.util.Map sn = (java.util.Map) snapshot;
+		return getOrphans( sn.keySet(), set, entityName, getSession() );
+	}
+
+	public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
+		Type elementType = persister.getElementType();
+		java.util.Map sn = (java.util.Map) getSnapshot();
+		if ( sn.size()!=set.size() ) {
+			return false;
+		}
+		else {
+			Iterator iter = set.iterator();
+			while ( iter.hasNext() ) {
+				Object test = iter.next();
+				Object oldValue = sn.get(test);
+				if ( oldValue==null || elementType.isDirty( oldValue, test, getSession() ) ) return false;
+			}
+			return true;
+		}
+	}
+
+	public boolean isSnapshotEmpty(Serializable snapshot) {
+		return ( (java.util.Map) snapshot ).isEmpty();
+	}
+
+	public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
+		this.set = ( Set ) persister.getCollectionType().instantiate( anticipatedSize );
+	}
+
+	public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
+	throws HibernateException {
+		Serializable[] array = ( Serializable[] ) disassembled;
+		int size = array.length;
+		beforeInitialize( persister, size );
+		for (int i = 0; i < size; i++ ) {
+			Object element = persister.getElementType().assemble( array[i], getSession(), owner );
+			if ( element != null ) {
+				set.add( element );
+			}
+		}
+	}
+
+	public boolean empty() {
+		return set.isEmpty();
+	}
+
+	/**
+	 * @see java.util.Set#size()
+	 */
+	public int size() {
+		return readSize() ? getCachedSize() : set.size();
+	}
+
+	/**
+	 * @see java.util.Set#isEmpty()
+	 */
+	public boolean isEmpty() {
+		return readSize() ? getCachedSize()==0 : set.isEmpty();
+	}
+
+	/**
+	 * @see java.util.Set#contains(Object)
+	 */
+	public boolean contains(Object object) {
+		Boolean exists = readElementExistence(object);
+		return exists==null ? 
+				set.contains(object) : 
+				exists.booleanValue();
+	}
+
+	/**
+	 * @see java.util.Set#iterator()
+	 */
+	public Iterator iterator() {
+		read();
+		return new IteratorProxy( set.iterator() );
+	}
+
+	/**
+	 * @see java.util.Set#toArray()
+	 */
+	public Object[] toArray() {
+		read();
+		return set.toArray();
+	}
+
+	/**
+	 * @see java.util.Set#toArray(Object[])
+	 */
+	public Object[] toArray(Object[] array) {
+		read();
+		return set.toArray(array);
+	}
+
+	/**
+	 * @see java.util.Set#add(Object)
+	 */
+	public boolean add(Object value) {
+		Boolean exists = isOperationQueueEnabled() ? readElementExistence( value ) : null;
+		if ( exists == null ) {
+			initialize( true );
+			if ( set.add( value ) ) {
+				dirty();
+				return true;
+			}
+			else {
+				return false;
+			}
+		}
+		else if ( exists.booleanValue() ) {
+			return false;
+		}
+		else {
+			queueOperation( new SimpleAdd(value) );
+			return true;
+		}
+	}
+
+	/**
+	 * @see java.util.Set#remove(Object)
+	 */
+	public boolean remove(Object value) {
+		Boolean exists = isPutQueueEnabled() ? readElementExistence( value ) : null;
+		if ( exists==null ) {
+			initialize( true );
+			if ( set.remove( value ) ) {
+				dirty();
+				return true;
+			}
+			else {
+				return false;
+			}
+		}
+		else if ( exists.booleanValue() ) {
+			queueOperation( new SimpleRemove(value) );
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * @see java.util.Set#containsAll(Collection)
+	 */
+	public boolean containsAll(Collection coll) {
+		read();
+		return set.containsAll(coll);
+	}
+
+	/**
+	 * @see java.util.Set#addAll(Collection)
+	 */
+	public boolean addAll(Collection coll) {
+		if ( coll.size() > 0 ) {
+			initialize( true );
+			if ( set.addAll( coll ) ) {
+				dirty();
+				return true;
+			}
+			else {
+				return false;
+			}
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * @see java.util.Set#retainAll(Collection)
+	 */
+	public boolean retainAll(Collection coll) {
+		initialize( true );
+		if ( set.retainAll( coll ) ) {
+			dirty();
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * @see java.util.Set#removeAll(Collection)
+	 */
+	public boolean removeAll(Collection coll) {
+		if ( coll.size() > 0 ) {
+			initialize( true );
+			if ( set.removeAll( coll ) ) {
+				dirty();
+				return true;
+			}
+			else {
+				return false;
+			}
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * @see java.util.Set#clear()
+	 */
+	public void clear() {
+		if ( isClearQueueEnabled() ) {
+			queueOperation( new Clear() );
+		}
+		else {
+			initialize( true );
+			if ( !set.isEmpty() ) {
+				set.clear();
+				dirty();
+			}
+		}
+	}
+
+	public String toString() {
+		//if (needLoading) return "asleep";
+		read();
+		return set.toString();
+	}
+
+	public Object readFrom(
+	        ResultSet rs,
+	        CollectionPersister persister,
+	        CollectionAliases descriptor,
+	        Object owner) throws HibernateException, SQLException {
+		Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
+		if (element!=null) tempList.add(element);
+		return element;
+	}
+
+	public void beginRead() {
+		super.beginRead();
+		tempList = new ArrayList();
+	}
+
+	public boolean endRead() {
+		set.addAll(tempList);
+		tempList = null;
+		setInitialized();
+		return true;
+	}
+
+	public Iterator entries(CollectionPersister persister) {
+		return set.iterator();
+	}
+
+	public Serializable disassemble(CollectionPersister persister)
+	throws HibernateException {
+
+		Serializable[] result = new Serializable[ set.size() ];
+		Iterator iter = set.iterator();
+		int i=0;
+		while ( iter.hasNext() ) {
+			result[i++] = persister.getElementType().disassemble( iter.next(), getSession(), null );
+		}
+		return result;
+
+	}
+
+	public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
+		Type elementType = persister.getElementType();
+		final java.util.Map sn = (java.util.Map) getSnapshot();
+		ArrayList deletes = new ArrayList( sn.size() );
+		Iterator iter = sn.keySet().iterator();
+		while ( iter.hasNext() ) {
+			Object test = iter.next();
+			if ( !set.contains(test) ) {
+				// the element has been removed from the set
+				deletes.add(test);
+			}
+		}
+		iter = set.iterator();
+		while ( iter.hasNext() ) {
+			Object test = iter.next();
+			Object oldValue = sn.get(test);
+			if ( oldValue!=null && elementType.isDirty( test, oldValue, getSession() ) ) {
+				// the element has changed
+				deletes.add(oldValue);
+			}
+		}
+		return deletes.iterator();
+	}
+
+	public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
+		final java.util.Map sn = (java.util.Map) getSnapshot();
+		Object oldValue = sn.get(entry);
+		// note that it might be better to iterate the snapshot but this is safe,
+		// assuming the user implements equals() properly, as required by the Set
+		// contract!
+		return oldValue==null || elemType.isDirty( oldValue, entry, getSession() );
+	}
+
+	public boolean needsUpdating(Object entry, int i, Type elemType) {
+		return false;
+	}
+
+	public boolean isRowUpdatePossible() {
+		return false;
+	}
+
+	public Object getIndex(Object entry, int i, CollectionPersister persister) {
+		throw new UnsupportedOperationException("Sets don't have indexes");
+	}
+
+	public Object getElement(Object entry) {
+		return entry;
+	}
+
+	public Object getSnapshotElement(Object entry, int i) {
+		throw new UnsupportedOperationException("Sets don't support updating by element");
+	}
+
+	public boolean equals(Object other) {
+		read();
+		return set.equals(other);
+	}
+
+	public int hashCode() {
+		read();
+		return set.hashCode();
+	}
+
+	public boolean entryExists(Object key, int i) {
+		return true;
+	}
+
+	public boolean isWrapper(Object collection) {
+		return set==collection;
+	}
+
+	final class Clear implements DelayedOperation {
+		public void operate() {
+			set.clear();
+		}
+		public Object getAddedInstance() {
+			return null;
+		}
+		public Object getOrphan() {
+			throw new UnsupportedOperationException("queued clear cannot be used with orphan delete");
+		}
+	}
+
+	final class SimpleAdd implements DelayedOperation {
+		private Object value;
+		
+		public SimpleAdd(Object value) {
+			this.value = value;
+		}
+		public void operate() {
+			set.add(value);
+		}
+		public Object getAddedInstance() {
+			return value;
+		}
+		public Object getOrphan() {
+			return null;
+		}
+	}
+
+	final class SimpleRemove implements DelayedOperation {
+		private Object value;
+		
+		public SimpleRemove(Object value) {
+			this.value = value;
+		}
+		public void operate() {
+			set.remove(value);
+		}
+		public Object getAddedInstance() {
+			return null;
+		}
+		public Object getOrphan() {
+			return value;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentSortedMap.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentSortedMap.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentSortedMap.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,191 @@
+//$Id: PersistentSortedMap.java 7714 2005-08-01 16:29:33Z oneovthafew $
+package org.hibernate.collection;
+
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.BasicCollectionPersister;
+
+
+/**
+ * A persistent wrapper for a <tt>java.util.SortedMap</tt>. Underlying
+ * collection is a <tt>TreeMap</tt>.
+ *
+ * @see java.util.TreeMap
+ * @author <a href="mailto:doug.currie at alum.mit.edu">e</a>
+ */
+public class PersistentSortedMap extends PersistentMap implements SortedMap {
+
+	protected Comparator comparator;
+
+	protected Serializable snapshot(BasicCollectionPersister persister, EntityMode entityMode) throws HibernateException {
+		TreeMap clonedMap = new TreeMap(comparator);
+		Iterator iter = map.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry e = (Map.Entry) iter.next();
+			clonedMap.put( e.getKey(), persister.getElementType().deepCopy( e.getValue(), entityMode, persister.getFactory() ) );
+		}
+		return clonedMap;
+	}
+
+	public PersistentSortedMap(SessionImplementor session) {
+		super(session);
+	}
+
+	public void setComparator(Comparator comparator) {
+		this.comparator = comparator;
+	}
+
+	public PersistentSortedMap(SessionImplementor session, SortedMap map) {
+		super(session, map);
+		comparator = map.comparator();
+	}
+
+	public PersistentSortedMap() {} //needed for SOAP libraries, etc
+
+	/**
+	 * @see PersistentSortedMap#comparator()
+	 */
+	public Comparator comparator() {
+		return comparator;
+	}
+
+	/**
+	 * @see PersistentSortedMap#subMap(Object, Object)
+	 */
+	public SortedMap subMap(Object fromKey, Object toKey) {
+		read();
+		SortedMap m = ( (SortedMap) map ).subMap(fromKey, toKey);
+		return new SortedSubMap(m);
+	}
+
+	/**
+	 * @see PersistentSortedMap#headMap(Object)
+	 */
+	public SortedMap headMap(Object toKey) {
+		read();
+		SortedMap m;
+		m = ( (SortedMap) map ).headMap(toKey);
+		return new SortedSubMap(m);
+	}
+
+	/**
+	 * @see PersistentSortedMap#tailMap(Object)
+	 */
+	public SortedMap tailMap(Object fromKey) {
+		read();
+		SortedMap m;
+		m = ( (SortedMap) map ).tailMap(fromKey);
+		return new SortedSubMap(m);
+	}
+
+	/**
+	 * @see PersistentSortedMap#firstKey()
+	 */
+	public Object firstKey() {
+		read();
+		return ( (SortedMap) map ).firstKey();
+	}
+
+	/**
+	 * @see PersistentSortedMap#lastKey()
+	 */
+	public Object lastKey() {
+		read();
+		return ( (SortedMap) map ).lastKey();
+	}
+
+	class SortedSubMap implements SortedMap {
+
+		SortedMap submap;
+
+		SortedSubMap(SortedMap m) {
+			this.submap = m;
+		}
+		// from Map
+		public int size() {
+			return submap.size();
+		}
+		public boolean isEmpty() {
+			return submap.isEmpty();
+		}
+		public boolean containsKey(Object key) {
+			return submap.containsKey(key);
+		}
+		public boolean containsValue(Object key) {
+			return submap.containsValue(key) ;
+		}
+		public Object get(Object key) {
+			return submap.get(key);
+		}
+		public Object put(Object key, Object value) {
+			write();
+			return submap.put(key,  value);
+		}
+		public Object remove(Object key) {
+			write();
+			return submap.remove(key);
+		}
+		public void putAll(Map other) {
+			write();
+			submap.putAll(other);
+		}
+		public void clear() {
+			write();
+			submap.clear();
+		}
+		public Set keySet() {
+			return new SetProxy( submap.keySet() );
+		}
+		public Collection values() {
+			return new SetProxy( submap.values() );
+		}
+		public Set entrySet() {
+			return new EntrySetProxy( submap.entrySet() );
+		}
+		// from SortedMap
+		public Comparator comparator() {
+			return submap.comparator();
+		}
+		public SortedMap subMap(Object fromKey, Object toKey) {
+			SortedMap m;
+			m = submap.subMap(fromKey, toKey);
+			return new SortedSubMap( m );
+		}
+		public SortedMap headMap(Object toKey) {
+			SortedMap m;
+			m = submap.headMap(toKey);
+			return new SortedSubMap(m);
+		}
+		public SortedMap tailMap(Object fromKey) {
+			SortedMap m;
+			m = submap.tailMap(fromKey);
+			return new SortedSubMap(m);
+		}
+		public Object firstKey() {
+			return  submap.firstKey();
+		}
+		public Object lastKey() {
+			return submap.lastKey();
+		}
+
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentSortedSet.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentSortedSet.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/PersistentSortedSet.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,145 @@
+//$Id: PersistentSortedSet.java 7714 2005-08-01 16:29:33Z oneovthafew $
+package org.hibernate.collection;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.SortedSet;
+import java.util.TreeMap;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.BasicCollectionPersister;
+
+
+/**
+ * A persistent wrapper for a <tt>java.util.SortedSet</tt>. Underlying
+ * collection is a <tt>TreeSet</tt>.
+ *
+ * @see java.util.TreeSet
+ * @author <a href="mailto:doug.currie at alum.mit.edu">e</a>
+ */
+public class PersistentSortedSet extends PersistentSet implements SortedSet {
+
+	protected Comparator comparator;
+
+	protected Serializable snapshot(BasicCollectionPersister persister, EntityMode entityMode) 
+	throws HibernateException {
+		//if (set==null) return new Set(session);
+		TreeMap clonedSet = new TreeMap(comparator);
+		Iterator iter = set.iterator();
+		while ( iter.hasNext() ) {
+			Object copy = persister.getElementType().deepCopy( iter.next(), entityMode, persister.getFactory() );
+			clonedSet.put(copy, copy);
+		}
+		return clonedSet;
+	}
+
+	public void setComparator(Comparator comparator) {
+		this.comparator = comparator;
+	}
+
+	public PersistentSortedSet(SessionImplementor session) {
+		super(session);
+	}
+
+	public PersistentSortedSet(SessionImplementor session, SortedSet set) {
+		super(session, set);
+		comparator = set.comparator();
+	}
+
+	public PersistentSortedSet() {} //needed for SOAP libraries, etc
+
+	/**
+	 * @see PersistentSortedSet#comparator()
+	 */
+	public Comparator comparator() {
+		return comparator;
+	}
+
+	/**
+	 * @see PersistentSortedSet#subSet(Object,Object)
+	 */
+	public SortedSet subSet(Object fromElement, Object toElement) {
+		read();
+		SortedSet s;
+		s = ( (SortedSet) set ).subSet(fromElement, toElement);
+		return new SubSetProxy(s);
+	}
+
+	/**
+	 * @see PersistentSortedSet#headSet(Object)
+	 */
+	public SortedSet headSet(Object toElement) {
+		read();
+		SortedSet s = ( (SortedSet) set ).headSet(toElement);
+		return new SubSetProxy(s);
+	}
+
+	/**
+	 * @see PersistentSortedSet#tailSet(Object)
+	 */
+	public SortedSet tailSet(Object fromElement) {
+		read();
+		SortedSet s = ( (SortedSet) set ).tailSet(fromElement);
+		return new SubSetProxy(s);
+	}
+
+	/**
+	 * @see PersistentSortedSet#first()
+	 */
+	public Object first() {
+		read();
+		return ( (SortedSet) set ).first();
+	}
+
+	/**
+	 * @see PersistentSortedSet#last()
+	 */
+	public Object last() {
+		read();
+		return ( (SortedSet) set ).last();
+	}
+
+	/** wrapper for subSets to propagate write to its backing set */
+	class SubSetProxy extends SetProxy implements SortedSet {
+
+		SubSetProxy(SortedSet s) {
+			super(s);
+		}
+
+		public Comparator comparator() {
+			return ( (SortedSet) this.set ).comparator();
+		}
+
+		public Object first() {
+			return ( (SortedSet) this.set ).first();
+		}
+
+		public SortedSet headSet(Object toValue) {
+			return new SubSetProxy( ( (SortedSet) this.set ).headSet(toValue) );
+		}
+
+		public Object last() {
+			return ( (SortedSet) this.set ).last();
+		}
+
+		public SortedSet subSet(Object fromValue, Object toValue) {
+			return new SubSetProxy( ( (SortedSet) this.set ).subSet(fromValue, toValue) );
+		}
+
+		public SortedSet tailSet(Object fromValue) {
+			return new SubSetProxy( ( (SortedSet) this.set ).tailSet(fromValue) );
+		}
+
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/collection/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/collection/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines a framework for collection wrappers.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/collection/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/connection/ConnectionProvider.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/connection/ConnectionProvider.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/connection/ConnectionProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,71 @@
+//$Id: ConnectionProvider.java 9191 2006-02-01 14:40:34Z epbernard $
+package org.hibernate.connection;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import org.hibernate.HibernateException;
+
+/**
+ * A strategy for obtaining JDBC connections.
+ * <br><br>
+ * Implementors might also implement connection pooling.<br>
+ * <br>
+ * The <tt>ConnectionProvider</tt> interface is not intended to be
+ * exposed to the application. Instead it is used internally by
+ * Hibernate to obtain connections.<br>
+ * <br>
+ * Implementors should provide a public default constructor.
+ *
+ * @see ConnectionProviderFactory
+ * @author Gavin King
+ */
+public interface ConnectionProvider {
+	/**
+	 * Initialize the connection provider from given properties.
+	 * @param props <tt>SessionFactory</tt> properties
+	 */
+	public void configure(Properties props) throws HibernateException;
+	/**
+	 * Grab a connection, with the autocommit mode specified by
+	 * <tt>hibernate.connection.autocommit</tt>.
+	 * @return a JDBC connection
+	 * @throws SQLException
+	 */
+	public Connection getConnection() throws SQLException;
+	/**
+	 * Dispose of a used connection.
+	 * @param conn a JDBC connection
+	 * @throws SQLException
+	 */
+	public void closeConnection(Connection conn) throws SQLException;
+
+	/**
+	 * Release all resources held by this provider. JavaDoc requires a second sentence.
+	 * @throws HibernateException
+	 */
+	public void close() throws HibernateException;
+
+	/**
+	 * Does this connection provider support aggressive release of JDBC
+	 * connections and re-acquistion of those connections (if need be) later?
+	 * <p/>
+	 * This is used in conjunction with {@link org.hibernate.cfg.Environment.RELEASE_CONNECTIONS}
+	 * to aggressively release JDBC connections.  However, the configured ConnectionProvider
+	 * must support re-acquisition of the same underlying connection for that semantic to work.
+	 * <p/>
+	 * Typically, this is only true in managed environments where a container
+	 * tracks connections by transaction or thread.
+	 *
+	 * Note that JTA semantic depends on the fact that the underlying connection provider does
+	 * support aggressive release.
+	 */
+	public boolean supportsAggressiveRelease();
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/connection/ConnectionProviderFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/connection/ConnectionProviderFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/connection/ConnectionProviderFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,174 @@
+//$Id: ConnectionProviderFactory.java 7541 2005-07-18 22:37:31Z epbernard $
+package org.hibernate.connection;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Map;
+import java.beans.Introspector;
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * Instantiates a connection provider given either <tt>System</tt> properties or
+ * a <tt>java.util.Properties</tt> instance. The <tt>ConnectionProviderFactory</tt>
+ * first attempts to find a name of a <tt>ConnectionProvider</tt> subclass in the
+ * property <tt>hibernate.connection.provider_class</tt>. If missing, heuristics are used
+ * to choose either <tt>DriverManagerConnectionProvider</tt>,
+ * <tt>DatasourceConnectionProvider</tt>, <tt>C3P0ConnectionProvider</tt> or
+ * <tt>DBCPConnectionProvider</tt>.
+ * @see ConnectionProvider
+ * @author Gavin King
+ */
+
+public final class ConnectionProviderFactory {
+
+	private static final Log log = LogFactory.getLog(ConnectionProviderFactory.class);
+
+	/**
+	 * Instantiate a <tt>ConnectionProvider</tt> using <tt>System</tt> properties.
+	 * @return ConnectionProvider
+	 * @throws HibernateException
+	 */
+	public static ConnectionProvider newConnectionProvider() throws HibernateException {
+		return newConnectionProvider( Environment.getProperties() );
+	}
+
+	/**
+	 * Instantiate a <tt>ConnectionProvider</tt> using given properties.
+	 * Method newConnectionProvider.
+	 * @param properties hibernate <tt>SessionFactory</tt> properties
+	 * @return ConnectionProvider
+	 * @throws HibernateException
+	 */
+	public static ConnectionProvider newConnectionProvider(Properties properties) throws HibernateException {
+		return newConnectionProvider( properties, null );
+	}
+
+	/**
+	 * Instantiate a <tt>ConnectionProvider</tt> using given properties.
+	 * Method newConnectionProvider.
+	 * @param properties hibernate <tt>SessionFactory</tt> properties
+	 * @Param connectionProviderInjectionData object to be injected in the conenction provided
+	 * @return ConnectionProvider
+	 * @throws HibernateException
+	 */
+	public static ConnectionProvider newConnectionProvider(Properties properties, Map connectionProviderInjectionData) throws HibernateException {
+		ConnectionProvider connections;
+		String providerClass = properties.getProperty(Environment.CONNECTION_PROVIDER);
+		if ( providerClass!=null ) {
+			try {
+				log.info("Initializing connection provider: " + providerClass);
+				connections = (ConnectionProvider) ReflectHelper.classForName(providerClass).newInstance();
+			}
+			catch (Exception e) {
+				log.fatal("Could not instantiate connection provider", e);
+				throw new HibernateException("Could not instantiate connection provider: " + providerClass);
+			}
+		}
+		else if ( properties.getProperty(Environment.DATASOURCE)!=null ) {
+			connections = new DatasourceConnectionProvider();
+		}
+		else if ( properties.getProperty(Environment.C3P0_MAX_SIZE)!=null ) {
+			connections = new C3P0ConnectionProvider();
+		}
+		else if (
+			properties.getProperty(Environment.PROXOOL_XML)!=null ||
+			properties.getProperty(Environment.PROXOOL_PROPERTIES)!=null ||
+			properties.getProperty(Environment.PROXOOL_EXISTING_POOL)!=null
+		) {
+			connections = new ProxoolConnectionProvider();
+		}
+		else if ( properties.getProperty(Environment.URL)!=null ) {
+			connections = new DriverManagerConnectionProvider();
+		}
+		else {
+			connections = new UserSuppliedConnectionProvider();
+		}
+
+		if ( connectionProviderInjectionData != null && connectionProviderInjectionData.size() != 0 ) {
+			//inject the data
+			try {
+				BeanInfo info = Introspector.getBeanInfo( connections.getClass() );
+				PropertyDescriptor[] descritors = info.getPropertyDescriptors();
+				int size = descritors.length;
+				for (int index = 0 ; index < size ; index++) {
+					String propertyName = descritors[index].getName();
+					if ( connectionProviderInjectionData.containsKey( propertyName ) ) {
+						Method method = descritors[index].getWriteMethod();
+						method.invoke( connections, new Object[] { connectionProviderInjectionData.get( propertyName ) } );
+					}
+				}
+			}
+			catch (IntrospectionException e) {
+				throw new HibernateException("Unable to inject objects into the conenction provider", e);
+			}
+			catch (IllegalAccessException e) {
+				throw new HibernateException("Unable to inject objects into the conenction provider", e);
+			}
+			catch (InvocationTargetException e) {
+				throw new HibernateException("Unable to inject objects into the conenction provider", e);
+			}
+		}
+		connections.configure(properties);
+		return connections;
+	}
+
+	// cannot be instantiated
+	private ConnectionProviderFactory() { throw new UnsupportedOperationException(); }
+
+	/**
+	 * Transform JDBC connection properties.
+	 *
+	 * Passed in the form <tt>hibernate.connection.*</tt> to the
+	 * format accepted by <tt>DriverManager</tt> by triming the leading "<tt>hibernate.connection</tt>".
+	 */
+	public static Properties getConnectionProperties(Properties properties) {
+
+		Iterator iter = properties.keySet().iterator();
+		Properties result = new Properties();
+		while ( iter.hasNext() ) {
+			String prop = (String) iter.next();
+			if ( prop.indexOf(Environment.CONNECTION_PREFIX) > -1 && !SPECIAL_PROPERTIES.contains(prop) ) {
+				result.setProperty(
+					prop.substring( Environment.CONNECTION_PREFIX.length()+1 ),
+					properties.getProperty(prop)
+				);
+			}
+		}
+		String userName = properties.getProperty(Environment.USER);
+		if (userName!=null) result.setProperty( "user", userName );
+		return result;
+	}
+
+	private static final Set SPECIAL_PROPERTIES;
+	static {
+		SPECIAL_PROPERTIES = new HashSet();
+		SPECIAL_PROPERTIES.add(Environment.DATASOURCE);
+		SPECIAL_PROPERTIES.add(Environment.URL);
+		SPECIAL_PROPERTIES.add(Environment.CONNECTION_PROVIDER);
+		SPECIAL_PROPERTIES.add(Environment.POOL_SIZE);
+		SPECIAL_PROPERTIES.add(Environment.ISOLATION);
+		SPECIAL_PROPERTIES.add(Environment.DRIVER);
+		SPECIAL_PROPERTIES.add(Environment.USER);
+
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/connection/DatasourceConnectionProvider.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/connection/DatasourceConnectionProvider.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/connection/DatasourceConnectionProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,93 @@
+//$Id: DatasourceConnectionProvider.java 10075 2006-07-01 12:50:34Z epbernard $
+package org.hibernate.connection;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import javax.sql.DataSource;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.util.NamingHelper;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * A connection provider that uses a <tt>DataSource</tt> registered with JNDI.
+ * Hibernate will use this <tt>ConnectionProvider</tt> by default if the
+ * property <tt>hibernate.connection.datasource</tt> is set.
+ * @see ConnectionProvider
+ * @author Gavin King
+ */
+public class DatasourceConnectionProvider implements ConnectionProvider {
+	private DataSource ds;
+	private String user;
+	private String pass;
+
+	private static final Log log = LogFactory.getLog(DatasourceConnectionProvider.class);
+
+	public DataSource getDataSource() {
+		return ds;
+	}
+
+	public void setDataSource(DataSource ds) {
+		this.ds = ds;
+	}
+
+	public void configure(Properties props) throws HibernateException {
+
+		String jndiName = props.getProperty(Environment.DATASOURCE);
+		if (jndiName==null) {
+			String msg = "datasource JNDI name was not specified by property " + Environment.DATASOURCE;
+			log.fatal(msg);
+			throw new HibernateException(msg);
+		}
+
+		user = props.getProperty(Environment.USER);
+		pass = props.getProperty(Environment.PASS);
+
+		try {
+			ds = (DataSource) NamingHelper.getInitialContext(props).lookup(jndiName);
+		}
+		catch (Exception e) {
+			log.fatal( "Could not find datasource: " + jndiName, e );
+			throw new HibernateException( "Could not find datasource", e );
+		}
+		if (ds==null) {
+			throw new HibernateException( "Could not find datasource: " + jndiName );
+		}
+		log.info( "Using datasource: " + jndiName );
+	}
+
+	public Connection getConnection() throws SQLException {
+		if (user != null || pass != null) {
+			return ds.getConnection(user, pass);
+		}
+		else {
+			return ds.getConnection();
+		}
+	}
+
+	public void closeConnection(Connection conn) throws SQLException {
+		conn.close();
+	}
+
+	public void close() {}
+
+	/**
+	 * @see ConnectionProvider#supportsAggressiveRelease()
+	 */
+	public boolean supportsAggressiveRelease() {
+		return true;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/connection/DriverManagerConnectionProvider.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/connection/DriverManagerConnectionProvider.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/connection/DriverManagerConnectionProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,176 @@
+//$Id: DriverManagerConnectionProvider.java 7888 2005-08-12 21:22:38Z oneovthafew $
+package org.hibernate.connection;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.util.PropertiesHelper;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * A connection provider that uses <tt>java.sql.DriverManager</tt>. This provider
+ * also implements a very rudimentary connection pool.
+ * @see ConnectionProvider
+ * @author Gavin King
+ */
+public class DriverManagerConnectionProvider implements ConnectionProvider {
+
+	private String url;
+	private Properties connectionProps;
+	private Integer isolation;
+	private final ArrayList pool = new ArrayList();
+	private int poolSize;
+	private int checkedOut = 0;
+	private boolean autocommit;
+
+	private static final Log log = LogFactory.getLog(DriverManagerConnectionProvider.class);
+
+	public void configure(Properties props) throws HibernateException {
+
+		String driverClass = props.getProperty(Environment.DRIVER);
+
+		poolSize = PropertiesHelper.getInt(Environment.POOL_SIZE, props, 20); //default pool size 20
+		log.info("Using Hibernate built-in connection pool (not for production use!)");
+		log.info("Hibernate connection pool size: " + poolSize);
+		
+		autocommit = PropertiesHelper.getBoolean(Environment.AUTOCOMMIT, props);
+		log.info("autocommit mode: " + autocommit);
+
+		isolation = PropertiesHelper.getInteger(Environment.ISOLATION, props);
+		if (isolation!=null)
+		log.info( "JDBC isolation level: " + Environment.isolationLevelToString( isolation.intValue() ) );
+
+		if (driverClass==null) {
+			log.warn("no JDBC Driver class was specified by property " + Environment.DRIVER);
+		}
+		else {
+			try {
+				// trying via forName() first to be as close to DriverManager's semantics
+				Class.forName(driverClass);
+			}
+			catch (ClassNotFoundException cnfe) {
+				try {
+					ReflectHelper.classForName(driverClass);
+				}
+				catch (ClassNotFoundException e) {
+					String msg = "JDBC Driver class not found: " + driverClass;
+					log.fatal(msg, e);
+					throw new HibernateException(msg, e);
+				}
+			}
+		}
+
+		url = props.getProperty(Environment.URL);
+		if (url==null) {
+			String msg = "JDBC URL was not specified by property " + Environment.URL;
+			log.fatal(msg);
+			throw new HibernateException(msg);
+		}
+
+		connectionProps = ConnectionProviderFactory.getConnectionProperties(props);
+
+		log.info( "using driver: " + driverClass + " at URL: " + url );
+		// if debug level is enabled, then log the password, otherwise mask it
+		if ( log.isDebugEnabled() ) {
+			log.info( "connection properties: " + connectionProps );
+		} 
+		else if ( log.isInfoEnabled() ) {
+			log.info( "connection properties: " + PropertiesHelper.maskOut(connectionProps, "password") );
+		}
+
+	}
+
+	public Connection getConnection() throws SQLException {
+
+		if ( log.isTraceEnabled() ) log.trace( "total checked-out connections: " + checkedOut );
+
+		synchronized (pool) {
+			if ( !pool.isEmpty() ) {
+				int last = pool.size() - 1;
+				if ( log.isTraceEnabled() ) {
+					log.trace("using pooled JDBC connection, pool size: " + last);
+					checkedOut++;
+				}
+				Connection pooled = (Connection) pool.remove(last);
+				if (isolation!=null) pooled.setTransactionIsolation( isolation.intValue() );
+				if ( pooled.getAutoCommit()!=autocommit ) pooled.setAutoCommit(autocommit);
+				return pooled;
+			}
+		}
+
+		log.debug("opening new JDBC connection");
+		Connection conn = DriverManager.getConnection(url, connectionProps);
+		if (isolation!=null) conn.setTransactionIsolation( isolation.intValue() );
+		if ( conn.getAutoCommit()!=autocommit ) conn.setAutoCommit(autocommit);
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( "created connection to: " + url + ", Isolation Level: " + conn.getTransactionIsolation() );
+		}
+		if ( log.isTraceEnabled() ) checkedOut++;
+
+		return conn;
+	}
+
+	public void closeConnection(Connection conn) throws SQLException {
+
+		if ( log.isDebugEnabled() ) checkedOut--;
+
+		synchronized (pool) {
+			int currentSize = pool.size();
+			if ( currentSize < poolSize ) {
+				if ( log.isTraceEnabled() ) log.trace("returning connection to pool, pool size: " + (currentSize + 1) );
+				pool.add(conn);
+				return;
+			}
+		}
+
+		log.debug("closing JDBC connection");
+
+		conn.close();
+
+	}
+
+	protected void finalize() {
+		close();
+	}
+
+	public void close() {
+
+		log.info("cleaning up connection pool: " + url);
+
+		Iterator iter = pool.iterator();
+		while ( iter.hasNext() ) {
+			try {
+				( (Connection) iter.next() ).close();
+			}
+			catch (SQLException sqle) {
+				log.warn("problem closing pooled connection", sqle);
+			}
+		}
+		pool.clear();
+
+	}
+
+	/**
+	 * @see ConnectionProvider#supportsAggressiveRelease()
+	 */
+	public boolean supportsAggressiveRelease() {
+		return false;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/connection/UserSuppliedConnectionProvider.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/connection/UserSuppliedConnectionProvider.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/connection/UserSuppliedConnectionProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,56 @@
+//$Id: UserSuppliedConnectionProvider.java 6463 2005-04-19 15:39:07Z steveebersole $
+package org.hibernate.connection;
+
+import java.sql.Connection;
+import java.util.Properties;
+
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+
+/**
+ * An implementation of the <literal>ConnectionProvider</literal> interface that
+ * simply throws an exception when a connection is requested. This implementation
+ * indicates that the user is expected to supply a JDBC connection.
+ * @see ConnectionProvider
+ * @author Gavin King
+ */
+public class UserSuppliedConnectionProvider implements ConnectionProvider {
+
+	/**
+	 * @see org.hibernate.connection.ConnectionProvider#configure(Properties)
+	 */
+	public void configure(Properties props) throws HibernateException {
+		LogFactory.getLog(UserSuppliedConnectionProvider.class).warn("No connection properties specified - the user must supply JDBC connections");
+	}
+
+	/**
+	 * @see org.hibernate.connection.ConnectionProvider#getConnection()
+	 */
+	public Connection getConnection() {
+		throw new UnsupportedOperationException("The user must supply a JDBC connection");
+	}
+
+	/**
+	 * @see org.hibernate.connection.ConnectionProvider#closeConnection(Connection)
+	 */
+	public void closeConnection(Connection conn) {
+		throw new UnsupportedOperationException("The user must supply a JDBC connection");
+	}
+
+	public void close() {
+	}
+
+	/**
+	 * @see ConnectionProvider#supportsAggressiveRelease()
+	 */
+	public boolean supportsAggressiveRelease() {
+		return false;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/connection/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/connection/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/connection/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package abstracts the mechanism for obtaining
+	a JDBC connection.
+</p>
+<p>
+	A concrete implementation of <tt>ConnectionProvider</tt> may be 
+	selected by specifying <tt>hibernate.connection.provider_class</tt>.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/connection/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/context/CurrentSessionContext.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/context/CurrentSessionContext.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/context/CurrentSessionContext.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+package org.hibernate.context;
+
+import org.hibernate.HibernateException;
+
+import java.io.Serializable;
+
+/**
+ * Defines the contract for implementations which know how to
+ * scope the notion of a {@link org.hibernate.SessionFactory#getCurrentSession() current session}.
+ * <p/>
+ * Implementations should adhere to the following:
+ * <ul>
+ * <li>contain a constructor accepting a single argument of type
+ * {@link org.hibernate.engine.SessionFactoryImplementor}
+ * <li>should be thread safe
+ * <li>should be fully serializable
+ * </ul>
+ * <p/>
+ * Implementors should be aware that they are also fully responsible for
+ * cleanup of any generated current-sessions.
+ * <p/>
+ * Note that there will be exactly one instance of the configured
+ * CurrentSessionContext implementation per {@link org.hibernate.SessionFactory}.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public interface CurrentSessionContext extends Serializable {
+	/**
+	 * Retrieve the current session according to the scoping defined
+	 * by this implementation.
+	 *
+	 * @return The current session.
+	 * @throws org.hibernate.HibernateException Typically indicates an issue
+	 * locating or creating the current session.
+	 */
+	public org.hibernate.classic.Session currentSession() throws HibernateException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/context/JTASessionContext.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/context/JTASessionContext.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/context/JTASessionContext.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,168 @@
+package org.hibernate.context;
+
+import org.hibernate.HibernateException;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.classic.Session;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.util.JTAHelper;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.Synchronization;
+import java.util.Map;
+import java.util.Hashtable;
+
+/**
+ * An implementation of {@link CurrentSessionContext} which scopes the notion
+ * of a current session to a JTA transaction.  Because JTA gives us a nice
+ * tie-in to clean up after ourselves, this implementation will generate
+ * Sessions as needed provided a JTA transaction is in effect.  If a session
+ * is not already associated with the current JTA transaction at the time
+ * {@link #currentSession()} is called, a new session will be opened and it
+ * will be associated with that JTA transaction.
+ * <p/>
+ * Note that the sessions returned from this method are automatically configured with
+ * both the {@link org.hibernate.cfg.Environment#FLUSH_BEFORE_COMPLETION auto-flush} and
+ * {@link org.hibernate.cfg.Environment#AUTO_CLOSE_SESSION auto-close} attributes set to
+ * true, meaning that the Session will be automatically flushed and closed
+ * as part of the lifecycle for the JTA transaction to which it is associated.
+ * Additionally, it will also be configured to aggressively release JDBC
+ * connections after each statement is executed.  These settings are governed
+ * by the {@link #isAutoFlushEnabled()}, {@link #isAutoCloseEnabled()}, and
+ * {@link #getConnectionReleaseMode()} methods; these are provided (along with
+ * the {@link #buildOrObtainSession()} method) for easier subclassing for custom
+ * JTA-based session tracking logic (like maybe long-session semantics).
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class JTASessionContext implements CurrentSessionContext {
+
+	private static final Log log = LogFactory.getLog( JTASessionContext.class );
+
+	protected final SessionFactoryImplementor factory;
+	private transient Map currentSessionMap = new Hashtable();
+
+	public JTASessionContext(SessionFactoryImplementor factory) {
+		this.factory = factory;
+	}
+
+	public Session currentSession() throws HibernateException {
+		TransactionManager transactionManager = factory.getTransactionManager();
+		if ( transactionManager == null ) {
+			throw new HibernateException( "No TransactionManagerLookup specified" );
+		}
+
+		Transaction txn = null;
+		try {
+			txn = transactionManager.getTransaction();
+			if ( txn == null ) {
+				throw new HibernateException( "Unable to locate current JTA transaction" );
+			}
+			if ( !JTAHelper.isInProgress( txn.getStatus() ) ) {
+				// We could register the session against the transaction even though it is
+				// not started, but we'd have no guarentee of ever getting the map
+				// entries cleaned up (aside from spawning threads).
+				throw new HibernateException( "Current transaction is not in progress" );
+			}
+		}
+		catch ( HibernateException e ) {
+			throw e;
+		}
+		catch ( Throwable t ) {
+			throw new HibernateException( "Problem locating/validating JTA transaction", t );
+		}
+
+		Session currentSession = ( Session ) currentSessionMap.get( txn );
+
+		if ( currentSession == null ) {
+			currentSession = buildOrObtainSession();
+
+			try {
+				txn.registerSynchronization( buildCleanupSynch( txn ) );
+			}
+			catch ( Throwable t ) {
+				try {
+					currentSession.close();
+				}
+				catch ( Throwable ignore ) {
+					log.debug( "Unable to release generated current-session on failed synch registration", ignore );
+				}
+				throw new HibernateException( "Unable to register cleanup Synchronization with TransactionManager" );
+			}
+
+			currentSessionMap.put( txn, currentSession );
+		}
+
+		return currentSession;
+	}
+
+	private CleanupSynch buildCleanupSynch(Transaction txn) {
+		return new CleanupSynch( txn, this );
+	}
+
+	/**
+	 * Strictly provided for subclassing purposes; specifically to allow long-session
+	 * support.
+	 * <p/>
+	 * This implementation always just opens a new session.
+	 *
+	 * @return the built or (re)obtained session.
+	 */
+	protected Session buildOrObtainSession() {
+		return factory.openSession(
+				null,
+		        isAutoFlushEnabled(),
+		        isAutoCloseEnabled(),
+		        getConnectionReleaseMode()
+			);
+	}
+
+	/**
+	 * Mainly for subclass usage.  This impl always returns true.
+	 *
+	 * @return Whether or not the the session should be closed by transaction completion.
+	 */
+	protected boolean isAutoCloseEnabled() {
+		return true;
+	}
+
+	/**
+	 * Mainly for subclass usage.  This impl always returns true.
+	 *
+	 * @return Whether or not the the session should be flushed prior transaction completion.
+	 */
+	protected boolean isAutoFlushEnabled() {
+		return true;
+	}
+
+	/**
+	 * Mainly for subclass usage.  This impl always returns after_statement.
+	 *
+	 * @return The connection release mode for any built sessions.
+	 */
+	protected ConnectionReleaseMode getConnectionReleaseMode() {
+		return ConnectionReleaseMode.AFTER_STATEMENT;
+	}
+
+	/**
+	 * JTA transaction synch used for cleanup of the internal session map.
+	 */
+	protected static class CleanupSynch implements Synchronization {
+		private Transaction txn;
+		private JTASessionContext context;
+
+		public CleanupSynch(Transaction txn, JTASessionContext context) {
+			this.txn = txn;
+			this.context = context;
+		}
+
+		public void beforeCompletion() {
+		}
+
+		public void afterCompletion(int i) {
+			context.currentSessionMap.remove( txn );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/context/ManagedSessionContext.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/context/ManagedSessionContext.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/context/ManagedSessionContext.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,125 @@
+package org.hibernate.context;
+
+import org.hibernate.classic.Session;
+import org.hibernate.HibernateException;
+import org.hibernate.SessionFactory;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * Represents a {@link CurrentSessionContext} the notion of a contextual session
+ * is managed by some external entity (generally some form of interceptor, etc).
+ * This external manager is responsible for scoping these contextual sessions
+ * appropriately binding/unbinding them here for exposure to the application
+ * through {@link SessionFactory#getCurrentSession} calls.
+ * <p/>
+ *  Basically exposes two interfaces.  <ul>
+ * <li>First is the implementation of CurrentSessionContext which is then used
+ * by the {@link SessionFactory#getCurrentSession()} calls.  This
+ * portion is instance-based specific to the session factory owning the given
+ * instance of this impl (there will be one instance of this per each session
+ * factory using this strategy).
+ * <li>Second is the externally facing methods {@link #hasBind}, {@link #bind},
+ * and {@link #unbind} used by the external thing to manage exposure of the
+ * current session it is scoping.  This portion is static to allow easy
+ * reference from that external thing.
+ * </ul>
+ * The underlying storage of the current sessions here is a static
+ * {@link ThreadLocal}-based map where the sessions are keyed by the
+ * the owning session factory.
+ *
+ * @author Steve Ebersole
+ */
+public class ManagedSessionContext implements CurrentSessionContext {
+
+	private static final ThreadLocal context = new ThreadLocal();
+	private final SessionFactoryImplementor factory;
+
+	public ManagedSessionContext(SessionFactoryImplementor factory) {
+		this.factory = factory;
+	}
+
+	/**
+	 * @see CurrentSessionContext#currentSession
+	 */
+	public Session currentSession() {
+		Session current = existingSession( factory );
+		if ( current == null ) {
+			throw new HibernateException( "No session currently bound to execution context" );
+		}
+		return current;
+	}
+
+	/**
+	 * Check to see if there is already a session associated with the current
+	 * thread for the given session factory.
+	 *
+	 * @param factory The factory against which to check for a given session
+	 * within the current thread.
+	 * @return True if there is currently a session bound.
+	 */
+	public static boolean hasBind(SessionFactory factory) {
+		return existingSession( factory ) != null;
+	}
+
+	/**
+	 * Binds the given session to the current context for its session factory.
+	 *
+	 * @param session The session to be bound.
+	 * @return Any previously bound session (should be null in most cases).
+	 */
+	public static Session bind(Session session) {
+		return ( Session ) sessionMap( true ).put( session.getSessionFactory(), session );
+	}
+
+	/**
+	 * Unbinds the session (if one) current associated with the context for the
+	 * given session.
+	 *
+	 * @param factory The factory for which to unbind the current session.
+	 * @return The bound session if one, else null.
+	 */
+	public static Session unbind(SessionFactory factory) {
+		Session existing = null;
+		Map sessionMap = sessionMap();
+		if ( sessionMap != null ) {
+			existing = ( Session ) sessionMap.remove( factory );
+			doCleanup();
+		}
+		return existing;
+	}
+
+	private static Session existingSession(SessionFactory factory) {
+		Map sessionMap = sessionMap();
+		if ( sessionMap == null ) {
+			return null;
+		}
+		else {
+			return ( Session ) sessionMap.get( factory );
+		}
+	}
+
+	protected static Map sessionMap() {
+		return sessionMap( false );
+	}
+
+	private static synchronized Map sessionMap(boolean createMap) {
+		Map sessionMap = ( Map ) context.get();
+		if ( sessionMap == null && createMap ) {
+			sessionMap = new HashMap();
+			context.set( sessionMap );
+		}
+		return sessionMap;
+	}
+
+	private static synchronized void doCleanup() {
+		Map sessionMap = sessionMap( false );
+		if ( sessionMap != null ) {
+			if ( sessionMap.isEmpty() ) {
+				context.set( null );
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/context/ThreadLocalSessionContext.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/context/ThreadLocalSessionContext.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/context/ThreadLocalSessionContext.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,339 @@
+package org.hibernate.context;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.HashMap;
+import java.util.Map;
+import javax.transaction.Synchronization;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.HibernateException;
+import org.hibernate.SessionFactory;
+import org.hibernate.classic.Session;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * A {@link CurrentSessionContext} impl which scopes the notion of current
+ * session by the current thread of execution.  Unlike the JTA counterpart,
+ * threads do not give us a nice hook to perform any type of cleanup making
+ * it questionable for this impl to actually generate Session instances.  In
+ * the interest of usability, it was decided to have this default impl
+ * actually generate a session upon first request and then clean it up
+ * after the {@link org.hibernate.Transaction} associated with that session
+ * is committed/rolled-back.  In order for ensuring that happens, the sessions
+ * generated here are unusable until after {@link Session#beginTransaction()}
+ * has been called. If <tt>close()</tt> is called on a session managed by
+ * this class, it will be automatically unbound.
+ * <p/>
+ * Additionally, the static {@link #bind} and {@link #unbind} methods are
+ * provided to allow application code to explicitly control opening and
+ * closing of these sessions.  This, with some from of interception,
+ * is the preferred approach.  It also allows easy framework integration
+ * and one possible approach for implementing long-sessions.
+ * <p/>
+ * The {@link #buildOrObtainSession}, {@link #isAutoCloseEnabled},
+ * {@link #isAutoFlushEnabled}, {@link #getConnectionReleaseMode}, and
+ * {@link #buildCleanupSynch} methods are all provided to allow easy
+ * subclassing (for long- running session scenarios, for example).
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class ThreadLocalSessionContext implements CurrentSessionContext {
+
+	private static final Log log = LogFactory.getLog( ThreadLocalSessionContext.class );
+	private static final Class[] SESS_PROXY_INTERFACES = new Class[] {
+			org.hibernate.classic.Session.class,
+	        org.hibernate.engine.SessionImplementor.class,
+	        org.hibernate.jdbc.JDBCContext.Context.class,
+	        org.hibernate.event.EventSource.class
+	};
+
+	/**
+	 * A ThreadLocal maintaining current sessions for the given execution thread.
+	 * The actual ThreadLocal variable is a java.util.Map to account for
+	 * the possibility for multiple SessionFactorys being used during execution
+	 * of the given thread.
+	 */
+	private static final ThreadLocal context = new ThreadLocal();
+
+	protected final SessionFactoryImplementor factory;
+
+	public ThreadLocalSessionContext(SessionFactoryImplementor factory) {
+		this.factory = factory;
+	}
+
+	public final Session currentSession() throws HibernateException {
+		Session current = existingSession( factory );
+		if (current == null) {
+			current = buildOrObtainSession();
+			// register a cleanup synch
+			current.getTransaction().registerSynchronization( buildCleanupSynch() );
+			// wrap the session in the transaction-protection proxy
+			if ( needsWrapping( current ) ) {
+				current = wrap( current );
+			}
+			// then bind it
+			doBind( current, factory );
+		}
+		return current;
+	}
+
+	private boolean needsWrapping(Session session) {
+		// try to make sure we don't wrap and already wrapped session
+		return session != null
+		       && ! Proxy.isProxyClass( session.getClass() )
+		       || ( Proxy.getInvocationHandler( session ) != null
+		       && ! ( Proxy.getInvocationHandler( session ) instanceof TransactionProtectionWrapper ) );
+	}
+
+	protected SessionFactoryImplementor getFactory() {
+		return factory;
+	}
+
+	/**
+	 * Strictly provided for subclassing purposes; specifically to allow long-session
+	 * support.
+	 * <p/>
+	 * This implementation always just opens a new session.
+	 *
+	 * @return the built or (re)obtained session.
+	 */
+	protected Session buildOrObtainSession() {
+		return factory.openSession(
+				null,
+		        isAutoFlushEnabled(),
+		        isAutoCloseEnabled(),
+		        getConnectionReleaseMode()
+			);
+	}
+
+	protected CleanupSynch buildCleanupSynch() {
+		return new CleanupSynch( factory );
+	}
+
+	/**
+	 * Mainly for subclass usage.  This impl always returns true.
+	 *
+	 * @return Whether or not the the session should be closed by transaction completion.
+	 */
+	protected boolean isAutoCloseEnabled() {
+		return true;
+	}
+
+	/**
+	 * Mainly for subclass usage.  This impl always returns true.
+	 *
+	 * @return Whether or not the the session should be flushed prior transaction completion.
+	 */
+	protected boolean isAutoFlushEnabled() {
+		return true;
+	}
+
+	/**
+	 * Mainly for subclass usage.  This impl always returns after_transaction.
+	 *
+	 * @return The connection release mode for any built sessions.
+	 */
+	protected ConnectionReleaseMode getConnectionReleaseMode() {
+		return factory.getSettings().getConnectionReleaseMode();
+	}
+
+	protected Session wrap(Session session) {
+		TransactionProtectionWrapper wrapper = new TransactionProtectionWrapper( session );
+		Session wrapped = ( Session ) Proxy.newProxyInstance(
+				Session.class.getClassLoader(),
+		        SESS_PROXY_INTERFACES,
+		        wrapper
+			);
+		// yick!  need this for proper serialization/deserialization handling...
+		wrapper.setWrapped( wrapped );
+		return wrapped;
+	}
+
+	/**
+	 * Associates the given session with the current thread of execution.
+	 *
+	 * @param session The session to bind.
+	 */
+	public static void bind(org.hibernate.Session session) {
+		SessionFactory factory = session.getSessionFactory();
+		cleanupAnyOrphanedSession( factory );
+		doBind( session, factory );
+	}
+
+	private static void cleanupAnyOrphanedSession(SessionFactory factory) {
+		Session orphan = doUnbind( factory, false );
+		if ( orphan != null ) {
+			log.warn( "Already session bound on call to bind(); make sure you clean up your sessions!" );
+			try {
+				if ( orphan.getTransaction() != null && orphan.getTransaction().isActive() ) {
+					try {
+						orphan.getTransaction().rollback();
+					}
+					catch( Throwable t ) {
+						log.debug( "Unable to rollback transaction for orphaned session", t );
+					}
+				}
+				orphan.close();
+			}
+			catch( Throwable t ) {
+				log.debug( "Unable to close orphaned session", t );
+			}
+		}
+	}
+
+	/**
+	 * Unassociate a previously bound session from the current thread of execution.
+	 *
+	 * @return The session which was unbound.
+	 */
+	public static Session unbind(SessionFactory factory) {
+		return doUnbind( factory, true );
+	}
+
+	private static Session existingSession(SessionFactory factory) {
+		Map sessionMap = sessionMap();
+		if ( sessionMap == null ) {
+			return null;
+		}
+		else {
+			return ( Session ) sessionMap.get( factory );
+		}
+	}
+
+	protected static Map sessionMap() {
+		return ( Map ) context.get();
+	}
+
+	private static void doBind(org.hibernate.Session session, SessionFactory factory) {
+		Map sessionMap = sessionMap();
+		if ( sessionMap == null ) {
+			sessionMap = new HashMap();
+			context.set( sessionMap );
+		}
+		sessionMap.put( factory, session );
+	}
+
+	private static Session doUnbind(SessionFactory factory, boolean releaseMapIfEmpty) {
+		Map sessionMap = sessionMap();
+		Session session = null;
+		if ( sessionMap != null ) {
+			session = ( Session ) sessionMap.remove( factory );
+			if ( releaseMapIfEmpty && sessionMap.isEmpty() ) {
+				context.set( null );
+			}
+		}
+		return session;
+	}
+
+	/**
+	 * JTA transaction synch used for cleanup of the internal session map.
+	 */
+	protected static class CleanupSynch implements Synchronization, Serializable {
+		protected final SessionFactory factory;
+
+		public CleanupSynch(SessionFactory factory) {
+			this.factory = factory;
+		}
+
+		public void beforeCompletion() {
+		}
+
+		public void afterCompletion(int i) {
+			unbind( factory );
+		}
+	}
+
+	private class TransactionProtectionWrapper implements InvocationHandler, Serializable {
+		private final Session realSession;
+		private Session wrappedSession;
+
+		public TransactionProtectionWrapper(Session realSession) {
+			this.realSession = realSession;
+		}
+
+		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+			try {
+				// If close() is called, guarantee unbind()
+				if ( "close".equals( method.getName()) ) {
+					unbind( realSession.getSessionFactory() );
+				}
+				else if ( "toString".equals( method.getName() )
+					     || "equals".equals( method.getName() )
+					     || "hashCode".equals( method.getName() )
+				         || "getStatistics".equals( method.getName() )
+					     || "isOpen".equals( method.getName() ) ) {
+					// allow these to go through the the real session no matter what
+				}
+				else if ( !realSession.isOpen() ) {
+					// essentially, if the real session is closed allow any
+					// method call to pass through since the real session
+					// will complain by throwing an appropriate exception;
+					// NOTE that allowing close() above has the same basic effect,
+					//   but we capture that there simply to perform the unbind...
+				}
+				else if ( !realSession.getTransaction().isActive() ) {
+					// limit the methods available if no transaction is active
+					if ( "beginTransaction".equals( method.getName() )
+					     || "getTransaction".equals( method.getName() )
+					     || "isTransactionInProgress".equals( method.getName() )
+					     || "setFlushMode".equals( method.getName() )
+					     || "getSessionFactory".equals( method.getName() ) ) {
+						log.trace( "allowing method [" + method.getName() + "] in non-transacted context" );
+					}
+					else if ( "reconnect".equals( method.getName() )
+					          || "disconnect".equals( method.getName() ) ) {
+						// allow these (deprecated) methods to pass through
+					}
+					else {
+						throw new HibernateException( method.getName() + " is not valid without active transaction" );
+					}
+				}
+				log.trace( "allowing proxied method [" + method.getName() + "] to proceed to real session" );
+				return method.invoke( realSession, args );
+			}
+			catch ( InvocationTargetException e ) {
+				if ( e.getTargetException() instanceof RuntimeException ) {
+					throw ( RuntimeException ) e.getTargetException();
+				}
+				else {
+					throw e;
+				}
+			}
+		}
+
+		public void setWrapped(Session wrapped) {
+			this.wrappedSession = wrapped;
+		}
+
+
+		// serialization ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+		private void writeObject(ObjectOutputStream oos) throws IOException {
+			// if a ThreadLocalSessionContext-bound session happens to get
+			// serialized, to be completely correct, we need to make sure
+			// that unbinding of that session occurs.
+			oos.defaultWriteObject();
+			if ( existingSession( factory ) == wrappedSession ) {
+				unbind( factory );
+			}
+		}
+
+		private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+			// on the inverse, it makes sense that if a ThreadLocalSessionContext-
+			// bound session then gets deserialized to go ahead and re-bind it to
+			// the ThreadLocalSessionContext session map.
+			ois.defaultReadObject();
+			realSession.getTransaction().registerSynchronization( buildCleanupSynch() );
+			doBind( wrappedSession, factory );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AbstractEmptinessExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AbstractEmptinessExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AbstractEmptinessExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,86 @@
+// $Id: AbstractEmptinessExpression.java 6670 2005-05-03 22:19:00Z steveebersole $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.persister.entity.PropertyMapping;
+import org.hibernate.sql.ConditionFragment;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.Type;
+
+/**
+ * Implementation of AbstractEmptinessExpression.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractEmptinessExpression implements Criterion {
+
+	private static final TypedValue[] NO_VALUES = new TypedValue[0];
+
+	protected final String propertyName;
+
+	protected AbstractEmptinessExpression(String propertyName) {
+		this.propertyName = propertyName;
+	}
+
+	protected abstract boolean excludeEmpty();
+
+	public final String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
+		String entityName = criteriaQuery.getEntityName( criteria, propertyName );
+		String actualPropertyName = criteriaQuery.getPropertyName( propertyName );
+		String sqlAlias = criteriaQuery.getSQLAlias( criteria, propertyName );
+
+		SessionFactoryImplementor factory = criteriaQuery.getFactory();
+		QueryableCollection collectionPersister = getQueryableCollection( entityName, actualPropertyName, factory );
+
+		String[] collectionKeys = collectionPersister.getKeyColumnNames();
+		String[] ownerKeys = ( ( Loadable ) factory.getEntityPersister( entityName ) ).getIdentifierColumnNames();
+
+		String innerSelect = "(select 1 from " + collectionPersister.getTableName()
+		        + " where "
+		        + new ConditionFragment().setTableAlias( sqlAlias ).setCondition( ownerKeys, collectionKeys ).toFragmentString()
+		        + ")";
+
+		return excludeEmpty()
+		        ? "exists " + innerSelect
+		        : "not exists " + innerSelect;
+	}
+
+
+	protected QueryableCollection getQueryableCollection(String entityName, String propertyName, SessionFactoryImplementor factory)
+	        throws HibernateException {
+		PropertyMapping ownerMapping = ( PropertyMapping ) factory.getEntityPersister( entityName );
+		Type type = ownerMapping.toType( propertyName );
+		if ( !type.isCollectionType() ) {
+			throw new MappingException(
+			        "Property path [" + entityName + "." + propertyName + "] does not reference a collection"
+			);
+		}
+
+		String role = ( ( CollectionType ) type ).getRole();
+		try {
+			return ( QueryableCollection ) factory.getCollectionPersister( role );
+		}
+		catch ( ClassCastException cce ) {
+			throw new QueryException( "collection role is not queryable: " + role );
+		}
+		catch ( Exception e ) {
+			throw new QueryException( "collection role not found: " + role );
+		}
+	}
+
+	public final TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
+	        throws HibernateException {
+		return NO_VALUES;
+	}
+
+	public final String toString() {
+		return propertyName + ( excludeEmpty() ? " is not empty" : " is empty" );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AggregateProjection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AggregateProjection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AggregateProjection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+//$Id: AggregateProjection.java 9908 2006-05-08 20:59:20Z max.andersen at jboss.com $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.type.Type;
+
+/**
+ * An aggregation
+ * @author max
+ */
+public class AggregateProjection extends SimpleProjection {
+
+	protected final String propertyName;
+	private final String aggregate;
+	
+	protected AggregateProjection(String aggregate, String propertyName) {
+		this.aggregate = aggregate;
+		this.propertyName = propertyName;
+	}
+
+	public String toString() {
+		return aggregate + "(" + propertyName + ')';
+	}
+
+	public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return new Type[] { criteriaQuery.getType(criteria, propertyName) };
+	}
+
+	public String toSqlString(Criteria criteria, int loc, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return new StringBuffer()
+			.append(aggregate)
+			.append("(")
+			.append( criteriaQuery.getColumn(criteria, propertyName) )
+			.append(") as y")
+			.append(loc)
+			.append('_')
+			.toString();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AliasedProjection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AliasedProjection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AliasedProjection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,65 @@
+//$Id: AliasedProjection.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.type.Type;
+
+/**
+ * @author Gavin King
+ */
+public class AliasedProjection implements Projection {
+	
+	private final Projection projection;
+	private final String alias;
+	
+	public String toString() {
+		return projection.toString() + " as " + alias;
+	}
+	
+	protected AliasedProjection(Projection projection, String alias) {
+		this.projection = projection;
+		this.alias = alias;
+	}
+
+	public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return projection.toSqlString(criteria, position, criteriaQuery);
+	}
+
+	public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return projection.toGroupSqlString(criteria, criteriaQuery);
+	}
+
+	public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		return projection.getTypes(criteria, criteriaQuery);
+	}
+
+	public String[] getColumnAliases(int loc) {
+		return projection.getColumnAliases(loc);
+	}
+
+	public Type[] getTypes(String alias, Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return this.alias.equals(alias) ?
+				getTypes(criteria, criteriaQuery) :
+				null;
+	}
+
+	public String[] getColumnAliases(String alias, int loc) {
+		return this.alias.equals(alias) ? 
+				getColumnAliases(loc) :
+				null;
+	}
+
+	public String[] getAliases() {
+		return new String[]{ alias };
+	}
+
+	public boolean isGrouped() {
+		return projection.isGrouped();
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AliasedProjection.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AvgProjection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AvgProjection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AvgProjection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: AvgProjection.java 9908 2006-05-08 20:59:20Z max.andersen at jboss.com $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.type.Type;
+
+/**
+ * @author Gavin King
+ */
+public class AvgProjection extends AggregateProjection {
+
+	public AvgProjection(String propertyName) {
+		super("avg", propertyName);
+	}
+	
+	public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		return new Type[] { Hibernate.DOUBLE };
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/AvgProjection.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/BetweenExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/BetweenExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/BetweenExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+//$Id: BetweenExpression.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Constrains a property to between two values
+ * @author Gavin King
+ */
+public class BetweenExpression implements Criterion {
+
+	private final String propertyName;
+	private final Object lo;
+	private final Object hi;
+
+	protected BetweenExpression(String propertyName, Object lo, Object hi) {
+		this.propertyName = propertyName;
+		this.lo = lo;
+		this.hi = hi;
+	}
+
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		return StringHelper.join(
+			" and ",
+			StringHelper.suffix( criteriaQuery.getColumnsUsingProjection(criteria, propertyName), " between ? and ?" )
+		);
+
+		//TODO: get SQL rendering out of this package!
+	}
+
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		return new TypedValue[] {
+				criteriaQuery.getTypedValue(criteria, propertyName, lo),
+				criteriaQuery.getTypedValue(criteria, propertyName, hi)
+		};
+	}
+
+	public String toString() {
+		return propertyName + " between " + lo + " and " + hi;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Conjunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Conjunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Conjunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+package org.hibernate.criterion;
+
+
+/**
+ * @author Gavin King
+ */
+public class Conjunction extends Junction {
+
+	public Conjunction() {
+		super("and");
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CountProjection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CountProjection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CountProjection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+//$Id: CountProjection.java 9913 2006-05-09 07:40:11Z max.andersen at jboss.com $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.type.Type;
+
+/**
+ * A count
+ * @author Gavin King
+ */
+public class CountProjection extends AggregateProjection {
+
+	private boolean distinct;
+
+	protected CountProjection(String prop) {
+		super("count", prop);
+	}
+
+	public String toString() {
+		if(distinct) {
+			return "distinct " + super.toString();
+		} else {
+			return super.toString();
+		}
+	}
+
+	public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return new Type[] { Hibernate.INTEGER };
+	}
+
+	public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		StringBuffer buf = new StringBuffer();
+		buf.append("count(");
+		if (distinct) buf.append("distinct ");
+		return buf.append( criteriaQuery.getColumn(criteria, propertyName) )
+			.append(") as y")
+			.append(position)
+			.append('_')
+			.toString();
+	}
+	
+	public CountProjection setDistinct() {
+		distinct = true;
+		return this;
+	}
+	
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CountProjection.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CriteriaQuery.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CriteriaQuery.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CriteriaQuery.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,92 @@
+//$Id: CriteriaQuery.java 6970 2005-05-31 20:24:41Z oneovthafew $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.type.Type;
+
+/**
+ * An instance of <tt>CriteriaQuery</tt> is passed to criterion, 
+ * order and projection instances when actually compiling and
+ * executing the query. This interface is not used by application
+ * code.
+ * 
+ * @author Gavin King
+ */
+public interface CriteriaQuery {
+	public SessionFactoryImplementor getFactory();
+	
+	/**
+	 * Get the names of the columns mapped by a property path,
+	 * ignoring projection aliases
+	 */
+	public String getColumn(Criteria criteria, String propertyPath) 
+	throws HibernateException;
+	
+	/**
+	 * Get the type of a property path, ignoring projection aliases
+	 */
+	public Type getType(Criteria criteria, String propertyPath)
+	throws HibernateException;
+
+	/**
+	 * Get the names of the columns mapped by a property path
+	 */
+	public String[] getColumnsUsingProjection(Criteria criteria, String propertyPath) 
+	throws HibernateException;
+	
+	/**
+	 * Get the type of a property path
+	 */
+	public Type getTypeUsingProjection(Criteria criteria, String propertyPath)
+	throws HibernateException;
+
+	/**
+	 * Get the a typed value for the given property value.
+	 */
+	public TypedValue getTypedValue(Criteria criteria, String propertyPath, Object value) 
+	throws HibernateException;
+	
+	/**
+	 * Get the entity name of an entity
+	 */
+	public String getEntityName(Criteria criteria);
+	
+	/**
+	 * Get the entity name of an entity, taking into account
+	 * the qualifier of the property path
+	 */
+	public String getEntityName(Criteria criteria, String propertyPath);
+
+	/**
+	 * Get the root table alias of an entity
+	 */
+	public String getSQLAlias(Criteria subcriteria);
+
+	/**
+	 * Get the root table alias of an entity, taking into account
+	 * the qualifier of the property path
+	 */
+	public String getSQLAlias(Criteria criteria, String propertyPath);
+	
+	/**
+	 * Get the property name, given a possibly qualified property name
+	 */
+	public String getPropertyName(String propertyName);
+	
+	/**
+	 * Get the identifier column names of this entity
+	 */
+	public String[] getIdentifierColumns(Criteria subcriteria);
+	
+	/**
+	 * Get the identifier type of this entity
+	 */
+	public Type getIdentifierType(Criteria subcriteria);
+	
+	public TypedValue getTypedIdentifierValue(Criteria subcriteria, Object value);
+	
+	public String generateSQLAlias();
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CriteriaQuery.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CriteriaSpecification.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CriteriaSpecification.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CriteriaSpecification.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+//$Id: CriteriaSpecification.java 9116 2006-01-23 21:21:01Z steveebersole $
+package org.hibernate.criterion;
+
+import org.hibernate.transform.AliasToEntityMapResultTransformer;
+import org.hibernate.transform.DistinctRootEntityResultTransformer;
+import org.hibernate.transform.PassThroughResultTransformer;
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.transform.RootEntityResultTransformer;
+
+/**
+ * @author Gavin King
+ */
+public interface CriteriaSpecification {
+
+	/**
+	 * The alias that refers to the "root" entity of the criteria query.
+	 */
+	public static final String ROOT_ALIAS = "this";
+
+	/**
+	 * Each row of results is a <tt>Map</tt> from alias to entity instance
+	 */
+	public static final ResultTransformer ALIAS_TO_ENTITY_MAP = new AliasToEntityMapResultTransformer();
+
+	/**
+	 * Each row of results is an instance of the root entity
+	 */
+	public static final ResultTransformer ROOT_ENTITY = new RootEntityResultTransformer();
+
+	/**
+	 * Each row of results is a distinct instance of the root entity
+	 */
+	public static final ResultTransformer DISTINCT_ROOT_ENTITY = new DistinctRootEntityResultTransformer();
+
+	/**
+	 * This result transformer is selected implicitly by calling <tt>setProjection()</tt>
+	 */
+	public static final ResultTransformer PROJECTION = new PassThroughResultTransformer();
+
+	/**
+	 * Specifies joining to an entity based on an inner join.
+	 */
+	public static final int INNER_JOIN = org.hibernate.sql.JoinFragment.INNER_JOIN;
+
+	/**
+	 * Specifies joining to an entity based on a full join.
+	 */
+	public static final int FULL_JOIN = org.hibernate.sql.JoinFragment.FULL_JOIN;
+
+	/**
+	 * Specifies joining to an entity based on a left outer join.
+	 */
+	public static final int LEFT_JOIN = org.hibernate.sql.JoinFragment.LEFT_OUTER_JOIN;
+	
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/CriteriaSpecification.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Criterion.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Criterion.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Criterion.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+//$Id: Criterion.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+
+import java.io.Serializable;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.TypedValue;
+
+/**
+ * An object-oriented representation of a query criterion that may be used 
+ * as a restriction in a <tt>Criteria</tt> query.
+ * Built-in criterion types are provided by the <tt>Restrictions</tt> factory 
+ * class. This interface might be implemented by application classes that 
+ * define custom restriction criteria.
+ *
+ * @see Restrictions
+ * @see org.hibernate.Criteria
+ * @author Gavin King
+ */
+public interface Criterion extends Serializable {
+
+	/**
+	 * Render the SQL fragment
+	 * @param criteriaQuery
+	 * @param alias
+	 * @return String
+	 * @throws HibernateException
+	 */
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException;
+	
+	/**
+	 * Return typed values for all parameters in the rendered SQL fragment
+	 * @param criteria TODO
+	 * @param criteriaQuery 
+	 * @return TypedValue[]
+	 * @throws HibernateException
+	 */
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException;
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/DetachedCriteria.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/DetachedCriteria.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/DetachedCriteria.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,125 @@
+//$Id: DetachedCriteria.java 8757 2005-12-06 03:35:50Z steveebersole $
+package org.hibernate.criterion;
+
+import java.io.Serializable;
+
+import org.hibernate.Criteria;
+import org.hibernate.FetchMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.impl.CriteriaImpl;
+import org.hibernate.impl.SessionImpl;
+import org.hibernate.transform.ResultTransformer;
+
+/**
+ * Some applications need to create criteria queries in "detached
+ * mode", where the Hibernate session is not available. This class
+ * may be instantiated anywhere, and then a <literal>Criteria</literal>
+ * may be obtained by passing a session to 
+ * <literal>getExecutableCriteria()</literal>. All methods have the
+ * same semantics and behavior as the corresponding methods of the
+ * <literal>Criteria</literal> interface.
+ * 
+ * @see org.hibernate.Criteria
+ * @author Gavin King
+ */
+public class DetachedCriteria implements CriteriaSpecification, Serializable {
+	
+	private final CriteriaImpl impl;
+	private final Criteria criteria;
+	
+	protected DetachedCriteria(String entityName) {
+		impl = new CriteriaImpl(entityName, null);
+		criteria = impl;
+	}
+	
+	protected DetachedCriteria(String entityName, String alias) {
+		impl = new CriteriaImpl(entityName, alias, null);
+		criteria = impl;
+	}
+	
+	protected DetachedCriteria(CriteriaImpl impl, Criteria criteria) {
+		this.impl = impl;
+		this.criteria = criteria;
+	}
+	
+	/**
+	 * Get an executable instance of <literal>Criteria</literal>,
+	 * to actually run the query.
+	 */
+	public Criteria getExecutableCriteria(Session session) {
+		impl.setSession( ( SessionImplementor ) session );
+		return impl;
+	}
+	
+	public static DetachedCriteria forEntityName(String entityName) {
+		return new DetachedCriteria(entityName);
+	}
+	
+	public static DetachedCriteria forEntityName(String entityName, String alias) {
+		return new DetachedCriteria(entityName, alias);
+	}
+	
+	public static DetachedCriteria forClass(Class clazz) {
+		return new DetachedCriteria( clazz.getName() );
+	}
+	
+	public static DetachedCriteria forClass(Class clazz, String alias) {
+		return new DetachedCriteria( clazz.getName() , alias );
+	}
+	
+	public DetachedCriteria add(Criterion criterion) {
+		criteria.add(criterion);
+		return this;
+	}
+
+	public DetachedCriteria addOrder(Order order) {
+		criteria.addOrder(order);
+		return this;
+	}
+
+	public DetachedCriteria createAlias(String associationPath, String alias)
+	throws HibernateException {
+		criteria.createAlias(associationPath, alias);
+		return this;
+	}
+
+	public DetachedCriteria createCriteria(String associationPath, String alias)
+	throws HibernateException {
+		return new DetachedCriteria( impl, criteria.createCriteria(associationPath) );
+	}
+
+	public DetachedCriteria createCriteria(String associationPath)
+	throws HibernateException {
+		return new DetachedCriteria( impl, criteria.createCriteria(associationPath) );
+	}
+
+	public String getAlias() {
+		return criteria.getAlias();
+	}
+
+	public DetachedCriteria setFetchMode(String associationPath, FetchMode mode)
+	throws HibernateException {
+		criteria.setFetchMode(associationPath, mode);
+		return this;
+	}
+
+	public DetachedCriteria setProjection(Projection projection) {
+		criteria.setProjection(projection);
+		return this;
+	}
+
+	public DetachedCriteria setResultTransformer(ResultTransformer resultTransformer) {
+		criteria.setResultTransformer(resultTransformer);
+		return this;
+	}
+	
+	public String toString() {
+		return "DetachableCriteria(" + criteria.toString() + ')';
+	}
+	
+	CriteriaImpl getCriteriaImpl() {
+		return impl;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/DetachedCriteria.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Disjunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Disjunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Disjunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+package org.hibernate.criterion;
+
+
+/**
+ * @author Gavin King
+ */
+public class Disjunction extends Junction {
+
+	protected Disjunction() {
+		super("or");
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Distinct.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Distinct.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Distinct.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,58 @@
+//$Id: Distinct.java 6452 2005-04-18 17:16:57Z oneovthafew $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.type.Type;
+
+/**
+ * @author Gavin King
+ */
+public class Distinct implements Projection {
+
+	private final Projection projection;
+	
+	public Distinct(Projection proj) {
+		this.projection = proj;
+	}
+
+	public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery)
+			throws HibernateException {
+		return "distinct " + projection.toSqlString(criteria, position, criteriaQuery);
+	}
+
+	public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
+			throws HibernateException {
+		return projection.toGroupSqlString(criteria, criteriaQuery);
+	}
+
+	public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery)
+			throws HibernateException {
+		return projection.getTypes(criteria, criteriaQuery);
+	}
+
+	public Type[] getTypes(String alias, Criteria criteria, CriteriaQuery criteriaQuery)
+			throws HibernateException {
+		return projection.getTypes(alias, criteria, criteriaQuery);
+	}
+
+	public String[] getColumnAliases(int loc) {
+		return projection.getColumnAliases(loc);
+	}
+
+	public String[] getColumnAliases(String alias, int loc) {
+		return projection.getColumnAliases(alias, loc);
+	}
+
+	public String[] getAliases() {
+		return projection.getAliases();
+	}
+
+	public boolean isGrouped() {
+		return projection.isGrouped();
+	}
+
+	public String toString() {
+		return "distinct " + projection.toString();
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Distinct.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/EmptyExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/EmptyExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/EmptyExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+//$Id: EmptyExpression.java 6661 2005-05-03 20:12:20Z steveebersole $
+package org.hibernate.criterion;
+
+/**
+ * @author Gavin King
+ */
+public class EmptyExpression extends AbstractEmptinessExpression implements Criterion {
+
+	protected EmptyExpression(String propertyName) {
+		super( propertyName );
+	}
+
+	protected boolean excludeEmpty() {
+		return false;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/EmptyExpression.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Example.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Example.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Example.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,374 @@
+//$Id: Example.java 10061 2006-06-28 05:20:51Z steve.ebersole at jboss.com $
+package org.hibernate.criterion;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.hibernate.Criteria;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.Type;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Support for query by example.
+ * <pre>
+ * List results = session.createCriteria(Parent.class)
+ *     .add( Example.create(parent).ignoreCase() )
+ *     .createCriteria("child")
+ *         .add( Example.create( parent.getChild() ) )
+ *     .list();
+ * </pre>
+ * "Examples" may be mixed and matched with "Expressions" in the same <tt>Criteria</tt>.
+ * @see org.hibernate.Criteria
+ * @author Gavin King
+ */
+
+public class Example implements Criterion {
+
+	private final Object entity;
+	private final Set excludedProperties = new HashSet();
+	private PropertySelector selector;
+	private boolean isLikeEnabled;
+	private Character escapeCharacter;
+	private boolean isIgnoreCaseEnabled;
+	private MatchMode matchMode;
+
+	/**
+	 * A strategy for choosing property values for inclusion in the query
+	 * criteria
+	 */
+
+	public static interface PropertySelector extends Serializable {
+		public boolean include(Object propertyValue, String propertyName, Type type);
+	}
+
+	private static final PropertySelector NOT_NULL = new NotNullPropertySelector();
+	private static final PropertySelector ALL = new AllPropertySelector();
+	private static final PropertySelector NOT_NULL_OR_ZERO = new NotNullOrZeroPropertySelector();
+
+	static final class AllPropertySelector implements PropertySelector {
+		public boolean include(Object object, String propertyName, Type type) {
+			return true;
+		}
+		
+		private Object readResolve() {
+			return ALL;
+		}
+	}
+
+	static final class NotNullPropertySelector implements PropertySelector {
+		public boolean include(Object object, String propertyName, Type type) {
+			return object!=null;
+		}
+		
+		private Object readResolve() {
+			return NOT_NULL;
+		}
+	}
+
+	static final class NotNullOrZeroPropertySelector implements PropertySelector {
+		public boolean include(Object object, String propertyName, Type type) {
+			return object!=null && (
+				!(object instanceof Number) || ( (Number) object ).longValue()!=0
+			);
+		}
+		
+		private Object readResolve() {
+			return NOT_NULL_OR_ZERO;
+		}
+	}
+
+	/**
+	 * Set escape character for "like" clause
+	 */
+	public Example setEscapeCharacter(Character escapeCharacter) {
+		this.escapeCharacter = escapeCharacter;
+		return this;
+	}
+
+	/**
+	 * Set the property selector
+	 */
+	public Example setPropertySelector(PropertySelector selector) {
+		this.selector = selector;
+		return this;
+	}
+
+	/**
+	 * Exclude zero-valued properties
+	 */
+	public Example excludeZeroes() {
+		setPropertySelector(NOT_NULL_OR_ZERO);
+		return this;
+	}
+
+	/**
+	 * Don't exclude null or zero-valued properties
+	 */
+	public Example excludeNone() {
+		setPropertySelector(ALL);
+		return this;
+	}
+
+	/**
+	 * Use the "like" operator for all string-valued properties
+	 */
+	public Example enableLike(MatchMode matchMode) {
+		isLikeEnabled = true;
+		this.matchMode = matchMode;
+		return this;
+	}
+
+	/**
+	 * Use the "like" operator for all string-valued properties
+	 */
+	public Example enableLike() {
+		return enableLike(MatchMode.EXACT);
+	}
+
+	/**
+	 * Ignore case for all string-valued properties
+	 */
+	public Example ignoreCase() {
+		isIgnoreCaseEnabled = true;
+		return this;
+	}
+
+	/**
+	 * Exclude a particular named property
+	 */
+	public Example excludeProperty(String name) {
+		excludedProperties.add(name);
+		return this;
+	}
+
+	/**
+	 * Create a new instance, which includes all non-null properties
+	 * by default
+	 * @param entity
+	 * @return a new instance of <tt>Example</tt>
+	 */
+	public static Example create(Object entity) {
+		if (entity==null) throw new NullPointerException("null example");
+		return new Example(entity, NOT_NULL);
+	}
+
+	protected Example(Object entity, PropertySelector selector) {
+		this.entity = entity;
+		this.selector = selector;
+	}
+
+	public String toString() {
+		return "example (" + entity + ')';
+	}
+
+	private boolean isPropertyIncluded(Object value, String name, Type type) {
+		return !excludedProperties.contains(name) &&
+			!type.isAssociationType() &&
+			selector.include(value, name, type);
+	}
+
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
+		throws HibernateException {
+
+		StringBuffer buf = new StringBuffer().append('(');
+		EntityPersister meta = criteriaQuery.getFactory().getEntityPersister( criteriaQuery.getEntityName(criteria) );
+		String[] propertyNames = meta.getPropertyNames();
+		Type[] propertyTypes = meta.getPropertyTypes();
+		//TODO: get all properties, not just the fetched ones!
+		Object[] propertyValues = meta.getPropertyValues( entity, getEntityMode(criteria, criteriaQuery) );
+		for (int i=0; i<propertyNames.length; i++) {
+			Object propertyValue = propertyValues[i];
+			String propertyName = propertyNames[i];
+
+			boolean isPropertyIncluded = i!=meta.getVersionProperty() &&
+				isPropertyIncluded( propertyValue, propertyName, propertyTypes[i] );
+			if (isPropertyIncluded) {
+				if ( propertyTypes[i].isComponentType() ) {
+					appendComponentCondition(
+						propertyName,
+						propertyValue,
+						(AbstractComponentType) propertyTypes[i],
+						criteria,
+						criteriaQuery,
+						buf
+					);
+				}
+				else {
+					appendPropertyCondition(
+						propertyName,
+						propertyValue,
+						criteria,
+						criteriaQuery,
+						buf
+					);
+				}
+			}
+		}
+		if ( buf.length()==1 ) buf.append("1=1"); //yuck!
+		return buf.append(')').toString();
+	}
+
+	private static final Object[] TYPED_VALUES = new TypedValue[0];
+
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+
+		EntityPersister meta = criteriaQuery.getFactory()
+				.getEntityPersister( criteriaQuery.getEntityName(criteria) );
+		String[] propertyNames = meta.getPropertyNames();
+		Type[] propertyTypes = meta.getPropertyTypes();
+		 //TODO: get all properties, not just the fetched ones!
+		Object[] values = meta.getPropertyValues( entity, getEntityMode(criteria, criteriaQuery) );
+		List list = new ArrayList();
+		for (int i=0; i<propertyNames.length; i++) {
+			Object value = values[i];
+			Type type = propertyTypes[i];
+			String name = propertyNames[i];
+
+			boolean isPropertyIncluded = i!=meta.getVersionProperty() &&
+				isPropertyIncluded(value, name, type);
+
+			if (isPropertyIncluded) {
+				if ( propertyTypes[i].isComponentType() ) {
+					addComponentTypedValues(name, value, (AbstractComponentType) type, list, criteria, criteriaQuery);
+				}
+				else {
+					addPropertyTypedValue(value, type, list);
+				}
+			}
+		}
+		return (TypedValue[]) list.toArray(TYPED_VALUES);
+	}
+	
+	private EntityMode getEntityMode(Criteria criteria, CriteriaQuery criteriaQuery) {
+		EntityPersister meta = criteriaQuery.getFactory()
+				.getEntityPersister( criteriaQuery.getEntityName(criteria) );
+		EntityMode result = meta.guessEntityMode(entity);
+		if (result==null) {
+			throw new ClassCastException( entity.getClass().getName() );
+		}
+		return result;
+	}
+
+	protected void addPropertyTypedValue(Object value, Type type, List list) {
+		if ( value!=null ) {
+			if ( value instanceof String ) {
+				String string = (String) value;
+				if (isIgnoreCaseEnabled) string = string.toLowerCase();
+				if (isLikeEnabled) string = matchMode.toMatchString(string);
+				value = string;
+			}
+			list.add( new TypedValue(type, value, null) );
+		}
+	}
+
+	protected void addComponentTypedValues(
+			String path, 
+			Object component, 
+			AbstractComponentType type, 
+			List list, 
+			Criteria criteria, 
+			CriteriaQuery criteriaQuery)
+	throws HibernateException {
+
+		if (component!=null) {
+			String[] propertyNames = type.getPropertyNames();
+			Type[] subtypes = type.getSubtypes();
+			Object[] values = type.getPropertyValues( component, getEntityMode(criteria, criteriaQuery) );
+			for (int i=0; i<propertyNames.length; i++) {
+				Object value = values[i];
+				Type subtype = subtypes[i];
+				String subpath = StringHelper.qualify( path, propertyNames[i] );
+				if ( isPropertyIncluded(value, subpath, subtype) ) {
+					if ( subtype.isComponentType() ) {
+						addComponentTypedValues(subpath, value, (AbstractComponentType) subtype, list, criteria, criteriaQuery);
+					}
+					else {
+						addPropertyTypedValue(value, subtype, list);
+					}
+				}
+			}
+		}
+	}
+
+	protected void appendPropertyCondition(
+		String propertyName,
+		Object propertyValue,
+		Criteria criteria,
+		CriteriaQuery cq,
+		StringBuffer buf)
+	throws HibernateException {
+		Criterion crit;
+		if ( propertyValue!=null ) {
+			boolean isString = propertyValue instanceof String;
+			if ( isLikeEnabled && isString ) {
+				crit = new LikeExpression(
+						propertyName,
+						( String ) propertyValue,
+						matchMode,
+						escapeCharacter,
+						isIgnoreCaseEnabled
+				);
+			}
+			else {
+				crit = new SimpleExpression( propertyName, propertyValue, "=", isIgnoreCaseEnabled && isString );
+			}
+		}
+		else {
+			crit = new NullExpression(propertyName);
+		}
+		String critCondition = crit.toSqlString(criteria, cq);
+		if ( buf.length()>1 && critCondition.trim().length()>0 ) buf.append(" and ");
+		buf.append(critCondition);
+	}
+
+	protected void appendComponentCondition(
+		String path,
+		Object component,
+		AbstractComponentType type,
+		Criteria criteria,
+		CriteriaQuery criteriaQuery,
+		StringBuffer buf)
+	throws HibernateException {
+
+		if (component!=null) {
+			String[] propertyNames = type.getPropertyNames();
+			Object[] values = type.getPropertyValues( component, getEntityMode(criteria, criteriaQuery) );
+			Type[] subtypes = type.getSubtypes();
+			for (int i=0; i<propertyNames.length; i++) {
+				String subpath = StringHelper.qualify( path, propertyNames[i] );
+				Object value = values[i];
+				if ( isPropertyIncluded( value, subpath, subtypes[i] ) ) {
+					Type subtype = subtypes[i];
+					if ( subtype.isComponentType() ) {
+						appendComponentCondition(
+							subpath,
+							value,
+							(AbstractComponentType) subtype,
+							criteria,
+							criteriaQuery,
+							buf
+						);
+					}
+					else {
+						appendPropertyCondition(
+							subpath,
+							value,
+							criteria,
+							criteriaQuery,
+							buf
+						);
+					}
+				}
+			}
+		}
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/ExistsSubqueryExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/ExistsSubqueryExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/ExistsSubqueryExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+//$Id: ExistsSubqueryExpression.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+
+/**
+ * @author Gavin King
+ */
+public class ExistsSubqueryExpression extends SubqueryExpression {
+
+	protected String toLeftSqlString(Criteria criteria, CriteriaQuery outerQuery) {
+		return "";
+	}
+	
+	protected ExistsSubqueryExpression(String quantifier, DetachedCriteria dc) {
+		super(null, quantifier, dc);
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/ExistsSubqueryExpression.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Expression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Expression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Expression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+//$Id: Expression.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+
+
+/**
+ * This class is semi-deprecated. Use <tt>Restrictions</tt>.
+ *
+ * @see Restrictions
+ * @author Gavin King
+ */
+public final class Expression extends Restrictions {
+
+	private Expression() {
+		//cannot be instantiated
+	}
+
+	/**
+	 * Apply a constraint expressed in SQL, with the given JDBC
+	 * parameters. Any occurrences of <tt>{alias}</tt> will be
+	 * replaced by the table alias.
+	 *
+	 * @param sql
+	 * @param values
+	 * @param types
+	 * @return Criterion
+	 */
+	public static Criterion sql(String sql, Object[] values, Type[] types) {
+		return new SQLCriterion(sql, values, types);
+	}
+	/**
+	 * Apply a constraint expressed in SQL, with the given JDBC
+	 * parameter. Any occurrences of <tt>{alias}</tt> will be replaced
+	 * by the table alias.
+	 *
+	 * @param sql
+	 * @param value
+	 * @param type
+	 * @return Criterion
+	 */
+	public static Criterion sql(String sql, Object value, Type type) {
+		return new SQLCriterion(sql, new Object[] { value }, new Type[] { type } );
+	}
+	/**
+	 * Apply a constraint expressed in SQL. Any occurrences of <tt>{alias}</tt>
+	 * will be replaced by the table alias.
+	 *
+	 * @param sql
+	 * @return Criterion
+	 */
+	public static Criterion sql(String sql) {
+		return new SQLCriterion(sql, ArrayHelper.EMPTY_OBJECT_ARRAY, ArrayHelper.EMPTY_TYPE_ARRAY);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/IdentifierEqExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/IdentifierEqExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/IdentifierEqExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+//$Id: IdentifierEqExpression.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.util.StringHelper;
+
+/**
+ * An identifier constraint
+ * @author Gavin King
+ */
+public class IdentifierEqExpression implements Criterion {
+
+	private final Object value;
+
+	protected IdentifierEqExpression(Object value) {
+		this.value = value;
+	}
+
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+
+		String[] columns = criteriaQuery.getIdentifierColumns(criteria);
+
+		String result = StringHelper.join(
+			" and ",
+			StringHelper.suffix( columns, " = ?" )
+		);
+		if (columns.length>1) result = '(' + result + ')';
+		return result;
+
+		//TODO: get SQL rendering out of this package!
+	}
+
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		return new TypedValue[] { criteriaQuery.getTypedIdentifierValue(criteria, value) };
+	}
+
+	public String toString() {
+		return "id = " + value;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/IdentifierEqExpression.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/IdentifierProjection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/IdentifierProjection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/IdentifierProjection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,61 @@
+//$Id: IdentifierProjection.java 6970 2005-05-31 20:24:41Z oneovthafew $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.type.Type;
+import org.hibernate.util.StringHelper;
+
+/**
+ * A property value, or grouped property value
+ * @author Gavin King
+ */
+public class IdentifierProjection extends SimpleProjection {
+
+	private boolean grouped;
+	
+	protected IdentifierProjection(boolean grouped) {
+		this.grouped = grouped;
+	}
+	
+	protected IdentifierProjection() {
+		this(false);
+	}
+	
+	public String toString() {
+		return "id";
+	}
+
+	public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return new Type[] { criteriaQuery.getIdentifierType(criteria) };
+	}
+
+	public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		StringBuffer buf = new StringBuffer();
+		String[] cols = criteriaQuery.getIdentifierColumns(criteria);
+		for ( int i=0; i<cols.length; i++ ) {
+			buf.append( cols[i] )
+				.append(" as y")
+				.append(position + i)
+				.append('_');
+		}
+		return buf.toString();
+	}
+
+	public boolean isGrouped() {
+		return grouped;
+	}
+	
+	public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		if (!grouped) {
+			return super.toGroupSqlString(criteria, criteriaQuery);
+		}
+		else {
+			return StringHelper.join( ", ", criteriaQuery.getIdentifierColumns(criteria) );
+		}
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/IdentifierProjection.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/IlikeExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/IlikeExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/IlikeExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+//$Id: IlikeExpression.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.PostgreSQLDialect;
+import org.hibernate.engine.TypedValue;
+
+/**
+ * A case-insensitive "like"
+ * @author Gavin King
+ */
+public class IlikeExpression implements Criterion {
+
+	private final String propertyName;
+	private final Object value;
+
+	protected IlikeExpression(String propertyName, Object value) {
+		this.propertyName = propertyName;
+		this.value = value;
+	}
+
+	protected IlikeExpression(String propertyName, String value, MatchMode matchMode) {
+		this( propertyName, matchMode.toMatchString(value) );
+	}
+
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		Dialect dialect = criteriaQuery.getFactory().getDialect();
+		String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);
+		if (columns.length!=1) throw new HibernateException("ilike may only be used with single-column properties");
+		if ( dialect instanceof PostgreSQLDialect ) {
+			return columns[0] + " ilike ?";
+		}
+		else {
+			return dialect.getLowercaseFunction() + '(' + columns[0] + ") like ?";
+		}
+
+		//TODO: get SQL rendering out of this package!
+	}
+
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		return new TypedValue[] { criteriaQuery.getTypedValue( criteria, propertyName, value.toString().toLowerCase() ) };
+	}
+
+	public String toString() {
+		return propertyName + " ilike " + value;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/InExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/InExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/InExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,74 @@
+//$Id: InExpression.java 7557 2005-07-19 23:25:36Z oneovthafew $
+package org.hibernate.criterion;
+
+import java.util.ArrayList;
+
+
+
+import org.hibernate.Criteria;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+
+
+import org.hibernate.engine.TypedValue;
+
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.Type;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Constrains the property to a specified list of values
+ * @author Gavin King
+ */
+public class InExpression implements Criterion {
+
+	private final String propertyName;
+	private final Object[] values;
+
+	protected InExpression(String propertyName, Object[] values) {
+		this.propertyName = propertyName;
+		this.values = values;
+	}
+
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);
+		String singleValueParam = StringHelper.repeat( "?, ", columns.length-1 )  + "?";
+		if ( columns.length>1 ) singleValueParam = '(' + singleValueParam + ')';
+		String params = values.length>0 ?
+			StringHelper.repeat( singleValueParam + ", ", values.length-1 ) + singleValueParam :
+			"";
+		String cols = StringHelper.join(", ", columns);
+		if ( columns.length>1 ) cols = '(' + cols + ')';
+		return cols + " in (" + params + ')';
+	}
+
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		ArrayList list = new ArrayList();
+		Type type = criteriaQuery.getTypeUsingProjection(criteria, propertyName);
+		if ( type.isComponentType() ) {
+			AbstractComponentType actype = (AbstractComponentType) type;
+			Type[] types = actype.getSubtypes();
+			for ( int i=0; i<types.length; i++ ) {
+				for ( int j=0; j<values.length; j++ ) {
+					Object subval = values[j]==null ? 
+						null : 
+						actype.getPropertyValues( values[j], EntityMode.POJO )[i];
+					list.add( new TypedValue( types[i], subval, EntityMode.POJO ) );
+				}
+			}
+		}
+		else {
+			for ( int j=0; j<values.length; j++ ) {
+				list.add( new TypedValue( type, values[j], EntityMode.POJO ) );
+			}
+		}
+		return (TypedValue[]) list.toArray( new TypedValue[ list.size() ] );
+	}
+
+	public String toString() {
+		return propertyName + " in (" + StringHelper.toString(values) + ')';
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Junction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Junction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Junction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,71 @@
+package org.hibernate.criterion;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.util.StringHelper;
+
+/**
+ * A sequence of a logical expressions combined by some
+ * associative logical operator
+ *
+ * @author Gavin King
+ */
+public class Junction implements Criterion {
+
+	private final List criteria = new ArrayList();
+	private final String op;
+	
+	protected Junction(String op) {
+		this.op = op;
+	}
+	
+	public Junction add(Criterion criterion) {
+		criteria.add(criterion);
+		return this;
+	}
+
+	public String getOp() {
+		return op;
+	}
+
+	public TypedValue[] getTypedValues(Criteria crit, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		ArrayList typedValues = new ArrayList();
+		Iterator iter = criteria.iterator();
+		while ( iter.hasNext() ) {
+			TypedValue[] subvalues = ( (Criterion) iter.next() ).getTypedValues(crit, criteriaQuery);
+			for ( int i=0; i<subvalues.length; i++ ) {
+				typedValues.add( subvalues[i] );
+			}
+		}
+		return (TypedValue[]) typedValues.toArray( new TypedValue[ typedValues.size() ] );
+	}
+
+	public String toSqlString(Criteria crit, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+
+		if ( criteria.size()==0 ) return "1=1";
+
+		StringBuffer buffer = new StringBuffer()
+			.append('(');
+		Iterator iter = criteria.iterator();
+		while ( iter.hasNext() ) {
+			buffer.append( ( (Criterion) iter.next() ).toSqlString(crit, criteriaQuery) );
+			if ( iter.hasNext() ) buffer.append(' ').append(op).append(' ');
+		}
+		return buffer.append(')').toString();
+	}
+
+	/**
+	 * @see java.lang.Object#toString()
+	 */
+	public String toString() {
+		return '(' + StringHelper.join( ' ' + op + ' ', criteria.iterator() ) + ')';
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/LikeExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/LikeExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/LikeExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,75 @@
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.TypedValue;
+
+/**
+ * A criterion representing a "like" expression
+ *
+ * @author Scott Marlow
+ * @author Steve Ebersole
+ */
+public class LikeExpression implements Criterion {
+	private final String propertyName;
+	private final Object value;
+	private final Character escapeChar;
+	private final boolean ignoreCase;
+
+	protected LikeExpression(
+			String propertyName,
+			String value,
+			Character escapeChar,
+			boolean ignoreCase) {
+		this.propertyName = propertyName;
+		this.value = value;
+		this.escapeChar = escapeChar;
+		this.ignoreCase = ignoreCase;
+	}
+
+	protected LikeExpression(
+			String propertyName,
+			String value) {
+		this( propertyName, value, null, false );
+	}
+
+	protected LikeExpression(
+			String propertyName,
+			String value,
+			MatchMode matchMode) {
+		this( propertyName, matchMode.toMatchString( value ) );
+	}
+
+	protected LikeExpression(
+			String propertyName,
+			String value,
+			MatchMode matchMode,
+			Character escapeChar,
+			boolean ignoreCase) {
+		this( propertyName, matchMode.toMatchString( value ), escapeChar, ignoreCase );
+	}
+
+	public String toSqlString(
+			Criteria criteria,
+			CriteriaQuery criteriaQuery) throws HibernateException {
+		Dialect dialect = criteriaQuery.getFactory().getDialect();
+		String[] columns = criteriaQuery.getColumnsUsingProjection( criteria, propertyName );
+		if ( columns.length != 1 ) {
+			throw new HibernateException( "Like may only be used with single-column properties" );
+		}
+		String lhs = ignoreCase
+				? dialect.getLowercaseFunction() + '(' + columns[0] + ')'
+	            : columns[0];
+		return lhs + " like ?" + ( escapeChar == null ? "" : " escape \'" + escapeChar + "\'" );
+
+	}
+
+	public TypedValue[] getTypedValues(
+			Criteria criteria,
+			CriteriaQuery criteriaQuery) throws HibernateException {
+		return new TypedValue[] {
+				criteriaQuery.getTypedValue( criteria, propertyName, value.toString().toLowerCase() )
+		};
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/LogicalExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/LogicalExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/LogicalExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+//$Id: LogicalExpression.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.TypedValue;
+
+/**
+ * Superclass of binary logical expressions
+ * @author Gavin King
+ */
+public class LogicalExpression implements Criterion {
+
+	private final Criterion lhs;
+	private final Criterion rhs;
+	private final String op;
+
+	protected LogicalExpression(Criterion lhs, Criterion rhs, String op) {
+		this.lhs = lhs;
+		this.rhs = rhs;
+		this.op = op;
+	}
+
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+
+		TypedValue[] lhstv = lhs.getTypedValues(criteria, criteriaQuery);
+		TypedValue[] rhstv = rhs.getTypedValues(criteria, criteriaQuery);
+		TypedValue[] result = new TypedValue[ lhstv.length + rhstv.length ];
+		System.arraycopy(lhstv, 0, result, 0, lhstv.length);
+		System.arraycopy(rhstv, 0, result, lhstv.length, rhstv.length);
+		return result;
+	}
+
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+
+		return '(' +
+			lhs.toSqlString(criteria, criteriaQuery) +
+			' ' +
+			getOp() +
+			' ' +
+			rhs.toSqlString(criteria, criteriaQuery) +
+			')';
+	}
+
+	public String getOp() {
+		return op;
+	}
+
+	public String toString() {
+		return lhs.toString() + ' ' + getOp() + ' ' + rhs.toString();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/MatchMode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/MatchMode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/MatchMode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,82 @@
+//$Id: MatchMode.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents an strategy for matching strings using "like".
+ *
+ * @see Example#enableLike(MatchMode)
+ * @author Gavin King
+ */
+public abstract class MatchMode implements Serializable {
+	private final String name;
+	private static final Map INSTANCES = new HashMap();
+
+	protected MatchMode(String name) {
+		this.name=name;
+	}
+	public String toString() {
+		return name;
+	}
+
+	/**
+	 * Match the entire string to the pattern
+	 */
+	public static final MatchMode EXACT = new MatchMode("EXACT") {
+		public String toMatchString(String pattern) {
+			return pattern;
+		}
+	};
+
+	/**
+	 * Match the start of the string to the pattern
+	 */
+	public static final MatchMode START = new MatchMode("START") {
+		public String toMatchString(String pattern) {
+			return pattern + '%';
+		}
+	};
+
+	/**
+	 * Match the end of the string to the pattern
+	 */
+	public static final MatchMode END = new MatchMode("END") {
+		public String toMatchString(String pattern) {
+			return '%' + pattern;
+		}
+	};
+
+	/**
+	 * Match the pattern anywhere in the string
+	 */
+	public static final MatchMode ANYWHERE = new MatchMode("ANYWHERE") {
+		public String toMatchString(String pattern) {
+			return '%' + pattern + '%';
+		}
+	};
+
+	static {
+		INSTANCES.put( EXACT.name, EXACT );
+		INSTANCES.put( END.name, END );
+		INSTANCES.put( START.name, START );
+		INSTANCES.put( ANYWHERE.name, ANYWHERE );
+	}
+
+	private Object readResolve() {
+		return INSTANCES.get(name);
+	}
+
+	/**
+	 * convert the pattern, by appending/prepending "%"
+	 */
+	public abstract String toMatchString(String pattern);
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NaturalIdentifier.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NaturalIdentifier.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NaturalIdentifier.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+//$Id: NaturalIdentifier.java 6899 2005-05-25 01:22:07Z oneovthafew $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.TypedValue;
+
+/**
+ * @author Gavin King
+ */
+public class NaturalIdentifier implements Criterion {
+		
+	private Junction conjunction = new Conjunction();
+
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
+		return conjunction.getTypedValues(criteria, criteriaQuery);
+	}
+
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
+		return conjunction.toSqlString(criteria, criteriaQuery);
+	}
+	
+	public NaturalIdentifier set(String property, Object value) {
+		conjunction.add( Restrictions.eq(property, value) );
+		return this;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NaturalIdentifier.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NotEmptyExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NotEmptyExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NotEmptyExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+//$Id: NotEmptyExpression.java 6661 2005-05-03 20:12:20Z steveebersole $
+package org.hibernate.criterion;
+
+/**
+ * @author Gavin King
+ */
+public class NotEmptyExpression extends AbstractEmptinessExpression implements Criterion {
+
+	protected NotEmptyExpression(String propertyName) {
+		super( propertyName );
+	}
+
+	protected boolean excludeEmpty() {
+		return true;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NotEmptyExpression.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NotExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NotExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NotExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+//$Id: NotExpression.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.engine.TypedValue;
+
+/**
+ * Negates another criterion
+ * @author Gavin King
+ */
+public class NotExpression implements Criterion {
+
+	private Criterion criterion;
+
+	protected NotExpression(Criterion criterion) {
+		this.criterion = criterion;
+	}
+
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		if ( criteriaQuery.getFactory().getDialect() instanceof MySQLDialect ) {
+			return "not (" + criterion.toSqlString(criteria, criteriaQuery) + ')';
+		}
+		else {
+			return "not " + criterion.toSqlString(criteria, criteriaQuery);
+		}
+	}
+
+	public TypedValue[] getTypedValues(
+		Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		return criterion.getTypedValues(criteria, criteriaQuery);
+	}
+
+	public String toString() {
+		return "not " + criterion.toString();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NotNullExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NotNullExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NotNullExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+//$Id: NotNullExpression.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Constrains a property to be non-null
+ * @author Gavin King
+ */
+public class NotNullExpression implements Criterion {
+
+	private final String propertyName;
+
+	private static final TypedValue[] NO_VALUES = new TypedValue[0];
+
+	protected NotNullExpression(String propertyName) {
+		this.propertyName = propertyName;
+	}
+
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);
+		String result = StringHelper.join(
+			" or ",
+			StringHelper.suffix( columns, " is not null" )
+		);
+		if (columns.length>1) result = '(' + result + ')';
+		return result;
+
+		//TODO: get SQL rendering out of this package!
+	}
+
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		return NO_VALUES;
+	}
+
+	public String toString() {
+		return propertyName + " is not null";
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NullExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NullExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/NullExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+//$Id: NullExpression.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Constrains a property to be null
+ * @author Gavin King
+ */
+public class NullExpression implements Criterion {
+
+	private final String propertyName;
+
+	private static final TypedValue[] NO_VALUES = new TypedValue[0];
+
+	protected NullExpression(String propertyName) {
+		this.propertyName = propertyName;
+	}
+
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);
+		String result = StringHelper.join(
+			" and ",
+			StringHelper.suffix( columns, " is null" )
+		);
+		if (columns.length>1) result = '(' + result + ')';
+		return result;
+
+		//TODO: get SQL rendering out of this package!
+	}
+
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return NO_VALUES;
+	}
+
+	public String toString() {
+		return propertyName + " is null";
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Order.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Order.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Order.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,83 @@
+//$Id: Order.java 7495 2005-07-15 16:52:10Z oneovthafew $
+package org.hibernate.criterion;
+
+import java.io.Serializable;
+import java.sql.Types;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Represents an order imposed upon a <tt>Criteria</tt> result set
+ * @author Gavin King
+ */
+public class Order implements Serializable {
+
+	private boolean ascending;
+	private boolean ignoreCase;
+	private String propertyName;
+	
+	public String toString() {
+		return propertyName + ' ' + (ascending?"asc":"desc");
+	}
+	
+	public Order ignoreCase() {
+		ignoreCase = true;
+		return this;
+	}
+
+	/**
+	 * Constructor for Order.
+	 */
+	protected Order(String propertyName, boolean ascending) {
+		this.propertyName = propertyName;
+		this.ascending = ascending;
+	}
+
+	/**
+	 * Render the SQL fragment
+	 *
+	 */
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);
+		Type type = criteriaQuery.getTypeUsingProjection(criteria, propertyName);
+		StringBuffer fragment = new StringBuffer();
+		for ( int i=0; i<columns.length; i++ ) {
+			SessionFactoryImplementor factory = criteriaQuery.getFactory();
+			boolean lower = ignoreCase && type.sqlTypes( factory )[i]==Types.VARCHAR;
+			if (lower) {
+				fragment.append( factory.getDialect().getLowercaseFunction() )
+					.append('(');
+			}
+			fragment.append( columns[i] );
+			if (lower) fragment.append(')');
+			fragment.append( ascending ? " asc" : " desc" );
+			if ( i<columns.length-1 ) fragment.append(", ");
+		}
+		return fragment.toString();
+	}
+
+	/**
+	 * Ascending order
+	 *
+	 * @param propertyName
+	 * @return Order
+	 */
+	public static Order asc(String propertyName) {
+		return new Order(propertyName, true);
+	}
+
+	/**
+	 * Descending order
+	 *
+	 * @param propertyName
+	 * @return Order
+	 */
+	public static Order desc(String propertyName) {
+		return new Order(propertyName, false);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Projection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Projection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Projection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,81 @@
+//$Id: Projection.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+
+import java.io.Serializable;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.type.Type;
+
+/**
+ * An object-oriented representation of a query result set projection 
+ * in a <tt>Criteria</tt> query. Built-in projection types are provided 
+ * by the <tt>Projections</tt> factory class.
+ * This interface might be implemented by application classes that
+ * define custom projections.
+ *
+ * @see Projections
+ * @see org.hibernate.Criteria
+ * @author Gavin King
+ */
+public interface Projection extends Serializable {
+
+	/**
+	 * Render the SQL fragment
+	 * @param criteriaQuery
+	 * @param columnAlias
+	 * @return String
+	 * @throws HibernateException
+	 */
+	public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) 
+	throws HibernateException;
+	
+	/**
+	 * Render the SQL fragment to be used in the group by clause
+	 * @param criteriaQuery
+	 * @param columnAlias
+	 * @return String
+	 * @throws HibernateException
+	 */
+	public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException;
+	
+	/**
+	 * Return types returned by the rendered SQL fragment
+	 * @param criteria
+	 * @param criteriaQuery 
+	 * @return Type[]
+	 * @throws HibernateException
+	 */
+	public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException;
+	/**
+	 * Return types for a particular user-visible alias
+	 */
+	public Type[] getTypes(String alias, Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException;
+		
+	/**
+	 * Get the SQL select clause column aliases
+	 */
+	public String[] getColumnAliases(int loc);
+	/**
+	 * Get the SQL select clause column aliases for a particular
+	 * user-visible alias
+	 */
+	public String[] getColumnAliases(String alias, int loc);
+	
+	/**
+	 * Get the user-visible aliases for this projection
+	 * (ie. the ones that will be passed to the 
+	 * <tt>ResultTransformer</tt>)
+	 */
+	public String[] getAliases();
+	
+	/**
+	 * Does this projection specify grouping attributes?
+	 */
+	public boolean isGrouped();
+	
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Projection.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/ProjectionList.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/ProjectionList.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/ProjectionList.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,125 @@
+//$Id: ProjectionList.java 6490 2005-04-23 07:09:03Z oneovthafew $
+package org.hibernate.criterion;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * @author Gavin King
+ */
+public class ProjectionList implements Projection {
+	
+	private List elements = new ArrayList();
+	
+	protected ProjectionList() {}
+	
+	public ProjectionList create() {
+		return new ProjectionList();
+	}
+	
+	public ProjectionList add(Projection proj) {
+		elements.add(proj);
+		return this;
+	}
+
+	public ProjectionList add(Projection projection, String alias) {
+		return add( Projections.alias(projection, alias) );
+	}
+
+	public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		List types = new ArrayList( getLength() );
+		for ( int i=0; i<getLength(); i++ ) {
+			Type[] elemTypes = getProjection(i).getTypes(criteria, criteriaQuery);
+			ArrayHelper.addAll(types, elemTypes);
+		}
+		return ArrayHelper.toTypeArray(types);
+	}
+	
+	public String toSqlString(Criteria criteria, int loc, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		StringBuffer buf = new StringBuffer();
+		for ( int i=0; i<getLength(); i++ ) {
+			Projection proj = getProjection(i);
+			buf.append( proj.toSqlString(criteria, loc, criteriaQuery) );
+			loc += proj.getColumnAliases(loc).length;
+			if ( i<elements.size()-1 ) buf.append(", ");
+		}
+		return buf.toString();
+	}
+	
+	public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		StringBuffer buf = new StringBuffer();
+		for ( int i=0; i<getLength(); i++ ) {
+			Projection proj = getProjection(i);
+			if ( proj.isGrouped() ) {
+				buf.append( proj.toGroupSqlString(criteria, criteriaQuery) )
+					.append(", ");
+			}
+		}
+		if ( buf.length()>2 ) buf.setLength( buf.length()-2 ); //pull off the last ", "
+		return buf.toString();
+	}
+	
+	public String[] getColumnAliases(int loc) {
+		List result = new ArrayList( getLength() );
+		for ( int i=0; i<getLength(); i++ ) {
+			String[] colAliases = getProjection(i).getColumnAliases(loc);
+			ArrayHelper.addAll(result, colAliases);
+			loc+=colAliases.length;
+		}
+		return ArrayHelper.toStringArray(result);
+	}
+
+	public String[] getColumnAliases(String alias, int loc) {
+		for ( int i=0; i<getLength(); i++ ) {
+			String[] result = getProjection(i).getColumnAliases(alias, loc);
+			if (result!=null) return result;
+			loc += getProjection(i).getColumnAliases(loc).length;
+		}
+		return null;
+	}
+
+	public Type[] getTypes(String alias, Criteria criteria, CriteriaQuery criteriaQuery) {
+		for ( int i=0; i<getLength(); i++ ) {
+			Type[] result = getProjection(i).getTypes(alias, criteria, criteriaQuery);
+			if (result!=null) return result;
+		}
+		return null;
+	}
+
+	public String[] getAliases() {
+		List result = new ArrayList( getLength() );
+		for ( int i=0; i<getLength(); i++ ) {
+			String[] aliases = getProjection(i).getAliases();
+			ArrayHelper.addAll(result, aliases);
+		}
+		return ArrayHelper.toStringArray(result);
+
+	}
+	
+	public Projection getProjection(int i) {
+		return (Projection) elements.get(i);
+	}
+	
+	public int getLength() {
+		return elements.size();
+	}
+	
+	public String toString() {
+		return elements.toString();
+	}
+
+	public boolean isGrouped() {
+		for ( int i=0; i<getLength(); i++ ) {
+			if ( getProjection(i).isGrouped() ) return true;
+		}
+		return false;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/ProjectionList.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Projections.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Projections.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Projections.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,128 @@
+//$Id: Projections.java 6970 2005-05-31 20:24:41Z oneovthafew $
+package org.hibernate.criterion;
+
+import org.hibernate.type.Type;
+
+/**
+ * The <tt>criterion</tt> package may be used by applications as a framework for building
+ * new kinds of <tt>Projection</tt>. However, it is intended that most applications will
+ * simply use the built-in projection types via the static factory methods of this class.<br/>
+ * <br/>
+ * The factory methods that take an alias allow the projected value to be referred to by 
+ * criterion and order instances.
+ *
+ * @see org.hibernate.Criteria
+ * @see Restrictions factory methods for <tt>Criterion</tt> instances
+ * @author Gavin King
+ */
+public final class Projections {
+
+	private Projections() {
+		//cannot be instantiated
+	}
+	
+	/**
+	 * Create a distinct projection from a projection
+	 */
+	public static Projection distinct(Projection proj) {
+		return new Distinct(proj);
+	}
+	
+	/**
+	 * Create a new projection list
+	 */
+	public static ProjectionList projectionList() {
+		return new ProjectionList();
+	}
+		
+	/**
+	 * The query row count, ie. <tt>count(*)</tt>
+	 */
+	public static Projection rowCount() {
+		return new RowCountProjection();
+	}
+	
+	/**
+	 * A property value count
+	 */
+	public static CountProjection count(String propertyName) {
+		return new CountProjection(propertyName);
+	}
+	
+	/**
+	 * A distinct property value count
+	 */
+	public static CountProjection countDistinct(String propertyName) {
+		return new CountProjection(propertyName).setDistinct();
+	}
+	
+	/**
+	 * A property maximum value
+	 */
+	public static AggregateProjection max(String propertyName) {
+		return new AggregateProjection("max", propertyName);
+	}
+	
+	/**
+	 * A property minimum value
+	 */
+	public static AggregateProjection min(String propertyName) {
+		return new AggregateProjection("min", propertyName);
+	}
+	
+	/**
+	 * A property average value
+	 */
+	public static AggregateProjection avg(String propertyName) {
+		return new AvgProjection(propertyName);
+	}
+	
+	/**
+	 * A property value sum
+	 */
+	public static AggregateProjection sum(String propertyName) {
+		return new AggregateProjection("sum", propertyName);
+	}
+	
+	/**
+	 * A SQL projection, a typed select clause fragment
+	 */
+	public static Projection sqlProjection(String sql, String[] columnAliases, Type[] types) {
+		return new SQLProjection(sql, columnAliases, types);
+	}
+	
+	/**
+	 * A grouping SQL projection, specifying both select clause and group by clause fragments
+	 */
+	public static Projection sqlGroupProjection(String sql, String groupBy, String[] columnAliases, Type[] types) {
+		return new SQLProjection(sql, groupBy, columnAliases, types);
+	}
+
+	/**
+	 * A grouping property value
+	 */
+	public static PropertyProjection groupProperty(String propertyName) {
+		return new PropertyProjection(propertyName, true);
+	}
+	
+	/**
+	 * A projected property value
+	 */
+	public static PropertyProjection property(String propertyName) {
+		return new PropertyProjection(propertyName);
+	}
+	
+	/**
+	 * A projected identifier value
+	 */
+	public static IdentifierProjection id() {
+		return new IdentifierProjection();
+	}
+	
+	/**
+	 * Assign an alias to a projection, by wrapping it
+	 */
+	public static Projection alias(Projection projection, String alias) {
+		return new AliasedProjection(projection, alias);
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Projections.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Property.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Property.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Property.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,235 @@
+//$Id: Property.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+import java.util.Collection;
+
+/**
+ * A factory for property-specific criterion and projection instances
+ * @author Gavin King
+ */
+public class Property extends PropertyProjection {
+	//private String propertyName;
+	protected Property(String propertyName) {
+		super(propertyName);
+	}
+
+	public Criterion between(Object min, Object max) {
+		return Restrictions.between(getPropertyName(), min, max);
+	}
+
+	public Criterion in(Collection values) {
+		return Restrictions.in(getPropertyName(), values);
+	}
+
+	public Criterion in(Object[] values) {
+		return Restrictions.in(getPropertyName(), values);
+	}
+
+	public SimpleExpression like(Object value) {
+		return Restrictions.like(getPropertyName(), value);
+	}
+
+	public SimpleExpression like(String value, MatchMode matchMode) {
+		return Restrictions.like(getPropertyName(), value, matchMode);
+	}
+
+	public SimpleExpression eq(Object value) {
+		return Restrictions.eq(getPropertyName(), value);
+	}
+
+	public SimpleExpression ne(Object value) {
+		return Restrictions.ne(getPropertyName(), value);
+	}
+
+	public SimpleExpression gt(Object value) {
+		return Restrictions.gt(getPropertyName(), value);
+	}
+
+	public SimpleExpression lt(Object value) {
+		return Restrictions.lt(getPropertyName(), value);
+	}
+
+	public SimpleExpression le(Object value) {
+		return Restrictions.le(getPropertyName(), value);
+	}
+
+	public SimpleExpression ge(Object value) {
+		return Restrictions.ge(getPropertyName(), value);
+	}
+
+	public PropertyExpression eqProperty(Property other) {
+		return Restrictions.eqProperty( getPropertyName(), other.getPropertyName() );
+	}
+
+	public PropertyExpression neProperty(Property other) {
+		return Restrictions.neProperty( getPropertyName(), other.getPropertyName() );
+	}
+	
+	public PropertyExpression leProperty(Property other) {
+		return Restrictions.leProperty( getPropertyName(), other.getPropertyName() );
+	}
+
+	public PropertyExpression geProperty(Property other) {
+		return Restrictions.geProperty( getPropertyName(), other.getPropertyName() );
+	}
+	
+	public PropertyExpression ltProperty(Property other) {
+		return Restrictions.ltProperty( getPropertyName(), other.getPropertyName() );
+	}
+
+	public PropertyExpression gtProperty(Property other) {
+		return Restrictions.gtProperty( getPropertyName(), other.getPropertyName() );
+	}
+	
+	public PropertyExpression eqProperty(String other) {
+		return Restrictions.eqProperty( getPropertyName(), other );
+	}
+
+	public PropertyExpression neProperty(String other) {
+		return Restrictions.neProperty( getPropertyName(), other );
+	}
+	
+	public PropertyExpression leProperty(String other) {
+		return Restrictions.leProperty( getPropertyName(), other );
+	}
+
+	public PropertyExpression geProperty(String other) {
+		return Restrictions.geProperty( getPropertyName(), other );
+	}
+	
+	public PropertyExpression ltProperty(String other) {
+		return Restrictions.ltProperty( getPropertyName(), other );
+	}
+
+	public PropertyExpression gtProperty(String other) {
+		return Restrictions.gtProperty( getPropertyName(), other );
+	}
+	
+	public Criterion isNull() {
+		return Restrictions.isNull(getPropertyName());
+	}
+
+	public Criterion isNotNull() {
+		return Restrictions.isNotNull(getPropertyName());
+	}
+
+	public Criterion isEmpty() {
+		return Restrictions.isEmpty(getPropertyName());
+	}
+
+	public Criterion isNotEmpty() {
+		return Restrictions.isNotEmpty(getPropertyName());
+	}
+	
+	public CountProjection count() {
+		return Projections.count(getPropertyName());
+	}
+	
+	public AggregateProjection max() {
+		return Projections.max(getPropertyName());
+	}
+
+	public AggregateProjection min() {
+		return Projections.min(getPropertyName());
+	}
+
+	public AggregateProjection avg() {
+		return Projections.avg(getPropertyName());
+	}
+	
+	/*public PropertyProjection project() {
+		return Projections.property(getPropertyName());
+	}*/
+
+	public PropertyProjection group() {
+		return Projections.groupProperty(getPropertyName());
+	}
+	
+	public Order asc() {
+		return Order.asc(getPropertyName());
+	}
+
+	public Order desc() {
+		return Order.desc(getPropertyName());
+	}
+
+	public static Property forName(String propertyName) {
+		return new Property(propertyName);
+	}
+	
+	/**
+	 * Get a component attribute of this property
+	 */
+	public Property getProperty(String propertyName) {
+		return forName( getPropertyName() + '.' + propertyName );
+	}
+	
+	public Criterion eq(DetachedCriteria subselect) {
+		return Subqueries.propertyEq( getPropertyName(), subselect );
+	}
+
+	public Criterion ne(DetachedCriteria subselect) {
+		return Subqueries.propertyNe( getPropertyName(), subselect );
+	}
+
+	public Criterion lt(DetachedCriteria subselect) {
+		return Subqueries.propertyLt( getPropertyName(), subselect );
+	}
+
+	public Criterion le(DetachedCriteria subselect) {
+		return Subqueries.propertyLe( getPropertyName(), subselect );
+	}
+
+	public Criterion gt(DetachedCriteria subselect) {
+		return Subqueries.propertyGt( getPropertyName(), subselect );
+	}
+
+	public Criterion ge(DetachedCriteria subselect) {
+		return Subqueries.propertyGe( getPropertyName(), subselect );
+	}
+
+	public Criterion notIn(DetachedCriteria subselect) {
+		return Subqueries.propertyNotIn( getPropertyName(), subselect );
+	}
+
+	public Criterion in(DetachedCriteria subselect) {
+		return Subqueries.propertyIn( getPropertyName(), subselect );
+	}
+
+	public Criterion eqAll(DetachedCriteria subselect) {
+		return Subqueries.propertyEqAll( getPropertyName(), subselect );
+	}
+
+	public Criterion gtAll(DetachedCriteria subselect) {
+		return Subqueries.propertyGtAll( getPropertyName(), subselect );
+	}
+
+	public Criterion ltAll(DetachedCriteria subselect) {
+		return Subqueries.propertyLtAll( getPropertyName(), subselect );
+	}
+
+	public Criterion leAll(DetachedCriteria subselect) {
+		return Subqueries.propertyLeAll( getPropertyName(), subselect );
+	}
+
+	public Criterion geAll(DetachedCriteria subselect) {
+		return Subqueries.propertyGeAll( getPropertyName(), subselect );
+	}
+
+	public Criterion gtSome(DetachedCriteria subselect) {
+		return Subqueries.propertyGtSome( getPropertyName(), subselect );
+	}
+
+	public Criterion ltSome(DetachedCriteria subselect) {
+		return Subqueries.propertyLtSome( getPropertyName(), subselect );
+	}
+
+	public Criterion leSome(DetachedCriteria subselect) {
+		return Subqueries.propertyLeSome( getPropertyName(), subselect );
+	}
+
+	public Criterion geSome(DetachedCriteria subselect) {
+		return Subqueries.propertyGeSome( getPropertyName(), subselect );
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Property.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/PropertyExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/PropertyExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/PropertyExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+//$Id: PropertyExpression.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.util.StringHelper;
+
+/**
+ * superclass for comparisons between two properties (with SQL binary operators)
+ * @author Gavin King
+ */
+public class PropertyExpression implements Criterion {
+
+	private final String propertyName;
+	private final String otherPropertyName;
+	private final String op;
+
+	private static final TypedValue[] NO_TYPED_VALUES = new TypedValue[0];
+
+	protected PropertyExpression(String propertyName, String otherPropertyName, String op) {
+		this.propertyName = propertyName;
+		this.otherPropertyName = otherPropertyName;
+		this.op = op;
+	}
+
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		String[] xcols = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);
+		String[] ycols = criteriaQuery.getColumnsUsingProjection(criteria, otherPropertyName);
+		String result = StringHelper.join(
+			" and ",
+			StringHelper.add(xcols, getOp(), ycols)
+		);
+		if (xcols.length>1) result = '(' + result + ')';
+		return result;
+		//TODO: get SQL rendering out of this package!
+	}
+
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return NO_TYPED_VALUES;
+	}
+
+	public String toString() {
+		return propertyName + getOp() + otherPropertyName;
+	}
+
+	public String getOp() {
+		return op;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/PropertyProjection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/PropertyProjection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/PropertyProjection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+//$Id: PropertyProjection.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.type.Type;
+
+/**
+ * A property value, or grouped property value
+ * @author Gavin King
+ */
+public class PropertyProjection extends SimpleProjection {
+
+	private String propertyName;
+	private boolean grouped;
+	
+	protected PropertyProjection(String prop, boolean grouped) {
+		this.propertyName = prop;
+		this.grouped = grouped;
+	}
+	
+	protected PropertyProjection(String prop) {
+		this(prop, false);
+	}
+
+	public String getPropertyName() {
+		return propertyName;
+	}
+	
+	public String toString() {
+		return propertyName;
+	}
+
+	public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return new Type[] { criteriaQuery.getType(criteria, propertyName) };
+	}
+
+	public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return new StringBuffer()
+			.append( criteriaQuery.getColumn(criteria, propertyName) )
+			.append(" as y")
+			.append(position)
+			.append('_')
+			.toString();
+	}
+
+	public boolean isGrouped() {
+		return grouped;
+	}
+	
+	public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		if (!grouped) {
+			return super.toGroupSqlString(criteria, criteriaQuery);
+		}
+		else {
+			return criteriaQuery.getColumn(criteria, propertyName);
+		}
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/PropertyProjection.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/PropertySubqueryExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/PropertySubqueryExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/PropertySubqueryExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+//$Id: PropertySubqueryExpression.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+
+/**
+ * A comparison between a property value in the outer query and the
+ * result of a subquery
+ * @author Gavin King
+ */
+public class PropertySubqueryExpression extends SubqueryExpression {
+	private String propertyName;
+
+	protected PropertySubqueryExpression(String propertyName, String op, String quantifier, DetachedCriteria dc) {
+		super(op, quantifier, dc);
+		this.propertyName = propertyName;
+	}
+
+	protected String toLeftSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
+		return criteriaQuery.getColumn(criteria, propertyName);
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/PropertySubqueryExpression.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Restrictions.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Restrictions.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Restrictions.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,368 @@
+//$Id: Restrictions.java 7844 2005-08-11 07:26:26Z oneovthafew $
+package org.hibernate.criterion;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * The <tt>criterion</tt> package may be used by applications as a framework for building
+ * new kinds of <tt>Criterion</tt>. However, it is intended that most applications will
+ * simply use the built-in criterion types via the static factory methods of this class.
+ *
+ * @see org.hibernate.Criteria
+ * @see Projections factory methods for <tt>Projection</tt> instances
+ * @author Gavin King
+ */
+public class Restrictions {
+
+	Restrictions() {
+		//cannot be instantiated
+	}
+
+	/**
+	 * Apply an "equal" constraint to the identifier property
+	 * @param propertyName
+	 * @param value
+	 * @return Criterion
+	 */
+	public static Criterion idEq(Object value) {
+		return new IdentifierEqExpression(value);
+	}
+	/**
+	 * Apply an "equal" constraint to the named property
+	 * @param propertyName
+	 * @param value
+	 * @return Criterion
+	 */
+	public static SimpleExpression eq(String propertyName, Object value) {
+		return new SimpleExpression(propertyName, value, "=");
+	}
+	/**
+	 * Apply a "not equal" constraint to the named property
+	 * @param propertyName
+	 * @param value
+	 * @return Criterion
+	 */
+	public static SimpleExpression ne(String propertyName, Object value) {
+		return new SimpleExpression(propertyName, value, "<>");
+	}
+	/**
+	 * Apply a "like" constraint to the named property
+	 * @param propertyName
+	 * @param value
+	 * @return Criterion
+	 */
+	public static SimpleExpression like(String propertyName, Object value) {
+		return new SimpleExpression(propertyName, value, " like ");
+	}
+	/**
+	 * Apply a "like" constraint to the named property
+	 * @param propertyName
+	 * @param value
+	 * @return Criterion
+	 */
+	public static SimpleExpression like(String propertyName, String value, MatchMode matchMode) {
+		return new SimpleExpression(propertyName, matchMode.toMatchString(value), " like " );
+	}
+	/**
+	 * A case-insensitive "like", similar to Postgres <tt>ilike</tt>
+	 * operator
+	 *
+	 * @param propertyName
+	 * @param value
+	 * @return Criterion
+	 */
+	public static Criterion ilike(String propertyName, String value, MatchMode matchMode) {
+		return new IlikeExpression(propertyName, value, matchMode);
+	}
+	/**
+	 * A case-insensitive "like", similar to Postgres <tt>ilike</tt>
+	 * operator
+	 *
+	 * @param propertyName
+	 * @param value
+	 * @return Criterion
+	 */
+	public static Criterion ilike(String propertyName, Object value) {
+		return new IlikeExpression(propertyName, value);
+	}
+	/**
+	 * Apply a "greater than" constraint to the named property
+	 * @param propertyName
+	 * @param value
+	 * @return Criterion
+	 */
+	public static SimpleExpression gt(String propertyName, Object value) {
+		return new SimpleExpression(propertyName, value, ">");
+	}
+	/**
+	 * Apply a "less than" constraint to the named property
+	 * @param propertyName
+	 * @param value
+	 * @return Criterion
+	 */
+	public static SimpleExpression lt(String propertyName, Object value) {
+		return new SimpleExpression(propertyName, value, "<");
+	}
+	/**
+	 * Apply a "less than or equal" constraint to the named property
+	 * @param propertyName
+	 * @param value
+	 * @return Criterion
+	 */
+	public static SimpleExpression le(String propertyName, Object value) {
+		return new SimpleExpression(propertyName, value, "<=");
+	}
+	/**
+	 * Apply a "greater than or equal" constraint to the named property
+	 * @param propertyName
+	 * @param value
+	 * @return Criterion
+	 */
+	public static SimpleExpression ge(String propertyName, Object value) {
+		return new SimpleExpression(propertyName, value, ">=");
+	}
+	/**
+	 * Apply a "between" constraint to the named property
+	 * @param propertyName
+	 * @param lo value
+	 * @param hi value
+	 * @return Criterion
+	 */
+	public static Criterion between(String propertyName, Object lo, Object hi) {
+		return new BetweenExpression(propertyName, lo, hi);
+	}
+	/**
+	 * Apply an "in" constraint to the named property
+	 * @param propertyName
+	 * @param values
+	 * @return Criterion
+	 */
+	public static Criterion in(String propertyName, Object[] values) {
+		return new InExpression(propertyName, values);
+	}
+	/**
+	 * Apply an "in" constraint to the named property
+	 * @param propertyName
+	 * @param values
+	 * @return Criterion
+	 */
+	public static Criterion in(String propertyName, Collection values) {
+		return new InExpression( propertyName, values.toArray() );
+	}
+	/**
+	 * Apply an "is null" constraint to the named property
+	 * @return Criterion
+	 */
+	public static Criterion isNull(String propertyName) {
+		return new NullExpression(propertyName);
+	}
+	/**
+	 * Apply an "equal" constraint to two properties
+	 */
+	public static PropertyExpression eqProperty(String propertyName, String otherPropertyName) {
+		return new PropertyExpression(propertyName, otherPropertyName, "=");
+	}
+	/**
+	 * Apply a "not equal" constraint to two properties
+	 */
+	public static PropertyExpression neProperty(String propertyName, String otherPropertyName) {
+		return new PropertyExpression(propertyName, otherPropertyName, "<>");
+	}
+	/**
+	 * Apply a "less than" constraint to two properties
+	 */
+	public static PropertyExpression ltProperty(String propertyName, String otherPropertyName) {
+		return new PropertyExpression(propertyName, otherPropertyName, "<");
+	}
+	/**
+	 * Apply a "less than or equal" constraint to two properties
+	 */
+	public static PropertyExpression leProperty(String propertyName, String otherPropertyName) {
+		return new PropertyExpression(propertyName, otherPropertyName, "<=");
+	}
+	/**
+	 * Apply a "greater than" constraint to two properties
+	 */
+	public static PropertyExpression gtProperty(String propertyName, String otherPropertyName) {
+		return new PropertyExpression(propertyName, otherPropertyName, ">");
+	}
+	/**
+	 * Apply a "greater than or equal" constraint to two properties
+	 */
+	public static PropertyExpression geProperty(String propertyName, String otherPropertyName) {
+		return new PropertyExpression(propertyName, otherPropertyName, ">=");
+	}
+	/**
+	 * Apply an "is not null" constraint to the named property
+	 * @return Criterion
+	 */
+	public static Criterion isNotNull(String propertyName) {
+		return new NotNullExpression(propertyName);
+	}
+	/**
+	 * Return the conjuction of two expressions
+	 *
+	 * @param lhs
+	 * @param rhs
+	 * @return Criterion
+	 */
+	public static LogicalExpression and(Criterion lhs, Criterion rhs) {
+		return new LogicalExpression(lhs, rhs, "and");
+	}
+	/**
+	 * Return the disjuction of two expressions
+	 *
+	 * @param lhs
+	 * @param rhs
+	 * @return Criterion
+	 */
+	public static LogicalExpression or(Criterion lhs, Criterion rhs) {
+		return new LogicalExpression(lhs, rhs, "or");
+	}
+	/**
+	 * Return the negation of an expression
+	 *
+	 * @param expression
+	 * @return Criterion
+	 */
+	public static Criterion not(Criterion expression) {
+		return new NotExpression(expression);
+	}
+	/**
+	 * Apply a constraint expressed in SQL, with the given JDBC
+	 * parameters. Any occurrences of <tt>{alias}</tt> will be
+	 * replaced by the table alias.
+	 *
+	 * @param sql
+	 * @param values
+	 * @param types
+	 * @return Criterion
+	 */
+	public static Criterion sqlRestriction(String sql, Object[] values, Type[] types) {
+		return new SQLCriterion(sql, values, types);
+	}
+	/**
+	 * Apply a constraint expressed in SQL, with the given JDBC
+	 * parameter. Any occurrences of <tt>{alias}</tt> will be replaced
+	 * by the table alias.
+	 *
+	 * @param sql
+	 * @param value
+	 * @param type
+	 * @return Criterion
+	 */
+	public static Criterion sqlRestriction(String sql, Object value, Type type) {
+		return new SQLCriterion(sql, new Object[] { value }, new Type[] { type } );
+	}
+	/**
+	 * Apply a constraint expressed in SQL. Any occurrences of <tt>{alias}</tt>
+	 * will be replaced by the table alias.
+	 *
+	 * @param sql
+	 * @return Criterion
+	 */
+	public static Criterion sqlRestriction(String sql) {
+		return new SQLCriterion(sql, ArrayHelper.EMPTY_OBJECT_ARRAY, ArrayHelper.EMPTY_TYPE_ARRAY);
+	}
+
+	/**
+	 * Group expressions together in a single conjunction (A and B and C...)
+	 *
+	 * @return Conjunction
+	 */
+	public static Conjunction conjunction() {
+		return new Conjunction();
+	}
+
+	/**
+	 * Group expressions together in a single disjunction (A or B or C...)
+	 *
+	 * @return Conjunction
+	 */
+	public static Disjunction disjunction() {
+		return new Disjunction();
+	}
+
+	/**
+	 * Apply an "equals" constraint to each property in the
+	 * key set of a <tt>Map</tt>
+	 *
+	 * @param propertyNameValues a map from property names to values
+	 * @return Criterion
+	 */
+	public static Criterion allEq(Map propertyNameValues) {
+		Conjunction conj = conjunction();
+		Iterator iter = propertyNameValues.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			conj.add( eq( (String) me.getKey(), me.getValue() ) );
+		}
+		return conj;
+	}
+	
+	/**
+	 * Constrain a collection valued property to be empty
+	 */
+	public static Criterion isEmpty(String propertyName) {
+		return new EmptyExpression(propertyName);
+	}
+
+	/**
+	 * Constrain a collection valued property to be non-empty
+	 */
+	public static Criterion isNotEmpty(String propertyName) {
+		return new NotEmptyExpression(propertyName);
+	}
+	
+	/**
+	 * Constrain a collection valued property by size
+	 */
+	public static Criterion sizeEq(String propertyName, int size) {
+		return new SizeExpression(propertyName, size, "=");
+	}
+	
+	/**
+	 * Constrain a collection valued property by size
+	 */
+	public static Criterion sizeNe(String propertyName, int size) {
+		return new SizeExpression(propertyName, size, "<>");
+	}
+	
+	/**
+	 * Constrain a collection valued property by size
+	 */
+	public static Criterion sizeGt(String propertyName, int size) {
+		return new SizeExpression(propertyName, size, "<");
+	}
+	
+	/**
+	 * Constrain a collection valued property by size
+	 */
+	public static Criterion sizeLt(String propertyName, int size) {
+		return new SizeExpression(propertyName, size, ">");
+	}
+	
+	/**
+	 * Constrain a collection valued property by size
+	 */
+	public static Criterion sizeGe(String propertyName, int size) {
+		return new SizeExpression(propertyName, size, "<=");
+	}
+	
+	/**
+	 * Constrain a collection valued property by size
+	 */
+	public static Criterion sizeLe(String propertyName, int size) {
+		return new SizeExpression(propertyName, size, ">=");
+	}
+	
+	public static NaturalIdentifier naturalId() {
+		return new NaturalIdentifier();
+	}
+		
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Restrictions.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/RowCountProjection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/RowCountProjection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/RowCountProjection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: RowCountProjection.java 9908 2006-05-08 20:59:20Z max.andersen at jboss.com $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.type.Type;
+
+/**
+ * A row count
+ * @author Gavin King
+ */
+public class RowCountProjection extends SimpleProjection {
+
+	protected RowCountProjection() {}
+
+	public String toString() {
+		return "count(*)";
+	}
+
+	public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return new Type[] { Hibernate.INTEGER };
+	}
+
+	public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return new StringBuffer()
+			.append("count(*) as y")
+			.append(position)
+			.append('_')
+			.toString();
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/RowCountProjection.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SQLCriterion.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SQLCriterion.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SQLCriterion.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: SQLCriterion.java 5757 2005-02-18 03:47:27Z oneovthafew $
+package org.hibernate.criterion;
+
+
+import org.hibernate.Criteria;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.type.Type;
+import org.hibernate.util.StringHelper;
+
+/**
+ * A SQL fragment. The string {alias} will be replaced by the
+ * alias of the root entity.
+ */
+public class SQLCriterion implements Criterion {
+
+	private final String sql;
+	private final TypedValue[] typedValues;
+
+	public String toSqlString(
+		Criteria criteria,
+		CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		return StringHelper.replace( sql, "{alias}", criteriaQuery.getSQLAlias(criteria) );
+	}
+
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		return typedValues;
+	}
+
+	public String toString() {
+		return sql;
+	}
+
+	protected SQLCriterion(String sql, Object[] values, Type[] types) {
+		this.sql = sql;
+		typedValues = new TypedValue[values.length];
+		for ( int i=0; i<typedValues.length; i++ ) {
+			typedValues[i] = new TypedValue( types[i], values[i], EntityMode.POJO );
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SQLProjection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SQLProjection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SQLProjection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,77 @@
+//$Id: SQLProjection.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.type.Type;
+import org.hibernate.util.StringHelper;
+
+/**
+ * A SQL fragment. The string {alias} will be replaced by the
+ * alias of the root entity.
+ */
+public class SQLProjection implements Projection {
+
+	private final String sql;
+	private final String groupBy;
+	private final Type[] types;
+	private String[] aliases;
+	private String[] columnAliases;
+	private boolean grouped;
+
+	public String toSqlString(
+			Criteria criteria, 
+			int loc, 
+			CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		return StringHelper.replace( sql, "{alias}", criteriaQuery.getSQLAlias(criteria) );
+	}
+
+	public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		return StringHelper.replace( groupBy, "{alias}", criteriaQuery.getSQLAlias(criteria) );
+	}
+
+	public Type[] getTypes(Criteria crit, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		return types;
+	}
+
+	public String toString() {
+		return sql;
+	}
+
+	protected SQLProjection(String sql, String[] columnAliases, Type[] types) {
+		this(sql, null, columnAliases, types);
+	}
+	
+	protected SQLProjection(String sql, String groupBy, String[] columnAliases, Type[] types) {
+		this.sql = sql;
+		this.types = types;
+		this.aliases = columnAliases;
+		this.columnAliases = columnAliases;
+		this.grouped = groupBy!=null;
+		this.groupBy = groupBy;
+	}
+
+	public String[] getAliases() {
+		return aliases;
+	}
+	
+	public String[] getColumnAliases(int loc) {
+		return columnAliases;
+	}
+	
+	public boolean isGrouped() {
+		return grouped;
+	}
+
+	public Type[] getTypes(String alias, Criteria crit, CriteriaQuery criteriaQuery) {
+		return null; //unsupported
+	}
+
+	public String[] getColumnAliases(String alias, int loc) {
+		return null; //unsupported
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SQLProjection.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SimpleExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SimpleExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SimpleExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,82 @@
+//$Id: SimpleExpression.java 7641 2005-07-25 04:57:05Z oneovthafew $
+package org.hibernate.criterion;
+
+
+import java.sql.Types;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.type.Type;
+
+/**
+ * superclass for "simple" comparisons (with SQL binary operators)
+ * @author Gavin King
+ */
+public class SimpleExpression implements Criterion {
+
+	private final String propertyName;
+	private final Object value;
+	private boolean ignoreCase;
+	private final String op;
+
+	protected SimpleExpression(String propertyName, Object value, String op) {
+		this.propertyName = propertyName;
+		this.value = value;
+		this.op = op;
+	}
+
+	protected SimpleExpression(String propertyName, Object value, String op, boolean ignoreCase) {
+		this.propertyName = propertyName;
+		this.value = value;
+		this.ignoreCase = ignoreCase;
+		this.op = op;
+	}
+
+	public SimpleExpression ignoreCase() {
+		ignoreCase = true;
+		return this;
+	}
+
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+
+		String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);
+		Type type = criteriaQuery.getTypeUsingProjection(criteria, propertyName);
+		StringBuffer fragment = new StringBuffer();
+		if (columns.length>1) fragment.append('(');
+		SessionFactoryImplementor factory = criteriaQuery.getFactory();
+		int[] sqlTypes = type.sqlTypes( factory );
+		for ( int i=0; i<columns.length; i++ ) {
+			boolean lower = ignoreCase && 
+					( sqlTypes[i]==Types.VARCHAR || sqlTypes[i]==Types.CHAR );
+			if (lower) {
+				fragment.append( factory.getDialect().getLowercaseFunction() )
+					.append('(');
+			}
+			fragment.append( columns[i] );
+			if (lower) fragment.append(')');
+			fragment.append( getOp() ).append("?");
+			if ( i<columns.length-1 ) fragment.append(" and ");
+		}
+		if (columns.length>1) fragment.append(')');
+		return fragment.toString();
+
+	}
+
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		Object icvalue = ignoreCase ? value.toString().toLowerCase() : value;
+		return new TypedValue[] { criteriaQuery.getTypedValue(criteria, propertyName, icvalue) };
+	}
+
+	public String toString() {
+		return propertyName + getOp() + value;
+	}
+
+	protected final String getOp() {
+		return op;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SimpleProjection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SimpleProjection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SimpleProjection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: SimpleProjection.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.type.Type;
+
+
+/**
+ * A single-column projection that may be aliased
+ * @author Gavin King
+ */
+public abstract class SimpleProjection implements Projection {
+
+	public Projection as(String alias) {
+		return Projections.alias(this, alias);
+	}
+
+	public String[] getColumnAliases(String alias, int loc) {
+		return null;
+	}
+	
+	public Type[] getTypes(String alias, Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return null;
+	}
+
+	public String[] getColumnAliases(int loc) {
+		return new String[] { "y" + loc + "_" };
+	}
+	
+	public String[] getAliases() {
+		return new String[1];
+	}
+
+	public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		throw new UnsupportedOperationException("not a grouping projection");
+	}
+
+	public boolean isGrouped() {
+		return false;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SimpleProjection.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SimpleSubqueryExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SimpleSubqueryExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SimpleSubqueryExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: SimpleSubqueryExpression.java 5757 2005-02-18 03:47:27Z oneovthafew $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.TypedValue;
+
+/**
+ * A comparison between a constant value and the the result of a subquery
+ * @author Gavin King
+ */
+public class SimpleSubqueryExpression extends SubqueryExpression {
+	
+	private Object value;
+	
+	protected SimpleSubqueryExpression(Object value, String op, String quantifier, DetachedCriteria dc) {
+		super(op, quantifier, dc);
+		this.value = value;
+	}
+	
+	
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		TypedValue[] superTv = super.getTypedValues(criteria, criteriaQuery);
+		TypedValue[] result = new TypedValue[superTv.length+1];
+		System.arraycopy(superTv, 0, result, 1, superTv.length);
+		result[0] = new TypedValue( getTypes()[0], value, EntityMode.POJO );
+		return result;
+	}
+	
+	protected String toLeftSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
+		return "?";
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SimpleSubqueryExpression.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SizeExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SizeExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SizeExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+//$Id: SizeExpression.java 7844 2005-08-11 07:26:26Z oneovthafew $
+package org.hibernate.criterion;
+
+
+import org.hibernate.Criteria;
+import org.hibernate.EntityMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.sql.ConditionFragment;
+
+/**
+ * @author Gavin King
+ */
+public class SizeExpression implements Criterion {
+	
+	private final String propertyName;
+	private final int size;
+	private final String op;
+	
+	protected SizeExpression(String propertyName, int size, String op) {
+		this.propertyName = propertyName;
+		this.size = size;
+		this.op = op;
+	}
+
+	public String toString() {
+		return propertyName + ".size" + op + size;
+	}
+
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		String role = criteriaQuery.getEntityName(criteria, propertyName) + 
+				'.' +  
+				criteriaQuery.getPropertyName(propertyName);
+		QueryableCollection cp = (QueryableCollection) criteriaQuery.getFactory()
+				.getCollectionPersister(role);
+		//String[] fk = StringHelper.qualify( "collection_", cp.getKeyColumnNames() );
+		String[] fk = cp.getKeyColumnNames();
+		String[] pk = ( (Loadable) cp.getOwnerEntityPersister() ).getIdentifierColumnNames(); //TODO: handle property-ref
+		return "? " + 
+				op + 
+				" (select count(*) from " +
+				cp.getTableName() +
+				//" collection_ where " +
+				" where " +
+				new ConditionFragment()
+						.setTableAlias( criteriaQuery.getSQLAlias(criteria, propertyName) )
+						.setCondition(pk, fk)
+						.toFragmentString() +
+				")";
+	}
+
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		return new TypedValue[] { 
+			new TypedValue( Hibernate.INTEGER, new Integer(size), EntityMode.POJO ) 
+		};
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SizeExpression.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Subqueries.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Subqueries.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Subqueries.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,160 @@
+//$Id: Subqueries.java 8467 2005-10-26 21:20:17Z oneovthafew $
+package org.hibernate.criterion;
+
+/**
+ * Factory class for criterion instances that represent expressions
+ * involving subqueries.
+ * 
+ * @see Restriction
+ * @see Projection
+ * @see org.hibernate.Criteria
+ * @author Gavin King
+ */
+public class Subqueries {
+		
+	public static Criterion exists(DetachedCriteria dc) {
+		return new ExistsSubqueryExpression("exists", dc);
+	}
+	
+	public static Criterion notExists(DetachedCriteria dc) {
+		return new ExistsSubqueryExpression("not exists", dc);
+	}
+	
+	public static Criterion propertyEqAll(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, "=", "all", dc);
+	}
+	
+	public static Criterion propertyIn(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, "in", null, dc);
+	}
+	
+	public static Criterion propertyNotIn(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, "not in", null, dc);
+	}
+	
+	public static Criterion propertyEq(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, "=", null, dc);
+	}
+	
+	public static Criterion propertyNe(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, "<>", null, dc);
+	}
+	
+	public static Criterion propertyGt(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, ">", null, dc);
+	}
+	
+	public static Criterion propertyLt(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, "<", null, dc);
+	}
+	
+	public static Criterion propertyGe(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, ">=", null, dc);
+	}
+	
+	public static Criterion propertyLe(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, "<=", null, dc);
+	}
+	
+	public static Criterion propertyGtAll(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, ">", "all", dc);
+	}
+	
+	public static Criterion propertyLtAll(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, "<", "all", dc);
+	}
+	
+	public static Criterion propertyGeAll(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, ">=", "all", dc);
+	}
+	
+	public static Criterion propertyLeAll(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, "<=", "all", dc);
+	}
+	
+	public static Criterion propertyGtSome(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, ">", "some", dc);
+	}
+	
+	public static Criterion propertyLtSome(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, "<", "some", dc);
+	}
+	
+	public static Criterion propertyGeSome(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, ">=", "some", dc);
+	}
+	
+	public static Criterion propertyLeSome(String propertyName, DetachedCriteria dc) {
+		return new PropertySubqueryExpression(propertyName, "<=", "some", dc);
+	}
+	
+	public static Criterion eqAll(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, "=", "all", dc);
+	}
+	
+	public static Criterion in(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, "in", null, dc);
+	}
+	
+	public static Criterion notIn(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, "not in", null, dc);
+	}
+	
+	public static Criterion eq(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, "=", null, dc);
+	}
+	
+	public static Criterion gt(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, ">", null, dc);
+	}
+	
+	public static Criterion lt(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, "<", null, dc);
+	}
+	
+	public static Criterion ge(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, ">=", null, dc);
+	}
+	
+	public static Criterion le(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, "<=", null, dc);
+	}
+	
+	public static Criterion ne(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, "<>", null, dc);
+	}
+	
+	public static Criterion gtAll(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, ">", "all", dc);
+	}
+	
+	public static Criterion ltAll(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, "<", "all", dc);
+	}
+	
+	public static Criterion geAll(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, ">=", "all", dc);
+	}
+	
+	public static Criterion leAll(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, "<=", "all", dc);
+	}
+	
+	public static Criterion gtSome(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, ">", "some", dc);
+	}
+	
+	public static Criterion ltSome(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, "<", "some", dc);
+	}
+	
+	public static Criterion geSome(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, ">=", "some", dc);
+	}
+	
+	public static Criterion leSome(Object value, DetachedCriteria dc) {
+		return new SimpleSubqueryExpression(value, "<=", "some", dc);
+	}
+	
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/Subqueries.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SubqueryExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SubqueryExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SubqueryExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,89 @@
+//$Id: SubqueryExpression.java 7365 2005-07-04 02:40:29Z oneovthafew $
+package org.hibernate.criterion;
+
+import org.hibernate.Criteria;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.impl.CriteriaImpl;
+import org.hibernate.loader.criteria.CriteriaQueryTranslator;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.sql.Select;
+import org.hibernate.type.Type;
+
+/**
+ * @author Gavin King
+ */
+public abstract class SubqueryExpression implements Criterion {
+	
+	private CriteriaImpl criteriaImpl;
+	private String quantifier;
+	private String op;
+	private QueryParameters params;
+	private Type[] types;
+	
+	protected Type[] getTypes() {
+		return types;
+	}
+	
+	protected SubqueryExpression(String op, String quantifier, DetachedCriteria dc) {
+		this.criteriaImpl = dc.getCriteriaImpl();
+		this.quantifier = quantifier;
+		this.op = op;
+	}
+	
+	protected abstract String toLeftSqlString(Criteria criteria, CriteriaQuery outerQuery);
+
+	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
+	throws HibernateException {
+		
+		final SessionImplementor session = ( (CriteriaImpl) criteria ).getSession(); //ugly!
+		final SessionFactoryImplementor factory = session.getFactory();
+		
+		final OuterJoinLoadable persister = (OuterJoinLoadable) factory.getEntityPersister( criteriaImpl.getEntityOrClassName() );
+		CriteriaQueryTranslator innerQuery = new CriteriaQueryTranslator( 
+				factory, 
+				criteriaImpl, 
+				criteriaImpl.getEntityOrClassName(), //implicit polymorphism not supported (would need a union) 
+				criteriaQuery.generateSQLAlias(),
+				criteriaQuery
+			);
+		
+		params = innerQuery.getQueryParameters(); //TODO: bad lifecycle....
+		types = innerQuery.getProjectedTypes();
+		
+		//String filter = persister.filterFragment( innerQuery.getRootSQLALias(), session.getEnabledFilters() );
+		
+		String sql = new Select( factory.getDialect() )
+			.setWhereClause( innerQuery.getWhereCondition() )
+			.setGroupByClause( innerQuery.getGroupBy() )
+			.setSelectClause( innerQuery.getSelect() )
+			.setFromClause(
+					persister.fromTableFragment( innerQuery.getRootSQLALias() ) +   
+					persister.fromJoinFragment( innerQuery.getRootSQLALias(), true, false )
+				)
+			.toStatementString();
+		
+		final StringBuffer buf = new StringBuffer()
+			.append( toLeftSqlString(criteria, criteriaQuery) );
+		if (op!=null) buf.append(' ').append(op).append(' ');
+		if (quantifier!=null) buf.append(quantifier).append(' ');
+		return buf.append('(').append(sql).append(')')
+			.toString();
+	}
+
+	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) 
+	throws HibernateException {
+		Type[] types = params.getPositionalParameterTypes();
+		Object[] values = params.getPositionalParameterValues();
+		TypedValue[] tv = new TypedValue[types.length];
+		for ( int i=0; i<types.length; i++ ) {
+			tv[i] = new TypedValue( types[i], values[i], EntityMode.POJO );
+		}
+		return tv;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/SubqueryExpression.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>
+	A framework for defining restriction criteria and order criteria.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/criterion/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Cache71Dialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Cache71Dialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Cache71Dialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,655 @@
+//$Id:  $
+package org.hibernate.dialect;
+
+import java.sql.CallableStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.NoArgSQLFunction;
+import org.hibernate.dialect.function.NvlFunction;
+import org.hibernate.dialect.function.SQLFunctionTemplate;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.dialect.function.VarArgsSQLFunction;
+import org.hibernate.dialect.function.StandardJDBCEscapeFunction;
+import org.hibernate.dialect.function.ConvertFunction;
+import org.hibernate.dialect.function.ConditionalParenthesisFunction;
+import org.hibernate.dialect.lock.LockingStrategy;
+import org.hibernate.dialect.lock.SelectLockingStrategy;
+import org.hibernate.dialect.lock.UpdateLockingStrategy;
+import org.hibernate.exception.CacheSQLStateConverter;
+import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.exception.TemplatedViolatedConstraintNameExtracter;
+import org.hibernate.exception.ViolatedConstraintNameExtracter;
+import org.hibernate.id.IdentityGenerator;
+import org.hibernate.persister.entity.Lockable;
+import org.hibernate.sql.CacheJoinFragment;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Cach&eacute; 2007.1 dialect. This class is required in order to use Hibernate with Intersystems Caché SQL.<br>
+ * <br>
+ * Compatible with Caché 2007.1.
+ * <br>
+ * <head>
+ * <title>Cach&eacute; and Hibernate</title>
+ * </head>
+ * <body>
+ * <h1>Cach&eacute; and Hibernate</h1>
+ * <h2>PREREQUISITES</h2>
+ * These setup instructions assume that both Cach&eacute; and Hibernate are installed and operational.
+ * <br>
+ * <h2>HIBERNATE DIRECTORIES AND FILES</h2>
+ * JBoss distributes the InterSystems Cache' dialect for Hibernate 3.2.1
+ * For earlier versions of Hibernate please contact
+ * <a href="http://www.intersystems.com/support/cache-support.html">InterSystems Worldwide Response Center</A> (WRC)
+ * for the appropriate source files.
+ * <br>
+ * <h2>CACH&Eacute; DOCUMENTATION</h2>
+ * Documentation for Cach&eacute; is available online when Cach&eacute; is running.
+ * It can also be obtained from the
+ * <a href="http://www.intersystems.com/cache/downloads/documentation.html">InterSystems</A> website.
+ * The book, "Object-oriented Application Development Using the Cach&eacute; Post-relational Database:
+ * is also available from Springer-Verlag.
+ * <br>
+ * <h2>HIBERNATE DOCUMENTATION</h2>
+ * Hibernate comes with extensive electronic documentation.
+ * In addition, several books on Hibernate are available from
+ * <a href="http://www.manning.com">Manning Publications Co</a>.
+ * Three available titles are "Hibernate Quickly", "Hibernate in Action", and "Java Persistence with Hibernate".
+ * <br>
+ * <h2>TO SET UP HIBERNATE FOR USE WITH CACH&Eacute;</h2>
+ * The following steps assume that the directory where Cach&eacute; was installed is C:\CacheSys.
+ * This is the default installation directory for  Cach&eacute;.
+ * The default installation directory for Hibernate is assumed to be C:\Hibernate.
+ * <p/>
+ * If either product is installed in a different location, the pathnames that follow should be modified appropriately.
+ * <p/>
+ * Cach&eacute; version 2007.1 and above is recommended for use with
+ * Hibernate.  The next step depends on the location of your
+ * CacheDB.jar depending on your version of Cach&eacute;.
+ * <ol>
+ * <li>Copy C:\CacheSys\dev\java\lib\JDK15\CacheDB.jar to C:\Hibernate\lib\CacheDB.jar.</li>
+ * <p/>
+ * <li>Insert the following files into your Java classpath:
+ * <p/>
+ * <ul>
+ * <li>All jar files in the directory C:\Hibernate\lib</li>
+ * <li>The directory (or directories) where hibernate.properties and/or hibernate.cfg.xml are kept.</li>
+ * </ul>
+ * </li>
+ * <p/>
+ * <li>In the file, hibernate.properties (or hibernate.cfg.xml),
+ * specify the Cach&eacute; dialect and the Cach&eacute; version URL settings.</li>
+ * </ol>
+ * <p/>
+ * For example, in Hibernate 3.2, typical entries in hibernate.properties would have the following
+ * "name=value" pairs:
+ * <p/>
+ * <table cols=3 border cellpadding=5 cellspacing=0>
+ * <tr>
+ * <th>Property Name</th>
+ * <th>Property Value</th>
+ * </tr>
+ * <tr>
+ * <td>hibernate.dialect</td>
+ * <td>org.hibernate.dialect.Cache71Dialect</td>
+ * </tr>
+ * <tr>
+ * <td>hibernate.connection.driver_class</td>
+ * <td>com.intersys.jdbc.CacheDriver</td>
+ * </tr>
+ * <tr>
+ * <td>hibernate.connection.username</td>
+ * <td>(see note 1)</td>
+ * </tr>
+ * <tr>
+ * <td>hibernate.connection.password</td>
+ * <td>(see note 1)</td>
+ * </tr>
+ * <tr>
+ * <td>hibernate.connection.url</td>
+ * <td>jdbc:Cache://127.0.0.1:1972/USER</td>
+ * </tr>
+ * </table>
+ * <p/>
+ * <dl>
+ * <dt><b>Note 1</b></dt>
+ * <dd>Please contact your administrator for the userid and password you should use when attempting access via JDBC.
+ * By default, these are chosen to be "_SYSTEM" and "SYS" respectively as noted in the SQL standard.</dd>
+ * </dl>
+ * <br>
+ * <h2>CACH&Eacute; VERSION URL</h2>
+ * This is the standard URL for the JDBC driver.
+ * For a JDBC driver on the machine hosting Cach&eacute;, use the IP "loopback" address, 127.0.0.1.
+ * For 1972, the default port, specify the super server port of your Cach&eacute; instance.
+ * For USER, substitute the NAMESPACE which contains your Cach&eacute; database data.
+ * <br>
+ * <h2>CACH&Eacute; DIALECTS</h2>
+ * Choices for Dialect are:
+ * <br>
+ * <p/>
+ * <ol>
+ * <li>org.hibernate.dialect.Cache71Dialect (requires Cach&eacute;
+ * 2007.1 or above)</li>
+ * <p/>
+ * </ol>
+ * <br>
+ * <h2>SUPPORT FOR IDENTITY COLUMNS</h2>
+ * Cach&eacute; 2007.1 or later supports identity columns.  For
+ * Hibernate to use identity columns, specify "native" as the
+ * generator.
+ * <br>
+ * <h2>SEQUENCE DIALECTS SUPPORT SEQUENCES</h2>
+ * <p/>
+ * To use Hibernate sequence support with Cach&eacute; in a namespace, you must FIRST load the following file into that namespace:
+ * <pre>
+ *     etc\CacheSequences.xml
+ * </pre>
+ * For example, at the COS terminal prompt in the namespace, run the
+ * following command:
+ * <p>
+ * d LoadFile^%apiOBJ("c:\hibernate\etc\CacheSequences.xml","ck")
+ * <p>
+ * In your Hibernate mapping you can specify sequence use.
+ * <p>
+ * For example, the following shows the use of a sequence generator in a Hibernate mapping:
+ * <pre>
+ *     &lt;id name="id" column="uid" type="long" unsaved-value="null"&gt;
+ *         &lt;generator class="sequence"/&gt;
+ *     &lt;/id&gt;
+ * </pre>
+ * <br>
+ * <p/>
+ * Some versions of Hibernate under some circumstances call
+ * getSelectSequenceNextValString() in the dialect.  If this happens
+ * you will receive the error message: new MappingException( "Dialect
+ * does not support sequences" ).
+ * <br>
+ * <h2>HIBERNATE FILES ASSOCIATED WITH CACH&Eacute; DIALECT</h2>
+ * The following files are associated with Cach&eacute; dialect:
+ * <p/>
+ * <ol>
+ * <li>src\org\hibernate\dialect\Cache71Dialect.java</li>
+ * <li>src\org\hibernate\dialect\function\ConditionalParenthesisFunction.java</li>
+ * <li>src\org\hibernate\dialect\function\ConvertFunction.java</li>
+ * <li>src\org\hibernate\exception\CacheSQLStateConverter.java</li>
+ * <li>src\org\hibernate\sql\CacheJoinFragment.java</li>
+ * </ol>
+ * Cache71Dialect ships with Hibernate 3.2.  All other dialects are distributed by InterSystems and subclass Cache71Dialect.
+ *
+ * @author Jonathan Levinson
+ */
+
+public class Cache71Dialect extends Dialect {
+
+	/**
+	 * Creates new <code>Caché71Dialect</code> instance. Sets up the JDBC /
+	 * Caché type mappings.
+	 */
+	public Cache71Dialect() {
+		super();
+		commonRegistration();
+		register71Functions();
+	}
+
+	protected final void commonRegistration() {
+		// Note: For object <-> SQL datatype mappings see:
+		//	 Configuration Manager | Advanced | SQL | System DDL Datatype Mappings
+		//
+		//	TBD	registerColumnType(Types.BINARY,        "binary($1)");
+		// changed 08-11-2005, jsl
+		registerColumnType( Types.BINARY, "varbinary($1)" );
+		registerColumnType( Types.BIGINT, "BigInt" );
+		registerColumnType( Types.BIT, "bit" );
+		registerColumnType( Types.CHAR, "char(1)" );
+		registerColumnType( Types.DATE, "date" );
+		registerColumnType( Types.DECIMAL, "decimal" );
+		registerColumnType( Types.DOUBLE, "double" );
+		registerColumnType( Types.FLOAT, "float" );
+		registerColumnType( Types.INTEGER, "integer" );
+		registerColumnType( Types.LONGVARBINARY, "longvarbinary" );	// binary %Stream
+		registerColumnType( Types.LONGVARCHAR, "longvarchar" );		// character %Stream
+		registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
+		registerColumnType( Types.REAL, "real" );
+		registerColumnType( Types.SMALLINT, "smallint" );
+		registerColumnType( Types.TIMESTAMP, "timestamp" );
+		registerColumnType( Types.TIME, "time" );
+		registerColumnType( Types.TINYINT, "tinyint" );
+		// TBD should this be varbinary($1)?
+		//		registerColumnType(Types.VARBINARY,     "binary($1)");
+		registerColumnType( Types.VARBINARY, "longvarbinary" );
+		registerColumnType( Types.VARCHAR, "varchar($l)" );
+		registerColumnType( Types.BLOB, "longvarbinary" );
+		registerColumnType( Types.CLOB, "longvarchar" );
+
+		getDefaultProperties().setProperty( Environment.USE_STREAMS_FOR_BINARY, "false" );
+		getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
+		//getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, NO_BATCH);
+
+		getDefaultProperties().setProperty( Environment.USE_SQL_COMMENTS, "false" );
+
+		registerFunction( "abs", new StandardSQLFunction( "abs" ) );
+		registerFunction( "acos", new StandardJDBCEscapeFunction( "acos", Hibernate.DOUBLE ) );
+		registerFunction( "%alphaup", new StandardSQLFunction( "%alphaup", Hibernate.STRING ) );
+		registerFunction( "ascii", new StandardSQLFunction( "ascii", Hibernate.STRING ) );
+		registerFunction( "asin", new StandardJDBCEscapeFunction( "asin", Hibernate.DOUBLE ) );
+		registerFunction( "atan", new StandardJDBCEscapeFunction( "atan", Hibernate.DOUBLE ) );
+		registerFunction( "bit_length", new SQLFunctionTemplate( Hibernate.INTEGER, "($length(?1)*8)" ) );
+		// hibernate impelemnts cast in Dialect.java
+		registerFunction( "ceiling", new StandardSQLFunction( "ceiling", Hibernate.INTEGER ) );
+		registerFunction( "char", new StandardJDBCEscapeFunction( "char", Hibernate.CHARACTER ) );
+		registerFunction( "character_length", new StandardSQLFunction( "character_length", Hibernate.INTEGER ) );
+		registerFunction( "char_length", new StandardSQLFunction( "char_length", Hibernate.INTEGER ) );
+		registerFunction( "cos", new StandardJDBCEscapeFunction( "cos", Hibernate.DOUBLE ) );
+		registerFunction( "cot", new StandardJDBCEscapeFunction( "cot", Hibernate.DOUBLE ) );
+		registerFunction( "coalesce", new VarArgsSQLFunction( "coalesce(", ",", ")" ) );
+		registerFunction( "concat", new VarArgsSQLFunction( Hibernate.STRING, "", "||", "" ) );
+		registerFunction( "convert", new ConvertFunction() );
+		registerFunction( "curdate", new StandardJDBCEscapeFunction( "curdate", Hibernate.DATE ) );
+		registerFunction( "current_date", new NoArgSQLFunction( "current_date", Hibernate.DATE, false ) );
+		registerFunction( "current_time", new NoArgSQLFunction( "current_time", Hibernate.TIME, false ) );
+		registerFunction(
+				"current_timestamp", new ConditionalParenthesisFunction( "current_timestamp", Hibernate.TIMESTAMP )
+		);
+		registerFunction( "curtime", new StandardJDBCEscapeFunction( "curtime", Hibernate.TIME ) );
+		registerFunction( "database", new StandardJDBCEscapeFunction( "database", Hibernate.STRING ) );
+		registerFunction( "dateadd", new VarArgsSQLFunction( Hibernate.TIMESTAMP, "dateadd(", ",", ")" ) );
+		registerFunction( "datediff", new VarArgsSQLFunction( Hibernate.INTEGER, "datediff(", ",", ")" ) );
+		registerFunction( "datename", new VarArgsSQLFunction( Hibernate.STRING, "datename(", ",", ")" ) );
+		registerFunction( "datepart", new VarArgsSQLFunction( Hibernate.INTEGER, "datepart(", ",", ")" ) );
+		registerFunction( "day", new StandardSQLFunction( "day", Hibernate.INTEGER ) );
+		registerFunction( "dayname", new StandardJDBCEscapeFunction( "dayname", Hibernate.STRING ) );
+		registerFunction( "dayofmonth", new StandardJDBCEscapeFunction( "dayofmonth", Hibernate.INTEGER ) );
+		registerFunction( "dayofweek", new StandardJDBCEscapeFunction( "dayofweek", Hibernate.INTEGER ) );
+		registerFunction( "dayofyear", new StandardJDBCEscapeFunction( "dayofyear", Hibernate.INTEGER ) );
+		// is it necessary to register %exact since it can only appear in a where clause?
+		registerFunction( "%exact", new StandardSQLFunction( "%exact", Hibernate.STRING ) );
+		registerFunction( "exp", new StandardJDBCEscapeFunction( "exp", Hibernate.DOUBLE ) );
+		registerFunction( "%external", new StandardSQLFunction( "%external", Hibernate.STRING ) );
+		registerFunction( "$extract", new VarArgsSQLFunction( Hibernate.INTEGER, "$extract(", ",", ")" ) );
+		registerFunction( "$find", new VarArgsSQLFunction( Hibernate.INTEGER, "$find(", ",", ")" ) );
+		registerFunction( "floor", new StandardSQLFunction( "floor", Hibernate.INTEGER ) );
+		registerFunction( "getdate", new StandardSQLFunction( "getdate", Hibernate.TIMESTAMP ) );
+		registerFunction( "hour", new StandardJDBCEscapeFunction( "hour", Hibernate.INTEGER ) );
+		registerFunction( "ifnull", new VarArgsSQLFunction( "ifnull(", ",", ")" ) );
+		registerFunction( "%internal", new StandardSQLFunction( "%internal" ) );
+		registerFunction( "isnull", new VarArgsSQLFunction( "isnull(", ",", ")" ) );
+		registerFunction( "isnumeric", new StandardSQLFunction( "isnumeric", Hibernate.INTEGER ) );
+		registerFunction( "lcase", new StandardJDBCEscapeFunction( "lcase", Hibernate.STRING ) );
+		registerFunction( "left", new StandardJDBCEscapeFunction( "left", Hibernate.STRING ) );
+		registerFunction( "len", new StandardSQLFunction( "len", Hibernate.INTEGER ) );
+		registerFunction( "length", new StandardSQLFunction( "length", Hibernate.INTEGER ) );
+		registerFunction( "$length", new VarArgsSQLFunction( "$length(", ",", ")" ) );
+		// aggregate functions shouldn't be registered, right?
+		//registerFunction( "list", new StandardSQLFunction("list",Hibernate.STRING) );
+		// stopped on $list
+		registerFunction( "$list", new VarArgsSQLFunction( "$list(", ",", ")" ) );
+		registerFunction( "$listdata", new VarArgsSQLFunction( "$listdata(", ",", ")" ) );
+		registerFunction( "$listfind", new VarArgsSQLFunction( "$listfind(", ",", ")" ) );
+		registerFunction( "$listget", new VarArgsSQLFunction( "$listget(", ",", ")" ) );
+		registerFunction( "$listlength", new StandardSQLFunction( "$listlength", Hibernate.INTEGER ) );
+		registerFunction( "locate", new StandardSQLFunction( "$FIND", Hibernate.INTEGER ) );
+		registerFunction( "log", new StandardJDBCEscapeFunction( "log", Hibernate.DOUBLE ) );
+		registerFunction( "log10", new StandardJDBCEscapeFunction( "log", Hibernate.DOUBLE ) );
+		registerFunction( "lower", new StandardSQLFunction( "lower" ) );
+		registerFunction( "ltrim", new StandardSQLFunction( "ltrim" ) );
+		registerFunction( "minute", new StandardJDBCEscapeFunction( "minute", Hibernate.INTEGER ) );
+		registerFunction( "mod", new StandardJDBCEscapeFunction( "mod", Hibernate.DOUBLE ) );
+		registerFunction( "month", new StandardJDBCEscapeFunction( "month", Hibernate.INTEGER ) );
+		registerFunction( "monthname", new StandardJDBCEscapeFunction( "monthname", Hibernate.STRING ) );
+		registerFunction( "now", new StandardJDBCEscapeFunction( "monthname", Hibernate.TIMESTAMP ) );
+		registerFunction( "nullif", new VarArgsSQLFunction( "nullif(", ",", ")" ) );
+		registerFunction( "nvl", new NvlFunction() );
+		registerFunction( "%odbcin", new StandardSQLFunction( "%odbcin" ) );
+		registerFunction( "%odbcout", new StandardSQLFunction( "%odbcin" ) );
+		registerFunction( "%pattern", new VarArgsSQLFunction( Hibernate.STRING, "", "%pattern", "" ) );
+		registerFunction( "pi", new StandardJDBCEscapeFunction( "pi", Hibernate.DOUBLE ) );
+		registerFunction( "$piece", new VarArgsSQLFunction( Hibernate.STRING, "$piece(", ",", ")" ) );
+		registerFunction( "position", new VarArgsSQLFunction( Hibernate.INTEGER, "position(", " in ", ")" ) );
+		registerFunction( "power", new VarArgsSQLFunction( Hibernate.STRING, "power(", ",", ")" ) );
+		registerFunction( "quarter", new StandardJDBCEscapeFunction( "quarter", Hibernate.INTEGER ) );
+		registerFunction( "repeat", new VarArgsSQLFunction( Hibernate.STRING, "repeat(", ",", ")" ) );
+		registerFunction( "replicate", new VarArgsSQLFunction( Hibernate.STRING, "replicate(", ",", ")" ) );
+		registerFunction( "right", new StandardJDBCEscapeFunction( "right", Hibernate.STRING ) );
+		registerFunction( "round", new VarArgsSQLFunction( Hibernate.FLOAT, "round(", ",", ")" ) );
+		registerFunction( "rtrim", new StandardSQLFunction( "rtrim", Hibernate.STRING ) );
+		registerFunction( "second", new StandardJDBCEscapeFunction( "second", Hibernate.INTEGER ) );
+		registerFunction( "sign", new StandardSQLFunction( "sign", Hibernate.INTEGER ) );
+		registerFunction( "sin", new StandardJDBCEscapeFunction( "sin", Hibernate.DOUBLE ) );
+		registerFunction( "space", new StandardSQLFunction( "space", Hibernate.STRING ) );
+		registerFunction( "%sqlstring", new VarArgsSQLFunction( Hibernate.STRING, "%sqlstring(", ",", ")" ) );
+		registerFunction( "%sqlupper", new VarArgsSQLFunction( Hibernate.STRING, "%sqlupper(", ",", ")" ) );
+		registerFunction( "sqrt", new StandardJDBCEscapeFunction( "SQRT", Hibernate.DOUBLE ) );
+		registerFunction( "%startswith", new VarArgsSQLFunction( Hibernate.STRING, "", "%startswith", "" ) );
+		// below is for Cache' that don't have str in 2007.1 there is str and we register str directly
+		registerFunction( "str", new SQLFunctionTemplate( Hibernate.STRING, "cast(?1 as char varying)" ) );
+		registerFunction( "string", new VarArgsSQLFunction( Hibernate.STRING, "string(", ",", ")" ) );
+		// note that %string is deprecated
+		registerFunction( "%string", new VarArgsSQLFunction( Hibernate.STRING, "%string(", ",", ")" ) );
+		registerFunction( "substr", new VarArgsSQLFunction( Hibernate.STRING, "substr(", ",", ")" ) );
+		registerFunction( "substring", new VarArgsSQLFunction( Hibernate.STRING, "substring(", ",", ")" ) );
+		registerFunction( "sysdate", new NoArgSQLFunction( "sysdate", Hibernate.TIMESTAMP, false ) );
+		registerFunction( "tan", new StandardJDBCEscapeFunction( "tan", Hibernate.DOUBLE ) );
+		registerFunction( "timestampadd", new StandardJDBCEscapeFunction( "timestampadd", Hibernate.DOUBLE ) );
+		registerFunction( "timestampdiff", new StandardJDBCEscapeFunction( "timestampdiff", Hibernate.DOUBLE ) );
+		registerFunction( "tochar", new VarArgsSQLFunction( Hibernate.STRING, "tochar(", ",", ")" ) );
+		registerFunction( "to_char", new VarArgsSQLFunction( Hibernate.STRING, "to_char(", ",", ")" ) );
+		registerFunction( "todate", new VarArgsSQLFunction( Hibernate.STRING, "todate(", ",", ")" ) );
+		registerFunction( "to_date", new VarArgsSQLFunction( Hibernate.STRING, "todate(", ",", ")" ) );
+		registerFunction( "tonumber", new StandardSQLFunction( "tonumber" ) );
+		registerFunction( "to_number", new StandardSQLFunction( "tonumber" ) );
+		// TRIM(end_keyword string-expression-1 FROM string-expression-2)
+		// use Hibernate implementation "From" is one of the parameters they pass in position ?3
+		//registerFunction( "trim", new SQLFunctionTemplate(Hibernate.STRING, "trim(?1 ?2 from ?3)") );
+		registerFunction( "truncate", new StandardJDBCEscapeFunction( "truncate", Hibernate.STRING ) );
+		registerFunction( "ucase", new StandardJDBCEscapeFunction( "ucase", Hibernate.STRING ) );
+		registerFunction( "upper", new StandardSQLFunction( "upper" ) );
+		// %upper is deprecated
+		registerFunction( "%upper", new StandardSQLFunction( "%upper" ) );
+		registerFunction( "user", new StandardJDBCEscapeFunction( "user", Hibernate.STRING ) );
+		registerFunction( "week", new StandardJDBCEscapeFunction( "user", Hibernate.INTEGER ) );
+		registerFunction( "xmlconcat", new VarArgsSQLFunction( Hibernate.STRING, "xmlconcat(", ",", ")" ) );
+		registerFunction( "xmlelement", new VarArgsSQLFunction( Hibernate.STRING, "xmlelement(", ",", ")" ) );
+		// xmlforest requires a new kind of function constructor
+		registerFunction( "year", new StandardJDBCEscapeFunction( "year", Hibernate.INTEGER ) );
+	}
+
+	protected final void register71Functions() {
+		this.registerFunction( "str", new VarArgsSQLFunction( Hibernate.STRING, "str(", ",", ")" ) );
+	}
+
+	// DDL support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean hasAlterTable() {
+		// Does this dialect support the ALTER TABLE syntax?
+		return true;
+	}
+
+	public boolean qualifyIndexName() {
+		// Do we need to qualify index names with the schema name?
+		return false;
+	}
+
+	public boolean supportsUnique() {
+		// Does this dialect support the UNIQUE column syntax?
+		return true;
+	}
+
+	/**
+	 * The syntax used to add a foreign key constraint to a table.
+	 *
+	 * @return String
+	 */
+	public String getAddForeignKeyConstraintString(
+			String constraintName,
+			String[] foreignKey,
+			String referencedTable,
+			String[] primaryKey,
+			boolean referencesPrimaryKey) {
+		// The syntax used to add a foreign key constraint to a table.
+		return new StringBuffer( 300 )
+				.append( " ADD CONSTRAINT " )
+				.append( constraintName )
+				.append( " FOREIGN KEY " )
+				.append( constraintName )
+				.append( " (" )
+				.append( StringHelper.join( ", ", foreignKey ) )	// identifier-commalist
+				.append( ") REFERENCES " )
+				.append( referencedTable )
+				.append( " (" )
+				.append( StringHelper.join( ", ", primaryKey ) ) // identifier-commalist
+				.append( ") " )
+				.toString();
+	}
+
+	public boolean supportsCheck() {
+		// Does this dialect support check constraints?
+		return false;
+	}
+
+	public String getAddColumnString() {
+		// The syntax used to add a column to a table
+		return " add column";
+	}
+
+	public String getCascadeConstraintsString() {
+		// Completely optional cascading drop clause.
+		return "";
+	}
+
+	public boolean dropConstraints() {
+		// Do we need to drop constraints before dropping tables in this dialect?
+		return true;
+	}
+
+	public boolean supportsCascadeDelete() {
+		return true;
+	}
+
+	public boolean hasSelfReferentialForeignKeyBug() {
+		return true;
+	}
+
+	// temporary table support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsTemporaryTables() {
+		return true;
+	}
+
+	public String generateTemporaryTableName(String baseTableName) {
+		String name = super.generateTemporaryTableName( baseTableName );
+		return name.length() > 25 ? name.substring( 1, 25 ) : name;
+	}
+
+	public String getCreateTemporaryTableString() {
+		return "create global temporary table";
+	}
+
+	public Boolean performTemporaryTableDDLInIsolation() {
+		return Boolean.FALSE;
+	}
+
+	public String getCreateTemporaryTablePostfix() {
+		return "";
+	}
+
+	public boolean dropTemporaryTableAfterUse() {
+		return true;
+	}
+
+	// IDENTITY support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsIdentityColumns() {
+		return true;
+	}
+
+	public Class getNativeIdentifierGeneratorClass() {
+		return IdentityGenerator.class;
+	}
+
+	public boolean hasDataTypeInIdentityColumn() {
+		// Whether this dialect has an Identity clause added to the data type or a completely seperate identity
+		// data type
+		return true;
+	}
+
+	public String getIdentityColumnString() throws MappingException {
+		// The keyword used to specify an identity column, if identity column key generation is supported.
+		return "identity";
+	}
+
+	public String getIdentitySelectString() {
+		return "SELECT LAST_IDENTITY() FROM %TSQL_sys.snf";
+	}
+
+	// SEQUENCE support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsSequences() {
+		return false;
+	}
+
+// It really does support sequences, but InterSystems elects to suggest usage of IDENTITY instead :/
+// Anyway, below are the actual support overrides for users wanting to use this combo...
+//
+//	public String getSequenceNextValString(String sequenceName) {
+//		return "select InterSystems.Sequences_GetNext('" + sequenceName + "') from InterSystems.Sequences where ucase(name)=ucase('" + sequenceName + "')";
+//	}
+//
+//	public String getSelectSequenceNextValString(String sequenceName) {
+//		return "(select InterSystems.Sequences_GetNext('" + sequenceName + "') from InterSystems.Sequences where ucase(name)=ucase('" + sequenceName + "'))";
+//	}
+//
+//	public String getCreateSequenceString(String sequenceName) {
+//		return "insert into InterSystems.Sequences(Name) values (ucase('" + sequenceName + "'))";
+//	}
+//
+//	public String getDropSequenceString(String sequenceName) {
+//		return "delete from InterSystems.Sequences where ucase(name)=ucase('" + sequenceName + "')";
+//	}
+//
+//	public String getQuerySequencesString() {
+//		return "select name from InterSystems.Sequences";
+//	}
+
+	// lock acquisition support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsForUpdate() {
+		// Does this dialect support the FOR UPDATE syntax?
+		return false;
+	}
+
+	public boolean supportsForUpdateOf() {
+		// Does this dialect support FOR UPDATE OF, allowing particular rows to be locked?
+		return false;
+	}
+
+	public boolean supportsForUpdateNowait() {
+		// Does this dialect support the Oracle-style FOR UPDATE NOWAIT syntax?
+		return false;
+	}
+
+	public boolean supportsOuterJoinForUpdate() {
+		return false;
+	}
+
+	public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
+		// InterSystems Cache' does not current support "SELECT ... FOR UPDATE" syntax...
+		// Set your transaction mode to READ_COMMITTED before using
+		if ( lockMode.greaterThan( LockMode.READ ) ) {
+			return new UpdateLockingStrategy( lockable, lockMode );
+		}
+		else {
+			return new SelectLockingStrategy( lockable, lockMode );
+		}
+	}
+
+	// LIMIT support (ala TOP) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsLimit() {
+		return true;
+	}
+
+	public boolean supportsLimitOffset() {
+		return false;
+	}
+
+	public boolean supportsVariableLimit() {
+		return true;
+	}
+
+	public boolean bindLimitParametersFirst() {
+		// Does the LIMIT clause come at the start of the SELECT statement, rather than at the end?
+		return true;
+	}
+
+	public boolean useMaxForLimit() {
+		// Does the LIMIT clause take a "maximum" row number instead of a total number of returned rows?
+		return true;
+	}
+
+	public String getLimitString(String sql, boolean hasOffset) {
+		if ( hasOffset ) {
+			throw new UnsupportedOperationException( "An offset may not be specified to <TOP n> in Cache SQL" );
+		}
+
+		// This does not support the Cache SQL 'DISTINCT BY (comma-list)' extensions,
+		// but this extension is not supported through Hibernate anyway.
+		int insertionPoint = sql.startsWith( "select distinct" ) ? 15 : 6;
+
+		return new StringBuffer( sql.length() + 8 )
+				.append( sql )
+				.insert( insertionPoint, " TOP ? " )
+				.toString();
+	}
+
+	// callable statement support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
+		return col;
+	}
+
+	public ResultSet getResultSet(CallableStatement ps) throws SQLException {
+		ps.execute();
+		return ( ResultSet ) ps.getObject( 1 );
+	}
+
+	// miscellaneous support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public String getLowercaseFunction() {
+		// The name of the SQL function that transforms a string to lowercase
+		return "lower";
+	}
+
+	public String getNullColumnString() {
+		// The keyword used to specify a nullable column.
+		return " null";
+	}
+
+	public JoinFragment createOuterJoinFragment() {
+		// Create an OuterJoinGenerator for this dialect.
+		return new CacheJoinFragment();
+	}
+
+	public String getNoColumnsInsertString() {
+		// The keyword used to insert a row without specifying
+		// any column values
+		return " default values";
+	}
+
+	public SQLExceptionConverter buildSQLExceptionConverter() {
+		return new CacheSQLStateConverter( EXTRACTER );
+	}
+
+	public static final ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
+		/**
+		 * Extract the name of the violated constraint from the given SQLException.
+		 *
+		 * @param sqle The exception that was the result of the constraint violation.
+		 * @return The extracted constraint name.
+		 */
+		public String extractConstraintName(SQLException sqle) {
+			return extractUsingTemplate( "constraint (", ") violated", sqle.getMessage() );
+		}
+	};
+
+
+	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsEmptyInList() {
+		return false;
+	}
+
+	public boolean areStringComparisonsCaseInsensitive() {
+		return true;
+	}
+
+	public boolean supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() {
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DB2390Dialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DB2390Dialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DB2390Dialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: DB2390Dialect.java 5712 2005-02-13 13:48:39Z oneovthafew $
+package org.hibernate.dialect;
+
+/**
+ * An SQL dialect for DB2/390. This class provides support for
+ * DB2 Universal Database for OS/390, also known as DB2/390.
+ *
+ * @author Kristoffer Dyrkorn
+ */
+public class DB2390Dialect extends DB2Dialect {
+
+	public boolean supportsSequences() {
+		return false;
+	}
+
+	public String getIdentitySelectString() {
+		return "select identity_val_local() from sysibm.sysdummy1";
+	}
+
+	public boolean supportsLimit() {
+		return true;
+	}
+
+	public boolean supportsLimitOffset() {
+		return false;
+	}
+
+	public String getLimitString(String sql, int offset, int limit) {
+		return new StringBuffer(sql.length() + 40)
+			.append(sql)
+			.append(" fetch first ")
+			.append(limit)
+			.append(" rows only ")
+			.toString();
+	}
+
+	public boolean useMaxForLimit() {
+		return true;
+	}
+
+	public boolean supportsVariableLimit() {
+		return false;
+	}
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DB2400Dialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DB2400Dialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DB2400Dialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+package org.hibernate.dialect;
+
+/**
+* An SQL dialect for DB2/400
+* @author Peter DeGregorio (pdegregorio)
+* This class provides support for DB2 Universal Database for iSeries,
+* also known as DB2/400.
+*/
+public class DB2400Dialect extends DB2Dialect {
+
+	public boolean supportsSequences() {
+		return false;
+	}
+
+	public String getIdentitySelectString() {
+		return "select identity_val_local() from sysibm.sysdummy1";
+	}
+
+	public boolean supportsLimit() {
+		return true;
+	}
+
+	public boolean supportsLimitOffset() {
+		return false;
+	}
+
+	public String getLimitString(String sql, int offset, int limit) {
+		return new StringBuffer(sql.length() + 40)
+			.append(sql)
+			.append(" fetch first ")
+			.append(limit)
+			.append(" rows only ")
+			.toString();
+	}
+
+	public boolean useMaxForLimit() {
+		return true;
+	}
+
+	public boolean supportsVariableLimit() {
+		return false;
+	}
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DB2Dialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DB2Dialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DB2Dialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,369 @@
+//$Id: DB2Dialect.java 10963 2006-12-08 16:06:14Z steve.ebersole at jboss.com $
+package org.hibernate.dialect;
+
+import java.sql.CallableStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.Hibernate;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.NoArgSQLFunction;
+import org.hibernate.dialect.function.SQLFunctionTemplate;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.dialect.function.VarArgsSQLFunction;
+import org.hibernate.dialect.function.AnsiTrimEmulationFunction;
+
+/**
+ * An SQL dialect for DB2.
+ * @author Gavin King
+ */
+public class DB2Dialect extends Dialect {
+
+	public DB2Dialect() {
+		super();
+		registerColumnType( Types.BIT, "smallint" );
+		registerColumnType( Types.BIGINT, "bigint" );
+		registerColumnType( Types.SMALLINT, "smallint" );
+		registerColumnType( Types.TINYINT, "smallint" );
+		registerColumnType( Types.INTEGER, "integer" );
+		registerColumnType( Types.CHAR, "char(1)" );
+		registerColumnType( Types.VARCHAR, "varchar($l)" );
+		registerColumnType( Types.FLOAT, "float" );
+		registerColumnType( Types.DOUBLE, "double" );
+		registerColumnType( Types.DATE, "date" );
+		registerColumnType( Types.TIME, "time" );
+		registerColumnType( Types.TIMESTAMP, "timestamp" );
+		registerColumnType( Types.VARBINARY, "varchar($l) for bit data" );
+		registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
+		registerColumnType( Types.BLOB, "blob($l)" );
+		registerColumnType( Types.CLOB, "clob($l)" );
+
+		registerFunction("abs", new StandardSQLFunction("abs") );
+		registerFunction("absval", new StandardSQLFunction("absval") );
+		registerFunction("sign", new StandardSQLFunction("sign", Hibernate.INTEGER) );
+
+		registerFunction("ceiling", new StandardSQLFunction("ceiling") );
+		registerFunction("ceil", new StandardSQLFunction("ceil") );
+		registerFunction("floor", new StandardSQLFunction("floor") );
+		registerFunction("round", new StandardSQLFunction("round") );
+
+		registerFunction("acos", new StandardSQLFunction("acos", Hibernate.DOUBLE) );
+		registerFunction("asin", new StandardSQLFunction("asin", Hibernate.DOUBLE) );
+		registerFunction("atan", new StandardSQLFunction("atan", Hibernate.DOUBLE) );
+		registerFunction("cos", new StandardSQLFunction("cos", Hibernate.DOUBLE) );
+		registerFunction("cot", new StandardSQLFunction("cot", Hibernate.DOUBLE) );
+		registerFunction("degrees", new StandardSQLFunction("degrees", Hibernate.DOUBLE) );
+		registerFunction("exp", new StandardSQLFunction("exp", Hibernate.DOUBLE) );
+		registerFunction("float", new StandardSQLFunction("float", Hibernate.DOUBLE) );
+		registerFunction("hex", new StandardSQLFunction("hex", Hibernate.STRING) );
+		registerFunction("ln", new StandardSQLFunction("ln", Hibernate.DOUBLE) );
+		registerFunction("log", new StandardSQLFunction("log", Hibernate.DOUBLE) );
+		registerFunction("log10", new StandardSQLFunction("log10", Hibernate.DOUBLE) );
+		registerFunction("radians", new StandardSQLFunction("radians", Hibernate.DOUBLE) );
+		registerFunction("rand", new NoArgSQLFunction("rand", Hibernate.DOUBLE) );
+		registerFunction("sin", new StandardSQLFunction("sin", Hibernate.DOUBLE) );
+		registerFunction("soundex", new StandardSQLFunction("soundex", Hibernate.STRING) );
+		registerFunction("sqrt", new StandardSQLFunction("sqrt", Hibernate.DOUBLE) );
+		registerFunction("stddev", new StandardSQLFunction("stddev", Hibernate.DOUBLE) );
+		registerFunction("tan", new StandardSQLFunction("tan", Hibernate.DOUBLE) );
+		registerFunction("variance", new StandardSQLFunction("variance", Hibernate.DOUBLE) );
+
+		registerFunction("julian_day", new StandardSQLFunction("julian_day", Hibernate.INTEGER) );
+		registerFunction("microsecond", new StandardSQLFunction("microsecond", Hibernate.INTEGER) );
+		registerFunction("midnight_seconds", new StandardSQLFunction("midnight_seconds", Hibernate.INTEGER) );
+		registerFunction("minute", new StandardSQLFunction("minute", Hibernate.INTEGER) );
+		registerFunction("month", new StandardSQLFunction("month", Hibernate.INTEGER) );
+		registerFunction("monthname", new StandardSQLFunction("monthname", Hibernate.STRING) );
+		registerFunction("quarter", new StandardSQLFunction("quarter", Hibernate.INTEGER) );
+		registerFunction("hour", new StandardSQLFunction("hour", Hibernate.INTEGER) );
+		registerFunction("second", new StandardSQLFunction("second", Hibernate.INTEGER) );
+		registerFunction("current_date", new NoArgSQLFunction("current date", Hibernate.DATE, false) );
+		registerFunction("date", new StandardSQLFunction("date", Hibernate.DATE) );
+		registerFunction("day", new StandardSQLFunction("day", Hibernate.INTEGER) );
+		registerFunction("dayname", new StandardSQLFunction("dayname", Hibernate.STRING) );
+		registerFunction("dayofweek", new StandardSQLFunction("dayofweek", Hibernate.INTEGER) );
+		registerFunction("dayofweek_iso", new StandardSQLFunction("dayofweek_iso", Hibernate.INTEGER) );
+		registerFunction("dayofyear", new StandardSQLFunction("dayofyear", Hibernate.INTEGER) );
+		registerFunction("days", new StandardSQLFunction("days", Hibernate.LONG) );
+		registerFunction("current_time", new NoArgSQLFunction("current time", Hibernate.TIME, false) );
+		registerFunction("time", new StandardSQLFunction("time", Hibernate.TIME) );
+		registerFunction("current_timestamp", new NoArgSQLFunction("current timestamp", Hibernate.TIMESTAMP, false) );
+		registerFunction("timestamp", new StandardSQLFunction("timestamp", Hibernate.TIMESTAMP) );
+		registerFunction("timestamp_iso", new StandardSQLFunction("timestamp_iso", Hibernate.TIMESTAMP) );
+		registerFunction("week", new StandardSQLFunction("week", Hibernate.INTEGER) );
+		registerFunction("week_iso", new StandardSQLFunction("week_iso", Hibernate.INTEGER) );
+		registerFunction("year", new StandardSQLFunction("year", Hibernate.INTEGER) );
+
+		registerFunction("double", new StandardSQLFunction("double", Hibernate.DOUBLE) );
+		registerFunction("varchar", new StandardSQLFunction("varchar", Hibernate.STRING) );
+		registerFunction("real", new StandardSQLFunction("real", Hibernate.FLOAT) );
+		registerFunction("bigint", new StandardSQLFunction("bigint", Hibernate.LONG) );
+		registerFunction("char", new StandardSQLFunction("char", Hibernate.CHARACTER) );
+		registerFunction("integer", new StandardSQLFunction("integer", Hibernate.INTEGER) );
+		registerFunction("smallint", new StandardSQLFunction("smallint", Hibernate.SHORT) );
+
+		registerFunction("digits", new StandardSQLFunction("digits", Hibernate.STRING) );
+		registerFunction("chr", new StandardSQLFunction("chr", Hibernate.CHARACTER) );
+		registerFunction("upper", new StandardSQLFunction("upper") );
+		registerFunction("lower", new StandardSQLFunction("lower") );
+		registerFunction("ucase", new StandardSQLFunction("ucase") );
+		registerFunction("lcase", new StandardSQLFunction("lcase") );
+		registerFunction("length", new StandardSQLFunction("length", Hibernate.LONG) );
+		registerFunction("ltrim", new StandardSQLFunction("ltrim") );
+		registerFunction("rtrim", new StandardSQLFunction("rtrim") );
+		registerFunction( "substr", new StandardSQLFunction( "substr", Hibernate.STRING ) );
+		registerFunction( "posstr", new StandardSQLFunction( "posstr", Hibernate.INTEGER ) );
+
+		registerFunction( "substring", new StandardSQLFunction( "substr", Hibernate.STRING ) );
+		registerFunction( "bit_length", new SQLFunctionTemplate( Hibernate.INTEGER, "length(?1)*8" ) );
+		registerFunction( "trim", new AnsiTrimEmulationFunction() );
+
+		registerFunction( "concat", new VarArgsSQLFunction(Hibernate.STRING, "", "||", "") );
+
+		registerFunction( "str", new SQLFunctionTemplate( Hibernate.STRING, "rtrim(char(?1))" ) );
+
+		registerKeyword("current");
+		registerKeyword("date");
+		registerKeyword("time");
+		registerKeyword("timestamp");
+		registerKeyword("fetch");
+		registerKeyword("first");
+		registerKeyword("rows");
+		registerKeyword("only");
+
+		getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, NO_BATCH);
+	}
+
+	public String getLowercaseFunction() {
+		return "lcase";
+	}
+
+	public String getAddColumnString() {
+		return "add column";
+	}
+	public boolean dropConstraints() {
+		return false;
+	}
+	public boolean supportsIdentityColumns() {
+		return true;
+	}
+	public String getIdentitySelectString() {
+		return "values identity_val_local()";
+	}
+	public String getIdentityColumnString() {
+		return "generated by default as identity"; //not null ... (start with 1) is implicit
+	}
+	public String getIdentityInsertString() {
+		return "default";
+	}
+
+	public String getSequenceNextValString(String sequenceName) {
+		return "values nextval for " + sequenceName;
+	}
+	public String getCreateSequenceString(String sequenceName) {
+		return "create sequence " + sequenceName;
+	}
+	public String getDropSequenceString(String sequenceName) {
+		return "drop sequence " + sequenceName + " restrict";
+	}
+
+	public boolean supportsSequences() {
+		return true;
+	}
+
+	public String getQuerySequencesString() {
+		return "select seqname from sysibm.syssequences";
+	}
+
+	public boolean supportsLimit() {
+		return true;
+	}
+
+	/*public String getLimitString(String sql, boolean hasOffset) {
+		StringBuffer rownumber = new StringBuffer(50)
+			.append(" rownumber() over(");
+		int orderByIndex = sql.toLowerCase().indexOf("order by");
+		if (orderByIndex>0) rownumber.append( sql.substring(orderByIndex) );
+		rownumber.append(") as row_,");
+		StringBuffer pagingSelect = new StringBuffer( sql.length()+100 )
+			.append("select * from ( ")
+			.append(sql)
+			.insert( getAfterSelectInsertPoint(sql)+16, rownumber.toString() )
+			.append(" ) as temp_ where row_ ");
+		if (hasOffset) {
+			pagingSelect.append("between ?+1 and ?");
+		}
+		else {
+			pagingSelect.append("<= ?");
+		}
+		return pagingSelect.toString();
+	}*/
+
+	/**
+	 * Render the <tt>rownumber() over ( .... ) as rownumber_,</tt> 
+	 * bit, that goes in the select list
+	 */
+	private String getRowNumber(String sql) {
+		StringBuffer rownumber = new StringBuffer(50)
+			.append("rownumber() over(");
+
+		int orderByIndex = sql.toLowerCase().indexOf("order by");
+
+		if ( orderByIndex>0 && !hasDistinct(sql) ) {
+			rownumber.append( sql.substring(orderByIndex) );
+		}
+
+		rownumber.append(") as rownumber_,");
+
+		return rownumber.toString();
+	}
+
+	public String getLimitString(String sql, boolean hasOffset) {
+
+		int startOfSelect = sql.toLowerCase().indexOf("select");
+
+		StringBuffer pagingSelect = new StringBuffer( sql.length()+100 )
+					.append( sql.substring(0, startOfSelect) ) //add the comment
+					.append("select * from ( select ") //nest the main query in an outer select
+					.append( getRowNumber(sql) ); //add the rownnumber bit into the outer query select list
+
+		if ( hasDistinct(sql) ) {
+			pagingSelect.append(" row_.* from ( ") //add another (inner) nested select
+				.append( sql.substring(startOfSelect) ) //add the main query
+				.append(" ) as row_"); //close off the inner nested select
+		}
+		else {
+			pagingSelect.append( sql.substring( startOfSelect + 6 ) ); //add the main query
+		}
+
+		pagingSelect.append(" ) as temp_ where rownumber_ ");
+
+		//add the restriction to the outer select
+		if (hasOffset) {
+			pagingSelect.append("between ?+1 and ?");
+		}
+		else {
+			pagingSelect.append("<= ?");
+		}
+
+		return pagingSelect.toString();
+	}
+
+	private static boolean hasDistinct(String sql) {
+		return sql.toLowerCase().indexOf("select distinct")>=0;
+	}
+
+	public String getForUpdateString() {
+		return " for read only with rs";
+	}
+
+	public boolean useMaxForLimit() {
+		return true;
+	}
+
+	public boolean supportsOuterJoinForUpdate() {
+		return false;
+	}
+
+	public boolean supportsNotNullUnique() {
+		return false;
+	}
+
+	public String getSelectClauseNullString(int sqlType) {
+		String literal;
+		switch(sqlType) {
+			case Types.VARCHAR:
+			case Types.CHAR:
+				literal = "'x'";
+				break;
+			case Types.DATE:
+				literal = "'2000-1-1'";
+				break;
+			case Types.TIMESTAMP:
+				literal = "'2000-1-1 00:00:00'";
+				break;
+			case Types.TIME:
+				literal = "'00:00:00'";
+				break;
+			default:
+				literal = "0";
+		}
+		return "nullif(" + literal + ',' + literal + ')';
+	}
+
+	public static void main(String[] args) {
+		System.out.println( new DB2Dialect().getLimitString("/*foo*/ select * from foos", true) );
+		System.out.println( new DB2Dialect().getLimitString("/*foo*/ select distinct * from foos", true) );
+		System.out.println( new DB2Dialect().getLimitString("/*foo*/ select * from foos foo order by foo.bar, foo.baz", true) );
+		System.out.println( new DB2Dialect().getLimitString("/*foo*/ select distinct * from foos foo order by foo.bar, foo.baz", true) );
+	}
+
+	public boolean supportsUnionAll() {
+		return true;
+	}
+
+	public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
+		return col;
+	}
+
+	public ResultSet getResultSet(CallableStatement ps) throws SQLException {
+		boolean isResultSet = ps.execute();
+		// This assumes you will want to ignore any update counts 
+		while (!isResultSet && ps.getUpdateCount() != -1) {
+		    isResultSet = ps.getMoreResults();
+		}
+		ResultSet rs = ps.getResultSet();
+		// You may still have other ResultSets or update counts left to process here 
+		// but you can't do it now or the ResultSet you just got will be closed 
+		return rs;
+	}
+
+	public boolean supportsCommentOn() {
+		return true;
+	}
+
+	public boolean supportsTemporaryTables() {
+		return true;
+	}
+
+	public String getCreateTemporaryTableString() {
+		return "declare global temporary table";
+	}
+
+	public String getCreateTemporaryTablePostfix() {
+		return "not logged";
+	}
+
+	public String generateTemporaryTableName(String baseTableName) {
+		return "session." + super.generateTemporaryTableName(baseTableName);
+	}
+
+	public boolean supportsCurrentTimestampSelection() {
+		return true;
+	}
+
+	public String getCurrentTimestampSelectString() {
+		return "values current timestamp";
+	}
+
+	public boolean isCurrentTimestampSelectStringCallable() {
+		return false;
+	}
+
+	public boolean supportsParametersInInsertSelect() {
+		// DB2 known to not support parameters within the select
+		// clause of an SQL INSERT ... SELECT ... statement
+		return false;
+	}
+
+	public String getCurrentTimestampSQLFunctionName() {
+		return "sysdate";
+	}
+
+	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsEmptyInList() {
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DataDirectOracle9Dialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DataDirectOracle9Dialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DataDirectOracle9Dialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+package org.hibernate.dialect;
+
+import java.sql.CallableStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class DataDirectOracle9Dialect extends Oracle9Dialect {
+	
+	public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
+		return col; // sql server just returns automatically
+	}
+	
+	public ResultSet getResultSet(CallableStatement ps) throws SQLException {
+		boolean isResultSet = ps.execute(); 
+//		 This assumes you will want to ignore any update counts 
+		while (!isResultSet && ps.getUpdateCount() != -1) { 
+		    isResultSet = ps.getMoreResults(); 
+		} 
+		ResultSet rs = ps.getResultSet(); 
+//		 You may still have other ResultSets or update counts left to process here 
+//		 but you can't do it now or the ResultSet you just got will be closed 
+		return rs;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DerbyDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DerbyDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DerbyDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,198 @@
+//$Id: DerbyDialect.java 10988 2006-12-13 18:37:01Z steve.ebersole at jboss.com $
+package org.hibernate.dialect;
+
+import org.hibernate.Hibernate;
+import org.hibernate.QueryException;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+import org.hibernate.dialect.function.VarArgsSQLFunction;
+import org.hibernate.dialect.function.SQLFunction;
+import org.hibernate.dialect.function.SQLFunctionTemplate;
+import org.hibernate.id.TableHiLoGenerator;
+import org.hibernate.sql.CaseFragment;
+import org.hibernate.sql.DerbyCaseFragment;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @author Simon Johnston
+ *
+ * Hibernate Dialect for Cloudscape 10 - aka Derby. This implements both an 
+ * override for the identity column generator as well as for the case statement
+ * issue documented at:
+ * http://www.jroller.com/comments/kenlars99/Weblog/cloudscape_soon_to_be_derby
+ */
+public class DerbyDialect extends DB2Dialect {
+
+	public DerbyDialect() {
+		super();
+		registerFunction( "concat", new VarArgsSQLFunction( Hibernate.STRING, "(","||",")" ) );
+		registerFunction( "trim", new DerbyTrimFunctionEmulation() );
+	}
+
+	/**
+	 * This is different in Cloudscape to DB2.
+	 */
+	public String getIdentityColumnString() {
+		return "not null generated always as identity"; //$NON-NLS-1
+	}
+
+	/**
+	 * Return the case statement modified for Cloudscape.
+	 */
+	public CaseFragment createCaseFragment() {
+		return new DerbyCaseFragment();
+	}
+
+	public boolean dropConstraints() {
+	      return true;
+	}
+
+	public Class getNativeIdentifierGeneratorClass() {
+		return TableHiLoGenerator.class;
+	}
+
+	public boolean supportsSequences() {
+		return false;
+	}
+
+	public boolean supportsLimit() {
+		return false;
+	}
+
+	public boolean supportsLimitOffset() {
+		return false;
+	}
+
+	public String getQuerySequencesString() {
+	   return null ;
+	}
+
+	/**
+	 * A specialized function template to emulate the ANSI trim function on Derby DB
+	 * since it does not support the full trim specification.  However, we cannot even
+	 * fully emulate it because there is not standard 'replace' function either. :(
+	 */
+	public static class DerbyTrimFunctionEmulation implements SQLFunction {
+		private static final SQLFunction LEADING_SPACE_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "ltrim( ?1 )");
+		private static final SQLFunction TRAILING_SPACE_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "rtrim( ?1 )");
+		private static final SQLFunction BOTH_SPACE_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "ltrim( rtrim( ?1 ) )");
+		private static final SQLFunction BOTH_SPACE_TRIM_FROM = new SQLFunctionTemplate( Hibernate.STRING, "ltrim( rtrim( ?2 ) )");
+
+		public Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
+			return Hibernate.STRING;
+		}
+
+		public boolean hasArguments() {
+			return true;
+		}
+
+		public boolean hasParenthesesIfNoArguments() {
+			return false;
+		}
+
+		public String render(List args, SessionFactoryImplementor factory) throws QueryException {
+			// according to both the ANSI-SQL and EJB3 specs, trim can either take
+			// exactly one parameter or a variable number of parameters between 1 and 4.
+			// from the SQL spec:
+			//
+			// <trim function> ::=
+			//      TRIM <left paren> <trim operands> <right paren>
+			//
+			// <trim operands> ::=
+			//      [ [ <trim specification> ] [ <trim character> ] FROM ] <trim source>
+			//
+			// <trim specification> ::=
+			//      LEADING
+			//      | TRAILING
+			//      | BOTH
+			//
+			// If only <trim specification> is omitted, BOTH is assumed;
+			// if <trim character> is omitted, space is assumed
+			if ( args.size() == 1 ) {
+				// we have the form: trim(trimSource)
+				//      so we trim leading and trailing spaces
+				return BOTH_SPACE_TRIM.render( args, factory );
+			}
+			else if ( "from".equalsIgnoreCase( ( String ) args.get( 0 ) ) ) {
+				// we have the form: trim(from trimSource).
+				//      This is functionally equivalent to trim(trimSource)
+				return BOTH_SPACE_TRIM_FROM.render( args, factory );
+			}
+			else {
+				// otherwise, a trim-specification and/or a trim-character
+				// have been specified;  we need to decide which options
+				// are present and "do the right thing"
+				boolean leading = true;         // should leading trim-characters be trimmed?
+				boolean trailing = true;        // should trailing trim-characters be trimmed?
+				String trimCharacter;    		// the trim-character
+				String trimSource;       		// the trim-source
+
+				// potentialTrimCharacterArgIndex = 1 assumes that a
+				// trim-specification has been specified.  we handle the
+				// exception to that explicitly
+				int potentialTrimCharacterArgIndex = 1;
+				String firstArg = ( String ) args.get( 0 );
+				if ( "leading".equalsIgnoreCase( firstArg ) ) {
+					trailing = false;
+				}
+				else if ( "trailing".equalsIgnoreCase( firstArg ) ) {
+					leading = false;
+				}
+				else if ( "both".equalsIgnoreCase( firstArg ) ) {
+				}
+				else {
+					potentialTrimCharacterArgIndex = 0;
+				}
+
+				String potentialTrimCharacter = ( String ) args.get( potentialTrimCharacterArgIndex );
+				if ( "from".equalsIgnoreCase( potentialTrimCharacter ) ) {
+					trimCharacter = "' '";
+					trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 1 );
+				}
+				else if ( potentialTrimCharacterArgIndex + 1 >= args.size() ) {
+					trimCharacter = "' '";
+					trimSource = potentialTrimCharacter;
+				}
+				else {
+					trimCharacter = potentialTrimCharacter;
+					if ( "from".equalsIgnoreCase( ( String ) args.get( potentialTrimCharacterArgIndex + 1 ) ) ) {
+						trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 2 );
+					}
+					else {
+						trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 1 );
+					}
+				}
+
+				List argsToUse = new ArrayList();
+				argsToUse.add( trimSource );
+				argsToUse.add( trimCharacter );
+
+				if ( trimCharacter.equals( "' '" ) ) {
+					if ( leading && trailing ) {
+						return BOTH_SPACE_TRIM.render( argsToUse, factory );
+					}
+					else if ( leading ) {
+						return LEADING_SPACE_TRIM.render( argsToUse, factory );
+					}
+					else {
+						return TRAILING_SPACE_TRIM.render( argsToUse, factory );
+					}
+				}
+				else {
+					throw new HibernateException( "cannot specify trim character when using Derby as Derby does not support the ANSI trim function, not does it support a replace function to properly emmulate it" );
+				}
+			}
+		}
+	}
+
+
+	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsLobValueChangePropogation() {
+		return false;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DerbyDialect.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Dialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Dialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Dialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1763 @@
+//$Id: Dialect.java 11303 2007-03-19 22:06:14Z steve.ebersole at jboss.com $
+package org.hibernate.dialect;
+
+import java.sql.CallableStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.CastFunction;
+import org.hibernate.dialect.function.SQLFunction;
+import org.hibernate.dialect.function.SQLFunctionTemplate;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.dialect.lock.LockingStrategy;
+import org.hibernate.dialect.lock.SelectLockingStrategy;
+import org.hibernate.engine.Mapping;
+import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.exception.SQLStateConverter;
+import org.hibernate.exception.ViolatedConstraintNameExtracter;
+import org.hibernate.id.IdentityGenerator;
+import org.hibernate.id.SequenceGenerator;
+import org.hibernate.id.TableHiLoGenerator;
+import org.hibernate.mapping.Column;
+import org.hibernate.persister.entity.Lockable;
+import org.hibernate.sql.ANSICaseFragment;
+import org.hibernate.sql.ANSIJoinFragment;
+import org.hibernate.sql.CaseFragment;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.sql.ForUpdateFragment;
+import org.hibernate.type.Type;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Represents a dialect of SQL implemented by a particular RDBMS.
+ * Subclasses implement Hibernate compatibility with different systems.<br>
+ * <br>
+ * Subclasses should provide a public default constructor that <tt>register()</tt>
+ * a set of type mappings and default Hibernate properties.<br>
+ * <br>
+ * Subclasses should be immutable.
+ *
+ * @author Gavin King, David Channon
+ */
+public abstract class Dialect {
+
+	private static final Log log = LogFactory.getLog( Dialect.class );
+
+	public static final String DEFAULT_BATCH_SIZE = "15";
+	public static final String NO_BATCH = "0";
+
+	/**
+	 * Characters used for quoting SQL identifiers
+	 */
+	public static final String QUOTE = "`\"[";
+	public static final String CLOSED_QUOTE = "`\"]";
+
+
+	// build the map of standard ANSI SQL aggregation functions ~~~~~~~~~~~~~~~
+
+	private static final Map STANDARD_AGGREGATE_FUNCTIONS = new HashMap();
+	static {
+		STANDARD_AGGREGATE_FUNCTIONS.put( "count", new StandardSQLFunction("count") {
+			public Type getReturnType(Type columnType, Mapping mapping) {
+				return Hibernate.LONG;
+			}
+		} );
+
+		STANDARD_AGGREGATE_FUNCTIONS.put( "avg", new StandardSQLFunction("avg") {
+			public Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
+				int[] sqlTypes;
+				try {
+					sqlTypes = columnType.sqlTypes( mapping );
+				}
+				catch ( MappingException me ) {
+					throw new QueryException( me );
+				}
+				if ( sqlTypes.length != 1 ) throw new QueryException( "multi-column type in avg()" );
+				return Hibernate.DOUBLE;
+			}
+		} );
+
+		STANDARD_AGGREGATE_FUNCTIONS.put( "max", new StandardSQLFunction("max") );
+		STANDARD_AGGREGATE_FUNCTIONS.put( "min", new StandardSQLFunction("min") );
+		STANDARD_AGGREGATE_FUNCTIONS.put( "sum", new StandardSQLFunction("sum") {
+			public Type getReturnType(Type columnType, Mapping mapping) {
+				//pre H3.2 behavior: super.getReturnType(ct, m);
+				int[] sqlTypes;
+				try {
+					sqlTypes = columnType.sqlTypes( mapping );
+				}
+				catch ( MappingException me ) {
+					throw new QueryException( me );
+				}
+				if ( sqlTypes.length != 1 ) throw new QueryException( "multi-column type in sum()" );
+				int sqlType = sqlTypes[0];
+
+				// First allow the actual type to control the return value. (the actual underlying sqltype could actually be different)
+				if ( columnType == Hibernate.BIG_INTEGER ) {
+					return Hibernate.BIG_INTEGER;
+				}
+				else if ( columnType == Hibernate.BIG_DECIMAL ) {
+					return Hibernate.BIG_DECIMAL;
+				}
+				else if ( columnType == Hibernate.LONG || columnType == Hibernate.SHORT || columnType == Hibernate.INTEGER) {
+					return Hibernate.LONG;
+				}
+				else if ( columnType == Hibernate.FLOAT || columnType == Hibernate.DOUBLE) {
+					return Hibernate.DOUBLE;
+				}
+
+				// finally use the sqltype if == on Hibernate types did not find a match.
+				if ( sqlType == Types.NUMERIC ) {
+					return columnType; //because numeric can be anything
+				}
+				else if ( sqlType == Types.FLOAT || sqlType == Types.DOUBLE || sqlType == Types.DECIMAL || sqlType == Types.REAL) {
+					return Hibernate.DOUBLE;
+				}
+				else if ( sqlType == Types.BIGINT || sqlType == Types.INTEGER || sqlType == Types.SMALLINT || sqlType == Types.TINYINT ) {
+					return Hibernate.LONG;
+				}
+				else {
+					return columnType;
+				}
+			}
+		});
+	}
+
+	private final TypeNames typeNames = new TypeNames();
+	private final TypeNames hibernateTypeNames = new TypeNames();
+
+	private final Properties properties = new Properties();
+	private final Map sqlFunctions = new HashMap();
+	private final Set sqlKeywords = new HashSet();
+
+
+	// constructors and factory methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	protected Dialect() {
+		log.info( "Using dialect: " + this );
+		sqlFunctions.putAll( STANDARD_AGGREGATE_FUNCTIONS );
+
+		// standard sql92 functions (can be overridden by subclasses)
+		registerFunction( "substring", new SQLFunctionTemplate( Hibernate.STRING, "substring(?1, ?2, ?3)" ) );
+		registerFunction( "locate", new SQLFunctionTemplate( Hibernate.INTEGER, "locate(?1, ?2, ?3)" ) );
+		registerFunction( "trim", new SQLFunctionTemplate( Hibernate.STRING, "trim(?1 ?2 ?3 ?4)" ) );
+		registerFunction( "length", new StandardSQLFunction( "length", Hibernate.INTEGER ) );
+		registerFunction( "bit_length", new StandardSQLFunction( "bit_length", Hibernate.INTEGER ) );
+		registerFunction( "coalesce", new StandardSQLFunction( "coalesce" ) );
+		registerFunction( "nullif", new StandardSQLFunction( "nullif" ) );
+		registerFunction( "abs", new StandardSQLFunction( "abs" ) );
+		registerFunction( "mod", new StandardSQLFunction( "mod", Hibernate.INTEGER) );
+		registerFunction( "sqrt", new StandardSQLFunction( "sqrt", Hibernate.DOUBLE) );
+		registerFunction( "upper", new StandardSQLFunction("upper") );
+		registerFunction( "lower", new StandardSQLFunction("lower") );
+		registerFunction( "cast", new CastFunction() );
+		registerFunction( "extract", new SQLFunctionTemplate(Hibernate.INTEGER, "extract(?1 ?2 ?3)") );
+
+		//map second/minute/hour/day/month/year to ANSI extract(), override on subclasses
+		registerFunction( "second", new SQLFunctionTemplate(Hibernate.INTEGER, "extract(second from ?1)") );
+		registerFunction( "minute", new SQLFunctionTemplate(Hibernate.INTEGER, "extract(minute from ?1)") );
+		registerFunction( "hour", new SQLFunctionTemplate(Hibernate.INTEGER, "extract(hour from ?1)") );
+		registerFunction( "day", new SQLFunctionTemplate(Hibernate.INTEGER, "extract(day from ?1)") );
+		registerFunction( "month", new SQLFunctionTemplate(Hibernate.INTEGER, "extract(month from ?1)") );
+		registerFunction( "year", new SQLFunctionTemplate(Hibernate.INTEGER, "extract(year from ?1)") );
+
+		registerFunction( "str", new SQLFunctionTemplate(Hibernate.STRING, "cast(?1 as char)") );
+
+        // register hibernate types for default use in scalar sqlquery type auto detection
+		registerHibernateType( Types.BIGINT, Hibernate.BIG_INTEGER.getName() );
+		registerHibernateType( Types.BINARY, Hibernate.BINARY.getName() );
+		registerHibernateType( Types.BIT, Hibernate.BOOLEAN.getName() );
+		registerHibernateType( Types.CHAR, Hibernate.CHARACTER.getName() );
+		registerHibernateType( Types.DATE, Hibernate.DATE.getName() );
+		registerHibernateType( Types.DOUBLE, Hibernate.DOUBLE.getName() );
+		registerHibernateType( Types.FLOAT, Hibernate.FLOAT.getName() );
+		registerHibernateType( Types.INTEGER, Hibernate.INTEGER.getName() );
+		registerHibernateType( Types.SMALLINT, Hibernate.SHORT.getName() );
+		registerHibernateType( Types.TINYINT, Hibernate.BYTE.getName() );
+		registerHibernateType( Types.TIME, Hibernate.TIME.getName() );
+		registerHibernateType( Types.TIMESTAMP, Hibernate.TIMESTAMP.getName() );
+		registerHibernateType( Types.VARCHAR, Hibernate.STRING.getName() );
+		registerHibernateType( Types.VARBINARY, Hibernate.BINARY.getName() );
+		registerHibernateType( Types.NUMERIC, Hibernate.BIG_DECIMAL.getName() );
+		registerHibernateType( Types.DECIMAL, Hibernate.BIG_DECIMAL.getName() );
+		registerHibernateType( Types.BLOB, Hibernate.BLOB.getName() );
+		registerHibernateType( Types.CLOB, Hibernate.CLOB.getName() );
+	}
+
+	/**
+	 * Get an instance of the dialect specified by the current <tt>System</tt> properties.
+	 *
+	 * @return The specified Dialect
+	 * @throws HibernateException If no dialect was specified, or if it could not be instantiated.
+	 */
+	public static Dialect getDialect() throws HibernateException {
+		String dialectName = Environment.getProperties().getProperty( Environment.DIALECT );
+		return instantiateDialect( dialectName );
+	}
+
+
+	/**
+	 * Get an instance of the dialect specified by the given properties or by
+	 * the current <tt>System</tt> properties.
+	 *
+	 * @param props The properties to use for finding the dialect class to use.
+	 * @return The specified Dialect
+	 * @throws HibernateException If no dialect was specified, or if it could not be instantiated.
+	 */
+	public static Dialect getDialect(Properties props) throws HibernateException {
+		String dialectName = props.getProperty( Environment.DIALECT );
+		if ( dialectName == null ) {
+			return getDialect();
+		}
+		return instantiateDialect( dialectName );
+	}
+
+	private static Dialect instantiateDialect(String dialectName) throws HibernateException {
+		if ( dialectName == null ) {
+			throw new HibernateException( "The dialect was not set. Set the property hibernate.dialect." );
+		}
+		try {
+			return ( Dialect ) ReflectHelper.classForName( dialectName ).newInstance();
+		}
+		catch ( ClassNotFoundException cnfe ) {
+			throw new HibernateException( "Dialect class not found: " + dialectName );
+		}
+		catch ( Exception e ) {
+			throw new HibernateException( "Could not instantiate dialect class", e );
+		}
+	}
+
+	/**
+	 * Retrieve a set of default Hibernate properties for this database.
+	 *
+	 * @return a set of Hibernate properties
+	 */
+	public final Properties getDefaultProperties() {
+		return properties;
+	}
+
+	public String toString() {
+		return getClass().getName();
+	}
+
+
+	// database type mapping support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Get the name of the database type associated with the given
+	 * {@link java.sql.Types} typecode.
+	 *
+	 * @param code The {@link java.sql.Types} typecode
+	 * @return the database type name
+	 * @throws HibernateException If no mapping was specified for that type.
+	 */
+	public String getTypeName(int code) throws HibernateException {
+		String result = typeNames.get( code );
+		if ( result == null ) {
+			throw new HibernateException( "No default type mapping for (java.sql.Types) " + code );
+		}
+		return result;
+	}
+
+	/**
+	 * Get the name of the database type associated with the given
+	 * {@link java.sql.Types} typecode with the given storage specification
+	 * parameters.
+	 *
+	 * @param code The {@link java.sql.Types} typecode
+	 * @param length The datatype length
+	 * @param precision The datatype precision
+	 * @param scale The datatype scale
+	 * @return the database type name
+	 * @throws HibernateException If no mapping was specified for that type.
+	 */
+	public String getTypeName(int code, int length, int precision, int scale) throws HibernateException {
+		String result = typeNames.get( code, length, precision, scale );
+		if ( result == null ) {
+			throw new HibernateException(
+					"No type mapping for java.sql.Types code: " +
+					code +
+					", length: " +
+					length
+			);
+		}
+		return result;
+	}
+
+	/**
+	 * Get the name of the database type appropriate for casting operations
+	 * (via the CAST() SQL function) for the given {@link java.sql.Types} typecode.
+	 *
+	 * @param code The {@link java.sql.Types} typecode
+	 * @return The database type name
+	 */
+	public String getCastTypeName(int code) {
+		return getTypeName( code, Column.DEFAULT_LENGTH, Column.DEFAULT_PRECISION, Column.DEFAULT_SCALE );
+	}
+
+	/**
+	 * Subclasses register a type name for the given type code and maximum
+	 * column length. <tt>$l</tt> in the type name with be replaced by the
+	 * column length (if appropriate).
+	 *
+	 * @param code The {@link java.sql.Types} typecode
+	 * @param capacity The maximum length of database type
+	 * @param name The database type name
+	 */
+	protected void registerColumnType(int code, int capacity, String name) {
+		typeNames.put( code, capacity, name );
+	}
+
+	/**
+	 * Subclasses register a type name for the given type code. <tt>$l</tt> in
+	 * the type name with be replaced by the column length (if appropriate).
+	 *
+	 * @param code The {@link java.sql.Types} typecode
+	 * @param name The database type name
+	 */
+	protected void registerColumnType(int code, String name) {
+		typeNames.put( code, name );
+	}
+
+
+	// hibernate type mapping support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Get the name of the Hibernate {@link org.hibernate.type.Type} associated with th given
+	 * {@link java.sql.Types} typecode.
+	 *
+	 * @param code The {@link java.sql.Types} typecode
+	 * @return The Hibernate {@link org.hibernate.type.Type} name.
+	 * @throws HibernateException If no mapping was specified for that type.
+	 */
+	public String getHibernateTypeName(int code) throws HibernateException {
+		String result = hibernateTypeNames.get( code );
+		if ( result == null ) {
+			throw new HibernateException( "No Hibernate type mapping for java.sql.Types code: " + code );
+		}
+		return result;
+	}
+
+	/**
+	 * Get the name of the Hibernate {@link org.hibernate.type.Type} associated
+	 * with the given {@link java.sql.Types} typecode with the given storage
+	 * specification parameters.
+	 *
+	 * @param code The {@link java.sql.Types} typecode
+	 * @param length The datatype length
+	 * @param precision The datatype precision
+	 * @param scale The datatype scale
+	 * @return The Hibernate {@link org.hibernate.type.Type} name.
+	 * @throws HibernateException If no mapping was specified for that type.
+	 */
+	public String getHibernateTypeName(int code, int length, int precision, int scale) throws HibernateException {
+		String result = hibernateTypeNames.get( code, length, precision, scale );
+		if ( result == null ) {
+			throw new HibernateException(
+					"No Hibernate type mapping for java.sql.Types code: " +
+					code +
+					", length: " +
+					length
+			);
+		}
+		return result;
+	}
+
+	/**
+	 * Registers a Hibernate {@link org.hibernate.type.Type} name for the given
+	 * {@link java.sql.Types} type code and maximum column length.
+	 *
+	 * @param code The {@link java.sql.Types} typecode
+	 * @param capacity The maximum length of database type
+	 * @param name The Hibernate {@link org.hibernate.type.Type} name
+	 */
+	protected void registerHibernateType(int code, int capacity, String name) {
+		hibernateTypeNames.put( code, capacity, name);
+	}
+
+	/**
+	 * Registers a Hibernate {@link org.hibernate.type.Type} name for the given
+	 * {@link java.sql.Types} type code.
+	 *
+	 * @param code The {@link java.sql.Types} typecode
+	 * @param name The Hibernate {@link org.hibernate.type.Type} name
+	 */
+	protected void registerHibernateType(int code, String name) {
+		hibernateTypeNames.put( code, name);
+	}
+
+
+	// function support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	protected void registerFunction(String name, SQLFunction function) {
+		sqlFunctions.put( name, function );
+	}
+
+	/**
+	 * Retrieves a map of the dialect's registered fucntions
+	 * (functionName => {@link org.hibernate.dialect.function.SQLFunction}).
+	 *
+	 * @return The map of registered functions.
+	 */
+	public final Map getFunctions() {
+		return sqlFunctions;
+	}
+
+
+	// keyword support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	protected void registerKeyword(String word) {
+		sqlKeywords.add(word);
+	}
+
+	public Set getKeywords() {
+		return sqlKeywords;
+	}
+
+
+	// native identifier generatiion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * The class (which implements {@link org.hibernate.id.IdentifierGenerator})
+	 * which acts as this dialects native generation strategy.
+	 * <p/>
+	 * Comes into play whenever the user specifies the native generator.
+	 *
+	 * @return The native generator class.
+	 */
+	public Class getNativeIdentifierGeneratorClass() {
+		if ( supportsIdentityColumns() ) {
+			return IdentityGenerator.class;
+		}
+		else if ( supportsSequences() ) {
+			return SequenceGenerator.class;
+		}
+		else {
+			return TableHiLoGenerator.class;
+		}
+	}
+
+
+	// IDENTITY support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Does this dialect support identity column key generation?
+	 *
+	 * @return True if IDENTITY columns are supported; false otherwise.
+	 */
+	public boolean supportsIdentityColumns() {
+		return false;
+	}
+
+	/**
+	 * Does the dialect support some form of inserting and selecting
+	 * the generated IDENTITY value all in the same statement.
+	 *
+	 * @return True if the dialect supports selecting the just
+	 * generated IDENTITY in the insert statement.
+	 */
+	public boolean supportsInsertSelectIdentity() {
+		return false;
+	}
+
+	/**
+	 * Whether this dialect have an Identity clause added to the data type or a
+	 * completely seperate identity data type
+	 *
+	 * @return boolean
+	 */
+	public boolean hasDataTypeInIdentityColumn() {
+		return true;
+	}
+
+	/**
+	 * Provided we {@link #supportsInsertSelectIdentity}, then attch the
+	 * "select identity" clause to the  insert statement.
+	 *  <p/>
+	 * Note, if {@link #supportsInsertSelectIdentity} == false then
+	 * the insert-string should be returned without modification.
+	 *
+	 * @param insertString The insert command
+	 * @return The insert command with any necessary identity select
+	 * clause attached.
+	 */
+	public String appendIdentitySelectToInsert(String insertString) {
+		return insertString;
+	}
+
+	/**
+	 * Get the select command to use to retrieve the last generated IDENTITY
+	 * value for a particuar table
+	 *
+	 * @param table The table into which the insert was done
+	 * @param column The PK column.
+	 * @param type The {@link java.sql.Types} type code.
+	 * @return The appropriate select command
+	 * @throws MappingException If IDENTITY generation is not supported.
+	 */
+	public String getIdentitySelectString(String table, String column, int type) throws MappingException {
+		return getIdentitySelectString();
+	}
+
+	/**
+	 * Get the select command to use to retrieve the last generated IDENTITY
+	 * value.
+	 *
+	 * @return The appropriate select command
+	 * @throws MappingException If IDENTITY generation is not supported.
+	 */
+	protected String getIdentitySelectString() throws MappingException {
+		throw new MappingException( "Dialect does not support identity key generation" );
+	}
+
+	/**
+	 * The syntax used during DDL to define a column as being an IDENTITY of
+	 * a particular type.
+	 *
+	 * @param type The {@link java.sql.Types} type code.
+	 * @return The appropriate DDL fragment.
+	 * @throws MappingException If IDENTITY generation is not supported.
+	 */
+	public String getIdentityColumnString(int type) throws MappingException {
+		return getIdentityColumnString();
+	}
+
+	/**
+	 * The syntax used during DDL to define a column as being an IDENTITY.
+	 *
+	 * @return The appropriate DDL fragment.
+	 * @throws MappingException If IDENTITY generation is not supported.
+	 */
+	protected String getIdentityColumnString() throws MappingException {
+		throw new MappingException( "Dialect does not support identity key generation" );
+	}
+
+	/**
+	 * The keyword used to insert a generated value into an identity column (or null).
+	 * Need if the dialect does not support inserts that specify no column values.
+	 *
+	 * @return The appropriate keyword.
+	 */
+	public String getIdentityInsertString() {
+		return null;
+	}
+
+
+	// SEQUENCE support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Does this dialect support sequences?
+	 *
+	 * @return True if sequences supported; false otherwise.
+	 */
+	public boolean supportsSequences() {
+		return false;
+	}
+
+	/**
+	 * Does this dialect support "pooled" sequences.  Not aware of a better
+	 * name for this.  Essentially can we specify the initial and increment values?
+	 *
+	 * @return True if such "pooled" sequences are supported; false otherwise.
+	 * @see #getCreateSequenceStrings(String, int, int)
+	 * @see #getCreateSequenceString(String, int, int)
+	 */
+	public boolean supportsPooledSequences() {
+		return false;
+	}
+
+	/**
+	 * Generate the appropriate select statement to to retreive the next value
+	 * of a sequence.
+	 * <p/>
+	 * This should be a "stand alone" select statement.
+	 *
+	 * @param sequenceName the name of the sequence
+	 * @return String The "nextval" select string.
+	 * @throws MappingException If sequences are not supported.
+	 */
+	public String getSequenceNextValString(String sequenceName) throws MappingException {
+		throw new MappingException( "Dialect does not support sequences" );
+	}
+
+	/**
+	 * Generate the select expression fragment that will retreive the next
+	 * value of a sequence as part of another (typically DML) statement.
+	 * <p/>
+	 * This differs from {@link #getSequenceNextValString(String)} in that this
+	 * should return an expression usable within another statement.
+	 *
+	 * @param sequenceName the name of the sequence
+	 * @return The "nextval" fragment.
+	 * @throws MappingException If sequences are not supported.
+	 */
+	public String getSelectSequenceNextValString(String sequenceName) throws MappingException {
+		throw new MappingException( "Dialect does not support sequences" );
+	}
+
+	/**
+	 * The multiline script used to create a sequence.
+	 *
+	 * @param sequenceName The name of the sequence
+	 * @return The sequence creation commands
+	 * @throws MappingException If sequences are not supported.
+	 * @deprecated Use {@link #getCreateSequenceString(String, int, int)} instead
+	 */
+	public String[] getCreateSequenceStrings(String sequenceName) throws MappingException {
+		return new String[] { getCreateSequenceString( sequenceName ) };
+	}
+
+	/**
+	 * An optional multi-line form for databases which {@link #supportsPooledSequences()}.
+	 *
+	 * @param sequenceName The name of the sequence
+	 * @param initialValue The initial value to apply to 'create sequence' statement
+	 * @param incrementSize The increment value to apply to 'create sequence' statement
+	 * @return The sequence creation commands
+	 * @throws MappingException If sequences are not supported.
+	 */
+	public String[] getCreateSequenceStrings(String sequenceName, int initialValue, int incrementSize) throws MappingException {
+		return new String[] { getCreateSequenceString( sequenceName, initialValue, incrementSize ) };
+	}
+
+	/**
+	 * Typically dialects which support sequences can create a sequence
+	 * with a single command.  This is convenience form of
+	 * {@link #getCreateSequenceStrings} to help facilitate that.
+	 * <p/>
+	 * Dialects which support sequences and can create a sequence in a
+	 * single command need *only* override this method.  Dialects
+	 * which support sequences but require multiple commands to create
+	 * a sequence should instead override {@link #getCreateSequenceStrings}.
+	 *
+	 * @param sequenceName The name of the sequence
+	 * @return The sequence creation command
+	 * @throws MappingException If sequences are not supported.
+	 */
+	protected String getCreateSequenceString(String sequenceName) throws MappingException {
+		throw new MappingException( "Dialect does not support sequences" );
+	}
+
+	/**
+	 * Overloaded form of {@link #getCreateSequenceString(String)}, additionally
+	 * taking the initial value and increment size to be applied to the sequence
+	 * definition.
+	 * </p>
+	 * The default definition is to suffix {@link #getCreateSequenceString(String)}
+	 * with the string: " start with {initialValue} increment by {incrementSize}" where
+	 * {initialValue} and {incrementSize} are replacement placeholders.  Generally
+	 * dialects should only need to override this method if different key phrases
+	 * are used to apply the allocation information.
+	 *
+	 * @param sequenceName The name of the sequence
+	 * @param initialValue The initial value to apply to 'create sequence' statement
+	 * @param incrementSize The increment value to apply to 'create sequence' statement
+	 * @return The sequence creation command
+	 * @throws MappingException If sequences are not supported.
+	 */
+	protected String getCreateSequenceString(String sequenceName, int initialValue, int incrementSize) throws MappingException {
+		if ( supportsPooledSequences() ) {
+			return getCreateSequenceString( sequenceName ) + " start with " + initialValue + " increment by " + incrementSize;
+		}
+		throw new MappingException( "Dialect does not support pooled sequences" );
+	}
+
+	/**
+	 * The multiline script used to drop a sequence.
+	 *
+	 * @param sequenceName The name of the sequence
+	 * @return The sequence drop commands
+	 * @throws MappingException If sequences are not supported.
+	 */
+	public String[] getDropSequenceStrings(String sequenceName) throws MappingException {
+		return new String[]{getDropSequenceString( sequenceName )};
+	}
+
+	/**
+	 * Typically dialects which support sequences can drop a sequence
+	 * with a single command.  This is convenience form of
+	 * {@link #getDropSequenceStrings} to help facilitate that.
+	 * <p/>
+	 * Dialects which support sequences and can drop a sequence in a
+	 * single command need *only* override this method.  Dialects
+	 * which support sequences but require multiple commands to drop
+	 * a sequence should instead override {@link #getDropSequenceStrings}.
+	 *
+	 * @param sequenceName The name of the sequence
+	 * @return The sequence drop commands
+	 * @throws MappingException If sequences are not supported.
+	 */
+	protected String getDropSequenceString(String sequenceName) throws MappingException {
+		throw new MappingException( "Dialect does not support sequences" );
+	}
+
+	/**
+	 * Get the select command used retrieve the names of all sequences.
+	 *
+	 * @return The select command; or null if sequences are not supported.
+	 * @see org.hibernate.tool.hbm2ddl.SchemaUpdate
+	 */
+	public String getQuerySequencesString() {
+		return null;
+	}
+
+
+	// GUID support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Get the command used to select a GUID from the underlying database.
+	 * <p/>
+	 * Optional operation.
+	 *
+	 * @return The appropriate command.
+	 */
+	public String getSelectGUIDString() {
+		throw new UnsupportedOperationException( "dialect does not support GUIDs" );
+	}
+
+
+	// limit/offset support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Does this dialect support some form of limiting query results
+	 * via a SQL clause?
+	 *
+	 * @return True if this dialect supports some form of LIMIT.
+	 */
+	public boolean supportsLimit() {
+		return false;
+	}
+
+	/**
+	 * Does this dialect's LIMIT support (if any) additionally
+	 * support specifying an offset?
+	 *
+	 * @return True if the dialect supports an offset within the limit support.
+	 */
+	public boolean supportsLimitOffset() {
+		return supportsLimit();
+	}
+
+	/**
+	 * Does this dialect support bind variables (i.e., prepared statememnt
+	 * parameters) for its limit/offset?
+	 *
+	 * @return True if bind variables can be used; false otherwise.
+	 */
+	public boolean supportsVariableLimit() {
+		return supportsLimit();
+	}
+
+	/**
+	 * ANSI SQL defines the LIMIT clause to be in the form LIMIT offset, limit.
+	 * Does this dialect require us to bind the parameters in reverse order?
+	 *
+	 * @return true if the correct order is limit, offset
+	 */
+	public boolean bindLimitParametersInReverseOrder() {
+		return false;
+	}
+
+	/**
+	 * Does the <tt>LIMIT</tt> clause come at the start of the
+	 * <tt>SELECT</tt> statement, rather than at the end?
+	 *
+	 * @return true if limit parameters should come before other parameters
+	 */
+	public boolean bindLimitParametersFirst() {
+		return false;
+	}
+
+	/**
+	 * Does the <tt>LIMIT</tt> clause take a "maximum" row number instead
+	 * of a total number of returned rows?
+	 * <p/>
+	 * This is easiest understood via an example.  Consider you have a table
+	 * with 20 rows, but you only want to retrieve rows number 11 through 20.
+	 * Generally, a limit with offset would say that the offset = 11 and the
+	 * limit = 10 (we only want 10 rows at a time); this is specifying the
+	 * total number of returned rows.  Some dialects require that we instead
+	 * specify offset = 11 and limit = 20, where 20 is the "last" row we want
+	 * relative to offset (i.e. total number of rows = 20 - 11 = 9)
+	 * <p/>
+	 * So essentially, is limit relative from offset?  Or is limit absolute?
+	 *
+	 * @return True if limit is relative from offset; false otherwise.
+	 */
+	public boolean useMaxForLimit() {
+		return false;
+	}
+
+	/**
+	 * Given a limit and an offset, apply the limit clause to the query.
+	 *
+	 * @param query The query to which to apply the limit.
+	 * @param offset The offset of the limit
+	 * @param limit The limit of the limit ;)
+	 * @return The modified query statement with the limit applied.
+	 */
+	public String getLimitString(String query, int offset, int limit) {
+		return getLimitString( query, offset > 0 );
+	}
+
+	/**
+	 * Apply s limit clause to the query.
+	 * <p/>
+	 * Typically dialects utilize {@link #supportsVariableLimit() variable}
+	 * limit caluses when they support limits.  Thus, when building the
+	 * select command we do not actually need to know the limit or the offest
+	 * since we will just be using placeholders.
+	 * <p/>
+	 * Here we do still pass along whether or not an offset was specified
+	 * so that dialects not supporting offsets can generate proper exceptions.
+	 * In general, dialects will override one or the other of this method and
+	 * {@link #getLimitString(String, int, int)}.
+	 *
+	 * @param query The query to which to apply the limit.
+	 * @param hasOffset Is the query requesting an offset?
+	 * @return the modified SQL
+	 */
+	protected String getLimitString(String query, boolean hasOffset) {
+		throw new UnsupportedOperationException( "paged queries not supported" );
+	}
+
+
+	// lock acquisition support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Get a strategy instance which knows how to acquire a database-level lock
+	 * of the specified mode for this dialect.
+	 *
+	 * @param lockable The persister for the entity to be locked.
+	 * @param lockMode The type of lock to be acquired.
+	 * @return The appropriate locking strategy.
+	 * @since 3.2
+	 */
+	public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
+		return new SelectLockingStrategy( lockable, lockMode );
+	}
+
+	/**
+	 * Given a lock mode, determine the appropriate for update fragment to use.
+	 *
+	 * @param lockMode The lock mode to apply.
+	 * @return The appropriate for update fragment.
+	 */
+	public String getForUpdateString(LockMode lockMode) {
+		if ( lockMode==LockMode.UPGRADE ) {
+			return getForUpdateString();
+		}
+		else if ( lockMode==LockMode.UPGRADE_NOWAIT ) {
+			return getForUpdateNowaitString();
+		}
+		else if ( lockMode==LockMode.FORCE ) {
+			return getForUpdateNowaitString();
+		}
+		else {
+			return "";
+		}
+	}
+
+	/**
+	 * Get the string to append to SELECT statements to acquire locks
+	 * for this dialect.
+	 *
+	 * @return The appropriate <tt>FOR UPDATE</tt> clause string.
+	 */
+	public String getForUpdateString() {
+		return " for update";
+	}
+
+	/**
+	 * Is <tt>FOR UPDATE OF</tt> syntax supported?
+	 *
+	 * @return True if the database supports <tt>FOR UPDATE OF</tt> syntax;
+	 * false otherwise.
+	 */
+	public boolean forUpdateOfColumns() {
+		// by default we report no support
+		return false;
+	}
+
+	/**
+	 * Does this dialect support <tt>FOR UPDATE</tt> in conjunction with
+	 * outer joined rows?
+	 *
+	 * @return True if outer joined rows can be locked via <tt>FOR UPDATE</tt>.
+	 */
+	public boolean supportsOuterJoinForUpdate() {
+		return true;
+	}
+
+	/**
+	 * Get the <tt>FOR UPDATE OF column_list</tt> fragment appropriate for this
+	 * dialect given the aliases of the columns to be write locked.
+	 *
+	 * @param aliases The columns to be write locked.
+	 * @return The appropriate <tt>FOR UPDATE OF column_list</tt> clause string.
+	 */
+	public String getForUpdateString(String aliases) {
+		// by default we simply return the getForUpdateString() result since
+		// the default is to say no support for "FOR UPDATE OF ..."
+		return getForUpdateString();
+	}
+
+	/**
+	 * Retrieves the <tt>FOR UPDATE NOWAIT</tt> syntax specific to this dialect.
+	 *
+	 * @return The appropriate <tt>FOR UPDATE NOWAIT</tt> clause string.
+	 */
+	public String getForUpdateNowaitString() {
+		// by default we report no support for NOWAIT lock semantics
+		return getForUpdateString();
+	}
+
+	/**
+	 * Get the <tt>FOR UPDATE OF column_list NOWAIT</tt> fragment appropriate
+	 * for this dialect given the aliases of the columns to be write locked.
+	 *
+	 * @param aliases The columns to be write locked.
+	 * @return The appropriate <tt>FOR UPDATE colunm_list NOWAIT</tt> clause string.
+	 */
+	public String getForUpdateNowaitString(String aliases) {
+		return getForUpdateString( aliases );
+	}
+
+	/**
+	 * Some dialects support an alternative means to <tt>SELECT FOR UPDATE</tt>,
+	 * whereby a "lock hint" is appends to the table name in the from clause.
+	 * <p/>
+	 * contributed by <a href="http://sourceforge.net/users/heschulz">Helge Schulz</a>
+	 *
+	 * @param mode The lock mode to apply
+	 * @param tableName The name of the table to which to apply the lock hint.
+	 * @return The table with any required lock hints.
+	 */
+	public String appendLockHint(LockMode mode, String tableName) {
+		return tableName;
+	}
+
+	/**
+	 * Modifies the given SQL by applying the appropriate updates for the specified
+	 * lock modes and key columns.
+	 * <p/>
+	 * The behavior here is that of an ANSI SQL <tt>SELECT FOR UPDATE</tt>.  This
+	 * method is really intended to allow dialects which do not support
+	 * <tt>SELECT FOR UPDATE</tt> to achieve this in their own fashion.
+	 *
+	 * @param sql the SQL string to modify
+	 * @param aliasedLockModes a map of lock modes indexed by aliased table names.
+	 * @param keyColumnNames a map of key columns indexed by aliased table names.
+	 * @return the modified SQL string.
+	 */
+	public String applyLocksToSql(String sql, Map aliasedLockModes, Map keyColumnNames) {
+		return sql + new ForUpdateFragment( this, aliasedLockModes, keyColumnNames ).toFragmentString();
+	}
+
+
+	// table support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Command used to create a table.
+	 *
+	 * @return The command used to create a table.
+	 */
+	public String getCreateTableString() {
+		return "create table";
+	}
+
+	/**
+	 * Slight variation on {@link #getCreateTableString}.  Here, we have the
+	 * command used to create a table when there is no primary key and
+	 * duplicate rows are expected.
+	 * <p/>
+	 * Most databases do not care about the distinction; originally added for
+	 * Teradata support which does care.
+	 *
+	 * @return The command used to create a multiset table.
+	 */
+	public String getCreateMultisetTableString() {
+		return getCreateTableString();
+	}
+
+
+	// temporary table support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Does this dialect support temporary tables?
+	 *
+	 * @return True if temp tables are supported; false otherwise.
+	 */
+	public boolean supportsTemporaryTables() {
+		return false;
+	}
+
+	/**
+	 * Generate a temporary table name given the bas table.
+	 *
+	 * @param baseTableName The table name from which to base the temp table name.
+	 * @return The generated temp table name.
+	 */
+	public String generateTemporaryTableName(String baseTableName) {
+		return "HT_" + baseTableName;
+	}
+
+	/**
+	 * Command used to create a temporary table.
+	 *
+	 * @return The command used to create a temporary table.
+	 */
+	public String getCreateTemporaryTableString() {
+		return "create table";
+	}
+
+	/**
+	 * Get any fragments needing to be postfixed to the command for
+	 * temporary table creation.
+	 *
+	 * @return Any required postfix.
+	 */
+	public String getCreateTemporaryTablePostfix() {
+		return "";
+	}
+
+	/**
+	 * Does the dialect require that temporary table DDL statements occur in
+	 * isolation from other statements?  This would be the case if the creation
+	 * would cause any current transaction to get committed implicitly.
+	 * <p/>
+	 * JDBC defines a standard way to query for this information via the
+	 * {@link java.sql.DatabaseMetaData#dataDefinitionCausesTransactionCommit()}
+	 * method.  However, that does not distinguish between temporary table
+	 * DDL and other forms of DDL; MySQL, for example, reports DDL causing a
+	 * transaction commit via its driver, even though that is not the case for
+	 * temporary table DDL.
+	 * <p/>
+	 * Possible return values and their meanings:<ul>
+	 * <li>{@link Boolean#TRUE} - Unequivocally, perform the temporary table DDL
+	 * in isolation.</li>
+	 * <li>{@link Boolean#FALSE} - Unequivocally, do <b>not</b> perform the
+	 * temporary table DDL in isolation.</li>
+	 * <li><i>null</i> - defer to the JDBC driver response in regards to
+	 * {@link java.sql.DatabaseMetaData#dataDefinitionCausesTransactionCommit()}</li>
+	 * </ul>
+	 * 
+	 * @return see the result matrix above.
+	 */
+	public Boolean performTemporaryTableDDLInIsolation() {
+		return null;
+	}
+
+	/**
+	 * Do we need to drop the temporary table after use?
+	 *
+	 * @return True if the table should be dropped.
+	 */
+	public boolean dropTemporaryTableAfterUse() {
+		return true;
+	}
+
+
+	// callable statement support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Registers an OUT parameter which will be returing a
+	 * {@link java.sql.ResultSet}.  How this is accomplished varies greatly
+	 * from DB to DB, hence its inclusion (along with {@link #getResultSet}) here.
+	 *
+	 * @param statement The callable statement.
+	 * @param position The bind position at which to register the OUT param.
+	 * @return The number of (contiguous) bind positions used.
+	 * @throws SQLException Indicates problems registering the OUT param.
+	 */
+	public int registerResultSetOutParameter(CallableStatement statement, int position) throws SQLException {
+		throw new UnsupportedOperationException(
+				getClass().getName() +
+				" does not support resultsets via stored procedures"
+			);
+	}
+
+	/**
+	 * Given a callable statement previously processed by {@link #registerResultSetOutParameter},
+	 * extract the {@link java.sql.ResultSet} from the OUT parameter.
+	 *
+	 * @param statement The callable statement.
+	 * @return The extracted result set.
+	 * @throws SQLException Indicates problems extracting the result set.
+	 */
+	public ResultSet getResultSet(CallableStatement statement) throws SQLException {
+		throw new UnsupportedOperationException(
+				getClass().getName() +
+				" does not support resultsets via stored procedures"
+			);
+	}
+
+	// current timestamp support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Does this dialect support a way to retrieve the database's current
+	 * timestamp value?
+	 *
+	 * @return True if the current timestamp can be retrieved; false otherwise.
+	 */
+	public boolean supportsCurrentTimestampSelection() {
+		return false;
+	}
+
+	/**
+	 * Should the value returned by {@link #getCurrentTimestampSelectString}
+	 * be treated as callable.  Typically this indicates that JDBC escape
+	 * sytnax is being used...
+	 *
+	 * @return True if the {@link #getCurrentTimestampSelectString} return
+	 * is callable; false otherwise.
+	 */
+	public boolean isCurrentTimestampSelectStringCallable() {
+		throw new UnsupportedOperationException( "Database not known to define a current timestamp function" );
+	}
+
+	/**
+	 * Retrieve the command used to retrieve the current timestammp from the
+	 * database.
+	 *
+	 * @return The command.
+	 */
+	public String getCurrentTimestampSelectString() {
+		throw new UnsupportedOperationException( "Database not known to define a current timestamp function" );
+	}
+
+	/**
+	 * The name of the database-specific SQL function for retrieving the
+	 * current timestamp.
+	 *
+	 * @return The function name.
+	 */
+	public String getCurrentTimestampSQLFunctionName() {
+		// the standard SQL function name is current_timestamp...
+		return "current_timestamp";
+	}
+
+
+	// SQLException support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Build an instance of the SQLExceptionConverter preferred by this dialect for
+	 * converting SQLExceptions into Hibernate's JDBCException hierarchy.  The default
+	 * Dialect implementation simply returns a converter based on X/Open SQLState codes.
+	 * <p/>
+	 * It is strongly recommended that specific Dialect implementations override this
+	 * method, since interpretation of a SQL error is much more accurate when based on
+	 * the ErrorCode rather than the SQLState.  Unfortunately, the ErrorCode is a vendor-
+	 * specific approach.
+	 *
+	 * @return The Dialect's preferred SQLExceptionConverter.
+	 */
+	public SQLExceptionConverter buildSQLExceptionConverter() {
+		// The default SQLExceptionConverter for all dialects is based on SQLState
+		// since SQLErrorCode is extremely vendor-specific.  Specific Dialects
+		// may override to return whatever is most appropriate for that vendor.
+		return new SQLStateConverter( getViolatedConstraintNameExtracter() );
+	}
+
+	private static final ViolatedConstraintNameExtracter EXTRACTER = new ViolatedConstraintNameExtracter() {
+		public String extractConstraintName(SQLException sqle) {
+			return null;
+		}
+	};
+
+	public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
+		return EXTRACTER;
+	}
+
+
+	// union subclass support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Given a {@link java.sql.Types} type code, determine an appropriate
+	 * null value to use in a select clause.
+	 * <p/>
+	 * One thing to consider here is that certain databases might
+	 * require proper casting for the nulls here since the select here
+	 * will be part of a UNION/UNION ALL.
+	 *
+	 * @param sqlType The {@link java.sql.Types} type code.
+	 * @return The appropriate select clause value fragment.
+	 */
+	public String getSelectClauseNullString(int sqlType) {
+		return "null";
+	}
+
+	/**
+	 * Does this dialect support UNION ALL, which is generally a faster
+	 * variant of UNION?
+	 *
+	 * @return True if UNION ALL is supported; false otherwise.
+	 */
+	public boolean supportsUnionAll() {
+		return false;
+	}
+
+
+	// miscellaneous support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+	/**
+	 * Create a {@link org.hibernate.sql.JoinFragment} strategy responsible
+	 * for handling this dialect's variations in how joins are handled.
+	 *
+	 * @return This dialect's {@link org.hibernate.sql.JoinFragment} strategy.
+	 */
+	public JoinFragment createOuterJoinFragment() {
+		return new ANSIJoinFragment();
+	}
+
+	/**
+	 * Create a {@link org.hibernate.sql.CaseFragment} strategy responsible
+	 * for handling this dialect's variations in how CASE statements are
+	 * handled.
+	 *
+	 * @return This dialect's {@link org.hibernate.sql.CaseFragment} strategy.
+	 */
+	public CaseFragment createCaseFragment() {
+		return new ANSICaseFragment();
+	}
+
+	/**
+	 * The fragment used to insert a row without specifying any column values.
+	 * This is not possible on some databases.
+	 *
+	 * @return The appropriate empty values clause.
+	 */
+	public String getNoColumnsInsertString() {
+		return "values ( )";
+	}
+
+	/**
+	 * The name of the SQL function that transforms a string to
+	 * lowercase
+	 *
+	 * @return The dialect-specific lowercase function.
+	 */
+	public String getLowercaseFunction() {
+		return "lower";
+	}
+
+	/**
+	 * Meant as a means for end users to affect the select strings being sent
+	 * to the database and perhaps manipulate them in some fashion.
+	 * <p/>
+	 * The recommend approach is to instead use
+	 * {@link org.hibernate.Interceptor#onPrepareStatement(String)}.
+	 *
+	 * @param select The select command
+	 * @return The mutated select command, or the same as was passed in.
+	 */
+	public String transformSelectString(String select) {
+		return select;
+	}
+
+	/**
+	 * What is the maximum length Hibernate can use for generated aliases?
+	 *
+	 * @return The maximum length.
+	 */
+	public int getMaxAliasLength() {
+		return 10;
+	}
+
+	/**
+	 * The SQL literal value to which this database maps boolean values.
+	 *
+	 * @param bool The boolean value
+	 * @return The appropriate SQL literal.
+	 */
+	public String toBooleanValueString(boolean bool) {
+		return bool ? "1" : "0";
+	}
+
+
+	// identifier quoting support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * The character specific to this dialect used to begin a quoted identifier.
+	 *
+	 * @return The dialect's specific open quote character.
+	 */
+	public char openQuote() {
+		return '"';
+	}
+
+	/**
+	 * The character specific to this dialect used to close a quoted identifier.
+	 *
+	 * @return The dialect's specific close quote character.
+	 */
+	public char closeQuote() {
+		return '"';
+	}
+
+	/**
+	 * Apply dialect-specific quoting.
+	 * <p/>
+	 * By default, the incoming value is checked to see if its first character
+	 * is the back-tick (`).  If so, the dialect specific quoting is applied.
+	 *
+	 * @param column The value to be quoted.
+	 * @return The quoted (or unmodified, if not starting with back-tick) value.
+	 * @see #openQuote()
+	 * @see #closeQuote()
+	 */
+	public final String quote(String column) {
+		if ( column.charAt( 0 ) == '`' ) {
+			return openQuote() + column.substring( 1, column.length() - 1 ) + closeQuote();
+		}
+		else {
+			return column;
+		}
+	}
+
+
+	// DDL support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Does this dialect support the <tt>ALTER TABLE</tt> syntax?
+	 *
+	 * @return True if we support altering of tables; false otherwise.
+	 */
+	public boolean hasAlterTable() {
+		return true;
+	}
+
+	/**
+	 * Do we need to drop constraints before dropping tables in this dialect?
+	 *
+	 * @return True if constraints must be dropped prior to dropping
+	 * the table; false otherwise.
+	 */
+	public boolean dropConstraints() {
+		return true;
+	}
+
+	/**
+	 * Do we need to qualify index names with the schema name?
+	 *
+	 * @return boolean
+	 */
+	public boolean qualifyIndexName() {
+		return true;
+	}
+
+	/**
+	 * Does this dialect support the <tt>UNIQUE</tt> column syntax?
+	 *
+	 * @return boolean
+	 */
+	public boolean supportsUnique() {
+		return true;
+	}
+
+    /**
+     * Does this dialect support adding Unique constraints via create and alter table ?
+     * @return boolean
+     */
+	public boolean supportsUniqueConstraintInCreateAlterTable() {
+	    return true;
+	}
+
+	/**
+	 * The syntax used to add a column to a table (optional).
+	 *
+	 * @return The "add column" fragment.
+	 */
+	public String getAddColumnString() {
+		throw new UnsupportedOperationException( "No add column syntax supported by Dialect" );
+	}
+
+	public String getDropForeignKeyString() {
+		return " drop constraint ";
+	}
+
+	public String getTableTypeString() {
+		// grrr... for differentiation of mysql storage engines
+		return "";
+	}
+
+	/**
+	 * The syntax used to add a foreign key constraint to a table.
+	 *
+	 * @param constraintName The FK constraint name.
+	 * @param foreignKey The names of the columns comprising the FK
+	 * @param referencedTable The table referenced by the FK
+	 * @param primaryKey The explicit columns in the referencedTable referenced
+	 * by this FK.
+	 * @param referencesPrimaryKey if false, constraint should be
+	 * explicit about which column names the constraint refers to
+	 *
+	 * @return the "add FK" fragment
+	 */
+	public String getAddForeignKeyConstraintString(
+			String constraintName,
+			String[] foreignKey,
+			String referencedTable,
+			String[] primaryKey,
+			boolean referencesPrimaryKey) {
+		StringBuffer res = new StringBuffer( 30 );
+
+		res.append( " add constraint " )
+				.append( constraintName )
+				.append( " foreign key (" )
+				.append( StringHelper.join( ", ", foreignKey ) )
+				.append( ") references " )
+				.append( referencedTable );
+
+		if ( !referencesPrimaryKey ) {
+			res.append( " (" )
+					.append( StringHelper.join( ", ", primaryKey ) )
+					.append( ')' );
+		}
+
+		return res.toString();
+	}
+
+	/**
+	 * The syntax used to add a primary key constraint to a table.
+	 *
+	 * @param constraintName The name of the PK constraint.
+	 * @return The "add PK" fragment
+	 */
+	public String getAddPrimaryKeyConstraintString(String constraintName) {
+		return " add constraint " + constraintName + " primary key ";
+	}
+
+	public boolean hasSelfReferentialForeignKeyBug() {
+		return false;
+	}
+
+	/**
+	 * The keyword used to specify a nullable column.
+	 *
+	 * @return String
+	 */
+	public String getNullColumnString() {
+		return "";
+	}
+
+	public boolean supportsCommentOn() {
+		return false;
+	}
+
+	public String getTableComment(String comment) {
+		return "";
+	}
+
+	public String getColumnComment(String comment) {
+		return "";
+	}
+
+	public boolean supportsIfExistsBeforeTableName() {
+		return false;
+	}
+
+	public boolean supportsIfExistsAfterTableName() {
+		return false;
+	}
+
+	/**
+	 * Does this dialect support column-level check constraints?
+	 *
+	 * @return True if column-level CHECK constraints are supported; false
+	 * otherwise.
+	 */
+	public boolean supportsColumnCheck() {
+		return true;
+	}
+
+	/**
+	 * Does this dialect support table-level check constraints?
+	 *
+	 * @return True if table-level CHECK constraints are supported; false
+	 * otherwise.
+	 */
+	public boolean supportsTableCheck() {
+		return true;
+	}
+
+	public boolean supportsCascadeDelete() {
+		return true;
+	}
+
+	public boolean supportsNotNullUnique() {
+		return true;
+	}
+
+	/**
+	 * Completely optional cascading drop clause
+	 *
+	 * @return String
+	 */
+	public String getCascadeConstraintsString() {
+		return "";
+	}
+
+
+	// Informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Does this dialect support empty IN lists?
+	 * <p/>
+	 * For example, is [where XYZ in ()] a supported construct?
+	 *
+	 * @return True if empty in lists are supported; false otherwise.
+	 * @since 3.2
+	 */
+	public boolean supportsEmptyInList() {
+		return true;
+	}
+
+	/**
+	 * Are string comparisons implicitly case insensitive.
+	 * <p/>
+	 * In other words, does [where 'XYZ' = 'xyz'] resolve to true?
+	 *
+	 * @return True if comparisons are case insensitive.
+	 * @since 3.2
+	 */
+	public boolean areStringComparisonsCaseInsensitive() {
+		return false;
+	}
+
+	/**
+	 * Is this dialect known to support what ANSI-SQL terms "row value
+	 * constructor" syntax; sometimes called tuple syntax.
+	 * <p/>
+	 * Basically, does it support syntax like
+	 * "... where (FIRST_NAME, LAST_NAME) = ('Steve', 'Ebersole') ...".
+	 *
+	 * @return True if this SQL dialect is known to support "row value
+	 * constructor" syntax; false otherwise.
+	 * @since 3.2
+	 */
+	public boolean supportsRowValueConstructorSyntax() {
+		// return false here, as most databases do not properly support this construct...
+		return false;
+	}
+
+	/**
+	 * If the dialect supports {@link #supportsRowValueConstructorSyntax() row values},
+	 * does it offer such support in IN lists as well?
+	 * <p/>
+	 * For example, "... where (FIRST_NAME, LAST_NAME) IN ( (?, ?), (?, ?) ) ..."
+	 *
+	 * @return True if this SQL dialect is known to support "row value
+	 * constructor" syntax in the IN list; false otherwise.
+	 * @since 3.2
+	 */
+	public boolean supportsRowValueConstructorSyntaxInInList() {
+		return false;
+	}
+
+	/**
+	 * Should LOBs (both BLOB and CLOB) be bound using stream operations (i.e.
+	 * {@link java.sql.PreparedStatement#setBinaryStream}).
+	 *
+	 * @return True if BLOBs and CLOBs should be bound using stream operations.
+	 * @since 3.2
+	 */
+	public boolean useInputStreamToInsertBlob() {
+		return true;
+	}
+
+	/**
+	 * Does this dialect support parameters within the select clause of
+	 * INSERT ... SELECT ... statements?
+	 *
+	 * @return True if this is supported; false otherwise.
+	 * @since 3.2
+	 */
+	public boolean supportsParametersInInsertSelect() {
+		return true;
+	}
+
+	/**
+	 * Does this dialect support asking the result set its positioning
+	 * information on forward only cursors.  Specifically, in the case of
+	 * scrolling fetches, Hibernate needs to use
+	 * {@link java.sql.ResultSet#isAfterLast} and
+	 * {@link java.sql.ResultSet#isBeforeFirst}.  Certain drivers do not
+	 * allow access to these methods for forward only cursors.
+	 * <p/>
+	 * NOTE : this is highly driver dependent!
+	 *
+	 * @return True if methods like {@link java.sql.ResultSet#isAfterLast} and
+	 * {@link java.sql.ResultSet#isBeforeFirst} are supported for forward
+	 * only cursors; false otherwise.
+	 * @since 3.2
+	 */
+	public boolean supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() {
+		return true;
+	}
+
+	/**
+	 * Does this dialect support definition of cascade delete constraints
+	 * which can cause circular chains?
+	 *
+	 * @return True if circular cascade delete constraints are supported; false
+	 * otherwise.
+	 * @since 3.2
+	 */
+	public boolean supportsCircularCascadeDeleteConstraints() {
+		return true;
+	}
+
+	/**
+	 * Are subselects supported as the left-hand-side (LHS) of
+	 * IN-predicates.
+	 * <p/>
+	 * In other words, is syntax like "... <subquery> IN (1, 2, 3) ..." supported?
+	 *
+	 * @return True if subselects can appear as the LHS of an in-predicate;
+	 * false otherwise.
+	 * @since 3.2
+	 */
+	public boolean  supportsSubselectAsInPredicateLHS() {
+		return true;
+	}
+
+	/**
+	 * Expected LOB usage pattern is such that I can perform an insert
+	 * via prepared statement with a parameter binding for a LOB value
+	 * without crazy casting to JDBC driver implementation-specific classes...
+	 * <p/>
+	 * Part of the trickiness here is the fact that this is largely
+	 * driver dependent.  For example, Oracle (which is notoriously bad with
+	 * LOB support in their drivers historically) actually does a pretty good
+	 * job with LOB support as of the 10.2.x versions of their drivers...
+	 *
+	 * @return True if normal LOB usage patterns can be used with this driver;
+	 * false if driver-specific hookiness needs to be applied.
+	 * @since 3.2
+	 */
+	public boolean supportsExpectedLobUsagePattern() {
+		return true;
+	}
+
+	/**
+	 * Does the dialect support propogating changes to LOB
+	 * values back to the database?  Talking about mutating the
+	 * internal value of the locator as opposed to supplying a new
+	 * locator instance...
+	 * <p/>
+	 * For BLOBs, the internal value might be changed by:
+	 * {@link java.sql.Blob#setBinaryStream},
+	 * {@link java.sql.Blob#setBytes(long, byte[])},
+	 * {@link java.sql.Blob#setBytes(long, byte[], int, int)},
+	 * or {@link java.sql.Blob#truncate(long)}.
+	 * <p/>
+	 * For CLOBs, the internal value might be changed by:
+	 * {@link java.sql.Clob#setAsciiStream(long)},
+	 * {@link java.sql.Clob#setCharacterStream(long)},
+	 * {@link java.sql.Clob#setString(long, String)},
+	 * {@link java.sql.Clob#setString(long, String, int, int)},
+	 * or {@link java.sql.Clob#truncate(long)}.
+	 * <p/>
+	 * NOTE : I do not know the correct answer currently for
+	 * databases which (1) are not part of the cruise control process
+	 * or (2) do not {@link #supportsExpectedLobUsagePattern}.
+	 *
+	 * @return True if the changes are propogated back to the
+	 * database; false otherwise.
+	 * @since 3.2
+	 */
+	public boolean supportsLobValueChangePropogation() {
+		return true;
+	}
+
+	/**
+	 * Is it supported to materialize a LOB locator outside the transaction in
+	 * which it was created?
+	 * <p/>
+	 * Again, part of the trickiness here is the fact that this is largely
+	 * driver dependent.
+	 * <p/>
+	 * NOTE: all database I have tested which {@link #supportsExpectedLobUsagePattern()}
+	 * also support the ability to materialize a LOB outside the owning transaction...
+	 *
+	 * @return True if unbounded materialization is supported; false otherwise.
+	 * @since 3.2
+	 */
+	public boolean supportsUnboundedLobLocatorMaterialization() {
+		return true;
+	}
+
+	/**
+	 * Does this dialect support referencing the table being mutated in
+	 * a subquery.  The "table being mutated" is the table referenced in
+	 * an UPDATE or a DELETE query.  And so can that table then be
+	 * referenced in a subquery of said UPDATE/DELETE query.
+	 * <p/>
+	 * For example, would the following two syntaxes be supported:<ul>
+	 * <li>delete from TABLE_A where ID not in ( select ID from TABLE_A )</li>
+	 * <li>update TABLE_A set NON_ID = 'something' where ID in ( select ID from TABLE_A)</li>
+	 * </ul>
+	 *
+	 * @return True if this dialect allows references the mutating table from
+	 * a subquery.
+	 */
+	public boolean supportsSubqueryOnMutatingTable() {
+		return true;
+	}
+
+	/**
+	 * Does the dialect support an exists statement in the select clause?
+	 *
+	 * @return True if exists checks are allowed in the select clause; false otherwise.
+	 */
+	public boolean supportsExistsInSelect() {
+		return true;
+	}
+
+	/**
+	 * For the underlying database, is READ_COMMITTED isolation implemented by
+	 * forcing readers to wait for write locks to be released?
+	 *
+	 * @return True if writers block readers to achieve READ_COMMITTED; false otherwise.
+	 */
+	public boolean doesReadCommittedCauseWritersToBlockReaders() {
+		return false;
+	}
+
+	/**
+	 * For the underlying database, is REPEATABLE_READ isolation implemented by
+	 * forcing writers to wait for read locks to be released?
+	 *
+	 * @return True if readers block writers to achieve REPEATABLE_READ; false otherwise.
+	 */
+	public boolean doesRepeatableReadCauseReadersToBlockWriters() {
+		return false;
+	}
+
+	/**
+	 * Does this dialect support using a JDBC bind parameter as an argument
+	 * to a function or procedure call?
+	 *
+	 * @return True if the database supports accepting bind params as args; false otherwise.
+	 */
+	public boolean supportsBindAsCallableArgument() {
+		return true;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DialectFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DialectFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/DialectFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,136 @@
+// $Id: DialectFactory.java 9789 2006-04-25 17:06:55Z epbernard $
+package org.hibernate.dialect;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * A factory for generating Dialect instances.
+ *
+ * @author Steve Ebersole
+ */
+public class DialectFactory {
+
+	/**
+	 * Builds an appropriate Dialect instance.
+	 * <p/>
+	 * If a dialect is explicitly named in the incoming properties, it is used. Otherwise, the database name and version
+	 * (obtained from connection metadata) are used to make the dertemination.
+	 * <p/>
+	 * An exception is thrown if a dialect was not explicitly set and the database name is not known.
+	 *
+	 * @param props The configuration properties.
+	 * @param databaseName The name of the database product (obtained from metadata).
+	 * @param databaseMajorVersion The major version of the database product (obtained from metadata).
+	 *
+	 * @return The appropriate dialect.
+	 *
+	 * @throws HibernateException No dialect specified and database name not known.
+	 */
+	public static Dialect buildDialect(Properties props, String databaseName, int databaseMajorVersion)
+	        throws HibernateException {
+		String dialectName = props.getProperty( Environment.DIALECT );
+		if ( dialectName == null ) {
+			return determineDialect( databaseName, databaseMajorVersion );
+		}
+		else {
+			return buildDialect( dialectName );
+		}
+	}
+
+	/**
+	 * Determine the appropriate Dialect to use given the database product name
+	 * and major version.
+	 *
+	 * @param databaseName The name of the database product (obtained from metadata).
+	 * @param databaseMajorVersion The major version of the database product (obtained from metadata).
+	 *
+	 * @return An appropriate dialect instance.
+	 */
+	public static Dialect determineDialect(String databaseName, int databaseMajorVersion) {
+		if ( databaseName == null ) {
+			throw new HibernateException( "Hibernate Dialect must be explicitly set" );
+		}
+
+		DatabaseDialectMapper mapper = ( DatabaseDialectMapper ) MAPPERS.get( databaseName );
+		if ( mapper == null ) {
+			throw new HibernateException( "Hibernate Dialect must be explicitly set for database: " + databaseName );
+		}
+
+		String dialectName = mapper.getDialectClass( databaseMajorVersion );
+		return buildDialect( dialectName );
+	}
+
+	/**
+	 * Returns a dialect instance given the name of the class to use.
+	 *
+	 * @param dialectName The name of the dialect class.
+	 *
+	 * @return The dialect instance.
+	 */
+	public static Dialect buildDialect(String dialectName) {
+		try {
+			return ( Dialect ) ReflectHelper.classForName( dialectName ).newInstance();
+		}
+		catch ( ClassNotFoundException cnfe ) {
+			throw new HibernateException( "Dialect class not found: " + dialectName );
+		}
+		catch ( Exception e ) {
+			throw new HibernateException( "Could not instantiate dialect class", e );
+		}
+	}
+
+	/**
+	 * For a given database product name, instances of
+	 * DatabaseDialectMapper know which Dialect to use for different versions.
+	 */
+	public static interface DatabaseDialectMapper {
+		public String getDialectClass(int majorVersion);
+	}
+
+	/**
+	 * A simple DatabaseDialectMapper for dialects which are independent
+	 * of the underlying database product version.
+	 */
+	public static class VersionInsensitiveMapper implements DatabaseDialectMapper {
+		private String dialectClassName;
+
+		public VersionInsensitiveMapper(String dialectClassName) {
+			this.dialectClassName = dialectClassName;
+		}
+
+		public String getDialectClass(int majorVersion) {
+			return dialectClassName;
+		}
+	}
+
+	private static final Map MAPPERS = new HashMap();
+	static {
+		// TODO : this is the stuff it'd be nice to move to a properties file or some other easily user-editable place
+		MAPPERS.put( "HSQL Database Engine", new VersionInsensitiveMapper( "org.hibernate.dialect.HSQLDialect" ) );
+		MAPPERS.put( "DB2/NT", new VersionInsensitiveMapper( "org.hibernate.dialect.DB2Dialect" ) );
+		MAPPERS.put( "MySQL", new VersionInsensitiveMapper( "org.hibernate.dialect.MySQLDialect" ) );
+		MAPPERS.put( "PostgreSQL", new VersionInsensitiveMapper( "org.hibernate.dialect.PostgreSQLDialect" ) );
+		MAPPERS.put( "Microsoft SQL Server Database", new VersionInsensitiveMapper( "org.hibernate.dialect.SQLServerDialect" ) );
+		MAPPERS.put( "Microsoft SQL Server", new VersionInsensitiveMapper( "org.hibernate.dialect.SQLServerDialect" ) );
+		MAPPERS.put( "Sybase SQL Server", new VersionInsensitiveMapper( "org.hibernate.dialect.SybaseDialect" ) );
+		MAPPERS.put( "Informix Dynamic Server", new VersionInsensitiveMapper( "org.hibernate.dialect.InformixDialect" ) );
+		MAPPERS.put( "Apache Derby", new VersionInsensitiveMapper( "org.hibernate.dialect.DerbyDialect" ) );
+		
+		MAPPERS.put(
+		        "Oracle",
+		        new DatabaseDialectMapper() {
+			        public String getDialectClass(int majorVersion) {
+			            return majorVersion > 8
+			                    ? "org.hibernate.dialect.Oracle9Dialect"
+				                : "org.hibernate.dialect.OracleDialect";
+			        }
+		        }
+		);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/FirebirdDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/FirebirdDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/FirebirdDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+//$Id: FirebirdDialect.java 4202 2004-08-09 06:38:52Z oneovthafew $
+package org.hibernate.dialect;
+
+/**
+ * An SQL dialect for Firebird.
+ * @author Reha CENANI
+ */
+public class FirebirdDialect extends InterbaseDialect {
+
+	public String getDropSequenceString(String sequenceName) {
+		return "drop generator " + sequenceName;
+	}
+
+	public String getLimitString(String sql, boolean hasOffset) {
+		return new StringBuffer( sql.length()+20 )
+			.append(sql)
+			.insert(6, hasOffset ? " first ? skip ?" : " first ?")
+			.toString();
+	}
+
+	public boolean bindLimitParametersFirst() {
+		return true;
+	}
+
+	public boolean bindLimitParametersInReverseOrder() {
+		return true;
+	}
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/FrontBaseDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/FrontBaseDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/FrontBaseDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,91 @@
+//$Id: FrontBaseDialect.java 9328 2006-02-23 17:32:47Z steveebersole $
+package org.hibernate.dialect;
+
+import org.hibernate.dialect.lock.LockingStrategy;
+import org.hibernate.dialect.lock.UpdateLockingStrategy;
+import org.hibernate.dialect.lock.SelectLockingStrategy;
+import org.hibernate.persister.entity.Lockable;
+import org.hibernate.LockMode;
+
+import java.sql.Types;
+
+/**
+ * An SQL Dialect for Frontbase.  Assumes you're using the latest version
+ * of the FrontBase JDBC driver, available from <tt>http://frontbase.com/</tt>
+ * <p>
+ * <b>NOTE</b>: The latest JDBC driver is not always included with the
+ * latest release of FrontBase.  Download the driver separately, and enjoy
+ * the informative release notes.
+ * <p>
+ * This dialect was tested with JDBC driver version 2.3.1.  This driver
+ * contains a bug that causes batches of updates to fail.  (The bug should be
+ * fixed in the next release of the JDBC driver.)  If you are using JDBC driver
+ * 2.3.1, you can work-around this problem by setting the following in your
+ * <tt>hibernate.properties</tt> file: <tt>hibernate.jdbc.batch_size=15</tt>
+ *
+ * @author Ron Lussier <tt>rlussier at lenscraft.com</tt>
+ */
+public class FrontBaseDialect extends Dialect {
+
+	public FrontBaseDialect() {
+		super();
+
+		registerColumnType( Types.BIT, "bit" );
+		registerColumnType( Types.BIGINT, "longint" );
+		registerColumnType( Types.SMALLINT, "smallint" );
+		registerColumnType( Types.TINYINT, "tinyint" );
+		registerColumnType( Types.INTEGER, "integer" );
+		registerColumnType( Types.CHAR, "char(1)" );
+		registerColumnType( Types.VARCHAR, "varchar($l)" );
+		registerColumnType( Types.FLOAT, "float" );
+		registerColumnType( Types.DOUBLE, "double precision" );
+		registerColumnType( Types.DATE, "date" );
+		registerColumnType( Types.TIME, "time" );
+		registerColumnType( Types.TIMESTAMP, "timestamp" );
+		registerColumnType( Types.VARBINARY, "bit varying($l)" );
+		registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
+		registerColumnType( Types.BLOB, "blob" );
+		registerColumnType( Types.CLOB, "clob" );
+	}
+
+	public String getAddColumnString() {
+		return "add column";
+	}
+
+	public String getCascadeConstraintsString() {
+		return " cascade";
+	}
+
+	public boolean dropConstraints() {
+		return false;
+	}
+
+	/**
+	 * Does this dialect support the <tt>FOR UPDATE</tt> syntax. No!
+	 *
+	 * @return false always. FrontBase doesn't support this syntax,
+	 * which was dropped with SQL92
+	 */
+	public String getForUpdateString() {
+		return "";
+	}
+
+	public String getCurrentTimestampCallString() {
+		// TODO : not sure this is correct, could not find docs on how to do this.
+		return "{?= call current_timestamp}";
+	}
+
+	public boolean isCurrentTimestampSelectStringCallable() {
+		return true;
+	}
+
+	public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
+		// Frontbase has no known variation of a "SELECT ... FOR UPDATE" syntax...
+		if ( lockMode.greaterThan( LockMode.READ ) ) {
+			return new UpdateLockingStrategy( lockable, lockMode );
+		}
+		else {
+			return new SelectLockingStrategy( lockable, lockMode );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/H2Dialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/H2Dialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/H2Dialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,298 @@
+package org.hibernate.dialect;
+
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.Hibernate;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.NoArgSQLFunction;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.dialect.function.VarArgsSQLFunction;
+import org.hibernate.exception.TemplatedViolatedConstraintNameExtracter;
+import org.hibernate.exception.ViolatedConstraintNameExtracter;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * A dialect compatible with the H2 database.
+ * 
+ * @author Thomas Mueller
+ *
+ */
+public class H2Dialect extends Dialect {
+
+    private String querySequenceString;
+    public H2Dialect() {
+        super();
+               
+        querySequenceString = "select sequence_name from information_schema.sequences";
+        try {
+        	// HHH-2300
+            Class constants = ReflectHelper.classForName( "org.h2.engine.Constants" );
+            Integer build = (Integer)constants.getDeclaredField("BUILD_ID" ).get(null);
+            int buildid = build.intValue();
+            if(buildid < 32) {
+                querySequenceString = "select name from information_schema.sequences";
+            }
+        } catch(Throwable e) {
+            // ignore (probably H2 not in the classpath)
+        }
+        registerColumnType(Types.BOOLEAN, "boolean");
+        registerColumnType(Types.BIGINT, "bigint");
+        registerColumnType(Types.BINARY, "binary");
+        registerColumnType(Types.BIT, "bit");
+        registerColumnType(Types.CHAR, "char($l)");
+        registerColumnType(Types.DATE, "date");
+        registerColumnType(Types.DECIMAL, "decimal($p,$s)");
+        registerColumnType(Types.DOUBLE, "double");
+        registerColumnType(Types.FLOAT, "float");
+        registerColumnType(Types.INTEGER, "integer");
+        registerColumnType(Types.LONGVARBINARY, "longvarbinary");
+        registerColumnType(Types.LONGVARCHAR, "longvarchar");
+        registerColumnType(Types.REAL, "real");        
+        registerColumnType(Types.SMALLINT, "smallint");
+        registerColumnType(Types.TINYINT, "tinyint");
+        registerColumnType(Types.TIME, "time");
+        registerColumnType(Types.TIMESTAMP, "timestamp");
+        registerColumnType(Types.VARCHAR, "varchar($l)");
+        registerColumnType(Types.VARBINARY, "binary($l)");
+        registerColumnType(Types.NUMERIC, "numeric");
+        registerColumnType(Types.BLOB, "blob");
+        registerColumnType(Types.CLOB, "clob");
+        
+        // select topic, syntax from information_schema.help
+        // where section like 'Function%' order by section, topic
+
+//        registerFunction("abs", new StandardSQLFunction("abs"));
+        registerFunction("acos", new StandardSQLFunction("acos", Hibernate.DOUBLE));
+        registerFunction("asin", new StandardSQLFunction("asin", Hibernate.DOUBLE));
+        registerFunction("atan", new StandardSQLFunction("atan", Hibernate.DOUBLE));
+        registerFunction("atan2", new StandardSQLFunction("atan2", Hibernate.DOUBLE));
+        registerFunction("bitand", new StandardSQLFunction("bitand", Hibernate.INTEGER));
+        registerFunction("bitor", new StandardSQLFunction("bitor", Hibernate.INTEGER));
+        registerFunction("bitxor", new StandardSQLFunction("bitxor", Hibernate.INTEGER));
+        registerFunction("ceiling", new StandardSQLFunction("ceiling", Hibernate.DOUBLE));
+        registerFunction("cos", new StandardSQLFunction("cos", Hibernate.DOUBLE));
+        registerFunction("cot", new StandardSQLFunction("cot", Hibernate.DOUBLE));
+        registerFunction("degrees", new StandardSQLFunction("degrees", Hibernate.DOUBLE));
+        registerFunction("exp", new StandardSQLFunction("exp", Hibernate.DOUBLE));
+        registerFunction("floor", new StandardSQLFunction("floor", Hibernate.DOUBLE));
+        registerFunction("log", new StandardSQLFunction("log", Hibernate.DOUBLE));
+        registerFunction("log10", new StandardSQLFunction("log10", Hibernate.DOUBLE));
+//        registerFunction("mod", new StandardSQLFunction("mod", Hibernate.INTEGER));
+        registerFunction("pi", new NoArgSQLFunction("pi", Hibernate.DOUBLE));
+        registerFunction("power", new StandardSQLFunction("power", Hibernate.DOUBLE));
+        registerFunction("radians", new StandardSQLFunction("radians", Hibernate.DOUBLE));
+        registerFunction("rand", new NoArgSQLFunction("rand", Hibernate.DOUBLE));
+        registerFunction("round", new StandardSQLFunction("round", Hibernate.DOUBLE));
+        registerFunction("roundmagic", new StandardSQLFunction("roundmagic", Hibernate.DOUBLE));
+        registerFunction("sign", new StandardSQLFunction("sign", Hibernate.INTEGER));
+        registerFunction("sin", new StandardSQLFunction("sin", Hibernate.DOUBLE));
+//        registerFunction("sqrt", new StandardSQLFunction("sqrt", Hibernate.DOUBLE));
+        registerFunction("tan", new StandardSQLFunction("tan", Hibernate.DOUBLE));
+        registerFunction("truncate", new StandardSQLFunction("truncate", Hibernate.DOUBLE));
+
+        registerFunction("compress", new StandardSQLFunction("compress", Hibernate.BINARY));
+        registerFunction("expand", new StandardSQLFunction("compress", Hibernate.BINARY));
+        registerFunction("decrypt", new StandardSQLFunction("decrypt", Hibernate.BINARY));
+        registerFunction("encrypt", new StandardSQLFunction("encrypt", Hibernate.BINARY));
+        registerFunction("hash", new StandardSQLFunction("hash", Hibernate.BINARY));
+
+        registerFunction("ascii", new StandardSQLFunction("ascii", Hibernate.INTEGER));
+//        registerFunction("bit_length", new StandardSQLFunction("bit_length", Hibernate.INTEGER));
+        registerFunction("char", new StandardSQLFunction("char", Hibernate.CHARACTER));
+        registerFunction("concat", new VarArgsSQLFunction(Hibernate.STRING, "(", "||", ")"));
+        registerFunction("difference", new StandardSQLFunction("difference", Hibernate.INTEGER));
+        registerFunction("hextoraw", new StandardSQLFunction("hextoraw", Hibernate.STRING));
+        registerFunction("lower", new StandardSQLFunction("lower", Hibernate.STRING));
+        registerFunction("insert", new StandardSQLFunction("lower", Hibernate.STRING));
+        registerFunction("left", new StandardSQLFunction("left", Hibernate.STRING));
+//        registerFunction("length", new StandardSQLFunction("length", Hibernate.INTEGER));
+//        registerFunction("locate", new StandardSQLFunction("locate", Hibernate.INTEGER));
+//        registerFunction("lower", new StandardSQLFunction("lower", Hibernate.STRING));
+        registerFunction("lcase", new StandardSQLFunction("lcase", Hibernate.STRING));
+        registerFunction("ltrim", new StandardSQLFunction("ltrim", Hibernate.STRING));
+        registerFunction("octet_length", new StandardSQLFunction("octet_length", Hibernate.INTEGER));
+        registerFunction("position", new StandardSQLFunction("position", Hibernate.INTEGER));
+        registerFunction("rawtohex", new StandardSQLFunction("rawtohex", Hibernate.STRING));
+        registerFunction("repeat", new StandardSQLFunction("repeat", Hibernate.STRING));
+        registerFunction("replace", new StandardSQLFunction("replace", Hibernate.STRING));
+        registerFunction("right", new StandardSQLFunction("right", Hibernate.STRING));
+        registerFunction("rtrim", new StandardSQLFunction("rtrim", Hibernate.STRING));
+        registerFunction("soundex", new StandardSQLFunction("soundex", Hibernate.STRING));
+        registerFunction("space", new StandardSQLFunction("space", Hibernate.STRING));
+        registerFunction("stringencode", new StandardSQLFunction("stringencode", Hibernate.STRING));
+        registerFunction("stringdecode", new StandardSQLFunction("stringdecode", Hibernate.STRING));
+//        registerFunction("substring", new StandardSQLFunction("substring", Hibernate.STRING));
+//        registerFunction("upper", new StandardSQLFunction("upper", Hibernate.STRING));
+        registerFunction("ucase", new StandardSQLFunction("ucase", Hibernate.STRING));
+
+        registerFunction("stringtoutf8", new StandardSQLFunction("stringtoutf8", Hibernate.BINARY));
+        registerFunction("utf8tostring", new StandardSQLFunction("utf8tostring", Hibernate.STRING));
+
+        registerFunction("current_date", new NoArgSQLFunction("current_date", Hibernate.DATE));
+        registerFunction("current_time", new NoArgSQLFunction("current_time", Hibernate.TIME));
+        registerFunction("current_timestamp", new NoArgSQLFunction("current_timestamp", Hibernate.TIMESTAMP));
+        registerFunction("datediff", new NoArgSQLFunction("datediff", Hibernate.INTEGER));
+        registerFunction("dayname", new StandardSQLFunction("dayname", Hibernate.STRING));
+        registerFunction("dayofmonth", new StandardSQLFunction("dayofmonth", Hibernate.INTEGER));
+        registerFunction("dayofweek", new StandardSQLFunction("dayofweek", Hibernate.INTEGER));
+        registerFunction("dayofyear", new StandardSQLFunction("dayofyear", Hibernate.INTEGER));
+//        registerFunction("hour", new StandardSQLFunction("hour", Hibernate.INTEGER));
+//        registerFunction("minute", new StandardSQLFunction("minute", Hibernate.INTEGER));
+//        registerFunction("month", new StandardSQLFunction("month", Hibernate.INTEGER));
+        registerFunction("monthname", new StandardSQLFunction("monthname", Hibernate.STRING));
+        registerFunction("quater", new StandardSQLFunction("quater", Hibernate.INTEGER));
+//        registerFunction("second", new StandardSQLFunction("second", Hibernate.INTEGER));
+        registerFunction("week", new StandardSQLFunction("week", Hibernate.INTEGER));
+//        registerFunction("year", new StandardSQLFunction("year", Hibernate.INTEGER));
+
+        registerFunction("curdate", new NoArgSQLFunction("curdate", Hibernate.DATE));
+        registerFunction("curtime", new NoArgSQLFunction("curtime", Hibernate.TIME));
+        registerFunction("curtimestamp", new NoArgSQLFunction("curtimestamp", Hibernate.TIME));
+        registerFunction("now", new NoArgSQLFunction("now", Hibernate.TIMESTAMP));
+
+        registerFunction("database", new NoArgSQLFunction("database", Hibernate.STRING));
+        registerFunction("user", new NoArgSQLFunction("user", Hibernate.STRING));
+
+        getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE);
+
+    }
+
+    public String getAddColumnString() {
+        return "add column";
+    }
+
+    public boolean supportsIdentityColumns() {
+        return true;
+    }
+
+    public String getIdentityColumnString() {
+        return "generated by default as identity"; // not null is implicit
+    }
+
+    public String getIdentitySelectString() {
+        return "call identity()";
+    }
+
+    public String getIdentityInsertString() {
+        return "null";
+    }
+
+    public String getForUpdateString() {
+        return " for update";
+    }
+
+    public boolean supportsUnique() {
+        return true;
+    }
+
+    public boolean supportsLimit() {
+        return true;
+    }
+
+    public String getLimitString(String sql, boolean hasOffset) {
+        return new StringBuffer(sql.length() + 20).
+            append(sql).
+            append(hasOffset ? " limit ? offset ?" : " limit ?").
+            toString();
+    }
+    
+    public boolean bindLimitParametersInReverseOrder() {
+        return true;
+    }    
+
+    public boolean bindLimitParametersFirst() {
+        return false;
+    }
+
+    public boolean supportsIfExistsAfterTableName() {
+        return true;
+    }
+
+    public boolean supportsSequences() {
+        return true;
+    }
+
+	public boolean supportsPooledSequences() {
+		return true;
+	}
+
+    public String getCreateSequenceString(String sequenceName) {
+        return "create sequence " + sequenceName;
+    }
+
+    public String getDropSequenceString(String sequenceName) {
+        return "drop sequence " + sequenceName;
+    }
+
+    public String getSelectSequenceNextValString(String sequenceName) {
+        return "next value for " + sequenceName;
+    }
+
+    public String getSequenceNextValString(String sequenceName) {
+        return "call next value for " + sequenceName;
+    }
+
+    public String getQuerySequencesString() {
+        return querySequenceString;
+    }
+
+	public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
+        return EXTRACTER;
+    }
+
+    private static ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
+
+        /**
+         * Extract the name of the violated constraint from the given SQLException.
+         *
+         * @param sqle The exception that was the result of the constraint violation.
+         * @return The extracted constraint name.
+         */
+        public String extractConstraintName(SQLException sqle) {
+            String constraintName = null;
+            // 23000: Check constraint violation: {0}
+            // 23001: Unique index or primary key violation: {0}
+            if(sqle.getSQLState().startsWith("23")) {
+                String message = sqle.getMessage();
+                int idx = message.indexOf("violation: ");
+                if(idx > 0) {
+                    constraintName = message.substring(idx + "violation: ".length());
+                }
+            }
+            return constraintName;
+        }
+
+    };
+
+    public boolean supportsTemporaryTables() {
+        return true;
+    }
+    
+    public String getCreateTemporaryTableString() {
+        return "create temporary table if not exists";
+    }
+
+    public boolean supportsCurrentTimestampSelection() {
+        return true;
+    }
+    
+    public boolean isCurrentTimestampSelectStringCallable() {
+        return false;
+    }
+    
+    public String getCurrentTimestampSelectString() {
+        return "call current_timestamp()";
+    }    
+    
+    public boolean supportsUnionAll() {
+        return true;
+    }
+
+
+	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsLobValueChangePropogation() {
+		return false;
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/HSQLDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/HSQLDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/HSQLDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,325 @@
+//$Id: HSQLDialect.java 11259 2007-03-07 22:55:12Z steve.ebersole at jboss.com $
+package org.hibernate.dialect;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import java.io.Serializable;
+
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.JDBCException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.entity.Lockable;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.NoArgSQLFunction;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.dialect.function.VarArgsSQLFunction;
+import org.hibernate.dialect.lock.LockingStrategy;
+import org.hibernate.dialect.lock.SelectLockingStrategy;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.exception.TemplatedViolatedConstraintNameExtracter;
+import org.hibernate.exception.ViolatedConstraintNameExtracter;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * An SQL dialect compatible with HSQLDB (Hypersonic SQL).
+ * <p/>
+ * Note this version supports HSQLDB version 1.8 and higher, only.
+ *
+ * @author Christoph Sturm, Phillip Baird
+ */
+public class HSQLDialect extends Dialect {
+
+	private static final Log log = LogFactory.getLog( HSQLDialect.class );
+
+	private boolean schemaSupport;
+
+	public HSQLDialect() {
+		super();
+		registerColumnType( Types.BIGINT, "bigint" );
+		registerColumnType( Types.BINARY, "binary" );
+		registerColumnType( Types.BIT, "bit" );
+		registerColumnType( Types.CHAR, "char(1)" );
+		registerColumnType( Types.DATE, "date" );
+		registerColumnType( Types.DECIMAL, "decimal" );
+		registerColumnType( Types.DOUBLE, "double" );
+		registerColumnType( Types.FLOAT, "float" );
+		registerColumnType( Types.INTEGER, "integer" );
+		registerColumnType( Types.LONGVARBINARY, "longvarbinary" );
+		registerColumnType( Types.LONGVARCHAR, "longvarchar" );
+		registerColumnType( Types.SMALLINT, "smallint" );
+		registerColumnType( Types.TINYINT, "tinyint" );
+		registerColumnType( Types.TIME, "time" );
+		registerColumnType( Types.TIMESTAMP, "timestamp" );
+		registerColumnType( Types.VARCHAR, "varchar($l)" );
+		registerColumnType( Types.VARBINARY, "varbinary($l)" );
+		registerColumnType( Types.NUMERIC, "numeric" );
+		//HSQL has no Blob/Clob support .... but just put these here for now!
+		registerColumnType( Types.BLOB, "longvarbinary" );
+		registerColumnType( Types.CLOB, "longvarchar" );
+
+		registerFunction( "ascii", new StandardSQLFunction( "ascii", Hibernate.INTEGER ) );
+		registerFunction( "char", new StandardSQLFunction( "char", Hibernate.CHARACTER ) );
+		registerFunction( "length", new StandardSQLFunction( "length", Hibernate.LONG ) );
+		registerFunction( "lower", new StandardSQLFunction( "lower" ) );
+		registerFunction( "upper", new StandardSQLFunction( "upper" ) );
+		registerFunction( "lcase", new StandardSQLFunction( "lcase" ) );
+		registerFunction( "ucase", new StandardSQLFunction( "ucase" ) );
+		registerFunction( "soundex", new StandardSQLFunction( "soundex", Hibernate.STRING ) );
+		registerFunction( "ltrim", new StandardSQLFunction( "ltrim" ) );
+		registerFunction( "rtrim", new StandardSQLFunction( "rtrim" ) );
+		registerFunction( "reverse", new StandardSQLFunction( "reverse" ) );
+		registerFunction( "space", new StandardSQLFunction( "space", Hibernate.STRING ) );
+		registerFunction( "rawtohex", new StandardSQLFunction( "rawtohex" ) );
+		registerFunction( "hextoraw", new StandardSQLFunction( "hextoraw" ) );
+
+		registerFunction( "user", new NoArgSQLFunction( "user", Hibernate.STRING ) );
+		registerFunction( "database", new NoArgSQLFunction( "database", Hibernate.STRING ) );
+
+		registerFunction( "current_date", new NoArgSQLFunction( "current_date", Hibernate.DATE, false ) );
+		registerFunction( "curdate", new NoArgSQLFunction( "curdate", Hibernate.DATE ) );
+		registerFunction( "current_timestamp", new NoArgSQLFunction( "current_timestamp", Hibernate.TIMESTAMP, false ) );
+		registerFunction( "now", new NoArgSQLFunction( "now", Hibernate.TIMESTAMP ) );
+		registerFunction( "current_time", new NoArgSQLFunction( "current_time", Hibernate.TIME, false ) );
+		registerFunction( "curtime", new NoArgSQLFunction( "curtime", Hibernate.TIME ) );
+		registerFunction( "day", new StandardSQLFunction( "day", Hibernate.INTEGER ) );
+		registerFunction( "dayofweek", new StandardSQLFunction( "dayofweek", Hibernate.INTEGER ) );
+		registerFunction( "dayofyear", new StandardSQLFunction( "dayofyear", Hibernate.INTEGER ) );
+		registerFunction( "dayofmonth", new StandardSQLFunction( "dayofmonth", Hibernate.INTEGER ) );
+		registerFunction( "month", new StandardSQLFunction( "month", Hibernate.INTEGER ) );
+		registerFunction( "year", new StandardSQLFunction( "year", Hibernate.INTEGER ) );
+		registerFunction( "week", new StandardSQLFunction( "week", Hibernate.INTEGER ) );
+		registerFunction( "quater", new StandardSQLFunction( "quater", Hibernate.INTEGER ) );
+		registerFunction( "hour", new StandardSQLFunction( "hour", Hibernate.INTEGER ) );
+		registerFunction( "minute", new StandardSQLFunction( "minute", Hibernate.INTEGER ) );
+		registerFunction( "second", new StandardSQLFunction( "second", Hibernate.INTEGER ) );
+		registerFunction( "dayname", new StandardSQLFunction( "dayname", Hibernate.STRING ) );
+		registerFunction( "monthname", new StandardSQLFunction( "monthname", Hibernate.STRING ) );
+
+		registerFunction( "abs", new StandardSQLFunction( "abs" ) );
+		registerFunction( "sign", new StandardSQLFunction( "sign", Hibernate.INTEGER ) );
+
+		registerFunction( "acos", new StandardSQLFunction( "acos", Hibernate.DOUBLE ) );
+		registerFunction( "asin", new StandardSQLFunction( "asin", Hibernate.DOUBLE ) );
+		registerFunction( "atan", new StandardSQLFunction( "atan", Hibernate.DOUBLE ) );
+		registerFunction( "cos", new StandardSQLFunction( "cos", Hibernate.DOUBLE ) );
+		registerFunction( "cot", new StandardSQLFunction( "cot", Hibernate.DOUBLE ) );
+		registerFunction( "exp", new StandardSQLFunction( "exp", Hibernate.DOUBLE ) );
+		registerFunction( "log", new StandardSQLFunction( "log", Hibernate.DOUBLE ) );
+		registerFunction( "log10", new StandardSQLFunction( "log10", Hibernate.DOUBLE ) );
+		registerFunction( "sin", new StandardSQLFunction( "sin", Hibernate.DOUBLE ) );
+		registerFunction( "sqrt", new StandardSQLFunction( "sqrt", Hibernate.DOUBLE ) );
+		registerFunction( "tan", new StandardSQLFunction( "tan", Hibernate.DOUBLE ) );
+		registerFunction( "pi", new NoArgSQLFunction( "pi", Hibernate.DOUBLE ) );
+		registerFunction( "rand", new StandardSQLFunction( "rand", Hibernate.FLOAT ) );
+
+		registerFunction( "radians", new StandardSQLFunction( "radians", Hibernate.DOUBLE ) );
+		registerFunction( "degrees", new StandardSQLFunction( "degrees", Hibernate.DOUBLE ) );
+		registerFunction( "roundmagic", new StandardSQLFunction( "roundmagic" ) );
+
+		registerFunction( "ceiling", new StandardSQLFunction( "ceiling" ) );
+		registerFunction( "floor", new StandardSQLFunction( "floor" ) );
+
+		// Multi-param dialect functions...
+		registerFunction( "mod", new StandardSQLFunction( "mod", Hibernate.INTEGER ) );
+
+		// function templates
+		registerFunction( "concat", new VarArgsSQLFunction( Hibernate.STRING, "(", "||", ")" ) );
+
+		getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
+
+		try {
+			// Does present HSQLDB Database class support schemas?
+			// yuck! Perhaps we should think about a new dialect?  Especially
+			// if more things are going to break back-compat moving forward
+			ReflectHelper.classForName( "org.hsqldb.Database" ).getDeclaredField( "schemaManager" );
+			schemaSupport = true;
+		}
+		catch (Throwable t) {
+			schemaSupport = false;
+		}
+	}
+
+	public String getAddColumnString() {
+		return "add column";
+	}
+
+	public boolean supportsIdentityColumns() {
+		return true;
+	}
+
+	public String getIdentityColumnString() {
+		return "generated by default as identity (start with 1)"; //not null is implicit
+	}
+
+	public String getIdentitySelectString() {
+		return "call identity()";
+	}
+
+	public String getIdentityInsertString() {
+		return "null";
+	}
+
+	public String getForUpdateString() {
+		return "";
+	}
+
+	public boolean supportsUnique() {
+		return false;
+	}
+
+	public boolean supportsLimit() {
+		return true;
+	}
+
+	public String getLimitString(String sql, boolean hasOffset) {
+		return new StringBuffer( sql.length() + 10 )
+				.append( sql )
+				.insert( sql.toLowerCase().indexOf( "select" ) + 6, hasOffset ? " limit ? ?" : " top ?" )
+				.toString();
+	}
+
+	public boolean bindLimitParametersFirst() {
+		return true;
+	}
+
+	public boolean supportsIfExistsAfterTableName() {
+		return true;
+	}
+
+	public boolean supportsColumnCheck() {
+		return false;
+	}
+
+	public boolean supportsSequences() {
+		return true;
+	}
+
+	public boolean supportsPooledSequences() {
+		return true;
+	}
+
+	public String[] getCreateSequenceStrings(String sequenceName) {
+		return getCreateSequenceStrings( sequenceName, 1, 1 );
+	}
+
+	public String[] getCreateSequenceStrings(String sequenceName, int initialValue, int incrementSize) {
+		return new String[] {
+				"create table dual_" + sequenceName + " (zero integer)",
+		        "insert into dual_" + sequenceName + " values (0)",
+		        "create sequence " + sequenceName + " start with " + initialValue + " increment by " + incrementSize
+		};
+	}
+
+	public String[] getDropSequenceStrings(String sequenceName) {
+		return new String[] {
+				"drop table dual_" + sequenceName + " if exists",
+		        "drop sequence " + sequenceName
+		};
+	}
+
+	public String getSelectSequenceNextValString(String sequenceName) {
+		return "next value for " + sequenceName;
+	}
+
+	public String getSequenceNextValString(String sequenceName) {
+		return "select next value for " + sequenceName + " from dual_" + sequenceName;
+	}
+
+	public String getQuerySequencesString() {
+		if ( schemaSupport ) {
+			return "select sequence_name from information_schema.system_sequences";
+		}
+		else {
+			return "select sequence_name from system_sequences";
+		}
+	}
+
+	public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
+		return EXTRACTER;
+	}
+
+	private static ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
+
+		/**
+		 * Extract the name of the violated constraint from the given SQLException.
+		 *
+		 * @param sqle The exception that was the result of the constraint violation.
+		 * @return The extracted constraint name.
+		 */
+		public String extractConstraintName(SQLException sqle) {
+			String constraintName = null;
+
+			int errorCode = JDBCExceptionHelper.extractErrorCode( sqle );
+
+			if ( errorCode == -8 ) {
+				constraintName = extractUsingTemplate(
+						"Integrity constraint violation ", " table:", sqle.getMessage()
+				);
+			}
+			else if ( errorCode == -9 ) {
+				constraintName = extractUsingTemplate(
+						"Violation of unique index: ", " in statement [", sqle.getMessage()
+				);
+			}
+			else if ( errorCode == -104 ) {
+				constraintName = extractUsingTemplate(
+						"Unique constraint violation: ", " in statement [", sqle.getMessage()
+				);
+			}
+			else if ( errorCode == -177 ) {
+				constraintName = extractUsingTemplate(
+						"Integrity constraint violation - no parent ", " table:", sqle.getMessage()
+				);
+			}
+
+			return constraintName;
+		}
+
+	};
+
+	/**
+	 * HSQL does not really support temp tables; just take advantage of the
+	 * fact that it is a single user db...
+	 */
+	public boolean supportsTemporaryTables() {
+		return true;
+	}
+
+	public boolean supportsCurrentTimestampSelection() {
+		return false;
+	}
+
+	public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
+		// HSQLDB only supports READ_UNCOMMITTED transaction isolation
+		return new ReadUncommittedLockingStrategy( lockable, lockMode );
+	}
+
+	public static class ReadUncommittedLockingStrategy extends SelectLockingStrategy {
+		public ReadUncommittedLockingStrategy(Lockable lockable, LockMode lockMode) {
+			super( lockable, lockMode );
+		}
+
+		public void lock(Serializable id, Object version, Object object, SessionImplementor session)
+				throws StaleObjectStateException, JDBCException {
+			if ( getLockMode().greaterThan( LockMode.READ ) ) {
+				log.warn( "HSQLDB supports only READ_UNCOMMITTED isolation" );
+			}
+			super.lock( id, version, object, session );
+		}
+	}
+
+
+	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsEmptyInList() {
+		return false;
+	}
+
+	public boolean supportsLobValueChangePropogation() {
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/InformixDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/InformixDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/InformixDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,213 @@
+//$Id: InformixDialect.java 11177 2007-02-09 15:43:04Z steve.ebersole at jboss.com $
+package org.hibernate.dialect;
+
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.MappingException;
+import org.hibernate.Hibernate;
+import org.hibernate.dialect.function.VarArgsSQLFunction;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.exception.TemplatedViolatedConstraintNameExtracter;
+import org.hibernate.exception.ViolatedConstraintNameExtracter;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Informix dialect.<br>
+ * <br>
+ * Seems to work with Informix Dynamic Server Version 7.31.UD3,
+ * Informix JDBC driver version 2.21JC3.
+ * @author Steve Molitor
+ */
+public class InformixDialect extends Dialect {
+
+	/**
+	 * Creates new <code>InformixDialect</code> instance. Sets up the JDBC /
+	 * Informix type mappings.
+	 */
+	public InformixDialect() {
+		super();
+
+		registerColumnType(Types.BIGINT, "int8");
+		registerColumnType(Types.BINARY, "byte");
+		registerColumnType(Types.BIT, "smallint"); // Informix doesn't have a bit type
+		registerColumnType(Types.CHAR, "char($l)");
+		registerColumnType(Types.DATE, "date");
+		registerColumnType(Types.DECIMAL, "decimal");
+        registerColumnType(Types.DOUBLE, "float");
+        registerColumnType(Types.FLOAT, "smallfloat");
+		registerColumnType(Types.INTEGER, "integer");
+		registerColumnType(Types.LONGVARBINARY, "blob"); // or BYTE
+		registerColumnType(Types.LONGVARCHAR, "clob"); // or TEXT?
+		registerColumnType(Types.NUMERIC, "decimal"); // or MONEY
+		registerColumnType(Types.REAL, "smallfloat");
+		registerColumnType(Types.SMALLINT, "smallint");
+		registerColumnType(Types.TIMESTAMP, "datetime year to fraction(5)");
+		registerColumnType(Types.TIME, "datetime hour to second");
+		registerColumnType(Types.TINYINT, "smallint");
+		registerColumnType(Types.VARBINARY, "byte");
+		registerColumnType(Types.VARCHAR, "varchar($l)");
+		registerColumnType(Types.VARCHAR, 255, "varchar($l)");
+		registerColumnType(Types.VARCHAR, 32739, "lvarchar($l)");
+
+		registerFunction( "concat", new VarArgsSQLFunction( Hibernate.STRING, "(", "||", ")" ) );
+	}
+
+	public String getAddColumnString() {
+		return "add";
+	}
+
+	public boolean supportsIdentityColumns() {
+		return true;
+	}
+
+	public String getIdentitySelectString(String table, String column, int type) 
+	throws MappingException {
+		return type==Types.BIGINT ?
+			"select dbinfo('serial8') from systables where tabid=1" :
+			"select dbinfo('sqlca.sqlerrd1') from systables where tabid=1";
+	}
+
+	public String getIdentityColumnString(int type) throws MappingException {
+		return type==Types.BIGINT ?
+			"serial8 not null" :
+			"serial not null";
+	}
+
+	public boolean hasDataTypeInIdentityColumn() {
+		return false;
+	}
+
+	/**
+	 * The syntax used to add a foreign key constraint to a table.
+	 * Informix constraint name must be at the end.
+	 * @return String
+	 */
+	public String getAddForeignKeyConstraintString(
+			String constraintName, 
+			String[] foreignKey, 
+			String referencedTable, 
+			String[] primaryKey, boolean referencesPrimaryKey
+	) {
+		StringBuffer result = new StringBuffer(30);
+		
+		result.append(" add constraint ")
+			.append(" foreign key (")
+			.append( StringHelper.join(", ", foreignKey) )
+			.append(") references ")
+			.append(referencedTable);
+		
+		if(!referencesPrimaryKey) {
+			result.append(" (")
+			   .append( StringHelper.join(", ", primaryKey) )
+			   .append(')');
+		}
+
+		result.append(" constraint ").append(constraintName);
+			
+			return result.toString();
+	}
+
+	/**
+	 * The syntax used to add a primary key constraint to a table.
+	 * Informix constraint name must be at the end.
+	 * @return String
+	 */
+	public String getAddPrimaryKeyConstraintString(String constraintName) {
+		return " add constraint primary key constraint " + constraintName + " ";
+	}
+
+	public String getCreateSequenceString(String sequenceName) {
+		return "create sequence " + sequenceName;
+	}
+	public String getDropSequenceString(String sequenceName) {
+		return "drop sequence " + sequenceName + " restrict";
+	}
+
+	public String getSequenceNextValString(String sequenceName) {
+		return "select " + getSelectSequenceNextValString( sequenceName ) + " from systables where tabid=1";
+	}
+
+	public String getSelectSequenceNextValString(String sequenceName) {
+		return sequenceName + ".nextval";
+	}
+
+	public boolean supportsSequences() {
+		return true;
+	}
+
+	public boolean supportsLimit() {
+		return true;
+	}
+
+	public boolean useMaxForLimit() {
+		return true;
+	}
+
+	public boolean supportsLimitOffset() {
+		return false;
+	}
+
+	public String getLimitString(String querySelect, int offset, int limit) {
+		if (offset>0) throw new UnsupportedOperationException("informix has no offset");
+		return new StringBuffer( querySelect.length()+8 )
+			.append(querySelect)
+			.insert( querySelect.toLowerCase().indexOf( "select" ) + 6, " first " + limit )
+			.toString();
+	}
+
+	public boolean supportsVariableLimit() {
+		return false;
+	}
+
+	public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
+        return EXTRACTER;
+	}
+
+	private static ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
+
+		/**
+		 * Extract the name of the violated constraint from the given SQLException.
+		 *
+		 * @param sqle The exception that was the result of the constraint violation.
+		 * @return The extracted constraint name.
+		 */
+		public String extractConstraintName(SQLException sqle) {
+			String constraintName = null;
+			
+			int errorCode = JDBCExceptionHelper.extractErrorCode(sqle);
+			if ( errorCode == -268 ) {
+				constraintName = extractUsingTemplate( "Unique constraint (", ") violated.", sqle.getMessage() );
+			}
+			else if ( errorCode == -691 ) {
+				constraintName = extractUsingTemplate( "Missing key in referenced table for referential constraint (", ").", sqle.getMessage() );
+			}
+			else if ( errorCode == -692 ) {
+				constraintName = extractUsingTemplate( "Key value for constraint (", ") is still being referenced.", sqle.getMessage() );
+			}
+			
+			if (constraintName != null) {
+				// strip table-owner because Informix always returns constraint names as "<table-owner>.<constraint-name>"
+				int i = constraintName.indexOf('.');
+				if (i != -1) {
+					constraintName = constraintName.substring(i + 1);
+				}
+			}
+
+			return constraintName;
+		}
+
+	};
+
+	public boolean supportsCurrentTimestampSelection() {
+		return true;
+	}
+
+	public boolean isCurrentTimestampSelectStringCallable() {
+		return false;
+	}
+
+	public String getCurrentTimestampSelectString() {
+		return "select distinct current timestamp from informix.systables";
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/IngresDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/IngresDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/IngresDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,292 @@
+//$Id: IngresDialect.java 10963 2006-12-08 16:06:14Z steve.ebersole at jboss.com $
+package org.hibernate.dialect;
+
+import java.sql.Types;
+
+import org.hibernate.Hibernate;
+import org.hibernate.dialect.function.SQLFunctionTemplate;
+import org.hibernate.dialect.function.NoArgSQLFunction;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.dialect.function.VarArgsSQLFunction;
+
+
+/**
+ * An Ingres SQL dialect.
+ * <p/>
+ * Known limitations:
+ * - only supports simple constants or columns on the left side of an IN, making (1,2,3) in (...) or (<subselect) in (...) non-supported
+ * - supports only 31 digits in decimal
+ *
+ * @author Ian Booth, Bruce Lunsford, Max Rydahl Andersen
+ */
+public class IngresDialect extends Dialect {
+
+	public IngresDialect() {
+		super();
+		registerColumnType( Types.BIT, "tinyint" );
+		registerColumnType( Types.TINYINT, "tinyint" );
+		registerColumnType( Types.SMALLINT, "smallint" );
+		registerColumnType( Types.INTEGER, "integer" );
+		registerColumnType( Types.BIGINT, "bigint" );
+		registerColumnType( Types.REAL, "real" );
+		registerColumnType( Types.FLOAT, "float" );
+		registerColumnType( Types.DOUBLE, "float" );
+		registerColumnType( Types.NUMERIC, "decimal($p, $s)" );
+		registerColumnType( Types.DECIMAL, "decimal($p, $s)" );
+		registerColumnType( Types.BINARY, 32000, "byte($l)" );
+		registerColumnType( Types.BINARY, "long byte" );
+		registerColumnType( Types.VARBINARY, 32000, "varbyte($l)" );
+		registerColumnType( Types.VARBINARY, "long byte" );
+		registerColumnType( Types.LONGVARBINARY, "long byte" );
+		registerColumnType( Types.CHAR, "char(1)" );
+		registerColumnType( Types.VARCHAR, 32000, "varchar($l)" );
+		registerColumnType( Types.VARCHAR, "long varchar" );
+		registerColumnType( Types.LONGVARCHAR, "long varchar" );
+		registerColumnType( Types.DATE, "date" );
+		registerColumnType( Types.TIME, "date" );
+		registerColumnType( Types.TIMESTAMP, "date" );
+		registerColumnType( Types.BLOB, "long byte" );
+		registerColumnType( Types.CLOB, "long varchar" );
+
+		registerFunction( "abs", new StandardSQLFunction( "abs" ) );
+		registerFunction( "atan", new StandardSQLFunction( "atan", Hibernate.DOUBLE ) );
+		registerFunction( "bit_add", new StandardSQLFunction( "bit_add" ) );
+		registerFunction( "bit_and", new StandardSQLFunction( "bit_and" ) );
+		registerFunction( "bit_length", new StandardSQLFunction( "bit_length" ) );
+		registerFunction( "bit_not", new StandardSQLFunction( "bit_not" ) );
+		registerFunction( "bit_or", new StandardSQLFunction( "bit_or" ) );
+		registerFunction( "bit_xor", new StandardSQLFunction( "bit_xor" ) );
+		registerFunction( "character_length", new StandardSQLFunction( "character_length", Hibernate.LONG ) );
+		registerFunction( "charextract", new StandardSQLFunction( "charextract", Hibernate.STRING ) );
+		registerFunction( "concat", new VarArgsSQLFunction( Hibernate.STRING, "(", "+", ")" ) );
+		registerFunction( "cos", new StandardSQLFunction( "cos", Hibernate.DOUBLE ) );
+		registerFunction( "current_user", new NoArgSQLFunction( "current_user", Hibernate.STRING, false ) );
+		registerFunction( "current_time", new NoArgSQLFunction( "date('now')", Hibernate.TIMESTAMP, false ) );
+		registerFunction( "current_timestamp", new NoArgSQLFunction( "date('now')", Hibernate.TIMESTAMP, false ) );
+		registerFunction( "current_date", new NoArgSQLFunction( "date('now')", Hibernate.TIMESTAMP, false ) );
+		registerFunction( "date_trunc", new StandardSQLFunction( "date_trunc", Hibernate.TIMESTAMP ) );
+		registerFunction( "day", new StandardSQLFunction( "day", Hibernate.INTEGER ) );
+		registerFunction( "dba", new NoArgSQLFunction( "dba", Hibernate.STRING, true ) );
+		registerFunction( "dow", new StandardSQLFunction( "dow", Hibernate.STRING ) );
+		registerFunction( "extract", new SQLFunctionTemplate( Hibernate.INTEGER, "date_part('?1', ?3)" ) );
+		registerFunction( "exp", new StandardSQLFunction( "exp", Hibernate.DOUBLE ) );
+		registerFunction( "gmt_timestamp", new StandardSQLFunction( "gmt_timestamp", Hibernate.STRING ) );
+		registerFunction( "hash", new StandardSQLFunction( "hash", Hibernate.INTEGER ) );
+		registerFunction( "hex", new StandardSQLFunction( "hex", Hibernate.STRING ) );
+		registerFunction( "hour", new StandardSQLFunction( "hour", Hibernate.INTEGER ) );
+		registerFunction( "initial_user", new NoArgSQLFunction( "initial_user", Hibernate.STRING, false ) );
+		registerFunction( "intextract", new StandardSQLFunction( "intextract", Hibernate.INTEGER ) );
+		registerFunction( "left", new StandardSQLFunction( "left", Hibernate.STRING ) );
+		registerFunction( "locate", new SQLFunctionTemplate( Hibernate.LONG, "locate(?1, ?2)" ) );
+		registerFunction( "length", new StandardSQLFunction( "length", Hibernate.LONG ) );
+		registerFunction( "ln", new StandardSQLFunction( "ln", Hibernate.DOUBLE ) );
+		registerFunction( "log", new StandardSQLFunction( "log", Hibernate.DOUBLE ) );
+		registerFunction( "lower", new StandardSQLFunction( "lower" ) );
+		registerFunction( "lowercase", new StandardSQLFunction( "lowercase" ) );
+		registerFunction( "minute", new StandardSQLFunction( "minute", Hibernate.INTEGER ) );
+		registerFunction( "month", new StandardSQLFunction( "month", Hibernate.INTEGER ) );
+		registerFunction( "octet_length", new StandardSQLFunction( "octet_length", Hibernate.LONG ) );
+		registerFunction( "pad", new StandardSQLFunction( "pad", Hibernate.STRING ) );
+		registerFunction( "position", new StandardSQLFunction( "position", Hibernate.LONG ) );
+		registerFunction( "power", new StandardSQLFunction( "power", Hibernate.DOUBLE ) );
+		registerFunction( "random", new NoArgSQLFunction( "random", Hibernate.LONG, true ) );
+		registerFunction( "randomf", new NoArgSQLFunction( "randomf", Hibernate.DOUBLE, true ) );
+		registerFunction( "right", new StandardSQLFunction( "right", Hibernate.STRING ) );
+		registerFunction( "session_user", new NoArgSQLFunction( "session_user", Hibernate.STRING, false ) );
+		registerFunction( "second", new StandardSQLFunction( "second", Hibernate.INTEGER ) );
+		registerFunction( "size", new NoArgSQLFunction( "size", Hibernate.LONG, true ) );
+		registerFunction( "squeeze", new StandardSQLFunction( "squeeze" ) );
+		registerFunction( "sin", new StandardSQLFunction( "sin", Hibernate.DOUBLE ) );
+		registerFunction( "soundex", new StandardSQLFunction( "soundex", Hibernate.STRING ) );
+		registerFunction( "sqrt", new StandardSQLFunction( "sqrt", Hibernate.DOUBLE ) );
+		registerFunction( "substring", new SQLFunctionTemplate( Hibernate.STRING, "substring(?1 FROM ?2 FOR ?3)" ) );
+		registerFunction( "system_user", new NoArgSQLFunction( "system_user", Hibernate.STRING, false ) );
+		registerFunction( "trim", new StandardSQLFunction( "trim", Hibernate.STRING ) );
+		registerFunction( "unhex", new StandardSQLFunction( "unhex", Hibernate.STRING ) );
+		registerFunction( "upper", new StandardSQLFunction( "upper" ) );
+		registerFunction( "uppercase", new StandardSQLFunction( "uppercase" ) );
+		registerFunction( "user", new NoArgSQLFunction( "user", Hibernate.STRING, false ) );
+		registerFunction( "usercode", new NoArgSQLFunction( "usercode", Hibernate.STRING, true ) );
+		registerFunction( "username", new NoArgSQLFunction( "username", Hibernate.STRING, true ) );
+		registerFunction( "uuid_create", new StandardSQLFunction( "uuid_create", Hibernate.BYTE ) );
+		registerFunction( "uuid_compare", new StandardSQLFunction( "uuid_compare", Hibernate.INTEGER ) );
+		registerFunction( "uuid_from_char", new StandardSQLFunction( "uuid_from_char", Hibernate.BYTE ) );
+		registerFunction( "uuid_to_char", new StandardSQLFunction( "uuid_to_char", Hibernate.STRING ) );
+		registerFunction( "year", new StandardSQLFunction( "year", Hibernate.INTEGER ) );
+	}
+
+	/**
+	 * Do we need to drop constraints before dropping tables in this dialect?
+	 *
+	 * @return boolean
+	 */
+	public boolean dropConstraints() {
+		return false;
+	}
+
+	/**
+	 * Does this dialect support <tt>FOR UPDATE OF</tt>, allowing
+	 * particular rows to be locked?
+	 *
+	 * @return True (Ingres does support "for update of" syntax...)
+	 */
+	public boolean supportsForUpdateOf() {
+		return true;
+	}
+
+	/**
+	 * The syntax used to add a column to a table (optional).
+	 */
+	public String getAddColumnString() {
+		return "add column";
+	}
+
+	/**
+	 * The keyword used to specify a nullable column.
+	 *
+	 * @return String
+	 */
+	public String getNullColumnString() {
+		return " with null";
+	}
+
+	/**
+	 * Does this dialect support sequences?
+	 *
+	 * @return boolean
+	 */
+	public boolean supportsSequences() {
+		return true;
+	}
+
+	/**
+	 * The syntax that fetches the next value of a sequence, if sequences are supported.
+	 *
+	 * @param sequenceName the name of the sequence
+	 *
+	 * @return String
+	 */
+	public String getSequenceNextValString(String sequenceName) {
+		return "select nextval for " + sequenceName;
+	}
+
+	/**
+	 * The syntax used to create a sequence, if sequences are supported.
+	 *
+	 * @param sequenceName the name of the sequence
+	 *
+	 * @return String
+	 */
+	public String getCreateSequenceString(String sequenceName) {
+		return "create sequence " + sequenceName;
+	}
+
+	/**
+	 * The syntax used to drop a sequence, if sequences are supported.
+	 *
+	 * @param sequenceName the name of the sequence
+	 *
+	 * @return String
+	 */
+	public String getDropSequenceString(String sequenceName) {
+		return "drop sequence " + sequenceName + " restrict";
+	}
+
+	/**
+	 * A query used to find all sequences
+	 */
+	public String getQuerySequencesString() {
+		return "select seq_name from iisequence";
+	}
+
+	/**
+	 * The name of the SQL function that transforms a string to
+	 * lowercase
+	 *
+	 * @return String
+	 */
+	public String getLowercaseFunction() {
+		return "lowercase";
+	}
+
+	/**
+	 * Does this <tt>Dialect</tt> have some kind of <tt>LIMIT</tt> syntax?
+	 */
+	public boolean supportsLimit() {
+		return true;
+	}
+
+	/**
+	 * Does this dialect support an offset?
+	 */
+	public boolean supportsLimitOffset() {
+		return false;
+	}
+
+	/**
+	 * Add a <tt>LIMIT</tt> clause to the given SQL <tt>SELECT</tt>
+	 *
+	 * @return the modified SQL
+	 */
+	public String getLimitString(String querySelect, int offset, int limit) {
+		if ( offset > 0 ) {
+			throw new UnsupportedOperationException( "offset not supported" );
+		}
+		return new StringBuffer( querySelect.length() + 16 )
+				.append( querySelect )
+				.insert( 6, " first " + limit )
+				.toString();
+	}
+
+	public boolean supportsVariableLimit() {
+		return false;
+	}
+
+	/**
+	 * Does the <tt>LIMIT</tt> clause take a "maximum" row number instead
+	 * of a total number of returned rows?
+	 */
+	public boolean useMaxForLimit() {
+		return true;
+	}
+
+	/**
+	 * Ingres explicitly needs "unique not null", because "with null" is default
+	 */
+	public boolean supportsNotNullUnique() {
+		return false;
+	}
+
+	/**
+	 * Does this dialect support temporary tables?
+	 */
+	public boolean supportsTemporaryTables() {
+		return true;
+	}
+
+	public String getCreateTemporaryTableString() {
+		return "declare global temporary table";
+	}
+
+	public String getCreateTemporaryTablePostfix() {
+		return "on commit preserve rows with norecovery";
+	}
+
+	public String generateTemporaryTableName(String baseTableName) {
+		return "session." + super.generateTemporaryTableName( baseTableName );
+	}
+
+
+	/**
+	 * Expression for current_timestamp
+	 */
+	public String getCurrentTimestampSQLFunctionName() {
+		return "date(now)";
+	}
+
+	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsSubselectAsInPredicateLHS() {
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/InterbaseDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/InterbaseDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/InterbaseDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,105 @@
+//$Id: InterbaseDialect.java 7746 2005-08-03 23:29:32Z oneovthafew $
+package org.hibernate.dialect;
+
+import java.sql.Types;
+
+import org.hibernate.Hibernate;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.VarArgsSQLFunction;
+
+/**
+ * An SQL dialect for Interbase.
+ * @author Gavin King
+ */
+public class InterbaseDialect extends Dialect {
+
+	public InterbaseDialect() {
+		super();
+		registerColumnType( Types.BIT, "smallint" );
+		registerColumnType( Types.BIGINT, "numeric(18,0)" );
+		registerColumnType( Types.SMALLINT, "smallint" );
+		registerColumnType( Types.TINYINT, "smallint" );
+		registerColumnType( Types.INTEGER, "integer" );
+		registerColumnType( Types.CHAR, "char(1)" );
+		registerColumnType( Types.VARCHAR, "varchar($l)" );
+		registerColumnType( Types.FLOAT, "float" );
+		registerColumnType( Types.DOUBLE, "double precision" );
+		registerColumnType( Types.DATE, "date" );
+		registerColumnType( Types.TIME, "time" );
+		registerColumnType( Types.TIMESTAMP, "timestamp" );
+		registerColumnType( Types.VARBINARY, "blob" );
+		registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
+		registerColumnType( Types.BLOB, "blob" );
+		registerColumnType( Types.CLOB, "blob sub_type 1" );
+		
+		registerFunction( "concat", new VarArgsSQLFunction( Hibernate.STRING, "(","||",")" ) );
+
+		getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, NO_BATCH);
+	}
+
+	public String getAddColumnString() {
+		return "add";
+	}
+
+	public String getSequenceNextValString(String sequenceName) {
+		return "select " + getSelectSequenceNextValString( sequenceName ) + " from RDB$DATABASE";
+	}
+
+	public String getSelectSequenceNextValString(String sequenceName) {
+		return "gen_id( " + sequenceName + ", 1 )";
+	}
+
+	public String getCreateSequenceString(String sequenceName) {
+		return "create generator " + sequenceName;
+	}
+
+	public String getDropSequenceString(String sequenceName) {
+		return "delete from RDB$GENERATORS where RDB$GENERATOR_NAME = '" + sequenceName.toUpperCase() + "'";
+	}
+
+	public String getQuerySequencesString() {
+		return "select RDB$GENERATOR_NAME from RDB$GENERATORS";
+	}
+	
+	public String getForUpdateString() {
+		return " with lock";
+	}
+	public String getForUpdateString(String aliases) {
+		return " for update of " + aliases + " with lock";
+	}
+
+	public boolean supportsSequences() {
+		return true;
+	}
+
+	public boolean supportsLimit() {
+		return true;
+	}
+
+	public String getLimitString(String sql, boolean hasOffset) {
+		return new StringBuffer( sql.length()+15 )
+			.append(sql)
+			.append(hasOffset ? " rows ? to ?" : " rows ?")
+			.toString();
+	}
+
+	public boolean bindLimitParametersFirst() {
+		return false;
+	}
+
+	public boolean bindLimitParametersInReverseOrder() {
+		return false;
+	}
+
+	public String getCurrentTimestampCallString() {
+		// TODO : not sure which (either?) is correct, could not find docs on how to do this.
+		// did find various blogs and forums mentioning that select CURRENT_TIMESTAMP
+		// does not work...
+		return "{?= call CURRENT_TIMESTAMP }";
+//		return "select CURRENT_TIMESTAMP from RDB$DATABASE";
+	}
+
+	public boolean isCurrentTimestampSelectStringCallable() {
+		return true;
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/JDataStoreDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/JDataStoreDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/JDataStoreDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+// $Id: JDataStoreDialect.java 7075 2005-06-08 07:06:50Z oneovthafew $
+package org.hibernate.dialect;
+
+import java.sql.Types;
+
+import org.hibernate.cfg.Environment;
+
+/**
+ * A <tt>Dialect</tt> for JDataStore.
+ * 
+ * @author Vishy Kasar
+ */
+public class JDataStoreDialect extends Dialect {
+
+	/**
+	 * Creates new JDataStoreDialect
+	 */
+	public JDataStoreDialect() {
+		super();
+
+		registerColumnType( Types.BIT, "tinyint" );
+		registerColumnType( Types.BIGINT, "bigint" );
+		registerColumnType( Types.SMALLINT, "smallint" );
+		registerColumnType( Types.TINYINT, "tinyint" );
+		registerColumnType( Types.INTEGER, "integer" );
+		registerColumnType( Types.CHAR, "char(1)" );
+		registerColumnType( Types.VARCHAR, "varchar($l)" );
+		registerColumnType( Types.FLOAT, "float" );
+		registerColumnType( Types.DOUBLE, "double" );
+		registerColumnType( Types.DATE, "date" );
+		registerColumnType( Types.TIME, "time" );
+		registerColumnType( Types.TIMESTAMP, "timestamp" );
+		registerColumnType( Types.VARBINARY, "varbinary($l)" );
+		registerColumnType( Types.NUMERIC, "numeric($p, $s)" );
+
+		registerColumnType( Types.BLOB, "varbinary" );
+		registerColumnType( Types.CLOB, "varchar" );
+
+		getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
+	}
+
+	public String getAddColumnString() {
+		return "add";
+	}
+
+	public boolean dropConstraints() {
+		return false;
+	}
+
+	public String getCascadeConstraintsString() {
+		return " cascade";
+	}
+
+	public boolean supportsIdentityColumns() {
+		return true;
+	}
+
+	public String getIdentitySelectString() {
+		return null; // NOT_SUPPORTED_SHOULD_USE_JDBC3_PreparedStatement.getGeneratedKeys_method
+	}
+
+	public String getIdentityColumnString() {
+		return "autoincrement";
+	}
+
+	public String getNoColumnsInsertString() {
+		return "default values";
+	}
+
+	public boolean supportsColumnCheck() {
+		return false;
+	}
+
+	public boolean supportsTableCheck() {
+		return false;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/JDataStoreDialect.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MckoiDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MckoiDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MckoiDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,98 @@
+//$Id: MckoiDialect.java 9328 2006-02-23 17:32:47Z steveebersole $
+package org.hibernate.dialect;
+
+import java.sql.Types;
+
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.persister.entity.Lockable;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.dialect.lock.LockingStrategy;
+import org.hibernate.dialect.lock.UpdateLockingStrategy;
+import org.hibernate.dialect.lock.SelectLockingStrategy;
+import org.hibernate.sql.CaseFragment;
+import org.hibernate.sql.MckoiCaseFragment;
+
+/**
+ * An SQL dialect compatible with McKoi SQL
+ * @author Doug Currie, Gabe Hicks
+ */
+public class MckoiDialect extends Dialect {
+	public MckoiDialect() {
+		super();
+		registerColumnType( Types.BIT, "bit" );
+		registerColumnType( Types.BIGINT, "bigint" );
+		registerColumnType( Types.SMALLINT, "smallint" );
+		registerColumnType( Types.TINYINT, "tinyint" );
+		registerColumnType( Types.INTEGER, "integer" );
+		registerColumnType( Types.CHAR, "char(1)" );
+		registerColumnType( Types.VARCHAR, "varchar($l)" );
+		registerColumnType( Types.FLOAT, "float" );
+		registerColumnType( Types.DOUBLE, "double" );
+		registerColumnType( Types.DATE, "date" );
+		registerColumnType( Types.TIME, "time" );
+		registerColumnType( Types.TIMESTAMP, "timestamp" );
+		registerColumnType( Types.VARBINARY, "varbinary" );
+		registerColumnType( Types.NUMERIC, "numeric" );
+		registerColumnType( Types.BLOB, "blob" );
+		registerColumnType( Types.CLOB, "clob" );
+
+		registerFunction( "upper", new StandardSQLFunction("upper") );
+		registerFunction( "lower", new StandardSQLFunction("lower") );
+		registerFunction( "sqrt", new StandardSQLFunction("sqrt", Hibernate.DOUBLE) );
+		registerFunction( "abs", new StandardSQLFunction("abs") );
+		registerFunction( "sign", new StandardSQLFunction( "sign", Hibernate.INTEGER ) );
+		registerFunction( "length", new StandardSQLFunction( "length", Hibernate.INTEGER ) );
+		registerFunction( "round", new StandardSQLFunction( "round", Hibernate.INTEGER ) );
+		registerFunction( "mod", new StandardSQLFunction( "mod", Hibernate.INTEGER ) );
+		registerFunction( "least", new StandardSQLFunction("least") );
+		registerFunction( "greatest", new StandardSQLFunction("greatest") );
+		registerFunction( "user", new StandardSQLFunction( "user", Hibernate.STRING ) );
+		registerFunction( "concat", new StandardSQLFunction( "concat", Hibernate.STRING ) );
+
+		getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, NO_BATCH);
+	}
+
+	public String getAddColumnString() {
+		return "add column";
+	}
+
+	public String getSequenceNextValString(String sequenceName) {
+		return "select " + getSelectSequenceNextValString( sequenceName );
+	}
+
+	public String getSelectSequenceNextValString(String sequenceName) {
+		return "nextval('" + sequenceName + "')";
+	}
+
+	public String getCreateSequenceString(String sequenceName) {
+		return "create sequence " + sequenceName;
+	}
+
+	public String getDropSequenceString(String sequenceName) {
+		return "drop sequence " + sequenceName;
+	}
+
+	public String getForUpdateString() {
+		return "";
+	}
+
+	public boolean supportsSequences() {
+		return true;
+	}
+
+	public CaseFragment createCaseFragment() {
+		return new MckoiCaseFragment();
+	}
+
+	public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
+		// Mckoi has no known variation of a "SELECT ... FOR UPDATE" syntax...
+		if ( lockMode.greaterThan( LockMode.READ ) ) {
+			return new UpdateLockingStrategy( lockable, lockMode );
+		}
+		else {
+			return new SelectLockingStrategy( lockable, lockMode );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MimerSQLDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MimerSQLDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MimerSQLDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,221 @@
+//$Id: MimerSQLDialect.java 7822 2005-08-10 19:49:36Z oneovthafew $
+package org.hibernate.dialect;
+
+import java.sql.Types;
+
+import org.hibernate.Hibernate;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.*;
+
+/**
+ * An Hibernate 3 SQL dialect for Mimer SQL. This dialect requires Mimer SQL 9.2.1 or later
+ * because of the mappings to NCLOB, BINARY, and BINARY VARYING.
+ * @author Fredrik Ålund <fredrik.alund at mimer.se>
+ */
+public class MimerSQLDialect extends Dialect {
+
+	private static final int NATIONAL_CHAR_LENGTH = 2000;
+	private static final int BINARY_MAX_LENGTH = 2000;
+
+	/**
+	 * Even thoug Mimer SQL supports character and binary columns up to 15 000 in lenght,
+	 * this is also the maximum width of the table (exluding LOBs). To avoid breaking the limit all the
+	 * time we limit the length of the character columns to CHAR_MAX_LENTH, NATIONAL_CHAR_LENGTH for national
+	 * characters, and BINARY_MAX_LENGTH for binary types.
+	 *
+	 */
+	public MimerSQLDialect() {
+		super();
+		registerColumnType( Types.BIT, "ODBC.BIT" );
+		registerColumnType( Types.BIGINT, "BIGINT" );
+		registerColumnType( Types.SMALLINT, "SMALLINT" );
+		registerColumnType( Types.TINYINT, "ODBC.TINYINT" );
+		registerColumnType( Types.INTEGER, "INTEGER" );
+		registerColumnType( Types.CHAR, "NCHAR(1)" );
+		registerColumnType( Types.VARCHAR, NATIONAL_CHAR_LENGTH, "NATIONAL CHARACTER VARYING($l)" );
+		registerColumnType( Types.VARCHAR, "NCLOB($l)" );
+		registerColumnType( Types.LONGVARCHAR, "CLOB($1)");
+		registerColumnType( Types.FLOAT, "FLOAT" );
+		registerColumnType( Types.DOUBLE, "DOUBLE PRECISION" );
+		registerColumnType( Types.DATE, "DATE" );
+		registerColumnType( Types.TIME, "TIME" );
+		registerColumnType( Types.TIMESTAMP, "TIMESTAMP" );
+		registerColumnType( Types.VARBINARY, BINARY_MAX_LENGTH, "BINARY VARYING($l)" );
+		registerColumnType( Types.VARBINARY, "BLOB($1)" );
+		registerColumnType( Types.LONGVARBINARY, "BLOB($1)");
+		registerColumnType( Types.BINARY, BINARY_MAX_LENGTH, "BINARY" );
+		registerColumnType( Types.BINARY, "BLOB($1)" );
+		registerColumnType( Types.NUMERIC, "NUMERIC(19, $l)" );
+		registerColumnType( Types.BLOB, "BLOB($l)" );
+		registerColumnType( Types.CLOB, "NCLOB($l)" );
+
+		registerFunction("abs", new StandardSQLFunction("abs") );
+		registerFunction("sign", new StandardSQLFunction("sign", Hibernate.INTEGER) );
+		registerFunction("ceiling", new StandardSQLFunction("ceiling") );
+		registerFunction("floor", new StandardSQLFunction("floor") );
+		registerFunction("round", new StandardSQLFunction("round") );
+
+		registerFunction("dacos", new StandardSQLFunction("dacos", Hibernate.DOUBLE) );
+		registerFunction("acos", new StandardSQLFunction("dacos", Hibernate.DOUBLE) );
+		registerFunction("dasin", new StandardSQLFunction("dasin", Hibernate.DOUBLE) );
+		registerFunction("asin", new StandardSQLFunction("dasin", Hibernate.DOUBLE) );
+		registerFunction("datan", new StandardSQLFunction("datan", Hibernate.DOUBLE) );
+		registerFunction("atan", new StandardSQLFunction("datan", Hibernate.DOUBLE) );
+		registerFunction("datan2", new StandardSQLFunction("datan2", Hibernate.DOUBLE) );
+		registerFunction("atan2", new StandardSQLFunction("datan2", Hibernate.DOUBLE) );
+		registerFunction("dcos", new StandardSQLFunction("dcos", Hibernate.DOUBLE) );
+		registerFunction("cos", new StandardSQLFunction("dcos", Hibernate.DOUBLE) );
+		registerFunction("dcot", new StandardSQLFunction("dcot", Hibernate.DOUBLE) );
+		registerFunction("cot", new StandardSQLFunction("dcot", Hibernate.DOUBLE) );
+		registerFunction("ddegrees", new StandardSQLFunction("ddegrees", Hibernate.DOUBLE) );
+		registerFunction("degrees", new StandardSQLFunction("ddegrees", Hibernate.DOUBLE) );
+		registerFunction("dexp", new StandardSQLFunction("dexp", Hibernate.DOUBLE) );
+		registerFunction("exp", new StandardSQLFunction("dexp", Hibernate.DOUBLE) );
+		registerFunction("dlog", new StandardSQLFunction("dlog", Hibernate.DOUBLE) );
+		registerFunction("log", new StandardSQLFunction("dlog", Hibernate.DOUBLE) );
+		registerFunction("dlog10", new StandardSQLFunction("dlog10", Hibernate.DOUBLE) );
+		registerFunction("log10", new StandardSQLFunction("dlog10", Hibernate.DOUBLE) );
+		registerFunction("dradian", new StandardSQLFunction("dradian", Hibernate.DOUBLE) );
+		registerFunction("radian", new StandardSQLFunction("dradian", Hibernate.DOUBLE) );
+		registerFunction("dsin", new StandardSQLFunction("dsin", Hibernate.DOUBLE) );
+		registerFunction("sin", new StandardSQLFunction("dsin", Hibernate.DOUBLE) );
+		registerFunction("soundex", new StandardSQLFunction("soundex", Hibernate.STRING) );
+		registerFunction("dsqrt", new StandardSQLFunction("dsqrt", Hibernate.DOUBLE) );
+		registerFunction("sqrt", new StandardSQLFunction("dsqrt", Hibernate.DOUBLE) );
+		registerFunction("dtan", new StandardSQLFunction("dtan", Hibernate.DOUBLE) );
+		registerFunction("tan", new StandardSQLFunction("dtan", Hibernate.DOUBLE) );
+		registerFunction("dpower", new StandardSQLFunction("dpower") );
+		registerFunction("power", new StandardSQLFunction("dpower") );
+
+		registerFunction("date", new StandardSQLFunction("date", Hibernate.DATE) );
+		registerFunction("dayofweek", new StandardSQLFunction("dayofweek", Hibernate.INTEGER) );
+		registerFunction("dayofyear", new StandardSQLFunction("dayofyear", Hibernate.INTEGER) );
+		registerFunction("time", new StandardSQLFunction("time", Hibernate.TIME) );
+		registerFunction("timestamp", new StandardSQLFunction("timestamp", Hibernate.TIMESTAMP) );
+		registerFunction("week", new StandardSQLFunction("week", Hibernate.INTEGER) );
+
+
+		registerFunction("varchar", new StandardSQLFunction("varchar", Hibernate.STRING) );
+		registerFunction("real", new StandardSQLFunction("real", Hibernate.FLOAT) );
+		registerFunction("bigint", new StandardSQLFunction("bigint", Hibernate.LONG) );
+		registerFunction("char", new StandardSQLFunction("char", Hibernate.CHARACTER) );
+		registerFunction("integer", new StandardSQLFunction("integer", Hibernate.INTEGER) );
+		registerFunction("smallint", new StandardSQLFunction("smallint", Hibernate.SHORT) );
+
+		registerFunction("ascii_char", new StandardSQLFunction("ascii_char", Hibernate.CHARACTER) );
+		registerFunction("ascii_code", new StandardSQLFunction("ascii_code", Hibernate.STRING));
+		registerFunction("unicode_char", new StandardSQLFunction("unicode_char", Hibernate.LONG));
+		registerFunction("unicode_code", new StandardSQLFunction("unicode_code", Hibernate.STRING));
+		registerFunction("upper", new StandardSQLFunction("upper") );
+		registerFunction("lower", new StandardSQLFunction("lower") );
+		registerFunction("char_length", new StandardSQLFunction("char_length", Hibernate.LONG) );
+		registerFunction("bit_length", new StandardSQLFunction("bit_length", Hibernate.STRING));
+
+		getDefaultProperties().setProperty(Environment.USE_STREAMS_FOR_BINARY, "true");
+		getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, "50");
+	}
+
+	/**
+	 * The syntax used to add a column to a table
+	 */
+	public String getAddColumnString() {
+		return "add column";
+	}
+
+	/**
+	 * We do not have to drop constraints before we drop the table
+	 */
+	public boolean dropConstraints() {
+		return false;
+	}
+
+	/**
+	 * TODO: Check if Mimer SQL cannot handle the way DB2 does
+	 */
+	public boolean supportsIdentityColumns() {
+		return false;
+	}
+
+	/**
+	 * Mimer SQL supports sequences
+	 * @return boolean
+	 */
+	public boolean supportsSequences() {
+		return true;
+	}
+
+	/**
+	 * The syntax used to get the next value of a sequence in Mimer SQL
+	 */
+	public String getSequenceNextValString(String sequenceName) {
+		return "select next_value of " + sequenceName + " from system.onerow";
+	}
+
+	/**
+	 * The syntax used to create a sequence. Since we presume the sequences will be used as keys,
+	 * we make them unique.
+	 */
+	public String getCreateSequenceString(String sequenceName) {
+		return "create unique sequence " + sequenceName;
+	}
+
+	/**
+	* The syntax used to drop sequences
+	*/
+	public String getDropSequenceString(String sequenceName) {
+		return "drop sequence " + sequenceName + " restrict";
+	}
+
+	/**
+	* Mimer SQL does not support limit
+	*/
+	public boolean supportsLimit() {
+		return false;
+	}
+
+	/**
+	* The syntax for using cascade on constraints
+	*/
+	public String getCascadeConstraintsString() {
+		return " cascade";
+	}
+
+	/**
+	* The syntax for fetching all sequnces avialable in the current schema.
+	*/
+	public String getQuerySequencesString() {
+		return "select sequence_schema || '.' || sequence_name from information_schema.ext_sequences";
+	}
+
+	/**
+	 * Does the <tt>FOR UPDATE OF</tt> syntax specify particular
+	 * columns?
+	 */
+	public boolean forUpdateOfColumns() {
+		return false;
+	}
+
+	/**
+	 * Support the FOR UPDATE syntax? For now, returns false since
+	 * the current version of the Mimer SQL JDBC Driver does not support
+	 * updatable resultsets. Otherwise, Mimer SQL actually supports the for update syntax.
+	 * @return boolean
+	 */
+	public boolean supportsForUpdate() {
+		return false;
+	}
+
+
+	/**
+	 * For now, simply return false since we don't updatable result sets.
+	 */
+	public boolean supportsOuterJoinForUpdate() {
+		return false;
+	}
+}
+
+
+
+
+
+


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MimerSQLDialect.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQL5Dialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQL5Dialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQL5Dialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+package org.hibernate.dialect;
+
+import java.sql.Types;
+
+/**
+ * An SQL dialect for MySQL 5.x specific features.
+ *
+ * @author Steve Ebersole
+ */
+public class MySQL5Dialect extends MySQLDialect {
+	protected void registerVarcharTypes() {
+		registerColumnType( Types.VARCHAR, "longtext" );
+		registerColumnType( Types.VARCHAR, 16777215, "mediumtext" );
+		registerColumnType( Types.VARCHAR, 65535, "varchar($l)" );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQL5InnoDBDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQL5InnoDBDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQL5InnoDBDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+//$Id:  $
+package org.hibernate.dialect;
+
+/**
+ * @author Gavin King, Scott Marlow
+ */
+public class MySQL5InnoDBDialect extends MySQL5Dialect {
+
+	public boolean supportsCascadeDelete() {
+		return true;
+	}
+	
+	public String getTableTypeString() {
+		return " ENGINE=InnoDB";
+	}
+
+	public boolean hasSelfReferentialForeignKeyBug() {
+		return true;
+	}
+	
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQL5InnoDBDialect.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQLDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQLDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQLDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,350 @@
+//$Id: MySQLDialect.java 10963 2006-12-08 16:06:14Z steve.ebersole at jboss.com $
+package org.hibernate.dialect;
+
+import java.sql.CallableStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.Hibernate;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.NoArgSQLFunction;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.util.StringHelper;
+
+/**
+ * An SQL dialect for MySQL (prior to 5.x).
+ *
+ * @author Gavin King
+ */
+public class MySQLDialect extends Dialect {
+
+	public MySQLDialect() {
+		super();
+		registerColumnType( Types.BIT, "bit" );
+		registerColumnType( Types.BIGINT, "bigint" );
+		registerColumnType( Types.SMALLINT, "smallint" );
+		registerColumnType( Types.TINYINT, "tinyint" );
+		registerColumnType( Types.INTEGER, "integer" );
+		registerColumnType( Types.CHAR, "char(1)" );
+		registerColumnType( Types.FLOAT, "float" );
+		registerColumnType( Types.DOUBLE, "double precision" );
+		registerColumnType( Types.DATE, "date" );
+		registerColumnType( Types.TIME, "time" );
+		registerColumnType( Types.TIMESTAMP, "datetime" );
+		registerColumnType( Types.VARBINARY, "longblob" );
+		registerColumnType( Types.VARBINARY, 16777215, "mediumblob" );
+		registerColumnType( Types.VARBINARY, 65535, "blob" );
+		registerColumnType( Types.VARBINARY, 255, "tinyblob" );
+		registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
+		registerColumnType( Types.BLOB, "longblob" );
+		registerColumnType( Types.BLOB, 16777215, "mediumblob" );
+		registerColumnType( Types.BLOB, 65535, "blob" );
+		registerColumnType( Types.CLOB, "longtext" );
+		registerColumnType( Types.CLOB, 16777215, "mediumtext" );
+		registerColumnType( Types.CLOB, 65535, "text" );
+		registerVarcharTypes();
+
+		registerFunction("ascii", new StandardSQLFunction("ascii", Hibernate.INTEGER) );
+		registerFunction("bin", new StandardSQLFunction("bin", Hibernate.STRING) );
+		registerFunction("char_length", new StandardSQLFunction("char_length", Hibernate.LONG) );
+		registerFunction("character_length", new StandardSQLFunction("character_length", Hibernate.LONG) );
+		registerFunction("lcase", new StandardSQLFunction("lcase") );
+		registerFunction("lower", new StandardSQLFunction("lower") );
+		registerFunction("length", new StandardSQLFunction("length", Hibernate.LONG) );
+		registerFunction("ltrim", new StandardSQLFunction("ltrim") );
+		registerFunction("ord", new StandardSQLFunction("ord", Hibernate.INTEGER) );
+		registerFunction("quote", new StandardSQLFunction("quote") );
+		registerFunction("reverse", new StandardSQLFunction("reverse") );
+		registerFunction("rtrim", new StandardSQLFunction("rtrim") );
+		registerFunction("soundex", new StandardSQLFunction("soundex") );
+		registerFunction("space", new StandardSQLFunction("space", Hibernate.STRING) );
+		registerFunction("ucase", new StandardSQLFunction("ucase") );
+		registerFunction("upper", new StandardSQLFunction("upper") );
+		registerFunction("unhex", new StandardSQLFunction("unhex", Hibernate.STRING) );
+
+		registerFunction("abs", new StandardSQLFunction("abs") );
+		registerFunction("sign", new StandardSQLFunction("sign", Hibernate.INTEGER) );
+
+		registerFunction("acos", new StandardSQLFunction("acos", Hibernate.DOUBLE) );
+		registerFunction("asin", new StandardSQLFunction("asin", Hibernate.DOUBLE) );
+		registerFunction("atan", new StandardSQLFunction("atan", Hibernate.DOUBLE) );
+		registerFunction("cos", new StandardSQLFunction("cos", Hibernate.DOUBLE) );
+		registerFunction("cot", new StandardSQLFunction("cot", Hibernate.DOUBLE) );
+		registerFunction("crc32", new StandardSQLFunction("crc32", Hibernate.LONG) );
+		registerFunction("exp", new StandardSQLFunction("exp", Hibernate.DOUBLE) );
+		registerFunction("ln", new StandardSQLFunction("ln", Hibernate.DOUBLE) );
+		registerFunction("log", new StandardSQLFunction("log", Hibernate.DOUBLE) );
+		registerFunction("log2", new StandardSQLFunction("log2", Hibernate.DOUBLE) );
+		registerFunction("log10", new StandardSQLFunction("log10", Hibernate.DOUBLE) );
+		registerFunction("pi", new NoArgSQLFunction("pi", Hibernate.DOUBLE) );
+		registerFunction("rand", new NoArgSQLFunction("rand", Hibernate.DOUBLE) );
+		registerFunction("sin", new StandardSQLFunction("sin", Hibernate.DOUBLE) );
+		registerFunction("sqrt", new StandardSQLFunction("sqrt", Hibernate.DOUBLE) );
+		registerFunction("tan", new StandardSQLFunction("tan", Hibernate.DOUBLE) );
+
+		registerFunction("radians", new StandardSQLFunction("radians", Hibernate.DOUBLE) );
+		registerFunction("degrees", new StandardSQLFunction("degrees", Hibernate.DOUBLE) );
+
+		registerFunction("ceiling", new StandardSQLFunction("ceiling", Hibernate.INTEGER) );
+		registerFunction("ceil", new StandardSQLFunction("ceil", Hibernate.INTEGER) );
+		registerFunction("floor", new StandardSQLFunction("floor", Hibernate.INTEGER) );
+		registerFunction("round", new StandardSQLFunction("round", Hibernate.INTEGER) );
+
+		registerFunction("datediff", new StandardSQLFunction("datediff", Hibernate.INTEGER) );
+		registerFunction("timediff", new StandardSQLFunction("timediff", Hibernate.TIME) );
+		registerFunction("date_format", new StandardSQLFunction("date_format", Hibernate.STRING) );
+
+		registerFunction("curdate", new NoArgSQLFunction("curdate", Hibernate.DATE) );
+		registerFunction("curtime", new NoArgSQLFunction("curtime", Hibernate.TIME) );
+		registerFunction("current_date", new NoArgSQLFunction("current_date", Hibernate.DATE, false) );
+		registerFunction("current_time", new NoArgSQLFunction("current_time", Hibernate.TIME, false) );
+		registerFunction("current_timestamp", new NoArgSQLFunction("current_timestamp", Hibernate.TIMESTAMP, false) );
+		registerFunction("date", new StandardSQLFunction("date", Hibernate.DATE) );
+		registerFunction("day", new StandardSQLFunction("day", Hibernate.INTEGER) );
+		registerFunction("dayofmonth", new StandardSQLFunction("dayofmonth", Hibernate.INTEGER) );
+		registerFunction("dayname", new StandardSQLFunction("dayname", Hibernate.STRING) );
+		registerFunction("dayofweek", new StandardSQLFunction("dayofweek", Hibernate.INTEGER) );
+		registerFunction("dayofyear", new StandardSQLFunction("dayofyear", Hibernate.INTEGER) );
+		registerFunction("from_days", new StandardSQLFunction("from_days", Hibernate.DATE) );
+		registerFunction("from_unixtime", new StandardSQLFunction("from_unixtime", Hibernate.TIMESTAMP) );
+		registerFunction("hour", new StandardSQLFunction("hour", Hibernate.INTEGER) );
+		registerFunction("last_day", new StandardSQLFunction("last_day", Hibernate.DATE) );
+		registerFunction("localtime", new NoArgSQLFunction("localtime", Hibernate.TIMESTAMP) );
+		registerFunction("localtimestamp", new NoArgSQLFunction("localtimestamp", Hibernate.TIMESTAMP) );
+		registerFunction("microseconds", new StandardSQLFunction("microseconds", Hibernate.INTEGER) );
+		registerFunction("minute", new StandardSQLFunction("minute", Hibernate.INTEGER) );
+		registerFunction("month", new StandardSQLFunction("month", Hibernate.INTEGER) );
+		registerFunction("monthname", new StandardSQLFunction("monthname", Hibernate.STRING) );
+		registerFunction("now", new NoArgSQLFunction("now", Hibernate.TIMESTAMP) );
+		registerFunction("quarter", new StandardSQLFunction("quarter", Hibernate.INTEGER) );
+		registerFunction("second", new StandardSQLFunction("second", Hibernate.INTEGER) );
+		registerFunction("sec_to_time", new StandardSQLFunction("sec_to_time", Hibernate.TIME) );
+		registerFunction("sysdate", new NoArgSQLFunction("sysdate", Hibernate.TIMESTAMP) );
+		registerFunction("time", new StandardSQLFunction("time", Hibernate.TIME) );
+		registerFunction("timestamp", new StandardSQLFunction("timestamp", Hibernate.TIMESTAMP) );
+		registerFunction("time_to_sec", new StandardSQLFunction("time_to_sec", Hibernate.INTEGER) );
+		registerFunction("to_days", new StandardSQLFunction("to_days", Hibernate.LONG) );
+		registerFunction("unix_timestamp", new StandardSQLFunction("unix_timestamp", Hibernate.LONG) );
+		registerFunction("utc_date", new NoArgSQLFunction("utc_date", Hibernate.STRING) );
+		registerFunction("utc_time", new NoArgSQLFunction("utc_time", Hibernate.STRING) );
+		registerFunction("utc_timestamp", new NoArgSQLFunction("utc_timestamp", Hibernate.STRING) );
+		registerFunction("week", new StandardSQLFunction("week", Hibernate.INTEGER) );
+		registerFunction("weekday", new StandardSQLFunction("weekday", Hibernate.INTEGER) );
+		registerFunction("weekofyear", new StandardSQLFunction("weekofyear", Hibernate.INTEGER) );
+		registerFunction("year", new StandardSQLFunction("year", Hibernate.INTEGER) );
+		registerFunction("yearweek", new StandardSQLFunction("yearweek", Hibernate.INTEGER) );
+
+		registerFunction("hex", new StandardSQLFunction("hex", Hibernate.STRING) );
+		registerFunction("oct", new StandardSQLFunction("oct", Hibernate.STRING) );
+
+		registerFunction("octet_length", new StandardSQLFunction("octet_length", Hibernate.LONG) );
+		registerFunction("bit_length", new StandardSQLFunction("bit_length", Hibernate.LONG) );
+
+		registerFunction("bit_count", new StandardSQLFunction("bit_count", Hibernate.LONG) );
+		registerFunction("encrypt", new StandardSQLFunction("encrypt", Hibernate.STRING) );
+		registerFunction("md5", new StandardSQLFunction("md5", Hibernate.STRING) );
+		registerFunction("sha1", new StandardSQLFunction("sha1", Hibernate.STRING) );
+		registerFunction("sha", new StandardSQLFunction("sha", Hibernate.STRING) );
+
+		registerFunction( "concat", new StandardSQLFunction( "concat", Hibernate.STRING ) );
+
+		getDefaultProperties().setProperty(Environment.MAX_FETCH_DEPTH, "2");
+		getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE);
+	}
+
+	protected void registerVarcharTypes() {
+		registerColumnType( Types.VARCHAR, "longtext" );
+		registerColumnType( Types.VARCHAR, 16777215, "mediumtext" );
+		registerColumnType( Types.VARCHAR, 65535, "text" );
+		registerColumnType( Types.VARCHAR, 255, "varchar($l)" );
+	}
+
+	public String getAddColumnString() {
+		return "add column";
+	}
+	
+	public boolean qualifyIndexName() {
+		return false;
+	}
+
+	public boolean supportsIdentityColumns() {
+		return true;
+	}
+	
+	public String getIdentitySelectString() {
+		return "select last_insert_id()";
+	}
+
+	public String getIdentityColumnString() {
+		return "not null auto_increment"; //starts with 1, implicitly
+	}
+
+	public String getAddForeignKeyConstraintString(
+			String constraintName, 
+			String[] foreignKey, 
+			String referencedTable, 
+			String[] primaryKey, boolean referencesPrimaryKey
+	) {
+		String cols = StringHelper.join(", ", foreignKey);
+		return new StringBuffer(30)
+			.append(" add index ")
+			.append(constraintName)
+			.append(" (")
+			.append(cols)
+			.append("), add constraint ")
+			.append(constraintName)
+			.append(" foreign key (")
+			.append(cols)
+			.append(") references ")
+			.append(referencedTable)
+			.append(" (")
+			.append( StringHelper.join(", ", primaryKey) )
+			.append(')')
+			.toString();
+	}
+
+	public boolean supportsLimit() {
+		return true;
+	}
+	
+	public String getDropForeignKeyString() {
+		return " drop foreign key ";
+	}
+
+	public String getLimitString(String sql, boolean hasOffset) {
+		return new StringBuffer( sql.length()+20 )
+			.append(sql)
+			.append( hasOffset ? " limit ?, ?" : " limit ?")
+			.toString();
+	}
+	
+	/*
+	 * Temporary, until MySQL fix Connector/J bug
+	 */
+	/*public String getLimitString(String sql, int offset, int limit) {
+		StringBuffer buf = new StringBuffer( sql.length()+20 )
+			.append(sql);
+		if (offset>0) {
+			buf.append(" limit ")
+				.append(offset)
+				.append(", ")
+				.append(limit);
+		}
+		else {
+			buf.append(" limit ")
+				.append(limit);
+		}
+		return buf.toString();
+	}*/
+
+	/*
+	 * Temporary, until MySQL fix Connector/J bug
+	 */
+	/*public boolean supportsVariableLimit() {
+		return false;
+	}*/
+
+	public char closeQuote() {
+		return '`';
+	}
+
+	public char openQuote() {
+		return '`';
+	}
+
+	public boolean supportsIfExistsBeforeTableName() {
+		return true;
+	}
+
+	public String getSelectGUIDString() {
+		return "select uuid()";
+	}
+
+	public boolean supportsCascadeDelete() {
+		return false;
+	}
+	
+	public String getTableComment(String comment) {
+		return " comment='" + comment + "'";
+	}
+
+	public String getColumnComment(String comment) {
+		return " comment '" + comment + "'";
+	}
+
+	public boolean supportsTemporaryTables() {
+		return true;
+	}
+
+	public String getCreateTemporaryTableString() {
+		return "create temporary table if not exists";
+	}
+
+	public String getCastTypeName(int code) {
+		if ( code==Types.INTEGER ) {
+			return "signed";
+		}
+		else if ( code==Types.VARCHAR ) {
+			return "char";
+		}
+		else if ( code==Types.VARBINARY ) {
+			return "binary";
+		}
+		else {
+			return super.getCastTypeName( code );
+		}
+	}
+
+	public boolean supportsCurrentTimestampSelection() {
+		return true;
+	}
+
+	public boolean isCurrentTimestampSelectStringCallable() {
+		return false;
+	}
+
+	public String getCurrentTimestampSelectString() {
+		return "select now()";
+	}
+
+	public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
+		return col;
+	} 
+	
+	public ResultSet getResultSet(CallableStatement ps) throws SQLException {
+		boolean isResultSet = ps.execute(); 
+		while (!isResultSet && ps.getUpdateCount() != -1) { 
+			isResultSet = ps.getMoreResults(); 
+		} 
+		return ps.getResultSet();
+	}
+
+	public boolean supportsRowValueConstructorSyntax() {
+		return true;
+	}
+
+	public Boolean performTemporaryTableDDLInIsolation() {
+		return Boolean.FALSE;
+	}
+
+
+	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsEmptyInList() {
+		return false;
+	}
+
+	public boolean areStringComparisonsCaseInsensitive() {
+		return true;
+	}
+
+	public boolean supportsLobValueChangePropogation() {
+		// note: at least my local MySQL 5.1 install shows this not working...
+		return false;
+	}
+
+	public boolean supportsSubqueryOnMutatingTable() {
+		return false;
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQLInnoDBDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQLInnoDBDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQLInnoDBDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+//$Id: MySQLInnoDBDialect.java 7118 2005-06-12 21:55:12Z oneovthafew $
+package org.hibernate.dialect;
+
+/**
+ * @author Gavin King
+ */
+public class MySQLInnoDBDialect extends MySQLDialect {
+
+	public boolean supportsCascadeDelete() {
+		return true;
+	}
+	
+	public String getTableTypeString() {
+		return " type=InnoDB";
+	}
+
+	public boolean hasSelfReferentialForeignKeyBug() {
+		return true;
+	}
+	
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQLInnoDBDialect.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQLMyISAMDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQLMyISAMDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQLMyISAMDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+//$Id: MySQLMyISAMDialect.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.dialect;
+
+/**
+ * @author Gavin King
+ */
+public class MySQLMyISAMDialect extends MySQLDialect {
+
+	public String getTableTypeString() {
+		return " type=MyISAM";
+	}
+
+	public boolean dropConstraints() {
+		return false;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/MySQLMyISAMDialect.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Oracle9Dialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Oracle9Dialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Oracle9Dialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,343 @@
+//$Id: Oracle9Dialect.java 11259 2007-03-07 22:55:12Z steve.ebersole at jboss.com $
+package org.hibernate.dialect;
+
+import java.sql.CallableStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.NoArgSQLFunction;
+import org.hibernate.dialect.function.NvlFunction;
+import org.hibernate.dialect.function.SQLFunctionTemplate;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.dialect.function.VarArgsSQLFunction;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.exception.TemplatedViolatedConstraintNameExtracter;
+import org.hibernate.exception.ViolatedConstraintNameExtracter;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * An SQL dialect for Oracle 9 (uses ANSI-style syntax where possible).
+ * @author Gavin King, David Channon
+ */
+public class Oracle9Dialect extends Dialect {
+
+	public Oracle9Dialect() {
+		super();
+		registerColumnType( Types.BIT, "number(1,0)" );
+		registerColumnType( Types.BIGINT, "number(19,0)" );
+		registerColumnType( Types.SMALLINT, "number(5,0)" );
+		registerColumnType( Types.TINYINT, "number(3,0)" );
+		registerColumnType( Types.INTEGER, "number(10,0)" );
+		registerColumnType( Types.CHAR, "char(1 char)" );
+		registerColumnType( Types.VARCHAR, 4000, "varchar2($l char)" );
+		registerColumnType( Types.VARCHAR, "long" );
+		registerColumnType( Types.FLOAT, "float" );
+		registerColumnType( Types.DOUBLE, "double precision" );
+		registerColumnType( Types.DATE, "date" );
+		registerColumnType( Types.TIME, "date" );
+		registerColumnType( Types.TIMESTAMP, "timestamp" );
+		registerColumnType( Types.VARBINARY, 2000, "raw($l)" );
+		registerColumnType( Types.VARBINARY, "long raw" );
+		registerColumnType( Types.NUMERIC, "number($p,$s)" );
+		registerColumnType( Types.DECIMAL, "number($p,$s)" );
+		registerColumnType( Types.BLOB, "blob" );
+		registerColumnType( Types.CLOB, "clob" );
+
+		// Oracle driver reports to support getGeneratedKeys(), but they only
+		// support the version taking an array of the names of the columns to
+		// be returned (via its RETURNING clause).  No other driver seems to
+		// support this overloaded version.
+		getDefaultProperties().setProperty(Environment.USE_GET_GENERATED_KEYS, "false");
+		getDefaultProperties().setProperty(Environment.USE_STREAMS_FOR_BINARY, "true");
+		getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE);
+
+		registerFunction( "abs", new StandardSQLFunction("abs") );
+		registerFunction( "sign", new StandardSQLFunction("sign", Hibernate.INTEGER) );
+
+		registerFunction( "acos", new StandardSQLFunction("acos", Hibernate.DOUBLE) );
+		registerFunction( "asin", new StandardSQLFunction("asin", Hibernate.DOUBLE) );
+		registerFunction( "atan", new StandardSQLFunction("atan", Hibernate.DOUBLE) );
+		registerFunction( "cos", new StandardSQLFunction("cos", Hibernate.DOUBLE) );
+		registerFunction( "cosh", new StandardSQLFunction("cosh", Hibernate.DOUBLE) );
+		registerFunction( "exp", new StandardSQLFunction("exp", Hibernate.DOUBLE) );
+		registerFunction( "ln", new StandardSQLFunction("ln", Hibernate.DOUBLE) );
+		registerFunction( "sin", new StandardSQLFunction("sin", Hibernate.DOUBLE) );
+		registerFunction( "sinh", new StandardSQLFunction("sinh", Hibernate.DOUBLE) );
+		registerFunction( "stddev", new StandardSQLFunction("stddev", Hibernate.DOUBLE) );
+		registerFunction( "sqrt", new StandardSQLFunction("sqrt", Hibernate.DOUBLE) );
+		registerFunction( "tan", new StandardSQLFunction("tan", Hibernate.DOUBLE) );
+		registerFunction( "tanh", new StandardSQLFunction("tanh", Hibernate.DOUBLE) );
+		registerFunction( "variance", new StandardSQLFunction("variance", Hibernate.DOUBLE) );
+
+		registerFunction( "round", new StandardSQLFunction("round") );
+		registerFunction( "trunc", new StandardSQLFunction("trunc") );
+		registerFunction( "ceil", new StandardSQLFunction("ceil") );
+		registerFunction( "floor", new StandardSQLFunction("floor") );
+
+		registerFunction( "chr", new StandardSQLFunction("chr", Hibernate.CHARACTER) );
+		registerFunction( "initcap", new StandardSQLFunction("initcap") );
+		registerFunction( "lower", new StandardSQLFunction("lower") );
+		registerFunction( "ltrim", new StandardSQLFunction("ltrim") );
+		registerFunction( "rtrim", new StandardSQLFunction("rtrim") );
+		registerFunction( "soundex", new StandardSQLFunction("soundex") );
+		registerFunction( "upper", new StandardSQLFunction("upper") );
+		registerFunction( "ascii", new StandardSQLFunction("ascii", Hibernate.INTEGER) );
+		registerFunction( "length", new StandardSQLFunction("length", Hibernate.LONG) );
+
+		registerFunction( "to_char", new StandardSQLFunction("to_char", Hibernate.STRING) );
+		registerFunction( "to_date", new StandardSQLFunction("to_date", Hibernate.TIMESTAMP) );
+
+		registerFunction( "current_date", new NoArgSQLFunction("current_date", Hibernate.DATE, false) );
+		registerFunction( "current_time", new NoArgSQLFunction("current_timestamp", Hibernate.TIME, false) );
+		registerFunction( "current_timestamp", new NoArgSQLFunction("current_timestamp", Hibernate.TIMESTAMP, false) );
+		
+		registerFunction( "lastday", new StandardSQLFunction("lastday", Hibernate.DATE) );
+		registerFunction( "sysdate", new NoArgSQLFunction("sysdate", Hibernate.DATE, false) );
+		registerFunction( "systimestamp", new NoArgSQLFunction("systimestamp", Hibernate.TIMESTAMP, false) );
+		registerFunction( "uid", new NoArgSQLFunction("uid", Hibernate.INTEGER, false) );
+		registerFunction( "user", new NoArgSQLFunction("user", Hibernate.STRING, false) );
+
+		registerFunction( "rowid", new NoArgSQLFunction("rowid", Hibernate.LONG, false) );
+		registerFunction( "rownum", new NoArgSQLFunction("rownum", Hibernate.LONG, false) );
+
+		// Multi-param string dialect functions...
+		registerFunction( "concat", new VarArgsSQLFunction(Hibernate.STRING, "", "||", "") );
+		registerFunction( "instr", new StandardSQLFunction("instr", Hibernate.INTEGER) );
+		registerFunction( "instrb", new StandardSQLFunction("instrb", Hibernate.INTEGER) );
+		registerFunction( "lpad", new StandardSQLFunction("lpad", Hibernate.STRING) );
+		registerFunction( "replace", new StandardSQLFunction("replace", Hibernate.STRING) );
+		registerFunction( "rpad", new StandardSQLFunction("rpad", Hibernate.STRING) );
+		registerFunction( "substr", new StandardSQLFunction("substr", Hibernate.STRING) );
+		registerFunction( "substrb", new StandardSQLFunction("substrb", Hibernate.STRING) );
+		registerFunction( "translate", new StandardSQLFunction("translate", Hibernate.STRING) );
+
+		registerFunction( "substring", new StandardSQLFunction( "substr", Hibernate.STRING ) );
+		registerFunction( "locate", new SQLFunctionTemplate( Hibernate.INTEGER, "instr(?2,?1)" ) );
+		registerFunction( "bit_length", new SQLFunctionTemplate( Hibernate.INTEGER, "vsize(?1)*8" ) );
+		registerFunction( "coalesce", new NvlFunction() );
+
+		// Multi-param numeric dialect functions...
+		registerFunction( "atan2", new StandardSQLFunction("atan2", Hibernate.FLOAT) );
+		registerFunction( "log", new StandardSQLFunction("log", Hibernate.INTEGER) );
+		registerFunction( "mod", new StandardSQLFunction("mod", Hibernate.INTEGER) );
+		registerFunction( "nvl", new StandardSQLFunction("nvl") );
+		registerFunction( "nvl2", new StandardSQLFunction("nvl2") );
+		registerFunction( "power", new StandardSQLFunction("power", Hibernate.FLOAT) );
+
+		// Multi-param date dialect functions...
+		registerFunction( "add_months", new StandardSQLFunction("add_months", Hibernate.DATE) );
+		registerFunction( "months_between", new StandardSQLFunction("months_between", Hibernate.FLOAT) );
+		registerFunction( "next_day", new StandardSQLFunction("next_day", Hibernate.DATE) );
+
+		registerFunction( "str", new StandardSQLFunction("to_char", Hibernate.STRING) );
+	}
+
+	public String getAddColumnString() {
+		return "add";
+	}
+
+	public String getSequenceNextValString(String sequenceName) {
+		return "select " + getSelectSequenceNextValString( sequenceName ) + " from dual";
+	}
+
+	public String getSelectSequenceNextValString(String sequenceName) {
+		return sequenceName + ".nextval";
+	}
+
+	public String getCreateSequenceString(String sequenceName) {
+		return "create sequence " + sequenceName; //starts with 1, implicitly
+	}
+
+	public String getDropSequenceString(String sequenceName) {
+		return "drop sequence " + sequenceName;
+	}
+
+	public String getCascadeConstraintsString() {
+		return " cascade constraints";
+	}
+
+	public boolean dropConstraints() {
+		return false;
+	}
+
+	public String getForUpdateNowaitString() {
+		return " for update nowait";
+	}
+
+	public boolean supportsSequences() {
+		return true;
+	}
+
+	public boolean supportsPooledSequences() {
+		return true;
+	}
+
+	public boolean supportsLimit() {
+		return true;
+	}
+
+	public String getLimitString(String sql, boolean hasOffset) {
+		
+		sql = sql.trim();
+		boolean isForUpdate = false;
+		if ( sql.toLowerCase().endsWith(" for update") ) {
+			sql = sql.substring( 0, sql.length()-11 );
+			isForUpdate = true;
+		}
+		
+		StringBuffer pagingSelect = new StringBuffer( sql.length()+100 );
+		if (hasOffset) {
+			pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
+		}
+		else {
+			pagingSelect.append("select * from ( ");
+		}
+		pagingSelect.append(sql);
+		if (hasOffset) {
+			pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?");
+		}
+		else {
+			pagingSelect.append(" ) where rownum <= ?");
+		}
+
+		if ( isForUpdate ) {
+			pagingSelect.append( " for update" );
+		}
+		
+		return pagingSelect.toString();
+	}
+
+	public String getForUpdateString(String aliases) {
+		return getForUpdateString() + " of " + aliases;
+	}
+
+	public String getForUpdateNowaitString(String aliases) {
+		return getForUpdateString() + " of " + aliases + " nowait";
+	}
+
+	public boolean bindLimitParametersInReverseOrder() {
+		return true;
+	}
+
+	public boolean useMaxForLimit() {
+		return true;
+	}
+	
+	public boolean forUpdateOfColumns() {
+		return true;
+	}
+
+	public String getQuerySequencesString() {
+		return "select sequence_name from user_sequences";
+	}
+
+	public String getSelectGUIDString() {
+		return "select rawtohex(sys_guid()) from dual";
+	}
+	
+	public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
+        return EXTRACTER;
+	}
+
+	private static ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
+
+		/**
+		 * Extract the name of the violated constraint from the given SQLException.
+		 *
+		 * @param sqle The exception that was the result of the constraint violation.
+		 * @return The extracted constraint name.
+		 */
+		public String extractConstraintName(SQLException sqle) {
+			int errorCode = JDBCExceptionHelper.extractErrorCode(sqle);
+			if ( errorCode == 1 || errorCode == 2291 || errorCode == 2292 ) {
+				return extractUsingTemplate( "constraint (", ") violated", sqle.getMessage() );
+			}
+			else if ( errorCode == 1400 ) {
+				// simple nullability constraint
+				return null;
+			}
+			else {
+				return null;
+			}
+		}
+
+	};
+
+	// not final-static to avoid possible classcast exceptions if using different oracle drivers.
+	int oracletypes_cursor_value = 0; 
+	public int registerResultSetOutParameter(java.sql.CallableStatement statement,int col) throws SQLException {
+		if(oracletypes_cursor_value==0) {
+			try {
+				Class types = ReflectHelper.classForName("oracle.jdbc.driver.OracleTypes");
+				oracletypes_cursor_value = types.getField("CURSOR").getInt(types.newInstance());
+			} catch (Exception se) {
+				throw new HibernateException("Problem while trying to load or access OracleTypes.CURSOR value",se);
+			} 
+		}
+		//	register the type of the out param - an Oracle specific type
+		statement.registerOutParameter(col, oracletypes_cursor_value);
+		col++;
+		return col;
+	}
+	
+	public ResultSet getResultSet(CallableStatement ps) throws SQLException {
+		ps.execute();
+		return ( ResultSet ) ps.getObject( 1 );
+	}
+
+	public boolean supportsUnionAll() {
+		return true;
+	}
+	
+	public boolean supportsCommentOn() {
+		return true;
+	}
+
+	public boolean supportsTemporaryTables() {
+		return true;
+	}
+
+	public String generateTemporaryTableName(String baseTableName) {
+		String name = super.generateTemporaryTableName(baseTableName);
+		return name.length() > 30 ? name.substring( 1, 30 ) : name;
+	}
+
+	public String getCreateTemporaryTableString() {
+		return "create global temporary table";
+	}
+
+	public String getCreateTemporaryTablePostfix() {
+		return "on commit delete rows";
+	}
+
+	public boolean dropTemporaryTableAfterUse() {
+		return false;
+	}
+
+	public boolean supportsCurrentTimestampSelection() {
+		return true;
+	}
+
+	public String getCurrentTimestampSelectString() {
+		return "select systimestamp from dual";
+	}
+
+	public boolean isCurrentTimestampSelectStringCallable() {
+		return false;
+	}
+
+
+	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsEmptyInList() {
+		return false;
+	}
+
+	public boolean supportsExistsInSelect() {
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/OracleDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/OracleDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/OracleDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,85 @@
+//$Id: OracleDialect.java 8610 2005-11-18 18:30:27Z steveebersole $
+package org.hibernate.dialect;
+
+import java.sql.Types;
+
+import org.hibernate.sql.CaseFragment;
+import org.hibernate.sql.DecodeCaseFragment;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.sql.OracleJoinFragment;
+
+/**
+ * An SQL dialect for Oracle, compatible with Oracle 8.
+ * @author Gavin King
+ */
+public class OracleDialect extends Oracle9Dialect {
+
+	public OracleDialect() {
+		super();
+		// Oracle8 and previous define only a "DATE" type which
+		//      is used to represent all aspects of date/time
+		registerColumnType( Types.TIMESTAMP, "date" );
+		registerColumnType( Types.CHAR, "char(1)" );
+		registerColumnType( Types.VARCHAR, 4000, "varchar2($l)" );
+	}
+
+	public JoinFragment createOuterJoinFragment() {
+		return new OracleJoinFragment();
+	}
+	public CaseFragment createCaseFragment() {
+		return new DecodeCaseFragment();
+	}
+
+	public String getLimitString(String sql, boolean hasOffset) {
+
+		sql = sql.trim();
+		boolean isForUpdate = false;
+		if ( sql.toLowerCase().endsWith(" for update") ) {
+			sql = sql.substring( 0, sql.length()-11 );
+			isForUpdate = true;
+		}
+		
+		StringBuffer pagingSelect = new StringBuffer( sql.length()+100 );
+		if (hasOffset) {
+			pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
+		}
+		else {
+			pagingSelect.append("select * from ( ");
+		}
+		pagingSelect.append(sql);
+		if (hasOffset) {
+			pagingSelect.append(" ) row_ ) where rownum_ <= ? and rownum_ > ?");
+		}
+		else {
+			pagingSelect.append(" ) where rownum <= ?");
+		}
+
+		if ( isForUpdate ) {
+			pagingSelect.append( " for update" );
+		}
+		
+		return pagingSelect.toString();
+	}
+
+	public String getSelectClauseNullString(int sqlType) {
+		switch(sqlType) {
+			case Types.VARCHAR:
+			case Types.CHAR:
+				return "to_char(null)";
+			case Types.DATE:
+			case Types.TIMESTAMP:
+			case Types.TIME:
+				return "to_date(null)";
+			default:
+				return "to_number(null)";
+		}
+	}
+
+	public String getCurrentTimestampSelectString() {
+		return "select sysdate from dual";
+	}
+
+	public String getCurrentTimestampSQLFunctionName() {
+		return "sysdate";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/PointbaseDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/PointbaseDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/PointbaseDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+//$Id: PointbaseDialect.java 9328 2006-02-23 17:32:47Z steveebersole $
+//Created on 04 February 2002, 17:35
+package org.hibernate.dialect;
+
+import org.hibernate.dialect.lock.LockingStrategy;
+import org.hibernate.dialect.lock.UpdateLockingStrategy;
+import org.hibernate.dialect.lock.SelectLockingStrategy;
+import org.hibernate.persister.entity.Lockable;
+import org.hibernate.LockMode;
+
+import java.sql.Types;
+
+/**
+ * A <tt>Dialect</tt> for Pointbase.
+ * @author  Ed Mackenzie
+ */
+public class PointbaseDialect extends org.hibernate.dialect.Dialect {
+
+	/**
+	 * Creates new PointbaseDialect
+	 */
+	public PointbaseDialect() {
+		super();
+		registerColumnType( Types.BIT, "smallint" ); //no pointbase BIT
+		registerColumnType( Types.BIGINT, "bigint" );
+		registerColumnType( Types.SMALLINT, "smallint" );
+		registerColumnType( Types.TINYINT, "smallint" ); //no pointbase TINYINT
+		registerColumnType( Types.INTEGER, "integer" );
+		registerColumnType( Types.CHAR, "char(1)" );
+		registerColumnType( Types.VARCHAR, "varchar($l)" );
+		registerColumnType( Types.FLOAT, "float" );
+		registerColumnType( Types.DOUBLE, "double precision" );
+		registerColumnType( Types.DATE, "date" );
+		registerColumnType( Types.TIME, "time" );
+		registerColumnType( Types.TIMESTAMP, "timestamp" );
+		//the BLOB type requires a size arguement - this defaults to
+		//bytes - no arg defaults to 1 whole byte!
+		//other argument mods include K - kilobyte, M - megabyte, G - gigabyte.
+		//refer to the PBdevelopers guide for more info.
+		registerColumnType( Types.VARBINARY, "blob($l)" );
+		registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
+	}
+
+	public String getAddColumnString() {
+		return "add";
+	}
+
+	public boolean dropConstraints() {
+		return false;
+	}
+
+	public String getCascadeConstraintsString() {
+		return " cascade";
+	}
+
+	public String getForUpdateString() {
+		return "";
+	}
+
+	public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
+		// Pointbase has no known variation of a "SELECT ... FOR UPDATE" syntax...
+		if ( lockMode.greaterThan( LockMode.READ ) ) {
+			return new UpdateLockingStrategy( lockable, lockMode );
+		}
+		else {
+			return new SelectLockingStrategy( lockable, lockMode );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,312 @@
+//$Id: PostgreSQLDialect.java 11367 2007-03-29 13:26:40Z steve.ebersole at jboss.com $
+package org.hibernate.dialect;
+
+import java.sql.Types;
+import java.sql.SQLException;
+
+import org.hibernate.Hibernate;
+import org.hibernate.exception.ViolatedConstraintNameExtracter;
+import org.hibernate.exception.TemplatedViolatedConstraintNameExtracter;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.NoArgSQLFunction;
+import org.hibernate.dialect.function.PositionSubstringFunction;
+import org.hibernate.dialect.function.SQLFunctionTemplate;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.dialect.function.VarArgsSQLFunction;
+import org.hibernate.id.SequenceGenerator;
+
+/**
+ * An SQL dialect for Postgres
+ * @author Gavin King
+ */
+public class PostgreSQLDialect extends Dialect {
+
+	public PostgreSQLDialect() {
+		super();
+		registerColumnType( Types.BIT, "bool" );
+		registerColumnType( Types.BIGINT, "int8" );
+		registerColumnType( Types.SMALLINT, "int2" );
+		registerColumnType( Types.TINYINT, "int2" );
+		registerColumnType( Types.INTEGER, "int4" );
+		registerColumnType( Types.CHAR, "char(1)" );
+		registerColumnType( Types.VARCHAR, "varchar($l)" );
+		registerColumnType( Types.FLOAT, "float4" );
+		registerColumnType( Types.DOUBLE, "float8" );
+		registerColumnType( Types.DATE, "date" );
+		registerColumnType( Types.TIME, "time" );
+		registerColumnType( Types.TIMESTAMP, "timestamp" );
+		registerColumnType( Types.VARBINARY, "bytea" );
+		registerColumnType( Types.CLOB, "text" );
+		registerColumnType( Types.BLOB, "oid" );
+		registerColumnType( Types.NUMERIC, "numeric($p, $s)" );
+
+		registerFunction( "abs", new StandardSQLFunction("abs") );
+		registerFunction( "sign", new StandardSQLFunction("sign", Hibernate.INTEGER) );
+
+		registerFunction( "acos", new StandardSQLFunction("acos", Hibernate.DOUBLE) );
+		registerFunction( "asin", new StandardSQLFunction("asin", Hibernate.DOUBLE) );
+		registerFunction( "atan", new StandardSQLFunction("atan", Hibernate.DOUBLE) );
+		registerFunction( "cos", new StandardSQLFunction("cos", Hibernate.DOUBLE) );
+		registerFunction( "cot", new StandardSQLFunction("cot", Hibernate.DOUBLE) );
+		registerFunction( "exp", new StandardSQLFunction("exp", Hibernate.DOUBLE) );
+		registerFunction( "ln", new StandardSQLFunction("ln", Hibernate.DOUBLE) );
+		registerFunction( "log", new StandardSQLFunction("log", Hibernate.DOUBLE) );
+		registerFunction( "sin", new StandardSQLFunction("sin", Hibernate.DOUBLE) );
+		registerFunction( "sqrt", new StandardSQLFunction("sqrt", Hibernate.DOUBLE) );
+		registerFunction( "cbrt", new StandardSQLFunction("cbrt", Hibernate.DOUBLE) );
+		registerFunction( "tan", new StandardSQLFunction("tan", Hibernate.DOUBLE) );
+		registerFunction( "radians", new StandardSQLFunction("radians", Hibernate.DOUBLE) );
+		registerFunction( "degrees", new StandardSQLFunction("degrees", Hibernate.DOUBLE) );
+
+		registerFunction( "stddev", new StandardSQLFunction("stddev", Hibernate.DOUBLE) );
+		registerFunction( "variance", new StandardSQLFunction("variance", Hibernate.DOUBLE) );
+
+		registerFunction( "random", new NoArgSQLFunction("random", Hibernate.DOUBLE) );
+
+		registerFunction( "round", new StandardSQLFunction("round") );
+		registerFunction( "trunc", new StandardSQLFunction("trunc") );
+		registerFunction( "ceil", new StandardSQLFunction("ceil") );
+		registerFunction( "floor", new StandardSQLFunction("floor") );
+
+		registerFunction( "chr", new StandardSQLFunction("chr", Hibernate.CHARACTER) );
+		registerFunction( "lower", new StandardSQLFunction("lower") );
+		registerFunction( "upper", new StandardSQLFunction("upper") );
+		registerFunction( "substr", new StandardSQLFunction("substr", Hibernate.STRING) );
+		registerFunction( "initcap", new StandardSQLFunction("initcap") );
+		registerFunction( "to_ascii", new StandardSQLFunction("to_ascii") );
+		registerFunction( "quote_ident", new StandardSQLFunction("quote_ident", Hibernate.STRING) );
+		registerFunction( "quote_literal", new StandardSQLFunction("quote_literal", Hibernate.STRING) );
+		registerFunction( "md5", new StandardSQLFunction("md5") );
+		registerFunction( "ascii", new StandardSQLFunction("ascii", Hibernate.INTEGER) );
+		registerFunction( "length", new StandardSQLFunction("length", Hibernate.LONG) );
+		registerFunction( "char_length", new StandardSQLFunction("char_length", Hibernate.LONG) );
+		registerFunction( "bit_length", new StandardSQLFunction("bit_length", Hibernate.LONG) );
+		registerFunction( "octet_length", new StandardSQLFunction("octet_length", Hibernate.LONG) );
+
+		registerFunction( "current_date", new NoArgSQLFunction("current_date", Hibernate.DATE, false) );
+		registerFunction( "current_time", new NoArgSQLFunction("current_time", Hibernate.TIME, false) );
+		registerFunction( "current_timestamp", new NoArgSQLFunction("current_timestamp", Hibernate.TIMESTAMP, false) );
+		registerFunction( "localtime", new NoArgSQLFunction("localtime", Hibernate.TIME, false) );
+		registerFunction( "localtimestamp", new NoArgSQLFunction("localtimestamp", Hibernate.TIMESTAMP, false) );
+		registerFunction( "now", new NoArgSQLFunction("now", Hibernate.TIMESTAMP) );
+		registerFunction( "timeofday", new NoArgSQLFunction("timeofday", Hibernate.STRING) );
+		registerFunction( "age", new StandardSQLFunction("age") );
+
+		registerFunction( "current_user", new NoArgSQLFunction("current_user", Hibernate.STRING, false) );
+		registerFunction( "session_user", new NoArgSQLFunction("session_user", Hibernate.STRING, false) );
+		registerFunction( "user", new NoArgSQLFunction("user", Hibernate.STRING, false) );
+		registerFunction( "current_database", new NoArgSQLFunction("current_database", Hibernate.STRING, true) );
+		registerFunction( "current_schema", new NoArgSQLFunction("current_schema", Hibernate.STRING, true) );
+		
+		registerFunction( "to_char", new StandardSQLFunction("to_char", Hibernate.STRING) );
+		registerFunction( "to_date", new StandardSQLFunction("to_date", Hibernate.DATE) );
+		registerFunction( "to_timestamp", new StandardSQLFunction("to_timestamp", Hibernate.TIMESTAMP) );
+		registerFunction( "to_number", new StandardSQLFunction("to_number", Hibernate.BIG_DECIMAL) );
+
+		registerFunction( "concat", new VarArgsSQLFunction( Hibernate.STRING, "(","||",")" ) );
+
+		registerFunction( "locate", new PositionSubstringFunction() );
+
+		registerFunction( "str", new SQLFunctionTemplate(Hibernate.STRING, "cast(?1 as varchar)") );
+
+		getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE);
+	}
+
+	public String getAddColumnString() {
+		return "add column";
+	}
+
+	public String getSequenceNextValString(String sequenceName) {
+		return "select " + getSelectSequenceNextValString( sequenceName );
+	}
+
+	public String getSelectSequenceNextValString(String sequenceName) {
+		return "nextval ('" + sequenceName + "')";
+	}
+
+	public String getCreateSequenceString(String sequenceName) {
+		return "create sequence " + sequenceName; //starts with 1, implicitly
+	}
+
+	public String getDropSequenceString(String sequenceName) {
+		return "drop sequence " + sequenceName;
+	}
+
+	public String getCascadeConstraintsString() {
+		return "";//" cascade";
+	}
+	public boolean dropConstraints() {
+		return true;
+	}
+
+	public boolean supportsSequences() {
+		return true;
+	}
+
+	public String getQuerySequencesString() {
+		return "select relname from pg_class where relkind='S'";
+	}
+
+	public boolean supportsLimit() {
+		return true;
+	}
+
+	public String getLimitString(String sql, boolean hasOffset) {
+		return new StringBuffer( sql.length()+20 )
+			.append(sql)
+			.append(hasOffset ? " limit ? offset ?" : " limit ?")
+			.toString();
+	}
+
+	public boolean bindLimitParametersInReverseOrder() {
+		return true;
+	}
+
+	public boolean supportsIdentityColumns() {
+		return true;
+	}
+
+	public String getForUpdateString(String aliases) {
+		return getForUpdateString() + " of " + aliases;
+	}
+
+	public String getIdentitySelectString(String table, String column, int type) {
+		return new StringBuffer().append("select currval('")
+			.append(table)
+			.append('_')
+			.append(column)
+			.append("_seq')")
+			.toString();
+	}
+
+	public String getIdentityColumnString(int type) {
+		return type==Types.BIGINT ?
+			"bigserial not null" :
+			"serial not null";
+	}
+
+	public boolean hasDataTypeInIdentityColumn() {
+		return false;
+	}
+
+	public String getNoColumnsInsertString() {
+		return "default values";
+	}
+
+	public Class getNativeIdentifierGeneratorClass() {
+		return SequenceGenerator.class;
+	}
+
+	public boolean supportsOuterJoinForUpdate() {
+		return false;
+	}
+	
+	public boolean useInputStreamToInsertBlob() {
+		return false;
+	}
+
+	public boolean supportsUnionAll() {
+		return true;
+	}
+
+	/**
+	 * Workaround for postgres bug #1453
+	 */
+	public String getSelectClauseNullString(int sqlType) {
+		String typeName = getTypeName(sqlType, 1, 1, 0);
+		//trim off the length/precision/scale
+		int loc = typeName.indexOf('(');
+		if (loc>-1) {
+			typeName = typeName.substring(0, loc);
+		}
+		return "null::" + typeName;
+	}
+
+	public boolean supportsCommentOn() {
+		return true;
+	}
+
+	public boolean supportsTemporaryTables() {
+		return true;
+	}
+
+	public String getCreateTemporaryTableString() {
+		return "create local temporary table";
+	}
+
+	public String getCreateTemporaryTablePostfix() {
+		return "on commit drop";
+	}
+
+	/*public boolean dropTemporaryTableAfterUse() {
+		//we have to, because postgres sets current tx
+		//to rollback only after a failed create table
+		return true;
+	}*/
+
+	public boolean supportsCurrentTimestampSelection() {
+		return true;
+	}
+
+	public boolean isCurrentTimestampSelectStringCallable() {
+		return false;
+	}
+
+	public String getCurrentTimestampSelectString() {
+		return "select now()";
+	}
+
+	public String toBooleanValueString(boolean bool) {
+		return bool ? "true" : "false";
+	}
+
+	public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
+		return EXTRACTER;
+	}
+
+	/**
+	 * Constraint-name extractor for Postgres contraint violation exceptions.
+	 * Orginally contributed by Denny Bartelt.
+	 */
+	private static ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
+		public String extractConstraintName(SQLException sqle) {
+			try {
+				int sqlState = Integer.valueOf( JDBCExceptionHelper.extractSqlState(sqle)).intValue();
+				switch (sqlState) {
+					// CHECK VIOLATION
+					case 23514: return extractUsingTemplate("violates check constraint \"","\"", sqle.getMessage());
+					// UNIQUE VIOLATION
+					case 23505: return extractUsingTemplate("violates unique constraint \"","\"", sqle.getMessage());
+					// FOREIGN KEY VIOLATION
+					case 23503: return extractUsingTemplate("violates foreign key constraint \"","\"", sqle.getMessage());
+					// NOT NULL VIOLATION
+					case 23502: return extractUsingTemplate("null value in column \"","\" violates not-null constraint", sqle.getMessage());
+					// TODO: RESTRICT VIOLATION
+					case 23001: return null;
+					// ALL OTHER
+					default: return null;
+				}
+			} catch (NumberFormatException nfe) {
+				return null;
+			}
+		}
+	};
+
+
+	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+// seems to not really...
+//	public boolean supportsRowValueConstructorSyntax() {
+//		return true;
+//	}
+
+	public boolean supportsEmptyInList() {
+		return false;
+	}
+
+	public boolean supportsExpectedLobUsagePattern() {
+		// seems to have spotty LOB suppport
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/ProgressDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/ProgressDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/ProgressDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+//$Id: ProgressDialect.java 4609 2004-09-27 03:17:46Z oneovthafew $
+// contributed by Phillip Baird
+package org.hibernate.dialect;
+
+import java.sql.Types;
+
+/**
+ * An SQL dialect compatible with Progress 9.1C<br>
+ *<br>
+ * Connection Parameters required:
+ *<ul>
+ * <li>hibernate.dialect org.hibernate.sql.ProgressDialect
+ * <li>hibernate.driver com.progress.sql.jdbc.JdbcProgressDriver
+ * <li>hibernate.url jdbc:JdbcProgress:T:host:port:dbname;WorkArounds=536870912
+ * <li>hibernate.username username
+ * <li>hibernate.password password
+ *</ul>
+ * The WorkArounds parameter in the URL is required to avoid an error
+ * in the Progress 9.1C JDBC driver related to PreparedStatements.
+ * @author Phillip Baird
+ *
+ */
+public class ProgressDialect extends Dialect {
+	public ProgressDialect() {
+		super();
+		registerColumnType( Types.BIT, "bit" );
+		registerColumnType( Types.BIGINT, "numeric" );
+		registerColumnType( Types.SMALLINT, "smallint" );
+		registerColumnType( Types.TINYINT, "tinyint" );
+		registerColumnType( Types.INTEGER, "integer" );
+		registerColumnType( Types.CHAR, "character(1)" );
+		registerColumnType( Types.VARCHAR, "varchar($l)" );
+		registerColumnType( Types.FLOAT, "real" );
+		registerColumnType( Types.DOUBLE, "double precision" );
+		registerColumnType( Types.DATE, "date" );
+		registerColumnType( Types.TIME, "time" );
+		registerColumnType( Types.TIMESTAMP, "timestamp" );
+		registerColumnType( Types.VARBINARY, "varbinary($l)" );
+		registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
+	}
+
+	public boolean hasAlterTable(){
+		return false;
+	}
+
+	public String getAddColumnString() {
+		return "add column";
+	}
+
+	public boolean qualifyIndexName() {
+		return false;
+	}
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/RDMSOS2200Dialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/RDMSOS2200Dialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/RDMSOS2200Dialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,322 @@
+/*
+ * Created on Aug 24, 2005
+ * This is the Hibernate dialect for the Unisys 2200 Relational Database (RDMS).
+ * This dialect was developed for use with Hibernate 3.0.5. Other versions may
+ * require modifications to the dialect.
+ *
+ * Version History:
+ * Also change the version displayed below in the constructor
+ * 1.1
+ * 1.0  2005-10-24  CDH - First dated version for use with CP 11
+ */
+package org.hibernate.dialect;
+
+import org.hibernate.dialect.function.NoArgSQLFunction;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.dialect.function.SQLFunctionTemplate;
+import org.hibernate.dialect.lock.LockingStrategy;
+import org.hibernate.dialect.lock.UpdateLockingStrategy;
+import org.hibernate.dialect.lock.SelectLockingStrategy;
+
+import java.sql.Types;
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.persister.entity.Lockable;
+import org.hibernate.sql.CaseFragment;
+import org.hibernate.sql.DecodeCaseFragment;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Ploski and Hanson
+ */
+public class RDMSOS2200Dialect extends Dialect {
+	private static Log log = LogFactory.getLog(RDMSOS2200Dialect.class);
+
+	public RDMSOS2200Dialect() {
+		super();
+        // Display the dialect version.
+		log.info("RDMSOS2200Dialect version: 1.0");
+
+        /**
+         * This section registers RDMS Biult-in Functions (BIFs) with Hibernate.
+         * The first parameter is the 'register' function name with Hibernate.
+         * The second parameter is the defined RDMS SQL Function and it's
+         * characteristics. If StandardSQLFunction(...) is used, the RDMS BIF
+         * name and the return type (if any) is specified.  If
+         * SQLFunctionTemplate(...) is used, the return type and a template
+         * string is provided, plus an optional hasParenthesesIfNoArgs flag.
+         */
+		registerFunction( "abs", new StandardSQLFunction("abs") );
+		registerFunction( "sign", new StandardSQLFunction("sign", Hibernate.INTEGER) );
+
+		registerFunction("ascii", new StandardSQLFunction("ascii", Hibernate.INTEGER) );
+		registerFunction("char_length", new StandardSQLFunction("char_length", Hibernate.INTEGER) );
+		registerFunction("character_length", new StandardSQLFunction("character_length", Hibernate.INTEGER) );
+		registerFunction("length", new StandardSQLFunction("length", Hibernate.INTEGER) );
+
+		// The RDMS concat() function only supports 2 parameters
+		registerFunction( "concat", new SQLFunctionTemplate(Hibernate.STRING, "concat(?1, ?2)") );
+		registerFunction( "instr", new StandardSQLFunction("instr", Hibernate.STRING) );
+		registerFunction( "lpad", new StandardSQLFunction("lpad", Hibernate.STRING) );
+		registerFunction( "replace", new StandardSQLFunction("replace", Hibernate.STRING) );
+		registerFunction( "rpad", new StandardSQLFunction("rpad", Hibernate.STRING) );
+		registerFunction( "substr", new StandardSQLFunction("substr", Hibernate.STRING) );
+
+		registerFunction("lcase", new StandardSQLFunction("lcase") );
+		registerFunction("lower", new StandardSQLFunction("lower") );
+		registerFunction("ltrim", new StandardSQLFunction("ltrim") );
+		registerFunction("reverse", new StandardSQLFunction("reverse") );
+		registerFunction("rtrim", new StandardSQLFunction("rtrim") );
+
+		// RDMS does not directly support the trim() function, we use rtrim() and ltrim()
+		registerFunction("trim", new SQLFunctionTemplate(Hibernate.INTEGER, "ltrim(rtrim(?1))" ) );
+		registerFunction("soundex", new StandardSQLFunction("soundex") );
+		registerFunction("space", new StandardSQLFunction("space", Hibernate.STRING) );
+		registerFunction("ucase", new StandardSQLFunction("ucase") );
+		registerFunction("upper", new StandardSQLFunction("upper") );
+
+		registerFunction("acos", new StandardSQLFunction("acos", Hibernate.DOUBLE) );
+		registerFunction("asin", new StandardSQLFunction("asin", Hibernate.DOUBLE) );
+		registerFunction("atan", new StandardSQLFunction("atan", Hibernate.DOUBLE) );
+		registerFunction("cos", new StandardSQLFunction("cos", Hibernate.DOUBLE) );
+		registerFunction("cosh", new StandardSQLFunction("cosh", Hibernate.DOUBLE) );
+		registerFunction("cot", new StandardSQLFunction("cot", Hibernate.DOUBLE) );
+		registerFunction("exp", new StandardSQLFunction("exp", Hibernate.DOUBLE) );
+		registerFunction("ln", new StandardSQLFunction("ln", Hibernate.DOUBLE) );
+		registerFunction("log", new StandardSQLFunction("log", Hibernate.DOUBLE) );
+		registerFunction("log10", new StandardSQLFunction("log10", Hibernate.DOUBLE) );
+		registerFunction("pi", new NoArgSQLFunction("pi", Hibernate.DOUBLE) );
+		registerFunction("rand", new NoArgSQLFunction("rand", Hibernate.DOUBLE) );
+		registerFunction("sin", new StandardSQLFunction("sin", Hibernate.DOUBLE) );
+		registerFunction("sinh", new StandardSQLFunction("sinh", Hibernate.DOUBLE) );
+		registerFunction("sqrt", new StandardSQLFunction("sqrt", Hibernate.DOUBLE) );
+		registerFunction("tan", new StandardSQLFunction("tan", Hibernate.DOUBLE) );
+		registerFunction("tanh", new StandardSQLFunction("tanh", Hibernate.DOUBLE) );
+
+		registerFunction( "round", new StandardSQLFunction("round") );
+		registerFunction( "trunc", new StandardSQLFunction("trunc") );
+		registerFunction( "ceil", new StandardSQLFunction("ceil") );
+		registerFunction( "floor", new StandardSQLFunction("floor") );
+
+		registerFunction( "chr", new StandardSQLFunction("chr", Hibernate.CHARACTER) );
+		registerFunction( "initcap", new StandardSQLFunction("initcap") );
+
+		registerFunction( "user", new NoArgSQLFunction("user", Hibernate.STRING, false) );
+
+		registerFunction( "current_date", new NoArgSQLFunction("current_date", Hibernate.DATE, false) );
+		registerFunction( "current_time", new NoArgSQLFunction("current_timestamp", Hibernate.TIME, false) );
+		registerFunction( "current_timestamp", new NoArgSQLFunction("current_timestamp", Hibernate.TIMESTAMP, false) );
+		registerFunction("curdate", new NoArgSQLFunction("curdate",Hibernate.DATE) );
+		registerFunction("curtime", new NoArgSQLFunction("curtime",Hibernate.TIME) );
+		registerFunction("days", new StandardSQLFunction("days",Hibernate.INTEGER) );
+		registerFunction("dayofmonth", new StandardSQLFunction("dayofmonth",Hibernate.INTEGER) );
+		registerFunction("dayname", new StandardSQLFunction("dayname",Hibernate.STRING) );
+		registerFunction("dayofweek", new StandardSQLFunction("dayofweek",Hibernate.INTEGER) );
+		registerFunction("dayofyear", new StandardSQLFunction("dayofyear",Hibernate.INTEGER) );
+		registerFunction("hour", new StandardSQLFunction("hour",Hibernate.INTEGER) );
+		registerFunction("last_day", new StandardSQLFunction("last_day",Hibernate.DATE) );
+		registerFunction("microsecond", new StandardSQLFunction("microsecond",Hibernate.INTEGER) );
+		registerFunction("minute", new StandardSQLFunction("minute",Hibernate.INTEGER) );
+		registerFunction("month", new StandardSQLFunction("month",Hibernate.INTEGER) );
+		registerFunction("monthname", new StandardSQLFunction("monthname",Hibernate.STRING) );
+		registerFunction("now", new NoArgSQLFunction("now",Hibernate.TIMESTAMP) );
+		registerFunction("quarter", new StandardSQLFunction("quarter",Hibernate.INTEGER) );
+		registerFunction("second", new StandardSQLFunction("second",Hibernate.INTEGER) );
+		registerFunction("time", new StandardSQLFunction("time",Hibernate.TIME) );
+		registerFunction("timestamp", new StandardSQLFunction("timestamp",Hibernate.TIMESTAMP) );
+		registerFunction("week", new StandardSQLFunction("week",Hibernate.INTEGER) );
+		registerFunction("year", new StandardSQLFunction("year",Hibernate.INTEGER) );
+
+		registerFunction("atan2", new StandardSQLFunction("atan2",Hibernate.DOUBLE) );
+		registerFunction( "mod", new StandardSQLFunction("mod",Hibernate.INTEGER) );
+		registerFunction( "nvl", new StandardSQLFunction("nvl") );
+		registerFunction( "power", new StandardSQLFunction("power", Hibernate.DOUBLE) );
+
+		/**
+		 * For a list of column types to register, see section A-1
+		 * in 7862 7395, the Unisys JDBC manual.
+		 *
+		 * Here are column sizes as documented in Table A-1 of
+		 * 7831 0760, "Enterprise Relational Database Server
+		 * for ClearPath OS2200 Administration Guide"
+		 * Numeric - 21
+		 * Decimal - 22 (21 digits plus one for sign)
+		 * Float   - 60 bits
+		 * Char    - 28000
+		 * NChar   - 14000
+		 * BLOB+   - 4294967296 (4 Gb)
+		 * + RDMS JDBC driver does not support BLOBs
+		 *
+		 * DATE, TIME and TIMESTAMP literal formats are
+		 * are all described in section 2.3.4 DATE Literal Format
+		 * in 7830 8160.
+		 * The DATE literal format is: YYYY-MM-DD
+		 * The TIME literal format is: HH:MM:SS[.[FFFFFF]]
+		 * The TIMESTAMP literal format is: YYYY-MM-DD HH:MM:SS[.[FFFFFF]]
+		 *
+		 * Note that $l (dollar-L) will use the length value if provided.
+		 * Also new for Hibernate3 is the $p percision and $s (scale) parameters
+		 */
+		registerColumnType(Types.BIT, "SMALLINT");
+		registerColumnType(Types.TINYINT, "SMALLINT");
+		registerColumnType(Types.BIGINT, "NUMERIC(21,0)");
+		registerColumnType(Types.SMALLINT, "SMALLINT");
+		registerColumnType(Types.CHAR, "CHARACTER(1)");
+		registerColumnType(Types.DOUBLE, "DOUBLE PRECISION");
+		registerColumnType(Types.FLOAT, "FLOAT");
+		registerColumnType(Types.REAL, "REAL");
+		registerColumnType(Types.INTEGER, "INTEGER");
+		registerColumnType(Types.NUMERIC, "NUMERIC(21,$l)");
+		registerColumnType(Types.DECIMAL, "NUMERIC(21,$l)");
+		registerColumnType(Types.DATE, "DATE");
+		registerColumnType(Types.TIME, "TIME");
+		registerColumnType(Types.TIMESTAMP, "TIMESTAMP");
+		registerColumnType(Types.VARCHAR, "CHARACTER($l)");
+        registerColumnType(Types.BLOB, "BLOB($l)" );
+        /*
+         * The following types are not supported in RDMS/JDBC and therefore commented out.
+         * However, in some cases, mapping them to CHARACTER columns works
+         * for many applications, but does not work for all cases.
+         */
+        // registerColumnType(Types.VARBINARY, "CHARACTER($l)");
+        // registerColumnType(Types.BLOB, "CHARACTER($l)" );  // For use prior to CP 11.0
+        // registerColumnType(Types.CLOB, "CHARACTER($l)" );
+	}
+
+
+	// Dialect method overrides ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    /**
+     * RDMS does not support qualifing index names with the schema name.
+     */
+	public boolean qualifyIndexName() {
+		return false;
+	}
+
+	/**
+	 * The RDMS DB supports the 'FOR UPDATE OF' clause. However, the RDMS-JDBC
+     * driver does not support this feature, so a false is return.
+     * The base dialect also returns a false, but we will leave this over-ride
+     * in to make sure it stays false.
+	 */
+	public boolean forUpdateOfColumns() {
+		return false;
+	}
+
+	/**
+	 * Since the RDMS-JDBC driver does not support for updates, this string is
+     * set to an empty string. Whenever, the driver does support this feature,
+     * the returned string should be " FOR UPDATE OF". Note that RDMS does not
+     * support the string 'FOR UPDATE' string.
+	 */
+	public String getForUpdateString() {
+		return ""; // Original Dialect.java returns " for update";
+	}
+
+    /**
+     * RDMS does not support adding Unique constraints via create and alter table.
+     */
+	public boolean supportsUniqueConstraintInCreateAlterTable() {
+	    return true;
+	}
+
+	// Verify the state of this new method in Hibernate 3.0 Dialect.java
+    /**
+     * RDMS does not support Cascade Deletes.
+     * Need to review this in the future when support is provided.
+     */
+	public boolean supportsCascadeDelete() {
+		return false; // Origial Dialect.java returns true;
+	}
+
+	/**
+     * Currently, RDMS-JDBC does not support ForUpdate.
+     * Need to review this in the future when support is provided.
+	 */
+    public boolean supportsOuterJoinForUpdate() {
+		return false;
+	}
+
+	public String getAddColumnString() {
+		return "add";
+	}
+
+	public String getNullColumnString() {
+		// The keyword used to specify a nullable column.
+		return " null";
+	}
+
+    // *** Sequence methods - start. The RDMS dialect needs these
+
+    // methods to make it possible to use the Native Id generator
+
+	public boolean supportsSequences() {
+		return true;
+	}
+
+	public String getSequenceNextValString(String sequenceName) {
+	    // The where clause was added to eliminate this statement from Brute Force Searches.
+        return  "select permuted_id('NEXT',31) from rdms.rdms_dummy where key_col = 1 ";
+	}
+
+	public String getCreateSequenceString(String sequenceName) {
+        // We must return a valid RDMS/RSA command from this method to
+        // prevent RDMS/RSA from issuing *ERROR 400
+        return "";
+	}
+
+	public String getDropSequenceString(String sequenceName) {
+        // We must return a valid RDMS/RSA command from this method to
+        // prevent RDMS/RSA from issuing *ERROR 400
+        return "";
+	}
+
+	// *** Sequence methods - end
+
+    public String getCascadeConstraintsString() {
+        // Used with DROP TABLE to delete all records in the table.
+        return " including contents";
+    }
+
+	public CaseFragment createCaseFragment() {
+		return new DecodeCaseFragment();
+	}
+
+	public boolean supportsLimit() {
+		return true;
+	}
+
+	public boolean supportsLimitOffset() {
+		return false;
+	}
+
+    public String getLimitString(String sql, int offset, int limit) {
+        if (offset>0) throw new UnsupportedOperationException("RDMS does not support paged queries");
+		return new StringBuffer(sql.length() + 40)
+			.append(sql)
+			.append(" fetch first ")
+			.append(limit)
+			.append(" rows only ")
+			.toString();
+	}
+
+	public boolean supportsVariableLimit() {
+		return false;
+	}
+
+	public boolean supportsUnionAll() {
+		// RDMS supports the UNION ALL clause.
+          return true;
+	}
+
+	public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
+		// RDMS has no known variation of a "SELECT ... FOR UPDATE" syntax...
+		if ( lockMode.greaterThan( LockMode.READ ) ) {
+			return new UpdateLockingStrategy( lockable, lockMode );
+		}
+		else {
+			return new SelectLockingStrategy( lockable, lockMode );
+		}
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/RDMSOS2200Dialect.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/ResultColumnReferenceStrategy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/ResultColumnReferenceStrategy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/ResultColumnReferenceStrategy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+package org.hibernate.dialect;
+
+import java.io.Serializable;
+import java.io.ObjectStreamException;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * Defines how we need to reference columns in the group-by, having, and order-by
+ * clauses.
+ *
+ * @author Steve Ebersole
+ */
+public class ResultColumnReferenceStrategy implements Serializable {
+
+	private static final Map INSTANCES = new HashMap();
+
+	/**
+	 * This strategy says to reference the result columns by the qualified column name
+	 * found in the result source.  This strategy is not strictly allowed by ANSI SQL
+	 * but is Hibernate's legacy behavior and is also the fastest of the strategies; thus
+	 * it should be used if supported by the underlying database.
+	 */
+	public static final ResultColumnReferenceStrategy SOURCE = new ResultColumnReferenceStrategy( "source");
+
+	/**
+	 * For databases which do not support {@link #SOURCE}, ANSI SQL defines two allowable
+	 * approaches.  One is to reference the result column by the alias it is given in the
+	 * result source (if it is given an alias).  This strategy says to use this approach.
+	 * <p/>
+	 * The other QNSI SQL compliant approach is {@link #ORDINAL}.
+	 */
+	public static final ResultColumnReferenceStrategy ALIAS = new ResultColumnReferenceStrategy( "alias" );
+
+	/**
+	 * For databases which do not support {@link #SOURCE}, ANSI SQL defines two allowable
+	 * approaches.  One is to reference the result column by the ordinal position at which
+	 * it appears in the result source.  This strategy says to use this approach.
+	 * <p/>
+	 * The other QNSI SQL compliant approach is {@link #ALIAS}.
+	 */
+	public static final ResultColumnReferenceStrategy ORDINAL = new ResultColumnReferenceStrategy( "ordinal" );
+
+	static {
+		ResultColumnReferenceStrategy.INSTANCES.put( ResultColumnReferenceStrategy.SOURCE.name, ResultColumnReferenceStrategy.SOURCE );
+		ResultColumnReferenceStrategy.INSTANCES.put( ResultColumnReferenceStrategy.ALIAS.name, ResultColumnReferenceStrategy.ALIAS );
+		ResultColumnReferenceStrategy.INSTANCES.put( ResultColumnReferenceStrategy.ORDINAL.name, ResultColumnReferenceStrategy.ORDINAL );
+	}
+
+	private final String name;
+
+	public ResultColumnReferenceStrategy(String name) {
+		this.name = name;
+	}
+
+	public String toString() {
+		return name;
+	}
+
+	private Object readResolve() throws ObjectStreamException {
+		return parse( name );
+	}
+
+	public static ResultColumnReferenceStrategy parse(String name) {
+		return ( ResultColumnReferenceStrategy ) ResultColumnReferenceStrategy.INSTANCES.get( name );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SAPDBDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SAPDBDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SAPDBDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,195 @@
+//$Id: SAPDBDialect.java 8749 2005-12-04 17:32:04Z oneovthafew $
+// contributed by Brad Clow
+package org.hibernate.dialect;
+
+import java.sql.Types;
+
+import org.hibernate.Hibernate;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.NoArgSQLFunction;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.dialect.function.VarArgsSQLFunction;
+import org.hibernate.sql.CaseFragment;
+import org.hibernate.sql.DecodeCaseFragment;
+import org.hibernate.sql.OracleJoinFragment;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.util.StringHelper;
+
+/**
+ * An SQL dialect compatible with SAP DB.
+ * @author Brad Clow
+ */
+public class SAPDBDialect extends Dialect {
+
+	public SAPDBDialect() {
+		super();
+		registerColumnType( Types.BIT, "boolean" );
+		registerColumnType( Types.BIGINT, "fixed(19,0)" );
+		registerColumnType( Types.SMALLINT, "smallint" );
+		registerColumnType( Types.TINYINT, "fixed(3,0)" );
+		registerColumnType( Types.INTEGER, "int" );
+		registerColumnType( Types.CHAR, "char(1)" );
+		registerColumnType( Types.VARCHAR, "varchar($l)" );
+		registerColumnType( Types.FLOAT, "float" );
+		registerColumnType( Types.DOUBLE, "double precision" );
+		registerColumnType( Types.DATE, "date" );
+		registerColumnType( Types.TIME, "time" );
+		registerColumnType( Types.TIMESTAMP, "timestamp" );
+		registerColumnType( Types.VARBINARY, "long byte" );
+		registerColumnType( Types.NUMERIC, "fixed($p,$s)" );
+		registerColumnType( Types.CLOB, "long varchar" );
+		registerColumnType( Types.BLOB, "long byte" );
+		
+		registerFunction( "abs", new StandardSQLFunction("abs") );
+		registerFunction( "sign", new StandardSQLFunction("sign", Hibernate.INTEGER) );
+
+		registerFunction( "exp", new StandardSQLFunction("exp", Hibernate.DOUBLE) );
+		registerFunction( "ln", new StandardSQLFunction("ln", Hibernate.DOUBLE) );
+		registerFunction( "log", new StandardSQLFunction("ln", Hibernate.DOUBLE) );
+		registerFunction( "pi", new NoArgSQLFunction("pi", Hibernate.DOUBLE) );
+		registerFunction( "power", new StandardSQLFunction("power") );
+		registerFunction( "acos", new StandardSQLFunction("acos", Hibernate.DOUBLE) );
+		registerFunction( "asin", new StandardSQLFunction("asin", Hibernate.DOUBLE) );
+		registerFunction( "atan", new StandardSQLFunction("atan", Hibernate.DOUBLE) );
+		registerFunction( "cos", new StandardSQLFunction("cos", Hibernate.DOUBLE) );
+		registerFunction( "cosh", new StandardSQLFunction("cosh", Hibernate.DOUBLE) );
+		registerFunction( "cot", new StandardSQLFunction("cos", Hibernate.DOUBLE) );
+		registerFunction( "sin", new StandardSQLFunction("sin", Hibernate.DOUBLE) );
+		registerFunction( "sinh", new StandardSQLFunction("sinh", Hibernate.DOUBLE) );
+		registerFunction( "tan", new StandardSQLFunction("tan", Hibernate.DOUBLE) );
+		registerFunction( "tanh", new StandardSQLFunction("tanh", Hibernate.DOUBLE) );
+		registerFunction( "radians", new StandardSQLFunction("radians", Hibernate.DOUBLE) );
+		registerFunction( "degrees", new StandardSQLFunction("degrees", Hibernate.DOUBLE) );
+		registerFunction( "atan2", new StandardSQLFunction("atan2", Hibernate.DOUBLE) );
+
+		registerFunction( "round", new StandardSQLFunction("round") );
+		registerFunction( "trunc", new StandardSQLFunction("trunc") );
+		registerFunction( "ceil", new StandardSQLFunction("ceil") );
+		registerFunction( "floor", new StandardSQLFunction("floor") );
+		registerFunction( "greatest", new StandardSQLFunction("greatest") );
+		registerFunction( "least", new StandardSQLFunction("least") );
+
+		registerFunction("time", new StandardSQLFunction("time", Hibernate.TIME) );
+		registerFunction("timestamp", new StandardSQLFunction("timestamp", Hibernate.TIMESTAMP) );
+		registerFunction("date", new StandardSQLFunction("date", Hibernate.DATE) );
+		registerFunction("microsecond", new StandardSQLFunction("microsecond", Hibernate.INTEGER) );
+
+		registerFunction("dayname", new StandardSQLFunction("dayname", Hibernate.STRING) );
+		registerFunction("monthname", new StandardSQLFunction("monthname", Hibernate.STRING) );
+		registerFunction("dayofmonth", new StandardSQLFunction("dayofmonth", Hibernate.INTEGER) );
+		registerFunction("dayofweek", new StandardSQLFunction("dayofweek", Hibernate.INTEGER) );
+		registerFunction("dayofyear", new StandardSQLFunction("dayofyear", Hibernate.INTEGER) );
+		registerFunction("weekofyear", new StandardSQLFunction("weekofyear", Hibernate.INTEGER) );
+
+		registerFunction( "replace", new StandardSQLFunction("replace", Hibernate.STRING) );
+		registerFunction( "translate", new StandardSQLFunction("translate", Hibernate.STRING) );
+		registerFunction( "lpad", new StandardSQLFunction("lpad", Hibernate.STRING) );
+		registerFunction( "rpad", new StandardSQLFunction("rpad", Hibernate.STRING) );
+		registerFunction( "substr", new StandardSQLFunction("substr", Hibernate.STRING) );
+		registerFunction( "initcap", new StandardSQLFunction("initcap", Hibernate.STRING) );
+		registerFunction( "lower", new StandardSQLFunction("lower", Hibernate.STRING) );
+		registerFunction( "ltrim", new StandardSQLFunction("ltrim", Hibernate.STRING) );
+		registerFunction( "rtrim", new StandardSQLFunction("rtrim", Hibernate.STRING) );
+		registerFunction( "lfill", new StandardSQLFunction("ltrim", Hibernate.STRING) );
+		registerFunction( "rfill", new StandardSQLFunction("rtrim", Hibernate.STRING) );
+		registerFunction( "soundex", new StandardSQLFunction("soundex", Hibernate.STRING) );
+		registerFunction( "upper", new StandardSQLFunction("upper", Hibernate.STRING) );
+		registerFunction( "ascii", new StandardSQLFunction("ascii", Hibernate.STRING) );
+		registerFunction( "index", new StandardSQLFunction("index", Hibernate.INTEGER) );
+
+		registerFunction( "value", new StandardSQLFunction( "value" ) );
+		
+		registerFunction( "concat", new VarArgsSQLFunction( Hibernate.STRING, "(", "||", ")" ) );
+		registerFunction( "substring", new StandardSQLFunction( "substr", Hibernate.STRING ) );
+		registerFunction( "locate", new StandardSQLFunction("index", Hibernate.INTEGER) );
+		registerFunction( "coalesce", new StandardSQLFunction( "value" ) );
+
+		getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE);
+
+	}
+
+	public boolean dropConstraints() {
+		return false;
+	}
+
+	public String getAddColumnString() {
+		return "add";
+	}
+
+	public String getAddForeignKeyConstraintString(
+			String constraintName, 
+			String[] foreignKey, 
+			String referencedTable, 
+			String[] primaryKey, boolean referencesPrimaryKey
+	) {
+		StringBuffer res = new StringBuffer(30)
+			.append(" foreign key ")
+			.append(constraintName)
+			.append(" (")
+			.append( StringHelper.join(", ", foreignKey) )
+			.append(") references ")
+			.append(referencedTable);
+		
+		if(!referencesPrimaryKey) {
+			res.append(" (")
+			   .append( StringHelper.join(", ", primaryKey) )
+			   .append(')');
+		}
+			
+		return res.toString();
+	}
+
+	public String getAddPrimaryKeyConstraintString(String constraintName) {
+		return " primary key ";
+	}
+
+	public String getNullColumnString() {
+		return " null";
+	}
+
+	public String getSequenceNextValString(String sequenceName) {
+		return "select " + getSelectSequenceNextValString( sequenceName ) + " from dual";
+	}
+
+	public String getSelectSequenceNextValString(String sequenceName) {
+		return sequenceName + ".nextval";
+	}
+
+	public String getCreateSequenceString(String sequenceName) {
+		return "create sequence " + sequenceName;
+	}
+
+	public String getDropSequenceString(String sequenceName) {
+		return "drop sequence " + sequenceName;
+	}
+
+	public String getQuerySequencesString() {
+		return "select sequence_name from domain.sequences";
+	}
+
+	public JoinFragment createOuterJoinFragment() {
+		return new OracleJoinFragment();
+	}
+
+
+	public boolean supportsSequences() {
+		return true;
+	}
+
+	public CaseFragment createCaseFragment() {
+		return new DecodeCaseFragment();
+	}
+
+	public boolean supportsTemporaryTables() {
+		return true;
+	}
+
+	public String getCreateTemporaryTablePostfix() {
+		return "ignore rollback";
+	}
+
+	public String generateTemporaryTableName(String baseTableName) {
+		return "temp." + super.generateTemporaryTableName(baseTableName);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SQLServerDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SQLServerDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SQLServerDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,140 @@
+//$Id: SQLServerDialect.java 11303 2007-03-19 22:06:14Z steve.ebersole at jboss.com $
+package org.hibernate.dialect;
+
+import java.sql.Types;
+import java.util.Map;
+import java.util.Iterator;
+
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.util.StringHelper;
+import org.hibernate.dialect.function.SQLFunctionTemplate;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.dialect.function.AnsiTrimEmulationFunction;
+
+/**
+ * A dialect for Microsoft SQL Server 2000 and 2005
+ *
+ * @author Gavin King
+ */
+public class SQLServerDialect extends SybaseDialect {
+
+	public SQLServerDialect() {
+		registerColumnType( Types.VARBINARY, "image" );
+		registerColumnType( Types.VARBINARY, 8000, "varbinary($l)" );
+
+		registerFunction( "second", new SQLFunctionTemplate( Hibernate.INTEGER, "datepart(second, ?1)" ) );
+		registerFunction( "minute", new SQLFunctionTemplate( Hibernate.INTEGER, "datepart(minute, ?1)" ) );
+		registerFunction( "hour", new SQLFunctionTemplate( Hibernate.INTEGER, "datepart(hour, ?1)" ) );
+		registerFunction( "locate", new StandardSQLFunction( "charindex", Hibernate.INTEGER ) );
+
+		registerFunction( "extract", new SQLFunctionTemplate( Hibernate.INTEGER, "datepart(?1, ?3)" ) );
+		registerFunction( "mod", new SQLFunctionTemplate( Hibernate.INTEGER, "?1 % ?2" ) );
+		registerFunction( "bit_length", new SQLFunctionTemplate( Hibernate.INTEGER, "datalength(?1) * 8" ) );
+
+		registerFunction( "trim", new AnsiTrimEmulationFunction() );
+
+		registerKeyword( "top" );
+	}
+
+	public String getNoColumnsInsertString() {
+		return "default values";
+	}
+
+	static int getAfterSelectInsertPoint(String sql) {
+		int selectIndex = sql.toLowerCase().indexOf( "select" );
+		final int selectDistinctIndex = sql.toLowerCase().indexOf( "select distinct" );
+		return selectIndex + ( selectDistinctIndex == selectIndex ? 15 : 6 );
+	}
+
+	public String getLimitString(String querySelect, int offset, int limit) {
+		if ( offset > 0 ) {
+			throw new UnsupportedOperationException( "sql server has no offset" );
+		}
+		return new StringBuffer( querySelect.length() + 8 )
+				.append( querySelect )
+				.insert( getAfterSelectInsertPoint( querySelect ), " top " + limit )
+				.toString();
+	}
+
+	/**
+	 * Use <tt>insert table(...) values(...) select SCOPE_IDENTITY()</tt>
+	 */
+	public String appendIdentitySelectToInsert(String insertSQL) {
+		return insertSQL + " select scope_identity()";
+	}
+
+	public boolean supportsLimit() {
+		return true;
+	}
+
+	public boolean useMaxForLimit() {
+		return true;
+	}
+
+	public boolean supportsLimitOffset() {
+		return false;
+	}
+
+	public boolean supportsVariableLimit() {
+		return false;
+	}
+
+	public char closeQuote() {
+		return ']';
+	}
+
+	public char openQuote() {
+		return '[';
+	}
+
+	public String appendLockHint(LockMode mode, String tableName) {
+		if ( mode.greaterThan( LockMode.READ ) ) {
+			// does this need holdlock also? : return tableName + " with (updlock, rowlock, holdlock)";
+			return tableName + " with (updlock, rowlock)";
+		}
+		else {
+			return tableName;
+		}
+	}
+
+	public String getSelectGUIDString() {
+		return "select newid()";
+	}
+
+	// The current_timestamp is more accurate, but only known to be supported
+	// in SQL Server 7.0 and later (i.e., Sybase not known to support it at all)
+	public String getCurrentTimestampSelectString() {
+		return "select current_timestamp";
+	}
+
+	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean areStringComparisonsCaseInsensitive() {
+		return true;
+	}
+
+	public boolean supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() {
+		return false;
+	}
+
+	public boolean supportsCircularCascadeDeleteConstraints() {
+		// SQL Server (at least up through 2005) does not support defining
+		// cascade delete constraints which can circel back to the mutating
+		// table
+		return false;
+	}
+
+	public boolean supportsLobValueChangePropogation() {
+		// note: at least my local SQL Server 2005 Express shows this not working...
+		return false;
+	}
+
+	public boolean doesReadCommittedCauseWritersToBlockReaders() {
+		return false; // here assume SQLServer2005 using snapshot isolation, which does not have this problem
+	}
+
+	public boolean doesRepeatableReadCauseReadersToBlockWriters() {
+		return false; // here assume SQLServer2005 using snapshot isolation, which does not have this problem
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Sybase11Dialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Sybase11Dialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/Sybase11Dialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+//$Id: Sybase11Dialect.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.dialect;
+
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.sql.Sybase11JoinFragment;
+
+/**
+ * A SQL dialect suitable for use with Sybase 11.9.2 (specifically: avoids ANSI JOIN syntax)
+ * @author Colm O' Flaherty
+ */
+public class Sybase11Dialect extends SybaseDialect  {
+	public Sybase11Dialect() {
+		super();
+	}
+
+	public JoinFragment createOuterJoinFragment() {
+		return new Sybase11JoinFragment();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SybaseAnywhereDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SybaseAnywhereDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SybaseAnywhereDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+package org.hibernate.dialect;
+
+/**
+ * SQL Dialect for Sybase Anywhere
+ * extending Sybase (Enterprise) Dialect
+ * (Tested on ASA 8.x)
+ * @author ?
+ */
+public class SybaseAnywhereDialect extends SybaseDialect {
+
+	/**
+	 * Sybase Anywhere syntax would require a "DEFAULT" for each column specified,
+	 * but I suppose Hibernate use this syntax only with tables with just 1 column
+	 */
+	public String getNoColumnsInsertString() {
+		return "values (default)";
+	}
+
+
+	/**
+	 * ASA does not require to drop constraint before dropping tables, and DROP statement
+	 * syntax used by Hibernate to drop constraint is not compatible with ASA, so disable it
+	 */
+	public boolean dropConstraints() {
+		return false;
+	}
+
+	public boolean supportsInsertSelectIdentity() {
+		return false;
+	}
+	
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SybaseDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SybaseDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/SybaseDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,238 @@
+//$Id: SybaseDialect.java 11303 2007-03-19 22:06:14Z steve.ebersole at jboss.com $
+package org.hibernate.dialect;
+
+import java.sql.CallableStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Map;
+import java.util.Iterator;
+
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.CharIndexFunction;
+import org.hibernate.dialect.function.NoArgSQLFunction;
+import org.hibernate.dialect.function.SQLFunctionTemplate;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.dialect.function.VarArgsSQLFunction;
+
+/**
+ * An SQL dialect compatible with Sybase and MS SQL Server.
+ * @author Gavin King
+ */
+
+public class SybaseDialect extends Dialect {
+	public SybaseDialect() {
+		super();
+		registerColumnType( Types.BIT, "tinyint" ); //Sybase BIT type does not support null values
+		registerColumnType( Types.BIGINT, "numeric(19,0)" );
+		registerColumnType( Types.SMALLINT, "smallint" );
+		registerColumnType( Types.TINYINT, "tinyint" );
+		registerColumnType( Types.INTEGER, "int" );
+		registerColumnType( Types.CHAR, "char(1)" );
+		registerColumnType( Types.VARCHAR, "varchar($l)" );
+		registerColumnType( Types.FLOAT, "float" );
+		registerColumnType( Types.DOUBLE, "double precision" );
+		registerColumnType( Types.DATE, "datetime" );
+		registerColumnType( Types.TIME, "datetime" );
+		registerColumnType( Types.TIMESTAMP, "datetime" );
+		registerColumnType( Types.VARBINARY, "varbinary($l)" );
+		registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
+		registerColumnType( Types.BLOB, "image" );
+		registerColumnType( Types.CLOB, "text" );
+
+		registerFunction( "ascii", new StandardSQLFunction("ascii", Hibernate.INTEGER) );
+		registerFunction( "char", new StandardSQLFunction("char", Hibernate.CHARACTER) );
+		registerFunction( "len", new StandardSQLFunction("len", Hibernate.LONG) );
+		registerFunction( "lower", new StandardSQLFunction("lower") );
+		registerFunction( "upper", new StandardSQLFunction("upper") );
+		registerFunction( "str", new StandardSQLFunction("str", Hibernate.STRING) );
+		registerFunction( "ltrim", new StandardSQLFunction("ltrim") );
+		registerFunction( "rtrim", new StandardSQLFunction("rtrim") );
+		registerFunction( "reverse", new StandardSQLFunction("reverse") );
+		registerFunction( "space", new StandardSQLFunction("space", Hibernate.STRING) );
+
+		registerFunction( "user", new NoArgSQLFunction("user", Hibernate.STRING) );
+
+		registerFunction( "current_timestamp", new NoArgSQLFunction("getdate", Hibernate.TIMESTAMP) );
+		registerFunction( "current_time", new NoArgSQLFunction("getdate", Hibernate.TIME) );
+		registerFunction( "current_date", new NoArgSQLFunction("getdate", Hibernate.DATE) );
+		
+		registerFunction( "getdate", new NoArgSQLFunction("getdate", Hibernate.TIMESTAMP) );
+		registerFunction( "getutcdate", new NoArgSQLFunction("getutcdate", Hibernate.TIMESTAMP) );
+		registerFunction( "day", new StandardSQLFunction("day", Hibernate.INTEGER) );
+		registerFunction( "month", new StandardSQLFunction("month", Hibernate.INTEGER) );
+		registerFunction( "year", new StandardSQLFunction("year", Hibernate.INTEGER) );
+		registerFunction( "datename", new StandardSQLFunction("datename", Hibernate.STRING) );
+
+		registerFunction( "abs", new StandardSQLFunction("abs") );
+		registerFunction( "sign", new StandardSQLFunction("sign", Hibernate.INTEGER) );
+
+		registerFunction( "acos", new StandardSQLFunction("acos", Hibernate.DOUBLE) );
+		registerFunction( "asin", new StandardSQLFunction("asin", Hibernate.DOUBLE) );
+		registerFunction( "atan", new StandardSQLFunction("atan", Hibernate.DOUBLE) );
+		registerFunction( "cos", new StandardSQLFunction("cos", Hibernate.DOUBLE) );
+		registerFunction( "cot", new StandardSQLFunction("cot", Hibernate.DOUBLE) );
+		registerFunction( "exp", new StandardSQLFunction("exp", Hibernate.DOUBLE) );
+		registerFunction( "log", new StandardSQLFunction( "log", Hibernate.DOUBLE) );
+		registerFunction( "log10", new StandardSQLFunction("log10", Hibernate.DOUBLE) );
+		registerFunction( "sin", new StandardSQLFunction("sin", Hibernate.DOUBLE) );
+		registerFunction( "sqrt", new StandardSQLFunction("sqrt", Hibernate.DOUBLE) );
+		registerFunction( "tan", new StandardSQLFunction("tan", Hibernate.DOUBLE) );
+		registerFunction( "pi", new NoArgSQLFunction("pi", Hibernate.DOUBLE) );
+		registerFunction( "square", new StandardSQLFunction("square") );
+		registerFunction( "rand", new StandardSQLFunction("rand", Hibernate.FLOAT) );
+
+		registerFunction("radians", new StandardSQLFunction("radians", Hibernate.DOUBLE) );
+		registerFunction("degrees", new StandardSQLFunction("degrees", Hibernate.DOUBLE) );
+
+		registerFunction( "round", new StandardSQLFunction("round") );
+		registerFunction( "ceiling", new StandardSQLFunction("ceiling") );
+		registerFunction( "floor", new StandardSQLFunction("floor") );
+
+		registerFunction( "isnull", new StandardSQLFunction("isnull") );
+
+		registerFunction( "concat", new VarArgsSQLFunction( Hibernate.STRING, "(","+",")" ) );
+		
+		registerFunction( "length", new StandardSQLFunction( "len", Hibernate.INTEGER ) );
+		registerFunction( "trim", new SQLFunctionTemplate( Hibernate.STRING, "ltrim(rtrim(?1))") );
+		registerFunction( "locate", new CharIndexFunction() );
+
+		getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, NO_BATCH);
+	}
+
+	public String getAddColumnString() {
+		return "add";
+	}
+	public String getNullColumnString() {
+		return " null";
+	}
+	public boolean qualifyIndexName() {
+		return false;
+	}
+
+	public String getForUpdateString() {
+		return "";
+	}
+
+	public boolean supportsIdentityColumns() {
+		return true;
+	}
+	public String getIdentitySelectString() {
+		return "select @@identity";
+	}
+	public String getIdentityColumnString() {
+		return "identity not null"; //starts with 1, implicitly
+	}
+
+	public boolean supportsInsertSelectIdentity() {
+		return true;
+	}
+
+	public String appendIdentitySelectToInsert(String insertSQL) {
+		return insertSQL + "\nselect @@identity";
+	}
+
+	public String appendLockHint(LockMode mode, String tableName) {
+		if ( mode.greaterThan( LockMode.READ ) ) {
+			return tableName + " holdlock";
+		}
+		else {
+			return tableName;
+		}
+	}
+
+	public String applyLocksToSql(String sql, Map aliasedLockModes, Map keyColumnNames) {
+		Iterator itr = aliasedLockModes.entrySet().iterator();
+		StringBuffer buffer = new StringBuffer( sql );
+		int correction = 0;
+		while ( itr.hasNext() ) {
+			final Map.Entry entry = ( Map.Entry ) itr.next();
+			final LockMode lockMode = ( LockMode ) entry.getValue();
+			if ( lockMode.greaterThan( LockMode.READ ) ) {
+				final String alias = ( String ) entry.getKey();
+				int start = -1, end = -1;
+				if ( sql.endsWith( " " + alias ) ) {
+					start = ( sql.length() - alias.length() ) + correction;
+					end = start + alias.length();
+				}
+				else {
+					int position = sql.indexOf( " " + alias + " " );
+					if ( position <= -1 ) {
+						position = sql.indexOf( " " + alias + "," );
+					}
+					if ( position > -1 ) {
+						start = position + correction + 1;
+						end = start + alias.length();
+					}
+				}
+
+				if ( start > -1 ) {
+					final String lockHint = appendLockHint( lockMode, alias );
+					buffer.replace( start, end, lockHint );
+					correction += ( lockHint.length() - alias.length() );
+				}
+			}
+		}
+		return buffer.toString();
+	}
+	
+	public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
+		return col; // sql server just returns automatically
+	}
+
+	public ResultSet getResultSet(CallableStatement ps) throws SQLException {
+		boolean isResultSet = ps.execute();
+//		 This assumes you will want to ignore any update counts 
+		while ( !isResultSet && ps.getUpdateCount() != -1 ) {
+			isResultSet = ps.getMoreResults();
+		}
+//		 You may still have other ResultSets or update counts left to process here
+//		 but you can't do it now or the ResultSet you just got will be closed
+		return ps.getResultSet();
+	}
+
+	public boolean supportsCurrentTimestampSelection() {
+		return true;
+	}
+
+	public boolean isCurrentTimestampSelectStringCallable() {
+		return false;
+	}
+
+	public String getCurrentTimestampSelectString() {
+		return "select getdate()";
+	}
+
+	public boolean supportsTemporaryTables() {
+		return true;
+	}
+
+	public String generateTemporaryTableName(String baseTableName) {
+		return "#" + baseTableName;
+	}
+
+	public boolean dropTemporaryTableAfterUse() {
+		return true;  // sql-server, at least needed this dropped after use; strange!
+	}
+
+
+	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsEmptyInList() {
+		return false;
+	}
+
+	public boolean supportsExistsInSelect() {
+		return false;
+	}
+
+	public boolean doesReadCommittedCauseWritersToBlockReaders() {
+		return true;
+	}
+
+	public boolean doesRepeatableReadCauseReadersToBlockWriters() {
+		return true;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/TeradataDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/TeradataDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/TeradataDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,237 @@
+package org.hibernate.dialect;
+
+import java.sql.Types;
+
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.SQLFunctionTemplate;
+import org.hibernate.dialect.function.VarArgsSQLFunction;
+
+/**
+ * A dialect for the Teradata database created by MCR as part of the
+ * dialect certification process.
+ *
+ * @author Jay Nance
+ */
+public class TeradataDialect extends Dialect {
+
+	/**
+	 * Constructor
+	 */
+	public TeradataDialect() {
+		super();
+		//registerColumnType data types
+		registerColumnType( Types.NUMERIC, "NUMERIC($p,$s)" );
+		registerColumnType( Types.DOUBLE, "DOUBLE PRECISION" );
+		registerColumnType( Types.BIGINT, "NUMERIC(18,0)" );
+		registerColumnType( Types.BIT, "BYTEINT" );
+		registerColumnType( Types.TINYINT, "BYTEINT" );
+		registerColumnType( Types.VARBINARY, "VARBYTE($l)" );
+		registerColumnType( Types.BINARY, "BYTEINT" );
+		registerColumnType( Types.LONGVARCHAR, "LONG VARCHAR" );
+		registerColumnType( Types.CHAR, "CHAR(1)" );
+		registerColumnType( Types.DECIMAL, "DECIMAL" );
+		registerColumnType( Types.INTEGER, "INTEGER" );
+		registerColumnType( Types.SMALLINT, "SMALLINT" );
+		registerColumnType( Types.FLOAT, "FLOAT" );
+		registerColumnType( Types.VARCHAR, "VARCHAR($l)" );
+		registerColumnType( Types.DATE, "DATE" );
+		registerColumnType( Types.TIME, "TIME" );
+		registerColumnType( Types.TIMESTAMP, "TIMESTAMP" );
+		registerColumnType( Types.BOOLEAN, "BYTEINT" );  // hibernate seems to ignore this type...
+		registerColumnType( Types.BLOB, "BLOB" );
+		registerColumnType( Types.CLOB, "CLOB" );
+
+		registerFunction( "year", new SQLFunctionTemplate( Hibernate.INTEGER, "extract(year from ?1)" ) );
+		registerFunction( "length", new SQLFunctionTemplate( Hibernate.INTEGER, "character_length(?1)" ) );
+		registerFunction( "concat", new VarArgsSQLFunction( Hibernate.STRING, "(", "||", ")" ) );
+		registerFunction( "substring", new SQLFunctionTemplate( Hibernate.STRING, "substring(?1 from ?2 for ?3)" ) );
+		registerFunction( "locate", new SQLFunctionTemplate( Hibernate.STRING, "position(?1 in ?2)" ) );
+		registerFunction( "mod", new SQLFunctionTemplate( Hibernate.STRING, "?1 mod ?2" ) );
+		registerFunction( "str", new SQLFunctionTemplate( Hibernate.STRING, "cast(?1 as varchar(255))" ) );
+
+		// bit_length feels a bit broken to me. We have to cast to char in order to
+		// pass when a numeric value is supplied. But of course the answers given will
+		// be wildly different for these two datatypes. 1234.5678 will be 9 bytes as
+		// a char string but will be 8 or 16 bytes as a true numeric.
+		// Jay Nance 2006-09-22
+		registerFunction(
+				"bit_length", new SQLFunctionTemplate( Hibernate.INTEGER, "octet_length(cast(?1 as char))*4" )
+		);
+
+		// The preference here would be
+		//   SQLFunctionTemplate( Hibernate.TIMESTAMP, "current_timestamp(?1)", false)
+		// but this appears not to work.
+		// Jay Nance 2006-09-22
+		registerFunction( "current_timestamp", new SQLFunctionTemplate( Hibernate.TIMESTAMP, "current_timestamp" ) );
+		registerFunction( "current_time", new SQLFunctionTemplate( Hibernate.TIMESTAMP, "current_time" ) );
+		registerFunction( "current_date", new SQLFunctionTemplate( Hibernate.TIMESTAMP, "current_date" ) );
+		// IBID for current_time and current_date
+
+		registerKeyword( "password" );
+		registerKeyword( "type" );
+		registerKeyword( "title" );
+		registerKeyword( "year" );
+		registerKeyword( "month" );
+		registerKeyword( "summary" );
+		registerKeyword( "alias" );
+		registerKeyword( "value" );
+		registerKeyword( "first" );
+		registerKeyword( "role" );
+		registerKeyword( "account" );
+		registerKeyword( "class" );
+
+		// Tell hibernate to use getBytes instead of getBinaryStream
+		getDefaultProperties().setProperty( Environment.USE_STREAMS_FOR_BINARY, "false" );
+		// No batch statements
+		getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, NO_BATCH );
+	}
+
+	/**
+	 * Does this dialect support the <tt>FOR UPDATE</tt> syntax?
+	 *
+	 * @return empty string ... Teradata does not support <tt>FOR UPDATE<tt> syntax
+	 */
+	public String getForUpdateString() {
+		return "";
+	}
+
+	public boolean supportsIdentityColumns() {
+		return false;
+	}
+
+	public boolean supportsSequences() {
+		return false;
+	}
+
+	public String getAddColumnString() {
+		return "Add Column";
+	}
+
+	public boolean supportsTemporaryTables() {
+		return true;
+	}
+
+	public String getCreateTemporaryTableString() {
+		return "create global temporary table";
+	}
+
+	public String getCreateTemporaryTablePostfix() {
+		return " on commit preserve rows";
+	}
+
+	public Boolean performTemporaryTableDDLInIsolation() {
+		return Boolean.TRUE;
+	}
+
+	public boolean dropTemporaryTableAfterUse() {
+		return false;
+	}
+
+	/**
+	 * Get the name of the database type associated with the given
+	 * <tt>java.sql.Types</tt> typecode.
+	 *
+	 * @param code <tt>java.sql.Types</tt> typecode
+	 * @param length the length or precision of the column
+	 * @param precision the precision of the column
+	 * @param scale the scale of the column
+	 *
+	 * @return the database type name
+	 *
+	 * @throws HibernateException
+	 */
+	public String getTypeName(int code, int length, int precision, int scale) throws HibernateException {
+		/*
+		 * We might want a special case for 19,2. This is very common for money types
+		 * and here it is converted to 18,1
+		 */
+		float f = precision > 0 ? ( float ) scale / ( float ) precision : 0;
+		int p = ( precision > 18 ? 18 : precision );
+		int s = ( precision > 18 ? ( int ) ( 18.0 * f ) : ( scale > 18 ? 18 : scale ) );
+
+		return super.getTypeName( code, length, p, s );
+	}
+
+	public boolean supportsCascadeDelete() {
+		return false;
+	}
+
+	public boolean supportsCircularCascadeDeleteConstraints() {
+		return false;
+	}
+
+	public boolean areStringComparisonsCaseInsensitive() {
+		return true;
+	}
+
+	public boolean supportsEmptyInList() {
+		return false;
+	}
+
+	public String getSelectClauseNullString(int sqlType) {
+		String v = "null";
+
+		switch ( sqlType ) {
+			case Types.BIT:
+			case Types.TINYINT:
+			case Types.SMALLINT:
+			case Types.INTEGER:
+			case Types.BIGINT:
+			case Types.FLOAT:
+			case Types.REAL:
+			case Types.DOUBLE:
+			case Types.NUMERIC:
+			case Types.DECIMAL:
+				v = "cast(null as decimal)";
+				break;
+			case Types.CHAR:
+			case Types.VARCHAR:
+			case Types.LONGVARCHAR:
+				v = "cast(null as varchar(255))";
+				break;
+			case Types.DATE:
+			case Types.TIME:
+			case Types.TIMESTAMP:
+				v = "cast(null as timestamp)";
+				break;
+			case Types.BINARY:
+			case Types.VARBINARY:
+			case Types.LONGVARBINARY:
+			case Types.NULL:
+			case Types.OTHER:
+			case Types.JAVA_OBJECT:
+			case Types.DISTINCT:
+			case Types.STRUCT:
+			case Types.ARRAY:
+			case Types.BLOB:
+			case Types.CLOB:
+			case Types.REF:
+			case Types.DATALINK:
+			case Types.BOOLEAN:
+				break;
+		}
+		return v;
+	}
+
+	public String getCreateMultisetTableString() {
+		return "create multiset table ";
+	}
+
+	public boolean supportsLobValueChangePropogation() {
+		return false;
+	}
+
+	public boolean doesReadCommittedCauseWritersToBlockReaders() {
+		return true;
+	}
+
+	public boolean doesRepeatableReadCauseReadersToBlockWriters() {
+		return true;
+	}
+
+	public boolean supportsBindAsCallableArgument() {
+		return false;
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/TimesTenDialect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/TimesTenDialect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/TimesTenDialect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,205 @@
+package org.hibernate.dialect;
+
+import java.sql.Types;
+
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.persister.entity.Lockable;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.NoArgSQLFunction;
+import org.hibernate.dialect.function.StandardSQLFunction;
+import org.hibernate.dialect.lock.LockingStrategy;
+import org.hibernate.dialect.lock.UpdateLockingStrategy;
+import org.hibernate.dialect.lock.SelectLockingStrategy;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.sql.OracleJoinFragment;
+
+/**
+ * A SQL dialect for TimesTen 5.1.
+ * 
+ * Known limitations:
+ * joined-subclass support because of no CASE support in TimesTen
+ * No support for subqueries that includes aggregation
+ *  - size() in HQL not supported
+ *  - user queries that does subqueries with aggregation
+ * No CLOB/BLOB support 
+ * No cascade delete support.
+ * No Calendar support
+ * No support for updating primary keys.
+ * 
+ * @author Sherry Listgarten and Max Andersen
+ */
+public class TimesTenDialect extends Dialect {
+	
+	public TimesTenDialect() {
+		super();
+		registerColumnType( Types.BIT, "TINYINT" );
+		registerColumnType( Types.BIGINT, "BIGINT" );
+		registerColumnType( Types.SMALLINT, "SMALLINT" );
+		registerColumnType( Types.TINYINT, "TINYINT" );
+		registerColumnType( Types.INTEGER, "INTEGER" );
+		registerColumnType( Types.CHAR, "CHAR(1)" );
+		registerColumnType( Types.VARCHAR, "VARCHAR($l)" );
+		registerColumnType( Types.FLOAT, "FLOAT" );
+		registerColumnType( Types.DOUBLE, "DOUBLE" );
+		registerColumnType( Types.DATE, "DATE" );
+		registerColumnType( Types.TIME, "TIME" );
+		registerColumnType( Types.TIMESTAMP, "TIMESTAMP" );
+		registerColumnType( Types.VARBINARY, "VARBINARY($l)" );
+		registerColumnType( Types.NUMERIC, "DECIMAL($p, $s)" );
+		// TimesTen has no BLOB/CLOB support, but these types may be suitable 
+		// for some applications. The length is limited to 4 million bytes.
+        registerColumnType( Types.BLOB, "VARBINARY(4000000)" ); 
+        registerColumnType( Types.CLOB, "VARCHAR(4000000)" );
+	
+		getDefaultProperties().setProperty(Environment.USE_STREAMS_FOR_BINARY, "true");
+		getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE);
+		registerFunction( "lower", new StandardSQLFunction("lower") );
+		registerFunction( "upper", new StandardSQLFunction("upper") );
+		registerFunction( "rtrim", new StandardSQLFunction("rtrim") );
+		registerFunction( "concat", new StandardSQLFunction("concat", Hibernate.STRING) );
+		registerFunction( "mod", new StandardSQLFunction("mod") );
+		registerFunction( "to_char", new StandardSQLFunction("to_char",Hibernate.STRING) );
+		registerFunction( "to_date", new StandardSQLFunction("to_date",Hibernate.TIMESTAMP) );
+		registerFunction( "sysdate", new NoArgSQLFunction("sysdate", Hibernate.TIMESTAMP, false) );
+		registerFunction( "getdate", new NoArgSQLFunction("getdate", Hibernate.TIMESTAMP, false) );
+		registerFunction( "nvl", new StandardSQLFunction("nvl") );
+
+	}
+	
+	public boolean dropConstraints() {
+            return true;
+	}
+	
+	public boolean qualifyIndexName() {
+            return false;
+	}
+
+	public boolean supportsUnique() {
+		return false;
+	}
+    
+	public boolean supportsUniqueConstraintInCreateAlterTable() {
+		return false;
+	}
+	
+    public String getAddColumnString() {
+            return "add";
+	}
+
+	public boolean supportsSequences() {
+		return true;
+	}
+
+	public String getSelectSequenceNextValString(String sequenceName) {
+		return sequenceName + ".nextval";
+	}
+
+	public String getSequenceNextValString(String sequenceName) {
+		return "select first 1 " + sequenceName + ".nextval from sys.tables";
+	}
+
+	public String getCreateSequenceString(String sequenceName) {
+		return "create sequence " + sequenceName;
+	}
+
+	public String getDropSequenceString(String sequenceName) {
+		return "drop sequence " + sequenceName;
+	}
+
+	public String getQuerySequencesString() {
+		return "select NAME from sys.sequences";
+	}
+
+	public JoinFragment createOuterJoinFragment() {
+		return new OracleJoinFragment();
+	}
+
+	// new methods in dialect3
+	/*public boolean supportsForUpdateNowait() {
+		return false;
+	}*/
+	
+	public String getForUpdateString() {
+		return "";
+	}
+	
+	public boolean supportsColumnCheck() {
+		return false;
+	}
+
+	public boolean supportsTableCheck() {
+		return false;
+	}
+	
+	public boolean supportsLimitOffset() {
+		return false;
+	}
+
+	public boolean supportsVariableLimit() {
+		return false;
+	}
+
+	public boolean supportsLimit() {
+		return true;
+	}
+
+	public boolean useMaxForLimit() {
+		return true;
+	}
+
+	public String getLimitString(String querySelect, int offset, int limit) {
+		if ( offset > 0 ) {
+			throw new UnsupportedOperationException( "TimesTen does not support offset" );
+		}
+		return new StringBuffer( querySelect.length()+8 )
+			.append(querySelect)
+			.insert( 6, " first " + limit )
+			.toString();
+	}
+
+	public boolean supportsCurrentTimestampSelection() {
+		return true;
+	}
+
+	public String getCurrentTimestampSelectString() {
+		return "select first 1 sysdate from sys.tables";
+	}
+
+	public boolean isCurrentTimestampSelectStringCallable() {
+		return false;
+	}
+
+	public boolean supportsTemporaryTables() {
+		return true;
+	}
+
+	public String generateTemporaryTableName(String baseTableName) {
+		String name = super.generateTemporaryTableName(baseTableName);
+		return name.length() > 30 ? name.substring( 1, 30 ) : name;
+	}
+
+	public String getCreateTemporaryTableString() {
+		return "create global temporary table";
+	}
+
+	public String getCreateTemporaryTablePostfix() {
+		return "on commit delete rows";
+	}
+
+	public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
+		// TimesTen has no known variation of a "SELECT ... FOR UPDATE" syntax...
+		if ( lockMode.greaterThan( LockMode.READ ) ) {
+			return new UpdateLockingStrategy( lockable, lockMode );
+		}
+		else {
+			return new SelectLockingStrategy( lockable, lockMode );
+		}
+	}
+
+	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean supportsEmptyInList() {
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/TypeNames.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/TypeNames.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/TypeNames.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,116 @@
+//$Id: TypeNames.java 6254 2005-03-30 18:01:41Z oneovthafew $
+package org.hibernate.dialect;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.TreeMap;
+import java.util.Iterator;
+
+import org.hibernate.MappingException;
+import org.hibernate.util.StringHelper;
+
+/**
+ * This class maps a type to names. Associations
+ * may be marked with a capacity. Calling the get()
+ * method with a type and actual size n will return
+ * the associated name with smallest capacity >= n,
+ * if available and an unmarked default type otherwise.
+ * Eg, setting
+ * <pre>
+ *	names.put(type,        "TEXT" );
+ *	names.put(type,   255, "VARCHAR($l)" );
+ *	names.put(type, 65534, "LONGVARCHAR($l)" );
+ * </pre>
+ * will give you back the following:
+ * <pre>
+ *  names.get(type)         // --> "TEXT" (default)
+ *  names.get(type,    100) // --> "VARCHAR(100)" (100 is in [0:255])
+ *  names.get(type,   1000) // --> "LONGVARCHAR(1000)" (1000 is in [256:65534])
+ *  names.get(type, 100000) // --> "TEXT" (default)
+ * </pre>
+ * On the other hand, simply putting
+ * <pre>
+ *	names.put(type, "VARCHAR($l)" );
+ * </pre>
+ * would result in
+ * <pre>
+ *  names.get(type)        // --> "VARCHAR($l)" (will cause trouble)
+ *  names.get(type, 100)   // --> "VARCHAR(100)"
+ *  names.get(type, 10000) // --> "VARCHAR(10000)"
+ * </pre>
+ *
+ * @author Christoph Beck
+ */
+public class TypeNames {
+
+	private HashMap weighted = new HashMap();
+	private HashMap defaults = new HashMap();
+
+	/**
+	 * get default type name for specified type
+	 * @param typecode the type key
+	 * @return the default type name associated with specified key
+	 */
+	public String get(int typecode) throws MappingException {
+		String result = (String) defaults.get( new Integer(typecode) );
+		if (result==null) throw new MappingException("No Dialect mapping for JDBC type: " + typecode);
+		return result;
+	}
+
+	/**
+	 * get type name for specified type and size
+	 * @param typecode the type key
+	 * @param size the SQL length
+	 * @param scale the SQL scale
+	 * @param precision the SQL precision
+	 * @return the associated name with smallest capacity >= size,
+	 * if available and the default type name otherwise
+	 */
+	public String get(int typecode, int size, int precision, int scale) throws MappingException {
+		Map map = (Map) weighted.get( new Integer(typecode) );
+		if ( map!=null && map.size()>0 ) {
+			// iterate entries ordered by capacity to find first fit
+			Iterator entries = map.entrySet().iterator();
+			while ( entries.hasNext() ) {
+				Map.Entry entry = (Map.Entry)entries.next();
+				if ( size <= ( (Integer) entry.getKey() ).intValue() ) {
+					return replace( (String) entry.getValue(), size, precision, scale );
+				}
+			}
+		}
+		return replace( get(typecode), size, precision, scale );
+	}
+	
+	private static String replace(String type, int size, int precision, int scale) {
+		type = StringHelper.replaceOnce(type, "$s", Integer.toString(scale) );
+		type = StringHelper.replaceOnce(type, "$l", Integer.toString(size) );
+		return StringHelper.replaceOnce(type, "$p", Integer.toString(precision) );
+	}
+
+	/**
+	 * set a type name for specified type key and capacity
+	 * @param typecode the type key
+	 */
+	public void put(int typecode, int capacity, String value) {
+		TreeMap map = (TreeMap)weighted.get( new Integer(typecode) );
+		if (map == null) {// add new ordered map
+			map = new TreeMap();
+			weighted.put( new Integer(typecode), map );
+		}
+		map.put(new Integer(capacity), value);
+	}
+
+	/**
+	 * set a default type name for specified type key
+	 * @param typecode the type key
+	 */
+	public void put(int typecode, String value) {
+		defaults.put( new Integer(typecode), value );
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/AnsiTrimEmulationFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/AnsiTrimEmulationFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/AnsiTrimEmulationFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,146 @@
+package org.hibernate.dialect.function;
+
+import org.hibernate.Hibernate;
+import org.hibernate.QueryException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * A {@link SQLFunction} implementation that emulates the ANSI SQL trim function
+ * on dialects which do not support the full definition.  However, this function
+ * definition does assume the availability of ltrim, rtrim, and replace functions
+ * which it uses in various combinations to emulate the desired ANSI trim()
+ * functionality.
+ *
+ * @author Steve Ebersole
+ */
+public class AnsiTrimEmulationFunction implements SQLFunction {
+
+	private static final SQLFunction LEADING_SPACE_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "ltrim( ?1 )");
+	private static final SQLFunction TRAILING_SPACE_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "rtrim( ?1 )");
+	private static final SQLFunction BOTH_SPACE_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "ltrim( rtrim( ?1 ) )");
+	private static final SQLFunction BOTH_SPACE_TRIM_FROM = new SQLFunctionTemplate( Hibernate.STRING, "ltrim( rtrim( ?2 ) )");
+
+	private static final SQLFunction LEADING_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "replace( replace( rtrim( replace( replace( ?1, ' ', '${space}$' ), ?2, ' ' ) ), ' ', ?2 ), '${space}$', ' ' )" );
+	private static final SQLFunction TRAILING_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "replace( replace( ltrim( replace( replace( ?1, ' ', '${space}$' ), ?2, ' ' ) ), ' ', ?2 ), '${space}$', ' ' )" );
+	private static final SQLFunction BOTH_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "replace( replace( ltrim( rtrim( replace( replace( ?1, ' ', '${space}$' ), ?2, ' ' ) ) ), ' ', ?2 ), '${space}$', ' ' )" );
+
+	public Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
+		return Hibernate.STRING;
+	}
+
+	public boolean hasArguments() {
+		return true;
+	}
+
+	public boolean hasParenthesesIfNoArguments() {
+		return false;
+	}
+
+	public String render(List args, SessionFactoryImplementor factory) throws QueryException {
+		// according to both the ANSI-SQL and EJB3 specs, trim can either take
+		// exactly one parameter or a variable number of parameters between 1 and 4.
+		// from the SQL spec:
+		//
+		// <trim function> ::=
+		//      TRIM <left paren> <trim operands> <right paren>
+		//
+		// <trim operands> ::=
+		//      [ [ <trim specification> ] [ <trim character> ] FROM ] <trim source>
+		//
+		// <trim specification> ::=
+		//      LEADING
+		//      | TRAILING
+		//      | BOTH
+		//
+		// If only <trim specification> is omitted, BOTH is assumed;
+		// if <trim character> is omitted, space is assumed
+		if ( args.size() == 1 ) {
+			// we have the form: trim(trimSource)
+			//      so we trim leading and trailing spaces
+			return BOTH_SPACE_TRIM.render( args, factory );
+		}
+		else if ( "from".equalsIgnoreCase( ( String ) args.get( 0 ) ) ) {
+			// we have the form: trim(from trimSource).
+			//      This is functionally equivalent to trim(trimSource)
+			return BOTH_SPACE_TRIM_FROM.render( args, factory );
+		}
+		else {
+			// otherwise, a trim-specification and/or a trim-character
+			// have been specified;  we need to decide which options
+			// are present and "do the right thing"
+			boolean leading = true;         // should leading trim-characters be trimmed?
+			boolean trailing = true;        // should trailing trim-characters be trimmed?
+			String trimCharacter = null;    // the trim-character
+			String trimSource = null;       // the trim-source
+
+			// potentialTrimCharacterArgIndex = 1 assumes that a
+			// trim-specification has been specified.  we handle the
+			// exception to that explicitly
+			int potentialTrimCharacterArgIndex = 1;
+			String firstArg = ( String ) args.get( 0 );
+			if ( "leading".equalsIgnoreCase( firstArg ) ) {
+				trailing = false;
+			}
+			else if ( "trailing".equalsIgnoreCase( firstArg ) ) {
+				leading = false;
+			}
+			else if ( "both".equalsIgnoreCase( firstArg ) ) {
+			}
+			else {
+				potentialTrimCharacterArgIndex = 0;
+			}
+
+			String potentialTrimCharacter = ( String ) args.get( potentialTrimCharacterArgIndex );
+			if ( "from".equalsIgnoreCase( potentialTrimCharacter ) ) {
+				trimCharacter = "' '";
+				trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 1 );
+			}
+			else if ( potentialTrimCharacterArgIndex + 1 >= args.size() ) {
+				trimCharacter = "' '";
+				trimSource = potentialTrimCharacter;
+			}
+			else {
+				trimCharacter = potentialTrimCharacter;
+				if ( "from".equalsIgnoreCase( ( String ) args.get( potentialTrimCharacterArgIndex + 1 ) ) ) {
+					trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 2 );
+				}
+				else {
+					trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 1 );
+				}
+			}
+
+			List argsToUse = null;
+			argsToUse = new ArrayList();
+			argsToUse.add( trimSource );
+			argsToUse.add( trimCharacter );
+
+			if ( trimCharacter.equals( "' '" ) ) {
+				if ( leading && trailing ) {
+					return BOTH_SPACE_TRIM.render( argsToUse, factory );
+				}
+				else if ( leading ) {
+					return LEADING_SPACE_TRIM.render( argsToUse, factory );
+				}
+				else {
+					return TRAILING_SPACE_TRIM.render( argsToUse, factory );
+				}
+			}
+			else {
+				if ( leading && trailing ) {
+					return BOTH_TRIM.render( argsToUse, factory );
+				}
+				else if ( leading ) {
+					return LEADING_TRIM.render( argsToUse, factory );
+				}
+				else {
+					return TRAILING_TRIM.render( argsToUse, factory );
+				}
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/CastFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/CastFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/CastFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+//$Id: CastFunction.java 7368 2005-07-04 02:54:27Z oneovthafew $
+package org.hibernate.dialect.function;
+
+import java.util.List;
+
+import org.hibernate.QueryException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * ANSI-SQL style <tt>cast(foo as type)</tt> where the type is
+ * a Hibernate type
+ * @author Gavin King
+ */
+public class CastFunction implements SQLFunction {
+
+	public Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
+		return columnType; //note there is a wierd implementation in the client side
+	}
+
+	public boolean hasArguments() {
+		return true;
+	}
+
+	public boolean hasParenthesesIfNoArguments() {
+		return true;
+	}
+
+	public String render(List args, SessionFactoryImplementor factory) throws QueryException {
+		if ( args.size()!=2 ) {
+			throw new QueryException("cast() requires two arguments");
+		}
+		String type = (String) args.get(1);
+		int[] sqlTypeCodes = TypeFactory.heuristicType(type).sqlTypes(factory);
+		if ( sqlTypeCodes.length!=1 ) {
+			throw new QueryException("invalid Hibernate type for cast()");
+		}
+		String sqlType = factory.getDialect().getCastTypeName( sqlTypeCodes[0] );
+		if (sqlType==null) {
+			//TODO: never reached, since getTypeName() actually throws an exception!
+			sqlType = type;
+		}
+		/*else {
+			//trim off the length/precision/scale
+			int loc = sqlType.indexOf('(');
+			if (loc>-1) {
+				sqlType = sqlType.substring(0, loc);
+			}
+		}*/
+		return "cast(" + args.get(0) + " as " + sqlType + ')';
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/CastFunction.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/CharIndexFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/CharIndexFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/CharIndexFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: CharIndexFunction.java 8470 2005-10-26 22:12:27Z oneovthafew $
+package org.hibernate.dialect.function;
+
+import java.util.List;
+
+import org.hibernate.Hibernate;
+import org.hibernate.QueryException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Emulation of <tt>locate()</tt> on Sybase
+ * @author Nathan Moon
+ */
+public class CharIndexFunction implements SQLFunction {
+
+	public Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
+		return Hibernate.INTEGER;
+	}
+
+	public boolean hasArguments() {
+		return true;
+	}
+
+	public boolean hasParenthesesIfNoArguments() {
+		return true;
+	}
+
+	public String render(List args, SessionFactoryImplementor factory) throws QueryException {
+		boolean threeArgs = args.size() > 2;
+		Object pattern = args.get(0);
+		Object string = args.get(1);
+		Object start = threeArgs ? args.get(2) : null;
+
+		StringBuffer buf = new StringBuffer();
+		buf.append("charindex(").append( pattern ).append(", ");
+		if (threeArgs) buf.append( "right(");
+		buf.append( string );
+		if (threeArgs) buf.append( ", char_length(" ).append( string ).append(")-(").append( start ).append("-1))");
+		buf.append(')');
+		return buf.toString();
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/CharIndexFunction.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ClassicAvgFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ClassicAvgFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ClassicAvgFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+/**
+ * 
+ */
+package org.hibernate.dialect.function;
+
+import java.sql.Types;
+
+import org.hibernate.Hibernate;
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.type.Type;
+
+/**
+ * Classic AVG sqlfunction that return types as it was done in Hibernate 3.1 
+ * 
+ * @author Max Rydahl Andersen
+ *
+ */
+public class ClassicAvgFunction extends StandardSQLFunction {
+	public ClassicAvgFunction() {
+		super( "avg" );
+	}
+
+	public Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
+		int[] sqlTypes;
+		try {
+			sqlTypes = columnType.sqlTypes( mapping );
+		}
+		catch ( MappingException me ) {
+			throw new QueryException( me );
+		}
+		if ( sqlTypes.length != 1 ) throw new QueryException( "multi-column type in avg()" );
+		int sqlType = sqlTypes[0];
+		if ( sqlType == Types.INTEGER || sqlType == Types.BIGINT || sqlType == Types.TINYINT ) {
+			return Hibernate.FLOAT;
+		}
+		else {
+			return columnType;
+		}
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ClassicCountFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ClassicCountFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ClassicCountFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+/**
+ * 
+ */
+package org.hibernate.dialect.function;
+
+import org.hibernate.Hibernate;
+import org.hibernate.engine.Mapping;
+import org.hibernate.type.Type;
+
+
+/**
+ * Classic COUNT sqlfunction that return types as it was done in Hibernate 3.1 
+ * 
+ * @author Max Rydahl Andersen
+ *
+ */
+public class ClassicCountFunction extends StandardSQLFunction {
+	public ClassicCountFunction() {
+		super( "count" );
+	}
+
+	public Type getReturnType(Type columnType, Mapping mapping) {
+		return Hibernate.INTEGER;
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ClassicSumFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ClassicSumFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ClassicSumFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+/**
+ * 
+ */
+package org.hibernate.dialect.function;
+
+
+/**
+ * Classic SUM sqlfunction that return types as it was done in Hibernate 3.1 
+ * 
+ * @author Max Rydahl Andersen
+ *
+ */
+public class ClassicSumFunction extends StandardSQLFunction {
+	public ClassicSumFunction() {
+		super( "sum" );
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ConditionalParenthesisFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ConditionalParenthesisFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ConditionalParenthesisFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: ConditionalParenthesisFunction.java,v 1.4 2005/04/26 18:08:01 oneovthafew Exp $
+package org.hibernate.dialect.function;
+
+import java.util.List;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Essentially the same as {@link org.hibernate.dialect.function.StandardSQLFunction},
+ * except that here the parentheses are not included when no arguments are given.
+ *
+ * @author Jonathan Levinson
+ */
+public class ConditionalParenthesisFunction extends StandardSQLFunction {
+
+	public ConditionalParenthesisFunction(String name) {
+		super( name );
+	}
+
+	public ConditionalParenthesisFunction(String name, Type type) {
+		super( name, type );
+	}
+
+	public boolean hasParenthesesIfNoArguments() {
+		return false;
+	}
+
+	public String render(List args, SessionFactoryImplementor factory) {
+		final boolean hasArgs = !args.isEmpty();
+		StringBuffer buf = new StringBuffer();
+		buf.append( getName() );
+		if ( hasArgs ) {
+			buf.append( "(" );
+			for ( int i = 0; i < args.size(); i++ ) {
+				buf.append( args.get( i ) );
+				if ( i < args.size() - 1 ) {
+					buf.append( ", " );
+				}
+			}
+			buf.append( ")" );
+		}
+		return buf.toString();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ConvertFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ConvertFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/ConvertFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: CastFunction.java 7368 2005-07-04 02:54:27Z oneovthafew $
+package org.hibernate.dialect.function;
+
+import java.util.List;
+
+import org.hibernate.QueryException;
+import org.hibernate.Hibernate;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * A Cach&eacute; defintion of a convert function.
+ *
+ * @author Jonathan Levinson
+ */
+public class ConvertFunction implements SQLFunction {
+
+	public Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
+		return Hibernate.STRING;
+	}
+
+	public boolean hasArguments() {
+		return true;
+	}
+
+	public boolean hasParenthesesIfNoArguments() {
+		return true;
+	}
+
+	public String render(List args, SessionFactoryImplementor factory) throws QueryException {
+		if ( args.size() != 2 && args.size() != 3 ) {
+			throw new QueryException( "convert() requires two or three arguments" );
+		}
+		String type = ( String ) args.get( 1 );
+
+		if ( args.size() == 2 ) {
+			return "{fn convert(" + args.get( 0 ) + " , " + type + ")}";
+		}
+		else {
+			return "convert(" + args.get( 0 ) + " , " + type + "," + args.get( 2 ) + ")";
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/NoArgSQLFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/NoArgSQLFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/NoArgSQLFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: NoArgSQLFunction.java 6608 2005-04-29 15:32:30Z oneovthafew $
+package org.hibernate.dialect.function;
+
+import java.util.List;
+
+import org.hibernate.QueryException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+
+/**
+ * A function which takes no arguments
+ * @author Michi
+ */
+public class NoArgSQLFunction implements SQLFunction {
+    private Type returnType;
+    private boolean hasParenthesesIfNoArguments;
+    private String name;
+
+    public NoArgSQLFunction(String name, Type returnType) {
+        this(name, returnType, true);
+    }
+
+    public NoArgSQLFunction(String name, Type returnType, boolean hasParenthesesIfNoArguments) {
+        this.returnType = returnType;
+        this.hasParenthesesIfNoArguments = hasParenthesesIfNoArguments;
+        this.name = name;
+    }
+
+    public Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
+        return returnType;
+    }
+
+    public boolean hasArguments() {
+        return false;
+    }
+
+    public boolean hasParenthesesIfNoArguments() {
+        return hasParenthesesIfNoArguments;
+    }
+    
+    public String render(List args, SessionFactoryImplementor factory) throws QueryException {
+    	if ( args.size()>0 ) {
+    		throw new QueryException("function takes no arguments: " + name);
+    	}
+    	return hasParenthesesIfNoArguments ? name + "()" : name;
+    }
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/NvlFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/NvlFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/NvlFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+//$Id: NvlFunction.java 6608 2005-04-29 15:32:30Z oneovthafew $
+package org.hibernate.dialect.function;
+
+import java.util.List;
+
+import org.hibernate.QueryException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Emulation of <tt>coalesce()</tt> on Oracle, using multiple
+ * <tt>nvl()</tt> calls
+ * @author Gavin King
+ */
+public class NvlFunction implements SQLFunction {
+
+	public Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
+		return columnType;
+	}
+
+	public boolean hasArguments() {
+		return true;
+	}
+
+	public boolean hasParenthesesIfNoArguments() {
+		return true;
+	}
+
+	public String render(List args, SessionFactoryImplementor factory) throws QueryException {
+		int lastIndex = args.size()-1;
+		Object last = args.remove(lastIndex);
+		if ( lastIndex==0 ) return last.toString();
+		Object secondLast = args.get(lastIndex-1);
+		String nvl = "nvl(" + secondLast + ", " + last + ")";
+		args.set(lastIndex-1, nvl);
+		return render(args, factory);
+	}
+
+	
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/NvlFunction.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/PositionSubstringFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/PositionSubstringFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/PositionSubstringFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+//$Id: PositionSubstringFunction.java 6608 2005-04-29 15:32:30Z oneovthafew $
+package org.hibernate.dialect.function;
+
+import java.util.List;
+
+import org.hibernate.Hibernate;
+import org.hibernate.QueryException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Emulation of <tt>locate()</tt> on PostgreSQL
+ * @author Gavin King
+ */
+public class PositionSubstringFunction implements SQLFunction {
+
+	public Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
+		return Hibernate.INTEGER;
+	}
+
+	public boolean hasArguments() {
+		return true;
+	}
+
+	public boolean hasParenthesesIfNoArguments() {
+		return true;
+	}
+
+	public String render(List args, SessionFactoryImplementor factory) throws QueryException {
+		boolean threeArgs = args.size() > 2;
+		Object pattern = args.get(0);
+		Object string = args.get(1);
+		Object start = threeArgs ? args.get(2) : null;
+
+		StringBuffer buf = new StringBuffer();
+		if (threeArgs) buf.append('(');
+		buf.append("position(").append( pattern ).append(" in ");
+		if (threeArgs) buf.append( "substring(");
+		buf.append( string );
+		if (threeArgs) buf.append( ", " ).append( start ).append(')');
+		buf.append(')');
+		if (threeArgs) buf.append('+').append( start ).append("-1)");
+		return buf.toString();
+	}
+
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/PositionSubstringFunction.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/SQLFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/SQLFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/SQLFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,58 @@
+//$Id: SQLFunction.java 10774 2006-11-08 16:54:55Z steve.ebersole at jboss.com $
+package org.hibernate.dialect.function;
+
+import java.util.List;
+
+import org.hibernate.QueryException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Provides support routines for the HQL functions as used
+ * in the various SQL Dialects
+ *
+ * Provides an interface for supporting various HQL functions that are
+ * translated to SQL. The Dialect and its sub-classes use this interface to
+ * provide details required for processing of the function.
+ *
+ * @author David Channon
+ */
+public interface SQLFunction {
+	/**
+	 * The return type of the function.  May be either a concrete type which
+	 * is preset, or variable depending upon the type of the first function
+	 * argument.
+	 *
+	 * @param columnType the type of the first argument
+	 * @param mapping The mapping source.
+	 * @return The type to be expected as a return.
+	 * @throws org.hibernate.QueryException Indicates an issue resolving the return type.
+	 */
+	public Type getReturnType(Type columnType, Mapping mapping) throws QueryException;
+
+	/**
+	 * Does this function have any arguments?
+	 *
+	 * @return True if the function expects to have parameters; false otherwise.
+	 */
+	public boolean hasArguments();
+
+	/**
+	 * If there are no arguments, are parens required?
+	 *
+	 * @return True if a no-arg call of this function requires parentheses.
+	 */
+	public boolean hasParenthesesIfNoArguments();
+
+	/**
+	 * Render the function call as SQL fragment.
+	 *
+	 * @param args The function arguments
+	 * @param factory The SessionFactory
+	 * @return The rendered function call
+	 * @throws org.hibernate.QueryException Indicates a problem rendering the
+	 * function call.
+	 */
+	public String render(List args, SessionFactoryImplementor factory) throws QueryException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/SQLFunctionRegistry.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/SQLFunctionRegistry.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/SQLFunctionRegistry.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+package org.hibernate.dialect.function;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hibernate.dialect.Dialect;
+
+public class SQLFunctionRegistry {
+
+	private final Dialect dialect;
+	private final Map userFunctions;
+	
+	public SQLFunctionRegistry(Dialect dialect, Map userFunctions) {
+		this.dialect = dialect;
+		this.userFunctions = new HashMap();
+		this.userFunctions.putAll( userFunctions );
+	}
+	
+	public SQLFunction findSQLFunction(String functionName) {
+		String name = functionName.toLowerCase();
+		SQLFunction userFunction = (SQLFunction) userFunctions.get( name );
+		
+		return userFunction!=null?userFunction:(SQLFunction) dialect.getFunctions().get(name); // TODO: lowercasing done here. Was done "at random" before; maybe not needed at all ?
+	}
+
+	public boolean hasFunction(String functionName) {
+		String name = functionName.toLowerCase();
+		boolean hasUserFunction = userFunctions.containsKey ( name );
+		
+		return hasUserFunction || dialect.getFunctions().containsKey ( name ); // TODO: toLowerCase was not done before. Only used in Template.
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/SQLFunctionTemplate.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/SQLFunctionTemplate.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/SQLFunctionTemplate.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,123 @@
+//$Id: SQLFunctionTemplate.java 6608 2005-04-29 15:32:30Z oneovthafew $
+package org.hibernate.dialect.function;
+
+import org.hibernate.QueryException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents HQL functions that can have different representations in different SQL dialects.
+ * E.g. in HQL we can define function <code>concat(?1, ?2)</code> to concatenate two strings 
+ * p1 and p2. Target SQL function will be dialect-specific, e.g. <code>(?1 || ?2)</code> for 
+ * Oracle, <code>concat(?1, ?2)</code> for MySql, <code>(?1 + ?2)</code> for MS SQL.
+ * Each dialect will define a template as a string (exactly like above) marking function 
+ * parameters with '?' followed by parameter's index (first index is 1).
+ *
+ * @author <a href="mailto:alex at jboss.org">Alexey Loubyansky</a>
+ * @version <tt>$Revision: 6608 $</tt>
+ */
+public class SQLFunctionTemplate implements SQLFunction {
+	private final Type type;
+	private final boolean hasArguments;
+	private final boolean hasParenthesesIfNoArgs;
+
+	private final String template;
+	private final String[] chunks;
+	private final int[] paramIndexes;
+
+	public SQLFunctionTemplate(Type type, String template) {
+		this( type, template, true );
+	}
+
+	public SQLFunctionTemplate(Type type, String template, boolean hasParenthesesIfNoArgs) {
+		this.type = type;
+		this.template = template;
+
+		List chunkList = new ArrayList();
+		List paramList = new ArrayList();
+		StringBuffer chunk = new StringBuffer( 10 );
+		StringBuffer index = new StringBuffer( 2 );
+
+		for ( int i = 0; i < template.length(); ++i ) {
+			char c = template.charAt( i );
+			if ( c == '?' ) {
+				chunkList.add( chunk.toString() );
+				chunk.delete( 0, chunk.length() );
+
+				while ( ++i < template.length() ) {
+					c = template.charAt( i );
+					if ( Character.isDigit( c ) ) {
+						index.append( c );
+					}
+					else {
+						chunk.append( c );
+						break;
+					}
+				}
+
+				paramList.add( new Integer( Integer.parseInt( index.toString() ) - 1 ) );
+				index.delete( 0, index.length() );
+			}
+			else {
+				chunk.append( c );
+			}
+		}
+
+		if ( chunk.length() > 0 ) {
+			chunkList.add( chunk.toString() );
+		}
+
+		chunks = ( String[] ) chunkList.toArray( new String[chunkList.size()] );
+		paramIndexes = new int[paramList.size()];
+		for ( int i = 0; i < paramIndexes.length; ++i ) {
+			paramIndexes[i] = ( ( Integer ) paramList.get( i ) ).intValue();
+		}
+
+		hasArguments = paramIndexes.length > 0;
+		this.hasParenthesesIfNoArgs = hasParenthesesIfNoArgs;
+	}
+
+	/**
+	 * Applies the template to passed in arguments.
+	 * @param args function arguments
+	 *
+	 * @return generated SQL function call
+	 */
+	public String render(List args, SessionFactoryImplementor factory) {
+		StringBuffer buf = new StringBuffer();
+		for ( int i = 0; i < chunks.length; ++i ) {
+			if ( i < paramIndexes.length ) {
+				Object arg = paramIndexes[i] < args.size() ? args.get( paramIndexes[i] ) : null;
+				if ( arg != null ) {
+					buf.append( chunks[i] ).append( arg );
+				}
+			}
+			else {
+				buf.append( chunks[i] );
+			}
+		}
+		return buf.toString();
+	}
+
+	// SQLFunction implementation
+
+	public Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
+		return type;
+	}
+
+	public boolean hasArguments() {
+		return hasArguments;
+	}
+
+	public boolean hasParenthesesIfNoArguments() {
+		return hasParenthesesIfNoArgs;
+	}
+	
+	public String toString() {
+		return template;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/SQLFunctionTemplate.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/StandardJDBCEscapeFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/StandardJDBCEscapeFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/StandardJDBCEscapeFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+package org.hibernate.dialect.function;
+
+import java.util.List;
+
+import org.hibernate.type.Type;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Analogous to {@link org.hibernate.dialect.function.StandardSQLFunction}
+ * except that standard JDBC escape sequences (i.e. {fn blah}) are used when
+ * rendering the SQL.
+ *
+ * @author Steve Ebersole
+ */
+public class StandardJDBCEscapeFunction extends StandardSQLFunction {
+	public StandardJDBCEscapeFunction(String name) {
+		super( name );
+	}
+
+	public StandardJDBCEscapeFunction(String name, Type typeValue) {
+		super( name, typeValue );
+	}
+
+	public String render(List args, SessionFactoryImplementor factory) {
+		return "{fn " + super.render( args, factory ) + "}";
+	}
+
+	public String toString() {
+		return "{fn " + getName() + "...}";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/StandardSQLFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/StandardSQLFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/StandardSQLFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,107 @@
+//$Id: StandardSQLFunction.java 10774 2006-11-08 16:54:55Z steve.ebersole at jboss.com $
+package org.hibernate.dialect.function;
+
+import java.util.List;
+
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Provides a standard implementation that supports the majority of the HQL
+ * functions that are translated to SQL. The Dialect and its sub-classes use
+ * this class to provide details required for processing of the associated
+ * function.
+ *
+ * @author David Channon
+ */
+public class StandardSQLFunction implements SQLFunction {
+	private final String name;
+	private final Type type;
+
+	/**
+	 * Construct a standard SQL function definition with a variable return type;
+	 * the actual return type will depend on the types to which the function
+	 * is applied.
+	 * <p/>
+	 * Using this form, the return type is considered non-static and assumed
+	 * to be the type of the first argument.
+	 *
+	 * @param name The name of the function.
+	 */
+	public StandardSQLFunction(String name) {
+		this( name, null );
+	}
+
+	/**
+	 * Construct a standard SQL function definition with a static return type.
+	 *
+	 * @param name The name of the function.
+	 * @param type The static return type.
+	 */
+	public StandardSQLFunction(String name, Type type) {
+		this.name = name;
+		this.type = type;
+	}
+
+	/**
+	 * Function name accessor
+	 *
+	 * @return The function name.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Function static return type accessor.
+	 *
+	 * @return The static function return type; or null if return type is
+	 * not static.
+	 */
+	public Type getType() {
+		return type;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Type getReturnType(Type columnType, Mapping mapping) {
+		// return the concrete type, or the underlying type if a concrete type
+		// was not specified
+		return type == null ? columnType : type;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public boolean hasArguments() {
+		return true;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public boolean hasParenthesesIfNoArguments() {
+		return true;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public String render(List args, SessionFactoryImplementor factory) {
+		StringBuffer buf = new StringBuffer();
+		buf.append( name ).append( '(' );
+		for ( int i = 0; i < args.size(); i++ ) {
+			buf.append( args.get( i ) );
+			if ( i < args.size() - 1 ) {
+				buf.append( ", " );
+			}
+		}
+		return buf.append( ')' ).toString();
+	}
+
+	public String toString() {
+		return name;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/VarArgsSQLFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/VarArgsSQLFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/VarArgsSQLFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,58 @@
+//$Id: VarArgsSQLFunction.java 6608 2005-04-29 15:32:30Z oneovthafew $
+package org.hibernate.dialect.function;
+
+import java.util.List;
+
+import org.hibernate.QueryException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Support for slightly more general templating than <tt>StandardSQLFunction</tt>,
+ * with an unlimited number of arguments.
+ * @author Gavin King
+ */
+public class VarArgsSQLFunction implements SQLFunction {
+
+	private final String begin;
+	private final String sep;
+	private final String end;
+	private final Type type;
+	
+	public VarArgsSQLFunction(Type type, String begin, String sep, String end) {
+		this.begin = begin;
+		this.sep = sep;
+		this.end = end;
+		this.type = type;
+	}
+
+	public VarArgsSQLFunction(String begin, String sep, String end) {
+		this.begin = begin;
+		this.sep = sep;
+		this.end = end;
+		this.type = null;
+	}
+
+	public Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
+		return type==null ? columnType : type;
+	}
+
+	public boolean hasArguments() {
+		return true;
+	}
+
+	public boolean hasParenthesesIfNoArguments() {
+		return true;
+	}
+
+	public String render(List args, SessionFactoryImplementor factory) throws QueryException {
+		StringBuffer buf = new StringBuffer().append(begin);
+		for ( int i=0; i<args.size(); i++ ) {
+			buf.append( args.get(i) );
+			if (i<args.size()-1) buf.append(sep);
+		}
+		return buf.append(end).toString();
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/VarArgsSQLFunction.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	A framework for defining database-specific SQL functions
+	that are available via the dialect.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/function/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/lock/LockingStrategy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/lock/LockingStrategy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/lock/LockingStrategy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+package org.hibernate.dialect.lock;
+
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.JDBCException;
+
+import java.io.Serializable;
+
+/**
+ * A strategy abstraction for how locks are obtained in the underlying database.
+ * <p/>
+ * All locking provided implemenations assume the underlying database supports
+ * (and that the connection is in) at least read-committed transaction isolation.
+ * The most glaring exclusion to this is HSQLDB which only offers support for
+ * READ_UNCOMMITTED isolation.
+ *
+ * @see org.hibernate.dialect.Dialect#getLockingStrategy
+ * @since 3.2
+ *
+ * @author Steve Ebersole
+ */
+public interface LockingStrategy {
+	/**
+	 * Acquire an appropriate type of lock on the underlying data that will
+	 * endure until the end of the current transaction.
+	 *
+	 * @param id The id of the row to be locked
+	 * @param version The current version (or null if not versioned)
+	 * @param object The object logically being locked (currently not used)
+	 * @param session The session from which the lock request originated
+	 * @throws StaleObjectStateException Indicates an optimisitic lock failure
+	 * as part of acquiring the requested database lock.
+	 * @throws JDBCException
+	 */
+	public void lock(Serializable id, Object version, Object object, SessionImplementor session)
+	throws StaleObjectStateException, JDBCException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/lock/SelectLockingStrategy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/lock/SelectLockingStrategy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/lock/SelectLockingStrategy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,119 @@
+package org.hibernate.dialect.lock;
+
+import org.hibernate.persister.entity.Lockable;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.JDBCException;
+import org.hibernate.LockMode;
+import org.hibernate.sql.SimpleSelect;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.exception.JDBCExceptionHelper;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * A locking strategy where the locks are obtained through select statements.
+ * <p/>
+ * For non-read locks, this is achieved through the Dialect's specific
+ * SELECT ... FOR UPDATE syntax.
+ *
+ * @see org.hibernate.dialect.Dialect#getForUpdateString(org.hibernate.LockMode)
+ * @see org.hibernate.dialect.Dialect#appendLockHint(org.hibernate.LockMode, String)
+ * @since 3.2
+ *
+ * @author Steve Ebersole
+ */
+public class SelectLockingStrategy implements LockingStrategy {
+
+	private final Lockable lockable;
+	private final LockMode lockMode;
+	private final String sql;
+
+	/**
+	 * Construct a locking strategy based on SQL SELECT statements.
+	 *
+	 * @param lockable The metadata for the entity to be locked.
+	 * @param lockMode Indictates the type of lock to be acquired.
+	 */
+	public SelectLockingStrategy(Lockable lockable, LockMode lockMode) {
+		this.lockable = lockable;
+		this.lockMode = lockMode;
+		this.sql = generateLockString();
+	}
+
+	/**
+	 * @see LockingStrategy#lock
+	 */
+	public void lock(
+	        Serializable id,
+	        Object version,
+	        Object object,
+	        SessionImplementor session) throws StaleObjectStateException, JDBCException {
+
+		SessionFactoryImplementor factory = session.getFactory();
+		try {
+			PreparedStatement st = session.getBatcher().prepareSelectStatement( sql );
+			try {
+				lockable.getIdentifierType().nullSafeSet( st, id, 1, session );
+				if ( lockable.isVersioned() ) {
+					lockable.getVersionType().nullSafeSet(
+							st,
+							version,
+							lockable.getIdentifierType().getColumnSpan( factory ) + 1,
+							session
+					);
+				}
+
+				ResultSet rs = st.executeQuery();
+				try {
+					if ( !rs.next() ) {
+						if ( factory.getStatistics().isStatisticsEnabled() ) {
+							factory.getStatisticsImplementor()
+									.optimisticFailure( lockable.getEntityName() );
+						}
+						throw new StaleObjectStateException( lockable.getEntityName(), id );
+					}
+				}
+				finally {
+					rs.close();
+				}
+			}
+			finally {
+				session.getBatcher().closeStatement( st );
+			}
+
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					session.getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not lock: " + MessageHelper.infoString( lockable, id, session.getFactory() ),
+					sql
+				);
+		}
+	}
+
+	protected LockMode getLockMode() {
+		return lockMode;
+	}
+
+	protected String generateLockString() {
+		SessionFactoryImplementor factory = lockable.getFactory();
+		SimpleSelect select = new SimpleSelect( factory.getDialect() )
+				.setLockMode( lockMode )
+				.setTableName( lockable.getRootTableName() )
+				.addColumn( lockable.getRootTableIdentifierColumnNames()[0] )
+				.addCondition( lockable.getRootTableIdentifierColumnNames(), "=?" );
+		if ( lockable.isVersioned() ) {
+			select.addCondition( lockable.getVersionColumnName(), "=?" );
+		}
+		if ( factory.getSettings().isCommentsEnabled() ) {
+			select.setComment( lockMode + " lock " + lockable.getEntityName() );
+		}
+		return select.toStatementString();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/lock/UpdateLockingStrategy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/lock/UpdateLockingStrategy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/lock/UpdateLockingStrategy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,122 @@
+package org.hibernate.dialect.lock;
+
+import org.hibernate.persister.entity.Lockable;
+import org.hibernate.LockMode;
+import org.hibernate.HibernateException;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.JDBCException;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.sql.Update;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * A locking strategy where the locks are obtained through update statements.
+ * <p/>
+ * This strategy is not valid for read style locks.
+ *
+ * @since 3.2
+ *
+ * @author Steve Ebersole
+ */
+public class UpdateLockingStrategy implements LockingStrategy {
+	private static final Log log = LogFactory.getLog( UpdateLockingStrategy.class );
+
+	private final Lockable lockable;
+	private final LockMode lockMode;
+	private final String sql;
+
+	/**
+	 * Construct a locking strategy based on SQL UPDATE statements.
+	 *
+	 * @param lockable The metadata for the entity to be locked.
+	 * @param lockMode Indictates the type of lock to be acquired.  Note that
+	 * read-locks are not valid for this strategy.
+	 */
+	public UpdateLockingStrategy(Lockable lockable, LockMode lockMode) {
+		this.lockable = lockable;
+		this.lockMode = lockMode;
+		if ( lockMode.lessThan( LockMode.UPGRADE ) ) {
+			throw new HibernateException( "[" + lockMode + "] not valid for update statement" );
+		}
+		if ( !lockable.isVersioned() ) {
+			log.warn( "write locks via update not supported for non-versioned entities [" + lockable.getEntityName() + "]" );
+			this.sql = null;
+		}
+		else {
+			this.sql = generateLockString();
+		}
+	}
+
+	/**
+	 * @see LockingStrategy#lock
+	 */
+	public void lock(
+			Serializable id,
+	        Object version,
+	        Object object,
+	        SessionImplementor session) throws StaleObjectStateException, JDBCException {
+		if ( !lockable.isVersioned() ) {
+			throw new HibernateException( "write locks via update not supported for non-versioned entities [" + lockable.getEntityName() + "]" );
+		}
+		// todo : should we additionally check the current isolation mode explicitly?
+		SessionFactoryImplementor factory = session.getFactory();
+		try {
+			PreparedStatement st = session.getBatcher().prepareSelectStatement( sql );
+			try {
+				lockable.getVersionType().nullSafeSet( st, version, 1, session );
+				int offset = 2;
+
+				lockable.getIdentifierType().nullSafeSet( st, id, offset, session );
+				offset += lockable.getIdentifierType().getColumnSpan( factory );
+
+				if ( lockable.isVersioned() ) {
+					lockable.getVersionType().nullSafeSet( st, version, offset, session );
+				}
+
+				int affected = st.executeUpdate();
+				if ( affected < 0 ) {
+					factory.getStatisticsImplementor().optimisticFailure( lockable.getEntityName() );
+					throw new StaleObjectStateException( lockable.getEntityName(), id );
+				}
+
+			}
+			finally {
+				session.getBatcher().closeStatement( st );
+			}
+
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					session.getFactory().getSQLExceptionConverter(),
+			        sqle,
+			        "could not lock: " + MessageHelper.infoString( lockable, id, session.getFactory() ),
+			        sql
+			);
+		}
+	}
+
+	protected String generateLockString() {
+		SessionFactoryImplementor factory = lockable.getFactory();
+		Update update = new Update( factory.getDialect() );
+		update.setTableName( lockable.getRootTableName() );
+		update.setPrimaryKeyColumnNames( lockable.getRootTableIdentifierColumnNames() );
+		update.setVersionColumnName( lockable.getVersionColumnName() );
+		update.addColumn( lockable.getVersionColumnName() );
+		if ( factory.getSettings().isCommentsEnabled() ) {
+			update.setComment( lockMode + " lock " + lockable.getEntityName() );
+		}
+		return update.toStatementString();
+	}
+
+	protected LockMode getLockMode() {
+		return lockMode;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,11 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package abstracts the SQL dialect of the underlying database.
+</p>
+<p>
+	A concrete <tt>Dialect</tt> may be specifed using <tt>hibernate.dialect</tt>.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/dialect/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ActionQueue.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ActionQueue.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ActionQueue.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,531 @@
+// $Id: ActionQueue.java 11402 2007-04-11 14:24:35Z steve.ebersole at jboss.com $
+package org.hibernate.engine;
+
+import org.hibernate.action.EntityInsertAction;
+import org.hibernate.action.EntityDeleteAction;
+import org.hibernate.action.Executable;
+import org.hibernate.action.EntityUpdateAction;
+import org.hibernate.action.CollectionRecreateAction;
+import org.hibernate.action.CollectionRemoveAction;
+import org.hibernate.action.CollectionUpdateAction;
+import org.hibernate.action.EntityIdentityInsertAction;
+import org.hibernate.action.BulkOperationCleanupAction;
+import org.hibernate.HibernateException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.cache.CacheException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.io.ObjectInputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+
+/**
+ * Responsible for maintaining the queue of actions related to events.
+ * </p>
+ * The ActionQueue holds the DML operations queued as part of a session's
+ * transactional-write-behind semantics.  DML operations are queued here
+ * until a flush forces them to be executed against the database.
+ *
+ * @author Steve Ebersole
+ */
+public class ActionQueue {
+
+	private static final Log log = LogFactory.getLog( ActionQueue.class );
+	private static final int INIT_QUEUE_LIST_SIZE = 5;
+
+	private SessionImplementor session;
+
+	// Object insertions, updates, and deletions have list semantics because
+	// they must happen in the right order so as to respect referential
+	// integrity
+	private ArrayList insertions;
+	private ArrayList deletions;
+	private ArrayList updates;
+	// Actually the semantics of the next three are really "Bag"
+	// Note that, unlike objects, collection insertions, updates,
+	// deletions are not really remembered between flushes. We
+	// just re-use the same Lists for convenience.
+	private ArrayList collectionCreations;
+	private ArrayList collectionUpdates;
+	private ArrayList collectionRemovals;
+
+	private ArrayList executions;
+
+	/**
+	 * Constructs an action queue bound to the given session.
+	 *
+	 * @param session The session "owning" this queue.
+	 */
+	public ActionQueue(SessionImplementor session) {
+		this.session = session;
+		init();
+	}
+
+	private void init() {
+		insertions = new ArrayList( INIT_QUEUE_LIST_SIZE );
+		deletions = new ArrayList( INIT_QUEUE_LIST_SIZE );
+		updates = new ArrayList( INIT_QUEUE_LIST_SIZE );
+
+		collectionCreations = new ArrayList( INIT_QUEUE_LIST_SIZE );
+		collectionRemovals = new ArrayList( INIT_QUEUE_LIST_SIZE );
+		collectionUpdates = new ArrayList( INIT_QUEUE_LIST_SIZE );
+
+		executions = new ArrayList( INIT_QUEUE_LIST_SIZE * 3 );
+	}
+
+	public void clear() {
+		updates.clear();
+		insertions.clear();
+		deletions.clear();
+
+		collectionCreations.clear();
+		collectionRemovals.clear();
+		collectionUpdates.clear();
+	}
+
+	public void addAction(EntityInsertAction action) {
+		insertions.add( action );
+	}
+
+	public void addAction(EntityDeleteAction action) {
+		deletions.add( action );
+	}
+
+	public void addAction(EntityUpdateAction action) {
+		updates.add( action );
+	}
+
+	public void addAction(CollectionRecreateAction action) {
+		collectionCreations.add( action );
+	}
+
+	public void addAction(CollectionRemoveAction action) {
+		collectionRemovals.add( action );
+	}
+
+	public void addAction(CollectionUpdateAction action) {
+		collectionUpdates.add( action );
+	}
+
+	public void addAction(EntityIdentityInsertAction insert) {
+		insertions.add( insert );
+	}
+
+	public void addAction(BulkOperationCleanupAction cleanupAction) {
+		// Add these directly to the executions queue
+		executions.add( cleanupAction );
+	}
+
+	/**
+	 * Perform all currently queued entity-insertion actions.
+	 *
+	 * @throws HibernateException error executing queued insertion actions.
+	 */
+	public void executeInserts() throws HibernateException {
+		executeActions( insertions );
+	}
+
+	/**
+	 * Perform all currently queued actions.
+	 *
+	 * @throws HibernateException error executing queued actions.
+	 */
+	public void executeActions() throws HibernateException {
+		executeActions( insertions );
+		executeActions( updates );
+		executeActions( collectionRemovals );
+		executeActions( collectionUpdates );
+		executeActions( collectionCreations );
+		executeActions( deletions );
+	}
+
+	/**
+	 * Prepares the internal action queues for execution.
+	 *
+	 * @throws HibernateException error preparing actions.
+	 */
+	public void prepareActions() throws HibernateException {
+		prepareActions( collectionRemovals );
+		prepareActions( collectionUpdates );
+		prepareActions( collectionCreations );
+	}
+
+	/**
+	 * Performs cleanup of any held cache softlocks.
+	 *
+	 * @param success Was the transaction successful.
+	 */
+	public void afterTransactionCompletion(boolean success) {
+		int size = executions.size();
+		final boolean invalidateQueryCache = session.getFactory().getSettings().isQueryCacheEnabled();
+		for ( int i = 0; i < size; i++ ) {
+			try {
+				Executable exec = ( Executable ) executions.get(i);
+				try {
+					exec.afterTransactionCompletion( success );
+				}
+				finally {
+					if ( invalidateQueryCache ) {
+						session.getFactory().getUpdateTimestampsCache().invalidate( exec.getPropertySpaces() );
+					}
+				}
+			}
+			catch (CacheException ce) {
+				log.error( "could not release a cache lock", ce );
+				// continue loop
+			}
+			catch (Exception e) {
+				throw new AssertionFailure( "Exception releasing cache locks", e );
+			}
+		}
+		executions.clear();
+	}
+
+	/**
+	 * Check whether the given tables/query-spaces are to be executed against
+	 * given the currently queued actions.
+	 *
+	 * @param tables The table/query-spaces to check.
+	 * @return True if we contain pending actions against any of the given
+	 * tables; false otherwise.
+	 */
+	public boolean areTablesToBeUpdated(Set tables) {
+		return areTablesToUpdated( updates, tables ) ||
+		       areTablesToUpdated( insertions, tables ) ||
+		       areTablesToUpdated( deletions, tables ) ||
+		       areTablesToUpdated( collectionUpdates, tables ) ||
+		       areTablesToUpdated( collectionCreations, tables ) ||
+		       areTablesToUpdated( collectionRemovals, tables );
+	}
+
+	/**
+	 * Check whether any insertion or deletion actions are currently queued.
+	 *
+	 * @return True if insertions or deletions are currently queued; false otherwise.
+	 */
+	public boolean areInsertionsOrDeletionsQueued() {
+		return ( insertions.size() > 0 || deletions.size() > 0 );
+	}
+
+	private static boolean areTablesToUpdated(List executables, Set tablespaces) {
+		int size = executables.size();
+		for ( int j = 0; j < size; j++ ) {
+			Serializable[] spaces = ( (Executable) executables.get(j) ).getPropertySpaces();
+			for ( int i = 0; i < spaces.length; i++ ) {
+				if ( tablespaces.contains( spaces[i] ) ) {
+					if ( log.isDebugEnabled() ) log.debug( "changes must be flushed to space: " + spaces[i] );
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	private void executeActions(List list) throws HibernateException {
+		int size = list.size();
+		for ( int i = 0; i < size; i++ ) {
+			execute( (Executable) list.get(i) );
+		}
+		list.clear();
+		session.getBatcher().executeBatch();
+	}
+
+	public void execute(Executable executable) {
+		final boolean lockQueryCache = session.getFactory().getSettings().isQueryCacheEnabled();
+		if ( executable.hasAfterTransactionCompletion() || lockQueryCache ) {
+			executions.add( executable );
+		}
+		if (lockQueryCache) {
+			session.getFactory()
+				.getUpdateTimestampsCache()
+				.preinvalidate( executable.getPropertySpaces() );
+		}
+		executable.execute();
+	}
+
+	private void prepareActions(List queue) throws HibernateException {
+		int size = queue.size();
+		for ( int i=0; i<size; i++ ) {
+			Executable executable = ( Executable ) queue.get(i);
+			executable.beforeExecutions();
+		}
+	}
+
+	/**
+	 * Returns a string representation of the object.
+	 *
+	 * @return a string representation of the object.
+	 */
+	public String toString() {
+		return new StringBuffer()
+				.append("ActionQueue[insertions=").append(insertions)
+				.append(" updates=").append(updates)
+		        .append(" deletions=").append(deletions)
+				.append(" collectionCreations=").append(collectionCreations)
+				.append(" collectionRemovals=").append(collectionRemovals)
+				.append(" collectionUpdates=").append(collectionUpdates)
+		        .append("]")
+				.toString();
+	}
+
+	public int numberOfCollectionRemovals() {
+		return collectionRemovals.size();
+	}
+
+	public int numberOfCollectionUpdates() {
+		return collectionUpdates.size();
+	}
+
+	public int numberOfCollectionCreations() {
+		return collectionCreations.size();
+	}
+
+	public int numberOfDeletions() {
+		return deletions.size();
+	}
+
+	public int numberOfUpdates() {
+		return updates.size();
+	}
+
+	public int numberOfInsertions() {
+		return insertions.size();
+	}
+
+	public void sortCollectionActions() {
+		if ( session.getFactory().getSettings().isOrderUpdatesEnabled() ) {
+			//sort the updates by fk
+			java.util.Collections.sort( collectionCreations );
+			java.util.Collections.sort( collectionUpdates );
+			java.util.Collections.sort( collectionRemovals );
+		}
+	}
+
+	public void sortActions() {
+		if ( session.getFactory().getSettings().isOrderUpdatesEnabled() ) {
+			//sort the updates by pk
+			java.util.Collections.sort( updates );
+		}
+		if ( session.getFactory().getSettings().isOrderInsertsEnabled() ) {
+			sortInsertActions();
+		}
+	}
+
+	/**
+	 * Provided the option is set ({@link org.hibernate.cfg.Environment#ORDER_INSERTS}),
+	 * then order the {@link #insertions} queue such that we group inserts
+	 * against the same entity together (without violating constraints).  The
+	 * original order is generated by cascade order, which in turn is based on
+	 * the directionality of foreign-keys.  So even though we will be changing
+	 * the ordering here, we need to make absolutely certain that we do not
+	 * circumvent this FK ordering to the extent of causing constraint
+	 * violations
+	 */
+	private void sortInsertActions() {
+		// IMPLEMENTATION NOTES:
+		//
+		// The main data structure in this ordering algorithm is the 'positionToAction'
+		// map.  Essentially this can be thought of as an put-ordered map (the problem with
+		// actually implementing it that way and doing away with the 'nameList' is that
+		// we'd end up having potential duplicate key values).  'positionToAction' maitains
+		// a mapping from a position within the 'nameList' structure to a "partial queue"
+		// of actions.
+
+		HashMap positionToAction = new HashMap();
+		List nameList = new ArrayList();
+
+		loopInsertion: while( !insertions.isEmpty() ) {
+			EntityInsertAction action = ( EntityInsertAction ) insertions.remove( 0 );
+			String thisEntityName = action.getEntityName();
+
+			// see if we have already encountered this entity-name...
+			if ( ! nameList.contains( thisEntityName ) ) {
+				// we have not, so create the proper entries in nameList and positionToAction
+				ArrayList segmentedActionQueue = new ArrayList();
+				segmentedActionQueue.add( action );
+				nameList.add( thisEntityName );
+				positionToAction.put( new Integer( nameList.indexOf( thisEntityName ) ), segmentedActionQueue );
+			}
+			else {
+				// we have seen it before, so we need to determine if this insert action is
+				// is depenedent upon a previously processed action in terms of FK
+				// relationships (this FK checking is done against the entity's property-state
+				// associated with the action...)
+				int lastPos = nameList.lastIndexOf( thisEntityName );
+				Object[] states = action.getState();
+				for ( int i = 0; i < states.length; i++ ) {
+					for ( int j = 0; j < nameList.size(); j++ ) {
+						ArrayList tmpList = ( ArrayList ) positionToAction.get( new Integer( j ) );
+						for ( int k = 0; k < tmpList.size(); k++ ) {
+							final EntityInsertAction checkAction = ( EntityInsertAction ) tmpList.get( k );
+							if ( checkAction.getInstance() == states[i] && j > lastPos ) {
+								// 'checkAction' is inserting an entity upon which 'action'
+								// depends...
+								// note: this is an assumption and may not be correct in the case of one-to-one
+								ArrayList segmentedActionQueue = new ArrayList();
+								segmentedActionQueue.add( action );
+								nameList.add( thisEntityName );
+								positionToAction.put(new Integer( nameList.lastIndexOf( thisEntityName ) ), segmentedActionQueue );
+								continue loopInsertion;
+							}
+						}
+					}
+				}
+
+				ArrayList actionQueue = ( ArrayList ) positionToAction.get( new Integer( lastPos ) );
+ 				actionQueue.add( action );
+ 			}
+ 		}
+
+ 		// now iterate back through positionToAction map and move entityInsertAction back to insertion list
+		for ( int p = 0; p < nameList.size(); p++ ) {
+			ArrayList actionQueue = ( ArrayList ) positionToAction.get( new Integer( p ) );
+			Iterator itr = actionQueue.iterator();
+			while ( itr.hasNext() ) {
+				insertions.add( itr.next() );
+			}
+		}
+	}
+
+	public ArrayList cloneDeletions() {
+		return (ArrayList) deletions.clone();
+	}
+
+	public void clearFromFlushNeededCheck(int previousCollectionRemovalSize) {
+		collectionCreations.clear();
+		collectionUpdates.clear();
+		updates.clear();
+		// collection deletions are a special case since update() can add
+		// deletions of collections not loaded by the session.
+		for ( int i = collectionRemovals.size()-1; i >= previousCollectionRemovalSize; i-- ) {
+			collectionRemovals.remove(i);
+		}
+	}
+
+	public boolean hasAnyQueuedActions() {
+		return updates.size() > 0 ||
+		       insertions.size() > 0 ||
+		       deletions.size() > 0 ||
+		       collectionUpdates.size() > 0 ||
+		       collectionRemovals.size() > 0 ||
+		       collectionCreations.size() > 0;
+	}
+
+	/**
+	 * Used by the owning session to explicitly control serialization of the
+	 * action queue
+	 *
+	 * @param oos The stream to which the action queue should get written
+	 * @throws IOException
+	 */
+	public void serialize(ObjectOutputStream oos) throws IOException {
+		log.trace( "serializing action-queue" );
+
+		int queueSize = insertions.size();
+		log.trace( "starting serialization of [" + queueSize + "] insertions entries" );
+		oos.writeInt( queueSize );
+		for ( int i = 0; i < queueSize; i++ ) {
+			oos.writeObject( insertions.get( i ) );
+		}
+
+		queueSize = deletions.size();
+		log.trace( "starting serialization of [" + queueSize + "] deletions entries" );
+		oos.writeInt( queueSize );
+		for ( int i = 0; i < queueSize; i++ ) {
+			oos.writeObject( deletions.get( i ) );
+		}
+
+		queueSize = updates.size();
+		log.trace( "starting serialization of [" + queueSize + "] updates entries" );
+		oos.writeInt( queueSize );
+		for ( int i = 0; i < queueSize; i++ ) {
+			oos.writeObject( updates.get( i ) );
+		}
+
+		queueSize = collectionUpdates.size();
+		log.trace( "starting serialization of [" + queueSize + "] collectionUpdates entries" );
+		oos.writeInt( queueSize );
+		for ( int i = 0; i < queueSize; i++ ) {
+			oos.writeObject( collectionUpdates.get( i ) );
+		}
+
+		queueSize = collectionRemovals.size();
+		log.trace( "starting serialization of [" + queueSize + "] collectionRemovals entries" );
+		oos.writeInt( queueSize );
+		for ( int i = 0; i < queueSize; i++ ) {
+			oos.writeObject( collectionRemovals.get( i ) );
+		}
+
+		queueSize = collectionCreations.size();
+		log.trace( "starting serialization of [" + queueSize + "] collectionCreations entries" );
+		oos.writeInt( queueSize );
+		for ( int i = 0; i < queueSize; i++ ) {
+			oos.writeObject( collectionCreations.get( i ) );
+		}
+	}
+
+	/**
+	 * Used by the owning session to explicitly control deserialization of the
+	 * action queue
+	 *
+	 * @param ois The stream from which to read the action queue
+	 * @throws IOException
+	 */
+	public static ActionQueue deserialize(
+			ObjectInputStream ois,
+	        SessionImplementor session) throws IOException, ClassNotFoundException {
+		log.trace( "deserializing action-queue" );
+		ActionQueue rtn = new ActionQueue( session );
+
+		int queueSize = ois.readInt();
+		log.trace( "starting deserialization of [" + queueSize + "] insertions entries" );
+		rtn.insertions = new ArrayList( queueSize );
+		for ( int i = 0; i < queueSize; i++ ) {
+			rtn.insertions.add( ois.readObject() );
+		}
+
+		queueSize = ois.readInt();
+		log.trace( "starting deserialization of [" + queueSize + "] deletions entries" );
+		rtn.deletions = new ArrayList( queueSize );
+		for ( int i = 0; i < queueSize; i++ ) {
+			rtn.deletions.add( ois.readObject() );
+		}
+
+		queueSize = ois.readInt();
+		log.trace( "starting deserialization of [" + queueSize + "] updates entries" );
+		rtn.updates = new ArrayList( queueSize );
+		for ( int i = 0; i < queueSize; i++ ) {
+			rtn.updates.add( ois.readObject() );
+		}
+
+		queueSize = ois.readInt();
+		log.trace( "starting deserialization of [" + queueSize + "] collectionUpdates entries" );
+		rtn.collectionUpdates = new ArrayList( queueSize );
+		for ( int i = 0; i < queueSize; i++ ) {
+			rtn.collectionUpdates.add( ois.readObject() );
+		}
+
+		queueSize = ois.readInt();
+		log.trace( "starting deserialization of [" + queueSize + "] collectionRemovals entries" );
+		rtn.collectionRemovals = new ArrayList( queueSize );
+		for ( int i = 0; i < queueSize; i++ ) {
+			rtn.collectionRemovals.add( ois.readObject() );
+		}
+
+		queueSize = ois.readInt();
+		log.trace( "starting deserialization of [" + queueSize + "] collectionCreations entries" );
+		rtn.collectionCreations = new ArrayList( queueSize );
+		for ( int i = 0; i < queueSize; i++ ) {
+			rtn.collectionCreations.add( ois.readObject() );
+		}
+		return rtn;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/AssociationKey.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/AssociationKey.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/AssociationKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+//$Id: AssociationKey.java 7458 2005-07-12 20:12:57Z oneovthafew $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+
+/**
+ * Identifies a named association belonging to a particular
+ * entity instance. Used to record the fact that an association
+ * is null during loading.
+ * 
+ * @author Gavin King
+ */
+final class AssociationKey implements Serializable {
+	private EntityKey ownerKey;
+	private String propertyName;
+	
+	public AssociationKey(EntityKey ownerKey, String propertyName) {
+		this.ownerKey = ownerKey;
+		this.propertyName = propertyName;
+	}
+	
+	public boolean equals(Object that) {
+		AssociationKey key = (AssociationKey) that;
+		return key.propertyName.equals(propertyName) && 
+			key.ownerKey.equals(ownerKey);
+	}
+	
+	public int hashCode() {
+		return ownerKey.hashCode() + propertyName.hashCode();
+	}
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/AssociationKey.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/BatchFetchQueue.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/BatchFetchQueue.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/BatchFetchQueue.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,276 @@
+//$Id: BatchFetchQueue.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.commons.collections.SequencedHashMap;
+import org.hibernate.EntityMode;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.util.MarkerObject;
+
+/**
+ * Tracks entity and collection keys that are available for batch
+ * fetching, and the queries which were used to load entities, which
+ * can be re-used as a subquery for loading owned collections.
+ *
+ * @author Gavin King
+ */
+public class BatchFetchQueue {
+
+	public static final Object MARKER = new MarkerObject( "MARKER" );
+
+	/**
+	 * Defines a sequence of {@link EntityKey} elements that are currently
+	 * elegible for batch-fetching.
+	 * <p/>
+	 * Even though this is a map, we only use the keys.  A map was chosen in
+	 * order to utilize a {@link SequencedHashMap} to maintain sequencing
+	 * as well as uniqueness.
+	 * <p/>
+	 * TODO : this would be better as a SequencedReferenceSet, but no such beast exists!
+	 */
+	private final Map batchLoadableEntityKeys = new SequencedHashMap(8);
+
+	/**
+	 * A map of {@link SubselectFetch subselect-fetch descriptors} keyed by the
+	 * {@link EntityKey) against which the descriptor is registered.
+	 */
+	private final Map subselectsByEntityKey = new HashMap(8);
+
+	/**
+	 * The owning persistence context.
+	 */
+	private final PersistenceContext context;
+
+	/**
+	 * Constructs a queue for the given context.
+	 *
+	 * @param context The owning context.
+	 */
+	public BatchFetchQueue(PersistenceContext context) {
+		this.context = context;
+	}
+
+	/**
+	 * Clears all entries from this fetch queue.
+	 */
+	public void clear() {
+		batchLoadableEntityKeys.clear();
+		subselectsByEntityKey.clear();
+	}
+
+	/**
+	 * Retrieve the fetch descriptor associated with the given entity key.
+	 *
+	 * @param key The entity key for which to locate any defined subselect fetch.
+	 * @return The fetch descriptor; may return null if no subselect fetch queued for
+	 * this entity key.
+	 */
+	public SubselectFetch getSubselect(EntityKey key) {
+		return (SubselectFetch) subselectsByEntityKey.get(key);
+	}
+
+	/**
+	 * Adds a subselect fetch decriptor for the given entity key.
+	 *
+	 * @param key The entity for which to register the subselect fetch.
+	 * @param subquery The fetch descriptor.
+	 */
+	public void addSubselect(EntityKey key, SubselectFetch subquery) {
+		subselectsByEntityKey.put(key, subquery);
+	}
+
+	/**
+	 * After evicting or deleting an entity, we don't need to
+	 * know the query that was used to load it anymore (don't
+	 * call this after loading the entity, since we might still
+	 * need to load its collections)
+	 */
+	public void removeSubselect(EntityKey key) {
+		subselectsByEntityKey.remove(key);
+	}
+
+	/**
+	 * Clears all pending subselect fetches from the queue.
+	 * <p/>
+	 * Called after flushing.
+	 */
+	public void clearSubselects() {
+		subselectsByEntityKey.clear();
+	}
+
+	/**
+	 * If an EntityKey represents a batch loadable entity, add
+	 * it to the queue.
+	 * <p/>
+	 * Note that the contract here is such that any key passed in should
+	 * previously have been been checked for existence within the
+	 * {@link PersistenceContext}; failure to do so may cause the
+	 * referenced entity to be included in a batch even though it is
+	 * already associated with the {@link PersistenceContext}.
+	 */
+	public void addBatchLoadableEntityKey(EntityKey key) {
+		if ( key.isBatchLoadable() ) {
+			batchLoadableEntityKeys.put( key, MARKER );
+		}
+	}
+
+	/**
+	 * After evicting or deleting or loading an entity, we don't
+	 * need to batch fetch it anymore, remove it from the queue
+	 * if necessary
+	 */
+	public void removeBatchLoadableEntityKey(EntityKey key) {
+		if ( key.isBatchLoadable() ) batchLoadableEntityKeys.remove(key);
+	}
+
+	/**
+	 * Get a batch of uninitialized collection keys for a given role
+	 *
+	 * @param collectionPersister The persister for the collection role.
+	 * @param id A key that must be included in the batch fetch
+	 * @param batchSize the maximum number of keys to return
+	 * @return an array of collection keys, of length batchSize (padded with nulls)
+	 */
+	public Serializable[] getCollectionBatch(
+			final CollectionPersister collectionPersister,
+			final Serializable id,
+			final int batchSize,
+			final EntityMode entityMode) {
+		Serializable[] keys = new Serializable[batchSize];
+		keys[0] = id;
+		int i = 1;
+		//int count = 0;
+		int end = -1;
+		boolean checkForEnd = false;
+		// this only works because collection entries are kept in a sequenced
+		// map by persistence context (maybe we should do like entities and
+		// keep a separate sequences set...)
+		Iterator iter = context.getCollectionEntries().entrySet().iterator(); //TODO: calling entrySet on an IdentityMap is SLOW!!
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+
+			CollectionEntry ce = (CollectionEntry) me.getValue();
+			PersistentCollection collection = (PersistentCollection) me.getKey();
+			if ( !collection.wasInitialized() && ce.getLoadedPersister() == collectionPersister ) {
+
+				if ( checkForEnd && i == end ) {
+					return keys; //the first key found after the given key
+				}
+
+				//if ( end == -1 && count > batchSize*10 ) return keys; //try out ten batches, max
+
+				final boolean isEqual = collectionPersister.getKeyType().isEqual(
+						id,
+						ce.getLoadedKey(),
+						entityMode,
+						collectionPersister.getFactory()
+				);
+
+				if ( isEqual ) {
+					end = i;
+					//checkForEnd = false;
+				}
+				else if ( !isCached( ce.getLoadedKey(), collectionPersister, entityMode ) ) {
+					keys[i++] = ce.getLoadedKey();
+					//count++;
+				}
+
+				if ( i == batchSize ) {
+					i = 1; //end of array, start filling again from start
+					if ( end != -1 ) {
+						checkForEnd = true;
+					}
+				}
+			}
+
+		}
+		return keys; //we ran out of keys to try
+	}
+
+	/**
+	 * Get a batch of unloaded identifiers for this class, using a slightly
+	 * complex algorithm that tries to grab keys registered immediately after
+	 * the given key.
+	 *
+	 * @param persister The persister for the entities being loaded.
+	 * @param id The identifier of the entity currently demanding load.
+	 * @param batchSize The maximum number of keys to return
+	 * @return an array of identifiers, of length batchSize (possibly padded with nulls)
+	 */
+	public Serializable[] getEntityBatch(
+			final EntityPersister persister,
+			final Serializable id,
+			final int batchSize,
+			final EntityMode entityMode) {
+		Serializable[] ids = new Serializable[batchSize];
+		ids[0] = id; //first element of array is reserved for the actual instance we are loading!
+		int i = 1;
+		int end = -1;
+		boolean checkForEnd = false;
+
+		Iterator iter = batchLoadableEntityKeys.keySet().iterator();
+		while ( iter.hasNext() ) {
+			EntityKey key = (EntityKey) iter.next();
+			if ( key.getEntityName().equals( persister.getEntityName() ) ) { //TODO: this needn't exclude subclasses...
+				if ( checkForEnd && i == end ) {
+					//the first id found after the given id
+					return ids;
+				}
+				if ( persister.getIdentifierType().isEqual( id, key.getIdentifier(), entityMode ) ) {
+					end = i;
+				}
+				else {
+					if ( !isCached( key, persister, entityMode ) ) {
+						ids[i++] = key.getIdentifier();
+					}
+				}
+				if ( i == batchSize ) {
+					i = 1; //end of array, start filling again from start
+					if (end!=-1) checkForEnd = true;
+				}
+			}
+		}
+		return ids; //we ran out of ids to try
+	}
+
+	private boolean isCached(
+			EntityKey entityKey,
+			EntityPersister persister,
+			EntityMode entityMode) {
+		if ( persister.hasCache() ) {
+			CacheKey key = new CacheKey(
+					entityKey.getIdentifier(),
+					persister.getIdentifierType(),
+					entityKey.getEntityName(),
+					entityMode,
+					context.getSession().getFactory()
+			);
+			return persister.getCacheAccessStrategy().get( key, context.getSession().getTimestamp() ) != null;
+		}
+		return false;
+	}
+
+	private boolean isCached(
+			Serializable collectionKey,
+			CollectionPersister persister,
+			EntityMode entityMode) {
+		if ( persister.hasCache() ) {
+			CacheKey cacheKey = new CacheKey(
+					collectionKey,
+			        persister.getKeyType(),
+			        persister.getRole(),
+			        entityMode,
+			        context.getSession().getFactory()
+			);
+			return persister.getCacheAccessStrategy().get( cacheKey, context.getSession().getTimestamp() ) != null;
+		}
+		return false;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/BatchFetchQueue.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Cascade.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Cascade.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Cascade.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,360 @@
+//$Id: Cascade.java 10720 2006-11-06 11:35:40Z max.andersen at jboss.com $
+package org.hibernate.engine;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.event.EventSource;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.util.CollectionHelper;
+
+/**
+ * Delegate responsible for, in conjunction with the various
+ * {@link CascadingAction actions}, implementing cascade processing.
+ *
+ * @author Gavin King
+ * @see CascadingAction
+ */
+public final class Cascade {
+
+	/**
+	 * A cascade point that occurs just after the insertion of the parent entity and
+	 * just before deletion
+	 */
+	public static final int AFTER_INSERT_BEFORE_DELETE = 1;
+	/**
+	 * A cascade point that occurs just before the insertion of the parent entity and
+	 * just after deletion
+	 */
+	public static final int BEFORE_INSERT_AFTER_DELETE = 2;
+	/**
+	 * A cascade point that occurs just after the insertion of the parent entity and
+	 * just before deletion, inside a collection
+	 */
+	public static final int AFTER_INSERT_BEFORE_DELETE_VIA_COLLECTION = 3;
+	/**
+	 * A cascade point that occurs just after update of the parent entity
+	 */
+	public static final int AFTER_UPDATE = 0;
+	/**
+	 * A cascade point that occurs just before the session is flushed
+	 */
+	public static final int BEFORE_FLUSH = 0;
+	/**
+	 * A cascade point that occurs just after eviction of the parent entity from the
+	 * session cache
+	 */
+	public static final int AFTER_EVICT = 0;
+	/**
+	 * A cascade point that occurs just after locking a transient parent entity into the
+	 * session cache
+	 */
+	public static final int BEFORE_REFRESH = 0;
+	/**
+	 * A cascade point that occurs just after refreshing a parent entity
+	 */
+	public static final int AFTER_LOCK = 0;
+	/**
+	 * A cascade point that occurs just before merging from a transient parent entity into
+	 * the object in the session cache
+	 */
+	public static final int BEFORE_MERGE = 0;
+
+
+	private static final Log log = LogFactory.getLog( Cascade.class );
+
+
+	private int cascadeTo;
+	private EventSource eventSource;
+	private CascadingAction action;
+
+	public Cascade(final CascadingAction action, final int cascadeTo, final EventSource eventSource) {
+		this.cascadeTo = cascadeTo;
+		this.eventSource = eventSource;
+		this.action = action;
+	}
+
+	/**
+	 * Cascade an action from the parent entity instance to all its children.
+	 *
+	 * @param persister The parent's entity persister
+	 * @param parent The parent reference.
+	 * @throws HibernateException
+	 */
+	public void cascade(final EntityPersister persister, final Object parent)
+	throws HibernateException {
+		cascade( persister, parent, null );
+	}
+
+	/**
+	 * Cascade an action from the parent entity instance to all its children.  This
+	 * form is typicaly called from within cascade actions.
+	 *
+	 * @param persister The parent's entity persister
+	 * @param parent The parent reference.
+	 * @param anything Anything ;)   Typically some form of cascade-local cache
+	 * which is specific to each CascadingAction type
+	 * @throws HibernateException
+	 */
+	public void cascade(final EntityPersister persister, final Object parent, final Object anything)
+			throws HibernateException {
+
+		if ( persister.hasCascades() || action.requiresNoCascadeChecking() ) { // performance opt
+			if ( log.isTraceEnabled() ) {
+				log.trace( "processing cascade " + action + " for: " + persister.getEntityName() );
+			}
+
+			Type[] types = persister.getPropertyTypes();
+			CascadeStyle[] cascadeStyles = persister.getPropertyCascadeStyles();
+			EntityMode entityMode = eventSource.getEntityMode();
+			boolean hasUninitializedLazyProperties = persister.hasUninitializedLazyProperties( parent, entityMode );
+			for ( int i=0; i<types.length; i++) {
+				CascadeStyle style = cascadeStyles[i];
+				if ( hasUninitializedLazyProperties && persister.getPropertyLaziness()[i] && ! action.performOnLazyProperty() ) {
+					//do nothing to avoid a lazy property initialization
+					continue;
+				}
+
+				if ( style.doCascade( action ) ) {
+					cascadeProperty(
+					        persister.getPropertyValue( parent, i, entityMode ),
+					        types[i],
+					        style,
+					        anything,
+					        false
+					);
+				}
+				else if ( action.requiresNoCascadeChecking() ) {
+					action.noCascade(
+							eventSource,
+							persister.getPropertyValue( parent, i, entityMode ),
+							parent,
+							persister,
+							i
+					);
+				}
+			}
+
+			if ( log.isTraceEnabled() ) {
+				log.trace( "done processing cascade " + action + " for: " + persister.getEntityName() );
+			}
+		}
+	}
+
+	/**
+	 * Cascade an action to the child or children
+	 */
+	private void cascadeProperty(
+			final Object child,
+			final Type type,
+			final CascadeStyle style,
+			final Object anything,
+			final boolean isCascadeDeleteEnabled) throws HibernateException {
+
+		if (child!=null) {
+			if ( type.isAssociationType() ) {
+				AssociationType associationType = (AssociationType) type;
+				if ( cascadeAssociationNow( associationType ) ) {
+					cascadeAssociation(
+							child,
+							type,
+							style,
+							anything,
+							isCascadeDeleteEnabled
+						);
+				}
+			}
+			else if ( type.isComponentType() ) {
+				cascadeComponent( child, (AbstractComponentType) type, anything );
+			}
+		}
+	}
+
+	private boolean cascadeAssociationNow(AssociationType associationType) {
+		return associationType.getForeignKeyDirection().cascadeNow(cascadeTo) &&
+			( eventSource.getEntityMode()!=EntityMode.DOM4J || associationType.isEmbeddedInXML() );
+	}
+
+	private void cascadeComponent(
+			final Object child,
+			final AbstractComponentType componentType,
+			final Object anything) {
+		Object[] children = componentType.getPropertyValues(child, eventSource);
+		Type[] types = componentType.getSubtypes();
+		for ( int i=0; i<types.length; i++ ) {
+			CascadeStyle componentPropertyStyle = componentType.getCascadeStyle(i);
+			if ( componentPropertyStyle.doCascade(action) ) {
+				cascadeProperty(
+						children[i],
+						types[i],
+						componentPropertyStyle,
+						anything,
+						false
+					);
+			}
+		}
+	}
+
+	private void cascadeAssociation(
+			final Object child,
+			final Type type,
+			final CascadeStyle style,
+			final Object anything,
+			final boolean isCascadeDeleteEnabled) {
+		if ( type.isEntityType() || type.isAnyType() ) {
+			cascadeToOne( child, type, style, anything, isCascadeDeleteEnabled );
+		}
+		else if ( type.isCollectionType() ) {
+			cascadeCollection( child, style, anything, (CollectionType) type );
+		}
+	}
+
+	/**
+	 * Cascade an action to a collection
+	 */
+	private void cascadeCollection(
+			final Object child,
+			final CascadeStyle style,
+			final Object anything,
+			final CollectionType type) {
+		CollectionPersister persister = eventSource.getFactory()
+				.getCollectionPersister( type.getRole() );
+		Type elemType = persister.getElementType();
+
+		final int oldCascadeTo = cascadeTo;
+		if ( cascadeTo==AFTER_INSERT_BEFORE_DELETE) {
+			cascadeTo = AFTER_INSERT_BEFORE_DELETE_VIA_COLLECTION;
+		}
+
+		//cascade to current collection elements
+		if ( elemType.isEntityType() || elemType.isAnyType() || elemType.isComponentType() ) {
+			cascadeCollectionElements(
+				child,
+				type,
+				style,
+				elemType,
+				anything,
+				persister.isCascadeDeleteEnabled()
+			);
+		}
+
+		cascadeTo = oldCascadeTo;
+	}
+
+	/**
+	 * Cascade an action to a to-one association or any type
+	 */
+	private void cascadeToOne(
+			final Object child,
+			final Type type,
+			final CascadeStyle style,
+			final Object anything,
+			final boolean isCascadeDeleteEnabled) {
+		final String entityName = type.isEntityType()
+				? ( (EntityType) type ).getAssociatedEntityName()
+				: null;
+		if ( style.reallyDoCascade(action) ) { //not really necessary, but good for consistency...
+			action.cascade(eventSource, child, entityName, anything, isCascadeDeleteEnabled);
+		}
+	}
+
+	/**
+	 * Cascade to the collection elements
+	 */
+	private void cascadeCollectionElements(
+			final Object child,
+			final CollectionType collectionType,
+			final CascadeStyle style,
+			final Type elemType,
+			final Object anything,
+			final boolean isCascadeDeleteEnabled) throws HibernateException {
+		// we can't cascade to non-embedded elements
+		boolean embeddedElements = eventSource.getEntityMode()!=EntityMode.DOM4J ||
+				( (EntityType) collectionType.getElementType( eventSource.getFactory() ) ).isEmbeddedInXML();
+		
+		boolean reallyDoCascade = style.reallyDoCascade(action) && 
+			embeddedElements && child!=CollectionType.UNFETCHED_COLLECTION;
+		
+		if ( reallyDoCascade ) {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "cascade " + action + " for collection: " + collectionType.getRole() );
+			}
+			
+			Iterator iter = action.getCascadableChildrenIterator(eventSource, collectionType, child);
+			while ( iter.hasNext() ) {
+				cascadeProperty(
+						iter.next(), 
+						elemType,
+						style, 
+						anything, 
+						isCascadeDeleteEnabled 
+					);
+			}
+			
+			if ( log.isTraceEnabled() ) {
+				log.trace( "done cascade " + action + " for collection: " + collectionType.getRole() );
+			}
+		}
+		
+		final boolean deleteOrphans = style.hasOrphanDelete() && 
+				action.deleteOrphans() && 
+				elemType.isEntityType() && 
+				child instanceof PersistentCollection; //a newly instantiated collection can't have orphans
+		
+		if ( deleteOrphans ) { // handle orphaned entities!!
+			if ( log.isTraceEnabled() ) {
+				log.trace( "deleting orphans for collection: " + collectionType.getRole() );
+			}
+			
+			// we can do the cast since orphan-delete does not apply to:
+			// 1. newly instantiated collections
+			// 2. arrays (we can't track orphans for detached arrays)
+			final String entityName = collectionType.getAssociatedEntityName( eventSource.getFactory() );
+			deleteOrphans( entityName, (PersistentCollection) child );
+			
+			if ( log.isTraceEnabled() ) {
+				log.trace( "done deleting orphans for collection: " + collectionType.getRole() );
+			}
+		}
+	}
+
+	/**
+	 * Delete any entities that were removed from the collection
+	 */
+	private void deleteOrphans(String entityName, PersistentCollection pc) throws HibernateException {
+		//TODO: suck this logic into the collection!
+		final Collection orphans;
+		if ( pc.wasInitialized() ) {
+			CollectionEntry ce = eventSource.getPersistenceContext().getCollectionEntry(pc);
+			orphans = ce==null ? 
+					CollectionHelper.EMPTY_COLLECTION :
+					ce.getOrphans(entityName, pc);
+		}
+		else {
+			orphans = pc.getQueuedOrphans(entityName);
+		}
+		
+		final Iterator orphanIter = orphans.iterator();
+		while ( orphanIter.hasNext() ) {
+			Object orphan = orphanIter.next();
+			if (orphan!=null) {
+				if ( log.isTraceEnabled() ) {
+					log.trace("deleting orphaned entity instance: " + entityName);
+				}
+				eventSource.delete( entityName, orphan, false, null );
+			}
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CascadeStyle.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CascadeStyle.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CascadeStyle.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,275 @@
+//$Id: CascadeStyle.java 10799 2006-11-13 19:34:33Z steve.ebersole at jboss.com $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hibernate.MappingException;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * A contract for defining the aspects of cascading various persistence actions.
+ *
+ * @see CascadingAction
+ *
+ * @author Gavin King
+ */
+public abstract class CascadeStyle implements Serializable {
+
+	/**
+	 * For this style, should the given action be cascaded?
+	 *
+	 * @param action The action to be checked for cascade-ability.
+	 * @return True if the action should be cascaded under this style; false otherwise.
+	 */
+	public abstract boolean doCascade(CascadingAction action);
+
+	/**
+	 * Probably more aptly named something like doCascadeToCollectionElements(); it is
+	 * however used from both the collection and to-one logic branches...
+	 * <p/>
+	 * For this style, should the given action really be cascaded?  The default
+	 * implementation is simply to return {@link #doCascade}; for certain
+	 * styles (currently only delete-orphan), however, we need to be able to
+	 * control this seperately.
+	 *
+	 * @param action The action to be checked for cascade-ability.
+	 * @return True if the action should be really cascaded under this style;
+	 * false otherwise.
+	 */
+	public boolean reallyDoCascade(CascadingAction action) {
+		return doCascade(action);
+	}
+
+	/**
+	 * Do we need to delete orphaned collection elements?
+	 *
+	 * @return True if this style need to account for orphan delete
+	 * operations; false othwerwise.
+	 */
+	public boolean hasOrphanDelete() {
+		return false;
+	}
+
+	public static final class MultipleCascadeStyle extends CascadeStyle {
+		private final CascadeStyle[] styles;
+		public MultipleCascadeStyle(CascadeStyle[] styles) {
+			this.styles = styles;
+		}
+		public boolean doCascade(CascadingAction action) {
+			for (int i=0; i<styles.length; i++) {
+				if ( styles[i].doCascade(action) ) return true;
+			}
+			return false;
+		}
+		public boolean reallyDoCascade(CascadingAction action) {
+			for (int i=0; i<styles.length; i++) {
+				if ( styles[i].reallyDoCascade(action) ) return true;
+			}
+			return false;
+		}
+		public boolean hasOrphanDelete() {
+			for (int i=0; i<styles.length; i++) {
+				if ( styles[i].hasOrphanDelete() ) return true;
+			}
+			return false;
+		}
+		public String toString() {
+			return ArrayHelper.toString(styles);
+		}
+	}
+
+	/**
+	 * save / delete / update / evict / lock / replicate / merge / persist + delete orphans
+	 */
+	public static final CascadeStyle ALL_DELETE_ORPHAN = new CascadeStyle() {
+		public boolean doCascade(CascadingAction action) {
+			return true;
+		}
+		public boolean hasOrphanDelete() {
+			return true;
+		}
+		public String toString() {
+			return "STYLE_ALL_DELETE_ORPHAN";
+		}
+	};
+
+	/**
+	 * save / delete / update / evict / lock / replicate / merge / persist
+	 */
+	public static final CascadeStyle ALL = new CascadeStyle() {
+		public boolean doCascade(CascadingAction action) {
+			return true;
+		}
+		public String toString() {
+			return "STYLE_ALL";
+		}
+	};
+
+	/**
+	 * save / update
+	 */
+	public static final CascadeStyle UPDATE = new CascadeStyle() {
+		public boolean doCascade(CascadingAction action) {
+			return action==CascadingAction.SAVE_UPDATE || action==CascadingAction.SAVE_UPDATE_COPY;
+		}
+		public String toString() {
+			return "STYLE_SAVE_UPDATE";
+		}
+	};
+
+	/**
+	 * lock
+	 */
+	public static final CascadeStyle LOCK = new CascadeStyle() {
+		public boolean doCascade(CascadingAction action) {
+			return action==CascadingAction.LOCK;
+		}
+		public String toString() {
+			return "STYLE_LOCK";
+		}
+	};
+
+	/**
+	 * refresh
+	 */
+	public static final CascadeStyle REFRESH = new CascadeStyle() {
+		public boolean doCascade(CascadingAction action) {
+			return action==CascadingAction.REFRESH;
+		}
+		public String toString() {
+			return "STYLE_REFRESH";
+		}
+	};
+
+	/**
+	 * evict
+	 */
+	public static final CascadeStyle EVICT = new CascadeStyle() {
+		public boolean doCascade(CascadingAction action) {
+			return action==CascadingAction.EVICT;
+		}
+		public String toString() {
+			return "STYLE_EVICT";
+		}
+	};
+
+	/**
+	 * replicate
+	 */
+	public static final CascadeStyle REPLICATE = new CascadeStyle() {
+		public boolean doCascade(CascadingAction action) {
+			return action==CascadingAction.REPLICATE;
+		}
+		public String toString() {
+			return "STYLE_REPLICATE";
+		}
+	};
+	/**
+	 * merge
+	 */
+	public static final CascadeStyle MERGE = new CascadeStyle() {
+		public boolean doCascade(CascadingAction action) {
+			return action==CascadingAction.MERGE;
+		}
+		public String toString() {
+			return "STYLE_MERGE";
+		}
+	};
+
+	/**
+	 * create
+	 */
+	public static final CascadeStyle PERSIST = new CascadeStyle() {
+		public boolean doCascade(CascadingAction action) {
+			return action==CascadingAction.PERSIST
+				|| action==CascadingAction.PERSIST_ON_FLUSH;
+		}
+		public String toString() {
+			return "STYLE_PERSIST";
+		}
+	};
+
+	/**
+	 * delete
+	 */
+	public static final CascadeStyle DELETE = new CascadeStyle() {
+		public boolean doCascade(CascadingAction action) {
+			return action==CascadingAction.DELETE;
+		}
+		public String toString() {
+			return "STYLE_DELETE";
+		}
+	};
+
+	/**
+	 * delete + delete orphans
+	 */
+	public static final CascadeStyle DELETE_ORPHAN = new CascadeStyle() {
+		public boolean doCascade(CascadingAction action) {
+			return action==CascadingAction.DELETE || action==CascadingAction.SAVE_UPDATE;
+		}
+		public boolean reallyDoCascade(CascadingAction action) {
+			return action==CascadingAction.DELETE;
+		}
+		public boolean hasOrphanDelete() {
+			return true;
+		}
+		public String toString() {
+			return "STYLE_DELETE_ORPHAN";
+		}
+	};
+
+	/**
+	 * no cascades
+	 */
+	public static final CascadeStyle NONE = new CascadeStyle() {
+		public boolean doCascade(CascadingAction action) {
+			return false;
+		}
+		public String toString() {
+			return "STYLE_NONE";
+		}
+	};
+
+	/**
+	 * package-protected constructor
+	 */
+	CascadeStyle() {
+	}
+
+	static final Map STYLES = new HashMap();
+
+	static {
+		STYLES.put( "all", ALL );
+		STYLES.put( "all-delete-orphan", ALL_DELETE_ORPHAN );
+		STYLES.put( "save-update", UPDATE );
+		STYLES.put( "persist", PERSIST );
+		STYLES.put( "merge", MERGE );
+		STYLES.put( "lock", LOCK );
+		STYLES.put( "refresh", REFRESH );
+		STYLES.put( "replicate", REPLICATE );
+		STYLES.put( "evict", EVICT );
+		STYLES.put( "delete", DELETE );
+		STYLES.put( "remove", DELETE ); // adds remove as a sort-of alias for delete...
+		STYLES.put( "delete-orphan", DELETE_ORPHAN );
+		STYLES.put( "none", NONE );
+	}
+
+	/**
+	 * Factory method for obtaining named cascade styles
+	 *
+	 * @param cascade The named cascade style name.
+	 * @return The appropriate CascadeStyle
+	 */
+	public static CascadeStyle getCascadeStyle(String cascade) {
+		CascadeStyle style = (CascadeStyle) STYLES.get(cascade);
+		if (style==null) {
+			throw new MappingException("Unsupported cascade style: " + cascade);
+		}
+		else {
+			return style;
+		}
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CascadeStyle.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CascadingAction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CascadingAction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CascadingAction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,438 @@
+//$Id: CascadingAction.java 10451 2006-09-05 06:53:46Z epbernard $
+package org.hibernate.engine;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.ReplicationMode;
+import org.hibernate.TransientObjectException;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.event.EventSource;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.Type;
+import org.hibernate.type.EntityType;
+
+/**
+ * A session action that may be cascaded from parent entity to its children
+ *
+ * @author Gavin King
+ */
+public abstract class CascadingAction {
+
+	private static final Log log = LogFactory.getLog( CascadingAction.class );
+
+
+	// the CascadingAction contract ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * protected constructor
+	 */
+	CascadingAction() {
+	}
+
+	/**
+	 * Cascade the action to the child object.
+	 *
+	 * @param session The session within which the cascade is occuring.
+	 * @param child The child to which cascading should be performed.
+	 * @param entityName The child's entity name
+	 * @param anything Anything ;)  Typically some form of cascade-local cache
+	 * which is specific to each CascadingAction type
+	 * @param isCascadeDeleteEnabled Are cascading deletes enabled.
+	 * @throws HibernateException
+	 */
+	public abstract void cascade(
+			EventSource session,
+			Object child,
+			String entityName,
+			Object anything,
+			boolean isCascadeDeleteEnabled) throws HibernateException;
+
+	/**
+	 * Given a collection, get an iterator of the children upon which the
+	 * current cascading action should be visited.
+	 *
+	 * @param session The session within which the cascade is occuring.
+	 * @param collectionType The mapping type of the collection.
+	 * @param collection The collection instance.
+	 * @return The children iterator.
+	 */
+	public abstract Iterator getCascadableChildrenIterator(
+			EventSource session,
+			CollectionType collectionType,
+			Object collection);
+
+	/**
+	 * Does this action potentially extrapolate to orphan deletes?
+	 *
+	 * @return True if this action can lead to deletions of orphans.
+	 */
+	public abstract boolean deleteOrphans();
+
+
+	/**
+	 * Does the specified cascading action require verification of no cascade validity?
+	 *
+	 * @return True if this action requires no-cascade verification; false otherwise.
+	 */
+	public boolean requiresNoCascadeChecking() {
+		return false;
+	}
+
+	/**
+	 * Called (in the case of {@link #requiresNoCascadeChecking} returning true) to validate
+	 * that no cascade on the given property is considered a valid semantic.
+	 *
+	 * @param session The session witin which the cascade is occurring.
+	 * @param child The property value
+	 * @param parent The property value owner
+	 * @param persister The entity persister for the owner
+	 * @param propertyIndex The index of the property within the owner.
+	 */
+	public void noCascade(EventSource session, Object child, Object parent, EntityPersister persister, int propertyIndex) {
+	}
+
+	/**
+	 * Should this action be performed (or noCascade consulted) in the case of lazy properties.
+	 */
+	public boolean performOnLazyProperty() {
+		return true;
+	}
+
+
+	// the CascadingAction implementations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * @see org.hibernate.Session#delete(Object)
+	 */
+	public static final CascadingAction DELETE = new CascadingAction() {
+		public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+		throws HibernateException {
+			if ( log.isTraceEnabled() ) {
+				log.trace("cascading to delete: " + entityName);
+			}
+			session.delete( entityName, child, isCascadeDeleteEnabled, ( Set ) anything );
+		}
+		public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
+			// delete does cascade to uninitialized collections
+			return CascadingAction.getAllElementsIterator(session, collectionType, collection);
+		}
+		public boolean deleteOrphans() {
+			// orphans should be deleted during delete
+			return true;
+		}
+		public String toString() {
+			return "ACTION_DELETE";
+		}
+	};
+
+	/**
+	 * @see org.hibernate.Session#lock(Object, LockMode)
+	 */
+	public static final CascadingAction LOCK = new CascadingAction() {
+		public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+		throws HibernateException {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "cascading to lock: " + entityName );
+			}
+			session.lock( entityName, child, LockMode.NONE/*(LockMode) anything*/ );
+		}
+		public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
+			// lock doesn't cascade to uninitialized collections
+			return getLoadedElementsIterator(session, collectionType, collection);
+		}
+		public boolean deleteOrphans() {
+			//TODO: should orphans really be deleted during lock???
+			return false;
+		}
+		public String toString() {
+			return "ACTION_LOCK";
+		}
+	};
+
+	/**
+	 * @see org.hibernate.Session#refresh(Object)
+	 */
+	public static final CascadingAction REFRESH = new CascadingAction() {
+		public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+		throws HibernateException {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "cascading to refresh: " + entityName );
+			}
+			session.refresh( child, (Map) anything );
+		}
+		public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
+			// refresh doesn't cascade to uninitialized collections
+			return getLoadedElementsIterator(session, collectionType, collection);
+		}
+		public boolean deleteOrphans() {
+			return false;
+		}
+		public String toString() {
+			return "ACTION_REFRESH";
+		}
+	};
+
+	/**
+	 * @see org.hibernate.Session#evict(Object)
+	 */
+	public static final CascadingAction EVICT = new CascadingAction() {
+		public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+		throws HibernateException {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "cascading to evict: " + entityName );
+			}
+			session.evict(child);
+		}
+		public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
+			// evicts don't cascade to uninitialized collections
+			return getLoadedElementsIterator(session, collectionType, collection);
+		}
+		public boolean deleteOrphans() {
+			return false;
+		}
+		public boolean performOnLazyProperty() {
+			return false;
+		}
+		public String toString() {
+			return "ACTION_EVICT";
+		}
+	};
+
+	/**
+	 * @see org.hibernate.Session#saveOrUpdate(Object)
+	 */
+	public static final CascadingAction SAVE_UPDATE = new CascadingAction() {
+		public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+		throws HibernateException {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "cascading to saveOrUpdate: " + entityName );
+			}
+			session.saveOrUpdate(entityName, child);
+		}
+		public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
+			// saves / updates don't cascade to uninitialized collections
+			return getLoadedElementsIterator(session, collectionType, collection);
+		}
+		public boolean deleteOrphans() {
+			// orphans should be deleted during save/update
+			return true;
+		}
+		public boolean performOnLazyProperty() {
+			return false;
+		}
+		public String toString() {
+			return "ACTION_SAVE_UPDATE";
+		}
+	};
+
+	/**
+	 * @see org.hibernate.Session#merge(Object)
+	 */
+	public static final CascadingAction MERGE = new CascadingAction() {
+		public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+		throws HibernateException {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "cascading to merge: " + entityName );
+			}
+			session.merge( entityName, child, (Map) anything );
+		}
+		public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
+			// merges don't cascade to uninitialized collections
+//			//TODO: perhaps this does need to cascade after all....
+			return getLoadedElementsIterator(session, collectionType, collection);
+		}
+		public boolean deleteOrphans() {
+			// orphans should not be deleted during merge??
+			return false;
+		}
+		public String toString() {
+			return "ACTION_MERGE";
+		}
+	};
+
+	/**
+	 * @see org.hibernate.classic.Session#saveOrUpdateCopy(Object)
+	 */
+	public static final CascadingAction SAVE_UPDATE_COPY = new CascadingAction() {
+		// for deprecated saveOrUpdateCopy()
+		public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+		throws HibernateException {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "cascading to saveOrUpdateCopy: " + entityName );
+			}
+			session.saveOrUpdateCopy( entityName, child, (Map) anything );
+		}
+		public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
+			// saves / updates don't cascade to uninitialized collections
+			return getLoadedElementsIterator(session, collectionType, collection);
+		}
+		public boolean deleteOrphans() {
+			// orphans should not be deleted during copy??
+			return false;
+		}
+		public String toString() {
+			return "ACTION_SAVE_UPDATE_COPY";
+		}
+	};
+
+	/**
+	 * @see org.hibernate.Session#persist(Object)
+	 */
+	public static final CascadingAction PERSIST = new CascadingAction() {
+		public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+		throws HibernateException {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "cascading to persist: " + entityName );
+			}
+			session.persist( entityName, child, (Map) anything );
+		}
+		public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
+			// persists don't cascade to uninitialized collections
+			return CascadingAction.getAllElementsIterator(session, collectionType, collection);
+		}
+		public boolean deleteOrphans() {
+			return false;
+		}
+		public boolean performOnLazyProperty() {
+			return false;
+		}
+		public String toString() {
+			return "ACTION_PERSIST";
+		}
+	};
+
+	/**
+	 * Execute persist during flush time
+	 *
+	 * @see org.hibernate.Session#persist(Object)
+	 */
+	public static final CascadingAction PERSIST_ON_FLUSH = new CascadingAction() {
+		public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+		throws HibernateException {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "cascading to persistOnFlush: " + entityName );
+			}
+			session.persistOnFlush( entityName, child, (Map) anything );
+		}
+		public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
+			// persists don't cascade to uninitialized collections
+			return CascadingAction.getLoadedElementsIterator(session, collectionType, collection);
+		}
+		public boolean deleteOrphans() {
+			return true;
+		}
+		public boolean requiresNoCascadeChecking() {
+			return true;
+		}
+		public void noCascade(
+				EventSource session,
+				Object child,
+				Object parent,
+				EntityPersister persister,
+				int propertyIndex) {
+			if ( child == null ) {
+				return;
+			}
+			Type type = persister.getPropertyTypes()[propertyIndex];
+			if ( type.isEntityType() ) {
+				String childEntityName = ( ( EntityType ) type ).getAssociatedEntityName( session.getFactory() );
+
+				if ( ! isInManagedState( child, session )
+						&& ! ( child instanceof HibernateProxy ) //a proxy cannot be transient and it breaks ForeignKeys.isTransient
+						&& ForeignKeys.isTransient( childEntityName, child, null, session ) ) {
+					String parentEntiytName = persister.getEntityName();
+					String propertyName = persister.getPropertyNames()[propertyIndex];
+					throw new TransientObjectException(
+							"object references an unsaved transient instance - " +
+							"save the transient instance before flushing: " +
+							parentEntiytName + "." + propertyName + " -> " + childEntityName
+					);
+
+				}
+			}
+		}
+		public boolean performOnLazyProperty() {
+			return false;
+		}
+
+		private boolean isInManagedState(Object child, EventSource session) {
+			EntityEntry entry = session.getPersistenceContext().getEntry( child );
+			return entry != null && (entry.getStatus() == Status.MANAGED || entry.getStatus() == Status.READ_ONLY);
+		}
+
+		public String toString() {
+			return "ACTION_PERSIST_ON_FLUSH";
+		}
+	};
+
+	/**
+	 * @see org.hibernate.Session#replicate(Object, org.hibernate.ReplicationMode)
+	 */
+	public static final CascadingAction REPLICATE = new CascadingAction() {
+		public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+		throws HibernateException {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "cascading to replicate: " + entityName );
+			}
+			session.replicate( entityName, child, (ReplicationMode) anything );
+		}
+		public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
+			// replicate does cascade to uninitialized collections
+			return getLoadedElementsIterator(session, collectionType, collection);
+		}
+		public boolean deleteOrphans() {
+			return false; //I suppose?
+		}
+		public String toString() {
+			return "ACTION_REPLICATE";
+		}
+	};
+
+
+	// static helper methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Given a collection, get an iterator of all its children, loading them
+	 * from the database if necessary.
+	 *
+	 * @param session The session within which the cascade is occuring.
+	 * @param collectionType The mapping type of the collection.
+	 * @param collection The collection instance.
+	 * @return The children iterator.
+	 */
+	private static Iterator getAllElementsIterator(
+			EventSource session,
+			CollectionType collectionType,
+			Object collection) {
+		return collectionType.getElementsIterator( collection, session );
+	}
+
+	/**
+	 * Iterate just the elements of the collection that are already there. Don't load
+	 * any new elements from the database.
+	 */
+	public static Iterator getLoadedElementsIterator(SessionImplementor session, CollectionType collectionType, Object collection) {
+		if ( collectionIsInitialized(collection) ) {
+			// handles arrays and newly instantiated collections
+			return collectionType.getElementsIterator(collection, session);
+		}
+		else {
+			// does not handle arrays (thats ok, cos they can't be lazy)
+			// or newly instantiated collections, so we can do the cast
+			return ( (PersistentCollection) collection ).queuedAdditionIterator();
+		}
+	}
+
+	private static boolean collectionIsInitialized(Object collection) {
+		return !(collection instanceof PersistentCollection) || ( (PersistentCollection) collection ).wasInitialized();
+	}
+
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CascadingAction.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CollectionEntry.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CollectionEntry.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CollectionEntry.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,397 @@
+//$Id: CollectionEntry.java 9551 2006-03-04 03:49:55Z steve.ebersole at jboss.com $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Collection;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.pretty.MessageHelper;
+
+/**
+ * We need an entry to tell us all about the current state
+ * of a collection with respect to its persistent state
+ * 
+ * @author Gavin King
+ */
+public final class CollectionEntry implements Serializable {
+
+	private static final Log log = LogFactory.getLog(CollectionEntry.class);
+	
+	//ATTRIBUTES MAINTAINED BETWEEN FLUSH CYCLES
+	
+	// session-start/post-flush persistent state
+	private Serializable snapshot;
+	// allow the CollectionSnapshot to be serialized
+	private String role;
+	
+	// "loaded" means the reference that is consistent 
+	// with the current database state
+	private transient CollectionPersister loadedPersister;
+	private Serializable loadedKey;
+
+	// ATTRIBUTES USED ONLY DURING FLUSH CYCLE
+	
+	// during flush, we navigate the object graph to
+	// collections and decide what to do with them
+	private transient boolean reached;
+	private transient boolean processed;
+	private transient boolean doupdate;
+	private transient boolean doremove;
+	private transient boolean dorecreate;
+	// if we instantiate a collection during the flush() process,
+	// we must ignore it for the rest of the flush()
+	private transient boolean ignore;
+	
+	// "current" means the reference that was found during flush() 
+	private transient CollectionPersister currentPersister;
+	private transient Serializable currentKey;
+
+	/**
+	 * For newly wrapped collections, or dereferenced collection wrappers
+	 */
+	public CollectionEntry(CollectionPersister persister, PersistentCollection collection) {
+		// new collections that get found + wrapped
+		// during flush shouldn't be ignored
+		ignore = false;
+
+		collection.clearDirty(); //a newly wrapped collection is NOT dirty (or we get unnecessary version updates)
+		
+		snapshot = persister.isMutable() ?
+				collection.getSnapshot(persister) :
+				null;
+		collection.setSnapshot(loadedKey, role, snapshot);
+	}
+
+	/**
+	 * For collections just loaded from the database
+	 */
+	public CollectionEntry(
+			final PersistentCollection collection, 
+			final CollectionPersister loadedPersister, 
+			final Serializable loadedKey, 
+			final boolean ignore
+	) {
+		this.ignore=ignore;
+
+		//collection.clearDirty()
+		
+		this.loadedKey = loadedKey;
+		setLoadedPersister(loadedPersister);
+
+		collection.setSnapshot(loadedKey, role, null);
+
+		//postInitialize() will be called after initialization
+	}
+
+	/**
+	 * For uninitialized detached collections
+	 */
+	public CollectionEntry(CollectionPersister loadedPersister, Serializable loadedKey) {
+		// detached collection wrappers that get found + reattached
+		// during flush shouldn't be ignored
+		ignore = false;
+
+		//collection.clearDirty()
+		
+		this.loadedKey = loadedKey;
+		setLoadedPersister(loadedPersister);
+	}
+	
+	/**
+	 * For initialized detached collections
+	 */
+	CollectionEntry(PersistentCollection collection, SessionFactoryImplementor factory)
+	throws MappingException {
+		// detached collections that get found + reattached
+		// during flush shouldn't be ignored
+		ignore = false;
+
+		loadedKey = collection.getKey();
+		setLoadedPersister( factory.getCollectionPersister( collection.getRole() ) );
+
+		snapshot = collection.getStoredSnapshot();		
+	}
+
+	/**
+	 * Used from custom serialization.
+	 *
+	 * @see #serialize
+	 * @see #deserialize
+	 */
+	private CollectionEntry(
+			String role,
+	        Serializable snapshot,
+	        Serializable loadedKey,
+	        SessionFactoryImplementor factory) {
+		this.role = role;
+		this.snapshot = snapshot;
+		this.loadedKey = loadedKey;
+		if ( role != null ) {
+			afterDeserialize( factory );
+		}
+	}
+
+	/**
+	 * Determine if the collection is "really" dirty, by checking dirtiness
+	 * of the collection elements, if necessary
+	 */
+	private void dirty(PersistentCollection collection) throws HibernateException {
+		
+		boolean forceDirty = collection.wasInitialized() &&
+				!collection.isDirty() && //optimization
+				getLoadedPersister() != null &&
+				getLoadedPersister().isMutable() && //optimization
+				( collection.isDirectlyAccessible() || getLoadedPersister().getElementType().isMutable() ) && //optimization
+				!collection.equalsSnapshot( getLoadedPersister() );
+		
+		if ( forceDirty ) {
+			collection.dirty();
+		}
+		
+	}
+
+	public void preFlush(PersistentCollection collection) throws HibernateException {
+		
+		boolean nonMutableChange = collection.isDirty() && 
+				getLoadedPersister()!=null && 
+				!getLoadedPersister().isMutable();
+		if (nonMutableChange) {
+			throw new HibernateException(
+					"changed an immutable collection instance: " + 
+					MessageHelper.collectionInfoString( getLoadedPersister().getRole(), getLoadedKey() )
+				);
+		}
+		
+		dirty(collection);
+		
+		if ( log.isDebugEnabled() && collection.isDirty() && getLoadedPersister() != null ) {
+			log.debug(
+					"Collection dirty: " +
+					MessageHelper.collectionInfoString( getLoadedPersister().getRole(), getLoadedKey() )
+				);
+		}
+
+		setDoupdate(false);
+		setDoremove(false);
+		setDorecreate(false);
+		setReached(false);
+		setProcessed(false);
+	}
+
+	public void postInitialize(PersistentCollection collection) throws HibernateException {
+		snapshot = getLoadedPersister().isMutable() ?
+				collection.getSnapshot( getLoadedPersister() ) :
+				null;
+		collection.setSnapshot(loadedKey, role, snapshot);
+	}
+
+	/**
+	 * Called after a successful flush
+	 */
+	public void postFlush(PersistentCollection collection) throws HibernateException {
+		if ( isIgnore() ) {
+			ignore = false;
+		}
+		else if ( !isProcessed() ) {
+			throw new AssertionFailure( "collection [" + collection.getRole() + "] was not processed by flush()" );
+		}
+		collection.setSnapshot(loadedKey, role, snapshot);
+	}
+	
+	/**
+	 * Called after execution of an action
+	 */
+	public void afterAction(PersistentCollection collection) {
+		loadedKey = getCurrentKey();
+		setLoadedPersister( getCurrentPersister() );
+		
+		boolean resnapshot = collection.wasInitialized() && 
+				( isDoremove() || isDorecreate() || isDoupdate() );
+		if ( resnapshot ) {
+			snapshot = loadedPersister==null || !loadedPersister.isMutable() ? 
+					null : 
+					collection.getSnapshot(loadedPersister); //re-snapshot
+		}
+		
+		collection.postAction();
+	}
+
+	public Serializable getKey() {
+		return getLoadedKey();
+	}
+
+	public String getRole() {
+		return role;
+	}
+
+	public Serializable getSnapshot() {
+		return snapshot;
+	}
+
+	private void setLoadedPersister(CollectionPersister persister) {
+		loadedPersister = persister;
+		setRole( persister == null ? null : persister.getRole() );
+	}
+	
+	void afterDeserialize(SessionFactoryImplementor factory) {
+		loadedPersister = factory.getCollectionPersister(role);
+	}
+
+	public boolean wasDereferenced() {
+		return getLoadedKey() == null;
+	}
+
+	public boolean isReached() {
+		return reached;
+	}
+
+	public void setReached(boolean reached) {
+		this.reached = reached;
+	}
+
+	public boolean isProcessed() {
+		return processed;
+	}
+
+	public void setProcessed(boolean processed) {
+		this.processed = processed;
+	}
+
+	public boolean isDoupdate() {
+		return doupdate;
+	}
+
+	public void setDoupdate(boolean doupdate) {
+		this.doupdate = doupdate;
+	}
+
+	public boolean isDoremove() {
+		return doremove;
+	}
+
+	public void setDoremove(boolean doremove) {
+		this.doremove = doremove;
+	}
+
+	public boolean isDorecreate() {
+		return dorecreate;
+	}
+
+	public void setDorecreate(boolean dorecreate) {
+		this.dorecreate = dorecreate;
+	}
+
+	public boolean isIgnore() {
+		return ignore;
+	}
+
+	public CollectionPersister getCurrentPersister() {
+		return currentPersister;
+	}
+
+	public void setCurrentPersister(CollectionPersister currentPersister) {
+		this.currentPersister = currentPersister;
+	}
+
+	/**
+	 * This is only available late during the flush
+	 * cycle
+	 */
+	public Serializable getCurrentKey() {
+		return currentKey;
+	}
+
+	public void setCurrentKey(Serializable currentKey) {
+		this.currentKey = currentKey;
+	}
+	
+	/**
+	 * This is only available late during the flush cycle
+	 */
+	public CollectionPersister getLoadedPersister() {
+		return loadedPersister;
+	}
+
+	public Serializable getLoadedKey() {
+		return loadedKey;
+	}
+
+	public void setRole(String role) {
+		this.role = role;
+	}
+
+	public String toString() {
+		String result = "CollectionEntry" + 
+				MessageHelper.collectionInfoString( loadedPersister.getRole(), loadedKey );
+		if (currentPersister!=null) {
+			result += "->" + 
+					MessageHelper.collectionInfoString( currentPersister.getRole(), currentKey );
+		}
+		return result;
+	}
+
+	/**
+	 * Get the collection orphans (entities which were removed from the collection)
+	 */
+	public Collection getOrphans(String entityName, PersistentCollection collection) 
+	throws HibernateException {
+		if (snapshot==null) {
+			throw new AssertionFailure("no collection snapshot for orphan delete");
+		}
+		return collection.getOrphans( snapshot, entityName );
+	}
+
+	public boolean isSnapshotEmpty(PersistentCollection collection) {
+		//TODO: does this really need to be here?
+		//      does the collection already have
+		//      it's own up-to-date snapshot?
+		return collection.wasInitialized() && 
+			( getLoadedPersister()==null || getLoadedPersister().isMutable() ) &&
+			collection.isSnapshotEmpty( getSnapshot() );
+	}
+
+
+
+	/**
+	 * Custom serialization routine used during serialization of a
+	 * Session/PersistenceContext for increased performance.
+	 *
+	 * @param oos The stream to which we should write the serial data.
+	 * @throws java.io.IOException
+	 */
+	void serialize(ObjectOutputStream oos) throws IOException {
+		oos.writeObject( role );
+		oos.writeObject( snapshot );
+		oos.writeObject( loadedKey );
+	}
+
+	/**
+	 * Custom deserialization routine used during deserialization of a
+	 * Session/PersistenceContext for increased performance.
+	 *
+	 * @param ois The stream from which to read the entry.
+	 * @param session The session being deserialized.
+	 * @return The deserialized CollectionEntry
+	 * @throws IOException
+	 * @throws ClassNotFoundException
+	 */
+	static CollectionEntry deserialize(
+			ObjectInputStream ois,
+	        SessionImplementor session) throws IOException, ClassNotFoundException {
+		return new CollectionEntry(
+				( String ) ois.readObject(),
+		        ( Serializable ) ois.readObject(),
+		        ( Serializable ) ois.readObject(),
+		        session.getFactory()
+		);
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CollectionKey.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CollectionKey.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/CollectionKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,113 @@
+//$Id: CollectionKey.java 9194 2006-02-01 19:59:07Z steveebersole $
+package org.hibernate.engine;
+
+import org.hibernate.EntityMode;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.type.Type;
+
+
+
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+
+/**
+ * Uniquely identifies a collection instance in a particular session.
+ *
+ * @author Gavin King
+ */
+public final class CollectionKey implements Serializable {
+
+	private final String role;
+	private final Serializable key;
+	private final Type keyType;
+	private final SessionFactoryImplementor factory;
+	private final int hashCode;
+	private EntityMode entityMode;
+
+	public CollectionKey(CollectionPersister persister, Serializable key, EntityMode em) {
+		this( persister.getRole(), key, persister.getKeyType(), em, persister.getFactory() );
+	}
+
+	private CollectionKey(
+			String role,
+	        Serializable key,
+	        Type keyType,
+	        EntityMode entityMode,
+	        SessionFactoryImplementor factory) {
+		this.role = role;
+		this.key = key;
+		this.keyType = keyType;
+		this.entityMode = entityMode;
+		this.factory = factory;
+		this.hashCode = generateHashCode(); //cache the hashcode
+	}
+
+	public boolean equals(Object other) {
+		CollectionKey that = (CollectionKey) other;
+		return that.role.equals(role) &&
+		       keyType.isEqual(that.key, key, entityMode, factory);
+	}
+
+	public int generateHashCode() {
+		int result = 17;
+		result = 37 * result + role.hashCode();
+		result = 37 * result + keyType.getHashCode(key, entityMode, factory);
+		return result;
+	}
+
+	public int hashCode() {
+		return hashCode;
+	}
+
+	public String getRole() {
+		return role;
+	}
+
+	public Serializable getKey() {
+		return key;
+	}
+
+	public String toString() {
+		return "CollectionKey" +
+		       MessageHelper.collectionInfoString( factory.getCollectionPersister(role), key, factory );
+	}
+
+	/**
+	 * Custom serialization routine used during serialization of a
+	 * Session/PersistenceContext for increased performance.
+	 *
+	 * @param oos The stream to which we should write the serial data.
+	 * @throws java.io.IOException
+	 */
+	void serialize(ObjectOutputStream oos) throws IOException {
+		oos.writeObject( role );
+		oos.writeObject( key );
+		oos.writeObject( keyType );
+		oos.writeObject( entityMode.toString() );
+	}
+
+	/**
+	 * Custom deserialization routine used during deserialization of a
+	 * Session/PersistenceContext for increased performance.
+	 *
+	 * @param ois The stream from which to read the entry.
+	 * @param session The session being deserialized.
+	 * @return The deserialized CollectionKey
+	 * @throws IOException
+	 * @throws ClassNotFoundException
+	 */
+	static CollectionKey deserialize(
+			ObjectInputStream ois,
+	        SessionImplementor session) throws IOException, ClassNotFoundException {
+		return new CollectionKey(
+				( String ) ois.readObject(),
+		        ( Serializable ) ois.readObject(),
+		        ( Type ) ois.readObject(),
+		        EntityMode.parse( ( String ) ois.readObject() ),
+		        session.getFactory()
+		);
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Collections.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Collections.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Collections.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,254 @@
+//$Id: Collections.java 8694 2005-11-28 19:28:17Z steveebersole $
+package org.hibernate.engine;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.type.CollectionType;
+
+import java.io.Serializable;
+
+/**
+ * Implements book-keeping for the collection persistence by reachability algorithm
+ * @author Gavin King
+ */
+public final class Collections {
+
+	private Collections() {}
+
+	private static final Log log = LogFactory.getLog(Collections.class);
+
+	/**
+	 * record the fact that this collection was dereferenced
+	 *
+	 * @param coll The collection to be updated by unreachability.
+	 * @throws HibernateException
+	 */
+	public static void processUnreachableCollection(PersistentCollection coll, SessionImplementor session)
+	throws HibernateException {
+
+		if ( coll.getOwner()==null ) {
+			processNeverReferencedCollection(coll, session);
+		}
+		else {
+			processDereferencedCollection(coll, session);
+		}
+
+	}
+
+	private static void processDereferencedCollection(PersistentCollection coll, SessionImplementor session)
+	throws HibernateException {
+
+		final PersistenceContext persistenceContext = session.getPersistenceContext();
+		CollectionEntry entry = persistenceContext.getCollectionEntry(coll);
+		final CollectionPersister loadedPersister = entry.getLoadedPersister();
+
+		if ( log.isDebugEnabled() && loadedPersister != null )
+			log.debug(
+					"Collection dereferenced: " +
+					MessageHelper.collectionInfoString(
+							loadedPersister,
+					        entry.getLoadedKey(),
+					        session.getFactory()
+						)
+				);
+
+		// do a check
+		boolean hasOrphanDelete = loadedPersister != null &&
+		                          loadedPersister.hasOrphanDelete();
+		if (hasOrphanDelete) {
+			Serializable ownerId = loadedPersister.getOwnerEntityPersister()
+					.getIdentifier( coll.getOwner(), session.getEntityMode() );
+			if ( ownerId == null ) {
+				// the owning entity may have been deleted and its identifier unset due to
+				// identifier-rollback; in which case, try to look up its identifier from
+				// the persistence context
+				if ( session.getFactory().getSettings().isIdentifierRollbackEnabled() ) {
+					EntityEntry ownerEntry = persistenceContext.getEntry( coll.getOwner() );
+					if ( ownerEntry != null ) {
+						ownerId = ownerEntry.getId();
+					}
+				}
+				if ( ownerId == null ) {
+					throw new AssertionFailure( "Unable to determine collection owner identifier for orphan-delete processing" );
+				}
+			}
+			EntityKey key = new EntityKey(
+					ownerId,
+			        loadedPersister.getOwnerEntityPersister(),
+			        session.getEntityMode()
+			);
+			Object owner = persistenceContext.getEntity(key);
+			if ( owner == null ) {
+				throw new AssertionFailure(
+						"collection owner not associated with session: " +
+						loadedPersister.getRole()
+				);
+			}
+			EntityEntry e = persistenceContext.getEntry(owner);
+			//only collections belonging to deleted entities are allowed to be dereferenced in the case of orphan delete
+			if ( e != null && e.getStatus() != Status.DELETED && e.getStatus() != Status.GONE ) {
+				throw new HibernateException(
+						"A collection with cascade=\"all-delete-orphan\" was no longer referenced by the owning entity instance: " +
+						loadedPersister.getRole()
+				);
+			}
+		}
+
+		// do the work
+		entry.setCurrentPersister(null);
+		entry.setCurrentKey(null);
+		prepareCollectionForUpdate( coll, entry, session.getEntityMode(), session.getFactory() );
+
+	}
+
+	private static void processNeverReferencedCollection(PersistentCollection coll, SessionImplementor session)
+	throws HibernateException {
+
+		final PersistenceContext persistenceContext = session.getPersistenceContext();
+		CollectionEntry entry = persistenceContext.getCollectionEntry(coll);
+
+		log.debug(
+				"Found collection with unloaded owner: " +
+				MessageHelper.collectionInfoString(
+						entry.getLoadedPersister(),
+				        entry.getLoadedKey(),
+				        session.getFactory()
+				)
+		);
+
+		entry.setCurrentPersister( entry.getLoadedPersister() );
+		entry.setCurrentKey( entry.getLoadedKey() );
+
+		prepareCollectionForUpdate( coll, entry, session.getEntityMode(), session.getFactory() );
+
+	}
+
+	/**
+	 * Initialize the role of the collection.
+	 *
+	 * @param collection The collection to be updated by reachibility.
+	 * @param type The type of the collection.
+	 * @param entity The owner of the collection.
+	 * @throws HibernateException
+	 */
+	public static void processReachableCollection(
+			PersistentCollection collection,
+	        CollectionType type,
+	        Object entity,
+	        SessionImplementor session)
+	throws HibernateException {
+
+		collection.setOwner(entity);
+
+		CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(collection);
+
+		if ( ce == null ) {
+			// refer to comment in StatefulPersistenceContext.addCollection()
+			throw new HibernateException(
+					"Found two representations of same collection: " +
+					type.getRole()
+			);
+		}
+
+		// The CollectionEntry.isReached() stuff is just to detect any silly users  
+		// who set up circular or shared references between/to collections.
+		if ( ce.isReached() ) {
+			// We've been here before
+			throw new HibernateException(
+					"Found shared references to a collection: " +
+					type.getRole()
+			);
+		}
+		ce.setReached(true);
+
+		SessionFactoryImplementor factory = session.getFactory();
+		CollectionPersister persister = factory.getCollectionPersister( type.getRole() );
+		ce.setCurrentPersister(persister);
+		ce.setCurrentKey( type.getKeyOfOwner(entity, session) ); //TODO: better to pass the id in as an argument?
+
+		if ( log.isDebugEnabled() ) {
+			log.debug(
+					"Collection found: " +
+					MessageHelper.collectionInfoString( persister, ce.getCurrentKey(), factory ) +
+					", was: " +
+					MessageHelper.collectionInfoString( ce.getLoadedPersister(), ce.getLoadedKey(), factory ) +
+					( collection.wasInitialized() ? " (initialized)" : " (uninitialized)" )
+			);
+		}
+
+		prepareCollectionForUpdate( collection, ce, session.getEntityMode(), factory );
+
+	}
+
+	/**
+	 * 1. record the collection role that this collection is referenced by
+	 * 2. decide if the collection needs deleting/creating/updating (but
+	 *	don't actually schedule the action yet)
+	 */
+	private static void prepareCollectionForUpdate(
+			PersistentCollection collection,
+	        CollectionEntry entry,
+	        EntityMode entityMode,
+	        SessionFactoryImplementor factory)
+	throws HibernateException {
+
+		if ( entry.isProcessed() ) {
+			throw new AssertionFailure( "collection was processed twice by flush()" );
+		}
+		entry.setProcessed(true);
+
+		final CollectionPersister loadedPersister = entry.getLoadedPersister();
+		final CollectionPersister currentPersister = entry.getCurrentPersister();
+		if ( loadedPersister != null || currentPersister != null ) {					// it is or was referenced _somewhere_
+
+			boolean ownerChanged = loadedPersister != currentPersister ||				// if either its role changed,
+			                       !currentPersister
+					                       .getKeyType().isEqual(                       // or its key changed
+													entry.getLoadedKey(),
+			                                        entry.getCurrentKey(),
+			                                        entityMode, factory
+			                       );
+
+			if (ownerChanged) {
+
+				// do a check
+				final boolean orphanDeleteAndRoleChanged = loadedPersister != null &&
+				                                           currentPersister != null &&
+				                                           loadedPersister.hasOrphanDelete();
+
+				if (orphanDeleteAndRoleChanged) {
+					throw new HibernateException(
+							"Don't change the reference to a collection with cascade=\"all-delete-orphan\": " +
+							loadedPersister.getRole()
+						);
+				}
+
+				// do the work
+				if ( currentPersister != null ) {
+					entry.setDorecreate(true);											// we will need to create new entries
+				}
+
+				if ( loadedPersister != null ) {
+					entry.setDoremove(true);											// we will need to remove ye olde entries
+					if ( entry.isDorecreate() ) {
+						log.trace( "Forcing collection initialization" );
+						collection.forceInitialization();								// force initialize!
+					}
+				}
+
+			}
+			else if ( collection.isDirty() ) {											// else if it's elements changed
+				entry.setDoupdate(true);
+			}
+
+		}
+
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Collections.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/EntityEntry.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/EntityEntry.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/EntityEntry.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,316 @@
+//$Id: EntityEntry.java 9283 2006-02-14 03:24:18Z steveebersole $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.UniqueKeyLoadable;
+import org.hibernate.pretty.MessageHelper;
+
+/**
+ * We need an entry to tell us all about the current state
+ * of an object with respect to its persistent state
+ * 
+ * @author Gavin King
+ */
+public final class EntityEntry implements Serializable {
+
+	private LockMode lockMode;
+	private Status status;
+	private final Serializable id;
+	private Object[] loadedState;
+	private Object[] deletedState;
+	private boolean existsInDatabase;
+	private Object version;
+	private transient EntityPersister persister; // for convenience to save some lookups
+	private final EntityMode entityMode;
+	private final String entityName;
+	private boolean isBeingReplicated;
+	private boolean loadedWithLazyPropertiesUnfetched; //NOTE: this is not updated when properties are fetched lazily!
+	private final transient Object rowId;
+
+	EntityEntry(
+			final Status status,
+			final Object[] loadedState,
+			final Object rowId,
+			final Serializable id,
+			final Object version,
+			final LockMode lockMode,
+			final boolean existsInDatabase,
+			final EntityPersister persister,
+			final EntityMode entityMode,
+			final boolean disableVersionIncrement,
+			final boolean lazyPropertiesAreUnfetched) {
+		this.status=status;
+		this.loadedState=loadedState;
+		this.id=id;
+		this.rowId=rowId;
+		this.existsInDatabase=existsInDatabase;
+		this.version=version;
+		this.lockMode=lockMode;
+		this.isBeingReplicated=disableVersionIncrement;
+		this.loadedWithLazyPropertiesUnfetched = lazyPropertiesAreUnfetched;
+		this.persister=persister;
+		this.entityMode = entityMode;
+		this.entityName = persister == null ?
+				null : persister.getEntityName();
+	}
+
+	/**
+	 * Used during custom deserialization
+	 */
+	private EntityEntry(
+			final SessionFactoryImplementor factory,
+			final String entityName,
+			final Serializable id,
+			final EntityMode entityMode,
+			final Status status,
+			final Object[] loadedState,
+	        final Object[] deletedState,
+			final Object version,
+			final LockMode lockMode,
+			final boolean existsInDatabase,
+			final boolean isBeingReplicated,
+			final boolean loadedWithLazyPropertiesUnfetched) {
+		this.entityName = entityName;
+		this.persister = factory.getEntityPersister( entityName );
+		this.id = id;
+		this.entityMode = entityMode;
+		this.status = status;
+		this.loadedState = loadedState;
+		this.deletedState = deletedState;
+		this.version = version;
+		this.lockMode = lockMode;
+		this.existsInDatabase = existsInDatabase;
+		this.isBeingReplicated = isBeingReplicated;
+		this.loadedWithLazyPropertiesUnfetched = loadedWithLazyPropertiesUnfetched;
+		this.rowId = null; // this is equivalent to the old behavior...
+	}
+
+	public LockMode getLockMode() {
+		return lockMode;
+	}
+
+	public void setLockMode(LockMode lockMode) {
+		this.lockMode = lockMode;
+	}
+
+	public Status getStatus() {
+		return status;
+	}
+
+	public void setStatus(Status status) {
+		if (status==Status.READ_ONLY) {
+			loadedState = null; //memory optimization
+		}
+		this.status = status;
+	}
+
+	public Serializable getId() {
+		return id;
+	}
+
+	public Object[] getLoadedState() {
+		return loadedState;
+	}
+
+	public Object[] getDeletedState() {
+		return deletedState;
+	}
+
+	public void setDeletedState(Object[] deletedState) {
+		this.deletedState = deletedState;
+	}
+
+	public boolean isExistsInDatabase() {
+		return existsInDatabase;
+	}
+
+	public Object getVersion() {
+		return version;
+	}
+
+	public EntityPersister getPersister() {
+		return persister;
+	}
+
+	void afterDeserialize(SessionFactoryImplementor factory) {
+		persister = factory.getEntityPersister( entityName );
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public boolean isBeingReplicated() {
+		return isBeingReplicated;
+	}
+	
+	public Object getRowId() {
+		return rowId;
+	}
+	
+	/**
+	 * After actually updating the database, update the snapshot information,
+	 * and escalate the lock mode
+	 */
+	public void postUpdate(Object entity, Object[] updatedState, Object nextVersion) {
+		this.loadedState = updatedState;
+		
+		setLockMode(LockMode.WRITE);
+		
+		if ( getPersister().isVersioned() ) {
+			this.version = nextVersion;
+			getPersister().setPropertyValue( 
+					entity, 
+					getPersister().getVersionProperty(), 
+					nextVersion, 
+					entityMode 
+				);
+		}
+		
+		FieldInterceptionHelper.clearDirty( entity );
+	}
+
+	/**
+	 * After actually deleting a row, record the fact that the instance no longer
+	 * exists in the database
+	 */
+	public void postDelete() {
+		status = Status.GONE;
+		existsInDatabase = false;
+	}
+	
+	/**
+	 * After actually inserting a row, record the fact that the instance exists on the 
+	 * database (needed for identity-column key generation)
+	 */
+	public void postInsert() {
+		existsInDatabase = true;
+	}
+	
+	public boolean isNullifiable(boolean earlyInsert, SessionImplementor session) {
+		return getStatus() == Status.SAVING || (
+				earlyInsert ?
+						!isExistsInDatabase() :
+						session.getPersistenceContext().getNullifiableEntityKeys()
+							.contains( new EntityKey( getId(), getPersister(), entityMode ) )
+				);
+	}
+	
+	public Object getLoadedValue(String propertyName) {
+		int propertyIndex = ( (UniqueKeyLoadable) persister ).getPropertyIndex(propertyName);
+		return loadedState[propertyIndex];
+	}
+	
+	
+	public boolean requiresDirtyCheck(Object entity) {
+		
+		boolean isMutableInstance = 
+				status != Status.READ_ONLY && 
+				persister.isMutable();
+		
+		return isMutableInstance && (
+				getPersister().hasMutableProperties() ||
+				!FieldInterceptionHelper.isInstrumented( entity ) ||
+				FieldInterceptionHelper.extractFieldInterceptor( entity).isDirty()
+			);
+		
+	}
+
+	public void forceLocked(Object entity, Object nextVersion) {
+		version = nextVersion;
+		loadedState[ persister.getVersionProperty() ] = version;
+		setLockMode( LockMode.FORCE );
+		persister.setPropertyValue(
+				entity,
+		        getPersister().getVersionProperty(),
+		        nextVersion,
+		        entityMode
+		);
+	}
+
+	public void setReadOnly(boolean readOnly, Object entity) {
+		if (status!=Status.MANAGED && status!=Status.READ_ONLY) {
+			throw new HibernateException("instance was not in a valid state");
+		}
+		if (readOnly) {
+			setStatus(Status.READ_ONLY);
+			loadedState = null;
+		}
+		else {
+			setStatus(Status.MANAGED);
+			loadedState = getPersister().getPropertyValues(entity, entityMode);
+		}
+	}
+	
+	public String toString() {
+		return "EntityEntry" + 
+				MessageHelper.infoString(entityName, id) + 
+				'(' + status + ')';
+	}
+
+	public boolean isLoadedWithLazyPropertiesUnfetched() {
+		return loadedWithLazyPropertiesUnfetched;
+	}
+
+
+	/**
+	 * Custom serialization routine used during serialization of a
+	 * Session/PersistenceContext for increased performance.
+	 *
+	 * @param oos The stream to which we should write the serial data.
+	 * @throws java.io.IOException
+	 */
+	void serialize(ObjectOutputStream oos) throws IOException {
+		oos.writeObject( entityName );
+		oos.writeObject( id );
+		oos.writeObject( entityMode.toString() );
+		oos.writeObject( status.toString() );
+		// todo : potentially look at optimizing these two arrays
+		oos.writeObject( loadedState );
+		oos.writeObject( deletedState );
+		oos.writeObject( version );
+		oos.writeObject( lockMode.toString() );
+		oos.writeBoolean( existsInDatabase );
+		oos.writeBoolean( isBeingReplicated );
+		oos.writeBoolean( loadedWithLazyPropertiesUnfetched );
+	}
+
+	/**
+	 * Custom deserialization routine used during deserialization of a
+	 * Session/PersistenceContext for increased performance.
+	 *
+	 * @param ois The stream from which to read the entry.
+	 * @param session The session being deserialized.
+	 * @return The deserialized EntityEntry
+	 * @throws IOException
+	 * @throws ClassNotFoundException
+	 */
+	static EntityEntry deserialize(
+			ObjectInputStream ois,
+	        SessionImplementor session) throws IOException, ClassNotFoundException {
+		return new EntityEntry(
+				session.getFactory(),
+		        ( String ) ois.readObject(),
+				( Serializable ) ois.readObject(),
+	            EntityMode.parse( ( String ) ois.readObject() ),
+				Status.parse( ( String ) ois.readObject() ),
+	            ( Object[] ) ois.readObject(),
+	            ( Object[] ) ois.readObject(),
+	            ( Object ) ois.readObject(),
+	            LockMode.parse( ( String ) ois.readObject() ),
+	            ois.readBoolean(),
+	            ois.readBoolean(),
+	            ois.readBoolean()
+		);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/EntityKey.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/EntityKey.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/EntityKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,156 @@
+//$Id: EntityKey.java 9194 2006-02-01 19:59:07Z steveebersole $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.EntityMode;
+import org.hibernate.util.SerializationHelper;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.type.Type;
+
+/**
+ * Uniquely identifies of an entity instance in a particular session by identifier.
+ * <p/>
+ * Uniqueing information consists of the entity-name and the identifier value.
+ *
+ * @see EntityUniqueKey
+ * @author Gavin King
+ */
+public final class EntityKey implements Serializable {
+	private final Serializable identifier;
+	private final String rootEntityName;
+	private final String entityName;
+	private final Type identifierType;
+	private final boolean isBatchLoadable;
+	private final SessionFactoryImplementor factory;
+	private final int hashCode;
+	private final EntityMode entityMode;
+
+	/**
+	 * Construct a unique identifier for an entity class instance
+	 */
+	public EntityKey(Serializable id, EntityPersister persister, EntityMode entityMode) {
+		if ( id == null ) {
+			throw new AssertionFailure( "null identifier" );
+		}
+		this.identifier = id; 
+		this.entityMode = entityMode;
+		this.rootEntityName = persister.getRootEntityName();
+		this.entityName = persister.getEntityName();
+		this.identifierType = persister.getIdentifierType();
+		this.isBatchLoadable = persister.isBatchLoadable();
+		this.factory = persister.getFactory();
+		hashCode = generateHashCode(); //cache the hashcode
+	}
+
+	/**
+	 * Used to reconstruct an EntityKey during deserialization.
+	 *
+	 * @param identifier The identifier value
+	 * @param rootEntityName The root entity name
+	 * @param entityName The specific entity name
+	 * @param identifierType The type of the identifier value
+	 * @param batchLoadable Whether represented entity is eligible for batch loading
+	 * @param factory The session factory
+	 * @param entityMode The entity's entity mode
+	 */
+	private EntityKey(
+			Serializable identifier,
+	        String rootEntityName,
+	        String entityName,
+	        Type identifierType,
+	        boolean batchLoadable,
+	        SessionFactoryImplementor factory,
+	        EntityMode entityMode) {
+		this.identifier = identifier;
+		this.rootEntityName = rootEntityName;
+		this.entityName = entityName;
+		this.identifierType = identifierType;
+		this.isBatchLoadable = batchLoadable;
+		this.factory = factory;
+		this.entityMode = entityMode;
+		this.hashCode = generateHashCode();
+	}
+
+	public boolean isBatchLoadable() {
+		return isBatchLoadable;
+	}
+
+	/**
+	 * Get the user-visible identifier
+	 */
+	public Serializable getIdentifier() {
+		return identifier;
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public boolean equals(Object other) {
+		EntityKey otherKey = (EntityKey) other;
+		return otherKey.rootEntityName.equals(this.rootEntityName) && 
+			identifierType.isEqual(otherKey.identifier, this.identifier, entityMode, factory);
+	}
+	
+	private int generateHashCode() {
+		int result = 17;
+		result = 37 * result + rootEntityName.hashCode();
+		result = 37 * result + identifierType.getHashCode( identifier, entityMode, factory );
+		return result;
+	}
+
+	public int hashCode() {
+		return hashCode;
+	}
+
+	public String toString() {
+		return "EntityKey" + 
+			MessageHelper.infoString( factory.getEntityPersister( entityName ), identifier, factory );
+	}
+
+	/**
+	 * Custom serialization routine used during serialization of a
+	 * Session/PersistenceContext for increased performance.
+	 *
+	 * @param oos The stream to which we should write the serial data.
+	 * @throws IOException
+	 */
+	void serialize(ObjectOutputStream oos) throws IOException {
+		oos.writeObject( identifier );
+		oos.writeObject( rootEntityName );
+		oos.writeObject( entityName );
+		oos.writeObject( identifierType );
+		oos.writeBoolean( isBatchLoadable );
+		oos.writeObject( entityMode.toString() );
+	}
+
+	/**
+	 * Custom deserialization routine used during deserialization of a
+	 * Session/PersistenceContext for increased performance.
+	 *
+	 * @param ois The stream from which to read the entry.
+	 * @param session The session being deserialized.
+	 * @return The deserialized EntityEntry
+	 * @throws IOException
+	 * @throws ClassNotFoundException
+	 */
+	static EntityKey deserialize(
+			ObjectInputStream ois,
+	        SessionImplementor session) throws IOException, ClassNotFoundException {
+		return new EntityKey(
+				( Serializable ) ois.readObject(),
+		        ( String ) ois.readObject(),
+		        ( String ) ois.readObject(),
+		        ( Type ) ois.readObject(),
+		        ois.readBoolean(),
+		        session.getFactory(),
+		        EntityMode.parse( ( String ) ois.readObject() )
+		);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/EntityUniqueKey.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/EntityUniqueKey.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/EntityUniqueKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,137 @@
+//$Id: EntityUniqueKey.java 9194 2006-02-01 19:59:07Z steveebersole $
+package org.hibernate.engine;
+
+import org.hibernate.EntityMode;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.type.Type;
+
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+
+/**
+ * Used to uniquely key an entity instance in relation to a particular session
+ * by some unique property reference, as opposed to identifier.
+ * <p/>
+ * Uniqueing information consists of the entity-name, the referenced
+ * property name, and the referenced property value.
+ *
+ * @see EntityKey
+ * @author Gavin King
+ */
+public class EntityUniqueKey implements Serializable {
+	private final String uniqueKeyName;
+	private final String entityName;
+	private final Object key;
+	private final Type keyType;
+	private final EntityMode entityMode;
+	private final int hashCode;
+
+	public EntityUniqueKey(
+			final String entityName,
+	        final String uniqueKeyName,
+	        final Object semiResolvedKey,
+	        final Type keyType,
+	        final EntityMode entityMode,
+	        final SessionFactoryImplementor factory
+	) {
+		this.uniqueKeyName = uniqueKeyName;
+		this.entityName = entityName;
+		this.key = semiResolvedKey;
+		this.keyType = keyType.getSemiResolvedType(factory);
+		this.entityMode = entityMode;
+		this.hashCode = generateHashCode(factory);
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public Object getKey() {
+		return key;
+	}
+
+	public String getUniqueKeyName() {
+		return uniqueKeyName;
+	}
+
+	public int generateHashCode(SessionFactoryImplementor factory) {
+		int result = 17;
+		result = 37 * result + entityName.hashCode();
+		result = 37 * result + uniqueKeyName.hashCode();
+		result = 37 * result + keyType.getHashCode(key, entityMode, factory);
+		return result;
+	}
+
+	public int hashCode() {
+		return hashCode;
+	}
+
+	public boolean equals(Object other) {
+		EntityUniqueKey that = (EntityUniqueKey) other;
+		return that.entityName.equals(entityName) &&
+		       that.uniqueKeyName.equals(uniqueKeyName) &&
+		       keyType.isEqual(that.key, key, entityMode);
+	}
+
+	public String toString() {
+		return "EntityUniqueKey" + MessageHelper.infoString(entityName, uniqueKeyName, key);
+	}
+
+	private void writeObject(ObjectOutputStream oos) throws IOException {
+		checkAbilityToSerialize();
+		oos.defaultWriteObject();
+	}
+
+	private void checkAbilityToSerialize() {
+		// The unique property value represented here may or may not be
+		// serializable, so we do an explicit check here in order to generate
+		// a better error message
+		if ( key != null && ! Serializable.class.isAssignableFrom( key.getClass() ) ) {
+			throw new IllegalStateException(
+					"Cannot serialize an EntityUniqueKey which represents a non " +
+					"serializable property value [" + entityName + "." + uniqueKeyName + "]"
+			);
+		}
+	}
+
+	/**
+	 * Custom serialization routine used during serialization of a
+	 * Session/PersistenceContext for increased performance.
+	 *
+	 * @param oos The stream to which we should write the serial data.
+	 * @throws IOException
+	 */
+	void serialize(ObjectOutputStream oos) throws IOException {
+		checkAbilityToSerialize();
+		oos.writeObject( uniqueKeyName );
+		oos.writeObject( entityName );
+		oos.writeObject( key );
+		oos.writeObject( keyType );
+		oos.writeObject( entityMode );
+	}
+
+	/**
+	 * Custom deserialization routine used during deserialization of a
+	 * Session/PersistenceContext for increased performance.
+	 *
+	 * @param ois The stream from which to read the entry.
+	 * @param session The session being deserialized.
+	 * @return The deserialized EntityEntry
+	 * @throws IOException
+	 * @throws ClassNotFoundException
+	 */
+	static EntityUniqueKey deserialize(
+			ObjectInputStream ois,
+	        SessionImplementor session) throws IOException, ClassNotFoundException {
+		return new EntityUniqueKey(
+				( String ) ois.readObject(),
+		        ( String ) ois.readObject(),
+		        ois.readObject(),
+		        ( Type ) ois.readObject(),
+		        ( EntityMode ) ois.readObject(),
+		        session.getFactory()
+		);
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/EntityUniqueKey.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ExecuteUpdateResultCheckStyle.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ExecuteUpdateResultCheckStyle.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ExecuteUpdateResultCheckStyle.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,73 @@
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
+
+/**
+ * For persistence operations (INSERT, UPDATE, DELETE) what style of determining
+ * results (success/failure) is to be used.
+ *
+ * @author Steve Ebersole
+ */
+public class ExecuteUpdateResultCheckStyle implements Serializable {
+	/**
+	 * Do not perform checking.  Either user simply does not want checking, or is
+	 * indicating a {@link java.sql.CallableStatement} execution in which the
+	 * checks are being performed explicitly and failures are handled through
+	 * propogation of {@link java.sql.SQLException}s.
+	 */
+	public static final ExecuteUpdateResultCheckStyle NONE = new ExecuteUpdateResultCheckStyle( "none" );
+	/**
+	 * Perform row-count checking.  Row counts are the int values returned by both
+	 * {@link java.sql.PreparedStatement#executeUpdate()} and
+	 * {@link java.sql.Statement#executeBatch()}.  These values are checked
+	 * against some expected count.
+	 */
+	public static final ExecuteUpdateResultCheckStyle COUNT = new ExecuteUpdateResultCheckStyle( "rowcount" );
+	/**
+	 * Essentially the same as {@link #COUNT} except that the row count actually
+	 * comes from an output parameter registered as part of a
+	 * {@link java.sql.CallableStatement}.  This style explicitly prohibits
+	 * statement batching from being used...
+	 */
+	public static final ExecuteUpdateResultCheckStyle PARAM = new ExecuteUpdateResultCheckStyle( "param" );
+
+	private final String name;
+
+	private ExecuteUpdateResultCheckStyle(String name) {
+		this.name = name;
+	}
+
+	private Object readResolve() throws ObjectStreamException {
+		Object resolved = parse( name );
+		if ( resolved == null ) {
+			throw new InvalidObjectException( "unknown result style [" + name + "]" );
+		}
+		return resolved;
+	}
+
+	public static ExecuteUpdateResultCheckStyle parse(String name) {
+		if ( name.equals( NONE.name ) ) {
+			return NONE;
+		}
+		else if ( name.equals( COUNT.name ) ) {
+			return COUNT;
+		}
+		else if ( name.equals( PARAM.name ) ) {
+			return PARAM;
+		}
+		else {
+			return null;
+		}
+	}
+
+	public static ExecuteUpdateResultCheckStyle determineDefault(String customSql, boolean callable) {
+		if ( customSql == null ) {
+			return COUNT;
+		}
+		else {
+			return callable ? PARAM : COUNT;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/FilterDefinition.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/FilterDefinition.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/FilterDefinition.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+// $Id: FilterDefinition.java 9765 2006-04-19 01:45:07Z max.andersen at jboss.com $
+package org.hibernate.engine;
+
+import org.hibernate.type.Type;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+
+/**
+ * A FilterDefinition defines the global attributes of a dynamic filter.  This
+ * information includes its name as well as its defined parameters (name and type).
+ * 
+ * @author Steve Ebersole
+ */
+public class FilterDefinition implements Serializable {
+	private final String filterName;
+	private final String defaultFilterCondition;
+	private final Map parameterTypes = new HashMap();
+
+	/**
+	 * Construct a new FilterDefinition instance.
+	 *
+	 * @param name The name of the filter for which this configuration is in effect.
+	 */
+	public FilterDefinition(String name, String defaultCondition, Map parameterTypes) {
+		this.filterName = name;
+		this.defaultFilterCondition = defaultCondition;
+		this.parameterTypes.putAll( parameterTypes );
+	}
+
+	/**
+	 * Get the name of the filter this configuration defines.
+	 *
+	 * @return The filter name for this configuration.
+	 */
+	public String getFilterName() {
+		return filterName;
+	}
+
+	/**
+	 * Get a set of the parameters defined by this configuration.
+	 *
+	 * @return The parameters named by this configuration.
+	 */
+	public Set getParameterNames() {
+		return parameterTypes.keySet();
+	}
+
+	/**
+	 * Retreive the type of the named parameter defined for this filter.
+	 *
+	 * @param parameterName The name of the filter parameter for which to return the type.
+	 * @return The type of the named parameter.
+	 */
+    public Type getParameterType(String parameterName) {
+	    return (Type) parameterTypes.get(parameterName);
+    }
+
+	public String getDefaultFilterCondition() {
+		return defaultFilterCondition;
+	}
+
+	public Map getParameterTypes() {
+		return parameterTypes;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ForeignKeys.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ForeignKeys.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ForeignKeys.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,230 @@
+//$Id: ForeignKeys.java 10133 2006-07-24 10:35:25Z max.andersen at jboss.com $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.TransientObjectException;
+import org.hibernate.intercept.LazyPropertyInitializer;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+
+/**
+ * Algorithms related to foreign key constraint transparency
+ * 
+ * @author Gavin King
+ */
+public final class ForeignKeys {
+	
+	private ForeignKeys() {}
+	
+	public static class Nullifier {
+	
+		private final boolean isDelete;
+		private final boolean isEarlyInsert;
+		private final SessionImplementor session;
+		private final Object self;
+		
+		public Nullifier(Object self, boolean isDelete, boolean isEarlyInsert, SessionImplementor session) {
+			this.isDelete = isDelete;
+			this.isEarlyInsert = isEarlyInsert;
+			this.session = session;
+			this.self = self;
+		}
+		
+		/**
+		 * Nullify all references to entities that have not yet 
+		 * been inserted in the database, where the foreign key
+		 * points toward that entity
+		 */
+		public void nullifyTransientReferences(final Object[] values, final Type[] types) 
+		throws HibernateException {
+			for ( int i = 0; i < types.length; i++ ) {
+				values[i] = nullifyTransientReferences( values[i], types[i] );
+			}
+		}
+	
+		/**
+		 * Return null if the argument is an "unsaved" entity (ie. 
+		 * one with no existing database row), or the input argument 
+		 * otherwise. This is how Hibernate avoids foreign key constraint
+		 * violations.
+		 */
+		private Object nullifyTransientReferences(final Object value, final Type type) 
+		throws HibernateException {
+			if ( value == null ) {
+				return null;
+			}
+			else if ( type.isEntityType() ) {
+				EntityType entityType = (EntityType) type;
+				if ( entityType.isOneToOne() ) {
+					return value;
+				}
+				else {
+					String entityName = entityType.getAssociatedEntityName();
+					return isNullifiable(entityName, value) ? null : value;
+				}
+			}
+			else if ( type.isAnyType() ) {
+				return isNullifiable(null, value) ? null : value;
+			}
+			else if ( type.isComponentType() ) {
+				AbstractComponentType actype = (AbstractComponentType) type;
+				Object[] subvalues = actype.getPropertyValues(value, session);
+				Type[] subtypes = actype.getSubtypes();
+				boolean substitute = false;
+				for ( int i = 0; i < subvalues.length; i++ ) {
+					Object replacement = nullifyTransientReferences( subvalues[i], subtypes[i] );
+					if ( replacement != subvalues[i] ) {
+						substitute = true;
+						subvalues[i] = replacement;
+					}
+				}
+				if (substitute) actype.setPropertyValues( value, subvalues, session.getEntityMode() );
+				return value;
+			}
+			else {
+				return value;
+			}
+		}
+	
+		/**
+		 * Determine if the object already exists in the database, 
+		 * using a "best guess"
+		 */
+		private boolean isNullifiable(final String entityName, Object object) 
+		throws HibernateException {
+			
+			if (object==LazyPropertyInitializer.UNFETCHED_PROPERTY) return false; //this is kinda the best we can do...
+			
+			if ( object instanceof HibernateProxy ) {
+				// if its an uninitialized proxy it can't be transient
+				LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer();
+				if ( li.getImplementation(session) == null ) {
+					return false;
+					// ie. we never have to null out a reference to
+					// an uninitialized proxy
+				}
+				else {
+					//unwrap it
+					object = li.getImplementation();
+				}
+			}
+	
+			// if it was a reference to self, don't need to nullify
+			// unless we are using native id generation, in which
+			// case we definitely need to nullify
+			if ( object == self ) {
+				return isEarlyInsert || (
+					isDelete &&
+					session.getFactory()
+						.getDialect()
+						.hasSelfReferentialForeignKeyBug()
+				);
+			}
+	
+			// See if the entity is already bound to this session, if not look at the
+			// entity identifier and assume that the entity is persistent if the
+			// id is not "unsaved" (that is, we rely on foreign keys to keep
+			// database integrity)
+	
+			EntityEntry entityEntry = session.getPersistenceContext().getEntry(object);
+			if ( entityEntry==null ) {
+				return isTransient(entityName, object, null, session);
+			}
+			else {
+				return entityEntry.isNullifiable(isEarlyInsert, session);
+			}
+	
+		}
+		
+	}
+	
+	/**
+	 * Is this instance persistent or detached?
+	 * If <tt>assumed</tt> is non-null, don't hit the database to make the 
+	 * determination, instead assume that value; the client code must be 
+	 * prepared to "recover" in the case that this assumed result is incorrect.
+	 */
+	public static boolean isNotTransient(String entityName, Object entity, Boolean assumed, SessionImplementor session) 
+	throws HibernateException {
+		if (entity instanceof HibernateProxy) return true;
+		if ( session.getPersistenceContext().isEntryFor(entity) ) return true;
+		return !isTransient(entityName, entity, assumed, session);
+	}
+	
+	/**
+	 * Is this instance, which we know is not persistent, actually transient?
+	 * If <tt>assumed</tt> is non-null, don't hit the database to make the 
+	 * determination, instead assume that value; the client code must be 
+	 * prepared to "recover" in the case that this assumed result is incorrect.
+	 */
+	public static boolean isTransient(String entityName, Object entity, Boolean assumed, SessionImplementor session) 
+	throws HibernateException {
+		
+		if (entity==LazyPropertyInitializer.UNFETCHED_PROPERTY) {
+			// an unfetched association can only point to
+			// an entity that already exists in the db
+			return false;
+		}
+		
+		// let the interceptor inspect the instance to decide
+		Boolean isUnsaved = session.getInterceptor().isTransient(entity);
+		if (isUnsaved!=null) return isUnsaved.booleanValue();
+		
+		// let the persister inspect the instance to decide
+		EntityPersister persister = session.getEntityPersister(entityName, entity);
+		isUnsaved = persister.isTransient(entity, session);
+		if (isUnsaved!=null) return isUnsaved.booleanValue();
+
+		// we use the assumed value, if there is one, to avoid hitting
+		// the database
+		if (assumed!=null) return assumed.booleanValue();
+		
+		// hit the database, after checking the session cache for a snapshot
+		Object[] snapshot = session.getPersistenceContext()
+		        .getDatabaseSnapshot( persister.getIdentifier( entity, session.getEntityMode() ), persister );
+		return snapshot==null;
+
+	}
+
+	/**
+	 * Return the identifier of the persistent or transient object, or throw
+	 * an exception if the instance is "unsaved"
+	 *
+	 * Used by OneToOneType and ManyToOneType to determine what id value should 
+	 * be used for an object that may or may not be associated with the session. 
+	 * This does a "best guess" using any/all info available to use (not just the 
+	 * EntityEntry).
+	 */
+	public static Serializable getEntityIdentifierIfNotUnsaved(
+			final String entityName, 
+			final Object object, 
+			final SessionImplementor session) 
+	throws HibernateException {
+		if ( object == null ) {
+			return null;
+		}
+		else {
+			Serializable id = session.getContextEntityIdentifier( object );
+			if ( id == null ) {
+				// context-entity-identifier returns null explicitly if the entity
+				// is not associated with the persistence context; so make some
+				// deeper checks...
+				if ( isTransient(entityName, object, Boolean.FALSE, session) ) {
+					throw new TransientObjectException(
+							"object references an unsaved transient instance - save the transient instance before flushing: " +
+							(entityName == null ? session.guessEntityName( object ) : entityName)
+					);
+				}
+				id = session.getEntityPersister( entityName, object ).getIdentifier( object, session.getEntityMode() );
+			}
+			return id;
+		}
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ForeignKeys.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/HibernateIterator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/HibernateIterator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/HibernateIterator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+//$Id: HibernateIterator.java 4782 2004-11-21 00:11:27Z pgmjsd $
+package org.hibernate.engine;
+
+import org.hibernate.JDBCException;
+
+import java.util.Iterator;
+
+/**
+ * An iterator that may be "closed"
+ * @see org.hibernate.Hibernate#close(java.util.Iterator)
+ * @author Gavin King
+ */
+public interface HibernateIterator extends Iterator {
+	public void close() throws JDBCException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/IdentifierValue.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/IdentifierValue.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/IdentifierValue.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,115 @@
+//$Id: IdentifierValue.java 7017 2005-06-05 04:31:34Z oneovthafew $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * A strategy for determining if an identifier value is an identifier of
+ * a new transient instance or a previously persistent transient instance.
+ * The strategy is determined by the <tt>unsaved-value</tt> attribute in
+ * the mapping file.
+ * 
+ * @author Gavin King
+ */
+public class IdentifierValue {
+
+	private static final Log log = LogFactory.getLog(IdentifierValue.class);
+	
+	private final Serializable value;
+	
+	/**
+	 * Always assume the transient instance is newly instantiated
+	 */
+	public static final IdentifierValue ANY = new IdentifierValue() {
+		public final Boolean isUnsaved(Serializable id) {
+			log.trace("id unsaved-value strategy ANY");
+			return Boolean.TRUE;
+		}
+		public Serializable getDefaultValue(Serializable currentValue) {
+			return currentValue;
+		}
+		public String toString() {
+			return "SAVE_ANY";
+		}
+	};
+	
+	/**
+	 * Never assume the transient instance is newly instantiated
+	 */
+	public static final IdentifierValue NONE = new IdentifierValue() {
+		public final Boolean isUnsaved(Serializable id) {
+			log.trace("id unsaved-value strategy NONE");
+			return Boolean.FALSE;
+		}
+		public Serializable getDefaultValue(Serializable currentValue) {
+			return currentValue;
+		}
+		public String toString() {
+			return "SAVE_NONE";
+		}
+	};
+	
+	/**
+	 * Assume the transient instance is newly instantiated if the identifier
+	 * is null.
+	 */
+	public static final IdentifierValue NULL = new IdentifierValue() {
+		public final Boolean isUnsaved(Serializable id) {
+			log.trace("id unsaved-value strategy NULL");
+			return id==null ? Boolean.TRUE : Boolean.FALSE;
+		}
+		public Serializable getDefaultValue(Serializable currentValue) {
+			return null;
+		}
+		public String toString() {
+			return "SAVE_NULL";
+		}
+	};
+	
+	/**
+	 * Assume nothing.
+	 */
+	public static final IdentifierValue UNDEFINED = new IdentifierValue() {
+		public final Boolean isUnsaved(Serializable id) {
+			log.trace("id unsaved-value strategy UNDEFINED");
+			return null;
+		}
+		public Serializable getDefaultValue(Serializable currentValue) {
+			return null;
+		}
+		public String toString() {
+			return "UNDEFINED";
+		}
+	};
+	
+	protected IdentifierValue() {
+		this.value = null;
+	}
+	
+	/**
+	 * Assume the transient instance is newly instantiated if
+	 * its identifier is null or equal to <tt>value</tt>
+	 */
+	public IdentifierValue(Serializable value) {
+		this.value = value;
+	}
+	
+	/**
+	 * Does the given identifier belong to a new instance?
+	 */
+	public Boolean isUnsaved(Serializable id) {
+		if ( log.isTraceEnabled() ) log.trace("id unsaved-value: " + value);
+		return id==null || id.equals(value) ? Boolean.TRUE : Boolean.FALSE;
+	}
+	
+	public Serializable getDefaultValue(Serializable currentValue) {
+		return value;
+	}
+	
+	public String toString() {
+		return "identifier unsaved-value: " + value;
+	}
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/IdentifierValue.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/JoinHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/JoinHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/JoinHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,157 @@
+//$Id: JoinHelper.java 7586 2005-07-21 01:11:52Z oneovthafew $
+package org.hibernate.engine;
+
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.persister.entity.PropertyMapping;
+import org.hibernate.type.AssociationType;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * @author Gavin King
+ */
+public final class JoinHelper {
+	
+	private JoinHelper() {}
+	
+	/**
+	 * Get the aliased columns of the owning entity which are to 
+	 * be used in the join
+	 */
+	public static String[] getAliasedLHSColumnNames(
+			AssociationType type, 
+			String alias, 
+			int property, 
+			OuterJoinLoadable lhsPersister,
+			Mapping mapping
+	) {
+		return getAliasedLHSColumnNames(type, alias, property, 0, lhsPersister, mapping);
+	}
+	
+	/**
+	 * Get the columns of the owning entity which are to 
+	 * be used in the join
+	 */
+	public static String[] getLHSColumnNames(
+			AssociationType type, 
+			int property, 
+			OuterJoinLoadable lhsPersister,
+			Mapping mapping
+	) {
+		return getLHSColumnNames(type, property, 0, lhsPersister, mapping);
+	}
+	
+	/**
+	 * Get the aliased columns of the owning entity which are to 
+	 * be used in the join
+	 */
+	public static String[] getAliasedLHSColumnNames(
+			AssociationType type, 
+			String alias, 
+			int property, 
+			int begin, 
+			OuterJoinLoadable lhsPersister,
+			Mapping mapping
+	) {
+		if ( type.useLHSPrimaryKey() ) {
+			return StringHelper.qualify( alias, lhsPersister.getIdentifierColumnNames() );
+		}
+		else {
+			String propertyName = type.getLHSPropertyName();
+			if (propertyName==null) {
+				return ArrayHelper.slice( 
+						lhsPersister.toColumns(alias, property), 
+						begin, 
+						type.getColumnSpan(mapping) 
+					);
+			}
+			else {
+				return ( (PropertyMapping) lhsPersister ).toColumns(alias, propertyName); //bad cast
+			}
+		}
+	}
+	
+	/**
+	 * Get the columns of the owning entity which are to 
+	 * be used in the join
+	 */
+	public static String[] getLHSColumnNames(
+			AssociationType type, 
+			int property, 
+			int begin, 
+			OuterJoinLoadable lhsPersister,
+			Mapping mapping
+	) {
+		if ( type.useLHSPrimaryKey() ) {
+			//return lhsPersister.getSubclassPropertyColumnNames(property);
+			return lhsPersister.getIdentifierColumnNames();
+		}
+		else {
+			String propertyName = type.getLHSPropertyName();
+			if (propertyName==null) {
+				//slice, to get the columns for this component
+				//property
+				return ArrayHelper.slice( 
+						lhsPersister.getSubclassPropertyColumnNames(property),
+						begin, 
+						type.getColumnSpan(mapping) 
+					);
+			}
+			else {
+				//property-refs for associations defined on a
+				//component are not supported, so no need to slice
+				return lhsPersister.getPropertyColumnNames(propertyName);
+			}
+		}
+	}
+	
+	public static String getLHSTableName(
+		AssociationType type, 
+		int property, 
+		OuterJoinLoadable lhsPersister
+	) {
+		if ( type.useLHSPrimaryKey() ) {
+			return lhsPersister.getTableName();
+		}
+		else {
+			String propertyName = type.getLHSPropertyName();
+			if (propertyName==null) {
+				//if there is no property-ref, assume the join
+				//is to the subclass table (ie. the table of the
+				//subclass that the association belongs to)
+				return lhsPersister.getSubclassPropertyTableName(property);
+			}
+			else {
+				//handle a property-ref
+				String propertyRefTable = lhsPersister.getPropertyTableName(propertyName);
+				if (propertyRefTable==null) {
+					//it is possible that the tree-walking in OuterJoinLoader can get to
+					//an association defined by a subclass, in which case the property-ref
+					//might refer to a property defined on a subclass of the current class
+					//in this case, the table name is not known - this temporary solution 
+					//assumes that the property-ref refers to a property of the subclass
+					//table that the association belongs to (a reasonable guess)
+					//TODO: fix this, add: OuterJoinLoadable.getSubclassPropertyTableName(String propertyName)
+					propertyRefTable = lhsPersister.getSubclassPropertyTableName(property);
+				}
+				return propertyRefTable;
+			}
+		}
+	}
+	
+	/**
+	 * Get the columns of the associated table which are to 
+	 * be used in the join
+	 */
+	public static String[] getRHSColumnNames(AssociationType type, SessionFactoryImplementor factory) {
+		String uniqueKeyPropertyName = type.getRHSUniqueKeyPropertyName();
+		Joinable joinable = type.getAssociatedJoinable(factory);
+		if (uniqueKeyPropertyName==null) {
+			return joinable.getKeyColumnNames();
+		}
+		else {
+			return ( (OuterJoinLoadable) joinable ).getPropertyColumnNames(uniqueKeyPropertyName);
+		}
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/JoinHelper.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/JoinSequence.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/JoinSequence.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/JoinSequence.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,267 @@
+//$Id: JoinSequence.java 9336 2006-02-24 22:12:13Z steveebersole $
+package org.hibernate.engine;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.MappingException;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.sql.QueryJoinFragment;
+import org.hibernate.type.AssociationType;
+import org.hibernate.util.CollectionHelper;
+
+/**
+ * @author Gavin King
+ */
+public class JoinSequence {
+
+	private final SessionFactoryImplementor factory;
+	private final List joins = new ArrayList();
+	private boolean useThetaStyle = false;
+	private final StringBuffer conditions = new StringBuffer();
+	private String rootAlias;
+	private Joinable rootJoinable;
+	private Selector selector;
+	private JoinSequence next;
+	private boolean isFromPart = false;
+
+	public String toString() {
+		StringBuffer buf = new StringBuffer();
+		buf.append( "JoinSequence{" );
+		if ( rootJoinable != null ) {
+			buf.append( rootJoinable )
+					.append( '[' )
+					.append( rootAlias )
+					.append( ']' );
+		}
+		for ( int i = 0; i < joins.size(); i++ ) {
+			buf.append( "->" ).append( joins.get( i ) );
+		}
+		return buf.append( '}' ).toString();
+	}
+
+	final class Join {
+
+		private final AssociationType associationType;
+		private final Joinable joinable;
+		private final int joinType;
+		private final String alias;
+		private final String[] lhsColumns;
+
+		Join(AssociationType associationType, String alias, int joinType, String[] lhsColumns)
+				throws MappingException {
+			this.associationType = associationType;
+			this.joinable = associationType.getAssociatedJoinable( factory );
+			this.alias = alias;
+			this.joinType = joinType;
+			this.lhsColumns = lhsColumns;
+		}
+
+		String getAlias() {
+			return alias;
+		}
+
+		AssociationType getAssociationType() {
+			return associationType;
+		}
+
+		Joinable getJoinable() {
+			return joinable;
+		}
+
+		int getJoinType() {
+			return joinType;
+		}
+
+		String[] getLHSColumns() {
+			return lhsColumns;
+		}
+
+		public String toString() {
+			return joinable.toString() + '[' + alias + ']';
+		}
+	}
+
+	public JoinSequence(SessionFactoryImplementor factory) {
+		this.factory = factory;
+	}
+
+	public JoinSequence getFromPart() {
+		JoinSequence fromPart = new JoinSequence( factory );
+		fromPart.joins.addAll( this.joins );
+		fromPart.useThetaStyle = this.useThetaStyle;
+		fromPart.rootAlias = this.rootAlias;
+		fromPart.rootJoinable = this.rootJoinable;
+		fromPart.selector = this.selector;
+		fromPart.next = this.next == null ? null : this.next.getFromPart();
+		fromPart.isFromPart = true;
+		return fromPart;
+	}
+
+	public JoinSequence copy() {
+		JoinSequence copy = new JoinSequence( factory );
+		copy.joins.addAll( this.joins );
+		copy.useThetaStyle = this.useThetaStyle;
+		copy.rootAlias = this.rootAlias;
+		copy.rootJoinable = this.rootJoinable;
+		copy.selector = this.selector;
+		copy.next = this.next == null ? null : this.next.copy();
+		copy.isFromPart = this.isFromPart;
+		copy.conditions.append( this.conditions.toString() );
+		return copy;
+	}
+
+	public JoinSequence addJoin(AssociationType associationType, String alias, int joinType, String[] referencingKey)
+			throws MappingException {
+		joins.add( new Join( associationType, alias, joinType, referencingKey ) );
+		return this;
+	}
+
+	public JoinFragment toJoinFragment() throws MappingException {
+		return toJoinFragment( CollectionHelper.EMPTY_MAP, true );
+	}
+
+	public JoinFragment toJoinFragment(Map enabledFilters, boolean includeExtraJoins) throws MappingException {
+		return toJoinFragment( enabledFilters, includeExtraJoins, null, null );
+	}
+
+	public JoinFragment toJoinFragment(
+			Map enabledFilters,
+	        boolean includeExtraJoins,
+	        String withClauseFragment,
+	        String withClauseJoinAlias) throws MappingException {
+		QueryJoinFragment joinFragment = new QueryJoinFragment( factory.getDialect(), useThetaStyle );
+		if ( rootJoinable != null ) {
+			joinFragment.addCrossJoin( rootJoinable.getTableName(), rootAlias );
+			String filterCondition = rootJoinable.filterFragment( rootAlias, enabledFilters );
+			// JoinProcessor needs to know if the where clause fragment came from a dynamic filter or not so it
+			// can put the where clause fragment in the right place in the SQL AST.   'hasFilterCondition' keeps track
+			// of that fact.
+			joinFragment.setHasFilterCondition( joinFragment.addCondition( filterCondition ) );
+			if (includeExtraJoins) { //TODO: not quite sure about the full implications of this!
+				addExtraJoins( joinFragment, rootAlias, rootJoinable, true );
+			}
+		}
+
+		Joinable last = rootJoinable;
+
+		for ( int i = 0; i < joins.size(); i++ ) {
+			Join join = ( Join ) joins.get( i );
+			String on = join.getAssociationType().getOnCondition( join.getAlias(), factory, enabledFilters );
+			String condition = null;
+			if ( last != null &&
+			        isManyToManyRoot( last ) &&
+			        ( ( QueryableCollection ) last ).getElementType() == join.getAssociationType() ) {
+				// the current join represents the join between a many-to-many association table
+				// and its "target" table.  Here we need to apply any additional filters
+				// defined specifically on the many-to-many
+				String manyToManyFilter = ( ( QueryableCollection ) last )
+				        .getManyToManyFilterFragment( join.getAlias(), enabledFilters );
+				condition = "".equals( manyToManyFilter )
+						? on
+						: "".equals( on )
+								? manyToManyFilter
+								: on + " and " + manyToManyFilter;
+			}
+			else {
+				condition = on;
+			}
+			if ( withClauseFragment != null ) {
+				if ( join.getAlias().equals( withClauseJoinAlias ) ) {
+					condition += " and " + withClauseFragment;
+				}
+			}
+			joinFragment.addJoin(
+			        join.getJoinable().getTableName(),
+					join.getAlias(),
+					join.getLHSColumns(),
+					JoinHelper.getRHSColumnNames( join.getAssociationType(), factory ),
+					join.joinType,
+					condition
+			);
+			if (includeExtraJoins) { //TODO: not quite sure about the full implications of this!
+				addExtraJoins( joinFragment, join.getAlias(), join.getJoinable(), join.joinType == JoinFragment.INNER_JOIN );
+			}
+			last = join.getJoinable();
+		}
+		if ( next != null ) {
+			joinFragment.addFragment( next.toJoinFragment( enabledFilters, includeExtraJoins ) );
+		}
+		joinFragment.addCondition( conditions.toString() );
+		if ( isFromPart ) joinFragment.clearWherePart();
+		return joinFragment;
+	}
+
+	private boolean isManyToManyRoot(Joinable joinable) {
+		if ( joinable != null && joinable.isCollection() ) {
+			QueryableCollection persister = ( QueryableCollection ) joinable;
+			return persister.isManyToMany();
+		}
+		return false;
+	}
+
+	private boolean isIncluded(String alias) {
+		return selector != null && selector.includeSubclasses( alias );
+	}
+
+	private void addExtraJoins(JoinFragment joinFragment, String alias, Joinable joinable, boolean innerJoin) {
+		boolean include = isIncluded( alias );
+		joinFragment.addJoins( joinable.fromJoinFragment( alias, innerJoin, include ),
+				joinable.whereJoinFragment( alias, innerJoin, include ) );
+	}
+
+	public JoinSequence addCondition(String condition) {
+		if ( condition.trim().length() != 0 ) {
+			if ( !condition.startsWith( " and " ) ) conditions.append( " and " );
+			conditions.append( condition );
+		}
+		return this;
+	}
+
+	public JoinSequence addCondition(String alias, String[] columns, String condition) {
+		for ( int i = 0; i < columns.length; i++ ) {
+			conditions.append( " and " )
+					.append( alias )
+					.append( '.' )
+					.append( columns[i] )
+					.append( condition );
+		}
+		return this;
+	}
+
+	public JoinSequence setRoot(Joinable joinable, String alias) {
+		this.rootAlias = alias;
+		this.rootJoinable = joinable;
+		return this;
+	}
+
+	public JoinSequence setNext(JoinSequence next) {
+		this.next = next;
+		return this;
+	}
+
+	public JoinSequence setSelector(Selector s) {
+		this.selector = s;
+		return this;
+	}
+
+	public JoinSequence setUseThetaStyle(boolean useThetaStyle) {
+		this.useThetaStyle = useThetaStyle;
+		return this;
+	}
+
+	public boolean isThetaStyle() {
+		return useThetaStyle;
+	}
+
+	public int getJoinCount() {
+		return joins.size();
+	}
+	
+	public static interface Selector {
+		public boolean includeSubclasses(String alias);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Mapping.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Mapping.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Mapping.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+//$Id: Mapping.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.engine;
+
+import org.hibernate.MappingException;
+import org.hibernate.type.Type;
+
+/**
+ * Defines operations common to "compiled" mappings (ie. <tt>SessionFactory</tt>)
+ * and "uncompiled" mappings (ie. <tt>Configuration</tt>) that are used by
+ * implementors of <tt>Type</tt>.
+ *
+ * @see org.hibernate.type.Type
+ * @see org.hibernate.impl.SessionFactoryImpl
+ * @see org.hibernate.cfg.Configuration
+ * @author Gavin King
+ */
+public interface Mapping {
+	public Type getIdentifierType(String className) throws MappingException;
+	public String getIdentifierPropertyName(String className) throws MappingException;
+	public Type getReferencedPropertyType(String className, String propertyName) throws MappingException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/NamedQueryDefinition.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/NamedQueryDefinition.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/NamedQueryDefinition.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,123 @@
+//$Id: NamedQueryDefinition.java 7966 2005-08-19 23:40:24Z epbernard $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.hibernate.CacheMode;
+import org.hibernate.FlushMode;
+
+
+/**
+ * Definition of a named query, defined in the mapping metadata.
+ *
+ * @author Gavin King
+ */
+public class NamedQueryDefinition implements Serializable {
+	private final String query;
+	private final boolean cacheable;
+	private final String cacheRegion;
+	private final Integer timeout;
+	private final Integer fetchSize;
+	private final FlushMode flushMode;
+	private final Map parameterTypes;
+	private CacheMode cacheMode;
+	private boolean readOnly;
+	private String comment;
+
+	// kept for backward compatibility until after the 3.1beta5 release of HA
+	public NamedQueryDefinition(
+			String query,
+			boolean cacheable,
+			String cacheRegion,
+			Integer timeout,
+			Integer fetchSize,
+			FlushMode flushMode,
+			Map parameterTypes
+	) {
+		this(
+				query,
+				cacheable,
+				cacheRegion,
+				timeout,
+				fetchSize,
+				flushMode,
+				null,
+				false,
+				null,
+				parameterTypes
+		);
+	}
+
+	public NamedQueryDefinition(
+			String query,
+			boolean cacheable,
+			String cacheRegion,
+			Integer timeout,
+			Integer fetchSize,
+			FlushMode flushMode,
+			CacheMode cacheMode,
+			boolean readOnly,
+			String comment,
+			Map parameterTypes
+	) {
+		this.query = query;
+		this.cacheable = cacheable;
+		this.cacheRegion = cacheRegion;
+		this.timeout = timeout;
+		this.fetchSize = fetchSize;
+		this.flushMode = flushMode;
+		this.parameterTypes = parameterTypes;
+		this.cacheMode = cacheMode;
+		this.readOnly = readOnly;
+		this.comment = comment;
+	}
+
+	public String getQueryString() {
+		return query;
+	}
+
+	public boolean isCacheable() {
+		return cacheable;
+	}
+
+	public String getCacheRegion() {
+		return cacheRegion;
+	}
+
+	public Integer getFetchSize() {
+		return fetchSize;
+	}
+
+	public Integer getTimeout() {
+		return timeout;
+	}
+
+	public FlushMode getFlushMode() {
+		return flushMode;
+	}
+
+	public String toString() {
+		return getClass().getName() + '(' + query + ')';
+	}
+
+	public Map getParameterTypes() {
+		return parameterTypes;
+	}
+
+	public String getQuery() {
+		return query;
+	}
+
+	public CacheMode getCacheMode() {
+		return cacheMode;
+	}
+
+	public boolean isReadOnly() {
+		return readOnly;
+	}
+
+	public String getComment() {
+		return comment;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/NamedQueryDefinition.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/NamedSQLQueryDefinition.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/NamedSQLQueryDefinition.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/NamedSQLQueryDefinition.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,185 @@
+//$Id: NamedSQLQueryDefinition.java 11198 2007-02-13 21:04:10Z epbernard $
+package org.hibernate.engine;
+
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.FlushMode;
+import org.hibernate.CacheMode;
+import org.hibernate.engine.query.sql.NativeSQLQueryReturn;
+
+/**
+ * Definition of a named native SQL query, defined
+ * in the mapping metadata.
+ * 
+ * @author Max Andersen
+ */
+public class NamedSQLQueryDefinition extends NamedQueryDefinition {
+
+	private NativeSQLQueryReturn[] queryReturns;
+	private final List querySpaces;
+	private final boolean callable;
+	private String resultSetRef;
+
+	/**
+	 * This form used to construct a NamedSQLQueryDefinition from the binder
+	 * code when a the result-set mapping information is explicitly
+	 * provided in the query definition (i.e., no resultset-mapping used)
+	 *
+	 * @param query The sql query string
+	 * @param queryReturns The in-lined query return definitions
+	 * @param querySpaces Any specified query spaces (used for auto-flushing)
+	 * @param cacheable Whether the query results are cacheable
+	 * @param cacheRegion If cacheable, the region into which to store the results
+	 * @param timeout A JDBC-level timeout to be applied
+	 * @param fetchSize A JDBC-level fetch-size to be applied
+	 * @param flushMode The flush mode to use for this query
+	 * @param cacheMode The cache mode to use during execution and subsequent result loading
+	 * @param readOnly Whether returned entities should be marked as read-only in the session
+	 * @param comment Any sql comment to be applied to the query
+	 * @param parameterTypes parameter type map
+	 * @param callable Does the query string represent a callable object (i.e., proc)
+	 */
+	public NamedSQLQueryDefinition(
+			String query,
+			NativeSQLQueryReturn[] queryReturns,
+			List querySpaces,
+			boolean cacheable,
+			String cacheRegion,
+			Integer timeout,
+			Integer fetchSize,
+			FlushMode flushMode,
+			CacheMode cacheMode,
+			boolean readOnly,
+			String comment,
+			Map parameterTypes,
+			boolean callable) {
+		super(
+				query.trim(), /* trim done to workaround stupid oracle bug that cant handle whitespaces before a { in a sp */
+				cacheable,
+				cacheRegion,
+				timeout,
+				fetchSize,
+				flushMode,
+				cacheMode,
+				readOnly,
+				comment,
+				parameterTypes
+		);
+		this.queryReturns = queryReturns;
+		this.querySpaces = querySpaces;
+		this.callable = callable;
+	}
+
+	/**
+	 * This form used to construct a NamedSQLQueryDefinition from the binder
+	 * code when a resultset-mapping reference is used.
+	 *
+	 * @param query The sql query string
+	 * @param resultSetRef The resultset-mapping name
+	 * @param querySpaces Any specified query spaces (used for auto-flushing)
+	 * @param cacheable Whether the query results are cacheable
+	 * @param cacheRegion If cacheable, the region into which to store the results
+	 * @param timeout A JDBC-level timeout to be applied
+	 * @param fetchSize A JDBC-level fetch-size to be applied
+	 * @param flushMode The flush mode to use for this query
+	 * @param cacheMode The cache mode to use during execution and subsequent result loading
+	 * @param readOnly Whether returned entities should be marked as read-only in the session
+	 * @param comment Any sql comment to be applied to the query
+	 * @param parameterTypes parameter type map
+	 * @param callable Does the query string represent a callable object (i.e., proc)
+	 */
+	public NamedSQLQueryDefinition(
+			String query,
+			String resultSetRef,
+			List querySpaces,
+			boolean cacheable,
+			String cacheRegion,
+			Integer timeout,
+			Integer fetchSize,
+			FlushMode flushMode,
+			CacheMode cacheMode,
+			boolean readOnly,
+			String comment,
+			Map parameterTypes,
+			boolean callable) {
+		super(
+				query.trim(), /* trim done to workaround stupid oracle bug that cant handle whitespaces before a { in a sp */
+				cacheable,
+				cacheRegion,
+				timeout,
+				fetchSize,
+				flushMode,
+				cacheMode,
+				readOnly,
+				comment,
+				parameterTypes
+		);
+		this.resultSetRef = resultSetRef;
+		this.querySpaces = querySpaces;
+		this.callable = callable;
+	}
+
+	/**
+	 * This form used from annotations (?).  Essentially the same as the above using a
+	 * resultset-mapping reference, but without cacheMode, readOnly, and comment.
+	 *
+	 * FIXME: annotations do not use it, so it can be remove from my POV
+	 * @deprecated
+	 *
+	 *
+	 * @param query The sql query string
+	 * @param resultSetRef The result-set-mapping name
+	 * @param querySpaces Any specified query spaces (used for auto-flushing)
+	 * @param cacheable Whether the query results are cacheable
+	 * @param cacheRegion If cacheable, the region into which to store the results
+	 * @param timeout A JDBC-level timeout to be applied
+	 * @param fetchSize A JDBC-level fetch-size to be applied
+	 * @param flushMode The flush mode to use for this query
+	 * @param parameterTypes parameter type map
+	 * @param callable Does the query string represent a callable object (i.e., proc)
+	 */
+	public NamedSQLQueryDefinition(
+			String query,
+			String resultSetRef,
+			List querySpaces,
+			boolean cacheable,
+			String cacheRegion,
+			Integer timeout,
+			Integer fetchSize,
+			FlushMode flushMode,
+			Map parameterTypes,
+			boolean callable) {
+		this(
+				query,
+				resultSetRef,
+				querySpaces,
+				cacheable,
+				cacheRegion,
+				timeout,
+				fetchSize,
+				flushMode,
+				null,
+				false,
+				null,
+				parameterTypes,
+				callable
+		);
+	}
+
+	public NativeSQLQueryReturn[] getQueryReturns() {
+		return queryReturns;
+	}
+
+	public List getQuerySpaces() {
+		return querySpaces;
+	}
+
+	public boolean isCallable() {
+		return callable;
+	}
+
+	public String getResultSetRef() {
+		return resultSetRef;
+	}
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/NamedSQLQueryDefinition.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Nullability.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Nullability.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Nullability.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,183 @@
+//$Id: Nullability.java 7566 2005-07-20 07:16:33Z oneovthafew $
+package org.hibernate.engine;
+
+import java.util.Iterator;
+
+import org.hibernate.HibernateException;
+import org.hibernate.PropertyValueException;
+import org.hibernate.intercept.LazyPropertyInitializer;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.Type;
+
+/**
+ * Implements the algorithm for validating property values
+ * for illegal null values
+ * @author Gavin King
+ */
+public final class Nullability {
+	
+	private final SessionImplementor session;
+	
+	public Nullability(SessionImplementor session) {
+		this.session = session;
+	}
+	/**
+	 * Check nullability of the class persister properties
+	 *
+	 * @param values entity properties
+	 * @param persister class persister
+	 * @param isUpdate wether it is intended to be updated or saved
+	 * @throws org.hibernate.PropertyValueException Break the nullability of one property
+	 * @throws HibernateException error while getting Component values
+	 */
+	public void checkNullability(
+			final Object[] values,
+			final EntityPersister persister,
+			final boolean isUpdate) 
+	throws PropertyValueException, HibernateException {
+
+		/*
+		  * Algorithm
+		  * Check for any level one nullability breaks
+		  * Look at non null components to
+		  *   recursively check next level of nullability breaks
+		  * Look at Collections contraining component to
+		  *   recursively check next level of nullability breaks
+		  *
+		  *
+		  * In the previous implementation, not-null stuffs where checked
+		  * filtering by level one only updateable
+		  * or insertable columns. So setting a sub component as update="false"
+		  * has no effect on not-null check if the main component had good checkeability
+		  * In this implementation, we keep this feature.
+		  * However, I never see any documentation mentioning that, but it's for
+		  * sure a limitation.
+		  */
+
+		final boolean[] nullability = persister.getPropertyNullability();
+		final boolean[] checkability = isUpdate ?
+			persister.getPropertyUpdateability() :
+			persister.getPropertyInsertability();
+		final Type[] propertyTypes = persister.getPropertyTypes();
+
+		for ( int i = 0; i < values.length; i++ ) {
+			
+			if ( checkability[i] && values[i]!=LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
+				final Object value = values[i];
+				if ( !nullability[i] && value == null ) {
+					
+					//check basic level one nullablilty
+					throw new PropertyValueException(
+							"not-null property references a null or transient value",
+							persister.getEntityName(),
+							persister.getPropertyNames()[i]
+						);
+					
+				}
+				else if ( value != null ) {
+					
+					//values is not null and is checkable, we'll look deeper
+					String breakProperties = checkSubElementsNullability( propertyTypes[i], value );
+					if ( breakProperties != null ) {
+						throw new PropertyValueException(
+							"not-null property references a null or transient value",
+							persister.getEntityName(),
+							buildPropertyPath( persister.getPropertyNames()[i], breakProperties )
+						);
+					}
+					
+				}
+			}
+			
+		}
+	}
+
+	/**
+	 * check sub elements-nullability. Returns property path that break
+	 * nullability or null if none
+	 *
+	 * @param propertyType type to check
+	 * @param value value to check
+	 *
+	 * @return property path
+	 * @throws HibernateException error while getting subcomponent values
+	 */
+	private String checkSubElementsNullability(final Type propertyType, final Object value) 
+	throws HibernateException {
+		//for non null args, check for components and elements containing components
+		if ( propertyType.isComponentType() ) {
+			return checkComponentNullability( value, (AbstractComponentType) propertyType );
+		}
+		else if ( propertyType.isCollectionType() ) {
+
+			//persistent collections may have components
+			CollectionType collectionType = (CollectionType) propertyType;
+			Type collectionElementType = collectionType.getElementType( session.getFactory() );
+			if ( collectionElementType.isComponentType() ) {
+				//check for all components values in the collection
+
+				AbstractComponentType componentType = (AbstractComponentType) collectionElementType;
+				Iterator iter = CascadingAction.getLoadedElementsIterator(session, collectionType, value);
+				while ( iter.hasNext() ) {
+					Object compValue = iter.next();
+					if (compValue != null) {
+						return checkComponentNullability(compValue, componentType);
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * check component nullability. Returns property path that break
+	 * nullability or null if none
+	 *
+	 * @param value component properties
+	 * @param compType component not-nullable type
+	 *
+	 * @return property path
+	 * @throws HibernateException error while getting subcomponent values
+	 */
+	private String checkComponentNullability(final Object value, final AbstractComponentType compType) 
+	throws HibernateException {
+		/* will check current level if some of them are not null
+		 * or sublevels if they exist
+		 */
+		boolean[] nullability = compType.getPropertyNullability();
+		if ( nullability!=null ) {
+			//do the test
+			final Object[] values = compType.getPropertyValues( value, session.getEntityMode() );
+			final Type[] propertyTypes = compType.getSubtypes();
+			for ( int i=0; i<values.length; i++ ) {
+				final Object subvalue = values[i];
+				if ( !nullability[i] && subvalue==null ) {
+					return compType.getPropertyNames()[i];
+				}
+				else if ( subvalue != null ) {
+					String breakProperties = checkSubElementsNullability( propertyTypes[i], subvalue );
+					if ( breakProperties != null ) {
+						return buildPropertyPath( compType.getPropertyNames()[i], breakProperties );
+					}
+	 			}
+	 		}
+		}
+		return null;
+	}
+
+	/**
+	 * Return a well formed property path.
+	 * Basicaly, it will return parent.child
+	 *
+	 * @param parent parent in path
+	 * @param child child in path
+	 * @return parent-child path
+	 */
+	private static String buildPropertyPath(String parent, String child) {
+		return new StringBuffer( parent.length() + child.length() + 1 )
+			.append(parent).append('.').append(child).toString();
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Nullability.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ParameterBinder.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ParameterBinder.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ParameterBinder.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,114 @@
+// $Id: ParameterBinder.java 7385 2005-07-06 17:13:15Z steveebersole $
+package org.hibernate.engine;
+
+import org.hibernate.HibernateException;
+import org.hibernate.type.Type;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Map;
+import java.util.Iterator;
+
+/**
+ * Centralizes the commonality regarding binding of parameter values into
+ * PreparedStatements as this logic is used in many places.
+ * <p/>
+ * Ideally would like to move to the parameter handling as it is done in
+ * the hql.ast package.
+ * 
+ * @author Steve Ebersole
+ */
+public class ParameterBinder {
+
+	private static final Log log = LogFactory.getLog( ParameterBinder.class );
+
+	public static interface NamedParameterSource {
+		public int[] getNamedParameterLocations(String name);
+	}
+
+	private ParameterBinder() {
+	}
+
+	public static int bindQueryParameters(
+	        final PreparedStatement st,
+	        final QueryParameters queryParameters,
+	        final int start,
+	        final NamedParameterSource source,
+	        SessionImplementor session) throws SQLException, HibernateException {
+		int col = start;
+		col += bindPositionalParameters( st, queryParameters, col, session );
+		col += bindNamedParameters( st, queryParameters, col, source, session );
+		return col;
+	}
+
+	public static int bindPositionalParameters(
+	        final PreparedStatement st,
+	        final QueryParameters queryParameters,
+	        final int start,
+	        final SessionImplementor session) throws SQLException, HibernateException {
+		return bindPositionalParameters(
+		        st,
+		        queryParameters.getPositionalParameterValues(),
+		        queryParameters.getPositionalParameterTypes(),
+		        start,
+		        session
+		);
+	}
+
+	public static int bindPositionalParameters(
+	        final PreparedStatement st,
+	        final Object[] values,
+	        final Type[] types,
+	        final int start,
+	        final SessionImplementor session) throws SQLException, HibernateException {
+		int span = 0;
+		for ( int i = 0; i < values.length; i++ ) {
+			types[i].nullSafeSet( st, values[i], start + span, session );
+			span += types[i].getColumnSpan( session.getFactory() );
+		}
+		return span;
+	}
+
+	public static int bindNamedParameters(
+	        final PreparedStatement ps,
+	        final QueryParameters queryParameters,
+	        final int start,
+	        final NamedParameterSource source,
+	        final SessionImplementor session) throws SQLException, HibernateException {
+		return bindNamedParameters( ps, queryParameters.getNamedParameters(), start, source, session );
+	}
+
+	public static int bindNamedParameters(
+	        final PreparedStatement ps,
+	        final Map namedParams,
+	        final int start,
+	        final NamedParameterSource source,
+	        final SessionImplementor session) throws SQLException, HibernateException {
+		if ( namedParams != null ) {
+			// assumes that types are all of span 1
+			Iterator iter = namedParams.entrySet().iterator();
+			int result = 0;
+			while ( iter.hasNext() ) {
+				Map.Entry e = ( Map.Entry ) iter.next();
+				String name = ( String ) e.getKey();
+				TypedValue typedval = ( TypedValue ) e.getValue();
+				int[] locations = source.getNamedParameterLocations( name );
+				for ( int i = 0; i < locations.length; i++ ) {
+					if ( log.isDebugEnabled() ) {
+						log.debug( "bindNamedParameters() " +
+								typedval.getValue() + " -> " + name +
+								" [" + ( locations[i] + start ) + "]" );
+					}
+					typedval.getType().nullSafeSet( ps, typedval.getValue(), locations[i] + start, session );
+				}
+				result += locations.length;
+			}
+			return result;
+		}
+		else {
+			return 0;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/PersistenceContext.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/PersistenceContext.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/PersistenceContext.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,440 @@
+//$Id: PersistenceContext.java 11319 2007-03-20 03:12:56Z steve.ebersole at jboss.com $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.loading.LoadContexts;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Holds the state of the persistence context, including the 
+ * first-level cache, entries, snapshots, proxies, etc.
+ * 
+ * @author Gavin King
+ */
+public interface PersistenceContext {
+	
+	public boolean isStateless();
+	
+	/**
+	 * Get the session to which this persistence context is bound.
+	 *
+	 * @return The session.
+	 */
+	public SessionImplementor getSession();
+
+	/**
+	 * Retrieve this persistence context's managed load context.
+	 *
+	 * @return The load context
+	 */
+	public LoadContexts getLoadContexts();
+
+	/**
+	 * Add a collection which has no owner loaded
+	 */
+	public void addUnownedCollection(CollectionKey key, PersistentCollection collection);
+
+	/**
+	 * Get and remove a collection whose owner is not yet loaded,
+	 * when its owner is being loaded
+	 */
+	public PersistentCollection useUnownedCollection(CollectionKey key);
+
+	/**
+	 * Get the <tt>BatchFetchQueue</tt>, instantiating one if
+	 * necessary.
+	 */
+	public BatchFetchQueue getBatchFetchQueue();
+	
+	/**
+	 * Clear the state of the persistence context
+	 */
+	public void clear();
+
+	/**
+	 * @return false if we know for certain that all the entities are read-only
+	 */
+	public boolean hasNonReadOnlyEntities();
+
+	/**
+	 * Set the status of an entry
+	 */
+	public void setEntryStatus(EntityEntry entry, Status status);
+
+	/**
+	 * Called after transactions end
+	 */
+	public void afterTransactionCompletion();
+
+	/**
+	 * Get the current state of the entity as known to the underlying
+	 * database, or null if there is no corresponding row 
+	 */
+	public Object[] getDatabaseSnapshot(Serializable id, EntityPersister persister)
+			throws HibernateException;
+
+	public Object[] getCachedDatabaseSnapshot(EntityKey key);
+
+	public Object[] getNaturalIdSnapshot(Serializable id, EntityPersister persister)
+	throws HibernateException;
+
+	/**
+	 * Add a canonical mapping from entity key to entity instance
+	 */
+	public void addEntity(EntityKey key, Object entity);
+
+	/**
+	 * Get the entity instance associated with the given 
+	 * <tt>EntityKey</tt>
+	 */
+	public Object getEntity(EntityKey key);
+
+	/**
+	 * Is there an entity with the given key in the persistence context
+	 */
+	public boolean containsEntity(EntityKey key);
+
+	/**
+	 * Remove an entity from the session cache, also clear
+	 * up other state associated with the entity, all except
+	 * for the <tt>EntityEntry</tt>
+	 */
+	public Object removeEntity(EntityKey key);
+
+	/**
+	 * Get an entity cached by unique key
+	 */
+	public Object getEntity(EntityUniqueKey euk);
+
+	/**
+	 * Add an entity to the cache by unique key
+	 */
+	public void addEntity(EntityUniqueKey euk, Object entity);
+
+	/**
+	 * Retreive the EntityEntry representation of the given entity.
+	 *
+	 * @param entity The entity for which to locate the EntityEntry.
+	 * @return The EntityEntry for the given entity.
+	 */
+	public EntityEntry getEntry(Object entity);
+
+	/**
+	 * Remove an entity entry from the session cache
+	 */
+	public EntityEntry removeEntry(Object entity);
+
+	/**
+	 * Is there an EntityEntry for this instance?
+	 */
+	public boolean isEntryFor(Object entity);
+
+	/**
+	 * Get the collection entry for a persistent collection
+	 */
+	public CollectionEntry getCollectionEntry(PersistentCollection coll);
+
+	/**
+	 * Adds an entity to the internal caches.
+	 */
+	public EntityEntry addEntity(final Object entity, final Status status,
+			final Object[] loadedState, final EntityKey entityKey, final Object version,
+			final LockMode lockMode, final boolean existsInDatabase,
+			final EntityPersister persister, final boolean disableVersionIncrement, boolean lazyPropertiesAreUnfetched);
+
+	/**
+	 * Generates an appropriate EntityEntry instance and adds it 
+	 * to the event source's internal caches.
+	 */
+	public EntityEntry addEntry(final Object entity, final Status status,
+			final Object[] loadedState, final Object rowId, final Serializable id,
+			final Object version, final LockMode lockMode, final boolean existsInDatabase,
+			final EntityPersister persister, final boolean disableVersionIncrement, boolean lazyPropertiesAreUnfetched);
+
+	/**
+	 * Is the given collection associated with this persistence context?
+	 */
+	public boolean containsCollection(PersistentCollection collection);
+	
+	/**
+	 * Is the given proxy associated with this persistence context?
+	 */
+	public boolean containsProxy(Object proxy);
+
+	/**
+	 * Takes the given object and, if it represents a proxy, reassociates it with this event source.
+	 *
+	 * @param value The possible proxy to be reassociated.
+	 * @return Whether the passed value represented an actual proxy which got initialized.
+	 * @throws MappingException
+	 */
+	public boolean reassociateIfUninitializedProxy(Object value) throws MappingException;
+
+	/**
+	 * If a deleted entity instance is re-saved, and it has a proxy, we need to
+	 * reset the identifier of the proxy 
+	 */
+	public void reassociateProxy(Object value, Serializable id) throws MappingException;
+
+	/**
+	 * Get the entity instance underlying the given proxy, throwing
+	 * an exception if the proxy is uninitialized. If the given object
+	 * is not a proxy, simply return the argument.
+	 */
+	public Object unproxy(Object maybeProxy) throws HibernateException;
+
+	/**
+	 * Possibly unproxy the given reference and reassociate it with the current session.
+	 *
+	 * @param maybeProxy The reference to be unproxied if it currently represents a proxy.
+	 * @return The unproxied instance.
+	 * @throws HibernateException
+	 */
+	public Object unproxyAndReassociate(Object maybeProxy) throws HibernateException;
+
+	/**
+	 * Attempts to check whether the given key represents an entity already loaded within the
+	 * current session.
+	 * @param object The entity reference against which to perform the uniqueness check.
+	 * @throws HibernateException
+	 */
+	public void checkUniqueness(EntityKey key, Object object) throws HibernateException;
+
+	/**
+	 * If the existing proxy is insufficiently "narrow" (derived), instantiate a new proxy
+	 * and overwrite the registration of the old one. This breaks == and occurs only for
+	 * "class" proxies rather than "interface" proxies. Also init the proxy to point to
+	 * the given target implementation if necessary.
+	 *
+	 * @param proxy The proxy instance to be narrowed.
+	 * @param persister The persister for the proxied entity.
+	 * @param key The internal cache key for the proxied entity.
+	 * @param object (optional) the actual proxied entity instance.
+	 * @return An appropriately narrowed instance.
+	 * @throws HibernateException
+	 */
+	public Object narrowProxy(Object proxy, EntityPersister persister, EntityKey key, Object object)
+			throws HibernateException;
+
+	/**
+	 * Return the existing proxy associated with the given <tt>EntityKey</tt>, or the
+	 * third argument (the entity associated with the key) if no proxy exists. Init
+	 * the proxy to the target implementation, if necessary.
+	 */
+	public Object proxyFor(EntityPersister persister, EntityKey key, Object impl)
+			throws HibernateException;
+
+	/**
+	 * Return the existing proxy associated with the given <tt>EntityKey</tt>, or the
+	 * argument (the entity associated with the key) if no proxy exists.
+	 * (slower than the form above)
+	 */
+	public Object proxyFor(Object impl) throws HibernateException;
+
+	/**
+	 * Get the entity that owns this persistent collection
+	 */
+	public Object getCollectionOwner(Serializable key, CollectionPersister collectionPersister)
+			throws MappingException;
+
+	/**
+	 * add a collection we just loaded up (still needs initializing)
+	 */
+	public void addUninitializedCollection(CollectionPersister persister,
+			PersistentCollection collection, Serializable id);
+
+	/**
+	 * add a detached uninitialized collection
+	 */
+	public void addUninitializedDetachedCollection(CollectionPersister persister,
+			PersistentCollection collection);
+
+	/**
+	 * Add a new collection (ie. a newly created one, just instantiated by the
+	 * application, with no database state or snapshot)
+	 * @param collection The collection to be associated with the persistence context
+	 */
+	public void addNewCollection(CollectionPersister persister, PersistentCollection collection)
+			throws HibernateException;
+
+	/**
+	 * add an (initialized) collection that was created by another session and passed
+	 * into update() (ie. one with a snapshot and existing state on the database)
+	 */
+	public void addInitializedDetachedCollection(CollectionPersister collectionPersister,
+			PersistentCollection collection) throws HibernateException;
+
+	/**
+	 * add a collection we just pulled out of the cache (does not need initializing)
+	 */
+	public CollectionEntry addInitializedCollection(CollectionPersister persister,
+			PersistentCollection collection, Serializable id) throws HibernateException;
+
+	/**
+	 * Get the collection instance associated with the <tt>CollectionKey</tt>
+	 */
+	public PersistentCollection getCollection(CollectionKey collectionKey);
+
+	/**
+	 * Register a collection for non-lazy loading at the end of the
+	 * two-phase load
+	 */
+	public void addNonLazyCollection(PersistentCollection collection);
+
+	/**
+	 * Force initialization of all non-lazy collections encountered during
+	 * the current two-phase load (actually, this is a no-op, unless this
+	 * is the "outermost" load)
+	 */
+	public void initializeNonLazyCollections() throws HibernateException;
+
+	/**
+	 * Get the <tt>PersistentCollection</tt> object for an array
+	 */
+	public PersistentCollection getCollectionHolder(Object array);
+
+	/**
+	 * Register a <tt>PersistentCollection</tt> object for an array.
+	 * Associates a holder with an array - MUST be called after loading 
+	 * array, since the array instance is not created until endLoad().
+	 */
+	public void addCollectionHolder(PersistentCollection holder);
+	
+	/**
+	 * Remove the mapping of collection to holder during eviction
+	 * of the owning entity
+	 */
+	public PersistentCollection removeCollectionHolder(Object array);
+
+	/**
+	 * Get the snapshot of the pre-flush collection state
+	 */
+	public Serializable getSnapshot(PersistentCollection coll);
+
+	/**
+	 * Get the collection entry for a collection passed to filter,
+	 * which might be a collection wrapper, an array, or an unwrapped
+	 * collection. Return null if there is no entry.
+	 */
+	public CollectionEntry getCollectionEntryOrNull(Object collection);
+
+	/**
+	 * Get an existing proxy by key
+	 */
+	public Object getProxy(EntityKey key);
+
+	/**
+	 * Add a proxy to the session cache
+	 */
+	public void addProxy(EntityKey key, Object proxy);
+
+	/**
+	 * Remove a proxy from the session cache
+	 */
+	public Object removeProxy(EntityKey key);
+
+	/** 
+	 * Retrieve the set of EntityKeys representing nullifiable references
+	 */
+	public HashSet getNullifiableEntityKeys();
+
+	/**
+	 * Get the mapping from key value to entity instance
+	 */
+	public Map getEntitiesByKey();
+	
+	/**
+	 * Get the mapping from entity instance to entity entry
+	 */
+	public Map getEntityEntries();
+
+	/**
+	 * Get the mapping from collection instance to collection entry
+	 */
+	public Map getCollectionEntries();
+
+	/**
+	 * Get the mapping from collection key to collection instance
+	 */
+	public Map getCollectionsByKey();
+
+	/**
+	 * How deep are we cascaded?
+	 */
+	public int getCascadeLevel();
+	
+	/**
+	 * Called before cascading
+	 */
+	public int incrementCascadeLevel();
+
+	/**
+	 * Called after cascading
+	 */
+	public int decrementCascadeLevel();
+
+	/**
+	 * Is a flush cycle currently in process?
+	 */
+	public boolean isFlushing();
+	
+	/**
+	 * Called before and after the flushcycle
+	 */
+	public void setFlushing(boolean flushing);
+
+	/**
+	 * Call this before begining a two-phase load
+	 */
+	public void beforeLoad();
+
+	/**
+	 * Call this after finishing a two-phase load
+	 */
+	public void afterLoad();
+
+	/**
+	 * Returns a string representation of the object.
+	 *
+	 * @return a string representation of the object.
+	 */
+	public String toString();
+
+	/**
+	 * Search the persistence context for an owner for the child object,
+	 * given a collection role
+	 */
+	public Serializable getOwnerId(String entity, String property, Object childObject, Map mergeMap);
+
+	/**
+	 * Search the persistence context for an index of the child object,
+	 * given a collection role
+	 */
+	public Object getIndexInOwner(String entity, String property, Object childObject, Map mergeMap);
+
+	/**
+	 * Record the fact that the association belonging to the keyed
+	 * entity is null.
+	 */
+	public void addNullProperty(EntityKey ownerKey, String propertyName);
+
+	/**
+	 * Is the association property belonging to the keyed entity null?
+	 */
+	public boolean isPropertyNull(EntityKey ownerKey, String propertyName);
+	
+	/**
+	 * Set the object to read only and discard it's snapshot
+	 */
+	public void setReadOnly(Object entity, boolean readOnly);
+
+	void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Serializable generatedId);
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/QueryParameters.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/QueryParameters.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/QueryParameters.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,482 @@
+//$Id: QueryParameters.java 9636 2006-03-16 14:14:48Z max.andersen at jboss.com $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.QueryException;
+import org.hibernate.ScrollMode;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.hql.classic.ParserHelper;
+import org.hibernate.pretty.Printer;
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * @author Gavin King
+ */
+public final class QueryParameters {
+	private static final Log log = LogFactory.getLog(QueryParameters.class);
+
+	private Type[] positionalParameterTypes;
+	private Object[] positionalParameterValues;
+	private Map namedParameters;
+	private Map lockModes;
+	private RowSelection rowSelection;
+	private boolean cacheable;
+	private String cacheRegion;
+	private String comment;
+	private ScrollMode scrollMode;
+	private Serializable[] collectionKeys;
+	private Object optionalObject;
+	private String optionalEntityName;
+	private Serializable optionalId;
+	private boolean readOnly;
+	private boolean callable = false;
+	private boolean autodiscovertypes = false;
+	private boolean isNaturalKeyLookup;
+	
+	private final ResultTransformer resultTransformer; // why is all others non final ?
+	
+	private String processedSQL;
+	private Type[] processedPositionalParameterTypes;
+	private Object[] processedPositionalParameterValues;
+	
+	public QueryParameters() {
+		this( ArrayHelper.EMPTY_TYPE_ARRAY, ArrayHelper.EMPTY_OBJECT_ARRAY );
+	}
+
+	public QueryParameters(Type type, Object value) {
+		this( new Type[] {type}, new Object[] {value} );
+	}
+
+	public QueryParameters(
+		final Type[] positionalParameterTypes,
+		final Object[] postionalParameterValues,
+		final Object optionalObject,
+		final String optionalEntityName,
+		final Serializable optionalObjectId
+	) {
+		this(positionalParameterTypes, postionalParameterValues);
+		this.optionalObject = optionalObject;
+		this.optionalId = optionalObjectId;
+		this.optionalEntityName = optionalEntityName;
+
+	}
+
+	public QueryParameters(
+		final Type[] positionalParameterTypes,
+		final Object[] postionalParameterValues
+	) {
+		this(
+			positionalParameterTypes,
+			postionalParameterValues, 
+			null, 
+			null, 
+			false, 
+			null, 
+			null,
+			false,
+			null
+		);
+	}
+
+	public QueryParameters(
+		final Type[] positionalParameterTypes,
+		final Object[] postionalParameterValues,
+		final Serializable[] collectionKeys
+	) {
+		this(
+			positionalParameterTypes,
+			postionalParameterValues,
+			null,
+			collectionKeys
+		);
+	}
+
+	public QueryParameters(
+			final Type[] positionalParameterTypes,
+			final Object[] postionalParameterValues,
+			final Map namedParameters,
+			final Serializable[] collectionKeys
+		) {
+			this(
+				positionalParameterTypes,
+				postionalParameterValues,
+				namedParameters,
+				null,
+				null,
+				false,
+				false,
+				null, 
+				null,
+				collectionKeys,
+				null
+			);
+		}
+
+	public QueryParameters(
+		final Type[] positionalParameterTypes,
+		final Object[] positionalParameterValues,
+		final Map lockModes,
+		final RowSelection rowSelection,
+		final boolean cacheable,
+		final String cacheRegion,
+		//final boolean forceCacheRefresh,
+		final String comment,
+		final boolean isLookupByNaturalKey,
+		final ResultTransformer transformer
+	) {
+		this(
+			positionalParameterTypes,
+			positionalParameterValues,
+			null,
+			lockModes,
+			rowSelection,
+			false,
+			cacheable,
+			cacheRegion, 
+			comment,
+			null,
+			transformer
+		);
+		isNaturalKeyLookup = isLookupByNaturalKey;
+	}
+
+	public QueryParameters(
+			final Type[] positionalParameterTypes,
+			final Object[] positionalParameterValues,
+			final Map namedParameters,
+			final Map lockModes,
+			final RowSelection rowSelection,
+			final boolean readOnly,
+			final boolean cacheable,
+			final String cacheRegion,
+			//final boolean forceCacheRefresh,
+			final String comment,
+			final Serializable[] collectionKeys,
+			ResultTransformer transformer			
+	) {
+		this.positionalParameterTypes = positionalParameterTypes;
+		this.positionalParameterValues = positionalParameterValues;
+		this.namedParameters = namedParameters;
+		this.lockModes = lockModes;
+		this.rowSelection = rowSelection;
+		this.cacheable = cacheable;
+		this.cacheRegion = cacheRegion;
+		//this.forceCacheRefresh = forceCacheRefresh;
+		this.comment = comment;
+		this.collectionKeys = collectionKeys;
+		this.readOnly = readOnly;
+		this.resultTransformer = transformer;
+	}
+	
+	public QueryParameters(
+		final Type[] positionalParameterTypes,
+		final Object[] positionalParameterValues,
+		final Map namedParameters,
+		final Map lockModes,
+		final RowSelection rowSelection,
+		final boolean readOnly,
+		final boolean cacheable,
+		final String cacheRegion,
+		//final boolean forceCacheRefresh,
+		final String comment,
+		final Serializable[] collectionKeys,
+		final Object optionalObject,
+		final String optionalEntityName,
+		final Serializable optionalId,
+		final ResultTransformer transformer
+	) {
+		this(
+			positionalParameterTypes, 
+			positionalParameterValues, 
+			namedParameters, 
+			lockModes, 
+			rowSelection, 
+			readOnly, 
+			cacheable, 
+			cacheRegion,
+			comment,
+			collectionKeys,
+			transformer
+		);
+		this.optionalEntityName = optionalEntityName;
+		this.optionalId = optionalId;
+		this.optionalObject = optionalObject;
+	}
+
+	public boolean hasRowSelection() {
+		return rowSelection!=null;
+	}
+
+	public Map getNamedParameters() {
+		return namedParameters;
+	}
+
+	public Type[] getPositionalParameterTypes() {
+		return positionalParameterTypes;
+	}
+
+	public Object[] getPositionalParameterValues() {
+		return positionalParameterValues;
+	}
+
+	public RowSelection getRowSelection() {
+		return rowSelection;
+	}
+	
+	public ResultTransformer getResultTransformer() {
+		return resultTransformer;
+	}
+
+	public void setNamedParameters(Map map) {
+		namedParameters = map;
+	}
+
+	public void setPositionalParameterTypes(Type[] types) {
+		positionalParameterTypes = types;
+	}
+
+	public void setPositionalParameterValues(Object[] objects) {
+		positionalParameterValues = objects;
+	}
+
+	public void setRowSelection(RowSelection selection) {
+		rowSelection = selection;
+	}
+
+	public Map getLockModes() {
+		return lockModes;
+	}
+
+	public void setLockModes(Map map) {
+		lockModes = map;
+	}
+
+	public void traceParameters(SessionFactoryImplementor factory) throws HibernateException {
+		Printer print = new Printer(factory);
+		if (positionalParameterValues.length!=0) {
+			log.trace(
+					"parameters: " + 
+					print.toString(positionalParameterTypes, positionalParameterValues) 
+				);
+		}
+		if (namedParameters!=null) {
+			log.trace( "named parameters: " + print.toString(namedParameters) );
+		}
+	}
+
+	public boolean isCacheable() {
+		return cacheable;
+	}
+
+	public void setCacheable(boolean b) {
+		cacheable = b;
+	}
+
+	public String getCacheRegion() {
+		return cacheRegion;
+	}
+
+	public void setCacheRegion(String cacheRegion) {
+		this.cacheRegion = cacheRegion;
+	}
+
+	public void validateParameters() throws QueryException {
+		int types = positionalParameterTypes==null ? 0 : positionalParameterTypes.length;
+		int values = positionalParameterValues==null ? 0 : positionalParameterValues.length;
+		if (types!=values) {
+			throw new QueryException(
+					"Number of positional parameter types:" + types + 
+					" does not match number of positional parameters: " + values
+				);
+		}
+	}
+
+	public String getComment() {
+		return comment;
+	}
+
+	public void setComment(String comment) {
+		this.comment = comment;
+	}
+
+	public ScrollMode getScrollMode() {
+		return scrollMode;
+	}
+
+	public void setScrollMode(ScrollMode scrollMode) {
+		this.scrollMode = scrollMode;
+	}
+
+	public Serializable[] getCollectionKeys() {
+		return collectionKeys;
+	}
+
+	public void setCollectionKeys(Serializable[] collectionKeys) {
+		this.collectionKeys = collectionKeys;
+	}
+
+	public String getOptionalEntityName() {
+		return optionalEntityName;
+	}
+
+	public void setOptionalEntityName(String optionalEntityName) {
+		this.optionalEntityName = optionalEntityName;
+	}
+
+	public Serializable getOptionalId() {
+		return optionalId;
+	}
+
+	public void setOptionalId(Serializable optionalId) {
+		this.optionalId = optionalId;
+	}
+
+	public Object getOptionalObject() {
+		return optionalObject;
+	}
+
+	public void setOptionalObject(Object optionalObject) {
+		this.optionalObject = optionalObject;
+	}
+
+	public boolean isReadOnly() {
+		return readOnly;
+	}
+
+	public void setReadOnly(boolean readOnly) {
+		this.readOnly = readOnly;
+	}
+
+	public void setCallable(boolean callable) {
+		this.callable = callable;		
+	}
+
+	public boolean isCallable() {
+		return callable;
+	}
+	
+	public boolean hasAutoDiscoverScalarTypes() {
+		return autodiscovertypes;
+	}
+
+	public void processFilters(String sql, SessionImplementor session) {
+		
+		if ( session.getEnabledFilters().size()==0 || sql.indexOf(ParserHelper.HQL_VARIABLE_PREFIX)<0 ) {
+			// HELLA IMPORTANT OPTIMIZATION!!!
+			processedPositionalParameterValues = getPositionalParameterValues();
+			processedPositionalParameterTypes = getPositionalParameterTypes();
+			processedSQL = sql;
+		}
+		else {
+			
+			Dialect dialect = session.getFactory().getDialect();
+			String symbols = new StringBuffer().append( ParserHelper.HQL_SEPARATORS )
+					.append( dialect.openQuote() )
+					.append( dialect.closeQuote() )
+					.toString();
+			StringTokenizer tokens = new StringTokenizer( sql, symbols, true );
+			StringBuffer result = new StringBuffer();
+		
+			List parameters = new ArrayList();
+			List parameterTypes = new ArrayList();
+		
+			while ( tokens.hasMoreTokens() ) {
+				final String token = tokens.nextToken();
+				if ( token.startsWith( ParserHelper.HQL_VARIABLE_PREFIX ) ) {
+					String filterParameterName = token.substring( 1 );
+					Object value = session.getFilterParameterValue( filterParameterName );
+					Type type = session.getFilterParameterType( filterParameterName );
+					if ( value != null && Collection.class.isAssignableFrom( value.getClass() ) ) {
+						Iterator itr = ( ( Collection ) value ).iterator();
+						while ( itr.hasNext() ) {
+							Object elementValue = itr.next();
+							result.append( '?' );
+							parameters.add( elementValue );
+							parameterTypes.add( type );
+							if ( itr.hasNext() ) {
+								result.append( ", " );
+							}
+						}
+					}
+					else {
+						result.append( '?' );
+						parameters.add( value );
+						parameterTypes.add( type );
+					}
+				}
+				else {
+					result.append( token );
+				}
+			}
+			parameters.addAll( Arrays.asList( getPositionalParameterValues() ) );
+			parameterTypes.addAll( Arrays.asList( getPositionalParameterTypes() ) );
+			processedPositionalParameterValues = parameters.toArray();
+			processedPositionalParameterTypes = ( Type[] ) parameterTypes.toArray( new Type[0] );
+			processedSQL = result.toString();
+			
+		}
+	}
+
+	public String getFilteredSQL() {
+		return processedSQL;
+	}
+
+	public Object[] getFilteredPositionalParameterValues() {
+		return processedPositionalParameterValues;
+	}
+
+	public Type[] getFilteredPositionalParameterTypes() {
+		return processedPositionalParameterTypes;
+	}
+
+	public boolean isNaturalKeyLookup() {
+		return isNaturalKeyLookup;
+	}
+
+	public void setNaturalKeyLookup(boolean isNaturalKeyLookup) {
+		this.isNaturalKeyLookup = isNaturalKeyLookup;
+	}
+
+	public void setAutoDiscoverScalarTypes(boolean autodiscovertypes) {
+		this.autodiscovertypes = autodiscovertypes;
+	}
+
+	public QueryParameters createCopyUsing(RowSelection selection) {
+		QueryParameters copy = new QueryParameters(
+				this.positionalParameterTypes,
+		        this.positionalParameterValues,
+		        this.namedParameters,
+		        this.lockModes,
+	            selection,
+		        this.readOnly,
+		        this.cacheable,
+	            this.cacheRegion,
+		        this.comment,
+		        this.collectionKeys,
+		        this.optionalObject,
+				this.optionalEntityName,
+				this.optionalId,
+				this.resultTransformer
+		);
+		copy.processedSQL = this.processedSQL;
+		copy.processedPositionalParameterTypes = this.processedPositionalParameterTypes;
+		copy.processedPositionalParameterValues = this.processedPositionalParameterValues;
+		return copy;
+	}
+
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ResultSetMappingDefinition.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ResultSetMappingDefinition.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ResultSetMappingDefinition.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+//$Id: ResultSetMappingDefinition.java 10018 2006-06-15 05:21:06Z steve.ebersole at jboss.com $
+package org.hibernate.engine;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.io.Serializable;
+
+import org.hibernate.engine.query.sql.NativeSQLQueryReturn;
+
+/**
+ * Keep a description of the resultset mapping
+ *
+ * @author Emmanuel Bernard
+ */
+public class ResultSetMappingDefinition implements Serializable {
+
+	private final String name;
+	private final List /*NativeSQLQueryReturn*/ queryReturns = new ArrayList();
+
+	public ResultSetMappingDefinition(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void addQueryReturn(NativeSQLQueryReturn queryReturn) {
+		queryReturns.add( queryReturn );
+	}
+
+// We could also keep these if needed for binary compatibility with annotations, provided
+// it only uses the addXXX() methods...
+//	public void addEntityQueryReturn(NativeSQLQueryNonScalarReturn entityQueryReturn) {
+//		entityQueryReturns.add(entityQueryReturn);
+//	}
+//
+//	public void addScalarQueryReturn(NativeSQLQueryScalarReturn scalarQueryReturn) {
+//		scalarQueryReturns.add(scalarQueryReturn);
+//	}
+
+	public NativeSQLQueryReturn[] getQueryReturns() {
+		return ( NativeSQLQueryReturn[] ) queryReturns.toArray( new NativeSQLQueryReturn[0] );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/RowSelection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/RowSelection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/RowSelection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+//$Id: RowSelection.java 9299 2006-02-16 22:51:00Z steveebersole $
+package org.hibernate.engine;
+
+/**
+ * Represents a selection of rows in a JDBC <tt>ResultSet</tt>
+ * @author Gavin King
+ */
+public final class RowSelection {
+	private Integer firstRow;
+	private Integer maxRows;
+	private Integer timeout;
+	private Integer fetchSize;
+
+	public void setFirstRow(Integer firstRow) {
+		this.firstRow = firstRow;
+	}
+
+	public Integer getFirstRow() {
+		return firstRow;
+	}
+
+	public void setMaxRows(Integer maxRows) {
+		this.maxRows = maxRows;
+	}
+
+	public Integer getMaxRows() {
+		return maxRows;
+	}
+
+	public void setTimeout(Integer timeout) {
+		this.timeout = timeout;
+	}
+
+	public Integer getTimeout() {
+		return timeout;
+	}
+
+	public Integer getFetchSize() {
+		return fetchSize;
+	}
+
+	public void setFetchSize(Integer fetchSize) {
+		this.fetchSize = fetchSize;
+	}
+
+	public boolean definesLimits() {
+		return maxRows != null ||
+	           ( firstRow != null && firstRow.intValue() <= 0 );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/SessionFactoryImplementor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/SessionFactoryImplementor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/SessionFactoryImplementor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,200 @@
+//$Id: SessionFactoryImplementor.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.engine;
+
+import java.util.Map;
+import java.util.Set;
+import java.sql.Connection;
+
+import javax.transaction.TransactionManager;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.MappingException;
+import org.hibernate.SessionFactory;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.proxy.EntityNotFoundDelegate;
+import org.hibernate.engine.query.QueryPlanCache;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.cache.QueryCache;
+import org.hibernate.cache.UpdateTimestampsCache;
+import org.hibernate.cache.Region;
+import org.hibernate.cfg.Settings;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.function.SQLFunctionRegistry;
+import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.stat.StatisticsImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Defines the internal contract between the <tt>SessionFactory</tt> and other parts of
+ * Hibernate such as implementors of <tt>Type</tt>.
+ *
+ * @see org.hibernate.SessionFactory
+ * @see org.hibernate.impl.SessionFactoryImpl
+ * @author Gavin King
+ */
+public interface SessionFactoryImplementor extends Mapping, SessionFactory {
+
+	/**
+	 * Get the persister for the named entity
+	 *
+	 * @param entityName The name of the entity for which to retrieve the persister.
+	 * @return The persister
+	 * @throws MappingException Indicates persister could not be found with that name.
+	 */
+	public EntityPersister getEntityPersister(String entityName) throws MappingException;
+
+	/**
+	 * Get the persister object for a collection role.
+	 *
+	 * @param role The role (name) of the collection for which to retrieve the
+	 * persister.
+	 * @return The persister
+	 * @throws MappingException Indicates persister could not be found with that role.
+	 */
+	public CollectionPersister getCollectionPersister(String role) throws MappingException;
+
+	/**
+	 * Get the SQL dialect.
+	 * <p/>
+	 * Shorthand for {@link #getSettings()}.{@link Settings#getDialect()}
+	 *
+	 * @return The dialect
+	 */
+	public Dialect getDialect();
+
+	/**
+	 * Get the factory scoped interceptor for this factory.
+	 *
+	 * @return The factory scope interceptor, or null if none.
+	 */
+	public Interceptor getInterceptor();
+
+	public QueryPlanCache getQueryPlanCache();
+
+	/**
+	 * Get the return types of a query
+	 */
+	public Type[] getReturnTypes(String queryString) throws HibernateException;
+
+	/**
+	 * Get the return aliases of a query
+	 */
+	public String[] getReturnAliases(String queryString) throws HibernateException;
+
+	/**
+	 * Get the connection provider
+	 */
+	public ConnectionProvider getConnectionProvider();
+	/**
+	 * Get the names of all persistent classes that implement/extend the given interface/class
+	 */
+	public String[] getImplementors(String className) throws MappingException;
+	/**
+	 * Get a class name, using query language imports
+	 */
+	public String getImportedClassName(String name);
+
+
+	/**
+	 * Get the JTA transaction manager
+	 */
+	public TransactionManager getTransactionManager();
+
+
+	/**
+	 * Get the default query cache
+	 */
+	public QueryCache getQueryCache();
+	/**
+	 * Get a particular named query cache, or the default cache
+	 * @param regionName the name of the cache region, or null for the default query cache
+	 * @return the existing cache, or a newly created cache if none by that region name
+	 */
+	public QueryCache getQueryCache(String regionName) throws HibernateException;
+	
+	/**
+	 * Get the cache of table update timestamps
+	 */
+	public UpdateTimestampsCache getUpdateTimestampsCache();
+	/**
+	 * Statistics SPI
+	 */
+	public StatisticsImplementor getStatisticsImplementor();
+	
+	public NamedQueryDefinition getNamedQuery(String queryName);
+	public NamedSQLQueryDefinition getNamedSQLQuery(String queryName);
+	public ResultSetMappingDefinition getResultSetMapping(String name);
+
+	/**
+	 * Get the identifier generator for the hierarchy
+	 */
+	public IdentifierGenerator getIdentifierGenerator(String rootEntityName);
+	
+	/**
+	 * Get a named second-level cache region
+	 *
+	 * @param regionName The name of the region to retrieve.
+	 * @return The region
+	 */
+	public Region getSecondLevelCacheRegion(String regionName);
+
+	/**
+	 * Get a map of all the second level cache regions currently maintained in
+	 * this session factory.  The map is structured with the region name as the
+	 * key and the {@link Region} instances as the values.
+	 *
+	 * @return The map of regions
+	 */
+	public Map getAllSecondLevelCacheRegions();
+	
+	/**
+	 * Retrieves the SQLExceptionConverter in effect for this SessionFactory.
+	 *
+	 * @return The SQLExceptionConverter for this SessionFactory.
+	 */
+	public SQLExceptionConverter getSQLExceptionConverter();
+
+	public Settings getSettings();
+
+	/**
+	 * Get a nontransactional "current" session for Hibernate EntityManager
+	 */
+	public org.hibernate.classic.Session openTemporarySession() throws HibernateException;
+
+	/**
+	 * Open a session conforming to the given parameters.  Used mainly by
+	 * {@link org.hibernate.context.JTASessionContext} for current session processing.
+	 *
+	 * @param connection The external jdbc connection to use, if one (i.e., optional).
+	 * @param flushBeforeCompletionEnabled Should the session be auto-flushed
+	 * prior to transaction completion?
+	 * @param autoCloseSessionEnabled Should the session be auto-closed after
+	 * transaction completion?
+	 * @param connectionReleaseMode The release mode for managed jdbc connections.
+	 * @return An appropriate session.
+	 * @throws HibernateException
+	 */
+	public org.hibernate.classic.Session openSession(
+			final Connection connection,
+			final boolean flushBeforeCompletionEnabled,
+			final boolean autoCloseSessionEnabled,
+			final ConnectionReleaseMode connectionReleaseMode) throws HibernateException;
+
+	/**
+	 * Retrieves a set of all the collection roles in which the given entity
+	 * is a participant, as either an index or an element.
+	 *
+	 * @param entityName The entity name for which to get the collection roles.
+	 * @return set of all the collection roles in which the given entityName participates.
+	 */
+	public Set getCollectionRolesByEntityParticipant(String entityName);
+
+	public EntityNotFoundDelegate getEntityNotFoundDelegate();
+
+	public SQLFunctionRegistry getSqlFunctionRegistry();
+		
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/SessionImplementor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/SessionImplementor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/SessionImplementor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,302 @@
+//$Id: SessionImplementor.java 10018 2006-06-15 05:21:06Z steve.ebersole at jboss.com $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.CacheMode;
+import org.hibernate.EntityMode;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.Query;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Transaction;
+import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.event.EventListeners;
+import org.hibernate.impl.CriteriaImpl;
+import org.hibernate.jdbc.Batcher;
+import org.hibernate.jdbc.JDBCContext;
+import org.hibernate.loader.custom.CustomQuery;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.type.Type;
+
+
+/**
+ * Defines the internal contract between the <tt>Session</tt> and other parts of
+ * Hibernate such as implementors of <tt>Type</tt> or <tt>EntityPersister</tt>.
+ *
+ * @see org.hibernate.Session the interface to the application
+ * @see org.hibernate.impl.SessionImpl the actual implementation
+ * @author Gavin King
+ */
+public interface SessionImplementor extends Serializable {
+
+	/**
+	 * Retrieves the interceptor currently in use by this event source.
+	 *
+	 * @return The interceptor.
+	 */
+	public Interceptor getInterceptor();
+	
+	/**
+	 * Enable/disable automatic cache clearing from after transaction
+	 * completion (for EJB3)
+	 */
+	public void setAutoClear(boolean enabled);
+		
+	/**
+	 * Does this <tt>Session</tt> have an active Hibernate transaction
+	 * or is there a JTA transaction in progress?
+	 */
+	public boolean isTransactionInProgress();
+
+	/**
+	 * Initialize the collection (if not already initialized)
+	 */
+	public void initializeCollection(PersistentCollection collection, boolean writing) 
+	throws HibernateException;
+	
+	/**
+	 * Load an instance without checking if it was deleted. 
+	 * 
+	 * When <tt>nullable</tt> is disabled this method may create a new proxy or 
+	 * return an existing proxy; if it does not exist, throw an exception.
+	 * 
+	 * When <tt>nullable</tt> is enabled, the method does not create new proxies 
+	 * (but might return an existing proxy); if it does not exist, return 
+	 * <tt>null</tt>.
+	 * 
+	 * When <tt>eager</tt> is enabled, the object is eagerly fetched
+	 */
+	public Object internalLoad(String entityName, Serializable id, boolean eager, boolean nullable) 
+	throws HibernateException;
+
+	/**
+	 * Load an instance immediately. This method is only called when lazily initializing a proxy.
+	 * Do not return the proxy.
+	 */
+	public Object immediateLoad(String entityName, Serializable id) throws HibernateException;
+
+	/**
+	 * System time before the start of the transaction
+	 */
+	public long getTimestamp();
+	/**
+	 * Get the creating <tt>SessionFactoryImplementor</tt>
+	 */
+	public SessionFactoryImplementor getFactory();
+	/**
+	 * Get the prepared statement <tt>Batcher</tt> for this session
+	 */
+	public Batcher getBatcher();
+	
+	/**
+	 * Execute a <tt>find()</tt> query
+	 */
+	public List list(String query, QueryParameters queryParameters) throws HibernateException;
+	/**
+	 * Execute an <tt>iterate()</tt> query
+	 */
+	public Iterator iterate(String query, QueryParameters queryParameters) throws HibernateException;
+	/**
+	 * Execute a <tt>scroll()</tt> query
+	 */
+	public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException;
+	/**
+	 * Execute a criteria query
+	 */
+	public ScrollableResults scroll(CriteriaImpl criteria, ScrollMode scrollMode);
+	/**
+	 * Execute a criteria query
+	 */
+	public List list(CriteriaImpl criteria);
+	
+	/**
+	 * Execute a filter
+	 */
+	public List listFilter(Object collection, String filter, QueryParameters queryParameters) throws HibernateException;
+	/**
+	 * Iterate a filter
+	 */
+	public Iterator iterateFilter(Object collection, String filter, QueryParameters queryParameters) throws HibernateException;
+	
+	/**
+	 * Get the <tt>EntityPersister</tt> for any instance
+	 * @param entityName optional entity name
+	 * @param object the entity instance
+	 */
+	public EntityPersister getEntityPersister(String entityName, Object object) throws HibernateException;
+	
+	/**
+	 * Get the entity instance associated with the given <tt>Key</tt>,
+	 * calling the Interceptor if necessary
+	 */
+	public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException;
+
+	/**
+	 * Notify the session that the transaction completed, so we no longer
+	 * own the old locks. (Also we should release cache softlocks.) May
+	 * be called multiple times during the transaction completion process.
+	 * Also called after an autocommit, in which case the second argument
+	 * is null.
+	 */
+	public void afterTransactionCompletion(boolean successful, Transaction tx);
+	
+	/**
+	 * Notify the session that the transaction is about to complete
+	 */
+	public void beforeTransactionCompletion(Transaction tx);
+
+	/**
+	 * Return the identifier of the persistent object, or null if 
+	 * not associated with the session
+	 */
+	public Serializable getContextEntityIdentifier(Object object);
+
+	/**
+	 * The best guess entity name for an entity not in an association
+	 */
+	public String bestGuessEntityName(Object object);
+	
+	/**
+	 * The guessed entity name for an entity not in an association
+	 */
+	public String guessEntityName(Object entity) throws HibernateException;
+	
+	/** 
+	 * Instantiate the entity class, initializing with the given identifier
+	 */
+	public Object instantiate(String entityName, Serializable id) throws HibernateException;
+	
+	/**
+	 * Execute an SQL Query
+	 */
+	public List listCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) 
+	throws HibernateException;
+	
+	/**
+	 * Execute an SQL Query
+	 */
+	public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) 
+	throws HibernateException;
+
+	/**
+	 * Execute a native SQL query, and return the results as a fully built list.
+	 *
+	 * @param spec The specification of the native SQL query to execute.
+	 * @param queryParameters The parameters by which to perform the execution.
+	 * @return The result list.
+	 * @throws HibernateException
+	 */
+	public List list(NativeSQLQuerySpecification spec, QueryParameters queryParameters)
+	throws HibernateException;
+
+	/**
+	 * Execute a native SQL query, and return the results as a scrollable result.
+	 *
+	 * @param spec The specification of the native SQL query to execute.
+	 * @param queryParameters The parameters by which to perform the execution.
+	 * @return The resulting scrollable result.
+	 * @throws HibernateException
+	 */
+	public ScrollableResults scroll(NativeSQLQuerySpecification spec, QueryParameters queryParameters)
+	throws HibernateException;
+
+	/**
+	 * Retreive the currently set value for a filter parameter.
+	 *
+	 * @param filterParameterName The filter parameter name in the format
+	 * {FILTER_NAME.PARAMETER_NAME}.
+	 * @return The filter parameter value.
+	 */
+	public Object getFilterParameterValue(String filterParameterName);
+
+	/**
+	 * Retreive the type for a given filter parrameter.
+	 *
+	 * @param filterParameterName The filter parameter name in the format
+	 * {FILTER_NAME.PARAMETER_NAME}.
+	 */
+	public Type getFilterParameterType(String filterParameterName);
+
+	/**
+	 * Return the currently enabled filters.  The filter map is keyed by filter
+	 * name, with values corresponding to the {@link org.hibernate.impl.FilterImpl}
+	 * instance.
+	 * @return The currently enabled filters.
+	 */
+	public Map getEnabledFilters();
+	
+	public int getDontFlushFromFind();
+	
+	/**
+	 * Retrieves the configured event listeners from this event source.
+	 *
+	 * @return The configured event listeners.
+	 */
+	public EventListeners getListeners();
+	
+	//TODO: temporary
+	
+	/**
+	 * Get the persistence context for this session
+	 */
+	public PersistenceContext getPersistenceContext();
+	
+	/**
+	 * Execute a HQL update or delete query
+	 */
+	int executeUpdate(String query, QueryParameters queryParameters) throws HibernateException;
+	
+	/**
+	 * Execute a native SQL update or delete query
+	 */
+	int executeNativeUpdate(NativeSQLQuerySpecification specification, QueryParameters queryParameters) throws HibernateException;
+
+	// copied from Session:
+	
+	public EntityMode getEntityMode();
+	public CacheMode getCacheMode();
+	public void setCacheMode(CacheMode cm);
+	public boolean isOpen();
+	public boolean isConnected();
+	public FlushMode getFlushMode();
+	public void setFlushMode(FlushMode fm);
+	public Connection connection();
+	public void flush();
+	
+	/**
+	 * Get a Query instance for a named query or named native SQL query
+	 */
+	public Query getNamedQuery(String name);
+	/**
+	 * Get a Query instance for a named native SQL query
+	 */
+	public Query getNamedSQLQuery(String name);
+	
+	public boolean isEventSource();
+
+	public void afterScrollOperation();
+
+	public void setFetchProfile(String name);
+
+	public String getFetchProfile();
+
+	public JDBCContext getJDBCContext();
+
+	/**
+	 * Determine whether the session is closed.  Provided seperately from
+	 * {@link #isOpen()} as this method does not attempt any JTA synch
+	 * registration, where as {@link #isOpen()} does; which makes this one
+	 * nicer to use for most internal purposes.
+	 *
+	 * @return True if the session is closed; false otherwise.
+	 */
+	public boolean isClosed();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/StatefulPersistenceContext.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1363 @@
+// $Id: StatefulPersistenceContext.java 11490 2007-05-09 01:43:11Z steve.ebersole at jboss.com $
+package org.hibernate.engine;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections.ReferenceMap;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.NonUniqueObjectException;
+import org.hibernate.PersistentObjectException;
+import org.hibernate.TransientObjectException;
+import org.hibernate.engine.loading.LoadContexts;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+import org.hibernate.tuple.ElementWrapper;
+import org.hibernate.util.IdentityMap;
+import org.hibernate.util.MarkerObject;
+
+/**
+ * A <tt>PersistenceContext</tt> represents the state of persistent "stuff" which
+ * Hibernate is tracking.  This includes persistent entities, collections,
+ * as well as proxies generated.
+ * </p>
+ * There is meant to be a one-to-one correspondence between a SessionImpl and
+ * a PersistentContext.  The SessionImpl uses the PersistentContext to track
+ * the current state of its context.  Event-listeners then use the
+ * PersistentContext to drive their processing.
+ *
+ * @author Steve Ebersole
+ */
+public class StatefulPersistenceContext implements PersistenceContext {
+
+	public static final Object NO_ROW = new MarkerObject( "NO_ROW" );
+
+	private static final Log log = LogFactory.getLog( StatefulPersistenceContext.class );
+	private static final Log PROXY_WARN_LOG = LogFactory.getLog( StatefulPersistenceContext.class.getName() + ".ProxyWarnLog" );
+	private static final int INIT_COLL_SIZE = 8;
+
+	private SessionImplementor session;
+	
+	// Loaded entity instances, by EntityKey
+	private Map entitiesByKey;
+
+	// Loaded entity instances, by EntityUniqueKey
+	private Map entitiesByUniqueKey;
+	
+	// Identity map of EntityEntry instances, by the entity instance
+	private Map entityEntries;
+	
+	// Entity proxies, by EntityKey
+	private Map proxiesByKey;
+	
+	// Snapshots of current database state for entities
+	// that have *not* been loaded
+	private Map entitySnapshotsByKey;
+	
+	// Identity map of array holder ArrayHolder instances, by the array instance
+	private Map arrayHolders;
+	
+	// Identity map of CollectionEntry instances, by the collection wrapper
+	private Map collectionEntries;
+	
+	// Collection wrappers, by the CollectionKey
+	private Map collectionsByKey; //key=CollectionKey, value=PersistentCollection
+	
+	// Set of EntityKeys of deleted objects
+	private HashSet nullifiableEntityKeys;
+	
+	// properties that we have tried to load, and not found in the database
+	private HashSet nullAssociations;
+	
+	// A list of collection wrappers that were instantiating during result set
+	// processing, that we will need to initialize at the end of the query
+	private List nonlazyCollections;
+	
+	// A container for collections we load up when the owning entity is not
+	// yet loaded ... for now, this is purely transient!
+	private Map unownedCollections;
+	
+	private int cascading = 0;
+	private int loadCounter = 0;
+	private boolean flushing = false;
+	
+	private boolean hasNonReadOnlyEntities = false;
+
+	private LoadContexts loadContexts;
+	private BatchFetchQueue batchFetchQueue;
+
+
+
+	/**
+	 * Constructs a PersistentContext, bound to the given session.
+	 *
+	 * @param session The session "owning" this context.
+	 */
+	public StatefulPersistenceContext(SessionImplementor session) {
+		this.session = session;
+
+		entitiesByKey = new HashMap( INIT_COLL_SIZE );
+		entitiesByUniqueKey = new HashMap( INIT_COLL_SIZE );
+		proxiesByKey = new ReferenceMap( ReferenceMap.HARD, ReferenceMap.WEAK );
+		entitySnapshotsByKey = new HashMap( INIT_COLL_SIZE );
+
+		entityEntries = IdentityMap.instantiateSequenced( INIT_COLL_SIZE );
+		collectionEntries = IdentityMap.instantiateSequenced( INIT_COLL_SIZE );
+		collectionsByKey = new HashMap( INIT_COLL_SIZE );
+		arrayHolders = IdentityMap.instantiate( INIT_COLL_SIZE );
+
+		nullifiableEntityKeys = new HashSet();
+
+		initTransientState();
+	}
+
+	private void initTransientState() {
+		nullAssociations = new HashSet( INIT_COLL_SIZE );
+		nonlazyCollections = new ArrayList( INIT_COLL_SIZE );
+	}
+
+	public boolean isStateless() {
+		return false;
+	}
+	
+	public SessionImplementor getSession() {
+		return session;
+	}
+
+	public LoadContexts getLoadContexts() {
+		if ( loadContexts == null ) {
+			loadContexts = new LoadContexts( this );
+		}
+		return loadContexts;
+	}
+
+	public void addUnownedCollection(CollectionKey key, PersistentCollection collection) {
+		if (unownedCollections==null) {
+			unownedCollections = new HashMap(8);
+		}
+		unownedCollections.put(key, collection);
+	}
+	
+	public PersistentCollection useUnownedCollection(CollectionKey key) {
+		if (unownedCollections==null) {
+			return null;
+		}
+		else {
+			return (PersistentCollection) unownedCollections.remove(key);
+		}
+	}
+	
+	/**
+	 * Get the <tt>BatchFetchQueue</tt>, instantiating one if
+	 * necessary.
+	 */
+	public BatchFetchQueue getBatchFetchQueue() {
+		if (batchFetchQueue==null) {
+			batchFetchQueue = new BatchFetchQueue(this);
+		}
+		return batchFetchQueue;
+	}
+
+	public void clear() {
+		Iterator itr = proxiesByKey.values().iterator();
+		while ( itr.hasNext() ) {
+			final LazyInitializer li = ( ( HibernateProxy ) itr.next() ).getHibernateLazyInitializer();
+			li.setSession( null );
+		}
+		Map.Entry[] collectionEntryArray = IdentityMap.concurrentEntries( collectionEntries );
+		for ( int i = 0; i < collectionEntryArray.length; i++ ) {
+			( ( PersistentCollection ) collectionEntryArray[i].getKey() ).unsetSession( getSession() );
+		}
+		arrayHolders.clear();
+		entitiesByKey.clear();
+		entitiesByUniqueKey.clear();
+		entityEntries.clear();
+		entitySnapshotsByKey.clear();
+		collectionsByKey.clear();
+		collectionEntries.clear();
+		if ( unownedCollections != null ) {
+			unownedCollections.clear();
+		}
+		proxiesByKey.clear();
+		nullifiableEntityKeys.clear();
+		if ( batchFetchQueue != null ) {
+			batchFetchQueue.clear();
+		}
+		hasNonReadOnlyEntities = false;
+	}
+	
+	public boolean hasNonReadOnlyEntities() {
+		return hasNonReadOnlyEntities;
+	}
+	
+	public void setEntryStatus(EntityEntry entry, Status status) {
+		entry.setStatus(status);
+		setHasNonReadOnlyEnties(status);
+	}
+	
+	private void setHasNonReadOnlyEnties(Status status) {
+		if ( status==Status.DELETED || status==Status.MANAGED || status==Status.SAVING ) {
+			hasNonReadOnlyEntities = true;
+		}
+	}
+
+	public void afterTransactionCompletion() {
+		// Downgrade locks
+		Iterator iter = entityEntries.values().iterator();
+		while ( iter.hasNext() ) {
+			( (EntityEntry) iter.next() ).setLockMode(LockMode.NONE);
+		}
+	}
+
+	/**
+	 * Get the current state of the entity as known to the underlying
+	 * database, or null if there is no corresponding row 
+	 */
+	public Object[] getDatabaseSnapshot(Serializable id, EntityPersister persister)
+	throws HibernateException {
+		EntityKey key = new EntityKey( id, persister, session.getEntityMode() );
+		Object cached = entitySnapshotsByKey.get(key);
+		if (cached!=null) {
+			return cached==NO_ROW ? null : (Object[]) cached;
+		}
+		else {
+			Object[] snapshot = persister.getDatabaseSnapshot( id, session );
+			entitySnapshotsByKey.put( key, snapshot==null ? NO_ROW : snapshot );
+			return snapshot;
+		}
+	}
+
+	public Object[] getNaturalIdSnapshot(Serializable id, EntityPersister persister)
+	throws HibernateException {
+		if ( !persister.hasNaturalIdentifier() ) {
+			return null;
+		}
+
+		// if the natural-id is marked as non-mutable, it is not retrieved during a
+		// normal database-snapshot operation...
+		int[] props = persister.getNaturalIdentifierProperties();
+		boolean[] updateable = persister.getPropertyUpdateability();
+		boolean allNatualIdPropsAreUpdateable = true;
+		for ( int i = 0; i < props.length; i++ ) {
+			if ( !updateable[ props[i] ] ) {
+				allNatualIdPropsAreUpdateable = false;
+				break;
+			}
+		}
+
+		if ( allNatualIdPropsAreUpdateable ) {
+			// do this when all the properties are updateable since there is
+			// a certain likelihood that the information will already be
+			// snapshot-cached.
+			Object[] entitySnapshot = getDatabaseSnapshot( id, persister );
+			if ( entitySnapshot == NO_ROW ) {
+				return null;
+			}
+			Object[] naturalIdSnapshot = new Object[ props.length ];
+			for ( int i = 0; i < props.length; i++ ) {
+				naturalIdSnapshot[i] = entitySnapshot[ props[i] ];
+			}
+			return naturalIdSnapshot;
+		}
+		else {
+			return persister.getNaturalIdentifierSnapshot( id, session );
+		}
+	}
+
+	/**
+	 * Retrieve the cached database snapshot for the requested entity key.
+	 * <p/>
+	 * This differs from {@link #getDatabaseSnapshot} is two important respects:<ol>
+	 * <li>no snapshot is obtained from the database if not already cached</li>
+	 * <li>an entry of {@link #NO_ROW} here is interpretet as an exception</li>
+	 * </ol>
+	 * @param key The entity key for which to retrieve the cached snapshot
+	 * @return The cached snapshot
+	 * @throws IllegalStateException if the cached snapshot was == {@link #NO_ROW}.
+	 */
+	public Object[] getCachedDatabaseSnapshot(EntityKey key) {
+		Object snapshot = entitySnapshotsByKey.get( key );
+		if ( snapshot == NO_ROW ) {
+			throw new IllegalStateException( "persistence context reported no row snapshot for " + MessageHelper.infoString( key.getEntityName(), key.getIdentifier() ) );
+		}
+		return ( Object[] ) snapshot;
+	}
+
+	/*public void removeDatabaseSnapshot(EntityKey key) {
+		entitySnapshotsByKey.remove(key);
+	}*/
+
+	public void addEntity(EntityKey key, Object entity) {
+		entitiesByKey.put(key, entity);
+		getBatchFetchQueue().removeBatchLoadableEntityKey(key);
+	}
+
+	/**
+	 * Get the entity instance associated with the given 
+	 * <tt>EntityKey</tt>
+	 */
+	public Object getEntity(EntityKey key) {
+		return entitiesByKey.get(key);
+	}
+
+	public boolean containsEntity(EntityKey key) {
+		return entitiesByKey.containsKey(key);
+	}
+
+	/**
+	 * Remove an entity from the session cache, also clear
+	 * up other state associated with the entity, all except
+	 * for the <tt>EntityEntry</tt>
+	 */
+	public Object removeEntity(EntityKey key) {
+		Object entity = entitiesByKey.remove(key);
+		Iterator iter = entitiesByUniqueKey.values().iterator();
+		while ( iter.hasNext() ) {
+			if ( iter.next()==entity ) iter.remove();
+		}
+		entitySnapshotsByKey.remove(key);
+		nullifiableEntityKeys.remove(key);
+		getBatchFetchQueue().removeBatchLoadableEntityKey(key);
+		getBatchFetchQueue().removeSubselect(key);
+		return entity;
+	}
+
+	/**
+	 * Get an entity cached by unique key
+	 */
+	public Object getEntity(EntityUniqueKey euk) {
+		return entitiesByUniqueKey.get(euk);
+	}
+
+	/**
+	 * Add an entity to the cache by unique key
+	 */
+	public void addEntity(EntityUniqueKey euk, Object entity) {
+		entitiesByUniqueKey.put(euk, entity);
+	}
+
+	/**
+	 * Retreive the EntityEntry representation of the given entity.
+	 *
+	 * @param entity The entity for which to locate the EntityEntry.
+	 * @return The EntityEntry for the given entity.
+	 */
+	public EntityEntry getEntry(Object entity) {
+		return (EntityEntry) entityEntries.get(entity);
+	}
+
+	/**
+	 * Remove an entity entry from the session cache
+	 */
+	public EntityEntry removeEntry(Object entity) {
+		return (EntityEntry) entityEntries.remove(entity);
+	}
+
+	/**
+	 * Is there an EntityEntry for this instance?
+	 */
+	public boolean isEntryFor(Object entity) {
+		return entityEntries.containsKey(entity);
+	}
+
+	/**
+	 * Get the collection entry for a persistent collection
+	 */
+	public CollectionEntry getCollectionEntry(PersistentCollection coll) {
+		return (CollectionEntry) collectionEntries.get(coll);
+	}
+
+	/**
+	 * Adds an entity to the internal caches.
+	 */
+	public EntityEntry addEntity(
+			final Object entity,
+			final Status status,
+			final Object[] loadedState,
+			final EntityKey entityKey,
+			final Object version,
+			final LockMode lockMode,
+			final boolean existsInDatabase,
+			final EntityPersister persister,
+			final boolean disableVersionIncrement, 
+			boolean lazyPropertiesAreUnfetched
+	) {
+		
+		addEntity( entityKey, entity );
+		
+		return addEntry(
+				entity,
+				status,
+				loadedState,
+				null,
+				entityKey.getIdentifier(),
+				version,
+				lockMode,
+				existsInDatabase,
+				persister,
+				disableVersionIncrement, 
+				lazyPropertiesAreUnfetched
+			);
+	}
+
+
+	/**
+	 * Generates an appropriate EntityEntry instance and adds it 
+	 * to the event source's internal caches.
+	 */
+	public EntityEntry addEntry(
+			final Object entity,
+			final Status status,
+			final Object[] loadedState,
+			final Object rowId,
+			final Serializable id,
+			final Object version,
+			final LockMode lockMode,
+			final boolean existsInDatabase,
+			final EntityPersister persister,
+			final boolean disableVersionIncrement, 
+			boolean lazyPropertiesAreUnfetched) {
+		
+		EntityEntry e = new EntityEntry(
+				status,
+				loadedState,
+				rowId,
+				id,
+				version,
+				lockMode,
+				existsInDatabase,
+				persister,
+				session.getEntityMode(),
+				disableVersionIncrement,
+				lazyPropertiesAreUnfetched
+			);
+		entityEntries.put(entity, e);
+		
+		setHasNonReadOnlyEnties(status);
+		return e;
+	}
+
+	public boolean containsCollection(PersistentCollection collection) {
+		return collectionEntries.containsKey(collection);
+	}
+
+	public boolean containsProxy(Object entity) {
+		return proxiesByKey.containsValue( entity );
+	}
+	
+	/**
+	 * Takes the given object and, if it represents a proxy, reassociates it with this event source.
+	 *
+	 * @param value The possible proxy to be reassociated.
+	 * @return Whether the passed value represented an actual proxy which got initialized.
+	 * @throws MappingException
+	 */
+	public boolean reassociateIfUninitializedProxy(Object value) throws MappingException {
+		if ( value instanceof ElementWrapper ) {
+			value = ( (ElementWrapper) value ).getElement();
+		}
+		
+		if ( !Hibernate.isInitialized(value) ) {
+			HibernateProxy proxy = (HibernateProxy) value;
+			LazyInitializer li = proxy.getHibernateLazyInitializer();
+			reassociateProxy(li, proxy);
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * If a deleted entity instance is re-saved, and it has a proxy, we need to
+	 * reset the identifier of the proxy 
+	 */
+	public void reassociateProxy(Object value, Serializable id) throws MappingException {
+		if ( value instanceof ElementWrapper ) {
+			value = ( (ElementWrapper) value ).getElement();
+		}
+		
+		if ( value instanceof HibernateProxy ) {
+			if ( log.isDebugEnabled() ) log.debug("setting proxy identifier: " + id);
+			HibernateProxy proxy = (HibernateProxy) value;
+			LazyInitializer li = proxy.getHibernateLazyInitializer();
+			li.setIdentifier(id);
+			reassociateProxy(li, proxy);
+		}
+	}
+
+	/**
+	 * Associate a proxy that was instantiated by another session with this session
+	 *
+	 * @param li The proxy initializer.
+	 * @param proxy The proxy to reassociate.
+	 */
+	private void reassociateProxy(LazyInitializer li, HibernateProxy proxy) {
+		if ( li.getSession() != this.getSession() ) {
+			EntityPersister persister = session.getFactory().getEntityPersister( li.getEntityName() );
+			EntityKey key = new EntityKey( li.getIdentifier(), persister, session.getEntityMode() );
+		  	// any earlier proxy takes precedence
+			if ( !proxiesByKey.containsKey( key ) ) {
+				proxiesByKey.put( key, proxy );
+			}
+			proxy.getHibernateLazyInitializer().setSession( session );
+		}
+	}
+
+	/**
+	 * Get the entity instance underlying the given proxy, throwing
+	 * an exception if the proxy is uninitialized. If the given object
+	 * is not a proxy, simply return the argument.
+	 */
+	public Object unproxy(Object maybeProxy) throws HibernateException {
+		if ( maybeProxy instanceof ElementWrapper ) {
+			maybeProxy = ( (ElementWrapper) maybeProxy ).getElement();
+		}
+		
+		if ( maybeProxy instanceof HibernateProxy ) {
+			HibernateProxy proxy = (HibernateProxy) maybeProxy;
+			LazyInitializer li = proxy.getHibernateLazyInitializer();
+			if ( li.isUninitialized() ) {
+				throw new PersistentObjectException(
+						"object was an uninitialized proxy for " +
+						li.getEntityName()
+				);
+			}
+			return li.getImplementation(); //unwrap the object
+		}
+		else {
+			return maybeProxy;
+		}
+	}
+
+	/**
+	 * Possibly unproxy the given reference and reassociate it with the current session.
+	 *
+	 * @param maybeProxy The reference to be unproxied if it currently represents a proxy.
+	 * @return The unproxied instance.
+	 * @throws HibernateException
+	 */
+	public Object unproxyAndReassociate(Object maybeProxy) throws HibernateException {
+		if ( maybeProxy instanceof ElementWrapper ) {
+			maybeProxy = ( (ElementWrapper) maybeProxy ).getElement();
+		}
+		
+		if ( maybeProxy instanceof HibernateProxy ) {
+			HibernateProxy proxy = (HibernateProxy) maybeProxy;
+			LazyInitializer li = proxy.getHibernateLazyInitializer();
+			reassociateProxy(li, proxy);
+			return li.getImplementation(); //initialize + unwrap the object
+		}
+		else {
+			return maybeProxy;
+		}
+	}
+
+	/**
+	 * Attempts to check whether the given key represents an entity already loaded within the
+	 * current session.
+	 * @param object The entity reference against which to perform the uniqueness check.
+	 * @throws HibernateException
+	 */
+	public void checkUniqueness(EntityKey key, Object object) throws HibernateException {
+		Object entity = getEntity(key);
+		if ( entity == object ) {
+			throw new AssertionFailure( "object already associated, but no entry was found" );
+		}
+		if ( entity != null ) {
+			throw new NonUniqueObjectException( key.getIdentifier(), key.getEntityName() );
+		}
+	}
+
+	/**
+	 * If the existing proxy is insufficiently "narrow" (derived), instantiate a new proxy
+	 * and overwrite the registration of the old one. This breaks == and occurs only for
+	 * "class" proxies rather than "interface" proxies. Also init the proxy to point to
+	 * the given target implementation if necessary.
+	 *
+	 * @param proxy The proxy instance to be narrowed.
+	 * @param persister The persister for the proxied entity.
+	 * @param key The internal cache key for the proxied entity.
+	 * @param object (optional) the actual proxied entity instance.
+	 * @return An appropriately narrowed instance.
+	 * @throws HibernateException
+	 */
+	public Object narrowProxy(Object proxy, EntityPersister persister, EntityKey key, Object object)
+	throws HibernateException {
+		
+		boolean alreadyNarrow = persister.getConcreteProxyClass( session.getEntityMode() )
+				.isAssignableFrom( proxy.getClass() );
+		
+		if ( !alreadyNarrow ) {
+			if ( PROXY_WARN_LOG.isWarnEnabled() ) {
+				PROXY_WARN_LOG.warn(
+						"Narrowing proxy to " +
+						persister.getConcreteProxyClass( session.getEntityMode() ) +
+						" - this operation breaks =="
+				);
+			}
+
+			if ( object != null ) {
+				proxiesByKey.remove(key);
+				return object; //return the proxied object
+			}
+			else {
+				proxy = persister.createProxy( key.getIdentifier(), session );
+				proxiesByKey.put(key, proxy); //overwrite old proxy
+				return proxy;
+			}
+			
+		}
+		else {
+			
+			if ( object != null ) {
+				LazyInitializer li = ( (HibernateProxy) proxy ).getHibernateLazyInitializer();
+				li.setImplementation(object);
+			}
+			
+			return proxy;
+			
+		}
+		
+	}
+
+	/**
+	 * Return the existing proxy associated with the given <tt>EntityKey</tt>, or the
+	 * third argument (the entity associated with the key) if no proxy exists. Init
+	 * the proxy to the target implementation, if necessary.
+	 */
+	public Object proxyFor(EntityPersister persister, EntityKey key, Object impl) 
+	throws HibernateException {
+		if ( !persister.hasProxy() ) return impl;
+		Object proxy = proxiesByKey.get(key);
+		if ( proxy != null ) {
+			return narrowProxy(proxy, persister, key, impl);
+		}
+		else {
+			return impl;
+		}
+	}
+
+	/**
+	 * Return the existing proxy associated with the given <tt>EntityKey</tt>, or the
+	 * argument (the entity associated with the key) if no proxy exists.
+	 * (slower than the form above)
+	 */
+	public Object proxyFor(Object impl) throws HibernateException {
+		EntityEntry e = getEntry(impl);
+		EntityPersister p = e.getPersister();
+		return proxyFor( p, new EntityKey( e.getId(), p, session.getEntityMode() ), impl );
+	}
+
+	/**
+	 * Get the entity that owns this persistent collection
+	 */
+	public Object getCollectionOwner(Serializable key, CollectionPersister collectionPersister) throws MappingException {
+		return getEntity( new EntityKey( key, collectionPersister.getOwnerEntityPersister(), session.getEntityMode() ) );
+	}
+
+	/**
+	 * add a collection we just loaded up (still needs initializing)
+	 */
+	public void addUninitializedCollection(CollectionPersister persister, PersistentCollection collection, Serializable id) {
+		CollectionEntry ce = new CollectionEntry(collection, persister, id, flushing);
+		addCollection(collection, ce, id);
+	}
+
+	/**
+	 * add a detached uninitialized collection
+	 */
+	public void addUninitializedDetachedCollection(CollectionPersister persister, PersistentCollection collection) {
+		CollectionEntry ce = new CollectionEntry( persister, collection.getKey() );
+		addCollection( collection, ce, collection.getKey() );
+	}
+
+	/**
+	 * Add a new collection (ie. a newly created one, just instantiated by the
+	 * application, with no database state or snapshot)
+	 * @param collection The collection to be associated with the persistence context
+	 */
+	public void addNewCollection(CollectionPersister persister, PersistentCollection collection)
+	throws HibernateException {
+		addCollection(collection, persister);
+	}
+
+	/**
+	 * Add an collection to the cache, with a given collection entry.
+	 *
+	 * @param coll The collection for which we are adding an entry.
+	 * @param entry The entry representing the collection.
+	 * @param key The key of the collection's entry.
+	 */
+	private void addCollection(PersistentCollection coll, CollectionEntry entry, Serializable key) {
+		collectionEntries.put( coll, entry );
+		CollectionKey collectionKey = new CollectionKey( entry.getLoadedPersister(), key, session.getEntityMode() );
+		PersistentCollection old = ( PersistentCollection ) collectionsByKey.put( collectionKey, coll );
+		if ( old != null ) {
+			if ( old == coll ) {
+				throw new AssertionFailure("bug adding collection twice");
+			}
+			// or should it actually throw an exception?
+			old.unsetSession( session );
+			collectionEntries.remove( old );
+			// watch out for a case where old is still referenced
+			// somewhere in the object graph! (which is a user error)
+		}
+	}
+
+	/**
+	 * Add a collection to the cache, creating a new collection entry for it
+	 *
+	 * @param collection The collection for which we are adding an entry.
+	 * @param persister The collection persister
+	 */
+	private void addCollection(PersistentCollection collection, CollectionPersister persister) {
+		CollectionEntry ce = new CollectionEntry( persister, collection );
+		collectionEntries.put( collection, ce );
+	}
+
+	/**
+	 * add an (initialized) collection that was created by another session and passed
+	 * into update() (ie. one with a snapshot and existing state on the database)
+	 */
+	public void addInitializedDetachedCollection(CollectionPersister collectionPersister, PersistentCollection collection) 
+	throws HibernateException {
+		if ( collection.isUnreferenced() ) {
+			//treat it just like a new collection
+			addCollection( collection, collectionPersister );
+		}
+		else {
+			CollectionEntry ce = new CollectionEntry( collection, session.getFactory() );
+			addCollection( collection, ce, collection.getKey() );
+		}
+	}
+
+	/**
+	 * add a collection we just pulled out of the cache (does not need initializing)
+	 */
+	public CollectionEntry addInitializedCollection(CollectionPersister persister, PersistentCollection collection, Serializable id)
+	throws HibernateException {
+		CollectionEntry ce = new CollectionEntry(collection, persister, id, flushing);
+		ce.postInitialize(collection);
+		addCollection(collection, ce, id);
+		return ce;
+	}
+	
+	/**
+	 * Get the collection instance associated with the <tt>CollectionKey</tt>
+	 */
+	public PersistentCollection getCollection(CollectionKey collectionKey) {
+		return (PersistentCollection) collectionsByKey.get(collectionKey);
+	}
+	
+	/**
+	 * Register a collection for non-lazy loading at the end of the
+	 * two-phase load
+	 */
+	public void addNonLazyCollection(PersistentCollection collection) {
+		nonlazyCollections.add(collection);
+	}
+
+	/**
+	 * Force initialization of all non-lazy collections encountered during
+	 * the current two-phase load (actually, this is a no-op, unless this
+	 * is the "outermost" load)
+	 */
+	public void initializeNonLazyCollections() throws HibernateException {
+		if ( loadCounter == 0 ) {
+			log.debug( "initializing non-lazy collections" );
+			//do this work only at the very highest level of the load
+			loadCounter++; //don't let this method be called recursively
+			try {
+				int size;
+				while ( ( size = nonlazyCollections.size() ) > 0 ) {
+					//note that each iteration of the loop may add new elements
+					( (PersistentCollection) nonlazyCollections.remove( size - 1 ) ).forceInitialization();
+				}
+			}
+			finally {
+				loadCounter--;
+				clearNullProperties();
+			}
+		}
+	}
+
+
+	/**
+	 * Get the <tt>PersistentCollection</tt> object for an array
+	 */
+	public PersistentCollection getCollectionHolder(Object array) {
+		return (PersistentCollection) arrayHolders.get(array);
+	}
+
+	/**
+	 * Register a <tt>PersistentCollection</tt> object for an array.
+	 * Associates a holder with an array - MUST be called after loading 
+	 * array, since the array instance is not created until endLoad().
+	 */
+	public void addCollectionHolder(PersistentCollection holder) {
+		//TODO:refactor + make this method private
+		arrayHolders.put( holder.getValue(), holder );
+	}
+
+	public PersistentCollection removeCollectionHolder(Object array) {
+		return (PersistentCollection) arrayHolders.remove(array);
+	}
+
+	/**
+	 * Get the snapshot of the pre-flush collection state
+	 */
+	public Serializable getSnapshot(PersistentCollection coll) {
+		return getCollectionEntry(coll).getSnapshot();
+	}
+
+	/**
+	 * Get the collection entry for a collection passed to filter,
+	 * which might be a collection wrapper, an array, or an unwrapped
+	 * collection. Return null if there is no entry.
+	 */
+	public CollectionEntry getCollectionEntryOrNull(Object collection) {
+		PersistentCollection coll;
+		if ( collection instanceof PersistentCollection ) {
+			coll = (PersistentCollection) collection;
+			//if (collection==null) throw new TransientObjectException("Collection was not yet persistent");
+		}
+		else {
+			coll = getCollectionHolder(collection);
+			if ( coll == null ) {
+				//it might be an unwrapped collection reference!
+				//try to find a wrapper (slowish)
+				Iterator wrappers = IdentityMap.keyIterator(collectionEntries);
+				while ( wrappers.hasNext() ) {
+					PersistentCollection pc = (PersistentCollection) wrappers.next();
+					if ( pc.isWrapper(collection) ) {
+						coll = pc;
+						break;
+					}
+				}
+			}
+		}
+
+		return (coll == null) ? null : getCollectionEntry(coll);
+	}
+
+	/**
+	 * Get an existing proxy by key
+	 */
+	public Object getProxy(EntityKey key) {
+		return proxiesByKey.get(key);
+	}
+
+	/**
+	 * Add a proxy to the session cache
+	 */
+	public void addProxy(EntityKey key, Object proxy) {
+		proxiesByKey.put(key, proxy);
+	}
+
+	/**
+	 * Remove a proxy from the session cache.
+	 * <p/>
+	 * Additionally, ensure that any load optimization references
+	 * such as batch or subselect loading get cleaned up as well.
+	 *
+	 * @param key The key of the entity proxy to be removed
+	 * @return The proxy reference.
+	 */
+	public Object removeProxy(EntityKey key) {
+		if ( batchFetchQueue != null ) {
+			batchFetchQueue.removeBatchLoadableEntityKey( key );
+			batchFetchQueue.removeSubselect( key );
+		}
+		return proxiesByKey.remove( key );
+	}
+
+	/**
+	 * Record the fact that an entity does not exist in the database
+	 * 
+	 * @param key the primary key of the entity
+	 */
+	/*public void addNonExistantEntityKey(EntityKey key) {
+		nonExistantEntityKeys.add(key);
+	}*/
+
+	/**
+	 * Record the fact that an entity does not exist in the database
+	 * 
+	 * @param key a unique key of the entity
+	 */
+	/*public void addNonExistantEntityUniqueKey(EntityUniqueKey key) {
+		nonExistentEntityUniqueKeys.add(key);
+	}*/
+
+	/*public void removeNonExist(EntityKey key) {
+		nonExistantEntityKeys.remove(key);
+	}*/
+
+	/** 
+	 * Retrieve the set of EntityKeys representing nullifiable references
+	 */
+	public HashSet getNullifiableEntityKeys() {
+		return nullifiableEntityKeys;
+	}
+
+	public Map getEntitiesByKey() {
+		return entitiesByKey;
+	}
+
+	public Map getEntityEntries() {
+		return entityEntries;
+	}
+
+	public Map getCollectionEntries() {
+		return collectionEntries;
+	}
+
+	public Map getCollectionsByKey() {
+		return collectionsByKey;
+	}
+
+	/**
+	 * Do we already know that the entity does not exist in the
+	 * database?
+	 */
+	/*public boolean isNonExistant(EntityKey key) {
+		return nonExistantEntityKeys.contains(key);
+	}*/
+
+	/**
+	 * Do we already know that the entity does not exist in the
+	 * database?
+	 */
+	/*public boolean isNonExistant(EntityUniqueKey key) {
+		return nonExistentEntityUniqueKeys.contains(key);
+	}*/
+
+	public int getCascadeLevel() {
+		return cascading;
+	}
+
+	public int incrementCascadeLevel() {
+		return ++cascading;
+	}
+
+	public int decrementCascadeLevel() {
+		return --cascading;
+	}
+
+	public boolean isFlushing() {
+		return flushing;
+	}
+
+	public void setFlushing(boolean flushing) {
+		this.flushing = flushing;
+	}
+
+	/**
+	 * Call this before begining a two-phase load
+	 */
+	public void beforeLoad() {
+		loadCounter++;
+	}
+
+	/**
+	 * Call this after finishing a two-phase load
+	 */
+	public void afterLoad() {
+		loadCounter--;
+	}
+
+	/**
+	 * Returns a string representation of the object.
+	 *
+	 * @return a string representation of the object.
+	 */
+	public String toString() {
+		return new StringBuffer()
+				.append("PersistenceContext[entityKeys=")
+				.append(entitiesByKey.keySet())
+				.append(",collectionKeys=")
+				.append(collectionsByKey.keySet())
+				.append("]")
+				.toString();
+	}
+	
+	/**
+	 * Search the persistence context for an owner for the child object,
+	 * given a collection role. If <tt>mergeMap</tt> is non-null, also
+	 * check the detached graph being merged for a parent.
+	 */
+	public Serializable getOwnerId(String entity, String property, Object childEntity, Map mergeMap) {
+		
+		EntityPersister persister = session.getFactory()
+				.getEntityPersister(entity);
+		final CollectionPersister collectionPersister = session.getFactory()
+				.getCollectionPersister(entity + '.' + property);
+		
+		Iterator entities = entityEntries.entrySet().iterator();
+		while ( entities.hasNext() ) {
+			Map.Entry me = (Map.Entry) entities.next();
+			EntityEntry ee = (EntityEntry) me.getValue();
+			if ( persister.isSubclassEntityName( ee.getEntityName() ) ) {
+				Object instance = me.getKey();
+
+				//check if the managed object is the parent
+				boolean found = isFoundInParent( 
+						property, 
+						childEntity, 
+						persister, 
+						collectionPersister,
+						instance 
+					);
+
+				if (!found && mergeMap!=null) {
+					//check if the detached object being merged is the parent
+					Object unmergedInstance = mergeMap.get(instance);
+					Object unmergedChild = mergeMap.get(childEntity);
+					if ( unmergedInstance!=null && unmergedChild!=null ) {
+						found = isFoundInParent( 
+								property, 
+								unmergedChild, 
+								persister, 
+								collectionPersister,
+								unmergedInstance 
+							);
+					}
+				}
+				
+				if ( found ) {
+					return ee.getId();
+				}
+				
+			}
+		}
+		return null;
+	}
+
+	private boolean isFoundInParent(
+			String property, 
+			Object childEntity, 
+			EntityPersister persister, 
+			CollectionPersister collectionPersister,
+			Object potentialParent
+	) {
+		Object collection = persister.getPropertyValue( 
+				potentialParent, 
+				property, 
+				session.getEntityMode() 
+			);
+		return collection!=null && Hibernate.isInitialized(collection) &&
+				collectionPersister.getCollectionType()
+						.contains(collection, childEntity, session);
+	}
+
+	/**
+	 * Search the persistence context for an index of the child object,
+	 * given a collection role
+	 */
+	public Object getIndexInOwner(String entity, String property, Object childEntity, Map mergeMap) {
+
+		EntityPersister persister = session.getFactory()
+				.getEntityPersister(entity);
+		CollectionPersister cp = session.getFactory()
+				.getCollectionPersister(entity + '.' + property);
+		Iterator entities = entityEntries.entrySet().iterator();
+		while ( entities.hasNext() ) {
+			Map.Entry me = (Map.Entry) entities.next();
+			EntityEntry ee = (EntityEntry) me.getValue();
+			if ( persister.isSubclassEntityName( ee.getEntityName() ) ) {
+				Object instance = me.getKey();
+				
+				Object index = getIndexInParent(property, childEntity, persister, cp, instance);
+				
+				if (index==null && mergeMap!=null) {
+					Object unmergedInstance = mergeMap.get(instance);
+					Object unmergedChild = mergeMap.get(childEntity);
+					if ( unmergedInstance!=null && unmergedChild!=null ) {
+						index = getIndexInParent(property, unmergedChild, persister, cp, unmergedInstance);
+					}
+				}
+				
+				if (index!=null) return index;
+			}
+		}
+		return null;
+	}
+	
+	private Object getIndexInParent(
+			String property, 
+			Object childEntity, 
+			EntityPersister persister, 
+			CollectionPersister collectionPersister,
+			Object potentialParent
+	){	
+		Object collection = persister.getPropertyValue( potentialParent, property, session.getEntityMode() );
+		if ( collection!=null && Hibernate.isInitialized(collection) ) {
+			return collectionPersister.getCollectionType().indexOf(collection, childEntity);
+		}
+		else {
+			return null;
+		}
+	}
+	
+	/**
+	 * Record the fact that the association belonging to the keyed
+	 * entity is null.
+	 */
+	public void addNullProperty(EntityKey ownerKey, String propertyName) {
+		nullAssociations.add( new AssociationKey(ownerKey, propertyName) );
+	}
+	
+	/**
+	 * Is the association property belonging to the keyed entity null?
+	 */
+	public boolean isPropertyNull(EntityKey ownerKey, String propertyName) {
+		return nullAssociations.contains( new AssociationKey(ownerKey, propertyName) );
+	}
+	
+	private void clearNullProperties() {
+		nullAssociations.clear();
+	}
+
+	public void setReadOnly(Object entity, boolean readOnly) {
+		EntityEntry entry = getEntry(entity);
+		if (entry==null) {
+			throw new TransientObjectException("Instance was not associated with the session");
+		}
+		entry.setReadOnly(readOnly, entity);
+		hasNonReadOnlyEntities = hasNonReadOnlyEntities || !readOnly;
+	}
+
+	public void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Serializable generatedId) {
+		Object entity = entitiesByKey.remove( oldKey );
+		EntityEntry oldEntry = ( EntityEntry ) entityEntries.remove( entity );
+
+		EntityKey newKey = new EntityKey( generatedId, oldEntry.getPersister(), getSession().getEntityMode() );
+		addEntity( newKey, entity );
+		addEntry(
+				entity,
+		        oldEntry.getStatus(),
+		        oldEntry.getLoadedState(),
+		        oldEntry.getRowId(),
+		        generatedId,
+		        oldEntry.getVersion(),
+		        oldEntry.getLockMode(),
+		        oldEntry.isExistsInDatabase(),
+		        oldEntry.getPersister(),
+		        oldEntry.isBeingReplicated(),
+		        oldEntry.isLoadedWithLazyPropertiesUnfetched()
+		);
+	}
+
+	/**
+	 * Used by the owning session to explicitly control serialization of the
+	 * persistence context.
+	 *
+	 * @param oos The stream to which the persistence context should get written
+	 * @throws IOException serialization errors.
+	 */
+	public void serialize(ObjectOutputStream oos) throws IOException {
+		log.trace( "serializing persistent-context" );
+
+		oos.writeBoolean( hasNonReadOnlyEntities );
+
+		oos.writeInt( entitiesByKey.size() );
+		log.trace( "starting serialization of [" + entitiesByKey.size() + "] entitiesByKey entries" );
+		Iterator itr = entitiesByKey.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			Map.Entry entry = ( Map.Entry ) itr.next();
+			( ( EntityKey ) entry.getKey() ).serialize( oos );
+			oos.writeObject( entry.getValue() );
+		}
+
+		oos.writeInt( entitiesByUniqueKey.size() );
+		log.trace( "starting serialization of [" + entitiesByUniqueKey.size() + "] entitiesByUniqueKey entries" );
+		itr = entitiesByUniqueKey.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			Map.Entry entry = ( Map.Entry ) itr.next();
+			( ( EntityUniqueKey ) entry.getKey() ).serialize( oos );
+			oos.writeObject( entry.getValue() );
+		}
+
+		oos.writeInt( proxiesByKey.size() );
+		log.trace( "starting serialization of [" + proxiesByKey.size() + "] proxiesByKey entries" );
+		itr = proxiesByKey.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			Map.Entry entry = ( Map.Entry ) itr.next();
+			( ( EntityKey ) entry.getKey() ).serialize( oos );
+			oos.writeObject( entry.getValue() );
+		}
+
+		oos.writeInt( entitySnapshotsByKey.size() );
+		log.trace( "starting serialization of [" + entitySnapshotsByKey.size() + "] entitySnapshotsByKey entries" );
+		itr = entitySnapshotsByKey.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			Map.Entry entry = ( Map.Entry ) itr.next();
+			( ( EntityKey ) entry.getKey() ).serialize( oos );
+			oos.writeObject( entry.getValue() );
+		}
+
+		oos.writeInt( entityEntries.size() );
+		log.trace( "starting serialization of [" + entityEntries.size() + "] entityEntries entries" );
+		itr = entityEntries.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			Map.Entry entry = ( Map.Entry ) itr.next();
+			oos.writeObject( entry.getKey() );
+			( ( EntityEntry ) entry.getValue() ).serialize( oos );
+		}
+
+		oos.writeInt( collectionsByKey.size() );
+		log.trace( "starting serialization of [" + collectionsByKey.size() + "] collectionsByKey entries" );
+		itr = collectionsByKey.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			Map.Entry entry = ( Map.Entry ) itr.next();
+			( ( CollectionKey ) entry.getKey() ).serialize( oos );
+			oos.writeObject( entry.getValue() );
+		}
+
+		oos.writeInt( collectionEntries.size() );
+		log.trace( "starting serialization of [" + collectionEntries.size() + "] collectionEntries entries" );
+		itr = collectionEntries.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			Map.Entry entry = ( Map.Entry ) itr.next();
+			oos.writeObject( entry.getKey() );
+			( ( CollectionEntry ) entry.getValue() ).serialize( oos );
+		}
+
+		oos.writeInt( arrayHolders.size() );
+		log.trace( "starting serialization of [" + arrayHolders.size() + "] arrayHolders entries" );
+		itr = arrayHolders.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			Map.Entry entry = ( Map.Entry ) itr.next();
+			oos.writeObject( entry.getKey() );
+			oos.writeObject( entry.getValue() );
+		}
+
+		oos.writeInt( nullifiableEntityKeys.size() );
+		log.trace( "starting serialization of [" + nullifiableEntityKeys.size() + "] nullifiableEntityKeys entries" );
+		itr = nullifiableEntityKeys.iterator();
+		while ( itr.hasNext() ) {
+			EntityKey entry = ( EntityKey ) itr.next();
+			entry.serialize( oos );
+		}
+	}
+
+	public static StatefulPersistenceContext deserialize(
+			ObjectInputStream ois,
+	        SessionImplementor session) throws IOException, ClassNotFoundException {
+		log.trace( "deserializing persistent-context" );
+		StatefulPersistenceContext rtn = new StatefulPersistenceContext( session );
+
+		// during deserialization, we need to reconnect all proxies and
+		// collections to this session, as well as the EntityEntry and
+		// CollectionEntry instances; these associations are transient
+		// because serialization is used for different things.
+
+		try {
+			// todo : we can actually just determine this from the incoming EntityEntry-s
+			rtn.hasNonReadOnlyEntities = ois.readBoolean();
+
+			int count = ois.readInt();
+			log.trace( "staring deserialization of [" + count + "] entitiesByKey entries" );
+			rtn.entitiesByKey = new HashMap( count < INIT_COLL_SIZE ? INIT_COLL_SIZE : count );
+			for ( int i = 0; i < count; i++ ) {
+				rtn.entitiesByKey.put( EntityKey.deserialize( ois, session ), ois.readObject() );
+			}
+
+			count = ois.readInt();
+			log.trace( "staring deserialization of [" + count + "] entitiesByUniqueKey entries" );
+			rtn.entitiesByUniqueKey = new HashMap( count < INIT_COLL_SIZE ? INIT_COLL_SIZE : count );
+			for ( int i = 0; i < count; i++ ) {
+				rtn.entitiesByUniqueKey.put( EntityUniqueKey.deserialize( ois, session ), ois.readObject() );
+			}
+
+			count = ois.readInt();
+			log.trace( "staring deserialization of [" + count + "] proxiesByKey entries" );
+			rtn.proxiesByKey = new ReferenceMap( ReferenceMap.HARD, ReferenceMap.WEAK, count < INIT_COLL_SIZE ? INIT_COLL_SIZE : count, .75f );
+			for ( int i = 0; i < count; i++ ) {
+				EntityKey ek = EntityKey.deserialize( ois, session );
+				Object proxy = ois.readObject();
+				if ( proxy instanceof HibernateProxy ) {
+					( ( HibernateProxy ) proxy ).getHibernateLazyInitializer().setSession( session );
+					rtn.proxiesByKey.put( ek, proxy );
+				}
+				else {
+					log.trace( "encountered prunded proxy" );
+				}
+				// otherwise, the proxy was pruned during the serialization process
+			}
+
+			count = ois.readInt();
+			log.trace( "staring deserialization of [" + count + "] entitySnapshotsByKey entries" );
+			rtn.entitySnapshotsByKey = new HashMap( count < INIT_COLL_SIZE ? INIT_COLL_SIZE : count );
+			for ( int i = 0; i < count; i++ ) {
+				rtn.entitySnapshotsByKey.put( EntityKey.deserialize( ois, session ), ois.readObject() );
+			}
+
+			count = ois.readInt();
+			log.trace( "staring deserialization of [" + count + "] entityEntries entries" );
+			rtn.entityEntries = IdentityMap.instantiateSequenced( count < INIT_COLL_SIZE ? INIT_COLL_SIZE : count );
+			for ( int i = 0; i < count; i++ ) {
+				Object entity = ois.readObject();
+				EntityEntry entry = EntityEntry.deserialize( ois, session );
+				rtn.entityEntries.put( entity, entry );
+			}
+
+			count = ois.readInt();
+			log.trace( "staring deserialization of [" + count + "] collectionsByKey entries" );
+			rtn.collectionsByKey = new HashMap( count < INIT_COLL_SIZE ? INIT_COLL_SIZE : count );
+			for ( int i = 0; i < count; i++ ) {
+				rtn.collectionsByKey.put( CollectionKey.deserialize( ois, session ), ois.readObject() );
+			}
+
+			count = ois.readInt();
+			log.trace( "staring deserialization of [" + count + "] collectionEntries entries" );
+			rtn.collectionEntries = IdentityMap.instantiateSequenced( count < INIT_COLL_SIZE ? INIT_COLL_SIZE : count );
+			for ( int i = 0; i < count; i++ ) {
+				final PersistentCollection pc = ( PersistentCollection ) ois.readObject();
+				final CollectionEntry ce = CollectionEntry.deserialize( ois, session );
+				pc.setCurrentSession( session );
+				rtn.collectionEntries.put( pc, ce );
+			}
+
+			count = ois.readInt();
+			log.trace( "staring deserialization of [" + count + "] arrayHolders entries" );
+			rtn.arrayHolders = IdentityMap.instantiate( count < INIT_COLL_SIZE ? INIT_COLL_SIZE : count );
+			for ( int i = 0; i < count; i++ ) {
+				rtn.arrayHolders.put( ois.readObject(), ois.readObject() );
+			}
+
+			count = ois.readInt();
+			log.trace( "staring deserialization of [" + count + "] nullifiableEntityKeys entries" );
+			rtn.nullifiableEntityKeys = new HashSet();
+			for ( int i = 0; i < count; i++ ) {
+				rtn.nullifiableEntityKeys.add( EntityKey.deserialize( ois, session ) );
+			}
+
+		}
+		catch ( HibernateException he ) {
+			throw new InvalidObjectException( he.getMessage() );
+		}
+
+		return rtn;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Status.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Status.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Status.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+//$Id: Status.java 9194 2006-02-01 19:59:07Z steveebersole $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
+
+/**
+ * Represents the status of an entity with respect to
+ * this session. These statuses are for internal
+ * book-keeping only and are not intended to represent
+ * any notion that is visible to the _application_.
+ */
+public final class Status implements Serializable {
+
+	public static final Status MANAGED = new Status( "MANAGED" );
+	public static final Status READ_ONLY = new Status( "READ_ONLY" );
+	public static final Status DELETED = new Status( "DELETED" );
+	public static final Status GONE = new Status( "GONE" );
+	public static final Status LOADING = new Status( "LOADING" );
+	public static final Status SAVING = new Status( "SAVING" );
+
+	private String name;
+
+	private Status(String name) {
+		this.name = name;
+	}
+
+	public String toString() {
+		return name;
+	}
+
+	private Object readResolve() throws ObjectStreamException {
+		return parse( name );
+	}
+
+	public static Status parse(String name) throws InvalidObjectException {
+		if ( name.equals(MANAGED.name) ) return MANAGED;
+		if ( name.equals(READ_ONLY.name) ) return READ_ONLY;
+		if ( name.equals(DELETED.name) ) return DELETED;
+		if ( name.equals(GONE.name) ) return GONE;
+		if ( name.equals(LOADING.name) ) return LOADING;
+		if ( name.equals(SAVING.name) ) return SAVING;
+		throw new InvalidObjectException( "invalid Status" );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/SubselectFetch.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/SubselectFetch.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/SubselectFetch.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+//$Id: SubselectFetch.java 7670 2005-07-29 05:36:14Z oneovthafew $
+package org.hibernate.engine;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.persister.entity.PropertyMapping;
+import org.hibernate.util.StringHelper;
+
+/**
+ * @author Gavin King
+ */
+public class SubselectFetch {
+	private final Set resultingEntityKeys;
+	private final String queryString;
+	private final String alias;
+	private final Loadable loadable;
+	private final QueryParameters queryParameters;
+	private final Map namedParameterLocMap;
+	
+	public SubselectFetch(
+		//final String queryString, 
+		final String alias, 
+		final Loadable loadable,
+		final QueryParameters queryParameters, 
+		final Set resultingEntityKeys,
+		final Map namedParameterLocMap
+	) {
+		this.resultingEntityKeys = resultingEntityKeys;
+		this.queryParameters = queryParameters;
+		this.namedParameterLocMap = namedParameterLocMap;
+		this.loadable = loadable;
+		this.alias = alias;
+		
+		//TODO: ugly here:
+		final String queryString = queryParameters.getFilteredSQL();
+		int fromIndex = queryString.indexOf(" from ");
+		int orderByIndex = queryString.lastIndexOf("order by");
+		this.queryString = orderByIndex>0 ? 
+				queryString.substring(fromIndex, orderByIndex) : 
+				queryString.substring(fromIndex);
+			
+	}
+
+	public QueryParameters getQueryParameters() {
+		return queryParameters;
+	}
+	
+	/**
+	 * Get the Set of EntityKeys
+	 */
+	public Set getResult() {
+		return resultingEntityKeys;
+	}
+	
+	public String toSubselectString(String ukname) {
+		
+		String[] joinColumns = ukname==null ?
+			StringHelper.qualify( alias, loadable.getIdentifierColumnNames() ) :
+			( (PropertyMapping) loadable ).toColumns(alias, ukname);
+		
+		return new StringBuffer()
+			.append("select ")
+			.append( StringHelper.join(", ", joinColumns) )
+			.append(queryString)
+			.toString();
+	}
+	
+	public String toString() {
+		return "SubselectFetch(" + queryString + ')';
+	}
+	
+	public Map getNamedParameterLocMap() {
+		return namedParameterLocMap;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/SubselectFetch.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/TransactionHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/TransactionHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/TransactionHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+//$Id: TransactionHelper.java 9056 2006-01-13 19:40:15Z steveebersole $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.transaction.IsolatedWork;
+import org.hibernate.engine.transaction.Isolater;
+import org.hibernate.exception.JDBCExceptionHelper;
+
+/**
+ * Allows work to be done outside the current transaction, by suspending it,
+ * and performing work in a new transaction
+ * 
+ * @author Emmanuel Bernard
+ */
+public abstract class TransactionHelper {
+
+	// todo : remove this and just have subclasses use Isolater/IsolatedWork directly...
+
+	/**
+	 * The work to be done
+	 */
+	protected abstract Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException;
+
+	/**
+	 * Suspend the current transaction and perform work in a new transaction
+	 */
+	public Serializable doWorkInNewTransaction(final SessionImplementor session)
+	throws HibernateException {
+		class Work implements IsolatedWork {
+			Serializable generatedValue;
+			public void doWork(Connection connection) throws HibernateException {
+				String sql = null;
+				try {
+					generatedValue = doWorkInCurrentTransaction( connection, sql );
+				}
+				catch( SQLException sqle ) {
+					throw JDBCExceptionHelper.convert(
+							session.getFactory().getSQLExceptionConverter(),
+							sqle,
+							"could not get or update next value",
+							sql
+						);
+				}
+			}
+		}
+		Work work = new Work();
+		Isolater.doIsolatedWork( work, session );
+		return work.generatedValue;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/TwoPhaseLoad.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/TwoPhaseLoad.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/TwoPhaseLoad.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,273 @@
+//$Id: TwoPhaseLoad.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.CacheMode;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.cache.entry.CacheEntry;
+import org.hibernate.event.PostLoadEvent;
+import org.hibernate.event.PostLoadEventListener;
+import org.hibernate.event.PreLoadEvent;
+import org.hibernate.event.PreLoadEventListener;
+import org.hibernate.intercept.LazyPropertyInitializer;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.property.BackrefPropertyAccessor;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * Functionality relating to Hibernate's two-phase loading process,
+ * that may be reused by persisters that do not use the Loader
+ * framework
+ * 
+ * @author Gavin King
+ */
+public final class TwoPhaseLoad {
+
+	private static final Log log = LogFactory.getLog(TwoPhaseLoad.class);
+	
+	private TwoPhaseLoad() {}
+
+	/**
+	 * Register the "hydrated" state of an entity instance, after the first step of 2-phase loading.
+	 * 
+	 * Add the "hydrated state" (an array) of an uninitialized entity to the session. We don't try
+	 * to resolve any associations yet, because there might be other entities waiting to be
+	 * read from the JDBC result set we are currently processing
+	 */
+	public static void postHydrate(
+		final EntityPersister persister, 
+		final Serializable id, 
+		final Object[] values, 
+		final Object rowId,
+		final Object object, 
+		final LockMode lockMode,
+		final boolean lazyPropertiesAreUnfetched, 
+		final SessionImplementor session) 
+	throws HibernateException {
+		
+		Object version = Versioning.getVersion(values, persister);
+		session.getPersistenceContext().addEntry( 
+				object, 
+				Status.LOADING,
+				values, 
+				rowId, 
+				id, 
+				version, 
+				lockMode, 
+				true, 
+				persister, 
+				false, 
+				lazyPropertiesAreUnfetched 
+			);
+	
+		if ( log.isTraceEnabled() && version!=null ) {
+			String versionStr = persister.isVersioned()
+					? persister.getVersionType().toLoggableString( version, session.getFactory() )
+			        : "null";
+			log.trace( "Version: " + versionStr );
+		}
+	
+	}
+
+	/**
+	 * Perform the second step of 2-phase load. Fully initialize the entity 
+	 * instance.
+	 *
+	 * After processing a JDBC result set, we "resolve" all the associations
+	 * between the entities which were instantiated and had their state
+	 * "hydrated" into an array
+	 */
+	public static void initializeEntity(
+			final Object entity, 
+			final boolean readOnly,
+			final SessionImplementor session,
+			final PreLoadEvent preLoadEvent,
+			final PostLoadEvent postLoadEvent) throws HibernateException {
+		
+		//TODO: Should this be an InitializeEntityEventListener??? (watch out for performance!)
+	
+		final PersistenceContext persistenceContext = session.getPersistenceContext();
+		EntityEntry entityEntry = persistenceContext.getEntry(entity);
+		if ( entityEntry == null ) {
+			throw new AssertionFailure( "possible non-threadsafe access to the session" );
+		}
+		EntityPersister persister = entityEntry.getPersister();
+		Serializable id = entityEntry.getId();
+		Object[] hydratedState = entityEntry.getLoadedState();
+	
+		if ( log.isDebugEnabled() )
+			log.debug(
+					"resolving associations for " +
+					MessageHelper.infoString(persister, id, session.getFactory())
+				);
+	
+		Type[] types = persister.getPropertyTypes();
+		for ( int i = 0; i < hydratedState.length; i++ ) {
+			final Object value = hydratedState[i];
+			if ( value!=LazyPropertyInitializer.UNFETCHED_PROPERTY && value!=BackrefPropertyAccessor.UNKNOWN ) {
+				hydratedState[i] = types[i].resolve( value, session, entity );
+			}
+		}
+	
+		//Must occur after resolving identifiers!
+		if ( session.isEventSource() ) {
+			preLoadEvent.setEntity(entity).setState(hydratedState).setId(id).setPersister(persister);
+			PreLoadEventListener[] listeners = session.getListeners().getPreLoadEventListeners();
+			for ( int i = 0; i < listeners.length; i++ ) {
+				listeners[i].onPreLoad(preLoadEvent);
+			}
+		}
+	
+		persister.setPropertyValues( entity, hydratedState, session.getEntityMode() );
+	
+		final SessionFactoryImplementor factory = session.getFactory();
+		if ( persister.hasCache() && session.getCacheMode().isPutEnabled() ) {
+			
+			if ( log.isDebugEnabled() )
+				log.debug(
+						"adding entity to second-level cache: " +
+						MessageHelper.infoString( persister, id, session.getFactory() )
+					);
+
+			Object version = Versioning.getVersion(hydratedState, persister);
+			CacheEntry entry = new CacheEntry(
+					hydratedState, 
+					persister, 
+					entityEntry.isLoadedWithLazyPropertiesUnfetched(), 
+					version, 
+					session, 
+					entity
+			);
+			CacheKey cacheKey = new CacheKey( 
+					id, 
+					persister.getIdentifierType(), 
+					persister.getRootEntityName(), 
+					session.getEntityMode(), 
+					session.getFactory() 
+			);
+			boolean put = persister.getCacheAccessStrategy().putFromLoad(
+					cacheKey,
+					persister.getCacheEntryStructure().structure( entry ),
+					session.getTimestamp(),
+					version,
+					useMinimalPuts( session, entityEntry )
+			);
+
+			if ( put && factory.getStatistics().isStatisticsEnabled() ) {
+				factory.getStatisticsImplementor().secondLevelCachePut( persister.getCacheAccessStrategy().getRegion().getName() );
+			}
+		}
+	
+		if ( readOnly || !persister.isMutable() ) {
+			//no need to take a snapshot - this is a 
+			//performance optimization, but not really
+			//important, except for entities with huge 
+			//mutable property values
+			persistenceContext.setEntryStatus(entityEntry, Status.READ_ONLY);
+		}
+		else {
+			//take a snapshot
+			TypeFactory.deepCopy( 
+					hydratedState, 
+					persister.getPropertyTypes(), 
+					persister.getPropertyUpdateability(), 
+					hydratedState,  //after setting values to object, entityMode
+					session
+				);
+			persistenceContext.setEntryStatus(entityEntry, Status.MANAGED);
+		}
+		
+		persister.afterInitialize(
+				entity, 
+				entityEntry.isLoadedWithLazyPropertiesUnfetched(), 
+				session
+			);
+		
+		if ( session.isEventSource() ) {
+			postLoadEvent.setEntity(entity).setId(id).setPersister(persister);
+			PostLoadEventListener[] listeners = session.getListeners().getPostLoadEventListeners();
+			for ( int i = 0; i < listeners.length; i++ ) {
+				listeners[i].onPostLoad(postLoadEvent);
+			}
+		}
+		
+		if ( log.isDebugEnabled() )
+			log.debug(
+					"done materializing entity " +
+					MessageHelper.infoString( persister, id, session.getFactory() )
+				);
+		
+		if ( factory.getStatistics().isStatisticsEnabled() ) {
+			factory.getStatisticsImplementor().loadEntity( persister.getEntityName() );
+		}
+	
+	}
+
+	private static boolean useMinimalPuts(SessionImplementor session, EntityEntry entityEntry) {
+		return ( session.getFactory().getSettings().isMinimalPutsEnabled() && 
+						session.getCacheMode()!=CacheMode.REFRESH ) ||
+				( entityEntry.getPersister().hasLazyProperties() && 
+						entityEntry.isLoadedWithLazyPropertiesUnfetched() && 
+						entityEntry.getPersister().isLazyPropertiesCacheable() );
+	}
+
+	/**
+	 * Add an uninitialized instance of an entity class, as a placeholder to ensure object 
+	 * identity. Must be called before <tt>postHydrate()</tt>.
+	 *
+	 * Create a "temporary" entry for a newly instantiated entity. The entity is uninitialized,
+	 * but we need the mapping from id to instance in order to guarantee uniqueness.
+	 */
+	public static void addUninitializedEntity(
+			final EntityKey key, 
+			final Object object, 
+			final EntityPersister persister, 
+			final LockMode lockMode,
+			final boolean lazyPropertiesAreUnfetched, 
+			final SessionImplementor session
+	) {
+		session.getPersistenceContext().addEntity(
+				object, 
+				Status.LOADING, 
+				null, 
+				key, 
+				null, 
+				lockMode, 
+				true, 
+				persister, 
+				false, 
+				lazyPropertiesAreUnfetched
+			);
+	}
+
+	public static void addUninitializedCachedEntity(
+			final EntityKey key, 
+			final Object object, 
+			final EntityPersister persister, 
+			final LockMode lockMode,
+			final boolean lazyPropertiesAreUnfetched,
+			final Object version,
+			final SessionImplementor session
+	) {
+		session.getPersistenceContext().addEntity(
+				object, 
+				Status.LOADING, 
+				null, 
+				key, 
+				version, 
+				lockMode, 
+				true, 
+				persister, 
+				false, 
+				lazyPropertiesAreUnfetched
+			);
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/TwoPhaseLoad.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/TypedValue.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/TypedValue.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/TypedValue.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+//$Id: TypedValue.java 6638 2005-05-02 14:34:17Z oneovthafew $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+
+import org.hibernate.EntityMode;
+import org.hibernate.type.Type;
+
+/**
+ * An ordered pair of a value and its Hibernate type.
+ * 
+ * @see org.hibernate.type.Type
+ * @author Gavin King
+ */
+public final class TypedValue implements Serializable {
+	private final Type type;
+	private final Object value;
+	private final EntityMode entityMode;
+
+	public TypedValue(Type type, Object value, EntityMode entityMode) {
+		this.type = type;
+		this.value=value;
+		this.entityMode = entityMode;
+	}
+
+	public Object getValue() {
+		return value;
+	}
+
+	public Type getType() {
+		return type;
+	}
+
+	public String toString() {
+		return value==null ? "null" : value.toString();
+	}
+
+	public int hashCode() {
+		//int result = 17;
+		//result = 37 * result + type.hashCode();
+		//result = 37 * result + ( value==null ? 0 : value.hashCode() );
+		//return result;
+		return value==null ? 0 : type.getHashCode(value, entityMode);
+	}
+
+	public boolean equals(Object other) {
+		if ( !(other instanceof TypedValue) ) return false;
+		TypedValue that = (TypedValue) other;
+		/*return that.type.equals(type) && 
+			EqualsHelper.equals(that.value, value);*/
+		return type.getReturnedClass() == that.type.getReturnedClass() &&
+			type.isEqual(that.value, value, entityMode);
+	}
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/UnsavedValueFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/UnsavedValueFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/UnsavedValueFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,115 @@
+//$Id: UnsavedValueFactory.java 7736 2005-08-03 20:03:34Z steveebersole $
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+
+import org.hibernate.InstantiationException;
+import org.hibernate.MappingException;
+import org.hibernate.property.Getter;
+import org.hibernate.type.IdentifierType;
+import org.hibernate.type.PrimitiveType;
+import org.hibernate.type.Type;
+import org.hibernate.type.VersionType;
+
+/**
+ * @author Gavin King
+ */
+public class UnsavedValueFactory {
+	
+	private static Object instantiate(Constructor constructor) {
+		try {
+			return constructor.newInstance(null);
+		}
+		catch (Exception e) {
+			throw new InstantiationException( "could not instantiate test object", constructor.getDeclaringClass(), e );
+		}
+	}
+	
+	/**
+	 * Return an IdentifierValue for the specified unsaved-value. If none is specified, 
+	 * guess the unsaved value by instantiating a test instance of the class and
+	 * reading it's id property, or if that is not possible, using the java default
+	 * value for the type 
+	 */
+	public static IdentifierValue getUnsavedIdentifierValue(
+			String unsavedValue, 
+			Getter identifierGetter,
+			Type identifierType,
+			Constructor constructor) {
+		
+		if ( unsavedValue == null ) {
+			if ( identifierGetter!=null && constructor!=null ) {
+				// use the id value of a newly instantiated instance as the unsaved-value
+				Serializable defaultValue = (Serializable) identifierGetter.get( instantiate(constructor) );
+				return new IdentifierValue( defaultValue );
+			}
+			else if ( identifierGetter != null && (identifierType instanceof PrimitiveType) ) {
+				Serializable defaultValue = ( ( PrimitiveType ) identifierType ).getDefaultValue();
+				return new IdentifierValue( defaultValue );
+			}
+			else {
+				return IdentifierValue.NULL;
+			}
+		}
+		else if ( "null".equals( unsavedValue ) ) {
+			return IdentifierValue.NULL;
+		}
+		else if ( "undefined".equals( unsavedValue ) ) {
+			return IdentifierValue.UNDEFINED;
+		}
+		else if ( "none".equals( unsavedValue ) ) {
+			return IdentifierValue.NONE;
+		}
+		else if ( "any".equals( unsavedValue ) ) {
+			return IdentifierValue.ANY;
+		}
+		else {
+			try {
+				return new IdentifierValue( ( Serializable ) ( ( IdentifierType ) identifierType ).stringToObject( unsavedValue ) );
+			}
+			catch ( ClassCastException cce ) {
+				throw new MappingException( "Bad identifier type: " + identifierType.getName() );
+			}
+			catch ( Exception e ) {
+				throw new MappingException( "Could not parse identifier unsaved-value: " + unsavedValue );
+			}
+		}
+	}
+
+	public static VersionValue getUnsavedVersionValue(
+			String versionUnsavedValue, 
+			Getter versionGetter,
+			VersionType versionType,
+			Constructor constructor) {
+		
+		if ( versionUnsavedValue == null ) {
+			if ( constructor!=null ) {
+				Object defaultValue = versionGetter.get( instantiate(constructor) );
+				// if the version of a newly instantiated object is not the same
+				// as the version seed value, use that as the unsaved-value
+				return versionType.isEqual( versionType.seed( null ), defaultValue ) ?
+						VersionValue.UNDEFINED :
+						new VersionValue( defaultValue );
+			}
+			else {
+				return VersionValue.UNDEFINED;
+			}
+		}
+		else if ( "undefined".equals( versionUnsavedValue ) ) {
+			return VersionValue.UNDEFINED;
+		}
+		else if ( "null".equals( versionUnsavedValue ) ) {
+			return VersionValue.NULL;
+		}
+		else if ( "negative".equals( versionUnsavedValue ) ) {
+			return VersionValue.NEGATIVE;
+		}
+		else {
+			// this should not happen since the DTD prevents it
+			throw new MappingException( "Could not parse version unsaved-value: " + versionUnsavedValue );
+		}
+		
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/UnsavedValueFactory.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ValueInclusion.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ValueInclusion.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/ValueInclusion.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+package org.hibernate.engine;
+
+import java.io.Serializable;
+import java.io.ObjectStreamException;
+import java.io.StreamCorruptedException;
+
+/**
+ * An enum of the different ways a value might be "included".
+ * <p/>
+ * This is really an expanded true/false notion with "PARTIAL" being the
+ * expansion.  PARTIAL deals with components in the cases where
+ * parts of the referenced component might define inclusion, but the
+ * component overall does not.
+ *
+ * @author Steve Ebersole
+ */
+public class ValueInclusion implements Serializable {
+
+	public static final ValueInclusion NONE = new ValueInclusion( "none" );
+	public static final ValueInclusion FULL = new ValueInclusion( "full" );
+	public static final ValueInclusion PARTIAL = new ValueInclusion( "partial" );
+
+	private final String name;
+
+	public ValueInclusion(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public String toString() {
+		return "ValueInclusion[" + name + "]";
+	}
+
+	private Object readResolve() throws ObjectStreamException {
+		if ( name.equals( NONE.name ) ) {
+			return NONE;
+		}
+		else if ( name.equals( FULL.name ) ) {
+			return FULL;
+		}
+		else if ( name.equals( PARTIAL.name ) ) {
+			return PARTIAL;
+		}
+		else {
+			throw new StreamCorruptedException( "unrecognized value inclusion [" + name + "]" );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/VersionValue.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/VersionValue.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/VersionValue.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,109 @@
+//$Id: VersionValue.java 7017 2005-06-05 04:31:34Z oneovthafew $
+package org.hibernate.engine;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.MappingException;
+import org.hibernate.id.IdentifierGeneratorFactory;
+
+/**
+ * A strategy for determining if a version value is an version of
+ * a new transient instance or a previously persistent transient instance.
+ * The strategy is determined by the <tt>unsaved-value</tt> attribute in
+ * the mapping file.
+ * 
+ * @author Gavin King
+ */
+public class VersionValue {
+
+	private static final Log log = LogFactory.getLog(VersionValue.class);
+
+	private final Object value;
+	/**
+	 * Assume the transient instance is newly instantiated if the version
+	 * is null, otherwise assume it is a detached instance.
+	 */
+	public static final VersionValue NULL = new VersionValue() {
+		public final Boolean isUnsaved(Object version) {
+			log.trace("version unsaved-value strategy NULL");
+			return version==null ? Boolean.TRUE : Boolean.FALSE;
+		}
+		public Object getDefaultValue(Object currentValue) {
+			return null;
+		}
+		public String toString() {
+			return "VERSION_SAVE_NULL";
+		}
+	};
+	/**
+	 * Assume the transient instance is newly instantiated if the version
+	 * is null, otherwise defer to the identifier unsaved-value.
+	 */
+	public static final VersionValue UNDEFINED = new VersionValue() {
+		public final Boolean isUnsaved(Object version) {
+			log.trace("version unsaved-value strategy UNDEFINED");
+			return version==null ? Boolean.TRUE : null;
+		}
+		public Object getDefaultValue(Object currentValue) {
+			return currentValue;
+		}
+		public String toString() {
+			return "VERSION_UNDEFINED";
+		}
+	};
+	/**
+	 * Assume the transient instance is newly instantiated if the version
+	 * is negative, otherwise assume it is a detached instance.
+	 */
+	public static final VersionValue NEGATIVE = new VersionValue() {
+	
+		public final Boolean isUnsaved(Object version) throws MappingException {
+			log.trace("version unsaved-value strategy NEGATIVE");
+			if (version==null) return Boolean.TRUE;
+			if (version instanceof Number) {
+				return ( (Number) version ).longValue() < 0l ? Boolean.TRUE : Boolean.FALSE;
+			}
+			else {
+				throw new MappingException("unsaved-value NEGATIVE may only be used with short, int and long types");
+			}
+		}
+		public Object getDefaultValue(Object currentValue) {
+			return IdentifierGeneratorFactory.createNumber( -1l, currentValue.getClass() );
+		}
+		public String toString() {
+			return "VERSION_NEGATIVE";
+		}
+	};
+	
+	protected VersionValue() {
+		this.value = null;
+	}
+
+	/**
+	 * Assume the transient instance is newly instantiated if
+	 * its version is null or equal to <tt>value</tt>
+	 * @param value value to compare to
+	 */
+	public VersionValue(Object value) {
+		this.value = value;
+	}
+	
+	/**
+	 * Does the given version belong to a new instance?
+	 *
+	 * @param version version to check
+	 * @return true is unsaved, false is saved, null is undefined
+	 */
+	public Boolean isUnsaved(Object version) throws MappingException  {
+		if ( log.isTraceEnabled() ) log.trace("version unsaved-value: " + value);
+		return version==null || version.equals(value) ? Boolean.TRUE : Boolean.FALSE;
+	}
+	
+	public Object getDefaultValue(Object currentValue) {
+		return value;
+	}
+	
+	public String toString() {
+		return "version unsaved-value: " + value;
+	}
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/VersionValue.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Versioning.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Versioning.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/Versioning.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,172 @@
+//$Id: Versioning.java 10857 2006-11-21 23:28:07Z steve.ebersole at jboss.com $
+package org.hibernate.engine;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.type.VersionType;
+
+/**
+ * Utilities for dealing with optimisitic locking values.
+ *
+ * @author Gavin King
+ */
+public final class Versioning {
+	/**
+	 * Apply no optimistic locking
+	 */
+	public static final int OPTIMISTIC_LOCK_NONE = -1;
+
+	/**
+	 * Apply optimisitc locking based on the defined version or timestamp
+	 * property.
+	 */
+	public static final int OPTIMISTIC_LOCK_VERSION = 0;
+
+	/**
+	 * Apply optimisitc locking based on the a current vs. snapshot comparison
+	 * of <b>all</b> properties.
+	 */
+	public static final int OPTIMISTIC_LOCK_ALL = 2;
+
+	/**
+	 * Apply optimisitc locking based on the a current vs. snapshot comparison
+	 * of <b>dirty</b> properties.
+	 */
+	public static final int OPTIMISTIC_LOCK_DIRTY = 1;
+
+	private static final Log log = LogFactory.getLog( Versioning.class );
+
+	/**
+	 * Private constructor disallowing instantiation.
+	 */
+	private Versioning() {}
+
+	/**
+	 * Create an initial optimisitc locking value according the {@link VersionType}
+	 * contract for the version property.
+	 *
+	 * @param versionType The version type.
+	 * @param session The originating session
+	 * @return The initial optimisitc locking value
+	 */
+	private static Object seed(VersionType versionType, SessionImplementor session) {
+		Object seed = versionType.seed( session );
+		if ( log.isTraceEnabled() ) log.trace("Seeding: " + seed);
+		return seed;
+	}
+
+	/**
+	 * Create an initial optimisitc locking value according the {@link VersionType}
+	 * contract for the version property <b>if required</b> and inject it into
+	 * the snapshot state.
+	 *
+	 * @param fields The current snapshot state
+	 * @param versionProperty The index of the version property
+	 * @param versionType The version type
+	 * @param session The orginating session
+	 * @return True if we injected a new version value into the fields array; false
+	 * otherwise.
+	 */
+	public static boolean seedVersion(
+	        Object[] fields,
+	        int versionProperty,
+	        VersionType versionType,
+	        SessionImplementor session) {
+		Object initialVersion = fields[versionProperty];
+		if (
+			initialVersion==null ||
+			// This next bit is to allow for both unsaved-value="negative"
+			// and for "older" behavior where version number did not get
+			// seeded if it was already set in the object
+			// TODO: shift it into unsaved-value strategy
+			( (initialVersion instanceof Number) && ( (Number) initialVersion ).longValue()<0 )
+		) {
+			fields[versionProperty] = seed( versionType, session );
+			return true;
+		}
+		else {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "using initial version: " + initialVersion );
+			}
+			return false;
+		}
+	}
+
+
+	/**
+	 * Generate the next increment in the optimisitc locking value according
+	 * the {@link VersionType} contract for the version property.
+	 *
+	 * @param version The current version
+	 * @param versionType The version type
+	 * @param session The originating session
+	 * @return The incremented optimistic locking value.
+	 */
+	public static Object increment(Object version, VersionType versionType, SessionImplementor session) {
+		Object next = versionType.next( version, session );
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"Incrementing: " +
+					versionType.toLoggableString( version, session.getFactory() ) +
+					" to " +
+					versionType.toLoggableString( next, session.getFactory() )
+			);
+		}
+		return next;
+	}
+
+	/**
+	 * Inject the optimisitc locking value into the entity state snapshot.
+	 *
+	 * @param fields The state snapshot
+	 * @param version The optimisitc locking value
+	 * @param persister The entity persister
+	 */
+	public static void setVersion(Object[] fields, Object version, EntityPersister persister) {
+		if ( !persister.isVersioned() ) {
+			return;
+		}
+		fields[ persister.getVersionProperty() ] = version;
+	}
+
+	/**
+	 * Extract the optimisitc locking value out of the entity state snapshot.
+	 *
+	 * @param fields The state snapshot
+	 * @param persister The entity persister
+	 * @return The extracted optimisitc locking value
+	 */
+	public static Object getVersion(Object[] fields, EntityPersister persister) {
+		if ( !persister.isVersioned() ) {
+			return null;
+		}
+		return fields[ persister.getVersionProperty() ];
+	}
+
+	/**
+	 * Do we need to increment the version number, given the dirty properties?
+	 *
+	 * @param dirtyProperties The array of property indexes which were deemed dirty
+	 * @param hasDirtyCollections Were any collections found to be dirty (structurally changed)
+	 * @param propertyVersionability An array indicating versionability of each property.
+	 * @return True if a version increment is required; false otherwise.
+	 */
+	public static boolean isVersionIncrementRequired(
+			final int[] dirtyProperties,
+			final boolean hasDirtyCollections,
+			final boolean[] propertyVersionability) {
+		if ( hasDirtyCollections ) {
+			return true;
+		}
+		for ( int i = 0; i < dirtyProperties.length; i++ ) {
+			if ( propertyVersionability[ dirtyProperties[i] ] ) {
+				return true;
+			}
+		}
+	    return false;
+	}
+
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/CollectionLoadContext.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/CollectionLoadContext.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/CollectionLoadContext.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,322 @@
+package org.hibernate.engine.loading;
+
+import java.sql.ResultSet;
+import java.io.Serializable;
+import java.util.Map;
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.HashSet;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.EntityMode;
+import org.hibernate.CacheMode;
+import org.hibernate.cache.entry.CollectionCacheEntry;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.engine.CollectionKey;
+import org.hibernate.engine.Status;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.CollectionEntry;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Represents state associated with the processing of a given {@link ResultSet}
+ * in regards to loading collections.
+ * <p/>
+ * Another implementation option to consider is to not expose {@link ResultSet}s
+ * directly (in the JDBC redesign) but to always "wrap" them and apply a
+ * [series of] context[s] to that wrapper.
+ *
+ * @author Steve Ebersole
+ */
+public class CollectionLoadContext {
+	private static final Log log = LogFactory.getLog( CollectionLoadContext.class );
+
+	private final LoadContexts loadContexts;
+	private final ResultSet resultSet;
+	private Set localLoadingCollectionKeys = new HashSet();
+
+	/**
+	 * Creates a collection load context for the given result set.
+	 *
+	 * @param loadContexts Callback to other collection load contexts.
+	 * @param resultSet The result set this is "wrapping".
+	 */
+	public CollectionLoadContext(LoadContexts loadContexts, ResultSet resultSet) {
+		this.loadContexts = loadContexts;
+		this.resultSet = resultSet;
+	}
+
+	public ResultSet getResultSet() {
+		return resultSet;
+	}
+
+	public LoadContexts getLoadContext() {
+		return loadContexts;
+	}
+
+	/**
+	 * Retrieve the collection that is being loaded as part of processing this
+	 * result set.
+	 * <p/>
+	 * Basically, there are two valid return values from this method:<ul>
+	 * <li>an instance of {@link PersistentCollection} which indicates to
+	 * continue loading the result set row data into that returned collection
+	 * instance; this may be either an instance already associated and in the
+	 * midst of being loaded, or a newly instantiated instance as a matching
+	 * associated collection was not found.</li>
+	 * <li><i>null</i> indicates to ignore the corresponding result set row
+	 * data relating to the requested collection; this indicates that either
+	 * the collection was found to already be associated with the persistence
+	 * context in a fully loaded state, or it was found in a loading state
+	 * associated with another result set processing context.</li>
+	 * </ul>
+	 *
+	 * @param persister The persister for the collection being requested.
+	 * @param key The key of the collection being requested.
+	 *
+	 * @return The loading collection (see discussion above).
+	 */
+	public PersistentCollection getLoadingCollection(final CollectionPersister persister, final Serializable key) {
+		final EntityMode em = loadContexts.getPersistenceContext().getSession().getEntityMode();
+		final CollectionKey collectionKey = new CollectionKey( persister, key, em );
+		if ( log.isTraceEnabled() ) {
+			log.trace( "starting attempt to find loading collection [" + MessageHelper.collectionInfoString( persister.getRole(), key ) + "]" );
+		}
+		final LoadingCollectionEntry loadingCollectionEntry = loadContexts.locateLoadingCollectionEntry( collectionKey );
+		if ( loadingCollectionEntry == null ) {
+			// look for existing collection as part of the persistence context
+			PersistentCollection collection = loadContexts.getPersistenceContext().getCollection( collectionKey );
+			if ( collection != null ) {
+				if ( collection.wasInitialized() ) {
+					log.trace( "collection already initialized; ignoring" );
+					return null; // ignore this row of results! Note the early exit
+				}
+				else {
+					// initialize this collection
+					log.trace( "collection not yet initialized; initializing" );
+				}
+			}
+			else {
+				Object owner = loadContexts.getPersistenceContext().getCollectionOwner( key, persister );
+				final boolean newlySavedEntity = owner != null
+						&& loadContexts.getPersistenceContext().getEntry( owner ).getStatus() != Status.LOADING
+						&& em != EntityMode.DOM4J;
+				if ( newlySavedEntity ) {
+					// important, to account for newly saved entities in query
+					// todo : some kind of check for new status...
+					log.trace( "owning entity already loaded; ignoring" );
+					return null;
+				}
+				else {
+					// create one
+					if ( log.isTraceEnabled() ) {
+						log.trace( "instantiating new collection [key=" + key + ", rs=" + resultSet + "]" );
+					}
+					collection = persister.getCollectionType()
+							.instantiate( loadContexts.getPersistenceContext().getSession(), persister, key );
+				}
+			}
+			collection.beforeInitialize( persister, -1 );
+			collection.beginRead();
+			localLoadingCollectionKeys.add( collectionKey );
+			loadContexts.registerLoadingCollectionEntry( collectionKey, new LoadingCollectionEntry( resultSet, persister, key, collection ) );
+			return collection;
+		}
+		else {
+			if ( loadingCollectionEntry.getResultSet() == resultSet ) {
+				log.trace( "found loading collection bound to current result set processing; reading row" );
+				return loadingCollectionEntry.getCollection();
+			}
+			else {
+				// ignore this row, the collection is in process of
+				// being loaded somewhere further "up" the stack
+				log.trace( "collection is already being initialized; ignoring row" );
+				return null;
+			}
+		}
+	}
+
+	/**
+	 * Finish the process of collection-loading for this bound result set.  Mainly this
+	 * involves cleaning up resources and notifying the collections that loading is
+	 * complete.
+	 *
+	 * @param persister The persister for which to complete loading.
+	 */
+	public void endLoadingCollections(CollectionPersister persister) {
+		SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
+		if ( loadContexts.getLoadingCollectionEntryMap() == null
+				|| loadContexts.getLoadingCollectionEntryMap().isEmpty()
+				|| localLoadingCollectionKeys.isEmpty() ) {
+			return;
+		}
+
+		// in an effort to avoid concurrent-modification-exceptions (from
+		// potential recursive calls back through here as a result of the
+		// eventual call to PersistentCollection#endRead), we scan the
+		// internal loadingCollections map for matches and store those matches
+		// in a temp collection.  the temp collection is then used to "drive"
+		// the #endRead processing.
+		List matches = null;
+		Iterator iter = loadContexts.getLoadingCollectionEntryMap().entrySet().iterator();
+		while ( iter.hasNext() ) {
+			final Map.Entry mapEntry = ( Map.Entry ) iter.next();
+			final CollectionKey collectionKey = ( CollectionKey ) mapEntry.getKey();
+			final LoadingCollectionEntry lce = ( LoadingCollectionEntry ) mapEntry.getValue();
+			if ( localLoadingCollectionKeys.contains( collectionKey ) && lce.getResultSet() == resultSet && lce.getPersister() == persister) {
+				if ( matches == null ) {
+					matches = new ArrayList();
+				}
+				matches.add( lce );
+				if ( lce.getCollection().getOwner() == null ) {
+					session.getPersistenceContext().addUnownedCollection(
+							new CollectionKey( persister, lce.getKey(), session.getEntityMode() ),
+							lce.getCollection()
+					);
+				}
+				if ( log.isTraceEnabled() ) {
+					log.trace( "removing collection load entry [" + lce + "]" );
+				}
+				iter.remove();
+			}
+		}
+
+		endLoadingCollections( persister, matches );
+	}
+
+	private void endLoadingCollections(CollectionPersister persister, List matchedCollectionEntries) {
+		if ( matchedCollectionEntries == null ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "no collections were found in result set for role: " + persister.getRole() );
+			}
+			return;
+		}
+
+		final int count = matchedCollectionEntries.size();
+		if ( log.isDebugEnabled() ) {
+			log.debug( count + " collections were found in result set for role: " + persister.getRole() );
+		}
+
+		for ( int i = 0; i < count; i++ ) {
+			LoadingCollectionEntry lce = ( LoadingCollectionEntry ) matchedCollectionEntries.get( i );
+			endLoadingCollection( lce, persister );
+		}
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( count + " collections initialized for role: " + persister.getRole() );
+		}
+	}
+
+	private void endLoadingCollection(LoadingCollectionEntry lce, CollectionPersister persister) {
+		if ( log.isTraceEnabled() ) {
+			log.debug( "ending loading collection [" + lce + "]" );
+		}
+		final SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
+		final EntityMode em = session.getEntityMode();
+
+		boolean hasNoQueuedAdds = lce.getCollection().endRead(); // warning: can cause a recursive calls! (proxy initialization)
+
+		if ( persister.getCollectionType().hasHolder( em ) ) {
+			getLoadContext().getPersistenceContext().addCollectionHolder( lce.getCollection() );
+		}
+
+		CollectionEntry ce = getLoadContext().getPersistenceContext().getCollectionEntry( lce.getCollection() );
+		if ( ce == null ) {
+			ce = getLoadContext().getPersistenceContext().addInitializedCollection( persister, lce.getCollection(), lce.getKey() );
+		}
+		else {
+			ce.postInitialize( lce.getCollection() );
+		}
+
+		boolean addToCache = hasNoQueuedAdds && // there were no queued additions
+				persister.hasCache() &&             // and the role has a cache
+				session.getCacheMode().isPutEnabled() &&
+				!ce.isDoremove();                   // and this is not a forced initialization during flush
+		if ( addToCache ) {
+			addCollectionToCache( lce, persister );
+		}
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( "collection fully initialized: " + MessageHelper.collectionInfoString(persister, lce.getKey(), session.getFactory() ) );
+		}
+
+		if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
+			session.getFactory().getStatisticsImplementor().loadCollection( persister.getRole() );
+		}
+	}
+
+	/**
+	 * Add the collection to the second-level cache
+	 *
+	 * @param lce The entry representing the collection to add
+	 * @param persister The persister
+	 */
+	private void addCollectionToCache(LoadingCollectionEntry lce, CollectionPersister persister) {
+		final SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
+		final SessionFactoryImplementor factory = session.getFactory();
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Caching collection: " + MessageHelper.collectionInfoString( persister, lce.getKey(), factory ) );
+		}
+
+		if ( !session.getEnabledFilters().isEmpty() && persister.isAffectedByEnabledFilters( session ) ) {
+			// some filters affecting the collection are enabled on the session, so do not do the put into the cache.
+			log.debug( "Refusing to add to cache due to enabled filters" );
+			// todo : add the notion of enabled filters to the CacheKey to differentiate filtered collections from non-filtered;
+			//      but CacheKey is currently used for both collections and entities; would ideally need to define two seperate ones;
+			//      currently this works in conjuction with the check on
+			//      DefaultInitializeCollectionEventHandler.initializeCollectionFromCache() (which makes sure to not read from
+			//      cache with enabled filters).
+			return; // EARLY EXIT!!!!!
+		}
+
+		final Object version;
+		if ( persister.isVersioned() ) {
+			final Object collectionOwner = getLoadContext().getPersistenceContext().getCollectionOwner( lce.getKey(), persister );
+			version = getLoadContext().getPersistenceContext().getEntry( collectionOwner ).getVersion();
+		}
+		else {
+			version = null;
+		}
+
+		CollectionCacheEntry entry = new CollectionCacheEntry( lce.getCollection(), persister );
+		CacheKey cacheKey = new CacheKey(
+				lce.getKey(),
+				persister.getKeyType(),
+				persister.getRole(),
+				session.getEntityMode(),
+				session.getFactory()
+		);
+		boolean put = persister.getCacheAccessStrategy().putFromLoad(
+				cacheKey,
+				persister.getCacheEntryStructure().structure(entry),
+				session.getTimestamp(),
+				version,
+				factory.getSettings().isMinimalPutsEnabled() && session.getCacheMode()!= CacheMode.REFRESH
+		);
+
+		if ( put && factory.getStatistics().isStatisticsEnabled() ) {
+			factory.getStatisticsImplementor().secondLevelCachePut( persister.getCacheAccessStrategy().getRegion().getName() );
+		}
+	}
+
+	void cleanup() {
+		if ( !localLoadingCollectionKeys.isEmpty() ) {
+			log.warn( "On CollectionLoadContext#clear, loadingCollections contained [" + localLoadingCollectionKeys.size() + "] entries" );
+		}
+		loadContexts.cleanupCollectionEntries( localLoadingCollectionKeys );
+		localLoadingCollectionKeys.clear();
+	}
+
+
+	public String toString() {
+		return super.toString() + "<rs=" + resultSet + ">";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/EntityLoadContext.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/EntityLoadContext.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/EntityLoadContext.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+package org.hibernate.engine.loading;
+
+import java.sql.ResultSet;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class EntityLoadContext {
+	private static final Log log = LogFactory.getLog( EntityLoadContext.class );
+
+	private final LoadContexts loadContexts;
+	private final ResultSet resultSet;
+	private final List hydratingEntities = new ArrayList( 20 ); // todo : need map? the prob is a proper key, right?
+
+	public EntityLoadContext(LoadContexts loadContexts, ResultSet resultSet) {
+		this.loadContexts = loadContexts;
+		this.resultSet = resultSet;
+	}
+
+	void cleanup() {
+		if ( !hydratingEntities.isEmpty() ) {
+			log.warn( "On EntityLoadContext#clear, hydratingEntities contained [" + hydratingEntities.size() + "] entries" );
+		}
+		hydratingEntities.clear();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/LoadContexts.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/LoadContexts.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/LoadContexts.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,199 @@
+package org.hibernate.engine.loading;
+
+import java.sql.ResultSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Iterator;
+import java.util.HashMap;
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.util.IdentityMap;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.CollectionKey;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.EntityMode;
+
+/**
+ * Maps {@link ResultSet result-sets} to specific contextual data
+ * related to processing that {@link ResultSet result-sets}.
+ * <p/>
+ * Implementation note: internally an {@link IdentityMap} is used to maintain
+ * the mappings; {@link IdentityMap} was chosen because I'd rather not be
+ * dependent upon potentially bad {@link ResultSet#equals} and {ResultSet#hashCode}
+ * implementations.
+ * <p/>
+ * Considering the JDBC-redesign work, would further like this contextual info
+ * not mapped seperately, but available based on the result set being processed.
+ * This would also allow maintaining a single mapping as we could reliably get
+ * notification of the result-set closing...
+ *
+ * @author Steve Ebersole
+ */
+public class LoadContexts {
+	private static final Log log = LogFactory.getLog( LoadContexts.class );
+
+	private final PersistenceContext persistenceContext;
+	private Map collectionLoadContexts;
+	private Map entityLoadContexts;
+
+	private Map xrefLoadingCollectionEntries;
+
+	/**
+	 * Creates and binds this to the given persistence context.
+	 *
+	 * @param persistenceContext The persistence context to which this
+	 * will be bound.
+	 */
+	public LoadContexts(PersistenceContext persistenceContext) {
+		this.persistenceContext = persistenceContext;
+	}
+
+	/**
+	 * Retrieves the persistence context to which this is bound.
+	 *
+	 * @return The persistence context to which this is bound.
+	 */
+	public PersistenceContext getPersistenceContext() {
+		return persistenceContext;
+	}
+
+	/**
+	 * Get the {@link CollectionLoadContext} associated with the given
+	 * {@link ResultSet}, creating one if needed.
+	 *
+	 * @param resultSet The result set for which to retrieve the context.
+	 * @return The processing context.
+	 */
+	public CollectionLoadContext getCollectionLoadContext(ResultSet resultSet) {
+		CollectionLoadContext context = null;
+		if ( collectionLoadContexts == null ) {
+			collectionLoadContexts = IdentityMap.instantiate( 8 );
+		}
+		else {
+			context = ( CollectionLoadContext ) collectionLoadContexts.get( resultSet );
+		}
+		if ( context == null ) {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "constructing collection load context for result set [" + resultSet + "]" );
+			}
+			context = new CollectionLoadContext( this, resultSet );
+			collectionLoadContexts.put( resultSet, context );
+		}
+		return context;
+	}
+
+	/**
+	 * Attempt to locate the loading collection given the owner's key.  The lookup here
+	 * occurs against all result-set contexts...
+	 *
+	 * @param persister The collection persister
+	 * @param ownerKey The owner key
+	 * @return The loading collection, or null if not found.
+	 */
+	public PersistentCollection locateLoadingCollection(CollectionPersister persister, Serializable ownerKey) {
+		LoadingCollectionEntry lce = locateLoadingCollectionEntry( new CollectionKey( persister, ownerKey, getEntityMode() ) );
+		if ( lce != null ) {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "returning loading collection:" + MessageHelper.collectionInfoString( persister, ownerKey, getSession().getFactory() ) );
+			}
+			return lce.getCollection();
+		}
+		else {
+			// todo : should really move this log statement to CollectionType, where this is used from...
+			if ( log.isTraceEnabled() ) {
+				log.trace( "creating collection wrapper:" + MessageHelper.collectionInfoString( persister, ownerKey, getSession().getFactory() ) );
+			}
+			return null;
+		}
+	}
+
+	/**
+	 * Locate the LoadingCollectionEntry within *any* of the tracked
+	 * {@link CollectionLoadContext}s.
+	 * <p/>
+	 * Implementation note: package protected, as this is meant solely for use
+	 * by {@link CollectionLoadContext} to be able to locate collections
+	 * being loaded by other {@link CollectionLoadContext}s/{@link ResultSet}s.
+	 *
+	 * @param key The collection key.
+	 * @return The located entry; or null.
+	 */
+	LoadingCollectionEntry locateLoadingCollectionEntry(CollectionKey key) {
+		if ( xrefLoadingCollectionEntries == null ) {
+			return null;
+		}
+		if ( log.isTraceEnabled() ) {
+			log.trace( "attempting to locate loading collection entry [" + key + "] in any result-set context" );
+		}
+		LoadingCollectionEntry rtn = ( LoadingCollectionEntry ) xrefLoadingCollectionEntries.get( key );
+		if ( log.isTraceEnabled() ) {
+			if ( rtn == null ) {
+				log.trace( "collection [" + key + "] located in load context" );
+			}
+			else {
+				log.trace( "collection [" + key + "] not located in load context" );
+			}
+		}
+		return rtn;
+	}
+
+	/*package*/void registerLoadingCollectionEntry(CollectionKey entryKey, LoadingCollectionEntry entry) {
+		if ( xrefLoadingCollectionEntries == null ) {
+			xrefLoadingCollectionEntries = new HashMap();
+		}
+		xrefLoadingCollectionEntries.put( entryKey, entry );
+	}
+
+	/*package*/Map getLoadingCollectionEntryMap() {
+		return xrefLoadingCollectionEntries;
+	}
+
+	/*package*/void cleanupCollectionEntries(Set entryKeys) {
+		Iterator itr = entryKeys.iterator();
+		while ( itr.hasNext() ) {
+			final CollectionKey entryKey = ( CollectionKey ) itr.next();
+			xrefLoadingCollectionEntries.remove( entryKey );
+		}
+	}
+
+	public EntityLoadContext getEntityLoadContext(ResultSet resultSet) {
+		EntityLoadContext context = null;
+		if ( entityLoadContexts == null ) {
+			entityLoadContexts = IdentityMap.instantiate( 8 );
+		}
+		else {
+			context = ( EntityLoadContext ) entityLoadContexts.get( resultSet );
+		}
+		if ( context == null ) {
+			context = new EntityLoadContext( this, resultSet );
+			entityLoadContexts.put( resultSet, context );
+		}
+		return context;
+	}
+
+	public void cleanup(ResultSet resultSet) {
+		if ( collectionLoadContexts != null ) {
+			CollectionLoadContext collectionLoadContext = ( CollectionLoadContext ) collectionLoadContexts.remove( resultSet );
+			collectionLoadContext.cleanup();
+		}
+		if ( entityLoadContexts != null ) {
+			EntityLoadContext entityLoadContext = ( EntityLoadContext ) entityLoadContexts.remove( resultSet );
+			entityLoadContext.cleanup();
+		}
+	}
+
+	private SessionImplementor getSession() {
+		return getPersistenceContext().getSession();
+	}
+
+	private EntityMode getEntityMode() {
+		return getSession().getEntityMode();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/LoadingCollectionEntry.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/LoadingCollectionEntry.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/loading/LoadingCollectionEntry.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+package org.hibernate.engine.loading;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.pretty.MessageHelper;
+
+/**
+ * Represents a collection currently being loaded.
+ *
+ * @author Steve Ebersole
+ */
+public class LoadingCollectionEntry {
+	private final ResultSet resultSet;
+	private final CollectionPersister persister;
+	private final Serializable key;
+	private final PersistentCollection collection;
+
+	public LoadingCollectionEntry(
+			ResultSet resultSet,
+			CollectionPersister persister,
+			Serializable key,
+			PersistentCollection collection) {
+		this.resultSet = resultSet;
+		this.persister = persister;
+		this.key = key;
+		this.collection = collection;
+	}
+
+	public ResultSet getResultSet() {
+		return resultSet;
+	}
+
+	public CollectionPersister getPersister() {
+		return persister;
+	}
+
+	public Serializable getKey() {
+		return key;
+	}
+
+	public PersistentCollection getCollection() {
+		return collection;
+	}
+
+	public String toString() {
+		return getClass().getName() + "<rs=" + resultSet + ", coll=" + MessageHelper.collectionInfoString( persister.getRole(), key ) + ">@" + Integer.toHexString( hashCode() );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package contains classes that are "shared" by other packages, 
+	and implementations of some key algorithms.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/FilterQueryPlan.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/FilterQueryPlan.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/FilterQueryPlan.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+package org.hibernate.engine.query;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * Extends an HQLQueryPlan to maintain a reference to the collection-role name
+ * being filtered.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class FilterQueryPlan extends HQLQueryPlan implements Serializable {
+
+	private final String collectionRole;
+
+	public FilterQueryPlan(
+			String hql,
+	        String collectionRole,
+	        boolean shallow,
+	        Map enabledFilters,
+	        SessionFactoryImplementor factory) {
+		super( hql, collectionRole, shallow, enabledFilters, factory );
+		this.collectionRole = collectionRole;
+	}
+
+	public String getCollectionRole() {
+		return collectionRole;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/HQLQueryPlan.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/HQLQueryPlan.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/HQLQueryPlan.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,315 @@
+package org.hibernate.engine.query;
+
+import org.hibernate.hql.QuerySplitter;
+import org.hibernate.hql.QueryTranslator;
+import org.hibernate.hql.ParameterTranslations;
+import org.hibernate.hql.FilterTranslator;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.EmptyIterator;
+import org.hibernate.util.JoinedIterator;
+import org.hibernate.util.IdentitySet;
+import org.hibernate.HibernateException;
+import org.hibernate.ScrollableResults;
+import org.hibernate.QueryException;
+import org.hibernate.type.Type;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.RowSelection;
+import org.hibernate.event.EventSource;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.HashMap;
+
+/**
+ * Defines a query execution plan for an HQL query (or filter).
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class HQLQueryPlan implements Serializable {
+
+	// TODO : keep seperate notions of QT[] here for shallow/non-shallow queries...
+
+	private static final Log log = LogFactory.getLog( HQLQueryPlan.class );
+
+	private final String sourceQuery;
+	private final QueryTranslator[] translators;
+	private final String[] sqlStrings;
+
+	private final ParameterMetadata parameterMetadata;
+	private final ReturnMetadata returnMetadata;
+	private final Set querySpaces;
+
+	private final Set enabledFilterNames;
+	private final boolean shallow;
+
+
+	public HQLQueryPlan(String hql, boolean shallow, Map enabledFilters, SessionFactoryImplementor factory) {
+		this( hql, null, shallow, enabledFilters, factory );
+	}
+
+	protected HQLQueryPlan(String hql, String collectionRole, boolean shallow, Map enabledFilters, SessionFactoryImplementor factory) {
+		this.sourceQuery = hql;
+		this.shallow = shallow;
+
+		Set copy = new HashSet();
+		copy.addAll( enabledFilters.keySet() );
+		this.enabledFilterNames = java.util.Collections.unmodifiableSet( copy );
+
+		Set combinedQuerySpaces = new HashSet();
+		String[] concreteQueryStrings = QuerySplitter.concreteQueries( hql, factory );
+		final int length = concreteQueryStrings.length;
+		translators = new QueryTranslator[length];
+		List sqlStringList = new ArrayList();
+		for ( int i=0; i<length; i++ ) {
+			if ( collectionRole == null ) {
+				translators[i] = factory.getSettings()
+						.getQueryTranslatorFactory()
+						.createQueryTranslator( hql, concreteQueryStrings[i], enabledFilters, factory );
+				translators[i].compile( factory.getSettings().getQuerySubstitutions(), shallow );
+			}
+			else {
+				translators[i] = factory.getSettings()
+						.getQueryTranslatorFactory()
+						.createFilterTranslator( hql, concreteQueryStrings[i], enabledFilters, factory );
+				( ( FilterTranslator ) translators[i] ).compile( collectionRole, factory.getSettings().getQuerySubstitutions(), shallow );
+			}
+			combinedQuerySpaces.addAll( translators[i].getQuerySpaces() );
+			sqlStringList.addAll( translators[i].collectSqlStrings() );
+		}
+
+		this.sqlStrings = ArrayHelper.toStringArray( sqlStringList );
+		this.querySpaces = combinedQuerySpaces;
+
+		if ( length == 0 ) {
+			parameterMetadata = new ParameterMetadata( null, null );
+			returnMetadata = null;
+		}
+		else {
+			this.parameterMetadata = buildParameterMetadata( translators[0].getParameterTranslations(), hql );
+			if ( translators[0].isManipulationStatement() ) {
+				returnMetadata = null;
+			}
+			else {
+				if ( length > 1 ) {
+					final int returns = translators[0].getReturnTypes().length;
+					returnMetadata = new ReturnMetadata( translators[0].getReturnAliases(), new Type[returns] );
+				}
+				else {
+					returnMetadata = new ReturnMetadata( translators[0].getReturnAliases(), translators[0].getReturnTypes() );
+				}
+			}
+		}
+	}
+
+	public String getSourceQuery() {
+		return sourceQuery;
+	}
+
+	public Set getQuerySpaces() {
+		return querySpaces;
+	}
+
+	public ParameterMetadata getParameterMetadata() {
+		return parameterMetadata;
+	}
+
+	public ReturnMetadata getReturnMetadata() {
+		return returnMetadata;
+	}
+
+	public Set getEnabledFilterNames() {
+		return enabledFilterNames;
+	}
+
+	public String[] getSqlStrings() {
+		return sqlStrings;
+	}
+
+	public Set getUtilizedFilterNames() {
+		// TODO : add this info to the translator and aggregate it here...
+		return null;
+	}
+
+	public boolean isShallow() {
+		return shallow;
+	}
+
+	public List performList(
+			QueryParameters queryParameters,
+	        SessionImplementor session) throws HibernateException {
+		if ( log.isTraceEnabled() ) {
+			log.trace( "find: " + getSourceQuery() );
+			queryParameters.traceParameters( session.getFactory() );
+		}
+		boolean hasLimit = queryParameters.getRowSelection() != null &&
+		                   queryParameters.getRowSelection().definesLimits();
+		boolean needsLimit = hasLimit && translators.length > 1;
+		QueryParameters queryParametersToUse;
+		if ( needsLimit ) {
+			log.warn( "firstResult/maxResults specified on polymorphic query; applying in memory!" );
+			RowSelection selection = new RowSelection();
+			selection.setFetchSize( queryParameters.getRowSelection().getFetchSize() );
+			selection.setTimeout( queryParameters.getRowSelection().getTimeout() );
+			queryParametersToUse = queryParameters.createCopyUsing( selection );
+		}
+		else {
+			queryParametersToUse = queryParameters;
+		}
+
+		List combinedResults = new ArrayList();
+		IdentitySet distinction = new IdentitySet();
+		int includedCount = -1;
+		translator_loop: for ( int i = 0; i < translators.length; i++ ) {
+			List tmp = translators[i].list( session, queryParametersToUse );
+			if ( needsLimit ) {
+				// NOTE : firstRow is zero-based
+				int first = queryParameters.getRowSelection().getFirstRow() == null
+				            ? 0
+			                : queryParameters.getRowSelection().getFirstRow().intValue();
+				int max = queryParameters.getRowSelection().getMaxRows() == null
+				            ? -1
+			                : queryParameters.getRowSelection().getMaxRows().intValue();
+				final int size = tmp.size();
+				for ( int x = 0; x < size; x++ ) {
+					final Object result = tmp.get( x );
+					if ( distinction.add( result ) ) {
+						continue;
+					}
+					includedCount++;
+					if ( includedCount < first ) {
+						continue;
+					}
+					combinedResults.add( result );
+					if ( max >= 0 && includedCount > max ) {
+						// break the outer loop !!!
+						break translator_loop;
+					}
+				}
+			}
+			else {
+				combinedResults.addAll( tmp );
+			}
+		}
+		return combinedResults;
+	}
+
+	public Iterator performIterate(
+			QueryParameters queryParameters,
+	        EventSource session) throws HibernateException {
+		if ( log.isTraceEnabled() ) {
+			log.trace( "iterate: " + getSourceQuery() );
+			queryParameters.traceParameters( session.getFactory() );
+		}
+		if ( translators.length == 0 ) {
+			return EmptyIterator.INSTANCE;
+		}
+
+		Iterator[] results = null;
+		boolean many = translators.length > 1;
+		if (many) {
+			results = new Iterator[translators.length];
+		}
+
+		Iterator result = null;
+		for ( int i = 0; i < translators.length; i++ ) {
+			result = translators[i].iterate( queryParameters, session );
+			if (many) results[i] = result;
+		}
+
+		return many ? new JoinedIterator(results) : result;
+	}
+
+	public ScrollableResults performScroll(
+			QueryParameters queryParameters,
+	        SessionImplementor session) throws HibernateException {
+		if ( log.isTraceEnabled() ) {
+			log.trace( "iterate: " + getSourceQuery() );
+			queryParameters.traceParameters( session.getFactory() );
+		}
+		if ( translators.length != 1 ) {
+			throw new QueryException( "implicit polymorphism not supported for scroll() queries" );
+		}
+		if ( queryParameters.getRowSelection().definesLimits() && translators[0].containsCollectionFetches() ) {
+			throw new QueryException( "firstResult/maxResults not supported in conjunction with scroll() of a query containing collection fetches" );
+		}
+
+		return translators[0].scroll( queryParameters, session );
+	}
+
+	public int performExecuteUpdate(QueryParameters queryParameters, SessionImplementor session)
+			throws HibernateException {
+		if ( log.isTraceEnabled() ) {
+			log.trace( "executeUpdate: " + getSourceQuery() );
+			queryParameters.traceParameters( session.getFactory() );
+		}
+		if ( translators.length != 1 ) {
+			log.warn( "manipulation query [" + getSourceQuery() + "] resulted in [" + translators.length + "] split queries" );
+		}
+		int result = 0;
+		for ( int i = 0; i < translators.length; i++ ) {
+			result += translators[i].executeUpdate( queryParameters, session );
+		}
+		return result;
+	}
+
+	private ParameterMetadata buildParameterMetadata(ParameterTranslations parameterTranslations, String hql) {
+		long start = System.currentTimeMillis();
+		ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( hql );
+		long end = System.currentTimeMillis();
+		if ( log.isTraceEnabled() ) {
+			log.trace( "HQL param location recognition took " + (end - start) + " mills (" + hql + ")" );
+		}
+
+		int ordinalParamCount = parameterTranslations.getOrdinalParameterCount();
+		int[] locations = ArrayHelper.toIntArray( recognizer.getOrdinalParameterLocationList() );
+		if ( parameterTranslations.supportsOrdinalParameterMetadata() && locations.length != ordinalParamCount ) {
+			throw new HibernateException( "ordinal parameter mismatch" );
+		}
+		ordinalParamCount = locations.length;
+		OrdinalParameterDescriptor[] ordinalParamDescriptors = new OrdinalParameterDescriptor[ordinalParamCount];
+		for ( int i = 1; i <= ordinalParamCount; i++ ) {
+			ordinalParamDescriptors[ i - 1 ] = new OrdinalParameterDescriptor(
+					i,
+			        parameterTranslations.supportsOrdinalParameterMetadata()
+		                    ? parameterTranslations.getOrdinalParameterExpectedType( i )
+		                    : null,
+			        locations[ i - 1 ]
+			);
+		}
+
+		Iterator itr = recognizer.getNamedParameterDescriptionMap().entrySet().iterator();
+		Map namedParamDescriptorMap = new HashMap();
+		while( itr.hasNext() ) {
+			final Map.Entry entry = ( Map.Entry ) itr.next();
+			final String name = ( String ) entry.getKey();
+			final ParamLocationRecognizer.NamedParameterDescription description =
+					( ParamLocationRecognizer.NamedParameterDescription ) entry.getValue();
+			namedParamDescriptorMap.put(
+					name,
+					new NamedParameterDescriptor(
+							name,
+					        parameterTranslations.getNamedParameterExpectedType( name ),
+					        description.buildPositionsArray(),
+					        description.isJpaStyle()
+					)
+			);
+		}
+
+		return new ParameterMetadata( ordinalParamDescriptors, namedParamDescriptorMap );
+	}
+
+	public QueryTranslator[] getTranslators() {
+		QueryTranslator[] copy = new QueryTranslator[translators.length];
+		System.arraycopy(translators, 0, copy, 0, copy.length);
+		return copy;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/NamedParameterDescriptor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/NamedParameterDescriptor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/NamedParameterDescriptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+package org.hibernate.engine.query;
+
+import org.hibernate.type.Type;
+
+import java.io.Serializable;
+
+/**
+ * Descriptor regarding a named parameter.
+ *
+ * @author Steve Ebersole
+ */
+public class NamedParameterDescriptor implements Serializable {
+	private final String name;
+	private final Type expectedType;
+	private final int[] sourceLocations;
+	private final boolean jpaStyle;
+
+	public NamedParameterDescriptor(String name, Type expectedType, int[] sourceLocations, boolean jpaStyle) {
+		this.name = name;
+		this.expectedType = expectedType;
+		this.sourceLocations = sourceLocations;
+		this.jpaStyle = jpaStyle;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public Type getExpectedType() {
+		return expectedType;
+	}
+
+	public int[] getSourceLocations() {
+		return sourceLocations;
+	}
+
+	public boolean isJpaStyle() {
+		return jpaStyle;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/NativeSQLQueryPlan.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/NativeSQLQueryPlan.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/NativeSQLQueryPlan.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,182 @@
+package org.hibernate.engine.query;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.QueryException;
+import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
+import org.hibernate.action.BulkOperationCleanupAction;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.event.EventSource;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.loader.custom.sql.SQLCustomQuery;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * Defines a query execution plan for a native-SQL query.
+ * 
+ * @author Steve Ebersole
+ */
+public class NativeSQLQueryPlan implements Serializable {
+	private final String sourceQuery;
+
+	private final SQLCustomQuery customQuery;
+
+	private static final Log log = LogFactory.getLog(NativeSQLQueryPlan.class);
+
+	public NativeSQLQueryPlan(
+			NativeSQLQuerySpecification specification,
+			SessionFactoryImplementor factory) {
+		this.sourceQuery = specification.getQueryString();
+
+		customQuery = new SQLCustomQuery(
+				specification.getQueryString(),
+				specification.getQueryReturns(),
+				specification.getQuerySpaces(),
+				factory );
+	}
+
+	public String getSourceQuery() {
+		return sourceQuery;
+	}
+
+	public SQLCustomQuery getCustomQuery() {
+		return customQuery;
+	}
+
+	private int[] getNamedParameterLocs(String name) throws QueryException {
+		Object loc = customQuery.getNamedParameterBindPoints().get( name );
+		if ( loc == null ) {
+			throw new QueryException(
+					"Named parameter does not appear in Query: " + name,
+					customQuery.getSQL() );
+		}
+		if ( loc instanceof Integer ) {
+			return new int[] { ((Integer) loc ).intValue() };
+		}
+		else {
+			return ArrayHelper.toIntArray( (List) loc );
+		}
+	}
+
+	/**
+	 * Bind positional parameter values to the <tt>PreparedStatement</tt>
+	 * (these are parameters specified by a JDBC-style ?).
+	 */
+	private int bindPositionalParameters(final PreparedStatement st,
+			final QueryParameters queryParameters, final int start,
+			final SessionImplementor session) throws SQLException,
+			HibernateException {
+
+		final Object[] values = queryParameters
+				.getFilteredPositionalParameterValues();
+		final Type[] types = queryParameters
+				.getFilteredPositionalParameterTypes();
+		int span = 0;
+		for (int i = 0; i < values.length; i++) {
+			types[i].nullSafeSet( st, values[i], start + span, session );
+			span += types[i].getColumnSpan( session.getFactory() );
+		}
+		return span;
+	}
+
+	/**
+	 * Bind named parameters to the <tt>PreparedStatement</tt>. This has an
+	 * empty implementation on this superclass and should be implemented by
+	 * subclasses (queries) which allow named parameters.
+	 */
+	private int bindNamedParameters(final PreparedStatement ps,
+			final Map namedParams, final int start,
+			final SessionImplementor session) throws SQLException,
+			HibernateException {
+
+		if ( namedParams != null ) {
+			// assumes that types are all of span 1
+			Iterator iter = namedParams.entrySet().iterator();
+			int result = 0;
+			while ( iter.hasNext() ) {
+				Map.Entry e = (Map.Entry) iter.next();
+				String name = (String) e.getKey();
+				TypedValue typedval = (TypedValue) e.getValue();
+				int[] locs = getNamedParameterLocs( name );
+				for (int i = 0; i < locs.length; i++) {
+					if ( log.isDebugEnabled() ) {
+						log.debug( "bindNamedParameters() "
+								+ typedval.getValue() + " -> " + name + " ["
+								+ (locs[i] + start ) + "]" );
+					}
+					typedval.getType().nullSafeSet( ps, typedval.getValue(),
+							locs[i] + start, session );
+				}
+				result += locs.length;
+			}
+			return result;
+		}
+		else {
+			return 0;
+		}
+	}
+
+	protected void coordinateSharedCacheCleanup(SessionImplementor session) {
+		BulkOperationCleanupAction action = new BulkOperationCleanupAction( session, getCustomQuery().getQuerySpaces() );
+
+		action.init();
+
+		if ( session.isEventSource() ) {
+			( ( EventSource ) session ).getActionQueue().addAction( action );
+		}
+	}
+
+	public int performExecuteUpdate(QueryParameters queryParameters,
+			SessionImplementor session) throws HibernateException {
+		
+		coordinateSharedCacheCleanup( session );
+		
+		if(queryParameters.isCallable()) {
+			throw new IllegalArgumentException("callable not yet supported for native queries");
+		}
+		
+		int result = 0;
+		PreparedStatement ps;
+		try {
+			queryParameters.processFilters( this.customQuery.getSQL(),
+					session );
+			String sql = queryParameters.getFilteredSQL();
+
+			ps = session.getBatcher().prepareStatement( sql );
+
+			try {
+				int col = 1;
+				col += bindPositionalParameters( ps, queryParameters, col,
+						session );
+				col += bindNamedParameters( ps, queryParameters
+						.getNamedParameters(), col, session );
+				result = ps.executeUpdate();
+			}
+			finally {
+				if ( ps != null ) {
+					session.getBatcher().closeStatement( ps );
+				}				
+			}			
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert( session.getFactory()
+					.getSQLExceptionConverter(), sqle,
+					"could not execute native bulk manipulation query", this.sourceQuery );
+		}
+
+		return result;
+	}
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/OrdinalParameterDescriptor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/OrdinalParameterDescriptor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/OrdinalParameterDescriptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+package org.hibernate.engine.query;
+
+import org.hibernate.type.Type;
+
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class OrdinalParameterDescriptor implements Serializable {
+	private final int ordinalPosition;
+	private final Type expectedType;
+	private final int sourceLocation;
+
+	public OrdinalParameterDescriptor(int ordinalPosition, Type expectedType, int sourceLocation) {
+		this.ordinalPosition = ordinalPosition;
+		this.expectedType = expectedType;
+		this.sourceLocation = sourceLocation;
+	}
+
+	public int getOrdinalPosition() {
+		return ordinalPosition;
+	}
+
+	public Type getExpectedType() {
+		return expectedType;
+	}
+
+	public int getSourceLocation() {
+		return sourceLocation;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ParamLocationRecognizer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ParamLocationRecognizer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ParamLocationRecognizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,108 @@
+package org.hibernate.engine.query;
+
+import org.hibernate.util.ArrayHelper;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Implements a parameter parser recognizer specifically for the purpose
+ * of journaling parameter locations.
+ *
+ * @author Steve Ebersole
+ */
+public class ParamLocationRecognizer implements ParameterParser.Recognizer {
+
+	public static class NamedParameterDescription {
+		private final boolean jpaStyle;
+		private final List positions = new ArrayList();
+
+		public NamedParameterDescription(boolean jpaStyle) {
+			this.jpaStyle = jpaStyle;
+		}
+
+		public boolean isJpaStyle() {
+			return jpaStyle;
+		}
+
+		private void add(int position) {
+			positions.add( new Integer( position ) );
+		}
+
+		public int[] buildPositionsArray() {
+			return ArrayHelper.toIntArray( positions );
+		}
+	}
+
+	private Map namedParameterDescriptions = new HashMap();
+	private List ordinalParameterLocationList = new ArrayList();
+
+	/**
+	 * Convenience method for creating a param location recognizer and
+	 * initiating the parse.
+	 *
+	 * @param query The query to be parsed for parameter locations.
+	 * @return The generated recognizer, with journaled location info.
+	 */
+	public static ParamLocationRecognizer parseLocations(String query) {
+		ParamLocationRecognizer recognizer = new ParamLocationRecognizer();
+		ParameterParser.parse( query, recognizer );
+		return recognizer;
+	}
+
+	/**
+	 * Returns the map of named parameter locations.  The map is keyed by
+	 * parameter name; the corresponding value is a (@link NamedParameterDescription}.
+	 *
+	 * @return The map of named parameter locations.
+	 */
+	public Map getNamedParameterDescriptionMap() {
+		return namedParameterDescriptions;
+	}
+
+	/**
+	 * Returns the list of ordinal parameter locations.  The list elements
+	 * are Integers, representing the location for that given ordinal.  Thus
+	 * {@link #getOrdinalParameterLocationList()}.elementAt(n) represents the
+	 * location for the nth parameter.
+	 *
+	 * @return The list of ordinal parameter locations.
+	 */
+	public List getOrdinalParameterLocationList() {
+		return ordinalParameterLocationList;
+	}
+
+
+	// Recognition code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void ordinalParameter(int position) {
+		ordinalParameterLocationList.add( new Integer( position ) );
+	}
+
+	public void namedParameter(String name, int position) {
+		getOrBuildNamedParameterDescription( name, false ).add( position );
+	}
+
+	public void jpaPositionalParameter(String name, int position) {
+		getOrBuildNamedParameterDescription( name, true ).add( position );
+	}
+
+	private NamedParameterDescription getOrBuildNamedParameterDescription(String name, boolean jpa) {
+		NamedParameterDescription desc = ( NamedParameterDescription ) namedParameterDescriptions.get( name );
+		if ( desc == null ) {
+			desc = new NamedParameterDescription( jpa );
+			namedParameterDescriptions.put( name, desc );
+		}
+		return desc;
+	}
+
+	public void other(char character) {
+		// don't care...
+	}
+
+	public void outParameter(int position) {
+		// don't care...
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ParameterMetadata.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ParameterMetadata.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ParameterMetadata.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,88 @@
+package org.hibernate.engine.query;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.QueryParameterException;
+import org.hibernate.type.Type;
+
+/**
+ * Encapsulates metadata about parameters encountered within a query.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class ParameterMetadata implements Serializable {
+
+	private static final OrdinalParameterDescriptor[] EMPTY_ORDINALS = new OrdinalParameterDescriptor[0];
+
+	private final OrdinalParameterDescriptor[] ordinalDescriptors;
+	private final Map namedDescriptorMap;
+
+	/**
+	 * Instantiates a ParameterMetadata container.
+	 *
+	 * @param ordinalDescriptors
+	 * @param namedDescriptorMap
+	 */
+	public ParameterMetadata(OrdinalParameterDescriptor[] ordinalDescriptors, Map namedDescriptorMap) {
+		if ( ordinalDescriptors == null ) {
+			this.ordinalDescriptors = EMPTY_ORDINALS;
+		}
+		else {
+			OrdinalParameterDescriptor[] copy = new OrdinalParameterDescriptor[ ordinalDescriptors.length ];
+			System.arraycopy( ordinalDescriptors, 0, copy, 0, ordinalDescriptors.length );
+			this.ordinalDescriptors = copy;
+		}
+		if ( namedDescriptorMap == null ) {
+			this.namedDescriptorMap = java.util.Collections.EMPTY_MAP;
+		}
+		else {
+			int size = ( int ) ( ( namedDescriptorMap.size() / .75 ) + 1 );
+			Map copy = new HashMap( size );
+			copy.putAll( namedDescriptorMap );
+			this.namedDescriptorMap = java.util.Collections.unmodifiableMap( copy );
+		}
+	}
+
+	public int getOrdinalParameterCount() {
+		return ordinalDescriptors.length;
+	}
+
+	public OrdinalParameterDescriptor getOrdinalParameterDescriptor(int position) {
+		if ( position < 1 || position > ordinalDescriptors.length ) {
+			throw new IndexOutOfBoundsException( "Remember that ordinal parameters are 1-based!" );
+		}
+		return ordinalDescriptors[position - 1];
+	}
+
+	public Type getOrdinalParameterExpectedType(int position) {
+		return getOrdinalParameterDescriptor( position ).getExpectedType();
+	}
+
+	public int getOrdinalParameterSourceLocation(int position) {
+		return getOrdinalParameterDescriptor( position ).getSourceLocation();
+	}
+
+	public Set getNamedParameterNames() {
+		return namedDescriptorMap.keySet();
+	}
+
+	public NamedParameterDescriptor getNamedParameterDescriptor(String name) {
+		NamedParameterDescriptor meta = ( NamedParameterDescriptor ) namedDescriptorMap.get( name );
+		if ( meta == null ) {
+			throw new QueryParameterException( "could not locate named parameter [" + name + "]" );
+		}
+		return meta;
+	}
+
+	public Type getNamedParameterExpectedType(String name) {
+		return getNamedParameterDescriptor( name ).getExpectedType();
+	}
+
+	public int[] getNamedParameterSourceLocations(String name) {
+		return getNamedParameterDescriptor( name ).getSourceLocations();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ParameterParser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ParameterParser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ParameterParser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,108 @@
+package org.hibernate.engine.query;
+
+import org.hibernate.QueryException;
+import org.hibernate.hql.classic.ParserHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * The single available method {@link #parse} is responsible for parsing a
+ * query string and recognizing tokens in relation to parameters (either
+ * named, JPA-style, or ordinal) and providing callbacks about such
+ * recognitions.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class ParameterParser {
+
+	public static interface Recognizer {
+		public void outParameter(int position);
+		public void ordinalParameter(int position);
+		public void namedParameter(String name, int position);
+		public void jpaPositionalParameter(String name, int position);
+		public void other(char character);
+	}
+
+	private ParameterParser() {
+		// disallow instantiation
+	}
+
+	/**
+	 * Performs the actual parsing and tokenizing of the query string making appropriate
+	 * callbacks to the given recognizer upon recognition of the various tokens.
+	 * <p/>
+	 * Note that currently, this only knows how to deal with a single output
+	 * parameter (for callable statements).  If we later add support for
+	 * multiple output params, this, obviously, needs to change.
+	 *
+	 * @param sqlString The string to be parsed/tokenized.
+	 * @param recognizer The thing which handles recognition events.
+	 * @throws QueryException
+	 */
+	public static void parse(String sqlString, Recognizer recognizer) throws QueryException {
+		boolean hasMainOutputParameter = sqlString.indexOf( "call" ) > 0 &&
+		                                 sqlString.indexOf( "?" ) < sqlString.indexOf( "call" ) &&
+		                                 sqlString.indexOf( "=" ) < sqlString.indexOf( "call" );
+		boolean foundMainOutputParam = false;
+
+		int stringLength = sqlString.length();
+		boolean inQuote = false;
+		for ( int indx = 0; indx < stringLength; indx++ ) {
+			char c = sqlString.charAt( indx );
+			if ( inQuote ) {
+				if ( '\'' == c ) {
+					inQuote = false;
+				}
+				recognizer.other( c );
+			}
+			else if ( '\'' == c ) {
+				inQuote = true;
+				recognizer.other( c );
+			}
+			else {
+				if ( c == ':' ) {
+					// named parameter
+					int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS, indx + 1 );
+					int chopLocation = right < 0 ? sqlString.length() : right;
+					String param = sqlString.substring( indx + 1, chopLocation );
+					if ( StringHelper.isEmpty( param ) ) {
+						throw new QueryException("Space is not allowed after parameter prefix ':' '"
+								+ sqlString + "'");
+					}
+					recognizer.namedParameter( param, indx );
+					indx = chopLocation - 1;
+				}
+				else if ( c == '?' ) {
+					// could be either an ordinal or JPA-positional parameter
+					if ( indx < stringLength - 1 && Character.isDigit( sqlString.charAt( indx + 1 ) ) ) {
+						// a peek ahead showed this as an JPA-positional parameter
+						int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS, indx + 1 );
+						int chopLocation = right < 0 ? sqlString.length() : right;
+						String param = sqlString.substring( indx + 1, chopLocation );
+						// make sure this "name" is an integral
+						try {
+							new Integer( param );
+						}
+						catch( NumberFormatException e ) {
+							throw new QueryException( "JPA-style positional param was not an integral ordinal" );
+						}
+						recognizer.jpaPositionalParameter( param, indx );
+						indx = chopLocation - 1;
+					}
+					else {
+						if ( hasMainOutputParameter && !foundMainOutputParam ) {
+							foundMainOutputParam = true;
+							recognizer.outParameter( indx );
+						}
+						else {
+							recognizer.ordinalParameter( indx );
+						}
+					}
+				}
+				else {
+					recognizer.other( c );
+				}
+			}
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/QueryMetadata.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/QueryMetadata.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/QueryMetadata.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,72 @@
+package org.hibernate.engine.query;
+
+import org.hibernate.type.Type;
+
+import java.io.Serializable;
+import java.util.Set;
+
+/**
+ * Defines metadata regarding a translated HQL or native-SQL query.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class QueryMetadata implements Serializable {
+	private final String sourceQuery;
+	private final ParameterMetadata parameterMetadata;
+	private final String[] returnAliases;
+	private final Type[] returnTypes;
+	private final Set querySpaces;
+
+	public QueryMetadata(
+			String sourceQuery,
+	        ParameterMetadata parameterMetadata,
+	        String[] returnAliases,
+	        Type[] returnTypes,
+	        Set querySpaces) {
+		this.sourceQuery = sourceQuery;
+		this.parameterMetadata = parameterMetadata;
+		this.returnAliases = returnAliases;
+		this.returnTypes = returnTypes;
+		this.querySpaces = querySpaces;
+	}
+
+	/**
+	 * Get the source HQL or native-SQL query.
+	 *
+	 * @return The source query.
+	 */
+	public String getSourceQuery() {
+		return sourceQuery;
+	}
+
+	public ParameterMetadata getParameterMetadata() {
+		return parameterMetadata;
+	}
+
+	/**
+	 * Return source query select clause aliases (if any)
+	 *
+	 * @return an array of aliases as strings.
+	 */
+	public String[] getReturnAliases() {
+		return returnAliases;
+	}
+
+	/**
+	 * An array of types describing the returns of the source query.
+	 *
+	 * @return The return type array.
+	 */
+	public Type[] getReturnTypes() {
+		return returnTypes;
+	}
+
+	/**
+	 * The set of query spaces affected by this source query.
+	 *
+	 * @return The set of query spaces.
+	 */
+	public Set getQuerySpaces() {
+		return querySpaces;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/QueryPlanCache.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/QueryPlanCache.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/QueryPlanCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,263 @@
+package org.hibernate.engine.query;
+
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.SimpleMRUCache;
+import org.hibernate.util.SoftLimitMRUCache;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
+import org.hibernate.QueryException;
+import org.hibernate.MappingException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+
+/**
+ * Acts as a cache for compiled query plans, as well as query-parameter metadata.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class QueryPlanCache implements Serializable {
+
+	private static final Log log = LogFactory.getLog( QueryPlanCache.class );
+
+	private SessionFactoryImplementor factory;
+
+	public QueryPlanCache(SessionFactoryImplementor factory) {
+		this.factory = factory;
+	}
+
+	// simple cache of param metadata based on query string.  Ideally, the
+	// original "user-supplied query" string should be used to retreive this
+	// metadata (i.e., not the para-list-expanded query string) to avoid
+	// unnecessary cache entries.
+	// Used solely for caching param metadata for native-sql queries, see
+	// getSQLParameterMetadata() for a discussion as to why...
+	private final SimpleMRUCache sqlParamMetadataCache = new SimpleMRUCache();
+
+	// the cache of the actual plans...
+	private final SoftLimitMRUCache planCache = new SoftLimitMRUCache( 128 );
+
+
+	public ParameterMetadata getSQLParameterMetadata(String query) {
+		ParameterMetadata metadata = ( ParameterMetadata ) sqlParamMetadataCache.get( query );
+		if ( metadata == null ) {
+			// for native-sql queries, the param metadata is determined outside
+			// any relation to a query plan, because query plan creation and/or
+			// retreival for a native-sql query depends on all of the return
+			// types having been set, which might not be the case up-front when
+			// param metadata would be most useful
+			metadata = buildNativeSQLParameterMetadata( query );
+			sqlParamMetadataCache.put( query, metadata );
+		}
+		return metadata;
+	}
+
+	public HQLQueryPlan getHQLQueryPlan(String queryString, boolean shallow, Map enabledFilters)
+			throws QueryException, MappingException {
+		HQLQueryPlanKey key = new HQLQueryPlanKey( queryString, shallow, enabledFilters );
+		HQLQueryPlan plan = ( HQLQueryPlan ) planCache.get ( key );
+
+		if ( plan == null ) {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "unable to locate HQL query plan in cache; generating (" + queryString + ")" );
+			}
+			plan = new HQLQueryPlan(queryString, shallow, enabledFilters, factory );
+		}
+		else {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "located HQL query plan in cache (" + queryString + ")" );
+			}
+		}
+
+		planCache.put( key, plan );
+
+		return plan;
+	}
+
+	public FilterQueryPlan getFilterQueryPlan(String filterString, String collectionRole, boolean shallow, Map enabledFilters)
+			throws QueryException, MappingException {
+		FilterQueryPlanKey key = new FilterQueryPlanKey( filterString, collectionRole, shallow, enabledFilters );
+		FilterQueryPlan plan = ( FilterQueryPlan ) planCache.get ( key );
+
+		if ( plan == null ) {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "unable to locate collection-filter query plan in cache; generating (" + collectionRole + " : " + filterString + ")" );
+			}
+			plan = new FilterQueryPlan( filterString, collectionRole, shallow, enabledFilters, factory );
+		}
+		else {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "located collection-filter query plan in cache (" + collectionRole + " : " + filterString + ")" );
+			}
+		}
+
+		planCache.put( key, plan );
+
+		return plan;
+	}
+
+	public NativeSQLQueryPlan getNativeSQLQueryPlan(NativeSQLQuerySpecification spec) {
+		NativeSQLQueryPlan plan = ( NativeSQLQueryPlan ) planCache.get( spec );
+
+		if ( plan == null ) {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "unable to locate native-sql query plan in cache; generating (" + spec.getQueryString() + ")" );
+			}
+			plan = new NativeSQLQueryPlan( spec, factory );
+		}
+		else {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "located native-sql query plan in cache (" + spec.getQueryString() + ")" );
+			}
+		}
+
+		planCache.put( spec, plan );
+		return plan;
+	}
+
+	private ParameterMetadata buildNativeSQLParameterMetadata(String sqlString) {
+		ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( sqlString );
+
+		OrdinalParameterDescriptor[] ordinalDescriptors =
+				new OrdinalParameterDescriptor[ recognizer.getOrdinalParameterLocationList().size() ];
+		for ( int i = 0; i < recognizer.getOrdinalParameterLocationList().size(); i++ ) {
+			final Integer position = ( Integer ) recognizer.getOrdinalParameterLocationList().get( i );
+			ordinalDescriptors[i] = new OrdinalParameterDescriptor( i, null, position.intValue() );
+		}
+
+		Iterator itr = recognizer.getNamedParameterDescriptionMap().entrySet().iterator();
+		Map namedParamDescriptorMap = new HashMap();
+		while( itr.hasNext() ) {
+			final Map.Entry entry = ( Map.Entry ) itr.next();
+			final String name = ( String ) entry.getKey();
+			final ParamLocationRecognizer.NamedParameterDescription description =
+					( ParamLocationRecognizer.NamedParameterDescription ) entry.getValue();
+			namedParamDescriptorMap.put(
+					name ,
+			        new NamedParameterDescriptor( name, null, description.buildPositionsArray(), description.isJpaStyle() )
+			);
+		}
+
+		return new ParameterMetadata( ordinalDescriptors, namedParamDescriptorMap );
+	}
+
+	private static class HQLQueryPlanKey implements Serializable {
+		private final String query;
+		private final boolean shallow;
+		private final Set filterNames;
+		private final int hashCode;
+
+		public HQLQueryPlanKey(String query, boolean shallow, Map enabledFilters) {
+			this.query = query;
+			this.shallow = shallow;
+
+			if ( enabledFilters == null || enabledFilters.isEmpty() ) {
+				filterNames = Collections.EMPTY_SET;
+			}
+			else {
+				Set tmp = new HashSet();
+				tmp.addAll( enabledFilters.keySet() );
+				this.filterNames = Collections.unmodifiableSet( tmp );
+			}
+
+			int hash = query.hashCode();
+			hash = 29 * hash + ( shallow ? 1 : 0 );
+			hash = 29 * hash + filterNames.hashCode();
+			this.hashCode = hash;
+		}
+
+		public boolean equals(Object o) {
+			if ( this == o ) {
+				return true;
+			}
+			if ( o == null || getClass() != o.getClass() ) {
+				return false;
+			}
+
+			final HQLQueryPlanKey that = ( HQLQueryPlanKey ) o;
+
+			if ( shallow != that.shallow ) {
+				return false;
+			}
+			if ( !filterNames.equals( that.filterNames ) ) {
+				return false;
+			}
+			if ( !query.equals( that.query ) ) {
+				return false;
+			}
+
+			return true;
+		}
+
+		public int hashCode() {
+			return hashCode;
+		}
+	}
+
+	private static class FilterQueryPlanKey implements Serializable {
+		private final String query;
+		private final String collectionRole;
+		private final boolean shallow;
+		private final Set filterNames;
+		private final int hashCode;
+
+		public FilterQueryPlanKey(String query, String collectionRole, boolean shallow, Map enabledFilters) {
+			this.query = query;
+			this.collectionRole = collectionRole;
+			this.shallow = shallow;
+
+			if ( enabledFilters == null || enabledFilters.isEmpty() ) {
+				filterNames = Collections.EMPTY_SET;
+			}
+			else {
+				Set tmp = new HashSet();
+				tmp.addAll( enabledFilters.keySet() );
+				this.filterNames = Collections.unmodifiableSet( tmp );
+			}
+
+			int hash = query.hashCode();
+			hash = 29 * hash + collectionRole.hashCode();
+			hash = 29 * hash + ( shallow ? 1 : 0 );
+			hash = 29 * hash + filterNames.hashCode();
+			this.hashCode = hash;
+		}
+
+		public boolean equals(Object o) {
+			if ( this == o ) {
+				return true;
+			}
+			if ( o == null || getClass() != o.getClass() ) {
+				return false;
+			}
+
+			final FilterQueryPlanKey that = ( FilterQueryPlanKey ) o;
+
+			if ( shallow != that.shallow ) {
+				return false;
+			}
+			if ( !filterNames.equals( that.filterNames ) ) {
+				return false;
+			}
+			if ( !query.equals( that.query ) ) {
+				return false;
+			}
+			if ( !collectionRole.equals( that.collectionRole ) ) {
+				return false;
+			}
+
+			return true;
+		}
+
+		public int hashCode() {
+			return hashCode;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ReturnMetadata.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ReturnMetadata.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/ReturnMetadata.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+package org.hibernate.engine.query;
+
+import org.hibernate.type.Type;
+
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class ReturnMetadata implements Serializable {
+	private final String[] returnAliases;
+	private final Type[] returnTypes;
+
+	public ReturnMetadata(String[] returnAliases, Type[] returnTypes) {
+		this.returnAliases = returnAliases;
+		this.returnTypes = returnTypes;
+	}
+
+	public String[] getReturnAliases() {
+		return returnAliases;
+	}
+
+	public Type[] getReturnTypes() {
+		return returnTypes;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryCollectionReturn.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryCollectionReturn.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryCollectionReturn.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+// $Id: NativeSQLQueryCollectionReturn.java 7232 2005-06-19 17:16:40 -0500 (Sun, 19 Jun 2005) maxcsaucdk $
+package org.hibernate.engine.query.sql;
+
+import java.util.Map;
+
+import org.hibernate.LockMode;
+
+/**
+ * Represents a return defined as part of a native sql query which
+ * names a collection role in the form {classname}.{collectionrole}; it
+ * is used in defining a custom sql query for loading an entity's
+ * collection in non-fetching scenarios (i.e., loading the collection
+ * itself as the "root" of the result).
+ *
+ * @author Steve Ebersole
+ */
+public class NativeSQLQueryCollectionReturn extends NativeSQLQueryNonScalarReturn {
+	private String ownerEntityName;
+	private String ownerProperty;
+
+	/**
+	 * Construct a native-sql return representing a collection initializer
+	 *
+	 * @param alias The result alias
+	 * @param ownerEntityName The entity-name of the entity owning the collection
+	 * to be initialized.
+	 * @param ownerProperty The property name (on the owner) which represents
+	 * the collection to be initialized.
+	 * @param propertyResults Any user-supplied column->property mappings
+	 * @param lockMode The lock mode to apply to the collection.
+	 */
+	public NativeSQLQueryCollectionReturn(
+			String alias,
+			String ownerEntityName,
+			String ownerProperty,
+			Map propertyResults,
+			LockMode lockMode) {
+		super( alias, propertyResults, lockMode );
+		this.ownerEntityName = ownerEntityName;
+		this.ownerProperty = ownerProperty;
+	}
+
+	/**
+	 * Returns the class owning the collection.
+	 *
+	 * @return The class owning the collection.
+	 */
+	public String getOwnerEntityName() {
+		return ownerEntityName;
+	}
+
+	/**
+	 * Returns the name of the property representing the collection from the {@link #getOwnerEntityName}.
+	 *
+	 * @return The name of the property representing the collection on the owner class.
+	 */
+	public String getOwnerProperty() {
+		return ownerProperty;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryJoinReturn.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryJoinReturn.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryJoinReturn.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,56 @@
+// $Id: NativeSQLQueryJoinReturn.java 7232 2005-06-19 17:16:40 -0500 (Sun, 19 Jun 2005) maxcsaucdk $
+package org.hibernate.engine.query.sql;
+
+import java.util.Map;
+
+import org.hibernate.LockMode;
+
+/**
+ * Represents a return defined as part of a native sql query which
+ * names a fetched role.
+ *
+ * @author Steve Ebersole
+ */
+public class NativeSQLQueryJoinReturn extends NativeSQLQueryNonScalarReturn {
+	private String ownerAlias;
+	private String ownerProperty;
+
+	/**
+	 * Construct a return descriptor representing some form of fetch.
+	 *
+	 * @param alias The result alias
+	 * @param ownerAlias The owner's result alias
+	 * @param ownerProperty The owner's property representing the thing to be fetched
+	 * @param propertyResults Any user-supplied column->property mappings
+	 * @param lockMode The lock mode to apply
+	 */
+	public NativeSQLQueryJoinReturn(
+			String alias,
+			String ownerAlias,
+			String ownerProperty,
+			Map propertyResults,
+			LockMode lockMode) {
+		super( alias, propertyResults, lockMode );
+		this.ownerAlias = ownerAlias;
+		this.ownerProperty = ownerProperty;
+	}
+
+	/**
+	 * Retrieve the alias of the owner of this fetched association.
+	 *
+	 * @return The owner's alias.
+	 */
+	public String getOwnerAlias() {
+		return ownerAlias;
+	}
+
+	/**
+	 * Retrieve the property name (relative to the owner) which maps to
+	 * the association to be fetched.
+	 *
+	 * @return The property name.
+	 */
+	public String getOwnerProperty() {
+		return ownerProperty;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryNonScalarReturn.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryNonScalarReturn.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryNonScalarReturn.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+// $Id: NativeSQLQueryNonScalarReturn.java 7232 2005-06-19 17:16:40 -0500 (Sun, 19 Jun 2005) maxcsaucdk $
+package org.hibernate.engine.query.sql;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+
+/**
+ * Represents the base information for a non-scalar return defined as part of
+ * a native sql query.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class NativeSQLQueryNonScalarReturn implements NativeSQLQueryReturn, Serializable {
+	private final String alias;
+	private final LockMode lockMode;
+	private final Map propertyResults = new HashMap();
+
+	/**
+	 * Constructs some form of non-scalar return descriptor
+	 *
+	 * @param alias The result alias
+	 * @param propertyResults Any user-supplied column->property mappings
+	 * @param lockMode The lock mode to apply to the return.
+	 */
+	protected NativeSQLQueryNonScalarReturn(String alias, Map propertyResults, LockMode lockMode) {
+		this.alias = alias;
+		if ( alias == null ) {
+			throw new HibernateException("alias must be specified");
+		}
+		this.lockMode = lockMode;
+		if ( propertyResults != null ) {
+			this.propertyResults.putAll( propertyResults );
+		}
+	}
+
+	/**
+	 * Retrieve the defined result alias
+	 *
+	 * @return The result alias.
+	 */
+	public String getAlias() {
+		return alias;
+	}
+
+	/**
+	 * Retrieve the lock-mode to apply to this return
+	 *
+	 * @return The lock mode
+	 */
+	public LockMode getLockMode() {
+		return lockMode;
+	}
+
+	/**
+	 * Retrieve the user-supplied column->property mappings.
+	 *
+	 * @return The property mappings.
+	 */
+	public Map getPropertyResultsMap() {
+		return Collections.unmodifiableMap( propertyResults );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryReturn.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryReturn.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryReturn.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+package org.hibernate.engine.query.sql;
+
+/**
+ * Describes a return in a native SQL query.
+ *
+ * @author Steve Ebersole
+ */
+public interface NativeSQLQueryReturn {
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryRootReturn.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryRootReturn.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryRootReturn.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+// $Id: NativeSQLQueryRootReturn.java 7232 2005-06-19 17:16:40 -0500 (Sun, 19 Jun 2005) maxcsaucdk $
+package org.hibernate.engine.query.sql;
+
+import java.util.Map;
+
+import org.hibernate.LockMode;
+
+/**
+ * Represents a return defined as part of a native sql query which
+ * names a "root" entity.  A root entity means it is explicitly a
+ * "column" in the result, as opposed to a fetched relationship or role.
+ *
+ * @author Steve Ebersole
+ */
+public class NativeSQLQueryRootReturn extends NativeSQLQueryNonScalarReturn {
+	private String returnEntityName;
+
+	/**
+	 * Construct a return representing an entity returned at the root
+	 * of the result.
+	 *
+	 * @param alias The result alias
+	 * @param entityName The entity name.
+	 * @param lockMode The lock mode to apply
+	 */
+	public NativeSQLQueryRootReturn(String alias, String entityName, LockMode lockMode) {
+		this(alias, entityName, null, lockMode);
+	}
+
+	/**
+	 *
+	 * @param alias The result alias
+	 * @param entityName The entity name.
+	 * @param propertyResults Any user-supplied column->property mappings
+	 * @param lockMode The lock mode to apply
+	 */
+	public NativeSQLQueryRootReturn(String alias, String entityName, Map propertyResults, LockMode lockMode) {
+		super( alias, propertyResults, lockMode );
+		this.returnEntityName = entityName;
+
+	}
+
+	/**
+	 * The name of the entity to be returned.
+	 *
+	 * @return The entity name
+	 */
+	public String getReturnEntityName() {
+		return returnEntityName;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryScalarReturn.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryScalarReturn.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQueryScalarReturn.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+package org.hibernate.engine.query.sql;
+
+import org.hibernate.type.Type;
+
+/**
+ * Describes a scalar return in a native SQL query.
+ *
+ * @author gloegl
+ */
+public class NativeSQLQueryScalarReturn implements NativeSQLQueryReturn {
+	private Type type;
+	private String columnAlias;
+
+	public NativeSQLQueryScalarReturn(String alias, Type type) {
+		this.type = type;
+		this.columnAlias = alias;
+	}
+
+	public String getColumnAlias() {
+		return columnAlias;
+	}
+
+	public Type getType() {
+		return type;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQuerySpecification.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQuerySpecification.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/query/sql/NativeSQLQuerySpecification.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,80 @@
+package org.hibernate.engine.query.sql;
+
+import org.hibernate.util.ArrayHelper;
+
+import java.util.Set;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Defines the specification or blue-print for a native-sql query.
+ * Essentially a simple struct containing the information needed to "translate"
+ * a native-sql query and cache that translated representation.  Also used as
+ * the key by which the native-sql query plans are cached.
+ *
+ * @author Steve Ebersole
+ */
+public class NativeSQLQuerySpecification {
+	private final String queryString;
+	private final NativeSQLQueryReturn[] queryReturns;
+	private final Set querySpaces;
+	private final int hashCode;
+
+	public NativeSQLQuerySpecification(
+			String queryString,
+	        NativeSQLQueryReturn[] queryReturns,
+	        Collection querySpaces) {
+		this.queryString = queryString;
+		this.queryReturns = queryReturns;
+		if ( querySpaces == null ) {
+			this.querySpaces = Collections.EMPTY_SET;
+		}
+		else {
+			Set tmp = new HashSet();
+			tmp.addAll( querySpaces );
+			this.querySpaces = Collections.unmodifiableSet( tmp );
+		}
+
+		// pre-determine and cache the hashcode
+		int hashCode = queryString.hashCode();
+		hashCode = 29 * hashCode + this.querySpaces.hashCode();
+		if ( this.queryReturns != null ) {
+			hashCode = 29 * hashCode + ArrayHelper.toList( this.queryReturns ).hashCode();
+		}
+		this.hashCode = hashCode;
+	}
+
+	public String getQueryString() {
+		return queryString;
+	}
+
+	public NativeSQLQueryReturn[] getQueryReturns() {
+		return queryReturns;
+	}
+
+	public Set getQuerySpaces() {
+		return querySpaces;
+	}
+
+	public boolean equals(Object o) {
+		if ( this == o ) {
+			return true;
+		}
+		if ( o == null || getClass() != o.getClass() ) {
+			return false;
+		}
+
+		final NativeSQLQuerySpecification that = ( NativeSQLQuerySpecification ) o;
+
+		return querySpaces.equals( that.querySpaces ) &&
+		       queryString.equals( that.queryString ) &&
+		       Arrays.equals( queryReturns, that.queryReturns );
+	}
+
+
+	public int hashCode() {
+		return hashCode;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/transaction/IsolatedWork.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/transaction/IsolatedWork.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/transaction/IsolatedWork.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+package org.hibernate.engine.transaction;
+
+import org.hibernate.HibernateException;
+
+import java.sql.Connection;
+
+/**
+ * Represents work that needs to be performed in a manner
+ * which isolates it from any current application unit of
+ * work transaction.
+ *
+ * @author Steve Ebersole
+ */
+public interface IsolatedWork {
+	/**
+	 * Perform the actual work to be done.
+	 *
+	 * @param connection The JDBC connection to use.
+	 * @throws HibernateException
+	 */
+	public void doWork(Connection connection) throws HibernateException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/engine/transaction/Isolater.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/engine/transaction/Isolater.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/engine/transaction/Isolater.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,230 @@
+package org.hibernate.engine.transaction;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.exception.JDBCExceptionHelper;
+
+/**
+ * Class which provides the isolation semantics required by
+ * an {@link IsolatedWork}.  Processing comes in two flavors:<ul>
+ * <li>{@link #doIsolatedWork} : makes sure the work to be done is
+ * performed in a seperate, distinct transaction</li>
+ * <li>{@link #doNonTransactedWork} : makes sure the work to be
+ * done is performed outside the scope of any transaction</li>
+ * </ul>
+ *
+ * @author Steve Ebersole
+ */
+public class Isolater {
+
+	private static final Log log = LogFactory.getLog( Isolater.class );
+
+	/**
+	 * Ensures that all processing actually performed by the given work will
+	 * occur on a seperate transaction.
+	 *
+	 * @param work The work to be performed.
+	 * @param session The session from which this request is originating.
+	 * @throws HibernateException
+	 */
+	public static void doIsolatedWork(IsolatedWork work, SessionImplementor session) throws HibernateException {
+		boolean isJta = session.getFactory().getTransactionManager() != null;
+		if ( isJta ) {
+			new JtaDelegate( session ).delegateWork( work, true );
+		}
+		else {
+			new JdbcDelegate( session ).delegateWork( work, true );
+		}
+	}
+
+	/**
+	 * Ensures that all processing actually performed by the given work will
+	 * occur outside of a transaction.
+	 *
+	 * @param work The work to be performed.
+	 * @param session The session from which this request is originating.
+	 * @throws HibernateException
+	 */
+	public static void doNonTransactedWork(IsolatedWork work, SessionImplementor session) throws HibernateException {
+		boolean isJta = session.getFactory().getTransactionManager() != null;
+		if ( isJta ) {
+			new JtaDelegate( session ).delegateWork( work, false );
+		}
+		else {
+			new JdbcDelegate( session ).delegateWork( work, false );
+		}
+	}
+
+	// should be ok performance-wise to generate new delegate instances for each
+	// request since these are locally stack-scoped.  Besides, it makes the code
+	// much easier to read than the old TransactionHelper stuff...
+
+	private static interface Delegate {
+		public void delegateWork(IsolatedWork work, boolean transacted) throws HibernateException;
+	}
+
+	/**
+	 * An isolation delegate for JTA-based transactions.  Essentially susepnds
+	 * any current transaction, does the work in a new transaction, and then
+	 * resumes the initial transaction (if there was one).
+	 */
+	public static class JtaDelegate implements Delegate {
+		private final SessionImplementor session;
+
+		public JtaDelegate(SessionImplementor session) {
+			this.session = session;
+		}
+
+		public void delegateWork(IsolatedWork work, boolean transacted) throws HibernateException {
+			TransactionManager transactionManager = session.getFactory().getTransactionManager();
+			Transaction surroundingTransaction = null;
+			Connection connection = null;
+			boolean caughtException = false;
+
+			try {
+				// First we need to suspend any current JTA transaction and obtain
+				// a JDBC connection
+				surroundingTransaction = transactionManager.suspend();
+				if ( log.isDebugEnabled() ) {
+					log.debug( "surrounding JTA transaction suspended [" + surroundingTransaction + "]" );
+				}
+
+				if ( transacted ) {
+					transactionManager.begin();
+				}
+
+				connection = session.getBatcher().openConnection();
+
+				// perform the actual work
+				work.doWork( connection );
+
+				// if everything went ok, commit the transaction and close the obtained
+				// connection handle...
+				session.getBatcher().closeConnection( connection );
+
+				if ( transacted ) {
+					transactionManager.commit();
+				}
+			}
+			catch( Throwable t ) {
+				// at some point the processing went bad, so we need to:
+				//      1) make sure the connection handle gets released
+				//      2) try to cleanup the JTA context as much as possible
+				caughtException = true;
+				try {
+					if ( connection != null && !connection.isClosed() ) {
+						session.getBatcher().closeConnection( connection );
+					}
+				}
+				catch( Throwable ignore ) {
+					log.trace( "unable to release connection on exception [" + ignore + "]" );
+				}
+				if ( transacted ) {
+					try {
+						transactionManager.rollback();
+					}
+					catch( Throwable ignore ) {
+						log.trace( "unable to rollback new transaction on exception [" + ignore + "]" );
+					}
+				}
+				// finally handle the exception
+				if ( t instanceof HibernateException ) {
+					throw ( HibernateException ) t;
+				}
+				else {
+					throw new HibernateException( "error performing isolated work", t );
+				}
+			}
+			finally {
+				if ( surroundingTransaction != null ) {
+					try {
+						transactionManager.resume( surroundingTransaction );
+						if ( log.isDebugEnabled() ) {
+							log.debug( "surrounding JTA transaction resumed [" + surroundingTransaction + "]" );
+						}
+					}
+					catch( Throwable t ) {
+						if ( !caughtException ) {
+							throw new HibernateException( "unable to resume previously suspended transaction", t );
+						}
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * An isolation delegate for JDBC-based transactions.  Basically just
+	 * grabs a new connection and does the work on that.
+	 */
+	public static class JdbcDelegate implements Delegate {
+		private final SessionImplementor session;
+
+		public JdbcDelegate(SessionImplementor session) {
+			this.session = session;
+		}
+
+		public void delegateWork(IsolatedWork work, boolean transacted) throws HibernateException {
+			Connection connection = null;
+			boolean wasAutoCommit = false;
+			try {
+				connection = session.getBatcher().openConnection();
+
+				if ( transacted ) {
+					if ( connection.getAutoCommit() ) {
+						wasAutoCommit = true;
+						connection.setAutoCommit( false );
+					}
+				}
+
+				work.doWork( connection );
+
+				if ( transacted ) {
+					connection.commit();
+				}
+			}
+			catch( Throwable t ) {
+				try {
+					if ( transacted && connection != null && !connection.isClosed() ) {
+						connection.rollback();
+					}
+				}
+				catch( Throwable ignore ) {
+					log.trace( "unable to release connection on exception [" + ignore + "]" );
+				}
+
+				if ( t instanceof HibernateException ) {
+					throw ( HibernateException ) t;
+				}
+				else if ( t instanceof SQLException ) {
+					throw JDBCExceptionHelper.convert(
+							session.getFactory().getSQLExceptionConverter(),
+					        ( SQLException ) t,
+					        "error performing isolated work"
+					);
+				}
+				else {
+					throw new HibernateException( "error performing isolated work", t );
+				}
+			}
+			finally {
+				if ( transacted && wasAutoCommit ) {
+					try {
+						connection.setAutoCommit( true );
+					}
+					catch( Throwable ignore ) {
+						log.trace( "was unable to reset connection back to auto-commit" );
+					}
+				}
+				session.getBatcher().closeConnection( connection );
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/AbstractEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/AbstractEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/AbstractEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: AbstractEvent.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+
+/**
+ * Defines a base class for Session generated events.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractEvent implements Serializable {
+
+	private final EventSource session;
+
+    /**
+     * Constructs an event from the given event session.
+     *
+     * @param source The session event source.
+     */
+	public AbstractEvent(EventSource source) {
+		this.session = source;
+	}
+
+    /**
+     * Returns the session event source for this event.  This is the underlying
+     * session from which this event was generated.
+     *
+     * @return The session event source.
+     */
+	public final EventSource getSession() {
+		return session;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/AutoFlushEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/AutoFlushEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/AutoFlushEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+///$Id: AutoFlushEvent.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event;
+
+import java.util.Set;
+
+
+/** Defines an event class for the auto-flushing of a session.
+ *
+ * @author Steve Ebersole
+ */
+public class AutoFlushEvent extends FlushEvent {
+
+	private Set querySpaces;
+	private boolean flushRequired;
+
+	public AutoFlushEvent(Set querySpaces, EventSource source) {
+		super(source);
+		this.querySpaces = querySpaces;
+	}
+
+	public Set getQuerySpaces() {
+		return querySpaces;
+	}
+
+	public void setQuerySpaces(Set querySpaces) {
+		this.querySpaces = querySpaces;
+	}
+
+	public boolean isFlushRequired() {
+		return flushRequired;
+	}
+
+	public void setFlushRequired(boolean dirty) {
+		this.flushRequired = dirty;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/AutoFlushEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/AutoFlushEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/AutoFlushEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+//$Id: AutoFlushEventListener.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.HibernateException;
+
+import java.io.Serializable;
+
+/**
+ * Defines the contract for handling of session auto-flush events.
+ *
+ * @author Steve Ebersole
+ */
+public interface AutoFlushEventListener extends Serializable {
+
+    /** Handle the given auto-flush event.
+     *
+     * @param event The auto-flush event to be handled.
+     * @throws HibernateException
+     */
+	public void onAutoFlush(AutoFlushEvent event) throws HibernateException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/DeleteEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/DeleteEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/DeleteEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,59 @@
+//$Id: DeleteEvent.java 7450 2005-07-11 20:33:59Z steveebersole $
+package org.hibernate.event;
+
+
+/** Defines an event class for the deletion of an entity.
+ *
+ * @author Steve Ebersole
+ */
+public class DeleteEvent extends AbstractEvent {
+
+	private Object object;
+	private String entityName;
+	private boolean cascadeDeleteEnabled;
+
+	/**
+	 * Constructs a new DeleteEvent instance.
+	 *
+	 * @param object The entity to be deleted.
+	 * @param source The session from which the delete event was generated.
+	 */
+	public DeleteEvent(Object object, EventSource source) {
+		super(source);
+		if (object == null) {
+			throw new IllegalArgumentException(
+					"attempt to create delete event with null entity"
+				);
+		}
+		this.object = object;
+	}
+
+	public DeleteEvent(String entityName, Object object, EventSource source) {
+		this(object, source);
+		this.entityName = entityName;
+	}
+
+	public DeleteEvent(String entityName, Object object, boolean isCascadeDeleteEnabled, EventSource source) {
+		this(object, source);
+		this.entityName = entityName;
+		cascadeDeleteEnabled = isCascadeDeleteEnabled;
+	}
+
+	/**
+     * Returns the encapsulated entity to be deleed.
+     *
+     * @return The entity to be deleted.
+     */
+	public Object getObject() {
+		return object;
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+	
+	public boolean isCascadeDeleteEnabled() {
+		return cascadeDeleteEnabled;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/DeleteEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/DeleteEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/DeleteEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+//$Id: DeleteEventListener.java 9944 2006-05-24 21:14:56Z steve.ebersole at jboss.com $
+package org.hibernate.event;
+
+import org.hibernate.HibernateException;
+
+import java.io.Serializable;
+import java.util.Set;
+
+/**
+ * Defines the contract for handling of deletion events generated from a session.
+ *
+ * @author Steve Ebersole
+ */
+public interface DeleteEventListener extends Serializable {
+
+    /** Handle the given delete event.
+     *
+     * @param event The delete event to be handled.
+     * @throws HibernateException
+     */
+	public void onDelete(DeleteEvent event) throws HibernateException;
+
+	public void onDelete(DeleteEvent event, Set transientEntities) throws HibernateException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/DirtyCheckEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/DirtyCheckEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/DirtyCheckEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+//$Id: DirtyCheckEvent.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event;
+
+
+/** Defines an event class for the dirty-checking of a session.
+ *
+ * @author Steve Ebersole
+ */
+public class DirtyCheckEvent extends FlushEvent {
+	
+	private boolean dirty;
+
+	public DirtyCheckEvent(EventSource source) {
+		super(source);
+	}
+
+	public boolean isDirty() {
+		return dirty;
+	}
+
+	public void setDirty(boolean dirty) {
+		this.dirty = dirty;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/DirtyCheckEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/DirtyCheckEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/DirtyCheckEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: DirtyCheckEventListener.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.HibernateException;
+
+import java.io.Serializable;
+
+/**
+ * Defines the contract for handling of session dirty-check events.
+ *
+ * @author Steve Ebersole
+ */
+public interface DirtyCheckEventListener extends Serializable {
+
+    /** Handle the given dirty-check event.
+     *
+     * @param event The dirty-check event to be handled.
+     * @throws HibernateException
+     */
+	public void onDirtyCheck(DirtyCheckEvent event) throws HibernateException;
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/EventListeners.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/EventListeners.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/EventListeners.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,390 @@
+//$Id: EventListeners.java 8416 2005-10-16 13:27:54Z epbernard $
+package org.hibernate.event;
+
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.MappingException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.event.def.DefaultAutoFlushEventListener;
+import org.hibernate.event.def.DefaultDeleteEventListener;
+import org.hibernate.event.def.DefaultDirtyCheckEventListener;
+import org.hibernate.event.def.DefaultEvictEventListener;
+import org.hibernate.event.def.DefaultFlushEntityEventListener;
+import org.hibernate.event.def.DefaultFlushEventListener;
+import org.hibernate.event.def.DefaultInitializeCollectionEventListener;
+import org.hibernate.event.def.DefaultLoadEventListener;
+import org.hibernate.event.def.DefaultLockEventListener;
+import org.hibernate.event.def.DefaultMergeEventListener;
+import org.hibernate.event.def.DefaultPersistEventListener;
+import org.hibernate.event.def.DefaultPostLoadEventListener;
+import org.hibernate.event.def.DefaultPreLoadEventListener;
+import org.hibernate.event.def.DefaultRefreshEventListener;
+import org.hibernate.event.def.DefaultReplicateEventListener;
+import org.hibernate.event.def.DefaultSaveEventListener;
+import org.hibernate.event.def.DefaultSaveOrUpdateCopyEventListener;
+import org.hibernate.event.def.DefaultSaveOrUpdateEventListener;
+import org.hibernate.event.def.DefaultUpdateEventListener;
+import org.hibernate.event.def.DefaultPersistOnFlushEventListener;
+import org.hibernate.util.Cloneable;
+
+/**
+ * A convience holder for all defined session event listeners.
+ *
+ * @author Steve Ebersole
+ */
+public class EventListeners extends Cloneable implements Serializable {
+
+	private LoadEventListener[] loadEventListeners = { new DefaultLoadEventListener() };
+	private SaveOrUpdateEventListener[] saveOrUpdateEventListeners = { new DefaultSaveOrUpdateEventListener() };
+	private MergeEventListener[] mergeEventListeners = { new DefaultMergeEventListener() };
+	private PersistEventListener[] persistEventListeners = { new DefaultPersistEventListener() };
+	private PersistEventListener[] persistOnFlushEventListeners = { new DefaultPersistOnFlushEventListener() };
+	private ReplicateEventListener[] replicateEventListeners = { new DefaultReplicateEventListener() };
+	private DeleteEventListener[] deleteEventListeners = { new DefaultDeleteEventListener() };
+	private AutoFlushEventListener[] autoFlushEventListeners = { new DefaultAutoFlushEventListener() };
+	private DirtyCheckEventListener[] dirtyCheckEventListeners = { new DefaultDirtyCheckEventListener() };
+	private FlushEventListener[] flushEventListeners = { new DefaultFlushEventListener() };
+	private EvictEventListener[] evictEventListeners = { new DefaultEvictEventListener() };
+	private LockEventListener[] lockEventListeners = { new DefaultLockEventListener() };
+	private RefreshEventListener[] refreshEventListeners = { new DefaultRefreshEventListener() };
+	private FlushEntityEventListener[] flushEntityEventListeners = { new DefaultFlushEntityEventListener() };
+	private InitializeCollectionEventListener[] initializeCollectionEventListeners = 
+			{ new DefaultInitializeCollectionEventListener() };
+
+	private PostLoadEventListener[] postLoadEventListeners = { new DefaultPostLoadEventListener() };
+	private PreLoadEventListener[] preLoadEventListeners = { new DefaultPreLoadEventListener() };
+	
+	private PreDeleteEventListener[] preDeleteEventListeners = {};
+	private PreUpdateEventListener[] preUpdateEventListeners = {};
+	private PreInsertEventListener[] preInsertEventListeners = {};
+	private PostDeleteEventListener[] postDeleteEventListeners = {};
+	private PostUpdateEventListener[] postUpdateEventListeners = {};
+	private PostInsertEventListener[] postInsertEventListeners = {};
+	private PostDeleteEventListener[] postCommitDeleteEventListeners = {};
+	private PostUpdateEventListener[] postCommitUpdateEventListeners = {};
+	private PostInsertEventListener[] postCommitInsertEventListeners = {};
+
+	private SaveOrUpdateEventListener[] saveEventListeners = { new DefaultSaveEventListener() };
+	private SaveOrUpdateEventListener[] updateEventListeners = { new DefaultUpdateEventListener() };
+	private MergeEventListener[] saveOrUpdateCopyEventListeners = { new DefaultSaveOrUpdateCopyEventListener() };//saveOrUpdateCopy() is deprecated!
+
+	private static Map eventInterfaceFromType;
+
+	static {
+		eventInterfaceFromType = new HashMap();
+
+		eventInterfaceFromType.put("auto-flush", AutoFlushEventListener.class);
+		eventInterfaceFromType.put("merge", MergeEventListener.class);
+		eventInterfaceFromType.put("create", PersistEventListener.class);
+		eventInterfaceFromType.put("create-onflush", PersistEventListener.class);
+		eventInterfaceFromType.put("delete", DeleteEventListener.class);
+		eventInterfaceFromType.put("dirty-check", DirtyCheckEventListener.class);
+		eventInterfaceFromType.put("evict", EvictEventListener.class);
+		eventInterfaceFromType.put("flush", FlushEventListener.class);
+		eventInterfaceFromType.put("flush-entity", FlushEntityEventListener.class);
+		eventInterfaceFromType.put("load", LoadEventListener.class);
+		eventInterfaceFromType.put("load-collection", InitializeCollectionEventListener.class);
+		eventInterfaceFromType.put("lock", LockEventListener.class);
+		eventInterfaceFromType.put("refresh", RefreshEventListener.class);
+		eventInterfaceFromType.put("replicate", ReplicateEventListener.class);
+		eventInterfaceFromType.put("save-update", SaveOrUpdateEventListener.class);
+		eventInterfaceFromType.put("save", SaveOrUpdateEventListener.class);
+		eventInterfaceFromType.put("update", SaveOrUpdateEventListener.class);
+		eventInterfaceFromType.put("pre-load", PreLoadEventListener.class);
+		eventInterfaceFromType.put("pre-update", PreUpdateEventListener.class);
+		eventInterfaceFromType.put("pre-delete", PreDeleteEventListener.class);
+		eventInterfaceFromType.put("pre-insert", PreInsertEventListener.class);
+		eventInterfaceFromType.put("post-load", PostLoadEventListener.class);
+		eventInterfaceFromType.put("post-update", PostUpdateEventListener.class);
+		eventInterfaceFromType.put("post-delete", PostDeleteEventListener.class);
+		eventInterfaceFromType.put("post-insert", PostInsertEventListener.class);
+		eventInterfaceFromType.put("post-commit-update", PostUpdateEventListener.class);
+		eventInterfaceFromType.put("post-commit-delete", PostDeleteEventListener.class);
+		eventInterfaceFromType.put("post-commit-insert", PostInsertEventListener.class);
+		eventInterfaceFromType = Collections.unmodifiableMap( eventInterfaceFromType );
+	}
+
+	public Class getListenerClassFor(String type) {
+		Class clazz = (Class) eventInterfaceFromType.get(type);
+		
+		if (clazz == null) {
+			throw new MappingException("Unrecognized listener type [" + type + "]");
+		}
+
+		return clazz;
+	}
+
+    public LoadEventListener[] getLoadEventListeners() {
+        return loadEventListeners;
+    }
+
+    public void setLoadEventListeners(LoadEventListener[] loadEventListener) {
+        this.loadEventListeners = loadEventListener;
+    }
+
+	public ReplicateEventListener[] getReplicateEventListeners() {
+		return replicateEventListeners;
+	}
+
+	public void setReplicateEventListeners(ReplicateEventListener[] replicateEventListener) {
+		this.replicateEventListeners = replicateEventListener;
+	}
+
+	public DeleteEventListener[] getDeleteEventListeners() {
+		return deleteEventListeners;
+	}
+
+	public void setDeleteEventListeners(DeleteEventListener[] deleteEventListener) {
+		this.deleteEventListeners = deleteEventListener;
+	}
+
+	public AutoFlushEventListener[] getAutoFlushEventListeners() {
+		return autoFlushEventListeners;
+	}
+
+	public void setAutoFlushEventListeners(AutoFlushEventListener[] autoFlushEventListener) {
+		this.autoFlushEventListeners = autoFlushEventListener;
+	}
+
+	public DirtyCheckEventListener[] getDirtyCheckEventListeners() {
+		return dirtyCheckEventListeners;
+	}
+
+	public void setDirtyCheckEventListeners(DirtyCheckEventListener[] dirtyCheckEventListener) {
+		this.dirtyCheckEventListeners = dirtyCheckEventListener;
+	}
+
+	public FlushEventListener[] getFlushEventListeners() {
+		return flushEventListeners;
+	}
+
+	public void setFlushEventListeners(FlushEventListener[] flushEventListener) {
+		this.flushEventListeners = flushEventListener;
+	}
+
+	public EvictEventListener[] getEvictEventListeners() {
+		return evictEventListeners;
+	}
+
+	public void setEvictEventListeners(EvictEventListener[] evictEventListener) {
+		this.evictEventListeners = evictEventListener;
+	}
+
+	public LockEventListener[] getLockEventListeners() {
+		return lockEventListeners;
+	}
+
+	public void setLockEventListeners(LockEventListener[] lockEventListener) {
+		this.lockEventListeners = lockEventListener;
+	}
+
+	public RefreshEventListener[] getRefreshEventListeners() {
+		return refreshEventListeners;
+	}
+
+	public void setRefreshEventListeners(RefreshEventListener[] refreshEventListener) {
+		this.refreshEventListeners = refreshEventListener;
+	}
+
+	public InitializeCollectionEventListener[] getInitializeCollectionEventListeners() {
+		return initializeCollectionEventListeners;
+	}
+
+	public void setInitializeCollectionEventListeners(InitializeCollectionEventListener[] initializeCollectionEventListener) {
+		this.initializeCollectionEventListeners = initializeCollectionEventListener;
+	}
+	
+	public FlushEntityEventListener[] getFlushEntityEventListeners() {
+		return flushEntityEventListeners;
+	}
+	
+	public void setFlushEntityEventListeners(FlushEntityEventListener[] flushEntityEventListener) {
+		this.flushEntityEventListeners = flushEntityEventListener;
+	}
+	
+	public SaveOrUpdateEventListener[] getSaveOrUpdateEventListeners() {
+		return saveOrUpdateEventListeners;
+	}
+	
+	public void setSaveOrUpdateEventListeners(SaveOrUpdateEventListener[] saveOrUpdateEventListener) {
+		this.saveOrUpdateEventListeners = saveOrUpdateEventListener;
+	}
+	
+	public MergeEventListener[] getMergeEventListeners() {
+		return mergeEventListeners;
+	}
+	
+	public void setMergeEventListeners(MergeEventListener[] mergeEventListener) {
+		this.mergeEventListeners = mergeEventListener;
+	}
+	
+	public PersistEventListener[] getPersistEventListeners() {
+		return persistEventListeners;
+	}
+	
+	public void setPersistEventListeners(PersistEventListener[] createEventListener) {
+		this.persistEventListeners = createEventListener;
+	}
+
+	public PersistEventListener[] getPersistOnFlushEventListeners() {
+		return persistOnFlushEventListeners;
+	}
+
+	public void setPersistOnFlushEventListeners(PersistEventListener[] createEventListener) {
+		this.persistOnFlushEventListeners = createEventListener;
+	}
+	
+	public MergeEventListener[] getSaveOrUpdateCopyEventListeners() {
+		return saveOrUpdateCopyEventListeners;
+	}
+	
+	public void setSaveOrUpdateCopyEventListeners(MergeEventListener[] saveOrUpdateCopyEventListener) {
+		this.saveOrUpdateCopyEventListeners = saveOrUpdateCopyEventListener;
+	}
+	
+	public SaveOrUpdateEventListener[] getSaveEventListeners() {
+		return saveEventListeners;
+	}
+	
+	public void setSaveEventListeners(SaveOrUpdateEventListener[] saveEventListener) {
+		this.saveEventListeners = saveEventListener;
+	}
+	
+	public SaveOrUpdateEventListener[] getUpdateEventListeners() {
+		return updateEventListeners;
+	}
+	
+	public void setUpdateEventListeners(SaveOrUpdateEventListener[] updateEventListener) {
+		this.updateEventListeners = updateEventListener;
+	}
+
+	public PostLoadEventListener[] getPostLoadEventListeners() {
+		return postLoadEventListeners;
+	}
+
+	public void setPostLoadEventListeners(PostLoadEventListener[] postLoadEventListener) {
+		this.postLoadEventListeners = postLoadEventListener;
+	}
+
+	public PreLoadEventListener[] getPreLoadEventListeners() {
+		return preLoadEventListeners;
+	}
+
+	public void setPreLoadEventListeners(PreLoadEventListener[] preLoadEventListener) {
+		this.preLoadEventListeners = preLoadEventListener;
+	}
+
+	public PostDeleteEventListener[] getPostDeleteEventListeners() {
+		return postDeleteEventListeners;
+	}
+	
+	public PostInsertEventListener[] getPostInsertEventListeners() {
+		return postInsertEventListeners;
+	}
+	
+	public PostUpdateEventListener[] getPostUpdateEventListeners() {
+		return postUpdateEventListeners;
+	}
+	
+	public void setPostDeleteEventListeners(PostDeleteEventListener[] postDeleteEventListener) {
+		this.postDeleteEventListeners = postDeleteEventListener;
+	}
+	
+	public void setPostInsertEventListeners(PostInsertEventListener[] postInsertEventListener) {
+		this.postInsertEventListeners = postInsertEventListener;
+	}
+	
+	public void setPostUpdateEventListeners(PostUpdateEventListener[] postUpdateEventListener) {
+		this.postUpdateEventListeners = postUpdateEventListener;
+	}
+	
+	public PreDeleteEventListener[] getPreDeleteEventListeners() {
+		return preDeleteEventListeners;
+	}
+	
+	public void setPreDeleteEventListeners(PreDeleteEventListener[] preDeleteEventListener) {
+		this.preDeleteEventListeners = preDeleteEventListener;
+	}
+	
+	public PreInsertEventListener[] getPreInsertEventListeners() {
+		return preInsertEventListeners;
+	}
+	
+	public void setPreInsertEventListeners(PreInsertEventListener[] preInsertEventListener) {
+		this.preInsertEventListeners = preInsertEventListener;
+	}
+	
+	public PreUpdateEventListener[] getPreUpdateEventListeners() {
+		return preUpdateEventListeners;
+	}
+	
+	public void setPreUpdateEventListeners(PreUpdateEventListener[] preUpdateEventListener) {
+		this.preUpdateEventListeners = preUpdateEventListener;
+	}
+	
+	/**
+	 * Call <tt>initialize()</tt> on any listeners that implement 
+	 * <tt>Initializable</tt>.
+	 * @see Initializable
+	 */
+	public void initializeListeners(Configuration cfg) {
+		Field[] fields = getClass().getDeclaredFields();
+		for ( int i = 0; i < fields.length; i++ ) {
+			Object[] listeners;
+			try {
+				Object listener = fields[i].get(this);
+				if (listener instanceof Object[]) {
+					listeners = (Object[]) listener;
+				}
+				else {
+					continue;
+				}
+
+			}
+			catch (Exception e) {
+				throw new AssertionFailure("could not init listeners");
+			}
+			int length = listeners.length;
+			for (int index = 0 ; index < length ; index++) {
+				Object listener = listeners[index];
+				if (listener instanceof Initializable ) {
+					( (Initializable) listener ).initialize(cfg);
+				}
+			}
+
+		}
+	}
+
+	public PostDeleteEventListener[] getPostCommitDeleteEventListeners() {
+		return postCommitDeleteEventListeners;
+	}
+
+	public void setPostCommitDeleteEventListeners(
+			PostDeleteEventListener[] postCommitDeleteEventListeners) {
+		this.postCommitDeleteEventListeners = postCommitDeleteEventListeners;
+	}
+
+	public PostInsertEventListener[] getPostCommitInsertEventListeners() {
+		return postCommitInsertEventListeners;
+	}
+
+	public void setPostCommitInsertEventListeners(
+			PostInsertEventListener[] postCommitInsertEventListeners) {
+		this.postCommitInsertEventListeners = postCommitInsertEventListeners;
+	}
+
+	public PostUpdateEventListener[] getPostCommitUpdateEventListeners() {
+		return postCommitUpdateEventListeners;
+	}
+
+	public void setPostCommitUpdateEventListeners(
+			PostUpdateEventListener[] postCommitUpdateEventListeners) {
+		this.postCommitUpdateEventListeners = postCommitUpdateEventListeners;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/EventSource.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/EventSource.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/EventSource.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+//$Id: EventSource.java 9944 2006-05-24 21:14:56Z steve.ebersole at jboss.com $
+package org.hibernate.event;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.engine.ActionQueue;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * @author Gavin King
+ */
+public interface EventSource extends SessionImplementor, Session {
+	
+	/**
+	 * Get the ActionQueue for this session
+	 */
+	public ActionQueue getActionQueue();
+
+	/**
+	 * Instantiate an entity instance, using either an interceptor,
+	 * or the given persister
+	 */
+	public Object instantiate(EntityPersister persister, Serializable id) throws HibernateException;
+
+	/**
+	 * Force an immediate flush
+	 */
+	public void forceFlush(EntityEntry e) throws HibernateException;
+
+	/**
+	 * Cascade merge an entity instance
+	 */
+	public void merge(String entityName, Object object, Map copiedAlready) throws HibernateException;
+	/**
+	 * Cascade persist an entity instance
+	 */
+	public void persist(String entityName, Object object, Map createdAlready) throws HibernateException;
+
+	/**
+	 * Cascade persist an entity instance during the flush process
+	 */
+	public void persistOnFlush(String entityName, Object object, Map copiedAlready);
+	/**
+	 * Cascade refesh an entity instance
+	 */
+	public void refresh(Object object, Map refreshedAlready) throws HibernateException;
+	/**
+	 * Cascade copy an entity instance
+	 */
+	public void saveOrUpdateCopy(String entityName, Object object, Map copiedAlready) throws HibernateException;
+	
+	/**
+	 * Cascade delete an entity instance
+	 */
+	public void delete(String entityName, Object child, boolean isCascadeDeleteEnabled, Set transientEntities);
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/EventSource.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/EvictEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/EvictEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/EvictEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: EvictEvent.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.event;
+
+
+/**
+ *  Defines an event class for the evicting of an entity.
+ *
+ * @author Steve Ebersole
+ */
+public class EvictEvent extends AbstractEvent {
+
+	private Object object;
+
+	public EvictEvent(Object object, EventSource source) {
+		super(source);
+		this.object = object;
+	}
+
+	public Object getObject() {
+		return object;
+	}
+
+	public void setObject(Object object) {
+		this.object = object;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/EvictEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/EvictEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/EvictEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: EvictEventListener.java 4533 2004-09-12 03:02:54Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.HibernateException;
+
+import java.io.Serializable;
+
+/**
+ * Defines the contract for handling of evict events generated from a session.
+ *
+ * @author Steve Ebersole
+ */
+public interface EvictEventListener extends Serializable {
+
+    /** 
+     * Handle the given evict event.
+     *
+     * @param event The evict event to be handled.
+     * @throws HibernateException
+     */
+	public void onEvict(EvictEvent event) throws HibernateException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEntityEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEntityEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEntityEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,71 @@
+//$Id: FlushEntityEvent.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.engine.EntityEntry;
+
+/**
+ * @author Gavin King
+ */
+public class FlushEntityEvent extends AbstractEvent {
+	
+	private Object entity;
+	private Object[] propertyValues;
+	private Object[] databaseSnapshot;
+	private int[] dirtyProperties;
+	private boolean hasDirtyCollection;
+	private boolean dirtyCheckPossible;
+	private boolean dirtyCheckHandledByInterceptor;
+	private EntityEntry entityEntry;
+	
+	public FlushEntityEvent(EventSource source, Object entity, EntityEntry entry) {
+		super(source);
+		this.entity = entity;
+		this.entityEntry = entry;
+	}
+
+	public EntityEntry getEntityEntry() {
+		return entityEntry;
+	}
+	public Object[] getDatabaseSnapshot() {
+		return databaseSnapshot;
+	}
+	public void setDatabaseSnapshot(Object[] databaseSnapshot) {
+		this.databaseSnapshot = databaseSnapshot;
+	}
+	public boolean hasDatabaseSnapshot() {
+		return databaseSnapshot!=null;
+	}
+	public boolean isDirtyCheckHandledByInterceptor() {
+		return dirtyCheckHandledByInterceptor;
+	}
+	public void setDirtyCheckHandledByInterceptor(boolean dirtyCheckHandledByInterceptor) {
+		this.dirtyCheckHandledByInterceptor = dirtyCheckHandledByInterceptor;
+	}
+	public boolean isDirtyCheckPossible() {
+		return dirtyCheckPossible;
+	}
+	public void setDirtyCheckPossible(boolean dirtyCheckPossible) {
+		this.dirtyCheckPossible = dirtyCheckPossible;
+	}
+	public int[] getDirtyProperties() {
+		return dirtyProperties;
+	}
+	public void setDirtyProperties(int[] dirtyProperties) {
+		this.dirtyProperties = dirtyProperties;
+	}
+	public boolean hasDirtyCollection() {
+		return hasDirtyCollection;
+	}
+	public void setHasDirtyCollection(boolean hasDirtyCollection) {
+		this.hasDirtyCollection = hasDirtyCollection;
+	}
+	public Object[] getPropertyValues() {
+		return propertyValues;
+	}
+	public void setPropertyValues(Object[] propertyValues) {
+		this.propertyValues = propertyValues;
+	}
+	public Object getEntity() {
+		return entity;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEntityEvent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEntityEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEntityEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEntityEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+//$Id: FlushEntityEventListener.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+
+/**
+ * @author Gavin King
+ */
+public interface FlushEntityEventListener extends Serializable {
+	public void onFlushEntity(FlushEntityEvent event) throws HibernateException;
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEntityEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+//$Id: FlushEvent.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.event;
+
+
+/** 
+ * Defines an event class for the flushing of a session.
+ *
+ * @author Steve Ebersole
+ */
+public class FlushEvent extends AbstractEvent {
+	
+	public FlushEvent(EventSource source) {
+		super(source);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/FlushEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+//$Id: FlushEventListener.java 4185 2004-08-08 11:24:56Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.HibernateException;
+
+import java.io.Serializable;
+
+/**
+ * Defines the contract for handling of session flush events.
+ *
+ * @author Steve Ebersole
+ */
+public interface FlushEventListener extends Serializable {
+
+    /** Handle the given flush event.
+     *
+     * @param event The flush event to be handled.
+     * @throws HibernateException
+     */
+	public void onFlush(FlushEvent event) throws HibernateException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/Initializable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/Initializable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/Initializable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+//$Id: Initializable.java 7793 2005-08-10 05:06:40Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.cfg.Configuration;
+
+/**
+ * An event listener that requires access to mappings to
+ * initialize state at initialization time.
+ * @author Gavin King
+ */
+public interface Initializable {
+	public void initialize(Configuration cfg);
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/Initializable.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/InitializeCollectionEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/InitializeCollectionEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/InitializeCollectionEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+//$Id: InitializeCollectionEvent.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.collection.PersistentCollection;
+
+/**
+ * An event that occurs when a collection wants to be
+ * initialized
+ * 
+ * @author Gavin King
+ */
+public class InitializeCollectionEvent extends AbstractEvent {
+	
+	private final PersistentCollection collection;
+
+	public InitializeCollectionEvent(PersistentCollection collection, EventSource source) {
+		super(source);
+		this.collection = collection;
+	}
+	
+	public PersistentCollection getCollection() {
+		return collection;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/InitializeCollectionEvent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/InitializeCollectionEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/InitializeCollectionEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/InitializeCollectionEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+//$Id: InitializeCollectionEventListener.java 4345 2004-08-16 12:12:12Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.HibernateException;
+
+import java.io.Serializable;
+
+/**
+ * Defines the contract for handling of collection initialization events 
+ * generated by a session.
+ *
+ * @author Gavin King
+ */
+public interface InitializeCollectionEventListener extends Serializable {
+
+	public void onInitializeCollection(InitializeCollectionEvent event) throws HibernateException;
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/InitializeCollectionEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/LoadEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/LoadEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/LoadEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,107 @@
+//$Id: LoadEvent.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+import org.hibernate.LockMode;
+
+/**
+ *  Defines an event class for the loading of an entity.
+ *
+ * @author Steve Ebersole
+ */
+public class LoadEvent extends AbstractEvent {
+
+	public static final LockMode DEFAULT_LOCK_MODE = LockMode.NONE;
+
+	private Serializable entityId;
+	private String entityClassName;
+	private Object instanceToLoad;
+	private LockMode lockMode;
+	private boolean isAssociationFetch;
+	private Object result;
+
+	public LoadEvent(Serializable entityId, Object instanceToLoad, EventSource source) {
+		this(entityId, null, instanceToLoad, null, false, source);
+	}
+
+	public LoadEvent(Serializable entityId, String entityClassName, LockMode lockMode, EventSource source) {
+		this(entityId, entityClassName, null, lockMode, false, source);
+	}
+	
+	public LoadEvent(Serializable entityId, String entityClassName, boolean isAssociationFetch, EventSource source) {
+		this(entityId, entityClassName, null, null, isAssociationFetch, source);
+	}
+	
+	public boolean isAssociationFetch() {
+		return isAssociationFetch;
+	}
+
+	private LoadEvent(
+			Serializable entityId,
+			String entityClassName,
+			Object instanceToLoad,
+			LockMode lockMode,
+			boolean isAssociationFetch,
+			EventSource source) {
+
+		super(source);
+
+		if ( entityId == null ) {
+			throw new IllegalArgumentException("id to load is required for loading");
+		}
+
+		if ( lockMode == LockMode.WRITE ) {
+			throw new IllegalArgumentException("Invalid lock mode for loading");
+		}
+		else if ( lockMode == null ) {
+			lockMode = DEFAULT_LOCK_MODE;
+		}
+
+		this.entityId = entityId;
+		this.entityClassName = entityClassName;
+		this.instanceToLoad = instanceToLoad;
+		this.lockMode = lockMode;
+		this.isAssociationFetch = isAssociationFetch;
+	}
+
+	public Serializable getEntityId() {
+		return entityId;
+	}
+
+	public void setEntityId(Serializable entityId) {
+		this.entityId = entityId;
+	}
+
+	public String getEntityClassName() {
+		return entityClassName;
+	}
+
+	public void setEntityClassName(String entityClassName) {
+		this.entityClassName = entityClassName;
+	}
+
+	public Object getInstanceToLoad() {
+		return instanceToLoad;
+	}
+
+	public void setInstanceToLoad(Object instanceToLoad) {
+		this.instanceToLoad = instanceToLoad;
+	}
+
+	public LockMode getLockMode() {
+		return lockMode;
+	}
+
+	public void setLockMode(LockMode lockMode) {
+		this.lockMode = lockMode;
+	}
+
+	public Object getResult() {
+		return result;
+	}
+
+	public void setResult(Object result) {
+		this.result = result;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/LoadEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/LoadEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/LoadEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,122 @@
+//$Id: LoadEventListener.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.HibernateException;
+
+import java.io.Serializable;
+
+/**
+ * Defines the contract for handling of load events generated from a session.
+ *
+ * @author Steve Ebersole
+ */
+public interface LoadEventListener extends Serializable {
+
+	/** 
+	 * Handle the given load event.
+     *
+     * @param event The load event to be handled.
+     * @return The result (i.e., the loaded entity).
+     * @throws HibernateException
+     */
+	public void onLoad(LoadEvent event, LoadType loadType) throws HibernateException;
+
+	public static final LoadType RELOAD = new LoadType("GET")
+			.setAllowNulls(false)
+			.setAllowProxyCreation(false)
+			.setCheckDeleted(true)
+			.setNakedEntityReturned(false);
+
+	public static final LoadType GET = new LoadType("GET")
+			.setAllowNulls(true)
+			.setAllowProxyCreation(false)
+			.setCheckDeleted(true)
+			.setNakedEntityReturned(false);
+	
+	public static final LoadType LOAD = new LoadType("LOAD")
+			.setAllowNulls(false)
+			.setAllowProxyCreation(true)
+			.setCheckDeleted(true)
+			.setNakedEntityReturned(false);
+	
+	public static final LoadType IMMEDIATE_LOAD = new LoadType("IMMEDIATE_LOAD")
+			.setAllowNulls(true)
+			.setAllowProxyCreation(false)
+			.setCheckDeleted(false)
+			.setNakedEntityReturned(true);
+	
+	public static final LoadType INTERNAL_LOAD_EAGER = new LoadType("INTERNAL_LOAD_EAGER")
+			.setAllowNulls(false)
+			.setAllowProxyCreation(false)
+			.setCheckDeleted(false)
+			.setNakedEntityReturned(false);
+	
+	public static final LoadType INTERNAL_LOAD_LAZY = new LoadType("INTERNAL_LOAD_LAZY")
+			.setAllowNulls(false)
+			.setAllowProxyCreation(true)
+			.setCheckDeleted(false)
+			.setNakedEntityReturned(false);
+	
+	public static final LoadType INTERNAL_LOAD_NULLABLE = new LoadType("INTERNAL_LOAD_NULLABLE")
+			.setAllowNulls(true)
+			.setAllowProxyCreation(false)
+			.setCheckDeleted(false)
+			.setNakedEntityReturned(false);
+
+	public static final class LoadType {
+		private String name;
+
+		private boolean nakedEntityReturned;
+		private boolean allowNulls;
+		private boolean checkDeleted;
+		private boolean allowProxyCreation;
+
+        private LoadType(String name) {
+	        this.name = name;
+        }
+
+		public boolean isAllowNulls() {
+			return allowNulls;
+		}
+
+		private LoadType setAllowNulls(boolean allowNulls) {
+			this.allowNulls = allowNulls;
+			return this;
+		}
+
+		public boolean isNakedEntityReturned() {
+			return nakedEntityReturned;
+		}
+
+		private LoadType setNakedEntityReturned(boolean immediateLoad) {
+			this.nakedEntityReturned = immediateLoad;
+			return this;
+		}
+
+		public boolean isCheckDeleted() {
+			return checkDeleted;
+		}
+
+		private LoadType setCheckDeleted(boolean checkDeleted) {
+			this.checkDeleted = checkDeleted;
+			return this;
+		}
+
+		public boolean isAllowProxyCreation() {
+			return allowProxyCreation;
+		}
+
+		private LoadType setAllowProxyCreation(boolean allowProxyCreation) {
+			this.allowProxyCreation = allowProxyCreation;
+			return this;
+		}
+
+		public String getName() {
+			return name;
+		}
+		
+		public String toString() {
+			return name;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/LockEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/LockEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/LockEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+//$Id: LockEvent.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.LockMode;
+
+/**
+ *  Defines an event class for the locking of an entity.
+ *
+ * @author Steve Ebersole
+ */
+public class LockEvent extends AbstractEvent {
+
+	private Object object;
+	private LockMode lockMode;
+	private String entityName;
+
+	public LockEvent(String entityName, Object original, LockMode lockMode, EventSource source) {
+		this(original, lockMode, source);
+		this.entityName = entityName;
+	}
+
+	public LockEvent(Object object, LockMode lockMode, EventSource source) {
+		super(source);
+		this.object = object;
+		this.lockMode = lockMode;
+	}
+
+	public Object getObject() {
+		return object;
+	}
+
+	public void setObject(Object object) {
+		this.object = object;
+	}
+
+	public LockMode getLockMode() {
+		return lockMode;
+	}
+
+	public void setLockMode(LockMode lockMode) {
+		this.lockMode = lockMode;
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public void setEntityName(String entityName) {
+		this.entityName = entityName;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/LockEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/LockEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/LockEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: LockEventListener.java 4185 2004-08-08 11:24:56Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.HibernateException;
+
+import java.io.Serializable;
+
+/**
+ * Defines the contract for handling of lock events generated from a session.
+ *
+ * @author Steve Ebersole
+ */
+public interface LockEventListener extends Serializable {
+
+    /** Handle the given lock event.
+     *
+     * @param event The lock event to be handled.
+     * @throws HibernateException
+     */
+	public void onLock(LockEvent event) throws HibernateException;
+}
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/MergeEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/MergeEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/MergeEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,82 @@
+//$Id: MergeEvent.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+/** 
+ * An event class for merge() and saveOrUpdateCopy()
+ *
+ * @author Gavin King
+ */
+public class MergeEvent extends AbstractEvent {
+
+	private Object original;
+	private Serializable requestedId;
+	private String entityName;
+	private Object entity;
+	private Object result;
+
+	public MergeEvent(String entityName, Object original, EventSource source) {
+		this(original, source);
+		this.entityName = entityName;
+	}
+
+	public MergeEvent(String entityName, Object original, Serializable id, EventSource source) {
+		this(entityName, original, source);
+		this.requestedId = id;
+		if ( requestedId == null ) {
+			throw new IllegalArgumentException(
+					"attempt to create merge event with null identifier"
+				);
+		}
+	}
+
+	public MergeEvent(Object object, EventSource source) {
+		super(source);
+		if ( object == null ) {
+			throw new IllegalArgumentException(
+					"attempt to create merge event with null entity"
+				);
+		}
+		this.original = object;
+	}
+
+	public Object getOriginal() {
+		return original;
+	}
+
+	public void setOriginal(Object object) {
+		this.original = object;
+	}
+
+	public Serializable getRequestedId() {
+		return requestedId;
+	}
+
+	public void setRequestedId(Serializable requestedId) {
+		this.requestedId = requestedId;
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public void setEntityName(String entityName) {
+		this.entityName = entityName;
+	}
+
+	public Object getEntity() {
+		return entity;
+	}
+	public void setEntity(Object entity) {
+		this.entity = entity;
+	}
+
+	public Object getResult() {
+		return result;
+	}
+
+	public void setResult(Object result) {
+		this.result = result;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/MergeEvent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/MergeEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/MergeEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/MergeEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+//$Id: MergeEventListener.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Defines the contract for handling of merge events generated from a session.
+ *
+ * @author Gavin King
+ */
+public interface MergeEventListener extends Serializable {
+
+    /** 
+     * Handle the given merge event.
+     *
+     * @param event The merge event to be handled.
+     * @throws HibernateException
+     */
+	public void onMerge(MergeEvent event) throws HibernateException;
+
+    /** 
+     * Handle the given merge event.
+     *
+     * @param event The merge event to be handled.
+     * @throws HibernateException
+     */
+	public void onMerge(MergeEvent event, Map copiedAlready) throws HibernateException;
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/MergeEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PersistEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PersistEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PersistEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+//$Id: PersistEvent.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.event;
+
+
+
+/** 
+ * An event class for persist()
+ *
+ * @author Gavin King
+ */
+public class PersistEvent extends AbstractEvent {
+
+	private Object object;
+	private String entityName;
+
+	public PersistEvent(String entityName, Object original, EventSource source) {
+		this(original, source);
+		this.entityName = entityName;
+	}
+
+	public PersistEvent(Object object, EventSource source) {
+		super(source);
+		if ( object == null ) {
+			throw new IllegalArgumentException(
+					"attempt to create create event with null entity"
+			);
+		}
+		this.object = object;
+	}
+
+	public Object getObject() {
+		return object;
+	}
+
+	public void setObject(Object object) {
+		this.object = object;
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public void setEntityName(String entityName) {
+		this.entityName = entityName;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PersistEvent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PersistEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PersistEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PersistEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+//$Id: PersistEventListener.java 5835 2005-02-21 14:39:02Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Defines the contract for handling of create events generated from a session.
+ *
+ * @author Gavin King
+ */
+public interface PersistEventListener extends Serializable {
+
+    /** 
+     * Handle the given create event.
+     *
+     * @param event The create event to be handled.
+     * @throws HibernateException
+     */
+	public void onPersist(PersistEvent event) throws HibernateException;
+
+    /** 
+     * Handle the given create event.
+     *
+     * @param event The create event to be handled.
+     * @throws HibernateException
+     */
+	public void onPersist(PersistEvent event, Map createdAlready) throws HibernateException;
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PersistEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostDeleteEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostDeleteEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostDeleteEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: PostDeleteEvent.java 10680 2006-11-01 22:53:30Z epbernard $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Occurs after deleting an item from the datastore
+ * 
+ * @author Gavin King
+ */
+public class PostDeleteEvent extends AbstractEvent {
+	private Object entity;
+	private EntityPersister persister;
+	private Serializable id;
+	private Object[] deletedState;
+	
+	public PostDeleteEvent(
+			Object entity, 
+			Serializable id,
+			Object[] deletedState,
+			EntityPersister persister,
+			EventSource source
+	) {
+		super(source);
+		this.entity = entity;
+		this.id = id;
+		this.persister = persister;
+		this.deletedState = deletedState;
+	}
+	
+	public Serializable getId() {
+		return id;
+	}
+	public EntityPersister getPersister() {
+		return persister;
+	}
+	public Object getEntity() {
+		return entity;
+	}
+	public Object[] getDeletedState() {
+		return deletedState;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostDeleteEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostDeleteEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostDeleteEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+//$Id: PostDeleteEventListener.java 7581 2005-07-20 22:48:22Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+/**
+ * Called after deleting an item from the datastore
+ * 
+ * @author Gavin King
+ */
+public interface PostDeleteEventListener extends Serializable {
+	public void onPostDelete(PostDeleteEvent event);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostInsertEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostInsertEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostInsertEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: PostInsertEvent.java 10680 2006-11-01 22:53:30Z epbernard $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Occurs after inserting an item in the datastore
+ * 
+ * @author Gavin King
+ */
+public class PostInsertEvent extends AbstractEvent {
+	private Object entity;
+	private EntityPersister persister;
+	private Object[] state;
+	private Serializable id;
+	
+	public PostInsertEvent(
+			Object entity, 
+			Serializable id,
+			Object[] state,
+			EntityPersister persister,
+			EventSource source
+	) {
+		super(source);
+		this.entity = entity;
+		this.id = id;
+		this.state = state;
+		this.persister = persister;
+	}
+	
+	public Object getEntity() {
+		return entity;
+	}
+	public Serializable getId() {
+		return id;
+	}
+	public EntityPersister getPersister() {
+		return persister;
+	}
+	public Object[] getState() {
+		return state;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostInsertEvent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostInsertEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostInsertEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostInsertEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+//$Id: PostInsertEventListener.java 7581 2005-07-20 22:48:22Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+/**
+ * Called after insterting an item in the datastore
+ * 
+ * @author Gavin King
+ */
+public interface PostInsertEventListener extends Serializable {
+	public void onPostInsert(PostInsertEvent event);
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostInsertEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostLoadEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostLoadEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostLoadEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: PostLoadEvent.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Occurs after an an entity instance is fully loaded.
+ *
+ * @author <a href="mailto:kabir.khan at jboss.org">Kabir Khan</a>, Gavin King
+ */
+public class PostLoadEvent extends AbstractEvent {
+	private Object entity;
+	private Serializable id;
+	private EntityPersister persister;
+
+	public PostLoadEvent(EventSource session) {
+		super(session);
+	}
+
+	public Object getEntity() {
+		return entity;
+	}
+	
+	public EntityPersister getPersister() {
+		return persister;
+	}
+	
+	public Serializable getId() {
+		return id;
+	}
+
+	public PostLoadEvent setEntity(Object entity) {
+		this.entity = entity;
+		return this;
+	}
+	
+	public PostLoadEvent setId(Serializable id) {
+		this.id = id;
+		return this;
+	}
+
+	public PostLoadEvent setPersister(EntityPersister persister) {
+		this.persister = persister;
+		return this;
+	}
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostLoadEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostLoadEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostLoadEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+//$Id: PostLoadEventListener.java 5006 2004-12-19 20:15:13Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+/**
+ * Occurs after an an entity instance is fully loaded.
+ *
+ * @author <a href="mailto:kabir.khan at jboss.org">Kabir Khan</a>
+ */
+public interface PostLoadEventListener extends Serializable {
+	public void onPostLoad(PostLoadEvent event);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostUpdateEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostUpdateEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostUpdateEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+//$Id: PostUpdateEvent.java 9964 2006-05-30 15:40:54Z epbernard $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Occurs after the datastore is updated
+ * 
+ * @author Gavin King
+ */
+public class PostUpdateEvent extends AbstractEvent {
+	private Object entity;
+	private EntityPersister persister;
+	private Object[] state;
+	private Object[] oldState;
+	private Serializable id;
+	
+	public PostUpdateEvent(
+			Object entity, 
+			Serializable id,
+			Object[] state,
+			Object[] oldState,
+			EntityPersister persister,
+			EventSource source
+	) {
+		super(source);
+		this.entity = entity;
+		this.id = id;
+		this.state = state;
+		this.oldState = oldState;
+		this.persister = persister;
+	}
+	
+	public Object getEntity() {
+		return entity;
+	}
+	public Serializable getId() {
+		return id;
+	}
+	public Object[] getOldState() {
+		return oldState;
+	}
+	public EntityPersister getPersister() {
+		return persister;
+	}
+	public Object[] getState() {
+		return state;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostUpdateEvent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostUpdateEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostUpdateEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostUpdateEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+//$Id: PostUpdateEventListener.java 7581 2005-07-20 22:48:22Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+/**
+ * Called after updating the datastore
+ * 
+ * @author Gavin King
+ */
+public interface PostUpdateEventListener extends Serializable {
+	public void onPostUpdate(PostUpdateEvent event);
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PostUpdateEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreDeleteEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreDeleteEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreDeleteEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+//$Id: PreDeleteEvent.java 7581 2005-07-20 22:48:22Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Occurs before deleting an item from the datastore
+ * 
+ * @author Gavin King
+ */
+public class PreDeleteEvent {
+	private Object entity;
+	private EntityPersister persister;
+	private Serializable id;
+	private Object[] deletedState;
+	
+	public Object getEntity() {
+		return entity;
+	}
+	public Serializable getId() {
+		return id;
+	}
+	public EntityPersister getPersister() {
+		return persister;
+	}
+	public Object[] getDeletedState() {
+		return deletedState;
+	}
+	
+	public PreDeleteEvent(
+			Object entity, 
+			Serializable id,
+			Object[] deletedState,
+			EntityPersister persister
+	) {
+		this.entity = entity;
+		this.persister = persister;
+		this.id = id;
+		this.deletedState = deletedState;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreDeleteEvent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreDeleteEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreDeleteEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreDeleteEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+//$Id: PreDeleteEventListener.java 11272 2007-03-12 00:17:45Z epbernard $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+/**
+ * Called before deleting an item from the datastore
+ * 
+ * @author Gavin King
+ */
+public interface PreDeleteEventListener extends Serializable {
+	/**
+	 * Return true if the operation should be vetoed
+	 */
+	public boolean onPreDelete(PreDeleteEvent event);
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreDeleteEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreInsertEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreInsertEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreInsertEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+//$Id: PreInsertEvent.java 7850 2005-08-11 19:37:08Z epbernard $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * Occurs before inserting an item in the datastore
+ * 
+ * @author Gavin King
+ */
+public class PreInsertEvent {
+	private Object entity;
+	private EntityPersister persister;
+	private Object[] state;
+	private Serializable id;
+	private SessionImplementor source;
+
+	public PreInsertEvent(
+			Object entity,
+			Serializable id,
+			Object[] state,
+			EntityPersister persister,
+			SessionImplementor source
+	) {
+		this.source = source;
+		this.entity = entity;
+		this.id = id;
+		this.state = state;
+		this.persister = persister;
+	}
+
+	public Object getEntity() {
+		return entity;
+	}
+	public Serializable getId() {
+		return id;
+	}
+	public EntityPersister getPersister() {
+		return persister;
+	}
+	public Object[] getState() {
+		return state;
+	}
+	public SessionImplementor getSource() {
+		return source;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreInsertEvent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreInsertEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreInsertEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreInsertEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+//$Id: PreInsertEventListener.java 11272 2007-03-12 00:17:45Z epbernard $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+/**
+ * Called before inserting an item in the datastore
+ * 
+ * @author Gavin King
+ */
+public interface PreInsertEventListener extends Serializable {
+	/**
+	 * Return true if the operation should be vetoed
+	 */
+	public boolean onPreInsert(PreInsertEvent event);
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreInsertEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreLoadEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreLoadEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreLoadEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+//$Id: PreLoadEvent.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Called before injecting property values into a newly 
+ * loaded entity instance.
+ *
+ * @author Gavin King
+ */
+public class PreLoadEvent extends AbstractEvent {
+	private Object entity;
+	private Object[] state;
+	private Serializable id;
+	private EntityPersister persister;
+
+	public PreLoadEvent(EventSource session) {
+		super(session);
+	}
+
+	public Object getEntity() {
+		return entity;
+	}
+	
+	public Serializable getId() {
+		return id;
+	}
+	
+	public EntityPersister getPersister() {
+		return persister;
+	}
+	
+	public Object[] getState() {
+		return state;
+	}
+
+	public PreLoadEvent setEntity(Object entity) {
+		this.entity = entity;
+		return this;
+	}
+	
+	public PreLoadEvent setId(Serializable id) {
+		this.id = id;
+		return this;
+	}
+	
+	public PreLoadEvent setPersister(EntityPersister persister) {
+		this.persister = persister;
+		return this;
+	}
+	
+	public PreLoadEvent setState(Object[] state) {
+		this.state = state;
+		return this;
+	}
+	
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreLoadEvent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreLoadEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreLoadEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreLoadEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,14 @@
+//$Id: PreLoadEventListener.java 5006 2004-12-19 20:15:13Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+/**
+ * Called before injecting property values into a newly 
+ * loaded entity instance.
+ *
+ * @author Gavin King
+ */
+public interface PreLoadEventListener extends Serializable {
+	public void onPreLoad(PreLoadEvent event);
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreLoadEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreUpdateEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreUpdateEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreUpdateEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,56 @@
+//$Id: PreUpdateEvent.java 7850 2005-08-11 19:37:08Z epbernard $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * Occurs before updating the datastore
+ * 
+ * @author Gavin King
+ */
+public class PreUpdateEvent {
+	private Object entity;
+	private EntityPersister persister;
+	private Object[] state;
+	private Object[] oldState;
+	private Serializable id;
+	private SessionImplementor source;
+
+	public PreUpdateEvent(
+			Object entity,
+			Serializable id,
+			Object[] state,
+			Object[] oldState,
+			EntityPersister persister,
+			SessionImplementor source
+	) {
+		this.source = source;
+		this.entity = entity;
+		this.id = id;
+		this.state = state;
+		this.oldState = oldState;
+		this.persister = persister;
+	}
+
+	public Object getEntity() {
+		return entity;
+	}
+	public Serializable getId() {
+		return id;
+	}
+	public Object[] getOldState() {
+		return oldState;
+	}
+	public EntityPersister getPersister() {
+		return persister;
+	}
+	public Object[] getState() {
+		return state;
+	}
+	public SessionImplementor getSource() {
+		return source;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreUpdateEvent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreUpdateEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreUpdateEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreUpdateEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+//$Id: PreUpdateEventListener.java 11272 2007-03-12 00:17:45Z epbernard $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+/**
+ * Called before updating the datastore
+ * 
+ * @author Gavin King
+ */
+public interface PreUpdateEventListener extends Serializable {
+	/**
+	 * Return true if the operation should be vetoed
+	 */
+	public boolean onPreUpdate(PreUpdateEvent event);
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/PreUpdateEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/RefreshEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/RefreshEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/RefreshEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+//$Id: RefreshEvent.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.LockMode;
+
+/**
+ *  Defines an event class for the refreshing of an object.
+ *
+ * @author Steve Ebersole
+ */
+public class RefreshEvent extends AbstractEvent {
+
+	private Object object;
+	private LockMode lockMode = LockMode.READ;
+
+	public RefreshEvent(Object object, EventSource source) {
+		super(source);
+		if (object == null) {
+			throw new IllegalArgumentException("Attempt to generate refresh event with null object");
+		}
+		this.object = object;
+	}
+
+	public RefreshEvent(Object object, LockMode lockMode, EventSource source) {
+		this(object, source);
+		if (lockMode == null) {
+			throw new IllegalArgumentException("Attempt to generate refresh event with null lock mode");
+		}
+		this.lockMode = lockMode;
+	}
+
+	public Object getObject() {
+		return object;
+	}
+
+	public LockMode getLockMode() {
+		return lockMode;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/RefreshEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/RefreshEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/RefreshEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: RefreshEventListener.java 7485 2005-07-15 03:35:18Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.HibernateException;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * Defines the contract for handling of refresh events generated from a session.
+ *
+ * @author Steve Ebersole
+ */
+public interface RefreshEventListener extends Serializable {
+
+    /** 
+     * Handle the given refresh event.
+     *
+     * @param event The refresh event to be handled.
+     * @throws HibernateException
+     */
+	public void onRefresh(RefreshEvent event) throws HibernateException;
+	
+	public void onRefresh(RefreshEvent event, Map refreshedAlready) throws HibernateException;
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/ReplicateEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/ReplicateEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/ReplicateEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+//$Id: ReplicateEvent.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.ReplicationMode;
+
+/**
+ *  Defines an event class for the replication of an entity.
+ *
+ * @author Steve Ebersole
+ */
+public class ReplicateEvent extends AbstractEvent {
+
+	private Object object;
+	private ReplicationMode replicationMode;
+	private String entityName;
+
+	public ReplicateEvent(Object object, ReplicationMode replicationMode, EventSource source) {
+		this(null, object, replicationMode, source);
+	}
+	
+	public ReplicateEvent(String entityName, Object object, ReplicationMode replicationMode, EventSource source) {
+		super(source);
+		this.entityName = entityName;
+
+		if ( object == null ) {
+			throw new IllegalArgumentException(
+					"attempt to create replication strategy with null entity"
+			);
+		}
+		if ( replicationMode == null ) {
+			throw new IllegalArgumentException(
+					"attempt to create replication strategy with null replication mode"
+			);
+		}
+
+		this.object = object;
+		this.replicationMode = replicationMode;
+	}
+
+	public Object getObject() {
+		return object;
+	}
+
+	public void setObject(Object object) {
+		this.object = object;
+	}
+
+	public ReplicationMode getReplicationMode() {
+		return replicationMode;
+	}
+
+	public void setReplicationMode(ReplicationMode replicationMode) {
+		this.replicationMode = replicationMode;
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+	public void setEntityName(String entityName) {
+		this.entityName = entityName;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/ReplicateEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/ReplicateEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/ReplicateEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: ReplicateEventListener.java 4185 2004-08-08 11:24:56Z oneovthafew $
+package org.hibernate.event;
+
+import org.hibernate.HibernateException;
+
+import java.io.Serializable;
+
+/**
+ * Defines the contract for handling of replicate events generated from a session.
+ *
+ * @author Steve Ebersole
+ */
+public interface ReplicateEventListener extends Serializable {
+
+    /** Handle the given replicate event.
+     *
+     * @param event The replicate event to be handled.
+     * @throws HibernateException
+     */
+	public void onReplicate(ReplicateEvent event) throws HibernateException;
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/SaveOrUpdateEvent.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/SaveOrUpdateEvent.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/SaveOrUpdateEvent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,94 @@
+//$Id: SaveOrUpdateEvent.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+import org.hibernate.engine.EntityEntry;
+
+/** 
+ * An event class for saveOrUpdate()
+ *
+ * @author Steve Ebersole
+ */
+public class SaveOrUpdateEvent extends AbstractEvent {
+
+	private Object object;
+	private Serializable requestedId;
+	private String entityName;
+	private Object entity;
+	private EntityEntry entry;
+	private Serializable resultId;
+
+	public SaveOrUpdateEvent(String entityName, Object original, EventSource source) {
+		this(original, source);
+		this.entityName = entityName;
+	}
+
+	public SaveOrUpdateEvent(String entityName, Object original, Serializable id, EventSource source) {
+		this(entityName, original, source);
+		this.requestedId = id;
+		if ( requestedId == null ) {
+			throw new IllegalArgumentException(
+					"attempt to create saveOrUpdate event with null identifier"
+				);
+		}
+	}
+
+	public SaveOrUpdateEvent(Object object, EventSource source) {
+		super(source);
+		if ( object == null ) {
+			throw new IllegalArgumentException(
+					"attempt to create saveOrUpdate event with null entity"
+				);
+		}
+		this.object = object;
+	}
+
+	public Object getObject() {
+		return object;
+	}
+
+	public void setObject(Object object) {
+		this.object = object;
+	}
+
+	public Serializable getRequestedId() {
+		return requestedId;
+	}
+
+	public void setRequestedId(Serializable requestedId) {
+		this.requestedId = requestedId;
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public void setEntityName(String entityName) {
+		this.entityName = entityName;
+	}
+
+	public Object getEntity() {
+		return entity;
+	}
+	
+	public void setEntity(Object entity) {
+		this.entity = entity;
+	}
+	
+	public EntityEntry getEntry() {
+		return entry;
+	}
+	
+	public void setEntry(EntityEntry entry) {
+		this.entry = entry;
+	}
+
+	public Serializable getResultId() {
+		return resultId;
+	}
+
+	public void setResultId(Serializable resultId) {
+		this.resultId = resultId;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/SaveOrUpdateEvent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/SaveOrUpdateEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/SaveOrUpdateEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/SaveOrUpdateEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+//$Id: SaveOrUpdateEventListener.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Defines the contract for handling of update events generated from a session.
+ *
+ * @author Steve Ebersole
+ */
+public interface SaveOrUpdateEventListener extends Serializable {
+
+    /** 
+     * Handle the given update event.
+     *
+     * @param event The update event to be handled.
+     * @throws HibernateException
+     */
+	public void onSaveOrUpdate(SaveOrUpdateEvent event) throws HibernateException;
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/SaveOrUpdateEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractFlushingEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractFlushingEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractFlushingEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,356 @@
+//$Id: AbstractFlushingEventListener.java 11402 2007-04-11 14:24:35Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.action.CollectionRecreateAction;
+import org.hibernate.action.CollectionRemoveAction;
+import org.hibernate.action.CollectionUpdateAction;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.ActionQueue;
+import org.hibernate.engine.Cascade;
+import org.hibernate.engine.CascadingAction;
+import org.hibernate.engine.CollectionEntry;
+import org.hibernate.engine.CollectionKey;
+import org.hibernate.engine.Collections;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.Status;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.FlushEntityEvent;
+import org.hibernate.event.FlushEntityEventListener;
+import org.hibernate.event.FlushEvent;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.pretty.Printer;
+import org.hibernate.util.IdentityMap;
+import org.hibernate.util.LazyIterator;
+
+/**
+ * A convenience base class for listeners whose functionality results in flushing.
+ *
+ * @author Steve Eberole
+ */
+public abstract class AbstractFlushingEventListener implements Serializable {
+
+	private static final Log log = LogFactory.getLog(AbstractFlushingEventListener.class);
+	
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	// Pre-flushing section
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/** 
+	 * Coordinates the processing necessary to get things ready for executions
+	 * as db calls by preping the session caches and moving the appropriate
+	 * entities and collections to their respective execution queues.
+	 *
+	 * @param event The flush event.
+	 * @throws HibernateException Error flushing caches to execution queues.
+	 */
+	protected void flushEverythingToExecutions(FlushEvent event) throws HibernateException {
+
+		log.trace("flushing session");
+		
+		EventSource session = event.getSession();
+		
+		final PersistenceContext persistenceContext = session.getPersistenceContext();
+		session.getInterceptor().preFlush( new LazyIterator( persistenceContext.getEntitiesByKey() ) );
+
+		prepareEntityFlushes(session);
+		// we could move this inside if we wanted to
+		// tolerate collection initializations during
+		// collection dirty checking:
+		prepareCollectionFlushes(session);
+		// now, any collections that are initialized
+		// inside this block do not get updated - they
+		// are ignored until the next flush
+				
+		persistenceContext.setFlushing(true);
+		try {
+			flushEntities(event);
+			flushCollections(session);
+		}
+		finally {
+			persistenceContext.setFlushing(false);
+		}
+
+		//some statistics
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Flushed: " +
+					session.getActionQueue().numberOfInsertions() + " insertions, " +
+					session.getActionQueue().numberOfUpdates() + " updates, " +
+					session.getActionQueue().numberOfDeletions() + " deletions to " +
+					persistenceContext.getEntityEntries().size() + " objects"
+				);
+			log.debug( "Flushed: " +
+					session.getActionQueue().numberOfCollectionCreations() + " (re)creations, " +
+					session.getActionQueue().numberOfCollectionUpdates() + " updates, " +
+					session.getActionQueue().numberOfCollectionRemovals() + " removals to " +
+					persistenceContext.getCollectionEntries().size() + " collections"
+				);
+			new Printer( session.getFactory() ).toString( 
+					persistenceContext.getEntitiesByKey().values().iterator(), 
+					session.getEntityMode() 
+				);
+		}
+	}
+
+	/**
+	 * process cascade save/update at the start of a flush to discover
+	 * any newly referenced entity that must be passed to saveOrUpdate(),
+	 * and also apply orphan delete
+	 */
+	private void prepareEntityFlushes(EventSource session) throws HibernateException {
+		
+		log.debug("processing flush-time cascades");
+
+		final Map.Entry[] list = IdentityMap.concurrentEntries( session.getPersistenceContext().getEntityEntries() );
+		//safe from concurrent modification because of how entryList() is implemented on IdentityMap
+		final int size = list.length;
+		final Object anything = getAnything();
+		for ( int i=0; i<size; i++ ) {
+			Map.Entry me = list[i];
+			EntityEntry entry = (EntityEntry) me.getValue();
+			Status status = entry.getStatus();
+			if ( status == Status.MANAGED || status == Status.SAVING ) {
+				cascadeOnFlush( session, entry.getPersister(), me.getKey(), anything );
+			}
+		}
+	}
+	
+	private void cascadeOnFlush(EventSource session, EntityPersister persister, Object object, Object anything) 
+	throws HibernateException {
+		session.getPersistenceContext().incrementCascadeLevel();
+		try {
+			new Cascade( getCascadingAction(), Cascade.BEFORE_FLUSH, session )
+			.cascade( persister, object, anything );
+		}
+		finally {
+			session.getPersistenceContext().decrementCascadeLevel();
+		}
+	}
+	
+	protected Object getAnything() { return null; }
+	
+	protected CascadingAction getCascadingAction() {
+		return CascadingAction.SAVE_UPDATE;
+	}
+
+	/**
+	 * Initialize the flags of the CollectionEntry, including the
+	 * dirty check.
+	 */
+	private void prepareCollectionFlushes(SessionImplementor session) throws HibernateException {
+
+		// Initialize dirty flags for arrays + collections with composite elements
+		// and reset reached, doupdate, etc.
+		
+		log.debug("dirty checking collections");
+
+		final List list = IdentityMap.entries( session.getPersistenceContext().getCollectionEntries() );
+		final int size = list.size();
+		for ( int i = 0; i < size; i++ ) {
+			Map.Entry e = ( Map.Entry ) list.get( i );
+			( (CollectionEntry) e.getValue() ).preFlush( (PersistentCollection) e.getKey() );
+		}
+	}
+
+	/**
+	 * 1. detect any dirty entities
+	 * 2. schedule any entity updates
+	 * 3. search out any reachable collections
+	 */
+	private void flushEntities(FlushEvent event) throws HibernateException {
+
+		log.trace("Flushing entities and processing referenced collections");
+
+		// Among other things, updateReachables() will recursively load all
+		// collections that are moving roles. This might cause entities to
+		// be loaded.
+
+		// So this needs to be safe from concurrent modification problems.
+		// It is safe because of how IdentityMap implements entrySet()
+
+		final EventSource source = event.getSession();
+		
+		final Map.Entry[] list = IdentityMap.concurrentEntries( source.getPersistenceContext().getEntityEntries() );
+		final int size = list.length;
+		for ( int i = 0; i < size; i++ ) {
+
+			// Update the status of the object and if necessary, schedule an update
+
+			Map.Entry me = list[i];
+			EntityEntry entry = (EntityEntry) me.getValue();
+			Status status = entry.getStatus();
+
+			if ( status != Status.LOADING && status != Status.GONE ) {
+				FlushEntityEvent entityEvent = new FlushEntityEvent( source, me.getKey(), entry );
+				FlushEntityEventListener[] listeners = source.getListeners().getFlushEntityEventListeners();
+				for ( int j = 0; j < listeners.length; j++ ) {
+					listeners[j].onFlushEntity(entityEvent);
+				}
+			}
+		}
+
+		source.getActionQueue().sortActions();
+	}
+
+	/**
+	 * process any unreferenced collections and then inspect all known collections,
+	 * scheduling creates/removes/updates
+	 */
+	private void flushCollections(EventSource session) throws HibernateException {
+
+		log.trace("Processing unreferenced collections");
+
+		List list = IdentityMap.entries( session.getPersistenceContext().getCollectionEntries() );
+		int size = list.size();
+		for ( int i = 0; i < size; i++ ) {
+			Map.Entry me = ( Map.Entry ) list.get( i );
+			CollectionEntry ce = (CollectionEntry) me.getValue();
+			if ( !ce.isReached() && !ce.isIgnore() ) {
+				Collections.processUnreachableCollection( (PersistentCollection) me.getKey(), session );
+			}
+		}
+
+		// Schedule updates to collections:
+
+		log.trace( "Scheduling collection removes/(re)creates/updates" );
+
+		list = IdentityMap.entries( session.getPersistenceContext().getCollectionEntries() );
+		size = list.size();
+		ActionQueue actionQueue = session.getActionQueue();
+		for ( int i = 0; i < size; i++ ) {
+			Map.Entry me = (Map.Entry) list.get(i);
+			PersistentCollection coll = (PersistentCollection) me.getKey();
+			CollectionEntry ce = (CollectionEntry) me.getValue();
+
+			if ( ce.isDorecreate() ) {
+				session.getInterceptor().onCollectionRecreate( coll, ce.getCurrentKey() );
+				actionQueue.addAction(
+						new CollectionRecreateAction( 
+								coll, 
+								ce.getCurrentPersister(), 
+								ce.getCurrentKey(), 
+								session 
+							)
+					);
+			}
+			if ( ce.isDoremove() ) {
+				session.getInterceptor().onCollectionRemove( coll, ce.getLoadedKey() );
+				actionQueue.addAction(
+						new CollectionRemoveAction( 
+								coll, 
+								ce.getLoadedPersister(), 
+								ce.getLoadedKey(), 
+								ce.isSnapshotEmpty(coll), 
+								session 
+							)
+					);
+			}
+			if ( ce.isDoupdate() ) {
+				session.getInterceptor().onCollectionUpdate( coll, ce.getLoadedKey() );
+				actionQueue.addAction(
+						new CollectionUpdateAction( 
+								coll, 
+								ce.getLoadedPersister(), 
+								ce.getLoadedKey(), 
+								ce.isSnapshotEmpty(coll), 
+								session 
+							)
+					);
+			}
+
+		}
+
+		actionQueue.sortCollectionActions();
+		
+	}
+
+	/**
+	 * Execute all SQL and second-level cache updates, in a
+	 * special order so that foreign-key constraints cannot
+	 * be violated:
+	 * <ol>
+	 * <li> Inserts, in the order they were performed
+	 * <li> Updates
+	 * <li> Deletion of collection elements
+	 * <li> Insertion of collection elements
+	 * <li> Deletes, in the order they were performed
+	 * </ol>
+	 */
+	protected void performExecutions(EventSource session) throws HibernateException {
+
+		log.trace("executing flush");
+
+		try {
+			session.getJDBCContext().getConnectionManager().flushBeginning();
+			// we need to lock the collection caches before
+			// executing entity inserts/updates in order to
+			// account for bidi associations
+			session.getActionQueue().prepareActions();
+			session.getActionQueue().executeActions();
+		}
+		catch (HibernateException he) {
+			log.error("Could not synchronize database state with session", he);
+			throw he;
+		}
+		finally {
+			session.getJDBCContext().getConnectionManager().flushEnding();
+		}
+	}
+
+
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	// Post-flushing section
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * 1. Recreate the collection key -> collection map
+	 * 2. rebuild the collection entries
+	 * 3. call Interceptor.postFlush()
+	 */
+	protected void postFlush(SessionImplementor session) throws HibernateException {
+
+		log.trace( "post flush" );
+
+		final PersistenceContext persistenceContext = session.getPersistenceContext();
+		persistenceContext.getCollectionsByKey().clear();
+		persistenceContext.getBatchFetchQueue()
+				.clearSubselects(); //the database has changed now, so the subselect results need to be invalidated
+
+		Iterator iter = persistenceContext.getCollectionEntries().entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			CollectionEntry collectionEntry = (CollectionEntry) me.getValue();
+			PersistentCollection persistentCollection = (PersistentCollection) me.getKey();
+			collectionEntry.postFlush(persistentCollection);
+			if ( collectionEntry.getLoadedPersister() == null ) {
+				//if the collection is dereferenced, remove from the session cache
+				//iter.remove(); //does not work, since the entrySet is not backed by the set
+				persistenceContext.getCollectionEntries()
+						.remove(persistentCollection);
+			}
+			else {
+				//otherwise recreate the mapping between the collection and its key
+				CollectionKey collectionKey = new CollectionKey( 
+						collectionEntry.getLoadedPersister(), 
+						collectionEntry.getLoadedKey(), 
+						session.getEntityMode() 
+					);
+				persistenceContext.getCollectionsByKey()
+						.put(collectionKey, persistentCollection);
+			}
+		}
+		
+		session.getInterceptor().postFlush( new LazyIterator( persistenceContext.getEntitiesByKey() ) );
+
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractLockUpgradeEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractLockUpgradeEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractLockUpgradeEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,100 @@
+//$Id: AbstractLockUpgradeEventListener.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.LockMode;
+import org.hibernate.ObjectDeletedException;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.cache.access.SoftLock;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.Status;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.pretty.MessageHelper;
+
+/**
+ * A convenience base class for listeners that respond to requests to perform a
+ * pessimistic lock upgrade on an entity.
+ *
+ * @author Gavin King
+ */
+public class AbstractLockUpgradeEventListener extends AbstractReassociateEventListener {
+
+	private static final Log log = LogFactory.getLog(AbstractLockUpgradeEventListener.class);
+
+	/**
+	 * Performs a pessimistic lock upgrade on a given entity, if needed.
+	 *
+	 * @param object The entity for which to upgrade the lock.
+	 * @param entry The entity's EntityEntry instance.
+	 * @param requestedLockMode The lock mode being requested for locking.
+	 * @param source The session which is the source of the event being processed.
+	 */
+	protected void upgradeLock(Object object, EntityEntry entry, LockMode requestedLockMode, SessionImplementor source) {
+
+		if ( requestedLockMode.greaterThan( entry.getLockMode() ) ) {
+			// The user requested a "greater" (i.e. more restrictive) form of
+			// pessimistic lock
+
+			if ( entry.getStatus() != Status.MANAGED ) {
+				throw new ObjectDeletedException(
+						"attempted to lock a deleted instance",
+						entry.getId(),
+						entry.getPersister().getEntityName()
+				);
+			}
+
+			final EntityPersister persister = entry.getPersister();
+
+			if ( log.isTraceEnabled() )
+				log.trace(
+						"locking " +
+						MessageHelper.infoString( persister, entry.getId(), source.getFactory() ) +
+						" in mode: " +
+						requestedLockMode
+				);
+
+			final SoftLock lock;
+			final CacheKey ck;
+			if ( persister.hasCache() ) {
+				ck = new CacheKey( 
+						entry.getId(), 
+						persister.getIdentifierType(), 
+						persister.getRootEntityName(), 
+						source.getEntityMode(), 
+						source.getFactory() 
+				);
+				lock = persister.getCacheAccessStrategy().lockItem( ck, entry.getVersion() );
+			}
+			else {
+				ck = null;
+				lock = null;
+			}
+			
+			try {
+				if ( persister.isVersioned() && requestedLockMode == LockMode.FORCE ) {
+					// todo : should we check the current isolation mode explicitly?
+					Object nextVersion = persister.forceVersionIncrement(
+							entry.getId(), entry.getVersion(), source
+					);
+					entry.forceLocked( object, nextVersion );
+				}
+				else {
+					persister.lock( entry.getId(), entry.getVersion(), object, requestedLockMode, source );
+				}
+				entry.setLockMode(requestedLockMode);
+			}
+			finally {
+				// the database now holds a lock + the object is flushed from the cache,
+				// so release the soft lock
+				if ( persister.hasCache() ) {
+					persister.getCacheAccessStrategy().unlockItem( ck, lock );
+				}
+			}
+
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractReassociateEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractReassociateEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractReassociateEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,87 @@
+//$Id: AbstractReassociateEventListener.java 10948 2006-12-07 21:53:10Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.LockMode;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.Status;
+import org.hibernate.engine.Versioning;
+import org.hibernate.event.AbstractEvent;
+import org.hibernate.event.EventSource;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * A convenience base class for listeners that respond to requests to reassociate an entity
+ * to a session ( such as through lock() or update() ).
+ *
+ * @author Gavin King
+ */
+public class AbstractReassociateEventListener implements Serializable {
+
+	private static final Log log = LogFactory.getLog( AbstractReassociateEventListener.class );
+
+	/**
+	 * Associates a given entity (either transient or associated with another session) to
+	 * the given session.
+	 *
+	 * @param event The event triggering the re-association
+	 * @param object The entity to be associated
+	 * @param id The id of the entity.
+	 * @param persister The entity's persister instance.
+	 *
+	 * @return An EntityEntry representing the entity within this session.
+	 */
+	protected final EntityEntry reassociate(AbstractEvent event, Object object, Serializable id, EntityPersister persister) {
+
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"reassociating transient instance: " +
+							MessageHelper.infoString( persister, id, event.getSession().getFactory() )
+			);
+		}
+
+		EventSource source = event.getSession();
+		EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
+
+		source.getPersistenceContext().checkUniqueness( key, object );
+
+		//get a snapshot
+		Object[] values = persister.getPropertyValues( object, source.getEntityMode() );
+		TypeFactory.deepCopy(
+				values,
+				persister.getPropertyTypes(),
+				persister.getPropertyUpdateability(),
+				values,
+				source
+		);
+		Object version = Versioning.getVersion( values, persister );
+
+		EntityEntry newEntry = source.getPersistenceContext().addEntity(
+				object,
+				Status.MANAGED,
+				values,
+				key,
+				version,
+				LockMode.NONE,
+				true,
+				persister,
+				false,
+				true //will be ignored, using the existing Entry instead
+		);
+
+		new OnLockVisitor( source, id, object ).process( object, persister );
+
+		persister.afterReassociate( object, source );
+
+		return newEntry;
+
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractSaveEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractSaveEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractSaveEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,542 @@
+//$Id: AbstractSaveEventListener.java 10948 2006-12-07 21:53:10Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.LockMode;
+import org.hibernate.NonUniqueObjectException;
+import org.hibernate.action.EntityIdentityInsertAction;
+import org.hibernate.action.EntityInsertAction;
+import org.hibernate.classic.Lifecycle;
+import org.hibernate.classic.Validatable;
+import org.hibernate.engine.Cascade;
+import org.hibernate.engine.CascadingAction;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.ForeignKeys;
+import org.hibernate.engine.Nullability;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.Status;
+import org.hibernate.engine.Versioning;
+import org.hibernate.event.EventSource;
+import org.hibernate.id.IdentifierGenerationException;
+import org.hibernate.id.IdentifierGeneratorFactory;
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.intercept.FieldInterceptor;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * A convenience bas class for listeners responding to save events.
+ *
+ * @author Steve Ebersole.
+ */
+public abstract class AbstractSaveEventListener extends AbstractReassociateEventListener {
+
+	protected static final int PERSISTENT = 0;
+	protected static final int TRANSIENT = 1;
+	protected static final int DETACHED = 2;
+	protected static final int DELETED = 3;
+
+	private static final Log log = LogFactory.getLog( AbstractSaveEventListener.class );
+
+	/**
+	 * Prepares the save call using the given requested id.
+	 *
+	 * @param entity The entity to be saved.
+	 * @param requestedId The id to which to associate the entity.
+	 * @param entityName The name of the entity being saved.
+	 * @param anything Generally cascade-specific information.
+	 * @param source The session which is the source of this save event.
+	 *
+	 * @return The id used to save the entity.
+	 */
+	protected Serializable saveWithRequestedId(
+			Object entity,
+			Serializable requestedId,
+			String entityName,
+			Object anything,
+			EventSource source) {
+		return performSave(
+				entity,
+				requestedId,
+				source.getEntityPersister( entityName, entity ),
+				false,
+				anything,
+				source,
+				true
+		);
+	}
+
+	/**
+	 * Prepares the save call using a newly generated id.
+	 *
+	 * @param entity The entity to be saved
+	 * @param entityName The entity-name for the entity to be saved
+	 * @param anything Generally cascade-specific information.
+	 * @param source The session which is the source of this save event.
+	 * @param requiresImmediateIdAccess does the event context require
+	 * access to the identifier immediately after execution of this method (if
+	 * not, post-insert style id generators may be postponed if we are outside
+	 * a transaction).
+	 *
+	 * @return The id used to save the entity; may be null depending on the
+	 *         type of id generator used and the requiresImmediateIdAccess value
+	 */
+	protected Serializable saveWithGeneratedId(
+			Object entity,
+			String entityName,
+			Object anything,
+			EventSource source,
+			boolean requiresImmediateIdAccess) {
+		EntityPersister persister = source.getEntityPersister( entityName, entity );
+		Serializable generatedId = persister.getIdentifierGenerator().generate( source, entity );
+		if ( generatedId == null ) {
+			throw new IdentifierGenerationException( "null id generated for:" + entity.getClass() );
+		}
+		else if ( generatedId == IdentifierGeneratorFactory.SHORT_CIRCUIT_INDICATOR ) {
+			return source.getIdentifier( entity );
+		}
+		else if ( generatedId == IdentifierGeneratorFactory.POST_INSERT_INDICATOR ) {
+			return performSave( entity, null, persister, true, anything, source, requiresImmediateIdAccess );
+		}
+		else {
+
+			if ( log.isDebugEnabled() ) {
+				log.debug(
+						"generated identifier: " +
+								persister.getIdentifierType().toLoggableString( generatedId, source.getFactory() ) +
+								", using strategy: " +
+								persister.getIdentifierGenerator().getClass().getName()
+						//TODO: define toString()s for generators
+				);
+			}
+
+			return performSave( entity, generatedId, persister, false, anything, source, true );
+		}
+	}
+
+	/**
+	 * Ppepares the save call by checking the session caches for a pre-existing
+	 * entity and performing any lifecycle callbacks.
+	 *
+	 * @param entity The entity to be saved.
+	 * @param id The id by which to save the entity.
+	 * @param persister The entity's persister instance.
+	 * @param useIdentityColumn Is an identity column being used?
+	 * @param anything Generally cascade-specific information.
+	 * @param source The session from which the event originated.
+	 * @param requiresImmediateIdAccess does the event context require
+	 * access to the identifier immediately after execution of this method (if
+	 * not, post-insert style id generators may be postponed if we are outside
+	 * a transaction).
+	 *
+	 * @return The id used to save the entity; may be null depending on the
+	 *         type of id generator used and the requiresImmediateIdAccess value
+	 */
+	protected Serializable performSave(
+			Object entity,
+			Serializable id,
+			EntityPersister persister,
+			boolean useIdentityColumn,
+			Object anything,
+			EventSource source,
+			boolean requiresImmediateIdAccess) {
+
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"saving " +
+							MessageHelper.infoString( persister, id, source.getFactory() )
+			);
+		}
+
+		EntityKey key;
+		if ( !useIdentityColumn ) {
+			key = new EntityKey( id, persister, source.getEntityMode() );
+			Object old = source.getPersistenceContext().getEntity( key );
+			if ( old != null ) {
+				if ( source.getPersistenceContext().getEntry( old ).getStatus() == Status.DELETED ) {
+					source.forceFlush( source.getPersistenceContext().getEntry( old ) );
+				}
+				else {
+					throw new NonUniqueObjectException( id, persister.getEntityName() );
+				}
+			}
+			persister.setIdentifier( entity, id, source.getEntityMode() );
+		}
+		else {
+			key = null;
+		}
+
+		if ( invokeSaveLifecycle( entity, persister, source ) ) {
+			return id; //EARLY EXIT
+		}
+
+		return performSaveOrReplicate(
+				entity,
+				key,
+				persister,
+				useIdentityColumn,
+				anything,
+				source,
+				requiresImmediateIdAccess
+		);
+	}
+
+	protected boolean invokeSaveLifecycle(Object entity, EntityPersister persister, EventSource source) {
+		// Sub-insertions should occur before containing insertion so
+		// Try to do the callback now
+		if ( persister.implementsLifecycle( source.getEntityMode() ) ) {
+			log.debug( "calling onSave()" );
+			if ( ( ( Lifecycle ) entity ).onSave( source ) ) {
+				log.debug( "insertion vetoed by onSave()" );
+				return true;
+			}
+		}
+		return false;
+	}
+
+	protected void validate(Object entity, EntityPersister persister, EventSource source) {
+		if ( persister.implementsValidatable( source.getEntityMode() ) ) {
+			( ( Validatable ) entity ).validate();
+		}
+	}
+
+	/**
+	 * Performs all the actual work needed to save an entity (well to get the save moved to
+	 * the execution queue).
+	 *
+	 * @param entity The entity to be saved
+	 * @param key The id to be used for saving the entity (or null, in the case of identity columns)
+	 * @param persister The entity's persister instance.
+	 * @param useIdentityColumn Should an identity column be used for id generation?
+	 * @param anything Generally cascade-specific information.
+	 * @param source The session which is the source of the current event.
+	 * @param requiresImmediateIdAccess Is access to the identifier required immediately
+	 * after the completion of the save?  persist(), for example, does not require this...
+	 *
+	 * @return The id used to save the entity; may be null depending on the
+	 *         type of id generator used and the requiresImmediateIdAccess value
+	 */
+	protected Serializable performSaveOrReplicate(
+			Object entity,
+			EntityKey key,
+			EntityPersister persister,
+			boolean useIdentityColumn,
+			Object anything,
+			EventSource source,
+			boolean requiresImmediateIdAccess) {
+
+		validate( entity, persister, source );
+
+		Serializable id = key == null ? null : key.getIdentifier();
+
+		boolean inTxn = source.getJDBCContext().isTransactionInProgress();
+		boolean shouldDelayIdentityInserts = !inTxn && !requiresImmediateIdAccess;
+
+		if ( useIdentityColumn && !shouldDelayIdentityInserts ) {
+			log.trace( "executing insertions" );
+			source.getActionQueue().executeInserts();
+		}
+
+		// Put a placeholder in entries, so we don't recurse back and try to save() the
+		// same object again. QUESTION: should this be done before onSave() is called?
+		// likewise, should it be done before onUpdate()?
+		source.getPersistenceContext().addEntry(
+				entity,
+				Status.SAVING,
+				null,
+				null,
+				id,
+				null,
+				LockMode.WRITE,
+				useIdentityColumn,
+				persister,
+				false,
+				false
+		);
+
+		cascadeBeforeSave( source, persister, entity, anything );
+
+		Object[] values = persister.getPropertyValuesToInsert( entity, getMergeMap( anything ), source );
+		Type[] types = persister.getPropertyTypes();
+
+		boolean substitute = substituteValuesIfNecessary( entity, id, values, persister, source );
+
+		if ( persister.hasCollections() ) {
+			substitute = substitute || visitCollectionsBeforeSave( entity, id, values, types, source );
+		}
+
+		if ( substitute ) {
+			persister.setPropertyValues( entity, values, source.getEntityMode() );
+		}
+
+		TypeFactory.deepCopy(
+				values,
+				types,
+				persister.getPropertyUpdateability(),
+				values,
+				source
+		);
+
+		new ForeignKeys.Nullifier( entity, false, useIdentityColumn, source )
+				.nullifyTransientReferences( values, types );
+		new Nullability( source ).checkNullability( values, persister, false );
+
+		if ( useIdentityColumn ) {
+			EntityIdentityInsertAction insert = new EntityIdentityInsertAction(
+					values, entity, persister, source, shouldDelayIdentityInserts
+			);
+			if ( !shouldDelayIdentityInserts ) {
+				log.debug( "executing identity-insert immediately" );
+				source.getActionQueue().execute( insert );
+				id = insert.getGeneratedId();
+				//now done in EntityIdentityInsertAction
+				//persister.setIdentifier( entity, id, source.getEntityMode() );
+				key = new EntityKey( id, persister, source.getEntityMode() );
+				source.getPersistenceContext().checkUniqueness( key, entity );
+				//source.getBatcher().executeBatch(); //found another way to ensure that all batched joined inserts have been executed
+			}
+			else {
+				log.debug( "delaying identity-insert due to no transaction in progress" );
+				source.getActionQueue().addAction( insert );
+				key = insert.getDelayedEntityKey();
+			}
+		}
+
+		Object version = Versioning.getVersion( values, persister );
+		source.getPersistenceContext().addEntity(
+				entity,
+				Status.MANAGED,
+				values,
+				key,
+				version,
+				LockMode.WRITE,
+				useIdentityColumn,
+				persister,
+				isVersionIncrementDisabled(),
+				false
+		);
+		//source.getPersistenceContext().removeNonExist( new EntityKey( id, persister, source.getEntityMode() ) );
+
+		if ( !useIdentityColumn ) {
+			source.getActionQueue().addAction(
+					new EntityInsertAction( id, values, entity, version, persister, source )
+			);
+		}
+
+		cascadeAfterSave( source, persister, entity, anything );
+
+		markInterceptorDirty( entity, persister, source );
+
+		return id;
+	}
+
+	private void markInterceptorDirty(Object entity, EntityPersister persister, EventSource source) {
+		if ( FieldInterceptionHelper.isInstrumented( entity ) ) {
+			FieldInterceptor interceptor = FieldInterceptionHelper.injectFieldInterceptor(
+					entity,
+					persister.getEntityName(),
+					null,
+					source
+			);
+			interceptor.dirty();
+		}
+	}
+
+	protected Map getMergeMap(Object anything) {
+		return null;
+	}
+
+	/**
+	 * After the save, will te version number be incremented
+	 * if the instance is modified?
+	 *
+	 * @return True if the version will be incremented on an entity change after save;
+	 *         false otherwise.
+	 */
+	protected boolean isVersionIncrementDisabled() {
+		return false;
+	}
+
+	protected boolean visitCollectionsBeforeSave(Object entity, Serializable id, Object[] values, Type[] types, EventSource source) {
+		WrapVisitor visitor = new WrapVisitor( source );
+		// substitutes into values by side-effect
+		visitor.processEntityPropertyValues( values, types );
+		return visitor.isSubstitutionRequired();
+	}
+
+	/**
+	 * Perform any property value substitution that is necessary
+	 * (interceptor callback, version initialization...)
+	 *
+	 * @param entity The entity
+	 * @param id The entity identifier
+	 * @param values The snapshot entity state
+	 * @param persister The entity persister
+	 * @param source The originating session
+	 *
+	 * @return True if the snapshot state changed such that
+	 * reinjection of the values into the entity is required.
+	 */
+	protected boolean substituteValuesIfNecessary(
+			Object entity,
+			Serializable id,
+			Object[] values,
+			EntityPersister persister,
+			SessionImplementor source) {
+		boolean substitute = source.getInterceptor().onSave(
+				entity,
+				id,
+				values,
+				persister.getPropertyNames(),
+				persister.getPropertyTypes()
+		);
+
+		//keep the existing version number in the case of replicate!
+		if ( persister.isVersioned() ) {
+			substitute = Versioning.seedVersion(
+					values,
+					persister.getVersionProperty(),
+					persister.getVersionType(),
+					source
+			) || substitute;
+		}
+		return substitute;
+	}
+
+	/**
+	 * Handles the calls needed to perform pre-save cascades for the given entity.
+	 *
+	 * @param source The session from whcih the save event originated.
+	 * @param persister The entity's persister instance.
+	 * @param entity The entity to be saved.
+	 * @param anything Generally cascade-specific data
+	 */
+	protected void cascadeBeforeSave(
+			EventSource source,
+			EntityPersister persister,
+			Object entity,
+			Object anything) {
+
+		// cascade-save to many-to-one BEFORE the parent is saved
+		source.getPersistenceContext().incrementCascadeLevel();
+		try {
+			new Cascade( getCascadeAction(), Cascade.BEFORE_INSERT_AFTER_DELETE, source )
+					.cascade( persister, entity, anything );
+		}
+		finally {
+			source.getPersistenceContext().decrementCascadeLevel();
+		}
+	}
+
+	/**
+	 * Handles to calls needed to perform post-save cascades.
+	 *
+	 * @param source The session from which the event originated.
+	 * @param persister The entity's persister instance.
+	 * @param entity The entity beng saved.
+	 * @param anything Generally cascade-specific data
+	 */
+	protected void cascadeAfterSave(
+			EventSource source,
+			EntityPersister persister,
+			Object entity,
+			Object anything) {
+
+		// cascade-save to collections AFTER the collection owner was saved
+		source.getPersistenceContext().incrementCascadeLevel();
+		try {
+			new Cascade( getCascadeAction(), Cascade.AFTER_INSERT_BEFORE_DELETE, source )
+					.cascade( persister, entity, anything );
+		}
+		finally {
+			source.getPersistenceContext().decrementCascadeLevel();
+		}
+	}
+
+	protected abstract CascadingAction getCascadeAction();
+
+	/**
+	 * Determine whether the entity is persistent, detached, or transient
+	 *
+	 * @param entity The entity to check
+	 * @param entityName The name of the entity
+	 * @param entry The entity's entry in the persistence context
+	 * @param source The originating session.
+	 *
+	 * @return The state.
+	 */
+	protected int getEntityState(
+			Object entity,
+			String entityName,
+			EntityEntry entry, //pass this as an argument only to avoid double looking
+			SessionImplementor source) {
+
+		if ( entry != null ) { // the object is persistent
+
+			//the entity is associated with the session, so check its status
+			if ( entry.getStatus() != Status.DELETED ) {
+				// do nothing for persistent instances
+				if ( log.isTraceEnabled() ) {
+					log.trace(
+							"persistent instance of: " +
+									getLoggableName( entityName, entity )
+					);
+				}
+				return PERSISTENT;
+			}
+			else {
+				//ie. e.status==DELETED
+				if ( log.isTraceEnabled() ) {
+					log.trace(
+							"deleted instance of: " +
+									getLoggableName( entityName, entity )
+					);
+				}
+				return DELETED;
+			}
+
+		}
+		else { // the object is transient or detached
+
+			//the entity is not associated with the session, so
+			//try interceptor and unsaved-value
+
+			if ( ForeignKeys.isTransient( entityName, entity, getAssumedUnsaved(), source ) ) {
+				if ( log.isTraceEnabled() ) {
+					log.trace(
+							"transient instance of: " +
+									getLoggableName( entityName, entity )
+					);
+				}
+				return TRANSIENT;
+			}
+			else {
+				if ( log.isTraceEnabled() ) {
+					log.trace(
+							"detached instance of: " +
+									getLoggableName( entityName, entity )
+					);
+				}
+				return DETACHED;
+			}
+
+		}
+	}
+
+	protected String getLoggableName(String entityName, Object entity) {
+		return entityName == null ? entity.getClass().getName() : entityName;
+	}
+
+	protected Boolean getAssumedUnsaved() {
+		return null;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractVisitor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractVisitor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/AbstractVisitor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,157 @@
+//$Id: AbstractVisitor.java 7546 2005-07-19 18:17:15Z oneovthafew $
+package org.hibernate.event.def;
+
+import org.hibernate.HibernateException;
+import org.hibernate.event.EventSource;
+import org.hibernate.intercept.LazyPropertyInitializer;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+
+
+/**
+ * Abstract superclass of algorithms that walk
+ * a tree of property values of an entity, and
+ * perform specific functionality for collections,
+ * components and associated entities.
+ *
+ * @author Gavin King
+ */
+public abstract class AbstractVisitor {
+
+	private final EventSource session;
+
+	AbstractVisitor(EventSource session) {
+		this.session = session;
+	}
+
+	/**
+	 * Dispatch each property value to processValue().
+	 *
+	 * @param values
+	 * @param types
+	 * @throws HibernateException
+	 */
+	void processValues(Object[] values, Type[] types) throws HibernateException {
+		for ( int i=0; i<types.length; i++ ) {
+			if ( includeProperty(values, i) ) {
+				processValue( i, values, types );
+			}
+		}
+	}
+	
+	/**
+	 * Dispatch each property value to processValue().
+	 *
+	 * @param values
+	 * @param types
+	 * @throws HibernateException
+	 */
+	public void processEntityPropertyValues(Object[] values, Type[] types) throws HibernateException {
+		for ( int i=0; i<types.length; i++ ) {
+			if ( includeEntityProperty(values, i) ) {
+				processValue( i, values, types );
+			}
+		}
+	}
+	
+	void processValue(int i, Object[] values, Type[] types) {
+		processValue( values[i], types[i] );
+	}
+	
+	boolean includeEntityProperty(Object[] values, int i) {
+		return includeProperty(values, i);
+	}
+	
+	boolean includeProperty(Object[] values, int i) {
+		return values[i]!=LazyPropertyInitializer.UNFETCHED_PROPERTY;
+	}
+
+	/**
+	 * Visit a component. Dispatch each property
+	 * to processValue().
+	 * @param component
+	 * @param componentType
+	 * @throws HibernateException
+	 */
+	Object processComponent(Object component, AbstractComponentType componentType)
+	throws HibernateException {
+		if (component!=null) {
+			processValues(
+				componentType.getPropertyValues(component, session),
+				componentType.getSubtypes()
+			);
+		}
+		return null;
+	}
+
+	/**
+	 * Visit a property value. Dispatch to the
+	 * correct handler for the property type.
+	 * @param value
+	 * @param type
+	 * @throws HibernateException
+	 */
+	final Object processValue(Object value, Type type) throws HibernateException {
+
+		if ( type.isCollectionType() ) {
+			//even process null collections
+			return processCollection( value, (CollectionType) type );
+		}
+		else if ( type.isEntityType() ) {
+			return processEntity( value, (EntityType) type );
+		}
+		else if ( type.isComponentType() ) {
+			return processComponent( value, (AbstractComponentType) type );
+		}
+		else {
+			return null;
+		}
+	}
+
+	/**
+	 * Walk the tree starting from the given entity.
+	 *
+	 * @param object
+	 * @param persister
+	 * @throws HibernateException
+	 */
+	void process(Object object, EntityPersister persister)
+	throws HibernateException {
+		processEntityPropertyValues(
+			persister.getPropertyValues( object, getSession().getEntityMode() ),
+			persister.getPropertyTypes()
+		);
+	}
+
+	/**
+	 * Visit a collection. Default superclass
+	 * implementation is a no-op.
+	 * @param collection
+	 * @param type
+	 * @throws HibernateException
+	 */
+	Object processCollection(Object collection, CollectionType type)
+	throws HibernateException {
+		return null;
+	}
+
+	/**
+	 * Visit a many-to-one or one-to-one associated
+	 * entity. Default superclass implementation is
+	 * a no-op.
+	 * @param value
+	 * @param entityType
+	 * @throws HibernateException
+	 */
+	Object processEntity(Object value, EntityType entityType)
+	throws HibernateException {
+		return null;
+	}
+
+	final EventSource getSession() {
+		return session;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultAutoFlushEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultAutoFlushEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultAutoFlushEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,75 @@
+//$Id: DefaultAutoFlushEventListener.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event.def;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.event.AutoFlushEvent;
+import org.hibernate.event.AutoFlushEventListener;
+import org.hibernate.event.EventSource;
+
+/**
+ * Defines the default flush event listeners used by hibernate for 
+ * flushing session state in response to generated auto-flush events.
+ *
+ * @author Steve Ebersole
+ */
+public class DefaultAutoFlushEventListener extends AbstractFlushingEventListener implements AutoFlushEventListener {
+
+	private static final Log log = LogFactory.getLog(DefaultAutoFlushEventListener.class);
+
+    /** Handle the given auto-flush event.
+     *
+     * @param event The auto-flush event to be handled.
+     * @throws HibernateException
+     */
+	public void onAutoFlush(AutoFlushEvent event) throws HibernateException {
+
+		final EventSource source = event.getSession();
+		
+		if ( flushMightBeNeeded(source) ) {
+
+			final int oldSize = source.getActionQueue().numberOfCollectionRemovals();
+
+			flushEverythingToExecutions(event);
+			
+			if ( flushIsReallyNeeded(event, source) ) {
+
+				log.trace("Need to execute flush");
+
+				performExecutions(source);
+				postFlush(source);
+				// note: performExecutions() clears all collectionXxxxtion 
+				// collections (the collection actions) in the session
+
+				if ( source.getFactory().getStatistics().isStatisticsEnabled() ) {
+					source.getFactory().getStatisticsImplementor().flush();
+				}
+				
+			}
+			else {
+
+				log.trace("Dont need to execute flush");
+				source.getActionQueue().clearFromFlushNeededCheck( oldSize );
+			}
+			
+			event.setFlushRequired( flushIsReallyNeeded( event, source ) );
+
+		}
+
+	}
+
+	private boolean flushIsReallyNeeded(AutoFlushEvent event, final EventSource source) {
+		return source.getActionQueue()
+				.areTablesToBeUpdated( event.getQuerySpaces() ) || 
+						source.getFlushMode()==FlushMode.ALWAYS;
+	}
+
+	private boolean flushMightBeNeeded(final EventSource source) {
+		return !source.getFlushMode().lessThan(FlushMode.AUTO) && 
+				source.getDontFlushFromFind() == 0 &&
+				source.getPersistenceContext().hasNonReadOnlyEntities();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultDeleteEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultDeleteEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultDeleteEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,336 @@
+//$Id: DefaultDeleteEventListener.java 10948 2006-12-07 21:53:10Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.CacheMode;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.TransientObjectException;
+import org.hibernate.util.IdentitySet;
+import org.hibernate.action.EntityDeleteAction;
+import org.hibernate.classic.Lifecycle;
+import org.hibernate.engine.Cascade;
+import org.hibernate.engine.CascadingAction;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.ForeignKeys;
+import org.hibernate.engine.Nullability;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.Status;
+import org.hibernate.event.DeleteEvent;
+import org.hibernate.event.DeleteEventListener;
+import org.hibernate.event.EventSource;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+
+
+/**
+ * Defines the default delete event listener used by hibernate for deleting entities
+ * from the datastore in response to generated delete events.
+ *
+ * @author Steve Ebersole
+ */
+public class DefaultDeleteEventListener implements DeleteEventListener {
+
+	private static final Log log = LogFactory.getLog( DefaultDeleteEventListener.class );
+
+	/**
+	 * Handle the given delete event.
+	 *
+	 * @param event The delete event to be handled.
+	 *
+	 * @throws HibernateException
+	 */
+	public void onDelete(DeleteEvent event) throws HibernateException {
+		onDelete( event, new IdentitySet() );
+	}
+
+	/**
+	 * Handle the given delete event.  This is the cascaded form.
+	 *
+	 * @param event The delete event.
+	 * @param transientEntities The cache of entities already deleted
+	 *
+	 * @throws HibernateException
+	 */
+	public void onDelete(DeleteEvent event, Set transientEntities) throws HibernateException {
+
+		final EventSource source = event.getSession();
+
+		final PersistenceContext persistenceContext = source.getPersistenceContext();
+		Object entity = persistenceContext.unproxyAndReassociate( event.getObject() );
+
+		EntityEntry entityEntry = persistenceContext.getEntry( entity );
+		final EntityPersister persister;
+		final Serializable id;
+		final Object version;
+
+		if ( entityEntry == null ) {
+			log.trace( "entity was not persistent in delete processing" );
+
+			persister = source.getEntityPersister( event.getEntityName(), entity );
+
+			if ( ForeignKeys.isTransient( persister.getEntityName(), entity, null, source ) ) {
+				deleteTransientEntity( source, entity, event.isCascadeDeleteEnabled(), persister, transientEntities );
+				// EARLY EXIT!!!
+				return;
+			}
+			else {
+				performDetachedEntityDeletionCheck( event );
+			}
+
+			id = persister.getIdentifier( entity, source.getEntityMode() );
+
+			if ( id == null ) {
+				throw new TransientObjectException(
+						"the detached instance passed to delete() had a null identifier"
+				);
+			}
+
+			EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
+
+			persistenceContext.checkUniqueness( key, entity );
+
+			new OnUpdateVisitor( source, id, entity ).process( entity, persister );
+
+			version = persister.getVersion( entity, source.getEntityMode() );
+
+			entityEntry = persistenceContext.addEntity(
+					entity,
+					Status.MANAGED,
+					persister.getPropertyValues( entity, source.getEntityMode() ),
+					key,
+					version,
+					LockMode.NONE,
+					true,
+					persister,
+					false,
+					false
+			);
+		}
+		else {
+			log.trace( "deleting a persistent instance" );
+
+			if ( entityEntry.getStatus() == Status.DELETED || entityEntry.getStatus() == Status.GONE ) {
+				log.trace( "object was already deleted" );
+				return;
+			}
+			persister = entityEntry.getPersister();
+			id = entityEntry.getId();
+			version = entityEntry.getVersion();
+		}
+
+		/*if ( !persister.isMutable() ) {
+			throw new HibernateException(
+					"attempted to delete an object of immutable class: " +
+					MessageHelper.infoString(persister)
+				);
+		}*/
+
+		if ( invokeDeleteLifecycle( source, entity, persister ) ) {
+			return;
+		}
+
+		deleteEntity( source, entity, entityEntry, event.isCascadeDeleteEnabled(), persister, transientEntities );
+
+		if ( source.getFactory().getSettings().isIdentifierRollbackEnabled() ) {
+			persister.resetIdentifier( entity, id, version, source.getEntityMode() );
+		}
+	}
+
+	/**
+	 * Called when we have recognized an attempt to delete a detached entity.
+	 * <p/>
+	 * This is perfectly valid in Hibernate usage; JPA, however, forbids this.
+	 * Thus, this is a hook for HEM to affect this behavior.
+	 *
+	 * @param event The event.
+	 */
+	protected void performDetachedEntityDeletionCheck(DeleteEvent event) {
+		// ok in normal Hibernate usage to delete a detached entity; JPA however
+		// forbids it, thus this is a hook for HEM to affect this behavior
+	}
+
+	/**
+	 * We encountered a delete request on a transient instance.
+	 * <p/>
+	 * This is a deviation from historical Hibernate (pre-3.2) behavior to
+	 * align with the JPA spec, which states that transient entities can be
+	 * passed to remove operation in which case cascades still need to be
+	 * performed.
+	 *
+	 * @param session The session which is the source of the event
+	 * @param entity The entity being delete processed
+	 * @param cascadeDeleteEnabled Is cascading of deletes enabled
+	 * @param persister The entity persister
+	 * @param transientEntities A cache of already visited transient entities
+	 * (to avoid infinite recursion).
+	 */
+	protected void deleteTransientEntity(
+			EventSource session,
+			Object entity,
+			boolean cascadeDeleteEnabled,
+			EntityPersister persister,
+			Set transientEntities) {
+		log.info( "handling transient entity in delete processing" );
+		if ( transientEntities.contains( entity ) ) {
+			log.trace( "already handled transient entity; skipping" );
+			return;
+		}
+		transientEntities.add( entity );
+		cascadeBeforeDelete( session, persister, entity, null, transientEntities );
+		cascadeAfterDelete( session, persister, entity, transientEntities );
+	}
+
+	/**
+	 * Perform the entity deletion.  Well, as with most operations, does not
+	 * really perform it; just schedules an action/execution with the
+	 * {@link org.hibernate.engine.ActionQueue} for execution during flush.
+	 *
+	 * @param session The originating session
+	 * @param entity The entity to delete
+	 * @param entityEntry The entity's entry in the {@link PersistenceContext}
+	 * @param isCascadeDeleteEnabled Is delete cascading enabled?
+	 * @param persister The entity persister.
+	 * @param transientEntities A cache of already deleted entities.
+	 */
+	protected final void deleteEntity(
+			final EventSource session,
+			final Object entity,
+			final EntityEntry entityEntry,
+			final boolean isCascadeDeleteEnabled,
+			final EntityPersister persister,
+			final Set transientEntities) {
+
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"deleting " +
+							MessageHelper.infoString( persister, entityEntry.getId(), session.getFactory() )
+			);
+		}
+
+		final PersistenceContext persistenceContext = session.getPersistenceContext();
+		final Type[] propTypes = persister.getPropertyTypes();
+		final Object version = entityEntry.getVersion();
+
+		final Object[] currentState;
+		if ( entityEntry.getLoadedState() == null ) { //ie. the entity came in from update()
+			currentState = persister.getPropertyValues( entity, session.getEntityMode() );
+		}
+		else {
+			currentState = entityEntry.getLoadedState();
+		}
+
+		final Object[] deletedState = createDeletedState( persister, currentState, session );
+		entityEntry.setDeletedState( deletedState );
+
+		session.getInterceptor().onDelete(
+				entity,
+				entityEntry.getId(),
+				deletedState,
+				persister.getPropertyNames(),
+				propTypes
+		);
+
+		// before any callbacks, etc, so subdeletions see that this deletion happened first
+		persistenceContext.setEntryStatus( entityEntry, Status.DELETED );
+		EntityKey key = new EntityKey( entityEntry.getId(), persister, session.getEntityMode() );
+
+		cascadeBeforeDelete( session, persister, entity, entityEntry, transientEntities );
+
+		new ForeignKeys.Nullifier( entity, true, false, session )
+				.nullifyTransientReferences( entityEntry.getDeletedState(), propTypes );
+		new Nullability( session ).checkNullability( entityEntry.getDeletedState(), persister, true );
+		persistenceContext.getNullifiableEntityKeys().add( key );
+
+		// Ensures that containing deletions happen before sub-deletions
+		session.getActionQueue().addAction(
+				new EntityDeleteAction(
+						entityEntry.getId(),
+						deletedState,
+						version,
+						entity,
+						persister,
+						isCascadeDeleteEnabled,
+						session
+				)
+		);
+
+		cascadeAfterDelete( session, persister, entity, transientEntities );
+
+		// the entry will be removed after the flush, and will no longer
+		// override the stale snapshot
+		// This is now handled by removeEntity() in EntityDeleteAction
+		//persistenceContext.removeDatabaseSnapshot(key);
+	}
+
+	private Object[] createDeletedState(EntityPersister persister, Object[] currentState, EventSource session) {
+		Type[] propTypes = persister.getPropertyTypes();
+		final Object[] deletedState = new Object[propTypes.length];
+//		TypeFactory.deepCopy( currentState, propTypes, persister.getPropertyUpdateability(), deletedState, session );
+		boolean[] copyability = new boolean[propTypes.length];
+		java.util.Arrays.fill( copyability, true );
+		TypeFactory.deepCopy( currentState, propTypes, copyability, deletedState, session );
+		return deletedState;
+	}
+
+	protected boolean invokeDeleteLifecycle(EventSource session, Object entity, EntityPersister persister) {
+		if ( persister.implementsLifecycle( session.getEntityMode() ) ) {
+			log.debug( "calling onDelete()" );
+			if ( ( ( Lifecycle ) entity ).onDelete( session ) ) {
+				log.debug( "deletion vetoed by onDelete()" );
+				return true;
+			}
+		}
+		return false;
+	}
+
+	protected void cascadeBeforeDelete(
+			EventSource session,
+			EntityPersister persister,
+			Object entity,
+			EntityEntry entityEntry,
+			Set transientEntities) throws HibernateException {
+
+		CacheMode cacheMode = session.getCacheMode();
+		session.setCacheMode( CacheMode.GET );
+		session.getPersistenceContext().incrementCascadeLevel();
+		try {
+			// cascade-delete to collections BEFORE the collection owner is deleted
+			new Cascade( CascadingAction.DELETE, Cascade.AFTER_INSERT_BEFORE_DELETE, session )
+					.cascade( persister, entity, transientEntities );
+		}
+		finally {
+			session.getPersistenceContext().decrementCascadeLevel();
+			session.setCacheMode( cacheMode );
+		}
+	}
+
+	protected void cascadeAfterDelete(
+			EventSource session,
+			EntityPersister persister,
+			Object entity,
+			Set transientEntities) throws HibernateException {
+
+		CacheMode cacheMode = session.getCacheMode();
+		session.setCacheMode( CacheMode.GET );
+		session.getPersistenceContext().incrementCascadeLevel();
+		try {
+			// cascade-delete to many-to-one AFTER the parent was deleted
+			new Cascade( CascadingAction.DELETE, Cascade.BEFORE_INSERT_AFTER_DELETE, session )
+					.cascade( persister, entity, transientEntities );
+		}
+		finally {
+			session.getPersistenceContext().decrementCascadeLevel();
+			session.setCacheMode( cacheMode );
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultDirtyCheckEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultDirtyCheckEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultDirtyCheckEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+//$Id: DefaultDirtyCheckEventListener.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event.def;
+
+import org.hibernate.HibernateException;
+import org.hibernate.event.DirtyCheckEvent;
+import org.hibernate.event.DirtyCheckEventListener;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Defines the default dirty-check event listener used by hibernate for
+ * checking the session for dirtiness in response to generated dirty-check
+ * events.
+ *
+ * @author Steve Ebersole
+ */
+public class DefaultDirtyCheckEventListener extends AbstractFlushingEventListener implements DirtyCheckEventListener {
+
+	private static final Log log = LogFactory.getLog(DefaultDirtyCheckEventListener.class);
+
+    /** Handle the given dirty-check event.
+     *
+     * @param event The dirty-check event to be handled.
+     * @throws HibernateException
+     */
+	public void onDirtyCheck(DirtyCheckEvent event) throws HibernateException {
+
+		int oldSize = event.getSession().getActionQueue().numberOfCollectionRemovals();
+
+		try {
+			flushEverythingToExecutions(event);
+			boolean wasNeeded = event.getSession().getActionQueue().hasAnyQueuedActions();
+			log.debug( wasNeeded ? "session dirty" : "session not dirty" );
+			event.setDirty( wasNeeded );
+		}
+		finally {
+			event.getSession().getActionQueue().clearFromFlushNeededCheck( oldSize );
+		}
+		
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultEvictEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultEvictEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultEvictEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,100 @@
+//$Id: DefaultEvictEventListener.java 10224 2006-08-04 20:29:45Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.Cascade;
+import org.hibernate.engine.CascadingAction;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.EvictEvent;
+import org.hibernate.event.EvictEventListener;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+
+/**
+ * Defines the default evict event listener used by hibernate for evicting entities
+ * in response to generated flush events.  In particular, this implementation will
+ * remove any hard references to the entity that are held by the infrastructure
+ * (references held by application or other persistent instances are okay)
+ *
+ * @author Steve Ebersole
+ */
+public class DefaultEvictEventListener implements EvictEventListener {
+
+	private static final Log log = LogFactory.getLog(DefaultEvictEventListener.class);
+
+	/** 
+	 * Handle the given evict event.
+	 *
+	 * @param event The evict event to be handled.
+	 * @throws HibernateException
+	 */
+	public void onEvict(EvictEvent event) throws HibernateException {
+		EventSource source = event.getSession();
+		final Object object = event.getObject();
+		final PersistenceContext persistenceContext = source.getPersistenceContext();
+
+		if ( object instanceof HibernateProxy ) {
+			LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer();
+			Serializable id = li.getIdentifier();
+			EntityPersister persister = source.getFactory().getEntityPersister( li.getEntityName() );
+			if ( id == null ) {
+				throw new IllegalArgumentException("null identifier");
+			}
+
+			EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
+			persistenceContext.removeProxy( key );
+
+			if ( !li.isUninitialized() ) {
+				final Object entity = persistenceContext.removeEntity( key );
+				if ( entity != null ) {
+					EntityEntry e = event.getSession().getPersistenceContext().removeEntry( entity );
+					doEvict( entity, key, e.getPersister(), event.getSession() );
+				}
+			}
+			li.setSession( null );
+		}
+		else {
+			EntityEntry e = persistenceContext.removeEntry( object );
+			if ( e != null ) {
+				EntityKey key = new EntityKey( e.getId(), e.getPersister(), source.getEntityMode()  );
+				persistenceContext.removeEntity( key );
+				doEvict( object, key, e.getPersister(), source );
+			}
+		}
+	}
+
+	protected void doEvict(
+		final Object object, 
+		final EntityKey key, 
+		final EntityPersister persister,
+		final EventSource session) 
+	throws HibernateException {
+
+		if ( log.isTraceEnabled() ) {
+			log.trace( "evicting " + MessageHelper.infoString(persister) );
+		}
+
+		// remove all collections for the entity from the session-level cache
+		if ( persister.hasCollections() ) {
+			new EvictVisitor( session ).process( object, persister );
+		}
+
+		// remove any snapshot, not really for memory management purposes, but
+		// rather because it might now be stale, and there is no longer any 
+		// EntityEntry to take precedence
+		// This is now handled by removeEntity()
+		//session.getPersistenceContext().removeDatabaseSnapshot(key);
+
+		new Cascade( CascadingAction.EVICT, Cascade.AFTER_EVICT, session )
+				.cascade( persister, object );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultFlushEntityEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultFlushEntityEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultFlushEntityEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,520 @@
+//$Id: DefaultFlushEntityEventListener.java 10784 2006-11-11 05:13:01Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.action.EntityUpdateAction;
+import org.hibernate.action.DelayedPostInsertIdentifier;
+import org.hibernate.classic.Validatable;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.Nullability;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.Status;
+import org.hibernate.engine.Versioning;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.FlushEntityEvent;
+import org.hibernate.event.FlushEntityEventListener;
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * An event that occurs for each entity instance at flush time
+ *
+ * @author Gavin King
+ */
+public class DefaultFlushEntityEventListener implements FlushEntityEventListener {
+
+	private static final Log log = LogFactory.getLog(DefaultFlushEntityEventListener.class);
+
+	/**
+	 * make sure user didn't mangle the id
+	 */
+	public void checkId(Object object, EntityPersister persister, Serializable id, EntityMode entityMode)
+	throws HibernateException {
+
+		if ( id != null && id instanceof DelayedPostInsertIdentifier ) {
+			// this is a situation where the entity id is assigned by a post-insert generator
+			// and was saved outside the transaction forcing it to be delayed
+			return;
+		}
+
+		if ( persister.canExtractIdOutOfEntity() ) {
+
+			Serializable oid = persister.getIdentifier( object, entityMode );
+			if (id==null) {
+				throw new AssertionFailure("null id in " + persister.getEntityName() + " entry (don't flush the Session after an exception occurs)");
+			}
+			if ( !persister.getIdentifierType().isEqual(id, oid, entityMode) ) {
+				throw new HibernateException(
+						"identifier of an instance of " +
+						persister.getEntityName() +
+						" was altered from " + id +
+						" to " + oid
+					);
+			}
+		}
+
+	}
+
+	private void checkNaturalId(
+			EntityPersister persister,
+	        Serializable identifier,
+	        Object[] current,
+	        Object[] loaded,
+	        EntityMode entityMode,
+	        SessionImplementor session) {
+		if ( persister.hasNaturalIdentifier() ) {
+			if ( loaded == null ) {
+				loaded = session.getPersistenceContext().getNaturalIdSnapshot( identifier, persister );
+			}
+			Type[] types = persister.getPropertyTypes();
+			int[] props = persister.getNaturalIdentifierProperties();
+			boolean[] updateable = persister.getPropertyUpdateability();
+			for ( int i=0; i<props.length; i++ ) {
+				int prop = props[i];
+				if ( !updateable[prop] ) {
+					if ( !types[prop].isEqual( current[prop], loaded[prop], entityMode ) ) {
+						throw new HibernateException(
+								"immutable natural identifier of an instance of " +
+								persister.getEntityName() +
+								" was altered"
+							);
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Flushes a single entity's state to the database, by scheduling
+	 * an update action, if necessary
+	 */
+	public void onFlushEntity(FlushEntityEvent event) throws HibernateException {
+		final Object entity = event.getEntity();
+		final EntityEntry entry = event.getEntityEntry();
+		final EventSource session = event.getSession();
+		final EntityPersister persister = entry.getPersister();
+		final Status status = entry.getStatus();
+		final EntityMode entityMode = session.getEntityMode();
+		final Type[] types = persister.getPropertyTypes();
+
+		final boolean mightBeDirty = entry.requiresDirtyCheck(entity);
+
+		final Object[] values = getValues( entity, entry, entityMode, mightBeDirty, session );
+
+		event.setPropertyValues(values);
+
+		//TODO: avoid this for non-new instances where mightBeDirty==false
+		boolean substitute = wrapCollections( session, persister, types, values);
+
+		if ( isUpdateNecessary( event, mightBeDirty ) ) {
+			substitute = scheduleUpdate( event ) || substitute;
+		}
+
+		if ( status != Status.DELETED ) {
+			// now update the object .. has to be outside the main if block above (because of collections)
+			if (substitute) persister.setPropertyValues( entity, values, entityMode );
+
+			// Search for collections by reachability, updating their role.
+			// We don't want to touch collections reachable from a deleted object
+			if ( persister.hasCollections() ) {
+				new FlushVisitor(session, entity).processEntityPropertyValues(values, types);
+			}
+		}
+
+	}
+
+	private Object[] getValues(
+			Object entity,
+			EntityEntry entry,
+			EntityMode entityMode,
+			boolean mightBeDirty,
+	        SessionImplementor session
+	) {
+		final Object[] loadedState = entry.getLoadedState();
+		final Status status = entry.getStatus();
+		final EntityPersister persister = entry.getPersister();
+
+		final Object[] values;
+		if ( status == Status.DELETED ) {
+			//grab its state saved at deletion
+			values = entry.getDeletedState();
+		}
+		else if ( !mightBeDirty && loadedState!=null ) {
+			values = loadedState;
+		}
+		else {
+			checkId( entity, persister, entry.getId(), entityMode );
+
+			// grab its current state
+			values = persister.getPropertyValues( entity, entityMode );
+
+			checkNaturalId( persister, entry.getId(), values, loadedState, entityMode, session );
+		}
+		return values;
+	}
+
+	private boolean wrapCollections(
+			EventSource session,
+			EntityPersister persister,
+			Type[] types,
+			Object[] values
+	) {
+		if ( persister.hasCollections() ) {
+
+			// wrap up any new collections directly referenced by the object
+			// or its components
+
+			// NOTE: we need to do the wrap here even if its not "dirty",
+			// because collections need wrapping but changes to _them_
+			// don't dirty the container. Also, for versioned data, we
+			// need to wrap before calling searchForDirtyCollections
+
+			WrapVisitor visitor = new WrapVisitor(session);
+			// substitutes into values by side-effect
+			visitor.processEntityPropertyValues(values, types);
+			return visitor.isSubstitutionRequired();
+		}
+		else {
+			return false;
+		}
+	}
+
+	private boolean isUpdateNecessary(final FlushEntityEvent event, final boolean mightBeDirty) {
+		final Status status = event.getEntityEntry().getStatus();
+		if ( mightBeDirty || status==Status.DELETED ) {
+			// compare to cached state (ignoring collections unless versioned)
+			dirtyCheck(event);
+			if ( isUpdateNecessary(event) ) {
+				return true;
+			}
+			else {
+				FieldInterceptionHelper.clearDirty( event.getEntity() );
+				return false;
+			}
+		}
+		else {
+			return hasDirtyCollections( event, event.getEntityEntry().getPersister(), status );
+		}
+	}
+
+	private boolean scheduleUpdate(final FlushEntityEvent event) {
+		
+		final EntityEntry entry = event.getEntityEntry();
+		final EventSource session = event.getSession();
+		final Object entity = event.getEntity();
+		final Status status = entry.getStatus();
+		final EntityMode entityMode = session.getEntityMode();
+		final EntityPersister persister = entry.getPersister();
+		final Object[] values = event.getPropertyValues();
+		
+		if ( log.isTraceEnabled() ) {
+			if ( status == Status.DELETED ) {
+				log.trace(
+						"Updating deleted entity: " +
+						MessageHelper.infoString( persister, entry.getId(), session.getFactory() )
+					);
+			}
+			else {
+				log.trace(
+						"Updating entity: " +
+						MessageHelper.infoString( persister, entry.getId(), session.getFactory()  )
+					);
+			}
+		}
+
+		final boolean intercepted;
+		if ( !entry.isBeingReplicated() ) {
+			// give the Interceptor a chance to process property values, if the properties
+			// were modified by the Interceptor, we need to set them back to the object
+			intercepted = handleInterception( event );
+		}
+		else {
+			intercepted = false;
+		}
+
+		validate( entity, persister, status, entityMode );
+
+		// increment the version number (if necessary)
+		final Object nextVersion = getNextVersion(event);
+
+		// if it was dirtied by a collection only
+		int[] dirtyProperties = event.getDirtyProperties();
+		if ( event.isDirtyCheckPossible() && dirtyProperties == null ) {
+			if ( ! intercepted && !event.hasDirtyCollection() ) {
+				throw new AssertionFailure( "dirty, but no dirty properties" );
+			}
+			dirtyProperties = ArrayHelper.EMPTY_INT_ARRAY;
+		}
+
+		// check nullability but do not perform command execute
+		// we'll use scheduled updates for that.
+		new Nullability(session).checkNullability( values, persister, true );
+
+		// schedule the update
+		// note that we intentionally do _not_ pass in currentPersistentState!
+		session.getActionQueue().addAction(
+				new EntityUpdateAction(
+						entry.getId(),
+						values,
+						dirtyProperties,
+						event.hasDirtyCollection(),
+						entry.getLoadedState(),
+						entry.getVersion(),
+						nextVersion,
+						entity,
+						entry.getRowId(),
+						persister,
+						session
+					)
+			);
+		
+		return intercepted;
+	}
+
+	protected void validate(Object entity, EntityPersister persister, Status status, EntityMode entityMode) {
+		// validate() instances of Validatable
+		if ( status == Status.MANAGED && persister.implementsValidatable( entityMode ) ) {
+			( (Validatable) entity ).validate();
+		}
+	}
+	
+	protected boolean handleInterception(FlushEntityEvent event) {
+		SessionImplementor session = event.getSession();
+		EntityEntry entry = event.getEntityEntry();
+		EntityPersister persister = entry.getPersister();
+		Object entity = event.getEntity();
+		
+		//give the Interceptor a chance to modify property values
+		final Object[] values = event.getPropertyValues();
+		final boolean intercepted = invokeInterceptor( session, entity, entry, values, persister );
+
+		//now we might need to recalculate the dirtyProperties array
+		if ( intercepted && event.isDirtyCheckPossible() && !event.isDirtyCheckHandledByInterceptor() ) {
+			int[] dirtyProperties;
+			if ( event.hasDatabaseSnapshot() ) {
+				dirtyProperties = persister.findModified( event.getDatabaseSnapshot(), values, entity, session );
+			}
+			else {
+				dirtyProperties = persister.findDirty( values, entry.getLoadedState(), entity, session );
+			}
+			event.setDirtyProperties(dirtyProperties);
+		}
+		
+		return intercepted;
+	}
+
+	protected boolean invokeInterceptor(
+			SessionImplementor session,
+			Object entity,
+			EntityEntry entry,
+			final Object[] values,
+			EntityPersister persister) {
+		return session.getInterceptor().onFlushDirty(
+				entity,
+				entry.getId(),
+				values,
+				entry.getLoadedState(),
+				persister.getPropertyNames(),
+				persister.getPropertyTypes()
+		);
+	}
+
+	/**
+	 * Convience method to retreive an entities next version value
+	 */
+	private Object getNextVersion(FlushEntityEvent event) throws HibernateException {
+		
+		EntityEntry entry = event.getEntityEntry();
+		EntityPersister persister = entry.getPersister();
+		if ( persister.isVersioned() ) {
+
+			Object[] values = event.getPropertyValues();
+		    
+			if ( entry.isBeingReplicated() ) {
+				return Versioning.getVersion(values, persister);
+			}
+			else {
+				int[] dirtyProperties = event.getDirtyProperties();
+				
+				final boolean isVersionIncrementRequired = isVersionIncrementRequired( 
+						event, 
+						entry, 
+						persister, 
+						dirtyProperties 
+					);
+				
+				final Object nextVersion = isVersionIncrementRequired ?
+						Versioning.increment( entry.getVersion(), persister.getVersionType(), event.getSession() ) :
+						entry.getVersion(); //use the current version
+						
+				Versioning.setVersion(values, nextVersion, persister);
+				
+				return nextVersion;
+			}
+		}
+		else {
+			return null;
+		}
+		
+	}
+
+	private boolean isVersionIncrementRequired(
+			FlushEntityEvent event, 
+			EntityEntry entry, 
+			EntityPersister persister, 
+			int[] dirtyProperties
+	) {
+		final boolean isVersionIncrementRequired = entry.getStatus()!=Status.DELETED && ( 
+				dirtyProperties==null || 
+				Versioning.isVersionIncrementRequired( 
+						dirtyProperties, 
+						event.hasDirtyCollection(),
+						persister.getPropertyVersionability()
+					) 
+			);
+		return isVersionIncrementRequired;
+	}
+
+	/**
+	 * Performs all necessary checking to determine if an entity needs an SQL update
+	 * to synchronize its state to the database. Modifies the event by side-effect!
+	 * Note: this method is quite slow, avoid calling if possible!
+	 */
+	protected final boolean isUpdateNecessary(FlushEntityEvent event) throws HibernateException {
+
+		EntityPersister persister = event.getEntityEntry().getPersister();
+		Status status = event.getEntityEntry().getStatus();
+		
+		if ( !event.isDirtyCheckPossible() ) {
+			return true;
+		}
+		else {
+			
+			int[] dirtyProperties = event.getDirtyProperties();
+			if ( dirtyProperties!=null && dirtyProperties.length!=0 ) {
+				return true; //TODO: suck into event class
+			}
+			else {
+				return hasDirtyCollections( event, persister, status );
+			}
+			
+		}
+	}
+
+	private boolean hasDirtyCollections(FlushEntityEvent event, EntityPersister persister, Status status) {
+		if ( isCollectionDirtyCheckNecessary(persister, status) ) {
+			DirtyCollectionSearchVisitor visitor = new DirtyCollectionSearchVisitor( 
+					event.getSession(),
+					persister.getPropertyVersionability()
+				);
+			visitor.processEntityPropertyValues( event.getPropertyValues(), persister.getPropertyTypes() );
+			boolean hasDirtyCollections = visitor.wasDirtyCollectionFound();
+			event.setHasDirtyCollection(hasDirtyCollections);
+			return hasDirtyCollections;
+		}
+		else {
+			return false;
+		}
+	}
+
+	private boolean isCollectionDirtyCheckNecessary(EntityPersister persister, Status status) {
+		return status==Status.MANAGED && 
+				persister.isVersioned() && 
+				persister.hasCollections();
+	}
+	
+	/**
+	 * Perform a dirty check, and attach the results to the event
+	 */
+	protected void dirtyCheck(FlushEntityEvent event) throws HibernateException {
+		
+		final Object entity = event.getEntity();
+		final Object[] values = event.getPropertyValues();
+		final SessionImplementor session = event.getSession();
+		final EntityEntry entry = event.getEntityEntry();
+		final EntityPersister persister = entry.getPersister();
+		final Serializable id = entry.getId();
+		final Object[] loadedState = entry.getLoadedState();
+
+		int[] dirtyProperties = session.getInterceptor().findDirty( 
+				entity, 
+				id, 
+				values, 
+				loadedState, 
+				persister.getPropertyNames(), 
+				persister.getPropertyTypes() 
+			);
+		
+		event.setDatabaseSnapshot(null);
+
+		final boolean interceptorHandledDirtyCheck;
+		boolean cannotDirtyCheck;
+		
+		if ( dirtyProperties==null ) {
+			// Interceptor returned null, so do the dirtycheck ourself, if possible
+			interceptorHandledDirtyCheck = false;
+			
+			cannotDirtyCheck = loadedState==null; // object loaded by update()
+			if ( !cannotDirtyCheck ) {
+				// dirty check against the usual snapshot of the entity
+				dirtyProperties = persister.findDirty( values, loadedState, entity, session );
+				
+			}
+			else {
+				// dirty check against the database snapshot, if possible/necessary
+				final Object[] databaseSnapshot = getDatabaseSnapshot(session, persister, id);
+				if ( databaseSnapshot != null ) {
+					dirtyProperties = persister.findModified(databaseSnapshot, values, entity, session);
+					cannotDirtyCheck = false;
+					event.setDatabaseSnapshot(databaseSnapshot);
+				}
+			}
+		}
+		else {
+			// the Interceptor handled the dirty checking
+			cannotDirtyCheck = false;
+			interceptorHandledDirtyCheck = true;
+		}
+		
+		event.setDirtyProperties(dirtyProperties);
+		event.setDirtyCheckHandledByInterceptor(interceptorHandledDirtyCheck);
+		event.setDirtyCheckPossible(!cannotDirtyCheck);
+		
+	}
+
+	private Object[] getDatabaseSnapshot(SessionImplementor session, EntityPersister persister, Serializable id) {
+		if ( persister.isSelectBeforeUpdateRequired() ) {
+			Object[] snapshot = session.getPersistenceContext()
+					.getDatabaseSnapshot(id, persister);
+			if (snapshot==null) {
+				//do we even really need this? the update will fail anyway....
+				if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
+					session.getFactory().getStatisticsImplementor()
+							.optimisticFailure( persister.getEntityName() );
+				}
+				throw new StaleObjectStateException( persister.getEntityName(), id );
+			}
+			else {
+				return snapshot;
+			}
+		}
+		else {
+			//TODO: optimize away this lookup for entities w/o unsaved-value="undefined"
+			EntityKey entityKey = new EntityKey( id, persister, session.getEntityMode() );
+			return session.getPersistenceContext()
+					.getCachedDatabaseSnapshot( entityKey ); 
+		}
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultFlushEntityEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultFlushEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultFlushEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultFlushEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+//$Id: DefaultFlushEventListener.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.event.def;
+
+import org.hibernate.HibernateException;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.FlushEvent;
+import org.hibernate.event.FlushEventListener;
+
+/**
+ * Defines the default flush event listeners used by hibernate for 
+ * flushing session state in response to generated flush events.
+ *
+ * @author Steve Ebersole
+ */
+public class DefaultFlushEventListener extends AbstractFlushingEventListener implements FlushEventListener {
+
+	/** Handle the given flush event.
+	 *
+	 * @param event The flush event to be handled.
+	 * @throws HibernateException
+	 */
+	public void onFlush(FlushEvent event) throws HibernateException {
+		final EventSource source = event.getSession();
+		if ( source.getPersistenceContext().hasNonReadOnlyEntities() ) {
+			
+			flushEverythingToExecutions(event);
+			performExecutions(source);
+			postFlush(source);
+		
+			if ( source.getFactory().getStatistics().isStatisticsEnabled() ) {
+				source.getFactory().getStatisticsImplementor().flush();
+			}
+			
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultInitializeCollectionEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultInitializeCollectionEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultInitializeCollectionEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,150 @@
+//$Id: DefaultInitializeCollectionEventListener.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.cache.entry.CollectionCacheEntry;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.CollectionEntry;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.event.InitializeCollectionEvent;
+import org.hibernate.event.InitializeCollectionEventListener;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.pretty.MessageHelper;
+
+/**
+ * @author Gavin King
+ */
+public class DefaultInitializeCollectionEventListener implements InitializeCollectionEventListener {
+
+	private static final Log log = LogFactory.getLog(DefaultInitializeCollectionEventListener.class);
+
+	/**
+	 * called by a collection that wants to initialize itself
+	 */
+	public void onInitializeCollection(InitializeCollectionEvent event)
+	throws HibernateException {
+
+		PersistentCollection collection = event.getCollection();
+		SessionImplementor source = event.getSession();
+
+		CollectionEntry ce = source.getPersistenceContext().getCollectionEntry(collection);
+		if (ce==null) throw new HibernateException("collection was evicted");
+		if ( !collection.wasInitialized() ) {
+			if ( log.isTraceEnabled() ) {
+				log.trace(
+						"initializing collection " +
+						MessageHelper.collectionInfoString( ce.getLoadedPersister(), ce.getLoadedKey(), source.getFactory() )
+					);
+			}
+
+			log.trace("checking second-level cache");
+			final boolean foundInCache = initializeCollectionFromCache(
+					ce.getLoadedKey(),
+					ce.getLoadedPersister(),
+					collection,
+					source
+				);
+
+			if (foundInCache) {
+				log.trace("collection initialized from cache");
+			}
+			else {
+				log.trace("collection not cached");
+				ce.getLoadedPersister().initialize( ce.getLoadedKey(), source );
+				log.trace("collection initialized");
+
+				if ( source.getFactory().getStatistics().isStatisticsEnabled() ) {
+					source.getFactory().getStatisticsImplementor().fetchCollection( 
+							ce.getLoadedPersister().getRole() 
+						);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Try to initialize a collection from the cache
+	 *
+	 * @param id The id of the collection of initialize
+	 * @param persister The collection persister
+	 * @param collection The collection to initialize
+	 * @param source The originating session
+	 * @return true if we were able to initialize the collection from the cache;
+	 * false otherwise.
+	 */
+	private boolean initializeCollectionFromCache(
+			Serializable id,
+			CollectionPersister persister,
+			PersistentCollection collection,
+			SessionImplementor source) {
+
+		if ( !source.getEnabledFilters().isEmpty() && persister.isAffectedByEnabledFilters( source ) ) {
+			log.trace( "disregarding cached version (if any) of collection due to enabled filters ");
+			return false;
+		}
+
+		final boolean useCache = persister.hasCache() && 
+				source.getCacheMode().isGetEnabled();
+
+		if ( !useCache ) {
+			return false;
+		}
+		else {
+			
+			final SessionFactoryImplementor factory = source.getFactory();
+
+			final CacheKey ck = new CacheKey( 
+					id, 
+					persister.getKeyType(), 
+					persister.getRole(), 
+					source.getEntityMode(), 
+					source.getFactory() 
+				);
+			Object ce = persister.getCacheAccessStrategy().get( ck, source.getTimestamp() );
+			
+			if ( factory.getStatistics().isStatisticsEnabled() ) {
+				if ( ce == null ) {
+					factory.getStatisticsImplementor().secondLevelCacheMiss(
+							persister.getCacheAccessStrategy().getRegion().getName()
+					);
+				}
+				else {
+					factory.getStatisticsImplementor().secondLevelCacheHit(
+							persister.getCacheAccessStrategy().getRegion().getName()
+					);
+				}
+
+				
+			}
+			
+			if (ce==null) {
+				return false;
+			}
+			else {
+
+				CollectionCacheEntry cacheEntry = (CollectionCacheEntry) persister.getCacheEntryStructure()
+						.destructure(ce, factory);
+			
+				final PersistenceContext persistenceContext = source.getPersistenceContext();
+				cacheEntry.assemble(
+						collection, 
+						persister,  
+						persistenceContext.getCollectionOwner(id, persister)
+					);
+				persistenceContext.getCollectionEntry(collection).postInitialize(collection);
+				//addInitializedCollection(collection, persister, id);
+				return true;
+			}
+			
+		}
+	}
+
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultInitializeCollectionEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,607 @@
+//$Id: DefaultLoadEventListener.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.NonUniqueObjectException;
+import org.hibernate.PersistentObjectException;
+import org.hibernate.TypeMismatchException;
+import org.hibernate.EntityMode;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.cache.access.SoftLock;
+import org.hibernate.cache.entry.CacheEntry;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.Status;
+import org.hibernate.engine.TwoPhaseLoad;
+import org.hibernate.engine.Versioning;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.LoadEvent;
+import org.hibernate.event.LoadEventListener;
+import org.hibernate.event.PostLoadEvent;
+import org.hibernate.event.PostLoadEventListener;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * Defines the default load event listeners used by hibernate for loading entities
+ * in response to generated load events.
+ *
+ * @author Steve Ebersole
+ */
+public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener implements LoadEventListener {
+
+	public static final Object REMOVED_ENTITY_MARKER = new Object();
+	public static final Object INCONSISTENT_RTN_CLASS_MARKER = new Object();
+	public static final LockMode DEFAULT_LOCK_MODE = LockMode.NONE;
+
+	private static final Log log = LogFactory.getLog(DefaultLoadEventListener.class);
+
+
+	/**
+	 * Handle the given load event.
+	 *
+	 * @param event The load event to be handled.
+	 * @throws HibernateException
+	 */
+	public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType) throws HibernateException {
+
+		final SessionImplementor source = event.getSession();
+
+		EntityPersister persister;
+		if ( event.getInstanceToLoad() != null ) {
+			persister = source.getEntityPersister( null, event.getInstanceToLoad() ); //the load() which takes an entity does not pass an entityName
+			event.setEntityClassName( event.getInstanceToLoad().getClass().getName() );
+		}
+		else {
+			persister = source.getFactory().getEntityPersister( event.getEntityClassName() );
+		}
+
+		if ( persister == null ) {
+			throw new HibernateException(
+					"Unable to locate persister: " +
+					event.getEntityClassName()
+				);
+		}
+
+		if ( persister.getIdentifierType().isComponentType() && EntityMode.DOM4J == event.getSession().getEntityMode() ) {
+			// skip this check for composite-ids relating to dom4j entity-mode;
+			// alternatively, we could add a check to make sure the incoming id value is
+			// an instance of Element...
+		}
+		else {
+			Class idClass = persister.getIdentifierType().getReturnedClass();
+			if ( idClass != null && ! idClass.isInstance( event.getEntityId() ) ) {
+				throw new TypeMismatchException(
+						"Provided id of the wrong type. Expected: " + idClass + ", got " + event.getEntityId().getClass()
+				);
+			}
+		}
+
+		EntityKey keyToLoad = new EntityKey( event.getEntityId(), persister, source.getEntityMode()  );
+
+		try {
+			if ( loadType.isNakedEntityReturned() ) {
+				//do not return a proxy!
+				//(this option indicates we are initializing a proxy)
+				event.setResult( load(event, persister, keyToLoad, loadType) );
+			}
+			else {
+				//return a proxy if appropriate
+				if ( event.getLockMode() == LockMode.NONE ) {
+					event.setResult( proxyOrLoad(event, persister, keyToLoad, loadType) );
+				}
+				else {
+					event.setResult( lockAndLoad(event, persister, keyToLoad, loadType, source) );
+				}
+			}
+		}
+		catch(HibernateException e) {
+			log.info("Error performing load command", e);
+			throw e;
+		}
+	}
+
+	/**
+	 * Perfoms the load of an entity.
+	 *
+	 * @param event The initiating load request event
+	 * @param persister The persister corresponding to the entity to be loaded
+	 * @param keyToLoad The key of the entity to be loaded
+	 * @param options The defined load options
+	 * @return The loaded entity.
+	 * @throws HibernateException
+	 */
+	protected Object load(
+		final LoadEvent event,
+		final EntityPersister persister,
+		final EntityKey keyToLoad,
+		final LoadEventListener.LoadType options) {
+
+		if ( event.getInstanceToLoad() != null ) {
+			if ( event.getSession().getPersistenceContext().getEntry( event.getInstanceToLoad() ) != null ) {
+				throw new PersistentObjectException(
+						"attempted to load into an instance that was already associated with the session: " +
+						MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
+					);
+			}
+			persister.setIdentifier( event.getInstanceToLoad(), event.getEntityId(), event.getSession().getEntityMode() );
+		}
+
+		Object entity = doLoad(event, persister, keyToLoad, options);
+
+		boolean isOptionalInstance = event.getInstanceToLoad() != null;
+
+		if ( !options.isAllowNulls() || isOptionalInstance ) {
+			if ( entity == null ) {
+				event.getSession().getFactory().getEntityNotFoundDelegate().handleEntityNotFound( event.getEntityClassName(), event.getEntityId() );
+			}
+		}
+
+		if ( isOptionalInstance && entity != event.getInstanceToLoad() ) {
+			throw new NonUniqueObjectException( event.getEntityId(), event.getEntityClassName() );
+		}
+
+		return entity;
+	}
+
+	/**
+	 * Based on configured options, will either return a pre-existing proxy,
+	 * generate a new proxy, or perform an actual load.
+	 *
+	 * @param event The initiating load request event
+	 * @param persister The persister corresponding to the entity to be loaded
+	 * @param keyToLoad The key of the entity to be loaded
+	 * @param options The defined load options
+	 * @return The result of the proxy/load operation.
+	 */
+	protected Object proxyOrLoad(
+		final LoadEvent event,
+		final EntityPersister persister,
+		final EntityKey keyToLoad,
+		final LoadEventListener.LoadType options) {
+
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"loading entity: " +
+					MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
+				);
+		}
+
+		if ( !persister.hasProxy() ) {
+			// this class has no proxies (so do a shortcut)
+			return load(event, persister, keyToLoad, options);
+		}
+		else {
+			final PersistenceContext persistenceContext = event.getSession().getPersistenceContext();
+
+			// look for a proxy
+			Object proxy = persistenceContext.getProxy(keyToLoad);
+			if ( proxy != null ) {
+				return returnNarrowedProxy( event, persister, keyToLoad, options, persistenceContext, proxy );
+			}
+			else {
+				if ( options.isAllowProxyCreation() ) {
+					return createProxyIfNecessary( event, persister, keyToLoad, options, persistenceContext );
+				}
+				else {
+					// return a newly loaded object
+					return load(event, persister, keyToLoad, options);
+				}
+			}
+
+		}
+	}
+
+	/**
+	 * Given a proxy, initialize it and/or narrow it provided either
+	 * is necessary.
+	 *
+	 * @param event The initiating load request event
+	 * @param persister The persister corresponding to the entity to be loaded
+	 * @param keyToLoad The key of the entity to be loaded
+	 * @param options The defined load options
+	 * @param persistenceContext The originating session
+	 * @param proxy The proxy to narrow
+	 * @return The created/existing proxy
+	 */
+	private Object returnNarrowedProxy(
+			final LoadEvent event,
+			final EntityPersister persister,
+			final EntityKey keyToLoad,
+			final LoadEventListener.LoadType options,
+			final PersistenceContext persistenceContext,
+			final Object proxy) {
+		log.trace("entity proxy found in session cache");
+		LazyInitializer li = ( (HibernateProxy) proxy ).getHibernateLazyInitializer();
+		if ( li.isUnwrap() ) {
+			return li.getImplementation();
+		}
+		Object impl = null;
+		if ( !options.isAllowProxyCreation() ) {
+			impl = load( event, persister, keyToLoad, options );
+			if ( impl == null ) {
+				event.getSession().getFactory().getEntityNotFoundDelegate().handleEntityNotFound( persister.getEntityName(), keyToLoad.getIdentifier());
+			}
+		}
+		return persistenceContext.narrowProxy( proxy, persister, keyToLoad, impl );
+	}
+
+	/**
+	 * If there is already a corresponding proxy associated with the
+	 * persistence context, return it; otherwise create a proxy, associate it
+	 * with the persistence context, and return the just-created proxy.
+	 *
+	 * @param event The initiating load request event
+	 * @param persister The persister corresponding to the entity to be loaded
+	 * @param keyToLoad The key of the entity to be loaded
+	 * @param options The defined load options
+	 * @param persistenceContext The originating session
+	 * @return The created/existing proxy
+	 */
+	private Object createProxyIfNecessary(
+			final LoadEvent event,
+			final EntityPersister persister,
+			final EntityKey keyToLoad,
+			final LoadEventListener.LoadType options,
+			final PersistenceContext persistenceContext) {
+		Object existing = persistenceContext.getEntity( keyToLoad );
+		if ( existing != null ) {
+			// return existing object or initialized proxy (unless deleted)
+			log.trace( "entity found in session cache" );
+			if ( options.isCheckDeleted() ) {
+				EntityEntry entry = persistenceContext.getEntry( existing );
+				Status status = entry.getStatus();
+				if ( status == Status.DELETED || status == Status.GONE ) {
+					return null;
+				}
+			}
+			return existing;
+		}
+		else {
+			log.trace( "creating new proxy for entity" );
+			// return new uninitialized proxy
+			Object proxy = persister.createProxy( event.getEntityId(), event.getSession() );
+			persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey(keyToLoad);
+			persistenceContext.addProxy(keyToLoad, proxy);
+			return proxy;
+		}
+	}
+
+	/**
+	 * If the class to be loaded has been configured with a cache, then lock
+	 * given id in that cache and then perform the load.
+	 *
+	 * @param event The initiating load request event
+	 * @param persister The persister corresponding to the entity to be loaded
+	 * @param keyToLoad The key of the entity to be loaded
+	 * @param options The defined load options
+	 * @param source The originating session
+	 * @return The loaded entity
+	 * @throws HibernateException
+	 */
+	protected Object lockAndLoad(
+			final LoadEvent event,
+			final EntityPersister persister,
+			final EntityKey keyToLoad,
+			final LoadEventListener.LoadType options,
+			final SessionImplementor source) {
+		SoftLock lock = null;
+		final CacheKey ck;
+		if ( persister.hasCache() ) {
+			ck = new CacheKey(
+					event.getEntityId(),
+					persister.getIdentifierType(),
+					persister.getRootEntityName(),
+					source.getEntityMode(),
+					source.getFactory()
+			);
+			lock = persister.getCacheAccessStrategy().lockItem( ck, null );
+		}
+		else {
+			ck = null;
+		}
+
+		Object entity;
+		try {
+			entity = load(event, persister, keyToLoad, options);
+		}
+		finally {
+			if ( persister.hasCache() ) {
+				persister.getCacheAccessStrategy().unlockItem( ck, lock );
+			}
+		}
+
+		return event.getSession().getPersistenceContext().proxyFor( persister, keyToLoad, entity );
+	}
+
+
+	/**
+	 * Coordinates the efforts to load a given entity.  First, an attempt is
+	 * made to load the entity from the session-level cache.  If not found there,
+	 * an attempt is made to locate it in second-level cache.  Lastly, an
+	 * attempt is made to load it directly from the datasource.
+	 *
+	 * @param event The load event
+	 * @param persister The persister for the entity being requested for load
+	 * @param keyToLoad The EntityKey representing the entity to be loaded.
+	 * @param options The load options.
+	 * @return The loaded entity, or null.
+	 */
+	protected Object doLoad(
+			final LoadEvent event,
+			final EntityPersister persister,
+			final EntityKey keyToLoad,
+			final LoadEventListener.LoadType options) {
+
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"attempting to resolve: " +
+					MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
+				);
+		}
+
+		Object entity = loadFromSessionCache( event, keyToLoad, options );
+		if ( entity == REMOVED_ENTITY_MARKER ) {
+			log.debug( "load request found matching entity in context, but it is scheduled for removal; returning null" );
+			return null;
+		}
+		if ( entity == INCONSISTENT_RTN_CLASS_MARKER ) {
+			log.debug( "load request found matching entity in context, but the matched entity was of an inconsistent return type; returning null" );
+			return null;
+		}
+		if ( entity != null ) {
+			if ( log.isTraceEnabled() ) {
+				log.trace(
+						"resolved object in session cache: " +
+						MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory()  )
+					);
+			}
+			return entity;
+		}
+
+		entity = loadFromSecondLevelCache(event, persister, options);
+		if ( entity != null ) {
+			if ( log.isTraceEnabled() ) {
+				log.trace(
+						"resolved object in second-level cache: " +
+						MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
+					);
+			}
+			return entity;
+		}
+
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"object not resolved in any cache: " +
+					MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
+				);
+		}
+
+		return loadFromDatasource(event, persister, keyToLoad, options);
+	}
+
+	/**
+	 * Performs the process of loading an entity from the configured
+	 * underlying datasource.
+	 *
+	 * @param event The load event
+	 * @param persister The persister for the entity being requested for load
+	 * @param keyToLoad The EntityKey representing the entity to be loaded.
+	 * @param options The load options.
+	 * @return The object loaded from the datasource, or null if not found.
+	 */
+	protected Object loadFromDatasource(
+			final LoadEvent event,
+			final EntityPersister persister,
+			final EntityKey keyToLoad,
+			final LoadEventListener.LoadType options) {
+		final SessionImplementor source = event.getSession();
+		Object entity = persister.load(
+				event.getEntityId(),
+				event.getInstanceToLoad(),
+				event.getLockMode(),
+				source
+		);
+
+		if ( event.isAssociationFetch() && source.getFactory().getStatistics().isStatisticsEnabled() ) {
+			source.getFactory().getStatisticsImplementor().fetchEntity( event.getEntityClassName() );
+		}
+
+		return entity;
+	}
+
+	/**
+	 * Attempts to locate the entity in the session-level cache.
+	 * <p/>
+	 * If allowed to return nulls, then if the entity happens to be found in
+	 * the session cache, we check the entity type for proper handling
+	 * of entity hierarchies.
+	 * <p/>
+	 * If checkDeleted was set to true, then if the entity is found in the
+	 * session-level cache, it's current status within the session cache
+	 * is checked to see if it has previously been scheduled for deletion.
+	 *
+	 * @param event The load event
+	 * @param keyToLoad The EntityKey representing the entity to be loaded.
+	 * @param options The load options.
+	 * @return The entity from the session-level cache, or null.
+	 * @throws HibernateException Generally indicates problems applying a lock-mode.
+	 */
+	protected Object loadFromSessionCache(
+			final LoadEvent event,
+			final EntityKey keyToLoad,
+			final LoadEventListener.LoadType options) throws HibernateException {
+
+		SessionImplementor session = event.getSession();
+		Object old = session.getEntityUsingInterceptor( keyToLoad );
+
+		if ( old != null ) {
+			// this object was already loaded
+			EntityEntry oldEntry = session.getPersistenceContext().getEntry( old );
+			if ( options.isCheckDeleted() ) {
+				Status status = oldEntry.getStatus();
+				if ( status == Status.DELETED || status == Status.GONE ) {
+					return REMOVED_ENTITY_MARKER;
+				}
+			}
+			if ( options.isAllowNulls() ) {
+				EntityPersister persister = event.getSession().getFactory().getEntityPersister( event.getEntityClassName() );
+				if ( ! persister.isInstance( old, event.getSession().getEntityMode() ) ) {
+					return INCONSISTENT_RTN_CLASS_MARKER;
+				}
+			}
+			upgradeLock( old, oldEntry, event.getLockMode(), session );
+		}
+
+		return old;
+	}
+
+	/**
+	 * Attempts to load the entity from the second-level cache.
+	 *
+	 * @param event The load event
+	 * @param persister The persister for the entity being requested for load
+	 * @param options The load options.
+	 * @return The entity from the second-level cache, or null.
+	 */
+	protected Object loadFromSecondLevelCache(
+			final LoadEvent event,
+			final EntityPersister persister,
+			final LoadEventListener.LoadType options) {
+
+		final SessionImplementor source = event.getSession();
+
+		final boolean useCache = persister.hasCache()
+				&& source.getCacheMode().isGetEnabled()
+				&& event.getLockMode().lessThan(LockMode.READ);
+
+		if ( useCache ) {
+
+			final SessionFactoryImplementor factory = source.getFactory();
+
+			final CacheKey ck = new CacheKey(
+					event.getEntityId(),
+					persister.getIdentifierType(),
+					persister.getRootEntityName(),
+					source.getEntityMode(),
+					source.getFactory()
+			);
+			Object ce = persister.getCacheAccessStrategy().get( ck, source.getTimestamp() );
+			if ( factory.getStatistics().isStatisticsEnabled() ) {
+				if ( ce == null ) {
+					factory.getStatisticsImplementor().secondLevelCacheMiss(
+							persister.getCacheAccessStrategy().getRegion().getName()
+					);
+				}
+				else {
+					factory.getStatisticsImplementor().secondLevelCacheHit(
+							persister.getCacheAccessStrategy().getRegion().getName()
+					);
+				}
+			}
+
+			if ( ce != null ) {
+				CacheEntry entry = (CacheEntry) persister.getCacheEntryStructure().destructure( ce, factory );
+
+				// Entity was found in second-level cache...
+				return assembleCacheEntry(
+						entry,
+						event.getEntityId(),
+						persister,
+						event
+				);
+			}
+		}
+
+		return null;
+	}
+
+	private Object assembleCacheEntry(
+			final CacheEntry entry,
+			final Serializable id,
+			final EntityPersister persister,
+			final LoadEvent event) throws HibernateException {
+
+		final Object optionalObject = event.getInstanceToLoad();
+		final EventSource session = event.getSession();
+		final SessionFactoryImplementor factory = session.getFactory();
+
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"assembling entity from second-level cache: " +
+					MessageHelper.infoString( persister, id, factory )
+				);
+		}
+
+		EntityPersister subclassPersister = factory.getEntityPersister( entry.getSubclass() );
+		Object result = optionalObject == null ?
+				session.instantiate( subclassPersister, id ) : optionalObject;
+
+		// make it circular-reference safe
+		TwoPhaseLoad.addUninitializedCachedEntity(
+				new EntityKey( id, subclassPersister, session.getEntityMode() ),
+				result,
+				subclassPersister,
+				LockMode.NONE,
+				entry.areLazyPropertiesUnfetched(),
+				entry.getVersion(),
+				session
+			);
+
+		Type[] types = subclassPersister.getPropertyTypes();
+		Object[] values = entry.assemble( result, id, subclassPersister, session.getInterceptor(), session ); // intializes result by side-effect
+		TypeFactory.deepCopy(
+				values,
+				types,
+				subclassPersister.getPropertyUpdateability(),
+				values,
+				session
+			);
+
+		Object version = Versioning.getVersion( values, subclassPersister );
+		if ( log.isTraceEnabled() ) log.trace( "Cached Version: " + version );
+
+		final PersistenceContext persistenceContext = session.getPersistenceContext();
+		persistenceContext.addEntry(
+				result,
+				Status.MANAGED,
+				values,
+				null,
+				id,
+				version,
+				LockMode.NONE,
+				true,
+				subclassPersister,
+				false,
+				entry.areLazyPropertiesUnfetched()
+			);
+		subclassPersister.afterInitialize( result, entry.areLazyPropertiesUnfetched(), session );
+		persistenceContext.initializeNonLazyCollections();
+		// upgrade the lock if necessary:
+		//lock(result, lockMode);
+
+		//PostLoad is needed for EJB3
+		//TODO: reuse the PostLoadEvent...
+		PostLoadEvent postLoadEvent = new PostLoadEvent(session).setEntity(result)
+				.setId(id).setPersister(persister);
+		PostLoadEventListener[] listeners = session.getListeners().getPostLoadEventListeners();
+		for ( int i = 0; i < listeners.length; i++ ) {
+			listeners[i].onPostLoad(postLoadEvent);
+		}
+
+		return result;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultLockEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultLockEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultLockEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,79 @@
+//$Id: DefaultLockEventListener.java 7019 2005-06-05 05:09:58Z oneovthafew $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.TransientObjectException;
+import org.hibernate.engine.Cascade;
+import org.hibernate.engine.CascadingAction;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.ForeignKeys;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.LockEvent;
+import org.hibernate.event.LockEventListener;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Defines the default lock event listeners used by hibernate to lock entities
+ * in response to generated lock events.
+ *
+ * @author Steve Ebersole
+ */
+public class DefaultLockEventListener extends AbstractLockUpgradeEventListener implements LockEventListener {
+
+	/** Handle the given lock event.
+	 *
+	 * @param event The lock event to be handled.
+	 * @throws HibernateException
+	 */
+	public void onLock(LockEvent event) throws HibernateException {
+
+		if ( event.getObject() == null ) {
+			throw new NullPointerException( "attempted to lock null" );
+		}
+
+		if ( event.getLockMode() == LockMode.WRITE ) {
+			throw new HibernateException( "Invalid lock mode for lock()" );
+		}
+
+		SessionImplementor source = event.getSession();
+		
+		Object entity = source.getPersistenceContext().unproxyAndReassociate( event.getObject() );
+		//TODO: if object was an uninitialized proxy, this is inefficient,
+		//      resulting in two SQL selects
+		
+		EntityEntry entry = source.getPersistenceContext().getEntry(entity);
+		if (entry==null) {
+			final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
+			final Serializable id = persister.getIdentifier( entity, source.getEntityMode() );
+			if ( !ForeignKeys.isNotTransient( event.getEntityName(), entity, Boolean.FALSE, source ) ) {
+				throw new TransientObjectException(
+						"cannot lock an unsaved transient instance: " +
+						persister.getEntityName()
+				);
+			}
+
+			entry = reassociate(event, entity, id, persister);
+			
+			cascadeOnLock(event, persister, entity);
+		}
+
+		upgradeLock( entity, entry, event.getLockMode(), source );
+	}
+	
+	private void cascadeOnLock(LockEvent event, EntityPersister persister, Object entity) {
+		EventSource source = event.getSession();
+		source.getPersistenceContext().incrementCascadeLevel();
+		try {
+			new Cascade(CascadingAction.LOCK, Cascade.AFTER_LOCK, source)
+					.cascade( persister, entity, event.getLockMode() );
+		}
+		finally {
+			source.getPersistenceContext().decrementCascadeLevel();
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultMergeEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultMergeEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultMergeEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,440 @@
+//$Id: DefaultMergeEventListener.java 10784 2006-11-11 05:13:01Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.ObjectDeletedException;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.WrongClassException;
+import org.hibernate.engine.Cascade;
+import org.hibernate.engine.CascadingAction;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.MergeEvent;
+import org.hibernate.event.MergeEventListener;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.intercept.FieldInterceptor;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+import org.hibernate.type.ForeignKeyDirection;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.IdentityMap;
+
+/**
+ * Defines the default copy event listener used by hibernate for copying entities
+ * in response to generated copy events.
+ *
+ * @author Gavin King
+ */
+public class DefaultMergeEventListener extends AbstractSaveEventListener 
+	implements MergeEventListener {
+
+	private static final Log log = LogFactory.getLog(DefaultMergeEventListener.class);
+	
+	protected Map getMergeMap(Object anything) {
+		return IdentityMap.invert( (Map) anything );
+	}
+
+	/** 
+	 * Handle the given merge event.
+	 *
+	 * @param event The merge event to be handled.
+	 * @throws HibernateException
+	 */
+	public void onMerge(MergeEvent event) throws HibernateException {
+		onMerge( event, IdentityMap.instantiate(10) );
+	}
+
+	/** 
+	 * Handle the given merge event.
+	 *
+	 * @param event The merge event to be handled.
+	 * @throws HibernateException
+	 */
+	public void onMerge(MergeEvent event, Map copyCache) throws HibernateException {
+
+		final EventSource source = event.getSession();
+		final Object original = event.getOriginal();
+
+		if ( original != null ) {
+
+			final Object entity;
+			if ( original instanceof HibernateProxy ) {
+				LazyInitializer li = ( (HibernateProxy) original ).getHibernateLazyInitializer();
+				if ( li.isUninitialized() ) {
+					log.trace("ignoring uninitialized proxy");
+					event.setResult( source.load( li.getEntityName(), li.getIdentifier() ) );
+					return; //EARLY EXIT!
+				}
+				else {
+					entity = li.getImplementation();
+				}
+			}
+			else {
+				entity = original;
+			}
+			
+			if ( copyCache.containsKey(entity) ) {
+				log.trace("already merged");
+				event.setResult(entity);
+			}
+			else {
+
+				event.setEntity( entity );
+
+				int entityState = -1;
+
+				// Check the persistence context for an entry relating to this
+				// entity to be merged...
+				EntityEntry entry = source.getPersistenceContext().getEntry( entity );
+				if ( entry == null ) {
+					EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
+					Serializable id = persister.getIdentifier( entity, source.getEntityMode() );
+					if ( id != null ) {
+						EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
+						Object managedEntity = source.getPersistenceContext().getEntity( key );
+						entry = source.getPersistenceContext().getEntry( managedEntity );
+						if ( entry != null ) {
+							// we have specialized case of a detached entity from the
+							// perspective of the merge operation.  Specifically, we
+							// have an incoming entity instance which has a corresponding
+							// entry in the current persistence context, but registered
+							// under a different entity instance
+							entityState = DETACHED;
+						}
+					}
+				}
+
+				if ( entityState == -1 ) {
+					entityState = getEntityState( entity, event.getEntityName(), entry, source );
+				}
+
+				switch (entityState) {
+					case DETACHED:
+						entityIsDetached(event, copyCache);
+						break;
+					case TRANSIENT:
+						entityIsTransient(event, copyCache);
+						break;
+					case PERSISTENT:
+						entityIsPersistent(event, copyCache);
+						break;
+					default: //DELETED
+						throw new ObjectDeletedException( 
+								"deleted instance passed to merge", 
+								null, 
+								getLoggableName( event.getEntityName(), entity )
+							);			
+				}
+			}
+			
+		}
+		
+	}
+
+	protected void entityIsPersistent(MergeEvent event, Map copyCache) {
+		log.trace("ignoring persistent instance");
+		
+		//TODO: check that entry.getIdentifier().equals(requestedId)
+		
+		final Object entity = event.getEntity();
+		final EventSource source = event.getSession();
+		final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
+		
+		copyCache.put(entity, entity); //before cascade!
+		
+		cascadeOnMerge(source, persister, entity, copyCache);
+		copyValues(persister, entity, entity, source, copyCache);
+		
+		event.setResult(entity);
+	}
+	
+	protected void entityIsTransient(MergeEvent event, Map copyCache) {
+		
+		log.trace("merging transient instance");
+		
+		final Object entity = event.getEntity();
+		final EventSource source = event.getSession();
+
+		final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
+		final String entityName = persister.getEntityName();
+		
+		final Serializable id = persister.hasIdentifierProperty() ?
+				persister.getIdentifier( entity, source.getEntityMode() ) :
+		        null;
+
+		final Object copy = persister.instantiate( id, source.getEntityMode() );  //TODO: should this be Session.instantiate(Persister, ...)?
+		copyCache.put(entity, copy); //before cascade!
+		
+		// cascade first, so that all unsaved objects get their 
+		// copy created before we actually copy
+		//cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE);
+		super.cascadeBeforeSave(source, persister, entity, copyCache);
+		copyValues(persister, entity, copy, source, copyCache, ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT);
+		
+		//this bit is only *really* absolutely necessary for handling 
+		//requestedId, but is also good if we merge multiple object 
+		//graphs, since it helps ensure uniqueness
+		final Serializable requestedId = event.getRequestedId();
+		if (requestedId==null) {
+			saveWithGeneratedId( copy, entityName, copyCache, source, false );
+		}
+		else {
+			saveWithRequestedId( copy, requestedId, entityName, copyCache, source );
+		}
+		
+		// cascade first, so that all unsaved objects get their 
+		// copy created before we actually copy
+		super.cascadeAfterSave(source, persister, entity, copyCache);
+		copyValues(persister, entity, copy, source, copyCache, ForeignKeyDirection.FOREIGN_KEY_TO_PARENT);
+		
+		event.setResult(copy);
+
+	}
+
+	protected void entityIsDetached(MergeEvent event, Map copyCache) {
+		
+		log.trace("merging detached instance");
+		
+		final Object entity = event.getEntity();
+		final EventSource source = event.getSession();
+
+		final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
+		final String entityName = persister.getEntityName();
+			
+		Serializable id = event.getRequestedId();
+		if ( id == null ) {
+			id = persister.getIdentifier( entity, source.getEntityMode() );
+		}
+		else {
+			// check that entity id = requestedId
+			Serializable entityId = persister.getIdentifier( entity, source.getEntityMode() );
+			if ( !persister.getIdentifierType().isEqual( id, entityId, source.getEntityMode(), source.getFactory() ) ) {
+				throw new HibernateException( "merge requested with id not matching id of passed entity" );
+			}
+		}
+		
+		String previousFetchProfile = source.getFetchProfile();
+		source.setFetchProfile("merge");
+		//we must clone embedded composite identifiers, or 
+		//we will get back the same instance that we pass in
+		final Serializable clonedIdentifier = (Serializable) persister.getIdentifierType()
+				.deepCopy( id, source.getEntityMode(), source.getFactory() );
+		final Object result = source.get(entityName, clonedIdentifier);
+		source.setFetchProfile(previousFetchProfile);
+		
+		if ( result == null ) {
+			//TODO: we should throw an exception if we really *know* for sure  
+			//      that this is a detached instance, rather than just assuming
+			//throw new StaleObjectStateException(entityName, id);
+			
+			// we got here because we assumed that an instance
+			// with an assigned id was detached, when it was
+			// really persistent
+			entityIsTransient(event, copyCache);
+		}
+		else {
+			copyCache.put(entity, result); //before cascade!
+	
+			final Object target = source.getPersistenceContext().unproxy(result);
+			if ( target == entity ) {
+				throw new AssertionFailure("entity was not detached");
+			}
+			else if ( !source.getEntityName(target).equals(entityName) ) {
+				throw new WrongClassException(
+						"class of the given object did not match class of persistent copy",
+						event.getRequestedId(),
+						entityName
+					);
+			}
+			else if ( isVersionChanged( entity, source, persister, target ) ) {
+				if ( source.getFactory().getStatistics().isStatisticsEnabled() ) {
+					source.getFactory().getStatisticsImplementor()
+							.optimisticFailure( entityName );
+				}
+				throw new StaleObjectStateException( entityName, id );
+			}
+	
+			// cascade first, so that all unsaved objects get their 
+			// copy created before we actually copy
+			cascadeOnMerge(source, persister, entity, copyCache);
+			copyValues(persister, entity, target, source, copyCache);
+			
+			//copyValues works by reflection, so explicitly mark the entity instance dirty
+			markInterceptorDirty( entity, target );
+			
+			event.setResult(result);
+		}
+
+	}
+
+	private void markInterceptorDirty(final Object entity, final Object target) {
+		if ( FieldInterceptionHelper.isInstrumented( entity ) ) {
+			FieldInterceptor interceptor = FieldInterceptionHelper.extractFieldInterceptor( target );
+			if ( interceptor != null ) {
+				interceptor.dirty();
+			}
+		}
+	}
+
+	private boolean isVersionChanged(Object entity, EventSource source, EntityPersister persister, Object target) {
+		if ( ! persister.isVersioned() ) {
+			return false;
+		}
+		// for merging of versioned entities, we consider the version having
+		// been changed only when:
+		// 1) the two version values are different;
+		//      *AND*
+		// 2) The target actually represents database state!
+		//
+		// This second condition is a special case which allows
+		// an entity to be merged during the same transaction
+		// (though during a seperate operation) in which it was
+		// originally persisted/saved
+		boolean changed = ! persister.getVersionType().isSame(
+				persister.getVersion( target, source.getEntityMode() ),
+				persister.getVersion( entity, source.getEntityMode() ),
+				source.getEntityMode()
+		);
+
+		// TODO : perhaps we should additionally require that the incoming entity
+		// version be equivalent to the defined unsaved-value?
+		return changed && existsInDatabase( target, source, persister );
+	}
+
+	private boolean existsInDatabase(Object entity, EventSource source, EntityPersister persister) {
+		EntityEntry entry = source.getPersistenceContext().getEntry( entity );
+		if ( entry == null ) {
+			Serializable id = persister.getIdentifier( entity, source.getEntityMode() );
+			if ( id != null ) {
+				EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
+				Object managedEntity = source.getPersistenceContext().getEntity( key );
+				entry = source.getPersistenceContext().getEntry( managedEntity );
+			}
+		}
+
+		if ( entry == null ) {
+			// perhaps this should be an exception since it is only ever used
+			// in the above method?
+			return false;
+		}
+		else {
+			return entry.isExistsInDatabase();
+		}
+	}
+
+	protected void copyValues(
+		final EntityPersister persister, 
+		final Object entity, 
+		final Object target, 
+		final SessionImplementor source,
+		final Map copyCache
+	) {
+		
+		final Object[] copiedValues = TypeFactory.replace(
+				persister.getPropertyValues( entity, source.getEntityMode() ),
+				persister.getPropertyValues( target, source.getEntityMode() ),
+				persister.getPropertyTypes(),
+				source,
+				target, 
+				copyCache
+			);
+
+		persister.setPropertyValues( target, copiedValues, source.getEntityMode() );
+	}
+
+	protected void copyValues(
+			final EntityPersister persister,
+			final Object entity,
+			final Object target,
+			final SessionImplementor source,
+			final Map copyCache,
+			final ForeignKeyDirection foreignKeyDirection) {
+
+		final Object[] copiedValues;
+
+		if ( foreignKeyDirection == ForeignKeyDirection.FOREIGN_KEY_TO_PARENT ) {
+			// this is the second pass through on a merge op, so here we limit the
+			// replacement to associations types (value types were already replaced
+			// during the first pass)
+			copiedValues = TypeFactory.replaceAssociations(
+					persister.getPropertyValues( entity, source.getEntityMode() ),
+					persister.getPropertyValues( target, source.getEntityMode() ),
+					persister.getPropertyTypes(),
+					source,
+					target,
+					copyCache,
+					foreignKeyDirection
+			);
+		}
+		else {
+			copiedValues = TypeFactory.replace(
+					persister.getPropertyValues( entity, source.getEntityMode() ),
+					persister.getPropertyValues( target, source.getEntityMode() ),
+					persister.getPropertyTypes(),
+					source,
+					target,
+					copyCache,
+					foreignKeyDirection
+			);
+		}
+
+		persister.setPropertyValues( target, copiedValues, source.getEntityMode() );
+	}
+
+	/** 
+	 * Perform any cascades needed as part of this copy event.
+	 *
+	 * @param source The merge event being processed.
+	 * @param persister The persister of the entity being copied.
+	 * @param entity The entity being copied.
+	 * @param copyCache A cache of already copied instance.
+	 */
+	protected void cascadeOnMerge(
+		final EventSource source,
+		final EntityPersister persister,
+		final Object entity,
+		final Map copyCache
+	) {
+		source.getPersistenceContext().incrementCascadeLevel();
+		try {
+			new Cascade( getCascadeAction(), Cascade.BEFORE_MERGE, source )
+					.cascade(persister, entity, copyCache);
+		}
+		finally {
+			source.getPersistenceContext().decrementCascadeLevel();
+		}
+	}
+
+
+	protected CascadingAction getCascadeAction() {
+		return CascadingAction.MERGE;
+	}
+
+	protected Boolean getAssumedUnsaved() {
+		return Boolean.FALSE;
+	}
+	
+	/**
+	 * Cascade behavior is redefined by this subclass, disable superclass behavior
+	 */
+	protected void cascadeAfterSave(EventSource source, EntityPersister persister, Object entity, Object anything) 
+	throws HibernateException {
+	}
+
+	/**
+	 * Cascade behavior is redefined by this subclass, disable superclass behavior
+	 */
+	protected void cascadeBeforeSave(EventSource source, EntityPersister persister, Object entity, Object anything) 
+	throws HibernateException {
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultMergeEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPersistEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPersistEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPersistEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,144 @@
+// $Id: DefaultPersistEventListener.java 9673 2006-03-22 14:57:59Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.ObjectDeletedException;
+import org.hibernate.PersistentObjectException;
+import org.hibernate.engine.CascadingAction;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.PersistEvent;
+import org.hibernate.event.PersistEventListener;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+import org.hibernate.util.IdentityMap;
+
+/**
+ * Defines the default create event listener used by hibernate for creating
+ * transient entities in response to generated create events.
+ *
+ * @author Gavin King
+ */
+public class DefaultPersistEventListener extends AbstractSaveEventListener implements PersistEventListener {
+
+	private static final Log log = LogFactory.getLog(DefaultPersistEventListener.class);
+
+	/** 
+	 * Handle the given create event.
+	 *
+	 * @param event The create event to be handled.
+	 * @throws HibernateException
+	 */
+	public void onPersist(PersistEvent event) throws HibernateException {
+		onPersist( event, IdentityMap.instantiate(10) );
+	}
+		
+
+	/** 
+	 * Handle the given create event.
+	 *
+	 * @param event The create event to be handled.
+	 * @throws HibernateException
+	 */
+	public void onPersist(PersistEvent event, Map createCache) throws HibernateException {
+			
+		final SessionImplementor source = event.getSession();
+		final Object object = event.getObject();
+		
+		final Object entity;
+		if (object instanceof HibernateProxy) {
+			LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer();
+			if ( li.isUninitialized() ) {
+				if ( li.getSession()==source ) {
+					return; //NOTE EARLY EXIT!
+				}
+				else {
+					throw new PersistentObjectException("uninitialized proxy passed to persist()");
+				}
+			}
+			entity = li.getImplementation();
+		}
+		else {
+			entity = object;
+		}
+		
+		int entityState = getEntityState( 
+				entity, 
+				event.getEntityName(), 
+				source.getPersistenceContext().getEntry(entity), 
+				source 
+			);
+		
+		switch (entityState) {
+			case DETACHED: 
+				throw new PersistentObjectException( 
+						"detached entity passed to persist: " + 
+						getLoggableName( event.getEntityName(), entity ) 
+					);
+			case PERSISTENT:
+				entityIsPersistent(event, createCache);
+				break;
+			case TRANSIENT:
+				entityIsTransient(event, createCache);
+				break;
+			default: 
+				throw new ObjectDeletedException( 
+						"deleted entity passed to persist", 
+						null, 
+						getLoggableName( event.getEntityName(), entity )
+					);
+		}
+
+	}
+		
+	protected void entityIsPersistent(PersistEvent event, Map createCache) {
+		log.trace("ignoring persistent instance");
+		final EventSource source = event.getSession();
+		
+		//TODO: check that entry.getIdentifier().equals(requestedId)
+		
+		final Object entity = source.getPersistenceContext().unproxy( event.getObject() );
+		final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
+		
+		if ( createCache.put(entity, entity)==null ) {
+			//TODO: merge into one method!
+			cascadeBeforeSave(source, persister, entity, createCache);
+			cascadeAfterSave(source, persister, entity, createCache);
+		}
+
+	}
+	
+	/** 
+	 * Handle the given create event.
+	 *
+	 * @param event The save event to be handled.
+	 * @throws HibernateException
+	 */
+	protected void entityIsTransient(PersistEvent event, Map createCache) throws HibernateException {
+		
+		log.trace("saving transient instance");
+
+		final EventSource source = event.getSession();
+		
+		final Object entity = source.getPersistenceContext().unproxy( event.getObject() );
+		
+		if ( createCache.put(entity, entity)==null ) {
+			saveWithGeneratedId( entity, event.getEntityName(), createCache, source, false );
+		}
+
+	}
+
+	protected CascadingAction getCascadeAction() {
+		return CascadingAction.PERSIST;
+	}
+	
+	protected Boolean getAssumedUnsaved() {
+		return Boolean.TRUE;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPersistEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPersistOnFlushEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPersistOnFlushEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPersistOnFlushEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,14 @@
+//$Id: DefaultPersistOnFlushEventListener.java 9019 2006-01-11 18:50:33Z epbernard $
+package org.hibernate.event.def;
+
+import org.hibernate.engine.CascadingAction;
+
+/**
+ * When persist is used as the cascade action, persistOnFlush should be used
+ * @author Emmanuel Bernard
+ */
+public class DefaultPersistOnFlushEventListener extends DefaultPersistEventListener {
+	protected CascadingAction getCascadeAction() {
+		return CascadingAction.PERSIST_ON_FLUSH;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPostLoadEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPostLoadEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPostLoadEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: DefaultPostLoadEventListener.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event.def;
+
+import org.hibernate.classic.Lifecycle;
+import org.hibernate.event.PostLoadEvent;
+import org.hibernate.event.PostLoadEventListener;
+
+/**
+ * Call <tt>Lifecycle</tt> interface if necessary
+ *
+ * @author Gavin King
+ */
+public class DefaultPostLoadEventListener implements PostLoadEventListener {
+	
+	public void onPostLoad(PostLoadEvent event) {
+		if ( event.getPersister().implementsLifecycle( event.getSession().getEntityMode() ) ) {
+			//log.debug( "calling onLoad()" );
+			( ( Lifecycle ) event.getEntity() ).onLoad( event.getSession(), event.getId() );
+		}
+
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPreLoadEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPreLoadEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPreLoadEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+//$Id: DefaultPreLoadEventListener.java 7785 2005-08-08 23:24:44Z oneovthafew $
+package org.hibernate.event.def;
+
+import org.hibernate.event.PreLoadEvent;
+import org.hibernate.event.PreLoadEventListener;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Called before injecting property values into a newly 
+ * loaded entity instance.
+ *
+ * @author Gavin King
+ */
+public class DefaultPreLoadEventListener implements PreLoadEventListener {
+	
+	public void onPreLoad(PreLoadEvent event) {
+		EntityPersister persister = event.getPersister();
+		event.getSession()
+			.getInterceptor()
+			.onLoad( 
+					event.getEntity(), 
+					event.getId(), 
+					event.getState(), 
+					persister.getPropertyNames(), 
+					persister.getPropertyTypes() 
+				);
+	}
+	
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultPreLoadEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultRefreshEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultRefreshEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultRefreshEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,146 @@
+//$Id: DefaultRefreshEventListener.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.PersistentObjectException;
+import org.hibernate.UnresolvableObjectException;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.engine.Cascade;
+import org.hibernate.engine.CascadingAction;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.RefreshEvent;
+import org.hibernate.event.RefreshEventListener;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.Type;
+import org.hibernate.util.IdentityMap;
+
+/**
+ * Defines the default refresh event listener used by hibernate for refreshing entities
+ * in response to generated refresh events.
+ *
+ * @author Steve Ebersole
+ */
+public class DefaultRefreshEventListener implements RefreshEventListener {
+
+	private static final Log log = LogFactory.getLog(DefaultRefreshEventListener.class);
+	
+	public void onRefresh(RefreshEvent event) throws HibernateException {
+		onRefresh( event, IdentityMap.instantiate(10) );
+	}
+
+	/** 
+	 * Handle the given refresh event.
+	 *
+	 * @param event The refresh event to be handled.
+	 */
+	public void onRefresh(RefreshEvent event, Map refreshedAlready) {
+
+		final EventSource source = event.getSession();
+		
+		if ( source.getPersistenceContext().reassociateIfUninitializedProxy( event.getObject() ) ) return;
+
+		final Object object = source.getPersistenceContext().unproxyAndReassociate( event.getObject() );
+
+		if ( refreshedAlready.containsKey(object) ) {
+			log.trace("already refreshed");
+			return;
+		}
+
+		final EntityEntry e = source.getPersistenceContext().getEntry( object );
+		final EntityPersister persister;
+		final Serializable id;
+		
+		if ( e == null ) {
+			persister = source.getEntityPersister(null, object); //refresh() does not pass an entityName
+			id = persister.getIdentifier( object, event.getSession().getEntityMode() );
+			if ( log.isTraceEnabled() ) {
+				log.trace(
+						"refreshing transient " +
+						MessageHelper.infoString( persister, id, source.getFactory() )
+					);
+			}
+			EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
+			if ( source.getPersistenceContext().getEntry(key) != null ) {
+				throw new PersistentObjectException(
+						"attempted to refresh transient instance when persistent instance was already associated with the Session: " +
+						MessageHelper.infoString(persister, id, source.getFactory() )
+					);
+			}
+		}
+		else {
+			if ( log.isTraceEnabled() ) {
+				log.trace(
+						"refreshing " +
+						MessageHelper.infoString( e.getPersister(), e.getId(), source.getFactory()  )
+					);
+			}
+			if ( !e.isExistsInDatabase() ) {
+				throw new HibernateException( "this instance does not yet exist as a row in the database" );
+			}
+
+			persister = e.getPersister();
+			id = e.getId();
+		}
+
+		// cascade the refresh prior to refreshing this entity
+		refreshedAlready.put(object, object);
+		new Cascade(CascadingAction.REFRESH, Cascade.BEFORE_REFRESH, source)
+				.cascade( persister, object, refreshedAlready );
+
+		if ( e != null ) {
+			EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
+			source.getPersistenceContext().removeEntity(key);
+			if ( persister.hasCollections() ) new EvictVisitor( source ).process(object, persister);
+		}
+
+		if ( persister.hasCache() ) {
+			final CacheKey ck = new CacheKey(
+					id,
+					persister.getIdentifierType(),
+					persister.getRootEntityName(),
+					source.getEntityMode(), 
+					source.getFactory()
+			);
+			persister.getCacheAccessStrategy().evict( ck );
+		}
+		
+		evictCachedCollections( persister, id, source.getFactory() );
+		
+		String previousFetchProfile = source.getFetchProfile();
+		source.setFetchProfile("refresh");
+		Object result = persister.load( id, object, event.getLockMode(), source );
+		source.setFetchProfile(previousFetchProfile);
+		
+		UnresolvableObjectException.throwIfNull( result, id, persister.getEntityName() );
+
+	}
+
+	private void evictCachedCollections(EntityPersister persister, Serializable id, SessionFactoryImplementor factory) {
+		evictCachedCollections( persister.getPropertyTypes(), id, factory );
+	}
+
+	private void evictCachedCollections(Type[] types, Serializable id, SessionFactoryImplementor factory)
+	throws HibernateException {
+		for ( int i = 0; i < types.length; i++ ) {
+			if ( types[i].isCollectionType() ) {
+				factory.evictCollection( ( (CollectionType) types[i] ).getRole(), id );
+			}
+			else if ( types[i].isComponentType() ) {
+				AbstractComponentType actype = (AbstractComponentType) types[i];
+				evictCachedCollections( actype.getSubtypes(), id, factory );
+			}
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultReplicateEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultReplicateEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultReplicateEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,206 @@
+//$Id: DefaultReplicateEventListener.java 11089 2007-01-24 14:34:22Z max.andersen at jboss.com $
+package org.hibernate.event.def;
+
+import org.hibernate.HibernateException;
+import org.hibernate.TransientObjectException;
+import org.hibernate.ReplicationMode;
+import org.hibernate.LockMode;
+import org.hibernate.engine.Cascade;
+import org.hibernate.engine.CascadingAction;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.Status;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.ReplicateEvent;
+import org.hibernate.event.ReplicateEventListener;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.type.Type;
+
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Defines the default replicate event listener used by Hibernate to replicate
+ * entities in response to generated replicate events.
+ *
+ * @author Steve Ebersole
+ */
+public class DefaultReplicateEventListener extends AbstractSaveEventListener implements ReplicateEventListener {
+
+	private static final Log log = LogFactory.getLog( DefaultReplicateEventListener.class );
+
+	/**
+	 * Handle the given replicate event.
+	 *
+	 * @param event The replicate event to be handled.
+	 *
+	 * @throws TransientObjectException An invalid attempt to replicate a transient entity.
+	 */
+	public void onReplicate(ReplicateEvent event) {
+		final EventSource source = event.getSession();
+		if ( source.getPersistenceContext().reassociateIfUninitializedProxy( event.getObject() ) ) {
+			log.trace( "uninitialized proxy passed to replicate()" );
+			return;
+		}
+
+		Object entity = source.getPersistenceContext().unproxyAndReassociate( event.getObject() );
+
+		if ( source.getPersistenceContext().isEntryFor( entity ) ) {
+			log.trace( "ignoring persistent instance passed to replicate()" );
+			//hum ... should we cascade anyway? throw an exception? fine like it is?
+			return;
+		}
+
+		EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
+
+		// get the id from the object
+		/*if ( persister.isUnsaved(entity, source) ) {
+			throw new TransientObjectException("transient instance passed to replicate()");
+		}*/
+		Serializable id = persister.getIdentifier( entity, source.getEntityMode() );
+		if ( id == null ) {
+			throw new TransientObjectException( "instance with null id passed to replicate()" );
+		}
+
+		final ReplicationMode replicationMode = event.getReplicationMode();
+
+		final Object oldVersion;
+		if ( replicationMode == ReplicationMode.EXCEPTION ) {
+			//always do an INSERT, and let it fail by constraint violation
+			oldVersion = null;
+		}
+		else {
+			//what is the version on the database?
+			oldVersion = persister.getCurrentVersion( id, source );			
+		}
+
+		if ( oldVersion != null ) { 			
+			if ( log.isTraceEnabled() ) {
+				log.trace(
+						"found existing row for " +
+								MessageHelper.infoString( persister, id, source.getFactory() )
+				);
+			}
+
+			/// HHH-2378
+			final Object realOldVersion = persister.isVersioned() ? oldVersion : null;
+			
+			boolean canReplicate = replicationMode.shouldOverwriteCurrentVersion(
+					entity,
+					realOldVersion,
+					persister.getVersion( entity, source.getEntityMode() ),
+					persister.getVersionType()
+			);
+
+			if ( canReplicate ) {
+				//will result in a SQL UPDATE:
+				performReplication( entity, id, realOldVersion, persister, replicationMode, source );
+			}
+			else {
+				//else do nothing (don't even reassociate object!)
+				log.trace( "no need to replicate" );
+			}
+
+			//TODO: would it be better to do a refresh from db?
+		}
+		else {
+			// no existing row - do an insert
+			if ( log.isTraceEnabled() ) {
+				log.trace(
+						"no existing row, replicating new instance " +
+								MessageHelper.infoString( persister, id, source.getFactory() )
+				);
+			}
+
+			final boolean regenerate = persister.isIdentifierAssignedByInsert(); // prefer re-generation of identity!
+			final EntityKey key = regenerate ?
+					null : new EntityKey( id, persister, source.getEntityMode() );
+
+			performSaveOrReplicate(
+					entity,
+					key,
+					persister,
+					regenerate,
+					replicationMode,
+					source,
+					true
+			);
+
+		}
+	}
+
+	protected boolean visitCollectionsBeforeSave(Object entity, Serializable id, Object[] values, Type[] types, EventSource source) {
+		//TODO: we use two visitors here, inefficient!
+		OnReplicateVisitor visitor = new OnReplicateVisitor( source, id, entity, false );
+		visitor.processEntityPropertyValues( values, types );
+		return super.visitCollectionsBeforeSave( entity, id, values, types, source );
+	}
+
+	protected boolean substituteValuesIfNecessary(
+			Object entity,
+			Serializable id,
+			Object[] values,
+			EntityPersister persister,
+			SessionImplementor source) {
+		return false;
+	}
+
+	protected boolean isVersionIncrementDisabled() {
+		return true;
+	}
+
+	private void performReplication(
+			Object entity,
+			Serializable id,
+			Object version,
+			EntityPersister persister,
+			ReplicationMode replicationMode,
+			EventSource source) throws HibernateException {
+
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"replicating changes to " +
+							MessageHelper.infoString( persister, id, source.getFactory() )
+			);
+		}
+
+		new OnReplicateVisitor( source, id, entity, true ).process( entity, persister );
+
+		source.getPersistenceContext().addEntity(
+				entity,
+				Status.MANAGED,
+				null,
+				new EntityKey( id, persister, source.getEntityMode() ),
+				version,
+				LockMode.NONE,
+				true,
+				persister,
+				true,
+				false
+		);
+
+		cascadeAfterReplicate( entity, persister, replicationMode, source );
+	}
+
+	private void cascadeAfterReplicate(
+			Object entity,
+			EntityPersister persister,
+			ReplicationMode replicationMode,
+			EventSource source) {
+		source.getPersistenceContext().incrementCascadeLevel();
+		try {
+			new Cascade( CascadingAction.REPLICATE, Cascade.AFTER_UPDATE, source )
+					.cascade( persister, entity, replicationMode );
+		}
+		finally {
+			source.getPersistenceContext().decrementCascadeLevel();
+		}
+	}
+
+	protected CascadingAction getCascadeAction() {
+		return CascadingAction.REPLICATE;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultSaveEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultSaveEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultSaveEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+//$Id: DefaultSaveEventListener.java 8486 2005-10-29 10:32:45Z oneovthafew $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+
+import org.hibernate.Hibernate;
+import org.hibernate.PersistentObjectException;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.Status;
+import org.hibernate.event.SaveOrUpdateEvent;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * An event handler for save() events
+ * @author Gavin King
+ */
+public class DefaultSaveEventListener extends DefaultSaveOrUpdateEventListener {
+
+	protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event) {
+		// this implementation is supposed to tolerate incorrect unsaved-value
+		// mappings, for the purpose of backward-compatibility
+		EntityEntry entry = event.getSession().getPersistenceContext().getEntry( event.getEntity() );
+		if ( entry!=null && entry.getStatus() != Status.DELETED ) {
+			return entityIsPersistent(event);
+		}
+		else {
+			return entityIsTransient(event);
+		}
+	}
+	
+	protected Serializable saveWithGeneratedOrRequestedId(SaveOrUpdateEvent event) {
+		if ( event.getRequestedId() == null ) {
+			return super.saveWithGeneratedOrRequestedId(event);
+		}
+		else {
+			return saveWithRequestedId( 
+					event.getEntity(), 
+					event.getRequestedId(), 
+					event.getEntityName(), 
+					null, 
+					event.getSession() 
+				);
+		}
+		
+	}
+
+	protected boolean reassociateIfUninitializedProxy(Object object, SessionImplementor source) {
+		if ( !Hibernate.isInitialized(object) ) {
+			throw new PersistentObjectException("uninitialized proxy passed to save()");
+		}
+		else {
+			return false;
+		}
+	}
+	
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultSaveOrUpdateCopyEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultSaveOrUpdateCopyEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultSaveOrUpdateCopyEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,12 @@
+//$Id: DefaultSaveOrUpdateCopyEventListener.java 7793 2005-08-10 05:06:40Z oneovthafew $
+package org.hibernate.event.def;
+
+import org.hibernate.engine.CascadingAction;
+
+public class DefaultSaveOrUpdateCopyEventListener extends DefaultMergeEventListener {
+
+	protected CascadingAction getCascadeAction() {
+		return CascadingAction.SAVE_UPDATE_COPY;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultSaveOrUpdateCopyEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultSaveOrUpdateEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultSaveOrUpdateEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultSaveOrUpdateEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,368 @@
+// $Id: DefaultSaveOrUpdateEventListener.java 10948 2006-12-07 21:53:10Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.PersistentObjectException;
+import org.hibernate.TransientObjectException;
+import org.hibernate.classic.Lifecycle;
+import org.hibernate.engine.Cascade;
+import org.hibernate.engine.CascadingAction;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.Status;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.SaveOrUpdateEvent;
+import org.hibernate.event.SaveOrUpdateEventListener;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.proxy.HibernateProxy;
+
+/**
+ * Defines the default listener used by Hibernate for handling save-update
+ * events.
+ *
+ * @author Steve Ebersole
+ * @author Gavin King
+ */
+public class DefaultSaveOrUpdateEventListener extends AbstractSaveEventListener implements SaveOrUpdateEventListener {
+
+	private static final Log log = LogFactory.getLog( DefaultSaveOrUpdateEventListener.class );
+
+	/**
+	 * Handle the given update event.
+	 *
+	 * @param event The update event to be handled.
+	 */
+	public void onSaveOrUpdate(SaveOrUpdateEvent event) {
+		final SessionImplementor source = event.getSession();
+		final Object object = event.getObject();
+		final Serializable requestedId = event.getRequestedId();
+
+		if ( requestedId != null ) {
+			//assign the requested id to the proxy, *before*
+			//reassociating the proxy
+			if ( object instanceof HibernateProxy ) {
+				( ( HibernateProxy ) object ).getHibernateLazyInitializer().setIdentifier( requestedId );
+			}
+		}
+
+		if ( reassociateIfUninitializedProxy( object, source ) ) {
+			log.trace( "reassociated uninitialized proxy" );
+			// an uninitialized proxy, noop, don't even need to
+			// return an id, since it is never a save()
+		}
+		else {
+			//initialize properties of the event:
+			final Object entity = source.getPersistenceContext().unproxyAndReassociate( object );
+			event.setEntity( entity );
+			event.setEntry( source.getPersistenceContext().getEntry( entity ) );
+			//return the id in the event object
+			event.setResultId( performSaveOrUpdate( event ) );
+		}
+
+	}
+
+	protected boolean reassociateIfUninitializedProxy(Object object, SessionImplementor source) {
+		return source.getPersistenceContext().reassociateIfUninitializedProxy( object );
+	}
+
+	protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event) {
+		int entityState = getEntityState(
+				event.getEntity(),
+				event.getEntityName(),
+				event.getEntry(),
+				event.getSession()
+		);
+
+		switch ( entityState ) {
+			case DETACHED:
+				entityIsDetached( event );
+				return null;
+			case PERSISTENT:
+				return entityIsPersistent( event );
+			default: //TRANSIENT or DELETED
+				return entityIsTransient( event );
+		}
+	}
+
+	protected Serializable entityIsPersistent(SaveOrUpdateEvent event) throws HibernateException {
+		log.trace( "ignoring persistent instance" );
+
+		EntityEntry entityEntry = event.getEntry();
+		if ( entityEntry == null ) {
+			throw new AssertionFailure( "entity was transient or detached" );
+		}
+		else {
+
+			if ( entityEntry.getStatus() == Status.DELETED ) {
+				throw new AssertionFailure( "entity was deleted" );
+			}
+
+			final SessionFactoryImplementor factory = event.getSession().getFactory();
+
+			Serializable requestedId = event.getRequestedId();
+
+			Serializable savedId;
+			if ( requestedId == null ) {
+				savedId = entityEntry.getId();
+			}
+			else {
+
+				final boolean isEqual = !entityEntry.getPersister().getIdentifierType()
+						.isEqual( requestedId, entityEntry.getId(), event.getSession().getEntityMode(), factory );
+
+				if ( isEqual ) {
+					throw new PersistentObjectException(
+							"object passed to save() was already persistent: " +
+									MessageHelper.infoString( entityEntry.getPersister(), requestedId, factory )
+					);
+				}
+
+				savedId = requestedId;
+
+			}
+
+			if ( log.isTraceEnabled() ) {
+				log.trace(
+						"object already associated with session: " +
+								MessageHelper.infoString( entityEntry.getPersister(), savedId, factory )
+				);
+			}
+
+			return savedId;
+
+		}
+	}
+
+	/**
+	 * The given save-update event named a transient entity.
+	 * <p/>
+	 * Here, we will perform the save processing.
+	 *
+	 * @param event The save event to be handled.
+	 *
+	 * @return The entity's identifier after saving.
+	 */
+	protected Serializable entityIsTransient(SaveOrUpdateEvent event) {
+
+		log.trace( "saving transient instance" );
+
+		final EventSource source = event.getSession();
+
+		EntityEntry entityEntry = event.getEntry();
+		if ( entityEntry != null ) {
+			if ( entityEntry.getStatus() == Status.DELETED ) {
+				source.forceFlush( entityEntry );
+			}
+			else {
+				throw new AssertionFailure( "entity was persistent" );
+			}
+		}
+
+		Serializable id = saveWithGeneratedOrRequestedId( event );
+
+		source.getPersistenceContext().reassociateProxy( event.getObject(), id );
+
+		return id;
+	}
+
+	/**
+	 * Save the transient instance, assigning the right identifier
+	 *
+	 * @param event The initiating event.
+	 *
+	 * @return The entity's identifier value after saving.
+	 */
+	protected Serializable saveWithGeneratedOrRequestedId(SaveOrUpdateEvent event) {
+		return saveWithGeneratedId(
+				event.getEntity(),
+				event.getEntityName(),
+				null,
+				event.getSession(),
+				true
+		);
+	}
+
+	/**
+	 * The given save-update event named a detached entity.
+	 * <p/>
+	 * Here, we will perform the update processing.
+	 *
+	 * @param event The update event to be handled.
+	 */
+	protected void entityIsDetached(SaveOrUpdateEvent event) {
+
+		log.trace( "updating detached instance" );
+
+
+		if ( event.getSession().getPersistenceContext().isEntryFor( event.getEntity() ) ) {
+			//TODO: assertion only, could be optimized away
+			throw new AssertionFailure( "entity was persistent" );
+		}
+
+		Object entity = event.getEntity();
+
+		EntityPersister persister = event.getSession().getEntityPersister( event.getEntityName(), entity );
+
+		event.setRequestedId(
+				getUpdateId(
+						entity, persister, event.getRequestedId(), event.getSession().getEntityMode()
+				)
+		);
+
+		performUpdate( event, entity, persister );
+
+	}
+
+	/**
+	 * Determine the id to use for updating.
+	 *
+	 * @param entity The entity.
+	 * @param persister The entity persister
+	 * @param requestedId The requested identifier
+	 * @param entityMode The entity mode.
+	 *
+	 * @return The id.
+	 *
+	 * @throws TransientObjectException If the entity is considered transient.
+	 */
+	protected Serializable getUpdateId(
+			Object entity,
+			EntityPersister persister,
+			Serializable requestedId,
+			EntityMode entityMode) {
+		// use the id assigned to the instance
+		Serializable id = persister.getIdentifier( entity, entityMode );
+		if ( id == null ) {
+			// assume this is a newly instantiated transient object
+			// which should be saved rather than updated
+			throw new TransientObjectException(
+					"The given object has a null identifier: " +
+							persister.getEntityName()
+			);
+		}
+		else {
+			return id;
+		}
+
+	}
+
+	protected void performUpdate(
+			SaveOrUpdateEvent event,
+			Object entity,
+			EntityPersister persister) throws HibernateException {
+
+		if ( !persister.isMutable() ) {
+			log.trace( "immutable instance passed to doUpdate(), locking" );
+			reassociate( event, entity, event.getRequestedId(), persister );
+		}
+		else {
+
+			if ( log.isTraceEnabled() ) {
+				log.trace(
+						"updating " +
+								MessageHelper.infoString(
+										persister, event.getRequestedId(), event.getSession().getFactory()
+								)
+				);
+			}
+
+			final EventSource source = event.getSession();
+
+			EntityKey key = new EntityKey( event.getRequestedId(), persister, source.getEntityMode() );
+
+			source.getPersistenceContext().checkUniqueness( key, entity );
+
+			if ( invokeUpdateLifecycle( entity, persister, source ) ) {
+				reassociate( event, event.getObject(), event.getRequestedId(), persister );
+				return;
+			}
+
+			// this is a transient object with existing persistent state not loaded by the session
+
+			new OnUpdateVisitor( source, event.getRequestedId(), entity ).process( entity, persister );
+
+			//TODO: put this stuff back in to read snapshot from
+			//      the second-level cache (needs some extra work)
+			/*Object[] cachedState = null;
+
+			if ( persister.hasCache() ) {
+				CacheEntry entry = (CacheEntry) persister.getCache()
+						.get( event.getRequestedId(), source.getTimestamp() );
+			    cachedState = entry==null ?
+			    		null :
+			    		entry.getState(); //TODO: half-assemble this stuff
+			}*/
+
+			source.getPersistenceContext().addEntity(
+					entity,
+					Status.MANAGED,
+					null, //cachedState,
+					key,
+					persister.getVersion( entity, source.getEntityMode() ),
+					LockMode.NONE,
+					true,
+					persister,
+					false,
+					true //assume true, since we don't really know, and it doesn't matter
+			);
+
+			persister.afterReassociate( entity, source );
+
+			if ( log.isTraceEnabled() ) {
+				log.trace(
+						"updating " +
+								MessageHelper.infoString( persister, event.getRequestedId(), source.getFactory() )
+				);
+			}
+
+			cascadeOnUpdate( event, persister, entity );
+
+		}
+	}
+
+	protected boolean invokeUpdateLifecycle(Object entity, EntityPersister persister, EventSource source) {
+		if ( persister.implementsLifecycle( source.getEntityMode() ) ) {
+			log.debug( "calling onUpdate()" );
+			if ( ( ( Lifecycle ) entity ).onUpdate( source ) ) {
+				log.debug( "update vetoed by onUpdate()" );
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Handles the calls needed to perform cascades as part of an update request
+	 * for the given entity.
+	 *
+	 * @param event The event currently being processed.
+	 * @param persister The defined persister for the entity being updated.
+	 * @param entity The entity being updated.
+	 */
+	private void cascadeOnUpdate(SaveOrUpdateEvent event, EntityPersister persister, Object entity) {
+		EventSource source = event.getSession();
+		source.getPersistenceContext().incrementCascadeLevel();
+		try {
+			new Cascade( CascadingAction.SAVE_UPDATE, Cascade.AFTER_UPDATE, source )
+					.cascade( persister, entity );
+		}
+		finally {
+			source.getPersistenceContext().decrementCascadeLevel();
+		}
+	}
+
+	protected CascadingAction getCascadeAction() {
+		return CascadingAction.SAVE_UPDATE;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultSaveOrUpdateEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultUpdateEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultUpdateEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DefaultUpdateEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+//$Id: DefaultUpdateEventListener.java 5839 2005-02-22 03:09:35Z oneovthafew $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.ObjectDeletedException;
+import org.hibernate.EntityMode;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.Status;
+import org.hibernate.event.SaveOrUpdateEvent;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * An event handler for update() events
+ * @author Gavin King
+ */
+public class DefaultUpdateEventListener extends DefaultSaveOrUpdateEventListener {
+
+	protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event) {
+		// this implementation is supposed to tolerate incorrect unsaved-value
+		// mappings, for the purpose of backward-compatibility
+		EntityEntry entry = event.getSession().getPersistenceContext().getEntry( event.getEntity() );
+		if ( entry!=null ) {
+			if ( entry.getStatus()==Status.DELETED ) {
+				throw new ObjectDeletedException( "deleted instance passed to update()", null, event.getEntityName() );
+			}
+			else {
+				return entityIsPersistent(event);
+			}
+		}
+		else {
+			entityIsDetached(event);
+			return null;
+		}
+	}
+	
+	/**
+	 * If the user specified an id, assign it to the instance and use that, 
+	 * otherwise use the id already assigned to the instance
+	 */
+	protected Serializable getUpdateId(Object entity, EntityPersister persister, Serializable requestedId, EntityMode entityMode)
+	throws HibernateException {
+
+		if ( requestedId==null ) {
+			return super.getUpdateId(entity, persister, requestedId, entityMode);
+		}
+		else {
+			persister.setIdentifier(entity, requestedId, entityMode);
+			return requestedId;
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DirtyCollectionSearchVisitor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DirtyCollectionSearchVisitor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/DirtyCollectionSearchVisitor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,66 @@
+//$Id: DirtyCollectionSearchVisitor.java 7675 2005-07-29 06:25:23Z oneovthafew $
+package org.hibernate.event.def;
+
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.event.EventSource;
+import org.hibernate.type.CollectionType;
+
+/**
+ * Do we have a dirty collection here?
+ * 1. if it is a new application-instantiated collection, return true (does not occur anymore!)
+ * 2. if it is a component, recurse
+ * 3. if it is a wrappered collection, ask the collection entry
+ *
+ * @author Gavin King
+ */
+public class DirtyCollectionSearchVisitor extends AbstractVisitor {
+
+	private boolean dirty = false;
+	private boolean[] propertyVersionability;
+
+	DirtyCollectionSearchVisitor(EventSource session, boolean[] propertyVersionability) {
+		super(session);
+		this.propertyVersionability = propertyVersionability;
+	}
+
+	boolean wasDirtyCollectionFound() {
+		return dirty;
+	}
+
+	Object processCollection(Object collection, CollectionType type)
+		throws HibernateException {
+
+		if (collection!=null) {
+
+			SessionImplementor session = getSession();
+
+			final PersistentCollection persistentCollection;
+			if ( type.isArrayType() ) {
+				 persistentCollection = session.getPersistenceContext().getCollectionHolder(collection);
+				// if no array holder we found an unwrappered array (this can't occur,
+				// because we now always call wrap() before getting to here)
+				// return (ah==null) ? true : searchForDirtyCollections(ah, type);
+			}
+			else {
+				// if not wrappered yet, its dirty (this can't occur, because
+				// we now always call wrap() before getting to here)
+				// return ( ! (obj instanceof PersistentCollection) ) ?
+				//true : searchForDirtyCollections( (PersistentCollection) obj, type );
+				persistentCollection = (PersistentCollection) collection;
+			}
+
+			if ( persistentCollection.isDirty() ) { //we need to check even if it was not initialized, because of delayed adds!
+				dirty=true;
+				return null; //NOTE: EARLY EXIT!
+			}
+		}
+
+		return null;
+	}
+
+	boolean includeEntityProperty(Object[] values, int i) {
+		return propertyVersionability[i] && super.includeEntityProperty(values, i);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/EvictVisitor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/EvictVisitor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/EvictVisitor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,68 @@
+//$Id: EvictVisitor.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.event.def;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.CollectionEntry;
+import org.hibernate.engine.CollectionKey;
+import org.hibernate.event.EventSource;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.type.CollectionType;
+
+/**
+ * Evict any collections referenced by the object from the session cache.
+ * This will NOT pick up any collections that were dereferenced, so they
+ * will be deleted (suboptimal but not exactly incorrect).
+ *
+ * @author Gavin King
+ */
+public class EvictVisitor extends AbstractVisitor {
+	
+	private static final Log log = LogFactory.getLog(EvictVisitor.class);
+
+	EvictVisitor(EventSource session) {
+		super(session);
+	}
+
+	Object processCollection(Object collection, CollectionType type)
+		throws HibernateException {
+
+		if (collection!=null) evictCollection(collection, type);
+
+		return null;
+	}
+	public void evictCollection(Object value, CollectionType type) {
+
+		final Object pc;
+		if ( type.hasHolder( getSession().getEntityMode() ) ) {
+			pc = getSession().getPersistenceContext().removeCollectionHolder(value);
+		}
+		else if ( value instanceof PersistentCollection ) {
+			pc = value;
+		}
+		else {
+			return; //EARLY EXIT!
+		}
+
+		PersistentCollection collection = (PersistentCollection) pc;
+		if ( collection.unsetSession( getSession() ) ) evictCollection(collection);
+	}
+
+	private void evictCollection(PersistentCollection collection) {
+		CollectionEntry ce = (CollectionEntry) getSession().getPersistenceContext().getCollectionEntries().remove(collection);
+		if ( log.isDebugEnabled() )
+			log.debug(
+					"evicting collection: " +
+					MessageHelper.collectionInfoString( ce.getLoadedPersister(), ce.getLoadedKey(), getSession().getFactory() )
+			);
+		if ( ce.getLoadedPersister() != null && ce.getLoadedKey() != null ) {
+			//TODO: is this 100% correct?
+			getSession().getPersistenceContext().getCollectionsByKey().remove( 
+					new CollectionKey( ce.getLoadedPersister(), ce.getLoadedKey(), getSession().getEntityMode() ) 
+			);
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/FlushVisitor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/FlushVisitor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/FlushVisitor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: FlushVisitor.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.event.def;
+
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.Collections;
+import org.hibernate.event.EventSource;
+import org.hibernate.type.CollectionType;
+
+/**
+ * Process collections reachable from an entity. This
+ * visitor assumes that wrap was already performed for
+ * the entity.
+ *
+ * @author Gavin King
+ */
+public class FlushVisitor extends AbstractVisitor {
+	
+	private Object owner;
+
+	Object processCollection(Object collection, CollectionType type)
+	throws HibernateException {
+		
+		if (collection==CollectionType.UNFETCHED_COLLECTION) {
+			return null;
+		}
+
+		if (collection!=null) {
+			final PersistentCollection coll;
+			if ( type.hasHolder( getSession().getEntityMode() ) ) {
+				coll = getSession().getPersistenceContext().getCollectionHolder(collection);
+			}
+			else {
+				coll = (PersistentCollection) collection;
+			}
+
+			Collections.processReachableCollection( coll, type, owner, getSession() );
+		}
+
+		return null;
+
+	}
+
+	FlushVisitor(EventSource session, Object owner) {
+		super(session);
+		this.owner = owner;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/OnLockVisitor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/OnLockVisitor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/OnLockVisitor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,68 @@
+//$Id: OnLockVisitor.java 10948 2006-12-07 21:53:10Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.event.EventSource;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.CollectionType;
+
+/**
+ * When a transient entity is passed to lock(), we must inspect all its collections and
+ * 1. associate any uninitialized PersistentCollections with this session
+ * 2. associate any initialized PersistentCollections with this session, using the
+ * existing snapshot
+ * 3. throw an exception for each "new" collection
+ *
+ * @author Gavin King
+ */
+public class OnLockVisitor extends ReattachVisitor {
+
+	public OnLockVisitor(EventSource session, Serializable key, Object owner) {
+		super( session, key, owner );
+	}
+
+	Object processCollection(Object collection, CollectionType type) throws HibernateException {
+
+		SessionImplementor session = getSession();
+		CollectionPersister persister = session.getFactory().getCollectionPersister( type.getRole() );
+
+		if ( collection == null ) {
+			//do nothing
+		}
+		else if ( collection instanceof PersistentCollection ) {
+			PersistentCollection persistentCollection = ( PersistentCollection ) collection;
+			if ( persistentCollection.setCurrentSession( session ) ) {
+				if ( isOwnerUnchanged( persistentCollection, persister, extractCollectionKeyFromOwner( persister ) ) ) {
+					// a "detached" collection that originally belonged to the same entity
+					if ( persistentCollection.isDirty() ) {
+						throw new HibernateException( "reassociated object has dirty collection" );
+					}
+					reattachCollection( persistentCollection, type );
+				}
+				else {
+					// a "detached" collection that belonged to a different entity
+					throw new HibernateException( "reassociated object has dirty collection reference" );
+				}
+			}
+			else {
+				// a collection loaded in the current session
+				// can not possibly be the collection belonging
+				// to the entity passed to update()
+				throw new HibernateException( "reassociated object has dirty collection reference" );
+			}
+		}
+		else {
+			// brand new collection
+			//TODO: or an array!! we can't lock objects with arrays now??
+			throw new HibernateException( "reassociated object has dirty collection reference (or an array)" );
+		}
+
+		return null;
+
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/OnReplicateVisitor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/OnReplicateVisitor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/OnReplicateVisitor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,66 @@
+//$Id: OnReplicateVisitor.java 10948 2006-12-07 21:53:10Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.event.EventSource;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.CollectionType;
+
+/**
+ * When an entity is passed to replicate(), and there is an existing row, we must
+ * inspect all its collections and
+ * 1. associate any uninitialized PersistentCollections with this session
+ * 2. associate any initialized PersistentCollections with this session, using the
+ * existing snapshot
+ * 3. execute a collection removal (SQL DELETE) for each null collection property
+ * or "new" collection
+ *
+ * @author Gavin King
+ */
+public class OnReplicateVisitor extends ReattachVisitor {
+
+	private boolean isUpdate;
+
+	OnReplicateVisitor(EventSource session, Serializable key, Object owner, boolean isUpdate) {
+		super( session, key, owner );
+		this.isUpdate = isUpdate;
+	}
+
+	Object processCollection(Object collection, CollectionType type)
+			throws HibernateException {
+
+		if ( collection == CollectionType.UNFETCHED_COLLECTION ) {
+			return null;
+		}
+
+		EventSource session = getSession();
+		CollectionPersister persister = session.getFactory().getCollectionPersister( type.getRole() );
+
+		if ( isUpdate ) {
+			removeCollection( persister, extractCollectionKeyFromOwner( persister ), session );
+		}
+		if ( collection != null && ( collection instanceof PersistentCollection ) ) {
+			PersistentCollection wrapper = ( PersistentCollection ) collection;
+			wrapper.setCurrentSession( session );
+			if ( wrapper.wasInitialized() ) {
+				session.getPersistenceContext().addNewCollection( persister, wrapper );
+			}
+			else {
+				reattachCollection( wrapper, type );
+			}
+		}
+		else {
+			// otherwise a null or brand new collection
+			// this will also (inefficiently) handle arrays, which
+			// have no snapshot, so we can't do any better
+			//processArrayOrNewCollection(collection, type);
+		}
+
+		return null;
+
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/OnUpdateVisitor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/OnUpdateVisitor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/OnUpdateVisitor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+//$Id: OnUpdateVisitor.java 10948 2006-12-07 21:53:10Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.event.EventSource;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.CollectionType;
+
+/**
+ * When an entity is passed to update(), we must inspect all its collections and
+ * 1. associate any uninitialized PersistentCollections with this session
+ * 2. associate any initialized PersistentCollections with this session, using the
+ *    existing snapshot
+ * 3. execute a collection removal (SQL DELETE) for each null collection property
+ *    or "new" collection
+ *
+ * @author Gavin King
+ */
+public class OnUpdateVisitor extends ReattachVisitor {
+
+	OnUpdateVisitor(EventSource session, Serializable key, Object owner) {
+		super( session, key, owner );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	Object processCollection(Object collection, CollectionType type) throws HibernateException {
+
+		if ( collection == CollectionType.UNFETCHED_COLLECTION ) {
+			return null;
+		}
+
+		EventSource session = getSession();
+		CollectionPersister persister = session.getFactory().getCollectionPersister( type.getRole() );
+
+		final Serializable collectionKey = extractCollectionKeyFromOwner( persister );
+		if ( collection!=null && (collection instanceof PersistentCollection) ) {
+			PersistentCollection wrapper = (PersistentCollection) collection;
+			if ( wrapper.setCurrentSession(session) ) {
+				//a "detached" collection!
+				if ( !isOwnerUnchanged( wrapper, persister, collectionKey ) ) {
+					// if the collection belonged to a different entity,
+					// clean up the existing state of the collection
+					removeCollection( persister, collectionKey, session );
+				}
+				reattachCollection(wrapper, type);
+			}
+			else {
+				// a collection loaded in the current session
+				// can not possibly be the collection belonging
+				// to the entity passed to update()
+				removeCollection(persister, collectionKey, session);
+			}
+		}
+		else {
+			// null or brand new collection
+			// this will also (inefficiently) handle arrays, which have
+			// no snapshot, so we can't do any better
+			removeCollection(persister, collectionKey, session);
+		}
+
+		return null;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/ProxyVisitor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/ProxyVisitor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/ProxyVisitor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,79 @@
+//$Id: ProxyVisitor.java 7181 2005-06-17 19:36:08Z oneovthafew $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.event.EventSource;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.EntityType;
+
+/**
+ * Reassociates uninitialized proxies with the session
+ * @author Gavin King
+ */
+public abstract class ProxyVisitor extends AbstractVisitor {
+
+
+	public ProxyVisitor(EventSource session) {
+		super(session);
+	}
+
+	Object processEntity(Object value, EntityType entityType) throws HibernateException {
+
+		if (value!=null) {
+			getSession().getPersistenceContext().reassociateIfUninitializedProxy(value);
+			// if it is an initialized proxy, let cascade
+			// handle it later on
+		}
+
+		return null;
+	}
+
+	/**
+	 * Has the owner of the collection changed since the collection
+	 * was snapshotted and detached?
+	 */
+	protected static boolean isOwnerUnchanged(
+			final PersistentCollection snapshot, 
+			final CollectionPersister persister, 
+			final Serializable id
+	) {
+		return isCollectionSnapshotValid(snapshot) &&
+				persister.getRole().equals( snapshot.getRole() ) &&
+				id.equals( snapshot.getKey() );
+	}
+
+	private static boolean isCollectionSnapshotValid(PersistentCollection snapshot) {
+		return snapshot != null &&
+				snapshot.getRole() != null &&
+				snapshot.getKey() != null;
+	}
+	
+	/**
+	 * Reattach a detached (disassociated) initialized or uninitialized
+	 * collection wrapper, using a snapshot carried with the collection
+	 * wrapper
+	 */
+	protected void reattachCollection(PersistentCollection collection, CollectionType type)
+	throws HibernateException {
+		if ( collection.wasInitialized() ) {
+			CollectionPersister collectionPersister = getSession().getFactory()
+			.getCollectionPersister( type.getRole() );
+			getSession().getPersistenceContext()
+				.addInitializedDetachedCollection( collectionPersister, collection );
+		}
+		else {
+			if ( !isCollectionSnapshotValid(collection) ) {
+				throw new HibernateException( "could not reassociate uninitialized transient collection" );
+			}
+			CollectionPersister collectionPersister = getSession().getFactory()
+					.getCollectionPersister( collection.getRole() );
+			getSession().getPersistenceContext()
+				.addUninitializedDetachedCollection( collectionPersister, collection );
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/ReattachVisitor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/ReattachVisitor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/ReattachVisitor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,103 @@
+//$Id: ReattachVisitor.java 10948 2006-12-07 21:53:10Z steve.ebersole at jboss.com $
+package org.hibernate.event.def;
+
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.action.CollectionRemoveAction;
+import org.hibernate.event.EventSource;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.Type;
+
+/**
+ * Abstract superclass of visitors that reattach collections.
+ *
+ * @author Gavin King
+ */
+public abstract class ReattachVisitor extends ProxyVisitor {
+
+	private static final Log log = LogFactory.getLog( ReattachVisitor.class );
+
+	private final Serializable ownerIdentifier;
+	private final Object owner;
+
+	public ReattachVisitor(EventSource session, Serializable ownerIdentifier, Object owner) {
+		super( session );
+		this.ownerIdentifier = ownerIdentifier;
+		this.owner = owner;
+	}
+
+	/**
+	 * Retrieve the identifier of the entity being visited.
+	 *
+	 * @return The entity's identifier.
+	 */
+	final Serializable getOwnerIdentifier() {
+		return ownerIdentifier;
+	}
+
+	/**
+	 * Retrieve the entity being visited.
+	 *
+	 * @return The entity.
+	 */
+	final Object getOwner() {
+		return owner;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	Object processComponent(Object component, AbstractComponentType componentType) throws HibernateException {
+		Type[] types = componentType.getSubtypes();
+		if ( component == null ) {
+			processValues( new Object[types.length], types );
+		}
+		else {
+			super.processComponent( component, componentType );
+		}
+
+		return null;
+	}
+
+	/**
+	 * Schedules a collection for deletion.
+	 *
+	 * @param role The persister representing the collection to be removed.
+	 * @param collectionKey The collection key (differs from owner-id in the case of property-refs).
+	 * @param source The session from which the request originated.
+	 * @throws HibernateException
+	 */
+	void removeCollection(CollectionPersister role, Serializable collectionKey, EventSource source) throws HibernateException {
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"collection dereferenced while transient " +
+					MessageHelper.collectionInfoString( role, ownerIdentifier, source.getFactory() )
+			);
+		}
+		source.getActionQueue().addAction( new CollectionRemoveAction( null, role, collectionKey, false, source ) );
+	}
+
+	/**
+	 * This version is slightly different for say
+	 * {@link org.hibernate.type.CollectionType#getKeyOfOwner} in that here we
+	 * need to assume that the owner is not yet associated with the session,
+	 * and thus we cannot rely on the owner's EntityEntry snapshot...
+	 *
+	 * @param role The persister for the collection role being processed.
+	 * @return
+	 */
+	final Serializable extractCollectionKeyFromOwner(CollectionPersister role) {
+		if ( role.getCollectionType().useLHSPrimaryKey() ) {
+			return ownerIdentifier;
+		}
+		else {
+			return ( Serializable ) role.getOwnerEntityPersister().getPropertyValue( owner, role.getCollectionType().getLHSPropertyName(), getSession().getEntityMode() );
+		}
+
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/WrapVisitor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/WrapVisitor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/WrapVisitor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,137 @@
+//$Id: WrapVisitor.java 7181 2005-06-17 19:36:08Z oneovthafew $
+package org.hibernate.event.def;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.event.EventSource;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.Type;
+
+/**
+ * Wrap collections in a Hibernate collection
+ * wrapper.
+ * @author Gavin King
+ */
+public class WrapVisitor extends ProxyVisitor {
+
+	private static final Log log = LogFactory.getLog(WrapVisitor.class);
+
+	boolean substitute = false;
+
+	boolean isSubstitutionRequired() {
+		return substitute;
+	}
+
+	WrapVisitor(EventSource session) {
+		super(session);
+	}
+
+	Object processCollection(Object collection, CollectionType collectionType)
+	throws HibernateException {
+
+		if ( collection!=null && (collection instanceof PersistentCollection) ) {
+
+			final SessionImplementor session = getSession();
+			PersistentCollection coll = (PersistentCollection) collection;
+			if ( coll.setCurrentSession(session) ) {
+				reattachCollection( coll, collectionType );
+			}
+			return null;
+
+		}
+		else {
+			return processArrayOrNewCollection(collection, collectionType);
+		}
+
+	}
+
+	final Object processArrayOrNewCollection(Object collection, CollectionType collectionType)
+	throws HibernateException {
+
+		final SessionImplementor session = getSession();
+
+		if (collection==null) {
+			//do nothing
+			return null;
+		}
+		else {
+			CollectionPersister persister = session.getFactory().getCollectionPersister( collectionType.getRole() );
+
+			final PersistenceContext persistenceContext = session.getPersistenceContext();
+			//TODO: move into collection type, so we can use polymorphism!
+			if ( collectionType.hasHolder( session.getEntityMode() ) ) {
+				
+				if (collection==CollectionType.UNFETCHED_COLLECTION) return null;
+
+				PersistentCollection ah = persistenceContext.getCollectionHolder(collection);
+				if (ah==null) {
+					ah = collectionType.wrap(session, collection);
+					persistenceContext.addNewCollection( persister, ah );
+					persistenceContext.addCollectionHolder(ah);
+				}
+				return null;
+			}
+			else {
+
+				PersistentCollection persistentCollection = collectionType.wrap(session, collection);
+				persistenceContext.addNewCollection( persister, persistentCollection );
+
+				if ( log.isTraceEnabled() ) log.trace( "Wrapped collection in role: " + collectionType.getRole() );
+
+				return persistentCollection; //Force a substitution!
+
+			}
+
+		}
+
+	}
+
+	void processValue(int i, Object[] values, Type[] types) {
+		Object result = processValue( values[i], types[i] );
+		if (result!=null) {
+			substitute = true;
+			values[i] = result;
+		}
+	}
+
+	Object processComponent(Object component, AbstractComponentType componentType)
+	throws HibernateException {
+
+		if (component!=null) {
+			Object[] values = componentType.getPropertyValues( component, getSession() );
+			Type[] types = componentType.getSubtypes();
+			boolean substituteComponent = false;
+			for ( int i=0; i<types.length; i++ ) {
+				Object result = processValue( values[i], types[i] );
+				if (result!=null) {
+					values[i] = result;
+					substituteComponent = true;
+				}
+			}
+			if (substituteComponent) {
+				componentType.setPropertyValues( component, values, getSession().getEntityMode() );
+			}
+		}
+
+		return null;
+	}
+
+	void process(Object object, EntityPersister persister) throws HibernateException {
+		EntityMode entityMode = getSession().getEntityMode();
+		Object[] values = persister.getPropertyValues( object, entityMode );
+		Type[] types = persister.getPropertyTypes();
+		processEntityPropertyValues(values, types);
+		if ( isSubstitutionRequired() ) {
+			persister.setPropertyValues( object, values, entityMode );
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines a default set of event listeners that
+	implements the default behaviors of Hibernate.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/def/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/event/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/event/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/event/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines an event framework for Hibernate.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/event/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/CacheSQLStateConverter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/CacheSQLStateConverter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/CacheSQLStateConverter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,93 @@
+// $Id: $
+package org.hibernate.exception;
+
+import org.hibernate.JDBCException;
+
+import java.sql.SQLException;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A SQLExceptionConverter implementation specific to Cach&eacute; SQL,
+ * accounting for its custom integrity constraint violation error codes.
+ *
+ * @author Jonathan Levinson
+ */
+public class CacheSQLStateConverter implements SQLExceptionConverter {
+
+	private ViolatedConstraintNameExtracter extracter;
+
+	private static final Set SQL_GRAMMAR_CATEGORIES = new HashSet();
+	private static final Set DATA_CATEGORIES = new HashSet();
+	private static final Set INTEGRITY_VIOLATION_CATEGORIES = new HashSet();
+	private static final Set CONNECTION_CATEGORIES = new HashSet();
+
+	static {
+		SQL_GRAMMAR_CATEGORIES.add( "07" );
+		SQL_GRAMMAR_CATEGORIES.add( "37" );
+		SQL_GRAMMAR_CATEGORIES.add( "42" );
+		SQL_GRAMMAR_CATEGORIES.add( "65" );
+		SQL_GRAMMAR_CATEGORIES.add( "S0" );
+		SQL_GRAMMAR_CATEGORIES.add( "20" );
+
+		DATA_CATEGORIES.add( "22" );
+		DATA_CATEGORIES.add( "21" );
+		DATA_CATEGORIES.add( "02" );
+
+		INTEGRITY_VIOLATION_CATEGORIES.add( new Integer( 119 ) );
+		INTEGRITY_VIOLATION_CATEGORIES.add( new Integer( 120 ) );
+		INTEGRITY_VIOLATION_CATEGORIES.add( new Integer( 121 ) );
+		INTEGRITY_VIOLATION_CATEGORIES.add( new Integer( 122 ) );
+		INTEGRITY_VIOLATION_CATEGORIES.add( new Integer( 123 ) );
+		INTEGRITY_VIOLATION_CATEGORIES.add( new Integer( 124 ) );
+		INTEGRITY_VIOLATION_CATEGORIES.add( new Integer( 125 ) );
+		INTEGRITY_VIOLATION_CATEGORIES.add( new Integer( 127 ) );
+
+		CONNECTION_CATEGORIES.add( "08" );
+	}
+
+	public CacheSQLStateConverter(ViolatedConstraintNameExtracter extracter) {
+		this.extracter = extracter;
+	}
+
+	/**
+	 * Convert the given SQLException into Hibernate's JDBCException hierarchy.
+	 *
+	 * @param sqlException The SQLException to be converted.
+	 * @param message	  An optional error message.
+	 * @param sql		  Optionally, the sql being performed when the exception occurred.
+	 * @return The resulting JDBCException.
+	 */
+	public JDBCException convert(SQLException sqlException, String message, String sql) {
+		String sqlStateClassCode = JDBCExceptionHelper.extractSqlStateClassCode( sqlException );
+		Integer errorCode = new Integer( JDBCExceptionHelper.extractErrorCode( sqlException ) );
+		if ( sqlStateClassCode != null ) {
+			if ( SQL_GRAMMAR_CATEGORIES.contains( sqlStateClassCode ) ) {
+				return new SQLGrammarException( message, sqlException, sql );
+			}
+			else if ( INTEGRITY_VIOLATION_CATEGORIES.contains( errorCode ) ) {
+				String constraintName = extracter.extractConstraintName( sqlException );
+				return new ConstraintViolationException( message, sqlException, sql, constraintName );
+			}
+			else if ( CONNECTION_CATEGORIES.contains( sqlStateClassCode ) ) {
+				return new JDBCConnectionException( message, sqlException, sql );
+			}
+			else if ( DATA_CATEGORIES.contains( sqlStateClassCode ) ) {
+				return new DataException( message, sqlException, sql );
+			}
+		}
+		return handledNonSpecificException( sqlException, message, sql );
+	}
+
+	/**
+	 * Handle an exception not converted to a specific type based on the SQLState.
+	 *
+	 * @param sqlException The exception to be handled.
+	 * @param message	  An optional message
+	 * @param sql		  Optionally, the sql being performed when the exception occurred.
+	 * @return The converted exception; should <b>never</b> be null.
+	 */
+	protected JDBCException handledNonSpecificException(SQLException sqlException, String message, String sql) {
+		return new GenericJDBCException( message, sqlException, sql );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/Configurable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/Configurable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/Configurable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+// $Id: Configurable.java 4746 2004-11-11 20:57:28Z steveebersole $
+package org.hibernate.exception;
+
+import org.hibernate.HibernateException;
+
+import java.util.Properties;
+
+/**
+ * The Configurable interface defines the contract for SQLExceptionConverter impls that
+ * want to be configured prior to usage given the currently defined Hibernate properties.
+ *
+ * @author Steve Ebersole
+ */
+public interface Configurable {
+	// todo: this might really even be moved into the cfg package and used as the basis for all things which are configurable.
+
+	/**
+	 * Configure the component, using the given settings and properties.
+	 *
+	 * @param properties All defined startup properties.
+	 * @throws HibernateException Indicates a configuration exception.
+	 */
+	public void configure(Properties properties) throws HibernateException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/ConstraintViolationException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/ConstraintViolationException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/ConstraintViolationException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+// $Id: ConstraintViolationException.java 4782 2004-11-21 00:11:27Z pgmjsd $
+package org.hibernate.exception;
+
+import org.hibernate.JDBCException;
+
+import java.sql.SQLException;
+
+/**
+ * Implementation of JDBCException indicating that the requested DML operation
+ * resulted in a violation of a defined integrity constraint.
+ *
+ * @author Steve Ebersole
+ */
+public class ConstraintViolationException extends JDBCException {
+
+	private String constraintName;
+
+	public ConstraintViolationException(String message, SQLException root, String constraintName) {
+		super( message, root );
+		this.constraintName = constraintName;
+	}
+
+	public ConstraintViolationException(String message, SQLException root, String sql, String constraintName) {
+		super( message, root, sql );
+		this.constraintName = constraintName;
+	}
+
+	/**
+	 * Returns the name of the violated constraint, if known.
+	 *
+	 * @return The name of the violated constraint, or null if not known.
+	 */
+	public String getConstraintName() {
+		return constraintName;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/DataException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/DataException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/DataException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+// $Id: DataException.java 8062 2005-09-01 15:41:46Z oneovthafew $
+package org.hibernate.exception;
+
+import org.hibernate.JDBCException;
+
+import java.sql.SQLException;
+
+/**
+ * Implementation of JDBCException indicating that evaluation of the
+ * valid SQL statement against the given data resulted in some
+ * illegal operation, mismatched types or incorrect cardinality.
+ *
+ * @author Gavin King
+ */
+public class DataException extends JDBCException {
+	/**
+	 * Constructor for JDBCException.
+	 *
+	 * @param root The underlying exception.
+	 */
+	public DataException(String message, SQLException root) {
+		super( message, root );
+	}
+
+	/**
+	 * Constructor for JDBCException.
+	 *
+	 * @param message Optional message.
+	 * @param root    The underlying exception.
+	 */
+	public DataException(String message, SQLException root, String sql) {
+		super( message, root, sql );
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/DataException.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/ExceptionUtils.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/ExceptionUtils.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/ExceptionUtils.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,734 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowledgement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgement may appear in the software itself,
+ *    if and wherever such third-party acknowledgements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache at apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.hibernate.exception;
+
+import org.hibernate.util.ArrayHelper;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * <p>Provides utilities for manipulating and examining
+ * <code>Throwable</code> objects.</p>
+ *
+ * @author <a href="mailto:dlr at finemaltcoding.com">Daniel Rall</a>
+ * @author Dmitri Plotnikov
+ * @author Stephen Colebourne
+ * @author <a href="mailto:ggregory at seagullsw.com">Gary Gregory</a>
+ * @author Pete Gieser
+ * @version $Id: ExceptionUtils.java 4782 2004-11-21 00:11:27Z pgmjsd $
+ * @since 1.0
+ */
+public final class ExceptionUtils {
+
+	private static final String LINE_SEPARATOR = System.getProperty( "line.separator" );
+
+	/**
+	 * <p>Used when printing stack frames to denote the start of a
+	 * wrapped exception.</p>
+	 * <p/>
+	 * <p>Package private for accessibility by test suite.</p>
+	 */
+	static final String WRAPPED_MARKER = " [wrapped] ";
+
+	/**
+	 * <p>The names of methods commonly used to access a wrapped exception.</p>
+	 */
+	private static final String[] CAUSE_METHOD_NAMES = {
+		"getCause",
+		"getNextException",
+		"getTargetException",
+		"getException",
+		"getSourceException",
+		"getRootCause",
+		"getCausedByException",
+		"getNested"
+	};
+
+	/**
+	 * <p>The Method object for JDK1.4 getCause.</p>
+	 */
+	private static final Method THROWABLE_CAUSE_METHOD;
+
+	static {
+		Method getCauseMethod;
+		try {
+			getCauseMethod = Throwable.class.getMethod( "getCause", null );
+		}
+		catch ( Exception e ) {
+			getCauseMethod = null;
+		}
+		THROWABLE_CAUSE_METHOD = getCauseMethod;
+	}
+
+	private ExceptionUtils() {
+	}
+
+	//-----------------------------------------------------------------------
+	/**
+	 * <p>Adds to the list of method names used in the search for <code>Throwable</code>
+	 * objects.</p>
+	 *
+	 * @param methodName  the methodName to add to the list, <code>null</code>
+	 *  and empty strings are ignored
+	 * @since 2.0
+	 */
+	/*public static void addCauseMethodName(String methodName) {
+		if ( StringHelper.isNotEmpty(methodName) ) {
+			List list = new ArrayList( Arrays.asList(CAUSE_METHOD_NAMES );
+			list.add(methodName);
+			CAUSE_METHOD_NAMES = (String[]) list.toArray(new String[list.size()]);
+		}
+	}*/
+
+	/**
+	 * <p>Introspects the <code>Throwable</code> to obtain the cause.</p>
+	 * <p/>
+	 * <p>The method searches for methods with specific names that return a
+	 * <code>Throwable</code> object. This will pick up most wrapping exceptions,
+	 * including those from JDK 1.4, and
+	 * {@link org.apache.commons.lang.exception.NestableException NestableException}.
+	 * The method names can be added to using {@link #addCauseMethodName(String)}.</p>
+	 * <p/>
+	 * <p>The default list searched for are:</p>
+	 * <ul>
+	 * <li><code>getCause()</code></li>
+	 * <li><code>getNextException()</code></li>
+	 * <li><code>getTargetException()</code></li>
+	 * <li><code>getException()</code></li>
+	 * <li><code>getSourceException()</code></li>
+	 * <li><code>getRootCause()</code></li>
+	 * <li><code>getCausedByException()</code></li>
+	 * <li><code>getNested()</code></li>
+	 * </ul>
+	 * <p/>
+	 * <p>In the absence of any such method, the object is inspected for a
+	 * <code>detail</code> field assignable to a <code>Throwable</code>.</p>
+	 * <p/>
+	 * <p>If none of the above is found, returns <code>null</code>.</p>
+	 *
+	 * @param throwable the throwable to introspect for a cause, may be null
+	 * @return the cause of the <code>Throwable</code>,
+	 *         <code>null</code> if none found or null throwable input
+	 */
+	public static Throwable getCause(Throwable throwable) {
+		return getCause( throwable, CAUSE_METHOD_NAMES );
+	}
+
+	/**
+	 * <p>Introspects the <code>Throwable</code> to obtain the cause.</p>
+	 * <p/>
+	 * <ol>
+	 * <li>Try known exception types.</li>
+	 * <li>Try the supplied array of method names.</li>
+	 * <li>Try the field 'detail'.</li>
+	 * </ol>
+	 * <p/>
+	 * <p>A <code>null</code> set of method names means use the default set.
+	 * A <code>null</code> in the set of method names will be ignored.</p>
+	 *
+	 * @param throwable   the throwable to introspect for a cause, may be null
+	 * @param methodNames the method names, null treated as default set
+	 * @return the cause of the <code>Throwable</code>,
+	 *         <code>null</code> if none found or null throwable input
+	 */
+	public static Throwable getCause(Throwable throwable, String[] methodNames) {
+		if ( throwable == null ) {
+			return null;
+		}
+		Throwable cause = getCauseUsingWellKnownTypes( throwable );
+		if ( cause == null ) {
+			if ( methodNames == null ) {
+				methodNames = CAUSE_METHOD_NAMES;
+			}
+			for ( int i = 0; i < methodNames.length; i++ ) {
+				String methodName = methodNames[i];
+				if ( methodName != null ) {
+					cause = getCauseUsingMethodName( throwable, methodName );
+					if ( cause != null ) {
+						break;
+					}
+				}
+			}
+
+			if ( cause == null ) {
+				cause = getCauseUsingFieldName( throwable, "detail" );
+			}
+		}
+		return cause;
+	}
+
+	/**
+	 * <p>Introspects the <code>Throwable</code> to obtain the root cause.</p>
+	 * <p/>
+	 * <p>This method walks through the exception chain to the last element,
+	 * "root" of the tree, using {@link #getCause(Throwable)}, and
+	 * returns that exception.</p>
+	 *
+	 * @param throwable the throwable to get the root cause for, may be null
+	 * @return the root cause of the <code>Throwable</code>,
+	 *         <code>null</code> if none found or null throwable input
+	 */
+	public static Throwable getRootCause(Throwable throwable) {
+		Throwable cause = getCause( throwable );
+		if ( cause != null ) {
+			throwable = cause;
+			while ( ( throwable = getCause( throwable ) ) != null ) {
+				cause = throwable;
+			}
+		}
+		return cause;
+	}
+
+	/**
+	 * <p>Finds a <code>Throwable</code> for known types.</p>
+	 * <p/>
+	 * <p>Uses <code>instanceof</code> checks to examine the exception,
+	 * looking for well known types which could contain chained or
+	 * wrapped exceptions.</p>
+	 *
+	 * @param throwable the exception to examine
+	 * @return the wrapped exception, or <code>null</code> if not found
+	 */
+	private static Throwable getCauseUsingWellKnownTypes(Throwable throwable) {
+		if ( throwable instanceof Nestable ) {
+			return ( ( Nestable ) throwable ).getCause();
+		}
+		else if ( throwable instanceof SQLException ) {
+			return ( ( SQLException ) throwable ).getNextException();
+		}
+		else if ( throwable instanceof InvocationTargetException ) {
+			return ( ( InvocationTargetException ) throwable ).getTargetException();
+		}
+		else {
+			return null;
+		}
+	}
+
+	/**
+	 * <p>Finds a <code>Throwable</code> by method name.</p>
+	 *
+	 * @param throwable  the exception to examine
+	 * @param methodName the name of the method to find and invoke
+	 * @return the wrapped exception, or <code>null</code> if not found
+	 */
+	private static Throwable getCauseUsingMethodName(Throwable throwable, String methodName) {
+		Method method = null;
+		try {
+			method = throwable.getClass().getMethod( methodName, null );
+		}
+		catch ( NoSuchMethodException ignored ) {
+		}
+		catch ( SecurityException ignored ) {
+		}
+
+		if ( method != null && Throwable.class.isAssignableFrom( method.getReturnType() ) ) {
+			try {
+				return ( Throwable ) method.invoke( throwable, ArrayHelper.EMPTY_OBJECT_ARRAY );
+			}
+			catch ( IllegalAccessException ignored ) {
+			}
+			catch ( IllegalArgumentException ignored ) {
+			}
+			catch ( InvocationTargetException ignored ) {
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * <p>Finds a <code>Throwable</code> by field name.</p>
+	 *
+	 * @param throwable the exception to examine
+	 * @param fieldName the name of the attribute to examine
+	 * @return the wrapped exception, or <code>null</code> if not found
+	 */
+	private static Throwable getCauseUsingFieldName(Throwable throwable, String fieldName) {
+		Field field = null;
+		try {
+			field = throwable.getClass().getField( fieldName );
+		}
+		catch ( NoSuchFieldException ignored ) {
+		}
+		catch ( SecurityException ignored ) {
+		}
+
+		if ( field != null && Throwable.class.isAssignableFrom( field.getType() ) ) {
+			try {
+				return ( Throwable ) field.get( throwable );
+			}
+			catch ( IllegalAccessException ignored ) {
+			}
+			catch ( IllegalArgumentException ignored ) {
+			}
+		}
+		return null;
+	}
+
+	//-----------------------------------------------------------------------
+	/**
+	 * <p>Checks if the Throwable class has a <code>getCause</code> method.</p>
+	 * <p/>
+	 * <p>This is true for JDK 1.4 and above.</p>
+	 *
+	 * @return true if Throwable is nestable
+	 * @since 2.0
+	 */
+	public static boolean isThrowableNested() {
+		return ( THROWABLE_CAUSE_METHOD != null );
+	}
+
+	/**
+	 * <p>Checks whether this <code>Throwable</code> class can store a cause.</p>
+	 * <p/>
+	 * <p>This method does <b>not</b> check whether it actually does store a cause.<p>
+	 *
+	 * @param throwable the <code>Throwable</code> to examine, may be null
+	 * @return boolean <code>true</code> if nested otherwise <code>false</code>
+	 * @since 2.0
+	 */
+	public static boolean isNestedThrowable(Throwable throwable) {
+		if ( throwable == null ) {
+			return false;
+		}
+
+		if ( throwable instanceof Nestable ) {
+			return true;
+		}
+		else if ( throwable instanceof SQLException ) {
+			return true;
+		}
+		else if ( throwable instanceof InvocationTargetException ) {
+			return true;
+		}
+		else if ( isThrowableNested() ) {
+			return true;
+		}
+
+		Class cls = throwable.getClass();
+		for ( int i = 0, isize = CAUSE_METHOD_NAMES.length; i < isize; i++ ) {
+			try {
+				Method method = cls.getMethod( CAUSE_METHOD_NAMES[i], null );
+				if ( method != null && Throwable.class.isAssignableFrom( method.getReturnType() ) ) {
+					return true;
+				}
+			}
+			catch ( NoSuchMethodException ignored ) {
+			}
+			catch ( SecurityException ignored ) {
+			}
+		}
+
+		try {
+			Field field = cls.getField( "detail" );
+			if ( field != null ) {
+				return true;
+			}
+		}
+		catch ( NoSuchFieldException ignored ) {
+		}
+		catch ( SecurityException ignored ) {
+		}
+
+		return false;
+	}
+
+	//-----------------------------------------------------------------------
+	/**
+	 * <p>Counts the number of <code>Throwable</code> objects in the
+	 * exception chain.</p>
+	 * <p/>
+	 * <p>A throwable without cause will return <code>1</code>.
+	 * A throwable with one cause will return <code>2</code> and so on.
+	 * A <code>null</code> throwable will return <code>0</code>.</p>
+	 *
+	 * @param throwable the throwable to inspect, may be null
+	 * @return the count of throwables, zero if null input
+	 */
+	public static int getThrowableCount(Throwable throwable) {
+		int count = 0;
+		while ( throwable != null ) {
+			count++;
+			throwable = ExceptionUtils.getCause( throwable );
+		}
+		return count;
+	}
+
+	/**
+	 * <p>Returns the list of <code>Throwable</code> objects in the
+	 * exception chain.</p>
+	 * <p/>
+	 * <p>A throwable without cause will return an array containing
+	 * one element - the input throwable.
+	 * A throwable with one cause will return an array containing
+	 * two elements. - the input throwable and the cause throwable.
+	 * A <code>null</code> throwable will return an array size zero.</p>
+	 *
+	 * @param throwable the throwable to inspect, may be null
+	 * @return the array of throwables, never null
+	 */
+	public static Throwable[] getThrowables(Throwable throwable) {
+		List list = new ArrayList();
+		while ( throwable != null ) {
+			list.add( throwable );
+			throwable = ExceptionUtils.getCause( throwable );
+		}
+		return ( Throwable[] ) list.toArray( new Throwable[list.size()] );
+	}
+
+	//-----------------------------------------------------------------------
+	/**
+	 * <p>Returns the (zero based) index of the first <code>Throwable</code>
+	 * that matches the specified type in the exception chain.</p>
+	 * <p/>
+	 * <p>A <code>null</code> throwable returns <code>-1</code>.
+	 * A <code>null</code> type returns <code>-1</code>.
+	 * No match in the chain returns <code>-1</code>.</p>
+	 *
+	 * @param throwable the throwable to inspect, may be null
+	 * @param type      the type to search for
+	 * @return the index into the throwable chain, -1 if no match or null input
+	 */
+	public static int indexOfThrowable(Throwable throwable, Class type) {
+		return indexOfThrowable( throwable, type, 0 );
+	}
+
+	/**
+	 * <p>Returns the (zero based) index of the first <code>Throwable</code>
+	 * that matches the specified type in the exception chain from
+	 * a specified index.</p>
+	 * <p/>
+	 * <p>A <code>null</code> throwable returns <code>-1</code>.
+	 * A <code>null</code> type returns <code>-1</code>.
+	 * No match in the chain returns <code>-1</code>.
+	 * A negative start index is treated as zero.
+	 * A start index greater than the number of throwables returns <code>-1</code>.</p>
+	 *
+	 * @param throwable the throwable to inspect, may be null
+	 * @param type      the type to search for
+	 * @param fromIndex the (zero based) index of the starting position,
+	 *                  negative treated as zero, larger than chain size returns -1
+	 * @return the index into the throwable chain, -1 if no match or null input
+	 */
+	public static int indexOfThrowable(Throwable throwable, Class type, int fromIndex) {
+		if ( throwable == null ) {
+			return -1;
+		}
+		if ( fromIndex < 0 ) {
+			fromIndex = 0;
+		}
+		Throwable[] throwables = ExceptionUtils.getThrowables( throwable );
+		if ( fromIndex >= throwables.length ) {
+			return -1;
+		}
+		for ( int i = fromIndex; i < throwables.length; i++ ) {
+			if ( throwables[i].getClass().equals( type ) ) {
+				return i;
+			}
+		}
+		return -1;
+	}
+
+	//-----------------------------------------------------------------------
+	/**
+	 * <p>Prints a compact stack trace for the root cause of a throwable
+	 * to <code>System.err</code>.</p>
+	 * <p/>
+	 * <p>The compact stack trace starts with the root cause and prints
+	 * stack frames up to the place where it was caught and wrapped.
+	 * Then it prints the wrapped exception and continues with stack frames
+	 * until the wrapper exception is caught and wrapped again, etc.</p>
+	 * <p/>
+	 * <p>The method is equivalent to <code>printStackTrace</code> for throwables
+	 * that don't have nested causes.</p>
+	 *
+	 * @param throwable the throwable to output
+	 * @since 2.0
+	 */
+	public static void printRootCauseStackTrace(Throwable throwable) {
+		printRootCauseStackTrace( throwable, System.err );
+	}
+
+	/**
+	 * <p>Prints a compact stack trace for the root cause of a throwable.</p>
+	 * <p/>
+	 * <p>The compact stack trace starts with the root cause and prints
+	 * stack frames up to the place where it was caught and wrapped.
+	 * Then it prints the wrapped exception and continues with stack frames
+	 * until the wrapper exception is caught and wrapped again, etc.</p>
+	 * <p/>
+	 * <p>The method is equivalent to <code>printStackTrace</code> for throwables
+	 * that don't have nested causes.</p>
+	 *
+	 * @param throwable the throwable to output, may be null
+	 * @param stream    the stream to output to, may not be null
+	 * @throws IllegalArgumentException if the stream is <code>null</code>
+	 * @since 2.0
+	 */
+	public static void printRootCauseStackTrace(Throwable throwable, PrintStream stream) {
+		if ( throwable == null ) {
+			return;
+		}
+		if ( stream == null ) {
+			throw new IllegalArgumentException( "The PrintStream must not be null" );
+		}
+		String trace[] = getRootCauseStackTrace( throwable );
+		for ( int i = 0; i < trace.length; i++ ) {
+			stream.println( trace[i] );
+		}
+		stream.flush();
+	}
+
+	/**
+	 * <p>Prints a compact stack trace for the root cause of a throwable.</p>
+	 * <p/>
+	 * <p>The compact stack trace starts with the root cause and prints
+	 * stack frames up to the place where it was caught and wrapped.
+	 * Then it prints the wrapped exception and continues with stack frames
+	 * until the wrapper exception is caught and wrapped again, etc.</p>
+	 * <p/>
+	 * <p>The method is equivalent to <code>printStackTrace</code> for throwables
+	 * that don't have nested causes.</p>
+	 *
+	 * @param throwable the throwable to output, may be null
+	 * @param writer    the writer to output to, may not be null
+	 * @throws IllegalArgumentException if the writer is <code>null</code>
+	 * @since 2.0
+	 */
+	public static void printRootCauseStackTrace(Throwable throwable, PrintWriter writer) {
+		if ( throwable == null ) {
+			return;
+		}
+		if ( writer == null ) {
+			throw new IllegalArgumentException( "The PrintWriter must not be null" );
+		}
+		String trace[] = getRootCauseStackTrace( throwable );
+		for ( int i = 0; i < trace.length; i++ ) {
+			writer.println( trace[i] );
+		}
+		writer.flush();
+	}
+
+	//-----------------------------------------------------------------------
+	/**
+	 * <p>Creates a compact stack trace for the root cause of the supplied
+	 * <code>Throwable</code>.</p>
+	 *
+	 * @param throwable the throwable to examine, may be null
+	 * @return an array of stack trace frames, never null
+	 * @since 2.0
+	 */
+	public static String[] getRootCauseStackTrace(Throwable throwable) {
+		if ( throwable == null ) {
+			return ArrayHelper.EMPTY_STRING_ARRAY;
+		}
+		Throwable throwables[] = getThrowables( throwable );
+		int count = throwables.length;
+		ArrayList frames = new ArrayList();
+		List nextTrace = getStackFrameList( throwables[count - 1] );
+		for ( int i = count; --i >= 0; ) {
+			List trace = nextTrace;
+			if ( i != 0 ) {
+				nextTrace = getStackFrameList( throwables[i - 1] );
+				removeCommonFrames( trace, nextTrace );
+			}
+			if ( i == count - 1 ) {
+				frames.add( throwables[i].toString() );
+			}
+			else {
+				frames.add( WRAPPED_MARKER + throwables[i].toString() );
+			}
+			for ( int j = 0; j < trace.size(); j++ ) {
+				frames.add( trace.get( j ) );
+			}
+		}
+		return ( String[] ) frames.toArray( new String[0] );
+	}
+
+	/**
+	 * <p>Removes common frames from the cause trace given the two stack traces.</p>
+	 *
+	 * @param causeFrames   stack trace of a cause throwable
+	 * @param wrapperFrames stack trace of a wrapper throwable
+	 * @throws IllegalArgumentException if either argument is null
+	 * @since 2.0
+	 */
+	public static void removeCommonFrames(List causeFrames, List wrapperFrames) {
+		if ( causeFrames == null || wrapperFrames == null ) {
+			throw new IllegalArgumentException( "The List must not be null" );
+		}
+		int causeFrameIndex = causeFrames.size() - 1;
+		int wrapperFrameIndex = wrapperFrames.size() - 1;
+		while ( causeFrameIndex >= 0 && wrapperFrameIndex >= 0 ) {
+			// Remove the frame from the cause trace if it is the same
+			// as in the wrapper trace
+			String causeFrame = ( String ) causeFrames.get( causeFrameIndex );
+			String wrapperFrame = ( String ) wrapperFrames.get( wrapperFrameIndex );
+			if ( causeFrame.equals( wrapperFrame ) ) {
+				causeFrames.remove( causeFrameIndex );
+			}
+			causeFrameIndex--;
+			wrapperFrameIndex--;
+		}
+	}
+
+	//-----------------------------------------------------------------------
+	/**
+	 * <p>Gets the stack trace from a Throwable as a String.</p>
+	 *
+	 * @param throwable the <code>Throwable</code> to be examined
+	 * @return the stack trace as generated by the exception's
+	 *         <code>printStackTrace(PrintWriter)</code> method
+	 */
+	public static String getStackTrace(Throwable throwable) {
+		StringWriter sw = new StringWriter();
+		PrintWriter pw = new PrintWriter( sw, true );
+		throwable.printStackTrace( pw );
+		return sw.getBuffer().toString();
+	}
+
+	/**
+	 * <p>A way to get the entire nested stack-trace of an throwable.</p>
+	 *
+	 * @param throwable the <code>Throwable</code> to be examined
+	 * @return the nested stack trace, with the root cause first
+	 * @since 2.0
+	 */
+	public static String getFullStackTrace(Throwable throwable) {
+		StringWriter sw = new StringWriter();
+		PrintWriter pw = new PrintWriter( sw, true );
+		Throwable[] ts = getThrowables( throwable );
+		for ( int i = 0; i < ts.length; i++ ) {
+			ts[i].printStackTrace( pw );
+			if ( isNestedThrowable( ts[i] ) ) {
+				break;
+			}
+		}
+		return sw.getBuffer().toString();
+	}
+
+	//-----------------------------------------------------------------------
+	/**
+	 * <p>Captures the stack trace associated with the specified
+	 * <code>Throwable</code> object, decomposing it into a list of
+	 * stack frames.</p>
+	 *
+	 * @param throwable the <code>Throwable</code> to exaamine, may be null
+	 * @return an array of strings describing each stack frame, never null
+	 */
+	public static String[] getStackFrames(Throwable throwable) {
+		if ( throwable == null ) {
+			return ArrayHelper.EMPTY_STRING_ARRAY;
+		}
+		return getStackFrames( getStackTrace( throwable ) );
+	}
+
+	/**
+	 * <p>Functionality shared between the
+	 * <code>getStackFrames(Throwable)</code> methods of this and the
+	 * {@link org.apache.commons.lang.exception.NestableDelegate}
+	 * classes.</p>
+	 */
+	static String[] getStackFrames(String stackTrace) {
+		String linebreak = LINE_SEPARATOR;
+		StringTokenizer frames = new StringTokenizer( stackTrace, linebreak );
+		List list = new LinkedList();
+		while ( frames.hasMoreTokens() ) {
+			list.add( frames.nextToken() );
+		}
+		return ( String[] ) list.toArray( new String[list.size()] );
+	}
+
+	/**
+	 * <p>Produces a <code>List</code> of stack frames - the message
+	 * is not included.</p>
+	 * <p/>
+	 * <p>This works in most cases - it will only fail if the exception
+	 * message contains a line that starts with:
+	 * <code>&quot;&nbsp;&nbsp;&nbsp;at&quot;.</code></p>
+	 *
+	 * @param t is any throwable
+	 * @return List of stack frames
+	 */
+	static List getStackFrameList(Throwable t) {
+		String stackTrace = getStackTrace( t );
+		String linebreak = LINE_SEPARATOR;
+		StringTokenizer frames = new StringTokenizer( stackTrace, linebreak );
+		List list = new LinkedList();
+		boolean traceStarted = false;
+		while ( frames.hasMoreTokens() ) {
+			String token = frames.nextToken();
+			// Determine if the line starts with <whitespace>at
+			int at = token.indexOf( "at" );
+			if ( at != -1 && token.substring( 0, at ).trim().length() == 0 ) {
+				traceStarted = true;
+				list.add( token );
+			}
+			else if ( traceStarted ) {
+				break;
+			}
+		}
+		return list;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/GenericJDBCException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/GenericJDBCException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/GenericJDBCException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+// $Id: GenericJDBCException.java 4782 2004-11-21 00:11:27Z pgmjsd $
+package org.hibernate.exception;
+
+import org.hibernate.JDBCException;
+
+import java.sql.SQLException;
+
+/**
+ * Generic, non-specific JDBCException.
+ *
+ * @author Steve Ebersole
+ */
+public class GenericJDBCException extends JDBCException {
+	public GenericJDBCException(String string, SQLException root) {
+		super( string, root );
+	}
+
+	public GenericJDBCException(String string, SQLException root, String sql) {
+		super( string, root, sql );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/JDBCConnectionException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/JDBCConnectionException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/JDBCConnectionException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+// $Id: JDBCConnectionException.java 4782 2004-11-21 00:11:27Z pgmjsd $
+package org.hibernate.exception;
+
+import org.hibernate.JDBCException;
+
+import java.sql.SQLException;
+
+/**
+ * Implementation of JDBCException indicating problems with communicating with the
+ * database (can also include incorrect JDBC setup).
+ *
+ * @author Steve Ebersole
+ */
+public class JDBCConnectionException extends JDBCException {
+	public JDBCConnectionException(String string, SQLException root) {
+		super( string, root );
+	}
+
+	public JDBCConnectionException(String string, SQLException root, String sql) {
+		super( string, root, sql );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/JDBCExceptionHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/JDBCExceptionHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/JDBCExceptionHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,94 @@
+// $Id: JDBCExceptionHelper.java 9557 2006-03-06 15:16:27Z steve.ebersole at jboss.com $
+package org.hibernate.exception;
+
+import org.hibernate.JDBCException;
+import org.hibernate.util.JDBCExceptionReporter;
+
+import java.sql.SQLException;
+
+/**
+ * Implementation of JDBCExceptionHelper.
+ *
+ * @author Steve Ebersole
+ */
+public final class JDBCExceptionHelper {
+
+	private JDBCExceptionHelper() {
+	}
+
+	/**
+	 * Converts the given SQLException into Hibernate's JDBCException hierarchy, as well as performing
+	 * appropriate logging.
+	 *
+	 * @param converter    The converter to use.
+	 * @param sqlException The exception to convert.
+	 * @param message      An optional error message.
+	 * @return The converted JDBCException.
+	 */
+	public static JDBCException convert(SQLExceptionConverter converter, SQLException sqlException, String message) {
+		return convert( converter, sqlException, message, "???" );
+	}
+
+	/**
+	 * Converts the given SQLException into Hibernate's JDBCException hierarchy, as well as performing
+	 * appropriate logging.
+	 *
+	 * @param converter    The converter to use.
+	 * @param sqlException The exception to convert.
+	 * @param message      An optional error message.
+	 * @return The converted JDBCException.
+	 */
+	public static JDBCException convert(SQLExceptionConverter converter, SQLException sqlException, String message, String sql) {
+		JDBCExceptionReporter.logExceptions( sqlException, message + " [" + sql + "]" );
+		return converter.convert( sqlException, message, sql );
+	}
+
+	/**
+	 * For the given SQLException, locates the vendor-specific error code.
+	 *
+	 * @param sqlException The exception from which to extract the SQLState
+	 * @return The error code.
+	 */
+	public static int extractErrorCode(SQLException sqlException) {
+		int errorCode = sqlException.getErrorCode();
+		SQLException nested = sqlException.getNextException();
+		while ( errorCode == 0 && nested != null ) {
+			errorCode = nested.getErrorCode();
+			nested = nested.getNextException();
+		}
+		return errorCode;
+	}
+
+	/**
+	 * For the given SQLException, locates the X/Open-compliant SQLState.
+	 *
+	 * @param sqlException The exception from which to extract the SQLState
+	 * @return The SQLState code, or null.
+	 */
+	public static String extractSqlState(SQLException sqlException) {
+		String sqlState = sqlException.getSQLState();
+		SQLException nested = sqlException.getNextException();
+		while ( sqlState == null && nested != null ) {
+			sqlState = nested.getSQLState();
+			nested = nested.getNextException();
+		}
+		return sqlState;
+	}
+
+	/**
+	 * For the given SQLException, locates the X/Open-compliant SQLState's class code.
+	 *
+	 * @param sqlException The exception from which to extract the SQLState class code
+	 * @return The SQLState class code, or null.
+	 */
+	public static String extractSqlStateClassCode(SQLException sqlException) {
+		return determineSqlStateClassCode( extractSqlState( sqlException ) );
+	}
+
+	public static String determineSqlStateClassCode(String sqlState) {
+		if ( sqlState == null || sqlState.length() < 2 ) {
+			return sqlState;
+		}
+		return sqlState.substring( 0, 2 );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/LockAcquisitionException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/LockAcquisitionException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/LockAcquisitionException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+// $Id: LockAcquisitionException.java 4782 2004-11-21 00:11:27Z pgmjsd $
+package org.hibernate.exception;
+
+import org.hibernate.JDBCException;
+
+import java.sql.SQLException;
+
+/**
+ * Implementation of JDBCException indicating a problem acquiring lock
+ * on the database.
+ *
+ * @author Steve Ebersole
+ */
+public class LockAcquisitionException extends JDBCException {
+	public LockAcquisitionException(String string, SQLException root) {
+		super( string, root );
+	}
+
+	public LockAcquisitionException(String string, SQLException root, String sql) {
+		super( string, root, sql );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/Nestable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/Nestable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/Nestable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,203 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowledgement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgement may appear in the software itself,
+ *    if and wherever such third-party acknowledgements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache at apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.hibernate.exception;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * An interface to be implemented by {@link java.lang.Throwable}
+ * extensions which would like to be able to nest root exceptions
+ * inside themselves.
+ *
+ * @author <a href="mailto:dlr at collab.net">Daniel Rall</a>
+ * @author <a href="mailto:knielsen at apache.org">Kasper Nielsen</a>
+ * @author <a href="mailto:steven at caswell.name">Steven Caswell</a>
+ * @author Pete Gieser
+ * @version $Id: Nestable.java 4782 2004-11-21 00:11:27Z pgmjsd $
+ * @since 1.0
+ */
+public interface Nestable {
+
+	/**
+	 * Returns the reference to the exception or error that caused the
+	 * exception implementing the <code>Nestable</code> to be thrown.
+	 *
+	 * @return throwable that caused the original exception
+	 */
+	public Throwable getCause();
+
+	/**
+	 * Returns the error message of this and any nested
+	 * <code>Throwable</code>.
+	 *
+	 * @return the error message
+	 */
+	public String getMessage();
+
+	/**
+	 * Returns the error message of the <code>Throwable</code> in the chain
+	 * of <code>Throwable</code>s at the specified index, numbererd from 0.
+	 *
+	 * @param index the index of the <code>Throwable</code> in the chain of
+	 *              <code>Throwable</code>s
+	 * @return the error message, or null if the <code>Throwable</code> at the
+	 *         specified index in the chain does not contain a message
+	 * @throws IndexOutOfBoundsException if the <code>index</code> argument is
+	 *                                   negative or not less than the count of <code>Throwable</code>s in the
+	 *                                   chain
+	 */
+	public String getMessage(int index);
+
+	/**
+	 * Returns the error message of this and any nested <code>Throwable</code>s
+	 * in an array of Strings, one element for each message. Any
+	 * <code>Throwable</code> not containing a message is represented in the
+	 * array by a null. This has the effect of cause the length of the returned
+	 * array to be equal to the result of the {@link #getThrowableCount()}
+	 * operation.
+	 *
+	 * @return the error messages
+	 */
+	public String[] getMessages();
+
+	/**
+	 * Returns the <code>Throwable</code> in the chain of
+	 * <code>Throwable</code>s at the specified index, numbererd from 0.
+	 *
+	 * @param index the index, numbered from 0, of the <code>Throwable</code> in
+	 *              the chain of <code>Throwable</code>s
+	 * @return the <code>Throwable</code>
+	 * @throws IndexOutOfBoundsException if the <code>index</code> argument is
+	 *                                   negative or not less than the count of <code>Throwable</code>s in the
+	 *                                   chain
+	 */
+	public Throwable getThrowable(int index);
+
+	/**
+	 * Returns the number of nested <code>Throwable</code>s represented by
+	 * this <code>Nestable</code>, including this <code>Nestable</code>.
+	 *
+	 * @return the throwable count
+	 */
+	public int getThrowableCount();
+
+	/**
+	 * Returns this <code>Nestable</code> and any nested <code>Throwable</code>s
+	 * in an array of <code>Throwable</code>s, one element for each
+	 * <code>Throwable</code>.
+	 *
+	 * @return the <code>Throwable</code>s
+	 */
+	public Throwable[] getThrowables();
+
+	/**
+	 * Returns the index, numbered from 0, of the first occurrence of the
+	 * specified type in the chain of <code>Throwable</code>s, or -1 if the
+	 * specified type is not found in the chain.
+	 *
+	 * @param type <code>Class</code> to be found
+	 * @return index of the first occurrence of the type in the chain, or -1 if
+	 *         the type is not found
+	 */
+	public int indexOfThrowable(Class type);
+
+	/**
+	 * Returns the index, numbered from 0, of the first <code>Throwable</code>
+	 * that matches the specified type in the chain of <code>Throwable</code>s
+	 * with an index greater than or equal to the specified index, or -1 if
+	 * the type is not found.
+	 *
+	 * @param type      <code>Class</code> to be found
+	 * @param fromIndex the index, numbered from 0, of the starting position in
+	 *                  the chain to be searched
+	 * @return index of the first occurrence of the type in the chain, or -1 if
+	 *         the type is not found
+	 * @throws IndexOutOfBoundsException if the <code>fromIndex</code> argument
+	 *                                   is negative or not less than the count of <code>Throwable</code>s in the
+	 *                                   chain
+	 */
+	public int indexOfThrowable(Class type, int fromIndex);
+
+	/**
+	 * Prints the stack trace of this exception to the specified print
+	 * writer.  Includes information from the exception, if any,
+	 * which caused this exception.
+	 *
+	 * @param out <code>PrintWriter</code> to use for output.
+	 */
+	public void printStackTrace(PrintWriter out);
+
+	/**
+	 * Prints the stack trace of this exception to the specified print
+	 * stream.  Includes inforamation from the exception, if any,
+	 * which caused this exception.
+	 *
+	 * @param out <code>PrintStream</code> to use for output.
+	 */
+	public void printStackTrace(PrintStream out);
+
+	/**
+	 * Prints the stack trace for this exception only--root cause not
+	 * included--using the provided writer.  Used by {@link
+	 * org.apache.commons.lang.exception.NestableDelegate} to write
+	 * individual stack traces to a buffer.  The implementation of
+	 * this method should call
+	 * <code>super.printStackTrace(out);</code> in most cases.
+	 *
+	 * @param out The writer to use.
+	 */
+	public void printPartialStackTrace(PrintWriter out);
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/NestableDelegate.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/NestableDelegate.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/NestableDelegate.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,412 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowledgement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgement may appear in the software itself,
+ *    if and wherever such third-party acknowledgements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache at apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.hibernate.exception;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * <p>A shared implementation of the nestable exception functionality.</p>
+ * <p/>
+ * The code is shared between
+ * {@link org.apache.commons.lang.exception.NestableError NestableError},
+ * {@link org.apache.commons.lang.exception.NestableException NestableException} and
+ * {@link org.apache.commons.lang.exception.NestableRuntimeException NestableRuntimeException}.
+ * </p>
+ *
+ * @author <a href="mailto:Rafal.Krzewski at e-point.pl">Rafal Krzewski</a>
+ * @author <a href="mailto:dlr at collab.net">Daniel Rall</a>
+ * @author <a href="mailto:knielsen at apache.org">Kasper Nielsen</a>
+ * @author <a href="mailto:steven at caswell.name">Steven Caswell</a>
+ * @author Sean C. Sullivan
+ * @author Stephen Colebourne
+ * @version $Id: NestableDelegate.java 4782 2004-11-21 00:11:27Z pgmjsd $
+ * @since 1.0
+ */
+public class NestableDelegate implements Serializable {
+
+	/**
+	 * Constructor error message.
+	 */
+	private static final String MUST_BE_THROWABLE =
+			"The Nestable implementation passed to the NestableDelegate(Nestable) "
+			+ "constructor must extend java.lang.Throwable";
+
+	/**
+	 * Holds the reference to the exception or error that we're
+	 * wrapping (which must be a {@link
+	 * org.apache.commons.lang.exception.Nestable} implementation).
+	 */
+	private Throwable nestable = null;
+
+	/**
+	 * Whether to print the stack trace top-down.
+	 * This public flag may be set by calling code, typically in initialisation.
+	 *
+	 * @since 2.0
+	 */
+	private static boolean topDown = true;
+
+	/**
+	 * Whether to trim the repeated stack trace.
+	 * This public flag may be set by calling code, typically in initialisation.
+	 *
+	 * @since 2.0
+	 */
+	private static boolean trimStackFrames = true;
+
+	/**
+	 * Constructs a new <code>NestableDelegate</code> instance to manage the
+	 * specified <code>Nestable</code>.
+	 *
+	 * @param nestable the Nestable implementation (<i>must</i> extend
+	 *                 {@link java.lang.Throwable})
+	 * @since 2.0
+	 */
+	public NestableDelegate(Nestable nestable) {
+		if ( nestable instanceof Throwable ) {
+			this.nestable = ( Throwable ) nestable;
+		}
+		else {
+			throw new IllegalArgumentException( MUST_BE_THROWABLE );
+		}
+	}
+
+	/**
+	 * Returns the error message of the <code>Throwable</code> in the chain
+	 * of <code>Throwable</code>s at the specified index, numbererd from 0.
+	 *
+	 * @param index the index of the <code>Throwable</code> in the chain of
+	 *              <code>Throwable</code>s
+	 * @return the error message, or null if the <code>Throwable</code> at the
+	 *         specified index in the chain does not contain a message
+	 * @throws IndexOutOfBoundsException if the <code>index</code> argument is
+	 *                                   negative or not less than the count of <code>Throwable</code>s in the
+	 *                                   chain
+	 * @since 2.0
+	 */
+	public String getMessage(int index) {
+		Throwable t = this.getThrowable( index );
+		if ( Nestable.class.isInstance( t ) ) {
+			return ( ( Nestable ) t ).getMessage( 0 );
+		}
+		else {
+			return t.getMessage();
+		}
+	}
+
+	/**
+	 * Returns the full message contained by the <code>Nestable</code>
+	 * and any nested <code>Throwable</code>s.
+	 *
+	 * @param baseMsg the base message to use when creating the full
+	 *                message. Should be generally be called via
+	 *                <code>nestableHelper.getMessage( super.getMessage() )</code>,
+	 *                where <code>super</code> is an instance of {@link
+	 *                java.lang.Throwable}.
+	 * @return The concatenated message for this and all nested
+	 *         <code>Throwable</code>s
+	 * @since 2.0
+	 */
+	public String getMessage(String baseMsg) {
+		StringBuffer msg = new StringBuffer();
+		if ( baseMsg != null ) {
+			msg.append( baseMsg );
+		}
+
+		Throwable nestedCause = ExceptionUtils.getCause( this.nestable );
+		if ( nestedCause != null ) {
+			String causeMsg = nestedCause.getMessage();
+			if ( causeMsg != null ) {
+				if ( baseMsg != null ) {
+					msg.append( ": " );
+				}
+				msg.append( causeMsg );
+			}
+
+		}
+		return ( msg.length() > 0 ? msg.toString() : null );
+	}
+
+	/**
+	 * Returns the error message of this and any nested <code>Throwable</code>s
+	 * in an array of Strings, one element for each message. Any
+	 * <code>Throwable</code> not containing a message is represented in the
+	 * array by a null. This has the effect of cause the length of the returned
+	 * array to be equal to the result of the {@link #getThrowableCount()}
+	 * operation.
+	 *
+	 * @return the error messages
+	 * @since 2.0
+	 */
+	public String[] getMessages() {
+		Throwable[] throwables = this.getThrowables();
+		String[] msgs = new String[throwables.length];
+		for ( int i = 0; i < throwables.length; i++ ) {
+			msgs[i] = Nestable.class.isInstance( throwables[i] ) ?
+					( ( Nestable ) throwables[i] ).getMessage( 0 ) :
+					throwables[i].getMessage();
+		}
+		return msgs;
+	}
+
+	/**
+	 * Returns the <code>Throwable</code> in the chain of
+	 * <code>Throwable</code>s at the specified index, numbererd from 0.
+	 *
+	 * @param index the index, numbered from 0, of the <code>Throwable</code> in
+	 *              the chain of <code>Throwable</code>s
+	 * @return the <code>Throwable</code>
+	 * @throws IndexOutOfBoundsException if the <code>index</code> argument is
+	 *                                   negative or not less than the count of <code>Throwable</code>s in the
+	 *                                   chain
+	 * @since 2.0
+	 */
+	public Throwable getThrowable(int index) {
+		if ( index == 0 ) {
+			return this.nestable;
+		}
+		Throwable[] throwables = this.getThrowables();
+		return throwables[index];
+	}
+
+	/**
+	 * Returns the number of <code>Throwable</code>s contained in the
+	 * <code>Nestable</code> contained by this delegate.
+	 *
+	 * @return the throwable count
+	 * @since 2.0
+	 */
+	public int getThrowableCount() {
+		return ExceptionUtils.getThrowableCount( this.nestable );
+	}
+
+	/**
+	 * Returns this delegate's <code>Nestable</code> and any nested
+	 * <code>Throwable</code>s in an array of <code>Throwable</code>s, one
+	 * element for each <code>Throwable</code>.
+	 *
+	 * @return the <code>Throwable</code>s
+	 * @since 2.0
+	 */
+	public Throwable[] getThrowables() {
+		return ExceptionUtils.getThrowables( this.nestable );
+	}
+
+	/**
+	 * Returns the index, numbered from 0, of the first <code>Throwable</code>
+	 * that matches the specified type in the chain of <code>Throwable</code>s
+	 * held in this delegate's <code>Nestable</code> with an index greater than
+	 * or equal to the specified index, or -1 if the type is not found.
+	 *
+	 * @param type      <code>Class</code> to be found
+	 * @param fromIndex the index, numbered from 0, of the starting position in
+	 *                  the chain to be searched
+	 * @return index of the first occurrence of the type in the chain, or -1 if
+	 *         the type is not found
+	 * @throws IndexOutOfBoundsException if the <code>fromIndex</code> argument
+	 *                                   is negative or not less than the count of <code>Throwable</code>s in the
+	 *                                   chain
+	 * @since 2.0
+	 */
+	public int indexOfThrowable(Class type, int fromIndex) {
+		if ( fromIndex < 0 ) {
+			throw new IndexOutOfBoundsException( "The start index was out of bounds: " + fromIndex );
+		}
+		Throwable[] throwables = ExceptionUtils.getThrowables( this.nestable );
+		if ( fromIndex >= throwables.length ) {
+			throw new IndexOutOfBoundsException( "The start index was out of bounds: "
+					+ fromIndex + " >= " + throwables.length );
+		}
+		for ( int i = fromIndex; i < throwables.length; i++ ) {
+			if ( throwables[i].getClass().equals( type ) ) {
+				return i;
+			}
+		}
+		return -1;
+	}
+
+	/**
+	 * Prints the stack trace of this exception the the standar error
+	 * stream.
+	 */
+	public void printStackTrace() {
+		printStackTrace( System.err );
+	}
+
+	/**
+	 * Prints the stack trace of this exception to the specified
+	 * stream.
+	 *
+	 * @param out <code>PrintStream</code> to use for output.
+	 * @see #printStackTrace(PrintWriter)
+	 */
+	public void printStackTrace(PrintStream out) {
+		synchronized ( out ) {
+			PrintWriter pw = new PrintWriter( out, false );
+			printStackTrace( pw );
+			// Flush the PrintWriter before it's GC'ed.
+			pw.flush();
+		}
+	}
+
+	/**
+	 * Prints the stack trace of this exception to the specified
+	 * writer. If the Throwable class has a <code>getCause</code>
+	 * method (i.e. running on jre1.4 or higher), this method just
+	 * uses Throwable's printStackTrace() method. Otherwise, generates
+	 * the stack-trace, by taking into account the 'topDown' and
+	 * 'trimStackFrames' parameters. The topDown and trimStackFrames
+	 * are set to 'true' by default (produces jre1.4-like stack trace).
+	 *
+	 * @param out <code>PrintWriter</code> to use for output.
+	 */
+	public void printStackTrace(PrintWriter out) {
+		Throwable throwable = this.nestable;
+		// if running on jre1.4 or higher, use default printStackTrace
+		if ( ExceptionUtils.isThrowableNested() ) {
+			if ( throwable instanceof Nestable ) {
+				( ( Nestable ) throwable ).printPartialStackTrace( out );
+			}
+			else {
+				throwable.printStackTrace( out );
+			}
+			return;
+		}
+
+		// generating the nested stack trace
+		List stacks = new ArrayList();
+		while ( throwable != null ) {
+			String[] st = getStackFrames( throwable );
+			stacks.add( st );
+			throwable = ExceptionUtils.getCause( throwable );
+		}
+
+		// If NOT topDown, reverse the stack
+		String separatorLine = "Caused by: ";
+		if ( !topDown ) {
+			separatorLine = "Rethrown as: ";
+			Collections.reverse( stacks );
+		}
+
+		// Remove the repeated lines in the stack
+		if ( trimStackFrames ) trimStackFrames( stacks );
+
+		synchronized ( out ) {
+			for ( Iterator iter = stacks.iterator(); iter.hasNext(); ) {
+				String[] st = ( String[] ) iter.next();
+				for ( int i = 0, len = st.length; i < len; i++ ) {
+					out.println( st[i] );
+				}
+				if ( iter.hasNext() ) out.print( separatorLine );
+			}
+		}
+	}
+
+	/**
+	 * Captures the stack trace associated with the specified
+	 * <code>Throwable</code> object, decomposing it into a list of
+	 * stack frames.
+	 *
+	 * @param t The <code>Throwable</code>.
+	 * @return An array of strings describing each stack frame.
+	 * @since 2.0
+	 */
+	protected String[] getStackFrames(Throwable t) {
+		StringWriter sw = new StringWriter();
+		PrintWriter pw = new PrintWriter( sw, true );
+
+		// Avoid infinite loop between decompose() and printStackTrace().
+		if ( t instanceof Nestable ) {
+			( ( Nestable ) t ).printPartialStackTrace( pw );
+		}
+		else {
+			t.printStackTrace( pw );
+		}
+		return ExceptionUtils.getStackFrames( sw.getBuffer().toString() );
+	}
+
+	/**
+	 * Trims the stack frames. The first set is left untouched. The rest
+	 * of the frames are truncated from the bottom by comparing with
+	 * one just on top.
+	 *
+	 * @param stacks The list containing String[] elements
+	 * @since 2.0
+	 */
+	protected void trimStackFrames(List stacks) {
+		for ( int size = stacks.size(), i = size - 1; i > 0; i-- ) {
+			String[] curr = ( String[] ) stacks.get( i );
+			String[] next = ( String[] ) stacks.get( i - 1 );
+
+			List currList = new ArrayList( Arrays.asList( curr ) );
+			List nextList = new ArrayList( Arrays.asList( next ) );
+			ExceptionUtils.removeCommonFrames( currList, nextList );
+
+			int trimmed = curr.length - currList.size();
+			if ( trimmed > 0 ) {
+				currList.add( "\t... " + trimmed + " more" );
+				stacks.set( i,
+						currList.toArray( new String[currList.size()] ) );
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/NestableException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/NestableException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/NestableException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,254 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowledgement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgement may appear in the software itself,
+ *    if and wherever such third-party acknowledgements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache at apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.hibernate.exception;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * The base class of all exceptions which can contain other exceptions.
+ * <p/>
+ * It is intended to ease the debugging by carrying on the information
+ * about the exception which was caught and provoked throwing the
+ * current exception. Catching and rethrowing may occur multiple
+ * times, and provided that all exceptions except the first one
+ * are descendands of <code>NestedException</code>, when the
+ * exception is finally printed out using any of the <code>
+ * printStackTrace()</code> methods, the stacktrace will contain
+ * the information about all exceptions thrown and caught on
+ * the way.
+ * <p> Running the following program
+ * <p><blockquote><pre>
+ *  1 import org.apache.commons.lang.exception.NestableException;
+ *  2
+ *  3 public class Test {
+ *  4     public static void main( String[] args ) {
+ *  5         try {
+ *  6             a();
+ *  7         } catch(Exception e) {
+ *  8             e.printStackTrace();
+ *  9         }
+ * 10      }
+ * 11
+ * 12      public static void a() throws Exception {
+ * 13          try {
+ * 14              b();
+ * 15          } catch(Exception e) {
+ * 16              throw new NestableException("foo", e);
+ * 17          }
+ * 18      }
+ * 19
+ * 20      public static void b() throws Exception {
+ * 21          try {
+ * 22              c();
+ * 23          } catch(Exception e) {
+ * 24              throw new NestableException("bar", e);
+ * 25          }
+ * 26      }
+ * 27
+ * 28      public static void c() throws Exception {
+ * 29          throw new Exception("baz");
+ * 30      }
+ * 31 }
+ * </pre></blockquote>
+ * <p>Yields the following stacktrace:
+ * <p><blockquote><pre>
+ * org.apache.commons.lang.exception.NestableException: foo
+ *         at Test.a(Test.java:16)
+ *         at Test.main(Test.java:6)
+ * Caused by: org.apache.commons.lang.exception.NestableException: bar
+ *         at Test.b(Test.java:24)
+ *         at Test.a(Test.java:14)
+ *         ... 1 more
+ * Caused by: java.lang.Exception: baz
+ *         at Test.c(Test.java:29)
+ *         at Test.b(Test.java:22)
+ *         ... 2 more
+ * </pre></blockquote><br>
+ *
+ * @author <a href="mailto:Rafal.Krzewski at e-point.pl">Rafal Krzewski</a>
+ * @author <a href="mailto:dlr at collab.net">Daniel Rall</a>
+ * @author <a href="mailto:knielsen at apache.org">Kasper Nielsen</a>
+ * @author <a href="mailto:steven at caswell.name">Steven Caswell</a>
+ * @version $Id: NestableException.java 4782 2004-11-21 00:11:27Z pgmjsd $
+ * @since 1.0
+ */
+public class NestableException extends Exception implements Nestable {
+
+	/**
+	 * The helper instance which contains much of the code which we
+	 * delegate to.
+	 */
+	protected NestableDelegate delegate = new NestableDelegate( this );
+
+	/**
+	 * Holds the reference to the exception or error that caused
+	 * this exception to be thrown.
+	 */
+	private Throwable cause = null;
+
+	/**
+	 * Constructs a new <code>NestableException</code> without specified
+	 * detail message.
+	 */
+	public NestableException() {
+		super();
+	}
+
+	/**
+	 * Constructs a new <code>NestableException</code> with specified
+	 * detail message.
+	 *
+	 * @param msg The error message.
+	 */
+	public NestableException(String msg) {
+		super( msg );
+	}
+
+	/**
+	 * Constructs a new <code>NestableException</code> with specified
+	 * nested <code>Throwable</code>.
+	 *
+	 * @param cause the exception or error that caused this exception to be
+	 *              thrown
+	 */
+	public NestableException(Throwable cause) {
+		super();
+		this.cause = cause;
+	}
+
+	/**
+	 * Constructs a new <code>NestableException</code> with specified
+	 * detail message and nested <code>Throwable</code>.
+	 *
+	 * @param msg   the error message
+	 * @param cause the exception or error that caused this exception to be
+	 *              thrown
+	 */
+	public NestableException(String msg, Throwable cause) {
+		super( msg );
+		this.cause = cause;
+	}
+
+	public Throwable getCause() {
+		return cause;
+	}
+
+	/**
+	 * Returns the detail message string of this throwable. If it was
+	 * created with a null message, returns the following:
+	 * ( cause==null ? null : cause.toString() ).
+	 */
+	public String getMessage() {
+		if ( super.getMessage() != null ) {
+			return super.getMessage();
+		}
+		else if ( cause != null ) {
+			return cause.toString();
+		}
+		else {
+			return null;
+		}
+	}
+
+	public String getMessage(int index) {
+		if ( index == 0 ) {
+			return super.getMessage();
+		}
+		else {
+			return delegate.getMessage( index );
+		}
+	}
+
+	public String[] getMessages() {
+		return delegate.getMessages();
+	}
+
+	public Throwable getThrowable(int index) {
+		return delegate.getThrowable( index );
+	}
+
+	public int getThrowableCount() {
+		return delegate.getThrowableCount();
+	}
+
+	public Throwable[] getThrowables() {
+		return delegate.getThrowables();
+	}
+
+	public int indexOfThrowable(Class type) {
+		return delegate.indexOfThrowable( type, 0 );
+	}
+
+	public int indexOfThrowable(Class type, int fromIndex) {
+		return delegate.indexOfThrowable( type, fromIndex );
+	}
+
+	public void printStackTrace() {
+		delegate.printStackTrace();
+	}
+
+	public void printStackTrace(PrintStream out) {
+		delegate.printStackTrace( out );
+	}
+
+	public void printStackTrace(PrintWriter out) {
+		delegate.printStackTrace( out );
+	}
+
+	public final void printPartialStackTrace(PrintWriter out) {
+		super.printStackTrace( out );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/NestableRuntimeException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/NestableRuntimeException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/NestableRuntimeException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,214 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowledgement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgement may appear in the software itself,
+ *    if and wherever such third-party acknowledgements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache at apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.hibernate.exception;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+
+import antlr.RecognitionException;
+
+/**
+ * The base class of all runtime exceptions which can contain other
+ * exceptions.
+ *
+ * @author <a href="mailto:Rafal.Krzewski at e-point.pl">Rafal Krzewski</a>
+ * @author <a href="mailto:dlr at collab.net">Daniel Rall</a>
+ * @author <a href="mailto:knielsen at apache.org">Kasper Nielsen</a>
+ * @author <a href="mailto:steven at caswell.name">Steven Caswell</a>
+ * @version $Id: NestableRuntimeException.java 8137 2005-09-09 15:21:10Z epbernard $
+ * @see org.apache.commons.lang.exception.NestableException
+ * @since 1.0
+ */
+public class NestableRuntimeException extends RuntimeException implements Nestable {
+
+	/**
+	 * The helper instance which contains much of the code which we
+	 * delegate to.
+	 */
+	protected NestableDelegate delegate = new NestableDelegate( this );
+
+	/**
+	 * Holds the reference to the exception or error that caused
+	 * this exception to be thrown.
+	 */
+	private Throwable cause = null;
+
+	/**
+	 * Constructs a new <code>NestableRuntimeException</code> without specified
+	 * detail message.
+	 */
+	public NestableRuntimeException() {
+		super();
+	}
+
+	/**
+	 * Constructs a new <code>NestableRuntimeException</code> with specified
+	 * detail message.
+	 *
+	 * @param msg the error message
+	 */
+	public NestableRuntimeException(String msg) {
+		super( msg );
+	}
+
+	/**
+	 * Constructs a new <code>NestableRuntimeException</code> with specified
+	 * nested <code>Throwable</code>.
+	 *
+	 * @param cause the exception or error that caused this exception to be
+	 *              thrown
+	 */
+	public NestableRuntimeException(Throwable cause) {
+		super();
+		this.cause = cause;
+	}
+
+	/**
+	 * Constructs a new <code>NestableRuntimeException</code> with specified
+	 * detail message and nested <code>Throwable</code>.
+	 *
+	 * @param msg   the error message
+	 * @param cause the exception or error that caused this exception to be
+	 *              thrown
+	 */
+	public NestableRuntimeException(String msg, Throwable cause) {
+		super( msg );
+		this.cause = cause;
+	}
+
+	public Throwable getCause() {
+		return cause;
+	}
+
+	/**
+	 * Returns the detail message string of this throwable. If it was
+	 * created with a null message, returns the following:
+	 * ( cause==null ? null : cause.toString( ).
+	 */
+	public String getMessage() {
+		if ( super.getMessage() != null ) {
+			return super.getMessage();
+		}
+		else if ( cause != null ) {
+			return cause.toString();
+		}
+		else {
+			return null;
+		}
+	}
+
+	public String getMessage(int index) {
+		if ( index == 0 ) {
+			return super.getMessage();
+		}
+		else {
+			return delegate.getMessage( index );
+		}
+	}
+
+	public String[] getMessages() {
+		return delegate.getMessages();
+	}
+
+	public Throwable getThrowable(int index) {
+		return delegate.getThrowable( index );
+	}
+
+	public int getThrowableCount() {
+		return delegate.getThrowableCount();
+	}
+
+	public Throwable[] getThrowables() {
+		return delegate.getThrowables();
+	}
+
+	public int indexOfThrowable(Class type) {
+		return delegate.indexOfThrowable( type, 0 );
+	}
+
+	public int indexOfThrowable(Class type, int fromIndex) {
+		return delegate.indexOfThrowable( type, fromIndex );
+	}
+
+	public void printStackTrace() {
+		delegate.printStackTrace();
+	}
+
+	public void printStackTrace(PrintStream out) {
+		delegate.printStackTrace( out );
+	}
+
+	public void printStackTrace(PrintWriter out) {
+		delegate.printStackTrace( out );
+	}
+
+	public final void printPartialStackTrace(PrintWriter out) {
+		super.printStackTrace( out );
+	}
+
+
+
+	private void writeObject(ObjectOutputStream oos) throws IOException {
+		Throwable tempCause = cause;
+		//don't propagate RecognitionException, might be not serializable
+		if ( cause instanceof RecognitionException ) {
+			cause = null;
+		}
+		oos.defaultWriteObject();
+		cause = tempCause;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLExceptionConverter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLExceptionConverter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLExceptionConverter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+// $Id: SQLExceptionConverter.java 4782 2004-11-21 00:11:27Z pgmjsd $
+package org.hibernate.exception;
+
+import org.hibernate.JDBCException;
+
+import java.sql.SQLException;
+
+/**
+ * Defines a contract for implementations that know how to convert a SQLException
+ * into Hibernate's JDBCException hierarchy.  Inspired by Spring's
+ * SQLExceptionTranslator.
+ * <p/>
+ * Implementations <b>must</b> have a constructor which takes a
+ * {@link ViolatedConstraintNameExtracter} parameter.
+ * <p/>
+ * Implementations may implement {@link Configurable} if they need to perform
+ * configuration steps prior to first use.
+ *
+ * @author Steve Ebersole
+ * @see SQLExceptionConverterFactory
+ */
+public interface SQLExceptionConverter {
+	/**
+	 * Convert the given SQLException into Hibernate's JDBCException hierarchy.
+	 *
+	 * @param sqlException The SQLException to be converted.
+	 * @param message      An optional error message.
+	 * @return The resulting JDBCException.
+	 * @see ConstraintViolationException, JDBCConnectionException, SQLGrammarException, LockAcquisitionException
+	 */
+	public JDBCException convert(SQLException sqlException, String message, String sql);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLExceptionConverterFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLExceptionConverterFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLExceptionConverterFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,114 @@
+// $Id: SQLExceptionConverterFactory.java 4782 2004-11-21 00:11:27Z pgmjsd $
+package org.hibernate.exception;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.JDBCException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.StringHelper;
+
+import java.lang.reflect.Constructor;
+import java.sql.SQLException;
+import java.util.Properties;
+
+/**
+ * A factory for building SQLExceptionConverter instances.
+ *
+ * @author Steve Ebersole
+ */
+public class SQLExceptionConverterFactory {
+
+	private static final Log log = LogFactory.getLog( SQLExceptionConverterFactory.class );
+
+	private SQLExceptionConverterFactory() {
+		// Private constructor - stops checkstyle from complaining.
+	}
+
+	/**
+	 * Build a SQLExceptionConverter instance.
+	 * <p/>
+	 * First, looks for a {@link Environment.SQL_EXCEPTION_CONVERTER} property to see
+	 * if the configuration specified the class of a specific converter to use.  If this
+	 * property is set, attempt to construct an instance of that class.  If not set, or
+	 * if construction fails, the converter specific to the dialect will be used.
+	 *
+	 * @param dialect    The defined dialect.
+	 * @param properties The configuration properties.
+	 * @return An appropriate SQLExceptionConverter instance.
+	 * @throws HibernateException There was an error building the SQLExceptionConverter.
+	 */
+	public static SQLExceptionConverter buildSQLExceptionConverter(Dialect dialect, Properties properties) throws HibernateException {
+		SQLExceptionConverter converter = null;
+
+		String converterClassName = ( String ) properties.get( Environment.SQL_EXCEPTION_CONVERTER );
+		if ( StringHelper.isNotEmpty( converterClassName ) ) {
+			converter = constructConverter( converterClassName, dialect.getViolatedConstraintNameExtracter() );
+		}
+
+		if ( converter == null ) {
+			log.trace( "Using dialect defined converter" );
+			converter = dialect.buildSQLExceptionConverter();
+		}
+
+		if ( converter instanceof Configurable ) {
+			try {
+				( ( Configurable ) converter ).configure( properties );
+			}
+			catch ( HibernateException e ) {
+				log.warn( "Unable to configure SQLExceptionConverter", e );
+				throw e;
+			}
+		}
+
+		return converter;
+	}
+
+	/**
+	 * Builds a minimal converter.  The instance returned here just always converts to
+	 * {@link GenericJDBCException}.
+	 *
+	 * @return The minimal converter.
+	 */
+	public static SQLExceptionConverter buildMinimalSQLExceptionConverter() {
+		return new SQLExceptionConverter() {
+			public JDBCException convert(SQLException sqlException, String message, String sql) {
+				return new GenericJDBCException( message, sqlException, sql );
+			}
+		};
+	}
+
+	private static SQLExceptionConverter constructConverter(String converterClassName, ViolatedConstraintNameExtracter violatedConstraintNameExtracter) {
+		try {
+			log.trace( "Attempting to construct instance of specified SQLExceptionConverter [" + converterClassName + "]" );
+			Class converterClass = ReflectHelper.classForName( converterClassName );
+
+			// First, try to find a matching constructor accepting a ViolatedConstraintNameExtracter param...
+			Constructor[] ctors = converterClass.getDeclaredConstructors();
+			for ( int i = 0; i < ctors.length; i++ ) {
+				if ( ctors[i].getParameterTypes() != null && ctors[i].getParameterTypes().length == 1 ) {
+					if ( ViolatedConstraintNameExtracter.class.isAssignableFrom( ctors[i].getParameterTypes()[0] ) ) {
+						try {
+							return ( SQLExceptionConverter )
+									ctors[i].newInstance( new Object[]{violatedConstraintNameExtracter} );
+						}
+						catch ( Throwable t ) {
+							// eat it and try next
+						}
+					}
+				}
+			}
+
+			// Otherwise, try to use the no-arg constructor
+			return ( SQLExceptionConverter ) converterClass.newInstance();
+
+		}
+		catch ( Throwable t ) {
+			log.warn( "Unable to construct instance of specified SQLExceptionConverter", t );
+		}
+
+		return null;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLGrammarException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLGrammarException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLGrammarException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+// $Id: SQLGrammarException.java 4782 2004-11-21 00:11:27Z pgmjsd $
+package org.hibernate.exception;
+
+import org.hibernate.JDBCException;
+
+import java.sql.SQLException;
+
+/**
+ * Implementation of JDBCException indicating that the SQL sent to the database
+ * server was invalid (syntax error, invalid object references, etc).
+ *
+ * @author Steve Ebersole
+ */
+public class SQLGrammarException extends JDBCException {
+	/**
+	 * Constructor for JDBCException.
+	 *
+	 * @param root The underlying exception.
+	 */
+	public SQLGrammarException(String message, SQLException root) {
+		super( message, root );
+	}
+
+	/**
+	 * Constructor for JDBCException.
+	 *
+	 * @param message Optional message.
+	 * @param root    The underlying exception.
+	 */
+	public SQLGrammarException(String message, SQLException root, String sql) {
+		super( message, root, sql );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLStateConverter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLStateConverter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/SQLStateConverter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,105 @@
+// $Id: SQLStateConverter.java 9557 2006-03-06 15:16:27Z steve.ebersole at jboss.com $
+package org.hibernate.exception;
+
+import org.hibernate.JDBCException;
+
+import java.sql.SQLException;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A SQLExceptionConverter implementation which performs converion based on
+ * the underlying SQLState. Interpretation of a SQL error based on SQLState
+ * is not nearly as accurate as using the ErrorCode (which is, however, vendor-
+ * specific).  Use of a ErrorCode-based converter should be preferred approach
+ * for converting/interpreting SQLExceptions.
+ *
+ * @author Steve Ebersole
+ */
+public class SQLStateConverter implements SQLExceptionConverter {
+
+	private ViolatedConstraintNameExtracter extracter;
+
+	private static final Set SQL_GRAMMAR_CATEGORIES = new HashSet();
+	private static final Set DATA_CATEGORIES = new HashSet();
+	private static final Set INTEGRITY_VIOLATION_CATEGORIES = new HashSet();
+	private static final Set CONNECTION_CATEGORIES = new HashSet();
+
+	static {
+		SQL_GRAMMAR_CATEGORIES.add( "07" );
+		SQL_GRAMMAR_CATEGORIES.add( "37" );
+		SQL_GRAMMAR_CATEGORIES.add( "42" );
+		SQL_GRAMMAR_CATEGORIES.add( "65" );
+		SQL_GRAMMAR_CATEGORIES.add( "S0" );
+		SQL_GRAMMAR_CATEGORIES.add( "20" );
+		
+		DATA_CATEGORIES.add("22");
+		DATA_CATEGORIES.add("21");
+		DATA_CATEGORIES.add("02");
+
+		INTEGRITY_VIOLATION_CATEGORIES.add( "23" );
+		INTEGRITY_VIOLATION_CATEGORIES.add( "27" );
+		INTEGRITY_VIOLATION_CATEGORIES.add( "44" );
+
+		CONNECTION_CATEGORIES.add( "08" );
+	}
+
+	public SQLStateConverter(ViolatedConstraintNameExtracter extracter) {
+		this.extracter = extracter;
+	}
+
+	/**
+	 * Convert the given SQLException into Hibernate's JDBCException hierarchy.
+	 *
+	 * @param sqlException The SQLException to be converted.
+	 * @param message      An optional error message.
+	 * @param sql          Optionally, the sql being performed when the exception occurred.
+	 * @return The resulting JDBCException.
+	 */
+	public JDBCException convert(SQLException sqlException, String message, String sql) {
+		String sqlState = JDBCExceptionHelper.extractSqlState( sqlException );
+
+		if ( sqlState != null ) {
+			String sqlStateClassCode = JDBCExceptionHelper.determineSqlStateClassCode( sqlState );
+
+			if ( sqlStateClassCode != null ) {
+				if ( SQL_GRAMMAR_CATEGORIES.contains( sqlStateClassCode ) ) {
+					return new SQLGrammarException( message, sqlException, sql );
+				}
+				else if ( INTEGRITY_VIOLATION_CATEGORIES.contains( sqlStateClassCode ) ) {
+					String constraintName = extracter.extractConstraintName( sqlException );
+					return new ConstraintViolationException( message, sqlException, sql, constraintName );
+				}
+				else if ( CONNECTION_CATEGORIES.contains( sqlStateClassCode ) ) {
+					return new JDBCConnectionException( message, sqlException, sql );
+				}
+				else if ( DATA_CATEGORIES.contains( sqlStateClassCode ) ) {
+					return new DataException( message, sqlException, sql );
+				}
+			}
+
+			if ( "40001".equals( sqlState ) ) {
+				return new LockAcquisitionException( message, sqlException, sql );
+			}
+
+			if ( "61000".equals( sqlState ) ) {
+				// oracle sql-state code for deadlock
+				return new LockAcquisitionException( message, sqlException, sql );
+			}
+		}
+
+		return handledNonSpecificException( sqlException, message, sql );
+	}
+
+	/**
+	 * Handle an exception not converted to a specific type based on the SQLState.
+	 *
+	 * @param sqlException The exception to be handled.
+	 * @param message      An optional message
+	 * @param sql          Optionally, the sql being performed when the exception occurred.
+	 * @return The converted exception; should <b>never</b> be null.
+	 */
+	protected JDBCException handledNonSpecificException(SQLException sqlException, String message, String sql) {
+		return new GenericJDBCException( message, sqlException, sql );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/TemplatedViolatedConstraintNameExtracter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/TemplatedViolatedConstraintNameExtracter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/TemplatedViolatedConstraintNameExtracter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+// $Id: TemplatedViolatedConstraintNameExtracter.java 4782 2004-11-21 00:11:27Z pgmjsd $
+package org.hibernate.exception;
+
+
+
+/**
+ * Knows how to extract a violated constraint name from an error message based on the
+ * fact that the constraint name is templated within the message.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class TemplatedViolatedConstraintNameExtracter implements ViolatedConstraintNameExtracter {
+
+	/**
+	 * Extracts the constraint name based on a template (i.e., <i>templateStart</i><b>constraintName</b><i>templateEnd</i>).
+	 *
+	 * @param templateStart The pattern denoting the start of the constraint name within the message.
+	 * @param templateEnd   The pattern denoting the end of the constraint name within the message.
+	 * @param message       The templated error message containing the constraint name.
+	 * @return The found constraint name, or null.
+	 */
+	protected String extractUsingTemplate(String templateStart, String templateEnd, String message) {
+		int templateStartPosition = message.indexOf( templateStart );
+		if ( templateStartPosition < 0 ) {
+			return null;
+		}
+
+		int start = templateStartPosition + templateStart.length();
+		int end = message.indexOf( templateEnd, start );
+		if ( end < 0 ) {
+			end = message.length();
+		}
+
+		return message.substring( start, end );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/ViolatedConstraintNameExtracter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/ViolatedConstraintNameExtracter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/ViolatedConstraintNameExtracter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+// $Id: ViolatedConstraintNameExtracter.java 4746 2004-11-11 20:57:28Z steveebersole $
+package org.hibernate.exception;
+
+import java.sql.SQLException;
+
+/**
+ * Defines a contract for implementations that can extract the name of a violated
+ * constraint from a SQLException that is the result of that constraint violation.
+ *
+ * @author Steve Ebersole
+ */
+public interface ViolatedConstraintNameExtracter {
+	/**
+	 * Extract the name of the violated constraint from the given SQLException.
+	 *
+	 * @param sqle The exception that was the result of the constraint violation.
+	 * @return The extracted constraint name.
+	 */
+	public String extractConstraintName(SQLException sqle);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/exception/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/exception/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package is a fork of Apache commons-lang nestable exceptions.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/exception/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/CollectionProperties.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/CollectionProperties.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/CollectionProperties.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+// $Id: CollectionProperties.java 5699 2005-02-13 11:50:11Z oneovthafew $
+package org.hibernate.hql;
+
+import org.hibernate.persister.collection.CollectionPropertyNames;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Provides a map of collection function names to the corresponding property names.
+ *
+ * @author josh Aug 16, 2004 7:51:45 PM
+ */
+public final class CollectionProperties {
+	public static final Map HQL_COLLECTION_PROPERTIES;
+
+	private static final String COLLECTION_INDEX_LOWER = CollectionPropertyNames.COLLECTION_INDEX.toLowerCase();
+
+	static {
+		HQL_COLLECTION_PROPERTIES = new HashMap();
+		HQL_COLLECTION_PROPERTIES.put( CollectionPropertyNames.COLLECTION_ELEMENTS.toLowerCase(), CollectionPropertyNames.COLLECTION_ELEMENTS );
+		HQL_COLLECTION_PROPERTIES.put( CollectionPropertyNames.COLLECTION_INDICES.toLowerCase(), CollectionPropertyNames.COLLECTION_INDICES );
+		HQL_COLLECTION_PROPERTIES.put( CollectionPropertyNames.COLLECTION_SIZE.toLowerCase(), CollectionPropertyNames.COLLECTION_SIZE );
+		HQL_COLLECTION_PROPERTIES.put( CollectionPropertyNames.COLLECTION_MAX_INDEX.toLowerCase(), CollectionPropertyNames.COLLECTION_MAX_INDEX );
+		HQL_COLLECTION_PROPERTIES.put( CollectionPropertyNames.COLLECTION_MIN_INDEX.toLowerCase(), CollectionPropertyNames.COLLECTION_MIN_INDEX );
+		HQL_COLLECTION_PROPERTIES.put( CollectionPropertyNames.COLLECTION_MAX_ELEMENT.toLowerCase(), CollectionPropertyNames.COLLECTION_MAX_ELEMENT );
+		HQL_COLLECTION_PROPERTIES.put( CollectionPropertyNames.COLLECTION_MIN_ELEMENT.toLowerCase(), CollectionPropertyNames.COLLECTION_MIN_ELEMENT );
+		HQL_COLLECTION_PROPERTIES.put( COLLECTION_INDEX_LOWER, CollectionPropertyNames.COLLECTION_INDEX );
+	}
+
+	private CollectionProperties() {
+	}
+
+	public static boolean isCollectionProperty(String name) {
+		String key = name.toLowerCase();
+		// CollectionPropertyMapping processes everything except 'index'.
+		if ( COLLECTION_INDEX_LOWER.equals( key ) ) {
+			return false;
+		}
+		else {
+			return HQL_COLLECTION_PROPERTIES.containsKey( key );
+		}
+	}
+
+	public static String getNormalizedPropertyName(String name) {
+		return ( String ) HQL_COLLECTION_PROPERTIES.get( name );
+	}
+
+	public static boolean isAnyCollectionProperty(String name) {
+		String key = name.toLowerCase();
+		return HQL_COLLECTION_PROPERTIES.containsKey( key );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/CollectionSubqueryFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/CollectionSubqueryFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/CollectionSubqueryFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+// $Id: CollectionSubqueryFactory.java 9046 2006-01-13 03:10:57Z steveebersole $
+package org.hibernate.hql;
+
+import org.hibernate.engine.JoinSequence;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.util.StringHelper;
+
+import java.util.Map;
+
+/**
+ * Provides the SQL for collection subqueries.
+ * <br>
+ * Moved here from PathExpressionParser to make it re-useable.
+ * 
+ * @author josh
+ */
+public final class CollectionSubqueryFactory {
+
+	//TODO: refactor to .sql package
+
+	private CollectionSubqueryFactory() {
+	}
+
+	public static String createCollectionSubquery(
+			JoinSequence joinSequence,
+	        Map enabledFilters,
+	        String[] columns) {
+		try {
+			JoinFragment join = joinSequence.toJoinFragment( enabledFilters, true );
+			return new StringBuffer( "select " )
+					.append( StringHelper.join( ", ", columns ) )
+					.append( " from " )
+					.append( join.toFromFragmentString().substring( 2 ) )// remove initial ", "
+					.append( " where " )
+					.append( join.toWhereFragmentString().substring( 5 ) )// remove initial " and "
+					.toString();
+		}
+		catch ( MappingException me ) {
+			throw new QueryException( me );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/FilterTranslator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/FilterTranslator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/FilterTranslator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+// $Id: FilterTranslator.java 4899 2004-12-06 14:17:24Z pgmjsd $
+package org.hibernate.hql;
+
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+
+import java.util.Map;
+
+
+/**
+ * Specialized interface for filters.
+ *
+ * @author josh Mar 14, 2004 11:33:35 AM
+ */
+public interface FilterTranslator extends QueryTranslator {
+	/**
+	 * Compile a filter. This method may be called multiple
+	 * times. Subsequent invocations are no-ops.
+	 *
+	 * @param collectionRole the role name of the collection used as the basis for the filter.
+	 * @param replacements   Defined query substitutions.
+	 * @param shallow        Does this represent a shallow (scalar or entity-id) select?
+	 * @throws QueryException   There was a problem parsing the query string.
+	 * @throws MappingException There was a problem querying defined mappings.
+	 */
+	void compile(String collectionRole, Map replacements, boolean shallow)
+			throws QueryException, MappingException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/HolderInstantiator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/HolderInstantiator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/HolderInstantiator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,81 @@
+//$Id: HolderInstantiator.java 9636 2006-03-16 14:14:48Z max.andersen at jboss.com $
+package org.hibernate.hql;
+
+import java.lang.reflect.Constructor;
+
+import org.hibernate.transform.AliasToBeanConstructorResultTransformer;
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.transform.Transformers;
+
+/**
+ * @author Gavin King
+ */
+public final class HolderInstantiator {
+		
+	public static final HolderInstantiator NOOP_INSTANTIATOR = new HolderInstantiator(null,null);
+	
+	private final ResultTransformer transformer;
+	private final String[] queryReturnAliases;
+	
+	public static HolderInstantiator getHolderInstantiator(ResultTransformer selectNewTransformer, ResultTransformer customTransformer, String[] queryReturnAliases) {
+		if(selectNewTransformer!=null) {
+			return new HolderInstantiator(selectNewTransformer, queryReturnAliases);
+		} else {
+			return new HolderInstantiator(customTransformer, queryReturnAliases);
+		}
+	}
+	
+	public static ResultTransformer createSelectNewTransformer(Constructor constructor, boolean returnMaps, boolean returnLists) {
+		if ( constructor != null ) {
+			return new AliasToBeanConstructorResultTransformer(constructor);
+		}
+		else if ( returnMaps ) {
+			return Transformers.ALIAS_TO_ENTITY_MAP;			
+		}
+		else if ( returnLists ) {
+			return Transformers.TO_LIST;
+		}		
+		else {
+			return null;
+		}
+	}
+	
+	static public HolderInstantiator createClassicHolderInstantiator(Constructor constructor, 
+			ResultTransformer transformer) {
+		if ( constructor != null ) {
+			return new HolderInstantiator(new AliasToBeanConstructorResultTransformer(constructor), null);
+		}
+		else {
+			return new HolderInstantiator(transformer, null);
+		}
+	}
+	
+	public HolderInstantiator( 
+			ResultTransformer transformer,
+			String[] queryReturnAliases
+	) {
+		this.transformer = transformer;		
+		this.queryReturnAliases = queryReturnAliases;
+	}
+	
+	public boolean isRequired() {
+		return transformer!=null;
+	}
+	
+	public Object instantiate(Object[] row) {
+		if(transformer==null) {
+			return row;
+		} else {
+			return transformer.transformTuple(row, queryReturnAliases);
+		}
+	}	
+	
+	public String[] getQueryReturnAliases() {
+		return queryReturnAliases;
+	}
+
+	public ResultTransformer getResultTransformer() {
+		return transformer;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/HolderInstantiator.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/NameGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/NameGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/NameGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+// $Id: NameGenerator.java 4899 2004-12-06 14:17:24Z pgmjsd $
+package org.hibernate.hql;
+
+import org.hibernate.MappingException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Provides utility methods for generating HQL / SQL names.   Shared by both the 'classic' and 'new' query translators.
+ *
+ * @author josh Mar 18, 2004 7:17:25 AM
+ */
+public final class NameGenerator {
+	/**
+	 * Private empty constructor (checkstyle says utility classes should not have default constructors).
+	 */
+	private NameGenerator() {
+	}
+
+	public static String[][] generateColumnNames(Type[] types, SessionFactoryImplementor f) throws MappingException {
+		String[][] columnNames = new String[types.length][];
+		for ( int i = 0; i < types.length; i++ ) {
+			int span = types[i].getColumnSpan( f );
+			columnNames[i] = new String[span];
+			for ( int j = 0; j < span; j++ ) {
+				columnNames[i][j] = NameGenerator.scalarName( i, j );
+			}
+		}
+		return columnNames;
+	}
+
+	public static String scalarName(int x, int y) {
+		return new StringBuffer()
+				.append( "col_" )
+				.append( x )
+				.append( '_' )
+				.append( y )
+				.append( '_' )
+				.toString();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ParameterTranslations.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ParameterTranslations.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ParameterTranslations.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+package org.hibernate.hql;
+
+import org.hibernate.type.Type;
+import java.util.Set;
+
+/**
+ * Defines available information about the parameters encountered during
+ * query translation.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public interface ParameterTranslations {
+
+	public boolean supportsOrdinalParameterMetadata();
+
+	public int getOrdinalParameterCount();
+
+	public int getOrdinalParameterSqlLocation(int ordinalPosition);
+
+	public Type getOrdinalParameterExpectedType(int ordinalPosition);
+
+	public Set getNamedParameterNames();
+
+	public int[] getNamedParameterSqlLocations(String name);
+
+	public Type getNamedParameterExpectedType(String name);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QueryExecutionRequestException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QueryExecutionRequestException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QueryExecutionRequestException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+//$Id: $
+package org.hibernate.hql;
+
+import org.hibernate.QueryException;
+
+/**
+ * Expecting to execute an illegal operation regarding the query type
+ *
+ * @author Emmanuel Bernard
+ */
+public class QueryExecutionRequestException extends QueryException {
+
+	public QueryExecutionRequestException(String message, String queryString) {
+		super( message, queryString );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QuerySplitter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QuerySplitter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QuerySplitter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,134 @@
+//$Id: QuerySplitter.java 7646 2005-07-25 07:37:13Z oneovthafew $
+package org.hibernate.hql;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.MappingException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.hql.classic.ParserHelper;
+import org.hibernate.util.StringHelper;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Provides query splitting methods, which were originally in QueryTranslator.
+ * <br>
+ * TODO: This will need to be refactored at some point.
+ *
+ * @author josh Mar 14, 2004 10:50:23 AM
+ */
+public final class QuerySplitter {
+
+	private static final Log log = LogFactory.getLog( QuerySplitter.class );
+
+	private static final Set BEFORE_CLASS_TOKENS = new HashSet();
+	private static final Set NOT_AFTER_CLASS_TOKENS = new HashSet();
+
+	static {
+		BEFORE_CLASS_TOKENS.add( "from" );
+		BEFORE_CLASS_TOKENS.add( "delete" );
+		BEFORE_CLASS_TOKENS.add( "update" );
+		//beforeClassTokens.add("new"); DEFINITELY DON'T HAVE THIS!!
+		BEFORE_CLASS_TOKENS.add( "," );
+		NOT_AFTER_CLASS_TOKENS.add( "in" );
+		//notAfterClassTokens.add(",");
+		NOT_AFTER_CLASS_TOKENS.add( "from" );
+		NOT_AFTER_CLASS_TOKENS.add( ")" );
+	}
+
+	/**
+	 * Private empty constructor.
+	 * (or else checkstyle says: 'warning: Utility classes should not have a public or default constructor.')
+	 */
+	private QuerySplitter() {
+	}
+
+	/**
+	 * Handle Hibernate "implicit" polymorphism, by translating the query string into
+	 * several "concrete" queries against mapped classes.
+	 */
+	public static String[] concreteQueries(String query, SessionFactoryImplementor factory) throws MappingException {
+
+		//scan the query string for class names appearing in the from clause and replace
+		//with all persistent implementors of the class/interface, returning multiple
+		//query strings (make sure we don't pick up a class in the select clause!)
+
+		//TODO: this is one of the ugliest and most fragile pieces of code in Hibernate....
+
+		String[] tokens = StringHelper.split( StringHelper.WHITESPACE + "(),", query, true );
+		if ( tokens.length == 0 ) return new String[]{query}; // just especially for the trivial collection filter
+		ArrayList placeholders = new ArrayList();
+		ArrayList replacements = new ArrayList();
+		StringBuffer templateQuery = new StringBuffer( 40 );
+		int count = 0;
+		String last = null;
+		int nextIndex = 0;
+		String next = null;
+		boolean isSelectClause = false;
+
+		templateQuery.append( tokens[0] );
+		if ( "select".equals( tokens[0].toLowerCase() ) ) isSelectClause = true;
+        
+		for ( int i = 1; i < tokens.length; i++ ) {
+
+			//update last non-whitespace token, if necessary
+			if ( !ParserHelper.isWhitespace( tokens[i - 1] ) ) last = tokens[i - 1].toLowerCase();
+
+			// select-range is terminated by declaration of "from"
+			if ( "from".equals( tokens[i].toLowerCase() ) ) isSelectClause = false;
+
+			String token = tokens[i];
+			if ( !ParserHelper.isWhitespace( token ) || last == null ) {
+
+				//scan for next non-whitespace token
+				if ( nextIndex <= i ) {
+					for ( nextIndex = i + 1; nextIndex < tokens.length; nextIndex++ ) {
+						next = tokens[nextIndex].toLowerCase();
+						if ( !ParserHelper.isWhitespace( next ) ) break;
+					}
+				}
+
+				boolean process = !isSelectClause && 
+						isJavaIdentifier( token ) && 
+						isPossiblyClassName( last, next );
+						
+				if (process) {
+					String importedClassName = getImportedClass( token, factory );
+					if ( importedClassName != null ) {
+						String[] implementors = factory.getImplementors( importedClassName );
+						String placeholder = "$clazz" + count++ + "$";
+						if ( implementors != null ) {
+							placeholders.add( placeholder );
+							replacements.add( implementors );
+						}
+						token = placeholder; // Note this!!
+					}
+				}
+
+			}
+
+			templateQuery.append( token );
+
+		}
+		String[] results = StringHelper.multiply( templateQuery.toString(), placeholders.iterator(), replacements.iterator() );
+		if ( results.length == 0 ) log.warn( "no persistent classes found for query class: " + query );
+		return results;
+	}
+
+	private static boolean isPossiblyClassName(String last, String next) {
+		return "class".equals( last ) || ( 
+				BEFORE_CLASS_TOKENS.contains( last ) && 
+				!NOT_AFTER_CLASS_TOKENS.contains( next ) 
+			);
+	}
+
+	private static boolean isJavaIdentifier(String token) {
+		return Character.isJavaIdentifierStart( token.charAt( 0 ) );
+	}
+
+	public static String getImportedClass(String name, SessionFactoryImplementor factory) {
+		return factory.getImportedClassName( name );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QueryTranslator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QueryTranslator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QueryTranslator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,167 @@
+//$Id: QueryTranslator.java 9162 2006-01-27 23:40:32Z steveebersole $
+package org.hibernate.hql;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.ScrollableResults;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.event.EventSource;
+import org.hibernate.type.Type;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Defines the constract of an HQL->SQL translator.
+ *
+ * @author josh
+ */
+public interface QueryTranslator {
+
+	// Error message constants.
+	public static final String ERROR_CANNOT_FETCH_WITH_ITERATE = "fetch may not be used with scroll() or iterate()";
+	public static final String ERROR_NAMED_PARAMETER_DOES_NOT_APPEAR = "Named parameter does not appear in Query: ";
+    public static final String ERROR_CANNOT_DETERMINE_TYPE = "Could not determine type of: ";
+	public static final String ERROR_CANNOT_FORMAT_LITERAL =  "Could not format constant value to SQL literal: ";
+
+	/**
+	 * Compile a "normal" query. This method may be called multiple
+	 * times. Subsequent invocations are no-ops.
+	 *
+	 * @param replacements Defined query substitutions.
+	 * @param shallow      Does this represent a shallow (scalar or entity-id) select?
+	 * @throws QueryException   There was a problem parsing the query string.
+	 * @throws MappingException There was a problem querying defined mappings.
+	 */
+	void compile(Map replacements, boolean shallow) throws QueryException, MappingException;
+
+	/**
+	 * Perform a list operation given the underlying query definition.
+	 *
+	 * @param session         The session owning this query.
+	 * @param queryParameters The query bind parameters.
+	 * @return The query list results.
+	 * @throws HibernateException
+	 */
+	List list(SessionImplementor session, QueryParameters queryParameters)
+			throws HibernateException;
+
+	/**
+	 * Perform an iterate operation given the underlying query defintion.
+	 *
+	 * @param queryParameters The query bind parameters.
+	 * @param session         The session owning this query.
+	 * @return An iterator over the query results.
+	 * @throws HibernateException
+	 */
+	Iterator iterate(QueryParameters queryParameters, EventSource session)
+			throws HibernateException;
+
+	/**
+	 * Perform a scroll operation given the underlying query defintion.
+	 *
+	 * @param queryParameters The query bind parameters.
+	 * @param session         The session owning this query.
+	 * @return The ScrollableResults wrapper around the query results.
+	 * @throws HibernateException
+	 */
+	ScrollableResults scroll(QueryParameters queryParameters, SessionImplementor session)
+			throws HibernateException;
+
+	/**
+	 * Perform a bulk update/delete operation given the underlying query defintion.
+	 *
+	 * @param queryParameters The query bind parameters.
+	 * @param session         The session owning this query.
+	 * @return The number of entities updated or deleted.
+	 * @throws HibernateException
+	 */
+	int executeUpdate(QueryParameters queryParameters, SessionImplementor session)
+			throws HibernateException;
+
+	/**
+	 * Returns the set of query spaces (table names) that the query referrs to.
+	 *
+	 * @return A set of query spaces (table names).
+	 */
+	Set getQuerySpaces();
+
+	/**
+	 * Retrieve the query identifier for this translator.  The query identifier is
+	 * used in stats collection.
+	 *
+	 * @return the identifier
+	 */
+	String getQueryIdentifier();
+
+	/**
+	 * Returns the SQL string generated by the translator.
+	 *
+	 * @return the SQL string generated by the translator.
+	 */
+	String getSQLString();
+
+	List collectSqlStrings();
+
+	/**
+	 * Returns the HQL string processed by the translator.
+	 *
+	 * @return the HQL string processed by the translator.
+	 */
+	String getQueryString();
+
+	/**
+	 * Returns the filters enabled for this query translator.
+	 *
+	 * @return Filters enabled for this query execution.
+	 */
+	Map getEnabledFilters();
+
+	/**
+	 * Returns an array of Types represented in the query result.
+	 *
+	 * @return Query return types.
+	 */
+	Type[] getReturnTypes();
+	
+	/**
+	 * Returns an array of HQL aliases
+	 */
+	String[] getReturnAliases();
+
+	/**
+	 * Returns the column names in the generated SQL.
+	 *
+	 * @return the column names in the generated SQL.
+	 */
+	String[][] getColumnNames();
+
+	/**
+	 * Return information about any parameters encountered during
+	 * translation.
+	 *
+	 * @return The parameter information.
+	 */
+	ParameterTranslations getParameterTranslations();
+
+	/**
+	 * Validate the scrollability of the translated query.
+	 *
+	 * @throws HibernateException
+	 */
+	void validateScrollability() throws HibernateException;
+
+	/**
+	 * Does the translated query contain collection fetches?
+	 *
+	 * @return tru if the query does contain collection fetched;
+	 * false otherwise.
+	 */
+	boolean containsCollectionFetches();
+
+	boolean isManipulationStatement();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QueryTranslatorFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QueryTranslatorFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/QueryTranslatorFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: QueryTranslatorFactory.java 9162 2006-01-27 23:40:32Z steveebersole $
+package org.hibernate.hql;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+
+import java.util.Map;
+
+/**
+ * Facade for generation of {@link QueryTranslator} and {@link FilterTranslator} instances.
+ *
+ * @author Gavin King
+ */
+public interface QueryTranslatorFactory {
+	/**
+	 * Construct a {@link QueryTranslator} instance capable of translating
+	 * an HQL query string.
+	 *
+	 * @param queryIdentifier The query-identifier (used in
+	 * {@link org.hibernate.stat.QueryStatistics} collection). This is
+	 * typically the same as the queryString parameter except for the case of
+	 * split polymorphic queries which result in multiple physical sql
+	 * queries.
+	 * @param queryString The query string to be translated
+	 * @param filters Currently enabled filters
+	 * @param factory The session factory.
+	 * @return an appropriate translator.
+	 */
+	public QueryTranslator createQueryTranslator(String queryIdentifier, String queryString, Map filters, SessionFactoryImplementor factory);
+
+	/**
+	 * Construct a {@link FilterTranslator} instance capable of translating
+	 * an HQL filter string.
+	 *
+	 * @see #createQueryTranslator
+	 */
+	public FilterTranslator createFilterTranslator(String queryIdentifier, String queryString, Map filters, SessionFactoryImplementor factory);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/antlr/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/antlr/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/antlr/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>A special package for ANTLR-generated parser classes.</p>
+<p><i>NOTE: The classes in this package are generated from the ANTLR grammar files,
+do not register them into version control.</i></p>
+</body>
+</html>

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ASTQueryTranslatorFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ASTQueryTranslatorFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ASTQueryTranslatorFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: ASTQueryTranslatorFactory.java 9162 2006-01-27 23:40:32Z steveebersole $
+package org.hibernate.hql.ast;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.hql.FilterTranslator;
+import org.hibernate.hql.QueryTranslator;
+import org.hibernate.hql.QueryTranslatorFactory;
+
+import java.util.Map;
+
+/**
+ * Generates translators which uses the Antlr-based parser to perform
+ * the translation.
+ *
+ * @author Gavin King
+ */
+public class ASTQueryTranslatorFactory implements QueryTranslatorFactory {
+
+	private static final Log log = LogFactory.getLog( ASTQueryTranslatorFactory.class );
+
+	public ASTQueryTranslatorFactory() {
+		log.info( "Using ASTQueryTranslatorFactory" );
+	}
+
+	/**
+	 * @see QueryTranslatorFactory#createQueryTranslator
+	 */
+	public QueryTranslator createQueryTranslator(
+			String queryIdentifier,
+	        String queryString,
+	        Map filters,
+	        SessionFactoryImplementor factory) {
+		return new QueryTranslatorImpl( queryIdentifier, queryString, filters, factory );
+	}
+
+	/**
+	 * @see QueryTranslatorFactory#createFilterTranslator
+	 */
+	public FilterTranslator createFilterTranslator(
+			String queryIdentifier,
+	        String queryString,
+	        Map filters,
+	        SessionFactoryImplementor factory) {
+		return new QueryTranslatorImpl( queryIdentifier, queryString, filters, factory );
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ASTQueryTranslatorFactory.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/DetailedSemanticException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/DetailedSemanticException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/DetailedSemanticException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,77 @@
+// $Id: DetailedSemanticException.java 5690 2005-02-12 20:27:50Z pgmjsd $
+package org.hibernate.hql.ast;
+
+import antlr.SemanticException;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * Thrown when a call to the underlying Hibernate engine fails, indicating
+ * some form of semantic exception (e.g. a class name was not found in the
+ * current mappings, etc.).
+ */
+public class DetailedSemanticException extends SemanticException {
+	private Throwable cause;
+	private boolean showCauseMessage = true;
+
+	public DetailedSemanticException(String message) {
+		super( message );
+	}
+
+	public DetailedSemanticException(String s, Throwable e) {
+		super( s );
+		cause = e;
+	}
+
+	/**
+	 * Converts everything to a string.
+	 *
+	 * @return a string.
+	 */
+	public String toString() {
+		if ( cause == null || ( !showCauseMessage ) ) {
+			return super.toString();
+		}
+		else {
+			return super.toString() + "\n[cause=" + cause.toString() + "]";
+		}
+	}
+
+	/**
+	 * Prints a stack trace.
+	 */
+	public void printStackTrace() {
+		super.printStackTrace();
+		if ( cause != null ) {
+			cause.printStackTrace();
+		}
+	}
+
+	/**
+	 * Prints a stack trace to the specified print stream.
+	 *
+	 * @param s the print stream.
+	 */
+	public void printStackTrace(PrintStream s) {
+		super.printStackTrace( s );
+		if ( cause != null ) {
+			s.println( "Cause:" );
+			cause.printStackTrace( s );
+		}
+	}
+
+	/**
+	 * Prints this throwable and its backtrace to the specified print writer.
+	 *
+	 * @param w the print writer.s
+	 */
+	public void printStackTrace(PrintWriter w) {
+		super.printStackTrace( w );
+		if ( cause != null ) {
+			w.println( "Cause:" );
+			cause.printStackTrace( w );
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ErrorCounter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ErrorCounter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ErrorCounter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,72 @@
+// $Id: ErrorCounter.java 9242 2006-02-09 12:37:36Z steveebersole $
+package org.hibernate.hql.ast;
+
+import antlr.RecognitionException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.QueryException;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * An error handler that counts parsing errors and warnings.
+ */
+public class ErrorCounter implements ParseErrorHandler {
+	private Log log = LogFactory.getLog( ErrorCounter.class );
+	private Log hqlLog = LogFactory.getLog( "org.hibernate.hql.PARSER" );
+
+	private List errorList = new ArrayList();
+	private List warningList = new ArrayList();
+	private List recognitionExceptions = new ArrayList();
+
+	public void reportError(RecognitionException e) {
+		reportError( e.toString() );
+		recognitionExceptions.add( e );
+		if ( log.isDebugEnabled() ) {
+			log.debug( e, e );
+		}
+	}
+
+	public void reportError(String message) {
+		hqlLog.error( message );
+		errorList.add( message );
+	}
+
+	public int getErrorCount() {
+		return errorList.size();
+	}
+
+	public void reportWarning(String message) {
+		hqlLog.debug( message );
+		warningList.add( message );
+	}
+
+	private String getErrorString() {
+		StringBuffer buf = new StringBuffer();
+		for ( Iterator iterator = errorList.iterator(); iterator.hasNext(); ) {
+			buf.append( ( String ) iterator.next() );
+			if ( iterator.hasNext() ) buf.append( "\n" );
+
+		}
+		return buf.toString();
+	}
+
+	public void throwQueryException() throws QueryException {
+		if ( getErrorCount() > 0 ) {
+			if ( recognitionExceptions.size() > 0 ) {
+				throw QuerySyntaxException.convert( ( RecognitionException ) recognitionExceptions.get( 0 ) );
+			}
+			else {
+				throw new QueryException( getErrorString() );
+			}
+		}
+		else {
+			// all clear
+			if ( log.isDebugEnabled() ) {
+				log.debug( "throwQueryException() : no errors" );
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ErrorReporter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ErrorReporter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ErrorReporter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+// $Id: ErrorReporter.java 3974 2004-06-29 02:40:43Z pgmjsd $
+package org.hibernate.hql.ast;
+
+import antlr.RecognitionException;
+
+/**
+ * Implementations will report or handle errors invoked by an ANTLR base parser.
+ *
+ * @author josh Jun 27, 2004 9:49:55 PM
+ */
+public interface ErrorReporter {
+	void reportError(RecognitionException e);
+
+	void reportError(String s);
+
+	void reportWarning(String s);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlASTFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlASTFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlASTFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+package org.hibernate.hql.ast;
+
+import antlr.ASTFactory;
+import org.hibernate.hql.ast.tree.Node;
+
+/**
+ * User: Joshua Davis<br>
+ * Date: Sep 23, 2005<br>
+ * Time: 12:30:01 PM<br>
+ */
+public class HqlASTFactory extends ASTFactory {
+
+	/**
+	 * Returns the class for a given token type (a.k.a. AST node type).
+	 *
+	 * @param tokenType The token type.
+	 * @return Class - The AST node class to instantiate.
+	 */
+	public Class getASTNodeType(int tokenType) {
+		return Node.class;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlLexer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlLexer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlLexer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,59 @@
+// $Id: HqlLexer.java 7511 2005-07-16 17:28:40Z epbernard $
+package org.hibernate.hql.ast;
+
+import java.io.InputStream;
+import java.io.Reader;
+
+import antlr.Token;
+import org.hibernate.QueryException;
+import org.hibernate.hql.antlr.HqlBaseLexer;
+
+/**
+ * Custom lexer for the HQL grammar.  Extends the base lexer generated by ANTLR
+ * in order to keep the grammar source file clean.
+ */
+class HqlLexer extends HqlBaseLexer {
+	/**
+	 * A logger for this class. *
+	 */
+	private boolean possibleID = false;
+
+	public HqlLexer(InputStream in) {
+		super( in );
+	}
+
+    public HqlLexer(Reader in) {
+        super(in);
+    }
+
+	public void setTokenObjectClass(String cl) {
+		// Ignore the token class name parameter, and use a specific token class.
+		super.setTokenObjectClass( HqlToken.class.getName() );
+	}
+
+	protected void setPossibleID(boolean possibleID) {
+		this.possibleID = possibleID;
+	}
+
+	protected Token makeToken(int i) {
+		HqlToken token = ( HqlToken ) super.makeToken( i );
+		token.setPossibleID( possibleID );
+		possibleID = false;
+		return token;
+	}
+
+	public int testLiteralsTable(int i) {
+		int ttype = super.testLiteralsTable( i );
+		return ttype;
+	}
+
+	public void panic() {
+		//overriden to avoid System.exit
+		panic("CharScanner: panic");
+	}
+
+	public void panic(String s) {
+		//overriden to avoid System.exit
+		throw new QueryException(s);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlParser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlParser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlParser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,338 @@
+// $Id: HqlParser.java 8475 2005-10-27 11:43:19Z oneovthafew $
+package org.hibernate.hql.ast;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringReader;
+
+import antlr.ASTPair;
+import antlr.MismatchedTokenException;
+import antlr.RecognitionException;
+import antlr.Token;
+import antlr.TokenStream;
+import antlr.TokenStreamException;
+import antlr.collections.AST;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.hql.antlr.HqlBaseParser;
+import org.hibernate.hql.antlr.HqlTokenTypes;
+import org.hibernate.hql.ast.util.ASTPrinter;
+import org.hibernate.hql.ast.util.ASTUtil;
+import org.hibernate.QueryException;
+
+/**
+ * Implements the semantic action methods defined in the HQL base parser to keep the grammar
+ * source file a little cleaner.  Extends the parser class generated by ANTLR.
+ *
+ * @author Joshua Davis (pgmjsd at sourceforge.net)
+ */
+public final class HqlParser extends HqlBaseParser {
+	/**
+	 * A logger for this class.
+	 */
+	private static final Log log = LogFactory.getLog( HqlParser.class );
+
+	private ParseErrorHandler parseErrorHandler;
+	private ASTPrinter printer = getASTPrinter();
+
+	private static ASTPrinter getASTPrinter() {
+		return new ASTPrinter( org.hibernate.hql.antlr.HqlTokenTypes.class );
+	}
+
+	public static HqlParser getInstance(String hql) {
+        // [jsd] The fix for HHH-558...
+        HqlLexer lexer = new HqlLexer( new StringReader( hql ) );
+		return new HqlParser( lexer );
+	}
+
+	private HqlParser(TokenStream lexer) {
+		super( lexer );
+		initialize();
+	}
+
+	public void reportError(RecognitionException e) {
+		parseErrorHandler.reportError( e ); // Use the delegate.
+	}
+
+	public void reportError(String s) {
+		parseErrorHandler.reportError( s ); // Use the delegate.
+	}
+
+	public void reportWarning(String s) {
+		parseErrorHandler.reportWarning( s );
+	}
+
+	public ParseErrorHandler getParseErrorHandler() {
+		return parseErrorHandler;
+	}
+
+	/**
+	 * Overrides the base behavior to retry keywords as identifiers.
+	 *
+	 * @param token The token.
+	 * @param ex    The recognition exception.
+	 * @return AST - The new AST.
+	 * @throws antlr.RecognitionException if the substitution was not possible.
+	 * @throws antlr.TokenStreamException if the substitution was not possible.
+	 */
+	public AST handleIdentifierError(Token token, RecognitionException ex) throws RecognitionException, TokenStreamException {
+		// If the token can tell us if it could be an identifier...
+		if ( token instanceof HqlToken ) {
+			HqlToken hqlToken = ( HqlToken ) token;
+			// ... and the token could be an identifer and the error is
+			// a mismatched token error ...
+			if ( hqlToken.isPossibleID() && ( ex instanceof MismatchedTokenException ) ) {
+				MismatchedTokenException mte = ( MismatchedTokenException ) ex;
+				// ... and the expected token type was an identifier, then:
+				if ( mte.expecting == HqlTokenTypes.IDENT ) {
+					// Use the token as an identifier.
+					reportWarning( "Keyword  '"
+							+ token.getText()
+							+ "' is being interpreted as an identifier due to: " + mte.getMessage() );
+					// Add the token to the AST.
+					ASTPair currentAST = new ASTPair();
+					token.setType( HqlTokenTypes.WEIRD_IDENT );
+					astFactory.addASTChild( currentAST, astFactory.create( token ) );
+					consume();
+					AST identifierAST = currentAST.root;
+					return identifierAST;
+				}
+			} // if
+		} // if
+		// Otherwise, handle the error normally.
+		return super.handleIdentifierError( token, ex );
+	}
+
+	/**
+	 * Returns an equivalent tree for (NOT (a relop b) ), for example:<pre>
+	 * (NOT (GT a b) ) => (LE a b)
+	 * </pre>
+	 *
+	 * @param x The sub tree to transform, the parent is assumed to be NOT.
+	 * @return AST - The equivalent sub-tree.
+	 */
+	public AST negateNode(AST x) {
+		//TODO: switch statements are always evil! We already had bugs because 
+		//      of forgotten token types. Use polymorphism for this!
+		switch ( x.getType() ) {
+			case OR:
+				x.setType(AND);
+				x.setText("{and}");
+				negateNode( x.getFirstChild() );
+				negateNode( x.getFirstChild().getNextSibling() );
+				return x;
+			case AND:
+				x.setType(OR);
+				x.setText("{or}");
+				negateNode( x.getFirstChild() );
+				negateNode( x.getFirstChild().getNextSibling() );
+				return x;
+			case EQ:
+				x.setType( NE );
+				x.setText( "{not}" + x.getText() );
+				return x;	// (NOT (EQ a b) ) => (NE a b)
+			case NE:
+				x.setType( EQ );
+				x.setText( "{not}" + x.getText() );
+				return x;	// (NOT (NE a b) ) => (EQ a b)
+			case GT:
+				x.setType( LE );
+				x.setText( "{not}" + x.getText() );
+				return x;	// (NOT (GT a b) ) => (LE a b)
+			case LT:
+				x.setType( GE );
+				x.setText( "{not}" + x.getText() );
+				return x;	// (NOT (LT a b) ) => (GE a b)
+			case GE:
+				x.setType( LT );
+				x.setText( "{not}" + x.getText() );
+				return x;	// (NOT (GE a b) ) => (LT a b)
+			case LE:
+				x.setType( GT );
+				x.setText( "{not}" + x.getText() );
+				return x;	// (NOT (LE a b) ) => (GT a b)
+			case LIKE:
+				x.setType( NOT_LIKE );
+				x.setText( "{not}" + x.getText() );
+				return x;	// (NOT (LIKE a b) ) => (NOT_LIKE a b)
+			case NOT_LIKE:
+				x.setType( LIKE );
+				x.setText( "{not}" + x.getText() );
+				return x;	// (NOT (NOT_LIKE a b) ) => (LIKE a b)
+			case IN:
+				x.setType( NOT_IN );
+				x.setText( "{not}" + x.getText() );
+				return x;
+			case NOT_IN:
+				x.setType( IN );
+				x.setText( "{not}" + x.getText() );
+				return x;
+			case IS_NULL:
+				x.setType( IS_NOT_NULL );
+				x.setText( "{not}" + x.getText() );
+				return x;	// (NOT (IS_NULL a b) ) => (IS_NOT_NULL a b)
+			case IS_NOT_NULL:
+				x.setType( IS_NULL );
+				x.setText( "{not}" + x.getText() );
+				return x;	// (NOT (IS_NOT_NULL a b) ) => (IS_NULL a b)
+			case BETWEEN:
+				x.setType( NOT_BETWEEN );
+				x.setText( "{not}" + x.getText() );
+				return x;	// (NOT (BETWEEN a b) ) => (NOT_BETWEEN a b)
+			case NOT_BETWEEN:
+				x.setType( BETWEEN );
+				x.setText( "{not}" + x.getText() );
+				return x;	// (NOT (NOT_BETWEEN a b) ) => (BETWEEN a b)
+/* This can never happen because this rule will always eliminate the child NOT.
+			case NOT:
+				return x.getFirstChild();			// (NOT (NOT x) ) => (x)
+*/
+			default:
+				return super.negateNode( x );		// Just add a 'not' parent.
+		}
+	}
+
+	/**
+	 * Post process equality expressions, clean up the subtree.
+	 *
+	 * @param x The equality expression.
+	 * @return AST - The clean sub-tree.
+	 */
+	public AST processEqualityExpression(AST x) {
+		if ( x == null ) {
+			log.warn( "processEqualityExpression() : No expression to process!" );
+			return null;
+		}
+
+		int type = x.getType();
+		if ( type == EQ || type == NE ) {
+			boolean negated = type == NE;
+			if ( x.getNumberOfChildren() == 2 ) {
+				AST a = x.getFirstChild();
+				AST b = a.getNextSibling();
+				// (EQ NULL b) => (IS_NULL b)
+				if ( a.getType() == NULL && b.getType() != NULL ) {
+					return createIsNullParent( b, negated );
+				}
+				// (EQ a NULL) => (IS_NULL a)
+				else if ( b.getType() == NULL && a.getType() != NULL ) {
+					return createIsNullParent( a, negated );
+				}
+				else if ( b.getType() == EMPTY ) {
+					return processIsEmpty( a, negated );
+				}
+				else {
+					return x;
+				}
+			}
+			else {
+				return x;
+			}
+		}
+		else {
+			return x;
+		}
+	}
+
+	private AST createIsNullParent(AST node, boolean negated) {
+		node.setNextSibling( null );
+		int type = negated ? IS_NOT_NULL : IS_NULL;
+		String text = negated ? "is not null" : "is null";
+		return ASTUtil.createParent( astFactory, type, text, node );
+	}
+
+	private AST processIsEmpty(AST node, boolean negated) {
+		node.setNextSibling( null );
+		// NOTE: Because we're using ASTUtil.createParent(), the tree must be created from the bottom up.
+		// IS EMPTY x => (EXISTS (QUERY (SELECT_FROM (FROM x) ) ) )
+		AST ast = createSubquery( node );
+		ast = ASTUtil.createParent( astFactory, EXISTS, "exists", ast );
+		// Add NOT if it's negated.
+		if ( !negated ) {
+			ast = ASTUtil.createParent( astFactory, NOT, "not", ast );
+		}
+		return ast;
+	}
+
+	private AST createSubquery(AST node) {
+		AST ast = ASTUtil.createParent( astFactory, RANGE, "RANGE", node );
+		ast = ASTUtil.createParent( astFactory, FROM, "from", ast );
+		ast = ASTUtil.createParent( astFactory, SELECT_FROM, "SELECT_FROM", ast );
+		ast = ASTUtil.createParent( astFactory, QUERY, "QUERY", ast );
+		return ast;
+	}
+
+	public void showAst(AST ast, PrintStream out) {
+		showAst( ast, new PrintWriter( out ) );
+	}
+
+	private void showAst(AST ast, PrintWriter pw) {
+		printer.showAst( ast, pw );
+	}
+
+	private void initialize() {
+		// Initialize the error handling delegate.
+		parseErrorHandler = new ErrorCounter();
+		setASTFactory(new HqlASTFactory());	// Create nodes that track line and column number.
+	}
+
+	public void weakKeywords() throws TokenStreamException {
+
+		int t = LA( 1 );
+		switch ( t ) {
+			case ORDER:
+			case GROUP:
+                // Case 1: Multi token keywords GROUP BY and ORDER BY
+				// The next token ( LT(2) ) should be 'by'... otherwise, this is just an ident.
+				if ( LA( 2 ) != LITERAL_by ) {
+					LT( 1 ).setType( IDENT );
+					if ( log.isDebugEnabled() ) {
+						log.debug( "weakKeywords() : new LT(1) token - " + LT( 1 ) );
+					}
+				}
+				break;
+			default:
+                // Case 2: The current token is after FROM and before '.'.
+                if (LA(0) == FROM && t != IDENT && LA(2) == DOT) {
+                    HqlToken hqlToken = (HqlToken)LT(1);
+                    if (hqlToken.isPossibleID()) {
+                        hqlToken.setType(IDENT);
+                        if ( log.isDebugEnabled() ) {
+                            log.debug( "weakKeywords() : new LT(1) token - " + LT( 1 ) );
+                        }
+                    }
+                }
+				break;
+		}
+	}
+
+    public void handleDotIdent() throws TokenStreamException {
+        // This handles HHH-354, where there is a strange property name in a where clause.
+        // If the lookahead contains a DOT then something that isn't an IDENT...
+        if (LA(1) == DOT && LA(2) != IDENT) {
+            // See if the second lookahed token can be an identifier.
+            HqlToken t = (HqlToken)LT(2);
+            if (t.isPossibleID())
+            {
+                // Set it!
+                LT( 2 ).setType( IDENT );
+                if ( log.isDebugEnabled() ) {
+                    log.debug( "handleDotIdent() : new LT(2) token - " + LT( 1 ) );
+                }
+            }
+        }
+    }
+
+	public void processMemberOf(Token n, AST p, ASTPair currentAST) {
+		AST inAst = n == null ? astFactory.create( IN, "in" ) : astFactory.create( NOT_IN, "not in" );
+		astFactory.makeASTRoot( currentAST, inAst );
+		AST ast = createSubquery( p );
+		ast = ASTUtil.createParent( astFactory, IN_LIST, "inList", ast );
+		inAst.addChild( ast );
+	}
+
+	static public void panic() {
+		//overriden to avoid System.exit
+		throw new QueryException("Parser: panic");
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlSqlWalker.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlSqlWalker.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlSqlWalker.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1016 @@
+// $Id: HqlSqlWalker.java 10945 2006-12-07 14:50:42Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.QueryException;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.JoinSequence;
+import org.hibernate.engine.ParameterBinder;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.hql.QueryTranslator;
+import org.hibernate.hql.antlr.HqlSqlBaseWalker;
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.hql.antlr.HqlTokenTypes;
+import org.hibernate.hql.antlr.SqlTokenTypes;
+import org.hibernate.hql.ast.tree.AssignmentSpecification;
+import org.hibernate.hql.ast.tree.CollectionFunction;
+import org.hibernate.hql.ast.tree.ConstructorNode;
+import org.hibernate.hql.ast.tree.DeleteStatement;
+import org.hibernate.hql.ast.tree.DotNode;
+import org.hibernate.hql.ast.tree.FromClause;
+import org.hibernate.hql.ast.tree.FromElement;
+import org.hibernate.hql.ast.tree.FromReferenceNode;
+import org.hibernate.hql.ast.tree.IdentNode;
+import org.hibernate.hql.ast.tree.IndexNode;
+import org.hibernate.hql.ast.tree.InsertStatement;
+import org.hibernate.hql.ast.tree.IntoClause;
+import org.hibernate.hql.ast.tree.MethodNode;
+import org.hibernate.hql.ast.tree.ParameterNode;
+import org.hibernate.hql.ast.tree.QueryNode;
+import org.hibernate.hql.ast.tree.ResolvableNode;
+import org.hibernate.hql.ast.tree.RestrictableStatement;
+import org.hibernate.hql.ast.tree.SelectClause;
+import org.hibernate.hql.ast.tree.SelectExpression;
+import org.hibernate.hql.ast.tree.UpdateStatement;
+import org.hibernate.hql.ast.tree.Node;
+import org.hibernate.hql.ast.tree.OperatorNode;
+import org.hibernate.hql.ast.util.ASTPrinter;
+import org.hibernate.hql.ast.util.ASTUtil;
+import org.hibernate.hql.ast.util.AliasGenerator;
+import org.hibernate.hql.ast.util.JoinProcessor;
+import org.hibernate.hql.ast.util.LiteralProcessor;
+import org.hibernate.hql.ast.util.SessionFactoryHelper;
+import org.hibernate.hql.ast.util.SyntheticAndFactory;
+import org.hibernate.hql.ast.util.NodeTraverser;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.id.PostInsertIdentifierGenerator;
+import org.hibernate.id.SequenceGenerator;
+import org.hibernate.param.NamedParameterSpecification;
+import org.hibernate.param.ParameterSpecification;
+import org.hibernate.param.PositionalParameterSpecification;
+import org.hibernate.param.VersionTypeSeedParameterSpecification;
+import org.hibernate.param.CollectionFilterKeyParameterSpecification;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.Type;
+import org.hibernate.type.VersionType;
+import org.hibernate.type.DbTimestampType;
+import org.hibernate.usertype.UserVersionType;
+import org.hibernate.util.ArrayHelper;
+
+import antlr.ASTFactory;
+import antlr.RecognitionException;
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+/**
+ * Implements methods used by the HQL->SQL tree transform grammar (a.k.a. the second phase).
+ * <ul>
+ * <li>Isolates the Hibernate API-specific code from the ANTLR generated code.</li>
+ * <li>Handles the SQL framgents generated by the persisters in order to create the SELECT and FROM clauses,
+ * taking into account the joins and projections that are implied by the mappings (persister/queryable).</li>
+ * <li>Uses SqlASTFactory to create customized AST nodes.</li>
+ * </ul>
+ *
+ * @see SqlASTFactory
+ */
+public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, ParameterBinder.NamedParameterSource {
+	private static final Log log = LogFactory.getLog( HqlSqlWalker.class );
+
+	private final QueryTranslatorImpl queryTranslatorImpl;
+	private final HqlParser hqlParser;
+	private final SessionFactoryHelper sessionFactoryHelper;
+	private final Map tokenReplacements;
+	private final AliasGenerator aliasGenerator = new AliasGenerator();
+	private final LiteralProcessor literalProcessor;
+	private final ParseErrorHandler parseErrorHandler;
+	private final ASTPrinter printer;
+	private final String collectionFilterRole;
+
+	private FromClause currentFromClause = null;
+	private SelectClause selectClause;
+
+	private Set querySpaces = new HashSet();
+
+	private int parameterCount;
+	private Map namedParameters = new HashMap();
+	private ArrayList parameters = new ArrayList();
+	private int numberOfParametersInSetClause;
+	private int positionalParameterCount;
+
+	private ArrayList assignmentSpecifications = new ArrayList();
+
+	private int impliedJoinType;
+
+	/**
+	 * Create a new tree transformer.
+	 *
+	 * @param qti Back pointer to the query translator implementation that is using this tree transform.
+	 * @param sfi The session factory implementor where the Hibernate mappings can be found.
+	 * @param parser A reference to the phase-1 parser
+	 * @param tokenReplacements Registers the token replacement map with the walker.  This map will
+	 * be used to substitute function names and constants.
+	 * @param collectionRole The collection role name of the collection used as the basis for the
+	 * filter, NULL if this is not a collection filter compilation.
+	 */
+	public HqlSqlWalker(
+			QueryTranslatorImpl qti,
+			SessionFactoryImplementor sfi,
+			HqlParser parser,
+			Map tokenReplacements,
+			String collectionRole) {
+		setASTFactory( new SqlASTFactory( this ) );
+		// Initialize the error handling delegate.
+		this.parseErrorHandler = new ErrorCounter();
+		this.queryTranslatorImpl = qti;
+		this.sessionFactoryHelper = new SessionFactoryHelper( sfi );
+		this.literalProcessor = new LiteralProcessor( this );
+		this.tokenReplacements = tokenReplacements;
+		this.collectionFilterRole = collectionRole;
+		this.hqlParser = parser;
+		this.printer = new ASTPrinter( SqlTokenTypes.class );
+	}
+
+
+	protected void prepareFromClauseInputTree(AST fromClauseInput) {
+		if ( !isSubQuery() ) {
+//			// inject param specifications to account for dynamic filter param values
+//			if ( ! getEnabledFilters().isEmpty() ) {
+//				Iterator filterItr = getEnabledFilters().values().iterator();
+//				while ( filterItr.hasNext() ) {
+//					FilterImpl filter = ( FilterImpl ) filterItr.next();
+//					if ( ! filter.getFilterDefinition().getParameterNames().isEmpty() ) {
+//						Iterator paramItr = filter.getFilterDefinition().getParameterNames().iterator();
+//						while ( paramItr.hasNext() ) {
+//							String parameterName = ( String ) paramItr.next();
+//							// currently param filters *only* work with single-column parameter types;
+//							// if that limitation is ever lifted, this logic will need to change to account for that
+//							ParameterNode collectionFilterKeyParameter = ( ParameterNode ) astFactory.create( PARAM, "?" );
+//							DynamicFilterParameterSpecification paramSpec = new DynamicFilterParameterSpecification(
+//									filter.getName(),
+//									parameterName,
+//									filter.getFilterDefinition().getParameterType( parameterName ),
+//									 positionalParameterCount++
+//							);
+//							collectionFilterKeyParameter.setHqlParameterSpecification( paramSpec );
+//							parameters.add( paramSpec );
+//						}
+//					}
+//				}
+//			}
+
+			if ( isFilter() ) {
+				// Handle collection-fiter compilation.
+				// IMPORTANT NOTE: This is modifying the INPUT (HQL) tree, not the output tree!
+				QueryableCollection persister = sessionFactoryHelper.getCollectionPersister( collectionFilterRole );
+				Type collectionElementType = persister.getElementType();
+				if ( !collectionElementType.isEntityType() ) {
+					throw new QueryException( "collection of values in filter: this" );
+				}
+
+				String collectionElementEntityName = persister.getElementPersister().getEntityName();
+				ASTFactory inputAstFactory = hqlParser.getASTFactory();
+				AST fromElement = ASTUtil.create( inputAstFactory, HqlTokenTypes.FILTER_ENTITY, collectionElementEntityName );
+				ASTUtil.createSibling( inputAstFactory, HqlTokenTypes.ALIAS, "this", fromElement );
+				fromClauseInput.addChild( fromElement );
+				// Show the modified AST.
+				if ( log.isDebugEnabled() ) {
+					log.debug( "prepareFromClauseInputTree() : Filter - Added 'this' as a from element..." );
+				}
+				queryTranslatorImpl.showHqlAst( hqlParser.getAST() );
+
+				// Create a parameter specification for the collection filter...
+				Type collectionFilterKeyType = sessionFactoryHelper.requireQueryableCollection( collectionFilterRole ).getKeyType();
+				ParameterNode collectionFilterKeyParameter = ( ParameterNode ) astFactory.create( PARAM, "?" );
+				CollectionFilterKeyParameterSpecification collectionFilterKeyParameterSpec = new CollectionFilterKeyParameterSpecification(
+						collectionFilterRole, collectionFilterKeyType, positionalParameterCount++
+				);
+				collectionFilterKeyParameter.setHqlParameterSpecification( collectionFilterKeyParameterSpec );
+				parameters.add( collectionFilterKeyParameterSpec );
+			}
+		}
+	}
+
+	public boolean isFilter() {
+		return collectionFilterRole != null;
+	}
+
+	public SessionFactoryHelper getSessionFactoryHelper() {
+		return sessionFactoryHelper;
+	}
+
+	public Map getTokenReplacements() {
+		return tokenReplacements;
+	}
+
+	public AliasGenerator getAliasGenerator() {
+		return aliasGenerator;
+	}
+
+	public FromClause getCurrentFromClause() {
+		return currentFromClause;
+	}
+
+	public ParseErrorHandler getParseErrorHandler() {
+		return parseErrorHandler;
+	}
+
+	public void reportError(RecognitionException e) {
+		parseErrorHandler.reportError( e ); // Use the delegate.
+	}
+
+	public void reportError(String s) {
+		parseErrorHandler.reportError( s ); // Use the delegate.
+	}
+
+	public void reportWarning(String s) {
+		parseErrorHandler.reportWarning( s );
+	}
+
+	/**
+	 * Returns the set of unique query spaces (a.k.a.
+	 * table names) that occurred in the query.
+	 *
+	 * @return A set of table names (Strings).
+	 */
+	public Set getQuerySpaces() {
+		return querySpaces;
+	}
+
+	protected AST createFromElement(String path, AST alias, AST propertyFetch) throws SemanticException {
+		FromElement fromElement = currentFromClause.addFromElement( path, alias );
+		fromElement.setAllPropertyFetch(propertyFetch!=null);
+		return fromElement;
+	}
+
+	protected AST createFromFilterElement(AST filterEntity, AST alias) throws SemanticException {
+		FromElement fromElement = currentFromClause.addFromElement( filterEntity.getText(), alias );
+		FromClause fromClause = fromElement.getFromClause();
+		QueryableCollection persister = sessionFactoryHelper.getCollectionPersister( collectionFilterRole );
+		// Get the names of the columns used to link between the collection
+		// owner and the collection elements.
+		String[] keyColumnNames = persister.getKeyColumnNames();
+		String fkTableAlias = persister.isOneToMany()
+				? fromElement.getTableAlias()
+				: fromClause.getAliasGenerator().createName( collectionFilterRole );
+		JoinSequence join = sessionFactoryHelper.createJoinSequence();
+		join.setRoot( persister, fkTableAlias );
+		if ( !persister.isOneToMany() ) {
+			join.addJoin( ( AssociationType ) persister.getElementType(),
+					fromElement.getTableAlias(),
+					JoinFragment.INNER_JOIN,
+					persister.getElementColumnNames( fkTableAlias ) );
+		}
+		join.addCondition( fkTableAlias, keyColumnNames, " = ?" );
+		fromElement.setJoinSequence( join );
+		fromElement.setFilter( true );
+		if ( log.isDebugEnabled() ) {
+			log.debug( "createFromFilterElement() : processed filter FROM element." );
+		}
+		return fromElement;
+	}
+
+	protected void createFromJoinElement(
+	        AST path,
+	        AST alias,
+	        int joinType,
+	        AST fetchNode,
+	        AST propertyFetch,
+	        AST with) throws SemanticException {
+		boolean fetch = fetchNode != null;
+		if ( fetch && isSubQuery() ) {
+			throw new QueryException( "fetch not allowed in subquery from-elements" );
+		}
+		// The path AST should be a DotNode, and it should have been evaluated already.
+		if ( path.getType() != SqlTokenTypes.DOT ) {
+			throw new SemanticException( "Path expected for join!" );
+		}
+		DotNode dot = ( DotNode ) path;
+		int hibernateJoinType = JoinProcessor.toHibernateJoinType( joinType );
+		dot.setJoinType( hibernateJoinType );	// Tell the dot node about the join type.
+		dot.setFetch( fetch );
+		// Generate an explicit join for the root dot node.   The implied joins will be collected and passed up
+		// to the root dot node.
+		dot.resolve( true, false, alias == null ? null : alias.getText() );
+		FromElement fromElement = dot.getImpliedJoin();
+		fromElement.setAllPropertyFetch(propertyFetch!=null);
+
+		if ( with != null ) {
+			if ( fetch ) {
+				throw new SemanticException( "with-clause not allowed on fetched associations; use filters" );
+			}
+			handleWithFragment( fromElement, with );
+		}
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( "createFromJoinElement() : " + getASTPrinter().showAsString( fromElement, "-- join tree --" ) );
+		}
+	}
+
+	private void handleWithFragment(FromElement fromElement, AST hqlWithNode) throws SemanticException
+	{
+		try {
+			withClause( hqlWithNode );
+			AST hqlSqlWithNode = returnAST;
+			if ( log.isDebugEnabled() ) {
+				log.debug( "handleWithFragment() : " + getASTPrinter().showAsString( hqlSqlWithNode, "-- with clause --" ) );
+			}
+			WithClauseVisitor visitor = new WithClauseVisitor();
+			NodeTraverser traverser = new NodeTraverser( visitor );
+			traverser.traverseDepthFirst( hqlSqlWithNode );
+			FromElement referencedFromElement = visitor.getReferencedFromElement();
+			if ( referencedFromElement != fromElement ) {
+				throw new InvalidWithClauseException( "with-clause expressions did not reference from-clause element to which the with-clause was associated" );
+			}
+			SqlGenerator sql = new SqlGenerator( getSessionFactoryHelper().getFactory() );
+			sql.whereExpr( hqlSqlWithNode.getFirstChild() );
+			fromElement.setWithClauseFragment( visitor.getJoinAlias(), "(" + sql.getSQL() + ")" );
+
+		}
+		catch( SemanticException e ) {
+			throw e;
+		}
+		catch( InvalidWithClauseException e ) {
+			throw e;
+		}
+		catch ( Exception e) {
+			throw new SemanticException( e.getMessage() );
+		}
+	}
+
+	private static class WithClauseVisitor implements NodeTraverser.VisitationStrategy {
+		private FromElement referencedFromElement;
+		private String joinAlias;
+
+		public void visit(AST node) {
+			// todo : currently expects that the individual with expressions apply to the same sql table join.
+			//      This may not be the case for joined-subclass where the property values
+			//      might be coming from different tables in the joined hierarchy.  At some
+			//      point we should expand this to support that capability.  However, that has
+			//      some difficulties:
+			//          1) the biggest is how to handle ORs when the individual comparisons are
+			//              linked to different sql joins.
+			//          2) here we would need to track each comparison individually, along with
+			//              the join alias to which it applies and then pass that information
+			//              back to the FromElement so it can pass it along to the JoinSequence
+
+			if ( node instanceof DotNode ) {
+				DotNode dotNode = ( DotNode ) node;
+				FromElement fromElement = dotNode.getFromElement();
+				if ( referencedFromElement != null ) {
+					if ( fromElement != referencedFromElement ) {
+						throw new HibernateException( "with-clause referenced two different from-clause elements" );
+					}
+				}
+				else {
+					referencedFromElement = fromElement;
+					joinAlias = extractAppliedAlias( dotNode );
+					// todo : temporary
+					//      needed because currently persister is the one that
+					//      creates and renders the join fragments for inheritence
+					//      hierarchies...
+					if ( !joinAlias.equals( referencedFromElement.getTableAlias() ) ) {
+						throw new InvalidWithClauseException( "with clause can only reference columns in the driving table" );
+					}
+				}
+			}
+		}
+
+		private String extractAppliedAlias(DotNode dotNode) {
+			return dotNode.getText().substring( 0, dotNode.getText().indexOf( '.' ) );
+		}
+
+		public FromElement getReferencedFromElement() {
+			return referencedFromElement;
+		}
+
+		public String getJoinAlias() {
+			return joinAlias;
+		}
+	}
+
+	/**
+	 * Sets the current 'FROM' context.
+	 *
+	 * @param fromNode      The new 'FROM' context.
+	 * @param inputFromNode The from node from the input AST.
+	 */
+	protected void pushFromClause(AST fromNode, AST inputFromNode) {
+		FromClause newFromClause = ( FromClause ) fromNode;
+		newFromClause.setParentFromClause( currentFromClause );
+		currentFromClause = newFromClause;
+	}
+
+	/**
+	 * Returns to the previous 'FROM' context.
+	 */
+	private void popFromClause() {
+		currentFromClause = currentFromClause.getParentFromClause();
+	}
+
+	protected void lookupAlias(AST aliasRef)
+			throws SemanticException {
+		FromElement alias = currentFromClause.getFromElement( aliasRef.getText() );
+		FromReferenceNode aliasRefNode = ( FromReferenceNode ) aliasRef;
+		aliasRefNode.setFromElement( alias );
+	}
+
+	protected void setImpliedJoinType(int joinType) {
+		impliedJoinType = JoinProcessor.toHibernateJoinType( joinType );
+	}
+
+	public int getImpliedJoinType() {
+		return impliedJoinType;
+	}
+
+	protected AST lookupProperty(AST dot, boolean root, boolean inSelect) throws SemanticException {
+		DotNode dotNode = ( DotNode ) dot;
+		FromReferenceNode lhs = dotNode.getLhs();
+		AST rhs = lhs.getNextSibling();
+		switch ( rhs.getType() ) {
+			case SqlTokenTypes.ELEMENTS:
+			case SqlTokenTypes.INDICES:
+				if ( log.isDebugEnabled() ) {
+					log.debug( "lookupProperty() " + dotNode.getPath() + " => " + rhs.getText() + "(" + lhs.getPath() + ")" );
+				}
+				CollectionFunction f = ( CollectionFunction ) rhs;
+				// Re-arrange the tree so that the collection function is the root and the lhs is the path.
+				f.setFirstChild( lhs );
+				lhs.setNextSibling( null );
+				dotNode.setFirstChild( f );
+				resolve( lhs );			// Don't forget to resolve the argument!
+				f.resolve( inSelect );	// Resolve the collection function now.
+				return f;
+			default:
+				// Resolve everything up to this dot, but don't resolve the placeholders yet.
+				dotNode.resolveFirstChild();
+				return dotNode;
+		}
+	}
+
+	protected boolean isNonQualifiedPropertyRef(AST ident) {
+		final String identText = ident.getText();
+		if ( currentFromClause.isFromElementAlias( identText ) ) {
+			return false;
+		}
+
+		List fromElements = currentFromClause.getExplicitFromElements();
+		if ( fromElements.size() == 1 ) {
+			final FromElement fromElement = ( FromElement ) fromElements.get( 0 );
+			try {
+				log.trace( "attempting to resolve property [" + identText + "] as a non-qualified ref" );
+				return fromElement.getPropertyMapping( identText ).toType( identText ) != null;
+			}
+			catch( QueryException e ) {
+				// Should mean that no such property was found
+			}
+		}
+
+		return false;
+	}
+
+	protected AST lookupNonQualifiedProperty(AST property) throws SemanticException {
+		final FromElement fromElement = ( FromElement ) currentFromClause.getExplicitFromElements().get( 0 );
+		AST syntheticDotNode = generateSyntheticDotNodeForNonQualifiedPropertyRef( property, fromElement );
+		return lookupProperty( syntheticDotNode, false, getCurrentClauseType() == HqlSqlTokenTypes.SELECT );
+	}
+
+	private AST generateSyntheticDotNodeForNonQualifiedPropertyRef(AST property, FromElement fromElement) {
+		AST dot = getASTFactory().create( DOT, "{non-qualified-property-ref}" );
+		// TODO : better way?!?
+		( ( DotNode ) dot ).setPropertyPath( ( ( FromReferenceNode ) property ).getPath() );
+
+		IdentNode syntheticAlias = ( IdentNode ) getASTFactory().create( IDENT, "{synthetic-alias}" );
+		syntheticAlias.setFromElement( fromElement );
+		syntheticAlias.setResolved();
+
+		dot.setFirstChild( syntheticAlias );
+		dot.addChild( property );
+
+		return dot;
+	}
+
+	protected void processQuery(AST select, AST query) throws SemanticException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "processQuery() : " + query.toStringTree() );
+		}
+
+		try {
+			QueryNode qn = ( QueryNode ) query;
+
+			// Was there an explicit select expression?
+			boolean explicitSelect = select != null && select.getNumberOfChildren() > 0;
+
+			if ( !explicitSelect ) {
+				// No explicit select expression; render the id and properties
+				// projection lists for every persister in the from clause into
+				// a single 'token node'.
+				//TODO: the only reason we need this stuff now is collection filters,
+				//      we should get rid of derived select clause completely!
+				createSelectClauseFromFromClause( qn );
+			}
+			else {
+				// Use the explicitly declared select expression; determine the
+				// return types indicated by each select token
+				useSelectClause( select );
+			}
+
+			// After that, process the JOINs.
+			// Invoke a delegate to do the work, as this is farily complex.
+			JoinProcessor joinProcessor = new JoinProcessor( astFactory, queryTranslatorImpl );
+			joinProcessor.processJoins( qn, isSubQuery() );
+
+			// Attach any mapping-defined "ORDER BY" fragments
+			Iterator itr = qn.getFromClause().getProjectionList().iterator();
+			while ( itr.hasNext() ) {
+				final FromElement fromElement = ( FromElement ) itr.next();
+//			if ( fromElement.isFetch() && fromElement.isCollectionJoin() ) {
+				if ( fromElement.isFetch() && fromElement.getQueryableCollection() != null ) {
+					// Does the collection referenced by this FromElement
+					// specify an order-by attribute?  If so, attach it to
+					// the query's order-by
+					if ( fromElement.getQueryableCollection().hasOrdering() ) {
+						String orderByFragment = fromElement
+								.getQueryableCollection()
+								.getSQLOrderByString( fromElement.getCollectionTableAlias() );
+						qn.getOrderByClause().addOrderFragment( orderByFragment );
+					}
+					if ( fromElement.getQueryableCollection().hasManyToManyOrdering() ) {
+						String orderByFragment = fromElement.getQueryableCollection()
+								.getManyToManyOrderByString( fromElement.getTableAlias() );
+						qn.getOrderByClause().addOrderFragment( orderByFragment );
+					}
+				}
+			}
+		}
+		finally {
+			popFromClause();
+		}
+	}
+
+	protected void postProcessDML(RestrictableStatement statement) throws SemanticException {
+		statement.getFromClause().resolve();
+
+		FromElement fromElement = ( FromElement ) statement.getFromClause().getFromElements().get( 0 );
+		Queryable persister = fromElement.getQueryable();
+		// Make #@%$^#^&# sure no alias is applied to the table name
+		fromElement.setText( persister.getTableName() );
+
+		// append any filter fragments; the EMPTY_MAP is used under the assumption that
+		// currently enabled filters should not affect this process
+		if ( persister.getDiscriminatorType() != null ) {
+			new SyntheticAndFactory( getASTFactory() ).addDiscriminatorWhereFragment(
+			        statement,
+			        persister,
+			        java.util.Collections.EMPTY_MAP,
+			        fromElement.getTableAlias()
+			);
+		}
+
+	}
+
+	protected void postProcessUpdate(AST update) throws SemanticException {
+		UpdateStatement updateStatement = ( UpdateStatement ) update;
+
+		postProcessDML( updateStatement );
+	}
+
+	protected void postProcessDelete(AST delete) throws SemanticException {
+		postProcessDML( ( DeleteStatement ) delete );
+	}
+
+	public static boolean supportsIdGenWithBulkInsertion(IdentifierGenerator generator) {
+		return SequenceGenerator.class.isAssignableFrom( generator.getClass() )
+		        || PostInsertIdentifierGenerator.class.isAssignableFrom( generator.getClass() );
+	}
+
+	protected void postProcessInsert(AST insert) throws SemanticException, QueryException {
+		InsertStatement insertStatement = ( InsertStatement ) insert;
+		insertStatement.validate();
+
+		SelectClause selectClause = insertStatement.getSelectClause();
+		Queryable persister = insertStatement.getIntoClause().getQueryable();
+
+		if ( !insertStatement.getIntoClause().isExplicitIdInsertion() ) {
+			// We need to generate ids as part of this bulk insert.
+			//
+			// Note that this is only supported for sequence-style generators and
+			// post-insert-style generators; basically, only in-db generators
+			IdentifierGenerator generator = persister.getIdentifierGenerator();
+			if ( !supportsIdGenWithBulkInsertion( generator ) ) {
+				throw new QueryException( "can only generate ids as part of bulk insert with either sequence or post-insert style generators" );
+			}
+
+			AST idSelectExprNode = null;
+
+			if ( SequenceGenerator.class.isAssignableFrom( generator.getClass() ) ) {
+				String seqName = ( String ) ( ( SequenceGenerator ) generator ).generatorKey();
+				String nextval = sessionFactoryHelper.getFactory().getDialect().getSelectSequenceNextValString( seqName );
+				idSelectExprNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, nextval );
+			}
+			else {
+				//Don't need this, because we should never ever be selecting no columns in an insert ... select...
+				//and because it causes a bug on DB2
+				/*String idInsertString = sessionFactoryHelper.getFactory().getDialect().getIdentityInsertString();
+				if ( idInsertString != null ) {
+					idSelectExprNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, idInsertString );
+				}*/
+			}
+
+			if ( idSelectExprNode != null ) {
+				AST currentFirstSelectExprNode = selectClause.getFirstChild();
+				selectClause.setFirstChild( idSelectExprNode );
+				idSelectExprNode.setNextSibling( currentFirstSelectExprNode );
+
+				insertStatement.getIntoClause().prependIdColumnSpec();
+			}
+		}
+
+		final boolean includeVersionProperty = persister.isVersioned() &&
+				!insertStatement.getIntoClause().isExplicitVersionInsertion() &&
+				persister.isVersionPropertyInsertable();
+		if ( includeVersionProperty ) {
+			// We need to seed the version value as part of this bulk insert
+			VersionType versionType = persister.getVersionType();
+			AST versionValueNode = null;
+
+			if ( sessionFactoryHelper.getFactory().getDialect().supportsParametersInInsertSelect() ) {
+				versionValueNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" );
+				ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType );
+				( ( ParameterNode ) versionValueNode ).setHqlParameterSpecification( paramSpec );
+				parameters.add( 0, paramSpec );
+			}
+			else {
+				if ( isIntegral( versionType ) ) {
+					try {
+						Object seedValue = versionType.seed( null );
+						versionValueNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, seedValue.toString() );
+					}
+					catch( Throwable t ) {
+						throw new QueryException( "could not determine seed value for version on bulk insert [" + versionType + "]" );
+					}
+				}
+				else if ( isDatabaseGeneratedTimestamp( versionType ) ) {
+					String functionName = sessionFactoryHelper.getFactory().getDialect().getCurrentTimestampSQLFunctionName();
+					versionValueNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, functionName );
+				}
+				else {
+					throw new QueryException( "cannot handle version type [" + versionType + "] on bulk inserts with dialects not supporting parameters in insert-select statements" );
+				}
+			}
+
+			AST currentFirstSelectExprNode = selectClause.getFirstChild();
+			selectClause.setFirstChild( versionValueNode );
+			versionValueNode.setNextSibling( currentFirstSelectExprNode );
+
+			insertStatement.getIntoClause().prependVersionColumnSpec();
+		}
+
+		if ( insertStatement.getIntoClause().isDiscriminated() ) {
+			String sqlValue = insertStatement.getIntoClause().getQueryable().getDiscriminatorSQLValue();
+			AST discrimValue = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, sqlValue );
+			insertStatement.getSelectClause().addChild( discrimValue );
+		}
+
+	}
+
+	private boolean isDatabaseGeneratedTimestamp(Type type) {
+		// currently only the Hibernate-supplied DbTimestampType is supported here
+		return DbTimestampType.class.isAssignableFrom( type.getClass() );
+	}
+
+	private boolean isIntegral(Type type) {
+		return Long.class.isAssignableFrom( type.getReturnedClass() )
+		       || Integer.class.isAssignableFrom( type.getReturnedClass() )
+		       || long.class.isAssignableFrom( type.getReturnedClass() )
+		       || int.class.isAssignableFrom( type.getReturnedClass() );
+	}
+
+	private void useSelectClause(AST select) throws SemanticException {
+		selectClause = ( SelectClause ) select;
+		selectClause.initializeExplicitSelectClause( currentFromClause );
+	}
+
+	private void createSelectClauseFromFromClause(QueryNode qn) throws SemanticException {
+		AST select = astFactory.create( SELECT_CLAUSE, "{derived select clause}" );
+		AST sibling = qn.getFromClause();
+		qn.setFirstChild( select );
+		select.setNextSibling( sibling );
+		selectClause = ( SelectClause ) select;
+		selectClause.initializeDerivedSelectClause( currentFromClause );
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Derived SELECT clause created." );
+		}
+	}
+
+	protected void resolve(AST node) throws SemanticException {
+		if ( node != null ) {
+			// This is called when it's time to fully resolve a path expression.
+			ResolvableNode r = ( ResolvableNode ) node;
+			if ( isInFunctionCall() ) {
+				r.resolveInFunctionCall( false, true );
+			}
+			else {
+				r.resolve( false, true );	// Generate implicit joins, only if necessary.
+			}
+		}
+	}
+
+	protected void resolveSelectExpression(AST node) throws SemanticException {
+		// This is called when it's time to fully resolve a path expression.
+		int type = node.getType();
+		switch ( type ) {
+			case DOT:
+				DotNode dot = ( DotNode ) node;
+				dot.resolveSelectExpression();
+				break;
+			case ALIAS_REF:
+				// Notify the FROM element that it is being referenced by the select.
+				FromReferenceNode aliasRefNode = ( FromReferenceNode ) node;
+				//aliasRefNode.resolve( false, false, aliasRefNode.getText() ); //TODO: is it kosher to do it here?
+				aliasRefNode.resolve( false, false ); //TODO: is it kosher to do it here?
+				FromElement fromElement = aliasRefNode.getFromElement();
+				if ( fromElement != null ) {
+					fromElement.setIncludeSubclasses( true );
+				}
+			default:
+				break;
+		}
+	}
+
+	protected void beforeSelectClause() throws SemanticException {
+		// Turn off includeSubclasses on all FromElements.
+		FromClause from = getCurrentFromClause();
+		List fromElements = from.getFromElements();
+		for ( Iterator iterator = fromElements.iterator(); iterator.hasNext(); ) {
+			FromElement fromElement = ( FromElement ) iterator.next();
+			fromElement.setIncludeSubclasses( false );
+		}
+	}
+
+	protected AST generatePositionalParameter(AST inputNode) throws SemanticException {
+		if ( namedParameters.size() > 0 ) {
+			throw new SemanticException( "cannot define positional parameter after any named parameters have been defined" );
+		}
+		ParameterNode parameter = ( ParameterNode ) astFactory.create( PARAM, "?" );
+		PositionalParameterSpecification paramSpec = new PositionalParameterSpecification(
+				( ( Node ) inputNode ).getLine(),
+		        ( ( Node ) inputNode ).getColumn(),
+				positionalParameterCount++
+		);
+		parameter.setHqlParameterSpecification( paramSpec );
+		parameters.add( paramSpec );
+		return parameter;
+	}
+
+	protected AST generateNamedParameter(AST delimiterNode, AST nameNode) throws SemanticException {
+		String name = nameNode.getText();
+		trackNamedParameterPositions( name );
+
+		// create the node initially with the param name so that it shows
+		// appropriately in the "original text" attribute
+		ParameterNode parameter = ( ParameterNode ) astFactory.create( NAMED_PARAM, name );
+		parameter.setText( "?" );
+
+		NamedParameterSpecification paramSpec = new NamedParameterSpecification(
+				( ( Node ) delimiterNode ).getLine(),
+		        ( ( Node ) delimiterNode ).getColumn(),
+				name
+		);
+		parameter.setHqlParameterSpecification( paramSpec );
+		parameters.add( paramSpec );
+		return parameter;
+	}
+
+	private void trackNamedParameterPositions(String name) {
+		Integer loc = new Integer( parameterCount++ );
+		Object o = namedParameters.get( name );
+		if ( o == null ) {
+			namedParameters.put( name, loc );
+		}
+		else if ( o instanceof Integer ) {
+			ArrayList list = new ArrayList( 4 );
+			list.add( o );
+			list.add( loc );
+			namedParameters.put( name, list );
+		}
+		else {
+			( ( ArrayList ) o ).add( loc );
+		}
+	}
+
+	protected void processConstant(AST constant) throws SemanticException {
+		literalProcessor.processConstant( constant, true );  // Use the delegate, resolve identifiers as FROM element aliases.
+	}
+
+	protected void processBoolean(AST constant) throws SemanticException {
+		literalProcessor.processBoolean( constant );  // Use the delegate.
+	}
+
+	protected void processNumericLiteral(AST literal) {
+		literalProcessor.processNumeric( literal );
+	}
+
+	protected void processIndex(AST indexOp) throws SemanticException {
+		IndexNode indexNode = ( IndexNode ) indexOp;
+		indexNode.resolve( true, true );
+	}
+
+	protected void processFunction(AST functionCall, boolean inSelect) throws SemanticException {
+		MethodNode methodNode = ( MethodNode ) functionCall;
+		methodNode.resolve( inSelect );
+	}
+
+	protected void processConstructor(AST constructor) throws SemanticException {
+		ConstructorNode constructorNode = ( ConstructorNode ) constructor;
+		constructorNode.prepare();
+	}
+
+    protected void setAlias(AST selectExpr, AST ident) {
+        ((SelectExpression) selectExpr).setAlias(ident.getText());
+    }
+
+	/**
+	 * Returns the locations of all occurrences of the named parameter.
+	 */
+	public int[] getNamedParameterLocations(String name) throws QueryException {
+		Object o = namedParameters.get( name );
+		if ( o == null ) {
+			QueryException qe = new QueryException( QueryTranslator.ERROR_NAMED_PARAMETER_DOES_NOT_APPEAR + name );
+			qe.setQueryString( queryTranslatorImpl.getQueryString() );
+			throw qe;
+		}
+		if ( o instanceof Integer ) {
+			return new int[]{( ( Integer ) o ).intValue()};
+		}
+		else {
+			return ArrayHelper.toIntArray( ( ArrayList ) o );
+		}
+	}
+
+	public void addQuerySpaces(Serializable[] spaces) {
+		for ( int i = 0; i < spaces.length; i++ ) {
+			querySpaces.add( spaces[i] );
+		}
+	}
+
+	public Type[] getReturnTypes() {
+		return selectClause.getQueryReturnTypes();
+	}
+
+	public String[] getReturnAliases() {
+		return selectClause.getQueryReturnAliases();
+	}
+
+	public SelectClause getSelectClause() {
+		return selectClause;
+	}
+	
+	public FromClause getFinalFromClause() {
+		FromClause top = currentFromClause;
+		while ( top.getParentFromClause() != null ) {
+			top = top.getParentFromClause();
+		}
+		return top;
+	}
+
+	public boolean isShallowQuery() {
+		// select clauses for insert statements should alwasy be treated as shallow
+		return getStatementType() == INSERT || queryTranslatorImpl.isShallowQuery();
+	}
+
+	public Map getEnabledFilters() {
+		return queryTranslatorImpl.getEnabledFilters();
+	}
+
+	public LiteralProcessor getLiteralProcessor() {
+		return literalProcessor;
+	}
+
+	public ASTPrinter getASTPrinter() {
+		return printer;
+	}
+
+	public ArrayList getParameters() {
+		return parameters;
+	}
+
+	public int getNumberOfParametersInSetClause() {
+		return numberOfParametersInSetClause;
+	}
+
+	protected void evaluateAssignment(AST eq) throws SemanticException {
+		prepareLogicOperator( eq );
+		Queryable persister = getCurrentFromClause().getFromElement().getQueryable();
+		evaluateAssignment( eq, persister, -1 );
+	}
+
+	private void evaluateAssignment(AST eq, Queryable persister, int targetIndex) {
+		if ( persister.isMultiTable() ) {
+			// no need to even collect this information if the persister is considered multi-table
+			AssignmentSpecification specification = new AssignmentSpecification( eq, persister );
+			if ( targetIndex >= 0 ) {
+				assignmentSpecifications.add( targetIndex, specification );
+			}
+			else {
+				assignmentSpecifications.add( specification );
+			}
+			numberOfParametersInSetClause += specification.getParameters().length;
+		}
+	}
+
+	public ArrayList getAssignmentSpecifications() {
+		return assignmentSpecifications;
+	}
+
+	protected AST createIntoClause(String path, AST propertySpec) throws SemanticException {
+		Queryable persister = ( Queryable ) getSessionFactoryHelper().requireClassPersister( path );
+
+		IntoClause intoClause = ( IntoClause ) getASTFactory().create( INTO, persister.getEntityName() );
+		intoClause.setFirstChild( propertySpec );
+		intoClause.initialize( persister );
+
+		addQuerySpaces( persister.getQuerySpaces() );
+
+		return intoClause;
+	}
+
+	protected void prepareVersioned(AST updateNode, AST versioned) throws SemanticException {
+		UpdateStatement updateStatement = ( UpdateStatement ) updateNode;
+		FromClause fromClause = updateStatement.getFromClause();
+		if ( versioned != null ) {
+			// Make sure that the persister is versioned
+			Queryable persister = fromClause.getFromElement().getQueryable();
+			if ( !persister.isVersioned() ) {
+				throw new SemanticException( "increment option specified for update of non-versioned entity" );
+			}
+
+			VersionType versionType = persister.getVersionType();
+			if ( versionType instanceof UserVersionType ) {
+				throw new SemanticException( "user-defined version types not supported for increment option" );
+			}
+
+			AST eq = getASTFactory().create( HqlSqlTokenTypes.EQ, "=" );
+			AST versionPropertyNode = generateVersionPropertyNode( persister );
+
+			eq.setFirstChild( versionPropertyNode );
+
+			AST versionIncrementNode = null;
+			if ( Date.class.isAssignableFrom( versionType.getReturnedClass() ) ) {
+				versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" );
+				ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType );
+				( ( ParameterNode ) versionIncrementNode ).setHqlParameterSpecification( paramSpec );
+				parameters.add( 0, paramSpec );
+			}
+			else {
+				// Not possible to simply re-use the versionPropertyNode here as it causes
+				// OOM errors due to circularity :(
+				versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PLUS, "+" );
+				versionIncrementNode.setFirstChild( generateVersionPropertyNode( persister ) );
+				versionIncrementNode.addChild( getASTFactory().create( HqlSqlTokenTypes.IDENT, "1" ) );
+			}
+
+			eq.addChild( versionIncrementNode );
+
+			evaluateAssignment( eq, persister, 0 );
+
+			AST setClause = updateStatement.getSetClause();
+			AST currentFirstSetElement = setClause.getFirstChild();
+			setClause.setFirstChild( eq );
+			eq.setNextSibling( currentFirstSetElement );
+		}
+	}
+
+	private AST generateVersionPropertyNode(Queryable persister) throws SemanticException {
+		String versionPropertyName = persister.getPropertyNames()[ persister.getVersionProperty() ];
+		AST versionPropertyRef = getASTFactory().create( HqlSqlTokenTypes.IDENT, versionPropertyName );
+		AST versionPropertyNode = lookupNonQualifiedProperty( versionPropertyRef );
+		resolve( versionPropertyNode );
+		return versionPropertyNode;
+	}
+
+	protected void prepareLogicOperator(AST operator) throws SemanticException {
+		( ( OperatorNode ) operator ).initialize();
+	}
+
+	protected void prepareArithmeticOperator(AST operator) throws SemanticException {
+		( ( OperatorNode ) operator ).initialize();
+	}
+
+	public static void panic() {
+		throw new QueryException( "TreeWalker: panic" );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlToken.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlToken.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/HqlToken.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,71 @@
+// $Id: HqlToken.java 4335 2004-08-15 17:03:43Z pgmjsd $
+package org.hibernate.hql.ast;
+
+/**
+ * A custom token class for the HQL grammar.
+ * <p><i>NOTE:<i> This class must be public becuase it is instantiated by the ANTLR library.  Ignore any suggestions
+ * by various code 'analyzers' about this class being package local.</p>
+ */
+public class HqlToken extends antlr.CommonToken {
+	/**
+	 * True if this token could be an identifier. *
+	 */
+	private boolean possibleID = false;
+	/**
+	 * The previous token type. *
+	 */
+	private int tokenType;
+
+	/**
+	 * Returns true if the token could be an identifier.
+	 *
+	 * @return True if the token could be interpreted as in identifier,
+	 *         false if not.
+	 */
+	public boolean isPossibleID() {
+		return possibleID;
+	}
+
+	/**
+	 * Sets the type of the token, remembering the previous type.
+	 *
+	 * @param t The new token type.
+	 */
+	public void setType(int t) {
+		this.tokenType = getType();
+		super.setType( t );
+	}
+
+	/**
+	 * Returns the previous token type.
+	 *
+	 * @return int - The old token type.
+	 */
+	private int getPreviousType() {
+		return tokenType;
+	}
+
+	/**
+	 * Set to true if this token can be interpreted as an identifier,
+	 * false if not.
+	 *
+	 * @param possibleID True if this is a keyword/identifier, false if not.
+	 */
+	public void setPossibleID(boolean possibleID) {
+		this.possibleID = possibleID;
+	}
+
+	/**
+	 * Returns a string representation of the object.
+	 *
+	 * @return String - The debug string.
+	 */
+	public String toString() {
+		return "[\""
+				+ getText()
+				+ "\",<" + getType() + "> previously: <" + getPreviousType() + ">,line="
+				+ line + ",col="
+				+ col + ",possibleID=" + possibleID + "]";
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/InvalidPathException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/InvalidPathException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/InvalidPathException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+// $Id: InvalidPathException.java 4903 2004-12-07 07:53:10Z pgmjsd $
+package org.hibernate.hql.ast;
+
+import antlr.SemanticException;
+
+/**
+ * Exception thrown when an invalid path is found in a query.
+ *
+ * @author josh Dec 5, 2004 7:05:34 PM
+ */
+public class InvalidPathException extends SemanticException {
+	public InvalidPathException(String s) {
+		super( s );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/InvalidWithClauseException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/InvalidWithClauseException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/InvalidWithClauseException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+package org.hibernate.hql.ast;
+
+import org.hibernate.QueryException;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class InvalidWithClauseException extends QuerySyntaxException {
+	public InvalidWithClauseException(String message) {
+		super( message );
+	}
+
+	public InvalidWithClauseException(String message, String queryString) {
+		super( message, queryString );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ParameterTranslationsImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ParameterTranslationsImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ParameterTranslationsImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,149 @@
+package org.hibernate.hql.ast;
+
+import org.hibernate.hql.ParameterTranslations;
+import org.hibernate.type.Type;
+import org.hibernate.param.ParameterSpecification;
+import org.hibernate.param.PositionalParameterSpecification;
+import org.hibernate.param.NamedParameterSpecification;
+import org.hibernate.util.ArrayHelper;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.io.Serializable;
+
+/**
+ * Defines the information available for parameters encountered during
+ * query translation through the antlr-based parser.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class ParameterTranslationsImpl implements ParameterTranslations {
+
+	private final Map namedParameters;
+	private final ParameterInfo[] ordinalParameters;
+
+	public boolean supportsOrdinalParameterMetadata() {
+		return true;
+	}
+
+	public int getOrdinalParameterCount() {
+		return ordinalParameters.length;
+	}
+
+	public ParameterInfo getOrdinalParameterInfo(int ordinalPosition) {
+		// remember that ordinal parameters numbers are 1-based!!!
+		return ordinalParameters[ordinalPosition - 1];
+	}
+
+	public int getOrdinalParameterSqlLocation(int ordinalPosition) {
+		return getOrdinalParameterInfo( ordinalPosition ).getSqlLocations()[0];
+	}
+
+	public Type getOrdinalParameterExpectedType(int ordinalPosition) {
+		return getOrdinalParameterInfo( ordinalPosition ).getExpectedType();
+	}
+
+	public Set getNamedParameterNames() {
+		return namedParameters.keySet();
+	}
+
+	public ParameterInfo getNamedParameterInfo(String name) {
+		return ( ParameterInfo ) namedParameters.get( name );
+	}
+
+	public int[] getNamedParameterSqlLocations(String name) {
+		return getNamedParameterInfo( name ).getSqlLocations();
+	}
+
+	public Type getNamedParameterExpectedType(String name) {
+		return getNamedParameterInfo( name ).getExpectedType();
+	}
+
+	/**
+	 * Constructs a parameter metadata object given a list of parameter
+	 * specifications.
+	 * </p>
+	 * Note: the order in the incoming list denotes the parameter's
+	 * psudeo-position within the resulting sql statement.
+	 *
+	 * @param parameterSpecifications
+	 */
+	public ParameterTranslationsImpl(List parameterSpecifications) {
+
+		class NamedParamTempHolder {
+			String name;
+			Type type;
+			List positions = new ArrayList();
+		}
+
+		int size = parameterSpecifications.size();
+		List ordinalParameterList = new ArrayList();
+		Map namedParameterMap = new HashMap();
+		for ( int i = 0; i < size; i++ ) {
+			final ParameterSpecification spec = ( ParameterSpecification ) parameterSpecifications.get( i );
+			if ( PositionalParameterSpecification.class.isAssignableFrom( spec.getClass() ) ) {
+				PositionalParameterSpecification ordinalSpec = ( PositionalParameterSpecification ) spec;
+				ordinalParameterList.add( new ParameterInfo( i, ordinalSpec.getExpectedType() ) );
+			}
+			else if ( NamedParameterSpecification.class.isAssignableFrom( spec.getClass() ) ) {
+				NamedParameterSpecification namedSpec = ( NamedParameterSpecification ) spec;
+				NamedParamTempHolder paramHolder = ( NamedParamTempHolder ) namedParameterMap.get( namedSpec.getName() );
+				if ( paramHolder == null ) {
+					paramHolder = new NamedParamTempHolder();
+					paramHolder.name = namedSpec.getName();
+					paramHolder.type = namedSpec.getExpectedType();
+					namedParameterMap.put( namedSpec.getName(), paramHolder );
+				}
+				paramHolder.positions.add( new Integer( i ) );
+			}
+			else {
+				// don't care about other param types here, just those explicitly user-defined...
+			}
+		}
+
+		ordinalParameters = ( ParameterInfo[] ) ordinalParameterList.toArray( new ParameterInfo[ordinalParameterList.size()] );
+
+		if ( namedParameterMap.isEmpty() ) {
+			namedParameters = java.util.Collections.EMPTY_MAP;
+		}
+		else {
+			Map namedParametersBacking = new HashMap( namedParameterMap.size() );
+			Iterator itr = namedParameterMap.values().iterator();
+			while( itr.hasNext() ) {
+				final NamedParamTempHolder holder = ( NamedParamTempHolder ) itr.next();
+				namedParametersBacking.put(
+						holder.name,
+				        new ParameterInfo( ArrayHelper.toIntArray( holder.positions ), holder.type )
+				);
+			}
+			namedParameters = java.util.Collections.unmodifiableMap( namedParametersBacking );
+		}
+	}
+
+	public static class ParameterInfo implements Serializable {
+		private final int[] sqlLocations;
+		private final Type expectedType;
+
+		public ParameterInfo(int[] sqlPositions, Type expectedType) {
+			this.sqlLocations = sqlPositions;
+			this.expectedType = expectedType;
+		}
+
+		public ParameterInfo(int sqlPosition, Type expectedType) {
+			this.sqlLocations = new int[] { sqlPosition };
+			this.expectedType = expectedType;
+		}
+
+		public int[] getSqlLocations() {
+			return sqlLocations;
+		}
+
+		public Type getExpectedType() {
+			return expectedType;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ParseErrorHandler.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ParseErrorHandler.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/ParseErrorHandler.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+// $Id: ParseErrorHandler.java 4941 2004-12-11 16:31:18Z pgmjsd $
+
+package org.hibernate.hql.ast;
+
+import org.hibernate.QueryException;
+
+
+/**
+ * Defines the behavior of an error handler for the HQL parsers.
+ * User: josh
+ * Date: Dec 6, 2003
+ * Time: 12:20:43 PM
+ */
+public interface ParseErrorHandler extends ErrorReporter {
+
+	int getErrorCount();
+
+	// --Commented out by Inspection (12/11/04 10:56 AM): int getWarningCount();
+
+	void throwQueryException() throws QueryException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/QuerySyntaxException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/QuerySyntaxException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/QuerySyntaxException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+// $Id: QuerySyntaxException.java 9242 2006-02-09 12:37:36Z steveebersole $
+package org.hibernate.hql.ast;
+
+import antlr.RecognitionException;
+import org.hibernate.QueryException;
+
+/**
+ * Exception thrown when there is a syntax error in the HQL.
+ *
+ * @author josh
+ */
+public class QuerySyntaxException extends QueryException {
+
+	public QuerySyntaxException(String message) {
+		super( message );
+	}
+
+	public QuerySyntaxException(String message, String hql) {
+		this( message );
+		setQueryString( hql );
+	}
+
+	public static QuerySyntaxException convert(RecognitionException e) {
+		return convert( e, null );
+	}
+
+	public static QuerySyntaxException convert(RecognitionException e, String hql) {
+		String positionInfo = e.getLine() > 0 && e.getColumn() > 0
+				? " near line " + e.getLine() + ", column " + e.getColumn()
+				: "";
+		return new QuerySyntaxException( e.getMessage() + positionInfo, hql );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/QueryTranslatorImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/QueryTranslatorImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/QueryTranslatorImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,577 @@
+// $Id: QueryTranslatorImpl.java 10000 2006-06-08 21:04:45Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast;
+
+import antlr.ANTLRException;
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+import antlr.collections.AST;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.ScrollableResults;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.RowSelection;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.event.EventSource;
+import org.hibernate.hql.FilterTranslator;
+import org.hibernate.hql.QueryExecutionRequestException;
+import org.hibernate.hql.ParameterTranslations;
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.hql.antlr.HqlTokenTypes;
+import org.hibernate.hql.antlr.SqlTokenTypes;
+import org.hibernate.hql.ast.exec.BasicExecutor;
+import org.hibernate.hql.ast.exec.MultiTableDeleteExecutor;
+import org.hibernate.hql.ast.exec.MultiTableUpdateExecutor;
+import org.hibernate.hql.ast.exec.StatementExecutor;
+import org.hibernate.hql.ast.tree.FromElement;
+import org.hibernate.hql.ast.tree.InsertStatement;
+import org.hibernate.hql.ast.tree.QueryNode;
+import org.hibernate.hql.ast.tree.Statement;
+import org.hibernate.hql.ast.util.ASTPrinter;
+import org.hibernate.hql.ast.util.NodeTraverser;
+import org.hibernate.hql.ast.util.ASTUtil;
+import org.hibernate.loader.hql.QueryLoader;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.type.Type;
+import org.hibernate.util.IdentitySet;
+import org.hibernate.util.StringHelper;
+import org.hibernate.util.ReflectHelper;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.ArrayList;
+
+/**
+ * A QueryTranslator that uses an Antlr-based parser.
+ *
+ * @author Joshua Davis (pgmjsd at sourceforge.net)
+ */
+public class QueryTranslatorImpl implements FilterTranslator {
+
+	private static final Log log = LogFactory.getLog( QueryTranslatorImpl.class );
+	private static final Log AST_LOG = LogFactory.getLog( "org.hibernate.hql.ast.AST" );
+
+	private SessionFactoryImplementor factory;
+
+	private final String queryIdentifier;
+	private String hql;
+	private boolean shallowQuery;
+	private Map tokenReplacements;
+
+	private Map enabledFilters; //TODO:this is only needed during compilation .. can we eliminate the instvar?
+
+	private boolean compiled;
+	private QueryLoader queryLoader;
+	private StatementExecutor statementExecutor;
+
+	private Statement sqlAst;
+	private String sql;
+
+	private ParameterTranslations paramTranslations;
+
+	/**
+	 * Creates a new AST-based query translator.
+	 *
+	 * @param queryIdentifier The query-identifier (used in stats collection)
+	 * @param query The hql query to translate
+	 * @param enabledFilters Currently enabled filters
+	 * @param factory The session factory constructing this translator instance.
+	 */
+	public QueryTranslatorImpl(
+			String queryIdentifier,
+	        String query,
+	        Map enabledFilters,
+	        SessionFactoryImplementor factory) {
+		this.queryIdentifier = queryIdentifier;
+		this.hql = query;
+		this.compiled = false;
+		this.shallowQuery = false;
+		this.enabledFilters = enabledFilters;
+		this.factory = factory;
+	}
+
+	/**
+	 * Compile a "normal" query. This method may be called multiple
+	 * times. Subsequent invocations are no-ops.
+	 *
+	 * @param replacements Defined query substitutions.
+	 * @param shallow      Does this represent a shallow (scalar or entity-id) select?
+	 * @throws QueryException   There was a problem parsing the query string.
+	 * @throws MappingException There was a problem querying defined mappings.
+	 */
+	public void compile(
+	        Map replacements,
+	        boolean shallow) throws QueryException, MappingException {
+		doCompile( replacements, shallow, null );
+	}
+
+	/**
+	 * Compile a filter. This method may be called multiple
+	 * times. Subsequent invocations are no-ops.
+	 *
+	 * @param collectionRole the role name of the collection used as the basis for the filter.
+	 * @param replacements   Defined query substitutions.
+	 * @param shallow        Does this represent a shallow (scalar or entity-id) select?
+	 * @throws QueryException   There was a problem parsing the query string.
+	 * @throws MappingException There was a problem querying defined mappings.
+	 */
+	public void compile(
+	        String collectionRole,
+	        Map replacements,
+	        boolean shallow) throws QueryException, MappingException {
+		doCompile( replacements, shallow, collectionRole );
+	}
+
+	/**
+	 * Performs both filter and non-filter compiling.
+	 *
+	 * @param replacements   Defined query substitutions.
+	 * @param shallow        Does this represent a shallow (scalar or entity-id) select?
+	 * @param collectionRole the role name of the collection used as the basis for the filter, NULL if this
+	 *                       is not a filter.
+	 */
+	private synchronized void doCompile(Map replacements, boolean shallow, String collectionRole) {
+		// If the query is already compiled, skip the compilation.
+		if ( compiled ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "compile() : The query is already compiled, skipping..." );
+			}
+			return;
+		}
+
+		// Remember the parameters for the compilation.
+		this.tokenReplacements = replacements;
+		if ( tokenReplacements == null ) {
+			tokenReplacements = new HashMap();
+		}
+		this.shallowQuery = shallow;
+
+		try {
+			// PHASE 1 : Parse the HQL into an AST.
+			HqlParser parser = parse( true );
+
+			// PHASE 2 : Analyze the HQL AST, and produce an SQL AST.
+			HqlSqlWalker w = analyze( parser, collectionRole );
+
+			sqlAst = ( Statement ) w.getAST();
+
+			// at some point the generate phase needs to be moved out of here,
+			// because a single object-level DML might spawn multiple SQL DML
+			// command executions.
+			//
+			// Possible to just move the sql generation for dml stuff, but for
+			// consistency-sake probably best to just move responsiblity for
+			// the generation phase completely into the delegates
+			// (QueryLoader/StatementExecutor) themselves.  Also, not sure why
+			// QueryLoader currently even has a dependency on this at all; does
+			// it need it?  Ideally like to see the walker itself given to the delegates directly...
+
+			if ( sqlAst.needsExecutor() ) {
+				statementExecutor = buildAppropriateStatementExecutor( w );
+			}
+			else {
+				// PHASE 3 : Generate the SQL.
+				generate( ( QueryNode ) sqlAst );
+				queryLoader = new QueryLoader( this, factory, w.getSelectClause() );
+			}
+
+			compiled = true;
+		}
+		catch ( QueryException qe ) {
+			qe.setQueryString( hql );
+			throw qe;
+		}
+		catch ( RecognitionException e ) {
+			// we do not actually propogate ANTLRExceptions as a cause, so
+			// log it here for diagnostic purposes
+			if ( log.isTraceEnabled() ) {
+				log.trace( "converted antlr.RecognitionException", e );
+			}
+			throw QuerySyntaxException.convert( e, hql );
+		}
+		catch ( ANTLRException e ) {
+			// we do not actually propogate ANTLRExceptions as a cause, so
+			// log it here for diagnostic purposes
+			if ( log.isTraceEnabled() ) {
+				log.trace( "converted antlr.ANTLRException", e );
+			}
+			throw new QueryException( e.getMessage(), hql );
+		}
+
+		this.enabledFilters = null; //only needed during compilation phase...
+	}
+
+	private void generate(AST sqlAst) throws QueryException, RecognitionException {
+		if ( sql == null ) {
+			SqlGenerator gen = new SqlGenerator(factory);
+			gen.statement( sqlAst );
+			sql = gen.getSQL();
+			if ( log.isDebugEnabled() ) {
+				log.debug( "HQL: " + hql );
+				log.debug( "SQL: " + sql );
+			}
+			gen.getParseErrorHandler().throwQueryException();
+		}
+	}
+
+	private HqlSqlWalker analyze(HqlParser parser, String collectionRole) throws QueryException, RecognitionException {
+		HqlSqlWalker w = new HqlSqlWalker( this, factory, parser, tokenReplacements, collectionRole );
+		AST hqlAst = parser.getAST();
+
+		// Transform the tree.
+		w.statement( hqlAst );
+
+		if ( AST_LOG.isDebugEnabled() ) {
+			ASTPrinter printer = new ASTPrinter( SqlTokenTypes.class );
+			AST_LOG.debug( printer.showAsString( w.getAST(), "--- SQL AST ---" ) );
+		}
+
+		w.getParseErrorHandler().throwQueryException();
+
+		return w;
+	}
+
+	private HqlParser parse(boolean filter) throws TokenStreamException, RecognitionException {
+		// Parse the query string into an HQL AST.
+		HqlParser parser = HqlParser.getInstance( hql );
+		parser.setFilter( filter );
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( "parse() - HQL: " + hql );
+		}
+		parser.statement();
+
+		AST hqlAst = parser.getAST();
+
+		JavaConstantConverter converter = new JavaConstantConverter();
+		NodeTraverser walker = new NodeTraverser( converter );
+		walker.traverseDepthFirst( hqlAst );
+
+		showHqlAst( hqlAst );
+
+		parser.getParseErrorHandler().throwQueryException();
+		return parser;
+	}
+
+	void showHqlAst(AST hqlAst) {
+		if ( AST_LOG.isDebugEnabled() ) {
+			ASTPrinter printer = new ASTPrinter( HqlTokenTypes.class );
+			printer.setShowClassNames( false ); // The class names aren't interesting in the first tree.
+			AST_LOG.debug( printer.showAsString( hqlAst, "--- HQL AST ---" ) );
+		}
+	}
+
+	private void errorIfDML() throws HibernateException {
+		if ( sqlAst.needsExecutor() ) {
+			throw new QueryExecutionRequestException( "Not supported for DML operations", hql );
+		}
+	}
+
+	private void errorIfSelect() throws HibernateException {
+		if ( !sqlAst.needsExecutor() ) {
+			throw new QueryExecutionRequestException( "Not supported for select queries", hql );
+		}
+	}
+
+	public String getQueryIdentifier() {
+		return queryIdentifier;
+	}
+
+	public Statement getSqlAST() {
+		return sqlAst;
+	}
+
+	private HqlSqlWalker getWalker() {
+		return sqlAst.getWalker();
+	}
+
+	/**
+	 * Types of the return values of an <tt>iterate()</tt> style query.
+	 *
+	 * @return an array of <tt>Type</tt>s.
+	 */
+	public Type[] getReturnTypes() {
+		errorIfDML();
+		return getWalker().getReturnTypes();
+	}
+
+	public String[] getReturnAliases() {
+		errorIfDML();
+		return getWalker().getReturnAliases();
+	}
+
+	public String[][] getColumnNames() {
+		errorIfDML();
+		return getWalker().getSelectClause().getColumnNames();
+	}
+
+	public Set getQuerySpaces() {
+		return getWalker().getQuerySpaces();
+	}
+
+	public List list(SessionImplementor session, QueryParameters queryParameters)
+			throws HibernateException {
+		// Delegate to the QueryLoader...
+		errorIfDML();
+		QueryNode query = ( QueryNode ) sqlAst;
+		boolean hasLimit = queryParameters.getRowSelection() != null && queryParameters.getRowSelection().definesLimits();
+		boolean needsDistincting = ( query.getSelectClause().isDistinct() || hasLimit ) && containsCollectionFetches();
+
+		QueryParameters queryParametersToUse;
+		if ( hasLimit && containsCollectionFetches() ) {
+			log.warn( "firstResult/maxResults specified with collection fetch; applying in memory!" );
+			RowSelection selection = new RowSelection();
+			selection.setFetchSize( queryParameters.getRowSelection().getFetchSize() );
+			selection.setTimeout( queryParameters.getRowSelection().getTimeout() );
+			queryParametersToUse = queryParameters.createCopyUsing( selection );
+		}
+		else {
+			queryParametersToUse = queryParameters;
+		}
+
+		List results = queryLoader.list( session, queryParametersToUse );
+
+		if ( needsDistincting ) {
+			int includedCount = -1;
+			// NOTE : firstRow is zero-based
+			int first = !hasLimit || queryParameters.getRowSelection().getFirstRow() == null
+						? 0
+						: queryParameters.getRowSelection().getFirstRow().intValue();
+			int max = !hasLimit || queryParameters.getRowSelection().getMaxRows() == null
+						? -1
+						: queryParameters.getRowSelection().getMaxRows().intValue();
+			int size = results.size();
+			List tmp = new ArrayList();
+			IdentitySet distinction = new IdentitySet();
+			for ( int i = 0; i < size; i++ ) {
+				final Object result = results.get( i );
+				if ( !distinction.add( result ) ) {
+					continue;
+				}
+				includedCount++;
+				if ( includedCount < first ) {
+					continue;
+				}
+				tmp.add( result );
+				// NOTE : ( max - 1 ) because first is zero-based while max is not...
+				if ( max >= 0 && ( includedCount - first ) >= ( max - 1 ) ) {
+					break;
+				}
+			}
+			results = tmp;
+		}
+
+		return results;
+	}
+
+	/**
+	 * Return the query results as an iterator
+	 */
+	public Iterator iterate(QueryParameters queryParameters, EventSource session)
+			throws HibernateException {
+		// Delegate to the QueryLoader...
+		errorIfDML();
+		return queryLoader.iterate( queryParameters, session );
+	}
+
+	/**
+	 * Return the query results, as an instance of <tt>ScrollableResults</tt>
+	 */
+	public ScrollableResults scroll(QueryParameters queryParameters, SessionImplementor session)
+			throws HibernateException {
+		// Delegate to the QueryLoader...
+		errorIfDML();
+		return queryLoader.scroll( queryParameters, session );
+	}
+
+	public int executeUpdate(QueryParameters queryParameters, SessionImplementor session)
+			throws HibernateException {
+		errorIfSelect();
+		return statementExecutor.execute( queryParameters, session );
+	}
+
+	/**
+	 * The SQL query string to be called; implemented by all subclasses
+	 */
+	public String getSQLString() {
+		return sql;
+	}
+
+	public List collectSqlStrings() {
+		ArrayList list = new ArrayList();
+		if ( isManipulationStatement() ) {
+			String[] sqlStatements = statementExecutor.getSqlStatements();
+			for ( int i = 0; i < sqlStatements.length; i++ ) {
+				list.add( sqlStatements[i] );
+			}
+		}
+		else {
+			list.add( sql );
+		}
+		return list;
+	}
+
+	// -- Package local methods for the QueryLoader delegate --
+
+	public boolean isShallowQuery() {
+		return shallowQuery;
+	}
+
+	public String getQueryString() {
+		return hql;
+	}
+
+	public Map getEnabledFilters() {
+		return enabledFilters;
+	}
+
+	public int[] getNamedParameterLocs(String name) {
+		return getWalker().getNamedParameterLocations( name );
+	}
+
+	public boolean containsCollectionFetches() {
+		errorIfDML();
+		List collectionFetches = ( ( QueryNode ) sqlAst ).getFromClause().getCollectionFetches();
+		return collectionFetches != null && collectionFetches.size() > 0;
+	}
+
+	public boolean isManipulationStatement() {
+		return sqlAst.needsExecutor();
+	}
+
+	public void validateScrollability() throws HibernateException {
+		// Impl Note: allows multiple collection fetches as long as the
+		// entire fecthed graph still "points back" to a single
+		// root entity for return
+
+		errorIfDML();
+
+		QueryNode query = ( QueryNode ) sqlAst;
+
+		// If there are no collection fetches, then no further checks are needed
+		List collectionFetches = query.getFromClause().getCollectionFetches();
+		if ( collectionFetches.isEmpty() ) {
+			return;
+		}
+
+		// A shallow query is ok (although technically there should be no fetching here...)
+		if ( isShallowQuery() ) {
+			return;
+		}
+
+		// Otherwise, we have a non-scalar select with defined collection fetch(es).
+		// Make sure that there is only a single root entity in the return (no tuples)
+		if ( getReturnTypes().length > 1 ) {
+			throw new HibernateException( "cannot scroll with collection fetches and returned tuples" );
+		}
+
+		FromElement owner = null;
+		Iterator itr = query.getSelectClause().getFromElementsForLoad().iterator();
+		while ( itr.hasNext() ) {
+			// should be the first, but just to be safe...
+			final FromElement fromElement = ( FromElement ) itr.next();
+			if ( fromElement.getOrigin() == null ) {
+				owner = fromElement;
+				break;
+			}
+		}
+
+		if ( owner == null ) {
+			throw new HibernateException( "unable to locate collection fetch(es) owner for scrollability checks" );
+		}
+
+		// This is not strictly true.  We actually just need to make sure that
+		// it is ordered by root-entity PK and that that order-by comes before
+		// any non-root-entity ordering...
+
+		AST primaryOrdering = query.getOrderByClause().getFirstChild();
+		if ( primaryOrdering != null ) {
+			// TODO : this is a bit dodgy, come up with a better way to check this (plus see above comment)
+			String [] idColNames = owner.getQueryable().getIdentifierColumnNames();
+			String expectedPrimaryOrderSeq = StringHelper.join(
+			        ", ",
+			        StringHelper.qualify( owner.getTableAlias(), idColNames )
+			);
+			if (  !primaryOrdering.getText().startsWith( expectedPrimaryOrderSeq ) ) {
+				throw new HibernateException( "cannot scroll results with collection fetches which are not ordered primarily by the root entity's PK" );
+			}
+		}
+	}
+
+	private StatementExecutor buildAppropriateStatementExecutor(HqlSqlWalker walker) {
+		Statement statement = ( Statement ) walker.getAST();
+		if ( walker.getStatementType() == HqlSqlTokenTypes.DELETE ) {
+			FromElement fromElement = walker.getFinalFromClause().getFromElement();
+			Queryable persister = fromElement.getQueryable();
+			if ( persister.isMultiTable() ) {
+				return new MultiTableDeleteExecutor( walker );
+			}
+			else {
+				return new BasicExecutor( walker, persister );
+			}
+		}
+		else if ( walker.getStatementType() == HqlSqlTokenTypes.UPDATE ) {
+			FromElement fromElement = walker.getFinalFromClause().getFromElement();
+			Queryable persister = fromElement.getQueryable();
+			if ( persister.isMultiTable() ) {
+				// even here, if only properties mapped to the "base table" are referenced
+				// in the set and where clauses, this could be handled by the BasicDelegate.
+				// TODO : decide if it is better performance-wise to perform that check, or to simply use the MultiTableUpdateDelegate
+				return new MultiTableUpdateExecutor( walker );
+			}
+			else {
+				return new BasicExecutor( walker, persister );
+			}
+		}
+		else if ( walker.getStatementType() == HqlSqlTokenTypes.INSERT ) {
+			return new BasicExecutor( walker, ( ( InsertStatement ) statement ).getIntoClause().getQueryable() );
+		}
+		else {
+			throw new QueryException( "Unexpected statement type" );
+		}
+	}
+
+	public ParameterTranslations getParameterTranslations() {
+		if ( paramTranslations == null ) {
+			paramTranslations = new ParameterTranslationsImpl( getWalker().getParameters() );
+		}
+		return paramTranslations;
+	}
+
+	public static class JavaConstantConverter implements NodeTraverser.VisitationStrategy {
+		private AST dotRoot;
+		public void visit(AST node) {
+			if ( dotRoot != null ) {
+				// we are already processing a dot-structure
+				if ( ASTUtil.isSubtreeChild( dotRoot, node ) ) {
+					// igndore it...
+					return;
+				}
+				else {
+					// we are now at a new tree level
+					dotRoot = null;
+				}
+			}
+
+			if ( dotRoot == null && node.getType() == HqlTokenTypes.DOT ) {
+				dotRoot = node;
+				handleDotStructure( dotRoot );
+			}
+		}
+		private void handleDotStructure(AST dotStructureRoot) {
+			String expression = ASTUtil.getPathText( dotStructureRoot );
+			Object constant = ReflectHelper.getConstantValue( expression );
+			if ( constant != null ) {
+				dotStructureRoot.setFirstChild( null );
+				dotStructureRoot.setType( HqlTokenTypes.JAVA_CONSTANT );
+				dotStructureRoot.setText( expression );
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/SqlASTFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/SqlASTFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/SqlASTFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,221 @@
+// $Id: SqlASTFactory.java 10060 2006-06-28 02:53:39Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast;
+
+import antlr.ASTFactory;
+import antlr.Token;
+import antlr.collections.AST;
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.hql.ast.tree.AggregateNode;
+import org.hibernate.hql.ast.tree.BinaryArithmeticOperatorNode;
+import org.hibernate.hql.ast.tree.BinaryLogicOperatorNode;
+import org.hibernate.hql.ast.tree.Case2Node;
+import org.hibernate.hql.ast.tree.CaseNode;
+import org.hibernate.hql.ast.tree.CollectionFunction;
+import org.hibernate.hql.ast.tree.ConstructorNode;
+import org.hibernate.hql.ast.tree.CountNode;
+import org.hibernate.hql.ast.tree.DeleteStatement;
+import org.hibernate.hql.ast.tree.DotNode;
+import org.hibernate.hql.ast.tree.FromClause;
+import org.hibernate.hql.ast.tree.FromElement;
+import org.hibernate.hql.ast.tree.IdentNode;
+import org.hibernate.hql.ast.tree.ImpliedFromElement;
+import org.hibernate.hql.ast.tree.IndexNode;
+import org.hibernate.hql.ast.tree.InitializeableNode;
+import org.hibernate.hql.ast.tree.InsertStatement;
+import org.hibernate.hql.ast.tree.IntoClause;
+import org.hibernate.hql.ast.tree.LiteralNode;
+import org.hibernate.hql.ast.tree.MethodNode;
+import org.hibernate.hql.ast.tree.OrderByClause;
+import org.hibernate.hql.ast.tree.ParameterNode;
+import org.hibernate.hql.ast.tree.QueryNode;
+import org.hibernate.hql.ast.tree.SelectClause;
+import org.hibernate.hql.ast.tree.SelectExpressionImpl;
+import org.hibernate.hql.ast.tree.SqlFragment;
+import org.hibernate.hql.ast.tree.SqlNode;
+import org.hibernate.hql.ast.tree.UnaryArithmeticNode;
+import org.hibernate.hql.ast.tree.UpdateStatement;
+import org.hibernate.hql.ast.tree.BetweenOperatorNode;
+import org.hibernate.hql.ast.tree.UnaryLogicOperatorNode;
+import org.hibernate.hql.ast.tree.InLogicOperatorNode;
+import org.hibernate.hql.ast.tree.JavaConstantNode;
+import org.hibernate.hql.ast.tree.SessionFactoryAwareNode;
+import org.hibernate.hql.ast.tree.BooleanLiteralNode;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * Custom AST factory the intermediate tree that causes ANTLR to create specialized
+ * AST nodes, given the AST node type (from HqlSqlTokenTypes).   HqlSqlWalker registers
+ * this factory with itself when it is initialized.
+ *
+ * @author Joshua
+ */
+public class SqlASTFactory extends ASTFactory implements HqlSqlTokenTypes {
+	private HqlSqlWalker walker;
+
+	/**
+	 * Create factory with a specific mapping from token type
+	 * to Java AST node type.  Your subclasses of ASTFactory
+	 * can override and reuse the map stuff.
+	 */
+	public SqlASTFactory(HqlSqlWalker walker) {
+		super();
+		this.walker = walker;
+	}
+
+	/**
+	 * Returns the class for a given token type (a.k.a. AST node type).
+	 *
+	 * @param tokenType The token type.
+	 * @return Class - The AST node class to instantiate.
+	 */
+	public Class getASTNodeType(int tokenType) {
+		switch ( tokenType ) {
+			case SELECT:
+			case QUERY:
+				return QueryNode.class;
+			case UPDATE:
+				return UpdateStatement.class;
+			case DELETE:
+				return DeleteStatement.class;
+			case INSERT:
+				return InsertStatement.class;
+			case INTO:
+				return IntoClause.class;
+			case FROM:
+				return FromClause.class;
+			case FROM_FRAGMENT:
+				return FromElement.class;
+			case IMPLIED_FROM:
+				return ImpliedFromElement.class;
+			case DOT:
+				return DotNode.class;
+			case INDEX_OP:
+				return IndexNode.class;
+				// Alias references and identifiers use the same node class.
+			case ALIAS_REF:
+			case IDENT:
+				return IdentNode.class;
+			case SQL_TOKEN:
+				return SqlFragment.class;
+			case METHOD_CALL:
+				return MethodNode.class;
+			case ELEMENTS:
+			case INDICES:
+				return CollectionFunction.class;
+			case SELECT_CLAUSE:
+				return SelectClause.class;
+			case SELECT_EXPR:
+				return SelectExpressionImpl.class;
+			case AGGREGATE:
+				return AggregateNode.class;
+			case COUNT:
+				return CountNode.class;
+			case CONSTRUCTOR:
+				return ConstructorNode.class;
+			case NUM_INT:
+			case NUM_FLOAT:
+			case NUM_LONG:
+			case NUM_DOUBLE:
+			case QUOTED_STRING:
+				return LiteralNode.class;
+			case TRUE:
+			case FALSE:
+				return BooleanLiteralNode.class;
+			case JAVA_CONSTANT:
+				return JavaConstantNode.class;
+			case ORDER:
+				return OrderByClause.class;
+			case PLUS:
+			case MINUS:
+			case STAR:
+			case DIV:
+				return BinaryArithmeticOperatorNode.class;
+			case UNARY_MINUS:
+			case UNARY_PLUS:
+				return UnaryArithmeticNode.class;
+			case CASE2:
+				return Case2Node.class;
+			case CASE:
+				return CaseNode.class;
+			case PARAM:
+			case NAMED_PARAM:
+				return ParameterNode.class;
+			case EQ:
+			case NE:
+			case LT:
+			case GT:
+			case LE:
+			case GE:
+			case LIKE:
+			case NOT_LIKE:
+				return BinaryLogicOperatorNode.class;
+			case IN:
+			case NOT_IN:
+				return InLogicOperatorNode.class;
+			case BETWEEN:
+			case NOT_BETWEEN:
+				return BetweenOperatorNode.class;
+			case IS_NULL:
+			case IS_NOT_NULL:
+			case EXISTS:
+				return UnaryLogicOperatorNode.class;
+			default:
+				return SqlNode.class;
+		} // switch
+	}
+
+	protected AST createUsingCtor(Token token, String className) {
+		Class c;
+		AST t;
+		try {
+			c = Class.forName( className );
+			Class[] tokenArgType = new Class[]{antlr.Token.class};
+			Constructor ctor = c.getConstructor( tokenArgType );
+			if ( ctor != null ) {
+				t = ( AST ) ctor.newInstance( new Object[]{token} ); // make a new one
+				initializeSqlNode( t );
+			}
+			else {
+				// just do the regular thing if you can't find the ctor
+				// Your AST must have default ctor to use this.
+				t = create( c );
+			}
+		}
+		catch ( Exception e ) {
+			throw new IllegalArgumentException( "Invalid class or can't make instance, " + className );
+		}
+		return t;
+	}
+
+	private void initializeSqlNode(AST t) {
+		// Initialize SQL nodes here.
+		if ( t instanceof InitializeableNode ) {
+			InitializeableNode initializeableNode = ( InitializeableNode ) t;
+			initializeableNode.initialize( walker );
+		}
+		if ( t instanceof SessionFactoryAwareNode ) {
+			( ( SessionFactoryAwareNode ) t ).setSessionFactory( walker.getSessionFactoryHelper().getFactory() );
+		}
+	}
+
+	/**
+	 * Actually instantiate the AST node.
+	 *
+	 * @param c The class to instantiate.
+	 * @return The instantiated and initialized node.
+	 */
+	protected AST create(Class c) {
+		AST t;
+		try {
+			t = ( AST ) c.newInstance(); // make a new one
+			initializeSqlNode( t );
+		}
+		catch ( Exception e ) {
+			error( "Can't create AST Node " + c.getName() );
+			return null;
+		}
+		return t;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/SqlGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/SqlGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/SqlGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,267 @@
+// $Id: SqlGenerator.java 10060 2006-06-28 02:53:39Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import antlr.RecognitionException;
+import antlr.collections.AST;
+import org.hibernate.QueryException;
+import org.hibernate.dialect.function.SQLFunction;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.hql.antlr.SqlGeneratorBase;
+import org.hibernate.hql.ast.tree.MethodNode;
+import org.hibernate.hql.ast.tree.FromElement;
+import org.hibernate.hql.ast.tree.Node;
+
+/**
+ * Generates SQL by overriding callback methods in the base class, which does
+ * the actual SQL AST walking.
+ *
+ * @author Joshua Davis
+ * @author Steve Ebersole
+ */
+public class SqlGenerator extends SqlGeneratorBase implements ErrorReporter {
+	/**
+	 * Handles parser errors.
+	 */
+	private ParseErrorHandler parseErrorHandler;
+
+	/**
+	 * all append invocations on the buf should go through this Output instance variable.
+	 * The value of this variable may be temporarily substitued by sql function processing code
+	 * to catch generated arguments.
+	 * This is because sql function templates need arguments as seperate string chunks
+	 * that will be assembled into the target dialect-specific function call.
+	 */
+	private SqlWriter writer = new DefaultWriter();
+
+	private SessionFactoryImplementor sessionFactory;
+
+	private LinkedList outputStack = new LinkedList();
+
+	protected void out(String s) {
+		writer.clause( s );
+	}
+
+	protected void out(AST n) {
+		if ( n instanceof Node ) {
+			out( ( ( Node ) n ).getRenderText( sessionFactory ) );
+		}
+		else {
+			super.out( n );
+		}
+	}
+
+	protected void commaBetweenParameters(String comma) {
+		writer.commaBetweenParameters( comma );
+	}
+
+	public void reportError(RecognitionException e) {
+		parseErrorHandler.reportError( e ); // Use the delegate.
+	}
+
+	public void reportError(String s) {
+		parseErrorHandler.reportError( s ); // Use the delegate.
+	}
+
+	public void reportWarning(String s) {
+		parseErrorHandler.reportWarning( s );
+	}
+
+	public ParseErrorHandler getParseErrorHandler() {
+		return parseErrorHandler;
+	}
+
+	public SqlGenerator(SessionFactoryImplementor sfi) {
+		super();
+		parseErrorHandler = new ErrorCounter();
+		sessionFactory = sfi;
+	}
+
+	public String getSQL() {
+		return getStringBuffer().toString();
+	}
+
+	protected void optionalSpace() {
+		int c = getLastChar();
+		switch ( c ) {
+			case -1:
+				return;
+			case ' ':
+				return;
+			case ')':
+				return;
+			case '(':
+				return;
+			default:
+				out( " " );
+		}
+	}
+
+	protected void beginFunctionTemplate(AST m, AST i) {
+		MethodNode methodNode = ( MethodNode ) m;
+		SQLFunction template = methodNode.getSQLFunction();
+		if ( template == null ) {
+			// if template is null we just write the function out as it appears in the hql statement
+			super.beginFunctionTemplate( m, i );
+		}
+		else {
+			// this function has a template -> redirect output and catch the arguments
+			outputStack.addFirst( writer );
+			writer = new FunctionArguments();
+		}
+	}
+
+	protected void endFunctionTemplate(AST m) {
+		MethodNode methodNode = ( MethodNode ) m;
+		SQLFunction template = methodNode.getSQLFunction();
+		if ( template == null ) {
+			super.endFunctionTemplate( m );
+		}
+		else {
+			// this function has a template -> restore output, apply the template and write the result out
+			FunctionArguments functionArguments = ( FunctionArguments ) writer;   // TODO: Downcast to avoid using an interface?  Yuck.
+			writer = ( SqlWriter ) outputStack.removeFirst();
+			out( template.render( functionArguments.getArgs(), sessionFactory ) );
+		}
+	}
+
+	// --- Inner classes (moved here from sql-gen.g) ---
+
+	/**
+	 * Writes SQL fragments.
+	 */
+	interface SqlWriter {
+		void clause(String clause);
+
+		/**
+		 * todo remove this hack
+		 * The parameter is either ", " or " , ". This is needed to pass sql generating tests as the old
+		 * sql generator uses " , " in the WHERE and ", " in SELECT.
+		 *
+		 * @param comma either " , " or ", "
+		 */
+		void commaBetweenParameters(String comma);
+	}
+
+	/**
+	 * SQL function processing code redirects generated SQL output to an instance of this class
+	 * which catches function arguments.
+	 */
+	class FunctionArguments implements SqlWriter {
+		private int argInd;
+		private final List args = new ArrayList( 3 );
+
+		public void clause(String clause) {
+			if ( argInd == args.size() ) {
+				args.add( clause );
+			}
+			else {
+				args.set( argInd, args.get( argInd ) + clause );
+			}
+		}
+
+		public void commaBetweenParameters(String comma) {
+			++argInd;
+		}
+
+		public List getArgs() {
+			return args;
+		}
+	}
+
+	/**
+	 * The default SQL writer.
+	 */
+	class DefaultWriter implements SqlWriter {
+		public void clause(String clause) {
+			getStringBuffer().append( clause );
+		}
+
+		public void commaBetweenParameters(String comma) {
+			getStringBuffer().append( comma );
+		}
+	}
+
+    public static void panic() {
+		throw new QueryException( "TreeWalker: panic" );
+	}
+
+	protected void fromFragmentSeparator(AST a) {
+		// check two "adjecent" nodes at the top of the from-clause tree
+		AST next = a.getNextSibling();
+		if ( next == null || !hasText( a ) ) {
+			return;
+		}
+
+		FromElement left = ( FromElement ) a;
+		FromElement right = ( FromElement ) next;
+
+		///////////////////////////////////////////////////////////////////////
+		// HACK ALERT !!!!!!!!!!!!!!!!!!!!!!!!!!!!
+		// Attempt to work around "ghost" ImpliedFromElements that occasionally
+		// show up between the actual things being joined.  This consistently
+		// occurs from index nodes (at least against many-to-many).  Not sure
+		// if there are other conditions
+		//
+		// Essentially, look-ahead to the next FromElement that actually
+		// writes something to the SQL
+		while ( right != null && !hasText( right ) ) {
+			right = ( FromElement ) right.getNextSibling();
+		}
+		if ( right == null ) {
+			return;
+		}
+		///////////////////////////////////////////////////////////////////////
+
+		if ( !hasText( right ) ) {
+			return;
+		}
+
+		if ( right.getRealOrigin() == left ||
+		     ( right.getRealOrigin() != null && right.getRealOrigin() == left.getRealOrigin() ) ) {
+			// right represents a joins originating from left; or
+			// both right and left reprersent joins originating from the same FromElement
+			if ( right.getJoinSequence() != null && right.getJoinSequence().isThetaStyle() ) {
+				out( ", " );
+			}
+			else {
+				out( " " );
+			}
+		}
+		else {
+			// these are just two unrelated table references
+			out( ", " );
+		}
+	}
+
+	protected void nestedFromFragment(AST d, AST parent) {
+		// check a set of parent/child nodes in the from-clause tree
+		// to determine if a comma is required between them
+		if ( d != null && hasText( d ) ) {
+			if ( parent != null && hasText( parent ) ) {
+				// again, both should be FromElements
+				FromElement left = ( FromElement ) parent;
+				FromElement right = ( FromElement ) d;
+				if ( right.getRealOrigin() == left ) {
+					// right represents a joins originating from left...
+					if ( right.getJoinSequence() != null && right.getJoinSequence().isThetaStyle() ) {
+						out( ", " );
+					}
+					else {
+						out( " " );
+					}
+				}
+				else {
+					// not so sure this is even valid subtree.  but if it was, it'd
+					// represent two unrelated table references...
+					out( ", " );
+				}
+			}
+			out( d );
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/AbstractStatementExecutor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/AbstractStatementExecutor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/AbstractStatementExecutor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,227 @@
+// $Id: AbstractStatementExecutor.java 11288 2007-03-15 11:38:45Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.exec;
+
+import java.sql.PreparedStatement;
+import java.sql.Connection;
+import java.sql.Statement;
+
+import org.hibernate.HibernateException;
+import org.hibernate.action.BulkOperationCleanupAction;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.transaction.Isolater;
+import org.hibernate.engine.transaction.IsolatedWork;
+import org.hibernate.event.EventSource;
+import org.hibernate.hql.ast.HqlSqlWalker;
+import org.hibernate.hql.ast.SqlGenerator;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.sql.InsertSelect;
+import org.hibernate.sql.Select;
+import org.hibernate.sql.SelectFragment;
+import org.hibernate.util.StringHelper;
+
+import antlr.RecognitionException;
+import antlr.collections.AST;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * Implementation of AbstractStatementExecutor.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractStatementExecutor implements StatementExecutor {
+
+	private final Log log;
+	private final HqlSqlWalker walker;
+
+	public AbstractStatementExecutor(HqlSqlWalker walker, Log log) {
+		this.walker = walker;
+		this.log = log;
+	}
+
+	protected HqlSqlWalker getWalker() {
+		return walker;
+	}
+
+	protected SessionFactoryImplementor getFactory() {
+		return walker.getSessionFactoryHelper().getFactory();
+	}
+
+	protected abstract Queryable[] getAffectedQueryables();
+
+	protected String generateIdInsertSelect(Queryable persister, String tableAlias, AST whereClause) {
+		Select select = new Select( getFactory().getDialect() );
+		SelectFragment selectFragment = new SelectFragment()
+				.addColumns( tableAlias, persister.getIdentifierColumnNames(), persister.getIdentifierColumnNames() );
+		select.setSelectClause( selectFragment.toFragmentString().substring( 2 ) );
+
+		String rootTableName = persister.getTableName();
+		String fromJoinFragment = persister.fromJoinFragment( tableAlias, true, false );
+		String whereJoinFragment = persister.whereJoinFragment( tableAlias, true, false );
+
+		select.setFromClause( rootTableName + ' ' + tableAlias + fromJoinFragment );
+
+		if ( whereJoinFragment == null ) {
+			whereJoinFragment = "";
+		}
+		else {
+			whereJoinFragment = whereJoinFragment.trim();
+			if ( whereJoinFragment.startsWith( "and" ) ) {
+				whereJoinFragment = whereJoinFragment.substring( 4 );
+			}
+		}
+
+		String userWhereClause = "";
+		if ( whereClause.getNumberOfChildren() != 0 ) {
+			// If a where clause was specified in the update/delete query, use it to limit the
+			// returned ids here...
+			try {
+				SqlGenerator sqlGenerator = new SqlGenerator( getFactory() );
+				sqlGenerator.whereClause( whereClause );
+				userWhereClause = sqlGenerator.getSQL().substring( 7 );  // strip the " where "
+			}
+			catch ( RecognitionException e ) {
+				throw new HibernateException( "Unable to generate id select for DML operation", e );
+			}
+			if ( whereJoinFragment.length() > 0 ) {
+				whereJoinFragment += " and ";
+			}
+		}
+
+		select.setWhereClause( whereJoinFragment + userWhereClause );
+
+		InsertSelect insert = new InsertSelect( getFactory().getDialect() );
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			insert.setComment( "insert-select for " + persister.getEntityName() + " ids" );
+		}
+		insert.setTableName( persister.getTemporaryIdTableName() );
+		insert.setSelect( select );
+		return insert.toStatementString();
+	}
+
+	protected String generateIdSubselect(Queryable persister) {
+		return "select " + StringHelper.join( ", ", persister.getIdentifierColumnNames() ) +
+			        " from " + persister.getTemporaryIdTableName();
+	}
+
+	protected void createTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
+		// Don't really know all the codes required to adequately decipher returned jdbc exceptions here.
+		// simply allow the failure to be eaten and the subsequent insert-selects/deletes should fail
+		IsolatedWork work = new IsolatedWork() {
+			public void doWork(Connection connection) throws HibernateException {
+				Statement stmnt = null;
+				try {
+					stmnt = connection.createStatement();
+					stmnt.executeUpdate( persister.getTemporaryIdTableDDL() );
+				}
+				catch( Throwable t ) {
+					log.debug( "unable to create temporary id table [" + t.getMessage() + "]" );
+				}
+				finally {
+					if ( stmnt != null ) {
+						try {
+							stmnt.close();
+						}
+						catch( Throwable ignore ) {
+							// ignore
+						}
+					}
+				}
+			}
+		};
+		if ( shouldIsolateTemporaryTableDDL() ) {
+			if ( getFactory().getSettings().isDataDefinitionInTransactionSupported() ) {
+				Isolater.doIsolatedWork( work, session );
+			}
+			else {
+				Isolater.doNonTransactedWork( work, session );
+			}
+		}
+		else {
+			work.doWork( session.getJDBCContext().getConnectionManager().getConnection() );
+			session.getJDBCContext().getConnectionManager().afterStatement();
+		}
+	}
+
+	protected void dropTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
+		if ( getFactory().getDialect().dropTemporaryTableAfterUse() ) {
+			IsolatedWork work = new IsolatedWork() {
+				public void doWork(Connection connection) throws HibernateException {
+					Statement stmnt = null;
+					try {
+						stmnt = connection.createStatement();
+						stmnt.executeUpdate( "drop table " + persister.getTemporaryIdTableName() );
+					}
+					catch( Throwable t ) {
+						log.warn( "unable to drop temporary id table after use [" + t.getMessage() + "]" );
+					}
+					finally {
+						if ( stmnt != null ) {
+							try {
+								stmnt.close();
+							}
+							catch( Throwable ignore ) {
+								// ignore
+							}
+						}
+					}
+				}
+			};
+
+			if ( shouldIsolateTemporaryTableDDL() ) {
+				if ( getFactory().getSettings().isDataDefinitionInTransactionSupported() ) {
+					Isolater.doIsolatedWork( work, session );
+				}
+				else {
+					Isolater.doNonTransactedWork( work, session );
+				}
+			}
+			else {
+				work.doWork( session.getJDBCContext().getConnectionManager().getConnection() );
+				session.getJDBCContext().getConnectionManager().afterStatement();
+			}
+		}
+		else {
+			// at the very least cleanup the data :)
+			PreparedStatement ps = null;
+			try {
+				ps = session.getBatcher().prepareStatement( "delete from " + persister.getTemporaryIdTableName() );
+				ps.executeUpdate();
+			}
+			catch( Throwable t ) {
+				log.warn( "unable to cleanup temporary id table after use [" + t + "]" );
+			}
+			finally {
+				if ( ps != null ) {
+					try {
+						session.getBatcher().closeStatement( ps );
+					}
+					catch( Throwable ignore ) {
+						// ignore
+					}
+				}
+			}
+		}
+	}
+
+	protected void coordinateSharedCacheCleanup(SessionImplementor session) {
+		BulkOperationCleanupAction action = new BulkOperationCleanupAction( session, getAffectedQueryables() );
+
+		action.init();
+
+		if ( session.isEventSource() ) {
+			( ( EventSource ) session ).getActionQueue().addAction( action );
+		}
+	}
+
+	protected boolean shouldIsolateTemporaryTableDDL() {
+		Boolean dialectVote = getFactory().getDialect().performTemporaryTableDDLInIsolation();
+		if ( dialectVote != null ) {
+			return dialectVote.booleanValue();
+		}
+		else {
+			return getFactory().getSettings().isDataDefinitionImplicitCommit();
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/BasicExecutor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/BasicExecutor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/BasicExecutor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,96 @@
+// $Id: BasicExecutor.java 9242 2006-02-09 12:37:36Z steveebersole $
+package org.hibernate.hql.ast.exec;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Iterator;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.RowSelection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.hql.ast.HqlSqlWalker;
+import org.hibernate.hql.ast.QuerySyntaxException;
+import org.hibernate.hql.ast.SqlGenerator;
+import org.hibernate.param.ParameterSpecification;
+import org.hibernate.persister.entity.Queryable;
+
+import antlr.RecognitionException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Implementation of BasicExecutor.
+ *
+ * @author Steve Ebersole
+ */
+public class BasicExecutor extends AbstractStatementExecutor {
+	private static final Log log = LogFactory.getLog( BasicExecutor.class );
+
+	private final Queryable persister;
+	private final String sql;
+
+	public BasicExecutor(HqlSqlWalker walker, Queryable persister) {
+		super( walker, log );
+		this.persister = persister;
+		try {
+			SqlGenerator gen = new SqlGenerator( getFactory() );
+			gen.statement( walker.getAST() );
+			sql = gen.getSQL();
+			gen.getParseErrorHandler().throwQueryException();
+		}
+		catch ( RecognitionException e ) {
+			throw QuerySyntaxException.convert( e );
+		}
+	}
+
+	public String[] getSqlStatements() {
+		return new String[] { sql };
+	}
+
+	public int execute(QueryParameters parameters, SessionImplementor session) throws HibernateException {
+
+		coordinateSharedCacheCleanup( session );
+
+		PreparedStatement st = null;
+		RowSelection selection = parameters.getRowSelection();
+
+		try {
+			try {
+				st = session.getBatcher().prepareStatement( sql );
+				Iterator paramSpecifications = getWalker().getParameters().iterator();
+				int pos = 1;
+				while ( paramSpecifications.hasNext() ) {
+					final ParameterSpecification paramSpec = ( ParameterSpecification ) paramSpecifications.next();
+					pos += paramSpec.bind( st, parameters, session, pos );
+				}
+				if ( selection != null ) {
+					if ( selection.getTimeout() != null ) {
+						st.setQueryTimeout( selection.getTimeout().intValue() );
+					}
+				}
+
+				return st.executeUpdate();
+			}
+			finally {
+				if ( st != null ) {
+					session.getBatcher().closeStatement( st );
+				}
+			}
+		}
+		catch( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					getFactory().getSQLExceptionConverter(),
+			        sqle,
+			        "could not execute update query",
+			        sql
+				);
+		}
+	}
+
+	protected Queryable[] getAffectedQueryables() {
+		return new Queryable[] { persister };
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/MultiTableDeleteExecutor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/MultiTableDeleteExecutor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/MultiTableDeleteExecutor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,143 @@
+// $Id: MultiTableDeleteExecutor.java 11288 2007-03-15 11:38:45Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.exec;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Iterator;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.hql.ast.HqlSqlWalker;
+import org.hibernate.hql.ast.tree.DeleteStatement;
+import org.hibernate.hql.ast.tree.FromElement;
+import org.hibernate.param.ParameterSpecification;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.sql.Delete;
+import org.hibernate.util.StringHelper;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Implementation of MultiTableDeleteExecutor.
+ *
+ * @author Steve Ebersole
+ */
+public class MultiTableDeleteExecutor extends AbstractStatementExecutor {
+	private static final Log log = LogFactory.getLog( MultiTableDeleteExecutor.class );
+
+	private final Queryable persister;
+	private final String idInsertSelect;
+	private final String[] deletes;
+
+	public MultiTableDeleteExecutor(HqlSqlWalker walker) {
+		super( walker, log );
+
+		if ( !walker.getSessionFactoryHelper().getFactory().getDialect().supportsTemporaryTables() ) {
+			throw new HibernateException( "cannot perform multi-table deletes using dialect not supporting temp tables" );
+		}
+
+		DeleteStatement deleteStatement = ( DeleteStatement ) walker.getAST();
+		FromElement fromElement = deleteStatement.getFromClause().getFromElement();
+		String bulkTargetAlias = fromElement.getTableAlias();
+		this.persister = fromElement.getQueryable();
+
+		this.idInsertSelect = generateIdInsertSelect( persister, bulkTargetAlias, deleteStatement.getWhereClause() );
+		log.trace( "Generated ID-INSERT-SELECT SQL (multi-table delete) : " +  idInsertSelect );
+
+		String[] tableNames = persister.getConstraintOrderedTableNameClosure();
+		String[][] columnNames = persister.getContraintOrderedTableKeyColumnClosure();
+		String idSubselect = generateIdSubselect( persister );
+
+		deletes = new String[tableNames.length];
+		for ( int i = tableNames.length - 1; i >= 0; i-- ) {
+			// TODO : an optimization here would be to consider cascade deletes and not gen those delete statements;
+			//      the difficulty is the ordering of the tables here vs the cascade attributes on the persisters ->
+			//          the table info gotten here should really be self-contained (i.e., a class representation
+			//          defining all the needed attributes), then we could then get an array of those
+			final Delete delete = new Delete()
+					.setTableName( tableNames[i] )
+					.setWhere( "(" + StringHelper.join( ", ", columnNames[i] ) + ") IN (" + idSubselect + ")" );
+			if ( getFactory().getSettings().isCommentsEnabled() ) {
+				delete.setComment( "bulk delete" );
+			}
+
+			deletes[i] = delete.toStatementString();
+		}
+	}
+
+	public String[] getSqlStatements() {
+		return deletes;
+	}
+
+	public int execute(QueryParameters parameters, SessionImplementor session) throws HibernateException {
+		coordinateSharedCacheCleanup( session );
+
+		createTemporaryTableIfNecessary( persister, session );
+
+		try {
+			// First, save off the pertinent ids, saving the number of pertinent ids for return
+			PreparedStatement ps = null;
+			int resultCount = 0;
+			try {
+				try {
+					ps = session.getBatcher().prepareStatement( idInsertSelect );
+					Iterator paramSpecifications = getWalker().getParameters().iterator();
+					int pos = 1;
+					while ( paramSpecifications.hasNext() ) {
+						final ParameterSpecification paramSpec = ( ParameterSpecification ) paramSpecifications.next();
+						pos += paramSpec.bind( ps, parameters, session, pos );
+					}
+					resultCount = ps.executeUpdate();
+				}
+				finally {
+					if ( ps != null ) {
+						session.getBatcher().closeStatement( ps );
+					}
+				}
+			}
+			catch( SQLException e ) {
+				throw JDBCExceptionHelper.convert(
+						getFactory().getSQLExceptionConverter(),
+				        e,
+				        "could not insert/select ids for bulk delete",
+				        idInsertSelect
+					);
+			}
+
+			// Start performing the deletes
+			for ( int i = 0; i < deletes.length; i++ ) {
+				try {
+					try {
+						ps = session.getBatcher().prepareStatement( deletes[i] );
+						ps.executeUpdate();
+					}
+					finally {
+						if ( ps != null ) {
+							session.getBatcher().closeStatement( ps );
+						}
+					}
+				}
+				catch( SQLException e ) {
+					throw JDBCExceptionHelper.convert(
+							getFactory().getSQLExceptionConverter(),
+					        e,
+					        "error performing bulk delete",
+					        deletes[i]
+						);
+				}
+			}
+
+			return resultCount;
+		}
+		finally {
+			dropTemporaryTableIfNecessary( persister, session );
+		}
+	}
+
+	protected Queryable[] getAffectedQueryables() {
+		return new Queryable[] { persister };
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/MultiTableUpdateExecutor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/MultiTableUpdateExecutor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/MultiTableUpdateExecutor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,177 @@
+// $Id: MultiTableUpdateExecutor.java 11288 2007-03-15 11:38:45Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.exec;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.hql.ast.HqlSqlWalker;
+import org.hibernate.hql.ast.tree.AssignmentSpecification;
+import org.hibernate.hql.ast.tree.FromElement;
+import org.hibernate.hql.ast.tree.UpdateStatement;
+import org.hibernate.param.ParameterSpecification;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.sql.Update;
+import org.hibernate.util.StringHelper;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Implementation of MultiTableUpdateExecutor.
+ *
+ * @author Steve Ebersole
+ */
+public class MultiTableUpdateExecutor extends AbstractStatementExecutor {
+	private static final Log log = LogFactory.getLog( MultiTableUpdateExecutor.class );
+
+	private final Queryable persister;
+	private final String idInsertSelect;
+	private final String[] updates;
+	private final ParameterSpecification[][] hqlParameters;
+
+	public MultiTableUpdateExecutor(HqlSqlWalker walker) {
+		super( walker, log );
+
+		if ( !walker.getSessionFactoryHelper().getFactory().getDialect().supportsTemporaryTables() ) {
+			throw new HibernateException( "cannot perform multi-table updates using dialect not supporting temp tables" );
+		}
+
+		UpdateStatement updateStatement = ( UpdateStatement ) walker.getAST();
+		FromElement fromElement = updateStatement.getFromClause().getFromElement();
+		String bulkTargetAlias = fromElement.getTableAlias();
+		this.persister = fromElement.getQueryable();
+
+		this.idInsertSelect = generateIdInsertSelect( persister, bulkTargetAlias, updateStatement.getWhereClause() );
+		log.trace( "Generated ID-INSERT-SELECT SQL (multi-table update) : " +  idInsertSelect );
+
+		String[] tableNames = persister.getConstraintOrderedTableNameClosure();
+		String[][] columnNames = persister.getContraintOrderedTableKeyColumnClosure();
+
+		String idSubselect = generateIdSubselect( persister );
+		List assignmentSpecifications = walker.getAssignmentSpecifications();
+
+		updates = new String[tableNames.length];
+		hqlParameters = new ParameterSpecification[tableNames.length][];
+		for ( int tableIndex = 0; tableIndex < tableNames.length; tableIndex++ ) {
+			boolean affected = false;
+			List parameterList = new ArrayList();
+			Update update = new Update( getFactory().getDialect() )
+					.setTableName( tableNames[tableIndex] )
+					.setWhere( "(" + StringHelper.join( ", ", columnNames[tableIndex] ) + ") IN (" + idSubselect + ")" );
+			if ( getFactory().getSettings().isCommentsEnabled() ) {
+				update.setComment( "bulk update" );
+			}
+			final Iterator itr = assignmentSpecifications.iterator();
+			while ( itr.hasNext() ) {
+				final AssignmentSpecification specification = ( AssignmentSpecification ) itr.next();
+				if ( specification.affectsTable( tableNames[tableIndex] ) ) {
+					affected = true;
+					update.appendAssignmentFragment( specification.getSqlAssignmentFragment() );
+					if ( specification.getParameters() != null ) {
+						for ( int paramIndex = 0; paramIndex < specification.getParameters().length; paramIndex++ ) {
+							parameterList.add( specification.getParameters()[paramIndex] );
+						}
+					}
+				}
+			}
+			if ( affected ) {
+				updates[tableIndex] = update.toStatementString();
+				hqlParameters[tableIndex] = ( ParameterSpecification[] ) parameterList.toArray( new ParameterSpecification[0] );
+			}
+		}
+	}
+
+	public Queryable getAffectedQueryable() {
+		return persister;
+	}
+
+	public String[] getSqlStatements() {
+		return updates;
+	}
+
+	public int execute(QueryParameters parameters, SessionImplementor session) throws HibernateException {
+		coordinateSharedCacheCleanup( session );
+
+		createTemporaryTableIfNecessary( persister, session );
+
+		try {
+			// First, save off the pertinent ids, as the return value
+			PreparedStatement ps = null;
+			int resultCount = 0;
+			try {
+				try {
+					ps = session.getBatcher().prepareStatement( idInsertSelect );
+					int parameterStart = getWalker().getNumberOfParametersInSetClause();
+					List allParams = getWalker().getParameters();
+					Iterator whereParams = allParams.subList( parameterStart, allParams.size() ).iterator();
+					int sum = 1; // jdbc params are 1-based
+					while ( whereParams.hasNext() ) {
+						sum += ( ( ParameterSpecification ) whereParams.next() ).bind( ps, parameters, session, sum );
+					}
+					resultCount = ps.executeUpdate();
+				}
+				finally {
+					if ( ps != null ) {
+						session.getBatcher().closeStatement( ps );
+					}
+				}
+			}
+			catch( SQLException e ) {
+				throw JDBCExceptionHelper.convert(
+						getFactory().getSQLExceptionConverter(),
+				        e,
+				        "could not insert/select ids for bulk update",
+				        idInsertSelect
+					);
+			}
+
+			// Start performing the updates
+			for ( int i = 0; i < updates.length; i++ ) {
+				if ( updates[i] == null ) {
+					continue;
+				}
+				try {
+					try {
+						ps = session.getBatcher().prepareStatement( updates[i] );
+						if ( hqlParameters[i] != null ) {
+							int position = 1; // jdbc params are 1-based
+							for ( int x = 0; x < hqlParameters[i].length; x++ ) {
+								position += hqlParameters[i][x].bind( ps, parameters, session, position );
+							}
+						}
+						ps.executeUpdate();
+					}
+					finally {
+						if ( ps != null ) {
+							session.getBatcher().closeStatement( ps );
+						}
+					}
+				}
+				catch( SQLException e ) {
+					throw JDBCExceptionHelper.convert(
+							getFactory().getSQLExceptionConverter(),
+					        e,
+					        "error performing bulk update",
+					        updates[i]
+						);
+				}
+			}
+
+			return resultCount;
+		}
+		finally {
+			dropTemporaryTableIfNecessary( persister, session );
+		}
+	}
+
+	protected Queryable[] getAffectedQueryables() {
+		return new Queryable[] { persister };
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/StatementExecutor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/StatementExecutor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/exec/StatementExecutor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+// $Id: StatementExecutor.java 8631 2005-11-21 17:02:24Z steveebersole $
+package org.hibernate.hql.ast.exec;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * Encapsulates the strategy required to execute various types of update, delete,
+ * and insert statements issued through HQL.
+ *
+ * @author Steve Ebersole
+ */
+public interface StatementExecutor {
+
+	public String[] getSqlStatements();
+
+	/**
+	 * Execute the sql managed by this executor using the given parameters.
+	 *
+	 * @param parameters Essentially bind information for this processing.
+	 * @param session The session originating the request.
+	 * @return The number of entities updated/deleted.
+	 * @throws HibernateException
+	 */
+	public int execute(QueryParameters parameters, SessionImplementor session) throws HibernateException;
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,6 @@
+<html><head></head><body>
+<p>An ANTLR-based parser for Hibernate Query Language.</p>
+<p>
+	Classes in this package extend the ANTLR-generated parser classes.
+</p>
+</body></html>
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AbstractRestrictableStatement.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AbstractRestrictableStatement.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AbstractRestrictableStatement.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+// $Id: AbstractRestrictableStatement.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.hql.ast.util.ASTUtil;
+
+import antlr.collections.AST;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * Convenience implementation of RestrictableStatement to centralize common functionality.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractRestrictableStatement extends AbstractStatement implements RestrictableStatement {
+
+	private FromClause fromClause;
+	private AST whereClause;
+
+	protected abstract int getWhereClauseParentTokenType();
+	protected abstract Log getLog();
+
+	/**
+	 * @see org.hibernate.hql.ast.tree.RestrictableStatement#getFromClause
+	 */
+	public final FromClause getFromClause() {
+		if ( fromClause == null ) {
+			fromClause = ( FromClause ) ASTUtil.findTypeInChildren( this, HqlSqlTokenTypes.FROM );
+		}
+		return fromClause;
+	}
+
+	/**
+	 * @see RestrictableStatement#hasWhereClause
+	 */
+	public final boolean hasWhereClause() {
+		AST whereClause = locateWhereClause();
+		return whereClause != null && whereClause.getNumberOfChildren() > 0;
+	}
+
+	/**
+	 * @see org.hibernate.hql.ast.tree.RestrictableStatement#getWhereClause
+	 */
+	public final AST getWhereClause() {
+		if ( whereClause == null ) {
+			whereClause = locateWhereClause();
+			// If there is no WHERE node, make one.
+			if ( whereClause == null ) {
+				getLog().debug( "getWhereClause() : Creating a new WHERE clause..." );
+				whereClause = ASTUtil.create( getWalker().getASTFactory(), HqlSqlTokenTypes.WHERE, "WHERE" );
+				// inject the WHERE after the parent
+				AST parent = ASTUtil.findTypeInChildren( this, getWhereClauseParentTokenType() );
+				whereClause.setNextSibling( parent.getNextSibling() );
+				parent.setNextSibling( whereClause );
+			}
+		}
+		return whereClause;
+	}
+
+	protected AST locateWhereClause() {
+		return ASTUtil.findTypeInChildren( this, HqlSqlTokenTypes.WHERE );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AbstractSelectExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AbstractSelectExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AbstractSelectExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+// $Id: AbstractSelectExpression.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.type.Type;
+
+import antlr.SemanticException;
+
+/**
+ * Partial implementation of SelectExpression for all the nodes that aren't constructors.
+ *
+ * @author josh Nov 11, 2004 7:09:11 AM
+ */
+public abstract class AbstractSelectExpression extends HqlSqlWalkerNode implements SelectExpression {
+	
+	private String alias;
+	
+	public final void setAlias(String alias) {
+		this.alias = alias;
+	}
+	
+	public final String getAlias() {
+		return alias;
+	}
+
+	public boolean isConstructor() {
+		return false;
+	}
+
+	public boolean isReturnableEntity() throws SemanticException {
+		return false;
+	}
+
+	public FromElement getFromElement() {
+		return null;
+	}
+
+	public boolean isScalar() throws SemanticException {
+		// Default implementation:
+		// If this node has a data type, and that data type is not an association, then this is scalar.
+		Type type = getDataType();
+		return type != null && !type.isAssociationType();	// Moved here from SelectClause [jsd]
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AbstractStatement.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AbstractStatement.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AbstractStatement.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+// $Id: AbstractStatement.java 7486 2005-07-15 04:39:41Z oneovthafew $
+package org.hibernate.hql.ast.tree;
+
+import java.util.Iterator;
+
+/**
+ * Convenience implementation of Statement to centralize common functionality.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractStatement extends HqlSqlWalkerNode implements DisplayableNode, Statement {
+
+	/**
+	 * Returns additional display text for the AST node.
+	 *
+	 * @return String - The additional display text.
+	 */
+	public String getDisplayText() {
+		StringBuffer buf = new StringBuffer();
+		if ( getWalker().getQuerySpaces().size() > 0 ) {
+			buf.append( " querySpaces (" );
+			for ( Iterator iterator = getWalker().getQuerySpaces().iterator(); iterator.hasNext(); ) {
+				buf.append( iterator.next() );
+				if ( iterator.hasNext() ) {
+					buf.append( "," );
+				}
+			}
+			buf.append( ")" );
+		}
+		return buf.toString();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AggregateNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AggregateNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AggregateNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+// $Id: AggregateNode.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.ast.util.ColumnHelper;
+import org.hibernate.type.Type;
+
+import antlr.SemanticException;
+
+/**
+ * Represents an aggregate function i.e. min, max, sum, avg.
+ *
+ * @author josh Sep 21, 2004 9:22:02 PM
+ */
+public class AggregateNode extends AbstractSelectExpression implements SelectExpression {
+
+	public AggregateNode() {
+	}
+
+	public Type getDataType() {
+		// Get the function return value type, based on the type of the first argument.
+		return getSessionFactoryHelper().findFunctionReturnType( getText(), getFirstChild() );
+	}
+
+	public void setScalarColumnText(int i) throws SemanticException {
+		ColumnHelper.generateSingleScalarColumn( this, i );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AssignmentSpecification.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AssignmentSpecification.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/AssignmentSpecification.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,143 @@
+// $Id: AssignmentSpecification.java 8273 2005-09-30 17:54:42Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+
+import org.hibernate.QueryException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.hql.ast.SqlGenerator;
+import org.hibernate.hql.ast.util.ASTUtil;
+import org.hibernate.param.ParameterSpecification;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.persister.entity.UnionSubclassEntityPersister;
+
+import antlr.collections.AST;
+
+/**
+ * Encapsulates the information relating to an individual assignment within the
+ * set clause of an HQL update statement.  This information is used during execution
+ * of the update statements when the updates occur against "multi-table" stuff.
+ *
+ * @author Steve Ebersole
+ */
+public class AssignmentSpecification {
+
+	private final Set tableNames;
+	private final ParameterSpecification[] hqlParameters;
+	private final AST eq;
+	private final SessionFactoryImplementor factory;
+
+	private String sqlAssignmentString;
+
+	public AssignmentSpecification(AST eq, Queryable persister) {
+		if ( eq.getType() != HqlSqlTokenTypes.EQ ) {
+			throw new QueryException( "assignment in set-clause not associated with equals" );
+		}
+
+		this.eq = eq;
+		this.factory = persister.getFactory();
+
+		// Needed to bump this up to DotNode, because that is the only thing which currently
+		// knows about the property-ref path in the correct format; it is either this, or
+		// recurse over the DotNodes constructing the property path just like DotNode does
+		// internally
+		DotNode lhs = ( DotNode ) eq.getFirstChild();
+		SqlNode rhs = ( SqlNode ) lhs.getNextSibling();
+
+		validateLhs( lhs );
+
+		final String propertyPath = lhs.getPropertyPath();
+		Set temp = new HashSet();
+		// yuck!
+		if ( persister instanceof UnionSubclassEntityPersister ) {
+			UnionSubclassEntityPersister usep = ( UnionSubclassEntityPersister ) persister;
+			String[] tables = persister.getConstraintOrderedTableNameClosure();
+			int size = tables.length;
+			for ( int i = 0; i < size; i ++ ) {
+				temp.add( tables[i] );
+			}
+		}
+		else {
+			temp.add(
+					persister.getSubclassTableName( persister.getSubclassPropertyTableNumber( propertyPath ) )
+			);
+		}
+		this.tableNames = Collections.unmodifiableSet( temp );
+
+		if (rhs==null) {
+			hqlParameters = new ParameterSpecification[0];
+		}
+		else if ( isParam( rhs ) ) {
+			hqlParameters = new ParameterSpecification[] { ( ( ParameterNode ) rhs ).getHqlParameterSpecification() };
+		}
+		else {
+			List parameterList = ASTUtil.collectChildren(
+			        rhs,
+			        new ASTUtil.IncludePredicate() {
+				        public boolean include(AST node) {
+					        return isParam( node );
+			            }
+			        }
+			);
+			hqlParameters = new ParameterSpecification[ parameterList.size() ];
+			Iterator itr = parameterList.iterator();
+			int i = 0;
+			while( itr.hasNext() ) {
+				hqlParameters[i++] = ( ( ParameterNode ) itr.next() ).getHqlParameterSpecification();
+			}
+		}
+	}
+
+	public boolean affectsTable(String tableName) {
+		return this.tableNames.contains( tableName );
+	}
+
+	public ParameterSpecification[] getParameters() {
+		return hqlParameters;
+	}
+
+	public String getSqlAssignmentFragment() {
+		if ( sqlAssignmentString == null ) {
+			try {
+				SqlGenerator sqlGenerator = new SqlGenerator( factory );
+				sqlGenerator.comparisonExpr( eq, false );  // false indicates to not generate parens around the assignment
+				sqlAssignmentString = sqlGenerator.getSQL();
+			}
+			catch( Throwable t ) {
+				throw new QueryException( "cannot interpret set-clause assignment" );
+			}
+		}
+		return sqlAssignmentString;
+	}
+
+	private static boolean isParam(AST node) {
+		return node.getType() == HqlSqlTokenTypes.PARAM || node.getType() == HqlSqlTokenTypes.NAMED_PARAM;
+	}
+
+	private void validateLhs(FromReferenceNode lhs) {
+		// make sure the lhs is "assignable"...
+		if ( !lhs.isResolved() ) {
+			throw new UnsupportedOperationException( "cannot validate assignablity of unresolved node" );
+		}
+
+		if ( lhs.getDataType().isCollectionType() ) {
+			throw new QueryException( "collections not assignable in update statements" );
+		}
+		else if ( lhs.getDataType().isComponentType() ) {
+			throw new QueryException( "Components currently not assignable in update statements" );
+		}
+		else if ( lhs.getDataType().isEntityType() ) {
+			// currently allowed...
+		}
+
+		// TODO : why aren't these the same?
+		if ( lhs.getImpliedJoin() != null || lhs.getFromElement().isImplied() ) {
+			throw new QueryException( "Implied join paths are not assignable in update statements" );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BetweenOperatorNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BetweenOperatorNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BetweenOperatorNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,61 @@
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.type.Type;
+import org.hibernate.Hibernate;
+import antlr.SemanticException;
+
+/**
+ * Contract for nodes representing logcial BETWEEN (ternary) operators.
+ *
+ * @author Steve Ebersole
+ */
+public class BetweenOperatorNode extends SqlNode implements OperatorNode {
+
+	public void initialize() throws SemanticException {
+		Node fixture = getFixtureOperand();
+		if ( fixture == null ) {
+			throw new SemanticException( "fixture operand of a between operator was null" );
+		}
+		Node low = getLowOperand();
+		if ( low == null ) {
+			throw new SemanticException( "low operand of a between operator was null" );
+		}
+		Node high = getHighOperand();
+		if ( high == null ) {
+			throw new SemanticException( "high operand of a between operator was null" );
+		}
+		check( fixture, low, high );
+		check( low, high, fixture );
+		check( high, fixture, low );
+	}
+
+	public Type getDataType() {
+		// logic operators by definition resolve to boolean.
+		return Hibernate.BOOLEAN;
+	}
+
+	public Node getFixtureOperand() {
+		return ( Node ) getFirstChild();
+	}
+
+	public Node getLowOperand() {
+		return ( Node ) getFirstChild().getNextSibling();
+	}
+
+	public Node getHighOperand() {
+		return ( Node ) getFirstChild().getNextSibling().getNextSibling();
+	}
+
+	private void check(Node check, Node first, Node second) {
+		if ( ExpectedTypeAwareNode.class.isAssignableFrom( check.getClass() ) ) {
+			Type expectedType = null;
+			if ( SqlNode.class.isAssignableFrom( first.getClass() ) ) {
+				expectedType = ( ( SqlNode ) first ).getDataType();
+			}
+			if ( expectedType == null && SqlNode.class.isAssignableFrom( second.getClass() ) ) {
+				expectedType = ( ( SqlNode ) second ).getDataType();
+			}
+			( ( ExpectedTypeAwareNode ) check ).setExpectedType( expectedType );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BinaryArithmeticOperatorNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BinaryArithmeticOperatorNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BinaryArithmeticOperatorNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,191 @@
+//$Id: BinaryArithmeticOperatorNode.java 10000 2006-06-08 21:04:45Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.Hibernate;
+import org.hibernate.hql.ast.util.ColumnHelper;
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.type.Type;
+
+import antlr.SemanticException;
+
+/**
+ * Nodes which represent binary arithmetic operators.
+ *
+ * @author Gavin King
+ */
+public class BinaryArithmeticOperatorNode extends AbstractSelectExpression implements BinaryOperatorNode, DisplayableNode {
+
+	public void initialize() throws SemanticException {
+		Node lhs = getLeftHandOperand();
+		Node rhs = getRightHandOperand();
+		if ( lhs == null ) {
+			throw new SemanticException( "left-hand operand of a binary operator was null" );
+		}
+		if ( rhs == null ) {
+			throw new SemanticException( "right-hand operand of a binary operator was null" );
+		}
+
+		Type lhType = ( lhs instanceof SqlNode ) ? ( ( SqlNode ) lhs ).getDataType() : null;
+		Type rhType = ( rhs instanceof SqlNode ) ? ( ( SqlNode ) rhs ).getDataType() : null;
+
+		if ( ExpectedTypeAwareNode.class.isAssignableFrom( lhs.getClass() ) && rhType != null ) {
+			Type expectedType = null;
+			// we have something like : "? [op] rhs"
+			if ( isDateTimeType( rhType ) ) {
+				// more specifically : "? [op] datetime"
+				//      1) if the operator is MINUS, the param needs to be of
+				//          some datetime type
+				//      2) if the operator is PLUS, the param needs to be of
+				//          some numeric type
+				expectedType = getType() == HqlSqlTokenTypes.PLUS ? Hibernate.DOUBLE : rhType;
+			}
+			else {
+				expectedType = rhType;
+			}
+			( ( ExpectedTypeAwareNode ) lhs ).setExpectedType( expectedType );
+		}
+		else if ( ParameterNode.class.isAssignableFrom( rhs.getClass() ) && lhType != null ) {
+			Type expectedType = null;
+			// we have something like : "lhs [op] ?"
+			if ( isDateTimeType( lhType ) ) {
+				// more specifically : "datetime [op] ?"
+				//      1) if the operator is MINUS, we really cannot determine
+				//          the expected type as either another datetime or
+				//          numeric would be valid
+				//      2) if the operator is PLUS, the param needs to be of
+				//          some numeric type
+				if ( getType() == HqlSqlTokenTypes.PLUS ) {
+					expectedType = Hibernate.DOUBLE;
+				}
+			}
+			else {
+				expectedType = lhType;
+			}
+			( ( ExpectedTypeAwareNode ) rhs ).setExpectedType( expectedType );
+		}
+	}
+
+	/**
+	 * Figure out the type of the binary expression by looking at
+	 * the types of the operands. Sometimes we don't know both types,
+	 * if, for example, one is a parameter.
+	 */
+	public Type getDataType() {
+		if ( super.getDataType() == null ) {
+			super.setDataType( resolveDataType() );
+		}
+		return super.getDataType();
+	}
+
+	private Type resolveDataType() {
+		// TODO : we may also want to check that the types here map to exactly one column/JDBC-type
+		//      can't think of a situation where arithmetic expression between multi-column mappings
+		//      makes any sense.
+		Node lhs = getLeftHandOperand();
+		Node rhs = getRightHandOperand();
+		Type lhType = ( lhs instanceof SqlNode ) ? ( ( SqlNode ) lhs ).getDataType() : null;
+		Type rhType = ( rhs instanceof SqlNode ) ? ( ( SqlNode ) rhs ).getDataType() : null;
+		if ( isDateTimeType( lhType ) || isDateTimeType( rhType ) ) {
+			return resolveDateTimeArithmeticResultType( lhType, rhType );
+		}
+		else {
+			if ( lhType == null ) {
+				if ( rhType == null ) {
+					// we do not know either type
+					return Hibernate.DOUBLE; //BLIND GUESS!
+				}
+				else {
+					// we know only the rhs-hand type, so use that
+					return rhType;
+				}
+			}
+			else {
+				if ( rhType == null ) {
+					// we know only the lhs-hand type, so use that
+					return lhType;
+				}
+				else {
+					if ( lhType==Hibernate.DOUBLE || rhType==Hibernate.DOUBLE ) return Hibernate.DOUBLE;
+					if ( lhType==Hibernate.FLOAT || rhType==Hibernate.FLOAT ) return Hibernate.FLOAT;
+					if ( lhType==Hibernate.BIG_DECIMAL || rhType==Hibernate.BIG_DECIMAL ) return Hibernate.BIG_DECIMAL;
+					if ( lhType==Hibernate.BIG_INTEGER || rhType==Hibernate.BIG_INTEGER ) return Hibernate.BIG_INTEGER;
+					if ( lhType==Hibernate.LONG || rhType==Hibernate.LONG ) return Hibernate.LONG;
+					if ( lhType==Hibernate.INTEGER || rhType==Hibernate.INTEGER ) return Hibernate.INTEGER;
+					return lhType;
+				}
+			}
+		}
+	}
+
+	private boolean isDateTimeType(Type type) {
+		if ( type == null ) {
+			return false;
+		}
+		return java.util.Date.class.isAssignableFrom( type.getReturnedClass() ) ||
+	           java.util.Calendar.class.isAssignableFrom( type.getReturnedClass() );
+	}
+
+	private Type resolveDateTimeArithmeticResultType(Type lhType, Type rhType) {
+		// here, we work under the following assumptions:
+		//      ------------ valid cases --------------------------------------
+		//      1) datetime + {something other than datetime} : always results
+		//              in a datetime ( db will catch invalid conversions )
+		//      2) datetime - datetime : always results in a DOUBLE
+		//      3) datetime - {something other than datetime} : always results
+		//              in a datetime ( db will catch invalid conversions )
+		//      ------------ invalid cases ------------------------------------
+		//      4) datetime + datetime
+		//      5) {something other than datetime} - datetime
+		//      6) datetime * {any type}
+		//      7) datetime / {any type}
+		//      8) {any type} / datetime
+		// doing so allows us to properly handle parameters as either the left
+		// or right side here in the majority of cases
+		boolean lhsIsDateTime = isDateTimeType( lhType );
+		boolean rhsIsDateTime = isDateTimeType( rhType );
+
+		// handle the (assumed) valid cases:
+		// #1 - the only valid datetime addition synatx is one or the other is a datetime (but not both)
+		if ( getType() == HqlSqlTokenTypes.PLUS ) {
+			// one or the other needs to be a datetime for us to get into this method in the first place...
+			return lhsIsDateTime ? lhType : rhType;
+		}
+		else if ( getType() == HqlSqlTokenTypes.MINUS ) {
+			// #3 - note that this is also true of "datetime - :param"...
+			if ( lhsIsDateTime && !rhsIsDateTime ) {
+				return lhType;
+			}
+			// #2
+			if ( lhsIsDateTime && rhsIsDateTime ) {
+				return Hibernate.DOUBLE;
+			}
+		}
+		return null;
+	}
+
+	public void setScalarColumnText(int i) throws SemanticException {
+		ColumnHelper.generateSingleScalarColumn( this, i );
+	}
+
+	/**
+	 * Retrieves the left-hand operand of the operator.
+	 *
+	 * @return The left-hand operand
+	 */
+	public Node getLeftHandOperand() {
+		return ( Node ) getFirstChild();
+	}
+
+	/**
+	 * Retrieves the right-hand operand of the operator.
+	 *
+	 * @return The right-hand operand
+	 */
+	public Node getRightHandOperand() {
+		return ( Node ) getFirstChild().getNextSibling();
+	}
+
+	public String getDisplayText() {
+		return "{dataType=" + getDataType() + "}";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,198 @@
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.type.Type;
+import org.hibernate.Hibernate;
+import org.hibernate.TypeMismatchException;
+import org.hibernate.HibernateException;
+import org.hibernate.util.StringHelper;
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.engine.SessionFactoryImplementor;
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+/**
+ * Contract for nodes representing binary operators.
+ *
+ * @author Steve Ebersole
+ */
+public class BinaryLogicOperatorNode extends HqlSqlWalkerNode implements BinaryOperatorNode {
+	/**
+	 * Performs the operator node initialization by seeking out any parameter
+	 * nodes and setting their expected type, if possible.
+	 */
+	public void initialize() throws SemanticException {
+		Node lhs = getLeftHandOperand();
+		if ( lhs == null ) {
+			throw new SemanticException( "left-hand operand of a binary operator was null" );
+		}
+		Node rhs = getRightHandOperand();
+		if ( rhs == null ) {
+			throw new SemanticException( "right-hand operand of a binary operator was null" );
+		}
+
+		Type lhsType = extractDataType( lhs );
+		Type rhsType = extractDataType( rhs );
+
+		if ( lhsType == null ) {
+			lhsType = rhsType;
+		}
+		if ( rhsType == null ) {
+			rhsType = lhsType;
+		}
+
+		if ( ExpectedTypeAwareNode.class.isAssignableFrom( lhs.getClass() ) ) {
+			( ( ExpectedTypeAwareNode ) lhs ).setExpectedType( rhsType );
+		}
+		if ( ExpectedTypeAwareNode.class.isAssignableFrom( rhs.getClass() ) ) {
+			( ( ExpectedTypeAwareNode ) rhs ).setExpectedType( lhsType );
+		}
+
+		mutateRowValueConstructorSyntaxesIfNecessary( lhsType, rhsType );
+	}
+
+	protected final void mutateRowValueConstructorSyntaxesIfNecessary(Type lhsType, Type rhsType) {
+		// TODO : this really needs to be delayed unitl after we definitively know all node types
+		// where this is currently a problem is parameters for which where we cannot unequivocally
+		// resolve an expected type
+		SessionFactoryImplementor sessionFactory = getSessionFactoryHelper().getFactory();
+		if ( lhsType != null && rhsType != null ) {
+			int lhsColumnSpan = lhsType.getColumnSpan( sessionFactory );
+			if ( lhsColumnSpan != rhsType.getColumnSpan( sessionFactory ) ) {
+				throw new TypeMismatchException(
+						"left and right hand sides of a binary logic operator were incompatibile [" +
+						lhsType.getName() + " : "+ rhsType.getName() + "]"
+				);
+			}
+			if ( lhsColumnSpan > 1 ) {
+				// for dialects which are known to not support ANSI-SQL row-value-constructor syntax,
+				// we should mutate the tree.
+				if ( !sessionFactory.getDialect().supportsRowValueConstructorSyntax() ) {
+					mutateRowValueConstructorSyntax( lhsColumnSpan );
+				}
+			}
+		}
+	}
+
+	/**
+	 * Mutate the subtree relating to a row-value-constructor to instead use
+	 * a series of ANDed predicates.  This allows multi-column type comparisons
+	 * and explicit row-value-constructor syntax even on databases which do
+	 * not support row-value-constructor.
+	 * <p/>
+	 * For example, here we'd mutate "... where (col1, col2) = ('val1', 'val2) ..." to
+	 * "... where col1 = 'val1' and col2 = 'val2' ..."
+	 *
+	 * @param valueElements The number of elements in the row value constructor list.
+	 */
+	private void mutateRowValueConstructorSyntax(int valueElements) {
+		// mutation depends on the types of nodes invloved...
+		int comparisonType = getType();
+		String comparisonText = getText();
+		setType( HqlSqlTokenTypes.AND );
+		setText( "AND" );
+		String[] lhsElementTexts = extractMutationTexts( getLeftHandOperand(), valueElements );
+		String[] rhsElementTexts = extractMutationTexts( getRightHandOperand(), valueElements );
+
+		AST container = this;
+		for ( int i = valueElements - 1; i > 0; i-- ) {
+
+			if ( i == 1 ) {
+				AST op1 = getASTFactory().create( comparisonType, comparisonText );
+				AST lhs1 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, lhsElementTexts[0] );
+				AST rhs1 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, rhsElementTexts[0] );
+				op1.setFirstChild( lhs1 );
+				lhs1.setNextSibling( rhs1 );
+				container.setFirstChild( op1 );
+				AST op2 = getASTFactory().create( comparisonType, comparisonText );
+				AST lhs2 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, lhsElementTexts[1] );
+				AST rhs2 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, rhsElementTexts[1] );
+				op2.setFirstChild( lhs2 );
+				lhs2.setNextSibling( rhs2 );
+				op1.setNextSibling( op2 );
+			}
+			else {
+				AST op = getASTFactory().create( comparisonType, comparisonText );
+				AST lhs = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, lhsElementTexts[i] );
+				AST rhs = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, rhsElementTexts[i] );
+				op.setFirstChild( lhs );
+				lhs.setNextSibling( rhs );
+				AST newContainer = getASTFactory().create( HqlSqlTokenTypes.AND, "AND" );
+				container.setFirstChild( newContainer );
+				newContainer.setNextSibling( op );
+				container = newContainer;
+			}
+		}
+	}
+
+	private static String[] extractMutationTexts(Node operand, int count) {
+		if ( operand instanceof ParameterNode ) {
+			String[] rtn = new String[count];
+			for ( int i = 0; i < count; i++ ) {
+				rtn[i] = "?";
+			}
+			return rtn;
+		}
+		else if ( operand.getType() == HqlSqlTokenTypes.VECTOR_EXPR ) {
+			String[] rtn = new String[ operand.getNumberOfChildren() ];
+			int x = 0;
+			AST node = operand.getFirstChild();
+			while ( node != null ) {
+				rtn[ x++ ] = node.getText();
+				node = node.getNextSibling();
+			}
+			return rtn;
+		}
+		else if ( operand instanceof SqlNode ) {
+			String nodeText = operand.getText();
+			if ( nodeText.startsWith( "(" ) ) {
+				nodeText = nodeText.substring( 1 );
+			}
+			if ( nodeText.endsWith( ")" ) ) {
+				nodeText = nodeText.substring( 0, nodeText.length() - 1 );
+			}
+			String[] splits = StringHelper.split( ", ", nodeText );
+			if ( count != splits.length ) {
+				throw new HibernateException( "SqlNode's text did not reference expected number of columns" );
+			}
+			return splits;
+		}
+		else {
+			throw new HibernateException( "dont know how to extract row value elements from node : " + operand );
+		}
+	}
+
+	protected Type extractDataType(Node operand) {
+		Type type = null;
+		if ( operand instanceof SqlNode ) {
+			type = ( ( SqlNode ) operand ).getDataType();
+		}
+		if ( type == null && operand instanceof ExpectedTypeAwareNode ) {
+			type = ( ( ExpectedTypeAwareNode ) operand ).getExpectedType();
+		}
+		return type;
+	}
+
+	public Type getDataType() {
+		// logic operators by definition resolve to booleans
+		return Hibernate.BOOLEAN;
+	}
+
+	/**
+	 * Retrieves the left-hand operand of the operator.
+	 *
+	 * @return The left-hand operand
+	 */
+	public Node getLeftHandOperand() {
+		return ( Node ) getFirstChild();
+	}
+
+	/**
+	 * Retrieves the right-hand operand of the operator.
+	 *
+	 * @return The right-hand operand
+	 */
+	public Node getRightHandOperand() {
+		return ( Node ) getFirstChild().getNextSibling();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BinaryOperatorNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BinaryOperatorNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BinaryOperatorNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+package org.hibernate.hql.ast.tree;
+
+/**
+ * Contract for nodes representing binary operators.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public interface BinaryOperatorNode extends OperatorNode {
+	/**
+	 * Retrieves the left-hand operand of the operator.
+	 *
+	 * @return The left-hand operand
+	 */
+	public Node getLeftHandOperand();
+
+	/**
+	 * Retrieves the right-hand operand of the operator.
+	 *
+	 * @return The right-hand operand
+	 */
+	public Node getRightHandOperand();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BooleanLiteralNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BooleanLiteralNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/BooleanLiteralNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.type.Type;
+import org.hibernate.type.BooleanType;
+import org.hibernate.Hibernate;
+import org.hibernate.QueryException;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Represents a boolean literal within a query.
+ *
+ * @author Steve Ebersole
+ */
+public class BooleanLiteralNode extends LiteralNode implements ExpectedTypeAwareNode {
+	private Type expectedType;
+
+	public Type getDataType() {
+		return expectedType == null ? Hibernate.BOOLEAN : expectedType;
+	}
+
+	public BooleanType getTypeInternal() {
+		return ( BooleanType ) getDataType();
+	}
+
+	public Boolean getValue() {
+		return getType() == TRUE ? Boolean.TRUE : Boolean.FALSE;
+	}
+
+	/**
+	 * Expected-types really only pertinent here for boolean literals...
+	 *
+	 * @param expectedType
+	 */
+	public void setExpectedType(Type expectedType) {
+		this.expectedType = expectedType;
+	}
+
+	public Type getExpectedType() {
+		return expectedType;
+	}
+
+	public String getRenderText(SessionFactoryImplementor sessionFactory) {
+		try {
+			return getTypeInternal().objectToSQLString( getValue(), sessionFactory.getDialect() );
+		}
+		catch( Throwable t ) {
+			throw new QueryException( "Unable to render boolean literal value", t );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/Case2Node.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/Case2Node.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/Case2Node.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+// $Id: Case2Node.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.ast.util.ColumnHelper;
+import org.hibernate.type.Type;
+
+import antlr.SemanticException;
+
+/**
+ * Represents a case ... when .. then ... else ... end expression in a select.
+ *
+ * @author Gavin King
+ */
+public class Case2Node extends AbstractSelectExpression implements SelectExpression {
+	
+	public Type getDataType() {
+		return getFirstThenNode().getDataType();
+	}
+
+	private SelectExpression getFirstThenNode() {
+		return (SelectExpression) getFirstChild().getNextSibling().getFirstChild().getNextSibling();
+	}
+
+	public void setScalarColumnText(int i) throws SemanticException {
+		ColumnHelper.generateSingleScalarColumn( this, i );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/CaseNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/CaseNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/CaseNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+// $Id: CaseNode.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.ast.util.ColumnHelper;
+import org.hibernate.type.Type;
+
+import antlr.SemanticException;
+
+/**
+ * Represents a case ... when .. then ... else ... end expression in a select.
+ *
+ * @author Gavin King
+ */
+public class CaseNode extends AbstractSelectExpression implements SelectExpression {
+	
+	public Type getDataType() {
+		return getFirstThenNode().getDataType();
+	}
+
+	private SelectExpression getFirstThenNode() {
+		return (SelectExpression) getFirstChild().getFirstChild().getNextSibling();
+	}
+
+	public void setScalarColumnText(int i) throws SemanticException {
+		ColumnHelper.generateSingleScalarColumn( this, i );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/CollectionFunction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/CollectionFunction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/CollectionFunction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+// $Id: CollectionFunction.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+/**
+ * Represents 'elements()' or 'indices()'.
+ *
+ * @author josh Dec 6, 2004 8:36:42 AM
+ */
+public class CollectionFunction extends MethodNode implements DisplayableNode {
+	public void resolve(boolean inSelect) throws SemanticException {
+		initializeMethodNode( this, inSelect );
+		if ( !isCollectionPropertyMethod() ) {
+			throw new SemanticException( this.getText() + " is not a collection property name!" );
+		}
+		AST expr = getFirstChild();
+		if ( expr == null ) {
+			throw new SemanticException( this.getText() + " requires a path!" );
+		}
+		resolveCollectionProperty( expr );
+	}
+
+	protected void prepareSelectColumns(String[] selectColumns) {
+		// we need to strip off the embedded parens so that sql-gen does not double these up
+		String subselect = selectColumns[0].trim();
+		if ( subselect.startsWith( "(") && subselect.endsWith( ")" ) ) {
+			subselect = subselect.substring( 1, subselect.length() -1 );
+		}
+		selectColumns[0] = subselect;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ConstructorNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ConstructorNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ConstructorNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,158 @@
+// $Id: ConstructorNode.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import java.lang.reflect.Constructor;
+import java.util.Arrays;
+import java.util.List;
+
+import org.hibernate.PropertyNotFoundException;
+import org.hibernate.hql.ast.DetailedSemanticException;
+import org.hibernate.type.Type;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.StringHelper;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+/**
+ * Represents a constructor (new) in a SELECT.
+ *
+ * @author josh Sep 24, 2004 6:46:08 PM
+ */
+public class ConstructorNode extends SelectExpressionList implements SelectExpression {
+
+	private Constructor constructor;
+	private Type[] constructorArgumentTypes;
+	private boolean isMap;
+	private boolean isList;
+	
+	public boolean isMap() {
+		return isMap;
+	}
+	
+	public boolean isList() {
+		return isList;
+	}
+	
+	public String[] getAliases() {
+		SelectExpression[] selectExpressions = collectSelectExpressions();
+		String[] aliases = new String[selectExpressions.length] ;
+		for ( int i=0; i<selectExpressions.length; i++ ) {
+			String alias = selectExpressions[i].getAlias();
+			aliases[i] = alias==null ? Integer.toString(i) : alias;
+		}
+		return aliases;
+	}
+
+	public void setScalarColumnText(int i) throws SemanticException {
+		SelectExpression[] selectExpressions = collectSelectExpressions();
+		// Invoke setScalarColumnText on each constructor argument.
+		for ( int j = 0; j < selectExpressions.length; j++ ) {
+			SelectExpression selectExpression = selectExpressions[j];
+			selectExpression.setScalarColumnText( j );
+		}
+	}
+
+	protected AST getFirstSelectExpression() {
+		// Collect the select expressions, skip the first child because it is the class name.
+		return getFirstChild().getNextSibling();
+	}
+
+	/**
+	 * @deprecated (tell clover to ignore this method)
+	 */
+	public Type getDataType() {
+/*
+		// Return the type of the object created by the constructor.
+		AST firstChild = getFirstChild();
+		String text = firstChild.getText();
+		if ( firstChild.getType() == SqlTokenTypes.DOT ) {
+			DotNode dot = ( DotNode ) firstChild;
+			text = dot.getPath();
+		}
+		return getSessionFactoryHelper().requireEntityType( text );
+*/
+		throw new UnsupportedOperationException( "getDataType() is not supported by ConstructorNode!" );
+	}
+
+	public void prepare() throws SemanticException {
+		constructorArgumentTypes = resolveConstructorArgumentTypes();
+		String path = ( ( PathNode ) getFirstChild() ).getPath();
+		if ( "map".equals( path.toLowerCase() ) ) {
+			isMap = true;
+		}
+		else if ( "list".equals( path.toLowerCase() ) ) {
+			isList = true;
+		}
+		else {
+			constructor = resolveConstructor(path);
+		}
+	}
+
+	private Type[] resolveConstructorArgumentTypes() throws SemanticException {
+		SelectExpression[] argumentExpressions = collectSelectExpressions();
+		if ( argumentExpressions == null ) {
+			// return an empty Type array
+			return new Type[]{};
+		}
+
+		Type[] types = new Type[argumentExpressions.length];
+		for ( int x = 0; x < argumentExpressions.length; x++ ) {
+			types[x] = argumentExpressions[x].getDataType();
+		}
+		return types;
+	}
+
+	private Constructor resolveConstructor(String path) throws SemanticException {
+		String importedClassName = getSessionFactoryHelper().getImportedClassName( path );
+		String className = StringHelper.isEmpty( importedClassName ) ? path : importedClassName;
+		if ( className == null ) {
+			throw new SemanticException( "Unable to locate class [" + path + "]" );
+		}
+		try {
+			Class holderClass = ReflectHelper.classForName( className );
+			return ReflectHelper.getConstructor( holderClass, constructorArgumentTypes );
+		}
+		catch ( ClassNotFoundException e ) {
+			throw new DetailedSemanticException( "Unable to locate class [" + className + "]", e );
+		}
+		catch ( PropertyNotFoundException e ) {
+			// this is the exception returned by ReflectHelper.getConstructor() if it cannot
+			// locate an appropriate constructor
+			throw new DetailedSemanticException( "Unable to locate appropriate constructor on class [" + className + "]", e );
+		}
+	}
+	
+	public Constructor getConstructor() {
+		return constructor;
+	}
+
+	public List getConstructorArgumentTypeList() {
+		return Arrays.asList( constructorArgumentTypes );
+	}
+
+	public FromElement getFromElement() {
+		return null;
+	}
+
+	public boolean isConstructor() {
+		return true;
+	}
+
+	public boolean isReturnableEntity() throws SemanticException {
+		return false;
+	}
+
+	public boolean isScalar() {
+		// Constructors are always considered scalar results.
+		return true;
+	}
+	
+	public void setAlias(String alias) {
+		throw new UnsupportedOperationException("constructor may not be aliased");
+	}
+	
+	public String getAlias() {
+		throw new UnsupportedOperationException("constructor may not be aliased");
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/CountNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/CountNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/CountNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+// $Id: CountNode.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.ast.util.ColumnHelper;
+import org.hibernate.type.Type;
+
+import antlr.SemanticException;
+
+/**
+ * Represents a COUNT expression in a select.
+ *
+ * @author josh Sep 21, 2004 9:23:40 PM
+ */
+public class CountNode extends AbstractSelectExpression implements SelectExpression {
+	
+	public Type getDataType() {
+		return getSessionFactoryHelper().findFunctionReturnType( getText(), null );
+	}
+
+	public void setScalarColumnText(int i) throws SemanticException {
+		ColumnHelper.generateSingleScalarColumn( this, i );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/DeleteStatement.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/DeleteStatement.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/DeleteStatement.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+// $Id: DeleteStatement.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.hql.antlr.SqlTokenTypes;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Defines a top-level AST node representing an HQL delete statement.
+ *
+ * @author Steve Ebersole
+ */
+public class DeleteStatement extends AbstractRestrictableStatement {
+
+	private static final Log log = LogFactory.getLog( DeleteStatement.class );
+
+	/**
+	 * @see org.hibernate.hql.ast.tree.Statement#getStatementType()
+	 */
+	public int getStatementType() {
+		return HqlSqlTokenTypes.DELETE;
+	}
+
+	/**
+	 * @see org.hibernate.hql.ast.tree.Statement#needsExecutor()
+	 */
+	public boolean needsExecutor() {
+		return true;
+	}
+
+	protected int getWhereClauseParentTokenType() {
+		return SqlTokenTypes.FROM;
+	}
+
+	protected Log getLog() {
+		return log;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/DisplayableNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/DisplayableNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/DisplayableNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+// $Id: DisplayableNode.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+/**
+ * Implementors will return additional display text, which will be used
+ * by the ASTPrinter to display information (besides the node type and node
+ * text).
+ */
+public interface DisplayableNode {
+	/**
+	 * Returns additional display text for the AST node.
+	 *
+	 * @return String - The additional display text.
+	 */
+	String getDisplayText();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/DotNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/DotNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/DotNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,666 @@
+// $Id: DotNode.java 11378 2007-03-30 11:23:48Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.QueryException;
+import org.hibernate.engine.JoinSequence;
+import org.hibernate.hql.CollectionProperties;
+import org.hibernate.hql.antlr.SqlTokenTypes;
+import org.hibernate.hql.ast.util.ASTPrinter;
+import org.hibernate.hql.ast.util.ASTUtil;
+import org.hibernate.hql.ast.util.ColumnHelper;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.util.StringHelper;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Represents a reference to a property or alias expression.  This should duplicate the relevant behaviors in
+ * PathExpressionParser.
+ *
+ * @author Joshua Davis
+ */
+public class DotNode extends FromReferenceNode implements DisplayableNode, SelectExpression {
+
+	///////////////////////////////////////////////////////////////////////////
+	// USED ONLY FOR REGRESSION TESTING!!!!
+	//
+	// todo : obviously get rid of all this junk ;)
+	///////////////////////////////////////////////////////////////////////////
+	public static boolean useThetaStyleImplicitJoins = false;
+	public static boolean REGRESSION_STYLE_JOIN_SUPPRESSION = false;
+	public static interface IllegalCollectionDereferenceExceptionBuilder {
+		public QueryException buildIllegalCollectionDereferenceException(String collectionPropertyName, FromReferenceNode lhs);
+	}
+	public static final IllegalCollectionDereferenceExceptionBuilder DEF_ILLEGAL_COLL_DEREF_EXCP_BUILDER = new IllegalCollectionDereferenceExceptionBuilder() {
+		public QueryException buildIllegalCollectionDereferenceException(String propertyName, FromReferenceNode lhs) {
+			String lhsPath = ASTUtil.getPathText( lhs );
+			return new QueryException( "illegal attempt to dereference collection [" + lhsPath + "] with element property reference [" + propertyName + "]" );
+		}
+	};
+	public static IllegalCollectionDereferenceExceptionBuilder ILLEGAL_COLL_DEREF_EXCP_BUILDER = DEF_ILLEGAL_COLL_DEREF_EXCP_BUILDER;
+	///////////////////////////////////////////////////////////////////////////
+
+	private static final Log log = LogFactory.getLog( DotNode.class );
+
+	private static final int DEREF_UNKNOWN = 0;
+	private static final int DEREF_ENTITY = 1;
+	private static final int DEREF_COMPONENT = 2;
+	private static final int DEREF_COLLECTION = 3;
+	private static final int DEREF_PRIMITIVE = 4;
+	private static final int DEREF_IDENTIFIER = 5;
+	private static final int DEREF_JAVA_CONSTANT = 6;
+
+	/**
+	 * The identifier that is the name of the property.
+	 */
+	private String propertyName;
+	/**
+	 * The full path, to the root alias of this dot node.
+	 */
+	private String path;
+	/**
+	 * The unresolved property path relative to this dot node.
+	 */
+	private String propertyPath;
+
+	/**
+	 * The column names that this resolves to.
+	 */
+	private String[] columns;
+
+	/**
+	 * The type of join to create.   Default is an inner join.
+	 */
+	private int joinType = JoinFragment.INNER_JOIN;
+
+	/**
+	 * Fetch join or not.
+	 */
+	private boolean fetch = false;
+
+	/**
+	 * The type of dereference that hapened (DEREF_xxx).
+	 */
+	private int dereferenceType = DEREF_UNKNOWN;
+
+	private FromElement impliedJoin;
+
+	/**
+	 * Sets the join type for this '.' node structure.
+	 *
+	 * @param joinType The type of join to use.
+	 * @see JoinFragment
+	 */
+	public void setJoinType(int joinType) {
+		this.joinType = joinType;
+	}
+
+	private String[] getColumns() throws QueryException {
+		if ( columns == null ) {
+			// Use the table fromElement and the property name to get the array of column names.
+			String tableAlias = getLhs().getFromElement().getTableAlias();
+			columns = getFromElement().toColumns( tableAlias, propertyPath, false );
+		}
+		return columns;
+	}
+
+	public String getDisplayText() {
+		StringBuffer buf = new StringBuffer();
+		FromElement fromElement = getFromElement();
+		buf.append( "{propertyName=" ).append( propertyName );
+		buf.append( ",dereferenceType=" ).append( ASTPrinter.getConstantName( getClass(), dereferenceType ) );
+		buf.append( ",propertyPath=" ).append( propertyPath );
+		buf.append( ",path=" ).append( getPath() );
+		if ( fromElement != null ) {
+			buf.append( ",tableAlias=" ).append( fromElement.getTableAlias() );
+			buf.append( ",className=" ).append( fromElement.getClassName() );
+			buf.append( ",classAlias=" ).append( fromElement.getClassAlias() );
+		}
+		else {
+			buf.append( ",no from element" );
+		}
+		buf.append( '}' );
+		return buf.toString();
+	}
+
+	/**
+	 * Resolves the left hand side of the DOT.
+	 *
+	 * @throws SemanticException
+	 */
+	public void resolveFirstChild() throws SemanticException {
+		FromReferenceNode lhs = ( FromReferenceNode ) getFirstChild();
+		SqlNode property = ( SqlNode ) lhs.getNextSibling();
+
+		// Set the attributes of the property reference expression.
+		String propName = property.getText();
+		propertyName = propName;
+		// If the uresolved property path isn't set yet, just use the property name.
+		if ( propertyPath == null ) {
+			propertyPath = propName;
+		}
+		// Resolve the LHS fully, generate implicit joins.  Pass in the property name so that the resolver can
+		// discover foreign key (id) properties.
+		lhs.resolve( true, true, null, this );
+		setFromElement( lhs.getFromElement() );			// The 'from element' that the property is in.
+
+		checkSubclassOrSuperclassPropertyReference( lhs, propName );
+	}
+
+	public void resolveInFunctionCall(boolean generateJoin, boolean implicitJoin) throws SemanticException {
+		if ( isResolved() ) {
+			return;
+		}
+		Type propertyType = prepareLhs();			// Prepare the left hand side and get the data type.
+		if ( propertyType!=null && propertyType.isCollectionType() ) {
+			resolveIndex(null);
+		}
+		else {
+			resolveFirstChild();
+			super.resolve(generateJoin, implicitJoin);
+		}
+	}
+
+
+	public void resolveIndex(AST parent) throws SemanticException {
+		if ( isResolved() ) {
+			return;
+		}
+		Type propertyType = prepareLhs();			// Prepare the left hand side and get the data type.
+		dereferenceCollection( ( CollectionType ) propertyType, true, true, null, parent );
+	}
+
+	public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent)
+	throws SemanticException {
+		// If this dot has already been resolved, stop now.
+		if ( isResolved() ) {
+			return;
+		}
+		Type propertyType = prepareLhs(); // Prepare the left hand side and get the data type.
+
+		// If there is no data type for this node, and we're at the end of the path (top most dot node), then
+		// this might be a Java constant.
+		if ( propertyType == null ) {
+			if ( parent == null ) {
+				getWalker().getLiteralProcessor().lookupConstant( this );
+			}
+			// If the propertyType is null and there isn't a parent, just
+			// stop now... there was a problem resolving the node anyway.
+			return;
+		}
+
+		if ( propertyType.isComponentType() ) {
+			// The property is a component...
+			checkLhsIsNotCollection();
+			dereferenceComponent( parent );
+			initText();
+		}
+		else if ( propertyType.isEntityType() ) {
+			// The property is another class..
+			checkLhsIsNotCollection();
+			dereferenceEntity( ( EntityType ) propertyType, implicitJoin, classAlias, generateJoin, parent );
+			initText();
+		}
+		else if ( propertyType.isCollectionType() ) {
+			// The property is a collection...
+			checkLhsIsNotCollection();
+			dereferenceCollection( ( CollectionType ) propertyType, implicitJoin, false, classAlias, parent );
+		}
+		else {
+			// Otherwise, this is a primitive type.
+			if ( ! CollectionProperties.isAnyCollectionProperty( propertyName ) ) {
+				checkLhsIsNotCollection();
+			}
+			dereferenceType = DEREF_PRIMITIVE;
+			initText();
+		}
+		setResolved();
+	}
+
+	private void initText() {
+		String[] cols = getColumns();
+		String text = StringHelper.join( ", ", cols );
+		if ( cols.length > 1 && getWalker().isComparativeExpressionClause() ) {
+			text = "(" + text + ")";
+		}
+		setText( text );
+	}
+
+	private Type prepareLhs() throws SemanticException {
+		FromReferenceNode lhs = getLhs();
+		lhs.prepareForDot( propertyName );
+		return getDataType();
+	}
+
+	private void dereferenceCollection(CollectionType collectionType, boolean implicitJoin, boolean indexed, String classAlias, AST parent)
+	throws SemanticException {
+
+		dereferenceType = DEREF_COLLECTION;
+		String role = collectionType.getRole();
+
+		//foo.bars.size (also handles deprecated stuff like foo.bars.maxelement for backwardness)
+		boolean isSizeProperty = getNextSibling()!=null &&
+			CollectionProperties.isAnyCollectionProperty( getNextSibling().getText() );
+
+		if ( isSizeProperty ) indexed = true; //yuck!
+
+		QueryableCollection queryableCollection = getSessionFactoryHelper().requireQueryableCollection( role );
+		String propName = getPath();
+		FromClause currentFromClause = getWalker().getCurrentFromClause();
+
+		if ( getWalker().getStatementType() != SqlTokenTypes.SELECT && indexed && classAlias == null ) {
+			// should indicate that we are processing an INSERT/UPDATE/DELETE
+			// query with a subquery implied via a collection property
+			// function. Here, we need to use the table name itself as the
+			// qualification alias.
+			// TODO : verify this works for all databases...
+			// TODO : is this also the case in non-"indexed" scenarios?
+			String alias = getLhs().getFromElement().getQueryable().getTableName();
+			columns = getFromElement().toColumns( alias, propertyPath, false, true );
+		}
+
+		//We do not look for an existing join on the same path, because
+		//it makes sense to join twice on the same collection role
+		FromElementFactory factory = new FromElementFactory(
+		        currentFromClause,
+		        getLhs().getFromElement(),
+		        propName,
+				classAlias,
+		        getColumns(),
+		        implicitJoin
+		);
+		FromElement elem = factory.createCollection( queryableCollection, role, joinType, fetch, indexed );
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( "dereferenceCollection() : Created new FROM element for " + propName + " : " + elem );
+		}
+
+		setImpliedJoin( elem );
+		setFromElement( elem );	// This 'dot' expression now refers to the resulting from element.
+
+		if ( isSizeProperty ) {
+			elem.setText("");
+			elem.setUseWhereFragment(false);
+		}
+
+		if ( !implicitJoin ) {
+			EntityPersister entityPersister = elem.getEntityPersister();
+			if ( entityPersister != null ) {
+				getWalker().addQuerySpaces( entityPersister.getQuerySpaces() );
+			}
+		}
+		getWalker().addQuerySpaces( queryableCollection.getCollectionSpaces() );	// Always add the collection's query spaces.
+	}
+
+	private void dereferenceEntity(EntityType entityType, boolean implicitJoin, String classAlias, boolean generateJoin, AST parent) throws SemanticException {
+		checkForCorrelatedSubquery( "dereferenceEntity" );
+		// three general cases we check here as to whether to render a physical SQL join:
+		// 1) is our parent a DotNode as well?  If so, our property reference is
+		// 		being further de-referenced...
+		// 2) is this a DML statement
+		// 3) we were asked to generate any needed joins (generateJoins==true) *OR*
+		//		we are currently processing a select or from clause
+		// (an additional check is the REGRESSION_STYLE_JOIN_SUPPRESSION check solely intended for the test suite)
+		//
+		// The REGRESSION_STYLE_JOIN_SUPPRESSION is an additional check
+		// intended solely for use within the test suite.  This forces the
+		// implicit join resolution to behave more like the classic parser.
+		// The underlying issue is that classic translator is simply wrong
+		// about its decisions on whether or not to render an implicit join
+		// into a physical SQL join in a lot of cases.  The piece it generally
+		// tends to miss is that INNER joins effect the results by further
+		// restricting the data set!  A particular manifestation of this is
+		// the fact that the classic translator will skip the physical join
+		// for ToOne implicit joins *if the query is shallow*; the result
+		// being that Query.list() and Query.iterate() could return
+		// different number of results!
+		DotNode parentAsDotNode = null;
+		String property = propertyName;
+		final boolean joinIsNeeded;
+
+		if ( isDotNode( parent ) ) {
+			// our parent is another dot node, meaning we are being further dereferenced.
+			// thus we need to generate a join unless the parent refers to the associated
+			// entity's PK (because 'our' table would know the FK).
+			parentAsDotNode = ( DotNode ) parent;
+			property = parentAsDotNode.propertyName;
+			joinIsNeeded = generateJoin && !isReferenceToPrimaryKey( parentAsDotNode.propertyName, entityType );
+		}
+		else if ( ! getWalker().isSelectStatement() ) {
+			joinIsNeeded = false;
+		}
+		else if ( REGRESSION_STYLE_JOIN_SUPPRESSION ) {
+			// this is the regression style determination which matches the logic of the classic translator
+			joinIsNeeded = generateJoin && ( !getWalker().isInSelect() || !getWalker().isShallowQuery() );
+		}
+		else {
+			joinIsNeeded = generateJoin || ( getWalker().isInSelect() || getWalker().isInFrom() );
+		}
+
+		if ( joinIsNeeded ) {
+			dereferenceEntityJoin( classAlias, entityType, implicitJoin, parent );
+		}
+		else {
+			dereferenceEntityIdentifier( property, parentAsDotNode );
+		}
+
+	}
+
+	private boolean isDotNode(AST n) {
+		return n != null && n.getType() == SqlTokenTypes.DOT;
+	}
+
+	private void dereferenceEntityJoin(String classAlias, EntityType propertyType, boolean impliedJoin, AST parent)
+	throws SemanticException {
+		dereferenceType = DEREF_ENTITY;
+		if ( log.isDebugEnabled() ) {
+			log.debug( "dereferenceEntityJoin() : generating join for " + propertyName + " in "
+					+ getFromElement().getClassName() + " "
+					+ ( ( classAlias == null ) ? "{no alias}" : "(" + classAlias + ")" )
+					+ " parent = " + ASTUtil.getDebugString( parent )
+			);
+		}
+		// Create a new FROM node for the referenced class.
+		String associatedEntityName = propertyType.getAssociatedEntityName();
+		String tableAlias = getAliasGenerator().createName( associatedEntityName );
+
+		String[] joinColumns = getColumns();
+		String joinPath = getPath();
+
+		if ( impliedJoin && getWalker().isInFrom() ) {
+			joinType = getWalker().getImpliedJoinType();
+		}
+
+		FromClause currentFromClause = getWalker().getCurrentFromClause();
+		FromElement elem = currentFromClause.findJoinByPath( joinPath );
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// This is the piece which recognizes the condition where an implicit join path
+// resolved earlier in a correlated subquery is now being referenced in the
+// outer query.  For 3.0final, we just let this generate a second join (which
+// is exactly how the old parser handles this).  Eventually we need to add this
+// logic back in and complete the logic in FromClause.promoteJoin; however,
+// FromClause.promoteJoin has its own difficulties (see the comments in
+// FromClause.promoteJoin).
+//
+//		if ( elem == null ) {
+//			// see if this joinPath has been used in a "child" FromClause, and if so
+//			// promote that element to the outer query
+//			FromClause currentNodeOwner = getFromElement().getFromClause();
+//			FromClause currentJoinOwner = currentNodeOwner.locateChildFromClauseWithJoinByPath( joinPath );
+//			if ( currentJoinOwner != null && currentNodeOwner != currentJoinOwner ) {
+//				elem = currentJoinOwner.findJoinByPathLocal( joinPath );
+//				if ( elem != null ) {
+//					currentFromClause.promoteJoin( elem );
+//					// EARLY EXIT!!!
+//					return;
+//				}
+//			}
+//		}
+//
+///////////////////////////////////////////////////////////////////////////////
+
+		if ( elem == null ) {
+			// If this is an implied join in a from element, then use the impled join type which is part of the
+			// tree parser's state (set by the gramamar actions).
+			JoinSequence joinSequence = getSessionFactoryHelper()
+				.createJoinSequence( impliedJoin, propertyType, tableAlias, joinType, joinColumns );
+
+			FromElementFactory factory = new FromElementFactory(
+			        currentFromClause,
+					getLhs().getFromElement(),
+					joinPath,
+					classAlias,
+					joinColumns,
+					impliedJoin
+			);
+			elem = factory.createEntityJoin(
+					associatedEntityName,
+					tableAlias,
+					joinSequence,
+					fetch,
+					getWalker().isInFrom(),
+					propertyType
+			);
+		}
+		else {
+			currentFromClause.addDuplicateAlias(classAlias, elem);
+		}
+		setImpliedJoin( elem );
+		getWalker().addQuerySpaces( elem.getEntityPersister().getQuerySpaces() );
+		setFromElement( elem );	// This 'dot' expression now refers to the resulting from element.
+	}
+
+	private void setImpliedJoin(FromElement elem) {
+		this.impliedJoin = elem;
+		if ( getFirstChild().getType() == SqlTokenTypes.DOT ) {
+			DotNode dotLhs = ( DotNode ) getFirstChild();
+			if ( dotLhs.getImpliedJoin() != null ) {
+				this.impliedJoin = dotLhs.getImpliedJoin();
+			}
+		}
+	}
+
+	public FromElement getImpliedJoin() {
+		return impliedJoin;
+	}
+
+	/**
+	 * Is the given property name a reference to the primary key of the associated
+	 * entity construed by the given entity type?
+	 * <p/>
+	 * For example, consider a fragment like order.customer.id
+	 * (where order is a from-element alias).  Here, we'd have:
+	 * propertyName = "id" AND
+	 * owningType = ManyToOneType(Customer)
+	 * and are being asked to determine whether "customer.id" is a reference
+	 * to customer's PK...
+	 *
+	 * @param propertyName The name of the property to check.
+	 * @param owningType The type represeting the entity "owning" the property
+	 * @return True if propertyName references the entity's (owningType->associatedEntity)
+	 * primary key; false otherwise.
+	 */
+	private boolean isReferenceToPrimaryKey(String propertyName, EntityType owningType) {
+		EntityPersister persister = getSessionFactoryHelper()
+				.getFactory()
+				.getEntityPersister( owningType.getAssociatedEntityName() );
+		if ( persister.getEntityMetamodel().hasNonIdentifierPropertyNamedId() ) {
+			// only the identifier property field name can be a reference to the associated entity's PK...
+			return propertyName.equals( persister.getIdentifierPropertyName() ) && owningType.isReferenceToPrimaryKey();
+		}
+		else {
+			// here, we have two possibilities:
+			// 		1) the property-name matches the explicitly identifier property name
+			//		2) the property-name matches the implicit 'id' property name
+			if ( EntityPersister.ENTITY_ID.equals( propertyName ) ) {
+				// the referenced node text is the special 'id'
+				return owningType.isReferenceToPrimaryKey();
+			}
+			else {
+				String keyPropertyName = getSessionFactoryHelper().getIdentifierOrUniqueKeyPropertyName( owningType );
+				return keyPropertyName != null && keyPropertyName.equals( propertyName ) && owningType.isReferenceToPrimaryKey();
+			}
+		}
+	}
+
+	private void checkForCorrelatedSubquery(String methodName) {
+		if ( isCorrelatedSubselect() ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( methodName + "() : correlated subquery" );
+			}
+		}
+	}
+
+	private boolean isCorrelatedSubselect() {
+		return getWalker().isSubQuery() &&
+			getFromElement().getFromClause() != getWalker().getCurrentFromClause();
+	}
+
+	private void checkLhsIsNotCollection() throws SemanticException {
+		if ( getLhs().getDataType() != null && getLhs().getDataType().isCollectionType() ) {
+			throw ILLEGAL_COLL_DEREF_EXCP_BUILDER.buildIllegalCollectionDereferenceException( propertyName, getLhs() );
+		}
+	}
+	private void dereferenceComponent(AST parent) {
+		dereferenceType = DEREF_COMPONENT;
+		setPropertyNameAndPath( parent );
+	}
+
+	private void dereferenceEntityIdentifier(String propertyName, DotNode dotParent) {
+		// special shortcut for id properties, skip the join!
+		// this must only occur at the _end_ of a path expression
+		if ( log.isDebugEnabled() ) {
+			log.debug( "dereferenceShortcut() : property " +
+				propertyName + " in " + getFromElement().getClassName() +
+				" does not require a join." );
+		}
+
+		initText();
+		setPropertyNameAndPath( dotParent ); // Set the unresolved path in this node and the parent.
+		// Set the text for the parent.
+		if ( dotParent != null ) {
+			dotParent.dereferenceType = DEREF_IDENTIFIER;
+			dotParent.setText( getText() );
+			dotParent.columns = getColumns();
+		}
+	}
+
+	private void setPropertyNameAndPath(AST parent) {
+		if ( isDotNode( parent ) ) {
+			DotNode dotNode = ( DotNode ) parent;
+			AST lhs = dotNode.getFirstChild();
+			AST rhs = lhs.getNextSibling();
+			propertyName = rhs.getText();
+			propertyPath = propertyPath + "." + propertyName; // Append the new property name onto the unresolved path.
+			dotNode.propertyPath = propertyPath;
+			if ( log.isDebugEnabled() ) {
+				log.debug( "Unresolved property path is now '" + dotNode.propertyPath + "'" );
+			}
+		}
+		else {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "terminal propertyPath = [" + propertyPath + "]" );
+			}
+		}
+	}
+
+	public Type getDataType() {
+		if ( super.getDataType() == null ) {
+			FromElement fromElement = getLhs().getFromElement();
+			if ( fromElement == null ) {
+				return null;
+			}
+			// If the lhs is a collection, use CollectionPropertyMapping
+			Type propertyType = fromElement.getPropertyType( propertyName, propertyPath );
+			if ( log.isDebugEnabled() ) {
+				log.debug( "getDataType() : " + propertyPath + " -> " + propertyType );
+			}
+			super.setDataType( propertyType );
+		}
+		return super.getDataType();
+	}
+
+	public void setPropertyPath(String propertyPath) {
+		this.propertyPath = propertyPath;
+	}
+
+	public String getPropertyPath() {
+		return propertyPath;
+	}
+
+	public FromReferenceNode getLhs() {
+		FromReferenceNode lhs = ( ( FromReferenceNode ) getFirstChild() );
+		if ( lhs == null ) {
+			throw new IllegalStateException( "DOT node with no left-hand-side!" );
+		}
+		return lhs;
+	}
+
+	/**
+	 * Returns the full path of the node.
+	 *
+	 * @return the full path of the node.
+	 */
+	public String getPath() {
+		if ( path == null ) {
+			FromReferenceNode lhs = getLhs();
+			if ( lhs == null ) {
+				path = getText();
+			}
+			else {
+				SqlNode rhs = ( SqlNode ) lhs.getNextSibling();
+				path = lhs.getPath() + "." + rhs.getOriginalText();
+			}
+		}
+		return path;
+	}
+
+	public void setFetch(boolean fetch) {
+		this.fetch = fetch;
+	}
+
+	public void setScalarColumnText(int i) throws SemanticException {
+		String[] sqlColumns = getColumns();
+		ColumnHelper.generateScalarColumns( this, sqlColumns, i );
+	}
+
+	/**
+	 * Special method to resolve expressions in the SELECT list.
+	 *
+	 * @throws SemanticException if this cannot be resolved.
+	 */
+	public void resolveSelectExpression() throws SemanticException {
+		if ( getWalker().isShallowQuery() || getWalker().getCurrentFromClause().isSubQuery() ) {
+			resolve(false, true);
+		}
+		else {
+			resolve(true, false);
+			Type type = getDataType();
+			if ( type.isEntityType() ) {
+				FromElement fromElement = getFromElement();
+				fromElement.setIncludeSubclasses( true ); // Tell the destination fromElement to 'includeSubclasses'.
+				if ( useThetaStyleImplicitJoins ) {
+					fromElement.getJoinSequence().setUseThetaStyle( true );	// Use theta style (for regression)
+					// Move the node up, after the origin node.
+					FromElement origin = fromElement.getOrigin();
+					if ( origin != null ) {
+						ASTUtil.makeSiblingOfParent( origin, fromElement );
+					}
+				}
+			}
+		}
+
+		FromReferenceNode lhs = getLhs();
+		while ( lhs != null ) {
+			checkSubclassOrSuperclassPropertyReference( lhs, lhs.getNextSibling().getText() );
+			lhs = ( FromReferenceNode ) lhs.getFirstChild();
+		}
+	}
+
+	public void setResolvedConstant(String text) {
+		path = text;
+		dereferenceType = DEREF_JAVA_CONSTANT;
+		setResolved(); // Don't resolve the node again.
+	}
+
+	private boolean checkSubclassOrSuperclassPropertyReference(FromReferenceNode lhs, String propertyName) {
+		if ( lhs != null && !( lhs instanceof IndexNode ) ) {
+			final FromElement source = lhs.getFromElement();
+			if ( source != null ) {
+				source.handlePropertyBeingDereferenced( lhs.getDataType(), propertyName );
+			}
+		}
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ExpectedTypeAwareNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ExpectedTypeAwareNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ExpectedTypeAwareNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,14 @@
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.type.Type;
+
+/**
+ * Interface for nodes which wish to be made aware of any determined "expected
+ * type" based on the context within they appear in the query.
+ *
+ * @author Steve Ebersole
+ */
+public interface ExpectedTypeAwareNode {
+	public void setExpectedType(Type expectedType);
+	public Type getExpectedType();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromClause.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromClause.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromClause.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,364 @@
+// $Id: FromClause.java 10172 2006-07-26 18:01:49Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.tree;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.hql.ast.util.ASTIterator;
+import org.hibernate.hql.ast.util.ASTUtil;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+/**
+ * Represents the 'FROM' part of a query or subquery, containing all mapped class references.
+ *
+ * @author josh
+ */
+public class FromClause extends HqlSqlWalkerNode implements HqlSqlTokenTypes, DisplayableNode {
+	private static Log log = LogFactory.getLog( FromClause.class );
+	public static final int ROOT_LEVEL = 1;
+
+	private int level = ROOT_LEVEL;
+	private Set fromElements = new HashSet();
+	private Map fromElementByClassAlias = new HashMap();
+	private Map fromElementByTableAlias = new HashMap();
+	private Map fromElementsByPath = new HashMap();
+
+	/**
+	 * All of the implicit FROM xxx JOIN yyy elements that are the destination of a collection.  These are created from
+	 * index operators on collection property references.
+	 */
+	private Map collectionJoinFromElementsByPath = new HashMap();
+	/**
+	 * Pointer to the parent FROM clause, if there is one.
+	 */
+	private FromClause parentFromClause;
+	/**
+	 * Collection of FROM clauses of which this is the parent.
+	 */
+	private Set childFromClauses;
+	/**
+	 * Counts the from elements as they are added.
+	 */
+	private int fromElementCounter = 0;
+	/**
+	 * Implied FROM elements to add onto the end of the FROM clause.
+	 */
+	private List impliedElements = new LinkedList();
+
+	/**
+	 * Adds a new from element to the from node.
+	 *
+	 * @param path  The reference to the class.
+	 * @param alias The alias AST.
+	 * @return FromElement - The new FROM element.
+	 */
+	public FromElement addFromElement(String path, AST alias) throws SemanticException {
+		// The path may be a reference to an alias defined in the parent query.
+		String classAlias = ( alias == null ) ? null : alias.getText();
+		checkForDuplicateClassAlias( classAlias );
+		FromElementFactory factory = new FromElementFactory( this, null, path, classAlias, null, false );
+		return factory.addFromElement();
+	}
+
+	void registerFromElement(FromElement element) {
+		fromElements.add( element );
+		String classAlias = element.getClassAlias();
+		if ( classAlias != null ) {
+			// The HQL class alias refers to the class name.
+			fromElementByClassAlias.put( classAlias, element );
+		}
+		// Associate the table alias with the element.
+		String tableAlias = element.getTableAlias();
+		if ( tableAlias != null ) {
+			fromElementByTableAlias.put( tableAlias, element );
+		}
+	}
+
+	void addDuplicateAlias(String alias, FromElement element) {
+		fromElementByClassAlias.put( alias, element );
+	}
+
+	private void checkForDuplicateClassAlias(String classAlias) throws SemanticException {
+		if ( classAlias != null && fromElementByClassAlias.containsKey( classAlias ) ) {
+			throw new SemanticException( "Duplicate definition of alias '"
+					+ classAlias + "'" );
+		}
+	}
+
+	/**
+	 * Retreives the from-element represented by the given alias.
+	 *
+	 * @param aliasOrClassName The alias by which to locate the from-element.
+	 * @return The from-element assigned the given alias, or null if none.
+	 */
+	public FromElement getFromElement(String aliasOrClassName) {
+		FromElement fromElement = ( FromElement ) fromElementByClassAlias.get( aliasOrClassName );
+		if ( fromElement == null && getSessionFactoryHelper().isStrictJPAQLComplianceEnabled() ) {
+			fromElement = findIntendedAliasedFromElementBasedOnCrazyJPARequirements( aliasOrClassName );
+		}
+		if ( fromElement == null && parentFromClause != null ) {
+			fromElement = parentFromClause.getFromElement( aliasOrClassName );
+		}
+		return fromElement;
+	}
+
+	private FromElement findIntendedAliasedFromElementBasedOnCrazyJPARequirements(String specifiedAlias) {
+		Iterator itr = fromElementByClassAlias.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			Map.Entry entry = ( Map.Entry ) itr.next();
+			String alias = ( String ) entry.getKey();
+			if ( alias.equalsIgnoreCase( specifiedAlias ) ) {
+				return ( FromElement ) entry.getValue();
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Convenience method to check whether a given token represents a from-element alias.
+	 *
+	 * @param possibleAlias The potential from-element alias to check.
+	 * @return True if the possibleAlias is an alias to a from-element visible
+	 *         from this point in the query graph.
+	 */
+	public boolean isFromElementAlias(String possibleAlias) {
+		boolean isAlias = containsClassAlias( possibleAlias );
+		if ( !isAlias && parentFromClause != null ) {
+			// try the parent FromClause...
+			isAlias = parentFromClause.isFromElementAlias( possibleAlias );
+		}
+		return isAlias;
+	}
+
+	/**
+	 * Returns the list of from elements in order.
+	 *
+	 * @return the list of from elements (instances of FromElement).
+	 */
+	public List getFromElements() {
+		return ASTUtil.collectChildren( this, fromElementPredicate );
+	}
+	
+	public FromElement getFromElement() {
+		// TODO: not sure about this one
+//		List fromElements = getFromElements();
+//		if ( fromElements == null || fromElements.isEmpty() ) {
+//			throw new QueryException( "Unable to locate from element" );
+//		}
+		return (FromElement) getFromElements().get(0);
+	}
+
+	/**
+	 * Returns the list of from elements that will be part of the result set.
+	 *
+	 * @return the list of from elements that will be part of the result set.
+	 */
+	public List getProjectionList() {
+		return ASTUtil.collectChildren( this, projectionListPredicate );
+	}
+
+	public List getCollectionFetches() {
+		return ASTUtil.collectChildren( this, collectionFetchPredicate );
+	}
+
+	public boolean hasCollectionFecthes() {
+		return getCollectionFetches().size() > 0;
+	}
+
+	public List getExplicitFromElements() {
+		return ASTUtil.collectChildren( this, explicitFromPredicate );
+	}
+
+	private static ASTUtil.FilterPredicate fromElementPredicate = new ASTUtil.IncludePredicate() {
+		public boolean include(AST node) {
+			FromElement fromElement = ( FromElement ) node;
+			return fromElement.isFromOrJoinFragment();
+		}
+	};
+
+	private static ASTUtil.FilterPredicate projectionListPredicate = new ASTUtil.IncludePredicate() {
+		public boolean include(AST node) {
+			FromElement fromElement = ( FromElement ) node;
+			return fromElement.inProjectionList();
+		}
+	};
+
+	private static ASTUtil.FilterPredicate collectionFetchPredicate = new ASTUtil.IncludePredicate() {
+		public boolean include(AST node) {
+			FromElement fromElement = ( FromElement ) node;
+			return fromElement.isFetch() && fromElement.getQueryableCollection() != null;
+		}
+	};
+
+	private static ASTUtil.FilterPredicate explicitFromPredicate = new ASTUtil.IncludePredicate() {
+		public boolean include(AST node) {
+			final FromElement fromElement = ( FromElement ) node;
+			return !fromElement.isImplied();
+		}
+	};
+
+	FromElement findCollectionJoin(String path) {
+		return ( FromElement ) collectionJoinFromElementsByPath.get( path );
+	}
+
+	/**
+	 * Look for an existing implicit or explicit join by the
+	 * given path.
+	 */
+	FromElement findJoinByPath(String path) {
+		FromElement elem = findJoinByPathLocal( path );
+		if ( elem == null && parentFromClause != null ) {
+			elem = parentFromClause.findJoinByPath( path );
+		}
+		return elem;
+	}
+
+	FromElement findJoinByPathLocal(String path) {
+		Map joinsByPath = fromElementsByPath;
+		return ( FromElement ) joinsByPath.get( path );
+	}
+
+	void addJoinByPathMap(String path, FromElement destination) {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "addJoinByPathMap() : " + path + " -> " + destination );
+		}
+		fromElementsByPath.put( path, destination );
+	}
+
+	/**
+	 * Returns true if the from node contains the class alias name.
+	 *
+	 * @param alias The HQL class alias name.
+	 * @return true if the from node contains the class alias name.
+	 */
+	public boolean containsClassAlias(String alias) {
+		boolean isAlias = fromElementByClassAlias.containsKey( alias );
+		if ( !isAlias && getSessionFactoryHelper().isStrictJPAQLComplianceEnabled() ) {
+			isAlias = findIntendedAliasedFromElementBasedOnCrazyJPARequirements( alias ) != null;
+		}
+		return isAlias;
+	}
+
+	/**
+	 * Returns true if the from node contains the table alias name.
+	 *
+	 * @param alias The SQL table alias name.
+	 * @return true if the from node contains the table alias name.
+	 */
+	public boolean containsTableAlias(String alias) {
+		return fromElementByTableAlias.keySet().contains( alias );
+	}
+
+	public String getDisplayText() {
+		return "FromClause{" +
+				"level=" + level +
+				", fromElementCounter=" + fromElementCounter +
+				", fromElements=" + fromElements.size() +
+				", fromElementByClassAlias=" + fromElementByClassAlias.keySet() +
+				", fromElementByTableAlias=" + fromElementByTableAlias.keySet() +
+				", fromElementsByPath=" + fromElementsByPath.keySet() +
+				", collectionJoinFromElementsByPath=" + collectionJoinFromElementsByPath.keySet() +
+				", impliedElements=" + impliedElements +
+				"}";
+	}
+
+	public void setParentFromClause(FromClause parentFromClause) {
+		this.parentFromClause = parentFromClause;
+		if ( parentFromClause != null ) {
+			level = parentFromClause.getLevel() + 1;
+			parentFromClause.addChild( this );
+		}
+	}
+
+	private void addChild(FromClause fromClause) {
+		if ( childFromClauses == null ) {
+			childFromClauses = new HashSet();
+		}
+		childFromClauses.add( fromClause );
+	}
+
+	public FromClause locateChildFromClauseWithJoinByPath(String path) {
+		if ( childFromClauses != null && !childFromClauses.isEmpty() ) {
+			Iterator children = childFromClauses.iterator();
+			while ( children.hasNext() ) {
+				FromClause child = ( FromClause ) children.next();
+				if ( child.findJoinByPathLocal( path ) != null ) {
+					return child;
+				}
+			}
+		}
+		return null;
+	}
+
+	public void promoteJoin(FromElement elem) {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Promoting [" + elem + "] to [" + this + "]" );
+		}
+		//TODO: implement functionality
+		//  this might be painful to do here, as the "join post processing" for
+		//  the subquery has already been performed (meaning that for
+		//  theta-join dialects, the join conditions have already been moved
+		//  over to the where clause).  A "simple" solution here might to
+		//  perform "join post processing" once for the entire query (including
+		//  any subqueries) at one fell swoop
+	}
+
+	public boolean isSubQuery() {
+		// TODO : this is broke for subqueries in statements other than selects...
+		return parentFromClause != null;
+	}
+
+	void addCollectionJoinFromElementByPath(String path, FromElement destination) {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "addCollectionJoinFromElementByPath() : " + path + " -> " + destination );
+		}
+		collectionJoinFromElementsByPath.put( path, destination );	// Add the new node to the map so that we don't create it twice.
+	}
+
+	public FromClause getParentFromClause() {
+		return parentFromClause;
+	}
+
+	public int getLevel() {
+		return level;
+	}
+
+	public int nextFromElementCounter() {
+		return fromElementCounter++;
+	}
+
+	public void resolve() {
+		// Make sure that all from elements registered with this FROM clause are actually in the AST.
+		ASTIterator iter = new ASTIterator( this.getFirstChild() );
+		Set childrenInTree = new HashSet();
+		while ( iter.hasNext() ) {
+			childrenInTree.add( iter.next() );
+		}
+		for ( Iterator iterator = fromElements.iterator(); iterator.hasNext(); ) {
+			FromElement fromElement = ( FromElement ) iterator.next();
+			if ( !childrenInTree.contains( fromElement ) ) {
+				throw new IllegalStateException( "Element not in AST: " + fromElement );
+			}
+		}
+	}
+
+	public void addImpliedFromElement(FromElement element) {
+		impliedElements.add( element );
+	}
+
+	public String toString() {
+		return "FromClause{" +
+				"level=" + level +
+				"}";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromElement.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromElement.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromElement.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,551 @@
+// $Id: FromElement.java 10852 2006-11-21 17:39:14Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.tree;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.hibernate.QueryException;
+import org.hibernate.engine.JoinSequence;
+import org.hibernate.hql.QueryTranslator;
+import org.hibernate.hql.CollectionProperties;
+import org.hibernate.hql.antlr.SqlTokenTypes;
+import org.hibernate.hql.ast.util.ASTUtil;
+import org.hibernate.hql.ast.HqlSqlWalker;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.PropertyMapping;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.util.StringHelper;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Represents a single mapped class mentioned in an HQL FROM clause.  Each
+ * class reference will have the following symbols:
+ * <ul>
+ * <li>A class name - This is the name of the Java class that is mapped by Hibernate.</li>
+ * <li>[optional] an HQL alias for the mapped class.</li>
+ * <li>A table name - The name of the table that is mapped to the Java class.</li>
+ * <li>A table alias - The alias for the table that will be used in the resulting SQL.</li>
+ * </ul>
+ * <br>
+ * User: josh<br>
+ * Date: Dec 6, 2003<br>
+ * Time: 10:28:17 AM<br>
+ */
+public class FromElement extends HqlSqlWalkerNode implements DisplayableNode {
+	private static final Log log = LogFactory.getLog( FromElement.class );
+
+	private String className;
+	private String classAlias;
+	private String tableAlias;
+	private String collectionTableAlias;
+	private FromClause fromClause;
+	private boolean includeSubclasses = true;
+	private boolean collectionJoin = false;
+	private FromElement origin;
+	private String[] columns;
+	private String role;
+	private boolean fetch;
+	private boolean isAllPropertyFetch;
+	private boolean filter = false;
+	private int sequence = -1;
+	private boolean useFromFragment = false;
+	private boolean initialized = false;
+	private FromElementType elementType;
+	private boolean useWhereFragment = true;
+	private List destinations = new LinkedList();
+	private boolean manyToMany = false;
+	private String withClauseFragment = null;
+	private String withClauseJoinAlias;
+	private boolean dereferencedBySuperclassProperty;
+	private boolean dereferencedBySubclassProperty;
+
+	public FromElement() {
+	}
+
+	public String getCollectionSuffix() {
+		return elementType.getCollectionSuffix();
+	}
+
+	public void setCollectionSuffix(String suffix) {
+		elementType.setCollectionSuffix(suffix);
+	}
+
+	public void initializeCollection(FromClause fromClause, String classAlias, String tableAlias) {
+		doInitialize( fromClause, tableAlias, null, classAlias, null, null );
+		initialized = true;
+	}
+
+	public void initializeEntity(
+	        FromClause fromClause,
+	        String className,
+	        EntityPersister persister,
+	        EntityType type,
+	        String classAlias,
+	        String tableAlias) {
+		doInitialize( fromClause, tableAlias, className, classAlias, persister, type );
+		this.sequence = fromClause.nextFromElementCounter();
+		initialized = true;
+	}
+
+	private void doInitialize(FromClause fromClause, String tableAlias, String className, String classAlias,
+							  EntityPersister persister, EntityType type) {
+		if ( initialized ) {
+			throw new IllegalStateException( "Already initialized!!" );
+		}
+		this.fromClause = fromClause;
+		this.tableAlias = tableAlias;
+		this.className = className;
+		this.classAlias = classAlias;
+		this.elementType = new FromElementType( this, persister, type );
+		// Register the FromElement with the FROM clause, now that we have the names and aliases.
+		fromClause.registerFromElement( this );
+		if ( log.isDebugEnabled() ) {
+			log.debug( fromClause + " :  " + className + " ("
+					+ ( classAlias == null ? "no alias" : classAlias ) + ") -> " + tableAlias );
+		}
+	}
+
+	public EntityPersister getEntityPersister() {
+		return elementType.getEntityPersister();
+	}
+
+	public Type getDataType() {
+		return elementType.getDataType();
+	}
+
+	public Type getSelectType() {
+		return elementType.getSelectType();
+	}
+
+	public Queryable getQueryable() {
+		return elementType.getQueryable();
+	}
+
+	public String getClassName() {
+		return className;
+	}
+
+	public String getClassAlias() {
+		return classAlias;
+		//return classAlias == null ? className : classAlias;
+	}
+
+	private String getTableName() {
+		Queryable queryable = getQueryable();
+		return ( queryable != null ) ? queryable.getTableName() : "{none}";
+	}
+
+	public String getTableAlias() {
+		return tableAlias;
+	}
+
+	/**
+	 * Render the identifier select, but in a 'scalar' context (i.e. generate the column alias).
+	 *
+	 * @param i the sequence of the returned type
+	 * @return the identifier select with the column alias.
+	 */
+	String renderScalarIdentifierSelect(int i) {
+		return elementType.renderScalarIdentifierSelect( i );
+	}
+
+	void checkInitialized() {
+		if ( !initialized ) {
+			throw new IllegalStateException( "FromElement has not been initialized!" );
+		}
+	}
+
+	/**
+	 * Returns the identifier select SQL fragment.
+	 *
+	 * @param size The total number of returned types.
+	 * @param k    The sequence of the current returned type.
+	 * @return the identifier select SQL fragment.
+	 */
+	String renderIdentifierSelect(int size, int k) {
+		return elementType.renderIdentifierSelect( size, k );
+	}
+
+	/**
+	 * Returns the property select SQL fragment.
+	 *
+	 * @param size The total number of returned types.
+	 * @param k    The sequence of the current returned type.
+	 * @return the property select SQL fragment.
+	 */
+	String renderPropertySelect(int size, int k) {
+		return elementType.renderPropertySelect( size, k, isAllPropertyFetch );
+	}
+
+	String renderCollectionSelectFragment(int size, int k) {
+		return elementType.renderCollectionSelectFragment( size, k );
+	}
+
+	String renderValueCollectionSelectFragment(int size, int k) {
+		return elementType.renderValueCollectionSelectFragment( size, k );
+	}
+
+	public FromClause getFromClause() {
+		return fromClause;
+	}
+
+	/**
+	 * Returns true if this FromElement was implied by a path, or false if this FROM element is explicitly declared in
+	 * the FROM clause.
+	 *
+	 * @return true if this FromElement was implied by a path, or false if this FROM element is explicitly declared
+	 */
+	public boolean isImplied() {
+		return false;	// This is an explicit FROM element.
+	}
+
+	/**
+	 * Returns additional display text for the AST node.
+	 *
+	 * @return String - The additional display text.
+	 */
+	public String getDisplayText() {
+		StringBuffer buf = new StringBuffer();
+		buf.append( "FromElement{" );
+		appendDisplayText( buf );
+		buf.append( "}" );
+		return buf.toString();
+	}
+
+	protected void appendDisplayText(StringBuffer buf) {
+		buf.append( isImplied() ? (
+				isImpliedInFromClause() ? "implied in FROM clause" : "implied" )
+				: "explicit" );
+		buf.append( "," ).append( isCollectionJoin() ? "collection join" : "not a collection join" );
+		buf.append( "," ).append( fetch ? "fetch join" : "not a fetch join" );
+		buf.append( "," ).append( isAllPropertyFetch ? "fetch all properties" : "fetch non-lazy properties" );
+		buf.append( ",classAlias=" ).append( getClassAlias() );
+		buf.append( ",role=" ).append( role );
+		buf.append( ",tableName=" ).append( getTableName() );
+		buf.append( ",tableAlias=" ).append( getTableAlias() );
+		FromElement origin = getRealOrigin();
+		buf.append( ",origin=" ).append( origin == null ? "null" : origin.getText() );
+		buf.append( ",colums={" );
+		if ( columns != null ) {
+			for ( int i = 0; i < columns.length; i++ ) {
+				buf.append( columns[i] );
+				if ( i < columns.length ) {
+					buf.append( " " );
+				}
+			}
+		}
+		buf.append( ",className=" ).append( className );
+		buf.append( "}" );
+	}
+
+	public int hashCode() {
+		return super.hashCode();
+	}
+
+	public boolean equals(Object obj) {
+		return super.equals( obj );
+	}
+
+
+	public void setJoinSequence(JoinSequence joinSequence) {
+		elementType.setJoinSequence( joinSequence );
+	}
+
+	public JoinSequence getJoinSequence() {
+		return elementType.getJoinSequence();
+	}
+
+	public void setIncludeSubclasses(boolean includeSubclasses) {
+		if ( isDereferencedBySuperclassOrSubclassProperty() ) {
+			if ( !includeSubclasses && log.isTraceEnabled() ) {
+				log.trace( "attempt to disable subclass-inclusions", new Exception( "stack-trace source" ) );
+			}
+		}
+		this.includeSubclasses = includeSubclasses;
+	}
+
+	public boolean isIncludeSubclasses() {
+		return includeSubclasses;
+	}
+
+	public boolean isDereferencedBySuperclassOrSubclassProperty() {
+		return dereferencedBySubclassProperty || dereferencedBySuperclassProperty;
+	}
+
+	public String getIdentityColumn() {
+		checkInitialized();
+		String table = getTableAlias();
+		if ( table == null ) {
+			throw new IllegalStateException( "No table alias for node " + this );
+		}
+		String[] cols;
+		String propertyName;
+		if ( getEntityPersister() != null && getEntityPersister().getEntityMetamodel() != null
+				&& getEntityPersister().getEntityMetamodel().hasNonIdentifierPropertyNamedId() ) {
+			propertyName = getEntityPersister().getIdentifierPropertyName();
+		}
+		else {
+			propertyName = EntityPersister.ENTITY_ID;
+		}
+		if ( getWalker().getStatementType() == HqlSqlWalker.SELECT ) {
+			cols = getPropertyMapping( propertyName ).toColumns( table, propertyName );
+		}
+		else {
+			cols = getPropertyMapping( propertyName ).toColumns( propertyName );
+		}
+		String result = StringHelper.join( ", ", cols );
+		return  cols.length == 1 ? result : "(" + result + ")";
+	}
+
+	public void setCollectionJoin(boolean collectionJoin) {
+		this.collectionJoin = collectionJoin;
+	}
+
+	public boolean isCollectionJoin() {
+		return collectionJoin;
+	}
+
+	public void setRole(String role) {
+		this.role = role;
+	}
+
+	public void setQueryableCollection(QueryableCollection queryableCollection) {
+		elementType.setQueryableCollection( queryableCollection );
+	}
+
+	public QueryableCollection getQueryableCollection() {
+		return elementType.getQueryableCollection();
+	}
+
+	public void setColumns(String[] columns) {
+		this.columns = columns;
+	}
+
+	public void setOrigin(FromElement origin, boolean manyToMany) {
+		this.origin = origin;
+		this.manyToMany = manyToMany;
+		origin.addDestination( this );
+		if ( origin.getFromClause() == this.getFromClause() ) {
+			// TODO: Figure out a better way to get the FROM elements in a proper tree structure.
+			// If this is not the destination of a many-to-many, add it as a child of the origin.
+			if ( manyToMany ) {
+				ASTUtil.appendSibling( origin, this );
+			}
+			else {
+				if ( !getWalker().isInFrom() && !getWalker().isInSelect() ) {
+					getFromClause().addChild( this );
+				}
+				else {
+					origin.addChild( this );
+				}
+			}
+		}
+		else if ( !getWalker().isInFrom() ) {
+			// HHH-276 : implied joins in a subselect where clause - The destination needs to be added
+			// to the destination's from clause.
+			getFromClause().addChild( this );	// Not sure if this is will fix everything, but it works.
+		}
+		else {
+			// Otherwise, the destination node was implied by the FROM clause and the FROM clause processor
+			// will automatically add it in the right place.
+		}
+	}
+
+	public boolean isManyToMany() {
+		return manyToMany;
+	}
+
+	private void addDestination(FromElement fromElement) {
+		destinations.add( fromElement );
+	}
+
+	public List getDestinations() {
+		return destinations;
+	}
+
+	public FromElement getOrigin() {
+		return origin;
+	}
+
+	public FromElement getRealOrigin() {
+		if ( origin == null ) {
+			return null;
+		}
+		if ( origin.getText() == null || "".equals( origin.getText() ) ) {
+			return origin.getRealOrigin();
+		}
+		return origin;
+	}
+
+	public Type getPropertyType(String propertyName, String propertyPath) {
+		return elementType.getPropertyType( propertyName, propertyPath );
+	}
+
+	public String[] toColumns(String tableAlias, String path, boolean inSelect) {
+		return elementType.toColumns( tableAlias, path, inSelect );
+	}
+
+	public String[] toColumns(String tableAlias, String path, boolean inSelect, boolean forceAlias) {
+		return elementType.toColumns( tableAlias, path, inSelect, forceAlias );
+	}
+
+	public PropertyMapping getPropertyMapping(String propertyName) {
+		return elementType.getPropertyMapping( propertyName );
+	}
+
+	public void setFetch(boolean fetch) {
+		this.fetch = fetch;
+		// Fetch can't be used with scroll() or iterate().
+		if ( fetch && getWalker().isShallowQuery() ) {
+			throw new QueryException( QueryTranslator.ERROR_CANNOT_FETCH_WITH_ITERATE );
+		}
+	}
+
+	public boolean isFetch() {
+		return fetch;
+	}
+
+	public int getSequence() {
+		return sequence;
+	}
+
+	public void setFilter(boolean b) {
+		filter = b;
+	}
+
+	public boolean isFilter() {
+		return filter;
+	}
+
+	public boolean useFromFragment() {
+		checkInitialized();
+		// If it's not implied or it is implied and it's a many to many join where the target wasn't found.
+		return !isImplied() || this.useFromFragment;
+	}
+
+	public void setUseFromFragment(boolean useFromFragment) {
+		this.useFromFragment = useFromFragment;
+	}
+
+	public boolean useWhereFragment() {
+		return useWhereFragment;
+	}
+
+	public void setUseWhereFragment(boolean b) {
+		useWhereFragment = b;
+	}
+
+
+	public void setCollectionTableAlias(String collectionTableAlias) {
+		this.collectionTableAlias = collectionTableAlias;
+	}
+
+	public String getCollectionTableAlias() {
+		return collectionTableAlias;
+	}
+
+	public boolean isCollectionOfValuesOrComponents() {
+		return elementType.isCollectionOfValuesOrComponents();
+	}
+
+	public boolean isEntity() {
+		return elementType.isEntity();
+	}
+
+	public void setImpliedInFromClause(boolean flag) {
+		throw new UnsupportedOperationException( "Explicit FROM elements can't be implied in the FROM clause!" );
+	}
+
+	public boolean isImpliedInFromClause() {
+		return false;	// Since this is an explicit FROM element, it can't be implied in the FROM clause.
+	}
+
+	public void setInProjectionList(boolean inProjectionList) {
+		// Do nothing, eplicit from elements are *always* in the projection list.
+	}
+
+	public boolean inProjectionList() {
+		return !isImplied() && isFromOrJoinFragment();
+	}
+
+	public boolean isFromOrJoinFragment() {
+		return getType() == SqlTokenTypes.FROM_FRAGMENT || getType() == SqlTokenTypes.JOIN_FRAGMENT;
+	}
+
+	public boolean isAllPropertyFetch() {
+		return isAllPropertyFetch;
+	}
+
+	public void setAllPropertyFetch(boolean fetch) {
+		isAllPropertyFetch = fetch;
+	}
+
+	public String getWithClauseFragment() {
+		return withClauseFragment;
+	}
+
+	public String getWithClauseJoinAlias() {
+		return withClauseJoinAlias;
+	}
+
+	public void setWithClauseFragment(String withClauseJoinAlias, String withClauseFragment) {
+		this.withClauseJoinAlias = withClauseJoinAlias;
+		this.withClauseFragment = withClauseFragment;
+	}
+
+	public boolean hasCacheablePersister() {
+		if ( getQueryableCollection() != null ) {
+			return getQueryableCollection().hasCache();
+		}
+		else {
+			return getQueryable().hasCache();
+		}
+	}
+
+	public void handlePropertyBeingDereferenced(Type propertySource, String propertyName) {
+		if ( getQueryableCollection() != null && CollectionProperties.isCollectionProperty( propertyName ) ) {
+			// propertyName refers to something like collection.size...
+			return;
+		}
+		if ( propertySource.isComponentType() ) {
+			// property name is a sub-path of a component...
+			return;
+		}
+
+		Queryable persister = getQueryable();
+		if ( persister != null ) {
+			try {
+				Queryable.Declarer propertyDeclarer = persister.getSubclassPropertyDeclarer( propertyName );
+				if ( log.isTraceEnabled() ) {
+					log.trace( "handling property dereference [" + persister.getEntityName() + " (" + getClassAlias() + ") -> " + propertyName + " (" + propertyDeclarer + ")]" );
+				}
+				if ( propertyDeclarer == Queryable.Declarer.SUBCLASS ) {
+					dereferencedBySubclassProperty = true;
+					includeSubclasses = true;
+				}
+				else if ( propertyDeclarer == Queryable.Declarer.SUPERCLASS ) {
+					dereferencedBySuperclassProperty = true;
+				}
+			}
+			catch( QueryException ignore ) {
+				// ignore it; the incoming property could not be found so we
+				// cannot be sure what to do here.  At the very least, the
+				// safest is to simply not apply any dereference toggling...
+
+			}
+		}
+	}
+
+	public boolean isDereferencedBySuperclassProperty() {
+		return dereferencedBySuperclassProperty;
+	}
+
+	public boolean isDereferencedBySubclassProperty() {
+		return dereferencedBySubclassProperty;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromElementFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromElementFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromElementFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,500 @@
+// $Id: FromElementFactory.java 9586 2006-03-09 21:11:44Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.engine.JoinSequence;
+import org.hibernate.hql.antlr.SqlTokenTypes;
+import org.hibernate.hql.ast.util.ASTUtil;
+import org.hibernate.hql.ast.util.AliasGenerator;
+import org.hibernate.hql.ast.util.PathHelper;
+import org.hibernate.hql.ast.util.SessionFactoryHelper;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.util.StringHelper;
+
+import antlr.ASTFactory;
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Encapsulates the creation of FromElements and JoinSequences.
+ *
+ * @author josh Oct 12, 2004 4:54:25 AM
+ */
+class FromElementFactory implements SqlTokenTypes {
+
+	private static final Log log = LogFactory.getLog( FromElementFactory.class );
+
+	private FromClause fromClause;
+	private FromElement origin;
+	private String path;
+
+	private String classAlias;
+	private String[] columns;
+	private boolean implied;
+	private boolean inElementsFunction;
+	private boolean collection;
+	private QueryableCollection queryableCollection;
+	private CollectionType collectionType;
+
+	/**
+	 * Creates entity from elements.
+	 */
+	public FromElementFactory(FromClause fromClause, FromElement origin, String path) {
+		this.fromClause = fromClause;
+		this.origin = origin;
+		this.path = path;
+		collection = false;
+	}
+
+	/**
+	 * Creates collection from elements.
+	 */
+	public FromElementFactory(
+	        FromClause fromClause,
+	        FromElement origin,
+	        String path,
+	        String classAlias,
+	        String[] columns,
+	        boolean implied) {
+		this( fromClause, origin, path );
+		this.classAlias = classAlias;
+		this.columns = columns;
+		this.implied = implied;
+		collection = true;
+	}
+
+	FromElement addFromElement() throws SemanticException {
+		FromClause parentFromClause = fromClause.getParentFromClause();
+		if ( parentFromClause != null ) {
+			// Look up class name using the first identifier in the path.
+			String pathAlias = PathHelper.getAlias( path );
+			FromElement parentFromElement = parentFromClause.getFromElement( pathAlias );
+			if ( parentFromElement != null ) {
+				return createFromElementInSubselect( path, pathAlias, parentFromElement, classAlias );
+			}
+		}
+
+		EntityPersister entityPersister = fromClause.getSessionFactoryHelper().requireClassPersister( path );
+
+		FromElement elem = createAndAddFromElement( path,
+				classAlias,
+				entityPersister,
+				( EntityType ) ( ( Queryable ) entityPersister ).getType(),
+				null );
+
+		// Add to the query spaces.
+		fromClause.getWalker().addQuerySpaces( entityPersister.getQuerySpaces() );
+
+		return elem;
+	}
+
+	private FromElement createFromElementInSubselect(
+	        String path,
+	        String pathAlias,
+	        FromElement parentFromElement,
+	        String classAlias) throws SemanticException {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "createFromElementInSubselect() : path = " + path );
+		}
+		// Create an DotNode AST for the path and resolve it.
+		FromElement fromElement = evaluateFromElementPath( path, classAlias );
+		EntityPersister entityPersister = fromElement.getEntityPersister();
+
+		// If the first identifier in the path referrs to the class alias (not the class name), then this
+		// is a correlated subselect.  If it's a correlated sub-select, use the existing table alias.  Otherwise
+		// generate a new one.
+		String tableAlias = null;
+		boolean correlatedSubselect = pathAlias.equals( parentFromElement.getClassAlias() );
+		if ( correlatedSubselect ) {
+			tableAlias = fromElement.getTableAlias();
+		}
+		else {
+			tableAlias = null;
+		}
+
+		// If the from element isn't in the same clause, create a new from element.
+		if ( fromElement.getFromClause() != fromClause ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "createFromElementInSubselect() : creating a new FROM element..." );
+			}
+			fromElement = createFromElement( entityPersister );
+			initializeAndAddFromElement( fromElement,
+					path,
+					classAlias,
+					entityPersister,
+					( EntityType ) ( ( Queryable ) entityPersister ).getType(),
+					tableAlias
+			);
+		}
+		if ( log.isDebugEnabled() ) {
+			log.debug( "createFromElementInSubselect() : " + path + " -> " + fromElement );
+		}
+		return fromElement;
+	}
+
+	private FromElement evaluateFromElementPath(String path, String classAlias) throws SemanticException {
+		ASTFactory factory = fromClause.getASTFactory();
+		FromReferenceNode pathNode = ( FromReferenceNode ) PathHelper.parsePath( path, factory );
+		pathNode.recursiveResolve( FromReferenceNode.ROOT_LEVEL, // This is the root level node.
+				false, // Generate an explicit from clause at the root.
+				classAlias,
+		        null
+		);
+		if ( pathNode.getImpliedJoin() != null ) {
+			return pathNode.getImpliedJoin();
+		}
+		else {
+			return pathNode.getFromElement();
+		}
+	}
+
+	FromElement createCollectionElementsJoin(
+	        QueryableCollection queryableCollection,
+	        String collectionName) throws SemanticException {
+		JoinSequence collectionJoinSequence = fromClause.getSessionFactoryHelper()
+		        .createCollectionJoinSequence( queryableCollection, collectionName );
+		this.queryableCollection = queryableCollection;
+		return createCollectionJoin( collectionJoinSequence, null );
+	}
+
+	FromElement createCollection(
+	        QueryableCollection queryableCollection,
+	        String role,
+	        int joinType,
+	        boolean fetchFlag,
+	        boolean indexed)
+			throws SemanticException {
+		if ( !collection ) {
+			throw new IllegalStateException( "FromElementFactory not initialized for collections!" );
+		}
+		this.inElementsFunction = indexed;
+		FromElement elem;
+		this.queryableCollection = queryableCollection;
+		collectionType = queryableCollection.getCollectionType();
+		String roleAlias = fromClause.getAliasGenerator().createName( role );
+
+		// Correlated subqueries create 'special' implied from nodes
+		// because correlated subselects can't use an ANSI-style join
+		boolean explicitSubqueryFromElement = fromClause.isSubQuery() && !implied;
+		if ( explicitSubqueryFromElement ) {
+			String pathRoot = StringHelper.root( path );
+			FromElement origin = fromClause.getFromElement( pathRoot );
+			if ( origin == null || origin.getFromClause() != fromClause ) {
+				implied = true;
+			}
+		}
+
+		// super-duper-classic-parser-regression-testing-mojo-magic...
+		if ( explicitSubqueryFromElement && DotNode.useThetaStyleImplicitJoins ) {
+			implied = true;
+		}
+
+		Type elementType = queryableCollection.getElementType();
+		if ( elementType.isEntityType() ) { 			// A collection of entities...
+			elem = createEntityAssociation( role, roleAlias, joinType );
+		}
+		else if ( elementType.isComponentType() ) {		// A collection of components...
+			JoinSequence joinSequence = createJoinSequence( roleAlias, joinType );
+			elem = createCollectionJoin( joinSequence, roleAlias );
+		}
+		else {											// A collection of scalar elements...
+			JoinSequence joinSequence = createJoinSequence( roleAlias, joinType );
+			elem = createCollectionJoin( joinSequence, roleAlias );
+		}
+
+		elem.setRole( role );
+		elem.setQueryableCollection( queryableCollection );
+		// Don't include sub-classes for implied collection joins or subquery joins.
+		if ( implied ) {
+			elem.setIncludeSubclasses( false );
+		}
+
+		if ( explicitSubqueryFromElement ) {
+			elem.setInProjectionList( true );	// Treat explict from elements in sub-queries properly.
+		}
+
+		if ( fetchFlag ) {
+			elem.setFetch( true );
+		}
+		return elem;
+	}
+
+	FromElement createEntityJoin(
+	        String entityClass,
+	        String tableAlias,
+	        JoinSequence joinSequence,
+	        boolean fetchFlag,
+	        boolean inFrom,
+	        EntityType type) throws SemanticException {
+		FromElement elem = createJoin( entityClass, tableAlias, joinSequence, type, false );
+		elem.setFetch( fetchFlag );
+		EntityPersister entityPersister = elem.getEntityPersister();
+		int numberOfTables = entityPersister.getQuerySpaces().length;
+		if ( numberOfTables > 1 && implied && !elem.useFromFragment() ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "createEntityJoin() : Implied multi-table entity join" );
+			}
+			elem.setUseFromFragment( true );
+		}
+
+		// If this is an implied join in a FROM clause, then use ANSI-style joining, and set the
+		// flag on the FromElement that indicates that it was implied in the FROM clause itself.
+		if ( implied && inFrom ) {
+			joinSequence.setUseThetaStyle( false );
+			elem.setUseFromFragment( true );
+			elem.setImpliedInFromClause( true );
+		}
+		if ( elem.getWalker().isSubQuery() ) {
+			// two conditions where we need to transform this to a theta-join syntax:
+			//      1) 'elem' is the "root from-element" in correlated subqueries
+			//      2) The DotNode.useThetaStyleImplicitJoins has been set to true
+			//          and 'elem' represents an implicit join
+			if ( elem.getFromClause() != elem.getOrigin().getFromClause() ||
+//			        ( implied && DotNode.useThetaStyleImplicitJoins ) ) {
+			        DotNode.useThetaStyleImplicitJoins ) {
+				// the "root from-element" in correlated subqueries do need this piece
+				elem.setType( FROM_FRAGMENT );
+				joinSequence.setUseThetaStyle( true );
+				elem.setUseFromFragment( false );
+			}
+		}
+
+		return elem;
+	}
+
+	FromElement createElementJoin(QueryableCollection queryableCollection) throws SemanticException {
+		FromElement elem;
+
+		implied = true; //TODO: always true for now, but not if we later decide to support elements() in the from clause
+		inElementsFunction = true;
+		Type elementType = queryableCollection.getElementType();
+		if ( !elementType.isEntityType() ) {
+			throw new IllegalArgumentException( "Cannot create element join for a collection of non-entities!" );
+		}
+		this.queryableCollection = queryableCollection;
+		SessionFactoryHelper sfh = fromClause.getSessionFactoryHelper();
+		FromElement destination = null;
+		String tableAlias = null;
+		EntityPersister entityPersister = queryableCollection.getElementPersister();
+		tableAlias = fromClause.getAliasGenerator().createName( entityPersister.getEntityName() );
+		String associatedEntityName = entityPersister.getEntityName();
+		EntityPersister targetEntityPersister = sfh.requireClassPersister( associatedEntityName );
+		// Create the FROM element for the target (the elements of the collection).
+		destination = createAndAddFromElement( 
+				associatedEntityName,
+				classAlias,
+				targetEntityPersister,
+				( EntityType ) queryableCollection.getElementType(),
+				tableAlias
+			);
+		// If the join is implied, then don't include sub-classes on the element.
+		if ( implied ) {
+			destination.setIncludeSubclasses( false );
+		}
+		fromClause.addCollectionJoinFromElementByPath( path, destination );
+//		origin.addDestination(destination);
+		// Add the query spaces.
+		fromClause.getWalker().addQuerySpaces( entityPersister.getQuerySpaces() );
+
+		CollectionType type = queryableCollection.getCollectionType();
+		String role = type.getRole();
+		String roleAlias = origin.getTableAlias();
+
+		String[] targetColumns = sfh.getCollectionElementColumns( role, roleAlias );
+		AssociationType elementAssociationType = sfh.getElementAssociationType( type );
+
+		// Create the join element under the from element.
+		int joinType = JoinFragment.INNER_JOIN;
+		JoinSequence joinSequence = sfh.createJoinSequence( implied, elementAssociationType, tableAlias, joinType, targetColumns );
+		elem = initializeJoin( path, destination, joinSequence, targetColumns, origin, false );
+		elem.setUseFromFragment( true );	// The associated entity is implied, but it must be included in the FROM.
+		elem.setCollectionTableAlias( roleAlias );	// The collection alias is the role.
+		return elem;
+	}
+
+	private FromElement createCollectionJoin(JoinSequence collectionJoinSequence, String tableAlias) throws SemanticException {
+		String text = queryableCollection.getTableName();
+		AST ast = createFromElement( text );
+		FromElement destination = ( FromElement ) ast;
+		Type elementType = queryableCollection.getElementType();
+		if ( elementType.isCollectionType() ) {
+			throw new SemanticException( "Collections of collections are not supported!" );
+		}
+		destination.initializeCollection( fromClause, classAlias, tableAlias );
+		destination.setType( JOIN_FRAGMENT );		// Tag this node as a JOIN.
+		destination.setIncludeSubclasses( false );	// Don't include subclasses in the join.
+		destination.setCollectionJoin( true );		// This is a clollection join.
+		destination.setJoinSequence( collectionJoinSequence );
+		destination.setOrigin( origin, false );
+		destination.setCollectionTableAlias(tableAlias);
+//		origin.addDestination( destination );
+// This was the cause of HHH-242
+//		origin.setType( FROM_FRAGMENT );			// Set the parent node type so that the AST is properly formed.
+		origin.setText( "" );						// The destination node will have all the FROM text.
+		origin.setCollectionJoin( true );			// The parent node is a collection join too (voodoo - see JoinProcessor)
+		fromClause.addCollectionJoinFromElementByPath( path, destination );
+		fromClause.getWalker().addQuerySpaces( queryableCollection.getCollectionSpaces() );
+		return destination;
+	}
+
+	private FromElement createEntityAssociation(
+	        String role,
+	        String roleAlias,
+	        int joinType) throws SemanticException {
+		FromElement elem;
+		Queryable entityPersister = ( Queryable ) queryableCollection.getElementPersister();
+		String associatedEntityName = entityPersister.getEntityName();
+		// Get the class name of the associated entity.
+		if ( queryableCollection.isOneToMany() ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "createEntityAssociation() : One to many - path = " + path + " role = " + role + " associatedEntityName = " + associatedEntityName );
+			}
+			JoinSequence joinSequence = createJoinSequence( roleAlias, joinType );
+
+			elem = createJoin( associatedEntityName, roleAlias, joinSequence, ( EntityType ) queryableCollection.getElementType(), false );
+		}
+		else {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "createManyToMany() : path = " + path + " role = " + role + " associatedEntityName = " + associatedEntityName );
+			}
+			elem = createManyToMany( role, associatedEntityName,
+					roleAlias, entityPersister, ( EntityType ) queryableCollection.getElementType(), joinType );
+			fromClause.getWalker().addQuerySpaces( queryableCollection.getCollectionSpaces() );
+		}
+		elem.setCollectionTableAlias( roleAlias );
+		return elem;
+	}
+
+	private FromElement createJoin(
+	        String entityClass,
+	        String tableAlias,
+	        JoinSequence joinSequence,
+	        EntityType type,
+	        boolean manyToMany) throws SemanticException {
+		//  origin, path, implied, columns, classAlias,
+		EntityPersister entityPersister = fromClause.getSessionFactoryHelper().requireClassPersister( entityClass );
+		FromElement destination = createAndAddFromElement( entityClass,
+				classAlias,
+				entityPersister,
+				type,
+				tableAlias );
+		return initializeJoin( path, destination, joinSequence, getColumns(), origin, manyToMany );
+	}
+
+	private FromElement createManyToMany(
+	        String role,
+	        String associatedEntityName,
+	        String roleAlias,
+	        Queryable entityPersister,
+	        EntityType type,
+	        int joinType) throws SemanticException {
+		FromElement elem;
+		SessionFactoryHelper sfh = fromClause.getSessionFactoryHelper();
+		if ( inElementsFunction /*implied*/ ) {
+			// For implied many-to-many, just add the end join.
+			JoinSequence joinSequence = createJoinSequence( roleAlias, joinType );
+			elem = createJoin( associatedEntityName, roleAlias, joinSequence, type, true );
+		}
+		else {
+			// For an explicit many-to-many relationship, add a second join from the intermediate 
+			// (many-to-many) table to the destination table.  Also, make sure that the from element's 
+			// idea of the destination is the destination table.
+			String tableAlias = fromClause.getAliasGenerator().createName( entityPersister.getEntityName() );
+			String[] secondJoinColumns = sfh.getCollectionElementColumns( role, roleAlias );
+			// Add the second join, the one that ends in the destination table.
+			JoinSequence joinSequence = createJoinSequence( roleAlias, joinType );
+			joinSequence.addJoin( sfh.getElementAssociationType( collectionType ), tableAlias, joinType, secondJoinColumns );
+			elem = createJoin( associatedEntityName, tableAlias, joinSequence, type, false );
+			elem.setUseFromFragment( true );
+		}
+		return elem;
+	}
+
+	private JoinSequence createJoinSequence(String roleAlias, int joinType) {
+		SessionFactoryHelper sessionFactoryHelper = fromClause.getSessionFactoryHelper();
+		String[] joinColumns = getColumns();
+		if ( collectionType == null ) {
+			throw new IllegalStateException( "collectionType is null!" );
+		}
+		return sessionFactoryHelper.createJoinSequence( implied, collectionType, roleAlias, joinType, joinColumns );
+	}
+
+	private FromElement createAndAddFromElement(
+	        String className,
+	        String classAlias,
+	        EntityPersister entityPersister,
+	        EntityType type,
+	        String tableAlias) {
+		if ( !( entityPersister instanceof Joinable ) ) {
+			throw new IllegalArgumentException( "EntityPersister " + entityPersister + " does not implement Joinable!" );
+		}
+		FromElement element = createFromElement( entityPersister );
+		initializeAndAddFromElement( element, className, classAlias, entityPersister, type, tableAlias );
+		return element;
+	}
+
+	private void initializeAndAddFromElement(
+	        FromElement element,
+	        String className,
+	        String classAlias,
+	        EntityPersister entityPersister,
+	        EntityType type,
+	        String tableAlias) {
+		if ( tableAlias == null ) {
+			AliasGenerator aliasGenerator = fromClause.getAliasGenerator();
+			tableAlias = aliasGenerator.createName( entityPersister.getEntityName() );
+		}
+		element.initializeEntity( fromClause, className, entityPersister, type, classAlias, tableAlias );
+	}
+
+	private FromElement createFromElement(EntityPersister entityPersister) {
+		Joinable joinable = ( Joinable ) entityPersister;
+		String text = joinable.getTableName();
+		AST ast = createFromElement( text );
+		FromElement element = ( FromElement ) ast;
+		return element;
+	}
+
+	private AST createFromElement(String text) {
+		AST ast = ASTUtil.create( fromClause.getASTFactory(),
+				implied ? IMPLIED_FROM : FROM_FRAGMENT, // This causes the factory to instantiate the desired class.
+				text );
+		// Reset the node type, because the rest of the system is expecting FROM_FRAGMENT, all we wanted was
+		// for the factory to create the right sub-class.  This might get reset again later on anyway to make the
+		// SQL generation simpler.
+		ast.setType( FROM_FRAGMENT );
+		return ast;
+	}
+
+	private FromElement initializeJoin(
+	        String path,
+	        FromElement destination,
+	        JoinSequence joinSequence,
+	        String[] columns,
+	        FromElement origin,
+	        boolean manyToMany) {
+		destination.setType( JOIN_FRAGMENT );
+		destination.setJoinSequence( joinSequence );
+		destination.setColumns( columns );
+		destination.setOrigin( origin, manyToMany );
+		fromClause.addJoinByPathMap( path, destination );
+		return destination;
+	}
+
+	private String[] getColumns() {
+		if ( columns == null ) {
+			throw new IllegalStateException( "No foriegn key columns were supplied!" );
+		}
+		return columns;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromElementType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromElementType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromElementType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,415 @@
+// $Id: FromElementType.java 10824 2006-11-16 19:32:48Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.tree;
+
+import java.util.Map;
+
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.engine.JoinSequence;
+import org.hibernate.hql.CollectionProperties;
+import org.hibernate.hql.CollectionSubqueryFactory;
+import org.hibernate.hql.NameGenerator;
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.persister.collection.CollectionPropertyMapping;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.persister.entity.PropertyMapping;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Delegate that handles the type and join sequence information for a FromElement.
+ *
+ * @author josh Feb 12, 2005 10:17:34 AM
+ */
+class FromElementType {
+	private static final Log log = LogFactory.getLog( FromElementType.class );
+
+	private FromElement fromElement;
+	private EntityType entityType;
+	private EntityPersister persister;
+	private QueryableCollection queryableCollection;
+	private CollectionPropertyMapping collectionPropertyMapping;
+	private JoinSequence joinSequence;
+	private String collectionSuffix;
+
+	public FromElementType(FromElement fromElement, EntityPersister persister, EntityType entityType) {
+		this.fromElement = fromElement;
+		this.persister = persister;
+		this.entityType = entityType;
+		if ( persister != null ) {
+			fromElement.setText( ( ( Queryable ) persister ).getTableName() + " " + getTableAlias() );
+		}
+	}
+
+	private String getTableAlias() {
+		return fromElement.getTableAlias();
+	}
+
+	private String getCollectionTableAlias() {
+		return fromElement.getCollectionTableAlias();
+	}
+
+	public String getCollectionSuffix() {
+		return collectionSuffix;
+	}
+
+	public void setCollectionSuffix(String suffix) {
+		collectionSuffix = suffix;
+	}
+
+	public EntityPersister getEntityPersister() {
+		return persister;
+	}
+
+	public Type getDataType() {
+		if ( persister == null ) {
+			if ( queryableCollection == null ) {
+				return null;
+			}
+			return queryableCollection.getType();
+		}
+		else {
+			return entityType;
+		}
+	}
+
+	public Type getSelectType() {
+		if (entityType==null) return null;
+		boolean shallow = fromElement.getFromClause().getWalker().isShallowQuery();
+		return TypeFactory.manyToOne( entityType.getAssociatedEntityName(), shallow );
+	}
+
+	/**
+	 * Returns the Hibernate queryable implementation for the HQL class.
+	 *
+	 * @return the Hibernate queryable implementation for the HQL class.
+	 */
+	public Queryable getQueryable() {
+		return ( persister instanceof Queryable ) ? ( Queryable ) persister : null;
+	}
+
+	/**
+	 * Render the identifier select, but in a 'scalar' context (i.e. generate the column alias).
+	 *
+	 * @param i the sequence of the returned type
+	 * @return the identifier select with the column alias.
+	 */
+	String renderScalarIdentifierSelect(int i) {
+		checkInitialized();
+		String[] cols = getPropertyMapping( EntityPersister.ENTITY_ID ).toColumns( getTableAlias(), EntityPersister.ENTITY_ID );
+		StringBuffer buf = new StringBuffer();
+		// For property references generate <tablealias>.<columnname> as <projectionalias>
+		for ( int j = 0; j < cols.length; j++ ) {
+			String column = cols[j];
+			if ( j > 0 ) {
+				buf.append( ", " );
+			}
+			buf.append( column ).append( " as " ).append( NameGenerator.scalarName( i, j ) );
+		}
+		return buf.toString();
+	}
+
+	/**
+	 * Returns the identifier select SQL fragment.
+	 *
+	 * @param size The total number of returned types.
+	 * @param k    The sequence of the current returned type.
+	 * @return the identifier select SQL fragment.
+	 */
+	String renderIdentifierSelect(int size, int k) {
+		checkInitialized();
+		// Render the identifier select fragment using the table alias.
+		if ( fromElement.getFromClause().isSubQuery() ) {
+			// TODO: Replace this with a more elegant solution.
+			String[] idColumnNames = ( persister != null ) ?
+					( ( Queryable ) persister ).getIdentifierColumnNames() : new String[0];
+			StringBuffer buf = new StringBuffer();
+			for ( int i = 0; i < idColumnNames.length; i++ ) {
+				buf.append( fromElement.getTableAlias() ).append( '.' ).append( idColumnNames[i] );
+				if ( i != idColumnNames.length - 1 ) buf.append( ", " );
+			}
+			return buf.toString();
+		}
+		else {
+			if (persister==null) {
+				throw new QueryException( "not an entity" );
+			}
+			String fragment = ( ( Queryable ) persister ).identifierSelectFragment( getTableAlias(), getSuffix( size, k ) );
+			return trimLeadingCommaAndSpaces( fragment );
+		}
+	}
+
+	private String getSuffix(int size, int sequence) {
+		return generateSuffix( size, sequence );
+	}
+
+	private static String generateSuffix(int size, int k) {
+		String suffix = size == 1 ? "" : Integer.toString( k ) + '_';
+		return suffix;
+	}
+
+	private void checkInitialized() {
+		fromElement.checkInitialized();
+	}
+
+	/**
+	 * Returns the property select SQL fragment.
+	 * @param size The total number of returned types.
+	 * @param k    The sequence of the current returned type.
+	 * @return the property select SQL fragment.
+	 */
+	String renderPropertySelect(int size, int k, boolean allProperties) {
+		checkInitialized();
+		if ( persister == null ) {
+			return "";
+		}
+		else {
+			String fragment =  ( ( Queryable ) persister ).propertySelectFragment(
+					getTableAlias(),
+					getSuffix( size, k ),
+					allProperties
+				);
+			return trimLeadingCommaAndSpaces( fragment );
+		}
+	}
+
+	String renderCollectionSelectFragment(int size, int k) {
+		if ( queryableCollection == null ) {
+			return "";
+		}
+		else {
+			if ( collectionSuffix == null ) {
+				collectionSuffix = generateSuffix( size, k );
+			}
+			String fragment = queryableCollection.selectFragment( getCollectionTableAlias(), collectionSuffix );
+			return trimLeadingCommaAndSpaces( fragment );
+		}
+	}
+
+	public String renderValueCollectionSelectFragment(int size, int k) {
+		if ( queryableCollection == null ) {
+			return "";
+		}
+		else {
+			if ( collectionSuffix == null ) {
+				collectionSuffix = generateSuffix( size, k );
+			}
+			String fragment =  queryableCollection.selectFragment( getTableAlias(), collectionSuffix );
+			return trimLeadingCommaAndSpaces( fragment );
+		}
+	}
+
+	/**
+	 * This accounts for a quirk in Queryable, where it sometimes generates ',  ' in front of the
+	 * SQL fragment.  :-P
+	 *
+	 * @param fragment An SQL fragment.
+	 * @return The fragment, without the leading comma and spaces.
+	 */
+	private static String trimLeadingCommaAndSpaces(String fragment) {
+		if ( fragment.length() > 0 && fragment.charAt( 0 ) == ',' ) {
+			fragment = fragment.substring( 1 );
+		}
+		fragment = fragment.trim();
+		return fragment.trim();
+	}
+
+	public void setJoinSequence(JoinSequence joinSequence) {
+		this.joinSequence = joinSequence;
+	}
+
+	public JoinSequence getJoinSequence() {
+		if ( joinSequence != null ) {
+			return joinSequence;
+		}
+
+		// Class names in the FROM clause result in a JoinSequence (the old FromParser does this).
+		if ( persister instanceof Joinable ) {
+			Joinable joinable = ( Joinable ) persister;
+			return fromElement.getSessionFactoryHelper().createJoinSequence().setRoot( joinable, getTableAlias() );
+		}
+		else {
+			return null;	// TODO: Should this really return null?  If not, figure out something better to do here.
+		}
+	}
+
+	public void setQueryableCollection(QueryableCollection queryableCollection) {
+		if ( this.queryableCollection != null ) {
+			throw new IllegalStateException( "QueryableCollection is already defined for " + this + "!" );
+		}
+		this.queryableCollection = queryableCollection;
+		if ( !queryableCollection.isOneToMany() ) {
+			// For many-to-many joins, use the tablename from the queryable collection for the default text.
+			fromElement.setText( queryableCollection.getTableName() + " " + getTableAlias() );
+		}
+	}
+
+	public QueryableCollection getQueryableCollection() {
+		return queryableCollection;
+	}
+
+	/**
+	 * Returns the type of a property, given it's name (the last part) and the full path.
+	 *
+	 * @param propertyName The last part of the full path to the property.
+	 * @return The type.
+	 * @0param propertyPath The full property path.
+	 */
+	public Type getPropertyType(String propertyName, String propertyPath) {
+		checkInitialized();
+		Type type = null;
+		// If this is an entity and the property is the identifier property, then use getIdentifierType().
+		//      Note that the propertyName.equals( propertyPath ) checks whether we have a component
+		//      key reference, where the component class property name is the same as the
+		//      entity id property name; if the two are not equal, this is the case and
+		//      we'd need to "fall through" to using the property mapping.
+		if ( persister != null && propertyName.equals( propertyPath ) && propertyName.equals( persister.getIdentifierPropertyName() ) ) {
+			type = persister.getIdentifierType();
+		}
+		else {	// Otherwise, use the property mapping.
+			PropertyMapping mapping = getPropertyMapping( propertyName );
+			type = mapping.toType( propertyPath );
+		}
+		if ( type == null ) {
+			throw new MappingException( "Property " + propertyName + " does not exist in " +
+					( ( queryableCollection == null ) ? "class" : "collection" ) + " "
+					+ ( ( queryableCollection == null ) ? fromElement.getClassName() : queryableCollection.getRole() ) );
+		}
+		return type;
+	}
+
+	String[] toColumns(String tableAlias, String path, boolean inSelect) {
+		return toColumns( tableAlias, path, inSelect, false );
+	}
+
+	String[] toColumns(String tableAlias, String path, boolean inSelect, boolean forceAlias) {
+		checkInitialized();
+		PropertyMapping propertyMapping = getPropertyMapping( path );
+		// If this from element is a collection and the path is a collection property (maxIndex, etc.) then
+		// generate a sub-query.
+		if ( !inSelect && queryableCollection != null && CollectionProperties.isCollectionProperty( path ) ) {
+			Map enabledFilters = fromElement.getWalker().getEnabledFilters();
+			String subquery = CollectionSubqueryFactory.createCollectionSubquery(
+					joinSequence,
+			        enabledFilters,
+					propertyMapping.toColumns( tableAlias, path )
+			);
+			if ( log.isDebugEnabled() ) {
+				log.debug( "toColumns(" + tableAlias + "," + path + ") : subquery = " + subquery );
+			}
+			return new String[]{"(" + subquery + ")"};
+		}
+		else {
+			if ( forceAlias ) {
+				return propertyMapping.toColumns( tableAlias, path );
+			}
+			else if ( fromElement.getWalker().getStatementType() == HqlSqlTokenTypes.SELECT ) {
+				return propertyMapping.toColumns( tableAlias, path );
+			}
+			else if ( fromElement.getWalker().getCurrentClauseType() == HqlSqlTokenTypes.SELECT ) {
+				return propertyMapping.toColumns( tableAlias, path );
+			}
+			else if ( fromElement.getWalker().isSubQuery() ) {
+				// for a subquery, the alias to use depends on a few things (we
+				// already know this is not an overall SELECT):
+				//      1) if this FROM_ELEMENT represents a correlation to the
+				//          outer-most query
+				//              A) if the outer query represents a multi-table
+				//                  persister, we need to use the given alias
+				//                  in anticipation of one of the multi-table
+				//                  executors being used (as this subquery will
+				//                  actually be used in the "id select" phase
+				//                  of that multi-table executor)
+				//              B) otherwise, we need to use the persister's
+				//                  table name as the column qualification
+				//      2) otherwise (not correlated), use the given alias
+				if ( isCorrelation() ) {
+					if ( isMultiTable() ) {
+						return propertyMapping.toColumns( tableAlias, path );
+					}
+					else {
+						return propertyMapping.toColumns( extractTableName(), path );
+					}
+				}
+				else {
+					return propertyMapping.toColumns( tableAlias, path );
+				}
+			}
+			else {
+				String[] columns = propertyMapping.toColumns( path );
+				log.trace( "Using non-qualified column reference [" + path + " -> (" + ArrayHelper.toString( columns ) + ")]" );
+				return columns;
+			}
+		}
+	}
+
+	private boolean isCorrelation() {
+		FromClause top = fromElement.getWalker().getFinalFromClause();
+		return fromElement.getFromClause() != fromElement.getWalker().getCurrentFromClause() &&
+	           fromElement.getFromClause() == top;
+	}
+
+	private boolean isMultiTable() {
+		// should be safe to only ever expect EntityPersister references here
+		return fromElement.getQueryable() != null &&
+	           fromElement.getQueryable().isMultiTable();
+	}
+
+	private String extractTableName() {
+		// should be safe to only ever expect EntityPersister references here
+		return fromElement.getQueryable().getTableName();
+	}
+
+	PropertyMapping getPropertyMapping(String propertyName) {
+		checkInitialized();
+		if ( queryableCollection == null ) {		// Not a collection?
+			return ( PropertyMapping ) persister;	// Return the entity property mapping.
+		}
+		// If the property is a special collection property name, return a CollectionPropertyMapping.
+		if ( CollectionProperties.isCollectionProperty( propertyName ) ) {
+			if ( collectionPropertyMapping == null ) {
+				collectionPropertyMapping = new CollectionPropertyMapping( queryableCollection );
+			}
+			return collectionPropertyMapping;
+		}
+		if ( queryableCollection.getElementType().isAnyType() ) {
+			// collection of <many-to-any/> mappings...
+			// used to circumvent the component-collection check below...
+			return queryableCollection;
+
+		}
+		if ( queryableCollection.getElementType().isComponentType() ) {
+			// Collection of components.
+			if ( propertyName.equals( EntityPersister.ENTITY_ID ) ) {
+				return ( PropertyMapping ) queryableCollection.getOwnerEntityPersister();
+			}
+		}
+		return queryableCollection;
+	}
+
+	public boolean isCollectionOfValuesOrComponents() {
+		if ( persister == null ) {
+			if ( queryableCollection == null ) {
+				return false;
+			}
+			else {
+				return !queryableCollection.getElementType().isEntityType();
+			}
+		}
+		else {
+			return false;
+		}
+	}
+
+	public boolean isEntity() {
+		return persister != null;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromReferenceNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromReferenceNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/FromReferenceNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,109 @@
+// $Id: FromReferenceNode.java 7494 2005-07-15 16:20:04Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Represents a reference to a FROM element, for example a class alias in a WHERE clause.
+ *
+ * @author josh Jul 21, 2004 7:02:04 AM
+ */
+public abstract class FromReferenceNode extends AbstractSelectExpression
+        implements ResolvableNode, DisplayableNode, InitializeableNode, PathNode {
+
+	private static final Log log = LogFactory.getLog( FromReferenceNode.class );
+
+	private FromElement fromElement;
+	private boolean resolved = false;
+	public static final int ROOT_LEVEL = 0;
+
+	public FromElement getFromElement() {
+		return fromElement;
+	}
+
+	public void setFromElement(FromElement fromElement) {
+		this.fromElement = fromElement;
+	}
+
+	/**
+	 * Resolves the left hand side of the DOT.
+	 *
+	 * @throws SemanticException
+	 */
+	public void resolveFirstChild() throws SemanticException {
+	}
+
+	public String getPath() {
+		return getOriginalText();
+	}
+
+	public boolean isResolved() {
+		return resolved;
+	}
+
+	public void setResolved() {
+		this.resolved = true;
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Resolved :  " + this.getPath() + " -> " + this.getText() );
+		}
+	}
+
+	public String getDisplayText() {
+		StringBuffer buf = new StringBuffer();
+		buf.append( "{" ).append( ( fromElement == null ) ? "no fromElement" : fromElement.getDisplayText() );
+		buf.append( "}" );
+		return buf.toString();
+	}
+
+	public void recursiveResolve(int level, boolean impliedAtRoot, String classAlias) throws SemanticException {
+		recursiveResolve( level, impliedAtRoot, classAlias, this );
+	}
+
+	public void recursiveResolve(int level, boolean impliedAtRoot, String classAlias, AST parent) throws SemanticException {
+		AST lhs = getFirstChild();
+		int nextLevel = level + 1;
+		if ( lhs != null ) {
+			FromReferenceNode n = ( FromReferenceNode ) lhs;
+			n.recursiveResolve( nextLevel, impliedAtRoot, null, this );
+		}
+		resolveFirstChild();
+		boolean impliedJoin = true;
+		if ( level == ROOT_LEVEL && !impliedAtRoot ) {
+			impliedJoin = false;
+		}
+		resolve( true, impliedJoin, classAlias, parent );
+	}
+
+	public boolean isReturnableEntity() throws SemanticException {
+		return !isScalar() && fromElement.isEntity();
+	}
+
+	public void resolveInFunctionCall(boolean generateJoin, boolean implicitJoin) throws SemanticException {
+		resolve( generateJoin, implicitJoin );
+	}
+
+	public void resolve(boolean generateJoin, boolean implicitJoin) throws SemanticException {
+		resolve( generateJoin, implicitJoin, null );
+	}
+
+	public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias) throws SemanticException {
+		resolve( generateJoin, implicitJoin, classAlias, null );
+	}
+
+	public void prepareForDot(String propertyName) throws SemanticException {
+	}
+
+	/**
+	 * Sub-classes can override this method if they produce implied joins (e.g. DotNode).
+	 *
+	 * @return an implied join created by this from reference.
+	 */
+	public FromElement getImpliedJoin() {
+		return null;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/HqlSqlWalkerNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/HqlSqlWalkerNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/HqlSqlWalkerNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+// $Id: HqlSqlWalkerNode.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.ast.HqlSqlWalker;
+import org.hibernate.hql.ast.util.AliasGenerator;
+import org.hibernate.hql.ast.util.SessionFactoryHelper;
+
+import antlr.ASTFactory;
+
+/**
+ * A semantic analysis node, that points back to the main analyzer.
+ *
+ * @author josh Sep 24, 2004 4:08:13 PM
+ */
+public class HqlSqlWalkerNode extends SqlNode implements InitializeableNode {
+	/**
+	 * A pointer back to the phase 2 processor.
+	 */
+	private HqlSqlWalker walker;
+
+	public void initialize(Object param) {
+		walker = ( HqlSqlWalker ) param;
+	}
+
+	public HqlSqlWalker getWalker() {
+		return walker;
+	}
+
+	public SessionFactoryHelper getSessionFactoryHelper() {
+		return walker.getSessionFactoryHelper();
+	}
+
+	public ASTFactory getASTFactory() {
+		return walker.getASTFactory();
+	}
+
+	public AliasGenerator getAliasGenerator() {
+		return walker.getAliasGenerator();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/IdentNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/IdentNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/IdentNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,307 @@
+// $Id: IdentNode.java 10059 2006-06-28 02:37:56Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.tree;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+import org.hibernate.QueryException;
+import org.hibernate.dialect.function.SQLFunction;
+import org.hibernate.hql.antlr.SqlTokenTypes;
+import org.hibernate.hql.ast.util.ColumnHelper;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.Type;
+import org.hibernate.util.StringHelper;
+
+import java.util.List;
+
+/**
+ * Represents an identifier all by itself, which may be a function name,
+ * a class alias, or a form of naked property-ref depending on the
+ * context.
+ *
+ * @author josh Aug 16, 2004 7:20:55 AM
+ */
+public class IdentNode extends FromReferenceNode implements SelectExpression {
+
+	private static final int UNKNOWN = 0;
+	private static final int PROPERTY_REF = 1;
+	private static final int COMPONENT_REF = 2;
+
+	private boolean nakedPropertyRef = false;
+
+	public void resolveIndex(AST parent) throws SemanticException {
+		// An ident node can represent an index expression if the ident
+		// represents a naked property ref
+		//      *Note: this makes the assumption (which is currently the case
+		//      in the hql-sql grammar) that the ident is first resolved
+		//      itself (addrExpr -> resolve()).  The other option, if that
+		//      changes, is to call resolve from here; but it is
+		//      currently un-needed overhead.
+		if (!(isResolved() && nakedPropertyRef)) {
+			throw new UnsupportedOperationException();
+		}
+
+		String propertyName = getOriginalText();
+		if (!getDataType().isCollectionType()) {
+			throw new SemanticException("Collection expected; [" + propertyName + "] does not refer to a collection property");
+		}
+
+		// TODO : most of below was taken verbatim from DotNode; should either delegate this logic or super-type it
+		CollectionType type = (CollectionType) getDataType();
+		String role = type.getRole();
+		QueryableCollection queryableCollection = getSessionFactoryHelper().requireQueryableCollection(role);
+
+		String alias = null;  // DotNode uses null here...
+		String columnTableAlias = getFromElement().getTableAlias();
+		int joinType = JoinFragment.INNER_JOIN;
+		boolean fetch = false;
+
+		FromElementFactory factory = new FromElementFactory(
+				getWalker().getCurrentFromClause(),
+				getFromElement(),
+				propertyName,
+				alias,
+				getFromElement().toColumns(columnTableAlias, propertyName, false),
+				true
+		);
+		FromElement elem = factory.createCollection(queryableCollection, role, joinType, fetch, true);
+		setFromElement(elem);
+		getWalker().addQuerySpaces(queryableCollection.getCollectionSpaces());	// Always add the collection's query spaces.
+	}
+
+	public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent) {
+		if (!isResolved()) {
+			if (getWalker().getCurrentFromClause().isFromElementAlias(getText())) {
+				if (resolveAsAlias()) {
+					setResolved();
+					// We represent a from-clause alias
+				}
+			}
+			else if (parent != null && parent.getType() == SqlTokenTypes.DOT) {
+				DotNode dot = (DotNode) parent;
+				if (parent.getFirstChild() == this) {
+					if (resolveAsNakedComponentPropertyRefLHS(dot)) {
+						// we are the LHS of the DOT representing a naked comp-prop-ref
+						setResolved();
+					}
+				}
+				else {
+					if (resolveAsNakedComponentPropertyRefRHS(dot)) {
+						// we are the RHS of the DOT representing a naked comp-prop-ref
+						setResolved();
+					}
+				}
+			}
+			else {
+				int result = resolveAsNakedPropertyRef();
+				if (result == PROPERTY_REF) {
+					// we represent a naked (simple) prop-ref
+					setResolved();
+				}
+				else if (result == COMPONENT_REF) {
+					// EARLY EXIT!!!  return so the resolve call explicitly coming from DotNode can
+					// resolve this...
+					return;
+				}
+			}
+
+			// if we are still not resolved, we might represent a constant.
+			//      needed to add this here because the allowance of
+			//      naked-prop-refs in the grammar collides with the
+			//      definition of literals/constants ("nondeterminism").
+			//      TODO: cleanup the grammar so that "processConstants" is always just handled from here
+			if (!isResolved()) {
+				try {
+					getWalker().getLiteralProcessor().processConstant(this, false);
+				}
+				catch (Throwable ignore) {
+					// just ignore it for now, it'll get resolved later...
+				}
+			}
+		}
+	}
+
+	private boolean resolveAsAlias() {
+		// This is not actually a constant, but a reference to FROM element.
+		FromElement element = getWalker().getCurrentFromClause().getFromElement(getText());
+		if (element != null) {
+			setFromElement(element);
+			setText(element.getIdentityColumn());
+			setType(SqlTokenTypes.ALIAS_REF);
+			return true;
+		}
+		return false;
+	}
+
+	private Type getNakedPropertyType(FromElement fromElement)
+	{
+		if (fromElement == null) {
+			return null;
+		}
+		String property = getOriginalText();
+		Type propertyType = null;
+		try {
+			propertyType = fromElement.getPropertyType(property, property);
+		}
+		catch (Throwable t) {
+		}
+		return propertyType;
+	}
+
+	private int resolveAsNakedPropertyRef() {
+		FromElement fromElement = locateSingleFromElement();
+		if (fromElement == null) {
+			return UNKNOWN;
+		}
+		Queryable persister = fromElement.getQueryable();
+		if (persister == null) {
+			return UNKNOWN;
+		}
+		Type propertyType = getNakedPropertyType(fromElement);
+		if (propertyType == null) {
+			// assume this ident's text does *not* refer to a property on the given persister
+			return UNKNOWN;
+		}
+
+		if ((propertyType.isComponentType() || propertyType.isAssociationType() )) {
+			return COMPONENT_REF;
+		}
+
+		setFromElement(fromElement);
+		String property = getText();
+		String[] columns = getWalker().isSelectStatement()
+				? persister.toColumns(fromElement.getTableAlias(), property)
+				: persister.toColumns(property);
+		String text = StringHelper.join(", ", columns);
+		setText(columns.length == 1 ? text : "(" + text + ")");
+		setType(SqlTokenTypes.SQL_TOKEN);
+
+		// these pieces are needed for usage in select clause
+		super.setDataType(propertyType);
+		nakedPropertyRef = true;
+
+		return PROPERTY_REF;
+	}
+
+	private boolean resolveAsNakedComponentPropertyRefLHS(DotNode parent) {
+		FromElement fromElement = locateSingleFromElement();
+		if (fromElement == null) {
+			return false;
+		}
+
+		Type componentType = getNakedPropertyType(fromElement);
+		if ( componentType == null ) {
+			throw new QueryException( "Unable to resolve path [" + parent.getPath() + "], unexpected token [" + getOriginalText() + "]" );
+		}
+		if (!componentType.isComponentType()) {
+			throw new QueryException("Property '" + getOriginalText() + "' is not a component.  Use an alias to reference associations or collections.");
+		}
+
+		Type propertyType = null;  // used to set the type of the parent dot node
+		String propertyPath = getText() + "." + getNextSibling().getText();
+		try {
+			// check to see if our "propPath" actually
+			// represents a property on the persister
+			propertyType = fromElement.getPropertyType(getText(), propertyPath);
+		}
+		catch (Throwable t) {
+			// assume we do *not* refer to a property on the given persister
+			return false;
+		}
+
+		setFromElement(fromElement);
+		parent.setPropertyPath(propertyPath);
+		parent.setDataType(propertyType);
+
+		return true;
+	}
+
+	private boolean resolveAsNakedComponentPropertyRefRHS(DotNode parent) {
+		FromElement fromElement = locateSingleFromElement();
+		if (fromElement == null) {
+			return false;
+		}
+
+		Type propertyType = null;
+		String propertyPath = parent.getLhs().getText() + "." + getText();
+		try {
+			// check to see if our "propPath" actually
+			// represents a property on the persister
+			propertyType = fromElement.getPropertyType(getText(), propertyPath);
+		}
+		catch (Throwable t) {
+			// assume we do *not* refer to a property on the given persister
+			return false;
+		}
+
+		setFromElement(fromElement);
+		// this piece is needed for usage in select clause
+		super.setDataType(propertyType);
+		nakedPropertyRef = true;
+
+		return true;
+	}
+
+	private FromElement locateSingleFromElement() {
+		List fromElements = getWalker().getCurrentFromClause().getFromElements();
+		if (fromElements == null || fromElements.size() != 1) {
+			// TODO : should this be an error?
+			return null;
+		}
+		FromElement element = (FromElement) fromElements.get(0);
+		if (element.getClassAlias() != null) {
+			// naked property-refs cannot be used with an aliased from element
+			return null;
+		}
+		return element;
+	}
+
+	public Type getDataType() {
+		Type type = super.getDataType();
+		if (type != null) return type;
+		FromElement fe = getFromElement();
+		if (fe != null) return fe.getDataType();
+		SQLFunction sf = getWalker().getSessionFactoryHelper().findSQLFunction(getText());
+		return sf == null ? null : sf.getReturnType(null, null);
+	}
+
+	public void setScalarColumnText(int i) throws SemanticException {
+		if (nakedPropertyRef) {
+			// do *not* over-write the column text, as that has already been
+			// "rendered" during resolve
+			ColumnHelper.generateSingleScalarColumn(this, i);
+		}
+		else {
+			FromElement fe = getFromElement();
+			if (fe != null) {
+				setText(fe.renderScalarIdentifierSelect(i));
+			}
+			else {
+				ColumnHelper.generateSingleScalarColumn(this, i);
+			}
+		}
+	}
+
+	public String getDisplayText() {
+		StringBuffer buf = new StringBuffer();
+
+		if (getType() == SqlTokenTypes.ALIAS_REF) {
+			buf.append("{alias=").append(getOriginalText());
+			if (getFromElement() == null) {
+				buf.append(", no from element");
+			}
+			else {
+				buf.append(", className=").append(getFromElement().getClassName());
+				buf.append(", tableAlias=").append(getFromElement().getTableAlias());
+			}
+			buf.append("}");
+		}
+		else {
+			buf.append("{originalText=" + getOriginalText()).append("}");
+		}
+		return buf.toString();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ImpliedFromElement.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ImpliedFromElement.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ImpliedFromElement.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+// $Id: ImpliedFromElement.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+/**
+ * Represents a FROM element implied by a path expression or a collection reference.
+ *
+ * @author josh Feb 10, 2005 12:31:03 AM
+ */
+public class ImpliedFromElement extends FromElement {
+	/**
+	 * True if this from element was implied from a path in the FROM clause, but not
+	 * explicitly declard in the from clause.
+	 */
+	private boolean impliedInFromClause = false;
+
+	/**
+	 * True if this implied from element should be included in the projection list.
+	 */
+	private boolean inProjectionList = false;
+
+	public boolean isImplied() {
+		return true;
+	}
+
+	public void setImpliedInFromClause(boolean flag) {
+		impliedInFromClause = flag;
+	}
+
+	public boolean isImpliedInFromClause() {
+		return impliedInFromClause;
+	}
+
+	public void setInProjectionList(boolean inProjectionList) {
+		this.inProjectionList = inProjectionList;
+	}
+
+	public boolean inProjectionList() {
+		return inProjectionList && isFromOrJoinFragment();
+	}
+
+	public boolean isIncludeSubclasses() {
+		return false;	// Never include subclasses for implied from elements.
+	}
+
+	/**
+	 * Returns additional display text for the AST node.
+	 *
+	 * @return String - The additional display text.
+	 */
+	public String getDisplayText() {
+		StringBuffer buf = new StringBuffer();
+		buf.append( "ImpliedFromElement{" );
+		appendDisplayText( buf );
+		buf.append( "}" );
+		return buf.toString();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/InLogicOperatorNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/InLogicOperatorNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/InLogicOperatorNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+package org.hibernate.hql.ast.tree;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+import org.hibernate.type.Type;
+
+/**
+ * @author Steve Ebersole
+ */
+public class InLogicOperatorNode extends BinaryLogicOperatorNode implements BinaryOperatorNode {
+
+	public Node getInList() {
+		return getRightHandOperand();
+	}
+
+	public void initialize() throws SemanticException {
+		Node lhs = getLeftHandOperand();
+		if ( lhs == null ) {
+			throw new SemanticException( "left-hand operand of in operator was null" );
+		}
+		Node inList = getInList();
+		if ( inList == null ) {
+			throw new SemanticException( "right-hand operand of in operator was null" );
+		}
+
+		// for expected parameter type injection, we expect that the lhs represents
+		// some form of property ref and that the children of the in-list represent
+		// one-or-more params.
+		if ( SqlNode.class.isAssignableFrom( lhs.getClass() ) ) {
+			Type lhsType = ( ( SqlNode ) lhs ).getDataType();
+			AST inListChild = inList.getFirstChild();
+			while ( inListChild != null ) {
+				if ( ExpectedTypeAwareNode.class.isAssignableFrom( inListChild.getClass() ) ) {
+					( ( ExpectedTypeAwareNode ) inListChild ).setExpectedType( lhsType );
+				}
+				inListChild = inListChild.getNextSibling();
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/IndexNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/IndexNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/IndexNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,134 @@
+// $Id: IndexNode.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.QueryException;
+import org.hibernate.engine.JoinSequence;
+import org.hibernate.hql.ast.SqlGenerator;
+import org.hibernate.hql.ast.util.SessionFactoryHelper;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.Type;
+
+import antlr.RecognitionException;
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Represents the [] operator and provides it's semantics.
+ *
+ * @author josh Aug 14, 2004 7:07:10 AM
+ */
+public class IndexNode extends FromReferenceNode {
+
+	private static final Log log = LogFactory.getLog( IndexNode.class );
+
+	public void setScalarColumnText(int i) throws SemanticException {
+		throw new UnsupportedOperationException( "An IndexNode cannot generate column text!" );
+	}
+
+	public void prepareForDot(String propertyName) throws SemanticException {
+		FromElement fromElement = getFromElement();
+		if ( fromElement == null ) {
+			throw new IllegalStateException( "No FROM element for index operator!" );
+		}
+		QueryableCollection queryableCollection = fromElement.getQueryableCollection();
+		if ( queryableCollection != null && !queryableCollection.isOneToMany() ) {
+
+			FromReferenceNode collectionNode = ( FromReferenceNode ) getFirstChild();
+			String path = collectionNode.getPath() + "[]." + propertyName;
+			if ( log.isDebugEnabled() ) {
+				log.debug( "Creating join for many-to-many elements for " + path );
+			}
+			FromElementFactory factory = new FromElementFactory( fromElement.getFromClause(), fromElement, path );
+			// This will add the new from element to the origin.
+			FromElement elementJoin = factory.createElementJoin( queryableCollection );
+			setFromElement( elementJoin );
+		}
+	}
+
+	public void resolveIndex(AST parent) throws SemanticException {
+		throw new UnsupportedOperationException();
+	}
+
+	public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent) 
+	throws SemanticException {
+		if ( isResolved() ) {
+			return;
+		}
+		FromReferenceNode collectionNode = ( FromReferenceNode ) getFirstChild();
+		SessionFactoryHelper sessionFactoryHelper = getSessionFactoryHelper();
+		collectionNode.resolveIndex( this );		// Fully resolve the map reference, create implicit joins.
+
+		Type type = collectionNode.getDataType();
+		if ( !type.isCollectionType() ) {
+			throw new SemanticException( "The [] operator cannot be applied to type " + type.toString() );
+		}
+		String collectionRole = ( ( CollectionType ) type ).getRole();
+		QueryableCollection queryableCollection = sessionFactoryHelper.requireQueryableCollection( collectionRole );
+		if ( !queryableCollection.hasIndex() ) {
+			throw new QueryException( "unindexed fromElement before []: " + collectionNode.getPath() );
+		}
+
+		// Generate the inner join -- The elements need to be joined to the collection they are in.
+		FromElement fromElement = collectionNode.getFromElement();
+		String elementTable = fromElement.getTableAlias();
+		FromClause fromClause = fromElement.getFromClause();
+		String path = collectionNode.getPath();
+
+		FromElement elem = fromClause.findCollectionJoin( path );
+		if ( elem == null ) {
+			FromElementFactory factory = new FromElementFactory( fromClause, fromElement, path );
+			elem = factory.createCollectionElementsJoin( queryableCollection, elementTable );
+			if ( log.isDebugEnabled() ) {
+				log.debug( "No FROM element found for the elements of collection join path " + path
+						+ ", created " + elem );
+			}
+		}
+		else {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "FROM element found for collection join path " + path );
+			}
+		}
+
+		// Add the condition to the join sequence that qualifies the indexed element.
+		AST index = collectionNode.getNextSibling();	// The index should be a constant, which will have been processed already.
+		if ( index == null ) {
+			throw new QueryException( "No index value!" );
+		}
+
+		setFromElement( fromElement );							// The 'from element' that represents the elements of the collection.
+
+		// Sometimes use the element table alias, sometimes use the... umm... collection table alias (many to many)
+		String collectionTableAlias = elementTable;
+		if ( elem.getCollectionTableAlias() != null ) {
+			collectionTableAlias = elem.getCollectionTableAlias();
+		}
+
+		// TODO: get SQL rendering out of here, create an AST for the join expressions.
+		// Use the SQL generator grammar to generate the SQL text for the index expression.
+		JoinSequence joinSequence = fromElement.getJoinSequence();
+		String[] indexCols = queryableCollection.getIndexColumnNames();
+		if ( indexCols.length != 1 ) {
+			throw new QueryException( "composite-index appears in []: " + collectionNode.getPath() );
+		}
+		SqlGenerator gen = new SqlGenerator( getSessionFactoryHelper().getFactory() );
+		try {
+			gen.simpleExpr( index ); //TODO: used to be exprNoParens! was this needed?
+		}
+		catch ( RecognitionException e ) {
+			throw new QueryException( e.getMessage(), e );
+		}
+		String expression = gen.getSQL();
+		joinSequence.addCondition( collectionTableAlias + '.' + indexCols[0] + " = " + expression );
+
+		// Now, set the text for this node.  It should be the element columns.
+		String[] elementColumns = queryableCollection.getElementColumnNames( elementTable );
+		setText( elementColumns[0] );
+		setResolved();
+	}
+
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/InitializeableNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/InitializeableNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/InitializeableNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+// $Id: InitializeableNode.java 7460 2005-07-12 20:27:29Z steveebersole $
+
+package org.hibernate.hql.ast.tree;
+
+/**
+ * An interface for initializeable AST nodes.
+ */
+public interface InitializeableNode {
+	/**
+	 * Initializes the node with the parameter.
+	 *
+	 * @param param the initialization parameter.
+	 */
+	void initialize(Object param);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/InsertStatement.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/InsertStatement.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/InsertStatement.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+// $Id: InsertStatement.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.QueryException;
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+
+/**
+ * Defines a top-level AST node representing an HQL "insert select" statement.
+ *
+ * @author Steve Ebersole
+ */
+public class InsertStatement extends AbstractStatement {
+
+	/**
+	 * @see Statement#getStatementType()
+	 */
+	public int getStatementType() {
+		return HqlSqlTokenTypes.INSERT;
+	}
+
+	/**
+	 * @see Statement#needsExecutor()
+	 */
+	public boolean needsExecutor() {
+		return true;
+	}
+
+	/**
+	 * Performs detailed semantic validation on this insert statement tree.
+	 *
+	 * @throws QueryException Indicates validation failure.
+	 */
+	public void validate() throws QueryException {
+		getIntoClause().validateTypes( getSelectClause() );
+	}
+
+	/**
+	 * Retreive this insert statement's into-clause.
+	 *
+	 * @return The into-clause
+	 */
+	public IntoClause getIntoClause() {
+		return ( IntoClause ) getFirstChild();
+	}
+
+	/**
+	 * Retreive this insert statement's select-clause.
+	 *
+	 * @return The select-clause.
+	 */
+	public SelectClause getSelectClause() {
+		return ( ( QueryNode ) getIntoClause().getNextSibling() ).getSelectClause();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/IntoClause.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/IntoClause.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/IntoClause.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,234 @@
+// $Id: IntoClause.java 8050 2005-08-31 15:02:23Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.sql.Types;
+
+import org.hibernate.QueryException;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+
+import antlr.collections.AST;
+
+/**
+ * Represents an entity referenced in the INTO clause of an HQL
+ * INSERT statement.
+ *
+ * @author Steve Ebersole
+ */
+public class IntoClause extends HqlSqlWalkerNode implements DisplayableNode {
+
+	private Queryable persister;
+	private String columnSpec = "";
+	private Type[] types;
+
+	private boolean discriminated;
+	private boolean explicitIdInsertion;
+	private boolean explicitVersionInsertion;
+
+
+	public void initialize(Queryable persister) {
+		if ( persister.isAbstract() ) {
+			throw new QueryException( "cannot insert into abstract class (no table)" );
+		}
+		this.persister = persister;
+		initializeColumns();
+
+		if ( getWalker().getSessionFactoryHelper().hasPhysicalDiscriminatorColumn( persister ) ) {
+			discriminated = true;
+			columnSpec += ", " + persister.getDiscriminatorColumnName();
+		}
+
+		resetText();
+	}
+
+	private void resetText() {
+		setText( "into " + getTableName() + " ( " + columnSpec + " )" );
+	}
+
+	public String getTableName() {
+		return persister.getSubclassTableName( 0 );
+	}
+
+	public Queryable getQueryable() {
+		return persister;
+	}
+
+	public String getEntityName() {
+		return persister.getEntityName();
+	}
+
+	public Type[] getInsertionTypes() {
+		return types;
+	}
+
+	public boolean isDiscriminated() {
+		return discriminated;
+	}
+
+	public boolean isExplicitIdInsertion() {
+		return explicitIdInsertion;
+	}
+
+	public boolean isExplicitVersionInsertion() {
+		return explicitVersionInsertion;
+	}
+
+	public void prependIdColumnSpec() {
+		columnSpec = persister.getIdentifierColumnNames()[0] + ", " + columnSpec;
+		resetText();
+	}
+
+	public void prependVersionColumnSpec() {
+		columnSpec = persister.getPropertyColumnNames( persister.getVersionProperty() )[0] + ", " + columnSpec;
+		resetText();
+	}
+
+	public void validateTypes(SelectClause selectClause) throws QueryException {
+		Type[] selectTypes = selectClause.getQueryReturnTypes();
+		if ( selectTypes.length != types.length ) {
+			throw new QueryException( "number of select types did not match those for insert" );
+		}
+
+		for ( int i = 0; i < types.length; i++ ) {
+			if ( !areCompatible( types[i], selectTypes[i] ) ) {
+				throw new QueryException(
+				        "insertion type [" + types[i] + "] and selection type [" +
+				        selectTypes[i] + "] at position " + i + " are not compatible"
+				);
+			}
+		}
+
+		// otherwise, everything ok.
+	}
+
+	/**
+	 * Returns additional display text for the AST node.
+	 *
+	 * @return String - The additional display text.
+	 */
+	public String getDisplayText() {
+		StringBuffer buf = new StringBuffer();
+		buf.append( "IntoClause{" );
+		buf.append( "entityName=" ).append( getEntityName() );
+		buf.append( ",tableName=" ).append( getTableName() );
+		buf.append( ",columns={" ).append( columnSpec ).append( "}" );
+		buf.append( "}" );
+		return buf.toString();
+	}
+
+	private void initializeColumns() {
+		AST propertySpec = getFirstChild();
+		List types = new ArrayList();
+		visitPropertySpecNodes( propertySpec.getFirstChild(), types );
+		this.types = ArrayHelper.toTypeArray( types );
+		columnSpec = columnSpec.substring( 0, columnSpec.length() - 2 );
+	}
+
+	private void visitPropertySpecNodes(AST propertyNode, List types) {
+		if ( propertyNode == null ) {
+			return;
+		}
+		// TODO : we really need to be able to deal with component paths here also;
+		// this is difficult because the hql-sql grammar expects all those node types
+		// to be FromReferenceNodes.  One potential fix here would be to convert the
+		// IntoClause to just use a FromClause/FromElement combo (as a child of the
+		// InsertStatement) and move all this logic into the InsertStatement.  That's
+		// probably the easiest approach (read: least amount of changes to the grammar
+		// and code), but just doesn't feel right as then an insert would contain
+		// 2 from-clauses
+		String name = propertyNode.getText();
+		if ( isSuperclassProperty( name ) ) {
+			throw new QueryException( "INSERT statements cannot refer to superclass/joined properties [" + name + "]" );
+		}
+
+		if ( name.equals( persister.getIdentifierPropertyName() ) ) {
+			explicitIdInsertion = true;
+		}
+
+		if ( persister.isVersioned() ) {
+			if ( name.equals( persister.getPropertyNames()[ persister.getVersionProperty() ] ) ) {
+				explicitVersionInsertion = true;
+			}
+		}
+
+		String[] columnNames = persister.toColumns( name );
+		renderColumns( columnNames );
+		types.add( persister.toType( name ) );
+
+		// visit width-first, then depth
+		visitPropertySpecNodes( propertyNode.getNextSibling(), types );
+		visitPropertySpecNodes( propertyNode.getFirstChild(), types );
+	}
+
+	private void renderColumns(String[] columnNames) {
+		for ( int i = 0; i < columnNames.length; i++ ) {
+			columnSpec += columnNames[i] + ", ";
+		}
+	}
+
+	private boolean isSuperclassProperty(String propertyName) {
+		// really there are two situations where it should be ok to allow the insertion
+		// into properties defined on a superclass:
+		//      1) union-subclass with an abstract root entity
+		//      2) discrim-subclass
+		//
+		// #1 is handled already because of the fact that
+		// UnionSubclassPersister alreay always returns 0
+		// for this call...
+		//
+		// we may want to disallow it for discrim-subclass just for
+		// consistency-sake (currently does not work anyway)...
+		return persister.getSubclassPropertyTableNumber( propertyName ) != 0;
+	}
+
+	/**
+	 * Determine whether the two types are "assignment compatible".
+	 *
+	 * @param target The type defined in the into-clause.
+	 * @param source The type defined in the select clause.
+	 * @return True if they are assignment compatible.
+	 */
+	private boolean areCompatible(Type target, Type source) {
+		if ( target.equals( source ) ) {
+			// if the types report logical equivalence, return true...
+			return true;
+		}
+
+		// otherwise, perform a "deep equivalence" check...
+
+		if ( !target.getReturnedClass().isAssignableFrom( source.getReturnedClass() ) ) {
+			return false;
+		}
+
+		int[] targetDatatypes = target.sqlTypes( getSessionFactoryHelper().getFactory() );
+		int[] sourceDatatypes = source.sqlTypes( getSessionFactoryHelper().getFactory() );
+
+		if ( targetDatatypes.length != sourceDatatypes.length ) {
+			return false;
+		}
+
+		for ( int i = 0; i < targetDatatypes.length; i++ ) {
+			if ( !areSqlTypesCompatible( targetDatatypes[i], sourceDatatypes[i] ) ) {
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	private boolean areSqlTypesCompatible(int target, int source) {
+		switch ( target ) {
+			case Types.TIMESTAMP:
+				return source == Types.DATE || source == Types.TIME || source == Types.TIMESTAMP;
+			case Types.DATE:
+				return source == Types.DATE || source == Types.TIMESTAMP;
+			case Types.TIME:
+				return source == Types.TIME || source == Types.TIMESTAMP;
+			default:
+				return target == source;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/JavaConstantNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/JavaConstantNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/JavaConstantNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,66 @@
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.type.LiteralType;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.StringHelper;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.QueryException;
+import org.hibernate.hql.QueryTranslator;
+
+/**
+ * A node representing a static Java constant.
+ *
+ * @author Steve Ebersole
+ */
+public class JavaConstantNode extends Node implements ExpectedTypeAwareNode, SessionFactoryAwareNode {
+
+	private SessionFactoryImplementor factory;
+
+	private String constantExpression;
+	private Object constantValue;
+	private Type heuristicType;
+
+	private Type expectedType;
+
+	public void setText(String s) {
+		// for some reason the antlr.CommonAST initialization routines force
+		// this method to get called twice.  The first time with an empty string
+		if ( StringHelper.isNotEmpty( s ) ) {
+			constantExpression = s;
+			constantValue = ReflectHelper.getConstantValue( s );
+			heuristicType = TypeFactory.heuristicType( constantValue.getClass().getName() );
+			super.setText( s );
+		}
+	}
+
+	public void setExpectedType(Type expectedType) {
+		this.expectedType = expectedType;
+	}
+
+	public Type getExpectedType() {
+		return expectedType;
+	}
+
+	public void setSessionFactory(SessionFactoryImplementor factory) {
+		this.factory = factory;
+	}
+
+	private String resolveToLiteralString(Type type) {
+		try {
+			LiteralType literalType = ( LiteralType ) type;
+			Dialect dialect = factory.getDialect();
+			return literalType.objectToSQLString( constantValue, dialect );
+		}
+		catch ( Throwable t ) {
+			throw new QueryException( QueryTranslator.ERROR_CANNOT_FORMAT_LITERAL + constantExpression, t );
+		}
+	}
+
+	public String getRenderText(SessionFactoryImplementor sessionFactory) {
+		Type type = expectedType == null ? heuristicType : expectedType;
+		return resolveToLiteralString( type );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/LiteralNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/LiteralNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/LiteralNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+// $Id: LiteralNode.java 10060 2006-06-28 02:53:39Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.Hibernate;
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.hql.ast.util.ColumnHelper;
+import org.hibernate.type.Type;
+
+import antlr.SemanticException;
+
+/**
+ * Represents a literal.
+ *
+ * @author josh Jan 8, 2005 10:09:53 AM
+ */
+public class LiteralNode extends AbstractSelectExpression implements HqlSqlTokenTypes {
+
+	public void setScalarColumnText(int i) throws SemanticException {
+		ColumnHelper.generateSingleScalarColumn( this, i );
+	}
+
+	public Type getDataType() {
+		switch ( getType() ) {
+			case NUM_INT:
+				return Hibernate.INTEGER;
+			case NUM_FLOAT:
+				return Hibernate.FLOAT;
+			case NUM_LONG:
+				return Hibernate.LONG;
+			case NUM_DOUBLE:
+				return Hibernate.DOUBLE;
+			case QUOTED_STRING:
+				return Hibernate.STRING;
+			case TRUE:
+			case FALSE:
+				return Hibernate.BOOLEAN;
+			default:
+				return null;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/MethodNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/MethodNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/MethodNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,190 @@
+// $Id: MethodNode.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import java.util.Arrays;
+
+import org.hibernate.dialect.function.SQLFunction;
+import org.hibernate.hql.CollectionProperties;
+import org.hibernate.hql.antlr.SqlTokenTypes;
+import org.hibernate.hql.ast.util.ASTUtil;
+import org.hibernate.hql.ast.util.ColumnHelper;
+import org.hibernate.persister.collection.CollectionPropertyNames;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.type.Type;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Represents a method call.
+ *
+ * @author josh Aug 16, 2004 7:59:42 AM
+ */
+public class MethodNode extends AbstractSelectExpression implements SelectExpression {
+
+	private static final Log log = LogFactory.getLog( MethodNode.class );
+
+	private String methodName;
+	private FromElement fromElement;
+	private String[] selectColumns;
+	private SQLFunction function;
+	private boolean inSelect;
+
+	public void resolve(boolean inSelect) throws SemanticException {
+		// Get the function name node.
+		AST name = getFirstChild();
+		initializeMethodNode( name, inSelect );
+		AST exprList = name.getNextSibling();
+		// If the expression list has exactly one expression, and the type of the expression is a collection
+		// then this might be a collection function, such as index(c) or size(c).
+		if ( ASTUtil.hasExactlyOneChild( exprList ) && isCollectionPropertyMethod() ) {
+			collectionProperty( exprList.getFirstChild(), name );
+		}
+		else {
+			dialectFunction( exprList );
+		}
+	}
+
+	public SQLFunction getSQLFunction() {
+		return function;
+	}
+
+	private void dialectFunction(AST exprList) {
+		function = getSessionFactoryHelper().findSQLFunction( methodName );
+		if ( function != null ) {
+			AST firstChild = exprList != null ? exprList.getFirstChild() : null;
+			Type functionReturnType = getSessionFactoryHelper()
+					.findFunctionReturnType( methodName, firstChild );
+			setDataType( functionReturnType );
+		}
+		//TODO:
+		/*else {
+			methodName = (String) getWalker().getTokenReplacements().get( methodName );
+		}*/
+	}
+
+	public boolean isCollectionPropertyMethod() {
+		return CollectionProperties.isAnyCollectionProperty( methodName );
+	}
+
+	public void initializeMethodNode(AST name, boolean inSelect) {
+		name.setType( SqlTokenTypes.METHOD_NAME );
+		String text = name.getText();
+		methodName = text.toLowerCase();	// Use the lower case function name.
+		this.inSelect = inSelect;			// Remember whether we're in a SELECT clause or not.
+	}
+
+	private String getMethodName() {
+		return methodName;
+	}
+
+	private void collectionProperty(AST path, AST name) throws SemanticException {
+		if ( path == null ) {
+			throw new SemanticException( "Collection function " + name.getText() + " has no path!" );
+		}
+
+		SqlNode expr = ( SqlNode ) path;
+		Type type = expr.getDataType();
+		if ( log.isDebugEnabled() ) {
+			log.debug( "collectionProperty() :  name=" + name + " type=" + type );
+		}
+
+		resolveCollectionProperty( expr );
+	}
+
+	public boolean isScalar() throws SemanticException {
+		// Method expressions in a SELECT should always be considered scalar.
+		return true;
+	}
+
+	public void resolveCollectionProperty(AST expr) throws SemanticException {
+		String propertyName = CollectionProperties.getNormalizedPropertyName( getMethodName() );
+		if ( expr instanceof FromReferenceNode ) {
+			FromReferenceNode collectionNode = ( FromReferenceNode ) expr;
+			// If this is 'elements' then create a new FROM element.
+			if ( CollectionPropertyNames.COLLECTION_ELEMENTS.equals( propertyName ) ) {
+				handleElements( collectionNode, propertyName );
+			}
+			else {
+				// Not elements(x)
+				fromElement = collectionNode.getFromElement();
+				setDataType( fromElement.getPropertyType( propertyName, propertyName ) );
+				selectColumns = fromElement.toColumns( fromElement.getTableAlias(), propertyName, inSelect );
+			}
+			if ( collectionNode instanceof DotNode ) {
+				prepareAnyImplicitJoins( ( DotNode ) collectionNode );
+			}
+			if ( !inSelect ) {
+				fromElement.setText( "" );
+				fromElement.setUseWhereFragment( false );
+			}
+			prepareSelectColumns( selectColumns );
+			setText( selectColumns[0] );
+			setType( SqlTokenTypes.SQL_TOKEN );
+		}
+		else {
+			throw new SemanticException( 
+					"Unexpected expression " + expr + 
+					" found for collection function " + propertyName 
+				);
+		}
+	}
+
+	private void prepareAnyImplicitJoins(DotNode dotNode) throws SemanticException {
+		if ( dotNode.getLhs() instanceof DotNode ) {
+			DotNode lhs = ( DotNode ) dotNode.getLhs();
+			FromElement lhsOrigin = lhs.getFromElement();
+			if ( lhsOrigin != null && "".equals( lhsOrigin.getText() ) ) {
+				String lhsOriginText = lhsOrigin.getQueryable().getTableName() +
+				        " " + lhsOrigin.getTableAlias();
+				lhsOrigin.setText( lhsOriginText );
+			}
+			prepareAnyImplicitJoins( lhs );
+		}
+	}
+
+	private void handleElements(FromReferenceNode collectionNode, String propertyName) {
+		FromElement collectionFromElement = collectionNode.getFromElement();
+		QueryableCollection queryableCollection = collectionFromElement.getQueryableCollection();
+
+		String path = collectionNode.getPath() + "[]." + propertyName;
+		log.debug( "Creating elements for " + path );
+
+		fromElement = collectionFromElement;
+		if ( !collectionFromElement.isCollectionOfValuesOrComponents() ) {
+			getWalker().addQuerySpaces( queryableCollection.getElementPersister().getQuerySpaces() );
+		}
+
+		setDataType( queryableCollection.getElementType() );
+		selectColumns = collectionFromElement.toColumns( fromElement.getTableAlias(), propertyName, inSelect );
+	}
+
+	public void setScalarColumnText(int i) throws SemanticException {
+		if ( selectColumns == null ) { 	// Dialect function
+			ColumnHelper.generateSingleScalarColumn( this, i );
+		}
+		else {	// Collection 'property function'
+			ColumnHelper.generateScalarColumns( this, selectColumns, i );
+		}
+	}
+
+	protected void prepareSelectColumns(String[] columns) {
+		return;
+	}
+
+	public FromElement getFromElement() {
+		return fromElement;
+	}
+
+	public String getDisplayText() {
+		return "{" +
+				"method=" + getMethodName() +
+				",selectColumns=" + ( selectColumns == null ? 
+						null : Arrays.asList( selectColumns ) ) +
+				",fromElement=" + fromElement.getTableAlias() +
+				"}";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/Node.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/Node.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/Node.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,74 @@
+package org.hibernate.hql.ast.tree;
+
+import antlr.collections.AST;
+import antlr.Token;
+import org.hibernate.util.StringHelper;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Base node class for use by Hibernate within its AST trees.
+ *
+ * @author Joshua Davis
+ * @author Steve Ebersole
+ */
+public class Node extends antlr.CommonAST {
+	private String filename;
+	private int line;
+	private int column;
+	private int textLength;
+
+	public Node() {
+		super();
+	}
+
+	public Node(Token tok) {
+		super(tok);  // This will call initialize(tok)!
+	}
+
+	/**
+	 * Retrieve the text to be used for rendering this particular node.
+	 *
+	 * @param sessionFactory The session factory
+	 * @return The text to use for rendering
+	 */
+	public String getRenderText(SessionFactoryImplementor sessionFactory) {
+		// The basic implementation is to simply use the node's text
+		return getText();
+	}
+
+	public void initialize(Token tok) {
+		super.initialize(tok);
+		filename = tok.getFilename();
+		line = tok.getLine();
+		column = tok.getColumn();
+		String text = tok.getText();
+		textLength = StringHelper.isEmpty(text) ? 0 : text.length();
+	}
+
+	public void initialize(AST t) {
+		super.initialize( t );
+		if ( t instanceof Node ) {
+			Node n = (Node)t;
+			filename = n.filename;
+			line = n.line;
+			column = n.column;
+			textLength = n.textLength;
+		}
+	}
+
+	public String getFilename() {
+		return filename;
+	}
+
+	public int getLine() {
+		return line;
+	}
+
+	public int getColumn() {
+		return column;
+	}
+
+	public int getTextLength() {
+		return textLength;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/OperatorNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/OperatorNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/OperatorNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.type.Type;
+import antlr.SemanticException;
+
+/**
+ * Contract for nodes representing operators (logic or arithmetic).
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public interface OperatorNode {
+	/**
+	 * Called by the tree walker during hql-sql semantic analysis
+	 * after the operator sub-tree is completely built.
+	 */
+	public abstract void initialize() throws SemanticException;
+
+	/**
+	 * Retrieves the data type for the overall operator expression.
+	 *
+	 * @return The expression's data type.
+	 */
+	public Type getDataType();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/OrderByClause.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/OrderByClause.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/OrderByClause.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+// $Id: OrderByClause.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.hql.ast.util.ASTUtil;
+
+import antlr.collections.AST;
+
+/**
+ * Implementation of OrderByClause.
+ *
+ * @author Steve Ebersole
+ */
+public class OrderByClause extends HqlSqlWalkerNode implements HqlSqlTokenTypes {
+
+	public void addOrderFragment(String orderByFragment) {
+		AST fragment = ASTUtil.create( getASTFactory(), SQL_TOKEN, orderByFragment );
+		if ( getFirstChild() == null ) {
+            setFirstChild( fragment );
+		}
+		else {
+			addChild( fragment );
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ParameterNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ParameterNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ParameterNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+// $Id: ParameterNode.java 10060 2006-06-28 02:53:39Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.param.ParameterSpecification;
+import org.hibernate.type.Type;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Implementation of ParameterNode.
+ *
+ * @author Steve Ebersole
+ */
+public class ParameterNode extends HqlSqlWalkerNode implements DisplayableNode, ExpectedTypeAwareNode {
+	private ParameterSpecification parameterSpecification;
+
+	public ParameterSpecification getHqlParameterSpecification() {
+		return parameterSpecification;
+	}
+
+	public void setHqlParameterSpecification(ParameterSpecification parameterSpecification) {
+		this.parameterSpecification = parameterSpecification;
+	}
+
+	public String getDisplayText() {
+		return "{" + ( parameterSpecification == null ? "???" : parameterSpecification.renderDisplayInfo() ) + "}";
+	}
+
+	public void setExpectedType(Type expectedType) {
+		getHqlParameterSpecification().setExpectedType( expectedType );
+		setDataType( expectedType );
+	}
+
+	public Type getExpectedType() {
+		return getHqlParameterSpecification() == null ? null : getHqlParameterSpecification().getExpectedType();
+	}
+
+	public String getRenderText(SessionFactoryImplementor sessionFactory) {
+		int count = 0;
+		if ( getExpectedType() != null && ( count = getExpectedType().getColumnSpan( sessionFactory ) ) > 1 ) {
+			StringBuffer buffer = new StringBuffer();
+			buffer.append( "(?" );
+			for ( int i = 1; i < count; i++ ) {
+				buffer.append( ", ?" );
+			}
+			buffer.append( ")" );
+			return buffer.toString();
+		}
+		else {
+			return "?";
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/PathNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/PathNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/PathNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+// $Id: PathNode.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+/**
+ * An AST node with a path property.  This path property will be the fully qualified name.
+ *
+ * @author josh Nov 7, 2004 10:56:49 AM
+ */
+public interface PathNode {
+	/**
+	 * Returns the full path name represented by the node.
+	 *
+	 * @return the full path name represented by the node.
+	 */
+	String getPath();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/QueryNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/QueryNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/QueryNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,133 @@
+// $Id: QueryNode.java 7486 2005-07-15 04:39:41Z oneovthafew $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.hql.antlr.SqlTokenTypes;
+import org.hibernate.hql.ast.util.ASTUtil;
+import org.hibernate.hql.ast.util.ColumnHelper;
+import org.hibernate.type.Type;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Defines a top-level AST node representing an HQL select statement.
+ *
+ * @author Joshua Davis
+ */
+public class QueryNode extends AbstractRestrictableStatement implements SelectExpression {
+
+	private static final Log log = LogFactory.getLog( QueryNode.class );
+
+	private OrderByClause orderByClause;
+
+	/**
+	 * @see Statement#getStatementType() 
+	 */
+	public int getStatementType() {
+		return HqlSqlTokenTypes.QUERY;
+	}
+
+	/**
+	 * @see Statement#needsExecutor()
+	 */
+	public boolean needsExecutor() {
+		return false;
+	}
+
+	protected int getWhereClauseParentTokenType() {
+		return SqlTokenTypes.FROM;
+	}
+
+	protected Log getLog() {
+		return log;
+	}
+
+	/**
+	 * Locate the select clause that is part of this select statement.
+	 * </p>
+	 * Note, that this might return null as derived select clauses (i.e., no
+	 * select clause at the HQL-level) get generated much later than when we
+	 * get created; thus it depends upon lifecycle.
+	 *
+	 * @return Our select clause, or null.
+	 */
+	public final SelectClause getSelectClause() {
+		// Due to the complexity in initializing the SelectClause, do not generate one here.
+		// If it is not found; simply return null...
+		//
+		// Also, do not cache since it gets generated well after we are created.
+		return ( SelectClause ) ASTUtil.findTypeInChildren( this, SqlTokenTypes.SELECT_CLAUSE );
+	}
+
+	public final boolean hasOrderByClause() {
+		OrderByClause orderByClause = locateOrderByClause();
+		return orderByClause != null && orderByClause.getNumberOfChildren() > 0;
+	}
+
+	public final OrderByClause getOrderByClause() {
+		if ( orderByClause == null ) {
+			orderByClause = locateOrderByClause();
+
+			// if there is no order by, make one
+			if ( orderByClause == null ) {
+				log.debug( "getOrderByClause() : Creating a new ORDER BY clause" );
+				orderByClause = ( OrderByClause ) ASTUtil.create( getWalker().getASTFactory(), SqlTokenTypes.ORDER, "ORDER" );
+
+				// Find the WHERE; if there is no WHERE, find the FROM...
+				AST prevSibling = ASTUtil.findTypeInChildren( this, SqlTokenTypes.WHERE );
+				if ( prevSibling == null ) {
+					prevSibling = ASTUtil.findTypeInChildren( this, SqlTokenTypes.FROM );
+				}
+
+				// Now, inject the newly built ORDER BY into the tree
+				orderByClause.setNextSibling( prevSibling.getNextSibling() );
+				prevSibling.setNextSibling( orderByClause );
+			}
+		}
+		return orderByClause;
+	}
+
+	private OrderByClause locateOrderByClause() {
+		return ( OrderByClause ) ASTUtil.findTypeInChildren( this, SqlTokenTypes.ORDER );
+	}
+	
+	
+	private String alias;
+
+	public String getAlias() {
+		return alias;
+	}
+
+	public FromElement getFromElement() {
+		return null;
+	}
+
+	public boolean isConstructor() {
+		return false;
+	}
+
+	public boolean isReturnableEntity() throws SemanticException {
+		return false;
+	}
+
+	public boolean isScalar() throws SemanticException {
+		return true;
+	}
+
+	public void setAlias(String alias) {
+		this.alias = alias;
+	}
+
+	public void setScalarColumnText(int i) throws SemanticException {
+		ColumnHelper.generateSingleScalarColumn( this, i );
+	}
+
+	public Type getDataType() {
+		return ( (SelectExpression) getSelectClause().getFirstSelectExpression() ).getDataType();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ResolvableNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ResolvableNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/ResolvableNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+// $Id: ResolvableNode.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+/**
+ * The contract for expression sub-trees that can resolve themselves.
+ *
+ * @author josh Sep 25, 2004 11:27:36 AM
+ */
+public interface ResolvableNode {
+	/**
+	 * Does the work of resolving an identifier or a dot
+	 */
+	void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent) throws SemanticException;
+
+	/**
+	 * Does the work of resolving an identifier or a dot, but without a parent node
+	 */
+	void resolve(boolean generateJoin, boolean implicitJoin, String classAlias) throws SemanticException;
+
+	/**
+	 * Does the work of resolving an identifier or a dot, but without a parent node or alias
+	 */
+	void resolve(boolean generateJoin, boolean implicitJoin) throws SemanticException;
+
+	/**
+	 * Does the work of resolving inside of the scope of a function call
+	 */
+	void resolveInFunctionCall(boolean generateJoin, boolean implicitJoin) throws SemanticException;
+
+	/**
+	 * Does the work of resolving an an index [].
+	 */
+	void resolveIndex(AST parent) throws SemanticException;
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/RestrictableStatement.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/RestrictableStatement.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/RestrictableStatement.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+// $Id: RestrictableStatement.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import antlr.collections.AST;
+
+/**
+ * Type definition for Statements which are restrictable via a where-clause (and
+ * thus also having a from-clause).
+ *
+ * @author Steve Ebersole
+ */
+public interface RestrictableStatement extends Statement {
+	/**
+	 * Retreives the from-clause in effect for this statement.
+	 *
+	 * @return The from-clause for this statement; could be null if the from-clause
+	 * has not yet been parsed/generated.
+	 */
+	public FromClause getFromClause();
+
+	/**
+	 * Does this statement tree currently contain a where clause?
+	 *
+	 * @return True if a where-clause is found in the statement tree and
+	 * that where clause actually defines restrictions; false otherwise.
+	 */
+	public boolean hasWhereClause();
+
+	/**
+	 * Retreives the where-clause defining the restriction(s) in effect for
+	 * this statement.
+	 * <p/>
+	 * Note that this will generate a where-clause if one was not found, so caution
+	 * needs to taken prior to calling this that restrictions will actually exist
+	 * in the resulting statement tree (otherwise "unexpected end of subtree" errors
+	 * might occur during rendering).
+	 *
+	 * @return The where clause.
+	 */
+	public AST getWhereClause();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectClause.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectClause.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectClause.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,442 @@
+// $Id: SelectClause.java 10527 2006-09-25 15:13:41Z epbernard $
+package org.hibernate.hql.ast.tree;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.hql.antlr.SqlTokenTypes;
+import org.hibernate.hql.ast.util.ASTAppender;
+import org.hibernate.hql.ast.util.ASTIterator;
+import org.hibernate.hql.ast.util.ASTPrinter;
+import org.hibernate.hql.ast.QuerySyntaxException;
+import org.hibernate.type.Type;
+import org.hibernate.QueryException;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+/**
+ * Represents the list of expressions in a SELECT clause.
+ *
+ * @author josh Sep 21, 2004 7:53:55 AM
+ */
+public class SelectClause extends SelectExpressionList {
+
+	private boolean prepared = false;
+	private boolean scalarSelect;
+
+	private List fromElementsForLoad = new ArrayList();
+	//private Type[] sqlResultTypes;
+	private Type[] queryReturnTypes;
+	private String[][] columnNames;
+	private ConstructorNode constructorNode;
+	private List collectionFromElements;
+	private String[] aliases;
+
+	/**
+	 * Does this SelectClause represent a scalar query
+	 *
+	 * @return True if this is a scalara select clause; false otherwise.
+	 */
+	public boolean isScalarSelect() {
+		return scalarSelect;
+	}
+
+	public boolean isDistinct() {
+		return getFirstChild() != null && getFirstChild().getType() == SqlTokenTypes.DISTINCT;
+	}
+
+	/**
+	 * FromElements which need to be accounted for in the load phase (either for return or for fetch).
+	 *
+	 * @return List of appropriate FromElements.
+	 */
+	public List getFromElementsForLoad() {
+		return fromElementsForLoad;
+	}
+
+	/*
+	 * The types represented in the SQL result set.
+	 *
+	 * @return The types represented in the SQL result set.
+	 */
+	/*public Type[] getSqlResultTypes() {
+		return sqlResultTypes;
+	}*/
+
+	/**
+	 * The types actually being returned from this query at the "object level".
+	 *
+	 * @return The query return types.
+	 */
+	public Type[] getQueryReturnTypes() {
+		return queryReturnTypes;
+	}
+	
+	/**
+	 * The HQL aliases, or generated aliases
+	 */
+	public String[] getQueryReturnAliases() {
+		return aliases;
+	}
+
+	/**
+	 * The column alias names being used in the generated SQL.
+	 *
+	 * @return The SQL column aliases.
+	 */
+	public String[][] getColumnNames() {
+		return columnNames;
+	}
+
+	/**
+	 * The constructor to use for dynamic instantiation queries.
+	 *
+	 * @return The appropriate Constructor reference, or null if not a
+	 *         dynamic instantiation query.
+	 */
+	public Constructor getConstructor() {
+		return constructorNode == null ? null : constructorNode.getConstructor();
+	}
+	
+	public boolean isMap() {
+		return constructorNode == null ? false : constructorNode.isMap();
+	}
+	
+	public boolean isList() {
+		return constructorNode == null ? false : constructorNode.isList();
+	}
+	
+	/**
+	 * Prepares an explicitly defined select clause.
+	 *
+	 * @param fromClause The from clause linked to this select clause.
+	 * @throws SemanticException
+	 */
+	public void initializeExplicitSelectClause(FromClause fromClause) throws SemanticException {
+		if ( prepared ) {
+			throw new IllegalStateException( "SelectClause was already prepared!" );
+		}
+
+		//explicit = true;	// This is an explict Select.
+		//ArrayList sqlResultTypeList = new ArrayList();
+		ArrayList queryReturnTypeList = new ArrayList();
+
+		// First, collect all of the select expressions.
+		// NOTE: This must be done *before* invoking setScalarColumnText() because setScalarColumnText()
+		// changes the AST!!!
+		SelectExpression[] selectExpressions = collectSelectExpressions();
+		
+		for ( int i = 0; i < selectExpressions.length; i++ ) {
+			SelectExpression expr = selectExpressions[i];
+
+			if ( expr.isConstructor() ) {
+				constructorNode = ( ConstructorNode ) expr;
+				List constructorArgumentTypeList = constructorNode.getConstructorArgumentTypeList();
+				//sqlResultTypeList.addAll( constructorArgumentTypeList );
+				queryReturnTypeList.addAll( constructorArgumentTypeList );
+				scalarSelect = true;
+			}
+			else {
+				Type type = expr.getDataType();
+				if ( type == null ) {
+					throw new IllegalStateException( "No data type for node: " + expr.getClass().getName() + " "
+							+ new ASTPrinter( SqlTokenTypes.class ).showAsString( ( AST ) expr, "" ) );
+				}
+				//sqlResultTypeList.add( type );
+
+				// If the data type is not an association type, it could not have been in the FROM clause.
+				if ( expr.isScalar() ) {
+					scalarSelect = true;
+				}
+
+				if ( isReturnableEntity( expr ) ) {
+					fromElementsForLoad.add( expr.getFromElement() );
+				}
+
+				// Always add the type to the return type list.
+				queryReturnTypeList.add( type );
+			}
+		}
+
+		//init the aliases, after initing the constructornode
+		initAliases(selectExpressions);
+
+		if ( !getWalker().isShallowQuery() ) {
+			// add the fetched entities
+			List fromElements = fromClause.getProjectionList();
+	
+			ASTAppender appender = new ASTAppender( getASTFactory(), this );	// Get ready to start adding nodes.
+			int size = fromElements.size();
+	
+			Iterator iterator = fromElements.iterator();
+			for ( int k = 0; iterator.hasNext(); k++ ) {
+				FromElement fromElement = ( FromElement ) iterator.next();
+	
+				if ( fromElement.isFetch() ) {
+					FromElement origin = null;
+					if ( fromElement.getRealOrigin() == null ) {
+						// work around that crazy issue where the tree contains
+						// "empty" FromElements (no text); afaict, this is caused
+						// by FromElementFactory.createCollectionJoin()
+						if ( fromElement.getOrigin() == null ) {
+							throw new QueryException( "Unable to determine origin of join fetch [" + fromElement.getDisplayText() + "]" );
+						}
+						else {
+							origin = fromElement.getOrigin();
+						}
+					}
+					else {
+						origin = fromElement.getRealOrigin();
+					}
+					if ( !fromElementsForLoad.contains( origin ) ) {
+						throw new QueryException(
+								"query specified join fetching, but the owner " +
+								"of the fetched association was not present in the select list " +
+								"[" + fromElement.getDisplayText() + "]"
+						);
+					}
+					Type type = fromElement.getSelectType();
+					addCollectionFromElement( fromElement );
+					if ( type != null ) {
+						boolean collectionOfElements = fromElement.isCollectionOfValuesOrComponents();
+						if ( !collectionOfElements ) {
+							// Add the type to the list of returned sqlResultTypes.
+							fromElement.setIncludeSubclasses( true );
+							fromElementsForLoad.add( fromElement );
+							//sqlResultTypeList.add( type );
+							// Generate the select expression.
+							String text = fromElement.renderIdentifierSelect( size, k );
+							SelectExpressionImpl generatedExpr = ( SelectExpressionImpl ) appender.append( SqlTokenTypes.SELECT_EXPR, text, false );
+							if ( generatedExpr != null ) {
+								generatedExpr.setFromElement( fromElement );
+							}
+						}
+					}
+				}
+			}
+	
+			// generate id select fragment and then property select fragment for
+			// each expression, just like generateSelectFragments().
+			renderNonScalarSelects( collectSelectExpressions(), fromClause );
+		}
+
+		if ( scalarSelect || getWalker().isShallowQuery() ) {
+			// If there are any scalars (non-entities) selected, render the select column aliases.
+			renderScalarSelects( selectExpressions, fromClause );
+		}
+
+		finishInitialization( /*sqlResultTypeList,*/ queryReturnTypeList );
+	}
+
+	private void finishInitialization(/*ArrayList sqlResultTypeList,*/ ArrayList queryReturnTypeList) {
+		//sqlResultTypes = ( Type[] ) sqlResultTypeList.toArray( new Type[sqlResultTypeList.size()] );
+		queryReturnTypes = ( Type[] ) queryReturnTypeList.toArray( new Type[queryReturnTypeList.size()] );
+		initializeColumnNames();
+		prepared = true;
+	}
+
+	private void initializeColumnNames() {
+		// Generate an 2d array of column names, the first dimension is parallel with the
+		// return types array.  The second dimension is the list of column names for each
+		// type.
+
+		// todo: we should really just collect these from the various SelectExpressions, rather than regenerating here
+		columnNames = getSessionFactoryHelper().generateColumnNames( queryReturnTypes );
+	}
+
+	/**
+	 * Prepares a derived (i.e., not explicitly defined in the query) select clause.
+	 *
+	 * @param fromClause The from clause to which this select clause is linked.
+	 */
+	public void initializeDerivedSelectClause(FromClause fromClause) throws SemanticException {
+		if ( prepared ) {
+			throw new IllegalStateException( "SelectClause was already prepared!" );
+		}
+		//Used to be tested by the TCK but the test is no longer here
+//		if ( getSessionFactoryHelper().isStrictJPAQLComplianceEnabled() && !getWalker().isSubQuery() ) {
+//			// NOTE : the isSubQuery() bit is a temporary hack...
+//			throw new QuerySyntaxException( "JPA-QL compliance requires select clause" );
+//		}
+		List fromElements = fromClause.getProjectionList();
+
+		ASTAppender appender = new ASTAppender( getASTFactory(), this );	// Get ready to start adding nodes.
+		int size = fromElements.size();
+		ArrayList sqlResultTypeList = new ArrayList( size );
+		ArrayList queryReturnTypeList = new ArrayList( size );
+
+		Iterator iterator = fromElements.iterator();
+		for ( int k = 0; iterator.hasNext(); k++ ) {
+			FromElement fromElement = ( FromElement ) iterator.next();
+			Type type = fromElement.getSelectType();
+
+			addCollectionFromElement( fromElement );
+
+			if ( type != null ) {
+				boolean collectionOfElements = fromElement.isCollectionOfValuesOrComponents();
+				if ( !collectionOfElements ) {
+					if ( !fromElement.isFetch() ) {
+						// Add the type to the list of returned sqlResultTypes.
+						queryReturnTypeList.add( type );
+					}
+					fromElementsForLoad.add( fromElement );
+					sqlResultTypeList.add( type );
+					// Generate the select expression.
+					String text = fromElement.renderIdentifierSelect( size, k );
+					SelectExpressionImpl generatedExpr = ( SelectExpressionImpl ) appender.append( SqlTokenTypes.SELECT_EXPR, text, false );
+					if ( generatedExpr != null ) {
+						generatedExpr.setFromElement( fromElement );
+					}
+				}
+			}
+		}
+
+		// Get all the select expressions (that we just generated) and render the select.
+		SelectExpression[] selectExpressions = collectSelectExpressions();
+
+		if ( getWalker().isShallowQuery() ) {
+			renderScalarSelects( selectExpressions, fromClause );
+		}
+		else {
+			renderNonScalarSelects( selectExpressions, fromClause );
+		}
+		finishInitialization( /*sqlResultTypeList,*/ queryReturnTypeList );
+	}
+	
+	public static boolean VERSION2_SQL = false;
+
+	private void addCollectionFromElement(FromElement fromElement) {
+		if ( fromElement.isFetch() ) {
+			if ( fromElement.isCollectionJoin() || fromElement.getQueryableCollection() != null ) {
+				String suffix;
+				if (collectionFromElements==null) {
+					collectionFromElements = new ArrayList();
+					suffix = VERSION2_SQL ? "__" : "0__";
+				}
+				else {
+					suffix = Integer.toString( collectionFromElements.size() ) + "__";
+				}
+				collectionFromElements.add( fromElement );
+				fromElement.setCollectionSuffix( suffix );
+			}
+		}
+	}
+
+	protected AST getFirstSelectExpression() {
+		AST n = getFirstChild();
+		// Skip 'DISTINCT' and 'ALL', so we return the first expression node.
+		while ( n != null && ( n.getType() == SqlTokenTypes.DISTINCT || n.getType() == SqlTokenTypes.ALL ) ) {
+			n = n.getNextSibling();
+		}
+		return n;
+	}
+
+	private boolean isReturnableEntity(SelectExpression selectExpression) throws SemanticException {
+		FromElement fromElement = selectExpression.getFromElement();
+		boolean isFetchOrValueCollection = fromElement != null && 
+				( fromElement.isFetch() || fromElement.isCollectionOfValuesOrComponents() ); 
+		if ( isFetchOrValueCollection ) {
+			return false;
+		}
+		else {
+			return selectExpression.isReturnableEntity();
+		}
+	}
+
+	private void renderScalarSelects(SelectExpression[] se, FromClause currentFromClause) throws SemanticException {
+		if ( !currentFromClause.isSubQuery() ) {
+			for ( int i = 0; i < se.length; i++ ) {
+				SelectExpression expr = se[i];
+				expr.setScalarColumnText( i );	// Create SQL_TOKEN nodes for the columns.
+			}
+		}
+	}
+	
+	private void initAliases(SelectExpression[] selectExpressions) {
+		if (constructorNode==null) {
+			aliases = new String[selectExpressions.length];
+			for ( int i=0; i<selectExpressions.length; i++ ) {
+				String alias = selectExpressions[i].getAlias();
+				aliases[i] = alias==null ? Integer.toString(i) : alias;
+			}
+		}
+		else {
+			aliases = constructorNode.getAliases();
+		}
+	}
+
+	private void renderNonScalarSelects(SelectExpression[] selectExpressions, FromClause currentFromClause) 
+	throws SemanticException {
+		ASTAppender appender = new ASTAppender( getASTFactory(), this );
+		final int size = selectExpressions.length;
+		int nonscalarSize = 0;
+		for ( int i = 0; i < size; i++ ) {
+			if ( !selectExpressions[i].isScalar() ) nonscalarSize++;
+		}
+
+		int j = 0;
+		for ( int i = 0; i < size; i++ ) {
+			if ( !selectExpressions[i].isScalar() ) {
+				SelectExpression expr = selectExpressions[i];
+				FromElement fromElement = expr.getFromElement();
+				if ( fromElement != null ) {
+					renderNonScalarIdentifiers( fromElement, nonscalarSize, j, expr, appender );
+					j++;
+				}
+			}
+		}
+
+		if ( !currentFromClause.isSubQuery() ) {
+			// Generate the property select tokens.
+			int k = 0;
+			for ( int i = 0; i < size; i++ ) {
+				if ( !selectExpressions[i].isScalar() ) {
+					FromElement fromElement = selectExpressions[i].getFromElement();
+					if ( fromElement != null ) {
+						renderNonScalarProperties( appender, fromElement, nonscalarSize, k );
+						k++;
+					}
+				}
+			}
+		}
+	}
+
+	private void renderNonScalarIdentifiers(FromElement fromElement, int nonscalarSize, int j, SelectExpression expr, ASTAppender appender) {
+		String text = fromElement.renderIdentifierSelect( nonscalarSize, j );
+		if ( !fromElement.getFromClause().isSubQuery() ) {
+			if ( !scalarSelect && !getWalker().isShallowQuery() ) {
+				//TODO: is this a bit ugly?
+				expr.setText( text );
+			}
+			else {
+				appender.append( SqlTokenTypes.SQL_TOKEN, text, false );
+			}
+		}
+	}
+
+	private void renderNonScalarProperties(ASTAppender appender, FromElement fromElement, int nonscalarSize, int k) {
+		String text = fromElement.renderPropertySelect( nonscalarSize, k );
+		appender.append( SqlTokenTypes.SQL_TOKEN, text, false );
+		if ( fromElement.getQueryableCollection() != null && fromElement.isFetch() ) {
+			text = fromElement.renderCollectionSelectFragment( nonscalarSize, k );
+			appender.append( SqlTokenTypes.SQL_TOKEN, text, false );
+		}
+		// Look through the FromElement's children to find any collections of values that should be fetched...
+		ASTIterator iter = new ASTIterator( fromElement );
+		while ( iter.hasNext() ) {
+			FromElement child = ( FromElement ) iter.next();
+			if ( child.isCollectionOfValuesOrComponents() && child.isFetch() ) {
+				// Need a better way to define the suffixes here...
+				text = child.renderValueCollectionSelectFragment( nonscalarSize, nonscalarSize + k );
+				appender.append( SqlTokenTypes.SQL_TOKEN, text, false );
+			}
+		}
+	}
+
+	public List getCollectionFromElements() {
+		return collectionFromElements;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpression.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpression.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpression.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,61 @@
+// $Id: SelectExpression.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.type.Type;
+
+import antlr.SemanticException;
+
+/**
+ * Represents an element of a projection list, i.e. a select expression.
+ *
+ * @author josh Sep 21, 2004 9:00:13 PM
+ */
+public interface SelectExpression {
+	/**
+	 * Returns the data type of the select expression.
+	 *
+	 * @return The data type of the select expression.
+	 */
+	Type getDataType();
+
+	/**
+	 * Appends AST nodes that represent the columns after the current AST node.
+	 * (e.g. 'as col0_O_')
+	 *
+	 * @param i The index of the select expression in the projection list.
+	 */
+	void setScalarColumnText(int i) throws SemanticException;
+
+	/**
+	 * Returns the FROM element that this expression refers to.
+	 *
+	 * @return The FROM element.
+	 */
+	FromElement getFromElement();
+
+	/**
+	 * Returns true if the element is a constructor (e.g. new Foo).
+	 *
+	 * @return true if the element is a constructor (e.g. new Foo).
+	 */
+	boolean isConstructor();
+
+	/**
+	 * Returns true if this select expression represents an entity that can be returned.
+	 *
+	 * @return true if this select expression represents an entity that can be returned.
+	 */
+	boolean isReturnableEntity() throws SemanticException;
+
+	/**
+	 * Sets the text of the node.
+	 *
+	 * @param text the new node text.
+	 */
+	void setText(String text);
+
+	boolean isScalar() throws SemanticException;
+	
+	void setAlias(String alias);
+	String getAlias();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpressionImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpressionImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpressionImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+// $Id: SelectExpressionImpl.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+/**
+ * A select expression that was generated by a FROM element.
+ *
+ * @author josh Nov 6, 2004 8:27:38 AM
+ */
+public class SelectExpressionImpl extends FromReferenceNode implements SelectExpression {
+
+	public void resolveIndex(AST parent) throws SemanticException {
+		throw new UnsupportedOperationException();
+	}
+
+	public void setScalarColumnText(int i) throws SemanticException {
+		String text = getFromElement().renderScalarIdentifierSelect( i );
+		setText( text );
+	}
+
+	public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent) throws SemanticException {
+		// Generated select expressions are already resolved, nothing to do.
+		return;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpressionList.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpressionList.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SelectExpressionList.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+// $Id: SelectExpressionList.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import java.util.ArrayList;
+
+import org.hibernate.hql.antlr.SqlTokenTypes;
+import org.hibernate.hql.ast.util.ASTPrinter;
+
+import antlr.collections.AST;
+
+/**
+ * Common behavior - a node that contains a list of select expressions.
+ *
+ * @author josh Nov 6, 2004 8:51:00 AM
+ */
+public abstract class SelectExpressionList extends HqlSqlWalkerNode {
+	/**
+	 * Returns an array of SelectExpressions gathered from the children of the given parent AST node.
+	 *
+	 * @return an array of SelectExpressions gathered from the children of the given parent AST node.
+	 */
+	public SelectExpression[] collectSelectExpressions() {
+		// Get the first child to be considered.  Sub-classes may do this differently in order to skip nodes that
+		// are not select expressions (e.g. DISTINCT).
+		AST firstChild = getFirstSelectExpression();
+		AST parent = this;
+		ArrayList list = new ArrayList( parent.getNumberOfChildren() );
+		for ( AST n = firstChild; n != null; n = n.getNextSibling() ) {
+			if ( n instanceof SelectExpression ) {
+				list.add( n );
+			}
+			else {
+				throw new IllegalStateException( "Unexpected AST: " + n.getClass().getName() + " " + new ASTPrinter( SqlTokenTypes.class ).showAsString( n, "" ) );
+			}
+		}
+		return ( SelectExpression[] ) list.toArray( new SelectExpression[list.size()] );
+	}
+
+	/**
+	 * Returns the first select expression node that should be considered when building the array of select
+	 * expressions.
+	 *
+	 * @return the first select expression node that should be considered when building the array of select
+	 *         expressions
+	 */
+	protected abstract AST getFirstSelectExpression();
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SessionFactoryAwareNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SessionFactoryAwareNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SessionFactoryAwareNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,12 @@
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Interface for nodes which require access to the SessionFactory
+ *
+ * @author Steve Ebersole
+ */
+public interface SessionFactoryAwareNode {
+	public void setSessionFactory(SessionFactoryImplementor sessionFactory);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SqlFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SqlFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SqlFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+// $Id: SqlFragment.java 8215 2005-09-23 16:51:56Z pgmjsd $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.sql.JoinFragment;
+
+/**
+ * Represents an SQL fragment in the AST.
+ *
+ * @author josh Dec 5, 2004 9:01:52 AM
+ */
+public class SqlFragment extends Node {
+	private JoinFragment joinFragment;
+	private FromElement fromElement;
+
+	public void setJoinFragment(JoinFragment joinFragment) {
+		this.joinFragment = joinFragment;
+	}
+
+	public boolean hasFilterCondition() {
+		return joinFragment.hasFilterCondition();
+	}
+
+	public void setFromElement(FromElement fromElement) {
+		this.fromElement = fromElement;
+	}
+
+	public FromElement getFromElement() {
+		return fromElement;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SqlNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SqlNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/SqlNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+// $Id: SqlNode.java 8215 2005-09-23 16:51:56Z pgmjsd $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.type.Type;
+
+/**
+ * A base AST node for the intermediate tree.
+ * User: josh
+ * Date: Dec 6, 2003
+ * Time: 10:29:14 AM
+ */
+public class SqlNode extends Node {
+	/**
+	 * The original text for the node, mostly for debugging.
+	 */
+	private String originalText;
+	/**
+	 * The data type of this node.  Null for 'no type'.
+	 */
+	private Type dataType;
+
+	public void setText(String s) {
+		super.setText( s );
+		if ( s != null && s.length() > 0 && originalText == null ) {
+			originalText = s;
+		}
+	}
+
+	public String getOriginalText() {
+		return originalText;
+	}
+
+	public Type getDataType() {
+		return dataType;
+	}
+
+	public void setDataType(Type dataType) {
+		this.dataType = dataType;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/Statement.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/Statement.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/Statement.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+// $Id: Statement.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.ast.HqlSqlWalker;
+
+/**
+ * Common interface modeling the different HQL statements (i.e., INSERT, UPDATE, DELETE, SELECT).
+ *
+ * @author Steve Ebersole
+ */
+public interface Statement {
+
+	/**
+	 * Retreive the "phase 2" walker which generated this statement tree.
+	 *
+	 * @return The HqlSqlWalker instance which generated this statement tree.
+	 */
+	public HqlSqlWalker getWalker();
+
+	/**
+	 * Return the main token type representing the type of this statement.
+	 *
+	 * @return The corresponding token type.
+	 */
+	public int getStatementType();
+
+	/**
+	 * Does this statement require the StatementExecutor?
+	 * </p>
+	 * Essentially, at the JDBC level, does this require an executeUpdate()?
+	 *
+	 * @return True if this statement should be handed off to the
+	 * StatementExecutor to be executed; false otherwise.
+	 */
+	public boolean needsExecutor();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UnaryArithmeticNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UnaryArithmeticNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UnaryArithmeticNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+//$Id: UnaryArithmeticNode.java 8407 2005-10-14 17:23:18Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.ast.util.ColumnHelper;
+import org.hibernate.type.Type;
+
+import antlr.SemanticException;
+
+public class UnaryArithmeticNode extends AbstractSelectExpression implements UnaryOperatorNode {
+
+	public Type getDataType() {
+		return ( ( SqlNode ) getOperand() ).getDataType();
+	}
+
+	public void setScalarColumnText(int i) throws SemanticException {
+		ColumnHelper.generateSingleScalarColumn( this, i );
+	}
+
+	public void initialize() {
+		// nothing to do; even if the operand is a parameter, no way we could
+		// infer an appropriate expected type here
+	}
+
+	public Node getOperand() {
+		return ( Node ) getFirstChild();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UnaryLogicOperatorNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UnaryLogicOperatorNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UnaryLogicOperatorNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.type.Type;
+import org.hibernate.Hibernate;
+
+/**
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class UnaryLogicOperatorNode extends SqlNode implements UnaryOperatorNode {
+	public Node getOperand() {
+		return ( Node ) getFirstChild();
+	}
+
+	public void initialize() {
+		// nothing to do; even if the operand is a parameter, no way we could
+		// infer an appropriate expected type here
+	}
+
+	public Type getDataType() {
+		// logic operators by definition resolve to booleans
+		return Hibernate.BOOLEAN;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UnaryOperatorNode.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UnaryOperatorNode.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UnaryOperatorNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+package org.hibernate.hql.ast.tree;
+
+/**
+ * Contract for nodes representing unary operators.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public interface UnaryOperatorNode extends OperatorNode {
+	/**
+	 * Retrievs the node representing the operator's single operand.
+	 * 
+	 * @return The operator's single operand.
+	 */
+	public Node getOperand();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UpdateStatement.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UpdateStatement.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/tree/UpdateStatement.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+// $Id: UpdateStatement.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.hql.antlr.SqlTokenTypes;
+import org.hibernate.hql.ast.util.ASTUtil;
+
+import antlr.collections.AST;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Defines a top-level AST node representing an HQL update statement.
+ *
+ * @author Steve Ebersole
+ */
+public class UpdateStatement extends AbstractRestrictableStatement {
+
+	private static final Log log = LogFactory.getLog( UpdateStatement.class );
+
+	/**
+	 * @see org.hibernate.hql.ast.tree.Statement#getStatementType()
+	 */
+	public int getStatementType() {
+		return SqlTokenTypes.UPDATE;
+	}
+
+	/**
+	 * @see org.hibernate.hql.ast.tree.Statement#needsExecutor()
+	 */
+	public boolean needsExecutor() {
+		return true;
+	}
+
+	protected int getWhereClauseParentTokenType() {
+		return SqlTokenTypes.SET;
+	}
+
+	protected Log getLog() {
+		return log;
+	}
+
+	public AST getSetClause() {
+		return ASTUtil.findTypeInChildren( this, HqlSqlTokenTypes.SET );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTAppender.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTAppender.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTAppender.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+// $Id: ASTAppender.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.util;
+
+import antlr.ASTFactory;
+import antlr.collections.AST;
+
+/**
+ * Appends child nodes to a parent efficiently.
+ *
+ * @author josh Jul 24, 2004 8:28:23 AM
+ */
+public class ASTAppender {
+	private AST parent;
+	private AST last;
+	private ASTFactory factory;
+
+	public ASTAppender(ASTFactory factory, AST parent) {
+		this( parent );
+		this.factory = factory;
+	}
+
+	public ASTAppender(AST parent) {
+		this.parent = parent;
+		this.last = ASTUtil.getLastChild( parent );
+	}
+
+	public AST append(int type, String text, boolean appendIfEmpty) {
+		if ( text != null && ( appendIfEmpty || text.length() > 0 ) ) {
+			return append( factory.create( type, text ) );
+		}
+		else {
+			return null;
+		}
+	}
+
+	public AST append(AST child) {
+		if ( last == null ) {
+			parent.setFirstChild( child );
+		}
+		else {
+			last.setNextSibling( child );
+		}
+		last = child;
+		return last;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTIterator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTIterator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTIterator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,70 @@
+// $Id: ASTIterator.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.util;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import antlr.collections.AST;
+
+/**
+ * Depth first iteration of an ANTLR AST.
+ *
+ * @author josh Sep 25, 2004 7:44:39 AM
+ */
+public class ASTIterator implements Iterator {
+	private AST next, current;
+	private LinkedList parents = new LinkedList();
+
+	public void remove() {
+		throw new UnsupportedOperationException( "remove() is not supported" );
+	}
+
+	public boolean hasNext() {
+		return next != null;
+	}
+
+	public Object next() {
+		return nextNode();
+	}
+
+	public ASTIterator(AST tree) {
+		next = tree;
+		down();
+	}
+
+	public AST nextNode() {
+		current = next;
+		if ( next != null ) {
+			AST nextSibling = next.getNextSibling();
+			if ( nextSibling == null ) {
+				next = pop();
+			}
+			else {
+				next = nextSibling;
+				down();
+			}
+		}
+		return current;
+	}
+
+	private void down() {
+		while ( next != null && next.getFirstChild() != null ) {
+			push( next );
+			next = next.getFirstChild();
+		}
+	}
+
+	private void push(AST parent) {
+		parents.addFirst( parent );
+	}
+
+	private AST pop() {
+		if ( parents.size() == 0 ) {
+			return null;
+		}
+		else {
+			return ( AST ) parents.removeFirst();
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTParentsFirstIterator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTParentsFirstIterator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTParentsFirstIterator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,73 @@
+// $Id: ASTParentsFirstIterator.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.util;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import antlr.collections.AST;
+
+/**
+ * Depth first iteration of an ANTLR AST.
+ *
+ * @author josh Sep 25, 2004 7:44:39 AM
+ */
+public class ASTParentsFirstIterator implements Iterator {
+	private AST next, current, tree;
+	private LinkedList parents = new LinkedList();
+
+	public void remove() {
+		throw new UnsupportedOperationException( "remove() is not supported" );
+	}
+
+	public boolean hasNext() {
+		return next != null;
+	}
+
+	public Object next() {
+		return nextNode();
+	}
+
+	public ASTParentsFirstIterator(AST tree) {
+		this.tree = next = tree;
+	}
+
+	public AST nextNode() {
+		current = next;
+		if ( next != null ) {
+			AST child = next.getFirstChild();
+			if ( child == null ) {
+				AST sibling = next.getNextSibling();
+				if ( sibling == null ) {
+					AST parent = pop();
+					while ( parent != null && parent.getNextSibling() == null )
+						parent = pop();
+					next = ( parent != null ) ? parent.getNextSibling() : null;
+				}
+				else {
+					next = sibling;
+				}
+			}
+			else {
+				if ( next != tree ) {
+					push( next );
+				}
+				next = child;
+			}
+		}
+		return current;
+	}
+
+	private void push(AST parent) {
+		parents.addFirst( parent );
+	}
+
+	private AST pop() {
+		if ( parents.size() == 0 ) {
+			return null;
+		}
+		else {
+			return ( AST ) parents.removeFirst();
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTPrinter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTPrinter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTPrinter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,262 @@
+// $Id: ASTPrinter.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hibernate.hql.ast.tree.DisplayableNode;
+import org.hibernate.util.StringHelper;
+
+import antlr.collections.AST;
+
+/**
+ * An 'ASCII art' AST printer for debugging ANTLR grammars.
+ *
+ * @author Joshua Davis (pgmjsd at sourceforge.net)
+ */
+public class ASTPrinter {
+	private Map tokenTypeNamesByTokenType;
+	private Class tokenTypeConstants;
+	private boolean showClassNames = true;
+
+	/**
+	 * Constructs an org.hibernate.hql.antlr.ASTPrinter, given the class that contains the token type
+	 * constants (typically the '{grammar}TokenTypes' interface generated by
+	 * ANTLR).
+	 *
+	 * @param tokenTypeConstants The class with token type constants in it.
+	 */
+	public ASTPrinter(Class tokenTypeConstants) {
+		this.tokenTypeConstants = tokenTypeConstants;
+	}
+
+	/**
+	 * Returns true if the node class names will be displayed.
+	 *
+	 * @return true if the node class names will be displayed.
+	 */
+	public boolean isShowClassNames() {
+		return showClassNames;
+	}
+
+	/**
+	 * Enables or disables AST node class name display.
+	 *
+	 * @param showClassNames true to enable class name display, false to disable
+	 */
+	public void setShowClassNames(boolean showClassNames) {
+		this.showClassNames = showClassNames;
+	}
+
+	/**
+	 * Prints the AST in 'ASCII art' tree form to the specified print stream.
+	 *
+	 * @param ast The AST to print.
+	 * @param out The print stream.
+	 */
+	private void showAst(AST ast, PrintStream out) {
+		showAst( ast, new PrintWriter( out ) );
+	}
+
+	/**
+	 * Prints the AST in 'ASCII art' tree form to the specified print writer.
+	 *
+	 * @param ast The AST to print.
+	 * @param pw  The print writer.
+	 */
+	public void showAst(AST ast, PrintWriter pw) {
+		ArrayList parents = new ArrayList();
+		showAst( parents, pw, ast );
+		pw.flush();
+	}
+
+	/**
+	 * Prints the AST in 'ASCII art' tree form into a string.
+	 *
+	 * @param ast    The AST to display.
+	 * @param header The header for the display.
+	 * @return The AST in 'ASCII art' form, as a string.
+	 */
+	public String showAsString(AST ast, String header) {
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		PrintStream ps = new PrintStream( baos );
+		ps.println( header );
+		showAst( ast, ps );
+		ps.flush();
+		return new String( baos.toByteArray() );
+	}
+
+	/**
+	 * Get a single token type name in the specified set of token type constants (interface).
+	 *
+	 * @param tokenTypeConstants Token type constants interface (e.g. HqlSqlTokenTypes.class).
+	 * @param type               The token type ( typically from ast.getType() ).
+	 * @return The token type name, *or* the integer value if the name could not be found for some reason.
+	 */
+	public static String getConstantName(Class tokenTypeConstants, int type) {
+		String tokenTypeName = null;
+		if ( tokenTypeConstants != null ) {
+			Field[] fields = tokenTypeConstants.getFields();
+			for ( int i = 0; i < fields.length; i++ ) {
+				Field field = fields[i];
+				tokenTypeName = getTokenTypeName( field, type, true );
+				if ( tokenTypeName != null ) {
+					break;	// Stop if found.
+				}
+			} // for
+		} // if type constants were provided
+
+		// Use the integer value if no token type name was found
+		if ( tokenTypeName == null ) {
+			tokenTypeName = Integer.toString( type );
+		}
+
+		return tokenTypeName;
+	}
+
+	private static String getTokenTypeName(Field field, int type, boolean checkType) {
+		if ( Modifier.isStatic( field.getModifiers() ) ) {
+			try {
+				Object value = field.get( null );
+				if ( !checkType ) {
+					return field.getName();
+				}
+				else if ( value instanceof Integer ) {
+					Integer integer = ( Integer ) value;
+					if ( integer.intValue() == type ) {
+						return field.getName();
+					}
+				} // if value is an integer
+			} // try
+			catch ( IllegalArgumentException ignore ) {
+			}
+			catch ( IllegalAccessException ignore ) {
+			}
+		} // if the field is static
+		return null;
+	}
+
+	/**
+	 * Returns the token type name for the given token type.
+	 *
+	 * @param type The token type.
+	 * @return String - The token type name from the token type constant class,
+	 *         or just the integer as a string if none exists.
+	 */
+	private String getTokenTypeName(int type) {
+		// If the class with the constants in it was not supplied, just
+		// use the integer token type as the token type name.
+		if ( tokenTypeConstants == null ) {
+			return Integer.toString( type );
+		}
+
+		// Otherwise, create a type id -> name map from the class if it
+		// hasn't already been created.
+		if ( tokenTypeNamesByTokenType == null ) {
+			Field[] fields = tokenTypeConstants.getFields();
+			tokenTypeNamesByTokenType = new HashMap();
+			String tokenTypeName = null;
+			for ( int i = 0; i < fields.length; i++ ) {
+				Field field = fields[i];
+				tokenTypeName = getTokenTypeName( field, type, false );
+				if ( tokenTypeName != null ) {
+					try {
+						tokenTypeNamesByTokenType.put( field.get( null ), field.getName() );
+					}
+					catch ( IllegalAccessException ignore ) {
+					}
+				}
+			} // for
+		} // if the map hasn't been created.
+
+		return ( String ) tokenTypeNamesByTokenType.get( new Integer( type ) );
+	}
+
+	private void showAst(ArrayList parents, PrintWriter pw, AST ast) {
+		if ( ast == null ) {
+			pw.println( "AST is null!" );
+			return;
+		}
+
+		for ( int i = 0; i < parents.size(); i++ ) {
+			AST parent = ( AST ) parents.get( i );
+			if ( parent.getNextSibling() == null ) {
+
+				pw.print( "   " );
+			}
+			else {
+				pw.print( " | " );
+			}
+		}
+
+		if ( ast.getNextSibling() == null ) {
+			pw.print( " \\-" );
+		}
+		else {
+			pw.print( " +-" );
+		}
+
+		showNode( pw, ast );
+
+		ArrayList newParents = new ArrayList( parents );
+		newParents.add( ast );
+		for ( AST child = ast.getFirstChild(); child != null; child = child.getNextSibling() ) {
+			showAst( newParents, pw, child );
+		}
+		newParents.clear();
+	}
+
+	private void showNode(PrintWriter pw, AST ast) {
+		String s = nodeToString( ast, isShowClassNames() );
+		pw.println( s );
+	}
+
+	public String nodeToString(AST ast, boolean showClassName) {
+		if ( ast == null ) {
+			return "{null}";
+		}
+		StringBuffer buf = new StringBuffer();
+		buf.append( "[" ).append( getTokenTypeName( ast.getType() ) ).append( "] " );
+		if ( showClassName ) {
+			buf.append( StringHelper.unqualify( ast.getClass().getName() ) ).append( ": " );
+		}
+
+        buf.append( "'" );
+        String text = ast.getText();
+        appendEscapedMultibyteChars(text, buf);
+        buf.append( "'" );
+		if ( ast instanceof DisplayableNode ) {
+			DisplayableNode displayableNode = ( DisplayableNode ) ast;
+			// Add a space before the display text.
+			buf.append( " " ).append( displayableNode.getDisplayText() );
+		}
+		String s = buf.toString();
+		return s;
+	}
+
+    public static void appendEscapedMultibyteChars(String text, StringBuffer buf) {
+        char[] chars = text.toCharArray();
+        for (int i = 0; i < chars.length; i++) {
+            char aChar = chars[i];
+            if (aChar > 256) {
+                buf.append("\\u");
+                buf.append(Integer.toHexString(aChar));
+            }
+            else
+                buf.append(aChar);
+        }
+    }
+
+    public static String escapeMultibyteChars(String text)
+    {
+        StringBuffer buf = new StringBuffer();
+        appendEscapedMultibyteChars(text,buf);
+        return buf.toString();
+    }
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTUtil.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTUtil.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ASTUtil.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,360 @@
+// $Id: ASTUtil.java 10000 2006-06-08 21:04:45Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import antlr.ASTFactory;
+import antlr.collections.AST;
+import antlr.collections.impl.ASTArray;
+
+/**
+ * Provides utility methods for AST traversal and manipulation.
+ *
+ * @author Joshua Davis (pgmjsd at sourceforge.net)
+ */
+public final class ASTUtil {
+	/**
+	 * Private empty constructor.
+	 * (or else checkstyle says: 'warning: Utility classes should not have a public or default constructor.')
+	 *
+	 * @deprecated (tell clover to ignore this)
+	 */
+	private ASTUtil() {
+	}
+
+	/**
+	 * Creates a single node AST.
+	 *
+	 * @param astFactory The factory.
+	 * @param type       The node type.
+	 * @param text       The node text.
+	 * @return AST - A single node tree.
+	 */
+	public static AST create(ASTFactory astFactory, int type, String text) {
+		AST node = astFactory.create( type, text );
+		return node;
+	}
+
+	/**
+	 * Creates a single node AST as a sibling.
+	 *
+	 * @param astFactory  The factory.
+	 * @param type        The node type.
+	 * @param text        The node text.
+	 * @param prevSibling The previous sibling.
+	 * @return AST - A single node tree.
+	 */
+	public static AST createSibling(ASTFactory astFactory, int type, String text, AST prevSibling) {
+		AST node = astFactory.create( type, text );
+		node.setNextSibling( prevSibling.getNextSibling() );
+		prevSibling.setNextSibling( node );
+		return node;
+	}
+
+	public static AST insertSibling(AST node, AST prevSibling) {
+		node.setNextSibling( prevSibling.getNextSibling() );
+		prevSibling.setNextSibling( node );
+		return node;
+	}
+
+	/**
+	 * Creates a 'binary operator' subtree, given the information about the
+	 * parent and the two child nodex.
+	 *
+	 * @param factory    The AST factory.
+	 * @param parentType The type of the parent node.
+	 * @param parentText The text of the parent node.
+	 * @param child1     The first child.
+	 * @param child2     The second child.
+	 * @return AST - A new sub-tree of the form "(parent child1 child2)"
+	 */
+	public static AST createBinarySubtree(ASTFactory factory, int parentType, String parentText, AST child1, AST child2) {
+		ASTArray array = createAstArray( factory, 3, parentType, parentText, child1 );
+		array.add( child2 );
+		return factory.make( array );
+	}
+
+	/**
+	 * Creates a single parent of the specified child (i.e. a 'unary operator'
+	 * subtree).
+	 *
+	 * @param factory    The AST factory.
+	 * @param parentType The type of the parent node.
+	 * @param parentText The text of the parent node.
+	 * @param child      The child.
+	 * @return AST - A new sub-tree of the form "(parent child)"
+	 */
+	public static AST createParent(ASTFactory factory, int parentType, String parentText, AST child) {
+		ASTArray array = createAstArray( factory, 2, parentType, parentText, child );
+		return factory.make( array );
+	}
+
+	public static AST createTree(ASTFactory factory, AST[] nestedChildren) {
+		AST[] array = new AST[2];
+		int limit = nestedChildren.length - 1;
+		for ( int i = limit; i >= 0; i-- ) {
+			if ( i != limit ) {
+				array[1] = nestedChildren[i + 1];
+				array[0] = nestedChildren[i];
+				factory.make( array );
+			}
+		}
+		return array[0];
+	}
+
+	/**
+	 * Finds the first node of the specified type in the chain of children.
+	 *
+	 * @param parent The parent
+	 * @param type   The type to find.
+	 * @return The first node of the specified type, or null if not found.
+	 */
+	public static AST findTypeInChildren(AST parent, int type) {
+		AST n = parent.getFirstChild();
+		while ( n != null && n.getType() != type ) {
+			n = n.getNextSibling();
+		}
+		return n;
+	}
+
+	/**
+	 * Returns the last direct child of 'n'.
+	 *
+	 * @param n The parent
+	 * @return The last direct child of 'n'.
+	 */
+	public static AST getLastChild(AST n) {
+		return getLastSibling( n.getFirstChild() );
+	}
+
+	/**
+	 * Returns the last sibling of 'a'.
+	 *
+	 * @param a The sibling.
+	 * @return The last sibling of 'a'.
+	 */
+	private static AST getLastSibling(AST a) {
+		AST last = null;
+		while ( a != null ) {
+			last = a;
+			a = a.getNextSibling();
+		}
+		return last;
+	}
+
+	/**
+	 * Returns the 'list' representation with some brackets around it for debugging.
+	 *
+	 * @param n The tree.
+	 * @return The list representation of the tree.
+	 */
+	public static String getDebugString(AST n) {
+		StringBuffer buf = new StringBuffer();
+		buf.append( "[ " );
+		buf.append( ( n == null ) ? "{null}" : n.toStringTree() );
+		buf.append( " ]" );
+		return buf.toString();
+	}
+
+	/**
+	 * Find the previous sibling in the parent for the given child.
+	 *
+	 * @param parent the parent node
+	 * @param child  the child to find the previous sibling of
+	 * @return the previous sibling of the child
+	 */
+	public static AST findPreviousSibling(AST parent, AST child) {
+		AST prev = null;
+		AST n = parent.getFirstChild();
+		while ( n != null ) {
+			if ( n == child ) {
+				return prev;
+			}
+			prev = n;
+			n = n.getNextSibling();
+		}
+		throw new IllegalArgumentException( "Child not found in parent!" );
+	}
+
+	/**
+	 * Determine if a given node (test) is a direct (throtle to one level down)
+	 * child of another given node (fixture).
+	 *
+	 * @param fixture The node against which to testto be checked for children.
+	 * @param test The node to be tested as being a child of the parent.
+	 * @return True if test is contained in the fixtures's direct children;
+	 * false otherwise.
+	 */
+	public static boolean isDirectChild(AST fixture, AST test) {
+		AST n = fixture.getFirstChild();
+		while ( n != null ) {
+			if ( n == test ) {
+				return true;
+			}
+			n = n.getNextSibling();
+		}
+		return false;
+	}
+
+	/**
+	 * Determine if a given node (test) is contained anywhere in the subtree
+	 * of another given node (fixture).
+	 *
+	 * @param fixture The node against which to testto be checked for children.
+	 * @param test The node to be tested as being a subtree child of the parent.
+	 * @return True if child is contained in the parent's collection of children.
+	 */
+	public static boolean isSubtreeChild(AST fixture, AST test) {
+		AST n = fixture.getFirstChild();
+		while ( n != null ) {
+			if ( n == test ) {
+				return true;
+			}
+			if ( n.getFirstChild() != null && isSubtreeChild( n, test ) ) {
+				return true;
+			}
+			n = n.getNextSibling();
+		}
+		return false;
+	}
+
+	/**
+	 * Makes the child node a sibling of the parent, reconnecting all siblings.
+	 *
+	 * @param parent the parent
+	 * @param child  the child
+	 */
+	public static void makeSiblingOfParent(AST parent, AST child) {
+		AST prev = findPreviousSibling( parent, child );
+		if ( prev != null ) {
+			prev.setNextSibling( child.getNextSibling() );
+		}
+		else { // child == parent.getFirstChild()
+			parent.setFirstChild( child.getNextSibling() );
+		}
+		child.setNextSibling( parent.getNextSibling() );
+		parent.setNextSibling( child );
+	}
+
+	public static String getPathText(AST n) {
+		StringBuffer buf = new StringBuffer();
+		getPathText( buf, n );
+		return buf.toString();
+	}
+
+	private static void getPathText(StringBuffer buf, AST n) {
+		AST firstChild = n.getFirstChild();
+		// If the node has a first child, recurse into the first child.
+		if ( firstChild != null ) {
+			getPathText( buf, firstChild );
+		}
+		// Append the text of the current node.
+		buf.append( n.getText() );
+		// If there is a second child (RHS), recurse into that child.
+		if ( firstChild != null && firstChild.getNextSibling() != null ) {
+			getPathText( buf, firstChild.getNextSibling() );
+		}
+	}
+
+	public static boolean hasExactlyOneChild(AST n) {
+		return n != null && n.getFirstChild() != null && n.getFirstChild().getNextSibling() == null;
+	}
+
+	public static void appendSibling(AST n, AST s) {
+		while ( n.getNextSibling() != null ) {
+			n = n.getNextSibling();
+		}
+		n.setNextSibling( s );
+	}
+
+	/**
+	 * Inserts the child as the first child of the parent, all other children are shifted over to the 'right'.
+	 *
+	 * @param parent the parent
+	 * @param child  the new first child
+	 */
+	public static void insertChild(AST parent, AST child) {
+		if ( parent.getFirstChild() == null ) {
+			parent.setFirstChild( child );
+		}
+		else {
+			AST n = parent.getFirstChild();
+			parent.setFirstChild( child );
+			child.setNextSibling( n );
+		}
+	}
+
+	/**
+	 * Filters nodes out of a tree.
+	 */
+	public static interface FilterPredicate {
+		/**
+		 * Returns true if the node should be filtered out.
+		 *
+		 * @param n The node.
+		 * @return true if the node should be filtered out, false to keep the node.
+		 */
+		boolean exclude(AST n);
+	}
+
+	/**
+	 * A predicate that uses inclusion, rather than exclusion semantics.
+	 */
+	public abstract static class IncludePredicate implements FilterPredicate {
+		public final boolean exclude(AST node) {
+			return !include( node );
+		}
+
+		public abstract boolean include(AST node);
+	}
+
+	private static ASTArray createAstArray(ASTFactory factory, int size, int parentType, String parentText, AST child1) {
+		ASTArray array = new ASTArray( size );
+		array.add( factory.create( parentType, parentText ) );
+		array.add( child1 );
+		return array;
+	}
+
+	public static List collectChildren(AST root, FilterPredicate predicate) {
+//		List children = new ArrayList();
+//		collectChildren( children, root, predicate );
+//		return children;
+		return new CollectingNodeVisitor( predicate ).collect( root );
+	}
+
+	private static class CollectingNodeVisitor implements NodeTraverser.VisitationStrategy {
+		private final FilterPredicate predicate;
+		private final List collectedNodes = new ArrayList();
+
+		public CollectingNodeVisitor(FilterPredicate predicate) {
+			this.predicate = predicate;
+		}
+
+		public void visit(AST node) {
+			if ( predicate == null || !predicate.exclude( node ) ) {
+				collectedNodes.add( node );
+			}
+		}
+
+		public List getCollectedNodes() {
+			return collectedNodes;
+		}
+
+		public List collect(AST root) {
+			NodeTraverser traverser = new NodeTraverser( this );
+			traverser.traverseDepthFirst( root );
+			return collectedNodes;
+		}
+	}
+
+	private static void collectChildren(List children, AST root, FilterPredicate predicate) {
+		for ( AST n = root.getFirstChild(); n != null; n = n.getNextSibling() ) {
+			if ( predicate == null || !predicate.exclude( n ) ) {
+				children.add( n );
+			}
+			collectChildren( children, n, predicate );
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/AliasGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/AliasGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/AliasGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+// $Id: AliasGenerator.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.util;
+
+import org.hibernate.util.StringHelper;
+
+/**
+ * Generates class/table/column aliases during semantic analysis and SQL rendering.
+ * <p/>
+ * Its essential purpose is to keep an internal counter to ensure that the
+ * generated aliases are unique.
+ */
+public class AliasGenerator {
+	private int next = 0;
+
+	private int nextCount() {
+		return next++;
+	}
+
+	public String createName(String name) {
+		return StringHelper.generateAlias( name, nextCount() );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ColumnHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ColumnHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/ColumnHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+// $Id: ColumnHelper.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.util;
+
+import org.hibernate.hql.NameGenerator;
+import org.hibernate.hql.antlr.SqlTokenTypes;
+import org.hibernate.hql.ast.tree.HqlSqlWalkerNode;
+
+import antlr.ASTFactory;
+import antlr.collections.AST;
+
+/**
+ * Provides utility methods for dealing with arrays of SQL column names.
+ *
+ * @author josh Jan 3, 2005 9:08:47 AM
+ */
+public final class ColumnHelper {
+
+	/**
+	 * @deprecated (tell clover to filter this out)
+	 */
+	private ColumnHelper() {
+	}
+
+	public static void generateSingleScalarColumn(HqlSqlWalkerNode node, int i) {
+		ASTFactory factory = node.getASTFactory();
+		ASTUtil.createSibling( factory, SqlTokenTypes.SELECT_COLUMNS, " as " + NameGenerator.scalarName( i, 0 ), node );
+	}
+
+	/**
+	 * Generates the scalar column AST nodes for a given array of SQL columns
+	 */
+	public static void generateScalarColumns(HqlSqlWalkerNode node, String sqlColumns[], int i) {
+		if ( sqlColumns.length == 1 ) {
+			generateSingleScalarColumn( node, i );
+		}
+		else {
+			ASTFactory factory = node.getASTFactory();
+			AST n = node;
+			n.setText( sqlColumns[0] );	// Use the DOT node to emit the first column name.
+			// Create the column names, folled by the column aliases.
+			for ( int j = 0; j < sqlColumns.length; j++ ) {
+				if ( j > 0 ) {
+					n = ASTUtil.createSibling( factory, SqlTokenTypes.SQL_TOKEN, sqlColumns[j], n );
+				}
+				n = ASTUtil.createSibling( factory, SqlTokenTypes.SELECT_COLUMNS, " as " + NameGenerator.scalarName( i, j ), n );
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/JoinProcessor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/JoinProcessor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/JoinProcessor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,164 @@
+// $Id: JoinProcessor.java 10824 2006-11-16 19:32:48Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.util;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.Collections;
+import java.util.List;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.engine.JoinSequence;
+import org.hibernate.hql.antlr.SqlTokenTypes;
+import org.hibernate.hql.ast.QueryTranslatorImpl;
+import org.hibernate.hql.ast.tree.FromClause;
+import org.hibernate.hql.ast.tree.FromElement;
+import org.hibernate.hql.ast.tree.QueryNode;
+import org.hibernate.hql.ast.tree.DotNode;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.util.StringHelper;
+
+import antlr.ASTFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Performs the post-processing of the join information gathered during semantic analysis.
+ * The join generating classes are complex, this encapsulates some of the JoinSequence-related
+ * code.
+ *
+ * @author Joshua Davis
+ */
+public class JoinProcessor implements SqlTokenTypes {
+
+	private static final Log log = LogFactory.getLog( JoinProcessor.class );
+
+	private QueryTranslatorImpl queryTranslatorImpl;
+	private SyntheticAndFactory andFactory;
+
+	/**
+	 * Constructs a new JoinProcessor.
+	 *
+	 * @param astFactory		  The factory for AST node creation.
+	 * @param queryTranslatorImpl The query translator.
+	 */
+	public JoinProcessor(ASTFactory astFactory, QueryTranslatorImpl queryTranslatorImpl) {
+		this.andFactory = new SyntheticAndFactory( astFactory );
+		this.queryTranslatorImpl = queryTranslatorImpl;
+	}
+
+	/**
+	 * Translates an AST join type (i.e., the token type) into a JoinFragment.XXX join type.
+	 *
+	 * @param astJoinType The AST join type (from HqlSqlTokenTypes or SqlTokenTypes)
+	 * @return a JoinFragment.XXX join type.
+	 * @see JoinFragment
+	 * @see SqlTokenTypes
+	 */
+	public static int toHibernateJoinType(int astJoinType) {
+		switch ( astJoinType ) {
+			case LEFT_OUTER:
+				return JoinFragment.LEFT_OUTER_JOIN;
+			case INNER:
+				return JoinFragment.INNER_JOIN;
+			case RIGHT_OUTER:
+				return JoinFragment.RIGHT_OUTER_JOIN;
+			default:
+				throw new AssertionFailure( "undefined join type " + astJoinType );
+		}
+	}
+
+	public void processJoins(QueryNode query, boolean inSubquery) {
+		final FromClause fromClause = query.getFromClause();
+
+		final List fromElements;
+		if ( DotNode.useThetaStyleImplicitJoins ) {
+			// for regression testing against output from the old parser...
+			// found it easiest to simply reorder the FromElements here into ascending order
+			// in terms of injecting them into the resulting sql ast in orders relative to those
+			// expected by the old parser; this is definitely another of those "only needed
+			// for regression purposes".  The SyntheticAndFactory, then, simply injects them as it
+			// encounters them.
+			fromElements = new ArrayList();
+			ListIterator liter = fromClause.getFromElements().listIterator( fromClause.getFromElements().size() );
+			while ( liter.hasPrevious() ) {
+				fromElements.add( liter.previous() );
+			}
+		}
+		else {
+			fromElements = fromClause.getFromElements();
+		}
+
+		// Iterate through the alias,JoinSequence pairs and generate SQL token nodes.
+		Iterator iter = fromElements.iterator();
+		while ( iter.hasNext() ) {
+			final FromElement fromElement = ( FromElement ) iter.next();
+			JoinSequence join = fromElement.getJoinSequence();
+			join.setSelector(
+					new JoinSequence.Selector() {
+						public boolean includeSubclasses(String alias) {
+							// The uber-rule here is that we need to include  subclass joins if
+							// the FromElement is in any way dereferenced by a property from
+							// the subclass table; otherwise we end up with column references
+							// qualified by a non-existent table reference in the resulting SQL...
+							boolean containsTableAlias = fromClause.containsTableAlias( alias );
+							if ( fromElement.isDereferencedBySubclassProperty() ) {
+								// TODO : or should we return 'containsTableAlias'??
+								log.trace( "forcing inclusion of extra joins [alias=" + alias + ", containsTableAlias=" + containsTableAlias + "]" );
+								return true;
+							}
+							boolean shallowQuery = queryTranslatorImpl.isShallowQuery();
+							boolean includeSubclasses = fromElement.isIncludeSubclasses();
+							boolean subQuery = fromClause.isSubQuery();
+							return includeSubclasses && containsTableAlias && !subQuery && !shallowQuery;
+						}
+					}
+			);
+			addJoinNodes( query, join, fromElement, inSubquery );
+		}
+
+	}
+
+	private void addJoinNodes(QueryNode query, JoinSequence join, FromElement fromElement, boolean inSubquery) {
+		// Generate FROM and WHERE fragments for the from element.
+		JoinFragment joinFragment = join.toJoinFragment(
+				inSubquery ? Collections.EMPTY_MAP : queryTranslatorImpl.getEnabledFilters(),
+				fromElement.useFromFragment() || fromElement.isDereferencedBySuperclassOrSubclassProperty(),
+				fromElement.getWithClauseFragment(),
+				fromElement.getWithClauseJoinAlias()
+		);
+
+		String frag = joinFragment.toFromFragmentString();
+		String whereFrag = joinFragment.toWhereFragmentString();
+
+		// If the from element represents a JOIN_FRAGMENT and it is
+		// a theta-style join, convert its type from JOIN_FRAGMENT
+		// to FROM_FRAGMENT
+		if ( fromElement.getType() == JOIN_FRAGMENT &&
+				( join.isThetaStyle() || StringHelper.isNotEmpty( whereFrag ) ) ) {
+			fromElement.setType( FROM_FRAGMENT );
+			fromElement.getJoinSequence().setUseThetaStyle( true ); // this is used during SqlGenerator processing
+		}
+
+		// If there is a FROM fragment and the FROM element is an explicit, then add the from part.
+		if ( fromElement.useFromFragment() /*&& StringHelper.isNotEmpty( frag )*/ ) {
+			String fromFragment = processFromFragment( frag, join );
+			if ( log.isDebugEnabled() ) {
+				log.debug( "Using FROM fragment [" + fromFragment + "]" );
+			}
+			fromElement.setText( fromFragment.trim() ); // Set the text of the fromElement.
+		}
+		andFactory.addWhereFragment( joinFragment, whereFrag, query, fromElement );
+	}
+
+	private String processFromFragment(String frag, JoinSequence join) {
+		String fromFragment = frag.trim();
+		// The FROM fragment will probably begin with ', '.  Remove this if it is present.
+		if ( fromFragment.startsWith( ", " ) ) {
+			fromFragment = fromFragment.substring( 2 );
+		}
+		return fromFragment;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/LiteralProcessor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/LiteralProcessor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/LiteralProcessor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,297 @@
+// $Id: LiteralProcessor.java 11257 2007-03-07 22:39:25Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.util;
+
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.hql.QueryTranslator;
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.hql.antlr.SqlTokenTypes;
+import org.hibernate.hql.ast.HqlSqlWalker;
+import org.hibernate.hql.ast.InvalidPathException;
+import org.hibernate.hql.ast.tree.DotNode;
+import org.hibernate.hql.ast.tree.FromClause;
+import org.hibernate.hql.ast.tree.IdentNode;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.sql.InFragment;
+import org.hibernate.type.LiteralType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.ReflectHelper;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+
+/**
+ * A delegate that handles literals and constants for HqlSqlWalker, performing the token replacement functions and
+ * classifying literals.
+ *
+ * @author josh Sep 2, 2004 7:15:30 AM
+ */
+public class LiteralProcessor implements HqlSqlTokenTypes {
+	/**
+	 * Indicates that Float and Double literal values should
+	 * be treated using the SQL "exact" format (i.e., '.001')
+	 */
+	public static final int EXACT = 0;
+	/**
+	 * Indicates that Float and Double literal values should
+	 * be treated using the SQL "approximate" format (i.e., '1E-3')
+	 */
+	public static final int APPROXIMATE = 1;
+	/**
+	 * In what format should Float and Double literal values be sent
+	 * to the database?
+	 * @see #EXACT, #APPROXIMATE
+	 */
+	public static int DECIMAL_LITERAL_FORMAT = EXACT;
+
+	private static final Log log = LogFactory.getLog( LiteralProcessor.class );
+
+	private HqlSqlWalker walker;
+
+	public LiteralProcessor(HqlSqlWalker hqlSqlWalker) {
+		this.walker = hqlSqlWalker;
+	}
+
+	public boolean isAlias(String alias) {
+		FromClause from = walker.getCurrentFromClause();
+		while ( from.isSubQuery() ) {
+			if ( from.containsClassAlias(alias) ) {
+				return true;
+			}
+			from = from.getParentFromClause();
+		}
+		return from.containsClassAlias(alias);
+	}
+
+	public void processConstant(AST constant, boolean resolveIdent) throws SemanticException {
+		// If the constant is an IDENT, figure out what it means...
+		boolean isIdent = ( constant.getType() == IDENT || constant.getType() == WEIRD_IDENT );
+		if ( resolveIdent && isIdent && isAlias( constant.getText() ) ) { // IDENT is a class alias in the FROM.
+			IdentNode ident = ( IdentNode ) constant;
+			// Resolve to an identity column.
+			ident.resolve(false, true);
+		}
+		else {	// IDENT might be the name of a class.
+			Queryable queryable = walker.getSessionFactoryHelper().findQueryableUsingImports( constant.getText() );
+			if ( isIdent && queryable != null ) {
+				constant.setText( queryable.getDiscriminatorSQLValue() );
+			}
+			// Otherwise, it's a literal.
+			else {
+				processLiteral( constant );
+			}
+		}
+	}
+
+	public void lookupConstant(DotNode node) throws SemanticException {
+		String text = ASTUtil.getPathText( node );
+		Queryable persister = walker.getSessionFactoryHelper().findQueryableUsingImports( text );
+		if ( persister != null ) {
+			// the name of an entity class
+			final String discrim = persister.getDiscriminatorSQLValue();
+			node.setDataType( persister.getDiscriminatorType() );
+			if ( InFragment.NULL.equals(discrim) || InFragment.NOT_NULL.equals(discrim) ) {
+				throw new InvalidPathException( "subclass test not allowed for null or not null discriminator: '" + text + "'" );
+			}
+			else {
+				setSQLValue( node, text, discrim ); //the class discriminator value
+			}
+		}
+		else {
+			Object value = ReflectHelper.getConstantValue( text );
+			if ( value == null ) {
+				throw new InvalidPathException( "Invalid path: '" + text + "'" );
+			}
+			else {
+				setConstantValue( node, text, value );
+			}
+		}
+	}
+
+	private void setSQLValue(DotNode node, String text, String value) {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "setSQLValue() " + text + " -> " + value );
+		}
+		node.setFirstChild( null );	// Chop off the rest of the tree.
+		node.setType( SqlTokenTypes.SQL_TOKEN );
+		node.setText(value);
+		node.setResolvedConstant( text );
+	}
+
+	private void setConstantValue(DotNode node, String text, Object value) {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "setConstantValue() " + text + " -> " + value + " " + value.getClass().getName() );
+		}
+		node.setFirstChild( null );	// Chop off the rest of the tree.
+		if ( value instanceof String ) {
+			node.setType( SqlTokenTypes.QUOTED_STRING );
+		}
+		else if ( value instanceof Character ) {
+			node.setType( SqlTokenTypes.QUOTED_STRING );
+		}
+		else if ( value instanceof Byte ) {
+			node.setType( SqlTokenTypes.NUM_INT );
+		}
+		else if ( value instanceof Short ) {
+			node.setType( SqlTokenTypes.NUM_INT );
+		}
+		else if ( value instanceof Integer ) {
+			node.setType( SqlTokenTypes.NUM_INT );
+		}
+		else if ( value instanceof Long ) {
+			node.setType( SqlTokenTypes.NUM_LONG );
+		}
+		else if ( value instanceof Double ) {
+			node.setType( SqlTokenTypes.NUM_DOUBLE );
+		}
+		else if ( value instanceof Float ) {
+			node.setType( SqlTokenTypes.NUM_FLOAT );
+		}
+		else {
+			node.setType( SqlTokenTypes.CONSTANT );
+		}
+		Type type;
+		try {
+			type = TypeFactory.heuristicType( value.getClass().getName() );
+		}
+		catch ( MappingException me ) {
+			throw new QueryException( me );
+		}
+		if ( type == null ) {
+			throw new QueryException( QueryTranslator.ERROR_CANNOT_DETERMINE_TYPE + node.getText() );
+		}
+		try {
+			LiteralType literalType = ( LiteralType ) type;
+			Dialect dialect = walker.getSessionFactoryHelper().getFactory().getDialect();
+			node.setText( literalType.objectToSQLString( value, dialect ) );
+		}
+		catch ( Exception e ) {
+			throw new QueryException( QueryTranslator.ERROR_CANNOT_FORMAT_LITERAL + node.getText(), e );
+		}
+		node.setDataType( type );
+		node.setResolvedConstant( text );
+	}
+
+	public void processBoolean(AST constant) {
+		// TODO: something much better - look at the type of the other expression!
+		// TODO: Have comparisonExpression and/or arithmeticExpression rules complete the resolution of boolean nodes.
+		String replacement = ( String ) walker.getTokenReplacements().get( constant.getText() );
+		if ( replacement != null ) {
+			constant.setText( replacement );
+		}
+		else {
+			boolean bool = "true".equals( constant.getText().toLowerCase() );
+			Dialect dialect = walker.getSessionFactoryHelper().getFactory().getDialect();
+			constant.setText( dialect.toBooleanValueString(bool) );
+		}
+	}
+
+	private void processLiteral(AST constant) {
+		String replacement = ( String ) walker.getTokenReplacements().get( constant.getText() );
+		if ( replacement != null ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "processConstant() : Replacing '" + constant.getText() + "' with '" + replacement + "'" );
+			}
+			constant.setText( replacement );
+		}
+	}
+
+	public void processNumeric(AST literal) {
+		if ( literal.getType() == NUM_INT || literal.getType() == NUM_LONG ) {
+			literal.setText( determineIntegerRepresentation( literal.getText(), literal.getType() ) );
+		}
+		else if ( literal.getType() == NUM_FLOAT || literal.getType() == NUM_DOUBLE ) {
+			literal.setText( determineDecimalRepresentation( literal.getText(), literal.getType() ) );
+		}
+		else {
+			log.warn( "Unexpected literal token type [" + literal.getType() + "] passed for numeric processing" );
+		}
+	}
+
+	private String determineIntegerRepresentation(String text, int type) {
+		try {
+			if ( type == NUM_INT ) {
+				try {
+					return Integer.valueOf( text ).toString();
+				}
+				catch( NumberFormatException e ) {
+					log.trace( "could not format incoming text [" + text + "] as a NUM_INT; assuming numeric overflow and attempting as NUM_LONG" );
+				}
+			}
+			String literalValue = text;
+			if ( literalValue.endsWith( "l" ) || literalValue.endsWith( "L" ) ) {
+				literalValue = literalValue.substring( 0, literalValue.length() - 1 );
+			}
+			return Long.valueOf( literalValue ).toString();
+		}
+		catch( Throwable t ) {
+			throw new HibernateException( "Could not parse literal [" + text + "] as integer", t );
+		}
+	}
+
+	public String determineDecimalRepresentation(String text, int type) {
+		String literalValue = text;
+		if ( type == NUM_FLOAT ) {
+			if ( literalValue.endsWith( "f" ) || literalValue.endsWith( "F" ) ) {
+				literalValue = literalValue.substring( 0, literalValue.length() - 1 );
+			}
+		}
+		else if ( type == NUM_DOUBLE ) {
+			if ( literalValue.endsWith( "d" ) || literalValue.endsWith( "D" ) ) {
+				literalValue = literalValue.substring( 0, literalValue.length() - 1 );
+			}
+		}
+
+		BigDecimal number = null;
+		try {
+			number = new BigDecimal( literalValue );
+		}
+		catch( Throwable t ) {
+			throw new HibernateException( "Could not parse literal [" + text + "] as big-decimal", t );
+		}
+
+		return formatters[ DECIMAL_LITERAL_FORMAT ].format( number );
+	}
+
+	private static interface DecimalFormatter {
+		String format(BigDecimal number);
+	}
+
+	private static class ExactDecimalFormatter implements DecimalFormatter {
+		public String format(BigDecimal number) {
+			return number.toString();
+		}
+	}
+
+	private static class ApproximateDecimalFormatter implements DecimalFormatter {
+		private static final String FORMAT_STRING = "#0.0E0";
+		public String format(BigDecimal number) {
+			try {
+				// TODO : what amount of significant digits need to be supported here?
+				//      - from the DecimalFormat docs:
+				//          [significant digits] = [minimum integer digits] + [maximum fraction digits]
+				DecimalFormat jdkFormatter = new DecimalFormat( FORMAT_STRING );
+				jdkFormatter.setMinimumIntegerDigits( 1 );
+				jdkFormatter.setMaximumFractionDigits( Integer.MAX_VALUE );
+				return jdkFormatter.format( number );
+			}
+			catch( Throwable t ) {
+				throw new HibernateException( "Unable to format decimal literal in approximate format [" + number.toString() + "]", t );
+			}
+		}
+	}
+
+	private static final DecimalFormatter[] formatters = new DecimalFormatter[] {
+			new ExactDecimalFormatter(),
+			new ApproximateDecimalFormatter()
+	};
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/NodeTraverser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/NodeTraverser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/NodeTraverser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+package org.hibernate.hql.ast.util;
+
+import antlr.collections.AST;
+
+/**
+ * A visitor for traversing an AST tree.
+ *
+ * @author Steve Ebersole
+ */
+public class NodeTraverser {
+	public static interface VisitationStrategy {
+		public void visit(AST node);
+	}
+
+	private final VisitationStrategy strategy;
+
+	public NodeTraverser(VisitationStrategy strategy) {
+		this.strategy = strategy;
+	}
+
+	/**
+	 * Traverse the AST tree depth first.
+	 * <p/>
+	 * Note that the AST passed in is not visited itself.  Visitation starts
+	 * with its children.
+	 *
+	 * @param ast
+	 */
+	public void traverseDepthFirst(AST ast) {
+		if ( ast == null ) {
+			throw new IllegalArgumentException( "node to traverse cannot be null!" );
+		}
+		visitDepthFirst( ast.getFirstChild() );
+	}
+
+	private void visitDepthFirst(AST ast) {
+		if ( ast == null ) {
+			return;
+		}
+		strategy.visit( ast );
+		visitDepthFirst( ast.getFirstChild() );
+		visitDepthFirst( ast.getNextSibling() );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/PathHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/PathHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/PathHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+// $Id: PathHelper.java 7460 2005-07-12 20:27:29Z steveebersole $
+package org.hibernate.hql.ast.util;
+
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.util.StringHelper;
+
+import antlr.ASTFactory;
+import antlr.collections.AST;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Provides utility methods for paths.
+ *
+ * @author josh Sep 14, 2004 8:16:29 AM
+ */
+public final class PathHelper {
+
+	private static final Log log = LogFactory.getLog( PathHelper.class );
+
+	private PathHelper() {
+	}
+
+	/**
+	 * Turns a path into an AST.
+	 *
+	 * @param path    The path.
+	 * @param factory The AST factory to use.
+	 * @return An HQL AST representing the path.
+	 */
+	public static AST parsePath(String path, ASTFactory factory) {
+		String[] identifiers = StringHelper.split( ".", path );
+		AST lhs = null;
+		for ( int i = 0; i < identifiers.length; i++ ) {
+			String identifier = identifiers[i];
+			AST child = ASTUtil.create( factory, HqlSqlTokenTypes.IDENT, identifier );
+			if ( i == 0 ) {
+				lhs = child;
+			}
+			else {
+				lhs = ASTUtil.createBinarySubtree( factory, HqlSqlTokenTypes.DOT, ".", lhs, child );
+			}
+		}
+		if ( log.isDebugEnabled() ) {
+			log.debug( "parsePath() : " + path + " -> " + ASTUtil.getDebugString( lhs ) );
+		}
+		return lhs;
+	}
+
+	public static String getAlias(String path) {
+		return StringHelper.root( path );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/SessionFactoryHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/SessionFactoryHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/SessionFactoryHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,392 @@
+// $Id: SessionFactoryHelper.java 10824 2006-11-16 19:32:48Z steve.ebersole at jboss.com $
+package org.hibernate.hql.ast.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.dialect.function.SQLFunction;
+import org.hibernate.engine.JoinSequence;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.hql.NameGenerator;
+import org.hibernate.hql.ast.DetailedSemanticException;
+import org.hibernate.hql.ast.QuerySyntaxException;
+import org.hibernate.hql.ast.tree.SqlNode;
+import org.hibernate.persister.collection.CollectionPropertyMapping;
+import org.hibernate.persister.collection.CollectionPropertyNames;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.PropertyMapping;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+
+/**
+ * Helper for performing common and/or complex operations with the
+ * {@link SessionFactoryImplementor} during translation of an HQL query.
+ *
+ * @author Joshua Davis
+ */
+public class SessionFactoryHelper {
+
+	private SessionFactoryImplementor sfi;
+	private Map collectionPropertyMappingByRole;
+
+	/**
+	 * Construct a new SessionFactoryHelper instance.
+	 *
+	 * @param sfi The SessionFactory impl to be encapsualted.
+	 */
+	public SessionFactoryHelper(SessionFactoryImplementor sfi) {
+		this.sfi = sfi;
+		collectionPropertyMappingByRole = new HashMap();
+	}
+
+	/**
+	 * Get a handle to the encapsulated SessionFactory.
+	 *
+	 * @return The encapsulated SessionFactory.
+	 */
+	public SessionFactoryImplementor getFactory() {
+		return sfi;
+	}
+
+	/**
+	 * Does the given persister define a physical discriminator column
+	 * for the purpose of inheritence discrimination?
+	 *
+	 * @param persister The persister to be checked.
+	 * @return True if the persister does define an actual discriminator column.
+	 */
+	public boolean hasPhysicalDiscriminatorColumn(Queryable persister) {
+		if ( persister.getDiscriminatorType() != null ) {
+			String discrimColumnName = persister.getDiscriminatorColumnName();
+			// Needed the "clazz_" check to work around union-subclasses
+			// TODO : is there a way to tell whether a persister is truly discrim-column based inheritence?
+			if ( discrimColumnName != null && !"clazz_".equals( discrimColumnName ) ) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Given a (potentially unqualified) class name, locate its imported qualified name.
+	 *
+	 * @param className The potentially unqualified class name
+	 * @return The qualified class name.
+	 */
+	public String getImportedClassName(String className) {
+		return sfi.getImportedClassName( className );
+	}
+
+	/**
+	 * Given a (potentially unqualified) class name, locate its persister.
+	 *
+	 * @param className The (potentially unqualified) class name.
+	 * @return The defined persister for this class, or null if none found.
+	 */
+	public Queryable findQueryableUsingImports(String className) {
+		return findQueryableUsingImports( sfi, className );
+	}
+
+
+	/**
+	 * Given a (potentially unqualified) class name, locate its persister.
+	 *
+	 * @param sfi The session factory implementor.
+	 * @param className The (potentially unqualified) class name.
+	 * @return The defined persister for this class, or null if none found.
+	 */
+	public static Queryable findQueryableUsingImports(SessionFactoryImplementor sfi, String className) {
+		final String importedClassName = sfi.getImportedClassName( className );
+		if ( importedClassName == null ) {
+			return null;
+		}
+		try {
+			return ( Queryable ) sfi.getEntityPersister( importedClassName );
+		}
+		catch ( MappingException me ) {
+			return null;
+		}
+	}
+
+	/**
+	 * Locate the persister by class or entity name.
+	 *
+	 * @param name The class or entity name
+	 * @return The defined persister for this entity, or null if none found.
+	 * @throws MappingException
+	 */
+	private EntityPersister findEntityPersisterByName(String name) throws MappingException {
+		// First, try to get the persister using the given name directly.
+		try {
+			return sfi.getEntityPersister( name );
+		}
+		catch ( MappingException ignore ) {
+			// unable to locate it using this name
+		}
+
+		// If that didn't work, try using the 'import' name.
+		String importedClassName = sfi.getImportedClassName( name );
+		if ( importedClassName == null ) {
+			return null;
+		}
+		return sfi.getEntityPersister( importedClassName );
+	}
+
+	/**
+	 * Locate the persister by class or entity name, requiring that such a persister
+	 * exist.
+	 *
+	 * @param name The class or entity name
+	 * @return The defined persister for this entity
+	 * @throws SemanticException Indicates the persister could not be found
+	 */
+	public EntityPersister requireClassPersister(String name) throws SemanticException {
+		EntityPersister cp;
+		try {
+			cp = findEntityPersisterByName( name );
+			if ( cp == null ) {
+				throw new QuerySyntaxException( name + " is not mapped" );
+			}
+		}
+		catch ( MappingException e ) {
+			throw new DetailedSemanticException( e.getMessage(), e );
+		}
+		return cp;
+	}
+
+	/**
+	 * Locate the collection persister by the collection role.
+	 *
+	 * @param role The collection role name.
+	 * @return The defined CollectionPersister for this collection role, or null.
+	 */
+	public QueryableCollection getCollectionPersister(String role) {
+		try {
+			return ( QueryableCollection ) sfi.getCollectionPersister( role );
+		}
+		catch ( ClassCastException cce ) {
+			throw new QueryException( "collection is not queryable: " + role );
+		}
+		catch ( Exception e ) {
+			throw new QueryException( "collection not found: " + role );
+		}
+	}
+
+	/**
+	 * Locate the collection persister by the collection role, requiring that
+	 * such a persister exist.
+	 *
+	 * @param role The collection role name.
+	 * @return The defined CollectionPersister for this collection role.
+	 * @throws QueryException Indicates that the collection persister could not be found.
+	 */
+	public QueryableCollection requireQueryableCollection(String role) throws QueryException {
+		try {
+			QueryableCollection queryableCollection = ( QueryableCollection ) sfi.getCollectionPersister( role );
+			if ( queryableCollection != null ) {
+				collectionPropertyMappingByRole.put( role, new CollectionPropertyMapping( queryableCollection ) );
+			}
+			return queryableCollection;
+		}
+		catch ( ClassCastException cce ) {
+			throw new QueryException( "collection role is not queryable: " + role );
+		}
+		catch ( Exception e ) {
+			throw new QueryException( "collection role not found: " + role );
+		}
+	}
+
+	/**
+	 * Retreive a PropertyMapping describing the given collection role.
+	 *
+	 * @param role The collection role for whcih to retrieve the property mapping.
+	 * @return The property mapping.
+	 */
+	private PropertyMapping getCollectionPropertyMapping(String role) {
+		return ( PropertyMapping ) collectionPropertyMappingByRole.get( role );
+	}
+
+	/**
+	 * Retrieves the column names corresponding to the collection elements for the given
+	 * collection role.
+	 *
+	 * @param role The collection role
+	 * @param roleAlias The sql column-qualification alias (i.e., the table alias)
+	 * @return the collection element columns
+	 */
+	public String[] getCollectionElementColumns(String role, String roleAlias) {
+		return getCollectionPropertyMapping( role ).toColumns( roleAlias, CollectionPropertyNames.COLLECTION_ELEMENTS );
+	}
+
+	/**
+	 * Generate an empty join sequence instance.
+	 *
+	 * @return The generate join sequence.
+	 */
+	public JoinSequence createJoinSequence() {
+		return new JoinSequence( sfi );
+	}
+
+	/**
+	 * Generate a join sequence representing the given association type.
+	 *
+	 * @param implicit Should implicit joins (theta-style) or explicit joins (ANSI-style) be rendered
+	 * @param associationType The type representing the thing to be joined into.
+	 * @param tableAlias The table alias to use in qualifing the join conditions
+	 * @param joinType The type of join to render (inner, outer, etc);  see {@link org.hibernate.sql.JoinFragment}
+	 * @param columns The columns making up the condition of the join.
+	 * @return The generated join sequence.
+	 */
+	public JoinSequence createJoinSequence(boolean implicit, AssociationType associationType, String tableAlias, int joinType, String[] columns) {
+		JoinSequence joinSequence = createJoinSequence();
+		joinSequence.setUseThetaStyle( implicit );	// Implicit joins use theta style (WHERE pk = fk), explicit joins use JOIN (after from)
+		joinSequence.addJoin( associationType, tableAlias, joinType, columns );
+		return joinSequence;
+	}
+
+	/**
+	 * Create a join sequence rooted at the given collection.
+	 *
+	 * @param collPersister The persister for the collection at which the join should be rooted.
+	 * @param collectionName The alias to use for qualifying column references.
+	 * @return The generated join sequence.
+	 */
+	public JoinSequence createCollectionJoinSequence(QueryableCollection collPersister, String collectionName) {
+		JoinSequence joinSequence = createJoinSequence();
+		joinSequence.setRoot( collPersister, collectionName );
+		joinSequence.setUseThetaStyle( true );		// TODO: figure out how this should be set.
+///////////////////////////////////////////////////////////////////////////////
+// This was the reason for failures regarding INDEX_OP and subclass joins on
+// theta-join dialects; not sure what behaviour we were trying to emulate ;)
+//		joinSequence = joinSequence.getFromPart();	// Emulate the old addFromOnly behavior.
+		return joinSequence;
+	}
+
+	/**
+	 * Determine the name of the property for the entity encapsulated by the
+	 * given type which represents the id or unique-key.
+	 *
+	 * @param entityType The type representing the entity.
+	 * @return The corresponding property name
+	 * @throws QueryException Indicates such a property could not be found.
+	 */
+	public String getIdentifierOrUniqueKeyPropertyName(EntityType entityType) {
+		try {
+			return entityType.getIdentifierOrUniqueKeyPropertyName( sfi );
+		}
+		catch ( MappingException me ) {
+			throw new QueryException( me );
+		}
+	}
+
+	/**
+	 * Retreive the number of columns represented by this type.
+	 *
+	 * @param type The type.
+	 * @return The number of columns.
+	 */
+	public int getColumnSpan(Type type) {
+		return type.getColumnSpan( sfi );
+	}
+
+	/**
+	 * Given a collection type, determine the entity name of the elements
+	 * contained within instance of that collection.
+	 *
+	 * @param collectionType The collection type to check.
+	 * @return The entity name of the elements of this collection.
+	 */
+	public String getAssociatedEntityName(CollectionType collectionType) {
+		return collectionType.getAssociatedEntityName( sfi );
+	}
+
+	/**
+	 * Given a collection type, determine the Type representing elements
+	 * within instances of that collection.
+	 *
+	 * @param collectionType The collection type to be checked.
+	 * @return The Type of the elements of the collection.
+	 */
+	private Type getElementType(CollectionType collectionType) {
+		return collectionType.getElementType( sfi );
+	}
+
+	/**
+	 * Essentially the same as {@link #getElementType}, but requiring that the
+	 * element type be an association type.
+	 *
+	 * @param collectionType The collection type to be checked.
+	 * @return The AssociationType of the elements of the collection.
+	 */
+	public AssociationType getElementAssociationType(CollectionType collectionType) {
+		return ( AssociationType ) getElementType( collectionType );
+	}
+
+	/**
+	 * Locate a registered sql function by name.
+	 *
+	 * @param functionName The name of the function to locate
+	 * @return The sql function, or null if not found.
+	 */
+	public SQLFunction findSQLFunction(String functionName) {
+		return sfi.getSqlFunctionRegistry().findSQLFunction( functionName.toLowerCase() );
+	}
+
+	/**
+	 * Locate a registered sql function by name, requiring that such a registered function exist.
+	 *
+	 * @param functionName The name of the function to locate
+	 * @return The sql function.
+	 * @throws QueryException Indicates no matching sql functions could be found.
+	 */
+	private SQLFunction requireSQLFunction(String functionName) {
+		SQLFunction f = findSQLFunction( functionName );
+		if ( f == null ) {
+			throw new QueryException( "Unable to find SQL function: " + functionName );
+		}
+		return f;
+	}
+
+	/**
+	 * Find the function return type given the function name and the first argument expression node.
+	 *
+	 * @param functionName The function name.
+	 * @param first        The first argument expression.
+	 * @return the function return type given the function name and the first argument expression node.
+	 */
+	public Type findFunctionReturnType(String functionName, AST first) {
+		// locate the registered function by the given name
+		SQLFunction sqlFunction = requireSQLFunction( functionName );
+
+		// determine the type of the first argument...
+		Type argumentType = null;
+		if ( first != null ) {
+			if ( "cast".equals(functionName) ) {
+				argumentType = TypeFactory.heuristicType( first.getNextSibling().getText() );
+			}
+			else if ( first instanceof SqlNode ) {
+				argumentType = ( (SqlNode) first ).getDataType();
+			}
+		}
+
+		return sqlFunction.getReturnType( argumentType, sfi );
+	}
+
+	public String[][] generateColumnNames(Type[] sqlResultTypes) {
+		return NameGenerator.generateColumnNames( sqlResultTypes, sfi );
+	}
+
+	public boolean isStrictJPAQLComplianceEnabled() {
+		return sfi.getSettings().isStrictJPAQLCompliance();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/SyntheticAndFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/SyntheticAndFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/ast/util/SyntheticAndFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,134 @@
+// $Id: SyntheticAndFactory.java 8755 2005-12-06 00:18:35Z steveebersole $
+package org.hibernate.hql.ast.util;
+
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.hql.ast.tree.FromElement;
+import org.hibernate.hql.ast.tree.QueryNode;
+import org.hibernate.hql.ast.tree.RestrictableStatement;
+import org.hibernate.hql.ast.tree.SqlFragment;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.util.StringHelper;
+
+import antlr.ASTFactory;
+import antlr.collections.AST;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Creates synthetic and nodes based on the where fragment part of a JoinSequence.
+ *
+ * @author josh Dec 5, 2004 12:25:20 PM
+ */
+public class SyntheticAndFactory implements HqlSqlTokenTypes {
+	private static final Log log = LogFactory.getLog( SyntheticAndFactory.class );
+
+	private ASTFactory astFactory;
+	private AST thetaJoins;
+	private AST filters;
+
+	public SyntheticAndFactory(ASTFactory astFactory) {
+		this.astFactory = astFactory;
+	}
+
+	public void addWhereFragment(JoinFragment joinFragment, String whereFragment, QueryNode query, FromElement fromElement) {
+
+		if ( whereFragment == null ) {
+			return;
+		}
+
+		whereFragment = whereFragment.trim();
+		if ( StringHelper.isEmpty( whereFragment ) ) {
+			return;
+		}
+		else if ( !fromElement.useWhereFragment() && !joinFragment.hasThetaJoins() ) {
+			return;
+		}
+
+		// Forcefully remove leading ands from where fragments; the grammar will
+		// handle adding them
+		if ( whereFragment.startsWith( "and" ) ) {
+			whereFragment = whereFragment.substring( 4 );
+		}
+
+		if ( log.isDebugEnabled() ) log.debug( "Using WHERE fragment [" + whereFragment + "]" );
+
+		SqlFragment fragment = ( SqlFragment ) ASTUtil.create( astFactory, SQL_TOKEN, whereFragment );
+		fragment.setJoinFragment( joinFragment );
+		fragment.setFromElement( fromElement );
+
+		// Filter conditions need to be inserted before the HQL where condition and the
+		// theta join node.  This is because org.hibernate.loader.Loader binds the filter parameters first,
+		// then it binds all the HQL query parameters, see org.hibernate.loader.Loader.processFilterParameters().
+		if ( fragment.getFromElement().isFilter() || fragment.hasFilterCondition() ) {
+			if ( filters == null ) {
+				// Find or create the WHERE clause
+				AST where = query.getWhereClause();
+				// Create a new FILTERS node as a parent of all filters
+				filters = astFactory.create( FILTERS, "{filter conditions}" );
+				// Put the FILTERS node before the HQL condition and theta joins
+				ASTUtil.insertChild( where, filters );
+			}
+			
+			// add the current fragment to the FILTERS node
+			filters.addChild( fragment );
+		}
+		else {
+			if ( thetaJoins == null ) {
+				// Find or create the WHERE clause
+				AST where = query.getWhereClause();
+				// Create a new THETA_JOINS node as a parent of all filters
+				thetaJoins = astFactory.create( THETA_JOINS, "{theta joins}" );
+				// Put the THETA_JOINS node before the HQL condition, after the filters.
+				if (filters==null) {
+					ASTUtil.insertChild( where, thetaJoins );
+				}
+				else {
+					ASTUtil.insertSibling( thetaJoins, filters );
+				}
+			}
+			
+			// add the current fragment to the THETA_JOINS node
+			thetaJoins.addChild(fragment);
+		}
+
+	}
+
+	public void addDiscriminatorWhereFragment(RestrictableStatement statement, Queryable persister, Map enabledFilters, String alias) {
+		String whereFragment = persister.filterFragment( alias, enabledFilters ).trim();
+		if ( "".equals( whereFragment ) ) {
+			return;
+		}
+		if ( whereFragment.startsWith( "and" ) ) {
+			whereFragment = whereFragment.substring( 4 );
+		}
+
+		// Need to parse off the column qualifiers; this is assuming (which is true as of now)
+		// that this is only used from update and delete HQL statement parsing
+		whereFragment = StringHelper.replace( whereFragment, persister.generateFilterConditionAlias( alias ) + ".", "" );
+
+		// Note: this simply constructs a "raw" SQL_TOKEN representing the
+		// where fragment and injects this into the tree.  This "works";
+		// however it is probably not the best long-term solution.
+		//
+		// At some point we probably want to apply an additional grammar to
+		// properly tokenize this where fragment into constituent parts
+		// focused on the operators embedded within the fragment.
+		AST discrimNode = astFactory.create( SQL_TOKEN, whereFragment );
+
+		if ( statement.getWhereClause().getNumberOfChildren() == 0 ) {
+			statement.getWhereClause().setFirstChild( discrimNode );
+		}
+		else {
+			AST and = astFactory.create( AND, "{and}" );
+			AST currentFirstChild = statement.getWhereClause().getFirstChild();
+			and.setFirstChild( discrimNode );
+			and.addChild( currentFirstChild );
+			statement.getWhereClause().setFirstChild( and );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/ClassicQueryTranslatorFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/ClassicQueryTranslatorFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/ClassicQueryTranslatorFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+//$Id: ClassicQueryTranslatorFactory.java 9162 2006-01-27 23:40:32Z steveebersole $
+package org.hibernate.hql.classic;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.hql.FilterTranslator;
+import org.hibernate.hql.QueryTranslator;
+import org.hibernate.hql.QueryTranslatorFactory;
+
+import java.util.Map;
+
+/**
+ * Generates translators which uses the older hand-written parser to perform
+ * the translation.
+ *
+ * @author Gavin King
+ */
+public class ClassicQueryTranslatorFactory implements QueryTranslatorFactory {
+
+	/**
+	 * @see QueryTranslatorFactory#createQueryTranslator
+	 */
+	public QueryTranslator createQueryTranslator(
+			String queryIdentifier,
+	        String queryString,
+	        Map filters,
+	        SessionFactoryImplementor factory) {
+		return new QueryTranslatorImpl( queryIdentifier, queryString, filters, factory );
+	}
+
+	/**
+	 * @see QueryTranslatorFactory#createFilterTranslator
+	 */
+	public FilterTranslator createFilterTranslator(
+			String queryIdentifier,
+			String queryString,
+	        Map filters,
+	        SessionFactoryImplementor factory) {
+		return new QueryTranslatorImpl( queryIdentifier, queryString, filters, factory );
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/ClassicQueryTranslatorFactory.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/ClauseParser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/ClauseParser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/ClauseParser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,129 @@
+//$Id: ClauseParser.java 4907 2004-12-08 00:24:14Z oneovthafew $
+package org.hibernate.hql.classic;
+
+import org.hibernate.QueryException;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Parses the Hibernate query into its constituent clauses.
+ */
+public class ClauseParser implements Parser {
+
+	private Parser child;
+	private List selectTokens;
+	private boolean cacheSelectTokens = false;
+	private boolean byExpected = false;
+	private int parenCount = 0;
+
+	public void token(String token, QueryTranslatorImpl q) throws QueryException {
+		String lcToken = token.toLowerCase();
+
+		if ( "(".equals( token ) ) {
+			parenCount++;
+		}
+		else if ( ")".equals( token ) ) {
+			parenCount--;
+		}
+
+		if ( byExpected && !lcToken.equals( "by" ) ) {
+			throw new QueryException( "BY expected after GROUP or ORDER: " + token );
+		}
+
+		boolean isClauseStart = parenCount == 0; //ignore subselect keywords
+
+		if ( isClauseStart ) {
+			if ( lcToken.equals( "select" ) ) {
+				selectTokens = new ArrayList();
+				cacheSelectTokens = true;
+			}
+			else if ( lcToken.equals( "from" ) ) {
+				child = new FromParser();
+				child.start( q );
+				cacheSelectTokens = false;
+			}
+			else if ( lcToken.equals( "where" ) ) {
+				endChild( q );
+				child = new WhereParser();
+				child.start( q );
+			}
+			else if ( lcToken.equals( "order" ) ) {
+				endChild( q );
+				child = new OrderByParser();
+				byExpected = true;
+			}
+			else if ( lcToken.equals( "having" ) ) {
+				endChild( q );
+				child = new HavingParser();
+				child.start( q );
+			}
+			else if ( lcToken.equals( "group" ) ) {
+				endChild( q );
+				child = new GroupByParser();
+				byExpected = true;
+			}
+			else if ( lcToken.equals( "by" ) ) {
+				if ( !byExpected ) throw new QueryException( "GROUP or ORDER expected before BY" );
+				child.start( q );
+				byExpected = false;
+			}
+			else {
+				isClauseStart = false;
+			}
+		}
+
+		if ( !isClauseStart ) {
+			if ( cacheSelectTokens ) {
+				selectTokens.add( token );
+			}
+			else {
+				if ( child == null ) {
+					throw new QueryException( "query must begin with SELECT or FROM: " + token );
+				}
+				else {
+					child.token( token, q );
+				}
+			}
+		}
+
+	}
+
+	private void endChild(QueryTranslatorImpl q) throws QueryException {
+		if ( child == null ) {
+			//null child could occur for no from clause in a filter
+			cacheSelectTokens = false;
+		}
+		else {
+			child.end( q );
+		}
+	}
+
+	public void start(QueryTranslatorImpl q) {
+	}
+
+	public void end(QueryTranslatorImpl q) throws QueryException {
+		endChild( q );
+		if ( selectTokens != null ) {
+			child = new SelectParser();
+			child.start( q );
+			Iterator iter = selectTokens.iterator();
+			while ( iter.hasNext() ) {
+				token( ( String ) iter.next(), q );
+			}
+			child.end( q );
+		}
+		byExpected = false;
+		parenCount = 0;
+		cacheSelectTokens = false;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/FromParser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/FromParser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/FromParser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,231 @@
+//$Id: FromParser.java 5699 2005-02-13 11:50:11Z oneovthafew $
+package org.hibernate.hql.classic;
+
+import org.hibernate.QueryException;
+import org.hibernate.hql.QueryTranslator;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.sql.JoinFragment;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Parses the from clause of a hibernate query, looking for tables and
+ * aliases for the SQL query.
+ */
+
+public class FromParser implements Parser {
+
+	private final PathExpressionParser peParser = new FromPathExpressionParser();
+	private String entityName;
+	private String alias;
+	private boolean afterIn;
+	private boolean afterAs;
+	private boolean afterClass;
+	private boolean expectingJoin;
+	private boolean expectingIn;
+	private boolean expectingAs;
+	private boolean afterJoinType;
+	private int joinType;
+	private boolean afterFetch;
+
+	private static final int NONE = -666;
+
+	private static final Map JOIN_TYPES = new HashMap();
+
+	static {
+		JOIN_TYPES.put( "left", new Integer( JoinFragment.LEFT_OUTER_JOIN ) );
+		JOIN_TYPES.put( "right", new Integer( JoinFragment.RIGHT_OUTER_JOIN ) );
+		JOIN_TYPES.put( "full", new Integer( JoinFragment.FULL_JOIN ) );
+		JOIN_TYPES.put( "inner", new Integer( JoinFragment.INNER_JOIN ) );
+	}
+
+	public void token(String token, QueryTranslatorImpl q) throws QueryException {
+
+		// start by looking for HQL keywords...
+		String lcToken = token.toLowerCase();
+		if ( lcToken.equals( "," ) ) {
+			if ( !( expectingJoin | expectingAs ) ) throw new QueryException( "unexpected token: ," );
+			expectingJoin = false;
+			expectingAs = false;
+		}
+		else if ( lcToken.equals( "join" ) ) {
+			if ( !afterJoinType ) {
+				if ( !( expectingJoin | expectingAs ) ) throw new QueryException( "unexpected token: join" );
+				// inner joins can be abbreviated to 'join'
+				joinType = JoinFragment.INNER_JOIN;
+				expectingJoin = false;
+				expectingAs = false;
+			}
+			else {
+				afterJoinType = false;
+			}
+		}
+		else if ( lcToken.equals( "fetch" ) ) {
+			if ( q.isShallowQuery() ) throw new QueryException( QueryTranslator.ERROR_CANNOT_FETCH_WITH_ITERATE );
+			if ( joinType == NONE ) throw new QueryException( "unexpected token: fetch" );
+			if ( joinType == JoinFragment.FULL_JOIN || joinType == JoinFragment.RIGHT_OUTER_JOIN ) {
+				throw new QueryException( "fetch may only be used with inner join or left outer join" );
+			}
+			afterFetch = true;
+		}
+		else if ( lcToken.equals( "outer" ) ) {
+			// 'outer' is optional and is ignored
+			if ( !afterJoinType ||
+					( joinType != JoinFragment.LEFT_OUTER_JOIN && joinType != JoinFragment.RIGHT_OUTER_JOIN )
+			) {
+				throw new QueryException( "unexpected token: outer" );
+			}
+		}
+		else if ( JOIN_TYPES.containsKey( lcToken ) ) {
+			if ( !( expectingJoin | expectingAs ) ) throw new QueryException( "unexpected token: " + token );
+			joinType = ( ( Integer ) JOIN_TYPES.get( lcToken ) ).intValue();
+			afterJoinType = true;
+			expectingJoin = false;
+			expectingAs = false;
+		}
+		else if ( lcToken.equals( "class" ) ) {
+			if ( !afterIn ) throw new QueryException( "unexpected token: class" );
+			if ( joinType != NONE ) throw new QueryException( "outer or full join must be followed by path expression" );
+			afterClass = true;
+		}
+		else if ( lcToken.equals( "in" ) ) {
+			if ( !expectingIn ) throw new QueryException( "unexpected token: in" );
+			afterIn = true;
+			expectingIn = false;
+		}
+		else if ( lcToken.equals( "as" ) ) {
+			if ( !expectingAs ) throw new QueryException( "unexpected token: as" );
+			afterAs = true;
+			expectingAs = false;
+		}
+		else {
+
+			if ( afterJoinType ) throw new QueryException( "join expected: " + token );
+			if ( expectingJoin ) throw new QueryException( "unexpected token: " + token );
+			if ( expectingIn ) throw new QueryException( "in expected: " + token );
+
+			// now anything that is not a HQL keyword
+
+			if ( afterAs || expectingAs ) {
+
+				// (AS is always optional, for consistency with SQL/OQL)
+
+				// process the "new" HQL style where aliases are assigned
+				// _after_ the class name or path expression ie. using
+				// the AS construction
+
+				if ( entityName != null ) {
+					q.setAliasName( token, entityName );
+				}
+				else {
+					throw new QueryException( "unexpected: as " + token );
+				}
+				afterAs = false;
+				expectingJoin = true;
+				expectingAs = false;
+				entityName = null;
+
+			}
+			else if ( afterIn ) {
+
+				// process the "old" HQL style where aliases appear _first_
+				// ie. using the IN or IN CLASS constructions
+
+				if ( alias == null ) throw new QueryException( "alias not specified for: " + token );
+
+				if ( joinType != NONE ) throw new QueryException( "outer or full join must be followed by path expression" );
+
+				if ( afterClass ) {
+					// treat it as a classname
+					Queryable p = q.getEntityPersisterUsingImports( token );
+					if ( p == null ) throw new QueryException( "persister not found: " + token );
+					q.addFromClass( alias, p );
+				}
+				else {
+					// treat it as a path expression
+					peParser.setJoinType( JoinFragment.INNER_JOIN );
+					peParser.setUseThetaStyleJoin( true );
+					ParserHelper.parse( peParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
+					if ( !peParser.isCollectionValued() ) throw new QueryException( "path expression did not resolve to collection: " + token );
+					String nm = peParser.addFromCollection( q );
+					q.setAliasName( alias, nm );
+				}
+
+				alias = null;
+				afterIn = false;
+				afterClass = false;
+				expectingJoin = true;
+			}
+			else {
+
+				// handle a path expression or class name that
+				// appears at the start, in the "new" HQL
+				// style or an alias that appears at the start
+				// in the "old" HQL style
+
+				Queryable p = q.getEntityPersisterUsingImports( token );
+				if ( p != null ) {
+					// starts with the name of a mapped class (new style)
+					if ( joinType != NONE ) throw new QueryException( "outer or full join must be followed by path expression" );
+					entityName = q.createNameFor( p.getEntityName() );
+					q.addFromClass( entityName, p );
+					expectingAs = true;
+				}
+				else if ( token.indexOf( '.' ) < 0 ) {
+					// starts with an alias (old style)
+					// semi-bad thing about this: can't re-alias another alias.....
+					alias = token;
+					expectingIn = true;
+				}
+				else {
+
+					// starts with a path expression (new style)
+
+					// force HQL style: from Person p inner join p.cars c
+					//if (joinType==NONE) throw new QueryException("path expression must be preceded by full, left, right or inner join");
+
+					//allow ODMG OQL style: from Person p, p.cars c
+					if ( joinType != NONE ) {
+						peParser.setJoinType( joinType );
+					}
+					else {
+						peParser.setJoinType( JoinFragment.INNER_JOIN );
+					}
+					peParser.setUseThetaStyleJoin( q.isSubquery() );
+
+					ParserHelper.parse( peParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
+					entityName = peParser.addFromAssociation( q );
+
+					joinType = NONE;
+					peParser.setJoinType( JoinFragment.INNER_JOIN );
+
+					if ( afterFetch ) {
+						peParser.fetch( q, entityName );
+						afterFetch = false;
+					}
+
+					expectingAs = true;
+
+				}
+			}
+		}
+
+	}
+
+	public void start(QueryTranslatorImpl q) {
+		entityName = null;
+		alias = null;
+		afterIn = false;
+		afterAs = false;
+		afterClass = false;
+		expectingJoin = false;
+		expectingIn = false;
+		expectingAs = false;
+		joinType = NONE;
+	}
+
+	public void end(QueryTranslatorImpl q) {
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/FromPathExpressionParser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/FromPathExpressionParser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/FromPathExpressionParser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+//$Id: FromPathExpressionParser.java 5861 2005-02-22 14:07:36Z oneovthafew $
+package org.hibernate.hql.classic;
+
+import org.hibernate.QueryException;
+import org.hibernate.persister.collection.CollectionPropertyNames;
+import org.hibernate.type.Type;
+
+public class FromPathExpressionParser extends PathExpressionParser {
+
+	public void end(QueryTranslatorImpl q) throws QueryException {
+		if ( !isCollectionValued() ) {
+			Type type = getPropertyType();
+			if ( type.isEntityType() ) {
+				// "finish off" the join
+				token( ".", q );
+				token( null, q );
+			}
+			else if ( type.isCollectionType() ) {
+				// default to element set if no elements() specified
+				token( ".", q );
+				token( CollectionPropertyNames.COLLECTION_ELEMENTS, q );
+			}
+		}
+		super.end( q );
+	}
+
+	protected void setExpectingCollectionIndex() throws QueryException {
+		throw new QueryException( "illegal syntax near collection-valued path expression in from: "  + getCollectionName() );
+	}
+
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/GroupByParser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/GroupByParser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/GroupByParser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+//$Id: GroupByParser.java 4907 2004-12-08 00:24:14Z oneovthafew $
+package org.hibernate.hql.classic;
+
+import org.hibernate.QueryException;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Parses the GROUP BY clause of an aggregate query
+ */
+public class GroupByParser implements Parser {
+
+	//this is basically a copy/paste of OrderByParser ... might be worth refactoring
+
+	// This uses a PathExpressionParser but notice that compound paths are not valid,
+	// only bare names and simple paths:
+
+	// SELECT p FROM p IN CLASS eg.Person GROUP BY p.Name, p.Address, p
+
+	// The reason for this is SQL doesn't let you sort by an expression you are
+	// not returning in the result set.
+
+	private final PathExpressionParser pathExpressionParser;
+
+	{
+		pathExpressionParser = new PathExpressionParser();
+		pathExpressionParser.setUseThetaStyleJoin( true ); //TODO: would be nice to use false, but issues with MS SQL
+	}
+
+	public void token(String token, QueryTranslatorImpl q) throws QueryException {
+
+		if ( q.isName( StringHelper.root( token ) ) ) {
+			ParserHelper.parse( pathExpressionParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
+			q.appendGroupByToken( pathExpressionParser.getWhereColumn() );
+			pathExpressionParser.addAssociation( q );
+		}
+		else {
+			q.appendGroupByToken( token );
+		}
+	}
+
+	public void start(QueryTranslatorImpl q) throws QueryException {
+	}
+
+	public void end(QueryTranslatorImpl q) throws QueryException {
+	}
+
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/HavingParser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/HavingParser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/HavingParser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+//$Id: HavingParser.java 4907 2004-12-08 00:24:14Z oneovthafew $
+package org.hibernate.hql.classic;
+
+
+/**
+ * Parses the having clause of a hibernate query and translates it to an
+ * SQL having clause.
+ */
+public class HavingParser extends WhereParser {
+
+	void appendToken(QueryTranslatorImpl q, String token) {
+		q.appendHavingToken( token );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/OrderByParser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/OrderByParser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/OrderByParser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+//$Id: OrderByParser.java 4907 2004-12-08 00:24:14Z oneovthafew $
+package org.hibernate.hql.classic;
+
+import org.hibernate.QueryException;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Parses the ORDER BY clause of a query
+ */
+
+public class OrderByParser implements Parser {
+
+	// This uses a PathExpressionParser but notice that compound paths are not valid,
+	// only bare names and simple paths:
+
+	// SELECT p FROM p IN CLASS eg.Person ORDER BY p.Name, p.Address, p
+
+	// The reason for this is SQL doesn't let you sort by an expression you are
+	// not returning in the result set.
+
+	private final PathExpressionParser pathExpressionParser;
+
+	{
+		pathExpressionParser = new PathExpressionParser();
+		pathExpressionParser.setUseThetaStyleJoin( true ); //TODO: would be nice to use false, but issues with MS SQL
+	}
+
+	public void token(String token, QueryTranslatorImpl q) throws QueryException {
+
+		if ( q.isName( StringHelper.root( token ) ) ) {
+			ParserHelper.parse( pathExpressionParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
+			q.appendOrderByToken( pathExpressionParser.getWhereColumn() );
+			pathExpressionParser.addAssociation( q );
+		}
+		else if ( token.startsWith( ParserHelper.HQL_VARIABLE_PREFIX ) ) { //named query parameter
+			q.addNamedParameter( token.substring( 1 ) );
+			q.appendOrderByToken( "?" );
+		}
+		else {
+			q.appendOrderByToken( token );
+		}
+	}
+
+	public void start(QueryTranslatorImpl q) throws QueryException {
+	}
+
+	public void end(QueryTranslatorImpl q) throws QueryException {
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/Parser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/Parser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/Parser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: Parser.java 4907 2004-12-08 00:24:14Z oneovthafew $
+package org.hibernate.hql.classic;
+
+import org.hibernate.QueryException;
+
+/**
+ * A parser is a state machine that accepts a string of tokens,
+ * bounded by start() and end() and modifies a QueryTranslator. Parsers
+ * are NOT intended to be threadsafe. They SHOULD be reuseable
+ * for more than one token stream.
+ */
+
+public interface Parser {
+	public void token(String token, QueryTranslatorImpl q) throws QueryException;
+
+	public void start(QueryTranslatorImpl q) throws QueryException;
+
+	public void end(QueryTranslatorImpl q) throws QueryException;
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/ParserHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/ParserHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/ParserHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: ParserHelper.java 6879 2005-05-23 19:54:13Z oneovthafew $
+package org.hibernate.hql.classic;
+
+import org.hibernate.QueryException;
+import org.hibernate.util.StringHelper;
+
+import java.util.StringTokenizer;
+
+public final class ParserHelper {
+
+	public static final String HQL_VARIABLE_PREFIX = ":";
+
+	public static final String HQL_SEPARATORS = " \n\r\f\t,()=<>&|+-=/*'^![]#~\\";
+	//NOTICE: no " or . since they are part of (compound) identifiers
+	public static final String PATH_SEPARATORS = ".";
+
+	public static boolean isWhitespace(String str) {
+		return StringHelper.WHITESPACE.indexOf( str ) > -1;
+	}
+
+	private ParserHelper() {
+		//cannot instantiate
+	}
+
+	public static void parse(Parser p, String text, String seperators, QueryTranslatorImpl q) throws QueryException {
+		StringTokenizer tokens = new StringTokenizer( text, seperators, true );
+		p.start( q );
+		while ( tokens.hasMoreElements() ) p.token( tokens.nextToken(), q );
+		p.end( q );
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/PathExpressionParser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/PathExpressionParser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/PathExpressionParser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,504 @@
+//$Id: PathExpressionParser.java 10830 2006-11-16 20:22:07Z steve.ebersole at jboss.com $
+package org.hibernate.hql.classic;
+
+import java.util.LinkedList;
+import java.util.Map;
+
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.engine.JoinSequence;
+import org.hibernate.hql.CollectionSubqueryFactory;
+import org.hibernate.persister.collection.CollectionPropertyMapping;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.PropertyMapping;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * Parses an expression of the form foo.bar.baz and builds up an expression
+ * involving two less table joins than there are path components.
+ */
+public class PathExpressionParser implements Parser {
+
+	//TODO: this class does too many things! we need a different
+	//kind of path expression parser for each of the diffferent
+	//ways in which path expressions can occur
+
+	//We should actually rework this class to not implement Parser
+	//and just process path expressions in the most convenient way.
+
+	//The class is now way to complex!
+
+	private int dotcount;
+	private String currentName;
+	private String currentProperty;
+	private String oneToOneOwnerName;
+	private AssociationType ownerAssociationType;
+	private String[] columns;
+	private String collectionName;
+	private String collectionOwnerName;
+	private String collectionRole;
+	private final StringBuffer componentPath = new StringBuffer();
+	private Type type;
+	private final StringBuffer path = new StringBuffer();
+	private boolean ignoreInitialJoin;
+	private boolean continuation;
+	private int joinType = JoinFragment.INNER_JOIN; //default mode
+	private boolean useThetaStyleJoin = true;
+	private PropertyMapping currentPropertyMapping;
+	private JoinSequence joinSequence;
+
+	private boolean expectingCollectionIndex;
+	private LinkedList collectionElements = new LinkedList();
+
+	void setJoinType(int joinType) {
+		this.joinType = joinType;
+	}
+
+	void setUseThetaStyleJoin(boolean useThetaStyleJoin) {
+		this.useThetaStyleJoin = useThetaStyleJoin;
+	}
+
+	private void addJoin(String name, AssociationType joinableType) throws QueryException {
+		try {
+			joinSequence.addJoin( joinableType, name, joinType, currentColumns() );
+		}
+		catch ( MappingException me ) {
+			throw new QueryException( me );
+		}
+	}
+
+	private void addJoin(String name, AssociationType joinableType, String[] foreignKeyColumns) throws QueryException {
+		try {
+			joinSequence.addJoin( joinableType, name, joinType, foreignKeyColumns );
+		}
+		catch ( MappingException me ) {
+			throw new QueryException( me );
+		}
+	}
+
+	String continueFromManyToMany(String entityName, String[] joinColumns, QueryTranslatorImpl q) throws QueryException {
+		start( q );
+		continuation = true;
+		currentName = q.createNameFor( entityName );
+		q.addType( currentName, entityName );
+		Queryable classPersister = q.getEntityPersister( entityName );
+		//QueryJoinFragment join = q.createJoinFragment(useThetaStyleJoin);
+		addJoin( currentName, TypeFactory.manyToOne( entityName ), joinColumns );
+		currentPropertyMapping = classPersister;
+		return currentName;
+	}
+
+	public void ignoreInitialJoin() {
+		ignoreInitialJoin = true;
+	}
+
+	public void token(String token, QueryTranslatorImpl q) throws QueryException {
+
+		if ( token != null ) path.append( token );
+
+		String alias = q.getPathAlias( path.toString() );
+		if ( alias != null ) {
+			reset( q ); //reset the dotcount (but not the path)
+			currentName = alias; //after reset!
+			currentPropertyMapping = q.getPropertyMapping( currentName );
+			if ( !ignoreInitialJoin ) {
+				JoinSequence ojf = q.getPathJoin( path.toString() );
+				try {
+					joinSequence.addCondition( ojf.toJoinFragment( q.getEnabledFilters(), true ).toWhereFragmentString() ); //after reset!
+				}
+				catch ( MappingException me ) {
+					throw new QueryException( me );
+				}
+				// we don't need to worry about any condition in the ON clause
+				// here (toFromFragmentString), since anything in the ON condition
+				// is already applied to the whole query
+			}
+		}
+		else if ( ".".equals( token ) ) {
+			dotcount++;
+		}
+		else {
+			if ( dotcount == 0 ) {
+				if ( !continuation ) {
+					if ( !q.isName( token ) ) throw new QueryException( "undefined alias: " + token );
+					currentName = token;
+					currentPropertyMapping = q.getPropertyMapping( currentName );
+				}
+			}
+			else if ( dotcount == 1 ) {
+				if ( currentName != null ) {
+					currentProperty = token;
+				}
+				else if ( collectionName != null ) {
+					//processCollectionProperty(token, q.getCollectionPersister(collectionRole), collectionName);
+					continuation = false;
+				}
+				else {
+					throw new QueryException( "unexpected" );
+				}
+			}
+			else { // dotcount>=2
+
+				// Do the corresponding RHS
+				Type propertyType = getPropertyType();
+
+				if ( propertyType == null ) {
+					throw new QueryException( "unresolved property: " + path );
+				}
+
+				if ( propertyType.isComponentType() ) {
+					dereferenceComponent( token );
+				}
+				else if ( propertyType.isEntityType() ) {
+					if ( !isCollectionValued() ) dereferenceEntity( token, ( EntityType ) propertyType, q );
+				}
+				else if ( propertyType.isCollectionType() ) {
+					dereferenceCollection( token, ( ( CollectionType ) propertyType ).getRole(), q );
+
+				}
+				else {
+					if ( token != null ) throw new QueryException( "dereferenced: " + path );
+				}
+
+			}
+		}
+	}
+
+	private void dereferenceEntity(String propertyName, EntityType propertyType, QueryTranslatorImpl q)
+			throws QueryException {
+		//NOTE: we avoid joining to the next table if the named property is just the foreign key value
+
+		//if its "id"
+		boolean isIdShortcut = EntityPersister.ENTITY_ID.equals( propertyName ) &&
+				propertyType.isReferenceToPrimaryKey();
+
+		//or its the id property name
+		final String idPropertyName;
+		try {
+			idPropertyName = propertyType.getIdentifierOrUniqueKeyPropertyName( q.getFactory() );
+		}
+		catch ( MappingException me ) {
+			throw new QueryException( me );
+		}
+		boolean isNamedIdPropertyShortcut = idPropertyName != null
+				&& idPropertyName.equals( propertyName )
+				&& propertyType.isReferenceToPrimaryKey();
+
+
+		if ( isIdShortcut || isNamedIdPropertyShortcut ) {
+			// special shortcut for id properties, skip the join!
+			// this must only occur at the _end_ of a path expression
+			if ( componentPath.length() > 0 ) componentPath.append( '.' );
+			componentPath.append( propertyName );
+		}
+		else {
+			String entityClass = propertyType.getAssociatedEntityName();
+			String name = q.createNameFor( entityClass );
+			q.addType( name, entityClass );
+			addJoin( name, propertyType );
+			if ( propertyType.isOneToOne() ) oneToOneOwnerName = currentName;
+			ownerAssociationType = propertyType;
+			currentName = name;
+			currentProperty = propertyName;
+			q.addPathAliasAndJoin( path.substring( 0, path.toString().lastIndexOf( '.' ) ), name, joinSequence.copy() );
+			componentPath.setLength( 0 );
+			currentPropertyMapping = q.getEntityPersister( entityClass );
+		}
+	}
+
+	private void dereferenceComponent(String propertyName) {
+		if ( propertyName != null ) {
+			if ( componentPath.length() > 0 ) componentPath.append( '.' );
+			componentPath.append( propertyName );
+		}
+	}
+
+	private void dereferenceCollection(String propertyName, String role, QueryTranslatorImpl q) throws QueryException {
+		collectionRole = role;
+		QueryableCollection collPersister = q.getCollectionPersister( role );
+		String name = q.createNameForCollection( role );
+		addJoin( name, collPersister.getCollectionType() );
+		//if ( collPersister.hasWhere() ) join.addCondition( collPersister.getSQLWhereString(name) );
+		collectionName = name;
+		collectionOwnerName = currentName;
+		currentName = name;
+		currentProperty = propertyName;
+		componentPath.setLength( 0 );
+		currentPropertyMapping = new CollectionPropertyMapping( collPersister );
+	}
+
+	private String getPropertyPath() {
+		if ( currentProperty == null ) {
+			return EntityPersister.ENTITY_ID;
+		}
+		else {
+			if ( componentPath.length() > 0 ) {
+				return new StringBuffer()
+						.append( currentProperty )
+						.append( '.' )
+						.append( componentPath.toString() )
+						.toString();
+			}
+			else {
+				return currentProperty;
+			}
+		}
+	}
+
+	private PropertyMapping getPropertyMapping() {
+		return currentPropertyMapping;
+	}
+
+	private void setType() throws QueryException {
+		if ( currentProperty == null ) {
+			type = getPropertyMapping().getType();
+		}
+		else {
+			type = getPropertyType();
+		}
+	}
+
+	protected Type getPropertyType() throws QueryException {
+		String propertyPath = getPropertyPath();
+		Type propertyType = getPropertyMapping().toType( propertyPath );
+		if ( propertyType == null ) {
+			throw new QueryException( "could not resolve property type: " + propertyPath );
+		}
+		return propertyType;
+	}
+
+	protected String[] currentColumns() throws QueryException {
+		String propertyPath = getPropertyPath();
+		String[] propertyColumns = getPropertyMapping().toColumns( currentName, propertyPath );
+		if ( propertyColumns == null ) {
+			throw new QueryException( "could not resolve property columns: " + propertyPath );
+		}
+		return propertyColumns;
+	}
+
+	private void reset(QueryTranslatorImpl q) {
+		//join = q.createJoinFragment(useThetaStyleJoin);
+		dotcount = 0;
+		currentName = null;
+		currentProperty = null;
+		collectionName = null;
+		collectionRole = null;
+		componentPath.setLength( 0 );
+		type = null;
+		collectionName = null;
+		columns = null;
+		expectingCollectionIndex = false;
+		continuation = false;
+		currentPropertyMapping = null;
+	}
+
+	public void start(QueryTranslatorImpl q) {
+		if ( !continuation ) {
+			reset( q );
+			path.setLength( 0 );
+			joinSequence = new JoinSequence( q.getFactory() ).setUseThetaStyle( useThetaStyleJoin );
+		}
+	}
+
+	public void end(QueryTranslatorImpl q) throws QueryException {
+		ignoreInitialJoin = false;
+
+		Type propertyType = getPropertyType();
+		if ( propertyType != null && propertyType.isCollectionType() ) {
+			collectionRole = ( ( CollectionType ) propertyType ).getRole();
+			collectionName = q.createNameForCollection( collectionRole );
+			prepareForIndex( q );
+		}
+		else {
+			columns = currentColumns();
+			setType();
+		}
+
+		//important!!
+		continuation = false;
+
+	}
+
+	private void prepareForIndex(QueryTranslatorImpl q) throws QueryException {
+
+		QueryableCollection collPersister = q.getCollectionPersister( collectionRole );
+
+		if ( !collPersister.hasIndex() ) throw new QueryException( "unindexed collection before []: " + path );
+		String[] indexCols = collPersister.getIndexColumnNames();
+		if ( indexCols.length != 1 ) throw new QueryException( "composite-index appears in []: " + path );
+		//String[] keyCols = collPersister.getKeyColumnNames();
+
+		JoinSequence fromJoins = new JoinSequence( q.getFactory() )
+				.setUseThetaStyle( useThetaStyleJoin )
+				.setRoot( collPersister, collectionName )
+				.setNext( joinSequence.copy() );
+
+		if ( !continuation ) addJoin( collectionName, collPersister.getCollectionType() );
+
+		joinSequence.addCondition( collectionName + '.' + indexCols[0] + " = " ); //TODO: get SQL rendering out of here
+
+		CollectionElement elem = new CollectionElement();
+		elem.elementColumns = collPersister.getElementColumnNames(collectionName);
+		elem.elementType = collPersister.getElementType();
+		elem.isOneToMany = collPersister.isOneToMany();
+		elem.alias = collectionName;
+		elem.joinSequence = joinSequence;
+		collectionElements.addLast( elem );
+		setExpectingCollectionIndex();
+
+		q.addCollection( collectionName, collectionRole );
+		q.addFromJoinOnly( collectionName, fromJoins );
+	}
+
+	static final class CollectionElement {
+		Type elementType;
+		boolean isOneToMany;
+		String alias;
+		String[] elementColumns;
+		JoinSequence joinSequence;
+		StringBuffer indexValue = new StringBuffer();
+	}
+
+	public CollectionElement lastCollectionElement() {
+		return ( CollectionElement ) collectionElements.removeLast();
+	}
+
+	public void setLastCollectionElementIndexValue(String value) {
+		( ( CollectionElement ) collectionElements.getLast() ).indexValue.append( value );
+	}
+
+	public boolean isExpectingCollectionIndex() {
+		return expectingCollectionIndex;
+	}
+
+	protected void setExpectingCollectionIndex() throws QueryException {
+		expectingCollectionIndex = true;
+	}
+
+	public JoinSequence getWhereJoin() {
+		return joinSequence;
+	}
+
+	public String getWhereColumn() throws QueryException {
+		if ( columns.length != 1 ) {
+			throw new QueryException( "path expression ends in a composite value: " + path );
+		}
+		return columns[0];
+	}
+
+	public String[] getWhereColumns() {
+		return columns;
+	}
+
+	public Type getWhereColumnType() {
+		return type;
+	}
+
+	public String getName() {
+		return currentName == null ? collectionName : currentName;
+	}
+
+
+	public String getCollectionSubquery(Map enabledFilters) throws QueryException {
+		return CollectionSubqueryFactory.createCollectionSubquery( joinSequence, enabledFilters, currentColumns() );
+	}
+
+	public boolean isCollectionValued() throws QueryException {
+		//TODO: is there a better way?
+		return collectionName != null && !getPropertyType().isCollectionType();
+	}
+
+	public void addAssociation(QueryTranslatorImpl q) throws QueryException {
+		q.addJoin( getName(), joinSequence );
+	}
+
+	public String addFromAssociation(QueryTranslatorImpl q) throws QueryException {
+		if ( isCollectionValued() ) {
+			return addFromCollection( q );
+		}
+		else {
+			q.addFrom( currentName, joinSequence );
+			return currentName;
+		}
+	}
+
+	public String addFromCollection(QueryTranslatorImpl q) throws QueryException {
+		Type collectionElementType = getPropertyType();
+
+		if ( collectionElementType == null ) {
+			throw new QueryException( "must specify 'elements' for collection valued property in from clause: " + path );
+		}
+
+		if ( collectionElementType.isEntityType() ) {
+			// an association
+			QueryableCollection collectionPersister = q.getCollectionPersister( collectionRole );
+			Queryable entityPersister = ( Queryable ) collectionPersister.getElementPersister();
+			String clazz = entityPersister.getEntityName();
+
+			final String elementName;
+			if ( collectionPersister.isOneToMany() ) {
+				elementName = collectionName;
+				//allow index() function:
+				q.decoratePropertyMapping( elementName, collectionPersister );
+			}
+			else { //many-to-many
+				q.addCollection( collectionName, collectionRole );
+				elementName = q.createNameFor( clazz );
+				addJoin( elementName, ( AssociationType ) collectionElementType );
+			}
+			q.addFrom( elementName, clazz, joinSequence );
+			currentPropertyMapping = new CollectionPropertyMapping( collectionPersister );
+			return elementName;
+		}
+		else {
+			// collections of values
+			q.addFromCollection( collectionName, collectionRole, joinSequence );
+			return collectionName;
+		}
+
+	}
+
+	String getCollectionName() {
+		return collectionName;
+	}
+
+	String getCollectionRole() {
+		return collectionRole;
+	}
+
+	String getCollectionOwnerName() {
+		return collectionOwnerName;
+	}
+
+	String getOneToOneOwnerName() {
+		return oneToOneOwnerName;
+	}
+
+	AssociationType getOwnerAssociationType() {
+		return ownerAssociationType;
+	}
+
+	String getCurrentProperty() {
+		return currentProperty;
+	}
+
+	String getCurrentName() {
+		return currentName;
+	}
+
+	public void fetch(QueryTranslatorImpl q, String entityName) throws QueryException {
+		if ( isCollectionValued() ) {
+			q.setCollectionToFetch( getCollectionRole(), getCollectionName(), getCollectionOwnerName(), entityName );
+		}
+		else {
+			q.addEntityToFetch( entityName, getOneToOneOwnerName(), getOwnerAssociationType() );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/PreprocessingParser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/PreprocessingParser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/PreprocessingParser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,133 @@
+//$Id: PreprocessingParser.java 5063 2004-12-24 03:51:20Z pgmjsd $
+package org.hibernate.hql.classic;
+
+import org.hibernate.QueryException;
+import org.hibernate.hql.CollectionProperties;
+import org.hibernate.util.StringHelper;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *
+ */
+public class PreprocessingParser implements Parser {
+
+	private static final Set HQL_OPERATORS;
+
+	static {
+		HQL_OPERATORS = new HashSet();
+		HQL_OPERATORS.add( "<=" );
+		HQL_OPERATORS.add( ">=" );
+		HQL_OPERATORS.add( "=>" );
+		HQL_OPERATORS.add( "=<" );
+		HQL_OPERATORS.add( "!=" );
+		HQL_OPERATORS.add( "<>" );
+		HQL_OPERATORS.add( "!#" );
+		HQL_OPERATORS.add( "!~" );
+		HQL_OPERATORS.add( "!<" );
+		HQL_OPERATORS.add( "!>" );
+		HQL_OPERATORS.add( "is not" );
+		HQL_OPERATORS.add( "not like" );
+		HQL_OPERATORS.add( "not in" );
+		HQL_OPERATORS.add( "not between" );
+		HQL_OPERATORS.add( "not exists" );
+	}
+
+	private Map replacements;
+	private boolean quoted;
+	private StringBuffer quotedString;
+	private ClauseParser parser = new ClauseParser();
+	private String lastToken;
+	private String currentCollectionProp;
+
+	public PreprocessingParser(Map replacements) {
+		this.replacements = replacements;
+	}
+
+	public void token(String token, QueryTranslatorImpl q) throws QueryException {
+
+		//handle quoted strings
+		if ( quoted ) {
+			quotedString.append( token );
+		}
+		if ( "'".equals( token ) ) {
+			if ( quoted ) {
+				token = quotedString.toString();
+			}
+			else {
+				quotedString = new StringBuffer( 20 ).append( token );
+			}
+			quoted = !quoted;
+		}
+		if ( quoted ) return;
+
+		//ignore whitespace
+		if ( ParserHelper.isWhitespace( token ) ) return;
+
+		//do replacements
+		String substoken = ( String ) replacements.get( token );
+		token = ( substoken == null ) ? token : substoken;
+
+		//handle HQL2 collection syntax
+		if ( currentCollectionProp != null ) {
+			if ( "(".equals( token ) ) {
+				return;
+			}
+			else if ( ")".equals( token ) ) {
+				currentCollectionProp = null;
+				return;
+			}
+			else {
+				token = StringHelper.qualify( token, currentCollectionProp );
+			}
+		}
+		else {
+			String prop = CollectionProperties.getNormalizedPropertyName( token.toLowerCase() );
+			if ( prop != null ) {
+				currentCollectionProp = prop;
+				return;
+			}
+		}
+
+
+		//handle <=, >=, !=, is not, not between, not in
+		if ( lastToken == null ) {
+			lastToken = token;
+		}
+		else {
+			String doubleToken = ( token.length() > 1 ) ?
+					lastToken + ' ' + token :
+					lastToken + token;
+			if ( HQL_OPERATORS.contains( doubleToken.toLowerCase() ) ) {
+				parser.token( doubleToken, q );
+				lastToken = null;
+			}
+			else {
+				parser.token( lastToken, q );
+				lastToken = token;
+			}
+		}
+
+	}
+
+	public void start(QueryTranslatorImpl q) throws QueryException {
+		quoted = false;
+		parser.start( q );
+	}
+
+	public void end(QueryTranslatorImpl q) throws QueryException {
+		if ( lastToken != null ) parser.token( lastToken, q );
+		parser.end( q );
+		lastToken = null;
+		currentCollectionProp = null;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/QueryTranslatorImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/QueryTranslatorImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/QueryTranslatorImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1161 @@
+//$Id: QueryTranslatorImpl.java 11080 2007-01-23 16:29:18Z steve.ebersole at jboss.com $
+package org.hibernate.hql.classic;
+
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections.SequencedHashMap;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.ScrollableResults;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.JoinSequence;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.event.EventSource;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.hql.FilterTranslator;
+import org.hibernate.hql.HolderInstantiator;
+import org.hibernate.hql.NameGenerator;
+import org.hibernate.hql.ParameterTranslations;
+import org.hibernate.impl.IteratorImpl;
+import org.hibernate.loader.BasicLoader;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.persister.entity.PropertyMapping;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.sql.QuerySelect;
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * An instance of <tt>QueryTranslator</tt> translates a Hibernate
+ * query string to SQL.
+ */
+public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator {
+
+	private static final String[] NO_RETURN_ALIASES = new String[] {};
+
+	private final String queryIdentifier;
+	private final String queryString;
+
+	private final Map typeMap = new SequencedHashMap();
+	private final Map collections = new SequencedHashMap();
+	private List returnedTypes = new ArrayList();
+	private final List fromTypes = new ArrayList();
+	private final List scalarTypes = new ArrayList();
+	private final Map namedParameters = new HashMap();
+	private final Map aliasNames = new HashMap();
+	private final Map oneToOneOwnerNames = new HashMap();
+	private final Map uniqueKeyOwnerReferences = new HashMap();
+	private final Map decoratedPropertyMappings = new HashMap();
+
+	private final List scalarSelectTokens = new ArrayList();
+	private final List whereTokens = new ArrayList();
+	private final List havingTokens = new ArrayList();
+	private final Map joins = new SequencedHashMap();
+	private final List orderByTokens = new ArrayList();
+	private final List groupByTokens = new ArrayList();
+	private final Set querySpaces = new HashSet();
+	private final Set entitiesToFetch = new HashSet();
+
+	private final Map pathAliases = new HashMap();
+	private final Map pathJoins = new HashMap();
+
+	private Queryable[] persisters;
+	private int[] owners;
+	private EntityType[] ownerAssociationTypes;
+	private String[] names;
+	private boolean[] includeInSelect;
+	private int selectLength;
+	private Type[] returnTypes;
+	private Type[] actualReturnTypes;
+	private String[][] scalarColumnNames;
+	private Map tokenReplacements;
+	private int nameCount = 0;
+	private int parameterCount = 0;
+	private boolean distinct = false;
+	private boolean compiled;
+	private String sqlString;
+	private Class holderClass;
+	private Constructor holderConstructor;
+	private boolean hasScalars;
+	private boolean shallowQuery;
+	private QueryTranslatorImpl superQuery;
+
+	private QueryableCollection collectionPersister;
+	private int collectionOwnerColumn = -1;
+	private String collectionOwnerName;
+	private String fetchName;
+
+	private String[] suffixes;
+
+	private Map enabledFilters;
+
+	private static final Log log = LogFactory.getLog( QueryTranslatorImpl.class );
+
+	/**
+	 * Construct a query translator
+	 *
+	 * @param queryIdentifier A unique identifier for the query of which this
+	 * translation is part; typically this is the original, user-supplied query string.
+	 * @param queryString The "preprocessed" query string; at the very least
+	 * already processed by {@link org.hibernate.hql.QuerySplitter}.
+	 * @param enabledFilters Any enabled filters.
+	 * @param factory The session factory.
+	 */
+	public QueryTranslatorImpl(
+			String queryIdentifier,
+	        String queryString,
+	        Map enabledFilters,
+	        SessionFactoryImplementor factory) {
+		super( factory );
+		this.queryIdentifier = queryIdentifier;
+		this.queryString = queryString;
+		this.enabledFilters = enabledFilters;
+	}
+
+	/**
+	 * Construct a query translator; this form used internally.
+	 *
+	 * @param queryString The query string to process.
+	 * @param enabledFilters Any enabled filters.
+	 * @param factory The session factory.
+	 */
+	public QueryTranslatorImpl(
+	        String queryString,
+	        Map enabledFilters,
+	        SessionFactoryImplementor factory) {
+		this( queryString, queryString, enabledFilters, factory );
+	}
+
+	/**
+	 * Compile a subquery.
+	 *
+	 * @param superquery The containing query of the query to be compiled.
+	 *
+	 * @throws org.hibernate.MappingException Indicates problems resolving
+	 * things referenced in the query.
+	 * @throws org.hibernate.QueryException Generally some form of syntatic
+	 * failure.
+	 */
+	void compile(QueryTranslatorImpl superquery) throws QueryException, MappingException {
+		this.tokenReplacements = superquery.tokenReplacements;
+		this.superQuery = superquery;
+		this.shallowQuery = true;
+		this.enabledFilters = superquery.getEnabledFilters();
+		compile();
+	}
+
+
+	/**
+	 * Compile a "normal" query. This method may be called multiple
+	 * times. Subsequent invocations are no-ops.
+	 */
+	public synchronized void compile(
+			Map replacements,
+			boolean scalar) throws QueryException, MappingException {
+		if ( !compiled ) {
+			this.tokenReplacements = replacements;
+			this.shallowQuery = scalar;
+			compile();
+		}
+	}
+
+	/**
+	 * Compile a filter. This method may be called multiple
+	 * times. Subsequent invocations are no-ops.
+	 */
+	public synchronized void compile(
+			String collectionRole,
+			Map replacements,
+			boolean scalar) throws QueryException, MappingException {
+
+		if ( !isCompiled() ) {
+			addFromAssociation( "this", collectionRole );
+			compile( replacements, scalar );
+		}
+	}
+
+	/**
+	 * Compile the query (generate the SQL).
+	 *
+	 * @throws org.hibernate.MappingException Indicates problems resolving
+	 * things referenced in the query.
+	 * @throws org.hibernate.QueryException Generally some form of syntatic
+	 * failure.
+	 */
+	private void compile() throws QueryException, MappingException {
+
+		log.trace( "compiling query" );
+		try {
+			ParserHelper.parse( new PreprocessingParser( tokenReplacements ),
+					queryString,
+					ParserHelper.HQL_SEPARATORS,
+					this );
+			renderSQL();
+		}
+		catch ( QueryException qe ) {
+			qe.setQueryString( queryString );
+			throw qe;
+		}
+		catch ( MappingException me ) {
+			throw me;
+		}
+		catch ( Exception e ) {
+			log.debug( "unexpected query compilation problem", e );
+			e.printStackTrace();
+			QueryException qe = new QueryException( "Incorrect query syntax", e );
+			qe.setQueryString( queryString );
+			throw qe;
+		}
+
+		postInstantiate();
+
+		compiled = true;
+
+	}
+
+	public String getSQLString() {
+		return sqlString;
+	}
+
+	public List collectSqlStrings() {
+		return ArrayHelper.toList( new String[] { sqlString } );
+	}
+
+	public String getQueryString() {
+		return queryString;
+	}
+
+	/**
+	 * Persisters for the return values of a <tt>find()</tt> style query.
+	 *
+	 * @return an array of <tt>EntityPersister</tt>s.
+	 */
+	protected Loadable[] getEntityPersisters() {
+		return persisters;
+	}
+
+	/**
+	 * Types of the return values of an <tt>iterate()</tt> style query.
+	 *
+	 * @return an array of <tt>Type</tt>s.
+	 */
+	public Type[] getReturnTypes() {
+		return actualReturnTypes;
+	}
+	
+	public String[] getReturnAliases() {
+		// return aliases not supported in classic translator!
+		return NO_RETURN_ALIASES;
+	}
+
+	public String[][] getColumnNames() {
+		return scalarColumnNames;
+	}
+
+	private static void logQuery(String hql, String sql) {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "HQL: " + hql );
+			log.debug( "SQL: " + sql );
+		}
+	}
+
+	void setAliasName(String alias, String name) {
+		aliasNames.put( alias, name );
+	}
+
+	public String getAliasName(String alias) {
+		String name = ( String ) aliasNames.get( alias );
+		if ( name == null ) {
+			if ( superQuery != null ) {
+				name = superQuery.getAliasName( alias );
+			}
+			else {
+				name = alias;
+			}
+		}
+		return name;
+	}
+
+	String unalias(String path) {
+		String alias = StringHelper.root( path );
+		String name = getAliasName( alias );
+		if ( name != null ) {
+			return name + path.substring( alias.length() );
+		}
+		else {
+			return path;
+		}
+	}
+
+	void addEntityToFetch(String name, String oneToOneOwnerName, AssociationType ownerAssociationType) {
+		addEntityToFetch( name );
+		if ( oneToOneOwnerName != null ) oneToOneOwnerNames.put( name, oneToOneOwnerName );
+		if ( ownerAssociationType != null ) uniqueKeyOwnerReferences.put( name, ownerAssociationType );
+	}
+
+	private void addEntityToFetch(String name) {
+		entitiesToFetch.add( name );
+	}
+
+	private int nextCount() {
+		return ( superQuery == null ) ? nameCount++ : superQuery.nameCount++;
+	}
+
+	String createNameFor(String type) {
+		return StringHelper.generateAlias( type, nextCount() );
+	}
+
+	String createNameForCollection(String role) {
+		return StringHelper.generateAlias( role, nextCount() );
+	}
+
+	private String getType(String name) {
+		String type = ( String ) typeMap.get( name );
+		if ( type == null && superQuery != null ) {
+			type = superQuery.getType( name );
+		}
+		return type;
+	}
+
+	private String getRole(String name) {
+		String role = ( String ) collections.get( name );
+		if ( role == null && superQuery != null ) {
+			role = superQuery.getRole( name );
+		}
+		return role;
+	}
+
+	boolean isName(String name) {
+		return aliasNames.containsKey( name ) ||
+				typeMap.containsKey( name ) ||
+				collections.containsKey( name ) || (
+				superQuery != null && superQuery.isName( name )
+				);
+	}
+
+	PropertyMapping getPropertyMapping(String name) throws QueryException {
+		PropertyMapping decorator = getDecoratedPropertyMapping( name );
+		if ( decorator != null ) return decorator;
+
+		String type = getType( name );
+		if ( type == null ) {
+			String role = getRole( name );
+			if ( role == null ) {
+				throw new QueryException( "alias not found: " + name );
+			}
+			return getCollectionPersister( role ); //.getElementPropertyMapping();
+		}
+		else {
+			Queryable persister = getEntityPersister( type );
+			if ( persister == null ) throw new QueryException( "persistent class not found: " + type );
+			return persister;
+		}
+	}
+
+	private PropertyMapping getDecoratedPropertyMapping(String name) {
+		return ( PropertyMapping ) decoratedPropertyMappings.get( name );
+	}
+
+	void decoratePropertyMapping(String name, PropertyMapping mapping) {
+		decoratedPropertyMappings.put( name, mapping );
+	}
+
+	private Queryable getEntityPersisterForName(String name) throws QueryException {
+		String type = getType( name );
+		Queryable persister = getEntityPersister( type );
+		if ( persister == null ) throw new QueryException( "persistent class not found: " + type );
+		return persister;
+	}
+
+	Queryable getEntityPersisterUsingImports(String className) {
+		final String importedClassName = getFactory().getImportedClassName( className );
+		if ( importedClassName == null ) {
+			return null;
+		}
+		try {
+			return ( Queryable ) getFactory().getEntityPersister( importedClassName );
+		}
+		catch ( MappingException me ) {
+			return null;
+		}
+	}
+
+	Queryable getEntityPersister(String entityName) throws QueryException {
+		try {
+			return ( Queryable ) getFactory().getEntityPersister( entityName );
+		}
+		catch ( Exception e ) {
+			throw new QueryException( "persistent class not found: " + entityName );
+		}
+	}
+
+	QueryableCollection getCollectionPersister(String role) throws QueryException {
+		try {
+			return ( QueryableCollection ) getFactory().getCollectionPersister( role );
+		}
+		catch ( ClassCastException cce ) {
+			throw new QueryException( "collection role is not queryable: " + role );
+		}
+		catch ( Exception e ) {
+			throw new QueryException( "collection role not found: " + role );
+		}
+	}
+
+	void addType(String name, String type) {
+		typeMap.put( name, type );
+	}
+
+	void addCollection(String name, String role) {
+		collections.put( name, role );
+	}
+
+	void addFrom(String name, String type, JoinSequence joinSequence)
+			throws QueryException {
+		addType( name, type );
+		addFrom( name, joinSequence );
+	}
+
+	void addFromCollection(String name, String collectionRole, JoinSequence joinSequence)
+			throws QueryException {
+		//register collection role
+		addCollection( name, collectionRole );
+		addJoin( name, joinSequence );
+	}
+
+	void addFrom(String name, JoinSequence joinSequence)
+			throws QueryException {
+		fromTypes.add( name );
+		addJoin( name, joinSequence );
+	}
+
+	void addFromClass(String name, Queryable classPersister)
+			throws QueryException {
+		JoinSequence joinSequence = new JoinSequence( getFactory() )
+				.setRoot( classPersister, name );
+		//crossJoins.add(name);
+		addFrom( name, classPersister.getEntityName(), joinSequence );
+	}
+
+	void addSelectClass(String name) {
+		returnedTypes.add( name );
+	}
+
+	void addSelectScalar(Type type) {
+		scalarTypes.add( type );
+	}
+
+	void appendWhereToken(String token) {
+		whereTokens.add( token );
+	}
+
+	void appendHavingToken(String token) {
+		havingTokens.add( token );
+	}
+
+	void appendOrderByToken(String token) {
+		orderByTokens.add( token );
+	}
+
+	void appendGroupByToken(String token) {
+		groupByTokens.add( token );
+	}
+
+	void appendScalarSelectToken(String token) {
+		scalarSelectTokens.add( token );
+	}
+
+	void appendScalarSelectTokens(String[] tokens) {
+		scalarSelectTokens.add( tokens );
+	}
+
+	void addFromJoinOnly(String name, JoinSequence joinSequence) throws QueryException {
+		addJoin( name, joinSequence.getFromPart() );
+	}
+
+	void addJoin(String name, JoinSequence joinSequence) throws QueryException {
+		if ( !joins.containsKey( name ) ) joins.put( name, joinSequence );
+	}
+
+	void addNamedParameter(String name) {
+		if ( superQuery != null ) superQuery.addNamedParameter( name );
+		Integer loc = new Integer( parameterCount++ );
+		Object o = namedParameters.get( name );
+		if ( o == null ) {
+			namedParameters.put( name, loc );
+		}
+		else if ( o instanceof Integer ) {
+			ArrayList list = new ArrayList( 4 );
+			list.add( o );
+			list.add( loc );
+			namedParameters.put( name, list );
+		}
+		else {
+			( ( ArrayList ) o ).add( loc );
+		}
+	}
+
+	public int[] getNamedParameterLocs(String name) throws QueryException {
+		Object o = namedParameters.get( name );
+		if ( o == null ) {
+			QueryException qe = new QueryException( ERROR_NAMED_PARAMETER_DOES_NOT_APPEAR + name );
+			qe.setQueryString( queryString );
+			throw qe;
+		}
+		if ( o instanceof Integer ) {
+			return new int[]{ ( ( Integer ) o ).intValue() };
+		}
+		else {
+			return ArrayHelper.toIntArray( ( ArrayList ) o );
+		}
+	}
+
+	private void renderSQL() throws QueryException, MappingException {
+
+		final int rtsize;
+		if ( returnedTypes.size() == 0 && scalarTypes.size() == 0 ) {
+			//ie no select clause in HQL
+			returnedTypes = fromTypes;
+			rtsize = returnedTypes.size();
+		}
+		else {
+			rtsize = returnedTypes.size();
+			Iterator iter = entitiesToFetch.iterator();
+			while ( iter.hasNext() ) {
+				returnedTypes.add( iter.next() );
+			}
+		}
+		int size = returnedTypes.size();
+		persisters = new Queryable[size];
+		names = new String[size];
+		owners = new int[size];
+		ownerAssociationTypes = new EntityType[size];
+		suffixes = new String[size];
+		includeInSelect = new boolean[size];
+		for ( int i = 0; i < size; i++ ) {
+			String name = ( String ) returnedTypes.get( i );
+			//if ( !isName(name) ) throw new QueryException("unknown type: " + name);
+			persisters[i] = getEntityPersisterForName( name );
+			// TODO: cannot use generateSuffixes() - it handles the initial suffix differently.
+			suffixes[i] = ( size == 1 ) ? "" : Integer.toString( i ) + '_';
+			names[i] = name;
+			includeInSelect[i] = !entitiesToFetch.contains( name );
+			if ( includeInSelect[i] ) selectLength++;
+			if ( name.equals( collectionOwnerName ) ) collectionOwnerColumn = i;
+			String oneToOneOwner = ( String ) oneToOneOwnerNames.get( name );
+			owners[i] = ( oneToOneOwner == null ) ? -1 : returnedTypes.indexOf( oneToOneOwner );
+			ownerAssociationTypes[i] = (EntityType) uniqueKeyOwnerReferences.get( name );
+		}
+
+		if ( ArrayHelper.isAllNegative( owners ) ) owners = null;
+
+		String scalarSelect = renderScalarSelect(); //Must be done here because of side-effect! yuck...
+
+		int scalarSize = scalarTypes.size();
+		hasScalars = scalarTypes.size() != rtsize;
+
+		returnTypes = new Type[scalarSize];
+		for ( int i = 0; i < scalarSize; i++ ) {
+			returnTypes[i] = ( Type ) scalarTypes.get( i );
+		}
+
+		QuerySelect sql = new QuerySelect( getFactory().getDialect() );
+		sql.setDistinct( distinct );
+
+		if ( !shallowQuery ) {
+			renderIdentifierSelect( sql );
+			renderPropertiesSelect( sql );
+		}
+
+		if ( collectionPersister != null ) {
+			sql.addSelectFragmentString( collectionPersister.selectFragment( fetchName, "__" ) );
+		}
+
+		if ( hasScalars || shallowQuery ) sql.addSelectFragmentString( scalarSelect );
+
+		//TODO: for some dialects it would be appropriate to add the renderOrderByPropertiesSelect() to other select strings
+		mergeJoins( sql.getJoinFragment() );
+
+		sql.setWhereTokens( whereTokens.iterator() );
+
+		sql.setGroupByTokens( groupByTokens.iterator() );
+		sql.setHavingTokens( havingTokens.iterator() );
+		sql.setOrderByTokens( orderByTokens.iterator() );
+
+		if ( collectionPersister != null && collectionPersister.hasOrdering() ) {
+			sql.addOrderBy( collectionPersister.getSQLOrderByString( fetchName ) );
+		}
+
+		scalarColumnNames = NameGenerator.generateColumnNames( returnTypes, getFactory() );
+
+		// initialize the Set of queried identifier spaces (ie. tables)
+		Iterator iter = collections.values().iterator();
+		while ( iter.hasNext() ) {
+			CollectionPersister p = getCollectionPersister( ( String ) iter.next() );
+			addQuerySpaces( p.getCollectionSpaces() );
+		}
+		iter = typeMap.keySet().iterator();
+		while ( iter.hasNext() ) {
+			Queryable p = getEntityPersisterForName( ( String ) iter.next() );
+			addQuerySpaces( p.getQuerySpaces() );
+		}
+
+		sqlString = sql.toQueryString();
+
+		if ( holderClass != null ) holderConstructor = ReflectHelper.getConstructor( holderClass, returnTypes );
+
+		if ( hasScalars ) {
+			actualReturnTypes = returnTypes;
+		}
+		else {
+			actualReturnTypes = new Type[selectLength];
+			int j = 0;
+			for ( int i = 0; i < persisters.length; i++ ) {
+				if ( includeInSelect[i] ) {
+					actualReturnTypes[j++] = TypeFactory.manyToOne( persisters[i].getEntityName(), shallowQuery );
+				}
+			}
+		}
+
+	}
+
+	private void renderIdentifierSelect(QuerySelect sql) {
+		int size = returnedTypes.size();
+
+		for ( int k = 0; k < size; k++ ) {
+			String name = ( String ) returnedTypes.get( k );
+			String suffix = size == 1 ? "" : Integer.toString( k ) + '_';
+			sql.addSelectFragmentString( persisters[k].identifierSelectFragment( name, suffix ) );
+		}
+
+	}
+
+	/*private String renderOrderByPropertiesSelect() {
+		StringBuffer buf = new StringBuffer(10);
+
+		//add the columns we are ordering by to the select ID select clause
+		Iterator iter = orderByTokens.iterator();
+		while ( iter.hasNext() ) {
+			String token = (String) iter.next();
+			if ( token.lastIndexOf(".") > 0 ) {
+				//ie. it is of form "foo.bar", not of form "asc" or "desc"
+				buf.append(StringHelper.COMMA_SPACE).append(token);
+			}
+		}
+
+		return buf.toString();
+	}*/
+
+	private void renderPropertiesSelect(QuerySelect sql) {
+		int size = returnedTypes.size();
+		for ( int k = 0; k < size; k++ ) {
+			String suffix = size == 1 ? "" : Integer.toString( k ) + '_';
+			String name = ( String ) returnedTypes.get( k );
+			sql.addSelectFragmentString( persisters[k].propertySelectFragment( name, suffix, false ) );
+		}
+	}
+
+	/**
+	 * WARNING: side-effecty
+	 */
+	private String renderScalarSelect() {
+
+		boolean isSubselect = superQuery != null;
+
+		StringBuffer buf = new StringBuffer( 20 );
+
+		if ( scalarTypes.size() == 0 ) {
+			//ie. no select clause
+			int size = returnedTypes.size();
+			for ( int k = 0; k < size; k++ ) {
+
+				scalarTypes.add( TypeFactory.manyToOne( persisters[k].getEntityName(), shallowQuery ) );
+
+				String[] idColumnNames = persisters[k].getIdentifierColumnNames();
+				for ( int i = 0; i < idColumnNames.length; i++ ) {
+					buf.append( returnedTypes.get( k ) ).append( '.' ).append( idColumnNames[i] );
+					if ( !isSubselect ) buf.append( " as " ).append( NameGenerator.scalarName( k, i ) );
+					if ( i != idColumnNames.length - 1 || k != size - 1 ) buf.append( ", " );
+				}
+
+			}
+
+		}
+		else {
+			//there _was_ a select clause
+			Iterator iter = scalarSelectTokens.iterator();
+			int c = 0;
+			boolean nolast = false; //real hacky...
+			int parenCount = 0; // used to count the nesting of parentheses
+			while ( iter.hasNext() ) {
+				Object next = iter.next();
+				if ( next instanceof String ) {
+					String token = ( String ) next;
+
+					if ( "(".equals( token ) ) {
+						parenCount++;
+					}
+					else if ( ")".equals( token ) ) {
+						parenCount--;
+					}
+
+					String lc = token.toLowerCase();
+					if ( lc.equals( ", " ) ) {
+						if ( nolast ) {
+							nolast = false;
+						}
+						else {
+							if ( !isSubselect && parenCount == 0 ) {
+								int x = c++;
+								buf.append( " as " )
+										.append( NameGenerator.scalarName( x, 0 ) );
+							}
+						}
+					}
+					buf.append( token );
+					if ( lc.equals( "distinct" ) || lc.equals( "all" ) ) {
+						buf.append( ' ' );
+					}
+				}
+				else {
+					nolast = true;
+					String[] tokens = ( String[] ) next;
+					for ( int i = 0; i < tokens.length; i++ ) {
+						buf.append( tokens[i] );
+						if ( !isSubselect ) {
+							buf.append( " as " )
+									.append( NameGenerator.scalarName( c, i ) );
+						}
+						if ( i != tokens.length - 1 ) buf.append( ", " );
+					}
+					c++;
+				}
+			}
+			if ( !isSubselect && !nolast ) {
+				int x = c++;
+				buf.append( " as " )
+						.append( NameGenerator.scalarName( x, 0 ) );
+			}
+
+		}
+
+		return buf.toString();
+	}
+
+	private void mergeJoins(JoinFragment ojf) throws MappingException, QueryException {
+
+		Iterator iter = joins.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = ( Map.Entry ) iter.next();
+			String name = ( String ) me.getKey();
+			JoinSequence join = ( JoinSequence ) me.getValue();
+			join.setSelector( new JoinSequence.Selector() {
+				public boolean includeSubclasses(String alias) {
+					boolean include = returnedTypes.contains( alias ) && !isShallowQuery();
+					return include;
+				}
+			} );
+
+			if ( typeMap.containsKey( name ) ) {
+				ojf.addFragment( join.toJoinFragment( enabledFilters, true ) );
+			}
+			else if ( collections.containsKey( name ) ) {
+				ojf.addFragment( join.toJoinFragment( enabledFilters, true ) );
+			}
+			else {
+				//name from a super query (a bit inelegant that it shows up here)
+			}
+
+		}
+
+	}
+
+	public final Set getQuerySpaces() {
+		return querySpaces;
+	}
+
+	/**
+	 * Is this query called by scroll() or iterate()?
+	 *
+	 * @return true if it is, false if it is called by find() or list()
+	 */
+	boolean isShallowQuery() {
+		return shallowQuery;
+	}
+
+	void addQuerySpaces(Serializable[] spaces) {
+		for ( int i = 0; i < spaces.length; i++ ) {
+			querySpaces.add( spaces[i] );
+		}
+		if ( superQuery != null ) superQuery.addQuerySpaces( spaces );
+	}
+
+	void setDistinct(boolean distinct) {
+		this.distinct = distinct;
+	}
+
+	boolean isSubquery() {
+		return superQuery != null;
+	}
+
+	/**
+	 * Overrides method from Loader
+	 */
+	public CollectionPersister[] getCollectionPersisters() {
+		return collectionPersister == null ? null : new CollectionPersister[] { collectionPersister };
+	}
+
+	protected String[] getCollectionSuffixes() {
+		return collectionPersister == null ? null : new String[] { "__" };
+	}
+
+	void setCollectionToFetch(String role, String name, String ownerName, String entityName)
+			throws QueryException {
+		fetchName = name;
+		collectionPersister = getCollectionPersister( role );
+		collectionOwnerName = ownerName;
+		if ( collectionPersister.getElementType().isEntityType() ) {
+			addEntityToFetch( entityName );
+		}
+	}
+
+	protected String[] getSuffixes() {
+		return suffixes;
+	}
+
+	protected String[] getAliases() {
+		return names;
+	}
+
+	/**
+	 * Used for collection filters
+	 */
+	private void addFromAssociation(final String elementName, final String collectionRole)
+			throws QueryException {
+		//q.addCollection(collectionName, collectionRole);
+		QueryableCollection persister = getCollectionPersister( collectionRole );
+		Type collectionElementType = persister.getElementType();
+		if ( !collectionElementType.isEntityType() ) {
+			throw new QueryException( "collection of values in filter: " + elementName );
+		}
+
+		String[] keyColumnNames = persister.getKeyColumnNames();
+		//if (keyColumnNames.length!=1) throw new QueryException("composite-key collection in filter: " + collectionRole);
+
+		String collectionName;
+		JoinSequence join = new JoinSequence( getFactory() );
+		collectionName = persister.isOneToMany() ?
+				elementName :
+				createNameForCollection( collectionRole );
+		join.setRoot( persister, collectionName );
+		if ( !persister.isOneToMany() ) {
+			//many-to-many
+			addCollection( collectionName, collectionRole );
+			try {
+				join.addJoin( ( AssociationType ) persister.getElementType(),
+						elementName,
+						JoinFragment.INNER_JOIN,
+						persister.getElementColumnNames(collectionName) );
+			}
+			catch ( MappingException me ) {
+				throw new QueryException( me );
+			}
+		}
+		join.addCondition( collectionName, keyColumnNames, " = ?" );
+		//if ( persister.hasWhere() ) join.addCondition( persister.getSQLWhereString(collectionName) );
+		EntityType elemType = ( EntityType ) collectionElementType;
+		addFrom( elementName, elemType.getAssociatedEntityName(), join );
+
+	}
+
+	String getPathAlias(String path) {
+		return ( String ) pathAliases.get( path );
+	}
+
+	JoinSequence getPathJoin(String path) {
+		return ( JoinSequence ) pathJoins.get( path );
+	}
+
+	void addPathAliasAndJoin(String path, String alias, JoinSequence joinSequence) {
+		pathAliases.put( path, alias );
+		pathJoins.put( path, joinSequence );
+	}
+
+	public List list(SessionImplementor session, QueryParameters queryParameters)
+			throws HibernateException {
+		return list( session, queryParameters, getQuerySpaces(), actualReturnTypes );
+	}
+
+	/**
+	 * Return the query results as an iterator
+	 */
+	public Iterator iterate(QueryParameters queryParameters, EventSource session)
+			throws HibernateException {
+
+		boolean stats = session.getFactory().getStatistics().isStatisticsEnabled();
+		long startTime = 0;
+		if ( stats ) startTime = System.currentTimeMillis();
+
+		try {
+
+			PreparedStatement st = prepareQueryStatement( queryParameters, false, session );
+			ResultSet rs = getResultSet( st, queryParameters.hasAutoDiscoverScalarTypes(), false, queryParameters.getRowSelection(), session );
+			HolderInstantiator hi = HolderInstantiator.createClassicHolderInstantiator(holderConstructor, queryParameters.getResultTransformer());
+			Iterator result = new IteratorImpl( rs, st, session, returnTypes, getColumnNames(), hi );
+
+			if ( stats ) {
+				session.getFactory().getStatisticsImplementor().queryExecuted(
+						"HQL: " + queryString,
+						0,
+						System.currentTimeMillis() - startTime
+					);
+			}
+
+			return result;
+
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert( 
+					getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not execute query using iterate",
+					getSQLString() 
+				);
+		}
+
+	}
+
+	public int executeUpdate(QueryParameters queryParameters, SessionImplementor session) throws HibernateException {
+		throw new UnsupportedOperationException( "Not supported!  Use the AST translator...");
+	}
+
+	protected Object getResultColumnOrRow(Object[] row, ResultTransformer transformer, ResultSet rs, SessionImplementor session)
+			throws SQLException, HibernateException {
+		row = toResultRow( row );
+		if ( hasScalars ) {
+			String[][] scalarColumns = getColumnNames();
+			int queryCols = returnTypes.length;
+			if ( holderClass == null && queryCols == 1 ) {
+				return returnTypes[0].nullSafeGet( rs, scalarColumns[0], session, null );
+			}
+			else {
+				row = new Object[queryCols];
+				for ( int i = 0; i < queryCols; i++ )
+					row[i] = returnTypes[i].nullSafeGet( rs, scalarColumns[i], session, null );
+				return row;
+			}
+		}
+		else if ( holderClass == null ) {
+			return row.length == 1 ? row[0] : row;
+		}
+		else {
+			return row;
+		}
+
+	}
+
+	protected List getResultList(List results, ResultTransformer resultTransformer) throws QueryException {
+		if ( holderClass != null ) {
+			for ( int i = 0; i < results.size(); i++ ) {
+				Object[] row = ( Object[] ) results.get( i );
+				try {
+					results.set( i, holderConstructor.newInstance( row ) );
+				}
+				catch ( Exception e ) {
+					throw new QueryException( "could not instantiate: " + holderClass, e );
+				}
+			}
+		}
+		return results;
+	}
+
+	private Object[] toResultRow(Object[] row) {
+		if ( selectLength == row.length ) {
+			return row;
+		}
+		else {
+			Object[] result = new Object[selectLength];
+			int j = 0;
+			for ( int i = 0; i < row.length; i++ ) {
+				if ( includeInSelect[i] ) result[j++] = row[i];
+			}
+			return result;
+		}
+	}
+
+	void setHolderClass(Class clazz) {
+		holderClass = clazz;
+	}
+
+	protected LockMode[] getLockModes(Map lockModes) {
+		// unfortunately this stuff can't be cached because
+		// it is per-invocation, not constant for the
+		// QueryTranslator instance
+		HashMap nameLockModes = new HashMap();
+		if ( lockModes != null ) {
+			Iterator iter = lockModes.entrySet().iterator();
+			while ( iter.hasNext() ) {
+				Map.Entry me = ( Map.Entry ) iter.next();
+				nameLockModes.put( getAliasName( ( String ) me.getKey() ),
+						me.getValue() );
+			}
+		}
+		LockMode[] lockModeArray = new LockMode[names.length];
+		for ( int i = 0; i < names.length; i++ ) {
+			LockMode lm = ( LockMode ) nameLockModes.get( names[i] );
+			if ( lm == null ) lm = LockMode.NONE;
+			lockModeArray[i] = lm;
+		}
+		return lockModeArray;
+	}
+
+	protected String applyLocks(String sql, Map lockModes, Dialect dialect) throws QueryException {
+		// can't cache this stuff either (per-invocation)
+		final String result;
+		if ( lockModes == null || lockModes.size() == 0 ) {
+			result = sql;
+		}
+		else {
+			Map aliasedLockModes = new HashMap();
+			Iterator iter = lockModes.entrySet().iterator();
+			while ( iter.hasNext() ) {
+				Map.Entry me = ( Map.Entry ) iter.next();
+				aliasedLockModes.put( getAliasName( ( String ) me.getKey() ), me.getValue() );
+			}
+			Map keyColumnNames = null;
+			if ( dialect.forUpdateOfColumns() ) {
+				keyColumnNames = new HashMap();
+				for ( int i = 0; i < names.length; i++ ) {
+					keyColumnNames.put( names[i], persisters[i].getIdentifierColumnNames() );
+				}
+			}
+			result = dialect.applyLocksToSql( sql, aliasedLockModes, keyColumnNames );
+		}
+		logQuery( queryString, result );
+		return result;
+	}
+
+	protected boolean upgradeLocks() {
+		return true;
+	}
+
+	protected int[] getCollectionOwners() {
+		return new int[] { collectionOwnerColumn };
+	}
+
+	protected boolean isCompiled() {
+		return compiled;
+	}
+
+	public String toString() {
+		return queryString;
+	}
+
+	protected int[] getOwners() {
+		return owners;
+	}
+
+	protected EntityType[] getOwnerAssociationTypes() {
+		return ownerAssociationTypes;
+	}
+
+	public Class getHolderClass() {
+		return holderClass;
+	}
+
+	public Map getEnabledFilters() {
+		return enabledFilters;
+	}
+
+	public ScrollableResults scroll(final QueryParameters queryParameters,
+									final SessionImplementor session)
+			throws HibernateException {
+		HolderInstantiator hi = HolderInstantiator.createClassicHolderInstantiator(holderConstructor, queryParameters.getResultTransformer());
+		return scroll( queryParameters, returnTypes, hi, session );
+	}
+
+	public String getQueryIdentifier() {
+		return queryIdentifier;
+	}
+
+	protected boolean isSubselectLoadingEnabled() {
+		return hasSubselectLoadableCollections();
+	}
+
+	public void validateScrollability() throws HibernateException {
+		// This is the legacy behaviour for HQL queries...
+		if ( getCollectionPersisters() != null ) {
+			throw new HibernateException( "Cannot scroll queries which initialize collections" );
+		}
+	}
+
+	public boolean containsCollectionFetches() {
+		return false;
+	}
+
+	public boolean isManipulationStatement() {
+		// classic parser does not support bulk manipulation statements
+		return false;
+	}
+
+	public ParameterTranslations getParameterTranslations() {
+		return new ParameterTranslations() {
+
+			public boolean supportsOrdinalParameterMetadata() {
+				// classic translator does not support collection of ordinal
+				// param metadata
+				return false;
+			}
+
+			public int getOrdinalParameterCount() {
+				return 0; // not known!
+			}
+
+			public int getOrdinalParameterSqlLocation(int ordinalPosition) {
+				return 0; // not known!
+			}
+
+			public Type getOrdinalParameterExpectedType(int ordinalPosition) {
+				return null; // not known!
+			}
+
+			public Set getNamedParameterNames() {
+				return namedParameters.keySet();
+			}
+
+			public int[] getNamedParameterSqlLocations(String name) {
+				return getNamedParameterLocs( name );
+			}
+
+			public Type getNamedParameterExpectedType(String name) {
+				return null; // not known!
+			}
+		};
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/SelectParser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/SelectParser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/SelectParser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,228 @@
+//$Id: SelectParser.java 9915 2006-05-09 09:38:15Z max.andersen at jboss.com $
+package org.hibernate.hql.classic;
+
+import org.hibernate.Hibernate;
+import org.hibernate.QueryException;
+import org.hibernate.dialect.function.SQLFunction;
+import org.hibernate.hql.QuerySplitter;
+import org.hibernate.type.Type;
+import org.hibernate.util.ReflectHelper;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Parsers the select clause of a Hibernate query.
+ *
+ * @author Gavin King, David Channon
+ */
+public class SelectParser implements Parser {
+
+	//TODO: arithmetic expressions, multiple new Foo(...)
+
+	private static final Set COUNT_MODIFIERS = new HashSet();
+
+	static {
+		COUNT_MODIFIERS.add( "distinct" );
+		COUNT_MODIFIERS.add( "all" );
+		COUNT_MODIFIERS.add( "*" );
+	}
+
+	private LinkedList aggregateFuncTokenList = new LinkedList();
+
+	private boolean ready;
+	private boolean aggregate;
+	private boolean first;
+	private boolean afterNew;
+	private boolean insideNew;
+	private boolean aggregateAddSelectScalar;
+	private Class holderClass;
+
+	private final SelectPathExpressionParser pathExpressionParser;
+	private final PathExpressionParser aggregatePathExpressionParser;
+
+	{
+		pathExpressionParser = new SelectPathExpressionParser();
+		aggregatePathExpressionParser = new PathExpressionParser();
+		//TODO: would be nice to use false, but issues with MS SQL
+		pathExpressionParser.setUseThetaStyleJoin( true );
+		aggregatePathExpressionParser.setUseThetaStyleJoin( true );
+	}
+
+	public void token(String token, QueryTranslatorImpl q) throws QueryException {
+
+		String lctoken = token.toLowerCase();
+
+		if ( first ) {
+			first = false;
+			if ( "distinct".equals( lctoken ) ) {
+				q.setDistinct( true );
+				return;
+			}
+			else if ( "all".equals( lctoken ) ) {
+				q.setDistinct( false );
+				return;
+			}
+		}
+
+		if ( afterNew ) {
+			afterNew = false;
+			try {
+				holderClass = ReflectHelper.classForName( QuerySplitter.getImportedClass( token, q.getFactory() ) );
+			}
+			catch ( ClassNotFoundException cnfe ) {
+				throw new QueryException( cnfe );
+			}
+			if ( holderClass == null ) throw new QueryException( "class not found: " + token );
+			q.setHolderClass( holderClass );
+			insideNew = true;
+		}
+		else if ( token.equals( "," ) ) {
+			if ( !aggregate && ready ) throw new QueryException( "alias or expression expected in SELECT" );
+			q.appendScalarSelectToken( ", " );
+			ready = true;
+		}
+		else if ( "new".equals( lctoken ) ) {
+			afterNew = true;
+			ready = false;
+		}
+		else if ( "(".equals( token ) ) {
+			if ( insideNew && !aggregate && !ready ) {
+				//opening paren in new Foo ( ... )
+				ready = true;
+			}
+			else if ( aggregate ) {
+				q.appendScalarSelectToken( token );
+			}
+			else {
+				throw new QueryException( "aggregate function expected before ( in SELECT" );
+			}
+			ready = true;
+		}
+		else if ( ")".equals( token ) ) {
+			if ( insideNew && !aggregate && !ready ) {
+				//if we are inside a new Result(), but not inside a nested function
+				insideNew = false;
+			}
+			else if ( aggregate && ready ) {
+				q.appendScalarSelectToken( token );
+				aggregateFuncTokenList.removeLast();
+				if ( aggregateFuncTokenList.size() < 1 ) {
+					aggregate = false;
+					ready = false;
+				}
+			}
+			else {
+				throw new QueryException( "( expected before ) in select" );
+			}
+		}
+		else if ( COUNT_MODIFIERS.contains( lctoken ) ) {
+			if ( !ready || !aggregate ) throw new QueryException( token + " only allowed inside aggregate function in SELECT" );
+			q.appendScalarSelectToken( token );
+			if ( "*".equals( token ) ) q.addSelectScalar( getFunction( "count", q ).getReturnType( Hibernate.LONG, q.getFactory() ) ); //special case
+		}
+		else if ( getFunction( lctoken, q ) != null && token.equals( q.unalias( token ) ) ) {
+			// the name of an SQL function
+			if ( !ready ) throw new QueryException( ", expected before aggregate function in SELECT: " + token );
+			aggregate = true;
+			aggregateAddSelectScalar = true;
+			aggregateFuncTokenList.add( lctoken );
+			ready = false;
+			q.appendScalarSelectToken( token );
+			if ( !aggregateHasArgs( lctoken, q ) ) {
+				q.addSelectScalar( aggregateType( aggregateFuncTokenList, null, q ) );
+				if ( !aggregateFuncNoArgsHasParenthesis( lctoken, q ) ) {
+					aggregateFuncTokenList.removeLast();
+					if ( aggregateFuncTokenList.size() < 1 ) {
+						aggregate = false;
+						ready = false;
+					}
+					else {
+						ready = true;
+					}
+				}
+			}
+		}
+		else if ( aggregate ) {
+			boolean constantToken = false;
+			if ( !ready ) throw new QueryException( "( expected after aggregate function in SELECT" );
+			try {
+				ParserHelper.parse( aggregatePathExpressionParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
+			}
+			catch ( QueryException qex ) {
+				constantToken = true;
+			}
+
+			if ( constantToken ) {
+				q.appendScalarSelectToken( token );
+			}
+			else {
+				if ( aggregatePathExpressionParser.isCollectionValued() ) {
+					q.addCollection( aggregatePathExpressionParser.getCollectionName(),
+							aggregatePathExpressionParser.getCollectionRole() );
+				}
+				q.appendScalarSelectToken( aggregatePathExpressionParser.getWhereColumn() );
+				if ( aggregateAddSelectScalar ) {
+					q.addSelectScalar( aggregateType( aggregateFuncTokenList, aggregatePathExpressionParser.getWhereColumnType(), q ) );
+					aggregateAddSelectScalar = false;
+				}
+				aggregatePathExpressionParser.addAssociation( q );
+			}
+		}
+		else {
+			if ( !ready ) throw new QueryException( ", expected in SELECT" );
+			ParserHelper.parse( pathExpressionParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
+			if ( pathExpressionParser.isCollectionValued() ) {
+				q.addCollection( pathExpressionParser.getCollectionName(),
+						pathExpressionParser.getCollectionRole() );
+			}
+			else if ( pathExpressionParser.getWhereColumnType().isEntityType() ) {
+				q.addSelectClass( pathExpressionParser.getSelectName() );
+			}
+			q.appendScalarSelectTokens( pathExpressionParser.getWhereColumns() );
+			q.addSelectScalar( pathExpressionParser.getWhereColumnType() );
+			pathExpressionParser.addAssociation( q );
+
+			ready = false;
+		}
+	}
+
+	public boolean aggregateHasArgs(String funcToken, QueryTranslatorImpl q) {
+		return getFunction( funcToken, q ).hasArguments();
+	}
+
+	public boolean aggregateFuncNoArgsHasParenthesis(String funcToken, QueryTranslatorImpl q) {
+		return getFunction( funcToken, q ).hasParenthesesIfNoArguments();
+	}
+
+	public Type aggregateType(List funcTokenList, Type type, QueryTranslatorImpl q) throws QueryException {
+		Type retType = type;
+		Type argType;
+		for ( int i = funcTokenList.size() - 1; i >= 0; i-- ) {
+			argType = retType;
+			String funcToken = ( String ) funcTokenList.get( i );
+			retType = getFunction( funcToken, q ).getReturnType( argType, q.getFactory() );
+		}
+		return retType;
+	}
+
+	private SQLFunction getFunction(String name, QueryTranslatorImpl q) {
+		return q.getFactory().getSqlFunctionRegistry().findSQLFunction( name );
+	}
+
+	public void start(QueryTranslatorImpl q) {
+		ready = true;
+		first = true;
+		aggregate = false;
+		afterNew = false;
+		insideNew = false;
+		holderClass = null;
+		aggregateFuncTokenList.clear();
+	}
+
+	public void end(QueryTranslatorImpl q) {
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/SelectPathExpressionParser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/SelectPathExpressionParser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/SelectPathExpressionParser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+//$Id: SelectPathExpressionParser.java 5861 2005-02-22 14:07:36Z oneovthafew $
+package org.hibernate.hql.classic;
+
+import org.hibernate.QueryException;
+
+public class SelectPathExpressionParser extends PathExpressionParser {
+
+	public void end(QueryTranslatorImpl q) throws QueryException {
+		if ( getCurrentProperty() != null && !q.isShallowQuery() ) {
+			// "finish off" the join
+			token( ".", q );
+			token( null, q );
+		}
+		super.end( q );
+	}
+
+	protected void setExpectingCollectionIndex() throws QueryException {
+		throw new QueryException( "illegal syntax near collection-valued path expression in select: "  + getCollectionName() );
+	}
+
+	public String getSelectName() {
+		return getCurrentName();
+	}
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/WhereParser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/WhereParser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/WhereParser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,493 @@
+//$Id: WhereParser.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.hql.classic;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.engine.JoinSequence;
+import org.hibernate.hql.QueryTranslator;
+import org.hibernate.persister.collection.CollectionPropertyNames;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.sql.InFragment;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.LiteralType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Parses the where clause of a hibernate query and translates it to an
+ * SQL where clause.
+ */
+
+// We should reengineer this class so that, rather than the current ad -
+// hoc linear approach to processing a stream of tokens, we instead
+// build up a tree of expressions.
+
+// We would probably refactor to have LogicParser (builds a tree of simple
+// expressions connected by and, or, not), ExpressionParser (translates
+// from OO terms like foo, foo.Bar, foo.Bar.Baz to SQL terms like
+// FOOS.ID, FOOS.BAR_ID, etc) and PathExpressionParser (which does much
+// the same thing it does now)
+
+public class WhereParser implements Parser {
+
+	private final PathExpressionParser pathExpressionParser;
+
+	{
+		pathExpressionParser = new PathExpressionParser();
+		pathExpressionParser.setUseThetaStyleJoin( true ); //Need this, since join condition can appear inside parens!
+	}
+
+	private static final Set EXPRESSION_TERMINATORS = new HashSet();   //tokens that close a sub expression
+	private static final Set EXPRESSION_OPENERS = new HashSet();       //tokens that open a sub expression
+	private static final Set BOOLEAN_OPERATORS = new HashSet();        //tokens that would indicate a sub expression is a boolean expression
+	private static final Map NEGATIONS = new HashMap();
+
+	static {
+		EXPRESSION_TERMINATORS.add( "and" );
+		EXPRESSION_TERMINATORS.add( "or" );
+		EXPRESSION_TERMINATORS.add( ")" );
+		//expressionTerminators.add(","); // deliberately excluded
+
+		EXPRESSION_OPENERS.add( "and" );
+		EXPRESSION_OPENERS.add( "or" );
+		EXPRESSION_OPENERS.add( "(" );
+		//expressionOpeners.add(","); // deliberately excluded
+
+		BOOLEAN_OPERATORS.add( "<" );
+		BOOLEAN_OPERATORS.add( "=" );
+		BOOLEAN_OPERATORS.add( ">" );
+		BOOLEAN_OPERATORS.add( "#" );
+		BOOLEAN_OPERATORS.add( "~" );
+		BOOLEAN_OPERATORS.add( "like" );
+		BOOLEAN_OPERATORS.add( "ilike" );
+		BOOLEAN_OPERATORS.add( "regexp" );
+		BOOLEAN_OPERATORS.add( "rlike" );
+		BOOLEAN_OPERATORS.add( "is" );
+		BOOLEAN_OPERATORS.add( "in" );
+		BOOLEAN_OPERATORS.add( "any" );
+		BOOLEAN_OPERATORS.add( "some" );
+		BOOLEAN_OPERATORS.add( "all" );
+		BOOLEAN_OPERATORS.add( "exists" );
+		BOOLEAN_OPERATORS.add( "between" );
+		BOOLEAN_OPERATORS.add( "<=" );
+		BOOLEAN_OPERATORS.add( ">=" );
+		BOOLEAN_OPERATORS.add( "=>" );
+		BOOLEAN_OPERATORS.add( "=<" );
+		BOOLEAN_OPERATORS.add( "!=" );
+		BOOLEAN_OPERATORS.add( "<>" );
+		BOOLEAN_OPERATORS.add( "!#" );
+		BOOLEAN_OPERATORS.add( "!~" );
+		BOOLEAN_OPERATORS.add( "!<" );
+		BOOLEAN_OPERATORS.add( "!>" );
+		BOOLEAN_OPERATORS.add( "is not" );
+		BOOLEAN_OPERATORS.add( "not like" );
+		BOOLEAN_OPERATORS.add( "not ilike" );
+		BOOLEAN_OPERATORS.add( "not regexp" );
+		BOOLEAN_OPERATORS.add( "not rlike" );
+		BOOLEAN_OPERATORS.add( "not in" );
+		BOOLEAN_OPERATORS.add( "not between" );
+		BOOLEAN_OPERATORS.add( "not exists" );
+
+		NEGATIONS.put( "and", "or" );
+		NEGATIONS.put( "or", "and" );
+		NEGATIONS.put( "<", ">=" );
+		NEGATIONS.put( "=", "<>" );
+		NEGATIONS.put( ">", "<=" );
+		NEGATIONS.put( "#", "!#" );
+		NEGATIONS.put( "~", "!~" );
+		NEGATIONS.put( "like", "not like" );
+		NEGATIONS.put( "ilike", "not ilike" );
+		NEGATIONS.put( "regexp", "not regexp" );
+		NEGATIONS.put( "rlike", "not rlike" );
+		NEGATIONS.put( "is", "is not" );
+		NEGATIONS.put( "in", "not in" );
+		NEGATIONS.put( "exists", "not exists" );
+		NEGATIONS.put( "between", "not between" );
+		NEGATIONS.put( "<=", ">" );
+		NEGATIONS.put( ">=", "<" );
+		NEGATIONS.put( "=>", "<" );
+		NEGATIONS.put( "=<", ">" );
+		NEGATIONS.put( "!=", "=" );
+		NEGATIONS.put( "<>", "=" );
+		NEGATIONS.put( "!#", "#" );
+		NEGATIONS.put( "!~", "~" );
+		NEGATIONS.put( "!<", "<" );
+		NEGATIONS.put( "!>", ">" );
+		NEGATIONS.put( "is not", "is" );
+		NEGATIONS.put( "not like", "like" );
+		NEGATIONS.put( "not ilike", "ilike" );
+		NEGATIONS.put( "not regexp", "regexp" );
+		NEGATIONS.put( "not rlike", "rlike" );
+		NEGATIONS.put( "not in", "in" );
+		NEGATIONS.put( "not between", "between" );
+		NEGATIONS.put( "not exists", "exists" );
+
+	}
+	// Handles things like:
+	// a and b or c
+	// a and ( b or c )
+	// not a and not b
+	// not ( a and b )
+	// x between y and z            (overloaded "and")
+	// x in ( a, b, c )             (overloaded brackets)
+	// not not a
+	// a is not null                (overloaded "not")
+	// etc......
+	// and expressions like
+	// foo = bar                    (maps to: foo.id = bar.id)
+	// foo.Bar = 'foo'              (maps to: foo.bar = 'foo')
+	// foo.Bar.Baz = 1.0            (maps to: foo.bar = bar.id and bar.baz = 1.0)
+	// 1.0 = foo.Bar.Baz            (maps to: bar.baz = 1.0 and foo.Bar = bar.id)
+	// foo.Bar.Baz = a.B.C          (maps to: bar.Baz = b.C and foo.Bar = bar.id and a.B = b.id)
+	// foo.Bar.Baz + a.B.C          (maps to: bar.Baz + b.C and foo.Bar = bar.id and a.B = b.id)
+	// ( foo.Bar.Baz + 1.0 ) < 2.0  (maps to: ( bar.Baz + 1.0 ) < 2.0 and foo.Bar = bar.id)
+
+	private boolean betweenSpecialCase = false;       //Inside a BETWEEN ... AND ... expression
+	private boolean negated = false;
+
+	private boolean inSubselect = false;
+	private int bracketsSinceSelect = 0;
+	private StringBuffer subselect;
+
+	private boolean expectingPathContinuation = false;
+	private int expectingIndex = 0;
+
+	// The following variables are stacks that keep information about each subexpression
+	// in the list of nested subexpressions we are currently processing.
+
+	private LinkedList nots = new LinkedList();           //were an odd or even number of NOTs encountered
+	private LinkedList joins = new LinkedList();          //the join string built up by compound paths inside this expression
+	private LinkedList booleanTests = new LinkedList();   //a flag indicating if the subexpression is known to be boolean
+
+	private String getElementName(PathExpressionParser.CollectionElement element, QueryTranslatorImpl q) throws QueryException {
+		String name;
+		if ( element.isOneToMany ) {
+			name = element.alias;
+		}
+		else {
+			Type type = element.elementType;
+			if ( type.isEntityType() ) { //ie. a many-to-many
+				String entityName = ( ( EntityType ) type ).getAssociatedEntityName();
+				name = pathExpressionParser.continueFromManyToMany( entityName, element.elementColumns, q );
+			}
+			else {
+				throw new QueryException( "illegally dereferenced collection element" );
+			}
+		}
+		return name;
+	}
+
+	public void token(String token, QueryTranslatorImpl q) throws QueryException {
+
+		String lcToken = token.toLowerCase();
+
+		//Cope with [,]
+		if ( token.equals( "[" ) && !expectingPathContinuation ) {
+			expectingPathContinuation = false;
+			if ( expectingIndex == 0 ) throw new QueryException( "unexpected [" );
+			return;
+		}
+		else if ( token.equals( "]" ) ) {
+			expectingIndex--;
+			expectingPathContinuation = true;
+			return;
+		}
+
+		//Cope with a continued path expression (ie. ].baz)
+		if ( expectingPathContinuation ) {
+			boolean pathExpressionContinuesFurther = continuePathExpression( token, q );
+			if ( pathExpressionContinuesFurther ) return; //NOTE: early return
+		}
+
+		//Cope with a subselect
+		if ( !inSubselect && ( lcToken.equals( "select" ) || lcToken.equals( "from" ) ) ) {
+			inSubselect = true;
+			subselect = new StringBuffer( 20 );
+		}
+		if ( inSubselect && token.equals( ")" ) ) {
+			bracketsSinceSelect--;
+
+			if ( bracketsSinceSelect == -1 ) {
+				QueryTranslatorImpl subq = new QueryTranslatorImpl(
+				        subselect.toString(),
+						q.getEnabledFilters(),
+						q.getFactory()
+				);
+				try {
+					subq.compile( q );
+				}
+				catch ( MappingException me ) {
+					throw new QueryException( "MappingException occurred compiling subquery", me );
+				}
+				appendToken( q, subq.getSQLString() );
+				inSubselect = false;
+				bracketsSinceSelect = 0;
+			}
+		}
+		if ( inSubselect ) {
+			if ( token.equals( "(" ) ) bracketsSinceSelect++;
+			subselect.append( token ).append( ' ' );
+			return;
+		}
+
+		//Cope with special cases of AND, NOT, ()
+		specialCasesBefore( lcToken );
+
+		//Close extra brackets we opened
+		if ( !betweenSpecialCase && EXPRESSION_TERMINATORS.contains( lcToken ) ) {
+			closeExpression( q, lcToken );
+		}
+
+		//take note when this is a boolean expression
+		if ( BOOLEAN_OPERATORS.contains( lcToken ) ) {
+			booleanTests.removeLast();
+			booleanTests.addLast( Boolean.TRUE );
+		}
+
+		if ( lcToken.equals( "not" ) ) {
+			nots.addLast( new Boolean( !( ( Boolean ) nots.removeLast() ).booleanValue() ) );
+			negated = !negated;
+			return; //NOTE: early return
+		}
+
+		//process a token, mapping OO path expressions to SQL expressions
+		doToken( token, q );
+
+		//Open any extra brackets we might need.
+		if ( !betweenSpecialCase && EXPRESSION_OPENERS.contains( lcToken ) ) {
+			openExpression( q, lcToken );
+		}
+
+		//Cope with special cases of AND, NOT, )
+		specialCasesAfter( lcToken );
+
+	}
+
+	public void start(QueryTranslatorImpl q) throws QueryException {
+		token( "(", q );
+	}
+
+	public void end(QueryTranslatorImpl q) throws QueryException {
+		if ( expectingPathContinuation ) {
+			expectingPathContinuation = false;
+			PathExpressionParser.CollectionElement element = pathExpressionParser.lastCollectionElement();
+			if ( element.elementColumns.length != 1 ) throw new QueryException( "path expression ended in composite collection element" );
+			appendToken( q, element.elementColumns[0] );
+			addToCurrentJoin( element );
+		}
+		token( ")", q );
+	}
+
+	private void closeExpression(QueryTranslatorImpl q, String lcToken) {
+		if ( ( ( Boolean ) booleanTests.removeLast() ).booleanValue() ) { //it was a boolean expression
+
+			if ( booleanTests.size() > 0 ) {
+				// the next one up must also be
+				booleanTests.removeLast();
+				booleanTests.addLast( Boolean.TRUE );
+			}
+
+			// Add any joins
+			appendToken( q, ( joins.removeLast() ).toString() );
+
+		}
+		else {
+			StringBuffer join = ( StringBuffer ) joins.removeLast();
+			( ( StringBuffer ) joins.getLast() ).append( join.toString() );
+		}
+
+		if ( ( ( Boolean ) nots.removeLast() ).booleanValue() ) negated = !negated;
+
+		if ( !")".equals( lcToken ) ) appendToken( q, ")" );
+	}
+
+	private void openExpression(QueryTranslatorImpl q, String lcToken) {
+		nots.addLast( Boolean.FALSE );
+		booleanTests.addLast( Boolean.FALSE );
+		joins.addLast( new StringBuffer() );
+		if ( !"(".equals( lcToken ) ) appendToken( q, "(" );
+	}
+
+	private void preprocess(String token, QueryTranslatorImpl q) throws QueryException {
+		// ugly hack for cases like "elements(foo.bar.collection)"
+		// (multi-part path expression ending in elements or indices)
+		String[] tokens = StringHelper.split( ".", token, true );
+		if (
+				tokens.length > 5 &&
+				( CollectionPropertyNames.COLLECTION_ELEMENTS.equals( tokens[tokens.length - 1] )
+				|| CollectionPropertyNames.COLLECTION_INDICES.equals( tokens[tokens.length - 1] ) )
+		) {
+			pathExpressionParser.start( q );
+			for ( int i = 0; i < tokens.length - 3; i++ ) {
+				pathExpressionParser.token( tokens[i], q );
+			}
+			pathExpressionParser.token( null, q );
+			pathExpressionParser.end( q );
+			addJoin( pathExpressionParser.getWhereJoin(), q );
+			pathExpressionParser.ignoreInitialJoin();
+		}
+	}
+
+	private void doPathExpression(String token, QueryTranslatorImpl q) throws QueryException {
+
+		preprocess( token, q );
+
+		StringTokenizer tokens = new StringTokenizer( token, ".", true );
+		pathExpressionParser.start( q );
+		while ( tokens.hasMoreTokens() ) {
+			pathExpressionParser.token( tokens.nextToken(), q );
+		}
+		pathExpressionParser.end( q );
+		if ( pathExpressionParser.isCollectionValued() ) {
+			openExpression( q, "" );
+			appendToken( q, pathExpressionParser.getCollectionSubquery( q.getEnabledFilters() ) );
+			closeExpression( q, "" );
+			// this is ugly here, but needed because its a subquery
+			q.addQuerySpaces( q.getCollectionPersister( pathExpressionParser.getCollectionRole() ).getCollectionSpaces() );
+		}
+		else {
+			if ( pathExpressionParser.isExpectingCollectionIndex() ) {
+				expectingIndex++;
+			}
+			else {
+				addJoin( pathExpressionParser.getWhereJoin(), q );
+				appendToken( q, pathExpressionParser.getWhereColumn() );
+			}
+		}
+	}
+
+	private void addJoin(JoinSequence joinSequence, QueryTranslatorImpl q) throws QueryException {
+		//JoinFragment fromClause = q.createJoinFragment(true);
+		//fromClause.addJoins( join.toJoinFragment().toFromFragmentString(), StringHelper.EMPTY_STRING );
+		q.addFromJoinOnly( pathExpressionParser.getName(), joinSequence );
+		try {
+			addToCurrentJoin( joinSequence.toJoinFragment( q.getEnabledFilters(), true ).toWhereFragmentString() );
+		}
+		catch ( MappingException me ) {
+			throw new QueryException( me );
+		}
+	}
+
+	private void doToken(String token, QueryTranslatorImpl q) throws QueryException {
+		if ( q.isName( StringHelper.root( token ) ) ) { //path expression
+			doPathExpression( q.unalias( token ), q );
+		}
+		else if ( token.startsWith( ParserHelper.HQL_VARIABLE_PREFIX ) ) { //named query parameter
+			q.addNamedParameter( token.substring( 1 ) );
+			appendToken( q, "?" );
+		}
+		else {
+			Queryable persister = q.getEntityPersisterUsingImports( token );
+			if ( persister != null ) { // the name of a class
+				final String discrim = persister.getDiscriminatorSQLValue();
+				if ( InFragment.NULL.equals(discrim) || InFragment.NOT_NULL.equals(discrim) ) {
+					throw new QueryException( "subclass test not allowed for null or not null discriminator" );
+				}
+				else {
+					appendToken( q, discrim );
+				}
+			}
+			else {
+				Object constant;
+				if (
+						token.indexOf( '.' ) > -1 &&
+						( constant = ReflectHelper.getConstantValue( token ) ) != null
+				) {
+					Type type;
+					try {
+						type = TypeFactory.heuristicType( constant.getClass().getName() );
+					}
+					catch ( MappingException me ) {
+						throw new QueryException( me );
+					}
+					if ( type == null ) throw new QueryException( QueryTranslator.ERROR_CANNOT_DETERMINE_TYPE + token );
+					try {
+						appendToken( q, ( ( LiteralType ) type ).objectToSQLString( constant, q.getFactory().getDialect() ) );
+					}
+					catch ( Exception e ) {
+						throw new QueryException( QueryTranslator.ERROR_CANNOT_FORMAT_LITERAL + token, e );
+					}
+				}
+				else { //anything else
+
+					String negatedToken = negated ? ( String ) NEGATIONS.get( token.toLowerCase() ) : null;
+					if ( negatedToken != null && ( !betweenSpecialCase || !"or".equals( negatedToken ) ) ) {
+						appendToken( q, negatedToken );
+					}
+					else {
+						appendToken( q, token );
+					}
+				}
+			}
+		}
+	}
+
+	private void addToCurrentJoin(String sql) {
+		( ( StringBuffer ) joins.getLast() ).append( sql );
+	}
+
+	private void addToCurrentJoin(PathExpressionParser.CollectionElement ce)
+			throws QueryException {
+		try {
+			addToCurrentJoin( ce.joinSequence.toJoinFragment().toWhereFragmentString() + ce.indexValue.toString() );
+		}
+		catch ( MappingException me ) {
+			throw new QueryException( me );
+		}
+	}
+
+	private void specialCasesBefore(String lcToken) {
+		if ( lcToken.equals( "between" ) || lcToken.equals( "not between" ) ) {
+			betweenSpecialCase = true;
+		}
+	}
+
+	private void specialCasesAfter(String lcToken) {
+		if ( betweenSpecialCase && lcToken.equals( "and" ) ) {
+			betweenSpecialCase = false;
+		}
+	}
+
+	void appendToken(QueryTranslatorImpl q, String token) {
+		if ( expectingIndex > 0 ) {
+			pathExpressionParser.setLastCollectionElementIndexValue( token );
+		}
+		else {
+			q.appendWhereToken( token );
+		}
+	}
+
+	private boolean continuePathExpression(String token, QueryTranslatorImpl q) throws QueryException {
+
+		expectingPathContinuation = false;
+
+		PathExpressionParser.CollectionElement element = pathExpressionParser.lastCollectionElement();
+
+		if ( token.startsWith( "." ) ) { // the path expression continues after a ]
+
+			doPathExpression( getElementName( element, q ) + token, q ); // careful with this!
+
+			addToCurrentJoin( element );
+			return true; //NOTE: EARLY EXIT!
+
+		}
+
+		else { // the path expression ends at the ]
+			if ( element.elementColumns.length != 1 ) {
+				throw new QueryException( "path expression ended in composite collection element" );
+			}
+			appendToken( q, element.elementColumns[0] );
+			addToCurrentJoin( element );
+			return false;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package contains the Hibernate 2.x query parser which 
+	is being end-of-lifed.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/classic/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/hql/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/hql/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines the interface between Hibernate and
+	the HQL query parser implementation (to allow switching
+	between the 2.x and 3.0 HQL parsers).
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/hql/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/AbstractPostInsertGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/AbstractPostInsertGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/AbstractPostInsertGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+//$Id: AbstractPostInsertGenerator.java 9681 2006-03-24 18:10:04Z steve.ebersole at jboss.com $
+package org.hibernate.id;
+
+import java.io.Serializable;
+
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * @author Gavin King
+ */
+public abstract class AbstractPostInsertGenerator implements PostInsertIdentifierGenerator{
+	public Serializable generate(SessionImplementor s, Object obj) {
+		return IdentifierGeneratorFactory.POST_INSERT_INDICATOR;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/id/AbstractPostInsertGenerator.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/AbstractUUIDGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/AbstractUUIDGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/AbstractUUIDGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,77 @@
+//$Id: AbstractUUIDGenerator.java 5002 2004-12-19 16:25:07Z oneovthafew $
+package org.hibernate.id;
+
+import java.net.InetAddress;
+import org.hibernate.util.BytesHelper;
+
+/**
+ * The base class for identifier generators that use a UUID algorithm. This
+ * class implements the algorithm, subclasses define the identifier
+ * format.
+ *
+ * @see UUIDHexGenerator
+ * @author Gavin King
+ */
+
+public abstract class AbstractUUIDGenerator implements IdentifierGenerator {
+
+	private static final int IP;
+	static {
+		int ipadd;
+		try {
+			ipadd = BytesHelper.toInt( InetAddress.getLocalHost().getAddress() );
+		}
+		catch (Exception e) {
+			ipadd = 0;
+		}
+		IP = ipadd;
+	}
+	private static short counter = (short) 0;
+	private static final int JVM = (int) ( System.currentTimeMillis() >>> 8 );
+
+	public AbstractUUIDGenerator() {
+	}
+
+	/**
+	 * Unique across JVMs on this machine (unless they load this class
+	 * in the same quater second - very unlikely)
+	 */
+	protected int getJVM() {
+		return JVM;
+	}
+
+	/**
+	 * Unique in a millisecond for this JVM instance (unless there
+	 * are > Short.MAX_VALUE instances created in a millisecond)
+	 */
+	protected short getCount() {
+		synchronized(AbstractUUIDGenerator.class) {
+			if (counter<0) counter=0;
+			return counter++;
+		}
+	}
+
+	/**
+	 * Unique in a local network
+	 */
+	protected int getIP() {
+		return IP;
+	}
+
+	/**
+	 * Unique down to millisecond
+	 */
+	protected short getHiTime() {
+		return (short) ( System.currentTimeMillis() >>> 32 );
+	}
+	protected int getLoTime() {
+		return (int) System.currentTimeMillis();
+	}
+
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/Assigned.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/Assigned.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/Assigned.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+//$Id: Assigned.java 6914 2005-05-26 03:58:24Z oneovthafew $
+package org.hibernate.id;
+
+import java.io.Serializable;
+import java.util.Properties;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * <b>assigned</b><br>
+ * <br>
+ * An <tt>IdentifierGenerator</tt> that returns the current identifier assigned
+ * to an instance.
+ *
+ * @author Gavin King
+ */
+
+public class Assigned implements IdentifierGenerator, Configurable {
+	
+	private String entityName;
+
+	public Serializable generate(SessionImplementor session, Object obj) throws HibernateException {
+		
+		final Serializable id = session.getEntityPersister( entityName, obj ) 
+				//TODO: cache the persister, this shows up in yourkit
+				.getIdentifier( obj, session.getEntityMode() );
+		
+		if (id==null) {
+			throw new IdentifierGenerationException(
+				"ids for this class must be manually assigned before calling save(): " + 
+				entityName
+			);
+		}
+		
+		return id;
+	}
+
+	public void configure(Type type, Properties params, Dialect d)
+	throws MappingException {
+		entityName = params.getProperty(ENTITY_NAME);
+		if (entityName==null) {
+			throw new MappingException("no entity name");
+		}
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/Configurable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/Configurable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/Configurable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+//$Id: Configurable.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.id;
+
+import java.util.Properties;
+
+import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.type.Type;
+
+/**
+ * An <tt>IdentifierGenerator</tt> that supports "configuration".
+ *
+ * @see IdentifierGenerator
+ * @author Gavin King
+ */
+public interface Configurable {
+
+	/**
+	 * Configure this instance, given the value of parameters
+	 * specified by the user as <tt>&lt;param&gt;</tt> elements.
+	 * This method is called just once, following instantiation.
+	 *
+	 * @param params param values, keyed by parameter name
+	 */
+	public void configure(Type type, Properties params, Dialect d) throws MappingException;
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/ForeignGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/ForeignGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/ForeignGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,87 @@
+package org.hibernate.id;
+
+import java.io.Serializable;
+import java.util.Properties;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.Session;
+import org.hibernate.TransientObjectException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.ForeignKeys;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+
+/**
+ * <b>foreign</b><br>
+ * <br>
+ * An <tt>Identifier</tt> generator that uses the value of the id property of an
+ * associated object<br>
+ * <br>
+ * One mapping parameter is required: property.
+ *
+ * @author Gavin King
+ */
+public class ForeignGenerator implements IdentifierGenerator, Configurable {
+
+	private String propertyName;
+	private String entityName;
+
+	/**
+	 * @see org.hibernate.id.IdentifierGenerator#generate(org.hibernate.engine.SessionImplementor, java.lang.Object)
+	 */
+	public Serializable generate(SessionImplementor sessionImplementor, Object object)
+	throws HibernateException {
+		
+		Session session = (Session) sessionImplementor;
+
+		Object associatedObject = sessionImplementor.getFactory()
+		        .getClassMetadata( entityName )
+		        .getPropertyValue( object, propertyName, session.getEntityMode() );
+		
+		if ( associatedObject == null ) {
+			throw new IdentifierGenerationException(
+					"attempted to assign id from null one-to-one property: " + 
+					propertyName
+				);
+		}
+		
+		EntityType type = (EntityType) sessionImplementor.getFactory()
+        	.getClassMetadata( entityName )
+        	.getPropertyType( propertyName );
+
+		Serializable id;
+		try {
+			id = ForeignKeys.getEntityIdentifierIfNotUnsaved(
+					type.getAssociatedEntityName(), 
+					associatedObject, 
+					sessionImplementor
+				); 
+		}
+		catch (TransientObjectException toe) {
+			id = session.save( type.getAssociatedEntityName(), associatedObject );
+		}
+
+		if ( session.contains(object) ) {
+			//abort the save (the object is already saved by a circular cascade)
+			return IdentifierGeneratorFactory.SHORT_CIRCUIT_INDICATOR;
+			//throw new IdentifierGenerationException("save associated object first, or disable cascade for inverse association");
+		}
+		return id;
+	}
+
+	/**
+	 * @see org.hibernate.id.Configurable#configure(org.hibernate.type.Type, java.util.Properties, org.hibernate.dialect.Dialect)
+	 */
+	public void configure(Type type, Properties params, Dialect d)
+		throws MappingException {
+
+		propertyName = params.getProperty("property");
+		entityName = params.getProperty(ENTITY_NAME);
+		if (propertyName==null) throw new MappingException(
+			"param named \"property\" is required for foreign id generation strategy"
+		);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/GUIDGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/GUIDGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/GUIDGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+//$Id: GUIDGenerator.java 7265 2005-06-22 04:19:34Z oneovthafew $
+package org.hibernate.id;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.exception.JDBCExceptionHelper;
+
+/**
+ * Generates <tt>string</tt> values using the SQL Server NEWID() function.
+ *
+ * @author Joseph Fifield
+ */
+public class GUIDGenerator implements IdentifierGenerator {
+
+	private static final Log log = LogFactory.getLog(GUIDGenerator.class);
+
+	public Serializable generate(SessionImplementor session, Object obj) 
+	throws HibernateException {
+		
+		final String sql = session.getFactory().getDialect().getSelectGUIDString();
+		try {
+			PreparedStatement st = session.getBatcher().prepareSelectStatement(sql);
+			try {
+				ResultSet rs = st.executeQuery();
+				final String result;
+				try {
+					rs.next();
+					result = rs.getString(1);
+				}
+				finally {
+					rs.close();
+				}
+				log.debug("GUID identifier generated: " + result);
+				return result;
+			}
+			finally {
+				session.getBatcher().closeStatement(st);
+			}
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					session.getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not retrieve GUID",
+					sql
+				);
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentifierGenerationException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentifierGenerationException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentifierGenerationException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+//$Id: IdentifierGenerationException.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.id;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Thrown by <tt>IdentifierGenerator</tt> implementation class when
+ * ID generation fails.
+ *
+ * @see IdentifierGenerator
+ * @author Gavin King
+ */
+
+public class IdentifierGenerationException extends HibernateException {
+
+	public IdentifierGenerationException(String msg) {
+		super(msg);
+	}
+
+	public IdentifierGenerationException(String msg, Throwable t) {
+		super(msg, t);
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentifierGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentifierGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentifierGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: IdentifierGenerator.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.id;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+
+import java.io.Serializable;
+
+/**
+ * The general contract between a class that generates unique
+ * identifiers and the <tt>Session</tt>. It is not intended that
+ * this interface ever be exposed to the application. It <b>is</b>
+ * intended that users implement this interface to provide
+ * custom identifier generation strategies.<br>
+ * <br>
+ * Implementors should provide a public default constructor.<br>
+ * <br>
+ * Implementations that accept configuration parameters should
+ * also implement <tt>Configurable</tt>.
+ * <br>
+ * Implementors <em>must</em> be threadsafe
+ *
+ * @author Gavin King
+ * @see PersistentIdentifierGenerator
+ * @see Configurable
+ */
+public interface IdentifierGenerator {
+
+    /**
+     * The configuration parameter holding the entity name
+     */
+    public static final String ENTITY_NAME = "entity_name";
+    
+	/**
+	 * Generate a new identifier.
+	 * @param session
+	 * @param object the entity or toplevel collection for which the id is being generated
+	 *
+	 * @return a new identifier
+	 * @throws HibernateException
+	 */
+	public Serializable generate(SessionImplementor session, Object object) 
+	throws HibernateException;
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentifierGeneratorFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentifierGeneratorFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentifierGeneratorFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,131 @@
+//$Id: IdentifierGeneratorFactory.java 9686 2006-03-27 16:47:06Z steve.ebersole at jboss.com $
+package org.hibernate.id;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.type.Type;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * Factory and helper methods for <tt>IdentifierGenerator</tt> framework.
+ *
+ * @author Gavin King
+ */
+public final class IdentifierGeneratorFactory {
+	
+	private static final Log log = LogFactory.getLog(IdentifierGeneratorFactory.class);
+
+	/**
+	 * Get the generated identifier when using identity columns
+	 */
+	public static Serializable getGeneratedIdentity(ResultSet rs, Type type)
+	throws SQLException, HibernateException, IdentifierGenerationException {
+		if ( !rs.next() ) {
+			throw new HibernateException( "The database returned no natively generated identity value" );
+		}
+		final Serializable id = IdentifierGeneratorFactory.get( rs, type );
+
+		if ( log.isDebugEnabled() ) log.debug( "Natively generated identity: " + id );
+		return id;
+	}
+
+	// unhappy about this being public ... is there a better way?
+	public static Serializable get(ResultSet rs, Type type) 
+	throws SQLException, IdentifierGenerationException {
+	
+		Class clazz = type.getReturnedClass();
+		if ( clazz==Long.class ) {
+			return new Long( rs.getLong(1) );
+		}
+		else if ( clazz==Integer.class ) {
+			return new Integer( rs.getInt(1) );
+		}
+		else if ( clazz==Short.class ) {
+			return new Short( rs.getShort(1) );
+		}
+		else if ( clazz==String.class ) {
+			return rs.getString(1);
+		}
+		else {
+			throw new IdentifierGenerationException("this id generator generates long, integer, short or string");
+		}
+		
+	}
+
+	private static final HashMap GENERATORS = new HashMap();
+
+	public static final Serializable SHORT_CIRCUIT_INDICATOR = new Serializable() { 
+		public String toString() { return "SHORT_CIRCUIT_INDICATOR"; } 
+	};
+	
+	public static final Serializable POST_INSERT_INDICATOR = new Serializable() { 
+		public String toString() { return "POST_INSERT_INDICATOR"; } 
+	};
+
+	static {
+		GENERATORS.put("uuid", UUIDHexGenerator.class);
+		GENERATORS.put("hilo", TableHiLoGenerator.class);
+		GENERATORS.put("assigned", Assigned.class);
+		GENERATORS.put("identity", IdentityGenerator.class);
+		GENERATORS.put("select", SelectGenerator.class);
+		GENERATORS.put("sequence", SequenceGenerator.class);
+		GENERATORS.put("seqhilo", SequenceHiLoGenerator.class);
+		GENERATORS.put("increment", IncrementGenerator.class);
+		GENERATORS.put("foreign", ForeignGenerator.class);
+		GENERATORS.put("guid", GUIDGenerator.class);
+		GENERATORS.put("uuid.hex", UUIDHexGenerator.class); //uuid.hex is deprecated
+		GENERATORS.put("sequence-identity", SequenceIdentityGenerator.class);
+	}
+
+	public static IdentifierGenerator create(String strategy, Type type, Properties params, Dialect dialect) 
+	throws MappingException {
+		try {
+			Class clazz = getIdentifierGeneratorClass( strategy, dialect );
+			IdentifierGenerator idgen = (IdentifierGenerator) clazz.newInstance();
+			if (idgen instanceof Configurable) ( (Configurable) idgen).configure(type, params, dialect);
+			return idgen;
+		}
+		catch (Exception e) {
+			throw new MappingException("could not instantiate id generator", e);
+		}
+	}
+
+	public static Class getIdentifierGeneratorClass(String strategy, Dialect dialect) {
+		Class clazz = (Class) GENERATORS.get(strategy);
+		if ( "native".equals(strategy) ) clazz = dialect.getNativeIdentifierGeneratorClass();
+		try {
+			if (clazz==null) clazz = ReflectHelper.classForName(strategy);
+		}
+		catch (ClassNotFoundException e) {
+			throw new MappingException("could not interpret id generator strategy: " + strategy);
+		}
+		return clazz;
+	}
+
+	public static Number createNumber(long value, Class clazz) throws IdentifierGenerationException {
+		if ( clazz==Long.class ) {
+			return new Long(value);
+		}
+		else if ( clazz==Integer.class ) {
+			return new Integer( (int) value );
+		}
+		else if ( clazz==Short.class ) {
+			return new Short( (short) value );
+		}
+		else {
+			throw new IdentifierGenerationException("this id generator generates long, integer, short");
+		}
+	}
+
+	private IdentifierGeneratorFactory() {} //cannot be instantiated
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentityGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentityGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/IdentityGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,161 @@
+//$Id: IdentityGenerator.java 9681 2006-03-24 18:10:04Z steve.ebersole at jboss.com $
+package org.hibernate.id;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
+import org.hibernate.id.insert.IdentifierGeneratingInsert;
+import org.hibernate.id.insert.AbstractSelectingDelegate;
+import org.hibernate.id.insert.AbstractReturningDelegate;
+import org.hibernate.id.insert.InsertSelectIdentityInsert;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.HibernateException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.util.GetGeneratedKeysHelper;
+
+
+/**
+ * A generator for use with ANSI-SQL IDENTITY columns used as the primary key.
+ * The IdentityGenerator for autoincrement/identity key generation.
+ * <br><br>
+ * Indicates to the <tt>Session</tt> that identity (ie. identity/autoincrement
+ * column) key generation should be used.
+ *
+ * @author Christoph Sturm
+ */
+public class IdentityGenerator extends AbstractPostInsertGenerator {
+
+	public InsertGeneratedIdentifierDelegate getInsertGeneratedIdentifierDelegate(
+			PostInsertIdentityPersister persister,
+	        Dialect dialect,
+	        boolean isGetGeneratedKeysEnabled) throws HibernateException {
+		if ( isGetGeneratedKeysEnabled ) {
+			return new GetGeneratedKeysDelegate( persister, dialect );
+		}
+		else if ( dialect.supportsInsertSelectIdentity() ) {
+			return new InsertSelectDelegate( persister, dialect );
+		}
+		else {
+			return new BasicDelegate( persister, dialect );
+		}
+	}
+
+	/**
+	 * Delegate for dealing with IDENTITY columns using JDBC3 getGeneratedKeys
+	 */
+	public static class GetGeneratedKeysDelegate
+			extends AbstractReturningDelegate
+			implements InsertGeneratedIdentifierDelegate {
+		private final PostInsertIdentityPersister persister;
+		private final Dialect dialect;
+
+		public GetGeneratedKeysDelegate(PostInsertIdentityPersister persister, Dialect dialect) {
+			super( persister );
+			this.persister = persister;
+			this.dialect = dialect;
+		}
+
+		public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() {
+			IdentifierGeneratingInsert insert = new IdentifierGeneratingInsert( dialect );
+			insert.addIdentityColumn( persister.getRootTableKeyColumnNames()[0] );
+			return insert;
+		}
+
+		protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
+			return session.getBatcher().prepareStatement( insertSQL, true );
+		}
+
+		public Serializable executeAndExtract(PreparedStatement insert) throws SQLException {
+			insert.executeUpdate();
+			return IdentifierGeneratorFactory.getGeneratedIdentity(
+					GetGeneratedKeysHelper.getGeneratedKey( insert ),
+			        persister.getIdentifierType()
+			);
+		}
+	}
+
+	/**
+	 * Delegate for dealing with IDENTITY columns where the dialect supports returning
+	 * the generated IDENTITY value directly from the insert statement.
+	 */
+	public static class InsertSelectDelegate
+			extends AbstractReturningDelegate
+			implements InsertGeneratedIdentifierDelegate {
+		private final PostInsertIdentityPersister persister;
+		private final Dialect dialect;
+
+		public InsertSelectDelegate(PostInsertIdentityPersister persister, Dialect dialect) {
+			super( persister );
+			this.persister = persister;
+			this.dialect = dialect;
+		}
+
+		public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() {
+			InsertSelectIdentityInsert insert = new InsertSelectIdentityInsert( dialect );
+			insert.addIdentityColumn( persister.getRootTableKeyColumnNames()[0] );
+			return insert;
+		}
+
+		protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
+			return session.getBatcher().prepareStatement( insertSQL, false );
+		}
+
+		public Serializable executeAndExtract(PreparedStatement insert) throws SQLException {
+			if ( !insert.execute() ) {
+				while ( !insert.getMoreResults() && insert.getUpdateCount() != -1 ) {
+					// do nothing until we hit the rsult set containing the generated id
+				}
+			}
+			ResultSet rs = insert.getResultSet();
+			try {
+				return IdentifierGeneratorFactory.getGeneratedIdentity( rs, persister.getIdentifierType() );
+			}
+			finally {
+				rs.close();
+			}
+		}
+
+		public Serializable determineGeneratedIdentifier(SessionImplementor session, Object entity) {
+			throw new AssertionFailure( "insert statement returns generated value" );
+		}
+	}
+
+	/**
+	 * Delegate for dealing with IDENTITY columns where the dialect requires an
+	 * additional command execution to retrieve the generated IDENTITY value
+	 */
+	public static class BasicDelegate
+			extends AbstractSelectingDelegate
+			implements InsertGeneratedIdentifierDelegate {
+		private final PostInsertIdentityPersister persister;
+		private final Dialect dialect;
+
+		public BasicDelegate(PostInsertIdentityPersister persister, Dialect dialect) {
+			super( persister );
+			this.persister = persister;
+			this.dialect = dialect;
+		}
+
+		public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() {
+			IdentifierGeneratingInsert insert = new IdentifierGeneratingInsert( dialect );
+			insert.addIdentityColumn( persister.getRootTableKeyColumnNames()[0] );
+			return insert;
+		}
+
+		protected String getSelectSQL() {
+			return persister.getIdentitySelectString();
+		}
+
+		protected Serializable getResult(
+				SessionImplementor session,
+		        ResultSet rs,
+		        Object object) throws SQLException {
+			return IdentifierGeneratorFactory.getGeneratedIdentity( rs, persister.getIdentifierType() );
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/IncrementGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/IncrementGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/IncrementGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,116 @@
+package org.hibernate.id;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.mapping.Table;
+import org.hibernate.type.Type;
+import org.hibernate.util.StringHelper;
+
+/**
+ * <b>increment</b><br>
+ * <br>
+ * An <tt>IdentifierGenerator</tt> that returns a <tt>long</tt>, constructed by
+ * counting from the maximum primary key value at startup. Not safe for use in a
+ * cluster!<br>
+ * <br>
+ * Mapping parameters supported, but not usually needed: tables, column.
+ * (The tables parameter specified a comma-separated list of table names.)
+ *
+ * @author Gavin King
+ */
+public class IncrementGenerator implements IdentifierGenerator, Configurable {
+
+	private static final Log log = LogFactory.getLog(IncrementGenerator.class);
+
+	private long next;
+	private String sql;
+	private Class returnClass;
+
+	public synchronized Serializable generate(SessionImplementor session, Object object) 
+	throws HibernateException {
+
+		if (sql!=null) {
+			getNext( session );
+		}
+		return IdentifierGeneratorFactory.createNumber(next++, returnClass);
+	}
+
+	public void configure(Type type, Properties params, Dialect dialect)
+	throws MappingException {
+
+		String tableList = params.getProperty("tables");
+		if (tableList==null) tableList = params.getProperty(PersistentIdentifierGenerator.TABLES);
+		String[] tables = StringHelper.split(", ", tableList);
+		String column = params.getProperty("column");
+		if (column==null) column = params.getProperty(PersistentIdentifierGenerator.PK);
+		String schema = params.getProperty(PersistentIdentifierGenerator.SCHEMA);
+		String catalog = params.getProperty(PersistentIdentifierGenerator.CATALOG);
+		returnClass = type.getReturnedClass();
+		
+
+		StringBuffer buf = new StringBuffer();
+		for ( int i=0; i<tables.length; i++ ) {
+			if (tables.length>1) {
+				buf.append("select ").append(column).append(" from ");
+			}
+			buf.append( Table.qualify( catalog, schema, tables[i] ) );
+			if ( i<tables.length-1) buf.append(" union ");
+		}
+		if (tables.length>1) {
+			buf.insert(0, "( ").append(" ) ids_");
+			column = "ids_." + column;
+		}
+		
+		sql = "select max(" + column + ") from " + buf.toString();
+	}
+
+	private void getNext( SessionImplementor session ) {
+
+		log.debug("fetching initial value: " + sql);
+		
+		try {
+			PreparedStatement st = session.getBatcher().prepareSelectStatement(sql);
+			try {
+				ResultSet rs = st.executeQuery();
+				try {
+					if ( rs.next() ) {
+						next = rs.getLong(1) + 1;
+						if ( rs.wasNull() ) next = 1;
+					}
+					else {
+						next = 1;
+					}
+					sql=null;
+					log.debug("first free id: " + next);
+				}
+				finally {
+					rs.close();
+				}
+			}
+			finally {
+				session.getBatcher().closeStatement(st);
+			}
+			
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					session.getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not fetch initial value for increment generator",
+					sql
+				);
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,241 @@
+//$Id: MultipleHiLoPerTableGenerator.java 11320 2007-03-20 11:50:53Z steve.ebersole at jboss.com $
+package org.hibernate.id;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.TransactionHelper;
+import org.hibernate.mapping.Table;
+import org.hibernate.type.Type;
+import org.hibernate.util.PropertiesHelper;
+
+/**
+ *
+ * A hilo <tt>IdentifierGenerator</tt> that returns a <tt>Long</tt>, constructed using
+ * a hi/lo algorithm. The hi value MUST be fetched in a seperate transaction
+ * to the <tt>Session</tt> transaction so the generator must be able to obtain
+ * a new connection and commit it. Hence this implementation may not
+ * be used  when the user is supplying connections. In this
+ * case a <tt>SequenceHiLoGenerator</tt> would be a better choice (where
+ * supported).<br>
+ * <br>
+ *
+ * A hilo <tt>IdentifierGenerator</tt> that uses a database
+ * table to store the last generated values. A table can contains
+ * several hi values. They are distinct from each other through a key
+ * <p/>
+ * <p>This implementation is not compliant with a user connection</p>
+ * <p/>
+ * 
+ * <p>Allowed parameters (all of them are optional):</p>
+ * <ul>
+ * <li>table: table name (default <tt>hibernate_sequences</tt>)</li>
+ * <li>primary_key_column: key column name (default <tt>sequence_name</tt>)</li>
+ * <li>value_column: hi value column name(default <tt>sequence_next_hi_value</tt>)</li>
+ * <li>primary_key_value: key value for the current entity (default to the entity's primary table name)</li>
+ * <li>primary_key_length: length of the key column in DB represented as a varchar (default to 255)</li>
+ * <li>max_lo: max low value before increasing hi (default to Short.MAX_VALUE)</li>
+ * </ul>
+ *
+ * @author Emmanuel Bernard
+ * @author <a href="mailto:kr at hbt.de">Klaus Richarz</a>.
+ */
+public class MultipleHiLoPerTableGenerator 
+	extends TransactionHelper
+	implements PersistentIdentifierGenerator, Configurable {
+	
+	private static final Log log = LogFactory.getLog(MultipleHiLoPerTableGenerator.class);
+	
+	public static final String ID_TABLE = "table";
+	public static final String PK_COLUMN_NAME = "primary_key_column";
+	public static final String PK_VALUE_NAME = "primary_key_value";
+	public static final String VALUE_COLUMN_NAME = "value_column";
+	public static final String PK_LENGTH_NAME = "primary_key_length";
+
+	private static final int DEFAULT_PK_LENGTH = 255;
+	public static final String DEFAULT_TABLE = "hibernate_sequences";
+	private static final String DEFAULT_PK_COLUMN = "sequence_name";
+	private static final String DEFAULT_VALUE_COLUMN = "sequence_next_hi_value";
+	
+	private String tableName;
+	private String pkColumnName;
+	private String valueColumnName;
+	private String query;
+	private String insert;
+	private String update;
+
+	//hilo params
+	public static final String MAX_LO = "max_lo";
+
+	private long hi;
+	private int lo;
+	private int maxLo;
+	private Class returnClass;
+	private int keySize;
+
+
+	public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
+		return new String[] {
+			new StringBuffer( dialect.getCreateTableString() )
+					.append( ' ' )
+					.append( tableName )
+					.append( " ( " )
+					.append( pkColumnName )
+					.append( ' ' )
+					.append( dialect.getTypeName( Types.VARCHAR, keySize, 0, 0 ) )
+					.append( ",  " )
+					.append( valueColumnName )
+					.append( ' ' )
+					.append( dialect.getTypeName( Types.INTEGER ) )
+					.append( " ) " )
+					.toString()
+		};
+	}
+
+	public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
+		StringBuffer sqlDropString = new StringBuffer( "drop table " );
+		if ( dialect.supportsIfExistsBeforeTableName() ) {
+			sqlDropString.append( "if exists " );
+		}
+		sqlDropString.append( tableName ).append( dialect.getCascadeConstraintsString() );
+		if ( dialect.supportsIfExistsAfterTableName() ) {
+			sqlDropString.append( " if exists" );
+		}
+		return new String[] { sqlDropString.toString() };
+	}
+
+	public Object generatorKey() {
+		return tableName;
+	}
+
+	public Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException {
+		int result;
+		int rows;
+		do {
+			// The loop ensures atomicity of the
+			// select + update even for no transaction
+			// or read committed isolation level
+
+			//sql = query;
+			SQL.debug(query);
+			PreparedStatement qps = conn.prepareStatement(query);
+			PreparedStatement ips = null;
+			try {
+				//qps.setString(1, key);
+				ResultSet rs = qps.executeQuery();
+				boolean isInitialized = rs.next();
+				if ( !isInitialized ) {
+					result = 0;
+					ips = conn.prepareStatement(insert);
+					//ips.setString(1, key);
+					ips.setInt(1, result);
+					ips.execute();
+				}
+				else {
+					result = rs.getInt(1);
+				}
+				rs.close();
+			}
+			catch (SQLException sqle) {
+				log.error("could not read or init a hi value", sqle);
+				throw sqle;
+			}
+			finally {
+				if (ips != null) {
+					ips.close();
+				}
+				qps.close();
+			}
+
+			//sql = update;
+			PreparedStatement ups = conn.prepareStatement(update);
+			try {
+				ups.setInt( 1, result + 1 );
+				ups.setInt( 2, result );
+				//ups.setString( 3, key );
+				rows = ups.executeUpdate();
+			}
+			catch (SQLException sqle) {
+				log.error("could not update hi value in: " + tableName, sqle);
+				throw sqle;
+			}
+			finally {
+				ups.close();
+			}
+		}
+		while (rows==0);
+		return new Integer(result);
+	}
+
+	public synchronized Serializable generate(SessionImplementor session, Object obj)
+		throws HibernateException {
+		if (maxLo < 1) {
+			//keep the behavior consistent even for boundary usages
+			int val = ( (Integer) doWorkInNewTransaction(session) ).intValue();
+			if (val == 0) val = ( (Integer) doWorkInNewTransaction(session) ).intValue();
+			return IdentifierGeneratorFactory.createNumber( val, returnClass );
+		}
+		if (lo>maxLo) {
+			int hival = ( (Integer) doWorkInNewTransaction(session) ).intValue();
+			lo = (hival == 0) ? 1 : 0;
+			hi = hival * (maxLo+1);
+			log.debug("new hi value: " + hival);
+		}
+		return IdentifierGeneratorFactory.createNumber( hi + lo++, returnClass );
+	}
+
+	public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
+		tableName = PropertiesHelper.getString(ID_TABLE, params, DEFAULT_TABLE);
+		pkColumnName = PropertiesHelper.getString(PK_COLUMN_NAME, params, DEFAULT_PK_COLUMN);
+		valueColumnName = PropertiesHelper.getString(VALUE_COLUMN_NAME, params, DEFAULT_VALUE_COLUMN);
+		String schemaName = params.getProperty(SCHEMA);
+		String catalogName = params.getProperty(CATALOG);
+		keySize = PropertiesHelper.getInt(PK_LENGTH_NAME, params, DEFAULT_PK_LENGTH);
+		String keyValue = PropertiesHelper.getString(PK_VALUE_NAME, params, params.getProperty(TABLE) );
+
+		if ( tableName.indexOf( '.' )<0 ) {
+			tableName = Table.qualify( catalogName, schemaName, tableName );
+		}
+
+		query = "select " +
+			valueColumnName +
+			" from " +
+			dialect.appendLockHint(LockMode.UPGRADE, tableName) +
+			" where " + pkColumnName + " = '" + keyValue + "'" +
+			dialect.getForUpdateString();
+
+		update = "update " +
+			tableName +
+			" set " +
+			valueColumnName +
+			" = ? where " +
+			valueColumnName +
+			" = ? and " +
+			pkColumnName +
+			" = '" + 
+			keyValue 
+			+ "'";
+		
+		insert = "insert into " + tableName +
+			"(" + pkColumnName + ", " +	valueColumnName + ") " +
+			"values('"+ keyValue +"', ?)";
+
+
+		//hilo config
+		maxLo = PropertiesHelper.getInt(MAX_LO, params, Short.MAX_VALUE);
+		lo = maxLo + 1; // so we "clock over" on the first invocation
+		returnClass = type.getReturnedClass();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,80 @@
+//$Id: PersistentIdentifierGenerator.java 6514 2005-04-26 06:37:54Z oneovthafew $
+package org.hibernate.id;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * An <tt>IdentifierGenerator</tt> that requires creation of database objects.
+ * <br><br>
+ * All <tt>PersistentIdentifierGenerator</tt>s that also implement
+ * <tt>Configurable</tt> have access to a special mapping parameter: schema
+ *
+ * @see IdentifierGenerator
+ * @see Configurable
+ * @author Gavin King
+ */
+public interface PersistentIdentifierGenerator extends IdentifierGenerator {
+
+	/**
+	 * The configuration parameter holding the schema name
+	 */
+	public static final String SCHEMA = "schema";
+
+	/**
+	 * The configuration parameter holding the table name for the
+	 * generated id
+	 */
+	public static final String TABLE = "target_table";
+
+	/**
+	 * The configuration parameter holding the table names for all
+	 * tables for which the id must be unique
+	 */
+	public static final String TABLES = "identity_tables";
+
+	/**
+	 * The configuration parameter holding the primary key column
+	 * name of the generated id
+	 */
+	public static final String PK = "target_column";
+
+    /**
+     * The configuration parameter holding the catalog name
+     */
+    public static final String CATALOG = "catalog";
+    
+	/**
+	 * The SQL required to create the underlying database objects.
+	 * @param dialect
+	 * @return String[]
+	 * @throws HibernateException
+	 */
+	public String[] sqlCreateStrings(Dialect dialect) throws HibernateException;
+
+	/**
+	 * The SQL required to remove the underlying database objects.
+	 * @param dialect
+	 * @return String
+	 * @throws HibernateException
+	 */
+	public String[] sqlDropStrings(Dialect dialect) throws HibernateException;
+
+	/**
+	 * Return a key unique to the underlying database objects. Prevents us from
+	 * trying to create/remove them multiple times.
+	 * @return Object an identifying key for this generator
+	 */
+	public Object generatorKey();
+	
+	static final Log SQL = LogFactory.getLog("org.hibernate.SQL");
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/PostInsertIdentifierGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/PostInsertIdentifierGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/PostInsertIdentifierGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+//$Id: PostInsertIdentifierGenerator.java 9681 2006-03-24 18:10:04Z steve.ebersole at jboss.com $
+package org.hibernate.id;
+
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
+
+/**
+ * @author Gavin King
+ */
+public interface PostInsertIdentifierGenerator extends IdentifierGenerator {
+	public InsertGeneratedIdentifierDelegate getInsertGeneratedIdentifierDelegate(
+			PostInsertIdentityPersister persister,
+	        Dialect dialect,
+	        boolean isGetGeneratedKeysEnabled) throws HibernateException;
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/id/PostInsertIdentifierGenerator.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/PostInsertIdentityPersister.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/PostInsertIdentityPersister.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/PostInsertIdentityPersister.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: PostInsertIdentityPersister.java 9681 2006-03-24 18:10:04Z steve.ebersole at jboss.com $
+package org.hibernate.id;
+
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * A persister that may have an identity assigned by execution of 
+ * a SQL <tt>INSERT</tt>.
+ *
+ * @author Gavin King
+ */
+public interface PostInsertIdentityPersister extends EntityPersister {
+	/**
+	 * Get a SQL select string that performs a select based on a unique
+	 * key determined by the given property name).
+	 *
+	 * @param propertyName The name of the property which maps to the
+	 * column(s) to use in the select statement restriction.
+	 * @return The SQL select string
+	 */
+	public String getSelectByUniqueKeyString(String propertyName);
+
+	/**
+	 * Get the database-specific SQL command to retrieve the last
+	 * generated IDENTITY value.
+	 *
+	 * @return The SQL command string
+	 */
+	public String getIdentitySelectString();
+
+	/**
+	 * The names of the primary key columns in the root table.
+	 *
+	 * @return The primary key column names.
+	 */
+	public String[] getRootTableKeyColumnNames();
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/id/PostInsertIdentityPersister.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/SelectGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/SelectGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/SelectGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,138 @@
+//$Id: SelectGenerator.java 11060 2007-01-19 12:51:31Z steve.ebersole at jboss.com $
+package org.hibernate.id;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import org.hibernate.MappingException;
+import org.hibernate.HibernateException;
+import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
+import org.hibernate.id.insert.IdentifierGeneratingInsert;
+import org.hibernate.id.insert.AbstractSelectingDelegate;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.ValueInclusion;
+import org.hibernate.type.Type;
+
+/**
+ * A generator that selects the just inserted row to determine the identifier
+ * value assigned by the database. The correct row is located using a unique
+ * key.
+ * <p/>
+ * One mapping parameter is required: key (unless a natural-id is defined in the mapping).
+ *
+ * @author Gavin King
+ */
+public class SelectGenerator extends AbstractPostInsertGenerator implements Configurable {
+	
+	private String uniqueKeyPropertyName;
+
+	public void configure(Type type, Properties params, Dialect d) throws MappingException {
+		uniqueKeyPropertyName = params.getProperty( "key" );
+	}
+
+	public InsertGeneratedIdentifierDelegate getInsertGeneratedIdentifierDelegate(
+			PostInsertIdentityPersister persister,
+	        Dialect dialect,
+	        boolean isGetGeneratedKeysEnabled) throws HibernateException {
+		return new SelectGeneratorDelegate( persister, dialect, uniqueKeyPropertyName );
+	}
+
+	private static String determineNameOfPropertyToUse(PostInsertIdentityPersister persister, String supplied) {
+		if ( supplied != null ) {
+			return supplied;
+		}
+		int[] naturalIdPropertyIndices = persister.getNaturalIdentifierProperties();
+		if ( naturalIdPropertyIndices == null ){
+			throw new IdentifierGenerationException(
+					"no natural-id property defined; need to specify [key] in " +
+					"generator parameters"
+			);
+		}
+		if ( naturalIdPropertyIndices.length > 1 ) {
+			throw new IdentifierGenerationException(
+					"select generator does not currently support composite " +
+					"natural-id properties; need to specify [key] in generator parameters"
+			);
+		}
+		ValueInclusion inclusion = persister.getPropertyInsertGenerationInclusions() [ naturalIdPropertyIndices[0] ];
+		if ( inclusion != ValueInclusion.NONE ) {
+			throw new IdentifierGenerationException(
+					"natural-id also defined as insert-generated; need to specify [key] " +
+					"in generator parameters"
+			);
+		}
+		return persister.getPropertyNames() [ naturalIdPropertyIndices[0] ];
+	}
+
+
+	/**
+	 * The delegate for the select generation strategy.
+	 */
+	public static class SelectGeneratorDelegate
+			extends AbstractSelectingDelegate
+			implements InsertGeneratedIdentifierDelegate {
+		private final PostInsertIdentityPersister persister;
+		private final Dialect dialect;
+
+		private final String uniqueKeyPropertyName;
+		private final Type uniqueKeyType;
+		private final Type idType;
+
+		private final String idSelectString;
+
+		private SelectGeneratorDelegate(
+				PostInsertIdentityPersister persister,
+		        Dialect dialect,
+		        String suppliedUniqueKeyPropertyName) {
+			super( persister );
+			this.persister = persister;
+			this.dialect = dialect;
+			this.uniqueKeyPropertyName = determineNameOfPropertyToUse( persister, suppliedUniqueKeyPropertyName );
+
+			idSelectString = persister.getSelectByUniqueKeyString( uniqueKeyPropertyName );
+			uniqueKeyType = persister.getPropertyType( uniqueKeyPropertyName );
+			idType = persister.getIdentifierType();
+		}
+
+		public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() {
+			return new IdentifierGeneratingInsert( dialect );
+		}
+
+
+		// AbstractSelectingDelegate impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+		protected String getSelectSQL() {
+			return idSelectString;
+		}
+
+		protected void bindParameters(
+				SessionImplementor session,
+		        PreparedStatement ps,
+		        Object entity) throws SQLException {
+			Object uniqueKeyValue = persister.getPropertyValue( entity, uniqueKeyPropertyName, session.getEntityMode() );
+			uniqueKeyType.nullSafeSet( ps, uniqueKeyValue, 1, session );
+		}
+
+		protected Serializable getResult(
+				SessionImplementor session,
+		        ResultSet rs,
+		        Object entity) throws SQLException {
+			if ( !rs.next() ) {
+				throw new IdentifierGenerationException(
+						"the inserted row could not be located by the unique key: " +
+						uniqueKeyPropertyName
+				);
+			}
+			return ( Serializable ) idType.nullSafeGet(
+					rs,
+					persister.getRootTableKeyColumnNames(),
+					session,
+					entity
+			);
+		}
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/id/SelectGenerator.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/SequenceGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/SequenceGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/SequenceGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,126 @@
+//$Id: SequenceGenerator.java 9686 2006-03-27 16:47:06Z steve.ebersole at jboss.com $
+package org.hibernate.id;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.mapping.Table;
+import org.hibernate.type.Type;
+import org.hibernate.util.PropertiesHelper;
+
+/**
+ * <b>sequence</b><br>
+ * <br>
+ * Generates <tt>long</tt> values using an oracle-style sequence. A higher
+ * performance algorithm is <tt>SequenceHiLoGenerator</tt>.<br>
+ * <br>
+ * Mapping parameters supported: sequence, parameters.
+ *
+ * @see SequenceHiLoGenerator
+ * @see TableHiLoGenerator
+ * @author Gavin King
+ */
+
+public class SequenceGenerator implements PersistentIdentifierGenerator, Configurable {
+
+	/**
+	 * The sequence parameter
+	 */
+	public static final String SEQUENCE = "sequence";
+
+	/**
+	 * The parameters parameter, appended to the create sequence DDL.
+	 * For example (Oracle): <tt>INCREMENT BY 1 START WITH 1 MAXVALUE 100 NOCACHE</tt>.
+	 */
+	public static final String PARAMETERS = "parameters";
+
+	private String sequenceName;
+	private String parameters;
+	private Type identifierType;
+	private String sql;
+
+	private static final Log log = LogFactory.getLog(SequenceGenerator.class);
+
+	public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
+		sequenceName = PropertiesHelper.getString(SEQUENCE, params, "hibernate_sequence");
+		parameters = params.getProperty(PARAMETERS);
+		String schemaName = params.getProperty(SCHEMA);
+		String catalogName = params.getProperty(CATALOG);
+
+		if (sequenceName.indexOf( '.' ) < 0) {
+			sequenceName = Table.qualify( catalogName, schemaName, sequenceName );
+		}
+
+		this.identifierType = type;
+		sql = dialect.getSequenceNextValString(sequenceName);
+	}
+
+	public Serializable generate(SessionImplementor session, Object obj) 
+	throws HibernateException {
+		
+		try {
+
+			PreparedStatement st = session.getBatcher().prepareSelectStatement(sql);
+			try {
+				ResultSet rs = st.executeQuery();
+				try {
+					rs.next();
+					Serializable result = IdentifierGeneratorFactory.get(
+							rs, identifierType
+						);
+					if ( log.isDebugEnabled() ) {
+						log.debug("Sequence identifier generated: " + result);
+					}
+					return result;
+				}
+				finally {
+					rs.close();
+				}
+			}
+			finally {
+				session.getBatcher().closeStatement(st);
+			}
+			
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					session.getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not get next sequence value",
+					sql
+				);
+		}
+
+	}
+
+	public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
+		String[] ddl = dialect.getCreateSequenceStrings(sequenceName);
+		if ( parameters != null ) {
+			ddl[ddl.length - 1] += ' ' + parameters;
+		}
+		return ddl;
+	}
+
+	public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
+		return dialect.getDropSequenceStrings(sequenceName);
+	}
+
+	public Object generatorKey() {
+		return sequenceName;
+	}
+
+	public String getSequenceName() {
+		return sequenceName;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,68 @@
+//$Id: SequenceHiLoGenerator.java 9720 2006-03-31 00:11:54Z epbernard $
+package org.hibernate.id;
+
+import java.io.Serializable;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+import org.hibernate.util.PropertiesHelper;
+
+/**
+ * <b>seqhilo</b><br>
+ * <br>
+ * An <tt>IdentifierGenerator</tt> that combines a hi/lo algorithm with an underlying
+ * oracle-style sequence that generates hi values. The user may specify a
+ * maximum lo value to determine how often new hi values are fetched.<br>
+ * <br>
+ * If sequences are not available, <tt>TableHiLoGenerator</tt> might be an
+ * alternative.<br>
+ * <br>
+ * Mapping parameters supported: sequence, max_lo, parameters.
+ *
+ * @see TableHiLoGenerator
+ * @author Gavin King
+ */
+public class SequenceHiLoGenerator extends SequenceGenerator {
+
+	public static final String MAX_LO = "max_lo";
+
+	private static final Log log = LogFactory.getLog(SequenceHiLoGenerator.class);
+
+	private int maxLo;
+	private int lo;
+	private long hi;
+	private Class returnClass;
+
+	public void configure(Type type, Properties params, Dialect d) throws MappingException {
+		super.configure(type, params, d);
+		maxLo = PropertiesHelper.getInt(MAX_LO, params, 9);
+		lo = maxLo + 1; // so we "clock over" on the first invocation
+		returnClass = type.getReturnedClass();
+	}
+
+	public synchronized Serializable generate(SessionImplementor session, Object obj) 
+	throws HibernateException {
+		if (maxLo < 1) {
+			//keep the behavior consistent even for boundary usages
+			long val = ( (Number) super.generate(session, obj) ).longValue();
+			if (val == 0) val = ( (Number) super.generate(session, obj) ).longValue();
+			return IdentifierGeneratorFactory.createNumber( val, returnClass );
+		}
+		if ( lo>maxLo ) {
+			long hival = ( (Number) super.generate(session, obj) ).longValue();
+			lo = (hival == 0) ? 1 : 0;
+			hi = hival * ( maxLo+1 );
+			if ( log.isDebugEnabled() )
+				log.debug("new hi value: " + hival);
+		}
+
+		return IdentifierGeneratorFactory.createNumber( hi + lo++, returnClass );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/SequenceIdentityGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/SequenceIdentityGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/SequenceIdentityGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,100 @@
+package org.hibernate.id;
+
+import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
+import org.hibernate.id.insert.AbstractReturningDelegate;
+import org.hibernate.id.insert.IdentifierGeneratingInsert;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.sql.Insert;
+import org.hibernate.util.NamedGeneratedKeysHelper;
+import org.hibernate.type.Type;
+import org.hibernate.engine.SessionImplementor;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Properties;
+
+/**
+ * A generator which combines sequence generation with immediate retrieval
+ * through JDBC3 {@link java.sql.Connection#prepareStatement(String, String[]) getGeneratedKeys}.
+ * In this respect it works much like ANSI-SQL IDENTITY generation.
+ * <p/>
+ * This generator only known to work with newer Oracle drivers compiled for
+ * JDK 1.4 (JDBC3).
+ * <p/>
+ * Note: Due to a bug in Oracle drivers, sql comments on these insert statements
+ * are completely disabled.
+ *
+ * @author Steve Ebersole
+ */
+public class SequenceIdentityGenerator extends SequenceGenerator
+		implements PostInsertIdentifierGenerator {
+
+	private static final Log log = LogFactory.getLog( SequenceIdentityGenerator.class );
+
+	public Serializable generate(SessionImplementor s, Object obj) {
+		return IdentifierGeneratorFactory.POST_INSERT_INDICATOR;
+	}
+
+	public InsertGeneratedIdentifierDelegate getInsertGeneratedIdentifierDelegate(
+			PostInsertIdentityPersister persister,
+	        Dialect dialect,
+	        boolean isGetGeneratedKeysEnabled) throws HibernateException {
+		return new Delegate( persister, dialect, getSequenceName() );
+	}
+
+	public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
+		super.configure( type, params, dialect );
+	}
+
+	public static class Delegate extends AbstractReturningDelegate {
+		private final Dialect dialect;
+		private final String sequenceNextValFragment;
+		private final String[] keyColumns;
+
+		public Delegate(PostInsertIdentityPersister persister, Dialect dialect, String sequenceName) {
+			super( persister );
+			this.dialect = dialect;
+			this.sequenceNextValFragment = dialect.getSelectSequenceNextValString( sequenceName );
+			this.keyColumns = getPersister().getRootTableKeyColumnNames();
+			if ( keyColumns.length > 1 ) {
+				throw new HibernateException( "sequence-identity generator cannot be used with with multi-column keys" );
+			}
+		}
+
+		public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() {
+			NoCommentsInsert insert = new NoCommentsInsert( dialect );
+			insert.addColumn( getPersister().getRootTableKeyColumnNames()[0], sequenceNextValFragment );
+			return insert;
+		}
+
+		protected PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException {
+			return session.getBatcher().prepareStatement( insertSQL, keyColumns );
+		}
+
+		protected Serializable executeAndExtract(PreparedStatement insert) throws SQLException {
+			insert.executeUpdate();
+			return IdentifierGeneratorFactory.getGeneratedIdentity(
+					NamedGeneratedKeysHelper.getGeneratedKey( insert ),
+			        getPersister().getIdentifierType()
+			);
+		}
+	}
+
+	public static class NoCommentsInsert extends IdentifierGeneratingInsert {
+		public NoCommentsInsert(Dialect dialect) {
+			super( dialect );
+		}
+
+		public Insert setComment(String comment) {
+			// don't allow comments on these insert statements as comments totally
+			// blow up the Oracle getGeneratedKeys "support" :(
+			log.info( "disallowing insert statement comment for select-identity due to Oracle driver bug" );
+			return this;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/TableGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/TableGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/TableGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,170 @@
+//$Id: TableGenerator.java 11303 2007-03-19 22:06:14Z steve.ebersole at jboss.com $
+package org.hibernate.id;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.TransactionHelper;
+import org.hibernate.mapping.Table;
+import org.hibernate.type.Type;
+import org.hibernate.util.PropertiesHelper;
+
+/**
+ * An <tt>IdentifierGenerator</tt> that uses a database
+ * table to store the last generated value. It is not
+ * intended that applications use this strategy directly.
+ * However, it may be used to build other (efficient)
+ * strategies. The returned type is <tt>Integer</tt>.<br>
+ * <br>
+ * The hi value MUST be fetched in a seperate transaction
+ * to the <tt>Session</tt> transaction so the generator must
+ * be able to obtain a new connection and commit it. Hence
+ * this implementation may not be used when Hibernate is
+ * fetching connections  when the user is supplying
+ * connections.<br>
+ * <br>
+ * The returned value is of type <tt>integer</tt>.<br>
+ * <br>
+ * Mapping parameters supported: table, column
+ *
+ * @see TableHiLoGenerator
+ * @author Gavin King
+ */
+public class TableGenerator extends TransactionHelper
+	implements PersistentIdentifierGenerator, Configurable {
+	/* COLUMN and TABLE should be renamed but it would break the public API */
+	/** The column parameter */
+	public static final String COLUMN = "column";
+	
+	/** Default column name */
+	public static final String DEFAULT_COLUMN_NAME = "next_hi";
+	
+	/** The table parameter */
+	public static final String TABLE = "table";
+	
+	/** Default table name */	
+	public static final String DEFAULT_TABLE_NAME = "hibernate_unique_key";
+
+	private static final Log log = LogFactory.getLog(TableGenerator.class);
+
+	private String tableName;
+	private String columnName;
+	private String query;
+	private String update;
+
+	public void configure(Type type, Properties params, Dialect dialect) {
+
+		tableName = PropertiesHelper.getString(TABLE, params, DEFAULT_TABLE_NAME);
+		columnName = PropertiesHelper.getString(COLUMN, params, DEFAULT_COLUMN_NAME);
+		String schemaName = params.getProperty(SCHEMA);
+		String catalogName = params.getProperty(CATALOG);
+
+		if ( tableName.indexOf( '.' )<0 ) {
+			tableName = Table.qualify( catalogName, schemaName, tableName );
+		}
+
+		query = "select " + 
+			columnName + 
+			" from " + 
+			dialect.appendLockHint(LockMode.UPGRADE, tableName) +
+			dialect.getForUpdateString();
+
+		update = "update " + 
+			tableName + 
+			" set " + 
+			columnName + 
+			" = ? where " + 
+			columnName + 
+			" = ?";
+	}
+
+	public synchronized Serializable generate(SessionImplementor session, Object object)
+		throws HibernateException {
+		int result = ( (Integer) doWorkInNewTransaction(session) ).intValue();
+		return new Integer(result);
+	}
+
+
+	public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
+		return new String[] {
+			dialect.getCreateTableString() + " " + tableName + " ( " + columnName + " " + dialect.getTypeName(Types.INTEGER) + " )",
+			"insert into " + tableName + " values ( 0 )"
+		};
+	}
+
+	public String[] sqlDropStrings(Dialect dialect) {
+		StringBuffer sqlDropString = new StringBuffer( "drop table " );
+		if ( dialect.supportsIfExistsBeforeTableName() ) {
+			sqlDropString.append( "if exists " );
+		}
+		sqlDropString.append( tableName ).append( dialect.getCascadeConstraintsString() );
+		if ( dialect.supportsIfExistsAfterTableName() ) {
+			sqlDropString.append( " if exists" );
+		}
+		return new String[] { sqlDropString.toString() };
+	}
+
+	public Object generatorKey() {
+		return tableName;
+	}
+
+	public Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException {
+		int result;
+		int rows;
+		do {
+			// The loop ensures atomicity of the
+			// select + update even for no transaction
+			// or read committed isolation level
+
+			sql = query;
+			SQL.debug(query);
+			PreparedStatement qps = conn.prepareStatement(query);
+			try {
+				ResultSet rs = qps.executeQuery();
+				if ( !rs.next() ) {
+					String err = "could not read a hi value - you need to populate the table: " + tableName;
+					log.error(err);
+					throw new IdentifierGenerationException(err);
+				}
+				result = rs.getInt(1);
+				rs.close();
+			}
+			catch (SQLException sqle) {
+				log.error("could not read a hi value", sqle);
+				throw sqle;
+			}
+			finally {
+				qps.close();
+			}
+
+			sql = update;
+			SQL.debug(update);
+			PreparedStatement ups = conn.prepareStatement(update);
+			try {
+				ups.setInt( 1, result + 1 );
+				ups.setInt( 2, result );
+				rows = ups.executeUpdate();
+			}
+			catch (SQLException sqle) {
+				log.error("could not update hi value in: " + tableName, sqle);
+				throw sqle;
+			}
+			finally {
+				ups.close();
+			}
+		}
+		while (rows==0);
+		return new Integer(result);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/TableHiLoGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/TableHiLoGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/TableHiLoGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,72 @@
+//$Id: TableHiLoGenerator.java 11123 2007-01-31 23:46:11Z steve.ebersole at jboss.com $
+package org.hibernate.id;
+
+import java.io.Serializable;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+import org.hibernate.util.PropertiesHelper;
+
+/**
+ * <b>hilo</b><br>
+ * <br>
+ * An <tt>IdentifierGenerator</tt> that returns a <tt>Long</tt>, constructed using
+ * a hi/lo algorithm. The hi value MUST be fetched in a seperate transaction
+ * to the <tt>Session</tt> transaction so the generator must be able to obtain
+ * a new connection and commit it. Hence this implementation may not
+ * be used  when the user is supplying connections. In this
+ * case a <tt>SequenceHiLoGenerator</tt> would be a better choice (where
+ * supported).<br>
+ * <br>
+ * Mapping parameters supported: table, column, max_lo
+ *
+ * @see SequenceHiLoGenerator
+ * @author Gavin King
+ */
+
+public class TableHiLoGenerator extends TableGenerator {
+
+	/**
+	 * The max_lo parameter
+	 */
+	public static final String MAX_LO = "max_lo";
+
+	private long hi;
+	private int lo;
+	private int maxLo;
+	private Class returnClass;
+
+	private static final Log log = LogFactory.getLog(TableHiLoGenerator.class);
+
+	public void configure(Type type, Properties params, Dialect d) {
+		super.configure(type, params, d);
+		maxLo = PropertiesHelper.getInt(MAX_LO, params, Short.MAX_VALUE);
+		lo = maxLo + 1; // so we "clock over" on the first invocation
+		returnClass = type.getReturnedClass();
+	}
+
+	public synchronized Serializable generate(SessionImplementor session, Object obj) 
+	throws HibernateException {
+        if (maxLo < 1) {
+			//keep the behavior consistent even for boundary usages
+			long val = ( (Number) super.generate(session, obj) ).longValue();
+			if (val == 0) val = ( (Number) super.generate(session, obj) ).longValue();
+			return IdentifierGeneratorFactory.createNumber( val, returnClass );
+		}
+		if (lo>maxLo) {
+			long hival = ( (Number) super.generate(session, obj) ).longValue();
+			lo = (hival == 0) ? 1 : 0;
+			hi = hival * (maxLo+1);
+			log.debug("new hi value: " + hival);
+		}
+
+		return IdentifierGeneratorFactory.createNumber( hi + lo++, returnClass );
+
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/UUIDHexGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/UUIDHexGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/UUIDHexGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,75 @@
+//$Id: UUIDHexGenerator.java 8049 2005-08-30 23:28:50Z turin42 $
+package org.hibernate.id;
+
+import java.io.Serializable;
+import java.util.Properties;
+
+import org.hibernate.Hibernate;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+import org.hibernate.util.PropertiesHelper;
+
+/**
+ * <b>uuid</b><br>
+ * <br>
+ * A <tt>UUIDGenerator</tt> that returns a string of length 32,
+ * This string will consist of only hex digits. Optionally,
+ * the string may be generated with separators between each
+ * component of the UUID.
+ *
+ * Mapping parameters supported: separator.
+ *
+ * @author Gavin King
+ */
+
+public class UUIDHexGenerator extends AbstractUUIDGenerator implements Configurable {
+
+	private String sep = "";
+
+	protected String format(int intval) {
+		String formatted = Integer.toHexString(intval);
+		StringBuffer buf = new StringBuffer("00000000");
+		buf.replace( 8-formatted.length(), 8, formatted );
+		return buf.toString();
+	}
+
+	protected String format(short shortval) {
+		String formatted = Integer.toHexString(shortval);
+		StringBuffer buf = new StringBuffer("0000");
+		buf.replace( 4-formatted.length(), 4, formatted );
+		return buf.toString();
+	}
+
+	public Serializable generate(SessionImplementor session, Object obj) {
+		return new StringBuffer(36)
+			.append( format( getIP() ) ).append(sep)
+			.append( format( getJVM() ) ).append(sep)
+			.append( format( getHiTime() ) ).append(sep)
+			.append( format( getLoTime() ) ).append(sep)
+			.append( format( getCount() ) )
+			.toString();
+	}
+
+	public void configure(Type type, Properties params, Dialect d) {
+		sep = PropertiesHelper.getString("separator", params, "");
+	}
+
+	public static void main( String[] args ) throws Exception {
+		Properties props = new Properties();
+		props.setProperty("separator", "/");
+		IdentifierGenerator gen = new UUIDHexGenerator();
+		( (Configurable) gen ).configure(Hibernate.STRING, props, null);
+		IdentifierGenerator gen2 = new UUIDHexGenerator();
+		( (Configurable) gen2 ).configure(Hibernate.STRING, props, null);
+
+		for ( int i=0; i<10; i++) {
+			String id = (String) gen.generate(null, null);
+			System.out.println(id);
+			String id2 = (String) gen2.generate(null, null);
+			System.out.println(id2);
+		}
+
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/AccessCallback.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/AccessCallback.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/AccessCallback.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+package org.hibernate.id.enhanced;
+
+/**
+ * Contract for providing callback access to a {@link DatabaseStructure},
+ * typically from the {@link Optimizer}.
+ *
+ * @author Steve Ebersole
+ */
+public interface AccessCallback {
+	/**
+	 * Retrieve the next value from the underlying source.
+	 *
+	 * @return The next value.
+	 */
+	public long getNextValue();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,61 @@
+package org.hibernate.id.enhanced;
+
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * Encapsulates definition of the underlying data structure backing a
+ * sequence-style generator.
+ *
+ * @author Steve Ebersole
+ */
+public interface DatabaseStructure {
+	/**
+	 * The name of the database structure (table or sequence).
+	 * @return The structure name.
+	 */
+	public String getName();
+
+	/**
+	 * How many times has this structure been accessed through this reference?
+	 * @return The number of accesses.
+	 */
+	public int getTimesAccessed();
+
+	/**
+	 * The configured increment size
+	 * @return The configured increment size
+	 */
+	public int getIncrementSize();
+
+	/**
+	 * A callback to be able to get the next value from the underlying
+	 * structure as needed.
+	 *
+	 * @param session The session.
+	 * @return The next value.
+	 */
+	public AccessCallback buildCallback(SessionImplementor session);
+
+	/**
+	 * Prepare this structure for use.  Called sometime after instantiation,
+	 * but before first use.
+	 *
+	 * @param optimizer The optimizer being applied to the generator.
+	 */
+	public void prepare(Optimizer optimizer);
+
+	/**
+	 * Commands needed to create the underlying structures.
+	 * @param dialect The database dialect being used.
+	 * @return The creation commands.
+	 */
+	public String[] sqlCreateStrings(Dialect dialect);
+
+	/**
+	 * Commands needed to drop the underlying structures.
+	 * @param dialect The database dialect being used.
+	 * @return The drop commands.
+	 */
+	public String[] sqlDropStrings(Dialect dialect);
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/Optimizer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/Optimizer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/Optimizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+package org.hibernate.id.enhanced;
+
+import java.io.Serializable;
+
+/**
+ * Performs optimization on an optimizable identifier generator.  Typically
+ * this optimization takes the form of trying to ensure we do not have to
+ * hit the database on each and every request to get an identifier value.
+ * <p/>
+ * Optimizers work on constructor injection.  They should provide
+ * a constructor with the following arguments <ol>
+ * <li>java.lang.Class - The return type for the generated values</li>
+ * <li>int - The increment size</li>
+ * </ol>
+ *
+ * @author Steve Ebersole
+ */
+public interface Optimizer {
+	/**
+	 * Generate an identifier value accounting for this specific optimization.
+	 *
+	 * @param callback Callback to access the underlying value source.
+	 * @return The generated identifier value.
+	 */
+	public Serializable generate(AccessCallback callback);
+
+	/**
+	 * A common means to access the last value obtained from the underlying
+	 * source.  This is intended for testing purposes, since accessing the
+	 * unerlying database source directly is much more difficult.
+	 *
+	 * @return The last value we obtained from the underlying source;
+	 * -1 indicates we have not yet consulted with the source.
+	 */
+	public long getLastSourceValue();
+
+	/**
+	 * Retrieves the defined increment size.
+	 *
+	 * @return The increment size.
+	 */
+	public int getIncrementSize();
+
+	/**
+	 * Are increments to be applied to the values stored in the underlying
+	 * value source?
+	 *
+	 * @return True if the values in the source are to be incremented
+	 * according to the defined increment size; false otherwise, in which
+	 * case the increment is totally an in memory construct.
+	 */
+	public boolean applyIncrementSizeToSourceValues();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,202 @@
+package org.hibernate.id.enhanced;
+
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.id.IdentifierGeneratorFactory;
+
+/**
+ * Factory for {@link Optimizer} instances.
+ *
+ * @author Steve Ebersole
+ */
+public class OptimizerFactory {
+	private static final Log log = LogFactory.getLog( OptimizerFactory.class );
+
+	public static final String NONE = "none";
+	public static final String HILO = "hilo";
+	public static final String POOL = "pooled";
+
+	private static Class[] CTOR_SIG = new Class[] { Class.class, int.class };
+
+	public static Optimizer buildOptimizer(String type, Class returnClass, int incrementSize) {
+		String optimizerClassName;
+		if ( NONE.equals( type ) ) {
+			optimizerClassName = NoopOptimizer.class.getName();
+		}
+		else if ( HILO.equals( type ) ) {
+			optimizerClassName = HiLoOptimizer.class.getName();
+		}
+		else if ( POOL.equals( type ) ) {
+			optimizerClassName = PooledOptimizer.class.getName();
+		}
+		else {
+			optimizerClassName = type;
+		}
+
+		try {
+			Class optimizerClass = ReflectHelper.classForName( optimizerClassName );
+			Constructor ctor = optimizerClass.getConstructor( CTOR_SIG );
+			return ( Optimizer ) ctor.newInstance( new Object[] { returnClass, new Integer( incrementSize ) } );
+		}
+		catch( Throwable ignore ) {
+			// intentionally empty
+		}
+
+		// the default...
+		return new NoopOptimizer( returnClass, incrementSize );
+	}
+
+	public static abstract class OptimizerSupport implements Optimizer {
+		protected final Class returnClass;
+		protected final int incrementSize;
+
+		protected OptimizerSupport(Class returnClass, int incrementSize) {
+			if ( returnClass == null ) {
+				throw new HibernateException( "return class is required" );
+			}
+			this.returnClass = returnClass;
+			this.incrementSize = incrementSize;
+		}
+
+		protected Serializable make(long value) {
+			return IdentifierGeneratorFactory.createNumber( value, returnClass );
+		}
+
+		public Class getReturnClass() {
+			return returnClass;
+		}
+
+		public int getIncrementSize() {
+			return incrementSize;
+		}
+	}
+
+	public static class NoopOptimizer extends OptimizerSupport {
+		private long lastSourceValue = -1;
+
+		public NoopOptimizer(Class returnClass, int incrementSize) {
+			super( returnClass, incrementSize );
+		}
+
+		public Serializable generate(AccessCallback callback) {
+			if ( lastSourceValue == -1 ) {
+				while( lastSourceValue <= 0 ) {
+					lastSourceValue = callback.getNextValue();
+				}
+			}
+			else {
+				lastSourceValue = callback.getNextValue();
+			}
+			return make( lastSourceValue );
+		}
+
+		public long getLastSourceValue() {
+			return lastSourceValue;
+		}
+
+		public boolean applyIncrementSizeToSourceValues() {
+			return false;
+		}
+	}
+
+	public static class HiLoOptimizer extends OptimizerSupport {
+		private long lastSourceValue = -1;
+		private long value;
+		private long hiValue;
+
+		public HiLoOptimizer(Class returnClass, int incrementSize) {
+			super( returnClass, incrementSize );
+			if ( incrementSize < 1 ) {
+				throw new HibernateException( "increment size cannot be less than 1" );
+			}
+			if ( log.isTraceEnabled() ) {
+				log.trace( "creating hilo optimizer with [incrementSize=" + incrementSize + "; returnClass="  + returnClass.getName() + "]" );
+			}
+		}
+
+		public Serializable generate(AccessCallback callback) {
+			if ( lastSourceValue < 0 ) {
+				lastSourceValue = callback.getNextValue();
+				while ( lastSourceValue <= 0 ) {
+					lastSourceValue = callback.getNextValue();
+				}
+				hiValue = ( lastSourceValue * incrementSize ) + 1;
+				value = hiValue - incrementSize;
+			}
+			else if ( value >= hiValue ) {
+				lastSourceValue = callback.getNextValue();
+				hiValue = ( lastSourceValue * incrementSize ) + 1;
+			}
+			return make( value++ );
+		}
+
+
+		public long getLastSourceValue() {
+			return lastSourceValue;
+		}
+
+		public boolean applyIncrementSizeToSourceValues() {
+			return false;
+		}
+
+		public long getLastValue() {
+			return value - 1;
+		}
+
+		public long getHiValue() {
+			return hiValue;
+		}
+	}
+
+	public static class PooledOptimizer extends OptimizerSupport {
+		private long value;
+		private long hiValue = -1;
+
+		public PooledOptimizer(Class returnClass, int incrementSize) {
+			super( returnClass, incrementSize );
+			if ( incrementSize < 1 ) {
+				throw new HibernateException( "increment size cannot be less than 1" );
+			}
+			if ( log.isTraceEnabled() ) {
+				log.trace( "creating pooled optimizer with [incrementSize=" + incrementSize + "; returnClass="  + returnClass.getName() + "]" );
+			}
+		}
+
+		public Serializable generate(AccessCallback callback) {
+			if ( hiValue < 0 ) {
+				value = callback.getNextValue();
+				if ( value < 1 ) {
+					// unfortunately not really safe to normalize this
+					// to 1 as an initial value like we do the others
+					// because we would not be able to control this if
+					// we are using a sequence...
+					log.info( "pooled optimizer source reported [" + value + "] as the initial value; use of 1 or greater highly recommended" );
+				}
+				hiValue = callback.getNextValue();
+			}
+			else if ( value >= hiValue ) {
+				hiValue = callback.getNextValue();
+				value = hiValue - incrementSize;
+			}
+			return make( value++ );
+		}
+
+		public long getLastSourceValue() {
+			return hiValue;
+		}
+
+		public boolean applyIncrementSizeToSourceValues() {
+			return true;
+		}
+
+		public long getLastValue() {
+			return value - 1;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,103 @@
+package org.hibernate.id.enhanced;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.HibernateException;
+
+/**
+ * Describes a sequence.
+ *
+ * @author Steve Ebersole
+ */
+public class SequenceStructure implements DatabaseStructure {
+	private static final Log log = LogFactory.getLog( SequenceStructure.class );
+
+	private final String sequenceName;
+	private final int initialValue;
+	private final int incrementSize;
+	private final String sql;
+	private boolean applyIncrementSizeToSourceValues;
+	private int accessCounter;
+
+	public SequenceStructure(Dialect dialect, String sequenceName, int initialValue, int incrementSize) {
+		this.sequenceName = sequenceName;
+		this.initialValue = initialValue;
+		this.incrementSize = incrementSize;
+		sql = dialect.getSequenceNextValString( sequenceName );
+	}
+
+	public String getName() {
+		return sequenceName;
+	}
+
+	public int getIncrementSize() {
+		return incrementSize;
+	}
+
+	public int getTimesAccessed() {
+		return accessCounter;
+	}
+
+	public AccessCallback buildCallback(final SessionImplementor session) {
+		return new AccessCallback() {
+			public long getNextValue() {
+				accessCounter++;
+				try {
+					PreparedStatement st = session.getBatcher().prepareSelectStatement( sql );
+					try {
+						ResultSet rs = st.executeQuery();
+						try {
+							rs.next();
+							long result = rs.getLong( 1 );
+							if ( log.isDebugEnabled() ) {
+								log.debug("Sequence identifier generated: " + result);
+							}
+							return result;
+						}
+						finally {
+							try {
+								rs.close();
+							}
+							catch( Throwable ignore ) {
+								// intentionally empty
+							}
+						}
+					}
+					finally {
+						session.getBatcher().closeStatement( st );
+					}
+
+				}
+				catch ( SQLException sqle) {
+					throw JDBCExceptionHelper.convert(
+							session.getFactory().getSQLExceptionConverter(),
+							sqle,
+							"could not get next sequence value",
+							sql
+					);
+				}
+			}
+		};
+	}
+
+	public void prepare(Optimizer optimizer) {
+		applyIncrementSizeToSourceValues = optimizer.applyIncrementSizeToSourceValues();
+	}
+
+	public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
+		int sourceIncrementSize = applyIncrementSizeToSourceValues ? incrementSize : 1;
+		return dialect.getCreateSequenceStrings( sequenceName, initialValue, sourceIncrementSize );
+	}
+
+	public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
+		return dialect.getDropSequenceStrings( sequenceName );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,175 @@
+package org.hibernate.id.enhanced;
+
+import java.util.Properties;
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.id.PersistentIdentifierGenerator;
+import org.hibernate.id.Configurable;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.mapping.Table;
+import org.hibernate.util.PropertiesHelper;
+import org.hibernate.type.Type;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * Generates identifier values based on an sequence-style database structure.
+ * Variations range from actually using a sequence to using a table to mimic
+ * a sequence.  These variations are encapsulated by the {@link DatabaseStructure}
+ * interface internally.
+ * <p/>
+ * General configuration parameters:
+ * <table>
+ * 	 <tr>
+ *     <td><b>NAME</b></td>
+ *     <td><b>DEFAULT</b></td>
+ *     <td><b>DESCRIPTION</b></td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #SEQUENCE_PARAM}</td>
+ *     <td>{@link #DEF_SEQUENCE_NAME}</td>
+ *     <td>The name of the sequence/table to use to store/retrieve values</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #INITIAL_PARAM}</td>
+ *     <td>{@link #DEFAULT_INITIAL_VALUE}</td>
+ *     <td>The initial value to be stored for the given segment; the effect in terms of storage varies based on {@link Optimizer} and {@link DatabaseStructure}</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #INCREMENT_PARAM}</td>
+ *     <td>{@link #DEFAULT_INCREMENT_SIZE}</td>
+ *     <td>The increment size for the underlying segment; the effect in terms of storage varies based on {@link Optimizer} and {@link DatabaseStructure}</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #OPT_PARAM}</td>
+ *     <td><i>depends on defined increment size</i></td>
+ *     <td>Allows explicit definition of which optimization strategy to use</td>
+ *   </tr>
+ *     <td>{@link #FORCE_TBL_PARAM}</td>
+ *     <td><b><i>false<i/></b></td>
+ *     <td>Allows explicit definition of which optimization strategy to use</td>
+ *   </tr>
+ * </table>
+ * <p/>
+ * Configuration parameters used specifically when the underlying structure is a table:
+ * <table>
+ * 	 <tr>
+ *     <td><b>NAME</b></td>
+ *     <td><b>DEFAULT</b></td>
+ *     <td><b>DESCRIPTION</b></td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #VALUE_COLUMN_PARAM}</td>
+ *     <td>{@link #DEF_VALUE_COLUMN}</td>
+ *     <td>The name of column which holds the sequence value for the given segment</td>
+ *   </tr>
+ * </table>
+ *
+ * @author Steve Ebersole
+ */
+public class SequenceStyleGenerator implements PersistentIdentifierGenerator, Configurable {
+	private static final Log log = LogFactory.getLog( SequenceStyleGenerator.class );
+
+	// general purpose parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	public static final String SEQUENCE_PARAM = "sequence_name";
+	public static final String DEF_SEQUENCE_NAME = "hibernate_sequence";
+
+	public static final String INITIAL_PARAM = "initial_value";
+	public static final int DEFAULT_INITIAL_VALUE = 1;
+
+	public static final String INCREMENT_PARAM = "increment_size";
+	public static final int DEFAULT_INCREMENT_SIZE = 1;
+
+	public static final String OPT_PARAM = "optimizer";
+
+	public static final String FORCE_TBL_PARAM = "force_table_use";
+
+
+	// table-specific parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	public static final String VALUE_COLUMN_PARAM = "value_column";
+	public static final String DEF_VALUE_COLUMN = "next_val";
+
+
+	// state ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	private DatabaseStructure databaseStructure;
+	private Optimizer optimizer;
+	private Type identifierType;
+
+	public DatabaseStructure getDatabaseStructure() {
+		return databaseStructure;
+	}
+
+	public Optimizer getOptimizer() {
+		return optimizer;
+	}
+
+	public Type getIdentifierType() {
+		return identifierType;
+	}
+
+
+	// Configurable implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
+		identifierType = type;
+		boolean forceTableUse = PropertiesHelper.getBoolean( FORCE_TBL_PARAM, params, false );
+
+		String sequenceName = PropertiesHelper.getString( SEQUENCE_PARAM, params, DEF_SEQUENCE_NAME );
+		if ( sequenceName.indexOf( '.' ) < 0 ) {
+			String schemaName = params.getProperty( SCHEMA );
+			String catalogName = params.getProperty( CATALOG );
+			sequenceName = Table.qualify( catalogName, schemaName, sequenceName );
+		}
+		int initialValue = PropertiesHelper.getInt( INITIAL_PARAM, params, DEFAULT_INITIAL_VALUE );
+		int incrementSize = PropertiesHelper.getInt( INCREMENT_PARAM, params, DEFAULT_INCREMENT_SIZE );
+
+		String valueColumnName = PropertiesHelper.getString( VALUE_COLUMN_PARAM, params, DEF_VALUE_COLUMN );
+
+		String defOptStrategy = incrementSize <= 1 ? OptimizerFactory.NONE : OptimizerFactory.POOL;
+		String optimizationStrategy = PropertiesHelper.getString( OPT_PARAM, params, defOptStrategy );
+		if ( OptimizerFactory.NONE.equals( optimizationStrategy ) && incrementSize > 1 ) {
+			log.warn( "config specified explicit optimizer of [" + OptimizerFactory.NONE + "], but [" + INCREMENT_PARAM + "=" + incrementSize + "; honoring optimizer setting" );
+			incrementSize = 1;
+		}
+		if ( dialect.supportsSequences() && !forceTableUse ) {
+			if ( OptimizerFactory.POOL.equals( optimizationStrategy ) && !dialect.supportsPooledSequences() ) {
+				// TODO : may even be better to fall back to a pooled table strategy here so that the db stored values remain consistent... 
+				optimizationStrategy = OptimizerFactory.HILO;
+			}
+			databaseStructure = new SequenceStructure( dialect, sequenceName, initialValue, incrementSize );
+		}
+		else {
+			databaseStructure = new TableStructure( dialect, sequenceName, valueColumnName, initialValue, incrementSize );
+		}
+
+		optimizer = OptimizerFactory.buildOptimizer( optimizationStrategy, identifierType.getReturnedClass(), incrementSize );
+		databaseStructure.prepare( optimizer );
+	}
+
+
+	// IdentifierGenerator implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
+		return optimizer.generate( databaseStructure.buildCallback( session ) );
+	}
+
+
+	// PersistentIdentifierGenerator implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public Object generatorKey() {
+		return databaseStructure.getName();
+	}
+
+	public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
+		return databaseStructure.sqlCreateStrings( dialect );
+	}
+
+	public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
+		return databaseStructure.sqlDropStrings( dialect );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,321 @@
+package org.hibernate.id.enhanced;
+
+import java.sql.Types;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.Properties;
+import java.util.HashMap;
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.engine.TransactionHelper;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.id.PersistentIdentifierGenerator;
+import org.hibernate.id.Configurable;
+import org.hibernate.type.Type;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.LockMode;
+import org.hibernate.mapping.Table;
+import org.hibernate.util.PropertiesHelper;
+import org.hibernate.util.StringHelper;
+import org.hibernate.util.CollectionHelper;
+
+/**
+ * An enhanced version of explicit table-based generator.  The main basis
+ * conceptualization is similiar to the legacy
+ * {@link org.hibernate.id.MultipleHiLoPerTableGenerator} in terms of the
+ * underlying storage structure (namely a single table capable of holding
+ * multiple generator values).  The differentiator is, as with
+ * {@link SequenceStyleGenerator} as well, the externalization of the notion
+ * of an optimizer.
+ * <p/>
+ * Configuration parameters:
+ * <table>
+ * 	 <tr>
+ *     <td><b>NAME</b></td>
+ *     <td><b>DEFAULT</b></td>
+ *     <td><b>DESCRIPTION</b></td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #TABLE_PARAM}</td>
+ *     <td>{@link #DEF_TABLE}</td>
+ *     <td>The name of the table to use to store/retrieve values</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #VALUE_COLUMN_PARAM}</td>
+ *     <td>{@link #DEF_VALUE_COLUMN}</td>
+ *     <td>The name of column which holds the sequence value for the given segment</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #SEGMENT_COLUMN_PARAM}</td>
+ *     <td>{@link #DEF_SEGMENT_COLUMN}</td>
+ *     <td>The name of the column which holds the segment key</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #SEGMENT_VALUE_PARAM}</td>
+ *     <td>{@link #DEF_SEGMENT_VALUE}</td>
+ *     <td>The value indicating which segment is used by this generator; refers to values in the {@link #SEGMENT_COLUMN_PARAM} column</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #SEGMENT_LENGTH_PARAM}</td>
+ *     <td>{@link #DEF_SEGMENT_LENGTH}</td>
+ *     <td>The data length of the {@link #SEGMENT_COLUMN_PARAM} column; used for schema creation</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #INITIAL_PARAM}</td>
+ *     <td>{@link #DEFAULT_INITIAL_VALUE}</td>
+ *     <td>The initial value to be stored for the given segment</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #INCREMENT_PARAM}</td>
+ *     <td>{@link #DEFAULT_INCREMENT_SIZE}</td>
+ *     <td>The increment size for the underlying segment; see the discussion on {@link Optimizer} for more details.</td>
+ *   </tr>
+ *   <tr>
+ *     <td>{@link #OPT_PARAM}</td>
+ *     <td><i>depends on defined increment size</i></td>
+ *     <td>Allows explicit definition of which optimization strategy to use</td>
+ *   </tr>
+ * </table>
+ *
+ * @author Steve Ebersole
+ */
+public class TableGenerator extends TransactionHelper implements PersistentIdentifierGenerator, Configurable {
+	private static final Log log = LogFactory.getLog( TableGenerator.class );
+
+	public static final String TABLE_PARAM = "table_name";
+	public static final String DEF_TABLE = "hibernate_sequences";
+
+	public static final String VALUE_COLUMN_PARAM = "value_column_name";
+	public static final String DEF_VALUE_COLUMN = "next_val";
+
+	public static final String SEGMENT_COLUMN_PARAM = "segment_column_name";
+	public static final String DEF_SEGMENT_COLUMN = "sequence_name";
+
+	public static final String SEGMENT_VALUE_PARAM = "segment_value";
+	public static final String DEF_SEGMENT_VALUE = "default";
+
+	public static final String SEGMENT_LENGTH_PARAM = "segment_value_length";
+	public static final int DEF_SEGMENT_LENGTH = 255;
+
+	public static final String INITIAL_PARAM = "initial_value";
+	public static final int DEFAULT_INITIAL_VALUE = 1;
+
+	public static final String INCREMENT_PARAM = "increment_size";
+	public static final int DEFAULT_INCREMENT_SIZE = 1;
+
+	public static final String OPT_PARAM = "optimizer";
+
+
+	private String tableName;
+	private String valueColumnName;
+	private String segmentColumnName;
+	private String segmentValue;
+	private int segmentValueLength;
+	private int initialValue;
+	private int incrementSize;
+
+	private Type identifierType;
+
+	private String query;
+	private String insert;
+	private String update;
+
+	private Optimizer optimizer;
+	private long accessCount = 0;
+
+	public String getTableName() {
+		return tableName;
+	}
+
+	public String getSegmentColumnName() {
+		return segmentColumnName;
+	}
+
+	public String getSegmentValue() {
+		return segmentValue;
+	}
+
+	public int getSegmentValueLength() {
+		return segmentValueLength;
+	}
+
+	public String getValueColumnName() {
+		return valueColumnName;
+	}
+
+	public Type getIdentifierType() {
+		return identifierType;
+	}
+
+	public int getInitialValue() {
+		return initialValue;
+	}
+
+	public int getIncrementSize() {
+		return incrementSize;
+	}
+
+	public Optimizer getOptimizer() {
+		return optimizer;
+	}
+
+	public long getTableAccessCount() {
+		return accessCount;
+	}
+
+	public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
+		tableName = PropertiesHelper.getString( TABLE_PARAM, params, DEF_TABLE );
+		if ( tableName.indexOf( '.' ) < 0 ) {
+			String schemaName = params.getProperty( SCHEMA );
+			String catalogName = params.getProperty( CATALOG );
+			tableName = Table.qualify( catalogName, schemaName, tableName );
+		}
+
+		segmentColumnName = PropertiesHelper.getString( SEGMENT_COLUMN_PARAM, params, DEF_SEGMENT_COLUMN );
+		segmentValue = params.getProperty( SEGMENT_VALUE_PARAM );
+		if ( StringHelper.isEmpty( segmentValue ) ) {
+			log.debug( "explicit segment value for id generator [" + tableName + '.' + segmentColumnName + "] suggested; using default [" + DEF_SEGMENT_VALUE + "]" );
+			segmentValue = DEF_SEGMENT_VALUE;
+		}
+		segmentValueLength = PropertiesHelper.getInt( SEGMENT_LENGTH_PARAM, params, DEF_SEGMENT_LENGTH );
+		valueColumnName = PropertiesHelper.getString( VALUE_COLUMN_PARAM, params, DEF_VALUE_COLUMN );
+		initialValue = PropertiesHelper.getInt( INITIAL_PARAM, params, DEFAULT_INITIAL_VALUE );
+		incrementSize = PropertiesHelper.getInt( INCREMENT_PARAM, params, DEFAULT_INCREMENT_SIZE );
+		identifierType = type;
+
+		String query = "select " + valueColumnName +
+				" from " + tableName + " tbl" +
+				" where tbl." + segmentColumnName + "=?";
+		HashMap lockMap = new HashMap();
+		lockMap.put( "tbl", LockMode.UPGRADE );
+		this.query = dialect.applyLocksToSql( query, lockMap, CollectionHelper.EMPTY_MAP );
+
+		update = "update " + tableName +
+				" set " + valueColumnName + "=? " +
+				" where " + valueColumnName + "=? and " + segmentColumnName + "=?";
+
+		insert = "insert into " + tableName + " (" + segmentColumnName + ", " + valueColumnName + ") " + " values (?,?)";
+
+		String defOptStrategy = incrementSize <= 1 ? OptimizerFactory.NONE : OptimizerFactory.POOL;
+		String optimizationStrategy = PropertiesHelper.getString( OPT_PARAM, params, defOptStrategy );
+		optimizer = OptimizerFactory.buildOptimizer( optimizationStrategy, identifierType.getReturnedClass(), incrementSize );
+	}
+
+	public synchronized Serializable generate(final SessionImplementor session, Object obj) {
+		return optimizer.generate(
+				new AccessCallback() {
+					public long getNextValue() {
+						return ( ( Number ) doWorkInNewTransaction( session ) ).longValue();
+					}
+				}
+		);
+	}
+
+	public Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException {
+		int result;
+		int rows;
+		do {
+			sql = query;
+			SQL.debug( sql );
+			PreparedStatement queryPS = conn.prepareStatement( query );
+			try {
+				queryPS.setString( 1, segmentValue );
+				ResultSet queryRS = queryPS.executeQuery();
+				if ( !queryRS.next() ) {
+					PreparedStatement insertPS = null;
+					try {
+						result = initialValue;
+						sql = insert;
+						SQL.debug( sql );
+						insertPS = conn.prepareStatement( insert );
+						insertPS.setString( 1, segmentValue );
+						insertPS.setLong( 2, result );
+						insertPS.execute();
+					}
+					finally {
+						if ( insertPS != null ) {
+							insertPS.close();
+						}
+					}
+				}
+				else {
+					result = queryRS.getInt( 1 );
+				}
+				queryRS.close();
+			}
+			catch ( SQLException sqle ) {
+				log.error( "could not read or init a hi value", sqle );
+				throw sqle;
+			}
+			finally {
+				queryPS.close();
+			}
+
+			sql = update;
+			SQL.debug( sql );
+			PreparedStatement updatePS = conn.prepareStatement( update );
+			try {
+				long newValue = optimizer.applyIncrementSizeToSourceValues()
+						? result + incrementSize : result + 1;
+				updatePS.setLong( 1, newValue );
+				updatePS.setLong( 2, result );
+				updatePS.setString( 3, segmentValue );
+				rows = updatePS.executeUpdate();
+			}
+			catch ( SQLException sqle ) {
+				log.error( "could not update hi value in: " + tableName, sqle );
+				throw sqle;
+			}
+			finally {
+				updatePS.close();
+			}
+		}
+		while ( rows == 0 );
+
+		accessCount++;
+
+		return new Integer( result );
+	}
+
+	public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
+		return new String[] {
+				new StringBuffer()
+						.append( dialect.getCreateTableString() )
+						.append( ' ' )
+						.append( tableName )
+						.append( " ( " )
+						.append( segmentColumnName )
+						.append( ' ' )
+						.append( dialect.getTypeName( Types.VARCHAR, segmentValueLength, 0, 0 ) )
+						.append( ",  " )
+						.append( valueColumnName )
+						.append( ' ' )
+						.append( dialect.getTypeName( Types.BIGINT ) )
+						.append( " ) " )
+						.toString()
+		};
+	}
+
+	public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
+		StringBuffer sqlDropString = new StringBuffer().append( "drop table " );
+		if ( dialect.supportsIfExistsBeforeTableName() ) {
+			sqlDropString.append( "if exists " );
+		}
+		sqlDropString.append( tableName ).append( dialect.getCascadeConstraintsString() );
+		if ( dialect.supportsIfExistsAfterTableName() ) {
+			sqlDropString.append( " if exists" );
+		}
+		return new String[] { sqlDropString.toString() };
+	}
+
+	public Object generatorKey() {
+		return tableName;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/TableStructure.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/TableStructure.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/enhanced/TableStructure.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,144 @@
+package org.hibernate.id.enhanced;
+
+import java.sql.Types;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.LockMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.TransactionHelper;
+import org.hibernate.id.IdentifierGenerationException;
+
+/**
+ * Describes a table used to mimic sequence behavior
+ *
+ * @author Steve Ebersole
+ */
+public class TableStructure extends TransactionHelper implements DatabaseStructure {
+	private static final Log log = LogFactory.getLog( TableStructure.class );
+	private static final Log SQL_LOG = LogFactory.getLog( "org.hibernate.SQL" );
+
+	private final String tableName;
+	private final String valueColumnName;
+	private final int initialValue;
+	private final int incrementSize;
+	private final String select;
+	private final String update;
+	private boolean applyIncrementSizeToSourceValues;
+	private int accessCounter;
+
+	public TableStructure(Dialect dialect, String tableName, String valueColumnName, int initialValue, int incrementSize) {
+		this.tableName = tableName;
+		this.initialValue = initialValue;
+		this.incrementSize = incrementSize;
+		this.valueColumnName = valueColumnName;
+
+		select = "select " + valueColumnName + " id_val" +
+				" from " + dialect.appendLockHint( LockMode.UPGRADE, tableName ) +
+				dialect.getForUpdateString();
+
+		update = "update " + tableName +
+				" set " + valueColumnName + "= ?" +
+				" where " + valueColumnName + "=?";
+	}
+
+	public String getName() {
+		return tableName;
+	}
+
+	public int getIncrementSize() {
+		return incrementSize;
+	}
+
+	public int getTimesAccessed() {
+		return accessCounter;
+	}
+
+	public void prepare(Optimizer optimizer) {
+		applyIncrementSizeToSourceValues = optimizer.applyIncrementSizeToSourceValues();
+	}
+
+	public AccessCallback buildCallback(final SessionImplementor session) {
+		return new AccessCallback() {
+			public long getNextValue() {
+				return ( ( Number ) doWorkInNewTransaction( session ) ).longValue();
+			}
+		};
+	}
+
+	public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
+		return new String[] {
+				dialect.getCreateTableString() + " " + tableName + " ( " + valueColumnName + " " + dialect.getTypeName( Types.BIGINT ) + " )",
+				"insert into " + tableName + " values ( " + initialValue + " )"
+		};
+	}
+
+	public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
+		StringBuffer sqlDropString = new StringBuffer().append( "drop table " );
+		if ( dialect.supportsIfExistsBeforeTableName() ) {
+			sqlDropString.append( "if exists " );
+		}
+		sqlDropString.append( tableName ).append( dialect.getCascadeConstraintsString() );
+		if ( dialect.supportsIfExistsAfterTableName() ) {
+			sqlDropString.append( " if exists" );
+		}
+		return new String[] { sqlDropString.toString() };
+	}
+
+	protected Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException {
+		long result;
+		int rows;
+		do {
+			sql = select;
+			SQL_LOG.debug( sql );
+			PreparedStatement qps = conn.prepareStatement( select );
+			try {
+				ResultSet rs = qps.executeQuery();
+				if ( !rs.next() ) {
+					String err = "could not read a hi value - you need to populate the table: " + tableName;
+					log.error( err );
+					throw new IdentifierGenerationException( err );
+				}
+				result = rs.getLong( 1 );
+				rs.close();
+			}
+			catch ( SQLException sqle ) {
+				log.error( "could not read a hi value", sqle );
+				throw sqle;
+			}
+			finally {
+				qps.close();
+			}
+
+			sql = update;
+			SQL_LOG.debug( sql );
+			PreparedStatement ups = conn.prepareStatement( update );
+			try {
+				int increment = applyIncrementSizeToSourceValues ? incrementSize : 1;
+				ups.setLong( 1, result + increment );
+				ups.setLong( 2, result );
+				rows = ups.executeUpdate();
+			}
+			catch ( SQLException sqle ) {
+				log.error( "could not update hi value in: " + tableName, sqle );
+				throw sqle;
+			}
+			finally {
+				ups.close();
+			}
+		} while ( rows == 0 );
+
+		accessCounter++;
+
+		return new Long( result );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/AbstractReturningDelegate.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/AbstractReturningDelegate.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/AbstractReturningDelegate.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+package org.hibernate.id.insert;
+
+import org.hibernate.id.PostInsertIdentityPersister;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.pretty.MessageHelper;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * Abstract InsertGeneratedIdentifierDelegate implementation where the
+ * underlying strategy causes the enerated identitifer to be returned as an
+ * effect of performing the insert statement.  Thus, there is no need for an
+ * additional sql statement to determine the generated identitifer.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractReturningDelegate implements InsertGeneratedIdentifierDelegate {
+	private final PostInsertIdentityPersister persister;
+
+	public AbstractReturningDelegate(PostInsertIdentityPersister persister) {
+		this.persister = persister;
+	}
+
+	public final Serializable performInsert(String insertSQL, SessionImplementor session, Binder binder) {
+		try {
+			// prepare and execute the insert
+			PreparedStatement insert = prepare( insertSQL, session );
+			try {
+				binder.bindValues( insert );
+				return executeAndExtract( insert );
+			}
+			finally {
+				releaseStatement( insert, session );
+			}
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					session.getFactory().getSQLExceptionConverter(),
+			        sqle,
+			        "could not insert: " + MessageHelper.infoString( persister ),
+			        insertSQL
+				);
+		}
+	}
+
+	protected PostInsertIdentityPersister getPersister() {
+		return persister;
+	}
+
+	protected abstract PreparedStatement prepare(String insertSQL, SessionImplementor session) throws SQLException;
+
+	protected abstract Serializable executeAndExtract(PreparedStatement insert) throws SQLException;
+
+	protected void releaseStatement(PreparedStatement insert, SessionImplementor session) throws SQLException {
+		session.getBatcher().closeStatement( insert );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/AbstractSelectingDelegate.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/AbstractSelectingDelegate.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/AbstractSelectingDelegate.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,113 @@
+package org.hibernate.id.insert;
+
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.id.PostInsertIdentityPersister;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.ResultSet;
+import java.io.Serializable;
+
+/**
+ * Abstract InsertGeneratedIdentifierDelegate implementation where the
+ * underlying strategy requires an subsequent select after the insert
+ * to determine the generated identifier.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractSelectingDelegate implements InsertGeneratedIdentifierDelegate {
+	private final PostInsertIdentityPersister persister;
+
+	protected AbstractSelectingDelegate(PostInsertIdentityPersister persister) {
+		this.persister = persister;
+	}
+
+	public final Serializable performInsert(String insertSQL, SessionImplementor session, Binder binder) {
+		try {
+			// prepare and execute the insert
+			PreparedStatement insert = session.getBatcher().prepareStatement( insertSQL, false );
+			try {
+				binder.bindValues( insert );
+				insert.executeUpdate();
+			}
+			finally {
+				session.getBatcher().closeStatement( insert );
+			}
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					session.getFactory().getSQLExceptionConverter(),
+			        sqle,
+			        "could not insert: " + MessageHelper.infoString( persister ),
+			        insertSQL
+				);
+		}
+
+		final String selectSQL = getSelectSQL();
+
+		try {
+			//fetch the generated id in a separate query
+			PreparedStatement idSelect = session.getBatcher().prepareStatement( selectSQL );
+			try {
+				bindParameters( session, idSelect, binder.getEntity() );
+				ResultSet rs = idSelect.executeQuery();
+				try {
+					return getResult( session, rs, binder.getEntity() );
+				}
+				finally {
+					rs.close();
+				}
+			}
+			finally {
+				session.getBatcher().closeStatement( idSelect );
+			}
+
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					session.getFactory().getSQLExceptionConverter(),
+			        sqle,
+			        "could not retrieve generated id after insert: " + MessageHelper.infoString( persister ),
+			        insertSQL
+			);
+		}
+	}
+
+	/**
+	 * Get the SQL statement to be used to retrieve generated key values.
+	 *
+	 * @return The SQL command string
+	 */
+	protected abstract String getSelectSQL();
+
+	/**
+	 * Bind any required parameter values into the SQL command {@link #getSelectSQL}.
+	 *
+	 * @param session The session
+	 * @param ps The prepared {@link #getSelectSQL SQL} command
+	 * @param entity The entity being saved.
+	 * @throws SQLException
+	 */
+	protected void bindParameters(
+			SessionImplementor session,
+	        PreparedStatement ps,
+	        Object entity) throws SQLException {
+	}
+
+	/**
+	 * Extract the generated key value from the given result set.
+	 *
+	 * @param session The session
+	 * @param rs The result set containing the generated primay key values.
+	 * @param entity The entity being saved.
+	 * @return The generated identifier
+	 * @throws SQLException
+	 */
+	protected abstract Serializable getResult(
+			SessionImplementor session,
+	        ResultSet rs,
+	        Object entity) throws SQLException;
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/Binder.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/Binder.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/Binder.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,12 @@
+package org.hibernate.id.insert;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface Binder {
+	public void bindValues(PreparedStatement ps) throws SQLException;
+	public Object getEntity();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/IdentifierGeneratingInsert.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/IdentifierGeneratingInsert.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/IdentifierGeneratingInsert.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+package org.hibernate.id.insert;
+
+import org.hibernate.sql.Insert;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * Nothing more than a distinguishing subclass of Insert used to indicate
+ * intent.  Some subclasses of this also provided some additional
+ * functionality or semantic to the genernated SQL statement string.
+ *
+ * @author Steve Ebersole
+ */
+public class IdentifierGeneratingInsert extends Insert {
+	public IdentifierGeneratingInsert(Dialect dialect) {
+		super( dialect );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/InsertGeneratedIdentifierDelegate.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/InsertGeneratedIdentifierDelegate.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/InsertGeneratedIdentifierDelegate.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+package org.hibernate.id.insert;
+
+import org.hibernate.engine.SessionImplementor;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * Responsible for handling delegation relating to variants in how
+ * insert-generated-identifier generator strategies dictate processing:<ul>
+ * <li>building the sql insert statement
+ * <li>determination of the generated identifier value
+ * </ul>
+ *
+ * @author Steve Ebersole
+ */
+public interface InsertGeneratedIdentifierDelegate {
+
+	/**
+	 * Build a {@link org.hibernate.sql.Insert} specific to the delegate's mode
+	 * of handling generated key values.
+	 *
+	 * @return The insert object.
+	 */
+	public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert();
+
+	/**
+	 * Perform the indicated insert SQL statement and determine the identifier value
+	 * generated.
+	 *
+	 * @param insertSQL
+	 * @param session
+	 * @param binder
+	 * @return The generated identifier value.
+	 */
+	public Serializable performInsert(String insertSQL, SessionImplementor session, Binder binder);
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/InsertSelectIdentityInsert.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/InsertSelectIdentityInsert.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/insert/InsertSelectIdentityInsert.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+package org.hibernate.id.insert;
+
+import org.hibernate.dialect.Dialect;
+
+/**
+ * Specialized IdentifierGeneratingInsert which appends the database
+ * specific clause which signifies to return generated IDENTITY values
+ * to the end of the insert statement.
+ * 
+ * @author Steve Ebersole
+ */
+public class InsertSelectIdentityInsert extends IdentifierGeneratingInsert {
+	public InsertSelectIdentityInsert(Dialect dialect) {
+		super( dialect );
+	}
+
+	public String toStatementString() {
+		return getDialect().appendIdentitySelectToInsert( super.toStatementString() );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/id/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/id/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/id/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package contains internal implementation classes for the
+	main API interfaces.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/id/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/AbstractQueryImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/AbstractQueryImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/AbstractQueryImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,878 @@
+//$Id: AbstractQueryImpl.java 10856 2006-11-21 21:57:42Z steve.ebersole at jboss.com $
+package org.hibernate.impl;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.CacheMode;
+import org.hibernate.FlushMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.NonUniqueResultException;
+import org.hibernate.PropertyNotFoundException;
+import org.hibernate.Query;
+import org.hibernate.QueryException;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.RowSelection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.engine.query.ParameterMetadata;
+import org.hibernate.hql.classic.ParserHelper;
+import org.hibernate.property.Getter;
+import org.hibernate.proxy.HibernateProxyHelper;
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.type.SerializableType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.MarkerObject;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Abstract implementation of the Query interface.
+ *
+ * @author Gavin King, Max Andersen
+ */
+public abstract class AbstractQueryImpl implements Query {
+
+	private static final Object UNSET_PARAMETER = new MarkerObject("<unset parameter>");
+	private static final Object UNSET_TYPE = new MarkerObject("<unset type>");
+
+	private final String queryString;
+	protected final SessionImplementor session;
+	protected final ParameterMetadata parameterMetadata;
+
+	// parameter bind values...
+	private List values = new ArrayList(4);
+	private List types = new ArrayList(4);
+	private Map namedParameters = new HashMap(4);
+	private Map namedParameterLists = new HashMap(4);
+
+	private Object optionalObject;
+	private Serializable optionalId;
+	private String optionalEntityName;
+
+	private RowSelection selection;
+	private boolean cacheable;
+	private String cacheRegion;
+	private String comment;
+	private FlushMode flushMode;
+	private CacheMode cacheMode;
+	private FlushMode sessionFlushMode;
+	private CacheMode sessionCacheMode;
+	private Serializable collectionKey;
+	private boolean readOnly;
+	private ResultTransformer resultTransformer;
+
+	public AbstractQueryImpl(
+			String queryString,
+	        FlushMode flushMode,
+	        SessionImplementor session,
+	        ParameterMetadata parameterMetadata) {
+		this.session = session;
+		this.queryString = queryString;
+		this.selection = new RowSelection();
+		this.flushMode = flushMode;
+		this.cacheMode = null;
+		this.parameterMetadata = parameterMetadata;
+	}
+
+	public String toString() {
+		return StringHelper.unqualify( getClass().getName() ) + '(' + queryString + ')';
+	}
+
+	public final String getQueryString() {
+		return queryString;
+	}
+
+	//TODO: maybe call it getRowSelection() ?
+	public RowSelection getSelection() {
+		return selection;
+	}
+	
+	public Query setFlushMode(FlushMode flushMode) {
+		this.flushMode = flushMode;
+		return this;
+	}
+	
+	public Query setCacheMode(CacheMode cacheMode) {
+		this.cacheMode = cacheMode;
+		return this;
+	}
+
+	public Query setCacheable(boolean cacheable) {
+		this.cacheable = cacheable;
+		return this;
+	}
+
+	public Query setCacheRegion(String cacheRegion) {
+		if (cacheRegion != null)
+			this.cacheRegion = cacheRegion.trim();
+		return this;
+	}
+
+	public Query setComment(String comment) {
+		this.comment = comment;
+		return this;
+	}
+
+	public Query setFirstResult(int firstResult) {
+		selection.setFirstRow( new Integer(firstResult) );
+		return this;
+	}
+
+	public Query setMaxResults(int maxResults) {
+		selection.setMaxRows( new Integer(maxResults) );
+		return this;
+	}
+
+	public Query setTimeout(int timeout) {
+		selection.setTimeout( new Integer(timeout) );
+		return this;
+	}
+	public Query setFetchSize(int fetchSize) {
+		selection.setFetchSize( new Integer(fetchSize) );
+		return this;
+	}
+
+	public Type[] getReturnTypes() throws HibernateException {
+		return session.getFactory().getReturnTypes( queryString );
+	}
+
+	public String[] getReturnAliases() throws HibernateException {
+		return session.getFactory().getReturnAliases( queryString );
+	}
+
+	public Query setCollectionKey(Serializable collectionKey) {
+		this.collectionKey = collectionKey;
+		return this;
+	}
+
+	public boolean isReadOnly() {
+		return readOnly;
+	}
+
+	public Query setReadOnly(boolean readOnly) {
+		this.readOnly = readOnly;
+		return this;
+	}
+
+	public Query setResultTransformer(ResultTransformer transformer) {
+		this.resultTransformer = transformer;
+		return this;
+	}
+	
+	public void setOptionalEntityName(String optionalEntityName) {
+		this.optionalEntityName = optionalEntityName;
+	}
+
+	public void setOptionalId(Serializable optionalId) {
+		this.optionalId = optionalId;
+	}
+
+	public void setOptionalObject(Object optionalObject) {
+		this.optionalObject = optionalObject;
+	}
+
+	SessionImplementor getSession() {
+		return session;
+	}
+
+	protected abstract Map getLockModes();
+
+
+	// Parameter handling code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Returns a shallow copy of the named parameter value map.
+	 *
+	 * @return Shallow copy of the named parameter value map
+	 */
+	protected Map getNamedParams() {
+		return new HashMap( namedParameters );
+	}
+
+	/**
+	 * Returns an array representing all named parameter names encountered
+	 * during (intial) parsing of the query.
+	 * <p/>
+	 * Note <i>initial</i> here means different things depending on whether
+	 * this is a native-sql query or an HQL/filter query.  For native-sql, a
+	 * precursory inspection of the query string is performed specifically to
+	 * locate defined parameters.  For HQL/filter queries, this is the
+	 * information returned from the query-translator.  This distinction
+	 * holds true for all parameter metadata exposed here.
+	 *
+	 * @return Array of named parameter names.
+	 * @throws HibernateException
+	 */
+	public String[] getNamedParameters() throws HibernateException {
+		return ArrayHelper.toStringArray( parameterMetadata.getNamedParameterNames() );
+	}
+
+	/**
+	 * Does this query contain named parameters?
+	 *
+	 * @return True if the query was found to contain named parameters; false
+	 * otherwise;
+	 */
+	public boolean hasNamedParameters() {
+		return parameterMetadata.getNamedParameterNames().size() > 0;
+	}
+
+	/**
+	 * Retreive the value map for any named parameter lists (i.e., for
+	 * auto-expansion) bound to this query.
+	 *
+	 * @return The parameter list value map.
+	 */
+	protected Map getNamedParameterLists() {
+		return namedParameterLists;
+	}
+
+	/**
+	 * Retreives the list of parameter values bound to this query for
+	 * ordinal parameters.
+	 *
+	 * @return The ordinal parameter values.
+	 */
+	protected List getValues() {
+		return values;
+	}
+
+	/**
+	 * Retreives the list of parameter {@link Type type}s bound to this query for
+	 * ordinal parameters.
+	 *
+	 * @return The ordinal parameter types.
+	 */
+	protected List getTypes() {
+		return types;
+	}
+
+	/**
+	 * Perform parameter validation.  Used prior to executing the encapsulated
+	 * query.
+	 *
+	 * @throws QueryException
+	 */
+	protected void verifyParameters() throws QueryException {
+		verifyParameters(false);
+	}
+
+	/**
+	 * Perform parameter validation.  Used prior to executing the encapsulated
+	 * query.
+	 *
+	 * @param reserveFirstParameter if true, the first ? will not be verified since
+	 * its needed for e.g. callable statements returning a out parameter
+	 * @throws HibernateException
+	 */
+	protected void verifyParameters(boolean reserveFirstParameter) throws HibernateException {
+		if ( parameterMetadata.getNamedParameterNames().size() != namedParameters.size() + namedParameterLists.size() ) {
+			Set missingParams = new HashSet( parameterMetadata.getNamedParameterNames() );
+			missingParams.removeAll( namedParameterLists.keySet() );
+			missingParams.removeAll( namedParameters.keySet() );
+			throw new QueryException( "Not all named parameters have been set: " + missingParams, getQueryString() );
+		}
+
+		int positionalValueSpan = 0;
+		for ( int i = 0; i < values.size(); i++ ) {
+			Object object = types.get( i );
+			if( values.get( i ) == UNSET_PARAMETER || object == UNSET_TYPE ) {
+				if ( reserveFirstParameter && i==0 ) {
+					continue;
+				}
+				else {
+					throw new QueryException( "Unset positional parameter at position: " + i, getQueryString() );
+				}
+			}
+			positionalValueSpan += ( (Type) object ).getColumnSpan( session.getFactory() );
+		}
+
+		if ( parameterMetadata.getOrdinalParameterCount() != positionalValueSpan ) {
+			if ( reserveFirstParameter && parameterMetadata.getOrdinalParameterCount() - 1 != positionalValueSpan ) {
+				throw new QueryException(
+				 		"Expected positional parameter count: " +
+				 		(parameterMetadata.getOrdinalParameterCount()-1) +
+				 		", actual parameters: " +
+				 		values,
+				 		getQueryString()
+				 	);
+			}
+			else if ( !reserveFirstParameter ) {
+				throw new QueryException(
+				 		"Expected positional parameter count: " +
+				 		parameterMetadata.getOrdinalParameterCount() +
+				 		", actual parameters: " +
+				 		values,
+				 		getQueryString()
+				 	);
+			}
+		}
+	}
+
+	public Query setParameter(int position, Object val, Type type) {
+		if ( parameterMetadata.getOrdinalParameterCount() == 0 ) {
+			throw new IllegalArgumentException("No positional parameters in query: " + getQueryString() );
+		}
+		if ( position < 0 || position > parameterMetadata.getOrdinalParameterCount() - 1 ) {
+			throw new IllegalArgumentException("Positional parameter does not exist: " + position + " in query: " + getQueryString() );
+		}
+		int size = values.size();
+		if ( position < size ) {
+			values.set( position, val );
+			types.set( position, type );
+		}
+		else {
+			// prepend value and type list with null for any positions before the wanted position.
+			for ( int i = 0; i < position - size; i++ ) {
+				values.add( UNSET_PARAMETER );
+				types.add( UNSET_TYPE );
+			}
+			values.add( val );
+			types.add( type );
+		}
+		return this;
+	}
+
+	public Query setParameter(String name, Object val, Type type) {
+		if ( !parameterMetadata.getNamedParameterNames().contains( name ) ) {
+			throw new IllegalArgumentException("Parameter " + name + " does not exist as a named parameter in [" + getQueryString() + "]");
+		}
+		else {
+			 namedParameters.put( name, new TypedValue( type, val, session.getEntityMode() ) );
+			 return this;
+		}
+	}
+
+	public Query setParameter(int position, Object val) throws HibernateException {
+		if (val == null) {
+			setParameter( position, val, Hibernate.SERIALIZABLE );
+		}
+		else {
+			setParameter( position, val, determineType( position, val ) );
+		}
+		return this;
+	}
+
+	public Query setParameter(String name, Object val) throws HibernateException {
+		if (val == null) {
+			Type type = parameterMetadata.getNamedParameterExpectedType( name );
+			if ( type == null ) {
+				type = Hibernate.SERIALIZABLE;
+			}
+			setParameter( name, val, type );
+		}
+		else {
+			setParameter( name, val, determineType( name, val ) );
+		}
+		return this;
+	}
+
+	protected Type determineType(int paramPosition, Object paramValue, Type defaultType) {
+		Type type = parameterMetadata.getOrdinalParameterExpectedType( paramPosition + 1 );
+		if ( type == null ) {
+			type = defaultType;
+		}
+		return type;
+	}
+
+	protected Type determineType(int paramPosition, Object paramValue) throws HibernateException {
+		Type type = parameterMetadata.getOrdinalParameterExpectedType( paramPosition + 1 );
+		if ( type == null ) {
+			type = guessType( paramValue );
+		}
+		return type;
+	}
+
+	protected Type determineType(String paramName, Object paramValue, Type defaultType) {
+		Type type = parameterMetadata.getNamedParameterExpectedType( paramName );
+		if ( type == null ) {
+			type = defaultType;
+		}
+		return type;
+	}
+
+	protected Type determineType(String paramName, Object paramValue) throws HibernateException {
+		Type type = parameterMetadata.getNamedParameterExpectedType( paramName );
+		if ( type == null ) {
+			type = guessType( paramValue );
+		}
+		return type;
+	}
+
+	protected Type determineType(String paramName, Class clazz) throws HibernateException {
+		Type type = parameterMetadata.getNamedParameterExpectedType( paramName );
+		if ( type == null ) {
+			type = guessType( clazz );
+		}
+		return type;
+	}
+
+	private Type guessType(Object param) throws HibernateException {
+		Class clazz = HibernateProxyHelper.getClassWithoutInitializingProxy( param );
+		return guessType( clazz );
+	}
+
+	private Type guessType(Class clazz) throws HibernateException {
+		String typename = clazz.getName();
+		Type type = TypeFactory.heuristicType(typename);
+		boolean serializable = type!=null && type instanceof SerializableType;
+		if (type==null || serializable) {
+			try {
+				session.getFactory().getEntityPersister( clazz.getName() );
+			}
+			catch (MappingException me) {
+				if (serializable) {
+					return type;
+				}
+				else {
+					throw new HibernateException("Could not determine a type for class: " + typename);
+				}
+			}
+			return Hibernate.entity(clazz);
+		}
+		else {
+			return type;
+		}
+	}
+
+	public Query setString(int position, String val) {
+		setParameter(position, val, Hibernate.STRING);
+		return this;
+	}
+
+	public Query setCharacter(int position, char val) {
+		setParameter(position, new Character(val), Hibernate.CHARACTER);
+		return this;
+	}
+
+	public Query setBoolean(int position, boolean val) {
+		Boolean valueToUse = val ? Boolean.TRUE : Boolean.FALSE;
+		Type typeToUse = determineType( position, valueToUse, Hibernate.BOOLEAN );
+		setParameter( position, valueToUse, typeToUse );
+		return this;
+	}
+
+	public Query setByte(int position, byte val) {
+		setParameter(position, new Byte(val), Hibernate.BYTE);
+		return this;
+	}
+
+	public Query setShort(int position, short val) {
+		setParameter(position, new Short(val), Hibernate.SHORT);
+		return this;
+	}
+
+	public Query setInteger(int position, int val) {
+		setParameter(position, new Integer(val), Hibernate.INTEGER);
+		return this;
+	}
+
+	public Query setLong(int position, long val) {
+		setParameter(position, new Long(val), Hibernate.LONG);
+		return this;
+	}
+
+	public Query setFloat(int position, float val) {
+		setParameter(position, new Float(val), Hibernate.FLOAT);
+		return this;
+	}
+
+	public Query setDouble(int position, double val) {
+		setParameter(position, new Double(val), Hibernate.DOUBLE);
+		return this;
+	}
+
+	public Query setBinary(int position, byte[] val) {
+		setParameter(position, val, Hibernate.BINARY);
+		return this;
+	}
+
+	public Query setText(int position, String val) {
+		setParameter(position, val, Hibernate.TEXT);
+		return this;
+	}
+
+	public Query setSerializable(int position, Serializable val) {
+		setParameter(position, val, Hibernate.SERIALIZABLE);
+		return this;
+	}
+
+	public Query setDate(int position, Date date) {
+		setParameter(position, date, Hibernate.DATE);
+		return this;
+	}
+
+	public Query setTime(int position, Date date) {
+		setParameter(position, date, Hibernate.TIME);
+		return this;
+	}
+
+	public Query setTimestamp(int position, Date date) {
+		setParameter(position, date, Hibernate.TIMESTAMP);
+		return this;
+	}
+
+	public Query setEntity(int position, Object val) {
+		setParameter( position, val, Hibernate.entity( resolveEntityName( val ) ) );
+		return this;
+	}
+
+	private String resolveEntityName(Object val) {
+		if ( val == null ) {
+			throw new IllegalArgumentException( "entity for parameter binding cannot be null" );
+		}
+		return session.bestGuessEntityName( val );
+	}
+
+	public Query setLocale(int position, Locale locale) {
+		setParameter(position, locale, Hibernate.LOCALE);
+		return this;
+	}
+
+	public Query setCalendar(int position, Calendar calendar) {
+		setParameter(position, calendar, Hibernate.CALENDAR);
+		return this;
+	}
+
+	public Query setCalendarDate(int position, Calendar calendar) {
+		setParameter(position, calendar, Hibernate.CALENDAR_DATE);
+		return this;
+	}
+
+	public Query setBinary(String name, byte[] val) {
+		setParameter(name, val, Hibernate.BINARY);
+		return this;
+	}
+
+	public Query setText(String name, String val) {
+		setParameter(name, val, Hibernate.TEXT);
+		return this;
+	}
+
+	public Query setBoolean(String name, boolean val) {
+		Boolean valueToUse = val ? Boolean.TRUE : Boolean.FALSE;
+		Type typeToUse = determineType( name, valueToUse, Hibernate.BOOLEAN );
+		setParameter( name, valueToUse, typeToUse );
+		return this;
+	}
+
+	public Query setByte(String name, byte val) {
+		setParameter(name, new Byte(val), Hibernate.BYTE);
+		return this;
+	}
+
+	public Query setCharacter(String name, char val) {
+		setParameter(name, new Character(val), Hibernate.CHARACTER);
+		return this;
+	}
+
+	public Query setDate(String name, Date date) {
+		setParameter(name, date, Hibernate.DATE);
+		return this;
+	}
+
+	public Query setDouble(String name, double val) {
+		setParameter(name, new Double(val), Hibernate.DOUBLE);
+		return this;
+	}
+
+	public Query setEntity(String name, Object val) {
+		setParameter( name, val, Hibernate.entity( resolveEntityName( val ) ) );
+		return this;
+	}
+
+	public Query setFloat(String name, float val) {
+		setParameter(name, new Float(val), Hibernate.FLOAT);
+		return this;
+	}
+
+	public Query setInteger(String name, int val) {
+		setParameter(name, new Integer(val), Hibernate.INTEGER);
+		return this;
+	}
+
+	public Query setLocale(String name, Locale locale) {
+		setParameter(name, locale, Hibernate.LOCALE);
+		return this;
+	}
+
+	public Query setCalendar(String name, Calendar calendar) {
+		setParameter(name, calendar, Hibernate.CALENDAR);
+		return this;
+	}
+
+	public Query setCalendarDate(String name, Calendar calendar) {
+		setParameter(name, calendar, Hibernate.CALENDAR_DATE);
+		return this;
+	}
+
+	public Query setLong(String name, long val) {
+		setParameter(name, new Long(val), Hibernate.LONG);
+		return this;
+	}
+
+	public Query setSerializable(String name, Serializable val) {
+		setParameter(name, val, Hibernate.SERIALIZABLE);
+		return this;
+	}
+
+	public Query setShort(String name, short val) {
+		setParameter(name, new Short(val), Hibernate.SHORT);
+		return this;
+	}
+
+	public Query setString(String name, String val) {
+		setParameter(name, val, Hibernate.STRING);
+		return this;
+	}
+
+	public Query setTime(String name, Date date) {
+		setParameter(name, date, Hibernate.TIME);
+		return this;
+	}
+
+	public Query setTimestamp(String name, Date date) {
+		setParameter(name, date, Hibernate.TIMESTAMP);
+		return this;
+	}
+
+	public Query setBigDecimal(int position, BigDecimal number) {
+		setParameter(position, number, Hibernate.BIG_DECIMAL);
+		return this;
+	}
+
+	public Query setBigDecimal(String name, BigDecimal number) {
+		setParameter(name, number, Hibernate.BIG_DECIMAL);
+		return this;
+	}
+
+	public Query setBigInteger(int position, BigInteger number) {
+		setParameter(position, number, Hibernate.BIG_INTEGER);
+		return this;
+	}
+
+	public Query setBigInteger(String name, BigInteger number) {
+		setParameter(name, number, Hibernate.BIG_INTEGER);
+		return this;
+	}
+
+	public Query setParameterList(String name, Collection vals, Type type) throws HibernateException {
+		if ( !parameterMetadata.getNamedParameterNames().contains( name ) ) {
+			throw new IllegalArgumentException("Parameter " + name + " does not exist as a named parameter in [" + getQueryString() + "]");
+		}
+		namedParameterLists.put( name, new TypedValue( type, vals, session.getEntityMode() ) );
+		return this;
+	}
+	
+	/**
+	 * Warning: adds new parameters to the argument by side-effect, as well as
+	 * mutating the query string!
+	 */
+	protected String expandParameterLists(Map namedParamsCopy) {
+		String query = this.queryString;
+		Iterator iter = namedParameterLists.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			query = expandParameterList( query, (String) me.getKey(), (TypedValue) me.getValue(), namedParamsCopy );
+		}
+		return query;
+	}
+
+	/**
+	 * Warning: adds new parameters to the argument by side-effect, as well as
+	 * mutating the query string!
+	 */
+	private String expandParameterList(String query, String name, TypedValue typedList, Map namedParamsCopy) {
+		Collection vals = (Collection) typedList.getValue();
+		Type type = typedList.getType();
+		if ( vals.size() == 1 ) {
+			// short-circuit for performance...
+			namedParamsCopy.put( name, new TypedValue( type, vals.iterator().next(), session.getEntityMode() ) );
+			return query;
+		}
+
+		StringBuffer list = new StringBuffer( 16 );
+		Iterator iter = vals.iterator();
+		int i = 0;
+		boolean isJpaPositionalParam = parameterMetadata.getNamedParameterDescriptor( name ).isJpaStyle();
+		while ( iter.hasNext() ) {
+			String alias = ( isJpaPositionalParam ? 'x' + name : name ) + i++ + '_';
+			namedParamsCopy.put( alias, new TypedValue( type, iter.next(), session.getEntityMode() ) );
+			list.append( ParserHelper.HQL_VARIABLE_PREFIX ).append( alias );
+			if ( iter.hasNext() ) {
+				list.append( ", " );
+			}
+		}
+		String paramPrefix = isJpaPositionalParam ? "?" : ParserHelper.HQL_VARIABLE_PREFIX;
+		return StringHelper.replace( query, paramPrefix + name, list.toString(), true );
+	}
+
+	public Query setParameterList(String name, Collection vals) throws HibernateException {
+		if ( vals == null ) {
+			throw new QueryException( "Collection must be not null!" );
+		}
+
+		if( vals.size() == 0 ) {
+			setParameterList( name, vals, null );
+		}
+		else {
+			setParameterList(name, vals, determineType( name, vals.iterator().next() ) );
+		}
+
+		return this;
+	}
+
+	public Query setParameterList(String name, Object[] vals, Type type) throws HibernateException {
+		return setParameterList( name, Arrays.asList(vals), type );
+	}
+
+	public Query setParameterList(String name, Object[] vals) throws HibernateException {
+		return setParameterList( name, Arrays.asList(vals) );
+	}
+
+	public Query setProperties(Map map) throws HibernateException {
+		String[] params = getNamedParameters();
+		for (int i = 0; i < params.length; i++) {
+			String namedParam = params[i];
+				final Object object = map.get(namedParam);
+				if(object==null) {
+					continue;
+				}
+				Class retType = object.getClass();
+				if ( Collection.class.isAssignableFrom( retType ) ) {
+					setParameterList( namedParam, ( Collection ) object );
+				}
+				else if ( retType.isArray() ) {
+					setParameterList( namedParam, ( Object[] ) object );
+				}
+				else {
+					setParameter( namedParam, object, determineType( namedParam, retType ) );
+				}
+
+			
+		}
+		return this;				
+	}
+	
+	public Query setProperties(Object bean) throws HibernateException {
+		Class clazz = bean.getClass();
+		String[] params = getNamedParameters();
+		for (int i = 0; i < params.length; i++) {
+			String namedParam = params[i];
+			try {
+				Getter getter = ReflectHelper.getGetter( clazz, namedParam );
+				Class retType = getter.getReturnType();
+				final Object object = getter.get( bean );
+				if ( Collection.class.isAssignableFrom( retType ) ) {
+					setParameterList( namedParam, ( Collection ) object );
+				}
+				else if ( retType.isArray() ) {
+				 	setParameterList( namedParam, ( Object[] ) object );
+				}
+				else {
+					setParameter( namedParam, object, determineType( namedParam, retType ) );
+				}
+			}
+			catch (PropertyNotFoundException pnfe) {
+				// ignore
+			}
+		}
+		return this;
+	}
+
+	public Query setParameters(Object[] values, Type[] types) {
+		this.values = Arrays.asList(values);
+		this.types = Arrays.asList(types);
+		return this;
+	}
+
+
+	// Execution methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public Object uniqueResult() throws HibernateException {
+		return uniqueElement( list() );
+	}
+
+	static Object uniqueElement(List list) throws NonUniqueResultException {
+		int size = list.size();
+		if (size==0) return null;
+		Object first = list.get(0);
+		for ( int i=1; i<size; i++ ) {
+			if ( list.get(i)!=first ) {
+				throw new NonUniqueResultException( list.size() );
+			}
+		}
+		return first;
+	}
+
+	protected RowSelection getRowSelection() {
+		return selection;
+	}
+
+	public Type[] typeArray() {
+		return ArrayHelper.toTypeArray( getTypes() );
+	}
+	
+	public Object[] valueArray() {
+		return getValues().toArray();
+	}
+
+	public QueryParameters getQueryParameters(Map namedParams) {
+		return new QueryParameters(
+				typeArray(),
+				valueArray(),
+				namedParams,
+				getLockModes(),
+				getSelection(),
+				readOnly,
+				cacheable,
+				cacheRegion,
+				comment,
+				collectionKey == null ? null : new Serializable[] { collectionKey },
+				optionalObject,
+				optionalEntityName,
+				optionalId,
+				resultTransformer
+		);
+	}
+	
+	protected void before() {
+		if ( flushMode!=null ) {
+			sessionFlushMode = getSession().getFlushMode();
+			getSession().setFlushMode(flushMode);
+		}
+		if ( cacheMode!=null ) {
+			sessionCacheMode = getSession().getCacheMode();
+			getSession().setCacheMode(cacheMode);
+		}
+	}
+	
+	protected void after() {
+		if (sessionFlushMode!=null) {
+			getSession().setFlushMode(sessionFlushMode);
+			sessionFlushMode = null;
+		}
+		if (sessionCacheMode!=null) {
+			getSession().setCacheMode(sessionCacheMode);
+			sessionCacheMode = null;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/AbstractScrollableResults.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/AbstractScrollableResults.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/AbstractScrollableResults.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,254 @@
+//$Id: AbstractScrollableResults.java 7469 2005-07-14 13:12:19Z steveebersole $
+package org.hibernate.impl;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.ScrollableResults;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.hql.HolderInstantiator;
+import org.hibernate.loader.Loader;
+import org.hibernate.type.Type;
+
+/**
+ * Implementation of the <tt>ScrollableResults</tt> interface
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractScrollableResults implements ScrollableResults {
+
+	private final ResultSet resultSet;
+	private final PreparedStatement ps;
+	private final SessionImplementor session;
+	private final Loader loader;
+	private final QueryParameters queryParameters;
+	private final Type[] types;
+	private HolderInstantiator holderInstantiator;
+
+	public AbstractScrollableResults(
+	        ResultSet rs,
+	        PreparedStatement ps,
+	        SessionImplementor sess,
+			Loader loader,
+			QueryParameters queryParameters,
+	        Type[] types,
+	        HolderInstantiator holderInstantiator) throws MappingException {
+		this.resultSet=rs;
+		this.ps=ps;
+		this.session = sess;
+		this.loader = loader;
+		this.queryParameters = queryParameters;
+		this.types = types;
+		this.holderInstantiator = holderInstantiator!=null && holderInstantiator.isRequired()
+		        ? holderInstantiator 
+		        : null;
+	}
+
+	protected abstract Object[] getCurrentRow();
+
+	protected ResultSet getResultSet() {
+		return resultSet;
+	}
+
+	protected PreparedStatement getPs() {
+		return ps;
+	}
+
+	protected SessionImplementor getSession() {
+		return session;
+	}
+
+	protected Loader getLoader() {
+		return loader;
+	}
+
+	protected QueryParameters getQueryParameters() {
+		return queryParameters;
+	}
+
+	protected Type[] getTypes() {
+		return types;
+	}
+
+	protected HolderInstantiator getHolderInstantiator() {
+		return holderInstantiator;
+	}
+
+	public final void close() throws HibernateException {
+		try {
+			// not absolutely necessary, but does help with aggressive release
+			session.getBatcher().closeQueryStatement(ps, resultSet);
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					session.getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not close results"
+				);
+		}
+	}
+
+	public final Object[] get() throws HibernateException {
+		return getCurrentRow();
+	}
+
+	public final Object get(int col) throws HibernateException {
+		return getCurrentRow()[col];
+	}
+
+	/**
+	 * Check that the requested type is compatible with the result type, and
+	 * return the column value.  This version makes sure the the classes
+	 * are identical.
+	 *
+	 * @param col the column
+	 * @param returnType a "final" type
+	 */
+	protected final Object getFinal(int col, Type returnType) throws HibernateException {
+		if ( holderInstantiator!=null ) {
+			throw new HibernateException("query specifies a holder class");
+		}
+		
+		if ( returnType.getReturnedClass()==types[col].getReturnedClass() ) {
+			return get(col);
+		}
+		else {
+			return throwInvalidColumnTypeException(col, types[col], returnType);
+		}
+	}
+
+	/**
+	 * Check that the requested type is compatible with the result type, and
+	 * return the column value.  This version makes sure the the classes
+	 * are "assignable".
+	 *
+	 * @param col the column
+	 * @param returnType any type
+	 */
+	protected final Object getNonFinal(int col, Type returnType) throws HibernateException {
+		if ( holderInstantiator!=null ) {
+			throw new HibernateException("query specifies a holder class");
+		}
+		
+		if ( returnType.getReturnedClass().isAssignableFrom( types[col].getReturnedClass() ) ) {
+			return get(col);
+		}
+		else {
+			return throwInvalidColumnTypeException(col, types[col], returnType);
+		}
+	}
+
+	public final BigDecimal getBigDecimal(int col) throws HibernateException {
+		return (BigDecimal) getFinal(col, Hibernate.BIG_DECIMAL);
+	}
+
+	public final BigInteger getBigInteger(int col) throws HibernateException {
+		return (BigInteger) getFinal(col, Hibernate.BIG_INTEGER);
+	}
+
+	public final byte[] getBinary(int col) throws HibernateException {
+		return (byte[]) getFinal(col, Hibernate.BINARY);
+	}
+
+	public final String getText(int col) throws HibernateException {
+		return (String) getFinal(col, Hibernate.TEXT);
+	}
+
+	public final Blob getBlob(int col) throws HibernateException {
+		return (Blob) getNonFinal(col, Hibernate.BLOB);
+	}
+
+	public final Clob getClob(int col) throws HibernateException {
+		return (Clob) getNonFinal(col, Hibernate.CLOB);
+	}
+
+	public final Boolean getBoolean(int col) throws HibernateException {
+		return (Boolean) getFinal(col, Hibernate.BOOLEAN);
+	}
+
+	public final Byte getByte(int col) throws HibernateException {
+		return (Byte) getFinal(col, Hibernate.BYTE);
+	}
+
+	public final Character getCharacter(int col) throws HibernateException {
+		return (Character) getFinal(col, Hibernate.CHARACTER);
+	}
+
+	public final Date getDate(int col) throws HibernateException {
+		return (Date) getNonFinal(col, Hibernate.TIMESTAMP);
+	}
+
+	public final Calendar getCalendar(int col) throws HibernateException {
+		return (Calendar) getNonFinal(col, Hibernate.CALENDAR);
+	}
+
+	public final Double getDouble(int col) throws HibernateException {
+		return (Double) getFinal(col, Hibernate.DOUBLE);
+	}
+
+	public final Float getFloat(int col) throws HibernateException {
+		return (Float) getFinal(col, Hibernate.FLOAT);
+	}
+
+	public final Integer getInteger(int col) throws HibernateException {
+		return (Integer) getFinal(col, Hibernate.INTEGER);
+	}
+
+	public final Long getLong(int col) throws HibernateException {
+		return (Long) getFinal(col, Hibernate.LONG);
+	}
+
+	public final Short getShort(int col) throws HibernateException {
+		return (Short) getFinal(col, Hibernate.SHORT);
+	}
+
+	public final String getString(int col) throws HibernateException {
+		return (String) getFinal(col, Hibernate.STRING);
+	}
+
+	public final Locale getLocale(int col) throws HibernateException {
+		return (Locale) getFinal(col, Hibernate.LOCALE);
+	}
+
+	/*public final Currency getCurrency(int col) throws HibernateException {
+		return (Currency) get(col);
+	}*/
+
+	public final TimeZone getTimeZone(int col) throws HibernateException {
+		return (TimeZone) getNonFinal(col, Hibernate.TIMEZONE);
+	}
+
+	public final Type getType(int i) {
+		return types[i];
+	}
+
+	private Object throwInvalidColumnTypeException(
+	        int i,
+	        Type type,
+	        Type returnType) throws HibernateException {
+		throw new HibernateException( 
+				"incompatible column types: " + 
+				type.getName() + 
+				", " + 
+				returnType.getName() 
+		);
+	}
+
+	protected void afterScrollOperation() {
+		session.afterScrollOperation();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/AbstractSessionImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/AbstractSessionImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/AbstractSessionImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,150 @@
+//$Id: AbstractSessionImpl.java 10018 2006-06-15 05:21:06Z steve.ebersole at jboss.com $
+package org.hibernate.impl;
+
+import org.hibernate.MappingException;
+import org.hibernate.Query;
+import org.hibernate.SQLQuery;
+import org.hibernate.HibernateException;
+import org.hibernate.ScrollableResults;
+import org.hibernate.SessionException;
+import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
+import org.hibernate.engine.NamedQueryDefinition;
+import org.hibernate.engine.NamedSQLQueryDefinition;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.query.HQLQueryPlan;
+import org.hibernate.engine.query.NativeSQLQueryPlan;
+
+import java.util.List;
+
+/**
+ * Functionality common to stateless and stateful sessions
+ * 
+ * @author Gavin King
+ */
+public abstract class AbstractSessionImpl implements SessionImplementor {
+
+	protected transient SessionFactoryImpl factory;
+	private boolean closed = false;
+
+	protected AbstractSessionImpl(SessionFactoryImpl factory) {
+		this.factory = factory;
+	}
+
+	public SessionFactoryImplementor getFactory() {
+		return factory;
+	}
+
+	public boolean isClosed() {
+		return closed;
+	}
+
+	protected void setClosed() {
+		closed = true;
+	}
+
+	protected void errorIfClosed() {
+		if ( closed ) {
+			throw new SessionException( "Session is closed!" );
+		}
+	}
+
+	public Query getNamedQuery(String queryName) throws MappingException {
+		errorIfClosed();
+		NamedQueryDefinition nqd = factory.getNamedQuery( queryName );
+		final Query query;
+		if ( nqd != null ) {
+			String queryString = nqd.getQueryString();
+			query = new QueryImpl(
+					queryString,
+			        nqd.getFlushMode(),
+			        this,
+			        getHQLQueryPlan( queryString, false ).getParameterMetadata()
+			);
+			query.setComment( "named HQL query " + queryName );
+		}
+		else {
+			NamedSQLQueryDefinition nsqlqd = factory.getNamedSQLQuery( queryName );
+			if ( nsqlqd==null ) {
+				throw new MappingException( "Named query not known: " + queryName );
+			}
+			query = new SQLQueryImpl(
+					nsqlqd,
+			        this,
+			        factory.getQueryPlanCache().getSQLParameterMetadata( nsqlqd.getQueryString() )
+			);
+			query.setComment( "named native SQL query " + queryName );
+			nqd = nsqlqd;
+		}
+		initQuery( query, nqd );
+		return query;
+	}
+
+	public Query getNamedSQLQuery(String queryName) throws MappingException {
+		errorIfClosed();
+		NamedSQLQueryDefinition nsqlqd = factory.getNamedSQLQuery( queryName );
+		if ( nsqlqd==null ) {
+			throw new MappingException( "Named SQL query not known: " + queryName );
+		}
+		Query query = new SQLQueryImpl(
+				nsqlqd,
+		        this,
+		        factory.getQueryPlanCache().getSQLParameterMetadata( nsqlqd.getQueryString() )
+		);
+		query.setComment( "named native SQL query " + queryName );
+		initQuery( query, nsqlqd );
+		return query;
+	}
+
+	private void initQuery(Query query, NamedQueryDefinition nqd) {
+		query.setCacheable( nqd.isCacheable() );
+		query.setCacheRegion( nqd.getCacheRegion() );
+		if ( nqd.getTimeout()!=null ) query.setTimeout( nqd.getTimeout().intValue() );
+		if ( nqd.getFetchSize()!=null ) query.setFetchSize( nqd.getFetchSize().intValue() );
+		if ( nqd.getCacheMode() != null ) query.setCacheMode( nqd.getCacheMode() );
+		query.setReadOnly( nqd.isReadOnly() );
+		if ( nqd.getComment() != null ) query.setComment( nqd.getComment() );
+	}
+
+	public Query createQuery(String queryString) {
+		errorIfClosed();
+		QueryImpl query = new QueryImpl(
+				queryString,
+		        this,
+		        getHQLQueryPlan( queryString, false ).getParameterMetadata()
+		);
+		query.setComment( queryString );
+		return query;
+	}
+
+	public SQLQuery createSQLQuery(String sql) {
+		errorIfClosed();
+		SQLQueryImpl query = new SQLQueryImpl(
+				sql,
+		        this,
+		        factory.getQueryPlanCache().getSQLParameterMetadata( sql )
+		);
+		query.setComment( "dynamic native SQL query" );
+		return query;
+	}
+
+	protected HQLQueryPlan getHQLQueryPlan(String query, boolean shallow) throws HibernateException {
+		return factory.getQueryPlanCache().getHQLQueryPlan( query, shallow, getEnabledFilters() );
+	}
+
+	protected NativeSQLQueryPlan getNativeSQLQueryPlan(NativeSQLQuerySpecification spec) throws HibernateException {
+		return factory.getQueryPlanCache().getNativeSQLQueryPlan( spec );
+	}
+
+	public List list(NativeSQLQuerySpecification spec, QueryParameters queryParameters)
+			throws HibernateException {
+		return listCustomQuery( getNativeSQLQueryPlan( spec ).getCustomQuery(), queryParameters );
+	}
+
+	public ScrollableResults scroll(NativeSQLQuerySpecification spec, QueryParameters queryParameters)
+			throws HibernateException {
+		return scrollCustomQuery( getNativeSQLQueryPlan( spec ).getCustomQuery(), queryParameters );
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/AbstractSessionImpl.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/CollectionFilterImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/CollectionFilterImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/CollectionFilterImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,81 @@
+//$Id: CollectionFilterImpl.java 8524 2005-11-04 21:28:49Z steveebersole $
+package org.hibernate.impl;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.ScrollableResults;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.query.ParameterMetadata;
+import org.hibernate.type.Type;
+
+/**
+ * implementation of the <tt>Query</tt> interface for collection filters
+ * @author Gavin King
+ */
+public class CollectionFilterImpl extends QueryImpl {
+
+	private Object collection;
+
+	public CollectionFilterImpl(
+			String queryString,
+	        Object collection,
+	        SessionImplementor session,
+	        ParameterMetadata parameterMetadata) {
+		super( queryString, session, parameterMetadata );
+		this.collection = collection;
+	}
+
+
+	/**
+	 * @see org.hibernate.Query#iterate()
+	 */
+	public Iterator iterate() throws HibernateException {
+		verifyParameters();
+		Map namedParams = getNamedParams();
+		return getSession().iterateFilter( 
+				collection, 
+				expandParameterLists(namedParams),
+				getQueryParameters(namedParams) 
+		);
+	}
+
+	/**
+	 * @see org.hibernate.Query#list()
+	 */
+	public List list() throws HibernateException {
+		verifyParameters();
+		Map namedParams = getNamedParams();
+		return getSession().listFilter( 
+				collection, 
+				expandParameterLists(namedParams),
+				getQueryParameters(namedParams) 
+		);
+	}
+
+	/**
+	 * @see org.hibernate.Query#scroll()
+	 */
+	public ScrollableResults scroll() throws HibernateException {
+		throw new UnsupportedOperationException("Can't scroll filters");
+	}
+
+	public Type[] typeArray() {
+		List typeList = getTypes();
+		int size = typeList.size();
+		Type[] result = new Type[size+1];
+		for (int i=0; i<size; i++) result[i+1] = (Type) typeList.get(i);
+		return result;
+	}
+
+	public Object[] valueArray() {
+		List valueList = getValues();
+		int size = valueList.size();
+		Object[] result = new Object[size+1];
+		for (int i=0; i<size; i++) result[i+1] = valueList.get(i);
+		return result;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/CriteriaImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/CriteriaImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/CriteriaImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,575 @@
+//$Id: CriteriaImpl.java 9116 2006-01-23 21:21:01Z steveebersole $
+package org.hibernate.impl;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.CacheMode;
+import org.hibernate.Criteria;
+import org.hibernate.FetchMode;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.criterion.Criterion;
+import org.hibernate.criterion.NaturalIdentifier;
+import org.hibernate.criterion.Order;
+import org.hibernate.criterion.Projection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Implementation of the <tt>Criteria</tt> interface
+ * @author Gavin King
+ */
+public class CriteriaImpl implements Criteria, Serializable {
+
+	private final String entityOrClassName;
+	private transient SessionImplementor session;
+	private final String rootAlias;
+
+	private List criterionEntries = new ArrayList();
+	private List orderEntries = new ArrayList();
+	private Projection projection;
+	private Criteria projectionCriteria;
+
+	private List subcriteriaList = new ArrayList();
+
+	private Map fetchModes = new HashMap();
+	private Map lockModes = new HashMap();
+
+	private Integer maxResults;
+	private Integer firstResult;
+	private Integer timeout;
+	private Integer fetchSize;
+
+	private boolean cacheable;
+	private String cacheRegion;
+	private String comment;
+
+	private FlushMode flushMode;
+	private CacheMode cacheMode;
+	private FlushMode sessionFlushMode;
+	private CacheMode sessionCacheMode;
+	
+	private ResultTransformer resultTransformer = Criteria.ROOT_ENTITY;
+
+
+	// Constructors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public CriteriaImpl(String entityOrClassName, SessionImplementor session) {
+		this(entityOrClassName, ROOT_ALIAS, session);
+	}
+
+	public CriteriaImpl(String entityOrClassName, String alias, SessionImplementor session) {
+		this.session = session;
+		this.entityOrClassName = entityOrClassName;
+		this.cacheable = false;
+		this.rootAlias = alias;
+	}
+
+	public String toString() {
+		return "CriteriaImpl(" +
+			entityOrClassName + ":" +
+			(rootAlias==null ? "" : rootAlias) +
+			subcriteriaList.toString() +
+			criterionEntries.toString() +
+			( projection==null ? "" : projection.toString() ) +
+			')';
+	}
+
+
+	// State ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public SessionImplementor getSession() {
+		return session;
+	}
+
+	public void setSession(SessionImplementor session) {
+		this.session = session;
+	}
+
+	public String getEntityOrClassName() {
+		return entityOrClassName;
+	}
+
+	public Map getLockModes() {
+		return lockModes;
+	}
+
+	public Criteria getProjectionCriteria() {
+		return projectionCriteria;
+	}
+
+	public Iterator iterateSubcriteria() {
+		return subcriteriaList.iterator();
+	}
+
+	public Iterator iterateExpressionEntries() {
+		return criterionEntries.iterator();
+	}
+
+	public Iterator iterateOrderings() {
+		return orderEntries.iterator();
+	}
+
+	public Criteria add(Criteria criteriaInst, Criterion expression) {
+		criterionEntries.add( new CriterionEntry(expression, criteriaInst) );
+		return this;
+	}
+
+
+	// Criteria impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public String getAlias() {
+		return rootAlias;
+	}
+
+	public Projection getProjection() {
+		return projection;
+	}
+
+	public Criteria setProjection(Projection projection) {
+		this.projection = projection;
+		this.projectionCriteria = this;
+		setResultTransformer( PROJECTION );
+		return this;
+	}
+
+	public Criteria add(Criterion expression) {
+		add( this, expression );
+		return this;
+	}
+
+	public Criteria addOrder(Order ordering) {
+		orderEntries.add( new OrderEntry( ordering, this ) );
+		return this;
+	}
+
+	public FetchMode getFetchMode(String path) {
+		return (FetchMode) fetchModes.get(path);
+	}
+
+	public Criteria setFetchMode(String associationPath, FetchMode mode) {
+		fetchModes.put( associationPath, mode );
+		return this;
+	}
+
+	public Criteria setLockMode(LockMode lockMode) {
+		return setLockMode( getAlias(), lockMode );
+	}
+
+	public Criteria setLockMode(String alias, LockMode lockMode) {
+		lockModes.put( alias, lockMode );
+		return this;
+	}
+
+	public Criteria createAlias(String associationPath, String alias) {
+		return createAlias( associationPath, alias, INNER_JOIN );
+	}
+
+	public Criteria createAlias(String associationPath, String alias, int joinType) {
+		new Subcriteria( this, associationPath, alias, joinType );
+		return this;
+	}
+
+	public Criteria createCriteria(String associationPath) {
+		return createCriteria( associationPath, INNER_JOIN );
+	}
+
+	public Criteria createCriteria(String associationPath, int joinType) {
+		return new Subcriteria( this, associationPath, joinType );
+	}
+
+	public Criteria createCriteria(String associationPath, String alias) {
+		return createCriteria( associationPath, alias, INNER_JOIN );
+	}
+
+	public Criteria createCriteria(String associationPath, String alias, int joinType) {
+		return new Subcriteria( this, associationPath, alias, joinType );
+	}
+
+	public ResultTransformer getResultTransformer() {
+		return resultTransformer;
+	}
+
+	public Criteria setResultTransformer(ResultTransformer tupleMapper) {
+		this.resultTransformer = tupleMapper;
+		return this;
+	}
+
+	public Integer getMaxResults() {
+		return maxResults;
+	}
+
+	public Criteria setMaxResults(int maxResults) {
+		this.maxResults = new Integer(maxResults);
+		return this;
+	}
+
+	public Integer getFirstResult() {
+		return firstResult;
+	}
+
+	public Criteria setFirstResult(int firstResult) {
+		this.firstResult = new Integer(firstResult);
+		return this;
+	}
+
+	public Integer getFetchSize() {
+		return fetchSize;
+	}
+
+	public Criteria setFetchSize(int fetchSize) {
+		this.fetchSize = new Integer(fetchSize);
+		return this;
+	}
+
+	public Integer getTimeout() {
+		return timeout;
+	}
+
+	public Criteria setTimeout(int timeout) {
+		this.timeout = new Integer(timeout);
+		return this;
+	}
+
+	public boolean getCacheable() {
+		return this.cacheable;
+	}
+
+	public Criteria setCacheable(boolean cacheable) {
+		this.cacheable = cacheable;
+		return this;
+	}
+
+	public String getCacheRegion() {
+		return this.cacheRegion;
+	}
+
+	public Criteria setCacheRegion(String cacheRegion) {
+		this.cacheRegion = cacheRegion.trim();
+		return this;
+	}
+
+	public String getComment() {
+		return comment;
+	}
+
+	public Criteria setComment(String comment) {
+		this.comment = comment;
+		return this;
+	}
+
+	public Criteria setFlushMode(FlushMode flushMode) {
+		this.flushMode = flushMode;
+		return this;
+	}
+
+	public Criteria setCacheMode(CacheMode cacheMode) {
+		this.cacheMode = cacheMode;
+		return this;
+	}
+
+	public List list() throws HibernateException {
+		before();
+		try {
+			return session.list( this );
+		}
+		finally {
+			after();
+		}
+	}
+	
+	public ScrollableResults scroll() {
+		return scroll( ScrollMode.SCROLL_INSENSITIVE );
+	}
+
+	public ScrollableResults scroll(ScrollMode scrollMode) {
+		before();
+		try {
+			return session.scroll(this, scrollMode);
+		}
+		finally {
+			after();
+		}
+	}
+
+	public Object uniqueResult() throws HibernateException {
+		return AbstractQueryImpl.uniqueElement( list() );
+	}
+
+	protected void before() {
+		if ( flushMode != null ) {
+			sessionFlushMode = getSession().getFlushMode();
+			getSession().setFlushMode( flushMode );
+		}
+		if ( cacheMode != null ) {
+			sessionCacheMode = getSession().getCacheMode();
+			getSession().setCacheMode( cacheMode );
+		}
+	}
+	
+	protected void after() {
+		if ( sessionFlushMode != null ) {
+			getSession().setFlushMode( sessionFlushMode );
+			sessionFlushMode = null;
+		}
+		if ( sessionCacheMode != null ) {
+			getSession().setCacheMode( sessionCacheMode );
+			sessionCacheMode = null;
+		}
+	}
+	
+	public boolean isLookupByNaturalKey() {
+		if ( projection != null ) {
+			return false;
+		}
+		if ( subcriteriaList.size() > 0 ) {
+			return false;
+		}
+		if ( criterionEntries.size() != 1 ) {
+			return false;
+		}
+		CriterionEntry ce = (CriterionEntry) criterionEntries.get(0);
+		return ce.getCriterion() instanceof NaturalIdentifier;
+	}
+
+
+	// Inner classes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public final class Subcriteria implements Criteria, Serializable {
+
+		private String alias;
+		private String path;
+		private Criteria parent;
+		private LockMode lockMode;
+		private int joinType;
+
+
+		// Constructors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+		private Subcriteria(Criteria parent, String path, String alias, int joinType) {
+			this.alias = alias;
+			this.path = path;
+			this.parent = parent;
+			this.joinType = joinType;
+			CriteriaImpl.this.subcriteriaList.add(this);
+		}
+
+		private Subcriteria(Criteria parent, String path, int joinType) {
+			this( parent, path, null, joinType );
+		}
+
+		public String toString() {
+			return "Subcriteria(" +
+				path + ":" +
+				(alias==null ? "" : alias) +
+				')';
+		}
+
+
+		// State ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+		public String getAlias() {
+			return alias;
+		}
+
+		public void setAlias(String alias) {
+			this.alias = alias;
+		}
+
+		public String getPath() {
+			return path;
+		}
+
+		public Criteria getParent() {
+			return parent;
+		}
+
+		public LockMode getLockMode() {
+			return lockMode;
+		}
+
+		public Criteria setLockMode(LockMode lockMode) {
+			this.lockMode = lockMode;
+			return this;
+		}
+
+		public int getJoinType() {
+			return joinType;
+		}
+
+
+		// Criteria impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+		public Criteria add(Criterion expression) {
+			CriteriaImpl.this.add(this, expression);
+			return this;
+		}
+
+		public Criteria addOrder(Order order) {
+			CriteriaImpl.this.orderEntries.add( new OrderEntry(order, this) );
+			return this;
+		}
+
+		public Criteria createAlias(String associationPath, String alias) {
+			return createAlias( associationPath, alias, INNER_JOIN );
+		}
+
+		public Criteria createAlias(String associationPath, String alias, int joinType) throws HibernateException {
+			new Subcriteria( this, associationPath, alias, joinType );
+			return this;
+		}
+
+		public Criteria createCriteria(String associationPath) {
+			return createCriteria( associationPath, INNER_JOIN );
+		}
+
+		public Criteria createCriteria(String associationPath, int joinType) throws HibernateException {
+			return new Subcriteria( Subcriteria.this, associationPath, joinType );
+		}
+
+		public Criteria createCriteria(String associationPath, String alias) {
+			return createCriteria( associationPath, alias, INNER_JOIN );
+		}
+
+		public Criteria createCriteria(String associationPath, String alias, int joinType) throws HibernateException {
+			return new Subcriteria( Subcriteria.this, associationPath, alias, joinType );
+		}
+
+		public Criteria setCacheable(boolean cacheable) {
+			CriteriaImpl.this.setCacheable(cacheable);
+			return this;
+		}
+
+		public Criteria setCacheRegion(String cacheRegion) {
+			CriteriaImpl.this.setCacheRegion(cacheRegion);
+			return this;
+		}
+
+		public List list() throws HibernateException {
+			return CriteriaImpl.this.list();
+		}
+
+		public ScrollableResults scroll() throws HibernateException {
+			return CriteriaImpl.this.scroll();
+		}
+
+		public ScrollableResults scroll(ScrollMode scrollMode) throws HibernateException {
+			return CriteriaImpl.this.scroll(scrollMode);
+		}
+
+		public Object uniqueResult() throws HibernateException {
+			return CriteriaImpl.this.uniqueResult();
+		}
+
+		public Criteria setFetchMode(String associationPath, FetchMode mode)
+			throws HibernateException {
+			CriteriaImpl.this.setFetchMode( StringHelper.qualify(path, associationPath), mode);
+			return this;
+		}
+
+		public Criteria setFlushMode(FlushMode flushMode) {
+			CriteriaImpl.this.setFlushMode(flushMode);
+			return this;
+		}
+
+		public Criteria setCacheMode(CacheMode cacheMode) {
+			CriteriaImpl.this.setCacheMode(cacheMode);
+			return this;
+		}
+
+		public Criteria setFirstResult(int firstResult) {
+			CriteriaImpl.this.setFirstResult(firstResult);
+			return this;
+		}
+
+		public Criteria setMaxResults(int maxResults) {
+			CriteriaImpl.this.setMaxResults(maxResults);
+			return this;
+		}
+
+		public Criteria setTimeout(int timeout) {
+			CriteriaImpl.this.setTimeout(timeout);
+			return this;
+		}
+
+		public Criteria setFetchSize(int fetchSize) {
+			CriteriaImpl.this.setFetchSize(fetchSize);
+			return this;
+		}
+
+		public Criteria setLockMode(String alias, LockMode lockMode) {
+			CriteriaImpl.this.setLockMode(alias, lockMode);
+			return this;
+		}
+
+		public Criteria setResultTransformer(ResultTransformer resultProcessor) {
+			CriteriaImpl.this.setResultTransformer(resultProcessor);
+			return this;
+		}
+
+		public Criteria setComment(String comment) {
+			CriteriaImpl.this.setComment(comment);
+			return this;
+		}
+
+		public Criteria setProjection(Projection projection) {
+			CriteriaImpl.this.projection = projection;
+			CriteriaImpl.this.projectionCriteria = this;
+			setResultTransformer(PROJECTION);
+			return this;
+		}
+	}
+
+	public static final class CriterionEntry implements Serializable {
+		private final Criterion criterion;
+		private final Criteria criteria;
+
+		private CriterionEntry(Criterion criterion, Criteria criteria) {
+			this.criteria = criteria;
+			this.criterion = criterion;
+		}
+
+		public Criterion getCriterion() {
+			return criterion;
+		}
+
+		public Criteria getCriteria() {
+			return criteria;
+		}
+
+		public String toString() {
+			return criterion.toString();
+		}
+	}
+
+	public static final class OrderEntry implements Serializable {
+		private final Order order;
+		private final Criteria criteria;
+
+		private OrderEntry(Order order, Criteria criteria) {
+			this.criteria = criteria;
+			this.order = order;
+		}
+
+		public Order getOrder() {
+			return order;
+		}
+
+		public Criteria getCriteria() {
+			return criteria;
+		}
+
+		public String toString() {
+			return order.toString();
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/FetchingScrollableResultsImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/FetchingScrollableResultsImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/FetchingScrollableResultsImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,293 @@
+// $Id: FetchingScrollableResultsImpl.java 7469 2005-07-14 13:12:19Z steveebersole $
+package org.hibernate.impl;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.hql.HolderInstantiator;
+import org.hibernate.type.Type;
+import org.hibernate.loader.Loader;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.QueryParameters;
+
+import java.sql.ResultSet;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * Implementation of ScrollableResults which can handle collection fetches.
+ *
+ * @author Steve Ebersole
+ */
+public class FetchingScrollableResultsImpl extends AbstractScrollableResults {
+
+	public FetchingScrollableResultsImpl(
+	        ResultSet rs,
+	        PreparedStatement ps,
+	        SessionImplementor sess,
+	        Loader loader,
+	        QueryParameters queryParameters,
+	        Type[] types,
+	        HolderInstantiator holderInstantiator) throws MappingException {
+		super( rs, ps, sess, loader, queryParameters, types, holderInstantiator );
+	}
+
+	private Object[] currentRow = null;
+	private int currentPosition = 0;
+	private Integer maxPosition = null;
+
+	protected Object[] getCurrentRow() {
+		return currentRow;
+	}
+
+	/**
+	 * Advance to the next result
+	 *
+	 * @return <tt>true</tt> if there is another result
+	 */
+	public boolean next() throws HibernateException {
+		if ( maxPosition != null && maxPosition.intValue() <= currentPosition ) {
+			currentRow = null;
+			currentPosition = maxPosition.intValue() + 1;
+			return false;
+		}
+
+		Object row = getLoader().loadSequentialRowsForward(
+				getResultSet(),
+				getSession(),
+				getQueryParameters(),
+				false
+		);
+
+
+		boolean afterLast;
+		try {
+			afterLast = getResultSet().isAfterLast();
+		}
+		catch( SQLException e ) {
+			throw JDBCExceptionHelper.convert(
+			        getSession().getFactory().getSQLExceptionConverter(),
+			        e,
+			        "exception calling isAfterLast()"
+				);
+		}
+
+		currentPosition++;
+		currentRow = new Object[] { row };
+
+		if ( afterLast ) {
+			if ( maxPosition == null ) {
+				// we just hit the last position
+				maxPosition = new Integer( currentPosition );
+			}
+		}
+
+		afterScrollOperation();
+
+		return true;
+	}
+
+	/**
+	 * Retreat to the previous result
+	 *
+	 * @return <tt>true</tt> if there is a previous result
+	 */
+	public boolean previous() throws HibernateException {
+		if ( currentPosition <= 1 ) {
+			currentPosition = 0;
+			currentRow = null;
+			return false;
+		}
+
+		Object loadResult = getLoader().loadSequentialRowsReverse(
+				getResultSet(),
+				getSession(),
+				getQueryParameters(),
+				false,
+		        ( maxPosition != null && currentPosition > maxPosition.intValue() )
+		);
+
+		currentRow = new Object[] { loadResult };
+		currentPosition--;
+
+		afterScrollOperation();
+
+		return true;
+
+	}
+
+	/**
+	 * Scroll an arbitrary number of locations
+	 *
+	 * @param positions a positive (forward) or negative (backward) number of rows
+	 *
+	 * @return <tt>true</tt> if there is a result at the new location
+	 */
+	public boolean scroll(int positions) throws HibernateException {
+		boolean more = false;
+		if ( positions > 0 ) {
+			// scroll ahead
+			for ( int i = 0; i < positions; i++ ) {
+				more = next();
+				if ( !more ) {
+					break;
+				}
+			}
+		}
+		else if ( positions < 0 ) {
+			// scroll backward
+			for ( int i = 0; i < ( 0 - positions ); i++ ) {
+				more = previous();
+				if ( !more ) {
+					break;
+				}
+			}
+		}
+		else {
+			throw new HibernateException( "scroll(0) not valid" );
+		}
+
+		afterScrollOperation();
+
+		return more;
+	}
+
+	/**
+	 * Go to the last result
+	 *
+	 * @return <tt>true</tt> if there are any results
+	 */
+	public boolean last() throws HibernateException {
+		boolean more = false;
+		if ( maxPosition != null ) {
+			for ( int i = currentPosition; i < maxPosition.intValue(); i++ ) {
+				more = next();
+			}
+		}
+		else {
+			try {
+				if ( getResultSet().isAfterLast() ) {
+					// should not be able to reach last without maxPosition being set
+					// unless there are no results
+					return false;
+				}
+
+				while ( !getResultSet().isAfterLast() ) {
+					more = next();
+				}
+			}
+			catch( SQLException e ) {
+				throw JDBCExceptionHelper.convert(
+						getSession().getFactory().getSQLExceptionConverter(),
+						e,
+						"exception calling isAfterLast()"
+					);
+			}
+		}
+
+		afterScrollOperation();
+
+		return more;
+	}
+
+	/**
+	 * Go to the first result
+	 *
+	 * @return <tt>true</tt> if there are any results
+	 */
+	public boolean first() throws HibernateException {
+		beforeFirst();
+		boolean more = next();
+
+		afterScrollOperation();
+
+		return more;
+	}
+
+	/**
+	 * Go to a location just before first result (this is the initial location)
+	 */
+	public void beforeFirst() throws HibernateException {
+		try {
+			getResultSet().beforeFirst();
+		}
+		catch( SQLException e ) {
+			throw JDBCExceptionHelper.convert(
+			        getSession().getFactory().getSQLExceptionConverter(),
+			        e,
+			        "exception calling beforeFirst()"
+				);
+		}
+		currentRow = null;
+		currentPosition = 0;
+	}
+
+	/**
+	 * Go to a location just after the last result
+	 */
+	public void afterLast() throws HibernateException {
+		// TODO : not sure the best way to handle this.
+		// The non-performant way :
+		last();
+		next();
+		afterScrollOperation();
+	}
+
+	/**
+	 * Is this the first result?
+	 *
+	 * @return <tt>true</tt> if this is the first row of results
+	 *
+	 * @throws org.hibernate.HibernateException
+	 */
+	public boolean isFirst() throws HibernateException {
+		return currentPosition == 1;
+	}
+
+	/**
+	 * Is this the last result?
+	 *
+	 * @return <tt>true</tt> if this is the last row of results
+	 *
+	 * @throws org.hibernate.HibernateException
+	 */
+	public boolean isLast() throws HibernateException {
+		if ( maxPosition == null ) {
+			// we have not yet hit the last result...
+			return false;
+		}
+		else {
+			return currentPosition == maxPosition.intValue();
+		}
+	}
+
+	/**
+	 * Get the current location in the result set. The first row is number <tt>0</tt>, contrary to JDBC.
+	 *
+	 * @return the row number, numbered from <tt>0</tt>, or <tt>-1</tt> if there is no current row
+	 */
+	public int getRowNumber() throws HibernateException {
+		return currentPosition;
+	}
+
+	/**
+	 * Set the current location in the result set, numbered from either the first row (row number <tt>0</tt>), or the last
+	 * row (row number <tt>-1</tt>).
+	 *
+	 * @param rowNumber the row number, numbered from the last row, in the case of a negative row number
+	 *
+	 * @return true if there is a row at that row number
+	 */
+	public boolean setRowNumber(int rowNumber) throws HibernateException {
+		if ( rowNumber == 1 ) {
+			return first();
+		}
+		else if ( rowNumber == -1 ) {
+			return last();
+		}
+		else if ( maxPosition != null && rowNumber == maxPosition.intValue() ) {
+			return last();
+		}
+		return scroll( rowNumber - currentPosition );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/FilterImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/FilterImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/FilterImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,151 @@
+// $Id: FilterImpl.java 8754 2005-12-05 23:36:59Z steveebersole $
+package org.hibernate.impl;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.Filter;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.FilterDefinition;
+import org.hibernate.type.Type;
+
+/**
+ * Implementation of FilterImpl.  FilterImpl implements the user's
+ * view into enabled dynamic filters, allowing them to set filter parameter values.
+ *
+ * @author Steve Ebersole
+ */
+public class FilterImpl implements Filter, Serializable {
+	public static final String MARKER = "$FILTER_PLACEHOLDER$";
+
+	private transient FilterDefinition definition;
+	private String filterName;
+	private Map parameters = new HashMap();
+	
+	void afterDeserialize(SessionFactoryImpl factory) {
+		definition = factory.getFilterDefinition(filterName);
+	}
+
+	/**
+	 * Constructs a new FilterImpl.
+	 *
+	 * @param configuration The filter's global configuration.
+	 */
+	public FilterImpl(FilterDefinition configuration) {
+		this.definition = configuration;
+		filterName = definition.getFilterName();
+	}
+
+	public FilterDefinition getFilterDefinition() {
+		return definition;
+	}
+
+	/**
+	 * Get the name of this filter.
+	 *
+	 * @return This filter's name.
+	 */
+	public String getName() {
+		return definition.getFilterName();
+	}
+	
+	public Map getParameters() {
+		return parameters;
+	}
+
+	/**
+	 * Set the named parameter's value for this filter.
+	 *
+	 * @param name The parameter's name.
+	 * @param value The value to be applied.
+	 * @return This FilterImpl instance (for method chaining).
+	 * @throws IllegalArgumentException Indicates that either the parameter was undefined or that the type
+	 * of the passed value did not match the configured type.
+	 */
+	public Filter setParameter(String name, Object value) throws IllegalArgumentException {
+		// Make sure this is a defined parameter and check the incoming value type
+		// TODO: what should be the actual exception type here?
+		Type type = definition.getParameterType( name );
+		if ( type == null ) {
+			throw new IllegalArgumentException( "Undefined filter parameter [" + name + "]" );
+		}
+		if ( value != null && !type.getReturnedClass().isAssignableFrom( value.getClass() ) ) {
+			throw new IllegalArgumentException( "Incorrect type for parameter [" + name + "]" );
+		}
+		parameters.put( name, value );
+		return this;
+	}
+
+	/**
+	 * Set the named parameter's value list for this filter.  Used
+	 * in conjunction with IN-style filter criteria.
+	 *
+	 * @param name   The parameter's name.
+	 * @param values The values to be expanded into an SQL IN list.
+	 * @return This FilterImpl instance (for method chaining).
+	 */
+	public Filter setParameterList(String name, Collection values) throws HibernateException  {
+		// Make sure this is a defined parameter and check the incoming value type
+		if ( values == null ) {
+			throw new IllegalArgumentException( "Collection must be not null!" );
+		}
+		Type type = definition.getParameterType( name );
+		if ( type == null ) {
+			throw new HibernateException( "Undefined filter parameter [" + name + "]" );
+		}
+		if ( values.size() > 0 ) {
+			Class elementClass = values.iterator().next().getClass();
+			if ( !type.getReturnedClass().isAssignableFrom( elementClass ) ) {
+				throw new HibernateException( "Incorrect type for parameter [" + name + "]" );
+			}
+		}
+		parameters.put( name, values );
+		return this;
+	}
+
+	/**
+	 * Set the named parameter's value list for this filter.  Used
+	 * in conjunction with IN-style filter criteria.
+	 *
+	 * @param name The parameter's name.
+	 * @param values The values to be expanded into an SQL IN list.
+	 * @return This FilterImpl instance (for method chaining).
+	 */
+	public Filter setParameterList(String name, Object[] values) throws IllegalArgumentException {
+		return setParameterList( name, Arrays.asList( values ) );
+	}
+
+	/**
+	 * Get the value of the named parameter for the current filter.
+	 *
+	 * @param name The name of the parameter for which to return the value.
+	 * @return The value of the named parameter.
+	 */
+	public Object getParameter(String name) {
+		return parameters.get( name );
+	}
+
+	/**
+	 * Perform validation of the filter state.  This is used to verify the
+	 * state of the filter after its enablement and before its use.
+	 *
+	 * @throws HibernateException If the state is not currently valid.
+	 */
+	public void validate() throws HibernateException {
+		// for each of the defined parameters, make sure its value
+		// has been set
+		Iterator itr = definition.getParameterNames().iterator();
+		while ( itr.hasNext() ) {
+			final String parameterName = (String) itr.next();
+			if ( parameters.get( parameterName ) == null ) {
+				throw new HibernateException(
+						"Filter [" + getName() + "] parameter [" + parameterName + "] value not set"
+				);
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/IteratorImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/IteratorImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/IteratorImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,152 @@
+//$Id: IteratorImpl.java 9944 2006-05-24 21:14:56Z steve.ebersole at jboss.com $
+package org.hibernate.impl;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.NoSuchElementException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.JDBCException;
+import org.hibernate.engine.HibernateIterator;
+import org.hibernate.event.EventSource;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.hql.HolderInstantiator;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+
+/**
+ * An implementation of <tt>java.util.Iterator</tt> that is
+ * returned by <tt>iterate()</tt> query execution methods.
+ * @author Gavin King
+ */
+public final class IteratorImpl implements HibernateIterator {
+
+	private static final Log log = LogFactory.getLog(IteratorImpl.class);
+
+	private ResultSet rs;
+	private final EventSource session;
+	private final Type[] types;
+	private final boolean single;
+	private Object currentResult;
+	private boolean hasNext;
+	private final String[][] names;
+	private PreparedStatement ps;
+	private Object nextResult;
+	private HolderInstantiator holderInstantiator;
+
+	public IteratorImpl(
+	        ResultSet rs,
+	        PreparedStatement ps,
+	        EventSource sess,
+	        Type[] types,
+	        String[][] columnNames,
+	        HolderInstantiator holderInstantiator)
+	throws HibernateException, SQLException {
+
+		this.rs=rs;
+		this.ps=ps;
+		this.session = sess;
+		this.types = types;
+		this.names = columnNames;
+		this.holderInstantiator = holderInstantiator;
+
+		single = types.length==1;
+
+		postNext();
+	}
+
+	public void close() throws JDBCException {
+		if (ps!=null) {
+			try {
+				log.debug("closing iterator");
+				nextResult = null;
+				session.getBatcher().closeQueryStatement(ps, rs);
+				ps = null;
+				rs = null;
+				hasNext = false;
+			}
+			catch (SQLException e) {
+				log.info( "Unable to close iterator", e );
+				throw JDBCExceptionHelper.convert(
+				        session.getFactory().getSQLExceptionConverter(),
+				        e,
+				        "Unable to close iterator"
+					);
+			}
+		}
+	}
+
+	private void postNext() throws HibernateException, SQLException {
+		this.hasNext = rs.next();
+		if (!hasNext) {
+			log.debug("exhausted results");
+			close();
+		}
+		else {
+			log.debug("retrieving next results");
+			boolean isHolder = holderInstantiator.isRequired();
+
+			if ( single && !isHolder ) {
+				nextResult = types[0].nullSafeGet( rs, names[0], session, null );
+			}
+			else {
+				Object[] nextResults = new Object[types.length];
+				for (int i=0; i<types.length; i++) {
+					nextResults[i] = types[i].nullSafeGet( rs, names[i], session, null );
+				}
+
+				if (isHolder) {
+					nextResult = holderInstantiator.instantiate(nextResults);
+				}
+				else {
+					nextResult = nextResults;
+				}
+			}
+
+		}
+	}
+
+	public boolean hasNext() {
+		return hasNext;
+	}
+
+	public Object next() {
+		if ( !hasNext ) throw new NoSuchElementException("No more results");
+		try {
+			currentResult = nextResult;
+			postNext();
+			log.debug("returning current results");
+			return currentResult;
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					session.getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not get next iterator result"
+				);
+		}
+	}
+
+	public void remove() {
+		if (!single) {
+			throw new UnsupportedOperationException("Not a single column hibernate query result set");
+		}
+		if (currentResult==null) {
+			throw new IllegalStateException("Called Iterator.remove() before next()");
+		}
+		if ( !( types[0] instanceof EntityType ) ) {
+			throw new UnsupportedOperationException("Not an entity");
+		}
+		
+		session.delete( 
+				( (EntityType) types[0] ).getAssociatedEntityName(), 
+				currentResult,
+				false,
+		        null
+			);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/QueryImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/QueryImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/QueryImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,119 @@
+//$Id: QueryImpl.java 8524 2005-11-04 21:28:49Z steveebersole $
+package org.hibernate.impl;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.Query;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.query.ParameterMetadata;
+
+/**
+ * default implementation of the <tt>Query</tt> interface,
+ * for "ordinary" HQL queries (not collection filters)
+ * @see CollectionFilterImpl
+ * @author Gavin King
+ */
+public class QueryImpl extends AbstractQueryImpl {
+
+	private Map lockModes = new HashMap(2);
+
+	public QueryImpl(
+			String queryString,
+	        FlushMode flushMode,
+	        SessionImplementor session,
+	        ParameterMetadata parameterMetadata) {
+		super( queryString, flushMode, session, parameterMetadata );
+	}
+
+	public QueryImpl(String queryString, SessionImplementor session, ParameterMetadata parameterMetadata) {
+		this( queryString, null, session, parameterMetadata );
+	}
+
+	public Iterator iterate() throws HibernateException {
+		verifyParameters();
+		Map namedParams = getNamedParams();
+		before();
+		try {
+			return getSession().iterate(
+					expandParameterLists(namedParams),
+			        getQueryParameters(namedParams)
+				);
+		}
+		finally {
+			after();
+		}
+	}
+
+	public ScrollableResults scroll() throws HibernateException {
+		return scroll( ScrollMode.SCROLL_INSENSITIVE );
+	}
+
+	public ScrollableResults scroll(ScrollMode scrollMode) throws HibernateException {
+		verifyParameters();
+		Map namedParams = getNamedParams();
+		before();
+		QueryParameters qp = getQueryParameters(namedParams);
+		qp.setScrollMode(scrollMode);
+		try {
+			return getSession().scroll( expandParameterLists(namedParams), qp );
+		}
+		finally {
+			after();
+		}
+	}
+
+	public List list() throws HibernateException {
+		verifyParameters();
+		Map namedParams = getNamedParams();
+		before();
+		try {
+			return getSession().list(
+					expandParameterLists(namedParams),
+			        getQueryParameters(namedParams)
+				);
+		}
+		finally {
+			after();
+		}
+	}
+
+	public int executeUpdate() throws HibernateException {
+		verifyParameters();
+		Map namedParams = getNamedParams();
+		before();
+		try {
+            return getSession().executeUpdate(
+                    expandParameterLists( namedParams ),
+                    getQueryParameters( namedParams )
+	            );
+		}
+		finally {
+			after();
+		}
+	}
+
+	public Query setLockMode(String alias, LockMode lockMode) {
+		lockModes.put(alias, lockMode);
+		return this;
+	}
+
+	protected Map getLockModes() {
+		return lockModes;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SQLQueryImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SQLQueryImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SQLQueryImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,344 @@
+//$Id: SQLQueryImpl.java 10862 2006-11-22 00:11:35Z steve.ebersole at jboss.com $
+package org.hibernate.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.io.Serializable;
+
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.Query;
+import org.hibernate.QueryException;
+import org.hibernate.SQLQuery;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.MappingException;
+import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
+import org.hibernate.engine.ResultSetMappingDefinition;
+import org.hibernate.engine.NamedSQLQueryDefinition;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.query.ParameterMetadata;
+import org.hibernate.engine.query.sql.NativeSQLQueryJoinReturn;
+import org.hibernate.engine.query.sql.NativeSQLQueryScalarReturn;
+import org.hibernate.engine.query.sql.NativeSQLQueryRootReturn;
+import org.hibernate.engine.query.sql.NativeSQLQueryReturn;
+import org.hibernate.type.Type;
+import org.hibernate.util.CollectionHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Implements SQL query passthrough.
+ *
+ * <pre>
+ * <sql-query name="mySqlQuery">
+ * <return alias="person" class="eg.Person"/>
+ *   SELECT {person}.NAME AS {person.name}, {person}.AGE AS {person.age}, {person}.SEX AS {person.sex}
+ *   FROM PERSON {person} WHERE {person}.NAME LIKE 'Hiber%'
+ * </sql-query>
+ * </pre>
+ *
+ * @author Max Andersen
+ */
+public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
+
+	private final List queryReturns;
+	private Collection querySpaces;
+	private final boolean callable;
+	private boolean autodiscovertypes;
+
+	/**
+	 * Constructs a SQLQueryImpl given a sql query defined in the mappings.
+	 *
+	 * @param queryDef The representation of the defined <sql-query/>.
+	 * @param session The session to which this SQLQueryImpl belongs.
+	 * @param parameterMetadata Metadata about parameters found in the query.
+	 */
+	SQLQueryImpl(NamedSQLQueryDefinition queryDef, SessionImplementor session, ParameterMetadata parameterMetadata) {
+		super( queryDef.getQueryString(), queryDef.getFlushMode(), session, parameterMetadata );
+		if ( queryDef.getResultSetRef() != null ) {
+			ResultSetMappingDefinition definition = session.getFactory()
+					.getResultSetMapping( queryDef.getResultSetRef() );
+			if (definition == null) {
+				throw new MappingException(
+						"Unable to find resultset-ref definition: " +
+						queryDef.getResultSetRef()
+					);
+			}
+			this.queryReturns = Arrays.asList( definition.getQueryReturns() );
+		}
+		else {
+			this.queryReturns = Arrays.asList( queryDef.getQueryReturns() );
+		}
+
+		this.querySpaces = queryDef.getQuerySpaces();
+		this.callable = queryDef.isCallable();
+	}
+
+	SQLQueryImpl(
+			final String sql,
+	        final List queryReturns,
+	        final Collection querySpaces,
+	        final FlushMode flushMode,
+	        boolean callable,
+	        final SessionImplementor session,
+	        ParameterMetadata parameterMetadata) {
+		// TODO : absolutely no usages of this constructor form; can it go away?
+		super( sql, flushMode, session, parameterMetadata );
+		this.queryReturns = queryReturns;
+		this.querySpaces = querySpaces;
+		this.callable = callable;
+	}
+
+	SQLQueryImpl(
+			final String sql,
+	        final String returnAliases[],
+	        final Class returnClasses[],
+	        final LockMode[] lockModes,
+	        final SessionImplementor session,
+	        final Collection querySpaces,
+	        final FlushMode flushMode,
+	        ParameterMetadata parameterMetadata) {
+		// TODO : this constructor form is *only* used from constructor directly below us; can it go away?
+		super( sql, flushMode, session, parameterMetadata );
+		queryReturns = new ArrayList(returnAliases.length);
+		for ( int i=0; i<returnAliases.length; i++ ) {
+			NativeSQLQueryRootReturn ret = new NativeSQLQueryRootReturn(
+					returnAliases[i],
+					returnClasses[i].getName(),
+					lockModes==null ? LockMode.NONE : lockModes[i]
+			);
+			queryReturns.add(ret);
+		}
+		this.querySpaces = querySpaces;
+		this.callable = false;
+	}
+
+	SQLQueryImpl(
+			final String sql,
+	        final String returnAliases[],
+	        final Class returnClasses[],
+	        final SessionImplementor session,
+	        ParameterMetadata parameterMetadata) {
+		this( sql, returnAliases, returnClasses, null, session, null, null, parameterMetadata );
+	}
+
+	SQLQueryImpl(String sql, SessionImplementor session, ParameterMetadata parameterMetadata) {
+		super( sql, null, session, parameterMetadata );
+		queryReturns = new ArrayList();
+		querySpaces = null;
+		callable = false;
+	}
+
+	private static final NativeSQLQueryReturn[] NO_SQL_RETURNS = new NativeSQLQueryReturn[0];
+
+	private NativeSQLQueryReturn[] getQueryReturns() {
+		return ( NativeSQLQueryReturn[] ) queryReturns.toArray( NO_SQL_RETURNS );
+	}
+
+	public List list() throws HibernateException {
+		verifyParameters();
+		before();
+
+		Map namedParams = getNamedParams();
+		NativeSQLQuerySpecification spec = generateQuerySpecification( namedParams );
+
+		try {
+			return getSession().list( spec, getQueryParameters( namedParams ) );
+		}
+		finally {
+			after();
+		}
+	}
+
+	private NativeSQLQuerySpecification generateQuerySpecification(Map namedParams) {
+		return new NativeSQLQuerySpecification(
+		        expandParameterLists(namedParams),
+		        getQueryReturns(),
+		        querySpaces
+		);
+	}
+
+	public ScrollableResults scroll(ScrollMode scrollMode) throws HibernateException {
+		verifyParameters();
+		before();
+
+		Map namedParams = getNamedParams();
+		NativeSQLQuerySpecification spec = generateQuerySpecification( namedParams );
+
+		QueryParameters qp = getQueryParameters( namedParams );
+		qp.setScrollMode( scrollMode );
+
+		try {
+			return getSession().scroll( spec, qp );
+		}
+		finally {
+			after();
+		}
+	}
+
+	public ScrollableResults scroll() throws HibernateException {
+		return scroll(ScrollMode.SCROLL_INSENSITIVE);
+	}
+
+	public Iterator iterate() throws HibernateException {
+		throw new UnsupportedOperationException("SQL queries do not currently support iteration");
+	}
+
+	public QueryParameters getQueryParameters(Map namedParams) {
+		QueryParameters qp = super.getQueryParameters(namedParams);
+		qp.setCallable(callable);
+		qp.setAutoDiscoverScalarTypes(autodiscovertypes);
+		return qp;
+	}
+
+	protected void verifyParameters() {
+		verifyParameters( callable );
+		boolean noReturns = queryReturns==null || queryReturns.isEmpty();
+		if ( noReturns ) {
+			this.autodiscovertypes = noReturns;
+		}
+		else {
+			Iterator itr = queryReturns.iterator();
+			while ( itr.hasNext() ) {
+				NativeSQLQueryReturn rtn = ( NativeSQLQueryReturn ) itr.next();
+				if ( rtn instanceof NativeSQLQueryScalarReturn ) {
+					NativeSQLQueryScalarReturn scalar = ( NativeSQLQueryScalarReturn ) rtn;
+					if ( scalar.getType() == null ) {
+						autodiscovertypes = true;
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	public String[] getReturnAliases() throws HibernateException {
+		throw new UnsupportedOperationException("SQL queries do not currently support returning aliases");
+	}
+
+	public Type[] getReturnTypes() throws HibernateException {
+		throw new UnsupportedOperationException("not yet implemented for SQL queries");
+	}
+
+	public Query setLockMode(String alias, LockMode lockMode) {
+		throw new UnsupportedOperationException("cannot set the lock mode for a native SQL query");
+	}
+
+	protected Map getLockModes() {
+		//we never need to apply locks to the SQL
+		return CollectionHelper.EMPTY_MAP;
+	}
+
+	public SQLQuery addScalar(String columnAlias, Type type) {
+		queryReturns.add( new NativeSQLQueryScalarReturn( columnAlias, type ) );
+		return this;
+	}
+
+	public SQLQuery addScalar(String columnAlias) {
+		autodiscovertypes = true;
+		queryReturns.add( new NativeSQLQueryScalarReturn( columnAlias, null ) );
+		return this;
+	}
+
+	public SQLQuery addJoin(String alias, String path) {
+		return addJoin(alias, path, LockMode.READ);
+	}
+
+	public SQLQuery addEntity(Class entityClass) {
+		return addEntity( StringHelper.unqualify( entityClass.getName() ), entityClass );
+	}
+
+	public SQLQuery addEntity(String entityName) {
+		return addEntity( StringHelper.unqualify( entityName ), entityName );
+	}
+
+	public SQLQuery addEntity(String alias, String entityName) {
+		return addEntity(alias, entityName, LockMode.READ);
+	}
+
+	public SQLQuery addEntity(String alias, Class entityClass) {
+		return addEntity( alias, entityClass.getName() );
+	}
+
+	public SQLQuery addJoin(String alias, String path, LockMode lockMode) {
+		int loc = path.indexOf('.');
+		if ( loc < 0 ) {
+			throw new QueryException( "not a property path: " + path );
+		}
+		String ownerAlias = path.substring(0, loc);
+		String role = path.substring(loc+1);
+		queryReturns.add( new NativeSQLQueryJoinReturn(alias, ownerAlias, role, CollectionHelper.EMPTY_MAP, lockMode) );
+		return this;
+	}
+
+	public SQLQuery addEntity(String alias, String entityName, LockMode lockMode) {
+		queryReturns.add( new NativeSQLQueryRootReturn(alias, entityName, lockMode) );
+		return this;
+	}
+
+	public SQLQuery addEntity(String alias, Class entityClass, LockMode lockMode) {
+		return addEntity( alias, entityClass.getName(), lockMode );
+	}
+
+	public SQLQuery setResultSetMapping(String name) {
+		ResultSetMappingDefinition mapping = session.getFactory().getResultSetMapping( name );
+		if ( mapping == null ) {
+			throw new MappingException( "Unknown SqlResultSetMapping [" + name + "]" );
+		}
+		NativeSQLQueryReturn[] returns = mapping.getQueryReturns();
+		int length = returns.length;
+		for ( int index = 0 ; index < length ; index++ ) {
+			queryReturns.add( returns[index] );
+		}
+		return this;
+	}
+
+	public SQLQuery addSynchronizedQuerySpace(String querySpace) {
+		if ( querySpaces == null ) {
+			querySpaces = new ArrayList();
+		}
+		querySpaces.add( querySpace );
+		return this;
+	}
+
+	public SQLQuery addSynchronizedEntityName(String entityName) {
+		return addQuerySpaces( getSession().getFactory().getEntityPersister( entityName ).getQuerySpaces() );
+	}
+
+	public SQLQuery addSynchronizedEntityClass(Class entityClass) {
+		return addQuerySpaces( getSession().getFactory().getEntityPersister( entityClass.getName() ).getQuerySpaces() );
+	}
+
+	private SQLQuery addQuerySpaces(Serializable[] spaces) {
+		if ( spaces != null ) {
+			if ( querySpaces == null ) {
+				querySpaces = new ArrayList();
+			}
+			for ( int i = 0; i < spaces.length; i++ ) {
+				querySpaces.add( spaces[i] );
+			}
+		}
+		return this;
+	}
+
+	public int executeUpdate() throws HibernateException {
+		Map namedParams = getNamedParams();
+		before();
+		try {
+			return getSession().executeNativeUpdate(
+					generateQuerySpecification( namedParams ),
+					getQueryParameters( namedParams )
+			);
+		}
+		finally {
+			after();
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/ScrollableResultsImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/ScrollableResultsImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/ScrollableResultsImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,251 @@
+//$Id: ScrollableResultsImpl.java 7469 2005-07-14 13:12:19Z steveebersole $
+package org.hibernate.impl;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.ScrollableResults;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.hql.HolderInstantiator;
+import org.hibernate.loader.Loader;
+import org.hibernate.type.Type;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * Implementation of the <tt>ScrollableResults</tt> interface
+ * @author Gavin King
+ */
+public class ScrollableResultsImpl extends AbstractScrollableResults implements ScrollableResults {
+
+	private Object[] currentRow;
+
+	public ScrollableResultsImpl(
+	        ResultSet rs,
+	        PreparedStatement ps,
+	        SessionImplementor sess,
+	        Loader loader,
+	        QueryParameters queryParameters,
+	        Type[] types, HolderInstantiator holderInstantiator) throws MappingException {
+		super( rs, ps, sess, loader, queryParameters, types, holderInstantiator );
+	}
+
+	protected Object[] getCurrentRow() {
+		return currentRow;
+	}
+
+	/**
+	 * @see org.hibernate.ScrollableResults#scroll(int)
+	 */
+	public boolean scroll(int i) throws HibernateException {
+		try {
+			boolean result = getResultSet().relative(i);
+			prepareCurrentRow(result);
+			return result;
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					getSession().getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not advance using scroll()"
+				);
+		}
+	}
+
+	/**
+	 * @see org.hibernate.ScrollableResults#first()
+	 */
+	public boolean first() throws HibernateException {
+		try {
+			boolean result = getResultSet().first();
+			prepareCurrentRow(result);
+			return result;
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					getSession().getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not advance using first()"
+				);
+		}
+	}
+
+	/**
+	 * @see org.hibernate.ScrollableResults#last()
+	 */
+	public boolean last() throws HibernateException {
+		try {
+			boolean result = getResultSet().last();
+			prepareCurrentRow(result);
+			return result;
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					getSession().getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not advance using last()"
+				);
+		}
+	}
+
+	/**
+	 * @see org.hibernate.ScrollableResults#next()
+	 */
+	public boolean next() throws HibernateException {
+		try {
+			boolean result = getResultSet().next();
+			prepareCurrentRow(result);
+			return result;
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					getSession().getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not advance using next()"
+				);
+		}
+	}
+
+	/**
+	 * @see org.hibernate.ScrollableResults#previous()
+	 */
+	public boolean previous() throws HibernateException {
+		try {
+			boolean result = getResultSet().previous();
+			prepareCurrentRow(result);
+			return result;
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					getSession().getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not advance using previous()"
+				);
+		}
+	}
+
+	/**
+	 * @see org.hibernate.ScrollableResults#afterLast()
+	 */
+	public void afterLast() throws HibernateException {
+		try {
+			getResultSet().afterLast();
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					getSession().getFactory().getSQLExceptionConverter(),
+					sqle,
+					"exception calling afterLast()"
+				);
+		}
+	}
+
+	/**
+	 * @see org.hibernate.ScrollableResults#beforeFirst()
+	 */
+	public void beforeFirst() throws HibernateException {
+		try {
+			getResultSet().beforeFirst();
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					getSession().getFactory().getSQLExceptionConverter(),
+					sqle,
+					"exception calling beforeFirst()"
+				);
+		}
+	}
+
+	/**
+	 * @see org.hibernate.ScrollableResults#isFirst()
+	 */
+	public boolean isFirst() throws HibernateException {
+		try {
+			return getResultSet().isFirst();
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					getSession().getFactory().getSQLExceptionConverter(),
+					sqle,
+					"exception calling isFirst()"
+				);
+		}
+	}
+
+	/**
+	 * @see org.hibernate.ScrollableResults#isLast()
+	 */
+	public boolean isLast() throws HibernateException {
+		try {
+			return getResultSet().isLast();
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					getSession().getFactory().getSQLExceptionConverter(),
+					sqle,
+					"exception calling isLast()"
+				);
+		}
+	}
+
+	public int getRowNumber() throws HibernateException {
+		try {
+			return getResultSet().getRow()-1;
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					getSession().getFactory().getSQLExceptionConverter(),
+					sqle,
+					"exception calling getRow()"
+				);
+		}
+	}
+
+	public boolean setRowNumber(int rowNumber) throws HibernateException {
+		if (rowNumber>=0) rowNumber++;
+		try {
+			boolean result = getResultSet().absolute(rowNumber);
+			prepareCurrentRow(result);
+			return result;
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					getSession().getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not advance using absolute()"
+				);
+		}
+	}
+
+	private void prepareCurrentRow(boolean underlyingScrollSuccessful) 
+	throws HibernateException {
+		
+		if (!underlyingScrollSuccessful) {
+			currentRow = null;
+			return;
+		}
+
+		Object result = getLoader().loadSingleRow(
+				getResultSet(),
+				getSession(),
+				getQueryParameters(),
+				false
+		);
+		if ( result != null && result.getClass().isArray() ) {
+			currentRow = (Object[]) result;
+		}
+		else {
+			currentRow = new Object[] { result };
+		}
+
+		if ( getHolderInstantiator() != null ) {
+			currentRow = new Object[] { getHolderInstantiator().instantiate(currentRow) };
+		}
+
+		afterScrollOperation();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1069 @@
+//$Id: SessionFactoryImpl.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.impl;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+import javax.transaction.TransactionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.MappingException;
+import org.hibernate.ObjectNotFoundException;
+import org.hibernate.QueryException;
+import org.hibernate.SessionFactory;
+import org.hibernate.StatelessSession;
+import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.cache.QueryCache;
+import org.hibernate.cache.UpdateTimestampsCache;
+import org.hibernate.cache.Region;
+import org.hibernate.cache.EntityRegion;
+import org.hibernate.cache.CollectionRegion;
+import org.hibernate.cache.impl.CacheDataDescriptionImpl;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cache.access.AccessType;
+import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.Settings;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.context.CurrentSessionContext;
+import org.hibernate.context.JTASessionContext;
+import org.hibernate.context.ManagedSessionContext;
+import org.hibernate.context.ThreadLocalSessionContext;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.function.SQLFunctionRegistry;
+import org.hibernate.engine.FilterDefinition;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.NamedQueryDefinition;
+import org.hibernate.engine.NamedSQLQueryDefinition;
+import org.hibernate.engine.ResultSetMappingDefinition;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.query.QueryPlanCache;
+import org.hibernate.event.EventListeners;
+import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.id.UUIDHexGenerator;
+import org.hibernate.jdbc.BatcherFactory;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.RootClass;
+import org.hibernate.metadata.ClassMetadata;
+import org.hibernate.metadata.CollectionMetadata;
+import org.hibernate.persister.PersisterFactory;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.proxy.EntityNotFoundDelegate;
+import org.hibernate.stat.Statistics;
+import org.hibernate.stat.StatisticsImpl;
+import org.hibernate.stat.StatisticsImplementor;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+import org.hibernate.tool.hbm2ddl.SchemaUpdate;
+import org.hibernate.tool.hbm2ddl.SchemaValidator;
+import org.hibernate.transaction.TransactionFactory;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.Type;
+import org.hibernate.util.CollectionHelper;
+import org.hibernate.util.ReflectHelper;
+
+
+/**
+ * Concrete implementation of the <tt>SessionFactory</tt> interface. Has the following
+ * responsibilites
+ * <ul>
+ * <li>caches configuration settings (immutably)
+ * <li>caches "compiled" mappings ie. <tt>EntityPersister</tt>s and
+ *     <tt>CollectionPersister</tt>s (immutable)
+ * <li>caches "compiled" queries (memory sensitive cache)
+ * <li>manages <tt>PreparedStatement</tt>s
+ * <li> delegates JDBC <tt>Connection</tt> management to the <tt>ConnectionProvider</tt>
+ * <li>factory for instances of <tt>SessionImpl</tt>
+ * </ul>
+ * This class must appear immutable to clients, even if it does all kinds of caching
+ * and pooling under the covers. It is crucial that the class is not only thread
+ * safe, but also highly concurrent. Synchronization must be used extremely sparingly.
+ *
+ * @see org.hibernate.connection.ConnectionProvider
+ * @see org.hibernate.classic.Session
+ * @see org.hibernate.hql.QueryTranslator
+ * @see org.hibernate.persister.entity.EntityPersister
+ * @see org.hibernate.persister.collection.CollectionPersister
+ * @author Gavin King
+ */
+public final class SessionFactoryImpl implements SessionFactory, SessionFactoryImplementor {
+
+	private final String name;
+	private final String uuid;
+
+	private final transient Map entityPersisters;
+	private final transient Map classMetadata;
+	private final transient Map collectionPersisters;
+	private final transient Map collectionMetadata;
+	private final transient Map collectionRolesByEntityParticipant;
+	private final transient Map identifierGenerators;
+	private final transient Map namedQueries;
+	private final transient Map namedSqlQueries;
+	private final transient Map sqlResultSetMappings;
+	private final transient Map filters;
+	private final transient Map imports;
+	private final transient Interceptor interceptor;
+	private final transient Settings settings;
+	private final transient Properties properties;
+	private transient SchemaExport schemaExport;
+	private final transient TransactionManager transactionManager;
+	private final transient QueryCache queryCache;
+	private final transient UpdateTimestampsCache updateTimestampsCache;
+	private final transient Map queryCaches;
+	private final transient Map allCacheRegions = new HashMap();
+	private final transient StatisticsImpl statistics = new StatisticsImpl(this);
+	private final transient EventListeners eventListeners;
+	private final transient CurrentSessionContext currentSessionContext;
+	private final transient EntityNotFoundDelegate entityNotFoundDelegate;
+	private final transient SQLFunctionRegistry sqlFunctionRegistry;
+	
+	private final QueryPlanCache queryPlanCache = new QueryPlanCache( this );
+
+	private transient boolean isClosed = false;
+	
+
+	private static final IdentifierGenerator UUID_GENERATOR = new UUIDHexGenerator();
+
+	private static final Log log = LogFactory.getLog(SessionFactoryImpl.class);
+
+	public SessionFactoryImpl(
+			Configuration cfg,
+	        Mapping mapping,
+	        Settings settings,
+	        EventListeners listeners)
+	throws HibernateException {
+
+		log.info("building session factory");
+
+		this.properties = new Properties();
+		this.properties.putAll( cfg.getProperties() );
+		this.interceptor = cfg.getInterceptor();
+		this.settings = settings;
+		this.sqlFunctionRegistry = new SQLFunctionRegistry(settings.getDialect(), cfg.getSqlFunctions());
+        this.eventListeners = listeners;
+        this.filters = new HashMap();
+		this.filters.putAll( cfg.getFilterDefinitions() );
+
+		if ( log.isDebugEnabled() ) {
+			log.debug("Session factory constructed with filter configurations : " + filters);
+		}
+
+		if ( log.isDebugEnabled() ) {
+			log.debug(
+					"instantiating session factory with properties: " + properties
+			);
+		}
+
+		// Caches
+		settings.getRegionFactory().start( settings, properties );
+
+		//Generators:
+
+		identifierGenerators = new HashMap();
+		Iterator classes = cfg.getClassMappings();
+		while ( classes.hasNext() ) {
+			PersistentClass model = (PersistentClass) classes.next();
+			if ( !model.isInherited() ) {
+				IdentifierGenerator generator = model.getIdentifier().createIdentifierGenerator(
+						settings.getDialect(),
+				        settings.getDefaultCatalogName(),
+				        settings.getDefaultSchemaName(),
+				        (RootClass) model
+					);
+				identifierGenerators.put( model.getEntityName(), generator );
+			}
+		}
+
+
+		///////////////////////////////////////////////////////////////////////
+		// Prepare persisters and link them up with their cache
+		// region/access-strategy
+
+		entityPersisters = new HashMap();
+		Map entityAccessStrategies = new HashMap();
+		Map classMeta = new HashMap();
+		classes = cfg.getClassMappings();
+		while ( classes.hasNext() ) {
+			final PersistentClass model = (PersistentClass) classes.next();
+			model.prepareTemporaryTables( mapping, settings.getDialect() );
+			// cache region is defined by the root-class in the hierarchy...
+			final String cacheRegionName = model.getRootClass().getCacheRegionName();
+			EntityRegionAccessStrategy accessStrategy = ( EntityRegionAccessStrategy ) entityAccessStrategies.get( cacheRegionName );
+			if ( accessStrategy == null && settings.isSecondLevelCacheEnabled() ) {
+				final AccessType accessType = AccessType.parse( model.getCacheConcurrencyStrategy() );
+				if ( accessType != null ) {
+					log.trace( "Building cache for entity data [" + model.getEntityName() + "]" );
+					EntityRegion entityRegion = settings.getRegionFactory().buildEntityRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) );
+					accessStrategy = entityRegion.buildAccessStrategy( accessType );
+					entityAccessStrategies.put( cacheRegionName, accessStrategy );
+					allCacheRegions.put( cacheRegionName, entityRegion );
+				}
+			}
+			EntityPersister cp = PersisterFactory.createClassPersister( model, accessStrategy, this, mapping );
+			entityPersisters.put( model.getEntityName(), cp );
+			classMeta.put( model.getEntityName(), cp.getClassMetadata() );
+		}
+		classMetadata = Collections.unmodifiableMap(classMeta);
+
+		Map tmpEntityToCollectionRoleMap = new HashMap();
+		collectionPersisters = new HashMap();
+		Iterator collections = cfg.getCollectionMappings();
+		while ( collections.hasNext() ) {
+			Collection model = (Collection) collections.next();
+			final String cacheRegionName = model.getCacheRegionName();
+			final AccessType accessType = AccessType.parse( model.getCacheConcurrencyStrategy() );
+			CollectionRegionAccessStrategy accessStrategy = null;
+			if ( accessType != null && settings.isSecondLevelCacheEnabled() ) {
+				log.trace( "Building cache for collection data [" + model.getRole() + "]" );
+				CollectionRegion collectionRegion = settings.getRegionFactory().buildCollectionRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) );
+				accessStrategy = collectionRegion.buildAccessStrategy( accessType );
+				entityAccessStrategies.put( cacheRegionName, accessStrategy );
+				allCacheRegions.put( cacheRegionName, collectionRegion );
+			}
+			CollectionPersister persister = PersisterFactory.createCollectionPersister( cfg, model, accessStrategy, this) ;
+			collectionPersisters.put( model.getRole(), persister.getCollectionMetadata() );
+			Type indexType = persister.getIndexType();
+			if ( indexType != null && indexType.isAssociationType() && !indexType.isAnyType() ) {
+				String entityName = ( ( AssociationType ) indexType ).getAssociatedEntityName( this );
+				Set roles = ( Set ) tmpEntityToCollectionRoleMap.get( entityName );
+				if ( roles == null ) {
+					roles = new HashSet();
+					tmpEntityToCollectionRoleMap.put( entityName, roles );
+				}
+				roles.add( persister.getRole() );
+			}
+			Type elementType = persister.getElementType();
+			if ( elementType.isAssociationType() && !elementType.isAnyType() ) {
+				String entityName = ( ( AssociationType ) elementType ).getAssociatedEntityName( this );
+				Set roles = ( Set ) tmpEntityToCollectionRoleMap.get( entityName );
+				if ( roles == null ) {
+					roles = new HashSet();
+					tmpEntityToCollectionRoleMap.put( entityName, roles );
+				}
+				roles.add( persister.getRole() );
+			}
+		}
+		collectionMetadata = Collections.unmodifiableMap(collectionPersisters);
+		Iterator itr = tmpEntityToCollectionRoleMap.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			final Map.Entry entry = ( Map.Entry ) itr.next();
+			entry.setValue( Collections.unmodifiableSet( ( Set ) entry.getValue() ) );
+		}
+		collectionRolesByEntityParticipant = Collections.unmodifiableMap( tmpEntityToCollectionRoleMap );
+
+		//Named Queries:
+		namedQueries = new HashMap( cfg.getNamedQueries() );
+		namedSqlQueries = new HashMap( cfg.getNamedSQLQueries() );
+		sqlResultSetMappings = new HashMap( cfg.getSqlResultSetMappings() );
+		imports = new HashMap( cfg.getImports() );
+
+		// after *all* persisters and named queries are registered
+		Iterator iter = entityPersisters.values().iterator();
+		while ( iter.hasNext() ) {
+			( (EntityPersister) iter.next() ).postInstantiate();
+		}
+		iter = collectionPersisters.values().iterator();
+		while ( iter.hasNext() ) {
+			( (CollectionPersister) iter.next() ).postInstantiate();
+		}
+
+		//JNDI + Serialization:
+
+		name = settings.getSessionFactoryName();
+		try {
+			uuid = (String) UUID_GENERATOR.generate(null, null);
+		}
+		catch (Exception e) {
+			throw new AssertionFailure("Could not generate UUID");
+		}
+		SessionFactoryObjectFactory.addInstance(uuid, name, this, properties);
+
+		log.debug("instantiated session factory");
+
+		if ( settings.isAutoCreateSchema() ) {
+			new SchemaExport( cfg, settings ).create( false, true );
+		}
+		if ( settings.isAutoUpdateSchema() ) {
+			new SchemaUpdate( cfg, settings ).execute( false, true );
+		}
+		if ( settings.isAutoValidateSchema() ) {
+			new SchemaValidator( cfg, settings ).validate();
+		}
+		if ( settings.isAutoDropSchema() ) {
+			schemaExport = new SchemaExport( cfg, settings );
+		}
+
+		if ( settings.getTransactionManagerLookup()!=null ) {
+			log.debug("obtaining JTA TransactionManager");
+			transactionManager = settings.getTransactionManagerLookup().getTransactionManager(properties);
+		}
+		else {
+			if ( settings.getTransactionFactory().isTransactionManagerRequired() ) {
+				throw new HibernateException("The chosen transaction strategy requires access to the JTA TransactionManager");
+			}
+			transactionManager = null;
+		}
+
+		currentSessionContext = buildCurrentSessionContext();
+
+		if ( settings.isQueryCacheEnabled() ) {
+			updateTimestampsCache = new UpdateTimestampsCache(settings, properties);
+			queryCache = settings.getQueryCacheFactory()
+			        .getQueryCache(null, updateTimestampsCache, settings, properties);
+			queryCaches = new HashMap();
+			allCacheRegions.put( updateTimestampsCache.getRegion().getName(), updateTimestampsCache.getRegion() );
+			allCacheRegions.put( queryCache.getRegion().getName(), queryCache.getRegion() );
+		}
+		else {
+			updateTimestampsCache = null;
+			queryCache = null;
+			queryCaches = null;
+		}
+
+		//checking for named queries
+		if ( settings.isNamedQueryStartupCheckingEnabled() ) {
+			Map errors = checkNamedQueries();
+			if ( !errors.isEmpty() ) {
+				Set keys = errors.keySet();
+				StringBuffer failingQueries = new StringBuffer( "Errors in named queries: " );
+				for ( Iterator iterator = keys.iterator() ; iterator.hasNext() ; ) {
+					String queryName = ( String ) iterator.next();
+					HibernateException e = ( HibernateException ) errors.get( queryName );
+					failingQueries.append( queryName );
+					if ( iterator.hasNext() ) {
+						failingQueries.append( ", " );
+					}
+					log.error( "Error in named query: " + queryName, e );
+				}
+				throw new HibernateException( failingQueries.toString() );
+			}
+		}
+
+		//stats
+		getStatistics().setStatisticsEnabled( settings.isStatisticsEnabled() );
+
+		// EntityNotFoundDelegate
+		EntityNotFoundDelegate entityNotFoundDelegate = cfg.getEntityNotFoundDelegate();
+		if ( entityNotFoundDelegate == null ) {
+			entityNotFoundDelegate = new EntityNotFoundDelegate() {
+				public void handleEntityNotFound(String entityName, Serializable id) {
+					throw new ObjectNotFoundException( id, entityName );
+				}
+			};
+		}
+		this.entityNotFoundDelegate = entityNotFoundDelegate;
+	}
+
+	public QueryPlanCache getQueryPlanCache() {
+		return queryPlanCache;
+	}
+
+	private Map checkNamedQueries() throws HibernateException {
+		Map errors = new HashMap();
+
+		// Check named HQL queries
+		log.debug("Checking " + namedQueries.size() + " named HQL queries");
+		Iterator itr = namedQueries.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			final Map.Entry entry = ( Map.Entry ) itr.next();
+			final String queryName = ( String ) entry.getKey();
+			final NamedQueryDefinition qd = ( NamedQueryDefinition ) entry.getValue();
+			// this will throw an error if there's something wrong.
+			try {
+				log.debug("Checking named query: " + queryName);
+				//TODO: BUG! this currently fails for named queries for non-POJO entities
+				queryPlanCache.getHQLQueryPlan( qd.getQueryString(), false, CollectionHelper.EMPTY_MAP );
+			}
+			catch ( QueryException e ) {
+				errors.put( queryName, e );
+			}
+			catch ( MappingException e ) {
+				errors.put( queryName, e );
+			}
+		}
+
+		log.debug("Checking " + namedSqlQueries.size() + " named SQL queries");
+		itr = namedSqlQueries.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			final Map.Entry entry = ( Map.Entry ) itr.next();
+			final String queryName = ( String ) entry.getKey();
+			final NamedSQLQueryDefinition qd = ( NamedSQLQueryDefinition ) entry.getValue();
+			// this will throw an error if there's something wrong.
+			try {
+				log.debug("Checking named SQL query: " + queryName);
+				// TODO : would be really nice to cache the spec on the query-def so as to not have to re-calc the hash;
+				// currently not doable though because of the resultset-ref stuff...
+				NativeSQLQuerySpecification spec;
+				if ( qd.getResultSetRef() != null ) {
+					ResultSetMappingDefinition definition = ( ResultSetMappingDefinition ) sqlResultSetMappings.get( qd.getResultSetRef() );
+					if ( definition == null ) {
+						throw new MappingException( "Unable to find resultset-ref definition: " + qd.getResultSetRef() );
+					}
+					spec = new NativeSQLQuerySpecification(
+							qd.getQueryString(),
+					        definition.getQueryReturns(),
+					        qd.getQuerySpaces()
+					);
+				}
+				else {
+					spec =  new NativeSQLQuerySpecification(
+							qd.getQueryString(),
+					        qd.getQueryReturns(),
+					        qd.getQuerySpaces()
+					);
+				}
+				queryPlanCache.getNativeSQLQueryPlan( spec );
+			}
+			catch ( QueryException e ) {
+				errors.put( queryName, e );
+			}
+			catch ( MappingException e ) {
+				errors.put( queryName, e );
+			}
+		}
+
+		return errors;
+	}
+
+	public StatelessSession openStatelessSession() {
+		return new StatelessSessionImpl( null, this );
+	}
+
+	public StatelessSession openStatelessSession(Connection connection) {
+		return new StatelessSessionImpl( connection, this );
+	}
+
+	private SessionImpl openSession(
+		Connection connection,
+	    boolean autoClose,
+	    long timestamp,
+	    Interceptor sessionLocalInterceptor
+	) {
+		return new SessionImpl(
+		        connection,
+		        this,
+		        autoClose,
+		        timestamp,
+		        sessionLocalInterceptor == null ? interceptor : sessionLocalInterceptor,
+		        settings.getDefaultEntityMode(),
+		        settings.isFlushBeforeCompletionEnabled(),
+		        settings.isAutoCloseSessionEnabled(),
+		        settings.getConnectionReleaseMode()
+			);
+	}
+
+	public org.hibernate.classic.Session openSession(Connection connection, Interceptor sessionLocalInterceptor) {
+		return openSession(connection, false, Long.MIN_VALUE, sessionLocalInterceptor);
+	}
+
+	public org.hibernate.classic.Session openSession(Interceptor sessionLocalInterceptor)
+	throws HibernateException {
+		// note that this timestamp is not correct if the connection provider
+		// returns an older JDBC connection that was associated with a
+		// transaction that was already begun before openSession() was called
+		// (don't know any possible solution to this!)
+		long timestamp = settings.getRegionFactory().nextTimestamp();
+		return openSession( null, true, timestamp, sessionLocalInterceptor );
+	}
+
+	public org.hibernate.classic.Session openSession(Connection connection) {
+		return openSession(connection, interceptor); //prevents this session from adding things to cache
+	}
+
+	public org.hibernate.classic.Session openSession() throws HibernateException {
+		return openSession(interceptor);
+	}
+
+	public org.hibernate.classic.Session openTemporarySession() throws HibernateException {
+		return new SessionImpl(
+				null,
+		        this,
+		        true,
+		        settings.getRegionFactory().nextTimestamp(),
+		        interceptor,
+		        settings.getDefaultEntityMode(),
+		        false,
+		        false,
+		        ConnectionReleaseMode.AFTER_STATEMENT
+			);
+	}
+
+	public org.hibernate.classic.Session openSession(
+			final Connection connection,
+	        final boolean flushBeforeCompletionEnabled,
+	        final boolean autoCloseSessionEnabled,
+	        final ConnectionReleaseMode connectionReleaseMode) throws HibernateException {
+		return new SessionImpl(
+				connection,
+		        this,
+		        true,
+		        settings.getRegionFactory().nextTimestamp(),
+		        interceptor,
+		        settings.getDefaultEntityMode(),
+		        flushBeforeCompletionEnabled,
+		        autoCloseSessionEnabled,
+		        connectionReleaseMode
+			);
+	}
+
+	public org.hibernate.classic.Session getCurrentSession() throws HibernateException {
+		if ( currentSessionContext == null ) {
+			throw new HibernateException( "No CurrentSessionContext configured!" );
+		}
+		return currentSessionContext.currentSession();
+	}
+
+	public EntityPersister getEntityPersister(String entityName) throws MappingException {
+		EntityPersister result = (EntityPersister) entityPersisters.get(entityName);
+		if (result==null) {
+			throw new MappingException( "Unknown entity: " + entityName );
+		}
+		return result;
+	}
+
+	public CollectionPersister getCollectionPersister(String role) throws MappingException {
+		CollectionPersister result = (CollectionPersister) collectionPersisters.get(role);
+		if (result==null) {
+			throw new MappingException( "Unknown collection role: " + role );
+		}
+		return result;
+	}
+
+	public Settings getSettings() {
+		return settings;
+	}
+
+	public Dialect getDialect() {
+		return settings.getDialect();
+	}
+
+	public Interceptor getInterceptor()
+	{
+		return interceptor;
+	}
+
+	public TransactionFactory getTransactionFactory() {
+		return settings.getTransactionFactory();
+	}
+
+	public TransactionManager getTransactionManager() {
+		return transactionManager;
+	}
+
+	public SQLExceptionConverter getSQLExceptionConverter() {
+		return settings.getSQLExceptionConverter();
+	}
+
+	public Set getCollectionRolesByEntityParticipant(String entityName) {
+		return ( Set ) collectionRolesByEntityParticipant.get( entityName );
+	}
+
+	// from javax.naming.Referenceable
+	public Reference getReference() throws NamingException {
+		log.debug("Returning a Reference to the SessionFactory");
+		return new Reference(
+			SessionFactoryImpl.class.getName(),
+		    new StringRefAddr("uuid", uuid),
+		    SessionFactoryObjectFactory.class.getName(),
+		    null
+		);
+	}
+
+	private Object readResolve() throws ObjectStreamException {
+		log.trace("Resolving serialized SessionFactory");
+		// look for the instance by uuid
+		Object result = SessionFactoryObjectFactory.getInstance(uuid);
+		if (result==null) {
+			// in case we were deserialized in a different JVM, look for an instance with the same name
+			// (alternatively we could do an actual JNDI lookup here....)
+			result = SessionFactoryObjectFactory.getNamedInstance(name);
+			if (result==null) {
+				throw new InvalidObjectException("Could not find a SessionFactory named: " + name);
+			}
+			else {
+				log.debug("resolved SessionFactory by name");
+			}
+		}
+		else {
+			log.debug("resolved SessionFactory by uid");
+		}
+		return result;
+	}
+
+	public NamedQueryDefinition getNamedQuery(String queryName) {
+		return (NamedQueryDefinition) namedQueries.get(queryName);
+	}
+
+	public NamedSQLQueryDefinition getNamedSQLQuery(String queryName) {
+		return (NamedSQLQueryDefinition) namedSqlQueries.get(queryName);
+	}
+
+	public ResultSetMappingDefinition getResultSetMapping(String resultSetName) {
+		return (ResultSetMappingDefinition) sqlResultSetMappings.get(resultSetName);
+	}
+
+	public Type getIdentifierType(String className) throws MappingException {
+		return getEntityPersister(className).getIdentifierType();
+	}
+	public String getIdentifierPropertyName(String className) throws MappingException {
+		return getEntityPersister(className).getIdentifierPropertyName();
+	}
+
+	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+		log.trace("deserializing");
+		in.defaultReadObject();
+		log.debug("deserialized: " + uuid);
+	}
+
+	private void writeObject(ObjectOutputStream out) throws IOException {
+		log.debug("serializing: " + uuid);
+		out.defaultWriteObject();
+		log.trace("serialized");
+	}
+
+	public Type[] getReturnTypes(String queryString) throws HibernateException {
+		return queryPlanCache.getHQLQueryPlan( queryString, false, CollectionHelper.EMPTY_MAP ).getReturnMetadata().getReturnTypes();
+	}
+
+	public String[] getReturnAliases(String queryString) throws HibernateException {
+		return queryPlanCache.getHQLQueryPlan( queryString, false, CollectionHelper.EMPTY_MAP ).getReturnMetadata().getReturnAliases();
+	}
+
+	public ClassMetadata getClassMetadata(Class persistentClass) throws HibernateException {
+		return getClassMetadata( persistentClass.getName() );
+	}
+
+	public CollectionMetadata getCollectionMetadata(String roleName) throws HibernateException {
+		return (CollectionMetadata) collectionMetadata.get(roleName);
+	}
+
+	public ClassMetadata getClassMetadata(String entityName) throws HibernateException {
+		return (ClassMetadata) classMetadata.get(entityName);
+	}
+
+	/**
+	 * Return the names of all persistent (mapped) classes that extend or implement the
+	 * given class or interface, accounting for implicit/explicit polymorphism settings
+	 * and excluding mapped subclasses/joined-subclasses of other classes in the result.
+	 */
+	public String[] getImplementors(String className) throws MappingException {
+
+		final Class clazz;
+		try {
+			clazz = ReflectHelper.classForName(className);
+		}
+		catch (ClassNotFoundException cnfe) {
+			return new String[] { className }; //for a dynamic-class
+		}
+
+		ArrayList results = new ArrayList();
+		Iterator iter = entityPersisters.values().iterator();
+		while ( iter.hasNext() ) {
+			//test this entity to see if we must query it
+			EntityPersister testPersister = (EntityPersister) iter.next();
+			if ( testPersister instanceof Queryable ) {
+				Queryable testQueryable = (Queryable) testPersister;
+				String testClassName = testQueryable.getEntityName();
+				boolean isMappedClass = className.equals(testClassName);
+				if ( testQueryable.isExplicitPolymorphism() ) {
+					if ( isMappedClass ) {
+						return new String[] {className}; //NOTE EARLY EXIT
+					}
+				}
+				else {
+					if (isMappedClass) {
+						results.add(testClassName);
+					}
+					else {
+						final Class mappedClass = testQueryable.getMappedClass( EntityMode.POJO );
+						if ( mappedClass!=null && clazz.isAssignableFrom( mappedClass ) ) {
+							final boolean assignableSuperclass;
+							if ( testQueryable.isInherited() ) {
+								Class mappedSuperclass = getEntityPersister( testQueryable.getMappedSuperclass() ).getMappedClass( EntityMode.POJO);
+								assignableSuperclass = clazz.isAssignableFrom(mappedSuperclass);
+							}
+							else {
+								assignableSuperclass = false;
+							}
+							if ( !assignableSuperclass ) {
+								results.add( testClassName );
+							}
+						}
+					}
+				}
+			}
+		}
+		return (String[]) results.toArray( new String[ results.size() ] );
+	}
+
+	public String getImportedClassName(String className) {
+		String result = (String) imports.get(className);
+		if (result==null) {
+			try {
+				ReflectHelper.classForName(className);
+				return className;
+			}
+			catch (ClassNotFoundException cnfe) {
+				return null;
+			}
+		}
+		else {
+			return result;
+		}
+	}
+
+	public Map getAllClassMetadata() throws HibernateException {
+		return classMetadata;
+	}
+
+	public Map getAllCollectionMetadata() throws HibernateException {
+		return collectionMetadata;
+	}
+
+	/**
+	 * Closes the session factory, releasing all held resources.
+	 *
+	 * <ol>
+	 * <li>cleans up used cache regions and "stops" the cache provider.
+	 * <li>close the JDBC connection
+	 * <li>remove the JNDI binding
+	 * </ol>
+	 *
+	 * Note: Be aware that the sessionfactory instance still can
+	 * be a "heavy" object memory wise after close() has been called.  Thus
+	 * it is important to not keep referencing the instance to let the garbage
+	 * collector release the memory.
+	 */
+	public void close() throws HibernateException {
+
+		log.info("closing");
+
+		isClosed = true;
+
+		Iterator iter = entityPersisters.values().iterator();
+		while ( iter.hasNext() ) {
+			EntityPersister p = (EntityPersister) iter.next();
+			if ( p.hasCache() ) {
+				p.getCacheAccessStrategy().destroy();
+			}
+		}
+
+		iter = collectionPersisters.values().iterator();
+		while ( iter.hasNext() ) {
+			CollectionPersister p = (CollectionPersister) iter.next();
+			if ( p.hasCache() ) {
+				p.getCacheAccessStrategy().destroy();
+			}
+		}
+
+		if ( settings.isQueryCacheEnabled() )  {
+			queryCache.destroy();
+
+			iter = queryCaches.values().iterator();
+			while ( iter.hasNext() ) {
+				QueryCache cache = (QueryCache) iter.next();
+				cache.destroy();
+			}
+			updateTimestampsCache.destroy();
+		}
+
+		settings.getRegionFactory().stop();
+
+		try {
+			settings.getConnectionProvider().close();
+		}
+		finally {
+			SessionFactoryObjectFactory.removeInstance(uuid, name, properties);
+		}
+
+		if ( settings.isAutoDropSchema() ) {
+			schemaExport.drop( false, true );
+		}
+
+	}
+
+	public void evictEntity(String entityName, Serializable id) throws HibernateException {
+		EntityPersister p = getEntityPersister( entityName );
+		if ( p.hasCache() ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "evicting second-level cache: " + MessageHelper.infoString(p, id, this) );
+			}
+			CacheKey cacheKey = new CacheKey( id, p.getIdentifierType(), p.getRootEntityName(), EntityMode.POJO, this );
+			p.getCacheAccessStrategy().evict( cacheKey );
+		}
+	}
+
+	public void evictEntity(String entityName) throws HibernateException {
+		EntityPersister p = getEntityPersister( entityName );
+		if ( p.hasCache() ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "evicting second-level cache: " + p.getEntityName() );
+			}
+			p.getCacheAccessStrategy().evictAll();
+		}
+	}
+
+	public void evict(Class persistentClass, Serializable id) throws HibernateException {
+		EntityPersister p = getEntityPersister( persistentClass.getName() );
+		if ( p.hasCache() ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "evicting second-level cache: " + MessageHelper.infoString(p, id, this) );
+			}
+			CacheKey cacheKey = new CacheKey( id, p.getIdentifierType(), p.getRootEntityName(), EntityMode.POJO, this );
+			p.getCacheAccessStrategy().evict( cacheKey );
+		}
+	}
+
+	public void evict(Class persistentClass) throws HibernateException {
+		EntityPersister p = getEntityPersister( persistentClass.getName() );
+		if ( p.hasCache() ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "evicting second-level cache: " + p.getEntityName() );
+			}
+			p.getCacheAccessStrategy().evictAll();
+		}
+	}
+
+	public void evictCollection(String roleName, Serializable id) throws HibernateException {
+		CollectionPersister p = getCollectionPersister( roleName );
+		if ( p.hasCache() ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "evicting second-level cache: " + MessageHelper.collectionInfoString(p, id, this) );
+			}
+			CacheKey cacheKey = new CacheKey( id, p.getKeyType(), p.getRole(), EntityMode.POJO, this );
+			p.getCacheAccessStrategy().evict( cacheKey );
+		}
+	}
+
+	public void evictCollection(String roleName) throws HibernateException {
+		CollectionPersister p = getCollectionPersister( roleName );
+		if ( p.hasCache() ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "evicting second-level cache: " + p.getRole() );
+			}
+			p.getCacheAccessStrategy().evictAll();
+		}
+	}
+
+	public Type getReferencedPropertyType(String className, String propertyName)
+		throws MappingException {
+		return getEntityPersister(className).getPropertyType(propertyName);
+	}
+
+	public ConnectionProvider getConnectionProvider() {
+		return settings.getConnectionProvider();
+	}
+
+	public UpdateTimestampsCache getUpdateTimestampsCache() {
+		return updateTimestampsCache;
+	}
+
+	public QueryCache getQueryCache() {
+		return queryCache;
+	}
+
+	public QueryCache getQueryCache(String regionName) throws HibernateException {
+		if ( regionName == null ) {
+			return getQueryCache();
+		}
+
+		if ( !settings.isQueryCacheEnabled() ) {
+			return null;
+		}
+
+		synchronized ( allCacheRegions ) {
+			QueryCache currentQueryCache = ( QueryCache ) queryCaches.get( regionName );
+			if ( currentQueryCache == null ) {
+				currentQueryCache = settings.getQueryCacheFactory().getQueryCache( regionName, updateTimestampsCache, settings, properties );
+				queryCaches.put( regionName, currentQueryCache );
+				allCacheRegions.put( currentQueryCache.getRegion().getName(), currentQueryCache.getRegion() );
+			}
+			return currentQueryCache;
+		}
+	}
+
+	public Region getSecondLevelCacheRegion(String regionName) {
+		synchronized ( allCacheRegions ) {
+			return ( Region ) allCacheRegions.get( regionName );
+		}
+	}
+
+	public Map getAllSecondLevelCacheRegions() {
+		synchronized ( allCacheRegions ) {
+			return new HashMap( allCacheRegions );
+		}
+	}
+
+	public boolean isClosed() {
+		return isClosed;
+	}
+
+	public Statistics getStatistics() {
+		return statistics;
+	}
+
+	public StatisticsImplementor getStatisticsImplementor() {
+		return statistics;
+	}
+
+	public void evictQueries() throws HibernateException {
+		if ( settings.isQueryCacheEnabled() ) {
+			queryCache.clear();
+		}
+	}
+
+	public void evictQueries(String cacheRegion) throws HibernateException {
+		if (cacheRegion==null) {
+			throw new NullPointerException("use the zero-argument form to evict the default query cache");
+		}
+		else {
+			synchronized (allCacheRegions) {
+				if ( settings.isQueryCacheEnabled() ) {
+					QueryCache currentQueryCache = (QueryCache) queryCaches.get(cacheRegion);
+					if ( currentQueryCache != null ) {
+						currentQueryCache.clear();
+					}
+				}
+			}
+		}
+	}
+
+	public FilterDefinition getFilterDefinition(String filterName) throws HibernateException {
+		FilterDefinition def = ( FilterDefinition ) filters.get( filterName );
+		if ( def == null ) {
+			throw new HibernateException( "No such filter configured [" + filterName + "]" );
+		}
+		return def;
+	}
+
+	public Set getDefinedFilterNames() {
+		return filters.keySet();
+	}
+
+	public BatcherFactory getBatcherFactory() {
+		return settings.getBatcherFactory();
+	}
+
+	public IdentifierGenerator getIdentifierGenerator(String rootEntityName) {
+		return (IdentifierGenerator) identifierGenerators.get(rootEntityName);
+	}
+
+	private CurrentSessionContext buildCurrentSessionContext() {
+		String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS );
+		// for backward-compatability
+		if ( impl == null && transactionManager != null ) {
+			impl = "jta";
+		}
+
+		if ( impl == null ) {
+			return null;
+		}
+		else if ( "jta".equals( impl ) ) {
+			if ( settings.getTransactionFactory().areCallbacksLocalToHibernateTransactions() ) {
+				log.warn( "JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()" );
+			}
+			return new JTASessionContext( this );
+		}
+		else if ( "thread".equals( impl ) ) {
+			return new ThreadLocalSessionContext( this );
+		}
+		else if ( "managed".equals( impl ) ) {
+			return new ManagedSessionContext( this );
+		}
+		else {
+			try {
+				Class implClass = ReflectHelper.classForName( impl );
+				return ( CurrentSessionContext ) implClass
+						.getConstructor( new Class[] { SessionFactoryImplementor.class } )
+						.newInstance( new Object[] { this } );
+			}
+			catch( Throwable t ) {
+				log.error( "Unable to construct current session context [" + impl + "]", t );
+				return null;
+			}
+		}
+	}
+
+	public EventListeners getEventListeners()
+	{
+		return eventListeners;
+	}
+
+	public EntityNotFoundDelegate getEntityNotFoundDelegate() {
+		return entityNotFoundDelegate;
+	}
+
+	/**
+	 * Custom serialization hook used during Session serialization.
+	 *
+	 * @param oos The stream to which to write the factory
+	 * @throws IOException Indicates problems writing out the serial data stream
+	 */
+	void serialize(ObjectOutputStream oos) throws IOException {
+		oos.writeUTF( uuid );
+		oos.writeBoolean( name != null );
+		if ( name != null ) {
+			oos.writeUTF( name );
+		}
+	}
+
+	/**
+	 * Custom deserialization hook used during Session deserialization.
+	 *
+	 * @param ois The stream from which to "read" the factory
+	 * @return The deserialized factory
+	 * @throws IOException indicates problems reading back serial data stream
+	 * @throws ClassNotFoundException indicates problems reading back serial data stream
+	 */
+	static SessionFactoryImpl deserialize(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+		String uuid = ois.readUTF();
+		boolean isNamed = ois.readBoolean();
+		String name = null;
+		if ( isNamed ) {
+			name = ois.readUTF();
+		}
+		Object result = SessionFactoryObjectFactory.getInstance( uuid );
+		if ( result == null ) {
+			log.trace( "could not locate session factory by uuid [" + uuid + "] during session deserialization; trying name" );
+			if ( isNamed ) {
+				result = SessionFactoryObjectFactory.getNamedInstance( name );
+			}
+			if ( result == null ) {
+				throw new InvalidObjectException( "could not resolve session factory during session deserialization [uuid=" + uuid + ", name=" + name + "]" );
+			}
+		}
+		return ( SessionFactoryImpl ) result;
+	}
+
+	public SQLFunctionRegistry getSqlFunctionRegistry() {
+		return sqlFunctionRegistry;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SessionFactoryObjectFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SessionFactoryObjectFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SessionFactoryObjectFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,161 @@
+//$Id: SessionFactoryObjectFactory.java 11337 2007-03-22 22:42:58Z epbernard $
+package org.hibernate.impl;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.event.EventContext;
+import javax.naming.event.NamespaceChangeListener;
+import javax.naming.event.NamingEvent;
+import javax.naming.event.NamingExceptionEvent;
+import javax.naming.event.NamingListener;
+import javax.naming.spi.ObjectFactory;
+
+import org.hibernate.SessionFactory;
+import org.hibernate.util.FastHashMap;
+import org.hibernate.util.NamingHelper;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Resolves <tt>SessionFactory</tt> JNDI lookups and deserialization
+ */
+public class SessionFactoryObjectFactory implements ObjectFactory {
+
+	private static final SessionFactoryObjectFactory INSTANCE; //to stop the class from being unloaded
+
+	private static final Log log;
+
+	static {
+		log = LogFactory.getLog(SessionFactoryObjectFactory.class);
+		INSTANCE = new SessionFactoryObjectFactory();
+		log.debug("initializing class SessionFactoryObjectFactory");
+	}
+
+	private static final FastHashMap INSTANCES = new FastHashMap();
+	private static final FastHashMap NAMED_INSTANCES = new FastHashMap();
+
+	private static final NamingListener LISTENER = new NamespaceChangeListener() {
+		public void objectAdded(NamingEvent evt) {
+			log.debug( "A factory was successfully bound to name: " + evt.getNewBinding().getName() );
+		}
+		public void objectRemoved(NamingEvent evt) {
+			String name = evt.getOldBinding().getName();
+			log.info("A factory was unbound from name: " + name);
+			Object instance = NAMED_INSTANCES.remove(name);
+			Iterator iter = INSTANCES.values().iterator();
+			while ( iter.hasNext() ) {
+				if ( iter.next()==instance ) iter.remove();
+			}
+		}
+		public void objectRenamed(NamingEvent evt) {
+			String name = evt.getOldBinding().getName();
+			log.info("A factory was renamed from name: " + name);
+			NAMED_INSTANCES.put( evt.getNewBinding().getName(), NAMED_INSTANCES.remove(name) );
+		}
+		public void namingExceptionThrown(NamingExceptionEvent evt) {
+			log.warn( "Naming exception occurred accessing factory: " + evt.getException() );
+		}
+	};
+
+	public Object getObjectInstance(Object reference, Name name, Context ctx, Hashtable env) throws Exception {
+		log.debug("JNDI lookup: " + name);
+		String uid = (String) ( (Reference) reference ).get(0).getContent();
+		return getInstance(uid);
+	}
+
+	public static void addInstance(String uid, String name, SessionFactory instance, Properties properties) {
+
+		log.debug("registered: " + uid + " (" + ( (name==null) ? "unnamed" : name ) + ')');
+		INSTANCES.put(uid, instance);
+		if (name!=null) NAMED_INSTANCES.put(name, instance);
+
+		//must add to JNDI _after_ adding to HashMaps, because some JNDI servers use serialization
+		if (name==null) {
+			log.info("Not binding factory to JNDI, no JNDI name configured");
+		}
+		else {
+
+			log.info("Factory name: " + name);
+
+			try {
+				Context ctx = NamingHelper.getInitialContext(properties);
+				NamingHelper.bind(ctx, name, instance);
+				log.info("Bound factory to JNDI name: " + name);
+				( (EventContext) ctx ).addNamingListener(name, EventContext.OBJECT_SCOPE, LISTENER);
+			}
+			catch (InvalidNameException ine) {
+				log.error("Invalid JNDI name: " + name, ine);
+			}
+			catch (NamingException ne) {
+				log.warn("Could not bind factory to JNDI", ne);
+			}
+			catch(ClassCastException cce) {
+				log.warn("InitialContext did not implement EventContext");
+			}
+
+		}
+
+	}
+
+	public static void removeInstance(String uid, String name, Properties properties) {
+		//TODO: theoretically non-threadsafe...
+
+		if (name!=null) {
+			log.info("Unbinding factory from JNDI name: " + name);
+
+			try {
+				Context ctx = NamingHelper.getInitialContext(properties);
+				ctx.unbind(name);
+				log.info("Unbound factory from JNDI name: " + name);
+			}
+			catch (InvalidNameException ine) {
+				log.error("Invalid JNDI name: " + name, ine);
+			}
+			catch (NamingException ne) {
+				log.warn("Could not unbind factory from JNDI", ne);
+			}
+
+			NAMED_INSTANCES.remove(name);
+
+		}
+
+		INSTANCES.remove(uid);
+
+	}
+
+	public static Object getNamedInstance(String name) {
+		log.debug("lookup: name=" + name);
+		Object result = NAMED_INSTANCES.get(name);
+		if (result==null) {
+			log.debug("Not found: " + name);
+			log.debug(NAMED_INSTANCES);
+		}
+		return result;
+	}
+
+	public static Object getInstance(String uid) {
+		log.debug("lookup: uid=" + uid);
+		Object result = INSTANCES.get(uid);
+		if (result==null) {
+			log.debug("Not found: " + uid);
+			log.debug(INSTANCES);
+		}
+		return result;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SessionImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SessionImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/SessionImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1958 @@
+//$Id: SessionImpl.java 10688 2006-11-02 18:53:25Z steve.ebersole at jboss.com $
+package org.hibernate.impl;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.sql.Connection;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.dom4j.Element;
+import org.hibernate.CacheMode;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.Criteria;
+import org.hibernate.EntityMode;
+import org.hibernate.Filter;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.ObjectDeletedException;
+import org.hibernate.Query;
+import org.hibernate.QueryException;
+import org.hibernate.ReplicationMode;
+import org.hibernate.SQLQuery;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.SessionException;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.TransientObjectException;
+import org.hibernate.UnresolvableObjectException;
+import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.ActionQueue;
+import org.hibernate.engine.CollectionEntry;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.FilterDefinition;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.StatefulPersistenceContext;
+import org.hibernate.engine.Status;
+import org.hibernate.engine.query.FilterQueryPlan;
+import org.hibernate.engine.query.HQLQueryPlan;
+import org.hibernate.engine.query.NativeSQLQueryPlan;
+import org.hibernate.event.AutoFlushEvent;
+import org.hibernate.event.AutoFlushEventListener;
+import org.hibernate.event.DeleteEvent;
+import org.hibernate.event.DeleteEventListener;
+import org.hibernate.event.DirtyCheckEvent;
+import org.hibernate.event.DirtyCheckEventListener;
+import org.hibernate.event.EventListeners;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.EvictEvent;
+import org.hibernate.event.EvictEventListener;
+import org.hibernate.event.FlushEvent;
+import org.hibernate.event.FlushEventListener;
+import org.hibernate.event.InitializeCollectionEvent;
+import org.hibernate.event.InitializeCollectionEventListener;
+import org.hibernate.event.LoadEvent;
+import org.hibernate.event.LoadEventListener;
+import org.hibernate.event.LockEvent;
+import org.hibernate.event.LockEventListener;
+import org.hibernate.event.MergeEvent;
+import org.hibernate.event.MergeEventListener;
+import org.hibernate.event.PersistEvent;
+import org.hibernate.event.PersistEventListener;
+import org.hibernate.event.RefreshEvent;
+import org.hibernate.event.RefreshEventListener;
+import org.hibernate.event.ReplicateEvent;
+import org.hibernate.event.ReplicateEventListener;
+import org.hibernate.event.SaveOrUpdateEvent;
+import org.hibernate.event.SaveOrUpdateEventListener;
+import org.hibernate.event.LoadEventListener.LoadType;
+import org.hibernate.jdbc.Batcher;
+import org.hibernate.jdbc.JDBCContext;
+import org.hibernate.loader.criteria.CriteriaLoader;
+import org.hibernate.loader.custom.CustomLoader;
+import org.hibernate.loader.custom.CustomQuery;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+import org.hibernate.stat.SessionStatistics;
+import org.hibernate.stat.SessionStatisticsImpl;
+import org.hibernate.tuple.DynamicMapInstantiator;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.CollectionHelper;
+import org.hibernate.util.StringHelper;
+
+
+/**
+ * Concrete implementation of a Session, and also the central, organizing component
+ * of Hibernate's internal implementation. As such, this class exposes two interfaces;
+ * Session itself, to the application, and SessionImplementor, to other components
+ * of Hibernate. This class is not threadsafe.
+ *
+ * @author Gavin King
+ */
+public final class SessionImpl extends AbstractSessionImpl 
+		implements EventSource, org.hibernate.classic.Session, JDBCContext.Context {
+
+	// todo : need to find a clean way to handle the "event source" role
+	// a seperate classs responsible for generating/dispatching events just duplicates most of the Session methods...
+	// passing around seperate reto interceptor, factory, actionQueue, and persistentContext is not manageable...
+
+	private static final Log log = LogFactory.getLog(SessionImpl.class);
+
+	private transient EntityMode entityMode = EntityMode.POJO;
+	private transient boolean autoClear; //for EJB3
+	
+	private transient long timestamp;
+	private transient FlushMode flushMode = FlushMode.AUTO;
+	private transient CacheMode cacheMode = CacheMode.NORMAL;
+
+	private transient Interceptor interceptor;
+
+	private transient int dontFlushFromFind = 0;
+
+	private transient ActionQueue actionQueue;
+	private transient StatefulPersistenceContext persistenceContext;
+	private transient JDBCContext jdbcContext;
+	private transient EventListeners listeners;
+
+	private transient boolean flushBeforeCompletionEnabled;
+	private transient boolean autoCloseSessionEnabled;
+	private transient ConnectionReleaseMode connectionReleaseMode;
+	
+	private transient String fetchProfile;
+
+	private transient Map enabledFilters = new HashMap();
+
+	private transient Session rootSession;
+	private transient Map childSessionsByEntityMode;
+
+	/**
+	 * Constructor used in building "child sessions".
+	 *
+	 * @param parent The parent session
+	 * @param entityMode
+	 */
+	private SessionImpl(SessionImpl parent, EntityMode entityMode) {
+		super( parent.factory );
+		this.rootSession = parent;
+		this.timestamp = parent.timestamp;
+		this.jdbcContext = parent.jdbcContext;
+		this.interceptor = parent.interceptor;
+		this.listeners = parent.listeners;
+		this.actionQueue = new ActionQueue( this );
+		this.entityMode = entityMode;
+		this.persistenceContext = new StatefulPersistenceContext( this );
+		this.flushBeforeCompletionEnabled = false;
+		this.autoCloseSessionEnabled = false;
+		this.connectionReleaseMode = null;
+
+		if ( factory.getStatistics().isStatisticsEnabled() ) {
+			factory.getStatisticsImplementor().openSession();
+		}
+
+		log.debug( "opened session [" + entityMode + "]" );
+	}
+
+	/**
+	 * Constructor used for openSession(...) processing, as well as construction
+	 * of sessions for getCurrentSession().
+	 *
+	 * @param connection The user-supplied connection to use for this session.
+	 * @param factory The factory from which this session was obtained
+	 * @param autoclose NOT USED
+	 * @param timestamp The timestamp for this session
+	 * @param interceptor The interceptor to be applied to this session
+	 * @param entityMode The entity-mode for this session
+	 * @param flushBeforeCompletionEnabled Should we auto flush before completion of transaction
+	 * @param autoCloseSessionEnabled Should we auto close after completion of transaction
+	 * @param connectionReleaseMode The mode by which we should release JDBC connections.
+	 */
+	SessionImpl(
+			final Connection connection,
+			final SessionFactoryImpl factory,
+			final boolean autoclose,
+			final long timestamp,
+			final Interceptor interceptor,
+			final EntityMode entityMode,
+			final boolean flushBeforeCompletionEnabled,
+			final boolean autoCloseSessionEnabled,
+			final ConnectionReleaseMode connectionReleaseMode) {
+		super( factory );
+		this.rootSession = null;
+		this.timestamp = timestamp;
+		this.entityMode = entityMode;
+		this.interceptor = interceptor;
+		this.listeners = factory.getEventListeners();
+		this.actionQueue = new ActionQueue( this );
+		this.persistenceContext = new StatefulPersistenceContext( this );
+		this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled;
+		this.autoCloseSessionEnabled = autoCloseSessionEnabled;
+		this.connectionReleaseMode = connectionReleaseMode;
+		this.jdbcContext = new JDBCContext( this, connection, interceptor );
+
+		if ( factory.getStatistics().isStatisticsEnabled() ) {
+			factory.getStatisticsImplementor().openSession();
+		}
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( "opened session at timestamp: " + timestamp );
+		}
+	}
+
+	public Session getSession(EntityMode entityMode) {
+		if ( this.entityMode == entityMode ) {
+			return this;
+		}
+
+		if ( rootSession != null ) {
+			rootSession.getSession( entityMode );
+		}
+
+		errorIfClosed();
+		checkTransactionSynchStatus();
+
+		SessionImpl rtn = null;
+		if ( childSessionsByEntityMode == null ) {
+			childSessionsByEntityMode = new HashMap();
+		}
+		else {
+			rtn = (SessionImpl) childSessionsByEntityMode.get( entityMode );
+		}
+
+		if ( rtn == null ) {
+			rtn = new SessionImpl( this, entityMode );
+			childSessionsByEntityMode.put( entityMode, rtn );
+		}
+
+		return rtn;
+	}
+
+	public void clear() {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		persistenceContext.clear();
+		actionQueue.clear();
+	}
+
+	public Batcher getBatcher() {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		// TODO : should remove this exposure
+		//  and have all references to the session's batcher use the ConnectionManager.
+		return jdbcContext.getConnectionManager().getBatcher();
+	}
+
+	public long getTimestamp() {
+		checkTransactionSynchStatus();
+		return timestamp;
+	}
+
+	public Connection close() throws HibernateException {
+		log.trace( "closing session" );
+		if ( isClosed() ) {
+			throw new SessionException( "Session was already closed" );
+		}
+		
+
+		if ( factory.getStatistics().isStatisticsEnabled() ) {
+			factory.getStatisticsImplementor().closeSession();
+		}
+
+		try {
+			try {
+				if ( childSessionsByEntityMode != null ) {
+					Iterator childSessions = childSessionsByEntityMode.values().iterator();
+					while ( childSessions.hasNext() ) {
+						final SessionImpl child = ( SessionImpl ) childSessions.next();
+						child.close();
+					}
+				}
+			}
+			catch( Throwable t ) {
+				// just ignore
+			}
+
+			if ( rootSession == null ) {
+				return jdbcContext.getConnectionManager().close();
+			}
+			else {
+				return null;
+			}
+		}
+		finally {
+			setClosed();
+			cleanup();
+		}
+	}
+
+	public ConnectionReleaseMode getConnectionReleaseMode() {
+		checkTransactionSynchStatus();
+		return connectionReleaseMode;
+	}
+
+	public boolean isAutoCloseSessionEnabled() {
+		return autoCloseSessionEnabled;
+	}
+
+	public boolean isOpen() {
+		checkTransactionSynchStatus();
+		return !isClosed();
+	}
+
+	public boolean isFlushModeNever() {
+		return FlushMode.isManualFlushMode( getFlushMode() );
+	}
+
+	public boolean isFlushBeforeCompletionEnabled() {
+		return flushBeforeCompletionEnabled;
+	}
+
+	public void managedFlush() {
+		if ( isClosed() ) {
+			log.trace( "skipping auto-flush due to session closed" );
+			return;
+		}
+		log.trace("automatically flushing session");
+		flush();
+		
+		if ( childSessionsByEntityMode != null ) {
+			Iterator iter = childSessionsByEntityMode.values().iterator();
+			while ( iter.hasNext() ) {
+				( (Session) iter.next() ).flush();
+			}
+		}
+	}
+
+	public boolean shouldAutoClose() {
+		return isAutoCloseSessionEnabled() && !isClosed();
+	}
+
+	public void managedClose() {
+		log.trace( "automatically closing session" );
+		close();
+	}
+
+	public Connection connection() throws HibernateException {
+		errorIfClosed();
+		return jdbcContext.borrowConnection();
+	}
+
+	public boolean isConnected() {
+		checkTransactionSynchStatus();
+		return !isClosed() && jdbcContext.getConnectionManager().isCurrentlyConnected();
+	}
+	
+	public boolean isTransactionInProgress() {
+		checkTransactionSynchStatus();
+		return !isClosed() && jdbcContext.isTransactionInProgress();
+	}
+
+	public Connection disconnect() throws HibernateException {
+		errorIfClosed();
+		log.debug( "disconnecting session" );
+		return jdbcContext.getConnectionManager().manualDisconnect();
+	}
+
+	public void reconnect() throws HibernateException {
+		errorIfClosed();
+		log.debug( "reconnecting session" );
+		checkTransactionSynchStatus();
+		jdbcContext.getConnectionManager().manualReconnect();
+	}
+
+	public void reconnect(Connection conn) throws HibernateException {
+		errorIfClosed();
+		log.debug( "reconnecting session" );
+		checkTransactionSynchStatus();
+		jdbcContext.getConnectionManager().manualReconnect( conn );
+	}
+
+	public void beforeTransactionCompletion(Transaction tx) {
+		log.trace( "before transaction completion" );
+		if ( rootSession == null ) {
+			try {
+				interceptor.beforeTransactionCompletion(tx);
+			}
+			catch (Throwable t) {
+				log.error("exception in interceptor beforeTransactionCompletion()", t);
+			}
+		}
+	}
+	
+	public void setAutoClear(boolean enabled) {
+		errorIfClosed();
+		autoClear = enabled;
+	}
+	
+	/**
+	 * Check if there is a Hibernate or JTA transaction in progress and, 
+	 * if there is not, flush if necessary, make sure the connection has 
+	 * been committed (if it is not in autocommit mode) and run the after 
+	 * completion processing
+	 */
+	public void afterOperation(boolean success) {
+		if ( !jdbcContext.isTransactionInProgress() ) {
+			jdbcContext.afterNontransactionalQuery( success );
+		}
+	}
+
+	public void afterTransactionCompletion(boolean success, Transaction tx) {
+		log.trace( "after transaction completion" );
+		persistenceContext.afterTransactionCompletion();
+		actionQueue.afterTransactionCompletion(success);
+		if ( rootSession == null && tx != null ) {
+			try {
+				interceptor.afterTransactionCompletion(tx);
+			}
+			catch (Throwable t) {
+				log.error("exception in interceptor afterTransactionCompletion()", t);
+			}
+		}
+		if ( autoClear ) {
+			clear();
+		}
+	}
+
+	/**
+	 * clear all the internal collections, just 
+	 * to help the garbage collector, does not
+	 * clear anything that is needed during the
+	 * afterTransactionCompletion() phase
+	 */
+	private void cleanup() {
+		persistenceContext.clear();
+	}
+
+	public LockMode getCurrentLockMode(Object object) throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		if ( object == null ) {
+			throw new NullPointerException( "null object passed to getCurrentLockMode()" );
+		}
+		if ( object instanceof HibernateProxy ) {
+			object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation(this);
+			if ( object == null ) {
+				return LockMode.NONE;
+			}
+		}
+		EntityEntry e = persistenceContext.getEntry(object);
+		if ( e == null ) {
+			throw new TransientObjectException( "Given object not associated with the session" );
+		}
+		if ( e.getStatus() != Status.MANAGED ) {
+			throw new ObjectDeletedException( 
+					"The given object was deleted", 
+					e.getId(), 
+					e.getPersister().getEntityName() 
+				);
+		}
+		return e.getLockMode();
+	}
+
+	public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException {
+		errorIfClosed();
+		// todo : should this get moved to PersistentContext?
+		// logically, is PersistentContext the "thing" to which an interceptor gets attached?
+		final Object result = persistenceContext.getEntity(key);
+		if ( result == null ) {
+			final Object newObject = interceptor.getEntity( key.getEntityName(), key.getIdentifier() );
+			if ( newObject != null ) {
+				lock( newObject, LockMode.NONE );
+			}
+			return newObject;
+		}
+		else {
+			return result;
+		}
+	}
+
+
+	// saveOrUpdate() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void saveOrUpdate(Object object) throws HibernateException {
+		saveOrUpdate(null, object);
+	}
+
+	public void saveOrUpdate(String entityName, Object obj) throws HibernateException {
+		fireSaveOrUpdate( new SaveOrUpdateEvent(entityName, obj, this) );
+	}
+
+	private void fireSaveOrUpdate(SaveOrUpdateEvent event) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		SaveOrUpdateEventListener[] saveOrUpdateEventListener = listeners.getSaveOrUpdateEventListeners();
+		for ( int i = 0; i < saveOrUpdateEventListener.length; i++ ) {
+			saveOrUpdateEventListener[i].onSaveOrUpdate(event);
+		}
+	}
+
+
+	// save() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void save(Object obj, Serializable id) throws HibernateException {
+		save(null, obj, id);
+	}
+
+	public Serializable save(Object obj) throws HibernateException {
+		return save(null, obj);
+	}
+
+	public Serializable save(String entityName, Object object) throws HibernateException {
+		return fireSave( new SaveOrUpdateEvent(entityName, object, this) );
+	}
+
+	public void save(String entityName, Object object, Serializable id) throws HibernateException {
+		fireSave( new SaveOrUpdateEvent(entityName, object, id, this) );
+	}
+
+	private Serializable fireSave(SaveOrUpdateEvent event) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		SaveOrUpdateEventListener[] saveEventListener = listeners.getSaveEventListeners();
+		for ( int i = 0; i < saveEventListener.length; i++ ) {
+			saveEventListener[i].onSaveOrUpdate(event);
+		}
+		return event.getResultId();
+	}
+
+
+	// update() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void update(Object obj) throws HibernateException {
+		update(null, obj);
+	}
+
+	public void update(Object obj, Serializable id) throws HibernateException {
+		update(null, obj, id);
+	}
+
+	public void update(String entityName, Object object) throws HibernateException {
+		fireUpdate( new SaveOrUpdateEvent(entityName, object, this) );
+	}
+
+	public void update(String entityName, Object object, Serializable id) throws HibernateException {
+		fireUpdate(new SaveOrUpdateEvent(entityName, object, id, this));
+	}
+
+	private void fireUpdate(SaveOrUpdateEvent event) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		SaveOrUpdateEventListener[] updateEventListener = listeners.getUpdateEventListeners();
+		for ( int i = 0; i < updateEventListener.length; i++ ) {
+			updateEventListener[i].onSaveOrUpdate(event);
+		}
+	}
+
+
+	// lock() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void lock(String entityName, Object object, LockMode lockMode) throws HibernateException {
+		fireLock( new LockEvent(entityName, object, lockMode, this) );
+	}
+
+	public void lock(Object object, LockMode lockMode) throws HibernateException {
+		fireLock( new LockEvent(object, lockMode, this) );
+	}
+
+	private void fireLock(LockEvent lockEvent) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		LockEventListener[] lockEventListener = listeners.getLockEventListeners();
+		for ( int i = 0; i < lockEventListener.length; i++ ) {
+			lockEventListener[i].onLock( lockEvent );
+		}
+	}
+
+
+	// persist() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void persist(String entityName, Object object) throws HibernateException {
+		firePersist( new PersistEvent(entityName, object, this) );
+	}
+
+	public void persist(Object object) throws HibernateException {
+		persist(null, object);
+	}
+
+	public void persist(String entityName, Object object, Map copiedAlready)
+	throws HibernateException {
+		firePersist( copiedAlready, new PersistEvent(entityName, object, this) );
+	}
+
+	private void firePersist(Map copiedAlready, PersistEvent event) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		PersistEventListener[] persistEventListener = listeners.getPersistEventListeners();
+		for ( int i = 0; i < persistEventListener.length; i++ ) {
+			persistEventListener[i].onPersist(event, copiedAlready);
+		}
+	}
+
+	private void firePersist(PersistEvent event) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		PersistEventListener[] createEventListener = listeners.getPersistEventListeners();
+		for ( int i = 0; i < createEventListener.length; i++ ) {
+			createEventListener[i].onPersist(event);
+		}
+	}
+
+
+	// persistOnFlush() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void persistOnFlush(String entityName, Object object)
+			throws HibernateException {
+		firePersistOnFlush( new PersistEvent(entityName, object, this) );
+	}
+
+	public void persistOnFlush(Object object) throws HibernateException {
+		persist(null, object);
+	}
+
+	public void persistOnFlush(String entityName, Object object, Map copiedAlready)
+			throws HibernateException {
+		firePersistOnFlush( copiedAlready, new PersistEvent(entityName, object, this) );
+	}
+
+	private void firePersistOnFlush(Map copiedAlready, PersistEvent event) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		PersistEventListener[] persistEventListener = listeners.getPersistOnFlushEventListeners();
+		for ( int i = 0; i < persistEventListener.length; i++ ) {
+			persistEventListener[i].onPersist(event, copiedAlready);
+		}
+	}
+
+	private void firePersistOnFlush(PersistEvent event) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		PersistEventListener[] createEventListener = listeners.getPersistOnFlushEventListeners();
+		for ( int i = 0; i < createEventListener.length; i++ ) {
+			createEventListener[i].onPersist(event);
+		}
+	}
+
+
+	// merge() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public Object merge(String entityName, Object object) throws HibernateException {
+		return fireMerge( new MergeEvent(entityName, object, this) );
+	}
+
+	public Object merge(Object object) throws HibernateException {
+		return merge(null, object);
+	}
+
+	public void merge(String entityName, Object object, Map copiedAlready) throws HibernateException {
+		fireMerge( copiedAlready, new MergeEvent(entityName, object, this) );
+	}
+
+	private Object fireMerge(MergeEvent event) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		MergeEventListener[] mergeEventListener = listeners.getMergeEventListeners();
+		for ( int i = 0; i < mergeEventListener.length; i++ ) {
+			mergeEventListener[i].onMerge(event);
+		}
+		return event.getResult();
+	}
+
+	private void fireMerge(Map copiedAlready, MergeEvent event) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		MergeEventListener[] mergeEventListener = listeners.getMergeEventListeners();
+		for ( int i = 0; i < mergeEventListener.length; i++ ) {
+			mergeEventListener[i].onMerge(event, copiedAlready);
+		}
+	}
+
+
+	// saveOrUpdateCopy() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public Object saveOrUpdateCopy(String entityName, Object object)
+			throws HibernateException {
+		return fireSaveOrUpdateCopy( new MergeEvent(entityName, object, this) );
+	}
+
+	public Object saveOrUpdateCopy(Object object) throws HibernateException {
+		return saveOrUpdateCopy( null, object );
+	}
+
+	public Object saveOrUpdateCopy(String entityName, Object object, Serializable id)
+			throws HibernateException {
+		return fireSaveOrUpdateCopy( new MergeEvent(entityName, object, id, this) );
+	}
+
+	public Object saveOrUpdateCopy(Object object, Serializable id)
+			throws HibernateException {
+		return saveOrUpdateCopy( null, object, id );
+	}
+
+	public void saveOrUpdateCopy(String entityName, Object object, Map copiedAlready)
+			throws HibernateException {
+		fireSaveOrUpdateCopy( copiedAlready, new MergeEvent( entityName, object, this ) );
+	}
+
+	private void fireSaveOrUpdateCopy(Map copiedAlready, MergeEvent event) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		MergeEventListener[] saveOrUpdateCopyEventListener = listeners.getSaveOrUpdateCopyEventListeners();
+		for ( int i = 0; i < saveOrUpdateCopyEventListener.length; i++ ) {
+			saveOrUpdateCopyEventListener[i].onMerge(event, copiedAlready);
+		}
+	}
+
+	private Object fireSaveOrUpdateCopy(MergeEvent event) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		MergeEventListener[] saveOrUpdateCopyEventListener = listeners.getSaveOrUpdateCopyEventListeners();
+		for ( int i = 0; i < saveOrUpdateCopyEventListener.length; i++ ) {
+			saveOrUpdateCopyEventListener[i].onMerge(event);
+		}
+		return event.getResult();
+	}
+
+
+	// delete() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Delete a persistent object
+	 */
+	public void delete(Object object) throws HibernateException {
+		fireDelete( new DeleteEvent(object, this) );
+	}
+
+	/**
+	 * Delete a persistent object (by explicit entity name)
+	 */
+	public void delete(String entityName, Object object) throws HibernateException {
+		fireDelete( new DeleteEvent( entityName, object, this ) );
+	}
+
+	/**
+	 * Delete a persistent object
+	 */
+	public void delete(String entityName, Object object, boolean isCascadeDeleteEnabled, Set transientEntities) throws HibernateException {
+		fireDelete( new DeleteEvent( entityName, object, isCascadeDeleteEnabled, this ), transientEntities );
+	}
+
+	private void fireDelete(DeleteEvent event) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		DeleteEventListener[] deleteEventListener = listeners.getDeleteEventListeners();
+		for ( int i = 0; i < deleteEventListener.length; i++ ) {
+			deleteEventListener[i].onDelete( event );
+		}
+	}
+
+	private void fireDelete(DeleteEvent event, Set transientEntities) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		DeleteEventListener[] deleteEventListener = listeners.getDeleteEventListeners();
+		for ( int i = 0; i < deleteEventListener.length; i++ ) {
+			deleteEventListener[i].onDelete( event, transientEntities );
+		}
+	}
+
+
+	// load()/get() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void load(Object object, Serializable id) throws HibernateException {
+		LoadEvent event = new LoadEvent(id, object, this);
+		fireLoad( event, LoadEventListener.RELOAD );
+	}
+
+	public Object load(Class entityClass, Serializable id) throws HibernateException {
+		return load( entityClass.getName(), id );
+	}
+
+	public Object load(String entityName, Serializable id) throws HibernateException {
+		LoadEvent event = new LoadEvent(id, entityName, false, this);
+		boolean success = false;
+		try {
+			fireLoad( event, LoadEventListener.LOAD );
+			if ( event.getResult() == null ) {
+				getFactory().getEntityNotFoundDelegate().handleEntityNotFound( entityName, id );
+			}
+			success = true;
+			return event.getResult();
+		}
+		finally {
+			afterOperation(success);
+		}
+	}
+
+	public Object get(Class entityClass, Serializable id) throws HibernateException {
+		return get( entityClass.getName(), id );
+	}
+
+	public Object get(String entityName, Serializable id) throws HibernateException {
+		LoadEvent event = new LoadEvent(id, entityName, false, this);
+		boolean success = false;
+		try {
+			fireLoad(event, LoadEventListener.GET);
+			success = true;
+			return event.getResult();
+		}
+		finally {
+			afterOperation(success);
+		}
+	}
+
+	/**
+	 * Load the data for the object with the specified id into a newly created object.
+	 * This is only called when lazily initializing a proxy.
+	 * Do NOT return a proxy.
+	 */
+	public Object immediateLoad(String entityName, Serializable id) throws HibernateException {
+		if ( log.isDebugEnabled() ) {
+			EntityPersister persister = getFactory().getEntityPersister(entityName);
+			log.debug( "initializing proxy: " + MessageHelper.infoString( persister, id, getFactory() ) );
+		}
+		
+		LoadEvent event = new LoadEvent(id, entityName, true, this);
+		fireLoad(event, LoadEventListener.IMMEDIATE_LOAD);
+		return event.getResult();
+	}
+
+	public Object internalLoad(String entityName, Serializable id, boolean eager, boolean nullable) throws HibernateException {
+		// todo : remove
+		LoadEventListener.LoadType type = nullable ? 
+				LoadEventListener.INTERNAL_LOAD_NULLABLE : 
+				eager ? LoadEventListener.INTERNAL_LOAD_EAGER : LoadEventListener.INTERNAL_LOAD_LAZY;
+		LoadEvent event = new LoadEvent(id, entityName, true, this);
+		fireLoad(event, type);
+		if ( !nullable ) {
+			UnresolvableObjectException.throwIfNull( event.getResult(), id, entityName );
+		}
+		return event.getResult();
+	}
+
+	public Object load(Class entityClass, Serializable id, LockMode lockMode) throws HibernateException {
+		return load( entityClass.getName(), id, lockMode );
+	}
+
+	public Object load(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
+		LoadEvent event = new LoadEvent(id, entityName, lockMode, this);
+		fireLoad( event, LoadEventListener.LOAD );
+		return event.getResult();
+	}
+
+	public Object get(Class entityClass, Serializable id, LockMode lockMode) throws HibernateException {
+		return get( entityClass.getName(), id, lockMode );
+	}
+
+	public Object get(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
+		LoadEvent event = new LoadEvent(id, entityName, lockMode, this);
+	   	fireLoad(event, LoadEventListener.GET);
+		return event.getResult();
+	}
+
+	private void fireLoad(LoadEvent event, LoadType loadType) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		LoadEventListener[] loadEventListener = listeners.getLoadEventListeners();
+		for ( int i = 0; i < loadEventListener.length; i++ ) {
+			loadEventListener[i].onLoad(event, loadType);
+		}
+	}
+
+
+	// refresh() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void refresh(Object object) throws HibernateException {
+		fireRefresh( new RefreshEvent(object, this) );
+	}
+
+	public void refresh(Object object, LockMode lockMode) throws HibernateException {
+		fireRefresh( new RefreshEvent(object, lockMode, this) );
+	}
+
+	public void refresh(Object object, Map refreshedAlready) throws HibernateException {
+		fireRefresh( refreshedAlready, new RefreshEvent(object, this) );
+	}
+
+	private void fireRefresh(RefreshEvent refreshEvent) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		RefreshEventListener[] refreshEventListener = listeners.getRefreshEventListeners();
+		for ( int i = 0; i < refreshEventListener.length; i++ ) {
+			refreshEventListener[i].onRefresh( refreshEvent );
+		}
+	}
+
+	private void fireRefresh(Map refreshedAlready, RefreshEvent refreshEvent) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		RefreshEventListener[] refreshEventListener = listeners.getRefreshEventListeners();
+		for ( int i = 0; i < refreshEventListener.length; i++ ) {
+			refreshEventListener[i].onRefresh( refreshEvent, refreshedAlready );
+		}
+	}
+
+
+	// replicate() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void replicate(Object obj, ReplicationMode replicationMode) throws HibernateException {
+		fireReplicate( new ReplicateEvent(obj, replicationMode, this) );
+	}
+
+	public void replicate(String entityName, Object obj, ReplicationMode replicationMode)
+	throws HibernateException {
+		fireReplicate( new ReplicateEvent(entityName, obj, replicationMode, this) );
+	}
+
+	private void fireReplicate(ReplicateEvent event) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		ReplicateEventListener[] replicateEventListener = listeners.getReplicateEventListeners();
+		for ( int i = 0; i < replicateEventListener.length; i++ ) {
+			replicateEventListener[i].onReplicate(event);
+		}
+	}
+
+
+	// evict() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * remove any hard references to the entity that are held by the infrastructure
+	 * (references held by application or other persistant instances are okay)
+	 */
+	public void evict(Object object) throws HibernateException {
+		fireEvict( new EvictEvent(object, this) );
+	}
+
+	private void fireEvict(EvictEvent evictEvent) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		EvictEventListener[] evictEventListener = listeners.getEvictEventListeners();
+		for ( int i = 0; i < evictEventListener.length; i++ ) {
+			evictEventListener[i].onEvict( evictEvent );
+		}
+	}
+
+	/**
+	 * detect in-memory changes, determine if the changes are to tables
+	 * named in the query and, if so, complete execution the flush
+	 */
+	protected boolean autoFlushIfRequired(Set querySpaces) throws HibernateException {
+		errorIfClosed();
+		if ( ! isTransactionInProgress() ) {
+			// do not auto-flush while outside a transaction
+			return false;
+		}
+		AutoFlushEvent event = new AutoFlushEvent(querySpaces, this);
+		AutoFlushEventListener[] autoFlushEventListener = listeners.getAutoFlushEventListeners();
+		for ( int i = 0; i < autoFlushEventListener.length; i++ ) {
+			autoFlushEventListener[i].onAutoFlush(event);
+		}
+		return event.isFlushRequired();
+	}
+
+	public boolean isDirty() throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		log.debug("checking session dirtiness");
+		if ( actionQueue.areInsertionsOrDeletionsQueued() ) {
+			log.debug("session dirty (scheduled updates and insertions)");
+			return true;
+		}
+		else {
+			DirtyCheckEvent event = new DirtyCheckEvent(this);
+			DirtyCheckEventListener[] dirtyCheckEventListener = listeners.getDirtyCheckEventListeners();
+			for ( int i = 0; i < dirtyCheckEventListener.length; i++ ) {
+				dirtyCheckEventListener[i].onDirtyCheck(event);
+			}
+			return event.isDirty();
+		}
+	}
+
+	public void flush() throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		if ( persistenceContext.getCascadeLevel() > 0 ) {
+			throw new HibernateException("Flush during cascade is dangerous");
+		}
+		FlushEventListener[] flushEventListener = listeners.getFlushEventListeners();
+		for ( int i = 0; i < flushEventListener.length; i++ ) {
+			flushEventListener[i].onFlush( new FlushEvent(this) );
+		}
+	}
+
+	public void forceFlush(EntityEntry entityEntry) throws HibernateException {
+		errorIfClosed();
+		if ( log.isDebugEnabled() ) {
+			log.debug(
+				"flushing to force deletion of re-saved object: " +
+				MessageHelper.infoString( entityEntry.getPersister(), entityEntry.getId(), getFactory() )
+			);
+		}
+
+		if ( persistenceContext.getCascadeLevel() > 0 ) {
+			throw new ObjectDeletedException(
+				"deleted object would be re-saved by cascade (remove deleted object from associations)",
+				entityEntry.getId(),
+				entityEntry.getPersister().getEntityName()
+			);
+		}
+
+		flush();
+	}
+
+	public Filter getEnabledFilter(String filterName) {
+		checkTransactionSynchStatus();
+		return (Filter) enabledFilters.get(filterName);
+	}
+
+	public Filter enableFilter(String filterName) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		FilterImpl filter = new FilterImpl( factory.getFilterDefinition(filterName) );
+		enabledFilters.put(filterName, filter);
+		return filter;
+	}
+
+	public void disableFilter(String filterName) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		enabledFilters.remove(filterName);
+	}
+
+	public Object getFilterParameterValue(String filterParameterName) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		String[] parsed = parseFilterParameterName(filterParameterName);
+		FilterImpl filter = (FilterImpl) enabledFilters.get( parsed[0] );
+		if (filter == null) {
+			throw new IllegalArgumentException("Filter [" + parsed[0] + "] currently not enabled");
+		}
+		return filter.getParameter( parsed[1] );
+	}
+
+	public Type getFilterParameterType(String filterParameterName) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		String[] parsed = parseFilterParameterName(filterParameterName);
+		FilterDefinition filterDef = factory.getFilterDefinition( parsed[0] );
+		if (filterDef == null) {
+			throw new IllegalArgumentException("Filter [" + parsed[0] + "] not defined");
+		}
+		Type type = filterDef.getParameterType( parsed[1] );
+		if (type == null) {
+			// this is an internal error of some sort...
+			throw new InternalError("Unable to locate type for filter parameter");
+		}
+		return type;
+	}
+
+	public Map getEnabledFilters() {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		// First, validate all the enabled filters...
+		//TODO: this implementation has bad performance
+		Iterator itr = enabledFilters.values().iterator();
+		while ( itr.hasNext() ) {
+			final Filter filter = (Filter) itr.next();
+			filter.validate();
+		}
+		return enabledFilters;
+	}
+
+	private String[] parseFilterParameterName(String filterParameterName) {
+		int dot = filterParameterName.indexOf('.');
+		if (dot <= 0) {
+			throw new IllegalArgumentException("Invalid filter-parameter name format"); // TODO: what type?
+		}
+		String filterName = filterParameterName.substring(0, dot);
+		String parameterName = filterParameterName.substring(dot+1);
+		return new String[] {filterName, parameterName};
+	}
+
+
+	/**
+	 * Retrieve a list of persistent objects using a hibernate query
+	 */
+	public List find(String query) throws HibernateException {
+		return list( query, new QueryParameters() );
+	}
+
+	public List find(String query, Object value, Type type) throws HibernateException {
+		return list( query, new QueryParameters(type, value) );
+	}
+
+	public List find(String query, Object[] values, Type[] types) throws HibernateException {
+		return list( query, new QueryParameters(types, values) );
+	}
+
+	public List list(String query, QueryParameters queryParameters) throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		queryParameters.validateParameters();
+		HQLQueryPlan plan = getHQLQueryPlan( query, false );
+		autoFlushIfRequired( plan.getQuerySpaces() );
+
+		List results = CollectionHelper.EMPTY_LIST;
+		boolean success = false;
+
+		dontFlushFromFind++;   //stops flush being called multiple times if this method is recursively called
+		try {
+			results = plan.performList( queryParameters, this );
+			success = true;
+		}
+		finally {
+			dontFlushFromFind--;
+			afterOperation(success);
+		}
+		return results;
+	}
+
+	public int executeUpdate(String query, QueryParameters queryParameters) throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		queryParameters.validateParameters();
+		HQLQueryPlan plan = getHQLQueryPlan( query, false );
+		autoFlushIfRequired( plan.getQuerySpaces() );
+
+		boolean success = false;
+		int result = 0;
+		try {
+			result = plan.performExecuteUpdate( queryParameters, this );
+			success = true;
+		}
+		finally {
+			afterOperation(success);
+		}
+		return result;
+	}
+
+    public int executeNativeUpdate(NativeSQLQuerySpecification nativeQuerySpecification,
+            QueryParameters queryParameters) throws HibernateException {
+        errorIfClosed();
+        checkTransactionSynchStatus();
+        queryParameters.validateParameters();
+        NativeSQLQueryPlan plan = getNativeSQLQueryPlan(nativeQuerySpecification);
+
+        
+        autoFlushIfRequired( plan.getCustomQuery().getQuerySpaces() );
+        
+        boolean success = false;
+        int result = 0;
+        try {
+            result = plan.performExecuteUpdate(queryParameters, this);
+            success = true;
+        } finally {
+            afterOperation(success);
+        }
+        return result;
+    }
+
+	public Iterator iterate(String query) throws HibernateException {
+		return iterate( query, new QueryParameters() );
+	}
+
+	public Iterator iterate(String query, Object value, Type type) throws HibernateException {
+		return iterate( query, new QueryParameters(type, value) );
+	}
+
+	public Iterator iterate(String query, Object[] values, Type[] types) throws HibernateException {
+		return iterate( query, new QueryParameters(types, values) );
+	}
+
+	public Iterator iterate(String query, QueryParameters queryParameters) throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		queryParameters.validateParameters();
+		HQLQueryPlan plan = getHQLQueryPlan( query, true );
+		autoFlushIfRequired( plan.getQuerySpaces() );
+
+		dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called
+		try {
+			return plan.performIterate( queryParameters, this );
+		}
+		finally {
+			dontFlushFromFind--;
+		}
+	}
+
+	public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		HQLQueryPlan plan = getHQLQueryPlan( query, false );
+		autoFlushIfRequired( plan.getQuerySpaces() );
+		dontFlushFromFind++;
+		try {
+			return plan.performScroll( queryParameters, this );
+		}
+		finally {
+			dontFlushFromFind--;
+		}
+	}
+
+	public int delete(String query) throws HibernateException {
+		return delete( query, ArrayHelper.EMPTY_OBJECT_ARRAY, ArrayHelper.EMPTY_TYPE_ARRAY );
+	}
+
+	public int delete(String query, Object value, Type type) throws HibernateException {
+		return delete( query, new Object[]{value}, new Type[]{type} );
+	}
+
+	public int delete(String query, Object[] values, Type[] types) throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		if ( query == null ) {
+			throw new IllegalArgumentException("attempt to perform delete-by-query with null query");
+		}
+
+		if ( log.isTraceEnabled() ) {
+			log.trace( "delete: " + query );
+			if ( values.length != 0 ) {
+				log.trace( "parameters: " + StringHelper.toString( values ) );
+			}
+		}
+
+		List list = find( query, values, types );
+		int deletionCount = list.size();
+		for ( int i = 0; i < deletionCount; i++ ) {
+			delete( list.get( i ) );
+		}
+
+		return deletionCount;
+	}
+
+	public Query createFilter(Object collection, String queryString) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		CollectionFilterImpl filter = new CollectionFilterImpl(
+				queryString,
+		        collection,
+		        this,
+		        getFilterQueryPlan( collection, queryString, null, false ).getParameterMetadata()
+		);
+		filter.setComment( queryString );
+		return filter;
+	}
+	
+	public Query getNamedQuery(String queryName) throws MappingException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return super.getNamedQuery(queryName);
+	}
+
+	public Object instantiate(String entityName, Serializable id) throws HibernateException {
+		return instantiate( factory.getEntityPersister(entityName), id );
+	}
+
+	/**
+	 * give the interceptor an opportunity to override the default instantiation
+	 */
+	public Object instantiate(EntityPersister persister, Serializable id) throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		Object result = interceptor.instantiate( persister.getEntityName(), entityMode, id );
+		if ( result == null ) {
+			result = persister.instantiate( id, entityMode );
+		}
+		return result;
+	}
+
+	public EntityMode getEntityMode() {
+		checkTransactionSynchStatus();
+		return entityMode;
+	}
+
+	public void setFlushMode(FlushMode flushMode) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		if ( log.isTraceEnabled() ) {
+			log.trace("setting flush mode to: " + flushMode);
+		}
+		this.flushMode = flushMode;
+	}
+	
+	public FlushMode getFlushMode() {
+		checkTransactionSynchStatus();
+		return flushMode;
+	}
+
+	public CacheMode getCacheMode() {
+		checkTransactionSynchStatus();
+		return cacheMode;
+	}
+	
+	public void setCacheMode(CacheMode cacheMode) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		if ( log.isTraceEnabled() ) {
+			log.trace("setting cache mode to: " + cacheMode);
+		}
+		this.cacheMode= cacheMode; 
+	}
+
+	public Transaction getTransaction() throws HibernateException {
+		errorIfClosed();
+		return jdbcContext.getTransaction();
+	}
+	
+	public Transaction beginTransaction() throws HibernateException {
+		errorIfClosed();
+		if ( rootSession != null ) {
+			// todo : should seriously consider not allowing a txn to begin from a child session
+			//      can always route the request to the root session...
+			log.warn( "Transaction started on non-root session" );
+		}
+		Transaction result = getTransaction();
+		result.begin();
+		return result;
+	}
+	
+	public void afterTransactionBegin(Transaction tx) {
+		errorIfClosed();
+		interceptor.afterTransactionBegin(tx);
+	}
+
+	public EntityPersister getEntityPersister(final String entityName, final Object object) {
+		errorIfClosed();
+		if (entityName==null) {
+			return factory.getEntityPersister( guessEntityName( object ) );
+		}
+		else {
+			// try block is a hack around fact that currently tuplizers are not
+			// given the opportunity to resolve a subclass entity name.  this
+			// allows the (we assume custom) interceptor the ability to
+			// influence this decision if we were not able to based on the
+			// given entityName
+			try {
+				return factory.getEntityPersister( entityName )
+						.getSubclassEntityPersister( object, getFactory(), entityMode );
+			}
+			catch( HibernateException e ) {
+				try {
+					return getEntityPersister( null, object );
+				}
+				catch( HibernateException e2 ) {
+					throw e;
+				}
+			}
+		}
+	}
+
+	// not for internal use:
+	public Serializable getIdentifier(Object object) throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		if ( object instanceof HibernateProxy ) {
+			LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer();
+			if ( li.getSession() != this ) {
+				throw new TransientObjectException( "The proxy was not associated with this session" );
+			}
+			return li.getIdentifier();
+		}
+		else {
+			EntityEntry entry = persistenceContext.getEntry(object);
+			if ( entry == null ) {
+				throw new TransientObjectException( "The instance was not associated with this session" );
+			}
+			return entry.getId();
+		}
+	}
+
+	/**
+	 * Get the id value for an object that is actually associated with the session. This
+	 * is a bit stricter than getEntityIdentifierIfNotUnsaved().
+	 */
+	public Serializable getContextEntityIdentifier(Object object) {
+		errorIfClosed();
+		if ( object instanceof HibernateProxy ) {
+			return getProxyIdentifier(object);
+		}
+		else {
+			EntityEntry entry = persistenceContext.getEntry(object);
+			return entry != null ? entry.getId() : null;
+		}
+	}
+	
+	private Serializable getProxyIdentifier(Object proxy) {
+		return ( (HibernateProxy) proxy ).getHibernateLazyInitializer().getIdentifier();
+	}
+
+	public Collection filter(Object collection, String filter) throws HibernateException {
+		return listFilter( collection, filter, new QueryParameters( new Type[1], new Object[1] ) );
+	}
+
+	public Collection filter(Object collection, String filter, Object value, Type type) throws HibernateException {
+		return listFilter( collection, filter, new QueryParameters( new Type[]{null, type}, new Object[]{null, value} ) );
+	}
+
+	public Collection filter(Object collection, String filter, Object[] values, Type[] types) 
+	throws HibernateException {
+		Object[] vals = new Object[values.length + 1];
+		Type[] typs = new Type[types.length + 1];
+		System.arraycopy( values, 0, vals, 1, values.length );
+		System.arraycopy( types, 0, typs, 1, types.length );
+		return listFilter( collection, filter, new QueryParameters( typs, vals ) );
+	}
+
+	private FilterQueryPlan getFilterQueryPlan(
+			Object collection,
+			String filter,
+			QueryParameters parameters,
+			boolean shallow) throws HibernateException {
+		if ( collection == null ) {
+			throw new NullPointerException( "null collection passed to filter" );
+		}
+
+		CollectionEntry entry = persistenceContext.getCollectionEntryOrNull( collection );
+		final CollectionPersister roleBeforeFlush = (entry == null) ? null : entry.getLoadedPersister();
+
+		FilterQueryPlan plan = null;
+		if ( roleBeforeFlush == null ) {
+			// if it was previously unreferenced, we need to flush in order to
+			// get its state into the database in order to execute query
+			flush();
+			entry = persistenceContext.getCollectionEntryOrNull( collection );
+			CollectionPersister roleAfterFlush = (entry == null) ? null : entry.getLoadedPersister();
+			if ( roleAfterFlush == null ) {
+				throw new QueryException( "The collection was unreferenced" );
+			}
+			plan = factory.getQueryPlanCache().getFilterQueryPlan( filter, roleAfterFlush.getRole(), shallow, getEnabledFilters() );
+		}
+		else {
+			// otherwise, we only need to flush if there are in-memory changes
+			// to the queried tables
+			plan = factory.getQueryPlanCache().getFilterQueryPlan( filter, roleBeforeFlush.getRole(), shallow, getEnabledFilters() );
+			if ( autoFlushIfRequired( plan.getQuerySpaces() ) ) {
+				// might need to run a different filter entirely after the flush
+				// because the collection role may have changed
+				entry = persistenceContext.getCollectionEntryOrNull( collection );
+				CollectionPersister roleAfterFlush = (entry == null) ? null : entry.getLoadedPersister();
+				if ( roleBeforeFlush != roleAfterFlush ) {
+					if ( roleAfterFlush == null ) {
+						throw new QueryException( "The collection was dereferenced" );
+					}
+					plan = factory.getQueryPlanCache().getFilterQueryPlan( filter, roleAfterFlush.getRole(), shallow, getEnabledFilters() );
+				}
+			}
+		}
+
+		if ( parameters != null ) {
+			parameters.getPositionalParameterValues()[0] = entry.getLoadedKey();
+			parameters.getPositionalParameterTypes()[0] = entry.getLoadedPersister().getKeyType();
+		}
+
+		return plan;
+	}
+
+	public List listFilter(Object collection, String filter, QueryParameters queryParameters) 
+	throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		FilterQueryPlan plan = getFilterQueryPlan( collection, filter, queryParameters, false );
+		List results = CollectionHelper.EMPTY_LIST;
+
+		boolean success = false;
+		dontFlushFromFind++;   //stops flush being called multiple times if this method is recursively called
+		try {
+			results = plan.performList( queryParameters, this );
+			success = true;
+		}
+		finally {
+			dontFlushFromFind--;
+			afterOperation(success);
+		}
+		return results;
+	}
+
+	public Iterator iterateFilter(Object collection, String filter, QueryParameters queryParameters) 
+	throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		FilterQueryPlan plan = getFilterQueryPlan( collection, filter, queryParameters, true );
+		return plan.performIterate( queryParameters, this );
+	}
+
+	public Criteria createCriteria(Class persistentClass, String alias) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return new CriteriaImpl( persistentClass.getName(), alias, this );
+	}
+
+	public Criteria createCriteria(String entityName, String alias) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return new CriteriaImpl(entityName, alias, this);
+	}
+
+	public Criteria createCriteria(Class persistentClass) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return new CriteriaImpl( persistentClass.getName(), this );
+	}
+
+	public Criteria createCriteria(String entityName) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return new CriteriaImpl(entityName, this);
+	}
+
+	public ScrollableResults scroll(CriteriaImpl criteria, ScrollMode scrollMode) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		String entityName = criteria.getEntityOrClassName();
+		CriteriaLoader loader = new CriteriaLoader(
+				getOuterJoinLoadable(entityName),
+				factory,
+				criteria,
+				entityName,
+				getEnabledFilters()
+		);
+		autoFlushIfRequired( loader.getQuerySpaces() );
+		dontFlushFromFind++;
+		try {
+			return loader.scroll(this, scrollMode);
+		}
+		finally {
+			dontFlushFromFind--;
+		}
+	}
+
+	public List list(CriteriaImpl criteria) throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		String[] implementors = factory.getImplementors( criteria.getEntityOrClassName() );
+		int size = implementors.length;
+
+		CriteriaLoader[] loaders = new CriteriaLoader[size];
+		Set spaces = new HashSet();
+		for( int i=0; i <size; i++ ) {
+
+			loaders[i] = new CriteriaLoader(
+					getOuterJoinLoadable( implementors[i] ),
+					factory,
+					criteria,
+					implementors[i],
+					getEnabledFilters()
+				);
+
+			spaces.addAll( loaders[i].getQuerySpaces() );
+
+		}
+
+		autoFlushIfRequired(spaces);
+
+		List results = Collections.EMPTY_LIST;
+		dontFlushFromFind++;
+		boolean success = false;
+		try {
+			for( int i=0; i<size; i++ ) {
+				final List currentResults = loaders[i].list(this);
+				currentResults.addAll(results);
+				results = currentResults;
+			}
+			success = true;
+		}
+		finally {
+			dontFlushFromFind--;
+			afterOperation(success);
+		}
+
+		return results;
+	}
+
+	private OuterJoinLoadable getOuterJoinLoadable(String entityName) throws MappingException {
+		EntityPersister persister = factory.getEntityPersister(entityName);
+		if ( !(persister instanceof OuterJoinLoadable) ) {
+			throw new MappingException( "class persister is not OuterJoinLoadable: " + entityName );
+		}
+		return ( OuterJoinLoadable ) persister;
+	}
+
+	public boolean contains(Object object) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		if ( object instanceof HibernateProxy ) {
+			//do not use proxiesByKey, since not all
+			//proxies that point to this session's
+			//instances are in that collection!
+			LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer();
+			if ( li.isUninitialized() ) {
+				//if it is an uninitialized proxy, pointing
+				//with this session, then when it is accessed,
+				//the underlying instance will be "contained"
+				return li.getSession()==this;
+			}
+			else {
+				//if it is initialized, see if the underlying
+				//instance is contained, since we need to 
+				//account for the fact that it might have been
+				//evicted
+				object = li.getImplementation();
+			}
+		}
+		// A session is considered to contain an entity only if the entity has
+		// an entry in the session's persistence context and the entry reports
+		// that the entity has not been removed
+		EntityEntry entry = persistenceContext.getEntry( object );
+		return entry != null && entry.getStatus() != Status.DELETED && entry.getStatus() != Status.GONE;
+	}
+	
+	public Query createQuery(String queryString) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return super.createQuery(queryString);
+	}
+	
+	public SQLQuery createSQLQuery(String sql) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return super.createSQLQuery(sql);
+	}
+
+	public Query createSQLQuery(String sql, String returnAlias, Class returnClass) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return new SQLQueryImpl(
+				sql,
+		        new String[] { returnAlias },
+		        new Class[] { returnClass },
+		        this,
+		        factory.getQueryPlanCache().getSQLParameterMetadata( sql )
+		);
+	}
+
+	public Query createSQLQuery(String sql, String returnAliases[], Class returnClasses[]) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return new SQLQueryImpl(
+				sql,
+		        returnAliases,
+		        returnClasses,
+		        this,
+		        factory.getQueryPlanCache().getSQLParameterMetadata( sql )
+		);
+	}
+
+	public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) 
+	throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+
+		if ( log.isTraceEnabled() ) {
+			log.trace( "scroll SQL query: " + customQuery.getSQL() );
+		}
+
+		CustomLoader loader = new CustomLoader( customQuery, getFactory() );
+
+		autoFlushIfRequired( loader.getQuerySpaces() );
+
+		dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called
+		try {
+			return loader.scroll(queryParameters, this);
+		}
+		finally {
+			dontFlushFromFind--;
+		}
+	}
+
+	// basically just an adapted copy of find(CriteriaImpl)
+	public List listCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) 
+	throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+
+		if ( log.isTraceEnabled() ) {
+			log.trace( "SQL query: " + customQuery.getSQL() );
+		}
+		
+		CustomLoader loader = new CustomLoader( customQuery, getFactory() );
+
+		autoFlushIfRequired( loader.getQuerySpaces() );
+
+		dontFlushFromFind++;
+		boolean success = false;
+		try {
+			List results = loader.list(this, queryParameters);
+			success = true;
+			return results;
+		}
+		finally {
+			dontFlushFromFind--;
+			afterOperation(success);
+		}
+	}
+
+	public SessionFactory getSessionFactory() {
+		checkTransactionSynchStatus();
+		return factory;
+	}
+	
+	public void initializeCollection(PersistentCollection collection, boolean writing) 
+	throws HibernateException {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		InitializeCollectionEventListener[] listener = listeners.getInitializeCollectionEventListeners();
+		for ( int i = 0; i < listener.length; i++ ) {
+			listener[i].onInitializeCollection( new InitializeCollectionEvent(collection, this) );
+		}
+	}
+
+	public String bestGuessEntityName(Object object) {
+		if (object instanceof HibernateProxy) {
+			LazyInitializer initializer = ( ( HibernateProxy ) object ).getHibernateLazyInitializer();
+			// it is possible for this method to be called during flush processing,
+			// so make certain that we do not accidently initialize an uninitialized proxy
+			if ( initializer.isUninitialized() ) {
+				return initializer.getEntityName();
+			}
+			object = initializer.getImplementation();
+		}
+		EntityEntry entry = persistenceContext.getEntry(object);
+		if (entry==null) {
+			return guessEntityName(object);
+		}
+		else {
+			return entry.getPersister().getEntityName();
+		}
+	}
+	
+	public String getEntityName(Object object) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		if (object instanceof HibernateProxy) {
+			if ( !persistenceContext.containsProxy( object ) ) {
+				throw new TransientObjectException("proxy was not associated with the session");
+			}
+			object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation();
+		}
+
+		EntityEntry entry = persistenceContext.getEntry(object);
+		if ( entry == null ) {
+			throwTransientObjectException( object );
+		}
+		return entry.getPersister().getEntityName();
+	}
+
+	private void throwTransientObjectException(Object object) throws HibernateException {
+		throw new TransientObjectException(
+				"object references an unsaved transient instance - save the transient instance before flushing: " +
+				guessEntityName(object)
+			);
+	}
+
+	public String guessEntityName(Object object) throws HibernateException {
+		errorIfClosed();
+		String entity = interceptor.getEntityName( object );
+		if ( entity == null ) {
+			if ( object instanceof Map ) {
+				entity = (String) ( (Map) object ).get( DynamicMapInstantiator.KEY );
+				if ( entity == null ) {
+					throw new HibernateException( "could not determine type of dynamic entity" );
+				}
+			}
+			else if ( object instanceof Element ) {
+				// TODO : really need to keep a map of nodeName -> entityName, but that would mean nodeName being distinct
+				entity = ( (Element) object ).getName();
+			}
+			else {
+				entity = object.getClass().getName();
+			}
+		}
+		return entity;
+	}
+
+	public void cancelQuery() throws HibernateException {
+		errorIfClosed();
+		getBatcher().cancelLastQuery();
+	}
+
+	public Interceptor getInterceptor() {
+		checkTransactionSynchStatus();
+		return interceptor;
+	}
+
+	public int getDontFlushFromFind() {
+		return dontFlushFromFind;
+	}
+
+	public String toString() {
+		StringBuffer buf = new StringBuffer(500)
+			.append( "SessionImpl(" );
+		if ( !isClosed() ) {
+			buf.append(persistenceContext)
+				.append(";")
+				.append(actionQueue);
+		}
+		else {
+			buf.append("<closed>");
+		}
+		return buf.append(')').toString();
+	}
+
+	public EventListeners getListeners() {
+		return listeners;
+	}
+
+	public ActionQueue getActionQueue() {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return actionQueue;
+	}
+	
+	public PersistenceContext getPersistenceContext() {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return persistenceContext;
+	}
+	
+	public SessionStatistics getStatistics() {
+		checkTransactionSynchStatus();
+		return new SessionStatisticsImpl(this);
+	}
+
+	public boolean isEventSource() {
+		checkTransactionSynchStatus();
+		return true;
+	}
+
+	public void setReadOnly(Object entity, boolean readOnly) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		persistenceContext.setReadOnly(entity, readOnly);
+	}
+
+	public void afterScrollOperation() {
+		// nothing to do in a stateful session
+	}
+
+	public String getFetchProfile() {
+		checkTransactionSynchStatus();
+		return fetchProfile;
+	}
+
+	public JDBCContext getJDBCContext() {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return jdbcContext;
+	}
+
+	public void setFetchProfile(String fetchProfile) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		this.fetchProfile = fetchProfile;
+	}
+
+	private void checkTransactionSynchStatus() {
+		if ( jdbcContext != null && !isClosed() ) {
+			jdbcContext.registerSynchronizationIfPossible();
+		}
+	}
+
+	/**
+	 * Used by JDK serialization...
+	 *
+	 * @param ois The input stream from which we are being read...
+	 * @throws IOException Indicates a general IO stream exception
+	 * @throws ClassNotFoundException Indicates a class resolution issue
+	 */
+	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+		log.trace( "deserializing session" );
+
+		boolean isRootSession = ois.readBoolean();
+		connectionReleaseMode = ConnectionReleaseMode.parse( ( String ) ois.readObject() );
+		entityMode = EntityMode.parse( ( String ) ois.readObject() );
+		autoClear = ois.readBoolean();
+		flushMode = FlushMode.parse( ( String ) ois.readObject() );
+		cacheMode = CacheMode.parse( ( String ) ois.readObject() );
+		flushBeforeCompletionEnabled = ois.readBoolean();
+		autoCloseSessionEnabled = ois.readBoolean();
+		fetchProfile = ( String ) ois.readObject();
+		interceptor = ( Interceptor ) ois.readObject();
+
+		factory = SessionFactoryImpl.deserialize( ois );
+		listeners = factory.getEventListeners();
+
+		if ( isRootSession ) {
+			jdbcContext = JDBCContext.deserialize( ois, this, interceptor );
+		}
+
+		persistenceContext = StatefulPersistenceContext.deserialize( ois, this );
+		actionQueue = ActionQueue.deserialize( ois, this );
+
+		enabledFilters = ( Map ) ois.readObject();
+		childSessionsByEntityMode = ( Map ) ois.readObject();
+
+		Iterator iter = enabledFilters.values().iterator();
+		while ( iter.hasNext() ) {
+			( ( FilterImpl ) iter.next() ).afterDeserialize(factory);
+		}
+
+		if ( isRootSession && childSessionsByEntityMode != null ) {
+			iter = childSessionsByEntityMode.values().iterator();
+			while ( iter.hasNext() ) {
+				final SessionImpl child = ( ( SessionImpl ) iter.next() );
+				child.rootSession = this;
+				child.jdbcContext = this.jdbcContext;
+			}
+		}
+	}
+
+	/**
+	 * Used by JDK serialization...
+	 *
+	 * @param oos The output stream to which we are being written...
+	 * @throws IOException Indicates a general IO stream exception
+	 */
+	private void writeObject(ObjectOutputStream oos) throws IOException {
+		if ( !jdbcContext.getConnectionManager().isReadyForSerialization() ) {
+			throw new IllegalStateException( "Cannot serialize a session while connected" );
+		}
+
+		log.trace( "serializing session" );
+
+		oos.writeBoolean( rootSession == null );
+		oos.writeObject( connectionReleaseMode.toString() );
+		oos.writeObject( entityMode.toString() );
+		oos.writeBoolean( autoClear );
+		oos.writeObject( flushMode.toString() );
+		oos.writeObject( cacheMode.toString() );
+		oos.writeBoolean( flushBeforeCompletionEnabled );
+		oos.writeBoolean( autoCloseSessionEnabled );
+		oos.writeObject( fetchProfile );
+		// we need to writeObject() on this since interceptor is user defined
+		oos.writeObject( interceptor );
+
+		factory.serialize( oos );
+
+		if ( rootSession == null ) {
+			jdbcContext.serialize( oos );
+		}
+
+		persistenceContext.serialize( oos );
+		actionQueue.serialize( oos );
+
+		// todo : look at optimizing these...
+		oos.writeObject( enabledFilters );
+		oos.writeObject( childSessionsByEntityMode );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,630 @@
+//$Id: StatelessSessionImpl.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.impl;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.CacheMode;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.Criteria;
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.EntityMode;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.SessionException;
+import org.hibernate.StatelessSession;
+import org.hibernate.Transaction;
+import org.hibernate.UnresolvableObjectException;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.StatefulPersistenceContext;
+import org.hibernate.engine.Versioning;
+import org.hibernate.engine.query.HQLQueryPlan;
+import org.hibernate.engine.query.NativeSQLQueryPlan;
+import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
+import org.hibernate.event.EventListeners;
+import org.hibernate.id.IdentifierGeneratorFactory;
+import org.hibernate.jdbc.Batcher;
+import org.hibernate.jdbc.JDBCContext;
+import org.hibernate.loader.criteria.CriteriaLoader;
+import org.hibernate.loader.custom.CustomLoader;
+import org.hibernate.loader.custom.CustomQuery;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.type.Type;
+import org.hibernate.util.CollectionHelper;
+
+/**
+ * @author Gavin King
+ */
+public class StatelessSessionImpl extends AbstractSessionImpl
+		implements JDBCContext.Context, StatelessSession {
+
+	private static final Log log = LogFactory.getLog( StatelessSessionImpl.class );
+
+	private JDBCContext jdbcContext;
+	private PersistenceContext temporaryPersistenceContext = new StatefulPersistenceContext( this );
+
+	StatelessSessionImpl(Connection connection, SessionFactoryImpl factory) {
+		super( factory );
+		this.jdbcContext = new JDBCContext( this, connection, EmptyInterceptor.INSTANCE );
+	}
+
+
+	// inserts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public Serializable insert(Object entity) {
+		errorIfClosed();
+		return insert(null, entity);
+	}
+
+	public Serializable insert(String entityName, Object entity) {
+		errorIfClosed();
+		EntityPersister persister = getEntityPersister(entityName, entity);
+		Serializable id = persister.getIdentifierGenerator().generate(this, entity);
+		Object[] state = persister.getPropertyValues(entity, EntityMode.POJO);
+		if ( persister.isVersioned() ) {
+			boolean substitute = Versioning.seedVersion(state, persister.getVersionProperty(), persister.getVersionType(), this);
+			if ( substitute ) {
+				persister.setPropertyValues( entity, state, EntityMode.POJO );
+			}
+		}
+		if ( id == IdentifierGeneratorFactory.POST_INSERT_INDICATOR ) {
+			id = persister.insert(state, entity, this);
+		}
+		else {
+			persister.insert(id, state, entity, this);
+		}
+		persister.setIdentifier(entity, id, EntityMode.POJO);
+		return id;
+	}
+
+
+	// deletes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void delete(Object entity) {
+		errorIfClosed();
+		delete(null, entity);
+	}
+
+	public void delete(String entityName, Object entity) {
+		errorIfClosed();
+		EntityPersister persister = getEntityPersister(entityName, entity);
+		Serializable id = persister.getIdentifier(entity, EntityMode.POJO);
+		Object version = persister.getVersion(entity, EntityMode.POJO);
+		persister.delete(id, version, entity, this);
+	}
+
+
+	// updates ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void update(Object entity) {
+		errorIfClosed();
+		update(null, entity);
+	}
+
+	public void update(String entityName, Object entity) {
+		errorIfClosed();
+		EntityPersister persister = getEntityPersister(entityName, entity);
+		Serializable id = persister.getIdentifier(entity, EntityMode.POJO);
+		Object[] state = persister.getPropertyValues(entity, EntityMode.POJO);
+		Object oldVersion;
+		if ( persister.isVersioned() ) {
+			oldVersion = persister.getVersion(entity, EntityMode.POJO);
+			Object newVersion = Versioning.increment( oldVersion, persister.getVersionType(), this );
+			Versioning.setVersion(state, newVersion, persister);
+			persister.setPropertyValues(entity, state, EntityMode.POJO);
+		}
+		else {
+			oldVersion = null;
+		}
+		persister.update(id, state, null, false, null, oldVersion, entity, null, this);
+	}
+
+
+	// loading ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public Object get(Class entityClass, Serializable id) {
+		return get( entityClass.getName(), id );
+	}
+
+	public Object get(Class entityClass, Serializable id, LockMode lockMode) {
+		return get( entityClass.getName(), id, lockMode );
+	}
+
+	public Object get(String entityName, Serializable id) {
+		return get(entityName, id, LockMode.NONE);
+	}
+
+	public Object get(String entityName, Serializable id, LockMode lockMode) {
+		errorIfClosed();
+		Object result = getFactory().getEntityPersister(entityName)
+				.load(id, null, lockMode, this);
+		temporaryPersistenceContext.clear();
+		return result;
+	}
+
+	public void refresh(Object entity) {
+		refresh( bestGuessEntityName( entity ), entity, LockMode.NONE );
+	}
+
+	public void refresh(String entityName, Object entity) {
+		refresh( entityName, entity, LockMode.NONE );
+	}
+
+	public void refresh(Object entity, LockMode lockMode) {
+		refresh( bestGuessEntityName( entity ), entity, lockMode );
+	}
+
+	public void refresh(String entityName, Object entity, LockMode lockMode) {
+		final EntityPersister persister = this.getEntityPersister( entityName, entity );
+		final Serializable id = persister.getIdentifier( entity, getEntityMode() );
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"refreshing transient " +
+					MessageHelper.infoString( persister, id, this.getFactory() )
+			);
+		}
+		// TODO : can this ever happen???
+//		EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
+//		if ( source.getPersistenceContext().getEntry( key ) != null ) {
+//			throw new PersistentObjectException(
+//					"attempted to refresh transient instance when persistent " +
+//					"instance was already associated with the Session: " +
+//					MessageHelper.infoString( persister, id, source.getFactory() )
+//			);
+//		}
+
+		if ( persister.hasCache() ) {
+			final CacheKey ck = new CacheKey(
+					id,
+			        persister.getIdentifierType(),
+			        persister.getRootEntityName(),
+			        this.getEntityMode(),
+			        this.getFactory()
+			);
+			persister.getCacheAccessStrategy().evict( ck );
+		}
+
+		String previousFetchProfile = this.getFetchProfile();
+		Object result = null;
+		try {
+			this.setFetchProfile( "refresh" );
+			result = persister.load( id, entity, lockMode, this );
+		}
+		finally {
+			this.setFetchProfile( previousFetchProfile );
+		}
+		UnresolvableObjectException.throwIfNull( result, id, persister.getEntityName() );
+	}
+
+	public Object immediateLoad(String entityName, Serializable id)
+			throws HibernateException {
+		throw new SessionException("proxies cannot be fetched by a stateless session");
+	}
+
+	public void initializeCollection(
+			PersistentCollection collection,
+	        boolean writing) throws HibernateException {
+		throw new SessionException("collections cannot be fetched by a stateless session");
+	}
+
+	public Object instantiate(
+			String entityName,
+	        Serializable id) throws HibernateException {
+		errorIfClosed();
+		return getFactory().getEntityPersister( entityName )
+				.instantiate( id, EntityMode.POJO );
+	}
+
+	public Object internalLoad(
+			String entityName,
+	        Serializable id,
+	        boolean eager,
+	        boolean nullable) throws HibernateException {
+		errorIfClosed();
+		EntityPersister persister = getFactory().getEntityPersister(entityName);
+		if ( !eager && persister.hasProxy() ) {
+			return persister.createProxy(id, this);
+		}
+		Object loaded = temporaryPersistenceContext.getEntity( new EntityKey(id, persister, EntityMode.POJO) );
+		//TODO: if not loaded, throw an exception
+		return loaded==null ? get( entityName, id ) : loaded;
+	}
+
+	public Iterator iterate(String query, QueryParameters queryParameters) throws HibernateException {
+		throw new UnsupportedOperationException();
+	}
+
+	public Iterator iterateFilter(Object collection, String filter, QueryParameters queryParameters)
+	throws HibernateException {
+		throw new UnsupportedOperationException();
+	}
+
+	public List listFilter(Object collection, String filter, QueryParameters queryParameters)
+	throws HibernateException {
+		throw new UnsupportedOperationException();
+	}
+
+
+	public boolean isOpen() {
+		return !isClosed();
+	}
+
+	public void close() {
+		managedClose();
+	}
+
+	public ConnectionReleaseMode getConnectionReleaseMode() {
+		return factory.getSettings().getConnectionReleaseMode();
+	}
+
+	public boolean isAutoCloseSessionEnabled() {
+		return factory.getSettings().isAutoCloseSessionEnabled();
+	}
+
+	public boolean isFlushBeforeCompletionEnabled() {
+		return true;
+	}
+
+	public boolean isFlushModeNever() {
+		return false;
+	}
+
+	public void managedClose() {
+		if ( isClosed() ) {
+			throw new SessionException( "Session was already closed!" );
+		}
+		jdbcContext.getConnectionManager().close();
+		setClosed();
+	}
+
+	public void managedFlush() {
+		errorIfClosed();
+		getBatcher().executeBatch();
+	}
+
+	public boolean shouldAutoClose() {
+		return isAutoCloseSessionEnabled() && !isClosed();
+	}
+
+	public void afterTransactionCompletion(boolean successful, Transaction tx) {}
+
+	public void beforeTransactionCompletion(Transaction tx) {}
+
+	public String bestGuessEntityName(Object object) {
+		if (object instanceof HibernateProxy) {
+			object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation();
+		}
+		return guessEntityName(object);
+	}
+
+	public Connection connection() {
+		errorIfClosed();
+		return jdbcContext.borrowConnection();
+	}
+
+	public int executeUpdate(String query, QueryParameters queryParameters)
+			throws HibernateException {
+		errorIfClosed();
+		queryParameters.validateParameters();
+		HQLQueryPlan plan = getHQLQueryPlan( query, false );
+		boolean success = false;
+		int result = 0;
+		try {
+			result = plan.performExecuteUpdate( queryParameters, this );
+			success = true;
+		}
+		finally {
+			afterOperation(success);
+		}
+		temporaryPersistenceContext.clear();
+		return result;
+	}
+
+	public Batcher getBatcher() {
+		errorIfClosed();
+		return jdbcContext.getConnectionManager()
+				.getBatcher();
+	}
+
+	public CacheMode getCacheMode() {
+		return CacheMode.IGNORE;
+	}
+
+	public int getDontFlushFromFind() {
+		return 0;
+	}
+
+	public Map getEnabledFilters() {
+		return CollectionHelper.EMPTY_MAP;
+	}
+
+	public Serializable getContextEntityIdentifier(Object object) {
+		errorIfClosed();
+		return null;
+	}
+
+	public EntityMode getEntityMode() {
+		return EntityMode.POJO;
+	}
+
+	public EntityPersister getEntityPersister(String entityName, Object object)
+			throws HibernateException {
+		errorIfClosed();
+		if ( entityName==null ) {
+			return factory.getEntityPersister( guessEntityName( object ) );
+		}
+		else {
+			return factory.getEntityPersister( entityName )
+					.getSubclassEntityPersister( object, getFactory(), EntityMode.POJO );
+		}
+	}
+
+	public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException {
+		errorIfClosed();
+		return null;
+	}
+
+	public Type getFilterParameterType(String filterParameterName) {
+		throw new UnsupportedOperationException();
+	}
+
+	public Object getFilterParameterValue(String filterParameterName) {
+		throw new UnsupportedOperationException();
+	}
+
+	public FlushMode getFlushMode() {
+		return FlushMode.COMMIT;
+	}
+
+	public Interceptor getInterceptor() {
+		return EmptyInterceptor.INSTANCE;
+	}
+
+	public EventListeners getListeners() {
+		throw new UnsupportedOperationException();
+	}
+
+	public PersistenceContext getPersistenceContext() {
+		return temporaryPersistenceContext;
+	}
+
+	public long getTimestamp() {
+		throw new UnsupportedOperationException();
+	}
+
+	public String guessEntityName(Object entity) throws HibernateException {
+		errorIfClosed();
+		return entity.getClass().getName();
+	}
+
+
+	public boolean isConnected() {
+		return jdbcContext.getConnectionManager().isCurrentlyConnected();
+	}
+
+	public boolean isTransactionInProgress() {
+		return jdbcContext.isTransactionInProgress();
+	}
+
+	public void setAutoClear(boolean enabled) {
+		throw new UnsupportedOperationException();
+	}
+
+	public void setCacheMode(CacheMode cm) {
+		throw new UnsupportedOperationException();
+	}
+
+	public void setFlushMode(FlushMode fm) {
+		throw new UnsupportedOperationException();
+	}
+
+	public Transaction getTransaction() throws HibernateException {
+		errorIfClosed();
+		return jdbcContext.getTransaction();
+	}
+
+	public Transaction beginTransaction() throws HibernateException {
+		errorIfClosed();
+		Transaction result = getTransaction();
+		result.begin();
+		return result;
+	}
+
+	public boolean isEventSource() {
+		return false;
+	}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+	//TODO: COPY/PASTE FROM SessionImpl, pull up!
+
+	public List list(String query, QueryParameters queryParameters) throws HibernateException {
+		errorIfClosed();
+		queryParameters.validateParameters();
+		HQLQueryPlan plan = getHQLQueryPlan( query, false );
+		boolean success = false;
+		List results = CollectionHelper.EMPTY_LIST;
+		try {
+			results = plan.performList( queryParameters, this );
+			success = true;
+		}
+		finally {
+			afterOperation(success);
+		}
+		temporaryPersistenceContext.clear();
+		return results;
+	}
+
+	public void afterOperation(boolean success) {
+		if ( !jdbcContext.isTransactionInProgress() ) {
+			jdbcContext.afterNontransactionalQuery(success);
+		}
+	}
+
+	public Criteria createCriteria(Class persistentClass, String alias) {
+		errorIfClosed();
+		return new CriteriaImpl( persistentClass.getName(), alias, this );
+	}
+
+	public Criteria createCriteria(String entityName, String alias) {
+		errorIfClosed();
+		return new CriteriaImpl(entityName, alias, this);
+	}
+
+	public Criteria createCriteria(Class persistentClass) {
+		errorIfClosed();
+		return new CriteriaImpl( persistentClass.getName(), this );
+	}
+
+	public Criteria createCriteria(String entityName) {
+		errorIfClosed();
+		return new CriteriaImpl(entityName, this);
+	}
+
+	public ScrollableResults scroll(CriteriaImpl criteria, ScrollMode scrollMode) {
+		errorIfClosed();
+		String entityName = criteria.getEntityOrClassName();
+		CriteriaLoader loader = new CriteriaLoader(
+				getOuterJoinLoadable(entityName),
+		        factory,
+		        criteria,
+		        entityName,
+		        getEnabledFilters()
+			);
+		return loader.scroll(this, scrollMode);
+	}
+
+	public List list(CriteriaImpl criteria) throws HibernateException {
+		errorIfClosed();
+		String[] implementors = factory.getImplementors( criteria.getEntityOrClassName() );
+		int size = implementors.length;
+
+		CriteriaLoader[] loaders = new CriteriaLoader[size];
+		for( int i=0; i <size; i++ ) {
+			loaders[i] = new CriteriaLoader(
+					getOuterJoinLoadable( implementors[i] ),
+			        factory,
+			        criteria,
+			        implementors[i],
+			        getEnabledFilters()
+			);
+		}
+
+
+		List results = Collections.EMPTY_LIST;
+		boolean success = false;
+		try {
+			for( int i=0; i<size; i++ ) {
+				final List currentResults = loaders[i].list(this);
+				currentResults.addAll(results);
+				results = currentResults;
+			}
+			success = true;
+		}
+		finally {
+			afterOperation(success);
+		}
+		temporaryPersistenceContext.clear();
+		return results;
+	}
+
+	private OuterJoinLoadable getOuterJoinLoadable(String entityName) throws MappingException {
+		EntityPersister persister = factory.getEntityPersister(entityName);
+		if ( !(persister instanceof OuterJoinLoadable) ) {
+			throw new MappingException( "class persister is not OuterJoinLoadable: " + entityName );
+		}
+		return ( OuterJoinLoadable ) persister;
+	}
+
+	public List listCustomQuery(CustomQuery customQuery, QueryParameters queryParameters)
+	throws HibernateException {
+		errorIfClosed();
+		CustomLoader loader = new CustomLoader( customQuery, getFactory() );
+
+		boolean success = false;
+		List results;
+		try {
+			results = loader.list(this, queryParameters);
+			success = true;
+		}
+		finally {
+			afterOperation(success);
+		}
+		temporaryPersistenceContext.clear();
+		return results;
+	}
+
+	public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters)
+	throws HibernateException {
+		errorIfClosed();
+		CustomLoader loader = new CustomLoader( customQuery, getFactory() );
+		return loader.scroll(queryParameters, this);
+	}
+
+	public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException {
+		errorIfClosed();
+		HQLQueryPlan plan = getHQLQueryPlan( query, false );
+		return plan.performScroll( queryParameters, this );
+	}
+
+	public void afterScrollOperation() {
+		temporaryPersistenceContext.clear();
+	}
+
+	public void flush() {}
+
+	public String getFetchProfile() {
+		return null;
+	}
+
+	public JDBCContext getJDBCContext() {
+		return jdbcContext;
+	}
+
+	public void setFetchProfile(String name) {}
+
+	public void afterTransactionBegin(Transaction tx) {}
+
+	protected boolean autoFlushIfRequired(Set querySpaces) throws HibernateException {
+		// no auto-flushing to support in stateless session
+		return false;
+	}
+	
+	public int executeNativeUpdate(NativeSQLQuerySpecification nativeSQLQuerySpecification,
+			QueryParameters queryParameters) throws HibernateException {
+		errorIfClosed();
+		queryParameters.validateParameters();
+		NativeSQLQueryPlan plan = getNativeSQLQueryPlan(nativeSQLQuerySpecification);
+
+		boolean success = false;
+		int result = 0;
+		try {
+			result = plan.performExecuteUpdate(queryParameters, this);
+			success = true;
+		} finally {
+			afterOperation(success);
+		}
+		temporaryPersistenceContext.clear();
+		return result;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/impl/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/impl/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package contains implementations of the
+	central Hibernate APIs, especially the
+	Hibernate session.
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/impl/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/AbstractFieldInterceptor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/AbstractFieldInterceptor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/AbstractFieldInterceptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,103 @@
+package org.hibernate.intercept;
+
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.LazyInitializationException;
+
+import java.util.Set;
+import java.io.Serializable;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractFieldInterceptor implements FieldInterceptor, Serializable {
+
+	private transient SessionImplementor session;
+	private Set uninitializedFields;
+	private final String entityName;
+
+	private transient boolean initializing;
+	private boolean dirty;
+
+	protected AbstractFieldInterceptor(SessionImplementor session, Set uninitializedFields, String entityName) {
+		this.session = session;
+		this.uninitializedFields = uninitializedFields;
+		this.entityName = entityName;
+	}
+
+
+	// FieldInterceptor impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public final void setSession(SessionImplementor session) {
+		this.session = session;
+	}
+
+	public final boolean isInitialized() {
+		return uninitializedFields == null || uninitializedFields.size() == 0;
+	}
+
+	public final boolean isInitialized(String field) {
+		return uninitializedFields == null || !uninitializedFields.contains( field );
+	}
+
+	public final void dirty() {
+		dirty = true;
+	}
+
+	public final boolean isDirty() {
+		return dirty;
+	}
+
+	public final void clearDirty() {
+		dirty = false;
+	}
+
+
+	// subclass accesses ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	protected final Object intercept(Object target, String fieldName, Object value) {
+		if ( initializing ) {
+			return value;
+		}
+
+		if ( uninitializedFields != null && uninitializedFields.contains( fieldName ) ) {
+			if ( session == null ) {
+				throw new LazyInitializationException( "entity with lazy properties is not associated with a session" );
+			}
+			else if ( !session.isOpen() || !session.isConnected() ) {
+				throw new LazyInitializationException( "session is not connected" );
+			}
+
+			final Object result;
+			initializing = true;
+			try {
+				result = ( ( LazyPropertyInitializer ) session.getFactory()
+						.getEntityPersister( entityName ) )
+						.initializeLazyProperty( fieldName, target, session );
+			}
+			finally {
+				initializing = false;
+			}
+			uninitializedFields = null; //let's assume that there is only one lazy fetch group, for now!
+			return result;
+		}
+		else {
+			return value;
+		}
+	}
+
+	public final SessionImplementor getSession() {
+		return session;
+	}
+
+	public final Set getUninitializedFields() {
+		return uninitializedFields;
+	}
+
+	public final String getEntityName() {
+		return entityName;
+	}
+
+	public final boolean isInitializing() {
+		return initializing;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/FieldInterceptionHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/FieldInterceptionHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/FieldInterceptionHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,93 @@
+package org.hibernate.intercept;
+
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.intercept.cglib.CGLIBHelper;
+import org.hibernate.intercept.javassist.JavassistHelper;
+
+import java.util.Set;
+
+/**
+ * Helper class for dealing with enhanced entity classes.
+ *
+ * @author Steve Ebersole
+ */
+public class FieldInterceptionHelper {
+
+	// VERY IMPORTANT!!!! - This class needs to be free of any static references
+	// to any CGLIB or Javassist classes.  Otherwise, users will always need both
+	// on their classpaths no matter which (if either) they use.
+	//
+	// Another option here would be to remove the Hibernate.isPropertyInitialized()
+	// method and have the users go through the SessionFactory to get this information.
+
+	private FieldInterceptionHelper() {
+	}
+
+	public static boolean isInstrumented(Class entityClass) {
+		Class[] definedInterfaces = entityClass.getInterfaces();
+		for ( int i = 0; i < definedInterfaces.length; i++ ) {
+			if ( "net.sf.cglib.transform.impl.InterceptFieldEnabled".equals( definedInterfaces[i].getName() )
+			     || "org.hibernate.bytecode.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public static boolean isInstrumented(Object entity) {
+		return entity != null && isInstrumented( entity.getClass() );
+	}
+
+	public static FieldInterceptor extractFieldInterceptor(Object entity) {
+		if ( entity == null ) {
+			return null;
+		}
+		Class[] definedInterfaces = entity.getClass().getInterfaces();
+		for ( int i = 0; i < definedInterfaces.length; i++ ) {
+			if ( "net.sf.cglib.transform.impl.InterceptFieldEnabled".equals( definedInterfaces[i].getName() ) ) {
+				// we have a CGLIB enhanced entity
+				return CGLIBHelper.extractFieldInterceptor( entity );
+			}
+			else if ( "org.hibernate.bytecode.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) {
+				// we have a Javassist enhanced entity
+				return JavassistHelper.extractFieldInterceptor( entity );
+			}
+		}
+		return null;
+	}
+
+	public static FieldInterceptor injectFieldInterceptor(
+			Object entity,
+	        String entityName,
+	        Set uninitializedFieldNames,
+	        SessionImplementor session) {
+		if ( entity != null ) {
+			Class[] definedInterfaces = entity.getClass().getInterfaces();
+			for ( int i = 0; i < definedInterfaces.length; i++ ) {
+				if ( "net.sf.cglib.transform.impl.InterceptFieldEnabled".equals( definedInterfaces[i].getName() ) ) {
+					// we have a CGLIB enhanced entity
+					return CGLIBHelper.injectFieldInterceptor( entity, entityName, uninitializedFieldNames, session );
+				}
+				else if ( "org.hibernate.bytecode.javassist.FieldHandled".equals( definedInterfaces[i].getName() ) ) {
+					// we have a Javassist enhanced entity
+					return JavassistHelper.injectFieldInterceptor( entity, entityName, uninitializedFieldNames, session );
+				}
+			}
+		}
+		return null;
+	}
+
+	public static void clearDirty(Object entity) {
+		FieldInterceptor interceptor = extractFieldInterceptor( entity );
+		if ( interceptor != null ) {
+			interceptor.clearDirty();
+		}
+	}
+
+	public static void markDirty(Object entity) {
+		FieldInterceptor interceptor = extractFieldInterceptor( entity );
+		if ( interceptor != null ) {
+			interceptor.dirty();
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/FieldInterceptor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/FieldInterceptor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/FieldInterceptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+package org.hibernate.intercept;
+
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * Contract for field interception handlers.
+ *
+ * @author Steve Ebersole
+ */
+public interface FieldInterceptor {
+
+	/**
+	 * Use to associate the entity to which we are bound to the given session.
+	 *
+	 * @param session The session to which we are now associated.
+	 */
+	public void setSession(SessionImplementor session);
+
+	/**
+	 * Is the entity to which we are bound completely initialized?
+	 *
+	 * @return True if the entity is initialized; otherwise false.
+	 */
+	public boolean isInitialized();
+
+	/**
+	 * The the given field initialized for the entity to which we are bound?
+	 *
+	 * @param field The name of the field to check
+	 * @return True if the given field is initialized; otherwise false.
+	 */
+	public boolean isInitialized(String field);
+
+	/**
+	 * Forcefully mark the entity as being dirty.
+	 */
+	public void dirty();
+
+	/**
+	 * Is the entity considered dirty?
+	 *
+	 * @return True if the entity is dirty; otherwise false.
+	 */
+	public boolean isDirty();
+
+	/**
+	 * Clear the internal dirty flag.
+	 */
+	public void clearDirty();
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/FieldInterceptor.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/LazyPropertyInitializer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/LazyPropertyInitializer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/LazyPropertyInitializer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+//$Id: LazyPropertyInitializer.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.intercept;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * Contract for controlling how lazy properties get initialized.
+ * 
+ * @author Gavin King
+ */
+public interface LazyPropertyInitializer {
+
+	/**
+	 * Marker value for uninitialized properties
+	 */
+	public static final Serializable UNFETCHED_PROPERTY = new Serializable() {
+		public String toString() {
+			return "<lazy>";
+		}
+		public Object readResolve() {
+			return UNFETCHED_PROPERTY;
+		}
+	};
+
+	/**
+	 * Initialize the property, and return its new value
+	 */
+	public Object initializeLazyProperty(String fieldName, Object entity, SessionImplementor session)
+	throws HibernateException;
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/LazyPropertyInitializer.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/cglib/CGLIBHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/cglib/CGLIBHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/cglib/CGLIBHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+package org.hibernate.intercept.cglib;
+
+import org.hibernate.intercept.FieldInterceptor;
+import org.hibernate.engine.SessionImplementor;
+import net.sf.cglib.transform.impl.InterceptFieldEnabled;
+
+import java.util.Set;
+
+/**
+ * @author Steve Ebersole
+ */
+public class CGLIBHelper {
+	private CGLIBHelper() {
+	}
+
+	public static FieldInterceptor extractFieldInterceptor(Object entity) {
+		return ( FieldInterceptor ) ( ( InterceptFieldEnabled ) entity ).getInterceptFieldCallback();
+	}
+
+	public static FieldInterceptor injectFieldInterceptor(
+			Object entity,
+	        String entityName,
+	        Set uninitializedFieldNames,
+	        SessionImplementor session) {
+		FieldInterceptorImpl fieldInterceptor = new FieldInterceptorImpl(
+				session, uninitializedFieldNames, entityName
+		);
+		( ( InterceptFieldEnabled ) entity ).setInterceptFieldCallback( fieldInterceptor );
+		return fieldInterceptor;
+
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/cglib/FieldInterceptorImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/cglib/FieldInterceptorImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/cglib/FieldInterceptorImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,147 @@
+//$Id: FieldInterceptorImpl.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.intercept.cglib;
+
+import java.io.Serializable;
+import java.util.Set;
+
+import net.sf.cglib.transform.impl.InterceptFieldCallback;
+
+import org.hibernate.intercept.AbstractFieldInterceptor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+
+/**
+ * A field-level interceptor that initializes lazily fetched properties.
+ * This interceptor can be attached to classes instrumented by CGLIB.
+ * Note that this implementation assumes that the instance variable
+ * name is the same as the name of the persistent property that must
+ * be loaded.
+ *
+ * @author Gavin King
+ */
+public final class FieldInterceptorImpl extends AbstractFieldInterceptor implements InterceptFieldCallback, Serializable {
+
+	/**
+	 * Package-protected constructor
+	 *
+	 * @param session
+	 * @param uninitializedFields
+	 * @param entityName
+	 */
+	FieldInterceptorImpl(SessionImplementor session, Set uninitializedFields, String entityName) {
+		super( session, uninitializedFields, entityName );
+	}
+
+	public boolean readBoolean(Object target, String name, boolean oldValue) {
+		return ( ( Boolean ) intercept( target, name, oldValue  ? Boolean.TRUE : Boolean.FALSE ) )
+				.booleanValue();
+	}
+
+	public byte readByte(Object target, String name, byte oldValue) {
+		return ( ( Byte ) intercept( target, name, new Byte( oldValue ) ) ).byteValue();
+	}
+
+	public char readChar(Object target, String name, char oldValue) {
+		return ( ( Character ) intercept( target, name, new Character( oldValue ) ) )
+				.charValue();
+	}
+
+	public double readDouble(Object target, String name, double oldValue) {
+		return ( ( Double ) intercept( target, name, new Double( oldValue ) ) )
+				.doubleValue();
+	}
+
+	public float readFloat(Object target, String name, float oldValue) {
+		return ( ( Float ) intercept( target, name, new Float( oldValue ) ) )
+				.floatValue();
+	}
+
+	public int readInt(Object target, String name, int oldValue) {
+		return ( ( Integer ) intercept( target, name, new Integer( oldValue ) ) )
+				.intValue();
+	}
+
+	public long readLong(Object target, String name, long oldValue) {
+		return ( ( Long ) intercept( target, name, new Long( oldValue ) ) ).longValue();
+	}
+
+	public short readShort(Object target, String name, short oldValue) {
+		return ( ( Short ) intercept( target, name, new Short( oldValue ) ) )
+				.shortValue();
+	}
+
+	public Object readObject(Object target, String name, Object oldValue) {
+		Object value = intercept( target, name, oldValue );
+		if (value instanceof HibernateProxy) {
+			LazyInitializer li = ( (HibernateProxy) value ).getHibernateLazyInitializer();
+			if ( li.isUnwrap() ) {
+				value = li.getImplementation();
+			}
+		}
+		return value;
+	}
+
+	public boolean writeBoolean(Object target, String name, boolean oldValue, boolean newValue) {
+		dirty();
+		intercept( target, name, oldValue ? Boolean.TRUE : Boolean.FALSE );
+		return newValue;
+	}
+
+	public byte writeByte(Object target, String name, byte oldValue, byte newValue) {
+		dirty();
+		intercept( target, name, new Byte( oldValue ) );
+		return newValue;
+	}
+
+	public char writeChar(Object target, String name, char oldValue, char newValue) {
+		dirty();
+		intercept( target, name, new Character( oldValue ) );
+		return newValue;
+	}
+
+	public double writeDouble(Object target, String name, double oldValue, double newValue) {
+		dirty();
+		intercept( target, name, new Double( oldValue ) );
+		return newValue;
+	}
+
+	public float writeFloat(Object target, String name, float oldValue, float newValue) {
+		dirty();
+		intercept( target, name, new Float( oldValue ) );
+		return newValue;
+	}
+
+	public int writeInt(Object target, String name, int oldValue, int newValue) {
+		dirty();
+		intercept( target, name, new Integer( oldValue ) );
+		return newValue;
+	}
+
+	public long writeLong(Object target, String name, long oldValue, long newValue) {
+		dirty();
+		intercept( target, name, new Long( oldValue ) );
+		return newValue;
+	}
+
+	public short writeShort(Object target, String name, short oldValue, short newValue) {
+		dirty();
+		intercept( target, name, new Short( oldValue ) );
+		return newValue;
+	}
+
+	public Object writeObject(Object target, String name, Object oldValue, Object newValue) {
+		dirty();
+		intercept( target, name, oldValue );
+		return newValue;
+	}
+
+	public String toString() {
+		return "FieldInterceptorImpl(" +
+			"entityName=" + getEntityName() +
+			",dirty=" + isDirty() +
+			",uninitializedFields=" + getUninitializedFields() +
+			')';
+	}
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/javassist/FieldInterceptorImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/javassist/FieldInterceptorImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/javassist/FieldInterceptorImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,154 @@
+//$Id: FieldInterceptorImpl.java 10206 2006-08-03 19:59:42Z steve.ebersole at jboss.com $
+package org.hibernate.intercept.javassist;
+
+import java.io.Serializable;
+import java.util.Set;
+
+import org.hibernate.bytecode.javassist.FieldHandler;
+import org.hibernate.intercept.AbstractFieldInterceptor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+
+/**
+ * A field-level interceptor that initializes lazily fetched properties.
+ * This interceptor can be attached to classes instrumented by Javassist.
+ * Note that this implementation assumes that the instance variable
+ * name is the same as the name of the persistent property that must
+ * be loaded.
+ * </p>
+ * Note: most of the interesting functionality here is farmed off
+ * to the super-class.  The stuff here mainly acts as an adapter to the
+ * Javassist-specific functionality, routing interception through
+ * the super-class's intercept() method
+ *
+ * @author Steve Ebersole
+ */
+public final class FieldInterceptorImpl extends AbstractFieldInterceptor implements FieldHandler, Serializable {
+
+	/**
+	 * Package-protected constructor.
+	 *
+	 * @param session
+	 * @param uninitializedFields
+	 * @param entityName
+	 */
+	FieldInterceptorImpl(SessionImplementor session, Set uninitializedFields, String entityName) {
+		super( session, uninitializedFields, entityName );
+	}
+
+
+	// FieldHandler impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean readBoolean(Object target, String name, boolean oldValue) {
+		return ( ( Boolean ) intercept( target, name, oldValue  ? Boolean.TRUE : Boolean.FALSE ) )
+				.booleanValue();
+	}
+
+	public byte readByte(Object target, String name, byte oldValue) {
+		return ( ( Byte ) intercept( target, name, new Byte( oldValue ) ) ).byteValue();
+	}
+
+	public char readChar(Object target, String name, char oldValue) {
+		return ( ( Character ) intercept( target, name, new Character( oldValue ) ) )
+				.charValue();
+	}
+
+	public double readDouble(Object target, String name, double oldValue) {
+		return ( ( Double ) intercept( target, name, new Double( oldValue ) ) )
+				.doubleValue();
+	}
+
+	public float readFloat(Object target, String name, float oldValue) {
+		return ( ( Float ) intercept( target, name, new Float( oldValue ) ) )
+				.floatValue();
+	}
+
+	public int readInt(Object target, String name, int oldValue) {
+		return ( ( Integer ) intercept( target, name, new Integer( oldValue ) ) )
+				.intValue();
+	}
+
+	public long readLong(Object target, String name, long oldValue) {
+		return ( ( Long ) intercept( target, name, new Long( oldValue ) ) ).longValue();
+	}
+
+	public short readShort(Object target, String name, short oldValue) {
+		return ( ( Short ) intercept( target, name, new Short( oldValue ) ) )
+				.shortValue();
+	}
+
+	public Object readObject(Object target, String name, Object oldValue) {
+		Object value = intercept( target, name, oldValue );
+		if (value instanceof HibernateProxy) {
+			LazyInitializer li = ( (HibernateProxy) value ).getHibernateLazyInitializer();
+			if ( li.isUnwrap() ) {
+				value = li.getImplementation();
+			}
+		}
+		return value;
+	}
+
+	public boolean writeBoolean(Object target, String name, boolean oldValue, boolean newValue) {
+		dirty();
+		intercept( target, name, oldValue ? Boolean.TRUE : Boolean.FALSE );
+		return newValue;
+	}
+
+	public byte writeByte(Object target, String name, byte oldValue, byte newValue) {
+		dirty();
+		intercept( target, name, new Byte( oldValue ) );
+		return newValue;
+	}
+
+	public char writeChar(Object target, String name, char oldValue, char newValue) {
+		dirty();
+		intercept( target, name, new Character( oldValue ) );
+		return newValue;
+	}
+
+	public double writeDouble(Object target, String name, double oldValue, double newValue) {
+		dirty();
+		intercept( target, name, new Double( oldValue ) );
+		return newValue;
+	}
+
+	public float writeFloat(Object target, String name, float oldValue, float newValue) {
+		dirty();
+		intercept( target, name, new Float( oldValue ) );
+		return newValue;
+	}
+
+	public int writeInt(Object target, String name, int oldValue, int newValue) {
+		dirty();
+		intercept( target, name, new Integer( oldValue ) );
+		return newValue;
+	}
+
+	public long writeLong(Object target, String name, long oldValue, long newValue) {
+		dirty();
+		intercept( target, name, new Long( oldValue ) );
+		return newValue;
+	}
+
+	public short writeShort(Object target, String name, short oldValue, short newValue) {
+		dirty();
+		intercept( target, name, new Short( oldValue ) );
+		return newValue;
+	}
+
+	public Object writeObject(Object target, String name, Object oldValue, Object newValue) {
+		dirty();
+		intercept( target, name, oldValue );
+		return newValue;
+	}
+
+	public String toString() {
+		return "FieldInterceptorImpl(" +
+		       "entityName=" + getEntityName() +
+		       ",dirty=" + isDirty() +
+		       ",uninitializedFields=" + getUninitializedFields() +
+		       ')';
+	}
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/javassist/JavassistHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/javassist/JavassistHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/javassist/JavassistHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+package org.hibernate.intercept.javassist;
+
+import org.hibernate.intercept.FieldInterceptor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.bytecode.javassist.FieldHandled;
+
+import java.util.Set;
+
+/**
+ * @author Steve Ebersole
+ */
+public class JavassistHelper {
+	private JavassistHelper() {
+	}
+
+	public static FieldInterceptor extractFieldInterceptor(Object entity) {
+		return ( FieldInterceptor ) ( ( FieldHandled ) entity ).getFieldHandler();
+	}
+
+	public static FieldInterceptor injectFieldInterceptor(
+			Object entity,
+	        String entityName,
+	        Set uninitializedFieldNames,
+	        SessionImplementor session) {
+		FieldInterceptorImpl fieldInterceptor = new FieldInterceptorImpl( session, uninitializedFieldNames, entityName );
+		( ( FieldHandled ) entity ).setFieldHandler( fieldInterceptor );
+		return fieldInterceptor;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package implements an interception
+	mechanism for lazy property fetching,
+	based on CGLIB bytecode instrumentation.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/intercept/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/AbstractBatcher.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/AbstractBatcher.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/AbstractBatcher.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,620 @@
+//$Id: AbstractBatcher.java 11332 2007-03-22 17:34:55Z steve.ebersole at jboss.com $
+package org.hibernate.jdbc;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.ScrollMode;
+import org.hibernate.TransactionException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.pretty.Formatter;
+import org.hibernate.util.GetGeneratedKeysHelper;
+import org.hibernate.util.JDBCExceptionReporter;
+import org.hibernate.util.NamedGeneratedKeysHelper;
+
+/**
+ * Manages prepared statements and batching.
+ *
+ * @author Gavin King
+ */
+public abstract class AbstractBatcher implements Batcher {
+
+	private static int globalOpenPreparedStatementCount;
+	private static int globalOpenResultSetCount;
+
+	private int openPreparedStatementCount;
+	private int openResultSetCount;
+
+	protected static final Log log = LogFactory.getLog(AbstractBatcher.class);
+	protected static final Log SQL_LOG = LogFactory.getLog("org.hibernate.SQL");
+
+	private final ConnectionManager connectionManager;
+	private final SessionFactoryImplementor factory;
+
+	private PreparedStatement batchUpdate;
+	private String batchUpdateSQL;
+
+	private HashSet statementsToClose = new HashSet();
+	private HashSet resultSetsToClose = new HashSet();
+	private PreparedStatement lastQuery;
+
+	private boolean releasing = false;
+	private final Interceptor interceptor;
+
+	private long transactionTimeout = -1;
+	boolean isTransactionTimeoutSet;
+
+	public AbstractBatcher(ConnectionManager connectionManager, Interceptor interceptor) {
+		this.connectionManager = connectionManager;
+		this.interceptor = interceptor;
+		this.factory = connectionManager.getFactory();
+	}
+
+	public void setTransactionTimeout(int seconds) {
+		isTransactionTimeoutSet = true;
+		transactionTimeout = System.currentTimeMillis() / 1000 + seconds;
+	}
+
+	public void unsetTransactionTimeout() {
+		isTransactionTimeoutSet = false;
+	}
+
+	protected PreparedStatement getStatement() {
+		return batchUpdate;
+	}
+
+	public CallableStatement prepareCallableStatement(String sql)
+	throws SQLException, HibernateException {
+		executeBatch();
+		logOpenPreparedStatement();
+		return getCallableStatement( connectionManager.getConnection(), sql, false);
+	}
+
+	public PreparedStatement prepareStatement(String sql)
+	throws SQLException, HibernateException {
+		return prepareStatement( sql, false );
+	}
+
+	public PreparedStatement prepareStatement(String sql, boolean getGeneratedKeys)
+			throws SQLException, HibernateException {
+		executeBatch();
+		logOpenPreparedStatement();
+		return getPreparedStatement(
+				connectionManager.getConnection(),
+		        sql,
+		        false,
+		        getGeneratedKeys,
+		        null,
+		        null,
+		        false
+		);
+	}
+
+	public PreparedStatement prepareStatement(String sql, String[] columnNames)
+			throws SQLException, HibernateException {
+		executeBatch();
+		logOpenPreparedStatement();
+		return getPreparedStatement(
+				connectionManager.getConnection(),
+		        sql,
+		        false,
+		        false,
+		        columnNames,
+		        null,
+		        false
+		);
+	}
+
+	public PreparedStatement prepareSelectStatement(String sql)
+			throws SQLException, HibernateException {
+		logOpenPreparedStatement();
+		return getPreparedStatement(
+				connectionManager.getConnection(),
+		        sql,
+		        false,
+		        false,
+		        null,
+		        null,
+		        false
+		);
+	}
+
+	public PreparedStatement prepareQueryStatement(
+			String sql,
+	        boolean scrollable,
+	        ScrollMode scrollMode) throws SQLException, HibernateException {
+		logOpenPreparedStatement();
+		PreparedStatement ps = getPreparedStatement(
+				connectionManager.getConnection(),
+		        sql,
+		        scrollable,
+		        scrollMode
+		);
+		setStatementFetchSize( ps );
+		statementsToClose.add( ps );
+		lastQuery = ps;
+		return ps;
+	}
+
+	public CallableStatement prepareCallableQueryStatement(
+			String sql,
+	        boolean scrollable,
+	        ScrollMode scrollMode) throws SQLException, HibernateException {
+		logOpenPreparedStatement();
+		CallableStatement ps = ( CallableStatement ) getPreparedStatement(
+				connectionManager.getConnection(),
+		        sql,
+		        scrollable,
+		        false,
+		        null,
+		        scrollMode,
+		        true
+		);
+		setStatementFetchSize( ps );
+		statementsToClose.add( ps );
+		lastQuery = ps;
+		return ps;
+	}
+
+	public void abortBatch(SQLException sqle) {
+		try {
+			if (batchUpdate!=null) closeStatement(batchUpdate);
+		}
+		catch (SQLException e) {
+			//noncritical, swallow and let the other propagate!
+			JDBCExceptionReporter.logExceptions(e);
+		}
+		finally {
+			batchUpdate=null;
+			batchUpdateSQL=null;
+		}
+	}
+
+	public ResultSet getResultSet(PreparedStatement ps) throws SQLException {
+		ResultSet rs = ps.executeQuery();
+		resultSetsToClose.add(rs);
+		logOpenResults();
+		return rs;
+	}
+
+	public ResultSet getResultSet(CallableStatement ps, Dialect dialect) throws SQLException {
+		ResultSet rs = dialect.getResultSet(ps);
+		resultSetsToClose.add(rs);
+		logOpenResults();
+		return rs;
+
+	}
+
+	public void closeQueryStatement(PreparedStatement ps, ResultSet rs) throws SQLException {
+		boolean psStillThere = statementsToClose.remove( ps );
+		try {
+			if ( rs != null ) {
+				if ( resultSetsToClose.remove( rs ) ) {
+					logCloseResults();
+					rs.close();
+				}
+			}
+		}
+		finally {
+			if ( psStillThere ) {
+				closeQueryStatement( ps );
+			}
+		}
+	}
+
+	public PreparedStatement prepareBatchStatement(String sql)
+			throws SQLException, HibernateException {
+		sql = getSQL( sql );
+
+		if ( !sql.equals(batchUpdateSQL) ) {
+			batchUpdate=prepareStatement(sql); // calls executeBatch()
+			batchUpdateSQL=sql;
+		}
+		else {
+			log.debug("reusing prepared statement");
+			log(sql);
+		}
+		return batchUpdate;
+	}
+
+	public CallableStatement prepareBatchCallableStatement(String sql)
+			throws SQLException, HibernateException {
+		if ( !sql.equals(batchUpdateSQL) ) { // TODO: what if batchUpdate is a callablestatement ?
+			batchUpdate=prepareCallableStatement(sql); // calls executeBatch()
+			batchUpdateSQL=sql;
+		}
+		return (CallableStatement)batchUpdate;
+	}
+
+
+	public void executeBatch() throws HibernateException {
+		if (batchUpdate!=null) {
+			try {
+				try {
+					doExecuteBatch(batchUpdate);
+				}
+				finally {
+					closeStatement(batchUpdate);
+				}
+			}
+			catch (SQLException sqle) {
+				throw JDBCExceptionHelper.convert(
+				        factory.getSQLExceptionConverter(),
+				        sqle,
+				        "Could not execute JDBC batch update",
+				        batchUpdateSQL
+					);
+			}
+			finally {
+				batchUpdate=null;
+				batchUpdateSQL=null;
+			}
+		}
+	}
+
+	public void closeStatement(PreparedStatement ps) throws SQLException {
+		logClosePreparedStatement();
+		closePreparedStatement(ps);
+	}
+
+	private void closeQueryStatement(PreparedStatement ps) throws SQLException {
+
+		try {
+			//work around a bug in all known connection pools....
+			if ( ps.getMaxRows()!=0 ) ps.setMaxRows(0);
+			if ( ps.getQueryTimeout()!=0 ) ps.setQueryTimeout(0);
+		}
+		catch (Exception e) {
+			log.warn("exception clearing maxRows/queryTimeout", e);
+//			ps.close(); //just close it; do NOT try to return it to the pool!
+			return; //NOTE: early exit!
+		}
+		finally {
+			closeStatement(ps);
+		}
+
+		if ( lastQuery==ps ) lastQuery = null;
+
+	}
+
+	/**
+	 * Actually releases the batcher, allowing it to cleanup internally held
+	 * resources.
+	 */
+	public void closeStatements() {
+		try {
+			releasing = true;
+
+			try {
+				if (batchUpdate!=null) batchUpdate.close();
+			}
+			catch (SQLException sqle) {
+				//no big deal
+				log.warn("Could not close a JDBC prepared statement", sqle);
+			}
+			batchUpdate=null;
+			batchUpdateSQL=null;
+
+			Iterator iter = resultSetsToClose.iterator();
+			while ( iter.hasNext() ) {
+				try {
+					logCloseResults();
+					( (ResultSet) iter.next() ).close();
+				}
+				catch (SQLException e) {
+					// no big deal
+					log.warn("Could not close a JDBC result set", e);
+				}
+				catch (Throwable e) {
+					// sybase driver (jConnect) throwing NPE here in certain cases
+					log.warn("Could not close a JDBC result set", e);
+				}
+			}
+			resultSetsToClose.clear();
+
+			iter = statementsToClose.iterator();
+			while ( iter.hasNext() ) {
+				try {
+					closeQueryStatement( (PreparedStatement) iter.next() );
+				}
+				catch (SQLException e) {
+					// no big deal
+					log.warn("Could not close a JDBC statement", e);
+				}
+			}
+			statementsToClose.clear();
+		}
+		finally {
+			releasing = false;
+		}
+	}
+
+	protected abstract void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException;
+
+	private String preparedStatementCountsToString() {
+		return
+				" (open PreparedStatements: " +
+				openPreparedStatementCount +
+				", globally: " +
+				globalOpenPreparedStatementCount +
+				")";
+	}
+
+	private String resultSetCountsToString() {
+		return
+				" (open ResultSets: " +
+				openResultSetCount +
+				", globally: " +
+				globalOpenResultSetCount +
+				")";
+	}
+
+	private void logOpenPreparedStatement() {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "about to open PreparedStatement" + preparedStatementCountsToString() );
+			openPreparedStatementCount++;
+			globalOpenPreparedStatementCount++;
+		}
+	}
+
+	private void logClosePreparedStatement() {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "about to close PreparedStatement" + preparedStatementCountsToString() );
+			openPreparedStatementCount--;
+			globalOpenPreparedStatementCount--;
+		}
+	}
+
+	private void logOpenResults() {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "about to open ResultSet" + resultSetCountsToString() );
+			openResultSetCount++;
+			globalOpenResultSetCount++;
+		}
+	}
+	private void logCloseResults() {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "about to close ResultSet" + resultSetCountsToString() );
+			openResultSetCount--;
+			globalOpenResultSetCount--;
+		}
+	}
+
+	protected SessionFactoryImplementor getFactory() {
+		return factory;
+	}
+
+	private void log(String sql) {
+		if ( SQL_LOG.isDebugEnabled() ) {
+			SQL_LOG.debug( format(sql) );
+		}
+		if ( factory.getSettings().isShowSqlEnabled() ) {
+			System.out.println( "Hibernate: " + format(sql) );
+		}
+	}
+
+	private String format(String sql) {
+		if ( factory.getSettings().isFormatSqlEnabled() ) {
+			return new Formatter(sql).format();
+		}
+		else {
+			return sql;
+		}
+	}
+
+	private PreparedStatement getPreparedStatement(
+			final Connection conn,
+	        final String sql,
+	        final boolean scrollable,
+	        final ScrollMode scrollMode)
+	throws SQLException {
+		return getPreparedStatement(
+				conn,
+		        sql,
+		        scrollable,
+		        false,
+		        null,
+		        scrollMode,
+		        false
+		);
+	}
+
+	private CallableStatement getCallableStatement(
+			final Connection conn,
+	        String sql,
+	        boolean scrollable) throws SQLException {
+		if ( scrollable && !factory.getSettings().isScrollableResultSetsEnabled() ) {
+			throw new AssertionFailure("scrollable result sets are not enabled");
+		}
+
+		sql = getSQL( sql );
+		log( sql );
+
+		log.trace("preparing callable statement");
+		if ( scrollable ) {
+			return conn.prepareCall(
+					sql,
+			        ResultSet.TYPE_SCROLL_INSENSITIVE,
+			        ResultSet.CONCUR_READ_ONLY
+			);
+		}
+		else {
+			return conn.prepareCall( sql );
+		}
+	}
+
+	private String getSQL(String sql) {
+		sql = interceptor.onPrepareStatement( sql );
+		if ( sql==null || sql.length() == 0 ) {
+			throw new AssertionFailure( "Interceptor.onPrepareStatement() returned null or empty string." );
+		}
+		return sql;
+	}
+
+	private PreparedStatement getPreparedStatement(
+			final Connection conn,
+	        String sql,
+	        boolean scrollable,
+	        final boolean useGetGeneratedKeys,
+	        final String[] namedGeneratedKeys,
+	        final ScrollMode scrollMode,
+	        final boolean callable) throws SQLException {
+		if ( scrollable && !factory.getSettings().isScrollableResultSetsEnabled() ) {
+			throw new AssertionFailure("scrollable result sets are not enabled");
+		}
+		if ( useGetGeneratedKeys && !factory.getSettings().isGetGeneratedKeysEnabled() ) {
+			throw new AssertionFailure("getGeneratedKeys() support is not enabled");
+		}
+
+		sql = getSQL( sql );
+		log( sql );
+
+		log.trace( "preparing statement" );
+		PreparedStatement result;
+		if ( scrollable ) {
+			if ( callable ) {
+				result = conn.prepareCall( sql, scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY );
+			}
+			else {
+				result = conn.prepareStatement( sql, scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY );
+			}
+		}
+		else if ( useGetGeneratedKeys ) {
+			result = GetGeneratedKeysHelper.prepareStatement( conn, sql );
+		}
+		else if ( namedGeneratedKeys != null ) {
+			result = NamedGeneratedKeysHelper.prepareStatement( conn, sql, namedGeneratedKeys );
+		}
+		else {
+			if ( callable ) {
+				result = conn.prepareCall( sql );
+			}
+			else {
+				result = conn.prepareStatement( sql );
+			}
+		}
+
+		setTimeout( result );
+
+		if ( factory.getStatistics().isStatisticsEnabled() ) {
+			factory.getStatisticsImplementor().prepareStatement();
+		}
+
+		return result;
+
+	}
+
+	private void setTimeout(PreparedStatement result) throws SQLException {
+		if ( isTransactionTimeoutSet ) {
+			int timeout = (int) ( transactionTimeout - ( System.currentTimeMillis() / 1000 ) );
+			if (timeout<=0) {
+				throw new TransactionException("transaction timeout expired");
+			}
+			else {
+				result.setQueryTimeout(timeout);
+			}
+		}
+	}
+
+	private void closePreparedStatement(PreparedStatement ps) throws SQLException {
+		try {
+			log.trace("closing statement");
+			ps.close();
+			if ( factory.getStatistics().isStatisticsEnabled() ) {
+				factory.getStatisticsImplementor().closeStatement();
+			}
+		}
+		finally {
+			if ( !releasing ) {
+				// If we are in the process of releasing, no sense
+				// checking for aggressive-release possibility.
+				connectionManager.afterStatement();
+			}
+		}
+	}
+
+	private void setStatementFetchSize(PreparedStatement statement) throws SQLException {
+		Integer statementFetchSize = factory.getSettings().getJdbcFetchSize();
+		if ( statementFetchSize!=null ) {
+			statement.setFetchSize( statementFetchSize.intValue() );
+		}
+	}
+
+	public Connection openConnection() throws HibernateException {
+		log.debug("opening JDBC connection");
+		try {
+			return factory.getConnectionProvider().getConnection();
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					factory.getSQLExceptionConverter(),
+			        sqle,
+			        "Cannot open connection"
+				);
+		}
+	}
+
+	public void closeConnection(Connection conn) throws HibernateException {
+		if ( log.isDebugEnabled() ) {
+			log.debug(
+					"closing JDBC connection" +
+					preparedStatementCountsToString() +
+					resultSetCountsToString()
+				);
+		}
+
+		try {
+			if ( !conn.isClosed() ) {
+				JDBCExceptionReporter.logAndClearWarnings(conn);
+			}
+			factory.getConnectionProvider().closeConnection(conn);
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					factory.getSQLExceptionConverter(),
+			        sqle,
+			        "Cannot close connection"
+				);
+		}
+	}
+
+	public void cancelLastQuery() throws HibernateException {
+		try {
+			if (lastQuery!=null) lastQuery.cancel();
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					factory.getSQLExceptionConverter(),
+			        sqle,
+			        "Cannot cancel query"
+				);
+		}
+	}
+
+	public boolean hasOpenResources() {
+		return resultSetsToClose.size() > 0 || statementsToClose.size() > 0;
+	}
+
+	public String openResourceStatsAsString() {
+		return preparedStatementCountsToString() + resultSetCountsToString();
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchFailedException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchFailedException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchFailedException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+package org.hibernate.jdbc;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Indicates a failed batch entry (-3 return).
+ *
+ * @author Steve Ebersole
+ */
+public class BatchFailedException extends HibernateException {
+	public BatchFailedException(String s) {
+		super( s );
+	}
+
+	public BatchFailedException(String string, Throwable root) {
+		super( string, root );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchedTooManyRowsAffectedException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchedTooManyRowsAffectedException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchedTooManyRowsAffectedException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+package org.hibernate.jdbc;
+
+/**
+ * Much like {@link TooManyRowsAffectedException}, indicates that more
+ * rows than what we were expcecting were affected.  Additionally, this form
+ * occurs from a batch and carries along the batch positon that failed.
+ *
+ * @author Steve Ebersole
+ */
+public class BatchedTooManyRowsAffectedException extends TooManyRowsAffectedException {
+	private final int batchPosition;
+
+	public BatchedTooManyRowsAffectedException(String message, int expectedRowCount, int actualRowCount, int batchPosition) {
+		super( message, expectedRowCount, actualRowCount );
+		this.batchPosition = batchPosition;
+	}
+
+	public int getBatchPosition() {
+		return batchPosition;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/Batcher.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/Batcher.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/Batcher.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,163 @@
+//$Id: Batcher.java 10040 2006-06-22 19:51:43Z steve.ebersole at jboss.com $
+package org.hibernate.jdbc;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.hibernate.HibernateException;
+import org.hibernate.ScrollMode;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * Manages <tt>PreparedStatement</tt>s for a session. Abstracts JDBC
+ * batching to maintain the illusion that a single logical batch
+ * exists for the whole session, even when batching is disabled.
+ * Provides transparent <tt>PreparedStatement</tt> caching.
+ *
+ * @see java.sql.PreparedStatement
+ * @see org.hibernate.impl.SessionImpl
+ * @author Gavin King
+ */
+public interface Batcher {
+	/**
+	 * Get a prepared statement for use in loading / querying. If not explicitly
+	 * released by <tt>closeQueryStatement()</tt>, it will be released when the
+	 * session is closed or disconnected.
+	 */
+	public PreparedStatement prepareQueryStatement(String sql, boolean scrollable, ScrollMode scrollMode) throws SQLException, HibernateException;
+	/**
+	 * Close a prepared statement opened with <tt>prepareQueryStatement()</tt>
+	 */
+	public void closeQueryStatement(PreparedStatement ps, ResultSet rs) throws SQLException;
+	/**
+	 * Get a prepared statement for use in loading / querying. If not explicitly
+	 * released by <tt>closeQueryStatement()</tt>, it will be released when the
+	 * session is closed or disconnected.
+	 */
+	public CallableStatement prepareCallableQueryStatement(String sql, boolean scrollable, ScrollMode scrollMode) throws SQLException, HibernateException;
+	
+	
+	/**
+	 * Get a non-batchable prepared statement to use for selecting. Does not
+	 * result in execution of the current batch.
+	 */
+	public PreparedStatement prepareSelectStatement(String sql) throws SQLException, HibernateException;
+
+	/**
+	 * Get a non-batchable prepared statement to use for inserting / deleting / updating,
+	 * using JDBC3 getGeneratedKeys ({@link Connection#prepareStatement(String, int)}).
+	 * <p/>
+	 * Must be explicitly released by {@link #closeStatement} after use.
+	 */
+	public PreparedStatement prepareStatement(String sql, boolean useGetGeneratedKeys) throws SQLException, HibernateException;
+
+	/**
+	 * Get a non-batchable prepared statement to use for inserting / deleting / updating.
+	 * using JDBC3 getGeneratedKeys ({@link Connection#prepareStatement(String, String[])}).
+	 * <p/>
+	 * Must be explicitly released by {@link #closeStatement} after use.
+	 */
+	public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException, HibernateException;
+
+	/**
+	 * Get a non-batchable prepared statement to use for inserting / deleting / updating.
+	 * <p/>
+	 * Must be explicitly released by {@link #closeStatement} after use.
+	 */
+	public PreparedStatement prepareStatement(String sql) throws SQLException, HibernateException;
+
+	/**
+	 * Get a non-batchable callable statement to use for inserting / deleting / updating.
+	 * <p/>
+	 * Must be explicitly released by {@link #closeStatement} after use.
+	 */
+	public CallableStatement prepareCallableStatement(String sql) throws SQLException, HibernateException;
+
+	/**
+	 * Close a prepared or callable statement opened using <tt>prepareStatement()</tt> or <tt>prepareCallableStatement()</tt>
+	 */
+	public void closeStatement(PreparedStatement ps) throws SQLException;
+
+	/**
+	 * Get a batchable prepared statement to use for inserting / deleting / updating
+	 * (might be called many times before a single call to <tt>executeBatch()</tt>).
+	 * After setting parameters, call <tt>addToBatch</tt> - do not execute the
+	 * statement explicitly.
+	 * @see Batcher#addToBatch
+	 */
+	public PreparedStatement prepareBatchStatement(String sql) throws SQLException, HibernateException;
+
+	/**
+	 * Get a batchable callable statement to use for inserting / deleting / updating
+	 * (might be called many times before a single call to <tt>executeBatch()</tt>).
+	 * After setting parameters, call <tt>addToBatch</tt> - do not execute the
+	 * statement explicitly.
+	 * @see Batcher#addToBatch
+	 */
+	public CallableStatement prepareBatchCallableStatement(String sql) throws SQLException, HibernateException;
+
+	/**
+	 * Add an insert / delete / update to the current batch (might be called multiple times
+	 * for single <tt>prepareBatchStatement()</tt>)
+	 */
+	public void addToBatch(Expectation expectation) throws SQLException, HibernateException;
+
+	/**
+	 * Execute the batch
+	 */
+	public void executeBatch() throws HibernateException;
+
+	/**
+	 * Close any query statements that were left lying around
+	 */
+	public void closeStatements();
+	/**
+	 * Execute the statement and return the result set
+	 */
+	public ResultSet getResultSet(PreparedStatement ps) throws SQLException;
+	/**
+	 * Execute the statement and return the result set from a callable statement
+	 */
+	public ResultSet getResultSet(CallableStatement ps, Dialect dialect) throws SQLException;
+
+	/**
+	 * Must be called when an exception occurs
+	 * @param sqle the (not null) exception that is the reason for aborting
+	 */
+	public void abortBatch(SQLException sqle);
+
+	/**
+	 * Cancel the current query statement
+	 */
+	public void cancelLastQuery() throws HibernateException;
+
+	public boolean hasOpenResources();
+
+	public String openResourceStatsAsString();
+
+	// TODO : remove these last two as batcher is no longer managing connections
+
+	/**
+	 * Obtain a JDBC connection
+	 */
+	public Connection openConnection() throws HibernateException;
+	/**
+	 * Dispose of the JDBC connection
+	 */
+	public void closeConnection(Connection conn) throws HibernateException;
+	
+	/**
+	 * Set the transaction timeout to <tt>seconds</tt> later
+	 * than the current system time.
+	 */
+	public void setTransactionTimeout(int seconds);
+	/**
+	 * Unset the transaction timeout, called after the end of a 
+	 * transaction.
+	 */
+	public void unsetTransactionTimeout();
+}
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatcherFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatcherFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatcherFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+//$Id: BatcherFactory.java 7683 2005-07-29 19:10:20Z maxcsaucdk $
+package org.hibernate.jdbc;
+
+import org.hibernate.Interceptor;
+
+
+/**
+ * Factory for <tt>Batcher</tt> instances.
+ * @author Gavin King
+ */
+public interface BatcherFactory {
+	public Batcher createBatcher(ConnectionManager connectionManager, Interceptor interceptor);
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatcherFactory.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchingBatcher.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchingBatcher.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchingBatcher.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+//$Id: BatchingBatcher.java 10040 2006-06-22 19:51:43Z steve.ebersole at jboss.com $
+package org.hibernate.jdbc;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.StaleStateException;
+
+/**
+ * An implementation of the <tt>Batcher</tt> interface that
+ * actually uses batching
+ * @author Gavin King
+ */
+public class BatchingBatcher extends AbstractBatcher {
+
+	private int batchSize;
+	private Expectation[] expectations;
+	
+	public BatchingBatcher(ConnectionManager connectionManager, Interceptor interceptor) {
+		super( connectionManager, interceptor );
+		expectations = new Expectation[ getFactory().getSettings().getJdbcBatchSize() ];
+	}
+
+	public void addToBatch(Expectation expectation) throws SQLException, HibernateException {
+		if ( !expectation.canBeBatched() ) {
+			throw new HibernateException( "attempting to batch an operation which cannot be batched" );
+		}
+		PreparedStatement batchUpdate = getStatement();
+		batchUpdate.addBatch();
+		expectations[ batchSize++ ] = expectation;
+		if ( batchSize == getFactory().getSettings().getJdbcBatchSize() ) {
+			doExecuteBatch( batchUpdate );
+		}
+	}
+
+	protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException {
+		if ( batchSize == 0 ) {
+			log.debug( "no batched statements to execute" );
+		}
+		else {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "Executing batch size: " + batchSize );
+			}
+
+			try {
+				checkRowCounts( ps.executeBatch(), ps );
+			}
+			catch (RuntimeException re) {
+				log.error( "Exception executing batch: ", re );
+				throw re;
+			}
+			finally {
+				batchSize = 0;
+			}
+
+		}
+
+	}
+
+	private void checkRowCounts(int[] rowCounts, PreparedStatement ps) throws SQLException, HibernateException {
+		int numberOfRowCounts = rowCounts.length;
+		if ( numberOfRowCounts != batchSize ) {
+			log.warn( "JDBC driver did not return the expected number of row counts" );
+		}
+		for ( int i = 0; i < numberOfRowCounts; i++ ) {
+			expectations[i].verifyOutcome( rowCounts[i], ps, i );
+		}
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchingBatcherFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchingBatcherFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchingBatcherFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+//$Id: BatchingBatcherFactory.java 7683 2005-07-29 19:10:20Z maxcsaucdk $
+package org.hibernate.jdbc;
+
+import org.hibernate.Interceptor;
+
+
+/**
+ * A BatcherFactory implementation which constructs Batcher instances
+ * capable of actually performing batch operations.
+ * 
+ * @author Gavin King
+ */
+public class BatchingBatcherFactory implements BatcherFactory {
+
+	public Batcher createBatcher(ConnectionManager connectionManager, Interceptor interceptor) {
+		return new BatchingBatcher( connectionManager, interceptor );
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BatchingBatcherFactory.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BorrowedConnectionProxy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BorrowedConnectionProxy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/BorrowedConnectionProxy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,117 @@
+package org.hibernate.jdbc;
+
+import org.hibernate.HibernateException;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.InvocationTargetException;
+import java.sql.Connection;
+
+/**
+ * A proxy for <i>borrowed</i> connections which funnels all requests back
+ * into the ConnectionManager from which it was borrowed to be properly
+ * handled (in terms of connection release modes).
+ * <p/>
+ * Note: the term borrowed here refers to connection references obtained
+ * via {@link org.hibernate.Session#connection()} for application usage.
+ *
+ * @author Steve Ebersole
+ */
+public class BorrowedConnectionProxy implements InvocationHandler {
+
+	private static final Class[] PROXY_INTERFACES = new Class[] { Connection.class, ConnectionWrapper.class };
+
+	private final ConnectionManager connectionManager;
+	private boolean useable = true;
+
+	public BorrowedConnectionProxy(ConnectionManager connectionManager) {
+		this.connectionManager = connectionManager;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+		if ( "close".equals( method.getName() ) ) {
+			connectionManager.releaseBorrowedConnection();
+			return null;
+		}
+		// should probably no-op commit/rollback here, at least in JTA scenarios
+		if ( !useable ) {
+			throw new HibernateException( "connnection proxy not usable after transaction completion" );
+		}
+
+		if ( "getWrappedConnection".equals( method.getName() ) ) {
+			return connectionManager.getConnection();
+		}
+
+		try {
+			return method.invoke( connectionManager.getConnection(), args );
+		}
+		catch( InvocationTargetException e ) {
+			throw e.getTargetException();
+		}
+	}
+
+	/**
+	 * Generates a Connection proxy wrapping the connection managed by the passed
+	 * connection manager.
+	 *
+	 * @param connectionManager The connection manager to wrap with the
+	 * connection proxy.
+	 * @return The generated proxy.
+	 */
+	public static Connection generateProxy(ConnectionManager connectionManager) {
+		BorrowedConnectionProxy handler = new BorrowedConnectionProxy( connectionManager );
+		return ( Connection ) Proxy.newProxyInstance(
+				getProxyClassLoader(),
+		        PROXY_INTERFACES,
+		        handler
+		);
+	}
+
+	/**
+	 * Marks a borrowed connection as no longer usable.
+	 *
+	 * @param connection The connection (proxy) to be marked.
+	 */
+	public static void renderUnuseable(Connection connection) {
+		if ( connection != null && Proxy.isProxyClass( connection.getClass() ) ) {
+			InvocationHandler handler = Proxy.getInvocationHandler( connection );
+			if ( BorrowedConnectionProxy.class.isAssignableFrom( handler.getClass() ) ) {
+				( ( BorrowedConnectionProxy ) handler ).useable = false;
+			}
+		}
+	}
+
+	/**
+	 * Convience method for unwrapping a connection proxy and getting a
+	 * handle to an underlying connection.
+	 *
+	 * @param connection The connection (proxy) to be unwrapped.
+	 * @return The unwrapped connection.
+	 */
+	public static Connection getWrappedConnection(Connection connection) {
+		if ( connection != null && connection instanceof ConnectionWrapper ) {
+			return ( ( ConnectionWrapper ) connection ).getWrappedConnection();
+		}
+		else {
+			return connection;
+		}
+	}
+
+	/**
+	 * Determines the appropriate class loader to which the generated proxy
+	 * should be scoped.
+	 *
+	 * @return The class loader appropriate for proxy construction.
+	 */
+	public static ClassLoader getProxyClassLoader() {
+		ClassLoader cl = Thread.currentThread().getContextClassLoader();
+		if ( cl == null ) {
+			cl = BorrowedConnectionProxy.class.getClassLoader();
+		}
+		return cl;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ColumnNameCache.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ColumnNameCache.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ColumnNameCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+// $Id: ColumnNameCache.java 5811 2005-02-20 23:02:37Z oneovthafew $
+package org.hibernate.jdbc;
+
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Implementation of ColumnNameCache.
+ *
+ * @author Steve Ebersole
+ */
+public class ColumnNameCache {
+
+	private final Map columnNameToIndexCache;
+
+	public ColumnNameCache(int columnCount) {
+		// should *not* need to grow beyond the size of the total number of columns in the rs
+		this.columnNameToIndexCache = new HashMap( columnCount );
+	}
+
+	public int getIndexForColumnName(String columnName, ResultSetWrapper rs)throws SQLException {
+		Integer cached = ( Integer ) columnNameToIndexCache.get( columnName );
+		if ( cached != null ) {
+			return cached.intValue();
+		}
+		else {
+			int index = rs.getTarget().findColumn( columnName );
+			columnNameToIndexCache.put( columnName, new Integer(index) );
+			return index;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ConnectionManager.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ConnectionManager.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ConnectionManager.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,539 @@
+// $Id: ConnectionManager.java 11303 2007-03-19 22:06:14Z steve.ebersole at jboss.com $
+package org.hibernate.jdbc;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.util.JDBCExceptionReporter;
+
+/**
+ * Encapsulates JDBC Connection management logic needed by Hibernate.
+ * <p/>
+ * The lifecycle is intended to span a logical series of interactions with the
+ * database.  Internally, this means the the lifecycle of the Session.
+ *
+ * @author Steve Ebersole
+ */
+public class ConnectionManager implements Serializable {
+
+	private static final Log log = LogFactory.getLog( ConnectionManager.class );
+
+	public static interface Callback {
+		public void connectionOpened();
+		public void connectionCleanedUp();
+		public boolean isTransactionInProgress();
+	}
+
+	private transient SessionFactoryImplementor factory;
+	private final Callback callback;
+
+	private final ConnectionReleaseMode releaseMode;
+	private transient Connection connection;
+	private transient Connection borrowedConnection;
+
+	private final boolean wasConnectionSupplied;
+	private transient Batcher batcher;
+	private transient Interceptor interceptor;
+	private boolean isClosed;
+	private transient boolean isFlushing;
+ 
+	/**
+	 * Constructs a ConnectionManager.
+	 * <p/>
+	 * This is the form used internally.
+	 * 
+	 * @param factory The SessionFactory.
+	 * @param callback An observer for internal state change.
+	 * @param releaseMode The mode by which to release JDBC connections.
+	 * @param connection An externally supplied connection.
+	 */ 
+	public ConnectionManager(
+	        SessionFactoryImplementor factory,
+	        Callback callback,
+	        ConnectionReleaseMode releaseMode,
+	        Connection connection,
+	        Interceptor interceptor) {
+		this.factory = factory;
+		this.callback = callback;
+
+		this.interceptor = interceptor;
+		this.batcher = factory.getSettings().getBatcherFactory().createBatcher( this, interceptor );
+
+		this.connection = connection;
+		wasConnectionSupplied = ( connection != null );
+
+		this.releaseMode = wasConnectionSupplied ? ConnectionReleaseMode.ON_CLOSE : releaseMode;
+	}
+
+	/**
+	 * Private constructor used exclusively from custom serialization
+	 */
+	private ConnectionManager(
+	        SessionFactoryImplementor factory,
+	        Callback callback,
+	        ConnectionReleaseMode releaseMode,
+	        Interceptor interceptor,
+	        boolean wasConnectionSupplied,
+	        boolean isClosed) {
+		this.factory = factory;
+		this.callback = callback;
+
+		this.interceptor = interceptor;
+		this.batcher = factory.getSettings().getBatcherFactory().createBatcher( this, interceptor );
+
+		this.wasConnectionSupplied = wasConnectionSupplied;
+		this.isClosed = isClosed;
+		this.releaseMode = wasConnectionSupplied ? ConnectionReleaseMode.ON_CLOSE : releaseMode;
+	}
+
+	/**
+	 * The session factory.
+	 *
+	 * @return the session factory.
+	 */
+	public SessionFactoryImplementor getFactory() {
+		return factory;
+	}
+
+	/**
+	 * The batcher managed by this ConnectionManager.
+	 *
+	 * @return The batcher.
+	 */
+	public Batcher getBatcher() {
+		return batcher;
+	}
+
+	/**
+	 * Was the connection being used here supplied by the user?
+	 *
+	 * @return True if the user supplied the JDBC connection; false otherwise
+	 */
+	public boolean isSuppliedConnection() {
+		return wasConnectionSupplied;
+	}
+
+	/**
+	 * Retrieves the connection currently managed by this ConnectionManager.
+	 * <p/>
+	 * Note, that we may need to obtain a connection to return here if a
+	 * connection has either not yet been obtained (non-UserSuppliedConnectionProvider)
+	 * or has previously been aggressively released (if supported in this environment).
+	 *
+	 * @return The current Connection.
+	 *
+	 * @throws HibernateException Indicates a connection is currently not
+	 * available (we are currently manually disconnected).
+	 */
+	public Connection getConnection() throws HibernateException {
+		if ( isClosed ) {
+			throw new HibernateException( "connection manager has been closed" );
+		}
+		if ( connection == null  ) {
+			openConnection();
+		}
+		return connection;
+	}
+
+	public boolean hasBorrowedConnection() {
+		// used from testsuite
+		return borrowedConnection != null;
+	}
+
+	public Connection borrowConnection() {
+		if ( isClosed ) {
+			throw new HibernateException( "connection manager has been closed" );
+		}
+		if ( isSuppliedConnection() ) {
+			return connection;
+		}
+		else {
+			if ( borrowedConnection == null ) {
+				borrowedConnection = BorrowedConnectionProxy.generateProxy( this );
+			}
+			return borrowedConnection;
+		}
+	}
+
+	public void releaseBorrowedConnection() {
+		if ( borrowedConnection != null ) {
+			try {
+				BorrowedConnectionProxy.renderUnuseable( borrowedConnection );
+			}
+			finally {
+				borrowedConnection = null;
+			}
+		}
+	}
+
+	/**
+	 * Is the connection considered "auto-commit"?
+	 *
+	 * @return True if we either do not have a connection, or the connection
+	 * really is in auto-commit mode.
+	 *
+	 * @throws SQLException Can be thrown by the Connection.isAutoCommit() check.
+	 */
+	public boolean isAutoCommit() throws SQLException {
+		return connection == null 
+			|| connection.isClosed()
+			|| connection.getAutoCommit();
+	}
+
+	/**
+	 * Will connections be released after each statement execution?
+	 * <p/>
+	 * Connections will be released after each statement if either:<ul>
+	 * <li>the defined release-mode is {@link ConnectionReleaseMode#AFTER_STATEMENT}; or
+	 * <li>the defined release-mode is {@link ConnectionReleaseMode#AFTER_TRANSACTION} but
+	 * we are in auto-commit mode.
+	 * <p/>
+	 * release-mode = {@link ConnectionReleaseMode#ON_CLOSE} should [b]never[/b] release
+	 * a connection.
+	 *
+	 * @return True if the connections will be released after each statement; false otherwise.
+	 */
+	public boolean isAggressiveRelease() {
+		if ( releaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {
+			return true;
+		}
+		else if ( releaseMode == ConnectionReleaseMode.AFTER_TRANSACTION ) {
+			boolean inAutoCommitState;
+			try {
+				inAutoCommitState = isAutoCommit()&& !callback.isTransactionInProgress();
+			}
+			catch( SQLException e ) {
+				// assume we are in an auto-commit state
+				inAutoCommitState = true;
+			}
+			return inAutoCommitState;
+		}
+		return false;
+	}
+
+	/**
+	 * Modified version of {@link #isAggressiveRelease} which does not force a
+	 * transaction check.  This is solely used from our {@link #afterTransaction}
+	 * callback, so no need to do the check; plus it seems to cause problems on
+	 * websphere (god i love websphere ;)
+	 * </p>
+	 * It uses this information to decide if an aggressive release was skipped
+	 * do to open resources, and if so forces a release.
+	 *
+	 * @return True if the connections will be released after each statement; false otherwise.
+	 */
+	private boolean isAggressiveReleaseNoTransactionCheck() {
+		if ( releaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {
+			return true;
+		}
+		else {
+			boolean inAutoCommitState;
+			try {
+				inAutoCommitState = isAutoCommit();
+			}
+			catch( SQLException e ) {
+				// assume we are in an auto-commit state
+				inAutoCommitState = true;
+			}
+			return releaseMode == ConnectionReleaseMode.AFTER_TRANSACTION && inAutoCommitState;
+		}
+	}
+
+	/**
+	 * Is this ConnectionManager instance "logically" connected.  Meaning
+	 * do we either have a cached connection available or do we have the
+	 * ability to obtain a connection on demand.
+	 *
+	 * @return True if logically connected; false otherwise.
+	 */
+	public boolean isCurrentlyConnected() {
+		return wasConnectionSupplied ? connection != null : !isClosed;
+	}
+
+	/**
+	 * To be called after execution of each JDBC statement.  Used to
+	 * conditionally release the JDBC connection aggressively if
+	 * the configured release mode indicates.
+	 */
+	public void afterStatement() {
+		if ( isAggressiveRelease() ) {
+			if ( isFlushing ) {
+				log.debug( "skipping aggressive-release due to flush cycle" );
+			}
+			else if ( batcher.hasOpenResources() ) {
+				log.debug( "skipping aggresive-release due to open resources on batcher" );
+			}
+			else if ( borrowedConnection != null ) {
+				log.debug( "skipping aggresive-release due to borrowed connection" );
+			}
+			else {
+				aggressiveRelease();
+			}
+		}
+	}
+
+	/**
+	 * To be called after local transaction completion.  Used to conditionally
+	 * release the JDBC connection aggressively if the configured release mode
+	 * indicates.
+	 */
+	public void afterTransaction() {
+		if ( isAfterTransactionRelease() ) {
+			aggressiveRelease();
+		}
+		else if ( isAggressiveReleaseNoTransactionCheck() && batcher.hasOpenResources() ) {
+			log.info( "forcing batcher resource cleanup on transaction completion; forgot to close ScrollableResults/Iterator?" );
+			batcher.closeStatements();
+			aggressiveRelease();
+		}
+		else if ( isOnCloseRelease() ) {
+			// log a message about potential connection leaks
+			log.debug( "transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!" );
+		}
+		batcher.unsetTransactionTimeout();
+	}
+
+	private boolean isAfterTransactionRelease() {
+		return releaseMode == ConnectionReleaseMode.AFTER_TRANSACTION;
+	}
+
+	private boolean isOnCloseRelease() {
+		return releaseMode == ConnectionReleaseMode.ON_CLOSE;
+	}
+
+	/**
+	 * To be called after Session completion.  Used to release the JDBC
+	 * connection.
+	 *
+	 * @return The connection mantained here at time of close.  Null if
+	 * there was no connection cached internally.
+	 */
+	public Connection close() {
+		try {
+			return cleanup();
+		}
+		finally {
+			isClosed = true;
+		}
+	}
+
+	/**
+	 * Manually disconnect the underlying JDBC Connection.  The assumption here
+	 * is that the manager will be reconnected at a later point in time.
+	 *
+	 * @return The connection mantained here at time of disconnect.  Null if
+	 * there was no connection cached internally.
+	 */
+	public Connection manualDisconnect() {
+		return cleanup();
+	}
+
+	/**
+	 * Manually reconnect the underlying JDBC Connection.  Should be called at
+	 * some point after manualDisconnect().
+	 * <p/>
+	 * This form is used for ConnectionProvider-supplied connections.
+	 */
+	public void manualReconnect() {
+	}
+
+	/**
+	 * Manually reconnect the underlying JDBC Connection.  Should be called at
+	 * some point after manualDisconnect().
+	 * <p/>
+	 * This form is used for user-supplied connections.
+	 */
+	public void manualReconnect(Connection suppliedConnection) {
+		this.connection = suppliedConnection;
+	}
+
+	/**
+	 * Releases the Connection and cleans up any resources associated with
+	 * that Connection.  This is intended for use:
+	 * 1) at the end of the session
+	 * 2) on a manual disconnect of the session
+	 * 3) from afterTransaction(), in the case of skipped aggressive releasing
+	 *
+	 * @return The released connection.
+	 * @throws HibernateException
+	 */
+	private Connection cleanup() throws HibernateException {
+		releaseBorrowedConnection();
+
+		if ( connection == null ) {
+			log.trace( "connection already null in cleanup : no action");
+			return null;
+		}
+
+		try {
+			log.trace( "performing cleanup" );
+
+			batcher.closeStatements();
+			Connection c = null;
+			if ( !wasConnectionSupplied ) {
+				closeConnection();
+			}
+			else {
+				c = connection;
+			}
+			connection = null;
+			return c;
+		}
+		finally {
+			callback.connectionCleanedUp();
+		}
+	}
+
+	/**
+	 * Performs actions required to perform an aggressive release of the
+	 * JDBC Connection.
+	 */
+	private void aggressiveRelease() {
+		if ( !wasConnectionSupplied ) {
+			log.debug( "aggressively releasing JDBC connection" );
+			if ( connection != null ) {
+				closeConnection();
+			}
+		}
+	}
+
+	/**
+	 * Pysically opens a JDBC Connection.
+	 *
+	 * @throws HibernateException
+	 */
+	private void openConnection() throws HibernateException {
+		if ( connection != null ) {
+			return;
+		}
+
+		log.debug("opening JDBC connection");
+		try {
+			connection = factory.getConnectionProvider().getConnection();
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					factory.getSQLExceptionConverter(),
+					sqle,
+					"Cannot open connection"
+				);
+		}
+
+		callback.connectionOpened(); // register synch; stats.connect()
+	}
+
+	/**
+	 * Physically closes the JDBC Connection.
+	 */
+	private void closeConnection() {
+		if ( log.isDebugEnabled() ) {
+			log.debug(
+					"releasing JDBC connection [" +
+					batcher.openResourceStatsAsString() + "]"
+				);
+		}
+
+		try {
+			if ( !connection.isClosed() ) {
+				JDBCExceptionReporter.logAndClearWarnings( connection );
+			}
+			factory.getConnectionProvider().closeConnection( connection );
+			connection = null;
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert( 
+					factory.getSQLExceptionConverter(), 
+					sqle, 
+					"Cannot release connection"
+				);
+		}
+	}
+
+	/**
+	 * Callback to let us know that a flush is beginning.  We use this fact
+	 * to temporarily circumvent aggressive connection releasing until after
+	 * the flush cycle is complete {@link #flushEnding()}
+	 */
+	public void flushBeginning() {
+		log.trace( "registering flush begin" );
+		isFlushing = true;
+	}
+
+	/**
+	 * Callback to let us know that a flush is ending.  We use this fact to
+	 * stop circumventing aggressive releasing connections.
+	 */
+	public void flushEnding() {
+		log.trace( "registering flush end" );
+		isFlushing = false;
+		afterStatement();
+	}
+
+	public boolean isReadyForSerialization() {
+		return wasConnectionSupplied ? connection == null : !batcher.hasOpenResources();
+	}
+
+	/**
+	 * Used during serialization.
+	 *
+	 * @param oos The stream to which we are being written.
+	 * @throws IOException Indicates an I/O error writing to the stream
+	 */
+	private void writeObject(ObjectOutputStream oos) throws IOException {
+		if ( !isReadyForSerialization() ) {
+			throw new IllegalStateException( "Cannot serialize a ConnectionManager while connected" );
+		}
+
+		oos.writeObject( factory );
+		oos.writeObject( interceptor );
+		oos.defaultWriteObject();
+	}
+
+	/**
+	 * Used during deserialization.
+	 *
+	 * @param ois The stream from which we are being read.
+	 * @throws IOException Indicates an I/O error reading the stream
+	 * @throws ClassNotFoundException Indicates resource class resolution.
+	 */
+	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+		factory = (SessionFactoryImplementor) ois.readObject();
+		interceptor = (Interceptor) ois.readObject();
+		ois.defaultReadObject();
+
+		this.batcher = factory.getSettings().getBatcherFactory().createBatcher( this, interceptor );
+	}
+
+	public void serialize(ObjectOutputStream oos) throws IOException {
+		oos.writeBoolean( wasConnectionSupplied );
+		oos.writeBoolean( isClosed );
+	}
+
+	public static ConnectionManager deserialize(
+			ObjectInputStream ois,
+	        SessionFactoryImplementor factory,
+	        Interceptor interceptor,
+	        ConnectionReleaseMode connectionReleaseMode,
+	        JDBCContext jdbcContext) throws IOException {
+		return new ConnectionManager(
+				factory,
+		        jdbcContext,
+		        connectionReleaseMode,
+		        interceptor,
+		        ois.readBoolean(),
+		        ois.readBoolean()
+		);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ConnectionWrapper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ConnectionWrapper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ConnectionWrapper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+package org.hibernate.jdbc;
+
+import java.sql.Connection;
+
+/**
+ * Interface implemented by JDBC connection wrappers in order to give
+ * access to the underlying wrapped connection.
+ *
+ * @author Steve Ebersole
+ */
+public interface ConnectionWrapper {
+	/**
+	 * Get a reference to the wrapped connection.
+	 *
+	 * @return The wrapped connection.
+	 */
+	public Connection getWrappedConnection();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/Expectation.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/Expectation.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/Expectation.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+package org.hibernate.jdbc;
+
+import org.hibernate.HibernateException;
+
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+
+/**
+ * Defines an expected DML operation outcome.
+ *
+ * @author Steve Ebersole
+ */
+public interface Expectation {
+	public void verifyOutcome(int rowCount, PreparedStatement statement, int batchPosition) throws SQLException, HibernateException;
+	public int prepare(PreparedStatement statement) throws SQLException, HibernateException;
+	public boolean canBeBatched();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/Expectations.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/Expectations.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/Expectations.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,174 @@
+package org.hibernate.jdbc;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.StaleStateException;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.util.JDBCExceptionReporter;
+import org.hibernate.exception.GenericJDBCException;
+
+import java.sql.CallableStatement;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.Types;
+
+/**
+ * Holds various often used {@link Expectation} definitions.
+ *
+ * @author Steve Ebersole
+ */
+public class Expectations {
+	private static final Log log = LogFactory.getLog( Expectations.class );
+
+	public static final int USUAL_EXPECTED_COUNT = 1;
+	public static final int USUAL_PARAM_POSITION = 1;
+
+
+	// Base Expectation impls ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public static class BasicExpectation implements Expectation {
+		private final int expectedRowCount;
+
+		protected BasicExpectation(int expectedRowCount) {
+			this.expectedRowCount = expectedRowCount;
+			if ( expectedRowCount < 0 ) {
+				throw new IllegalArgumentException( "Expected row count must be greater than zero" );
+			}
+		}
+
+		public final void verifyOutcome(int rowCount, PreparedStatement statement, int batchPosition) {
+			rowCount = determineRowCount( rowCount, statement );
+			if ( batchPosition < 0 ) {
+				checkNonBatched( rowCount );
+			}
+			else {
+				checkBatched( rowCount, batchPosition );
+			}
+		}
+
+		private void checkBatched(int rowCount, int batchPosition) {
+			if ( rowCount == -2 ) {
+				if ( log.isDebugEnabled() ) {
+					log.debug( "success of batch update unknown: " + batchPosition );
+				}
+			}
+			else if ( rowCount == -3 ) {
+				throw new BatchFailedException( "Batch update failed: " + batchPosition );
+			}
+			else {
+				if ( expectedRowCount > rowCount ) {
+					throw new StaleStateException(
+							"Batch update returned unexpected row count from update [" + batchPosition +
+							"]; actual row count: " + rowCount +
+							"; expected: " + expectedRowCount
+					);
+				}
+				if ( expectedRowCount < rowCount ) {
+					String msg = "Batch update returned unexpected row count from update [" +
+					             batchPosition + "]; actual row count: " + rowCount +
+					             "; expected: " + expectedRowCount;
+					throw new BatchedTooManyRowsAffectedException( msg, expectedRowCount, rowCount, batchPosition );
+				}
+			}
+		}
+
+		private void checkNonBatched(int rowCount) {
+			if ( expectedRowCount > rowCount ) {
+				throw new StaleStateException(
+						"Unexpected row count: " + rowCount + "; expected: " + expectedRowCount
+				);
+			}
+			if ( expectedRowCount < rowCount ) {
+				String msg = "Unexpected row count: " + rowCount + "; expected: " + expectedRowCount;
+				throw new TooManyRowsAffectedException( msg, expectedRowCount, rowCount );
+			}
+		}
+
+		public int prepare(PreparedStatement statement) throws SQLException, HibernateException {
+			return 0;
+		}
+
+		public boolean canBeBatched() {
+			return true;
+		}
+
+		protected int determineRowCount(int reportedRowCount, PreparedStatement statement) {
+			return reportedRowCount;
+		}
+	}
+
+	public static class BasicParamExpectation extends BasicExpectation {
+		private final int parameterPosition;
+		protected BasicParamExpectation(int expectedRowCount, int parameterPosition) {
+			super( expectedRowCount );
+			this.parameterPosition = parameterPosition;
+		}
+
+		public int prepare(PreparedStatement statement) throws SQLException, HibernateException {
+			toCallableStatement( statement ).registerOutParameter( parameterPosition, Types.NUMERIC );
+			return 1;
+		}
+
+		public boolean canBeBatched() {
+			return false;
+		}
+
+		protected int determineRowCount(int reportedRowCount, PreparedStatement statement) {
+			try {
+				return toCallableStatement( statement ).getInt( parameterPosition );
+			}
+			catch( SQLException sqle ) {
+				JDBCExceptionReporter.logExceptions( sqle, "could not extract row counts from CallableStatement" );
+				throw new GenericJDBCException( "could not extract row counts from CallableStatement", sqle );
+			}
+		}
+
+		private CallableStatement toCallableStatement(PreparedStatement statement) {
+			if ( ! CallableStatement.class.isInstance( statement ) ) {
+				throw new HibernateException( "BasicParamExpectation operates exclusively on CallableStatements : " + statement.getClass() );
+			}
+			return ( CallableStatement ) statement;
+		}
+	}
+
+
+	// Various Expectation instances ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public static final Expectation NONE = new Expectation() {
+		public void verifyOutcome(int rowCount, PreparedStatement statement, int batchPosition) {
+			// explicitly perform no checking...
+		}
+
+		public int prepare(PreparedStatement statement) {
+			return 0;
+		}
+
+		public boolean canBeBatched() {
+			return true;
+		}
+	};
+
+	public static final Expectation BASIC = new BasicExpectation( USUAL_EXPECTED_COUNT );
+
+	public static final Expectation PARAM = new BasicParamExpectation( USUAL_EXPECTED_COUNT, USUAL_PARAM_POSITION );
+
+
+	public static Expectation appropriateExpectation(ExecuteUpdateResultCheckStyle style) {
+		if ( style == ExecuteUpdateResultCheckStyle.NONE ) {
+			return NONE;
+		}
+		else if ( style == ExecuteUpdateResultCheckStyle.COUNT ) {
+			return BASIC;
+		}
+		else if ( style == ExecuteUpdateResultCheckStyle.PARAM ) {
+			return PARAM;
+		}
+		else {
+			throw new HibernateException( "unknown check style : " + style );
+		}
+	}
+
+	private Expectations() {
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/JDBCContext.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/JDBCContext.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/JDBCContext.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,313 @@
+// $Id: JDBCContext.java 10476 2006-09-08 21:00:48Z epbernard $
+package org.hibernate.jdbc;
+
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.transaction.TransactionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.SessionException;
+import org.hibernate.Transaction;
+import org.hibernate.TransactionException;
+import org.hibernate.util.JTAHelper;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.transaction.CacheSynchronization;
+import org.hibernate.transaction.TransactionFactory;
+
+/**
+ * Acts as the mediary between "entity-mode related" sessions in terms of
+ * their interaction with the JDBC data store.
+ *
+ * @author Steve Ebersole
+ */
+public class JDBCContext implements Serializable, ConnectionManager.Callback {
+
+	// TODO : make this the factory for "entity mode related" sessions;
+	// also means making this the target of transaction-synch and the
+	// thing that knows how to cascade things between related sessions
+	//
+	// At that point, perhaps this thing is a "SessionContext", and
+	// ConnectionManager is a "JDBCContext"?  A "SessionContext" should
+	// live in the impl package...
+
+	private static final Log log = LogFactory.getLog( JDBCContext.class );
+
+	public static interface Context extends TransactionFactory.Context {
+		/**
+		 * We cannot rely upon this method being called! It is only
+		 * called if we are using Hibernate Transaction API.
+		 */
+		public void afterTransactionBegin(Transaction tx);
+		public void beforeTransactionCompletion(Transaction tx);
+		public void afterTransactionCompletion(boolean success, Transaction tx);
+		public ConnectionReleaseMode getConnectionReleaseMode();
+		public boolean isAutoCloseSessionEnabled();
+	}
+
+	private Context owner;
+	private ConnectionManager connectionManager;
+	private transient boolean isTransactionCallbackRegistered;
+	private transient Transaction hibernateTransaction;
+
+	public JDBCContext(Context owner, Connection connection, Interceptor interceptor) {
+		this.owner = owner;
+		this.connectionManager = new ConnectionManager(
+		        owner.getFactory(),
+		        this,
+		        owner.getConnectionReleaseMode(),
+		        connection,
+		        interceptor
+			);
+
+		final boolean registerSynchronization = owner.isAutoCloseSessionEnabled()
+		        || owner.isFlushBeforeCompletionEnabled()
+		        || owner.getConnectionReleaseMode() == ConnectionReleaseMode.AFTER_TRANSACTION;
+		if ( registerSynchronization ) {
+			registerSynchronizationIfPossible();
+		}
+	}
+
+	/**
+	 * Private constructor used exclusively for custom serialization...
+	 *
+	 */
+	private JDBCContext() {
+	}
+
+	// ConnectionManager.Callback implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void connectionOpened() {
+		if ( owner.getFactory().getStatistics().isStatisticsEnabled() ) {
+			owner.getFactory().getStatisticsImplementor().connect();
+		}
+	}
+
+	public void connectionCleanedUp() {
+		if ( !isTransactionCallbackRegistered ) {
+			afterTransactionCompletion( false, null );
+			// Note : success = false, because we don't know the outcome of the transaction
+		}
+	}
+
+	public SessionFactoryImplementor getFactory() {
+		return owner.getFactory();
+	}
+
+	public ConnectionManager getConnectionManager() {
+		return connectionManager;
+	}
+
+	public Connection borrowConnection() {
+		return connectionManager.borrowConnection();
+	}
+	
+	public Connection connection() throws HibernateException {
+		if ( owner.isClosed() ) {
+			throw new SessionException( "Session is closed" );
+		}
+
+		return connectionManager.getConnection();
+	}
+
+	public boolean registerCallbackIfNecessary() {
+		if ( isTransactionCallbackRegistered ) {
+			return false;
+		}
+		else {
+			isTransactionCallbackRegistered = true;
+			return true;
+		}
+
+	}
+
+	public boolean registerSynchronizationIfPossible() {
+		if ( isTransactionCallbackRegistered ) {
+			// we already have a callback registered; either a local
+			// (org.hibernate.Transaction) transaction has accepted
+			// callback responsibilities, or we have previously
+			// registered a transaction synch.
+			return true;
+		}
+		boolean localCallbacksOnly = owner.getFactory().getSettings()
+				.getTransactionFactory()
+				.areCallbacksLocalToHibernateTransactions();
+		if ( localCallbacksOnly ) {
+			// the configured transaction-factory says it only supports
+			// local callback mode, so no sense attempting to register a
+			// JTA Synchronization
+			return false;
+		}
+		TransactionManager tm = owner.getFactory().getTransactionManager();
+		if ( tm == null ) {
+			// if there is no TM configured, we will not be able to access
+			// the javax.transaction.Transaction object in order to
+			// register a synch anyway.
+			return false;
+		}
+		else {
+			try {
+				if ( !isTransactionInProgress() ) {
+					log.trace( "TransactionFactory reported no active transaction; Synchronization not registered" );
+					return false;
+				}
+				else {
+					javax.transaction.Transaction tx = tm.getTransaction();
+					if ( JTAHelper.isMarkedForRollback( tx ) ) {
+						log.debug( "Transaction is marked for rollback; skipping Synchronization registration" );
+						return false;
+					}
+					else {
+						tx.registerSynchronization( new CacheSynchronization(owner, this, tx, null) );
+						isTransactionCallbackRegistered = true;
+						log.debug("successfully registered Synchronization");
+						return true;
+					}
+				}
+			}
+			catch( HibernateException e ) {
+				throw e;
+			}
+			catch (Exception e) {
+				throw new TransactionException( "could not register synchronization with JTA TransactionManager", e );
+			}
+		}
+	}
+	
+	public boolean isTransactionInProgress() {
+		return owner.getFactory().getSettings().getTransactionFactory()
+				.isTransactionInProgress( this, owner, hibernateTransaction );
+	}
+
+	public Transaction getTransaction() throws HibernateException {
+		if (hibernateTransaction==null) {
+			hibernateTransaction = owner.getFactory().getSettings()
+					.getTransactionFactory()
+					.createTransaction( this, owner );
+		}
+		return hibernateTransaction;
+	}
+	
+	public void beforeTransactionCompletion(Transaction tx) {
+		log.trace( "before transaction completion" );
+		owner.beforeTransactionCompletion(tx);
+	}
+	
+	/**
+	 * We cannot rely upon this method being called! It is only
+	 * called if we are using Hibernate Transaction API.
+	 */
+	public void afterTransactionBegin(Transaction tx) {
+		log.trace( "after transaction begin" );
+		owner.afterTransactionBegin(tx);
+	}
+
+	public void afterTransactionCompletion(boolean success, Transaction tx) {
+		log.trace( "after transaction completion" );
+
+		if ( getFactory().getStatistics().isStatisticsEnabled() ) {
+			getFactory().getStatisticsImplementor().endTransaction(success);
+		}
+
+		connectionManager.afterTransaction();
+
+		isTransactionCallbackRegistered = false;
+		hibernateTransaction = null;
+		owner.afterTransactionCompletion(success, tx);
+	}
+	
+	/**
+	 * Called after executing a query outside the scope of
+	 * a Hibernate or JTA transaction
+	 */
+	public void afterNontransactionalQuery(boolean success) {
+		log.trace( "after autocommit" );
+		try {
+			// check to see if the connection is in auto-commit 
+			// mode (no connection means aggressive connection
+			// release outside a JTA transaction context, so MUST
+			// be autocommit mode)
+			boolean isAutocommit = connectionManager.isAutoCommit();
+
+			connectionManager.afterTransaction();
+			
+			if ( isAutocommit ) {
+				owner.afterTransactionCompletion(success, null);
+			}
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert( 
+					owner.getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not inspect JDBC autocommit mode"
+				);
+		}
+	}
+
+
+	// serialization ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	private void writeObject(ObjectOutputStream oos) throws IOException {
+		// isTransactionCallbackRegistered denotes whether any Hibernate
+		// Transaction has registered as a callback against this
+		// JDBCContext; only one such callback is allowed.  Directly
+		// serializing this value causes problems with JDBCTransaction,
+		// or really any Transaction impl where the callback is local
+		// to the Transaction instance itself, since that Transaction
+		// is not serialized along with the JDBCContext.  Thus we
+		// handle that fact here explicitly...
+		oos.defaultWriteObject();
+		boolean deserHasCallbackRegistered = isTransactionCallbackRegistered
+				&& ! owner.getFactory().getSettings().getTransactionFactory()
+				.areCallbacksLocalToHibernateTransactions();
+		oos.writeBoolean( deserHasCallbackRegistered );
+	}
+
+	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+		ois.defaultReadObject();
+		isTransactionCallbackRegistered = ois.readBoolean();
+	}
+
+	/**
+	 * Custom serialization routine used during serialization of a
+	 * Session/PersistenceContext for increased performance.
+	 *
+	 * @param oos The stream to which we should write the serial data.
+	 * @throws IOException
+	 */
+	public void serialize(ObjectOutputStream oos) throws IOException {
+		connectionManager.serialize( oos );
+	}
+
+	/**
+	 * Custom deserialization routine used during deserialization of a
+	 * Session/PersistenceContext for increased performance.
+	 *
+	 * @param ois The stream from which to read the entry.
+	 * @throws IOException
+	 */
+	public static JDBCContext deserialize(
+			ObjectInputStream ois,
+	        Context context,
+	        Interceptor interceptor) throws IOException {
+		JDBCContext jdbcContext = new JDBCContext();
+		jdbcContext.owner = context;
+		jdbcContext.connectionManager = ConnectionManager.deserialize(
+				ois,
+				context.getFactory(),
+		        interceptor,
+		        context.getConnectionReleaseMode(),
+		        jdbcContext
+		);
+		return jdbcContext;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/NonBatchingBatcher.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/NonBatchingBatcher.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/NonBatchingBatcher.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+//$Id: NonBatchingBatcher.java 10040 2006-06-22 19:51:43Z steve.ebersole at jboss.com $
+package org.hibernate.jdbc;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+
+/**
+ * An implementation of the <tt>Batcher</tt> interface that does no batching
+ *
+ * @author Gavin King
+ */
+public class NonBatchingBatcher extends AbstractBatcher {
+
+	public NonBatchingBatcher(ConnectionManager connectionManager, Interceptor interceptor) {
+		super( connectionManager, interceptor );
+	}
+
+	public void addToBatch(Expectation expectation) throws SQLException, HibernateException {
+		PreparedStatement statement = getStatement();
+		final int rowCount = statement.executeUpdate();
+		expectation.verifyOutcome( rowCount, statement, 0 );
+	}
+
+	protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException {
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/NonBatchingBatcherFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/NonBatchingBatcherFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/NonBatchingBatcherFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+//$Id: NonBatchingBatcherFactory.java 7683 2005-07-29 19:10:20Z maxcsaucdk $
+package org.hibernate.jdbc;
+
+import org.hibernate.Interceptor;
+
+
+/**
+ * A BatcherFactory implementation which constructs Batcher instances
+ * that do not perform batch operations.
+ *
+ * @author Gavin King
+ */
+public class NonBatchingBatcherFactory implements BatcherFactory {
+
+	public Batcher createBatcher(ConnectionManager connectionManager, Interceptor interceptor) {
+		return new NonBatchingBatcher( connectionManager, interceptor );
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/NonBatchingBatcherFactory.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ResultSetWrapper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ResultSetWrapper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/ResultSetWrapper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,619 @@
+// $Id: ResultSetWrapper.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.jdbc;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Map;
+
+/**
+ * A ResultSet delegate, responsible for locally caching the columnName-to-columnIndex
+ * resolution that has been found to be inefficient in a few vendor's drivers (i.e., Oracle
+ * and Postgres).
+ *
+ * @author Steve Ebersole
+ */
+public class ResultSetWrapper implements ResultSet {
+
+	private ResultSet rs;
+	private ColumnNameCache columnNameCache;
+
+	public ResultSetWrapper(ResultSet resultSet, ColumnNameCache columnNameCache) {
+		this.rs = resultSet;
+		this.columnNameCache = columnNameCache;
+	}
+
+	/*package*/ ResultSet getTarget() {
+		return rs;
+	}
+
+
+	// ResultSet impl ("overridden") ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Overridden version to utilize local caching of the column indexes by name
+	 * to improve performance for those drivers which are known to not support
+	 * such caching by themselves.
+	 * <p/>
+	 * This implementation performs the caching based on the upper case version
+	 * of the given column name.
+	 *
+	 * @param columnName The column name to resolve into an index.
+	 * @return The column index corresponding to the given column name.
+	 * @throws SQLException - if the ResultSet object does not contain
+	 * columnName or a database access error occurs
+	 */
+	public int findColumn(String columnName) throws SQLException {
+		return columnNameCache.getIndexForColumnName( columnName, this );
+	}
+
+	public Array getArray(String colName) throws SQLException {
+		return rs.getArray( findColumn(colName) );
+	}
+
+	public void updateArray(String columnName, Array x) throws SQLException {
+		rs.updateArray( findColumn(columnName), x );
+	}
+
+	public InputStream getAsciiStream(String columnName) throws SQLException {
+		return rs.getAsciiStream( findColumn(columnName) );
+	}
+
+	public void updateAsciiStream(String columnName, InputStream x, int length) throws SQLException {
+		rs.updateAsciiStream( findColumn(columnName), x, length );
+	}
+
+	public BigDecimal getBigDecimal(String columnName) throws SQLException {
+		return rs.getBigDecimal( findColumn(columnName) );
+	}
+
+	public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException {
+		return rs.getBigDecimal( findColumn(columnName), scale );
+	}
+
+	public void updateBigDecimal(String columnName, BigDecimal x) throws SQLException {
+		rs.updateBigDecimal( findColumn(columnName), x );
+	}
+
+	public InputStream getBinaryStream(String columnName) throws SQLException {
+		return rs.getBinaryStream( findColumn(columnName) );
+	}
+
+	public void updateBinaryStream(String columnName, InputStream x, int length) throws SQLException {
+		rs.updateBinaryStream( findColumn(columnName), x, length );
+	}
+
+	public Blob getBlob(String columnName) throws SQLException {
+		return rs.getBlob( findColumn(columnName) );
+	}
+
+	public void updateBlob(String columnName, Blob x) throws SQLException {
+		rs.updateBlob( findColumn(columnName), x );
+	}
+
+	public boolean getBoolean(String columnName) throws SQLException {
+		return rs.getBoolean( findColumn(columnName) );
+	}
+
+	public void updateBoolean(String columnName, boolean x) throws SQLException {
+		rs.updateBoolean( findColumn(columnName), x );
+	}
+
+	public byte getByte(String columnName) throws SQLException {
+		return rs.getByte( findColumn(columnName) );
+	}
+
+	public void updateByte(String columnName, byte x) throws SQLException {
+		rs.updateByte( findColumn(columnName), x );
+	}
+
+	public byte[] getBytes(String columnName) throws SQLException {
+		return rs.getBytes( findColumn(columnName) );
+	}
+
+	public void updateBytes(String columnName, byte[] x) throws SQLException {
+		rs.updateBytes( findColumn(columnName), x );
+	}
+
+	public Reader getCharacterStream(String columnName) throws SQLException {
+		return rs.getCharacterStream( findColumn(columnName) );
+	}
+
+	public void updateCharacterStream(String columnName, Reader x, int length) throws SQLException {
+		rs.updateCharacterStream( findColumn(columnName), x, length );
+	}
+
+	public Clob getClob(String columnName) throws SQLException {
+		return rs.getClob( findColumn(columnName) );
+	}
+
+	public void updateClob(String columnName, Clob x) throws SQLException {
+		rs.updateClob( findColumn(columnName), x );
+	}
+
+	public Date getDate(String columnName) throws SQLException {
+		return rs.getDate( findColumn(columnName) );
+	}
+
+	public Date getDate(String columnName, Calendar cal) throws SQLException {
+		return rs.getDate( findColumn(columnName), cal );
+	}
+
+	public void updateDate(String columnName, Date x) throws SQLException {
+		rs.updateDate( findColumn(columnName), x );
+	}
+
+	public double getDouble(String columnName) throws SQLException {
+		return rs.getDouble( findColumn(columnName) );
+	}
+
+	public void updateDouble(String columnName, double x) throws SQLException {
+		rs.updateDouble( findColumn(columnName), x );
+	}
+
+	public float getFloat(String columnName) throws SQLException {
+		return rs.getFloat( findColumn(columnName) );
+	}
+
+	public void updateFloat(String columnName, float x) throws SQLException {
+		rs.updateFloat( findColumn(columnName), x );
+	}
+
+	public int getInt(String columnName) throws SQLException {
+		return rs.getInt( findColumn(columnName) );
+	}
+
+	public void updateInt(String columnName, int x) throws SQLException {
+		rs.updateInt( findColumn(columnName), x );
+	}
+
+	public long getLong(String columnName) throws SQLException {
+		return rs.getLong( findColumn(columnName) );
+	}
+
+	public void updateLong(String columnName, long x) throws SQLException {
+		rs.updateLong( findColumn(columnName), x );
+	}
+
+	public Object getObject(String columnName) throws SQLException {
+		return rs.getObject( findColumn(columnName) );
+	}
+
+	public Object getObject(String columnName, Map map) throws SQLException {
+		return rs.getObject( findColumn(columnName), map );
+	}
+
+	public void updateObject(String columnName, Object x) throws SQLException {
+		rs.updateObject( findColumn(columnName), x );
+	}
+
+	public void updateObject(String columnName, Object x, int scale) throws SQLException {
+		rs.updateObject( findColumn(columnName), x, scale );
+	}
+
+	public Ref getRef(String columnName) throws SQLException {
+		return rs.getRef( findColumn(columnName) );
+	}
+
+	public void updateRef(String columnName, Ref x) throws SQLException {
+		rs.updateRef( findColumn(columnName), x );
+	}
+
+	public short getShort(String columnName) throws SQLException {
+		return rs.getShort( findColumn(columnName) );
+	}
+
+	public void updateShort(String columnName, short x) throws SQLException {
+		rs.updateShort( findColumn(columnName), x );
+	}
+
+	public String getString(String columnName) throws SQLException {
+		return rs.getString( findColumn(columnName) );
+	}
+
+	public void updateString(String columnName, String x) throws SQLException {
+		rs.updateString( findColumn(columnName), x );
+	}
+
+	public Time getTime(String columnName) throws SQLException {
+		return rs.getTime( findColumn(columnName) );
+	}
+
+	public Time getTime(String columnName, Calendar cal) throws SQLException {
+		return rs.getTime( findColumn(columnName), cal );
+	}
+
+	public void updateTime(String columnName, Time x) throws SQLException {
+		rs.updateTime( findColumn(columnName), x );
+	}
+
+	public Timestamp getTimestamp(String columnName) throws SQLException {
+		return rs.getTimestamp( findColumn(columnName) );
+	}
+
+	public void updateTimestamp(String columnName, Timestamp x) throws SQLException {
+		rs.updateTimestamp( findColumn(columnName), x );
+	}
+
+	public Timestamp getTimestamp(String columnName, Calendar cal) throws SQLException {
+		return rs.getTimestamp( findColumn(columnName), cal );
+	}
+
+	public InputStream getUnicodeStream(String columnName) throws SQLException {
+		return rs.getUnicodeStream( findColumn(columnName) );
+	}
+
+	public URL getURL(String columnName) throws SQLException {
+		return rs.getURL( findColumn(columnName) );
+	}
+
+	public void updateNull(String columnName) throws SQLException {
+		rs.updateNull( findColumn(columnName) );
+	}
+
+
+	// ResultSet impl (delegated) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public int getConcurrency() throws SQLException {
+		return rs.getConcurrency();
+	}
+
+	public int getFetchDirection() throws SQLException {
+		return rs.getFetchDirection();
+	}
+
+	public int getFetchSize() throws SQLException {
+		return rs.getFetchSize();
+	}
+
+	public int getRow() throws SQLException {
+		return rs.getRow();
+	}
+
+	public int getType() throws SQLException {
+		return rs.getType();
+	}
+
+	public void afterLast() throws SQLException {
+		rs.afterLast();
+	}
+
+	public void beforeFirst() throws SQLException {
+		rs.beforeFirst();
+	}
+
+	public void cancelRowUpdates() throws SQLException {
+		rs.cancelRowUpdates();
+	}
+
+	public void clearWarnings() throws SQLException {
+		rs.clearWarnings();
+	}
+
+	public void close() throws SQLException {
+		rs.close();
+	}
+
+	public void deleteRow() throws SQLException {
+		rs.deleteRow();
+	}
+
+	public void insertRow() throws SQLException {
+		rs.insertRow();
+	}
+
+	public void moveToCurrentRow() throws SQLException {
+		rs.moveToCurrentRow();
+	}
+
+	public void moveToInsertRow() throws SQLException {
+		rs.moveToInsertRow();
+	}
+
+	public void refreshRow() throws SQLException {
+		rs.refreshRow();
+	}
+
+	public void updateRow() throws SQLException {
+		rs.updateRow();
+	}
+
+	public boolean first() throws SQLException {
+		return rs.first();
+	}
+
+	public boolean isAfterLast() throws SQLException {
+		return rs.isAfterLast();
+	}
+
+	public boolean isBeforeFirst() throws SQLException {
+		return rs.isBeforeFirst();
+	}
+
+	public boolean isFirst() throws SQLException {
+		return rs.isFirst();
+	}
+
+	public boolean isLast() throws SQLException {
+		return rs.isLast();
+	}
+
+	public boolean last() throws SQLException {
+		return rs.last();
+	}
+
+	public boolean next() throws SQLException {
+		return rs.next();
+	}
+
+	public boolean previous() throws SQLException {
+		return rs.previous();
+	}
+
+	public boolean rowDeleted() throws SQLException {
+		return rs.rowDeleted();
+	}
+
+	public boolean rowInserted() throws SQLException {
+		return rs.rowInserted();
+	}
+
+	public boolean rowUpdated() throws SQLException {
+		return rs.rowUpdated();
+	}
+
+	public boolean wasNull() throws SQLException {
+		return rs.wasNull();
+	}
+
+	public byte getByte(int columnIndex) throws SQLException {
+		return rs.getByte(columnIndex);
+	}
+
+	public double getDouble(int columnIndex) throws SQLException {
+		return rs.getDouble(columnIndex);
+	}
+
+	public float getFloat(int columnIndex) throws SQLException {
+		return rs.getFloat(columnIndex);
+	}
+
+	public int getInt(int columnIndex) throws SQLException {
+		return rs.getInt(columnIndex);
+	}
+
+	public long getLong(int columnIndex) throws SQLException {
+		return rs.getLong(columnIndex);
+	}
+
+	public short getShort(int columnIndex) throws SQLException {
+		return rs.getShort(columnIndex);
+	}
+
+	public void setFetchDirection(int direction) throws SQLException {
+		rs.setFetchDirection(direction);
+	}
+
+	public void setFetchSize(int rows) throws SQLException {
+		rs.setFetchSize(rows);
+	}
+
+	public void updateNull(int columnIndex) throws SQLException {
+		rs.updateNull(columnIndex);
+	}
+
+	public boolean absolute(int row) throws SQLException {
+		return rs.absolute(row);
+	}
+
+	public boolean getBoolean(int columnIndex) throws SQLException {
+		return rs.getBoolean(columnIndex);
+	}
+
+	public boolean relative(int rows) throws SQLException {
+		return rs.relative(rows);
+	}
+
+	public byte[] getBytes(int columnIndex) throws SQLException {
+		return rs.getBytes(columnIndex);
+	}
+
+	public void updateByte(int columnIndex, byte x) throws SQLException {
+		rs.updateByte(columnIndex, x);
+	}
+
+	public void updateDouble(int columnIndex, double x) throws SQLException {
+		rs.updateDouble(columnIndex, x);
+	}
+
+	public void updateFloat(int columnIndex, float x) throws SQLException {
+		rs.updateFloat(columnIndex, x);
+	}
+
+	public void updateInt(int columnIndex, int x) throws SQLException {
+		rs.updateInt(columnIndex, x);
+	}
+
+	public void updateLong(int columnIndex, long x) throws SQLException {
+		rs.updateLong(columnIndex, x);
+	}
+
+	public void updateShort(int columnIndex, short x) throws SQLException {
+		rs.updateShort(columnIndex, x);
+	}
+
+	public void updateBoolean(int columnIndex, boolean x) throws SQLException {
+		rs.updateBoolean(columnIndex, x);
+	}
+
+	public void updateBytes(int columnIndex, byte[] x) throws SQLException {
+		rs.updateBytes(columnIndex, x);
+	}
+
+	public InputStream getAsciiStream(int columnIndex) throws SQLException {
+		return rs.getAsciiStream(columnIndex);
+	}
+
+	public InputStream getBinaryStream(int columnIndex) throws SQLException {
+		return rs.getBinaryStream(columnIndex);
+	}
+
+	public InputStream getUnicodeStream(int columnIndex) throws SQLException {
+		return rs.getUnicodeStream(columnIndex);
+	}
+
+	public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException {
+		rs.updateAsciiStream(columnIndex, x, length);
+	}
+
+	public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException {
+		rs.updateBinaryStream(columnIndex, x, length);
+	}
+
+	public Reader getCharacterStream(int columnIndex) throws SQLException {
+		return rs.getCharacterStream(columnIndex);
+	}
+
+	public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException {
+		rs.updateCharacterStream(columnIndex, x, length);
+	}
+
+	public Object getObject(int columnIndex) throws SQLException {
+		return rs.getObject(columnIndex);
+	}
+
+	public void updateObject(int columnIndex, Object x) throws SQLException {
+		rs.updateObject(columnIndex, x);
+	}
+
+	public void updateObject(int columnIndex, Object x, int scale) throws SQLException {
+		rs.updateObject(columnIndex, x, scale);
+	}
+
+	public String getCursorName() throws SQLException {
+		return rs.getCursorName();
+	}
+
+	public String getString(int columnIndex) throws SQLException {
+		return rs.getString(columnIndex);
+	}
+
+	public void updateString(int columnIndex, String x) throws SQLException {
+		rs.updateString(columnIndex, x);
+	}
+
+	public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
+		return rs.getBigDecimal(columnIndex);
+	}
+
+	public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
+		return rs.getBigDecimal(columnIndex, scale);
+	}
+
+	public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException {
+		rs.updateBigDecimal(columnIndex, x);
+	}
+
+	public URL getURL(int columnIndex) throws SQLException {
+		return rs.getURL(columnIndex);
+	}
+
+	public Array getArray(int columnIndex) throws SQLException {
+		return rs.getArray(columnIndex);
+	}
+
+	public void updateArray(int columnIndex, Array x) throws SQLException {
+		rs.updateArray(columnIndex, x);
+	}
+
+	public Blob getBlob(int columnIndex) throws SQLException {
+		return rs.getBlob(columnIndex);
+	}
+
+	public void updateBlob(int columnIndex, Blob x) throws SQLException {
+		rs.updateBlob(columnIndex, x);
+	}
+
+	public Clob getClob(int columnIndex) throws SQLException {
+		return rs.getClob(columnIndex);
+	}
+
+	public void updateClob(int columnIndex, Clob x) throws SQLException {
+		rs.updateClob(columnIndex, x);
+	}
+
+	public Date getDate(int columnIndex) throws SQLException {
+		return rs.getDate(columnIndex);
+	}
+
+	public void updateDate(int columnIndex, Date x) throws SQLException {
+		rs.updateDate(columnIndex, x);
+	}
+
+	public Ref getRef(int columnIndex) throws SQLException {
+		return rs.getRef(columnIndex);
+	}
+
+	public void updateRef(int columnIndex, Ref x) throws SQLException {
+		rs.updateRef(columnIndex, x);
+	}
+
+	public ResultSetMetaData getMetaData() throws SQLException {
+		return rs.getMetaData();
+	}
+
+	public SQLWarning getWarnings() throws SQLException {
+		return rs.getWarnings();
+	}
+
+	public Statement getStatement() throws SQLException {
+		return rs.getStatement();
+	}
+
+	public Time getTime(int columnIndex) throws SQLException {
+		return rs.getTime(columnIndex);
+	}
+
+	public void updateTime(int columnIndex, Time x) throws SQLException {
+		rs.updateTime(columnIndex, x);
+	}
+
+	public Timestamp getTimestamp(int columnIndex) throws SQLException {
+		return rs.getTimestamp(columnIndex);
+	}
+
+	public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException {
+		rs.updateTimestamp(columnIndex, x);
+	}
+
+	public Object getObject(int columnIndex, Map map) throws SQLException {
+		return rs.getObject( columnIndex, map );
+	}
+
+	public Date getDate(int columnIndex, Calendar cal) throws SQLException {
+		return rs.getDate(columnIndex, cal);
+	}
+
+	public Time getTime(int columnIndex, Calendar cal) throws SQLException {
+		return rs.getTime(columnIndex, cal);
+	}
+
+	public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {
+		return rs.getTimestamp(columnIndex, cal);
+	}
+}
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/TooManyRowsAffectedException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/TooManyRowsAffectedException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/TooManyRowsAffectedException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+package org.hibernate.jdbc;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Indicates that more rows were affected then we were expecting to be.
+ * Typically indicates presence of duplicate "PK" values in the
+ * given table.
+ *
+ * @author Steve Ebersole
+ */
+public class TooManyRowsAffectedException extends HibernateException {
+	private final int expectedRowCount;
+	private final int actualRowCount;
+
+	public TooManyRowsAffectedException(String message, int expectedRowCount, int actualRowCount) {
+		super( message );
+		this.expectedRowCount = expectedRowCount;
+		this.actualRowCount = actualRowCount;
+	}
+
+	public int getExpectedRowCount() {
+		return expectedRowCount;
+	}
+
+	public int getActualRowCount() {
+		return actualRowCount;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package abstracts the mechanism for dispatching SQL statements 
+	to the database, and implements interaction with JDBC.
+</p>
+<p>
+	Concrete implementations of the <tt>Batcher</tt> interface may be 
+	selected by specifying <tt>hibernate.jdbc.factory_class</tt>.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/jdbc/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,143 @@
+//$Id: AbstractEntityJoinWalker.java 11080 2007-01-23 16:29:18Z steve.ebersole at jboss.com $
+package org.hibernate.loader;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.FetchMode;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.sql.Select;
+import org.hibernate.type.AssociationType;
+import org.hibernate.util.CollectionHelper;
+
+/**
+ * Abstract walker for walkers which begin at an entity (criteria
+ * queries and entity loaders).
+ * 
+ * @author Gavin King
+ */
+public abstract class AbstractEntityJoinWalker extends JoinWalker {
+
+	private final OuterJoinLoadable persister;
+	private String alias;
+	
+	public AbstractEntityJoinWalker(OuterJoinLoadable persister, SessionFactoryImplementor factory, Map enabledFilters) {
+		super( factory, enabledFilters );
+		this.persister = persister;
+		alias = generateRootAlias( persister.getEntityName() );
+	}
+
+	protected final void initAll(
+		final String whereString,
+		final String orderByString,
+		final LockMode lockMode)
+	throws MappingException {
+		
+		walkEntityTree( persister, getAlias() );
+		
+		List allAssociations = new ArrayList();
+		allAssociations.addAll(associations);
+		allAssociations.add( new OuterJoinableAssociation( 
+				persister.getEntityType(),
+				null, 
+				null, 
+				alias, 
+				JoinFragment.LEFT_OUTER_JOIN, 
+				getFactory(),
+				CollectionHelper.EMPTY_MAP
+			) );
+		
+		initPersisters(allAssociations, lockMode);
+		initStatementString( whereString, orderByString, lockMode);
+	}
+	
+	protected final void initProjection(
+		final String projectionString,
+		final String whereString,
+		final String orderByString,
+		final String groupByString,
+		final LockMode lockMode)
+	throws MappingException {
+		walkEntityTree( persister, getAlias() );
+		persisters = new Loadable[0];
+		initStatementString(projectionString, whereString, orderByString, groupByString, lockMode);
+	}
+
+	private void initStatementString(
+		final String condition,
+		final String orderBy,
+		final LockMode lockMode)
+	throws MappingException {
+		initStatementString(null, condition, orderBy, "", lockMode);
+	}
+
+	private void initStatementString(
+			final String projection,
+			final String condition,
+			final String orderBy,
+			final String groupBy,
+			final LockMode lockMode) throws MappingException {
+
+		final int joins = countEntityPersisters( associations );
+		suffixes = BasicLoader.generateSuffixes( joins + 1 );
+
+		JoinFragment ojf = mergeOuterJoins( associations );
+
+		Select select = new Select( getDialect() )
+				.setLockMode( lockMode )
+				.setSelectClause(
+						projection == null ?
+								persister.selectFragment( alias, suffixes[joins] ) + selectString( associations ) :
+								projection
+				)
+				.setFromClause(
+						getDialect().appendLockHint( lockMode, persister.fromTableFragment( alias ) ) +
+								persister.fromJoinFragment( alias, true, true )
+				)
+				.setWhereClause( condition )
+				.setOuterJoins(
+						ojf.toFromFragmentString(),
+						ojf.toWhereFragmentString() + getWhereFragment()
+				)
+				.setOrderByClause( orderBy( associations, orderBy ) )
+				.setGroupByClause( groupBy );
+
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			select.setComment( getComment() );
+		}
+		sql = select.toStatementString();
+	}
+
+	protected String getWhereFragment() throws MappingException {
+		// here we do not bother with the discriminator.
+		return persister.whereJoinFragment(alias, true, true);
+	}
+
+	/**
+	 * The superclass deliberately excludes collections
+	 */
+	protected boolean isJoinedFetchEnabled(AssociationType type, FetchMode config, CascadeStyle cascadeStyle) {
+		return isJoinedFetchEnabledInMapping(config, type);
+	}
+
+	public abstract String getComment();
+
+	protected final Loadable getPersister() {
+		return persister;
+	}
+
+	protected final String getAlias() {
+		return alias;
+	}
+
+	public String toString() {
+		return getClass().getName() + '(' + getPersister().getEntityName() + ')';
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/BasicLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/BasicLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/BasicLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,93 @@
+//$Id: BasicLoader.java 9870 2006-05-04 11:57:58Z steve.ebersole at jboss.com $
+package org.hibernate.loader;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.type.BagType;
+import org.hibernate.HibernateException;
+
+/**
+ * Uses the default mapping from property to result set column 
+ * alias defined by the entities' persisters. Used when Hibernate
+ * is generating result set column aliases.
+ * 
+ * @author Gavin King
+ */
+public abstract class BasicLoader extends Loader {
+
+	protected static final String[] NO_SUFFIX = {""};
+
+	private EntityAliases[] descriptors;
+	private CollectionAliases[] collectionDescriptors;
+
+	public BasicLoader(SessionFactoryImplementor factory) {
+		super(factory);
+	}
+
+	protected final EntityAliases[] getEntityAliases() {
+		return descriptors;
+	}
+
+	protected final CollectionAliases[] getCollectionAliases() {
+		return collectionDescriptors;
+	}
+
+	protected abstract String[] getSuffixes();
+	protected abstract String[] getCollectionSuffixes();
+
+	protected void postInstantiate() {
+		Loadable[] persisters = getEntityPersisters();
+		String[] suffixes = getSuffixes();
+		descriptors = new EntityAliases[persisters.length];
+		for ( int i=0; i<descriptors.length; i++ ) {
+			descriptors[i] = new DefaultEntityAliases( persisters[i], suffixes[i] );
+		}
+
+		CollectionPersister[] collectionPersisters = getCollectionPersisters();
+		int bagCount = 0;
+		if ( collectionPersisters != null ) {
+			String[] collectionSuffixes = getCollectionSuffixes();
+			collectionDescriptors = new CollectionAliases[collectionPersisters.length];
+			for ( int i = 0; i < collectionPersisters.length; i++ ) {
+				if ( isBag( collectionPersisters[i] ) ) {
+					bagCount++;
+				}
+				collectionDescriptors[i] = new GeneratedCollectionAliases(
+						collectionPersisters[i],
+						collectionSuffixes[i]
+					);
+			}
+		}
+		else {
+			collectionDescriptors = null;
+		}
+		if ( bagCount > 1 ) {
+			throw new HibernateException( "cannot simultaneously fetch multiple bags" );
+		}
+	}
+
+	private boolean isBag(CollectionPersister collectionPersister) {
+		return collectionPersister.getCollectionType().getClass().isAssignableFrom( BagType.class );
+	}
+
+	/**
+	 * Utility method that generates 0_, 1_ suffixes. Subclasses don't
+	 * necessarily need to use this algorithm, but it is intended that
+	 * they will in most cases.
+	 */
+	public static String[] generateSuffixes(int length) {
+		return generateSuffixes( 0, length );
+	}
+
+	public static String[] generateSuffixes(int seed, int length) {
+		if ( length == 0 ) return NO_SUFFIX;
+
+		String[] suffixes = new String[length];
+		for ( int i = 0; i < length; i++ ) {
+			suffixes[i] = Integer.toString( i + seed ) + "_";
+		}
+		return suffixes;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/CollectionAliases.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/CollectionAliases.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/CollectionAliases.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+// $Id: CollectionAliases.java 6828 2005-05-19 07:28:59Z steveebersole $
+package org.hibernate.loader;
+
+/**
+ * Type definition of CollectionAliases.
+ *
+ * @author Steve Ebersole
+ */
+public interface CollectionAliases {
+	/**
+	 * Returns the suffixed result-set column-aliases for columns making
+	 * up the key for this collection (i.e., its FK to its owner).
+	 *
+	 * @return The key result-set column aliases.
+	 */
+	public String[] getSuffixedKeyAliases();
+
+	/**
+	 * Returns the suffixed result-set column-aliases for the collumns
+	 * making up the collection's index (map or list).
+	 *
+	 * @return The index result-set column aliases.
+	 */
+	public String[] getSuffixedIndexAliases();
+
+	/**
+	 * Returns the suffixed result-set column-aliases for the columns
+	 * making up the collection's elements.
+	 *
+	 * @return The element result-set column aliases.
+	 */
+	public String[] getSuffixedElementAliases();
+
+	/**
+	 * Returns the suffixed result-set column-aliases for the column
+	 * defining the collection's identifier (if any).
+	 *
+	 * @return The identifier result-set column aliases.
+	 */
+	public String getSuffixedIdentifierAlias();
+
+	/**
+	 * Returns the suffix used to unique the column aliases for this
+	 * particular alias set.
+	 *
+	 * @return The uniqued column alias suffix.
+	 */
+	public String getSuffix();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/ColumnEntityAliases.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/ColumnEntityAliases.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/ColumnEntityAliases.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+package org.hibernate.loader;
+
+import java.util.Map;
+
+import org.hibernate.persister.entity.Loadable;
+
+/**
+ * EntityAliases that chooses the column names over the alias names.
+ * 
+ * @author max
+ *
+ */
+public class ColumnEntityAliases extends DefaultEntityAliases {
+
+	public ColumnEntityAliases(Map returnProperties, Loadable persister, String suffix) {
+		super(returnProperties, persister, suffix);
+	}
+	
+	protected String[] getIdentifierAliases(Loadable persister, String suffix) {
+		return persister.getIdentifierColumnNames();
+	}
+	
+	protected String getDiscriminatorAlias(Loadable persister, String suffix) {
+		return persister.getDiscriminatorColumnName();
+	}
+	
+	protected String[] getPropertyAliases(Loadable persister, int j) {
+		return persister.getPropertyColumnNames(j);
+	}
+	 
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/DefaultEntityAliases.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/DefaultEntityAliases.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/DefaultEntityAliases.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,137 @@
+package org.hibernate.loader;
+
+import java.util.Map;
+
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.util.CollectionHelper;
+
+/**
+ * EntityAliases which handles the logic of selecting user provided aliases (via return-property),
+ * before using the default aliases. 
+ *
+ * @author max
+ *
+ */
+public class DefaultEntityAliases implements EntityAliases {
+
+	private final String[] suffixedKeyColumns;
+	private final String[] suffixedVersionColumn;
+	private final String[][] suffixedPropertyColumns;
+	private final String suffixedDiscriminatorColumn;
+	private final String suffix;
+	private final String rowIdAlias;
+	private final Map userProvidedAliases;	
+
+	public DefaultEntityAliases(Loadable persister, String suffix) {
+		this(CollectionHelper.EMPTY_MAP, persister, suffix);
+	}
+	
+	/**
+	 * Calculate and cache select-clause suffixes.
+	 * @param map 
+	 */
+	public DefaultEntityAliases(Map userProvidedAliases, Loadable persister, String suffix) {
+		this.suffix = suffix;
+		this.userProvidedAliases = userProvidedAliases;
+		
+		String[] keyColumnsCandidates = getUserProvidedAliases(
+				persister.getIdentifierPropertyName(), 
+				(String[]) null
+			); 
+		if (keyColumnsCandidates==null) {
+			suffixedKeyColumns = getUserProvidedAliases(
+					"id", 
+					getIdentifierAliases(persister, suffix)
+				);
+		} 
+		else {
+			suffixedKeyColumns = keyColumnsCandidates;
+		}
+		intern(suffixedKeyColumns);
+		
+		suffixedPropertyColumns = getSuffixedPropertyAliases(persister);
+		suffixedDiscriminatorColumn = getUserProvidedAlias(
+				"class", 
+				getDiscriminatorAlias(persister, suffix)
+			);
+		if ( persister.isVersioned() ) { 
+			suffixedVersionColumn = suffixedPropertyColumns[ persister.getVersionProperty() ];
+		}
+		else {
+			suffixedVersionColumn = null;
+		}
+		rowIdAlias = Loadable.ROWID_ALIAS + suffix; // TODO: not visible to the user!
+	}
+
+	protected String getDiscriminatorAlias(Loadable persister, String suffix) {
+		return persister.getDiscriminatorAlias(suffix);
+	}
+
+	protected String[] getIdentifierAliases(Loadable persister, String suffix) {
+		return persister.getIdentifierAliases(suffix);
+	}
+	
+	protected String[] getPropertyAliases(Loadable persister, int j) {
+		return persister.getPropertyAliases(suffix, j);
+	}
+	
+	private String[] getUserProvidedAliases(String propertyPath, String[] defaultAliases) {
+		String[] result = (String[]) userProvidedAliases.get(propertyPath);
+		if (result==null) {
+			return defaultAliases;			
+		} 
+		else {
+			return result;
+		}
+	}
+
+	private String getUserProvidedAlias(String propertyPath, String defaultAlias) {
+		String[] columns = (String[]) userProvidedAliases.get(propertyPath);
+		if (columns==null) {
+			return defaultAlias;
+		} 
+		else {
+			return columns[0];
+		}
+	}
+	
+	public String[][] getSuffixedPropertyAliases(Loadable persister) {
+		int size = persister.getPropertyNames().length;
+		String[][] suffixedPropertyAliases = new String[size][];
+		for ( int j = 0; j < size; j++ ) {
+			suffixedPropertyAliases[j] = getUserProvidedAliases(
+					persister.getPropertyNames()[j],
+					getPropertyAliases(persister, j)
+				);
+			intern( suffixedPropertyAliases[j] );
+		}			
+		return suffixedPropertyAliases;
+	}
+
+	public String[] getSuffixedVersionAliases() {
+		return suffixedVersionColumn;
+	}
+
+	public String[][] getSuffixedPropertyAliases() {
+		return suffixedPropertyColumns;
+	}
+
+	public String getSuffixedDiscriminatorAlias() {
+		return suffixedDiscriminatorColumn;
+	}
+
+	public String[] getSuffixedKeyAliases() {
+		return suffixedKeyColumns;
+	}
+
+	public String getRowIdAlias() {
+		return rowIdAlias;
+	}
+	
+	private static void intern(String[] strings) {
+		for (int i=0; i<strings.length; i++ ) {
+			strings[i] = strings[i].intern();
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/EntityAliases.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/EntityAliases.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/EntityAliases.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: EntityAliases.java 5699 2005-02-13 11:50:11Z oneovthafew $
+package org.hibernate.loader;
+
+import org.hibernate.persister.entity.Loadable;
+
+/**
+ * Metadata describing the SQL result set column aliases
+ * for a particular entity.
+ * 
+ * @author Gavin King
+ */
+public interface EntityAliases {
+	/**
+	 * The result set column aliases for the primary key columns
+	 */
+	public String[] getSuffixedKeyAliases();
+	/**
+	 * The result set column aliases for the discriminator columns
+	 */
+	public String getSuffixedDiscriminatorAlias();
+	/**
+	 * The result set column aliases for the version columns
+	 */
+	public String[] getSuffixedVersionAliases();
+	/**
+	 * The result set column aliases for the property columns
+	 */
+	public String[][] getSuffixedPropertyAliases();
+	/**
+	 * The result set column aliases for the property columns of a subclass
+	 */
+	public String[][] getSuffixedPropertyAliases(Loadable persister);
+	/**
+	 * The result set column alias for the Oracle row id
+	 */
+	public String getRowIdAlias();
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/EntityAliases.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/GeneratedCollectionAliases.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/GeneratedCollectionAliases.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/GeneratedCollectionAliases.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,131 @@
+// $Id: GeneratedCollectionAliases.java 8410 2005-10-14 22:43:44Z maxcsaucdk $
+package org.hibernate.loader;
+
+import java.util.Map;
+
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.util.CollectionHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * CollectionAliases which handles the logic of selecting user provided aliases (via return-property),
+ * before using the default aliases. 
+ *
+ * @author Steve Ebersole and Max Rydahl Andersen
+ */
+public class GeneratedCollectionAliases implements CollectionAliases {
+	private final String suffix;
+	private final String[] keyAliases;
+	private final String[] indexAliases;
+	private final String[] elementAliases;
+	private final String identifierAlias;
+	private Map userProvidedAliases;
+	
+	public GeneratedCollectionAliases(Map userProvidedAliases, CollectionPersister persister, String suffix) {
+		this.suffix = suffix;
+		this.userProvidedAliases = userProvidedAliases;
+
+		this.keyAliases = getUserProvidedAliases(
+				"key", 
+				persister.getKeyColumnAliases( suffix )
+			);
+
+		this.indexAliases = getUserProvidedAliases(
+				"index",
+				persister.getIndexColumnAliases( suffix )
+				);
+		
+		this.elementAliases = getUserProvidedAliases( "element", 
+				persister.getElementColumnAliases( suffix )
+				);
+				
+		this.identifierAlias = getUserProvidedAlias( "id", 
+				persister.getIdentifierColumnAlias( suffix )
+				);
+	}
+
+	public GeneratedCollectionAliases(CollectionPersister persister, String string) {
+		this(CollectionHelper.EMPTY_MAP, persister, string);
+	}
+
+	/**
+	 * Returns the suffixed result-set column-aliases for columns making up the key for this collection (i.e., its FK to
+	 * its owner).
+	 *
+	 * @return The key result-set column aliases.
+	 */
+	public String[] getSuffixedKeyAliases() {
+		return keyAliases;
+	}
+
+	/**
+	 * Returns the suffixed result-set column-aliases for the collumns making up the collection's index (map or list).
+	 *
+	 * @return The index result-set column aliases.
+	 */
+	public String[] getSuffixedIndexAliases() {
+		return indexAliases;
+	}
+
+	/**
+	 * Returns the suffixed result-set column-aliases for the columns making up the collection's elements.
+	 *
+	 * @return The element result-set column aliases.
+	 */
+	public String[] getSuffixedElementAliases() {
+		return elementAliases;
+	}
+
+	/**
+	 * Returns the suffixed result-set column-aliases for the column defining the collection's identifier (if any).
+	 *
+	 * @return The identifier result-set column aliases.
+	 */
+	public String getSuffixedIdentifierAlias() {
+		return identifierAlias;
+	}
+
+	/**
+	 * Returns the suffix used to unique the column aliases for this particular alias set.
+	 *
+	 * @return The uniqued column alias suffix.
+	 */
+	public String getSuffix() {
+		return suffix;
+	}
+
+	public String toString() {
+		return super.toString() + " [suffix=" + suffix +
+		        ", suffixedKeyAliases=[" + join( keyAliases ) +
+		        "], suffixedIndexAliases=[" + join( indexAliases ) +
+		        "], suffixedElementAliases=[" + join( elementAliases ) +
+		        "], suffixedIdentifierAlias=[" + identifierAlias + "]]";
+	}
+
+	private String join(String[] aliases) {
+		if ( aliases == null) return null;
+
+		return StringHelper.join( ", ", aliases );
+	}
+	
+	private String[] getUserProvidedAliases(String propertyPath, String[] defaultAliases) {
+		String[] result = (String[]) userProvidedAliases.get(propertyPath);
+		if (result==null) {
+			return defaultAliases;			
+		} 
+		else {
+			return result;
+		}
+	}
+
+	private String getUserProvidedAlias(String propertyPath, String defaultAlias) {
+		String[] columns = (String[]) userProvidedAliases.get(propertyPath);
+		if (columns==null) {
+			return defaultAlias;
+		} 
+		else {
+			return columns[0];
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/JoinWalker.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/JoinWalker.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/JoinWalker.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,967 @@
+//$Id: JoinWalker.java 9889 2006-05-05 01:24:12Z steve.ebersole at jboss.com $
+package org.hibernate.loader;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.FetchMode;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.JoinHelper;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.sql.ConditionFragment;
+import org.hibernate.sql.DisjunctionFragment;
+import org.hibernate.sql.InFragment;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.ForeignKeyDirection;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Walks the metamodel, searching for joins, and collecting
+ * together information needed by <tt>OuterJoinLoader</tt>.
+ * 
+ * @see OuterJoinLoader
+ * @author Gavin King, Jon Lipsky
+ */
+public class JoinWalker {
+	
+	private final SessionFactoryImplementor factory;
+	protected final List associations = new ArrayList();
+	private final Set visitedAssociationKeys = new HashSet();
+	private final Map enabledFilters;
+
+	protected String[] suffixes;
+	protected String[] collectionSuffixes;
+	protected Loadable[] persisters;
+	protected int[] owners;
+	protected EntityType[] ownerAssociationTypes;
+	protected CollectionPersister[] collectionPersisters;
+	protected int[] collectionOwners;
+	protected String[] aliases;
+	protected LockMode[] lockModeArray;
+	protected String sql;
+	
+	public String[] getCollectionSuffixes() {
+		return collectionSuffixes;
+	}
+
+	public void setCollectionSuffixes(String[] collectionSuffixes) {
+		this.collectionSuffixes = collectionSuffixes;
+	}
+
+	public LockMode[] getLockModeArray() {
+		return lockModeArray;
+	}
+
+	public void setLockModeArray(LockMode[] lockModeArray) {
+		this.lockModeArray = lockModeArray;
+	}
+
+	public String[] getSuffixes() {
+		return suffixes;
+	}
+
+	public void setSuffixes(String[] suffixes) {
+		this.suffixes = suffixes;
+	}
+
+	public String[] getAliases() {
+		return aliases;
+	}
+
+	public void setAliases(String[] aliases) {
+		this.aliases = aliases;
+	}
+
+	public int[] getCollectionOwners() {
+		return collectionOwners;
+	}
+
+	public void setCollectionOwners(int[] collectionOwners) {
+		this.collectionOwners = collectionOwners;
+	}
+
+	public CollectionPersister[] getCollectionPersisters() {
+		return collectionPersisters;
+	}
+
+	public void setCollectionPersisters(CollectionPersister[] collectionPersisters) {
+		this.collectionPersisters = collectionPersisters;
+	}
+
+	public EntityType[] getOwnerAssociationTypes() {
+		return ownerAssociationTypes;
+	}
+
+	public void setOwnerAssociationTypes(EntityType[] ownerAssociationType) {
+		this.ownerAssociationTypes = ownerAssociationType;
+	}
+
+	public int[] getOwners() {
+		return owners;
+	}
+
+	public void setOwners(int[] owners) {
+		this.owners = owners;
+	}
+
+	public Loadable[] getPersisters() {
+		return persisters;
+	}
+
+	public void setPersisters(Loadable[] persisters) {
+		this.persisters = persisters;
+	}
+
+	public String getSQLString() {
+		return sql;
+	}
+
+	public void setSql(String sql) {
+		this.sql = sql;
+	}
+
+	protected SessionFactoryImplementor getFactory() {
+		return factory;
+	}
+
+	protected Dialect getDialect() {
+		return factory.getDialect();
+	}
+	
+	protected Map getEnabledFilters() {
+		return enabledFilters;
+	}
+
+	protected JoinWalker(SessionFactoryImplementor factory, Map enabledFilters) {
+		this.factory = factory;
+		this.enabledFilters = enabledFilters;
+	}
+
+	/**
+	 * Add on association (one-to-one, many-to-one, or a collection) to a list 
+	 * of associations to be fetched by outerjoin (if necessary)
+	 */
+	private void addAssociationToJoinTreeIfNecessary(
+		final AssociationType type,
+		final String[] aliasedLhsColumns,
+		final String alias,
+		final String path,
+		int currentDepth,
+		final int joinType)
+	throws MappingException {
+		
+		if (joinType>=0) {	
+			addAssociationToJoinTree(
+					type, 
+					aliasedLhsColumns, 
+					alias, 
+					path,
+					currentDepth,
+					joinType
+				);
+		}
+
+	}
+
+	/**
+	 * Add on association (one-to-one, many-to-one, or a collection) to a list 
+	 * of associations to be fetched by outerjoin 
+	 */
+	private void addAssociationToJoinTree(
+		final AssociationType type,
+		final String[] aliasedLhsColumns,
+		final String alias,
+		final String path,
+		final int currentDepth,
+		final int joinType)
+	throws MappingException {
+
+		Joinable joinable = type.getAssociatedJoinable( getFactory() );
+
+		String subalias = generateTableAlias(
+				associations.size()+1, //before adding to collection!
+				path, 
+				joinable
+			);
+
+		OuterJoinableAssociation assoc = new OuterJoinableAssociation(
+				type, 
+				alias, 
+				aliasedLhsColumns, 
+				subalias, 
+				joinType, 
+				getFactory(), 
+				enabledFilters
+			);
+		assoc.validateJoin(path);
+		associations.add(assoc);
+
+		int nextDepth = currentDepth+1;
+		if ( !joinable.isCollection() ) {
+			if (joinable instanceof OuterJoinLoadable) {
+				walkEntityTree(
+					(OuterJoinLoadable) joinable, 
+					subalias,
+					path, 
+					nextDepth
+				);
+			}
+		}
+		else {
+			if (joinable instanceof QueryableCollection) {
+				walkCollectionTree(
+					(QueryableCollection) joinable, 
+					subalias, 
+					path, 
+					nextDepth
+				);
+			}
+		}
+
+	}
+
+	/**
+	 * For an entity class, return a list of associations to be fetched by outerjoin
+	 */
+	protected final void walkEntityTree(OuterJoinLoadable persister, String alias)
+	throws MappingException {
+		walkEntityTree(persister, alias, "", 0);
+	}
+
+	/**
+	 * For a collection role, return a list of associations to be fetched by outerjoin
+	 */
+	protected final void walkCollectionTree(QueryableCollection persister, String alias)
+	throws MappingException {
+		walkCollectionTree(persister, alias, "", 0);
+		//TODO: when this is the entry point, we should use an INNER_JOIN for fetching the many-to-many elements!
+	}
+
+	/**
+	 * For a collection role, return a list of associations to be fetched by outerjoin
+	 */
+	private void walkCollectionTree(
+		final QueryableCollection persister,
+		final String alias,
+		final String path,
+		final int currentDepth)
+	throws MappingException {
+
+		if ( persister.isOneToMany() ) {
+			walkEntityTree(
+					(OuterJoinLoadable) persister.getElementPersister(),
+					alias,
+					path,
+					currentDepth
+				);
+		}
+		else {
+			Type type = persister.getElementType();
+			if ( type.isAssociationType() ) {
+				// a many-to-many;
+				// decrement currentDepth here to allow join across the association table
+				// without exceeding MAX_FETCH_DEPTH (i.e. the "currentDepth - 1" bit)
+				AssociationType associationType = (AssociationType) type;
+				String[] aliasedLhsColumns = persister.getElementColumnNames(alias);
+				String[] lhsColumns = persister.getElementColumnNames();
+				// if the current depth is 0, the root thing being loaded is the
+				// many-to-many collection itself.  Here, it is alright to use
+				// an inner join...
+				boolean useInnerJoin = currentDepth == 0;
+				final int joinType = getJoinType(
+						associationType,
+						persister.getFetchMode(),
+						path,
+						persister.getTableName(),
+						lhsColumns,
+						!useInnerJoin,
+						currentDepth - 1, 
+						null //operations which cascade as far as the collection also cascade to collection elements
+					);
+				addAssociationToJoinTreeIfNecessary(
+						associationType,
+						aliasedLhsColumns,
+						alias,
+						path,
+						currentDepth - 1,
+						joinType
+					);
+			}
+			else if ( type.isComponentType() ) {
+				walkCompositeElementTree(
+						(AbstractComponentType) type,
+						persister.getElementColumnNames(),
+						persister,
+						alias,
+						path,
+						currentDepth
+					);
+			}
+		}
+
+	}
+	
+	/**
+	 * Walk the tree for a particular entity association
+	 */
+	private final void walkEntityAssociationTree(
+		final AssociationType associationType,
+		final OuterJoinLoadable persister,
+		final int propertyNumber,
+		final String alias,
+		final String path,
+		final boolean nullable,
+		final int currentDepth)
+	throws MappingException {
+
+		String[] aliasedLhsColumns = JoinHelper.getAliasedLHSColumnNames(
+				associationType, alias, propertyNumber, persister, getFactory()
+			);
+
+		String[] lhsColumns = JoinHelper.getLHSColumnNames(
+				associationType, propertyNumber, persister, getFactory()
+			);
+		String lhsTable = JoinHelper.getLHSTableName(associationType, propertyNumber, persister);
+
+		String subpath = subPath( path, persister.getSubclassPropertyName(propertyNumber) );
+		int joinType = getJoinType(
+				associationType,
+				persister.getFetchMode(propertyNumber),
+				subpath,
+				lhsTable,
+				lhsColumns,
+				nullable,
+				currentDepth, 
+				persister.getCascadeStyle(propertyNumber)
+			);
+		addAssociationToJoinTreeIfNecessary(
+				associationType,
+				aliasedLhsColumns,
+				alias,
+				subpath,
+				currentDepth,
+				joinType
+			);
+
+	}
+
+	/**
+	 * For an entity class, add to a list of associations to be fetched 
+	 * by outerjoin
+	 */
+	private final void walkEntityTree(
+		final OuterJoinLoadable persister,
+		final String alias,
+		final String path,
+		final int currentDepth) 
+	throws MappingException {
+
+		int n = persister.countSubclassProperties();
+		for ( int i=0; i<n; i++ ) {
+			Type type = persister.getSubclassPropertyType(i);
+			if ( type.isAssociationType() ) {
+				walkEntityAssociationTree(
+					(AssociationType) type,
+					persister,
+					i,
+					alias,
+					path,
+					persister.isSubclassPropertyNullable(i),
+					currentDepth
+				);
+			}
+			else if ( type.isComponentType() ) {
+				walkComponentTree(
+					(AbstractComponentType) type,
+					i,
+					0,
+					persister,
+					alias,
+					subPath( path, persister.getSubclassPropertyName(i) ),
+					currentDepth
+				);
+			}
+		}
+	}
+
+	/**
+	 * For a component, add to a list of associations to be fetched by outerjoin
+	 */
+	private void walkComponentTree(
+		final AbstractComponentType componentType,
+		final int propertyNumber,
+		int begin,
+		final OuterJoinLoadable persister,
+		final String alias,
+		final String path,
+		final int currentDepth
+	) throws MappingException {
+
+		Type[] types = componentType.getSubtypes();
+		String[] propertyNames = componentType.getPropertyNames();
+		for ( int i=0; i <types.length; i++ ) {
+
+			if ( types[i].isAssociationType() ) {
+				AssociationType associationType = (AssociationType) types[i];
+
+				String[] aliasedLhsColumns = JoinHelper.getAliasedLHSColumnNames(
+					associationType, alias, propertyNumber, begin, persister, getFactory()
+				);
+
+				String[] lhsColumns = JoinHelper.getLHSColumnNames(
+					associationType, propertyNumber, begin, persister, getFactory()
+				);
+				String lhsTable = JoinHelper.getLHSTableName(associationType, propertyNumber, persister);
+
+				String subpath = subPath( path, propertyNames[i] );
+				final boolean[] propertyNullability = componentType.getPropertyNullability();
+				final int joinType = getJoinType(
+						associationType,
+						componentType.getFetchMode(i),
+						subpath,
+						lhsTable,
+						lhsColumns,
+						propertyNullability==null || propertyNullability[i],
+						currentDepth, 
+						componentType.getCascadeStyle(i)
+					);
+				addAssociationToJoinTreeIfNecessary(			
+						associationType,
+						aliasedLhsColumns,
+						alias,
+						subpath,
+						currentDepth,
+						joinType
+					);
+
+			}
+			else if ( types[i].isComponentType() ) {
+				String subpath = subPath( path, propertyNames[i] );
+				walkComponentTree(
+						(AbstractComponentType) types[i],
+						propertyNumber,
+						begin,
+						persister,
+						alias,
+						subpath,
+						currentDepth
+					);
+			}
+			
+			begin+=types[i].getColumnSpan( getFactory() );
+		}
+
+	}
+
+	/**
+	 * For a composite element, add to a list of associations to be fetched by outerjoin
+	 */
+	private void walkCompositeElementTree(
+		final AbstractComponentType compositeType,
+		final String[] cols,
+		final QueryableCollection persister,
+		final String alias,
+		final String path,
+		final int currentDepth) 
+	throws MappingException {
+
+		Type[] types = compositeType.getSubtypes();
+		String[] propertyNames = compositeType.getPropertyNames();
+		int begin = 0;
+		for ( int i=0; i <types.length; i++ ) {
+			int length = types[i].getColumnSpan( getFactory() );
+			String[] lhsColumns = ArrayHelper.slice(cols, begin, length);
+
+			if ( types[i].isAssociationType() ) {
+				AssociationType associationType = (AssociationType) types[i];
+
+				// simple, because we can't have a one-to-one or a collection 
+				// (or even a property-ref) in a composite-element:
+				String[] aliasedLhsColumns = StringHelper.qualify(alias, lhsColumns);
+
+				String subpath = subPath( path, propertyNames[i] );
+				final boolean[] propertyNullability = compositeType.getPropertyNullability();
+				final int joinType = getJoinType(
+						associationType,
+						compositeType.getFetchMode(i),
+						subpath,
+						persister.getTableName(),
+						lhsColumns,
+						propertyNullability==null || propertyNullability[i],
+						currentDepth, 
+						compositeType.getCascadeStyle(i)
+					);
+				addAssociationToJoinTreeIfNecessary(
+						associationType,
+						aliasedLhsColumns,
+						alias,
+						subpath,
+						currentDepth,
+						joinType
+					);
+			}
+			else if ( types[i].isComponentType() ) {
+				String subpath = subPath( path, propertyNames[i] );
+				walkCompositeElementTree(
+						(AbstractComponentType) types[i],
+						lhsColumns,
+						persister,
+						alias,
+						subpath,
+						currentDepth
+					);
+			}
+			begin+=length;
+		}
+
+	}
+
+	/**
+	 * Extend the path by the given property name
+	 */
+	private static String subPath(String path, String property) {
+		if ( path==null || path.length()==0) {
+			return property;
+		}
+		else {
+			return StringHelper.qualify(path, property);
+		}
+	}
+
+	/**
+	 * Get the join type (inner, outer, etc) or -1 if the
+	 * association should not be joined. Override on
+	 * subclasses.
+	 */
+	protected int getJoinType(
+			AssociationType type, 
+			FetchMode config, 
+			String path, 
+			String lhsTable,
+			String[] lhsColumns,
+			boolean nullable,
+			int currentDepth, 
+			CascadeStyle cascadeStyle)
+	throws MappingException {
+		
+		if  ( !isJoinedFetchEnabled(type, config, cascadeStyle) ) return -1;
+		
+		if ( isTooDeep(currentDepth) || ( type.isCollectionType() && isTooManyCollections() ) ) return -1;
+		
+		final boolean dupe = isDuplicateAssociation(lhsTable,  lhsColumns, type);
+		if (dupe) return -1;
+		
+		return getJoinType(nullable, currentDepth);
+		
+	}
+	
+	/**
+	 * Use an inner join if it is a non-null association and this
+	 * is the "first" join in a series
+	 */
+	protected int getJoinType(boolean nullable, int currentDepth) {
+		//TODO: this is too conservative; if all preceding joins were 
+		//      also inner joins, we could use an inner join here
+		return !nullable && currentDepth==0 ? 
+					JoinFragment.INNER_JOIN : 
+					JoinFragment.LEFT_OUTER_JOIN;
+	}
+
+	protected boolean isTooDeep(int currentDepth) {
+		Integer maxFetchDepth = getFactory().getSettings().getMaximumFetchDepth();
+		return maxFetchDepth!=null && currentDepth >= maxFetchDepth.intValue();
+	}
+	
+	protected boolean isTooManyCollections() {
+		return false;
+	}
+	
+	/**
+	 * Does the mapping, and Hibernate default semantics, specify that
+	 * this association should be fetched by outer joining
+	 */
+	protected boolean isJoinedFetchEnabledInMapping(FetchMode config, AssociationType type) 
+	throws MappingException {
+		if ( !type.isEntityType() && !type.isCollectionType() ) {
+			return false;
+		}
+		else {
+			if (config==FetchMode.JOIN) return true;
+			if (config==FetchMode.SELECT) return false;
+			if ( type.isEntityType() ) {
+				//TODO: look at the owning property and check that it 
+				//      isn't lazy (by instrumentation)
+				EntityType entityType =(EntityType) type;
+				EntityPersister persister = getFactory().getEntityPersister( entityType.getAssociatedEntityName() );
+				return !persister.hasProxy();
+			}
+			else {
+				return false;
+			}
+		}
+	}
+
+	/**
+	 * Override on subclasses to enable or suppress joining 
+	 * of certain association types
+	 */
+	protected boolean isJoinedFetchEnabled(AssociationType type, FetchMode config, CascadeStyle cascadeStyle) {
+		return type.isEntityType() && isJoinedFetchEnabledInMapping(config, type) ;
+	}
+	
+	protected String generateTableAlias(
+			final int n,
+			final String path,
+			final Joinable joinable
+	) {
+		return StringHelper.generateAlias( joinable.getName(), n );
+	}
+
+	protected String generateRootAlias(final String description) {
+		return StringHelper.generateAlias(description, 0);
+	}
+
+	/**
+	 * Used to detect circularities in the joined graph, note that 
+	 * this method is side-effecty
+	 */
+	protected boolean isDuplicateAssociation(
+		final String foreignKeyTable, 
+		final String[] foreignKeyColumns
+	) {
+		AssociationKey associationKey = new AssociationKey(foreignKeyColumns, foreignKeyTable);
+		return !visitedAssociationKeys.add( associationKey );
+	}
+	
+	/**
+	 * Used to detect circularities in the joined graph, note that 
+	 * this method is side-effecty
+	 */
+	protected boolean isDuplicateAssociation(
+		final String lhsTable,
+		final String[] lhsColumnNames,
+		final AssociationType type
+	) {
+		final String foreignKeyTable;
+		final String[] foreignKeyColumns;
+		if ( type.getForeignKeyDirection()==ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT ) {
+			foreignKeyTable = lhsTable;
+			foreignKeyColumns = lhsColumnNames;
+		}
+		else {
+			foreignKeyTable = type.getAssociatedJoinable( getFactory() ).getTableName();
+			foreignKeyColumns = JoinHelper.getRHSColumnNames( type, getFactory() );
+		}
+		return isDuplicateAssociation(foreignKeyTable, foreignKeyColumns);
+	}
+	
+	/**
+	 * Uniquely identifier a foreign key, so that we don't
+	 * join it more than once, and create circularities
+	 */
+	private static final class AssociationKey {
+		private String[] columns;
+		private String table;
+		private AssociationKey(String[] columns, String table) {
+			this.columns = columns;
+			this.table = table;
+		}
+		public boolean equals(Object other) {
+			AssociationKey that = (AssociationKey) other;
+			return that.table.equals(table) && Arrays.equals(columns, that.columns);
+		}
+		public int hashCode() {
+			return table.hashCode(); //TODO: inefficient
+		}
+	}
+	
+	/**
+	 * Should we join this association?
+	 */
+	protected boolean isJoinable(
+		final int joinType,
+		final Set visitedAssociationKeys, 
+		final String lhsTable,
+		final String[] lhsColumnNames,
+		final AssociationType type,
+		final int depth
+	) {
+		if (joinType<0) return false;
+		
+		if (joinType==JoinFragment.INNER_JOIN) return true;
+		
+		Integer maxFetchDepth = getFactory().getSettings().getMaximumFetchDepth();
+		final boolean tooDeep = maxFetchDepth!=null && 
+			depth >= maxFetchDepth.intValue();
+		
+		return !tooDeep && !isDuplicateAssociation(lhsTable, lhsColumnNames, type);
+	}
+	
+	protected String orderBy(final List associations, final String orderBy) {
+		return mergeOrderings( orderBy( associations ), orderBy );
+	}
+
+	protected static String mergeOrderings(String ordering1, String ordering2) {
+		if ( ordering1.length() == 0 ) {
+			return ordering2;
+		}
+		else if ( ordering2.length() == 0 ) {
+			return ordering1;
+		}
+		else {
+			return ordering1 + ", " + ordering2;
+		}
+	}
+	
+	/**
+	 * Generate a sequence of <tt>LEFT OUTER JOIN</tt> clauses for the given associations.
+	 */
+	protected final JoinFragment mergeOuterJoins(List associations)
+	throws MappingException {
+		JoinFragment outerjoin = getDialect().createOuterJoinFragment();
+		Iterator iter = associations.iterator();
+		OuterJoinableAssociation last = null;
+		while ( iter.hasNext() ) {
+			OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next();
+			if ( last != null && last.isManyToManyWith( oj ) ) {
+				oj.addManyToManyJoin( outerjoin, ( QueryableCollection ) last.getJoinable() );
+			}
+			else {
+				oj.addJoins(outerjoin);
+			}
+			last = oj;
+		}
+		last = null;
+		return outerjoin;
+	}
+
+	/**
+	 * Count the number of instances of Joinable which are actually
+	 * also instances of Loadable, or are one-to-many associations
+	 */
+	protected static final int countEntityPersisters(List associations)
+	throws MappingException {
+		int result = 0;
+		Iterator iter = associations.iterator();
+		while ( iter.hasNext() ) {
+			OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next();
+			if ( oj.getJoinable().consumesEntityAlias() ) {
+				result++;
+			}
+		}
+		return result;
+	}
+	
+	/**
+	 * Count the number of instances of Joinable which are actually
+	 * also instances of PersistentCollection which are being fetched
+	 * by outer join
+	 */
+	protected static final int countCollectionPersisters(List associations)
+	throws MappingException {
+		int result = 0;
+		Iterator iter = associations.iterator();
+		while ( iter.hasNext() ) {
+			OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next();
+			if ( oj.getJoinType()==JoinFragment.LEFT_OUTER_JOIN && oj.getJoinable().isCollection() ) {
+				result++;
+			}
+		}
+		return result;
+	}
+	
+	/**
+	 * Get the order by string required for collection fetching
+	 */
+	protected static final String orderBy(List associations)
+	throws MappingException {
+		StringBuffer buf = new StringBuffer();
+		Iterator iter = associations.iterator();
+		OuterJoinableAssociation last = null;
+		while ( iter.hasNext() ) {
+			OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next();
+			if ( oj.getJoinType() == JoinFragment.LEFT_OUTER_JOIN ) { // why does this matter?
+				if ( oj.getJoinable().isCollection() ) {
+					final QueryableCollection queryableCollection = (QueryableCollection) oj.getJoinable();
+					if ( queryableCollection.hasOrdering() ) {
+						final String orderByString = queryableCollection.getSQLOrderByString( oj.getRHSAlias() );
+						buf.append( orderByString ).append(", ");
+					}
+				}
+				else {
+					// it might still need to apply a collection ordering based on a
+					// many-to-many defined order-by...
+					if ( last != null && last.getJoinable().isCollection() ) {
+						final QueryableCollection queryableCollection = (QueryableCollection) last.getJoinable();
+						if ( queryableCollection.isManyToMany() && last.isManyToManyWith( oj ) ) {
+							if ( queryableCollection.hasManyToManyOrdering() ) {
+								final String orderByString = queryableCollection.getManyToManyOrderByString( oj.getRHSAlias() );
+								buf.append( orderByString ).append(", ");
+							}
+						}
+					}
+				}
+			}
+			last = oj;
+		}
+		if ( buf.length()>0 ) buf.setLength( buf.length()-2 );
+		return buf.toString();
+	}
+	
+	/**
+	 * Render the where condition for a (batch) load by identifier / collection key
+	 */
+	protected StringBuffer whereString(String alias, String[] columnNames, int batchSize) {
+		if ( columnNames.length==1 ) {
+			// if not a composite key, use "foo in (?, ?, ?)" for batching
+			// if no batch, and not a composite key, use "foo = ?"
+			InFragment in = new InFragment().setColumn( alias, columnNames[0] );
+			for ( int i=0; i<batchSize; i++ ) in.addValue("?");
+			return new StringBuffer( in.toFragmentString() );
+		}
+		else {
+			//a composite key
+			ConditionFragment byId = new ConditionFragment()
+					.setTableAlias(alias)
+					.setCondition( columnNames, "?" );
+	
+			StringBuffer whereString = new StringBuffer();
+			if ( batchSize==1 ) {
+				// if no batch, use "foo = ? and bar = ?"
+				whereString.append( byId.toFragmentString() );
+			}
+			else {
+				// if a composite key, use "( (foo = ? and bar = ?) or (foo = ? and bar = ?) )" for batching
+				whereString.append('('); //TODO: unnecessary for databases with ANSI-style joins
+				DisjunctionFragment df = new DisjunctionFragment();
+				for ( int i=0; i<batchSize; i++ ) {
+					df.addCondition(byId);
+				}
+				whereString.append( df.toFragmentString() );
+				whereString.append(')'); //TODO: unnecessary for databases with ANSI-style joins
+			}
+			return whereString;
+		}
+	}
+
+	protected void initPersisters(final List associations, final LockMode lockMode) throws MappingException {
+		
+		final int joins = countEntityPersisters(associations);
+		final int collections = countCollectionPersisters(associations);
+
+		collectionOwners = collections==0 ? null : new int[collections];
+		collectionPersisters = collections==0 ? null : new CollectionPersister[collections];
+		collectionSuffixes = BasicLoader.generateSuffixes( joins + 1, collections );
+
+		persisters = new Loadable[joins];
+		aliases = new String[joins];
+		owners = new int[joins];
+		ownerAssociationTypes = new EntityType[joins];
+		lockModeArray = ArrayHelper.fillArray(lockMode, joins);
+		
+		int i=0;
+		int j=0;
+		Iterator iter = associations.iterator();
+		while ( iter.hasNext() ) {
+			final OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next();
+			if ( !oj.isCollection() ) {
+				
+				persisters[i] = (Loadable) oj.getJoinable();
+				aliases[i] = oj.getRHSAlias();
+				owners[i] = oj.getOwner(associations);
+				ownerAssociationTypes[i] = (EntityType) oj.getJoinableType();
+				i++;
+				
+			}
+			else {
+				
+				QueryableCollection collPersister = (QueryableCollection) oj.getJoinable();
+				if ( oj.getJoinType()==JoinFragment.LEFT_OUTER_JOIN ) {
+					//it must be a collection fetch
+					collectionPersisters[j] = collPersister;
+					collectionOwners[j] = oj.getOwner(associations);
+					j++;
+				}
+	
+				if ( collPersister.isOneToMany() ) {
+					persisters[i] = (Loadable) collPersister.getElementPersister();
+					aliases[i] = oj.getRHSAlias();
+					i++;
+				}
+			}
+		}
+	
+		if ( ArrayHelper.isAllNegative(owners) ) owners = null;
+		if ( collectionOwners!=null && ArrayHelper.isAllNegative(collectionOwners) ) {
+			collectionOwners = null;
+		}
+	}
+
+	/**
+	 * Generate a select list of columns containing all properties of the entity classes
+	 */
+	protected final String selectString(List associations)
+	throws MappingException {
+
+		if ( associations.size()==0 ) {
+			return "";
+		}
+		else {
+			StringBuffer buf = new StringBuffer( associations.size() * 100 )
+				.append(", ");
+			int entityAliasCount=0;
+			int collectionAliasCount=0;
+			for ( int i=0; i<associations.size(); i++ ) {
+				OuterJoinableAssociation join = (OuterJoinableAssociation) associations.get(i);
+				OuterJoinableAssociation next = (i == associations.size() - 1)
+				        ? null
+				        : ( OuterJoinableAssociation ) associations.get( i + 1 );
+				final Joinable joinable = join.getJoinable();
+				final String entitySuffix = ( suffixes == null || entityAliasCount >= suffixes.length )
+				        ? null
+				        : suffixes[entityAliasCount];
+				final String collectionSuffix = ( collectionSuffixes == null || collectionAliasCount >= collectionSuffixes.length )
+				        ? null
+				        : collectionSuffixes[collectionAliasCount];
+				final String selectFragment = joinable.selectFragment(
+						next == null ? null : next.getJoinable(),
+						next == null ? null : next.getRHSAlias(),
+						join.getRHSAlias(),
+						entitySuffix,
+				        collectionSuffix,
+						join.getJoinType()==JoinFragment.LEFT_OUTER_JOIN
+				);
+				buf.append(selectFragment);
+				if ( joinable.consumesEntityAlias() ) entityAliasCount++;
+				if ( joinable.consumesCollectionAlias() && join.getJoinType()==JoinFragment.LEFT_OUTER_JOIN ) collectionAliasCount++;
+				if (
+					i<associations.size()-1 &&
+					selectFragment.trim().length()>0
+				) {
+					buf.append(", ");
+				}
+			}
+			return buf.toString();
+		}
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/JoinWalker.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/Loader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/Loader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/Loader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,2365 @@
+//$Id: Loader.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.loader;
+
+import java.io.Serializable;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.QueryException;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.WrongClassException;
+import org.hibernate.cache.FilterKey;
+import org.hibernate.cache.QueryCache;
+import org.hibernate.cache.QueryKey;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.EntityUniqueKey;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.RowSelection;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.SubselectFetch;
+import org.hibernate.engine.TwoPhaseLoad;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.PostLoadEvent;
+import org.hibernate.event.PreLoadEvent;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.hql.HolderInstantiator;
+import org.hibernate.impl.FetchingScrollableResultsImpl;
+import org.hibernate.impl.ScrollableResultsImpl;
+import org.hibernate.jdbc.ColumnNameCache;
+import org.hibernate.jdbc.ResultSetWrapper;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.persister.entity.UniqueKeyLoadable;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.type.VersionType;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Abstract superclass of object loading (and querying) strategies. This class implements
+ * useful common functionality that concrete loaders delegate to. It is not intended that this
+ * functionality would be directly accessed by client code. (Hence, all methods of this class
+ * are declared <tt>protected</tt> or <tt>private</tt>.) This class relies heavily upon the
+ * <tt>Loadable</tt> interface, which is the contract between this class and
+ * <tt>EntityPersister</tt>s that may be loaded by it.<br>
+ * <br>
+ * The present implementation is able to load any number of columns of entities and at most
+ * one collection role per query.
+ *
+ * @author Gavin King
+ * @see org.hibernate.persister.entity.Loadable
+ */
+public abstract class Loader {
+
+	private static final Log log = LogFactory.getLog( Loader.class );
+
+	private final SessionFactoryImplementor factory;
+	private ColumnNameCache columnNameCache;
+
+	public Loader(SessionFactoryImplementor factory) {
+		this.factory = factory;
+	}
+
+	/**
+	 * The SQL query string to be called; implemented by all subclasses
+	 *
+	 * @return The sql command this loader should use to get its {@link ResultSet}.
+	 */
+	protected abstract String getSQLString();
+
+	/**
+	 * An array of persisters of entity classes contained in each row of results;
+	 * implemented by all subclasses
+	 *
+	 * @return The entity persisters.
+	 */
+	protected abstract Loadable[] getEntityPersisters();
+	
+	/**
+	 * An array indicating whether the entities have eager property fetching
+	 * enabled.
+	 *
+	 * @return Eager property fetching indicators.
+	 */
+	protected boolean[] getEntityEagerPropertyFetches() {
+		return null;
+	}
+
+	/**
+	 * An array of indexes of the entity that owns a one-to-one association
+	 * to the entity at the given index (-1 if there is no "owner").  The
+	 * indexes contained here are relative to the result of
+	 * {@link #getEntityPersisters}.
+	 *
+	 * @return The owner indicators (see discussion above).
+	 */
+	protected int[] getOwners() {
+		return null;
+	}
+
+	/**
+	 * An array of the owner types corresponding to the {@link #getOwners()}
+	 * returns.  Indices indicating no owner would be null here.
+	 *
+	 * @return The types for the owners.
+	 */
+	protected EntityType[] getOwnerAssociationTypes() {
+		return null;
+	}
+
+	/**
+	 * An (optional) persister for a collection to be initialized; only 
+	 * collection loaders return a non-null value
+	 */
+	protected CollectionPersister[] getCollectionPersisters() {
+		return null;
+	}
+
+	/**
+	 * Get the index of the entity that owns the collection, or -1
+	 * if there is no owner in the query results (ie. in the case of a
+	 * collection initializer) or no collection.
+	 */
+	protected int[] getCollectionOwners() {
+		return null;
+	}
+
+	/**
+	 * What lock mode does this load entities with?
+	 *
+	 * @param lockModes a collection of lock modes specified dynamically via the Query interface
+	 */
+	protected abstract LockMode[] getLockModes(Map lockModes);
+
+	/**
+	 * Append <tt>FOR UPDATE OF</tt> clause, if necessary. This
+	 * empty superclass implementation merely returns its first
+	 * argument.
+	 */
+	protected String applyLocks(String sql, Map lockModes, Dialect dialect) throws HibernateException {
+		return sql;
+	}
+
+	/**
+	 * Does this query return objects that might be already cached
+	 * by the session, whose lock mode may need upgrading
+	 */
+	protected boolean upgradeLocks() {
+		return false;
+	}
+
+	/**
+	 * Return false is this loader is a batch entity loader
+	 */
+	protected boolean isSingleRowLoader() {
+		return false;
+	}
+
+	/**
+	 * Get the SQL table aliases of entities whose
+	 * associations are subselect-loadable, returning
+	 * null if this loader does not support subselect
+	 * loading
+	 */
+	protected String[] getAliases() {
+		return null;
+	}
+
+	/**
+	 * Modify the SQL, adding lock hints and comments, if necessary
+	 */
+	protected String preprocessSQL(String sql, QueryParameters parameters, Dialect dialect)
+			throws HibernateException {
+		
+		sql = applyLocks( sql, parameters.getLockModes(), dialect );
+		
+		return getFactory().getSettings().isCommentsEnabled() ?
+				prependComment( sql, parameters ) : sql;
+	}
+
+	private String prependComment(String sql, QueryParameters parameters) {
+		String comment = parameters.getComment();
+		if ( comment == null ) {
+			return sql;
+		}
+		else {
+			return new StringBuffer( comment.length() + sql.length() + 5 )
+					.append( "/* " )
+					.append( comment )
+					.append( " */ " )
+					.append( sql )
+					.toString();
+		}
+	}
+
+	/**
+	 * Execute an SQL query and attempt to instantiate instances of the class mapped by the given
+	 * persister from each row of the <tt>ResultSet</tt>. If an object is supplied, will attempt to
+	 * initialize that object. If a collection is supplied, attempt to initialize that collection.
+	 */
+	private List doQueryAndInitializeNonLazyCollections(final SessionImplementor session,
+														final QueryParameters queryParameters,
+														final boolean returnProxies) 
+		throws HibernateException, SQLException {
+
+		final PersistenceContext persistenceContext = session.getPersistenceContext();
+		persistenceContext.beforeLoad();
+		List result;
+		try {
+			result = doQuery( session, queryParameters, returnProxies );
+		}
+		finally {
+			persistenceContext.afterLoad();
+		}
+		persistenceContext.initializeNonLazyCollections();
+		return result;
+	}
+
+	/**
+	 * Loads a single row from the result set.  This is the processing used from the
+	 * ScrollableResults where no collection fetches were encountered.
+	 *
+	 * @param resultSet The result set from which to do the load.
+	 * @param session The session from which the request originated.
+	 * @param queryParameters The query parameters specified by the user.
+	 * @param returnProxies Should proxies be generated
+	 * @return The loaded "row".
+	 * @throws HibernateException
+	 */
+	public Object loadSingleRow(
+	        final ResultSet resultSet,
+	        final SessionImplementor session,
+	        final QueryParameters queryParameters,
+	        final boolean returnProxies) throws HibernateException {
+
+		final int entitySpan = getEntityPersisters().length;
+		final List hydratedObjects = entitySpan == 0 ? 
+				null : new ArrayList( entitySpan );
+
+		final Object result;
+		try {
+			result = getRowFromResultSet(
+			        resultSet,
+					session,
+					queryParameters,
+					getLockModes( queryParameters.getLockModes() ),
+					null,
+					hydratedObjects,
+					new EntityKey[entitySpan],
+					returnProxies
+				);
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+			        factory.getSQLExceptionConverter(),
+			        sqle,
+			        "could not read next row of results",
+			        getSQLString()
+				);
+		}
+
+		initializeEntitiesAndCollections( 
+				hydratedObjects, 
+				resultSet, 
+				session, 
+				queryParameters.isReadOnly() 
+			);
+		session.getPersistenceContext().initializeNonLazyCollections();
+		return result;
+	}
+
+	private Object sequentialLoad(
+	        final ResultSet resultSet,
+	        final SessionImplementor session,
+	        final QueryParameters queryParameters,
+	        final boolean returnProxies,
+	        final EntityKey keyToRead) throws HibernateException {
+
+		final int entitySpan = getEntityPersisters().length;
+		final List hydratedObjects = entitySpan == 0 ? 
+				null : new ArrayList( entitySpan );
+
+		Object result = null;
+		final EntityKey[] loadedKeys = new EntityKey[entitySpan];
+
+		try {
+			do {
+				Object loaded = getRowFromResultSet(
+						resultSet,
+						session,
+						queryParameters,
+						getLockModes( queryParameters.getLockModes() ),
+						null,
+						hydratedObjects,
+						loadedKeys,
+						returnProxies
+					);
+				if ( result == null ) {
+					result = loaded;
+				}
+			} 
+			while ( keyToRead.equals( loadedKeys[0] ) && resultSet.next() );
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+			        factory.getSQLExceptionConverter(),
+			        sqle,
+			        "could not perform sequential read of results (forward)",
+			        getSQLString()
+				);
+		}
+
+		initializeEntitiesAndCollections( 
+				hydratedObjects, 
+				resultSet, 
+				session, 
+				queryParameters.isReadOnly() 
+			);
+		session.getPersistenceContext().initializeNonLazyCollections();
+		return result;
+	}
+
+	/**
+	 * Loads a single logical row from the result set moving forward.  This is the
+	 * processing used from the ScrollableResults where there were collection fetches
+	 * encountered; thus a single logical row may have multiple rows in the underlying
+	 * result set.
+	 *
+	 * @param resultSet The result set from which to do the load.
+	 * @param session The session from which the request originated.
+	 * @param queryParameters The query parameters specified by the user.
+	 * @param returnProxies Should proxies be generated
+	 * @return The loaded "row".
+	 * @throws HibernateException
+	 */
+	public Object loadSequentialRowsForward(
+	        final ResultSet resultSet,
+	        final SessionImplementor session,
+	        final QueryParameters queryParameters,
+	        final boolean returnProxies) throws HibernateException {
+
+		// note that for sequential scrolling, we make the assumption that
+		// the first persister element is the "root entity"
+
+		try {
+			if ( resultSet.isAfterLast() ) {
+				// don't even bother trying to read further
+				return null;
+			}
+
+			if ( resultSet.isBeforeFirst() ) {
+				resultSet.next();
+			}
+
+			// We call getKeyFromResultSet() here so that we can know the
+			// key value upon which to perform the breaking logic.  However,
+			// it is also then called from getRowFromResultSet() which is certainly
+			// not the most efficient.  But the call here is needed, and there
+			// currently is no other way without refactoring of the doQuery()/getRowFromResultSet()
+			// methods
+			final EntityKey currentKey = getKeyFromResultSet(
+					0,
+					getEntityPersisters()[0],
+					null,
+					resultSet,
+					session
+				);
+
+			return sequentialLoad( resultSet, session, queryParameters, returnProxies, currentKey );
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+			        factory.getSQLExceptionConverter(),
+			        sqle,
+			        "could not perform sequential read of results (forward)",
+			        getSQLString()
+				);
+		}
+	}
+
+	/**
+	 * Loads a single logical row from the result set moving forward.  This is the
+	 * processing used from the ScrollableResults where there were collection fetches
+	 * encountered; thus a single logical row may have multiple rows in the underlying
+	 * result set.
+	 *
+	 * @param resultSet The result set from which to do the load.
+	 * @param session The session from which the request originated.
+	 * @param queryParameters The query parameters specified by the user.
+	 * @param returnProxies Should proxies be generated
+	 * @return The loaded "row".
+	 * @throws HibernateException
+	 */
+	public Object loadSequentialRowsReverse(
+	        final ResultSet resultSet,
+	        final SessionImplementor session,
+	        final QueryParameters queryParameters,
+	        final boolean returnProxies,
+	        final boolean isLogicallyAfterLast) throws HibernateException {
+
+		// note that for sequential scrolling, we make the assumption that
+		// the first persister element is the "root entity"
+
+		try {
+			if ( resultSet.isFirst() ) {
+				// don't even bother trying to read any further
+				return null;
+			}
+
+			EntityKey keyToRead = null;
+			// This check is needed since processing leaves the cursor
+			// after the last physical row for the current logical row;
+			// thus if we are after the last physical row, this might be
+			// caused by either:
+			//      1) scrolling to the last logical row
+			//      2) scrolling past the last logical row
+			// In the latter scenario, the previous logical row
+			// really is the last logical row.
+			//
+			// In all other cases, we should process back two
+			// logical records (the current logic row, plus the
+			// previous logical row).
+			if ( resultSet.isAfterLast() && isLogicallyAfterLast ) {
+				// position cursor to the last row
+				resultSet.last();
+				keyToRead = getKeyFromResultSet(
+						0,
+						getEntityPersisters()[0],
+						null,
+						resultSet,
+						session
+					);
+			}
+			else {
+				// Since the result set cursor is always left at the first
+				// physical row after the "last processed", we need to jump
+				// back one position to get the key value we are interested
+				// in skipping
+				resultSet.previous();
+
+				// sequentially read the result set in reverse until we recognize
+				// a change in the key value.  At that point, we are pointed at
+				// the last physical sequential row for the logical row in which
+				// we are interested in processing
+				boolean firstPass = true;
+				final EntityKey lastKey = getKeyFromResultSet(
+						0,
+						getEntityPersisters()[0],
+						null,
+						resultSet,
+						session
+					);
+				while ( resultSet.previous() ) {
+					EntityKey checkKey = getKeyFromResultSet(
+							0,
+							getEntityPersisters()[0],
+							null,
+							resultSet,
+							session
+						);
+
+					if ( firstPass ) {
+						firstPass = false;
+						keyToRead = checkKey;
+					}
+
+					if ( !lastKey.equals( checkKey ) ) {
+						break;
+					}
+				}
+
+			}
+
+			// Read backwards until we read past the first physical sequential
+			// row with the key we are interested in loading
+			while ( resultSet.previous() ) {
+				EntityKey checkKey = getKeyFromResultSet(
+						0,
+						getEntityPersisters()[0],
+						null,
+						resultSet,
+						session
+					);
+
+				if ( !keyToRead.equals( checkKey ) ) {
+					break;
+				}
+			}
+
+			// Finally, read ahead one row to position result set cursor
+			// at the first physical row we are interested in loading
+			resultSet.next();
+
+			// and perform the load
+			return sequentialLoad( resultSet, session, queryParameters, returnProxies, keyToRead );
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+			        factory.getSQLExceptionConverter(),
+			        sqle,
+			        "could not perform sequential read of results (forward)",
+			        getSQLString()
+				);
+		}
+	}
+
+	private static EntityKey getOptionalObjectKey(QueryParameters queryParameters, SessionImplementor session) {
+		final Object optionalObject = queryParameters.getOptionalObject();
+		final Serializable optionalId = queryParameters.getOptionalId();
+		final String optionalEntityName = queryParameters.getOptionalEntityName();
+
+		if ( optionalObject != null && optionalEntityName != null ) {
+			return new EntityKey( 
+					optionalId,
+					session.getEntityPersister( optionalEntityName, optionalObject ), 
+					session.getEntityMode()
+				);
+		}
+		else {
+			return null;
+		}
+
+	}
+
+	private Object getRowFromResultSet(
+	        final ResultSet resultSet,
+	        final SessionImplementor session,
+	        final QueryParameters queryParameters,
+	        final LockMode[] lockModeArray,
+	        final EntityKey optionalObjectKey,
+	        final List hydratedObjects,
+	        final EntityKey[] keys,
+	        boolean returnProxies) throws SQLException, HibernateException {
+
+		final Loadable[] persisters = getEntityPersisters();
+		final int entitySpan = persisters.length;
+
+		for ( int i = 0; i < entitySpan; i++ ) {
+			keys[i] = getKeyFromResultSet(
+			        i,
+					persisters[i],
+					i == entitySpan - 1 ?
+							queryParameters.getOptionalId() :
+							null,
+					resultSet,
+					session
+				);
+			//TODO: the i==entitySpan-1 bit depends upon subclass implementation (very bad)
+		}
+
+		registerNonExists( keys, persisters, session );
+
+		// this call is side-effecty
+		Object[] row = getRow(
+		        resultSet,
+				persisters,
+				keys,
+				queryParameters.getOptionalObject(),
+				optionalObjectKey,
+				lockModeArray,
+				hydratedObjects,
+				session
+		);
+
+		readCollectionElements( row, resultSet, session );
+
+		if ( returnProxies ) {
+			// now get an existing proxy for each row element (if there is one)
+			for ( int i = 0; i < entitySpan; i++ ) {
+				Object entity = row[i];
+				Object proxy = session.getPersistenceContext().proxyFor( persisters[i], keys[i], entity );
+				if ( entity != proxy ) {
+					// force the proxy to resolve itself
+					( (HibernateProxy) proxy ).getHibernateLazyInitializer().setImplementation(entity);
+					row[i] = proxy;
+				}
+			}
+		}
+
+		return getResultColumnOrRow( row, queryParameters.getResultTransformer(), resultSet, session );
+
+	}
+
+	/**
+	 * Read any collection elements contained in a single row of the result set
+	 */
+	private void readCollectionElements(Object[] row, ResultSet resultSet, SessionImplementor session)
+			throws SQLException, HibernateException {
+
+		//TODO: make this handle multiple collection roles!
+
+		final CollectionPersister[] collectionPersisters = getCollectionPersisters();
+		if ( collectionPersisters != null ) {
+
+			final CollectionAliases[] descriptors = getCollectionAliases();
+			final int[] collectionOwners = getCollectionOwners();
+
+			for ( int i=0; i<collectionPersisters.length; i++ ) {
+
+				final boolean hasCollectionOwners = collectionOwners !=null && 
+						collectionOwners[i] > -1;
+				//true if this is a query and we are loading multiple instances of the same collection role
+				//otherwise this is a CollectionInitializer and we are loading up a single collection or batch
+				
+				final Object owner = hasCollectionOwners ?
+						row[ collectionOwners[i] ] :
+						null; //if null, owner will be retrieved from session
+
+				final CollectionPersister collectionPersister = collectionPersisters[i];
+				final Serializable key;
+				if ( owner == null ) {
+					key = null;
+				}
+				else {
+					key = collectionPersister.getCollectionType().getKeyOfOwner( owner, session );
+					//TODO: old version did not require hashmap lookup:
+					//keys[collectionOwner].getIdentifier()
+				}
+	
+				readCollectionElement( 
+						owner, 
+						key, 
+						collectionPersister, 
+						descriptors[i], 
+						resultSet, 
+						session 
+					);
+				
+			}
+
+		}
+	}
+
+	private List doQuery(
+			final SessionImplementor session,
+			final QueryParameters queryParameters,
+			final boolean returnProxies) throws SQLException, HibernateException {
+
+		final RowSelection selection = queryParameters.getRowSelection();
+		final int maxRows = hasMaxRows( selection ) ?
+				selection.getMaxRows().intValue() :
+				Integer.MAX_VALUE;
+
+		final int entitySpan = getEntityPersisters().length;
+
+		final ArrayList hydratedObjects = entitySpan == 0 ? null : new ArrayList( entitySpan * 10 );
+		final PreparedStatement st = prepareQueryStatement( queryParameters, false, session );
+		final ResultSet rs = getResultSet( st, queryParameters.hasAutoDiscoverScalarTypes(), queryParameters.isCallable(), selection, session );
+
+// would be great to move all this below here into another method that could also be used
+// from the new scrolling stuff.
+//
+// Would need to change the way the max-row stuff is handled (i.e. behind an interface) so
+// that I could do the control breaking at the means to know when to stop
+		final LockMode[] lockModeArray = getLockModes( queryParameters.getLockModes() );
+		final EntityKey optionalObjectKey = getOptionalObjectKey( queryParameters, session );
+
+		final boolean createSubselects = isSubselectLoadingEnabled();
+		final List subselectResultKeys = createSubselects ? new ArrayList() : null;
+		final List results = new ArrayList();
+
+		try {
+
+			handleEmptyCollections( queryParameters.getCollectionKeys(), rs, session );
+
+			EntityKey[] keys = new EntityKey[entitySpan]; //we can reuse it for each row
+
+			if ( log.isTraceEnabled() ) log.trace( "processing result set" );
+
+			int count;
+			for ( count = 0; count < maxRows && rs.next(); count++ ) {
+				
+				if ( log.isTraceEnabled() ) log.debug("result set row: " + count);
+
+				Object result = getRowFromResultSet( 
+						rs,
+						session,
+						queryParameters,
+						lockModeArray,
+						optionalObjectKey,
+						hydratedObjects,
+						keys,
+						returnProxies 
+				);
+				results.add( result );
+
+				if ( createSubselects ) {
+					subselectResultKeys.add(keys);
+					keys = new EntityKey[entitySpan]; //can't reuse in this case
+				}
+				
+			}
+
+			if ( log.isTraceEnabled() ) {
+				log.trace( "done processing result set (" + count + " rows)" );
+			}
+
+		}
+		finally {
+			session.getBatcher().closeQueryStatement( st, rs );
+		}
+
+		initializeEntitiesAndCollections( hydratedObjects, rs, session, queryParameters.isReadOnly() );
+
+		if ( createSubselects ) createSubselects( subselectResultKeys, queryParameters, session );
+
+		return results; //getResultList(results);
+
+	}
+
+	protected boolean isSubselectLoadingEnabled() {
+		return false;
+	}
+	
+	protected boolean hasSubselectLoadableCollections() {
+		final Loadable[] loadables = getEntityPersisters();
+		for (int i=0; i<loadables.length; i++ ) {
+			if ( loadables[i].hasSubselectLoadableCollections() ) return true;
+		}
+		return false;
+	}
+	
+	private static Set[] transpose( List keys ) {
+		Set[] result = new Set[ ( ( EntityKey[] ) keys.get(0) ).length ];
+		for ( int j=0; j<result.length; j++ ) {
+			result[j] = new HashSet( keys.size() );
+			for ( int i=0; i<keys.size(); i++ ) {
+				result[j].add( ( ( EntityKey[] ) keys.get(i) ) [j] );
+			}
+		}
+		return result;
+	}
+
+	private void createSubselects(List keys, QueryParameters queryParameters, SessionImplementor session) {
+		if ( keys.size() > 1 ) { //if we only returned one entity, query by key is more efficient
+			
+			Set[] keySets = transpose(keys);
+			
+			Map namedParameterLocMap = buildNamedParameterLocMap( queryParameters );
+			
+			final Loadable[] loadables = getEntityPersisters();
+			final String[] aliases = getAliases();
+			final Iterator iter = keys.iterator();
+			while ( iter.hasNext() ) {
+				
+				final EntityKey[] rowKeys = (EntityKey[]) iter.next();
+				for ( int i=0; i<rowKeys.length; i++ ) {
+					
+					if ( rowKeys[i]!=null && loadables[i].hasSubselectLoadableCollections() ) {
+						
+						SubselectFetch subselectFetch = new SubselectFetch( 
+								//getSQLString(), 
+								aliases[i], 
+								loadables[i], 
+								queryParameters, 
+								keySets[i],
+								namedParameterLocMap
+							);
+						
+						session.getPersistenceContext()
+								.getBatchFetchQueue()
+								.addSubselect( rowKeys[i], subselectFetch );
+					}
+					
+				}
+				
+			}
+		}
+	}
+
+	private Map buildNamedParameterLocMap(QueryParameters queryParameters) {
+		if ( queryParameters.getNamedParameters()!=null ) {
+			final Map namedParameterLocMap = new HashMap();
+			Iterator piter = queryParameters.getNamedParameters().keySet().iterator();
+			while ( piter.hasNext() ) {
+				String name = (String) piter.next();
+				namedParameterLocMap.put(
+						name,
+						getNamedParameterLocs(name)
+					);
+			}
+			return namedParameterLocMap;
+		}
+		else {
+			return null;
+		}
+	}
+
+	private void initializeEntitiesAndCollections(
+			final List hydratedObjects,
+			final Object resultSetId,
+			final SessionImplementor session,
+			final boolean readOnly) 
+	throws HibernateException {
+		
+		final CollectionPersister[] collectionPersisters = getCollectionPersisters();
+		if ( collectionPersisters != null ) {
+			for ( int i=0; i<collectionPersisters.length; i++ ) {
+				if ( collectionPersisters[i].isArray() ) {
+					//for arrays, we should end the collection load before resolving
+					//the entities, since the actual array instances are not instantiated
+					//during loading
+					//TODO: or we could do this polymorphically, and have two
+					//      different operations implemented differently for arrays
+					endCollectionLoad( resultSetId, session, collectionPersisters[i] );
+				}
+			}
+		}
+
+		//important: reuse the same event instances for performance!
+		final PreLoadEvent pre;
+		final PostLoadEvent post;
+		if ( session.isEventSource() ) {
+			pre = new PreLoadEvent( (EventSource) session );
+			post = new PostLoadEvent( (EventSource) session );
+		}
+		else {
+			pre = null;
+			post = null;
+		}
+		
+		if ( hydratedObjects!=null ) {
+			int hydratedObjectsSize = hydratedObjects.size();
+			if ( log.isTraceEnabled() ) {
+				log.trace( "total objects hydrated: " + hydratedObjectsSize );
+			}
+			for ( int i = 0; i < hydratedObjectsSize; i++ ) {
+				TwoPhaseLoad.initializeEntity( hydratedObjects.get(i), readOnly, session, pre, post );
+			}
+		}
+		
+		if ( collectionPersisters != null ) {
+			for ( int i=0; i<collectionPersisters.length; i++ ) {
+				if ( !collectionPersisters[i].isArray() ) {
+					//for sets, we should end the collection load after resolving
+					//the entities, since we might call hashCode() on the elements
+					//TODO: or we could do this polymorphically, and have two
+					//      different operations implemented differently for arrays
+					endCollectionLoad( resultSetId, session, collectionPersisters[i] );
+				}
+			}
+		}
+		
+	}
+
+	private void endCollectionLoad(
+			final Object resultSetId, 
+			final SessionImplementor session, 
+			final CollectionPersister collectionPersister) {
+		//this is a query and we are loading multiple instances of the same collection role
+		session.getPersistenceContext()
+				.getLoadContexts()
+				.getCollectionLoadContext( ( ResultSet ) resultSetId )
+				.endLoadingCollections( collectionPersister );
+	}
+
+	protected List getResultList(List results, ResultTransformer resultTransformer) throws QueryException {
+		return results;
+	}
+
+	/**
+	 * Get the actual object that is returned in the user-visible result list.
+	 * This empty implementation merely returns its first argument. This is
+	 * overridden by some subclasses.
+	 */
+	protected Object getResultColumnOrRow(Object[] row, ResultTransformer transformer, ResultSet rs, SessionImplementor session)
+			throws SQLException, HibernateException {
+		return row;
+	}
+
+	/**
+	 * For missing objects associated by one-to-one with another object in the
+	 * result set, register the fact that the the object is missing with the
+	 * session.
+	 */
+	private void registerNonExists(
+	        final EntityKey[] keys,
+	        final Loadable[] persisters,
+	        final SessionImplementor session) {
+		
+		final int[] owners = getOwners();
+		if ( owners != null ) {
+			
+			EntityType[] ownerAssociationTypes = getOwnerAssociationTypes();
+			for ( int i = 0; i < keys.length; i++ ) {
+				
+				int owner = owners[i];
+				if ( owner > -1 ) {
+					EntityKey ownerKey = keys[owner];
+					if ( keys[i] == null && ownerKey != null ) {
+						
+						final PersistenceContext persistenceContext = session.getPersistenceContext();
+						
+						/*final boolean isPrimaryKey;
+						final boolean isSpecialOneToOne;
+						if ( ownerAssociationTypes == null || ownerAssociationTypes[i] == null ) {
+							isPrimaryKey = true;
+							isSpecialOneToOne = false;
+						}
+						else {
+							isPrimaryKey = ownerAssociationTypes[i].getRHSUniqueKeyPropertyName()==null;
+							isSpecialOneToOne = ownerAssociationTypes[i].getLHSPropertyName()!=null;
+						}*/
+						
+						//TODO: can we *always* use the "null property" approach for everything?
+						/*if ( isPrimaryKey && !isSpecialOneToOne ) {
+							persistenceContext.addNonExistantEntityKey( 
+									new EntityKey( ownerKey.getIdentifier(), persisters[i], session.getEntityMode() ) 
+							);
+						}
+						else if ( isSpecialOneToOne ) {*/
+						boolean isOneToOneAssociation = ownerAssociationTypes!=null && 
+								ownerAssociationTypes[i]!=null && 
+								ownerAssociationTypes[i].isOneToOne();
+						if ( isOneToOneAssociation ) {
+							persistenceContext.addNullProperty( ownerKey, 
+									ownerAssociationTypes[i].getPropertyName() );
+						}
+						/*}
+						else {
+							persistenceContext.addNonExistantEntityUniqueKey( new EntityUniqueKey( 
+									persisters[i].getEntityName(),
+									ownerAssociationTypes[i].getRHSUniqueKeyPropertyName(),
+									ownerKey.getIdentifier(),
+									persisters[owner].getIdentifierType(),
+									session.getEntityMode()
+							) );
+						}*/
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Read one collection element from the current row of the JDBC result set
+	 */
+	private void readCollectionElement(
+	        final Object optionalOwner,
+	        final Serializable optionalKey,
+	        final CollectionPersister persister,
+	        final CollectionAliases descriptor,
+	        final ResultSet rs,
+	        final SessionImplementor session) 
+	throws HibernateException, SQLException {
+
+		final PersistenceContext persistenceContext = session.getPersistenceContext();
+
+		final Serializable collectionRowKey = (Serializable) persister.readKey( 
+				rs, 
+				descriptor.getSuffixedKeyAliases(), 
+				session 
+			);
+		
+		if ( collectionRowKey != null ) {
+			// we found a collection element in the result set
+
+			if ( log.isDebugEnabled() ) {
+				log.debug( 
+						"found row of collection: " +
+						MessageHelper.collectionInfoString( persister, collectionRowKey, getFactory() ) 
+					);
+			}
+
+			Object owner = optionalOwner;
+			if ( owner == null ) {
+				owner = persistenceContext.getCollectionOwner( collectionRowKey, persister );
+				if ( owner == null ) {
+					//TODO: This is assertion is disabled because there is a bug that means the
+					//	  original owner of a transient, uninitialized collection is not known
+					//	  if the collection is re-referenced by a different object associated
+					//	  with the current Session
+					//throw new AssertionFailure("bug loading unowned collection");
+				}
+			}
+
+			PersistentCollection rowCollection = persistenceContext.getLoadContexts()
+					.getCollectionLoadContext( rs )
+					.getLoadingCollection( persister, collectionRowKey );
+
+			if ( rowCollection != null ) {
+				rowCollection.readFrom( rs, persister, descriptor, owner );
+			}
+
+		}
+		else if ( optionalKey != null ) {
+			// we did not find a collection element in the result set, so we
+			// ensure that a collection is created with the owner's identifier,
+			// since what we have is an empty collection
+
+			if ( log.isDebugEnabled() ) {
+				log.debug( 
+						"result set contains (possibly empty) collection: " +
+						MessageHelper.collectionInfoString( persister, optionalKey, getFactory() ) 
+					);
+			}
+
+			persistenceContext.getLoadContexts()
+					.getCollectionLoadContext( rs )
+					.getLoadingCollection( persister, optionalKey ); // handle empty collection
+
+		}
+
+		// else no collection element, but also no owner
+
+	}
+
+	/**
+	 * If this is a collection initializer, we need to tell the session that a collection
+	 * is being initilized, to account for the possibility of the collection having
+	 * no elements (hence no rows in the result set).
+	 */
+	private void handleEmptyCollections(
+	        final Serializable[] keys,
+	        final Object resultSetId,
+	        final SessionImplementor session) {
+
+		if ( keys != null ) {
+			// this is a collection initializer, so we must create a collection
+			// for each of the passed-in keys, to account for the possibility
+			// that the collection is empty and has no rows in the result set
+
+			CollectionPersister[] collectionPersisters = getCollectionPersisters();
+			for ( int j=0; j<collectionPersisters.length; j++ ) {
+				for ( int i = 0; i < keys.length; i++ ) {
+					//handle empty collections
+	
+					if ( log.isDebugEnabled() ) {
+						log.debug( 
+								"result set contains (possibly empty) collection: " +
+								MessageHelper.collectionInfoString( collectionPersisters[j], keys[i], getFactory() ) 
+							);
+					}
+
+					session.getPersistenceContext()
+							.getLoadContexts()
+							.getCollectionLoadContext( ( ResultSet ) resultSetId )
+							.getLoadingCollection( collectionPersisters[j], keys[i] );
+				}
+			}
+		}
+
+		// else this is not a collection initializer (and empty collections will
+		// be detected by looking for the owner's identifier in the result set)
+	}
+
+	/**
+	 * Read a row of <tt>Key</tt>s from the <tt>ResultSet</tt> into the given array.
+	 * Warning: this method is side-effecty.
+	 * <p/>
+	 * If an <tt>id</tt> is given, don't bother going to the <tt>ResultSet</tt>.
+	 */
+	private EntityKey getKeyFromResultSet(
+	        final int i,
+	        final Loadable persister,
+	        final Serializable id,
+	        final ResultSet rs,
+	        final SessionImplementor session) throws HibernateException, SQLException {
+
+		Serializable resultId;
+
+		// if we know there is exactly 1 row, we can skip.
+		// it would be great if we could _always_ skip this;
+		// it is a problem for <key-many-to-one>
+
+		if ( isSingleRowLoader() && id != null ) {
+			resultId = id;
+		}
+		else {
+			
+			Type idType = persister.getIdentifierType();
+			resultId = (Serializable) idType.nullSafeGet(
+					rs,
+					getEntityAliases()[i].getSuffixedKeyAliases(),
+					session,
+					null //problematic for <key-many-to-one>!
+				);
+			
+			final boolean idIsResultId = id != null && 
+					resultId != null && 
+					idType.isEqual( id, resultId, session.getEntityMode(), factory );
+			
+			if ( idIsResultId ) resultId = id; //use the id passed in
+		}
+
+		return resultId == null ?
+				null :
+				new EntityKey( resultId, persister, session.getEntityMode() );
+	}
+
+	/**
+	 * Check the version of the object in the <tt>ResultSet</tt> against
+	 * the object version in the session cache, throwing an exception
+	 * if the version numbers are different
+	 */
+	private void checkVersion(
+	        final int i,
+	        final Loadable persister,
+	        final Serializable id,
+	        final Object entity,
+	        final ResultSet rs,
+	        final SessionImplementor session) 
+	throws HibernateException, SQLException {
+
+		Object version = session.getPersistenceContext().getEntry( entity ).getVersion();
+
+		if ( version != null ) { //null version means the object is in the process of being loaded somewhere else in the ResultSet
+			VersionType versionType = persister.getVersionType();
+			Object currentVersion = versionType.nullSafeGet(
+					rs,
+					getEntityAliases()[i].getSuffixedVersionAliases(),
+					session,
+					null
+				);
+			if ( !versionType.isEqual(version, currentVersion) ) {
+				if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
+					session.getFactory().getStatisticsImplementor()
+							.optimisticFailure( persister.getEntityName() );
+				}
+				throw new StaleObjectStateException( persister.getEntityName(), id );
+			}
+		}
+
+	}
+
+	/**
+	 * Resolve any ids for currently loaded objects, duplications within the
+	 * <tt>ResultSet</tt>, etc. Instantiate empty objects to be initialized from the
+	 * <tt>ResultSet</tt>. Return an array of objects (a row of results) and an
+	 * array of booleans (by side-effect) that determine whether the corresponding
+	 * object should be initialized.
+	 */
+	private Object[] getRow(
+	        final ResultSet rs,
+	        final Loadable[] persisters,
+	        final EntityKey[] keys,
+	        final Object optionalObject,
+	        final EntityKey optionalObjectKey,
+	        final LockMode[] lockModes,
+	        final List hydratedObjects,
+	        final SessionImplementor session) 
+	throws HibernateException, SQLException {
+
+		final int cols = persisters.length;
+		final EntityAliases[] descriptors = getEntityAliases();
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( 
+					"result row: " + 
+					StringHelper.toString( keys ) 
+				);
+		}
+
+		final Object[] rowResults = new Object[cols];
+
+		for ( int i = 0; i < cols; i++ ) {
+
+			Object object = null;
+			EntityKey key = keys[i];
+
+			if ( keys[i] == null ) {
+				//do nothing
+			}
+			else {
+
+				//If the object is already loaded, return the loaded one
+				object = session.getEntityUsingInterceptor( key );
+				if ( object != null ) {
+					//its already loaded so don't need to hydrate it
+					instanceAlreadyLoaded( 
+							rs,
+							i,
+							persisters[i],
+							key,
+							object,
+							lockModes[i],
+							session 
+						);
+				}
+				else {
+					object = instanceNotYetLoaded( 
+							rs,
+							i,
+							persisters[i],
+							descriptors[i].getRowIdAlias(),
+							key,
+							lockModes[i],
+							optionalObjectKey,
+							optionalObject,
+							hydratedObjects,
+							session 
+						);
+				}
+
+			}
+
+			rowResults[i] = object;
+
+		}
+
+		return rowResults;
+	}
+
+	/**
+	 * The entity instance is already in the session cache
+	 */
+	private void instanceAlreadyLoaded(
+	        final ResultSet rs,
+	        final int i,
+	        final Loadable persister,
+	        final EntityKey key,
+	        final Object object,
+	        final LockMode lockMode,
+	        final SessionImplementor session) 
+	throws HibernateException, SQLException {
+
+		if ( !persister.isInstance( object, session.getEntityMode() ) ) {
+			throw new WrongClassException( 
+					"loaded object was of wrong class " + object.getClass(), 
+					key.getIdentifier(), 
+					persister.getEntityName() 
+				);
+		}
+
+		if ( LockMode.NONE != lockMode && upgradeLocks() ) { //no point doing this if NONE was requested
+
+			final boolean isVersionCheckNeeded = persister.isVersioned() &&
+					session.getPersistenceContext().getEntry(object)
+							.getLockMode().lessThan( lockMode );
+			// we don't need to worry about existing version being uninitialized
+			// because this block isn't called by a re-entrant load (re-entrant
+			// loads _always_ have lock mode NONE)
+			if (isVersionCheckNeeded) {
+				//we only check the version when _upgrading_ lock modes
+				checkVersion( i, persister, key.getIdentifier(), object, rs, session );
+				//we need to upgrade the lock mode to the mode requested
+				session.getPersistenceContext().getEntry(object)
+						.setLockMode(lockMode);
+			}
+		}
+	}
+
+	/**
+	 * The entity instance is not in the session cache
+	 */
+	private Object instanceNotYetLoaded(
+	        final ResultSet rs,
+	        final int i,
+	        final Loadable persister,
+	        final String rowIdAlias,
+	        final EntityKey key,
+	        final LockMode lockMode,
+	        final EntityKey optionalObjectKey,
+	        final Object optionalObject,
+	        final List hydratedObjects,
+	        final SessionImplementor session) 
+	throws HibernateException, SQLException {
+
+		final String instanceClass = getInstanceClass( 
+				rs, 
+				i, 
+				persister, 
+				key.getIdentifier(), 
+				session 
+			);
+
+		final Object object;
+		if ( optionalObjectKey != null && key.equals( optionalObjectKey ) ) {
+			//its the given optional object
+			object = optionalObject;
+		}
+		else {
+			// instantiate a new instance
+			object = session.instantiate( instanceClass, key.getIdentifier() );
+		}
+
+		//need to hydrate it.
+
+		// grab its state from the ResultSet and keep it in the Session
+		// (but don't yet initialize the object itself)
+		// note that we acquire LockMode.READ even if it was not requested
+		LockMode acquiredLockMode = lockMode == LockMode.NONE ? LockMode.READ : lockMode;
+		loadFromResultSet( 
+				rs, 
+				i, 
+				object, 
+				instanceClass, 
+				key, 
+				rowIdAlias, 
+				acquiredLockMode, 
+				persister, 
+				session 
+			);
+
+		//materialize associations (and initialize the object) later
+		hydratedObjects.add( object );
+
+		return object;
+	}
+	
+	private boolean isEagerPropertyFetchEnabled(int i) {
+		boolean[] array = getEntityEagerPropertyFetches();
+		return array!=null && array[i];
+	}
+
+
+	/**
+	 * Hydrate the state an object from the SQL <tt>ResultSet</tt>, into
+	 * an array or "hydrated" values (do not resolve associations yet),
+	 * and pass the hydrates state to the session.
+	 */
+	private void loadFromResultSet(
+	        final ResultSet rs,
+	        final int i,
+	        final Object object,
+	        final String instanceEntityName,
+	        final EntityKey key,
+	        final String rowIdAlias,
+	        final LockMode lockMode,
+	        final Loadable rootPersister,
+	        final SessionImplementor session) 
+	throws SQLException, HibernateException {
+
+		final Serializable id = key.getIdentifier();
+
+		// Get the persister for the _subclass_
+		final Loadable persister = (Loadable) getFactory().getEntityPersister( instanceEntityName );
+
+		if ( log.isTraceEnabled() ) {
+			log.trace( 
+					"Initializing object from ResultSet: " + 
+					MessageHelper.infoString( persister, id, getFactory() ) 
+				);
+		}
+		
+		boolean eagerPropertyFetch = isEagerPropertyFetchEnabled(i);
+
+		// add temp entry so that the next step is circular-reference
+		// safe - only needed because some types don't take proper
+		// advantage of two-phase-load (esp. components)
+		TwoPhaseLoad.addUninitializedEntity( 
+				key, 
+				object, 
+				persister, 
+				lockMode, 
+				!eagerPropertyFetch, 
+				session 
+			);
+
+		//This is not very nice (and quite slow):
+		final String[][] cols = persister == rootPersister ?
+				getEntityAliases()[i].getSuffixedPropertyAliases() :
+				getEntityAliases()[i].getSuffixedPropertyAliases(persister);
+
+		final Object[] values = persister.hydrate( 
+				rs, 
+				id, 
+				object, 
+				rootPersister, 
+				cols, 
+				eagerPropertyFetch, 
+				session 
+			);
+
+		final Object rowId = persister.hasRowId() ? rs.getObject(rowIdAlias) : null;
+
+		final AssociationType[] ownerAssociationTypes = getOwnerAssociationTypes();
+		if ( ownerAssociationTypes != null && ownerAssociationTypes[i] != null ) {
+			String ukName = ownerAssociationTypes[i].getRHSUniqueKeyPropertyName();
+			if (ukName!=null) {
+				final int index = ( (UniqueKeyLoadable) persister ).getPropertyIndex(ukName);
+				final Type type = persister.getPropertyTypes()[index];
+	
+				// polymorphism not really handled completely correctly,
+				// perhaps...well, actually its ok, assuming that the
+				// entity name used in the lookup is the same as the
+				// the one used here, which it will be
+	
+				EntityUniqueKey euk = new EntityUniqueKey( 
+						rootPersister.getEntityName(), //polymorphism comment above
+						ukName,
+						type.semiResolve( values[index], session, object ),
+						type,
+						session.getEntityMode(), session.getFactory()
+					);
+				session.getPersistenceContext().addEntity( euk, object );
+			}
+		}
+
+		TwoPhaseLoad.postHydrate( 
+				persister, 
+				id, 
+				values, 
+				rowId, 
+				object, 
+				lockMode, 
+				!eagerPropertyFetch, 
+				session 
+			);
+
+	}
+
+	/**
+	 * Determine the concrete class of an instance in the <tt>ResultSet</tt>
+	 */
+	private String getInstanceClass(
+	        final ResultSet rs,
+	        final int i,
+	        final Loadable persister,
+	        final Serializable id,
+	        final SessionImplementor session) 
+	throws HibernateException, SQLException {
+
+		if ( persister.hasSubclasses() ) {
+
+			// Code to handle subclasses of topClass
+			Object discriminatorValue = persister.getDiscriminatorType().nullSafeGet(
+					rs,
+					getEntityAliases()[i].getSuffixedDiscriminatorAlias(),
+					session,
+					null
+				);
+
+			final String result = persister.getSubclassForDiscriminatorValue( discriminatorValue );
+
+			if ( result == null ) {
+				//woops we got an instance of another class hierarchy branch
+				throw new WrongClassException( 
+						"Discriminator: " + discriminatorValue,
+						id,
+						persister.getEntityName() 
+					);
+			}
+
+			return result;
+
+		}
+		else {
+			return persister.getEntityName();
+		}
+	}
+
+	/**
+	 * Advance the cursor to the first required row of the <tt>ResultSet</tt>
+	 */
+	private void advance(final ResultSet rs, final RowSelection selection)
+			throws SQLException {
+
+		final int firstRow = getFirstRow( selection );
+		if ( firstRow != 0 ) {
+			if ( getFactory().getSettings().isScrollableResultSetsEnabled() ) {
+				// we can go straight to the first required row
+				rs.absolute( firstRow );
+			}
+			else {
+				// we need to step through the rows one row at a time (slow)
+				for ( int m = 0; m < firstRow; m++ ) rs.next();
+			}
+		}
+	}
+
+	private static boolean hasMaxRows(RowSelection selection) {
+		return selection != null && selection.getMaxRows() != null;
+	}
+
+	private static int getFirstRow(RowSelection selection) {
+		if ( selection == null || selection.getFirstRow() == null ) {
+			return 0;
+		}
+		else {
+			return selection.getFirstRow().intValue();
+		}
+	}
+
+	/**
+	 * Should we pre-process the SQL string, adding a dialect-specific
+	 * LIMIT clause.
+	 */
+	private static boolean useLimit(final RowSelection selection, final Dialect dialect) {
+		return dialect.supportsLimit() && hasMaxRows( selection );
+	}
+
+	/**
+	 * Obtain a <tt>PreparedStatement</tt> with all parameters pre-bound.
+	 * Bind JDBC-style <tt>?</tt> parameters, named parameters, and
+	 * limit parameters.
+	 */
+	protected final PreparedStatement prepareQueryStatement(
+	        final QueryParameters queryParameters,
+	        final boolean scroll,
+	        final SessionImplementor session) throws SQLException, HibernateException {
+
+		queryParameters.processFilters( getSQLString(), session );
+		String sql = queryParameters.getFilteredSQL();
+		final Dialect dialect = getFactory().getDialect();
+		final RowSelection selection = queryParameters.getRowSelection();
+		boolean useLimit = useLimit( selection, dialect );
+		boolean hasFirstRow = getFirstRow( selection ) > 0;
+		boolean useOffset = hasFirstRow && useLimit && dialect.supportsLimitOffset();
+		boolean callable = queryParameters.isCallable();
+		
+		boolean useScrollableResultSetToSkip = hasFirstRow &&
+				!useOffset &&
+				getFactory().getSettings().isScrollableResultSetsEnabled();
+		ScrollMode scrollMode = scroll ? queryParameters.getScrollMode() : ScrollMode.SCROLL_INSENSITIVE;
+
+		if ( useLimit ) {
+			sql = dialect.getLimitString( 
+					sql.trim(), //use of trim() here is ugly?
+					useOffset ? getFirstRow(selection) : 0, 
+					getMaxOrLimit(selection, dialect) 
+				);
+		}
+
+		sql = preprocessSQL( sql, queryParameters, dialect );
+		
+		PreparedStatement st = null;
+		
+		if (callable) {
+			st = session.getBatcher()
+				.prepareCallableQueryStatement( sql, scroll || useScrollableResultSetToSkip, scrollMode );
+		} 
+		else {
+			st = session.getBatcher()
+				.prepareQueryStatement( sql, scroll || useScrollableResultSetToSkip, scrollMode );
+		}
+				
+
+		try {
+
+			int col = 1;
+			//TODO: can we limit stored procedures ?!
+			if ( useLimit && dialect.bindLimitParametersFirst() ) {
+				col += bindLimitParameters( st, col, selection );
+			}
+			if (callable) {
+				col = dialect.registerResultSetOutParameter( (CallableStatement)st, col );
+			}
+
+			col += bindParameterValues( st, queryParameters, col, session );
+
+			if ( useLimit && !dialect.bindLimitParametersFirst() ) {
+				col += bindLimitParameters( st, col, selection );
+			}
+
+			if ( !useLimit ) {
+				setMaxRows( st, selection );
+			}
+
+			if ( selection != null ) {
+				if ( selection.getTimeout() != null ) {
+					st.setQueryTimeout( selection.getTimeout().intValue() );
+				}
+				if ( selection.getFetchSize() != null ) {
+					st.setFetchSize( selection.getFetchSize().intValue() );
+				}
+			}
+		}
+		catch ( SQLException sqle ) {
+			session.getBatcher().closeQueryStatement( st, null );
+			throw sqle;
+		}
+		catch ( HibernateException he ) {
+			session.getBatcher().closeQueryStatement( st, null );
+			throw he;
+		}
+
+		return st;
+	}
+
+	/**
+	 * Some dialect-specific LIMIT clauses require the maximium last row number
+	 * (aka, first_row_number + total_row_count), while others require the maximum
+	 * returned row count (the total maximum number of rows to return).
+	 *
+	 * @param selection The selection criteria
+	 * @param dialect The dialect
+	 * @return The appropriate value to bind into the limit clause.
+	 */
+	private static int getMaxOrLimit(final RowSelection selection, final Dialect dialect) {
+		final int firstRow = getFirstRow( selection );
+		final int lastRow = selection.getMaxRows().intValue();
+		if ( dialect.useMaxForLimit() ) {
+			return lastRow + firstRow;
+		}
+		else {
+			return lastRow;
+		}
+	}
+
+	/**
+	 * Bind parameter values needed by the dialect-specific LIMIT clause.
+	 *
+	 * @param statement The statement to which to bind limit param values.
+	 * @param index The bind position from which to start binding
+	 * @param selection The selection object containing the limit information.
+	 * @return The number of parameter values bound.
+	 * @throws java.sql.SQLException Indicates problems binding parameter values.
+	 */
+	private int bindLimitParameters(
+			final PreparedStatement statement,
+			final int index,
+			final RowSelection selection) throws SQLException {
+		Dialect dialect = getFactory().getDialect();
+		if ( !dialect.supportsVariableLimit() ) {
+			return 0;
+		}
+		if ( !hasMaxRows( selection ) ) {
+			throw new AssertionFailure( "no max results set" );
+		}
+		int firstRow = getFirstRow( selection );
+		int lastRow = getMaxOrLimit( selection, dialect );
+		boolean hasFirstRow = firstRow > 0 && dialect.supportsLimitOffset();
+		boolean reverse = dialect.bindLimitParametersInReverseOrder();
+		if ( hasFirstRow ) {
+			statement.setInt( index + ( reverse ? 1 : 0 ), firstRow );
+		}
+		statement.setInt( index + ( reverse || !hasFirstRow ? 0 : 1 ), lastRow );
+		return hasFirstRow ? 2 : 1;
+	}
+
+	/**
+	 * Use JDBC API to limit the number of rows returned by the SQL query if necessary
+	 */
+	private void setMaxRows(
+			final PreparedStatement st,
+			final RowSelection selection) throws SQLException {
+		if ( hasMaxRows( selection ) ) {
+			st.setMaxRows( selection.getMaxRows().intValue() + getFirstRow( selection ) );
+		}
+	}
+
+	/**
+	 * Bind all parameter values into the prepared statement in preparation
+	 * for execution.
+	 *
+	 * @param statement The JDBC prepared statement
+	 * @param queryParameters The encapsulation of the parameter values to be bound.
+	 * @param startIndex The position from which to start binding parameter values.
+	 * @param session The originating session.
+	 * @return The number of JDBC bind positions actually bound during this method execution.
+	 * @throws SQLException Indicates problems performing the binding.
+	 */
+	protected int bindParameterValues(
+			PreparedStatement statement,
+			QueryParameters queryParameters,
+			int startIndex,
+			SessionImplementor session) throws SQLException {
+		int span = 0;
+		span += bindPositionalParameters( statement, queryParameters, startIndex, session );
+		span += bindNamedParameters( statement, queryParameters.getNamedParameters(), startIndex + span, session );
+		return span;
+	}
+
+	/**
+	 * Bind positional parameter values to the JDBC prepared statement.
+	 * <p/>
+	 * Postional parameters are those specified by JDBC-style ? parameters
+	 * in the source query.  It is (currently) expected that these come
+	 * before any named parameters in the source query.
+	 *
+	 * @param statement The JDBC prepared statement
+	 * @param queryParameters The encapsulation of the parameter values to be bound.
+	 * @param startIndex The position from which to start binding parameter values.
+	 * @param session The originating session.
+	 * @return The number of JDBC bind positions actually bound during this method execution.
+	 * @throws SQLException Indicates problems performing the binding.
+	 * @throws org.hibernate.HibernateException Indicates problems delegating binding to the types.
+	 */
+	protected int bindPositionalParameters(
+	        final PreparedStatement statement,
+	        final QueryParameters queryParameters,
+	        final int startIndex,
+	        final SessionImplementor session) throws SQLException, HibernateException {
+		final Object[] values = queryParameters.getFilteredPositionalParameterValues();
+		final Type[] types = queryParameters.getFilteredPositionalParameterTypes();
+		int span = 0;
+		for ( int i = 0; i < values.length; i++ ) {
+			types[i].nullSafeSet( statement, values[i], startIndex + span, session );
+			span += types[i].getColumnSpan( getFactory() );
+		}
+		return span;
+	}
+
+	/**
+	 * Bind named parameters to the JDBC prepared statement.
+	 * <p/>
+	 * This is a generic implementation, the problem being that in the
+	 * general case we do not know enough information about the named
+	 * parameters to perform this in a complete manner here.  Thus this
+	 * is generally overridden on subclasses allowing named parameters to
+	 * apply the specific behavior.  The most usual limitation here is that
+	 * we need to assume the type span is always one...
+	 *
+	 * @param statement The JDBC prepared statement
+	 * @param namedParams A map of parameter names to values
+	 * @param startIndex The position from which to start binding parameter values.
+	 * @param session The originating session.
+	 * @return The number of JDBC bind positions actually bound during this method execution.
+	 * @throws SQLException Indicates problems performing the binding.
+	 * @throws org.hibernate.HibernateException Indicates problems delegating binding to the types.
+	 */
+	protected int bindNamedParameters(
+			final PreparedStatement statement,
+			final Map namedParams,
+			final int startIndex,
+			final SessionImplementor session) throws SQLException, HibernateException {
+		if ( namedParams != null ) {
+			// assumes that types are all of span 1
+			Iterator iter = namedParams.entrySet().iterator();
+			int result = 0;
+			while ( iter.hasNext() ) {
+				Map.Entry e = ( Map.Entry ) iter.next();
+				String name = ( String ) e.getKey();
+				TypedValue typedval = ( TypedValue ) e.getValue();
+				int[] locs = getNamedParameterLocs( name );
+				for ( int i = 0; i < locs.length; i++ ) {
+					if ( log.isDebugEnabled() ) {
+						log.debug(
+								"bindNamedParameters() " +
+								typedval.getValue() + " -> " + name +
+								" [" + ( locs[i] + startIndex ) + "]"
+							);
+					}
+					typedval.getType().nullSafeSet( statement, typedval.getValue(), locs[i] + startIndex, session );
+				}
+				result += locs.length;
+			}
+			return result;
+		}
+		else {
+			return 0;
+		}
+	}
+
+	public int[] getNamedParameterLocs(String name) {
+		throw new AssertionFailure("no named parameters");
+	}
+
+	/**
+	 * Fetch a <tt>PreparedStatement</tt>, call <tt>setMaxRows</tt> and then execute it,
+	 * advance to the first result and return an SQL <tt>ResultSet</tt>
+	 */
+	protected final ResultSet getResultSet(
+	        final PreparedStatement st,
+	        final boolean autodiscovertypes,
+	        final boolean callable,
+	        final RowSelection selection,
+	        final SessionImplementor session) 
+	throws SQLException, HibernateException {
+	
+		ResultSet rs = null;
+		try {
+			Dialect dialect = getFactory().getDialect();
+			if (callable) {
+				rs = session.getBatcher().getResultSet( (CallableStatement) st, dialect );
+			} 
+			else {
+				rs = session.getBatcher().getResultSet( st );
+			}
+			rs = wrapResultSetIfEnabled( rs , session );
+			
+			if ( !dialect.supportsLimitOffset() || !useLimit( selection, dialect ) ) {
+				advance( rs, selection );
+			}
+			
+			if ( autodiscovertypes ) {
+				autoDiscoverTypes( rs );
+			}
+			return rs;
+		}
+		catch ( SQLException sqle ) {
+			session.getBatcher().closeQueryStatement( st, rs );
+			throw sqle;
+		}
+	}
+
+	protected void autoDiscoverTypes(ResultSet rs) {
+		throw new AssertionFailure("Auto discover types not supported in this loader");
+		
+	}
+
+	private synchronized ResultSet wrapResultSetIfEnabled(final ResultSet rs, final SessionImplementor session) {
+		// synchronized to avoid multi-thread access issues; defined as method synch to avoid
+		// potential deadlock issues due to nature of code.
+		if ( session.getFactory().getSettings().isWrapResultSetsEnabled() ) {
+			try {
+				log.debug("Wrapping result set [" + rs + "]");
+				return new ResultSetWrapper( rs, retreiveColumnNameToIndexCache( rs ) );
+			}
+			catch(SQLException e) {
+				log.info("Error wrapping result set", e);
+				return rs;
+			}
+		}
+		else {
+			return rs;
+		}
+	}
+
+	private ColumnNameCache retreiveColumnNameToIndexCache(ResultSet rs) throws SQLException {
+		if ( columnNameCache == null ) {
+			log.trace("Building columnName->columnIndex cache");
+			columnNameCache = new ColumnNameCache( rs.getMetaData().getColumnCount() );
+		}
+
+		return columnNameCache;
+	}
+
+	/**
+	 * Called by subclasses that load entities
+	 * @param persister only needed for logging
+	 */
+	protected final List loadEntity(
+	        final SessionImplementor session,
+	        final Object id,
+	        final Type identifierType,
+	        final Object optionalObject,
+	        final String optionalEntityName,
+	        final Serializable optionalIdentifier,
+	        final EntityPersister persister) throws HibernateException {
+		
+		if ( log.isDebugEnabled() ) {
+			log.debug( 
+					"loading entity: " + 
+					MessageHelper.infoString( persister, id, identifierType, getFactory() ) 
+				);
+		}
+
+		List result;
+		try {
+			result = doQueryAndInitializeNonLazyCollections( 
+					session,
+					new QueryParameters( 
+							new Type[] { identifierType },
+							new Object[] { id },
+							optionalObject,
+							optionalEntityName,
+							optionalIdentifier 
+						),
+					false 
+				);
+		}
+		catch ( SQLException sqle ) {
+			final Loadable[] persisters = getEntityPersisters();
+			throw JDBCExceptionHelper.convert(
+			        factory.getSQLExceptionConverter(),
+			        sqle,
+			        "could not load an entity: " + 
+			        MessageHelper.infoString( persisters[persisters.length-1], id, identifierType, getFactory() ),
+			        getSQLString()
+				);
+		}
+
+		log.debug("done entity load");
+		
+		return result;
+		
+	}
+
+	/**
+	 * Called by subclasses that load entities
+	 * @param persister only needed for logging
+	 */
+	protected final List loadEntity(
+	        final SessionImplementor session,
+	        final Object key,
+	        final Object index,
+	        final Type keyType,
+	        final Type indexType,
+	        final EntityPersister persister) throws HibernateException {
+		
+		if ( log.isDebugEnabled() ) {
+			log.debug( "loading collection element by index" );
+		}
+
+		List result;
+		try {
+			result = doQueryAndInitializeNonLazyCollections( 
+					session,
+					new QueryParameters( 
+							new Type[] { keyType, indexType },
+							new Object[] { key, index }
+						),
+					false 
+				);
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+			        factory.getSQLExceptionConverter(),
+			        sqle,
+			        "could not collection element by index",
+			        getSQLString()
+				);
+		}
+
+		log.debug("done entity load");
+		
+		return result;
+		
+	}
+
+	/**
+	 * Called by wrappers that batch load entities
+	 * @param persister only needed for logging
+	 */
+	public final List loadEntityBatch(
+	        final SessionImplementor session,
+	        final Serializable[] ids,
+	        final Type idType,
+	        final Object optionalObject,
+	        final String optionalEntityName,
+	        final Serializable optionalId,
+	        final EntityPersister persister) throws HibernateException {
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( 
+					"batch loading entity: " + 
+					MessageHelper.infoString(persister, ids, getFactory() ) 
+				);
+		}
+
+		Type[] types = new Type[ids.length];
+		Arrays.fill( types, idType );
+		List result;
+		try {
+			result = doQueryAndInitializeNonLazyCollections( 
+					session,
+					new QueryParameters( types, ids, optionalObject, optionalEntityName, optionalId ),
+					false 
+				);
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+			        factory.getSQLExceptionConverter(),
+			        sqle,
+			        "could not load an entity batch: " + 
+			        MessageHelper.infoString( getEntityPersisters()[0], ids, getFactory() ),
+			        getSQLString()
+				);
+		}
+
+		log.debug("done entity batch load");
+		
+		return result;
+
+	}
+
+	/**
+	 * Called by subclasses that initialize collections
+	 */
+	public final void loadCollection(
+	        final SessionImplementor session,
+	        final Serializable id,
+	        final Type type) throws HibernateException {
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( 
+					"loading collection: "+ 
+					MessageHelper.collectionInfoString( getCollectionPersisters()[0], id, getFactory() )
+				);
+		}
+
+		Serializable[] ids = new Serializable[]{id};
+		try {
+			doQueryAndInitializeNonLazyCollections( 
+					session,
+					new QueryParameters( new Type[]{type}, ids, ids ),
+					true 
+				);
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					factory.getSQLExceptionConverter(),
+					sqle,
+					"could not initialize a collection: " + 
+					MessageHelper.collectionInfoString( getCollectionPersisters()[0], id, getFactory() ),
+					getSQLString()
+				);
+		}
+	
+		log.debug("done loading collection");
+
+	}
+
+	/**
+	 * Called by wrappers that batch initialize collections
+	 */
+	public final void loadCollectionBatch(
+	        final SessionImplementor session,
+	        final Serializable[] ids,
+	        final Type type) throws HibernateException {
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( 
+					"batch loading collection: "+ 
+					MessageHelper.collectionInfoString( getCollectionPersisters()[0], ids, getFactory() )
+				);
+		}
+
+		Type[] idTypes = new Type[ids.length];
+		Arrays.fill( idTypes, type );
+		try {
+			doQueryAndInitializeNonLazyCollections( 
+					session,
+					new QueryParameters( idTypes, ids, ids ),
+					true 
+				);
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+			        factory.getSQLExceptionConverter(),
+			        sqle,
+			        "could not initialize a collection batch: " + 
+			        MessageHelper.collectionInfoString( getCollectionPersisters()[0], ids, getFactory() ),
+			        getSQLString()
+				);
+		}
+		
+		log.debug("done batch load");
+
+	}
+
+	/**
+	 * Called by subclasses that batch initialize collections
+	 */
+	protected final void loadCollectionSubselect(
+	        final SessionImplementor session,
+	        final Serializable[] ids,
+	        final Object[] parameterValues,
+	        final Type[] parameterTypes,
+	        final Map namedParameters,
+	        final Type type) throws HibernateException {
+
+		Type[] idTypes = new Type[ids.length];
+		Arrays.fill( idTypes, type );
+		try {
+			doQueryAndInitializeNonLazyCollections( session,
+					new QueryParameters( parameterTypes, parameterValues, namedParameters, ids ),
+					true 
+				);
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+			        factory.getSQLExceptionConverter(),
+			        sqle,
+			        "could not load collection by subselect: " + 
+			        MessageHelper.collectionInfoString( getCollectionPersisters()[0], ids, getFactory() ),
+			        getSQLString()
+				);
+		}
+	}
+
+	/**
+	 * Return the query results, using the query cache, called
+	 * by subclasses that implement cacheable queries
+	 */
+	protected List list(
+	        final SessionImplementor session,
+	        final QueryParameters queryParameters,
+	        final Set querySpaces,
+	        final Type[] resultTypes) throws HibernateException {
+
+		final boolean cacheable = factory.getSettings().isQueryCacheEnabled() && 
+			queryParameters.isCacheable();
+
+		if ( cacheable ) {
+			return listUsingQueryCache( session, queryParameters, querySpaces, resultTypes );
+		}
+		else {
+			return listIgnoreQueryCache( session, queryParameters );
+		}
+	}
+
+	private List listIgnoreQueryCache(SessionImplementor session, QueryParameters queryParameters) {
+		return getResultList( doList( session, queryParameters ), queryParameters.getResultTransformer() );
+	}
+
+	private List listUsingQueryCache(
+			final SessionImplementor session, 
+			final QueryParameters queryParameters, 
+			final Set querySpaces, 
+			final Type[] resultTypes) {
+	
+		QueryCache queryCache = factory.getQueryCache( queryParameters.getCacheRegion() );
+		
+		Set filterKeys = FilterKey.createFilterKeys( 
+				session.getEnabledFilters(), 
+				session.getEntityMode() 
+			);
+		QueryKey key = new QueryKey( 
+				getSQLString(), 
+				queryParameters, 
+				filterKeys, 
+				session.getEntityMode() 
+			);
+		
+		List result = getResultFromQueryCache( 
+				session, 
+				queryParameters, 
+				querySpaces, 
+				resultTypes, 
+				queryCache, 
+				key 
+			);
+
+		if ( result == null ) {
+			result = doList( session, queryParameters );
+
+			putResultInQueryCache( 
+					session, 
+					queryParameters, 
+					resultTypes,
+					queryCache, 
+					key, 
+					result 
+				);
+		}
+
+		return getResultList( result, queryParameters.getResultTransformer() );
+	}
+
+	private List getResultFromQueryCache(
+			final SessionImplementor session, 
+			final QueryParameters queryParameters, 
+			final Set querySpaces, 
+			final Type[] resultTypes,
+			final QueryCache queryCache, 
+			final QueryKey key) {
+		List result = null;
+		
+		if ( session.getCacheMode().isGetEnabled() ) {
+			result = queryCache.get( 
+					key, 
+					resultTypes, 
+					queryParameters.isNaturalKeyLookup(), 
+					querySpaces, 
+					session 
+			);
+
+			if ( factory.getStatistics().isStatisticsEnabled() ) {
+				if ( result == null ) {
+					factory.getStatisticsImplementor()
+							.queryCacheMiss( getQueryIdentifier(), queryCache.getRegion().getName() );
+				}
+				else {
+					factory.getStatisticsImplementor()
+							.queryCacheHit( getQueryIdentifier(), queryCache.getRegion().getName() );
+				}
+			}
+			
+		}
+		
+		return result;
+	}
+
+	private void putResultInQueryCache(
+			final SessionImplementor session, 
+			final QueryParameters queryParameters, 
+			final Type[] resultTypes,
+			final QueryCache queryCache, 
+			final QueryKey key, 
+			final List result) {
+		
+		if ( session.getCacheMode().isPutEnabled() ) {
+			boolean put = queryCache.put(
+					key, 
+					resultTypes, 
+					result, 
+					queryParameters.isNaturalKeyLookup(), 
+					session 
+			);
+			if ( put && factory.getStatistics().isStatisticsEnabled() ) {
+				factory.getStatisticsImplementor()
+						.queryCachePut( getQueryIdentifier(), queryCache.getRegion().getName() );
+			}
+		}
+	}
+
+	/**
+	 * Actually execute a query, ignoring the query cache
+	 */
+	protected List doList(final SessionImplementor session, final QueryParameters queryParameters)
+			throws HibernateException {
+
+		final boolean stats = getFactory().getStatistics().isStatisticsEnabled();
+		long startTime = 0;
+		if ( stats ) startTime = System.currentTimeMillis();
+
+		List result;
+		try {
+			result = doQueryAndInitializeNonLazyCollections( session, queryParameters, true );
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+			        factory.getSQLExceptionConverter(),
+			        sqle,
+			        "could not execute query",
+			        getSQLString()
+				);
+		}
+
+		if ( stats ) {
+			getFactory().getStatisticsImplementor().queryExecuted(
+					getQueryIdentifier(),
+					result.size(),
+					System.currentTimeMillis() - startTime
+				);
+		}
+
+		return result;
+	}
+
+	/**
+	 * Check whether the current loader can support returning ScrollableResults.
+	 *
+	 * @throws HibernateException
+	 */
+	protected void checkScrollability() throws HibernateException {
+		// Allows various loaders (ok mainly the QueryLoader :) to check
+		// whether scrolling of their result set should be allowed.
+		//
+		// By default it is allowed.
+		return;
+	}
+
+	/**
+	 * Does the result set to be scrolled contain collection fetches?
+	 *
+	 * @return True if it does, and thus needs the special fetching scroll
+	 * functionality; false otherwise.
+	 */
+	protected boolean needsFetchingScroll() {
+		return false;
+	}
+
+	/**
+	 * Return the query results, as an instance of <tt>ScrollableResults</tt>
+	 *
+	 * @param queryParameters The parameters with which the query should be executed.
+	 * @param returnTypes The expected return types of the query
+	 * @param holderInstantiator If the return values are expected to be wrapped
+	 * in a holder, this is the thing that knows how to wrap them.
+	 * @param session The session from which the scroll request originated.
+	 * @return The ScrollableResults instance.
+	 * @throws HibernateException Indicates an error executing the query, or constructing
+	 * the ScrollableResults.
+	 */
+	protected ScrollableResults scroll(
+	        final QueryParameters queryParameters,
+	        final Type[] returnTypes,
+	        final HolderInstantiator holderInstantiator,
+	        final SessionImplementor session) throws HibernateException {
+
+		checkScrollability();
+
+		final boolean stats = getQueryIdentifier() != null &&
+				getFactory().getStatistics().isStatisticsEnabled();
+		long startTime = 0;
+		if ( stats ) startTime = System.currentTimeMillis();
+
+		try {
+
+			PreparedStatement st = prepareQueryStatement( queryParameters, true, session );
+			ResultSet rs = getResultSet(st, queryParameters.hasAutoDiscoverScalarTypes(), queryParameters.isCallable(), queryParameters.getRowSelection(), session);
+
+			if ( stats ) {
+				getFactory().getStatisticsImplementor().queryExecuted(
+						getQueryIdentifier(),
+						0,
+						System.currentTimeMillis() - startTime
+					);
+			}
+
+			if ( needsFetchingScroll() ) {
+				return new FetchingScrollableResultsImpl(
+						rs,
+						st,
+						session,
+						this,
+						queryParameters,
+						returnTypes,
+						holderInstantiator
+					);
+			}
+			else {
+				return new ScrollableResultsImpl(
+						rs,
+						st,
+						session,
+						this,
+						queryParameters,
+						returnTypes,
+						holderInstantiator
+					);
+			}
+
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+			        factory.getSQLExceptionConverter(),
+			        sqle,
+			        "could not execute query using scroll",
+			        getSQLString()
+				);
+		}
+
+	}
+
+	/**
+	 * Calculate and cache select-clause suffixes. Must be
+	 * called by subclasses after instantiation.
+	 */
+	protected void postInstantiate() {}
+
+	/**
+	 * Get the result set descriptor
+	 */
+	protected abstract EntityAliases[] getEntityAliases();
+
+	protected abstract CollectionAliases[] getCollectionAliases();
+
+	/**
+	 * Identifies the query for statistics reporting, if null,
+	 * no statistics will be reported
+	 */
+	protected String getQueryIdentifier() {
+		return null;
+	}
+
+	public final SessionFactoryImplementor getFactory() {
+		return factory;
+	}
+
+	public String toString() {
+		return getClass().getName() + '(' + getSQLString() + ')';
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/OuterJoinLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/OuterJoinLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/OuterJoinLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,102 @@
+//$Id: OuterJoinLoader.java 7124 2005-06-13 20:27:16Z oneovthafew $
+package org.hibernate.loader;
+
+import java.util.Map;
+
+import org.hibernate.LockMode;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.type.EntityType;
+
+/**
+ * Implements logic for walking a tree of associated classes.
+ *
+ * Generates an SQL select string containing all properties of those classes.
+ * Tables are joined using an ANSI-style left outer join.
+ *
+ * @author Gavin King
+ */
+public abstract class OuterJoinLoader extends BasicLoader {
+
+	protected Loadable[] persisters;
+	protected CollectionPersister[] collectionPersisters;
+	protected int[] collectionOwners;
+	protected String[] aliases;
+	protected LockMode[] lockModeArray;
+	protected int[] owners;
+	protected EntityType[] ownerAssociationTypes;
+	protected String sql;
+	protected String[] suffixes;
+	protected String[] collectionSuffixes;
+
+    private Map enabledFilters;
+    
+    protected final Dialect getDialect() {
+    	return getFactory().getDialect();
+    }
+
+	public OuterJoinLoader(SessionFactoryImplementor factory, Map enabledFilters) {
+		super(factory);
+		this.enabledFilters = enabledFilters;
+	}
+
+	protected String[] getSuffixes() {
+		return suffixes;
+	}
+
+	protected String[] getCollectionSuffixes() {
+		return collectionSuffixes;
+	}
+
+	protected final String getSQLString() {
+		return sql;
+	}
+
+	protected final Loadable[] getEntityPersisters() {
+		return persisters;
+	}
+
+	protected int[] getOwners() {
+		return owners;
+	}
+
+	protected EntityType[] getOwnerAssociationTypes() {
+		return ownerAssociationTypes;
+	}
+
+	protected LockMode[] getLockModes(Map lockModes) {
+		return lockModeArray;
+	}
+	
+	public Map getEnabledFilters() {
+		return enabledFilters;
+	}
+
+	protected final String[] getAliases() {
+		return aliases;
+	}
+
+	protected final CollectionPersister[] getCollectionPersisters() {
+		return collectionPersisters;
+	}
+
+	protected final int[] getCollectionOwners() {
+		return collectionOwners;
+	}
+
+	protected void initFromWalker(JoinWalker walker) {
+		persisters = walker.getPersisters();
+		collectionPersisters = walker.getCollectionPersisters();
+		ownerAssociationTypes = walker.getOwnerAssociationTypes();
+		lockModeArray = walker.getLockModeArray();
+		suffixes = walker.getSuffixes();
+		collectionSuffixes = walker.getCollectionSuffixes();
+		owners = walker.getOwners();
+		collectionOwners = walker.getCollectionOwners();
+		sql = walker.getSQLString();
+		aliases = walker.getAliases();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/OuterJoinableAssociation.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/OuterJoinableAssociation.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/OuterJoinableAssociation.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,163 @@
+//$Id: OuterJoinableAssociation.java 6828 2005-05-19 07:28:59Z steveebersole $
+package org.hibernate.loader;
+
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.MappingException;
+import org.hibernate.engine.JoinHelper;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.EntityType;
+
+public final class OuterJoinableAssociation {
+	private final AssociationType joinableType;
+	private final Joinable joinable;
+	private final String lhsAlias; // belong to other persister
+	private final String[] lhsColumns; // belong to other persister
+	private final String rhsAlias;
+	private final String[] rhsColumns;
+	private final int joinType;
+	private final String on;
+	private final Map enabledFilters;
+
+	public OuterJoinableAssociation(
+		AssociationType joinableType,
+		String lhsAlias,
+		String[] lhsColumns,
+		String rhsAlias,
+		int joinType,
+		SessionFactoryImplementor factory,
+		Map enabledFilters)
+	throws MappingException {
+		this.joinableType = joinableType;
+		this.lhsAlias = lhsAlias;
+		this.lhsColumns = lhsColumns;
+		this.rhsAlias = rhsAlias;
+		this.joinType = joinType;
+		this.joinable = joinableType.getAssociatedJoinable(factory);
+		this.rhsColumns = JoinHelper.getRHSColumnNames(joinableType, factory);
+		this.on = joinableType.getOnCondition(rhsAlias, factory, enabledFilters);
+		this.enabledFilters = enabledFilters; // needed later for many-to-many/filter application
+	}
+
+	public int getJoinType() {
+		return joinType;
+	}
+
+	public String getRHSAlias() {
+		return rhsAlias;
+	}
+
+	private boolean isOneToOne() {
+		if ( joinableType.isEntityType() )  {
+			EntityType etype = (EntityType) joinableType;
+			return etype.isOneToOne() /*&& etype.isReferenceToPrimaryKey()*/;
+		}
+		else {
+			return false;
+		}
+			
+	}
+	
+	public AssociationType getJoinableType() {
+		return joinableType;
+	}
+	
+	public String getRHSUniqueKeyName() {
+		return joinableType.getRHSUniqueKeyPropertyName();
+	}
+
+	public boolean isCollection() {
+		return joinableType.isCollectionType();
+	}
+
+	public Joinable getJoinable() {
+		return joinable;
+	}
+
+	public int getOwner(final List associations) {
+		if ( isOneToOne() || isCollection() ) {
+			return getPosition(lhsAlias, associations);
+		}
+		else {
+			return -1;
+		}
+	}
+
+	/**
+	 * Get the position of the join with the given alias in the
+	 * list of joins
+	 */
+	private static int getPosition(String lhsAlias, List associations) {
+		int result = 0;
+		for ( int i=0; i<associations.size(); i++ ) {
+			OuterJoinableAssociation oj = (OuterJoinableAssociation) associations.get(i);
+			if ( oj.getJoinable().consumesEntityAlias() /*|| oj.getJoinable().consumesCollectionAlias() */ ) {
+				if ( oj.rhsAlias.equals(lhsAlias) ) return result;
+				result++;
+			}
+		}
+		return -1;
+	}
+
+	public void addJoins(JoinFragment outerjoin) throws MappingException {
+		outerjoin.addJoin(
+			joinable.getTableName(),
+			rhsAlias,
+			lhsColumns,
+			rhsColumns,
+			joinType,
+			on
+		);
+		outerjoin.addJoins(
+			joinable.fromJoinFragment(rhsAlias, false, true),
+			joinable.whereJoinFragment(rhsAlias, false, true)
+		);
+	}
+
+	public void validateJoin(String path) throws MappingException {
+		if (
+			rhsColumns==null || 
+			lhsColumns==null ||
+			lhsColumns.length!=rhsColumns.length ||
+			lhsColumns.length==0
+		) {
+			throw new MappingException("invalid join columns for association: " + path);
+		}
+	}
+
+	public boolean isManyToManyWith(OuterJoinableAssociation other) {
+		if ( joinable.isCollection() ) {
+			QueryableCollection persister = ( QueryableCollection ) joinable;
+			if ( persister.isManyToMany() ) {
+				return persister.getElementType() == other.getJoinableType();
+			}
+		}
+		return false;
+	}
+
+	public void addManyToManyJoin(JoinFragment outerjoin, QueryableCollection collection) throws MappingException {
+		String manyToManyFilter = collection.getManyToManyFilterFragment( rhsAlias, enabledFilters );
+		String condition = "".equals( manyToManyFilter )
+				? on
+				: "".equals( on )
+						? manyToManyFilter
+						: on + " and " + manyToManyFilter;
+		outerjoin.addJoin(
+		        joinable.getTableName(),
+		        rhsAlias,
+		        lhsColumns,
+		        rhsColumns,
+		        joinType,
+		        condition
+		);
+		outerjoin.addJoins(
+			joinable.fromJoinFragment(rhsAlias, false, true),
+			joinable.whereJoinFragment(rhsAlias, false, true)
+		);
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/BasicCollectionJoinWalker.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/BasicCollectionJoinWalker.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/BasicCollectionJoinWalker.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,167 @@
+//$Id: BasicCollectionJoinWalker.java 9875 2006-05-04 16:23:44Z steve.ebersole at jboss.com $
+package org.hibernate.loader.collection;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.FetchMode;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.loader.BasicLoader;
+import org.hibernate.loader.OuterJoinableAssociation;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.sql.Select;
+import org.hibernate.type.AssociationType;
+import org.hibernate.util.CollectionHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Walker for collections of values and many-to-many associations
+ * 
+ * @see BasicCollectionLoader
+ * @author Gavin King
+ */
+public class BasicCollectionJoinWalker extends CollectionJoinWalker {
+	
+	private final QueryableCollection collectionPersister;
+
+	public BasicCollectionJoinWalker(
+			QueryableCollection collectionPersister, 
+			int batchSize, 
+			String subquery, 
+			SessionFactoryImplementor factory, 
+			Map enabledFilters)
+	throws MappingException {
+
+		super(factory, enabledFilters);
+
+		this.collectionPersister = collectionPersister;
+
+		String alias = generateRootAlias( collectionPersister.getRole() );
+
+		walkCollectionTree(collectionPersister, alias);
+
+		List allAssociations = new ArrayList();
+		allAssociations.addAll(associations);
+		allAssociations.add( new OuterJoinableAssociation( 
+				collectionPersister.getCollectionType(),
+				null, 
+				null, 
+				alias, 
+				JoinFragment.LEFT_OUTER_JOIN, 
+				getFactory(), 
+				CollectionHelper.EMPTY_MAP 
+			) );
+
+		initPersisters(allAssociations, LockMode.NONE);
+		initStatementString(alias, batchSize, subquery);
+
+	}
+
+	private void initStatementString(
+		final String alias,
+		final int batchSize,
+		final String subquery)
+	throws MappingException {
+
+		final int joins = countEntityPersisters( associations );
+		final int collectionJoins = countCollectionPersisters( associations ) + 1;
+
+		suffixes = BasicLoader.generateSuffixes( joins );
+		collectionSuffixes = BasicLoader.generateSuffixes( joins, collectionJoins );
+
+		StringBuffer whereString = whereString(
+				alias, 
+				collectionPersister.getKeyColumnNames(), 
+				subquery,
+				batchSize
+			);
+
+		String manyToManyOrderBy = "";
+		String filter = collectionPersister.filterFragment( alias, getEnabledFilters() );
+		if ( collectionPersister.isManyToMany() ) {
+			// from the collection of associations, locate OJA for the
+			// ManyToOne corresponding to this persister to fully
+			// define the many-to-many; we need that OJA so that we can
+			// use its alias here
+			// TODO : is there a better way here?
+			Iterator itr = associations.iterator();
+			AssociationType associationType = ( AssociationType ) collectionPersister.getElementType();
+			while ( itr.hasNext() ) {
+				OuterJoinableAssociation oja = ( OuterJoinableAssociation ) itr.next();
+				if ( oja.getJoinableType() == associationType ) {
+					// we found it
+					filter += collectionPersister.getManyToManyFilterFragment( 
+							oja.getRHSAlias(), 
+							getEnabledFilters() 
+						);
+						manyToManyOrderBy += collectionPersister.getManyToManyOrderByString( oja.getRHSAlias() );
+				}
+			}
+		}
+		whereString.insert( 0, StringHelper.moveAndToBeginning( filter ) );
+
+		JoinFragment ojf = mergeOuterJoins(associations);
+		Select select = new Select( getDialect() )
+			.setSelectClause(
+				collectionPersister.selectFragment(alias, collectionSuffixes[0] ) +
+				selectString(associations)
+			)
+			.setFromClause( collectionPersister.getTableName(), alias )
+			.setWhereClause( whereString.toString()	)
+			.setOuterJoins(
+				ojf.toFromFragmentString(),
+				ojf.toWhereFragmentString()
+			);
+
+		select.setOrderByClause( orderBy( associations, mergeOrderings( collectionPersister.getSQLOrderByString(alias), manyToManyOrderBy ) ) );
+
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			select.setComment( "load collection " + collectionPersister.getRole() );
+		}
+
+		sql = select.toStatementString();
+	}
+
+	/**
+	 * We can use an inner join for first many-to-many association
+	 */
+	protected int getJoinType(
+			AssociationType type, 
+			FetchMode config, 
+			String path, 
+			Set visitedAssociations,
+			String lhsTable,
+			String[] lhsColumns,
+			boolean nullable,
+			int currentDepth)
+	throws MappingException {
+
+		int joinType = super.getJoinType(
+				type, 
+				config, 
+				path, 
+				lhsTable, 
+				lhsColumns, 
+				nullable, 
+				currentDepth,
+				null
+			);
+		//we can use an inner join for the many-to-many
+		if ( joinType==JoinFragment.LEFT_OUTER_JOIN && "".equals(path) ) {
+			joinType=JoinFragment.INNER_JOIN;
+		}
+		return joinType;
+	}
+	
+	public String toString() {
+		return getClass().getName() + '(' + collectionPersister.getRole() + ')';
+	}
+
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/BasicCollectionJoinWalker.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/BasicCollectionLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/BasicCollectionLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/BasicCollectionLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+//$Id: BasicCollectionLoader.java 7123 2005-06-13 20:10:20Z oneovthafew $
+package org.hibernate.loader.collection;
+
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.MappingException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.loader.JoinWalker;
+import org.hibernate.persister.collection.QueryableCollection;
+
+/**
+ * Loads a collection of values or a many-to-many association.
+ * <br>
+ * The collection persister must implement <tt>QueryableCOllection<tt>. For
+ * other collections, create a customized subclass of <tt>Loader</tt>.
+ *
+ * @see OneToManyLoader
+ * @author Gavin King
+ */
+public class BasicCollectionLoader extends CollectionLoader {
+
+	private static final Log log = LogFactory.getLog(BasicCollectionLoader.class);
+
+	public BasicCollectionLoader(
+			QueryableCollection collectionPersister, 
+			SessionFactoryImplementor session, 
+			Map enabledFilters)
+	throws MappingException {
+		this(collectionPersister, 1, session, enabledFilters);
+	}
+
+	public BasicCollectionLoader(
+			QueryableCollection collectionPersister, 
+			int batchSize, 
+			SessionFactoryImplementor factory, 
+			Map enabledFilters)
+	throws MappingException {
+		this(collectionPersister, batchSize, null, factory, enabledFilters);
+	}
+	
+	protected BasicCollectionLoader(
+			QueryableCollection collectionPersister, 
+			int batchSize, 
+			String subquery, 
+			SessionFactoryImplementor factory, 
+			Map enabledFilters)
+	throws MappingException {
+		
+		super(collectionPersister, factory, enabledFilters);
+		
+		JoinWalker walker = new BasicCollectionJoinWalker(
+				collectionPersister, 
+				batchSize, 
+				subquery, 
+				factory, 
+				enabledFilters
+			);
+		initFromWalker( walker );
+
+		postInstantiate();
+
+		log.debug( "Static select for collection " + collectionPersister.getRole() + ": " + getSQLString() );
+	}
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/BatchingCollectionInitializer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/BatchingCollectionInitializer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/BatchingCollectionInitializer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,96 @@
+//$Id: BatchingCollectionInitializer.java 7123 2005-06-13 20:10:20Z oneovthafew $
+package org.hibernate.loader.collection;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.loader.Loader;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * "Batch" loads collections, using multiple foreign key values in the
+ * SQL <tt>where</tt> clause.
+ *
+ * @see BasicCollectionLoader
+ * @see OneToManyLoader
+ * @author Gavin King
+ */
+public class BatchingCollectionInitializer implements CollectionInitializer {
+
+	private final Loader[] loaders;
+	private final int[] batchSizes;
+	private final CollectionPersister collectionPersister;
+
+	public BatchingCollectionInitializer(CollectionPersister collPersister, int[] batchSizes, Loader[] loaders) {
+		this.loaders = loaders;
+		this.batchSizes = batchSizes;
+		this.collectionPersister = collPersister;
+	}
+
+	public void initialize(Serializable id, SessionImplementor session)
+	throws HibernateException {
+		
+		Serializable[] batch = session.getPersistenceContext().getBatchFetchQueue()
+			.getCollectionBatch( collectionPersister, id, batchSizes[0], session.getEntityMode() );
+		
+		for ( int i=0; i<batchSizes.length-1; i++) {
+			final int smallBatchSize = batchSizes[i];
+			if ( batch[smallBatchSize-1]!=null ) {
+				Serializable[] smallBatch = new Serializable[smallBatchSize];
+				System.arraycopy(batch, 0, smallBatch, 0, smallBatchSize);
+				loaders[i].loadCollectionBatch( session, smallBatch, collectionPersister.getKeyType() );
+				return; //EARLY EXIT!
+			}
+		}
+		
+		loaders[batchSizes.length-1].loadCollection( session, id, collectionPersister.getKeyType() );
+
+	}
+
+	public static CollectionInitializer createBatchingOneToManyInitializer(
+		final QueryableCollection persister,
+		final int maxBatchSize,
+		final SessionFactoryImplementor factory,
+		final Map enabledFilters)
+	throws MappingException {
+
+		if ( maxBatchSize>1 ) {
+			int[] batchSizesToCreate = ArrayHelper.getBatchSizes(maxBatchSize);
+			Loader[] loadersToCreate = new Loader[ batchSizesToCreate.length ];
+			for ( int i=0; i<batchSizesToCreate.length; i++ ) {
+				loadersToCreate[i] = new OneToManyLoader(persister, batchSizesToCreate[i], factory, enabledFilters);
+			}
+			return new BatchingCollectionInitializer(persister, batchSizesToCreate, loadersToCreate);
+		}
+		else {
+			return new OneToManyLoader(persister, factory, enabledFilters);
+		}
+	}
+
+	public static CollectionInitializer createBatchingCollectionInitializer(
+		final QueryableCollection persister,
+		final int maxBatchSize,
+		final SessionFactoryImplementor factory,
+		final Map enabledFilters)
+	throws MappingException {
+
+		if ( maxBatchSize>1 ) {
+			int[] batchSizesToCreate = ArrayHelper.getBatchSizes(maxBatchSize);
+			Loader[] loadersToCreate = new Loader[ batchSizesToCreate.length ];
+			for ( int i=0; i<batchSizesToCreate.length; i++ ) {
+				loadersToCreate[i] = new BasicCollectionLoader(persister, batchSizesToCreate[i], factory, enabledFilters);
+			}
+			return new BatchingCollectionInitializer(persister, batchSizesToCreate, loadersToCreate);
+		}
+		else {
+			return new BasicCollectionLoader(persister, factory, enabledFilters);
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/CollectionInitializer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/CollectionInitializer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/CollectionInitializer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: CollectionInitializer.java 7123 2005-06-13 20:10:20Z oneovthafew $
+package org.hibernate.loader.collection;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * An interface for collection loaders
+ * @see BasicCollectionLoader
+ * @see OneToManyLoader
+ * @author Gavin King
+ */
+public interface CollectionInitializer {
+	/**
+	 * Initialize the given collection
+	 */
+	public void initialize(Serializable id, SessionImplementor session) throws HibernateException;
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/CollectionJoinWalker.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/CollectionJoinWalker.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/CollectionJoinWalker.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+//$Id: CollectionJoinWalker.java 7627 2005-07-24 06:53:06Z oneovthafew $
+package org.hibernate.loader.collection;
+
+import java.util.Map;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.loader.JoinWalker;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Superclass of walkers for collection initializers
+ * 
+ * @see CollectionLoader
+ * @see OneToManyJoinWalker
+ * @see BasicCollectionJoinWalker
+ * @author Gavin King
+ */
+public abstract class CollectionJoinWalker extends JoinWalker {
+	
+	public CollectionJoinWalker(SessionFactoryImplementor factory, Map enabledFilters) {
+		super( factory, enabledFilters );
+	}
+
+	protected StringBuffer whereString(String alias, String[] columnNames, String subselect, int batchSize) {
+		if (subselect==null) {
+			return super.whereString(alias, columnNames, batchSize);
+		}
+		else {
+			StringBuffer buf = new StringBuffer();
+			if (columnNames.length>1) buf.append('(');
+			buf.append( StringHelper.join(", ", StringHelper.qualify(alias, columnNames) ) );
+			if (columnNames.length>1) buf.append(')');
+			buf.append(" in ")
+				.append('(')
+				.append(subselect) 
+				.append(')');
+			return buf;
+		}
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/CollectionJoinWalker.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/CollectionLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/CollectionLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/CollectionLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+//$Id: CollectionLoader.java 7124 2005-06-13 20:27:16Z oneovthafew $
+package org.hibernate.loader.collection;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.loader.OuterJoinLoader;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.type.Type;
+
+/**
+ * Superclass for loaders that initialize collections
+ * 
+ * @see OneToManyLoader
+ * @see BasicCollectionLoader
+ * @author Gavin King
+ */
+public class CollectionLoader extends OuterJoinLoader implements CollectionInitializer {
+
+	private final QueryableCollection collectionPersister;
+
+	public CollectionLoader(QueryableCollection collectionPersister, SessionFactoryImplementor factory, Map enabledFilters) {
+		super( factory, enabledFilters );
+		this.collectionPersister = collectionPersister;
+	}
+
+	protected boolean isSubselectLoadingEnabled() {
+		return hasSubselectLoadableCollections();
+	}
+
+	public void initialize(Serializable id, SessionImplementor session)
+	throws HibernateException {
+		loadCollection( session, id, getKeyType() );
+	}
+
+	protected Type getKeyType() {
+		return collectionPersister.getKeyType();
+	}
+
+	public String toString() {
+		return getClass().getName() + '(' + collectionPersister.getRole() + ')';
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/OneToManyJoinWalker.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/OneToManyJoinWalker.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/OneToManyJoinWalker.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,128 @@
+//$Id: OneToManyJoinWalker.java 7627 2005-07-24 06:53:06Z oneovthafew $
+package org.hibernate.loader.collection;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.loader.BasicLoader;
+import org.hibernate.loader.OuterJoinableAssociation;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.sql.Select;
+import org.hibernate.util.CollectionHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Walker for one-to-many associations
+ *
+ * @see OneToManyLoader
+ * @author Gavin King
+ */
+public class OneToManyJoinWalker extends CollectionJoinWalker {
+
+	private final QueryableCollection oneToManyPersister;
+
+	protected boolean isDuplicateAssociation(
+		final String foreignKeyTable, 
+		final String[] foreignKeyColumns
+	) {
+		//disable a join back to this same association
+		final boolean isSameJoin = oneToManyPersister.getTableName().equals(foreignKeyTable) &&
+			Arrays.equals( foreignKeyColumns, oneToManyPersister.getKeyColumnNames() );
+		return isSameJoin || 
+			super.isDuplicateAssociation(foreignKeyTable, foreignKeyColumns);
+	}
+
+	public OneToManyJoinWalker(
+			QueryableCollection oneToManyPersister, 
+			int batchSize, 
+			String subquery, 
+			SessionFactoryImplementor factory, 
+			Map enabledFilters)
+	throws MappingException {
+
+		super(factory, enabledFilters);
+
+		this.oneToManyPersister = oneToManyPersister;
+
+		final OuterJoinLoadable elementPersister = (OuterJoinLoadable) oneToManyPersister.getElementPersister();
+		final String alias = generateRootAlias( oneToManyPersister.getRole() );
+
+		walkEntityTree(elementPersister, alias);
+
+		List allAssociations = new ArrayList();
+		allAssociations.addAll(associations);
+		allAssociations.add( new OuterJoinableAssociation( 
+				oneToManyPersister.getCollectionType(),
+				null, 
+				null, 
+				alias, 
+				JoinFragment.LEFT_OUTER_JOIN, 
+				getFactory(), 
+				CollectionHelper.EMPTY_MAP 
+			) );
+		
+		initPersisters(allAssociations, LockMode.NONE);
+		initStatementString(elementPersister, alias, batchSize, subquery);
+
+	}
+
+	private void initStatementString(
+		final OuterJoinLoadable elementPersister,
+		final String alias,
+		final int batchSize,
+		final String subquery)
+	throws MappingException {
+
+		final int joins = countEntityPersisters( associations );
+		suffixes = BasicLoader.generateSuffixes( joins + 1 );
+
+		final int collectionJoins = countCollectionPersisters( associations ) + 1;
+		collectionSuffixes = BasicLoader.generateSuffixes( joins + 1, collectionJoins );
+
+		StringBuffer whereString = whereString(
+				alias, 
+				oneToManyPersister.getKeyColumnNames(), 
+				subquery,
+				batchSize
+			);
+		String filter = oneToManyPersister.filterFragment( alias, getEnabledFilters() );
+		whereString.insert( 0, StringHelper.moveAndToBeginning(filter) );
+
+		JoinFragment ojf = mergeOuterJoins(associations);
+		Select select = new Select( getDialect() )
+			.setSelectClause(
+				oneToManyPersister.selectFragment(null, null, alias, suffixes[joins], collectionSuffixes[0], true) +
+				selectString(associations)
+			)
+			.setFromClause(
+				elementPersister.fromTableFragment(alias) +
+				elementPersister.fromJoinFragment(alias, true, true)
+			)
+			.setWhereClause( whereString.toString() )
+			.setOuterJoins(
+				ojf.toFromFragmentString(),
+				ojf.toWhereFragmentString() +
+				elementPersister.whereJoinFragment(alias, true, true)
+			);
+
+		select.setOrderByClause( orderBy( associations, oneToManyPersister.getSQLOrderByString(alias) ) );
+
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			select.setComment( "load one-to-many " + oneToManyPersister.getRole() );
+		}
+
+		sql = select.toStatementString();
+	}
+
+	public String toString() {
+		return getClass().getName() + '(' + oneToManyPersister.getRole() + ')';
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/OneToManyJoinWalker.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/OneToManyLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/OneToManyLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/OneToManyLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+//$Id: OneToManyLoader.java 7123 2005-06-13 20:10:20Z oneovthafew $
+package org.hibernate.loader.collection;
+
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.MappingException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.loader.JoinWalker;
+import org.hibernate.persister.collection.QueryableCollection;
+
+/**
+ * Loads one-to-many associations<br>
+ * <br>
+ * The collection persister must implement <tt>QueryableCOllection<tt>. For
+ * other collections, create a customized subclass of <tt>Loader</tt>.
+ *
+ * @see BasicCollectionLoader
+ * @author Gavin King
+ */
+public class OneToManyLoader extends CollectionLoader {
+
+	private static final Log log = LogFactory.getLog(OneToManyLoader.class);
+
+	public OneToManyLoader(
+			QueryableCollection oneToManyPersister, 
+			SessionFactoryImplementor session, 
+			Map enabledFilters)
+	throws MappingException {
+		this(oneToManyPersister, 1, session, enabledFilters);
+	}
+
+	public OneToManyLoader(
+			QueryableCollection oneToManyPersister, 
+			int batchSize, 
+			SessionFactoryImplementor factory, 
+			Map enabledFilters)
+	throws MappingException {
+		this(oneToManyPersister, batchSize, null, factory, enabledFilters);
+	}
+
+	public OneToManyLoader(
+			QueryableCollection oneToManyPersister, 
+			int batchSize, 
+			String subquery, 
+			SessionFactoryImplementor factory, 
+			Map enabledFilters)
+	throws MappingException {
+
+		super(oneToManyPersister, factory, enabledFilters);
+		
+		JoinWalker walker = new OneToManyJoinWalker(
+				oneToManyPersister, 
+				batchSize, 
+				subquery, 
+				factory, 
+				enabledFilters
+			);
+		initFromWalker( walker );
+
+		postInstantiate();
+
+		log.debug( "Static select for one-to-many " + oneToManyPersister.getRole() + ": " + getSQLString() );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/SubselectCollectionLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/SubselectCollectionLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/SubselectCollectionLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,72 @@
+//$Id: SubselectCollectionLoader.java 7670 2005-07-29 05:36:14Z oneovthafew $
+package org.hibernate.loader.collection;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.type.Type;
+
+/**
+ * Implements subselect fetching for a collection
+ * @author Gavin King
+ */
+public class SubselectCollectionLoader extends BasicCollectionLoader {
+	
+	private final Serializable[] keys;
+	private final Type[] types;
+	private final Object[] values;
+	private final Map namedParameters;
+	private final Map namedParameterLocMap;
+
+	public SubselectCollectionLoader(
+			QueryableCollection persister, 
+			String subquery,
+			Collection entityKeys,
+			QueryParameters queryParameters,
+			Map namedParameterLocMap,
+			SessionFactoryImplementor factory, 
+			Map enabledFilters)
+	throws MappingException {
+		
+		super(persister, 1, subquery, factory, enabledFilters);
+
+		keys = new Serializable[ entityKeys.size() ];
+		Iterator iter = entityKeys.iterator();
+		int i=0;
+		while ( iter.hasNext() ) {
+			keys[i++] = ( (EntityKey) iter.next() ).getIdentifier();
+		}
+		
+		this.namedParameters = queryParameters.getNamedParameters();
+		this.types = queryParameters.getFilteredPositionalParameterTypes();
+		this.values = queryParameters.getFilteredPositionalParameterValues();
+		this.namedParameterLocMap = namedParameterLocMap;
+		
+	}
+
+	public void initialize(Serializable id, SessionImplementor session)
+	throws HibernateException {
+		loadCollectionSubselect( 
+				session, 
+				keys, 
+				values,
+				types,
+				namedParameters,
+				getKeyType() 
+			);
+	}
+
+	public int[] getNamedParameterLocs(String name) {
+		return (int[]) namedParameterLocMap.get( name );
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/SubselectCollectionLoader.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/SubselectOneToManyLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/SubselectOneToManyLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/SubselectOneToManyLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,72 @@
+//$Id: SubselectOneToManyLoader.java 7670 2005-07-29 05:36:14Z oneovthafew $
+package org.hibernate.loader.collection;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.type.Type;
+
+/**
+ * Implements subselect fetching for a one to many association
+ * @author Gavin King
+ */
+public class SubselectOneToManyLoader extends OneToManyLoader {
+	
+	private final Serializable[] keys;
+	private final Type[] types;
+	private final Object[] values;
+	private final Map namedParameters;
+	private final Map namedParameterLocMap;
+
+	public SubselectOneToManyLoader(
+			QueryableCollection persister, 
+			String subquery,
+			Collection entityKeys,
+			QueryParameters queryParameters,
+			Map namedParameterLocMap,
+			SessionFactoryImplementor factory, 
+			Map enabledFilters)
+	throws MappingException {
+		
+		super(persister, 1, subquery, factory, enabledFilters);
+
+		keys = new Serializable[ entityKeys.size() ];
+		Iterator iter = entityKeys.iterator();
+		int i=0;
+		while ( iter.hasNext() ) {
+			keys[i++] = ( (EntityKey) iter.next() ).getIdentifier();
+		}
+		
+		this.namedParameters = queryParameters.getNamedParameters();
+		this.types = queryParameters.getFilteredPositionalParameterTypes();
+		this.values = queryParameters.getFilteredPositionalParameterValues();
+		this.namedParameterLocMap = namedParameterLocMap;
+		
+	}
+
+	public void initialize(Serializable id, SessionImplementor session)
+	throws HibernateException {
+		loadCollectionSubselect( 
+				session, 
+				keys, 
+				values,
+				types,
+				namedParameters,
+				getKeyType() 
+			);
+	}
+
+	public int[] getNamedParameterLocs(String name) {
+		return (int[]) namedParameterLocMap.get( name );
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/SubselectOneToManyLoader.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines collection initializers
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/collection/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/CriteriaJoinWalker.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/CriteriaJoinWalker.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/CriteriaJoinWalker.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,174 @@
+//$Id: CriteriaJoinWalker.java 9116 2006-01-23 21:21:01Z steveebersole $
+package org.hibernate.loader.criteria;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.Criteria;
+import org.hibernate.FetchMode;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.impl.CriteriaImpl;
+import org.hibernate.loader.AbstractEntityJoinWalker;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * A <tt>JoinWalker</tt> for <tt>Criteria</tt> queries.
+ *
+ * @see CriteriaLoader
+ * @author Gavin King
+ */
+public class CriteriaJoinWalker extends AbstractEntityJoinWalker {
+
+	//TODO: add a CriteriaImplementor interface
+	//      this class depends directly upon CriteriaImpl in the impl package...
+
+	private final CriteriaQueryTranslator translator;
+	private final Set querySpaces;
+	private final Type[] resultTypes;
+	//the user visible aliases, which are unknown to the superclass,
+	//these are not the actual "physical" SQL aliases
+	private final String[] userAliases;
+	private final List userAliasList = new ArrayList();
+
+	public Type[] getResultTypes() {
+		return resultTypes;
+	}
+
+	public String[] getUserAliases() {
+		return userAliases;
+	}
+
+	public CriteriaJoinWalker(
+			final OuterJoinLoadable persister, 
+			final CriteriaQueryTranslator translator,
+			final SessionFactoryImplementor factory, 
+			final CriteriaImpl criteria, 
+			final String rootEntityName,
+			final Map enabledFilters)
+	throws HibernateException {
+		super(persister, factory, enabledFilters);
+
+		this.translator = translator;
+
+		querySpaces = translator.getQuerySpaces();
+
+		if ( translator.hasProjection() ) {
+			resultTypes = translator.getProjectedTypes();
+			
+			initProjection( 
+					translator.getSelect(), 
+					translator.getWhereCondition(), 
+					translator.getOrderBy(),
+					translator.getGroupBy(),
+					LockMode.NONE 
+				);
+		}
+		else {
+			resultTypes = new Type[] { TypeFactory.manyToOne( persister.getEntityName() ) };
+
+			initAll( translator.getWhereCondition(), translator.getOrderBy(), LockMode.NONE );
+		}
+		
+		userAliasList.add( criteria.getAlias() ); //root entity comes *last*
+		userAliases = ArrayHelper.toStringArray(userAliasList);
+
+	}
+
+	protected int getJoinType(
+			AssociationType type, 
+			FetchMode config, 
+			String path,
+			String lhsTable,
+			String[] lhsColumns,
+			boolean nullable,
+			int currentDepth, CascadeStyle cascadeStyle)
+	throws MappingException {
+
+		if ( translator.isJoin(path) ) {
+			return translator.getJoinType( path );
+		}
+		else {
+			if ( translator.hasProjection() ) {
+				return -1;
+			}
+			else {
+				FetchMode fetchMode = translator.getRootCriteria()
+					.getFetchMode(path);
+				if ( isDefaultFetchMode(fetchMode) ) {
+					return super.getJoinType(
+							type, 
+							config, 
+							path, 
+							lhsTable, 
+							lhsColumns, 
+							nullable,
+							currentDepth, cascadeStyle
+						);
+				}
+				else {
+					if ( fetchMode==FetchMode.JOIN ) {
+						isDuplicateAssociation(lhsTable, lhsColumns, type); //deliberately ignore return value!
+						return getJoinType(nullable, currentDepth);
+					}
+					else {
+						return -1;
+					}
+				}
+			}
+		}
+	}
+	
+	private static boolean isDefaultFetchMode(FetchMode fetchMode) {
+		return fetchMode==null || fetchMode==FetchMode.DEFAULT;
+	}
+
+	/**
+	 * Use the discriminator, to narrow the select to instances
+	 * of the queried subclass, also applying any filters.
+	 */
+	protected String getWhereFragment() throws MappingException {
+		return super.getWhereFragment() +
+			( (Queryable) getPersister() ).filterFragment( getAlias(), getEnabledFilters() );
+	}
+	
+	protected String generateTableAlias(int n, String path, Joinable joinable) {
+		if ( joinable.consumesEntityAlias() ) {
+			final Criteria subcriteria = translator.getCriteria(path);
+			String sqlAlias = subcriteria==null ? null : translator.getSQLAlias(subcriteria);
+			if (sqlAlias!=null) {
+				userAliasList.add( subcriteria.getAlias() ); //alias may be null
+				return sqlAlias; //EARLY EXIT
+			}
+			else {
+				userAliasList.add(null);
+			}
+		}
+		return super.generateTableAlias( n + translator.getSQLAliasCount(), path, joinable );
+	}
+
+	protected String generateRootAlias(String tableName) {
+		return CriteriaQueryTranslator.ROOT_SQL_ALIAS;
+	}
+
+	public Set getQuerySpaces() {
+		return querySpaces;
+	}
+	
+	public String getComment() {
+		return "criteria query";
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/CriteriaJoinWalker.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/CriteriaLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/CriteriaLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/CriteriaLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,169 @@
+//$Id: CriteriaLoader.java 11320 2007-03-20 11:50:53Z steve.ebersole at jboss.com $
+package org.hibernate.loader.criteria;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Iterator;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.QueryException;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.impl.CriteriaImpl;
+import org.hibernate.loader.OuterJoinLoader;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.persister.entity.Lockable;
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.type.Type;
+
+/**
+ * A <tt>Loader</tt> for <tt>Criteria</tt> queries. Note that criteria queries are
+ * more like multi-object <tt>load()</tt>s than like HQL queries.
+ *
+ * @author Gavin King
+ */
+public class CriteriaLoader extends OuterJoinLoader {
+
+	//TODO: this class depends directly upon CriteriaImpl, 
+	//      in the impl package ... add a CriteriaImplementor 
+	//      interface
+
+	//NOTE: unlike all other Loaders, this one is NOT
+	//      multithreaded, or cacheable!!
+
+	private final CriteriaQueryTranslator translator;
+	private final Set querySpaces;
+	private final Type[] resultTypes;
+	//the user visible aliases, which are unknown to the superclass,
+	//these are not the actual "physical" SQL aliases
+	private final String[] userAliases;
+
+	public CriteriaLoader(
+			final OuterJoinLoadable persister, 
+			final SessionFactoryImplementor factory, 
+			final CriteriaImpl criteria, 
+			final String rootEntityName,
+			final Map enabledFilters)
+	throws HibernateException {
+		super(factory, enabledFilters);
+
+		translator = new CriteriaQueryTranslator(
+				factory, 
+				criteria, 
+				rootEntityName, 
+				CriteriaQueryTranslator.ROOT_SQL_ALIAS
+			);
+
+		querySpaces = translator.getQuerySpaces();
+		
+		CriteriaJoinWalker walker = new CriteriaJoinWalker(
+				persister, 
+				translator,
+				factory, 
+				criteria, 
+				rootEntityName, 
+				enabledFilters
+			);
+
+		initFromWalker(walker);
+		
+		userAliases = walker.getUserAliases();
+		resultTypes = walker.getResultTypes();
+
+		postInstantiate();
+
+	}
+	
+	public ScrollableResults scroll(SessionImplementor session, ScrollMode scrollMode) 
+	throws HibernateException {
+		QueryParameters qp = translator.getQueryParameters();
+		qp.setScrollMode(scrollMode);
+		return scroll(qp, resultTypes, null, session);
+	}
+
+	public List list(SessionImplementor session) 
+	throws HibernateException {
+		return list( session, translator.getQueryParameters(), querySpaces, resultTypes );
+
+	}
+
+	protected Object getResultColumnOrRow(Object[] row, ResultTransformer transformer, ResultSet rs, SessionImplementor session)
+	throws SQLException, HibernateException {
+		final Object[] result;
+		final String[] aliases;
+		if ( translator.hasProjection() ) {
+			Type[] types = translator.getProjectedTypes();
+			result = new Object[types.length];
+			String[] columnAliases = translator.getProjectedColumnAliases();
+			for ( int i=0; i<result.length; i++ ) {
+				result[i] = types[i].nullSafeGet(rs, columnAliases[i], session, null);
+			}
+			aliases = translator.getProjectedAliases();
+		}
+		else {
+			result = row;
+			aliases = userAliases;
+		}
+		return translator.getRootCriteria().getResultTransformer()
+				.transformTuple(result, aliases);
+	}
+
+	public Set getQuerySpaces() {
+		return querySpaces;
+	}
+
+	protected String applyLocks(String sqlSelectString, Map lockModes, Dialect dialect) throws QueryException {
+		if ( lockModes == null || lockModes.isEmpty() ) {
+			return sqlSelectString;
+		}
+
+		final Map aliasedLockModes = new HashMap();
+		final Map keyColumnNames = dialect.forUpdateOfColumns() ? new HashMap() : null;
+		final String[] drivingSqlAliases = getAliases();
+		for ( int i = 0; i < drivingSqlAliases.length; i++ ) {
+			final LockMode lockMode = ( LockMode ) lockModes.get( drivingSqlAliases[i] );
+			if ( lockMode != null ) {
+				final Lockable drivingPersister = ( Lockable ) getEntityPersisters()[i];
+				final String rootSqlAlias = drivingPersister.getRootTableAlias( drivingSqlAliases[i] );
+				aliasedLockModes.put( rootSqlAlias, lockMode );
+				if ( keyColumnNames != null ) {
+					keyColumnNames.put( rootSqlAlias, drivingPersister.getRootTableIdentifierColumnNames() );
+				}
+			}
+		}
+		return dialect.applyLocksToSql( sqlSelectString, aliasedLockModes, keyColumnNames );
+	}
+
+	protected LockMode[] getLockModes(Map lockModes) {
+		final String[] entityAliases = getAliases();
+		if ( entityAliases == null ) {
+			return null;
+		}
+		final int size = entityAliases.length;
+		LockMode[] lockModesArray = new LockMode[size];
+		for ( int i=0; i<size; i++ ) {
+			LockMode lockMode = (LockMode) lockModes.get( entityAliases[i] );
+			lockModesArray[i] = lockMode==null ? LockMode.NONE : lockMode;
+		}
+		return lockModesArray;
+	}
+
+	protected boolean isSubselectLoadingEnabled() {
+		return hasSubselectLoadableCollections();
+	}
+	
+	protected List getResultList(List results, ResultTransformer resultTransformer) {
+		return translator.getRootCriteria().getResultTransformer().transformList( results );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/CriteriaQueryTranslator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/CriteriaQueryTranslator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/CriteriaQueryTranslator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,556 @@
+//$Id: CriteriaQueryTranslator.java 9636 2006-03-16 14:14:48Z max.andersen at jboss.com $
+package org.hibernate.loader.criteria;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.apache.commons.collections.SequencedHashMap;
+import org.hibernate.Criteria;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.hql.ast.util.SessionFactoryHelper;
+import org.hibernate.criterion.CriteriaQuery;
+import org.hibernate.criterion.Projection;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.RowSelection;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.impl.CriteriaImpl;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.persister.entity.PropertyMapping;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.Type;
+import org.hibernate.type.NullableType;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * @author Gavin King
+ */
+public class CriteriaQueryTranslator implements CriteriaQuery {
+
+	public static final String ROOT_SQL_ALIAS = Criteria.ROOT_ALIAS + '_';
+
+	private CriteriaQuery outerQueryTranslator;
+
+	private final CriteriaImpl rootCriteria;
+	private final String rootEntityName;
+	private final String rootSQLAlias;
+	private int aliasCount = 0;
+
+	private final Map criteriaEntityNames = new SequencedHashMap();
+	private final Map criteriaSQLAliasMap = new HashMap();
+	private final Map aliasCriteriaMap = new HashMap();
+	private final Map associationPathCriteriaMap = new SequencedHashMap();
+	private final Map associationPathJoinTypesMap = new SequencedHashMap();
+
+	private final SessionFactoryImplementor sessionFactory;
+
+	public CriteriaQueryTranslator(
+			final SessionFactoryImplementor factory,
+	        final CriteriaImpl criteria,
+	        final String rootEntityName,
+	        final String rootSQLAlias,
+	        CriteriaQuery outerQuery) throws HibernateException {
+		this( factory, criteria, rootEntityName, rootSQLAlias );
+		outerQueryTranslator = outerQuery;
+	}
+
+	public CriteriaQueryTranslator(
+			final SessionFactoryImplementor factory,
+	        final CriteriaImpl criteria,
+	        final String rootEntityName,
+	        final String rootSQLAlias) throws HibernateException {
+		this.rootCriteria = criteria;
+		this.rootEntityName = rootEntityName;
+		this.sessionFactory = factory;
+		this.rootSQLAlias = rootSQLAlias;
+		createAliasCriteriaMap();
+		createAssociationPathCriteriaMap();
+		createCriteriaEntityNameMap();
+		createCriteriaSQLAliasMap();
+	}
+
+	public String generateSQLAlias() {
+		return StringHelper.generateAlias( Criteria.ROOT_ALIAS, aliasCount ) + '_';
+	}
+
+	public String getRootSQLALias() {
+		return rootSQLAlias;
+	}
+
+	private Criteria getAliasedCriteria(String alias) {
+		return ( Criteria ) aliasCriteriaMap.get( alias );
+	}
+
+	public boolean isJoin(String path) {
+		return associationPathCriteriaMap.containsKey( path );
+	}
+
+	public int getJoinType(String path) {
+		Integer result = ( Integer ) associationPathJoinTypesMap.get( path );
+		return ( result == null ? Criteria.INNER_JOIN : result.intValue() );
+	}
+
+	public Criteria getCriteria(String path) {
+		return ( Criteria ) associationPathCriteriaMap.get( path );
+	}
+
+	public Set getQuerySpaces() {
+		Set result = new HashSet();
+		Iterator iter = criteriaEntityNames.values().iterator();
+		while ( iter.hasNext() ) {
+			String entityName = ( String ) iter.next();
+			result.addAll( Arrays.asList( getFactory().getEntityPersister( entityName ).getQuerySpaces() ) );
+		}
+		return result;
+	}
+
+	private void createAliasCriteriaMap() {
+		aliasCriteriaMap.put( rootCriteria.getAlias(), rootCriteria );
+		Iterator iter = rootCriteria.iterateSubcriteria();
+		while ( iter.hasNext() ) {
+			Criteria subcriteria = ( Criteria ) iter.next();
+			if ( subcriteria.getAlias() != null ) {
+				Object old = aliasCriteriaMap.put( subcriteria.getAlias(), subcriteria );
+				if ( old != null ) {
+					throw new QueryException( "duplicate alias: " + subcriteria.getAlias() );
+				}
+			}
+		}
+	}
+
+	private void createAssociationPathCriteriaMap() {
+		Iterator iter = rootCriteria.iterateSubcriteria();
+		while ( iter.hasNext() ) {
+			CriteriaImpl.Subcriteria crit = ( CriteriaImpl.Subcriteria ) iter.next();
+			String wholeAssociationPath = getWholeAssociationPath( crit );
+			Object old = associationPathCriteriaMap.put( wholeAssociationPath, crit );
+			if ( old != null ) {
+				throw new QueryException( "duplicate association path: " + wholeAssociationPath );
+			}
+			int joinType = crit.getJoinType();
+			old = associationPathJoinTypesMap.put( wholeAssociationPath, new Integer( joinType ) );
+			if ( old != null ) {
+				// TODO : not so sure this is needed...
+				throw new QueryException( "duplicate association path: " + wholeAssociationPath );
+			}
+		}
+	}
+
+	private String getWholeAssociationPath(CriteriaImpl.Subcriteria subcriteria) {
+		String path = subcriteria.getPath();
+
+		// some messy, complex stuff here, since createCriteria() can take an
+		// aliased path, or a path rooted at the creating criteria instance
+		Criteria parent = null;
+		if ( path.indexOf( '.' ) > 0 ) {
+			// if it is a compound path
+			String testAlias = StringHelper.root( path );
+			if ( !testAlias.equals( subcriteria.getAlias() ) ) {
+				// and the qualifier is not the alias of this criteria
+				//      -> check to see if we belong to some criteria other
+				//          than the one that created us
+				parent = ( Criteria ) aliasCriteriaMap.get( testAlias );
+			}
+		}
+		if ( parent == null ) {
+			// otherwise assume the parent is the the criteria that created us
+			parent = subcriteria.getParent();
+		}
+		else {
+			path = StringHelper.unroot( path );
+		}
+
+		if ( parent.equals( rootCriteria ) ) {
+			// if its the root criteria, we are done
+			return path;
+		}
+		else {
+			// otherwise, recurse
+			return getWholeAssociationPath( ( CriteriaImpl.Subcriteria ) parent ) + '.' + path;
+		}
+	}
+
+	private void createCriteriaEntityNameMap() {
+		criteriaEntityNames.put( rootCriteria, rootEntityName );
+		Iterator iter = associationPathCriteriaMap.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = ( Map.Entry ) iter.next();
+			criteriaEntityNames.put(
+					me.getValue(), //the criteria instance
+			        getPathEntityName( ( String ) me.getKey() )
+			);
+		}
+	}
+
+	private String getPathEntityName(String path) {
+		Queryable persister = ( Queryable ) sessionFactory.getEntityPersister( rootEntityName );
+		StringTokenizer tokens = new StringTokenizer( path, "." );
+		String componentPath = "";
+		while ( tokens.hasMoreTokens() ) {
+			componentPath += tokens.nextToken();
+			Type type = persister.toType( componentPath );
+			if ( type.isAssociationType() ) {
+				AssociationType atype = ( AssociationType ) type;
+				persister = ( Queryable ) sessionFactory.getEntityPersister(
+						atype.getAssociatedEntityName( sessionFactory )
+				);
+				componentPath = "";
+			}
+			else if ( type.isComponentType() ) {
+				componentPath += '.';
+			}
+			else {
+				throw new QueryException( "not an association: " + componentPath );
+			}
+		}
+		return persister.getEntityName();
+	}
+
+	public int getSQLAliasCount() {
+		return criteriaSQLAliasMap.size();
+	}
+
+	private void createCriteriaSQLAliasMap() {
+		int i = 0;
+		Iterator criteriaIterator = criteriaEntityNames.entrySet().iterator();
+		while ( criteriaIterator.hasNext() ) {
+			Map.Entry me = ( Map.Entry ) criteriaIterator.next();
+			Criteria crit = ( Criteria ) me.getKey();
+			String alias = crit.getAlias();
+			if ( alias == null ) {
+				alias = ( String ) me.getValue(); // the entity name
+			}
+			criteriaSQLAliasMap.put( crit, StringHelper.generateAlias( alias, i++ ) );
+		}
+		criteriaSQLAliasMap.put( rootCriteria, rootSQLAlias );
+	}
+
+	public CriteriaImpl getRootCriteria() {
+		return rootCriteria;
+	}
+
+	public QueryParameters getQueryParameters() {
+		List values = new ArrayList();
+		List types = new ArrayList();
+		Iterator iter = rootCriteria.iterateExpressionEntries();
+		while ( iter.hasNext() ) {
+			CriteriaImpl.CriterionEntry ce = ( CriteriaImpl.CriterionEntry ) iter.next();
+			TypedValue[] tv = ce.getCriterion().getTypedValues( ce.getCriteria(), this );
+			for ( int i = 0; i < tv.length; i++ ) {
+				values.add( tv[i].getValue() );
+				types.add( tv[i].getType() );
+			}
+		}
+		Object[] valueArray = values.toArray();
+		Type[] typeArray = ArrayHelper.toTypeArray( types );
+
+		RowSelection selection = new RowSelection();
+		selection.setFirstRow( rootCriteria.getFirstResult() );
+		selection.setMaxRows( rootCriteria.getMaxResults() );
+		selection.setTimeout( rootCriteria.getTimeout() );
+		selection.setFetchSize( rootCriteria.getFetchSize() );
+
+		Map lockModes = new HashMap();
+		iter = rootCriteria.getLockModes().entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = ( Map.Entry ) iter.next();
+			final Criteria subcriteria = getAliasedCriteria( ( String ) me.getKey() );
+			lockModes.put( getSQLAlias( subcriteria ), me.getValue() );
+		}
+		iter = rootCriteria.iterateSubcriteria();
+		while ( iter.hasNext() ) {
+			CriteriaImpl.Subcriteria subcriteria = ( CriteriaImpl.Subcriteria ) iter.next();
+			LockMode lm = subcriteria.getLockMode();
+			if ( lm != null ) {
+				lockModes.put( getSQLAlias( subcriteria ), lm );
+			}
+		}
+
+		return new QueryParameters(
+				typeArray,
+		        valueArray,
+		        lockModes,
+		        selection,
+		        rootCriteria.getCacheable(),
+		        rootCriteria.getCacheRegion(),
+		        rootCriteria.getComment(),
+		        rootCriteria.isLookupByNaturalKey(),
+		        rootCriteria.getResultTransformer()
+		);
+	}
+
+	public boolean hasProjection() {
+		return rootCriteria.getProjection() != null;
+	}
+
+	public String getGroupBy() {
+		if ( rootCriteria.getProjection().isGrouped() ) {
+			return rootCriteria.getProjection()
+					.toGroupSqlString( rootCriteria.getProjectionCriteria(), this );
+		}
+		else {
+			return "";
+		}
+	}
+
+	public String getSelect() {
+		return rootCriteria.getProjection().toSqlString(
+				rootCriteria.getProjectionCriteria(),
+		        0,
+		        this
+		);
+	}
+
+	public Type[] getProjectedTypes() {
+		return rootCriteria.getProjection().getTypes( rootCriteria, this );
+	}
+
+	public String[] getProjectedColumnAliases() {
+		return rootCriteria.getProjection().getColumnAliases( 0 );
+	}
+
+	public String[] getProjectedAliases() {
+		return rootCriteria.getProjection().getAliases();
+	}
+
+	public String getWhereCondition() {
+		StringBuffer condition = new StringBuffer( 30 );
+		Iterator criterionIterator = rootCriteria.iterateExpressionEntries();
+		while ( criterionIterator.hasNext() ) {
+			CriteriaImpl.CriterionEntry entry = ( CriteriaImpl.CriterionEntry ) criterionIterator.next();
+			String sqlString = entry.getCriterion().toSqlString( entry.getCriteria(), this );
+			condition.append( sqlString );
+			if ( criterionIterator.hasNext() ) {
+				condition.append( " and " );
+			}
+		}
+		return condition.toString();
+	}
+
+	public String getOrderBy() {
+		StringBuffer orderBy = new StringBuffer( 30 );
+		Iterator criterionIterator = rootCriteria.iterateOrderings();
+		while ( criterionIterator.hasNext() ) {
+			CriteriaImpl.OrderEntry oe = ( CriteriaImpl.OrderEntry ) criterionIterator.next();
+			orderBy.append( oe.getOrder().toSqlString( oe.getCriteria(), this ) );
+			if ( criterionIterator.hasNext() ) {
+				orderBy.append( ", " );
+			}
+		}
+		return orderBy.toString();
+	}
+
+	public SessionFactoryImplementor getFactory() {
+		return sessionFactory;
+	}
+
+	public String getSQLAlias(Criteria criteria) {
+		return ( String ) criteriaSQLAliasMap.get( criteria );
+	}
+
+	public String getEntityName(Criteria criteria) {
+		return ( String ) criteriaEntityNames.get( criteria );
+	}
+
+	public String getColumn(Criteria criteria, String propertyName) {
+		String[] cols = getColumns( propertyName, criteria );
+		if ( cols.length != 1 ) {
+			throw new QueryException( "property does not map to a single column: " + propertyName );
+		}
+		return cols[0];
+	}
+
+	/**
+	 * Get the names of the columns constrained
+	 * by this criterion.
+	 */
+	public String[] getColumnsUsingProjection(
+			Criteria subcriteria,
+	        String propertyName) throws HibernateException {
+
+		//first look for a reference to a projection alias
+		final Projection projection = rootCriteria.getProjection();
+		String[] projectionColumns = projection == null ?
+		                             null :
+		                             projection.getColumnAliases( propertyName, 0 );
+
+		if ( projectionColumns == null ) {
+			//it does not refer to an alias of a projection,
+			//look for a property
+			try {
+				return getColumns( propertyName, subcriteria );
+			}
+			catch ( HibernateException he ) {
+				//not found in inner query , try the outer query
+				if ( outerQueryTranslator != null ) {
+					return outerQueryTranslator.getColumnsUsingProjection( subcriteria, propertyName );
+				}
+				else {
+					throw he;
+				}
+			}
+		}
+		else {
+			//it refers to an alias of a projection
+			return projectionColumns;
+		}
+	}
+
+	public String[] getIdentifierColumns(Criteria subcriteria) {
+		String[] idcols =
+				( ( Loadable ) getPropertyMapping( getEntityName( subcriteria ) ) ).getIdentifierColumnNames();
+		return StringHelper.qualify( getSQLAlias( subcriteria ), idcols );
+	}
+
+	public Type getIdentifierType(Criteria subcriteria) {
+		return ( ( Loadable ) getPropertyMapping( getEntityName( subcriteria ) ) ).getIdentifierType();
+	}
+
+	public TypedValue getTypedIdentifierValue(Criteria subcriteria, Object value) {
+		final Loadable loadable = ( Loadable ) getPropertyMapping( getEntityName( subcriteria ) );
+		return new TypedValue(
+				loadable.getIdentifierType(),
+		        value,
+		        EntityMode.POJO
+		);
+	}
+
+	private String[] getColumns(
+			String propertyName,
+	        Criteria subcriteria) throws HibernateException {
+		return getPropertyMapping( getEntityName( subcriteria, propertyName ) )
+				.toColumns(
+						getSQLAlias( subcriteria, propertyName ),
+				        getPropertyName( propertyName )
+				);
+	}
+
+	public Type getTypeUsingProjection(Criteria subcriteria, String propertyName)
+			throws HibernateException {
+
+		//first look for a reference to a projection alias
+		final Projection projection = rootCriteria.getProjection();
+		Type[] projectionTypes = projection == null ?
+		                         null :
+		                         projection.getTypes( propertyName, subcriteria, this );
+
+		if ( projectionTypes == null ) {
+			try {
+				//it does not refer to an alias of a projection,
+				//look for a property
+				return getType( subcriteria, propertyName );
+			}
+			catch ( HibernateException he ) {
+				//not found in inner query , try the outer query
+				if ( outerQueryTranslator != null ) {
+					return outerQueryTranslator.getType( subcriteria, propertyName );
+				}
+				else {
+					throw he;
+				}
+			}
+		}
+		else {
+			if ( projectionTypes.length != 1 ) {
+				//should never happen, i think
+				throw new QueryException( "not a single-length projection: " + propertyName );
+			}
+			return projectionTypes[0];
+		}
+	}
+
+	public Type getType(Criteria subcriteria, String propertyName)
+			throws HibernateException {
+		return getPropertyMapping( getEntityName( subcriteria, propertyName ) )
+				.toType( getPropertyName( propertyName ) );
+	}
+
+	/**
+	 * Get the a typed value for the given property value.
+	 */
+	public TypedValue getTypedValue(Criteria subcriteria, String propertyName, Object value)
+			throws HibernateException {
+		// Detect discriminator values...
+		if ( value instanceof Class ) {
+			Class entityClass = ( Class ) value;
+			Queryable q = SessionFactoryHelper.findQueryableUsingImports( sessionFactory, entityClass.getName() );
+			if ( q != null ) {
+				Type type = q.getDiscriminatorType();
+				String stringValue = q.getDiscriminatorSQLValue();
+				// Convert the string value into the proper type.
+				if ( type instanceof NullableType ) {
+					NullableType nullableType = ( NullableType ) type;
+					value = nullableType.fromStringValue( stringValue );
+				}
+				else {
+					throw new QueryException( "Unsupported discriminator type " + type );
+				}
+				return new TypedValue(
+						type,
+				        value,
+				        EntityMode.POJO
+				);
+			}
+		}
+		// Otherwise, this is an ordinary value.
+		return new TypedValue(
+				getTypeUsingProjection( subcriteria, propertyName ),
+		        value,
+		        EntityMode.POJO
+		);
+	}
+
+	private PropertyMapping getPropertyMapping(String entityName)
+			throws MappingException {
+		return ( PropertyMapping ) sessionFactory.getEntityPersister( entityName );
+	}
+
+	//TODO: use these in methods above
+
+	public String getEntityName(Criteria subcriteria, String propertyName) {
+		if ( propertyName.indexOf( '.' ) > 0 ) {
+			String root = StringHelper.root( propertyName );
+			Criteria crit = getAliasedCriteria( root );
+			if ( crit != null ) {
+				return getEntityName( crit );
+			}
+		}
+		return getEntityName( subcriteria );
+	}
+
+	public String getSQLAlias(Criteria criteria, String propertyName) {
+		if ( propertyName.indexOf( '.' ) > 0 ) {
+			String root = StringHelper.root( propertyName );
+			Criteria subcriteria = getAliasedCriteria( root );
+			if ( subcriteria != null ) {
+				return getSQLAlias( subcriteria );
+			}
+		}
+		return getSQLAlias( criteria );
+	}
+
+	public String getPropertyName(String propertyName) {
+		if ( propertyName.indexOf( '.' ) > 0 ) {
+			String root = StringHelper.root( propertyName );
+			Criteria crit = getAliasedCriteria( root );
+			if ( crit != null ) {
+				return propertyName.substring( root.length() + 1 );
+			}
+		}
+		return propertyName;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/CriteriaQueryTranslator.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines the criteria query compiler and loader
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/criteria/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CollectionFetchReturn.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CollectionFetchReturn.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CollectionFetchReturn.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+package org.hibernate.loader.custom;
+
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.loader.EntityAliases;
+import org.hibernate.LockMode;
+
+/**
+ * Spefically a fetch return that refers to a collection association.
+ *
+ * @author Steve Ebersole
+ */
+public class CollectionFetchReturn extends FetchReturn {
+	private final CollectionAliases collectionAliases;
+	private final EntityAliases elementEntityAliases;
+
+	public CollectionFetchReturn(
+			String alias,
+			NonScalarReturn owner,
+			String ownerProperty,
+			CollectionAliases collectionAliases,
+	        EntityAliases elementEntityAliases,
+			LockMode lockMode) {
+		super( owner, ownerProperty, alias, lockMode );
+		this.collectionAliases = collectionAliases;
+		this.elementEntityAliases = elementEntityAliases;
+	}
+
+	public CollectionAliases getCollectionAliases() {
+		return collectionAliases;
+	}
+
+	public EntityAliases getElementEntityAliases() {
+		return elementEntityAliases;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CollectionReturn.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CollectionReturn.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CollectionReturn.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+package org.hibernate.loader.custom;
+
+import org.hibernate.LockMode;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.loader.EntityAliases;
+
+/**
+ * Represents a return which names a collection role; it
+ * is used in defining a custom query for loading an entity's
+ * collection in non-fetching scenarios (i.e., loading the collection
+ * itself as the "root" of the result).
+ *
+ * @author Steve Ebersole
+ */
+public class CollectionReturn extends NonScalarReturn {
+	private final String ownerEntityName;
+	private final String ownerProperty;
+	private final CollectionAliases collectionAliases;
+	private final EntityAliases elementEntityAliases;
+
+	public CollectionReturn(
+			String alias,
+			String ownerEntityName,
+			String ownerProperty,
+			CollectionAliases collectionAliases,
+	        EntityAliases elementEntityAliases,
+			LockMode lockMode) {
+		super( alias, lockMode );
+		this.ownerEntityName = ownerEntityName;
+		this.ownerProperty = ownerProperty;
+		this.collectionAliases = collectionAliases;
+		this.elementEntityAliases = elementEntityAliases;
+	}
+
+	/**
+	 * Returns the class owning the collection.
+	 *
+	 * @return The class owning the collection.
+	 */
+	public String getOwnerEntityName() {
+		return ownerEntityName;
+	}
+
+	/**
+	 * Returns the name of the property representing the collection from the {@link #getOwnerEntityName}.
+	 *
+	 * @return The name of the property representing the collection on the owner class.
+	 */
+	public String getOwnerProperty() {
+		return ownerProperty;
+	}
+
+	public CollectionAliases getCollectionAliases() {
+		return collectionAliases;
+	}
+
+	public EntityAliases getElementEntityAliases() {
+		return elementEntityAliases;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/ColumnCollectionAliases.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/ColumnCollectionAliases.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/ColumnCollectionAliases.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,127 @@
+package org.hibernate.loader.custom;
+
+import java.util.Map;
+
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.persister.collection.SQLLoadableCollection;
+import org.hibernate.util.StringHelper;
+
+/**
+ * CollectionAliases that uses columnnames instead of generated aliases.
+ * Aliases can still be overwritten via <return-property>
+ *  
+ * @author Max Rydahl Andersen
+ *
+ */
+public class ColumnCollectionAliases implements CollectionAliases {
+	private final String[] keyAliases;
+	private final String[] indexAliases;
+	private final String[] elementAliases;
+	private final String identifierAlias;
+	private Map userProvidedAliases;
+	
+	
+	public ColumnCollectionAliases(Map userProvidedAliases, SQLLoadableCollection persister) {
+		this.userProvidedAliases = userProvidedAliases;
+
+		this.keyAliases = getUserProvidedAliases(
+				"key", 
+				persister.getKeyColumnNames()
+			);
+
+		this.indexAliases = getUserProvidedAliases(
+				"index",
+				persister.getIndexColumnNames()
+				);
+		
+		this.elementAliases = getUserProvidedAliases( "element", 
+				persister.getElementColumnNames()
+				);
+				
+		this.identifierAlias = getUserProvidedAlias( "id", 
+				persister.getIdentifierColumnName()
+				);
+	
+	}
+
+
+	/**
+	 * Returns the suffixed result-set column-aliases for columns making up the key for this collection (i.e., its FK to
+	 * its owner).
+	 *
+	 * @return The key result-set column aliases.
+	 */
+	public String[] getSuffixedKeyAliases() {
+		return keyAliases;
+	}
+
+	/**
+	 * Returns the suffixed result-set column-aliases for the collumns making up the collection's index (map or list).
+	 *
+	 * @return The index result-set column aliases.
+	 */
+	public String[] getSuffixedIndexAliases() {
+		return indexAliases;
+	}
+
+	/**
+	 * Returns the suffixed result-set column-aliases for the columns making up the collection's elements.
+	 *
+	 * @return The element result-set column aliases.
+	 */
+	public String[] getSuffixedElementAliases() {
+		return elementAliases;
+	}
+
+	/**
+	 * Returns the suffixed result-set column-aliases for the column defining the collection's identifier (if any).
+	 *
+	 * @return The identifier result-set column aliases.
+	 */
+	public String getSuffixedIdentifierAlias() {
+		return identifierAlias;
+	}
+
+	/**
+	 * Returns the suffix used to unique the column aliases for this particular alias set.
+	 *
+	 * @return The uniqued column alias suffix.
+	 */
+	public String getSuffix() {
+		return "";
+	}
+
+	public String toString() {
+		return super.toString() + " [ suffixedKeyAliases=[" + join( keyAliases ) +
+		        "], suffixedIndexAliases=[" + join( indexAliases ) +
+		        "], suffixedElementAliases=[" + join( elementAliases ) +
+		        "], suffixedIdentifierAlias=[" + identifierAlias + "]]";
+	}
+
+	private String join(String[] aliases) {
+		if ( aliases == null) return null;
+
+		return StringHelper.join( ", ", aliases );
+	}
+	
+	private String[] getUserProvidedAliases(String propertyPath, String[] defaultAliases) {
+		String[] result = (String[]) userProvidedAliases.get(propertyPath);
+		if (result==null) {
+			return defaultAliases;			
+		} 
+		else {
+			return result;
+		}
+	}
+
+	private String getUserProvidedAlias(String propertyPath, String defaultAlias) {
+		String[] columns = (String[]) userProvidedAliases.get(propertyPath);
+		if (columns==null) {
+			return defaultAlias;
+		} 
+		else {
+			return columns[0];
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CustomLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CustomLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CustomLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,569 @@
+//$Id: CustomLoader.java 10087 2006-07-06 12:21:30Z steve.ebersole at jboss.com $
+package org.hibernate.loader.custom;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.HashSet;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.QueryException;
+import org.hibernate.ScrollableResults;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.hql.HolderInstantiator;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.loader.EntityAliases;
+import org.hibernate.loader.Loader;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.CollectionType;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * Extension point for loaders which use a SQL result set with "unexpected" column aliases.
+ * 
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public class CustomLoader extends Loader {
+	
+	// Currently *not* cachable if autodiscover types is in effect (e.g. "select * ...")
+
+	private final String sql;
+	private final Set querySpaces = new HashSet();
+	private final Map namedParameterBindPoints;
+
+	private final Queryable[] entityPersisters;
+	private final int[] entiytOwners;
+	private final EntityAliases[] entityAliases;
+
+	private final QueryableCollection[] collectionPersisters;
+	private final int[] collectionOwners;
+	private final CollectionAliases[] collectionAliases;
+
+	private final LockMode[] lockModes;
+//	private final String[] sqlAliases;
+//	private final String[] sqlAliasSuffixes;
+	private final ResultRowProcessor rowProcessor;
+
+	// this is only needed (afaict) for processing results from the query cache;
+	// however, this cannot possibly work in the case of discovered types...
+	private Type[] resultTypes;
+
+	// this is only needed (afaict) for ResultTransformer processing...
+	private String[] transformerAliases;
+
+
+	public CustomLoader(CustomQuery customQuery, SessionFactoryImplementor factory) {
+		super( factory );
+
+		this.sql = customQuery.getSQL();
+		this.querySpaces.addAll( customQuery.getQuerySpaces() );
+		this.namedParameterBindPoints = customQuery.getNamedParameterBindPoints();
+
+		List entityPersisters = new ArrayList();
+		List entityOwners = new ArrayList();
+		List entityAliases = new ArrayList();
+
+		List collectionPersisters = new ArrayList();
+		List collectionOwners = new ArrayList();
+		List collectionAliases = new ArrayList();
+
+		List lockModes = new ArrayList();
+		List resultColumnProcessors = new ArrayList();
+		List nonScalarReturnList = new ArrayList();
+		List resultTypes = new ArrayList();
+		List specifiedAliases = new ArrayList();
+		int returnableCounter = 0;
+		boolean hasScalars = false;
+
+		Iterator itr = customQuery.getCustomQueryReturns().iterator();
+		while ( itr.hasNext() ) {
+			final Return rtn = ( Return ) itr.next();
+			if ( rtn instanceof ScalarReturn ) {
+				ScalarReturn scalarRtn = ( ScalarReturn ) rtn;
+				resultTypes.add( scalarRtn.getType() );
+				specifiedAliases.add( scalarRtn.getColumnAlias() );
+				resultColumnProcessors.add(
+						new ScalarResultColumnProcessor(
+								scalarRtn.getColumnAlias(),
+								scalarRtn.getType()
+						)
+				);
+				hasScalars = true;
+			}
+			else if ( rtn instanceof RootReturn ) {
+				RootReturn rootRtn = ( RootReturn ) rtn;
+				Queryable persister = ( Queryable ) factory.getEntityPersister( rootRtn.getEntityName() );
+				entityPersisters.add( persister );
+				lockModes.add( rootRtn.getLockMode() );
+				resultColumnProcessors.add( new NonScalarResultColumnProcessor( returnableCounter++ ) );
+				nonScalarReturnList.add( rtn );
+				entityOwners.add( new Integer( -1 ) );
+				resultTypes.add( persister.getType() );
+				specifiedAliases.add( rootRtn.getAlias() );
+				entityAliases.add( rootRtn.getEntityAliases() );
+				ArrayHelper.addAll( querySpaces, persister.getQuerySpaces() );
+			}
+			else if ( rtn instanceof CollectionReturn ) {
+				CollectionReturn collRtn = ( CollectionReturn ) rtn;
+				String role = collRtn.getOwnerEntityName() + "." + collRtn.getOwnerProperty();
+				QueryableCollection persister = ( QueryableCollection ) factory.getCollectionPersister( role );
+				collectionPersisters.add( persister );
+				lockModes.add( collRtn.getLockMode() );
+				resultColumnProcessors.add( new NonScalarResultColumnProcessor( returnableCounter++ ) );
+				nonScalarReturnList.add( rtn );
+				collectionOwners.add( new Integer( -1 ) );
+				resultTypes.add( persister.getType() );
+				specifiedAliases.add( collRtn.getAlias() );
+				collectionAliases.add( collRtn.getCollectionAliases() );
+				// determine if the collection elements are entities...
+				Type elementType = persister.getElementType();
+				if ( elementType.isEntityType() ) {
+					Queryable elementPersister = ( Queryable ) ( ( EntityType ) elementType ).getAssociatedJoinable( factory );
+					entityPersisters.add( elementPersister );
+					entityOwners.add( new Integer( -1 ) );
+					entityAliases.add( collRtn.getElementEntityAliases() );
+					ArrayHelper.addAll( querySpaces, elementPersister.getQuerySpaces() );
+				}
+			}
+			else if ( rtn instanceof EntityFetchReturn ) {
+				EntityFetchReturn fetchRtn = ( EntityFetchReturn ) rtn;
+				NonScalarReturn ownerDescriptor = fetchRtn.getOwner();
+				int ownerIndex = nonScalarReturnList.indexOf( ownerDescriptor );
+				entityOwners.add( new Integer( ownerIndex ) );
+				lockModes.add( fetchRtn.getLockMode() );
+				Queryable ownerPersister = determineAppropriateOwnerPersister( ownerDescriptor );
+				EntityType fetchedType = ( EntityType ) ownerPersister.getPropertyType( fetchRtn.getOwnerProperty() );
+				String entityName = fetchedType.getAssociatedEntityName( getFactory() );
+				Queryable persister = ( Queryable ) factory.getEntityPersister( entityName );
+				entityPersisters.add( persister );
+				nonScalarReturnList.add( rtn );
+				specifiedAliases.add( fetchRtn.getAlias() );
+				entityAliases.add( fetchRtn.getEntityAliases() );
+				ArrayHelper.addAll( querySpaces, persister.getQuerySpaces() );
+			}
+			else if ( rtn instanceof CollectionFetchReturn ) {
+				CollectionFetchReturn fetchRtn = ( CollectionFetchReturn ) rtn;
+				NonScalarReturn ownerDescriptor = fetchRtn.getOwner();
+				int ownerIndex = nonScalarReturnList.indexOf( ownerDescriptor );
+				collectionOwners.add( new Integer( ownerIndex ) );
+				lockModes.add( fetchRtn.getLockMode() );
+				Queryable ownerPersister = determineAppropriateOwnerPersister( ownerDescriptor );
+				String role = ownerPersister.getEntityName() + '.' + fetchRtn.getOwnerProperty();
+				QueryableCollection persister = ( QueryableCollection ) factory.getCollectionPersister( role );
+				collectionPersisters.add( persister );
+				nonScalarReturnList.add( rtn );
+				specifiedAliases.add( fetchRtn.getAlias() );
+				collectionAliases.add( fetchRtn.getCollectionAliases() );
+				// determine if the collection elements are entities...
+				Type elementType = persister.getElementType();
+				if ( elementType.isEntityType() ) {
+					Queryable elementPersister = ( Queryable ) ( ( EntityType ) elementType ).getAssociatedJoinable( factory );
+					entityPersisters.add( elementPersister );
+					entityOwners.add( new Integer( ownerIndex ) );
+					entityAliases.add( fetchRtn.getElementEntityAliases() );
+					ArrayHelper.addAll( querySpaces, elementPersister.getQuerySpaces() );
+				}
+			}
+			else {
+				throw new HibernateException( "unexpected custom query return type : " + rtn.getClass().getName() );
+			}
+		}
+
+		this.entityPersisters = new Queryable[ entityPersisters.size() ];
+		for ( int i = 0; i < entityPersisters.size(); i++ ) {
+			this.entityPersisters[i] = ( Queryable ) entityPersisters.get( i );
+		}
+		this.entiytOwners = ArrayHelper.toIntArray( entityOwners );
+		this.entityAliases = new EntityAliases[ entityAliases.size() ];
+		for ( int i = 0; i < entityAliases.size(); i++ ) {
+			this.entityAliases[i] = ( EntityAliases ) entityAliases.get( i );
+		}
+
+		this.collectionPersisters = new QueryableCollection[ collectionPersisters.size() ];
+		for ( int i = 0; i < collectionPersisters.size(); i++ ) {
+			this.collectionPersisters[i] = ( QueryableCollection ) collectionPersisters.get( i );
+		}
+		this.collectionOwners = ArrayHelper.toIntArray( collectionOwners );
+		this.collectionAliases = new CollectionAliases[ collectionAliases.size() ];
+		for ( int i = 0; i < collectionAliases.size(); i++ ) {
+			this.collectionAliases[i] = ( CollectionAliases ) collectionAliases.get( i );
+		}
+
+		this.lockModes = new LockMode[ lockModes.size() ];
+		for ( int i = 0; i < lockModes.size(); i++ ) {
+			this.lockModes[i] = ( LockMode ) lockModes.get( i );
+		}
+
+		this.resultTypes = ArrayHelper.toTypeArray( resultTypes );
+		this.transformerAliases = ArrayHelper.toStringArray( specifiedAliases );
+
+		this.rowProcessor = new ResultRowProcessor(
+				hasScalars,
+		        ( ResultColumnProcessor[] ) resultColumnProcessors.toArray( new ResultColumnProcessor[ resultColumnProcessors.size() ] )
+		);
+	}
+
+	private Queryable determineAppropriateOwnerPersister(NonScalarReturn ownerDescriptor) {
+		String entityName = null;
+		if ( ownerDescriptor instanceof RootReturn ) {
+			entityName = ( ( RootReturn ) ownerDescriptor ).getEntityName();
+		}
+		else if ( ownerDescriptor instanceof CollectionReturn ) {
+			CollectionReturn collRtn = ( CollectionReturn ) ownerDescriptor;
+			String role = collRtn.getOwnerEntityName() + "." + collRtn.getOwnerProperty();
+			CollectionPersister persister = getFactory().getCollectionPersister( role );
+			EntityType ownerType = ( EntityType ) persister.getElementType();
+			entityName = ownerType.getAssociatedEntityName( getFactory() );
+		}
+		else if ( ownerDescriptor instanceof FetchReturn ) {
+			FetchReturn fetchRtn = ( FetchReturn ) ownerDescriptor;
+			Queryable persister = determineAppropriateOwnerPersister( fetchRtn.getOwner() );
+			Type ownerType = persister.getPropertyType( fetchRtn.getOwnerProperty() );
+			if ( ownerType.isEntityType() ) {
+				entityName = ( ( EntityType ) ownerType ).getAssociatedEntityName( getFactory() );
+			}
+			else if ( ownerType.isCollectionType() ) {
+				Type ownerCollectionElementType = ( ( CollectionType ) ownerType ).getElementType( getFactory() );
+				if ( ownerCollectionElementType.isEntityType() ) {
+					entityName = ( ( EntityType ) ownerCollectionElementType ).getAssociatedEntityName( getFactory() );
+				}
+			}
+		}
+
+		if ( entityName == null ) {
+			throw new HibernateException( "Could not determine fetch owner : " + ownerDescriptor );
+		}
+
+		return ( Queryable ) getFactory().getEntityPersister( entityName );
+	}
+
+	protected String getQueryIdentifier() {
+		return sql;
+	}
+
+	protected String getSQLString() {
+		return sql;
+	}
+
+	public Set getQuerySpaces() {
+		return querySpaces;
+	}
+
+	protected LockMode[] getLockModes(Map lockModesMap) {
+		return lockModes;
+	}
+
+	protected Loadable[] getEntityPersisters() {
+		return entityPersisters;
+	}
+
+	protected CollectionPersister[] getCollectionPersisters() {
+		return collectionPersisters;
+	}
+
+	protected int[] getCollectionOwners() {
+		return collectionOwners;
+	}
+	
+	protected int[] getOwners() {
+		return entiytOwners;
+	}
+
+	public List list(SessionImplementor session, QueryParameters queryParameters) throws HibernateException {
+		return list( session, queryParameters, querySpaces, resultTypes );
+	}
+
+	public ScrollableResults scroll(
+			final QueryParameters queryParameters,
+			final SessionImplementor session) throws HibernateException {		
+		return scroll(
+				queryParameters,
+				resultTypes,
+				getHolderInstantiator( queryParameters.getResultTransformer(), getReturnAliasesForTransformer() ),
+				session
+		);
+	}
+	
+	static private HolderInstantiator getHolderInstantiator(ResultTransformer resultTransformer, String[] queryReturnAliases) {
+		if ( resultTransformer != null ) {
+			return HolderInstantiator.NOOP_INSTANTIATOR;
+		}
+		else {
+			return new HolderInstantiator(resultTransformer, queryReturnAliases);
+		}
+	}
+	
+	protected Object getResultColumnOrRow(
+			Object[] row,
+	        ResultTransformer transformer,
+	        ResultSet rs,
+	        SessionImplementor session) throws SQLException, HibernateException {
+		return rowProcessor.buildResultRow( row, rs, transformer != null, session );
+	}
+
+	protected List getResultList(List results, ResultTransformer resultTransformer) throws QueryException {
+		// meant to handle dynamic instantiation queries...(Copy from QueryLoader)
+		HolderInstantiator holderInstantiator = HolderInstantiator.getHolderInstantiator(
+				null,
+				resultTransformer,
+				getReturnAliasesForTransformer()
+		);
+		if ( holderInstantiator.isRequired() ) {
+			for ( int i = 0; i < results.size(); i++ ) {
+				Object[] row = ( Object[] ) results.get( i );
+				Object result = holderInstantiator.instantiate(row);
+				results.set( i, result );
+			}
+			
+			return resultTransformer.transformList(results);
+		}
+		else {
+			return results;
+		}
+	}
+
+	private String[] getReturnAliasesForTransformer() {
+		return transformerAliases;
+	}
+	
+	protected EntityAliases[] getEntityAliases() {
+		return entityAliases;
+	}
+
+	protected CollectionAliases[] getCollectionAliases() {
+		return collectionAliases;
+	}
+	
+	public int[] getNamedParameterLocs(String name) throws QueryException {
+		Object loc = namedParameterBindPoints.get( name );
+		if ( loc == null ) {
+			throw new QueryException(
+					"Named parameter does not appear in Query: " + name,
+					sql
+			);
+		}
+		if ( loc instanceof Integer ) {
+			return new int[] { ( ( Integer ) loc ).intValue() };
+		}
+		else {
+			return ArrayHelper.toIntArray( ( List ) loc );
+		}
+	}
+
+
+	public class ResultRowProcessor {
+		private final boolean hasScalars;
+		private ResultColumnProcessor[] columnProcessors;
+
+		public ResultRowProcessor(boolean hasScalars, ResultColumnProcessor[] columnProcessors) {
+			this.hasScalars = hasScalars || ( columnProcessors == null || columnProcessors.length == 0 );
+			this.columnProcessors = columnProcessors;
+		}
+
+		public void prepareForAutoDiscovery(Metadata metadata) throws SQLException {
+			if ( columnProcessors == null || columnProcessors.length == 0 ) {
+				int columns = metadata.getColumnCount();
+				columnProcessors = new ResultColumnProcessor[ columns ];
+				for ( int i = 1; i <= columns; i++ ) {
+					columnProcessors[ i - 1 ] = new ScalarResultColumnProcessor( i );
+				}
+
+			}
+		}
+
+		/**
+		 * Build a logical result row.
+		 * <p/>
+		 * At this point, Loader has already processed all non-scalar result data.  We
+		 * just need to account for scalar result data here...
+		 *
+		 * @param data Entity data defined as "root returns" and already handled by the
+		 * normal Loader mechanism.
+		 * @param resultSet The JDBC result set (positioned at the row currently being processed).
+		 * @param hasTransformer Does this query have an associated {@link ResultTransformer}
+		 * @param session The session from which the query request originated.
+		 * @return The logical result row
+		 * @throws SQLException
+		 * @throws HibernateException
+		 */
+		public Object buildResultRow(
+				Object[] data,
+				ResultSet resultSet,
+				boolean hasTransformer,
+				SessionImplementor session) throws SQLException, HibernateException {
+			Object[] resultRow;
+			if ( !hasScalars ) {
+				resultRow = data;
+			}
+			else {
+				// build an array with indices equal to the total number
+				// of actual returns in the result Hibernate will return
+				// for this query (scalars + non-scalars)
+				resultRow = new Object[ columnProcessors.length ];
+				for ( int i = 0; i < columnProcessors.length; i++ ) {
+					resultRow[i] = columnProcessors[i].extract( data, resultSet, session );
+				}
+			}
+
+			return ( hasTransformer )
+			       ? resultRow
+			       : ( resultRow.length == 1 )
+			         ? resultRow[0]
+			         : resultRow;
+		}
+	}
+
+	private static interface ResultColumnProcessor {
+		public Object extract(Object[] data, ResultSet resultSet, SessionImplementor session) throws SQLException, HibernateException;
+		public void performDiscovery(Metadata metadata, List types, List aliases) throws SQLException, HibernateException;
+	}
+
+	public class NonScalarResultColumnProcessor implements ResultColumnProcessor {
+		private final int position;
+
+		public NonScalarResultColumnProcessor(int position) {
+			this.position = position;
+		}
+
+		public Object extract(
+				Object[] data,
+				ResultSet resultSet,
+				SessionImplementor session) throws SQLException, HibernateException {
+			return data[ position ];
+		}
+
+		public void performDiscovery(Metadata metadata, List types, List aliases) {
+		}
+
+	}
+
+	public class ScalarResultColumnProcessor implements ResultColumnProcessor {
+		private int position = -1;
+		private String alias;
+		private Type type;
+
+		public ScalarResultColumnProcessor(int position) {
+			this.position = position;
+		}
+
+		public ScalarResultColumnProcessor(String alias, Type type) {
+			this.alias = alias;
+			this.type = type;
+		}
+
+		public Object extract(
+				Object[] data,
+				ResultSet resultSet,
+				SessionImplementor session) throws SQLException, HibernateException {
+			return type.nullSafeGet( resultSet, alias, session, null );
+		}
+
+		public void performDiscovery(Metadata metadata, List types, List aliases) throws SQLException {
+			if ( alias == null ) {
+				alias = metadata.getColumnName( position );
+			}
+			else if ( position < 0 ) {
+				position = metadata.resolveColumnPosition( alias );
+			}
+			if ( type == null ) {
+				type = metadata.getHibernateType( position );
+			}
+			types.add( type );
+			aliases.add( alias );
+		}
+	}
+
+	protected void autoDiscoverTypes(ResultSet rs) {
+		try {
+			Metadata metadata = new Metadata( getFactory(), rs );
+			List aliases = new ArrayList();
+			List types = new ArrayList();
+
+			rowProcessor.prepareForAutoDiscovery( metadata );
+
+			for ( int i = 0; i < rowProcessor.columnProcessors.length; i++ ) {
+				rowProcessor.columnProcessors[i].performDiscovery( metadata, types, aliases );
+			}
+
+			resultTypes = ArrayHelper.toTypeArray( types );
+			transformerAliases = ArrayHelper.toStringArray( aliases );
+		}
+		catch ( SQLException e ) {
+			throw new HibernateException( "Exception while trying to autodiscover types.", e );
+		}
+	}
+
+	private static class Metadata {
+		private final SessionFactoryImplementor factory;
+		private final ResultSet resultSet;
+		private final ResultSetMetaData resultSetMetaData;
+
+		public Metadata(SessionFactoryImplementor factory, ResultSet resultSet) throws HibernateException {
+			try {
+				this.factory = factory;
+				this.resultSet = resultSet;
+				this.resultSetMetaData = resultSet.getMetaData();
+			}
+			catch( SQLException e ) {
+				throw new HibernateException( "Could not extract result set metadata", e );
+			}
+		}
+
+		public int getColumnCount() throws HibernateException {
+			try {
+				return resultSetMetaData.getColumnCount();
+			}
+			catch( SQLException e ) {
+				throw new HibernateException( "Could not determine result set column count", e );
+			}
+		}
+
+		public int resolveColumnPosition(String columnName) throws HibernateException {
+			try {
+				return resultSet.findColumn( columnName );
+			}
+			catch( SQLException e ) {
+				throw new HibernateException( "Could not resolve column name in result set [" + columnName + "]", e );
+			}
+		}
+
+		public String getColumnName(int position) throws HibernateException {
+			try {
+				return resultSetMetaData.getColumnName( position );
+			}
+			catch( SQLException e ) {
+				throw new HibernateException( "Could not resolve column name [" + position + "]", e );
+			}
+		}
+
+		public Type getHibernateType(int columnPos) throws SQLException {
+			int columnType = resultSetMetaData.getColumnType( columnPos );
+			int scale = resultSetMetaData.getScale( columnPos );
+			int precision = resultSetMetaData.getPrecision( columnPos );
+			return TypeFactory.heuristicType(
+					factory.getDialect().getHibernateTypeName(
+							columnType,
+							precision,
+							precision,
+							scale
+					)
+			);
+		}
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CustomLoader.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CustomQuery.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CustomQuery.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CustomQuery.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+//$Id: CustomQuery.java 10018 2006-06-15 05:21:06Z steve.ebersole at jboss.com $
+package org.hibernate.loader.custom;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.List;
+
+/**
+ * Extension point allowing any SQL query with named and positional parameters
+ * to be executed by Hibernate, returning managed entities, collections and
+ * simple scalar values.
+ * 
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public interface CustomQuery {
+	/**
+	 * The SQL query string to be performed.
+	 *
+	 * @return The SQL statement string.
+	 */
+	public String getSQL();
+
+	/**
+	 * Any query spaces to apply to the query execution.  Query spaces are
+	 * used in Hibernate's auto-flushing mechanism to determine which
+	 * entities need to be checked for pending changes.
+	 *
+	 * @return The query spaces
+	 */
+	public Set getQuerySpaces();
+
+	/**
+	 * A map representing positions within the supplied {@link #getSQL query} to
+	 * which we need to bind named parameters.
+	 * <p/>
+	 * Optional, may return null if no named parameters.
+	 * <p/>
+	 * The structure of the returned map (if one) as follows:<ol>
+	 * <li>The keys into the map are the named parameter names</li>
+	 * <li>The corresponding value is either an {@link Integer} if the
+	 * parameter occurs only once in the query; or a List of Integers if the
+	 * parameter occurs more than once</li>
+	 * </ol>
+	 */
+	public Map getNamedParameterBindPoints();
+
+	/**
+	 * A collection of {@link Return descriptors} describing the
+	 * JDBC result set to be expected and how to map this result set.
+	 *
+	 * @return List of return descriptors.
+	 */
+	public List getCustomQueryReturns();
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/CustomQuery.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/EntityFetchReturn.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/EntityFetchReturn.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/EntityFetchReturn.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+package org.hibernate.loader.custom;
+
+import org.hibernate.loader.EntityAliases;
+import org.hibernate.LockMode;
+
+/**
+ * Spefically a fetch return that refers to an entity association.
+ *
+ * @author Steve Ebersole
+ */
+public class EntityFetchReturn extends FetchReturn {
+	private final EntityAliases entityAliases;
+
+	public EntityFetchReturn(
+			String alias,
+			EntityAliases entityAliases,
+			NonScalarReturn owner,
+			String ownerProperty,
+			LockMode lockMode) {
+		super( owner, ownerProperty, alias, lockMode );
+		this.entityAliases = entityAliases;
+	}
+
+	public EntityAliases getEntityAliases() {
+		return entityAliases;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/FetchReturn.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/FetchReturn.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/FetchReturn.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+package org.hibernate.loader.custom;
+
+import org.hibernate.LockMode;
+
+/**
+ * Represents a return which names a fetched association.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class FetchReturn extends NonScalarReturn {
+	private final NonScalarReturn owner;
+	private final String ownerProperty;
+
+	/**
+	 * Creates a return descriptor for an association fetch.
+	 *
+	 * @param owner The return descriptor for the owner of the fetch
+	 * @param ownerProperty The name of the property represernting the association being fetched
+	 * @param alias The alias for the fetch
+	 * @param lockMode The lock mode to apply to the fetched association.
+	 */
+	public FetchReturn(
+			NonScalarReturn owner,
+			String ownerProperty,
+			String alias,
+			LockMode lockMode) {
+		super( alias, lockMode );
+		this.owner = owner;
+		this.ownerProperty = ownerProperty;
+	}
+
+	/**
+	 * Retrieves the return descriptor for the owner of this fetch.
+	 *
+	 * @return The owner
+	 */
+	public NonScalarReturn getOwner() {
+		return owner;
+	}
+
+	/**
+	 * The name of the property on the owner which represents this association.
+	 *
+	 * @return The property name.
+	 */
+	public String getOwnerProperty() {
+		return ownerProperty;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/NonScalarReturn.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/NonScalarReturn.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/NonScalarReturn.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+package org.hibernate.loader.custom;
+
+import org.hibernate.LockMode;
+import org.hibernate.HibernateException;
+
+/**
+ * Represents some non-scalar (entity/collection) return within the query result.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class NonScalarReturn implements Return {
+	private final String alias;
+	private final LockMode lockMode;
+
+	public NonScalarReturn(String alias, LockMode lockMode) {
+		this.alias = alias;
+		if ( alias == null ) {
+			throw new HibernateException("alias must be specified");
+		}
+		this.lockMode = lockMode;
+	}
+
+	public String getAlias() {
+		return alias;
+	}
+
+	public LockMode getLockMode() {
+		return lockMode;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/Return.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/Return.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/Return.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+package org.hibernate.loader.custom;
+
+/**
+ * Represents a return in a custom query.
+ *
+ * @author Steve Ebersole
+ */
+public interface Return {
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/RootReturn.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/RootReturn.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/RootReturn.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+package org.hibernate.loader.custom;
+
+import org.hibernate.LockMode;
+import org.hibernate.loader.EntityAliases;
+
+/**
+ * Represents a return which names a "root" entity.
+ * <p/>
+ * A root entity means it is explicitly a "column" in the result, as opposed to
+ * a fetched association.
+ *
+ * @author Steve Ebersole
+ */
+public class RootReturn extends NonScalarReturn {
+	private final String entityName;
+	private final EntityAliases entityAliases;
+
+	public RootReturn(
+			String alias,
+			String entityName,
+			EntityAliases entityAliases,
+			LockMode lockMode) {
+		super( alias, lockMode );
+		this.entityName = entityName;
+		this.entityAliases = entityAliases;
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public EntityAliases getEntityAliases() {
+		return entityAliases;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/ScalarReturn.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/ScalarReturn.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/ScalarReturn.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+package org.hibernate.loader.custom;
+
+import org.hibernate.type.Type;
+
+/**
+ * Represent a scalar (aka simple value) return within a query result.
+ *
+ * @author Steve Ebersole
+ */
+public class ScalarReturn implements Return {
+	private final Type type;
+	private final String columnAlias;
+
+	public ScalarReturn(Type type, String columnAlias) {
+		this.type = type;
+		this.columnAlias = columnAlias;
+	}
+
+	public Type getType() {
+		return type;
+	}
+
+	public String getColumnAlias() {
+		return columnAlias;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines a framework for custom loaders that accept 
+	handwritten SQL
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/SQLCustomQuery.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/SQLCustomQuery.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/SQLCustomQuery.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,232 @@
+//$Id: SQLCustomQuery.java 10018 2006-06-15 05:21:06Z steve.ebersole at jboss.com $
+package org.hibernate.loader.custom.sql;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashMap;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.query.sql.NativeSQLQueryReturn;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.loader.custom.CustomQuery;
+import org.hibernate.persister.collection.SQLLoadableCollection;
+import org.hibernate.persister.entity.SQLLoadable;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Implements Hibernate's built-in support for native SQL queries.
+ * <p/>
+ * This support is built on top of the notion of "custom queries"...
+ * 
+ * @author Gavin King
+ * @author Max Andersen
+ * @author Steve Ebersole
+ */
+public class SQLCustomQuery implements CustomQuery {
+
+	public static final Log log = LogFactory.getLog( SQLCustomQuery.class );
+
+	private final String sql;
+	private final Set querySpaces = new HashSet();
+	private final Map namedParameterBindPoints = new HashMap();
+	private final List customQueryReturns = new ArrayList();
+
+
+	public String getSQL() {
+		return sql;
+	}
+
+	public Set getQuerySpaces() {
+		return querySpaces;
+	}
+
+	public Map getNamedParameterBindPoints() {
+		return namedParameterBindPoints;
+	}
+
+	public List getCustomQueryReturns() {
+		return customQueryReturns;
+	}
+
+	public SQLCustomQuery(
+			final String sqlQuery,
+			final NativeSQLQueryReturn[] queryReturns,
+			final Collection additionalQuerySpaces,
+			final SessionFactoryImplementor factory) throws HibernateException {
+
+		log.trace( "starting processing of sql query [" + sqlQuery + "]" );
+		SQLQueryReturnProcessor processor = new SQLQueryReturnProcessor(queryReturns, factory);
+		SQLQueryReturnProcessor.ResultAliasContext aliasContext = processor.process();
+
+
+//		Map[] propertyResultMaps =  (Map[]) processor.getPropertyResults().toArray( new Map[0] );
+//		Map[] collectionResultMaps =  (Map[]) processor.getCollectionPropertyResults().toArray( new Map[0] );
+//
+//		List collectionSuffixes = new ArrayList();
+//		List collectionOwnerAliases = processor.getCollectionOwnerAliases();
+//		List collectionPersisters = processor.getCollectionPersisters();
+//		int size = collectionPersisters.size();
+//		if (size!=0) {
+//			collectionOwners = new int[size];
+//			collectionRoles = new String[size];
+//			//collectionDescriptors = new CollectionAliases[size];
+//			for ( int i=0; i<size; i++ ) {
+//				CollectionPersister collectionPersister = (CollectionPersister) collectionPersisters.get(i);
+//				collectionRoles[i] = ( collectionPersister ).getRole();
+//				collectionOwners[i] = processor.getAliases().indexOf( collectionOwnerAliases.get(i) );
+//				String suffix = i + "__";
+//				collectionSuffixes.add(suffix);
+//				//collectionDescriptors[i] = new GeneratedCollectionAliases( collectionResultMaps[i], collectionPersister, suffix );
+//			}
+//		}
+//		else {
+//			collectionRoles = null;
+//			//collectionDescriptors = null;
+//			collectionOwners = null;
+//		}
+//
+//		String[] aliases = ArrayHelper.toStringArray( processor.getAliases() );
+//		String[] collAliases = ArrayHelper.toStringArray( processor.getCollectionAliases() );
+//		String[] collSuffixes = ArrayHelper.toStringArray(collectionSuffixes);
+//
+//		SQLLoadable[] entityPersisters = (SQLLoadable[]) processor.getPersisters().toArray( new SQLLoadable[0] );
+//		SQLLoadableCollection[] collPersisters = (SQLLoadableCollection[]) collectionPersisters.toArray( new SQLLoadableCollection[0] );
+//        lockModes = (LockMode[]) processor.getLockModes().toArray( new LockMode[0] );
+//
+//        scalarColumnAliases = ArrayHelper.toStringArray( processor.getScalarColumnAliases() );
+//		scalarTypes = ArrayHelper.toTypeArray( processor.getScalarTypes() );
+//
+//		// need to match the "sequence" of what we return. scalar first, entity last.
+//		returnAliases = ArrayHelper.join(scalarColumnAliases, aliases);
+//
+//		String[] suffixes = BasicLoader.generateSuffixes(entityPersisters.length);
+
+		SQLQueryParser parser = new SQLQueryParser( sqlQuery, new ParserContext( aliasContext ) );
+		this.sql = parser.process();
+		this.namedParameterBindPoints.putAll( parser.getNamedParameters() );
+
+//		SQLQueryParser parser = new SQLQueryParser(
+//				sqlQuery,
+//				processor.getAlias2Persister(),
+//				processor.getAlias2Return(),
+//				aliases,
+//				collAliases,
+//				collPersisters,
+//				suffixes,
+//				collSuffixes
+//		);
+//
+//		sql = parser.process();
+//
+//		namedParameterBindPoints = parser.getNamedParameters();
+
+
+		customQueryReturns.addAll( processor.generateCustomReturns( parser.queryHasAliases() ) );
+
+//		// Populate entityNames, entityDescrptors and querySpaces
+//		entityNames = new String[entityPersisters.length];
+//		entityDescriptors = new EntityAliases[entityPersisters.length];
+//		for (int i = 0; i < entityPersisters.length; i++) {
+//			SQLLoadable persister = entityPersisters[i];
+//			//alias2Persister.put( aliases[i], persister );
+//			//TODO: Does not consider any other tables referenced in the query
+//			ArrayHelper.addAll( querySpaces, persister.getQuerySpaces() );
+//			entityNames[i] = persister.getEntityName();
+//			if ( parser.queryHasAliases() ) {
+//				entityDescriptors[i] = new DefaultEntityAliases(
+//						propertyResultMaps[i],
+//						entityPersisters[i],
+//						suffixes[i]
+//					);
+//			}
+//			else {
+//				entityDescriptors[i] = new ColumnEntityAliases(
+//						propertyResultMaps[i],
+//						entityPersisters[i],
+//						suffixes[i]
+//					);
+//			}
+//		}
+		if ( additionalQuerySpaces != null ) {
+			querySpaces.addAll( additionalQuerySpaces );
+		}
+
+//		if (size!=0) {
+//			collectionDescriptors = new CollectionAliases[size];
+//			for ( int i=0; i<size; i++ ) {
+//				CollectionPersister collectionPersister = (CollectionPersister) collectionPersisters.get(i);
+//				String suffix = i + "__";
+//				if( parser.queryHasAliases() ) {
+//					collectionDescriptors[i] = new GeneratedCollectionAliases( collectionResultMaps[i], collectionPersister, suffix );
+//				} else {
+//					collectionDescriptors[i] = new ColumnCollectionAliases( collectionResultMaps[i], (SQLLoadableCollection) collectionPersister );
+//				}
+//			}
+//		}
+//		else {
+//			collectionDescriptors = null;
+//		}
+//
+//
+//		// Resolve owners
+//		Map alias2OwnerAlias = processor.getAlias2OwnerAlias();
+//		int[] ownersArray = new int[entityPersisters.length];
+//		for ( int j=0; j < aliases.length; j++ ) {
+//			String ownerAlias = (String) alias2OwnerAlias.get( aliases[j] );
+//			if ( StringHelper.isNotEmpty(ownerAlias) ) {
+//				ownersArray[j] =  processor.getAliases().indexOf( ownerAlias );
+//			}
+//			else {
+//				ownersArray[j] = -1;
+//			}
+//		}
+//		if ( ArrayHelper.isAllNegative(ownersArray) ) {
+//			ownersArray = null;
+//		}
+//		this.entityOwners = ownersArray;
+
+	}
+
+
+	private static class ParserContext implements SQLQueryParser.ParserContext {
+
+		private final SQLQueryReturnProcessor.ResultAliasContext aliasContext;
+
+		public ParserContext(SQLQueryReturnProcessor.ResultAliasContext aliasContext) {
+			this.aliasContext = aliasContext;
+		}
+
+		public boolean isEntityAlias(String alias) {
+			return getEntityPersisterByAlias( alias ) != null;
+		}
+
+		public SQLLoadable getEntityPersisterByAlias(String alias) {
+			return aliasContext.getEntityPersister( alias );
+		}
+
+		public String getEntitySuffixByAlias(String alias) {
+			return aliasContext.getEntitySuffix( alias );
+		}
+
+		public boolean isCollectionAlias(String alias) {
+			return getCollectionPersisterByAlias( alias ) != null;
+		}
+
+		public SQLLoadableCollection getCollectionPersisterByAlias(String alias) {
+			return aliasContext.getCollectionPersister( alias );
+		}
+
+		public String getCollectionSuffixByAlias(String alias) {
+			return aliasContext.getCollectionSuffix( alias );
+		}
+
+		public Map getPropertyResultsMapByAlias(String alias) {
+			return aliasContext.getPropertyResultsMap( alias );
+		}
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/SQLCustomQuery.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/SQLQueryParser.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/SQLQueryParser.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/SQLQueryParser.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,274 @@
+//$Id: SQLQueryParser.java 10067 2006-06-28 13:24:59Z steve.ebersole at jboss.com $
+package org.hibernate.loader.custom.sql;
+
+import org.hibernate.QueryException;
+import org.hibernate.engine.query.ParameterParser;
+import org.hibernate.persister.collection.SQLLoadableCollection;
+import org.hibernate.persister.entity.SQLLoadable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Gavin King
+ * @author Max Andersen
+ * @author Steve Ebersole
+ */
+public class SQLQueryParser {
+
+	private final String originalQueryString;
+	private final ParserContext context;
+
+	private final Map namedParameters = new HashMap();
+	private long aliasesFound = 0;
+
+	static interface ParserContext {
+		boolean isEntityAlias(String aliasName);
+		SQLLoadable getEntityPersisterByAlias(String alias);
+		String getEntitySuffixByAlias(String alias);
+		boolean isCollectionAlias(String aliasName);
+		SQLLoadableCollection getCollectionPersisterByAlias(String alias);
+		String getCollectionSuffixByAlias(String alias);
+		Map getPropertyResultsMapByAlias(String alias);
+	}
+
+	public SQLQueryParser(String queryString, ParserContext context) {
+		this.originalQueryString = queryString;
+		this.context = context;
+	}
+
+	public Map getNamedParameters() {
+		return namedParameters;
+	}
+
+	public boolean queryHasAliases() {
+		return aliasesFound>0;
+	}
+
+	public String process() {
+		return substituteParams( substituteBrackets( originalQueryString ) );
+	}
+
+	// TODO: should "record" how many properties we have reffered to - and if we 
+	//       don't get'em'all we throw an exception! Way better than trial and error ;)
+	private String substituteBrackets(String sqlQuery) throws QueryException {
+
+		StringBuffer result = new StringBuffer( sqlQuery.length() + 20 );
+		int left, right;
+
+		// replace {....} with corresponding column aliases
+		for ( int curr = 0; curr < sqlQuery.length(); curr = right + 1 ) {
+			if ( ( left = sqlQuery.indexOf( '{', curr ) ) < 0 ) {
+				// No additional open braces found in the string, append the
+				// rest of the string in its entirty and quit this loop
+				result.append( sqlQuery.substring( curr ) );
+				break;
+			}
+
+			// apend everything up until the next encountered open brace
+			result.append( sqlQuery.substring( curr, left ) );
+
+			if ( ( right = sqlQuery.indexOf( '}', left + 1 ) ) < 0 ) {
+				throw new QueryException( "Unmatched braces for alias path", sqlQuery );
+			}
+
+			String aliasPath = sqlQuery.substring( left + 1, right );
+			int firstDot = aliasPath.indexOf( '.' );
+			if ( firstDot == -1 ) {
+				if ( context.isEntityAlias( aliasPath ) ) {
+					// it is a simple table alias {foo}
+					result.append( aliasPath );
+					aliasesFound++;
+				} 
+				else {
+					// passing through anything we do not know : to support jdbc escape sequences HB-898
+					result.append( '{' ).append(aliasPath).append( '}' );					
+				}
+			}
+			else {
+				String aliasName = aliasPath.substring(0, firstDot);
+				boolean isCollection = context.isCollectionAlias( aliasName );
+				boolean isEntity = context.isEntityAlias( aliasName );
+				
+				if ( isCollection ) {
+					// The current alias is referencing the collection to be eagerly fetched
+					String propertyName = aliasPath.substring( firstDot + 1 );
+					result.append( resolveCollectionProperties( aliasName, propertyName ) );
+					aliasesFound++;
+				} 
+				else if ( isEntity ) {
+					// it is a property reference {foo.bar}
+					String propertyName = aliasPath.substring( firstDot + 1 );
+					result.append( resolveProperties( aliasName, propertyName ) );
+					aliasesFound++;
+				}
+				else {
+					// passing through anything we do not know : to support jdbc escape sequences HB-898
+					result.append( '{' ).append(aliasPath).append( '}' );
+				}
+	
+			}
+		}
+
+		// Possibly handle :something parameters for the query ?
+
+		return result.toString();
+	}	
+
+	private String resolveCollectionProperties(
+			String aliasName,
+			String propertyName) {
+
+		Map fieldResults = context.getPropertyResultsMapByAlias( aliasName );
+		SQLLoadableCollection collectionPersister = context.getCollectionPersisterByAlias( aliasName );
+		String collectionSuffix = context.getCollectionSuffixByAlias( aliasName );
+
+		if ( "*".equals( propertyName ) ) {
+			if( !fieldResults.isEmpty() ) {
+				throw new QueryException("Using return-propertys together with * syntax is not supported.");
+			}
+			
+			String selectFragment = collectionPersister.selectFragment( aliasName, collectionSuffix );
+			aliasesFound++;
+			return selectFragment 
+						+ ", " 
+						+ resolveProperties( aliasName, propertyName );
+		}
+		else if ( "element.*".equals( propertyName ) ) {
+			return resolveProperties( aliasName, "*" );
+		}
+		else {
+			String[] columnAliases;
+
+			// Let return-propertys override whatever the persister has for aliases.
+			columnAliases = ( String[] ) fieldResults.get(propertyName);
+			if ( columnAliases==null ) {
+				columnAliases = collectionPersister.getCollectionPropertyColumnAliases( propertyName, collectionSuffix );
+			}
+			
+			if ( columnAliases == null || columnAliases.length == 0 ) {
+				throw new QueryException(
+						"No column name found for property [" + propertyName + "] for alias [" + aliasName + "]",
+						originalQueryString
+				);
+			}
+			if ( columnAliases.length != 1 ) {
+				// TODO: better error message since we actually support composites if names are explicitly listed.
+				throw new QueryException(
+						"SQL queries only support properties mapped to a single column - property [" +
+						propertyName + "] is mapped to " + columnAliases.length + " columns.",
+						originalQueryString
+				);
+			}
+			aliasesFound++;
+			return columnAliases[0];
+		
+		}
+	}
+	private String resolveProperties(
+			String aliasName,
+	        String propertyName) {
+		Map fieldResults = context.getPropertyResultsMapByAlias( aliasName );
+		SQLLoadable persister = context.getEntityPersisterByAlias( aliasName );
+		String suffix = context.getEntitySuffixByAlias( aliasName );
+
+		if ( "*".equals( propertyName ) ) {
+			if( !fieldResults.isEmpty() ) {
+				throw new QueryException("Using return-propertys together with * syntax is not supported.");
+			}			
+			aliasesFound++;
+			return persister.selectFragment( aliasName, suffix ) ;
+		}
+		else {
+
+			String[] columnAliases;
+
+			// Let return-propertys override whatever the persister has for aliases.
+			columnAliases = (String[]) fieldResults.get( propertyName );
+			if ( columnAliases == null ) {
+				columnAliases = persister.getSubclassPropertyColumnAliases( propertyName, suffix );
+			}
+
+			if ( columnAliases == null || columnAliases.length == 0 ) {
+				throw new QueryException(
+						"No column name found for property [" + propertyName + "] for alias [" + aliasName + "]",
+						originalQueryString
+				);
+			}
+			if ( columnAliases.length != 1 ) {
+				// TODO: better error message since we actually support composites if names are explicitly listed.
+				throw new QueryException(
+						"SQL queries only support properties mapped to a single column - property [" + propertyName + "] is mapped to " + columnAliases.length + " columns.",
+						originalQueryString
+				);
+			}			
+			aliasesFound++;
+			return columnAliases[0];
+		}
+	}
+
+	/**
+	 * Substitues JDBC parameter placeholders (?) for all encountered
+	 * parameter specifications.  It also tracks the positions of these
+	 * parameter specifications within the query string.  This accounts for
+	 * ordinal-params, named-params, and ejb3-positional-params.
+	 *
+	 * @param sqlString The query string.
+	 * @return The SQL query with parameter substitution complete.
+	 */
+	private String substituteParams(String sqlString) {
+		ParameterSubstitutionRecognizer recognizer = new ParameterSubstitutionRecognizer();
+		ParameterParser.parse( sqlString, recognizer );
+
+		namedParameters.clear();
+		namedParameters.putAll( recognizer.namedParameterBindPoints );
+
+		return recognizer.result.toString();
+	}
+
+	public static class ParameterSubstitutionRecognizer implements ParameterParser.Recognizer {
+		StringBuffer result = new StringBuffer();
+		Map namedParameterBindPoints = new HashMap();
+		int parameterCount = 0;
+
+		public void outParameter(int position) {
+			result.append( '?' );
+		}
+
+		public void ordinalParameter(int position) {
+			result.append( '?' );
+		}
+
+		public void namedParameter(String name, int position) {
+			addNamedParameter( name );
+			result.append( '?' );
+		}
+
+		public void jpaPositionalParameter(String name, int position) {
+			namedParameter( name, position );
+		}
+
+		public void other(char character) {
+			result.append( character );
+		}
+
+		private void addNamedParameter(String name) {
+			Integer loc = new Integer( parameterCount++ );
+			Object o = namedParameterBindPoints.get( name );
+			if ( o == null ) {
+				namedParameterBindPoints.put( name, loc );
+			}
+			else if ( o instanceof Integer ) {
+				ArrayList list = new ArrayList( 4 );
+				list.add( o );
+				list.add( loc );
+				namedParameterBindPoints.put( name, list );
+			}
+			else {
+				( ( List ) o ).add( loc );
+			}
+		}
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/SQLQueryParser.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/SQLQueryReturnProcessor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/SQLQueryReturnProcessor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/custom/sql/SQLQueryReturnProcessor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,502 @@
+//$Id: SQLQueryReturnProcessor.java 7370 2005-07-04 11:17:33Z maxcsaucdk $
+package org.hibernate.loader.custom.sql;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.loader.custom.Return;
+import org.hibernate.loader.custom.ScalarReturn;
+import org.hibernate.loader.custom.RootReturn;
+import org.hibernate.loader.custom.CollectionReturn;
+import org.hibernate.loader.custom.ColumnCollectionAliases;
+import org.hibernate.loader.custom.FetchReturn;
+import org.hibernate.loader.custom.CollectionFetchReturn;
+import org.hibernate.loader.custom.NonScalarReturn;
+import org.hibernate.loader.custom.EntityFetchReturn;
+import org.hibernate.loader.BasicLoader;
+import org.hibernate.loader.EntityAliases;
+import org.hibernate.loader.DefaultEntityAliases;
+import org.hibernate.loader.ColumnEntityAliases;
+import org.hibernate.loader.CollectionAliases;
+import org.hibernate.loader.GeneratedCollectionAliases;
+import org.hibernate.engine.query.sql.NativeSQLQueryReturn;
+import org.hibernate.engine.query.sql.NativeSQLQueryCollectionReturn;
+import org.hibernate.engine.query.sql.NativeSQLQueryScalarReturn;
+import org.hibernate.engine.query.sql.NativeSQLQueryNonScalarReturn;
+import org.hibernate.engine.query.sql.NativeSQLQueryJoinReturn;
+import org.hibernate.engine.query.sql.NativeSQLQueryRootReturn;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.persister.collection.SQLLoadableCollection;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.SQLLoadable;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Responsible for processing the series of {@link org.hibernate.engine.query.sql.NativeSQLQueryReturn returns}
+ * defined by a {@link org.hibernate.engine.query.sql.NativeSQLQuerySpecification} and
+ * breaking them down into a series of {@link Return returns} for use within the
+ * {@link org.hibernate.loader.custom.CustomLoader}.
+ *
+ * @author Gavin King
+ * @author Max Andersen
+ * @author Steve Ebersole
+ */
+public class SQLQueryReturnProcessor {
+
+	public static final Log log = LogFactory.getLog( SQLQueryReturnProcessor.class );
+
+	private NativeSQLQueryReturn[] queryReturns;
+
+//	private final List persisters = new ArrayList();
+
+	private final Map alias2Return = new HashMap();
+	private final Map alias2OwnerAlias = new HashMap();
+
+	private final Map alias2Persister = new HashMap();
+	private final Map alias2Suffix = new HashMap();
+
+	private final Map alias2CollectionPersister = new HashMap();
+	private final Map alias2CollectionSuffix = new HashMap();
+
+	private final Map entityPropertyResultMaps = new HashMap();
+	private final Map collectionPropertyResultMaps = new HashMap();
+
+//	private final List scalarTypes = new ArrayList();
+//	private final List scalarColumnAliases = new ArrayList();
+
+	private final SessionFactoryImplementor factory;
+
+//	private List collectionOwnerAliases = new ArrayList();
+//	private List collectionAliases = new ArrayList();
+//	private List collectionPersisters = new ArrayList();
+//	private List collectionResults = new ArrayList();
+
+	private int entitySuffixSeed = 0;
+	private int collectionSuffixSeed = 0;
+
+
+	public SQLQueryReturnProcessor(NativeSQLQueryReturn[] queryReturns, SessionFactoryImplementor factory) {
+		this.queryReturns = queryReturns;
+		this.factory = factory;
+	}
+
+	/*package*/ class ResultAliasContext {
+		public SQLLoadable getEntityPersister(String alias) {
+			return ( SQLLoadable ) alias2Persister.get( alias );
+		}
+
+		public SQLLoadableCollection getCollectionPersister(String alias) {
+			return ( SQLLoadableCollection ) alias2CollectionPersister.get( alias );
+		}
+
+		public String getEntitySuffix(String alias) {
+			return ( String ) alias2Suffix.get( alias );
+		}
+
+		public String getCollectionSuffix(String alias) {
+			return ( String ) alias2CollectionSuffix.get ( alias );
+		}
+
+		public String getOwnerAlias(String alias) {
+			return ( String ) alias2OwnerAlias.get( alias );
+		}
+
+		public Map getPropertyResultsMap(String alias) {
+			return internalGetPropertyResultsMap( alias );
+		}
+	}
+
+	private Map internalGetPropertyResultsMap(String alias) {
+		NativeSQLQueryReturn rtn = ( NativeSQLQueryReturn ) alias2Return.get( alias );
+		if ( rtn instanceof NativeSQLQueryNonScalarReturn ) {
+			return ( ( NativeSQLQueryNonScalarReturn ) rtn ).getPropertyResultsMap();
+		}
+		else {
+			return null;
+		}
+	}
+
+	private boolean hasPropertyResultMap(String alias) {
+		Map propertyMaps = internalGetPropertyResultsMap( alias );
+		return propertyMaps != null && ! propertyMaps.isEmpty();
+	}
+
+	public ResultAliasContext process() {
+		// first, break down the returns into maps keyed by alias
+		// so that role returns can be more easily resolved to their owners
+		for ( int i = 0; i < queryReturns.length; i++ ) {
+			if ( queryReturns[i] instanceof NativeSQLQueryNonScalarReturn ) {
+				NativeSQLQueryNonScalarReturn rtn = ( NativeSQLQueryNonScalarReturn ) queryReturns[i];
+				alias2Return.put( rtn.getAlias(), rtn );
+				if ( rtn instanceof NativeSQLQueryJoinReturn ) {
+					NativeSQLQueryJoinReturn fetchReturn = ( NativeSQLQueryJoinReturn ) rtn;
+					alias2OwnerAlias.put( fetchReturn.getAlias(), fetchReturn.getOwnerAlias() );
+				}
+			}
+		}
+
+		// Now, process the returns
+		for ( int i = 0; i < queryReturns.length; i++ ) {
+			processReturn( queryReturns[i] );
+		}
+
+		return new ResultAliasContext();
+	}
+
+	public List generateCustomReturns(boolean queryHadAliases) {
+		List customReturns = new ArrayList();
+		Map customReturnsByAlias = new HashMap();
+		for ( int i = 0; i < queryReturns.length; i++ ) {
+			if ( queryReturns[i] instanceof NativeSQLQueryScalarReturn ) {
+				NativeSQLQueryScalarReturn rtn = ( NativeSQLQueryScalarReturn ) queryReturns[i];
+				customReturns.add( new ScalarReturn( rtn.getType(), rtn.getColumnAlias() ) );
+			}
+			else if ( queryReturns[i] instanceof NativeSQLQueryRootReturn ) {
+				NativeSQLQueryRootReturn rtn = ( NativeSQLQueryRootReturn ) queryReturns[i];
+				String alias = rtn.getAlias();
+				EntityAliases entityAliases;
+				if ( queryHadAliases || hasPropertyResultMap( alias ) ) {
+					entityAliases = new DefaultEntityAliases(
+							( Map ) entityPropertyResultMaps.get( alias ),
+							( SQLLoadable ) alias2Persister.get( alias ),
+							( String ) alias2Suffix.get( alias )
+					);
+				}
+				else {
+					entityAliases = new ColumnEntityAliases(
+							( Map ) entityPropertyResultMaps.get( alias ),
+							( SQLLoadable ) alias2Persister.get( alias ),
+							( String ) alias2Suffix.get( alias )
+					);
+				}
+				RootReturn customReturn = new RootReturn(
+						alias,
+						rtn.getReturnEntityName(),
+						entityAliases,
+						rtn.getLockMode()
+				);
+				customReturns.add( customReturn );
+				customReturnsByAlias.put( rtn.getAlias(), customReturn );
+			}
+			else if ( queryReturns[i] instanceof NativeSQLQueryCollectionReturn ) {
+				NativeSQLQueryCollectionReturn rtn = ( NativeSQLQueryCollectionReturn ) queryReturns[i];
+				String alias = rtn.getAlias();
+				SQLLoadableCollection persister = ( SQLLoadableCollection ) alias2CollectionPersister.get( alias );
+				boolean isEntityElements = persister.getElementType().isEntityType();
+				CollectionAliases collectionAliases;
+				EntityAliases elementEntityAliases = null;
+				if ( queryHadAliases || hasPropertyResultMap( alias ) ) {
+					collectionAliases = new GeneratedCollectionAliases(
+							( Map ) collectionPropertyResultMaps.get( alias ),
+							( SQLLoadableCollection ) alias2CollectionPersister.get( alias ),
+							( String ) alias2CollectionSuffix.get( alias )
+					);
+					if ( isEntityElements ) {
+						elementEntityAliases = new DefaultEntityAliases(
+								( Map ) entityPropertyResultMaps.get( alias ),
+								( SQLLoadable ) alias2Persister.get( alias ),
+								( String ) alias2Suffix.get( alias )
+						);
+					}
+				}
+				else {
+					collectionAliases = new ColumnCollectionAliases(
+							( Map ) collectionPropertyResultMaps.get( alias ),
+							( SQLLoadableCollection ) alias2CollectionPersister.get( alias )
+					);
+					if ( isEntityElements ) {
+						elementEntityAliases = new ColumnEntityAliases(
+								( Map ) entityPropertyResultMaps.get( alias ),
+								( SQLLoadable ) alias2Persister.get( alias ),
+								( String ) alias2Suffix.get( alias )
+						);
+					}
+				}
+				CollectionReturn customReturn = new CollectionReturn(
+						alias,
+						rtn.getOwnerEntityName(),
+						rtn.getOwnerProperty(),
+						collectionAliases,
+				        elementEntityAliases,
+						rtn.getLockMode()
+				);
+				customReturns.add( customReturn );
+				customReturnsByAlias.put( rtn.getAlias(), customReturn );
+			}
+			else if ( queryReturns[i] instanceof NativeSQLQueryJoinReturn ) {
+				NativeSQLQueryJoinReturn rtn = ( NativeSQLQueryJoinReturn ) queryReturns[i];
+				String alias = rtn.getAlias();
+				FetchReturn customReturn;
+				NonScalarReturn ownerCustomReturn = ( NonScalarReturn ) customReturnsByAlias.get( rtn.getOwnerAlias() );
+				if ( alias2CollectionPersister.containsKey( alias ) ) {
+					SQLLoadableCollection persister = ( SQLLoadableCollection ) alias2CollectionPersister.get( alias );
+					boolean isEntityElements = persister.getElementType().isEntityType();
+					CollectionAliases collectionAliases;
+					EntityAliases elementEntityAliases = null;
+					if ( queryHadAliases || hasPropertyResultMap( alias ) ) {
+						collectionAliases = new GeneratedCollectionAliases(
+								( Map ) collectionPropertyResultMaps.get( alias ),
+								persister,
+								( String ) alias2CollectionSuffix.get( alias )
+						);
+						if ( isEntityElements ) {
+							elementEntityAliases = new DefaultEntityAliases(
+									( Map ) entityPropertyResultMaps.get( alias ),
+									( SQLLoadable ) alias2Persister.get( alias ),
+									( String ) alias2Suffix.get( alias )
+							);
+						}
+					}
+					else {
+						collectionAliases = new ColumnCollectionAliases(
+								( Map ) collectionPropertyResultMaps.get( alias ),
+								persister
+						);
+						if ( isEntityElements ) {
+							elementEntityAliases = new ColumnEntityAliases(
+									( Map ) entityPropertyResultMaps.get( alias ),
+									( SQLLoadable ) alias2Persister.get( alias ),
+									( String ) alias2Suffix.get( alias )
+							);
+						}
+					}
+					customReturn = new CollectionFetchReturn(
+							alias,
+							ownerCustomReturn,
+							rtn.getOwnerProperty(),
+							collectionAliases,
+					        elementEntityAliases,
+							rtn.getLockMode()
+					);
+				}
+				else {
+					EntityAliases entityAliases;
+					if ( queryHadAliases || hasPropertyResultMap( alias ) ) {
+						entityAliases = new DefaultEntityAliases(
+								( Map ) entityPropertyResultMaps.get( alias ),
+								( SQLLoadable ) alias2Persister.get( alias ),
+								( String ) alias2Suffix.get( alias )
+						);
+					}
+					else {
+						entityAliases = new ColumnEntityAliases(
+								( Map ) entityPropertyResultMaps.get( alias ),
+								( SQLLoadable ) alias2Persister.get( alias ),
+								( String ) alias2Suffix.get( alias )
+						);
+					}
+					customReturn = new EntityFetchReturn(
+							alias,
+							entityAliases,
+							ownerCustomReturn,
+							rtn.getOwnerProperty(),
+							rtn.getLockMode()
+					);
+				}
+				customReturns.add( customReturn );
+				customReturnsByAlias.put( alias, customReturn );
+			}
+		}
+		return customReturns;
+	}
+
+	private SQLLoadable getSQLLoadable(String entityName) throws MappingException {
+		EntityPersister persister = factory.getEntityPersister( entityName );
+		if ( !(persister instanceof SQLLoadable) ) {
+			throw new MappingException( "class persister is not SQLLoadable: " + entityName );
+		}
+		return (SQLLoadable) persister;
+	}
+
+	private String generateEntitySuffix() {
+		return BasicLoader.generateSuffixes( entitySuffixSeed++, 1 )[0];
+	}
+
+	private String generateCollectionSuffix() {
+		return collectionSuffixSeed++ + "__";
+	}
+
+	private void processReturn(NativeSQLQueryReturn rtn) {
+		if ( rtn instanceof NativeSQLQueryScalarReturn ) {
+			processScalarReturn( ( NativeSQLQueryScalarReturn ) rtn );
+		}
+		else if ( rtn instanceof NativeSQLQueryRootReturn ) {
+			processRootReturn( ( NativeSQLQueryRootReturn ) rtn );
+		}
+		else if ( rtn instanceof NativeSQLQueryCollectionReturn ) {
+			processCollectionReturn( ( NativeSQLQueryCollectionReturn ) rtn );
+		}
+		else {
+			processJoinReturn( ( NativeSQLQueryJoinReturn ) rtn );
+		}
+	}
+
+	private void processScalarReturn(NativeSQLQueryScalarReturn typeReturn) {
+//		scalarColumnAliases.add( typeReturn.getColumnAlias() );
+//		scalarTypes.add( typeReturn.getType() );
+	}
+
+	private void processRootReturn(NativeSQLQueryRootReturn rootReturn) {
+		if ( alias2Persister.containsKey( rootReturn.getAlias() ) ) {
+			// already been processed...
+			return;
+		}
+
+		SQLLoadable persister = getSQLLoadable( rootReturn.getReturnEntityName() );
+		addPersister( rootReturn.getAlias(), rootReturn.getPropertyResultsMap(), persister );
+	}
+
+	/**
+	 * @param propertyResult
+	 * @param persister
+	 */
+	private void addPersister(String alias, Map propertyResult, SQLLoadable persister) {
+		alias2Persister.put( alias, persister );
+		String suffix = generateEntitySuffix();
+		log.trace( "mapping alias [" + alias + "] to entity-suffix [" + suffix + "]" );
+		alias2Suffix.put( alias, suffix );
+		entityPropertyResultMaps.put( alias, propertyResult );
+	}
+
+	private void addCollection(String role, String alias, Map propertyResults) {
+		SQLLoadableCollection collectionPersister = ( SQLLoadableCollection ) factory.getCollectionPersister( role );
+		alias2CollectionPersister.put( alias, collectionPersister );
+		String suffix = generateCollectionSuffix();
+		log.trace( "mapping alias [" + alias + "] to collection-suffix [" + suffix + "]" );
+		alias2CollectionSuffix.put( alias, suffix );
+		collectionPropertyResultMaps.put( alias, propertyResults );
+
+		if ( collectionPersister.isOneToMany() ) {
+			SQLLoadable persister = ( SQLLoadable ) collectionPersister.getElementPersister();
+			addPersister( alias, filter( propertyResults ), persister );
+		}
+	}
+
+	private Map filter(Map propertyResults) {
+		Map result = new HashMap( propertyResults.size() );
+
+		String keyPrefix = "element.";
+
+		Iterator iter = propertyResults.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry element = ( Map.Entry ) iter.next();
+			String path = ( String ) element.getKey();
+			if ( path.startsWith( keyPrefix ) ) {
+				result.put( path.substring( keyPrefix.length() ), element.getValue() );
+			}
+		}
+
+		return result;
+	}
+
+	private void processCollectionReturn(NativeSQLQueryCollectionReturn collectionReturn) {
+		// we are initializing an owned collection
+		//collectionOwners.add( new Integer(-1) );
+//		collectionOwnerAliases.add( null );
+		String role = collectionReturn.getOwnerEntityName() + '.' + collectionReturn.getOwnerProperty();
+		addCollection(
+				role,
+				collectionReturn.getAlias(),
+				collectionReturn.getPropertyResultsMap()
+		);
+	}
+
+	private void processJoinReturn(NativeSQLQueryJoinReturn fetchReturn) {
+		String alias = fetchReturn.getAlias();
+//		if ( alias2Persister.containsKey( alias ) || collectionAliases.contains( alias ) ) {
+		if ( alias2Persister.containsKey( alias ) || alias2CollectionPersister.containsKey( alias ) ) {
+			// already been processed...
+			return;
+		}
+
+		String ownerAlias = fetchReturn.getOwnerAlias();
+
+		// Make sure the owner alias is known...
+		if ( !alias2Return.containsKey( ownerAlias ) ) {
+			throw new HibernateException( "Owner alias [" + ownerAlias + "] is unknown for alias [" + alias + "]" );
+		}
+
+		// If this return's alias has not been processed yet, do so b4 further processing of this return
+		if ( !alias2Persister.containsKey( ownerAlias ) ) {
+			NativeSQLQueryNonScalarReturn ownerReturn = ( NativeSQLQueryNonScalarReturn ) alias2Return.get(ownerAlias);
+			processReturn( ownerReturn );
+		}
+
+		SQLLoadable ownerPersister = ( SQLLoadable ) alias2Persister.get( ownerAlias );
+		Type returnType = ownerPersister.getPropertyType( fetchReturn.getOwnerProperty() );
+
+		if ( returnType.isCollectionType() ) {
+			String role = ownerPersister.getEntityName() + '.' + fetchReturn.getOwnerProperty();
+			addCollection( role, alias, fetchReturn.getPropertyResultsMap() );
+//			collectionOwnerAliases.add( ownerAlias );
+		}
+		else if ( returnType.isEntityType() ) {
+			EntityType eType = ( EntityType ) returnType;
+			String returnEntityName = eType.getAssociatedEntityName();
+			SQLLoadable persister = getSQLLoadable( returnEntityName );
+			addPersister( alias, fetchReturn.getPropertyResultsMap(), persister );
+		}
+
+	}
+
+//	public List getCollectionAliases() {
+//		return collectionAliases;
+//	}
+//
+//	/*public List getCollectionOwners() {
+//		return collectionOwners;
+//	}*/
+//
+//	public List getCollectionOwnerAliases() {
+//		return collectionOwnerAliases;
+//	}
+//
+//	public List getCollectionPersisters() {
+//		return collectionPersisters;
+//	}
+//
+//	public Map getAlias2Persister() {
+//		return alias2Persister;
+//	}
+//
+//	/*public boolean isCollectionInitializer() {
+//		return isCollectionInitializer;
+//	}*/
+//
+////	public List getPersisters() {
+////		return persisters;
+////	}
+//
+//	public Map getAlias2OwnerAlias() {
+//		return alias2OwnerAlias;
+//	}
+//
+//	public List getScalarTypes() {
+//		return scalarTypes;
+//	}
+//	public List getScalarColumnAliases() {
+//		return scalarColumnAliases;
+//	}
+//
+//	public List getPropertyResults() {
+//		return propertyResults;
+//	}
+//
+//	public List getCollectionPropertyResults() {
+//		return collectionResults;
+//	}
+//
+//
+//	public Map getAlias2Return() {
+//		return alias2Return;
+//	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,89 @@
+//$Id: AbstractEntityLoader.java 9636 2006-03-16 14:14:48Z max.andersen at jboss.com $
+package org.hibernate.loader.entity;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.loader.OuterJoinLoader;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.type.Type;
+
+public abstract class AbstractEntityLoader extends OuterJoinLoader 
+		implements UniqueEntityLoader {
+
+	protected static final Log log = LogFactory.getLog(EntityLoader.class);
+	protected final OuterJoinLoadable persister;
+	protected final Type uniqueKeyType;
+	protected final String entityName;
+
+	public AbstractEntityLoader(
+			OuterJoinLoadable persister, 
+			Type uniqueKeyType, 
+			SessionFactoryImplementor factory, 
+			Map enabledFilters) {
+		super( factory, enabledFilters );
+		this.uniqueKeyType = uniqueKeyType;
+		this.entityName = persister.getEntityName();
+		this.persister = persister;
+		
+	}
+
+	public Object load(Serializable id, Object optionalObject, SessionImplementor session) 
+	throws HibernateException {
+		return load(session, id, optionalObject, id);
+	}
+
+	protected Object load(SessionImplementor session, Object id, Object optionalObject, Serializable optionalId) 
+	throws HibernateException {
+		
+		List list = loadEntity(
+				session, 
+				id, 
+				uniqueKeyType, 
+				optionalObject, 
+				entityName, 
+				optionalId, 
+				persister
+			);
+		
+		if ( list.size()==1 ) {
+			return list.get(0);
+		}
+		else if ( list.size()==0 ) {
+			return null;
+		}
+		else {
+			if ( getCollectionOwners()!=null ) {
+				return list.get(0);
+			}
+			else {
+				throw new HibernateException(
+						"More than one row with the given identifier was found: " +
+						id +
+						", for class: " +
+						persister.getEntityName()
+					);
+			}
+		}
+		
+	}
+
+	protected Object getResultColumnOrRow(Object[] row, ResultTransformer transformer, ResultSet rs, SessionImplementor session) 
+	throws SQLException, HibernateException {
+		return row[row.length-1];
+	}
+
+	protected boolean isSingleRowLoader() {
+		return true;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/BatchingEntityLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/BatchingEntityLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/BatchingEntityLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,107 @@
+//$Id: BatchingEntityLoader.java 6929 2005-05-27 03:54:08Z oneovthafew $
+package org.hibernate.loader.entity;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.loader.Loader;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * "Batch" loads entities, using multiple primary key values in the
+ * SQL <tt>where</tt> clause.
+ *
+ * @see EntityLoader
+ * @author Gavin King
+ */
+public class BatchingEntityLoader implements UniqueEntityLoader {
+
+	private final Loader[] loaders;
+	private final int[] batchSizes;
+	private final EntityPersister persister;
+	private final Type idType;
+
+	public BatchingEntityLoader(EntityPersister persister, int[] batchSizes, Loader[] loaders) {
+		this.batchSizes = batchSizes;
+		this.loaders = loaders;
+		this.persister = persister;
+		idType = persister.getIdentifierType();
+	}
+
+	private Object getObjectFromList(List results, Serializable id, SessionImplementor session) {
+		// get the right object from the list ... would it be easier to just call getEntity() ??
+		Iterator iter = results.iterator();
+		while ( iter.hasNext() ) {
+			Object obj = iter.next();
+			final boolean equal = idType.isEqual( 
+					id, 
+					session.getContextEntityIdentifier(obj), 
+					session.getEntityMode(), 
+					session.getFactory() 
+			);
+			if ( equal ) return obj;
+		}
+		return null;
+	}
+
+	public Object load(Serializable id, Object optionalObject, SessionImplementor session)
+	throws HibernateException {
+		
+		Serializable[] batch = session.getPersistenceContext()
+			.getBatchFetchQueue()
+			.getEntityBatch( persister, id, batchSizes[0], session.getEntityMode() );
+		
+		for ( int i=0; i<batchSizes.length-1; i++) {
+			final int smallBatchSize = batchSizes[i];
+			if ( batch[smallBatchSize-1]!=null ) {
+				Serializable[] smallBatch = new Serializable[smallBatchSize];
+				System.arraycopy(batch, 0, smallBatch, 0, smallBatchSize);
+				final List results = loaders[i].loadEntityBatch(
+						session, 
+						smallBatch, 
+						idType, 
+						optionalObject, 
+						persister.getEntityName(), 
+						id, 
+						persister
+				);
+				return getObjectFromList(results, id, session); //EARLY EXIT
+			}
+		}
+		
+		return ( (UniqueEntityLoader) loaders[batchSizes.length-1] ).load(id, optionalObject, session);
+
+	}
+
+	public static UniqueEntityLoader createBatchingEntityLoader(
+		final OuterJoinLoadable persister,
+		final int maxBatchSize,
+		final LockMode lockMode,
+		final SessionFactoryImplementor factory,
+		final Map enabledFilters)
+	throws MappingException {
+
+		if ( maxBatchSize>1 ) {
+			int[] batchSizesToCreate = ArrayHelper.getBatchSizes(maxBatchSize);
+			Loader[] loadersToCreate = new Loader[ batchSizesToCreate.length ];
+			for ( int i=0; i<batchSizesToCreate.length; i++ ) {
+				loadersToCreate[i] = new EntityLoader(persister, batchSizesToCreate[i], lockMode, factory, enabledFilters);
+			}
+			return new BatchingEntityLoader(persister, batchSizesToCreate, loadersToCreate);
+		}
+		else {
+			return new EntityLoader(persister, lockMode, factory, enabledFilters);
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CascadeEntityJoinWalker.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CascadeEntityJoinWalker.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CascadeEntityJoinWalker.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+//$Id: CascadeEntityJoinWalker.java 9889 2006-05-05 01:24:12Z steve.ebersole at jboss.com $
+package org.hibernate.loader.entity;
+
+import org.hibernate.FetchMode;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.CascadingAction;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.loader.AbstractEntityJoinWalker;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.type.AssociationType;
+import org.hibernate.util.CollectionHelper;
+
+public class CascadeEntityJoinWalker extends AbstractEntityJoinWalker {
+	
+	private final CascadingAction cascadeAction;
+
+	public CascadeEntityJoinWalker(OuterJoinLoadable persister, CascadingAction action, SessionFactoryImplementor factory) 
+	throws MappingException {
+		super( persister, factory, CollectionHelper.EMPTY_MAP );
+		this.cascadeAction = action;
+		StringBuffer whereCondition = whereString( getAlias(), persister.getIdentifierColumnNames(), 1 )
+				//include the discriminator and class-level where, but not filters
+				.append( persister.filterFragment( getAlias(), CollectionHelper.EMPTY_MAP ) );
+	
+		initAll( whereCondition.toString(), "", LockMode.READ );
+	}
+
+	protected boolean isJoinedFetchEnabled(AssociationType type, FetchMode config, CascadeStyle cascadeStyle) {
+		return ( type.isEntityType() || type.isCollectionType() ) &&
+				( cascadeStyle==null || cascadeStyle.doCascade(cascadeAction) );
+	}
+
+	protected boolean isTooManyCollections() {
+		return countCollectionPersisters(associations)>0;
+	}
+
+	public String getComment() {
+		return "load " + getPersister().getEntityName();
+	}
+	
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CascadeEntityJoinWalker.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CascadeEntityLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CascadeEntityLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CascadeEntityLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: CascadeEntityLoader.java 7652 2005-07-26 05:51:47Z oneovthafew $
+package org.hibernate.loader.entity;
+
+import org.hibernate.MappingException;
+import org.hibernate.engine.CascadingAction;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.loader.JoinWalker;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.util.CollectionHelper;
+
+public class CascadeEntityLoader extends AbstractEntityLoader {
+	
+	public CascadeEntityLoader(
+			OuterJoinLoadable persister,
+			CascadingAction action,
+			SessionFactoryImplementor factory) 
+	throws MappingException {
+		super(
+				persister, 
+				persister.getIdentifierType(), 
+				factory, 
+				CollectionHelper.EMPTY_MAP
+			);
+
+		JoinWalker walker = new CascadeEntityJoinWalker(
+				persister, 
+				action,
+				factory
+			);
+		initFromWalker( walker );
+
+		postInstantiate();
+		
+		log.debug( "Static select for action " + action + " on entity " + entityName + ": " + getSQLString() );
+
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CascadeEntityLoader.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CollectionElementLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CollectionElementLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CollectionElementLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,111 @@
+//$Id: CollectionElementLoader.java 9636 2006-03-16 14:14:48Z max.andersen at jboss.com $
+package org.hibernate.loader.entity;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.loader.JoinWalker;
+import org.hibernate.loader.OuterJoinLoader;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * 
+ *
+ * @author Gavin King
+ */
+public class CollectionElementLoader extends OuterJoinLoader {
+	
+	private static final Log log = LogFactory.getLog(CollectionElementLoader.class);
+
+	private final OuterJoinLoadable persister;
+	private final Type keyType;
+	private final Type indexType;
+	private final String entityName;
+
+	public CollectionElementLoader(
+			QueryableCollection collectionPersister,
+			SessionFactoryImplementor factory, 
+			Map enabledFilters) 
+	throws MappingException {
+		super(factory, enabledFilters);
+
+		this.keyType = collectionPersister.getKeyType();
+		this.indexType = collectionPersister.getIndexType();
+		this.persister = (OuterJoinLoadable) collectionPersister.getElementPersister();
+		this.entityName = persister.getEntityName();
+		
+		JoinWalker walker = new EntityJoinWalker(
+				persister, 
+				ArrayHelper.join( 
+						collectionPersister.getKeyColumnNames(), 
+						collectionPersister.getIndexColumnNames()
+					),
+				1, 
+				LockMode.NONE, 
+				factory, 
+				enabledFilters
+			);
+		initFromWalker( walker );
+
+		postInstantiate();
+		
+		log.debug( "Static select for entity " + entityName + ": " + getSQLString() );
+
+	}
+
+	public Object loadElement(SessionImplementor session, Object key, Object index) 
+	throws HibernateException {
+		
+		List list = loadEntity(
+				session, 
+				key,
+				index,
+				keyType, 
+				indexType,
+				persister
+			);
+		
+		if ( list.size()==1 ) {
+			return list.get(0);
+		}
+		else if ( list.size()==0 ) {
+			return null;
+		}
+		else {
+			if ( getCollectionOwners()!=null ) {
+				return list.get(0);
+			}
+			else {
+				throw new HibernateException("More than one row was found");
+			}
+		}
+		
+	}
+
+	protected Object getResultColumnOrRow(
+		Object[] row,
+		ResultTransformer transformer,
+		ResultSet rs, SessionImplementor session)
+	throws SQLException, HibernateException {
+		return row[row.length-1];
+	}
+
+	protected boolean isSingleRowLoader() {
+		return true;
+	}
+
+	
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/CollectionElementLoader.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/EntityJoinWalker.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/EntityJoinWalker.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/EntityJoinWalker.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+//$Id: EntityJoinWalker.java 7652 2005-07-26 05:51:47Z oneovthafew $
+package org.hibernate.loader.entity;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.hibernate.FetchMode;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.loader.AbstractEntityJoinWalker;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.type.AssociationType;
+
+/**
+ * A walker for loaders that fetch entities
+ *
+ * @see EntityLoader
+ * @author Gavin King
+ */
+public class EntityJoinWalker extends AbstractEntityJoinWalker {
+	
+	private final LockMode lockMode;
+
+	public EntityJoinWalker(
+			OuterJoinLoadable persister, 
+			String[] uniqueKey, 
+			int batchSize, 
+			LockMode lockMode,
+			SessionFactoryImplementor factory, 
+			Map enabledFilters) 
+	throws MappingException {
+		super(persister, factory, enabledFilters);
+
+		this.lockMode = lockMode;
+		
+		StringBuffer whereCondition = whereString( getAlias(), uniqueKey, batchSize )
+			//include the discriminator and class-level where, but not filters
+			.append( persister.filterFragment( getAlias(), Collections.EMPTY_MAP ) );
+
+		initAll( whereCondition.toString(), "", lockMode );
+		
+	}
+
+	/**
+	 * Disable outer join fetching if this loader obtains an
+	 * upgrade lock mode
+	 */
+	protected boolean isJoinedFetchEnabled(AssociationType type, FetchMode config, CascadeStyle cascadeStyle) {
+		return lockMode.greaterThan(LockMode.READ) ?
+			false :
+			super.isJoinedFetchEnabled(type, config, cascadeStyle);
+	}
+
+	public String getComment() {
+		return "load " + getPersister().getEntityName();
+	}
+	
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/EntityJoinWalker.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/EntityLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/EntityLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/EntityLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,92 @@
+//$Id: EntityLoader.java 7652 2005-07-26 05:51:47Z oneovthafew $
+package org.hibernate.loader.entity;
+
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.loader.JoinWalker;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.type.Type;
+
+/**
+ * Loads an entity instance using outerjoin fetching to fetch associated entities.
+ * <br>
+ * The <tt>EntityPersister</tt> must implement <tt>Loadable</tt>. For other entities,
+ * create a customized subclass of <tt>Loader</tt>.
+ *
+ * @author Gavin King
+ */
+public class EntityLoader extends AbstractEntityLoader {
+	
+	private final boolean batchLoader;
+	
+	public EntityLoader(
+			OuterJoinLoadable persister, 
+			LockMode lockMode,
+			SessionFactoryImplementor factory, 
+			Map enabledFilters) 
+	throws MappingException {
+		this(persister, 1, lockMode, factory, enabledFilters);
+	}
+	
+	public EntityLoader(
+			OuterJoinLoadable persister, 
+			int batchSize, 
+			LockMode lockMode,
+			SessionFactoryImplementor factory, 
+			Map enabledFilters) 
+	throws MappingException {
+		this( 
+				persister, 
+				persister.getIdentifierColumnNames(), 
+				persister.getIdentifierType(), 
+				batchSize,
+				lockMode,
+				factory, 
+				enabledFilters 
+			);
+	}
+
+	public EntityLoader(
+			OuterJoinLoadable persister, 
+			String[] uniqueKey, 
+			Type uniqueKeyType, 
+			int batchSize, 
+			LockMode lockMode,
+			SessionFactoryImplementor factory, 
+			Map enabledFilters) 
+	throws MappingException {
+		super(persister, uniqueKeyType, factory, enabledFilters);
+
+		JoinWalker walker = new EntityJoinWalker(
+				persister, 
+				uniqueKey, 
+				batchSize, 
+				lockMode, 
+				factory, 
+				enabledFilters
+			);
+		initFromWalker( walker );
+
+		postInstantiate();
+
+		batchLoader = batchSize > 1;
+		
+		log.debug( "Static select for entity " + entityName + ": " + getSQLString() );
+
+	}
+
+	public Object loadByUniqueKey(SessionImplementor session, Object key) 
+	throws HibernateException {
+		return load(session, key, null, null);
+	}
+
+	protected boolean isSingleRowLoader() {
+		return !batchLoader;
+	}
+	
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/UniqueEntityLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/UniqueEntityLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/UniqueEntityLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+//$Id: UniqueEntityLoader.java 5699 2005-02-13 11:50:11Z oneovthafew $
+package org.hibernate.loader.entity;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * Loads entities for a <tt>EntityPersister</tt>
+ * @author Gavin King
+ */
+public interface UniqueEntityLoader {
+	/**
+	 * Load an entity instance. If <tt>optionalObject</tt> is supplied,
+	 * load the entity state into the given (uninitialized) object.
+	 */
+	public Object load(Serializable id, Object optionalObject, SessionImplementor session) throws HibernateException;
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines entity loaders
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/entity/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/hql/QueryLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/hql/QueryLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/hql/QueryLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,520 @@
+// $Id: QueryLoader.java 11116 2007-01-30 14:30:55Z steve.ebersole at jboss.com $
+package org.hibernate.loader.hql;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.QueryException;
+import org.hibernate.ScrollableResults;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.event.EventSource;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.hql.HolderInstantiator;
+import org.hibernate.hql.ast.QueryTranslatorImpl;
+import org.hibernate.hql.ast.tree.FromElement;
+import org.hibernate.hql.ast.tree.SelectClause;
+import org.hibernate.hql.ast.tree.QueryNode;
+import org.hibernate.impl.IteratorImpl;
+import org.hibernate.loader.BasicLoader;
+import org.hibernate.param.ParameterSpecification;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.persister.entity.Lockable;
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * A delegate that implements the Loader part of QueryTranslator.
+ *
+ * @author josh
+ */
+public class QueryLoader extends BasicLoader {
+
+	/**
+	 * The query translator that is delegating to this object.
+	 */
+	private QueryTranslatorImpl queryTranslator;
+
+	private Queryable[] entityPersisters;
+	private String[] entityAliases;
+	private String[] sqlAliases;
+	private String[] sqlAliasSuffixes;
+	private boolean[] includeInSelect;
+
+	private String[] collectionSuffixes;
+
+	private boolean hasScalars;
+	private String[][] scalarColumnNames;
+	//private Type[] sqlResultTypes;
+	private Type[] queryReturnTypes;
+
+	private final Map sqlAliasByEntityAlias = new HashMap(8);
+
+	private EntityType[] ownerAssociationTypes;
+	private int[] owners;
+	private boolean[] entityEagerPropertyFetches;
+
+	private int[] collectionOwners;
+	private QueryableCollection[] collectionPersisters;
+
+	private int selectLength;
+
+	private ResultTransformer selectNewTransformer;
+	private String[] queryReturnAliases;
+
+	private LockMode[] defaultLockModes;
+
+
+	/**
+	 * Creates a new Loader implementation.
+	 *
+	 * @param queryTranslator The query translator that is the delegator.
+	 * @param factory The factory from which this loader is being created.
+	 * @param selectClause The AST representing the select clause for loading.
+	 */
+	public QueryLoader(
+			final QueryTranslatorImpl queryTranslator,
+	        final SessionFactoryImplementor factory,
+	        final SelectClause selectClause) {
+		super( factory );
+		this.queryTranslator = queryTranslator;
+		initialize( selectClause );
+		postInstantiate();
+	}
+
+	private void initialize(SelectClause selectClause) {
+
+		List fromElementList = selectClause.getFromElementsForLoad();
+
+		hasScalars = selectClause.isScalarSelect();
+		scalarColumnNames = selectClause.getColumnNames();
+		//sqlResultTypes = selectClause.getSqlResultTypes();
+		queryReturnTypes = selectClause.getQueryReturnTypes();
+
+		selectNewTransformer = HolderInstantiator.createSelectNewTransformer(
+				selectClause.getConstructor(),
+				selectClause.isMap(),
+				selectClause.isList());
+		queryReturnAliases = selectClause.getQueryReturnAliases();
+
+		List collectionFromElements = selectClause.getCollectionFromElements();
+		if ( collectionFromElements != null && collectionFromElements.size()!=0 ) {
+			int length = collectionFromElements.size();
+			collectionPersisters = new QueryableCollection[length];
+			collectionOwners = new int[length];
+			collectionSuffixes = new String[length];
+			for ( int i=0; i<length; i++ ) {
+				FromElement collectionFromElement = (FromElement) collectionFromElements.get(i);
+				collectionPersisters[i] = collectionFromElement.getQueryableCollection();
+				collectionOwners[i] = fromElementList.indexOf( collectionFromElement.getOrigin() );
+//				collectionSuffixes[i] = collectionFromElement.getColumnAliasSuffix();
+//				collectionSuffixes[i] = Integer.toString( i ) + "_";
+				collectionSuffixes[i] = collectionFromElement.getCollectionSuffix();
+			}
+		}
+
+		int size = fromElementList.size();
+		entityPersisters = new Queryable[size];
+		entityEagerPropertyFetches = new boolean[size];
+		entityAliases = new String[size];
+		sqlAliases = new String[size];
+		sqlAliasSuffixes = new String[size];
+		includeInSelect = new boolean[size];
+		owners = new int[size];
+		ownerAssociationTypes = new EntityType[size];
+
+		for ( int i = 0; i < size; i++ ) {
+			final FromElement element = ( FromElement ) fromElementList.get( i );
+			entityPersisters[i] = ( Queryable ) element.getEntityPersister();
+
+			if ( entityPersisters[i] == null ) {
+				throw new IllegalStateException( "No entity persister for " + element.toString() );
+			}
+
+			entityEagerPropertyFetches[i] = element.isAllPropertyFetch();
+			sqlAliases[i] = element.getTableAlias();
+			entityAliases[i] = element.getClassAlias();
+			sqlAliasByEntityAlias.put( entityAliases[i], sqlAliases[i] );
+			// TODO should we just collect these like with the collections above?
+			sqlAliasSuffixes[i] = ( size == 1 ) ? "" : Integer.toString( i ) + "_";
+//			sqlAliasSuffixes[i] = element.getColumnAliasSuffix();
+			includeInSelect[i] = !element.isFetch();
+			if ( includeInSelect[i] ) {
+				selectLength++;
+			}
+
+			owners[i] = -1; //by default
+			if ( element.isFetch() ) {
+				if ( element.isCollectionJoin() || element.getQueryableCollection() != null ) {
+					// This is now handled earlier in this method.
+				}
+				else if ( element.getDataType().isEntityType() ) {
+					EntityType entityType = ( EntityType ) element.getDataType();
+					if ( entityType.isOneToOne() ) {
+						owners[i] = fromElementList.indexOf( element.getOrigin() );
+					}
+					ownerAssociationTypes[i] = entityType;
+				}
+			}
+		}
+
+		//NONE, because its the requested lock mode, not the actual! 
+		defaultLockModes = ArrayHelper.fillArray(LockMode.NONE, size);
+
+	}
+
+	// -- Loader implementation --
+
+	public final void validateScrollability() throws HibernateException {
+		queryTranslator.validateScrollability();
+	}
+
+	protected boolean needsFetchingScroll() {
+		return queryTranslator.containsCollectionFetches();
+	}
+
+	public Loadable[] getEntityPersisters() {
+		return entityPersisters;
+	}
+
+	public String[] getAliases() {
+		return sqlAliases;
+	}
+
+	public String[] getSqlAliasSuffixes() {
+		return sqlAliasSuffixes;
+	}
+
+	public String[] getSuffixes() {
+		return getSqlAliasSuffixes();
+	}
+
+	public String[] getCollectionSuffixes() {
+		return collectionSuffixes;
+	}
+
+	protected String getQueryIdentifier() {
+		return queryTranslator.getQueryIdentifier();
+	}
+
+	/**
+	 * The SQL query string to be called.
+	 */
+	protected String getSQLString() {
+		return queryTranslator.getSQLString();
+	}
+
+	/**
+	 * An (optional) persister for a collection to be initialized; only collection loaders
+	 * return a non-null value
+	 */
+	protected CollectionPersister[] getCollectionPersisters() {
+		return collectionPersisters;
+	}
+
+	protected int[] getCollectionOwners() {
+		return collectionOwners;
+	}
+
+	protected boolean[] getEntityEagerPropertyFetches() {
+		return entityEagerPropertyFetches;
+	}
+
+	/**
+	 * An array of indexes of the entity that owns a one-to-one association
+	 * to the entity at the given index (-1 if there is no "owner")
+	 */
+	protected int[] getOwners() {
+		return owners;
+	}
+
+	protected EntityType[] getOwnerAssociationTypes() {
+		return ownerAssociationTypes;
+	}
+
+	// -- Loader overrides --
+
+	protected boolean isSubselectLoadingEnabled() {
+		return hasSubselectLoadableCollections();
+	}
+
+	/**
+	 * @param lockModes a collection of lock modes specified dynamically via the Query interface
+	 */
+	protected LockMode[] getLockModes(Map lockModes) {
+
+		if ( lockModes==null || lockModes.size()==0 ) {
+			return defaultLockModes;
+		}
+		else {
+			// unfortunately this stuff can't be cached because
+			// it is per-invocation, not constant for the
+			// QueryTranslator instance
+
+			LockMode[] lockModeArray = new LockMode[entityAliases.length];
+			for ( int i = 0; i < entityAliases.length; i++ ) {
+				LockMode lockMode = (LockMode) lockModes.get( entityAliases[i] );
+				if ( lockMode == null ) {
+					//NONE, because its the requested lock mode, not the actual! 
+					lockMode = LockMode.NONE;
+				}
+				lockModeArray[i] = lockMode;
+			}
+			return lockModeArray;
+		}
+	}
+
+	protected String applyLocks(String sql, Map lockModes, Dialect dialect) throws QueryException {
+		if ( lockModes == null || lockModes.size() == 0 ) {
+			return sql;
+		}
+
+		// can't cache this stuff either (per-invocation)
+		// we are given a map of user-alias -> lock mode
+		// create a new map of sql-alias -> lock mode
+		final Map aliasedLockModes = new HashMap();
+		final Map keyColumnNames = dialect.forUpdateOfColumns() ? new HashMap() : null;
+		final Iterator iter = lockModes.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = ( Map.Entry ) iter.next();
+			final String userAlias = ( String ) me.getKey();
+			final String drivingSqlAlias = ( String ) sqlAliasByEntityAlias.get( userAlias );
+			if ( drivingSqlAlias == null ) {
+				throw new IllegalArgumentException( "could not locate alias to apply lock mode : " + userAlias );
+			}
+			// at this point we have (drivingSqlAlias) the SQL alias of the driving table
+			// corresponding to the given user alias.  However, the driving table is not
+			// (necessarily) the table against which we want to apply locks.  Mainly,
+			// the exception case here is joined-subclass hierarchies where we instead
+			// want to apply the lock against the root table (for all other strategies,
+			// it just happens that driving and root are the same).
+			final QueryNode select = ( QueryNode ) queryTranslator.getSqlAST();
+			final Lockable drivingPersister = ( Lockable ) select.getFromClause().getFromElement( userAlias ).getQueryable();
+			final String sqlAlias = drivingPersister.getRootTableAlias( drivingSqlAlias );
+			aliasedLockModes.put( sqlAlias, me.getValue() );
+			if ( keyColumnNames != null ) {
+				keyColumnNames.put( sqlAlias, drivingPersister.getRootTableIdentifierColumnNames() );
+			}
+		}
+		return dialect.applyLocksToSql( sql, aliasedLockModes, keyColumnNames );
+	}
+
+	protected boolean upgradeLocks() {
+		return true;
+	}
+
+	private boolean hasSelectNew() {
+		return selectNewTransformer!=null;
+	}
+
+	protected Object getResultColumnOrRow(Object[] row, ResultTransformer transformer, ResultSet rs, SessionImplementor session)
+			throws SQLException, HibernateException {
+
+		row = toResultRow( row );
+		boolean hasTransform = hasSelectNew() || transformer!=null;
+		if ( hasScalars ) {
+			String[][] scalarColumns = scalarColumnNames;
+			int queryCols = queryReturnTypes.length;
+			if ( !hasTransform && queryCols == 1 ) {
+				return queryReturnTypes[0].nullSafeGet( rs, scalarColumns[0], session, null );
+			}
+			else {
+				row = new Object[queryCols];
+				for ( int i = 0; i < queryCols; i++ ) {
+					row[i] = queryReturnTypes[i].nullSafeGet( rs, scalarColumns[i], session, null );
+				}
+				return row;
+			}
+		}
+		else if ( !hasTransform ) {
+			return row.length == 1 ? row[0] : row;
+		}
+		else {
+			return row;
+		}
+
+	}
+
+	protected List getResultList(List results, ResultTransformer resultTransformer) throws QueryException {
+		// meant to handle dynamic instantiation queries...
+		HolderInstantiator holderInstantiator = HolderInstantiator.getHolderInstantiator(selectNewTransformer, resultTransformer, queryReturnAliases);
+		if ( holderInstantiator.isRequired() ) {
+			for ( int i = 0; i < results.size(); i++ ) {
+				Object[] row = ( Object[] ) results.get( i );
+				Object result = holderInstantiator.instantiate(row);
+				results.set( i, result );
+			}
+
+			if(!hasSelectNew() && resultTransformer!=null) {
+				return resultTransformer.transformList(results);
+			} else {
+				return results;
+			}
+		} else {
+			return results;
+		}
+	}
+
+	// --- Query translator methods ---
+
+	public List list(
+			SessionImplementor session,
+			QueryParameters queryParameters) throws HibernateException {
+		checkQuery( queryParameters );
+		return list( session, queryParameters, queryTranslator.getQuerySpaces(), queryReturnTypes );
+	}
+
+	private void checkQuery(QueryParameters queryParameters) {
+		if ( hasSelectNew() && queryParameters.getResultTransformer() != null ) {
+			throw new QueryException( "ResultTransformer is not allowed for 'select new' queries." );
+		}
+	}
+
+	public Iterator iterate(
+			QueryParameters queryParameters,
+			EventSource session) throws HibernateException {
+		checkQuery( queryParameters );
+		final boolean stats = session.getFactory().getStatistics().isStatisticsEnabled();
+		long startTime = 0;
+		if ( stats ) {
+			startTime = System.currentTimeMillis();
+		}
+
+		try {
+
+			final PreparedStatement st = prepareQueryStatement( queryParameters, false, session );
+
+			if(queryParameters.isCallable()) {
+				throw new QueryException("iterate() not supported for callable statements");
+			}
+			final ResultSet rs = getResultSet(st, queryParameters.hasAutoDiscoverScalarTypes(), false, queryParameters.getRowSelection(), session);
+			final Iterator result = new IteratorImpl(
+					rs,
+			        st,
+			        session,
+			        queryReturnTypes,
+			        queryTranslator.getColumnNames(),
+			        HolderInstantiator.getHolderInstantiator(selectNewTransformer, queryParameters.getResultTransformer(), queryReturnAliases)
+				);
+
+			if ( stats ) {
+				session.getFactory().getStatisticsImplementor().queryExecuted(
+//						"HQL: " + queryTranslator.getQueryString(),
+						getQueryIdentifier(),
+						0,
+						System.currentTimeMillis() - startTime
+				);
+			}
+
+			return result;
+
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					getFactory().getSQLExceptionConverter(),
+			        sqle,
+			        "could not execute query using iterate",
+			        getSQLString()
+				);
+		}
+
+	}
+
+	public ScrollableResults scroll(
+			final QueryParameters queryParameters,
+	        final SessionImplementor session) throws HibernateException {
+		checkQuery( queryParameters );
+		return scroll( queryParameters, queryReturnTypes, HolderInstantiator.getHolderInstantiator(selectNewTransformer, queryParameters.getResultTransformer(), queryReturnAliases), session );
+	}
+
+	// -- Implementation private methods --
+
+	private Object[] toResultRow(Object[] row) {
+		if ( selectLength == row.length ) {
+			return row;
+		}
+		else {
+			Object[] result = new Object[selectLength];
+			int j = 0;
+			for ( int i = 0; i < row.length; i++ ) {
+				if ( includeInSelect[i] ) {
+					result[j++] = row[i];
+				}
+			}
+			return result;
+		}
+	}
+
+	/**
+	 * Returns the locations of all occurrences of the named parameter.
+	 */
+	public int[] getNamedParameterLocs(String name) throws QueryException {
+		return queryTranslator.getParameterTranslations().getNamedParameterSqlLocations( name );
+	}
+
+	/**
+	 * We specifically override this method here, because in general we know much more
+	 * about the parameters and their appropriate bind positions here then we do in
+	 * our super because we track them explciitly here through the ParameterSpecification
+	 * interface.
+	 *
+	 * @param queryParameters The encapsulation of the parameter values to be bound.
+	 * @param startIndex The position from which to start binding parameter values.
+	 * @param session The originating session.
+	 * @return The number of JDBC bind positions actually bound during this method execution.
+	 * @throws SQLException Indicates problems performing the binding.
+	 */
+	protected int bindParameterValues(
+			final PreparedStatement statement,
+			final QueryParameters queryParameters,
+			final int startIndex,
+			final SessionImplementor session) throws SQLException {
+		int position = bindFilterParameterValues( statement, queryParameters, startIndex, session );
+		List parameterSpecs = queryTranslator.getSqlAST().getWalker().getParameters();
+		Iterator itr = parameterSpecs.iterator();
+		while ( itr.hasNext() ) {
+			ParameterSpecification spec = ( ParameterSpecification ) itr.next();
+			position += spec.bind( statement, queryParameters, session, position );
+		}
+		return position - startIndex;
+	}
+
+	private int bindFilterParameterValues(
+			PreparedStatement st,
+			QueryParameters queryParameters,
+			int position,
+			SessionImplementor session) throws SQLException {
+		// todo : better to handle dynamic filters through implicit DynamicFilterParameterSpecification
+		// see the discussion there in DynamicFilterParameterSpecification's javadocs as to why
+		// it is currently not done that way.
+		int filteredParamCount = queryParameters.getFilteredPositionalParameterTypes() == null
+				? 0
+				: queryParameters.getFilteredPositionalParameterTypes().length;
+		int nonfilteredParamCount = queryParameters.getPositionalParameterTypes() == null
+				? 0
+				: queryParameters.getPositionalParameterTypes().length;
+		int filterParamCount = filteredParamCount - nonfilteredParamCount;
+		for ( int i = 0; i < filterParamCount; i++ ) {
+			Type type = queryParameters.getFilteredPositionalParameterTypes()[i];
+			Object value = queryParameters.getFilteredPositionalParameterValues()[i];
+			type.nullSafeSet( st, value, position, session );
+			position += type.getColumnSpan( getFactory() );
+		}
+
+		return position;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/hql/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/hql/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/hql/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines a loader for the AST-based query parser
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/hql/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/loader/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/loader/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,14 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines functionality for processing JDBC
+	result sets and returning complex graphs of persistent
+	objects.
+</p>
+<p>
+	Subclasses of <tt>Loader</tt> define a particular
+	query mechanism.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/loader/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/lob/BlobImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/lob/BlobImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/lob/BlobImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,113 @@
+//$Id: BlobImpl.java 4997 2004-12-18 18:48:20Z oneovthafew $
+package org.hibernate.lob;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.sql.Blob;
+import java.sql.SQLException;
+
+/**
+ * A dummy implementation of <tt>java.sql.Blob</tt> that
+ * may be used to insert new data into a BLOB.
+ * @author Gavin King
+ */
+public class BlobImpl implements Blob {
+
+	private InputStream stream;
+	private int length;
+	private boolean needsReset = false;
+
+	public BlobImpl(byte[] bytes) {
+		this.stream = new ByteArrayInputStream(bytes);
+		this.length = bytes.length;
+	}
+
+	public BlobImpl(InputStream stream, int length) {
+		this.stream = stream;
+		this.length = length;
+	}
+
+	/**
+	 * @see java.sql.Blob#length()
+	 */
+	public long length() throws SQLException {
+		return length;
+	}
+
+	/**
+	 * @see java.sql.Blob#truncate(long)
+	 */
+	public void truncate(long pos) throws SQLException {
+		excep();
+	}
+
+	/**
+	 * @see java.sql.Blob#getBytes(long, int)
+	 */
+	public byte[] getBytes(long pos, int len) throws SQLException {
+		excep(); return null;
+	}
+
+	/**
+	 * @see java.sql.Blob#setBytes(long, byte[])
+	 */
+	public int setBytes(long pos, byte[] bytes) throws SQLException {
+		excep(); return 0;
+	}
+
+	/**
+	 * @see java.sql.Blob#setBytes(long, byte[], int, int)
+	 */
+	public int setBytes(long pos, byte[] bytes, int i, int j)
+	throws SQLException {
+		excep(); return 0;
+	}
+
+	/**
+	 * @see java.sql.Blob#position(byte[], long)
+	 */
+	public long position(byte[] bytes, long pos) throws SQLException {
+		excep(); return 0;
+	}
+
+	/**
+	 * @see java.sql.Blob#getBinaryStream()
+	 */
+	public InputStream getBinaryStream() throws SQLException {
+		try {
+			if (needsReset) stream.reset();
+		}
+		catch (IOException ioe) {
+			throw new SQLException("could not reset reader");
+		}
+		needsReset = true;
+		return stream;
+	}
+
+	/**
+	 * @see java.sql.Blob#setBinaryStream(long)
+	 */
+	public OutputStream setBinaryStream(long pos) throws SQLException {
+		excep(); return null;
+	}
+
+	/**
+	 * @see java.sql.Blob#position(Blob, long)
+	 */
+	public long position(Blob blob, long pos) throws SQLException {
+		excep(); return 0;
+	}
+
+	private static void excep() {
+		throw new UnsupportedOperationException("Blob may not be manipulated from creating session");
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/lob/ClobImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/lob/ClobImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/lob/ClobImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,137 @@
+//$Id: ClobImpl.java 5683 2005-02-12 03:09:22Z oneovthafew $
+package org.hibernate.lob;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+import java.sql.Clob;
+import java.sql.SQLException;
+
+/**
+ * A dummy implementation of <tt>java.sql.Clob</tt> that
+ * may be used to insert new data into a CLOB.
+ * @author Gavin King
+ */
+public class ClobImpl implements Clob {
+
+	private Reader reader;
+	private int length;
+	private boolean needsReset = false;
+
+	public ClobImpl(String string) {
+		reader = new StringReader(string);
+		length = string.length();
+	}
+
+	public ClobImpl(Reader reader, int length) {
+		this.reader = reader;
+		this.length = length;
+	}
+
+	/**
+	 * @see java.sql.Clob#length()
+	 */
+	public long length() throws SQLException {
+		return length;
+	}
+
+	/**
+	 * @see java.sql.Clob#truncate(long)
+	 */
+	public void truncate(long pos) throws SQLException {
+		excep();
+	}
+
+	/**
+	 * @see java.sql.Clob#getAsciiStream()
+	 */
+	public InputStream getAsciiStream() throws SQLException {
+		try {
+			if (needsReset) reader.reset();
+		}
+		catch (IOException ioe) {
+			throw new SQLException("could not reset reader");
+		}
+		needsReset = true;
+		return new ReaderInputStream(reader);
+	}
+
+	/**
+	 * @see java.sql.Clob#setAsciiStream(long)
+	 */
+	public OutputStream setAsciiStream(long pos) throws SQLException {
+		excep(); return null;
+	}
+
+	/**
+	 * @see java.sql.Clob#getCharacterStream()
+	 */
+	public Reader getCharacterStream() throws SQLException {
+		try {
+			if (needsReset) reader.reset();
+		}
+		catch (IOException ioe) {
+			throw new SQLException("could not reset reader");
+		}
+		needsReset = true;
+		return reader;
+	}
+
+	/**
+	 * @see java.sql.Clob#setCharacterStream(long)
+	 */
+	public Writer setCharacterStream(long pos) throws SQLException {
+		excep(); return null;
+	}
+
+	/**
+	 * @see java.sql.Clob#getSubString(long, int)
+	 */
+	public String getSubString(long pos, int len) throws SQLException {
+		excep(); return null;
+	}
+
+	/**
+	 * @see java.sql.Clob#setString(long, String)
+	 */
+	public int setString(long pos, String string) throws SQLException {
+		excep(); return 0;
+	}
+
+	/**
+	 * @see java.sql.Clob#setString(long, String, int, int)
+	 */
+	public int setString(long pos, String string, int i, int j)
+	throws SQLException {
+		excep(); return 0;
+	}
+
+	/**
+	 * @see java.sql.Clob#position(String, long)
+	 */
+	public long position(String string, long pos) throws SQLException {
+		excep(); return 0;
+	}
+
+	/**
+	 * @see java.sql.Clob#position(Clob, long)
+	 */
+	public long position(Clob colb, long pos) throws SQLException {
+		excep(); return 0;
+	}
+
+
+	private static void excep() {
+		throw new UnsupportedOperationException("Blob may not be manipulated from creating session");
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/lob/ReaderInputStream.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/lob/ReaderInputStream.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/lob/ReaderInputStream.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+//$Id: ReaderInputStream.java 5683 2005-02-12 03:09:22Z oneovthafew $
+package org.hibernate.lob;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+/**
+ * Exposes a <tt>Reader</tt> as an <tt>InputStream</tt>
+ * @author Gavin King
+ */
+public class ReaderInputStream extends InputStream {
+	
+	private Reader reader;
+	
+	public ReaderInputStream(Reader reader) {
+		this.reader = reader;
+	}
+	
+	public int read() throws IOException {
+		return reader.read();
+	}
+	
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/lob/ReaderInputStream.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/lob/SerializableBlob.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/lob/SerializableBlob.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/lob/SerializableBlob.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,66 @@
+//$Id: SerializableBlob.java 5986 2005-03-02 11:43:36Z oneovthafew $
+package org.hibernate.lob;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.sql.Blob;
+import java.sql.SQLException;
+
+/**
+ * @author Gavin King
+ */
+public class SerializableBlob implements Serializable, Blob {
+	
+	private transient final Blob blob;
+	
+	public SerializableBlob(Blob blob) {
+		this.blob = blob;
+	}
+
+	public Blob getWrappedBlob() {
+		if ( blob==null ) {
+			throw new IllegalStateException("Blobs may not be accessed after serialization");
+		}
+		else {
+			return blob;
+		}
+	}
+	
+	public long length() throws SQLException {
+		return getWrappedBlob().length();
+	}
+
+	public byte[] getBytes(long pos, int length) throws SQLException {
+		return getWrappedBlob().getBytes(pos, length);
+	}
+
+	public InputStream getBinaryStream() throws SQLException {
+		return getWrappedBlob().getBinaryStream();
+	}
+
+	public long position(byte[] pattern, long start) throws SQLException {
+		return getWrappedBlob().position(pattern, start);
+	}
+
+	public long position(Blob pattern, long start) throws SQLException {
+		return getWrappedBlob().position(pattern, start);
+	}
+
+	public int setBytes(long pos, byte[] bytes) throws SQLException {
+		return getWrappedBlob().setBytes(pos, bytes);
+	}
+
+	public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException {
+		return getWrappedBlob().setBytes(pos, bytes, offset, len);
+	}
+
+	public OutputStream setBinaryStream(long pos) throws SQLException {
+		return getWrappedBlob().setBinaryStream(pos);
+	}
+
+	public void truncate(long len) throws SQLException {
+		getWrappedBlob().truncate(len);
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/lob/SerializableBlob.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/lob/SerializableClob.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/lob/SerializableClob.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/lob/SerializableClob.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,76 @@
+//$Id: SerializableClob.java 5986 2005-03-02 11:43:36Z oneovthafew $
+package org.hibernate.lob;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Serializable;
+import java.io.Writer;
+import java.sql.Clob;
+import java.sql.SQLException;
+
+/**
+ * @author Gavin King
+ */
+public class SerializableClob implements Serializable, Clob {
+
+	private transient final Clob clob;
+	
+	public SerializableClob(Clob blob) {
+		this.clob = blob;
+	}
+
+	public Clob getWrappedClob() {
+		if ( clob==null ) {
+			throw new IllegalStateException("Clobs may not be accessed after serialization");
+		}
+		else {
+			return clob;
+		}
+	}
+	
+	public long length() throws SQLException {
+		return getWrappedClob().length();
+	}
+
+	public String getSubString(long pos, int length) throws SQLException {
+		return getWrappedClob().getSubString(pos, length);
+	}
+
+	public Reader getCharacterStream() throws SQLException {
+		return getWrappedClob().getCharacterStream();
+	}
+
+	public InputStream getAsciiStream() throws SQLException {
+		return getWrappedClob().getAsciiStream();
+	}
+
+	public long position(String searchstr, long start) throws SQLException {
+		return getWrappedClob().position(searchstr, start);
+	}
+
+	public long position(Clob searchstr, long start) throws SQLException {
+		return getWrappedClob().position(searchstr, start);
+	}
+
+	public int setString(long pos, String str) throws SQLException {
+		return getWrappedClob().setString(pos, str);
+	}
+
+	public int setString(long pos, String str, int offset, int len) throws SQLException {
+		return getWrappedClob().setString(pos, str, offset, len);
+	}
+
+	public OutputStream setAsciiStream(long pos) throws SQLException {
+		return getWrappedClob().setAsciiStream(pos);
+	}
+
+	public Writer setCharacterStream(long pos) throws SQLException {
+		return getWrappedClob().setCharacterStream(pos);
+	}
+
+	public void truncate(long len) throws SQLException {
+		getWrappedClob().truncate(len);
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/lob/SerializableClob.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/lob/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/lob/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/lob/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines dummy and wrapper implementations 
+	of <tt>java.sql.Clob</tt> and <tt>java.sql.Blob</tt>.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/lob/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/AbstractAuxiliaryDatabaseObject.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/AbstractAuxiliaryDatabaseObject.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/AbstractAuxiliaryDatabaseObject.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+// $Id: AbstractAuxiliaryDatabaseObject.java 7801 2005-08-10 12:16:55Z steveebersole $
+package org.hibernate.mapping;
+
+import java.util.HashSet;
+
+import org.hibernate.dialect.Dialect;
+
+/**
+ * Convenience base class for {@link AuxiliaryDatabaseObject}s.
+ * <p/>
+ * This implementation performs dialect scoping checks strictly based on
+ * dialect name comparisons.  Custom implementations might want to do
+ * instanceof-type checks.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractAuxiliaryDatabaseObject implements AuxiliaryDatabaseObject {
+
+	private final HashSet dialectScopes;
+
+	protected AbstractAuxiliaryDatabaseObject() {
+		this.dialectScopes = new HashSet();
+	}
+
+	protected AbstractAuxiliaryDatabaseObject(HashSet dialectScopes) {
+		this.dialectScopes = dialectScopes;
+	}
+
+	public void addDialectScope(String dialectName) {
+		dialectScopes.add( dialectName );
+	}
+
+	public HashSet getDialectScopes() {
+		return dialectScopes;
+	}
+
+	public boolean appliesToDialect(Dialect dialect) {
+		// empty means no scoping
+		return dialectScopes.isEmpty() || dialectScopes.contains( dialect.getClass().getName() );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Any.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Any.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Any.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+//$Id: Any.java 4905 2004-12-07 09:59:56Z maxcsaucdk $
+package org.hibernate.mapping;
+
+import java.util.Map;
+
+import org.hibernate.MappingException;
+import org.hibernate.type.MetaType;
+import org.hibernate.type.AnyType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * A Hibernate "any" type (ie. polymorphic association to
+ * one-of-several tables).
+ * @author Gavin King
+ */
+public class Any extends SimpleValue {
+
+	private String identifierTypeName;
+	private String metaTypeName = "string";
+	private Map metaValues;
+
+	public Any(Table table) {
+		super(table);
+	}
+
+	public String getIdentifierType() {
+		return identifierTypeName;
+	}
+
+	public void setIdentifierType(String identifierType) {
+		this.identifierTypeName = identifierType;
+	}
+
+	public Type getType() throws MappingException {
+		return new AnyType(
+			metaValues==null ?
+				TypeFactory.heuristicType(metaTypeName) :
+				new MetaType( metaValues, TypeFactory.heuristicType(metaTypeName) ),
+				TypeFactory.heuristicType(identifierTypeName)
+		);
+	}
+
+	public void setTypeByReflection(String propertyClass, String propertyName) {}
+
+	public String getMetaType() {
+		return metaTypeName;
+	}
+
+	public void setMetaType(String type) {
+		metaTypeName = type;
+	}
+
+	public Map getMetaValues() {
+		return metaValues;
+	}
+
+	public void setMetaValues(Map metaValues) {
+		this.metaValues = metaValues;
+	}
+
+	public void setTypeUsingReflection(String className, String propertyName)
+		throws MappingException {
+	}
+
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Array.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Array.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Array.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,68 @@
+//$Id: Array.java 5793 2005-02-20 03:34:50Z oneovthafew $
+package org.hibernate.mapping;
+
+import org.hibernate.MappingException;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.PrimitiveType;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * An array mapping has a primary key consisting of
+ * the key columns + index column.
+ * @author Gavin King
+ */
+public class Array extends List {
+
+	private String elementClassName;
+
+	/**
+	 * Constructor for Array.
+	 * @param owner
+	 */
+	public Array(PersistentClass owner) {
+		super(owner);
+	}
+
+	public Class getElementClass() throws MappingException {
+		if (elementClassName==null) {
+			org.hibernate.type.Type elementType = getElement().getType();
+			return isPrimitiveArray() ?
+				( (PrimitiveType) elementType ).getPrimitiveClass() :
+				elementType.getReturnedClass();
+		}
+		else {
+			try {
+				return ReflectHelper.classForName(elementClassName);
+			}
+			catch (ClassNotFoundException cnfe) {
+				throw new MappingException(cnfe);
+			}
+		}
+	}
+
+	public CollectionType getDefaultCollectionType() throws MappingException {
+		return TypeFactory.array( getRole(), getReferencedPropertyName(), isEmbedded(), getElementClass() );
+	}
+
+	public boolean isArray() {
+		return true;
+	}
+
+	/**
+	 * @return Returns the elementClassName.
+	 */
+	public String getElementClassName() {
+		return elementClassName;
+	}
+	/**
+	 * @param elementClassName The elementClassName to set.
+	 */
+	public void setElementClassName(String elementClassName) {
+		this.elementClassName = elementClassName;
+	}
+	
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/AuxiliaryDatabaseObject.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/AuxiliaryDatabaseObject.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/AuxiliaryDatabaseObject.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+// $Id: AuxiliaryDatabaseObject.java 7800 2005-08-10 12:13:00Z steveebersole $
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+
+import org.hibernate.dialect.Dialect;
+
+/**
+ * Auxiliary database objects (i.e., triggers, stored procedures, etc) defined
+ * in the mappings.  Allows Hibernate to manage their lifecycle as part of
+ * creating/dropping the schema.
+ *
+ * @author Steve Ebersole
+ */
+public interface AuxiliaryDatabaseObject extends RelationalModel, Serializable {
+	/**
+	 * Add the given dialect name to the scope of dialects to which
+	 * this database object applies.
+	 *
+	 * @param dialectName The name of a dialect.
+	 */
+	void addDialectScope(String dialectName);
+
+	/**
+	 * Does this database object apply to the given dialect?
+	 *
+	 * @param dialect The dialect to check against.
+	 * @return True if this database object does apply to the given dialect.
+	 */
+	boolean appliesToDialect(Dialect dialect);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Backref.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Backref.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Backref.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: Backref.java 6924 2005-05-27 01:30:18Z oneovthafew $
+package org.hibernate.mapping;
+
+import org.hibernate.property.BackrefPropertyAccessor;
+import org.hibernate.property.PropertyAccessor;
+
+/**
+ * @author Gavin King
+ */
+public class Backref extends Property {
+	private String collectionRole;
+	private String entityName;
+	
+	public boolean isBackRef() {
+		return true;
+	}
+	public String getCollectionRole() {
+		return collectionRole;
+	}
+	public void setCollectionRole(String collectionRole) {
+		this.collectionRole = collectionRole;
+	}
+
+	public boolean isBasicPropertyAccessor() {
+		return false;
+	}
+
+	public PropertyAccessor getPropertyAccessor(Class clazz) {
+		return new BackrefPropertyAccessor(collectionRole, entityName);
+	}
+	
+	public String getEntityName() {
+		return entityName;
+	}
+	public void setEntityName(String entityName) {
+		this.entityName = entityName;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Backref.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Bag.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Bag.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Bag.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+//$Id: Bag.java 5793 2005-02-20 03:34:50Z oneovthafew $
+package org.hibernate.mapping;
+
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * A bag permits duplicates, so it has no primary key
+ * @author Gavin King
+ */
+public class Bag extends Collection {
+
+	public Bag(PersistentClass owner) {
+		super(owner);
+	}
+
+	public CollectionType getDefaultCollectionType() {
+		return TypeFactory.bag( getRole(), getReferencedPropertyName(), isEmbedded() );
+	}
+
+	void createPrimaryKey() {
+		//create an index on the key columns??
+	}
+
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Collection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Collection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Collection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,622 @@
+// $Id: Collection.java 11496 2007-05-09 03:54:06Z steve.ebersole at jboss.com $
+package org.hibernate.mapping;
+
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Properties;
+
+import org.hibernate.FetchMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.EmptyIterator;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * Mapping for a collection. Subclasses specialize to particular collection styles.
+ * 
+ * @author Gavin King
+ */
+public abstract class Collection implements Fetchable, Value, Filterable {
+
+	public static final String DEFAULT_ELEMENT_COLUMN_NAME = "elt";
+	public static final String DEFAULT_KEY_COLUMN_NAME = "id";
+
+	private KeyValue key;
+	private Value element;
+	private Table collectionTable;
+	private String role;
+	private boolean lazy;
+	private boolean extraLazy;
+	private boolean inverse;
+	private boolean mutable = true;
+	private boolean subselectLoadable;
+	private String cacheConcurrencyStrategy;
+	private String cacheRegionName;
+	private String orderBy;
+	private String where;
+	private String manyToManyWhere;
+	private String manyToManyOrderBy;
+	private PersistentClass owner;
+	private String referencedPropertyName;
+	private String nodeName;
+	private String elementNodeName;
+	private boolean sorted;
+	private Comparator comparator;
+	private String comparatorClassName;
+	private boolean orphanDelete;
+	private int batchSize = -1;
+	private FetchMode fetchMode;
+	private boolean embedded = true;
+	private boolean optimisticLocked = true;
+	private Class collectionPersisterClass;
+	private String typeName;
+	private Properties typeParameters;
+	private final java.util.Map filters = new HashMap();
+	private final java.util.Map manyToManyFilters = new HashMap();
+	private final java.util.Set synchronizedTables = new HashSet();
+
+	private String customSQLInsert;
+	private boolean customInsertCallable;
+	private ExecuteUpdateResultCheckStyle insertCheckStyle;
+	private String customSQLUpdate;
+	private boolean customUpdateCallable;
+	private ExecuteUpdateResultCheckStyle updateCheckStyle;
+	private String customSQLDelete;
+	private boolean customDeleteCallable;
+	private ExecuteUpdateResultCheckStyle deleteCheckStyle;
+	private String customSQLDeleteAll;
+	private boolean customDeleteAllCallable;
+	private ExecuteUpdateResultCheckStyle deleteAllCheckStyle;
+
+	private String loaderName;
+
+	protected Collection(PersistentClass owner) {
+		this.owner = owner;
+	}
+
+	public boolean isSet() {
+		return false;
+	}
+
+	public KeyValue getKey() {
+		return key;
+	}
+
+	public Value getElement() {
+		return element;
+	}
+
+	public boolean isIndexed() {
+		return false;
+	}
+
+	public Table getCollectionTable() {
+		return collectionTable;
+	}
+
+	public void setCollectionTable(Table table) {
+		this.collectionTable = table;
+	}
+
+	public boolean isSorted() {
+		return sorted;
+	}
+
+	public Comparator getComparator() {
+		if ( comparator == null && comparatorClassName != null ) {
+			try {
+				setComparator( (Comparator) ReflectHelper.classForName( comparatorClassName ).newInstance() );
+			}
+			catch ( Exception e ) {
+				throw new MappingException(
+						"Could not instantiate comparator class [" + comparatorClassName
+						+ "] for collection " + getRole()  
+				);
+			}
+		}
+		return comparator;
+	}
+
+	public boolean isLazy() {
+		return lazy;
+	}
+
+	public void setLazy(boolean lazy) {
+		this.lazy = lazy;
+	}
+
+	public String getRole() {
+		return role;
+	}
+
+	public abstract CollectionType getDefaultCollectionType() throws MappingException;
+
+	public boolean isPrimitiveArray() {
+		return false;
+	}
+
+	public boolean isArray() {
+		return false;
+	}
+
+	public boolean hasFormula() {
+		return false;
+	}
+
+	public boolean isOneToMany() {
+		return element instanceof OneToMany;
+	}
+
+	public boolean isInverse() {
+		return inverse;
+	}
+
+	public String getOwnerEntityName() {
+		return owner.getEntityName();
+	}
+
+	public String getOrderBy() {
+		return orderBy;
+	}
+
+	public void setComparator(Comparator comparator) {
+		this.comparator = comparator;
+	}
+
+	public void setElement(Value element) {
+		this.element = element;
+	}
+
+	public void setKey(KeyValue key) {
+		this.key = key;
+	}
+
+	public void setOrderBy(String orderBy) {
+		this.orderBy = orderBy;
+	}
+
+	public void setRole(String role) {
+		this.role = role==null ? null : role.intern();
+	}
+
+	public void setSorted(boolean sorted) {
+		this.sorted = sorted;
+	}
+
+	public void setInverse(boolean inverse) {
+		this.inverse = inverse;
+	}
+
+	public PersistentClass getOwner() {
+		return owner;
+	}
+
+	public void setOwner(PersistentClass owner) {
+		this.owner = owner;
+	}
+
+	public String getWhere() {
+		return where;
+	}
+
+	public void setWhere(String where) {
+		this.where = where;
+	}
+
+	public String getManyToManyWhere() {
+		return manyToManyWhere;
+	}
+
+	public void setManyToManyWhere(String manyToManyWhere) {
+		this.manyToManyWhere = manyToManyWhere;
+	}
+
+	public String getManyToManyOrdering() {
+		return manyToManyOrderBy;
+	}
+
+	public void setManyToManyOrdering(String orderFragment) {
+		this.manyToManyOrderBy = orderFragment;
+	}
+
+	public boolean isIdentified() {
+		return false;
+	}
+
+	public boolean hasOrphanDelete() {
+		return orphanDelete;
+	}
+
+	public void setOrphanDelete(boolean orphanDelete) {
+		this.orphanDelete = orphanDelete;
+	}
+
+	public int getBatchSize() {
+		return batchSize;
+	}
+
+	public void setBatchSize(int i) {
+		batchSize = i;
+	}
+
+	public FetchMode getFetchMode() {
+		return fetchMode;
+	}
+
+	public void setFetchMode(FetchMode fetchMode) {
+		this.fetchMode = fetchMode;
+	}
+
+	public void setCollectionPersisterClass(Class persister) {
+		this.collectionPersisterClass = persister;
+	}
+
+	public Class getCollectionPersisterClass() {
+		return collectionPersisterClass;
+	}
+
+	public void validate(Mapping mapping) throws MappingException {
+		if ( getKey().isCascadeDeleteEnabled() && ( !isInverse() || !isOneToMany() ) ) {
+			throw new MappingException(
+				"only inverse one-to-many associations may use on-delete=\"cascade\": " 
+				+ getRole() );
+		}
+		if ( !getKey().isValid( mapping ) ) {
+			throw new MappingException(
+				"collection foreign key mapping has wrong number of columns: "
+				+ getRole()
+				+ " type: "
+				+ getKey().getType().getName() );
+		}
+		if ( !getElement().isValid( mapping ) ) {
+			throw new MappingException( 
+				"collection element mapping has wrong number of columns: "
+				+ getRole()
+				+ " type: "
+				+ getElement().getType().getName() );
+		}
+
+		checkColumnDuplication();
+		
+		if ( elementNodeName!=null && elementNodeName.startsWith("@") ) {
+			throw new MappingException("element node must not be an attribute: " + elementNodeName );
+		}
+		if ( elementNodeName!=null && elementNodeName.equals(".") ) {
+			throw new MappingException("element node must not be the parent: " + elementNodeName );
+		}
+		if ( nodeName!=null && nodeName.indexOf('@')>-1 ) {
+			throw new MappingException("collection node must not be an attribute: " + elementNodeName );
+		}
+	}
+
+	private void checkColumnDuplication(java.util.Set distinctColumns, Iterator columns)
+			throws MappingException {
+		while ( columns.hasNext() ) {
+			Selectable s = (Selectable) columns.next();
+			if ( !s.isFormula() ) {
+				Column col = (Column) s;
+				if ( !distinctColumns.add( col.getName() ) ) {
+					throw new MappingException( "Repeated column in mapping for collection: "
+						+ getRole()
+						+ " column: "
+						+ col.getName() );
+				}
+			}
+		}
+	}
+
+	private void checkColumnDuplication() throws MappingException {
+		HashSet cols = new HashSet();
+		checkColumnDuplication( cols, getKey().getColumnIterator() );
+		if ( isIndexed() ) {
+			checkColumnDuplication( cols, ( (IndexedCollection) this )
+				.getIndex()
+				.getColumnIterator() );
+		}
+		if ( isIdentified() ) {
+			checkColumnDuplication( cols, ( (IdentifierCollection) this )
+				.getIdentifier()
+				.getColumnIterator() );
+		}
+		if ( !isOneToMany() ) {
+			checkColumnDuplication( cols, getElement().getColumnIterator() );
+		}
+	}
+
+	public Iterator getColumnIterator() {
+		return EmptyIterator.INSTANCE;
+	}
+
+	public int getColumnSpan() {
+		return 0;
+	}
+
+	public Type getType() throws MappingException {
+		return getCollectionType();
+	}
+
+	public CollectionType getCollectionType() {
+		if ( typeName == null ) {
+			return getDefaultCollectionType();
+		}
+		else {
+			return TypeFactory.customCollection( typeName, typeParameters, role, referencedPropertyName, isEmbedded() );
+		}
+	}
+
+	public boolean isNullable() {
+		return true;
+	}
+
+	public boolean isAlternateUniqueKey() {
+		return false;
+	}
+
+	public Table getTable() {
+		return owner.getTable();
+	}
+
+	public void createForeignKey() {
+	}
+
+	public boolean isSimpleValue() {
+		return false;
+	}
+
+	public boolean isValid(Mapping mapping) throws MappingException {
+		return true;
+	}
+
+	private void createForeignKeys() throws MappingException {
+		// if ( !isInverse() ) { // for inverse collections, let the "other end" handle it
+		if ( referencedPropertyName == null ) {
+			getElement().createForeignKey();
+			key.createForeignKeyOfEntity( getOwner().getEntityName() );
+		}
+		// }
+	}
+
+	abstract void createPrimaryKey();
+
+	public void createAllKeys() throws MappingException {
+		createForeignKeys();
+		if ( !isInverse() ) createPrimaryKey();
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return cacheConcurrencyStrategy;
+	}
+
+	public void setCacheConcurrencyStrategy(String cacheConcurrencyStrategy) {
+		this.cacheConcurrencyStrategy = cacheConcurrencyStrategy;
+	}
+
+	public void setTypeUsingReflection(String className, String propertyName) {
+	}
+
+	public String getCacheRegionName() {
+		return cacheRegionName == null ? role : cacheRegionName;
+	}
+
+	public void setCacheRegionName(String cacheRegionName) {
+		this.cacheRegionName = cacheRegionName;
+	}
+
+
+
+	public void setCustomSQLInsert(String customSQLInsert, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+		this.customSQLInsert = customSQLInsert;
+		this.customInsertCallable = callable;
+		this.insertCheckStyle = checkStyle;
+	}
+
+	public String getCustomSQLInsert() {
+		return customSQLInsert;
+	}
+
+	public boolean isCustomInsertCallable() {
+		return customInsertCallable;
+	}
+
+	public ExecuteUpdateResultCheckStyle getCustomSQLInsertCheckStyle() {
+		return insertCheckStyle;
+	}
+
+	public void setCustomSQLUpdate(String customSQLUpdate, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+		this.customSQLUpdate = customSQLUpdate;
+		this.customUpdateCallable = callable;
+		this.updateCheckStyle = checkStyle;
+	}
+
+	public String getCustomSQLUpdate() {
+		return customSQLUpdate;
+	}
+
+	public boolean isCustomUpdateCallable() {
+		return customUpdateCallable;
+	}
+
+	public ExecuteUpdateResultCheckStyle getCustomSQLUpdateCheckStyle() {
+		return updateCheckStyle;
+	}
+
+	public void setCustomSQLDelete(String customSQLDelete, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+		this.customSQLDelete = customSQLDelete;
+		this.customDeleteCallable = callable;
+		this.deleteCheckStyle = checkStyle;
+	}
+
+	public String getCustomSQLDelete() {
+		return customSQLDelete;
+	}
+
+	public boolean isCustomDeleteCallable() {
+		return customDeleteCallable;
+	}
+
+	public ExecuteUpdateResultCheckStyle getCustomSQLDeleteCheckStyle() {
+		return deleteCheckStyle;
+	}
+
+	public void setCustomSQLDeleteAll(String customSQLDeleteAll, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+		this.customSQLDeleteAll = customSQLDeleteAll;
+		this.customDeleteAllCallable = callable;
+		this.deleteAllCheckStyle = checkStyle;
+	}
+
+	public String getCustomSQLDeleteAll() {
+		return customSQLDeleteAll;
+	}
+
+	public boolean isCustomDeleteAllCallable() {
+		return customDeleteAllCallable;
+	}
+
+	public ExecuteUpdateResultCheckStyle getCustomSQLDeleteAllCheckStyle() {
+		return deleteAllCheckStyle;
+	}
+
+	public void addFilter(String name, String condition) {
+		filters.put( name, condition );
+	}
+
+	public java.util.Map getFilterMap() {
+		return filters;
+	}
+
+	public void addManyToManyFilter(String name, String condition) {
+		manyToManyFilters.put( name, condition );
+	}
+
+	public java.util.Map getManyToManyFilterMap() {
+		return manyToManyFilters;
+	}
+
+	public String toString() {
+		return getClass().getName() + '(' + getRole() + ')';
+	}
+
+	public java.util.Set getSynchronizedTables() {
+		return synchronizedTables;
+	}
+
+	public String getLoaderName() {
+		return loaderName;
+	}
+
+	public void setLoaderName(String name) {
+		this.loaderName = name==null ? null : name.intern();
+	}
+
+	public String getReferencedPropertyName() {
+		return referencedPropertyName;
+	}
+
+	public void setReferencedPropertyName(String propertyRef) {
+		this.referencedPropertyName = propertyRef==null ? null : propertyRef.intern();
+	}
+
+	public boolean isOptimisticLocked() {
+		return optimisticLocked;
+	}
+
+	public void setOptimisticLocked(boolean optimisticLocked) {
+		this.optimisticLocked = optimisticLocked;
+	}
+
+	public boolean isMap() {
+		return false;
+	}
+
+	public String getTypeName() {
+		return typeName;
+	}
+
+	public void setTypeName(String typeName) {
+		this.typeName = typeName;
+	}
+
+	public Properties getTypeParameters() {
+		return typeParameters;
+	}
+
+	public void setTypeParameters(Properties parameterMap) {
+		this.typeParameters = parameterMap;
+	}
+
+	public boolean[] getColumnInsertability() {
+		return ArrayHelper.EMPTY_BOOLEAN_ARRAY;
+	}
+
+	public boolean[] getColumnUpdateability() {
+		return ArrayHelper.EMPTY_BOOLEAN_ARRAY;
+	}
+
+	public String getNodeName() {
+		return nodeName;
+	}
+
+	public void setNodeName(String nodeName) {
+		this.nodeName = nodeName;
+	}
+
+	public String getElementNodeName() {
+		return elementNodeName;
+	}
+
+	public void setElementNodeName(String elementNodeName) {
+		this.elementNodeName = elementNodeName;
+	}
+
+	public boolean isEmbedded() {
+		return embedded;
+	}
+
+	public void setEmbedded(boolean embedded) {
+		this.embedded = embedded;
+	}
+
+	public boolean isSubselectLoadable() {
+		return subselectLoadable;
+	}
+	
+
+	public void setSubselectLoadable(boolean subqueryLoadable) {
+		this.subselectLoadable = subqueryLoadable;
+	}
+
+	public boolean isMutable() {
+		return mutable;
+	}
+
+	public void setMutable(boolean mutable) {
+		this.mutable = mutable;
+	}
+
+	public boolean isExtraLazy() {
+		return extraLazy;
+	}
+
+	public void setExtraLazy(boolean extraLazy) {
+		this.extraLazy = extraLazy;
+	}
+	
+	public boolean hasOrder() {
+		return orderBy!=null || manyToManyOrderBy!=null;
+	}
+
+	public void setComparatorClassName(String comparatorClassName) {
+		this.comparatorClassName = comparatorClassName;		
+	}
+	
+	public String getComparatorClassName() {
+		return comparatorClassName;
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Column.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Column.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Column.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,310 @@
+//$Id: Column.java 9908 2006-05-08 20:59:20Z max.andersen at jboss.com $
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.function.SQLFunctionRegistry;
+import org.hibernate.engine.Mapping;
+import org.hibernate.util.StringHelper;
+
+/**
+ * A column of a relational database table
+ * @author Gavin King
+ */
+public class Column implements Selectable, Serializable, Cloneable {
+
+	public static final int DEFAULT_LENGTH = 255;
+	public static final int DEFAULT_PRECISION = 19;
+	public static final int DEFAULT_SCALE = 2;
+
+	private int length=DEFAULT_LENGTH;
+	private int precision=DEFAULT_PRECISION;
+	private int scale=DEFAULT_SCALE;
+	private Value value;
+	private int typeIndex = 0;
+	private String name;
+	private boolean nullable=true;
+	private boolean unique=false;
+	private String sqlType;
+	private Integer sqlTypeCode;
+	private boolean quoted=false;
+	int uniqueInteger;
+	private String checkConstraint;
+	private String comment;
+	private String defaultValue;
+
+	public Column() { };
+
+	public Column(String columnName) {
+		setName(columnName);
+	}
+
+	public int getLength() {
+		return length;
+	}
+	public void setLength(int length) {
+		this.length = length;
+	}
+	public Value getValue() {
+		return value;
+	}
+	public void setValue(Value value) {
+		this.value= value;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		if (
+			name.charAt(0)=='`' ||
+			Dialect.QUOTE.indexOf( name.charAt(0) ) > -1 //TODO: deprecated, remove eventually
+		) {
+			quoted=true;
+			this.name=name.substring( 1, name.length()-1 );
+		}
+		else {
+			this.name = name;
+		}
+	}
+
+	/** returns quoted name as it would be in the mapping file. */
+	public String getQuotedName() {
+		return quoted ?
+				"`" + name + "`" :
+				name;
+	}
+
+	public String getQuotedName(Dialect d) {
+		return quoted ?
+			d.openQuote() + name + d.closeQuote() :
+			name;
+	}
+	
+	/**
+	 * For any column name, generate an alias that is unique
+	 * to that column name, and also 10 characters or less
+	 * in length.
+	 */
+	public String getAlias(Dialect dialect) {
+		String alias = name;
+		String unique = Integer.toString(uniqueInteger) + '_';
+		int lastLetter = StringHelper.lastIndexOfLetter(name);
+		if ( lastLetter == -1 ) {
+			alias = "column";
+		}
+		else if ( lastLetter < name.length()-1 ) {
+			alias = name.substring(0, lastLetter+1);
+		}
+		if ( alias.length() > dialect.getMaxAliasLength() ) {
+			alias = alias.substring( 0, dialect.getMaxAliasLength() - unique.length() );
+		}
+		boolean useRawName = name.equals(alias) && 
+			!quoted && 
+			!name.toLowerCase().equals("rowid");
+		if ( useRawName ) {
+			return alias;
+		}
+		else {
+			return alias + unique;
+		}
+	}
+	
+	/**
+	 * Generate a column alias that is unique across multiple tables
+	 */
+	public String getAlias(Dialect dialect, Table table) {
+		return getAlias(dialect) + table.getUniqueInteger() + '_';
+	}
+
+	public boolean isNullable() {
+		return nullable;
+	}
+
+	public void setNullable(boolean nullable) {
+		this.nullable=nullable;
+	}
+
+	public int getTypeIndex() {
+		return typeIndex;
+	}
+	public void setTypeIndex(int typeIndex) {
+		this.typeIndex = typeIndex;
+	}
+
+	public int getSqlTypeCode(Mapping mapping) throws MappingException {
+		org.hibernate.type.Type type = getValue().getType();
+		try {
+			int sqlTypeCode = type.sqlTypes(mapping)[ getTypeIndex() ];
+			if(getSqlTypeCode()!=null && getSqlTypeCode().intValue()!=sqlTypeCode) {
+				throw new MappingException("SQLType code's does not match. mapped as " + sqlTypeCode + " but is " + getSqlTypeCode() );
+			}
+			return sqlTypeCode;
+		}
+		catch (Exception e) {
+			throw new MappingException(
+					"Could not determine type for column " +
+					name +
+					" of type " +
+					type.getClass().getName() +
+					": " +
+					e.getClass().getName(),
+					e
+				);
+		}
+	}
+
+	/**
+	 * Returns the underlying columns sqltypecode.
+	 * If null, it is because the sqltype code is unknown.
+	 * 
+	 * Use #getSqlTypeCode(Mapping) to retreive the sqltypecode used
+	 * for the columns associated Value/Type.
+	 * 
+	 * @return sqltypecode if it is set, otherwise null.
+	 */
+	public Integer getSqlTypeCode() {
+		return sqlTypeCode;
+	}
+	
+	public void setSqlTypeCode(Integer typecode) {
+		sqlTypeCode=typecode;
+	}
+	
+	public boolean isUnique() {
+		return unique;
+	}
+
+
+	public String getSqlType(Dialect dialect, Mapping mapping) throws HibernateException {
+		return sqlType==null ?
+			dialect.getTypeName( getSqlTypeCode(mapping), getLength(), getPrecision(), getScale() ) :
+			sqlType;
+	}
+
+	public boolean equals(Object object) {
+		return object instanceof Column && equals( (Column) object );
+	}
+
+	public boolean equals(Column column) {
+		if (null == column) return false;
+		if (this == column) return true;
+
+		return isQuoted() ? 
+			name.equals(column.name) :
+			name.equalsIgnoreCase(column.name);
+	}
+
+	//used also for generation of FK names!
+	public int hashCode() {
+		return isQuoted() ? 
+			name.hashCode() : 
+			name.toLowerCase().hashCode();
+	}
+
+	public String getSqlType() {
+		return sqlType;
+	}
+
+	public void setSqlType(String sqlType) {
+		this.sqlType = sqlType;
+	}
+
+	public void setUnique(boolean unique) {
+		this.unique = unique;
+	}
+
+	public boolean isQuoted() {
+		return quoted;
+	}
+
+	public String toString() {
+		return getClass().getName() + '(' + getName() + ')';
+	}
+
+	public String getCheckConstraint() {
+		return checkConstraint;
+	}
+
+	public void setCheckConstraint(String checkConstraint) {
+		this.checkConstraint = checkConstraint;
+	}
+
+	public boolean hasCheckConstraint() {
+		return checkConstraint!=null;
+	}
+
+	public String getTemplate(Dialect dialect, SQLFunctionRegistry functionRegistry) {
+		return getQuotedName(dialect);
+	}
+
+	public boolean isFormula() {
+		return false;
+	}
+
+	public String getText(Dialect d) {
+		return getQuotedName(d);
+	}
+	public String getText() {
+		return getName();
+	}
+	
+	public int getPrecision() {
+		return precision;
+	}
+	public void setPrecision(int scale) {
+		this.precision = scale;
+	}
+
+	public int getScale() {
+		return scale;
+	}
+	public void setScale(int scale) {
+		this.scale = scale;
+	}
+
+	public String getComment() {
+		return comment;
+	}
+
+	public void setComment(String comment) {
+		this.comment = comment;
+	}
+
+	public String getDefaultValue() {
+		return defaultValue;
+	}
+
+	public void setDefaultValue(String defaultValue) {
+		this.defaultValue = defaultValue;
+	}
+
+	public String getCanonicalName() {
+		return quoted ? name : name.toLowerCase();
+	}
+
+	/**
+	 * Shallow copy, the value is not copied
+	 */
+	protected Object clone() {
+		Column copy = new Column();
+		copy.setLength( length );
+		copy.setScale( scale );
+		copy.setValue( value );
+		copy.setTypeIndex( typeIndex );
+		copy.setName( getQuotedName() );
+		copy.setNullable( nullable );
+		copy.setPrecision( precision );
+		copy.setUnique( unique );
+		copy.setSqlType( sqlType );
+		copy.setSqlTypeCode( sqlTypeCode );
+		copy.uniqueInteger = uniqueInteger; //usually useless
+		copy.setCheckConstraint( checkConstraint );
+		copy.setComment( comment );
+		copy.setDefaultValue( defaultValue );
+		return copy;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Component.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Component.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Component.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,275 @@
+//$Id: Component.java 10119 2006-07-14 00:09:19Z steve.ebersole at jboss.com $
+package org.hibernate.mapping;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.EntityMode;
+import org.hibernate.MappingException;
+import org.hibernate.tuple.component.ComponentMetamodel;
+import org.hibernate.type.ComponentType;
+import org.hibernate.type.EmbeddedComponentType;
+import org.hibernate.type.Type;
+import org.hibernate.util.JoinedIterator;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * The mapping for a component, composite element,
+ * composite identifier, etc.
+ * @author Gavin King
+ */
+public class Component extends SimpleValue implements MetaAttributable {
+
+	private ArrayList properties = new ArrayList();
+	private String componentClassName;
+	private boolean embedded;
+	private String parentProperty;
+	private PersistentClass owner;
+	private boolean dynamic;
+	private Map metaAttributes;
+	private String nodeName;
+	private boolean isKey;
+	private String roleName;
+
+	private java.util.Map tuplizerImpls;
+
+	public Component(PersistentClass owner) throws MappingException {
+		super( owner.getTable() );
+		this.owner = owner;
+	}
+
+	public Component(Component component) throws MappingException {
+		super( component.getTable() );
+		this.owner = component.getOwner();
+	}
+
+	public Component(Join join) throws MappingException {
+		super( join.getTable() );
+		this.owner = join.getPersistentClass();
+	}
+
+	public Component(Collection collection) throws MappingException {
+		super( collection.getCollectionTable() );
+		this.owner = collection.getOwner();
+	}
+
+	public int getPropertySpan() {
+		return properties.size();
+	}
+	public Iterator getPropertyIterator() {
+		return properties.iterator();
+	}
+	public void addProperty(Property p) {
+		properties.add(p);
+	}
+	public void addColumn(Column column) {
+		throw new UnsupportedOperationException("Cant add a column to a component");
+	}
+	public int getColumnSpan() {
+		int n=0;
+		Iterator iter = getPropertyIterator();
+		while ( iter.hasNext() ) {
+			Property p = (Property) iter.next();
+			n+= p.getColumnSpan();
+		}
+		return n;
+	}
+	public Iterator getColumnIterator() {
+		Iterator[] iters = new Iterator[ getPropertySpan() ];
+		Iterator iter = getPropertyIterator();
+		int i=0;
+		while ( iter.hasNext() ) {
+			iters[i++] = ( (Property) iter.next() ).getColumnIterator();
+		}
+		return new JoinedIterator(iters);
+	}
+
+	public void setTypeByReflection(String propertyClass, String propertyName) {}
+
+	public boolean isEmbedded() {
+		return embedded;
+	}
+
+	public String getComponentClassName() {
+		return componentClassName;
+	}
+
+	public Class getComponentClass() throws MappingException {
+		try {
+			return ReflectHelper.classForName(componentClassName);
+		}
+		catch (ClassNotFoundException cnfe) {
+			throw new MappingException("component class not found: " + componentClassName, cnfe);
+		}
+	}
+
+	public PersistentClass getOwner() {
+		return owner;
+	}
+
+	public String getParentProperty() {
+		return parentProperty;
+	}
+
+	public void setComponentClassName(String componentClass) {
+		this.componentClassName = componentClass;
+	}
+
+	public void setEmbedded(boolean embedded) {
+		this.embedded = embedded;
+	}
+
+	public void setOwner(PersistentClass owner) {
+		this.owner = owner;
+	}
+
+	public void setParentProperty(String parentProperty) {
+		this.parentProperty = parentProperty;
+	}
+
+	public boolean isDynamic() {
+		return dynamic;
+	}
+
+	public void setDynamic(boolean dynamic) {
+		this.dynamic = dynamic;
+	}
+
+	private Type type;
+
+	public Type getType() throws MappingException {
+		// added this caching as I noticed that getType() is being called multiple times...
+		if ( type == null ) {
+			type = buildType();
+		}
+		return type;
+	}
+
+	private Type buildType() {
+		// TODO : temporary initial step towards HHH-1907
+		ComponentMetamodel metamodel = new ComponentMetamodel( this );
+		if ( isEmbedded() ) {
+			return new EmbeddedComponentType( metamodel );
+		}
+		else {
+			return new ComponentType( metamodel );
+		}
+	}
+
+	public void setTypeUsingReflection(String className, String propertyName)
+		throws MappingException {
+	}
+	
+	public java.util.Map getMetaAttributes() {
+		return metaAttributes;
+	}
+	public MetaAttribute getMetaAttribute(String attributeName) {
+		return metaAttributes==null?null:(MetaAttribute) metaAttributes.get(attributeName);
+	}
+
+	public void setMetaAttributes(java.util.Map metas) {
+		this.metaAttributes = metas;
+	}
+	
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}
+	
+	public boolean[] getColumnInsertability() {
+		boolean[] result = new boolean[ getColumnSpan() ];
+		Iterator iter = getPropertyIterator();
+		int i=0;
+		while ( iter.hasNext() ) {
+			Property prop = (Property) iter.next();
+			boolean[] chunk = prop.getValue().getColumnInsertability();
+			if ( prop.isInsertable() ) {
+				System.arraycopy(chunk, 0, result, i, chunk.length);
+			}
+			i+=chunk.length;
+		}
+		return result;
+	}
+
+	public boolean[] getColumnUpdateability() {
+		boolean[] result = new boolean[ getColumnSpan() ];
+		Iterator iter = getPropertyIterator();
+		int i=0;
+		while ( iter.hasNext() ) {
+			Property prop = (Property) iter.next();
+			boolean[] chunk = prop.getValue().getColumnUpdateability();
+			if ( prop.isUpdateable() ) {
+				System.arraycopy(chunk, 0, result, i, chunk.length);
+			}
+			i+=chunk.length;
+		}
+		return result;
+	}
+	
+	public String getNodeName() {
+		return nodeName;
+	}
+	
+	public void setNodeName(String nodeName) {
+		this.nodeName = nodeName;
+	}
+	
+	public boolean isKey() {
+		return isKey;
+	}
+	
+	public void setKey(boolean isKey) {
+		this.isKey = isKey;
+	}
+	
+	public boolean hasPojoRepresentation() {
+		return componentClassName!=null;
+	}
+
+	public void addTuplizer(EntityMode entityMode, String implClassName) {
+		if ( tuplizerImpls == null ) {
+			tuplizerImpls = new HashMap();
+		}
+		tuplizerImpls.put( entityMode, implClassName );
+	}
+
+	public String getTuplizerImplClassName(EntityMode mode) {
+		// todo : remove this once ComponentMetamodel is complete and merged
+		if ( tuplizerImpls == null ) {
+			return null;
+		}
+		return ( String ) tuplizerImpls.get( mode );
+	}
+
+	public Map getTuplizerMap() {
+		if ( tuplizerImpls == null ) {
+			return null;
+		}
+		return java.util.Collections.unmodifiableMap( tuplizerImpls );
+	}
+
+	public Property getProperty(String propertyName) throws MappingException {
+		Iterator iter = getPropertyIterator();
+		while ( iter.hasNext() ) {
+			Property prop = (Property) iter.next();
+			if ( prop.getName().equals(propertyName) ) {
+				return prop;
+			}
+		}
+		throw new MappingException("component property not found: " + propertyName);
+	}
+
+	public String getRoleName() {
+		return roleName;
+	}
+
+	public void setRoleName(String roleName) {
+		this.roleName = roleName;
+	}
+
+	public String toString() {
+		return getClass().getName() + '(' + properties.toString() + ')';
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Constraint.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Constraint.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Constraint.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,111 @@
+//$Id: Constraint.java 10661 2006-10-31 02:19:13Z epbernard $
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.Mapping;
+
+/**
+ * A relational constraint.
+ *
+ * @author Gavin King
+ */
+public abstract class Constraint implements RelationalModel, Serializable {
+
+	private String name;
+	private final List columns = new ArrayList();
+	private Table table;
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Iterator getColumnIterator() {
+		return columns.iterator();
+	}
+
+	public void addColumn(Column column) {
+		if ( !columns.contains( column ) ) columns.add( column );
+	}
+
+	public void addColumns(Iterator columnIterator) {
+		while ( columnIterator.hasNext() ) {
+			Selectable col = (Selectable) columnIterator.next();
+			if ( !col.isFormula() ) addColumn( (Column) col );
+		}
+	}
+
+	/**
+	 * @param column
+	 * @return true if this constraint already contains a column with same name.
+	 */
+	public boolean containsColumn(Column column) {
+		return columns.contains( column );
+	}
+
+	public int getColumnSpan() {
+		return columns.size();
+	}
+
+	public Column getColumn(int i) {
+		return (Column) columns.get( i );
+	}
+
+	public Iterator columnIterator() {
+		return columns.iterator();
+	}
+
+	public Table getTable() {
+		return table;
+	}
+
+	public void setTable(Table table) {
+		this.table = table;
+	}
+
+	public boolean isGenerated(Dialect dialect) {
+		return true;
+	}
+
+	public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
+		if ( isGenerated( dialect ) ) {
+			return "alter table " + getTable()
+					.getQualifiedName( dialect, defaultCatalog, defaultSchema ) + " drop constraint " + getName();
+		}
+		else {
+			return null;
+		}
+	}
+
+	public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, String defaultSchema) {
+		if ( isGenerated( dialect ) ) {
+			String constraintString = sqlConstraintString( dialect, getName(), defaultCatalog, defaultSchema );
+			StringBuffer buf = new StringBuffer( "alter table " )
+					.append( getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema ) )
+					.append( constraintString );
+			return buf.toString();
+		}
+		else {
+			return null;
+		}
+	}
+
+	public List getColumns() {
+		return columns;
+	}
+
+	public abstract String sqlConstraintString(Dialect d, String constraintName, String defaultCatalog,
+											   String defaultSchema);
+
+	public String toString() {
+		return getClass().getName() + '(' + getTable().getName() + getColumns() + ") as " + name;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/DenormalizedTable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/DenormalizedTable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/DenormalizedTable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,90 @@
+//$Id: DenormalizedTable.java 10880 2006-11-29 15:18:34Z epbernard $
+package org.hibernate.mapping;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.util.JoinedIterator;
+
+/**
+ * @author Gavin King
+ */
+public class DenormalizedTable extends Table {
+	
+	private final Table includedTable;
+	
+	public DenormalizedTable(Table includedTable) {
+		this.includedTable = includedTable;
+		includedTable.setHasDenormalizedTables();
+	}
+	
+	public void createForeignKeys() {
+		includedTable.createForeignKeys();
+		Iterator iter = includedTable.getForeignKeyIterator();
+		while ( iter.hasNext() ) {
+			ForeignKey fk = (ForeignKey) iter.next();
+			createForeignKey( 
+					fk.getName() + Integer.toHexString( getName().hashCode() ), 
+					fk.getColumns(), 
+					fk.getReferencedEntityName() 
+				);
+		}
+	}
+
+	public Column getColumn(Column column) {
+		Column superColumn = super.getColumn( column );
+		if (superColumn != null) {
+			return superColumn;
+		}
+		else {
+			return includedTable.getColumn( column );
+		}
+	}
+
+	public Iterator getColumnIterator() {
+		return new JoinedIterator(
+				includedTable.getColumnIterator(),
+				super.getColumnIterator()
+			);
+	}
+
+	public boolean containsColumn(Column column) {
+		return super.containsColumn(column) || includedTable.containsColumn(column);
+	}
+
+	public PrimaryKey getPrimaryKey() {
+		return includedTable.getPrimaryKey();
+	}
+
+	public Iterator getUniqueKeyIterator() {
+		//wierd implementation because of hacky behavior
+		//of Table.sqlCreateString() which modifies the
+		//list of unique keys by side-effect on some
+		//dialects
+		Map uks = new HashMap();
+		uks.putAll( getUniqueKeys() );
+		uks.putAll( includedTable.getUniqueKeys() );
+		return uks.values().iterator();
+	}
+
+	public Iterator getIndexIterator() {
+		List indexes = new ArrayList();
+		Iterator iter = includedTable.getIndexIterator();
+		while ( iter.hasNext() ) {
+			Index parentIndex = (Index) iter.next();
+			Index index = new Index();
+			index.setName( getName() + parentIndex.getName() );
+			index.setTable(this);
+			index.addColumns( parentIndex.getColumnIterator() );
+			indexes.add( index );
+		}
+		return new JoinedIterator(
+				indexes.iterator(),
+				super.getIndexIterator()
+			);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/DependantValue.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/DependantValue.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/DependantValue.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+//$Id: DependantValue.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.mapping;
+
+import org.hibernate.MappingException;
+import org.hibernate.type.Type;
+
+/**
+ * A value which is "typed" by reference to some other
+ * value (for example, a foreign key is typed by the
+ * referenced primary key).
+ *
+ * @author Gavin King
+ */
+public class DependantValue extends SimpleValue {
+	private KeyValue wrappedValue;
+	private boolean nullable;
+	private boolean updateable;
+
+	public DependantValue(Table table, KeyValue prototype) {
+		super(table);
+		this.wrappedValue = prototype;
+	}
+
+	public Type getType() throws MappingException {
+		return wrappedValue.getType();
+	}
+
+	public void setTypeUsingReflection(String className, String propertyName) {}
+	
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}
+
+	public boolean isNullable() {
+		return nullable;
+	
+	}
+	
+	public void setNullable(boolean nullable) {
+		this.nullable = nullable;
+	}
+	
+	public boolean isUpdateable() {
+		return updateable;
+	}
+	
+	public void setUpdateable(boolean updateable) {
+		this.updateable = updateable;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Fetchable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Fetchable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Fetchable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+//$Id: Fetchable.java 6586 2005-04-28 08:35:10Z oneovthafew $
+package org.hibernate.mapping;
+
+import org.hibernate.FetchMode;
+
+/**
+ * Any mapping with an outer-join attribute
+ * @author Gavin King
+ */
+public interface Fetchable {
+	public FetchMode getFetchMode();
+	public void setFetchMode(FetchMode joinedFetch);
+	public boolean isLazy();
+	public void setLazy(boolean lazy);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Filterable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Filterable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Filterable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+// $Id: Filterable.java 4219 2004-08-10 05:11:47Z steveebersole $
+package org.hibernate.mapping;
+
+/**
+ * Defines mapping elements to which filters may be applied.
+ *
+ * @author Steve Ebersole
+ */
+public interface Filterable {
+	public void addFilter(String name, String condition);
+
+	public java.util.Map getFilterMap();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ForeignKey.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ForeignKey.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ForeignKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,163 @@
+//$Id: ForeignKey.java 7360 2005-07-01 16:38:03Z maxcsaucdk $
+package org.hibernate.mapping;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * A foreign key constraint
+ * @author Gavin King
+ */
+public class ForeignKey extends Constraint {
+
+	private Table referencedTable;
+	private String referencedEntityName;
+	private boolean cascadeDeleteEnabled;
+	private List referencedColumns = new ArrayList();    
+    
+	public String sqlConstraintString(Dialect dialect, String constraintName, String defaultCatalog, String defaultSchema) {
+		String[] cols = new String[ getColumnSpan() ];
+		String[] refcols = new String[ getColumnSpan() ];
+		int i=0;
+		Iterator refiter = null;
+		if(isReferenceToPrimaryKey() ) {
+			refiter = referencedTable.getPrimaryKey().getColumnIterator();
+		} 
+		else {
+			refiter = referencedColumns.iterator();
+		}
+		
+		Iterator iter = getColumnIterator();
+		while ( iter.hasNext() ) {
+			cols[i] = ( (Column) iter.next() ).getQuotedName(dialect);
+			refcols[i] = ( (Column) refiter.next() ).getQuotedName(dialect);
+			i++;
+		}
+		String result = dialect.getAddForeignKeyConstraintString(
+			constraintName, cols, referencedTable.getQualifiedName(dialect, defaultCatalog, defaultSchema), refcols, isReferenceToPrimaryKey()
+		);
+		return cascadeDeleteEnabled && dialect.supportsCascadeDelete() ? 
+			result + " on delete cascade" : 
+			result;
+	}
+
+	public Table getReferencedTable() {
+		return referencedTable;
+	}
+
+	private void appendColumns(StringBuffer buf, Iterator columns) {
+		while( columns.hasNext() ) {
+			Column column = (Column) columns.next();
+			buf.append( column.getName() );
+			if ( columns.hasNext() ) buf.append(",");
+		}
+	}
+
+	public void setReferencedTable(Table referencedTable) throws MappingException {
+		//if( isReferenceToPrimaryKey() ) alignColumns(referencedTable); // TODO: possibly remove to allow more piecemal building of a foreignkey.  
+		
+		this.referencedTable = referencedTable;
+	}
+
+	/**
+	 * Validates that columnspan of the foreignkey and the primarykey is the same.
+	 * 
+	 * Furthermore it aligns the length of the underlying tables columns.
+	 * @param referencedTable
+	 */
+	public void alignColumns() {
+		if ( isReferenceToPrimaryKey() ) alignColumns(referencedTable);
+	}
+	
+	private void alignColumns(Table referencedTable) {
+		if ( referencedTable.getPrimaryKey().getColumnSpan()!=getColumnSpan() ) {
+			StringBuffer sb = new StringBuffer();
+			sb.append("Foreign key (")
+                .append( getName() + ":")
+				.append( getTable().getName() )
+				.append(" [");
+			appendColumns( sb, getColumnIterator() );
+			sb.append("])")
+				.append(") must have same number of columns as the referenced primary key (")
+				.append( referencedTable.getName() )
+				.append(" [");
+			appendColumns( sb, referencedTable.getPrimaryKey().getColumnIterator() );
+			sb.append("])");
+			throw new MappingException( sb.toString() );
+		}
+		
+		Iterator fkCols = getColumnIterator();
+		Iterator pkCols = referencedTable.getPrimaryKey().getColumnIterator();
+		while ( pkCols.hasNext() ) {
+			( (Column) fkCols.next() ).setLength( ( (Column) pkCols.next() ).getLength() );
+		}
+
+	}
+
+	public String getReferencedEntityName() {
+		return referencedEntityName;
+	}
+
+	public void setReferencedEntityName(String referencedEntityName) {
+		this.referencedEntityName = referencedEntityName;
+	}
+
+	public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
+		return "alter table " + 
+			getTable().getQualifiedName(dialect, defaultCatalog, defaultSchema) + 
+			dialect.getDropForeignKeyString() + 
+			getName();
+	}
+
+	public boolean isCascadeDeleteEnabled() {
+		return cascadeDeleteEnabled;
+	}
+
+	public void setCascadeDeleteEnabled(boolean cascadeDeleteEnabled) {
+		this.cascadeDeleteEnabled = cascadeDeleteEnabled;
+	}
+	
+	public boolean isPhysicalConstraint() {
+		return referencedTable.isPhysicalTable() && 
+				getTable().isPhysicalTable() && 
+				!referencedTable.hasDenormalizedTables();
+	}
+
+	/** Returns the referenced columns if the foreignkey does not refer to the primary key */
+	public List getReferencedColumns() {
+		return referencedColumns;		
+	}
+
+	/** Does this foreignkey reference the primary key of the reference table */ 
+	public boolean isReferenceToPrimaryKey() {
+		return referencedColumns.isEmpty();
+	}
+
+	public void addReferencedColumns(Iterator referencedColumnsIterator) {
+		while ( referencedColumnsIterator.hasNext() ) {
+			Selectable col = (Selectable) referencedColumnsIterator.next();
+			if ( !col.isFormula() ) addReferencedColumn( (Column) col );
+		}
+	}
+
+	private void addReferencedColumn(Column column) {
+		if ( !referencedColumns.contains(column) ) referencedColumns.add(column);		
+	}
+	
+	public String toString() {
+		if(!isReferenceToPrimaryKey() ) {
+			StringBuffer result = new StringBuffer(getClass().getName() + '(' + getTable().getName() + getColumns() );
+			result.append( " ref-columns:" + '(' + getReferencedColumns() );
+			result.append( ") as " + getName() );
+			return result.toString();
+		} 
+		else {
+			return super.toString();
+		}
+		
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Formula.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Formula.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Formula.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+//$Id: Formula.java 9908 2006-05-08 20:59:20Z max.andersen at jboss.com $
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.function.SQLFunctionRegistry;
+import org.hibernate.sql.Template;
+
+/**
+ * A formula is a derived column value
+ * @author Gavin King
+ */
+public class Formula implements Selectable, Serializable {
+	private static int formulaUniqueInteger=0;
+
+	private String formula;
+	private int uniqueInteger;
+
+	public Formula() {
+		uniqueInteger = formulaUniqueInteger++;
+	}
+
+	public String getTemplate(Dialect dialect, SQLFunctionRegistry functionRegistry) {
+		return Template.renderWhereStringTemplate(formula, dialect, functionRegistry);
+	}
+	public String getText(Dialect dialect) {
+		return getFormula();
+	}
+	public String getText() {
+		return getFormula();
+	}
+	public String getAlias(Dialect dialect) {
+		return "formula" + Integer.toString(uniqueInteger) + '_';
+	}
+	public String getAlias(Dialect dialect, Table table) {
+		return getAlias(dialect);
+	}
+	public String getFormula() {
+		return formula;
+	}
+	public void setFormula(String string) {
+		formula = string;
+	}
+	public boolean isFormula() {
+		return true;
+	}
+
+	public String toString() {
+		return this.getClass().getName() + "( " + formula + " )";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IdentifierBag.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IdentifierBag.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IdentifierBag.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+//$Id: IdentifierBag.java 5793 2005-02-20 03:34:50Z oneovthafew $
+package org.hibernate.mapping;
+
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * An <tt>IdentifierBag</tt> has a primary key consisting of
+ * just the identifier column
+ */
+public class IdentifierBag extends IdentifierCollection {
+
+	public IdentifierBag(PersistentClass owner) {
+		super(owner);
+	}
+
+	public CollectionType getDefaultCollectionType() {
+		return TypeFactory.idbag( getRole(), getReferencedPropertyName(), isEmbedded() );
+	}
+
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IdentifierCollection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IdentifierCollection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IdentifierCollection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+//$Id: IdentifierCollection.java 4173 2004-08-08 04:56:01Z oneovthafew $
+package org.hibernate.mapping;
+
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+
+/**
+ * A collection with a synthetic "identifier" column
+ */
+public abstract class IdentifierCollection extends Collection {
+
+	public static final String DEFAULT_IDENTIFIER_COLUMN_NAME = "id";
+
+	private KeyValue identifier;
+
+	public IdentifierCollection(PersistentClass owner) {
+		super(owner);
+	}
+
+	public KeyValue getIdentifier() {
+		return identifier;
+	}
+	public void setIdentifier(KeyValue identifier) {
+		this.identifier = identifier;
+	}
+	public final boolean isIdentified() {
+		return true;
+	}
+
+	void createPrimaryKey() {
+		if ( !isOneToMany() ) {
+			PrimaryKey pk = new PrimaryKey();
+			pk.addColumns( getIdentifier().getColumnIterator() );
+			getCollectionTable().setPrimaryKey(pk);
+		}
+		else {
+			// don't create a unique key, 'cos some
+			// databases don't like a UK on nullable
+			// columns
+			//getCollectionTable().createUniqueKey( getIdentifier().getConstraintColumns() );
+		}
+		// create an index on the key columns??
+	}
+
+	public void validate(Mapping mapping) throws MappingException {
+		super.validate(mapping);
+		if ( !getIdentifier().isValid(mapping) ) {
+			throw new MappingException(
+				"collection id mapping has wrong number of columns: " +
+				getRole() +
+				" type: " +
+				getIdentifier().getType().getName()
+			);
+		}
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Index.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Index.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Index.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,145 @@
+//$Id: Index.java 10661 2006-10-31 02:19:13Z epbernard $
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.Mapping;
+import org.hibernate.util.StringHelper;
+
+/**
+ * A relational table index
+ *
+ * @author Gavin King
+ */
+public class Index implements RelationalModel, Serializable {
+
+	private Table table;
+	private List columns = new ArrayList();
+	private String name;
+
+	public String sqlCreateString(Dialect dialect, Mapping mapping, String defaultCatalog, String defaultSchema)
+			throws HibernateException {
+		return buildSqlCreateIndexString(
+				dialect,
+				getName(),
+				getTable(),
+				getColumnIterator(),
+				false,
+				defaultCatalog,
+				defaultSchema
+		);
+	}
+
+	public static String buildSqlDropIndexString(
+			Dialect dialect,
+			Table table,
+			String name,
+			String defaultCatalog,
+			String defaultSchema
+	) {
+		return "drop index " +
+				StringHelper.qualify(
+						table.getQualifiedName( dialect, defaultCatalog, defaultSchema ),
+						name
+				);
+	}
+
+	public static String buildSqlCreateIndexString(
+			Dialect dialect,
+			String name,
+			Table table,
+			Iterator columns,
+			boolean unique,
+			String defaultCatalog,
+			String defaultSchema
+	) {
+		//TODO handle supportsNotNullUnique=false, but such a case does not exist in the wild so far
+		StringBuffer buf = new StringBuffer( "create" )
+				.append( unique ?
+						" unique" :
+						"" )
+				.append( " index " )
+				.append( dialect.qualifyIndexName() ?
+						name :
+						StringHelper.unqualify( name ) )
+				.append( " on " )
+				.append( table.getQualifiedName( dialect, defaultCatalog, defaultSchema ) )
+				.append( " (" );
+		Iterator iter = columns;
+		while ( iter.hasNext() ) {
+			buf.append( ( (Column) iter.next() ).getQuotedName( dialect ) );
+			if ( iter.hasNext() ) buf.append( ", " );
+		}
+		buf.append( ")" );
+		return buf.toString();
+	}
+
+
+	// Used only in Table for sqlCreateString (but commented out at the moment)
+	public String sqlConstraintString(Dialect dialect) {
+		StringBuffer buf = new StringBuffer( " index (" );
+		Iterator iter = getColumnIterator();
+		while ( iter.hasNext() ) {
+			buf.append( ( (Column) iter.next() ).getQuotedName( dialect ) );
+			if ( iter.hasNext() ) buf.append( ", " );
+		}
+		return buf.append( ')' ).toString();
+	}
+
+	public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
+		return "drop index " +
+				StringHelper.qualify(
+						table.getQualifiedName( dialect, defaultCatalog, defaultSchema ),
+						name
+				);
+	}
+
+	public Table getTable() {
+		return table;
+	}
+
+	public void setTable(Table table) {
+		this.table = table;
+	}
+
+	public int getColumnSpan() {
+		return columns.size();
+	}
+
+	public Iterator getColumnIterator() {
+		return columns.iterator();
+	}
+
+	public void addColumn(Column column) {
+		if ( !columns.contains( column ) ) columns.add( column );
+	}
+
+	public void addColumns(Iterator extraColumns) {
+		while ( extraColumns.hasNext() ) addColumn( (Column) extraColumns.next() );
+	}
+
+	/**
+	 * @param column
+	 * @return true if this constraint already contains a column with same name.
+	 */
+	public boolean containsColumn(Column column) {
+		return columns.contains( column );
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String toString() {
+		return getClass().getName() + "(" + getName() + ")";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IndexBackref.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IndexBackref.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IndexBackref.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: IndexBackref.java 6924 2005-05-27 01:30:18Z oneovthafew $
+package org.hibernate.mapping;
+
+import org.hibernate.property.IndexPropertyAccessor;
+import org.hibernate.property.PropertyAccessor;
+
+/**
+ * @author Gavin King
+ */
+public class IndexBackref extends Property {
+	private String collectionRole;
+	private String entityName;
+	
+	public boolean isBackRef() {
+		return true;
+	}
+	public String getCollectionRole() {
+		return collectionRole;
+	}
+	public void setCollectionRole(String collectionRole) {
+		this.collectionRole = collectionRole;
+	}
+
+	public boolean isBasicPropertyAccessor() {
+		return false;
+	}
+
+	public PropertyAccessor getPropertyAccessor(Class clazz) {
+		return new IndexPropertyAccessor(collectionRole, entityName);
+	}
+	
+	public String getEntityName() {
+		return entityName;
+	}
+	public void setEntityName(String entityName) {
+		this.entityName = entityName;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IndexBackref.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IndexedCollection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IndexedCollection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/IndexedCollection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,94 @@
+//$Id: IndexedCollection.java 5797 2005-02-20 08:37:56Z oneovthafew $
+package org.hibernate.mapping;
+
+import java.util.Iterator;
+
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+
+/**
+ * Indexed collections include Lists, Maps, arrays and
+ * primitive arrays.
+ * @author Gavin King
+ */
+public abstract class IndexedCollection extends Collection {
+
+	public static final String DEFAULT_INDEX_COLUMN_NAME = "idx";
+
+	private Value index;
+	private String indexNodeName;
+
+	public IndexedCollection(PersistentClass owner) {
+		super(owner);
+	}
+
+	public Value getIndex() {
+		return index;
+	}
+	public void setIndex(Value index) {
+		this.index = index;
+	}
+	public final boolean isIndexed() {
+		return true;
+	}
+
+	void createPrimaryKey() {
+		if ( !isOneToMany() ) {
+			PrimaryKey pk = new PrimaryKey();
+			pk.addColumns( getKey().getColumnIterator() );
+			
+			// index should be last column listed
+			boolean isFormula = false;
+			Iterator iter = getIndex().getColumnIterator();
+			while ( iter.hasNext() ) {
+				if ( ( (Selectable) iter.next() ).isFormula() ) isFormula=true;
+			}
+			if (isFormula) {
+				//if it is a formula index, use the element columns in the PK
+				pk.addColumns( getElement().getColumnIterator() );
+			}
+			else {
+				pk.addColumns( getIndex().getColumnIterator() ); 
+			}
+			getCollectionTable().setPrimaryKey(pk);
+		}
+		else {
+			// don't create a unique key, 'cos some
+			// databases don't like a UK on nullable
+			// columns
+			/*ArrayList list = new ArrayList();
+			list.addAll( getKey().getConstraintColumns() );
+			list.addAll( getIndex().getConstraintColumns() );
+			getCollectionTable().createUniqueKey(list);*/
+		}
+	}
+
+	public void validate(Mapping mapping) throws MappingException {
+		super.validate(mapping);
+		if ( !getIndex().isValid(mapping) ) {
+			throw new MappingException(
+				"collection index mapping has wrong number of columns: " +
+				getRole() +
+				" type: " +
+				getIndex().getType().getName()
+			);
+		}
+		if ( indexNodeName!=null && !indexNodeName.startsWith("@") ) {
+			throw new MappingException("index node must be an attribute: " + indexNodeName );
+		}
+	}
+	
+	public boolean isList() {
+		return false;
+	}
+
+	public String getIndexNodeName() {
+		return indexNodeName;
+	}
+
+	public void setIndexNodeName(String indexNodeName) {
+		this.indexNodeName = indexNodeName;
+	}
+	
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Join.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Join.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Join.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,176 @@
+//$Id: Join.java 10040 2006-06-22 19:51:43Z steve.ebersole at jboss.com $
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.hibernate.sql.Alias;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+
+/**
+ * @author Gavin King
+ */
+public class Join implements Serializable {
+
+	private static final Alias PK_ALIAS = new Alias(15, "PK");
+
+	private ArrayList properties = new ArrayList();
+	private Table table;
+	private KeyValue key;
+	private PersistentClass persistentClass;
+	private boolean sequentialSelect;
+	private boolean inverse;
+	private boolean optional;
+
+	// Custom SQL
+	private String customSQLInsert;
+	private boolean customInsertCallable;
+	private ExecuteUpdateResultCheckStyle insertCheckStyle;
+	private String customSQLUpdate;
+	private boolean customUpdateCallable;
+	private ExecuteUpdateResultCheckStyle updateCheckStyle;
+	private String customSQLDelete;
+	private boolean customDeleteCallable;
+	private ExecuteUpdateResultCheckStyle deleteCheckStyle;
+
+	public void addProperty(Property prop) {
+		properties.add(prop);
+		prop.setPersistentClass( getPersistentClass() );
+	}
+	public boolean containsProperty(Property prop) {
+		return properties.contains(prop);
+	}
+	public Iterator getPropertyIterator() {
+		return properties.iterator();
+	}
+
+	public Table getTable() {
+		return table;
+	}
+	public void setTable(Table table) {
+		this.table = table;
+	}
+
+	public KeyValue getKey() {
+		return key;
+	}
+	public void setKey(KeyValue key) {
+		this.key = key;
+	}
+
+	public PersistentClass getPersistentClass() {
+		return persistentClass;
+	}
+
+	public void setPersistentClass(PersistentClass persistentClass) {
+		this.persistentClass = persistentClass;
+	}
+
+	public void createForeignKey() {
+		getKey().createForeignKeyOfEntity( persistentClass.getEntityName() );
+	}
+
+	public void createPrimaryKey() {
+		//Primary key constraint
+		PrimaryKey pk = new PrimaryKey();
+		pk.setTable(table);
+		pk.setName( PK_ALIAS.toAliasString( table.getName() ) );
+		table.setPrimaryKey(pk);
+
+		pk.addColumns( getKey().getColumnIterator() );
+	}
+
+	public int getPropertySpan() {
+		return properties.size();
+	}
+
+	public void setCustomSQLInsert(String customSQLInsert, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+		this.customSQLInsert = customSQLInsert;
+		this.customInsertCallable = callable;
+		this.insertCheckStyle = checkStyle;
+	}
+
+	public String getCustomSQLInsert() {
+		return customSQLInsert;
+	}
+
+	public boolean isCustomInsertCallable() {
+		return customInsertCallable;
+	}
+
+	public ExecuteUpdateResultCheckStyle getCustomSQLInsertCheckStyle() {
+		return insertCheckStyle;
+	}
+
+	public void setCustomSQLUpdate(String customSQLUpdate, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+		this.customSQLUpdate = customSQLUpdate;
+		this.customUpdateCallable = callable;
+		this.updateCheckStyle = checkStyle;
+	}
+
+	public String getCustomSQLUpdate() {
+		return customSQLUpdate;
+	}
+
+	public boolean isCustomUpdateCallable() {
+		return customUpdateCallable;
+	}
+
+	public ExecuteUpdateResultCheckStyle getCustomSQLUpdateCheckStyle() {
+		return updateCheckStyle;
+	}
+
+	public void setCustomSQLDelete(String customSQLDelete, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+		this.customSQLDelete = customSQLDelete;
+		this.customDeleteCallable = callable;
+		this.deleteCheckStyle = checkStyle;
+	}
+
+	public String getCustomSQLDelete() {
+		return customSQLDelete;
+	}
+
+	public boolean isCustomDeleteCallable() {
+		return customDeleteCallable;
+	}
+
+	public ExecuteUpdateResultCheckStyle getCustomSQLDeleteCheckStyle() {
+		return deleteCheckStyle;
+	}
+
+	public boolean isSequentialSelect() {
+		return sequentialSelect;
+	}
+	public void setSequentialSelect(boolean deferred) {
+		this.sequentialSelect = deferred;
+	}
+
+	public boolean isInverse() {
+		return inverse;
+	}
+
+	public void setInverse(boolean leftJoin) {
+		this.inverse = leftJoin;
+	}
+
+	public String toString() {
+		return getClass().getName() + '(' + table.toString() + ')';
+	}
+
+	public boolean isLazy() {
+		Iterator iter = getPropertyIterator();
+		while ( iter.hasNext() ) {
+			Property prop = (Property) iter.next();
+			if ( !prop.isLazy() ) return false;
+		}
+		return true;
+	}
+
+	public boolean isOptional() {
+		return optional;
+	}
+	public void setOptional(boolean nullable) {
+		this.optional = nullable;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/JoinedSubclass.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/JoinedSubclass.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/JoinedSubclass.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,58 @@
+//$Id: JoinedSubclass.java 7586 2005-07-21 01:11:52Z oneovthafew $
+package org.hibernate.mapping;
+
+import java.util.Iterator;
+
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+
+/**
+ * A subclass in a table-per-subclass mapping
+ * @author Gavin King
+ */
+public class JoinedSubclass extends Subclass implements TableOwner {
+
+	private Table table;
+	private KeyValue key;
+
+	public JoinedSubclass(PersistentClass superclass) {
+		super(superclass);
+	}
+
+	public Table getTable() {
+		return table;
+	}
+
+	public void setTable(Table table) {
+		this.table=table;
+		getSuperclass().addSubclassTable(table);
+	}
+
+	public KeyValue getKey() {
+		return key;
+	}
+
+	public void setKey(KeyValue key) {
+		this.key = key;
+	}
+
+	public void validate(Mapping mapping) throws MappingException {
+		super.validate(mapping);
+		if ( key!=null && !key.isValid(mapping) ) {
+			throw new MappingException(
+					"subclass key mapping has wrong number of columns: " +
+					getEntityName() +
+					" type: " +
+					key.getType().getName()
+				);
+		}
+	}
+
+	public Iterator getReferenceablePropertyIterator() {
+		return getPropertyIterator();
+	}
+	
+	public Object accept(PersistentClassVisitor mv) {
+		return mv.accept(this);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/KeyValue.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/KeyValue.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/KeyValue.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+//$Id: KeyValue.java 6514 2005-04-26 06:37:54Z oneovthafew $
+package org.hibernate.mapping;
+
+import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.id.IdentifierGenerator;
+
+/**
+ * Represents an identifying key of a table: the value for primary key
+ * of an entity, or a foreign key of a collection or join table or
+ * joined subclass table.
+ * @author Gavin King
+ */
+public interface KeyValue extends Value {
+	
+	public void createForeignKeyOfEntity(String entityName);
+	
+	public boolean isCascadeDeleteEnabled();
+	
+	public boolean isIdentityColumn(Dialect dialect);
+	
+	public String getNullValue();
+	
+	public boolean isUpdateable();
+
+	public IdentifierGenerator createIdentifierGenerator(
+			Dialect dialect, 
+			String defaultCatalog, 
+			String defaultSchema, 
+			RootClass rootClass) throws MappingException;
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/KeyValue.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/List.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/List.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/List.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+//$Id: List.java 5793 2005-02-20 03:34:50Z oneovthafew $
+package org.hibernate.mapping;
+
+import org.hibernate.MappingException;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * A list mapping has a primary key consisting of
+ * the key columns + index column.
+ * @author Gavin King
+ */
+public class List extends IndexedCollection {
+	
+	private int baseIndex;
+
+	public boolean isList() {
+		return true;
+	}
+
+	public List(PersistentClass owner) {
+		super(owner);
+	}
+
+	public CollectionType getDefaultCollectionType() throws MappingException {
+		return TypeFactory.list( getRole(), getReferencedPropertyName(), isEmbedded() );
+	}
+	
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}
+
+	public int getBaseIndex() {
+		return baseIndex;
+	}
+	
+	public void setBaseIndex(int baseIndex) {
+		this.baseIndex = baseIndex;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ManyToOne.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ManyToOne.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ManyToOne.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,91 @@
+//$Id: ManyToOne.java 7586 2005-07-21 01:11:52Z oneovthafew $
+package org.hibernate.mapping;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.MappingException;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * A many-to-one association mapping
+ * @author Gavin King
+ */
+public class ManyToOne extends ToOne {
+	
+	private boolean ignoreNotFound;
+	
+	public ManyToOne(Table table) {
+		super(table);
+	}
+
+	public Type getType() throws MappingException {
+		return TypeFactory.manyToOne( 
+				getReferencedEntityName(), 
+				getReferencedPropertyName(),
+				isLazy(),
+				isUnwrapProxy(),
+				isEmbedded(),
+				isIgnoreNotFound()
+			);
+	}
+
+	public void createForeignKey() throws MappingException {
+		// the case of a foreign key to something other than the pk is handled in createPropertyRefConstraints
+		if (referencedPropertyName==null && !hasFormula() ) {
+			createForeignKeyOfEntity( ( (EntityType) getType() ).getAssociatedEntityName() );
+		} 
+	}
+
+	public void createPropertyRefConstraints(Map persistentClasses) {
+		if (referencedPropertyName!=null) {
+			PersistentClass pc = (PersistentClass) persistentClasses.get(getReferencedEntityName() );
+			
+			Property property = pc.getReferencedProperty( getReferencedPropertyName() );
+			
+			if (property==null) {
+				throw new MappingException(
+						"Could not find property " + 
+						getReferencedPropertyName() + 
+						" on " + 
+						getReferencedEntityName() 
+					);
+			} 
+			else {
+				if ( !hasFormula() && !"none".equals( getForeignKeyName() ) ) {
+					java.util.List refColumns = new ArrayList();
+					Iterator iter = property.getColumnIterator();
+					while ( iter.hasNext() ) {
+						Column col = (Column) iter.next();
+						refColumns.add( col );							
+					}
+					
+					ForeignKey fk = getTable().createForeignKey( 
+							getForeignKeyName(), 
+							getConstraintColumns(), 
+							( (EntityType) getType() ).getAssociatedEntityName(), 
+							refColumns 
+						);
+					fk.setCascadeDeleteEnabled(isCascadeDeleteEnabled() );
+				}
+			}
+		}
+	}
+	
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}
+
+	public boolean isIgnoreNotFound() {
+		return ignoreNotFound;
+	}
+
+	public void setIgnoreNotFound(boolean ignoreNotFound) {
+		this.ignoreNotFound = ignoreNotFound;
+	}
+
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Map.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Map.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Map.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+//$Id: Map.java 7714 2005-08-01 16:29:33Z oneovthafew $
+package org.hibernate.mapping;
+
+import org.hibernate.MappingException;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * A map has a primary key consisting of
+ * the key columns + index columns.
+ */
+public class Map extends IndexedCollection {
+
+	public Map(PersistentClass owner) {
+		super(owner);
+	}
+	
+	public boolean isMap() {
+		return true;
+	}
+
+	public CollectionType getDefaultCollectionType() {
+		if ( isSorted() ) {
+			return TypeFactory.sortedMap( getRole(), getReferencedPropertyName(), isEmbedded(), getComparator() );
+		}
+		else if ( hasOrder() ) {
+			return TypeFactory.orderedMap( getRole(), getReferencedPropertyName(), isEmbedded() );
+		}
+		else {
+			return TypeFactory.map( getRole(), getReferencedPropertyName(), isEmbedded() );
+		}
+	}
+
+
+	public void createAllKeys() throws MappingException {
+		super.createAllKeys();
+		if ( !isInverse() ) getIndex().createForeignKey();
+	}
+
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/MetaAttributable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/MetaAttributable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/MetaAttributable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+package org.hibernate.mapping;
+
+/**
+ * Common interface for things that can handle meta attributes.
+ * 
+ * @since 3.0.1
+ */
+public interface MetaAttributable {
+
+	public java.util.Map getMetaAttributes();
+
+	public void setMetaAttributes(java.util.Map metas);
+		
+	public MetaAttribute getMetaAttribute(String name);
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/MetaAttribute.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/MetaAttribute.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/MetaAttribute.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+//$Id: MetaAttribute.java 10659 2006-10-30 16:19:10Z max.andersen at jboss.com $
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * A meta attribute is a named value or values.
+ * @author Gavin King
+ */
+public class MetaAttribute implements Serializable {
+	private String name;
+	private java.util.List values = new ArrayList();
+
+	public MetaAttribute(String name) {
+		this.name = name;
+	}
+	
+	public String getName() {
+		return name;
+	}	
+
+	public java.util.List getValues() {
+		return Collections.unmodifiableList(values);
+	}
+
+	public void addValue(String value) {
+		values.add(value);
+	}
+
+	public String getValue() {
+		if ( values.size()!=1 ) {
+			throw new IllegalStateException("no unique value");
+		}
+		return (String) values.get(0);
+	}
+
+	public boolean isMultiValued() {
+		return values.size()>1;
+	}
+
+	public String toString() {
+		return "[" + name + "=" + values + "]";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/OneToMany.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/OneToMany.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/OneToMany.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,145 @@
+//$Id: OneToMany.java 7246 2005-06-20 20:32:36Z oneovthafew $
+package org.hibernate.mapping;
+
+import java.util.Iterator;
+
+import org.hibernate.FetchMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * A mapping for a one-to-many association
+ * @author Gavin King
+ */
+public class OneToMany implements Value {
+
+	private String referencedEntityName;
+	private Table referencingTable;
+	private PersistentClass associatedClass;
+	private boolean embedded;
+	private boolean ignoreNotFound;
+
+	private EntityType getEntityType() {
+		return TypeFactory.manyToOne(
+				getReferencedEntityName(), 
+				null, 
+				false,
+				false,
+				isEmbedded(),
+				isIgnoreNotFound()
+			);
+	}
+
+	public OneToMany(PersistentClass owner) throws MappingException {
+		this.referencingTable = (owner==null) ? null : owner.getTable();
+	}
+
+	public PersistentClass getAssociatedClass() {
+		return associatedClass;
+	}
+
+    /**
+     * Associated entity on the many side
+     */
+	public void setAssociatedClass(PersistentClass associatedClass) {
+		this.associatedClass = associatedClass;
+	}
+
+	public void createForeignKey() {
+		// no foreign key element of for a one-to-many
+	}
+
+	public Iterator getColumnIterator() {
+		return associatedClass.getKey().getColumnIterator();
+	}
+
+	public int getColumnSpan() {
+		return associatedClass.getKey().getColumnSpan();
+	}
+
+	public FetchMode getFetchMode() {
+		return FetchMode.JOIN;
+	}
+
+    /** 
+     * Table of the owner entity (the "one" side)
+     */
+	public Table getTable() {
+		return referencingTable;
+	}
+
+	public Type getType() {
+		return getEntityType();
+	}
+
+	public boolean isNullable() {
+		return false;
+	}
+
+	public boolean isSimpleValue() {
+		return false;
+	}
+
+	public boolean isAlternateUniqueKey() {
+		return false;
+	}
+
+	public boolean hasFormula() {
+		return false;
+	}
+	
+	public boolean isValid(Mapping mapping) throws MappingException {
+		if (referencedEntityName==null) {
+			throw new MappingException("one to many association must specify the referenced entity");
+		}
+		return true;
+	}
+
+    public String getReferencedEntityName() {
+		return referencedEntityName;
+	}
+
+    /** 
+     * Associated entity on the "many" side
+     */    
+	public void setReferencedEntityName(String referencedEntityName) {
+		this.referencedEntityName = referencedEntityName==null ? null : referencedEntityName.intern();
+	}
+
+	public void setTypeUsingReflection(String className, String propertyName) {}
+	
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}
+	
+	
+	public boolean[] getColumnInsertability() {
+		//TODO: we could just return all false...
+		throw new UnsupportedOperationException();
+	}
+	
+	public boolean[] getColumnUpdateability() {
+		//TODO: we could just return all false...
+		throw new UnsupportedOperationException();
+	}
+	
+	public boolean isEmbedded() {
+		return embedded;
+	}
+	
+	public void setEmbedded(boolean embedded) {
+		this.embedded = embedded;
+	}
+
+	public boolean isIgnoreNotFound() {
+		return ignoreNotFound;
+	}
+
+	public void setIgnoreNotFound(boolean ignoreNotFound) {
+		this.ignoreNotFound = ignoreNotFound;
+	}
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/OneToOne.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/OneToOne.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/OneToOne.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,143 @@
+//$Id: OneToOne.java 7246 2005-06-20 20:32:36Z oneovthafew $
+package org.hibernate.mapping;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.hibernate.MappingException;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.ForeignKeyDirection;
+import org.hibernate.type.SpecialOneToOneType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * A one-to-one association mapping
+ * @author Gavin King
+ */
+public class OneToOne extends ToOne {
+
+	private boolean constrained;
+	private ForeignKeyDirection foreignKeyType;
+	private KeyValue identifier;
+	private String propertyName;
+	private String entityName;
+
+	public OneToOne(Table table, PersistentClass owner) throws MappingException {
+		super(table);
+		this.identifier = owner.getKey();
+		this.entityName = owner.getEntityName();
+	}
+
+	public String getPropertyName() {
+		return propertyName;
+	}
+
+	public void setPropertyName(String propertyName) {
+		this.propertyName = propertyName==null ? null : propertyName.intern();
+	}
+	
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public void setEntityName(String propertyName) {
+		this.entityName = entityName==null ? null : entityName.intern();
+	}
+	
+	public Type getType() throws MappingException {
+		if ( getColumnIterator().hasNext() ) {
+			return new SpecialOneToOneType(
+					getReferencedEntityName(), 
+					foreignKeyType, 
+					referencedPropertyName,
+					isLazy(),
+					isUnwrapProxy(),
+					entityName,
+					propertyName
+				);
+		}
+		else {
+			return TypeFactory.oneToOne( 
+					getReferencedEntityName(), 
+					foreignKeyType, 
+					referencedPropertyName,
+					isLazy(),
+					isUnwrapProxy(),
+					isEmbedded(),
+					entityName,
+					propertyName
+				);
+		}
+	}
+
+	public void createForeignKey() throws MappingException {
+		if ( constrained && referencedPropertyName==null) {
+			//TODO: handle the case of a foreign key to something other than the pk
+			createForeignKeyOfEntity( ( (EntityType) getType() ).getAssociatedEntityName() );
+		}
+	}
+
+	public java.util.List getConstraintColumns() {
+		ArrayList list = new ArrayList();
+		Iterator iter = identifier.getColumnIterator();
+		while ( iter.hasNext() ) list.add( iter.next() );
+		return list;
+	}
+	/**
+	 * Returns the constrained.
+	 * @return boolean
+	 */
+	public boolean isConstrained() {
+		return constrained;
+	}
+
+	/**
+	 * Returns the foreignKeyType.
+	 * @return AssociationType.ForeignKeyType
+	 */
+	public ForeignKeyDirection getForeignKeyType() {
+		return foreignKeyType;
+	}
+
+	/**
+	 * Returns the identifier.
+	 * @return Value
+	 */
+	public KeyValue getIdentifier() {
+		return identifier;
+	}
+
+	/**
+	 * Sets the constrained.
+	 * @param constrained The constrained to set
+	 */
+	public void setConstrained(boolean constrained) {
+		this.constrained = constrained;
+	}
+
+	/**
+	 * Sets the foreignKeyType.
+	 * @param foreignKeyType The foreignKeyType to set
+	 */
+	public void setForeignKeyType(ForeignKeyDirection foreignKeyType) {
+		this.foreignKeyType = foreignKeyType;
+	}
+
+	/**
+	 * Sets the identifier.
+	 * @param identifier The identifier to set
+	 */
+	public void setIdentifier(KeyValue identifier) {
+		this.identifier = identifier;
+	}
+
+	public boolean isNullable() {
+		return !constrained;
+	}
+
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PersistentClass.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PersistentClass.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PersistentClass.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,791 @@
+//$Id: PersistentClass.java 10927 2006-12-05 18:48:50Z steve.ebersole at jboss.com $
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+import java.util.*;
+import java.util.Set;
+
+import org.hibernate.MappingException;
+import org.hibernate.EntityMode;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.sql.Alias;
+import org.hibernate.util.EmptyIterator;
+import org.hibernate.util.JoinedIterator;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.SingletonIterator;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Mapping for an entity.
+ *
+ * @author Gavin King
+ */
+public abstract class PersistentClass implements Serializable, Filterable, MetaAttributable {
+
+	private static final Alias PK_ALIAS = new Alias(15, "PK");
+
+	public static final String NULL_DISCRIMINATOR_MAPPING = "null";
+	public static final String NOT_NULL_DISCRIMINATOR_MAPPING = "not null";
+
+	private String entityName;
+
+	private String className;
+	private String proxyInterfaceName;
+	
+	private String nodeName;
+
+	private String discriminatorValue;
+	private boolean lazy;
+	private ArrayList properties = new ArrayList();
+	private final ArrayList subclasses = new ArrayList();
+	private final ArrayList subclassProperties = new ArrayList();
+	private final ArrayList subclassTables = new ArrayList();
+	private boolean dynamicInsert;
+	private boolean dynamicUpdate;
+	private int batchSize=-1;
+	private boolean selectBeforeUpdate;
+	private java.util.Map metaAttributes;
+	private ArrayList joins = new ArrayList();
+	private final ArrayList subclassJoins = new ArrayList();
+	private final java.util.Map filters = new HashMap();
+	protected final java.util.Set synchronizedTables = new HashSet();
+	private String loaderName;
+	private Boolean isAbstract;
+	private boolean hasSubselectLoadableCollections;
+	private Component identifierMapper;
+
+	// Custom SQL
+	private String customSQLInsert;
+	private boolean customInsertCallable;
+	private ExecuteUpdateResultCheckStyle insertCheckStyle;
+	private String customSQLUpdate;
+	private boolean customUpdateCallable;
+	private ExecuteUpdateResultCheckStyle updateCheckStyle;
+	private String customSQLDelete;
+	private boolean customDeleteCallable;
+	private ExecuteUpdateResultCheckStyle deleteCheckStyle;
+
+	private String temporaryIdTableName;
+	private String temporaryIdTableDDL;
+
+	private java.util.Map tuplizerImpls;
+
+	protected int optimisticLockMode;
+
+	public String getClassName() {
+		return className;
+	}
+
+	public void setClassName(String className) {
+		this.className = className==null ? null : className.intern();
+	}
+
+	public String getProxyInterfaceName() {
+		return proxyInterfaceName;
+	}
+
+	public void setProxyInterfaceName(String proxyInterfaceName) {
+		this.proxyInterfaceName = proxyInterfaceName;
+	}
+
+	public Class getMappedClass() throws MappingException {
+		if (className==null) return null;
+		try {
+			return ReflectHelper.classForName(className);
+		}
+		catch (ClassNotFoundException cnfe) {
+			throw new MappingException("entity class not found: " + className, cnfe);
+		}
+	}
+
+	public Class getProxyInterface() {
+		if (proxyInterfaceName==null) return null;
+		try {
+			return ReflectHelper.classForName(proxyInterfaceName);
+		}
+		catch (ClassNotFoundException cnfe) {
+			throw new MappingException("proxy class not found: " + proxyInterfaceName, cnfe);
+		}
+	}
+	public boolean useDynamicInsert() {
+		return dynamicInsert;
+	}
+
+	abstract int nextSubclassId();
+	public abstract int getSubclassId();
+	
+	public boolean useDynamicUpdate() {
+		return dynamicUpdate;
+	}
+
+	public void setDynamicInsert(boolean dynamicInsert) {
+		this.dynamicInsert = dynamicInsert;
+	}
+
+	public void setDynamicUpdate(boolean dynamicUpdate) {
+		this.dynamicUpdate = dynamicUpdate;
+	}
+
+
+	public String getDiscriminatorValue() {
+		return discriminatorValue;
+	}
+
+	public void addSubclass(Subclass subclass) throws MappingException {
+		// inheritance cycle detection (paranoid check)
+		PersistentClass superclass = getSuperclass();
+		while (superclass!=null) {
+			if( subclass.getEntityName().equals( superclass.getEntityName() ) ) {
+				throw new MappingException(
+					"Circular inheritance mapping detected: " +
+					subclass.getEntityName() +
+					" will have it self as superclass when extending " +
+					getEntityName()
+				);
+			}
+			superclass = superclass.getSuperclass();
+		}
+		subclasses.add(subclass);
+	}
+
+	public boolean hasSubclasses() {
+		return subclasses.size() > 0;
+	}
+
+	public int getSubclassSpan() {
+		int n = subclasses.size();
+		Iterator iter = subclasses.iterator();
+		while ( iter.hasNext() ) {
+			n += ( (Subclass) iter.next() ).getSubclassSpan();
+		}
+		return n;
+	}
+	/**
+	 * Iterate over subclasses in a special 'order', most derived subclasses
+	 * first.
+	 */
+	public Iterator getSubclassIterator() {
+		Iterator[] iters = new Iterator[ subclasses.size() + 1 ];
+		Iterator iter = subclasses.iterator();
+		int i=0;
+		while ( iter.hasNext() ) {
+			iters[i++] = ( (Subclass) iter.next() ).getSubclassIterator();
+		}
+		iters[i] = subclasses.iterator();
+		return new JoinedIterator(iters);
+	}
+
+	public Iterator getSubclassClosureIterator() {
+		ArrayList iters = new ArrayList();
+		iters.add( new SingletonIterator(this) );
+		Iterator iter = getSubclassIterator();
+		while ( iter.hasNext() ) {
+			PersistentClass clazz = (PersistentClass)  iter.next();
+			iters.add( clazz.getSubclassClosureIterator() );
+		}
+		return new JoinedIterator(iters);
+	}
+	
+	public Table getIdentityTable() {
+		return getRootTable();
+	}
+	
+	public Iterator getDirectSubclasses() {
+		return subclasses.iterator();
+	}
+
+	public void addProperty(Property p) {
+		properties.add(p);
+		p.setPersistentClass(this);
+	}
+
+	public abstract Table getTable();
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public abstract boolean isMutable();
+	public abstract boolean hasIdentifierProperty();
+	public abstract Property getIdentifierProperty();
+	public abstract KeyValue getIdentifier();
+	public abstract Property getVersion();
+	public abstract Value getDiscriminator();
+	public abstract boolean isInherited();
+	public abstract boolean isPolymorphic();
+	public abstract boolean isVersioned();
+	public abstract String getCacheConcurrencyStrategy();
+	public abstract PersistentClass getSuperclass();
+	public abstract boolean isExplicitPolymorphism();
+	public abstract boolean isDiscriminatorInsertable();
+
+	public abstract Iterator getPropertyClosureIterator();
+	public abstract Iterator getTableClosureIterator();
+	public abstract Iterator getKeyClosureIterator();
+
+	protected void addSubclassProperty(Property prop) {
+		subclassProperties.add(prop);
+	}
+	protected void addSubclassJoin(Join join) {
+		subclassJoins.add(join);
+	}
+	protected void addSubclassTable(Table subclassTable) {
+		subclassTables.add(subclassTable);
+	}
+	public Iterator getSubclassPropertyClosureIterator() {
+		ArrayList iters = new ArrayList();
+		iters.add( getPropertyClosureIterator() );
+		iters.add( subclassProperties.iterator() );
+		for ( int i=0; i<subclassJoins.size(); i++ ) {
+			Join join = (Join) subclassJoins.get(i);
+			iters.add( join.getPropertyIterator() );
+		}
+		return new JoinedIterator(iters);
+	}
+	public Iterator getSubclassJoinClosureIterator() {
+		return new JoinedIterator( getJoinClosureIterator(), subclassJoins.iterator() );
+	}
+	public Iterator getSubclassTableClosureIterator() {
+		return new JoinedIterator( getTableClosureIterator(), subclassTables.iterator() );
+	}
+
+	public boolean isClassOrSuperclassJoin(Join join) {
+		return joins.contains(join);
+	}
+
+	public boolean isClassOrSuperclassTable(Table closureTable) {
+		return getTable()==closureTable;
+	}
+
+	public boolean isLazy() {
+		return lazy;
+	}
+
+	public void setLazy(boolean lazy) {
+		this.lazy = lazy;
+	}
+
+	public abstract boolean hasEmbeddedIdentifier();
+	public abstract Class getEntityPersisterClass();
+	public abstract void setEntityPersisterClass(Class classPersisterClass);
+	public abstract Table getRootTable();
+	public abstract RootClass getRootClass();
+	public abstract KeyValue getKey();
+
+	public void setDiscriminatorValue(String discriminatorValue) {
+		this.discriminatorValue = discriminatorValue;
+	}
+
+	public void setEntityName(String entityName) {
+		this.entityName = entityName==null ? null : entityName.intern();
+	}
+
+	public void createPrimaryKey() {
+		//Primary key constraint
+		PrimaryKey pk = new PrimaryKey();
+		Table table = getTable();
+		pk.setTable(table);
+		pk.setName( PK_ALIAS.toAliasString( table.getName() ) );
+		table.setPrimaryKey(pk);
+
+		pk.addColumns( getKey().getColumnIterator() );
+	}
+
+	public abstract String getWhere();
+
+	public int getBatchSize() {
+		return batchSize;
+	}
+
+	public void setBatchSize(int batchSize) {
+		this.batchSize = batchSize;
+	}
+
+	public boolean hasSelectBeforeUpdate() {
+		return selectBeforeUpdate;
+	}
+
+	public void setSelectBeforeUpdate(boolean selectBeforeUpdate) {
+		this.selectBeforeUpdate = selectBeforeUpdate;
+	}
+
+	/**
+	 * Build an iterator of properties which are "referenceable".
+	 *
+	 * @see #getReferencedProperty for a discussion of "referenceable"
+	 * @return The property iterator.
+	 */
+	public Iterator getReferenceablePropertyIterator() {
+		return getPropertyClosureIterator();
+	}
+
+	/**
+	 * Given a property path, locate the appropriate referenceable property reference.
+	 * <p/>
+	 * A referenceable property is a property  which can be a target of a foreign-key
+	 * mapping (an identifier or explcitly named in a property-ref).
+	 *
+	 * @param propertyPath The property path to resolve into a property reference.
+	 * @return The property reference (never null).
+	 * @throws MappingException If the property could not be found.
+	 */
+	public Property getReferencedProperty(String propertyPath) throws MappingException {
+		try {
+			return getRecursiveProperty( propertyPath, getReferenceablePropertyIterator() );
+		}
+		catch ( MappingException e ) {
+			throw new MappingException(
+					"property-ref [" + propertyPath + "] not found on entity [" + getEntityName() + "]", e
+			);
+		}
+	}
+
+	public Property getRecursiveProperty(String propertyPath) throws MappingException {
+		try {
+			return getRecursiveProperty( propertyPath, getPropertyIterator() );
+		}
+		catch ( MappingException e ) {
+			throw new MappingException(
+					"property [" + propertyPath + "] not found on entity [" + getEntityName() + "]", e
+			);
+		}
+	}
+
+	private Property getRecursiveProperty(String propertyPath, Iterator iter) throws MappingException {
+		Property property = null;
+		StringTokenizer st = new StringTokenizer( propertyPath, ".", false );
+		try {
+			while ( st.hasMoreElements() ) {
+				final String element = ( String ) st.nextElement();
+				if ( property == null ) {
+					Property identifierProperty = getIdentifierProperty();
+					if ( identifierProperty != null && identifierProperty.getName().equals( element ) ) {
+						// we have a mapped identifier property and the root of
+						// the incoming property path matched that identifier
+						// property
+						property = identifierProperty;
+					}
+					else if ( identifierProperty == null && getIdentifierMapper() != null ) {
+						// we have an embedded composite identifier
+						try {
+							identifierProperty = getProperty( element, getIdentifierMapper().getPropertyIterator() );
+							if ( identifierProperty != null ) {
+								// the root of the incoming property path matched one
+								// of the embedded composite identifier properties
+								property = identifierProperty;
+							}
+						}
+						catch( MappingException ignore ) {
+							// ignore it...
+						}
+					}
+
+					if ( property == null ) {
+						property = getProperty( element, iter );
+					}
+				}
+				else {
+					//flat recursive algorithm
+					property = ( ( Component ) property.getValue() ).getProperty( element );
+				}
+			}
+		}
+		catch ( MappingException e ) {
+			throw new MappingException( "property [" + propertyPath + "] not found on entity [" + getEntityName() + "]" );
+		}
+
+		return property;
+	}
+
+	private Property getProperty(String propertyName, Iterator iterator) throws MappingException {
+		while ( iterator.hasNext() ) {
+			Property prop = (Property) iterator.next();
+			if ( prop.getName().equals( StringHelper.root(propertyName) ) ) {
+				return prop;
+			}
+		}
+		throw new MappingException( "property [" + propertyName + "] not found on entity [" + getEntityName() + "]" );
+	}
+
+	public Property getProperty(String propertyName) throws MappingException {
+		Iterator iter = getPropertyClosureIterator();
+		Property identifierProperty = getIdentifierProperty();
+		if ( identifierProperty != null
+				&& identifierProperty.getName().equals( StringHelper.root(propertyName) )
+				) {
+			return identifierProperty;
+		}
+		else {
+			return getProperty( propertyName, iter );
+		}
+	}
+
+	abstract public int getOptimisticLockMode();
+
+	public void setOptimisticLockMode(int optimisticLockMode) {
+		this.optimisticLockMode = optimisticLockMode;
+	}
+
+	public void validate(Mapping mapping) throws MappingException {
+		Iterator iter = getPropertyIterator();
+		while ( iter.hasNext() ) {
+			Property prop = (Property) iter.next();
+			if ( !prop.isValid(mapping) ) {
+				throw new MappingException(
+						"property mapping has wrong number of columns: " +
+						StringHelper.qualify( getEntityName(), prop.getName() ) +
+						" type: " +
+						prop.getType().getName()
+					);
+			}
+		}
+		checkPropertyDuplication();
+		checkColumnDuplication();
+	}
+	
+	private void checkPropertyDuplication() throws MappingException {
+		HashSet names = new HashSet();
+		Iterator iter = getPropertyIterator();
+		while ( iter.hasNext() ) {
+			Property prop = (Property) iter.next();
+			if ( !names.add( prop.getName() ) ) {
+				throw new MappingException( "Duplicate property mapping of " + prop.getName() + " found in " + getEntityName());
+			}
+		}
+	}
+
+	public boolean isDiscriminatorValueNotNull() {
+		return NOT_NULL_DISCRIMINATOR_MAPPING.equals( getDiscriminatorValue() );
+	}
+	public boolean isDiscriminatorValueNull() {
+		return NULL_DISCRIMINATOR_MAPPING.equals( getDiscriminatorValue() );
+	}
+
+	public java.util.Map getMetaAttributes() {
+		return metaAttributes;
+	}
+
+	public void setMetaAttributes(java.util.Map metas) {
+		this.metaAttributes = metas;
+	}
+
+	public MetaAttribute getMetaAttribute(String name) {
+		return metaAttributes==null?null:(MetaAttribute) metaAttributes.get(name);
+	}
+
+	public String toString() {
+		return getClass().getName() + '(' + getEntityName() + ')';
+	}
+	
+	public Iterator getJoinIterator() {
+		return joins.iterator();
+	}
+
+	public Iterator getJoinClosureIterator() {
+		return joins.iterator();
+	}
+
+	public void addJoin(Join join) {
+		joins.add(join);
+		join.setPersistentClass(this);
+	}
+
+	public int getJoinClosureSpan() {
+		return joins.size();
+	}
+
+	public int getPropertyClosureSpan() {
+		int span = properties.size();
+		for ( int i=0; i<joins.size(); i++ ) {
+			Join join = (Join) joins.get(i);
+			span += join.getPropertySpan();
+		}
+		return span;
+	}
+
+	public int getJoinNumber(Property prop) {
+		int result=1;
+		Iterator iter = getSubclassJoinClosureIterator();
+		while ( iter.hasNext() ) {
+			Join join = (Join) iter.next();
+			if ( join.containsProperty(prop) ) return result;
+			result++;
+		}
+		return 0;
+	}
+
+	/**
+	 * Build an iterator over the properties defined on this class.  The returned
+	 * iterator only accounts for "normal" properties (i.e. non-identifier
+	 * properties).
+	 * <p/>
+	 * Differs from {@link #getUnjoinedPropertyIterator} in that the iterator
+	 * we return here will include properties defined as part of a join.
+	 *
+	 * @return An iterator over the "normal" properties.
+	 */
+	public Iterator getPropertyIterator() {
+		ArrayList iterators = new ArrayList();
+		iterators.add( properties.iterator() );
+		for ( int i = 0; i < joins.size(); i++ ) {
+			Join join = ( Join ) joins.get( i );
+			iterators.add( join.getPropertyIterator() );
+		}
+		return new JoinedIterator( iterators );
+	}
+
+	/**
+	 * Build an iterator over the properties defined on this class <b>which
+	 * are not defined as part of a join</b>.  As with {@link #getPropertyIterator},
+	 * the returned iterator only accounts for non-identifier properties.
+	 *
+	 * @return An iterator over the non-joined "normal" properties.
+	 */
+	public Iterator getUnjoinedPropertyIterator() {
+		return properties.iterator();
+	}
+
+	public void setCustomSQLInsert(String customSQLInsert, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+		this.customSQLInsert = customSQLInsert;
+		this.customInsertCallable = callable;
+		this.insertCheckStyle = checkStyle;
+	}
+
+	public String getCustomSQLInsert() {
+		return customSQLInsert;
+	}
+
+	public boolean isCustomInsertCallable() {
+		return customInsertCallable;
+	}
+
+	public ExecuteUpdateResultCheckStyle getCustomSQLInsertCheckStyle() {
+		return insertCheckStyle;
+	}
+
+	public void setCustomSQLUpdate(String customSQLUpdate, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+		this.customSQLUpdate = customSQLUpdate;
+		this.customUpdateCallable = callable;
+		this.updateCheckStyle = checkStyle;
+	}
+
+	public String getCustomSQLUpdate() {
+		return customSQLUpdate;
+	}
+
+	public boolean isCustomUpdateCallable() {
+		return customUpdateCallable;
+	}
+
+	public ExecuteUpdateResultCheckStyle getCustomSQLUpdateCheckStyle() {
+		return updateCheckStyle;
+	}
+
+	public void setCustomSQLDelete(String customSQLDelete, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
+		this.customSQLDelete = customSQLDelete;
+		this.customDeleteCallable = callable;
+		this.deleteCheckStyle = checkStyle;
+	}
+
+	public String getCustomSQLDelete() {
+		return customSQLDelete;
+	}
+
+	public boolean isCustomDeleteCallable() {
+		return customDeleteCallable;
+	}
+
+	public ExecuteUpdateResultCheckStyle getCustomSQLDeleteCheckStyle() {
+		return deleteCheckStyle;
+	}
+
+	public void addFilter(String name, String condition) {
+		filters.put(name, condition);
+	}
+
+	public java.util.Map getFilterMap() {
+		return filters;
+	}
+
+	public boolean isForceDiscriminator() {
+		return false;
+	}
+
+	public abstract boolean isJoinedSubclass();
+
+	public String getLoaderName() {
+		return loaderName;
+	}
+
+	public void setLoaderName(String loaderName) {
+		this.loaderName = loaderName==null ? null : loaderName.intern();
+	}
+
+	public abstract java.util.Set getSynchronizedTables();
+	
+	public void addSynchronizedTable(String table) {
+		synchronizedTables.add(table);
+	}
+
+	public Boolean isAbstract() {
+		return isAbstract;
+	}
+
+	public void setAbstract(Boolean isAbstract) {
+		this.isAbstract = isAbstract;
+	}
+
+	protected void checkColumnDuplication(Set distinctColumns, Iterator columns) 
+	throws MappingException {
+		while ( columns.hasNext() ) {
+			Selectable columnOrFormula = (Selectable) columns.next();
+			if ( !columnOrFormula.isFormula() ) {
+				Column col = (Column) columnOrFormula;
+				if ( !distinctColumns.add( col.getName() ) ) {
+					throw new MappingException( 
+							"Repeated column in mapping for entity: " +
+							getEntityName() +
+							" column: " +
+							col.getName() + 
+							" (should be mapped with insert=\"false\" update=\"false\")"
+						);
+				}
+			}
+		}
+	}
+	
+	protected void checkPropertyColumnDuplication(Set distinctColumns, Iterator properties) 
+	throws MappingException {
+		while ( properties.hasNext() ) {
+			Property prop = (Property) properties.next();
+			if ( prop.getValue() instanceof Component ) { //TODO: remove use of instanceof!
+				Component component = (Component) prop.getValue();
+				checkPropertyColumnDuplication( distinctColumns, component.getPropertyIterator() );
+			}
+			else {
+				if ( prop.isUpdateable() || prop.isInsertable() ) {
+					checkColumnDuplication( distinctColumns, prop.getColumnIterator() );
+				}
+			}
+		}
+	}
+	
+	protected Iterator getNonDuplicatedPropertyIterator() {
+		return getUnjoinedPropertyIterator();
+	}
+	
+	protected Iterator getDiscriminatorColumnIterator() {
+		return EmptyIterator.INSTANCE;
+	}
+	
+	protected void checkColumnDuplication() {
+		HashSet cols = new HashSet();
+		if (getIdentifierMapper() == null ) {
+			//an identifier mapper => getKey will be included in the getNonDuplicatedPropertyIterator()
+			//and checked later, so it needs to be excluded
+			checkColumnDuplication( cols, getKey().getColumnIterator() );
+		}
+		checkColumnDuplication( cols, getDiscriminatorColumnIterator() );
+		checkPropertyColumnDuplication( cols, getNonDuplicatedPropertyIterator() );
+		Iterator iter = getJoinIterator();
+		while ( iter.hasNext() ) {
+			cols.clear();
+			Join join = (Join) iter.next();
+			checkColumnDuplication( cols, join.getKey().getColumnIterator() );
+			checkPropertyColumnDuplication( cols, join.getPropertyIterator() );
+		}
+	}
+	
+	public abstract Object accept(PersistentClassVisitor mv);
+	
+	public String getNodeName() {
+		return nodeName;
+	}
+	
+	public void setNodeName(String nodeName) {
+		this.nodeName = nodeName;
+	}
+	
+	public boolean hasPojoRepresentation() {
+		return getClassName()!=null;
+	}
+
+	public boolean hasDom4jRepresentation() {
+		return getNodeName()!=null;
+	}
+
+	public boolean hasSubselectLoadableCollections() {
+		return hasSubselectLoadableCollections;
+	}
+	
+	public void setSubselectLoadableCollections(boolean hasSubselectCollections) {
+		this.hasSubselectLoadableCollections = hasSubselectCollections;
+	}
+
+	public void prepareTemporaryTables(Mapping mapping, Dialect dialect) {
+		if ( dialect.supportsTemporaryTables() ) {
+			temporaryIdTableName = dialect.generateTemporaryTableName( getTable().getName() );
+			Table table = new Table();
+			table.setName( temporaryIdTableName );
+			Iterator itr = getTable().getPrimaryKey().getColumnIterator();
+			while( itr.hasNext() ) {
+				Column column = (Column) itr.next();
+				table.addColumn( (Column) column.clone()  );
+			}
+			temporaryIdTableDDL = table.sqlTemporaryTableCreateString( dialect, mapping );
+		}
+	}
+
+	public String getTemporaryIdTableName() {
+		return temporaryIdTableName;
+	}
+
+	public String getTemporaryIdTableDDL() {
+		return temporaryIdTableDDL;
+	}
+
+	public Component getIdentifierMapper() {
+		return identifierMapper;
+	}
+
+	public boolean hasIdentifierMapper() {
+		return identifierMapper != null;
+	}
+
+	public void setIdentifierMapper(Component handle) {
+		this.identifierMapper = handle;
+	}
+
+	public void addTuplizer(EntityMode entityMode, String implClassName) {
+		if ( tuplizerImpls == null ) {
+			tuplizerImpls = new HashMap();
+		}
+		tuplizerImpls.put( entityMode, implClassName );
+	}
+
+	public String getTuplizerImplClassName(EntityMode mode) {
+		if ( tuplizerImpls == null ) return null;
+		return ( String ) tuplizerImpls.get( mode );
+	}
+
+	public java.util.Map getTuplizerMap() {
+		if ( tuplizerImpls == null ) {
+			return null;
+		}
+		return java.util.Collections.unmodifiableMap( tuplizerImpls );
+	}
+
+	public boolean hasNaturalId() {
+		Iterator props = getRootClass().getPropertyIterator();
+		while ( props.hasNext() ) {
+			if ( ( (Property) props.next() ).isNaturalIdentifier() ) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public abstract boolean isLazyPropertiesCacheable();
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PersistentClassVisitor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PersistentClassVisitor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PersistentClassVisitor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+/*
+ * Created on 07-Dec-2004
+ *
+ */
+package org.hibernate.mapping;
+
+/**
+ * @author max
+ *
+ */
+public interface PersistentClassVisitor {
+
+	/**
+	 * @param class1
+	 * @return
+	 */
+	Object accept(RootClass class1);
+
+	/**
+	 * @param subclass
+	 * @return
+	 */
+	Object accept(UnionSubclass subclass);
+
+	/**
+	 * @param subclass
+	 * @return
+	 */
+	Object accept(SingleTableSubclass subclass);
+
+	/**
+	 * @param subclass
+	 * @return
+	 */
+	Object accept(JoinedSubclass subclass);
+
+	/**
+	 * @param subclass
+	 * @return
+	 */
+	Object accept(Subclass subclass);
+
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PrimaryKey.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PrimaryKey.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PrimaryKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: PrimaryKey.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.mapping;
+
+import java.util.Iterator;
+
+import org.hibernate.dialect.Dialect;
+
+/**
+ * A primary key constraint
+ * @author Gavin King
+ */
+public class PrimaryKey extends Constraint {
+
+	public String sqlConstraintString(Dialect dialect) {
+		StringBuffer buf = new StringBuffer("primary key (");
+		Iterator iter = getColumnIterator();
+		while ( iter.hasNext() ) {
+			buf.append( ( (Column) iter.next() ).getQuotedName(dialect) );
+			if ( iter.hasNext() ) buf.append(", ");
+		}
+		return buf.append(')').toString();
+	}
+
+	public String sqlConstraintString(Dialect dialect, String constraintName, String defaultCatalog, String defaultSchema) {
+		StringBuffer buf = new StringBuffer(
+			dialect.getAddPrimaryKeyConstraintString(constraintName)
+		).append('(');
+		Iterator iter = getColumnIterator();
+		while ( iter.hasNext() ) {
+			buf.append( ( (Column) iter.next() ).getQuotedName(dialect) );
+			if ( iter.hasNext() ) buf.append(", ");
+		}
+		return buf.append(')').toString();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PrimitiveArray.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PrimitiveArray.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PrimitiveArray.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+//$Id: PrimitiveArray.java 4905 2004-12-07 09:59:56Z maxcsaucdk $
+package org.hibernate.mapping;
+
+/**
+ * A primitive array has a primary key consisting
+ * of the key columns + index column.
+ */
+public class PrimitiveArray extends Array {
+
+	public PrimitiveArray(PersistentClass owner) {
+		super(owner);
+	}
+
+	public boolean isPrimitiveArray() {
+		return true;
+	}
+
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Property.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Property.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Property.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,292 @@
+//$Id: Property.java 10245 2006-08-11 18:38:39Z steve.ebersole at jboss.com $
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+
+import org.hibernate.MappingException;
+import org.hibernate.PropertyNotFoundException;
+import org.hibernate.EntityMode;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.Mapping;
+import org.hibernate.property.Getter;
+import org.hibernate.property.PropertyAccessor;
+import org.hibernate.property.PropertyAccessorFactory;
+import org.hibernate.property.Setter;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * Represents a property as part of an entity or a component.
+ *
+ * @author Gavin King
+ */
+public class Property implements Serializable, MetaAttributable {
+
+	private String name;
+	private Value value;
+	private String cascade;
+	private boolean updateable = true;
+	private boolean insertable = true;
+	private boolean selectable = true;
+	private boolean optimisticLocked = true;
+	private PropertyGeneration generation = PropertyGeneration.NEVER;
+	private String propertyAccessorName;
+	private boolean lazy;
+	private boolean optional;
+	private String nodeName;
+	private java.util.Map metaAttributes;
+	private PersistentClass persistentClass;
+	private boolean naturalIdentifier;
+	
+	public boolean isBackRef() {
+		return false;
+	}
+
+	public Type getType() throws MappingException {
+		return value.getType();
+	}
+	
+	public int getColumnSpan() {
+		return value.getColumnSpan();
+	}
+	
+	public Iterator getColumnIterator() {
+		return value.getColumnIterator();
+	}
+	
+	public String getName() {
+		return name;
+	}
+	
+	public boolean isComposite() {
+		return value instanceof Component;
+	}
+
+	public Value getValue() {
+		return value;
+	}
+	
+	public boolean isPrimitive(Class clazz) {
+		return getGetter(clazz).getReturnType().isPrimitive();
+	}
+
+	public CascadeStyle getCascadeStyle() throws MappingException {
+		Type type = value.getType();
+		if ( type.isComponentType() && !type.isAnyType() ) {
+			AbstractComponentType actype = (AbstractComponentType) type;
+			int length = actype.getSubtypes().length;
+			for ( int i=0; i<length; i++ ) {
+				if ( actype.getCascadeStyle(i)!=CascadeStyle.NONE ) return CascadeStyle.ALL;
+			}
+			return CascadeStyle.NONE;
+		}
+		else if ( cascade==null || cascade.equals("none") ) {
+			return CascadeStyle.NONE;
+		}
+		else {
+			StringTokenizer tokens = new StringTokenizer(cascade, ", ");
+			CascadeStyle[] styles = new CascadeStyle[ tokens.countTokens() ] ;
+			int i=0;
+			while ( tokens.hasMoreTokens() ) {
+				styles[i++] = CascadeStyle.getCascadeStyle( tokens.nextToken() );
+			}
+			return new CascadeStyle.MultipleCascadeStyle(styles);
+		}
+	}
+
+	public String getCascade() {
+		return cascade;
+	}
+
+	public void setCascade(String cascade) {
+		this.cascade = cascade;
+	}
+
+	public void setName(String name) {
+		this.name = name==null ? null : name.intern();
+	}
+
+	public void setValue(Value value) {
+		this.value = value;
+	}
+
+	public boolean isUpdateable() {
+		// if the property mapping consists of all formulas, 
+		// make it non-updateable
+		final boolean[] columnUpdateability = value.getColumnUpdateability();
+		return updateable && ( 
+				//columnUpdateability.length==0 ||
+				!ArrayHelper.isAllFalse(columnUpdateability)
+			);
+	}
+
+	public boolean isInsertable() {
+		// if the property mapping consists of all formulas, 
+		// make it insertable
+		final boolean[] columnInsertability = value.getColumnInsertability();
+		return insertable && (
+				columnInsertability.length==0 ||
+				!ArrayHelper.isAllFalse(columnInsertability)
+			);
+	}
+
+    public PropertyGeneration getGeneration() {
+        return generation;
+    }
+
+    public void setGeneration(PropertyGeneration generation) {
+        this.generation = generation;
+    }
+
+    public void setUpdateable(boolean mutable) {
+		this.updateable = mutable;
+	}
+
+	public void setInsertable(boolean insertable) {
+		this.insertable = insertable;
+	}
+
+	public String getPropertyAccessorName() {
+		return propertyAccessorName;
+	}
+
+	public void setPropertyAccessorName(String string) {
+		propertyAccessorName = string;
+	}
+
+	/**
+	 * Approximate!
+	 */
+	boolean isNullable() {
+		return value==null || value.isNullable();
+	}
+
+	public boolean isBasicPropertyAccessor() {
+		return propertyAccessorName==null || "property".equals(propertyAccessorName);
+	}
+
+	public java.util.Map getMetaAttributes() {
+		return metaAttributes;
+	}
+
+	public MetaAttribute getMetaAttribute(String attributeName) {
+		return metaAttributes==null?null:(MetaAttribute) metaAttributes.get(attributeName);
+	}
+
+	public void setMetaAttributes(java.util.Map metas) {
+		this.metaAttributes = metas;
+	}
+
+	public boolean isValid(Mapping mapping) throws MappingException {
+		return getValue().isValid(mapping);
+	}
+
+	public String toString() {
+		return getClass().getName() + '(' + name + ')';
+	}
+	
+	public void setLazy(boolean lazy) {
+		this.lazy=lazy;
+	}
+	
+	public boolean isLazy() {
+		if ( value instanceof ToOne ) {
+			// both many-to-one and one-to-one are represented as a
+			// Property.  EntityPersister is relying on this value to
+			// determine "lazy fetch groups" in terms of field-level
+			// interception.  So we need to make sure that we return
+			// true here for the case of many-to-one and one-to-one
+			// with lazy="no-proxy"
+			//
+			// * impl note - lazy="no-proxy" currently forces both
+			// lazy and unwrap to be set to true.  The other case we
+			// are extremely interested in here is that of lazy="proxy"
+			// where lazy is set to true, but unwrap is set to false.
+			// thus we use both here under the assumption that this
+			// return is really only ever used during persister
+			// construction to determine the lazy property/field fetch
+			// groupings.  If that assertion changes then this check
+			// needs to change as well.  Partially, this is an issue with
+			// the overloading of the term "lazy" here...
+			ToOne toOneValue = ( ToOne ) value;
+			return toOneValue.isLazy() && toOneValue.isUnwrapProxy();
+		}
+		return lazy;
+	}
+	
+	public boolean isOptimisticLocked() {
+		return optimisticLocked;
+	}
+
+	public void setOptimisticLocked(boolean optimisticLocked) {
+		this.optimisticLocked = optimisticLocked;
+	}
+	
+	public boolean isOptional() {
+		return optional || isNullable();
+	}
+	
+	public void setOptional(boolean optional) {
+		this.optional = optional;
+	}
+
+	public PersistentClass getPersistentClass() {
+		return persistentClass;
+	}
+
+	public void setPersistentClass(PersistentClass persistentClass) {
+		this.persistentClass = persistentClass;
+	}
+
+	public boolean isSelectable() {
+		return selectable;
+	}
+	
+	public void setSelectable(boolean selectable) {
+		this.selectable = selectable;
+	}
+
+	public String getNodeName() {
+		return nodeName;
+	}
+
+	public void setNodeName(String nodeName) {
+		this.nodeName = nodeName;
+	}
+
+	public String getAccessorPropertyName( EntityMode mode ) {
+		if ( mode == EntityMode.DOM4J ) {
+			return nodeName;
+		}
+		else {
+			return getName();
+		}
+	}
+
+	// todo : remove
+	public Getter getGetter(Class clazz) throws PropertyNotFoundException, MappingException {
+		return getPropertyAccessor(clazz).getGetter(clazz, name);
+	}
+
+	// todo : remove
+	public Setter getSetter(Class clazz) throws PropertyNotFoundException, MappingException {
+		return getPropertyAccessor(clazz).getSetter(clazz, name);
+	}
+
+	// todo : remove
+	public PropertyAccessor getPropertyAccessor(Class clazz) throws MappingException {
+		return PropertyAccessorFactory.getPropertyAccessor( clazz, getPropertyAccessorName() );
+	}
+
+	public boolean isNaturalIdentifier() {
+		return naturalIdentifier;
+	}
+
+	public void setNaturalIdentifier(boolean naturalIdentifier) {
+		this.naturalIdentifier = naturalIdentifier;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PropertyGeneration.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PropertyGeneration.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/PropertyGeneration.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+
+/**
+ * Indicates whether given properties are generated by the database and, if
+ * so, at what time(s) they are generated.
+ *
+ * @author Steve Ebersole
+ */
+public class PropertyGeneration implements Serializable {
+
+	/**
+	 * Values for this property are never generated by the database.
+	 */
+	public static final PropertyGeneration NEVER = new PropertyGeneration( "never" );
+	/**
+	 * Values for this property are generated by the database on insert.
+	 */
+	public static final PropertyGeneration INSERT = new PropertyGeneration( "insert" );
+	/**
+	 * Values for this property are generated by the database on both insert and update.
+	 */
+	public static final PropertyGeneration ALWAYS = new PropertyGeneration( "always" );
+
+	private final String name;
+
+	private PropertyGeneration(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public static PropertyGeneration parse(String name) {
+		if ( "insert".equalsIgnoreCase( name ) ) {
+			return INSERT;
+		}
+		else if ( "always".equalsIgnoreCase( name ) ) {
+			return ALWAYS;
+		}
+		else {
+			return NEVER;
+		}
+	}
+
+	private Object readResolve() {
+		return parse( name );
+	}
+	
+	public String toString() {
+		return getClass().getName() + "(" + getName() + ")";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/RelationalModel.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/RelationalModel.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/RelationalModel.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+//$Id: RelationalModel.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.mapping;
+
+import org.hibernate.engine.Mapping;
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * A relational object which may be created using DDL
+ * @author Gavin King
+ */
+public interface RelationalModel {
+	public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, String defaultSchema) throws HibernateException;
+	public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/RootClass.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/RootClass.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/RootClass.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,276 @@
+//$Id: RootClass.java 8698 2005-11-29 14:34:11Z steveebersole $
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.SingletonIterator;
+
+/**
+ * The root class of an inheritance hierarchy
+ * @author Gavin King
+ */
+public class RootClass extends PersistentClass implements TableOwner {
+
+	public static final String DEFAULT_IDENTIFIER_COLUMN_NAME = "id";
+	public static final String DEFAULT_DISCRIMINATOR_COLUMN_NAME = "class";
+
+	private Property identifierProperty; //may be final
+	private KeyValue identifier; //may be final
+	private Property version; //may be final
+	private boolean polymorphic;
+	private String cacheConcurrencyStrategy;
+	private String cacheRegionName;
+	private boolean lazyPropertiesCacheable = true;
+	private Value discriminator; //may be final
+	private boolean mutable = true;
+	private boolean embeddedIdentifier = false; // may be final
+	private boolean explicitPolymorphism;
+	private Class entityPersisterClass;
+	private boolean forceDiscriminator = false;
+	private String where;
+	private Table table;
+	private boolean discriminatorInsertable = true;
+	private int nextSubclassId = 0;
+		
+	int nextSubclassId() {
+		return ++nextSubclassId;
+	}
+
+	public int getSubclassId() {
+		return 0;
+	}
+	
+	public void setTable(Table table) {
+		this.table=table;
+	}
+	public Table getTable() {
+		return table;
+	}
+
+	public Property getIdentifierProperty() {
+		return identifierProperty;
+	}
+	public KeyValue getIdentifier() {
+		return identifier;
+	}
+	public boolean hasIdentifierProperty() {
+		return identifierProperty!=null;
+	}
+
+	public Value getDiscriminator() {
+		return discriminator;
+	}
+
+	public boolean isInherited() {
+		return false;
+	}
+	public boolean isPolymorphic() {
+		return polymorphic;
+	}
+
+	public void setPolymorphic(boolean polymorphic) {
+		this.polymorphic = polymorphic;
+	}
+
+	public RootClass getRootClass() {
+		return this;
+	}
+
+	public Iterator getPropertyClosureIterator() {
+		return getPropertyIterator();
+	}
+	public Iterator getTableClosureIterator() {
+		return new SingletonIterator( getTable() );
+	}
+	public Iterator getKeyClosureIterator() {
+		return new SingletonIterator( getKey() );
+	}
+
+	public void addSubclass(Subclass subclass) throws MappingException {
+		super.addSubclass(subclass);
+		setPolymorphic(true);
+	}
+
+	public boolean isExplicitPolymorphism() {
+		return explicitPolymorphism;
+	}
+
+	public Property getVersion() {
+		return version;
+	}
+	public void setVersion(Property version) {
+		this.version = version;
+	}
+	public boolean isVersioned() {
+		return version!=null;
+	}
+
+	public boolean isMutable() {
+		return mutable;
+	}
+	public boolean hasEmbeddedIdentifier() {
+		return embeddedIdentifier;
+	}
+
+	public Class getEntityPersisterClass() {
+		return entityPersisterClass;
+	}
+
+	public Table getRootTable() {
+		return getTable();
+	}
+
+	public void setEntityPersisterClass(Class persister) {
+		this.entityPersisterClass = persister;
+	}
+
+	public PersistentClass getSuperclass() {
+		return null;
+	}
+
+	public KeyValue getKey() {
+		return getIdentifier();
+	}
+
+	public void setDiscriminator(Value discriminator) {
+		this.discriminator = discriminator;
+	}
+
+	public void setEmbeddedIdentifier(boolean embeddedIdentifier) {
+		this.embeddedIdentifier = embeddedIdentifier;
+	}
+
+	public void setExplicitPolymorphism(boolean explicitPolymorphism) {
+		this.explicitPolymorphism = explicitPolymorphism;
+	}
+
+	public void setIdentifier(KeyValue identifier) {
+		this.identifier = identifier;
+	}
+
+	public void setIdentifierProperty(Property identifierProperty) {
+		this.identifierProperty = identifierProperty;
+		identifierProperty.setPersistentClass(this);
+	}
+
+	public void setMutable(boolean mutable) {
+		this.mutable = mutable;
+	}
+
+	public boolean isDiscriminatorInsertable() {
+		return discriminatorInsertable;
+	}
+	
+	public void setDiscriminatorInsertable(boolean insertable) {
+		this.discriminatorInsertable = insertable;
+	}
+
+	public boolean isForceDiscriminator() {
+		return forceDiscriminator;
+	}
+
+	public void setForceDiscriminator(boolean forceDiscriminator) {
+		this.forceDiscriminator = forceDiscriminator;
+	}
+
+	public String getWhere() {
+		return where;
+	}
+
+	public void setWhere(String string) {
+		where = string;
+	}
+
+	public void validate(Mapping mapping) throws MappingException {
+		super.validate(mapping);
+		if ( !getIdentifier().isValid(mapping) ) {
+			throw new MappingException(
+				"identifier mapping has wrong number of columns: " +
+				getEntityName() +
+				" type: " +
+				getIdentifier().getType().getName()
+			);
+		}
+		checkCompositeIdentifier();
+	}
+
+	private void checkCompositeIdentifier() {
+		if ( getIdentifier() instanceof Component ) {
+			Component id = (Component) getIdentifier();
+			if ( !id.isDynamic() ) {
+				Class idClass = id.getComponentClass();
+				if ( idClass != null && !ReflectHelper.overridesEquals( idClass ) ) {
+					LogFactory.getLog(RootClass.class)
+						.warn( "composite-id class does not override equals(): "
+							+ id.getComponentClass().getName() );
+				}
+				if ( !ReflectHelper.overridesHashCode( idClass ) ) {
+					LogFactory.getLog(RootClass.class)
+						.warn( "composite-id class does not override hashCode(): "
+							+ id.getComponentClass().getName() );
+				}
+				if ( !Serializable.class.isAssignableFrom( idClass ) ) {
+					throw new MappingException( "composite-id class must implement Serializable: "
+						+ id.getComponentClass().getName() );
+				}
+			}
+		}
+	}
+	
+	public String getCacheConcurrencyStrategy() {
+		return cacheConcurrencyStrategy;
+	}
+
+	public void setCacheConcurrencyStrategy(String cacheConcurrencyStrategy) {
+		this.cacheConcurrencyStrategy = cacheConcurrencyStrategy;
+	}
+
+	public String getCacheRegionName() {
+		return cacheRegionName==null ? getEntityName() : cacheRegionName;
+	}
+	public void setCacheRegionName(String cacheRegionName) {
+		this.cacheRegionName = cacheRegionName;
+	}
+
+	public boolean isLazyPropertiesCacheable() {
+		return lazyPropertiesCacheable;
+	}
+
+	public void setLazyPropertiesCacheable(boolean lazyPropertiesCacheable) {
+		this.lazyPropertiesCacheable = lazyPropertiesCacheable;
+	}
+	
+	public boolean isJoinedSubclass() {
+		return false;
+	}
+
+	public java.util.Set getSynchronizedTables() {
+		return synchronizedTables;
+	}
+	
+	public Set getIdentityTables() {
+		Set tables = new HashSet();
+		Iterator iter = getSubclassClosureIterator();
+		while ( iter.hasNext() ) {
+			PersistentClass clazz = (PersistentClass) iter.next();
+			if ( clazz.isAbstract() == null || !clazz.isAbstract().booleanValue() ) tables.add( clazz.getIdentityTable() );
+		}
+		return tables;
+	}
+	
+	public Object accept(PersistentClassVisitor mv) {
+		return mv.accept(this);
+	}
+	
+	public int getOptimisticLockMode() {
+		return optimisticLockMode;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Selectable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Selectable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Selectable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,14 @@
+//$Id: Selectable.java 9908 2006-05-08 20:59:20Z max.andersen at jboss.com $
+package org.hibernate.mapping;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.function.SQLFunctionRegistry;
+
+public interface Selectable {
+	public String getAlias(Dialect dialect);
+	public String getAlias(Dialect dialect, Table table);
+	public boolean isFormula();
+	public String getTemplate(Dialect dialect, SQLFunctionRegistry functionRegistry);
+	public String getText(Dialect dialect);
+	public String getText();
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Selectable.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Set.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Set.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Set.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,86 @@
+//$Id: Set.java 7714 2005-08-01 16:29:33Z oneovthafew $
+package org.hibernate.mapping;
+
+import java.util.Iterator;
+
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.TypeFactory;
+
+/**
+ * A set with no nullable element columns. It will have a primary key
+ * consisting of all table columns (ie. key columns + element columns).
+ * @author Gavin King
+ */
+public class Set extends Collection {
+
+	public void validate(Mapping mapping) throws MappingException {
+		super.validate( mapping );
+		//for backward compatibility, disable this:
+		/*Iterator iter = getElement().getColumnIterator();
+		while ( iter.hasNext() ) {
+			Column col = (Column) iter.next();
+			if ( !col.isNullable() ) {
+				return;
+			}
+		}
+		throw new MappingException("set element mappings must have at least one non-nullable column: " + getRole() );*/
+	}
+
+	/**
+	 * Constructor for Set.
+	 * @param owner
+	 */
+	public Set(PersistentClass owner) {
+		super(owner);
+	}
+
+	public boolean isSet() {
+		return true;
+	}
+
+	public CollectionType getDefaultCollectionType() {
+		if ( isSorted() ) {
+			return TypeFactory.sortedSet( getRole(), getReferencedPropertyName(), isEmbedded(), getComparator() );
+		}
+		else if ( hasOrder() ) {
+			return TypeFactory.orderedSet( getRole(), getReferencedPropertyName(), isEmbedded() );
+		}
+		else {
+			return TypeFactory.set( getRole(), getReferencedPropertyName(), isEmbedded() );
+		}
+	}
+
+	void createPrimaryKey() {
+		if ( !isOneToMany() ) {
+			PrimaryKey pk = new PrimaryKey();
+			pk.addColumns( getKey().getColumnIterator() );
+			Iterator iter = getElement().getColumnIterator();
+			while ( iter.hasNext() ) {
+				Object selectable = iter.next();
+				if ( selectable instanceof Column ) {
+					Column col = (Column) selectable;
+					if ( !col.isNullable() ) {
+						pk.addColumn(col);
+					}
+				}
+			}
+			if ( pk.getColumnSpan()==getKey().getColumnSpan() ) { 
+				//for backward compatibility, allow a set with no not-null 
+				//element columns, using all columns in the row locater SQL
+				//TODO: create an implicit not null constraint on all cols?
+			}
+			else {
+				getCollectionTable().setPrimaryKey(pk);
+			}
+		}
+		else {
+			//create an index on the key columns??
+		}
+	}
+
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/SimpleAuxiliaryDatabaseObject.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/SimpleAuxiliaryDatabaseObject.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/SimpleAuxiliaryDatabaseObject.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+// $Id: SimpleAuxiliaryDatabaseObject.java 7800 2005-08-10 12:13:00Z steveebersole $
+package org.hibernate.mapping;
+
+import java.util.HashSet;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.Mapping;
+import org.hibernate.HibernateException;
+import org.hibernate.util.StringHelper;
+
+/**
+ * A simple implementation of AbstractAuxiliaryDatabaseObject in which the CREATE and DROP strings are
+ * provided up front.  Contains simple facilities for templating the catalog and schema
+ * names into the provided strings.
+ * <p/>
+ * This is the form created when the mapping documents use &lt;create/&gt; and
+ * &lt;drop/&gt;.
+ *
+ * @author Steve Ebersole
+ */
+public class SimpleAuxiliaryDatabaseObject extends AbstractAuxiliaryDatabaseObject {
+
+	private final String sqlCreateString;
+	private final String sqlDropString;
+
+	public SimpleAuxiliaryDatabaseObject(String sqlCreateString, String sqlDropString) {
+		this.sqlCreateString = sqlCreateString;
+		this.sqlDropString = sqlDropString;
+	}
+
+	public SimpleAuxiliaryDatabaseObject(String sqlCreateString, String sqlDropString, HashSet dialectScopes) {
+		super( dialectScopes );
+		this.sqlCreateString = sqlCreateString;
+		this.sqlDropString = sqlDropString;
+	}
+
+	public String sqlCreateString(
+	        Dialect dialect,
+	        Mapping p,
+	        String defaultCatalog,
+	        String defaultSchema) throws HibernateException {
+		return injectCatalogAndSchema( sqlCreateString, defaultCatalog, defaultSchema );
+	}
+
+	public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
+		return injectCatalogAndSchema( sqlDropString, defaultCatalog, defaultSchema );
+	}
+
+	private String injectCatalogAndSchema(String ddlString, String defaultCatalog, String defaultSchema) {
+		String rtn = StringHelper.replace( ddlString, "${catalog}", defaultCatalog );
+		rtn = StringHelper.replace( rtn, "${schema}", defaultSchema );
+		return rtn;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/SimpleValue.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/SimpleValue.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/SimpleValue.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,314 @@
+//$Id: SimpleValue.java 8046 2005-08-30 20:11:43Z oneovthafew $
+package org.hibernate.mapping;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+import org.hibernate.FetchMode;
+import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.Mapping;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.id.IdentifierGeneratorFactory;
+import org.hibernate.id.IdentityGenerator;
+import org.hibernate.id.PersistentIdentifierGenerator;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * Any value that maps to columns.
+ * @author Gavin King
+ */
+public class SimpleValue implements KeyValue {
+
+	private final List columns = new ArrayList();
+	private String typeName;
+	private Properties identifierGeneratorProperties;
+	private String identifierGeneratorStrategy = "assigned";
+	private String nullValue;
+	private Table table;
+	private String foreignKeyName;
+	private boolean alternateUniqueKey;
+	private Properties typeParameters;
+	private boolean cascadeDeleteEnabled;
+
+	public boolean isCascadeDeleteEnabled() {
+		return cascadeDeleteEnabled;
+	}
+
+	public void setCascadeDeleteEnabled(boolean cascadeDeleteEnabled) {
+		this.cascadeDeleteEnabled = cascadeDeleteEnabled;
+	}
+	
+	public void addColumn(Column column) {
+		if ( !columns.contains(column) ) columns.add(column);
+		column.setValue(this);
+		column.setTypeIndex( columns.size()-1 );
+	}
+	
+	public void addFormula(Formula formula) {
+		columns.add(formula);
+	}
+	
+	public boolean hasFormula() {
+		Iterator iter = getColumnIterator();
+		while ( iter.hasNext() ) {
+			Object o = iter.next();
+			if (o instanceof Formula) return true;
+		}
+		return false;
+	}
+
+	public int getColumnSpan() {
+		return columns.size();
+	}
+	public Iterator getColumnIterator() {
+		return columns.iterator();
+	}
+	public List getConstraintColumns() {
+		return columns;
+	}
+	public String getTypeName() {
+		return typeName;
+	}
+	public void setTypeName(String type) {
+		this.typeName = type;
+	}
+	public void setTable(Table table) {
+		this.table = table;
+	}
+	
+	public SimpleValue(Table table) {
+		this.table = table;
+	}
+
+	public SimpleValue() {}
+
+	public void createForeignKey() throws MappingException {}
+
+	public void createForeignKeyOfEntity(String entityName) {
+		if ( !hasFormula() && !"none".equals(getForeignKeyName())) {
+			ForeignKey fk = table.createForeignKey( getForeignKeyName(), getConstraintColumns(), entityName );
+			fk.setCascadeDeleteEnabled(cascadeDeleteEnabled);
+		}
+	}
+
+	public IdentifierGenerator createIdentifierGenerator(
+			Dialect dialect, 
+			String defaultCatalog, 
+			String defaultSchema, 
+			RootClass rootClass) 
+	throws MappingException {
+		
+		Properties params = new Properties();
+		
+		//if the hibernate-mapping did not specify a schema/catalog, use the defaults
+		//specified by properties - but note that if the schema/catalog were specified
+		//in hibernate-mapping, or as params, they will already be initialized and
+		//will override the values set here (they are in identifierGeneratorProperties)
+		if ( defaultSchema!=null ) {
+			params.setProperty(PersistentIdentifierGenerator.SCHEMA, defaultSchema);
+		}
+		if ( defaultCatalog!=null ) {
+			params.setProperty(PersistentIdentifierGenerator.CATALOG, defaultCatalog);
+		}
+		
+		//pass the entity-name, if not a collection-id
+		if (rootClass!=null) {
+			params.setProperty( IdentifierGenerator.ENTITY_NAME, rootClass.getEntityName() );
+		}
+		
+		//init the table here instead of earlier, so that we can get a quoted table name
+		//TODO: would it be better to simply pass the qualified table name, instead of
+		//      splitting it up into schema/catalog/table names
+		String tableName = getTable().getQuotedName(dialect);
+		params.setProperty( PersistentIdentifierGenerator.TABLE, tableName );
+		
+		//pass the column name (a generated id almost always has a single column)
+		String columnName = ( (Column) getColumnIterator().next() ).getQuotedName(dialect);
+		params.setProperty( PersistentIdentifierGenerator.PK, columnName );
+		
+		if (rootClass!=null) {
+			StringBuffer tables = new StringBuffer();
+			Iterator iter = rootClass.getIdentityTables().iterator();
+			while ( iter.hasNext() ) {
+				Table table= (Table) iter.next();
+				tables.append( table.getQuotedName(dialect) );
+				if ( iter.hasNext() ) tables.append(", ");
+			}
+			params.setProperty( PersistentIdentifierGenerator.TABLES, tables.toString() );
+		}
+		else {
+			params.setProperty( PersistentIdentifierGenerator.TABLES, tableName );
+		}
+
+		if (identifierGeneratorProperties!=null) {
+			params.putAll(identifierGeneratorProperties);
+		}
+		
+		return IdentifierGeneratorFactory.create(
+				identifierGeneratorStrategy,
+				getType(),
+				params,
+				dialect
+			);
+		
+	}
+
+	public boolean isUpdateable() {
+		//needed to satisfy KeyValue
+		return true;
+	}
+	
+	public FetchMode getFetchMode() {
+		return FetchMode.SELECT;
+	}
+
+	public Properties getIdentifierGeneratorProperties() {
+		return identifierGeneratorProperties;
+	}
+
+	public String getNullValue() {
+		return nullValue;
+	}
+
+	public Table getTable() {
+		return table;
+	}
+
+	/**
+	 * Returns the identifierGeneratorStrategy.
+	 * @return String
+	 */
+	public String getIdentifierGeneratorStrategy() {
+		return identifierGeneratorStrategy;
+	}
+	
+	public boolean isIdentityColumn(Dialect dialect) {
+		return IdentifierGeneratorFactory.getIdentifierGeneratorClass(identifierGeneratorStrategy, dialect)
+				.equals(IdentityGenerator.class);
+	}
+
+	/**
+	 * Sets the identifierGeneratorProperties.
+	 * @param identifierGeneratorProperties The identifierGeneratorProperties to set
+	 */
+	public void setIdentifierGeneratorProperties(Properties identifierGeneratorProperties) {
+		this.identifierGeneratorProperties = identifierGeneratorProperties;
+	}
+
+	/**
+	 * Sets the identifierGeneratorStrategy.
+	 * @param identifierGeneratorStrategy The identifierGeneratorStrategy to set
+	 */
+	public void setIdentifierGeneratorStrategy(String identifierGeneratorStrategy) {
+		this.identifierGeneratorStrategy = identifierGeneratorStrategy;
+	}
+
+	/**
+	 * Sets the nullValue.
+	 * @param nullValue The nullValue to set
+	 */
+	public void setNullValue(String nullValue) {
+		this.nullValue = nullValue;
+	}
+
+	public String getForeignKeyName() {
+		return foreignKeyName;
+	}
+
+	public void setForeignKeyName(String foreignKeyName) {
+		this.foreignKeyName = foreignKeyName;
+	}
+
+	public boolean isAlternateUniqueKey() {
+		return alternateUniqueKey;
+	}
+
+	public void setAlternateUniqueKey(boolean unique) {
+		this.alternateUniqueKey = unique;
+	}
+
+	public boolean isNullable() {
+		if ( hasFormula() ) return true;
+		boolean nullable = true;
+		Iterator iter = getColumnIterator();
+		while ( iter.hasNext() ) {
+			if ( !( (Column) iter.next() ).isNullable() ) {
+				nullable = false;
+				return nullable; //shortcut
+			}
+		}
+		return nullable;
+	}
+
+	public boolean isSimpleValue() {
+		return true;
+	}
+
+	public boolean isValid(Mapping mapping) throws MappingException {
+		return getColumnSpan()==getType().getColumnSpan(mapping);
+	}
+
+	public Type getType() throws MappingException {
+		if (typeName==null) {
+			throw new MappingException("No type name");
+		}
+		Type result = TypeFactory.heuristicType(typeName, typeParameters);
+		if (result==null) {
+			String msg = "Could not determine type for: " + typeName;
+			if(columns!=null && columns.size()>0) {
+				msg += ", for columns: " + columns;
+			}
+			throw new MappingException(msg);
+		}
+		return result;
+	}
+
+	public void setTypeUsingReflection(String className, String propertyName) throws MappingException {
+		if (typeName==null) {
+			if (className==null) {
+				throw new MappingException("you must specify types for a dynamic entity: " + propertyName);
+			}
+			typeName = ReflectHelper.reflectedPropertyClass(className, propertyName).getName();
+		}
+	}
+
+	public boolean isTypeSpecified() {
+		return typeName!=null;
+	}
+
+	public void setTypeParameters(Properties parameterMap) {
+		this.typeParameters = parameterMap;
+	}
+	
+	public Properties getTypeParameters() {
+		return typeParameters;
+	}
+
+	public String toString() {
+		return getClass().getName() + '(' + columns.toString() + ')';
+	}
+
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}
+	
+	public boolean[] getColumnInsertability() {
+		boolean[] result = new boolean[ getColumnSpan() ];
+		int i = 0;
+		Iterator iter = getColumnIterator();
+		while ( iter.hasNext() ) {
+			Selectable s = (Selectable) iter.next();
+			result[i++] = !s.isFormula();
+		}
+		return result;
+	}
+	
+	public boolean[] getColumnUpdateability() {
+		return getColumnInsertability();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/SingleTableSubclass.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/SingleTableSubclass.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/SingleTableSubclass.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: SingleTableSubclass.java 7270 2005-06-22 17:02:26Z turin42 $
+package org.hibernate.mapping;
+
+import java.util.Iterator;
+
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.util.JoinedIterator;
+
+/**
+ * @author Gavin King
+ */
+public class SingleTableSubclass extends Subclass {
+	
+	public SingleTableSubclass(PersistentClass superclass) {
+		super(superclass);
+	}
+	
+	protected Iterator getNonDuplicatedPropertyIterator() {
+		return new JoinedIterator( 
+				getSuperclass().getUnjoinedPropertyIterator(),
+				getUnjoinedPropertyIterator()
+		);
+	}
+	
+	protected Iterator getDiscriminatorColumnIterator() {
+		if ( isDiscriminatorInsertable() && !getDiscriminator().hasFormula() ) {
+			return getDiscriminator().getColumnIterator();
+		}
+		else {
+			return super.getDiscriminatorColumnIterator();
+		}
+	}
+
+	public Object accept(PersistentClassVisitor mv) {
+		return mv.accept(this);
+	}
+    
+    public void validate(Mapping mapping) throws MappingException {
+        if(getDiscriminator()==null) {
+            throw new MappingException("No discriminator found for " + getEntityName() + ". Discriminator is needed when 'single-table-per-hierarchy' is used and a class has subclasses");
+        }
+        super.validate(mapping);
+    }
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/SingleTableSubclass.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Subclass.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Subclass.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Subclass.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,257 @@
+//$Id: Subclass.java 10119 2006-07-14 00:09:19Z steve.ebersole at jboss.com $
+package org.hibernate.mapping;
+
+import java.util.*;
+import java.util.Map;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.EntityMode;
+import org.hibernate.util.JoinedIterator;
+import org.hibernate.util.SingletonIterator;
+
+/**
+ * A sublass in a table-per-class-hierarchy mapping
+ * @author Gavin King
+ */
+public class Subclass extends PersistentClass {
+
+	private PersistentClass superclass;
+	private Class classPersisterClass;
+	private final int subclassId;
+	
+	public Subclass(PersistentClass superclass) {
+		this.superclass = superclass;
+		this.subclassId = superclass.nextSubclassId();
+	}
+
+	int nextSubclassId() {
+		return getSuperclass().nextSubclassId();
+	}
+	
+	public int getSubclassId() {
+		return subclassId;
+	}
+	
+	public String getCacheConcurrencyStrategy() {
+		return getSuperclass().getCacheConcurrencyStrategy();
+	}
+
+	public RootClass getRootClass() {
+		return getSuperclass().getRootClass();
+	}
+
+	public PersistentClass getSuperclass() {
+		return superclass;
+	}
+
+	public Property getIdentifierProperty() {
+		return getSuperclass().getIdentifierProperty();
+	}
+	public KeyValue getIdentifier() {
+		return getSuperclass().getIdentifier();
+	}
+	public boolean hasIdentifierProperty() {
+		return getSuperclass().hasIdentifierProperty();
+	}
+	public Value getDiscriminator() {
+		return getSuperclass().getDiscriminator();
+	}
+	public boolean isMutable() {
+		return getSuperclass().isMutable();
+	}
+	public boolean isInherited() {
+		return true;
+	}
+	public boolean isPolymorphic() {
+		return true;
+	}
+
+	public void addProperty(Property p) {
+		super.addProperty(p);
+		getSuperclass().addSubclassProperty(p);
+	}
+	public void addJoin(Join j) {
+		super.addJoin(j);
+		getSuperclass().addSubclassJoin(j);
+	}
+
+	public Iterator getPropertyClosureIterator() {
+		return new JoinedIterator(
+				getSuperclass().getPropertyClosureIterator(),
+				getPropertyIterator()
+			);
+	}
+	public Iterator getTableClosureIterator() {
+		return new JoinedIterator(
+				getSuperclass().getTableClosureIterator(),
+				new SingletonIterator( getTable() )
+			);
+	}
+	public Iterator getKeyClosureIterator() {
+		return new JoinedIterator(
+				getSuperclass().getKeyClosureIterator(),
+				new SingletonIterator( getKey() )
+			);
+	}
+	protected void addSubclassProperty(Property p) {
+		super.addSubclassProperty(p);
+		getSuperclass().addSubclassProperty(p);
+	}
+	protected void addSubclassJoin(Join j) {
+		super.addSubclassJoin(j);
+		getSuperclass().addSubclassJoin(j);
+	}
+
+	protected void addSubclassTable(Table table) {
+		super.addSubclassTable(table);
+		getSuperclass().addSubclassTable(table);
+	}
+
+	public boolean isVersioned() {
+		return getSuperclass().isVersioned();
+	}
+	public Property getVersion() {
+		return getSuperclass().getVersion();
+	}
+
+	public boolean hasEmbeddedIdentifier() {
+		return getSuperclass().hasEmbeddedIdentifier();
+	}
+	public Class getEntityPersisterClass() {
+		if (classPersisterClass==null) {
+			return getSuperclass().getEntityPersisterClass();
+		}
+		else {
+			return classPersisterClass;
+		}
+	}
+
+	public Table getRootTable() {
+		return getSuperclass().getRootTable();
+	}
+
+	public KeyValue getKey() {
+		return getSuperclass().getIdentifier();
+	}
+
+	public boolean isExplicitPolymorphism() {
+		return getSuperclass().isExplicitPolymorphism();
+	}
+
+	public void setSuperclass(PersistentClass superclass) {
+		this.superclass = superclass;
+	}
+
+	public String getWhere() {
+		return getSuperclass().getWhere();
+	}
+
+	public boolean isJoinedSubclass() {
+		return getTable()!=getRootTable();
+	}
+
+	public void createForeignKey() {
+		if ( !isJoinedSubclass() ) {
+			throw new AssertionFailure( "not a joined-subclass" );
+		}
+		getKey().createForeignKeyOfEntity( getSuperclass().getEntityName() );
+	}
+
+	public void setEntityPersisterClass(Class classPersisterClass) {
+		this.classPersisterClass = classPersisterClass;
+	}
+
+	public boolean isLazyPropertiesCacheable() {
+		return getSuperclass().isLazyPropertiesCacheable();
+	}
+
+	public int getJoinClosureSpan() {
+		return getSuperclass().getJoinClosureSpan() + super.getJoinClosureSpan();
+	}
+
+	public int getPropertyClosureSpan() {
+		return getSuperclass().getPropertyClosureSpan() + super.getPropertyClosureSpan();
+	}
+
+	public Iterator getJoinClosureIterator() {
+		return new JoinedIterator(
+			getSuperclass().getJoinClosureIterator(),
+			super.getJoinClosureIterator()
+		);
+	}
+
+	public boolean isClassOrSuperclassJoin(Join join) {
+		return super.isClassOrSuperclassJoin(join) || getSuperclass().isClassOrSuperclassJoin(join);
+	}
+
+	public boolean isClassOrSuperclassTable(Table table) {
+		return super.isClassOrSuperclassTable(table) || getSuperclass().isClassOrSuperclassTable(table);
+	}
+
+	public Table getTable() {
+		return getSuperclass().getTable();
+	}
+
+	public boolean isForceDiscriminator() {
+		return getSuperclass().isForceDiscriminator();
+	}
+
+	public boolean isDiscriminatorInsertable() {
+		return getSuperclass().isDiscriminatorInsertable();
+	}
+
+	public java.util.Set getSynchronizedTables() {
+		HashSet result = new HashSet();
+		result.addAll(synchronizedTables);
+		result.addAll( getSuperclass().getSynchronizedTables() );
+		return result;
+	}
+
+	public Object accept(PersistentClassVisitor mv) {
+		return mv.accept(this);
+	}
+
+	public Map getFilterMap() {
+		return getSuperclass().getFilterMap();
+	}
+
+	public boolean hasSubselectLoadableCollections() {
+		return super.hasSubselectLoadableCollections() || 
+			getSuperclass().hasSubselectLoadableCollections();
+	}
+
+	public String getTuplizerImplClassName(EntityMode mode) {
+		String impl = super.getTuplizerImplClassName( mode );
+		if ( impl == null ) {
+			impl = getSuperclass().getTuplizerImplClassName( mode );
+		}
+		return impl;
+	}
+
+	public Map getTuplizerMap() {
+		Map specificTuplizerDefs = super.getTuplizerMap();
+		Map superclassTuplizerDefs = getSuperclass().getTuplizerMap();
+		if ( specificTuplizerDefs == null && superclassTuplizerDefs == null ) {
+			return null;
+		}
+		else {
+			Map combined = new HashMap();
+			if ( superclassTuplizerDefs != null ) {
+				combined.putAll( superclassTuplizerDefs );
+			}
+			if ( specificTuplizerDefs != null ) {
+				combined.putAll( specificTuplizerDefs );
+			}
+			return java.util.Collections.unmodifiableMap( combined );
+		}
+	}
+
+	public Component getIdentifierMapper() {
+		return superclass.getIdentifierMapper();
+	}
+	
+	public int getOptimisticLockMode() {
+		return superclass.getOptimisticLockMode();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Table.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Table.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Table.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,768 @@
+//$Id: Table.java 11303 2007-03-19 22:06:14Z steve.ebersole at jboss.com $
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections.SequencedHashMap;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.Mapping;
+import org.hibernate.tool.hbm2ddl.ColumnMetadata;
+import org.hibernate.tool.hbm2ddl.TableMetadata;
+import org.hibernate.util.CollectionHelper;
+
+/**
+ * A relational table
+ *
+ * @author Gavin King
+ */
+public class Table implements RelationalModel, Serializable {
+
+	private String name;
+	private String schema;
+	private String catalog;
+	/**
+	 * contains all columns, including the primary key
+	 */
+	private Map columns = new SequencedHashMap();
+	private KeyValue idValue;
+	private PrimaryKey primaryKey;
+	private Map indexes = new HashMap();
+	private Map foreignKeys = new HashMap();
+	private Map uniqueKeys = new HashMap();
+	private final int uniqueInteger;
+	private boolean quoted;
+	private boolean schemaQuoted;
+	private static int tableCounter = 0;
+	private List checkConstraints = new ArrayList();
+	private String rowId;
+	private String subselect;
+	private boolean isAbstract;
+	private boolean hasDenormalizedTables = false;
+	private String comment;
+
+	static class ForeignKeyKey implements Serializable {
+		String referencedClassName;
+		List columns;
+		List referencedColumns;
+
+		ForeignKeyKey(List columns, String referencedClassName, List referencedColumns) {
+			this.referencedClassName = referencedClassName;
+			this.columns = new ArrayList();
+			this.columns.addAll( columns );
+			if ( referencedColumns != null ) {
+				this.referencedColumns = new ArrayList();
+				this.referencedColumns.addAll( referencedColumns );
+			}
+			else {
+				this.referencedColumns = CollectionHelper.EMPTY_LIST;
+			}
+		}
+
+		public int hashCode() {
+			return columns.hashCode() + referencedColumns.hashCode();
+		}
+
+		public boolean equals(Object other) {
+			ForeignKeyKey fkk = (ForeignKeyKey) other;
+			return fkk.columns.equals( columns ) &&
+					fkk.referencedClassName.equals( referencedClassName ) && fkk.referencedColumns
+					.equals( referencedColumns );
+		}
+	}
+
+	public Table() {
+		uniqueInteger = tableCounter++;
+	}
+
+	public Table(String name) {
+		this();
+		setName( name );
+	}
+
+	public String getQualifiedName(Dialect dialect, String defaultCatalog, String defaultSchema) {
+		if ( subselect != null ) {
+			return "( " + subselect + " )";
+		}
+		String quotedName = getQuotedName( dialect );
+		String usedSchema = schema == null ?
+				defaultSchema :
+				getQuotedSchema( dialect );
+		String usedCatalog = catalog == null ?
+				defaultCatalog :
+				catalog;
+		return qualify( usedCatalog, usedSchema, quotedName );
+	}
+
+	public static String qualify(String catalog, String schema, String table) {
+		StringBuffer qualifiedName = new StringBuffer();
+		if ( catalog != null ) {
+			qualifiedName.append( catalog ).append( '.' );
+		}
+		if ( schema != null ) {
+			qualifiedName.append( schema ).append( '.' );
+		}
+		return qualifiedName.append( table ).toString();
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * returns quoted name as it would be in the mapping file.
+	 */
+	public String getQuotedName() {
+		return quoted ?
+				"`" + name + "`" :
+				name;
+	}
+
+	public String getQuotedName(Dialect dialect) {
+		return quoted ?
+				dialect.openQuote() + name + dialect.closeQuote() :
+				name;
+	}
+
+	/**
+	 * returns quoted name as it is in the mapping file.
+	 */
+	public String getQuotedSchema() {
+		return schemaQuoted ?
+				"`" + schema + "`" :
+				schema;
+	}
+
+	public String getQuotedSchema(Dialect dialect) {
+		return schemaQuoted ?
+				dialect.openQuote() + schema + dialect.closeQuote() :
+				schema;
+	}
+
+	public void setName(String name) {
+		if ( name.charAt( 0 ) == '`' ) {
+			quoted = true;
+			this.name = name.substring( 1, name.length() - 1 );
+		}
+		else {
+			this.name = name;
+		}
+	}
+
+	/**
+	 * Return the column which is identified by column provided as argument.
+	 *
+	 * @param column column with atleast a name.
+	 * @return the underlying column or null if not inside this table. Note: the instance *can* be different than the input parameter, but the name will be the same.
+	 */
+	public Column getColumn(Column column) {
+		if ( column == null ) {
+			return null;
+		}
+
+		Column myColumn = (Column) columns.get( column.getCanonicalName() );
+
+		return column.equals( myColumn ) ?
+				myColumn :
+				null;
+	}
+
+	public Column getColumn(int n) {
+		Iterator iter = columns.values().iterator();
+		for ( int i = 0; i < n - 1; i++ ) {
+			iter.next();
+		}
+		return (Column) iter.next();
+	}
+
+	public void addColumn(Column column) {
+		Column old = (Column) getColumn( column );
+		if ( old == null ) {
+			columns.put( column.getCanonicalName(), column );
+			column.uniqueInteger = columns.size();
+		}
+		else {
+			column.uniqueInteger = old.uniqueInteger;
+		}
+	}
+
+	public int getColumnSpan() {
+		return columns.size();
+	}
+
+	public Iterator getColumnIterator() {
+		return columns.values().iterator();
+	}
+
+	public Iterator getIndexIterator() {
+		return indexes.values().iterator();
+	}
+
+	public Iterator getForeignKeyIterator() {
+		return foreignKeys.values().iterator();
+	}
+
+	public Iterator getUniqueKeyIterator() {
+		return getUniqueKeys().values().iterator();
+	}
+
+	Map getUniqueKeys() {
+		if ( uniqueKeys.size() > 1 ) {
+			//deduplicate unique constraints sharing the same columns
+			//this is needed by Hibernate Annotations since it creates automagically
+			// unique constraints for the user
+			Iterator it = uniqueKeys.entrySet().iterator();
+			Map finalUniqueKeys = new HashMap( uniqueKeys.size() );
+			while ( it.hasNext() ) {
+				Map.Entry entry = (Map.Entry) it.next();
+				UniqueKey uk = (UniqueKey) entry.getValue();
+				List columns = uk.getColumns();
+				int size = finalUniqueKeys.size();
+				boolean skip = false;
+				Iterator tempUks = finalUniqueKeys.entrySet().iterator();
+				while ( tempUks.hasNext() ) {
+					final UniqueKey currentUk = (UniqueKey) ( (Map.Entry) tempUks.next() ).getValue();
+					if ( currentUk.getColumns().containsAll( columns ) && columns
+							.containsAll( currentUk.getColumns() ) ) {
+						skip = true;
+						break;
+					}
+				}
+				if ( !skip ) finalUniqueKeys.put( entry.getKey(), uk );
+			}
+			return finalUniqueKeys;
+		}
+		else {
+			return uniqueKeys;
+		}
+	}
+
+	public void validateColumns(Dialect dialect, Mapping mapping, TableMetadata tableInfo) {
+		Iterator iter = getColumnIterator();
+		while ( iter.hasNext() ) {
+			Column col = (Column) iter.next();
+
+			ColumnMetadata columnInfo = tableInfo.getColumnMetadata( col.getName() );
+
+			if ( columnInfo == null ) {
+				throw new HibernateException( "Missing column: " + col.getName() + " in " + Table.qualify( tableInfo.getCatalog(), tableInfo.getSchema(), tableInfo.getName()));
+			}
+			else {
+				final boolean typesMatch = col.getSqlType( dialect, mapping )
+						.startsWith( columnInfo.getTypeName().toLowerCase() )
+						|| columnInfo.getTypeCode() == col.getSqlTypeCode( mapping );
+				if ( !typesMatch ) {
+					throw new HibernateException(
+							"Wrong column type: " + col.getName() +
+									", expected: " + col.getSqlType( dialect, mapping )
+					);
+				}
+			}
+		}
+
+	}
+
+	public Iterator sqlAlterStrings(Dialect dialect, Mapping p, TableMetadata tableInfo, String defaultCatalog,
+									String defaultSchema)
+			throws HibernateException {
+
+		StringBuffer root = new StringBuffer( "alter table " )
+				.append( getQualifiedName( dialect, defaultCatalog, defaultSchema ) )
+				.append( ' ' )
+				.append( dialect.getAddColumnString() );
+
+		Iterator iter = getColumnIterator();
+		List results = new ArrayList();
+		while ( iter.hasNext() ) {
+			Column column = (Column) iter.next();
+
+			ColumnMetadata columnInfo = tableInfo.getColumnMetadata( column.getName() );
+
+			if ( columnInfo == null ) {
+				// the column doesnt exist at all.
+				StringBuffer alter = new StringBuffer( root.toString() )
+						.append( ' ' )
+						.append( column.getQuotedName( dialect ) )
+						.append( ' ' )
+						.append( column.getSqlType( dialect, p ) );
+
+				String defaultValue = column.getDefaultValue();
+				if ( defaultValue != null ) {
+					alter.append( " default " ).append( defaultValue );
+
+					if ( column.isNullable() ) {
+						alter.append( dialect.getNullColumnString() );
+					}
+					else {
+						alter.append( " not null" );
+					}
+
+				}
+
+				boolean useUniqueConstraint = column.isUnique() &&
+						dialect.supportsUnique() &&
+						( !column.isNullable() || dialect.supportsNotNullUnique() );
+				if ( useUniqueConstraint ) {
+					alter.append( " unique" );
+				}
+
+				if ( column.hasCheckConstraint() && dialect.supportsColumnCheck() ) {
+					alter.append( " check(" )
+							.append( column.getCheckConstraint() )
+							.append( ")" );
+				}
+
+				String columnComment = column.getComment();
+				if ( columnComment != null ) {
+					alter.append( dialect.getColumnComment( columnComment ) );
+				}
+
+				results.add( alter.toString() );
+			}
+
+		}
+
+		return results.iterator();
+	}
+
+	public boolean hasPrimaryKey() {
+		return getPrimaryKey() != null;
+	}
+
+	public String sqlTemporaryTableCreateString(Dialect dialect, Mapping mapping) throws HibernateException {
+		StringBuffer buffer = new StringBuffer( dialect.getCreateTemporaryTableString() )
+				.append( ' ' )
+				.append( name )
+				.append( " (" );
+		Iterator itr = getColumnIterator();
+		while ( itr.hasNext() ) {
+			final Column column = (Column) itr.next();
+			buffer.append( column.getQuotedName( dialect ) ).append( ' ' );
+			buffer.append( column.getSqlType( dialect, mapping ) );
+			if ( column.isNullable() ) {
+				buffer.append( dialect.getNullColumnString() );
+			}
+			else {
+				buffer.append( " not null" );
+			}
+			if ( itr.hasNext() ) {
+				buffer.append( ", " );
+			}
+		}
+		buffer.append( ") " );
+		buffer.append( dialect.getCreateTemporaryTablePostfix() );
+		return buffer.toString();
+	}
+
+	public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, String defaultSchema) {
+		StringBuffer buf = new StringBuffer( hasPrimaryKey() ? dialect.getCreateTableString() : dialect.getCreateMultisetTableString() )
+				.append( ' ' )
+				.append( getQualifiedName( dialect, defaultCatalog, defaultSchema ) )
+				.append( " (" );
+
+		boolean identityColumn = idValue != null && idValue.isIdentityColumn( dialect );
+
+		// Try to find out the name of the primary key to create it as identity if the IdentityGenerator is used
+		String pkname = null;
+		if ( hasPrimaryKey() && identityColumn ) {
+			pkname = ( (Column) getPrimaryKey().getColumnIterator().next() ).getQuotedName( dialect );
+		}
+
+		Iterator iter = getColumnIterator();
+		while ( iter.hasNext() ) {
+			Column col = (Column) iter.next();
+
+			buf.append( col.getQuotedName( dialect ) )
+					.append( ' ' );
+
+			if ( identityColumn && col.getQuotedName( dialect ).equals( pkname ) ) {
+				// to support dialects that have their own identity data type
+				if ( dialect.hasDataTypeInIdentityColumn() ) {
+					buf.append( col.getSqlType( dialect, p ) );
+				}
+				buf.append( ' ' )
+						.append( dialect.getIdentityColumnString( col.getSqlTypeCode( p ) ) );
+			}
+			else {
+
+				buf.append( col.getSqlType( dialect, p ) );
+
+				String defaultValue = col.getDefaultValue();
+				if ( defaultValue != null ) {
+					buf.append( " default " ).append( defaultValue );
+				}
+
+				if ( col.isNullable() ) {
+					buf.append( dialect.getNullColumnString() );
+				}
+				else {
+					buf.append( " not null" );
+				}
+
+			}
+
+			boolean useUniqueConstraint = col.isUnique() &&
+					( !col.isNullable() || dialect.supportsNotNullUnique() );
+			if ( useUniqueConstraint ) {
+				if ( dialect.supportsUnique() ) {
+					buf.append( " unique" );
+				}
+				else {
+					UniqueKey uk = getOrCreateUniqueKey( col.getQuotedName( dialect ) + '_' );
+					uk.addColumn( col );
+				}
+			}
+
+			if ( col.hasCheckConstraint() && dialect.supportsColumnCheck() ) {
+				buf.append( " check (" )
+						.append( col.getCheckConstraint() )
+						.append( ")" );
+			}
+
+			String columnComment = col.getComment();
+			if ( columnComment != null ) {
+				buf.append( dialect.getColumnComment( columnComment ) );
+			}
+
+			if ( iter.hasNext() ) {
+				buf.append( ", " );
+			}
+
+		}
+		if ( hasPrimaryKey() ) {
+			buf.append( ", " )
+					.append( getPrimaryKey().sqlConstraintString( dialect ) );
+		}
+
+		if ( dialect.supportsUniqueConstraintInCreateAlterTable() ) {
+			Iterator ukiter = getUniqueKeyIterator();
+			while ( ukiter.hasNext() ) {
+				UniqueKey uk = (UniqueKey) ukiter.next();
+				String constraint = uk.sqlConstraintString( dialect );
+				if ( constraint != null ) {
+					buf.append( ", " ).append( constraint );
+				}
+			}
+		}
+		/*Iterator idxiter = getIndexIterator();
+		while ( idxiter.hasNext() ) {
+			Index idx = (Index) idxiter.next();
+			buf.append(',').append( idx.sqlConstraintString(dialect) );
+		}*/
+
+		if ( dialect.supportsTableCheck() ) {
+			Iterator chiter = checkConstraints.iterator();
+			while ( chiter.hasNext() ) {
+				buf.append( ", check (" )
+						.append( chiter.next() )
+						.append( ')' );
+			}
+		}
+
+		buf.append( ')' );
+
+		if ( comment != null ) {
+			buf.append( dialect.getTableComment( comment ) );
+		}
+
+		return buf.append( dialect.getTableTypeString() ).toString();
+	}
+
+	public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
+		StringBuffer buf = new StringBuffer( "drop table " );
+		if ( dialect.supportsIfExistsBeforeTableName() ) {
+			buf.append( "if exists " );
+		}
+		buf.append( getQualifiedName( dialect, defaultCatalog, defaultSchema ) )
+				.append( dialect.getCascadeConstraintsString() );
+		if ( dialect.supportsIfExistsAfterTableName() ) {
+			buf.append( " if exists" );
+		}
+		return buf.toString();
+	}
+
+	public PrimaryKey getPrimaryKey() {
+		return primaryKey;
+	}
+
+	public void setPrimaryKey(PrimaryKey primaryKey) {
+		this.primaryKey = primaryKey;
+	}
+
+	public Index getOrCreateIndex(String indexName) {
+
+		Index index = (Index) indexes.get( indexName );
+
+		if ( index == null ) {
+			index = new Index();
+			index.setName( indexName );
+			index.setTable( this );
+			indexes.put( indexName, index );
+		}
+
+		return index;
+	}
+
+	public Index getIndex(String indexName) {
+		return (Index) indexes.get( indexName );
+	}
+
+	public Index addIndex(Index index) {
+		Index current = (Index) indexes.get( index.getName() );
+		if ( current != null ) {
+			throw new MappingException( "Index " + index.getName() + " already exists!" );
+		}
+		indexes.put( index.getName(), index );
+		return index;
+	}
+
+	public UniqueKey addUniqueKey(UniqueKey uniqueKey) {
+		UniqueKey current = (UniqueKey) uniqueKeys.get( uniqueKey.getName() );
+		if ( current != null ) {
+			throw new MappingException( "UniqueKey " + uniqueKey.getName() + " already exists!" );
+		}
+		uniqueKeys.put( uniqueKey.getName(), uniqueKey );
+		return uniqueKey;
+	}
+
+	public UniqueKey createUniqueKey(List keyColumns) {
+		String keyName = "UK" + uniqueColumnString( keyColumns.iterator() );
+		UniqueKey uk = getOrCreateUniqueKey( keyName );
+		uk.addColumns( keyColumns.iterator() );
+		return uk;
+	}
+
+	public UniqueKey getUniqueKey(String keyName) {
+		return (UniqueKey) uniqueKeys.get( keyName );
+	}
+
+	public UniqueKey getOrCreateUniqueKey(String keyName) {
+		UniqueKey uk = (UniqueKey) uniqueKeys.get( keyName );
+
+		if ( uk == null ) {
+			uk = new UniqueKey();
+			uk.setName( keyName );
+			uk.setTable( this );
+			uniqueKeys.put( keyName, uk );
+		}
+		return uk;
+	}
+
+	public void createForeignKeys() {
+	}
+
+	public ForeignKey createForeignKey(String keyName, List keyColumns, String referencedEntityName) {
+		return createForeignKey( keyName, keyColumns, referencedEntityName, null );
+	}
+
+	public ForeignKey createForeignKey(String keyName, List keyColumns, String referencedEntityName,
+									   List referencedColumns) {
+		Object key = new ForeignKeyKey( keyColumns, referencedEntityName, referencedColumns );
+
+		ForeignKey fk = (ForeignKey) foreignKeys.get( key );
+		if ( fk == null ) {
+			fk = new ForeignKey();
+			if ( keyName != null ) {
+				fk.setName( keyName );
+			}
+			else {
+				fk.setName( "FK" + uniqueColumnString( keyColumns.iterator(), referencedEntityName ) );
+				//TODO: add referencedClass to disambiguate to FKs on the same
+				//      columns, pointing to different tables
+			}
+			fk.setTable( this );
+			foreignKeys.put( key, fk );
+			fk.setReferencedEntityName( referencedEntityName );
+			fk.addColumns( keyColumns.iterator() );
+			if ( referencedColumns != null ) {
+				fk.addReferencedColumns( referencedColumns.iterator() );
+			}
+		}
+
+		if ( keyName != null ) {
+			fk.setName( keyName );
+		}
+
+		return fk;
+	}
+
+
+	public String uniqueColumnString(Iterator iterator) {
+		return uniqueColumnString( iterator, null );
+	}
+
+	public String uniqueColumnString(Iterator iterator, String referencedEntityName) {
+		int result = 0;
+		if ( referencedEntityName != null ) {
+			result += referencedEntityName.hashCode();
+		}
+		while ( iterator.hasNext() ) {
+			result += iterator.next().hashCode();
+		}
+		return ( Integer.toHexString( name.hashCode() ) + Integer.toHexString( result ) ).toUpperCase();
+	}
+
+
+	public String getSchema() {
+		return schema;
+	}
+
+	public void setSchema(String schema) {
+		if ( schema != null && schema.charAt( 0 ) == '`' ) {
+			schemaQuoted = true;
+			this.schema = schema.substring( 1, schema.length() - 1 );
+		}
+		else {
+			this.schema = schema;
+		}
+	}
+
+	public String getCatalog() {
+		return catalog;
+	}
+
+	public void setCatalog(String catalog) {
+		this.catalog = catalog;
+	}
+
+	public int getUniqueInteger() {
+		return uniqueInteger;
+	}
+
+	public void setIdentifierValue(KeyValue idValue) {
+		this.idValue = idValue;
+	}
+
+	public KeyValue getIdentifierValue() {
+		return idValue;
+	}
+
+	public boolean isSchemaQuoted() {
+		return schemaQuoted;
+	}
+
+	public boolean isQuoted() {
+		return quoted;
+	}
+
+	public void setQuoted(boolean quoted) {
+		this.quoted = quoted;
+	}
+
+	public void addCheckConstraint(String constraint) {
+		checkConstraints.add( constraint );
+	}
+
+	public boolean containsColumn(Column column) {
+		return columns.containsValue( column );
+	}
+
+	public String getRowId() {
+		return rowId;
+	}
+
+	public void setRowId(String rowId) {
+		this.rowId = rowId;
+	}
+
+	public String toString() {
+		StringBuffer buf = new StringBuffer().append( getClass().getName() )
+				.append( '(' );
+		if ( getCatalog() != null ) {
+			buf.append( getCatalog() + "." );
+		}
+		if ( getSchema() != null ) {
+			buf.append( getSchema() + "." );
+		}
+		buf.append( getName() ).append( ')' );
+		return buf.toString();
+	}
+
+	public String getSubselect() {
+		return subselect;
+	}
+
+	public void setSubselect(String subselect) {
+		this.subselect = subselect;
+	}
+
+	public boolean isSubselect() {
+		return subselect != null;
+	}
+
+	public boolean isAbstractUnionTable() {
+		return hasDenormalizedTables() && isAbstract;
+	}
+
+	public boolean hasDenormalizedTables() {
+		return hasDenormalizedTables;
+	}
+
+	void setHasDenormalizedTables() {
+		hasDenormalizedTables = true;
+	}
+
+	public void setAbstract(boolean isAbstract) {
+		this.isAbstract = isAbstract;
+	}
+
+	public boolean isAbstract() {
+		return isAbstract;
+	}
+
+	public boolean isPhysicalTable() {
+		return !isSubselect() && !isAbstractUnionTable();
+	}
+
+	public String getComment() {
+		return comment;
+	}
+
+	public void setComment(String comment) {
+		this.comment = comment;
+	}
+
+	public Iterator getCheckConstraintsIterator() {
+		return checkConstraints.iterator();
+	}
+
+	public Iterator sqlCommentStrings(Dialect dialect, String defaultCatalog, String defaultSchema) {
+		List comments = new ArrayList();
+		if ( dialect.supportsCommentOn() ) {
+			String tableName = getQualifiedName( dialect, defaultCatalog, defaultSchema );
+			if ( comment != null ) {
+				StringBuffer buf = new StringBuffer()
+						.append( "comment on table " )
+						.append( tableName )
+						.append( " is '" )
+						.append( comment )
+						.append( "'" );
+				comments.add( buf.toString() );
+			}
+			Iterator iter = getColumnIterator();
+			while ( iter.hasNext() ) {
+				Column column = (Column) iter.next();
+				String columnComment = column.getComment();
+				if ( columnComment != null ) {
+					StringBuffer buf = new StringBuffer()
+							.append( "comment on column " )
+							.append( tableName )
+							.append( '.' )
+							.append( column.getQuotedName( dialect ) )
+							.append( " is '" )
+							.append( columnComment )
+							.append( "'" );
+					comments.add( buf.toString() );
+				}
+			}
+		}
+		return comments.iterator();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/TableOwner.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/TableOwner.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/TableOwner.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+//$Id: TableOwner.java 4646 2004-10-06 23:24:14Z epbernard $
+package org.hibernate.mapping;
+
+/**
+ * Interface allowing to differenciate SubClasses
+ * from Classes, JoinedSubClasses and UnionSubClasses
+ * The first one has not its own table while the others have
+ * 
+ * @author Emmanuel Bernard
+ */
+public interface TableOwner {
+	void setTable(Table table);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ToOne.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ToOne.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ToOne.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,108 @@
+//$Id: ToOne.java 7246 2005-06-20 20:32:36Z oneovthafew $
+package org.hibernate.mapping;
+
+import org.hibernate.FetchMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.type.Type;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * A simple-point association (ie. a reference to another entity).
+ * @author Gavin King
+ */
+public abstract class ToOne extends SimpleValue implements Fetchable {
+
+	private FetchMode fetchMode;
+	protected String referencedPropertyName;
+	private String referencedEntityName;
+	private boolean embedded;
+	private boolean lazy = true;
+	protected boolean unwrapProxy;
+
+	protected ToOne(Table table) {
+		super(table);
+	}
+
+	public FetchMode getFetchMode() {
+		return fetchMode;
+	}
+
+	public void setFetchMode(FetchMode fetchMode) {
+		this.fetchMode=fetchMode;
+	}
+
+	public abstract void createForeignKey() throws MappingException;
+	public abstract Type getType() throws MappingException;
+
+	public String getReferencedPropertyName() {
+		return referencedPropertyName;
+	}
+
+	public void setReferencedPropertyName(String name) {
+		referencedPropertyName = name==null ? null : name.intern();
+	}
+
+	public String getReferencedEntityName() {
+		return referencedEntityName;
+	}
+
+	public void setReferencedEntityName(String referencedEntityName) {
+		this.referencedEntityName = referencedEntityName==null ? 
+				null : referencedEntityName.intern();
+	}
+
+	public void setTypeUsingReflection(String className, String propertyName)
+	throws MappingException {
+		if (referencedEntityName==null) {
+			referencedEntityName = ReflectHelper.reflectedPropertyClass(className, propertyName).getName();
+		}
+	}
+
+	public boolean isTypeSpecified() {
+		return referencedEntityName!=null;
+	}
+	
+	public Object accept(ValueVisitor visitor) {
+		return visitor.accept(this);
+	}
+	
+	public boolean isEmbedded() {
+		return embedded;
+	}
+	
+	public void setEmbedded(boolean embedded) {
+		this.embedded = embedded;
+	}
+
+	public boolean isValid(Mapping mapping) throws MappingException {
+		if (referencedEntityName==null) {
+			throw new MappingException("association must specify the referenced entity");
+		}
+		return super.isValid( mapping );
+	}
+
+	public boolean isLazy() {
+		return lazy;
+	}
+	
+	public void setLazy(boolean lazy) {
+		this.lazy = lazy;
+	}
+
+	public boolean isUnwrapProxy() {
+		return unwrapProxy;
+	}
+
+	public void setUnwrapProxy(boolean unwrapProxy) {
+		this.unwrapProxy = unwrapProxy;
+	}
+	
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/TypeDef.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/TypeDef.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/TypeDef.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+import java.util.Properties;
+
+/**
+ * Placeholder for typedef information
+ */
+public class TypeDef implements Serializable {
+
+	private String typeClass;
+	private Properties parameters;
+
+	public TypeDef(String typeClass, Properties parameters) {
+		this.typeClass = typeClass;
+		this.parameters = parameters;
+	}
+
+	public Properties getParameters() {
+		return parameters;
+	}
+	public String getTypeClass() {
+		return typeClass;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/UnionSubclass.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/UnionSubclass.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/UnionSubclass.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,58 @@
+//$Id: UnionSubclass.java 6514 2005-04-26 06:37:54Z oneovthafew $
+package org.hibernate.mapping;
+
+import java.util.Iterator;
+
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+
+/**
+ * A subclass in a table-per-concrete-class mapping
+ * @author Gavin King
+ */
+public class UnionSubclass extends Subclass implements TableOwner {
+
+	private Table table;
+	private KeyValue key;
+
+	public UnionSubclass(PersistentClass superclass) {
+		super(superclass);
+	}
+
+	public Table getTable() {
+		return table;
+	}
+
+	public void setTable(Table table) {
+		this.table = table;
+		getSuperclass().addSubclassTable(table);
+	}
+
+	public java.util.Set getSynchronizedTables() {
+		return synchronizedTables;
+	}
+	
+	protected Iterator getNonDuplicatedPropertyIterator() {
+		return getPropertyClosureIterator();
+	}
+
+	public void validate(Mapping mapping) throws MappingException {
+		super.validate(mapping);
+		if ( key!=null && !key.isValid(mapping) ) {
+			throw new MappingException(
+				"subclass key mapping has wrong number of columns: " +
+				getEntityName() +
+				" type: " +
+				key.getType().getName()
+			);
+		}
+	}
+	
+	public Table getIdentityTable() {
+		return getTable();
+	}
+	
+	public Object accept(PersistentClassVisitor mv) {
+		return mv.accept(this);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/UniqueKey.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/UniqueKey.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/UniqueKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,82 @@
+//$Id: UniqueKey.java 10661 2006-10-31 02:19:13Z epbernard $
+package org.hibernate.mapping;
+
+import java.util.Iterator;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.Mapping;
+import org.hibernate.util.StringHelper;
+
+/**
+ * A relational unique key constraint
+ *
+ * @author Gavin King
+ */
+public class UniqueKey extends Constraint {
+
+	public String sqlConstraintString(Dialect dialect) {
+		StringBuffer buf = new StringBuffer( "unique (" );
+		Iterator iter = getColumnIterator();
+		boolean nullable = false;
+		while ( iter.hasNext() ) {
+			Column column = (Column) iter.next();
+			if ( !nullable && column.isNullable() ) nullable = true;
+			buf.append( column.getQuotedName( dialect ) );
+			if ( iter.hasNext() ) buf.append( ", " );
+		}
+		//do not add unique constraint on DB not supporting unique and nullable columns
+		return !nullable || dialect.supportsNotNullUnique() ?
+				buf.append( ')' ).toString() :
+				null;
+	}
+
+	public String sqlConstraintString(Dialect dialect, String constraintName, String defaultCatalog,
+									  String defaultSchema) {
+		StringBuffer buf = new StringBuffer(
+				dialect.getAddPrimaryKeyConstraintString( constraintName )
+		).append( '(' );
+		Iterator iter = getColumnIterator();
+		boolean nullable = false;
+		while ( iter.hasNext() ) {
+			Column column = (Column) iter.next();
+			if ( !nullable && column.isNullable() ) nullable = true;
+			buf.append( column.getQuotedName( dialect ) );
+			if ( iter.hasNext() ) buf.append( ", " );
+		}
+		return !nullable || dialect.supportsNotNullUnique() ?
+				StringHelper.replace( buf.append( ')' ).toString(), "primary key", "unique" ) :
+				//TODO: improve this hack!
+				null;
+	}
+
+	public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, String defaultSchema) {
+		if ( dialect.supportsUniqueConstraintInCreateAlterTable() ) {
+			return super.sqlCreateString( dialect, p, defaultCatalog, defaultSchema );
+		}
+		else {
+			return Index.buildSqlCreateIndexString( dialect, getName(), getTable(), getColumnIterator(), true,
+					defaultCatalog, defaultSchema );
+		}
+	}
+
+	public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
+		if ( dialect.supportsUniqueConstraintInCreateAlterTable() ) {
+			return super.sqlDropString( dialect, defaultCatalog, defaultSchema );
+		}
+		else {
+			return Index.buildSqlDropIndexString( dialect, getTable(), getName(), defaultCatalog, defaultSchema );
+		}
+	}
+
+	public boolean isGenerated(Dialect dialect) {
+		if ( dialect.supportsNotNullUnique() ) return true;
+		Iterator iter = getColumnIterator();
+		while ( iter.hasNext() ) {
+			if ( ( (Column) iter.next() ).isNullable() ) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Value.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Value.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/Value.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: Value.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+import java.util.Iterator;
+
+import org.hibernate.FetchMode;
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.type.Type;
+
+/**
+ * A value is anything that is persisted by value, instead of
+ * by reference. It is essentially a Hibernate Type, together
+ * with zero or more columns. Values are wrapped by things with
+ * higher level semantics, for example properties, collections,
+ * classes.
+ *
+ * @author Gavin King
+ */
+public interface Value extends Serializable {
+	public int getColumnSpan();
+	public Iterator getColumnIterator();
+	public Type getType() throws MappingException;
+	public FetchMode getFetchMode();
+	public Table getTable();
+	public boolean hasFormula();
+	public boolean isAlternateUniqueKey();
+	public boolean isNullable();
+	public boolean[] getColumnUpdateability();
+	public boolean[] getColumnInsertability();
+	public void createForeignKey() throws MappingException;
+	public boolean isSimpleValue();
+	public boolean isValid(Mapping mapping) throws MappingException;
+	public void setTypeUsingReflection(String className, String propertyName) throws MappingException;
+	public Object accept(ValueVisitor visitor);
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ValueVisitor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ValueVisitor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/ValueVisitor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+/*
+ * Created on 06-Dec-2004
+ *
+ */
+package org.hibernate.mapping;
+
+/**
+ * @author max
+ *
+ */
+public interface ValueVisitor {
+
+	/**
+	 * @param bag
+	 */
+	Object accept(Bag bag);
+
+	/**
+	 * @param bag
+	 */
+	Object accept(IdentifierBag bag);
+
+	/**
+	 * @param list
+	 */
+	Object accept(List list);
+	
+	Object accept(PrimitiveArray primitiveArray);
+	Object accept(Array list);
+
+	/**
+	 * @param map
+	 */
+	Object accept(Map map);
+
+	/**
+	 * @param many
+	 */
+	Object accept(OneToMany many);
+
+	/**
+	 * @param set
+	 */
+	Object accept(Set set);
+
+	/**
+	 * @param any
+	 */
+	Object accept(Any any);
+
+	/**
+	 * @param value
+	 */
+	Object accept(SimpleValue value);
+	Object accept(DependantValue value);
+	
+	Object accept(Component component);
+	
+	Object accept(ManyToOne mto);
+	Object accept(OneToOne oto);
+	
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines the Hibernate configuration-time metamodel.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/mapping/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/metadata/ClassMetadata.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/metadata/ClassMetadata.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/metadata/ClassMetadata.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,186 @@
+//$Id: ClassMetadata.java 7516 2005-07-16 22:20:48Z oneovthafew $
+package org.hibernate.metadata;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.EntityMode;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Exposes entity class metadata to the application
+ *
+ * @see org.hibernate.SessionFactory#getClassMetadata(Class)
+ * @author Gavin King
+ */
+public interface ClassMetadata {
+
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    // stuff that is persister-centric and/or EntityInfo-centric ~~~~~~~~~~~~~~
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * The name of the entity
+	 */
+	public String getEntityName();
+
+	/**
+	 * Get the name of the identifier property (or return null)
+	 */
+	public String getIdentifierPropertyName();
+
+	/**
+	 * Get the names of the class' persistent properties
+	 */
+	public String[] getPropertyNames();
+
+	/**
+	 * Get the identifier Hibernate type
+	 */
+	public Type getIdentifierType();
+
+	/**
+	 * Get the Hibernate types of the class properties
+	 */
+	public Type[] getPropertyTypes();
+
+	/**
+	 * Get the type of a particular (named) property
+	 */
+	public Type getPropertyType(String propertyName) throws HibernateException;
+
+	/**
+	 * Does this class support dynamic proxies?
+	 */
+	public boolean hasProxy();
+
+	/**
+	 * Are instances of this class mutable?
+	 */
+	public boolean isMutable();
+
+	/**
+	 * Are instances of this class versioned by a timestamp or version number column?
+	 */
+	public boolean isVersioned();
+
+	/**
+	 * Get the index of the version property
+	 */
+	public int getVersionProperty();
+
+	/**
+	 * Get the nullability of the class' persistent properties
+	 */
+	public boolean[] getPropertyNullability();
+
+
+	/**
+	 * Get the "laziness" of the properties of this class
+	 */
+	public boolean[] getPropertyLaziness();
+
+	/**
+	 * Does this class have an identifier property?
+	 */
+	public boolean hasIdentifierProperty();
+
+	/**
+	 * Does this entity declare a natural id?
+	 */
+	public boolean hasNaturalIdentifier();
+
+	/**
+	 * Which properties hold the natural id?
+	 */
+	public int[] getNaturalIdentifierProperties();
+	
+	/**
+	 * Does this entity have mapped subclasses?
+	 */
+	public boolean hasSubclasses();
+	
+	/**
+	 * Does this entity extend a mapped superclass?
+	 */
+	public boolean isInherited();
+	
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	// stuff that is tuplizer-centric, but is passed a session ~~~~~~~~~~~~~~~~
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Return the values of the mapped properties of the object
+	 */
+	public Object[] getPropertyValuesToInsert(Object entity, Map mergeMap, SessionImplementor session) 
+	throws HibernateException;
+
+
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	// stuff that is Tuplizer-centric ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * The persistent class, or null
+	 */
+	public Class getMappedClass(EntityMode entityMode);
+
+	/**
+	 * Create a class instance initialized with the given identifier
+	 */
+	public Object instantiate(Serializable id, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Get the value of a particular (named) property
+	 */
+	public Object getPropertyValue(Object object, String propertyName, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Extract the property values from the given entity.
+	 *
+	 * @param entity The entity from which to extract the property values.
+	 * @param entityMode The entity-mode of the given entity
+	 * @return The property values.
+	 * @throws HibernateException
+	 */
+	public Object[] getPropertyValues(Object entity, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Set the value of a particular (named) property
+	 */
+	public void setPropertyValue(Object object, String propertyName, Object value, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Set the given values to the mapped properties of the given object
+	 */
+	public void setPropertyValues(Object object, Object[] values, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Get the identifier of an instance (throw an exception if no identifier property)
+	 */
+	public Serializable getIdentifier(Object entity, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Set the identifier of an instance (or do nothing if no identifier property)
+	 */
+	public void setIdentifier(Object object, Serializable id, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Does the class implement the <tt>Lifecycle</tt> interface?
+	 */
+	public boolean implementsLifecycle(EntityMode entityMode);
+
+	/**
+	 * Does the class implement the <tt>Validatable</tt> interface?
+	 */
+	public boolean implementsValidatable(EntityMode entityMode);
+
+	/**
+	 * Get the version number (or timestamp) from the object's version property
+	 * (or return null if not versioned)
+	 */
+	public Object getVersion(Object object, EntityMode entityMode) throws HibernateException;
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/metadata/CollectionMetadata.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/metadata/CollectionMetadata.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/metadata/CollectionMetadata.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+//$Id: CollectionMetadata.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.metadata;
+
+import org.hibernate.type.Type;
+
+/**
+ * Exposes collection metadata to the application
+ *
+ * @author Gavin King
+ */
+public interface CollectionMetadata {
+	/**
+	 * The collection key type
+	 */
+	public Type getKeyType();
+	/**
+	 * The collection element type
+	 */
+	public Type getElementType();
+	/**
+	 * The collection index type (or null if the collection has no index)
+	 */
+	public Type getIndexType();
+	/**
+	 * Is this collection indexed?
+	 */
+	public boolean hasIndex();
+	/**
+	 * The name of this collection role
+	 */
+	public String getRole();
+	/**
+	 * Is the collection an array?
+	 */
+	public boolean isArray();
+	/**
+	 * Is the collection a primitive array?
+	 */
+	public boolean isPrimitiveArray();
+	/**
+	 * Is the collection lazily initialized?
+	 */
+	public boolean isLazy();
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/metadata/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/metadata/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/metadata/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines an API for accessing the Hibernate 
+	runtime metamodel.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/metadata/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines the central Hibernate APIs.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/param/AbstractExplicitParameterSpecification.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/param/AbstractExplicitParameterSpecification.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/param/AbstractExplicitParameterSpecification.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+package org.hibernate.param;
+
+import org.hibernate.type.Type;
+
+/**
+ * Convenience base class for explicitly defined query parameters.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public abstract class AbstractExplicitParameterSpecification implements ExplicitParameterSpecification {
+
+	private final int sourceLine;
+	private final int sourceColumn;
+	private Type expectedType;
+
+	protected AbstractExplicitParameterSpecification(int sourceLine, int sourceColumn) {
+		this.sourceLine = sourceLine;
+		this.sourceColumn = sourceColumn;
+	}
+
+	public int getSourceLine() {
+		return sourceLine;
+	}
+
+	public int getSourceColumn() {
+		return sourceColumn;
+	}
+
+	public Type getExpectedType() {
+		return expectedType;
+	}
+
+	public void setExpectedType(Type expectedType) {
+		this.expectedType = expectedType;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/param/CollectionFilterKeyParameterSpecification.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/param/CollectionFilterKeyParameterSpecification.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/param/CollectionFilterKeyParameterSpecification.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+package org.hibernate.param;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * A specialized ParameterSpecification impl for dealing with a collection-key
+ * as part of a collection filter compilation.
+ *
+ * @author Steve Ebersole
+ */
+public class CollectionFilterKeyParameterSpecification implements ParameterSpecification {
+
+	private final String collectionRole;
+	private final Type keyType;
+	private final int queryParameterPosition;
+
+	/**
+	 * Creates a specialized collection-filter collection-key parameter spec.
+	 *
+	 * @param collectionRole The collection role being filtered.
+	 * @param keyType The mapped collection-key type.
+	 * @param queryParameterPosition The position within {@link org.hibernate.engine.QueryParameters} where
+	 * we can find the appropriate param value to bind.
+	 */
+	public CollectionFilterKeyParameterSpecification(String collectionRole, Type keyType, int queryParameterPosition) {
+		this.collectionRole = collectionRole;
+		this.keyType = keyType;
+		this.queryParameterPosition = queryParameterPosition;
+	}
+
+	public int bind(
+			PreparedStatement statement,
+			QueryParameters qp,
+			SessionImplementor session,
+			int position) throws SQLException {
+		Object value = qp.getPositionalParameterValues()[queryParameterPosition];
+		keyType.nullSafeSet( statement, value, position, session );
+		return keyType.getColumnSpan( session.getFactory() );
+	}
+
+	public Type getExpectedType() {
+		return keyType;
+	}
+
+	public void setExpectedType(Type expectedType) {
+		// todo : throw exception?
+	}
+
+	public String renderDisplayInfo() {
+		return "collection-filter-key=" + collectionRole;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/param/DynamicFilterParameterSpecification.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/param/DynamicFilterParameterSpecification.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/param/DynamicFilterParameterSpecification.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+package org.hibernate.param;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * A specialized ParameterSpecification impl for dealing with a dynamic filter
+ * parameters.
+ * <p/>
+ * Note: this class is currently not used.  The ideal way to deal with dynamic filter
+ * parameters for HQL would be to track them just as we do with other parameters
+ * in the translator.  However, the problem with that is that we currently do not
+ * know the filters which actually apply to the query; we know the active/enabled ones,
+ * but not the ones that actually "make it into" the resulting query.
+ *
+ * @author Steve Ebersole
+ */
+public class DynamicFilterParameterSpecification implements ParameterSpecification {
+	private final String filterName;
+	private final String parameterName;
+	private final Type definedParameterType;
+	private final int queryParameterPosition;
+
+	public DynamicFilterParameterSpecification(
+			String filterName,
+			String parameterName,
+			Type definedParameterType,
+			int queryParameterPosition) {
+		this.filterName = filterName;
+		this.parameterName = parameterName;
+		this.definedParameterType = definedParameterType;
+		this.queryParameterPosition = queryParameterPosition;
+	}
+
+	public int bind(
+			PreparedStatement statement,
+			QueryParameters qp,
+			SessionImplementor session,
+			int position) throws SQLException {
+		Object value = qp.getFilteredPositionalParameterValues()[queryParameterPosition];
+		definedParameterType.nullSafeSet( statement, value, position, session );
+		return definedParameterType.getColumnSpan( session.getFactory() );
+	}
+
+	public Type getExpectedType() {
+		return definedParameterType;
+	}
+
+	public void setExpectedType(Type expectedType) {
+		// todo : throw exception?
+	}
+
+	public String renderDisplayInfo() {
+		return "dynamic-filter={filterName=" + filterName + ",paramName=" + parameterName + "}";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/param/ExplicitParameterSpecification.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/param/ExplicitParameterSpecification.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/param/ExplicitParameterSpecification.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+package org.hibernate.param;
+
+/**
+ * An additional contract for parameters which originate from
+ * parameters explicitly encountered in the source statement
+ * (HQL or native-SQL).
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public interface ExplicitParameterSpecification extends ParameterSpecification {
+	public int getSourceLine();
+	public int getSourceColumn();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/param/NamedParameterSpecification.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/param/NamedParameterSpecification.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/param/NamedParameterSpecification.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+// $Id: NamedParameterSpecification.java 8513 2005-11-02 18:47:40Z steveebersole $
+package org.hibernate.param;
+
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.TypedValue;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * Relates to an explicit query named-parameter.
+ *
+ * @author Steve Ebersole
+ */
+public class NamedParameterSpecification extends AbstractExplicitParameterSpecification implements ParameterSpecification {
+
+	private final String name;
+
+	public NamedParameterSpecification(int sourceLine, int sourceColumn, String name) {
+		super( sourceLine, sourceColumn );
+		this.name = name;
+	}
+
+	/**
+	 * Bind the appropriate value into the given statement at the specified position.
+	 *
+	 * @param statement The statement into which the value should be bound.
+	 * @param qp The defined values for the current query execution.
+	 * @param session The session against which the current execution is occuring.
+	 * @param position The position from which to start binding value(s).
+	 *
+	 * @return The number of sql bind positions "eaten" by this bind operation.
+	 */
+	public int bind(PreparedStatement statement, QueryParameters qp, SessionImplementor session, int position)
+	        throws SQLException {
+		TypedValue typedValue = ( TypedValue ) qp.getNamedParameters().get( name );
+		typedValue.getType().nullSafeSet( statement, typedValue.getValue(), position, session );
+		return typedValue.getType().getColumnSpan( session.getFactory() );
+	}
+
+	public String renderDisplayInfo() {
+		return "name=" + name + ", expectedType=" + getExpectedType();
+	}
+
+	public String getName() {
+		return name;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/param/ParameterSpecification.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/param/ParameterSpecification.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/param/ParameterSpecification.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+// $Id: ParameterSpecification.java 10765 2006-11-08 04:30:27Z steve.ebersole at jboss.com $
+package org.hibernate.param;
+
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * Maintains information relating to parameters which need to get bound into a
+ * JDBC {@link PreparedStatement}.
+ *
+ * @author Steve Ebersole
+ */
+public interface ParameterSpecification {
+	/**
+	 * Bind the appropriate value into the given statement at the specified position.
+	 *
+	 * @param statement The statement into which the value should be bound.
+	 * @param qp The defined values for the current query execution.
+	 * @param session The session against which the current execution is occuring.
+	 * @param position The position from which to start binding value(s).
+	 *
+	 * @return The number of sql bind positions "eaten" by this bind operation.
+	 * @throws java.sql.SQLException Indicates problems performing the JDBC biind operation.
+	 */
+	public int bind(PreparedStatement statement, QueryParameters qp, SessionImplementor session, int position) throws SQLException;
+
+	/**
+	 * Get the type which we are expeting for a bind into this parameter based
+	 * on translated contextual information.
+	 *
+	 * @return The expected type.
+	 */
+	public Type getExpectedType();
+
+	/**
+	 * Injects the expected type.  Called during translation.
+	 *
+	 * @param expectedType The type to expect.
+	 */
+	public void setExpectedType(Type expectedType);
+
+	/**
+	 * Render this parameter into displayable info (for logging, etc).
+	 *
+	 * @return The displayable info.
+	 */
+	public String renderDisplayInfo();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/param/PositionalParameterSpecification.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/param/PositionalParameterSpecification.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/param/PositionalParameterSpecification.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+// $Id: PositionalParameterSpecification.java 8513 2005-11-02 18:47:40Z steveebersole $
+package org.hibernate.param;
+
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * Relates to an explicit query positional (or ordinal) parameter.
+ *
+ * @author Steve Ebersole
+ */
+public class PositionalParameterSpecification extends AbstractExplicitParameterSpecification implements ParameterSpecification {
+
+	private final int hqlPosition;
+
+	public PositionalParameterSpecification(int sourceLine, int sourceColumn, int hqlPosition) {
+		super( sourceLine, sourceColumn );
+		this.hqlPosition = hqlPosition;
+	}
+
+	/**
+	 * Bind the appropriate value into the given statement at the specified position.
+	 *
+	 * @param statement The statement into which the value should be bound.
+	 * @param qp The defined values for the current query execution.
+	 * @param session The session against which the current execution is occuring.
+	 * @param position The position from which to start binding value(s).
+	 *
+	 * @return The number of sql bind positions "eaten" by this bind operation.
+	 */
+	public int bind(PreparedStatement statement, QueryParameters qp, SessionImplementor session, int position) throws SQLException {
+		Type type = qp.getPositionalParameterTypes()[hqlPosition];
+		Object value = qp.getPositionalParameterValues()[hqlPosition];
+
+		type.nullSafeSet( statement, value, position, session );
+		return type.getColumnSpan( session.getFactory() );
+	}
+
+	public String renderDisplayInfo() {
+		return "ordinal=" + hqlPosition + ", expectedType=" + getExpectedType();
+	}
+
+	public int getHqlPosition() {
+		return hqlPosition;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/param/VersionTypeSeedParameterSpecification.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/param/VersionTypeSeedParameterSpecification.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/param/VersionTypeSeedParameterSpecification.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+// $Id: VersionTypeSeedParameterSpecification.java 8513 2005-11-02 18:47:40Z steveebersole $
+package org.hibernate.param;
+
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.VersionType;
+import org.hibernate.type.Type;
+import org.hibernate.param.ParameterSpecification;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * Implementation of VersionTypeSeedParameterSpecification.
+ *
+ * @author Steve Ebersole
+ */
+public class VersionTypeSeedParameterSpecification implements ParameterSpecification {
+
+	private VersionType type;
+
+	public VersionTypeSeedParameterSpecification(VersionType type) {
+		this.type = type;
+	}
+
+	/**
+	 * @see org.hibernate.param.ParameterSpecification#bind
+	 */
+	public int bind(PreparedStatement statement, QueryParameters qp, SessionImplementor session, int position)
+	        throws SQLException {
+		type.nullSafeSet( statement, type.seed( session ), position, session );
+		return 1;
+	}
+
+	public Type getExpectedType() {
+		return type;
+	}
+
+	public void setExpectedType(Type expectedType) {
+		// expected type is intrinsic here...
+	}
+
+	public String renderDisplayInfo() {
+		return "version-seed, type=" + type;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/PersisterFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/PersisterFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/PersisterFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,154 @@
+//$Id: PersisterFactory.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.persister;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.persister.collection.BasicCollectionPersister;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.collection.OneToManyPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.JoinedSubclassEntityPersister;
+import org.hibernate.persister.entity.SingleTableEntityPersister;
+import org.hibernate.persister.entity.UnionSubclassEntityPersister;
+
+/**
+ * Factory for <tt>EntityPersister</tt> and <tt>CollectionPersister</tt> instances
+ *
+ * @author Gavin King
+ */
+public final class PersisterFactory {
+
+	//TODO: make EntityPersister *not* depend on SessionFactoryImplementor
+	//interface, if possible
+
+	// TODO : still need to make CollectionPersisters EntityMode-aware
+
+	private PersisterFactory() {}
+
+	private static final Class[] PERSISTER_CONSTRUCTOR_ARGS = new Class[] {
+		PersistentClass.class, EntityRegionAccessStrategy.class, SessionFactoryImplementor.class, Mapping.class
+	};
+
+	// TODO: is it really neceassry to provide Configuration to CollectionPersisters ? Should it not be enough with associated class ?
+	// or why does EntityPersister's not get access to configuration ?
+	//
+	// The only reason I could see that Configuration gets passed to collection persisters
+	// is so that they can look up the dom4j node name of the entity element in case
+	// no explicit node name was applied at the collection element level.  Are you kidding me?
+	// Trivial to fix then.  Just store and expose the node name on the entity persister
+	// (which the collection persister looks up anyway via other means...).
+	private static final Class[] COLLECTION_PERSISTER_CONSTRUCTOR_ARGS = new Class[] {
+			Collection.class, CollectionRegionAccessStrategy.class, Configuration.class, SessionFactoryImplementor.class
+		};
+
+	public static EntityPersister createClassPersister(
+			PersistentClass model,
+			EntityRegionAccessStrategy cacheAccessStrategy,
+			SessionFactoryImplementor factory,
+			Mapping cfg) throws HibernateException {
+		Class persisterClass = model.getEntityPersisterClass();
+		if ( persisterClass == null || persisterClass == SingleTableEntityPersister.class ) {
+			return new SingleTableEntityPersister( model, cacheAccessStrategy, factory, cfg );
+		}
+		else if ( persisterClass == JoinedSubclassEntityPersister.class ) {
+			return new JoinedSubclassEntityPersister( model, cacheAccessStrategy, factory, cfg );
+		}
+		else if ( persisterClass == UnionSubclassEntityPersister.class ) {
+			return new UnionSubclassEntityPersister( model, cacheAccessStrategy, factory, cfg );
+		}
+		else {
+			return create( persisterClass, model, cacheAccessStrategy, factory, cfg );
+		}
+	}
+
+	public static CollectionPersister createCollectionPersister(
+			Configuration cfg,
+			Collection model,
+			CollectionRegionAccessStrategy cacheAccessStrategy,
+			SessionFactoryImplementor factory) throws HibernateException {
+		Class persisterClass = model.getCollectionPersisterClass();
+		if ( persisterClass == null ) {
+			return model.isOneToMany()
+					? ( CollectionPersister ) new OneToManyPersister( model, cacheAccessStrategy, cfg, factory )
+					: ( CollectionPersister ) new BasicCollectionPersister( model, cacheAccessStrategy, cfg, factory );
+		}
+		else {
+			return create( persisterClass, cfg, model, cacheAccessStrategy, factory );
+		}
+
+	}
+
+	private static EntityPersister create(
+			Class persisterClass, 
+			PersistentClass model, 
+			EntityRegionAccessStrategy cacheAccessStrategy,
+			SessionFactoryImplementor factory,
+			Mapping cfg) throws HibernateException {
+		Constructor pc;
+		try {
+			pc = persisterClass.getConstructor( PERSISTER_CONSTRUCTOR_ARGS );
+		}
+		catch ( Exception e ) {
+			throw new MappingException( "Could not get constructor for " + persisterClass.getName(), e );
+		}
+
+		try {
+			return (EntityPersister) pc.newInstance( new Object[] { model, cacheAccessStrategy, factory, cfg } );
+		}
+		catch (InvocationTargetException ite) {
+			Throwable e = ite.getTargetException();
+			if (e instanceof HibernateException) {
+				throw (HibernateException) e;
+			}
+			else {
+				throw new MappingException( "Could not instantiate persister " + persisterClass.getName(), e );
+			}
+		}
+		catch (Exception e) {
+			throw new MappingException( "Could not instantiate persister " + persisterClass.getName(), e );
+		}
+	}
+
+	private static CollectionPersister create(
+			Class persisterClass,
+			Configuration cfg,
+			Collection model,
+			CollectionRegionAccessStrategy cacheAccessStrategy,
+			SessionFactoryImplementor factory) throws HibernateException {
+		Constructor pc;
+		try {
+			pc = persisterClass.getConstructor( COLLECTION_PERSISTER_CONSTRUCTOR_ARGS );
+		}
+		catch (Exception e) {
+			throw new MappingException( "Could not get constructor for " + persisterClass.getName(), e );
+		}
+
+		try {
+			return (CollectionPersister) pc.newInstance( new Object[] { model, cacheAccessStrategy, cfg, factory } );
+		}
+		catch (InvocationTargetException ite) {
+			Throwable e = ite.getTargetException();
+			if (e instanceof HibernateException) {
+				throw (HibernateException) e;
+			}
+			else {
+				throw new MappingException( "Could not instantiate collection persister " + persisterClass.getName(), e );
+			}
+		}
+		catch (Exception e) {
+			throw new MappingException( "Could not instantiate collection persister " + persisterClass.getName(), e );
+		}
+	}
+
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1784 @@
+//$Id: AbstractCollectionPersister.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.persister.collection;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.FetchMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.TransientObjectException;
+import org.hibernate.jdbc.Expectation;
+import org.hibernate.jdbc.Expectations;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cache.entry.CacheEntryStructure;
+import org.hibernate.cache.entry.StructuredCollectionCacheEntry;
+import org.hibernate.cache.entry.StructuredMapCacheEntry;
+import org.hibernate.cache.entry.UnstructuredCacheEntry;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.SubselectFetch;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.loader.collection.CollectionInitializer;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Formula;
+import org.hibernate.mapping.IdentifierCollection;
+import org.hibernate.mapping.IndexedCollection;
+import org.hibernate.mapping.List;
+import org.hibernate.mapping.Selectable;
+import org.hibernate.mapping.Table;
+import org.hibernate.metadata.CollectionMetadata;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.Loadable;
+import org.hibernate.persister.entity.PropertyMapping;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.sql.Alias;
+import org.hibernate.sql.SelectFragment;
+import org.hibernate.sql.SimpleSelect;
+import org.hibernate.sql.Template;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.CollectionHelper;
+import org.hibernate.util.FilterHelper;
+import org.hibernate.util.StringHelper;
+
+
+/**
+ * Base implementation of the <tt>QueryableCollection</tt> interface.
+ *
+ * @author Gavin King
+ * @see BasicCollectionPersister
+ * @see OneToManyPersister
+ */
+public abstract class AbstractCollectionPersister
+		implements CollectionMetadata, SQLLoadableCollection {
+	// TODO: encapsulate the protected instance variables!
+
+	private final String role;
+
+	//SQL statements
+	private final String sqlDeleteString;
+	private final String sqlInsertRowString;
+	private final String sqlUpdateRowString;
+	private final String sqlDeleteRowString;
+	private final String sqlSelectSizeString;
+	private final String sqlSelectRowByIndexString;
+	private final String sqlDetectRowByIndexString;
+	private final String sqlDetectRowByElementString;
+
+	private final String sqlOrderByString;
+	protected final String sqlWhereString;
+	private final String sqlOrderByStringTemplate;
+	private final String sqlWhereStringTemplate;
+	private final boolean hasOrder;
+	protected final boolean hasWhere;
+	private final int baseIndex;
+	
+	private final String nodeName;
+	private final String elementNodeName;
+	private final String indexNodeName;
+
+	protected final boolean indexContainsFormula;
+	protected final boolean elementIsPureFormula;
+	
+	//types
+	private final Type keyType;
+	private final Type indexType;
+	protected final Type elementType;
+	private final Type identifierType;
+
+	//columns
+	protected final String[] keyColumnNames;
+	protected final String[] indexColumnNames;
+	protected final String[] indexFormulaTemplates;
+	protected final String[] indexFormulas;
+	protected final boolean[] indexColumnIsSettable;
+	protected final String[] elementColumnNames;
+	protected final String[] elementFormulaTemplates;
+	protected final String[] elementFormulas;
+	protected final boolean[] elementColumnIsSettable;
+	protected final boolean[] elementColumnIsInPrimaryKey;
+	protected final String[] indexColumnAliases;
+	protected final String[] elementColumnAliases;
+	protected final String[] keyColumnAliases;
+	
+	protected final String identifierColumnName;
+	private final String identifierColumnAlias;
+	//private final String unquotedIdentifierColumnName;
+
+	protected final String qualifiedTableName;
+
+	private final String queryLoaderName;
+
+	private final boolean isPrimitiveArray;
+	private final boolean isArray;
+	protected final boolean hasIndex;
+	protected final boolean hasIdentifier;
+	private final boolean isLazy;
+	private final boolean isExtraLazy;
+	private final boolean isInverse;
+	private final boolean isMutable;
+	private final boolean isVersioned;
+	protected final int batchSize;
+	private final FetchMode fetchMode;
+	private final boolean hasOrphanDelete;
+	private final boolean subselectLoadable;
+
+	//extra information about the element type
+	private final Class elementClass;
+	private final String entityName;
+
+	private final Dialect dialect;
+	private final SQLExceptionConverter sqlExceptionConverter;
+	private final SessionFactoryImplementor factory;
+	private final EntityPersister ownerPersister;
+	private final IdentifierGenerator identifierGenerator;
+	private final PropertyMapping elementPropertyMapping;
+	private final EntityPersister elementPersister;
+	private final CollectionRegionAccessStrategy cacheAccessStrategy;
+	private final CollectionType collectionType;
+	private CollectionInitializer initializer;
+	
+	private final CacheEntryStructure cacheEntryStructure;
+
+	// dynamic filters for the collection
+	private final FilterHelper filterHelper;
+
+	// dynamic filters specifically for many-to-many inside the collection
+	private final FilterHelper manyToManyFilterHelper;
+
+	private final String manyToManyWhereString;
+	private final String manyToManyWhereTemplate;
+
+	private final String manyToManyOrderByString;
+	private final String manyToManyOrderByTemplate;
+
+	// custom sql
+	private final boolean insertCallable;
+	private final boolean updateCallable;
+	private final boolean deleteCallable;
+	private final boolean deleteAllCallable;
+	private ExecuteUpdateResultCheckStyle insertCheckStyle;
+	private ExecuteUpdateResultCheckStyle updateCheckStyle;
+	private ExecuteUpdateResultCheckStyle deleteCheckStyle;
+	private ExecuteUpdateResultCheckStyle deleteAllCheckStyle;
+
+	private final Serializable[] spaces;
+
+	private Map collectionPropertyColumnAliases = new HashMap();
+	private Map collectionPropertyColumnNames = new HashMap();
+
+	private static final Log log = LogFactory.getLog( AbstractCollectionPersister.class );
+
+	public AbstractCollectionPersister(
+			final Collection collection,
+			final CollectionRegionAccessStrategy cacheAccessStrategy,
+			final Configuration cfg,
+			final SessionFactoryImplementor factory) throws MappingException, CacheException {
+
+		this.factory = factory;
+		this.cacheAccessStrategy = cacheAccessStrategy;
+		if ( factory.getSettings().isStructuredCacheEntriesEnabled() ) {
+			cacheEntryStructure = collection.isMap() ?
+					( CacheEntryStructure ) new StructuredMapCacheEntry() :
+					( CacheEntryStructure ) new StructuredCollectionCacheEntry();
+		}
+		else {
+			cacheEntryStructure = new UnstructuredCacheEntry();
+		}
+		
+		dialect = factory.getDialect();
+		sqlExceptionConverter = factory.getSQLExceptionConverter();
+		collectionType = collection.getCollectionType();
+		role = collection.getRole();
+		entityName = collection.getOwnerEntityName();
+		ownerPersister = factory.getEntityPersister(entityName);
+		queryLoaderName = collection.getLoaderName();
+		nodeName = collection.getNodeName();
+		isMutable = collection.isMutable();
+
+		Table table = collection.getCollectionTable();
+		fetchMode = collection.getElement().getFetchMode();
+		elementType = collection.getElement().getType();
+		//isSet = collection.isSet();
+		//isSorted = collection.isSorted();
+		isPrimitiveArray = collection.isPrimitiveArray();
+		isArray = collection.isArray();
+		subselectLoadable = collection.isSubselectLoadable();
+		
+		qualifiedTableName = table.getQualifiedName( 
+				dialect,
+				factory.getSettings().getDefaultCatalogName(),
+				factory.getSettings().getDefaultSchemaName() 
+			);
+
+		int spacesSize = 1 + collection.getSynchronizedTables().size();
+		spaces = new String[spacesSize];
+		spaces[0] = qualifiedTableName;
+		Iterator iter = collection.getSynchronizedTables().iterator();
+		for ( int i = 1; i < spacesSize; i++ ) {
+			spaces[i] = (String) iter.next();
+		}
+		
+		sqlOrderByString = collection.getOrderBy();
+		hasOrder = sqlOrderByString != null;
+		sqlOrderByStringTemplate = hasOrder ?
+				Template.renderOrderByStringTemplate(sqlOrderByString, dialect, factory.getSqlFunctionRegistry()) :
+				null;
+		sqlWhereString = StringHelper.isNotEmpty( collection.getWhere() ) ? "( " + collection.getWhere() + ") " : null;
+		hasWhere = sqlWhereString != null;
+		sqlWhereStringTemplate = hasWhere ?
+				Template.renderWhereStringTemplate(sqlWhereString, dialect, factory.getSqlFunctionRegistry()) :
+				null;
+
+		hasOrphanDelete = collection.hasOrphanDelete();
+
+		int batch = collection.getBatchSize();
+		if ( batch == -1 ) {
+			batch = factory.getSettings().getDefaultBatchFetchSize();
+		}
+		batchSize = batch;
+
+		isVersioned = collection.isOptimisticLocked();
+		
+		// KEY
+
+		keyType = collection.getKey().getType();
+		iter = collection.getKey().getColumnIterator();
+		int keySpan = collection.getKey().getColumnSpan();
+		keyColumnNames = new String[keySpan];
+		keyColumnAliases = new String[keySpan];
+		int k = 0;
+		while ( iter.hasNext() ) {
+			// NativeSQL: collect key column and auto-aliases
+			Column col = ( (Column) iter.next() );
+			keyColumnNames[k] = col.getQuotedName(dialect);
+			keyColumnAliases[k] = col.getAlias(dialect);
+			k++;
+		}
+		
+		//unquotedKeyColumnNames = StringHelper.unQuote(keyColumnAliases);
+
+		//ELEMENT
+
+		String elemNode = collection.getElementNodeName();
+		if ( elementType.isEntityType() ) {
+			String entityName = ( (EntityType) elementType ).getAssociatedEntityName();
+			elementPersister = factory.getEntityPersister(entityName);
+			if ( elemNode==null ) {
+				elemNode = cfg.getClassMapping(entityName).getNodeName();
+			}
+			// NativeSQL: collect element column and auto-aliases
+			
+		}
+		else {
+			elementPersister = null;
+		}		
+		elementNodeName = elemNode;
+
+		int elementSpan = collection.getElement().getColumnSpan();
+		elementColumnAliases = new String[elementSpan];
+		elementColumnNames = new String[elementSpan];
+		elementFormulaTemplates = new String[elementSpan];
+		elementFormulas = new String[elementSpan];
+		elementColumnIsSettable = new boolean[elementSpan];
+		elementColumnIsInPrimaryKey = new boolean[elementSpan];
+		boolean isPureFormula = true;
+		boolean hasNotNullableColumns = false;
+		int j = 0;
+		iter = collection.getElement().getColumnIterator();
+		while ( iter.hasNext() ) {
+			Selectable selectable = (Selectable) iter.next();
+			elementColumnAliases[j] = selectable.getAlias(dialect);
+			if ( selectable.isFormula() ) {
+				Formula form = (Formula) selectable;
+				elementFormulaTemplates[j] = form.getTemplate(dialect, factory.getSqlFunctionRegistry());
+				elementFormulas[j] = form.getFormula();
+			}
+			else {
+				Column col = (Column) selectable;
+				elementColumnNames[j] = col.getQuotedName(dialect);
+				elementColumnIsSettable[j] = true;
+				elementColumnIsInPrimaryKey[j] = !col.isNullable();
+				if ( !col.isNullable() ) {
+					hasNotNullableColumns = true;
+				}
+				isPureFormula = false;
+			}
+			j++;
+		}
+		elementIsPureFormula = isPureFormula;
+		
+		//workaround, for backward compatibility of sets with no
+		//not-null columns, assume all columns are used in the
+		//row locator SQL
+		if ( !hasNotNullableColumns ) {
+			Arrays.fill( elementColumnIsInPrimaryKey, true );
+		}
+
+
+		// INDEX AND ROW SELECT
+
+		hasIndex = collection.isIndexed();
+		if (hasIndex) {
+			// NativeSQL: collect index column and auto-aliases
+			IndexedCollection indexedCollection = (IndexedCollection) collection;
+			indexType = indexedCollection.getIndex().getType();
+			int indexSpan = indexedCollection.getIndex().getColumnSpan();
+			iter = indexedCollection.getIndex().getColumnIterator();
+			indexColumnNames = new String[indexSpan];
+			indexFormulaTemplates = new String[indexSpan];
+			indexFormulas = new String[indexSpan];
+			indexColumnIsSettable = new boolean[indexSpan];
+			indexColumnAliases = new String[indexSpan];
+			int i = 0;
+			boolean hasFormula = false;
+			while ( iter.hasNext() ) {
+				Selectable s = (Selectable) iter.next();
+				indexColumnAliases[i] = s.getAlias(dialect);
+				if ( s.isFormula() ) {
+					Formula indexForm = (Formula) s;
+					indexFormulaTemplates[i] = indexForm.getTemplate(dialect, factory.getSqlFunctionRegistry());
+					indexFormulas[i] = indexForm.getFormula();
+					hasFormula = true;
+				}
+				else {
+					Column indexCol = (Column) s;
+					indexColumnNames[i] = indexCol.getQuotedName(dialect);
+					indexColumnIsSettable[i] = true;
+				}
+				i++;
+			}
+			indexContainsFormula = hasFormula;
+			baseIndex = indexedCollection.isList() ? 
+					( (List) indexedCollection ).getBaseIndex() : 0;
+
+			indexNodeName = indexedCollection.getIndexNodeName(); 
+
+		}
+		else {
+			indexContainsFormula = false;
+			indexColumnIsSettable = null;
+			indexFormulaTemplates = null;
+			indexFormulas = null;
+			indexType = null;
+			indexColumnNames = null;
+			indexColumnAliases = null;
+			baseIndex = 0;
+			indexNodeName = null;
+		}
+		
+		hasIdentifier = collection.isIdentified();
+		if (hasIdentifier) {
+			if ( collection.isOneToMany() ) {
+				throw new MappingException( "one-to-many collections with identifiers are not supported" );
+			}
+			IdentifierCollection idColl = (IdentifierCollection) collection;
+			identifierType = idColl.getIdentifier().getType();
+			iter = idColl.getIdentifier().getColumnIterator();
+			Column col = ( Column ) iter.next();
+			identifierColumnName = col.getQuotedName(dialect);
+			identifierColumnAlias = col.getAlias(dialect);
+			//unquotedIdentifierColumnName = identifierColumnAlias;
+			identifierGenerator = idColl.getIdentifier().createIdentifierGenerator( 
+					factory.getDialect(),
+					factory.getSettings().getDefaultCatalogName(),
+					factory.getSettings().getDefaultSchemaName(),
+					null
+				);
+		}
+		else {
+			identifierType = null;
+			identifierColumnName = null;
+			identifierColumnAlias = null;
+			//unquotedIdentifierColumnName = null;
+			identifierGenerator = null;
+		}
+		
+		//GENERATE THE SQL:
+				
+		//sqlSelectString = sqlSelectString();
+		//sqlSelectRowString = sqlSelectRowString();
+
+		if ( collection.getCustomSQLInsert() == null ) {
+			sqlInsertRowString = generateInsertRowString();
+			insertCallable = false;
+			insertCheckStyle = ExecuteUpdateResultCheckStyle.COUNT;
+		}
+		else {
+			sqlInsertRowString = collection.getCustomSQLInsert();
+			insertCallable = collection.isCustomInsertCallable();
+			insertCheckStyle = collection.getCustomSQLInsertCheckStyle() == null
+					? ExecuteUpdateResultCheckStyle.determineDefault( collection.getCustomSQLInsert(), insertCallable )
+		            : collection.getCustomSQLInsertCheckStyle();
+		}
+
+		if ( collection.getCustomSQLUpdate() == null ) {
+			sqlUpdateRowString = generateUpdateRowString();
+			updateCallable = false;
+			updateCheckStyle = ExecuteUpdateResultCheckStyle.COUNT;
+		}
+		else {
+			sqlUpdateRowString = collection.getCustomSQLUpdate();
+			updateCallable = collection.isCustomUpdateCallable();
+			updateCheckStyle = collection.getCustomSQLUpdateCheckStyle() == null
+					? ExecuteUpdateResultCheckStyle.determineDefault( collection.getCustomSQLUpdate(), insertCallable )
+		            : collection.getCustomSQLUpdateCheckStyle();
+		}
+
+		if ( collection.getCustomSQLDelete() == null ) {
+			sqlDeleteRowString = generateDeleteRowString();
+			deleteCallable = false;
+			deleteCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
+		}
+		else {
+			sqlDeleteRowString = collection.getCustomSQLDelete();
+			deleteCallable = collection.isCustomDeleteCallable();
+			deleteCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
+		}
+
+		if ( collection.getCustomSQLDeleteAll() == null ) {
+			sqlDeleteString = generateDeleteString();
+			deleteAllCallable = false;
+			deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
+		}
+		else {
+			sqlDeleteString = collection.getCustomSQLDeleteAll();
+			deleteAllCallable = collection.isCustomDeleteAllCallable();
+			deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
+		}
+
+		sqlSelectSizeString = generateSelectSizeString(  collection.isIndexed() && !collection.isMap() );
+		sqlDetectRowByIndexString = generateDetectRowByIndexString();
+		sqlDetectRowByElementString = generateDetectRowByElementString();
+		sqlSelectRowByIndexString = generateSelectRowByIndexString();
+		
+		logStaticSQL();
+		
+		isLazy = collection.isLazy();
+		isExtraLazy = collection.isExtraLazy();
+
+		isInverse = collection.isInverse();
+
+		if ( collection.isArray() ) {
+			elementClass = ( (org.hibernate.mapping.Array) collection ).getElementClass();
+		}
+		else {
+			// for non-arrays, we don't need to know the element class
+			elementClass = null; //elementType.returnedClass();
+		}
+
+		if ( elementType.isComponentType() ) {
+			elementPropertyMapping = new CompositeElementPropertyMapping( 
+					elementColumnNames,
+					elementFormulaTemplates,
+					(AbstractComponentType) elementType,
+					factory 
+				);
+		}
+		else if ( !elementType.isEntityType() ) {
+			elementPropertyMapping = new ElementPropertyMapping( 
+					elementColumnNames,
+					elementType 
+				);
+		}
+		else {
+			if ( elementPersister instanceof PropertyMapping ) { //not all classpersisters implement PropertyMapping!
+				elementPropertyMapping = (PropertyMapping) elementPersister;
+			}
+			else {
+				elementPropertyMapping = new ElementPropertyMapping( 
+						elementColumnNames,
+						elementType 
+					);
+			}
+		}
+			
+		// Handle any filters applied to this collection
+		filterHelper = new FilterHelper( collection.getFilterMap(), dialect, factory.getSqlFunctionRegistry() );
+
+		// Handle any filters applied to this collection for many-to-many
+		manyToManyFilterHelper = new FilterHelper( collection.getManyToManyFilterMap(), dialect, factory.getSqlFunctionRegistry() );
+		manyToManyWhereString = StringHelper.isNotEmpty( collection.getManyToManyWhere() ) ?
+				"( " + collection.getManyToManyWhere() + ")" :
+				null;
+		manyToManyWhereTemplate = manyToManyWhereString == null ?
+				null :
+				Template.renderWhereStringTemplate( manyToManyWhereString, factory.getDialect(), factory.getSqlFunctionRegistry() );
+		manyToManyOrderByString = collection.getManyToManyOrdering();
+		manyToManyOrderByTemplate = manyToManyOrderByString == null
+				? null
+	            : Template.renderOrderByStringTemplate( manyToManyOrderByString, factory.getDialect(), factory.getSqlFunctionRegistry() );
+
+		initCollectionPropertyMap();
+	}
+
+	public void postInstantiate() throws MappingException {
+		initializer = queryLoaderName == null ?
+				createCollectionInitializer( CollectionHelper.EMPTY_MAP ) :
+				new NamedQueryCollectionInitializer( queryLoaderName, this );
+	}
+
+	protected void logStaticSQL() {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Static SQL for collection: " + getRole() );
+			if ( getSQLInsertRowString() != null ) {
+				log.debug( " Row insert: " + getSQLInsertRowString() );
+			}
+			if ( getSQLUpdateRowString() != null ) {
+				log.debug( " Row update: " + getSQLUpdateRowString() );
+			}
+			if ( getSQLDeleteRowString() != null ) {
+				log.debug( " Row delete: " + getSQLDeleteRowString() );
+			}
+			if ( getSQLDeleteString() != null ) {
+				log.debug( " One-shot delete: " + getSQLDeleteString() );
+			}
+		}
+	}
+
+	public void initialize(Serializable key, SessionImplementor session) throws HibernateException {
+		getAppropriateInitializer( key, session ).initialize( key, session );
+	}
+
+	protected CollectionInitializer getAppropriateInitializer(Serializable key, SessionImplementor session) {
+		if ( queryLoaderName != null ) {
+			//if there is a user-specified loader, return that
+			//TODO: filters!?
+			return initializer;
+		}
+		CollectionInitializer subselectInitializer = getSubselectInitializer( key, session );
+		if ( subselectInitializer != null ) {
+			return subselectInitializer;
+		}
+		else if ( session.getEnabledFilters().isEmpty() ) {
+			return initializer;
+		}
+		else {
+			return createCollectionInitializer( session.getEnabledFilters() );
+		}
+	}
+
+	private CollectionInitializer getSubselectInitializer(Serializable key, SessionImplementor session) {
+
+		if ( !isSubselectLoadable() ) {
+			return null;
+		}
+		
+		final PersistenceContext persistenceContext = session.getPersistenceContext();
+		
+		SubselectFetch subselect = persistenceContext.getBatchFetchQueue()
+			.getSubselect( new EntityKey( key, getOwnerEntityPersister(), session.getEntityMode() ) );
+		
+		if (subselect == null) {
+			return null;
+		}
+		else {
+			
+			// Take care of any entities that might have
+			// been evicted!	
+			Iterator iter = subselect.getResult().iterator();
+			while ( iter.hasNext() ) {
+				if ( !persistenceContext.containsEntity( (EntityKey) iter.next() ) ) {
+					iter.remove();
+				}
+			}	
+			
+			// Run a subquery loader
+			return createSubselectInitializer( subselect, session );
+		}
+	}
+
+	protected abstract CollectionInitializer createSubselectInitializer(SubselectFetch subselect, SessionImplementor session);
+
+	protected abstract CollectionInitializer createCollectionInitializer(Map enabledFilters)
+			throws MappingException;
+
+	public CollectionRegionAccessStrategy getCacheAccessStrategy() {
+		return cacheAccessStrategy;
+	}
+
+	public boolean hasCache() {
+		return cacheAccessStrategy != null;
+	}
+
+	public CollectionType getCollectionType() {
+		return collectionType;
+	}
+
+	protected String getSQLWhereString(String alias) {
+		return StringHelper.replace( sqlWhereStringTemplate, Template.TEMPLATE, alias );
+	}
+
+	public String getSQLOrderByString(String alias) {
+		return hasOrdering() ? 
+			StringHelper.replace( sqlOrderByStringTemplate, Template.TEMPLATE, alias ) : "";
+	}
+
+	public String getManyToManyOrderByString(String alias) {
+		if ( isManyToMany() && manyToManyOrderByString != null ) {
+			return StringHelper.replace( manyToManyOrderByTemplate, Template.TEMPLATE, alias );
+		}
+		else {
+			return "";
+		}
+	}
+	public FetchMode getFetchMode() {
+		return fetchMode;
+	}
+
+	public boolean hasOrdering() {
+		return hasOrder;
+	}
+
+	public boolean hasManyToManyOrdering() {
+		return isManyToMany() && manyToManyOrderByTemplate != null;
+	}
+
+	public boolean hasWhere() {
+		return hasWhere;
+	}
+
+	protected String getSQLDeleteString() {
+		return sqlDeleteString;
+	}
+
+	protected String getSQLInsertRowString() {
+		return sqlInsertRowString;
+	}
+
+	protected String getSQLUpdateRowString() {
+		return sqlUpdateRowString;
+	}
+
+	protected String getSQLDeleteRowString() {
+		return sqlDeleteRowString;
+	}
+
+	public Type getKeyType() {
+		return keyType;
+	}
+
+	public Type getIndexType() {
+		return indexType;
+	}
+
+	public Type getElementType() {
+		return elementType;
+	}
+
+	/**
+	 * Return the element class of an array, or null otherwise
+	 */
+	public Class getElementClass() { //needed by arrays
+		return elementClass;
+	}
+
+	public Object readElement(ResultSet rs, Object owner, String[] aliases, SessionImplementor session) 
+	throws HibernateException, SQLException {
+		return getElementType().nullSafeGet( rs, aliases, session, owner );
+	}
+
+	public Object readIndex(ResultSet rs, String[] aliases, SessionImplementor session) 
+	throws HibernateException, SQLException {
+		Object index = getIndexType().nullSafeGet( rs, aliases, session, null );
+		if ( index == null ) {
+			throw new HibernateException( "null index column for collection: " + role );
+		}
+		index = decrementIndexByBase( index );
+		return index;
+	}
+
+	protected Object decrementIndexByBase(Object index) {
+		if (baseIndex!=0) {
+			index = new Integer( ( (Integer) index ).intValue() - baseIndex );
+		}
+		return index;
+	}
+
+	public Object readIdentifier(ResultSet rs, String alias, SessionImplementor session) 
+	throws HibernateException, SQLException {
+		Object id = getIdentifierType().nullSafeGet( rs, alias, session, null );
+		if ( id == null ) {
+			throw new HibernateException( "null identifier column for collection: " + role );
+		}
+		return id;
+	}
+
+	public Object readKey(ResultSet rs, String[] aliases, SessionImplementor session) 
+	throws HibernateException, SQLException {
+		return getKeyType().nullSafeGet( rs, aliases, session, null );
+	}
+
+	/**
+	 * Write the key to a JDBC <tt>PreparedStatement</tt>
+	 */
+	protected int writeKey(PreparedStatement st, Serializable key, int i, SessionImplementor session)
+			throws HibernateException, SQLException {
+		
+		if ( key == null ) {
+			throw new NullPointerException( "null key for collection: " + role );  //an assertion
+		}
+		getKeyType().nullSafeSet( st, key, i, session );
+		return i + keyColumnAliases.length;
+	}
+
+	/**
+	 * Write the element to a JDBC <tt>PreparedStatement</tt>
+	 */
+	protected int writeElement(PreparedStatement st, Object elt, int i, SessionImplementor session)
+			throws HibernateException, SQLException {
+		getElementType().nullSafeSet(st, elt, i, elementColumnIsSettable, session);
+		return i + ArrayHelper.countTrue(elementColumnIsSettable);
+
+	}
+
+	/**
+	 * Write the index to a JDBC <tt>PreparedStatement</tt>
+	 */
+	protected int writeIndex(PreparedStatement st, Object index, int i, SessionImplementor session)
+			throws HibernateException, SQLException {
+		getIndexType().nullSafeSet( st, incrementIndexByBase(index), i, indexColumnIsSettable, session );
+		return i + ArrayHelper.countTrue(indexColumnIsSettable);
+	}
+
+	protected Object incrementIndexByBase(Object index) {
+		if (baseIndex!=0) {
+			index = new Integer( ( (Integer) index ).intValue() + baseIndex );
+		}
+		return index;
+	}
+
+	/**
+	 * Write the element to a JDBC <tt>PreparedStatement</tt>
+	 */
+	protected int writeElementToWhere(PreparedStatement st, Object elt, int i, SessionImplementor session)
+			throws HibernateException, SQLException {
+		if (elementIsPureFormula) {
+			throw new AssertionFailure("cannot use a formula-based element in the where condition");
+		}
+		getElementType().nullSafeSet(st, elt, i, elementColumnIsInPrimaryKey, session);
+		return i + elementColumnAliases.length;
+
+	}
+
+	/**
+	 * Write the index to a JDBC <tt>PreparedStatement</tt>
+	 */
+	protected int writeIndexToWhere(PreparedStatement st, Object index, int i, SessionImplementor session)
+			throws HibernateException, SQLException {
+		if (indexContainsFormula) {
+			throw new AssertionFailure("cannot use a formula-based index in the where condition");
+		}
+		getIndexType().nullSafeSet( st, incrementIndexByBase(index), i, session );
+		return i + indexColumnAliases.length;
+	}
+
+	/**
+	 * Write the identifier to a JDBC <tt>PreparedStatement</tt>
+	 */
+	public int writeIdentifier(PreparedStatement st, Object id, int i, SessionImplementor session)
+			throws HibernateException, SQLException {
+		
+		getIdentifierType().nullSafeSet( st, id, i, session );
+		return i + 1;
+	}
+
+	public boolean isPrimitiveArray() {
+		return isPrimitiveArray;
+	}
+
+	public boolean isArray() {
+		return isArray;
+	}
+
+	public String[] getKeyColumnAliases(String suffix) {
+		return new Alias( suffix ).toAliasStrings( keyColumnAliases );
+	}
+
+	public String[] getElementColumnAliases(String suffix) {
+		return new Alias( suffix ).toAliasStrings( elementColumnAliases );
+	}
+
+	public String[] getIndexColumnAliases(String suffix) {
+		if ( hasIndex ) {
+			return new Alias( suffix ).toAliasStrings( indexColumnAliases );
+		}
+		else {
+			return null;
+		}
+	}
+
+	public String getIdentifierColumnAlias(String suffix) {
+		if ( hasIdentifier ) {
+			return new Alias( suffix ).toAliasString( identifierColumnAlias );
+		}
+		else {
+			return null;
+		}
+	}
+	
+	public String getIdentifierColumnName() {
+		if ( hasIdentifier ) {
+			return identifierColumnName;
+		} else {
+			return null;
+		}
+	}
+
+	/**
+	 * Generate a list of collection index, key and element columns
+	 */
+	public String selectFragment(String alias, String columnSuffix) {
+		SelectFragment frag = generateSelectFragment( alias, columnSuffix );
+		appendElementColumns( frag, alias );
+		appendIndexColumns( frag, alias );
+		appendIdentifierColumns( frag, alias );
+
+		return frag.toFragmentString()
+				.substring( 2 ); //strip leading ','
+	}
+
+	protected String generateSelectSizeString(boolean isIntegerIndexed) {
+		String selectValue = isIntegerIndexed ? 
+			"max(" + getIndexColumnNames()[0] + ") + 1": //lists, arrays
+			"count(" + getElementColumnNames()[0] + ")"; //sets, maps, bags
+		return new SimpleSelect(dialect)
+				.setTableName( getTableName() )
+				.addCondition( getKeyColumnNames(), "=?" )
+				.addColumn(selectValue)
+				.toStatementString();
+	}
+
+	protected String generateDetectRowByIndexString() {
+		if ( !hasIndex() ) {
+			return null;
+		}
+		return new SimpleSelect(dialect)
+				.setTableName( getTableName() )
+				.addCondition( getKeyColumnNames(), "=?" )
+				.addCondition( getIndexColumnNames(), "=?" )
+				.addCondition( indexFormulas, "=?" )
+				.addColumn("1")
+				.toStatementString();
+	}
+
+	protected String generateSelectRowByIndexString() {
+		if ( !hasIndex() ) {
+			return null;
+		}
+		return new SimpleSelect(dialect)
+				.setTableName( getTableName() )
+				.addCondition( getKeyColumnNames(), "=?" )
+				.addCondition( getIndexColumnNames(), "=?" )
+				.addCondition( indexFormulas, "=?" )
+				.addColumns( getElementColumnNames(), elementColumnAliases )
+				.addColumns( indexFormulas, indexColumnAliases )
+				.toStatementString();
+	}
+
+	protected String generateDetectRowByElementString() {
+		return new SimpleSelect(dialect)
+				.setTableName( getTableName() )
+				.addCondition( getKeyColumnNames(), "=?" )
+				.addCondition( getElementColumnNames(), "=?" )
+				.addCondition( elementFormulas, "=?" )
+				.addColumn("1")
+				.toStatementString();
+	}
+
+	protected SelectFragment generateSelectFragment(String alias, String columnSuffix) {
+		return new SelectFragment()
+				.setSuffix( columnSuffix )
+				.addColumns( alias, keyColumnNames, keyColumnAliases );
+	}
+
+	protected void appendElementColumns(SelectFragment frag, String elemAlias) {
+		for ( int i=0; i<elementColumnIsSettable.length; i++ ) {
+			if ( elementColumnIsSettable[i] ) {
+				frag.addColumn( elemAlias, elementColumnNames[i], elementColumnAliases[i] );
+			}
+			else {
+				frag.addFormula( elemAlias, elementFormulaTemplates[i], elementColumnAliases[i] );
+			}
+		}
+	}
+
+	protected void appendIndexColumns(SelectFragment frag, String alias) {
+		if ( hasIndex ) {
+			for ( int i=0; i<indexColumnIsSettable.length; i++ ) {
+				if ( indexColumnIsSettable[i] ) {
+					frag.addColumn( alias, indexColumnNames[i], indexColumnAliases[i] );
+				}
+				else {
+					frag.addFormula( alias, indexFormulaTemplates[i], indexColumnAliases[i] );
+				}
+			}
+		}
+	}
+
+	protected void appendIdentifierColumns(SelectFragment frag, String alias) {
+		if ( hasIdentifier ) {
+			frag.addColumn( alias, identifierColumnName, identifierColumnAlias );
+		}
+	}
+
+	public String[] getIndexColumnNames() {
+		return indexColumnNames;
+	}
+
+	public String[] getIndexFormulas() {
+		return indexFormulas;
+	}
+
+	public String[] getIndexColumnNames(String alias) {
+		return qualify(alias, indexColumnNames, indexFormulaTemplates);
+
+	}
+
+	public String[] getElementColumnNames(String alias) {
+		return qualify(alias, elementColumnNames, elementFormulaTemplates);
+	}
+	
+	private static String[] qualify(String alias, String[] columnNames, String[] formulaTemplates) {
+		int span = columnNames.length;
+		String[] result = new String[span];
+		for (int i=0; i<span; i++) {
+			if ( columnNames[i]==null ) {
+				result[i] = StringHelper.replace( formulaTemplates[i], Template.TEMPLATE, alias );
+			}
+			else {
+				result[i] = StringHelper.qualify( alias, columnNames[i] );
+			}
+		}
+		return result;
+	}
+
+	public String[] getElementColumnNames() {
+		return elementColumnNames; //TODO: something with formulas...
+	}
+
+	public String[] getKeyColumnNames() {
+		return keyColumnNames;
+	}
+
+	public boolean hasIndex() {
+		return hasIndex;
+	}
+
+	public boolean isLazy() {
+		return isLazy;
+	}
+
+	public boolean isInverse() {
+		return isInverse;
+	}
+
+	public String getTableName() {
+		return qualifiedTableName;
+	}
+
+	public void remove(Serializable id, SessionImplementor session) throws HibernateException {
+
+		if ( !isInverse && isRowDeleteEnabled() ) {
+
+			if ( log.isDebugEnabled() ) {
+				log.debug( 
+						"Deleting collection: " + 
+						MessageHelper.collectionInfoString( this, id, getFactory() ) 
+					);
+			}
+
+			// Remove all the old entries
+
+			try {
+				int offset = 1;
+				PreparedStatement st = null;
+				Expectation expectation = Expectations.appropriateExpectation( getDeleteAllCheckStyle() );
+				boolean callable = isDeleteAllCallable();
+				boolean useBatch = expectation.canBeBatched();
+				String sql = getSQLDeleteString();
+				if ( useBatch ) {
+					if ( callable ) {
+						st = session.getBatcher().prepareBatchCallableStatement( sql );
+					}
+					else {
+						st = session.getBatcher().prepareBatchStatement( sql );
+					}
+				}
+				else {
+					if ( callable ) {
+						st = session.getBatcher().prepareCallableStatement( sql );
+					}
+					else {
+						st = session.getBatcher().prepareStatement( sql );
+					}
+				}
+
+
+				try {
+					offset+= expectation.prepare( st );
+
+					writeKey( st, id, offset, session );
+					if ( useBatch ) {
+						session.getBatcher().addToBatch( expectation );
+					}
+					else {
+						expectation.verifyOutcome( st.executeUpdate(), st, -1 );
+					}
+				}
+				catch ( SQLException sqle ) {
+					if ( useBatch ) {
+						session.getBatcher().abortBatch( sqle );
+					}
+					throw sqle;
+				}
+				finally {
+					if ( !useBatch ) {
+						session.getBatcher().closeStatement( st );
+					}
+				}
+
+				if ( log.isDebugEnabled() ) {
+					log.debug( "done deleting collection" );
+				}
+			}
+			catch ( SQLException sqle ) {
+				throw JDBCExceptionHelper.convert(
+				        sqlExceptionConverter,
+				        sqle,
+				        "could not delete collection: " + 
+				        MessageHelper.collectionInfoString( this, id, getFactory() ),
+				        getSQLDeleteString()
+					);
+			}
+
+		}
+
+	}
+
+	public void recreate(PersistentCollection collection, Serializable id, SessionImplementor session)
+			throws HibernateException {
+
+		if ( !isInverse && isRowInsertEnabled() ) {
+
+			if ( log.isDebugEnabled() ) {
+				log.debug( 
+						"Inserting collection: " + 
+						MessageHelper.collectionInfoString( this, id, getFactory() ) 
+					);
+			}
+
+			try {
+				//create all the new entries
+				Iterator entries = collection.entries(this);
+				if ( entries.hasNext() ) {
+					collection.preInsert( this );
+					int i = 0;
+					int count = 0;
+					while ( entries.hasNext() ) {
+
+						final Object entry = entries.next();
+						if ( collection.entryExists( entry, i ) ) {
+							int offset = 1;
+							PreparedStatement st = null;
+							Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() );
+							boolean callable = isInsertCallable();
+							boolean useBatch = expectation.canBeBatched();
+							String sql = getSQLInsertRowString();
+
+							if ( useBatch ) {
+								if ( callable ) {
+									st = session.getBatcher().prepareBatchCallableStatement( sql );
+								}
+								else {
+									st = session.getBatcher().prepareBatchStatement( sql );
+								}
+							}
+							else {
+								if ( callable ) {
+									st = session.getBatcher().prepareCallableStatement( sql );
+								}
+								else {
+									st = session.getBatcher().prepareStatement( sql );
+								}
+							}
+
+
+							try {
+								offset+= expectation.prepare( st );
+
+								//TODO: copy/paste from insertRows()
+								int loc = writeKey( st, id, offset, session );
+								if ( hasIdentifier ) {
+									loc = writeIdentifier( st, collection.getIdentifier(entry, i), loc, session );
+								}
+								if ( hasIndex /*&& !indexIsFormula*/ ) {
+									loc = writeIndex( st, collection.getIndex(entry, i, this), loc, session );
+								}
+								loc = writeElement(st, collection.getElement(entry), loc, session );
+
+								if ( useBatch ) {
+									session.getBatcher().addToBatch( expectation );
+								}
+								else {
+									expectation.verifyOutcome( st.executeUpdate(), st, -1 );
+								}
+
+								collection.afterRowInsert( this, entry, i );
+								count++;
+							}
+							catch ( SQLException sqle ) {
+								if ( useBatch ) {
+									session.getBatcher().abortBatch( sqle );
+								}
+								throw sqle;
+							}
+							finally {
+								if ( !useBatch ) {
+									session.getBatcher().closeStatement( st );
+								}
+							}
+
+						}
+						i++;
+					}
+
+					if ( log.isDebugEnabled() ) {
+						log.debug( "done inserting collection: " + count + " rows inserted" );
+					}
+
+				}
+				else {
+					if ( log.isDebugEnabled() ) {
+						log.debug( "collection was empty" );
+					}
+				}
+			}
+			catch ( SQLException sqle ) {
+				throw JDBCExceptionHelper.convert(
+				        sqlExceptionConverter,
+				        sqle,
+				        "could not insert collection: " + 
+				        MessageHelper.collectionInfoString( this, id, getFactory() ),
+				        getSQLInsertRowString()
+					);
+			}
+		}
+	}
+	
+	protected boolean isRowDeleteEnabled() {
+		return true;
+	}
+
+	public void deleteRows(PersistentCollection collection, Serializable id, SessionImplementor session)
+			throws HibernateException {
+
+		if ( !isInverse && isRowDeleteEnabled() ) {
+
+			if ( log.isDebugEnabled() ) {
+				log.debug( 
+						"Deleting rows of collection: " + 
+						MessageHelper.collectionInfoString( this, id, getFactory() ) 
+					);
+			}
+			
+			boolean deleteByIndex = !isOneToMany() && hasIndex && !indexContainsFormula;
+			
+			try {
+				//delete all the deleted entries
+				Iterator deletes = collection.getDeletes( this, !deleteByIndex );
+				if ( deletes.hasNext() ) {
+					int offset = 1;
+					int count = 0;
+					while ( deletes.hasNext() ) {
+						PreparedStatement st = null;
+						Expectation expectation = Expectations.appropriateExpectation( getDeleteCheckStyle() );
+						boolean callable = isDeleteCallable();
+						boolean useBatch = expectation.canBeBatched();
+						String sql = getSQLDeleteRowString();
+
+						if ( useBatch ) {
+							if ( callable ) {
+								st = session.getBatcher().prepareBatchCallableStatement( sql );
+							}
+							else {
+								st = session.getBatcher().prepareBatchStatement( sql );
+							}
+						}
+						else {
+							if ( callable ) {
+								st = session.getBatcher().prepareCallableStatement( sql );
+							}
+							else {
+								st = session.getBatcher().prepareStatement( sql );
+							}
+						}
+
+						try {
+							expectation.prepare( st );
+
+							Object entry = deletes.next();
+							int loc = offset;
+							if ( hasIdentifier ) {
+								writeIdentifier( st, entry, loc, session );
+							}
+							else {
+								loc = writeKey( st, id, loc, session );
+								if ( deleteByIndex ) {
+									writeIndexToWhere( st, entry, loc, session );
+								}
+								else {
+									writeElementToWhere( st, entry, loc, session );
+								}
+							}
+
+							if ( useBatch ) {
+								session.getBatcher().addToBatch( expectation );
+							}
+							else {
+								expectation.verifyOutcome( st.executeUpdate(), st, -1 );
+							}
+							count++;
+						}
+						catch ( SQLException sqle ) {
+							if ( useBatch ) {
+								session.getBatcher().abortBatch( sqle );
+							}
+							throw sqle;
+						}
+						finally {
+							if ( !useBatch ) {
+								session.getBatcher().closeStatement( st );
+							}
+						}
+
+						if ( log.isDebugEnabled() ) {
+							log.debug( "done deleting collection rows: " + count + " deleted" );
+						}
+					}
+				}
+				else {
+					if ( log.isDebugEnabled() ) {
+						log.debug( "no rows to delete" );
+					}
+				}
+			}
+			catch ( SQLException sqle ) {
+				throw JDBCExceptionHelper.convert(
+				        sqlExceptionConverter,
+				        sqle,
+				        "could not delete collection rows: " + 
+				        MessageHelper.collectionInfoString( this, id, getFactory() ),
+				        getSQLDeleteRowString()
+					);
+			}
+		}
+	}
+	
+	protected boolean isRowInsertEnabled() {
+		return true;
+	}
+
+	public void insertRows(PersistentCollection collection, Serializable id, SessionImplementor session)
+			throws HibernateException {
+
+		if ( !isInverse && isRowInsertEnabled() ) {
+
+			if ( log.isDebugEnabled() ) {
+				log.debug( 
+						"Inserting rows of collection: " + 
+						MessageHelper.collectionInfoString( this, id, getFactory() ) 
+					);
+			}
+
+			try {
+				//insert all the new entries
+				collection.preInsert( this );
+				Iterator entries = collection.entries( this );
+				Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() );
+				boolean callable = isInsertCallable();
+				boolean useBatch = expectation.canBeBatched();
+				String sql = getSQLInsertRowString();
+				int i = 0;
+				int count = 0;
+				while ( entries.hasNext() ) {
+					int offset = 1;
+					Object entry = entries.next();
+					PreparedStatement st = null;
+					if ( collection.needsInserting( entry, i, elementType ) ) {
+
+						if ( useBatch ) {
+							if ( st == null ) {
+								if ( callable ) {
+									st = session.getBatcher().prepareBatchCallableStatement( sql );
+								}
+								else {
+									st = session.getBatcher().prepareBatchStatement( sql );
+								}
+							}
+						}
+						else {
+							if ( callable ) {
+								st = session.getBatcher().prepareCallableStatement( sql );
+							}
+							else {
+								st = session.getBatcher().prepareStatement( sql );
+							}
+						}
+
+						try {
+							offset += expectation.prepare( st );
+							//TODO: copy/paste from recreate()
+							offset = writeKey( st, id, offset, session );
+							if ( hasIdentifier ) {
+								offset = writeIdentifier( st, collection.getIdentifier(entry, i), offset, session );
+							}
+							if ( hasIndex /*&& !indexIsFormula*/ ) {
+								offset = writeIndex( st, collection.getIndex(entry, i, this), offset, session );
+							}
+							writeElement(st, collection.getElement(entry), offset, session );
+
+							if ( useBatch ) {
+								session.getBatcher().addToBatch( expectation );
+							}
+							else {
+								expectation.verifyOutcome( st.executeUpdate(), st, -1 );
+							}
+							collection.afterRowInsert( this, entry, i );
+							count++;
+						}
+						catch ( SQLException sqle ) {
+							if ( useBatch ) {
+								session.getBatcher().abortBatch( sqle );
+							}
+							throw sqle;
+						}
+						finally {
+							if ( !useBatch ) {
+								session.getBatcher().closeStatement( st );
+							}
+						}
+					}
+					i++;
+				}
+				if ( log.isDebugEnabled() ) {
+					log.debug( "done inserting rows: " + count + " inserted" );
+				}
+			}
+			catch ( SQLException sqle ) {
+				throw JDBCExceptionHelper.convert(
+				        sqlExceptionConverter,
+				        sqle,
+				        "could not insert collection rows: " + 
+				        MessageHelper.collectionInfoString( this, id, getFactory() ),
+				        getSQLInsertRowString()
+					);
+			}
+
+		}
+	}
+
+
+	public String getRole() {
+		return role;
+	}
+
+	public String getOwnerEntityName() {
+		return entityName;
+	}
+
+	public EntityPersister getOwnerEntityPersister() {
+		return ownerPersister;
+	}
+
+	public IdentifierGenerator getIdentifierGenerator() {
+		return identifierGenerator;
+	}
+
+	public Type getIdentifierType() {
+		return identifierType;
+	}
+
+	public boolean hasOrphanDelete() {
+		return hasOrphanDelete;
+	}
+
+	public Type toType(String propertyName) throws QueryException {
+		if ( "index".equals( propertyName ) ) {
+			return indexType;
+		}
+		return elementPropertyMapping.toType( propertyName );
+	}
+
+	public abstract boolean isManyToMany();
+
+	public String getManyToManyFilterFragment(String alias, Map enabledFilters) {
+		StringBuffer buffer = new StringBuffer();
+		manyToManyFilterHelper.render( buffer, alias, enabledFilters );
+
+		if ( manyToManyWhereString != null ) {
+			buffer.append( " and " )
+					.append( StringHelper.replace( manyToManyWhereTemplate, Template.TEMPLATE, alias ) );
+		}
+
+		return buffer.toString();
+	}
+
+	public String[] toColumns(String alias, String propertyName)
+			throws QueryException {
+
+		if ( "index".equals( propertyName ) ) {
+			if ( isManyToMany() ) {
+				throw new QueryException( "index() function not supported for many-to-many association" );
+			}
+			return StringHelper.qualify( alias, indexColumnNames );
+		}
+
+		return elementPropertyMapping.toColumns( alias, propertyName );
+	}
+
+	public String[] toColumns(String propertyName)
+			throws QueryException {
+
+		if ( "index".equals( propertyName ) ) {
+			if ( isManyToMany() ) {
+				throw new QueryException( "index() function not supported for many-to-many association" );
+			}
+			return indexColumnNames;
+		}
+
+		return elementPropertyMapping.toColumns( propertyName );
+	}
+
+	public Type getType() {
+		return elementPropertyMapping.getType(); //==elementType ??
+	}
+
+	public String getName() {
+		return getRole();
+	}
+
+	public EntityPersister getElementPersister() {
+		if ( elementPersister == null ) {
+			throw new AssertionFailure( "not an association" );
+		}
+		return ( Loadable ) elementPersister;
+	}
+
+	public boolean isCollection() {
+		return true;
+	}
+
+	public Serializable[] getCollectionSpaces() {
+		return spaces;
+	}
+
+	protected abstract String generateDeleteString();
+
+	protected abstract String generateDeleteRowString();
+
+	protected abstract String generateUpdateRowString();
+
+	protected abstract String generateInsertRowString();
+
+	public void updateRows(PersistentCollection collection, Serializable id, SessionImplementor session) 
+	throws HibernateException {
+
+		if ( !isInverse && collection.isRowUpdatePossible() ) {
+
+			if ( log.isDebugEnabled() ) {
+				log.debug( "Updating rows of collection: " + role + "#" + id );
+			}
+
+			//update all the modified entries
+			int count = doUpdateRows( id, collection, session );
+
+			if ( log.isDebugEnabled() ) {
+				log.debug( "done updating rows: " + count + " updated" );
+			}
+		}
+	}
+
+	protected abstract int doUpdateRows(Serializable key, PersistentCollection collection, SessionImplementor session) 
+	throws HibernateException;
+
+	public CollectionMetadata getCollectionMetadata() {
+		return this;
+	}
+
+	public SessionFactoryImplementor getFactory() {
+		return factory;
+	}
+
+	protected String filterFragment(String alias) throws MappingException {
+		return hasWhere() ? " and " + getSQLWhereString( alias ) : "";
+	}
+
+	public String filterFragment(String alias, Map enabledFilters) throws MappingException {
+
+		StringBuffer sessionFilterFragment = new StringBuffer();
+		filterHelper.render( sessionFilterFragment, alias, enabledFilters );
+
+		return sessionFilterFragment.append( filterFragment( alias ) ).toString();
+	}
+
+	public String oneToManyFilterFragment(String alias) throws MappingException {
+		return "";
+	}
+
+	protected boolean isInsertCallable() {
+		return insertCallable;
+	}
+
+	protected ExecuteUpdateResultCheckStyle getInsertCheckStyle() {
+		return insertCheckStyle;
+	}
+
+	protected boolean isUpdateCallable() {
+		return updateCallable;
+	}
+
+	protected ExecuteUpdateResultCheckStyle getUpdateCheckStyle() {
+		return updateCheckStyle;
+	}
+
+	protected boolean isDeleteCallable() {
+		return deleteCallable;
+	}
+
+	protected ExecuteUpdateResultCheckStyle getDeleteCheckStyle() {
+		return deleteCheckStyle;
+	}
+
+	protected boolean isDeleteAllCallable() {
+		return deleteAllCallable;
+	}
+
+	protected ExecuteUpdateResultCheckStyle getDeleteAllCheckStyle() {
+		return deleteAllCheckStyle;
+	}
+
+	public String toString() {
+		return StringHelper.unqualify( getClass().getName() ) + '(' + role + ')';
+	}
+
+	public boolean isVersioned() {
+		return isVersioned && getOwnerEntityPersister().isVersioned();
+	}
+	
+	public String getNodeName() {
+		return nodeName;
+	}
+
+	public String getElementNodeName() {
+		return elementNodeName;
+	}
+
+	public String getIndexNodeName() {
+		return indexNodeName;
+	}
+
+	protected SQLExceptionConverter getSQLExceptionConverter() {
+		return sqlExceptionConverter;
+	}
+
+	public CacheEntryStructure getCacheEntryStructure() {
+		return cacheEntryStructure;
+	}
+
+	public boolean isAffectedByEnabledFilters(SessionImplementor session) {
+		return filterHelper.isAffectedBy( session.getEnabledFilters() ) ||
+		        ( isManyToMany() && manyToManyFilterHelper.isAffectedBy( session.getEnabledFilters() ) );
+	}
+
+	public boolean isSubselectLoadable() {
+		return subselectLoadable;
+	}
+	
+	public boolean isMutable() {
+		return isMutable;
+	}
+
+	public String[] getCollectionPropertyColumnAliases(String propertyName, String suffix) {
+		String rawAliases[] = (String[]) collectionPropertyColumnAliases.get(propertyName);
+
+		if ( rawAliases == null ) {
+			return null;
+		}
+		
+		String result[] = new String[rawAliases.length];
+		for ( int i=0; i<rawAliases.length; i++ ) {
+			result[i] = new Alias(suffix).toUnquotedAliasString( rawAliases[i] );
+		}
+		return result;
+	}
+	
+	//TODO: formulas ?
+	public void initCollectionPropertyMap() {
+
+		initCollectionPropertyMap( "key", keyType, keyColumnAliases, keyColumnNames );
+		initCollectionPropertyMap( "element", elementType, elementColumnAliases, elementColumnNames );
+		if (hasIndex) {
+			initCollectionPropertyMap( "index", indexType, indexColumnAliases, indexColumnNames );
+		}
+		if (hasIdentifier) {
+			initCollectionPropertyMap( 
+					"id", 
+					identifierType, 
+					new String[] { identifierColumnAlias }, 
+					new String[] { identifierColumnName } 
+				);
+		}
+	}
+
+	private void initCollectionPropertyMap(String aliasName, Type type, String[] columnAliases, String[] columnNames) {
+		
+		collectionPropertyColumnAliases.put(aliasName, columnAliases);
+		collectionPropertyColumnNames.put(aliasName, columnNames);
+	
+		if( type.isComponentType() ) {
+			AbstractComponentType ct = (AbstractComponentType) type;
+			String[] propertyNames = ct.getPropertyNames();
+			for (int i = 0; i < propertyNames.length; i++) {
+				String name = propertyNames[i];
+				collectionPropertyColumnAliases.put( aliasName + "." + name, columnAliases[i] );
+				collectionPropertyColumnNames.put( aliasName + "." + name, columnNames[i] );
+			}
+		} 
+		
+	}
+
+	public int getSize(Serializable key, SessionImplementor session) {
+		try {
+			PreparedStatement st = session.getBatcher().prepareSelectStatement(sqlSelectSizeString);
+			try {
+				getKeyType().nullSafeSet(st, key, 1, session);
+				ResultSet rs = st.executeQuery();
+				try {
+					return rs.next() ? rs.getInt(1) - baseIndex : 0;
+				}
+				finally {
+					rs.close();
+				}
+			}
+			finally {
+				session.getBatcher().closeStatement( st );
+			}
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not retrieve collection size: " + 
+					MessageHelper.collectionInfoString( this, key, getFactory() ),
+					sqlSelectSizeString
+				);
+		}
+	}
+	
+	public boolean indexExists(Serializable key, Object index, SessionImplementor session) {
+		return exists(key, incrementIndexByBase(index), getIndexType(), sqlDetectRowByIndexString, session);
+	}
+
+	public boolean elementExists(Serializable key, Object element, SessionImplementor session) {
+		return exists(key, element, getElementType(), sqlDetectRowByElementString, session);
+	}
+
+	private boolean exists(Serializable key, Object indexOrElement, Type indexOrElementType, String sql, SessionImplementor session) {
+		try {
+			PreparedStatement st = session.getBatcher().prepareSelectStatement(sql);
+			try {
+				getKeyType().nullSafeSet(st, key, 1, session);
+				indexOrElementType.nullSafeSet( st, indexOrElement, keyColumnNames.length + 1, session );
+				ResultSet rs = st.executeQuery();
+				try {
+					return rs.next();
+				}
+				finally {
+					rs.close();
+				}
+			}
+			catch( TransientObjectException e ) {
+				return false;
+			}
+			finally {
+				session.getBatcher().closeStatement( st );
+			}
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not check row existence: " + 
+					MessageHelper.collectionInfoString( this, key, getFactory() ),
+					sqlSelectSizeString
+				);
+		}
+	}
+
+	public Object getElementByIndex(Serializable key, Object index, SessionImplementor session, Object owner) {
+		try {
+			PreparedStatement st = session.getBatcher().prepareSelectStatement(sqlSelectRowByIndexString);
+			try {
+				getKeyType().nullSafeSet(st, key, 1, session);
+				getIndexType().nullSafeSet( st, incrementIndexByBase(index), keyColumnNames.length + 1, session );
+				ResultSet rs = st.executeQuery();
+				try {
+					if ( rs.next() ) {
+						return getElementType().nullSafeGet(rs, elementColumnAliases, session, owner);
+					}
+					else {
+						return null;
+					}
+				}
+				finally {
+					rs.close();
+				}
+			}
+			finally {
+				session.getBatcher().closeStatement( st );
+			}
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert(
+					getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not read row: " + 
+					MessageHelper.collectionInfoString( this, key, getFactory() ),
+					sqlSelectSizeString
+				);
+		}
+	}
+
+	public boolean isExtraLazy() {
+		return isExtraLazy;
+	}
+	
+	protected Dialect getDialect() {
+		return dialect;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,320 @@
+//$Id: BasicCollectionPersister.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.persister.collection;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Iterator;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.jdbc.Expectations;
+import org.hibernate.jdbc.Expectation;
+import org.hibernate.type.AssociationType;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.SubselectFetch;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.loader.collection.BatchingCollectionInitializer;
+import org.hibernate.loader.collection.CollectionInitializer;
+import org.hibernate.loader.collection.SubselectCollectionLoader;
+import org.hibernate.mapping.Collection;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.sql.Delete;
+import org.hibernate.sql.Insert;
+import org.hibernate.sql.Update;
+import org.hibernate.sql.SelectFragment;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * Collection persister for collections of values and many-to-many associations.
+ *
+ * @author Gavin King
+ */
+public class BasicCollectionPersister extends AbstractCollectionPersister {
+
+	public boolean isCascadeDeleteEnabled() {
+		return false;
+	}
+
+	public BasicCollectionPersister(
+			Collection collection,
+			CollectionRegionAccessStrategy cacheAccessStrategy,
+			Configuration cfg,
+			SessionFactoryImplementor factory) throws MappingException, CacheException {
+		super( collection, cacheAccessStrategy, cfg, factory );
+	}
+
+	/**
+	 * Generate the SQL DELETE that deletes all rows
+	 */
+	protected String generateDeleteString() {
+		
+		Delete delete = new Delete()
+				.setTableName( qualifiedTableName )
+				.setPrimaryKeyColumnNames( keyColumnNames );
+		
+		if ( hasWhere ) delete.setWhere( sqlWhereString );
+		
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			delete.setComment( "delete collection " + getRole() );
+		}
+		
+		return delete.toStatementString();
+	}
+
+	/**
+	 * Generate the SQL INSERT that creates a new row
+	 */
+	protected String generateInsertRowString() {
+		
+		Insert insert = new Insert( getDialect() )
+				.setTableName( qualifiedTableName )
+				.addColumns( keyColumnNames );
+		
+		if ( hasIdentifier) insert.addColumn( identifierColumnName );
+		
+		if ( hasIndex /*&& !indexIsFormula*/ ) {
+			insert.addColumns( indexColumnNames, indexColumnIsSettable );
+		}
+		
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			insert.setComment( "insert collection row " + getRole() );
+		}
+		
+		//if ( !elementIsFormula ) {
+			insert.addColumns( elementColumnNames, elementColumnIsSettable );
+		//}
+		
+		return insert.toStatementString();
+	}
+
+	/**
+	 * Generate the SQL UPDATE that updates a row
+	 */
+	protected String generateUpdateRowString() {
+		
+		Update update = new Update( getDialect() )
+			.setTableName( qualifiedTableName );
+		
+		//if ( !elementIsFormula ) {
+			update.addColumns( elementColumnNames, elementColumnIsSettable );
+		//}
+		
+		if ( hasIdentifier ) {
+			update.setPrimaryKeyColumnNames( new String[]{ identifierColumnName } );
+		}
+		else if ( hasIndex && !indexContainsFormula ) {
+			update.setPrimaryKeyColumnNames( ArrayHelper.join( keyColumnNames, indexColumnNames ) );
+		}
+		else {
+			update.setPrimaryKeyColumnNames( ArrayHelper.join( keyColumnNames, elementColumnNames, elementColumnIsInPrimaryKey ) );
+		}
+		
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			update.setComment( "update collection row " + getRole() );
+		}
+		
+		return update.toStatementString();
+	}
+
+	/**
+	 * Generate the SQL DELETE that deletes a particular row
+	 */
+	protected String generateDeleteRowString() {
+		
+		Delete delete = new Delete()
+			.setTableName( qualifiedTableName );
+		
+		if ( hasIdentifier ) {
+			delete.setPrimaryKeyColumnNames( new String[]{ identifierColumnName } );
+		}
+		else if ( hasIndex && !indexContainsFormula ) {
+			delete.setPrimaryKeyColumnNames( ArrayHelper.join( keyColumnNames, indexColumnNames ) );
+		}
+		else {
+			delete.setPrimaryKeyColumnNames( ArrayHelper.join( keyColumnNames, elementColumnNames, elementColumnIsInPrimaryKey ) );
+		}
+		
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			delete.setComment( "delete collection row " + getRole() );
+		}
+		
+		return delete.toStatementString();
+	}
+
+	public boolean consumesEntityAlias() {
+		return false;
+	}
+
+	public boolean consumesCollectionAlias() {
+//		return !isOneToMany();
+		return true;
+	}
+
+	public boolean isOneToMany() {
+		return false;
+	}
+
+	public boolean isManyToMany() {
+		return elementType.isEntityType(); //instanceof AssociationType;
+	}
+
+	protected int doUpdateRows(Serializable id, PersistentCollection collection, SessionImplementor session)
+			throws HibernateException {
+		
+		if ( ArrayHelper.isAllFalse(elementColumnIsSettable) ) return 0;
+
+		try {
+			PreparedStatement st = null;
+			Expectation expectation = Expectations.appropriateExpectation( getUpdateCheckStyle() );
+			boolean callable = isUpdateCallable();
+			boolean useBatch = expectation.canBeBatched();
+			Iterator entries = collection.entries( this );
+			String sql = getSQLUpdateRowString();
+			int i = 0;
+			int count = 0;
+			while ( entries.hasNext() ) {
+				Object entry = entries.next();
+				if ( collection.needsUpdating( entry, i, elementType ) ) {
+					int offset = 1;
+
+					if ( useBatch ) {
+						if ( st == null ) {
+							if ( callable ) {
+								st = session.getBatcher().prepareBatchCallableStatement( sql );
+							}
+							else {
+								st = session.getBatcher().prepareBatchStatement( sql );
+							}
+						}
+					}
+					else {
+						if ( callable ) {
+							st = session.getBatcher().prepareCallableStatement( sql );
+						}
+						else {
+							st = session.getBatcher().prepareStatement( sql );
+						}
+					}
+
+					try {
+						offset+= expectation.prepare( st );
+						int loc = writeElement( st, collection.getElement( entry ), offset, session );
+						if ( hasIdentifier ) {
+							writeIdentifier( st, collection.getIdentifier( entry, i ), loc, session );
+						}
+						else {
+							loc = writeKey( st, id, loc, session );
+							if ( hasIndex && !indexContainsFormula ) {
+								writeIndexToWhere( st, collection.getIndex( entry, i, this ), loc, session );
+							}
+							else {
+								writeElementToWhere( st, collection.getSnapshotElement( entry, i ), loc, session );
+							}
+						}
+
+						if ( useBatch ) {
+							session.getBatcher().addToBatch( expectation );
+						}
+						else {
+							expectation.verifyOutcome( st.executeUpdate(), st, -1 );
+						}
+					}
+					catch ( SQLException sqle ) {
+						if ( useBatch ) {
+							session.getBatcher().abortBatch( sqle );
+						}
+						throw sqle;
+					}
+					finally {
+						if ( !useBatch ) {
+							session.getBatcher().closeStatement( st );
+						}
+					}
+					count++;
+				}
+				i++;
+			}
+			return count;
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					getSQLExceptionConverter(),
+					sqle,
+					"could not update collection rows: " + MessageHelper.collectionInfoString( this, id, getFactory() ),
+					getSQLUpdateRowString()
+				);
+		}
+	}
+
+	public String selectFragment(
+	        Joinable rhs,
+	        String rhsAlias,
+	        String lhsAlias,
+	        String entitySuffix,
+	        String collectionSuffix,
+	        boolean includeCollectionColumns) {
+		// we need to determine the best way to know that two joinables
+		// represent a single many-to-many...
+		if ( rhs != null && isManyToMany() && !rhs.isCollection() ) {
+			AssociationType elementType = ( ( AssociationType ) getElementType() );
+			if ( rhs.equals( elementType.getAssociatedJoinable( getFactory() ) ) ) {
+				return manyToManySelectFragment( rhs, rhsAlias, lhsAlias, collectionSuffix );
+			}
+		}
+		return includeCollectionColumns ? selectFragment( lhsAlias, collectionSuffix ) : "";
+	}
+
+	private String manyToManySelectFragment(
+	        Joinable rhs,
+	        String rhsAlias,
+	        String lhsAlias,
+	        String collectionSuffix) {
+		SelectFragment frag = generateSelectFragment( lhsAlias, collectionSuffix );
+
+		String[] elementColumnNames = rhs.getKeyColumnNames();
+		frag.addColumns( rhsAlias, elementColumnNames, elementColumnAliases );
+		appendIndexColumns( frag, lhsAlias );
+		appendIdentifierColumns( frag, lhsAlias );
+
+		return frag.toFragmentString()
+				.substring( 2 ); //strip leading ','
+	}
+
+	/**
+	 * Create the <tt>CollectionLoader</tt>
+	 *
+	 * @see org.hibernate.loader.collection.BasicCollectionLoader
+	 */
+	protected CollectionInitializer createCollectionInitializer(java.util.Map enabledFilters)
+			throws MappingException {
+		return BatchingCollectionInitializer.createBatchingCollectionInitializer( this, batchSize, getFactory(), enabledFilters );
+	}
+
+	public String fromJoinFragment(String alias, boolean innerJoin, boolean includeSubclasses) {
+		return "";
+	}
+
+	public String whereJoinFragment(String alias, boolean innerJoin, boolean includeSubclasses) {
+		return "";
+	}
+
+	protected CollectionInitializer createSubselectInitializer(SubselectFetch subselect, SessionImplementor session) {
+		return new SubselectCollectionLoader( 
+				this,
+				subselect.toSubselectString( getCollectionType().getLHSPropertyName() ),
+				subselect.getResult(),
+				subselect.getQueryParameters(),
+				subselect.getNamedParameterLocMap(),
+				session.getFactory(),
+				session.getEnabledFilters() 
+			);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,288 @@
+//$Id: CollectionPersister.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.persister.collection;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cache.entry.CacheEntryStructure;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.metadata.CollectionMetadata;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.Type;
+
+/**
+ * A strategy for persisting a collection role. Defines a contract between
+ * the persistence strategy and the actual persistent collection framework
+ * and session. Does not define operations that are required for querying
+ * collections, or loading by outer join.<br>
+ * <br>
+ * Implements persistence of a collection instance while the instance is
+ * referenced in a particular role.<br>
+ * <br>
+ * This class is highly coupled to the <tt>PersistentCollection</tt>
+ * hierarchy, since double dispatch is used to load and update collection
+ * elements.<br>
+ * <br>
+ * May be considered an immutable view of the mapping object
+ *
+ * @see QueryableCollection
+ * @see PersistentCollection
+ * @author Gavin King
+ */
+public interface CollectionPersister {
+	/**
+	 * Initialize the given collection with the given key
+	 */
+	public void initialize(Serializable key, SessionImplementor session) //TODO: add owner argument!!
+	throws HibernateException;
+	/**
+	 * Is this collection role cacheable
+	 */
+	public boolean hasCache();
+	/**
+	 * Get the cache
+	 */
+	public CollectionRegionAccessStrategy getCacheAccessStrategy();
+	/**
+	 * Get the cache structure
+	 */
+	public CacheEntryStructure getCacheEntryStructure();
+	/**
+	 * Get the associated <tt>Type</tt>
+	 */
+	public CollectionType getCollectionType();
+	/**
+	 * Get the "key" type (the type of the foreign key)
+	 */
+	public Type getKeyType();
+	/**
+	 * Get the "index" type for a list or map (optional operation)
+	 */
+	public Type getIndexType();
+	/**
+	 * Get the "element" type
+	 */
+	public Type getElementType();
+	/**
+	 * Return the element class of an array, or null otherwise
+	 */
+	public Class getElementClass();
+	/**
+	 * Read the key from a row of the JDBC <tt>ResultSet</tt>
+	 */
+	public Object readKey(ResultSet rs, String[] keyAliases, SessionImplementor session)
+		throws HibernateException, SQLException;
+	/**
+	 * Read the element from a row of the JDBC <tt>ResultSet</tt>
+	 */
+	public Object readElement(
+		ResultSet rs,
+		Object owner,
+		String[] columnAliases,
+		SessionImplementor session)
+		throws HibernateException, SQLException;
+	/**
+	 * Read the index from a row of the JDBC <tt>ResultSet</tt>
+	 */
+	public Object readIndex(ResultSet rs, String[] columnAliases, SessionImplementor session)
+		throws HibernateException, SQLException;
+	/**
+	 * Read the identifier from a row of the JDBC <tt>ResultSet</tt>
+	 */
+	public Object readIdentifier(
+		ResultSet rs,
+		String columnAlias,
+		SessionImplementor session)
+		throws HibernateException, SQLException;
+	/**
+	 * Is this an array or primitive values?
+	 */
+	public boolean isPrimitiveArray();
+	/**
+	 * Is this an array?
+	 */
+	public boolean isArray();
+	/**
+	 * Is this a one-to-many association?
+	 */
+	public boolean isOneToMany();
+	/**
+	 * Is this a many-to-many association?  Note that this is mainly
+	 * a convenience feature as the single persister does not
+	 * conatin all the information needed to handle a many-to-many
+	 * itself, as internally it is looked at as two many-to-ones.
+	 */
+	public boolean isManyToMany();
+
+	public String getManyToManyFilterFragment(String alias, Map enabledFilters);
+
+	/**
+	 * Is this an "indexed" collection? (list or map)
+	 */
+	public boolean hasIndex();
+	/**
+	 * Is this collection lazyily initialized?
+	 */
+	public boolean isLazy();
+	/**
+	 * Is this collection "inverse", so state changes are not
+	 * propogated to the database.
+	 */
+	public boolean isInverse();
+	/**
+	 * Completely remove the persistent state of the collection
+	 */
+	public void remove(Serializable id, SessionImplementor session)
+		throws HibernateException;
+	/**
+	 * (Re)create the collection's persistent state
+	 */
+	public void recreate(
+		PersistentCollection collection,
+		Serializable key,
+		SessionImplementor session)
+		throws HibernateException;
+	/**
+	 * Delete the persistent state of any elements that were removed from
+	 * the collection
+	 */
+	public void deleteRows(
+		PersistentCollection collection,
+		Serializable key,
+		SessionImplementor session)
+		throws HibernateException;
+	/**
+	 * Update the persistent state of any elements that were modified
+	 */
+	public void updateRows(
+		PersistentCollection collection,
+		Serializable key,
+		SessionImplementor session)
+		throws HibernateException;
+	/**
+	 * Insert the persistent state of any new collection elements
+	 */
+	public void insertRows(
+		PersistentCollection collection,
+		Serializable key,
+		SessionImplementor session)
+		throws HibernateException;
+	/**
+	 * Get the name of this collection role (the fully qualified class name,
+	 * extended by a "property path")
+	 */
+	public String getRole();
+	/**
+	 * Get the persister of the entity that "owns" this collection
+	 */
+	public EntityPersister getOwnerEntityPersister();
+	/**
+	 * Get the surrogate key generation strategy (optional operation)
+	 */
+	public IdentifierGenerator getIdentifierGenerator();
+	/**
+	 * Get the type of the surrogate key
+	 */
+	public Type getIdentifierType();
+	/**
+	 * Does this collection implement "orphan delete"?
+	 */
+	public boolean hasOrphanDelete();
+	/**
+	 * Is this an ordered collection? (An ordered collection is
+	 * ordered by the initialization operation, not by sorting
+	 * that happens in memory, as in the case of a sorted collection.)
+	 */
+	public boolean hasOrdering();
+
+	public boolean hasManyToManyOrdering();
+
+	/**
+	 * Get the "space" that holds the persistent state
+	 */
+	public Serializable[] getCollectionSpaces();
+
+	public CollectionMetadata getCollectionMetadata();
+
+	/**
+	 * Is cascade delete handled by the database-level
+	 * foreign key constraint definition?
+	 */
+	public abstract boolean isCascadeDeleteEnabled();
+	
+	/**
+	 * Does this collection cause version increment of the 
+	 * owning entity?
+	 */
+	public boolean isVersioned();
+	
+	/**
+	 * Can the elements of this collection change?
+	 */
+	public boolean isMutable();
+	
+	//public boolean isSubselectLoadable();
+	
+	public String getNodeName();
+	
+	public String getElementNodeName();
+	
+	public String getIndexNodeName();
+
+	public void postInstantiate() throws MappingException;
+	
+	public SessionFactoryImplementor getFactory();
+
+	public boolean isAffectedByEnabledFilters(SessionImplementor session);
+
+	/**
+	 * Generates the collection's key column aliases, based on the given
+	 * suffix.
+	 *
+	 * @param suffix The suffix to use in the key column alias generation.
+	 * @return The key column aliases.
+	 */
+	public String[] getKeyColumnAliases(String suffix);
+
+	/**
+	 * Generates the collection's index column aliases, based on the given
+	 * suffix.
+	 *
+	 * @param suffix The suffix to use in the index column alias generation.
+	 * @return The key column aliases, or null if not indexed.
+	 */
+	public String[] getIndexColumnAliases(String suffix);
+
+	/**
+	 * Generates the collection's element column aliases, based on the given
+	 * suffix.
+	 *
+	 * @param suffix The suffix to use in the element column alias generation.
+	 * @return The key column aliases.
+	 */
+	public String[] getElementColumnAliases(String suffix);
+
+	/**
+	 * Generates the collection's identifier column aliases, based on the given
+	 * suffix.
+	 *
+	 * @param suffix The suffix to use in the key column alias generation.
+	 * @return The key column aliases.
+	 */
+	public String getIdentifierColumnAlias(String suffix);
+	
+	public boolean isExtraLazy();
+	public int getSize(Serializable key, SessionImplementor session);
+	public boolean indexExists(Serializable key, Object index, SessionImplementor session);
+	public boolean elementExists(Serializable key, Object element, SessionImplementor session);
+	public Object getElementByIndex(Serializable key, Object index, SessionImplementor session, Object owner);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CollectionPropertyMapping.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CollectionPropertyMapping.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CollectionPropertyMapping.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,100 @@
+package org.hibernate.persister.collection;
+
+import org.hibernate.Hibernate;
+import org.hibernate.QueryException;
+import org.hibernate.persister.entity.PropertyMapping;
+import org.hibernate.type.Type;
+
+/**
+ * @author Gavin King
+ */
+public class CollectionPropertyMapping implements PropertyMapping {
+
+	private final QueryableCollection memberPersister;
+
+	public CollectionPropertyMapping(QueryableCollection memberPersister) {
+		this.memberPersister = memberPersister;
+	}
+
+	public Type toType(String propertyName) throws QueryException {
+		if ( propertyName.equals(CollectionPropertyNames.COLLECTION_ELEMENTS) ) {
+			return memberPersister.getElementType();
+		}
+		else if ( propertyName.equals(CollectionPropertyNames.COLLECTION_INDICES) ) {
+			if ( !memberPersister.hasIndex() ) throw new QueryException("unindexed collection before indices()");
+			return memberPersister.getIndexType();
+		}
+		else if ( propertyName.equals(CollectionPropertyNames.COLLECTION_SIZE) ) {
+			return Hibernate.INTEGER;
+		}
+		else if ( propertyName.equals(CollectionPropertyNames.COLLECTION_MAX_INDEX) ) {
+			return memberPersister.getIndexType();
+		}
+		else if ( propertyName.equals(CollectionPropertyNames.COLLECTION_MIN_INDEX) ) {
+			return memberPersister.getIndexType();
+		}
+		else if ( propertyName.equals(CollectionPropertyNames.COLLECTION_MAX_ELEMENT) ) {
+			return memberPersister.getElementType();
+		}
+		else if ( propertyName.equals(CollectionPropertyNames.COLLECTION_MIN_ELEMENT) ) {
+			return memberPersister.getElementType();
+		}
+		else {
+			//return memberPersister.getPropertyType(propertyName);
+			throw new QueryException("illegal syntax near collection: " + propertyName);
+		}
+	}
+
+	public String[] toColumns(String alias, String propertyName) throws QueryException {
+		if ( propertyName.equals(CollectionPropertyNames.COLLECTION_ELEMENTS) ) {
+			return memberPersister.getElementColumnNames(alias);
+		}
+		else if ( propertyName.equals(CollectionPropertyNames.COLLECTION_INDICES) ) {
+			if ( !memberPersister.hasIndex() ) throw new QueryException("unindexed collection in indices()");
+			return memberPersister.getIndexColumnNames(alias);
+		}
+		else if ( propertyName.equals(CollectionPropertyNames.COLLECTION_SIZE) ) {
+			String[] cols = memberPersister.getKeyColumnNames();
+			return new String[] { "count(" + alias + '.' + cols[0] + ')' };
+		}
+		else if ( propertyName.equals(CollectionPropertyNames.COLLECTION_MAX_INDEX) ) {
+			if ( !memberPersister.hasIndex() ) throw new QueryException("unindexed collection in maxIndex()");
+			String[] cols = memberPersister.getIndexColumnNames(alias);
+			if ( cols.length!=1 ) throw new QueryException("composite collection index in maxIndex()");
+			return new String[] { "max(" + cols[0] + ')' };
+		}
+		else if ( propertyName.equals(CollectionPropertyNames.COLLECTION_MIN_INDEX) ) {
+			if ( !memberPersister.hasIndex() ) throw new QueryException("unindexed collection in minIndex()");
+			String[] cols = memberPersister.getIndexColumnNames(alias);
+			if ( cols.length!=1 ) throw new QueryException("composite collection index in minIndex()");
+			return new String[] { "min(" + cols[0] + ')' };
+		}
+		else if ( propertyName.equals(CollectionPropertyNames.COLLECTION_MAX_ELEMENT) ) {
+			String[] cols = memberPersister.getElementColumnNames(alias);
+			if ( cols.length!=1 ) throw new QueryException("composite collection element in maxElement()");
+			return new String[] { "max(" + cols[0] + ')' };
+		}
+		else if ( propertyName.equals(CollectionPropertyNames.COLLECTION_MIN_ELEMENT) ) {
+			String[] cols = memberPersister.getElementColumnNames(alias);
+			if ( cols.length!=1 ) throw new QueryException("composite collection element in minElement()");
+			return new String[] { "min(" + cols[0] + ')' };
+		}
+		else {
+			//return memberPersister.toColumns(alias, propertyName);
+			throw new QueryException("illegal syntax near collection: " + propertyName);
+		}
+	}
+
+	/**
+	 * Given a property path, return the corresponding column name(s).
+	 */
+	public String[] toColumns(String propertyName) throws QueryException, UnsupportedOperationException {
+		throw new UnsupportedOperationException( "References to collections must be define a SQL alias" );
+	}
+
+	public Type getType() {
+		//return memberPersister.getType();
+		return memberPersister.getCollectionType();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CollectionPropertyNames.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CollectionPropertyNames.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CollectionPropertyNames.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+// $Id: CollectionPropertyNames.java 5699 2005-02-13 11:50:11Z oneovthafew $
+package org.hibernate.persister.collection;
+
+/**
+ * The names of all the collection properties.
+ *
+ * @author josh Dec 23, 2004 7:35:02 AM
+ */
+public class CollectionPropertyNames {
+
+	public static final String COLLECTION_SIZE = "size";
+	public static final String COLLECTION_ELEMENTS = "elements";
+	public static final String COLLECTION_INDICES = "indices";
+	public static final String COLLECTION_MAX_INDEX = "maxIndex";
+	public static final String COLLECTION_MIN_INDEX = "minIndex";
+	public static final String COLLECTION_MAX_ELEMENT = "maxElement";
+	public static final String COLLECTION_MIN_ELEMENT = "minElement";
+	public static final String COLLECTION_INDEX = "index";
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CompositeElementPropertyMapping.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CompositeElementPropertyMapping.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/CompositeElementPropertyMapping.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: CompositeElementPropertyMapping.java 6136 2005-03-21 18:15:29Z oneovthafew $
+package org.hibernate.persister.collection;
+
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.persister.entity.AbstractPropertyMapping;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.Type;
+
+/**
+ * @author Gavin King
+ */
+public class CompositeElementPropertyMapping extends AbstractPropertyMapping {
+
+	private final AbstractComponentType compositeType;
+	
+	public CompositeElementPropertyMapping(
+			String[] elementColumns, 
+			String[] elementFormulaTemplates, 
+			AbstractComponentType compositeType, 
+			Mapping factory)
+	throws MappingException {
+
+		this.compositeType = compositeType;
+
+		initComponentPropertyPaths(null, compositeType, elementColumns, elementFormulaTemplates, factory);
+
+	}
+
+	public Type getType() {
+		return compositeType;
+	}
+
+	protected String getEntityName() {
+		return compositeType.getName();
+	}
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/ElementPropertyMapping.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/ElementPropertyMapping.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/ElementPropertyMapping.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+//$Id: ElementPropertyMapping.java 6179 2005-03-23 15:41:48Z steveebersole $
+package org.hibernate.persister.collection;
+
+import org.hibernate.MappingException;
+
+import org.hibernate.QueryException;
+
+import org.hibernate.persister.entity.PropertyMapping;
+
+import org.hibernate.type.Type;
+
+import org.hibernate.util.StringHelper;
+
+/**
+ * @author Gavin King
+ */
+public class ElementPropertyMapping implements PropertyMapping {
+
+	private final String[] elementColumns;
+	private final Type type;
+
+	public ElementPropertyMapping(String[] elementColumns, Type type)
+	throws MappingException {
+		this.elementColumns = elementColumns;
+		this.type = type;
+	}
+
+	public Type toType(String propertyName) throws QueryException {
+		if ( propertyName==null || "id".equals(propertyName) ) {
+			return type;
+		}
+		else {
+			throw new QueryException("cannot dereference scalar collection element: " + propertyName);
+		}
+	}
+
+	public String[] toColumns(String alias, String propertyName) throws QueryException {
+		if (propertyName==null || "id".equals(propertyName) ) {
+			return StringHelper.qualify(alias, elementColumns);
+		}
+		else {
+			throw new QueryException("cannot dereference scalar collection element: " + propertyName);
+		}
+	}
+
+	/**
+	 * Given a property path, return the corresponding column name(s).
+	 */
+	public String[] toColumns(String propertyName) throws QueryException, UnsupportedOperationException {
+		throw new UnsupportedOperationException( "References to collections must be define a SQL alias" );
+	}
+
+	public Type getType() {
+		return type;
+	}
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/NamedQueryCollectionInitializer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/NamedQueryCollectionInitializer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/NamedQueryCollectionInitializer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,59 @@
+//$Id: NamedQueryCollectionInitializer.java 10019 2006-06-15 07:50:12Z steve.ebersole at jboss.com $
+package org.hibernate.persister.collection;
+
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.impl.AbstractQueryImpl;
+import org.hibernate.loader.collection.CollectionInitializer;
+
+/**
+ * A wrapper around a named query.
+ * @author Gavin King
+ */
+public final class NamedQueryCollectionInitializer implements CollectionInitializer {
+	private final String queryName;
+	private final CollectionPersister persister;
+	
+	private static final Log log = LogFactory.getLog(NamedQueryCollectionInitializer.class);
+
+	public NamedQueryCollectionInitializer(String queryName, CollectionPersister persister) {
+		super();
+		this.queryName = queryName;
+		this.persister = persister;
+	}
+
+	public void initialize(Serializable key, SessionImplementor session) 
+	throws HibernateException {
+		
+		if ( log.isDebugEnabled() ) {
+			log.debug(
+					"initializing collection: " + 
+					persister.getRole() + 
+					" using named query: " + 
+					queryName 
+				);
+		}
+		
+		//TODO: is there a more elegant way than downcasting?
+		AbstractQueryImpl query = (AbstractQueryImpl) session.getNamedSQLQuery(queryName); 
+		if ( query.getNamedParameters().length>0 ) {
+			query.setParameter( 
+					query.getNamedParameters()[0], 
+					key, 
+					persister.getKeyType() 
+				);
+		}
+		else {
+			query.setParameter( 0, key, persister.getKeyType() );
+		}
+		query.setCollectionKey( key )
+				.setFlushMode( FlushMode.MANUAL )
+				.list();
+
+	}
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/NamedQueryCollectionInitializer.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,364 @@
+//$Id: OneToManyPersister.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.persister.collection;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Iterator;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.jdbc.Expectation;
+import org.hibernate.jdbc.Expectations;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.SubselectFetch;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.loader.collection.BatchingCollectionInitializer;
+import org.hibernate.loader.collection.CollectionInitializer;
+import org.hibernate.loader.collection.SubselectOneToManyLoader;
+import org.hibernate.loader.entity.CollectionElementLoader;
+import org.hibernate.mapping.Collection;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.persister.entity.OuterJoinLoadable;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.sql.Update;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * Collection persister for one-to-many associations.
+ *
+ * @author Gavin King
+ */
+public class OneToManyPersister extends AbstractCollectionPersister {
+
+	private final boolean cascadeDeleteEnabled;
+	private final boolean keyIsNullable;
+	private final boolean keyIsUpdateable;
+
+	protected boolean isRowDeleteEnabled() {
+		return keyIsUpdateable && keyIsNullable;
+	}
+
+	protected boolean isRowInsertEnabled() {
+		return keyIsUpdateable;
+	}
+
+	public boolean isCascadeDeleteEnabled() {
+		return cascadeDeleteEnabled;
+	}
+
+	public OneToManyPersister(
+			Collection collection,
+			CollectionRegionAccessStrategy cacheAccessStrategy,
+			Configuration cfg,
+			SessionFactoryImplementor factory) throws MappingException, CacheException {
+		super( collection, cacheAccessStrategy, cfg, factory );
+		cascadeDeleteEnabled = collection.getKey().isCascadeDeleteEnabled() &&
+				factory.getDialect().supportsCascadeDelete();
+		keyIsNullable = collection.getKey().isNullable();
+		keyIsUpdateable = collection.getKey().isUpdateable();
+	}
+
+	/**
+	 * Generate the SQL UPDATE that updates all the foreign keys to null
+	 */
+	protected String generateDeleteString() {
+		
+		Update update = new Update( getDialect() )
+				.setTableName( qualifiedTableName )
+				.addColumns( keyColumnNames, "null" )
+				.setPrimaryKeyColumnNames( keyColumnNames );
+		
+		if ( hasIndex && !indexContainsFormula ) update.addColumns( indexColumnNames, "null" );
+		
+		if ( hasWhere ) update.setWhere( sqlWhereString );
+		
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			update.setComment( "delete one-to-many " + getRole() );
+		}
+		
+		return update.toStatementString();
+	}
+
+	/**
+	 * Generate the SQL UPDATE that updates a foreign key to a value
+	 */
+	protected String generateInsertRowString() {
+		
+		Update update = new Update( getDialect() )
+				.setTableName( qualifiedTableName )
+				.addColumns( keyColumnNames );
+		
+		if ( hasIndex && !indexContainsFormula ) update.addColumns( indexColumnNames );
+		
+		//identifier collections not supported for 1-to-many
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			update.setComment( "create one-to-many row " + getRole() );
+		}
+		
+		return update.setPrimaryKeyColumnNames( elementColumnNames )
+				.toStatementString();
+	}
+
+	/**
+	 * Not needed for one-to-many association
+	 */
+	protected String generateUpdateRowString() {
+		return null;
+	}
+
+	/**
+	 * Generate the SQL UPDATE that updates a particular row's foreign
+	 * key to null
+	 */
+	protected String generateDeleteRowString() {
+		
+		Update update = new Update( getDialect() )
+				.setTableName( qualifiedTableName )
+				.addColumns( keyColumnNames, "null" );
+		
+		if ( hasIndex && !indexContainsFormula ) update.addColumns( indexColumnNames, "null" );
+		
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			update.setComment( "delete one-to-many row " + getRole() );
+		}
+		
+		//use a combination of foreign key columns and pk columns, since
+		//the ordering of removal and addition is not guaranteed when
+		//a child moves from one parent to another
+		String[] rowSelectColumnNames = ArrayHelper.join(keyColumnNames, elementColumnNames);
+		return update.setPrimaryKeyColumnNames( rowSelectColumnNames )
+				.toStatementString();
+	}
+
+	public boolean consumesEntityAlias() {
+		return true;
+	}
+	public boolean consumesCollectionAlias() {
+		return true;
+	}
+
+	public boolean isOneToMany() {
+		return true;
+	}
+
+	public boolean isManyToMany() {
+		return false;
+	}
+
+	protected int doUpdateRows(Serializable id, PersistentCollection collection, SessionImplementor session)
+			throws HibernateException {
+
+		// we finish all the "removes" first to take care of possible unique
+		// constraints and so that we can take better advantage of batching
+		
+		try {
+			int count = 0;
+			if ( isRowDeleteEnabled() ) {
+				boolean useBatch = true;
+				PreparedStatement st = null;
+				// update removed rows fks to null
+				try {
+					int i = 0;
+	
+					Iterator entries = collection.entries( this );
+					int offset = 1;
+					Expectation expectation = Expectations.NONE;
+					while ( entries.hasNext() ) {
+	
+						Object entry = entries.next();
+						if ( collection.needsUpdating( entry, i, elementType ) ) {  // will still be issued when it used to be null
+							if ( st == null ) {
+								String sql = getSQLDeleteRowString();
+								if ( isDeleteCallable() ) {
+									expectation = Expectations.appropriateExpectation( getDeleteCheckStyle() );
+									useBatch = expectation.canBeBatched();
+									st = useBatch
+											? session.getBatcher().prepareBatchCallableStatement( sql )
+								            : session.getBatcher().prepareCallableStatement( sql );
+									offset += expectation.prepare( st );
+								}
+								else {
+									st = session.getBatcher().prepareBatchStatement( getSQLDeleteRowString() );
+								}
+							}
+							int loc = writeKey( st, id, offset, session );
+							writeElementToWhere( st, collection.getSnapshotElement(entry, i), loc, session );
+							if ( useBatch ) {
+								session.getBatcher().addToBatch( expectation );
+							}
+							else {
+								expectation.verifyOutcome( st.executeUpdate(), st, -1 );
+							}
+							count++;
+						}
+						i++;
+					}
+				}
+				catch ( SQLException sqle ) {
+					if ( useBatch ) {
+						session.getBatcher().abortBatch( sqle );
+					}
+					throw sqle;
+				}
+				finally {
+					if ( !useBatch ) {
+						session.getBatcher().closeStatement( st );
+					}
+				}
+			}
+			
+			if ( isRowInsertEnabled() ) {
+				Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() );
+				boolean callable = isInsertCallable();
+				boolean useBatch = expectation.canBeBatched();
+				String sql = getSQLInsertRowString();
+				PreparedStatement st = null;
+				// now update all changed or added rows fks
+				try {
+					int i = 0;
+					Iterator entries = collection.entries( this );
+					while ( entries.hasNext() ) {
+						Object entry = entries.next();
+						int offset = 1;
+						if ( collection.needsUpdating( entry, i, elementType ) ) {
+							if ( useBatch ) {
+								if ( st == null ) {
+									if ( callable ) {
+										st = session.getBatcher().prepareBatchCallableStatement( sql );
+									}
+									else {
+										st = session.getBatcher().prepareBatchStatement( sql );
+									}
+								}
+							}
+							else {
+								if ( callable ) {
+									st = session.getBatcher().prepareCallableStatement( sql );
+								}
+								else {
+									st = session.getBatcher().prepareStatement( sql );
+								}
+							}
+
+							offset += expectation.prepare( st );
+
+							int loc = writeKey( st, id, offset, session );
+							if ( hasIndex && !indexContainsFormula ) {
+								loc = writeIndexToWhere( st, collection.getIndex( entry, i, this ), loc, session );
+							}
+
+							writeElementToWhere( st, collection.getElement( entry ), loc, session );
+
+							if ( useBatch ) {
+								session.getBatcher().addToBatch( expectation );
+							}
+							else {
+								expectation.verifyOutcome( st.executeUpdate(), st, -1 );
+							}
+							count++;
+						}
+						i++;
+					}
+				}
+				catch ( SQLException sqle ) {
+					if ( useBatch ) {
+						session.getBatcher().abortBatch( sqle );
+					}
+					throw sqle;
+				}
+				finally {
+					if ( !useBatch ) {
+						session.getBatcher().closeStatement( st );
+					}
+				}
+			}
+
+			return count;
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					getSQLExceptionConverter(),
+					sqle,
+					"could not update collection rows: " + 
+					MessageHelper.collectionInfoString( this, id, getFactory() ),
+					getSQLInsertRowString()
+			);
+		}
+	}
+
+	public String selectFragment(
+	        Joinable rhs,
+	        String rhsAlias,
+	        String lhsAlias,
+	        String entitySuffix,
+	        String collectionSuffix,
+	        boolean includeCollectionColumns) {
+		StringBuffer buf = new StringBuffer();
+		if ( includeCollectionColumns ) {
+//			buf.append( selectFragment( lhsAlias, "" ) )//ignore suffix for collection columns!
+			buf.append( selectFragment( lhsAlias, collectionSuffix ) )
+					.append( ", " );
+		}
+		OuterJoinLoadable ojl = ( OuterJoinLoadable ) getElementPersister();
+		return buf.append( ojl.selectFragment( lhsAlias, entitySuffix ) )//use suffix for the entity columns
+				.toString();
+	}
+
+	/**
+	 * Create the <tt>OneToManyLoader</tt>
+	 *
+	 * @see org.hibernate.loader.collection.OneToManyLoader
+	 */
+	protected CollectionInitializer createCollectionInitializer(java.util.Map enabledFilters) throws MappingException {
+		return BatchingCollectionInitializer.createBatchingOneToManyInitializer( this, batchSize, getFactory(), enabledFilters );
+	}
+
+	public String fromJoinFragment(String alias,
+								   boolean innerJoin,
+								   boolean includeSubclasses) {
+		return ( ( Joinable ) getElementPersister() ).fromJoinFragment( alias, innerJoin, includeSubclasses );
+	}
+
+	public String whereJoinFragment(String alias,
+									boolean innerJoin,
+									boolean includeSubclasses) {
+		return ( ( Joinable ) getElementPersister() ).whereJoinFragment( alias, innerJoin, includeSubclasses );
+	}
+
+	public String getTableName() {
+		return ( ( Joinable ) getElementPersister() ).getTableName();
+	}
+
+	public String filterFragment(String alias) throws MappingException {
+		String result = super.filterFragment( alias );
+		if ( getElementPersister() instanceof Joinable ) {
+			result += ( ( Joinable ) getElementPersister() ).oneToManyFilterFragment( alias );
+		}
+		return result;
+
+	}
+
+	protected CollectionInitializer createSubselectInitializer(SubselectFetch subselect, SessionImplementor session) {
+		return new SubselectOneToManyLoader( 
+				this,
+				subselect.toSubselectString( getCollectionType().getLHSPropertyName() ),
+				subselect.getResult(),
+				subselect.getQueryParameters(),
+				subselect.getNamedParameterLocMap(),
+				session.getFactory(),
+				session.getEnabledFilters() 
+			);
+	}
+
+	public Object getElementByIndex(Serializable key, Object index, SessionImplementor session, Object owner) {
+		return new CollectionElementLoader( this, getFactory(), session.getEnabledFilters() )
+				.loadElement( session, key, incrementIndexByBase(index) );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/QueryableCollection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/QueryableCollection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/QueryableCollection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,74 @@
+//$Id: QueryableCollection.java 9875 2006-05-04 16:23:44Z steve.ebersole at jboss.com $
+package org.hibernate.persister.collection;
+
+import org.hibernate.FetchMode;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.persister.entity.PropertyMapping;
+
+/**
+ * A collection role that may be queried or loaded by outer join.
+ * @author Gavin King
+ */
+public interface QueryableCollection extends PropertyMapping, Joinable, CollectionPersister {
+	/**
+	 * Generate a list of collection index and element columns
+	 */
+	public abstract String selectFragment(String alias, String columnSuffix);
+	/**
+	 * Get the names of the collection index columns if
+	 * this is an indexed collection (optional operation)
+	 */
+	public abstract String[] getIndexColumnNames();
+	/**
+	 * Get the index formulas if this is an indexed collection 
+	 * (optional operation)
+	 */
+	public abstract String[] getIndexFormulas();
+	/**
+	 * Get the names of the collection index columns if
+	 * this is an indexed collection (optional operation),
+	 * aliased by the given table alias
+	 */
+	public abstract String[] getIndexColumnNames(String alias);
+	/**
+	 * Get the names of the collection element columns (or the primary
+	 * key columns in the case of a one-to-many association),
+	 * aliased by the given table alias
+	 */
+	public abstract String[] getElementColumnNames(String alias);
+	/**
+	 * Get the names of the collection element columns (or the primary
+	 * key columns in the case of a one-to-many association)
+	 */
+	public abstract String[] getElementColumnNames();
+	/**
+	 * Get the order by SQL
+	 */
+	public abstract String getSQLOrderByString(String alias);
+
+	/**
+	 * Get the order-by to be applied at the target table of a many to many
+	 *
+	 * @param alias The alias for the many-to-many target table
+	 * @return appropriate order-by fragment or empty string.
+	 */
+	public abstract String getManyToManyOrderByString(String alias);
+
+	/**
+	 * Does this collection role have a where clause filter?
+	 */
+	public abstract boolean hasWhere();
+	/**
+	 * Get the persister of the element class, if this is a
+	 * collection of entities (optional operation).  Note that
+	 * for a one-to-many association, the returned persister
+	 * must be <tt>OuterJoinLoadable</tt>.
+	 */
+	public abstract EntityPersister getElementPersister();
+	/**
+	 * Should we load this collection role by outerjoining?
+	 */
+	public abstract FetchMode getFetchMode();
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/SQLLoadableCollection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/SQLLoadableCollection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/SQLLoadableCollection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+package org.hibernate.persister.collection;
+
+public interface SQLLoadableCollection extends QueryableCollection {
+
+	public abstract String[] getCollectionPropertyColumnAliases(String propertyName, String string);
+	
+	public abstract String getIdentifierColumnName();
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package abstracts the persistence mechanism for collections.
+</p>
+<p>
+	Concrete implementations of <tt>CollectionPersister</tt>
+	define strategies for persistence of particular collection
+	roles. Collection persisters may optionally implement 
+	<tt>QueryableCollection</tt> if they should be queryable
+	using HQL or loaded using <tt>OuterJoinLoader</tt>.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/collection/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,3839 @@
+//$Id: AbstractEntityPersister.java 11527 2007-05-15 20:16:50Z epbernard $
+package org.hibernate.persister.entity;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.Comparator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.EntityMode;
+import org.hibernate.FetchMode;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.StaleStateException;
+import org.hibernate.jdbc.Expectation;
+import org.hibernate.jdbc.Expectations;
+import org.hibernate.jdbc.TooManyRowsAffectedException;
+import org.hibernate.dialect.lock.LockingStrategy;
+import org.hibernate.cache.CacheConcurrencyStrategy;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cache.entry.CacheEntry;
+import org.hibernate.cache.entry.CacheEntryStructure;
+import org.hibernate.cache.entry.StructuredCacheEntry;
+import org.hibernate.cache.entry.UnstructuredCacheEntry;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.CascadingAction;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.Versioning;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.ValueInclusion;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.id.PostInsertIdentifierGenerator;
+import org.hibernate.id.PostInsertIdentityPersister;
+import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
+import org.hibernate.id.insert.Binder;
+import org.hibernate.intercept.LazyPropertyInitializer;
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.intercept.FieldInterceptor;
+import org.hibernate.loader.entity.BatchingEntityLoader;
+import org.hibernate.loader.entity.CascadeEntityLoader;
+import org.hibernate.loader.entity.EntityLoader;
+import org.hibernate.loader.entity.UniqueEntityLoader;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.Selectable;
+import org.hibernate.metadata.ClassMetadata;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.property.BackrefPropertyAccessor;
+import org.hibernate.sql.Alias;
+import org.hibernate.sql.Delete;
+import org.hibernate.sql.Insert;
+import org.hibernate.sql.JoinFragment;
+import org.hibernate.sql.Select;
+import org.hibernate.sql.SelectFragment;
+import org.hibernate.sql.SimpleSelect;
+import org.hibernate.sql.Template;
+import org.hibernate.sql.Update;
+import org.hibernate.tuple.entity.EntityMetamodel;
+import org.hibernate.tuple.entity.EntityTuplizer;
+import org.hibernate.tuple.Tuplizer;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.type.VersionType;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.CollectionHelper;
+import org.hibernate.util.FilterHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Basic functionality for persisting an entity via JDBC
+ * through either generated or custom SQL
+ *
+ * @author Gavin King
+ */
+public abstract class AbstractEntityPersister
+		implements OuterJoinLoadable, Queryable, ClassMetadata, UniqueKeyLoadable,
+		SQLLoadable, LazyPropertyInitializer, PostInsertIdentityPersister, Lockable {
+
+	private static final Log log = LogFactory.getLog( AbstractEntityPersister.class );
+
+	public static final String ENTITY_CLASS = "class";
+
+	// moved up from AbstractEntityPersister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	private final SessionFactoryImplementor factory;
+	private final EntityRegionAccessStrategy cacheAccessStrategy;
+	private final boolean isLazyPropertiesCacheable;
+	private final CacheEntryStructure cacheEntryStructure;
+	private final EntityMetamodel entityMetamodel;
+	private final Map entityNameBySubclass = new HashMap();
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	private final String[] rootTableKeyColumnNames;
+	private final String[] identifierAliases;
+	private final int identifierColumnSpan;
+	private final String versionColumnName;
+	private final boolean hasFormulaProperties;
+	private final int batchSize;
+	private final boolean hasSubselectLoadableCollections;
+	protected final String rowIdName;
+
+	private final Set lazyProperties;
+
+	// The optional SQL string defined in the where attribute
+	private final String sqlWhereString;
+	private final String sqlWhereStringTemplate;
+
+	//information about properties of this class,
+	//including inherited properties
+	//(only really needed for updatable/insertable properties)
+	private final int[] propertyColumnSpans;
+	private final String[] propertySubclassNames;
+	private final String[][] propertyColumnAliases;
+	private final String[][] propertyColumnNames;
+	private final String[][] propertyColumnFormulaTemplates;
+	private final boolean[][] propertyColumnUpdateable;
+	private final boolean[][] propertyColumnInsertable;
+	private final boolean[] propertyUniqueness;
+	private final boolean[] propertySelectable;
+
+	//information about lazy properties of this class
+	private final String[] lazyPropertyNames;
+	private final int[] lazyPropertyNumbers;
+	private final Type[] lazyPropertyTypes;
+	private final String[][] lazyPropertyColumnAliases;
+
+	//information about all properties in class hierarchy
+	private final String[] subclassPropertyNameClosure;
+	private final String[] subclassPropertySubclassNameClosure;
+	private final Type[] subclassPropertyTypeClosure;
+	private final String[][] subclassPropertyFormulaTemplateClosure;
+	private final String[][] subclassPropertyColumnNameClosure;
+	private final FetchMode[] subclassPropertyFetchModeClosure;
+	private final boolean[] subclassPropertyNullabilityClosure;
+	private final boolean[] propertyDefinedOnSubclass;
+	private final int[][] subclassPropertyColumnNumberClosure;
+	private final int[][] subclassPropertyFormulaNumberClosure;
+	private final CascadeStyle[] subclassPropertyCascadeStyleClosure;
+
+	//information about all columns/formulas in class hierarchy
+	private final String[] subclassColumnClosure;
+	private final boolean[] subclassColumnLazyClosure;
+	private final String[] subclassColumnAliasClosure;
+	private final boolean[] subclassColumnSelectableClosure;
+	private final String[] subclassFormulaClosure;
+	private final String[] subclassFormulaTemplateClosure;
+	private final String[] subclassFormulaAliasClosure;
+	private final boolean[] subclassFormulaLazyClosure;
+
+	// dynamic filters attached to the class-level
+	private final FilterHelper filterHelper;
+
+	private final Map uniqueKeyLoaders = new HashMap();
+	private final Map lockers = new HashMap();
+	private final Map loaders = new HashMap();
+
+	// SQL strings
+	private String sqlVersionSelectString;
+	private String sqlSnapshotSelectString;
+	private String sqlLazySelectString;
+
+	private String sqlIdentityInsertString;
+	private String sqlUpdateByRowIdString;
+	private String sqlLazyUpdateByRowIdString;
+
+	private String[] sqlDeleteStrings;
+	private String[] sqlInsertStrings;
+	private String[] sqlUpdateStrings;
+	private String[] sqlLazyUpdateStrings;
+
+	private String sqlInsertGeneratedValuesSelectString;
+	private String sqlUpdateGeneratedValuesSelectString;
+
+	//Custom SQL (would be better if these were private)
+	protected boolean[] insertCallable;
+	protected boolean[] updateCallable;
+	protected boolean[] deleteCallable;
+	protected String[] customSQLInsert;
+	protected String[] customSQLUpdate;
+	protected String[] customSQLDelete;
+	protected ExecuteUpdateResultCheckStyle[] insertResultCheckStyles;
+	protected ExecuteUpdateResultCheckStyle[] updateResultCheckStyles;
+	protected ExecuteUpdateResultCheckStyle[] deleteResultCheckStyles;
+
+	private InsertGeneratedIdentifierDelegate identityDelegate;
+
+	private boolean[] tableHasColumns;
+
+	private final String loaderName;
+
+	private UniqueEntityLoader queryLoader;
+
+	private final String temporaryIdTableName;
+	private final String temporaryIdTableDDL;
+
+	private final Map subclassPropertyAliases = new HashMap();
+	private final Map subclassPropertyColumnNames = new HashMap();
+
+	protected final BasicEntityPropertyMapping propertyMapping;
+
+	protected void addDiscriminatorToInsert(Insert insert) {}
+
+	protected void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) {}
+
+	protected abstract int[] getSubclassColumnTableNumberClosure();
+
+	protected abstract int[] getSubclassFormulaTableNumberClosure();
+
+	public abstract String getSubclassTableName(int j);
+
+	protected abstract String[] getSubclassTableKeyColumns(int j);
+
+	protected abstract boolean isClassOrSuperclassTable(int j);
+
+	protected abstract int getSubclassTableSpan();
+
+	protected abstract int getTableSpan();
+
+	protected abstract boolean isTableCascadeDeleteEnabled(int j);
+
+	protected abstract String getTableName(int j);
+
+	protected abstract String[] getKeyColumns(int j);
+
+	protected abstract boolean isPropertyOfTable(int property, int j);
+
+	protected abstract int[] getPropertyTableNumbersInSelect();
+
+	protected abstract int[] getPropertyTableNumbers();
+
+	protected abstract int getSubclassPropertyTableNumber(int i);
+
+	protected abstract String filterFragment(String alias) throws MappingException;
+
+	private static final String DISCRIMINATOR_ALIAS = "clazz_";
+
+	public String getDiscriminatorColumnName() {
+		return DISCRIMINATOR_ALIAS;
+	}
+
+	protected String getDiscriminatorAlias() {
+		return DISCRIMINATOR_ALIAS;
+	}
+
+	protected String getDiscriminatorFormulaTemplate() {
+		return null;
+	}
+
+	protected boolean isInverseTable(int j) {
+		return false;
+	}
+
+	protected boolean isNullableTable(int j) {
+		return false;
+	}
+
+	protected boolean isNullableSubclassTable(int j) {
+		return false;
+	}
+
+	protected boolean isInverseSubclassTable(int j) {
+		return false;
+	}
+
+	public boolean isSubclassEntityName(String entityName) {
+		return entityMetamodel.getSubclassEntityNames().contains(entityName);
+	}
+
+	private boolean[] getTableHasColumns() {
+		return tableHasColumns;
+	}
+
+	public String[] getRootTableKeyColumnNames() {
+		return rootTableKeyColumnNames;
+	}
+
+	protected String[] getSQLUpdateByRowIdStrings() {
+		if ( sqlUpdateByRowIdString == null ) {
+			throw new AssertionFailure( "no update by row id" );
+		}
+		String[] result = new String[getTableSpan() + 1];
+		result[0] = sqlUpdateByRowIdString;
+		System.arraycopy( sqlUpdateStrings, 0, result, 1, getTableSpan() );
+		return result;
+	}
+
+	protected String[] getSQLLazyUpdateByRowIdStrings() {
+		if ( sqlLazyUpdateByRowIdString == null ) {
+			throw new AssertionFailure( "no update by row id" );
+		}
+		String[] result = new String[getTableSpan()];
+		result[0] = sqlLazyUpdateByRowIdString;
+		for ( int i = 1; i < getTableSpan(); i++ ) {
+			result[i] = sqlLazyUpdateStrings[i];
+		}
+		return result;
+	}
+
+	protected String getSQLSnapshotSelectString() {
+		return sqlSnapshotSelectString;
+	}
+
+	protected String getSQLLazySelectString() {
+		return sqlLazySelectString;
+	}
+
+	protected String[] getSQLDeleteStrings() {
+		return sqlDeleteStrings;
+	}
+
+	protected String[] getSQLInsertStrings() {
+		return sqlInsertStrings;
+	}
+
+	protected String[] getSQLUpdateStrings() {
+		return sqlUpdateStrings;
+	}
+
+	protected String[] getSQLLazyUpdateStrings() {
+		return sqlLazyUpdateStrings;
+	}
+
+	/**
+	 * The query that inserts a row, letting the database generate an id
+	 * 
+	 * @return The IDENTITY-based insertion query.
+	 */
+	protected String getSQLIdentityInsertString() {
+		return sqlIdentityInsertString;
+	}
+
+	protected String getVersionSelectString() {
+		return sqlVersionSelectString;
+	}
+
+	protected boolean isInsertCallable(int j) {
+		return insertCallable[j];
+	}
+
+	protected boolean isUpdateCallable(int j) {
+		return updateCallable[j];
+	}
+
+	protected boolean isDeleteCallable(int j) {
+		return deleteCallable[j];
+	}
+
+	protected boolean isSubclassPropertyDeferred(String propertyName, String entityName) {
+		return false;
+	}
+
+	protected boolean isSubclassTableSequentialSelect(int j) {
+		return false;
+	}
+
+	public boolean hasSequentialSelect() {
+		return false;
+	}
+
+	/**
+	 * Decide which tables need to be updated.
+	 * <p/>
+	 * The return here is an array of boolean values with each index corresponding
+	 * to a given table in the scope of this persister.
+	 *
+	 * @param dirtyProperties The indices of all the entity properties considered dirty.
+	 * @param hasDirtyCollection Whether any collections owned by the entity which were considered dirty.
+	 *
+	 * @return Array of booleans indicating which table require updating.
+	 */
+	protected boolean[] getTableUpdateNeeded(final int[] dirtyProperties, boolean hasDirtyCollection) {
+
+		if ( dirtyProperties == null ) {
+			return getTableHasColumns(); // for objects that came in via update()
+		}
+		else {
+			boolean[] updateability = getPropertyUpdateability();
+			int[] propertyTableNumbers = getPropertyTableNumbers();
+			boolean[] tableUpdateNeeded = new boolean[ getTableSpan() ];
+			for ( int i = 0; i < dirtyProperties.length; i++ ) {
+				int property = dirtyProperties[i];
+				int table = propertyTableNumbers[property];
+				tableUpdateNeeded[table] = tableUpdateNeeded[table] ||
+						( getPropertyColumnSpan(property) > 0 && updateability[property] );
+			}
+			if ( isVersioned() ) {
+				tableUpdateNeeded[0] = tableUpdateNeeded[0] ||
+					Versioning.isVersionIncrementRequired( dirtyProperties, hasDirtyCollection, getPropertyVersionability() );
+			}
+			return tableUpdateNeeded;
+		}
+	}
+
+	public boolean hasRowId() {
+		return rowIdName != null;
+	}
+
+	public AbstractEntityPersister(
+			final PersistentClass persistentClass,
+			final EntityRegionAccessStrategy cacheAccessStrategy,
+			final SessionFactoryImplementor factory) throws HibernateException {
+
+		// moved up from AbstractEntityPersister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		this.factory = factory;
+		this.cacheAccessStrategy = cacheAccessStrategy;
+		isLazyPropertiesCacheable = persistentClass.isLazyPropertiesCacheable();
+		this.cacheEntryStructure = factory.getSettings().isStructuredCacheEntriesEnabled() ?
+				(CacheEntryStructure) new StructuredCacheEntry(this) :
+				(CacheEntryStructure) new UnstructuredCacheEntry();
+
+		this.entityMetamodel = new EntityMetamodel( persistentClass, factory );
+
+		if ( persistentClass.hasPojoRepresentation() ) {
+			//TODO: this is currently specific to pojos, but need to be available for all entity-modes
+			Iterator iter = persistentClass.getSubclassIterator();
+			while ( iter.hasNext() ) {
+				PersistentClass pc = ( PersistentClass ) iter.next();
+				entityNameBySubclass.put( pc.getMappedClass(), pc.getEntityName() );
+			}
+		}
+		// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+		int batch = persistentClass.getBatchSize();
+		if ( batch == -1 ) {
+			batch = factory.getSettings().getDefaultBatchFetchSize();
+		}
+		batchSize = batch;
+		hasSubselectLoadableCollections = persistentClass.hasSubselectLoadableCollections();
+
+		propertyMapping = new BasicEntityPropertyMapping( this );
+
+		// IDENTIFIER
+
+		identifierColumnSpan = persistentClass.getIdentifier().getColumnSpan();
+		rootTableKeyColumnNames = new String[identifierColumnSpan];
+		identifierAliases = new String[identifierColumnSpan];
+
+		rowIdName = persistentClass.getRootTable().getRowId();
+
+		loaderName = persistentClass.getLoaderName();
+
+		Iterator iter = persistentClass.getIdentifier().getColumnIterator();
+		int i = 0;
+		while ( iter.hasNext() ) {
+			Column col = ( Column ) iter.next();
+			rootTableKeyColumnNames[i] = col.getQuotedName( factory.getDialect() );
+			identifierAliases[i] = col.getAlias( factory.getDialect(), persistentClass.getRootTable() );
+			i++;
+		}
+
+		// VERSION
+
+		if ( persistentClass.isVersioned() ) {
+			versionColumnName = ( ( Column ) persistentClass.getVersion().getColumnIterator().next() ).getQuotedName( factory.getDialect() );
+		}
+		else {
+			versionColumnName = null;
+		}
+
+		//WHERE STRING
+
+		sqlWhereString = StringHelper.isNotEmpty( persistentClass.getWhere() ) ? "( " + persistentClass.getWhere() + ") " : null;
+		sqlWhereStringTemplate = sqlWhereString == null ?
+				null :
+				Template.renderWhereStringTemplate( sqlWhereString, factory.getDialect(), factory.getSqlFunctionRegistry() );
+
+		// PROPERTIES
+
+		final boolean lazyAvailable = isInstrumented(EntityMode.POJO);
+
+		int hydrateSpan = entityMetamodel.getPropertySpan();
+		propertyColumnSpans = new int[hydrateSpan];
+		propertySubclassNames = new String[hydrateSpan];
+		propertyColumnAliases = new String[hydrateSpan][];
+		propertyColumnNames = new String[hydrateSpan][];
+		propertyColumnFormulaTemplates = new String[hydrateSpan][];
+		propertyUniqueness = new boolean[hydrateSpan];
+		propertySelectable = new boolean[hydrateSpan];
+		propertyColumnUpdateable = new boolean[hydrateSpan][];
+		propertyColumnInsertable = new boolean[hydrateSpan][];
+		HashSet thisClassProperties = new HashSet();
+
+		lazyProperties = new HashSet();
+		ArrayList lazyNames = new ArrayList();
+		ArrayList lazyNumbers = new ArrayList();
+		ArrayList lazyTypes = new ArrayList();
+		ArrayList lazyColAliases = new ArrayList();
+
+		iter = persistentClass.getPropertyClosureIterator();
+		i = 0;
+		boolean foundFormula = false;
+		while ( iter.hasNext() ) {
+			Property prop = ( Property ) iter.next();
+			thisClassProperties.add( prop );
+
+			int span = prop.getColumnSpan();
+			propertyColumnSpans[i] = span;
+			propertySubclassNames[i] = prop.getPersistentClass().getEntityName();
+			String[] colNames = new String[span];
+			String[] colAliases = new String[span];
+			String[] templates = new String[span];
+			Iterator colIter = prop.getColumnIterator();
+			int k = 0;
+			while ( colIter.hasNext() ) {
+				Selectable thing = ( Selectable ) colIter.next();
+				colAliases[k] = thing.getAlias( factory.getDialect() , prop.getValue().getTable() );
+				if ( thing.isFormula() ) {
+					foundFormula = true;
+					templates[k] = thing.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
+				}
+				else {
+					colNames[k] = thing.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
+				}
+				k++;
+			}
+			propertyColumnNames[i] = colNames;
+			propertyColumnFormulaTemplates[i] = templates;
+			propertyColumnAliases[i] = colAliases;
+
+			if ( lazyAvailable && prop.isLazy() ) {
+				lazyProperties.add( prop.getName() );
+				lazyNames.add( prop.getName() );
+				lazyNumbers.add( new Integer( i ) );
+				lazyTypes.add( prop.getValue().getType() );
+				lazyColAliases.add( colAliases );
+			}
+
+			propertyColumnUpdateable[i] = prop.getValue().getColumnUpdateability();
+			propertyColumnInsertable[i] = prop.getValue().getColumnInsertability();
+
+			propertySelectable[i] = prop.isSelectable();
+
+			propertyUniqueness[i] = prop.getValue().isAlternateUniqueKey();
+
+			i++;
+
+		}
+		hasFormulaProperties = foundFormula;
+		lazyPropertyColumnAliases = ArrayHelper.to2DStringArray( lazyColAliases );
+		lazyPropertyNames = ArrayHelper.toStringArray( lazyNames );
+		lazyPropertyNumbers = ArrayHelper.toIntArray( lazyNumbers );
+		lazyPropertyTypes = ArrayHelper.toTypeArray( lazyTypes );
+
+		// SUBCLASS PROPERTY CLOSURE
+
+		ArrayList columns = new ArrayList();
+		ArrayList columnsLazy = new ArrayList();
+		ArrayList aliases = new ArrayList();
+		ArrayList formulas = new ArrayList();
+		ArrayList formulaAliases = new ArrayList();
+		ArrayList formulaTemplates = new ArrayList();
+		ArrayList formulasLazy = new ArrayList();
+		ArrayList types = new ArrayList();
+		ArrayList names = new ArrayList();
+		ArrayList classes = new ArrayList();
+		ArrayList templates = new ArrayList();
+		ArrayList propColumns = new ArrayList();
+		ArrayList joinedFetchesList = new ArrayList();
+		ArrayList cascades = new ArrayList();
+		ArrayList definedBySubclass = new ArrayList();
+		ArrayList propColumnNumbers = new ArrayList();
+		ArrayList propFormulaNumbers = new ArrayList();
+		ArrayList columnSelectables = new ArrayList();
+		ArrayList propNullables = new ArrayList();
+
+		iter = persistentClass.getSubclassPropertyClosureIterator();
+		while ( iter.hasNext() ) {
+			Property prop = ( Property ) iter.next();
+			names.add( prop.getName() );
+			classes.add( prop.getPersistentClass().getEntityName() );
+			boolean isDefinedBySubclass = !thisClassProperties.contains( prop );
+			definedBySubclass.add( Boolean.valueOf( isDefinedBySubclass ) );
+			propNullables.add( Boolean.valueOf( prop.isOptional() || isDefinedBySubclass ) ); //TODO: is this completely correct?
+			types.add( prop.getType() );
+
+			Iterator colIter = prop.getColumnIterator();
+			String[] cols = new String[prop.getColumnSpan()];
+			String[] forms = new String[prop.getColumnSpan()];
+			int[] colnos = new int[prop.getColumnSpan()];
+			int[] formnos = new int[prop.getColumnSpan()];
+			int l = 0;
+			Boolean lazy = Boolean.valueOf( prop.isLazy() && lazyAvailable );
+			while ( colIter.hasNext() ) {
+				Selectable thing = ( Selectable ) colIter.next();
+				if ( thing.isFormula() ) {
+					String template = thing.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
+					formnos[l] = formulaTemplates.size();
+					colnos[l] = -1;
+					formulaTemplates.add( template );
+					forms[l] = template;
+					formulas.add( thing.getText( factory.getDialect() ) );
+					formulaAliases.add( thing.getAlias( factory.getDialect() ) );
+					formulasLazy.add( lazy );
+				}
+				else {
+					String colName = thing.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
+					colnos[l] = columns.size(); //before add :-)
+					formnos[l] = -1;
+					columns.add( colName );
+					cols[l] = colName;
+					aliases.add( thing.getAlias( factory.getDialect(), prop.getValue().getTable() ) );
+					columnsLazy.add( lazy );
+					columnSelectables.add( Boolean.valueOf( prop.isSelectable() ) );
+				}
+				l++;
+			}
+			propColumns.add( cols );
+			templates.add( forms );
+			propColumnNumbers.add( colnos );
+			propFormulaNumbers.add( formnos );
+
+			joinedFetchesList.add( prop.getValue().getFetchMode() );
+			cascades.add( prop.getCascadeStyle() );
+		}
+		subclassColumnClosure = ArrayHelper.toStringArray( columns );
+		subclassColumnAliasClosure = ArrayHelper.toStringArray( aliases );
+		subclassColumnLazyClosure = ArrayHelper.toBooleanArray( columnsLazy );
+		subclassColumnSelectableClosure = ArrayHelper.toBooleanArray( columnSelectables );
+
+		subclassFormulaClosure = ArrayHelper.toStringArray( formulas );
+		subclassFormulaTemplateClosure = ArrayHelper.toStringArray( formulaTemplates );
+		subclassFormulaAliasClosure = ArrayHelper.toStringArray( formulaAliases );
+		subclassFormulaLazyClosure = ArrayHelper.toBooleanArray( formulasLazy );
+
+		subclassPropertyNameClosure = ArrayHelper.toStringArray( names );
+		subclassPropertySubclassNameClosure = ArrayHelper.toStringArray( classes );
+		subclassPropertyTypeClosure = ArrayHelper.toTypeArray( types );
+		subclassPropertyNullabilityClosure = ArrayHelper.toBooleanArray( propNullables );
+		subclassPropertyFormulaTemplateClosure = ArrayHelper.to2DStringArray( templates );
+		subclassPropertyColumnNameClosure = ArrayHelper.to2DStringArray( propColumns );
+		subclassPropertyColumnNumberClosure = ArrayHelper.to2DIntArray( propColumnNumbers );
+		subclassPropertyFormulaNumberClosure = ArrayHelper.to2DIntArray( propFormulaNumbers );
+
+		subclassPropertyCascadeStyleClosure = new CascadeStyle[cascades.size()];
+		iter = cascades.iterator();
+		int j = 0;
+		while ( iter.hasNext() ) {
+			subclassPropertyCascadeStyleClosure[j++] = ( CascadeStyle ) iter.next();
+		}
+		subclassPropertyFetchModeClosure = new FetchMode[joinedFetchesList.size()];
+		iter = joinedFetchesList.iterator();
+		j = 0;
+		while ( iter.hasNext() ) {
+			subclassPropertyFetchModeClosure[j++] = ( FetchMode ) iter.next();
+		}
+
+		propertyDefinedOnSubclass = new boolean[definedBySubclass.size()];
+		iter = definedBySubclass.iterator();
+		j = 0;
+		while ( iter.hasNext() ) {
+			propertyDefinedOnSubclass[j++] = ( ( Boolean ) iter.next() ).booleanValue();
+		}
+
+		// Handle any filters applied to the class level
+		filterHelper = new FilterHelper( persistentClass.getFilterMap(), factory.getDialect(), factory.getSqlFunctionRegistry() );
+
+		temporaryIdTableName = persistentClass.getTemporaryIdTableName();
+		temporaryIdTableDDL = persistentClass.getTemporaryIdTableDDL();
+	}
+
+	protected String generateLazySelectString() {
+
+		if ( !entityMetamodel.hasLazyProperties() ) {
+			return null;
+		}
+
+		HashSet tableNumbers = new HashSet();
+		ArrayList columnNumbers = new ArrayList();
+		ArrayList formulaNumbers = new ArrayList();
+		for ( int i = 0; i < lazyPropertyNames.length; i++ ) {
+			// all this only really needs to consider properties
+			// of this class, not its subclasses, but since we
+			// are reusing code used for sequential selects, we
+			// use the subclass closure
+			int propertyNumber = getSubclassPropertyIndex( lazyPropertyNames[i] );
+
+			int tableNumber = getSubclassPropertyTableNumber( propertyNumber );
+			tableNumbers.add( new Integer( tableNumber ) );
+
+			int[] colNumbers = subclassPropertyColumnNumberClosure[propertyNumber];
+			for ( int j = 0; j < colNumbers.length; j++ ) {
+				if ( colNumbers[j]!=-1 ) {
+					columnNumbers.add( new Integer( colNumbers[j] ) );
+				}
+			}
+			int[] formNumbers = subclassPropertyFormulaNumberClosure[propertyNumber];
+			for ( int j = 0; j < formNumbers.length; j++ ) {
+				if ( formNumbers[j]!=-1 ) {
+					formulaNumbers.add( new Integer( formNumbers[j] ) );
+				}
+			}
+		}
+
+		if ( columnNumbers.size()==0 && formulaNumbers.size()==0 ) {
+			// only one-to-one is lazy fetched
+			return null;
+		}
+
+		return renderSelect( ArrayHelper.toIntArray( tableNumbers ),
+				ArrayHelper.toIntArray( columnNumbers ),
+				ArrayHelper.toIntArray( formulaNumbers ) );
+
+	}
+
+	public Object initializeLazyProperty(String fieldName, Object entity, SessionImplementor session)
+			throws HibernateException {
+
+		final Serializable id = session.getContextEntityIdentifier( entity );
+
+		final EntityEntry entry = session.getPersistenceContext().getEntry( entity );
+		if ( entry == null ) {
+			throw new HibernateException( "entity is not associated with the session: " + id );
+		}
+
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"initializing lazy properties of: " +
+					MessageHelper.infoString( this, id, getFactory() ) +
+					", field access: " + fieldName
+				);
+		}
+
+		if ( hasCache() ) {
+			CacheKey cacheKey = new CacheKey(id, getIdentifierType(), getEntityName(), session.getEntityMode(), getFactory() );
+			Object ce = getCacheAccessStrategy().get( cacheKey, session.getTimestamp() );
+			if (ce!=null) {
+				CacheEntry cacheEntry = (CacheEntry) getCacheEntryStructure().destructure(ce, factory);
+				if ( !cacheEntry.areLazyPropertiesUnfetched() ) {
+					//note early exit here:
+					return initializeLazyPropertiesFromCache( fieldName, entity, session, entry, cacheEntry );
+				}
+			}
+		}
+
+		return initializeLazyPropertiesFromDatastore( fieldName, entity, session, id, entry );
+
+	}
+
+	private Object initializeLazyPropertiesFromDatastore(
+			final String fieldName,
+			final Object entity,
+			final SessionImplementor session,
+			final Serializable id,
+			final EntityEntry entry) {
+
+		if ( !hasLazyProperties() ) {
+			throw new AssertionFailure("no lazy properties");
+		}
+
+		log.trace("initializing lazy properties from datastore");
+
+		try {
+
+			Object result = null;
+			PreparedStatement ps = null;
+			ResultSet rs = null;
+			try {
+				final String lazySelect = getSQLLazySelectString();
+				if ( lazySelect != null ) {
+					// null sql means that the only lazy properties
+					// are shared PK one-to-one associations which are
+					// handled differently in the Type#nullSafeGet code...
+					ps = session.getBatcher().prepareSelectStatement(lazySelect);
+					getIdentifierType().nullSafeSet( ps, id, 1, session );
+					rs = session.getBatcher().getResultSet( ps );
+					rs.next();
+				}
+				final Object[] snapshot = entry.getLoadedState();
+				for ( int j = 0; j < lazyPropertyNames.length; j++ ) {
+					Object propValue = lazyPropertyTypes[j].nullSafeGet( rs, lazyPropertyColumnAliases[j], session, entity );
+					if ( initializeLazyProperty( fieldName, entity, session, snapshot, j, propValue ) ) {
+						result = propValue;
+					}
+				}
+			}
+			finally {
+				if ( rs != null ) {
+					session.getBatcher().closeQueryStatement( ps, rs );
+				}
+				else if ( ps != null ) {
+					session.getBatcher().closeStatement( ps );
+				}
+			}
+
+			log.trace( "done initializing lazy properties" );
+
+			return result;
+
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not initialize lazy properties: " +
+					MessageHelper.infoString( this, id, getFactory() ),
+					getSQLLazySelectString()
+				);
+		}
+	}
+
+	private Object initializeLazyPropertiesFromCache(
+			final String fieldName,
+			final Object entity,
+			final SessionImplementor session,
+			final EntityEntry entry,
+			final CacheEntry cacheEntry
+	) {
+
+		log.trace("initializing lazy properties from second-level cache");
+
+		Object result = null;
+		Serializable[] disassembledValues = cacheEntry.getDisassembledState();
+		final Object[] snapshot = entry.getLoadedState();
+		for ( int j = 0; j < lazyPropertyNames.length; j++ ) {
+			final Object propValue = lazyPropertyTypes[j].assemble(
+					disassembledValues[ lazyPropertyNumbers[j] ],
+					session,
+					entity
+				);
+			if ( initializeLazyProperty( fieldName, entity, session, snapshot, j, propValue ) ) {
+				result = propValue;
+			}
+		}
+
+		log.trace( "done initializing lazy properties" );
+
+		return result;
+	}
+
+	private boolean initializeLazyProperty(
+			final String fieldName,
+			final Object entity,
+			final SessionImplementor session,
+			final Object[] snapshot,
+			final int j,
+			final Object propValue) {
+		setPropertyValue( entity, lazyPropertyNumbers[j], propValue, session.getEntityMode() );
+		if (snapshot != null) {
+			// object have been loaded with setReadOnly(true); HHH-2236
+			snapshot[ lazyPropertyNumbers[j] ] = lazyPropertyTypes[j].deepCopy( propValue, session.getEntityMode(), factory );
+		}
+		return fieldName.equals( lazyPropertyNames[j] );
+	}
+
+	public boolean isBatchable() {
+		return optimisticLockMode()==Versioning.OPTIMISTIC_LOCK_NONE ||
+			( !isVersioned() && optimisticLockMode()==Versioning.OPTIMISTIC_LOCK_VERSION ) ||
+			getFactory().getSettings().isJdbcBatchVersionedData();
+	}
+
+	public Serializable[] getQuerySpaces() {
+		return getPropertySpaces();
+	}
+
+	protected Set getLazyProperties() {
+		return lazyProperties;
+	}
+
+	public boolean isBatchLoadable() {
+		return batchSize > 1;
+	}
+
+	public String[] getIdentifierColumnNames() {
+		return rootTableKeyColumnNames;
+	}
+
+	protected int getIdentifierColumnSpan() {
+		return identifierColumnSpan;
+	}
+
+	protected String[] getIdentifierAliases() {
+		return identifierAliases;
+	}
+
+	public String getVersionColumnName() {
+		return versionColumnName;
+	}
+
+	protected String getVersionedTableName() {
+		return getTableName( 0 );
+	}
+
+	protected boolean[] getSubclassColumnLazyiness() {
+		return subclassColumnLazyClosure;
+	}
+
+	protected boolean[] getSubclassFormulaLazyiness() {
+		return subclassFormulaLazyClosure;
+	}
+
+	/**
+	 * We can't immediately add to the cache if we have formulas
+	 * which must be evaluated, or if we have the possibility of
+	 * two concurrent updates to the same item being merged on
+	 * the database. This can happen if (a) the item is not
+	 * versioned and either (b) we have dynamic update enabled
+	 * or (c) we have multiple tables holding the state of the
+	 * item.
+	 */
+	public boolean isCacheInvalidationRequired() {
+		return hasFormulaProperties() ||
+				( !isVersioned() && ( entityMetamodel.isDynamicUpdate() || getTableSpan() > 1 ) );
+	}
+
+	public boolean isLazyPropertiesCacheable() {
+		return isLazyPropertiesCacheable;
+	}
+
+	public String selectFragment(String alias, String suffix) {
+		return identifierSelectFragment( alias, suffix ) +
+				propertySelectFragment( alias, suffix, false );
+	}
+
+	public String[] getIdentifierAliases(String suffix) {
+		// NOTE: this assumes something about how propertySelectFragment is implemented by the subclass!
+		// was toUnqotedAliasStrings( getIdentiferColumnNames() ) before - now tried
+		// to remove that unqoting and missing aliases..
+		return new Alias( suffix ).toAliasStrings( getIdentifierAliases() );
+	}
+
+	public String[] getPropertyAliases(String suffix, int i) {
+		// NOTE: this assumes something about how propertySelectFragment is implemented by the subclass!
+		return new Alias( suffix ).toUnquotedAliasStrings( propertyColumnAliases[i] );
+	}
+
+	public String getDiscriminatorAlias(String suffix) {
+		// NOTE: this assumes something about how propertySelectFragment is implemented by the subclass!
+		// was toUnqotedAliasStrings( getdiscriminatorColumnName() ) before - now tried
+		// to remove that unqoting and missing aliases..
+		return entityMetamodel.hasSubclasses() ?
+				new Alias( suffix ).toAliasString( getDiscriminatorAlias() ) :
+				null;
+	}
+
+	public String identifierSelectFragment(String name, String suffix) {
+		return new SelectFragment()
+				.setSuffix( suffix )
+				.addColumns( name, getIdentifierColumnNames(), getIdentifierAliases() )
+				.toFragmentString()
+				.substring( 2 ); //strip leading ", "
+	}
+
+
+	public String propertySelectFragment(String name, String suffix, boolean allProperties) {
+
+		SelectFragment select = new SelectFragment()
+				.setSuffix( suffix )
+				.setUsedAliases( getIdentifierAliases() );
+
+		int[] columnTableNumbers = getSubclassColumnTableNumberClosure();
+		String[] columnAliases = getSubclassColumnAliasClosure();
+		String[] columns = getSubclassColumnClosure();
+		for ( int i = 0; i < getSubclassColumnClosure().length; i++ ) {
+			boolean selectable = ( allProperties || !subclassColumnLazyClosure[i] ) &&
+				!isSubclassTableSequentialSelect( columnTableNumbers[i] ) &&
+				subclassColumnSelectableClosure[i];
+			if ( selectable ) {
+				String subalias = generateTableAlias( name, columnTableNumbers[i] );
+				select.addColumn( subalias, columns[i], columnAliases[i] );
+			}
+		}
+
+		int[] formulaTableNumbers = getSubclassFormulaTableNumberClosure();
+		String[] formulaTemplates = getSubclassFormulaTemplateClosure();
+		String[] formulaAliases = getSubclassFormulaAliasClosure();
+		for ( int i = 0; i < getSubclassFormulaTemplateClosure().length; i++ ) {
+			boolean selectable = ( allProperties || !subclassFormulaLazyClosure[i] )
+				&& !isSubclassTableSequentialSelect( formulaTableNumbers[i] );
+			if ( selectable ) {
+				String subalias = generateTableAlias( name, formulaTableNumbers[i] );
+				select.addFormula( subalias, formulaTemplates[i], formulaAliases[i] );
+			}
+		}
+
+		if ( entityMetamodel.hasSubclasses() ) {
+			addDiscriminatorToSelect( select, name, suffix );
+		}
+
+		if ( hasRowId() ) {
+			select.addColumn( name, rowIdName, ROWID_ALIAS );
+		}
+
+		return select.toFragmentString();
+	}
+
+	public Object[] getDatabaseSnapshot(Serializable id, SessionImplementor session)
+			throws HibernateException {
+
+		if ( log.isTraceEnabled() ) {
+			log.trace( "Getting current persistent state for: " + MessageHelper.infoString( this, id, getFactory() ) );
+		}
+
+		try {
+			PreparedStatement ps = session.getBatcher().prepareSelectStatement( getSQLSnapshotSelectString() );
+			try {
+				getIdentifierType().nullSafeSet( ps, id, 1, session );
+				//if ( isVersioned() ) getVersionType().nullSafeSet( ps, version, getIdentifierColumnSpan()+1, session );
+				ResultSet rs = ps.executeQuery();
+				try {
+					//if there is no resulting row, return null
+					if ( !rs.next() ) {
+						return null;
+					}
+
+					//otherwise return the "hydrated" state (ie. associations are not resolved)
+					Type[] types = getPropertyTypes();
+					Object[] values = new Object[types.length];
+					boolean[] includeProperty = getPropertyUpdateability();
+					for ( int i = 0; i < types.length; i++ ) {
+						if ( includeProperty[i] ) {
+							values[i] = types[i].hydrate( rs, getPropertyAliases( "", i ), session, null ); //null owner ok??
+						}
+					}
+					return values;
+				}
+				finally {
+					rs.close();
+				}
+			}
+			finally {
+				session.getBatcher().closeStatement( ps );
+			}
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not retrieve snapshot: " +
+					MessageHelper.infoString( this, id, getFactory() ),
+			        getSQLSnapshotSelectString()
+				);
+		}
+
+	}
+
+	/**
+	 * Generate the SQL that selects the version number by id
+	 */
+	protected String generateSelectVersionString() {
+		SimpleSelect select = new SimpleSelect( getFactory().getDialect() )
+				.setTableName( getVersionedTableName() );
+		if ( isVersioned() ) {
+			select.addColumn( versionColumnName );
+		}
+		else {
+			select.addColumns( rootTableKeyColumnNames );
+		}
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			select.setComment( "get version " + getEntityName() );
+		}
+		return select.addCondition( rootTableKeyColumnNames, "=?" ).toStatementString();
+	}
+
+	protected String generateInsertGeneratedValuesSelectString() {
+		return generateGeneratedValuesSelectString( getPropertyInsertGenerationInclusions() );
+	}
+
+	protected String generateUpdateGeneratedValuesSelectString() {
+		return generateGeneratedValuesSelectString( getPropertyUpdateGenerationInclusions() );
+	}
+
+	private String generateGeneratedValuesSelectString(ValueInclusion[] inclusions) {
+		Select select = new Select( getFactory().getDialect() );
+
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			select.setComment( "get generated state " + getEntityName() );
+		}
+
+		String[] aliasedIdColumns = StringHelper.qualify( getRootAlias(), getIdentifierColumnNames() );
+
+		// Here we render the select column list based on the properties defined as being generated.
+		// For partial component generation, we currently just re-select the whole component
+		// rather than trying to handle the individual generated portions.
+		String selectClause = concretePropertySelectFragment( getRootAlias(), inclusions );
+		selectClause = selectClause.substring( 2 );
+
+		String fromClause = fromTableFragment( getRootAlias() ) +
+				fromJoinFragment( getRootAlias(), true, false );
+
+		String whereClause = new StringBuffer()
+			.append( StringHelper.join( "=? and ", aliasedIdColumns ) )
+			.append( "=?" )
+			.append( whereJoinFragment( getRootAlias(), true, false ) )
+			.toString();
+
+		return select.setSelectClause( selectClause )
+				.setFromClause( fromClause )
+				.setOuterJoins( "", "" )
+				.setWhereClause( whereClause )
+				.toStatementString();
+	}
+
+	protected static interface InclusionChecker {
+		public boolean includeProperty(int propertyNumber);
+	}
+
+	protected String concretePropertySelectFragment(String alias, final ValueInclusion[] inclusions) {
+		return concretePropertySelectFragment(
+				alias,
+				new InclusionChecker() {
+					// TODO : currently we really do not handle ValueInclusion.PARTIAL...
+					// ValueInclusion.PARTIAL would indicate parts of a component need to
+					// be included in the select; currently we then just render the entire
+					// component into the select clause in that case.
+					public boolean includeProperty(int propertyNumber) {
+						return inclusions[propertyNumber] != ValueInclusion.NONE;
+					}
+				}
+		);
+	}
+
+	protected String concretePropertySelectFragment(String alias, final boolean[] includeProperty) {
+		return concretePropertySelectFragment(
+				alias,
+				new InclusionChecker() {
+					public boolean includeProperty(int propertyNumber) {
+						return includeProperty[propertyNumber];
+					}
+				}
+		);
+	}
+
+	protected String concretePropertySelectFragment(String alias, InclusionChecker inclusionChecker) {
+		int propertyCount = getPropertyNames().length;
+		int[] propertyTableNumbers = getPropertyTableNumbersInSelect();
+		SelectFragment frag = new SelectFragment();
+		for ( int i = 0; i < propertyCount; i++ ) {
+			if ( inclusionChecker.includeProperty( i ) ) {
+				frag.addColumns(
+						generateTableAlias( alias, propertyTableNumbers[i] ),
+						propertyColumnNames[i],
+						propertyColumnAliases[i]
+				);
+				frag.addFormulas(
+						generateTableAlias( alias, propertyTableNumbers[i] ),
+						propertyColumnFormulaTemplates[i],
+						propertyColumnAliases[i]
+				);
+			}
+		}
+		return frag.toFragmentString();
+	}
+
+	protected String generateSnapshotSelectString() {
+
+		//TODO: should we use SELECT .. FOR UPDATE?
+
+		Select select = new Select( getFactory().getDialect() );
+
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			select.setComment( "get current state " + getEntityName() );
+		}
+
+		String[] aliasedIdColumns = StringHelper.qualify( getRootAlias(), getIdentifierColumnNames() );
+		String selectClause = StringHelper.join( ", ", aliasedIdColumns ) +
+				concretePropertySelectFragment( getRootAlias(), getPropertyUpdateability() );
+
+		String fromClause = fromTableFragment( getRootAlias() ) +
+				fromJoinFragment( getRootAlias(), true, false );
+
+		String whereClause = new StringBuffer()
+			.append( StringHelper.join( "=? and ",
+					aliasedIdColumns ) )
+			.append( "=?" )
+			.append( whereJoinFragment( getRootAlias(), true, false ) )
+			.toString();
+
+		/*if ( isVersioned() ) {
+			where.append(" and ")
+				.append( getVersionColumnName() )
+				.append("=?");
+		}*/
+
+		return select.setSelectClause( selectClause )
+				.setFromClause( fromClause )
+				.setOuterJoins( "", "" )
+				.setWhereClause( whereClause )
+				.toStatementString();
+	}
+
+	public Object forceVersionIncrement(Serializable id, Object currentVersion, SessionImplementor session) {
+		if ( !isVersioned() ) {
+			throw new AssertionFailure( "cannot force version increment on non-versioned entity" );
+		}
+
+		if ( isVersionPropertyGenerated() ) {
+			// the difficulty here is exactly what do we update in order to
+			// force the version to be incremented in the db...
+			throw new HibernateException( "LockMode.FORCE is currently not supported for generated version properties" );
+		}
+
+		Object nextVersion = getVersionType().next( currentVersion, session );
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"Forcing version increment [" + MessageHelper.infoString( this, id, getFactory() ) +
+					"; " + getVersionType().toLoggableString( currentVersion, getFactory() ) +
+					" -> " + getVersionType().toLoggableString( nextVersion, getFactory() ) + "]"
+			);
+		}
+
+		// todo : cache this sql...
+		String versionIncrementString = generateVersionIncrementUpdateString();
+		PreparedStatement st = null;
+		try {
+			try {
+				st = session.getBatcher().prepareStatement( versionIncrementString );
+				getVersionType().nullSafeSet( st, nextVersion, 1, session );
+				getIdentifierType().nullSafeSet( st, id, 2, session );
+				getVersionType().nullSafeSet( st, currentVersion, 2 + getIdentifierColumnSpan(), session );
+				int rows = st.executeUpdate();
+				if ( rows != 1 ) {
+					throw new StaleObjectStateException( getEntityName(), id );
+				}
+			}
+			finally {
+				session.getBatcher().closeStatement( st );
+			}
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not retrieve version: " +
+					MessageHelper.infoString( this, id, getFactory() ),
+					getVersionSelectString()
+				);
+		}
+
+		return nextVersion;
+	}
+
+	private String generateVersionIncrementUpdateString() {
+		Update update = new Update( getFactory().getDialect() );
+		update.setTableName( getTableName( 0 ) );
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			update.setComment( "forced version increment" );
+		}
+		update.addColumn( getVersionColumnName() );
+		update.setPrimaryKeyColumnNames( getIdentifierColumnNames() );
+		update.setVersionColumnName( getVersionColumnName() );
+		return update.toStatementString();
+	}
+
+	/**
+	 * Retrieve the version number
+	 */
+	public Object getCurrentVersion(Serializable id, SessionImplementor session) throws HibernateException {
+
+		if ( log.isTraceEnabled() ) {
+			log.trace( "Getting version: " + MessageHelper.infoString( this, id, getFactory() ) );
+		}
+
+		try {
+
+			PreparedStatement st = session.getBatcher().prepareSelectStatement( getVersionSelectString() );
+			try {
+				getIdentifierType().nullSafeSet( st, id, 1, session );
+
+				ResultSet rs = st.executeQuery();
+				try {
+					if ( !rs.next() ) {
+						return null;
+					}
+					if ( !isVersioned() ) {
+						return this;
+					}
+					return getVersionType().nullSafeGet( rs, getVersionColumnName(), session, null );
+				}
+				finally {
+					rs.close();
+				}
+			}
+			finally {
+				session.getBatcher().closeStatement( st );
+			}
+
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not retrieve version: " +
+					MessageHelper.infoString( this, id, getFactory() ),
+					getVersionSelectString()
+				);
+		}
+
+	}
+
+	protected void initLockers() {
+		lockers.put( LockMode.READ, generateLocker( LockMode.READ ) );
+		lockers.put( LockMode.UPGRADE, generateLocker( LockMode.UPGRADE ) );
+		lockers.put( LockMode.UPGRADE_NOWAIT, generateLocker( LockMode.UPGRADE_NOWAIT ) );
+		lockers.put( LockMode.FORCE, generateLocker( LockMode.FORCE ) );
+	}
+
+	protected LockingStrategy generateLocker(LockMode lockMode) {
+		return factory.getDialect().getLockingStrategy( this, lockMode );
+	}
+
+	private LockingStrategy getLocker(LockMode lockMode) {
+		return ( LockingStrategy ) lockers.get( lockMode );
+	}
+
+	public void lock(
+			Serializable id,
+	        Object version,
+	        Object object,
+	        LockMode lockMode,
+	        SessionImplementor session) throws HibernateException {
+		getLocker( lockMode ).lock( id, version, object, session );
+	}
+
+	public String getRootTableName() {
+		return getSubclassTableName( 0 );
+	}
+
+	public String getRootTableAlias(String drivingAlias) {
+		return drivingAlias;
+	}
+
+	public String[] getRootTableIdentifierColumnNames() {
+		return getRootTableKeyColumnNames();
+	}
+
+	public String[] toColumns(String alias, String propertyName) throws QueryException {
+		return propertyMapping.toColumns( alias, propertyName );
+	}
+
+	public String[] toColumns(String propertyName) throws QueryException {
+		return propertyMapping.getColumnNames( propertyName );
+	}
+
+	public Type toType(String propertyName) throws QueryException {
+		return propertyMapping.toType( propertyName );
+	}
+
+	public String[] getPropertyColumnNames(String propertyName) {
+		return propertyMapping.getColumnNames( propertyName );
+	}
+
+	/**
+	 * Warning:
+	 * When there are duplicated property names in the subclasses
+	 * of the class, this method may return the wrong table
+	 * number for the duplicated subclass property (note that
+	 * SingleTableEntityPersister defines an overloaded form
+	 * which takes the entity name.
+	 */
+	public int getSubclassPropertyTableNumber(String propertyPath) {
+		String rootPropertyName = StringHelper.root(propertyPath);
+		Type type = propertyMapping.toType(rootPropertyName);
+		if ( type.isAssociationType() ) {
+			AssociationType assocType = ( AssociationType ) type;
+			if ( assocType.useLHSPrimaryKey() ) {
+				// performance op to avoid the array search
+				return 0;
+			}
+			else if ( type.isCollectionType() ) {
+				// properly handle property-ref-based associations
+				rootPropertyName = assocType.getLHSPropertyName();
+			}
+		}
+		//Enable for HHH-440, which we don't like:
+		/*if ( type.isComponentType() && !propertyName.equals(rootPropertyName) ) {
+			String unrooted = StringHelper.unroot(propertyName);
+			int idx = ArrayHelper.indexOf( getSubclassColumnClosure(), unrooted );
+			if ( idx != -1 ) {
+				return getSubclassColumnTableNumberClosure()[idx];
+			}
+		}*/
+		int index = ArrayHelper.indexOf( getSubclassPropertyNameClosure(), rootPropertyName); //TODO: optimize this better!
+		return index==-1 ? 0 : getSubclassPropertyTableNumber(index);
+	}
+
+	public Declarer getSubclassPropertyDeclarer(String propertyPath) {
+		int tableIndex = getSubclassPropertyTableNumber( propertyPath );
+		if ( tableIndex == 0 ) {
+			return Declarer.CLASS;
+		}
+		else if ( isClassOrSuperclassTable( tableIndex ) ) {
+			return Declarer.SUPERCLASS;
+		}
+		else {
+			return Declarer.SUBCLASS;
+		}
+	}
+
+	protected String generateTableAlias(String rootAlias, int tableNumber) {
+		if ( tableNumber == 0 ) {
+			return rootAlias;
+		}
+		StringBuffer buf = new StringBuffer().append( rootAlias );
+		if ( !rootAlias.endsWith( "_" ) ) {
+			buf.append( '_' );
+		}
+		return buf.append( tableNumber ).append( '_' ).toString();
+	}
+
+	public String[] toColumns(String name, final int i) {
+		final String alias = generateTableAlias( name, getSubclassPropertyTableNumber( i ) );
+		String[] cols = getSubclassPropertyColumnNames( i );
+		String[] templates = getSubclassPropertyFormulaTemplateClosure()[i];
+		String[] result = new String[cols.length];
+		for ( int j = 0; j < cols.length; j++ ) {
+			if ( cols[j] == null ) {
+				result[j] = StringHelper.replace( templates[j], Template.TEMPLATE, alias );
+			}
+			else {
+				result[j] = StringHelper.qualify( alias, cols[j] );
+			}
+		}
+		return result;
+	}
+
+	private int getSubclassPropertyIndex(String propertyName) {
+		return ArrayHelper.indexOf(subclassPropertyNameClosure, propertyName);
+	}
+
+	protected String[] getPropertySubclassNames() {
+		return propertySubclassNames;
+	}
+
+	public String[] getPropertyColumnNames(int i) {
+		return propertyColumnNames[i];
+	}
+
+	protected int getPropertyColumnSpan(int i) {
+		return propertyColumnSpans[i];
+	}
+
+	protected boolean hasFormulaProperties() {
+		return hasFormulaProperties;
+	}
+
+	public FetchMode getFetchMode(int i) {
+		return subclassPropertyFetchModeClosure[i];
+	}
+
+	public CascadeStyle getCascadeStyle(int i) {
+		return subclassPropertyCascadeStyleClosure[i];
+	}
+
+	public Type getSubclassPropertyType(int i) {
+		return subclassPropertyTypeClosure[i];
+	}
+
+	public String getSubclassPropertyName(int i) {
+		return subclassPropertyNameClosure[i];
+	}
+
+	public int countSubclassProperties() {
+		return subclassPropertyTypeClosure.length;
+	}
+
+	public String[] getSubclassPropertyColumnNames(int i) {
+		return subclassPropertyColumnNameClosure[i];
+	}
+
+	public boolean isDefinedOnSubclass(int i) {
+		return propertyDefinedOnSubclass[i];
+	}
+
+	protected String[][] getSubclassPropertyFormulaTemplateClosure() {
+		return subclassPropertyFormulaTemplateClosure;
+	}
+
+	protected Type[] getSubclassPropertyTypeClosure() {
+		return subclassPropertyTypeClosure;
+	}
+
+	protected String[][] getSubclassPropertyColumnNameClosure() {
+		return subclassPropertyColumnNameClosure;
+	}
+
+	protected String[] getSubclassPropertyNameClosure() {
+		return subclassPropertyNameClosure;
+	}
+
+	protected String[] getSubclassPropertySubclassNameClosure() {
+		return subclassPropertySubclassNameClosure;
+	}
+
+	protected String[] getSubclassColumnClosure() {
+		return subclassColumnClosure;
+	}
+
+	protected String[] getSubclassColumnAliasClosure() {
+		return subclassColumnAliasClosure;
+	}
+
+	protected String[] getSubclassFormulaClosure() {
+		return subclassFormulaClosure;
+	}
+
+	protected String[] getSubclassFormulaTemplateClosure() {
+		return subclassFormulaTemplateClosure;
+	}
+
+	protected String[] getSubclassFormulaAliasClosure() {
+		return subclassFormulaAliasClosure;
+	}
+
+	public String[] getSubclassPropertyColumnAliases(String propertyName, String suffix) {
+		String rawAliases[] = ( String[] ) subclassPropertyAliases.get( propertyName );
+
+		if ( rawAliases == null ) {
+			return null;
+		}
+
+		String result[] = new String[rawAliases.length];
+		for ( int i = 0; i < rawAliases.length; i++ ) {
+			result[i] = new Alias( suffix ).toUnquotedAliasString( rawAliases[i] );
+		}
+		return result;
+	}
+
+	public String[] getSubclassPropertyColumnNames(String propertyName) {
+		//TODO: should we allow suffixes on these ?
+		return ( String[] ) subclassPropertyColumnNames.get( propertyName );
+	}
+
+
+
+	//This is really ugly, but necessary:
+	/**
+	 * Must be called by subclasses, at the end of their constructors
+	 */
+	protected void initSubclassPropertyAliasesMap(PersistentClass model) throws MappingException {
+
+		// ALIASES
+		internalInitSubclassPropertyAliasesMap( null, model.getSubclassPropertyClosureIterator() );
+
+		// aliases for identifier ( alias.id ); skip if the entity defines a non-id property named 'id'
+		if ( ! entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
+			subclassPropertyAliases.put( ENTITY_ID, getIdentifierAliases() );
+			subclassPropertyColumnNames.put( ENTITY_ID, getIdentifierColumnNames() );
+		}
+
+		// aliases named identifier ( alias.idname )
+		if ( hasIdentifierProperty() ) {
+			subclassPropertyAliases.put( getIdentifierPropertyName(), getIdentifierAliases() );
+			subclassPropertyColumnNames.put( getIdentifierPropertyName(), getIdentifierColumnNames() );
+		}
+
+		// aliases for composite-id's
+		if ( getIdentifierType().isComponentType() ) {
+			// Fetch embedded identifiers propertynames from the "virtual" identifier component
+			AbstractComponentType componentId = ( AbstractComponentType ) getIdentifierType();
+			String[] idPropertyNames = componentId.getPropertyNames();
+			String[] idAliases = getIdentifierAliases();
+			String[] idColumnNames = getIdentifierColumnNames();
+
+			for ( int i = 0; i < idPropertyNames.length; i++ ) {
+				if ( entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
+					subclassPropertyAliases.put(
+							ENTITY_ID + "." + idPropertyNames[i],
+							new String[] { idAliases[i] }
+					);
+					subclassPropertyColumnNames.put(
+							ENTITY_ID + "." + getIdentifierPropertyName() + "." + idPropertyNames[i],
+							new String[] { idColumnNames[i] }
+					);
+				}
+//				if (hasIdentifierProperty() && !ENTITY_ID.equals( getIdentifierPropertyName() ) ) {
+				if ( hasIdentifierProperty() ) {
+					subclassPropertyAliases.put(
+							getIdentifierPropertyName() + "." + idPropertyNames[i],
+							new String[] { idAliases[i] }
+					);
+					subclassPropertyColumnNames.put(
+							getIdentifierPropertyName() + "." + idPropertyNames[i],
+							new String[] { idColumnNames[i] }
+					);
+				}
+				else {
+					// embedded composite ids ( alias.idname1, alias.idname2 )
+					subclassPropertyAliases.put( idPropertyNames[i], new String[] { idAliases[i] } );
+					subclassPropertyColumnNames.put( idPropertyNames[i],  new String[] { idColumnNames[i] } );
+				}
+			}
+		}
+
+		if ( entityMetamodel.isPolymorphic() ) {
+			subclassPropertyAliases.put( ENTITY_CLASS, new String[] { getDiscriminatorAlias() } );
+			subclassPropertyColumnNames.put( ENTITY_CLASS, new String[] { getDiscriminatorColumnName() } );
+		}
+
+	}
+
+	private void internalInitSubclassPropertyAliasesMap(String path, Iterator propertyIterator) {
+		while ( propertyIterator.hasNext() ) {
+
+			Property prop = ( Property ) propertyIterator.next();
+			String propname = path == null ? prop.getName() : path + "." + prop.getName();
+			if ( prop.isComposite() ) {
+				Component component = ( Component ) prop.getValue();
+				Iterator compProps = component.getPropertyIterator();
+				internalInitSubclassPropertyAliasesMap( propname, compProps );
+			}
+			else {
+				String[] aliases = new String[prop.getColumnSpan()];
+				String[] cols = new String[prop.getColumnSpan()];
+				Iterator colIter = prop.getColumnIterator();
+				int l = 0;
+				while ( colIter.hasNext() ) {
+					Selectable thing = ( Selectable ) colIter.next();
+					aliases[l] = thing.getAlias( getFactory().getDialect(), prop.getValue().getTable() );
+					cols[l] = thing.getText( getFactory().getDialect() ); // TODO: skip formulas?
+					l++;
+				}
+
+				subclassPropertyAliases.put( propname, aliases );
+				subclassPropertyColumnNames.put( propname, cols );
+			}
+		}
+
+	}
+
+	public Object loadByUniqueKey(String propertyName, Object uniqueKey, SessionImplementor session)
+			throws HibernateException {
+		return getAppropriateUniqueKeyLoader( propertyName, session.getEnabledFilters() )
+				.loadByUniqueKey( session, uniqueKey );
+	}
+
+	private EntityLoader getAppropriateUniqueKeyLoader(String propertyName, Map enabledFilters) {
+
+		final boolean useStaticLoader = ( enabledFilters == null || enabledFilters.isEmpty() )
+				&& propertyName.indexOf('.')<0; //ugly little workaround for fact that createUniqueKeyLoaders() does not handle component properties
+
+		if ( useStaticLoader ) {
+			return (EntityLoader) uniqueKeyLoaders.get( propertyName );
+		}
+		else {
+			return createUniqueKeyLoader(
+					propertyMapping.toType(propertyName),
+					propertyMapping.toColumns(propertyName),
+					enabledFilters
+				);
+		}
+	}
+
+	public int getPropertyIndex(String propertyName) {
+		return entityMetamodel.getPropertyIndex(propertyName);
+	}
+
+	protected void createUniqueKeyLoaders() throws MappingException {
+		Type[] propertyTypes = getPropertyTypes();
+		String[] propertyNames = getPropertyNames();
+		for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
+			if ( propertyUniqueness[i] ) {
+				//don't need filters for the static loaders
+				uniqueKeyLoaders.put(
+						propertyNames[i],
+						createUniqueKeyLoader(
+								propertyTypes[i],
+								getPropertyColumnNames( i ),
+								CollectionHelper.EMPTY_MAP
+							)
+					);
+				//TODO: create uk loaders for component properties
+			}
+		}
+	}
+
+	private EntityLoader createUniqueKeyLoader(Type uniqueKeyType, String[] columns, Map enabledFilters) {
+		if ( uniqueKeyType.isEntityType() ) {
+			String className = ( ( EntityType ) uniqueKeyType ).getAssociatedEntityName();
+			uniqueKeyType = getFactory().getEntityPersister( className ).getIdentifierType();
+		}
+
+		return new EntityLoader( this, columns, uniqueKeyType, 1, LockMode.NONE, getFactory(), enabledFilters );
+	}
+
+	protected String getSQLWhereString(String alias) {
+		return StringHelper.replace( sqlWhereStringTemplate, Template.TEMPLATE, alias );
+	}
+
+	protected boolean hasWhere() {
+		return sqlWhereString != null;
+	}
+
+	private void initOrdinaryPropertyPaths(Mapping mapping) throws MappingException {
+		for ( int i = 0; i < getSubclassPropertyNameClosure().length; i++ ) {
+			propertyMapping.initPropertyPaths( getSubclassPropertyNameClosure()[i],
+					getSubclassPropertyTypeClosure()[i],
+					getSubclassPropertyColumnNameClosure()[i],
+					getSubclassPropertyFormulaTemplateClosure()[i],
+					mapping );
+		}
+	}
+
+	private void initIdentifierPropertyPaths(Mapping mapping) throws MappingException {
+		String idProp = getIdentifierPropertyName();
+		if ( idProp != null ) {
+			propertyMapping.initPropertyPaths( idProp, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
+		}
+		if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) {
+			propertyMapping.initPropertyPaths( null, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
+		}
+		if ( ! entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
+			propertyMapping.initPropertyPaths( ENTITY_ID, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
+		}
+	}
+
+	private void initDiscriminatorPropertyPath(Mapping mapping) throws MappingException {
+		propertyMapping.initPropertyPaths( ENTITY_CLASS,
+				getDiscriminatorType(),
+				new String[]{getDiscriminatorColumnName()},
+				new String[]{getDiscriminatorFormulaTemplate()},
+				getFactory() );
+	}
+
+	protected void initPropertyPaths(Mapping mapping) throws MappingException {
+		initOrdinaryPropertyPaths(mapping);
+		initOrdinaryPropertyPaths(mapping); //do two passes, for collection property-ref!
+		initIdentifierPropertyPaths(mapping);
+		if ( entityMetamodel.isPolymorphic() ) {
+			initDiscriminatorPropertyPath( mapping );
+		}
+	}
+
+	protected UniqueEntityLoader createEntityLoader(LockMode lockMode, Map enabledFilters) throws MappingException {
+		//TODO: disable batch loading if lockMode > READ?
+		return BatchingEntityLoader.createBatchingEntityLoader( this, batchSize, lockMode, getFactory(), enabledFilters );
+	}
+
+	protected UniqueEntityLoader createEntityLoader(LockMode lockMode) throws MappingException {
+		return createEntityLoader( lockMode, CollectionHelper.EMPTY_MAP );
+	}
+
+	protected boolean check(int rows, Serializable id, int tableNumber, Expectation expectation, PreparedStatement statement) throws HibernateException {
+		try {
+			expectation.verifyOutcome( rows, statement, -1 );
+		}
+		catch( StaleStateException e ) {
+			if ( !isNullableTable( tableNumber ) ) {
+				if ( getFactory().getStatistics().isStatisticsEnabled() ) {
+					getFactory().getStatisticsImplementor()
+							.optimisticFailure( getEntityName() );
+				}
+				throw new StaleObjectStateException( getEntityName(), id );
+			}
+		}
+		catch( TooManyRowsAffectedException e ) {
+			throw new HibernateException(
+					"Duplicate identifier in table for: " +
+					MessageHelper.infoString( this, id, getFactory() )
+			);
+		}
+		catch ( Throwable t ) {
+			return false;
+		}
+		return true;
+	}
+
+	protected String generateUpdateString(boolean[] includeProperty, int j, boolean useRowId) {
+		return generateUpdateString( includeProperty, j, null, useRowId );
+	}
+
+	/**
+	 * Generate the SQL that updates a row by id (and version)
+	 */
+	protected String generateUpdateString(final boolean[] includeProperty,
+										  final int j,
+										  final Object[] oldFields,
+										  final boolean useRowId) {
+
+		Update update = new Update( getFactory().getDialect() ).setTableName( getTableName( j ) );
+
+		// select the correct row by either pk or rowid
+		if ( useRowId ) {
+			update.setPrimaryKeyColumnNames( new String[]{rowIdName} ); //TODO: eventually, rowIdName[j]
+		}
+		else {
+			update.setPrimaryKeyColumnNames( getKeyColumns( j ) );
+		}
+
+		boolean hasColumns = false;
+		for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
+			if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
+				// this is a property of the table, which we are updating
+				update.addColumns( getPropertyColumnNames(i), propertyColumnUpdateable[i] );
+				hasColumns = hasColumns || getPropertyColumnSpan( i ) > 0;
+			}
+		}
+
+		if ( j == 0 && isVersioned() && entityMetamodel.getOptimisticLockMode() == Versioning.OPTIMISTIC_LOCK_VERSION ) {
+			// this is the root (versioned) table, and we are using version-based
+			// optimistic locking;  if we are not updating the version, also don't
+			// check it (unless this is a "generated" version column)!
+			if ( checkVersion( includeProperty ) ) {
+				update.setVersionColumnName( getVersionColumnName() );
+				hasColumns = true;
+			}
+		}
+		else if ( entityMetamodel.getOptimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION && oldFields != null ) {
+			// we are using "all" or "dirty" property-based optimistic locking
+
+			boolean[] includeInWhere = entityMetamodel.getOptimisticLockMode() == Versioning.OPTIMISTIC_LOCK_ALL ?
+					getPropertyUpdateability() : //optimistic-lock="all", include all updatable properties
+					includeProperty; //optimistic-lock="dirty", include all properties we are updating this time
+
+			boolean[] versionability = getPropertyVersionability();
+			Type[] types = getPropertyTypes();
+			for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
+				boolean include = includeInWhere[i] &&
+						isPropertyOfTable( i, j ) &&
+						versionability[i];
+				if ( include ) {
+					// this property belongs to the table, and it is not specifically
+					// excluded from optimistic locking by optimistic-lock="false"
+					String[] propertyColumnNames = getPropertyColumnNames( i );
+					boolean[] propertyNullness = types[i].toColumnNullness( oldFields[i], getFactory() );
+					for ( int k=0; k<propertyNullness.length; k++ ) {
+						if ( propertyNullness[k] ) {
+							update.addWhereColumn( propertyColumnNames[k] );
+						}
+						else {
+							update.addWhereColumn( propertyColumnNames[k], " is null" );
+						}
+					}
+				}
+			}
+
+		}
+
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			update.setComment( "update " + getEntityName() );
+		}
+
+		return hasColumns ? update.toStatementString() : null;
+	}
+
+	private boolean checkVersion(final boolean[] includeProperty) {
+        return includeProperty[ getVersionProperty() ] ||
+				entityMetamodel.getPropertyUpdateGenerationInclusions()[ getVersionProperty() ] != ValueInclusion.NONE;
+	}
+
+	protected String generateInsertString(boolean[] includeProperty, int j) {
+		return generateInsertString( false, includeProperty, j );
+	}
+
+	protected String generateInsertString(boolean identityInsert, boolean[] includeProperty) {
+		return generateInsertString( identityInsert, includeProperty, 0 );
+	}
+
+	/**
+	 * Generate the SQL that inserts a row
+	 */
+	protected String generateInsertString(boolean identityInsert, boolean[] includeProperty, int j) {
+
+		// todo : remove the identityInsert param and variations;
+		//   identity-insert strings are now generated from generateIdentityInsertString()
+
+		Insert insert = new Insert( getFactory().getDialect() )
+				.setTableName( getTableName( j ) );
+
+		// add normal properties
+		for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
+			if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
+				// this property belongs on the table and is to be inserted
+				insert.addColumns( getPropertyColumnNames(i), propertyColumnInsertable[i] );
+			}
+		}
+
+		// add the discriminator
+		if ( j == 0 ) {
+			addDiscriminatorToInsert( insert );
+		}
+
+		// add the primary key
+		if ( j == 0 && identityInsert ) {
+			insert.addIdentityColumn( getKeyColumns( 0 )[0] );
+		}
+		else {
+			insert.addColumns( getKeyColumns( j ) );
+		}
+
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			insert.setComment( "insert " + getEntityName() );
+		}
+
+		String result = insert.toStatementString();
+
+		// append the SQL to return the generated identifier
+		if ( j == 0 && identityInsert && useInsertSelectIdentity() ) { //TODO: suck into Insert
+			result = getFactory().getDialect().appendIdentitySelectToInsert( result );
+		}
+
+		return result;
+	}
+
+	/**
+	 * Used to generate an insery statement against the root table in the
+	 * case of identifier generation strategies where the insert statement
+	 * executions actually generates the identifier value.
+	 *
+	 * @param includeProperty indices of the properties to include in the
+	 * insert statement.
+	 * @return The insert SQL statement string
+	 */
+	protected String generateIdentityInsertString(boolean[] includeProperty) {
+		Insert insert = identityDelegate.prepareIdentifierGeneratingInsert();
+		insert.setTableName( getTableName( 0 ) );
+
+		// add normal properties
+		for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
+			if ( includeProperty[i] && isPropertyOfTable( i, 0 ) ) {
+				// this property belongs on the table and is to be inserted
+				insert.addColumns( getPropertyColumnNames(i), propertyColumnInsertable[i] );
+			}
+		}
+
+		// add the discriminator
+		addDiscriminatorToInsert( insert );
+
+		// delegate already handles PK columns
+
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			insert.setComment( "insert " + getEntityName() );
+		}
+
+		return insert.toStatementString();
+	}
+
+	/**
+	 * Generate the SQL that deletes a row by id (and version)
+	 */
+	protected String generateDeleteString(int j) {
+		Delete delete = new Delete()
+				.setTableName( getTableName( j ) )
+				.setPrimaryKeyColumnNames( getKeyColumns( j ) );
+		if ( j == 0 ) {
+			delete.setVersionColumnName( getVersionColumnName() );
+		}
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			delete.setComment( "delete " + getEntityName() );
+		}
+		return delete.toStatementString();
+	}
+
+	protected int dehydrate(
+			Serializable id,
+			Object[] fields,
+			boolean[] includeProperty,
+			boolean[][] includeColumns,
+			int j,
+			PreparedStatement st,
+			SessionImplementor session) throws HibernateException, SQLException {
+		return dehydrate( id, fields, null, includeProperty, includeColumns, j, st, session, 1 );
+	}
+
+	/**
+	 * Marshall the fields of a persistent instance to a prepared statement
+	 */
+	protected int dehydrate(
+			final Serializable id,
+	        final Object[] fields,
+	        final Object rowId,
+	        final boolean[] includeProperty,
+	        final boolean[][] includeColumns,
+	        final int j,
+	        final PreparedStatement ps,
+	        final SessionImplementor session,
+	        int index) throws SQLException, HibernateException {
+
+		if ( log.isTraceEnabled() ) {
+			log.trace( "Dehydrating entity: " + MessageHelper.infoString( this, id, getFactory() ) );
+		}
+
+		for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
+			if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
+				getPropertyTypes()[i].nullSafeSet( ps, fields[i], index, includeColumns[i], session );
+				//index += getPropertyColumnSpan( i );
+				index += ArrayHelper.countTrue( includeColumns[i] ); //TODO:  this is kinda slow...
+			}
+		}
+
+		if ( rowId != null ) {
+			ps.setObject( index, rowId );
+			index += 1;
+		}
+		else if ( id != null ) {
+			getIdentifierType().nullSafeSet( ps, id, index, session );
+			index += getIdentifierColumnSpan();
+		}
+
+		return index;
+
+	}
+
+	/**
+	 * Unmarshall the fields of a persistent instance from a result set,
+	 * without resolving associations or collections. Question: should
+	 * this really be here, or should it be sent back to Loader?
+	 */
+	public Object[] hydrate(
+			final ResultSet rs,
+	        final Serializable id,
+	        final Object object,
+	        final Loadable rootLoadable,
+	        final String[][] suffixedPropertyColumns,
+	        final boolean allProperties,
+	        final SessionImplementor session) throws SQLException, HibernateException {
+
+		if ( log.isTraceEnabled() ) {
+			log.trace( "Hydrating entity: " + MessageHelper.infoString( this, id, getFactory() ) );
+		}
+
+		final AbstractEntityPersister rootPersister = (AbstractEntityPersister) rootLoadable;
+
+		final boolean hasDeferred = rootPersister.hasSequentialSelect();
+		PreparedStatement sequentialSelect = null;
+		ResultSet sequentialResultSet = null;
+		boolean sequentialSelectEmpty = false;
+		try {
+
+			if ( hasDeferred ) {
+				final String sql = rootPersister.getSequentialSelect( getEntityName() );
+				if ( sql != null ) {
+					//TODO: I am not so sure about the exception handling in this bit!
+					sequentialSelect = session.getBatcher().prepareSelectStatement( sql );
+					rootPersister.getIdentifierType().nullSafeSet( sequentialSelect, id, 1, session );
+					sequentialResultSet = sequentialSelect.executeQuery();
+					if ( !sequentialResultSet.next() ) {
+						// TODO: Deal with the "optional" attribute in the <join> mapping;
+						// this code assumes that optional defaults to "true" because it
+						// doesn't actually seem to work in the fetch="join" code
+						//
+						// Note that actual proper handling of optional-ality here is actually
+						// more involved than this patch assumes.  Remember that we might have
+						// multiple <join/> mappings associated with a single entity.  Really
+						// a couple of things need to happen to properly handle optional here:
+						//  1) First and foremost, when handling multiple <join/>s, we really
+						//      should be using the entity root table as the driving table;
+						//      another option here would be to choose some non-optional joined
+						//      table to use as the driving table.  In all likelihood, just using
+						//      the root table is much simplier
+						//  2) Need to add the FK columns corresponding to each joined table
+						//      to the generated select list; these would then be used when
+						//      iterating the result set to determine whether all non-optional
+						//      data is present
+						// My initial thoughts on the best way to deal with this would be
+						// to introduce a new SequentialSelect abstraction that actually gets
+						// generated in the persisters (ok, SingleTable...) and utilized here.
+						// It would encapsulated all this required optional-ality checking...
+						sequentialSelectEmpty = true;
+					}
+				}
+			}
+
+			final String[] propNames = getPropertyNames();
+			final Type[] types = getPropertyTypes();
+			final Object[] values = new Object[types.length];
+			final boolean[] laziness = getPropertyLaziness();
+			final String[] propSubclassNames = getSubclassPropertySubclassNameClosure();
+
+			for ( int i = 0; i < types.length; i++ ) {
+				if ( !propertySelectable[i] ) {
+					values[i] = BackrefPropertyAccessor.UNKNOWN;
+				}
+				else if ( allProperties || !laziness[i] ) {
+					//decide which ResultSet to get the property value from:
+					final boolean propertyIsDeferred = hasDeferred &&
+							rootPersister.isSubclassPropertyDeferred( propNames[i], propSubclassNames[i] );
+					if ( propertyIsDeferred && sequentialSelectEmpty ) {
+						values[i] = null;
+					}
+					else {
+						final ResultSet propertyResultSet = propertyIsDeferred ? sequentialResultSet : rs;
+						final String[] cols = propertyIsDeferred ? propertyColumnAliases[i] : suffixedPropertyColumns[i];
+						values[i] = types[i].hydrate( propertyResultSet, cols, session, object );
+					}
+				}
+				else {
+					values[i] = LazyPropertyInitializer.UNFETCHED_PROPERTY;
+				}
+			}
+
+			if ( sequentialResultSet != null ) {
+				sequentialResultSet.close();
+			}
+
+			return values;
+
+		}
+		finally {
+			if ( sequentialSelect != null ) {
+				session.getBatcher().closeStatement( sequentialSelect );
+			}
+		}
+	}
+
+	protected boolean useInsertSelectIdentity() {
+		return !useGetGeneratedKeys() && getFactory().getDialect().supportsInsertSelectIdentity();
+	}
+
+	protected boolean useGetGeneratedKeys() {
+		return getFactory().getSettings().isGetGeneratedKeysEnabled();
+	}
+
+	protected String getSequentialSelect(String entityName) {
+		throw new UnsupportedOperationException("no sequential selects");
+	}
+
+	/**
+	 * Perform an SQL INSERT, and then retrieve a generated identifier.
+	 * <p/>
+	 * This form is used for PostInsertIdentifierGenerator-style ids (IDENTITY,
+	 * select, etc).
+	 */
+	protected Serializable insert(
+			final Object[] fields,
+	        final boolean[] notNull,
+	        String sql,
+	        final Object object,
+	        final SessionImplementor session) throws HibernateException {
+
+		if ( log.isTraceEnabled() ) {
+			log.trace( "Inserting entity: " + getEntityName() + " (native id)" );
+			if ( isVersioned() ) {
+				log.trace( "Version: " + Versioning.getVersion( fields, this ) );
+			}
+		}
+
+		Binder binder = new Binder() {
+			public void bindValues(PreparedStatement ps) throws SQLException {
+				dehydrate( null, fields, notNull, propertyColumnInsertable, 0, ps, session );
+			}
+			public Object getEntity() {
+				return object;
+			}
+		};
+		return identityDelegate.performInsert( sql, session, binder );
+	}
+
+	public String getIdentitySelectString() {
+		//TODO: cache this in an instvar
+		return getFactory().getDialect().getIdentitySelectString(
+				getTableName(0),
+				getKeyColumns(0)[0],
+				getIdentifierType().sqlTypes( getFactory() )[0]
+		);
+	}
+
+	public String getSelectByUniqueKeyString(String propertyName) {
+		return new SimpleSelect( getFactory().getDialect() )
+			.setTableName( getTableName(0) )
+			.addColumns( getKeyColumns(0) )
+			.addCondition( getPropertyColumnNames(propertyName), "=?" )
+			.toStatementString();
+	}
+
+	/**
+	 * Perform an SQL INSERT.
+	 * <p/>
+	 * This for is used for all non-root tables as well as the root table
+	 * in cases where the identifier value is known before the insert occurs.
+	 */
+	protected void insert(
+			final Serializable id,
+	        final Object[] fields,
+	        final boolean[] notNull,
+	        final int j,
+	        final String sql,
+	        final Object object,
+	        final SessionImplementor session) throws HibernateException {
+
+		if ( isInverseTable( j ) ) {
+			return;
+		}
+
+		//note: it is conceptually possible that a UserType could map null to
+		//	  a non-null value, so the following is arguable:
+		if ( isNullableTable( j ) && isAllNull( fields, j ) ) {
+			return;
+		}
+
+		if ( log.isTraceEnabled() ) {
+			log.trace( "Inserting entity: " + MessageHelper.infoString( this, id, getFactory() ) );
+			if ( j == 0 && isVersioned() ) {
+				log.trace( "Version: " + Versioning.getVersion( fields, this ) );
+			}
+		}
+
+		Expectation expectation = Expectations.appropriateExpectation( insertResultCheckStyles[j] );
+		boolean callable = isInsertCallable( j );
+		// we can't batch joined inserts, *especially* not if it is an identity insert;
+		// nor can we batch statements where the expectation is based on an output param
+		final boolean useBatch = j == 0 && expectation.canBeBatched();
+		try {
+
+			// Render the SQL query
+			final PreparedStatement insert;
+			if ( useBatch ) {
+				if ( callable ) {
+					insert = session.getBatcher().prepareBatchCallableStatement( sql );
+				}
+				else {
+					insert = session.getBatcher().prepareBatchStatement( sql );
+				}
+			}
+			else {
+				if ( callable ) {
+					insert = session.getBatcher().prepareCallableStatement( sql );
+				}
+				else {
+					insert = session.getBatcher().prepareStatement( sql );
+				}
+			}
+
+			try {
+				int index = 1;
+				index += expectation.prepare( insert );
+
+				// Write the values of fields onto the prepared statement - we MUST use the state at the time the
+				// insert was issued (cos of foreign key constraints). Not necessarily the object's current state
+
+				dehydrate( id, fields, null, notNull, propertyColumnInsertable, j, insert, session, index );
+
+				if ( useBatch ) {
+					// TODO : shouldnt inserts be Expectations.NONE?
+					session.getBatcher().addToBatch( expectation );
+				}
+				else {
+					expectation.verifyOutcome( insert.executeUpdate(), insert, -1 );
+				}
+
+			}
+			catch ( SQLException sqle ) {
+				if ( useBatch ) {
+					session.getBatcher().abortBatch( sqle );
+				}
+				throw sqle;
+			}
+			finally {
+				if ( !useBatch ) {
+					session.getBatcher().closeStatement( insert );
+				}
+			}
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not insert: " + MessageHelper.infoString( this ),
+					sql
+				);
+		}
+
+	}
+
+	/**
+	 * Perform an SQL UPDATE or SQL INSERT
+	 */
+	protected void updateOrInsert(
+			final Serializable id,
+	        final Object[] fields,
+	        final Object[] oldFields,
+	        final Object rowId,
+	        final boolean[] includeProperty,
+	        final int j,
+	        final Object oldVersion,
+	        final Object object,
+	        final String sql,
+	        final SessionImplementor session) throws HibernateException {
+
+		if ( !isInverseTable( j ) ) {
+
+			final boolean isRowToUpdate;
+			if ( isNullableTable( j ) && oldFields != null && isAllNull( oldFields, j ) ) {
+				//don't bother trying to update, we know there is no row there yet
+				isRowToUpdate = false;
+			}
+			else if ( isNullableTable( j ) && isAllNull( fields, j ) ) {
+				//if all fields are null, we might need to delete existing row
+				isRowToUpdate = true;
+				delete( id, oldVersion, j, object, getSQLDeleteStrings()[j], session, null );
+			}
+			else {
+				//there is probably a row there, so try to update
+				//if no rows were updated, we will find out
+				isRowToUpdate = update( id, fields, oldFields, rowId, includeProperty, j, oldVersion, object, sql, session );
+			}
+
+			if ( !isRowToUpdate && !isAllNull( fields, j ) ) {
+				// assume that the row was not there since it previously had only null
+				// values, so do an INSERT instead
+				//TODO: does not respect dynamic-insert
+				insert( id, fields, getPropertyInsertability(), j, getSQLInsertStrings()[j], object, session );
+			}
+
+		}
+
+	}
+
+	protected boolean update(
+			final Serializable id,
+	        final Object[] fields,
+	        final Object[] oldFields,
+	        final Object rowId,
+	        final boolean[] includeProperty,
+	        final int j,
+	        final Object oldVersion,
+	        final Object object,
+	        final String sql,
+	        final SessionImplementor session) throws HibernateException {
+
+		final boolean useVersion = j == 0 && isVersioned();
+		final Expectation expectation = Expectations.appropriateExpectation( updateResultCheckStyles[j] );
+		final boolean callable = isUpdateCallable( j );
+		final boolean useBatch = j == 0 && expectation.canBeBatched() && isBatchable(); //note: updates to joined tables can't be batched...
+
+		if ( log.isTraceEnabled() ) {
+			log.trace( "Updating entity: " + MessageHelper.infoString( this, id, getFactory() ) );
+			if ( useVersion ) {
+				log.trace( "Existing version: " + oldVersion + " -> New version: " + fields[getVersionProperty()] );
+			}
+		}
+
+		try {
+
+			int index = 1; // starting index
+			final PreparedStatement update;
+			if ( useBatch ) {
+				if ( callable ) {
+					update = session.getBatcher().prepareBatchCallableStatement( sql );
+				}
+				else {
+					update = session.getBatcher().prepareBatchStatement( sql );
+				}
+			}
+			else {
+				if ( callable ) {
+					update = session.getBatcher().prepareCallableStatement( sql );
+				}
+				else {
+					update = session.getBatcher().prepareStatement( sql );
+				}
+			}
+
+			try {
+
+				index+= expectation.prepare( update );
+
+				//Now write the values of fields onto the prepared statement
+				index = dehydrate( id, fields, rowId, includeProperty, propertyColumnUpdateable, j, update, session, index );
+
+				// Write any appropriate versioning conditional parameters
+				if ( useVersion && Versioning.OPTIMISTIC_LOCK_VERSION == entityMetamodel.getOptimisticLockMode() ) {
+					if ( checkVersion( includeProperty ) ) {
+						getVersionType().nullSafeSet( update, oldVersion, index, session );
+					}
+				}
+				else if ( entityMetamodel.getOptimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION && oldFields != null ) {
+					boolean[] versionability = getPropertyVersionability(); //TODO: is this really necessary????
+					boolean[] includeOldField = entityMetamodel.getOptimisticLockMode() == Versioning.OPTIMISTIC_LOCK_ALL ?
+							getPropertyUpdateability() : includeProperty;
+					Type[] types = getPropertyTypes();
+					for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
+						boolean include = includeOldField[i] &&
+								isPropertyOfTable( i, j ) &&
+								versionability[i]; //TODO: is this really necessary????
+						if ( include ) {
+							boolean[] settable = types[i].toColumnNullness( oldFields[i], getFactory() );
+							types[i].nullSafeSet(
+									update,
+									oldFields[i],
+									index,
+									settable,
+									session
+								);
+							index += ArrayHelper.countTrue(settable);
+						}
+					}
+				}
+
+				if ( useBatch ) {
+					session.getBatcher().addToBatch( expectation );
+					return true;
+				}
+				else {
+					return check( update.executeUpdate(), id, j, expectation, update );
+				}
+
+			}
+			catch ( SQLException sqle ) {
+				if ( useBatch ) {
+					session.getBatcher().abortBatch( sqle );
+				}
+				throw sqle;
+			}
+			finally {
+				if ( !useBatch ) {
+					session.getBatcher().closeStatement( update );
+				}
+			}
+
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not update: " + MessageHelper.infoString( this, id, getFactory() ),
+					sql
+				);
+		}
+	}
+
+	/**
+	 * Perform an SQL DELETE
+	 */
+	protected void delete(
+			final Serializable id,
+			final Object version,
+			final int j,
+			final Object object,
+			final String sql,
+			final SessionImplementor session,
+			final Object[] loadedState) throws HibernateException {
+
+		if ( isInverseTable( j ) ) {
+			return;
+		}
+
+		final boolean useVersion = j == 0 && isVersioned();
+		final boolean callable = isDeleteCallable( j );
+		final Expectation expectation = Expectations.appropriateExpectation( deleteResultCheckStyles[j] );
+		final boolean useBatch = j == 0 && isBatchable() && expectation.canBeBatched();
+
+		if ( log.isTraceEnabled() ) {
+			log.trace( "Deleting entity: " + MessageHelper.infoString( this, id, getFactory() ) );
+			if ( useVersion ) {
+				log.trace( "Version: " + version );
+			}
+		}
+
+		if ( isTableCascadeDeleteEnabled( j ) ) {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "delete handled by foreign key constraint: " + getTableName( j ) );
+			}
+			return; //EARLY EXIT!
+		}
+
+		try {
+
+			//Render the SQL query
+			PreparedStatement delete;
+			int index = 1;
+			if ( useBatch ) {
+				if ( callable ) {
+					delete = session.getBatcher().prepareBatchCallableStatement( sql );
+				}
+				else {
+					delete = session.getBatcher().prepareBatchStatement( sql );
+				}
+			}
+			else {
+				if ( callable ) {
+					delete = session.getBatcher().prepareCallableStatement( sql );
+				}
+				else {
+					delete = session.getBatcher().prepareStatement( sql );
+				}
+			}
+
+			try {
+
+				index += expectation.prepare( delete );
+
+				// Do the key. The key is immutable so we can use the _current_ object state - not necessarily
+				// the state at the time the delete was issued
+				getIdentifierType().nullSafeSet( delete, id, index, session );
+				index += getIdentifierColumnSpan();
+
+				// We should use the _current_ object state (ie. after any updates that occurred during flush)
+
+				if ( useVersion ) {
+					getVersionType().nullSafeSet( delete, version, index, session );
+				}
+				else if ( entityMetamodel.getOptimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION && loadedState != null ) {
+					boolean[] versionability = getPropertyVersionability();
+					Type[] types = getPropertyTypes();
+					for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
+						if ( isPropertyOfTable( i, j ) && versionability[i] ) {
+							// this property belongs to the table and it is not specifically
+							// excluded from optimistic locking by optimistic-lock="false"
+							boolean[] settable = types[i].toColumnNullness( loadedState[i], getFactory() );
+							types[i].nullSafeSet( delete, loadedState[i], index, settable, session );
+							index += ArrayHelper.countTrue( settable );
+						}
+					}
+				}
+
+				if ( useBatch ) {
+					session.getBatcher().addToBatch( expectation );
+				}
+				else {
+					check( delete.executeUpdate(), id, j, expectation, delete );
+				}
+
+			}
+			catch ( SQLException sqle ) {
+				if ( useBatch ) {
+					session.getBatcher().abortBatch( sqle );
+				}
+				throw sqle;
+			}
+			finally {
+				if ( !useBatch ) {
+					session.getBatcher().closeStatement( delete );
+				}
+			}
+
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not delete: " +
+					MessageHelper.infoString( this, id, getFactory() ),
+					sql
+				);
+
+		}
+
+	}
+
+	private String[] getUpdateStrings(boolean byRowId, boolean lazy) {
+		if ( byRowId ) {
+			return lazy ? getSQLLazyUpdateByRowIdStrings() : getSQLUpdateByRowIdStrings();
+		}
+		else {
+			return lazy ? getSQLLazyUpdateStrings() : getSQLUpdateStrings();
+		}
+	}
+
+	/**
+	 * Update an object
+	 */
+	public void update(
+			final Serializable id,
+	        final Object[] fields,
+	        final int[] dirtyFields,
+	        final boolean hasDirtyCollection,
+	        final Object[] oldFields,
+	        final Object oldVersion,
+	        final Object object,
+	        final Object rowId,
+	        final SessionImplementor session) throws HibernateException {
+
+		//note: dirtyFields==null means we had no snapshot, and we couldn't get one using select-before-update
+		//	  oldFields==null just means we had no snapshot to begin with (we might have used select-before-update to get the dirtyFields)
+
+		final boolean[] tableUpdateNeeded = getTableUpdateNeeded( dirtyFields, hasDirtyCollection );
+		final int span = getTableSpan();
+
+		final boolean[] propsToUpdate;
+		final String[] updateStrings;
+		if ( entityMetamodel.isDynamicUpdate() && dirtyFields != null ) {
+			// For the case of dynamic-update="true", we need to generate the UPDATE SQL
+			propsToUpdate = getPropertiesToUpdate( dirtyFields, hasDirtyCollection );
+			// don't need to check laziness (dirty checking algorithm handles that)
+			updateStrings = new String[span];
+			for ( int j = 0; j < span; j++ ) {
+				updateStrings[j] = tableUpdateNeeded[j] ?
+						generateUpdateString( propsToUpdate, j, oldFields, j == 0 && rowId != null ) :
+						null;
+			}
+		}
+		else {
+			// For the case of dynamic-update="false", or no snapshot, we use the static SQL
+			updateStrings = getUpdateStrings(
+					rowId != null,
+					hasUninitializedLazyProperties( object, session.getEntityMode() )
+				);
+			propsToUpdate = getPropertyUpdateability( object, session.getEntityMode() );
+		}
+
+		for ( int j = 0; j < span; j++ ) {
+			// Now update only the tables with dirty properties (and the table with the version number)
+			if ( tableUpdateNeeded[j] ) {
+				updateOrInsert(
+						id,
+						fields,
+						oldFields,
+						j == 0 ? rowId : null,
+						propsToUpdate,
+						j,
+						oldVersion,
+						object,
+						updateStrings[j],
+						session
+					);
+			}
+		}
+	}
+
+	public Serializable insert(Object[] fields, Object object, SessionImplementor session)
+			throws HibernateException {
+
+		final int span = getTableSpan();
+		final Serializable id;
+		if ( entityMetamodel.isDynamicInsert() ) {
+			// For the case of dynamic-insert="true", we need to generate the INSERT SQL
+			boolean[] notNull = getPropertiesToInsert( fields );
+			id = insert( fields, notNull, generateInsertString( true, notNull ), object, session );
+			for ( int j = 1; j < span; j++ ) {
+				insert( id, fields, notNull, j, generateInsertString( notNull, j ), object, session );
+			}
+		}
+		else {
+			// For the case of dynamic-insert="false", use the static SQL
+			id = insert( fields, getPropertyInsertability(), getSQLIdentityInsertString(), object, session );
+			for ( int j = 1; j < span; j++ ) {
+				insert( id, fields, getPropertyInsertability(), j, getSQLInsertStrings()[j], object, session );
+			}
+		}
+		return id;
+	}
+
+	public void insert(Serializable id, Object[] fields, Object object, SessionImplementor session)
+			throws HibernateException {
+
+		final int span = getTableSpan();
+		if ( entityMetamodel.isDynamicInsert() ) {
+			// For the case of dynamic-insert="true", we need to generate the INSERT SQL
+			boolean[] notNull = getPropertiesToInsert( fields );
+			for ( int j = 0; j < span; j++ ) {
+				insert( id, fields, notNull, j, generateInsertString( notNull, j ), object, session );
+			}
+		}
+		else {
+			// For the case of dynamic-insert="false", use the static SQL
+			for ( int j = 0; j < span; j++ ) {
+				insert( id, fields, getPropertyInsertability(), j, getSQLInsertStrings()[j], object, session );
+			}
+		}
+	}
+
+	/**
+	 * Delete an object
+	 */
+	public void delete(Serializable id, Object version, Object object, SessionImplementor session)
+			throws HibernateException {
+		final int span = getTableSpan();
+		boolean isImpliedOptimisticLocking = !entityMetamodel.isVersioned() && entityMetamodel.getOptimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION;
+		Object[] loadedState = null;
+		if ( isImpliedOptimisticLocking ) {
+			// need to treat this as if it where optimistic-lock="all" (dirty does *not* make sense);
+			// first we need to locate the "loaded" state
+			//
+			// Note, it potentially could be a proxy, so perform the location the safe way...
+			EntityKey key = new EntityKey( id, this, session.getEntityMode() );
+			Object entity = session.getPersistenceContext().getEntity( key );
+			if ( entity != null ) {
+				EntityEntry entry = session.getPersistenceContext().getEntry( entity );
+				loadedState = entry.getLoadedState();
+			}
+		}
+
+		final String[] deleteStrings;
+		if ( isImpliedOptimisticLocking && loadedState != null ) {
+			// we need to utilize dynamic delete statements
+			deleteStrings = generateSQLDeletStrings( loadedState );
+		}
+		else {
+			// otherwise, utilize the static delete statements
+			deleteStrings = getSQLDeleteStrings();
+		}
+
+		for ( int j = span - 1; j >= 0; j-- ) {
+			delete( id, version, j, object, deleteStrings[j], session, loadedState );
+		}
+
+	}
+
+	private String[] generateSQLDeletStrings(Object[] loadedState) {
+		int span = getTableSpan();
+		String[] deleteStrings = new String[span];
+		for ( int j = span - 1; j >= 0; j-- ) {
+			Delete delete = new Delete()
+					.setTableName( getTableName( j ) )
+					.setPrimaryKeyColumnNames( getKeyColumns( j ) );
+			if ( getFactory().getSettings().isCommentsEnabled() ) {
+				delete.setComment( "delete " + getEntityName() + " [" + j + "]" );
+			}
+
+			boolean[] versionability = getPropertyVersionability();
+			Type[] types = getPropertyTypes();
+			for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
+				if ( isPropertyOfTable( i, j ) && versionability[i] ) {
+					// this property belongs to the table and it is not specifically
+					// excluded from optimistic locking by optimistic-lock="false"
+					String[] propertyColumnNames = getPropertyColumnNames( i );
+					boolean[] propertyNullness = types[i].toColumnNullness( loadedState[i], getFactory() );
+					for ( int k = 0; k < propertyNullness.length; k++ ) {
+						if ( propertyNullness[k] ) {
+							delete.addWhereFragment( propertyColumnNames[k] + " = ?" );
+						}
+						else {
+							delete.addWhereFragment( propertyColumnNames[k] + " is null" );
+						}
+					}
+				}
+			}
+			deleteStrings[j] = delete.toStatementString();
+		}
+		return deleteStrings;
+	}
+
+	protected void logStaticSQL() {
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Static SQL for entity: " + getEntityName() );
+			if ( sqlLazySelectString != null ) {
+				log.debug( " Lazy select: " + sqlLazySelectString );
+			}
+			if ( sqlVersionSelectString != null ) {
+				log.debug( " Version select: " + sqlVersionSelectString );
+			}
+			if ( sqlSnapshotSelectString != null ) {
+				log.debug( " Snapshot select: " + sqlSnapshotSelectString );
+			}
+			for ( int j = 0; j < getTableSpan(); j++ ) {
+				log.debug( " Insert " + j + ": " + getSQLInsertStrings()[j] );
+				log.debug( " Update " + j + ": " + getSQLUpdateStrings()[j] );
+				log.debug( " Delete " + j + ": " + getSQLDeleteStrings()[j] );
+
+			}
+			if ( sqlIdentityInsertString != null ) {
+				log.debug( " Identity insert: " + sqlIdentityInsertString );
+			}
+			if ( sqlUpdateByRowIdString != null ) {
+				log.debug( " Update by row id (all fields): " + sqlUpdateByRowIdString );
+			}
+			if ( sqlLazyUpdateByRowIdString != null ) {
+				log.debug( " Update by row id (non-lazy fields): " + sqlLazyUpdateByRowIdString );
+			}
+			if ( sqlInsertGeneratedValuesSelectString != null ) {
+				log.debug( "Insert-generated property select: " + sqlInsertGeneratedValuesSelectString );
+			}
+			if ( sqlUpdateGeneratedValuesSelectString != null ) {
+				log.debug( "Update-generated property select: " + sqlUpdateGeneratedValuesSelectString );
+			}
+		}
+	}
+
+	public String filterFragment(String alias, Map enabledFilters) throws MappingException {
+		final StringBuffer sessionFilterFragment = new StringBuffer();
+		filterHelper.render( sessionFilterFragment, generateFilterConditionAlias( alias ), enabledFilters );
+
+		return sessionFilterFragment.append( filterFragment( alias ) ).toString();
+	}
+
+	public String generateFilterConditionAlias(String rootAlias) {
+		return rootAlias;
+	}
+
+	public String oneToManyFilterFragment(String alias) throws MappingException {
+		return "";
+	}
+
+	public String fromJoinFragment(String alias, boolean innerJoin, boolean includeSubclasses) {
+		return getSubclassTableSpan() == 1 ?
+				"" : //just a performance opt!
+				createJoin( alias, innerJoin, includeSubclasses ).toFromFragmentString();
+	}
+
+	public String whereJoinFragment(String alias, boolean innerJoin, boolean includeSubclasses) {
+		return getSubclassTableSpan() == 1 ?
+				"" : //just a performance opt!
+				createJoin( alias, innerJoin, includeSubclasses ).toWhereFragmentString();
+	}
+
+	protected boolean isSubclassTableLazy(int j) {
+		return false;
+	}
+
+	protected JoinFragment createJoin(String name, boolean innerJoin, boolean includeSubclasses) {
+		final String[] idCols = StringHelper.qualify( name, getIdentifierColumnNames() ); //all joins join to the pk of the driving table
+		final JoinFragment join = getFactory().getDialect().createOuterJoinFragment();
+		final int tableSpan = getSubclassTableSpan();
+		for ( int j = 1; j < tableSpan; j++ ) { //notice that we skip the first table; it is the driving table!
+			final boolean joinIsIncluded = isClassOrSuperclassTable( j ) ||
+					( includeSubclasses && !isSubclassTableSequentialSelect( j ) && !isSubclassTableLazy( j ) );
+			if ( joinIsIncluded ) {
+				join.addJoin( getSubclassTableName( j ),
+						generateTableAlias( name, j ),
+						idCols,
+						getSubclassTableKeyColumns( j ),
+						innerJoin && isClassOrSuperclassTable( j ) && !isInverseTable( j ) && !isNullableTable( j ) ?
+						JoinFragment.INNER_JOIN : //we can inner join to superclass tables (the row MUST be there)
+						JoinFragment.LEFT_OUTER_JOIN //we can never inner join to subclass tables
+					);
+			}
+		}
+		return join;
+	}
+
+	protected JoinFragment createJoin(int[] tableNumbers, String drivingAlias) {
+		final String[] keyCols = StringHelper.qualify( drivingAlias, getSubclassTableKeyColumns( tableNumbers[0] ) );
+		final JoinFragment jf = getFactory().getDialect().createOuterJoinFragment();
+		for ( int i = 1; i < tableNumbers.length; i++ ) { //skip the driving table
+			final int j = tableNumbers[i];
+			jf.addJoin( getSubclassTableName( j ),
+					generateTableAlias( getRootAlias(), j ),
+					keyCols,
+					getSubclassTableKeyColumns( j ),
+					isInverseSubclassTable( j ) || isNullableSubclassTable( j ) ?
+					JoinFragment.LEFT_OUTER_JOIN :
+					JoinFragment.INNER_JOIN );
+		}
+		return jf;
+	}
+
+	protected SelectFragment createSelect(final int[] subclassColumnNumbers,
+										  final int[] subclassFormulaNumbers) {
+
+		SelectFragment selectFragment = new SelectFragment();
+
+		int[] columnTableNumbers = getSubclassColumnTableNumberClosure();
+		String[] columnAliases = getSubclassColumnAliasClosure();
+		String[] columns = getSubclassColumnClosure();
+		for ( int i = 0; i < subclassColumnNumbers.length; i++ ) {
+			if ( subclassColumnSelectableClosure[i] ) {
+				int columnNumber = subclassColumnNumbers[i];
+				final String subalias = generateTableAlias( getRootAlias(), columnTableNumbers[columnNumber] );
+				selectFragment.addColumn( subalias, columns[columnNumber], columnAliases[columnNumber] );
+			}
+		}
+
+		int[] formulaTableNumbers = getSubclassFormulaTableNumberClosure();
+		String[] formulaTemplates = getSubclassFormulaTemplateClosure();
+		String[] formulaAliases = getSubclassFormulaAliasClosure();
+		for ( int i = 0; i < subclassFormulaNumbers.length; i++ ) {
+			int formulaNumber = subclassFormulaNumbers[i];
+			final String subalias = generateTableAlias( getRootAlias(), formulaTableNumbers[formulaNumber] );
+			selectFragment.addFormula( subalias, formulaTemplates[formulaNumber], formulaAliases[formulaNumber] );
+		}
+
+		return selectFragment;
+	}
+
+	protected String createFrom(int tableNumber, String alias) {
+		return getSubclassTableName( tableNumber ) + ' ' + alias;
+	}
+
+	protected String createWhereByKey(int tableNumber, String alias) {
+		//TODO: move to .sql package, and refactor with similar things!
+		return StringHelper.join( "=? and ",
+				StringHelper.qualify( alias, getSubclassTableKeyColumns( tableNumber ) ) ) + "=?";
+	}
+
+	protected String renderSelect(
+			final int[] tableNumbers,
+	        final int[] columnNumbers,
+	        final int[] formulaNumbers) {
+
+		Arrays.sort( tableNumbers ); //get 'em in the right order (not that it really matters)
+
+		//render the where and from parts
+		int drivingTable = tableNumbers[0];
+		final String drivingAlias = generateTableAlias( getRootAlias(), drivingTable ); //we *could* regerate this inside each called method!
+		final String where = createWhereByKey( drivingTable, drivingAlias );
+		final String from = createFrom( drivingTable, drivingAlias );
+
+		//now render the joins
+		JoinFragment jf = createJoin( tableNumbers, drivingAlias );
+
+		//now render the select clause
+		SelectFragment selectFragment = createSelect( columnNumbers, formulaNumbers );
+
+		//now tie it all together
+		Select select = new Select( getFactory().getDialect() );
+		select.setSelectClause( selectFragment.toFragmentString().substring( 2 ) );
+		select.setFromClause( from );
+		select.setWhereClause( where );
+		select.setOuterJoins( jf.toFromFragmentString(), jf.toWhereFragmentString() );
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			select.setComment( "sequential select " + getEntityName() );
+		}
+		return select.toStatementString();
+	}
+
+	private String getRootAlias() {
+		return StringHelper.generateAlias( getEntityName() );
+	}
+
+	protected void postConstruct(Mapping mapping) throws MappingException {
+		initPropertyPaths(mapping);
+
+		//insert/update/delete SQL
+		final int joinSpan = getTableSpan();
+		sqlDeleteStrings = new String[joinSpan];
+		sqlInsertStrings = new String[joinSpan];
+		sqlUpdateStrings = new String[joinSpan];
+		sqlLazyUpdateStrings = new String[joinSpan];
+
+		sqlUpdateByRowIdString = rowIdName == null ?
+				null :
+				generateUpdateString( getPropertyUpdateability(), 0, true );
+		sqlLazyUpdateByRowIdString = rowIdName == null ?
+				null :
+				generateUpdateString( getNonLazyPropertyUpdateability(), 0, true );
+
+		for ( int j = 0; j < joinSpan; j++ ) {
+			sqlInsertStrings[j] = customSQLInsert[j] == null ?
+					generateInsertString( getPropertyInsertability(), j ) :
+					customSQLInsert[j];
+			sqlUpdateStrings[j] = customSQLUpdate[j] == null ?
+					generateUpdateString( getPropertyUpdateability(), j, false ) :
+					customSQLUpdate[j];
+			sqlLazyUpdateStrings[j] = customSQLUpdate[j] == null ?
+					generateUpdateString( getNonLazyPropertyUpdateability(), j, false ) :
+					customSQLUpdate[j];
+			sqlDeleteStrings[j] = customSQLDelete[j] == null ?
+					generateDeleteString( j ) :
+					customSQLDelete[j];
+		}
+
+		tableHasColumns = new boolean[joinSpan];
+		for ( int j = 0; j < joinSpan; j++ ) {
+			tableHasColumns[j] = sqlUpdateStrings[j] != null;
+		}
+
+		//select SQL
+		sqlSnapshotSelectString = generateSnapshotSelectString();
+		sqlLazySelectString = generateLazySelectString();
+		sqlVersionSelectString = generateSelectVersionString();
+		if ( hasInsertGeneratedProperties() ) {
+			sqlInsertGeneratedValuesSelectString = generateInsertGeneratedValuesSelectString();
+		}
+		if ( hasUpdateGeneratedProperties() ) {
+			sqlUpdateGeneratedValuesSelectString = generateUpdateGeneratedValuesSelectString();
+		}
+		if ( isIdentifierAssignedByInsert() ) {
+			identityDelegate = ( ( PostInsertIdentifierGenerator ) getIdentifierGenerator() )
+					.getInsertGeneratedIdentifierDelegate( this, getFactory().getDialect(), useGetGeneratedKeys() );
+			sqlIdentityInsertString = customSQLInsert[0] == null
+					? generateIdentityInsertString( getPropertyInsertability() )
+					: customSQLInsert[0];
+		}
+		else {
+			sqlIdentityInsertString = null;
+		}
+
+		logStaticSQL();
+
+	}
+
+	public void postInstantiate() throws MappingException {
+
+		createLoaders();
+		createUniqueKeyLoaders();
+		createQueryLoader();
+
+	}
+
+	private void createLoaders() {
+		loaders.put( LockMode.NONE, createEntityLoader( LockMode.NONE ) );
+
+		UniqueEntityLoader readLoader = createEntityLoader( LockMode.READ );
+		loaders.put( LockMode.READ, readLoader );
+
+		//TODO: inexact, what we really need to know is: are any outer joins used?
+		boolean disableForUpdate = getSubclassTableSpan() > 1 &&
+				hasSubclasses() &&
+				!getFactory().getDialect().supportsOuterJoinForUpdate();
+
+		loaders.put(
+				LockMode.UPGRADE,
+				disableForUpdate ?
+						readLoader :
+						createEntityLoader( LockMode.UPGRADE )
+			);
+		loaders.put(
+				LockMode.UPGRADE_NOWAIT,
+				disableForUpdate ?
+						readLoader :
+						createEntityLoader( LockMode.UPGRADE_NOWAIT )
+			);
+		loaders.put(
+				LockMode.FORCE,
+				disableForUpdate ?
+						readLoader :
+						createEntityLoader( LockMode.FORCE )
+			);
+
+		loaders.put(
+				"merge",
+				new CascadeEntityLoader( this, CascadingAction.MERGE, getFactory() )
+			);
+		loaders.put(
+				"refresh",
+				new CascadeEntityLoader( this, CascadingAction.REFRESH, getFactory() )
+			);
+	}
+
+	protected void createQueryLoader() {
+		if ( loaderName != null ) {
+			queryLoader = new NamedQueryLoader( loaderName, this );
+		}
+	}
+
+	/**
+	 * Load an instance using either the <tt>forUpdateLoader</tt> or the outer joining <tt>loader</tt>,
+	 * depending upon the value of the <tt>lock</tt> parameter
+	 */
+	public Object load(Serializable id, Object optionalObject, LockMode lockMode, SessionImplementor session)
+			throws HibernateException {
+
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"Fetching entity: " +
+					MessageHelper.infoString( this, id, getFactory() )
+				);
+		}
+
+		final UniqueEntityLoader loader = getAppropriateLoader( lockMode, session );
+		return loader.load( id, optionalObject, session );
+	}
+
+	private UniqueEntityLoader getAppropriateLoader(LockMode lockMode, SessionImplementor session) {
+		final Map enabledFilters = session.getEnabledFilters();
+		if ( queryLoader != null ) {
+			return queryLoader;
+		}
+		else if ( enabledFilters == null || enabledFilters.isEmpty() ) {
+			if ( session.getFetchProfile()!=null && LockMode.UPGRADE.greaterThan(lockMode) ) {
+				return (UniqueEntityLoader) loaders.get( session.getFetchProfile() );
+			}
+			else {
+				return (UniqueEntityLoader) loaders.get( lockMode );
+			}
+		}
+		else {
+			return createEntityLoader( lockMode, enabledFilters );
+		}
+	}
+
+	private boolean isAllNull(Object[] array, int tableNumber) {
+		for ( int i = 0; i < array.length; i++ ) {
+			if ( isPropertyOfTable( i, tableNumber ) && array[i] != null ) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	public boolean isSubclassPropertyNullable(int i) {
+		return subclassPropertyNullabilityClosure[i];
+	}
+
+	/**
+	 * Transform the array of property indexes to an array of booleans,
+	 * true when the property is dirty
+	 */
+	protected final boolean[] getPropertiesToUpdate(final int[] dirtyProperties, final boolean hasDirtyCollection) {
+		final boolean[] propsToUpdate = new boolean[ entityMetamodel.getPropertySpan() ];
+		final boolean[] updateability = getPropertyUpdateability(); //no need to check laziness, dirty checking handles that
+		for ( int j = 0; j < dirtyProperties.length; j++ ) {
+			int property = dirtyProperties[j];
+			if ( updateability[property] ) {
+				propsToUpdate[property] = true;
+			}
+		}
+		if ( isVersioned() ) {
+			propsToUpdate[ getVersionProperty() ] =
+				Versioning.isVersionIncrementRequired( dirtyProperties, hasDirtyCollection, getPropertyVersionability() );
+		}
+		return propsToUpdate;
+	}
+
+	/**
+	 * Transform the array of property indexes to an array of booleans,
+	 * true when the property is insertable and non-null
+	 */
+	protected boolean[] getPropertiesToInsert(Object[] fields) {
+		boolean[] notNull = new boolean[fields.length];
+		boolean[] insertable = getPropertyInsertability();
+		for ( int i = 0; i < fields.length; i++ ) {
+			notNull[i] = insertable[i] && fields[i] != null;
+		}
+		return notNull;
+	}
+
+	/**
+	 * Locate the property-indices of all properties considered to be dirty.
+	 *
+	 * @param currentState The current state of the entity (the state to be checked).
+	 * @param previousState The previous state of the entity (the state to be checked against).
+	 * @param entity The entity for which we are checking state dirtiness.
+	 * @param session The session in which the check is ccurring.
+	 * @return <tt>null</tt> or the indices of the dirty properties
+	 * @throws HibernateException
+	 */
+	public int[] findDirty(Object[] currentState, Object[] previousState, Object entity, SessionImplementor session)
+	throws HibernateException {
+		int[] props = TypeFactory.findDirty(
+				entityMetamodel.getProperties(),
+				currentState,
+				previousState,
+				propertyColumnUpdateable,
+				hasUninitializedLazyProperties( entity, session.getEntityMode() ),
+				session
+			);
+		if ( props == null ) {
+			return null;
+		}
+		else {
+			logDirtyProperties( props );
+			return props;
+		}
+	}
+
+	/**
+	 * Locate the property-indices of all properties considered to be dirty.
+	 *
+	 * @param old The old state of the entity.
+	 * @param current The current state of the entity.
+	 * @param entity The entity for which we are checking state modification.
+	 * @param session The session in which the check is ccurring.
+	 * @return <tt>null</tt> or the indices of the modified properties
+	 * @throws HibernateException
+	 */
+	public int[] findModified(Object[] old, Object[] current, Object entity, SessionImplementor session)
+	throws HibernateException {
+		int[] props = TypeFactory.findModified(
+				entityMetamodel.getProperties(),
+				current,
+				old,
+				propertyColumnUpdateable,
+				hasUninitializedLazyProperties( entity, session.getEntityMode() ),
+				session
+			);
+		if ( props == null ) {
+			return null;
+		}
+		else {
+			logDirtyProperties( props );
+			return props;
+		}
+	}
+
+	/**
+	 * Which properties appear in the SQL update?
+	 * (Initialized, updateable ones!)
+	 */
+	protected boolean[] getPropertyUpdateability(Object entity, EntityMode entityMode) {
+		return hasUninitializedLazyProperties( entity, entityMode ) ?
+				getNonLazyPropertyUpdateability() :
+				getPropertyUpdateability();
+	}
+
+	private void logDirtyProperties(int[] props) {
+		if ( log.isTraceEnabled() ) {
+			for ( int i = 0; i < props.length; i++ ) {
+				String propertyName = entityMetamodel.getProperties()[ props[i] ].getName();
+				log.trace( StringHelper.qualify( getEntityName(), propertyName ) + " is dirty" );
+			}
+		}
+	}
+
+	protected EntityTuplizer getTuplizer(SessionImplementor session) {
+		return getTuplizer( session.getEntityMode() );
+	}
+
+	protected EntityTuplizer getTuplizer(EntityMode entityMode) {
+		return entityMetamodel.getTuplizer( entityMode );
+	}
+
+	public SessionFactoryImplementor getFactory() {
+		return factory;
+	}
+
+	public EntityMetamodel getEntityMetamodel() {
+		return entityMetamodel;
+	}
+
+	public boolean hasCache() {
+		return cacheAccessStrategy != null;
+	}
+
+	public EntityRegionAccessStrategy getCacheAccessStrategy() {
+		return cacheAccessStrategy;
+	}
+
+	public CacheEntryStructure getCacheEntryStructure() {
+		return cacheEntryStructure;
+	}
+
+	public Comparator getVersionComparator() {
+		return isVersioned() ? getVersionType().getComparator() : null;
+	}
+
+	// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	public final String getEntityName() {
+		return entityMetamodel.getName();
+	}
+
+	public EntityType getEntityType() {
+		return entityMetamodel.getEntityType();
+	}
+
+	private String getSubclassEntityName(Class clazz) {
+		return ( String ) entityNameBySubclass.get( clazz );
+	}
+
+	public boolean isPolymorphic() {
+		return entityMetamodel.isPolymorphic();
+	}
+
+	public boolean isInherited() {
+		return entityMetamodel.isInherited();
+	}
+
+	public boolean hasCascades() {
+		return entityMetamodel.hasCascades();
+	}
+
+	public boolean hasIdentifierProperty() {
+		return !entityMetamodel.getIdentifierProperty().isVirtual();
+	}
+
+	public VersionType getVersionType() {
+		return ( VersionType ) locateVersionType();
+	}
+
+	private Type locateVersionType() {
+		return entityMetamodel.getVersionProperty() == null ?
+				null :
+				entityMetamodel.getVersionProperty().getType();
+	}
+
+	public int getVersionProperty() {
+		return entityMetamodel.getVersionPropertyIndex();
+	}
+
+	public boolean isVersioned() {
+		return entityMetamodel.isVersioned();
+	}
+
+	public boolean isIdentifierAssignedByInsert() {
+		return entityMetamodel.getIdentifierProperty().isIdentifierAssignedByInsert();
+	}
+
+	public boolean hasLazyProperties() {
+		return entityMetamodel.hasLazyProperties();
+	}
+
+//	public boolean hasUninitializedLazyProperties(Object entity) {
+//		if ( hasLazyProperties() ) {
+//			InterceptFieldCallback callback = ( ( InterceptFieldEnabled ) entity ).getInterceptFieldCallback();
+//			return callback != null && !( ( FieldInterceptor ) callback ).isInitialized();
+//		}
+//		else {
+//			return false;
+//		}
+//	}
+
+	public void afterReassociate(Object entity, SessionImplementor session) {
+		//if ( hasLazyProperties() ) {
+		if ( FieldInterceptionHelper.isInstrumented( entity ) ) {
+			FieldInterceptor interceptor = FieldInterceptionHelper.extractFieldInterceptor( entity );
+			if ( interceptor != null ) {
+				interceptor.setSession( session );
+			}
+			else {
+				FieldInterceptor fieldInterceptor = FieldInterceptionHelper.injectFieldInterceptor(
+						entity,
+						getEntityName(),
+						null,
+						session
+				);
+				fieldInterceptor.dirty();
+			}
+		}
+	}
+
+	public Boolean isTransient(Object entity, SessionImplementor session) throws HibernateException {
+		final Serializable id;
+		if ( canExtractIdOutOfEntity() ) {
+			id = getIdentifier( entity, session.getEntityMode() );
+		}
+		else {
+			id = null;
+		}
+		// we *always* assume an instance with a null
+		// identifier or no identifier property is unsaved!
+		if ( id == null ) {
+			return Boolean.TRUE;
+		}
+
+		// check the version unsaved-value, if appropriate
+		final Object version = getVersion( entity, session.getEntityMode() );
+		if ( isVersioned() ) {
+			// let this take precedence if defined, since it works for
+			// assigned identifiers
+			Boolean result = entityMetamodel.getVersionProperty()
+					.getUnsavedValue().isUnsaved( version );
+			if ( result != null ) {
+				return result;
+			}
+		}
+
+		// check the id unsaved-value
+		Boolean result = entityMetamodel.getIdentifierProperty()
+				.getUnsavedValue().isUnsaved( id );
+		if ( result != null ) {
+			return result;
+		}
+
+		// check to see if it is in the second-level cache
+		if ( hasCache() ) {
+			CacheKey ck = new CacheKey(
+					id,
+					getIdentifierType(),
+					getRootEntityName(),
+					session.getEntityMode(),
+					session.getFactory()
+				);
+			if ( getCacheAccessStrategy().get( ck, session.getTimestamp() ) != null ) {
+				return Boolean.FALSE;
+			}
+		}
+
+		return null;
+	}
+
+	public boolean hasCollections() {
+		return entityMetamodel.hasCollections();
+	}
+
+	public boolean hasMutableProperties() {
+		return entityMetamodel.hasMutableProperties();
+	}
+
+	public boolean isMutable() {
+		return entityMetamodel.isMutable();
+	}
+
+	public boolean isAbstract() {
+		return entityMetamodel.isAbstract();
+	}
+
+	public boolean hasSubclasses() {
+		return entityMetamodel.hasSubclasses();
+	}
+
+	public boolean hasProxy() {
+		return entityMetamodel.isLazy();
+	}
+
+	public IdentifierGenerator getIdentifierGenerator() throws HibernateException {
+		return entityMetamodel.getIdentifierProperty().getIdentifierGenerator();
+	}
+
+	public String getRootEntityName() {
+		return entityMetamodel.getRootName();
+	}
+
+	public ClassMetadata getClassMetadata() {
+		return this;
+	}
+
+	public String getMappedSuperclass() {
+		return entityMetamodel.getSuperclass();
+	}
+
+	public boolean isExplicitPolymorphism() {
+		return entityMetamodel.isExplicitPolymorphism();
+	}
+
+	protected boolean useDynamicUpdate() {
+		return entityMetamodel.isDynamicUpdate();
+	}
+
+	protected boolean useDynamicInsert() {
+		return entityMetamodel.isDynamicInsert();
+	}
+
+	protected boolean hasEmbeddedCompositeIdentifier() {
+		return entityMetamodel.getIdentifierProperty().isEmbedded();
+	}
+
+	public boolean canExtractIdOutOfEntity() {
+		return hasIdentifierProperty() || hasEmbeddedCompositeIdentifier() || hasIdentifierMapper();
+	}
+
+	private boolean hasIdentifierMapper() {
+		return entityMetamodel.getIdentifierProperty().hasIdentifierMapper();
+	}
+
+	public String[] getKeyColumnNames() {
+		return getIdentifierColumnNames();
+	}
+
+	public String getName() {
+		return getEntityName();
+	}
+
+	public boolean isCollection() {
+		return false;
+	}
+
+	public boolean consumesEntityAlias() {
+		return true;
+	}
+
+	public boolean consumesCollectionAlias() {
+		return false;
+	}
+
+	public Type getPropertyType(String propertyName) throws MappingException {
+		return propertyMapping.toType(propertyName);
+	}
+
+	public Type getType() {
+		return entityMetamodel.getEntityType();
+	}
+
+	public boolean isSelectBeforeUpdateRequired() {
+		return entityMetamodel.isSelectBeforeUpdate();
+	}
+
+	protected final int optimisticLockMode() {
+		return entityMetamodel.getOptimisticLockMode();
+	}
+
+	public Object createProxy(Serializable id, SessionImplementor session) throws HibernateException {
+		return entityMetamodel.getTuplizer( session.getEntityMode() )
+				.createProxy( id, session );
+	}
+
+	public String toString() {
+		return StringHelper.unqualify( getClass().getName() ) +
+				'(' + entityMetamodel.getName() + ')';
+	}
+
+	public final String selectFragment(
+			Joinable rhs,
+			String rhsAlias,
+			String lhsAlias,
+			String entitySuffix,
+			String collectionSuffix,
+			boolean includeCollectionColumns) {
+		return selectFragment( lhsAlias, entitySuffix );
+	}
+
+	public boolean isInstrumented(EntityMode entityMode) {
+		EntityTuplizer tuplizer = entityMetamodel.getTuplizerOrNull(entityMode);
+		return tuplizer!=null && tuplizer.isInstrumented();
+	}
+
+	public boolean hasInsertGeneratedProperties() {
+		return entityMetamodel.hasInsertGeneratedValues();
+	}
+
+	public boolean hasUpdateGeneratedProperties() {
+		return entityMetamodel.hasUpdateGeneratedValues();
+	}
+
+	public boolean isVersionPropertyGenerated() {
+		return isVersioned() && ( getPropertyUpdateGenerationInclusions() [ getVersionProperty() ] != ValueInclusion.NONE );
+	}
+
+	public boolean isVersionPropertyInsertable() {
+		return isVersioned() && getPropertyInsertability() [ getVersionProperty() ];
+	}
+
+	public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) {
+		getTuplizer( session ).afterInitialize( entity, lazyPropertiesAreUnfetched, session );
+	}
+
+	public String[] getPropertyNames() {
+		return entityMetamodel.getPropertyNames();
+	}
+
+	public Type[] getPropertyTypes() {
+		return entityMetamodel.getPropertyTypes();
+	}
+
+	public boolean[] getPropertyLaziness() {
+		return entityMetamodel.getPropertyLaziness();
+	}
+
+	public boolean[] getPropertyUpdateability() {
+		return entityMetamodel.getPropertyUpdateability();
+	}
+
+	public boolean[] getPropertyCheckability() {
+		return entityMetamodel.getPropertyCheckability();
+	}
+
+	public boolean[] getNonLazyPropertyUpdateability() {
+		return entityMetamodel.getNonlazyPropertyUpdateability();
+	}
+
+	public boolean[] getPropertyInsertability() {
+		return entityMetamodel.getPropertyInsertability();
+	}
+
+	public ValueInclusion[] getPropertyInsertGenerationInclusions() {
+		return entityMetamodel.getPropertyInsertGenerationInclusions();
+	}
+
+	public ValueInclusion[] getPropertyUpdateGenerationInclusions() {
+		return entityMetamodel.getPropertyUpdateGenerationInclusions();
+	}
+
+	public boolean[] getPropertyNullability() {
+		return entityMetamodel.getPropertyNullability();
+	}
+
+	public boolean[] getPropertyVersionability() {
+		return entityMetamodel.getPropertyVersionability();
+	}
+
+	public CascadeStyle[] getPropertyCascadeStyles() {
+		return entityMetamodel.getCascadeStyles();
+	}
+
+	public final Class getMappedClass(EntityMode entityMode) {
+		Tuplizer tup = entityMetamodel.getTuplizerOrNull(entityMode);
+		return tup==null ? null : tup.getMappedClass();
+	}
+
+	public boolean implementsLifecycle(EntityMode entityMode) {
+		return getTuplizer( entityMode ).isLifecycleImplementor();
+	}
+
+	public boolean implementsValidatable(EntityMode entityMode) {
+		return getTuplizer( entityMode ).isValidatableImplementor();
+	}
+
+	public Class getConcreteProxyClass(EntityMode entityMode) {
+		return getTuplizer( entityMode ).getConcreteProxyClass();
+	}
+
+	public void setPropertyValues(Object object, Object[] values, EntityMode entityMode)
+			throws HibernateException {
+		getTuplizer( entityMode ).setPropertyValues( object, values );
+	}
+
+	public void setPropertyValue(Object object, int i, Object value, EntityMode entityMode)
+			throws HibernateException {
+		getTuplizer( entityMode ).setPropertyValue( object, i, value );
+	}
+
+	public Object[] getPropertyValues(Object object, EntityMode entityMode)
+			throws HibernateException {
+		return getTuplizer( entityMode ).getPropertyValues( object );
+	}
+
+	public Object getPropertyValue(Object object, int i, EntityMode entityMode)
+			throws HibernateException {
+		return getTuplizer( entityMode ).getPropertyValue( object , i );
+	}
+
+	public Object getPropertyValue(Object object, String propertyName, EntityMode entityMode)
+			throws HibernateException {
+		return getTuplizer( entityMode ).getPropertyValue( object, propertyName );
+	}
+
+	public Serializable getIdentifier(Object object, EntityMode entityMode)
+			throws HibernateException {
+		return getTuplizer( entityMode ).getIdentifier( object );
+	}
+
+	public void setIdentifier(Object object, Serializable id, EntityMode entityMode)
+			throws HibernateException {
+		getTuplizer( entityMode ).setIdentifier( object, id );
+	}
+
+	public Object getVersion(Object object, EntityMode entityMode)
+			throws HibernateException {
+		return getTuplizer( entityMode ).getVersion( object );
+	}
+
+	public Object instantiate(Serializable id, EntityMode entityMode)
+			throws HibernateException {
+		return getTuplizer( entityMode ).instantiate( id );
+	}
+
+	public boolean isInstance(Object object, EntityMode entityMode) {
+		return getTuplizer( entityMode ).isInstance( object );
+	}
+
+	public boolean hasUninitializedLazyProperties(Object object, EntityMode entityMode) {
+		return getTuplizer( entityMode ).hasUninitializedLazyProperties( object );
+	}
+
+	public void resetIdentifier(Object entity, Serializable currentId, Object currentVersion, EntityMode entityMode) {
+		getTuplizer( entityMode ).resetIdentifier( entity, currentId, currentVersion );
+	}
+
+	public EntityPersister getSubclassEntityPersister(Object instance, SessionFactoryImplementor factory, EntityMode entityMode) {
+		if ( !hasSubclasses() ) {
+			return this;
+		}
+		else {
+			// TODO : really need a way to do something like :
+			//      getTuplizer(entityMode).determineConcreteSubclassEntityName(instance)
+			Class clazz = instance.getClass();
+			if ( clazz == getMappedClass( entityMode ) ) {
+				return this;
+			}
+			else {
+				String subclassEntityName = getSubclassEntityName( clazz );
+				if ( subclassEntityName == null ) {
+					throw new HibernateException(
+							"instance not of expected entity type: " + clazz.getName() +
+							" is not a: " + getEntityName()
+						);
+				}
+				else {
+					return factory.getEntityPersister( subclassEntityName );
+				}
+			}
+		}
+	}
+
+	public EntityMode guessEntityMode(Object object) {
+		return entityMetamodel.guessEntityMode(object);
+	}
+
+	public boolean isMultiTable() {
+		return false;
+	}
+
+	public String getTemporaryIdTableName() {
+		return temporaryIdTableName;
+	}
+
+	public String getTemporaryIdTableDDL() {
+		return temporaryIdTableDDL;
+	}
+
+	protected int getPropertySpan() {
+		return entityMetamodel.getPropertySpan();
+	}
+
+	public Object[] getPropertyValuesToInsert(Object object, Map mergeMap, SessionImplementor session) throws HibernateException {
+		return getTuplizer( session.getEntityMode() ).getPropertyValuesToInsert( object, mergeMap, session );
+	}
+
+	public void processInsertGeneratedProperties(Serializable id, Object entity, Object[] state, SessionImplementor session) {
+		if ( !hasInsertGeneratedProperties() ) {
+			throw new AssertionFailure("no insert-generated properties");
+		}
+		processGeneratedProperties( id, entity, state, session, sqlInsertGeneratedValuesSelectString, getPropertyInsertGenerationInclusions() );
+	}
+
+	public void processUpdateGeneratedProperties(Serializable id, Object entity, Object[] state, SessionImplementor session) {
+		if ( !hasUpdateGeneratedProperties() ) {
+			throw new AssertionFailure("no update-generated properties");
+		}
+		processGeneratedProperties( id, entity, state, session, sqlUpdateGeneratedValuesSelectString, getPropertyUpdateGenerationInclusions() );
+	}
+
+	private void processGeneratedProperties(
+			Serializable id,
+	        Object entity,
+	        Object[] state,
+	        SessionImplementor session,
+	        String selectionSQL,
+	        ValueInclusion[] includeds) {
+
+		session.getBatcher().executeBatch(); //force immediate execution of the insert
+
+		try {
+			PreparedStatement ps = session.getBatcher().prepareSelectStatement( selectionSQL );
+			ResultSet rs = null;
+			try {
+				getIdentifierType().nullSafeSet( ps, id, 1, session );
+				rs = session.getBatcher().getResultSet( ps );
+				if ( !rs.next() ) {
+					throw new HibernateException(
+							"Unable to locate row for retrieval of generated properties: " +
+							MessageHelper.infoString( this, id, getFactory() )
+						);
+				}
+				for ( int i = 0; i < getPropertySpan(); i++ ) {
+					if ( includeds[i] != ValueInclusion.NONE ) {
+						Object hydratedState = getPropertyTypes()[i].hydrate( rs, getPropertyAliases( "", i ), session, entity );
+						state[i] = getPropertyTypes()[i].resolve( hydratedState, session, entity );
+						setPropertyValue( entity, i, state[i], session.getEntityMode() );
+					}
+				}
+			}
+			finally {
+				session.getBatcher().closeQueryStatement( ps, rs );
+			}
+		}
+		catch( SQLException sqle ) {
+			JDBCExceptionHelper.convert(
+					getFactory().getSQLExceptionConverter(),
+					sqle,
+					"unable to select generated column values",
+					selectionSQL
+			);
+		}
+
+	}
+
+	public String getIdentifierPropertyName() {
+		return entityMetamodel.getIdentifierProperty().getName();
+	}
+
+	public Type getIdentifierType() {
+		return entityMetamodel.getIdentifierProperty().getType();
+	}
+
+	public boolean hasSubselectLoadableCollections() {
+		return hasSubselectLoadableCollections;
+	}
+
+	public int[] getNaturalIdentifierProperties() {
+		return entityMetamodel.getNaturalIdentifierProperties();
+	}
+
+	public Object[] getNaturalIdentifierSnapshot(Serializable id, SessionImplementor session) throws HibernateException {
+		if ( !hasNaturalIdentifier() ) {
+			throw new MappingException( "persistent class did not define a natural-id : " + MessageHelper.infoString( this ) );
+		}
+		if ( log.isTraceEnabled() ) {
+			log.trace( "Getting current natural-id snapshot state for: " + MessageHelper.infoString( this, id, getFactory() ) );
+		}
+
+		int[] naturalIdPropertyIndexes = getNaturalIdentifierProperties();
+		int naturalIdPropertyCount = naturalIdPropertyIndexes.length;
+		boolean[] naturalIdMarkers = new boolean[ getPropertySpan() ];
+		Type[] extractionTypes = new Type[ naturalIdPropertyCount ];
+		for ( int i = 0; i < naturalIdPropertyCount; i++ ) {
+			extractionTypes[i] = getPropertyTypes()[ naturalIdPropertyIndexes[i] ];
+			naturalIdMarkers[ naturalIdPropertyIndexes[i] ] = true;
+		}
+
+		///////////////////////////////////////////////////////////////////////
+		// TODO : look at perhaps caching this...
+		Select select = new Select( getFactory().getDialect() );
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			select.setComment( "get current natural-id state " + getEntityName() );
+		}
+		select.setSelectClause( concretePropertySelectFragmentSansLeadingComma( getRootAlias(), naturalIdMarkers ) );
+		select.setFromClause( fromTableFragment( getRootAlias() ) + fromJoinFragment( getRootAlias(), true, false ) );
+
+		String[] aliasedIdColumns = StringHelper.qualify( getRootAlias(), getIdentifierColumnNames() );
+		String whereClause = new StringBuffer()
+			.append( StringHelper.join( "=? and ",
+					aliasedIdColumns ) )
+			.append( "=?" )
+			.append( whereJoinFragment( getRootAlias(), true, false ) )
+			.toString();
+
+		String sql = select.setOuterJoins( "", "" )
+				.setWhereClause( whereClause )
+				.toStatementString();
+		///////////////////////////////////////////////////////////////////////
+
+		Object[] snapshot = new Object[ naturalIdPropertyCount ];
+		try {
+			PreparedStatement ps = session.getBatcher().prepareSelectStatement( sql );
+			try {
+				getIdentifierType().nullSafeSet( ps, id, 1, session );
+				ResultSet rs = ps.executeQuery();
+				try {
+					//if there is no resulting row, return null
+					if ( !rs.next() ) {
+						return null;
+					}
+
+					for ( int i = 0; i < naturalIdPropertyCount; i++ ) {
+						snapshot[i] = extractionTypes[i].hydrate( rs, getPropertyAliases( "", naturalIdPropertyIndexes[i] ), session, null );
+					}
+					return snapshot;
+				}
+				finally {
+					rs.close();
+				}
+			}
+			finally {
+				session.getBatcher().closeStatement( ps );
+			}
+		}
+		catch ( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+					getFactory().getSQLExceptionConverter(),
+					sqle,
+					"could not retrieve snapshot: " +
+					MessageHelper.infoString( this, id, getFactory() ),
+			        sql
+				);
+		}
+	}
+
+	protected String concretePropertySelectFragmentSansLeadingComma(String alias, boolean[] include) {
+		String concretePropertySelectFragment = concretePropertySelectFragment( alias, include );
+		int firstComma = concretePropertySelectFragment.indexOf( ", " );
+		if ( firstComma == 0 ) {
+			concretePropertySelectFragment = concretePropertySelectFragment.substring( 2 );
+		}
+		return concretePropertySelectFragment;
+	}
+	public boolean hasNaturalIdentifier() {
+		return entityMetamodel.hasNaturalIdentifier();
+	}
+
+	public void setPropertyValue(Object object, String propertyName, Object value, EntityMode entityMode)
+			throws HibernateException {
+		getTuplizer( entityMode ).setPropertyValue( object, propertyName, value );
+	}
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/AbstractPropertyMapping.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/AbstractPropertyMapping.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/AbstractPropertyMapping.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,234 @@
+//$Id: AbstractPropertyMapping.java 10852 2006-11-21 17:39:14Z steve.ebersole at jboss.com $
+package org.hibernate.persister.entity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.sql.Template;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Base implementation of a <tt>PropertyMapping</tt>
+ *
+ * @author Gavin King
+ */
+public abstract class AbstractPropertyMapping implements PropertyMapping {
+
+	private final Map typesByPropertyPath = new HashMap();
+	private final Map columnsByPropertyPath = new HashMap();
+	private final Map formulaTemplatesByPropertyPath = new HashMap();
+
+	public String[] getIdentifierColumnNames() {
+		throw new UnsupportedOperationException("one-to-one is not supported here");
+	}
+
+	protected abstract String getEntityName();
+
+	public Type toType(String propertyName) throws QueryException {
+		Type type = (Type) typesByPropertyPath.get(propertyName);
+		if ( type == null ) {
+			throw propertyException( propertyName );
+		}
+		return type;
+	}
+
+	protected final QueryException propertyException(String propertyName) throws QueryException {
+		return new QueryException( "could not resolve property: " + propertyName + " of: " + getEntityName() );
+	}
+
+	public String[] getColumnNames(String propertyName) {
+		String[] cols = (String[]) columnsByPropertyPath.get(propertyName);
+		if (cols==null) {
+			throw new MappingException("unknown property: " + propertyName);
+		}
+		return cols;
+	}
+
+	public String[] toColumns(String alias, String propertyName) throws QueryException {
+		//TODO: *two* hashmap lookups here is one too many...
+		String[] columns = (String[]) columnsByPropertyPath.get(propertyName);
+		if ( columns == null ) {
+			throw propertyException( propertyName );
+		}
+		String[] templates = (String[]) formulaTemplatesByPropertyPath.get(propertyName);
+		String[] result = new String[columns.length];
+		for ( int i=0; i<columns.length; i++ ) {
+			if ( columns[i]==null ) {
+				result[i] = StringHelper.replace( templates[i], Template.TEMPLATE, alias );
+			}
+			else {
+				result[i] = StringHelper.qualify( alias, columns[i] );
+			}
+		}
+		return result;
+	}
+
+	public String[] toColumns(String propertyName) throws QueryException {
+		String[] columns = (String[]) columnsByPropertyPath.get(propertyName);
+		if ( columns == null ) {
+			throw propertyException( propertyName );
+		}
+		String[] templates = (String[]) formulaTemplatesByPropertyPath.get(propertyName);
+		String[] result = new String[columns.length];
+		for ( int i=0; i<columns.length; i++ ) {
+			if ( columns[i]==null ) {
+				result[i] = StringHelper.replace( templates[i], Template.TEMPLATE, "" );
+			}
+			else {
+				result[i] = columns[i];
+			}
+		}
+		return result;
+	}
+
+	protected void addPropertyPath(String path, Type type, String[] columns, String[] formulaTemplates) {
+		typesByPropertyPath.put(path, type);
+		columnsByPropertyPath.put(path, columns);
+		if (formulaTemplates!=null) {
+			formulaTemplatesByPropertyPath.put(path, formulaTemplates);
+		}
+	}
+
+	/*protected void initPropertyPaths(
+			final String path,
+			final Type type,
+			final String[] columns,
+			final String[] formulaTemplates,
+			final Mapping factory)
+	throws MappingException {
+		//addFormulaPropertyPath(path, type, formulaTemplates);
+		initPropertyPaths(path, type, columns, formulaTemplates, factory);
+	}*/
+
+	protected void initPropertyPaths(
+			final String path,
+			final Type type,
+			String[] columns,
+			final String[] formulaTemplates,
+			final Mapping factory)
+	throws MappingException {
+
+		if ( columns.length!=type.getColumnSpan(factory) ) {
+			throw new MappingException(
+					"broken column mapping for: " + path +
+					" of: " + getEntityName()
+				);
+		}
+
+		if ( type.isAssociationType() ) {
+			AssociationType actype = (AssociationType) type;
+			if ( actype.useLHSPrimaryKey() ) {
+				columns = getIdentifierColumnNames();
+			}
+			else {
+				String foreignKeyProperty = actype.getLHSPropertyName();
+				if ( foreignKeyProperty!=null && !path.equals(foreignKeyProperty) ) {
+					//TODO: this requires that the collection is defined after the
+					//      referenced property in the mapping file (ok?)
+					columns = (String[]) columnsByPropertyPath.get(foreignKeyProperty);
+					if (columns==null) return; //get em on the second pass!
+				}
+			}
+		}
+
+		if (path!=null) addPropertyPath(path, type, columns, formulaTemplates);
+
+		if ( type.isComponentType() ) {
+			AbstractComponentType actype = (AbstractComponentType) type;
+			initComponentPropertyPaths( path, actype, columns, formulaTemplates, factory );
+			if ( actype.isEmbedded() ) {
+				initComponentPropertyPaths(
+						path==null ? null : StringHelper.qualifier(path),
+						actype,
+						columns,
+						formulaTemplates,
+						factory
+					);
+			}
+		}
+		else if ( type.isEntityType() ) {
+			initIdentifierPropertyPaths( path, (EntityType) type, columns, factory );
+		}
+	}
+
+	protected void initIdentifierPropertyPaths(
+			final String path,
+			final EntityType etype,
+			final String[] columns,
+			final Mapping factory) throws MappingException {
+
+		Type idtype = etype.getIdentifierOrUniqueKeyType( factory );
+		String idPropName = etype.getIdentifierOrUniqueKeyPropertyName(factory);
+		boolean hasNonIdentifierPropertyNamedId = hasNonIdentifierPropertyNamedId( etype, factory );
+
+		if ( etype.isReferenceToPrimaryKey() ) {
+			if ( !hasNonIdentifierPropertyNamedId ) {
+				String idpath1 = extendPath(path, EntityPersister.ENTITY_ID);
+				addPropertyPath(idpath1, idtype, columns, null);
+				initPropertyPaths(idpath1, idtype, columns, null, factory);
+			}
+		}
+
+		if (idPropName!=null) {
+			String idpath2 = extendPath(path, idPropName);
+			addPropertyPath(idpath2, idtype, columns, null);
+			initPropertyPaths(idpath2, idtype, columns, null, factory);
+		}
+	}
+
+	private boolean hasNonIdentifierPropertyNamedId(final EntityType entityType, final Mapping factory) {
+		// TODO : would be great to have a Mapping#hasNonIdentifierPropertyNamedId method
+		// I don't believe that Mapping#getReferencedPropertyType accounts for the identifier property; so
+		// if it returns for a property named 'id', then we should have a non-id field named id
+		try {
+			return factory.getReferencedPropertyType( entityType.getAssociatedEntityName(), EntityPersister.ENTITY_ID ) != null;
+		}
+		catch( MappingException e ) {
+			return false;
+		}
+	}
+
+	protected void initComponentPropertyPaths(
+			final String path,
+			final AbstractComponentType type,
+			final String[] columns,
+			String[] formulaTemplates, final Mapping factory)
+	throws MappingException {
+
+		Type[] types = type.getSubtypes();
+		String[] properties = type.getPropertyNames();
+		int begin=0;
+		for ( int i=0; i<properties.length; i++ ) {
+			String subpath = extendPath( path, properties[i] );
+			try {
+				int length = types[i].getColumnSpan(factory);
+				String[] columnSlice = ArrayHelper.slice(columns, begin, length);
+				String[] formulaSlice = formulaTemplates==null ?
+						null : ArrayHelper.slice(formulaTemplates, begin, length);
+				initPropertyPaths(subpath, types[i], columnSlice, formulaSlice, factory);
+				begin+=length;
+			}
+			catch (Exception e) {
+				throw new MappingException("bug in initComponentPropertyPaths", e);
+			}
+		}
+	}
+
+	private static String extendPath(String path, String property) {
+		if ( path==null || "".equals(path) ) {
+			return property;
+		}
+		else {
+			return StringHelper.qualify(path, property);
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/BasicEntityPropertyMapping.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/BasicEntityPropertyMapping.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/BasicEntityPropertyMapping.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: BasicEntityPropertyMapping.java 7636 2005-07-24 23:51:12Z oneovthafew $
+package org.hibernate.persister.entity;
+
+import org.hibernate.QueryException;
+import org.hibernate.type.Type;
+
+/**
+ * @author Gavin King
+ */
+public class BasicEntityPropertyMapping extends AbstractPropertyMapping {
+
+	private final AbstractEntityPersister persister;
+
+	public BasicEntityPropertyMapping(AbstractEntityPersister persister) {
+		this.persister = persister;
+	}
+	
+	public String[] getIdentifierColumnNames() {
+		return persister.getIdentifierColumnNames();
+	}
+
+	protected String getEntityName() {
+		return persister.getEntityName();
+	}
+
+	public Type getType() {
+		return persister.getType();
+	}
+
+	public String[] toColumns(final String alias, final String propertyName) throws QueryException {
+		return super.toColumns( 
+				persister.generateTableAlias( alias, persister.getSubclassPropertyTableNumber(propertyName) ), 
+				propertyName 
+			);
+	}
+	
+	
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/BasicEntityPropertyMapping.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/EntityPersister.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/EntityPersister.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/EntityPersister.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,660 @@
+//$Id: EntityPersister.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.persister.entity;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.EntityMode;
+import org.hibernate.tuple.entity.EntityMetamodel;
+import org.hibernate.cache.CacheConcurrencyStrategy;
+import org.hibernate.cache.OptimisticCacheSource;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cache.entry.CacheEntryStructure;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.ValueInclusion;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.metadata.ClassMetadata;
+import org.hibernate.type.Type;
+import org.hibernate.type.VersionType;
+
+/**
+ * Implementors define mapping and persistence logic for a particular
+ * strategy of entity mapping.  An instance of entity persisters corresponds
+ * to a given mapped entity.
+ * <p/>
+ * Implementors must be threadsafe (preferrably immutable) and must provide a constructor
+ * matching the signature of: {@link org.hibernate.mapping.PersistentClass}, {@link org.hibernate.engine.SessionFactoryImplementor}
+ *
+ * @author Gavin King
+ */
+public interface EntityPersister extends OptimisticCacheSource {
+
+	/**
+	 * The property name of the "special" identifier property in HQL
+	 */
+	public static final String ENTITY_ID = "id";
+
+	/**
+	 * Finish the initialization of this object.
+	 * <p/>
+	 * Called only once per {@link org.hibernate.SessionFactory} lifecycle,
+	 * after all entity persisters have been instantiated.
+	 *
+	 * @throws org.hibernate.MappingException Indicates an issue in the metdata.
+	 */
+	public void postInstantiate() throws MappingException;
+
+	/**
+	 * Return the SessionFactory to which this persister "belongs".
+	 *
+	 * @return The owning SessionFactory.
+	 */
+	public SessionFactoryImplementor getFactory();
+
+
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    // stuff that is persister-centric and/or EntityInfo-centric ~~~~~~~~~~~~~~
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Returns an object that identifies the space in which identifiers of
+	 * this entity hierarchy are unique.  Might be a table name, a JNDI URL, etc.
+	 *
+	 * @return The root entity name.
+	 */
+	public String getRootEntityName();
+
+	/**
+	 * The entity name which this persister maps.
+	 *
+	 * @return The name of the entity which this persister maps.
+	 */
+	public String getEntityName();
+
+	/**
+	 * Retrieve the underlying entity metamodel instance...
+	 *
+	 *@return The metamodel
+	 */
+	public EntityMetamodel getEntityMetamodel();
+
+	/**
+	 * Determine whether the given name represents a subclass entity
+	 * (or this entity itself) of the entity mapped by this persister.
+	 *
+	 * @param entityName The entity name to be checked.
+	 * @return True if the given entity name represents either the entity
+	 * mapped by this persister or one of its subclass entities; false
+	 * otherwise.
+	 */
+	public boolean isSubclassEntityName(String entityName);
+
+	/**
+	 * Returns an array of objects that identify spaces in which properties of
+	 * this entity are persisted, for instances of this class only.
+	 * <p/>
+	 * For most implementations, this returns the complete set of table names
+	 * to which instances of the mapped entity are persisted (not accounting
+	 * for superclass entity mappings).
+	 *
+	 * @return The property spaces.
+	 */
+	public Serializable[] getPropertySpaces();
+
+	/**
+	 * Returns an array of objects that identify spaces in which properties of
+	 * this entity are persisted, for instances of this class and its subclasses.
+	 * <p/>
+	 * Much like {@link #getPropertySpaces()}, except that here we include subclass
+	 * entity spaces.
+	 *
+	 * @return The query spaces.
+	 */
+	public Serializable[] getQuerySpaces();
+
+	/**
+	 * Determine whether this entity supports dynamic proxies.
+	 *
+	 * @return True if the entity has dynamic proxy support; false otherwise.
+	 */
+	public boolean hasProxy();
+
+	/**
+	 * Determine whether this entity contains references to persistent collections.
+	 *
+	 * @return True if the entity does contain persistent collections; false otherwise.
+	 */
+	public boolean hasCollections();
+
+	/**
+	 * Determine whether any properties of this entity are considered mutable.
+	 *
+	 * @return True if any properties of the entity are mutable; false otherwise (meaning none are).
+	 */
+	public boolean hasMutableProperties();
+
+	/**
+	 * Determine whether this entity contains references to persistent collections
+	 * which are fetchable by subselect?
+	 *
+	 * @return True if the entity contains collections fetchable by subselect; false otherwise.
+	 */
+	public boolean hasSubselectLoadableCollections();
+
+	/**
+	 * Determine whether this entity has any non-none cascading.
+	 *
+	 * @return True if the entity has any properties with a cscade other than NONE;
+	 * false otherwise (aka, no cascading).
+	 */
+	public boolean hasCascades();
+
+	/**
+	 * Determine whether instances of this entity are considered mutable.
+	 *
+	 * @return True if the entity is considered mutable; false otherwise.
+	 */
+	public boolean isMutable();
+
+	/**
+	 * Determine whether the entity is inherited one or more other entities.
+	 * In other words, is this entity a subclass of other entities.
+	 *
+	 * @return True if other entities extend this entity; false otherwise.
+	 */
+	public boolean isInherited();
+
+	/**
+	 * Are identifiers of this entity assigned known before the insert execution?
+	 * Or, are they generated (in the database) by the insert execution.
+	 *
+	 * @return True if identifiers for this entity are generated by the insert
+	 * execution.
+	 */
+	public boolean isIdentifierAssignedByInsert();
+
+	/**
+	 * Get the type of a particular property by name.
+	 *
+	 * @param propertyName The name of the property for which to retrieve
+	 * the typpe.
+	 * @return The type.
+	 * @throws org.hibernate.MappingException Typically indicates an unknown
+	 * property name.
+	 */
+	public Type getPropertyType(String propertyName) throws MappingException;
+
+	/**
+	 * Compare the two snapshots to determine if they represent dirty state.
+	 *
+	 * @param currentState The current snapshot
+	 * @param previousState The baseline snapshot
+	 * @param owner The entity containing the state
+	 * @param session The originating session
+	 * @return The indices of all dirty properties, or null if no properties
+	 * were dirty.
+	 */
+	public int[] findDirty(Object[] currentState, Object[] previousState, Object owner, SessionImplementor session);
+
+	/**
+	 * Compare the two snapshots to determine if they represent modified state.
+	 *
+	 * @param old The baseline snapshot
+	 * @param current The current snapshot
+	 * @param object The entity containing the state
+	 * @param session The originating session
+	 * @return The indices of all modified properties, or null if no properties
+	 * were modified.
+	 */
+	public int[] findModified(Object[] old, Object[] current, Object object, SessionImplementor session);
+
+	/**
+	 * Determine whether the entity has a particular property holding
+	 * the identifier value.
+	 *
+	 * @return True if the entity has a specific property holding identifier value.
+	 */
+	public boolean hasIdentifierProperty();
+
+	/**
+	 * Determine whether detahced instances of this entity carry their own
+	 * identifier value.
+	 * <p/>
+	 * The other option is the deperecated feature where users could supply
+	 * the id during session calls.
+	 *
+	 * @return True if either (1) {@link #hasIdentifierProperty()} or
+	 * (2) the identifier is an embedded composite identifier; false otherwise.
+	 */
+	public boolean canExtractIdOutOfEntity();
+
+	/**
+	 * Determine whether optimistic locking by column is enabled for this
+	 * entity.
+	 *
+	 * @return True if optimistic locking by column (i.e., <version/> or
+	 * <timestamp/>) is enabled; false otherwise.
+	 */
+	public boolean isVersioned();
+
+	/**
+	 * If {@link #isVersioned()}, then what is the type of the property
+	 * holding the locking value.
+	 *
+	 * @return The type of the version property; or null, if not versioned.
+	 */
+	public VersionType getVersionType();
+
+	/**
+	 * If {@link #isVersioned()}, then what is the index of the property
+	 * holding the locking value.
+	 *
+	 * @return The type of the version property; or -66, if not versioned.
+	 */
+	public int getVersionProperty();
+
+	/**
+	 * Determine whether this entity defines a natural identifier.
+	 *
+	 * @return True if the entity defines a natural id; false otherwise.
+	 */
+	public boolean hasNaturalIdentifier();
+
+	/**
+	 * If the entity defines a natural id ({@link #hasNaturalIdentifier()}), which
+	 * properties make up the natural id.
+	 *
+	 * @return The indices of the properties making of the natural id; or
+	 * null, if no natural id is defined.
+	 */
+	public int[] getNaturalIdentifierProperties();
+
+	/**
+	 * Retrieve the current state of the natural-id properties from the database.
+	 *
+	 * @param id The identifier of the entity for which to retrieve the naturak-id values.
+	 * @param session The session from which the request originated.
+	 * @return The natural-id snapshot.
+	 */
+	public Object[] getNaturalIdentifierSnapshot(Serializable id, SessionImplementor session);
+
+	/**
+	 * Determine which identifier generation strategy is used for this entity.
+	 *
+	 * @return The identifier generation strategy.
+	 */
+	public IdentifierGenerator getIdentifierGenerator();
+
+	/**
+	 * Determine whether this entity defines any lazy properties (ala
+	 * bytecode instrumentation).
+	 *
+	 * @return True if the entity has properties mapped as lazy; false otherwise.
+	 */
+	public boolean hasLazyProperties();
+
+	/**
+	 * Load an instance of the persistent class.
+	 */
+	public Object load(Serializable id, Object optionalObject, LockMode lockMode, SessionImplementor session)
+	throws HibernateException;
+
+	/**
+	 * Do a version check (optional operation)
+	 */
+	public void lock(Serializable id, Object version, Object object, LockMode lockMode, SessionImplementor session)
+	throws HibernateException;
+
+	/**
+	 * Persist an instance
+	 */
+	public void insert(Serializable id, Object[] fields, Object object, SessionImplementor session)
+	throws HibernateException;
+
+	/**
+	 * Persist an instance, using a natively generated identifier (optional operation)
+	 */
+	public Serializable insert(Object[] fields, Object object, SessionImplementor session)
+	throws HibernateException;
+
+	/**
+	 * Delete a persistent instance
+	 */
+	public void delete(Serializable id, Object version, Object object, SessionImplementor session)
+	throws HibernateException;
+
+	/**
+	 * Update a persistent instance
+	 */
+	public void update(
+		Serializable id,
+		Object[] fields,
+		int[] dirtyFields,
+		boolean hasDirtyCollection,
+		Object[] oldFields,
+		Object oldVersion,
+		Object object,
+		Object rowId,
+		SessionImplementor session
+	) throws HibernateException;
+
+	/**
+	 * Get the Hibernate types of the class properties
+	 */
+	public Type[] getPropertyTypes();
+
+	/**
+	 * Get the names of the class properties - doesn't have to be the names of the
+	 * actual Java properties (used for XML generation only)
+	 */
+	public String[] getPropertyNames();
+
+	/**
+	 * Get the "insertability" of the properties of this class
+	 * (does the property appear in an SQL INSERT)
+	 */
+	public boolean[] getPropertyInsertability();
+
+	/**
+	 * Which of the properties of this class are database generated values on insert?
+	 */
+	public ValueInclusion[] getPropertyInsertGenerationInclusions();
+
+	/**
+	 * Which of the properties of this class are database generated values on update?
+	 */
+	public ValueInclusion[] getPropertyUpdateGenerationInclusions();
+
+	/**
+	 * Get the "updateability" of the properties of this class
+	 * (does the property appear in an SQL UPDATE)
+	 */
+	public boolean[] getPropertyUpdateability();
+
+	/**
+	 * Get the "checkability" of the properties of this class
+	 * (is the property dirty checked, does the cache need
+	 * to be updated)
+	 */
+	public boolean[] getPropertyCheckability();
+
+	/**
+	 * Get the nullability of the properties of this class
+	 */
+	public boolean[] getPropertyNullability();
+
+	/**
+	 * Get the "versionability" of the properties of this class
+	 * (is the property optimistic-locked)
+	 */
+	public boolean[] getPropertyVersionability();
+	public boolean[] getPropertyLaziness();
+	/**
+	 * Get the cascade styles of the propertes (optional operation)
+	 */
+	public CascadeStyle[] getPropertyCascadeStyles();
+
+	/**
+	 * Get the identifier type
+	 */
+	public Type getIdentifierType();
+
+	/**
+	 * Get the name of the identifier property (or return null) - need not return the
+	 * name of an actual Java property
+	 */
+	public String getIdentifierPropertyName();
+
+	/**
+	 * Should we always invalidate the cache instead of
+	 * recaching updated state
+	 */
+	public boolean isCacheInvalidationRequired();
+	/**
+	 * Should lazy properties of this entity be cached?
+	 */
+	public boolean isLazyPropertiesCacheable();
+	/**
+	 * Does this class have a cache.
+	 */
+	public boolean hasCache();
+	/**
+	 * Get the cache (optional operation)
+	 */
+	public EntityRegionAccessStrategy getCacheAccessStrategy();
+	/**
+	 * Get the cache structure
+	 */
+	public CacheEntryStructure getCacheEntryStructure();
+
+	/**
+	 * Get the user-visible metadata for the class (optional operation)
+	 */
+	public ClassMetadata getClassMetadata();
+
+	/**
+	 * Is batch loading enabled?
+	 */
+	public boolean isBatchLoadable();
+
+	/**
+	 * Is select snapshot before update enabled?
+	 */
+	public boolean isSelectBeforeUpdateRequired();
+
+	/**
+	 * Get the current database state of the object, in a "hydrated" form, without
+	 * resolving identifiers
+	 * @return null if there is no row in the database
+	 */
+	public Object[] getDatabaseSnapshot(Serializable id, SessionImplementor session)
+	throws HibernateException;
+
+	/**
+	 * Get the current version of the object, or return null if there is no row for
+	 * the given identifier. In the case of unversioned data, return any object
+	 * if the row exists.
+	 */
+	public Object getCurrentVersion(Serializable id, SessionImplementor session)
+	throws HibernateException;
+
+	public Object forceVersionIncrement(Serializable id, Object currentVersion, SessionImplementor session)
+	throws HibernateException;
+
+	/**
+	 * Try to discover the entity mode from the entity instance
+	 */
+	public EntityMode guessEntityMode(Object object);
+
+	/**
+	 * Has the class actually been bytecode instrumented?
+	 */
+	public boolean isInstrumented(EntityMode entityMode);
+
+	/**
+	 * Does this entity define any properties as being database generated on insert?
+	 *
+	 * @return True if this entity contains at least one property defined
+	 * as generated (including version property, but not identifier).
+	 */
+	public boolean hasInsertGeneratedProperties();
+
+	/**
+	 * Does this entity define any properties as being database generated on update?
+	 *
+	 * @return True if this entity contains at least one property defined
+	 * as generated (including version property, but not identifier).
+	 */
+	public boolean hasUpdateGeneratedProperties();
+
+	/**
+	 * Does this entity contain a version property that is defined
+	 * to be database generated?
+	 *
+	 * @return true if this entity contains a version property and that
+	 * property has been marked as generated.
+	 */
+	public boolean isVersionPropertyGenerated();
+
+
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	// stuff that is tuplizer-centric, but is passed a session ~~~~~~~~~~~~~~~~
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Called just after the entities properties have been initialized
+	 */
+	public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session);
+
+	/**
+	 * Called just after the entity has been reassociated with the session
+	 */
+	public void afterReassociate(Object entity, SessionImplementor session);
+
+	/**
+	 * Create a new proxy instance
+	 */
+	public Object createProxy(Serializable id, SessionImplementor session)
+	throws HibernateException;
+
+	/**
+	 * Is this a new transient instance?
+	 */
+	public Boolean isTransient(Object object, SessionImplementor session) throws HibernateException;
+
+	/**
+	 * Return the values of the insertable properties of the object (including backrefs)
+	 */
+	public Object[] getPropertyValuesToInsert(Object object, Map mergeMap, SessionImplementor session) throws HibernateException;
+
+	/**
+	 * Perform a select to retrieve the values of any generated properties
+	 * back from the database, injecting these generated values into the
+	 * given entity as well as writing this state to the
+	 * {@link org.hibernate.engine.PersistenceContext}.
+	 * <p/>
+	 * Note, that because we update the PersistenceContext here, callers
+	 * need to take care that they have already written the initial snapshot
+	 * to the PersistenceContext before calling this method.
+	 *
+	 * @param id The entity's id value.
+	 * @param entity The entity for which to get the state.
+	 * @param state
+	 * @param session The session
+	 */
+	public void processInsertGeneratedProperties(Serializable id, Object entity, Object[] state, SessionImplementor session);
+	/**
+	 * Perform a select to retrieve the values of any generated properties
+	 * back from the database, injecting these generated values into the
+	 * given entity as well as writing this state to the
+	 * {@link org.hibernate.engine.PersistenceContext}.
+	 * <p/>
+	 * Note, that because we update the PersistenceContext here, callers
+	 * need to take care that they have already written the initial snapshot
+	 * to the PersistenceContext before calling this method.
+	 *
+	 * @param id The entity's id value.
+	 * @param entity The entity for which to get the state.
+	 * @param state
+	 * @param session The session
+	 */
+	public void processUpdateGeneratedProperties(Serializable id, Object entity, Object[] state, SessionImplementor session);
+
+
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	// stuff that is Tuplizer-centric ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * The persistent class, or null
+	 */
+	public Class getMappedClass(EntityMode entityMode);
+
+	/**
+	 * Does the class implement the <tt>Lifecycle</tt> interface.
+	 */
+	public boolean implementsLifecycle(EntityMode entityMode);
+
+	/**
+	 * Does the class implement the <tt>Validatable</tt> interface.
+	 */
+	public boolean implementsValidatable(EntityMode entityMode);
+	/**
+	 * Get the proxy interface that instances of <em>this</em> concrete class will be
+	 * cast to (optional operation).
+	 */
+	public Class getConcreteProxyClass(EntityMode entityMode);
+
+	/**
+	 * Set the given values to the mapped properties of the given object
+	 */
+	public void setPropertyValues(Object object, Object[] values, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Set the value of a particular property
+	 */
+	public void setPropertyValue(Object object, int i, Object value, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Return the (loaded) values of the mapped properties of the object (not including backrefs)
+	 */
+	public Object[] getPropertyValues(Object object, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Get the value of a particular property
+	 */
+	public Object getPropertyValue(Object object, int i, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Get the value of a particular property
+	 */
+	public Object getPropertyValue(Object object, String propertyName, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Get the identifier of an instance (throw an exception if no identifier property)
+	 */
+	public Serializable getIdentifier(Object object, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Set the identifier of an instance (or do nothing if no identifier property)
+	 */
+	public void setIdentifier(Object object, Serializable id, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Get the version number (or timestamp) from the object's version property (or return null if not versioned)
+	 */
+	public Object getVersion(Object object, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Create a class instance initialized with the given identifier
+	 */
+	public Object instantiate(Serializable id, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Is the given object an instance of this entity?
+	 */
+	public boolean isInstance(Object object, EntityMode entityMode);
+
+	/**
+	 * Does the given instance have any uninitialized lazy properties?
+	 */
+	public boolean hasUninitializedLazyProperties(Object object, EntityMode entityMode);
+
+	/**
+	 * Set the identifier and version of the given instance back
+	 * to its "unsaved" value, returning the id
+	 * @param currentId TODO
+	 * @param currentVersion TODO
+	 */
+	public void resetIdentifier(Object entity, Serializable currentId, Object currentVersion, EntityMode entityMode);
+
+	/**
+	 * Get the persister for an instance of this class or a subclass
+	 */
+	public EntityPersister getSubclassEntityPersister(Object instance, SessionFactoryImplementor factory, EntityMode entityMode);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Joinable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Joinable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Joinable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,71 @@
+//$Id: Joinable.java 6828 2005-05-19 07:28:59Z steveebersole $
+package org.hibernate.persister.entity;
+
+import org.hibernate.MappingException;
+
+import java.util.Map;
+
+/**
+ * Anything that can be loaded by outer join - namely
+ * persisters for classes or collections.
+ *
+ * @author Gavin King
+ */
+public interface Joinable {
+	//should this interface extend PropertyMapping?
+
+	/**
+	 * An identifying name; a class name or collection role name.
+	 */
+	public String getName();
+	/**
+	 * The table to join to.
+	 */
+	public String getTableName();
+
+	/**
+	 * All columns to select, when loading.
+	 */
+	public String selectFragment(Joinable rhs, String rhsAlias, String lhsAlias, String currentEntitySuffix, String currentCollectionSuffix, boolean includeCollectionColumns);
+
+	/**
+	 * Get the where clause part of any joins
+	 * (optional operation)
+	 */
+	public String whereJoinFragment(String alias, boolean innerJoin, boolean includeSubclasses);
+	/**
+	 * Get the from clause part of any joins
+	 * (optional operation)
+	 */
+	public String fromJoinFragment(String alias, boolean innerJoin, boolean includeSubclasses);
+	/**
+	 * The columns to join on
+	 */
+	public String[] getKeyColumnNames();
+	/**
+	 * Get the where clause filter, given a query alias and considering enabled session filters
+	 */
+	public String filterFragment(String alias, Map enabledFilters) throws MappingException;
+
+	public String oneToManyFilterFragment(String alias) throws MappingException;
+	/**
+	 * Is this instance actually a CollectionPersister?
+	 */
+	public boolean isCollection();
+
+	/**
+	 * Very, very, very ugly...
+	 *
+	 * @return Does this persister "consume" entity column aliases in the result
+	 * set?
+	 */
+	public boolean consumesEntityAlias();
+
+	/**
+	 * Very, very, very ugly...
+	 *
+	 * @return Does this persister "consume" collection column aliases in the result
+	 * set?
+	 */
+	public boolean consumesCollectionAlias();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,586 @@
+//$Id: JoinedSubclassEntityPersister.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.persister.entity;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.Versioning;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.KeyValue;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.Selectable;
+import org.hibernate.mapping.Subclass;
+import org.hibernate.mapping.Table;
+import org.hibernate.sql.CaseFragment;
+import org.hibernate.sql.SelectFragment;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * An <tt>EntityPersister</tt> implementing the normalized "table-per-subclass"
+ * mapping strategy
+ *
+ * @author Gavin King
+ */
+public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
+
+	// the class hierarchy structure
+	private final int tableSpan;
+	private final String[] tableNames;
+	private final String[] naturalOrderTableNames;
+	private final String[][] tableKeyColumns;
+	private final String[][] naturalOrderTableKeyColumns;
+	private final boolean[] naturalOrderCascadeDeleteEnabled;
+
+	private final String[] spaces;
+
+	private final String[] subclassClosure;
+
+	private final String[] subclassTableNameClosure;
+	private final String[][] subclassTableKeyColumnClosure;
+	private final boolean[] isClassOrSuperclassTable;
+
+	// properties of this class, including inherited properties
+	private final int[] naturalOrderPropertyTableNumbers;
+	private final int[] propertyTableNumbers;
+
+	// the closure of all properties in the entire hierarchy including
+	// subclasses and superclasses of this class
+	private final int[] subclassPropertyTableNumberClosure;
+
+	// the closure of all columns used by the entire hierarchy including
+	// subclasses and superclasses of this class
+	private final int[] subclassColumnTableNumberClosure;
+	private final int[] subclassFormulaTableNumberClosure;
+
+	// subclass discrimination works by assigning particular
+	// values to certain combinations of null primary key
+	// values in the outer join using an SQL CASE
+	private final Map subclassesByDiscriminatorValue = new HashMap();
+	private final String[] discriminatorValues;
+	private final String[] notNullColumnNames;
+	private final int[] notNullColumnTableNumbers;
+
+	private final String[] constraintOrderedTableNames;
+	private final String[][] constraintOrderedKeyColumnNames;
+
+	private final String discriminatorSQLString;
+
+	//INITIALIZATION:
+
+	public JoinedSubclassEntityPersister(
+			final PersistentClass persistentClass,
+			final EntityRegionAccessStrategy cacheAccessStrategy,
+			final SessionFactoryImplementor factory,
+			final Mapping mapping) throws HibernateException {
+
+		super( persistentClass, cacheAccessStrategy, factory );
+
+		// DISCRIMINATOR
+
+		final Object discriminatorValue;
+		if ( persistentClass.isPolymorphic() ) {
+			try {
+				discriminatorValue = new Integer( persistentClass.getSubclassId() );
+				discriminatorSQLString = discriminatorValue.toString();
+			}
+			catch (Exception e) {
+				throw new MappingException("Could not format discriminator value to SQL string", e );
+			}
+		}
+		else {
+			discriminatorValue = null;
+			discriminatorSQLString = null;
+		}
+
+		if ( optimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION ) {
+			throw new MappingException( "optimistic-lock=all|dirty not supported for joined-subclass mappings [" + getEntityName() + "]" );
+		}
+
+		//MULTITABLES
+
+		final int idColumnSpan = getIdentifierColumnSpan();
+
+		ArrayList tables = new ArrayList();
+		ArrayList keyColumns = new ArrayList();
+		ArrayList cascadeDeletes = new ArrayList();
+		Iterator titer = persistentClass.getTableClosureIterator();
+		Iterator kiter = persistentClass.getKeyClosureIterator();
+		while ( titer.hasNext() ) {
+			Table tab = (Table) titer.next();
+			KeyValue key = (KeyValue) kiter.next();
+			String tabname = tab.getQualifiedName(
+					factory.getDialect(),
+					factory.getSettings().getDefaultCatalogName(),
+					factory.getSettings().getDefaultSchemaName()
+			);
+			tables.add(tabname);
+			String[] keyCols = new String[idColumnSpan];
+			Iterator citer = key.getColumnIterator();
+			for ( int k=0; k<idColumnSpan; k++ ) {
+				keyCols[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
+			}
+			keyColumns.add(keyCols);
+			cascadeDeletes.add( new Boolean( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() ) );
+		}
+		naturalOrderTableNames = ArrayHelper.toStringArray(tables);
+		naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray(keyColumns);
+		naturalOrderCascadeDeleteEnabled = ArrayHelper.toBooleanArray(cascadeDeletes);
+
+		ArrayList subtables = new ArrayList();
+		ArrayList isConcretes = new ArrayList();
+		keyColumns = new ArrayList();
+		titer = persistentClass.getSubclassTableClosureIterator();
+		while ( titer.hasNext() ) {
+			Table tab = (Table) titer.next();
+			isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassTable(tab) ) );
+			String tabname = tab.getQualifiedName(
+					factory.getDialect(),
+					factory.getSettings().getDefaultCatalogName(),
+					factory.getSettings().getDefaultSchemaName()
+			);
+			subtables.add(tabname);
+			String[] key = new String[idColumnSpan];
+			Iterator citer = tab.getPrimaryKey().getColumnIterator();
+			for ( int k=0; k<idColumnSpan; k++ ) {
+				key[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
+			}
+			keyColumns.add(key);
+		}
+		subclassTableNameClosure = ArrayHelper.toStringArray(subtables);
+		subclassTableKeyColumnClosure = ArrayHelper.to2DStringArray(keyColumns);
+		isClassOrSuperclassTable = ArrayHelper.toBooleanArray(isConcretes);
+
+		constraintOrderedTableNames = new String[subclassTableNameClosure.length];
+		constraintOrderedKeyColumnNames = new String[subclassTableNameClosure.length][];
+		int currentPosition = 0;
+		for ( int i = subclassTableNameClosure.length - 1; i >= 0 ; i--, currentPosition++ ) {
+			constraintOrderedTableNames[currentPosition] = subclassTableNameClosure[i];
+			constraintOrderedKeyColumnNames[currentPosition] = subclassTableKeyColumnClosure[i];
+		}
+
+		tableSpan = naturalOrderTableNames.length;
+		tableNames = reverse(naturalOrderTableNames);
+		tableKeyColumns = reverse(naturalOrderTableKeyColumns);
+		reverse(subclassTableNameClosure, tableSpan);
+		reverse(subclassTableKeyColumnClosure, tableSpan);
+
+		spaces = ArrayHelper.join(
+				tableNames,
+				ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
+		);
+
+		// Custom sql
+		customSQLInsert = new String[tableSpan];
+		customSQLUpdate = new String[tableSpan];
+		customSQLDelete = new String[tableSpan];
+		insertCallable = new boolean[tableSpan];
+		updateCallable = new boolean[tableSpan];
+		deleteCallable = new boolean[tableSpan];
+		insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
+		updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
+		deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
+
+		PersistentClass pc = persistentClass;
+		int jk = tableSpan-1;
+		while (pc!=null) {
+			customSQLInsert[jk] = pc.getCustomSQLInsert();
+			insertCallable[jk] = customSQLInsert[jk] != null && pc.isCustomInsertCallable();
+			insertResultCheckStyles[jk] = pc.getCustomSQLInsertCheckStyle() == null
+			                              ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[jk], insertCallable[jk] )
+		                                  : pc.getCustomSQLInsertCheckStyle();
+			customSQLUpdate[jk] = pc.getCustomSQLUpdate();
+			updateCallable[jk] = customSQLUpdate[jk] != null && pc.isCustomUpdateCallable();
+			updateResultCheckStyles[jk] = pc.getCustomSQLUpdateCheckStyle() == null
+			                              ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[jk], updateCallable[jk] )
+		                                  : pc.getCustomSQLUpdateCheckStyle();
+			customSQLDelete[jk] = pc.getCustomSQLDelete();
+			deleteCallable[jk] = customSQLDelete[jk] != null && pc.isCustomDeleteCallable();
+			deleteResultCheckStyles[jk] = pc.getCustomSQLDeleteCheckStyle() == null
+			                              ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[jk], deleteCallable[jk] )
+		                                  : pc.getCustomSQLDeleteCheckStyle();
+			jk--;
+			pc = pc.getSuperclass();
+		}
+		if ( jk != -1 ) {
+			throw new AssertionFailure( "Tablespan does not match height of joined-subclass hiearchy." );
+		}
+
+		// PROPERTIES
+
+		int hydrateSpan = getPropertySpan();
+		naturalOrderPropertyTableNumbers = new int[hydrateSpan];
+		propertyTableNumbers = new int[hydrateSpan];
+		Iterator iter = persistentClass.getPropertyClosureIterator();
+		int i=0;
+		while( iter.hasNext() ) {
+			Property prop = (Property) iter.next();
+			String tabname = prop.getValue().getTable().getQualifiedName(
+				factory.getDialect(),
+				factory.getSettings().getDefaultCatalogName(),
+				factory.getSettings().getDefaultSchemaName()
+			);
+			propertyTableNumbers[i] = getTableId(tabname, tableNames);
+			naturalOrderPropertyTableNumbers[i] = getTableId(tabname, naturalOrderTableNames);
+			i++;
+		}
+
+		// subclass closure properties
+
+		//TODO: code duplication with SingleTableEntityPersister
+
+		ArrayList columnTableNumbers = new ArrayList();
+		ArrayList formulaTableNumbers = new ArrayList();
+		ArrayList propTableNumbers = new ArrayList();
+
+		iter = persistentClass.getSubclassPropertyClosureIterator();
+		while ( iter.hasNext() ) {
+			Property prop = (Property) iter.next();
+			Table tab = prop.getValue().getTable();
+			String tabname = tab.getQualifiedName(
+					factory.getDialect(),
+					factory.getSettings().getDefaultCatalogName(),
+					factory.getSettings().getDefaultSchemaName()
+			);
+			Integer tabnum = new Integer( getTableId(tabname, subclassTableNameClosure) );
+			propTableNumbers.add(tabnum);
+
+			Iterator citer = prop.getColumnIterator();
+			while ( citer.hasNext() ) {
+				Selectable thing = (Selectable) citer.next();
+				if ( thing.isFormula() ) {
+					formulaTableNumbers.add(tabnum);
+				}
+				else {
+					columnTableNumbers.add(tabnum);
+				}
+			}
+
+		}
+
+		subclassColumnTableNumberClosure = ArrayHelper.toIntArray(columnTableNumbers);
+		subclassPropertyTableNumberClosure = ArrayHelper.toIntArray(propTableNumbers);
+		subclassFormulaTableNumberClosure = ArrayHelper.toIntArray(formulaTableNumbers);
+
+		// SUBCLASSES
+
+		int subclassSpan = persistentClass.getSubclassSpan() + 1;
+		subclassClosure = new String[subclassSpan];
+		subclassClosure[subclassSpan-1] = getEntityName();
+		if ( persistentClass.isPolymorphic() ) {
+			subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
+			discriminatorValues = new String[subclassSpan];
+			discriminatorValues[subclassSpan-1] = discriminatorSQLString;
+			notNullColumnTableNumbers = new int[subclassSpan];
+			final int id = getTableId(
+				persistentClass.getTable().getQualifiedName(
+						factory.getDialect(),
+						factory.getSettings().getDefaultCatalogName(),
+						factory.getSettings().getDefaultSchemaName()
+				),
+				subclassTableNameClosure
+			);
+			notNullColumnTableNumbers[subclassSpan-1] = id;
+			notNullColumnNames = new String[subclassSpan];
+			notNullColumnNames[subclassSpan-1] =  subclassTableKeyColumnClosure[id][0]; //( (Column) model.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
+		}
+		else {
+			discriminatorValues = null;
+			notNullColumnTableNumbers = null;
+			notNullColumnNames = null;
+		}
+
+		iter = persistentClass.getSubclassIterator();
+		int k=0;
+		while ( iter.hasNext() ) {
+			Subclass sc = (Subclass) iter.next();
+			subclassClosure[k] = sc.getEntityName();
+			try {
+				if ( persistentClass.isPolymorphic() ) {
+					// we now use subclass ids that are consistent across all
+					// persisters for a class hierarchy, so that the use of
+					// "foo.class = Bar" works in HQL
+					Integer subclassId = new Integer( sc.getSubclassId() );//new Integer(k+1);
+					subclassesByDiscriminatorValue.put( subclassId, sc.getEntityName() );
+					discriminatorValues[k] = subclassId.toString();
+					int id = getTableId(
+						sc.getTable().getQualifiedName(
+								factory.getDialect(),
+								factory.getSettings().getDefaultCatalogName(),
+								factory.getSettings().getDefaultSchemaName()
+						),
+						subclassTableNameClosure
+					);
+					notNullColumnTableNumbers[k] = id;
+					notNullColumnNames[k] = subclassTableKeyColumnClosure[id][0]; //( (Column) sc.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
+				}
+			}
+			catch (Exception e) {
+				throw new MappingException("Error parsing discriminator value", e );
+			}
+			k++;
+		}
+
+		initLockers();
+
+		initSubclassPropertyAliasesMap(persistentClass);
+
+		postConstruct(mapping);
+
+	}
+
+	/*public void postInstantiate() throws MappingException {
+		super.postInstantiate();
+		//TODO: other lock modes?
+		loader = createEntityLoader(LockMode.NONE, CollectionHelper.EMPTY_MAP);
+	}*/
+
+	public String getSubclassPropertyTableName(int i) {
+		return subclassTableNameClosure[ subclassPropertyTableNumberClosure[i] ];
+	}
+
+	public Type getDiscriminatorType() {
+		return Hibernate.INTEGER;
+	}
+
+	public String getDiscriminatorSQLValue() {
+		return discriminatorSQLString;
+	}
+
+
+	public String getSubclassForDiscriminatorValue(Object value) {
+		return (String) subclassesByDiscriminatorValue.get(value);
+	}
+
+	public Serializable[] getPropertySpaces() {
+		return spaces; // don't need subclass tables, because they can't appear in conditions
+	}
+
+
+	protected String getTableName(int j) {
+		return naturalOrderTableNames[j];
+	}
+
+	protected String[] getKeyColumns(int j) {
+		return naturalOrderTableKeyColumns[j];
+	}
+
+	protected boolean isTableCascadeDeleteEnabled(int j) {
+		return naturalOrderCascadeDeleteEnabled[j];
+	}
+
+	protected boolean isPropertyOfTable(int property, int j) {
+		return naturalOrderPropertyTableNumbers[property]==j;
+	}
+
+	/**
+	 * Load an instance using either the <tt>forUpdateLoader</tt> or the outer joining <tt>loader</tt>,
+	 * depending upon the value of the <tt>lock</tt> parameter
+	 */
+	/*public Object load(Serializable id,	Object optionalObject, LockMode lockMode, SessionImplementor session)
+	throws HibernateException {
+
+		if ( log.isTraceEnabled() ) log.trace( "Materializing entity: " + MessageHelper.infoString(this, id) );
+
+		final UniqueEntityLoader loader = hasQueryLoader() ?
+				getQueryLoader() :
+				this.loader;
+		try {
+
+			final Object result = loader.load(id, optionalObject, session);
+
+			if (result!=null) lock(id, getVersion(result), result, lockMode, session);
+
+			return result;
+
+		}
+		catch (SQLException sqle) {
+			throw new JDBCException( "could not load by id: " +  MessageHelper.infoString(this, id), sqle );
+		}
+	}*/
+
+	private static final void reverse(Object[] objects, int len) {
+		Object[] temp = new Object[len];
+		for (int i=0; i<len; i++) {
+			temp[i] = objects[len-i-1];
+		}
+		for (int i=0; i<len; i++) {
+			objects[i] = temp[i];
+		}
+	}
+
+	private static final String[] reverse(String[] objects) {
+		int len = objects.length;
+		String[] temp = new String[len];
+		for (int i=0; i<len; i++) {
+			temp[i] = objects[len-i-1];
+		}
+		return temp;
+	}
+
+	private static final String[][] reverse(String[][] objects) {
+		int len = objects.length;
+		String[][] temp = new String[len][];
+		for (int i=0; i<len; i++) {
+			temp[i] = objects[len-i-1];
+		}
+		return temp;
+	}
+
+	public String fromTableFragment(String alias) {
+		return getTableName() + ' ' + alias;
+	}
+
+	public String getTableName() {
+		return tableNames[0];
+	}
+
+	private static int getTableId(String tableName, String[] tables) {
+		for ( int j=0; j<tables.length; j++ ) {
+			if ( tableName.equals( tables[j] ) ) {
+				return j;
+			}
+		}
+		throw new AssertionFailure("Table " + tableName + " not found");
+	}
+
+	public void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) {
+		if ( hasSubclasses() ) {
+			select.setExtraSelectList( discriminatorFragment(name), getDiscriminatorAlias() );
+		}
+	}
+
+	private CaseFragment discriminatorFragment(String alias) {
+		CaseFragment cases = getFactory().getDialect().createCaseFragment();
+
+		for ( int i=0; i<discriminatorValues.length; i++ ) {
+			cases.addWhenColumnNotNull(
+				generateTableAlias( alias, notNullColumnTableNumbers[i] ),
+				notNullColumnNames[i],
+				discriminatorValues[i]
+			);
+		}
+
+		return cases;
+	}
+
+	public String filterFragment(String alias) {
+		return hasWhere() ?
+			" and " + getSQLWhereString( generateFilterConditionAlias( alias ) ) :
+			"";
+	}
+
+	public String generateFilterConditionAlias(String rootAlias) {
+		return generateTableAlias( rootAlias, tableSpan-1 );
+	}
+
+	public String[] getIdentifierColumnNames() {
+		return tableKeyColumns[0];
+	}
+
+	public String[] toColumns(String alias, String propertyName) throws QueryException {
+
+		if ( ENTITY_CLASS.equals(propertyName) ) {
+			// This doesn't actually seem to work but it *might*
+			// work on some dbs. Also it doesn't work if there
+			// are multiple columns of results because it
+			// is not accounting for the suffix:
+			// return new String[] { getDiscriminatorColumnName() };
+
+			return new String[] { discriminatorFragment(alias).toFragmentString() };
+		}
+		else {
+			return super.toColumns(alias, propertyName);
+		}
+
+	}
+
+	protected int[] getPropertyTableNumbersInSelect() {
+		return propertyTableNumbers;
+	}
+
+	protected int getSubclassPropertyTableNumber(int i) {
+		return subclassPropertyTableNumberClosure[i];
+	}
+
+	public int getTableSpan() {
+		return tableSpan;
+	}
+
+	public boolean isMultiTable() {
+		return true;
+	}
+
+	protected int[] getSubclassColumnTableNumberClosure() {
+		return subclassColumnTableNumberClosure;
+	}
+
+	protected int[] getSubclassFormulaTableNumberClosure() {
+		return subclassFormulaTableNumberClosure;
+	}
+
+	protected int[] getPropertyTableNumbers() {
+		return naturalOrderPropertyTableNumbers;
+	}
+
+	protected String[] getSubclassTableKeyColumns(int j) {
+		return subclassTableKeyColumnClosure[j];
+	}
+
+	public String getSubclassTableName(int j) {
+		return subclassTableNameClosure[j];
+	}
+
+	public int getSubclassTableSpan() {
+		return subclassTableNameClosure.length;
+	}
+
+	protected boolean isClassOrSuperclassTable(int j) {
+		return isClassOrSuperclassTable[j];
+	}
+
+	public String getPropertyTableName(String propertyName) {
+		Integer index = getEntityMetamodel().getPropertyIndexOrNull(propertyName);
+		if ( index == null ) {
+			return null;
+		}
+		return tableNames[ propertyTableNumbers[ index.intValue() ] ];
+	}
+
+	public String[] getConstraintOrderedTableNameClosure() {
+		return constraintOrderedTableNames;
+	}
+
+	public String[][] getContraintOrderedTableKeyColumnClosure() {
+		return constraintOrderedKeyColumnNames;
+	}
+
+	public String getRootTableName() {
+		return naturalOrderTableNames[0];
+	}
+
+	public String getRootTableAlias(String drivingAlias) {
+		return generateTableAlias( drivingAlias, getTableId( getRootTableName(), tableNames ) );
+	}
+
+	public Declarer getSubclassPropertyDeclarer(String propertyPath) {
+		if ( "class".equals( propertyPath ) ) {
+			// special case where we need to force incloude all subclass joins
+			return Declarer.SUBCLASS;
+		}
+		return super.getSubclassPropertyDeclarer( propertyPath );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Loadable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Loadable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Loadable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,88 @@
+//$Id: Loadable.java 7458 2005-07-12 20:12:57Z oneovthafew $
+package org.hibernate.persister.entity;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Implemented by a <tt>EntityPersister</tt> that may be loaded
+ * using <tt>Loader</tt>.
+ *
+ * @see org.hibernate.loader.Loader
+ * @author Gavin King
+ */
+public interface Loadable extends EntityPersister {
+	
+	public static final String ROWID_ALIAS = "rowid_";
+
+	/**
+	 * Does this persistent class have subclasses?
+	 */
+	public boolean hasSubclasses();
+
+	/**
+	 * Get the discriminator type
+	 */
+	public Type getDiscriminatorType();
+
+	/**
+	 * Get the concrete subclass corresponding to the given discriminator
+	 * value
+	 */
+	public String getSubclassForDiscriminatorValue(Object value);
+
+	/**
+	 * Get the names of columns used to persist the identifier
+	 */
+	public String[] getIdentifierColumnNames();
+
+	/**
+	 * Get the result set aliases used for the identifier columns, given a suffix
+	 */
+	public String[] getIdentifierAliases(String suffix);
+	/**
+	 * Get the result set aliases used for the property columns, given a suffix (properties of this class, only).
+	 */
+	public String[] getPropertyAliases(String suffix, int i);
+	
+	/**
+	 * Get the result set column names mapped for this property (properties of this class, only).
+	 */
+	public String[] getPropertyColumnNames(int i);
+	
+	/**
+	 * Get the result set aliases used for the identifier columns, given a suffix
+	 */
+	public String getDiscriminatorAlias(String suffix);
+	
+	/**
+	 * @return the column name for the discriminator as specified in the mapping.
+	 */
+	public String getDiscriminatorColumnName();
+	
+	/**
+	 * Does the result set contain rowids?
+	 */
+	public boolean hasRowId();
+	
+	/**
+	 * Retrieve property values from one row of a result set
+	 */
+	public Object[] hydrate(
+			ResultSet rs,
+			Serializable id,
+			Object object,
+			Loadable rootLoadable,
+			String[][] suffixedPropertyColumns,
+			boolean allProperties, 
+			SessionImplementor session)
+	throws SQLException, HibernateException;
+
+	public boolean isAbstract();
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Lockable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Lockable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Lockable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+package org.hibernate.persister.entity;
+
+/**
+ * Contract for things that can be locked via a {@link org.hibernate.dialect.lock.LockingStrategy}.
+ * <p/>
+ * Currently only the root table gets locked, except for the case of HQL and Criteria queries
+ * against dialects which do not support either (1) FOR UPDATE OF or (2) support hint locking
+ * (in which case *all* queried tables would be locked).
+ *
+ * @author Steve Ebersole
+ * @since 3.2
+ */
+public interface Lockable extends EntityPersister {
+	/**
+	 * Locks are always applied to the "root table".
+	 *
+	 * @return The root table name
+	 */
+	public String getRootTableName();
+
+	/**
+	 * Get the SQL alias this persister would use for the root table
+	 * given the passed driving alias.
+	 *
+	 * @param drivingAlias The driving alias; or the alias for the table
+	 * mapped by this persister in the hierarchy.
+	 * @return The root table alias.
+	 */
+	public String getRootTableAlias(String drivingAlias);
+
+	/**
+	 * Get the names of columns on the root table used to persist the identifier.
+	 *
+	 * @return The root table identifier column names.
+	 */
+	public String[] getRootTableIdentifierColumnNames();
+
+	/**
+	 * For versioned entities, get the name of the column (again, expected on the
+	 * root table) used to store the version values.
+	 *
+	 * @return The version column name.
+	 */
+	public String getVersionColumnName();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/NamedQueryLoader.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/NamedQueryLoader.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/NamedQueryLoader.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,66 @@
+//$Id: NamedQueryLoader.java 10019 2006-06-15 07:50:12Z steve.ebersole at jboss.com $
+package org.hibernate.persister.entity;
+
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.impl.AbstractQueryImpl;
+import org.hibernate.loader.entity.UniqueEntityLoader;
+
+/**
+ * Not really a <tt>Loader</tt>, just a wrapper around a
+ * named query.
+ * @author Gavin King
+ */
+public final class NamedQueryLoader implements UniqueEntityLoader {
+	private final String queryName;
+	private final EntityPersister persister;
+	
+	private static final Log log = LogFactory.getLog(NamedQueryLoader.class);
+
+	public NamedQueryLoader(String queryName, EntityPersister persister) {
+		super();
+		this.queryName = queryName;
+		this.persister = persister;
+	}
+
+	public Object load(Serializable id, Object optionalObject, SessionImplementor session) 
+	throws HibernateException {
+		
+		if ( log.isDebugEnabled() ) {
+			log.debug(
+					"loading entity: " + persister.getEntityName() + 
+					" using named query: " + queryName 
+				);
+		}
+		
+		AbstractQueryImpl query = (AbstractQueryImpl) session.getNamedQuery(queryName);
+		if ( query.hasNamedParameters() ) {
+			query.setParameter( 
+					query.getNamedParameters()[0], 
+					id, 
+					persister.getIdentifierType() 
+				);
+		}
+		else {
+			query.setParameter( 0, id, persister.getIdentifierType() );
+		}
+		query.setOptionalId(id);
+		query.setOptionalEntityName( persister.getEntityName() );
+		query.setOptionalObject(optionalObject);
+		query.setFlushMode( FlushMode.MANUAL );
+		query.list();
+		
+		// now look up the object we are really interested in!
+		// (this lets us correctly handle proxies and multi-row
+		// or multi-column queries)
+		return session.getPersistenceContext()
+				.getEntity( new EntityKey( id, persister, session.getEntityMode() ) );
+
+	}
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/NamedQueryLoader.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/OuterJoinLoadable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/OuterJoinLoadable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/OuterJoinLoadable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,90 @@
+//$Id: OuterJoinLoadable.java 7652 2005-07-26 05:51:47Z oneovthafew $
+package org.hibernate.persister.entity;
+
+import org.hibernate.FetchMode;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+
+/**
+ * A <tt>EntityPersister</tt> that may be loaded by outer join using
+ * the <tt>OuterJoinLoader</tt> hierarchy and may be an element
+ * of a one-to-many association.
+ *
+ * @see org.hibernate.loader.OuterJoinLoader
+ * @author Gavin King
+ */
+public interface OuterJoinLoadable extends Loadable, Joinable {
+
+	/**
+	 * Generate a list of collection index, key and element columns
+	 */
+	public String selectFragment(String alias, String suffix);
+	/**
+	 * How many properties are there, for this class and all subclasses?
+	 */
+	public int countSubclassProperties();
+
+	/**
+	 * May this (subclass closure) property be fetched using an SQL outerjoin?
+	 */
+	public FetchMode getFetchMode(int i);
+	/**
+	 * Get the cascade style of this (subclass closure) property
+	 */
+	public CascadeStyle getCascadeStyle(int i);
+
+	/**
+	 * Is this property defined on a subclass of the mapped class.
+	 */
+	public boolean isDefinedOnSubclass(int i);
+
+	/**
+	 * Get the type of the numbered property of the class or a subclass.
+	 */
+	public Type getSubclassPropertyType(int i);
+
+	/**
+	 * Get the name of the numbered property of the class or a subclass.
+	 */
+	public String getSubclassPropertyName(int i);
+	
+	/**
+	 * Is the numbered property of the class of subclass nullable?
+	 */
+	public boolean isSubclassPropertyNullable(int i);
+
+	/**
+	 * Return the column names used to persist the numbered property of the
+	 * class or a subclass.
+	 */
+	public String[] getSubclassPropertyColumnNames(int i);
+
+	/**
+	 * Return the table name used to persist the numbered property of the
+	 * class or a subclass.
+	 */
+	public String getSubclassPropertyTableName(int i);
+	/**
+	 * Given the number of a property of a subclass, and a table alias,
+	 * return the aliased column names.
+	 */
+	public String[] toColumns(String name, int i);
+
+	/**
+	 * Get the main from table fragment, given a query alias.
+	 */
+	public String fromTableFragment(String alias);
+
+	/**
+	 * Get the column names for the given property path
+	 */
+	public String[] getPropertyColumnNames(String propertyPath);
+	/**
+	 * Get the table name for the given property path
+	 */
+	public String getPropertyTableName(String propertyName);
+	
+	public EntityType getEntityType();
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/PropertyMapping.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/PropertyMapping.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/PropertyMapping.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+//$Id: PropertyMapping.java 6179 2005-03-23 15:41:48Z steveebersole $
+package org.hibernate.persister.entity;
+
+import org.hibernate.QueryException;
+import org.hibernate.type.Type;
+
+/**
+ * Abstraction of all mappings that define properties:
+ * entities, collection elements.
+ *
+ * @author Gavin King
+ */
+public interface PropertyMapping {
+	// TODO: It would be really, really nice to use this to also model components!
+	/**
+	 * Given a component path expression, get the type of the property
+	 */
+	public Type toType(String propertyName) throws QueryException;
+	/**
+	 * Given a query alias and a property path, return the qualified
+	 * column name
+	 */
+	public String[] toColumns(String alias, String propertyName) throws QueryException;
+	/**
+	 * Given a property path, return the corresponding column name(s).
+	 */
+	public String[] toColumns(String propertyName) throws QueryException, UnsupportedOperationException;
+	/**
+	 * Get the type of the thing containing the properties
+	 */
+	public Type getType();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Queryable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Queryable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/Queryable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,154 @@
+//$Id: Queryable.java 10824 2006-11-16 19:32:48Z steve.ebersole at jboss.com $
+package org.hibernate.persister.entity;
+
+/**
+ * Extends the generic <tt>EntityPersister</tt> contract to add
+ * operations required by the Hibernate Query Language
+ *
+ * @author Gavin King
+ */
+public interface Queryable extends Loadable, PropertyMapping, Joinable {
+
+	/**
+	 * Is this an abstract class?
+	 */
+	public boolean isAbstract();
+	/**
+	 * Is this class explicit polymorphism only?
+	 */
+	public boolean isExplicitPolymorphism();
+	/**
+	 * Get the class that this class is mapped as a subclass of -
+	 * not necessarily the direct superclass
+	 */
+	public String getMappedSuperclass();
+	/**
+	 * Get the discriminator value for this particular concrete subclass,
+	 * as a string that may be embedded in a select statement
+	 */
+	public String getDiscriminatorSQLValue();
+
+	/**
+	 * Given a query alias and an identifying suffix, render the intentifier select fragment.
+	 */
+	public String identifierSelectFragment(String name, String suffix);
+	/**
+	 * Given a query alias and an identifying suffix, render the property select fragment.
+	 */
+	public String propertySelectFragment(String alias, String suffix, boolean allProperties);
+
+	/**
+	 * Get the names of columns used to persist the identifier
+	 */
+	public String[] getIdentifierColumnNames();
+
+	/**
+	 * Is the inheritence hierarchy described by this persister contained across
+	 * multiple tables?
+	 *
+	 * @return True if the inheritence hierarchy is spread across multiple tables; false otherwise.
+	 */
+	public boolean isMultiTable();
+
+	/**
+	 * Get the names of all tables used in the hierarchy (up and down) ordered such
+	 * that deletes in the given order would not cause contraint violations.
+	 *
+	 * @return The ordered array of table names.
+	 */
+	public String[] getConstraintOrderedTableNameClosure();
+
+	/**
+	 * For each table specified in {@link #getConstraintOrderedTableNameClosure()}, get
+	 * the columns that define the key between the various hierarchy classes.
+	 * <p/>
+	 * The first dimension here corresponds to the table indexes returned in
+	 * {@link #getConstraintOrderedTableNameClosure()}.
+	 * <p/>
+	 * The second dimension should have the same length across all the elements in
+	 * the first dimension.  If not, that'd be a problem ;)
+	 *
+	 * @return
+	 */
+	public String[][] getContraintOrderedTableKeyColumnClosure();
+
+	/**
+	 * Get the name of the temporary table to be used to (potentially) store id values
+	 * when performing bulk update/deletes.
+	 *
+	 * @return The appropriate temporary table name.
+	 */
+	public String getTemporaryIdTableName();
+
+	/**
+	 * Get the appropriate DDL command for generating the temporary table to
+	 * be used to (potentially) store id values when performing bulk update/deletes.
+	 *
+	 * @return The appropriate temporary table creation command.
+	 */
+	public String getTemporaryIdTableDDL();
+
+	/**
+	 * Given a property name, determine the number of the table which contains the column
+	 * to which this property is mapped.
+	 * <p/>
+	 * Note that this is <b>not</b> relative to the results from {@link #getConstraintOrderedTableNameClosure()}.
+	 * It is relative to the subclass table name closure maintained internal to the persister (yick!).
+	 * It is also relative to the indexing used to resolve {@link #getSubclassTableName}...
+	 *
+	 * @param propertyPath The name of the property.
+	 * @return The nunber of the table to which the property is mapped.
+	 */
+	public int getSubclassPropertyTableNumber(String propertyPath);
+
+	/**
+	 * Determine whether the given property is declared by our
+	 * mapped class, our super class, or one of our subclasses...
+	 * <p/>
+	 * Note: the method is called 'subclass property...' simply
+	 * for consistency sake (e.g. {@link #getSubclassPropertyTableNumber}
+	 *
+	 * @param propertyPath The property name.
+	 * @return The property declarer
+	 */
+	public Declarer getSubclassPropertyDeclarer(String propertyPath);
+
+	/**
+	 * Get the name of the table with the given index from the internal
+	 * array.
+	 *
+	 * @param number The index into the internal array.
+	 * @return
+	 */
+	public String getSubclassTableName(int number);
+
+	/**
+	 * Is the version property included in insert statements?
+	 */
+	public boolean isVersionPropertyInsertable();
+
+	/**
+	 * The alias used for any filter conditions (mapped where-fragments or
+	 * enabled-filters).
+	 * </p>
+	 * This may or may not be different from the root alias depending upon the
+	 * inheritence mapping strategy.
+	 *
+	 * @param rootAlias The root alias
+	 * @return The alias used for "filter conditions" within the where clause.
+	 */
+	public String generateFilterConditionAlias(String rootAlias);
+
+	public static class Declarer {
+		public static final Declarer CLASS = new Declarer( "class" );
+		public static final Declarer SUBCLASS = new Declarer( "subclass" );
+		public static final Declarer SUPERCLASS = new Declarer( "superclass" );
+		private final String name;
+		public Declarer(String name) {
+			this.name = name;
+		}
+		public String toString() {
+			return name;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/SQLLoadable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/SQLLoadable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/SQLLoadable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+//$Id: SQLLoadable.java 7363 2005-07-03 19:42:43Z maxcsaucdk $
+package org.hibernate.persister.entity;
+
+import org.hibernate.type.Type;
+
+/**
+ * A class persister that supports queries expressed in the
+ * platform native SQL dialect
+ *
+ * @author Gavin King, Max Andersen
+ */
+public interface SQLLoadable extends Loadable {
+
+	/**
+	 * Return the column alias names used to persist/query the named property of the class or a subclass (optional operation).
+	 */
+	public String[] getSubclassPropertyColumnAliases(String propertyName, String suffix);
+
+	/**
+	 * Return the column names used to persist/query the named property of the class or a subclass (optional operation).
+	 */
+	public String[] getSubclassPropertyColumnNames(String propertyName);
+	
+	/**
+	 * All columns to select, when loading.
+	 */
+	public String selectFragment(String alias, String suffix);
+
+	/**
+	 * Get the type
+	 */
+	public Type getType();
+
+	
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,713 @@
+//$Id: SingleTableEntityPersister.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.persister.entity;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Formula;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.Selectable;
+import org.hibernate.mapping.Subclass;
+import org.hibernate.mapping.Table;
+import org.hibernate.mapping.Value;
+import org.hibernate.sql.InFragment;
+import org.hibernate.sql.Insert;
+import org.hibernate.sql.SelectFragment;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.DiscriminatorType;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.MarkerObject;
+
+/**
+ * The default implementation of the <tt>EntityPersister</tt> interface.
+ * Implements the "table-per-class-hierarchy" or "roll-up" mapping strategy
+ * for an entity class and its inheritence hierarchy.  This is implemented
+ * as a single table holding all classes in the hierarchy with a discrimator
+ * column used to determine which concrete class is referenced.
+ *
+ * @author Gavin King
+ */
+public class SingleTableEntityPersister extends AbstractEntityPersister {
+
+	// the class hierarchy structure
+	private final int joinSpan;
+	private final String[] qualifiedTableNames;
+	private final boolean[] isInverseTable;
+	private final boolean[] isNullableTable;
+	private final String[][] keyColumnNames;
+	private final boolean[] cascadeDeleteEnabled;
+	private final boolean hasSequentialSelects;
+	
+	private final String[] spaces;
+
+	private final String[] subclassClosure;
+
+	private final String[] subclassTableNameClosure;
+	private final boolean[] subclassTableIsLazyClosure;
+	private final boolean[] isInverseSubclassTable;
+	private final boolean[] isNullableSubclassTable;
+	private final boolean[] subclassTableSequentialSelect;
+	private final String[][] subclassTableKeyColumnClosure;
+	private final boolean[] isClassOrSuperclassTable;
+
+	// properties of this class, including inherited properties
+	private final int[] propertyTableNumbers;
+
+	// the closure of all columns used by the entire hierarchy including
+	// subclasses and superclasses of this class
+	private final int[] subclassPropertyTableNumberClosure;
+
+	private final int[] subclassColumnTableNumberClosure;
+	private final int[] subclassFormulaTableNumberClosure;
+
+	// discriminator column
+	private final Map subclassesByDiscriminatorValue = new HashMap();
+	private final boolean forceDiscriminator;
+	private final String discriminatorColumnName;
+	private final String discriminatorFormula;
+	private final String discriminatorFormulaTemplate;
+	private final String discriminatorAlias;
+	private final Type discriminatorType;
+	private final String discriminatorSQLValue;
+	private final boolean discriminatorInsertable;
+
+	private final String[] constraintOrderedTableNames;
+	private final String[][] constraintOrderedKeyColumnNames;
+
+	//private final Map propertyTableNumbersByName = new HashMap();
+	private final Map propertyTableNumbersByNameAndSubclass = new HashMap();
+	
+	private final Map sequentialSelectStringsByEntityName = new HashMap();
+
+	private static final Object NULL_DISCRIMINATOR = new MarkerObject("<null discriminator>");
+	private static final Object NOT_NULL_DISCRIMINATOR = new MarkerObject("<not null discriminator>");
+
+	//INITIALIZATION:
+
+	public SingleTableEntityPersister(
+			final PersistentClass persistentClass, 
+			final EntityRegionAccessStrategy cacheAccessStrategy,
+			final SessionFactoryImplementor factory,
+			final Mapping mapping) throws HibernateException {
+
+		super( persistentClass, cacheAccessStrategy, factory );
+
+		// CLASS + TABLE
+
+		joinSpan = persistentClass.getJoinClosureSpan()+1;
+		qualifiedTableNames = new String[joinSpan];
+		isInverseTable = new boolean[joinSpan];
+		isNullableTable = new boolean[joinSpan];
+		keyColumnNames = new String[joinSpan][];
+		final Table table = persistentClass.getRootTable();
+		qualifiedTableNames[0] = table.getQualifiedName( 
+				factory.getDialect(), 
+				factory.getSettings().getDefaultCatalogName(), 
+				factory.getSettings().getDefaultSchemaName() 
+		);
+		isInverseTable[0] = false;
+		isNullableTable[0] = false;
+		keyColumnNames[0] = getIdentifierColumnNames();
+		cascadeDeleteEnabled = new boolean[joinSpan];
+
+		// Custom sql
+		customSQLInsert = new String[joinSpan];
+		customSQLUpdate = new String[joinSpan];
+		customSQLDelete = new String[joinSpan];
+		insertCallable = new boolean[joinSpan];
+		updateCallable = new boolean[joinSpan];
+		deleteCallable = new boolean[joinSpan];
+		insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];
+		updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];
+		deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];
+
+		customSQLInsert[0] = persistentClass.getCustomSQLInsert();
+		insertCallable[0] = customSQLInsert[0] != null && persistentClass.isCustomInsertCallable();
+		insertResultCheckStyles[0] = persistentClass.getCustomSQLInsertCheckStyle() == null
+									  ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[0], insertCallable[0] )
+									  : persistentClass.getCustomSQLInsertCheckStyle();
+		customSQLUpdate[0] = persistentClass.getCustomSQLUpdate();
+		updateCallable[0] = customSQLUpdate[0] != null && persistentClass.isCustomUpdateCallable();
+		updateResultCheckStyles[0] = persistentClass.getCustomSQLUpdateCheckStyle() == null
+									  ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[0], updateCallable[0] )
+									  : persistentClass.getCustomSQLUpdateCheckStyle();
+		customSQLDelete[0] = persistentClass.getCustomSQLDelete();
+		deleteCallable[0] = customSQLDelete[0] != null && persistentClass.isCustomDeleteCallable();
+		deleteResultCheckStyles[0] = persistentClass.getCustomSQLDeleteCheckStyle() == null
+									  ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[0], deleteCallable[0] )
+									  : persistentClass.getCustomSQLDeleteCheckStyle();
+
+		// JOINS
+
+		Iterator joinIter = persistentClass.getJoinClosureIterator();
+		int j = 1;
+		while ( joinIter.hasNext() ) {
+			Join join = (Join) joinIter.next();
+			qualifiedTableNames[j] = join.getTable().getQualifiedName( 
+					factory.getDialect(), 
+					factory.getSettings().getDefaultCatalogName(), 
+					factory.getSettings().getDefaultSchemaName() 
+			);
+			isInverseTable[j] = join.isInverse();
+			isNullableTable[j] = join.isOptional();
+			cascadeDeleteEnabled[j] = join.getKey().isCascadeDeleteEnabled() && 
+				factory.getDialect().supportsCascadeDelete();
+
+			customSQLInsert[j] = join.getCustomSQLInsert();
+			insertCallable[j] = customSQLInsert[j] != null && join.isCustomInsertCallable();
+			insertResultCheckStyles[j] = join.getCustomSQLInsertCheckStyle() == null
+			                              ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[j], insertCallable[j] )
+		                                  : join.getCustomSQLInsertCheckStyle();
+			customSQLUpdate[j] = join.getCustomSQLUpdate();
+			updateCallable[j] = customSQLUpdate[j] != null && join.isCustomUpdateCallable();
+			updateResultCheckStyles[j] = join.getCustomSQLUpdateCheckStyle() == null
+			                              ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[j], updateCallable[j] )
+		                                  : join.getCustomSQLUpdateCheckStyle();
+			customSQLDelete[j] = join.getCustomSQLDelete();
+			deleteCallable[j] = customSQLDelete[j] != null && join.isCustomDeleteCallable();
+			deleteResultCheckStyles[j] = join.getCustomSQLDeleteCheckStyle() == null
+			                              ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[j], deleteCallable[j] )
+		                                  : join.getCustomSQLDeleteCheckStyle();
+
+			Iterator iter = join.getKey().getColumnIterator();
+			keyColumnNames[j] = new String[ join.getKey().getColumnSpan() ];
+			int i = 0;
+			while ( iter.hasNext() ) {
+				Column col = (Column) iter.next();
+				keyColumnNames[j][i++] = col.getQuotedName( factory.getDialect() );
+			}
+
+			j++;
+		}
+
+		constraintOrderedTableNames = new String[qualifiedTableNames.length];
+		constraintOrderedKeyColumnNames = new String[qualifiedTableNames.length][];
+		for ( int i = qualifiedTableNames.length - 1, position = 0; i >= 0; i--, position++ ) {
+			constraintOrderedTableNames[position] = qualifiedTableNames[i];
+			constraintOrderedKeyColumnNames[position] = keyColumnNames[i];
+		}
+
+		spaces = ArrayHelper.join(
+				qualifiedTableNames, 
+				ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
+		);
+		
+		final boolean lazyAvailable = isInstrumented(EntityMode.POJO);
+
+		boolean hasDeferred = false;
+		ArrayList subclassTables = new ArrayList();
+		ArrayList joinKeyColumns = new ArrayList();
+		ArrayList isConcretes = new ArrayList();
+		ArrayList isDeferreds = new ArrayList();
+		ArrayList isInverses = new ArrayList();
+		ArrayList isNullables = new ArrayList();
+		ArrayList isLazies = new ArrayList();
+		subclassTables.add( qualifiedTableNames[0] );
+		joinKeyColumns.add( getIdentifierColumnNames() );
+		isConcretes.add(Boolean.TRUE);
+		isDeferreds.add(Boolean.FALSE);
+		isInverses.add(Boolean.FALSE);
+		isNullables.add(Boolean.FALSE);
+		isLazies.add(Boolean.FALSE);
+		joinIter = persistentClass.getSubclassJoinClosureIterator();
+		while ( joinIter.hasNext() ) {
+			Join join = (Join) joinIter.next();
+			isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassJoin(join) ) );
+			isDeferreds.add( new Boolean( join.isSequentialSelect() ) );
+			isInverses.add( new Boolean( join.isInverse() ) );
+			isNullables.add( new Boolean( join.isOptional() ) );
+			isLazies.add( new Boolean( lazyAvailable && join.isLazy() ) );
+			if ( join.isSequentialSelect() && !persistentClass.isClassOrSuperclassJoin(join) ) hasDeferred = true;
+			subclassTables.add( join.getTable().getQualifiedName( 
+					factory.getDialect(), 
+					factory.getSettings().getDefaultCatalogName(), 
+					factory.getSettings().getDefaultSchemaName() 
+			) );
+			Iterator iter = join.getKey().getColumnIterator();
+			String[] keyCols = new String[ join.getKey().getColumnSpan() ];
+			int i = 0;
+			while ( iter.hasNext() ) {
+				Column col = (Column) iter.next();
+				keyCols[i++] = col.getQuotedName( factory.getDialect() );
+			}
+			joinKeyColumns.add(keyCols);
+		}
+		
+		subclassTableSequentialSelect = ArrayHelper.toBooleanArray(isDeferreds);
+		subclassTableNameClosure = ArrayHelper.toStringArray(subclassTables);
+		subclassTableIsLazyClosure = ArrayHelper.toBooleanArray(isLazies);
+		subclassTableKeyColumnClosure = ArrayHelper.to2DStringArray(joinKeyColumns);
+		isClassOrSuperclassTable = ArrayHelper.toBooleanArray(isConcretes);
+		isInverseSubclassTable = ArrayHelper.toBooleanArray(isInverses);
+		isNullableSubclassTable = ArrayHelper.toBooleanArray(isNullables);
+		hasSequentialSelects = hasDeferred;
+
+		// DISCRIMINATOR
+
+		final Object discriminatorValue;
+		if ( persistentClass.isPolymorphic() ) {
+			Value discrimValue = persistentClass.getDiscriminator();
+			if (discrimValue==null) {
+				throw new MappingException("discriminator mapping required for single table polymorphic persistence");
+			}
+			forceDiscriminator = persistentClass.isForceDiscriminator();
+			Selectable selectable = (Selectable) discrimValue.getColumnIterator().next();
+			if ( discrimValue.hasFormula() ) {
+				Formula formula = (Formula) selectable;
+				discriminatorFormula = formula.getFormula();
+				discriminatorFormulaTemplate = formula.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
+				discriminatorColumnName = null;
+				discriminatorAlias = "clazz_";
+			}
+			else {
+				Column column = (Column) selectable;
+				discriminatorColumnName = column.getQuotedName( factory.getDialect() );
+				discriminatorAlias = column.getAlias( factory.getDialect(), persistentClass.getRootTable() );
+				discriminatorFormula = null;
+				discriminatorFormulaTemplate = null;
+			}
+			discriminatorType = persistentClass.getDiscriminator().getType();
+			if ( persistentClass.isDiscriminatorValueNull() ) {
+				discriminatorValue = NULL_DISCRIMINATOR;
+				discriminatorSQLValue = InFragment.NULL;
+				discriminatorInsertable = false;
+			}
+			else if ( persistentClass.isDiscriminatorValueNotNull() ) {
+				discriminatorValue = NOT_NULL_DISCRIMINATOR;
+				discriminatorSQLValue = InFragment.NOT_NULL;
+				discriminatorInsertable = false;
+			}
+			else {
+				discriminatorInsertable = persistentClass.isDiscriminatorInsertable() && !discrimValue.hasFormula();
+				try {
+					DiscriminatorType dtype = (DiscriminatorType) discriminatorType;
+					discriminatorValue = dtype.stringToObject( persistentClass.getDiscriminatorValue() );
+					discriminatorSQLValue = dtype.objectToSQLString( discriminatorValue, factory.getDialect() );
+				}
+				catch (ClassCastException cce) {
+					throw new MappingException("Illegal discriminator type: " + discriminatorType.getName() );
+				}
+				catch (Exception e) {
+					throw new MappingException("Could not format discriminator value to SQL string", e);
+				}
+			}
+		}
+		else {
+			forceDiscriminator = false;
+			discriminatorInsertable = false;
+			discriminatorColumnName = null;
+			discriminatorAlias = null;
+			discriminatorType = null;
+			discriminatorValue = null;
+			discriminatorSQLValue = null;
+			discriminatorFormula = null;
+			discriminatorFormulaTemplate = null;
+		}
+
+		// PROPERTIES
+
+		propertyTableNumbers = new int[ getPropertySpan() ];
+		Iterator iter = persistentClass.getPropertyClosureIterator();
+		int i=0;
+		while( iter.hasNext() ) {
+			Property prop = (Property) iter.next();
+			propertyTableNumbers[i++] = persistentClass.getJoinNumber(prop);
+
+		}
+
+		//TODO: code duplication with JoinedSubclassEntityPersister
+		
+		ArrayList columnJoinNumbers = new ArrayList();
+		ArrayList formulaJoinedNumbers = new ArrayList();
+		ArrayList propertyJoinNumbers = new ArrayList();
+		
+		iter = persistentClass.getSubclassPropertyClosureIterator();
+		while ( iter.hasNext() ) {
+			Property prop = (Property) iter.next();
+			Integer join = new Integer( persistentClass.getJoinNumber(prop) );
+			propertyJoinNumbers.add(join);
+
+			//propertyTableNumbersByName.put( prop.getName(), join );
+			propertyTableNumbersByNameAndSubclass.put( 
+					prop.getPersistentClass().getEntityName() + '.' + prop.getName(), 
+					join 
+			);
+
+			Iterator citer = prop.getColumnIterator();
+			while ( citer.hasNext() ) {
+				Selectable thing = (Selectable) citer.next();
+				if ( thing.isFormula() ) {
+					formulaJoinedNumbers.add(join);
+				}
+				else {
+					columnJoinNumbers.add(join);
+				}
+			}
+		}
+		subclassColumnTableNumberClosure = ArrayHelper.toIntArray(columnJoinNumbers);
+		subclassFormulaTableNumberClosure = ArrayHelper.toIntArray(formulaJoinedNumbers);
+		subclassPropertyTableNumberClosure = ArrayHelper.toIntArray(propertyJoinNumbers);
+
+		int subclassSpan = persistentClass.getSubclassSpan() + 1;
+		subclassClosure = new String[subclassSpan];
+		subclassClosure[0] = getEntityName();
+		if ( persistentClass.isPolymorphic() ) {
+			subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
+		}
+
+		// SUBCLASSES
+		if ( persistentClass.isPolymorphic() ) {
+			iter = persistentClass.getSubclassIterator();
+			int k=1;
+			while ( iter.hasNext() ) {
+				Subclass sc = (Subclass) iter.next();
+				subclassClosure[k++] = sc.getEntityName();
+				if ( sc.isDiscriminatorValueNull() ) {
+					subclassesByDiscriminatorValue.put( NULL_DISCRIMINATOR, sc.getEntityName() );
+				}
+				else if ( sc.isDiscriminatorValueNotNull() ) {
+					subclassesByDiscriminatorValue.put( NOT_NULL_DISCRIMINATOR, sc.getEntityName() );
+				}
+				else {
+					try {
+						DiscriminatorType dtype = (DiscriminatorType) discriminatorType;
+						subclassesByDiscriminatorValue.put(
+							dtype.stringToObject( sc.getDiscriminatorValue() ),
+							sc.getEntityName()
+						);
+					}
+					catch (ClassCastException cce) {
+						throw new MappingException("Illegal discriminator type: " + discriminatorType.getName() );
+					}
+					catch (Exception e) {
+						throw new MappingException("Error parsing discriminator value", e);
+					}
+				}
+			}
+		}
+
+		initLockers();
+
+		initSubclassPropertyAliasesMap(persistentClass);
+		
+		postConstruct(mapping);
+
+	}
+
+	protected boolean isInverseTable(int j) {
+		return isInverseTable[j];
+	}
+
+	protected boolean isInverseSubclassTable(int j) {
+		return isInverseSubclassTable[j];
+	}
+
+	public String getDiscriminatorColumnName() {
+		return discriminatorColumnName;
+	}
+
+	protected String getDiscriminatorAlias() {
+		return discriminatorAlias;
+	}
+
+	protected String getDiscriminatorFormulaTemplate() {
+		return discriminatorFormulaTemplate;
+	}
+
+	public String getTableName() {
+		return qualifiedTableNames[0];
+	}
+
+	public Type getDiscriminatorType() {
+		return discriminatorType;
+	}
+
+	public String getDiscriminatorSQLValue() {
+		return discriminatorSQLValue;
+	}
+
+	public String[] getSubclassClosure() {
+		return subclassClosure;
+	}
+
+	public String getSubclassForDiscriminatorValue(Object value) {
+		if (value==null) {
+			return (String) subclassesByDiscriminatorValue.get(NULL_DISCRIMINATOR);
+		}
+		else {
+			String result = (String) subclassesByDiscriminatorValue.get(value);
+			if (result==null) result = (String) subclassesByDiscriminatorValue.get(NOT_NULL_DISCRIMINATOR);
+			return result;
+		}
+	}
+
+	public Serializable[] getPropertySpaces() {
+		return spaces;
+	}
+
+	//Access cached SQL
+
+	protected boolean isDiscriminatorFormula() {
+		return discriminatorColumnName==null;
+	}
+
+	protected String getDiscriminatorFormula() {
+		return discriminatorFormula;
+	}
+
+	protected String getTableName(int j) {
+		return qualifiedTableNames[j];
+	}
+	
+	protected String[] getKeyColumns(int j) {
+		return keyColumnNames[j];
+	}
+	
+	protected boolean isTableCascadeDeleteEnabled(int j) {
+		return cascadeDeleteEnabled[j];
+	}
+	
+	protected boolean isPropertyOfTable(int property, int j) {
+		return propertyTableNumbers[property]==j;
+	}
+
+	protected boolean isSubclassTableSequentialSelect(int j) {
+		return subclassTableSequentialSelect[j] && !isClassOrSuperclassTable[j];
+	}
+	
+	// Execute the SQL:
+
+	public String fromTableFragment(String name) {
+		return getTableName() + ' ' + name;
+	}
+
+	public String filterFragment(String alias) throws MappingException {
+		String result = discriminatorFilterFragment(alias);
+		if ( hasWhere() ) result += " and " + getSQLWhereString(alias);
+		return result;
+	}
+	
+	public String oneToManyFilterFragment(String alias) throws MappingException {
+		return forceDiscriminator ?
+			discriminatorFilterFragment(alias) :
+			"";
+	}
+
+	private String discriminatorFilterFragment(String alias) throws MappingException {
+		if ( needsDiscriminator() ) {
+			InFragment frag = new InFragment();
+
+			if ( isDiscriminatorFormula() ) {
+				frag.setFormula( alias, getDiscriminatorFormulaTemplate() );
+			}
+			else {
+				frag.setColumn( alias, getDiscriminatorColumnName() );
+			}
+
+			String[] subclasses = getSubclassClosure();
+			for ( int i=0; i<subclasses.length; i++ ) {
+				final Queryable queryable = (Queryable) getFactory().getEntityPersister( subclasses[i] );
+				if ( !queryable.isAbstract() ) frag.addValue( queryable.getDiscriminatorSQLValue() );
+			}
+
+			StringBuffer buf = new StringBuffer(50)
+				.append(" and ")
+				.append( frag.toFragmentString() );
+
+			return buf.toString();
+		}
+		else {
+			return "";
+		}
+	}
+
+	private boolean needsDiscriminator() {
+		return forceDiscriminator || isInherited();
+	}
+
+	public String getSubclassPropertyTableName(int i) {
+		return subclassTableNameClosure[ subclassPropertyTableNumberClosure[i] ];
+	}
+
+	protected void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) {
+		if ( isDiscriminatorFormula() ) {
+			select.addFormula( name, getDiscriminatorFormulaTemplate(), getDiscriminatorAlias() );
+		}
+		else {
+			select.addColumn( name, getDiscriminatorColumnName(),  getDiscriminatorAlias() );
+		}
+	}
+	
+	protected int[] getPropertyTableNumbersInSelect() {
+		return propertyTableNumbers;
+	}
+
+	protected int getSubclassPropertyTableNumber(int i) {
+		return subclassPropertyTableNumberClosure[i];
+	}
+
+	public int getTableSpan() {
+		return joinSpan;
+	}
+
+	protected void addDiscriminatorToInsert(Insert insert) {
+
+		if (discriminatorInsertable) {
+			insert.addColumn( getDiscriminatorColumnName(), discriminatorSQLValue );
+		}
+
+	}
+
+	protected int[] getSubclassColumnTableNumberClosure() {
+		return subclassColumnTableNumberClosure;
+	}
+
+	protected int[] getSubclassFormulaTableNumberClosure() {
+		return subclassFormulaTableNumberClosure;
+	}
+
+	protected int[] getPropertyTableNumbers() {
+		return propertyTableNumbers;
+	}
+		
+	protected boolean isSubclassPropertyDeferred(String propertyName, String entityName) {
+		return hasSequentialSelects && 
+			isSubclassTableSequentialSelect( getSubclassPropertyTableNumber(propertyName, entityName) );
+	}
+	
+	public boolean hasSequentialSelect() {
+		return hasSequentialSelects;
+	}
+	
+	private int getSubclassPropertyTableNumber(String propertyName, String entityName) {
+		Type type = propertyMapping.toType(propertyName);
+		if ( type.isAssociationType() && ( (AssociationType) type ).useLHSPrimaryKey() ) return 0;
+		final Integer tabnum = (Integer) propertyTableNumbersByNameAndSubclass.get(entityName + '.' + propertyName);
+		return tabnum==null ? 0 : tabnum.intValue();
+	}
+	
+	protected String getSequentialSelect(String entityName) {
+		return (String) sequentialSelectStringsByEntityName.get(entityName);
+	}
+
+	private String generateSequentialSelect(Loadable persister) {
+		//if ( this==persister || !hasSequentialSelects ) return null;
+
+		//note that this method could easily be moved up to BasicEntityPersister,
+		//if we ever needed to reuse it from other subclasses
+		
+		//figure out which tables need to be fetched
+		AbstractEntityPersister subclassPersister = (AbstractEntityPersister) persister;
+		HashSet tableNumbers = new HashSet();
+		String[] props = subclassPersister.getPropertyNames();
+		String[] classes = subclassPersister.getPropertySubclassNames();
+		for ( int i=0; i<props.length; i++ ) {
+			int propTableNumber = getSubclassPropertyTableNumber( props[i], classes[i] );
+			if ( isSubclassTableSequentialSelect(propTableNumber) && !isSubclassTableLazy(propTableNumber) ) {
+				tableNumbers.add( new Integer(propTableNumber) );
+			}
+		}
+		if ( tableNumbers.isEmpty() ) return null;
+		
+		//figure out which columns are needed
+		ArrayList columnNumbers = new ArrayList();
+		final int[] columnTableNumbers = getSubclassColumnTableNumberClosure();
+		for ( int i=0; i<getSubclassColumnClosure().length; i++ ) {
+			if ( tableNumbers.contains( new Integer( columnTableNumbers[i] ) ) ) {
+				columnNumbers.add( new Integer(i) );
+			}
+		}
+		
+		//figure out which formulas are needed
+		ArrayList formulaNumbers = new ArrayList();
+		final int[] formulaTableNumbers = getSubclassColumnTableNumberClosure();
+		for ( int i=0; i<getSubclassFormulaTemplateClosure().length; i++ ) {
+			if ( tableNumbers.contains( new Integer( formulaTableNumbers[i] ) ) ) {
+				formulaNumbers.add( new Integer(i) );
+			}
+		}
+		
+		//render the SQL
+		return renderSelect( 
+			ArrayHelper.toIntArray(tableNumbers),
+			ArrayHelper.toIntArray(columnNumbers),
+			ArrayHelper.toIntArray(formulaNumbers)
+		);
+	}
+		
+		
+	protected String[] getSubclassTableKeyColumns(int j) {
+		return subclassTableKeyColumnClosure[j];
+	}
+
+	public String getSubclassTableName(int j) {
+		return subclassTableNameClosure[j];
+	}
+
+	public int getSubclassTableSpan() {
+		return subclassTableNameClosure.length;
+	}
+
+	protected boolean isClassOrSuperclassTable(int j) {
+		return isClassOrSuperclassTable[j];
+	}
+
+	protected boolean isSubclassTableLazy(int j) {
+		return subclassTableIsLazyClosure[j];
+	}
+	
+	protected boolean isNullableTable(int j) {
+		return isNullableTable[j];
+	}
+	
+	protected boolean isNullableSubclassTable(int j) {
+		return isNullableSubclassTable[j];
+	}
+
+	public String getPropertyTableName(String propertyName) {
+		Integer index = getEntityMetamodel().getPropertyIndexOrNull(propertyName);
+		if (index==null) return null;
+		return qualifiedTableNames[ propertyTableNumbers[ index.intValue() ] ];
+	}
+	
+	public void postInstantiate() {
+		super.postInstantiate();
+		if (hasSequentialSelects) {
+			String[] entityNames = getSubclassClosure();
+			for ( int i=1; i<entityNames.length; i++ ) {
+				Loadable loadable = (Loadable) getFactory().getEntityPersister( entityNames[i] );
+				if ( !loadable.isAbstract() ) { //perhaps not really necessary...
+					String sequentialSelect = generateSequentialSelect(loadable);
+					sequentialSelectStringsByEntityName.put( entityNames[i], sequentialSelect );
+				}
+			}
+		}
+	}
+
+	public boolean isMultiTable() {
+		return getTableSpan() > 1;
+	}
+
+	public String[] getConstraintOrderedTableNameClosure() {
+		return constraintOrderedTableNames;
+	}
+
+	public String[][] getContraintOrderedTableKeyColumnClosure() {
+		return constraintOrderedKeyColumnNames;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,459 @@
+//$Id: UnionSubclassEntityPersister.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.persister.entity;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.ArrayList;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cfg.Settings;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.id.IdentityGenerator;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Subclass;
+import org.hibernate.mapping.Table;
+import org.hibernate.sql.SelectFragment;
+import org.hibernate.sql.SimpleSelect;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.JoinedIterator;
+import org.hibernate.util.SingletonIterator;
+
+/**
+ * Implementation of the "table-per-concrete-class" or "roll-down" mapping 
+ * strategy for an entity and its inheritence hierarchy.
+ *
+ * @author Gavin King
+ */
+public class UnionSubclassEntityPersister extends AbstractEntityPersister {
+
+	// the class hierarchy structure
+	private final String subquery;
+	private final String tableName;
+	//private final String rootTableName;
+	private final String[] subclassClosure;
+	private final String[] spaces;
+	private final String[] subclassSpaces;
+	private final String discriminatorSQLValue;
+	private final Map subclassByDiscriminatorValue = new HashMap();
+
+	private final String[] constraintOrderedTableNames;
+	private final String[][] constraintOrderedKeyColumnNames;
+
+	//INITIALIZATION:
+
+	public UnionSubclassEntityPersister(
+			final PersistentClass persistentClass, 
+			final EntityRegionAccessStrategy cacheAccessStrategy,
+			final SessionFactoryImplementor factory,
+			final Mapping mapping) throws HibernateException {
+
+		super( persistentClass, cacheAccessStrategy, factory );
+		
+		if ( getIdentifierGenerator() instanceof IdentityGenerator ) {
+			throw new MappingException(
+					"Cannot use identity column key generation with <union-subclass> mapping for: " + 
+					getEntityName() 
+			);
+		}
+
+		// TABLE
+
+		tableName = persistentClass.getTable().getQualifiedName( 
+				factory.getDialect(), 
+				factory.getSettings().getDefaultCatalogName(), 
+				factory.getSettings().getDefaultSchemaName() 
+		);
+		/*rootTableName = persistentClass.getRootTable().getQualifiedName( 
+				factory.getDialect(), 
+				factory.getDefaultCatalog(), 
+				factory.getDefaultSchema() 
+		);*/
+
+		//Custom SQL
+
+		String sql;
+		boolean callable = false;
+		ExecuteUpdateResultCheckStyle checkStyle = null;
+		sql = persistentClass.getCustomSQLInsert();
+		callable = sql != null && persistentClass.isCustomInsertCallable();
+		checkStyle = sql == null
+				? ExecuteUpdateResultCheckStyle.COUNT
+	            : persistentClass.getCustomSQLInsertCheckStyle() == null
+						? ExecuteUpdateResultCheckStyle.determineDefault( sql, callable )
+	                    : persistentClass.getCustomSQLInsertCheckStyle();
+		customSQLInsert = new String[] { sql };
+		insertCallable = new boolean[] { callable };
+		insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };
+
+		sql = persistentClass.getCustomSQLUpdate();
+		callable = sql != null && persistentClass.isCustomUpdateCallable();
+		checkStyle = sql == null
+				? ExecuteUpdateResultCheckStyle.COUNT
+	            : persistentClass.getCustomSQLUpdateCheckStyle() == null
+						? ExecuteUpdateResultCheckStyle.determineDefault( sql, callable )
+	                    : persistentClass.getCustomSQLUpdateCheckStyle();
+		customSQLUpdate = new String[] { sql };
+		updateCallable = new boolean[] { callable };
+		updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };
+
+		sql = persistentClass.getCustomSQLDelete();
+		callable = sql != null && persistentClass.isCustomDeleteCallable();
+		checkStyle = sql == null
+				? ExecuteUpdateResultCheckStyle.COUNT
+	            : persistentClass.getCustomSQLDeleteCheckStyle() == null
+						? ExecuteUpdateResultCheckStyle.determineDefault( sql, callable )
+	                    : persistentClass.getCustomSQLDeleteCheckStyle();
+		customSQLDelete = new String[] { sql };
+		deleteCallable = new boolean[] { callable };
+		deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };
+
+		discriminatorSQLValue = String.valueOf( persistentClass.getSubclassId() );
+
+		// PROPERTIES
+
+		int subclassSpan = persistentClass.getSubclassSpan() + 1;
+		subclassClosure = new String[subclassSpan];
+		subclassClosure[0] = getEntityName();
+
+		// SUBCLASSES
+		subclassByDiscriminatorValue.put( 
+				new Integer( persistentClass.getSubclassId() ), 
+				persistentClass.getEntityName() 
+		);
+		if ( persistentClass.isPolymorphic() ) {
+			Iterator iter = persistentClass.getSubclassIterator();
+			int k=1;
+			while ( iter.hasNext() ) {
+				Subclass sc = (Subclass) iter.next();
+				subclassClosure[k++] = sc.getEntityName();
+				subclassByDiscriminatorValue.put( new Integer( sc.getSubclassId() ), sc.getEntityName() );
+			}
+		}
+		
+		//SPACES
+		//TODO: i'm not sure, but perhaps we should exclude
+		//      abstract denormalized tables?
+		
+		int spacesSize = 1 + persistentClass.getSynchronizedTables().size();
+		spaces = new String[spacesSize];
+		spaces[0] = tableName;
+		Iterator iter = persistentClass.getSynchronizedTables().iterator();
+		for ( int i=1; i<spacesSize; i++ ) {
+			spaces[i] = (String) iter.next();
+		}
+		
+		HashSet subclassTables = new HashSet();
+		iter = persistentClass.getSubclassTableClosureIterator();
+		while ( iter.hasNext() ) {
+			Table table = (Table) iter.next();
+			subclassTables.add( table.getQualifiedName(
+					factory.getDialect(), 
+					factory.getSettings().getDefaultCatalogName(), 
+					factory.getSettings().getDefaultSchemaName() 
+			) );
+		}
+		subclassSpaces = ArrayHelper.toStringArray(subclassTables);
+
+		subquery = generateSubquery(persistentClass, mapping);
+
+		if ( isMultiTable() ) {
+			int idColumnSpan = getIdentifierColumnSpan();
+			ArrayList tableNames = new ArrayList();
+			ArrayList keyColumns = new ArrayList();
+			if ( !isAbstract() ) {
+				tableNames.add( tableName );
+				keyColumns.add( getIdentifierColumnNames() );
+			}
+			iter = persistentClass.getSubclassTableClosureIterator();
+			while ( iter.hasNext() ) {
+				Table tab = ( Table ) iter.next();
+				if ( !tab.isAbstractUnionTable() ) {
+					String tableName = tab.getQualifiedName(
+							factory.getDialect(),
+							factory.getSettings().getDefaultCatalogName(),
+							factory.getSettings().getDefaultSchemaName()
+					);
+					tableNames.add( tableName );
+					String[] key = new String[idColumnSpan];
+					Iterator citer = tab.getPrimaryKey().getColumnIterator();
+					for ( int k=0; k<idColumnSpan; k++ ) {
+						key[k] = ( ( Column ) citer.next() ).getQuotedName( factory.getDialect() );
+					}
+					keyColumns.add( key );
+				}
+			}
+
+			constraintOrderedTableNames = ArrayHelper.toStringArray( tableNames );
+			constraintOrderedKeyColumnNames = ArrayHelper.to2DStringArray( keyColumns );
+		}
+		else {
+			constraintOrderedTableNames = new String[] { tableName };
+			constraintOrderedKeyColumnNames = new String[][] { getIdentifierColumnNames() };
+		}
+
+		initLockers();
+
+		initSubclassPropertyAliasesMap(persistentClass);
+		
+		postConstruct(mapping);
+
+	}
+
+	public Serializable[] getQuerySpaces() {
+		return subclassSpaces;
+	}
+	
+	public String getTableName() {
+		return subquery;
+	}
+
+	public Type getDiscriminatorType() {
+		return Hibernate.INTEGER;
+	}
+
+	public String getDiscriminatorSQLValue() {
+		return discriminatorSQLValue;
+	}
+
+	public String[] getSubclassClosure() {
+		return subclassClosure;
+	}
+
+	public String getSubclassForDiscriminatorValue(Object value) {
+		return (String) subclassByDiscriminatorValue.get(value);
+	}
+
+	public Serializable[] getPropertySpaces() {
+		return spaces;
+	}
+
+	protected boolean isDiscriminatorFormula() {
+		return false;
+	}
+
+	/**
+	 * Generate the SQL that selects a row by id
+	 */
+	protected String generateSelectString(LockMode lockMode) {
+		SimpleSelect select = new SimpleSelect( getFactory().getDialect() )
+			.setLockMode(lockMode)
+			.setTableName( getTableName() )
+			.addColumns( getIdentifierColumnNames() )
+			.addColumns( 
+					getSubclassColumnClosure(), 
+					getSubclassColumnAliasClosure(),
+					getSubclassColumnLazyiness()
+			)
+			.addColumns( 
+					getSubclassFormulaClosure(), 
+					getSubclassFormulaAliasClosure(),
+					getSubclassFormulaLazyiness()
+			);
+		//TODO: include the rowids!!!!
+		if ( hasSubclasses() ) {
+			if ( isDiscriminatorFormula() ) {
+				select.addColumn( getDiscriminatorFormula(), getDiscriminatorAlias() );
+			}
+			else {
+				select.addColumn( getDiscriminatorColumnName(), getDiscriminatorAlias() );
+			}
+		}
+		if ( getFactory().getSettings().isCommentsEnabled() ) {
+			select.setComment( "load " + getEntityName() );
+		}
+		return select.addCondition( getIdentifierColumnNames(), "=?" ).toStatementString();
+	}
+
+	protected String getDiscriminatorFormula() {
+		return null;
+	}
+
+	protected String getTableName(int j) {
+		return tableName;
+	}
+
+	protected String[] getKeyColumns(int j) {
+		return getIdentifierColumnNames();
+	}
+	
+	protected boolean isTableCascadeDeleteEnabled(int j) {
+		return false;
+	}
+	
+	protected boolean isPropertyOfTable(int property, int j) {
+		return true;
+	}
+
+	// Execute the SQL:
+
+	public String fromTableFragment(String name) {
+		return getTableName() + ' '  + name;
+	}
+
+	public String filterFragment(String name) {
+		return hasWhere() ?
+			" and " + getSQLWhereString(name) :
+			"";
+	}
+
+	public String getSubclassPropertyTableName(int i) {
+		return getTableName();//ie. the subquery! yuck!
+	}
+
+	protected void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) {
+		select.addColumn( name, getDiscriminatorColumnName(),  getDiscriminatorAlias() );
+	}
+	
+	protected int[] getPropertyTableNumbersInSelect() {
+		return new int[ getPropertySpan() ];
+	}
+
+	protected int getSubclassPropertyTableNumber(int i) {
+		return 0;
+	}
+
+	public int getSubclassPropertyTableNumber(String propertyName) {
+		return 0;
+	}
+
+	public boolean isMultiTable() {
+		// This could also just be true all the time...
+		return isAbstract() || hasSubclasses();
+	}
+
+	public int getTableSpan() {
+		return 1;
+	}
+
+	protected int[] getSubclassColumnTableNumberClosure() {
+		return new int[ getSubclassColumnClosure().length ];
+	}
+
+	protected int[] getSubclassFormulaTableNumberClosure() {
+		return new int[ getSubclassFormulaClosure().length ];
+	}
+
+	protected boolean[] getTableHasColumns() {
+		return new boolean[] { true };
+	}
+
+	protected int[] getPropertyTableNumbers() {
+		return new int[ getPropertySpan() ];
+	}
+
+	protected String generateSubquery(PersistentClass model, Mapping mapping) {
+
+		Dialect dialect = getFactory().getDialect();
+		Settings settings = getFactory().getSettings();
+		
+		if ( !model.hasSubclasses() ) {
+			return model.getTable().getQualifiedName(
+					dialect,
+					settings.getDefaultCatalogName(),
+					settings.getDefaultSchemaName()
+				);
+		}
+
+		HashSet columns = new HashSet();
+		Iterator titer = model.getSubclassTableClosureIterator();
+		while ( titer.hasNext() ) {
+			Table table = (Table) titer.next();
+			if ( !table.isAbstractUnionTable() ) {
+				Iterator citer = table.getColumnIterator();
+				while ( citer.hasNext() ) columns.add( citer.next() );
+			}
+		}
+
+		StringBuffer buf = new StringBuffer()
+			.append("( ");
+
+		Iterator siter = new JoinedIterator(
+			new SingletonIterator(model),
+			model.getSubclassIterator()
+		);
+
+		while ( siter.hasNext() ) {
+			PersistentClass clazz = (PersistentClass) siter.next();
+			Table table = clazz.getTable();
+			if ( !table.isAbstractUnionTable() ) {
+				//TODO: move to .sql package!!
+				buf.append("select ");
+				Iterator citer = columns.iterator();
+				while ( citer.hasNext() ) {
+					Column col = (Column) citer.next();
+					if ( !table.containsColumn(col) ) {
+						int sqlType = col.getSqlTypeCode(mapping);
+						buf.append( dialect.getSelectClauseNullString(sqlType) )
+							.append(" as ");
+					}
+					buf.append( col.getName() );
+					buf.append(", ");
+				}
+				buf.append( clazz.getSubclassId() )
+					.append(" as clazz_");
+				buf.append(" from ")
+					.append( table.getQualifiedName(
+							dialect,
+							settings.getDefaultCatalogName(),
+							settings.getDefaultSchemaName()
+					) );
+				buf.append(" union ");
+				if ( dialect.supportsUnionAll() ) {
+					buf.append("all ");
+				}
+			}
+		}
+		
+		if ( buf.length() > 2 ) {
+			//chop the last union (all)
+			buf.setLength( buf.length() - ( dialect.supportsUnionAll() ? 11 : 7 ) );
+		}
+
+		return buf.append(" )").toString();
+	}
+
+	protected String[] getSubclassTableKeyColumns(int j) {
+		if (j!=0) throw new AssertionFailure("only one table");
+		return getIdentifierColumnNames();
+	}
+
+	public String getSubclassTableName(int j) {
+		if (j!=0) throw new AssertionFailure("only one table");
+		return tableName;
+	}
+
+	public int getSubclassTableSpan() {
+		return 1;
+	}
+
+	protected boolean isClassOrSuperclassTable(int j) {
+		if (j!=0) throw new AssertionFailure("only one table");
+		return true;
+	}
+
+	public String getPropertyTableName(String propertyName) {
+		//TODO: check this....
+		return getTableName();
+	}
+
+	public String[] getConstraintOrderedTableNameClosure() {
+			return constraintOrderedTableNames;
+	}
+
+	public String[][] getContraintOrderedTableKeyColumnClosure() {
+		return constraintOrderedKeyColumnNames;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/UniqueKeyLoadable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/UniqueKeyLoadable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/UniqueKeyLoadable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: UniqueKeyLoadable.java 5732 2005-02-14 15:53:24Z oneovthafew $
+package org.hibernate.persister.entity;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * @author Gavin King
+ */
+public interface UniqueKeyLoadable extends Loadable {
+	/**
+	 * Load an instance of the persistent class, by a unique key other
+	 * than the primary key.
+	 */
+	public Object loadByUniqueKey(String propertyName, Object uniqueKey, SessionImplementor session) 
+	throws HibernateException;
+	/**
+	 * Get the property number of the unique key property
+	 */
+	public int getPropertyIndex(String propertyName);
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package abstracts persistence mechanisms for
+	entities, and defines the Hibernate runtime
+	metamodel.
+</p>
+<p>
+    Strategies for persisting entities implement the
+    <tt>EntityPersister</tt> interface. Optionally, 
+    they may implement certain additional interfaces
+    that define contracts with various loaders.
+    Concrete implementations in this package define
+    the built-in inheritance mapping strategies.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/entity/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/persister/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/persister/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	A persister defines a mapping strategy for a collection
+	or entity.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/persister/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/DDLFormatter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/DDLFormatter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/DDLFormatter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,126 @@
+//$Id: DDLFormatter.java 7664 2005-07-27 23:29:37Z oneovthafew $
+package org.hibernate.pretty;
+
+import java.util.StringTokenizer;
+
+public class DDLFormatter {
+	
+	private String sql;
+	
+	public DDLFormatter(String sql) {
+		this.sql = sql;
+	}
+
+	/**
+	 * Format an SQL statement using simple rules:
+	 *  a) Insert newline after each comma;
+	 *  b) Indent three spaces after each inserted newline;
+	 * If the statement contains single/double quotes return unchanged,
+	 * it is too complex and could be broken by simple formatting.
+	 */
+	public String format() {
+		if ( sql.toLowerCase().startsWith("create table") ) {
+			return formatCreateTable();
+		}
+		else if ( sql.toLowerCase().startsWith("alter table") ) {
+			return formatAlterTable();
+		}
+		else if ( sql.toLowerCase().startsWith("comment on") ) {
+			return formatCommentOn();
+		}
+		else {
+			return "\n    " + sql;
+		}
+	}
+
+	private String formatCommentOn() {
+		StringBuffer result = new StringBuffer(60).append("\n    ");
+		StringTokenizer tokens = new StringTokenizer( sql, " '[]\"", true );
+	
+		boolean quoted = false;
+		while ( tokens.hasMoreTokens() ) {
+			String token = tokens.nextToken();
+			result.append(token);
+			if ( isQuote(token) ) {
+				quoted = !quoted;
+			}
+			else if (!quoted) {
+				if ( "is".equals(token) ) {
+					result.append("\n       ");
+				}
+			}
+		}
+		
+		return result.toString();
+	}
+
+	private String formatAlterTable() {
+		StringBuffer result = new StringBuffer(60).append("\n    ");
+		StringTokenizer tokens = new StringTokenizer( sql, " (,)'[]\"", true );
+	
+		boolean quoted = false;
+		while ( tokens.hasMoreTokens() ) {
+			String token = tokens.nextToken();
+			if ( isQuote(token) ) {
+				quoted = !quoted;
+			}
+			else if (!quoted) {
+				if ( isBreak(token) ) {
+					result.append("\n        ");
+				}
+			}
+			result.append(token);
+		}
+		
+		return result.toString();
+	}
+
+	private String formatCreateTable() {
+		StringBuffer result = new StringBuffer(60).append("\n    ");
+		StringTokenizer tokens = new StringTokenizer( sql, "(,)'[]\"", true );
+	
+		int depth = 0;
+		boolean quoted = false;
+		while ( tokens.hasMoreTokens() ) {
+			String token = tokens.nextToken();
+			if ( isQuote(token) ) {
+				quoted = !quoted;
+				result.append(token);
+			}
+			else if (quoted) {
+				result.append(token);
+			}
+			else {
+				if ( ")".equals(token) ) {
+					depth--;
+					if (depth==0) result.append("\n    ");
+				}
+				result.append(token);
+				if ( ",".equals(token) && depth==1 ) result.append("\n       ");
+				if ( "(".equals(token) ) {
+					depth++;
+					if (depth==1) result.append("\n        ");
+				}
+			}
+		}
+		
+		return result.toString();
+	}
+
+	private static boolean isBreak(String token) {
+		return "drop".equals(token) ||
+			"add".equals(token) || 
+			"references".equals(token) || 
+			"foreign".equals(token) ||
+			"on".equals(token);
+	}
+
+	private static boolean isQuote(String tok) {
+		return "\"".equals(tok) || 
+				"`".equals(tok) || 
+				"]".equals(tok) || 
+				"[".equals(tok) ||
+				"'".equals(tok);
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/DDLFormatter.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/Formatter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/Formatter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/Formatter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,370 @@
+//$Id: Formatter.java 9961 2006-05-30 13:17:45Z max.andersen at jboss.com $
+package org.hibernate.pretty;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.hibernate.util.StringHelper;
+
+public class Formatter {
+	
+	private static final Set BEGIN_CLAUSES = new HashSet();
+	private static final Set END_CLAUSES = new HashSet();
+	private static final Set LOGICAL = new HashSet();
+	private static final Set QUANTIFIERS = new HashSet();
+	private static final Set DML = new HashSet();
+	private static final Set MISC = new HashSet();
+	static {
+		
+		BEGIN_CLAUSES.add("left");
+		BEGIN_CLAUSES.add("right");
+		BEGIN_CLAUSES.add("inner");
+		BEGIN_CLAUSES.add("outer");
+		BEGIN_CLAUSES.add("group");
+		BEGIN_CLAUSES.add("order");
+
+		END_CLAUSES.add("where");
+		END_CLAUSES.add("set");
+		END_CLAUSES.add("having");
+		END_CLAUSES.add("join");
+		END_CLAUSES.add("from");
+		END_CLAUSES.add("by");
+		END_CLAUSES.add("join");
+		END_CLAUSES.add("into");
+		END_CLAUSES.add("union");
+		
+		LOGICAL.add("and");
+		LOGICAL.add("or");
+		LOGICAL.add("when");
+		LOGICAL.add("else");
+		LOGICAL.add("end");
+		
+		QUANTIFIERS.add("in");
+		QUANTIFIERS.add("all");
+		QUANTIFIERS.add("exists");
+		QUANTIFIERS.add("some");
+		QUANTIFIERS.add("any");
+		
+		DML.add("insert");
+		DML.add("update");
+		DML.add("delete");
+		
+		MISC.add("select");
+		MISC.add("on");
+		//MISC.add("values");
+
+	}
+	
+	String indentString = "    ";
+	String initial = "\n    ";
+
+	boolean beginLine = true;
+	boolean afterBeginBeforeEnd = false;
+	boolean afterByOrSetOrFromOrSelect = false;
+	boolean afterValues = false;
+	boolean afterOn = false;
+	boolean afterBetween = false;
+	boolean afterInsert = false;
+	int inFunction = 0;
+	int parensSinceSelect = 0;
+	private LinkedList parenCounts = new LinkedList();
+	private LinkedList afterByOrFromOrSelects = new LinkedList();
+
+	int indent = 1;
+
+	StringBuffer result = new StringBuffer();
+	StringTokenizer tokens;
+	String lastToken;
+	String token;
+	String lcToken;
+	
+	public Formatter(String sql) {
+		tokens = new StringTokenizer(
+				sql, 
+				"()+*/-=<>'`\"[]," + StringHelper.WHITESPACE, 
+				true
+			);
+	}
+
+	public Formatter setInitialString(String initial) {
+		this.initial = initial;
+		return this;
+	}
+	
+	public Formatter setIndentString(String indent) {
+		this.indentString = indent;
+		return this;
+	}
+	
+	public String format() {
+		
+		result.append(initial);
+		
+		while ( tokens.hasMoreTokens() ) {
+			token = tokens.nextToken();
+			lcToken = token.toLowerCase();
+			
+			if ( "'".equals(token) ) {
+				String t;
+				do {
+					t = tokens.nextToken();
+					token += t;
+				} 
+				while ( !"'".equals(t) && tokens.hasMoreTokens() ); // cannot handle single quotes
+			}		
+			else if ( "\"".equals(token) ) {
+				String t;
+				do {
+					t = tokens.nextToken();
+					token += t;
+				} 
+				while ( !"\"".equals(t) );
+			}
+			
+			if ( afterByOrSetOrFromOrSelect && ",".equals(token) ) {
+				commaAfterByOrFromOrSelect();
+			}
+			else if ( afterOn && ",".equals(token) ) {
+				commaAfterOn();
+			}
+			
+			else if ( "(".equals(token) ) {
+				openParen();
+			}
+			else if ( ")".equals(token) ) {
+				closeParen();
+			}
+
+			else if ( BEGIN_CLAUSES.contains(lcToken) ) {
+				beginNewClause();
+			}
+
+			else if ( END_CLAUSES.contains(lcToken) ) {
+				endNewClause(); 
+			}
+			
+			else if ( "select".equals(lcToken) ) {
+				select();
+			}
+			
+			else if ( DML.contains(lcToken) ) {
+				updateOrInsertOrDelete();
+			}
+			
+			else if ( "values".equals(lcToken) ) {
+				values();
+			}
+			
+			else if ( "on".equals(lcToken) ) {
+				on();
+			}
+			
+			else if ( afterBetween && lcToken.equals("and") ) {
+				misc();
+				afterBetween = false;
+			}
+			
+			else if ( LOGICAL.contains(lcToken) ) {
+				logical();
+			}
+			
+			else if ( isWhitespace(token) ) {
+				white();
+			}
+			
+			else {
+				misc();
+			}
+			
+			if ( !isWhitespace( token ) ) lastToken = lcToken;
+			
+		}
+		return result.toString();
+	}
+
+	private void commaAfterOn() {
+		out();
+		indent--;
+		newline();
+		afterOn = false;
+		afterByOrSetOrFromOrSelect = true;
+	}
+
+	private void commaAfterByOrFromOrSelect() {
+		out();
+		newline();
+	}
+
+	private void logical() {
+		if ( "end".equals(lcToken) ) indent--;
+		newline();
+		out();
+		beginLine = false;
+	}
+
+	private void on() {
+		indent++;
+		afterOn = true;
+		newline();
+		out();
+		beginLine = false;
+	}
+
+	private void misc() {
+		out();
+		if ( "between".equals(lcToken) ) {
+			afterBetween = true;
+		}
+		if (afterInsert) {
+			newline();
+			afterInsert = false;
+		}
+		else {
+			beginLine = false;
+			if ( "case".equals(lcToken) ) {
+				indent++;
+			}
+		}
+	}
+
+	private void white() {
+		if ( !beginLine ) {
+			result.append(" ");
+		}
+	}
+	
+	private void updateOrInsertOrDelete() {
+		out();
+		indent++;
+		beginLine = false;
+		if ( "update".equals(lcToken) ) newline();
+		if ( "insert".equals(lcToken) ) afterInsert = true;
+	}
+
+	private void select() {
+		out();
+		indent++;
+		newline();
+		parenCounts.addLast( new Integer(parensSinceSelect) );
+		afterByOrFromOrSelects.addLast( new Boolean(afterByOrSetOrFromOrSelect) );
+		parensSinceSelect = 0;
+		afterByOrSetOrFromOrSelect = true;
+	}
+
+	private void out() {
+		result.append(token);
+	}
+
+	private void endNewClause() {
+		if (!afterBeginBeforeEnd) {
+			indent--;
+			if (afterOn) {
+				indent--;
+				afterOn=false;
+			}
+			newline();
+		}
+		out();
+		if ( !"union".equals(lcToken) ) indent++;
+		newline();
+		afterBeginBeforeEnd = false;
+		afterByOrSetOrFromOrSelect = "by".equals(lcToken) 
+				|| "set".equals(lcToken)
+				|| "from".equals(lcToken);
+	}
+
+	private void beginNewClause() {
+		if (!afterBeginBeforeEnd) {
+			if (afterOn) {
+				indent--;
+				afterOn=false;
+			}
+			indent--;
+			newline();
+		}
+		out();
+		beginLine = false;
+		afterBeginBeforeEnd = true;
+	}
+
+	private void values() {
+		indent--;
+		newline();
+		out();
+		indent++;
+		newline();
+		afterValues = true;
+	}
+
+	private void closeParen() {
+		parensSinceSelect--;
+		if (parensSinceSelect<0) {
+			indent--;
+			parensSinceSelect = ( (Integer) parenCounts.removeLast() ).intValue();
+			afterByOrSetOrFromOrSelect = ( (Boolean) afterByOrFromOrSelects.removeLast() ).booleanValue();
+		}
+		if ( inFunction>0 ) {
+			inFunction--;
+			out();
+		}
+		else {
+			if (!afterByOrSetOrFromOrSelect) {
+				indent--;
+				newline();
+			}
+			out();
+		}
+		beginLine = false;
+	}
+
+	private void openParen() {
+		if ( isFunctionName( lastToken ) || inFunction>0 ) {
+			inFunction++;
+		}
+		beginLine = false;
+		if ( inFunction>0 ) {
+			out();
+		}
+		else {
+			out();
+			if (!afterByOrSetOrFromOrSelect) {
+				indent++;
+				newline();
+				beginLine = true;
+			}
+		}
+		parensSinceSelect++;
+	}
+
+	private static boolean isFunctionName(String tok) {
+		final char begin = tok.charAt(0);
+		final boolean isIdentifier = Character.isJavaIdentifierStart( begin ) || '"'==begin;
+		return isIdentifier && 
+				!LOGICAL.contains(tok) && 
+				!END_CLAUSES.contains(tok) &&
+				!QUANTIFIERS.contains(tok) &&
+				!DML.contains(tok) &&
+				!MISC.contains(tok);
+	}
+
+	private static boolean isWhitespace(String token) {
+		return StringHelper.WHITESPACE.indexOf(token)>=0;
+	}
+	
+	private void newline() {
+		result.append("\n");
+		for ( int i=0; i<indent; i++ ) {
+			result.append(indentString);
+		}
+		beginLine = true;
+	}
+
+	public static void main(String[] args) {
+		if ( args.length>0 ) System.out.println( 
+			new Formatter( StringHelper.join(" ", args) ).format()
+		);
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/Formatter.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/MessageHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/MessageHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/MessageHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,321 @@
+//$Id: MessageHelper.java 9561 2006-03-07 14:17:16Z steve.ebersole at jboss.com $
+package org.hibernate.pretty;
+
+import java.io.Serializable;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.type.Type;
+
+/**
+ * MessageHelper methods for rendering log messages relating to managed
+ * entities and collections typically used in log statements and exception
+ * messages.
+ *
+ * @author Max Andersen, Gavin King
+ */
+public final class MessageHelper {
+
+	private MessageHelper() {
+	}
+
+
+	// entities ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Generate an info message string relating to a particular entity,
+	 * based on the given entityName and id.
+	 *
+	 * @param entityName The defined entity name.
+	 * @param id The entity id value.
+	 * @return An info string, in the form [FooBar#1].
+	 */
+	public static String infoString(String entityName, Serializable id) {
+		StringBuffer s = new StringBuffer();
+		s.append( '[' );
+		if( entityName == null ) {
+			s.append( "<null entity name>" );
+		}
+		else {
+			s.append( entityName );
+		}
+		s.append( '#' );
+
+		if ( id == null ) {
+			s.append( "<null>" );
+		}
+		else {
+			s.append( id );
+		}
+		s.append( ']' );
+
+		return s.toString();
+	}
+
+	/**
+	 * Generate an info message string relating to a particular entity.
+	 *
+	 * @param persister The persister for the entity
+	 * @param id The entity id value
+	 * @param factory The session factory
+	 * @return An info string, in the form [FooBar#1]
+	 */
+	public static String infoString(
+			EntityPersister persister, 
+			Object id, 
+			SessionFactoryImplementor factory) {
+		StringBuffer s = new StringBuffer();
+		s.append( '[' );
+		Type idType;
+		if( persister == null ) {
+			s.append( "<null EntityPersister>" );
+			idType = null;
+		}
+		else {
+			s.append( persister.getEntityName() );
+			idType = persister.getIdentifierType();
+		}
+		s.append( '#' );
+
+		if ( id == null ) {
+			s.append( "<null>" );
+		}
+		else {
+			if ( idType == null ) {
+				s.append( id );
+			}
+			else {
+				s.append( idType.toLoggableString( id, factory ) );
+			}
+		}
+		s.append( ']' );
+
+		return s.toString();
+
+	}
+
+	/**
+	 * Generate an info message string relating to a particular entity,.
+	 *
+	 * @param persister The persister for the entity
+	 * @param id The entity id value
+	 * @param identifierType The entity identifier type mapping
+	 * @param factory The session factory
+	 * @return An info string, in the form [FooBar#1]
+	 */
+	public static String infoString(
+			EntityPersister persister, 
+			Object id, 
+			Type identifierType,
+			SessionFactoryImplementor factory) {
+		StringBuffer s = new StringBuffer();
+		s.append( '[' );
+		if( persister == null ) {
+			s.append( "<null EntityPersister>" );
+		}
+		else {
+			s.append( persister.getEntityName() );
+		}
+		s.append( '#' );
+
+		if ( id == null ) {
+			s.append( "<null>" );
+		}
+		else {
+			s.append( identifierType.toLoggableString( id, factory ) );
+		}
+		s.append( ']' );
+
+		return s.toString();
+	}
+
+	/**
+	 * Generate an info message string relating to a series of entities.
+	 *
+	 * @param persister The persister for the entities
+	 * @param ids The entity id values
+	 * @param factory The session factory
+	 * @return An info string, in the form [FooBar#<1,2,3>]
+	 */
+	public static String infoString(
+			EntityPersister persister, 
+			Serializable[] ids, 
+			SessionFactoryImplementor factory) {
+		StringBuffer s = new StringBuffer();
+		s.append( '[' );
+		if( persister == null ) {
+			s.append( "<null EntityPersister>" );
+		}
+		else {
+			s.append( persister.getEntityName() );
+			s.append( "#<" );
+			for ( int i=0; i<ids.length; i++ ) {
+				s.append( persister.getIdentifierType().toLoggableString( ids[i], factory ) );
+				if ( i < ids.length-1 ) {
+					s.append( ", " );
+				}
+			}
+			s.append( '>' );
+		}
+		s.append( ']' );
+
+		return s.toString();
+
+	}
+
+	/**
+	 * Generate an info message string relating to given entity persister.
+	 *
+	 * @param persister The persister.
+	 * @return An info string, in the form [FooBar]
+	 */
+	public static String infoString(EntityPersister persister) {
+		StringBuffer s = new StringBuffer();
+		s.append( '[' );
+		if ( persister == null ) {
+			s.append( "<null EntityPersister>" );
+		}
+		else {
+			s.append( persister.getEntityName() );
+		}
+		s.append( ']' );
+		return s.toString();
+	}
+
+	/**
+	 * Generate an info message string relating to a given property value
+	 * for an entity.
+	 *
+	 * @param entityName The entity name
+	 * @param propertyName The name of the property
+	 * @param key The property value.
+	 * @return An info string, in the form [Foo.bars#1]
+	 */
+	public static String infoString(String entityName, String propertyName, Object key) {
+		StringBuffer s = new StringBuffer()
+				.append( '[' )
+				.append( entityName )
+				.append( '.' )
+				.append( propertyName )
+				.append( '#' );
+
+		if ( key == null ) {
+			s.append( "<null>" );
+		}
+		else {
+			s.append( key );
+		}
+		s.append( ']' );
+		return s.toString();
+	}
+
+
+	// collections ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+	/**
+	 * Generate an info message string relating to a series of managed
+	 * collections.
+	 *
+	 * @param persister The persister for the collections
+	 * @param ids The id values of the owners
+	 * @param factory The session factory
+	 * @return An info string, in the form [Foo.bars#<1,2,3>]
+	 */
+	public static String collectionInfoString(
+			CollectionPersister persister, 
+			Serializable[] ids, 
+			SessionFactoryImplementor factory) {
+		StringBuffer s = new StringBuffer();
+		s.append( '[' );
+		if ( persister == null ) {
+			s.append( "<unreferenced>" );
+		}
+		else {
+			s.append( persister.getRole() );
+			s.append( "#<" );
+			for ( int i = 0; i < ids.length; i++ ) {
+				// Need to use the identifier type of the collection owner
+				// since the incoming is value is actually the owner's id.
+				// Using the collection's key type causes problems with
+				// property-ref keys...
+				s.append( persister.getOwnerEntityPersister().getIdentifierType().toLoggableString( ids[i], factory ) );
+				if ( i < ids.length-1 ) {
+					s.append( ", " );
+				}
+			}
+			s.append( '>' );
+		}
+		s.append( ']' );
+		return s.toString();
+	}
+
+	/**
+	 * Generate an info message string relating to a particular managed
+	 * collection.
+	 *
+	 * @param persister The persister for the collection
+	 * @param id The id value of the owner
+	 * @param factory The session factory
+	 * @return An info string, in the form [Foo.bars#1]
+	 */
+	public static String collectionInfoString(
+			CollectionPersister persister, 
+			Serializable id, 
+			SessionFactoryImplementor factory) {
+		StringBuffer s = new StringBuffer();
+		s.append( '[' );
+		if ( persister == null ) {
+			s.append( "<unreferenced>" );
+		}
+		else {
+			s.append( persister.getRole() );
+			s.append( '#' );
+
+			if ( id == null ) {
+				s.append( "<null>" );
+			}
+			else {
+				// Need to use the identifier type of the collection owner
+				// since the incoming is value is actually the owner's id.
+				// Using the collection's key type causes problems with
+				// property-ref keys...
+				s.append( persister.getOwnerEntityPersister().getIdentifierType().toLoggableString( id, factory ) );
+			}
+		}
+		s.append( ']' );
+
+		return s.toString();
+	}
+
+	/**
+	 * Generate an info message string relating to a particular managed
+	 * collection.
+	 *
+	 * @param role The role-name of the collection
+	 * @param id The id value of the owner
+	 * @return An info string, in the form [Foo.bars#1]
+	 */
+	public static String collectionInfoString(String role, Serializable id) {
+		StringBuffer s = new StringBuffer();
+		s.append( '[' );
+		if( role == null ) {
+			s.append( "<unreferenced>" );
+		}
+		else {
+			s.append( role );
+			s.append( '#' );
+
+			if ( id == null ) {
+				s.append( "<null>" );
+			}
+			else {
+				s.append( id );
+			}
+		}
+		s.append( ']' );
+		return s.toString();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/Printer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/Printer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/Printer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,98 @@
+//$Id: Printer.java 5785 2005-02-19 12:58:24Z oneovthafew $
+package org.hibernate.pretty;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.EntityMode;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.TypedValue;
+import org.hibernate.intercept.LazyPropertyInitializer;
+import org.hibernate.metadata.ClassMetadata;
+import org.hibernate.type.Type;
+
+/**
+ * Renders entities to a nicely readable string.
+ * @author Gavin King
+ */
+public final class Printer {
+
+	private SessionFactoryImplementor factory;
+	private static final Log log = LogFactory.getLog(Printer.class);
+
+	/**
+	 * @param entity an actual entity object, not a proxy!
+	 */
+	public String toString(Object entity, EntityMode entityMode) throws HibernateException {
+
+		// todo : this call will not work for anything other than pojos!
+		ClassMetadata cm = factory.getClassMetadata( entity.getClass() );
+
+		if ( cm==null ) return entity.getClass().getName();
+
+		Map result = new HashMap();
+
+		if ( cm.hasIdentifierProperty() ) {
+			result.put(
+				cm.getIdentifierPropertyName(),
+				cm.getIdentifierType().toLoggableString( cm.getIdentifier( entity, entityMode ), factory )
+			);
+		}
+
+		Type[] types = cm.getPropertyTypes();
+		String[] names = cm.getPropertyNames();
+		Object[] values = cm.getPropertyValues( entity, entityMode );
+		for ( int i=0; i<types.length; i++ ) {
+			if ( !names[i].startsWith("_") ) {
+				String strValue = values[i]==LazyPropertyInitializer.UNFETCHED_PROPERTY ?
+					values[i].toString() :
+					types[i].toLoggableString( values[i], factory );
+				result.put( names[i], strValue );
+			}
+		}
+		return cm.getEntityName() + result.toString();
+	}
+
+	public String toString(Type[] types, Object[] values) throws HibernateException {
+		List list = new ArrayList( types.length * 5 );
+		for ( int i=0; i<types.length; i++ ) {
+			if ( types[i]!=null ) list.add( types[i].toLoggableString( values[i], factory ) );
+		}
+		return list.toString();
+	}
+
+	public String toString(Map namedTypedValues) throws HibernateException {
+		Map result = new HashMap();
+		Iterator iter = namedTypedValues.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			TypedValue tv = (TypedValue) me.getValue();
+			result.put( me.getKey(), tv.getType().toLoggableString( tv.getValue(), factory ) );
+		}
+		return result.toString();
+	}
+
+	public void toString(Iterator iter, EntityMode entityMode) throws HibernateException {
+		if ( !log.isDebugEnabled() || !iter.hasNext() ) return;
+		log.debug("listing entities:");
+		int i=0;
+		while ( iter.hasNext() ) {
+			if (i++>20) {
+				log.debug("more......");
+				break;
+			}
+			log.debug( toString( iter.next(), entityMode ) );
+		}
+	}
+
+	public Printer(SessionFactoryImplementor factory) {
+		this.factory = factory;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	Classes for pretty printing things for exception
+	and log messages.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/pretty/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/property/BackrefPropertyAccessor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/property/BackrefPropertyAccessor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/property/BackrefPropertyAccessor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,105 @@
+//$Id: BackrefPropertyAccessor.java 7516 2005-07-16 22:20:48Z oneovthafew $
+package org.hibernate.property;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Represents a "back-reference" to the id of a collection owner.
+ *
+ * @author Gavin King
+ */
+public class BackrefPropertyAccessor implements PropertyAccessor {
+
+	private final String propertyName;
+	private final String entityName;
+
+	/**
+	 * A placeholder for a property value, indicating that
+	 * we don't know the value of the back reference
+	 */
+	public static final Serializable UNKNOWN = new Serializable() {
+		public String toString() { return "<unknown>"; }
+		public Object readResolve() {
+			return UNKNOWN;
+		}
+	};
+	
+	/**
+	 * Constructs a new instance of BackrefPropertyAccessor.
+	 *
+	 * @param collectionRole The collection role which this back ref references.
+	 */
+	public BackrefPropertyAccessor(String collectionRole, String entityName) {
+		this.propertyName = collectionRole.substring( entityName.length() + 1 );
+		this.entityName = entityName;
+	}
+
+	public Setter getSetter(Class theClass, String propertyName) {
+		return new BackrefSetter();
+	}
+
+	public Getter getGetter(Class theClass, String propertyName) {
+		return new BackrefGetter();
+	}
+
+
+	/**
+	 * The Setter implementation for id backrefs.
+	 */
+	public static final class BackrefSetter implements Setter {
+
+		public Method getMethod() {
+			return null;
+		}
+
+		public String getMethodName() {
+			return null;
+		}
+
+		public void set(Object target, Object value, SessionFactoryImplementor factory) {
+			// this page intentionally left blank :)
+		}
+
+	}
+
+
+	/**
+	 * The Getter implementation for id backrefs.
+	 */
+	public class BackrefGetter implements Getter {
+		
+		public Object getForInsert(Object target, Map mergeMap, SessionImplementor session)
+		throws HibernateException {
+			if (session==null) {
+				return UNKNOWN;
+			}
+			else {
+				return session.getPersistenceContext()
+						.getOwnerId( entityName, propertyName, target, mergeMap );
+			}
+		}
+
+		public Object get(Object target)  {
+			return UNKNOWN;
+		}
+
+		public Method getMethod() {
+			return null;
+		}
+
+		public String getMethodName() {
+			return null;
+		}
+
+		public Class getReturnType() {
+			return Object.class;
+		}
+	}
+}
+


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/property/BackrefPropertyAccessor.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/property/BasicPropertyAccessor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/property/BasicPropertyAccessor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/property/BasicPropertyAccessor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,348 @@
+//$Id: BasicPropertyAccessor.java 7516 2005-07-16 22:20:48Z oneovthafew $
+package org.hibernate.property;
+
+import java.beans.Introspector;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.PropertyAccessException;
+import org.hibernate.PropertyNotFoundException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * Accesses property values via a get/set pair, which may be nonpublic.
+ * The default (and recommended strategy).
+ * @author Gavin King
+ */
+public class BasicPropertyAccessor implements PropertyAccessor {
+
+	private static final Log log = LogFactory.getLog(BasicPropertyAccessor.class);
+
+	public static final class BasicSetter implements Setter {
+		private Class clazz;
+		private final transient Method method;
+		private final String propertyName;
+
+		private BasicSetter(Class clazz, Method method, String propertyName) {
+			this.clazz=clazz;
+			this.method=method;
+			this.propertyName=propertyName;
+		}
+
+		public void set(Object target, Object value, SessionFactoryImplementor factory) 
+		throws HibernateException {
+			try {
+				method.invoke( target, new Object[] { value } );
+			}
+			catch (NullPointerException npe) {
+				if ( value==null && method.getParameterTypes()[0].isPrimitive() ) {
+					throw new PropertyAccessException(
+							npe, 
+							"Null value was assigned to a property of primitive type", 
+							true, 
+							clazz, 
+							propertyName
+						);
+				}
+				else {
+					throw new PropertyAccessException(
+							npe, 
+							"NullPointerException occurred while calling", 
+							true, 
+							clazz, 
+							propertyName
+						);
+				}
+			}
+			catch (InvocationTargetException ite) {
+				throw new PropertyAccessException(
+						ite, 
+						"Exception occurred inside", 
+						true, 
+						clazz, 
+						propertyName
+					);
+			}
+			catch (IllegalAccessException iae) {
+				throw new PropertyAccessException(
+						iae, 
+						"IllegalAccessException occurred while calling", 
+						true, 
+						clazz, 
+						propertyName
+					);
+				//cannot occur
+			}
+			catch (IllegalArgumentException iae) {
+				if ( value==null && method.getParameterTypes()[0].isPrimitive() ) {
+					throw new PropertyAccessException(
+							iae, 
+							"Null value was assigned to a property of primitive type", 
+							true, 
+							clazz, 
+							propertyName
+						);
+				}
+				else {
+					log.error(
+							"IllegalArgumentException in class: " + clazz.getName() +
+							", setter method of property: " + propertyName
+						);
+					log.error(
+							"expected type: " + 
+							method.getParameterTypes()[0].getName() +
+							", actual value: " + 
+							( value==null ? null : value.getClass().getName() )
+						);
+					throw new PropertyAccessException(
+							iae, 
+							"IllegalArgumentException occurred while calling", 
+							true, 
+							clazz, 
+							propertyName
+						);
+				}
+			}
+		}
+
+		public Method getMethod() {
+			return method;
+		}
+
+		public String getMethodName() {
+			return method.getName();
+		}
+
+		Object readResolve() {
+			return createSetter(clazz, propertyName);
+		}
+
+		public String toString() {
+			return "BasicSetter(" + clazz.getName() + '.' + propertyName + ')';
+		}
+	}
+
+	public static final class BasicGetter implements Getter {
+		private Class clazz;
+		private final transient Method method;
+		private final String propertyName;
+
+		private BasicGetter(Class clazz, Method method, String propertyName) {
+			this.clazz=clazz;
+			this.method=method;
+			this.propertyName=propertyName;
+		}
+
+		public Object get(Object target) throws HibernateException {
+			try {
+				return method.invoke(target, null);
+			}
+			catch (InvocationTargetException ite) {
+				throw new PropertyAccessException(
+						ite, 
+						"Exception occurred inside", 
+						false, 
+						clazz, 
+						propertyName
+					);
+			}
+			catch (IllegalAccessException iae) {
+				throw new PropertyAccessException(
+						iae, 
+						"IllegalAccessException occurred while calling", 
+						false, 
+						clazz, 
+						propertyName
+					);
+				//cannot occur
+			}
+			catch (IllegalArgumentException iae) {
+				log.error(
+						"IllegalArgumentException in class: " + clazz.getName() +
+						", getter method of property: " + propertyName
+					);
+				throw new PropertyAccessException(
+						iae, 
+						"IllegalArgumentException occurred calling", 
+						false, 
+						clazz, 
+						propertyName
+					);
+			}
+		}
+
+		public Object getForInsert(Object target, Map mergeMap, SessionImplementor session) {
+			return get( target );
+		}
+
+		public Class getReturnType() {
+			return method.getReturnType();
+		}
+
+		public Method getMethod() {
+			return method;
+		}
+
+		public String getMethodName() {
+			return method.getName();
+		}
+
+		public String toString() {
+			return "BasicGetter(" + clazz.getName() + '.' + propertyName + ')';
+		}
+		
+		Object readResolve() {
+			return createGetter(clazz, propertyName);
+		}
+	}
+
+
+	public Setter getSetter(Class theClass, String propertyName) 
+	throws PropertyNotFoundException {
+		return createSetter(theClass, propertyName);
+	}
+	
+	private static Setter createSetter(Class theClass, String propertyName) 
+	throws PropertyNotFoundException {
+		BasicSetter result = getSetterOrNull(theClass, propertyName);
+		if (result==null) {
+			throw new PropertyNotFoundException( 
+					"Could not find a setter for property " + 
+					propertyName + 
+					" in class " + 
+					theClass.getName() 
+				);
+		}
+		return result;
+	}
+
+	private static BasicSetter getSetterOrNull(Class theClass, String propertyName) {
+
+		if (theClass==Object.class || theClass==null) return null;
+
+		Method method = setterMethod(theClass, propertyName);
+
+		if (method!=null) {
+			if ( !ReflectHelper.isPublic(theClass, method) ) method.setAccessible(true);
+			return new BasicSetter(theClass, method, propertyName);
+		}
+		else {
+			BasicSetter setter = getSetterOrNull( theClass.getSuperclass(), propertyName );
+			if (setter==null) {
+				Class[] interfaces = theClass.getInterfaces();
+				for ( int i=0; setter==null && i<interfaces.length; i++ ) {
+					setter=getSetterOrNull( interfaces[i], propertyName );
+				}
+			}
+			return setter;
+		}
+
+	}
+
+	private static Method setterMethod(Class theClass, String propertyName) {
+
+		BasicGetter getter = getGetterOrNull(theClass, propertyName);
+		Class returnType = (getter==null) ? null : getter.getReturnType();
+
+		Method[] methods = theClass.getDeclaredMethods();
+		Method potentialSetter = null;
+		for (int i=0; i<methods.length; i++) {
+			String methodName = methods[i].getName();
+
+			if ( methods[i].getParameterTypes().length==1 && methodName.startsWith("set") ) {
+				String testStdMethod = Introspector.decapitalize( methodName.substring(3) );
+				String testOldMethod = methodName.substring(3);
+				if ( testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName) ) {
+					potentialSetter = methods[i];
+					if ( returnType==null || methods[i].getParameterTypes()[0].equals(returnType) ) {
+						return potentialSetter;
+					}
+				}
+			}
+		}
+		return potentialSetter;
+	}
+
+	public Getter getGetter(Class theClass, String propertyName) 
+	throws PropertyNotFoundException {
+		return createGetter(theClass, propertyName);
+	}
+	
+	public static Getter createGetter(Class theClass, String propertyName) 
+	throws PropertyNotFoundException {
+		BasicGetter result = getGetterOrNull(theClass, propertyName);
+		if (result==null) {
+			throw new PropertyNotFoundException( 
+					"Could not find a getter for " + 
+					propertyName + 
+					" in class " + 
+					theClass.getName() 
+			);
+		}
+		return result;
+
+	}
+
+	private static BasicGetter getGetterOrNull(Class theClass, String propertyName) {
+
+		if (theClass==Object.class || theClass==null) return null;
+
+		Method method = getterMethod(theClass, propertyName);
+
+		if (method!=null) {
+			if ( !ReflectHelper.isPublic(theClass, method) ) method.setAccessible(true);
+			return new BasicGetter(theClass, method, propertyName);
+		}
+		else {
+			BasicGetter getter = getGetterOrNull( theClass.getSuperclass(), propertyName );
+			if (getter==null) {
+				Class[] interfaces = theClass.getInterfaces();
+				for ( int i=0; getter==null && i<interfaces.length; i++ ) {
+					getter=getGetterOrNull( interfaces[i], propertyName );
+				}
+			}
+			return getter;
+		}
+	}
+
+	private static Method getterMethod(Class theClass, String propertyName) {
+
+		Method[] methods = theClass.getDeclaredMethods();
+		for (int i=0; i<methods.length; i++) {
+			// only carry on if the method has no parameters
+			if ( methods[i].getParameterTypes().length==0 ) {
+				String methodName = methods[i].getName();
+
+				// try "get"
+				if ( methodName.startsWith("get") ) {
+					String testStdMethod = Introspector.decapitalize( methodName.substring(3) );
+					String testOldMethod = methodName.substring(3);
+					if ( testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName) ) {
+						return methods[i];
+					}
+
+				}
+
+				// if not "get" then try "is"
+				/*boolean isBoolean = methods[i].getReturnType().equals(Boolean.class) ||
+					methods[i].getReturnType().equals(boolean.class);*/
+				if ( methodName.startsWith("is") ) {
+					String testStdMethod = Introspector.decapitalize( methodName.substring(2) );
+					String testOldMethod = methodName.substring(2);
+					if ( testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName) ) {
+						return methods[i];
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/property/ChainedPropertyAccessor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/property/ChainedPropertyAccessor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/property/ChainedPropertyAccessor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+package org.hibernate.property;
+
+import org.hibernate.PropertyNotFoundException;
+
+/**
+ * @author max
+ *
+ */
+public class ChainedPropertyAccessor implements PropertyAccessor {
+
+	final PropertyAccessor[] chain;
+	
+	public ChainedPropertyAccessor(PropertyAccessor[] chain) {
+		this.chain = chain;
+	}
+	
+	public Getter getGetter(Class theClass, String propertyName)
+			throws PropertyNotFoundException {
+		Getter result = null;
+		for (int i = 0; i < chain.length; i++) {
+			PropertyAccessor candidate = chain[i];
+			try {
+				result = candidate.getGetter(theClass, propertyName);
+				return result;
+			} catch (PropertyNotFoundException pnfe) {
+				// ignore
+			}
+		}
+		throw new PropertyNotFoundException("Could not find getter for " + propertyName + " on " + theClass);
+	}
+
+	public Setter getSetter(Class theClass, String propertyName)
+			throws PropertyNotFoundException {
+		Setter result = null;
+		for (int i = 0; i < chain.length; i++) {
+			PropertyAccessor candidate = chain[i];
+			try {
+				result = candidate.getSetter(theClass, propertyName);
+				return result;
+			} catch (PropertyNotFoundException pnfe) {
+				//
+			}
+		}
+		throw new PropertyNotFoundException("Could not find setter for " + propertyName + " on " + theClass);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/property/DirectPropertyAccessor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/property/DirectPropertyAccessor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/property/DirectPropertyAccessor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,145 @@
+//$Id: DirectPropertyAccessor.java 11412 2007-04-17 14:38:51Z max.andersen at jboss.com $
+package org.hibernate.property;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.PropertyAccessException;
+import org.hibernate.PropertyNotFoundException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * Accesses fields directly.
+ * @author Gavin King
+ */
+public class DirectPropertyAccessor implements PropertyAccessor {
+
+	public static final class DirectGetter implements Getter {
+		private final transient Field field;
+		private final Class clazz;
+		private final String name;
+		DirectGetter(Field field, Class clazz, String name) {
+			this.field = field;
+			this.clazz = clazz;
+			this.name = name;
+		}
+		public Object get(Object target) throws HibernateException {
+			try {
+				return field.get(target);
+			}
+			catch (Exception e) {
+				throw new PropertyAccessException(e, "could not get a field value by reflection", false, clazz, name);
+			}
+		}
+
+		public Object getForInsert(Object target, Map mergeMap, SessionImplementor session) {
+			return get( target );
+		}
+
+		public Method getMethod() {
+			return null;
+		}
+		public String getMethodName() {
+			return null;
+		}
+		public Class getReturnType() {
+			return field.getType();
+		}
+
+		Object readResolve() {
+			return new DirectGetter( getField(clazz, name), clazz, name );
+		}
+		
+		public String toString() {
+			return "DirectGetter(" + clazz.getName() + '.' + name + ')';
+		}
+	}
+
+	public static final class DirectSetter implements Setter {
+		private final transient Field field;
+		private final Class clazz;
+		private final String name;
+		DirectSetter(Field field, Class clazz, String name) {
+			this.field = field;
+			this.clazz = clazz;
+			this.name = name;
+		}
+		public Method getMethod() {
+			return null;
+		}
+		public String getMethodName() {
+			return null;
+		}
+		public void set(Object target, Object value, SessionFactoryImplementor factory) throws HibernateException {
+			try {
+				field.set(target, value);
+			}
+			catch (Exception e) {
+				if(value == null && field.getType().isPrimitive()) {
+					throw new PropertyAccessException(
+							e, 
+							"Null value was assigned to a property of primitive type", 
+							true, 
+							clazz, 
+							name
+						);					
+				} else {
+					throw new PropertyAccessException(e, "could not set a field value by reflection", true, clazz, name);
+				}
+			}
+		}
+
+		public String toString() {
+			return "DirectSetter(" + clazz.getName() + '.' + name + ')';
+		}
+		
+		Object readResolve() {
+			return new DirectSetter( getField(clazz, name), clazz, name );
+		}
+	}
+
+	private static Field getField(Class clazz, String name) throws PropertyNotFoundException {
+		if ( clazz==null || clazz==Object.class ) {
+			throw new PropertyNotFoundException("field not found: " + name); 
+		}
+		Field field;
+		try {
+			field = clazz.getDeclaredField(name);
+		}
+		catch (NoSuchFieldException nsfe) {
+			field = getField( clazz, clazz.getSuperclass(), name );
+		}
+		if ( !ReflectHelper.isPublic(clazz, field) ) field.setAccessible(true);
+		return field;
+	}
+
+	private static Field getField(Class root, Class clazz, String name) throws PropertyNotFoundException {
+		if ( clazz==null || clazz==Object.class ) {
+			throw new PropertyNotFoundException("field [" + name + "] not found on " + root.getName()); 
+		}
+		Field field;
+		try {
+			field = clazz.getDeclaredField(name);
+		}
+		catch (NoSuchFieldException nsfe) {
+			field = getField( root, clazz.getSuperclass(), name );
+		}
+		if ( !ReflectHelper.isPublic(clazz, field) ) field.setAccessible(true);
+		return field;
+	}
+	
+	public Getter getGetter(Class theClass, String propertyName)
+		throws PropertyNotFoundException {
+		return new DirectGetter( getField(theClass, propertyName), theClass, propertyName );
+	}
+
+	public Setter getSetter(Class theClass, String propertyName)
+		throws PropertyNotFoundException {
+		return new DirectSetter( getField(theClass, propertyName), theClass, propertyName );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/property/Dom4jAccessor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/property/Dom4jAccessor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/property/Dom4jAccessor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,359 @@
+// $Id: Dom4jAccessor.java 8063 2005-09-01 18:49:39Z oneovthafew $
+package org.hibernate.property;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.dom4j.Attribute;
+import org.dom4j.Element;
+import org.dom4j.Node;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.PropertyNotFoundException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.CollectionType;
+import org.hibernate.type.Type;
+
+/**
+ * Responsible for accessing property values represented as a dom4j Element
+ * or Attribute.
+ *
+ * @author Steve Ebersole
+ */
+public class Dom4jAccessor implements PropertyAccessor {
+	private String nodeName;
+	private Type propertyType;
+	private final SessionFactoryImplementor factory;
+
+	public Dom4jAccessor(String nodeName, Type propertyType, SessionFactoryImplementor factory) {
+		this.factory = factory;
+		this.nodeName = nodeName;
+		this.propertyType = propertyType;
+		
+	}
+
+	/**
+	 * Create a "getter" for the named attribute
+	 */
+	public Getter getGetter(Class theClass, String propertyName) 
+	throws PropertyNotFoundException {
+		if (nodeName==null) {
+			throw new MappingException("no node name for property: " + propertyName);
+		}
+		if ( ".".equals(nodeName) ) {
+			return new TextGetter(propertyType, factory);
+		}
+		else if ( nodeName.indexOf('/')>-1 ) {
+			return new ElementAttributeGetter(nodeName, propertyType, factory);
+		}
+		else if ( nodeName.indexOf('@')>-1 ) {
+			return new AttributeGetter(nodeName, propertyType, factory);
+		}
+		else {
+			return new ElementGetter(nodeName, propertyType, factory);
+		}
+	}
+
+	/**
+	 * Create a "setter" for the named attribute
+	 */
+	public Setter getSetter(Class theClass, String propertyName) 
+	throws PropertyNotFoundException {
+		if (nodeName==null) {
+			throw new MappingException("no node name for property: " + propertyName);
+		}
+		if ( ".".equals(nodeName) ) {
+			return new TextSetter(propertyType);
+		}
+		else if ( nodeName.indexOf('/')>-1 ) {
+			return new ElementAttributeSetter(nodeName, propertyType);
+		}
+		else if ( nodeName.indexOf('@')>-1 ) {
+			return new AttributeSetter(nodeName, propertyType);
+		}
+		else {
+			return new ElementSetter(nodeName, propertyType);
+		}
+	}
+
+	/**
+	 * Defines the strategy for getting property values out of a dom4j Node.
+	 */
+	public abstract static class Dom4jGetter implements Getter {
+		protected final Type propertyType;
+		protected final SessionFactoryImplementor factory;
+		
+		Dom4jGetter(Type propertyType, SessionFactoryImplementor factory) {
+			this.propertyType = propertyType;
+			this.factory = factory;
+		}
+		
+		public Object getForInsert(Object owner, Map mergeMap, SessionImplementor session) 
+		throws HibernateException {
+			return get( owner );
+		}
+
+		/**
+		 * Get the declared Java type
+		 */
+		public Class getReturnType() {
+			return Object.class;
+		}
+
+		/**
+		 * Optional operation (return null)
+		 */
+		public String getMethodName() {
+			return null;
+		}
+
+		/**
+		 * Optional operation (return null)
+		 */
+		public Method getMethod() {
+			return null;
+		}
+	}
+
+	public abstract static class Dom4jSetter implements Setter {
+		protected final Type propertyType;
+
+		Dom4jSetter(Type propertyType) {
+			this.propertyType = propertyType;
+		}
+		
+		/**
+		 * Optional operation (return null)
+		 */
+		public String getMethodName() {
+			return null;
+		}
+
+		/**
+		 * Optional operation (return null)
+		 */
+		public Method getMethod() {
+			return null;
+		}
+	}
+	
+	/**
+	 * For nodes like <tt>"."</tt>
+	 * @author Gavin King
+	 */
+	public static class TextGetter extends Dom4jGetter {
+		
+		TextGetter(Type propertyType, SessionFactoryImplementor factory) {
+			super(propertyType, factory);
+		}
+
+		public Object get(Object owner) throws HibernateException {
+			Element ownerElement = (Element) owner;
+			return super.propertyType.fromXMLNode(ownerElement, super.factory);
+		}	
+		
+	}
+	
+	/**
+	 * For nodes like <tt>"@bar"</tt>
+	 * @author Gavin King
+	 */
+	public static class AttributeGetter extends Dom4jGetter {
+		private final String attributeName;
+		
+		AttributeGetter(String name, Type propertyType, SessionFactoryImplementor factory) {
+			super(propertyType, factory);
+			attributeName = name.substring(1);
+		}
+
+		public Object get(Object owner) throws HibernateException {
+			Element ownerElement = (Element) owner;
+			Node attribute = ownerElement.attribute(attributeName);
+			return attribute==null ? null : 
+				super.propertyType.fromXMLNode(attribute, super.factory);
+		}	
+		
+	}
+
+	/**
+	 * For nodes like <tt>"foo"</tt>
+	 * @author Gavin King
+	 */
+	public static class ElementGetter extends Dom4jGetter {
+		private final String elementName;
+		
+		ElementGetter(String name, Type propertyType, SessionFactoryImplementor factory) {
+			super(propertyType, factory);
+			elementName = name;
+		}
+
+		public Object get(Object owner) throws HibernateException {
+			Element ownerElement = (Element) owner;
+			Node element = ownerElement.element(elementName);
+			return element==null ? 
+					null : super.propertyType.fromXMLNode(element, super.factory);
+		}	
+		
+	}
+	
+	/**
+	 * For nodes like <tt>"foo/@bar"</tt>
+	 * @author Gavin King
+	 */
+	public static class ElementAttributeGetter extends Dom4jGetter {
+		private final String elementName;
+		private final String attributeName;
+		
+		ElementAttributeGetter(String name, Type propertyType, SessionFactoryImplementor factory) {
+			super(propertyType, factory);
+			elementName = name.substring( 0, name.indexOf('/') );
+			attributeName = name.substring( name.indexOf('/')+2 );
+		}
+
+		public Object get(Object owner) throws HibernateException {
+			Element ownerElement = (Element) owner;
+			
+			Element element = ownerElement.element(elementName);
+			
+			if ( element==null ) {
+				return null;
+			}
+			else {
+				Attribute attribute = element.attribute(attributeName);
+				if (attribute==null) {
+					return null;
+				}
+				else {
+					return super.propertyType.fromXMLNode(attribute, super.factory);
+				}
+			}
+		}
+	}
+	
+	
+	/**
+	 * For nodes like <tt>"."</tt>
+	 * @author Gavin King
+	 */
+	public static class TextSetter extends Dom4jSetter {
+		
+		TextSetter(Type propertyType) {
+			super(propertyType);
+		}
+
+		public void set(Object target, Object value, SessionFactoryImplementor factory) 
+		throws HibernateException {
+			Element owner = ( Element ) target;
+			if ( !super.propertyType.isXMLElement() ) { //kinda ugly, but needed for collections with a "." node mapping
+				if (value==null) {
+					owner.setText(null); //is this ok?
+				}
+				else {
+					super.propertyType.setToXMLNode(owner, value, factory);
+				}
+			}
+		}
+
+	}
+	
+	/**
+	 * For nodes like <tt>"@bar"</tt>
+	 * @author Gavin King
+	 */
+	public static class AttributeSetter extends Dom4jSetter {
+		private final String attributeName;
+		
+		AttributeSetter(String name, Type propertyType) {
+			super(propertyType);
+			attributeName = name.substring(1);
+		}
+
+		public void set(Object target, Object value, SessionFactoryImplementor factory) 
+		throws HibernateException {
+			Element owner = ( Element ) target;
+			Attribute attribute = owner.attribute(attributeName);
+			if (value==null) {
+				if (attribute!=null) attribute.detach();
+			}
+			else {
+				if (attribute==null) {
+					owner.addAttribute(attributeName, "null");
+					attribute = owner.attribute(attributeName);
+				}
+				super.propertyType.setToXMLNode(attribute, value, factory);
+			}
+		}
+
+	}
+	
+	/**
+	 * For nodes like <tt>"foo"</tt>
+	 * @author Gavin King
+	 */
+	public static class ElementSetter extends Dom4jSetter {
+		private final String elementName;
+		
+		ElementSetter(String name, Type propertyType) {
+			super(propertyType);
+			elementName = name;
+		}
+
+		public void set(Object target, Object value, SessionFactoryImplementor factory) 
+		throws HibernateException {
+			if (value!=CollectionType.UNFETCHED_COLLECTION) {
+				Element owner = ( Element ) target;
+				Element existing = owner.element(elementName);
+				if (existing!=null) existing.detach();
+				if (value!=null) {
+					Element element = owner.addElement(elementName);
+					super.propertyType.setToXMLNode(element, value, factory);
+				}
+			}
+		}
+
+	}
+	
+	/**
+	 * For nodes like <tt>"foo/@bar"</tt>
+	 * @author Gavin King
+	 */
+	public static class ElementAttributeSetter extends Dom4jSetter {
+		private final String elementName;
+		private final String attributeName;
+		
+		ElementAttributeSetter(String name, Type propertyType) {
+			super(propertyType);
+			elementName = name.substring( 0, name.indexOf('/') );
+			attributeName = name.substring( name.indexOf('/')+2 );
+		}
+
+		public void set(Object target, Object value, SessionFactoryImplementor factory) 
+		throws HibernateException {
+			Element owner = ( Element ) target;
+			Element element = owner.element(elementName);
+			if (value==null) {
+				if (element!=null) element.detach();
+			}
+			else {
+				Attribute attribute;
+				if (element==null) {
+					element = owner.addElement(elementName);
+					attribute = null;
+				}
+				else {
+					attribute = element.attribute(attributeName);
+				}
+				
+				if (attribute==null) {
+					element.addAttribute(attributeName, "null");
+					attribute = element.attribute(attributeName);
+				}				
+				super.propertyType.setToXMLNode(attribute, value, factory);
+			}
+		}
+
+	}
+	
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/property/EmbeddedPropertyAccessor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/property/EmbeddedPropertyAccessor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/property/EmbeddedPropertyAccessor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,83 @@
+//$Id: EmbeddedPropertyAccessor.java 7516 2005-07-16 22:20:48Z oneovthafew $
+package org.hibernate.property;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.PropertyNotFoundException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * @author Gavin King
+ */
+public class EmbeddedPropertyAccessor implements PropertyAccessor {
+	
+	public static final class EmbeddedGetter implements Getter {
+		
+		private final Class clazz;
+		
+		EmbeddedGetter(Class clazz) {
+			this.clazz = clazz;
+		}
+		
+		public Object get(Object target) throws HibernateException {
+			return target;
+		}
+		
+		public Object getForInsert(Object target, Map mergeMap, SessionImplementor session) {
+			return get( target );
+		}
+
+		public Method getMethod() {
+			return null;
+		}
+
+		public String getMethodName() {
+			return null;
+		}
+
+		public Class getReturnType() {
+			return clazz;
+		}
+		
+		public String toString() {
+			return "EmbeddedGetter(" + clazz.getName() + ')';
+		}
+	}
+
+	public static final class EmbeddedSetter implements Setter {
+		
+		private final Class clazz;
+		
+		EmbeddedSetter(Class clazz) {
+			this.clazz = clazz;
+		}
+		
+		public Method getMethod() {
+			return null;
+		}
+
+		public String getMethodName() {
+			return null;
+		}
+
+		public void set(Object target, Object value, SessionFactoryImplementor factory) throws HibernateException {}
+		
+		public String toString() {
+			return "EmbeddedSetter(" + clazz.getName() + ')';
+		}
+	}
+
+	public Getter getGetter(Class theClass, String propertyName)
+	throws PropertyNotFoundException {
+		return new EmbeddedGetter(theClass);
+	}
+
+	public Setter getSetter(Class theClass, String propertyName)
+	throws PropertyNotFoundException {
+		return new EmbeddedSetter(theClass);
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/property/EmbeddedPropertyAccessor.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/property/Getter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/property/Getter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/property/Getter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+//$Id: Getter.java 7516 2005-07-16 22:20:48Z oneovthafew $
+package org.hibernate.property;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * Gets values of a particular property
+ *
+ * @author Gavin King
+ */
+public interface Getter extends Serializable {
+	/**
+	 * Get the property value from the given instance .
+	 * @param owner The instance containing the value to be retreived.
+	 * @return The extracted value.
+	 * @throws HibernateException
+	 */
+	public Object get(Object owner) throws HibernateException;
+
+	/**
+	 * Get the property value from the given owner instance.
+	 *
+	 * @param owner The instance containing the value to be retreived.
+	 * @param mergeMap a map of merged persistent instances to detached instances
+	 * @param session The session from which this request originated.
+	 * @return The extracted value.
+	 * @throws HibernateException
+	 */
+	public Object getForInsert(Object owner, Map mergeMap, SessionImplementor session) 
+	throws HibernateException;
+
+	/**
+	 * Get the declared Java type
+	 */
+	public Class getReturnType();
+
+	/**
+	 * Optional operation (return null)
+	 */
+	public String getMethodName();
+
+	/**
+	 * Optional operation (return null)
+	 */
+	public Method getMethod();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/property/IndexPropertyAccessor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/property/IndexPropertyAccessor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/property/IndexPropertyAccessor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,95 @@
+//$Id: IndexPropertyAccessor.java 7516 2005-07-16 22:20:48Z oneovthafew $
+package org.hibernate.property;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Represents a "back-reference" to the index of a collection.
+ *
+ * @author Gavin King
+ */
+public class IndexPropertyAccessor implements PropertyAccessor {
+	
+	private final String propertyName;
+	private final String entityName;
+
+	/**
+	 * Constructs a new instance of IndexPropertyAccessor.
+	 *
+	 * @param collectionRole The collection role which this back ref references.
+	 */
+	public IndexPropertyAccessor(String collectionRole, String entityName) {
+		this.propertyName = collectionRole.substring( entityName.length()+1 );
+		this.entityName = entityName;
+	}
+
+	public Setter getSetter(Class theClass, String propertyName) {
+		return new IndexSetter();
+	}
+
+	public Getter getGetter(Class theClass, String propertyName) {
+		return new IndexGetter();
+	}
+
+
+	/**
+	 * The Setter implementation for index backrefs.
+	 */
+	public static final class IndexSetter implements Setter {
+
+		public Method getMethod() {
+			return null;
+		}
+
+		public String getMethodName() {
+			return null;
+		}
+
+		public void set(Object target, Object value) {
+			// do nothing...
+		}
+
+		public void set(Object target, Object value, SessionFactoryImplementor factory) throws HibernateException {
+			// do nothing...
+		}
+
+	}
+
+
+	/**
+	 * The Getter implementation for index backrefs.
+	 */
+	public class IndexGetter implements Getter {
+		
+		public Object getForInsert(Object target, Map mergeMap, SessionImplementor session) throws HibernateException {
+			if (session==null) {
+				return BackrefPropertyAccessor.UNKNOWN;
+			}
+			else {
+				return session.getPersistenceContext()
+						.getIndexInOwner(entityName, propertyName, target, mergeMap);
+			}
+		}
+
+		public Object get(Object target)  {
+			return BackrefPropertyAccessor.UNKNOWN;
+		}
+
+		public Method getMethod() {
+			return null;
+		}
+
+		public String getMethodName() {
+			return null;
+		}
+
+		public Class getReturnType() {
+			return Object.class;
+		}
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/property/IndexPropertyAccessor.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/property/MapAccessor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/property/MapAccessor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/property/MapAccessor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,80 @@
+//$Id: MapAccessor.java 7516 2005-07-16 22:20:48Z oneovthafew $
+package org.hibernate.property;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.PropertyNotFoundException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * @author Gavin King
+ */
+public class MapAccessor implements PropertyAccessor {
+
+	public Getter getGetter(Class theClass, String propertyName)
+		throws PropertyNotFoundException {
+		return new MapGetter(propertyName);
+	}
+
+	public Setter getSetter(Class theClass, String propertyName)
+		throws PropertyNotFoundException {
+		return new MapSetter(propertyName);
+	}
+
+	public static final class MapSetter implements Setter {
+
+		private String name;
+
+		MapSetter(String name) {
+			this.name = name;
+		}
+
+		public Method getMethod() {
+			return null;
+		}
+
+		public String getMethodName() {
+			return null;
+		}
+
+		public void set(Object target, Object value, SessionFactoryImplementor factory)
+			throws HibernateException {
+			( (Map) target ).put(name, value);
+		}
+
+	}
+
+	public static final class MapGetter implements Getter {
+
+		private String name;
+
+		MapGetter(String name) {
+			this.name = name;
+		}
+
+		public Method getMethod() {
+			return null;
+		}
+
+		public String getMethodName() {
+			return null;
+		}
+
+		public Object get(Object target) throws HibernateException {
+			return ( (Map) target ).get(name);
+		}
+
+		public Object getForInsert(Object target, Map mergeMap, SessionImplementor session) {
+			return get( target );
+		}
+
+		public Class getReturnType() {
+			return Object.class;
+		}
+
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/property/NoopAccessor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/property/NoopAccessor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/property/NoopAccessor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,79 @@
+package org.hibernate.property;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.PropertyNotFoundException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.property.Getter;
+import org.hibernate.property.PropertyAccessor;
+import org.hibernate.property.Setter;
+
+/**
+ * Used to declare properties not represented at the pojo level
+ * 
+ * @author Michael Bartmann
+ */
+public class NoopAccessor implements PropertyAccessor {
+
+	public Getter getGetter(Class arg0, String arg1) throws PropertyNotFoundException {
+		return new NoopGetter();
+	}
+
+	public Setter getSetter(Class arg0, String arg1) throws PropertyNotFoundException {
+		return new NoopSetter();
+	}
+
+	/**
+	 * A Getter which will always return null. It should not be called anyway.
+	 */
+	private static class NoopGetter implements Getter {
+
+		/**
+		 * @return always null
+		 */
+		public Object get(Object target) throws HibernateException {
+			return null;
+		}
+
+		public Object getForInsert(Object target, Map map, SessionImplementor arg1)
+				throws HibernateException {
+			return null;
+		}
+
+		public Class getReturnType() {
+			return Object.class;
+		}
+
+		public String getMethodName() {
+			return null;
+		}
+
+		public Method getMethod() {
+			return null;
+		}
+
+	}
+
+	/**
+	 * A Setter which will just do nothing.
+	 */
+	private static class NoopSetter implements Setter {
+
+		public void set(Object target, Object value, SessionFactoryImplementor arg2)
+				throws HibernateException {
+			// do not do anything
+		}
+
+		public String getMethodName() {
+			return null;
+		}
+
+		public Method getMethod() {
+			return null;
+		}
+
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/property/NoopAccessor.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/property/PropertyAccessor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/property/PropertyAccessor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/property/PropertyAccessor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+//$Id: PropertyAccessor.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.property;
+
+import org.hibernate.PropertyNotFoundException;
+
+/**
+ * Abstracts the notion of a "property". Defines a strategy for accessing the
+ * value of an attribute.
+ * @author Gavin King
+ */
+public interface PropertyAccessor {
+	/**
+	 * Create a "getter" for the named attribute
+	 */
+	public Getter getGetter(Class theClass, String propertyName) throws PropertyNotFoundException;
+	/**
+	 * Create a "setter" for the named attribute
+	 */
+	public Setter getSetter(Class theClass, String propertyName) throws PropertyNotFoundException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/property/PropertyAccessorFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/property/PropertyAccessorFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/property/PropertyAccessorFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,135 @@
+//$Id: PropertyAccessorFactory.java 8451 2005-10-24 08:45:37Z maxcsaucdk $
+package org.hibernate.property;
+
+import java.util.Map;
+
+import org.hibernate.MappingException;
+import org.hibernate.EntityMode;
+import org.hibernate.type.Type;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.mapping.Property;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * A factory for building/retrieving PropertyAccessor instances.
+ *
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public final class PropertyAccessorFactory {
+
+	private static final PropertyAccessor BASIC_PROPERTY_ACCESSOR = new BasicPropertyAccessor();
+	private static final PropertyAccessor DIRECT_PROPERTY_ACCESSOR = new DirectPropertyAccessor();
+	private static final PropertyAccessor MAP_ACCESSOR = new MapAccessor();
+	private static final PropertyAccessor NOOP_ACCESSOR = new NoopAccessor();
+	private static final PropertyAccessor EMBEDDED_PROPERTY_ACCESSOR = new EmbeddedPropertyAccessor();
+
+	//TODO: ideally we need the construction of PropertyAccessor to take the following:
+	//      1) EntityMode
+	//      2) EntityMode-specific data (i.e., the classname for pojo entities)
+	//      3) Property-specific data based on the EntityMode (i.e., property-name or dom4j-node-name)
+	// The easiest way, with the introduction of the new runtime-metamodel classes, would be the
+	// the following predicates:
+	//      1) PropertyAccessorFactory.getPropertyAccessor() takes references to both a
+	//          org.hibernate.metadata.EntityModeMetadata and org.hibernate.metadata.Property
+	//      2) What is now termed a "PropertyAccessor" stores any values needed from those two
+	//          pieces of information
+	//      3) Code can then simply call PropertyAccess.getGetter() with no parameters; likewise with
+	//          PropertyAccessor.getSetter()
+
+    /**
+     * Retrieves a PropertyAccessor instance based on the given property definition and
+     * entity mode.
+     *
+     * @param property The property for which to retrieve an accessor.
+     * @param mode The mode for the resulting entity.
+     * @return An appropriate accessor.
+     * @throws MappingException
+     */
+	public static PropertyAccessor getPropertyAccessor(Property property, EntityMode mode) throws MappingException {
+		//TODO: this is temporary in that the end result will probably not take a Property reference per-se.
+	    if ( null == mode || EntityMode.POJO.equals( mode ) ) {
+		    return getPojoPropertyAccessor( property.getPropertyAccessorName() );
+	    }
+	    else if ( EntityMode.MAP.equals( mode ) ) {
+		    return getDynamicMapPropertyAccessor();
+	    }
+	    else if ( EntityMode.DOM4J.equals( mode ) ) {
+	    	//TODO: passing null here, because this method is not really used for DOM4J at the moment
+	    	//      but it is still a bug, if we don't get rid of this!
+		    return getDom4jPropertyAccessor( property.getAccessorPropertyName( mode ), property.getType(), null );
+	    }
+	    else {
+		    throw new MappingException( "Unknown entity mode [" + mode + "]" );
+	    }
+	}	/**
+	 * Retreives a PropertyAccessor specific for a PojoRepresentation with the given access strategy.
+	 *
+	 * @param pojoAccessorStrategy The access strategy.
+	 * @return An appropriate accessor.
+	 */
+	private static PropertyAccessor getPojoPropertyAccessor(String pojoAccessorStrategy) {
+		if ( StringHelper.isEmpty( pojoAccessorStrategy ) || "property".equals( pojoAccessorStrategy ) ) {
+			return BASIC_PROPERTY_ACCESSOR;
+		}
+		else if ( "field".equals( pojoAccessorStrategy ) ) {
+			return DIRECT_PROPERTY_ACCESSOR;
+		}
+		else if ( "embedded".equals( pojoAccessorStrategy ) ) {
+			return EMBEDDED_PROPERTY_ACCESSOR;
+		}
+		else if ( "noop".equals(pojoAccessorStrategy) ) {
+			return NOOP_ACCESSOR;
+		}
+		else {
+			return resolveCustomAccessor( pojoAccessorStrategy );
+		}
+	}
+
+	public static PropertyAccessor getDynamicMapPropertyAccessor() throws MappingException {
+		return MAP_ACCESSOR;
+	}
+
+	public static PropertyAccessor getDom4jPropertyAccessor(String nodeName, Type type, SessionFactoryImplementor factory) 
+	throws MappingException {
+		//TODO: need some caching scheme? really comes down to decision 
+		//      regarding amount of state (if any) kept on PropertyAccessors
+		return new Dom4jAccessor( nodeName, type, factory );
+	}
+
+	private static PropertyAccessor resolveCustomAccessor(String accessorName) {
+		Class accessorClass;
+		try {
+			accessorClass = ReflectHelper.classForName(accessorName);
+		}
+		catch (ClassNotFoundException cnfe) {
+			throw new MappingException("could not find PropertyAccessor class: " + accessorName, cnfe);
+		}
+		try {
+			return (PropertyAccessor) accessorClass.newInstance();
+		}
+		catch (Exception e) {
+			throw new MappingException("could not instantiate PropertyAccessor class: " + accessorName, e);
+		}
+	}
+
+	private PropertyAccessorFactory() {}
+
+	// todo : this eventually needs to be removed
+	public static PropertyAccessor getPropertyAccessor(Class optionalClass, String type) throws MappingException {
+		if ( type==null ) type = optionalClass==null || optionalClass==Map.class ? "map" : "property";
+		return getPropertyAccessor(type);
+	}
+
+	// todo : this eventually needs to be removed
+	public static PropertyAccessor getPropertyAccessor(String type) throws MappingException {
+		if ( type==null || "property".equals(type) ) return BASIC_PROPERTY_ACCESSOR;
+		if ( "field".equals(type) ) return DIRECT_PROPERTY_ACCESSOR;
+		if ( "map".equals(type) ) return MAP_ACCESSOR;
+		if ( "embedded".equals(type) ) return EMBEDDED_PROPERTY_ACCESSOR;
+		if ( "noop".equals(type)) return NOOP_ACCESSOR;
+		
+		return resolveCustomAccessor(type);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/property/Setter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/property/Setter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/property/Setter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+//$Id: Setter.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.property;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Sets values to a particular property.
+ * 
+ * @author Gavin King
+ */
+public interface Setter extends Serializable {
+	/**
+	 * Set the property value from the given instance
+	 *
+	 * @param target The instance upon which to set the given value.
+	 * @param value The value to be set on the target.
+	 * @param factory The session factory from which this request originated.
+	 * @throws HibernateException
+	 */
+	public void set(Object target, Object value, SessionFactoryImplementor factory) throws HibernateException;
+	/**
+	 * Optional operation (return null)
+	 */
+	public String getMethodName();
+	/**
+	 * Optional operation (return null)
+	 */
+	public Method getMethod();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/property/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/property/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/property/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package abstracts the notion of a "property" of
+	an entity. Support for JavaBean properties and
+	<tt>Map</tt> elements is included.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/property/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,140 @@
+package org.hibernate.proxy;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LazyInitializationException;
+import org.hibernate.ObjectNotFoundException;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * Convenience base class for lazy initialization handlers.  Centralizes the
+ * basic plumbing of doing lazy initialization freeing subclasses to
+ * acts as essentially adapters to their intended entity mode and/or
+ * proxy generation strategy.
+ *
+ * @author Gavin King
+ */
+public abstract class AbstractLazyInitializer implements LazyInitializer {
+	
+	private Object target;
+	private boolean initialized;
+	private String entityName;
+	private Serializable id;
+	private transient SessionImplementor session;
+	private boolean unwrap;
+	
+	protected AbstractLazyInitializer(String entityName, Serializable id, SessionImplementor session) {
+		this.id = id;
+		this.session = session;
+		this.entityName = entityName;
+	}
+
+	public final Serializable getIdentifier() {
+		return id;
+	}
+
+	public final void setIdentifier(Serializable id) {
+		this.id = id;
+	}
+
+	public final String getEntityName() {
+		return entityName;
+	}
+
+	public final boolean isUninitialized() {
+		return !initialized;
+	}
+
+	public final SessionImplementor getSession() {
+		return session;
+	}
+
+	public final void initialize() throws HibernateException {
+		if (!initialized) {
+			if ( session==null ) {
+				throw new LazyInitializationException("could not initialize proxy - no Session");
+			}
+			else if ( !session.isOpen() ) {
+				throw new LazyInitializationException("could not initialize proxy - the owning Session was closed");
+			}
+			else if ( !session.isConnected() ) {
+				throw new LazyInitializationException("could not initialize proxy - the owning Session is disconnected");
+			}
+			else {
+				target = session.immediateLoad(entityName, id);
+				initialized = true;
+				checkTargetState();
+			}
+		}
+		else {
+			checkTargetState();
+		}
+	}
+
+	private void checkTargetState() {
+		if ( !unwrap ) {
+			if ( target == null ) {
+				getSession().getFactory().getEntityNotFoundDelegate().handleEntityNotFound( entityName, id );
+			}
+		}
+	}
+
+	public final void setSession(SessionImplementor s) throws HibernateException {
+		if (s!=session) {
+			if ( isConnectedToSession() ) {
+				//TODO: perhaps this should be some other RuntimeException...
+				throw new HibernateException("illegally attempted to associate a proxy with two open Sessions");
+			}
+			else {
+				session = s;
+			}
+		}
+	}
+
+	protected final boolean isConnectedToSession() {
+		return session!=null && 
+				session.isOpen() && 
+				session.getPersistenceContext().containsProxy(this);
+	}
+	
+	public final void setImplementation(Object target) {
+		this.target = target;
+		initialized = true;
+	}
+
+	/**
+	 * Return the underlying persistent object, initializing if necessary
+	 */
+	public final Object getImplementation() {
+		initialize();
+		return target;
+	}
+
+	/**
+	 * Return the underlying persistent object in the given <tt>Session</tt>, or null,
+	 * do not initialize the proxy
+	 */
+	public final Object getImplementation(SessionImplementor s) throws HibernateException {
+		final EntityKey entityKey = new EntityKey(
+				getIdentifier(),
+				s.getFactory().getEntityPersister( getEntityName() ),
+				s.getEntityMode()
+			);
+		return s.getPersistenceContext().getEntity( entityKey );
+	}
+
+	protected final Object getTarget() {
+		return target;
+	}
+
+	public boolean isUnwrap() {
+		return unwrap;
+	}
+
+	public void setUnwrap(boolean unwrap) {
+		this.unwrap = unwrap;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/EntityNotFoundDelegate.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/EntityNotFoundDelegate.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/EntityNotFoundDelegate.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,12 @@
+package org.hibernate.proxy;
+
+import java.io.Serializable;
+
+/**
+ * Delegate to handle the scenario of an entity not found by a specified id.
+ *
+ * @author Steve Ebersole
+ */
+public interface EntityNotFoundDelegate {
+	public void handleEntityNotFound(String entityName, Serializable id);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/HibernateProxy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/HibernateProxy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/HibernateProxy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+package org.hibernate.proxy;
+
+import java.io.Serializable;
+
+/**
+ * Marker interface for entity proxies
+ *
+ * @author Gavin King
+ */
+public interface HibernateProxy extends Serializable {
+	/**
+	 * Perform serialization-time write-replacement of this proxy.
+	 *
+	 * @return The serializable proxy replacement.
+	 */
+	public Object writeReplace();
+
+	/**
+	 * Get the underlying lazy initialization handler.
+	 *
+	 * @return The lazy initializer.
+	 */
+	public LazyInitializer getHibernateLazyInitializer();
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/HibernateProxyHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/HibernateProxyHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/HibernateProxyHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: HibernateProxyHelper.java 4453 2004-08-29 07:31:03Z oneovthafew $
+package org.hibernate.proxy;
+
+
+/**
+ * Utility methods for working with proxies. (this class is being phased out)
+ * @author Gavin King
+ */
+public final class HibernateProxyHelper {
+
+	/**
+	 * Get the class of an instance or the underlying class
+	 * of a proxy (without initializing the proxy!). It is
+	 * almost always better to use the entity name!
+	 */
+	public static Class getClassWithoutInitializingProxy(Object object) {
+		if (object instanceof HibernateProxy) {
+			HibernateProxy proxy = (HibernateProxy) object;
+			LazyInitializer li = proxy.getHibernateLazyInitializer();
+			return li.getPersistentClass();
+		}
+		else {
+			return object.getClass();
+		}
+	}
+
+	private HibernateProxyHelper() {
+		//cant instantiate
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/LazyInitializer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/LazyInitializer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/LazyInitializer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,75 @@
+//$Id: LazyInitializer.java 7246 2005-06-20 20:32:36Z oneovthafew $
+package org.hibernate.proxy;
+
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * Handles fetching of the underlying entity for a proxy
+ * @author Gavin King
+ */
+public interface LazyInitializer {
+	
+	/**
+	 * Initialize the proxy, fetching the target
+	 * entity if necessary
+	 */
+	public abstract void initialize() throws HibernateException;
+	
+	/**
+	 * Get the identifier held by the proxy
+	 */
+	public abstract Serializable getIdentifier();
+
+	/**
+	 * Set the identifier property of the proxy
+	 */
+	public abstract void setIdentifier(Serializable id);
+	
+	/**
+	 * Get the entity name
+	 */
+	public abstract String getEntityName();
+	
+	/**
+	 * Get the actual class of the entity (don't
+	 * use this, use the entityName)
+	 */
+	public abstract Class getPersistentClass();
+	
+	/**
+	 * Is the proxy uninitialzed?
+	 */
+	public abstract boolean isUninitialized();
+	
+	/**
+	 * Initialize the proxy manually
+	 */
+	public abstract void setImplementation(Object target);
+	
+	/**
+	 * Get the session, if this proxy is attached
+	 */
+	public abstract SessionImplementor getSession();
+	
+	/**
+	 * Attach the proxy to a session
+	 */
+	public abstract void setSession(SessionImplementor s) throws HibernateException;
+
+	/**
+	 * Return the underlying persistent object, initializing if necessary
+	 */
+	public abstract Object getImplementation();
+
+	/**
+	 * Return the underlying persistent object in the given <tt>Session</tt>, or null
+	 */
+	public abstract Object getImplementation(SessionImplementor s)
+			throws HibernateException;
+	
+	public void setUnwrap(boolean unwrap);
+	public boolean isUnwrap();
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/ProxyFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/ProxyFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/ProxyFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+//$Id: ProxyFactory.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.proxy;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Set;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.AbstractComponentType;
+
+/**
+ * Contract for run-time, proxy-based lazy initialization proxies.
+ *
+ * @author Gavin King
+ */
+public interface ProxyFactory {
+
+	/**
+	 * Called immediately after instantiation of this factory.
+	 * <p/>
+	 * Essentially equivalent to contructor injection, but contracted
+	 * here via interface.
+	 *
+	 * @param entityName The name of the entity for which this factory should
+	 * generate proxies.
+	 * @param persistentClass The entity class for which to generate proxies;
+	 * not always the same as the entityName.
+	 * @param interfaces The interfaces to expose in the generated proxy;
+	 * {@link HibernateProxy} is already included in this collection.
+	 * @param getIdentifierMethod Reference to the identifier getter method;
+	 * invocation on this method should not force initialization
+	 * @param setIdentifierMethod Reference to the identifier setter method;
+	 * invocation on this method should not force initialization
+	 * @param componentIdType For composite identifier types, a reference to
+	 * the {@link org.hibernate.type.ComponentType type} of the identifier
+	 * property; again accessing the id should generally not cause
+	 * initialization - but need to bear in mind <key-many-to-one/>
+	 * mappings.
+	 * @throws HibernateException Indicates a problem completing post
+	 * instantiation initialization.
+	 */
+	public void postInstantiate(
+			String entityName,
+	        Class persistentClass,
+	        Set interfaces,
+	        Method getIdentifierMethod,
+	        Method setIdentifierMethod,
+	        AbstractComponentType componentIdType) throws HibernateException;
+
+	/**
+	 * Create a new proxy instance
+	 *
+	 * @param id The id value for the proxy to be generated.
+	 * @param session The session to which the generated proxy will be
+	 * associated.
+	 * @return The generated proxy.
+	 * @throws HibernateException Indicates problems generating the requested
+	 * proxy.
+	 */
+	public HibernateProxy getProxy(Serializable id,SessionImplementor session) throws HibernateException;
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/dom4j/Dom4jLazyInitializer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/dom4j/Dom4jLazyInitializer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/dom4j/Dom4jLazyInitializer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+// $Id: Dom4jLazyInitializer.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.proxy.dom4j;
+
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.proxy.AbstractLazyInitializer;
+import org.dom4j.Element;
+
+import java.io.Serializable;
+
+/**
+ * Lazy initializer for "dom4j" entity representations.
+ *
+ * @author Steve Ebersole
+ */
+public class Dom4jLazyInitializer extends AbstractLazyInitializer implements Serializable {
+
+	Dom4jLazyInitializer(String entityName, Serializable id, SessionImplementor session) {
+		super(entityName, id, session);
+	}
+
+	public Element getElement() {
+		return (Element) getImplementation();
+	}
+
+	public Class getPersistentClass() {
+		throw new UnsupportedOperationException("dom4j entity representation");
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/dom4j/Dom4jProxy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/dom4j/Dom4jProxy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/dom4j/Dom4jProxy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,568 @@
+// $Id: Dom4jProxy.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.proxy.dom4j;
+
+import org.dom4j.Element;
+import org.dom4j.QName;
+import org.dom4j.Namespace;
+import org.dom4j.Attribute;
+import org.dom4j.CDATA;
+import org.dom4j.Entity;
+import org.dom4j.Text;
+import org.dom4j.Node;
+import org.dom4j.Branch;
+import org.dom4j.ProcessingInstruction;
+import org.dom4j.Comment;
+import org.dom4j.Document;
+import org.dom4j.XPath;
+import org.dom4j.InvalidXPathException;
+import org.dom4j.Visitor;
+import org.hibernate.proxy.dom4j.Dom4jLazyInitializer;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+
+import java.io.Serializable;
+import java.io.Writer;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Iterator;
+
+/**
+ * Proxy for "dom4j" entity representations.
+ *
+ * @author Steve Ebersole
+ */
+public class Dom4jProxy implements HibernateProxy, Element, Serializable {
+
+	private Dom4jLazyInitializer li;
+
+	public Dom4jProxy(Dom4jLazyInitializer li) {
+		this.li = li;
+	}
+
+	public Object writeReplace() {
+		return this;
+	}
+
+	public LazyInitializer getHibernateLazyInitializer() {
+		return li;
+	}
+
+	public QName getQName() {
+		return target().getQName();
+	}
+
+	public QName getQName(String s) {
+		return target().getQName( s );
+	}
+
+	public void setQName(QName qName) {
+		target().setQName( qName );
+	}
+
+	public Namespace getNamespace() {
+		return target().getNamespace();
+	}
+
+	public Namespace getNamespaceForPrefix(String s) {
+		return target().getNamespaceForPrefix( s );
+	}
+
+	public Namespace getNamespaceForURI(String s) {
+		return target().getNamespaceForURI( s );
+	}
+
+	public List getNamespacesForURI(String s) {
+		return target().getNamespacesForURI( s );
+	}
+
+	public String getNamespacePrefix() {
+		return target().getNamespacePrefix();
+	}
+
+	public String getNamespaceURI() {
+		return target().getNamespaceURI();
+	}
+
+	public String getQualifiedName() {
+		return target().getQualifiedName();
+	}
+
+	public List additionalNamespaces() {
+		return target().additionalNamespaces();
+	}
+
+	public List declaredNamespaces() {
+		return target().declaredNamespaces();
+	}
+
+	public Element addAttribute(String attrName, String text) {
+		return target().addAttribute( attrName, text );
+	}
+
+	public Element addAttribute(QName attrName, String text) {
+		return target().addAttribute( attrName, text );
+	}
+
+	public Element addComment(String text) {
+		return target().addComment( text );
+	}
+
+	public Element addCDATA(String text) {
+		return target().addCDATA( text );
+	}
+
+	public Element addEntity(String name, String text) {
+		return target().addEntity( name, text );
+	}
+
+	public Element addNamespace(String prefix, String uri) {
+		return target().addNamespace( prefix, uri );
+	}
+
+	public Element addProcessingInstruction(String target, String text) {
+		return target().addProcessingInstruction( target, text );
+	}
+
+	public Element addProcessingInstruction(String target, Map data) {
+		return target().addProcessingInstruction( target, data );
+	}
+
+	public Element addText(String text) {
+		return target().addText( text );
+	}
+
+	public void add(Attribute attribute) {
+		target().add( attribute );
+	}
+
+	public void add(CDATA cdata) {
+		target().add( cdata );
+	}
+
+	public void add(Entity entity) {
+		target().add( entity );
+	}
+
+	public void add(Text text) {
+		target().add( text );
+	}
+
+	public void add(Namespace namespace) {
+		target().add( namespace );
+	}
+
+	public boolean remove(Attribute attribute) {
+		return target().remove( attribute );
+	}
+
+	public boolean remove(CDATA cdata) {
+		return target().remove( cdata );
+	}
+
+	public boolean remove(Entity entity) {
+		return target().remove( entity );
+	}
+
+	public boolean remove(Namespace namespace) {
+		return target().remove( namespace );
+	}
+
+	public boolean remove(Text text) {
+		return target().remove( text );
+	}
+
+	public boolean supportsParent() {
+		return target().supportsParent();
+	}
+
+	public Element getParent() {
+		return target().getParent();
+	}
+
+	public void setParent(Element element) {
+		target().setParent( element );
+	}
+
+	public Document getDocument() {
+		return target().getDocument();
+	}
+
+	public void setDocument(Document document) {
+		target().setDocument( document );
+	}
+
+	public boolean isReadOnly() {
+		return target().isReadOnly();
+	}
+
+	public boolean hasContent() {
+		return target().hasContent();
+	}
+
+	public String getName() {
+		return target().getName();
+	}
+
+	public void setName(String name) {
+		target().setName( name );
+	}
+
+	public String getText() {
+		return target().getText();
+	}
+
+	public void setText(String text) {
+		target().setText( text );
+	}
+
+	public String getTextTrim() {
+		return target().getTextTrim();
+	}
+
+	public String getStringValue() {
+		return target().getStringValue();
+	}
+
+	public String getPath() {
+		return target().getPath();
+	}
+
+	public String getPath(Element element) {
+		return target().getPath( element );
+	}
+
+	public String getUniquePath() {
+		return target().getUniquePath();
+	}
+
+	public String getUniquePath(Element element) {
+		return target().getUniquePath( element );
+	}
+
+	public String asXML() {
+		return target().asXML();
+	}
+
+	public void write(Writer writer) throws IOException {
+		target().write( writer );
+	}
+
+	public short getNodeType() {
+		return target().getNodeType();
+	}
+
+	public String getNodeTypeName() {
+		return target().getNodeTypeName();
+	}
+
+	public Node detach() {
+		Element parent = target().getParent();
+		if (parent!=null) parent.remove(this);
+		return target().detach();
+	}
+
+	public List selectNodes(String xpath) {
+		return target().selectNodes( xpath );
+	}
+
+	public Object selectObject(String xpath) {
+		return target().selectObject( xpath );
+	}
+
+	public List selectNodes(String xpath, String comparison) {
+		return target().selectNodes( xpath, comparison );
+	}
+
+	public List selectNodes(String xpath, String comparison, boolean removeDups) {
+		return target().selectNodes( xpath, comparison, removeDups );
+	}
+
+	public Node selectSingleNode(String xpath) {
+        return target().selectSingleNode( xpath );
+	}
+
+	public String valueOf(String xpath) {
+		return target().valueOf( xpath );
+	}
+
+	public Number numberValueOf(String xpath) {
+		return target().numberValueOf( xpath );
+	}
+
+	public boolean matches(String xpath) {
+		return target().matches( xpath );
+	}
+
+	public XPath createXPath(String xpath) throws InvalidXPathException {
+		return target().createXPath( xpath );
+	}
+
+	public Node asXPathResult(Element element) {
+		return target().asXPathResult( element );
+	}
+
+	public void accept(Visitor visitor) {
+		target().accept( visitor );
+	}
+
+	public Object clone() {
+		return target().clone();
+	}
+
+	public Object getData() {
+		return target().getData();
+	}
+
+	public void setData(Object data) {
+		target().setData( data );
+	}
+
+	public List attributes() {
+		return target().attributes();
+	}
+
+	public void setAttributes(List list) {
+		target().setAttributes( list );
+	}
+
+	public int attributeCount() {
+		return target().attributeCount();
+	}
+
+	public Iterator attributeIterator() {
+		return target().attributeIterator();
+	}
+
+	public Attribute attribute(int i) {
+		return target().attribute( i );
+	}
+
+	public Attribute attribute(String name) {
+		return target().attribute( name );
+	}
+
+	public Attribute attribute(QName qName) {
+		return target().attribute( qName );
+	}
+
+	public String attributeValue(String name) {
+		return target().attributeValue( name );
+	}
+
+	public String attributeValue(String name, String defaultValue) {
+		return target().attributeValue( name, defaultValue );
+	}
+
+	public String attributeValue(QName qName) {
+		return target().attributeValue( qName );
+	}
+
+	public String attributeValue(QName qName, String defaultValue) {
+		return target().attributeValue( qName, defaultValue );
+	}
+
+	/**
+	 * @deprecated
+	 */
+	public void setAttributeValue(String name, String value) {
+		target().setAttributeValue( name, value );
+	}
+
+	/**
+	 * @deprecated
+	 */
+	public void setAttributeValue(QName qName, String value) {
+		target().setAttributeValue( qName, value );
+	}
+
+	public Element element(String name) {
+		return target().element( name );
+	}
+
+	public Element element(QName qName) {
+		return target().element( qName );
+	}
+
+	public List elements() {
+		return target().elements();
+	}
+
+	public List elements(String name) {
+		return target().elements( name );
+	}
+
+	public List elements(QName qName) {
+		return target().elements( qName );
+	}
+
+	public Iterator elementIterator() {
+		return target().elementIterator();
+	}
+
+	public Iterator elementIterator(String name) {
+		return target().elementIterator( name );
+
+	}
+
+	public Iterator elementIterator(QName qName) {
+		return target().elementIterator( qName );
+	}
+
+	public boolean isRootElement() {
+		return target().isRootElement();
+	}
+
+	public boolean hasMixedContent() {
+		return target().hasMixedContent();
+	}
+
+	public boolean isTextOnly() {
+		return target().isTextOnly();
+	}
+
+	public void appendAttributes(Element element) {
+		target().appendAttributes( element );
+	}
+
+	public Element createCopy() {
+		return target().createCopy();
+	}
+
+	public Element createCopy(String name) {
+		return target().createCopy( name );
+	}
+
+	public Element createCopy(QName qName) {
+		return target().createCopy( qName );
+	}
+
+	public String elementText(String name) {
+		return target().elementText( name );
+	}
+
+	public String elementText(QName qName) {
+		return target().elementText( qName );
+	}
+
+	public String elementTextTrim(String name) {
+		return target().elementTextTrim( name );
+	}
+
+	public String elementTextTrim(QName qName) {
+		return target().elementTextTrim( qName );
+	}
+
+	public Node getXPathResult(int i) {
+		return target().getXPathResult( i );
+	}
+
+	public Node node(int i) {
+		return target().node( i );
+	}
+
+	public int indexOf(Node node) {
+		return target().indexOf( node );
+	}
+
+	public int nodeCount() {
+		return target().nodeCount();
+	}
+
+	public Element elementByID(String id) {
+		return target().elementByID( id );
+	}
+
+	public List content() {
+		return target().content();
+	}
+
+	public Iterator nodeIterator() {
+		return target().nodeIterator();
+	}
+
+	public void setContent(List list) {
+		target().setContent( list );
+	}
+
+	public void appendContent(Branch branch) {
+		target().appendContent( branch );
+	}
+
+	public void clearContent() {
+		target().clearContent();
+	}
+
+	public List processingInstructions() {
+		return target().processingInstructions();
+	}
+
+	public List processingInstructions(String name) {
+		return target().processingInstructions( name );
+	}
+
+	public ProcessingInstruction processingInstruction(String name) {
+		return target().processingInstruction( name );
+	}
+
+	public void setProcessingInstructions(List list) {
+		target().setProcessingInstructions( list );
+	}
+
+	public Element addElement(String name) {
+		return target().addElement( name );
+	}
+
+	public Element addElement(QName qName) {
+		return target().addElement( qName );
+	}
+
+	public Element addElement(String name, String text) {
+		return target().addElement( name, text );
+
+	}
+
+	public boolean removeProcessingInstruction(String name) {
+		return target().removeProcessingInstruction( name );
+	}
+
+	public void add(Node node) {
+		target().add( node );
+	}
+
+	public void add(Comment comment) {
+		target().add( comment );
+	}
+
+	public void add(Element element) {
+		target().add( element );
+	}
+
+	public void add(ProcessingInstruction processingInstruction) {
+		target().add( processingInstruction );
+	}
+
+	public boolean remove(Node node) {
+		return target().remove( node );
+	}
+
+	public boolean remove(Comment comment) {
+		return target().remove( comment );
+	}
+
+	public boolean remove(Element element) {
+		return target().remove( element );
+	}
+
+	public boolean remove(ProcessingInstruction processingInstruction) {
+		return target().remove( processingInstruction );
+	}
+
+	public void normalize() {
+		target().normalize();
+	}
+
+	private Element target() {
+		return li.getElement();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/dom4j/Dom4jProxyFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/dom4j/Dom4jProxyFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/dom4j/Dom4jProxyFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+// $Id: Dom4jProxyFactory.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.proxy.dom4j;
+
+import org.hibernate.HibernateException;
+import org.hibernate.proxy.dom4j.Dom4jLazyInitializer;
+import org.hibernate.proxy.dom4j.Dom4jProxy;
+import org.hibernate.proxy.ProxyFactory;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.engine.SessionImplementor;
+
+import java.util.Set;
+import java.lang.reflect.Method;
+import java.io.Serializable;
+
+/**
+ * Builds proxies for "dom4j" entity representations.
+ *
+ * @author Steve Ebersole
+ */
+public class Dom4jProxyFactory implements ProxyFactory {
+
+	private String entityName;
+
+	/**
+	 * Called immediately after instantiation
+	 */
+	public void postInstantiate(
+	        String entityName,
+	        Class persistentClass,
+	        Set interfaces,
+	        Method getIdentifierMethod,
+	        Method setIdentifierMethod,
+	        AbstractComponentType componentIdType) throws HibernateException {
+		this.entityName = entityName;
+	}
+
+	/**
+	 * Create a new proxy
+	 */
+	public HibernateProxy getProxy(Serializable id, SessionImplementor session) throws HibernateException {
+		return new Dom4jProxy( new Dom4jLazyInitializer( entityName, id, session ) );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/map/MapLazyInitializer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/map/MapLazyInitializer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/map/MapLazyInitializer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+//$Id: MapLazyInitializer.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.proxy.map;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.proxy.AbstractLazyInitializer;
+
+/**
+ * Lazy initializer for "dynamic-map" entity representations.
+ *
+ * @author Gavin King
+ */
+public class MapLazyInitializer extends AbstractLazyInitializer implements Serializable {
+
+	MapLazyInitializer(String entityName, Serializable id, SessionImplementor session) {
+		super(entityName, id, session);
+	}
+
+	public Map getMap() {
+		return (Map) getImplementation();
+	}
+
+	public Class getPersistentClass() {
+		throw new UnsupportedOperationException("dynamic-map entity representation");
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/map/MapProxy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/map/MapProxy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/map/MapProxy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,82 @@
+//$Id: MapProxy.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.proxy.map;
+
+import org.hibernate.proxy.map.MapLazyInitializer;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Proxy for "dynamic-map" entity representations.
+ *
+ * @author Gavin King
+ */
+public class MapProxy implements HibernateProxy, Map, Serializable {
+
+	private MapLazyInitializer li;
+
+	MapProxy(MapLazyInitializer li) {
+		this.li = li;
+	}
+
+	public Object writeReplace() {
+		return this;
+	}
+
+	public LazyInitializer getHibernateLazyInitializer() {
+		return li;
+	}
+
+	public int size() {
+		return li.getMap().size();
+	}
+
+	public void clear() {
+		li.getMap().clear();
+	}
+
+	public boolean isEmpty() {
+		return li.getMap().isEmpty();
+	}
+
+	public boolean containsKey(Object key) {
+		return li.getMap().containsKey(key);
+	}
+
+	public boolean containsValue(Object value) {
+		return li.getMap().containsValue(value);
+	}
+
+	public Collection values() {
+		return li.getMap().values();
+	}
+
+	public void putAll(Map t) {
+		li.getMap().putAll(t);
+	}
+
+	public Set entrySet() {
+		return li.getMap().entrySet();
+	}
+
+	public Set keySet() {
+		return li.getMap().keySet();
+	}
+
+	public Object get(Object key) {
+		return li.getMap().get(key);
+	}
+
+	public Object remove(Object key) {
+		return li.getMap().remove(key);
+	}
+
+	public Object put(Object key, Object value) {
+		return li.getMap().put(key, value);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/map/MapProxyFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/map/MapProxyFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/map/MapProxyFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+//$Id: MapProxyFactory.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.proxy.map;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Set;
+
+import org.hibernate.HibernateException;
+import org.hibernate.proxy.map.MapLazyInitializer;
+import org.hibernate.proxy.map.MapProxy;
+import org.hibernate.proxy.ProxyFactory;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.AbstractComponentType;
+
+/**
+ * @author Gavin King
+ */
+public class MapProxyFactory implements ProxyFactory {
+
+	private String entityName;
+
+	public void postInstantiate(
+		final String entityName, 
+		final Class persistentClass,
+		final Set interfaces, 
+		final Method getIdentifierMethod,
+		final Method setIdentifierMethod,
+		AbstractComponentType componentIdType) 
+	throws HibernateException {
+		
+		this.entityName = entityName;
+
+	}
+
+	public HibernateProxy getProxy(
+		final Serializable id, 
+		final SessionImplementor session)
+	throws HibernateException {
+		return new MapProxy( new MapLazyInitializer(entityName, id, session) );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines a framework for lazy-initializing
+	entity proxies.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/BasicLazyInitializer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/BasicLazyInitializer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/BasicLazyInitializer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,121 @@
+//$Id: BasicLazyInitializer.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.proxy.pojo;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.util.MarkerObject;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.proxy.AbstractLazyInitializer;
+
+/**
+ * Lazy initializer for POJOs
+ * @author Gavin King
+ */
+public abstract class BasicLazyInitializer extends AbstractLazyInitializer {
+
+	protected static final Object INVOKE_IMPLEMENTATION = new MarkerObject("INVOKE_IMPLEMENTATION");
+
+	protected Class persistentClass;
+	protected Method getIdentifierMethod;
+	protected Method setIdentifierMethod;
+	protected boolean overridesEquals;
+	private Object replacement;
+	protected AbstractComponentType componentIdType;
+
+	protected BasicLazyInitializer(
+			String entityName,
+	        Class persistentClass,
+	        Serializable id,
+	        Method getIdentifierMethod,
+	        Method setIdentifierMethod,
+	        AbstractComponentType componentIdType,
+	        SessionImplementor session) {
+		super(entityName, id, session);
+		this.persistentClass = persistentClass;
+		this.getIdentifierMethod = getIdentifierMethod;
+		this.setIdentifierMethod = setIdentifierMethod;
+		this.componentIdType = componentIdType;
+		overridesEquals = ReflectHelper.overridesEquals(persistentClass);
+	}
+
+	protected abstract Object serializableProxy();
+
+	protected final Object invoke(Method method, Object[] args, Object proxy) throws Throwable {
+
+		String methodName = method.getName();
+		int params = args.length;
+
+		if ( params==0 ) {
+
+			if ( "writeReplace".equals(methodName) ) {
+				return getReplacement();
+			}
+			else if ( !overridesEquals && "hashCode".equals(methodName) ) {
+				return new Integer( System.identityHashCode(proxy) );
+			}
+			else if ( isUninitialized() && method.equals(getIdentifierMethod) ) {
+				return getIdentifier();
+			}
+
+			else if ( "getHibernateLazyInitializer".equals(methodName) ) {
+				return this;
+			}
+
+		}
+		else if ( params==1 ) {
+
+			if ( !overridesEquals && "equals".equals(methodName) ) {
+				return args[0]==proxy ? Boolean.TRUE : Boolean.FALSE;
+			}
+			else if ( method.equals(setIdentifierMethod) ) {
+				initialize();
+				setIdentifier( (Serializable) args[0] );
+				return INVOKE_IMPLEMENTATION;
+			}
+
+		}
+
+		//if it is a property of an embedded component, invoke on the "identifier"
+		if ( componentIdType!=null && componentIdType.isMethodOf(method) ) {
+			return method.invoke( getIdentifier(), args );
+		}
+
+		// otherwise:
+		return INVOKE_IMPLEMENTATION;
+
+	}
+
+	private Object getReplacement() {
+
+		final SessionImplementor session = getSession();
+		if ( isUninitialized() && session != null && session.isOpen()) {
+			final EntityKey key = new EntityKey(
+					getIdentifier(),
+			        session.getFactory().getEntityPersister( getEntityName() ),
+			        session.getEntityMode()
+				);
+			final Object entity = session.getPersistenceContext().getEntity(key);
+			if (entity!=null) setImplementation( entity );
+		}
+
+		if ( isUninitialized() ) {
+			if (replacement==null) {
+				replacement = serializableProxy();
+			}
+			return replacement;
+		}
+		else {
+			return getTarget();
+		}
+
+	}
+
+	public final Class getPersistentClass() {
+		return persistentClass;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/cglib/CGLIBLazyInitializer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/cglib/CGLIBLazyInitializer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/cglib/CGLIBLazyInitializer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,198 @@
+// $Id: CGLIBLazyInitializer.java 11295 2007-03-18 04:05:28Z scottmarlownovell $
+package org.hibernate.proxy.pojo.cglib;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import net.sf.cglib.proxy.Callback;
+import net.sf.cglib.proxy.CallbackFilter;
+import net.sf.cglib.proxy.Enhancer;
+import net.sf.cglib.proxy.InvocationHandler;
+import net.sf.cglib.proxy.NoOp;
+
+import org.hibernate.HibernateException;
+import org.hibernate.LazyInitializationException;
+import org.hibernate.proxy.pojo.BasicLazyInitializer;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.util.ReflectHelper;
+
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * A <tt>LazyInitializer</tt> implemented using the CGLIB bytecode generation library
+ */
+public final class CGLIBLazyInitializer extends BasicLazyInitializer implements InvocationHandler {
+
+	private static final CallbackFilter FINALIZE_FILTER = new CallbackFilter() {
+		public int accept(Method method) {
+			if ( method.getParameterTypes().length == 0 && method.getName().equals("finalize") ){
+				return 1;
+			}
+			else {
+				return 0;
+			}
+		}
+	};
+
+	private Class[] interfaces;
+	private boolean constructed = false;
+
+	static HibernateProxy getProxy(final String entityName, final Class persistentClass,
+			final Class[] interfaces, final Method getIdentifierMethod,
+			final Method setIdentifierMethod, AbstractComponentType componentIdType,
+			final Serializable id, final SessionImplementor session) throws HibernateException {
+		// note: interfaces is assumed to already contain HibernateProxy.class
+
+		try {
+			final CGLIBLazyInitializer instance = new CGLIBLazyInitializer(
+					entityName,
+					persistentClass,
+					interfaces,
+					id,
+					getIdentifierMethod,
+					setIdentifierMethod,
+					componentIdType,
+					session
+				);
+
+			final HibernateProxy proxy;
+			Class factory = getProxyFactory(persistentClass,  interfaces);
+			proxy = getProxyInstance(factory, instance);
+			instance.constructed = true;
+			return proxy;
+		}
+		catch (Throwable t) {
+			LogFactory.getLog( BasicLazyInitializer.class )
+				.error( "CGLIB Enhancement failed: " + entityName, t );
+			throw new HibernateException( "CGLIB Enhancement failed: " + entityName, t );
+		}
+	}
+
+	public static HibernateProxy getProxy(final Class factory, final String entityName,
+			final Class persistentClass, final Class[] interfaces,
+			final Method getIdentifierMethod, final Method setIdentifierMethod,
+			final AbstractComponentType componentIdType, final Serializable id,
+			final SessionImplementor session) throws HibernateException {
+
+		final CGLIBLazyInitializer instance = new CGLIBLazyInitializer(
+				entityName,
+				persistentClass,
+				interfaces,
+				id,
+				getIdentifierMethod,
+				setIdentifierMethod,
+				componentIdType,
+				session
+			);
+
+		final HibernateProxy proxy;
+		try {
+			proxy = getProxyInstance(factory, instance);
+		}
+		catch (Exception e) {
+			throw new HibernateException( "CGLIB Enhancement failed: " + persistentClass.getName(), e );
+		}
+		instance.constructed = true;
+
+		return proxy;
+	}
+
+    private static HibernateProxy getProxyInstance(Class factory, CGLIBLazyInitializer instance) throws InstantiationException, IllegalAccessException {
+		HibernateProxy proxy;
+		try {
+			Enhancer.registerCallbacks(factory, new Callback[]{ instance, null });
+			proxy = (HibernateProxy)factory.newInstance();
+		} finally {
+			// HHH-2481 make sure the callback gets cleared, otherwise the instance stays in a static thread local.
+			Enhancer.registerCallbacks(factory, null);
+		}
+		return proxy;
+	}
+
+	public static Class getProxyFactory(Class persistentClass, Class[] interfaces)
+			throws HibernateException {
+		Enhancer e = new Enhancer();
+		e.setSuperclass( interfaces.length == 1 ? persistentClass : null );
+		e.setInterfaces(interfaces);
+		e.setCallbackTypes(new Class[]{
+			InvocationHandler.class,
+			NoOp.class,
+	  		});
+  		e.setCallbackFilter(FINALIZE_FILTER);
+  		e.setUseFactory(false);
+		e.setInterceptDuringConstruction( false );
+		return e.createClass();
+	}
+
+	private CGLIBLazyInitializer(final String entityName, final Class persistentClass,
+			final Class[] interfaces, final Serializable id, final Method getIdentifierMethod,
+			final Method setIdentifierMethod, final AbstractComponentType componentIdType,
+			final SessionImplementor session) {
+		super(
+				entityName,
+				persistentClass,
+				id,
+				getIdentifierMethod,
+				setIdentifierMethod,
+				componentIdType,
+				session
+			);
+		this.interfaces = interfaces;
+	}
+
+	public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+		if ( constructed ) {
+			Object result = invoke( method, args, proxy );
+			if ( result == INVOKE_IMPLEMENTATION ) {
+				Object target = getImplementation();
+				try {
+					final Object returnValue;
+					if ( ReflectHelper.isPublic( persistentClass, method ) ) {
+						if ( !method.getDeclaringClass().isInstance( target ) ) {
+							throw new ClassCastException( target.getClass().getName() );
+						}
+						returnValue = method.invoke( target, args );
+					}
+					else {
+						if ( !method.isAccessible() ) {
+							method.setAccessible( true );
+						}
+						returnValue = method.invoke( target, args );
+					}
+					return returnValue == target ? proxy : returnValue;
+				}
+				catch ( InvocationTargetException ite ) {
+					throw ite.getTargetException();
+				}
+			}
+			else {
+				return result;
+			}
+		}
+		else {
+			// while constructor is running
+			if ( method.getName().equals( "getHibernateLazyInitializer" ) ) {
+				return this;
+			}
+			else {
+				throw new LazyInitializationException( "unexpected case hit, method=" + method.getName() );
+			}
+		}
+	}
+
+	protected Object serializableProxy() {
+		return new SerializableProxy(
+				getEntityName(),
+				persistentClass,
+				interfaces,
+				getIdentifier(),
+				getIdentifierMethod,
+				setIdentifierMethod,
+				componentIdType 
+			);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/cglib/CGLIBProxyFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/cglib/CGLIBProxyFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/cglib/CGLIBProxyFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+//$Id: CGLIBProxyFactory.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.proxy.pojo.cglib;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Set;
+
+import org.hibernate.HibernateException;
+import org.hibernate.proxy.ProxyFactory;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.AbstractComponentType;
+
+/**
+ * @author Gavin King
+ */
+public class CGLIBProxyFactory implements ProxyFactory {
+
+	protected static final Class[] NO_CLASSES = new Class[0];
+
+	private Class persistentClass;
+	private String entityName;
+	private Class[] interfaces;
+	private Method getIdentifierMethod;
+	private Method setIdentifierMethod;
+	private AbstractComponentType componentIdType;
+	private Class factory;
+
+	public void postInstantiate(
+		final String entityName,
+		final Class persistentClass,
+		final Set interfaces,
+		final Method getIdentifierMethod,
+		final Method setIdentifierMethod,
+		AbstractComponentType componentIdType)
+	throws HibernateException {
+		this.entityName = entityName;
+		this.persistentClass = persistentClass;
+		this.interfaces = (Class[]) interfaces.toArray(NO_CLASSES);
+		this.getIdentifierMethod = getIdentifierMethod;
+		this.setIdentifierMethod = setIdentifierMethod;
+		this.componentIdType = componentIdType;
+		factory = CGLIBLazyInitializer.getProxyFactory(persistentClass, this.interfaces);
+	}
+
+	public HibernateProxy getProxy(Serializable id, SessionImplementor session)
+		throws HibernateException {
+
+		return CGLIBLazyInitializer.getProxy(
+				factory, 
+				entityName, 
+				persistentClass, 
+				interfaces, 
+				getIdentifierMethod, 
+				setIdentifierMethod,
+				componentIdType,
+				id, 
+				session
+			);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/cglib/SerializableProxy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/cglib/SerializableProxy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/cglib/SerializableProxy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,75 @@
+//$Id: SerializableProxy.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.proxy.pojo.cglib;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+import org.hibernate.HibernateException;
+import org.hibernate.type.AbstractComponentType;
+
+/**
+ * Serializable placeholder for <tt>CGLIB</tt> proxies
+ */
+public final class SerializableProxy implements Serializable {
+
+	private String entityName;
+	private Class persistentClass;
+	private Class[] interfaces;
+	private Serializable id;
+	private Class getIdentifierMethodClass;
+	private Class setIdentifierMethodClass;
+	private String getIdentifierMethodName;
+	private String setIdentifierMethodName;
+	private Class[] setIdentifierMethodParams;
+	private AbstractComponentType componentIdType;
+
+	public SerializableProxy() {}
+
+	public SerializableProxy(
+		final String entityName,
+		final Class persistentClass,
+		final Class[] interfaces,
+		final Serializable id,
+		final Method getIdentifierMethod,
+		final Method setIdentifierMethod,
+		AbstractComponentType componentIdType
+	) {
+		this.entityName = entityName;
+		this.persistentClass = persistentClass;
+		this.interfaces = interfaces;
+		this.id = id;
+		if (getIdentifierMethod!=null) {
+			getIdentifierMethodClass = getIdentifierMethod.getDeclaringClass();
+			getIdentifierMethodName = getIdentifierMethod.getName();
+		}
+		if (setIdentifierMethod!=null) {
+			setIdentifierMethodClass = setIdentifierMethod.getDeclaringClass();
+			setIdentifierMethodName = setIdentifierMethod.getName();
+			setIdentifierMethodParams = setIdentifierMethod.getParameterTypes();
+		}
+		this.componentIdType = componentIdType;
+	}
+
+	private Object readResolve() {
+		try {
+			return CGLIBLazyInitializer.getProxy(
+				entityName,
+				persistentClass,
+				interfaces,
+				getIdentifierMethodName==null ?
+					null :
+					getIdentifierMethodClass.getDeclaredMethod(getIdentifierMethodName, null),
+				setIdentifierMethodName==null ?
+					null :
+					setIdentifierMethodClass.getDeclaredMethod(setIdentifierMethodName, setIdentifierMethodParams),
+					componentIdType,
+				id,
+				null
+			);
+		}
+		catch (NoSuchMethodException nsme) {
+			throw new HibernateException("could not create proxy for entity: " + entityName, nsme);
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,213 @@
+package org.hibernate.proxy.pojo.javassist;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import javassist.util.proxy.MethodFilter;
+import javassist.util.proxy.MethodHandler;
+import javassist.util.proxy.ProxyFactory;
+import javassist.util.proxy.ProxyObject;
+
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.proxy.pojo.BasicLazyInitializer;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * A Javassist-based lazy initializer proxy.
+ *
+ * @author Muga Nishizawa
+ */
+public class JavassistLazyInitializer extends BasicLazyInitializer implements MethodHandler {
+
+	private static final MethodFilter FINALIZE_FILTER = new MethodFilter() {
+		public boolean isHandled(Method m) {
+			// skip finalize methods
+			return !( m.getParameterTypes().length == 0 && m.getName().equals( "finalize" ) );
+		}
+	};
+
+	private Class[] interfaces;
+	private boolean constructed = false;
+
+	private JavassistLazyInitializer(
+			final String entityName,
+	        final Class persistentClass,
+	        final Class[] interfaces,
+	        final Serializable id,
+	        final Method getIdentifierMethod,
+	        final Method setIdentifierMethod,
+	        final AbstractComponentType componentIdType,
+	        final SessionImplementor session) {
+		super( entityName, persistentClass, id, getIdentifierMethod, setIdentifierMethod, componentIdType, session );
+		this.interfaces = interfaces;
+	}
+
+	public static HibernateProxy getProxy(
+			final String entityName,
+	        final Class persistentClass,
+	        final Class[] interfaces,
+	        final Method getIdentifierMethod,
+	        final Method setIdentifierMethod,
+	        AbstractComponentType componentIdType,
+	        final Serializable id,
+	        final SessionImplementor session) throws HibernateException {
+		// note: interface is assumed to already contain HibernateProxy.class
+		try {
+			final JavassistLazyInitializer instance = new JavassistLazyInitializer(
+					entityName,
+			        persistentClass,
+			        interfaces,
+			        id,
+			        getIdentifierMethod,
+			        setIdentifierMethod,
+			        componentIdType,
+			        session
+			);
+			ProxyFactory factory = new ProxyFactory();
+			factory.setSuperclass( interfaces.length == 1 ? persistentClass : null );
+			factory.setInterfaces( interfaces );
+			factory.setFilter( FINALIZE_FILTER );
+			Class cl = factory.createClass();
+			final HibernateProxy proxy = ( HibernateProxy ) cl.newInstance();
+			( ( ProxyObject ) proxy ).setHandler( instance );
+			instance.constructed = true;
+			return proxy;
+		}
+		catch ( Throwable t ) {
+			LogFactory.getLog( BasicLazyInitializer.class ).error(
+					"Javassist Enhancement failed: " + entityName, t
+			);
+			throw new HibernateException(
+					"Javassist Enhancement failed: "
+					+ entityName, t
+			);
+		}
+	}
+
+	public static HibernateProxy getProxy(
+			final Class factory,
+	        final String entityName,
+	        final Class persistentClass,
+	        final Class[] interfaces,
+	        final Method getIdentifierMethod,
+	        final Method setIdentifierMethod,
+	        final AbstractComponentType componentIdType,
+	        final Serializable id,
+	        final SessionImplementor session) throws HibernateException {
+
+		final JavassistLazyInitializer instance = new JavassistLazyInitializer(
+				entityName,
+		        persistentClass,
+		        interfaces, id,
+		        getIdentifierMethod,
+		        setIdentifierMethod,
+		        componentIdType,
+		        session
+		);
+
+		final HibernateProxy proxy;
+		try {
+			proxy = ( HibernateProxy ) factory.newInstance();
+		}
+		catch ( Exception e ) {
+			throw new HibernateException(
+					"Javassist Enhancement failed: "
+					+ persistentClass.getName(), e
+			);
+		}
+		( ( ProxyObject ) proxy ).setHandler( instance );
+		instance.constructed = true;
+		return proxy;
+	}
+
+	public static Class getProxyFactory(
+			Class persistentClass,
+	        Class[] interfaces) throws HibernateException {
+		// note: interfaces is assumed to already contain HibernateProxy.class
+
+		try {
+			ProxyFactory factory = new ProxyFactory();
+			factory.setSuperclass( interfaces.length == 1 ? persistentClass : null );
+			factory.setInterfaces( interfaces );
+			factory.setFilter( FINALIZE_FILTER );
+			return factory.createClass();
+		}
+		catch ( Throwable t ) {
+			LogFactory.getLog( BasicLazyInitializer.class ).error(
+					"Javassist Enhancement failed: "
+					+ persistentClass.getName(), t
+			);
+			throw new HibernateException(
+					"Javassist Enhancement failed: "
+					+ persistentClass.getName(), t
+			);
+		}
+	}
+
+	public Object invoke(
+			final Object proxy,
+			final Method thisMethod,
+			final Method proceed,
+			final Object[] args) throws Throwable {
+		if ( this.constructed ) {
+			Object result;
+			try {
+				result = this.invoke( thisMethod, args, proxy );
+			}
+			catch ( Throwable t ) {
+				throw new Exception( t.getCause() );
+			}
+			if ( result == INVOKE_IMPLEMENTATION ) {
+				Object target = getImplementation();
+				final Object returnValue;
+				try {
+					if ( ReflectHelper.isPublic( persistentClass, thisMethod ) ) {
+						if ( !thisMethod.getDeclaringClass().isInstance( target ) ) {
+							throw new ClassCastException( target.getClass().getName() );
+						}
+						returnValue = thisMethod.invoke( target, args );
+					}
+					else {
+						if ( !thisMethod.isAccessible() ) {
+							thisMethod.setAccessible( true );
+						}
+						returnValue = thisMethod.invoke( target, args );
+					}
+					return returnValue == target ? proxy : returnValue;
+				}
+				catch ( InvocationTargetException ite ) {
+					throw ite.getTargetException();
+				}
+			}
+			else {
+				return result;
+			}
+		}
+		else {
+			// while constructor is running
+			if ( thisMethod.getName().equals( "getHibernateLazyInitializer" ) ) {
+				return this;
+			}
+			else {
+				return proceed.invoke( proxy, args );
+			}
+		}
+	}
+
+	protected Object serializableProxy() {
+		return new SerializableProxy(
+				getEntityName(),
+		        persistentClass,
+		        interfaces,
+		        getIdentifier(),
+		        getIdentifierMethod,
+		        setIdentifierMethod,
+		        componentIdType
+		);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistProxyFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistProxyFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistProxyFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,61 @@
+package org.hibernate.proxy.pojo.javassist;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Set;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.ProxyFactory;
+import org.hibernate.type.AbstractComponentType;
+
+/**
+ * A {@link ProxyFactory} implementation for producing Javassist-based proxies.
+ *
+ * @author Muga Nishizawa
+ */
+public class JavassistProxyFactory implements ProxyFactory, Serializable {
+
+	protected static final Class[] NO_CLASSES = new Class[0];
+	private Class persistentClass;
+	private String entityName;
+	private Class[] interfaces;
+	private Method getIdentifierMethod;
+	private Method setIdentifierMethod;
+	private AbstractComponentType componentIdType;
+	private Class factory;
+
+	public void postInstantiate(
+			final String entityName,
+			final Class persistentClass,
+	        final Set interfaces,
+			final Method getIdentifierMethod,
+	        final Method setIdentifierMethod,
+			AbstractComponentType componentIdType) throws HibernateException {
+		this.entityName = entityName;
+		this.persistentClass = persistentClass;
+		this.interfaces = (Class[]) interfaces.toArray(NO_CLASSES);
+		this.getIdentifierMethod = getIdentifierMethod;
+		this.setIdentifierMethod = setIdentifierMethod;
+		this.componentIdType = componentIdType;
+		factory = JavassistLazyInitializer.getProxyFactory( persistentClass, this.interfaces );
+	}
+
+	public HibernateProxy getProxy(
+			Serializable id,
+	        SessionImplementor session) throws HibernateException {
+		return JavassistLazyInitializer.getProxy(
+				factory,
+		        entityName,
+				persistentClass,
+		        interfaces,
+		        getIdentifierMethod,
+				setIdentifierMethod,
+		        componentIdType,
+		        id,
+		        session
+		);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/javassist/SerializableProxy.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/javassist/SerializableProxy.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/proxy/pojo/javassist/SerializableProxy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,74 @@
+package org.hibernate.proxy.pojo.javassist;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+import org.hibernate.HibernateException;
+import org.hibernate.type.AbstractComponentType;
+
+/**
+ * Serializable placeholder for Javassist proxies
+ */
+public final class SerializableProxy implements Serializable {
+
+	private String entityName;
+	private Class persistentClass;
+	private Class[] interfaces;
+	private Serializable id;
+	private Class getIdentifierMethodClass;
+	private Class setIdentifierMethodClass;
+	private String getIdentifierMethodName;
+	private String setIdentifierMethodName;
+	private Class[] setIdentifierMethodParams;
+	private AbstractComponentType componentIdType;
+
+	public SerializableProxy() {}
+
+	public SerializableProxy(
+		final String entityName,
+	    final Class persistentClass,
+	    final Class[] interfaces,
+	    final Serializable id,
+	    final Method getIdentifierMethod,
+	    final Method setIdentifierMethod,
+	    AbstractComponentType componentIdType
+	) {
+		this.entityName = entityName;
+		this.persistentClass = persistentClass;
+		this.interfaces = interfaces;
+		this.id = id;
+		if (getIdentifierMethod!=null) {
+			getIdentifierMethodClass = getIdentifierMethod.getDeclaringClass();
+			getIdentifierMethodName = getIdentifierMethod.getName();
+		}
+		if (setIdentifierMethod!=null) {
+			setIdentifierMethodClass = setIdentifierMethod.getDeclaringClass();
+			setIdentifierMethodName = setIdentifierMethod.getName();
+			setIdentifierMethodParams = setIdentifierMethod.getParameterTypes();
+		}
+		this.componentIdType = componentIdType;
+	}
+
+	private Object readResolve() {
+		try {
+			return JavassistLazyInitializer.getProxy(
+				entityName,
+				persistentClass,
+				interfaces,
+				getIdentifierMethodName==null ?
+					null :
+					getIdentifierMethodClass.getDeclaredMethod(getIdentifierMethodName, null),
+				setIdentifierMethodName==null ?
+					null :
+					setIdentifierMethodClass.getDeclaredMethod(setIdentifierMethodName, setIdentifierMethodParams),
+					componentIdType,
+				id,
+				null
+			);
+		}
+		catch (NoSuchMethodException nsme) {
+			throw new HibernateException("could not create proxy for entity: " + entityName, nsme);
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/HibernatePermission.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/secure/HibernatePermission.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/secure/HibernatePermission.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: HibernatePermission.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.secure;
+
+import java.security.Permission;
+
+/**
+ * @author Gavin King
+ */
+public class HibernatePermission extends Permission {
+	
+	public static final String INSERT = "insert";
+	public static final String UPDATE = "update";
+	public static final String DELETE = "delete";
+	public static final String READ = "read";
+	public static final String ANY = "*";
+	
+	private final String actions;
+
+	public HibernatePermission(String entityName, String actions) {
+		super(entityName);
+		this.actions = actions;
+	}
+
+	public boolean implies(Permission permission) {
+		//TODO!
+		return ( "*".equals( getName() ) || getName().equals( permission.getName() ) ) &&
+			( "*".equals(actions) || actions.indexOf( permission.getActions() ) >= 0 );
+	}
+
+	public boolean equals(Object obj) {
+		if ( !(obj instanceof HibernatePermission) ) return false;
+		HibernatePermission permission = (HibernatePermission) obj;
+		return permission.getName().equals( getName() ) && 
+			permission.getActions().equals(actions);
+	}
+
+	public int hashCode() {
+		return getName().hashCode() * 37 + actions.hashCode();
+	}
+
+	public String getActions() {
+		return actions;
+	}
+	
+	public String toString() {
+		return "HibernatePermission(" + getName() + ':' + actions + ')';
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/HibernatePermission.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCConfiguration.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCConfiguration.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCConfiguration.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+// $Id: JACCConfiguration.java 7592 2005-07-21 04:56:17Z oneovthafew $
+package org.hibernate.secure;
+
+import java.util.StringTokenizer;
+
+import javax.security.jacc.EJBMethodPermission;
+import javax.security.jacc.PolicyConfiguration;
+import javax.security.jacc.PolicyConfigurationFactory;
+import javax.security.jacc.PolicyContextException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+
+/**
+ * Adds Hibernate permissions to roles via JACC
+ * 
+ * @author Gavin King
+ */
+public class JACCConfiguration {
+
+	private static final Log log = LogFactory.getLog( JACCConfiguration.class );
+
+	private final PolicyConfiguration policyConfiguration;
+
+	public JACCConfiguration(String contextId) throws HibernateException {
+		try {
+			policyConfiguration = PolicyConfigurationFactory
+					.getPolicyConfigurationFactory()
+					.getPolicyConfiguration( contextId, false );
+		}
+		catch (ClassNotFoundException cnfe) {
+			throw new HibernateException( "JACC provider class not found", cnfe );
+		}
+		catch (PolicyContextException pce) {
+			throw new HibernateException( "policy context exception occurred", pce );
+		}
+	}
+
+	public void addPermission(String role, String entityName, String action) {
+
+		if ( action.equals( "*" ) ) {
+			action = "insert,read,update,delete";
+		}
+
+		StringTokenizer tok = new StringTokenizer( action, "," );
+
+		while ( tok.hasMoreTokens() ) {
+			String methodName = tok.nextToken().trim();
+			EJBMethodPermission permission = new EJBMethodPermission( 
+					entityName, 
+					methodName, 
+					null, // interfaces
+					null // arguments
+				);
+
+			if ( log.isDebugEnabled() ) {
+				log.debug( "adding permission to role " + role + ": " + permission );
+			}
+			try {
+				policyConfiguration.addToRole( role, permission );
+			}
+			catch (PolicyContextException pce) {
+				throw new HibernateException( "policy context exception occurred", pce );
+			}
+		}
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCConfiguration.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPermissions.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPermissions.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPermissions.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,123 @@
+//$Id: JACCPermissions.java 8661 2005-11-25 12:00:22Z epbernard $
+package org.hibernate.secure;
+
+import java.lang.reflect.UndeclaredThrowableException;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.Policy;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
+import java.util.Set;
+import javax.security.auth.Subject;
+import javax.security.jacc.EJBMethodPermission;
+import javax.security.jacc.PolicyContext;
+import javax.security.jacc.PolicyContextException;
+
+
+/**
+ * Copied from JBoss org.jboss.ejb3.security.JaccHelper and org.jboss.ejb3.security.SecurityActions
+ *
+ * @author <a href="mailto:kabir.khan at jboss.org">Kabir Khan</a>
+ */
+public class JACCPermissions {
+
+	public static void checkPermission(Class clazz, String contextID, EJBMethodPermission methodPerm)
+			throws SecurityException {
+		CodeSource ejbCS = clazz.getProtectionDomain().getCodeSource();
+
+		try {
+			setContextID( contextID );
+
+			Policy policy = Policy.getPolicy();
+			// Get the caller
+			Subject caller = getContextSubject();
+
+			Principal[] principals = null;
+			if ( caller != null ) {
+				// Get the caller principals
+				Set principalsSet = caller.getPrincipals();
+				principals = new Principal[ principalsSet.size() ];
+				principalsSet.toArray( principals );
+			}
+
+			ProtectionDomain pd = new ProtectionDomain( ejbCS, null, null, principals );
+			if ( policy.implies( pd, methodPerm ) == false ) {
+				String msg = "Denied: " + methodPerm + ", caller=" + caller;
+				SecurityException e = new SecurityException( msg );
+				throw e;
+			}
+		}
+		catch (PolicyContextException e) {
+			throw new RuntimeException( e );
+		}
+	}
+
+	interface PolicyContextActions {
+		/**
+		 * The JACC PolicyContext key for the current Subject
+		 */
+		static final String SUBJECT_CONTEXT_KEY = "javax.security.auth.Subject.container";
+		PolicyContextActions PRIVILEGED = new PolicyContextActions() {
+			private final PrivilegedExceptionAction exAction = new PrivilegedExceptionAction() {
+				public Object run() throws Exception {
+					return (Subject) PolicyContext.getContext( SUBJECT_CONTEXT_KEY );
+				}
+			};
+
+			public Subject getContextSubject() throws PolicyContextException {
+				try {
+					return (Subject) AccessController.doPrivileged( exAction );
+				}
+				catch (PrivilegedActionException e) {
+					Exception ex = e.getException();
+					if ( ex instanceof PolicyContextException ) {
+						throw (PolicyContextException) ex;
+					}
+					else {
+						throw new UndeclaredThrowableException( ex );
+					}
+				}
+			}
+		};
+
+		PolicyContextActions NON_PRIVILEGED = new PolicyContextActions() {
+			public Subject getContextSubject() throws PolicyContextException {
+				return (Subject) PolicyContext.getContext( SUBJECT_CONTEXT_KEY );
+			}
+		};
+
+		Subject getContextSubject() throws PolicyContextException;
+	}
+
+	static Subject getContextSubject() throws PolicyContextException {
+		if ( System.getSecurityManager() == null ) {
+			return PolicyContextActions.NON_PRIVILEGED.getContextSubject();
+		}
+		else {
+			return PolicyContextActions.PRIVILEGED.getContextSubject();
+		}
+	}
+
+	private static class SetContextID implements PrivilegedAction {
+		String contextID;
+
+		SetContextID(String contextID) {
+			this.contextID = contextID;
+		}
+
+		public Object run() {
+			String previousID = PolicyContext.getContextID();
+			PolicyContext.setContextID( contextID );
+			return previousID;
+		}
+	}
+
+	static String setContextID(String contextID) {
+		PrivilegedAction action = new SetContextID( contextID );
+		String previousID = (String) AccessController.doPrivileged( action );
+		return previousID;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreDeleteEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreDeleteEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreDeleteEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: JACCPreDeleteEventListener.java 8702 2005-11-29 18:34:29Z kabkhan $
+package org.hibernate.secure;
+
+import javax.security.jacc.EJBMethodPermission;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.event.Initializable;
+import org.hibernate.event.PreDeleteEvent;
+import org.hibernate.event.PreDeleteEventListener;
+
+/**
+ * Check security before any deletion
+ *
+ * @author <a href="mailto:kabir.khan at jboss.org">Kabir Khan</a>
+ */
+public class JACCPreDeleteEventListener implements PreDeleteEventListener, Initializable, JACCSecurityListener {
+	private String contextID;
+
+	public boolean onPreDelete(PreDeleteEvent event) {
+
+		EJBMethodPermission deletePermission = new EJBMethodPermission(
+				event.getPersister().getEntityName(),
+				HibernatePermission.DELETE,
+				null,
+				null
+		);
+
+		JACCPermissions.checkPermission( event.getEntity().getClass(), contextID, deletePermission );
+
+		return false;
+	}
+
+   public void initialize(Configuration cfg){
+      contextID = cfg.getProperty(Environment.JACC_CONTEXTID);
+   }
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreDeleteEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreInsertEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreInsertEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreInsertEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: JACCPreInsertEventListener.java 8702 2005-11-29 18:34:29Z kabkhan $
+package org.hibernate.secure;
+
+import javax.security.jacc.EJBMethodPermission;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.event.Initializable;
+import org.hibernate.event.PreInsertEvent;
+import org.hibernate.event.PreInsertEventListener;
+
+/**
+ * Check security before an insertion
+ *
+ * @author <a href="mailto:kabir.khan at jboss.org">Kabir Khan</a>
+ */
+public class JACCPreInsertEventListener implements PreInsertEventListener, Initializable, JACCSecurityListener {
+	private String contextID;
+
+	public boolean onPreInsert(PreInsertEvent event) {
+
+		EJBMethodPermission insertPermission = new EJBMethodPermission(
+				event.getPersister().getEntityName(),
+				HibernatePermission.INSERT,
+				null,
+				null
+		);
+
+		JACCPermissions.checkPermission( event.getEntity().getClass(), contextID, insertPermission );
+
+		return false;
+	}
+
+
+   public void initialize(Configuration cfg){
+      contextID = cfg.getProperty(Environment.JACC_CONTEXTID);
+   }
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreInsertEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreLoadEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreLoadEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreLoadEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+// $Id: JACCPreLoadEventListener.java 8702 2005-11-29 18:34:29Z kabkhan $
+package org.hibernate.secure;
+
+import javax.security.jacc.EJBMethodPermission;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.event.Initializable;
+import org.hibernate.event.PreLoadEvent;
+import org.hibernate.event.PreLoadEventListener;
+
+/**
+ * Check security before any load
+ *
+ * @author <a href="mailto:kabir.khan at jboss.org">Kabir Khan</a>
+ * @version $Revision: 8702 $
+ */
+public class JACCPreLoadEventListener implements PreLoadEventListener, Initializable, JACCSecurityListener {
+	private String contextID;
+
+	public void onPreLoad(PreLoadEvent event) {
+
+		EJBMethodPermission loadPermission = new EJBMethodPermission(
+				event.getPersister().getEntityName(),
+				HibernatePermission.READ,
+				null,
+				null
+		);
+
+		JACCPermissions.checkPermission( event.getEntity().getClass(), contextID, loadPermission );
+
+	}
+
+
+   public void initialize(Configuration cfg){
+      contextID = cfg.getProperty(Environment.JACC_CONTEXTID);
+   }
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreLoadEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreUpdateEventListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreUpdateEventListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreUpdateEventListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+//$Id: JACCPreUpdateEventListener.java 8702 2005-11-29 18:34:29Z kabkhan $
+package org.hibernate.secure;
+
+import javax.security.jacc.EJBMethodPermission;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.event.Initializable;
+import org.hibernate.event.PreUpdateEvent;
+import org.hibernate.event.PreUpdateEventListener;
+
+/**
+ * Check security before any update
+ *
+ * @author <a href="mailto:kabir.khan at jboss.org">Kabir Khan</a>
+ * @version $Revision: 8702 $
+ */
+public class JACCPreUpdateEventListener implements PreUpdateEventListener, Initializable, JACCSecurityListener {
+	private String contextID;
+
+	public boolean onPreUpdate(PreUpdateEvent event) {
+
+		EJBMethodPermission updatePermission = new EJBMethodPermission(
+				event.getPersister().getEntityName(),
+				HibernatePermission.UPDATE,
+				null,
+				null
+		);
+
+		JACCPermissions.checkPermission( event.getEntity().getClass(), contextID, updatePermission );
+
+		return false;
+	}
+
+
+   public void initialize(Configuration cfg){
+      contextID = cfg.getProperty(Environment.JACC_CONTEXTID);
+   }
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCPreUpdateEventListener.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCSecurityListener.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCSecurityListener.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/secure/JACCSecurityListener.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,11 @@
+package org.hibernate.secure;
+
+/**
+ * Marker interface for JACC event listeners
+ * 
+ * @author <a href="kabir.khan at jboss.com">Kabir Khan</a>
+ * @version $Revision: 8702 $
+ */
+public interface JACCSecurityListener{
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/secure/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/secure/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>
+	Declarative security for CRUD operations on entities.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/secure/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ANSICaseFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ANSICaseFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ANSICaseFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+//$Id: ANSICaseFragment.java 4851 2004-12-02 05:09:49Z oneovthafew $
+package org.hibernate.sql;
+
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ An ANSI SQL CASE expression.
+ <br>
+ <code>case when ... then ... end as ...</code>
+ <br>
+ @author Gavin King, Simon Harris
+ */
+public class ANSICaseFragment extends CaseFragment {
+
+	public String toFragmentString() {
+		
+		StringBuffer buf = new StringBuffer( cases.size() * 15 + 10 )
+			.append("case");
+
+		Iterator iter = cases.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			buf.append(" when ")
+				.append( me.getKey() )
+				.append(" is not null then ")
+				.append( me.getValue() );
+		}
+		
+		buf.append(" end");
+
+		if (returnColumnName!=null) {
+			buf.append(" as ")
+				.append(returnColumnName);
+		}
+
+		return buf.toString();
+	}
+	
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ANSIJoinFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ANSIJoinFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ANSIJoinFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,117 @@
+//$Id: ANSIJoinFragment.java 4886 2004-12-05 15:04:21Z pgmjsd $
+package org.hibernate.sql;
+
+import org.hibernate.AssertionFailure;
+
+/**
+ * An ANSI-style join
+ *
+ * @author Gavin King
+ */
+public class ANSIJoinFragment extends JoinFragment {
+
+	private StringBuffer buffer = new StringBuffer();
+	private StringBuffer conditions = new StringBuffer();
+
+	public void addJoin(String tableName, String alias, String[] fkColumns, String[] pkColumns, int joinType) {
+		addJoin(tableName, alias, fkColumns, pkColumns, joinType, null);
+	}
+
+	public void addJoin(String tableName, String alias, String[] fkColumns, String[] pkColumns, int joinType, String on) {
+		String joinString;
+		switch (joinType) {
+			case INNER_JOIN:
+				joinString = " inner join ";
+				break;
+			case LEFT_OUTER_JOIN:
+				joinString = " left outer join ";
+				break;
+			case RIGHT_OUTER_JOIN:
+				joinString = " right outer join ";
+				break;
+			case FULL_JOIN:
+				joinString = " full outer join ";
+				break;
+			default:
+				throw new AssertionFailure("undefined join type");
+		}
+
+		buffer.append(joinString)
+			.append(tableName)
+			.append(' ')
+			.append(alias)
+			.append(" on ");
+
+
+		for ( int j=0; j<fkColumns.length; j++) {
+			/*if ( fkColumns[j].indexOf('.')<1 ) {
+				throw new AssertionFailure("missing alias");
+			}*/
+			buffer.append( fkColumns[j] )
+				.append('=')
+				.append(alias)
+				.append('.')
+				.append( pkColumns[j] );
+			if ( j<fkColumns.length-1 ) buffer.append(" and ");
+		}
+
+		addCondition(buffer, on);
+
+	}
+
+	public String toFromFragmentString() {
+		return buffer.toString();
+	}
+
+	public String toWhereFragmentString() {
+		return conditions.toString();
+	}
+
+	public void addJoins(String fromFragment, String whereFragment) {
+		buffer.append(fromFragment);
+		//where fragment must be empty!
+	}
+
+	public JoinFragment copy() {
+		ANSIJoinFragment copy = new ANSIJoinFragment();
+		copy.buffer = new StringBuffer( buffer.toString() );
+		return copy;
+	}
+
+	public void addCondition(String alias, String[] columns, String condition) {
+		for ( int i=0; i<columns.length; i++ ) {
+			conditions.append(" and ")
+				.append(alias)
+				.append('.')
+				.append( columns[i] )
+				.append(condition);
+		}
+	}
+
+	public void addCrossJoin(String tableName, String alias) {
+		buffer.append(", ")
+			.append(tableName)
+			.append(' ')
+			.append(alias);
+	}
+
+	public void addCondition(String alias, String[] fkColumns, String[] pkColumns) {
+		throw new UnsupportedOperationException();
+
+	}
+
+	public boolean addCondition(String condition) {
+		return addCondition(conditions, condition);
+	}
+
+	public void addFromFragmentString(String fromFragmentString) {
+		buffer.append(fromFragmentString);
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Alias.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Alias.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Alias.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,90 @@
+//$Id: Alias.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.sql;
+
+import org.hibernate.dialect.Dialect;
+
+/**
+ * An alias generator for SQL identifiers
+ * @author Gavin King
+ */
+public final class Alias {
+
+	private final int length;
+	private final String suffix;
+
+	/**
+	 * Constructor for Alias.
+	 */
+	public Alias(int length, String suffix) {
+		super();
+		this.length = (suffix==null) ? length : length - suffix.length();
+		this.suffix = suffix;
+	}
+
+	/**
+	 * Constructor for Alias.
+	 */
+	public Alias(String suffix) {
+		super();
+		this.length = Integer.MAX_VALUE;
+		this.suffix = suffix;
+	}
+
+	public String toAliasString(String sqlIdentifier) {
+		char begin = sqlIdentifier.charAt(0);
+		int quoteType = Dialect.QUOTE.indexOf(begin);
+		String unquoted = getUnquotedAliasString(sqlIdentifier, quoteType);
+		if ( quoteType >= 0 ) {
+			char endQuote = Dialect.CLOSED_QUOTE.charAt(quoteType);
+			return begin + unquoted + endQuote;
+		}
+		else {
+			return unquoted;
+		}
+	}
+
+	public String toUnquotedAliasString(String sqlIdentifier) {
+		return getUnquotedAliasString(sqlIdentifier);
+	}
+
+	private String getUnquotedAliasString(String sqlIdentifier) {
+		char begin = sqlIdentifier.charAt(0);
+		int quoteType = Dialect.QUOTE.indexOf(begin);
+		return getUnquotedAliasString(sqlIdentifier, quoteType);
+	}
+
+	private String getUnquotedAliasString(String sqlIdentifier, int quoteType) {
+		String unquoted = sqlIdentifier;
+		if ( quoteType >= 0 ) {
+			//if the identifier is quoted, remove the quotes
+			unquoted = unquoted.substring( 1, unquoted.length()-1 );
+		}
+		if ( unquoted.length() > length ) {
+			//truncate the identifier to the max alias length, less the suffix length
+			unquoted = unquoted.substring(0, length);
+		}
+		if ( suffix == null ) {
+			return unquoted;
+		}
+		else {
+			return unquoted + suffix;
+		}
+	}
+
+	public String[] toUnquotedAliasStrings(String[] sqlIdentifiers) {
+		String[] aliases = new String[ sqlIdentifiers.length ];
+		for ( int i=0; i<sqlIdentifiers.length; i++ ) {
+			aliases[i] = toUnquotedAliasString(sqlIdentifiers[i]);
+		}
+		return aliases;
+	}
+
+	public String[] toAliasStrings(String[] sqlIdentifiers) {
+		String[] aliases = new String[ sqlIdentifiers.length ];
+		for ( int i=0; i<sqlIdentifiers.length; i++ ) {
+			aliases[i] = toAliasString(sqlIdentifiers[i]);
+		}
+		return aliases;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/CacheJoinFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/CacheJoinFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/CacheJoinFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: $
+package org.hibernate.sql;
+
+import org.hibernate.AssertionFailure;
+
+/**
+ * A Cach&eacute; dialect join.  Differs from ANSI only in that full outer join
+ * is not supported.
+ *
+ * @author Jeff Miller
+ * @author Jonathan Levinson
+ */
+public class CacheJoinFragment extends ANSIJoinFragment {
+
+	public void addJoin(String tableName, String alias, String[] fkColumns, String[] pkColumns, int joinType, String on) {
+		if ( joinType == FULL_JOIN ) {
+			throw new AssertionFailure( "Cache does not support full outer joins" );
+		}
+		super.addJoin( tableName, alias, fkColumns, pkColumns, joinType, on );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/CaseFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/CaseFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/CaseFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: CaseFragment.java 4070 2004-07-23 05:30:26Z steveebersole $
+package org.hibernate.sql;
+
+import java.util.Map;
+
+import org.hibernate.util.StringHelper;
+
+import org.apache.commons.collections.SequencedHashMap;
+
+/**
+ * Abstract SQL case fragment renderer
+ *
+ * @author Gavin King, Simon Harris
+ */
+public abstract class CaseFragment {
+	public abstract String toFragmentString();
+
+	protected String returnColumnName;
+
+	protected Map cases = new SequencedHashMap();
+
+	public CaseFragment setReturnColumnName(String returnColumnName) {
+		this.returnColumnName = returnColumnName;
+		return this;
+	}
+
+	public CaseFragment setReturnColumnName(String returnColumnName, String suffix) {
+		return setReturnColumnName( new Alias(suffix).toAliasString(returnColumnName) );
+	}
+
+	public CaseFragment addWhenColumnNotNull(String alias, String columnName, String value) {
+		cases.put( StringHelper.qualify(alias, columnName), value );
+		return this;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ConditionFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ConditionFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ConditionFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,58 @@
+//$Id: ConditionFragment.java 4218 2004-08-10 05:06:14Z oneovthafew $
+package org.hibernate.sql;
+
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * @author Gavin King
+ */
+public class ConditionFragment {
+	private String tableAlias;
+	private String[] lhs;
+	private String[] rhs;
+	private String op = "=";
+
+	/**
+	 * Sets the op.
+	 * @param op The op to set
+	 */
+	public ConditionFragment setOp(String op) {
+		this.op = op;
+		return this;
+	}
+
+	/**
+	 * Sets the tableAlias.
+	 * @param tableAlias The tableAlias to set
+	 */
+	public ConditionFragment setTableAlias(String tableAlias) {
+		this.tableAlias = tableAlias;
+		return this;
+	}
+
+	public ConditionFragment setCondition(String[] lhs, String[] rhs) {
+		this.lhs = lhs;
+		this.rhs = rhs;
+		return this;
+	}
+
+	public ConditionFragment setCondition(String[] lhs, String rhs) {
+		this.lhs = lhs;
+		this.rhs = ArrayHelper.fillArray(rhs, lhs.length);
+		return this;
+	}
+
+	public String toFragmentString() {
+		StringBuffer buf = new StringBuffer( lhs.length * 10 );
+		for ( int i=0; i<lhs.length; i++ ) {
+			buf.append(tableAlias)
+				.append('.')
+				.append( lhs[i] )
+				.append(op)
+				.append( rhs[i] );
+			if (i<lhs.length-1) buf.append(" and ");
+		}
+		return buf.toString();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/DecodeCaseFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/DecodeCaseFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/DecodeCaseFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+//$Id: DecodeCaseFragment.java 4851 2004-12-02 05:09:49Z oneovthafew $
+package org.hibernate.sql;
+
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ An Oracle-style DECODE function.
+ <br>
+ <code>decode(pkvalue, key1, 1, key2, 2, ..., 0)</code>
+ <br>
+
+ @author Simon Harris
+ */
+public class DecodeCaseFragment extends CaseFragment {
+
+	public String toFragmentString() {
+		
+		StringBuffer buf = new StringBuffer( cases.size() * 15 + 10 )
+			.append("decode(");
+
+		Iterator iter = cases.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+
+			if ( iter.hasNext() ) {
+				buf.append(", ")
+					.append( me.getKey() )
+					.append(", ")
+					.append( me.getValue() );
+			}
+			else {
+				buf.insert( 7, me.getKey() )
+					.append(", ")
+					.append( me.getValue() );
+			}
+		}
+
+		buf.append(')');
+		
+		if (returnColumnName!=null) {
+			buf.append(" as ")
+				.append(returnColumnName);
+		}
+		
+		return buf.toString();
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Delete.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Delete.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Delete.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,84 @@
+//$Id: Delete.java 10226 2006-08-05 04:27:55Z steve.ebersole at jboss.com $
+package org.hibernate.sql;
+
+import org.hibernate.util.StringHelper;
+
+/**
+ * An SQL <tt>DELETE</tt> statement
+ *
+ * @author Gavin King
+ */
+public class Delete {
+
+	private String tableName;
+	private String[] primaryKeyColumnNames;
+	private String versionColumnName;
+	private String where;
+
+	private String comment;
+	public Delete setComment(String comment) {
+		this.comment = comment;
+		return this;
+	}
+
+	public Delete setTableName(String tableName) {
+		this.tableName = tableName;
+		return this;
+	}
+
+	public String toStatementString() {
+		StringBuffer buf = new StringBuffer( tableName.length() + 10 );
+		if ( comment!=null ) {
+			buf.append( "/* " ).append(comment).append( " */ " );
+		}
+		buf.append( "delete from " ).append(tableName);
+		if ( where != null || primaryKeyColumnNames != null || versionColumnName != null ) {
+			buf.append( " where " );
+		}
+		boolean conditionsAppended = false;
+		if ( primaryKeyColumnNames != null ) {
+			buf.append( StringHelper.join( "=? and ", primaryKeyColumnNames ) ).append( "=?" );
+			conditionsAppended = true;
+		}
+		if ( where!=null ) {
+			if ( conditionsAppended ) {
+				buf.append( " and " );
+			}
+			buf.append( where );
+			conditionsAppended = true;
+		}
+		if ( versionColumnName!=null ) {
+			if ( conditionsAppended ) {
+				buf.append( " and " );
+			}
+			buf.append( versionColumnName ).append( "=?" );
+		}
+		return buf.toString();
+	}
+
+	public Delete setWhere(String where) {
+		this.where=where;
+		return this;
+	}
+
+	public Delete addWhereFragment(String fragment) {
+		if ( where == null ) {
+			where = fragment;
+		}
+		else {
+			where += ( " and " + fragment );
+		}
+		return this;
+	}
+
+	public Delete setPrimaryKeyColumnNames(String[] primaryKeyColumnNames) {
+		this.primaryKeyColumnNames = primaryKeyColumnNames;
+		return this;
+	}
+
+	public Delete setVersionColumnName(String versionColumnName) {
+		this.versionColumnName = versionColumnName;
+		return this;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/DerbyCaseFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/DerbyCaseFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/DerbyCaseFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+//$Id: DerbyCaseFragment.java 4631 2004-09-29 12:29:05Z pgmjsd $
+package org.hibernate.sql;
+
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * @author Simon Johnston
+ * @see org.hibernate.dialect.DerbyDialect
+ */
+public class DerbyCaseFragment extends CaseFragment {
+
+	/**
+	 * From http://www.jroller.com/comments/kenlars99/Weblog/cloudscape_soon_to_be_derby
+	 * <p/>
+	 * The problem we had, was when Hibernate does a select with a case statement, for joined subclasses.
+	 * This seems to be because there was no else at the end of the case statement (other dbs seem to not mind).
+	 */
+	public String toFragmentString() {
+		StringBuffer buf = new StringBuffer( cases.size() * 15 + 10 );
+		buf.append( "case" ); 								//$NON-NLS-1
+		Iterator iter = cases.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = ( Map.Entry ) iter.next();
+			buf.append( " when " )//$NON-NLS-1
+					.append( me.getKey() )
+					.append( " is not null then " )//$NON-NLS-1
+					.append( me.getValue() );
+		}
+		// null is not considered the same type as Integer.
+		buf.append( " else -1" );								//$NON-NLS-1
+		buf.append( " end" );									//$NON-NLS-1
+		if ( returnColumnName != null ) {
+			buf.append( " as " )//$NON-NLS-1
+					.append( returnColumnName );
+		}
+		return buf.toString();
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/DerbyCaseFragment.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/DisjunctionFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/DisjunctionFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/DisjunctionFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+//$Id: DisjunctionFragment.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.sql;
+
+/**
+ * A disjunctive string of conditions
+ * @author Gavin King
+ */
+public class DisjunctionFragment {
+
+	private StringBuffer buffer = new StringBuffer();
+
+	public DisjunctionFragment addCondition(ConditionFragment fragment) {
+		if ( buffer.length()>0 ) buffer.append(" or ");
+		buffer.append("(")
+			.append( fragment.toFragmentString() )
+			.append(")");
+		return this;
+	}
+
+	public String toFragmentString() {
+		return buffer.toString();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ForUpdateFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ForUpdateFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/ForUpdateFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,79 @@
+//$Id: ForUpdateFragment.java 11320 2007-03-20 11:50:53Z steve.ebersole at jboss.com $
+package org.hibernate.sql;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.LockMode;
+import org.hibernate.QueryException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.util.StringHelper;
+
+/**
+ * @author Gavin King
+ */
+public class ForUpdateFragment {
+	private final StringBuffer aliases = new StringBuffer();
+	private boolean isNowaitEnabled;
+	private final Dialect dialect;
+
+	public ForUpdateFragment(Dialect dialect) {
+		this.dialect = dialect;
+	}
+
+	public ForUpdateFragment(Dialect dialect, Map lockModes, Map keyColumnNames) throws QueryException {
+		this( dialect );
+		LockMode upgradeType = null;
+		Iterator iter = lockModes.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			final Map.Entry me = ( Map.Entry ) iter.next();
+			final LockMode lockMode = ( LockMode ) me.getValue();
+			if ( LockMode.READ.lessThan( lockMode ) ) {
+				final String tableAlias = ( String ) me.getKey();
+				if ( dialect.forUpdateOfColumns() ) {
+					String[] keyColumns = ( String[] ) keyColumnNames.get( tableAlias ); //use the id column alias
+					if ( keyColumns == null ) {
+						throw new IllegalArgumentException( "alias not found: " + tableAlias );
+					}
+					keyColumns = StringHelper.qualify( tableAlias, keyColumns );
+					for ( int i = 0; i < keyColumns.length; i++ ) {
+						addTableAlias( keyColumns[i] );
+					}
+				}
+				else {
+					addTableAlias( tableAlias );
+				}
+				if ( upgradeType != null && lockMode != upgradeType ) {
+					throw new QueryException( "mixed LockModes" );
+				}
+				upgradeType = lockMode;
+			}
+		}
+
+		if ( upgradeType == LockMode.UPGRADE_NOWAIT ) {
+			setNowaitEnabled( true );
+		}
+	}
+
+	public ForUpdateFragment addTableAlias(String alias) {
+		if ( aliases.length() > 0 ) {
+			aliases.append( ", " );
+		}
+		aliases.append( alias );
+		return this;
+	}
+
+	public String toFragmentString() {
+		if ( aliases.length() == 0 ) {
+			return "";
+		}
+		return isNowaitEnabled ?
+				dialect.getForUpdateNowaitString( aliases.toString() ) :
+				dialect.getForUpdateString( aliases.toString() );
+	}
+
+	public ForUpdateFragment setNowaitEnabled(boolean nowait) {
+		isNowaitEnabled = nowait;
+		return this;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/HSQLCaseFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/HSQLCaseFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/HSQLCaseFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+//$Id: HSQLCaseFragment.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.sql;
+
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * The HSQL CASEWHEN function.
+ * <br>
+ * <code>casewhen(..., ..., ...) as ...</code>
+ * <br>
+ * @author Wolfgang Jung
+ */
+public class HSQLCaseFragment extends CaseFragment {
+
+	public String toFragmentString() {
+		StringBuffer buf = new StringBuffer( cases.size() * 15 + 10 );
+		StringBuffer buf2 = new StringBuffer( cases.size() );
+
+		Iterator iter = cases.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			buf.append(" casewhen(")
+				.append( me.getKey() )
+				.append(" is not null")
+				.append(", ")
+				.append( me.getValue() )
+				.append(", ");
+			buf2.append(")");
+		}
+
+		buf.append("-1"); //null caused some problems
+		buf.append( buf2.toString() );
+		if ( returnColumnName!=null ) {
+			buf.append(" as ")
+				.append(returnColumnName);
+		}
+		return buf.toString();
+	}
+}
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/InFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/InFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/InFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,94 @@
+//$Id: InFragment.java 7022 2005-06-05 06:36:26Z oneovthafew $
+package org.hibernate.sql;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.util.StringHelper;
+
+/**
+ * An SQL IN expression.
+ * <br>
+ * <code>... in(...)</code>
+ * <br>
+ * @author Gavin King
+ */
+public class InFragment {
+
+	public static final String NULL = "null";
+	public static final String NOT_NULL = "not null";
+
+	private String columnName;
+	private List values = new ArrayList();
+
+	/**
+	 * @param value, an SQL literal, NULL, or NOT_NULL
+	 */
+	public InFragment addValue(Object value) {
+		values.add(value);
+		return this;
+	}
+
+	public InFragment setColumn(String columnName) {
+		this.columnName = columnName;
+		return this;
+	}
+
+	public InFragment setColumn(String alias, String columnName) {
+		this.columnName = StringHelper.qualify(alias, columnName);
+		return setColumn(this.columnName);
+	}
+
+	public InFragment setFormula(String alias, String formulaTemplate) {
+		this.columnName = StringHelper.replace(formulaTemplate, Template.TEMPLATE, alias);
+		return setColumn(this.columnName);
+	}
+
+	public String toFragmentString() {
+		if ( values.size()==0 ) return "1=2";
+		StringBuffer buf = new StringBuffer( values.size() * 5 );
+		buf.append(columnName);
+		//following doesn't handle (null, not null) but unnecessary
+		//since this would mean all rows
+		if ( values.size()>1 ) {
+			boolean allowNull = false;
+			buf.append(" in (");
+			Iterator iter = values.iterator();
+			while ( iter.hasNext() ) {
+				Object value = iter.next();
+				if ( NULL.equals(value) ) {
+					allowNull = true;
+				}
+				else if ( NOT_NULL.equals(value) ) {
+					throw new IllegalArgumentException("not null makes no sense for in expression");
+				}
+				else {
+					buf.append(value);
+					buf.append(", ");
+				}
+			}
+			buf.setLength( buf.length()-2 );
+			buf.append(')');
+			if (allowNull) {
+				buf.insert(0, " is null or ")
+					.insert(0, columnName)
+					.insert(0, '(')
+					.append(')');
+			}
+		}
+		else {
+			Object value = values.iterator().next();
+			if ( NULL.equals(value) ) {
+				buf.append(" is null");
+			}
+			else if ( NOT_NULL.equals(value) ) {
+				buf.append(" is not null");
+			}
+			else {
+				buf.append("=").append(value);
+			}
+		}
+		return buf.toString();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Insert.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Insert.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Insert.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,108 @@
+//$Id: Insert.java 9681 2006-03-24 18:10:04Z steve.ebersole at jboss.com $
+package org.hibernate.sql;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.commons.collections.SequencedHashMap;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.type.LiteralType;
+
+/**
+ * An SQL <tt>INSERT</tt> statement
+ *
+ * @author Gavin King
+ */
+public class Insert {
+	private Dialect dialect;
+	private String tableName;
+	private String comment;
+	private Map columns = new SequencedHashMap();
+
+	public Insert(Dialect dialect) {
+		this.dialect = dialect;
+	}
+
+	protected Dialect getDialect() {
+		return dialect;
+	}
+
+	public Insert setComment(String comment) {
+		this.comment = comment;
+		return this;
+	}
+
+	public Insert addColumn(String columnName) {
+		return addColumn(columnName, "?");
+	}
+
+	public Insert addColumns(String[] columnNames) {
+		for ( int i=0; i<columnNames.length; i++ ) {
+			addColumn( columnNames[i] );
+		}
+		return this;
+	}
+
+	public Insert addColumns(String[] columnNames, boolean[] insertable) {
+		for ( int i=0; i<columnNames.length; i++ ) {
+			if ( insertable[i] ) {
+				addColumn( columnNames[i] );
+			}
+		}
+		return this;
+	}
+
+	public Insert addColumn(String columnName, String value) {
+		columns.put(columnName, value);
+		return this;
+	}
+
+	public Insert addColumn(String columnName, Object value, LiteralType type) throws Exception {
+		return addColumn( columnName, type.objectToSQLString(value, dialect) );
+	}
+
+	public Insert addIdentityColumn(String columnName) {
+		String value = dialect.getIdentityInsertString();
+		if ( value != null ) {
+			addColumn( columnName, value );
+		}
+		return this;
+	}
+
+	public Insert setTableName(String tableName) {
+		this.tableName = tableName;
+		return this;
+	}
+
+	public String toStatementString() {
+		StringBuffer buf = new StringBuffer( columns.size()*15 + tableName.length() + 10 );
+		if ( comment != null ) {
+			buf.append( "/* " ).append( comment ).append( " */ " );
+		}
+		buf.append("insert into ")
+			.append(tableName);
+		if ( columns.size()==0 ) {
+			buf.append(' ').append( dialect.getNoColumnsInsertString() );
+		}
+		else {
+			buf.append(" (");
+			Iterator iter = columns.keySet().iterator();
+			while ( iter.hasNext() ) {
+				buf.append( iter.next() );
+				if ( iter.hasNext() ) {
+					buf.append( ", " );
+				}
+			}
+			buf.append(") values (");
+			iter = columns.values().iterator();
+			while ( iter.hasNext() ) {
+				buf.append( iter.next() );
+				if ( iter.hasNext() ) {
+					buf.append( ", " );
+				}
+			}
+			buf.append(')');
+		}
+		return buf.toString();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/InsertSelect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/InsertSelect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/InsertSelect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+// $Id: InsertSelect.java 7057 2005-06-07 20:06:10Z steveebersole $
+package org.hibernate.sql;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.HibernateException;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * Implementation of InsertSelect.
+ *
+ * @author Steve Ebersole
+ */
+public class InsertSelect {
+
+	private Dialect dialect;
+	private String tableName;
+	private String comment;
+	private List columnNames = new ArrayList();
+	private Select select;
+
+	public InsertSelect(Dialect dialect) {
+		this.dialect = dialect;
+	}
+
+	public InsertSelect setTableName(String tableName) {
+		this.tableName = tableName;
+		return this;
+	}
+
+	public InsertSelect setComment(String comment) {
+		this.comment = comment;
+		return this;
+	}
+
+	public InsertSelect addColumn(String columnName) {
+		columnNames.add( columnName );
+		return this;
+	}
+
+	public InsertSelect addColumns(String[] columnNames) {
+		for ( int i = 0; i < columnNames.length; i++ ) {
+			this.columnNames.add( columnNames[i] );
+		}
+		return this;
+	}
+
+	public InsertSelect setSelect(Select select) {
+		this.select = select;
+		return this;
+	}
+
+	public String toStatementString() {
+		if ( tableName == null ) throw new HibernateException( "no table name defined for insert-select" );
+		if ( select == null ) throw new HibernateException( "no select defined for insert-select" );
+
+		StringBuffer buf = new StringBuffer( (columnNames.size() * 15) + tableName.length() + 10 );
+		if ( comment!=null ) {
+			buf.append( "/* " ).append( comment ).append( " */ " );
+		}
+		buf.append( "insert into " ).append( tableName );
+		if ( !columnNames.isEmpty() ) {
+			buf.append( " (" );
+			Iterator itr = columnNames.iterator();
+			while ( itr.hasNext() ) {
+				buf.append( itr.next() );
+				if ( itr.hasNext() ) {
+					buf.append( ", " );
+				}
+			}
+			buf.append( ")" );
+		}
+		buf.append( ' ' ).append( select.toStatementString() );
+		return buf.toString();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/JoinFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/JoinFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/JoinFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,87 @@
+//$Id: JoinFragment.java 6034 2005-03-07 12:31:37Z pgmjsd $
+package org.hibernate.sql;
+
+import org.hibernate.util.StringHelper;
+
+/**
+ * An abstract SQL join fragment renderer
+ *
+ * @author Gavin King
+ */
+public abstract class JoinFragment {
+
+	public abstract void addJoin(String tableName, String alias, String[] fkColumns, String[] pkColumns, int joinType);
+
+	public abstract void addJoin(String tableName, String alias, String[] fkColumns, String[] pkColumns, int joinType, String on);
+
+	public abstract void addCrossJoin(String tableName, String alias);
+
+	public abstract void addJoins(String fromFragment, String whereFragment);
+
+	public abstract String toFromFragmentString();
+
+	public abstract String toWhereFragmentString();
+
+	// --Commented out by Inspection (12/4/04 9:10 AM): public abstract void addCondition(String alias, String[] columns, String condition);
+	public abstract void addCondition(String alias, String[] fkColumns, String[] pkColumns);
+
+	public abstract boolean addCondition(String condition);
+	// --Commented out by Inspection (12/4/04 9:10 AM): public abstract void addFromFragmentString(String fromFragmentString);
+
+	public abstract JoinFragment copy();
+
+	public static final int INNER_JOIN = 0;
+	public static final int FULL_JOIN = 4;
+	public static final int LEFT_OUTER_JOIN = 1;
+	public static final int RIGHT_OUTER_JOIN = 2;
+
+	private boolean hasFilterCondition = false;
+	private boolean hasThetaJoins = false;
+
+	public void addFragment(JoinFragment ojf) {
+		if ( ojf.hasThetaJoins() ) {
+			hasThetaJoins = true;
+		}
+		addJoins( ojf.toFromFragmentString(), ojf.toWhereFragmentString() );
+	}
+
+	/**
+	 * Appends the 'on' condition to the buffer, returning true if the condition was added.
+	 * Returns false if the 'on' condition was empty.
+	 *
+	 * @param buffer The buffer to append the 'on' condition to.
+	 * @param on     The 'on' condition.
+	 * @return Returns true if the condition was added, false if the condition was already in 'on' string.
+	 */
+	protected boolean addCondition(StringBuffer buffer, String on) {
+		if ( StringHelper.isNotEmpty( on ) ) {
+			if ( !on.startsWith( " and" ) ) buffer.append( " and " );
+			buffer.append( on );
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	/**
+	 * True if the where fragment is from a filter condition.
+	 *
+	 * @return True if the where fragment is from a filter condition.
+	 */
+	public boolean hasFilterCondition() {
+		return hasFilterCondition;
+	}
+
+	public void setHasFilterCondition(boolean b) {
+		this.hasFilterCondition = b;
+	}
+
+	public boolean hasThetaJoins() {
+		return hasThetaJoins;
+	}
+
+	public void setHasThetaJoins(boolean hasThetaJoins) {
+		this.hasThetaJoins = hasThetaJoins;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/MckoiCaseFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/MckoiCaseFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/MckoiCaseFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+//$Id: MckoiCaseFragment.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.sql;
+
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A Mckoi IF function.
+ * <br>
+ * <code>if(..., ..., ...) as ...</code>
+ * <br>
+ * @author Gavin King
+ */
+public class MckoiCaseFragment extends CaseFragment {
+
+	public String toFragmentString() {
+		StringBuffer buf = new StringBuffer( cases.size() * 15 + 10 );
+		StringBuffer buf2= new StringBuffer( cases.size() );
+
+		Iterator iter = cases.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			buf.append(" if(")
+				.append( me.getKey() )
+				.append(" is not null")
+				.append(", ")
+				.append( me.getValue() )
+				.append(", ");
+			buf2.append(")");
+		}
+
+		buf.append("null");
+		buf.append(buf2);
+		if (returnColumnName!=null) {
+			buf.append(" as ")
+				.append(returnColumnName);
+		}
+
+		return buf.toString();
+	}
+}
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/OracleJoinFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/OracleJoinFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/OracleJoinFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,127 @@
+//$Id: OracleJoinFragment.java 6750 2005-05-11 15:26:04Z oneovthafew $
+package org.hibernate.sql;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * An Oracle-style (theta) join
+ *
+ * @author Jon Lipsky, Gavin King
+ */
+public class OracleJoinFragment extends JoinFragment {
+
+	private StringBuffer afterFrom = new StringBuffer();
+	private StringBuffer afterWhere = new StringBuffer();
+
+	public void addJoin(String tableName, String alias, String[] fkColumns, String[] pkColumns, int joinType) {
+
+		addCrossJoin( tableName, alias );
+
+		for ( int j = 0; j < fkColumns.length; j++ ) {
+			setHasThetaJoins( true );
+			afterWhere.append( " and " )
+					.append( fkColumns[j] );
+			if ( joinType == RIGHT_OUTER_JOIN || joinType == FULL_JOIN ) afterWhere.append( "(+)" );
+			afterWhere.append( '=' )
+					.append( alias )
+					.append( '.' )
+					.append( pkColumns[j] );
+			if ( joinType == LEFT_OUTER_JOIN || joinType == FULL_JOIN ) afterWhere.append( "(+)" );
+		}
+
+	}
+
+	public String toFromFragmentString() {
+		return afterFrom.toString();
+	}
+
+	public String toWhereFragmentString() {
+		return afterWhere.toString();
+	}
+
+	public void addJoins(String fromFragment, String whereFragment) {
+		afterFrom.append( fromFragment );
+		afterWhere.append( whereFragment );
+	}
+
+	public JoinFragment copy() {
+		OracleJoinFragment copy = new OracleJoinFragment();
+		copy.afterFrom = new StringBuffer( afterFrom.toString() );
+		copy.afterWhere = new StringBuffer( afterWhere.toString() );
+		return copy;
+	}
+
+	public void addCondition(String alias, String[] columns, String condition) {
+		for ( int i = 0; i < columns.length; i++ ) {
+			afterWhere.append( " and " )
+					.append( alias )
+					.append( '.' )
+					.append( columns[i] )
+					.append( condition );
+		}
+	}
+
+	public void addCrossJoin(String tableName, String alias) {
+		afterFrom.append( ", " )
+				.append( tableName )
+				.append( ' ' )
+				.append( alias );
+	}
+
+	public void addCondition(String alias, String[] fkColumns, String[] pkColumns) {
+		throw new UnsupportedOperationException();
+	}
+
+	public boolean addCondition(String condition) {
+		return addCondition( afterWhere, condition );
+	}
+
+	public void addFromFragmentString(String fromFragmentString) {
+		afterFrom.append( fromFragmentString );
+	}
+
+	public void addJoin(String tableName, String alias, String[] fkColumns, String[] pkColumns, int joinType, String on) {
+		//arbitrary on clause ignored!!
+		addJoin( tableName, alias, fkColumns, pkColumns, joinType );
+		if ( joinType == JoinFragment.INNER_JOIN ) {
+			addCondition( on );
+		}
+		else if ( joinType == JoinFragment.LEFT_OUTER_JOIN ) {
+			addLeftOuterJoinCondition( on );
+		}
+		else {
+			throw new UnsupportedOperationException( "join type not supported by OracleJoinFragment (use Oracle9Dialect)" );
+		}
+	}
+
+	/**
+	 * This method is a bit of a hack, and assumes
+	 * that the column on the "right" side of the
+	 * join appears on the "left" side of the
+	 * operator, which is extremely wierd if this
+	 * was a normal join condition, but is natural
+	 * for a filter.
+	 */
+	private void addLeftOuterJoinCondition(String on) {
+		StringBuffer buf = new StringBuffer( on );
+		for ( int i = 0; i < buf.length(); i++ ) {
+			char character = buf.charAt( i );
+			boolean isInsertPoint = OPERATORS.contains( new Character( character ) ) ||
+					( character == ' ' && buf.length() > i + 3 && "is ".equals( buf.substring( i + 1, i + 4 ) ) );
+			if ( isInsertPoint ) {
+				buf.insert( i, "(+)" );
+				i += 3;
+			}
+		}
+		addCondition( buf.toString() );
+	}
+
+	private static final Set OPERATORS = new HashSet();
+
+	static {
+		OPERATORS.add( new Character( '=' ) );
+		OPERATORS.add( new Character( '<' ) );
+		OPERATORS.add( new Character( '>' ) );
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/QueryJoinFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/QueryJoinFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/QueryJoinFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,129 @@
+//$Id: QueryJoinFragment.java 4889 2004-12-05 17:20:21Z pgmjsd $
+package org.hibernate.sql;
+
+import org.hibernate.dialect.Dialect;
+
+/**
+ * A join that appears in a translated HQL query
+ *
+ * @author Gavin King
+ */
+public class QueryJoinFragment extends JoinFragment {
+
+	private StringBuffer afterFrom = new StringBuffer();
+	private StringBuffer afterWhere = new StringBuffer();
+	private Dialect dialect;
+	private boolean useThetaStyleInnerJoins;
+
+	public QueryJoinFragment(Dialect dialect, boolean useThetaStyleInnerJoins) {
+		this.dialect = dialect;
+		this.useThetaStyleInnerJoins = useThetaStyleInnerJoins;
+	}
+
+	public void addJoin(String tableName, String alias, String[] fkColumns, String[] pkColumns, int joinType) {
+		addJoin( tableName, alias, alias, fkColumns, pkColumns, joinType, null );
+	}
+
+	public void addJoin(String tableName, String alias, String[] fkColumns, String[] pkColumns, int joinType, String on) {
+		addJoin( tableName, alias, alias, fkColumns, pkColumns, joinType, on );
+	}
+
+	private void addJoin(String tableName, String alias, String concreteAlias, String[] fkColumns, String[] pkColumns, int joinType, String on) {
+		if ( !useThetaStyleInnerJoins || joinType != INNER_JOIN ) {
+			JoinFragment jf = dialect.createOuterJoinFragment();
+			jf.addJoin( tableName, alias, fkColumns, pkColumns, joinType, on );
+			addFragment( jf );
+		}
+		else {
+			addCrossJoin( tableName, alias );
+			addCondition( concreteAlias, fkColumns, pkColumns );
+			addCondition( on );
+		}
+	}
+
+	public String toFromFragmentString() {
+		return afterFrom.toString();
+	}
+
+	public String toWhereFragmentString() {
+		return afterWhere.toString();
+	}
+
+	public void addJoins(String fromFragment, String whereFragment) {
+		afterFrom.append( fromFragment );
+		afterWhere.append( whereFragment );
+	}
+
+	public JoinFragment copy() {
+		QueryJoinFragment copy = new QueryJoinFragment( dialect, useThetaStyleInnerJoins );
+		copy.afterFrom = new StringBuffer( afterFrom.toString() );
+		copy.afterWhere = new StringBuffer( afterWhere.toString() );
+		return copy;
+	}
+
+	public void addCondition(String alias, String[] columns, String condition) {
+		for ( int i = 0; i < columns.length; i++ ) {
+			afterWhere.append( " and " )
+					.append( alias )
+					.append( '.' )
+					.append( columns[i] )
+					.append( condition );
+		}
+	}
+
+
+	public void addCrossJoin(String tableName, String alias) {
+		afterFrom.append( ", " )
+				.append( tableName )
+				.append( ' ' )
+				.append( alias );
+	}
+
+	public void addCondition(String alias, String[] fkColumns, String[] pkColumns) {
+		for ( int j = 0; j < fkColumns.length; j++ ) {
+			afterWhere.append( " and " )
+					.append( fkColumns[j] )
+					.append( '=' )
+					.append( alias )
+					.append( '.' )
+					.append( pkColumns[j] );
+		}
+	}
+
+	/**
+	 * Add the condition string to the join fragment.
+	 *
+	 * @param condition
+	 * @return true if the condition was added, false if it was already in the fragment.
+	 */
+	public boolean addCondition(String condition) {
+		// if the condition is not already there...
+		if (
+				afterFrom.toString().indexOf( condition.trim() ) < 0 &&
+				afterWhere.toString().indexOf( condition.trim() ) < 0
+		) {
+			if ( !condition.startsWith( " and " ) ) {
+				afterWhere.append( " and " );
+			}
+			afterWhere.append( condition );
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	public void addFromFragmentString(String fromFragmentString) {
+		afterFrom.append( fromFragmentString );
+	}
+
+	public void clearWherePart() {
+		afterWhere.setLength( 0 );
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/QuerySelect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/QuerySelect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/QuerySelect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,190 @@
+//$Id: QuerySelect.java 6999 2005-06-03 02:04:13Z oneovthafew $
+package org.hibernate.sql;
+
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.hibernate.dialect.Dialect;
+
+/**
+ * A translated HQL query
+ * @author Gavin King
+ */
+public class QuerySelect {
+	private Dialect dialect;
+	private JoinFragment joins;
+	private StringBuffer select = new StringBuffer();
+	private StringBuffer where = new StringBuffer();
+	private StringBuffer groupBy = new StringBuffer();
+	private StringBuffer orderBy = new StringBuffer();
+	private StringBuffer having = new StringBuffer();
+	private String comment;
+	private boolean distinct=false;
+
+	private static final HashSet DONT_SPACE_TOKENS = new HashSet();
+	static {
+		//dontSpace.add("'");
+		DONT_SPACE_TOKENS.add(".");
+		DONT_SPACE_TOKENS.add("+");
+		DONT_SPACE_TOKENS.add("-");
+		DONT_SPACE_TOKENS.add("/");
+		DONT_SPACE_TOKENS.add("*");
+		DONT_SPACE_TOKENS.add("<");
+		DONT_SPACE_TOKENS.add(">");
+		DONT_SPACE_TOKENS.add("=");
+		DONT_SPACE_TOKENS.add("#");
+		DONT_SPACE_TOKENS.add("~");
+		DONT_SPACE_TOKENS.add("|");
+		DONT_SPACE_TOKENS.add("&");
+		DONT_SPACE_TOKENS.add("<=");
+		DONT_SPACE_TOKENS.add(">=");
+		DONT_SPACE_TOKENS.add("=>");
+		DONT_SPACE_TOKENS.add("=<");
+		DONT_SPACE_TOKENS.add("!=");
+		DONT_SPACE_TOKENS.add("<>");
+		DONT_SPACE_TOKENS.add("!#");
+		DONT_SPACE_TOKENS.add("!~");
+		DONT_SPACE_TOKENS.add("!<");
+		DONT_SPACE_TOKENS.add("!>");
+		DONT_SPACE_TOKENS.add("("); //for MySQL
+		DONT_SPACE_TOKENS.add(")");
+	}
+
+	public QuerySelect(Dialect dialect) {
+		this.dialect = dialect;
+		joins = new QueryJoinFragment(dialect, false);
+	}
+
+	public JoinFragment getJoinFragment() {
+		return joins;
+	}
+
+	public void addSelectFragmentString(String fragment) {
+		if ( fragment.length()>0 && fragment.charAt(0)==',' ) fragment = fragment.substring(1);
+		fragment = fragment.trim();
+		if ( fragment.length()>0 ) {
+			if ( select.length()>0 ) select.append(", ");
+			select.append(fragment);
+		}
+	}
+
+	public void addSelectColumn(String columnName, String alias) {
+		addSelectFragmentString(columnName + ' ' + alias);
+	}
+
+	public void setDistinct(boolean distinct) {
+		this.distinct = distinct;
+	}
+
+	public void setWhereTokens(Iterator tokens) {
+		//if ( conjunctiveWhere.length()>0 ) conjunctiveWhere.append(" and ");
+		appendTokens(where, tokens);
+	}
+
+	public void prependWhereConditions(String conditions) {
+		if (where.length() > 0) {
+			where.insert(0, conditions + " and ");
+		}
+		else {
+			where.append(conditions);
+		}
+	}
+
+	public void setGroupByTokens(Iterator tokens) {
+		//if ( groupBy.length()>0 ) groupBy.append(" and ");
+		appendTokens(groupBy, tokens);
+	}
+
+	public void setOrderByTokens(Iterator tokens) {
+		//if ( orderBy.length()>0 ) orderBy.append(" and ");
+		appendTokens(orderBy, tokens);
+	}
+
+	public void setHavingTokens(Iterator tokens) {
+		//if ( having.length()>0 ) having.append(" and ");
+		appendTokens(having, tokens);
+	}
+
+	public void addOrderBy(String orderByString) {
+		if ( orderBy.length() > 0 ) orderBy.append(", ");
+		orderBy.append(orderByString);
+	}
+
+	public String toQueryString() {
+		StringBuffer buf = new StringBuffer(50);
+		if (comment!=null) buf.append("/* ").append(comment).append(" */ ");
+		buf.append("select ");
+		if (distinct) buf.append("distinct ");
+		String from = joins.toFromFragmentString();
+		if ( from.startsWith(",") ) {
+			from = from.substring(1);
+		}
+		else if ( from.startsWith(" inner join") ){
+			from = from.substring(11);
+		}
+
+		buf.append( select.toString() )
+			.append(" from")
+			.append(from);
+
+		String outerJoinsAfterWhere = joins.toWhereFragmentString().trim();
+		String whereConditions = where.toString().trim();
+		boolean hasOuterJoinsAfterWhere = outerJoinsAfterWhere.length() > 0;
+		boolean hasWhereConditions = whereConditions.length() > 0;
+		if (hasOuterJoinsAfterWhere || hasWhereConditions) {
+			buf.append(" where ");
+			if (hasOuterJoinsAfterWhere) {
+				buf.append( outerJoinsAfterWhere.substring(4) );
+			}
+			if (hasWhereConditions) {
+				if (hasOuterJoinsAfterWhere) {
+					buf.append(" and (");
+				}
+				buf.append(whereConditions);
+				if (hasOuterJoinsAfterWhere) {
+					buf.append(")");
+				}
+			}
+		}
+
+		if ( groupBy.length() > 0 ) buf.append(" group by ").append( groupBy.toString() );
+		if ( having.length() > 0 ) buf.append(" having ").append( having.toString() );
+		if ( orderBy.length() > 0 ) buf.append(" order by ").append( orderBy.toString() );
+
+		return dialect.transformSelectString( buf.toString() );
+	}
+
+	private static void appendTokens(StringBuffer buf, Iterator iter) {
+		boolean lastSpaceable=true;
+		boolean lastQuoted=false;
+		while ( iter.hasNext() ) {
+			String token = (String) iter.next();
+			boolean spaceable = !DONT_SPACE_TOKENS.contains(token);
+			boolean quoted = token.startsWith("'");
+			if (spaceable && lastSpaceable) {
+				if ( !quoted || !lastQuoted ) buf.append(' ');
+			}
+			lastSpaceable = spaceable;
+			buf.append(token);
+			lastQuoted = token.endsWith("'");
+		}
+	}
+
+	public void setComment(String comment) {
+		this.comment = comment;
+	}
+
+	public QuerySelect copy() {
+		QuerySelect copy = new QuerySelect(dialect);
+		copy.joins = this.joins.copy();
+		copy.select.append( this.select.toString() );
+		copy.where.append( this.where.toString() );
+		copy.groupBy.append( this.groupBy.toString() );
+		copy.orderBy.append( this.orderBy.toString() );
+		copy.having.append( this.having.toString() );
+		copy.comment = this.comment;
+		copy.distinct = this.distinct;
+		return copy;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Select.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Select.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Select.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,155 @@
+//$Id: Select.java 7143 2005-06-15 02:57:03Z oneovthafew $
+package org.hibernate.sql;
+
+import org.hibernate.LockMode;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.util.StringHelper;
+
+
+/**
+ * A simple SQL <tt>SELECT</tt> statement
+ * @author Gavin King
+ */
+public class Select {
+
+	private String selectClause;
+	private String fromClause;
+	private String outerJoinsAfterFrom;
+	private String whereClause;
+	private String outerJoinsAfterWhere;
+	private String orderByClause;
+	private String groupByClause;
+	private String comment;
+	private LockMode lockMode;
+	public final Dialect dialect;
+
+	private int guesstimatedBufferSize = 20;
+	
+	public Select(Dialect dialect) {
+		this.dialect = dialect;
+	}
+
+	/**
+	 * Construct an SQL <tt>SELECT</tt> statement from the given clauses
+	 */
+	public String toStatementString() {
+		StringBuffer buf = new StringBuffer(guesstimatedBufferSize);
+		if ( StringHelper.isNotEmpty(comment) ) {
+			buf.append("/* ").append(comment).append(" */ ");
+		}
+		
+		buf.append("select ").append(selectClause)
+				.append(" from ").append(fromClause);
+		
+		if ( StringHelper.isNotEmpty(outerJoinsAfterFrom) ) {
+			buf.append(outerJoinsAfterFrom);
+		}
+		
+		if ( StringHelper.isNotEmpty(whereClause) || StringHelper.isNotEmpty(outerJoinsAfterWhere) ) {
+			buf.append(" where " );
+			// the outerJoinsAfterWhere needs to come before where clause to properly
+			// handle dynamic filters
+			if ( StringHelper.isNotEmpty(outerJoinsAfterWhere) ) {
+				buf.append(outerJoinsAfterWhere);
+				if ( StringHelper.isNotEmpty(whereClause) ) {
+					buf.append( " and " );
+				}
+			}
+			if ( StringHelper.isNotEmpty(whereClause) ) {
+				buf.append(whereClause);
+			}
+		}
+		
+		if ( StringHelper.isNotEmpty(groupByClause) ) {
+			buf.append(" group by ").append(groupByClause);
+		}
+		
+		if ( StringHelper.isNotEmpty(orderByClause) ) {
+			buf.append(" order by ").append(orderByClause);
+		}
+		
+		if (lockMode!=null) {
+			buf.append( dialect.getForUpdateString(lockMode) );
+		}
+		
+		return dialect.transformSelectString( buf.toString() );
+	}
+
+	/**
+	 * Sets the fromClause.
+	 * @param fromClause The fromClause to set
+	 */
+	public Select setFromClause(String fromClause) {
+		this.fromClause = fromClause;
+		this.guesstimatedBufferSize += fromClause.length();
+		return this;
+	}
+
+	public Select setFromClause(String tableName, String alias) {
+		this.fromClause = tableName + ' ' + alias;
+		this.guesstimatedBufferSize += fromClause.length();
+		return this;
+	}
+
+	public Select setOrderByClause(String orderByClause) {
+		this.orderByClause = orderByClause;
+		this.guesstimatedBufferSize += orderByClause.length();
+		return this;
+	}
+
+	public Select setGroupByClause(String groupByClause) {
+		this.groupByClause = groupByClause;
+		this.guesstimatedBufferSize += groupByClause.length();
+		return this;
+	}
+
+	public Select setOuterJoins(String outerJoinsAfterFrom, String outerJoinsAfterWhere) {
+		this.outerJoinsAfterFrom = outerJoinsAfterFrom;
+
+		// strip off any leading 'and' token
+		String tmpOuterJoinsAfterWhere = outerJoinsAfterWhere.trim();
+		if ( tmpOuterJoinsAfterWhere.startsWith("and") ) {
+			tmpOuterJoinsAfterWhere = tmpOuterJoinsAfterWhere.substring(4);
+		}
+		this.outerJoinsAfterWhere = tmpOuterJoinsAfterWhere;
+
+		this.guesstimatedBufferSize += outerJoinsAfterFrom.length() + outerJoinsAfterWhere.length();
+		return this;
+	}
+
+
+	/**
+	 * Sets the selectClause.
+	 * @param selectClause The selectClause to set
+	 */
+	public Select setSelectClause(String selectClause) {
+		this.selectClause = selectClause;
+		this.guesstimatedBufferSize += selectClause.length();
+		return this;
+	}
+
+	/**
+	 * Sets the whereClause.
+	 * @param whereClause The whereClause to set
+	 */
+	public Select setWhereClause(String whereClause) {
+		this.whereClause = whereClause;
+		this.guesstimatedBufferSize += whereClause.length();
+		return this;
+	}
+
+	public Select setComment(String comment) {
+		this.comment = comment;
+		this.guesstimatedBufferSize += comment.length();
+		return this;
+	}
+
+	public LockMode getLockMode() {
+		return lockMode;
+	}
+	
+	public Select setLockMode(LockMode lockMode) {
+		this.lockMode = lockMode;
+		return this;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/SelectFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/SelectFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/SelectFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,128 @@
+//$Id: SelectFragment.java 7479 2005-07-14 23:56:53Z oneovthafew $
+package org.hibernate.sql;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.util.StringHelper;
+
+/**
+ * A fragment of an SQL <tt>SELECT</tt> clause
+ *
+ * @author Gavin King
+ */
+public class SelectFragment {
+	private String suffix;
+	private List columns = new ArrayList();
+	//private List aliases = new ArrayList();
+	private List columnAliases = new ArrayList();
+	private String extraSelectList;
+	private String[] usedAliases;
+	
+	public SelectFragment() {}
+	
+	public SelectFragment setUsedAliases(String[] aliases) {
+		usedAliases = aliases;
+		return this;
+	}
+	
+	public SelectFragment setExtraSelectList(String extraSelectList) {
+		this.extraSelectList = extraSelectList;
+		return this;
+	}
+	
+	public SelectFragment setExtraSelectList(CaseFragment caseFragment, String fragmentAlias) {
+		setExtraSelectList( caseFragment.setReturnColumnName(fragmentAlias, suffix).toFragmentString() );
+		return this;
+	}
+
+	public SelectFragment setSuffix(String suffix) {
+		this.suffix = suffix;
+		return this;
+	}
+
+	public SelectFragment addColumn(String columnName) {
+		addColumn(null, columnName);
+		return this;
+	}
+
+	public SelectFragment addColumns(String[] columnNames) {
+		for (int i=0; i<columnNames.length; i++) addColumn( columnNames[i] );
+		return this;
+	}
+
+	public SelectFragment addColumn(String tableAlias, String columnName) {
+		return addColumn(tableAlias, columnName, columnName);
+	}
+
+	public SelectFragment addColumn(String tableAlias, String columnName, String columnAlias) {
+		columns.add( StringHelper.qualify(tableAlias, columnName) );
+		//columns.add(columnName);
+		//aliases.add(tableAlias);
+		columnAliases.add(columnAlias);
+		return this;
+	}
+
+	public SelectFragment addColumns(String tableAlias, String[] columnNames) {
+		for (int i=0; i<columnNames.length; i++) addColumn( tableAlias, columnNames[i] );
+		return this;
+	}
+
+	public SelectFragment addColumns(String tableAlias, String[] columnNames, String[] columnAliases) {
+		for (int i=0; i<columnNames.length; i++) {
+			if ( columnNames[i]!=null ) addColumn( tableAlias, columnNames[i], columnAliases[i] );
+		}
+		return this;
+	}
+
+	public SelectFragment addFormulas(String tableAlias, String[] formulas, String[] formulaAliases) {
+		for ( int i=0; i<formulas.length; i++ ) {
+			if ( formulas[i]!=null ) addFormula( tableAlias, formulas[i], formulaAliases[i] );
+		}
+		return this;
+	}
+
+	public SelectFragment addFormula(String tableAlias, String formula, String formulaAlias) {
+		columns.add( StringHelper.replace(formula, Template.TEMPLATE, tableAlias) );
+		columnAliases.add(formulaAlias);
+		return this;
+	}
+
+	public String toFragmentString() {
+		StringBuffer buf = new StringBuffer( columns.size() * 10 );
+		Iterator iter = columns.iterator();
+		Iterator columnAliasIter = columnAliases.iterator();
+		//HashMap columnsUnique = new HashMap();
+		HashSet columnsUnique = new HashSet();
+		if (usedAliases!=null) columnsUnique.addAll( Arrays.asList(usedAliases) );
+		while ( iter.hasNext() ) {
+			String column = (String) iter.next();
+			String columnAlias = (String) columnAliasIter.next();
+			//TODO: eventually put this back in, once we think all is fixed
+			//Object otherAlias = columnsUnique.put(qualifiedColumn, columnAlias);
+			/*if ( otherAlias!=null && !columnAlias.equals(otherAlias) ) {
+				throw new AssertionFailure("bug in Hibernate SQL alias generation");
+			}*/
+			if ( columnsUnique.add(columnAlias) ) {
+				buf.append(", ")
+					.append(column)
+					.append(" as ");
+				if (suffix==null) {
+					buf.append(columnAlias);
+				}
+				else {
+					buf.append( new Alias(suffix).toAliasString(columnAlias) );
+				}
+			}
+		}
+		if (extraSelectList!=null) {
+			buf.append(", ")
+				.append(extraSelectList);
+		}
+		return buf.toString();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/SimpleSelect.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/SimpleSelect.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/SimpleSelect.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,188 @@
+//$Id: SimpleSelect.java 7627 2005-07-24 06:53:06Z oneovthafew $
+package org.hibernate.sql;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.LockMode;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * An SQL <tt>SELECT</tt> statement with no table joins
+ *
+ * @author Gavin King
+ */
+public class SimpleSelect {
+
+	public SimpleSelect(Dialect dialect) {
+		this.dialect = dialect;
+	}
+
+	//private static final Alias DEFAULT_ALIAS = new Alias(10, null);
+
+	private String tableName;
+	private String orderBy;
+	private Dialect dialect;
+	private LockMode lockMode = LockMode.READ;
+	private String comment;
+
+	private List columns = new ArrayList();
+	private Map aliases = new HashMap();
+	private List whereTokens = new ArrayList();
+
+	public SimpleSelect addColumns(String[] columnNames, String[] columnAliases) {
+		for ( int i=0; i<columnNames.length; i++ ) {
+			if ( columnNames[i]!=null  ) {
+				addColumn( columnNames[i], columnAliases[i] );
+			}
+		}
+		return this;
+	}
+
+	public SimpleSelect addColumns(String[] columns, String[] aliases, boolean[] ignore) {
+		for ( int i=0; i<ignore.length; i++ ) {
+			if ( !ignore[i] && columns[i]!=null ) {
+				addColumn( columns[i], aliases[i] );
+			}
+		}
+		return this;
+	}
+
+	public SimpleSelect addColumns(String[] columnNames) {
+		for ( int i=0; i<columnNames.length; i++ ) {
+			if ( columnNames[i]!=null ) addColumn( columnNames[i] );
+		}
+		return this;
+	}
+	public SimpleSelect addColumn(String columnName) {
+		columns.add(columnName);
+		//aliases.put( columnName, DEFAULT_ALIAS.toAliasString(columnName) );
+		return this;
+	}
+
+	public SimpleSelect addColumn(String columnName, String alias) {
+		columns.add(columnName);
+		aliases.put(columnName, alias);
+		return this;
+	}
+
+	public SimpleSelect setTableName(String tableName) {
+		this.tableName = tableName;
+		return this;
+	}
+
+	public SimpleSelect setLockMode(LockMode lockMode) {
+		this.lockMode = lockMode;
+		return this;
+	}
+
+	public SimpleSelect addWhereToken(String token) {
+		whereTokens.add(token);
+		return this;
+	}
+	
+	private void and() {
+		if ( whereTokens.size()>0 ) {
+			whereTokens.add("and");
+		}
+	}
+
+	public SimpleSelect addCondition(String lhs, String op, String rhs) {
+		and();
+		whereTokens.add( lhs + ' ' + op + ' ' + rhs );
+		return this;
+	}
+
+	public SimpleSelect addCondition(String lhs, String condition) {
+		and();
+		whereTokens.add( lhs + ' ' + condition );
+		return this;
+	}
+
+	public SimpleSelect addCondition(String[] lhs, String op, String[] rhs) {
+		for ( int i=0; i<lhs.length; i++ ) {
+			addCondition( lhs[i], op, rhs[i] );
+		}
+		return this;
+	}
+
+	public SimpleSelect addCondition(String[] lhs, String condition) {
+		for ( int i=0; i<lhs.length; i++ ) {
+			if ( lhs[i]!=null ) addCondition( lhs[i], condition );
+		}
+		return this;
+	}
+
+	public String toStatementString() {
+		StringBuffer buf = new StringBuffer( 
+				columns.size()*10 + 
+				tableName.length() + 
+				whereTokens.size() * 10 + 
+				10 
+			);
+		
+		if ( comment!=null ) {
+			buf.append("/* ").append(comment).append(" */ ");
+		}
+		
+		buf.append("select ");
+		Set uniqueColumns = new HashSet();
+		Iterator iter = columns.iterator();
+		boolean appendComma = false;
+		while ( iter.hasNext() ) {
+			String col = (String) iter.next();
+			String alias = (String) aliases.get(col);
+			if ( uniqueColumns.add(alias==null ? col : alias) ) {
+				if (appendComma) buf.append(", ");
+				buf.append(col);
+				if ( alias!=null && !alias.equals(col) ) {
+					buf.append(" as ")
+						.append(alias);
+				}
+				appendComma = true;
+			}
+		}
+		
+		buf.append(" from ")
+			.append( dialect.appendLockHint(lockMode, tableName) );
+		
+		if ( whereTokens.size() > 0 ) {
+			buf.append(" where ")
+				.append( toWhereClause() );
+		}
+		
+		if (orderBy!=null) buf.append(orderBy);
+		
+		if (lockMode!=null) {
+			buf.append( dialect.getForUpdateString(lockMode) );
+		}
+
+		return dialect.transformSelectString( buf.toString() );
+	}
+
+	public String toWhereClause() {
+		StringBuffer buf = new StringBuffer( whereTokens.size() * 5 );
+		Iterator iter = whereTokens.iterator();
+		while ( iter.hasNext() ) {
+			buf.append( iter.next() );
+			if ( iter.hasNext() ) buf.append(' ');
+		}
+		return buf.toString();
+	}
+
+	public SimpleSelect setOrderBy(String orderBy) {
+		this.orderBy = orderBy;
+		return this;
+	}
+
+	public SimpleSelect setComment(String comment) {
+		this.comment = comment;
+		return this;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Sybase11JoinFragment.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Sybase11JoinFragment.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Sybase11JoinFragment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,98 @@
+//$Id: Sybase11JoinFragment.java 4886 2004-12-05 15:04:21Z pgmjsd $
+package org.hibernate.sql;
+
+
+/**
+ * An old Sybase-style join (before Sybase supported the ANSI style "inner join" etc syntax)
+ * This is needed for Sybase 11.9.2 and earlier, using the HQL 2.* syntax with Collections.
+ *
+ * @author Colm O' Flaherty
+ */
+public class Sybase11JoinFragment extends JoinFragment {
+
+	private StringBuffer afterFrom = new StringBuffer();
+	private StringBuffer afterWhere = new StringBuffer();
+
+	public void addJoin(String tableName, String alias, String[] fkColumns, String[] pkColumns, int joinType) {
+
+		addCrossJoin(tableName, alias);
+
+		for ( int j=0; j<fkColumns.length; j++) {
+			//full joins are not supported.. yet!
+			if (joinType==JoinFragment.FULL_JOIN ) throw new UnsupportedOperationException();
+
+			afterWhere.append(" and ")
+				.append( fkColumns[j] )
+				.append( " " );
+
+			if (joinType==LEFT_OUTER_JOIN ) afterWhere.append("*");
+			afterWhere.append('=');
+			if (joinType==RIGHT_OUTER_JOIN ) afterWhere.append("*");
+
+			afterWhere.append (" ")
+				.append(alias)
+				.append('.')
+				.append( pkColumns[j] );
+		}
+
+	}
+
+	public String toFromFragmentString() {
+		return afterFrom.toString();
+	}
+
+	public String toWhereFragmentString() {
+		return afterWhere.toString();
+	}
+
+	public void addJoins(String fromFragment, String whereFragment) {
+		afterFrom.append(fromFragment);
+		afterWhere.append(whereFragment);
+	}
+
+	public JoinFragment copy() {
+		Sybase11JoinFragment copy = new Sybase11JoinFragment();
+		copy.afterFrom = new StringBuffer( afterFrom.toString() );
+		copy.afterWhere = new StringBuffer( afterWhere.toString() );
+		return copy;
+	}
+
+	public void addCondition(String alias, String[] columns, String condition) {
+		for ( int i=0; i<columns.length; i++ ) {
+			afterWhere.append(" and ")
+				.append(alias)
+				.append('.')
+				.append( columns[i] )
+				.append(condition);
+		}
+	}
+
+	public void addCrossJoin(String tableName, String alias) {
+		afterFrom.append(", ")
+			.append(tableName)
+			.append(' ')
+			.append(alias);
+	}
+
+	public void addCondition(String alias, String[] fkColumns, String[] pkColumns) {
+		throw new UnsupportedOperationException();
+
+	}
+
+	public boolean addCondition(String condition) {
+		return addCondition(afterWhere, condition);
+	}
+
+
+	public void addFromFragmentString(String fromFragmentString) {
+		afterFrom.append(fromFragmentString);
+	}
+
+
+	public void addJoin(String tableName, String alias, String[] fkColumns, String[] pkColumns, int joinType, String on) {
+		addJoin(tableName, alias, fkColumns, pkColumns, joinType);
+		addCondition(on);
+	}
+}
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Template.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Template.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Template.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,318 @@
+//$Id: Template.java 9922 2006-05-10 16:58:09Z steve.ebersole at jboss.com $
+package org.hibernate.sql;
+
+import java.util.HashSet;
+import java.util.StringTokenizer;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.function.SQLFunctionRegistry;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Parses SQL fragments specified in mapping documents
+ *
+ * @author Gavin King
+ */
+public final class Template {
+
+	private static final java.util.Set KEYWORDS = new HashSet();
+	private static final java.util.Set BEFORE_TABLE_KEYWORDS = new HashSet();
+	private static final java.util.Set FUNCTION_KEYWORDS = new HashSet();
+	static {
+		KEYWORDS.add("and");
+		KEYWORDS.add("or");
+		KEYWORDS.add("not");
+		KEYWORDS.add("like");
+		KEYWORDS.add("is");
+		KEYWORDS.add("in");
+		KEYWORDS.add("between");
+		KEYWORDS.add("null");
+		KEYWORDS.add("select");
+		KEYWORDS.add("distinct");
+		KEYWORDS.add("from");
+		KEYWORDS.add("join");
+		KEYWORDS.add("inner");
+		KEYWORDS.add("outer");
+		KEYWORDS.add("left");
+		KEYWORDS.add("right");
+		KEYWORDS.add("on");
+		KEYWORDS.add("where");
+		KEYWORDS.add("having");
+		KEYWORDS.add("group");
+		KEYWORDS.add("order");
+		KEYWORDS.add("by");
+		KEYWORDS.add("desc");
+		KEYWORDS.add("asc");
+		KEYWORDS.add("limit");
+		KEYWORDS.add("any");
+		KEYWORDS.add("some");
+		KEYWORDS.add("exists");
+		KEYWORDS.add("all");
+		
+		BEFORE_TABLE_KEYWORDS.add("from");
+		BEFORE_TABLE_KEYWORDS.add("join");
+		
+		FUNCTION_KEYWORDS.add("as");
+		FUNCTION_KEYWORDS.add("leading");
+		FUNCTION_KEYWORDS.add("trailing");
+		FUNCTION_KEYWORDS.add("from");
+		FUNCTION_KEYWORDS.add("case");
+		FUNCTION_KEYWORDS.add("when");
+		FUNCTION_KEYWORDS.add("then");
+		FUNCTION_KEYWORDS.add("else");
+		FUNCTION_KEYWORDS.add("end");
+	}
+
+	public static final String TEMPLATE = "$PlaceHolder$";
+
+	private Template() {}
+
+	public static String renderWhereStringTemplate(String sqlWhereString, Dialect dialect, SQLFunctionRegistry functionRegistry) {
+		return renderWhereStringTemplate(sqlWhereString, TEMPLATE, dialect, functionRegistry);
+	}
+
+	/**
+	 * Same functionality as {@link #renderWhereStringTemplate(String, String, Dialect, SQLFunctionRegistry)},
+	 * except that a SQLFunctionRegistry is not provided (i.e., only the dialect-defined functions are
+	 * considered).  This is only intended for use by the annotations project until the
+	 * many-to-many/map-key-from-target-table feature is pulled into core.
+	 *
+	 * @deprecated Only intended for annotations usage; use {@link #renderWhereStringTemplate(String, String, Dialect, SQLFunctionRegistry)} instead
+	 */
+	public static String renderWhereStringTemplate(String sqlWhereString, String placeholder, Dialect dialect) {
+		return renderWhereStringTemplate( sqlWhereString, placeholder, dialect, new SQLFunctionRegistry( dialect, java.util.Collections.EMPTY_MAP ) );
+	}
+
+	/**
+	 * Takes the where condition provided in the mapping attribute and interpolates the alias. 
+	 * Handles subselects, quoted identifiers, quoted strings, expressions, SQL functions, 
+	 * named parameters.
+	 *
+	 * @param sqlWhereString The string into which to interpolate the placeholder value
+	 * @param placeholder The value to be interpolated into the the sqlWhereString
+	 * @param dialect The dialect to apply
+	 * @param functionRegistry The registry of all sql functions
+	 * @return The rendered sql fragment
+	 */
+	public static String renderWhereStringTemplate(String sqlWhereString, String placeholder, Dialect dialect, SQLFunctionRegistry functionRegistry ) {
+		//TODO: make this a bit nicer
+		String symbols = new StringBuffer()
+			.append("=><!+-*/()',|&`")
+			.append(StringHelper.WHITESPACE)
+			.append( dialect.openQuote() )
+			.append( dialect.closeQuote() )
+			.toString();
+		StringTokenizer tokens = new StringTokenizer(sqlWhereString, symbols, true);
+		
+		StringBuffer result = new StringBuffer();
+		boolean quoted = false;
+		boolean quotedIdentifier = false;
+		boolean beforeTable = false;
+		boolean inFromClause = false;
+		boolean afterFromTable = false;
+		
+		boolean hasMore = tokens.hasMoreTokens();
+		String nextToken = hasMore ? tokens.nextToken() : null;
+		while (hasMore) {
+			String token = nextToken;
+			String lcToken = token.toLowerCase();
+			hasMore = tokens.hasMoreTokens();
+			nextToken = hasMore ? tokens.nextToken() : null;
+			
+			boolean isQuoteCharacter = false;
+			
+			if ( !quotedIdentifier && "'".equals(token) ) {
+				quoted = !quoted;
+				isQuoteCharacter = true;
+			}
+			
+			if ( !quoted ) {
+				
+				boolean isOpenQuote;
+				if ( "`".equals(token) ) {
+					isOpenQuote = !quotedIdentifier;
+					token = lcToken = isOpenQuote ? 
+						new Character( dialect.openQuote() ).toString() :
+						new Character( dialect.closeQuote() ).toString();
+					quotedIdentifier = isOpenQuote;	
+					isQuoteCharacter = true;
+				}
+				else if ( !quotedIdentifier && ( dialect.openQuote()==token.charAt(0) ) ) {
+					isOpenQuote = true;
+					quotedIdentifier = true;	
+					isQuoteCharacter = true;
+				}
+				else if ( quotedIdentifier && ( dialect.closeQuote()==token.charAt(0) ) ) {
+					quotedIdentifier = false;
+					isQuoteCharacter = true;
+					isOpenQuote = false;
+				}
+				else {
+					isOpenQuote = false;
+				}
+				
+				if (isOpenQuote) {
+					result.append(placeholder).append('.');
+				}
+				
+			}
+	
+			boolean quotedOrWhitespace = quoted || 
+				quotedIdentifier || 
+				isQuoteCharacter || 
+				Character.isWhitespace( token.charAt(0) );
+			
+			if (quotedOrWhitespace) {
+				result.append(token);
+			}
+			else if (beforeTable) {
+				result.append(token);
+				beforeTable = false;
+				afterFromTable = true;
+			}
+			else if (afterFromTable) {
+				if ( !"as".equals(lcToken) ) afterFromTable = false;
+				result.append(token);
+			}
+			else if ( isNamedParameter(token) ) {
+				result.append(token);
+			}
+			else if (
+				isIdentifier(token, dialect) &&
+				!isFunctionOrKeyword(lcToken, nextToken, dialect , functionRegistry)
+			) {
+				result.append(placeholder)
+					.append('.')
+					.append( dialect.quote(token) );
+			}
+			else {
+				if ( BEFORE_TABLE_KEYWORDS.contains(lcToken) ) {
+					beforeTable = true;
+					inFromClause = true;
+				}
+				else if ( inFromClause && ",".equals(lcToken) ) {
+					beforeTable = true;
+				}
+				result.append(token);
+			}
+			
+			if ( //Yuck:
+					inFromClause && 
+					KEYWORDS.contains(lcToken) && //"as" is not in KEYWORDS
+					!BEFORE_TABLE_KEYWORDS.contains(lcToken)
+			) { 
+				inFromClause = false;
+			}
+
+		}
+		return result.toString();
+	}
+
+	/**
+	 * Takes order by clause provided in the mapping attribute and interpolates the alias.
+	 * Handles asc, desc, SQL functions, quoted identifiers.
+	 */
+	public static String renderOrderByStringTemplate(String sqlOrderByString, Dialect dialect, SQLFunctionRegistry functionRegistry) {
+		//TODO: make this a bit nicer
+		String symbols = new StringBuffer()
+			.append("=><!+-*/()',|&`")
+			.append(StringHelper.WHITESPACE)
+			.append( dialect.openQuote() )
+			.append( dialect.closeQuote() )
+			.toString();
+		StringTokenizer tokens = new StringTokenizer(sqlOrderByString, symbols, true);
+		
+		StringBuffer result = new StringBuffer();
+		boolean quoted = false;
+		boolean quotedIdentifier = false;
+		
+		boolean hasMore = tokens.hasMoreTokens();
+		String nextToken = hasMore ? tokens.nextToken() : null;
+		while (hasMore) {
+			String token = nextToken;
+			String lcToken = token.toLowerCase();
+			hasMore = tokens.hasMoreTokens();
+			nextToken = hasMore ? tokens.nextToken() : null;
+			
+			boolean isQuoteCharacter = false;
+			
+			if ( !quotedIdentifier && "'".equals(token) ) {
+				quoted = !quoted;
+				isQuoteCharacter = true;
+			}
+			
+			if ( !quoted ) {
+				
+				boolean isOpenQuote;
+				if ( "`".equals(token) ) {
+					isOpenQuote = !quotedIdentifier;
+					token = lcToken = isOpenQuote ? 
+						new Character( dialect.openQuote() ).toString() :
+						new Character( dialect.closeQuote() ).toString();
+					quotedIdentifier = isOpenQuote;	
+					isQuoteCharacter = true;
+				}
+				else if ( !quotedIdentifier && ( dialect.openQuote()==token.charAt(0) ) ) {
+					isOpenQuote = true;
+					quotedIdentifier = true;	
+					isQuoteCharacter = true;
+				}
+				else if ( quotedIdentifier && ( dialect.closeQuote()==token.charAt(0) ) ) {
+					quotedIdentifier = false;
+					isQuoteCharacter = true;
+					isOpenQuote = false;
+				}
+				else {
+					isOpenQuote = false;
+				}
+				
+				if (isOpenQuote) {
+					result.append(TEMPLATE).append('.');
+				}
+				
+			}
+	
+			boolean quotedOrWhitespace = quoted || 
+				quotedIdentifier || 
+				isQuoteCharacter || 
+				Character.isWhitespace( token.charAt(0) );
+			
+			if (quotedOrWhitespace) {
+				result.append(token);
+			}
+			else if (
+				isIdentifier(token, dialect) &&
+				!isFunctionOrKeyword(lcToken, nextToken, dialect, functionRegistry)
+			) {
+				result.append(TEMPLATE)
+					.append('.')
+					.append( dialect.quote(token) );
+			}
+			else {
+				result.append(token);
+			}
+		}
+		return result.toString();
+	}
+	
+	private static boolean isNamedParameter(String token) {
+		return token.startsWith(":");
+	}
+
+	private static boolean isFunctionOrKeyword(String lcToken, String nextToken, Dialect dialect, SQLFunctionRegistry functionRegistry) {
+		return "(".equals(nextToken) ||
+			KEYWORDS.contains(lcToken) ||
+			functionRegistry.hasFunction(lcToken) ||
+			dialect.getKeywords().contains(lcToken) ||
+			FUNCTION_KEYWORDS.contains(lcToken);
+	}
+
+	private static boolean isIdentifier(String token, Dialect dialect) {
+		return token.charAt(0)=='`' || ( //allow any identifier quoted with backtick
+			Character.isLetter( token.charAt(0) ) && //only recognizes identifiers beginning with a letter
+			token.indexOf('.') < 0
+		);
+	}
+
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Update.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Update.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/Update.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,189 @@
+//$Id: Update.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.sql;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.type.LiteralType;
+import org.hibernate.util.StringHelper;
+
+import org.apache.commons.collections.SequencedHashMap;
+
+/**
+ * An SQL <tt>UPDATE</tt> statement
+ *
+ * @author Gavin King
+ */
+public class Update {
+
+	private String tableName;
+	private String[] primaryKeyColumnNames;
+	private String versionColumnName;
+	private String where;
+	private String assignments;
+	private String comment;
+
+	private Map columns = new SequencedHashMap();
+	private Map whereColumns = new SequencedHashMap();
+	
+	private Dialect dialect;
+	
+	public Update(Dialect dialect) {
+		this.dialect = dialect;
+	}
+
+	public String getTableName() {
+		return tableName;
+	}
+
+	public Update appendAssignmentFragment(String fragment) {
+		if ( assignments == null ) {
+			assignments = fragment;
+		}
+		else {
+			assignments += ", " + fragment;
+		}
+		return this;
+	}
+
+	public Update setTableName(String tableName) {
+		this.tableName = tableName;
+		return this;
+	}
+
+	public Update setPrimaryKeyColumnNames(String[] primaryKeyColumnNames) {
+		this.primaryKeyColumnNames = primaryKeyColumnNames;
+		return this;
+	}
+
+	public Update setVersionColumnName(String versionColumnName) {
+		this.versionColumnName = versionColumnName;
+		return this;
+	}
+
+
+	public Update setComment(String comment) {
+		this.comment = comment;
+		return this;
+	}
+
+	public Update addColumns(String[] columnNames) {
+		for ( int i=0; i<columnNames.length; i++ ) {
+			addColumn( columnNames[i] );
+		}
+		return this;
+	}
+
+	public Update addColumns(String[] columnNames, boolean[] updateable) {
+		for ( int i=0; i<columnNames.length; i++ ) {
+			if ( updateable[i] ) addColumn( columnNames[i] );
+		}
+		return this;
+	}
+
+	public Update addColumns(String[] columnNames, String value) {
+		for ( int i=0; i<columnNames.length; i++ ) {
+			addColumn( columnNames[i], value );
+		}
+		return this;
+	}
+
+	public Update addColumn(String columnName) {
+		return addColumn(columnName, "?");
+	}
+
+	public Update addColumn(String columnName, String value) {
+		columns.put(columnName, value);
+		return this;
+	}
+
+	public Update addColumn(String columnName, Object value, LiteralType type) throws Exception {
+		return addColumn( columnName, type.objectToSQLString(value, dialect) );
+	}
+
+	public Update addWhereColumns(String[] columnNames) {
+		for ( int i=0; i<columnNames.length; i++ ) {
+			addWhereColumn( columnNames[i] );
+		}
+		return this;
+	}
+
+	public Update addWhereColumns(String[] columnNames, String value) {
+		for ( int i=0; i<columnNames.length; i++ ) {
+			addWhereColumn( columnNames[i], value );
+		}
+		return this;
+	}
+
+	public Update addWhereColumn(String columnName) {
+		return addWhereColumn(columnName, "=?");
+	}
+
+	public Update addWhereColumn(String columnName, String value) {
+		whereColumns.put(columnName, value);
+		return this;
+	}
+
+	public Update setWhere(String where) {
+		this.where=where;
+		return this;
+	}
+
+	public String toStatementString() {
+		StringBuffer buf = new StringBuffer( (columns.size() * 15) + tableName.length() + 10 );
+		if ( comment!=null ) {
+			buf.append( "/* " ).append( comment ).append( " */ " );
+		}
+		buf.append( "update " ).append( tableName ).append( " set " );
+		boolean assignmentsAppended = false;
+		Iterator iter = columns.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry e = (Map.Entry) iter.next();
+			buf.append( e.getKey() ).append( '=' ).append( e.getValue() );
+			if ( iter.hasNext() ) {
+				buf.append( ", " );
+			}
+			assignmentsAppended = true;
+		}
+		if ( assignments != null ) {
+			if ( assignmentsAppended ) {
+				buf.append( ", " );
+			}
+			buf.append( assignments );
+		}
+
+		boolean conditionsAppended = false;
+		if ( primaryKeyColumnNames != null || where != null || !whereColumns.isEmpty() || versionColumnName != null ) {
+			buf.append( " where " );
+		}
+		if ( primaryKeyColumnNames != null ) {
+			buf.append( StringHelper.join( "=? and ", primaryKeyColumnNames ) ).append( "=?" );
+			conditionsAppended = true;
+		}
+		if ( where != null ) {
+			if ( conditionsAppended ) {
+				buf.append( " and " );
+			}
+			buf.append( where );
+			conditionsAppended = true;
+		}
+		iter = whereColumns.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			final Map.Entry e = (Map.Entry) iter.next();
+			if ( conditionsAppended ) {
+				buf.append( " and " );
+			}
+			buf.append( e.getKey() ).append( e.getValue() );
+			conditionsAppended = true;
+		}
+		if ( versionColumnName != null ) {
+			if ( conditionsAppended ) {
+				buf.append( " and " );
+			}
+			buf.append( versionColumnName ).append( "=?" );
+		}
+
+		return buf.toString();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/sql/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/sql/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines helper classes for rendering SQL
+	fragments and SQL statements.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/sql/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/CategorizedStatistics.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/stat/CategorizedStatistics.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/stat/CategorizedStatistics.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+//$Id: CategorizedStatistics.java 7093 2005-06-09 06:33:06Z oneovthafew $
+package org.hibernate.stat;
+
+import java.io.Serializable;
+
+/**
+ * Statistics for a particular "category" (a named entity,
+ * collection role, second level cache region or query).
+ * 
+ * @author Gavin King
+ */
+public class CategorizedStatistics implements Serializable {
+	
+	private final String categoryName;
+
+	CategorizedStatistics(String categoryName) {
+		this.categoryName = categoryName;
+	}
+	
+	public String getCategoryName() {
+		return categoryName;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/CategorizedStatistics.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/CollectionStatistics.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/stat/CollectionStatistics.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/stat/CollectionStatistics.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: CollectionStatistics.java 7093 2005-06-09 06:33:06Z oneovthafew $
+package org.hibernate.stat;
+
+
+/**
+ * Collection related statistics
+ * 
+ * @author Gavin King
+ */
+public class CollectionStatistics extends CategorizedStatistics {
+	
+	CollectionStatistics(String role) {
+		super(role);
+	}
+	
+	long loadCount;
+	long fetchCount;
+	long updateCount;
+	long removeCount;
+	long recreateCount;
+	
+	public long getLoadCount() {
+		return loadCount;
+	}
+	public long getFetchCount() {
+		return fetchCount;
+	}
+	public long getRecreateCount() {
+		return recreateCount;
+	}
+	public long getRemoveCount() {
+		return removeCount;
+	}
+	public long getUpdateCount() {
+		return updateCount;
+	}
+
+	public String toString() {
+		return new StringBuffer()
+		    .append("CollectionStatistics")
+			.append("[loadCount=").append(this.loadCount)
+			.append(",fetchCount=").append(this.fetchCount)
+			.append(",recreateCount=").append(this.recreateCount)
+			.append(",removeCount=").append(this.removeCount)
+			.append(",updateCount=").append(this.updateCount)
+			.append(']')
+			.toString();
+	}
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/CollectionStatistics.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/EntityStatistics.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/stat/EntityStatistics.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/stat/EntityStatistics.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+//$Id: EntityStatistics.java 7864 2005-08-11 23:22:52Z oneovthafew $
+package org.hibernate.stat;
+
+
+/**
+ * Entity related statistics
+ * 
+ * @author Gavin King
+ */
+public class EntityStatistics extends CategorizedStatistics {
+	
+	EntityStatistics(String name) {
+		super(name);
+	}
+
+	long loadCount;
+	long updateCount;
+	long insertCount;
+	long deleteCount;
+	long fetchCount;
+	long optimisticFailureCount;
+
+	public long getDeleteCount() {
+		return deleteCount;
+	}
+	public long getInsertCount() {
+		return insertCount;
+	}
+	public long getLoadCount() {
+		return loadCount;
+	}
+	public long getUpdateCount() {
+		return updateCount;
+	}
+	public long getFetchCount() {
+		return fetchCount;
+	}
+	public long getOptimisticFailureCount() {
+		return optimisticFailureCount;
+	}
+
+	public String toString() {
+		return new StringBuffer()
+		    .append("EntityStatistics")
+			.append("[loadCount=").append(this.loadCount)
+			.append(",updateCount=").append(this.updateCount)
+			.append(",insertCount=").append(this.insertCount)
+			.append(",deleteCount=").append(this.deleteCount)
+			.append(",fetchCount=").append(this.fetchCount)
+			.append(",optimisticLockFailureCount=").append(this.optimisticFailureCount)
+			.append(']')
+			.toString();
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/EntityStatistics.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/QueryStatistics.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/stat/QueryStatistics.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/stat/QueryStatistics.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,112 @@
+//$Id: QueryStatistics.java 9162 2006-01-27 23:40:32Z steveebersole $
+package org.hibernate.stat;
+
+
+/**
+ * Query statistics (HQL and SQL)
+ * 
+ * Note that for a cached query, the cache miss is equals to the db count
+ * 
+ * @author Gavin King
+ */
+public class QueryStatistics extends CategorizedStatistics {
+
+	/*package*/ long cacheHitCount;
+	/*package*/ long cacheMissCount;
+	/*package*/ long cachePutCount;
+	private long executionCount;
+	private long executionRowCount;
+	private long executionAvgTime;
+	private long executionMaxTime;
+	private long executionMinTime;
+
+	QueryStatistics(String query) {
+		super(query);
+	}
+
+	/**
+	 * queries executed to the DB
+	 */
+	public long getExecutionCount() {
+		return executionCount;
+	}
+	
+	/**
+	 * Queries retrieved successfully from the cache
+	 */
+	public long getCacheHitCount() {
+		return cacheHitCount;
+	}
+	
+	public long getCachePutCount() {
+		return cachePutCount;
+	}
+	
+	public long getCacheMissCount() {
+		return cacheMissCount;
+	}
+	
+	/**
+	 * Number of lines returned by all the executions of this query (from DB)
+	 * For now, {@link org.hibernate.Query#iterate()} 
+	 * and {@link org.hibernate.Query#scroll()()} do not fill this statistic
+	 *
+	 * @return The number of rows cumulatively returned by the given query; iterate
+	 * and scroll queries do not effect this total as their number of returned rows
+	 * is not known at execution time.
+	 */
+	public long getExecutionRowCount() {
+		return executionRowCount;
+	}
+
+	/**
+	 * average time in ms taken by the excution of this query onto the DB
+	 */
+	public long getExecutionAvgTime() {
+		return executionAvgTime;
+	}
+
+	/**
+	 * max time in ms taken by the excution of this query onto the DB
+	 */
+	public long getExecutionMaxTime() {
+		return executionMaxTime;
+	}
+	
+	/**
+	 * min time in ms taken by the excution of this query onto the DB
+	 */
+	public long getExecutionMinTime() {
+		return executionMinTime;
+	}
+	
+	/**
+	 * add statistics report of a DB query
+	 * 
+	 * @param rows rows count returned
+	 * @param time time taken
+	 */
+	void executed(long rows, long time) {
+		if (time < executionMinTime) executionMinTime = time;
+		if (time > executionMaxTime) executionMaxTime = time;
+		executionAvgTime = ( executionAvgTime * executionCount + time ) / ( executionCount + 1 );
+		executionCount++;
+		executionRowCount += rows;
+	}
+
+	public String toString() {
+		return new StringBuffer()
+				.append( "QueryStatistics" )
+				.append( "[cacheHitCount=" ).append( this.cacheHitCount )
+				.append( ",cacheMissCount=" ).append( this.cacheMissCount )
+				.append( ",cachePutCount=" ).append( this.cachePutCount )
+				.append( ",executionCount=" ).append( this.executionCount )
+				.append( ",executionRowCount=" ).append( this.executionRowCount )
+				.append( ",executionAvgTime=" ).append( this.executionAvgTime )
+				.append( ",executionMaxTime=" ).append( this.executionMaxTime )
+				.append( ",executionMinTime=" ).append( this.executionMinTime )
+				.append( ']' )
+				.toString();
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/QueryStatistics.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SecondLevelCacheStatistics.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SecondLevelCacheStatistics.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SecondLevelCacheStatistics.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,71 @@
+//$Id: SecondLevelCacheStatistics.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.stat;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.cache.CacheKey;
+import org.hibernate.cache.Region;
+
+/**
+ * Second level cache statistics of a specific region
+ * 
+ * @author Gavin King
+ */
+public class SecondLevelCacheStatistics extends CategorizedStatistics {
+	
+    private transient Region region;
+	long hitCount;
+	long missCount;
+	long putCount;
+
+	SecondLevelCacheStatistics(Region region) {
+		super( region.getName() );
+		this.region = region;
+	}
+	public long getHitCount() {
+		return hitCount;
+	}
+	public long getMissCount() {
+		return missCount;
+	}
+	public long getPutCount() {
+		return putCount;
+	}
+	public long getElementCountInMemory() {
+		return region.getElementCountInMemory();
+	}
+	public long getElementCountOnDisk() {
+		return region.getElementCountOnDisk();
+	}
+	public long getSizeInMemory() {
+		return region.getSizeInMemory();
+	}
+	
+	public Map getEntries() {
+		Map map = new HashMap();
+		Iterator iter = region.toMap().entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			map.put( ( (CacheKey) me.getKey() ).getKey(), me.getValue() );
+		}
+		return map;
+	}
+
+	public String toString() {
+		StringBuffer buf = new StringBuffer()
+		    .append("SecondLevelCacheStatistics")
+			.append("[hitCount=").append(this.hitCount)
+			.append(",missCount=").append(this.missCount)
+			.append(",putCount=").append(this.putCount);
+		//not sure if this would ever be null but wanted to be careful
+		if ( region != null ) {
+			buf.append(",elementCountInMemory=").append(this.getElementCountInMemory())
+				.append(",elementCountOnDisk=").append(this.getElementCountOnDisk())
+				.append(",sizeInMemory=").append(this.getSizeInMemory());
+		}
+		buf.append(']');
+		return buf.toString();
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SecondLevelCacheStatistics.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SessionStatistics.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SessionStatistics.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SessionStatistics.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+//$Id: SessionStatistics.java 6750 2005-05-11 15:26:04Z oneovthafew $
+package org.hibernate.stat;
+
+import java.util.Set;
+
+/**
+ * Information about the first-level (session) cache
+ * for a particular session instance
+ * @author Gavin King
+ */
+public interface SessionStatistics {
+
+	/**
+	 * Get the number of entity instances associated with the session
+	 */
+	public int getEntityCount();
+	/**
+	 * Get the number of collection instances associated with the session
+	 */
+	public int getCollectionCount();
+
+	/**
+	 * Get the set of all <tt>EntityKey</tt>s
+	 * @see org.hibernate.engine.EntityKey
+	 */
+	public Set getEntityKeys();
+	/**
+	 * Get the set of all <tt>CollectionKey</tt>s
+	 * @see org.hibernate.engine.CollectionKey
+	 */
+	public Set getCollectionKeys();
+	
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SessionStatistics.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SessionStatisticsImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SessionStatisticsImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SessionStatisticsImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: SessionStatisticsImpl.java 7688 2005-07-29 21:43:18Z epbernard $
+package org.hibernate.stat;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * @author Gavin King
+ */
+public class SessionStatisticsImpl implements SessionStatistics {
+
+	private final SessionImplementor session;
+	
+	public SessionStatisticsImpl(SessionImplementor session) {
+		this.session = session;
+	}
+
+	public int getEntityCount() {
+		return session.getPersistenceContext().getEntityEntries().size();
+	}
+	
+	public int getCollectionCount() {
+		return session.getPersistenceContext().getCollectionEntries().size();
+	}
+	
+	public Set getEntityKeys() {
+		return Collections.unmodifiableSet( session.getPersistenceContext().getEntitiesByKey().keySet() );
+	}
+	
+	public Set getCollectionKeys() {
+		return Collections.unmodifiableSet( session.getPersistenceContext().getCollectionsByKey().keySet() );
+	}
+	
+	public String toString() {
+		return new StringBuffer()
+			.append("SessionStatistics[")
+			.append("entity count=").append( getEntityCount() )
+			.append("collection count=").append( getCollectionCount() )
+			.append(']')
+			.toString();
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/SessionStatisticsImpl.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/Statistics.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/stat/Statistics.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/stat/Statistics.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,211 @@
+//$Id: Statistics.java 8262 2005-09-30 07:48:53Z oneovthafew $
+package org.hibernate.stat;
+
+
+/**
+ * Statistics for a particular <tt>SessionFactory</tt>.
+ * Beware of milliseconds metrics, they are depdendent of the JVM precision:
+ * you may then encounter a 10 ms approximation dending on you OS platform.
+ * Please refer to the JVM documentation for more information.
+ * 
+ * @author Emmanuel Bernard
+ */
+public interface Statistics {
+	/**
+	 * reset all statistics
+	 */
+	public void clear();
+
+    /**
+	 * find entity statistics per name
+	 * 
+	 * @param entityName entity name
+	 * @return EntityStatistics object
+	 */
+	public EntityStatistics getEntityStatistics(String entityName);
+	/**
+	 * Get collection statistics per role
+	 * 
+	 * @param role collection role
+	 * @return CollectionStatistics
+	 */
+	public CollectionStatistics getCollectionStatistics(String role);
+
+    /**
+	 * Second level cache statistics per region
+	 * 
+	 * @param regionName region name
+	 * @return SecondLevelCacheStatistics
+	 */
+	public SecondLevelCacheStatistics getSecondLevelCacheStatistics(String regionName);
+
+    /**
+	 * Query statistics from query string (HQL or SQL)
+	 * 
+	 * @param queryString query string
+	 * @return QueryStatistics
+	 */
+	public QueryStatistics getQueryStatistics(String queryString);
+
+    /**
+     * Get global number of entity deletes
+	 * @return entity deletion count
+	 */
+	public long getEntityDeleteCount();
+
+    /**
+     * Get global number of entity inserts
+	 * @return entity insertion count
+	 */
+	public long getEntityInsertCount();
+
+    /**
+     * Get global number of entity loads
+	 * @return entity load (from DB)
+	 */
+	public long getEntityLoadCount();
+	/**
+     * Get global number of entity fetchs
+	 * @return entity fetch (from DB)
+	 */
+	public long getEntityFetchCount();
+
+	/**
+     * Get global number of entity updates
+	 * @return entity update
+	 */
+	public long getEntityUpdateCount();
+
+    /**
+     * Get global number of executed queries
+	 * @return query execution count
+	 */
+	public long getQueryExecutionCount();
+
+    /**
+     * Get the time in milliseconds of the slowest query.
+     */
+	public long getQueryExecutionMaxTime();
+	/**
+	 * Get the query string for the slowest query.
+	 */
+	public String getQueryExecutionMaxTimeQueryString();
+
+    /**
+     * Get the global number of cached queries successfully retrieved from cache
+     */
+	public long getQueryCacheHitCount();
+    /**
+     * Get the global number of cached queries *not* found in cache
+     */
+	public long getQueryCacheMissCount();
+    /**
+     * Get the global number of cacheable queries put in cache
+     */
+	public long getQueryCachePutCount();
+	/**
+     * Get the global number of flush executed by sessions (either implicit or explicit)
+     */
+	public long getFlushCount();
+	/**
+	 * Get the global number of connections asked by the sessions
+     * (the actual number of connections used may be much smaller depending
+     * whether you use a connection pool or not)
+	 */
+	public long getConnectCount();
+	/**
+     * Global number of cacheable entities/collections successfully retrieved from the cache
+     */
+	public long getSecondLevelCacheHitCount();
+	/**
+     * Global number of cacheable entities/collections not found in the cache and loaded from the database.
+     */
+	public long getSecondLevelCacheMissCount();
+	/**
+	 * Global number of cacheable entities/collections put in the cache
+	 */
+	public long getSecondLevelCachePutCount();
+	/**
+	 * Global number of sessions closed
+	 */
+	public long getSessionCloseCount();
+	/**
+	 * Global number of sessions opened
+	 */
+	public long getSessionOpenCount();
+	/**
+	 * Global number of collections loaded
+	 */
+	public long getCollectionLoadCount();
+	/**
+	 * Global number of collections fetched
+	 */
+	public long getCollectionFetchCount();
+	/**
+	 * Global number of collections updated
+	 */
+	public long getCollectionUpdateCount();
+	/**
+	 * Global number of collections removed
+	 */
+    //even on inverse="true"
+	public long getCollectionRemoveCount();
+	/**
+	 * Global number of collections recreated
+	 */
+	public long getCollectionRecreateCount();
+	/**
+	 * @return start time in ms (JVM standards {@link System#currentTimeMillis()})
+	 */
+	public long getStartTime();
+	/**
+	 * log in info level the main statistics
+	 */
+	public void logSummary();
+	/**
+	 * Are statistics logged
+	 */
+	public boolean isStatisticsEnabled();
+	/**
+	 * Enable statistics logs (this is a dynamic parameter)
+	 */
+	public void setStatisticsEnabled(boolean b);
+
+	/**
+	 * Get all executed query strings
+	 */
+	public String[] getQueries();
+	/**
+	 * Get the names of all entities
+	 */
+	public String[] getEntityNames();
+	/**
+	 * Get the names of all collection roles
+	 */
+	public String[] getCollectionRoleNames();
+	/**
+	 * Get all second-level cache region names
+	 */
+	public String[] getSecondLevelCacheRegionNames();
+	/**
+	 * The number of transactions we know to have been successful
+	 */
+	public long getSuccessfulTransactionCount();
+	/**
+	 * The number of transactions we know to have completed
+	 */
+	public long getTransactionCount();
+	/**
+	 * The number of prepared statements that were acquired
+	 */
+	public long getPrepareStatementCount();
+	/**
+	 * The number of prepared statements that were released
+	 */
+	public long getCloseStatementCount();
+	/**
+	 * The number of <tt>StaleObjectStateException</tt>s 
+	 * that occurred
+	 */
+	public long getOptimisticFailureCount();
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/Statistics.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/StatisticsImpl.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/stat/StatisticsImpl.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/stat/StatisticsImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,640 @@
+//$Id: StatisticsImpl.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.stat;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.cache.Cache;
+import org.hibernate.cache.Region;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * @see org.hibernate.stat.Statistics 
+ *  
+ * @author Gavin King
+ */
+public class StatisticsImpl implements Statistics, StatisticsImplementor {
+	
+	//TODO: we should provide some way to get keys of collection of statistics to make it easier to retrieve from a GUI perspective
+	
+	private static final Log log = LogFactory.getLog(StatisticsImpl.class);
+
+	private SessionFactoryImplementor sessionFactory;
+
+	private boolean isStatisticsEnabled;
+	private long startTime;
+	private long sessionOpenCount;
+	private long sessionCloseCount;
+	private long flushCount;
+	private long connectCount;
+	
+	private long prepareStatementCount;
+	private long closeStatementCount;
+	
+	private long entityLoadCount;
+	private long entityUpdateCount;
+	private long entityInsertCount;
+	private long entityDeleteCount;
+	private long entityFetchCount;
+	private long collectionLoadCount;
+	private long collectionUpdateCount;
+	private long collectionRemoveCount;
+	private long collectionRecreateCount;
+	private long collectionFetchCount;
+	
+	private long secondLevelCacheHitCount;
+	private long secondLevelCacheMissCount;
+	private long secondLevelCachePutCount;
+	
+	private long queryExecutionCount;
+	private long queryExecutionMaxTime;
+	private String queryExecutionMaxTimeQueryString;
+	private long queryCacheHitCount;
+	private long queryCacheMissCount;
+	private long queryCachePutCount;
+	
+	private long commitedTransactionCount;
+	private long transactionCount;
+	
+	private long optimisticFailureCount;
+	
+	/** second level cache statistics per region */
+	private final Map secondLevelCacheStatistics = new HashMap();
+	/** entity statistics per name */
+	private final Map entityStatistics = new HashMap();
+	/** collection statistics per name */
+	private final Map collectionStatistics = new HashMap();
+	/** entity statistics per query string (HQL or SQL) */
+	private final Map queryStatistics = new HashMap();
+
+	public StatisticsImpl() {
+		clear();
+	}
+
+	public StatisticsImpl(SessionFactoryImplementor sessionFactory) {
+		clear();
+		this.sessionFactory = sessionFactory;
+	}
+	
+	/**
+	 * reset all statistics
+	 */
+	public synchronized void clear() {
+		secondLevelCacheHitCount = 0;
+		secondLevelCacheMissCount = 0;
+		secondLevelCachePutCount = 0;
+		
+		sessionCloseCount = 0;
+		sessionOpenCount = 0;
+		flushCount = 0;
+		connectCount = 0;
+		
+		prepareStatementCount = 0;
+		closeStatementCount = 0;
+		
+		entityDeleteCount = 0;
+		entityInsertCount = 0;
+		entityUpdateCount = 0;
+		entityLoadCount = 0;
+		entityFetchCount = 0;
+		
+		collectionRemoveCount = 0;
+		collectionUpdateCount = 0;
+		collectionRecreateCount = 0;
+		collectionLoadCount = 0;
+		collectionFetchCount = 0;
+		
+		queryExecutionCount = 0;
+		queryCacheHitCount = 0;
+		queryExecutionMaxTime = 0;
+		queryExecutionMaxTimeQueryString = null;
+		queryCacheMissCount = 0;
+		queryCachePutCount = 0;
+		
+		transactionCount = 0;
+		commitedTransactionCount = 0;
+		
+		optimisticFailureCount = 0;
+		
+		secondLevelCacheStatistics.clear();
+		entityStatistics.clear();
+		collectionStatistics.clear();
+		queryStatistics.clear();
+		
+		startTime = System.currentTimeMillis();
+	}
+	
+	public synchronized void openSession() {
+		sessionOpenCount++;
+	}
+	
+	public synchronized void closeSession() {
+		sessionCloseCount++;
+	}
+	
+	public synchronized void flush() {
+		flushCount++;
+	}
+	
+	public synchronized void connect() {
+		connectCount++;
+	}
+	
+	public synchronized void loadEntity(String entityName) {
+		entityLoadCount++;
+		getEntityStatistics(entityName).loadCount++;
+	}
+
+	public synchronized void fetchEntity(String entityName) {
+		entityFetchCount++;
+		getEntityStatistics(entityName).fetchCount++;
+	}
+
+	/**
+	 * find entity statistics per name
+	 * 
+	 * @param entityName entity name
+	 * @return EntityStatistics object
+	 */
+	public synchronized EntityStatistics getEntityStatistics(String entityName) {
+		EntityStatistics es = (EntityStatistics) entityStatistics.get(entityName);
+		if (es==null) {
+			es = new EntityStatistics(entityName);
+			entityStatistics.put(entityName, es);
+		}
+		return es;
+	}
+	
+	public synchronized void updateEntity(String entityName) {
+		entityUpdateCount++;
+		EntityStatistics es = getEntityStatistics(entityName);
+		es.updateCount++;
+	}
+
+	public synchronized void insertEntity(String entityName) {
+		entityInsertCount++;
+		EntityStatistics es = getEntityStatistics(entityName);
+		es.insertCount++;
+	}
+
+	public synchronized void deleteEntity(String entityName) {
+		entityDeleteCount++;
+		EntityStatistics es = getEntityStatistics(entityName);
+		es.deleteCount++;
+	}
+
+	/**
+	 * Get collection statistics per role
+	 * 
+	 * @param role collection role
+	 * @return CollectionStatistics
+	 */
+	public synchronized CollectionStatistics getCollectionStatistics(String role) {
+		CollectionStatistics cs = (CollectionStatistics) collectionStatistics.get(role);
+		if (cs==null) {
+			cs = new CollectionStatistics(role);
+			collectionStatistics.put(role, cs);
+		}
+		return cs;
+	}
+	
+	public synchronized void loadCollection(String role) {
+		collectionLoadCount++;
+		getCollectionStatistics(role).loadCount++;
+	}
+
+	public synchronized void fetchCollection(String role) {
+		collectionFetchCount++;
+		getCollectionStatistics(role).fetchCount++;
+	}
+
+	public synchronized void updateCollection(String role) {
+		collectionUpdateCount++;
+		getCollectionStatistics(role).updateCount++;
+	}
+
+	public synchronized void recreateCollection(String role) {
+		collectionRecreateCount++;
+		getCollectionStatistics(role).recreateCount++;
+	}
+
+	public synchronized void removeCollection(String role) {
+		collectionRemoveCount++;
+		getCollectionStatistics(role).removeCount++;
+	}
+	
+	/**
+	 * Second level cache statistics per region
+	 * 
+	 * @param regionName region name
+	 * @return SecondLevelCacheStatistics
+	 */
+	public synchronized SecondLevelCacheStatistics getSecondLevelCacheStatistics(String regionName) {
+		SecondLevelCacheStatistics slcs = ( SecondLevelCacheStatistics ) secondLevelCacheStatistics.get( regionName );
+		if ( slcs == null ) {
+			if ( sessionFactory == null ) {
+				return null;
+			}
+			Region region = sessionFactory.getSecondLevelCacheRegion( regionName );
+			if ( region == null ) {
+				return null;
+			}
+			slcs = new SecondLevelCacheStatistics( region );
+			secondLevelCacheStatistics.put( regionName, slcs );
+		}
+		return slcs;
+	}
+
+	public synchronized void secondLevelCachePut(String regionName) {
+		secondLevelCachePutCount++;
+		getSecondLevelCacheStatistics(regionName).putCount++;
+	}
+
+	public synchronized void secondLevelCacheHit(String regionName) {
+		secondLevelCacheHitCount++;
+		getSecondLevelCacheStatistics(regionName).hitCount++;
+	}
+
+	public synchronized void secondLevelCacheMiss(String regionName) {
+		secondLevelCacheMissCount++;
+		getSecondLevelCacheStatistics(regionName).missCount++;
+	}
+
+	public synchronized void queryExecuted(String hql, int rows, long time) {
+		queryExecutionCount++;
+		if (queryExecutionMaxTime<time) {
+			queryExecutionMaxTime=time;
+			queryExecutionMaxTimeQueryString = hql;
+		}
+		if (hql!=null) {
+			QueryStatistics qs = getQueryStatistics(hql);
+			qs.executed(rows, time);
+		}
+	}
+	
+	public synchronized void queryCacheHit(String hql, String regionName) {
+		queryCacheHitCount++;
+		if (hql!=null) {
+			QueryStatistics qs = getQueryStatistics(hql);
+			qs.cacheHitCount++;
+		}
+		SecondLevelCacheStatistics slcs = getSecondLevelCacheStatistics(regionName);
+		slcs.hitCount++;
+	}
+
+	public synchronized void queryCacheMiss(String hql, String regionName) {
+		queryCacheMissCount++;
+		if (hql!=null) {
+			QueryStatistics qs = getQueryStatistics(hql);
+			qs.cacheMissCount++;
+		}
+		SecondLevelCacheStatistics slcs = getSecondLevelCacheStatistics(regionName);
+		slcs.missCount++;
+	}
+
+	public synchronized void queryCachePut(String hql, String regionName) {
+		queryCachePutCount++;
+		if (hql!=null) {
+			QueryStatistics qs = getQueryStatistics(hql);
+			qs.cachePutCount++;
+		}
+		SecondLevelCacheStatistics slcs = getSecondLevelCacheStatistics(regionName);
+		slcs.putCount++;
+	}
+
+	/**
+	 * Query statistics from query string (HQL or SQL)
+	 * 
+	 * @param queryString query string
+	 * @return QueryStatistics
+	 */
+	public synchronized QueryStatistics getQueryStatistics(String queryString) {
+		QueryStatistics qs = (QueryStatistics) queryStatistics.get(queryString);
+		if (qs==null) {
+			qs = new QueryStatistics(queryString);
+			queryStatistics.put(queryString, qs);
+		}
+		return qs;
+	}
+
+	/**
+	 * @return entity deletion count
+	 */
+	public long getEntityDeleteCount() {
+		return entityDeleteCount;
+	}
+	
+	/**
+	 * @return entity insertion count
+	 */
+	public long getEntityInsertCount() {
+		return entityInsertCount;
+	}
+	
+	/**
+	 * @return entity load (from DB)
+	 */
+	public long getEntityLoadCount() {
+		return entityLoadCount;
+	}
+	
+	/**
+	 * @return entity fetch (from DB)
+	 */
+	public long getEntityFetchCount() {
+		return entityFetchCount;
+	}
+
+	/**
+	 * @return entity update
+	 */
+	public long getEntityUpdateCount() {
+		return entityUpdateCount;
+	}
+
+	public long getQueryExecutionCount() {
+		return queryExecutionCount;
+	}
+	
+	public long getQueryCacheHitCount() {
+		return queryCacheHitCount;
+	}
+	
+	public long getQueryCacheMissCount() {
+		return queryCacheMissCount;
+	}
+	
+	public long getQueryCachePutCount() {
+		return queryCachePutCount;
+	}
+	
+	/**
+	 * @return flush
+	 */
+	public long getFlushCount() {
+		return flushCount;
+	}
+	
+	/**
+	 * @return session connect
+	 */
+	public long getConnectCount() {
+		return connectCount;
+	}
+
+	/**
+	 * @return second level cache hit
+	 */
+	public long getSecondLevelCacheHitCount() {
+		return secondLevelCacheHitCount;
+	}
+
+	/**
+	 * @return second level cache miss
+	 */
+	public long getSecondLevelCacheMissCount() {
+		return secondLevelCacheMissCount;
+	}
+	
+	/**
+	 * @return second level cache put
+	 */
+	public long getSecondLevelCachePutCount() {
+		return secondLevelCachePutCount;
+	}
+
+	/**
+	 * @return session closing
+	 */
+	public long getSessionCloseCount() {
+		return sessionCloseCount;
+	}
+	
+	/**
+	 * @return session opening
+	 */
+	public long getSessionOpenCount() {
+		return sessionOpenCount;
+	}
+
+	/**
+	 * @return collection loading (from DB)
+	 */
+	public long getCollectionLoadCount() {
+		return collectionLoadCount;
+	}
+
+	/**
+	 * @return collection fetching (from DB)
+	 */
+	public long getCollectionFetchCount() {
+		return collectionFetchCount;
+	}
+	
+	/**
+	 * @return collection update
+	 */
+	public long getCollectionUpdateCount() {
+		return collectionUpdateCount;
+	}
+
+	/**
+	 * @return collection removal
+	 * FIXME: even if isInverse="true"?
+	 */
+	public long getCollectionRemoveCount() {
+		return collectionRemoveCount;
+	}
+	/**
+	 * @return collection recreation
+	 */
+	public long getCollectionRecreateCount() {
+		return collectionRecreateCount;
+	}
+
+	/**
+	 * @return start time in ms (JVM standards {@link System#currentTimeMillis()})
+	 */
+	public long getStartTime() {
+		return startTime;
+	}
+	
+	/**
+	 * log in info level the main statistics
+	 */
+	public void logSummary() {
+		log.info("Logging statistics....");
+		log.info("start time: " + startTime);
+		log.info("sessions opened: " + sessionOpenCount);
+		log.info("sessions closed: " + sessionCloseCount);
+		log.info("transactions: " + transactionCount);
+		log.info("successful transactions: " + commitedTransactionCount);
+		log.info("optimistic lock failures: " + optimisticFailureCount);
+		log.info("flushes: " + flushCount);
+		log.info("connections obtained: " + connectCount);
+		log.info("statements prepared: " + prepareStatementCount);
+		log.info("statements closed: " + closeStatementCount);
+		log.info("second level cache puts: " + secondLevelCachePutCount);
+		log.info("second level cache hits: " + secondLevelCacheHitCount);
+		log.info("second level cache misses: " + secondLevelCacheMissCount);
+		log.info("entities loaded: " + entityLoadCount);
+		log.info("entities updated: " + entityUpdateCount);
+		log.info("entities inserted: " + entityInsertCount);
+		log.info("entities deleted: " + entityDeleteCount);
+		log.info("entities fetched (minimize this): " + entityFetchCount);
+		log.info("collections loaded: " + collectionLoadCount);
+		log.info("collections updated: " + collectionUpdateCount);
+		log.info("collections removed: " + collectionRemoveCount);
+		log.info("collections recreated: " + collectionRecreateCount);
+		log.info("collections fetched (minimize this): " + collectionFetchCount);
+		log.info("queries executed to database: " + queryExecutionCount);
+		log.info("query cache puts: " + queryCachePutCount);
+		log.info("query cache hits: " + queryCacheHitCount);
+		log.info("query cache misses: " + queryCacheMissCount);
+		log.info("max query time: " + queryExecutionMaxTime + "ms");
+	}
+	
+	/**
+	 * Are statistics logged
+	 */
+	public boolean isStatisticsEnabled() {
+		return isStatisticsEnabled;
+	}
+	
+	/**
+	 * Enable statistics logs (this is a dynamic parameter)
+	 */
+	public void setStatisticsEnabled(boolean b) {
+		isStatisticsEnabled = b;
+	}
+
+	/**
+	 * @return Returns the max query execution time,
+	 * for all queries
+	 */
+	public long getQueryExecutionMaxTime() {
+		return queryExecutionMaxTime;
+	}
+	
+	/**
+	 * Get all executed query strings
+	 */
+	public String[] getQueries() {
+		return ArrayHelper.toStringArray( queryStatistics.keySet() );
+	}
+	
+	/**
+	 * Get the names of all entities
+	 */
+	public String[] getEntityNames() {
+		if (sessionFactory==null) {
+			return ArrayHelper.toStringArray( entityStatistics.keySet() );
+		}
+		else {
+			return ArrayHelper.toStringArray( sessionFactory.getAllClassMetadata().keySet() );
+		}
+	}
+
+	/**
+	 * Get the names of all collection roles
+	 */
+	public String[] getCollectionRoleNames() {
+		if (sessionFactory==null) {
+			return ArrayHelper.toStringArray( collectionStatistics.keySet() );
+		}
+		else {
+			return ArrayHelper.toStringArray( sessionFactory.getAllCollectionMetadata().keySet() );
+		}
+	}
+	
+	/**
+	 * Get all second-level cache region names
+	 */
+	public String[] getSecondLevelCacheRegionNames() {
+		if (sessionFactory==null) {
+			return ArrayHelper.toStringArray( secondLevelCacheStatistics.keySet() );
+		}
+		else {
+			return ArrayHelper.toStringArray( sessionFactory.getAllSecondLevelCacheRegions().keySet() );
+		}
+	}
+
+	public void endTransaction(boolean success) {
+		transactionCount++;
+		if (success) commitedTransactionCount++;
+	}
+	
+	public long getSuccessfulTransactionCount() {
+		return commitedTransactionCount;
+	}
+	
+	public long getTransactionCount() {
+		return transactionCount;
+	}
+
+	public void closeStatement() {
+		closeStatementCount++;
+	}
+
+	public void prepareStatement() {
+		prepareStatementCount++;
+	}
+
+	public long getCloseStatementCount() {
+		return closeStatementCount;
+	}
+
+	public long getPrepareStatementCount() {
+		return prepareStatementCount;
+	}
+
+	public void optimisticFailure(String entityName) {
+		optimisticFailureCount++;
+		getEntityStatistics(entityName).optimisticFailureCount++;
+	}
+
+	public long getOptimisticFailureCount() {
+		return optimisticFailureCount;
+	}
+	public String toString() {
+		return new StringBuffer()
+			.append("Statistics[")
+			.append("start time=").append(startTime)
+			.append(",sessions opened=").append(sessionOpenCount)
+			.append(",sessions closed=").append(sessionCloseCount)
+			.append(",transactions=").append(transactionCount)
+			.append(",successful transactions=").append(commitedTransactionCount)
+			.append(",optimistic lock failures=").append(optimisticFailureCount)
+			.append(",flushes=").append(flushCount)
+			.append(",connections obtained=").append(connectCount)
+			.append(",statements prepared=").append(prepareStatementCount)
+			.append(",statements closed=").append(closeStatementCount)
+			.append(",second level cache puts=").append(secondLevelCachePutCount)
+			.append(",second level cache hits=").append(secondLevelCacheHitCount)
+			.append(",second level cache misses=").append(secondLevelCacheMissCount)
+			.append(",entities loaded=").append(entityLoadCount)
+			.append(",entities updated=").append(entityUpdateCount)
+			.append(",entities inserted=").append(entityInsertCount)
+			.append(",entities deleted=").append(entityDeleteCount)
+			.append(",entities fetched=").append(entityFetchCount)
+			.append(",collections loaded=").append(collectionLoadCount)
+			.append(",collections updated=").append(collectionUpdateCount)
+			.append(",collections removed=").append(collectionRemoveCount)
+			.append(",collections recreated=").append(collectionRecreateCount)
+			.append(",collections fetched=").append(collectionFetchCount)
+			.append(",queries executed to database=").append(queryExecutionCount)
+			.append(",query cache puts=").append(queryCachePutCount)
+			.append(",query cache hits=").append(queryCacheHitCount)
+			.append(",query cache misses=").append(queryCacheMissCount)
+			.append(",max query time=").append(queryExecutionMaxTime)
+			.append(']')
+			.toString();
+	}
+
+	public String getQueryExecutionMaxTimeQueryString() {
+		return queryExecutionMaxTimeQueryString;
+	}
+	
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/StatisticsImplementor.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/stat/StatisticsImplementor.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/stat/StatisticsImplementor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: StatisticsImplementor.java 7864 2005-08-11 23:22:52Z oneovthafew $
+package org.hibernate.stat;
+
+/**
+ * Statistics SPI for the Hibernate core
+ * 
+ * @author Emmanuel Bernard
+ */
+public interface StatisticsImplementor {
+	public void openSession();
+	public void closeSession();
+	public void flush();
+	public void connect();
+	public void loadEntity(String entityName);
+	public void fetchEntity(String entityName);
+	public void updateEntity(String entityName);
+	public void insertEntity(String entityName);
+	public void deleteEntity(String entityName);
+	public void loadCollection(String role);
+	public void fetchCollection(String role);
+	public void updateCollection(String role);
+	public void recreateCollection(String role);
+	public void removeCollection(String role);
+	public void secondLevelCachePut(String regionName);
+	public void secondLevelCacheHit(String regionName);
+	public void secondLevelCacheMiss(String regionName);
+	public void queryExecuted(String hql, int rows, long time);
+	public void queryCacheHit(String hql, String regionName);
+	public void queryCacheMiss(String hql, String regionName);
+	public void queryCachePut(String hql, String regionName);
+	public void endTransaction(boolean success);
+	public void closeStatement();
+	public void prepareStatement();
+	public void optimisticFailure(String entityName);
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/stat/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/stat/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package exposes statistics about a running 
+	Hibernate instance to the application.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/stat/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ColumnMetadata.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ColumnMetadata.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ColumnMetadata.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+//$Id: ColumnMetadata.java 7854 2005-08-11 20:41:21Z oneovthafew $
+package org.hibernate.tool.hbm2ddl;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.StringTokenizer;
+
+/**
+ * JDBC column metadata
+ * @author Christoph Sturm
+ */
+public class ColumnMetadata {
+	private final String name;
+	private final String typeName;
+	private final int columnSize;
+	private final int decimalDigits;
+	private final String isNullable;
+	private final int typeCode;
+
+	ColumnMetadata(ResultSet rs) throws SQLException {
+		name = rs.getString("COLUMN_NAME");
+		columnSize = rs.getInt("COLUMN_SIZE");
+		decimalDigits = rs.getInt("DECIMAL_DIGITS");
+		isNullable = rs.getString("IS_NULLABLE");
+		typeCode = rs.getInt("DATA_TYPE");
+		typeName = new StringTokenizer( rs.getString("TYPE_NAME"), "() " ).nextToken();
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public String getTypeName() {
+		return typeName;
+	}
+
+	public int getColumnSize() {
+		return columnSize;
+	}
+
+	public int getDecimalDigits() {
+		return decimalDigits;
+	}
+
+	public String getNullable() {
+		return isNullable;
+	}
+
+	public String toString() {
+		return "ColumnMetadata(" + name + ')';
+	}
+
+	public int getTypeCode() {
+		return typeCode;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ConnectionHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ConnectionHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ConnectionHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+package org.hibernate.tool.hbm2ddl;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * Contract for delegates responsible for managing connection used by the
+ * hbm2ddl tools.
+ *
+ * @author Steve Ebersole
+ */
+interface ConnectionHelper {
+	/**
+	 * Prepare the helper for use.
+	 *
+	 * @param needsAutoCommit Should connection be forced to auto-commit
+	 * if not already.
+	 * @throws SQLException
+	 */
+	public void prepare(boolean needsAutoCommit) throws SQLException;
+
+	/**
+	 * Get a reference to the connection we are using.
+	 *
+	 * @return The JDBC connection.
+	 * @throws SQLException
+	 */
+	public Connection getConnection() throws SQLException;
+
+	/**
+	 * Release any resources held by this helper.
+	 *
+	 * @throws SQLException
+	 */
+	public void release() throws SQLException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/DatabaseMetadata.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/DatabaseMetadata.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/DatabaseMetadata.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,181 @@
+//$Id: DatabaseMetadata.java 10726 2006-11-06 14:50:05Z max.andersen at jboss.com $
+package org.hibernate.tool.hbm2ddl;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.mapping.Table;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.util.StringHelper;
+
+/**
+ * JDBC database metadata
+ * @author Christoph Sturm, Teodor Danciu
+ */
+public class DatabaseMetadata {
+	
+	private static final Log log = LogFactory.getLog(DatabaseMetadata.class);
+	
+	private final Map tables = new HashMap();
+	private final Set sequences = new HashSet();
+	private final boolean extras;
+
+	private DatabaseMetaData meta;
+	private SQLExceptionConverter sqlExceptionConverter;
+
+	public DatabaseMetadata(Connection connection, Dialect dialect) throws SQLException {
+		this(connection, dialect, true);
+	}
+
+	public DatabaseMetadata(Connection connection, Dialect dialect, boolean extras) throws SQLException {
+		sqlExceptionConverter = dialect.buildSQLExceptionConverter();
+		meta = connection.getMetaData();
+		this.extras = extras;
+		initSequences(connection, dialect);
+	}
+
+	private static final String[] TYPES = {"TABLE"};
+
+	public TableMetadata getTableMetadata(String name, String schema, String catalog, boolean isQuoted) throws HibernateException {
+
+		Object identifier = identifier(catalog, schema, name);
+		TableMetadata table = (TableMetadata) tables.get(identifier);
+		if (table!=null) {
+			return table;
+		}
+		else {
+			
+			try {
+				ResultSet rs = null;
+				try {
+					if ( (isQuoted && meta.storesMixedCaseQuotedIdentifiers())) {
+						rs = meta.getTables(catalog, schema, name, TYPES);
+					} else if ( (isQuoted && meta.storesUpperCaseQuotedIdentifiers()) 
+						|| (!isQuoted && meta.storesUpperCaseIdentifiers() )) {
+						rs = meta.getTables( 
+								StringHelper.toUpperCase(catalog), 
+								StringHelper.toUpperCase(schema), 
+								StringHelper.toUpperCase(name), 
+								TYPES 
+							);
+					}
+					else if ( (isQuoted && meta.storesLowerCaseQuotedIdentifiers())
+							|| (!isQuoted && meta.storesLowerCaseIdentifiers() )) {
+						rs = meta.getTables( 
+								StringHelper.toLowerCase(catalog), 
+								StringHelper.toLowerCase(schema), 
+								StringHelper.toLowerCase(name), 
+								TYPES 
+							);
+					}
+					else {
+						rs = meta.getTables(catalog, schema, name, TYPES);
+					}
+					
+					while ( rs.next() ) {
+						String tableName = rs.getString("TABLE_NAME");
+						if ( name.equalsIgnoreCase(tableName) ) {
+							table = new TableMetadata(rs, meta, extras);
+							tables.put(identifier, table);
+							return table;
+						}
+					}
+					
+					log.info("table not found: " + name);
+					return null;
+
+				}
+				finally {
+					if (rs!=null) rs.close();
+				}
+			}
+			catch (SQLException sqle) {
+				throw JDBCExceptionHelper.convert(
+                        sqlExceptionConverter,
+				        sqle,
+				        "could not get table metadata: " + name
+					);
+			}
+		}
+
+	}
+
+	private Object identifier(String catalog, String schema, String name) {
+		return Table.qualify(catalog,schema,name);
+	}
+
+	private void initSequences(Connection connection, Dialect dialect) throws SQLException {
+		if ( dialect.supportsSequences() ) {
+			String sql = dialect.getQuerySequencesString();
+			if (sql!=null) {
+	
+				Statement statement = null;
+				ResultSet rs = null;
+				try {
+					statement = connection.createStatement();
+					rs = statement.executeQuery(sql);
+		
+					while ( rs.next() ) {
+						sequences.add( rs.getString(1).toLowerCase().trim() );
+					}
+				}
+				finally {
+					if (rs!=null) rs.close();
+					if (statement!=null) statement.close();
+				}
+				
+			}
+		}
+	}
+
+	public boolean isSequence(Object key) {
+		if (key instanceof String){
+			String[] strings = StringHelper.split(".", (String) key);
+			return sequences.contains( strings[strings.length-1].toLowerCase());
+		}
+		return false;
+	}
+
+ 	public boolean isTable(Object key) throws HibernateException {
+ 		if(key instanceof String) {
+			Table tbl = new Table((String)key);
+			if ( getTableMetadata( tbl.getName(), tbl.getSchema(), tbl.getCatalog(), tbl.isQuoted() ) != null ) {
+ 				return true;
+ 			} else {
+ 				String[] strings = StringHelper.split(".", (String) key);
+ 				if(strings.length==3) {
+					tbl = new Table(strings[2]);
+					tbl.setCatalog(strings[0]);
+					tbl.setSchema(strings[1]);
+					return getTableMetadata( tbl.getName(), tbl.getSchema(), tbl.getCatalog(), tbl.isQuoted() ) != null;
+ 				} else if (strings.length==2) {
+					tbl = new Table(strings[1]);
+					tbl.setSchema(strings[0]);
+					return getTableMetadata( tbl.getName(), tbl.getSchema(), tbl.getCatalog(), tbl.isQuoted() ) != null;
+ 				}
+ 			}
+ 		}
+ 		return false;
+ 	}
+ 	
+	public String toString() {
+		return "DatabaseMetadata" + tables.keySet().toString() + sequences.toString();
+	}
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ForeignKeyMetadata.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ForeignKeyMetadata.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ForeignKeyMetadata.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+//$Id: ForeignKeyMetadata.java 4279 2004-08-13 08:05:47Z oneovthafew $
+package org.hibernate.tool.hbm2ddl;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * JDBC foreign key metadata
+ * @author Christoph Sturm
+ */
+public class ForeignKeyMetadata {
+	private final String name;
+	private final List columns = new ArrayList();
+
+	ForeignKeyMetadata(ResultSet rs) throws SQLException {
+		name = rs.getString("FK_NAME");
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	void addColumn(ColumnMetadata column) {
+		if (column != null) columns.add(column);
+	}
+
+	public ColumnMetadata[] getColumns() {
+		return (ColumnMetadata[]) columns.toArray(new ColumnMetadata[0]);
+	}
+
+	public String toString() {
+		return "ForeignKeyMetadata(" + name + ')';
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/IndexMetadata.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/IndexMetadata.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/IndexMetadata.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+//$Id: IndexMetadata.java 4279 2004-08-13 08:05:47Z oneovthafew $
+package org.hibernate.tool.hbm2ddl;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * JDBC index metadata
+ * @author Christoph Sturm
+ */
+public class IndexMetadata {
+	private final String name;
+	private final List columns = new ArrayList();
+
+	IndexMetadata(ResultSet rs) throws SQLException {
+		name = rs.getString("INDEX_NAME");
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	void addColumn(ColumnMetadata column) {
+		if (column != null) columns.add(column);
+	}
+
+	public ColumnMetadata[] getColumns() {
+		return (ColumnMetadata[]) columns.toArray(new ColumnMetadata[0]);
+	}
+
+	public String toString() {
+		return "IndexMatadata(" + name + ')';
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ManagedProviderConnectionHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ManagedProviderConnectionHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/ManagedProviderConnectionHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+package org.hibernate.tool.hbm2ddl;
+
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.connection.ConnectionProviderFactory;
+import org.hibernate.util.JDBCExceptionReporter;
+
+import java.util.Properties;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * A {@link ConnectionHelper} implementation based on an internally
+ * built and managed {@link ConnectionProvider}.
+ *
+ * @author Steve Ebersole
+ */
+class ManagedProviderConnectionHelper implements ConnectionHelper {
+	private Properties cfgProperties;
+	private ConnectionProvider connectionProvider;
+	private Connection connection;
+
+	public ManagedProviderConnectionHelper(Properties cfgProperties) {
+		this.cfgProperties = cfgProperties;
+	}
+
+	public void prepare(boolean needsAutoCommit) throws SQLException {
+		connectionProvider = ConnectionProviderFactory.newConnectionProvider( cfgProperties );
+		connection = connectionProvider.getConnection();
+		if ( needsAutoCommit && !connection.getAutoCommit() ) {
+			connection.commit();
+			connection.setAutoCommit( true );
+		}
+	}
+
+	public Connection getConnection() throws SQLException {
+		return connection;
+	}
+
+	public void release() throws SQLException {
+		if ( connection != null ) {
+			try {
+				JDBCExceptionReporter.logAndClearWarnings( connection );
+				connectionProvider.closeConnection( connection );
+			}
+			finally {
+				connectionProvider.close();
+			}
+		}
+		connection = null;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,436 @@
+//$Id: SchemaExport.java 10765 2006-11-08 04:30:27Z steve.ebersole at jboss.com $
+package org.hibernate.tool.hbm2ddl;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.Writer;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.SQLWarning;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.JDBCException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.NamingStrategy;
+import org.hibernate.cfg.Settings;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.pretty.DDLFormatter;
+import org.hibernate.util.ConfigHelper;
+import org.hibernate.util.PropertiesHelper;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.JDBCExceptionReporter;
+
+/**
+ * Commandline tool to export table schema to the database. This
+ * class may also be called from inside an application.
+ *
+ * @author Daniel Bradby, Gavin King
+ */
+public class SchemaExport {
+
+	private static final Log log = LogFactory.getLog( SchemaExport.class );
+
+	private ConnectionHelper connectionHelper;
+	private String[] dropSQL;
+	private String[] createSQL;
+	private String outputFile = null;
+	private String importFile = "/import.sql";
+	private Dialect dialect;
+	private String delimiter;
+	private final List exceptions = new ArrayList();
+	private boolean haltOnError = false;
+	private boolean format = true;
+
+	/**
+	 * Create a schema exporter for the given Configuration
+	 */
+	public SchemaExport(Configuration cfg) throws HibernateException {
+		this( cfg, cfg.getProperties() );
+	}
+
+	/**
+	 * Create a schema exporter for the given Configuration
+	 * and given settings
+	 */
+	public SchemaExport(Configuration cfg, Settings settings) throws HibernateException {
+		dialect = settings.getDialect();
+		connectionHelper = new SuppliedConnectionProviderConnectionHelper(
+				settings.getConnectionProvider()
+		);
+		dropSQL = cfg.generateDropSchemaScript( dialect );
+		createSQL = cfg.generateSchemaCreationScript( dialect );
+		format = settings.isFormatSqlEnabled();
+	}
+
+	/**
+	 * Create a schema exporter for the given Configuration, with the given
+	 * database connection properties.
+	 *
+	 * @deprecated properties may be specified via the Configuration object
+	 */
+	public SchemaExport(Configuration cfg, Properties properties)
+			throws HibernateException {
+		dialect = Dialect.getDialect( properties );
+
+		Properties props = new Properties();
+		props.putAll( dialect.getDefaultProperties() );
+		props.putAll( properties );
+
+		connectionHelper = new ManagedProviderConnectionHelper( props );
+		dropSQL = cfg.generateDropSchemaScript( dialect );
+		createSQL = cfg.generateSchemaCreationScript( dialect );
+		format = PropertiesHelper.getBoolean( Environment.FORMAT_SQL, props );
+	}
+
+	public SchemaExport(Configuration cfg, Connection connection) {
+		this.connectionHelper = new SuppliedConnectionHelper( connection );
+		dialect = Dialect.getDialect( cfg.getProperties() );
+		dropSQL = cfg.generateDropSchemaScript( dialect );
+		createSQL = cfg.generateSchemaCreationScript( dialect );
+	}
+
+	/**
+	 * Set an output filename. The generated script will be written to this file.
+	 */
+	public SchemaExport setOutputFile(String filename) {
+		outputFile = filename;
+		return this;
+	}
+
+	public SchemaExport setImportFile(String filename) {
+		importFile = filename;
+		return this;
+	}
+
+	/**
+	 * Set the end of statement delimiter
+	 */
+	public SchemaExport setDelimiter(String delimiter) {
+		this.delimiter = delimiter;
+		return this;
+	}
+
+	/**
+	 * Run the schema creation script.
+	 *
+	 * @param script print the DDL to the console
+	 * @param export export the script to the database
+	 */
+	public void create(boolean script, boolean export) {
+		execute( script, export, false, false );
+	}
+
+	/**
+	 * Run the drop schema script.
+	 *
+	 * @param script print the DDL to the console
+	 * @param export export the script to the database
+	 */
+	public void drop(boolean script, boolean export) {
+		execute( script, export, true, false );
+	}
+
+	private String format(String sql) {
+		return format ?
+		       new DDLFormatter( sql ).format() :
+		       sql;
+	}
+
+	public void execute(boolean script, boolean export, boolean justDrop, boolean justCreate) {
+
+		log.info( "Running hbm2ddl schema export" );
+
+		Connection connection = null;
+		Writer outputFileWriter = null;
+		Reader importFileReader = null;
+		Statement statement = null;
+
+		exceptions.clear();
+
+		try {
+
+			try {
+				InputStream stream = ConfigHelper.getResourceAsStream( importFile );
+				importFileReader = new InputStreamReader( stream );
+			}
+			catch ( HibernateException e ) {
+				log.debug( "import file not found: " + importFile );
+			}
+
+			if ( outputFile != null ) {
+				log.info( "writing generated schema to file: " + outputFile );
+				outputFileWriter = new FileWriter( outputFile );
+			}
+
+			if ( export ) {
+				log.info( "exporting generated schema to database" );
+				connectionHelper.prepare( true );
+				connection = connectionHelper.getConnection();
+				statement = connection.createStatement();
+			}
+
+			if ( !justCreate ) {
+				drop( script, export, outputFileWriter, statement );
+			}
+
+			if ( !justDrop ) {
+				create( script, export, outputFileWriter, statement );
+				if ( export && importFileReader != null ) {
+					importScript( importFileReader, statement );
+				}
+			}
+
+			log.info( "schema export complete" );
+
+		}
+
+		catch ( Exception e ) {
+			exceptions.add( e );
+			log.error( "schema export unsuccessful", e );
+		}
+
+		finally {
+
+			try {
+				if ( statement != null ) {
+					statement.close();
+				}
+				if ( connection != null ) {
+					connectionHelper.release();
+				}
+			}
+			catch ( Exception e ) {
+				exceptions.add( e );
+				log.error( "Could not close connection", e );
+			}
+
+			try {
+				if ( outputFileWriter != null ) {
+					outputFileWriter.close();
+				}
+				if ( importFileReader != null ) {
+					importFileReader.close();
+				}
+			}
+			catch ( IOException ioe ) {
+				exceptions.add( ioe );
+				log.error( "Error closing output file: " + outputFile, ioe );
+			}
+
+		}
+	}
+
+	private void importScript(Reader importFileReader, Statement statement)
+			throws IOException {
+		log.info( "Executing import script: " + importFile );
+		BufferedReader reader = new BufferedReader( importFileReader );
+		long lineNo = 0;
+		for ( String sql = reader.readLine(); sql != null; sql = reader.readLine() ) {
+			try {
+				lineNo++;
+				String trimmedSql = sql.trim();
+				if ( trimmedSql.length() == 0 ||
+				     trimmedSql.startsWith( "--" ) ||
+				     trimmedSql.startsWith( "//" ) ||
+				     trimmedSql.startsWith( "/*" ) ) {
+					continue;
+				}
+				else {
+					if ( trimmedSql.endsWith( ";" ) ) {
+						trimmedSql = trimmedSql.substring( 0, trimmedSql.length() - 1 );
+					}
+					log.debug( trimmedSql );
+					statement.execute( trimmedSql );
+				}
+			}
+			catch ( SQLException e ) {
+				throw new JDBCException( "Error during import script execution at line " + lineNo, e );
+			}
+		}
+	}
+
+	private void create(boolean script, boolean export, Writer fileOutput, Statement statement)
+			throws IOException {
+		for ( int j = 0; j < createSQL.length; j++ ) {
+			try {
+				execute( script, export, fileOutput, statement, createSQL[j] );
+			}
+			catch ( SQLException e ) {
+				if ( haltOnError ) {
+					throw new JDBCException( "Error during DDL export", e );
+				}
+				exceptions.add( e );
+				log.error( "Unsuccessful: " + createSQL[j] );
+				log.error( e.getMessage() );
+			}
+		}
+	}
+
+	private void drop(boolean script, boolean export, Writer fileOutput, Statement statement)
+			throws IOException {
+		for ( int i = 0; i < dropSQL.length; i++ ) {
+			try {
+				execute( script, export, fileOutput, statement, dropSQL[i] );
+			}
+			catch ( SQLException e ) {
+				exceptions.add( e );
+				log.debug( "Unsuccessful: " + dropSQL[i] );
+				log.debug( e.getMessage() );
+			}
+		}
+	}
+
+	private void execute(boolean script, boolean export, Writer fileOutput, Statement statement, final String sql)
+			throws IOException, SQLException {
+		String formatted = format( sql );
+		if ( delimiter != null ) {
+			formatted += delimiter;
+		}
+		if ( script ) {
+			System.out.println( formatted );
+		}
+		log.debug( formatted );
+		if ( outputFile != null ) {
+			fileOutput.write( formatted + "\n" );
+		}
+		if ( export ) {
+			statement.executeUpdate( sql );
+			try {
+				SQLWarning warnings = statement.getWarnings();
+				if ( warnings != null) {
+					JDBCExceptionReporter.logAndClearWarnings( connectionHelper.getConnection() );
+				}
+			}
+			catch( SQLException sqle ) {
+				log.warn( "unable to log SQLWarnings : " + sqle );
+			}
+		}
+
+		
+	}
+
+	public static void main(String[] args) {
+		try {
+			Configuration cfg = new Configuration();
+
+			boolean script = true;
+			boolean drop = false;
+			boolean create = false;
+			boolean halt = false;
+			boolean export = true;
+			String outFile = null;
+			String importFile = "/import.sql";
+			String propFile = null;
+			boolean format = false;
+			String delim = null;
+
+			for ( int i = 0; i < args.length; i++ ) {
+				if ( args[i].startsWith( "--" ) ) {
+					if ( args[i].equals( "--quiet" ) ) {
+						script = false;
+					}
+					else if ( args[i].equals( "--drop" ) ) {
+						drop = true;
+					}
+					else if ( args[i].equals( "--create" ) ) {
+						create = true;
+					}
+					else if ( args[i].equals( "--haltonerror" ) ) {
+						halt = true;
+					}
+					else if ( args[i].equals( "--text" ) ) {
+						export = false;
+					}
+					else if ( args[i].startsWith( "--output=" ) ) {
+						outFile = args[i].substring( 9 );
+					}
+					else if ( args[i].startsWith( "--import=" ) ) {
+						importFile = args[i].substring( 9 );
+					}
+					else if ( args[i].startsWith( "--properties=" ) ) {
+						propFile = args[i].substring( 13 );
+					}
+					else if ( args[i].equals( "--format" ) ) {
+						format = true;
+					}
+					else if ( args[i].startsWith( "--delimiter=" ) ) {
+						delim = args[i].substring( 12 );
+					}
+					else if ( args[i].startsWith( "--config=" ) ) {
+						cfg.configure( args[i].substring( 9 ) );
+					}
+					else if ( args[i].startsWith( "--naming=" ) ) {
+						cfg.setNamingStrategy(
+								( NamingStrategy ) ReflectHelper.classForName( args[i].substring( 9 ) )
+										.newInstance()
+						);
+					}
+				}
+				else {
+					String filename = args[i];
+					if ( filename.endsWith( ".jar" ) ) {
+						cfg.addJar( new File( filename ) );
+					}
+					else {
+						cfg.addFile( filename );
+					}
+				}
+
+			}
+
+			if ( propFile != null ) {
+				Properties props = new Properties();
+				props.putAll( cfg.getProperties() );
+				props.load( new FileInputStream( propFile ) );
+				cfg.setProperties( props );
+			}
+
+			SchemaExport se = new SchemaExport( cfg )
+					.setHaltOnError( halt )
+					.setOutputFile( outFile )
+					.setImportFile( importFile )
+					.setDelimiter( delim );
+			if ( format ) {
+				se.setFormat( true );
+			}
+			se.execute( script, export, drop, create );
+
+		}
+		catch ( Exception e ) {
+			log.error( "Error creating schema ", e );
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * Returns a List of all Exceptions which occured during the export.
+	 *
+	 * @return A List containig the Exceptions occured during the export
+	 */
+	public List getExceptions() {
+		return exceptions;
+	}
+
+	public SchemaExport setFormat(boolean format) {
+		this.format = format;
+		return this;
+	}
+
+	public SchemaExport setHaltOnError(boolean haltOnError) {
+		this.haltOnError = haltOnError;
+		return this;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExportTask.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExportTask.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExportTask.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,232 @@
+//$Id: SchemaExportTask.java 7863 2005-08-11 23:11:03Z oneovthafew $
+package org.hibernate.tool.hbm2ddl;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.NamingStrategy;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.ReflectHelper;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.FileSet;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * An Ant task for <tt>SchemaExport</tt>.
+ *
+ * <pre>
+ * &lt;taskdef name="schemaexport"
+ *     classname="org.hibernate.tool.hbm2ddl.SchemaExportTask"
+ *     classpathref="class.path"/&gt;
+ *
+ * &lt;schemaexport
+ *     properties="${build.classes.dir}/hibernate.properties"
+ *     quiet="no"
+ *     text="no"
+ *     drop="no"
+ *     delimiter=";"
+ *     output="${build.dir}/schema-export.sql"&gt;
+ *     &lt;fileset dir="${build.classes.dir}"&gt;
+ *         &lt;include name="*.hbm.xml"/&gt;
+ *     &lt;/fileset&gt;
+ * &lt;/schemaexport&gt;
+ * </pre>
+ *
+ * @see SchemaExport
+ * @author Rong C Ou
+ */
+public class SchemaExportTask extends MatchingTask {
+
+	private List fileSets = new LinkedList();
+	private File propertiesFile = null;
+	private File configurationFile = null;
+	private File outputFile = null;
+	private boolean quiet = false;
+	private boolean text = false;
+	private boolean drop = false;
+	private boolean create = false;
+	private boolean haltOnError = false;
+	private String delimiter = null;
+	private String namingStrategy = null;
+
+	public void addFileset(FileSet set) {
+		fileSets.add(set);
+	}
+
+	/**
+	 * Set a properties file
+	 * @param propertiesFile the properties file name
+	 */
+	public void setProperties(File propertiesFile) {
+		if ( !propertiesFile.exists() ) {
+			throw new BuildException("Properties file: " + propertiesFile + " does not exist.");
+	}
+
+		log("Using properties file " + propertiesFile, Project.MSG_DEBUG);
+		this.propertiesFile = propertiesFile;
+	}
+
+	/**
+	 * Set a <literal>.cfg.xml</literal> file, which will be
+	 * loaded as a resource, from the classpath
+	 * @param configurationFile the path to the resource
+	 */
+	public void setConfig(File configurationFile) {
+		this.configurationFile = configurationFile;
+	}
+
+	/**
+	 * Enable "quiet" mode. The schema will not be
+	 * written to standard out.
+	 * @param quiet true to enable quiet mode
+	 */
+	public void setQuiet(boolean quiet) {
+		this.quiet = quiet;
+	}
+
+	/**
+	 * Enable "text-only" mode. The schema will not
+	 * be exported to the database.
+	 * @param text true to enable text-only mode
+	 */
+	public void setText(boolean text) {
+		this.text = text;
+	}
+
+	/**
+	 * Enable "drop" mode. Database objects will be
+	 * dropped but not recreated.
+	 * @param drop true to enable drop mode
+	 */
+	public void setDrop(boolean drop) {
+		this.drop = drop;
+	}
+
+	/**
+	 * Enable "create" mode. Database objects will be
+	 * created but not first dropped.
+	 * @param create true to enable create mode
+	 */
+	public void setCreate(boolean create) {
+		this.create = create;
+	}
+
+	/**
+	 * Set the end of statement delimiter for the generated script
+	 * @param delimiter the delimiter
+	 */
+	public void setDelimiter(String delimiter) {
+		this.delimiter = delimiter;
+	}
+
+	/**
+	 * Set the script output file
+	 * @param outputFile the file name
+	 */
+	public void setOutput(File outputFile) {
+		this.outputFile = outputFile;
+	}
+
+	/**
+	 * Execute the task
+	 */
+	public void execute() throws BuildException {
+		try {
+			getSchemaExport( getConfiguration() ).execute(!quiet, !text, drop, create);
+		}
+		catch (HibernateException e) {
+			throw new BuildException("Schema text failed: " + e.getMessage(), e);
+		}
+		catch (FileNotFoundException e) {
+			throw new BuildException("File not found: " + e.getMessage(), e);
+		}
+		catch (IOException e) {
+			throw new BuildException("IOException : " + e.getMessage(), e);
+		}
+		catch (Exception e) {
+			throw new BuildException(e);
+		}
+	}
+
+	private String[] getFiles() {
+
+		List files = new LinkedList();
+		for ( Iterator i = fileSets.iterator(); i.hasNext(); ) {
+
+			FileSet fs = (FileSet) i.next();
+			DirectoryScanner ds = fs.getDirectoryScanner( getProject() );
+
+			String[] dsFiles = ds.getIncludedFiles();
+			for (int j = 0; j < dsFiles.length; j++) {
+				File f = new File(dsFiles[j]);
+				if ( !f.isFile() ) {
+					f = new File( ds.getBasedir(), dsFiles[j] );
+				}
+
+				files.add( f.getAbsolutePath() );
+			}
+		}
+
+		return ArrayHelper.toStringArray(files);
+	}
+
+	private Configuration getConfiguration() throws Exception {
+		Configuration cfg = new Configuration();
+		if (namingStrategy!=null) {
+			cfg.setNamingStrategy(
+					(NamingStrategy) ReflectHelper.classForName(namingStrategy).newInstance()
+				);
+		}
+		if (configurationFile != null) {
+			cfg.configure( configurationFile );
+		}
+
+		String[] files = getFiles();
+		for (int i = 0; i < files.length; i++) {
+			String filename = files[i];
+			if ( filename.endsWith(".jar") ) {
+				cfg.addJar( new File(filename) );
+			}
+			else {
+				cfg.addFile(filename);
+			}
+		}
+		return cfg;
+	}
+
+	private SchemaExport getSchemaExport(Configuration cfg) throws HibernateException, IOException {
+		Properties properties = new Properties();
+		properties.putAll( cfg.getProperties() );
+		if (propertiesFile == null) {
+			properties.putAll( getProject().getProperties() );
+		}
+		else {
+			properties.load( new FileInputStream(propertiesFile) );
+		}
+		cfg.setProperties(properties);
+		return new SchemaExport(cfg)
+				.setHaltOnError(haltOnError)
+				.setOutputFile( outputFile.getPath() )
+				.setDelimiter(delimiter);
+	}
+
+	public void setNamingStrategy(String namingStrategy) {
+		this.namingStrategy = namingStrategy;
+	}
+
+	public void setHaltonerror(boolean haltOnError) {
+		this.haltOnError = haltOnError;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,191 @@
+//$Id: SchemaUpdate.java 9250 2006-02-10 03:48:37Z steveebersole $
+package org.hibernate.tool.hbm2ddl;
+
+import java.io.FileInputStream;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.NamingStrategy;
+import org.hibernate.cfg.Settings;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * A commandline tool to update a database schema. May also be called from
+ * inside an application.
+ *
+ * @author Christoph Sturm
+ */
+public class SchemaUpdate {
+
+	private static final Log log = LogFactory.getLog( SchemaUpdate.class );
+	private ConnectionHelper connectionHelper;
+	private Configuration configuration;
+	private Dialect dialect;
+	private List exceptions;
+
+	public SchemaUpdate(Configuration cfg) throws HibernateException {
+		this( cfg, cfg.getProperties() );
+	}
+
+	public SchemaUpdate(Configuration cfg, Properties connectionProperties) throws HibernateException {
+		this.configuration = cfg;
+		dialect = Dialect.getDialect( connectionProperties );
+		Properties props = new Properties();
+		props.putAll( dialect.getDefaultProperties() );
+		props.putAll( connectionProperties );
+		connectionHelper = new ManagedProviderConnectionHelper( props );
+		exceptions = new ArrayList();
+	}
+
+	public SchemaUpdate(Configuration cfg, Settings settings) throws HibernateException {
+		this.configuration = cfg;
+		dialect = settings.getDialect();
+		connectionHelper = new SuppliedConnectionProviderConnectionHelper(
+				settings.getConnectionProvider()
+		);
+		exceptions = new ArrayList();
+	}
+
+	public static void main(String[] args) {
+		try {
+			Configuration cfg = new Configuration();
+
+			boolean script = true;
+			// If true then execute db updates, otherwise just generate and display updates
+			boolean doUpdate = true;
+			String propFile = null;
+
+			for ( int i = 0; i < args.length; i++ ) {
+				if ( args[i].startsWith( "--" ) ) {
+					if ( args[i].equals( "--quiet" ) ) {
+						script = false;
+					}
+					else if ( args[i].startsWith( "--properties=" ) ) {
+						propFile = args[i].substring( 13 );
+					}
+					else if ( args[i].startsWith( "--config=" ) ) {
+						cfg.configure( args[i].substring( 9 ) );
+					}
+					else if ( args[i].startsWith( "--text" ) ) {
+						doUpdate = false;
+					}
+					else if ( args[i].startsWith( "--naming=" ) ) {
+						cfg.setNamingStrategy(
+								( NamingStrategy ) ReflectHelper.classForName( args[i].substring( 9 ) ).newInstance()
+						);
+					}
+				}
+				else {
+					cfg.addFile( args[i] );
+				}
+
+			}
+
+			if ( propFile != null ) {
+				Properties props = new Properties();
+				props.putAll( cfg.getProperties() );
+				props.load( new FileInputStream( propFile ) );
+				cfg.setProperties( props );
+			}
+
+			new SchemaUpdate( cfg ).execute( script, doUpdate );
+		}
+		catch ( Exception e ) {
+			log.error( "Error running schema update", e );
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * Execute the schema updates
+	 *
+	 * @param script print all DDL to the console
+	 */
+	public void execute(boolean script, boolean doUpdate) {
+
+		log.info( "Running hbm2ddl schema update" );
+
+		Connection connection = null;
+		Statement stmt = null;
+
+		exceptions.clear();
+
+		try {
+
+			DatabaseMetadata meta;
+			try {
+				log.info( "fetching database metadata" );
+				connectionHelper.prepare( true );
+				connection = connectionHelper.getConnection();
+				meta = new DatabaseMetadata( connection, dialect );
+				stmt = connection.createStatement();
+			}
+			catch ( SQLException sqle ) {
+				exceptions.add( sqle );
+				log.error( "could not get database metadata", sqle );
+				throw sqle;
+			}
+
+			log.info( "updating schema" );
+
+			String[] createSQL = configuration.generateSchemaUpdateScript( dialect, meta );
+			for ( int j = 0; j < createSQL.length; j++ ) {
+
+				final String sql = createSQL[j];
+				try {
+					if ( script ) {
+						System.out.println( sql );
+					}
+					if ( doUpdate ) {
+						log.debug( sql );
+						stmt.executeUpdate( sql );
+					}
+				}
+				catch ( SQLException e ) {
+					exceptions.add( e );
+					log.error( "Unsuccessful: " + sql );
+					log.error( e.getMessage() );
+				}
+			}
+
+			log.info( "schema update complete" );
+
+		}
+		catch ( Exception e ) {
+			exceptions.add( e );
+			log.error( "could not complete schema update", e );
+		}
+		finally {
+
+			try {
+				if ( stmt != null ) {
+					stmt.close();
+				}
+				connectionHelper.release();
+			}
+			catch ( Exception e ) {
+				exceptions.add( e );
+				log.error( "Error closing connection", e );
+			}
+
+		}
+	}
+
+	/**
+	 * Returns a List of all Exceptions which occured during the export.
+	 *
+	 * @return A List containig the Exceptions occured during the export
+	 */
+	public List getExceptions() {
+		return exceptions;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdateTask.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdateTask.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdateTask.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,182 @@
+//$Id: SchemaUpdateTask.java 7863 2005-08-11 23:11:03Z oneovthafew $
+package org.hibernate.tool.hbm2ddl;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.NamingStrategy;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.ReflectHelper;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.FileSet;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * An Ant task for <tt>SchemaUpdate</tt>.
+ *
+ * <pre>
+ * &lt;taskdef name="schemaupdate"
+ *     classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask"
+ *     classpathref="class.path"/&gt;
+ *
+ * &lt;schemaupdate
+ *     properties="${build.classes.dir}/hibernate.properties"
+ *     quiet="no"
+ *     &lt;fileset dir="${build.classes.dir}"&gt;
+ *         &lt;include name="*.hbm.xml"/&gt;
+ *     &lt;/fileset&gt;
+ * &lt;/schemaupdate&gt;
+ * </pre>
+ *
+ * @see SchemaUpdate
+ * @author Rong C Ou, Gavin King
+ */
+public class SchemaUpdateTask extends MatchingTask {
+
+	private List fileSets = new LinkedList();
+	private File propertiesFile = null;
+	private File configurationFile = null;
+	private boolean quiet = false;
+	private boolean text = true;
+	private String namingStrategy = null;
+
+	public void addFileset(FileSet set) {
+		fileSets.add(set);
+	}
+
+	/**
+	 * Set a properties file
+	 * @param propertiesFile the properties file name
+	 */
+	public void setProperties(File propertiesFile) {
+		if ( !propertiesFile.exists() ) {
+			throw new BuildException("Properties file: " + propertiesFile + " does not exist.");
+		}
+
+		log("Using properties file " + propertiesFile, Project.MSG_DEBUG);
+		this.propertiesFile = propertiesFile;
+	}
+
+	/**
+	 * Set a <literal>.cfg.xml</literal> file
+	 * @param configurationFile the file name
+	 */
+	public void setConfig(File configurationFile) {
+		this.configurationFile = configurationFile;
+	}
+
+	/**
+     * Enable "text-only" mode. The schema will not
+	 * be updated in the database.
+	 * @param text true to enable text-only mode
+     */
+    public void setText(boolean text) {
+        this.text = text;
+    }
+
+	/**
+	 * Enable "quiet" mode. The schema will not be
+	 * written to standard out.
+	 * @param quiet true to enable quiet mode
+	 */
+	public void setQuiet(boolean quiet) {
+		this.quiet = quiet;
+	}
+
+	/**
+	 * Execute the task
+	 */
+	public void execute() throws BuildException {
+		try {
+			Configuration cfg = getConfiguration();
+			getSchemaUpdate(cfg).execute(!quiet, !text);
+		}
+		catch (HibernateException e) {
+			throw new BuildException("Schema text failed: " + e.getMessage(), e);
+		}
+		catch (FileNotFoundException e) {
+			throw new BuildException("File not found: " + e.getMessage(), e);
+		}
+		catch (IOException e) {
+			throw new BuildException("IOException : " + e.getMessage(), e);
+		}
+		catch (Exception e) {
+			throw new BuildException(e);
+		}
+	}
+
+	private String[] getFiles() {
+
+		List files = new LinkedList();
+		for ( Iterator i = fileSets.iterator(); i.hasNext(); ) {
+
+			FileSet fs = (FileSet) i.next();
+			DirectoryScanner ds = fs.getDirectoryScanner( getProject() );
+
+			String[] dsFiles = ds.getIncludedFiles();
+			for (int j = 0; j < dsFiles.length; j++) {
+				File f = new File(dsFiles[j]);
+				if ( !f.isFile() ) {
+					f = new File( ds.getBasedir(), dsFiles[j] );
+				}
+
+				files.add( f.getAbsolutePath() );
+			}
+		}
+
+		return ArrayHelper.toStringArray(files);
+	}
+
+	private Configuration getConfiguration() throws Exception {
+		Configuration cfg = new Configuration();
+		if (namingStrategy!=null) {
+			cfg.setNamingStrategy(
+					(NamingStrategy) ReflectHelper.classForName(namingStrategy).newInstance()
+				);
+		}
+		if (configurationFile!=null) {
+			cfg.configure( configurationFile );
+		}
+
+		String[] files = getFiles();
+		for (int i = 0; i < files.length; i++) {
+			String filename = files[i];
+			if ( filename.endsWith(".jar") ) {
+				cfg.addJar( new File(filename) );
+			}
+			else {
+				cfg.addFile(filename);
+			}
+		}
+		return cfg;
+	}
+
+	private SchemaUpdate getSchemaUpdate(Configuration cfg) throws HibernateException, IOException {
+		Properties properties = new Properties();
+		properties.putAll( cfg.getProperties() );
+		if (propertiesFile == null) {
+			properties.putAll( getProject().getProperties() );
+		}
+		else {
+			properties.load( new FileInputStream(propertiesFile) );
+		}
+		cfg.setProperties(properties);
+		return new SchemaUpdate(cfg);
+	}
+
+	public void setNamingStrategy(String namingStrategy) {
+		this.namingStrategy = namingStrategy;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,134 @@
+//$Id: SchemaValidator.java 9249 2006-02-10 03:48:37Z steveebersole $
+package org.hibernate.tool.hbm2ddl;
+
+import java.io.FileInputStream;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.NamingStrategy;
+import org.hibernate.cfg.Settings;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * A commandline tool to update a database schema. May also be called from
+ * inside an application.
+ *
+ * @author Christoph Sturm
+ */
+public class SchemaValidator {
+
+	private static final Log log = LogFactory.getLog( SchemaValidator.class );
+	private ConnectionHelper connectionHelper;
+	private Configuration configuration;
+	private Dialect dialect;
+
+	public SchemaValidator(Configuration cfg) throws HibernateException {
+		this( cfg, cfg.getProperties() );
+	}
+
+	public SchemaValidator(Configuration cfg, Properties connectionProperties) throws HibernateException {
+		this.configuration = cfg;
+		dialect = Dialect.getDialect( connectionProperties );
+		Properties props = new Properties();
+		props.putAll( dialect.getDefaultProperties() );
+		props.putAll( connectionProperties );
+		connectionHelper = new ManagedProviderConnectionHelper( props );
+	}
+
+	public SchemaValidator(Configuration cfg, Settings settings) throws HibernateException {
+		this.configuration = cfg;
+		dialect = settings.getDialect();
+		connectionHelper = new SuppliedConnectionProviderConnectionHelper(
+				settings.getConnectionProvider()
+		);
+	}
+
+	public static void main(String[] args) {
+		try {
+			Configuration cfg = new Configuration();
+
+			String propFile = null;
+
+			for ( int i = 0; i < args.length; i++ ) {
+				if ( args[i].startsWith( "--" ) ) {
+					if ( args[i].startsWith( "--properties=" ) ) {
+						propFile = args[i].substring( 13 );
+					}
+					else if ( args[i].startsWith( "--config=" ) ) {
+						cfg.configure( args[i].substring( 9 ) );
+					}
+					else if ( args[i].startsWith( "--naming=" ) ) {
+						cfg.setNamingStrategy(
+								( NamingStrategy ) ReflectHelper.classForName( args[i].substring( 9 ) ).newInstance()
+						);
+					}
+				}
+				else {
+					cfg.addFile( args[i] );
+				}
+
+			}
+
+			if ( propFile != null ) {
+				Properties props = new Properties();
+				props.putAll( cfg.getProperties() );
+				props.load( new FileInputStream( propFile ) );
+				cfg.setProperties( props );
+			}
+
+			new SchemaValidator( cfg ).validate();
+		}
+		catch ( Exception e ) {
+			log.error( "Error running schema update", e );
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * Perform the validations.
+	 */
+	public void validate() {
+
+		log.info( "Running schema validator" );
+
+		Connection connection = null;
+
+		try {
+
+			DatabaseMetadata meta;
+			try {
+				log.info( "fetching database metadata" );
+				connectionHelper.prepare( false );
+				connection = connectionHelper.getConnection();
+				meta = new DatabaseMetadata( connection, dialect, false );
+			}
+			catch ( SQLException sqle ) {
+				log.error( "could not get database metadata", sqle );
+				throw sqle;
+			}
+
+			configuration.validateSchema( dialect, meta );
+
+		}
+		catch ( SQLException e ) {
+			log.error( "could not complete schema validation", e );
+		}
+		finally {
+
+			try {
+				connectionHelper.release();
+			}
+			catch ( Exception e ) {
+				log.error( "Error closing connection", e );
+			}
+
+		}
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidatorTask.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidatorTask.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidatorTask.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,161 @@
+//$Id: SchemaValidatorTask.java 7863 2005-08-11 23:11:03Z oneovthafew $
+package org.hibernate.tool.hbm2ddl;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.NamingStrategy;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.ReflectHelper;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.FileSet;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * An Ant task for <tt>SchemaUpdate</tt>.
+ *
+ * <pre>
+ * &lt;taskdef name="schemavalidator"
+ *     classname="org.hibernate.tool.hbm2ddl.SchemaValidatorTask"
+ *     classpathref="class.path"/&gt;
+ *
+ * &lt;schemaupdate
+ *     properties="${build.classes.dir}/hibernate.properties"
+ *     &lt;fileset dir="${build.classes.dir}"&gt;
+ *         &lt;include name="*.hbm.xml"/&gt;
+ *     &lt;/fileset&gt;
+ * &lt;/schemaupdate&gt;
+ * </pre>
+ *
+ * @see SchemaValidator
+ * @author Gavin King
+ */
+public class SchemaValidatorTask extends MatchingTask {
+
+	private List fileSets = new LinkedList();
+	private File propertiesFile = null;
+	private File configurationFile = null;
+	private String namingStrategy = null;
+
+	public void addFileset(FileSet set) {
+		fileSets.add(set);
+	}
+
+	/**
+	 * Set a properties file
+	 * @param propertiesFile the properties file name
+	 */
+	public void setProperties(File propertiesFile) {
+		if ( !propertiesFile.exists() ) {
+			throw new BuildException("Properties file: " + propertiesFile + " does not exist.");
+		}
+
+		log("Using properties file " + propertiesFile, Project.MSG_DEBUG);
+		this.propertiesFile = propertiesFile;
+	}
+
+	/**
+	 * Set a <literal>.cfg.xml</literal> file
+	 * @param configurationFile the file name
+	 */
+	public void setConfig(File configurationFile) {
+		this.configurationFile = configurationFile;
+	}
+
+	/**
+	 * Execute the task
+	 */
+	public void execute() throws BuildException {
+		try {
+			Configuration cfg = getConfiguration();
+			getSchemaValidator(cfg).validate();
+		}
+		catch (HibernateException e) {
+			throw new BuildException("Schema text failed: " + e.getMessage(), e);
+		}
+		catch (FileNotFoundException e) {
+			throw new BuildException("File not found: " + e.getMessage(), e);
+		}
+		catch (IOException e) {
+			throw new BuildException("IOException : " + e.getMessage(), e);
+		}
+		catch (Exception e) {
+			throw new BuildException(e);
+		}
+	}
+
+	private String[] getFiles() {
+
+		List files = new LinkedList();
+		for ( Iterator i = fileSets.iterator(); i.hasNext(); ) {
+
+			FileSet fs = (FileSet) i.next();
+			DirectoryScanner ds = fs.getDirectoryScanner( getProject() );
+
+			String[] dsFiles = ds.getIncludedFiles();
+			for (int j = 0; j < dsFiles.length; j++) {
+				File f = new File(dsFiles[j]);
+				if ( !f.isFile() ) {
+					f = new File( ds.getBasedir(), dsFiles[j] );
+				}
+
+				files.add( f.getAbsolutePath() );
+			}
+		}
+
+		return ArrayHelper.toStringArray(files);
+	}
+
+	private Configuration getConfiguration() throws Exception {
+		Configuration cfg = new Configuration();
+		if (namingStrategy!=null) {
+			cfg.setNamingStrategy(
+					(NamingStrategy) ReflectHelper.classForName(namingStrategy).newInstance()
+				);
+		}
+		if (configurationFile!=null) {
+			cfg.configure( configurationFile );
+		}
+
+		String[] files = getFiles();
+		for (int i = 0; i < files.length; i++) {
+			String filename = files[i];
+			if ( filename.endsWith(".jar") ) {
+				cfg.addJar( new File(filename) );
+			}
+			else {
+				cfg.addFile(filename);
+			}
+		}
+		return cfg;
+	}
+
+	private SchemaValidator getSchemaValidator(Configuration cfg) throws HibernateException, IOException {
+		Properties properties = new Properties();
+		properties.putAll( cfg.getProperties() );
+		if (propertiesFile == null) {
+			properties.putAll( getProject().getProperties() );
+		}
+		else {
+			properties.load( new FileInputStream(propertiesFile) );
+		}
+		cfg.setProperties(properties);
+		return new SchemaValidator(cfg);
+	}
+
+	public void setNamingStrategy(String namingStrategy) {
+		this.namingStrategy = namingStrategy;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidatorTask.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SuppliedConnectionHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SuppliedConnectionHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SuppliedConnectionHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+package org.hibernate.tool.hbm2ddl;
+
+import org.hibernate.util.JDBCExceptionReporter;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * A {@link ConnectionHelper} implementation based on an explicitly supplied
+ * connection.
+ *
+ * @author Steve Ebersole
+ */
+class SuppliedConnectionHelper implements ConnectionHelper {
+	private Connection connection;
+	private boolean toggleAutoCommit;
+
+	public SuppliedConnectionHelper(Connection connection) {
+		this.connection = connection;
+	}
+
+	public void prepare(boolean needsAutoCommit) throws SQLException {
+		toggleAutoCommit = needsAutoCommit && !connection.getAutoCommit();
+		if ( toggleAutoCommit ) {
+			try {
+				connection.commit();
+			}
+			catch( Throwable ignore ) {
+				// might happen with a managed connection
+			}
+			connection.setAutoCommit( true );
+		}
+	}
+
+	public Connection getConnection() {
+		return connection;
+	}
+
+	public void release() throws SQLException {
+		JDBCExceptionReporter.logAndClearWarnings( connection );
+		if ( toggleAutoCommit ) {
+			connection.setAutoCommit( false );
+		}
+		connection = null;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SuppliedConnectionProviderConnectionHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SuppliedConnectionProviderConnectionHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/SuppliedConnectionProviderConnectionHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+package org.hibernate.tool.hbm2ddl;
+
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.util.JDBCExceptionReporter;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * A {@link ConnectionHelper} implementation based on a provided
+ * {@link ConnectionProvider}.  Essentially, ensures that the connection
+ * gets cleaned up, but that the provider itself remains usable since it
+ * was externally provided to us.
+ *
+ * @author Steve Ebersole
+ */
+class SuppliedConnectionProviderConnectionHelper implements ConnectionHelper {
+	private ConnectionProvider provider;
+	private Connection connection;
+	private boolean toggleAutoCommit;
+
+	public SuppliedConnectionProviderConnectionHelper(ConnectionProvider provider) {
+		this.provider = provider;
+	}
+
+	public void prepare(boolean needsAutoCommit) throws SQLException {
+		connection = provider.getConnection();
+		toggleAutoCommit = needsAutoCommit && !connection.getAutoCommit();
+		if ( toggleAutoCommit ) {
+			try {
+				connection.commit();
+			}
+			catch( Throwable ignore ) {
+				// might happen with a managed connection
+			}
+			connection.setAutoCommit( true );
+		}
+	}
+
+	public Connection getConnection() throws SQLException {
+		return connection;
+	}
+
+	public void release() throws SQLException {
+		// we only release the connection
+		if ( connection != null ) {
+			JDBCExceptionReporter.logAndClearWarnings( connection );
+			if ( toggleAutoCommit ) {
+				connection.setAutoCommit( false );
+			}
+			provider.closeConnection( connection );
+			connection = null;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/TableMetadata.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/TableMetadata.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/TableMetadata.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,160 @@
+//$Id: TableMetadata.java 10726 2006-11-06 14:50:05Z max.andersen at jboss.com $
+package org.hibernate.tool.hbm2ddl;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * JDBC table metadata
+ * @author Christoph Sturm, Max Rydahl Andersen
+ */
+public class TableMetadata {
+	
+	private static final Log log = LogFactory.getLog(TableMetadata.class);
+	
+	private final String catalog;
+	private final String schema;
+	private final String name;
+	private final Map columns = new HashMap();
+	private final Map foreignKeys = new HashMap();
+	private final Map indexes = new HashMap();
+
+	TableMetadata(ResultSet rs, DatabaseMetaData meta, boolean extras) throws SQLException {
+		catalog = rs.getString("TABLE_CAT");
+		schema = rs.getString("TABLE_SCHEM");
+		name = rs.getString("TABLE_NAME");
+		initColumns(meta);
+		if (extras) {
+			initForeignKeys(meta);
+			initIndexes(meta);
+		}
+		String cat = catalog==null ? "" : catalog + '.';
+		String schem = schema==null ? "" : schema + '.';
+		log.info( "table found: " + cat + schem + name );
+		log.info( "columns: " + columns.keySet() );
+		if (extras) {
+			log.info( "foreign keys: " + foreignKeys.keySet() );
+			log.info( "indexes: " + indexes.keySet() );
+		}
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public String getCatalog() {
+		return catalog;
+	}
+	
+	public String getSchema() {
+		return schema;
+	}
+	
+	public String toString() {
+		return "TableMetadata(" + name + ')';
+	}
+
+	public ColumnMetadata getColumnMetadata(String columnName) {
+		return (ColumnMetadata) columns.get( columnName.toLowerCase() );
+	}
+
+	public ForeignKeyMetadata getForeignKeyMetadata(String keyName) {
+		return (ForeignKeyMetadata) foreignKeys.get( keyName.toLowerCase() );
+	}
+
+	public IndexMetadata getIndexMetadata(String indexName) {
+		return (IndexMetadata) indexes.get( indexName.toLowerCase() );
+	}
+
+	private void addForeignKey(ResultSet rs) throws SQLException {
+		String fk = rs.getString("FK_NAME");
+
+		if (fk == null) return;
+
+		ForeignKeyMetadata info = getForeignKeyMetadata(fk);
+		if (info == null) {
+			info = new ForeignKeyMetadata(rs);
+			foreignKeys.put( info.getName().toLowerCase(), info );
+		}
+
+		info.addColumn( getColumnMetadata( rs.getString("FKCOLUMN_NAME") ) );
+	}
+
+	private void addIndex(ResultSet rs) throws SQLException {
+		String index = rs.getString("INDEX_NAME");
+
+		if (index == null) return;
+
+		IndexMetadata info = getIndexMetadata(index);
+		if (info == null) {
+			info = new IndexMetadata(rs);
+			indexes.put( info.getName().toLowerCase(), info );
+		}
+
+		info.addColumn( getColumnMetadata( rs.getString("COLUMN_NAME") ) );
+	}
+
+	public void addColumn(ResultSet rs) throws SQLException {
+		String column = rs.getString("COLUMN_NAME");
+
+		if (column==null) return;
+
+		if ( getColumnMetadata(column) == null ) {
+			ColumnMetadata info = new ColumnMetadata(rs);
+			columns.put( info.getName().toLowerCase(), info );
+		}
+	}
+
+	private void initForeignKeys(DatabaseMetaData meta) throws SQLException {
+		ResultSet rs = null;
+
+		try {
+			rs = meta.getImportedKeys(catalog, schema, name);
+			while ( rs.next() ) addForeignKey(rs);
+		}
+		finally {
+			if (rs != null) rs.close();
+		}
+	}
+
+	private void initIndexes(DatabaseMetaData meta) throws SQLException {
+		ResultSet rs = null;
+
+		try {
+			rs = meta.getIndexInfo(catalog, schema, name, false, true);
+			
+			while ( rs.next() ) {
+				if ( rs.getShort("TYPE") == DatabaseMetaData.tableIndexStatistic ) continue;
+				addIndex(rs);
+			}
+		}
+		finally {
+			if (rs != null) rs.close();
+		}
+	}
+
+	private void initColumns(DatabaseMetaData meta) throws SQLException {
+		ResultSet rs = null;
+		
+		try {
+			rs = meta.getColumns(catalog, schema, name, "%");
+			while ( rs.next() ) addColumn(rs);
+		}
+		finally  {
+			if (rs != null) rs.close();
+		}
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>
+	The <tt>hbm2ddl</tt> tool.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/hbm2ddl/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/BasicInstrumentationTask.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/BasicInstrumentationTask.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/BasicInstrumentationTask.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,383 @@
+package org.hibernate.tool.instrument;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.FileSet;
+import org.hibernate.bytecode.util.ClassDescriptor;
+import org.hibernate.bytecode.util.ByteCodeHelper;
+import org.hibernate.bytecode.util.FieldFilter;
+import org.hibernate.bytecode.ClassTransformer;
+import org.hibernate.util.StringHelper;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.CRC32;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.DataInputStream;
+import java.io.ByteArrayInputStream;
+
+/**
+ * Super class for all Hibernate instrumentation tasks.  Provides the basic
+ * templating of how instrumentation should occur.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class BasicInstrumentationTask extends Task {
+
+	private static final int ZIP_MAGIC = 0x504B0304;
+	private static final int CLASS_MAGIC = 0xCAFEBABE;
+
+	protected final Logger logger = new Logger();
+	private List filesets = new ArrayList();
+	private Set classNames = new HashSet();
+	private boolean extended;
+	private boolean verbose;
+
+	public void addFileset(FileSet set) {
+		this.filesets.add( set );
+	}
+
+	protected final Iterator filesets() {
+		return filesets.iterator();
+	}
+
+	public boolean isExtended() {
+		return extended;
+	}
+
+	public void setExtended(boolean extended) {
+		this.extended = extended;
+	}
+
+	public boolean isVerbose() {
+		return verbose;
+	}
+
+	public void setVerbose(boolean verbose) {
+		this.verbose = verbose;
+	}
+
+	public void execute() throws BuildException {
+		if ( isExtended() ) {
+			collectClassNames();
+		}
+		logger.info( "starting instrumentation" );
+		Project project = getProject();
+		Iterator filesets = filesets();
+		while ( filesets.hasNext() ) {
+			FileSet fs = ( FileSet ) filesets.next();
+			DirectoryScanner ds = fs.getDirectoryScanner( project );
+			String[] includedFiles = ds.getIncludedFiles();
+			File d = fs.getDir( project );
+			for ( int i = 0; i < includedFiles.length; ++i ) {
+				File file = new File( d, includedFiles[i] );
+				try {
+					processFile( file );
+				}
+				catch ( Exception e ) {
+					throw new BuildException( e );
+				}
+			}
+		}
+	}
+
+	private void collectClassNames() {
+		logger.info( "collecting class names for extended instrumentation determination" );
+		Project project = getProject();
+		Iterator filesets = filesets();
+		while ( filesets.hasNext() ) {
+			FileSet fs = ( FileSet ) filesets.next();
+			DirectoryScanner ds = fs.getDirectoryScanner( project );
+			String[] includedFiles = ds.getIncludedFiles();
+			File d = fs.getDir( project );
+			for ( int i = 0; i < includedFiles.length; ++i ) {
+				File file = new File( d, includedFiles[i] );
+				try {
+					collectClassNames( file );
+				}
+				catch ( Exception e ) {
+					throw new BuildException( e );
+				}
+			}
+		}
+		logger.info( classNames.size() + " class(es) being checked" );
+	}
+
+	private void collectClassNames(File file) throws Exception {
+	    if ( isClassFile( file ) ) {
+			byte[] bytes = ByteCodeHelper.readByteCode( file );
+			ClassDescriptor descriptor = getClassDescriptor( bytes );
+		    classNames.add( descriptor.getName() );
+	    }
+	    else if ( isJarFile( file ) ) {
+		    ZipEntryHandler collector = new ZipEntryHandler() {
+			    public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception {
+					if ( !entry.isDirectory() ) {
+						// see if the entry represents a class file
+						DataInputStream din = new DataInputStream( new ByteArrayInputStream( byteCode ) );
+						if ( din.readInt() == CLASS_MAGIC ) {
+				            classNames.add( getClassDescriptor( byteCode ).getName() );
+						}
+					}
+			    }
+		    };
+		    ZipFileProcessor processor = new ZipFileProcessor( collector );
+		    processor.process( file );
+	    }
+	}
+
+	protected void processFile(File file) throws Exception {
+		logger.verbose( "processing file : " + file.toURL() );
+	    if ( isClassFile( file ) ) {
+	        processClassFile(file);
+	    }
+	    else if ( isJarFile( file ) ) {
+	        processJarFile(file);
+	    }
+	    else {
+		    logger.verbose( "ignoring " + file.toURL() );
+
+	    }
+	}
+
+	protected final boolean isClassFile(File file) throws IOException {
+        return checkMagic( file, CLASS_MAGIC );
+    }
+
+    protected final boolean isJarFile(File file) throws IOException {
+        return checkMagic(file, ZIP_MAGIC);
+    }
+
+	protected final boolean checkMagic(File file, long magic) throws IOException {
+        DataInputStream in = new DataInputStream( new FileInputStream( file ) );
+        try {
+            int m = in.readInt();
+            return magic == m;
+        }
+        finally {
+            in.close();
+        }
+    }
+
+	protected void processClassFile(File file) throws Exception {
+		logger.verbose( "Starting class file : " + file.toURL() );
+		byte[] bytes = ByteCodeHelper.readByteCode( file );
+		ClassDescriptor descriptor = getClassDescriptor( bytes );
+		ClassTransformer transformer = getClassTransformer( descriptor );
+		if ( transformer == null ) {
+			logger.verbose( "skipping file : " + file.toURL() );
+			return;
+		}
+
+		logger.info( "processing class [" + descriptor.getName() + "]; file = " + file.toURL() );
+		byte[] transformedBytes = transformer.transform(
+				getClass().getClassLoader(),
+				descriptor.getName(),
+				null,
+				null,
+				descriptor.getBytes()
+		);
+
+		OutputStream out = new FileOutputStream( file );
+		try {
+			out.write( transformedBytes );
+			out.flush();
+		}
+		finally {
+			try {
+				out.close();
+			}
+			catch ( IOException ignore) {
+				// intentionally empty
+			}
+		}
+	}
+
+	protected void processJarFile(final File file) throws Exception {
+		logger.verbose( "starting jar file : " + file.toURL() );
+
+        File tempFile = File.createTempFile(
+		        file.getName(),
+		        null,
+		        new File( file.getAbsoluteFile().getParent() )
+        );
+
+        try {
+			FileOutputStream fout = new FileOutputStream( tempFile, false );
+			try {
+				final ZipOutputStream out = new ZipOutputStream( fout );
+				ZipEntryHandler transformer = new ZipEntryHandler() {
+					public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception {
+								logger.verbose( "starting entry : " + entry.toString() );
+								if ( !entry.isDirectory() ) {
+									// see if the entry represents a class file
+									DataInputStream din = new DataInputStream( new ByteArrayInputStream( byteCode ) );
+									if ( din.readInt() == CLASS_MAGIC ) {
+										ClassDescriptor descriptor = getClassDescriptor( byteCode );
+										ClassTransformer transformer = getClassTransformer( descriptor );
+										if ( transformer == null ) {
+											logger.verbose( "skipping entry : " + entry.toString() );
+										}
+										else {
+											logger.info( "processing class [" + descriptor.getName() + "]; entry = " + file.toURL() );
+											byteCode = transformer.transform(
+													getClass().getClassLoader(),
+													descriptor.getName(),
+													null,
+													null,
+													descriptor.getBytes()
+											);
+										}
+									}
+									else {
+										logger.verbose( "ignoring zip entry : " + entry.toString() );
+									}
+								}
+
+								ZipEntry outEntry = new ZipEntry( entry.getName() );
+								outEntry.setMethod( entry.getMethod() );
+								outEntry.setComment( entry.getComment() );
+								outEntry.setSize( byteCode.length );
+
+								if ( outEntry.getMethod() == ZipEntry.STORED ){
+									CRC32 crc = new CRC32();
+									crc.update( byteCode );
+									outEntry.setCrc( crc.getValue() );
+									outEntry.setCompressedSize( byteCode.length );
+								}
+								out.putNextEntry( outEntry );
+								out.write( byteCode );
+								out.closeEntry();
+					}
+				};
+				ZipFileProcessor processor = new ZipFileProcessor( transformer );
+				processor.process( file );
+				out.close();
+			}
+			finally{
+				fout.close();
+			}
+
+            if ( file.delete() ) {
+	            File newFile = new File( tempFile.getAbsolutePath() );
+                if( !newFile.renameTo( file ) ) {
+	                throw new IOException( "can not rename " + tempFile + " to " + file );
+                }
+            }
+            else {
+	            throw new IOException("can not delete " + file);
+            }
+        }
+        finally {
+	        tempFile.delete();
+        }
+	}
+
+	protected boolean isBeingIntrumented(String className) {
+		logger.verbose( "checking to see if class [" + className + "] is set to be instrumented" );
+		return classNames.contains( className );
+	}
+
+	protected abstract ClassDescriptor getClassDescriptor(byte[] byecode) throws Exception;
+
+	protected abstract ClassTransformer getClassTransformer(ClassDescriptor descriptor);
+
+	protected class CustomFieldFilter implements FieldFilter {
+		private final ClassDescriptor descriptor;
+
+		public CustomFieldFilter(ClassDescriptor descriptor) {
+			this.descriptor = descriptor;
+		}
+
+		public boolean shouldInstrumentField(String className, String fieldName) {
+			if ( descriptor.getName().equals( className ) ) {
+				logger.verbose( "accepting transformation of field [" + className + "." + fieldName + "]" );
+				return true;
+			}
+			else {
+				logger.verbose( "rejecting transformation of field [" + className + "." + fieldName + "]" );
+				return false;
+			}
+		}
+
+		public boolean shouldTransformFieldAccess(
+				String transformingClassName,
+				String fieldOwnerClassName,
+				String fieldName) {
+			if ( descriptor.getName().equals( fieldOwnerClassName ) ) {
+				logger.verbose( "accepting transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]" );
+				return true;
+			}
+			else if ( isExtended() && isBeingIntrumented( fieldOwnerClassName ) ) {
+				logger.verbose( "accepting extended transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]" );
+				return true;
+			}
+			else {
+				logger.verbose( "rejecting transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]; caller = " + transformingClassName  );
+				return false;
+			}
+		}
+	}
+
+	protected class Logger {
+		public void verbose(String message) {
+			if ( verbose ) {
+				System.out.println( message );
+			}
+			log( message, Project.MSG_VERBOSE );
+		}
+
+		public void debug(String message) {
+			log( message, Project.MSG_DEBUG );
+		}
+
+		public void info(String message) {
+			log( message, Project.MSG_INFO );
+		}
+
+		public void warn(String message) {
+			log( message, Project.MSG_WARN );
+		}
+	}
+
+
+	private static interface ZipEntryHandler {
+		public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception;
+	}
+
+	private static class ZipFileProcessor {
+		private final ZipEntryHandler entryHandler;
+
+		public ZipFileProcessor(ZipEntryHandler entryHandler) {
+			this.entryHandler = entryHandler;
+		}
+
+		public void process(File file) throws Exception {
+			ZipInputStream zip = new ZipInputStream( new FileInputStream( file ) );
+
+			try {
+				ZipEntry entry;
+				while ( (entry = zip.getNextEntry()) != null ) {
+					byte bytes[] = ByteCodeHelper.readByteCode( zip );
+					entryHandler.handleEntry( entry, bytes );
+					zip.closeEntry();
+				}
+            }
+            finally {
+	            zip.close();
+            }
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/cglib/InstrumentTask.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/cglib/InstrumentTask.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/cglib/InstrumentTask.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,106 @@
+//$Id: InstrumentTask.java 10206 2006-08-03 19:59:42Z steve.ebersole at jboss.com $
+package org.hibernate.tool.instrument.cglib;
+
+import org.hibernate.bytecode.util.BasicClassFilter;
+import org.hibernate.bytecode.util.ClassDescriptor;
+import org.hibernate.bytecode.cglib.BytecodeProviderImpl;
+import org.hibernate.bytecode.ClassTransformer;
+import org.hibernate.tool.instrument.BasicInstrumentationTask;
+import org.objectweb.asm.ClassReader;
+
+import java.io.ByteArrayInputStream;
+
+import net.sf.cglib.core.ClassNameReader;
+import net.sf.cglib.transform.impl.InterceptFieldEnabled;
+
+/**
+ * An Ant task for instrumenting persistent classes in order to enable
+ * field-level interception using CGLIB.
+ * <p/>
+ * In order to use this task, typically you would define a a taskdef
+ * similiar to:<pre>
+ * <taskdef name="instrument" classname="org.hibernate.tool.instrument.cglib.InstrumentTask">
+ *     <classpath refid="lib.class.path"/>
+ * </taskdef>
+ * </pre>
+ * where <tt>lib.class.path</tt> is an ANT path reference containing all the
+ * required Hibernate and CGLIB libraries.
+ * <p/>
+ * And then use it like:<pre>
+ * <instrument verbose="true">
+ *     <fileset dir="${testclasses.dir}/org/hibernate/test">
+ *         <include name="yadda/yadda/**"/>
+ *         ...
+ *     </fileset>
+ * </instrument>
+ * </pre>
+ * where the nested ANT fileset includes the class you would like to have
+ * instrumented.
+ * <p/>
+ * Optionally you can chose to enable "Extended Instrumentation" if desired
+ * by specifying the extended attriubute on the task:<pre>
+ * <instrument verbose="true" extended="true">
+ *     ...
+ * </instrument>
+ * </pre>
+ * See the Hibernate manual regarding this option.
+ *
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public class InstrumentTask extends BasicInstrumentationTask {
+
+	private static final BasicClassFilter CLASS_FILTER = new BasicClassFilter();
+
+	private final BytecodeProviderImpl provider = new BytecodeProviderImpl();
+
+
+	protected ClassDescriptor getClassDescriptor(byte[] byecode) throws Exception {
+		return new CustomClassDescriptor( byecode );
+	}
+
+	protected ClassTransformer getClassTransformer(ClassDescriptor descriptor) {
+		if ( descriptor.isInstrumented() ) {
+			logger.verbose( "class [" + descriptor.getName() + "] already instrumented" );
+			return null;
+		}
+		else {
+			return provider.getTransformer( CLASS_FILTER, new CustomFieldFilter( descriptor ) );
+		}
+	}
+
+	private static class CustomClassDescriptor implements ClassDescriptor {
+		private final byte[] bytecode;
+		private final String name;
+		private final boolean isInstrumented;
+
+		public CustomClassDescriptor(byte[] bytecode) throws Exception {
+			this.bytecode = bytecode;
+			ClassReader reader = new ClassReader( new ByteArrayInputStream( bytecode ) );
+			String[] names = ClassNameReader.getClassInfo( reader );
+			this.name = names[0];
+			boolean instrumented = false;
+			for ( int i = 1; i < names.length; i++ ) {
+				if ( InterceptFieldEnabled.class.getName().equals( names[i] ) ) {
+					instrumented = true;
+					break;
+				}
+			}
+			this.isInstrumented = instrumented;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public boolean isInstrumented() {
+			return isInstrumented;
+		}
+
+		public byte[] getBytes() {
+			return bytecode;
+		}
+	}
+
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/javassist/InstrumentTask.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/javassist/InstrumentTask.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/javassist/InstrumentTask.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,100 @@
+package org.hibernate.tool.instrument.javassist;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.ByteArrayInputStream;
+
+import javassist.bytecode.ClassFile;
+
+import org.hibernate.tool.instrument.BasicInstrumentationTask;
+import org.hibernate.bytecode.util.ClassDescriptor;
+import org.hibernate.bytecode.util.BasicClassFilter;
+import org.hibernate.bytecode.util.FieldFilter;
+import org.hibernate.bytecode.ClassTransformer;
+import org.hibernate.bytecode.javassist.BytecodeProviderImpl;
+import org.hibernate.bytecode.javassist.FieldHandled;
+
+/**
+ * An Ant task for instrumenting persistent classes in order to enable
+ * field-level interception using Javassist.
+ * <p/>
+ * In order to use this task, typically you would define a a taskdef
+ * similiar to:<pre>
+ * <taskdef name="instrument" classname="org.hibernate.tool.instrument.javassist.InstrumentTask">
+ *     <classpath refid="lib.class.path"/>
+ * </taskdef>
+ * </pre>
+ * where <tt>lib.class.path</tt> is an ANT path reference containing all the
+ * required Hibernate and Javassist libraries.
+ * <p/>
+ * And then use it like:<pre>
+ * <instrument verbose="true">
+ *     <fileset dir="${testclasses.dir}/org/hibernate/test">
+ *         <include name="yadda/yadda/**"/>
+ *         ...
+ *     </fileset>
+ * </instrument>
+ * </pre>
+ * where the nested ANT fileset includes the class you would like to have
+ * instrumented.
+ * <p/>
+ * Optionally you can chose to enable "Extended Instrumentation" if desired
+ * by specifying the extended attriubute on the task:<pre>
+ * <instrument verbose="true" extended="true">
+ *     ...
+ * </instrument>
+ * </pre>
+ * See the Hibernate manual regarding this option.
+ *
+ * @author Muga Nishizawa
+ * @author Steve Ebersole
+ */
+public class InstrumentTask extends BasicInstrumentationTask {
+
+	private static final BasicClassFilter CLASS_FILTER = new BasicClassFilter();
+
+	private final BytecodeProviderImpl provider = new BytecodeProviderImpl();
+
+	protected ClassDescriptor getClassDescriptor(byte[] bytecode) throws IOException {
+		return new CustomClassDescriptor( bytecode );
+	}
+
+	protected ClassTransformer getClassTransformer(ClassDescriptor descriptor) {
+		if ( descriptor.isInstrumented() ) {
+			logger.verbose( "class [" + descriptor.getName() + "] already instrumented" );
+			return null;
+		}
+		else {
+			return provider.getTransformer( CLASS_FILTER, new CustomFieldFilter( descriptor ) );
+		}
+	}
+
+	private static class CustomClassDescriptor implements ClassDescriptor {
+		private final byte[] bytes;
+		private final ClassFile classFile;
+
+		public CustomClassDescriptor(byte[] bytes) throws IOException {
+			this.bytes = bytes;
+			this.classFile = new ClassFile( new DataInputStream( new ByteArrayInputStream( bytes ) ) );
+		}
+
+		public String getName() {
+			return classFile.getName();
+		}
+
+		public boolean isInstrumented() {
+			String[] intfs = classFile.getInterfaces();
+			for ( int i = 0; i < intfs.length; i++ ) {
+				if ( FieldHandled.class.getName().equals( intfs[i] ) ) {
+					return true;
+				}
+			}
+			return false;
+		}
+
+		public byte[] getBytes() {
+			return bytes;
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,11 @@
+<html>
+<head></head>
+<body>
+<p>
+	The <tt>instrument</tt> tool for adding field-interception hooks
+	to persistent classes using built-time bytecode processing. Use
+	this tool only if you wish to take advantage of lazy property
+	fetching (the <tt>&lt;lazy&gt;</tt> mapping element).
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/tool/instrument/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/BESTransactionManagerLookup.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/BESTransactionManagerLookup.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/BESTransactionManagerLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+//$Id: BESTransactionManagerLookup.java 4388 2004-08-20 07:44:37Z oneovthafew $
+package org.hibernate.transaction;
+
+/**
+ * A <tt>TransactionManager</tt> lookup strategy for Borland ES.
+ * @author Etienne Hardy
+ */
+public final class BESTransactionManagerLookup extends JNDITransactionManagerLookup {
+
+	protected String getName() {
+		return "java:pm/TransactionManager";
+	}
+
+	public String getUserTransactionName() {
+		return "java:comp/UserTransaction";
+	}
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/CMTTransaction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/CMTTransaction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/CMTTransaction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,167 @@
+//$Id: CMTTransaction.java 9680 2006-03-22 23:47:31Z epbernard $
+package org.hibernate.transaction;
+
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.Transaction;
+import org.hibernate.TransactionException;
+import org.hibernate.jdbc.JDBCContext;
+import org.hibernate.util.JTAHelper;
+
+/**
+ * Implements a basic transaction strategy for CMT transactions. All work is done 
+ * in the context of the container managed transaction.
+ * @author Gavin King
+ */
+public class CMTTransaction implements Transaction {
+
+	private static final Log log = LogFactory.getLog(CMTTransaction.class);
+
+	protected final JDBCContext jdbcContext;
+	protected final TransactionFactory.Context transactionContext;
+
+	private boolean begun;
+
+	public CMTTransaction(JDBCContext jdbcContext, TransactionFactory.Context transactionContext) {
+		this.jdbcContext = jdbcContext;
+		this.transactionContext = transactionContext;
+	}
+
+	public void begin() throws HibernateException {
+		if (begun) {
+			return;
+		}
+
+		log.debug("begin");
+		
+		boolean synchronization = jdbcContext.registerSynchronizationIfPossible();
+
+		if ( !synchronization ) {
+			throw new TransactionException("Could not register synchronization for container transaction");
+		}
+
+		begun = true;
+		
+		jdbcContext.afterTransactionBegin(this);
+	}
+
+	public void commit() throws HibernateException {
+		if (!begun) {
+			throw new TransactionException("Transaction not successfully started");
+		}
+
+		log.debug("commit");
+
+		boolean flush = !transactionContext.isFlushModeNever() &&
+		        !transactionContext.isFlushBeforeCompletionEnabled();
+
+		if (flush) {
+			transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback()
+		}
+
+		begun = false;
+
+	}
+
+	public void rollback() throws HibernateException {
+		if (!begun) {
+			throw new TransactionException("Transaction not successfully started");
+		}
+
+		log.debug("rollback");
+
+		try {
+			getTransaction().setRollbackOnly();
+		}
+		catch (SystemException se) {
+			log.error("Could not set transaction to rollback only", se);
+			throw new TransactionException("Could not set transaction to rollback only", se);
+		}
+
+		begun = false;
+
+	}
+
+	public javax.transaction.Transaction getTransaction() throws SystemException {
+		return transactionContext.getFactory().getTransactionManager().getTransaction();
+	}
+
+	public boolean isActive() throws TransactionException {
+
+		if (!begun) return false;
+
+		final int status;
+		try {
+			status = getTransaction().getStatus();
+		}
+		catch (SystemException se) {
+			log.error("Could not determine transaction status", se);
+			throw new TransactionException("Could not determine transaction status: ", se);
+		}
+		if (status==Status.STATUS_UNKNOWN) {
+			throw new TransactionException("Could not determine transaction status");
+		}
+		else {
+			return status==Status.STATUS_ACTIVE;
+		}
+	}
+
+	public boolean wasRolledBack() throws TransactionException {
+
+		if (!begun) return false;
+
+		final int status;
+		try {
+			status = getTransaction().getStatus();
+		}
+		catch (SystemException se) {
+			log.error("Could not determine transaction status", se);
+			throw new TransactionException("Could not determine transaction status", se);
+		}
+		if (status==Status.STATUS_UNKNOWN) {
+			throw new TransactionException("Could not determine transaction status");
+		}
+		else {
+			return JTAHelper.isRollback(status);
+		}
+	}
+
+	public boolean wasCommitted() throws TransactionException {
+
+		if ( !begun ) return false;
+
+		final int status;
+		try {
+			status = getTransaction().getStatus();
+		}
+		catch (SystemException se) {
+			log.error("Could not determine transaction status", se);
+			throw new TransactionException("Could not determine transaction status: ", se);
+		}
+		if (status==Status.STATUS_UNKNOWN) {
+			throw new TransactionException("Could not determine transaction status");
+		}
+		else {
+			return status==Status.STATUS_COMMITTED;
+		}
+	}
+
+	public void registerSynchronization(Synchronization sync) throws HibernateException {
+		try {
+			getTransaction().registerSynchronization(sync);
+		}
+		catch (Exception e) {
+			throw new TransactionException("Could not register synchronization", e);
+		}
+	}
+
+	public void setTimeout(int seconds) {
+		throw new UnsupportedOperationException("cannot set transaction timeout in CMT");
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/CMTTransaction.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/CMTTransactionFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/CMTTransactionFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/CMTTransactionFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+//$Id: CMTTransactionFactory.java 9595 2006-03-10 18:14:21Z steve.ebersole at jboss.com $
+package org.hibernate.transaction;
+
+import java.util.Properties;
+
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Transaction;
+import org.hibernate.TransactionException;
+import org.hibernate.util.JTAHelper;
+import org.hibernate.jdbc.JDBCContext;
+
+import javax.transaction.SystemException;
+
+/**
+ * Factory for <tt>CMTTransaction</tt>.
+ *
+ * @see CMTTransaction
+ * @author Gavin King
+ */
+public class CMTTransactionFactory implements TransactionFactory {
+
+	public ConnectionReleaseMode getDefaultReleaseMode() {
+		return ConnectionReleaseMode.AFTER_STATEMENT;
+	}
+
+	public void configure(Properties props) throws HibernateException {}
+
+	public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)
+	throws HibernateException {
+		return new CMTTransaction(jdbcContext, transactionContext);
+	}
+
+	public boolean isTransactionManagerRequired() {
+		return true;
+	}
+
+	public boolean areCallbacksLocalToHibernateTransactions() {
+		return false;
+	}
+
+	public boolean isTransactionInProgress(
+			JDBCContext jdbcContext,
+	        Context transactionContext,
+	        Transaction transaction) {
+		try {
+			return JTAHelper.isTransactionInProgress(
+					transactionContext.getFactory().getTransactionManager().getTransaction()
+			);
+		}
+		catch( SystemException se ) {
+			throw new TransactionException( "Unable to check transaction status", se );
+		}
+
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/CMTTransactionFactory.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/CacheSynchronization.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/CacheSynchronization.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/CacheSynchronization.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,99 @@
+//$Id: CacheSynchronization.java 9239 2006-02-08 22:34:34Z steveebersole $
+package org.hibernate.transaction;
+
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.TransactionException;
+import org.hibernate.jdbc.JDBCContext;
+import org.hibernate.util.JTAHelper;
+
+/**
+ * @author Gavin King
+ */
+public final class CacheSynchronization implements Synchronization {
+
+	private static final Log log = LogFactory.getLog(CacheSynchronization.class);
+
+	private final TransactionFactory.Context ctx;
+	private JDBCContext jdbcContext;
+	private final Transaction transaction;
+	private final org.hibernate.Transaction hibernateTransaction;
+
+	public CacheSynchronization(
+			TransactionFactory.Context ctx, 
+			JDBCContext jdbcContext, 
+			Transaction transaction, 
+			org.hibernate.Transaction tx
+	) {
+		this.ctx = ctx;
+		this.jdbcContext = jdbcContext;
+		this.transaction = transaction;
+		this.hibernateTransaction = tx;
+	}
+
+	public void beforeCompletion() {
+		log.trace("transaction before completion callback");
+
+		boolean flush;
+		try {
+			flush = !ctx.isFlushModeNever() &&
+			        ctx.isFlushBeforeCompletionEnabled() && 
+			        !JTAHelper.isRollback( transaction.getStatus() ); 
+					//actually, this last test is probably unnecessary, since 
+					//beforeCompletion() doesn't get called during rollback
+		}
+		catch (SystemException se) {
+			log.error("could not determine transaction status", se);
+			setRollbackOnly();
+			throw new TransactionException("could not determine transaction status in beforeCompletion()", se);
+		}
+		
+		try {
+			if (flush) {
+				log.trace("automatically flushing session");
+				ctx.managedFlush();
+			}
+		}
+		catch (RuntimeException re) {
+			setRollbackOnly();
+			throw re;
+		}
+		finally {
+			jdbcContext.beforeTransactionCompletion(hibernateTransaction);
+		}
+	}
+
+	private void setRollbackOnly() {
+		try {
+			transaction.setRollbackOnly();
+		}
+		catch (SystemException se) {
+			log.error("could not set transaction to rollback only", se);
+		}
+	}
+
+	public void afterCompletion(int status) {
+		if ( log.isTraceEnabled() ) {
+			log.trace("transaction after completion callback, status: " + status);
+		}
+		try {
+			jdbcContext.afterTransactionCompletion(status==Status.STATUS_COMMITTED, hibernateTransaction);
+		}
+		finally {
+			if ( ctx.shouldAutoClose() && !ctx.isClosed() ) {
+				log.trace("automatically closing session");
+				ctx.managedClose();
+			}
+		}
+	}
+	
+	public String toString() {
+		return CacheSynchronization.class.getName();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JBossTransactionManagerLookup.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JBossTransactionManagerLookup.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JBossTransactionManagerLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+//$Id: JBossTransactionManagerLookup.java 8435 2005-10-18 16:23:33Z steveebersole $
+package org.hibernate.transaction;
+
+/**
+ * A <tt>TransactionManager</tt> lookup strategy for JBoss
+ * @author Gavin King
+ */
+public final class JBossTransactionManagerLookup extends JNDITransactionManagerLookup {
+
+	protected String getName() {
+		return "java:/TransactionManager";
+	}
+
+	public String getUserTransactionName() {
+		return "UserTransaction";
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JDBCTransaction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JDBCTransaction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JDBCTransaction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,255 @@
+//$Id: JDBCTransaction.java 9595 2006-03-10 18:14:21Z steve.ebersole at jboss.com $
+package org.hibernate.transaction;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Transaction;
+import org.hibernate.TransactionException;
+import org.hibernate.jdbc.JDBCContext;
+
+/**
+ * Implements a basic transaction strategy for JDBC connections.This is the
+ * default <tt>Transaction</tt> implementation used if none is explicitly
+ * specified.
+ * @author Anton van Straaten, Gavin King
+ */
+public class JDBCTransaction implements Transaction {
+
+	private static final Log log = LogFactory.getLog(JDBCTransaction.class);
+
+	private final JDBCContext jdbcContext;
+	private final TransactionFactory.Context transactionContext;
+
+	private boolean toggleAutoCommit;
+	private boolean begun;
+	private boolean rolledBack;
+	private boolean committed;
+	private boolean commitFailed;
+	private List synchronizations;
+	private boolean callback;
+	private int timeout = -1;
+
+	public JDBCTransaction(JDBCContext jdbcContext, TransactionFactory.Context transactionContext) {
+		this.jdbcContext = jdbcContext;
+		this.transactionContext = transactionContext;
+	}
+
+	public void begin() throws HibernateException {
+		if (begun) {
+			return;
+		}
+		if (commitFailed) {
+			throw new TransactionException("cannot re-start transaction after failed commit");
+		}
+
+		log.debug("begin");
+
+		try {
+			toggleAutoCommit = jdbcContext.connection().getAutoCommit();
+			if ( log.isDebugEnabled() ) {
+				log.debug("current autocommit status: " + toggleAutoCommit);
+			}
+			if (toggleAutoCommit) {
+				log.debug("disabling autocommit");
+				jdbcContext.connection().setAutoCommit(false);
+			}
+		}
+		catch (SQLException e) {
+			log.error("JDBC begin failed", e);
+			throw new TransactionException("JDBC begin failed: ", e);
+		}
+
+		callback = jdbcContext.registerCallbackIfNecessary();
+
+		begun = true;
+		committed = false;
+		rolledBack = false;
+
+		if ( timeout>0 ) {
+			jdbcContext.getConnectionManager()
+					.getBatcher()
+					.setTransactionTimeout(timeout);
+		}
+
+		jdbcContext.afterTransactionBegin(this);
+	}
+
+	private void closeIfRequired() throws HibernateException {
+		if ( callback && transactionContext.shouldAutoClose() && !transactionContext.isClosed() ) {
+			try {
+				transactionContext.managedClose();
+			}
+			catch (HibernateException he) {
+				log.error("Could not close session", he);
+				//swallow, the transaction was finished
+			}
+		}
+	}
+
+	public void commit() throws HibernateException {
+		if (!begun) {
+			throw new TransactionException("Transaction not successfully started");
+		}
+
+		log.debug("commit");
+
+		if ( !transactionContext.isFlushModeNever() && callback ) {
+			transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback()
+		}
+
+		notifyLocalSynchsBeforeTransactionCompletion();
+		if ( callback ) {
+			jdbcContext.beforeTransactionCompletion( this );
+		}
+
+		try {
+			commitAndResetAutoCommit();
+			log.debug("committed JDBC Connection");
+			committed = true;
+			if ( callback ) {
+				jdbcContext.afterTransactionCompletion( true, this );
+			}
+			notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_COMMITTED );
+		}
+		catch (SQLException e) {
+			log.error("JDBC commit failed", e);
+			commitFailed = true;
+			if ( callback ) {
+				jdbcContext.afterTransactionCompletion( false, this );
+			}
+			notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_UNKNOWN );
+			throw new TransactionException("JDBC commit failed", e);
+		}
+		finally {
+			closeIfRequired();
+		}
+	}
+
+	private void commitAndResetAutoCommit() throws SQLException {
+		try {
+			jdbcContext.connection().commit();
+		}
+		finally {
+			toggleAutoCommit();
+		}
+	}
+
+	public void rollback() throws HibernateException {
+
+		if (!begun && !commitFailed) {
+			throw new TransactionException("Transaction not successfully started");
+		}
+
+		log.debug("rollback");
+
+		if (!commitFailed) {
+
+			/*notifyLocalSynchsBeforeTransactionCompletion();
+			if ( callback ) {
+				jdbcContext.notifyLocalSynchsBeforeTransactionCompletion( this );
+			}*/
+
+			try {
+				rollbackAndResetAutoCommit();
+				log.debug("rolled back JDBC Connection");
+				rolledBack = true;
+				notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_ROLLEDBACK);
+			}
+			catch (SQLException e) {
+				log.error("JDBC rollback failed", e);
+				notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_UNKNOWN);
+				throw new TransactionException("JDBC rollback failed", e);
+			}
+			finally {
+				if ( callback ) {
+					jdbcContext.afterTransactionCompletion( false, this );
+				}
+				closeIfRequired();
+			}
+		}
+	}
+
+	private void rollbackAndResetAutoCommit() throws SQLException {
+		try {
+			jdbcContext.connection().rollback();
+		}
+		finally {
+			toggleAutoCommit();
+		}
+	}
+
+	private void toggleAutoCommit() {
+		try {
+			if (toggleAutoCommit) {
+				log.debug("re-enabling autocommit");
+				jdbcContext.connection().setAutoCommit( true );
+			}
+		}
+		catch (Exception sqle) {
+			log.error("Could not toggle autocommit", sqle);
+			//swallow it (the transaction _was_ successful or successfully rolled back)
+		}
+	}
+
+	public boolean wasRolledBack() {
+		return rolledBack;
+	}
+
+	public boolean wasCommitted() {
+		return committed;
+	}
+
+	public boolean isActive() {
+		return begun && ! ( rolledBack || committed | commitFailed );
+	}
+
+	public void registerSynchronization(Synchronization sync) throws HibernateException {
+		if (sync==null) throw new NullPointerException("null Synchronization");
+		if (synchronizations==null) {
+			synchronizations = new ArrayList();
+		}
+		synchronizations.add(sync);
+	}
+
+	private void notifyLocalSynchsBeforeTransactionCompletion() {
+		if (synchronizations!=null) {
+			for ( int i=0; i<synchronizations.size(); i++ ) {
+				Synchronization sync = (Synchronization) synchronizations.get(i);
+				try {
+					sync.beforeCompletion();
+				}
+				catch (Throwable t) {
+					log.error("exception calling user Synchronization", t);
+				}
+			}
+		}
+	}
+
+	private void notifyLocalSynchsAfterTransactionCompletion(int status) {
+		begun = false;
+		if (synchronizations!=null) {
+			for ( int i=0; i<synchronizations.size(); i++ ) {
+				Synchronization sync = (Synchronization) synchronizations.get(i);
+				try {
+					sync.afterCompletion(status);
+				}
+				catch (Throwable t) {
+					log.error("exception calling user Synchronization", t);
+				}
+			}
+		}
+	}
+
+	public void setTimeout(int seconds) {
+		timeout = seconds;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JDBCTransactionFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JDBCTransactionFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JDBCTransactionFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+//$Id: JDBCTransactionFactory.java 10013 2006-06-11 17:00:19Z gavin.king at jboss.com $
+package org.hibernate.transaction;
+
+import java.util.Properties;
+
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Transaction;
+import org.hibernate.jdbc.JDBCContext;
+
+/**
+ * Factory for <tt>JDBCTransaction</tt>.
+ * @see JDBCTransaction
+ * @author Anton van Straaten
+ */
+public final class JDBCTransactionFactory implements TransactionFactory {
+
+	public ConnectionReleaseMode getDefaultReleaseMode() {
+		return ConnectionReleaseMode.AFTER_TRANSACTION;
+	}
+
+	public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)
+	throws HibernateException {
+		return new JDBCTransaction( jdbcContext, transactionContext );
+	}
+
+	public void configure(Properties props) throws HibernateException {}
+
+	public boolean isTransactionManagerRequired() {
+		return false;
+	}
+
+	public boolean areCallbacksLocalToHibernateTransactions() {
+		return true;
+	}
+
+	public boolean isTransactionInProgress(
+			JDBCContext jdbcContext,
+	        Context transactionContext,
+	        Transaction transaction) {
+//		try {
+//			// for JDBC-based transactions, we only want to return true
+//			// here if we (this transaction) are managing the transaction
+//			return transaction != null &&
+//			       transaction.isActive() &&
+//			       !jdbcContext.getConnectionManager().isAutoCommit();
+//		}
+//		catch ( SQLException e ) {
+//			// assume we are in auto-commit!
+//			return false;
+//		}
+		return transaction != null && transaction.isActive();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JNDITransactionManagerLookup.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JNDITransactionManagerLookup.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JNDITransactionManagerLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: JNDITransactionManagerLookup.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.transaction;
+
+import java.util.Properties;
+
+import javax.naming.NamingException;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.HibernateException;
+import org.hibernate.util.NamingHelper;
+
+/**
+ * Locates a <tt>TransactionManager</tt> in JNDI.
+ * @author Gavin King
+ */
+public abstract class JNDITransactionManagerLookup implements TransactionManagerLookup {
+
+	/**
+	 * @see org.hibernate.transaction.TransactionManagerLookup#getTransactionManager(java.util.Properties)
+	 */
+	public TransactionManager getTransactionManager(Properties props) throws HibernateException {
+		try {
+			return (TransactionManager) NamingHelper.getInitialContext(props).lookup( getName() );
+		}
+		catch (NamingException ne) {
+			throw new HibernateException( "Could not locate TransactionManager", ne );
+		}
+	}
+
+	protected abstract String getName();
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JOTMTransactionManagerLookup.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JOTMTransactionManagerLookup.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JOTMTransactionManagerLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+package org.hibernate.transaction;
+
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+
+import org.hibernate.HibernateException;
+
+/**
+ * TransactionManager lookup strategy for JOTM
+ * @author Low Heng Sin
+ */
+public class JOTMTransactionManagerLookup implements TransactionManagerLookup {
+
+	/**
+	 * @see org.hibernate.transaction.TransactionManagerLookup#getTransactionManager(Properties)
+	 */
+	public TransactionManager getTransactionManager(Properties props) throws HibernateException {
+		try {
+			Class clazz = Class.forName("org.objectweb.jotm.Current");
+			return (TransactionManager) clazz.getMethod("getTransactionManager", null).invoke(null, null);
+		}
+		catch (Exception e) {
+			throw new HibernateException( "Could not obtain JOTM transaction manager instance", e );
+		}
+	}
+
+	public String getUserTransactionName() {
+		return "java:comp/UserTransaction";
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JOnASTransactionManagerLookup.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JOnASTransactionManagerLookup.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JOnASTransactionManagerLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+package org.hibernate.transaction;
+
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+
+import org.hibernate.HibernateException;
+
+/**
+ * TransactionManager lookup strategy for JOnAS
+ * @author ?
+ */
+public class JOnASTransactionManagerLookup implements TransactionManagerLookup {
+
+	/**
+	 * @see org.hibernate.transaction.TransactionManagerLookup#getTransactionManager(Properties)
+	 */
+	public TransactionManager getTransactionManager(Properties props) throws HibernateException {
+		try {
+			Class clazz = Class.forName("org.objectweb.jonas_tm.Current");
+			return (TransactionManager) clazz.getMethod("getTransactionManager", null).invoke(null, null);
+		}
+		catch (Exception e) {
+			throw new HibernateException( "Could not obtain JOnAS transaction manager instance", e );
+		}
+	}
+
+	public String getUserTransactionName() {
+		return "java:comp/UserTransaction";
+	}
+
+}
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JRun4TransactionManagerLookup.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JRun4TransactionManagerLookup.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JRun4TransactionManagerLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+package org.hibernate.transaction;
+
+/**
+ * TransactionManager lookup strategy for JRun4
+ * @author Joseph Bissen
+ */
+public class JRun4TransactionManagerLookup extends JNDITransactionManagerLookup {
+
+	protected String getName() {
+		return "java:/TransactionManager";
+	}
+
+	public String getUserTransactionName() {
+		return "java:comp/UserTransaction";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JTATransaction.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JTATransaction.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JTATransaction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,339 @@
+//$Id: JTATransaction.java 9601 2006-03-11 18:17:43Z epbernard $
+package org.hibernate.transaction;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.TransactionManager;
+import javax.transaction.UserTransaction;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.Transaction;
+import org.hibernate.TransactionException;
+import org.hibernate.jdbc.JDBCContext;
+import org.hibernate.util.JTAHelper;
+
+/**
+ * Implements a basic transaction strategy for JTA transactions. Instances check to
+ * see if there is an existing JTA transaction. If none exists, a new transaction
+ * is started. If one exists, all work is done in the existing context. The
+ * following properties are used to locate the underlying <tt>UserTransaction</tt>:
+ * <br><br>
+ * <table>
+ * <tr><td><tt>hibernate.jndi.url</tt></td><td>JNDI initial context URL</td></tr>
+ * <tr><td><tt>hibernate.jndi.class</tt></td><td>JNDI provider class</td></tr>
+ * <tr><td><tt>jta.UserTransaction</tt></td><td>JNDI name</td></tr>
+ * </table>
+ * @author Gavin King
+ */
+public class JTATransaction implements Transaction {
+
+	private static final Log log = LogFactory.getLog(JTATransaction.class);
+
+	private final JDBCContext jdbcContext;
+	private final TransactionFactory.Context transactionContext;
+
+	private UserTransaction ut;
+	private boolean newTransaction;
+	private boolean begun;
+	private boolean commitFailed;
+	private boolean commitSucceeded;
+	private boolean callback;
+	
+	public JTATransaction(
+			InitialContext context, 
+			String utName, 
+			JDBCContext jdbcContext, 
+			TransactionFactory.Context transactionContext
+	) {
+		this.jdbcContext = jdbcContext;
+		this.transactionContext = transactionContext;
+
+		log.debug("Looking for UserTransaction under: " + utName);
+		
+		try {
+			ut = (UserTransaction) context.lookup(utName);
+		}
+		catch (NamingException ne) {
+			log.error("Could not find UserTransaction in JNDI", ne);
+			throw new TransactionException("Could not find UserTransaction in JNDI: ", ne);
+		}
+		if (ut==null) {
+			throw new AssertionFailure("A naming service lookup returned null");
+		}
+
+		log.debug("Obtained UserTransaction");
+	}
+
+	public void begin() throws HibernateException {
+		if (begun) {
+			return;
+		}
+		if (commitFailed) {
+			throw new TransactionException("cannot re-start transaction after failed commit");
+		}
+		
+		log.debug("begin");
+
+		try {
+			newTransaction = ut.getStatus() == Status.STATUS_NO_TRANSACTION;
+			if (newTransaction) {
+				ut.begin();
+				log.debug("Began a new JTA transaction");
+			}
+		}
+		catch (Exception e) {
+			log.error("JTA transaction begin failed", e);
+			throw new TransactionException("JTA transaction begin failed", e);
+		}
+
+		/*if (newTransaction) {
+			// don't need a synchronization since we are committing
+			// or rolling back the transaction ourselves - assuming
+			// that we do no work in beforeTransactionCompletion()
+			synchronization = false;
+		}*/
+
+		boolean synchronization = jdbcContext.registerSynchronizationIfPossible();
+
+		if ( !newTransaction && !synchronization ) {
+			log.warn("You should set hibernate.transaction.manager_lookup_class if cache is enabled");
+		}
+
+		if (!synchronization) {
+			//if we could not register a synchronization,
+			//do the before/after completion callbacks
+			//ourself (but we need to let jdbcContext
+			//know that this is what we are going to
+			//do, so it doesn't keep trying to register
+			//synchronizations)
+			callback = jdbcContext.registerCallbackIfNecessary();
+		}
+
+		begun = true;
+		commitSucceeded = false;
+		
+		jdbcContext.afterTransactionBegin(this);
+	}
+
+	public void commit() throws HibernateException {
+		if (!begun) {
+			throw new TransactionException("Transaction not successfully started");
+		}
+
+		log.debug("commit");
+
+		boolean flush = !transactionContext.isFlushModeNever()
+		        && ( callback || !transactionContext.isFlushBeforeCompletionEnabled() );
+
+		if (flush) {
+			transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback()
+		}
+
+		if (callback && newTransaction) {
+			jdbcContext.beforeTransactionCompletion(this);
+		}
+
+		closeIfRequired();
+
+		if (newTransaction) {
+			try {
+				ut.commit();
+				commitSucceeded = true;
+				log.debug("Committed JTA UserTransaction");
+			}
+			catch (Exception e) {
+				commitFailed = true; // so the transaction is already rolled back, by JTA spec
+				log.error("JTA commit failed", e);
+				throw new TransactionException("JTA commit failed: ", e);
+			}
+			finally {
+				afterCommitRollback();
+			}
+		}
+		else {
+			// this one only really needed for badly-behaved applications!
+			// (if the TransactionManager has a Sychronization registered,
+			// its a noop)
+			// (actually we do need it for downgrading locks)
+			afterCommitRollback();
+		}
+
+	}
+
+	public void rollback() throws HibernateException {
+		if (!begun && !commitFailed) {
+			throw new TransactionException("Transaction not successfully started");
+		}
+
+		log.debug("rollback");
+
+		/*if (!synchronization && newTransaction && !commitFailed) {
+			jdbcContext.beforeTransactionCompletion(this);
+		}*/
+
+		try {
+			closeIfRequired();
+		}
+		catch (Exception e) {
+			log.error("could not close session during rollback", e);
+			//swallow it, and continue to roll back JTA transaction
+		}
+
+		try {
+			if (newTransaction) {
+				if (!commitFailed) {
+					ut.rollback();
+					log.debug("Rolled back JTA UserTransaction");
+				}
+			}
+			else {
+				ut.setRollbackOnly();
+				log.debug("set JTA UserTransaction to rollback only");
+			}
+		}
+		catch (Exception e) {
+			log.error("JTA rollback failed", e);
+			throw new TransactionException("JTA rollback failed", e);
+		}
+		finally {
+			afterCommitRollback();
+		}
+	}
+
+	private static final int NULL = Integer.MIN_VALUE;
+
+	private void afterCommitRollback() throws TransactionException {
+		
+		begun = false;
+
+		if (callback) { // this method is a noop if there is a Synchronization!
+
+			if (!newTransaction) {
+				log.warn("You should set hibernate.transaction.manager_lookup_class if cache is enabled");
+			}
+			int status=NULL;
+			try {
+				status = ut.getStatus();
+			}
+			catch (Exception e) {
+				log.error("Could not determine transaction status after commit", e);
+				throw new TransactionException("Could not determine transaction status after commit", e);
+			}
+			finally {
+				/*if (status!=Status.STATUS_COMMITTED && status!=Status.STATUS_ROLLEDBACK) {
+					log.warn("Transaction not complete - you should set hibernate.transaction.manager_lookup_class if cache is enabled");
+					//throw exception??
+				}*/
+				jdbcContext.afterTransactionCompletion(status==Status.STATUS_COMMITTED, this);
+			}
+
+		}
+	}
+
+	public boolean wasRolledBack() throws TransactionException {
+
+		//if (!begun) return false;
+		//if (commitFailed) return true;
+
+		final int status;
+		try {
+			status = ut.getStatus();
+		}
+		catch (SystemException se) {
+			log.error("Could not determine transaction status", se);
+			throw new TransactionException("Could not determine transaction status", se);
+		}
+		if (status==Status.STATUS_UNKNOWN) {
+			throw new TransactionException("Could not determine transaction status");
+		}
+		else {
+			return JTAHelper.isRollback(status);
+		}
+	}
+
+	public boolean wasCommitted() throws TransactionException {
+
+		//if (!begun || commitFailed) return false;
+
+		final int status;
+		try {
+			status = ut.getStatus();
+		}
+		catch (SystemException se) {
+			log.error("Could not determine transaction status", se);
+			throw new TransactionException("Could not determine transaction status: ", se);
+		}
+		if (status==Status.STATUS_UNKNOWN) {
+			throw new TransactionException("Could not determine transaction status");
+		}
+		else {
+			return status==Status.STATUS_COMMITTED;
+		}
+	}
+	
+	public boolean isActive() throws TransactionException {
+
+		if (!begun || commitFailed || commitSucceeded) return false;
+
+		final int status;
+		try {
+			status = ut.getStatus();
+		}
+		catch (SystemException se) {
+			log.error("Could not determine transaction status", se);
+			throw new TransactionException("Could not determine transaction status: ", se);
+		}
+		if (status==Status.STATUS_UNKNOWN) {
+			throw new TransactionException("Could not determine transaction status");
+		}
+		else {
+			return status==Status.STATUS_ACTIVE;
+		}
+	}
+
+	public void registerSynchronization(Synchronization sync) throws HibernateException {
+		if (getTransactionManager()==null) {
+			throw new IllegalStateException("JTA TransactionManager not available");
+		}
+		else {
+			try {
+				getTransactionManager().getTransaction().registerSynchronization(sync);
+			}
+			catch (Exception e) {
+				throw new TransactionException("could not register synchronization", e);
+			}
+		}
+	}
+
+	private TransactionManager getTransactionManager() {
+		return transactionContext.getFactory().getTransactionManager();
+	}
+
+	private void closeIfRequired() throws HibernateException {
+		boolean close = callback && 
+				transactionContext.shouldAutoClose() && 
+				!transactionContext.isClosed();
+		if ( close ) {
+			transactionContext.managedClose();
+		}
+	}
+
+	public void setTimeout(int seconds) {
+		try {
+			ut.setTransactionTimeout(seconds);
+		}
+		catch (SystemException se) {
+			throw new TransactionException("could not set transaction timeout", se);
+		}
+	}
+
+	protected UserTransaction getUserTransaction() {
+		return ut;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JTATransactionFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JTATransactionFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/JTATransactionFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,111 @@
+//$Id: JTATransactionFactory.java 10347 2006-08-24 15:37:11Z steve.ebersole at jboss.com $
+package org.hibernate.transaction;
+
+import java.util.Properties;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.transaction.SystemException;
+import javax.transaction.UserTransaction;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Transaction;
+import org.hibernate.TransactionException;
+import org.hibernate.jdbc.JDBCContext;
+import org.hibernate.cfg.Environment;
+import org.hibernate.util.NamingHelper;
+import org.hibernate.util.JTAHelper;
+
+/**
+ * Factory for <tt>JTATransaction</tt>.
+ *
+ * @see JTATransaction
+ * @author Gavin King
+ */
+public class JTATransactionFactory implements TransactionFactory {
+
+	private static final Log log = LogFactory.getLog(JTATransactionFactory.class);
+	private static final String DEFAULT_USER_TRANSACTION_NAME = "java:comp/UserTransaction";
+
+	protected InitialContext context;
+	protected String utName;
+
+	public void configure(Properties props) throws HibernateException {
+		try {
+			context = NamingHelper.getInitialContext(props);
+		}
+		catch (NamingException ne) {
+			log.error("Could not obtain initial context", ne);
+			throw new HibernateException( "Could not obtain initial context", ne );
+		}
+
+		utName = props.getProperty(Environment.USER_TRANSACTION);
+
+		if (utName==null) {
+			TransactionManagerLookup lookup = TransactionManagerLookupFactory.getTransactionManagerLookup(props);
+			if (lookup!=null) utName = lookup.getUserTransactionName();
+		}
+
+		if (utName==null) utName = DEFAULT_USER_TRANSACTION_NAME;
+	}
+
+	public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)
+	throws HibernateException {
+		return new JTATransaction(context, utName, jdbcContext, transactionContext);
+	}
+
+	public ConnectionReleaseMode getDefaultReleaseMode() {
+		return ConnectionReleaseMode.AFTER_STATEMENT;
+	}
+
+	public boolean isTransactionManagerRequired() {
+		return false;
+	}
+
+	public boolean areCallbacksLocalToHibernateTransactions() {
+		return false;
+	}
+
+	public boolean isTransactionInProgress(
+			JDBCContext jdbcContext,
+	        Context transactionContext,
+	        Transaction transaction) {
+		try {
+            // Essentially:
+			// 1) If we have a local (Hibernate) transaction in progress
+			//      and it already has the UserTransaction cached, use that
+			//      UserTransaction to determine the status.
+			// 2) If a transaction manager has been located, use
+			//      that transaction manager to determine the status.
+			// 3) Finally, as the last resort, try to lookup the
+			//      UserTransaction via JNDI and use that to determine the
+			//      status.
+            if ( transaction != null ) {
+				UserTransaction ut = ( ( JTATransaction ) transaction ).getUserTransaction();
+                if ( ut != null ) {
+                    return JTAHelper.isInProgress( ut.getStatus() );
+                }
+            }
+
+            if ( jdbcContext.getFactory().getTransactionManager() != null ) {
+                return JTAHelper.isInProgress( jdbcContext.getFactory().getTransactionManager().getStatus() );
+            }
+            else {
+                try {
+					UserTransaction ut = ( UserTransaction ) context.lookup( utName );
+			        return ut != null && JTAHelper.isInProgress( ut.getStatus() );
+				}
+				catch ( NamingException ne ) {
+					throw new TransactionException( "Unable to locate UserTransaction to check status", ne );
+				}
+            }
+		}
+		catch( SystemException se ) {
+			throw new TransactionException( "Unable to check transaction status", se );
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/OC4JTransactionManagerLookup.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/OC4JTransactionManagerLookup.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/OC4JTransactionManagerLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+package org.hibernate.transaction;
+
+/**
+ * TransactionManagerLookup for the OC4J (Oracle) app-server.
+ * 
+ * @author Stijn Janssens
+ */
+public class OC4JTransactionManagerLookup extends JNDITransactionManagerLookup {
+	protected String getName() {
+		return "java:comp/pm/TransactionManager";
+	}
+
+	public String getUserTransactionName() {
+		return "java:comp/UserTransaction";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/OrionTransactionManagerLookup.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/OrionTransactionManagerLookup.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/OrionTransactionManagerLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+//$Id: OrionTransactionManagerLookup.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.transaction;
+
+/**
+ * TransactionManager lookup strategy for Orion
+ * @author Gavin King
+ */
+public class OrionTransactionManagerLookup
+extends JNDITransactionManagerLookup {
+
+	/**
+	 * @see org.hibernate.transaction.JNDITransactionManagerLookup#getName()
+	 */
+	protected String getName() {
+		return "java:comp/UserTransaction";
+	}
+
+	public String getUserTransactionName() {
+		return "java:comp/UserTransaction";
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/ResinTransactionManagerLookup.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/ResinTransactionManagerLookup.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/ResinTransactionManagerLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+//$Id: ResinTransactionManagerLookup.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.transaction;
+
+/**
+ * TransactionManager lookup strategy for Resin
+ * @author Aapo Laakkonen
+ */
+public class ResinTransactionManagerLookup
+extends JNDITransactionManagerLookup {
+
+	/**
+	 * @see org.hibernate.transaction.JNDITransactionManagerLookup#getName()
+	 */
+	protected String getName() {
+		return "java:comp/TransactionManager";
+	}
+
+	public String getUserTransactionName() {
+		return "java:comp/UserTransaction";
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/SunONETransactionManagerLookup.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/SunONETransactionManagerLookup.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/SunONETransactionManagerLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+//$Id: SunONETransactionManagerLookup.java 11274 2007-03-12 00:18:38Z epbernard $
+package org.hibernate.transaction;
+
+/**
+ * TransactionManager lookup strategy for Sun ONE Application Server 7 and above
+ * 
+ * @author Robert Davidson, Sanjeev Krishnan
+ * @author Emmanuel Bernard
+ */
+public class SunONETransactionManagerLookup extends JNDITransactionManagerLookup {
+
+	protected String getName() {
+		return "java:appserver/TransactionManager";
+	}
+
+	public String getUserTransactionName() {
+		return "java:comp/UserTransaction";
+	}
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,87 @@
+//$Id: TransactionFactory.java 9595 2006-03-10 18:14:21Z steve.ebersole at jboss.com $
+package org.hibernate.transaction;
+
+import java.util.Properties;
+
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Transaction;
+import org.hibernate.jdbc.JDBCContext;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * An abstract factory for <tt>Transaction</tt> instances. Concrete implementations
+ * are specified by <tt>hibernate.transaction.factory_class</tt>.<br>
+ * <br>
+ * Implementors must be threadsafe and should declare a public default constructor.
+ * @see Transaction
+ *
+ * @author Anton van Straaten, Gavin King
+ */
+public interface TransactionFactory {
+
+	public static interface Context {
+		public SessionFactoryImplementor getFactory();
+//		public boolean isOpen();
+		public boolean isClosed();
+
+		public boolean isFlushModeNever();
+		public boolean isFlushBeforeCompletionEnabled();
+		public void managedFlush();
+
+		public boolean shouldAutoClose();
+		public void managedClose();
+	}
+
+	/**
+	 * Begin a transaction and return the associated <tt>Transaction</tt> instance.
+	 *
+	 * @param jdbcContext  The jdbc context to which the transaction belongs
+	 * @param context The contract regarding the context in which this transaction will operate.
+	 * @return Transaction
+	 * @throws HibernateException
+	 */
+	public Transaction createTransaction(JDBCContext jdbcContext, Context context) throws HibernateException;
+
+	/**
+	 * Configure from the given properties.
+	 * @param props
+	 * @throws HibernateException
+	 */
+	public void configure(Properties props) throws HibernateException;
+	
+	/**
+	 * Get the default connection release mode
+	 */
+	public ConnectionReleaseMode getDefaultReleaseMode();
+	
+	/**
+	 * Do we require access to the JTA TransactionManager for
+	 * this strategy?
+	 */
+	public boolean isTransactionManagerRequired();
+
+	/**
+	 * Are all transaction callbacks local to Hibernate Transactions?
+	 * Or can the callbacks originate from some other source (e.g.
+	 * a JTA Synchronization).
+	 *
+	 * @return true if callbacks only ever originate from
+	 * the Hibernate {@link Transaction}; false otherwise.
+	 */
+	public boolean areCallbacksLocalToHibernateTransactions();
+
+	/**
+	 * Determine whether an underlying transaction is in progress.
+	 * <p/>
+	 * Mainly this is used in determining whether to register a
+	 * synchronization as well as whether or not to circumvent
+	 * auto flushing outside transactions.
+	 *
+	 * @param jdbcContext
+	 * @param transactionContext
+	 * @param transaction
+	 * @return true if an underlying transaction is know to be in effect.
+	 */
+	public boolean isTransactionInProgress(JDBCContext jdbcContext, Context transactionContext, Transaction transaction);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionFactoryFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionFactoryFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionFactoryFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,56 @@
+package org.hibernate.transaction;
+
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * @author Gavin King
+ */
+public final class TransactionFactoryFactory {
+
+	private static final Log log = LogFactory.getLog(TransactionFactoryFactory.class);
+
+	/**
+	 * Obtain a TransactionFactory with the transaction handling strategy
+	 * specified by the given Properties.
+	 *
+	 * @param transactionProps transaction properties
+	 * @return TransactionFactory
+	 * @throws HibernateException
+	 */
+	public static TransactionFactory buildTransactionFactory(Properties transactionProps) throws HibernateException {
+
+		String strategyClassName = transactionProps.getProperty(Environment.TRANSACTION_STRATEGY);
+		if (strategyClassName==null) {
+			log.info("Using default transaction strategy (direct JDBC transactions)");
+			return new JDBCTransactionFactory();
+		}
+		log.info("Transaction strategy: " + strategyClassName);
+		TransactionFactory factory;
+		try {
+			factory = (TransactionFactory) ReflectHelper.classForName(strategyClassName).newInstance();
+		}
+		catch (ClassNotFoundException e) {
+			log.error("TransactionFactory class not found", e);
+			throw new HibernateException("TransactionFactory class not found: " + strategyClassName);
+		}
+		catch (IllegalAccessException e) {
+			log.error("Failed to instantiate TransactionFactory", e);
+			throw new HibernateException("Failed to instantiate TransactionFactory: " + e);
+		}
+		catch (java.lang.InstantiationException e) {
+			log.error("Failed to instantiate TransactionFactory", e);
+			throw new HibernateException("Failed to instantiate TransactionFactory: " + e);
+		}
+		factory.configure(transactionProps);
+		return factory;
+	}
+
+	private TransactionFactoryFactory() {}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionManagerLookup.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionManagerLookup.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionManagerLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+//$Id: TransactionManagerLookup.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.transaction;
+
+import java.util.Properties;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Concrete implementations locate and return the JTA
+ * <tt>TransactionManager</tt>.
+ * @author Gavin King
+ */
+public interface TransactionManagerLookup {
+
+	/**
+	 * Obtain the JTA <tt>TransactionManager</tt>
+	 */
+	public TransactionManager getTransactionManager(Properties props) throws HibernateException;
+
+	/**
+	 * Return the JNDI name of the JTA <tt>UserTransaction</tt>
+	 * or <tt>null</tt> (optional operation).
+	 */
+	public String getUserTransactionName();
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionManagerLookupFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionManagerLookupFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/TransactionManagerLookupFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+//$Id: TransactionManagerLookupFactory.java 11412 2007-04-17 14:38:51Z max.andersen at jboss.com $
+package org.hibernate.transaction;
+
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * @author Gavin King
+ */
+public final class TransactionManagerLookupFactory {
+
+	private static final Log log = LogFactory.getLog(TransactionManagerLookupFactory.class);
+
+	private TransactionManagerLookupFactory() {}
+
+	public static final TransactionManager getTransactionManager(Properties props) throws HibernateException {
+		log.info("obtaining TransactionManager");
+		return getTransactionManagerLookup(props).getTransactionManager(props);
+	}
+
+	public static final TransactionManagerLookup getTransactionManagerLookup(Properties props) throws HibernateException {
+
+		String tmLookupClass = props.getProperty(Environment.TRANSACTION_MANAGER_STRATEGY);
+		if (tmLookupClass==null) {
+			log.info("No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)");
+			return null;
+		}
+		else {
+
+			log.info("instantiating TransactionManagerLookup: " + tmLookupClass);
+
+			try {
+				TransactionManagerLookup lookup = (TransactionManagerLookup) ReflectHelper.classForName(tmLookupClass).newInstance();
+				log.info("instantiated TransactionManagerLookup");
+				return lookup;
+			}
+			catch (Exception e) {
+				log.error("Could not instantiate TransactionManagerLookup", e);
+				throw new HibernateException("Could not instantiate TransactionManagerLookup '" + tmLookupClass + "'");
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/WebSphereExtendedJTATransactionLookup.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/WebSphereExtendedJTATransactionLookup.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/WebSphereExtendedJTATransactionLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,217 @@
+//$Id: WebSphereExtendedJTATransactionLookup.java 11498 2007-05-09 14:55:16Z steve.ebersole at jboss.com $
+package org.hibernate.transaction;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Properties;
+
+import javax.naming.NamingException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAResource;
+
+import org.hibernate.HibernateException;
+import org.hibernate.util.NamingHelper;
+
+/**
+ * TransactionManagerLookup implementation intended for use with WebSphere
+ * Application Server (WAS).
+ * <p/>
+ * WAS, unlike every other app server on the planet, does not allow direct
+ * access to the JTS TransactionManager.  Instead, for common transaction-
+ * related tasks users must utilize a proprietary API known as
+ * ExtendedJTATransaction.
+ * <p/>
+ * Even more unfortunate, the exact TransactionManagerLookup to use inside of
+ * WAS is highly dependent upon (1) WAS version as well as (2) the WAS
+ * container in which Hibernate will be utilized.
+ * <p/>
+ * WebSphereExtendedJTATransactionLookup is reported to work on WAS version 6
+ * in any of the standard J2EE/JEE component containers.
+ *
+ * @author Gavin King
+ * @author <a href="mailto:jesper at udby.com>Jesper Udby</a>
+ */
+public class WebSphereExtendedJTATransactionLookup implements TransactionManagerLookup {
+
+	public TransactionManager getTransactionManager(Properties props) {
+		return new TransactionManagerAdapter( props );
+	}
+
+	public String getUserTransactionName() {
+		return "java:comp/UserTransaction";
+	}
+
+	public static class TransactionManagerAdapter implements TransactionManager {
+		private final Properties properties;
+		private final Class synchronizationCallbackClass;
+		private final Method registerSynchronizationMethod;
+		private final Method getLocalIdMethod;
+		private Object extendedJTATransaction;
+
+		private TransactionManagerAdapter(Properties props) throws HibernateException {
+			this.properties = props;
+			try {
+				synchronizationCallbackClass = Class.forName( "com.ibm.websphere.jtaextensions.SynchronizationCallback" );
+				Class extendedJTATransactionClass = Class.forName( "com.ibm.websphere.jtaextensions.ExtendedJTATransaction" );
+				registerSynchronizationMethod = extendedJTATransactionClass.getMethod(
+						"registerSynchronizationCallbackForCurrentTran",
+						new Class[] { synchronizationCallbackClass }
+				);
+				getLocalIdMethod = extendedJTATransactionClass.getMethod( "getLocalId", null );
+
+			}
+			catch ( ClassNotFoundException cnfe ) {
+				throw new HibernateException( cnfe );
+			}
+			catch ( NoSuchMethodException nsme ) {
+				throw new HibernateException( nsme );
+			}
+		}
+
+		public void begin() throws NotSupportedException, SystemException {
+			throw new UnsupportedOperationException();
+		}
+
+		public void commit() throws UnsupportedOperationException {
+			throw new UnsupportedOperationException();
+		}
+
+		public int getStatus() throws UnsupportedOperationException {
+			throw new UnsupportedOperationException();
+		}
+
+		public Transaction getTransaction() throws SystemException {
+			return new TransactionAdapter( properties );
+		}
+
+		public void resume(Transaction txn) throws UnsupportedOperationException {
+			throw new UnsupportedOperationException();
+		}
+
+		public void rollback() throws UnsupportedOperationException {
+			throw new UnsupportedOperationException();
+		}
+
+		public void setRollbackOnly() throws UnsupportedOperationException {
+			throw new UnsupportedOperationException();
+		}
+
+		public void setTransactionTimeout(int i) throws UnsupportedOperationException {
+			throw new UnsupportedOperationException();
+		}
+
+		public Transaction suspend() throws UnsupportedOperationException {
+			throw new UnsupportedOperationException();
+		}
+
+		public class TransactionAdapter implements Transaction {
+
+			private TransactionAdapter(Properties props) {
+				try {
+					if ( extendedJTATransaction == null ) {
+						extendedJTATransaction = NamingHelper.getInitialContext( props )
+								.lookup( "java:comp/websphere/ExtendedJTATransaction" );
+					}
+				}
+				catch (NamingException ne) {
+					throw new HibernateException(ne);
+				}
+			}
+
+			public void registerSynchronization(final Synchronization synchronization)
+					throws RollbackException, IllegalStateException,
+					SystemException {
+
+				final InvocationHandler ih = new InvocationHandler() {
+
+					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+						if ( "afterCompletion".equals( method.getName() ) ) {
+							int status = args[2].equals(Boolean.TRUE) ?
+									Status.STATUS_COMMITTED :
+									Status.STATUS_UNKNOWN;
+							synchronization.afterCompletion(status);
+						}
+						else if ( "beforeCompletion".equals( method.getName() ) ) {
+							synchronization.beforeCompletion();
+						}
+						else if ( "toString".equals( method.getName() ) ) {
+							return synchronization.toString();
+						}
+						return null;
+					}
+
+				};
+
+				final Object synchronizationCallback = Proxy.newProxyInstance(
+						getClass().getClassLoader(),
+						new Class[] { synchronizationCallbackClass },
+						ih
+					);
+
+				try {
+					registerSynchronizationMethod.invoke(
+							extendedJTATransaction,
+							new Object[] { synchronizationCallback }
+						);
+				}
+				catch (Exception e) {
+					throw new HibernateException(e);
+				}
+
+			}
+
+			public int hashCode() {
+				return getLocalId().hashCode();
+			}
+
+			public boolean equals(Object other) {
+				if ( !(other instanceof TransactionAdapter) ) return false;
+				TransactionAdapter that = (TransactionAdapter) other;
+				return getLocalId().equals( that.getLocalId() );
+			}
+
+			private Object getLocalId() throws HibernateException {
+				try {
+					return getLocalIdMethod.invoke( extendedJTATransaction, null );
+				}
+				catch ( Exception e ) {
+					throw new HibernateException( e );
+				}
+			}
+
+			public void commit() throws UnsupportedOperationException {
+				throw new UnsupportedOperationException();
+			}
+
+			public boolean delistResource(XAResource resource, int i) throws UnsupportedOperationException {
+				throw new UnsupportedOperationException();
+			}
+
+			public boolean enlistResource(XAResource resource) throws UnsupportedOperationException {
+				throw new UnsupportedOperationException();
+			}
+
+			public int getStatus() {
+				return new Integer(0).equals( getLocalId() ) ?
+						Status.STATUS_NO_TRANSACTION : Status.STATUS_ACTIVE;
+			}
+
+			public void rollback() throws UnsupportedOperationException {
+				throw new UnsupportedOperationException();
+			}
+
+			public void setRollbackOnly() throws UnsupportedOperationException {
+				throw new UnsupportedOperationException();
+			}
+		}
+
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/WebSphereExtendedJTATransactionLookup.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/WebSphereTransactionManagerLookup.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/WebSphereTransactionManagerLookup.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/WebSphereTransactionManagerLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,68 @@
+//$Id: WebSphereTransactionManagerLookup.java 8469 2005-10-26 22:03:03Z oneovthafew $
+package org.hibernate.transaction;
+
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.HibernateException;
+
+/**
+ * TransactionManager lookup strategy for WebSphere (versions 4, 5.0 and 5.1)
+ * @author Gavin King
+ */
+public class WebSphereTransactionManagerLookup implements TransactionManagerLookup {
+
+	private static final Log log = LogFactory.getLog(WebSphereTransactionManagerLookup.class);
+	private final int wsVersion;
+	private final Class tmfClass;
+	
+	public WebSphereTransactionManagerLookup() {
+		try {
+			Class clazz;
+			int version;
+			try {
+				clazz = Class.forName("com.ibm.ws.Transaction.TransactionManagerFactory");
+				version = 5;
+				log.info("WebSphere 5.1");
+			}
+			catch (Exception e) {
+				try {
+					clazz = Class.forName("com.ibm.ejs.jts.jta.TransactionManagerFactory");
+					version = 5;
+					log.info("WebSphere 5.0");
+				} 
+				catch (Exception e2) {
+					clazz = Class.forName("com.ibm.ejs.jts.jta.JTSXA");
+					version = 4;
+					log.info("WebSphere 4");
+				}
+			}
+
+			tmfClass=clazz;
+			wsVersion=version;
+		}
+		catch (Exception e) {
+			throw new HibernateException( "Could not obtain WebSphere TransactionManagerFactory instance", e );
+		}
+	}
+
+	public TransactionManager getTransactionManager(Properties props) throws HibernateException {
+		try {
+			return (TransactionManager) tmfClass.getMethod("getTransactionManager", null).invoke(null, null);
+		}
+		catch (Exception e) {
+			throw new HibernateException( "Could not obtain WebSphere TransactionManager", e );
+		}
+	}
+
+	public String getUserTransactionName() {
+		return wsVersion==5 ?
+			"java:comp/UserTransaction":
+			"jta/usertransaction";
+	}
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/WeblogicTransactionManagerLookup.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/WeblogicTransactionManagerLookup.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/WeblogicTransactionManagerLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+//$Id: WeblogicTransactionManagerLookup.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.transaction;
+
+/**
+ * TransactionManager lookup strategy for WebLogic
+ * @author Gavin King
+ */
+public final class WeblogicTransactionManagerLookup extends JNDITransactionManagerLookup {
+
+	/**
+	 * @see org.hibernate.transaction.JNDITransactionManagerLookup#getName()
+	 */
+	protected String getName() {
+		return "javax.transaction.TransactionManager";
+	}
+
+	public String getUserTransactionName() {
+		return "javax.transaction.UserTransaction";
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package abstracts the underlying transaction mechanism
+	(JTA or JDBC) and provides strategies for obtaining application
+	server <tt>TransactionManager</tt>s.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/transaction/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transform/AliasToBeanConstructorResultTransformer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transform/AliasToBeanConstructorResultTransformer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transform/AliasToBeanConstructorResultTransformer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+package org.hibernate.transform;
+
+import java.lang.reflect.Constructor;
+import java.util.List;
+
+import org.hibernate.QueryException;
+
+public class AliasToBeanConstructorResultTransformer implements ResultTransformer {
+
+	private Constructor constructor;
+
+	public AliasToBeanConstructorResultTransformer(Constructor constructor) {
+		this.constructor = constructor;
+	}
+	
+	public Object transformTuple(Object[] tuple, String[] aliases) {
+		try {
+			return constructor.newInstance( tuple );
+		}
+		catch ( Exception e ) {
+			throw new QueryException( 
+					"could not instantiate: " + 
+					constructor.getDeclaringClass().getName(), 
+					e );
+		}
+	}
+
+	public List transformList(List collection) {
+		return collection;
+	}
+
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transform/AliasToBeanResultTransformer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transform/AliasToBeanResultTransformer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transform/AliasToBeanResultTransformer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,81 @@
+/*
+ * Created on 27-Jan-2005
+ *
+ */
+package org.hibernate.transform;
+
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.property.ChainedPropertyAccessor;
+import org.hibernate.property.PropertyAccessor;
+import org.hibernate.property.PropertyAccessorFactory;
+import org.hibernate.property.Setter;
+
+/**
+ * Result transformer that allows to transform a result to 
+ * a user specified class which will be populated via setter  
+ * methods or fields matching the alias names. 
+ * 
+ * <pre>
+ * List resultWithAliasedBean = s.createCriteria(Enrolment.class)
+ *			.createAlias("student", "st")
+ *			.createAlias("course", "co")
+ *			.setProjection( Projections.projectionList()
+ *					.add( Projections.property("co.description"), "courseDescription" )
+ *			)
+ *			.setResultTransformer( new AliasToBeanResultTransformer(StudentDTO.class) )
+ *			.list();
+ *
+ *  StudentDTO dto = (StudentDTO)resultWithAliasedBean.get(0);
+ *	</pre>
+ *
+ * @author max
+ *
+ */
+public class AliasToBeanResultTransformer implements ResultTransformer {
+	
+	private final Class resultClass;
+	private Setter[] setters;
+	private PropertyAccessor propertyAccessor;
+	
+	public AliasToBeanResultTransformer(Class resultClass) {
+		if(resultClass==null) throw new IllegalArgumentException("resultClass cannot be null");
+		this.resultClass = resultClass;
+		propertyAccessor = new ChainedPropertyAccessor(new PropertyAccessor[] { PropertyAccessorFactory.getPropertyAccessor(resultClass,null), PropertyAccessorFactory.getPropertyAccessor("field")}); 		
+	}
+
+	public Object transformTuple(Object[] tuple, String[] aliases) {
+		Object result;
+		
+		try {
+			if(setters==null) {
+				setters = new Setter[aliases.length];
+				for (int i = 0; i < aliases.length; i++) {
+					String alias = aliases[i];
+					if(alias != null) {
+						setters[i] = propertyAccessor.getSetter(resultClass, alias);
+					}
+				}
+			}
+			result = resultClass.newInstance();
+			
+			for (int i = 0; i < aliases.length; i++) {
+				if(setters[i]!=null) {
+					setters[i].set(result, tuple[i], null);
+				}
+			}
+		} catch (InstantiationException e) {
+			throw new HibernateException("Could not instantiate resultclass: " + resultClass.getName());
+		} catch (IllegalAccessException e) {
+			throw new HibernateException("Could not instantiate resultclass: " + resultClass.getName());
+		}
+		
+		return result;
+	}
+
+	public List transformList(List collection) {
+		return collection;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transform/AliasToEntityMapResultTransformer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transform/AliasToEntityMapResultTransformer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transform/AliasToEntityMapResultTransformer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+//$Id: AliasToEntityMapResultTransformer.java 9649 2006-03-17 11:25:05Z max.andersen at jboss.com $
+package org.hibernate.transform;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Gavin King
+ */
+public class AliasToEntityMapResultTransformer implements ResultTransformer {
+
+	public Object transformTuple(Object[] tuple, String[] aliases) {
+		Map result = new HashMap(tuple.length);
+		for ( int i=0; i<tuple.length; i++ ) {
+			String alias = aliases[i];
+			if ( alias!=null ) {
+				result.put( alias, tuple[i] );
+			}
+		}
+		return result;
+	}
+
+	public List transformList(List collection) {
+		return collection;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transform/DistinctRootEntityResultTransformer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transform/DistinctRootEntityResultTransformer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transform/DistinctRootEntityResultTransformer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+//$Id: DistinctRootEntityResultTransformer.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.transform;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Gavin King
+ */
+public class DistinctRootEntityResultTransformer implements ResultTransformer {
+
+	private static final Log log = LogFactory.getLog(DistinctRootEntityResultTransformer.class);
+
+	static final class Identity {
+		final Object entity;
+		Identity(Object entity) {
+			this.entity = entity;
+		}
+		public boolean equals(Object other) {
+			Identity that = (Identity) other;
+			return entity==that.entity;
+		}
+		public int hashCode() {
+			return System.identityHashCode(entity);
+		}
+	}
+
+	public Object transformTuple(Object[] tuple, String[] aliases) {
+		return tuple[ tuple.length-1 ];
+	}
+
+	public List transformList(List list) {
+		List result = new ArrayList( list.size() );
+		Set distinct = new HashSet();
+		for ( int i=0; i<list.size(); i++ ) {
+			Object entity = list.get(i);
+			if ( distinct.add( new Identity(entity) ) ) {
+				result.add(entity);
+			}
+		}
+		if ( log.isDebugEnabled() ) log.debug(
+			"transformed: " +
+			list.size() + " rows to: " +
+			result.size() + " distinct results"
+		);
+		return result;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transform/PassThroughResultTransformer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transform/PassThroughResultTransformer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transform/PassThroughResultTransformer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+//$Id: PassThroughResultTransformer.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.transform;
+
+import java.util.List;
+
+/**
+ * @author max
+ */
+public class PassThroughResultTransformer implements ResultTransformer {
+
+	public Object transformTuple(Object[] tuple, String[] aliases) {
+		return tuple.length==1 ? tuple[0] : tuple;
+	}
+
+	public List transformList(List collection) {
+		return collection;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transform/ResultTransformer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transform/ResultTransformer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transform/ResultTransformer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+//$Id: ResultTransformer.java 5685 2005-02-12 07:19:50Z steveebersole $
+package org.hibernate.transform;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Implementors define a strategy for transforming criteria query
+ * results into the actual application-visible query result list.
+ * @see org.hibernate.Criteria#setResultTransformer(ResultTransformer)
+ * @author Gavin King
+ */
+public interface ResultTransformer extends Serializable {
+	public Object transformTuple(Object[] tuple, String[] aliases);
+	public List transformList(List collection);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transform/RootEntityResultTransformer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transform/RootEntityResultTransformer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transform/RootEntityResultTransformer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+//$Id: RootEntityResultTransformer.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.transform;
+
+import java.util.List;
+
+/**
+ * @author Gavin King
+ */
+public class RootEntityResultTransformer implements ResultTransformer {
+
+	public Object transformTuple(Object[] tuple, String[] aliases) {
+		return tuple[ tuple.length-1 ];
+	}
+
+	public List transformList(List collection) {
+		return collection;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transform/ToListResultTransformer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transform/ToListResultTransformer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transform/ToListResultTransformer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+package org.hibernate.transform;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class ToListResultTransformer implements ResultTransformer {
+
+	public static final ResultTransformer INSTANCE = new ToListResultTransformer();
+
+	private ToListResultTransformer() {}
+	
+	public Object transformTuple(Object[] tuple, String[] aliases) {
+		return Arrays.asList(tuple);
+	}
+
+	public List transformList(List collection) {
+		return collection;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transform/Transformers.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transform/Transformers.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transform/Transformers.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+package org.hibernate.transform;
+
+final public class Transformers {
+
+	private Transformers() {}
+	
+	/**
+	 * Each row of results is a <tt>Map</tt> from alias to values/entities
+	 */
+	public static final ResultTransformer ALIAS_TO_ENTITY_MAP = new AliasToEntityMapResultTransformer();
+
+	/**
+	 * Each row of results is a <tt>List</tt> 
+	 */
+	public static final ResultTransformer TO_LIST = ToListResultTransformer.INSTANCE;
+	
+	/**
+	 * Creates a resulttransformer that will inject aliased values into 
+	 * instances of Class via property methods or fields.
+	 */
+	public static ResultTransformer aliasToBean(Class target) {
+		return new AliasToBeanResultTransformer(target);
+	}
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/transform/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/transform/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/transform/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	Defines strategies for post-processing criteria query
+	result sets into a form convenient to the application.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/transform/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Dom4jInstantiator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Dom4jInstantiator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Dom4jInstantiator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+//$Id: Dom4jInstantiator.java 7449 2005-07-11 17:31:50Z steveebersole $
+package org.hibernate.tuple;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.dom4j.Element;
+import org.hibernate.util.XMLHelper;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Component;
+
+/**
+ * Performs "instantiation" based on DOM4J elements.
+ */
+public class Dom4jInstantiator implements Instantiator {
+	private final String nodeName;
+	private final HashSet isInstanceNodeNames = new HashSet();
+
+	public Dom4jInstantiator(Component component) {
+		this.nodeName = component.getNodeName();
+		isInstanceNodeNames.add( nodeName );
+	}
+
+	public Dom4jInstantiator(PersistentClass mappingInfo) {
+		this.nodeName = mappingInfo.getNodeName();
+		isInstanceNodeNames.add( nodeName );
+
+		if ( mappingInfo.hasSubclasses() ) {
+			Iterator itr = mappingInfo.getSubclassClosureIterator();
+			while ( itr.hasNext() ) {
+				final PersistentClass subclassInfo = ( PersistentClass ) itr.next();
+				isInstanceNodeNames.add( subclassInfo.getNodeName() );
+			}
+		}
+	}
+	
+	public Object instantiate(Serializable id) {
+		return instantiate();
+	}
+	
+	public Object instantiate() {
+		return XMLHelper.generateDom4jElement( nodeName );
+	}
+
+	public boolean isInstance(Object object) {
+		if ( object instanceof Element ) {
+			return isInstanceNodeNames.contains( ( ( Element ) object ).getName() );
+		}
+		else {
+			return false;
+		}
+	}
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Dom4jInstantiator.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/DynamicMapInstantiator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/DynamicMapInstantiator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/DynamicMapInstantiator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+//$Id: DynamicMapInstantiator.java 7674 2005-07-29 06:14:16Z oneovthafew $
+package org.hibernate.tuple;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.mapping.PersistentClass;
+
+
+public class DynamicMapInstantiator implements Instantiator {
+	public static final String KEY = "$type$";
+
+	private String entityName;
+	private Set isInstanceEntityNames = new HashSet();
+
+	public DynamicMapInstantiator() {
+		this.entityName = null;
+	}
+
+	public DynamicMapInstantiator(PersistentClass mappingInfo) {
+		this.entityName = mappingInfo.getEntityName();
+		isInstanceEntityNames.add( entityName );
+		if ( mappingInfo.hasSubclasses() ) {
+			Iterator itr = mappingInfo.getSubclassClosureIterator();
+			while ( itr.hasNext() ) {
+				final PersistentClass subclassInfo = ( PersistentClass ) itr.next();
+				isInstanceEntityNames.add( subclassInfo.getEntityName() );
+			}
+		}
+	}
+
+	public final Object instantiate(Serializable id) {
+		return instantiate();
+	}
+
+	public final Object instantiate() {
+		Map map = generateMap();
+		if ( entityName!=null ) {
+			map.put( KEY, entityName );
+		}
+		return map;
+	}
+
+	public final boolean isInstance(Object object) {
+		if ( object instanceof Map ) {
+			if ( entityName == null ) {
+				return true;
+			}
+			String type = ( String ) ( ( Map ) object ).get( KEY );
+			return type == null || isInstanceEntityNames.contains( type );
+		}
+		else {
+			return false;
+		}
+	}
+
+	protected Map generateMap() {
+		return new HashMap();
+	}
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/DynamicMapInstantiator.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/ElementWrapper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/ElementWrapper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/ElementWrapper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,575 @@
+// $Id: ElementWrapper.java 6601 2005-04-29 03:06:37Z oneovthafew $
+package org.hibernate.tuple;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.Writer;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.dom4j.Attribute;
+import org.dom4j.Branch;
+import org.dom4j.CDATA;
+import org.dom4j.Comment;
+import org.dom4j.Document;
+import org.dom4j.Element;
+import org.dom4j.Entity;
+import org.dom4j.InvalidXPathException;
+import org.dom4j.Namespace;
+import org.dom4j.Node;
+import org.dom4j.ProcessingInstruction;
+import org.dom4j.QName;
+import org.dom4j.Text;
+import org.dom4j.Visitor;
+import org.dom4j.XPath;
+
+/**
+ * Wraps dom4j elements, allowing them to exist in a 
+ * non-hierarchical structure.
+ *
+ * @author Gavin King
+ */
+public class ElementWrapper implements Element, Serializable {
+
+	private Element element;
+	private Element parent;
+	
+	public Element getElement() {
+		return element;
+	}
+
+	public ElementWrapper(Element element) {
+		this.element = element;
+	}
+
+	public QName getQName() {
+		return element.getQName();
+	}
+
+	public QName getQName(String s) {
+		return element.getQName( s );
+	}
+
+	public void setQName(QName qName) {
+		element.setQName( qName );
+	}
+
+	public Namespace getNamespace() {
+		return element.getNamespace();
+	}
+
+	public Namespace getNamespaceForPrefix(String s) {
+		return element.getNamespaceForPrefix( s );
+	}
+
+	public Namespace getNamespaceForURI(String s) {
+		return element.getNamespaceForURI( s );
+	}
+
+	public List getNamespacesForURI(String s) {
+		return element.getNamespacesForURI( s );
+	}
+
+	public String getNamespacePrefix() {
+		return element.getNamespacePrefix();
+	}
+
+	public String getNamespaceURI() {
+		return element.getNamespaceURI();
+	}
+
+	public String getQualifiedName() {
+		return element.getQualifiedName();
+	}
+
+	public List additionalNamespaces() {
+		return element.additionalNamespaces();
+	}
+
+	public List declaredNamespaces() {
+		return element.declaredNamespaces();
+	}
+
+	public Element addAttribute(String attrName, String text) {
+		return element.addAttribute( attrName, text );
+	}
+
+	public Element addAttribute(QName attrName, String text) {
+		return element.addAttribute( attrName, text );
+	}
+
+	public Element addComment(String text) {
+		return element.addComment( text );
+	}
+
+	public Element addCDATA(String text) {
+		return element.addCDATA( text );
+	}
+
+	public Element addEntity(String name, String text) {
+		return element.addEntity( name, text );
+	}
+
+	public Element addNamespace(String prefix, String uri) {
+		return element.addNamespace( prefix, uri );
+	}
+
+	public Element addProcessingInstruction(String target, String text) {
+		return element.addProcessingInstruction( target, text );
+	}
+
+	public Element addProcessingInstruction(String target, Map data) {
+		return element.addProcessingInstruction( target, data );
+	}
+
+	public Element addText(String text) {
+		return element.addText( text );
+	}
+
+	public void add(Attribute attribute) {
+		element.add( attribute );
+	}
+
+	public void add(CDATA cdata) {
+		element.add( cdata );
+	}
+
+	public void add(Entity entity) {
+		element.add( entity );
+	}
+
+	public void add(Text text) {
+		element.add( text );
+	}
+
+	public void add(Namespace namespace) {
+		element.add( namespace );
+	}
+
+	public boolean remove(Attribute attribute) {
+		return element.remove( attribute );
+	}
+
+	public boolean remove(CDATA cdata) {
+		return element.remove( cdata );
+	}
+
+	public boolean remove(Entity entity) {
+		return element.remove( entity );
+	}
+
+	public boolean remove(Namespace namespace) {
+		return element.remove( namespace );
+	}
+
+	public boolean remove(Text text) {
+		return element.remove( text );
+	}
+
+	public boolean supportsParent() {
+		return element.supportsParent();
+	}
+
+	public Element getParent() {
+		return parent==null ? element.getParent() : parent;
+	}
+
+	public void setParent(Element parent) {
+		element.setParent( parent );
+		this.parent = parent;
+	}
+
+	public Document getDocument() {
+		return element.getDocument();
+	}
+
+	public void setDocument(Document document) {
+		element.setDocument( document );
+	}
+
+	public boolean isReadOnly() {
+		return element.isReadOnly();
+	}
+
+	public boolean hasContent() {
+		return element.hasContent();
+	}
+
+	public String getName() {
+		return element.getName();
+	}
+
+	public void setName(String name) {
+		element.setName( name );
+	}
+
+	public String getText() {
+		return element.getText();
+	}
+
+	public void setText(String text) {
+		element.setText( text );
+	}
+
+	public String getTextTrim() {
+		return element.getTextTrim();
+	}
+
+	public String getStringValue() {
+		return element.getStringValue();
+	}
+
+	public String getPath() {
+		return element.getPath();
+	}
+
+	public String getPath(Element element) {
+		return element.getPath( element );
+	}
+
+	public String getUniquePath() {
+		return element.getUniquePath();
+	}
+
+	public String getUniquePath(Element element) {
+		return element.getUniquePath( element );
+	}
+
+	public String asXML() {
+		return element.asXML();
+	}
+
+	public void write(Writer writer) throws IOException {
+		element.write( writer );
+	}
+
+	public short getNodeType() {
+		return element.getNodeType();
+	}
+
+	public String getNodeTypeName() {
+		return element.getNodeTypeName();
+	}
+
+	public Node detach() {
+		if (parent!=null) {
+			parent.remove(this);
+			parent = null;
+		}
+		return element.detach();
+	}
+
+	public List selectNodes(String xpath) {
+		return element.selectNodes( xpath );
+	}
+
+	public Object selectObject(String xpath) {
+		return element.selectObject( xpath );
+	}
+
+	public List selectNodes(String xpath, String comparison) {
+		return element.selectNodes( xpath, comparison );
+	}
+
+	public List selectNodes(String xpath, String comparison, boolean removeDups) {
+		return element.selectNodes( xpath, comparison, removeDups );
+	}
+
+	public Node selectSingleNode(String xpath) {
+        return element.selectSingleNode( xpath );
+	}
+
+	public String valueOf(String xpath) {
+		return element.valueOf( xpath );
+	}
+
+	public Number numberValueOf(String xpath) {
+		return element.numberValueOf( xpath );
+	}
+
+	public boolean matches(String xpath) {
+		return element.matches( xpath );
+	}
+
+	public XPath createXPath(String xpath) throws InvalidXPathException {
+		return element.createXPath( xpath );
+	}
+
+	public Node asXPathResult(Element element) {
+		return element.asXPathResult( element );
+	}
+
+	public void accept(Visitor visitor) {
+		element.accept( visitor );
+	}
+
+	public Object clone() {
+		return element.clone();
+	}
+
+	public Object getData() {
+		return element.getData();
+	}
+
+	public void setData(Object data) {
+		element.setData( data );
+	}
+
+	public List attributes() {
+		return element.attributes();
+	}
+
+	public void setAttributes(List list) {
+		element.setAttributes( list );
+	}
+
+	public int attributeCount() {
+		return element.attributeCount();
+	}
+
+	public Iterator attributeIterator() {
+		return element.attributeIterator();
+	}
+
+	public Attribute attribute(int i) {
+		return element.attribute( i );
+	}
+
+	public Attribute attribute(String name) {
+		return element.attribute( name );
+	}
+
+	public Attribute attribute(QName qName) {
+		return element.attribute( qName );
+	}
+
+	public String attributeValue(String name) {
+		return element.attributeValue( name );
+	}
+
+	public String attributeValue(String name, String defaultValue) {
+		return element.attributeValue( name, defaultValue );
+	}
+
+	public String attributeValue(QName qName) {
+		return element.attributeValue( qName );
+	}
+
+	public String attributeValue(QName qName, String defaultValue) {
+		return element.attributeValue( qName, defaultValue );
+	}
+
+	/**
+	 * @deprecated
+	 */
+	public void setAttributeValue(String name, String value) {
+		element.setAttributeValue( name, value );
+	}
+
+	/**
+	 * @deprecated
+	 */
+	public void setAttributeValue(QName qName, String value) {
+		element.setAttributeValue( qName, value );
+	}
+
+	public Element element(String name) {
+		return element.element( name );
+	}
+
+	public Element element(QName qName) {
+		return element.element( qName );
+	}
+
+	public List elements() {
+		return element.elements();
+	}
+
+	public List elements(String name) {
+		return element.elements( name );
+	}
+
+	public List elements(QName qName) {
+		return element.elements( qName );
+	}
+
+	public Iterator elementIterator() {
+		return element.elementIterator();
+	}
+
+	public Iterator elementIterator(String name) {
+		return element.elementIterator( name );
+
+	}
+
+	public Iterator elementIterator(QName qName) {
+		return element.elementIterator( qName );
+	}
+
+	public boolean isRootElement() {
+		return element.isRootElement();
+	}
+
+	public boolean hasMixedContent() {
+		return element.hasMixedContent();
+	}
+
+	public boolean isTextOnly() {
+		return element.isTextOnly();
+	}
+
+	public void appendAttributes(Element element) {
+		element.appendAttributes( element );
+	}
+
+	public Element createCopy() {
+		return element.createCopy();
+	}
+
+	public Element createCopy(String name) {
+		return element.createCopy( name );
+	}
+
+	public Element createCopy(QName qName) {
+		return element.createCopy( qName );
+	}
+
+	public String elementText(String name) {
+		return element.elementText( name );
+	}
+
+	public String elementText(QName qName) {
+		return element.elementText( qName );
+	}
+
+	public String elementTextTrim(String name) {
+		return element.elementTextTrim( name );
+	}
+
+	public String elementTextTrim(QName qName) {
+		return element.elementTextTrim( qName );
+	}
+
+	public Node getXPathResult(int i) {
+		return element.getXPathResult( i );
+	}
+
+	public Node node(int i) {
+		return element.node( i );
+	}
+
+	public int indexOf(Node node) {
+		return element.indexOf( node );
+	}
+
+	public int nodeCount() {
+		return element.nodeCount();
+	}
+
+	public Element elementByID(String id) {
+		return element.elementByID( id );
+	}
+
+	public List content() {
+		return element.content();
+	}
+
+	public Iterator nodeIterator() {
+		return element.nodeIterator();
+	}
+
+	public void setContent(List list) {
+		element.setContent( list );
+	}
+
+	public void appendContent(Branch branch) {
+		element.appendContent( branch );
+	}
+
+	public void clearContent() {
+		element.clearContent();
+	}
+
+	public List processingInstructions() {
+		return element.processingInstructions();
+	}
+
+	public List processingInstructions(String name) {
+		return element.processingInstructions( name );
+	}
+
+	public ProcessingInstruction processingInstruction(String name) {
+		return element.processingInstruction( name );
+	}
+
+	public void setProcessingInstructions(List list) {
+		element.setProcessingInstructions( list );
+	}
+
+	public Element addElement(String name) {
+		return element.addElement( name );
+	}
+
+	public Element addElement(QName qName) {
+		return element.addElement( qName );
+	}
+
+	public Element addElement(String name, String text) {
+		return element.addElement( name, text );
+
+	}
+
+	public boolean removeProcessingInstruction(String name) {
+		return element.removeProcessingInstruction( name );
+	}
+
+	public void add(Node node) {
+		element.add( node );
+	}
+
+	public void add(Comment comment) {
+		element.add( comment );
+	}
+
+	public void add(Element element) {
+		element.add( element );
+	}
+
+	public void add(ProcessingInstruction processingInstruction) {
+		element.add( processingInstruction );
+	}
+
+	public boolean remove(Node node) {
+		return element.remove( node );
+	}
+
+	public boolean remove(Comment comment) {
+		return element.remove( comment );
+	}
+
+	public boolean remove(Element element) {
+		return element.remove( element );
+	}
+
+	public boolean remove(ProcessingInstruction processingInstruction) {
+		return element.remove( processingInstruction );
+	}
+
+	public void normalize() {
+		element.normalize();
+	}
+	
+	public boolean equals(Object other) {
+		return element.equals(other);
+	}
+	
+	public int hashCode() {
+		return element.hashCode();
+	}
+	
+	public String toString() {
+		return element.toString();
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/ElementWrapper.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/EntityModeToTuplizerMapping.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/EntityModeToTuplizerMapping.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/EntityModeToTuplizerMapping.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,72 @@
+package org.hibernate.tuple;
+
+import org.apache.commons.collections.SequencedHashMap;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+
+import java.util.Map;
+import java.util.Collections;
+import java.util.Iterator;
+import java.io.Serializable;
+
+/**
+ * Centralizes handling of {@link EntityMode} to {@link Tuplizer} mappings.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class EntityModeToTuplizerMapping implements Serializable {
+
+	// map of EntityMode -> Tuplizer
+	private final Map tuplizers = Collections.synchronizedMap( new SequencedHashMap() );
+
+	protected void addTuplizer(EntityMode entityMode, Tuplizer tuplizer) {
+		tuplizers.put( entityMode, tuplizer );
+	}
+
+	/**
+	 * Given a supposed instance of an entity/component, guess its entity mode.
+	 *
+	 * @param object The supposed instance of the entity/component.
+	 * @return The guessed entity mode.
+	 */
+	public EntityMode guessEntityMode(Object object) {
+		Iterator itr = tuplizers.entrySet().iterator();
+		while( itr.hasNext() ) {
+			Map.Entry entry = ( Map.Entry ) itr.next();
+			Tuplizer tuplizer = ( Tuplizer ) entry.getValue();
+			if ( tuplizer.isInstance( object ) ) {
+				return ( EntityMode ) entry.getKey();
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Locate the contained tuplizer responsible for the given entity-mode.  If
+	 * no such tuplizer is defined on this mapping, then return null.
+	 *
+	 * @param entityMode The entity-mode for which the caller wants a tuplizer.
+	 * @return The tuplizer, or null if not found.
+	 */
+	public Tuplizer getTuplizerOrNull(EntityMode entityMode) {
+		return ( Tuplizer ) tuplizers.get( entityMode );
+	}
+
+	/**
+	 * Locate the tuplizer contained within this mapping which is responsible
+	 * for the given entity-mode.  If no such tuplizer is defined on this
+	 * mapping, then an exception is thrown.
+	 *
+	 * @param entityMode The entity-mode for which the caller wants a tuplizer.
+	 * @return The tuplizer.
+	 * @throws HibernateException Unable to locate the requested tuplizer.
+	 */
+	public Tuplizer getTuplizer(EntityMode entityMode) {
+		Tuplizer tuplizer = getTuplizerOrNull( entityMode );
+		if ( tuplizer == null ) {
+			throw new HibernateException( "No tuplizer found for entity-mode [" + entityMode + "]");
+		}
+		return tuplizer;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/IdentifierProperty.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/IdentifierProperty.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/IdentifierProperty.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,100 @@
+// $Id: IdentifierProperty.java 9295 2006-02-15 22:28:15Z epbernard $
+package org.hibernate.tuple;
+
+import org.hibernate.engine.IdentifierValue;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.id.PostInsertIdentifierGenerator;
+import org.hibernate.type.Type;
+
+/**
+ * Represents a defined entity identifier property within the Hibernate
+ * runtime-metamodel.
+ *
+ * @author Steve Ebersole
+ */
+public class IdentifierProperty extends Property {
+
+	private boolean virtual;
+	private boolean embedded;
+	private IdentifierValue unsavedValue;
+	private IdentifierGenerator identifierGenerator;
+	private boolean identifierAssignedByInsert;
+	private boolean hasIdentifierMapper;
+
+	/**
+	 * Construct a non-virtual identifier property.
+	 *
+	 * @param name The name of the property representing the identifier within
+	 * its owning entity.
+	 * @param node The node name to use for XML-based representation of this
+	 * property.
+	 * @param type The Hibernate Type for the identifier property.
+	 * @param embedded Is this an embedded identifier.
+	 * @param unsavedValue The value which, if found as the value on the identifier
+	 * property, represents new (i.e., un-saved) instances of the owning entity.
+	 * @param identifierGenerator The generator to use for id value generation.
+	 */
+	public IdentifierProperty(
+			String name,
+			String node,
+			Type type,
+			boolean embedded,
+			IdentifierValue unsavedValue,
+			IdentifierGenerator identifierGenerator) {
+		super(name, node, type);
+		this.virtual = false;
+		this.embedded = embedded;
+		this.hasIdentifierMapper = false;
+		this.unsavedValue = unsavedValue;
+		this.identifierGenerator = identifierGenerator;
+		this.identifierAssignedByInsert = identifierGenerator instanceof PostInsertIdentifierGenerator;
+	}
+
+	/**
+	 * Construct a virtual IdentifierProperty.
+	 *
+	 * @param type The Hibernate Type for the identifier property.
+	 * @param embedded Is this an embedded identifier.
+	 * @param unsavedValue The value which, if found as the value on the identifier
+	 * property, represents new (i.e., un-saved) instances of the owning entity.
+	 * @param identifierGenerator The generator to use for id value generation.
+	 */
+	public IdentifierProperty(
+	        Type type,
+	        boolean embedded,
+			boolean hasIdentifierMapper,
+			IdentifierValue unsavedValue,
+	        IdentifierGenerator identifierGenerator) {
+		super(null, null, type);
+		this.virtual = true;
+		this.embedded = embedded;
+		this.hasIdentifierMapper = hasIdentifierMapper;
+		this.unsavedValue = unsavedValue;
+		this.identifierGenerator = identifierGenerator;
+		this.identifierAssignedByInsert = identifierGenerator instanceof PostInsertIdentifierGenerator;
+	}
+
+	public boolean isVirtual() {
+		return virtual;
+	}
+
+	public boolean isEmbedded() {
+		return embedded;
+	}
+
+	public IdentifierValue getUnsavedValue() {
+		return unsavedValue;
+	}
+
+	public IdentifierGenerator getIdentifierGenerator() {
+		return identifierGenerator;
+	}
+
+	public boolean isIdentifierAssignedByInsert() {
+		return identifierAssignedByInsert;
+	}
+
+	public boolean hasIdentifierMapper() {
+		return hasIdentifierMapper;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Instantiator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Instantiator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Instantiator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+// $Id: Instantiator.java 7449 2005-07-11 17:31:50Z steveebersole $
+package org.hibernate.tuple;
+
+
+import java.io.Serializable;
+
+/**
+ * Contract for implementors responsible for instantiating entity/component instances.
+ *
+ * @author Steve Ebersole
+ */
+public interface Instantiator extends Serializable {
+
+	/**
+	 * Perform the requested entity instantiation.
+	 * <p/>
+	 * This form is never called for component instantiation, only entity instantiation.
+	 *
+	 * @param id The id of the entity to be instantiated.
+	 * @return An appropriately instantiated entity.
+	 */
+	public Object instantiate(Serializable id);
+
+	/**
+	 * Perform the requested instantiation.
+	 *
+	 * @return The instantiated data structure. 
+	 */
+	public Object instantiate();
+
+	/**
+	 * Performs check to see if the given object is an instance of the entity
+	 * or component which this Instantiator instantiates.
+	 *
+	 * @param object The object to be checked.
+	 * @return True is the object does respresent an instance of the underlying
+	 * entity/component.
+	 */
+	public boolean isInstance(Object object);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/PojoInstantiator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/PojoInstantiator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/PojoInstantiator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,107 @@
+//$Id: PojoInstantiator.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.tuple;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.InstantiationException;
+import org.hibernate.PropertyNotFoundException;
+import org.hibernate.bytecode.ReflectionOptimizer;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Component;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * Defines a POJO-based instantiator for use from the tuplizers.
+ */
+public class PojoInstantiator implements Instantiator, Serializable {
+
+	private static final Log log = LogFactory.getLog(PojoInstantiator.class);
+
+	private transient Constructor constructor;
+
+	private final Class mappedClass;
+	private final transient ReflectionOptimizer.InstantiationOptimizer optimizer;
+	private final boolean embeddedIdentifier;
+	private final Class proxyInterface;
+
+	public PojoInstantiator(Component component, ReflectionOptimizer.InstantiationOptimizer optimizer) {
+		this.mappedClass = component.getComponentClass();
+		this.optimizer = optimizer;
+
+		this.proxyInterface = null;
+		this.embeddedIdentifier = false;
+
+		try {
+			constructor = ReflectHelper.getDefaultConstructor(mappedClass);
+		}
+		catch ( PropertyNotFoundException pnfe ) {
+			log.info(
+			        "no default (no-argument) constructor for class: " +
+					mappedClass.getName() +
+					" (class must be instantiated by Interceptor)"
+			);
+			constructor = null;
+		}
+	}
+
+	public PojoInstantiator(PersistentClass persistentClass, ReflectionOptimizer.InstantiationOptimizer optimizer) {
+		this.mappedClass = persistentClass.getMappedClass();
+		this.proxyInterface = persistentClass.getProxyInterface();
+		this.embeddedIdentifier = persistentClass.hasEmbeddedIdentifier();
+		this.optimizer = optimizer;
+
+		try {
+			constructor = ReflectHelper.getDefaultConstructor( mappedClass );
+		}
+		catch ( PropertyNotFoundException pnfe ) {
+			log.info(
+			        "no default (no-argument) constructor for class: " +
+					mappedClass.getName() +
+					" (class must be instantiated by Interceptor)"
+			);
+			constructor = null;
+		}
+	}
+
+	private void readObject(java.io.ObjectInputStream stream)
+	throws ClassNotFoundException, IOException {
+		stream.defaultReadObject();
+		constructor = ReflectHelper.getDefaultConstructor(mappedClass);
+	}
+
+	public Object instantiate() {
+		if ( ReflectHelper.isAbstractClass(mappedClass) ) {
+			throw new InstantiationException( "Cannot instantiate abstract class or interface: ", mappedClass );
+		}
+		else if ( optimizer != null ) {
+			return optimizer.newInstance();
+		}
+		else if ( constructor == null ) {
+			throw new InstantiationException( "No default constructor for entity: ", mappedClass );
+		}
+		else {
+			try {
+				return constructor.newInstance( null );
+			}
+			catch ( Exception e ) {
+				throw new InstantiationException( "Could not instantiate entity: ", mappedClass, e );
+			}
+		}
+	}
+	
+	public Object instantiate(Serializable id) {
+		final boolean useEmbeddedIdentifierInstanceAsEntity = embeddedIdentifier && 
+				id != null && 
+				id.getClass().equals(mappedClass);
+		return useEmbeddedIdentifierInstanceAsEntity ? id : instantiate();
+	}
+
+	public boolean isInstance(Object object) {
+		return mappedClass.isInstance(object) || 
+				( proxyInterface!=null && proxyInterface.isInstance(object) ); //this one needed only for guessEntityMode()
+	}
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/PojoInstantiator.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Property.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Property.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Property.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+// $Id: Property.java 5814 2005-02-21 02:08:46Z oneovthafew $
+package org.hibernate.tuple;
+
+import org.hibernate.type.Type;
+
+import java.io.Serializable;
+
+/**
+ * Defines the basic contract of a Property within the runtime metamodel.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class Property implements Serializable {
+	private String name;
+	private String node;
+	private Type type;
+
+	/**
+	 * Constructor for Property instances.
+	 *
+	 * @param name The name by which the property can be referenced within
+	 * its owner.
+	 * @param node The node name to use for XML-based representation of this
+	 * property.
+	 * @param type The Hibernate Type of this property.
+	 */
+	protected Property(String name, String node, Type type) {
+		this.name = name;
+		this.node = node;
+		this.type = type;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public String getNode() {
+		return node;
+	}
+
+	public Type getType() {
+		return type;
+	}
+	
+	public String toString() {
+		return "Property(" + name + ':' + type.getName() + ')';
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/PropertyFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/PropertyFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/PropertyFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,171 @@
+// $Id: PropertyFactory.java 10119 2006-07-14 00:09:19Z steve.ebersole at jboss.com $
+package org.hibernate.tuple;
+
+import java.lang.reflect.Constructor;
+
+import org.hibernate.EntityMode;
+import org.hibernate.mapping.PropertyGeneration;
+import org.hibernate.engine.IdentifierValue;
+import org.hibernate.engine.UnsavedValueFactory;
+import org.hibernate.engine.VersionValue;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.mapping.KeyValue;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.property.Getter;
+import org.hibernate.property.PropertyAccessor;
+import org.hibernate.property.PropertyAccessorFactory;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.Type;
+import org.hibernate.type.VersionType;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * Responsible for generation of runtime metamodel {@link Property} representations.
+ * Makes distinction between identifier, version, and other (standard) properties.
+ *
+ * @author Steve Ebersole
+ */
+public class PropertyFactory {
+
+	/**
+	 * Generates an IdentifierProperty representation of the for a given entity mapping.
+	 *
+	 * @param mappedEntity The mapping definition of the entity.
+	 * @param generator The identifier value generator to use for this identifier.
+	 * @return The appropriate IdentifierProperty definition.
+	 */
+	public static IdentifierProperty buildIdentifierProperty(PersistentClass mappedEntity, IdentifierGenerator generator) {
+
+		String mappedUnsavedValue = mappedEntity.getIdentifier().getNullValue();
+		Type type = mappedEntity.getIdentifier().getType();
+		Property property = mappedEntity.getIdentifierProperty();
+		
+		IdentifierValue unsavedValue = UnsavedValueFactory.getUnsavedIdentifierValue(
+				mappedUnsavedValue,
+				getGetter( property ),
+				type,
+				getConstructor(mappedEntity)
+			);
+
+		if ( property == null ) {
+			// this is a virtual id property...
+			return new IdentifierProperty(
+			        type,
+					mappedEntity.hasEmbeddedIdentifier(),
+					mappedEntity.hasIdentifierMapper(),
+					unsavedValue,
+					generator
+				);
+		}
+		else {
+			return new IdentifierProperty(
+					property.getName(),
+					property.getNodeName(),
+					type,
+					mappedEntity.hasEmbeddedIdentifier(),
+					unsavedValue,
+					generator
+				);
+		}
+	}
+
+	/**
+	 * Generates a VersionProperty representation for an entity mapping given its
+	 * version mapping Property.
+	 *
+	 * @param property The version mapping Property.
+	 * @param lazyAvailable Is property lazy loading currently available.
+	 * @return The appropriate VersionProperty definition.
+	 */
+	public static VersionProperty buildVersionProperty(Property property, boolean lazyAvailable) {
+		String mappedUnsavedValue = ( (KeyValue) property.getValue() ).getNullValue();
+		
+		VersionValue unsavedValue = UnsavedValueFactory.getUnsavedVersionValue(
+				mappedUnsavedValue, 
+				getGetter( property ),
+				(VersionType) property.getType(),
+				getConstructor( property.getPersistentClass() )
+			);
+
+		boolean lazy = lazyAvailable && property.isLazy();
+
+		return new VersionProperty(
+		        property.getName(),
+		        property.getNodeName(),
+		        property.getValue().getType(),
+		        lazy,
+				property.isInsertable(),
+				property.isUpdateable(),
+		        property.getGeneration() == PropertyGeneration.INSERT || property.getGeneration() == PropertyGeneration.ALWAYS,
+				property.getGeneration() == PropertyGeneration.ALWAYS,
+				property.isOptional(),
+				property.isUpdateable() && !lazy,
+				property.isOptimisticLocked(),
+		        property.getCascadeStyle(),
+		        unsavedValue
+			);
+	}
+
+	/**
+	 * Generate a "standard" (i.e., non-identifier and non-version) based on the given
+	 * mapped property.
+	 *
+	 * @param property The mapped property.
+	 * @param lazyAvailable Is property lazy loading currently available.
+	 * @return The appropriate StandardProperty definition.
+	 */
+	public static StandardProperty buildStandardProperty(Property property, boolean lazyAvailable) {
+		
+		final Type type = property.getValue().getType();
+		
+		// we need to dirty check collections, since they can cause an owner
+		// version number increment
+		
+		// we need to dirty check many-to-ones with not-found="ignore" in order 
+		// to update the cache (not the database), since in this case a null
+		// entity reference can lose information
+		
+		boolean alwaysDirtyCheck = type.isAssociationType() && 
+				( (AssociationType) type ).isAlwaysDirtyChecked(); 
+
+		return new StandardProperty(
+				property.getName(),
+				property.getNodeName(),
+				type,
+				lazyAvailable && property.isLazy(),
+				property.isInsertable(),
+				property.isUpdateable(),
+		        property.getGeneration() == PropertyGeneration.INSERT || property.getGeneration() == PropertyGeneration.ALWAYS,
+				property.getGeneration() == PropertyGeneration.ALWAYS,
+				property.isOptional(),
+				alwaysDirtyCheck || property.isUpdateable(),
+				property.isOptimisticLocked(),
+				property.getCascadeStyle(),
+		        property.getValue().getFetchMode()
+			);
+	}
+
+	private static Constructor getConstructor(PersistentClass persistentClass) {
+		if ( persistentClass == null || !persistentClass.hasPojoRepresentation() ) {
+			return null;
+		}
+
+		try {
+			return ReflectHelper.getDefaultConstructor( persistentClass.getMappedClass() );
+		}
+		catch( Throwable t ) {
+			return null;
+		}
+	}
+
+	private static Getter getGetter(Property mappingProperty) {
+		if ( mappingProperty == null || !mappingProperty.getPersistentClass().hasPojoRepresentation() ) {
+			return null;
+		}
+
+		PropertyAccessor pa = PropertyAccessorFactory.getPropertyAccessor( mappingProperty, EntityMode.POJO );
+		return pa.getGetter( mappingProperty.getPersistentClass().getMappedClass(), mappingProperty.getName() );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/StandardProperty.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/StandardProperty.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/StandardProperty.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,115 @@
+// $Id: StandardProperty.java 10119 2006-07-14 00:09:19Z steve.ebersole at jboss.com $
+package org.hibernate.tuple;
+
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.type.Type;
+import org.hibernate.FetchMode;
+
+/**
+ * Represents a basic property within the Hibernate runtime-metamodel.
+ *
+ * @author Steve Ebersole
+ */
+public class StandardProperty extends Property {
+
+    private final boolean lazy;
+    private final boolean insertable;
+    private final boolean updateable;
+	private final boolean insertGenerated;
+	private final boolean updateGenerated;
+    private final boolean nullable;
+    private final boolean dirtyCheckable;
+    private final boolean versionable;
+    private final CascadeStyle cascadeStyle;
+	private final FetchMode fetchMode;
+
+    /**
+     * Constructs StandardProperty instances.
+     *
+     * @param name The name by which the property can be referenced within
+     * its owner.
+     * @param node The node name to use for XML-based representation of this
+     * property.
+     * @param type The Hibernate Type of this property.
+     * @param lazy Should this property be handled lazily?
+     * @param insertable Is this property an insertable value?
+     * @param updateable Is this property an updateable value?
+     * @param insertGenerated Is this property generated in the database on insert?
+     * @param updateGenerated Is this property generated in the database on update?
+     * @param nullable Is this property a nullable value?
+     * @param checkable Is this property a checkable value?
+     * @param versionable Is this property a versionable value?
+     * @param cascadeStyle The cascade style for this property's value.
+     * @param fetchMode Any fetch mode defined for this property
+     */
+    public StandardProperty(
+            String name,
+            String node,
+            Type type,
+            boolean lazy,
+            boolean insertable,
+            boolean updateable,
+            boolean insertGenerated,
+            boolean updateGenerated,
+            boolean nullable,
+            boolean checkable,
+            boolean versionable,
+            CascadeStyle cascadeStyle,
+            FetchMode fetchMode) {
+        super(name, node, type);
+        this.lazy = lazy;
+        this.insertable = insertable;
+        this.updateable = updateable;
+        this.insertGenerated = insertGenerated;
+	    this.updateGenerated = updateGenerated;
+        this.nullable = nullable;
+        this.dirtyCheckable = checkable;
+        this.versionable = versionable;
+        this.cascadeStyle = cascadeStyle;
+	    this.fetchMode = fetchMode;
+    }
+
+    public boolean isLazy() {
+        return lazy;
+    }
+
+    public boolean isInsertable() {
+        return insertable;
+    }
+
+    public boolean isUpdateable() {
+        return updateable;
+    }
+
+	public boolean isInsertGenerated() {
+		return insertGenerated;
+	}
+
+	public boolean isUpdateGenerated() {
+		return updateGenerated;
+	}
+
+    public boolean isNullable() {
+        return nullable;
+    }
+
+    public boolean isDirtyCheckable(boolean hasUninitializedProperties) {
+        return isDirtyCheckable() && ( !hasUninitializedProperties || !isLazy() );
+    }
+
+    public boolean isDirtyCheckable() {
+        return dirtyCheckable;
+    }
+
+    public boolean isVersionable() {
+        return versionable;
+    }
+
+    public CascadeStyle getCascadeStyle() {
+        return cascadeStyle;
+    }
+
+	public FetchMode getFetchMode() {
+		return fetchMode;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Tuplizer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Tuplizer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/Tuplizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,95 @@
+// $Id: Tuplizer.java 10119 2006-07-14 00:09:19Z steve.ebersole at jboss.com $
+package org.hibernate.tuple;
+
+import org.hibernate.HibernateException;
+
+/**
+ * A tuplizer defines the contract for things which know how to manage
+ * a particular representation of a piece of data, given that
+ * representation's {@link org.hibernate.EntityMode} (the entity-mode
+ * essentially defining which representation).
+ * </p>
+ * If that given piece of data is thought of as a data structure, then a tuplizer
+ * is the thing which knows how to<ul>
+ * <li>create such a data structure appropriately
+ * <li>extract values from and inject values into such a data structure
+ * </ul>
+ * </p>
+ * For example, a given piece of data might be represented as a POJO class.
+ * Here, it's representation and entity-mode is POJO.  Well a tuplizer for POJO
+ * entity-modes would know how to<ul>
+ * <li>create the data structure by calling the POJO's constructor
+ * <li>extract and inject values through getters/setter, or by direct field access, etc
+ * </ul>
+ * </p>
+ * That same piece of data might also be represented as a DOM structure, using
+ * the tuplizer associated with the DOM4J entity-mode, which would generate instances
+ * of {@link org.dom4j.Element} as the data structure and know how to access the
+ * values as either nested {@link org.dom4j.Element}s or as {@link org.dom4j.Attribute}s.
+ *
+ * @see org.hibernate.tuple.entity.EntityTuplizer
+ * @see org.hibernate.tuple.component.ComponentTuplizer
+ *
+ * @author Steve Ebersole
+ */
+public interface Tuplizer {
+
+	/**
+	 * Extract the current values contained on the given entity.
+	 *
+	 * @param entity The entity from which to extract values.
+	 * @return The current property values.
+	 * @throws HibernateException
+	 */
+	public Object[] getPropertyValues(Object entity) throws HibernateException;
+
+	/**
+	 * Inject the given values into the given entity.
+	 *
+	 * @param entity The entity.
+	 * @param values The values to be injected.
+	 * @throws HibernateException
+	 */
+	public void setPropertyValues(Object entity, Object[] values) throws HibernateException;
+
+	/**
+	 * Extract the value of a particular property from the given entity.
+	 *
+	 * @param entity The entity from which to extract the property value.
+	 * @param i The index of the property for which to extract the value.
+	 * @return The current value of the given property on the given entity.
+	 * @throws HibernateException
+	 */
+	public Object getPropertyValue(Object entity, int i) throws HibernateException;
+
+	/**
+	 * Generate a new, empty entity.
+	 *
+	 * @return The new, empty entity instance.
+	 * @throws HibernateException
+	 */
+	public Object instantiate() throws HibernateException;
+	
+	/**
+	 * Is the given object considered an instance of the the entity (acconting
+	 * for entity-mode) managed by this tuplizer.
+	 *
+	 * @param object The object to be checked.
+	 * @return True if the object is considered as an instance of this entity
+	 *      within the given mode.
+	 */
+	public boolean isInstance(Object object);
+
+	/**
+	 * Return the pojo class managed by this tuplizer.
+	 * </p>
+	 * Need to determine how to best handle this for the Tuplizers for EntityModes
+	 * other than POJO.
+	 * </p>
+	 * todo : be really nice to not have this here since it is essentially pojo specific...
+	 *
+	 * @return The persistent class.
+	 */
+	public Class getMappedClass();
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/VersionProperty.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/VersionProperty.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/VersionProperty.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,59 @@
+// $Id: VersionProperty.java 10119 2006-07-14 00:09:19Z steve.ebersole at jboss.com $
+package org.hibernate.tuple;
+
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.VersionValue;
+import org.hibernate.type.Type;
+
+/**
+ * Represents a version property within the Hibernate runtime-metamodel.
+ *
+ * @author Steve Ebersole
+ */
+public class VersionProperty extends StandardProperty {
+
+    private final VersionValue unsavedValue;
+
+    /**
+     * Constructs VersionProperty instances.
+     *
+     * @param name The name by which the property can be referenced within
+     * its owner.
+     * @param node The node name to use for XML-based representation of this
+     * property.
+     * @param type The Hibernate Type of this property.
+     * @param lazy Should this property be handled lazily?
+     * @param insertable Is this property an insertable value?
+     * @param updateable Is this property an updateable value?
+     * @param insertGenerated Is this property generated in the database on insert?
+     * @param updateGenerated Is this property generated in the database on update?
+     * @param nullable Is this property a nullable value?
+     * @param checkable Is this property a checkable value?
+     * @param versionable Is this property a versionable value?
+     * @param cascadeStyle The cascade style for this property's value.
+     * @param unsavedValue The value which, if found as the value of
+     * this (i.e., the version) property, represents new (i.e., un-saved)
+     * instances of the owning entity.
+     */
+    public VersionProperty(
+            String name,
+            String node,
+            Type type,
+            boolean lazy,
+            boolean insertable,
+            boolean updateable,
+            boolean insertGenerated,
+            boolean updateGenerated,
+            boolean nullable,
+            boolean checkable,
+            boolean versionable,
+            CascadeStyle cascadeStyle,
+            VersionValue unsavedValue) {
+        super( name, node, type, lazy, insertable, updateable, insertGenerated, updateGenerated, nullable, checkable, versionable, cascadeStyle, null );
+        this.unsavedValue = unsavedValue;
+    }
+
+    public VersionValue getUnsavedValue() {
+        return unsavedValue;
+    }
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/AbstractComponentTuplizer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/AbstractComponentTuplizer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/AbstractComponentTuplizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,108 @@
+//$Id: AbstractComponentTuplizer.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.tuple.component;
+
+import java.lang.reflect.Method;
+import java.util.Iterator;
+
+import org.hibernate.HibernateException;
+import org.hibernate.tuple.Instantiator;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.Property;
+import org.hibernate.property.Getter;
+import org.hibernate.property.Setter;
+
+/**
+ * Support for tuplizers relating to components.
+ *
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public abstract class AbstractComponentTuplizer implements ComponentTuplizer {
+
+	protected final Getter[] getters;
+	protected final Setter[] setters;
+	protected final int propertySpan;
+	protected final Instantiator instantiator;
+	protected final boolean hasCustomAccessors;
+
+	protected abstract Instantiator buildInstantiator(Component component);
+	protected abstract Getter buildGetter(Component component, Property prop);
+	protected abstract Setter buildSetter(Component component, Property prop);
+
+	protected AbstractComponentTuplizer(Component component) {
+		propertySpan = component.getPropertySpan();
+		getters = new Getter[propertySpan];
+		setters = new Setter[propertySpan];
+
+		Iterator iter = component.getPropertyIterator();
+		boolean foundCustomAccessor=false;
+		int i = 0;
+		while ( iter.hasNext() ) {
+			Property prop = ( Property ) iter.next();
+			getters[i] = buildGetter( component, prop );
+			setters[i] = buildSetter( component, prop );
+			if ( !prop.isBasicPropertyAccessor() ) {
+				foundCustomAccessor = true;
+			}
+			i++;
+		}
+		hasCustomAccessors = foundCustomAccessor;
+
+		String[] getterNames = new String[propertySpan];
+		String[] setterNames = new String[propertySpan];
+		Class[] propTypes = new Class[propertySpan];
+		for ( int j = 0; j < propertySpan; j++ ) {
+			getterNames[j] = getters[j].getMethodName();
+			setterNames[j] = setters[j].getMethodName();
+			propTypes[j] = getters[j].getReturnType();
+		}
+		instantiator = buildInstantiator( component );
+	}
+
+	public Object getPropertyValue(Object component, int i) throws HibernateException {
+		return getters[i].get( component );
+	}
+
+	public Object[] getPropertyValues(Object component) throws HibernateException {
+		Object[] values = new Object[propertySpan];
+		for ( int i = 0; i < propertySpan; i++ ) {
+			values[i] = getPropertyValue( component, i );
+		}
+		return values;
+	}
+
+	public boolean isInstance(Object object) {
+		return instantiator.isInstance(object);
+	}
+
+	public void setPropertyValues(Object component, Object[] values) throws HibernateException {
+		for ( int i = 0; i < propertySpan; i++ ) {
+			setters[i].set( component, values[i], null );
+		}
+	}
+
+	/**
+	* This method does not populate the component parent
+	*/
+	public Object instantiate() throws HibernateException {
+		return instantiator.instantiate();
+	}
+
+	public Object getParent(Object component) {
+		return null;
+	}
+
+	public boolean hasParentProperty() {
+		return false;
+	}
+
+	public boolean isMethodOf(Method method) {
+		return false;
+	}
+
+	public void setParent(Object component, Object parent, SessionFactoryImplementor factory) {
+		throw new UnsupportedOperationException();
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/ComponentEntityModeToTuplizerMapping.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/ComponentEntityModeToTuplizerMapping.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/ComponentEntityModeToTuplizerMapping.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,109 @@
+package org.hibernate.tuple.component;
+
+import org.hibernate.tuple.EntityModeToTuplizerMapping;
+import org.hibernate.tuple.Tuplizer;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.util.ReflectHelper;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.io.Serializable;
+
+/**
+ * Handles mapping {@link EntityMode}s to {@link ComponentTuplizer}s.
+ * <p/>
+ * Most of the handling is really in the super class; here we just create
+ * the tuplizers and add them to the superclass
+ *
+ * @author Steve Ebersole
+ */
+class ComponentEntityModeToTuplizerMapping extends EntityModeToTuplizerMapping implements Serializable {
+
+	private static final Class[] COMPONENT_TUP_CTOR_SIG = new Class[] { Component.class };
+
+	public ComponentEntityModeToTuplizerMapping(Component component) {
+		PersistentClass owner = component.getOwner();
+
+		// create our own copy of the user-supplied tuplizer impl map
+		Map userSuppliedTuplizerImpls = new HashMap();
+		if ( component.getTuplizerMap() != null ) {
+			userSuppliedTuplizerImpls.putAll( component.getTuplizerMap() );
+		}
+
+		// Build the dynamic-map tuplizer...
+		Tuplizer dynamicMapTuplizer = null;
+		String tuplizerImpl = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.MAP );
+		if ( tuplizerImpl == null ) {
+			dynamicMapTuplizer = new DynamicMapComponentTuplizer( component );
+		}
+		else {
+			dynamicMapTuplizer = buildComponentTuplizer( tuplizerImpl, component );
+		}
+
+		// then the pojo tuplizer, using the dynamic-map tuplizer if no pojo representation is available
+		tuplizerImpl = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.POJO );
+		Tuplizer pojoTuplizer = null;
+		if ( owner.hasPojoRepresentation() && component.hasPojoRepresentation() ) {
+			if ( tuplizerImpl == null ) {
+				pojoTuplizer = new PojoComponentTuplizer( component );
+			}
+			else {
+				pojoTuplizer = buildComponentTuplizer( tuplizerImpl, component );
+			}
+		}
+		else {
+			pojoTuplizer = dynamicMapTuplizer;
+		}
+
+		// then dom4j tuplizer, if dom4j representation is available
+		Tuplizer dom4jTuplizer = null;
+		tuplizerImpl = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.DOM4J );
+		if ( owner.hasDom4jRepresentation() ) {
+			if ( tuplizerImpl == null ) {
+				dom4jTuplizer = new Dom4jComponentTuplizer( component );
+			}
+			else {
+				dom4jTuplizer = buildComponentTuplizer( tuplizerImpl, component );
+			}
+		}
+		else {
+			dom4jTuplizer = null;
+		}
+
+		// put the "standard" tuplizers into the tuplizer map first
+		if ( pojoTuplizer != null ) {
+			addTuplizer( EntityMode.POJO, pojoTuplizer );
+		}
+		if ( dynamicMapTuplizer != null ) {
+			addTuplizer( EntityMode.MAP, dynamicMapTuplizer );
+		}
+		if ( dom4jTuplizer != null ) {
+			addTuplizer( EntityMode.DOM4J, dom4jTuplizer );
+		}
+
+		// then handle any user-defined entity modes...
+		if ( !userSuppliedTuplizerImpls.isEmpty() ) {
+			Iterator itr = userSuppliedTuplizerImpls.entrySet().iterator();
+			while ( itr.hasNext() ) {
+				Map.Entry entry = ( Map.Entry ) itr.next();
+				EntityMode entityMode = ( EntityMode ) entry.getKey();
+				ComponentTuplizer tuplizer = buildComponentTuplizer( ( String ) entry.getValue(), component );
+				addTuplizer( entityMode, tuplizer );
+			}
+		}
+	}
+
+	private ComponentTuplizer buildComponentTuplizer(String tuplizerImpl, Component component) {
+		try {
+			Class implClass = ReflectHelper.classForName( tuplizerImpl );
+			return ( ComponentTuplizer ) implClass.getConstructor( COMPONENT_TUP_CTOR_SIG ).newInstance( new Object[] { component } );
+		}
+		catch( Throwable t ) {
+			throw new HibernateException( "Could not build tuplizer [" + tuplizerImpl + "]", t );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/ComponentMetamodel.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/ComponentMetamodel.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/ComponentMetamodel.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,88 @@
+package org.hibernate.tuple.component;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.Property;
+import org.hibernate.HibernateException;
+import org.hibernate.tuple.StandardProperty;
+import org.hibernate.tuple.PropertyFactory;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * Centralizes metamodel information about a component.
+ *
+ * @author Steve Ebersole
+ */
+public class ComponentMetamodel implements Serializable {
+
+	// TODO : will need reference to session factory to fully complete HHH-1907
+
+//	private final SessionFactoryImplementor sessionFactory;
+	private final String role;
+	private final boolean isKey;
+	private final StandardProperty[] properties;
+	private final ComponentEntityModeToTuplizerMapping tuplizerMapping;
+
+	// cached for efficiency...
+	private final int propertySpan;
+	private final Map propertyIndexes = new HashMap();
+
+//	public ComponentMetamodel(Component component, SessionFactoryImplementor sessionFactory) {
+	public ComponentMetamodel(Component component) {
+//		this.sessionFactory = sessionFactory;
+		this.role = component.getRoleName();
+		this.isKey = component.isKey();
+		propertySpan = component.getPropertySpan();
+		properties = new StandardProperty[propertySpan];
+		Iterator itr = component.getPropertyIterator();
+		int i = 0;
+		while ( itr.hasNext() ) {
+			Property property = ( Property ) itr.next();
+			properties[i] = PropertyFactory.buildStandardProperty( property, false );
+			propertyIndexes.put( property.getName(), new Integer( i ) );
+			i++;
+		}
+
+		tuplizerMapping = new ComponentEntityModeToTuplizerMapping( component );
+	}
+
+	public boolean isKey() {
+		return isKey;
+	}
+
+	public int getPropertySpan() {
+		return propertySpan;
+	}
+
+	public StandardProperty[] getProperties() {
+		return properties;
+	}
+
+	public StandardProperty getProperty(int index) {
+		if ( index < 0 || index >= propertySpan ) {
+			throw new IllegalArgumentException( "illegal index value for component property access [request=" + index + ", span=" + propertySpan + "]" );
+		}
+		return properties[index];
+	}
+
+	public int getPropertyIndex(String propertyName) {
+		Integer index = ( Integer ) propertyIndexes.get( propertyName );
+		if ( index == null ) {
+			throw new HibernateException( "component does not contain such a property [" + propertyName + "]" );
+		}
+		return index.intValue();
+	}
+
+	public StandardProperty getProperty(String propertyName) {
+		return getProperty( getPropertyIndex( propertyName ) );
+	}
+
+	public ComponentEntityModeToTuplizerMapping getTuplizerMapping() {
+		return tuplizerMapping;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/ComponentTuplizer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/ComponentTuplizer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/ComponentTuplizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+//$Id: ComponentTuplizer.java 7451 2005-07-11 21:49:08Z steveebersole $
+package org.hibernate.tuple.component;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.tuple.Tuplizer;
+
+/**
+ * Defines further responsibilities reagarding tuplization based on
+ * a mapped components.
+ * </p>
+ * ComponentTuplizer implementations should have the following constructor signature:
+ *      (org.hibernate.mapping.Component)
+ * 
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public interface ComponentTuplizer extends Tuplizer, Serializable {
+	/**
+	 * Retreive the current value of the parent property.
+	 *
+	 * @param component The component instance from which to extract the parent
+	 * property value.
+	 * @return The current value of the parent property.
+	 */
+	public Object getParent(Object component);
+
+    /**
+     * Set the value of the parent property.
+     *
+     * @param component The component instance on which to set the parent.
+     * @param parent The parent to be set on the comonent.
+     * @param factory The current session factory.
+     */
+	public void setParent(Object component, Object parent, SessionFactoryImplementor factory);
+
+	/**
+	 * Does the component managed by this tuuplizer contain a parent property?
+	 *
+	 * @return True if the component does contain a parent property; false otherwise.
+	 */
+	public boolean hasParentProperty();
+
+	/**
+	 * Is the given method available via the managed component as a property getter?
+	 *
+	 * @param method The method which to check against the managed component.
+	 * @return True if the managed component is available from the managed component; else false.
+	 */
+	public boolean isMethodOf(Method method);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/Dom4jComponentTuplizer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/Dom4jComponentTuplizer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/Dom4jComponentTuplizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: Dom4jComponentTuplizer.java 7449 2005-07-11 17:31:50Z steveebersole $
+package org.hibernate.tuple.component;
+
+import org.dom4j.Element;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.Property;
+import org.hibernate.property.Getter;
+import org.hibernate.property.PropertyAccessor;
+import org.hibernate.property.PropertyAccessorFactory;
+import org.hibernate.property.Setter;
+import org.hibernate.tuple.Instantiator;
+import org.hibernate.tuple.Dom4jInstantiator;
+
+/**
+ * A {@link ComponentTuplizer} specific to the dom4j entity mode.
+ *
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public class Dom4jComponentTuplizer extends AbstractComponentTuplizer  {
+
+	public Class getMappedClass() {
+		return Element.class;
+	}
+
+	public Dom4jComponentTuplizer(Component component) {
+		super(component);
+	}
+
+	protected Instantiator buildInstantiator(Component component) {
+		return new Dom4jInstantiator( component );
+	}
+
+	private PropertyAccessor buildPropertyAccessor(Property property) {
+		//TODO: currently we don't know a SessionFactory reference when building the Tuplizer
+		//      THIS IS A BUG (embedded-xml=false on component)
+		// TODO : fix this after HHH-1907 is complete
+		return PropertyAccessorFactory.getDom4jPropertyAccessor( property.getNodeName(), property.getType(), null );
+	}
+
+	protected Getter buildGetter(Component component, Property prop) {
+		return buildPropertyAccessor(prop).getGetter( null, prop.getName() );
+	}
+
+	protected Setter buildSetter(Component component, Property prop) {
+		return buildPropertyAccessor(prop).getSetter( null, prop.getName() );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/DynamicMapComponentTuplizer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/DynamicMapComponentTuplizer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/DynamicMapComponentTuplizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+//$Id: DynamicMapComponentTuplizer.java 7449 2005-07-11 17:31:50Z steveebersole $
+package org.hibernate.tuple.component;
+
+import java.util.Map;
+
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.Property;
+import org.hibernate.property.Getter;
+import org.hibernate.property.PropertyAccessor;
+import org.hibernate.property.PropertyAccessorFactory;
+import org.hibernate.property.Setter;
+import org.hibernate.tuple.Instantiator;
+import org.hibernate.tuple.DynamicMapInstantiator;
+
+/**
+ * A {@link ComponentTuplizer} specific to the dynamic-map entity mode.
+ *
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public class DynamicMapComponentTuplizer extends AbstractComponentTuplizer {
+
+	public Class getMappedClass() {
+		return Map.class;
+	}
+
+	protected Instantiator buildInstantiator(Component component) {
+		return new DynamicMapInstantiator();
+	}
+
+	public DynamicMapComponentTuplizer(Component component) {
+		super(component);
+	}
+
+	private PropertyAccessor buildPropertyAccessor(Property property) {
+		return PropertyAccessorFactory.getDynamicMapPropertyAccessor();
+	}
+
+	protected Getter buildGetter(Component component, Property prop) {
+		return buildPropertyAccessor(prop).getGetter( null, prop.getName() );
+	}
+
+	protected Setter buildSetter(Component component, Property prop) {
+		return buildPropertyAccessor(prop).getSetter( null, prop.getName() );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,167 @@
+//$Id: PojoComponentTuplizer.java 9619 2006-03-15 00:12:47Z steve.ebersole at jboss.com $
+package org.hibernate.tuple.component;
+
+import java.lang.reflect.Method;
+import java.io.Serializable;
+
+import org.hibernate.HibernateException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.tuple.component.AbstractComponentTuplizer;
+import org.hibernate.tuple.Instantiator;
+import org.hibernate.tuple.PojoInstantiator;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.bytecode.ReflectionOptimizer;
+import org.hibernate.bytecode.BasicProxyFactory;
+import org.hibernate.cfg.Environment;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.Property;
+import org.hibernate.property.Getter;
+import org.hibernate.property.PropertyAccessor;
+import org.hibernate.property.PropertyAccessorFactory;
+import org.hibernate.property.Setter;
+
+/**
+ * A {@link ComponentTuplizer} specific to the pojo entity mode.
+ *
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public class PojoComponentTuplizer extends AbstractComponentTuplizer {
+
+	private final Class componentClass;
+	private ReflectionOptimizer optimizer;
+	private final Getter parentGetter;
+	private final Setter parentSetter;
+
+	public PojoComponentTuplizer(Component component) {
+		super( component );
+
+		this.componentClass = component.getComponentClass();
+
+		String[] getterNames = new String[propertySpan];
+		String[] setterNames = new String[propertySpan];
+		Class[] propTypes = new Class[propertySpan];
+		for ( int i = 0; i < propertySpan; i++ ) {
+			getterNames[i] = getters[i].getMethodName();
+			setterNames[i] = setters[i].getMethodName();
+			propTypes[i] = getters[i].getReturnType();
+		}
+
+		final String parentPropertyName = component.getParentProperty();
+		if ( parentPropertyName == null ) {
+			parentSetter = null;
+			parentGetter = null;
+		}
+		else {
+			PropertyAccessor pa = PropertyAccessorFactory.getPropertyAccessor( null );
+			parentSetter = pa.getSetter( componentClass, parentPropertyName );
+			parentGetter = pa.getGetter( componentClass, parentPropertyName );
+		}
+
+		if ( hasCustomAccessors || !Environment.useReflectionOptimizer() ) {
+			optimizer = null;
+		}
+		else {
+			// TODO: here is why we need to make bytecode provider global :(
+			// TODO : again, fix this after HHH-1907 is complete
+			optimizer = Environment.getBytecodeProvider().getReflectionOptimizer(
+					componentClass, getterNames, setterNames, propTypes
+			);
+		}
+	}
+
+	public Class getMappedClass() {
+		return componentClass;
+	}
+
+	public Object[] getPropertyValues(Object component) throws HibernateException {
+		if ( optimizer != null && optimizer.getAccessOptimizer() != null ) {
+			return optimizer.getAccessOptimizer().getPropertyValues( component );
+		}
+		else {
+			return super.getPropertyValues(component);
+		}
+	}
+
+	public void setPropertyValues(Object component, Object[] values) throws HibernateException {
+		if ( optimizer != null && optimizer.getAccessOptimizer() != null ) {
+				optimizer.getAccessOptimizer().setPropertyValues( component, values );
+		}
+		else {
+			super.setPropertyValues(component, values);
+		}
+
+	}
+
+	public Object getParent(Object component) {
+		return parentGetter.get( component );
+	}
+
+	public boolean hasParentProperty() {
+		return parentGetter!=null;
+	}
+
+	public boolean isMethodOf(Method method) {
+		for ( int i=0; i<propertySpan; i++ ) {
+			final Method getterMethod = getters[i].getMethod();
+			if ( getterMethod!=null && getterMethod.equals(method) ) return true;
+		}
+		return false;
+	}
+
+	public void setParent(Object component, Object parent, SessionFactoryImplementor factory) {
+		parentSetter.set(component, parent, factory);
+	}
+
+	protected Instantiator buildInstantiator(Component component) {
+		if ( component.isEmbedded() && ReflectHelper.isAbstractClass( component.getComponentClass() ) ) {
+			return new ProxiedInstantiator( component );
+		}
+		if ( optimizer == null ) {
+			return new PojoInstantiator( component, null );
+		}
+		else {
+			return new PojoInstantiator( component, optimizer.getInstantiationOptimizer() );
+		}
+	}
+
+	protected Getter buildGetter(Component component, Property prop) {
+		return prop.getGetter( component.getComponentClass() );
+	}
+
+	protected Setter buildSetter(Component component, Property prop) {
+		return prop.getSetter( component.getComponentClass() );
+	}
+
+	private static class ProxiedInstantiator implements Instantiator {
+		private final Class proxiedClass;
+		private final BasicProxyFactory factory;
+
+		public ProxiedInstantiator(Component component) {
+			proxiedClass = component.getComponentClass();
+			if ( proxiedClass.isInterface() ) {
+				factory = Environment.getBytecodeProvider()
+						.getProxyFactoryFactory()
+						.buildBasicProxyFactory( null, new Class[] { proxiedClass } );
+			}
+			else {
+				factory = Environment.getBytecodeProvider()
+						.getProxyFactoryFactory()
+						.buildBasicProxyFactory( proxiedClass, null );
+			}
+		}
+
+		public Object instantiate(Serializable id) {
+			throw new AssertionFailure( "ProxiedInstantiator can only be used to instantiate component" );
+		}
+
+		public Object instantiate() {
+			return factory.getProxy();
+		}
+
+		public boolean isInstance(Object object) {
+			return proxiedClass.isInstance( object );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,410 @@
+// $Id: AbstractEntityTuplizer.java 7516 2005-07-16 22:20:48Z oneovthafew $
+package org.hibernate.tuple.entity;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.tuple.Instantiator;
+import org.hibernate.tuple.VersionProperty;
+import org.hibernate.tuple.StandardProperty;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.id.Assigned;
+import org.hibernate.intercept.LazyPropertyInitializer;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.property.Getter;
+import org.hibernate.property.Setter;
+import org.hibernate.proxy.ProxyFactory;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.ComponentType;
+
+
+/**
+ * Support for tuplizers relating to entities.
+ *
+ * @author Steve Ebersole
+ * @author Gavin King
+ */
+public abstract class AbstractEntityTuplizer implements EntityTuplizer {
+
+	//TODO: currently keeps Getters and Setters (instead of PropertyAccessors) because of the way getGetter() and getSetter() are implemented currently; yuck!
+
+	private final EntityMetamodel entityMetamodel;
+
+	private final Getter idGetter;
+	private final Setter idSetter;
+
+	protected final Getter[] getters;
+	protected final Setter[] setters;
+	protected final int propertySpan;
+	protected final boolean hasCustomAccessors;
+	private final Instantiator instantiator;
+	private final ProxyFactory proxyFactory;
+	private final AbstractComponentType identifierMapperType;
+
+
+	/**
+	 * Return the entity-mode handled by this tuplizer instance.
+	 *
+	 * @return The entity-mode
+	 */
+	protected abstract EntityMode getEntityMode();
+
+	/**
+	 * Build an appropriate Getter for the given property.
+	 *
+	 * @param mappedProperty The property to be accessed via the built Getter.
+	 * @param mappedEntity The entity information regarding the mapped entity owning this property.
+	 * @return An appropriate Getter instance.
+	 */
+	protected abstract Getter buildPropertyGetter(Property mappedProperty, PersistentClass mappedEntity);
+
+	/**
+	 * Build an appropriate Setter for the given property.
+	 *
+	 * @param mappedProperty The property to be accessed via the built Setter.
+	 * @param mappedEntity The entity information regarding the mapped entity owning this property.
+	 * @return An appropriate Setter instance.
+	 */
+	protected abstract Setter buildPropertySetter(Property mappedProperty, PersistentClass mappedEntity);
+
+	/**
+	 * Build an appropriate Instantiator for the given mapped entity.
+	 *
+	 * @param mappingInfo The mapping information regarding the mapped entity.
+	 * @return An appropriate Instantiator instance.
+	 */
+	protected abstract Instantiator buildInstantiator(PersistentClass mappingInfo);
+
+	/**
+	 * Build an appropriate ProxyFactory for the given mapped entity.
+	 *
+	 * @param mappingInfo The mapping information regarding the mapped entity.
+	 * @param idGetter The constructed Getter relating to the entity's id property.
+	 * @param idSetter The constructed Setter relating to the entity's id property.
+	 * @return An appropriate ProxyFactory instance.
+	 */
+	protected abstract ProxyFactory buildProxyFactory(PersistentClass mappingInfo, Getter idGetter, Setter idSetter);
+
+	/**
+	 * Constructs a new AbstractEntityTuplizer instance.
+	 *
+	 * @param entityMetamodel The "interpreted" information relating to the mapped entity.
+	 * @param mappingInfo The parsed "raw" mapping data relating to the given entity.
+	 */
+	public AbstractEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappingInfo) {
+		this.entityMetamodel = entityMetamodel;
+
+		if ( !entityMetamodel.getIdentifierProperty().isVirtual() ) {
+			idGetter = buildPropertyGetter( mappingInfo.getIdentifierProperty(), mappingInfo );
+			idSetter = buildPropertySetter( mappingInfo.getIdentifierProperty(), mappingInfo );
+		}
+		else {
+			idGetter = null;
+			idSetter = null;
+		}
+
+		propertySpan = entityMetamodel.getPropertySpan();
+
+        getters = new Getter[propertySpan];
+		setters = new Setter[propertySpan];
+
+		Iterator iter = mappingInfo.getPropertyClosureIterator();
+		boolean foundCustomAccessor=false;
+		int i=0;
+		while ( iter.hasNext() ) {
+			//TODO: redesign how PropertyAccessors are acquired...
+			Property property = (Property) iter.next();
+			getters[i] = buildPropertyGetter(property, mappingInfo);
+			setters[i] = buildPropertySetter(property, mappingInfo);
+			if ( !property.isBasicPropertyAccessor() ) foundCustomAccessor = true;
+			i++;
+		}
+		hasCustomAccessors = foundCustomAccessor;
+
+        instantiator = buildInstantiator( mappingInfo );
+
+		if ( entityMetamodel.isLazy() ) {
+			proxyFactory = buildProxyFactory( mappingInfo, idGetter, idSetter );
+			if (proxyFactory == null) {
+				entityMetamodel.setLazy( false );
+			}
+		}
+		else {
+			proxyFactory = null;
+		}
+		
+		Component mapper = mappingInfo.getIdentifierMapper();
+		identifierMapperType = mapper==null ? null : (AbstractComponentType) mapper.getType();
+	}
+
+	/** Retreives the defined entity-name for the tuplized entity.
+	 *
+	 * @return The entity-name.
+	 */
+	protected String getEntityName() {
+		return entityMetamodel.getName();
+	}
+
+	/**
+	 * Retreives the defined entity-names for any subclasses defined for this
+	 * entity.
+	 *
+	 * @return Any subclass entity-names.
+	 */
+	protected Set getSubclassEntityNames() {
+		return entityMetamodel.getSubclassEntityNames();
+	}
+
+	public Serializable getIdentifier(Object entity) throws HibernateException {
+		final Object id;
+		if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) {
+			id = entity;
+		}
+		else {
+			if ( idGetter == null ) {
+				if (identifierMapperType==null) {
+					throw new HibernateException( "The class has no identifier property: " + getEntityName() );
+				}
+				else {
+					ComponentType copier = (ComponentType) entityMetamodel.getIdentifierProperty().getType();
+					id = copier.instantiate( getEntityMode() );
+					copier.setPropertyValues( id, identifierMapperType.getPropertyValues( entity, getEntityMode() ), getEntityMode() );
+				}
+			}
+			else {
+				id = idGetter.get( entity );
+			}
+		}
+
+		try {
+			return (Serializable) id;
+		}
+		catch ( ClassCastException cce ) {
+			StringBuffer msg = new StringBuffer( "Identifier classes must be serializable. " );
+			if ( id != null ) {
+				msg.append( id.getClass().getName() + " is not serializable. " );
+			}
+			if ( cce.getMessage() != null ) {
+				msg.append( cce.getMessage() );
+			}
+			throw new ClassCastException( msg.toString() );
+		}
+	}
+
+
+	public void setIdentifier(Object entity, Serializable id) throws HibernateException {
+		if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) {
+			if ( entity != id ) {
+				AbstractComponentType copier = (AbstractComponentType) entityMetamodel.getIdentifierProperty().getType();
+				copier.setPropertyValues( entity, copier.getPropertyValues( id, getEntityMode() ), getEntityMode() );
+			}
+		}
+		else if ( idSetter != null ) {
+			idSetter.set( entity, id, getFactory() );
+		}
+	}
+
+	public void resetIdentifier(Object entity, Serializable currentId, Object currentVersion) {
+		if ( entityMetamodel.getIdentifierProperty().getIdentifierGenerator() instanceof Assigned ) {
+			//return currentId;
+		}
+		else {
+			//reset the id
+			Serializable result = entityMetamodel.getIdentifierProperty()
+					.getUnsavedValue()
+					.getDefaultValue( currentId );
+			setIdentifier( entity, result );
+			//reset the version
+			VersionProperty versionProperty = entityMetamodel.getVersionProperty();
+			if ( entityMetamodel.isVersioned() ) {
+				setPropertyValue(
+				        entity,
+				        entityMetamodel.getVersionPropertyIndex(),
+						versionProperty.getUnsavedValue().getDefaultValue( currentVersion )
+					);
+			}
+			//return the id, so we can use it to reset the proxy id
+			//return result;
+		}
+	}
+
+	public Object getVersion(Object entity) throws HibernateException {
+		if ( !entityMetamodel.isVersioned() ) return null;
+		return getters[ entityMetamodel.getVersionPropertyIndex() ].get( entity );
+	}
+
+	protected boolean shouldGetAllProperties(Object entity) {
+		return !hasUninitializedLazyProperties( entity );
+	}
+
+	public Object[] getPropertyValues(Object entity) throws HibernateException {
+		boolean getAll = shouldGetAllProperties( entity );
+		final int span = entityMetamodel.getPropertySpan();
+		final Object[] result = new Object[span];
+
+		for ( int j = 0; j < span; j++ ) {
+			StandardProperty property = entityMetamodel.getProperties()[j];
+			if ( getAll || !property.isLazy() ) {
+				result[j] = getters[j].get( entity );
+			}
+			else {
+				result[j] = LazyPropertyInitializer.UNFETCHED_PROPERTY;
+			}
+		}
+		return result;
+	}
+
+	public Object[] getPropertyValuesToInsert(Object entity, Map mergeMap, SessionImplementor session) 
+	throws HibernateException {
+		final int span = entityMetamodel.getPropertySpan();
+		final Object[] result = new Object[span];
+
+		for ( int j = 0; j < span; j++ ) {
+			result[j] = getters[j].getForInsert( entity, mergeMap, session );
+		}
+		return result;
+	}
+
+	public Object getPropertyValue(Object entity, int i) throws HibernateException {
+		return getters[i].get( entity );
+	}
+
+	public Object getPropertyValue(Object entity, String propertyPath) throws HibernateException {
+		
+		int loc = propertyPath.indexOf('.');
+		String basePropertyName = loc>0 ?
+			propertyPath.substring(0, loc) : propertyPath;
+			
+		int index = entityMetamodel.getPropertyIndex( basePropertyName );
+		Object baseValue = getPropertyValue( entity, index );
+		if ( loc>0 ) {
+			ComponentType type = (ComponentType) entityMetamodel.getPropertyTypes()[index];
+			return getComponentValue( type, baseValue, propertyPath.substring(loc+1) );
+		}
+		else {
+			return baseValue;
+		}
+	}
+
+	/**
+	 * Extract a component property value.
+	 *
+	 * @param type The component property types.
+	 * @param component The component instance itself.
+	 * @param propertyPath The property path for the property to be extracted.
+	 * @return The property value extracted.
+	 */
+	protected Object getComponentValue(ComponentType type, Object component, String propertyPath) {
+		
+		int loc = propertyPath.indexOf('.');
+		String basePropertyName = loc>0 ?
+			propertyPath.substring(0, loc) : propertyPath;
+		
+		String[] propertyNames = type.getPropertyNames();
+		int index=0;
+		for ( ; index<propertyNames.length; index++ ) {
+			if ( basePropertyName.equals( propertyNames[index] ) ) break;
+		}
+		if (index==propertyNames.length) {
+			throw new MappingException( "component property not found: " + basePropertyName );
+		}
+		
+		Object baseValue = type.getPropertyValue( component, index, getEntityMode() );
+		
+		if ( loc>0 ) {
+			ComponentType subtype = (ComponentType) type.getSubtypes()[index];
+			return getComponentValue( subtype, baseValue, propertyPath.substring(loc+1) );
+		}
+		else {
+			return baseValue;
+		}
+		
+	}
+
+	public void setPropertyValues(Object entity, Object[] values) throws HibernateException {
+		boolean setAll = !entityMetamodel.hasLazyProperties();
+
+		for ( int j = 0; j < entityMetamodel.getPropertySpan(); j++ ) {
+			if ( setAll || values[j] != LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
+				setters[j].set( entity, values[j], getFactory() );
+			}
+		}
+	}
+
+	public void setPropertyValue(Object entity, int i, Object value) throws HibernateException {
+		setters[i].set( entity, value, getFactory() );
+	}
+
+	public void setPropertyValue(Object entity, String propertyName, Object value) throws HibernateException {
+		setters[ entityMetamodel.getPropertyIndex( propertyName ) ].set( entity, value, getFactory() );
+	}
+
+	public final Object instantiate(Serializable id) throws HibernateException {
+		Object result = getInstantiator().instantiate( id );
+		if ( id != null ) {
+			setIdentifier( result, id );
+		}
+		return result;
+	}
+
+	public final Object instantiate() throws HibernateException {
+		return instantiate( null );
+	}
+
+	public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) {}
+
+	public boolean hasUninitializedLazyProperties(Object entity) {
+		// the default is to simply not lazy fetch properties for now...
+		return false;
+	}
+
+	public final boolean isInstance(Object object) {
+        return getInstantiator().isInstance( object );
+	}
+
+	public boolean hasProxy() {
+		return entityMetamodel.isLazy();
+	}
+
+	public final Object createProxy(Serializable id, SessionImplementor session)
+	throws HibernateException {
+		return getProxyFactory().getProxy( id, session );
+	}
+
+	public boolean isLifecycleImplementor() {
+		return false;
+	}
+
+	public boolean isValidatableImplementor() {
+		return false;
+	}
+	
+	protected final EntityMetamodel getEntityMetamodel() {
+		return entityMetamodel;
+	}
+
+	protected final SessionFactoryImplementor getFactory() {
+		return entityMetamodel.getSessionFactory();
+	}
+
+	protected final Instantiator getInstantiator() {
+		return instantiator;
+	}
+
+	protected final ProxyFactory getProxyFactory() {
+		return proxyFactory;
+	}
+	
+	public String toString() {
+		return getClass().getName() + '(' + getEntityMetamodel().getName() + ')';
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/Dom4jEntityTuplizer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/Dom4jEntityTuplizer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/Dom4jEntityTuplizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,123 @@
+// $Id: Dom4jEntityTuplizer.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.tuple.entity;
+
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.proxy.ProxyFactory;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.dom4j.Dom4jProxyFactory;
+import org.hibernate.property.PropertyAccessor;
+import org.hibernate.property.PropertyAccessorFactory;
+import org.hibernate.property.Getter;
+import org.hibernate.property.Setter;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.tuple.Instantiator;
+import org.hibernate.tuple.Dom4jInstantiator;
+import org.hibernate.type.AbstractComponentType;
+import org.dom4j.Element;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Iterator;
+
+/**
+ * An {@link EntityTuplizer} specific to the dom4j entity mode.
+ *
+ * @author Steve Ebersole
+ * @author Gavin King
+ */
+public class Dom4jEntityTuplizer extends AbstractEntityTuplizer {
+
+	static final Log log = LogFactory.getLog( Dom4jEntityTuplizer.class );
+
+	private Set subclassNodeNames = new HashSet();
+
+	Dom4jEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
+		super(entityMetamodel, mappedEntity);
+		Iterator itr = mappedEntity.getSubclassClosureIterator();
+		while( itr.hasNext() ) {
+			final PersistentClass mapping = ( PersistentClass ) itr.next();
+			subclassNodeNames.add( mapping.getNodeName() );
+		}
+	}
+	
+	public EntityMode getEntityMode() {
+		return EntityMode.DOM4J;
+	}
+
+	private PropertyAccessor buildPropertyAccessor(Property mappedProperty) {
+		if ( mappedProperty.isBackRef() ) {
+			return mappedProperty.getPropertyAccessor(null);
+		}
+		else {
+			return PropertyAccessorFactory.getDom4jPropertyAccessor( 
+					mappedProperty.getNodeName(), 
+					mappedProperty.getType(),
+					getEntityMetamodel().getSessionFactory()
+				);
+		}
+	}
+
+	protected Getter buildPropertyGetter(Property mappedProperty, PersistentClass mappedEntity) {
+		return buildPropertyAccessor(mappedProperty).getGetter( null, mappedProperty.getName() );
+	}
+
+	protected Setter buildPropertySetter(Property mappedProperty, PersistentClass mappedEntity) {
+		return buildPropertyAccessor(mappedProperty).getSetter( null, mappedProperty.getName() );
+	}
+
+	protected Instantiator buildInstantiator(PersistentClass persistentClass) {
+		return new Dom4jInstantiator( persistentClass );
+	}
+
+	public Serializable getIdentifier(Object entityOrId) throws HibernateException {
+		if (entityOrId instanceof Element) {
+			return super.getIdentifier(entityOrId);
+		}
+		else {
+			//it was not embedded, so the argument is just an id
+			return (Serializable) entityOrId;
+		}
+	}
+	
+	protected ProxyFactory buildProxyFactory(PersistentClass mappingInfo, Getter idGetter, Setter idSetter) {
+		HashSet proxyInterfaces = new HashSet();
+		proxyInterfaces.add( HibernateProxy.class );
+		proxyInterfaces.add( Element.class );
+
+		ProxyFactory pf = new Dom4jProxyFactory();
+		try {
+			pf.postInstantiate(
+					getEntityName(),
+					Element.class,
+					proxyInterfaces,
+					null,
+					null,
+					mappingInfo.hasEmbeddedIdentifier() ?
+			                (AbstractComponentType) mappingInfo.getIdentifier().getType() :
+			                null
+			);
+		}
+		catch ( HibernateException he ) {
+			log.warn( "could not create proxy factory for:" + getEntityName(), he );
+			pf = null;
+		}
+		return pf;
+	}
+
+	public Class getMappedClass() {
+		return Element.class;
+	}
+
+	public Class getConcreteProxyClass() {
+		return Element.class;
+	}
+
+	public boolean isInstrumented() {
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,93 @@
+// $Id: DynamicMapEntityTuplizer.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.tuple.entity;
+
+import java.util.Map;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.tuple.entity.AbstractEntityTuplizer;
+import org.hibernate.tuple.Instantiator;
+import org.hibernate.tuple.DynamicMapInstantiator;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.property.Getter;
+import org.hibernate.property.PropertyAccessor;
+import org.hibernate.property.PropertyAccessorFactory;
+import org.hibernate.property.Setter;
+import org.hibernate.proxy.map.MapProxyFactory;
+import org.hibernate.proxy.ProxyFactory;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * An {@link EntityTuplizer} specific to the dynamic-map entity mode.
+ *
+ * @author Steve Ebersole
+ * @author Gavin King
+ */
+public class DynamicMapEntityTuplizer extends AbstractEntityTuplizer {
+
+	static final Log log = LogFactory.getLog( DynamicMapEntityTuplizer.class );
+
+	DynamicMapEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
+		super(entityMetamodel, mappedEntity);
+	}
+	
+	public EntityMode getEntityMode() {
+		return EntityMode.MAP;
+	}
+
+	private PropertyAccessor buildPropertyAccessor(Property mappedProperty) {
+		if ( mappedProperty.isBackRef() ) {
+			return mappedProperty.getPropertyAccessor(null);
+		}
+		else {
+			return PropertyAccessorFactory.getDynamicMapPropertyAccessor();
+		}
+	}
+
+	protected Getter buildPropertyGetter(Property mappedProperty, PersistentClass mappedEntity) {
+		return buildPropertyAccessor(mappedProperty).getGetter( null, mappedProperty.getName() );
+	}
+
+	protected Setter buildPropertySetter(Property mappedProperty, PersistentClass mappedEntity) {
+		return buildPropertyAccessor(mappedProperty).getSetter( null, mappedProperty.getName() );
+	}
+
+	protected Instantiator buildInstantiator(PersistentClass mappingInfo) {
+        return new DynamicMapInstantiator( mappingInfo );
+	}
+
+	protected ProxyFactory buildProxyFactory(PersistentClass mappingInfo, Getter idGetter, Setter idSetter) {
+
+		ProxyFactory pf = new MapProxyFactory();
+		try {
+			//TODO: design new lifecycle for ProxyFactory
+			pf.postInstantiate(
+					getEntityName(),
+					null,
+					null,
+					null,
+					null,
+					null
+			);
+		}
+		catch ( HibernateException he ) {
+			log.warn( "could not create proxy factory for:" + getEntityName(), he );
+			pf = null;
+		}
+		return pf;
+	}
+
+	public Class getMappedClass() {
+		return Map.class;
+	}
+
+	public Class getConcreteProxyClass() {
+		return Map.class;
+	}
+
+	public boolean isInstrumented() {
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/EntityEntityModeToTuplizerMapping.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/EntityEntityModeToTuplizerMapping.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/EntityEntityModeToTuplizerMapping.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,113 @@
+package org.hibernate.tuple.entity;
+
+import org.hibernate.tuple.EntityModeToTuplizerMapping;
+import org.hibernate.tuple.Tuplizer;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.util.ReflectHelper;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.HashMap;
+import java.io.Serializable;
+
+/**
+ * Handles mapping {@link EntityMode}s to {@link EntityTuplizer}s.
+ * <p/>
+ * Most of the handling is really in the super class; here we just create
+ * the tuplizers and add them to the superclass
+ *
+ * @author Steve Ebersole
+ */
+public class EntityEntityModeToTuplizerMapping extends EntityModeToTuplizerMapping implements Serializable {
+
+	private static final Class[] ENTITY_TUP_CTOR_SIG = new Class[] { EntityMetamodel.class, PersistentClass.class };
+
+	/**
+	 * Instantiates a EntityEntityModeToTuplizerMapping based on the given
+	 * entity mapping and metamodel definitions.
+	 *
+	 * @param mappedEntity The entity mapping definition.
+	 * @param em The entity metamodel definition.
+	 */
+	public EntityEntityModeToTuplizerMapping(PersistentClass mappedEntity, EntityMetamodel em) {
+		// create our own copy of the user-supplied tuplizer impl map
+		Map userSuppliedTuplizerImpls = new HashMap();
+		if ( mappedEntity.getTuplizerMap() != null ) {
+			userSuppliedTuplizerImpls.putAll( mappedEntity.getTuplizerMap() );
+		}
+
+		// Build the dynamic-map tuplizer...
+		Tuplizer dynamicMapTuplizer = null;
+		String tuplizerImpl = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.MAP );
+		if ( tuplizerImpl == null ) {
+			dynamicMapTuplizer = new DynamicMapEntityTuplizer( em, mappedEntity );
+		}
+		else {
+			dynamicMapTuplizer = buildEntityTuplizer( tuplizerImpl, mappedEntity, em );
+		}
+
+		// then the pojo tuplizer, using the dynamic-map tuplizer if no pojo representation is available
+		Tuplizer pojoTuplizer = null;
+		tuplizerImpl = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.POJO );
+		if ( mappedEntity.hasPojoRepresentation() ) {
+			if ( tuplizerImpl == null ) {
+				pojoTuplizer = new PojoEntityTuplizer( em, mappedEntity );
+			}
+			else {
+				pojoTuplizer = buildEntityTuplizer( tuplizerImpl, mappedEntity, em );
+			}
+		}
+		else {
+			pojoTuplizer = dynamicMapTuplizer;
+		}
+
+		// then dom4j tuplizer, if dom4j representation is available
+		Tuplizer dom4jTuplizer = null;
+		tuplizerImpl = ( String ) userSuppliedTuplizerImpls.remove( EntityMode.DOM4J );
+		if ( mappedEntity.hasDom4jRepresentation() ) {
+			if ( tuplizerImpl == null ) {
+				dom4jTuplizer = new Dom4jEntityTuplizer( em, mappedEntity );
+			}
+			else {
+				dom4jTuplizer = buildEntityTuplizer( tuplizerImpl, mappedEntity, em );
+			}
+		}
+		else {
+			dom4jTuplizer = null;
+		}
+
+		// put the "standard" tuplizers into the tuplizer map first
+		if ( pojoTuplizer != null ) {
+			addTuplizer( EntityMode.POJO, pojoTuplizer );
+		}
+		if ( dynamicMapTuplizer != null ) {
+			addTuplizer( EntityMode.MAP, dynamicMapTuplizer );
+		}
+		if ( dom4jTuplizer != null ) {
+			addTuplizer( EntityMode.DOM4J, dom4jTuplizer );
+		}
+
+		// then handle any user-defined entity modes...
+		if ( !userSuppliedTuplizerImpls.isEmpty() ) {
+			Iterator itr = userSuppliedTuplizerImpls.entrySet().iterator();
+			while ( itr.hasNext() ) {
+				Map.Entry entry = ( Map.Entry ) itr.next();
+				EntityMode entityMode = ( EntityMode ) entry.getKey();
+				EntityTuplizer tuplizer = buildEntityTuplizer( ( String ) entry.getValue(), mappedEntity, em );
+				addTuplizer( entityMode, tuplizer );
+			}
+		}
+	}
+
+	private static EntityTuplizer buildEntityTuplizer(String className, PersistentClass pc, EntityMetamodel em) {
+		try {
+			Class implClass = ReflectHelper.classForName( className );
+			return ( EntityTuplizer ) implClass.getConstructor( ENTITY_TUP_CTOR_SIG ).newInstance( new Object[] { em, pc } );
+		}
+		catch( Throwable t ) {
+			throw new HibernateException( "Could not build tuplizer [" + className + "]", t );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,586 @@
+// $Id: EntityMetamodel.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.tuple.entity;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.tuple.IdentifierProperty;
+import org.hibernate.tuple.StandardProperty;
+import org.hibernate.tuple.PropertyFactory;
+import org.hibernate.tuple.VersionProperty;
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.Versioning;
+import org.hibernate.engine.ValueInclusion;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.PropertyGeneration;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * Centralizes metamodel information about an entity.
+ *
+ * @author Steve Ebersole
+ */
+public class EntityMetamodel implements Serializable {
+
+	private static final Log log = LogFactory.getLog(EntityMetamodel.class);
+
+	private static final int NO_VERSION_INDX = -66;
+
+	private final SessionFactoryImplementor sessionFactory;
+
+	private final String name;
+	private final String rootName;
+	private final EntityType entityType;
+
+	private final IdentifierProperty identifierProperty;
+	private final boolean versioned;
+
+	private final int propertySpan;
+	private final int versionPropertyIndex;
+	private final StandardProperty[] properties;
+	// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	private final String[] propertyNames;
+	private final Type[] propertyTypes;
+	private final boolean[] propertyLaziness;
+	private final boolean[] propertyUpdateability;
+	private final boolean[] nonlazyPropertyUpdateability;
+	private final boolean[] propertyCheckability;
+	private final boolean[] propertyInsertability;
+	private final ValueInclusion[] insertInclusions;
+	private final ValueInclusion[] updateInclusions;
+	private final boolean[] propertyNullability;
+	private final boolean[] propertyVersionability;
+	private final CascadeStyle[] cascadeStyles;
+	private final boolean hasInsertGeneratedValues;
+	private final boolean hasUpdateGeneratedValues;
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	private final Map propertyIndexes = new HashMap();
+	private final boolean hasCollections;
+	private final boolean hasMutableProperties;
+	private final boolean hasLazyProperties;
+	private final boolean hasNonIdentifierPropertyNamedId;
+
+	private final int[] naturalIdPropertyNumbers;
+
+	private boolean lazy; //not final because proxy factory creation can fail
+	private final boolean hasCascades;
+	private final boolean mutable;
+	private final boolean isAbstract;
+	private final boolean selectBeforeUpdate;
+	private final boolean dynamicUpdate;
+	private final boolean dynamicInsert;
+	private final int optimisticLockMode;
+
+	private final boolean polymorphic;
+	private final String superclass;  // superclass entity-name
+	private final boolean explicitPolymorphism;
+	private final boolean inherited;
+	private final boolean hasSubclasses;
+	private final Set subclassEntityNames = new HashSet();
+
+	private final EntityEntityModeToTuplizerMapping tuplizerMapping;
+
+	public EntityTuplizer getTuplizer(EntityMode entityMode) {
+		return (EntityTuplizer) tuplizerMapping.getTuplizer( entityMode );
+	}
+
+	public EntityTuplizer getTuplizerOrNull(EntityMode entityMode) {
+		return ( EntityTuplizer ) tuplizerMapping.getTuplizerOrNull( entityMode );
+	}
+
+	public EntityMode guessEntityMode(Object object) {
+		return tuplizerMapping.guessEntityMode( object );
+	}
+
+	public EntityMetamodel(PersistentClass persistentClass, SessionFactoryImplementor sessionFactory) {
+		this.sessionFactory = sessionFactory;
+
+		name = persistentClass.getEntityName();
+		rootName = persistentClass.getRootClass().getEntityName();
+		entityType = TypeFactory.manyToOne( name );
+
+		identifierProperty = PropertyFactory.buildIdentifierProperty(
+		        persistentClass,
+		        sessionFactory.getIdentifierGenerator( rootName )
+			);
+
+		versioned = persistentClass.isVersioned();
+
+		boolean lazyAvailable = persistentClass.hasPojoRepresentation() &&
+		                        FieldInterceptionHelper.isInstrumented( persistentClass.getMappedClass() );
+		boolean hasLazy = false;
+
+		propertySpan = persistentClass.getPropertyClosureSpan();
+		properties = new StandardProperty[propertySpan];
+		List naturalIdNumbers = new ArrayList();
+		// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		propertyNames = new String[propertySpan];
+		propertyTypes = new Type[propertySpan];
+		propertyUpdateability = new boolean[propertySpan];
+		propertyInsertability = new boolean[propertySpan];
+		insertInclusions = new ValueInclusion[propertySpan];
+		updateInclusions = new ValueInclusion[propertySpan];
+		nonlazyPropertyUpdateability = new boolean[propertySpan];
+		propertyCheckability = new boolean[propertySpan];
+		propertyNullability = new boolean[propertySpan];
+		propertyVersionability = new boolean[propertySpan];
+		propertyLaziness = new boolean[propertySpan];
+		cascadeStyles = new CascadeStyle[propertySpan];
+		// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+		Iterator iter = persistentClass.getPropertyClosureIterator();
+		int i = 0;
+		int tempVersionProperty = NO_VERSION_INDX;
+		boolean foundCascade = false;
+		boolean foundCollection = false;
+		boolean foundMutable = false;
+		boolean foundNonIdentifierPropertyNamedId = false;
+		boolean foundInsertGeneratedValue = false;
+		boolean foundUpdateGeneratedValue = false;
+
+		while ( iter.hasNext() ) {
+			Property prop = ( Property ) iter.next();
+
+			if ( prop == persistentClass.getVersion() ) {
+				tempVersionProperty = i;
+				properties[i] = PropertyFactory.buildVersionProperty( prop, lazyAvailable );
+			}
+			else {
+				properties[i] = PropertyFactory.buildStandardProperty( prop, lazyAvailable );
+			}
+
+			if ( prop.isNaturalIdentifier() ) {
+				naturalIdNumbers.add( new Integer(i) );
+			}
+
+			if ( "id".equals( prop.getName() ) ) {
+				foundNonIdentifierPropertyNamedId = true;
+			}
+
+			// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+			boolean lazy = prop.isLazy() && lazyAvailable;
+			if ( lazy ) hasLazy = true;
+			propertyLaziness[i] = lazy;
+
+			propertyNames[i] = properties[i].getName();
+			propertyTypes[i] = properties[i].getType();
+			propertyNullability[i] = properties[i].isNullable();
+			propertyUpdateability[i] = properties[i].isUpdateable();
+			propertyInsertability[i] = properties[i].isInsertable();
+			insertInclusions[i] = determineInsertValueGenerationType( prop, properties[i] );
+			updateInclusions[i] = determineUpdateValueGenerationType( prop, properties[i] );
+			propertyVersionability[i] = properties[i].isVersionable();
+			nonlazyPropertyUpdateability[i] = properties[i].isUpdateable() && !lazy;
+			propertyCheckability[i] = propertyUpdateability[i] ||
+					( propertyTypes[i].isAssociationType() && ( (AssociationType) propertyTypes[i] ).isAlwaysDirtyChecked() );
+
+			cascadeStyles[i] = properties[i].getCascadeStyle();
+			// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+			if ( properties[i].isLazy() ) {
+				hasLazy = true;
+			}
+
+			if ( properties[i].getCascadeStyle() != CascadeStyle.NONE ) {
+				foundCascade = true;
+			}
+
+			if ( indicatesCollection( properties[i].getType() ) ) {
+				foundCollection = true;
+			}
+
+			if ( propertyTypes[i].isMutable() && propertyCheckability[i] ) {
+				foundMutable = true;
+			}
+
+			if ( insertInclusions[i] != ValueInclusion.NONE ) {
+				foundInsertGeneratedValue = true;
+			}
+
+			if ( updateInclusions[i] != ValueInclusion.NONE ) {
+				foundUpdateGeneratedValue = true;
+			}
+
+			mapPropertyToIndex(prop, i);
+			i++;
+		}
+
+		if (naturalIdNumbers.size()==0) {
+			naturalIdPropertyNumbers = null;
+		}
+		else {
+			naturalIdPropertyNumbers = ArrayHelper.toIntArray(naturalIdNumbers);
+		}
+
+		hasInsertGeneratedValues = foundInsertGeneratedValue;
+		hasUpdateGeneratedValues = foundUpdateGeneratedValue;
+
+		hasCascades = foundCascade;
+		hasNonIdentifierPropertyNamedId = foundNonIdentifierPropertyNamedId;
+		versionPropertyIndex = tempVersionProperty;
+		hasLazyProperties = hasLazy;
+		if ( hasLazyProperties ) {
+			log.info( "lazy property fetching available for: " + name );
+		}
+
+		lazy = persistentClass.isLazy() && (
+				// TODO: this disables laziness even in non-pojo entity modes:
+				!persistentClass.hasPojoRepresentation() ||
+				!ReflectHelper.isFinalClass( persistentClass.getProxyInterface() )
+		);
+		mutable = persistentClass.isMutable();
+		if ( persistentClass.isAbstract() == null ) {
+			// legacy behavior (with no abstract attribute specified)
+			isAbstract = persistentClass.hasPojoRepresentation() &&
+			             ReflectHelper.isAbstractClass( persistentClass.getMappedClass() );
+		}
+		else {
+			isAbstract = persistentClass.isAbstract().booleanValue();
+			if ( !isAbstract && persistentClass.hasPojoRepresentation() &&
+			     ReflectHelper.isAbstractClass( persistentClass.getMappedClass() ) ) {
+				log.warn( "entity [" + name + "] is abstract-class/interface explicitly mapped as non-abstract; be sure to supply entity-names" );
+			}
+		}
+		selectBeforeUpdate = persistentClass.hasSelectBeforeUpdate();
+		dynamicUpdate = persistentClass.useDynamicUpdate();
+		dynamicInsert = persistentClass.useDynamicInsert();
+
+		polymorphic = persistentClass.isPolymorphic();
+		explicitPolymorphism = persistentClass.isExplicitPolymorphism();
+		inherited = persistentClass.isInherited();
+		superclass = inherited ?
+				persistentClass.getSuperclass().getEntityName() :
+				null;
+		hasSubclasses = persistentClass.hasSubclasses();
+
+		optimisticLockMode = persistentClass.getOptimisticLockMode();
+		if ( optimisticLockMode > Versioning.OPTIMISTIC_LOCK_VERSION && !dynamicUpdate ) {
+			throw new MappingException( "optimistic-lock=all|dirty requires dynamic-update=\"true\": " + name );
+		}
+		if ( versionPropertyIndex != NO_VERSION_INDX && optimisticLockMode > Versioning.OPTIMISTIC_LOCK_VERSION ) {
+			throw new MappingException( "version and optimistic-lock=all|dirty are not a valid combination : " + name );
+		}
+
+		hasCollections = foundCollection;
+		hasMutableProperties = foundMutable;
+
+		iter = persistentClass.getSubclassIterator();
+		while ( iter.hasNext() ) {
+			subclassEntityNames.add( ( (PersistentClass) iter.next() ).getEntityName() );
+		}
+		subclassEntityNames.add( name );
+
+		tuplizerMapping = new EntityEntityModeToTuplizerMapping( persistentClass, this );
+	}
+
+	private ValueInclusion determineInsertValueGenerationType(Property mappingProperty, StandardProperty runtimeProperty) {
+		if ( runtimeProperty.isInsertGenerated() ) {
+			return ValueInclusion.FULL;
+		}
+		else if ( mappingProperty.getValue() instanceof Component ) {
+			if ( hasPartialInsertComponentGeneration( ( Component ) mappingProperty.getValue() ) ) {
+				return ValueInclusion.PARTIAL;
+			}
+		}
+		return ValueInclusion.NONE;
+	}
+
+	private boolean hasPartialInsertComponentGeneration(Component component) {
+		Iterator subProperties = component.getPropertyIterator();
+		while ( subProperties.hasNext() ) {
+			Property prop = ( Property ) subProperties.next();
+			if ( prop.getGeneration() == PropertyGeneration.ALWAYS || prop.getGeneration() == PropertyGeneration.INSERT ) {
+				return true;
+			}
+			else if ( prop.getValue() instanceof Component ) {
+				if ( hasPartialInsertComponentGeneration( ( Component ) prop.getValue() ) ) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	private ValueInclusion determineUpdateValueGenerationType(Property mappingProperty, StandardProperty runtimeProperty) {
+		if ( runtimeProperty.isUpdateGenerated() ) {
+			return ValueInclusion.FULL;
+		}
+		else if ( mappingProperty.getValue() instanceof Component ) {
+			if ( hasPartialUpdateComponentGeneration( ( Component ) mappingProperty.getValue() ) ) {
+				return ValueInclusion.PARTIAL;
+			}
+		}
+		return ValueInclusion.NONE;
+	}
+
+	private boolean hasPartialUpdateComponentGeneration(Component component) {
+		Iterator subProperties = component.getPropertyIterator();
+		while ( subProperties.hasNext() ) {
+			Property prop = ( Property ) subProperties.next();
+			if ( prop.getGeneration() == PropertyGeneration.ALWAYS ) {
+				return true;
+			}
+			else if ( prop.getValue() instanceof Component ) {
+				if ( hasPartialUpdateComponentGeneration( ( Component ) prop.getValue() ) ) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	private void mapPropertyToIndex(Property prop, int i) {
+		propertyIndexes.put( prop.getName(), new Integer(i) );
+		if ( prop.getValue() instanceof Component ) {
+			Iterator iter = ( (Component) prop.getValue() ).getPropertyIterator();
+			while ( iter.hasNext() ) {
+				Property subprop = (Property) iter.next();
+				propertyIndexes.put(
+						prop.getName() + '.' + subprop.getName(),
+						new Integer(i)
+					);
+			}
+		}
+	}
+
+	public int[] getNaturalIdentifierProperties() {
+		return naturalIdPropertyNumbers;
+	}
+
+	public boolean hasNaturalIdentifier() {
+		return naturalIdPropertyNumbers!=null;
+	}
+
+	public Set getSubclassEntityNames() {
+		return subclassEntityNames;
+	}
+
+	private boolean indicatesCollection(Type type) {
+		if ( type.isCollectionType() ) {
+			return true;
+		}
+		else if ( type.isComponentType() ) {
+			Type[] subtypes = ( ( AbstractComponentType ) type ).getSubtypes();
+			for ( int i = 0; i < subtypes.length; i++ ) {
+				if ( indicatesCollection( subtypes[i] ) ) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	public SessionFactoryImplementor getSessionFactory() {
+		return sessionFactory;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public String getRootName() {
+		return rootName;
+	}
+
+	public EntityType getEntityType() {
+		return entityType;
+	}
+
+	public IdentifierProperty getIdentifierProperty() {
+		return identifierProperty;
+	}
+
+	public int getPropertySpan() {
+		return propertySpan;
+	}
+
+	public int getVersionPropertyIndex() {
+		return versionPropertyIndex;
+	}
+
+	public VersionProperty getVersionProperty() {
+		if ( NO_VERSION_INDX == versionPropertyIndex ) {
+			return null;
+		}
+		else {
+			return ( VersionProperty ) properties[ versionPropertyIndex ];
+		}
+	}
+
+	public StandardProperty[] getProperties() {
+		return properties;
+	}
+
+	public int getPropertyIndex(String propertyName) {
+		Integer index = getPropertyIndexOrNull(propertyName);
+		if ( index == null ) {
+			throw new HibernateException("Unable to resolve property: " + propertyName);
+		}
+		return index.intValue();
+	}
+
+	public Integer getPropertyIndexOrNull(String propertyName) {
+		return (Integer) propertyIndexes.get( propertyName );
+	}
+
+	public boolean hasCollections() {
+		return hasCollections;
+	}
+
+	public boolean hasMutableProperties() {
+		return hasMutableProperties;
+	}
+
+	public boolean hasNonIdentifierPropertyNamedId() {
+		return hasNonIdentifierPropertyNamedId;
+	}
+
+	public boolean hasLazyProperties() {
+		return hasLazyProperties;
+	}
+
+	public boolean hasCascades() {
+		return hasCascades;
+	}
+
+	public boolean isMutable() {
+		return mutable;
+	}
+
+	public boolean isSelectBeforeUpdate() {
+		return selectBeforeUpdate;
+	}
+
+	public boolean isDynamicUpdate() {
+		return dynamicUpdate;
+	}
+
+	public boolean isDynamicInsert() {
+		return dynamicInsert;
+	}
+
+	public int getOptimisticLockMode() {
+		return optimisticLockMode;
+	}
+
+	public boolean isPolymorphic() {
+		return polymorphic;
+	}
+
+	public String getSuperclass() {
+		return superclass;
+	}
+
+	public boolean isExplicitPolymorphism() {
+		return explicitPolymorphism;
+	}
+
+	public boolean isInherited() {
+		return inherited;
+	}
+
+	public boolean hasSubclasses() {
+		return hasSubclasses;
+	}
+
+	public boolean isLazy() {
+		return lazy;
+	}
+
+	public void setLazy(boolean lazy) {
+		this.lazy = lazy;
+	}
+
+	public boolean isVersioned() {
+		return versioned;
+	}
+
+	public boolean isAbstract() {
+		return isAbstract;
+	}
+
+	public String toString() {
+		return "EntityMetamodel(" + name + ':' + ArrayHelper.toString(properties) + ')';
+	}
+
+	// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	public String[] getPropertyNames() {
+		return propertyNames;
+	}
+
+	public Type[] getPropertyTypes() {
+		return propertyTypes;
+	}
+
+	public boolean[] getPropertyLaziness() {
+		return propertyLaziness;
+	}
+
+	public boolean[] getPropertyUpdateability() {
+		return propertyUpdateability;
+	}
+
+	public boolean[] getPropertyCheckability() {
+		return propertyCheckability;
+	}
+
+	public boolean[] getNonlazyPropertyUpdateability() {
+		return nonlazyPropertyUpdateability;
+	}
+
+	public boolean[] getPropertyInsertability() {
+		return propertyInsertability;
+	}
+
+	public ValueInclusion[] getPropertyInsertGenerationInclusions() {
+		return insertInclusions;
+	}
+
+	public ValueInclusion[] getPropertyUpdateGenerationInclusions() {
+		return updateInclusions;
+	}
+
+	public boolean[] getPropertyNullability() {
+		return propertyNullability;
+	}
+
+	public boolean[] getPropertyVersionability() {
+		return propertyVersionability;
+	}
+
+	public CascadeStyle[] getCascadeStyles() {
+		return cascadeStyles;
+	}
+
+	public boolean hasInsertGeneratedValues() {
+		return hasInsertGeneratedValues;
+	}
+
+	public boolean hasUpdateGeneratedValues() {
+		return hasUpdateGeneratedValues;
+	}
+
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,178 @@
+//$Id: EntityTuplizer.java 7516 2005-07-16 22:20:48Z oneovthafew $
+package org.hibernate.tuple.entity;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.tuple.Tuplizer;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * Defines further responsibilities reagarding tuplization based on
+ * a mapped entity.
+ * <p/>
+ * EntityTuplizer implementations should have the following constructor signature:
+ *      (org.hibernate.tuple.entity.EntityMetamodel, org.hibernate.mapping.PersistentClass)
+ *
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public interface EntityTuplizer extends Tuplizer {
+
+    /**
+     * Create an entity instance initialized with the given identifier.
+     *
+     * @param id The identifier value for the entity to be instantiated.
+     * @return The instantiated entity.
+     * @throws HibernateException
+     */
+	public Object instantiate(Serializable id) throws HibernateException;
+
+    /**
+     * Extract the identifier value from the given entity.
+     *
+     * @param entity The entity from which to extract the identifier value.
+     * @return The identifier value.
+     * @throws HibernateException If the entity does not define an identifier property, or an
+     * error occurrs accessing its value.
+     */
+	public Serializable getIdentifier(Object entity) throws HibernateException;
+
+    /**
+     * Inject the identifier value into the given entity.
+     * </p>
+     * Has no effect if the entity does not define an identifier property
+     *
+     * @param entity The entity to inject with the identifier value.
+     * @param id The value to be injected as the identifier.
+     * @throws HibernateException
+     */
+	public void setIdentifier(Object entity, Serializable id) throws HibernateException;
+
+	/**
+	 * Inject the given identifier and version into the entity, in order to
+	 * "roll back" to their original values.
+	 *
+	 * @param currentId The identifier value to inject into the entity.
+	 * @param currentVersion The version value to inject into the entity.
+	 */
+	public void resetIdentifier(Object entity, Serializable currentId, Object currentVersion);
+
+    /**
+     * Extract the value of the version property from the given entity.
+     *
+     * @param entity The entity from which to extract the version value.
+     * @return The value of the version property, or null if not versioned.
+     * @throws HibernateException
+     */
+	public Object getVersion(Object entity) throws HibernateException;
+
+	/**
+	 * Inject the value of a particular property.
+	 *
+	 * @param entity The entity into which to inject the value.
+	 * @param i The property's index.
+	 * @param value The property value to inject.
+	 * @throws HibernateException
+	 */
+	public void setPropertyValue(Object entity, int i, Object value) throws HibernateException;
+
+	/**
+	 * Inject the value of a particular property.
+	 *
+	 * @param entity The entity into which to inject the value.
+	 * @param propertyName The name of the property.
+	 * @param value The property value to inject.
+	 * @throws HibernateException
+	 */
+	public void setPropertyValue(Object entity, String propertyName, Object value) throws HibernateException;
+
+	/**
+	 * Extract the values of the insertable properties of the entity (including backrefs)
+	 *
+	 * @param entity The entity from which to extract.
+	 * @param mergeMap a map of instances being merged to merged instances
+	 * @param session The session in which the resuest is being made.
+	 * @return The insertable property values.
+	 * @throws HibernateException
+	 */
+	public Object[] getPropertyValuesToInsert(Object entity, Map mergeMap, SessionImplementor session)
+	throws HibernateException;
+
+	/**
+	 * Extract the value of a particular property from the given entity.
+	 *
+	 * @param entity The entity from which to extract the property value.
+	 * @param propertyName The name of the property for which to extract the value.
+	 * @return The current value of the given property on the given entity.
+	 * @throws HibernateException
+	 */
+	public Object getPropertyValue(Object entity, String propertyName) throws HibernateException;
+
+    /**
+     * Called just after the entities properties have been initialized.
+     *
+     * @param entity The entity being initialized.
+     * @param lazyPropertiesAreUnfetched Are defined lazy properties currently unfecthed
+     * @param session The session initializing this entity.
+     */
+	public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session);
+
+	/**
+	 * Does this entity, for this mode, present a possibility for proxying?
+	 *
+	 * @return True if this tuplizer can generate proxies for this entity.
+	 */
+	public boolean hasProxy();
+
+	/**
+	 * Generates an appropriate proxy representation of this entity for this
+	 * entity-mode.
+	 *
+	 * @param id The id of the instance for which to generate a proxy.
+	 * @param session The session to which the proxy should be bound.
+	 * @return The generate proxies.
+	 * @throws HibernateException Indicates an error generating the proxy.
+	 */
+	public Object createProxy(Serializable id, SessionImplementor session) throws HibernateException;
+
+	/**
+	 * Does the {@link #getMappedClass() class} managed by this tuplizer implement
+	 * the {@link org.hibernate.classic.Lifecycle} interface.
+	 *
+	 * @return True if the Lifecycle interface is implemented; false otherwise.
+	 */
+	public boolean isLifecycleImplementor();
+
+	/**
+	 * Does the {@link #getMappedClass() class} managed by this tuplizer implement
+	 * the {@link org.hibernate.classic.Validatable} interface.
+	 *
+	 * @return True if the Validatable interface is implemented; false otherwise.
+	 */
+	public boolean isValidatableImplementor();
+
+	// TODO: getConcreteProxyClass() is solely used (externally) to perform narrowProxy()
+	// would be great to fully encapsulate that narrowProxy() functionality within the
+	// Tuplizer, itself, with a Tuplizer.narrowProxy(..., PersistentContext) method
+	/**
+	 * Returns the java class to which generated proxies will be typed.
+	 *
+	 * @return The java class to which generated proxies will be typed
+	 */
+	public Class getConcreteProxyClass();
+	
+    /**
+     * Does the given entity instance have any currently uninitialized lazy properties?
+     *
+     * @param entity The entity to be check for uninitialized lazy properties.
+     * @return True if uninitialized lazy properties were found; false otherwise.
+     */
+	public boolean hasUninitializedLazyProperties(Object entity);
+	
+	/**
+	 * Is it an instrumented POJO?
+	 */
+	public boolean isInstrumented();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,284 @@
+// $Id: PojoEntityTuplizer.java 9210 2006-02-03 22:15:19Z steveebersole $
+package org.hibernate.tuple.entity;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.tuple.entity.AbstractEntityTuplizer;
+import org.hibernate.tuple.entity.EntityMetamodel;
+import org.hibernate.tuple.Instantiator;
+import org.hibernate.tuple.PojoInstantiator;
+import org.hibernate.bytecode.ReflectionOptimizer;
+import org.hibernate.cfg.Environment;
+import org.hibernate.classic.Lifecycle;
+import org.hibernate.classic.Validatable;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.intercept.FieldInterceptor;
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.Subclass;
+import org.hibernate.property.Getter;
+import org.hibernate.property.Setter;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.ProxyFactory;
+import org.hibernate.type.AbstractComponentType;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * An {@link EntityTuplizer} specific to the pojo entity mode.
+ *
+ * @author Steve Ebersole
+ * @author Gavin King
+ */
+public class PojoEntityTuplizer extends AbstractEntityTuplizer {
+
+	static final Log log = LogFactory.getLog( PojoEntityTuplizer.class );
+
+	private final Class mappedClass;
+	private final Class proxyInterface;
+	private final boolean lifecycleImplementor;
+	private final boolean validatableImplementor;
+	private final Set lazyPropertyNames = new HashSet();
+	private ReflectionOptimizer optimizer;
+
+	public PojoEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
+		super( entityMetamodel, mappedEntity );
+		this.mappedClass = mappedEntity.getMappedClass();
+		this.proxyInterface = mappedEntity.getProxyInterface();
+		this.lifecycleImplementor = Lifecycle.class.isAssignableFrom( mappedClass );
+		this.validatableImplementor = Validatable.class.isAssignableFrom( mappedClass );
+
+		Iterator iter = mappedEntity.getPropertyClosureIterator();
+		while ( iter.hasNext() ) {
+			Property property = (Property) iter.next();
+			if ( property.isLazy() ) {
+				lazyPropertyNames.add( property.getName() );
+			}
+		}
+
+		String[] getterNames = new String[propertySpan];
+		String[] setterNames = new String[propertySpan];
+		Class[] propTypes = new Class[propertySpan];
+		for ( int i = 0; i < propertySpan; i++ ) {
+			getterNames[i] = getters[i].getMethodName();
+			setterNames[i] = setters[i].getMethodName();
+			propTypes[i] = getters[i].getReturnType();
+		}
+
+		if ( hasCustomAccessors || !Environment.useReflectionOptimizer() ) {
+			optimizer = null;
+		}
+		else {
+			// todo : YUCK!!!
+			optimizer = Environment.getBytecodeProvider().getReflectionOptimizer( mappedClass, getterNames, setterNames, propTypes );
+//			optimizer = getFactory().getSettings().getBytecodeProvider().getReflectionOptimizer(
+//					mappedClass, getterNames, setterNames, propTypes
+//			);
+		}
+	
+	}
+
+	protected ProxyFactory buildProxyFactory(PersistentClass persistentClass, Getter idGetter, Setter idSetter) {
+		// determine the id getter and setter methods from the proxy interface (if any)
+        // determine all interfaces needed by the resulting proxy
+		HashSet proxyInterfaces = new HashSet();
+		proxyInterfaces.add( HibernateProxy.class );
+		
+		Class mappedClass = persistentClass.getMappedClass();
+		Class proxyInterface = persistentClass.getProxyInterface();
+
+		if ( proxyInterface!=null && !mappedClass.equals( proxyInterface ) ) {
+			if ( !proxyInterface.isInterface() ) {
+				throw new MappingException(
+				        "proxy must be either an interface, or the class itself: " + 
+				        getEntityName()
+					);
+			}
+			proxyInterfaces.add( proxyInterface );
+		}
+
+		if ( mappedClass.isInterface() ) {
+			proxyInterfaces.add( mappedClass );
+		}
+
+		Iterator iter = persistentClass.getSubclassIterator();
+		while ( iter.hasNext() ) {
+			Subclass subclass = ( Subclass ) iter.next();
+			Class subclassProxy = subclass.getProxyInterface();
+			Class subclassClass = subclass.getMappedClass();
+			if ( subclassProxy!=null && !subclassClass.equals( subclassProxy ) ) {
+				if ( !proxyInterface.isInterface() ) {
+					throw new MappingException(
+					        "proxy must be either an interface, or the class itself: " + 
+					        subclass.getEntityName()
+					);
+				}
+				proxyInterfaces.add( subclassProxy );
+			}
+		}
+
+		Iterator properties = persistentClass.getPropertyIterator();
+		Class clazz = persistentClass.getMappedClass();
+		while ( properties.hasNext() ) {
+			Property property = (Property) properties.next();
+			Method method = property.getGetter(clazz).getMethod();
+			if ( method != null && Modifier.isFinal( method.getModifiers() ) ) {
+				log.error(
+						"Getters of lazy classes cannot be final: " + persistentClass.getEntityName() + 
+						"." + property.getName() 
+					);
+			}
+			method = property.getSetter(clazz).getMethod();
+            if ( method != null && Modifier.isFinal( method.getModifiers() ) ) {
+				log.error(
+						"Setters of lazy classes cannot be final: " + persistentClass.getEntityName() + 
+						"." + property.getName() 
+					);
+			}
+		}
+
+		Method idGetterMethod = idGetter==null ? null : idGetter.getMethod();
+		Method idSetterMethod = idSetter==null ? null : idSetter.getMethod();
+
+		Method proxyGetIdentifierMethod = idGetterMethod==null || proxyInterface==null ? 
+				null :
+		        ReflectHelper.getMethod(proxyInterface, idGetterMethod);
+		Method proxySetIdentifierMethod = idSetterMethod==null || proxyInterface==null  ? 
+				null :
+		        ReflectHelper.getMethod(proxyInterface, idSetterMethod);
+
+		ProxyFactory pf = buildProxyFactoryInternal( persistentClass, idGetter, idSetter );
+		try {
+			pf.postInstantiate(
+					getEntityName(),
+					mappedClass,
+					proxyInterfaces,
+					proxyGetIdentifierMethod,
+					proxySetIdentifierMethod,
+					persistentClass.hasEmbeddedIdentifier() ?
+			                (AbstractComponentType) persistentClass.getIdentifier().getType() :
+			                null
+			);
+		}
+		catch ( HibernateException he ) {
+			log.warn( "could not create proxy factory for:" + getEntityName(), he );
+			pf = null;
+		}
+		return pf;
+	}
+
+	protected ProxyFactory buildProxyFactoryInternal(PersistentClass persistentClass, Getter idGetter, Setter idSetter) {
+		// TODO : YUCK!!!  finx after HHH-1907 is complete
+		return Environment.getBytecodeProvider().getProxyFactoryFactory().buildProxyFactory();
+//		return getFactory().getSettings().getBytecodeProvider().getProxyFactoryFactory().buildProxyFactory();
+	}
+
+	protected Instantiator buildInstantiator(PersistentClass persistentClass) {
+		if ( optimizer == null ) {
+			return new PojoInstantiator( persistentClass, null );
+		}
+		else {
+			return new PojoInstantiator( persistentClass, optimizer.getInstantiationOptimizer() );
+		}
+	}
+
+	public void setPropertyValues(Object entity, Object[] values) throws HibernateException {
+		if ( !getEntityMetamodel().hasLazyProperties() && optimizer != null && optimizer.getAccessOptimizer() != null ) {
+			setPropertyValuesWithOptimizer( entity, values );
+		}
+		else {
+			super.setPropertyValues( entity, values );
+		}
+	}
+
+	public Object[] getPropertyValues(Object entity) throws HibernateException {
+		if ( shouldGetAllProperties( entity ) && optimizer != null && optimizer.getAccessOptimizer() != null ) {
+			return getPropertyValuesWithOptimizer( entity );
+		}
+		else {
+			return super.getPropertyValues( entity );
+		}
+	}
+
+	public Object[] getPropertyValuesToInsert(Object entity, Map mergeMap, SessionImplementor session) throws HibernateException {
+		if ( shouldGetAllProperties( entity ) && optimizer != null && optimizer.getAccessOptimizer() != null ) {
+			return getPropertyValuesWithOptimizer( entity );
+		}
+		else {
+			return super.getPropertyValuesToInsert( entity, mergeMap, session );
+		}
+	}
+
+	protected void setPropertyValuesWithOptimizer(Object object, Object[] values) {
+		optimizer.getAccessOptimizer().setPropertyValues( object, values );
+	}
+
+	protected Object[] getPropertyValuesWithOptimizer(Object object) {
+		return optimizer.getAccessOptimizer().getPropertyValues( object );
+	}
+
+	public EntityMode getEntityMode() {
+		return EntityMode.POJO;
+	}
+
+	public Class getMappedClass() {
+		return mappedClass;
+	}
+
+	public boolean isLifecycleImplementor() {
+		return lifecycleImplementor;
+	}
+
+	public boolean isValidatableImplementor() {
+		return validatableImplementor;
+	}
+
+	protected Getter buildPropertyGetter(Property mappedProperty, PersistentClass mappedEntity) {
+		return mappedProperty.getGetter( mappedEntity.getMappedClass() );
+	}
+
+	protected Setter buildPropertySetter(Property mappedProperty, PersistentClass mappedEntity) {
+		return mappedProperty.getSetter( mappedEntity.getMappedClass() );
+	}
+
+	public Class getConcreteProxyClass() {
+		return proxyInterface;
+	}
+
+    //TODO: need to make the majority of this functionality into a top-level support class for custom impl support
+
+	public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) {
+		if ( isInstrumented() ) {
+			Set lazyProps = lazyPropertiesAreUnfetched && getEntityMetamodel().hasLazyProperties() ?
+					lazyPropertyNames : null;
+			//TODO: if we support multiple fetch groups, we would need
+			//      to clone the set of lazy properties!
+			FieldInterceptionHelper.injectFieldInterceptor( entity, getEntityName(), lazyProps, session );
+		}
+	}
+
+	public boolean hasUninitializedLazyProperties(Object entity) {
+		if ( getEntityMetamodel().hasLazyProperties() ) {
+			FieldInterceptor callback = FieldInterceptionHelper.extractFieldInterceptor( entity );
+			return callback != null && !callback.isInitialized();
+		}
+		else {
+			return false;
+		}
+	}
+
+	public boolean isInstrumented() {
+		return FieldInterceptionHelper.isInstrumented( getMappedClass() );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package defines a runtime metamodel for entities at
+	the object level and abstracts the differences between
+	the various entity modes. It is unaware of mappings to
+	the database. 
+</p>
+<p>
+    (This package is still undergoing maturation and will change 
+    over the next few months.)
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/tuple/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractBynaryType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractBynaryType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractBynaryType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,166 @@
+//$Id: $
+package org.hibernate.type;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.ResultSet;
+import java.sql.Types;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Comparator;
+
+import org.hibernate.HibernateException;
+import org.hibernate.EntityMode;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.cfg.Environment;
+
+/**
+ * Logic to bind stream of byte into a VARBINARY
+ *
+ * @author Gavin King
+ * @author Emmanuel Bernard
+ */
+public abstract class AbstractBynaryType extends MutableType implements VersionType, Comparator {
+
+	/**
+	 * Convert the byte[] into the expected object type
+	 */
+	abstract protected Object toExternalFormat(byte[] bytes);
+
+	/**
+	 * Convert the object into the internal byte[] representation
+	 */
+	abstract protected byte[] toInternalFormat(Object bytes);
+
+	public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
+		byte[] internalValue = toInternalFormat( value );
+		if ( Environment.useStreamsForBinary() ) {
+			st.setBinaryStream( index, new ByteArrayInputStream( internalValue ), internalValue.length );
+		}
+		else {
+			st.setBytes( index, internalValue );
+		}
+	}
+
+	public Object get(ResultSet rs, String name) throws HibernateException, SQLException {
+
+		if ( Environment.useStreamsForBinary() ) {
+
+			InputStream inputStream = rs.getBinaryStream(name);
+
+			if (inputStream==null) return toExternalFormat( null ); // is this really necessary?
+
+			ByteArrayOutputStream outputStream = new ByteArrayOutputStream(2048);
+			byte[] buffer = new byte[2048];
+
+			try {
+				while (true) {
+					int amountRead = inputStream.read(buffer);
+					if (amountRead == -1) {
+						break;
+					}
+					outputStream.write(buffer, 0, amountRead);
+				}
+
+				inputStream.close();
+				outputStream.close();
+			}
+			catch (IOException ioe) {
+				throw new HibernateException( "IOException occurred reading a binary value", ioe );
+			}
+
+			return toExternalFormat( outputStream.toByteArray() );
+
+		}
+		else {
+			return toExternalFormat( rs.getBytes(name) );
+		}
+	}
+
+	public int sqlType() {
+		return Types.VARBINARY;
+	}
+
+	// VersionType impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	//      Note : simply returns null for seed() and next() as the only known
+	//      application of binary types for versioning is for use with the
+	//      TIMESTAMP datatype supported by Sybase and SQL Server, which
+	//      are completely db-generated values...
+	public Object seed(SessionImplementor session) {
+		return null;
+	}
+
+	public Object next(Object current, SessionImplementor session) {
+		return current;
+	}
+
+	public Comparator getComparator() {
+		return this;
+	}
+
+	public int compare(Object o1, Object o2) {
+		return compare( o1, o2, null );
+	}
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean isEqual(Object x, Object y) {
+		return x==y || ( x!=null && y!=null && java.util.Arrays.equals( toInternalFormat(x), toInternalFormat(y) ) );
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode) {
+		byte[] bytes = toInternalFormat(x);
+		int hashCode = 1;
+		for ( int j=0; j<bytes.length; j++ ) {
+			hashCode = 31 * hashCode + bytes[j];
+		}
+		return hashCode;
+	}
+
+	public int compare(Object x, Object y, EntityMode entityMode) {
+		byte[] xbytes = toInternalFormat(x);
+		byte[] ybytes = toInternalFormat(y);
+		if ( xbytes.length < ybytes.length ) return -1;
+		if ( xbytes.length > ybytes.length ) return 1;
+		for ( int i=0; i<xbytes.length; i++ ) {
+			if ( xbytes[i] < ybytes[i] ) return -1;
+			if ( xbytes[i] > ybytes[i] ) return 1;
+		}
+		return 0;
+	}
+
+	public abstract String getName();
+
+	public String toString(Object val) {
+		byte[] bytes = toInternalFormat(val);
+		StringBuffer buf = new StringBuffer();
+		for ( int i=0; i<bytes.length; i++ ) {
+			String hexStr = Integer.toHexString( bytes[i] - Byte.MIN_VALUE );
+			if ( hexStr.length()==1 ) buf.append('0');
+			buf.append(hexStr);
+		}
+		return buf.toString();
+	}
+
+	public Object deepCopyNotNull(Object value) {
+		byte[] bytes = toInternalFormat(value);
+		byte[] result = new byte[bytes.length];
+		System.arraycopy(bytes, 0, result, 0, bytes.length);
+		return toExternalFormat(result);
+	}
+
+	public Object fromStringValue(String xml) throws HibernateException {
+		if (xml == null)
+			return null;
+		if (xml.length() % 2 != 0)
+			throw new IllegalArgumentException("The string is not a valid xml representation of a binary content.");
+		byte[] bytes = new byte[xml.length() / 2];
+		for (int i = 0; i < bytes.length; i++) {
+			String hexStr = xml.substring(i * 2, (i + 1) * 2);
+			bytes[i] = (byte) (Integer.parseInt(hexStr, 16) + Byte.MIN_VALUE);
+		}
+		return toExternalFormat(bytes);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractCharArrayType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractCharArrayType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractCharArrayType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,96 @@
+//$Id: $
+package org.hibernate.type;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.Types;
+import java.io.Reader;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.CharArrayReader;
+
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * Logic to bind stream of char into a VARCHAR
+ *
+ * @author Emmanuel Bernard
+ */
+public abstract class AbstractCharArrayType extends MutableType {
+
+	/**
+	 * Convert the char[] into the expected object type
+	 */
+	abstract protected Object toExternalFormat(char[] chars);
+
+	/**
+	 * Convert the object into the internal char[] representation
+	 */
+	abstract protected char[] toInternalFormat(Object chars);
+
+	public Object get(ResultSet rs, String name) throws SQLException {
+		Reader stream = rs.getCharacterStream(name);
+		if ( stream == null ) return toExternalFormat( null );
+		CharArrayWriter writer = new CharArrayWriter();
+		for(;;) {
+			try {
+				int c = stream.read();
+				if ( c == -1) return toExternalFormat( writer.toCharArray() );
+				writer.write( c );
+			}
+			catch (IOException e) {
+				throw new HibernateException("Unable to read character stream from rs");
+			}
+		}
+	}
+
+	public abstract Class getReturnedClass();
+
+	public void set(PreparedStatement st, Object value, int index) throws SQLException {
+		char[] chars = toInternalFormat( value );
+		st.setCharacterStream(index, new CharArrayReader(chars), chars.length);
+	}
+
+	public int sqlType() {
+		return Types.VARCHAR;
+	}
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+
+		return '\'' + new String( toInternalFormat( value ) ) + '\'';
+	}
+
+	public Object stringToObject(String xml) throws Exception {
+		if (xml == null) return toExternalFormat( null );
+		int length = xml.length();
+		char[] chars = new char[length];
+		for (int index = 0 ; index < length ; index++ ) {
+			chars[index] = xml.charAt( index );
+		}
+		return toExternalFormat( chars );
+	}
+
+	public String toString(Object value) {
+		if (value == null) return null;
+		return new String( toInternalFormat( value ) );
+	}
+
+	public Object fromStringValue(String xml) {
+		if (xml == null) return null;
+		int length = xml.length();
+		char[] chars = new char[length];
+		for (int index = 0 ; index < length ; index++ ) {
+			chars[index] = xml.charAt( index );
+		}
+		return toExternalFormat( chars );
+	}
+
+	protected Object deepCopyNotNull(Object value) throws HibernateException {
+		char[] chars = toInternalFormat(value);
+		char[] result = new char[chars.length];
+		System.arraycopy(chars, 0, result, 0, chars.length);
+		return toExternalFormat(result);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractComponentType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractComponentType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractComponentType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+//$Id: AbstractComponentType.java 7670 2005-07-29 05:36:14Z oneovthafew $
+package org.hibernate.type;
+
+import java.lang.reflect.Method;
+
+import org.hibernate.EntityMode;
+import org.hibernate.FetchMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * Enables other Component-like types to hold collections and have cascades, etc.
+ *
+ * @see ComponentType
+ * @see AnyType
+ * @author Gavin King
+ */
+public interface AbstractComponentType extends Type {
+	/**
+	 * Get the types of the component properties
+	 */
+	public Type[] getSubtypes();
+	/**
+	 * Get the names of the component properties
+	 */
+	public String[] getPropertyNames();
+	/**
+	 * Optional operation
+	 * @return nullability of component properties
+	 */
+	public boolean[] getPropertyNullability();
+	/**
+	 * Get the values of the component properties of 
+	 * a component instance
+	 */
+	public Object[] getPropertyValues(Object component, SessionImplementor session) throws HibernateException;
+	/**
+	 * Optional operation
+	 */
+	public Object[] getPropertyValues(Object component, EntityMode entityMode) throws HibernateException;
+	/**
+	 * Optional operation
+	 */
+	public void setPropertyValues(Object component, Object[] values, EntityMode entityMode) throws HibernateException;
+	public Object getPropertyValue(Object component, int i, SessionImplementor session) throws HibernateException;
+	//public Object instantiate(Object parent, SessionImplementor session) throws HibernateException;
+	public CascadeStyle getCascadeStyle(int i);
+	public FetchMode getFetchMode(int i);
+	public boolean isMethodOf(Method method);
+	public boolean isEmbedded();
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/AbstractType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,164 @@
+//$Id: AbstractType.java 7793 2005-08-10 05:06:40Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map;
+
+import org.dom4j.Element;
+import org.dom4j.Node;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.util.EqualsHelper;
+
+/**
+ * Abstract superclass of the built in Type hierarchy.
+ * @author Gavin King
+ */
+public abstract class AbstractType implements Type {
+
+	public boolean isAssociationType() {
+		return false;
+	}
+
+	public boolean isCollectionType() {
+		return false;
+	}
+
+	public boolean isComponentType() {
+		return false;
+	}
+
+	public boolean isEntityType() {
+		return false;
+	}
+	
+	public boolean isXMLElement() {
+		return false;
+	}
+
+	public int compare(Object x, Object y, EntityMode entityMode) {
+		return ( (Comparable) x ).compareTo(y);
+	}
+
+	public Serializable disassemble(Object value, SessionImplementor session, Object owner)
+	throws HibernateException {
+
+		if (value==null) {
+			return null;
+		}
+		else {
+			return (Serializable) deepCopy( value, session.getEntityMode(), session.getFactory() );
+		}
+	}
+
+	public Object assemble(Serializable cached, SessionImplementor session, Object owner) 
+	throws HibernateException {
+		if ( cached==null ) {
+			return null;
+		}
+		else {
+			return deepCopy( cached, session.getEntityMode(), session.getFactory() );
+		}
+	}
+
+	public boolean isDirty(Object old, Object current, SessionImplementor session) 
+	throws HibernateException {
+		return !isSame( old, current, session.getEntityMode() );
+	}
+
+	public Object hydrate(
+		ResultSet rs,
+		String[] names,
+		SessionImplementor session,
+		Object owner)
+	throws HibernateException, SQLException {
+		// TODO: this is very suboptimal for some subclasses (namely components),
+		// since it does not take advantage of two-phase-load
+		return nullSafeGet(rs, names, session, owner);
+	}
+
+	public Object resolve(Object value, SessionImplementor session, Object owner)
+	throws HibernateException {
+		return value;
+	}
+
+	public Object semiResolve(Object value, SessionImplementor session, Object owner) 
+	throws HibernateException {
+		return value;
+	}
+	
+	public boolean isAnyType() {
+		return false;
+	}
+
+	public boolean isModified(Object old, Object current, boolean[] checkable, SessionImplementor session)
+	throws HibernateException {
+		return isDirty(old, current, session);
+	}
+	
+	public boolean isSame(Object x, Object y, EntityMode entityMode) throws HibernateException {
+		return isEqual(x, y, entityMode);
+	}
+
+	public boolean isEqual(Object x, Object y, EntityMode entityMode) {
+		return EqualsHelper.equals(x, y);
+	}
+	
+	public int getHashCode(Object x, EntityMode entityMode) {
+		return x.hashCode();
+	}
+
+	public boolean isEqual(Object x, Object y, EntityMode entityMode, SessionFactoryImplementor factory) {
+		return isEqual(x, y, entityMode);
+	}
+	
+	public int getHashCode(Object x, EntityMode entityMode, SessionFactoryImplementor factory) {
+		return getHashCode(x, entityMode);
+	}
+	
+	protected static void replaceNode(Node container, Element value) {
+		if ( container!=value ) { //not really necessary, I guess...
+			Element parent = container.getParent();
+			container.detach();
+			value.setName( container.getName() );
+			value.detach();
+			parent.add(value);
+		}
+	}
+	
+	public Type getSemiResolvedType(SessionFactoryImplementor factory) {
+		return this;
+	}
+
+	public Object replace(
+			Object original, 
+			Object target, 
+			SessionImplementor session, 
+			Object owner, 
+			Map copyCache, 
+			ForeignKeyDirection foreignKeyDirection) 
+	throws HibernateException {
+		boolean include;
+		if ( isAssociationType() ) {
+			AssociationType atype = (AssociationType) this;
+			include = atype.getForeignKeyDirection()==foreignKeyDirection;
+		}
+		else {
+			include = ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT==foreignKeyDirection;
+		}
+		return include ? replace(original, target, session, owner, copyCache) : target;
+	}
+
+	public void beforeAssemble(Serializable cached, SessionImplementor session) {}
+
+	/*public Object copy(Object original, Object target, SessionImplementor session, Object owner, Map copyCache)
+	throws HibernateException {
+		if (original==null) return null;
+		return assemble( disassemble(original, session), session, owner );
+	}*/
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/AdaptedImmutableType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/AdaptedImmutableType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/AdaptedImmutableType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,65 @@
+//$Id: AdaptedImmutableType.java 7238 2005-06-20 09:17:00Z oneovthafew $
+package org.hibernate.type;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+
+/**
+ * Optimize a mutable type, if the user promises not to mutable the
+ * instances.
+ * 
+ * @author Gavin King
+ */
+public class AdaptedImmutableType extends ImmutableType {
+	
+	private final NullableType mutableType;
+
+	public AdaptedImmutableType(NullableType mutableType) {
+		this.mutableType = mutableType;
+	}
+
+	public Object get(ResultSet rs, String name) throws HibernateException, SQLException {
+		return mutableType.get(rs, name);
+	}
+
+	public void set(PreparedStatement st, Object value, int index) throws HibernateException,
+			SQLException {
+		mutableType.set(st, value, index);
+	}
+
+	public int sqlType() {
+		return mutableType.sqlType();
+	}
+
+	public String toString(Object value) throws HibernateException {
+		return mutableType.toString(value);
+	}
+
+	public Object fromStringValue(String xml) throws HibernateException {
+		return mutableType.fromStringValue(xml);
+	}
+
+	public Class getReturnedClass() {
+		return mutableType.getReturnedClass();
+	}
+
+	public String getName() {
+		return "imm_" + mutableType.getName();
+	}
+	
+	public boolean isEqual(Object x, Object y) {
+		return mutableType.isEqual(x, y);
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode) {
+		return mutableType.getHashCode(x, entityMode);
+	}
+	
+	public int compare(Object x, Object y, EntityMode entityMode) {
+		return mutableType.compare(x, y, entityMode);
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/type/AdaptedImmutableType.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/AnyType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/AnyType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/AnyType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,369 @@
+//$Id: AnyType.java 7670 2005-07-29 05:36:14Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Map;
+
+import org.dom4j.Node;
+import org.hibernate.EntityMode;
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.TransientObjectException;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.ForeignKeys;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.proxy.HibernateProxyHelper;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * Handles "any" mappings and the old deprecated "object" type
+ * @author Gavin King
+ */
+public class AnyType extends AbstractType implements AbstractComponentType, AssociationType {
+
+	private final Type identifierType;
+	private final Type metaType;
+
+	public AnyType(Type metaType, Type identifierType) {
+		this.identifierType = identifierType;
+		this.metaType = metaType;
+	}
+
+	public AnyType() {
+		this(Hibernate.STRING, Hibernate.SERIALIZABLE);
+	}
+
+	public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory)
+	throws HibernateException {
+		return value;
+	}
+	
+	public boolean isMethodOf(Method method) {
+		return false;
+	}
+
+	public boolean isSame(Object x, Object y, EntityMode entityMode) throws HibernateException {
+		return x==y;
+	}
+
+	public int compare(Object x, Object y, EntityMode entityMode) {
+		return 0; //TODO: entities CAN be compared, by PK and entity name, fix this!
+	}
+
+	public int getColumnSpan(Mapping session)
+	throws MappingException {
+		return 2;
+	}
+
+	public String getName() {
+		return "object";
+	}
+
+	public boolean isMutable() {
+		return false;
+	}
+
+	public Object nullSafeGet(ResultSet rs,	String name, SessionImplementor session, Object owner)
+	throws HibernateException, SQLException {
+
+		throw new UnsupportedOperationException("object is a multicolumn type");
+	}
+
+	public Object nullSafeGet(ResultSet rs,	String[] names,	SessionImplementor session,	Object owner)
+	throws HibernateException, SQLException {
+		return resolveAny(
+				(String) metaType.nullSafeGet(rs, names[0], session, owner),
+				(Serializable) identifierType.nullSafeGet(rs, names[1], session, owner),
+				session
+			);
+	}
+
+	public Object hydrate(ResultSet rs,	String[] names,	SessionImplementor session,	Object owner)
+	throws HibernateException, SQLException {
+		String entityName = (String) metaType.nullSafeGet(rs, names[0], session, owner);
+		Serializable id = (Serializable) identifierType.nullSafeGet(rs, names[1], session, owner);
+		return new ObjectTypeCacheEntry(entityName, id);
+	}
+
+	public Object resolve(Object value, SessionImplementor session, Object owner)
+	throws HibernateException {
+		ObjectTypeCacheEntry holder = (ObjectTypeCacheEntry) value;
+		return resolveAny(holder.entityName, holder.id, session);
+	}
+
+	public Object semiResolve(Object value, SessionImplementor session, Object owner)
+	throws HibernateException {
+		throw new UnsupportedOperationException("any mappings may not form part of a property-ref");
+	}
+	
+	private Object resolveAny(String entityName, Serializable id, SessionImplementor session)
+	throws HibernateException {
+		return entityName==null || id==null ?
+				null : session.internalLoad( entityName, id, false, false );
+	}
+
+	public void nullSafeSet(PreparedStatement st, Object value,	int index, SessionImplementor session)
+	throws HibernateException, SQLException {
+		nullSafeSet(st, value, index, null, session);
+	}
+	
+	public void nullSafeSet(PreparedStatement st, Object value,	int index, boolean[] settable, SessionImplementor session)
+	throws HibernateException, SQLException {
+
+		Serializable id;
+		String entityName;
+		if (value==null) {
+			id=null;
+			entityName=null;
+		}
+		else {
+			entityName = session.bestGuessEntityName(value);
+			id = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, value, session);
+		}
+		
+		// metaType is assumed to be single-column type
+		if ( settable==null || settable[0] ) {
+			metaType.nullSafeSet(st, entityName, index, session);
+		}
+		if (settable==null) {
+			identifierType.nullSafeSet(st, id, index+1, session);
+		}
+		else {
+			boolean[] idsettable = new boolean[ settable.length-1 ];
+			System.arraycopy(settable, 1, idsettable, 0, idsettable.length);
+			identifierType.nullSafeSet(st, id, index+1, idsettable, session);
+		}
+	}
+
+	public Class getReturnedClass() {
+		return Object.class;
+	}
+
+	public int[] sqlTypes(Mapping mapping) throws MappingException {
+		return ArrayHelper.join(
+				metaType.sqlTypes(mapping),
+				identifierType.sqlTypes(mapping)
+			);
+	}
+
+	public void setToXMLNode(Node xml, Object value, SessionFactoryImplementor factory) {
+		throw new UnsupportedOperationException("any types cannot be stringified");
+	}
+
+	public String toLoggableString(Object value, SessionFactoryImplementor factory) 
+	throws HibernateException {
+		//TODO: terrible implementation!
+		return value==null ?
+				"null" :
+				Hibernate.entity( HibernateProxyHelper.getClassWithoutInitializingProxy(value) )
+						.toLoggableString(value, factory);
+	}
+
+	public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException {
+		throw new UnsupportedOperationException(); //TODO: is this right??
+	}
+
+	public static final class ObjectTypeCacheEntry implements Serializable {
+		String entityName;
+		Serializable id;
+		ObjectTypeCacheEntry(String entityName, Serializable id) {
+			this.entityName = entityName;
+			this.id = id;
+		}
+	}
+
+	public Object assemble(
+		Serializable cached,
+		SessionImplementor session,
+		Object owner)
+	throws HibernateException {
+
+		ObjectTypeCacheEntry e = (ObjectTypeCacheEntry) cached;
+		return e==null ? null : session.internalLoad(e.entityName, e.id, false, false);
+	}
+
+	public Serializable disassemble(Object value, SessionImplementor session, Object owner)
+	throws HibernateException {
+		return value==null ?
+			null :
+			new ObjectTypeCacheEntry(
+						session.bestGuessEntityName(value),
+						ForeignKeys.getEntityIdentifierIfNotUnsaved( 
+								session.bestGuessEntityName(value), value, session 
+							)
+					);
+	}
+
+	public boolean isAnyType() {
+		return true;
+	}
+
+	public Object replace(
+			Object original, 
+			Object target,
+			SessionImplementor session, 
+			Object owner, 
+			Map copyCache)
+	throws HibernateException {
+		if (original==null) {
+			return null;
+		}
+		else {
+			String entityName = session.bestGuessEntityName(original);
+			Serializable id = ForeignKeys.getEntityIdentifierIfNotUnsaved( 
+					entityName, 
+					original, 
+					session 
+				);
+			return session.internalLoad( 
+					entityName, 
+					id, 
+					false, 
+					false
+				);
+		}
+	}
+	public CascadeStyle getCascadeStyle(int i) {
+		return CascadeStyle.NONE;
+	}
+
+	public FetchMode getFetchMode(int i) {
+		return FetchMode.SELECT;
+	}
+
+	private static final String[] PROPERTY_NAMES = new String[] { "class", "id" };
+
+	public String[] getPropertyNames() {
+		return PROPERTY_NAMES;
+	}
+
+	public Object getPropertyValue(Object component, int i, SessionImplementor session)
+		throws HibernateException {
+
+		return i==0 ?
+				session.bestGuessEntityName(component) :
+				getIdentifier(component, session);
+	}
+
+	public Object[] getPropertyValues(Object component, SessionImplementor session)
+		throws HibernateException {
+
+		return new Object[] { session.bestGuessEntityName(component), getIdentifier(component, session) };
+	}
+
+	private Serializable getIdentifier(Object value, SessionImplementor session) throws HibernateException {
+		try {
+			return ForeignKeys.getEntityIdentifierIfNotUnsaved( session.bestGuessEntityName(value), value, session );
+		}
+		catch (TransientObjectException toe) {
+			return null;
+		}
+	}
+
+	public Type[] getSubtypes() {
+		return new Type[] { metaType, identifierType };
+	}
+
+	public void setPropertyValues(Object component, Object[] values, EntityMode entityMode)
+		throws HibernateException {
+
+		throw new UnsupportedOperationException();
+
+	}
+
+	public Object[] getPropertyValues(Object component, EntityMode entityMode) {
+		throw new UnsupportedOperationException();
+	}
+
+	public boolean isComponentType() {
+		return true;
+	}
+
+	public ForeignKeyDirection getForeignKeyDirection() {
+		//return AssociationType.FOREIGN_KEY_TO_PARENT; //this is better but causes a transient object exception...
+		return ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT;
+	}
+
+	public boolean isAssociationType() {
+		return true;
+	}
+
+	public boolean useLHSPrimaryKey() {
+		return false;
+	}
+
+	public Joinable getAssociatedJoinable(SessionFactoryImplementor factory) {
+		throw new UnsupportedOperationException("any types do not have a unique referenced persister");
+	}
+
+	public boolean isModified(Object old, Object current, boolean[] checkable, SessionImplementor session)
+	throws HibernateException {
+		if (current==null) return old!=null;
+		if (old==null) return current!=null;
+		ObjectTypeCacheEntry holder = (ObjectTypeCacheEntry) old;
+		boolean[] idcheckable = new boolean[checkable.length-1];
+		System.arraycopy(checkable, 1, idcheckable, 0, idcheckable.length);
+		return ( checkable[0] && !holder.entityName.equals( session.bestGuessEntityName(current) ) ) ||
+				identifierType.isModified(holder.id, getIdentifier(current, session), idcheckable, session);
+	}
+
+	public String getAssociatedEntityName(SessionFactoryImplementor factory)
+		throws MappingException {
+		throw new UnsupportedOperationException("any types do not have a unique referenced persister");
+	}
+	
+	public boolean[] getPropertyNullability() {
+		return null;
+	}
+
+	public String getOnCondition(String alias, SessionFactoryImplementor factory, Map enabledFilters)
+	throws MappingException {
+		throw new UnsupportedOperationException();
+	}
+	
+	public boolean isReferenceToPrimaryKey() {
+		return true;
+	}
+	
+	public String getRHSUniqueKeyPropertyName() {
+		return null;
+	}
+
+	public String getLHSPropertyName() {
+		return null;
+	}
+
+	public boolean isAlwaysDirtyChecked() {
+		return false;
+	}
+
+	public boolean isEmbeddedInXML() {
+		return false;
+	}
+	
+	public boolean[] toColumnNullness(Object value, Mapping mapping) {
+		boolean[] result = new boolean[ getColumnSpan(mapping) ];
+		if (value!=null) Arrays.fill(result, true);
+		return result;
+	}
+
+	public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session) 
+	throws HibernateException {
+		//TODO!!!
+		return isDirty(old, current, session);
+	}
+
+	public boolean isEmbedded() {
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/ArrayType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/ArrayType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/ArrayType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,121 @@
+//$Id: ArrayType.java 10086 2006-07-05 18:17:27Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentArrayHolder;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+
+/**
+ * A type for persistent arrays.
+ * @author Gavin King
+ */
+public class ArrayType extends CollectionType {
+
+	private final Class elementClass;
+	private final Class arrayClass;
+
+	public ArrayType(String role, String propertyRef, Class elementClass, boolean isEmbeddedInXML) {
+		super(role, propertyRef, isEmbeddedInXML);
+		this.elementClass = elementClass;
+		arrayClass = Array.newInstance(elementClass, 0).getClass();
+	}
+
+	public Class getReturnedClass() {
+		return arrayClass;
+	}
+
+	public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister, Serializable key) 
+	throws HibernateException {
+		return new PersistentArrayHolder(session, persister);
+	}
+
+	/**
+	 * Not defined for collections of primitive type
+	 */
+	public Iterator getElementsIterator(Object collection) {
+		return Arrays.asList( (Object[]) collection ).iterator();
+	}
+
+	public PersistentCollection wrap(SessionImplementor session, Object array) {
+		return new PersistentArrayHolder(session, array);
+	}
+
+	public boolean isArrayType() {
+		return true;
+	}
+
+	public String toLoggableString(Object value, SessionFactoryImplementor factory) throws HibernateException {
+		if ( value == null ) {
+			return "null";
+		}
+		int length = Array.getLength(value);
+		List list = new ArrayList(length);
+		Type elemType = getElementType(factory);
+		for ( int i=0; i<length; i++ ) {
+			list.add( elemType.toLoggableString( Array.get(value, i), factory ) );
+		}
+		return list.toString();
+	}
+	
+	public Object instantiateResult(Object original) {
+		return Array.newInstance( elementClass, Array.getLength(original) );
+	}
+
+	public Object replaceElements(
+		Object original,
+		Object target,
+		Object owner, 
+		Map copyCache, 
+		SessionImplementor session)
+	throws HibernateException {
+		
+		int length = Array.getLength(original);
+		if ( length!=Array.getLength(target) ) {
+			//note: this affects the return value!
+			target=instantiateResult(original);
+		}
+		
+		Type elemType = getElementType( session.getFactory() );
+		for ( int i=0; i<length; i++ ) {
+			Array.set( target, i, elemType.replace( Array.get(original, i), null, session, owner, copyCache ) );
+		}
+		
+		return target;
+	
+	}
+
+	public Object instantiate(int anticipatedSize) {
+		throw new UnsupportedOperationException();
+	}
+
+	public Object indexOf(Object array, Object element) {
+		int length = Array.getLength(array);
+		for ( int i=0; i<length; i++ ) {
+			//TODO: proxies!
+			if ( Array.get(array, i)==element ) return new Integer(i);
+		}
+		return null;
+	}
+
+	protected boolean initializeImmediately(EntityMode entityMode) {
+		return true;
+	}
+
+	public boolean hasHolder(EntityMode entityMode) {
+		return true;
+	}
+	
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/AssociationType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/AssociationType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/AssociationType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,74 @@
+//$Id: AssociationType.java 7017 2005-06-05 04:31:34Z oneovthafew $
+package org.hibernate.type;
+
+import org.hibernate.MappingException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.persister.entity.Joinable;
+
+import java.util.Map;
+
+/**
+ * A type that represents some kind of association between entities.
+ * @see org.hibernate.engine.Cascade
+ * @author Gavin King
+ */
+public interface AssociationType extends Type {
+
+	/**
+	 * Get the foreign key directionality of this association
+	 */
+	public ForeignKeyDirection getForeignKeyDirection();
+
+	//TODO: move these to a new JoinableType abstract class,
+	//extended by EntityType and PersistentCollectionType:
+
+	/**
+	 * Is the primary key of the owning entity table
+	 * to be used in the join?
+	 */
+	public boolean useLHSPrimaryKey();
+	/**
+	 * Get the name of a property in the owning entity 
+	 * that provides the join key (null if the identifier)
+	 */
+	public String getLHSPropertyName();
+	
+	/**
+	 * The name of a unique property of the associated entity 
+	 * that provides the join key (null if the identifier of
+	 * an entity, or key of a collection)
+	 */
+	public String getRHSUniqueKeyPropertyName();
+
+	/**
+	 * Get the "persister" for this association - a class or
+	 * collection persister
+	 */
+	public Joinable getAssociatedJoinable(SessionFactoryImplementor factory) throws MappingException;
+	
+	/**
+	 * Get the entity name of the associated entity
+	 */
+	public String getAssociatedEntityName(SessionFactoryImplementor factory) throws MappingException;
+	
+	/**
+	 * Get the "filtering" SQL fragment that is applied in the 
+	 * SQL on clause, in addition to the usual join condition
+	 */	
+	public String getOnCondition(String alias, SessionFactoryImplementor factory, Map enabledFilters) 
+	throws MappingException;
+	
+	/**
+	 * Do we dirty check this association, even when there are
+	 * no columns to be updated?
+	 */
+	public abstract boolean isAlwaysDirtyChecked();
+	
+	public boolean isEmbeddedInXML();
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/BagType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/BagType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/BagType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+//$Id: BagType.java 10086 2006-07-05 18:17:27Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.dom4j.Element;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentBag;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.collection.PersistentElementHolder;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+
+public class BagType extends CollectionType {
+
+	public BagType(String role, String propertyRef, boolean isEmbeddedInXML) {
+		super(role, propertyRef, isEmbeddedInXML);
+	}
+
+	public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister, Serializable key)
+	throws HibernateException {
+		if ( session.getEntityMode()==EntityMode.DOM4J ) {
+			return new PersistentElementHolder(session, persister, key);
+		}
+		else {
+			return new PersistentBag(session);
+		}
+	}
+
+	public Class getReturnedClass() {
+		return java.util.Collection.class;
+	}
+
+	public PersistentCollection wrap(SessionImplementor session, Object collection) {
+		if ( session.getEntityMode()==EntityMode.DOM4J ) {
+			return new PersistentElementHolder( session, (Element) collection );
+		}
+		else {
+			return new PersistentBag( session, (Collection) collection );
+		}
+	}
+
+	public Object instantiate(int anticipatedSize) {
+		return anticipatedSize <= 0 ? new ArrayList() : new ArrayList( anticipatedSize + 1 );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/BigDecimalType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/BigDecimalType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/BigDecimalType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,66 @@
+//$Id: BigDecimalType.java 5744 2005-02-16 12:50:19Z oneovthafew $
+package org.hibernate.type;
+
+import java.math.BigDecimal;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+
+/**
+ * <tt>big_decimal</tt>: A type that maps an SQL NUMERIC to a
+ * <tt>java.math.BigDecimal</tt>
+ * @see java.math.BigDecimal
+ * @author Gavin King
+ */
+public class BigDecimalType extends ImmutableType {
+
+	public Object get(ResultSet rs, String name)
+	throws HibernateException, SQLException {
+		return rs.getBigDecimal(name);
+	}
+
+	public void set(PreparedStatement st, Object value, int index)
+	throws HibernateException, SQLException {
+		st.setBigDecimal(index, (BigDecimal) value);
+	}
+
+	public int sqlType() {
+		return Types.NUMERIC;
+	}
+
+	public String toString(Object value) throws HibernateException {
+		return value.toString();
+	}
+
+	public Class getReturnedClass() {
+		return BigDecimal.class;
+	}
+
+	public boolean isEqual(Object x, Object y) {
+		return x==y || ( x!=null && y!=null && ( (BigDecimal) x ).compareTo( (BigDecimal) y )==0 );
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode) {
+		return ( (BigDecimal) x ).intValue();
+	}
+
+	public String getName() {
+		return "big_decimal";
+	}
+
+	public Object fromStringValue(String xml) {
+		return new BigDecimal(xml);
+	}
+
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/BigIntegerType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/BigIntegerType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/BigIntegerType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,79 @@
+//$Id: BigIntegerType.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.type;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * <tt>big_integer</tt>: A type that maps an SQL NUMERIC to a
+ * <tt>java.math.BigInteger</tt>
+ * @see java.math.BigInteger
+ * @author Gavin King
+ */
+public class BigIntegerType extends ImmutableType implements DiscriminatorType {
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return value.toString();
+	}
+
+	public Object stringToObject(String xml) throws Exception {
+		return new BigInteger(xml);
+	}
+
+	public Object get(ResultSet rs, String name)
+	throws HibernateException, SQLException {
+		//return rs.getBigDecimal(name).toBigIntegerExact(); this 1.5 only. 
+		BigDecimal bigDecimal = rs.getBigDecimal(name);
+		return bigDecimal==null ? null : 
+			bigDecimal.setScale(0, BigDecimal.ROUND_UNNECESSARY).unscaledValue();
+	}
+
+	public void set(PreparedStatement st, Object value, int index)
+	throws HibernateException, SQLException {
+		st.setBigDecimal( index, new BigDecimal( (BigInteger) value ) );
+	}
+
+	public int sqlType() {
+		return Types.NUMERIC;
+	}
+
+	public String toString(Object value) throws HibernateException {
+		return value.toString();
+	}
+
+	public Class getReturnedClass() {
+		return BigInteger.class;
+	}
+
+	public boolean isEqual(Object x, Object y) {
+		return x==y || ( x!=null && y!=null && ( (BigInteger) x ).compareTo( (BigInteger) y )==0 );
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode) {
+		return ( (BigInteger) x ).intValue();
+	}
+
+	public String getName() {
+		return "big_integer";
+	}
+
+	public Object fromStringValue(String xml) {
+		return new BigInteger(xml);
+	}
+
+
+}
+
+
+
+
+
+


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/type/BigIntegerType.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/BinaryType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/BinaryType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/BinaryType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+//$Id: BinaryType.java 10009 2006-06-10 03:24:05Z epbernard $
+package org.hibernate.type;
+
+/**
+ * <tt>binary</tt>: A type that maps an SQL VARBINARY to a Java byte[].
+ * @author Gavin King
+ */
+public class BinaryType extends AbstractBynaryType {
+
+	protected Object toExternalFormat(byte[] bytes) {
+		return bytes;
+	}
+
+	protected byte[] toInternalFormat(Object bytes) {
+		return (byte[]) bytes;
+	}
+
+	public Class getReturnedClass() {
+		return byte[].class;
+	}
+
+	public String getName() { return "binary"; }
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/BlobType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/BlobType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/BlobType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,159 @@
+//$Id: BlobType.java 7644 2005-07-25 06:53:09Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.Blob;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Map;
+
+import org.dom4j.Node;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.lob.BlobImpl;
+import org.hibernate.lob.SerializableBlob;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * <tt>blob</tt>: A type that maps an SQL BLOB to a java.sql.Blob.
+ * @author Gavin King
+ */
+public class BlobType extends AbstractType {
+
+	public void set(PreparedStatement st, Object value, int index, SessionImplementor session) 
+	throws HibernateException, SQLException {
+		
+		if (value==null) {
+			st.setNull(index, Types.BLOB);
+		}
+		else {
+			
+			if (value instanceof SerializableBlob) {
+				value = ( (SerializableBlob) value ).getWrappedBlob();
+			}
+		
+			final boolean useInputStream = session.getFactory().getDialect().useInputStreamToInsertBlob() && 
+				(value instanceof BlobImpl);
+			
+			if ( useInputStream ) {
+				BlobImpl blob = (BlobImpl) value;
+				st.setBinaryStream( index, blob.getBinaryStream(), (int) blob.length() );
+			}
+			else {
+				st.setBlob(index, (Blob) value);
+			}
+			
+		}
+		
+	}
+
+	public Object get(ResultSet rs, String name) throws HibernateException, SQLException {
+		Blob value = rs.getBlob(name);
+		return rs.wasNull() ? null : new SerializableBlob(value);
+	}
+
+	public Class getReturnedClass() {
+		return Blob.class;
+	}
+
+	public boolean isEqual(Object x, Object y, EntityMode entityMode) {
+		return x == y;
+	}
+	
+	public int getHashCode(Object x, EntityMode entityMode) {
+		return System.identityHashCode(x);
+	}
+
+	public int compare(Object x, Object y, EntityMode entityMode) {
+		return 0; //lobs cannot be compared
+	}
+
+	public String getName() {
+		return "blob";
+	}
+	
+	public Serializable disassemble(Object value, SessionImplementor session, Object owner)
+		throws HibernateException {
+		throw new UnsupportedOperationException("Blobs are not cacheable");
+	}
+
+	public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory)  {
+		return value;
+	}
+	
+	public Object fromXMLNode(Node xml, Mapping factory) {
+		throw new UnsupportedOperationException("todo");
+	}
+	
+	public int getColumnSpan(Mapping mapping) {
+		return 1;
+	}
+	
+	public boolean isMutable() {
+		return false;
+	}
+	
+	public Object nullSafeGet(ResultSet rs, String name,
+			SessionImplementor session, Object owner)
+			throws HibernateException, SQLException {
+		return get(rs, name);
+	}
+	
+	public Object nullSafeGet(ResultSet rs, String[] names,
+			SessionImplementor session, Object owner)
+			throws HibernateException, SQLException {
+		return get( rs, names[0] );
+	}
+	
+	public void nullSafeSet(PreparedStatement st, Object value, int index,
+			boolean[] settable, SessionImplementor session)
+			throws HibernateException, SQLException {
+		if ( settable[0] ) set(st, value, index, session);
+	}
+	
+	public void nullSafeSet(PreparedStatement st, Object value, int index,
+			SessionImplementor session) throws HibernateException, SQLException {
+		set(st, value, index, session);
+	}
+	
+	public Object replace(Object original, Object target,
+			SessionImplementor session, Object owner, Map copyCache)
+			throws HibernateException {
+		//Blobs are ignored by merge()
+		return target;
+	}
+	
+	public int[] sqlTypes(Mapping mapping) throws MappingException {
+		return new int[] { Types.BLOB };
+	}
+	
+	public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory) {
+		throw new UnsupportedOperationException("todo");
+	}
+	
+	public String toLoggableString(Object value, SessionFactoryImplementor factory)
+			throws HibernateException {
+		return value==null ? "null" : value.toString();
+	}
+	
+	public boolean[] toColumnNullness(Object value, Mapping mapping) {
+		return value==null ? ArrayHelper.FALSE : ArrayHelper.TRUE;
+	}
+
+	public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session) throws HibernateException {
+		return checkable[0] && isDirty(old, current, session);
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/BooleanType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/BooleanType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/BooleanType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+//$Id: BooleanType.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.dialect.Dialect;
+
+/**
+ * <tt>boolean</tt>: A type that maps an SQL BIT to a Java Boolean.
+ * @author Gavin King
+ */
+public class BooleanType extends PrimitiveType implements DiscriminatorType {
+
+	public Serializable getDefaultValue() {
+		return Boolean.FALSE;
+	}
+	
+	public Object get(ResultSet rs, String name) throws SQLException {
+		return rs.getBoolean(name) ? Boolean.TRUE : Boolean.FALSE;
+	}
+
+	public Class getPrimitiveClass() {
+		return boolean.class;
+	}
+
+	public Class getReturnedClass() {
+		return Boolean.class;
+	}
+
+	public void set(PreparedStatement st, Object value, int index)
+	throws SQLException {
+		st.setBoolean( index, ( (Boolean) value ).booleanValue() );
+	}
+
+	public int sqlType() {
+		return Types.BIT;
+	}
+
+	public String getName() { return "boolean"; }
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return dialect.toBooleanValueString( ( (Boolean) value ).booleanValue() );
+	}
+
+	public Object stringToObject(String xml) throws Exception {
+		return fromStringValue(xml);
+	}
+
+	public Object fromStringValue(String xml) {
+		return Boolean.valueOf(xml);
+	}
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/ByteType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/ByteType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/ByteType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,73 @@
+//$Id: ByteType.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Comparator;
+
+import org.hibernate.util.ComparableComparator;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * <tt>byte</tt>: A type that maps an SQL TINYINT to a Java Byte.
+ * @author Gavin King
+ */
+public class ByteType extends PrimitiveType implements DiscriminatorType, VersionType {
+
+	private static final Byte ZERO = new Byte( (byte) 0 );
+
+	public Serializable getDefaultValue() {
+		return ZERO;
+	}
+	
+	public Object get(ResultSet rs, String name) throws SQLException {
+		return new Byte( rs.getByte(name) );
+	}
+
+	public Class getPrimitiveClass() {
+		return byte.class;
+	}
+
+	public Class getReturnedClass() {
+		return Byte.class;
+	}
+
+	public void set(PreparedStatement st, Object value, int index) throws SQLException {
+		st.setByte( index, ( (Byte) value ).byteValue() );
+	}
+
+	public int sqlType() {
+		return Types.TINYINT;
+	}
+
+	public String getName() { return "byte"; }
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return value.toString();
+	}
+
+	public Object stringToObject(String xml) throws Exception {
+		return new Byte(xml);
+	}
+
+	public Object fromStringValue(String xml) {
+		return new Byte(xml);
+	}
+
+	public Object next(Object current, SessionImplementor session) {
+		return new Byte( (byte) ( ( (Byte) current ).byteValue() + 1 ) );
+	}
+
+	public Object seed(SessionImplementor session) {
+		return ZERO;
+	}
+
+	public Comparator getComparator() {
+		return ComparableComparator.INSTANCE;
+	}
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/CalendarDateType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/CalendarDateType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/CalendarDateType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,95 @@
+//$Id: CalendarDateType.java 8761 2005-12-06 04:34:23Z oneovthafew $
+package org.hibernate.type;
+
+import java.sql.Date;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import org.hibernate.EntityMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.util.CalendarComparator;
+
+/**
+ * <tt>calendar_date</tt>: A type mapping for a <tt>Calendar</tt>
+ * object that represents a date.
+ * @author Gavin King
+ */
+public class CalendarDateType extends MutableType {
+
+	public Object get(ResultSet rs, String name) throws HibernateException, SQLException {
+
+		Date date = rs.getDate(name);
+		if (date!=null) {
+			Calendar cal = new GregorianCalendar();
+			cal.setTime(date);
+			return cal;
+		}
+		else {
+			return null;
+		}
+
+	}
+
+	public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
+		final Calendar cal = (Calendar) value;
+		//st.setDate( index,  new Date( cal.getTimeInMillis() ), cal ); //JDK 1.5 only
+		st.setDate( index,  new Date( cal.getTime().getTime() ), cal );
+	}
+
+	public int sqlType() {
+		return Types.DATE;
+	}
+
+	public String toString(Object value) throws HibernateException {
+		return Hibernate.DATE.toString( ( (Calendar) value ).getTime() );
+	}
+
+	public Object fromStringValue(String xml) throws HibernateException {
+		Calendar result = new GregorianCalendar();
+		result.setTime( ( (java.util.Date) Hibernate.DATE.fromStringValue(xml) ) );
+		return result;
+	}
+
+	public Object deepCopyNotNull(Object value)  {
+		return ( (Calendar) value ).clone();
+	}
+
+	public Class getReturnedClass() {
+		return Calendar.class;
+	}
+
+	public int compare(Object x, Object y, EntityMode entityMode) {
+		return CalendarComparator.INSTANCE.compare(x, y);
+	}
+
+	public boolean isEqual(Object x, Object y)  {
+		if (x==y) return true;
+		if (x==null || y==null) return false;
+
+		Calendar calendar1 = (Calendar) x;
+		Calendar calendar2 = (Calendar) y;
+
+		return calendar1.get(Calendar.DAY_OF_MONTH) == calendar2.get(Calendar.DAY_OF_MONTH)
+			&& calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH)
+			&& calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR);
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode) {
+		Calendar calendar = (Calendar) x;
+		int hashCode = 1;
+		hashCode = 31 * hashCode + calendar.get(Calendar.DAY_OF_MONTH);
+		hashCode = 31 * hashCode + calendar.get(Calendar.MONTH);
+		hashCode = 31 * hashCode + calendar.get(Calendar.YEAR);
+		return hashCode;
+	}
+
+	public String getName() {
+		return "calendar_date";
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/CalendarType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/CalendarType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/CalendarType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,124 @@
+//$Id: CalendarType.java 7736 2005-08-03 20:03:34Z steveebersole $
+package org.hibernate.type;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.Calendar;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import org.hibernate.EntityMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.cfg.Environment;
+import org.hibernate.util.CalendarComparator;
+
+/**
+ * <tt>calendar</tt>: A type mapping for a <tt>Calendar</tt> object that
+ * represents a datetime.
+ * @author Gavin King
+ */
+public class CalendarType extends MutableType implements VersionType {
+
+	public Object get(ResultSet rs, String name) throws HibernateException, SQLException {
+
+		Timestamp ts = rs.getTimestamp(name);
+		if (ts!=null) {
+			Calendar cal = new GregorianCalendar();
+			if ( Environment.jvmHasTimestampBug() ) {
+				cal.setTime( new Date( ts.getTime() + ts.getNanos() / 1000000 ) );
+			}
+			else {
+				cal.setTime(ts);
+			}
+			return cal;
+		}
+		else {
+			return null;
+		}
+
+	}
+
+	public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
+		final Calendar cal = (Calendar) value;
+		//st.setTimestamp( index,  new Timestamp( cal.getTimeInMillis() ), cal ); //JDK 1.5 only
+		st.setTimestamp( index,  new Timestamp( cal.getTime().getTime() ), cal );
+	}
+
+	public int sqlType() {
+		return Types.TIMESTAMP;
+	}
+
+	public String toString(Object value) throws HibernateException {
+		return Hibernate.TIMESTAMP.toString( ( (Calendar) value ).getTime() );
+	}
+
+	public Object fromStringValue(String xml) throws HibernateException {
+		Calendar result = new GregorianCalendar();
+		result.setTime( ( (Date) Hibernate.TIMESTAMP.fromStringValue(xml) ) );
+		return result;
+	}
+
+	public Object deepCopyNotNull(Object value) throws HibernateException {
+		return ( (Calendar) value ).clone();
+	}
+
+	public Class getReturnedClass() {
+		return Calendar.class;
+	}
+	
+	public int compare(Object x, Object y, EntityMode entityMode) {
+		return CalendarComparator.INSTANCE.compare(x, y);
+	}
+
+	public boolean isEqual(Object x, Object y) {
+		if (x==y) return true;
+		if (x==null || y==null) return false;
+
+		Calendar calendar1 = (Calendar) x;
+		Calendar calendar2 = (Calendar) y;
+
+		return calendar1.get(Calendar.MILLISECOND) == calendar2.get(Calendar.MILLISECOND)
+			&& calendar1.get(Calendar.SECOND) == calendar2.get(Calendar.SECOND)
+			&& calendar1.get(Calendar.MINUTE) == calendar2.get(Calendar.MINUTE)
+			&& calendar1.get(Calendar.HOUR_OF_DAY) == calendar2.get(Calendar.HOUR_OF_DAY)
+			&& calendar1.get(Calendar.DAY_OF_MONTH) == calendar2.get(Calendar.DAY_OF_MONTH)
+			&& calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH)
+			&& calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR);
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode) {
+		Calendar calendar = (Calendar) x;
+		int hashCode = 1;
+		hashCode = 31 * hashCode + calendar.get(Calendar.MILLISECOND);
+		hashCode = 31 * hashCode + calendar.get(Calendar.SECOND);
+		hashCode = 31 * hashCode + calendar.get(Calendar.MINUTE);
+		hashCode = 31 * hashCode + calendar.get(Calendar.HOUR_OF_DAY);
+		hashCode = 31 * hashCode + calendar.get(Calendar.DAY_OF_MONTH);
+		hashCode = 31 * hashCode + calendar.get(Calendar.MONTH);
+		hashCode = 31 * hashCode + calendar.get(Calendar.YEAR);
+		return hashCode;
+	}
+
+	public String getName() {
+		return "calendar";
+	}
+
+	public Object next(Object current, SessionImplementor session) {
+		return seed( session );
+	}
+
+	public Object seed(SessionImplementor session) {
+		return Calendar.getInstance();
+	}
+
+	public Comparator getComparator() {
+		return CalendarComparator.INSTANCE;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharArrayType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharArrayType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharArrayType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+//$Id: $
+package org.hibernate.type;
+
+/**
+ * put char[] into VARCHAR
+ * @author Emmanuel Bernard
+ */
+public class CharArrayType extends AbstractCharArrayType {
+
+	protected Object toExternalFormat(char[] chars) {
+		return chars;
+	}
+
+	protected char[] toInternalFormat(Object chars) {
+		return (char[]) chars;
+	}
+
+	public Class getReturnedClass() {
+		return char[].class;
+	}
+
+	public String getName() { return "characters"; }
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharBooleanType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharBooleanType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharBooleanType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,70 @@
+//$Id: CharBooleanType.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.type;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+
+
+/**
+ * Superclass for types that map Java boolean to SQL CHAR(1).
+ * @author Gavin King
+ */
+public abstract class CharBooleanType extends BooleanType {
+
+	protected abstract String getTrueString();
+	protected abstract String getFalseString();
+
+	public Object get(ResultSet rs, String name) throws SQLException {
+		String code = rs.getString(name);
+		if ( code==null || code.length()==0 ) {
+			return null;
+		}
+		else {
+			return getTrueString().equalsIgnoreCase( code.trim() ) ? 
+					Boolean.TRUE : Boolean.FALSE;
+		}
+	}
+
+	public void set(PreparedStatement st, Object value, int index)
+	throws SQLException {
+		st.setString( index, toCharacter(value) );
+
+	}
+
+	public int sqlType() {
+		return Types.CHAR;
+	}
+
+	private String toCharacter(Object value) {
+		return ( (Boolean) value ).booleanValue() ? getTrueString() : getFalseString();
+	}
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return "'" + toCharacter(value) + "'";
+	}
+
+	public Object stringToObject(String xml) throws Exception {
+		if ( getTrueString().equalsIgnoreCase(xml) ) {
+			return Boolean.TRUE;
+		}
+		else if ( getFalseString().equalsIgnoreCase(xml) ) {
+			return Boolean.FALSE;
+		}
+		else {
+			throw new HibernateException("Could not interpret: " + xml);
+		}
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharacterArrayType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharacterArrayType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharacterArrayType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: $
+package org.hibernate.type;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Bridge Character[] and VARCHAR
+ * @author Emmanuel Bernard
+ */
+public class CharacterArrayType extends AbstractCharArrayType {
+	protected Object toExternalFormat(char[] chars) {
+		if (chars == null) return null;
+		Character[] characters = new Character[chars.length];
+		for (int i = 0 ; i < chars.length ; i++) {
+			characters[i] = new Character( chars[i] );
+		}
+		return characters;
+	}
+
+	protected char[] toInternalFormat(Object value) {
+		if (value == null) return null;
+		Character[] characters = (Character[]) value;
+		char[] chars = new char[characters.length];
+		for (int i = 0 ; i < characters.length ; i++) {
+			if (characters[i] == null)
+				throw new HibernateException("Unable to store an Character[] when one of its element is null");
+			chars[i] = characters[i].charValue();
+		}
+		return chars;
+	}
+
+	public Class getReturnedClass() {
+		return Character[].class;
+	}
+
+	public String getName() { return "wrapper-characters"; }
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharacterType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharacterType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/CharacterType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,68 @@
+//$Id: CharacterType.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * <tt>character</tt>: A type that maps an SQL CHAR(1) to a Java Character.
+ * @author Gavin King
+ */
+public class CharacterType extends PrimitiveType implements DiscriminatorType {
+
+	public Serializable getDefaultValue() {
+		throw new UnsupportedOperationException("not a valid id type");
+	}
+	
+	public Object get(ResultSet rs, String name) throws SQLException {
+		String str = rs.getString(name);
+		if (str==null) {
+			return null;
+		}
+		else {
+			return new Character( str.charAt(0) );
+		}
+	}
+
+	public Class getPrimitiveClass() {
+		return char.class;
+	}
+
+	public Class getReturnedClass() {
+		return Character.class;
+	}
+
+	public void set(PreparedStatement st, Object value, int index) throws SQLException {
+		st.setString( index, (value).toString() );
+	}
+
+	public int sqlType() {
+		return Types.CHAR;
+	}
+	public String getName() { return "character"; }
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return '\'' + value.toString() + '\'';
+	}
+
+	public Object stringToObject(String xml) throws Exception {
+		if ( xml.length() != 1 ) throw new MappingException("multiple or zero characters found parsing string");
+		return new Character( xml.charAt(0) );
+	}
+
+	public Object fromStringValue(String xml) {
+		return new Character( xml.charAt(0) );
+	}
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/ClassType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/ClassType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/ClassType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+//$Id: ClassType.java 4582 2004-09-25 11:22:20Z oneovthafew $
+package org.hibernate.type;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * <tt>class</tt>: A type that maps an SQL VARCHAR to a Java Class.
+ * @author Gavin King
+ */
+public class ClassType extends ImmutableType {
+
+	public Object get(ResultSet rs, String name) throws HibernateException, SQLException {
+		String str = (String) Hibernate.STRING.get(rs, name);
+		if (str == null) {
+			return null;
+		}
+		else {
+			try {
+				return ReflectHelper.classForName(str);
+			}
+			catch (ClassNotFoundException cnfe) {
+				throw new HibernateException("Class not found: " + str);
+			}
+		}
+	}
+
+	public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
+		//TODO: would be nice to handle proxy classes elegantly!
+		Hibernate.STRING.set(st, ( (Class) value ).getName(), index);
+	}
+
+	public int sqlType() {
+		return Hibernate.STRING.sqlType();
+	}
+
+	public String toString(Object value) throws HibernateException {
+		return ( (Class) value ).getName();
+	}
+
+	public Class getReturnedClass() {
+		return Class.class;
+	}
+
+	public String getName() {
+		return "class";
+	}
+
+	public Object fromStringValue(String xml) throws HibernateException {
+		try {
+			return ReflectHelper.classForName(xml);
+		}
+		catch (ClassNotFoundException cnfe) {
+			throw new HibernateException("could not parse xml", cnfe);
+		}
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/ClobType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/ClobType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/ClobType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,169 @@
+//$Id: ClobType.java 7644 2005-07-25 06:53:09Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.Clob;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Map;
+
+import org.dom4j.Node;
+import org.hibernate.EntityMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.lob.ClobImpl;
+import org.hibernate.lob.SerializableClob;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * <tt>clob</tt>: A type that maps an SQL CLOB to a java.sql.Clob.
+ * @author Gavin King
+ */
+public class ClobType extends AbstractType {
+
+	public void set(PreparedStatement st, Object value, int index, SessionImplementor session) 
+	throws HibernateException, SQLException {
+		
+		if (value==null) {
+			st.setNull(index, Types.CLOB);
+		}
+		else {
+		
+			if (value instanceof SerializableClob) {
+				value = ( (SerializableClob) value ).getWrappedClob();
+			}
+		
+			final boolean useReader = session.getFactory().getDialect().useInputStreamToInsertBlob() && 
+				(value instanceof ClobImpl);
+			
+			if ( useReader ) {
+				ClobImpl clob = (ClobImpl) value;
+				st.setCharacterStream( index, clob.getCharacterStream(), (int) clob.length() );
+			}
+			else {
+				st.setClob(index, (Clob) value);
+			}
+			
+		}
+		
+	}
+
+	public Object get(ResultSet rs, String name) throws HibernateException, SQLException {
+		Clob value = rs.getClob(name);
+		return rs.wasNull() ? null : new SerializableClob(value);
+	}
+
+	public Class getReturnedClass() {
+		return Clob.class;
+	}
+
+	public boolean isEqual(Object x, Object y, EntityMode entityMode) {
+		return x == y;
+	}
+	
+	public int getHashCode(Object x, EntityMode entityMode) {
+		return System.identityHashCode(x);
+	}
+
+	public int compare(Object x, Object y, EntityMode entityMode) {
+		return 0; //lobs cannot be compared
+	}
+
+	public String getName() {
+		return "clob";
+	}
+	
+	public Serializable disassemble(Object value, SessionImplementor session, Object owner)
+		throws HibernateException {
+		throw new UnsupportedOperationException("Clobs are not cacheable");
+	}
+
+	public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory)  {
+		return value;
+	}
+	
+	public Object fromXMLNode(Node xml, Mapping factory) {
+		return Hibernate.createClob( xml.getText() );
+	}
+	
+	public int getColumnSpan(Mapping mapping) {
+		return 1;
+	}
+	
+	public boolean isMutable() {
+		return false;
+	}
+	
+	public Object nullSafeGet(ResultSet rs, String name,
+			SessionImplementor session, Object owner)
+			throws HibernateException, SQLException {
+		return get(rs, name);
+	}
+	
+	public Object nullSafeGet(ResultSet rs, String[] names,
+			SessionImplementor session, Object owner)
+			throws HibernateException, SQLException {
+		return get( rs, names[0] );
+	}
+	
+	public void nullSafeSet(PreparedStatement st, Object value, int index,
+			boolean[] settable, SessionImplementor session)
+			throws HibernateException, SQLException {
+		if ( settable[0] ) set(st, value, index, session);
+	}
+	
+	public void nullSafeSet(PreparedStatement st, Object value, int index,
+			SessionImplementor session) throws HibernateException, SQLException {
+		set(st, value, index, session);
+	}
+	
+	public Object replace(Object original, Object target,
+			SessionImplementor session, Object owner, Map copyCache)
+			throws HibernateException {
+		//Clobs are ignored by merge() operation
+		return target;
+	}
+	
+	public int[] sqlTypes(Mapping mapping) throws MappingException {
+		return new int[] { Types.CLOB };
+	}
+	
+	public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory) {
+		if (value!=null) {
+			Clob clob = (Clob) value;
+			try {
+				int len = (int) clob.length();
+				node.setText( clob.getSubString(0, len) );
+			}
+			catch (SQLException sqle) {
+				throw new HibernateException("could not read XML from Clob", sqle);
+			}
+		}
+	}
+	
+	public String toLoggableString(Object value, SessionFactoryImplementor factory)
+			throws HibernateException {
+		return value==null ? "null" : value.toString();
+	}
+
+	public boolean[] toColumnNullness(Object value, Mapping mapping) {
+		return value==null ? ArrayHelper.FALSE : ArrayHelper.TRUE;
+	}
+
+	public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session) throws HibernateException {
+		return checkable[0] && isDirty(old, current, session);
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/CollectionType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/CollectionType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/CollectionType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,639 @@
+// $Id: CollectionType.java 11302 2007-03-19 20:44:11Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.dom4j.Element;
+import org.dom4j.Node;
+import org.hibernate.EntityMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.CollectionKey;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.MarkerObject;
+
+/**
+ * A type that handles Hibernate <tt>PersistentCollection</tt>s (including arrays).
+ * 
+ * @author Gavin King
+ */
+public abstract class CollectionType extends AbstractType implements AssociationType {
+
+	private static final Object NOT_NULL_COLLECTION = new MarkerObject( "NOT NULL COLLECTION" );
+	public static final Object UNFETCHED_COLLECTION = new MarkerObject( "UNFETCHED COLLECTION" );
+
+	private final String role;
+	private final String foreignKeyPropertyName;
+	private final boolean isEmbeddedInXML;
+
+	public CollectionType(String role, String foreignKeyPropertyName, boolean isEmbeddedInXML) {
+		this.role = role;
+		this.foreignKeyPropertyName = foreignKeyPropertyName;
+		this.isEmbeddedInXML = isEmbeddedInXML;
+	}
+	
+	public boolean isEmbeddedInXML() {
+		return isEmbeddedInXML;
+	}
+
+	public String getRole() {
+		return role;
+	}
+
+	public Object indexOf(Object collection, Object element) {
+		throw new UnsupportedOperationException( "generic collections don't have indexes" );
+	}
+
+	public boolean contains(Object collection, Object childObject, SessionImplementor session) {
+		// we do not have to worry about queued additions to uninitialized
+		// collections, since they can only occur for inverse collections!
+		Iterator elems = getElementsIterator( collection, session );
+		while ( elems.hasNext() ) {
+			Object element = elems.next();
+			// worrying about proxies is perhaps a little bit of overkill here...
+			if ( element instanceof HibernateProxy ) {
+				LazyInitializer li = ( (HibernateProxy) element ).getHibernateLazyInitializer();
+				if ( !li.isUninitialized() ) element = li.getImplementation();
+			}
+			if ( element == childObject ) return true;
+		}
+		return false;
+	}
+
+	public boolean isCollectionType() {
+		return true;
+	}
+
+	public final boolean isEqual(Object x, Object y, EntityMode entityMode) {
+		return x == y
+			|| ( x instanceof PersistentCollection && ( (PersistentCollection) x ).isWrapper( y ) )
+			|| ( y instanceof PersistentCollection && ( (PersistentCollection) y ).isWrapper( x ) );
+	}
+
+	public int compare(Object x, Object y, EntityMode entityMode) {
+		return 0; // collections cannot be compared
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode) {
+		throw new UnsupportedOperationException( "cannot perform lookups on collections" );
+	}
+
+	/**
+	 * Instantiate an uninitialized collection wrapper or holder. Callers MUST add the holder to the
+	 * persistence context!
+	 *
+	 * @param session The session from which the request is originating.
+	 * @param persister The underlying collection persister (metadata)
+	 * @param key The owner key.
+	 * @return The instantiated collection.
+	 */
+	public abstract PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister, Serializable key);
+
+	public Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object owner) throws SQLException {
+		return nullSafeGet( rs, new String[] { name }, session, owner );
+	}
+
+	public Object nullSafeGet(ResultSet rs, String[] name, SessionImplementor session, Object owner)
+			throws HibernateException, SQLException {
+		return resolve( null, session, owner );
+	}
+
+	public final void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable,
+			SessionImplementor session) throws HibernateException, SQLException {
+		//NOOP
+	}
+
+	public void nullSafeSet(PreparedStatement st, Object value, int index,
+			SessionImplementor session) throws HibernateException, SQLException {
+	}
+
+	public int[] sqlTypes(Mapping session) throws MappingException {
+		return ArrayHelper.EMPTY_INT_ARRAY;
+	}
+
+	public int getColumnSpan(Mapping session) throws MappingException {
+		return 0;
+	}
+
+	public String toLoggableString(Object value, SessionFactoryImplementor factory)
+			throws HibernateException {
+		if ( value == null ) {
+			return "null";
+		}
+		else if ( !Hibernate.isInitialized( value ) ) {
+			return "<uninitialized>";
+		}
+		else {
+			return renderLoggableString( value, factory );
+		}
+	}
+
+	protected String renderLoggableString(Object value, SessionFactoryImplementor factory)
+			throws HibernateException {
+		if ( Element.class.isInstance( value ) ) {
+			// for DOM4J "collections" only
+			// TODO: it would be better if this was done at the higher level by Printer
+			return ( ( Element ) value ).asXML();
+		}
+		else {
+			List list = new ArrayList();
+			Type elemType = getElementType( factory );
+			Iterator iter = getElementsIterator( value );
+			while ( iter.hasNext() ) {
+				list.add( elemType.toLoggableString( iter.next(), factory ) );
+			}
+			return list.toString();
+		}
+	}
+
+	public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory)
+			throws HibernateException {
+		return value;
+	}
+
+	public String getName() {
+		return getReturnedClass().getName() + '(' + getRole() + ')';
+	}
+
+	/**
+	 * Get an iterator over the element set of the collection, which may not yet be wrapped
+	 *
+	 * @param collection The collection to be iterated
+	 * @param session The session from which the request is originating.
+	 * @return The iterator.
+	 */
+	public Iterator getElementsIterator(Object collection, SessionImplementor session) {
+		if ( session.getEntityMode()==EntityMode.DOM4J ) {
+			final SessionFactoryImplementor factory = session.getFactory();
+			final CollectionPersister persister = factory.getCollectionPersister( getRole() );
+			final Type elementType = persister.getElementType();
+			
+			List elements = ( (Element) collection ).elements( persister.getElementNodeName() );
+			ArrayList results = new ArrayList();
+			for ( int i=0; i<elements.size(); i++ ) {
+				Element value = (Element) elements.get(i);
+				results.add( elementType.fromXMLNode( value, factory ) );
+			}
+			return results.iterator();
+		}
+		else {
+			return getElementsIterator(collection);
+		}
+	}
+
+	/**
+	 * Get an iterator over the element set of the collection in POJO mode
+	 *
+	 * @param collection The collection to be iterated
+	 * @return The iterator.
+	 */
+	protected Iterator getElementsIterator(Object collection) {
+		return ( (Collection) collection ).iterator();
+	}
+
+	public boolean isMutable() {
+		return false;
+	}
+
+	public Serializable disassemble(Object value, SessionImplementor session, Object owner)
+			throws HibernateException {
+		//remember the uk value
+		
+		//This solution would allow us to eliminate the owner arg to disassemble(), but
+		//what if the collection was null, and then later had elements added? seems unsafe
+		//session.getPersistenceContext().getCollectionEntry( (PersistentCollection) value ).getKey();
+		
+		final Serializable key = getKeyOfOwner(owner, session);
+		if (key==null) {
+			return null;
+		}
+		else {
+			return getPersister(session)
+					.getKeyType()
+					.disassemble( key, session, owner );
+		}
+	}
+
+	public Object assemble(Serializable cached, SessionImplementor session, Object owner)
+			throws HibernateException {
+		//we must use the "remembered" uk value, since it is 
+		//not available from the EntityEntry during assembly
+		if (cached==null) {
+			return null;
+		}
+		else {
+			final Serializable key = (Serializable) getPersister(session)
+					.getKeyType()
+					.assemble( cached, session, owner);
+			return resolveKey( key, session, owner );
+		}
+	}
+
+	/**
+	 * Is the owning entity versioned?
+	 *
+	 * @param session The session from which the request is originating.
+	 * @return True if the collection owner is versioned; false otherwise.
+	 * @throws org.hibernate.MappingException Indicates our persister could not be located.
+	 */
+	private boolean isOwnerVersioned(SessionImplementor session) throws MappingException {
+		return getPersister( session ).getOwnerEntityPersister().isVersioned();
+	}
+
+	private CollectionPersister getPersister(SessionImplementor session) {
+		return session.getFactory().getCollectionPersister( role );
+	}
+
+	public boolean isDirty(Object old, Object current, SessionImplementor session)
+			throws HibernateException {
+
+		// collections don't dirty an unversioned parent entity
+
+		// TODO: I don't really like this implementation; it would be better if
+		// this was handled by searchForDirtyCollections()
+		return isOwnerVersioned( session ) && super.isDirty( old, current, session );
+		// return false;
+
+	}
+
+	public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session)
+			throws HibernateException {
+		return isDirty(old, current, session);
+	}
+
+	/**
+	 * Wrap the naked collection instance in a wrapper, or instantiate a
+	 * holder. Callers <b>MUST</b> add the holder to the persistence context!
+	 *
+	 * @param session The session from which the request is originating.
+	 * @param collection The bare collection to be wrapped.
+	 * @return The wrapped collection.
+	 */
+	public abstract PersistentCollection wrap(SessionImplementor session, Object collection);
+
+	/**
+	 * Note: return true because this type is castable to <tt>AssociationType</tt>. Not because
+	 * all collections are associations.
+	 */
+	public boolean isAssociationType() {
+		return true;
+	}
+
+	public ForeignKeyDirection getForeignKeyDirection() {
+		return ForeignKeyDirection.FOREIGN_KEY_TO_PARENT;
+	}
+
+	/**
+	 * Get the key value from the owning entity instance, usually the identifier, but might be some
+	 * other unique key, in the case of property-ref
+	 *
+	 * @param owner The collection owner
+	 * @param session The session from which the request is originating.
+	 * @return The collection owner's key
+	 */
+	public Serializable getKeyOfOwner(Object owner, SessionImplementor session) {
+		
+		EntityEntry entityEntry = session.getPersistenceContext().getEntry( owner );
+		if ( entityEntry == null ) return null; // This just handles a particular case of component
+									  // projection, perhaps get rid of it and throw an exception
+		
+		if ( foreignKeyPropertyName == null ) {
+			return entityEntry.getId();
+		}
+		else {
+			// TODO: at the point where we are resolving collection references, we don't
+			// know if the uk value has been resolved (depends if it was earlier or
+			// later in the mapping document) - now, we could try and use e.getStatus()
+			// to decide to semiResolve(), trouble is that initializeEntity() reuses
+			// the same array for resolved and hydrated values
+			Object id;
+			if ( entityEntry.getLoadedState() != null ) {
+				id = entityEntry.getLoadedValue( foreignKeyPropertyName );
+			}
+			else {
+				id = entityEntry.getPersister().getPropertyValue( owner, foreignKeyPropertyName, session.getEntityMode() );
+			}
+
+			// NOTE VERY HACKISH WORKAROUND!!
+			Type keyType = getPersister( session ).getKeyType();
+			if ( !keyType.getReturnedClass().isInstance( id ) ) {
+				id = (Serializable) keyType.semiResolve(
+						entityEntry.getLoadedValue( foreignKeyPropertyName ),
+						session,
+						owner 
+					);
+			}
+
+			return (Serializable) id;
+		}
+	}
+
+	public Object hydrate(ResultSet rs, String[] name, SessionImplementor session, Object owner) {
+		// can't just return null here, since that would
+		// cause an owning component to become null
+		return NOT_NULL_COLLECTION;
+	}
+
+	public Object resolve(Object value, SessionImplementor session, Object owner)
+			throws HibernateException {
+		
+		return resolveKey( getKeyOfOwner( owner, session ), session, owner );
+	}
+	
+	private Object resolveKey(Serializable key, SessionImplementor session, Object owner) {
+		// if (key==null) throw new AssertionFailure("owner identifier unknown when re-assembling
+		// collection reference");
+		return key == null ? null : // TODO: can this case really occur??
+			getCollection( key, session, owner );
+	}
+
+	public Object semiResolve(Object value, SessionImplementor session, Object owner)
+			throws HibernateException {
+		throw new UnsupportedOperationException(
+			"collection mappings may not form part of a property-ref" );
+	}
+
+	public boolean isArrayType() {
+		return false;
+	}
+
+	public boolean useLHSPrimaryKey() {
+		return foreignKeyPropertyName == null;
+	}
+
+	public String getRHSUniqueKeyPropertyName() {
+		return null;
+	}
+
+	public Joinable getAssociatedJoinable(SessionFactoryImplementor factory)
+			throws MappingException {
+		return (Joinable) factory.getCollectionPersister( role );
+	}
+
+	public boolean isModified(Object old, Object current, boolean[] checkable, SessionImplementor session) throws HibernateException {
+		return false;
+	}
+
+	public String getAssociatedEntityName(SessionFactoryImplementor factory)
+			throws MappingException {
+		try {
+			
+			QueryableCollection collectionPersister = (QueryableCollection) factory
+					.getCollectionPersister( role );
+			
+			if ( !collectionPersister.getElementType().isEntityType() ) {
+				throw new MappingException( 
+						"collection was not an association: " + 
+						collectionPersister.getRole() 
+					);
+			}
+			
+			return collectionPersister.getElementPersister().getEntityName();
+			
+		}
+		catch (ClassCastException cce) {
+			throw new MappingException( "collection role is not queryable " + role );
+		}
+	}
+
+	/**
+	 * Replace the elements of a collection with the elements of another collection.
+	 *
+	 * @param original The 'source' of the replacement elements (where we copy from)
+	 * @param target The target of the replacement elements (where we copy to)
+	 * @param owner The owner of the collection being merged
+	 * @param copyCache The map of elements already replaced.
+	 * @param session The session from which the merge event originated.
+	 * @return The merged collection.
+	 */
+	public Object replaceElements(
+			Object original,
+			Object target,
+			Object owner,
+			Map copyCache,
+			SessionImplementor session) {
+		// TODO: does not work for EntityMode.DOM4J yet!
+		java.util.Collection result = ( java.util.Collection ) target;
+		result.clear();
+
+		// copy elements into newly empty target collection
+		Type elemType = getElementType( session.getFactory() );
+		Iterator iter = ( (java.util.Collection) original ).iterator();
+		while ( iter.hasNext() ) {
+			result.add( elemType.replace( iter.next(), null, session, owner, copyCache ) );
+		}
+
+		// if the original is a PersistentCollection, and that original
+		// was not flagged as dirty, then reset the target's dirty flag
+		// here after the copy operation.
+		// </p>
+		// One thing to be careful of here is a "bare" original collection
+		// in which case we should never ever ever reset the dirty flag
+		// on the target because we simply do not know...
+		if ( original instanceof PersistentCollection ) {
+			if ( result instanceof PersistentCollection ) {
+				if ( ! ( ( PersistentCollection ) original ).isDirty() ) {
+					( ( PersistentCollection ) result ).clearDirty();
+				}
+			}
+		}
+
+		return result;
+	}
+
+	/**
+	 * Instantiate a new "underlying" collection exhibiting the same capacity
+	 * charactersitcs and the passed "original".
+	 *
+	 * @param original The original collection.
+	 * @return The newly instantiated collection.
+	 */
+	protected Object instantiateResult(Object original) {
+		// by default just use an unanticipated capacity since we don't
+		// know how to extract the capacity to use from original here...
+		return instantiate( -1 );
+	}
+
+	/**
+	 * Instantiate an empty instance of the "underlying" collection (not a wrapper),
+	 * but with the given anticipated size (i.e. accounting for initial capacity
+	 * and perhaps load factor).
+	 *
+	 * @param anticipatedSize The anticipated size of the instaniated collection
+	 * after we are done populating it.
+	 * @return A newly instantiated collection to be wrapped.
+	 */
+	public abstract Object instantiate(int anticipatedSize);
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Object replace(
+			final Object original,
+			final Object target,
+			final SessionImplementor session,
+			final Object owner,
+			final Map copyCache) throws HibernateException {
+		if ( original == null ) {
+			return null;
+		}
+		if ( !Hibernate.isInitialized( original ) ) {
+			return target;
+		}
+
+		// for a null target, or a target which is the same as the original, we
+		// need to put the merged elements in a new collection
+		Object result = target == null || target == original ? instantiateResult( original ) : target;
+		
+		//for arrays, replaceElements() may return a different reference, since
+		//the array length might not match
+		result = replaceElements( original, result, owner, copyCache, session );
+
+		if (original==target) {
+			//get the elements back into the target
+			//TODO: this is a little inefficient, don't need to do a whole
+			//      deep replaceElements() call
+			replaceElements( result, target, owner, copyCache, session );
+			result = target;
+		}
+
+		return result;
+	}
+
+	/**
+	 * Get the Hibernate type of the collection elements
+	 *
+	 * @param factory The session factory.
+	 * @return The type of the collection elements
+	 * @throws MappingException Indicates the underlying persister could not be located.
+	 */
+	public final Type getElementType(SessionFactoryImplementor factory) throws MappingException {
+		return factory.getCollectionPersister( getRole() ).getElementType();
+	}
+
+	public String toString() {
+		return getClass().getName() + '(' + getRole() + ')';
+	}
+
+	public String getOnCondition(String alias, SessionFactoryImplementor factory, Map enabledFilters)
+			throws MappingException {
+		return getAssociatedJoinable( factory ).filterFragment( alias, enabledFilters );
+	}
+
+	/**
+	 * instantiate a collection wrapper (called when loading an object)
+	 *
+	 * @param key The collection owner key
+	 * @param session The session from which the request is originating.
+	 * @param owner The collection owner
+	 * @return The collection
+	 */
+	public Object getCollection(Serializable key, SessionImplementor session, Object owner) {
+
+		CollectionPersister persister = getPersister( session );
+		final PersistenceContext persistenceContext = session.getPersistenceContext();
+		final EntityMode entityMode = session.getEntityMode();
+
+		if (entityMode==EntityMode.DOM4J && !isEmbeddedInXML) {
+			return UNFETCHED_COLLECTION;
+		}
+		
+		// check if collection is currently being loaded
+		PersistentCollection collection = persistenceContext.getLoadContexts().locateLoadingCollection( persister, key );
+		
+		if ( collection == null ) {
+			
+			// check if it is already completely loaded, but unowned
+			collection = persistenceContext.useUnownedCollection( new CollectionKey(persister, key, entityMode) );
+			
+			if ( collection == null ) {
+				// create a new collection wrapper, to be initialized later
+				collection = instantiate( session, persister, key );
+				collection.setOwner(owner);
+	
+				persistenceContext.addUninitializedCollection( persister, collection, key );
+	
+				// some collections are not lazy:
+				if ( initializeImmediately( entityMode ) ) {
+					session.initializeCollection( collection, false );
+				}
+				else if ( !persister.isLazy() ) {
+					persistenceContext.addNonLazyCollection( collection );
+				}
+	
+				if ( hasHolder( entityMode ) ) {
+					session.getPersistenceContext().addCollectionHolder( collection );
+				}
+				
+			}
+			
+		}
+		
+		collection.setOwner(owner);
+
+		return collection.getValue();
+	}
+
+	public boolean hasHolder(EntityMode entityMode) {
+		return entityMode == EntityMode.DOM4J;
+	}
+
+	protected boolean initializeImmediately(EntityMode entityMode) {
+		return entityMode == EntityMode.DOM4J;
+	}
+
+	public String getLHSPropertyName() {
+		return foreignKeyPropertyName;
+	}
+
+	public boolean isXMLElement() {
+		return true;
+	}
+
+	public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException {
+		return xml;
+	}
+
+	public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory) 
+	throws HibernateException {
+		if ( !isEmbeddedInXML ) {
+			node.detach();
+		}
+		else {
+			replaceNode( node, (Element) value );
+		}
+	}
+	
+	/**
+	 * We always need to dirty check the collection because we sometimes 
+	 * need to incremement version number of owner and also because of 
+	 * how assemble/disassemble is implemented for uks
+	 */
+	public boolean isAlwaysDirtyChecked() {
+		return true; 
+	}
+
+	public boolean[] toColumnNullness(Object value, Mapping mapping) {
+		return ArrayHelper.EMPTY_BOOLEAN_ARRAY;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/ComponentType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/ComponentType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/ComponentType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,636 @@
+//$Id: ComponentType.java 10119 2006-07-14 00:09:19Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.dom4j.Element;
+import org.dom4j.Node;
+import org.hibernate.EntityMode;
+import org.hibernate.FetchMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.tuple.component.ComponentTuplizer;
+import org.hibernate.tuple.component.ComponentMetamodel;
+import org.hibernate.tuple.StandardProperty;
+import org.hibernate.tuple.EntityModeToTuplizerMapping;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Handles "component" mappings
+ *
+ * @author Gavin King
+ */
+public class ComponentType extends AbstractType implements AbstractComponentType {
+
+	private final String[] propertyNames;
+	private final Type[] propertyTypes;
+	private final boolean[] propertyNullability;
+	protected final int propertySpan;
+	private final CascadeStyle[] cascade;
+	private final FetchMode[] joinedFetch;
+	private final boolean isKey;
+
+	protected final EntityModeToTuplizerMapping tuplizerMapping;
+
+	public ComponentType(ComponentMetamodel metamodel) {
+		// for now, just "re-flatten" the metamodel since this is temporary stuff anyway (HHH-1907)
+		this.isKey = metamodel.isKey();
+		this.propertySpan = metamodel.getPropertySpan();
+		this.propertyNames = new String[ propertySpan ];
+		this.propertyTypes = new Type[ propertySpan ];
+		this.propertyNullability = new boolean[ propertySpan ];
+		this.cascade = new CascadeStyle[ propertySpan ];
+		this.joinedFetch = new FetchMode[ propertySpan ];
+
+		for ( int i = 0; i < propertySpan; i++ ) {
+			StandardProperty prop = metamodel.getProperty( i );
+			this.propertyNames[i] = prop.getName();
+			this.propertyTypes[i] = prop.getType();
+			this.propertyNullability[i] = prop.isNullable();
+			this.cascade[i] = prop.getCascadeStyle();
+			this.joinedFetch[i] = prop.getFetchMode();
+		}
+
+		this.tuplizerMapping = metamodel.getTuplizerMapping();
+	}
+
+	public int[] sqlTypes(Mapping mapping) throws MappingException {
+		//Not called at runtime so doesn't matter if its slow :)
+		int[] sqlTypes = new int[getColumnSpan( mapping )];
+		int n = 0;
+		for ( int i = 0; i < propertySpan; i++ ) {
+			int[] subtypes = propertyTypes[i].sqlTypes( mapping );
+			for ( int j = 0; j < subtypes.length; j++ ) {
+				sqlTypes[n++] = subtypes[j];
+			}
+		}
+		return sqlTypes;
+	}
+
+	public int getColumnSpan(Mapping mapping) throws MappingException {
+		int span = 0;
+		for ( int i = 0; i < propertySpan; i++ ) {
+			span += propertyTypes[i].getColumnSpan( mapping );
+		}
+		return span;
+	}
+
+	public final boolean isComponentType() {
+		return true;
+	}
+
+	public Class getReturnedClass() {
+		return tuplizerMapping.getTuplizer( EntityMode.POJO ).getMappedClass(); //TODO
+	}
+
+	public boolean isSame(Object x, Object y, EntityMode entityMode) throws HibernateException {
+		if ( x == y ) {
+			return true;
+		}
+		if ( x == null || y == null ) {
+			return false;
+		}
+		Object[] xvalues = getPropertyValues( x, entityMode );
+		Object[] yvalues = getPropertyValues( y, entityMode );
+		for ( int i = 0; i < propertySpan; i++ ) {
+			if ( !propertyTypes[i].isSame( xvalues[i], yvalues[i], entityMode ) ) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	public boolean isEqual(Object x, Object y, EntityMode entityMode)
+			throws HibernateException {
+		if ( x == y ) {
+			return true;
+		}
+		if ( x == null || y == null ) {
+			return false;
+		}
+		Object[] xvalues = getPropertyValues( x, entityMode );
+		Object[] yvalues = getPropertyValues( y, entityMode );
+		for ( int i = 0; i < propertySpan; i++ ) {
+			if ( !propertyTypes[i].isEqual( xvalues[i], yvalues[i], entityMode ) ) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	public boolean isEqual(Object x, Object y, EntityMode entityMode, SessionFactoryImplementor factory)
+			throws HibernateException {
+		if ( x == y ) {
+			return true;
+		}
+		if ( x == null || y == null ) {
+			return false;
+		}
+		Object[] xvalues = getPropertyValues( x, entityMode );
+		Object[] yvalues = getPropertyValues( y, entityMode );
+		for ( int i = 0; i < propertySpan; i++ ) {
+			if ( !propertyTypes[i].isEqual( xvalues[i], yvalues[i], entityMode, factory ) ) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	public int compare(Object x, Object y, EntityMode entityMode) {
+		if ( x == y ) {
+			return 0;
+		}
+		Object[] xvalues = getPropertyValues( x, entityMode );
+		Object[] yvalues = getPropertyValues( y, entityMode );
+		for ( int i = 0; i < propertySpan; i++ ) {
+			int propertyCompare = propertyTypes[i].compare( xvalues[i], yvalues[i], entityMode );
+			if ( propertyCompare != 0 ) {
+				return propertyCompare;
+			}
+		}
+		return 0;
+	}
+
+	public boolean isMethodOf(Method method) {
+		return false;
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode) {
+		int result = 17;
+		Object[] values = getPropertyValues( x, entityMode );
+		for ( int i = 0; i < propertySpan; i++ ) {
+			Object y = values[i];
+			result *= 37;
+			if ( y != null ) {
+				result += propertyTypes[i].getHashCode( y, entityMode );
+			}
+		}
+		return result;
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode, SessionFactoryImplementor factory) {
+		int result = 17;
+		Object[] values = getPropertyValues( x, entityMode );
+		for ( int i = 0; i < propertySpan; i++ ) {
+			Object y = values[i];
+			result *= 37;
+			if ( y != null ) {
+				result += propertyTypes[i].getHashCode( y, entityMode, factory );
+			}
+		}
+		return result;
+	}
+
+	public boolean isDirty(Object x, Object y, SessionImplementor session)
+			throws HibernateException {
+		if ( x == y ) {
+			return false;
+		}
+		if ( x == null || y == null ) {
+			return true;
+		}
+		EntityMode entityMode = session.getEntityMode();
+		Object[] xvalues = getPropertyValues( x, entityMode );
+		Object[] yvalues = getPropertyValues( y, entityMode );
+		for ( int i = 0; i < xvalues.length; i++ ) {
+			if ( propertyTypes[i].isDirty( xvalues[i], yvalues[i], session ) ) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public boolean isDirty(Object x, Object y, boolean[] checkable, SessionImplementor session)
+			throws HibernateException {
+		if ( x == y ) {
+			return false;
+		}
+		if ( x == null || y == null ) {
+			return true;
+		}
+		EntityMode entityMode = session.getEntityMode();
+		Object[] xvalues = getPropertyValues( x, entityMode );
+		Object[] yvalues = getPropertyValues( y, entityMode );
+		int loc = 0;
+		for ( int i = 0; i < xvalues.length; i++ ) {
+			int len = propertyTypes[i].getColumnSpan( session.getFactory() );
+			if ( len <= 1 ) {
+				final boolean dirty = ( len == 0 || checkable[loc] ) &&
+				                      propertyTypes[i].isDirty( xvalues[i], yvalues[i], session );
+				if ( dirty ) {
+					return true;
+				}
+			}
+			else {
+				boolean[] subcheckable = new boolean[len];
+				System.arraycopy( checkable, loc, subcheckable, 0, len );
+				final boolean dirty = propertyTypes[i].isDirty( xvalues[i], yvalues[i], subcheckable, session );
+				if ( dirty ) {
+					return true;
+				}
+			}
+			loc += len;
+		}
+		return false;
+	}
+
+	public boolean isModified(Object old, Object current, boolean[] checkable, SessionImplementor session)
+			throws HibernateException {
+
+		if ( current == null ) {
+			return old != null;
+		}
+		if ( old == null ) {
+			return current != null;
+		}
+		Object[] currentValues = getPropertyValues( current, session );
+		Object[] oldValues = ( Object[] ) old;
+		int loc = 0;
+		for ( int i = 0; i < currentValues.length; i++ ) {
+			int len = propertyTypes[i].getColumnSpan( session.getFactory() );
+			boolean[] subcheckable = new boolean[len];
+			System.arraycopy( checkable, loc, subcheckable, 0, len );
+			if ( propertyTypes[i].isModified( oldValues[i], currentValues[i], subcheckable, session ) ) {
+				return true;
+			}
+			loc += len;
+		}
+		return false;
+
+	}
+
+	public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
+			throws HibernateException, SQLException {
+		return resolve( hydrate( rs, names, session, owner ), session, owner );
+	}
+
+	public void nullSafeSet(PreparedStatement st, Object value, int begin, SessionImplementor session)
+			throws HibernateException, SQLException {
+
+		Object[] subvalues = nullSafeGetValues( value, session.getEntityMode() );
+
+		for ( int i = 0; i < propertySpan; i++ ) {
+			propertyTypes[i].nullSafeSet( st, subvalues[i], begin, session );
+			begin += propertyTypes[i].getColumnSpan( session.getFactory() );
+		}
+	}
+
+	public void nullSafeSet(
+			PreparedStatement st,
+			Object value,
+			int begin,
+			boolean[] settable,
+			SessionImplementor session)
+			throws HibernateException, SQLException {
+
+		Object[] subvalues = nullSafeGetValues( value, session.getEntityMode() );
+
+		int loc = 0;
+		for ( int i = 0; i < propertySpan; i++ ) {
+			int len = propertyTypes[i].getColumnSpan( session.getFactory() );
+			if ( len == 0 ) {
+				//noop
+			}
+			else if ( len == 1 ) {
+				if ( settable[loc] ) {
+					propertyTypes[i].nullSafeSet( st, subvalues[i], begin, session );
+					begin++;
+				}
+			}
+			else {
+				boolean[] subsettable = new boolean[len];
+				System.arraycopy( settable, loc, subsettable, 0, len );
+				propertyTypes[i].nullSafeSet( st, subvalues[i], begin, subsettable, session );
+				begin += ArrayHelper.countTrue( subsettable );
+			}
+			loc += len;
+		}
+	}
+
+	private Object[] nullSafeGetValues(Object value, EntityMode entityMode) throws HibernateException {
+		if ( value == null ) {
+			return new Object[propertySpan];
+		}
+		else {
+			return getPropertyValues( value, entityMode );
+		}
+	}
+
+	public Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object owner)
+			throws HibernateException, SQLException {
+
+		return nullSafeGet( rs, new String[] {name}, session, owner );
+	}
+
+	public Object getPropertyValue(Object component, int i, SessionImplementor session)
+			throws HibernateException {
+		return getPropertyValue( component, i, session.getEntityMode() );
+	}
+
+	public Object getPropertyValue(Object component, int i, EntityMode entityMode)
+			throws HibernateException {
+		return tuplizerMapping.getTuplizer( entityMode ).getPropertyValue( component, i );
+	}
+
+	public Object[] getPropertyValues(Object component, SessionImplementor session)
+			throws HibernateException {
+		return getPropertyValues( component, session.getEntityMode() );
+	}
+
+	public Object[] getPropertyValues(Object component, EntityMode entityMode)
+			throws HibernateException {
+		return tuplizerMapping.getTuplizer( entityMode ).getPropertyValues( component );
+	}
+
+	public void setPropertyValues(Object component, Object[] values, EntityMode entityMode)
+			throws HibernateException {
+		tuplizerMapping.getTuplizer( entityMode ).setPropertyValues( component, values );
+	}
+
+	public Type[] getSubtypes() {
+		return propertyTypes;
+	}
+
+	public String getName() {
+		return "component" + ArrayHelper.toString( propertyNames );
+	}
+
+	public String toLoggableString(Object value, SessionFactoryImplementor factory)
+			throws HibernateException {
+		if ( value == null ) {
+			return "null";
+		}
+		Map result = new HashMap();
+		EntityMode entityMode = tuplizerMapping.guessEntityMode( value );
+		if ( entityMode == null ) {
+			throw new ClassCastException( value.getClass().getName() );
+		}
+		Object[] values = getPropertyValues( value, entityMode );
+		for ( int i = 0; i < propertyTypes.length; i++ ) {
+			result.put( propertyNames[i], propertyTypes[i].toLoggableString( values[i], factory ) );
+		}
+		return StringHelper.unqualify( getName() ) + result.toString();
+	}
+
+	public String[] getPropertyNames() {
+		return propertyNames;
+	}
+
+	public Object deepCopy(Object component, EntityMode entityMode, SessionFactoryImplementor factory)
+			throws HibernateException {
+		if ( component == null ) {
+			return null;
+		}
+
+		Object[] values = getPropertyValues( component, entityMode );
+		for ( int i = 0; i < propertySpan; i++ ) {
+			values[i] = propertyTypes[i].deepCopy( values[i], entityMode, factory );
+		}
+
+		Object result = instantiate( entityMode );
+		setPropertyValues( result, values, entityMode );
+
+		//not absolutely necessary, but helps for some
+		//equals()/hashCode() implementations
+		ComponentTuplizer ct = ( ComponentTuplizer ) tuplizerMapping.getTuplizer( entityMode );
+		if ( ct.hasParentProperty() ) {
+			ct.setParent( result, ct.getParent( component ), factory );
+		}
+
+		return result;
+	}
+
+	public Object replace(
+			Object original,
+			Object target,
+			SessionImplementor session,
+			Object owner,
+			Map copyCache)
+			throws HibernateException {
+
+		if ( original == null ) {
+			return null;
+		}
+		//if ( original == target ) return target;
+
+		final Object result = target == null
+				? instantiate( owner, session )
+				: target;
+
+		final EntityMode entityMode = session.getEntityMode();
+		Object[] values = TypeFactory.replace(
+				getPropertyValues( original, entityMode ),
+				getPropertyValues( result, entityMode ),
+				propertyTypes,
+				session,
+				owner,
+				copyCache
+		);
+
+		setPropertyValues( result, values, entityMode );
+		return result;
+	}
+
+	public Object replace(
+			Object original,
+			Object target,
+			SessionImplementor session,
+			Object owner,
+			Map copyCache,
+			ForeignKeyDirection foreignKeyDirection)
+			throws HibernateException {
+
+		if ( original == null ) {
+			return null;
+		}
+		//if ( original == target ) return target;
+
+		final Object result = target == null ?
+				instantiate( owner, session ) :
+				target;
+
+		final EntityMode entityMode = session.getEntityMode();
+		Object[] values = TypeFactory.replace(
+				getPropertyValues( original, entityMode ),
+				getPropertyValues( result, entityMode ),
+				propertyTypes,
+				session,
+				owner,
+				copyCache,
+				foreignKeyDirection
+		);
+
+		setPropertyValues( result, values, entityMode );
+		return result;
+	}
+
+	/**
+	 * This method does not populate the component parent
+	 */
+	public Object instantiate(EntityMode entityMode) throws HibernateException {
+		return tuplizerMapping.getTuplizer( entityMode ).instantiate();
+	}
+
+	public Object instantiate(Object parent, SessionImplementor session)
+			throws HibernateException {
+
+		Object result = instantiate( session.getEntityMode() );
+
+		ComponentTuplizer ct = ( ComponentTuplizer ) tuplizerMapping.getTuplizer( session.getEntityMode() );
+		if ( ct.hasParentProperty() && parent != null ) {
+			ct.setParent(
+					result,
+					session.getPersistenceContext().proxyFor( parent ),
+					session.getFactory()
+			);
+		}
+
+		return result;
+	}
+
+	public CascadeStyle getCascadeStyle(int i) {
+		return cascade[i];
+	}
+
+	public boolean isMutable() {
+		return true;
+	}
+
+	public Serializable disassemble(Object value, SessionImplementor session, Object owner)
+			throws HibernateException {
+
+		if ( value == null ) {
+			return null;
+		}
+		else {
+			Object[] values = getPropertyValues( value, session.getEntityMode() );
+			for ( int i = 0; i < propertyTypes.length; i++ ) {
+				values[i] = propertyTypes[i].disassemble( values[i], session, owner );
+			}
+			return values;
+		}
+	}
+
+	public Object assemble(Serializable object, SessionImplementor session, Object owner)
+			throws HibernateException {
+
+		if ( object == null ) {
+			return null;
+		}
+		else {
+			Object[] values = ( Object[] ) object;
+			Object[] assembled = new Object[values.length];
+			for ( int i = 0; i < propertyTypes.length; i++ ) {
+				assembled[i] = propertyTypes[i].assemble( ( Serializable ) values[i], session, owner );
+			}
+			Object result = instantiate( owner, session );
+			setPropertyValues( result, assembled, session.getEntityMode() );
+			return result;
+		}
+	}
+
+	public FetchMode getFetchMode(int i) {
+		return joinedFetch[i];
+	}
+
+	public Object hydrate(
+			final ResultSet rs,
+			final String[] names,
+			final SessionImplementor session,
+			final Object owner)
+			throws HibernateException, SQLException {
+
+		int begin = 0;
+		boolean notNull = false;
+		Object[] values = new Object[propertySpan];
+		for ( int i = 0; i < propertySpan; i++ ) {
+			int length = propertyTypes[i].getColumnSpan( session.getFactory() );
+			String[] range = ArrayHelper.slice( names, begin, length ); //cache this
+			Object val = propertyTypes[i].hydrate( rs, range, session, owner );
+			if ( val == null ) {
+				if ( isKey ) {
+					return null; //different nullability rules for pk/fk
+				}
+			}
+			else {
+				notNull = true;
+			}
+			values[i] = val;
+			begin += length;
+		}
+
+		return notNull ? values : null;
+	}
+
+	public Object resolve(Object value, SessionImplementor session, Object owner)
+			throws HibernateException {
+
+		if ( value != null ) {
+			Object result = instantiate( owner, session );
+			Object[] values = ( Object[] ) value;
+			Object[] resolvedValues = new Object[values.length]; //only really need new array during semiresolve!
+			for ( int i = 0; i < values.length; i++ ) {
+				resolvedValues[i] = propertyTypes[i].resolve( values[i], session, owner );
+			}
+			setPropertyValues( result, resolvedValues, session.getEntityMode() );
+			return result;
+		}
+		else {
+			return null;
+		}
+	}
+
+	public Object semiResolve(Object value, SessionImplementor session, Object owner)
+			throws HibernateException {
+		//note that this implementation is kinda broken
+		//for components with many-to-one associations
+		return resolve( value, session, owner );
+	}
+
+	public boolean[] getPropertyNullability() {
+		return propertyNullability;
+	}
+
+	public boolean isXMLElement() {
+		return true;
+	}
+
+	public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException {
+		return xml;
+	}
+
+	public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory) throws HibernateException {
+		replaceNode( node, ( Element ) value );
+	}
+
+	public boolean[] toColumnNullness(Object value, Mapping mapping) {
+		boolean[] result = new boolean[ getColumnSpan( mapping ) ];
+		if ( value == null ) {
+			return result;
+		}
+		Object[] values = getPropertyValues( value, EntityMode.POJO ); //TODO!!!!!!!
+		int loc = 0;
+		for ( int i = 0; i < propertyTypes.length; i++ ) {
+			boolean[] propertyNullness = propertyTypes[i].toColumnNullness( values[i], mapping );
+			System.arraycopy( propertyNullness, 0, result, loc, propertyNullness.length );
+			loc += propertyNullness.length;
+		}
+		return result;
+	}
+
+	public boolean isEmbedded() {
+		return false;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/CompositeCustomType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/CompositeCustomType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/CompositeCustomType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,274 @@
+//$Id: CompositeCustomType.java 7670 2005-07-29 05:36:14Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map;
+import java.util.Properties;
+
+import org.dom4j.Element;
+import org.dom4j.Node;
+import org.hibernate.EntityMode;
+import org.hibernate.FetchMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.usertype.CompositeUserType;
+
+/**
+ * Adapts <tt>CompositeUserType</tt> to <tt>Type</tt> interface
+ * @author Gavin King
+ */
+public class CompositeCustomType extends AbstractType
+	implements AbstractComponentType {
+
+	private final CompositeUserType userType;
+	private final String name;
+
+	public CompositeCustomType(Class userTypeClass, Properties parameters) 
+	throws MappingException {
+		name = userTypeClass.getName();
+
+		if ( !CompositeUserType.class.isAssignableFrom(userTypeClass) ) {
+			throw new MappingException( 
+					"Custom type does not implement CompositeUserType: " + 
+					userTypeClass.getName() 
+				);
+		}
+		
+		try {
+			userType = (CompositeUserType) userTypeClass.newInstance();
+		}
+		catch (InstantiationException ie) {
+			throw new MappingException( 
+					"Cannot instantiate custom type: " + 
+					userTypeClass.getName() 
+				);
+		}
+		catch (IllegalAccessException iae) {
+			throw new MappingException( 
+					"IllegalAccessException trying to instantiate custom type: " + 
+					userTypeClass.getName() 
+				);
+		}
+		TypeFactory.injectParameters(userType, parameters);
+	}
+	
+	public boolean isMethodOf(Method method) {
+		return false;
+	}
+
+	public Type[] getSubtypes() {
+		return userType.getPropertyTypes();
+	}
+
+	public String[] getPropertyNames() {
+		return userType.getPropertyNames();
+	}
+
+	public Object[] getPropertyValues(Object component, SessionImplementor session)
+		throws HibernateException {
+		return getPropertyValues( component, session.getEntityMode() );
+	}
+
+	public Object[] getPropertyValues(Object component, EntityMode entityMode)
+		throws HibernateException {
+
+		int len = getSubtypes().length;
+		Object[] result = new Object[len];
+		for ( int i=0; i<len; i++ ) {
+			result[i] = getPropertyValue(component, i);
+		}
+		return result;
+	}
+
+	public void setPropertyValues(Object component, Object[] values, EntityMode entityMode)
+		throws HibernateException {
+
+		for (int i=0; i<values.length; i++) {
+			userType.setPropertyValue( component, i, values[i] );
+		}
+	}
+
+	public Object getPropertyValue(Object component, int i, SessionImplementor session)
+		throws HibernateException {
+		return getPropertyValue(component, i);
+	}
+
+	public Object getPropertyValue(Object component, int i)
+		throws HibernateException {
+		return userType.getPropertyValue(component, i);
+	}
+
+	public CascadeStyle getCascadeStyle(int i) {
+		return CascadeStyle.NONE;
+	}
+
+	public FetchMode getFetchMode(int i) {
+		return FetchMode.DEFAULT;
+	}
+
+	public boolean isComponentType() {
+		return true;
+	}
+
+	public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory) 
+	throws HibernateException {
+		return userType.deepCopy(value);
+	}
+
+	public Object assemble(
+		Serializable cached,
+		SessionImplementor session,
+		Object owner)
+		throws HibernateException {
+
+		return userType.assemble(cached, session, owner);
+	}
+
+	public Serializable disassemble(Object value, SessionImplementor session, Object owner)
+	throws HibernateException {
+		return userType.disassemble(value, session);
+	}
+	
+	public Object replace(
+			Object original, 
+			Object target,
+			SessionImplementor session, 
+			Object owner, 
+			Map copyCache)
+	throws HibernateException {
+		return userType.replace(original, target, session, owner);
+	}
+	
+	public boolean isEqual(Object x, Object y, EntityMode entityMode) 
+	throws HibernateException {
+		return userType.equals(x, y);
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode) {
+		return userType.hashCode(x);
+	}
+	
+	public int getColumnSpan(Mapping mapping) throws MappingException {
+		Type[] types = userType.getPropertyTypes();
+		int n=0;
+		for (int i=0; i<types.length; i++) {
+			n+=types[i].getColumnSpan(mapping);
+		}
+		return n;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public Class getReturnedClass() {
+		return userType.returnedClass();
+	}
+
+	public boolean isMutable() {
+		return userType.isMutable();
+	}
+
+	public Object nullSafeGet(
+		ResultSet rs,
+		String columnName,
+		SessionImplementor session,
+		Object owner)
+		throws HibernateException, SQLException {
+
+		return userType.nullSafeGet(rs, new String[] {columnName}, session, owner);
+	}
+
+	public Object nullSafeGet(
+		ResultSet rs,
+		String[] names,
+		SessionImplementor session,
+		Object owner)
+		throws HibernateException, SQLException {
+
+		return userType.nullSafeGet(rs, names, session, owner);
+	}
+
+	public void nullSafeSet(
+		PreparedStatement st,
+		Object value,
+		int index,
+		SessionImplementor session)
+		throws HibernateException, SQLException {
+
+		userType.nullSafeSet(st, value, index, session);
+
+	}
+
+	public void nullSafeSet(
+		PreparedStatement st,
+		Object value,
+		int index,
+		boolean[] settable, 
+		SessionImplementor session)
+		throws HibernateException, SQLException {
+
+		userType.nullSafeSet(st, value, index, session);
+
+	}
+
+	public int[] sqlTypes(Mapping mapping) throws MappingException {
+		Type[] types = userType.getPropertyTypes();
+		int[] result = new int[ getColumnSpan(mapping) ];
+		int n=0;
+		for (int i=0; i<types.length; i++) {
+			int[] sqlTypes = types[i].sqlTypes(mapping);
+			for ( int k=0; k<sqlTypes.length; k++ ) result[n++] = sqlTypes[k];
+		}
+		return result;
+	}
+	
+	public String toLoggableString(Object value, SessionFactoryImplementor factory)
+		throws HibernateException {
+
+		return value==null ? "null" : value.toString();
+	}
+
+	public boolean[] getPropertyNullability() {
+		return null;
+	}
+
+	public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException {
+		return xml;
+	}
+
+	public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory) 
+	throws HibernateException {
+		replaceNode( node, (Element) value );
+	}
+
+	public boolean[] toColumnNullness(Object value, Mapping mapping) {
+		boolean[] result = new boolean[ getColumnSpan(mapping) ];
+		if (value==null) return result;
+		Object[] values = getPropertyValues(value, EntityMode.POJO); //TODO!!!!!!!
+		int loc = 0;
+		Type[] propertyTypes = getSubtypes();
+		for ( int i=0; i<propertyTypes.length; i++ ) {
+			boolean[] propertyNullness = propertyTypes[i].toColumnNullness( values[i], mapping );
+			System.arraycopy(propertyNullness, 0, result, loc, propertyNullness.length);
+			loc += propertyNullness.length;
+		}
+		return result;
+	}
+
+	public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session) throws HibernateException {
+		return isDirty(old, current, session);
+	}
+	
+	public boolean isEmbedded() {
+		return false;
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/CurrencyType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/CurrencyType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/CurrencyType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,142 @@
+//$Id: CurrencyType.java 8173 2005-09-14 19:54:49Z oneovthafew $
+package org.hibernate.type;
+
+import java.lang.reflect.Method;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * <tt>currency</tt>: A type that maps an SQL VARCHAR to a
+ * <tt>java.util.Currency</tt>
+ * @see java.util.Currency
+ * @author Gavin King
+ */
+public class CurrencyType extends ImmutableType implements LiteralType {
+
+	public static final Class CURRENCY_CLASS;
+	private static final Method CURRENCY_GET_INSTANCE;
+	private static final Method CURRENCY_GET_CODE;
+
+	static {
+		Class clazz;
+		try {
+			clazz = Class.forName("java.util.Currency");
+		}
+		catch (ClassNotFoundException cnfe) {
+			clazz = null;
+		}
+		if (clazz==null) {
+			CURRENCY_CLASS = null;
+			CURRENCY_GET_INSTANCE = null;
+			CURRENCY_GET_CODE = null;
+		}
+		else {
+			CURRENCY_CLASS = clazz;
+			try {
+				CURRENCY_GET_INSTANCE = clazz.getMethod("getInstance", new Class[] { String.class } );
+				CURRENCY_GET_CODE = clazz.getMethod("getCurrencyCode", new Class[0] );
+			}
+			catch (Exception e) {
+				throw new AssertionFailure("Exception in static initializer of CurrencyType", e);
+			}
+		}
+	}
+
+	/**
+	 * @see org.hibernate.type.NullableType#get(ResultSet, String)
+	 */
+	public Object get(ResultSet rs, String name)
+	throws HibernateException, SQLException {
+		String code = (String) Hibernate.STRING.nullSafeGet(rs, name);
+		try {
+			return code==null ? null : 
+					CURRENCY_GET_INSTANCE.invoke(null, new Object[] { code } );
+		}
+		catch (Exception e) {
+			throw new HibernateException("Could not resolve currency code: " + code);
+		}
+	}
+
+	/**
+	 * @see org.hibernate.type.NullableType#set(PreparedStatement, Object, int)
+	 */
+	public void set(PreparedStatement st, Object value, int index)
+	throws HibernateException, SQLException {
+		Object code;
+		try {
+			code = CURRENCY_GET_CODE.invoke(value, null);
+		}
+		catch (Exception e) {
+			throw new HibernateException("Could not get Currency code", e);
+		}
+		Hibernate.STRING.set(st, code, index);
+	}
+
+	/**
+	 * @see org.hibernate.type.NullableType#sqlType()
+	 */
+	public int sqlType() {
+		return Hibernate.STRING.sqlType();
+	}
+
+	/**
+	 */
+	public String toString(Object value) throws HibernateException {
+		try {
+			return (String) CURRENCY_GET_CODE.invoke(value, null);
+		}
+		catch (Exception e) {
+			throw new HibernateException("Could not get Currency code", e);
+		}
+	}
+
+	/**
+	 * @see org.hibernate.type.Type#getReturnedClass()
+	 */
+	public Class getReturnedClass() {
+		return CURRENCY_CLASS;
+	}
+
+	/**
+	 * @see org.hibernate.type.Type#getName()
+	 */
+	public String getName() {
+		return "currency";
+	}
+
+	/**
+	 * @see org.hibernate.type.LiteralType#objectToSQLString(Object, Dialect)
+	 */
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		String code;
+		try {
+			code = (String) CURRENCY_GET_CODE.invoke(value, null);
+		}
+		catch (Exception e) {
+			throw new HibernateException("Could not get Currency code", e);
+		}
+		return ( (LiteralType) Hibernate.STRING ).objectToSQLString(code, dialect);
+	}
+
+	public Object fromStringValue(String xml) throws HibernateException {
+		try {
+			return CURRENCY_GET_INSTANCE.invoke( null, new Object[] {xml} );
+		}
+		catch (Exception e) {
+			throw new HibernateException("Could not resolve currency code: " + xml);
+		}
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/CustomCollectionType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/CustomCollectionType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/CustomCollectionType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,94 @@
+//$Id: CustomCollectionType.java 11496 2007-05-09 03:54:06Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.usertype.UserCollectionType;
+import org.hibernate.usertype.LoggableUserType;
+
+/**
+ * A custom type for mapping user-written classes that implement <tt>PersistentCollection</tt>
+ * 
+ * @see org.hibernate.collection.PersistentCollection
+ * @see org.hibernate.usertype.UserCollectionType
+ * @author Gavin King
+ */
+public class CustomCollectionType extends CollectionType {
+
+	private final UserCollectionType userType;
+	private final boolean customLogging;
+
+	public CustomCollectionType(Class userTypeClass, String role, String foreignKeyPropertyName, boolean isEmbeddedInXML) {
+		super(role, foreignKeyPropertyName, isEmbeddedInXML);
+
+		if ( !UserCollectionType.class.isAssignableFrom( userTypeClass ) ) {
+			throw new MappingException( "Custom type does not implement UserCollectionType: " + userTypeClass.getName() );
+		}
+
+		try {
+			userType = ( UserCollectionType ) userTypeClass.newInstance();
+		}
+		catch ( InstantiationException ie ) {
+			throw new MappingException( "Cannot instantiate custom type: " + userTypeClass.getName() );
+		}
+		catch ( IllegalAccessException iae ) {
+			throw new MappingException( "IllegalAccessException trying to instantiate custom type: " + userTypeClass.getName() );
+		}
+
+		customLogging = LoggableUserType.class.isAssignableFrom( userTypeClass );
+	}
+
+	public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister, Serializable key)
+	throws HibernateException {
+		return userType.instantiate(session, persister);
+	}
+
+	public PersistentCollection wrap(SessionImplementor session, Object collection) {
+		return userType.wrap(session, collection);
+	}
+
+	public Class getReturnedClass() {
+		return userType.instantiate( -1 ).getClass();
+	}
+
+	public Object instantiate(int anticipatedType) {
+		return userType.instantiate( anticipatedType );
+	}
+
+	public Iterator getElementsIterator(Object collection) {
+		return userType.getElementsIterator(collection);
+	}
+	public boolean contains(Object collection, Object entity, SessionImplementor session) {
+		return userType.contains(collection, entity);
+	}
+	public Object indexOf(Object collection, Object entity) {
+		return userType.indexOf(collection, entity);
+	}
+
+	public Object replaceElements(Object original, Object target, Object owner, Map copyCache, SessionImplementor session)
+	throws HibernateException {
+		CollectionPersister cp = session.getFactory().getCollectionPersister( getRole() );
+		return userType.replaceElements(original, target, cp, owner, copyCache, session);
+	}
+
+	protected String renderLoggableString(Object value, SessionFactoryImplementor factory) throws HibernateException {
+		if ( customLogging ) {
+			return ( ( LoggableUserType ) userType ).toLoggableString( value, factory );
+		}
+		else {
+			return super.renderLoggableString( value, factory );
+		}
+	}
+
+	public UserCollectionType getUserType() {
+		return userType;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/type/CustomCollectionType.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/CustomType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/CustomType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/CustomType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,238 @@
+//$Id: CustomType.java 10084 2006-07-05 15:03:52Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Properties;
+
+import org.dom4j.Node;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.usertype.EnhancedUserType;
+import org.hibernate.usertype.UserType;
+import org.hibernate.usertype.UserVersionType;
+import org.hibernate.usertype.LoggableUserType;
+
+/**
+ * Adapts {@link UserType} to the generic {@link Type} interface, in order
+ * to isolate user code from changes in the internal Type contracts.
+ *
+ * @see org.hibernate.usertype.UserType
+ * @author Gavin King
+ */
+public class CustomType extends AbstractType implements IdentifierType, DiscriminatorType, VersionType {
+
+	private final UserType userType;
+	private final String name;
+	private final int[] types;
+	private final boolean customLogging;
+
+	public CustomType(Class userTypeClass, Properties parameters) throws MappingException {
+
+		if ( !UserType.class.isAssignableFrom( userTypeClass ) ) {
+			throw new MappingException(
+					"Custom type does not implement UserType: " +
+					userTypeClass.getName()
+				);
+		}
+
+		name = userTypeClass.getName();
+
+		try {
+			userType = ( UserType ) userTypeClass.newInstance();
+		}
+		catch ( InstantiationException ie ) {
+			throw new MappingException(
+					"Cannot instantiate custom type: " +
+					userTypeClass.getName()
+				);
+		}
+		catch ( IllegalAccessException iae ) {
+			throw new MappingException(
+					"IllegalAccessException trying to instantiate custom type: " +
+					userTypeClass.getName()
+				);
+		}
+
+        TypeFactory.injectParameters( userType, parameters );
+		types = userType.sqlTypes();
+
+		customLogging = LoggableUserType.class.isAssignableFrom( userTypeClass );
+	}
+
+	public int[] sqlTypes(Mapping pi) {
+		return types;
+	}
+
+	public int getColumnSpan(Mapping session) {
+		return types.length;
+	}
+
+	public Class getReturnedClass() {
+		return userType.returnedClass();
+	}
+
+	public boolean isEqual(Object x, Object y) throws HibernateException {
+		return userType.equals(x, y);
+	}
+
+	public boolean isEqual(Object x, Object y, EntityMode entityMode)
+	throws HibernateException {
+		return isEqual(x, y);
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode) {
+		return userType.hashCode(x);
+	}
+
+	public Object nullSafeGet(
+		ResultSet rs,
+		String[] names,
+		SessionImplementor session,
+		Object owner
+	) throws HibernateException, SQLException {
+
+		return userType.nullSafeGet(rs, names, owner);
+	}
+
+	public Object nullSafeGet(
+		ResultSet rs,
+		String columnName,
+		SessionImplementor session,
+		Object owner
+	) throws HibernateException, SQLException {
+		return nullSafeGet(rs, new String[] { columnName }, session, owner);
+	}
+
+
+	public Object assemble(Serializable cached, SessionImplementor session, Object owner)
+	throws HibernateException {
+		return userType.assemble(cached, owner);
+	}
+
+	public Serializable disassemble(Object value, SessionImplementor session, Object owner)
+	throws HibernateException {
+		return userType.disassemble(value);
+	}
+
+	public Object replace(
+			Object original,
+			Object target,
+			SessionImplementor session,
+			Object owner,
+			Map copyCache)
+	throws HibernateException {
+		return userType.replace(original, target, owner);
+	}
+
+	public void nullSafeSet(
+		PreparedStatement st,
+		Object value,
+		int index,
+		boolean[] settable,
+		SessionImplementor session
+	) throws HibernateException, SQLException {
+
+		if ( settable[0] ) userType.nullSafeSet(st, value, index);
+	}
+
+	public void nullSafeSet(
+		PreparedStatement st,
+		Object value,
+		int index,
+		SessionImplementor session
+	) throws HibernateException, SQLException {
+
+		userType.nullSafeSet(st, value, index);
+	}
+
+	public String toXMLString(Object value, SessionFactoryImplementor factory) {
+		if (value==null) return null;
+		if (userType instanceof EnhancedUserType) {
+			return ( (EnhancedUserType) userType ).toXMLString(value);
+		}
+		else {
+			return value.toString();
+		}
+	}
+
+	public Object fromXMLString(String xml, Mapping factory) {
+		return ( (EnhancedUserType) userType ).fromXMLString(xml);
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory)
+	throws HibernateException {
+		return userType.deepCopy(value);
+	}
+
+	public boolean isMutable() {
+		return userType.isMutable();
+	}
+
+	public Object stringToObject(String xml) {
+		return ( (EnhancedUserType) userType ).fromXMLString(xml);
+	}
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return ( (EnhancedUserType) userType ).objectToSQLString(value);
+	}
+
+	public Comparator getComparator() {
+		return (Comparator) userType;
+	}
+
+	public Object next(Object current, SessionImplementor session) {
+		return ( (UserVersionType) userType ).next( current, session );
+	}
+
+	public Object seed(SessionImplementor session) {
+		return ( (UserVersionType) userType ).seed( session );
+	}
+
+	public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException {
+		return fromXMLString( xml.getText(), factory );
+	}
+
+	public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory)
+	throws HibernateException {
+		node.setText( toXMLString(value, factory) );
+	}
+
+	public String toLoggableString(Object value, SessionFactoryImplementor factory)
+	throws HibernateException {
+		if ( value == null ) {
+			return "null";
+		}
+		else if ( customLogging ) {
+			return ( ( LoggableUserType ) userType ).toLoggableString( value, factory );
+		}
+		else {
+			return toXMLString( value, factory );
+		}
+	}
+
+	public boolean[] toColumnNullness(Object value, Mapping mapping) {
+		boolean[] result = new boolean[ getColumnSpan(mapping) ];
+		if (value!=null) Arrays.fill(result, true);
+		return result;
+	}
+
+	public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session) throws HibernateException {
+		return checkable[0] && isDirty(old, current, session);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/DateType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/DateType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/DateType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,107 @@
+//$Id: DateType.java 8891 2005-12-21 05:13:29Z oneovthafew $
+package org.hibernate.type;
+
+import java.sql.Date;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+import org.hibernate.EntityMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * <tt>date</tt>: A type that maps an SQL DATE to a Java Date.
+ * @author Gavin King
+ */
+public class DateType extends MutableType implements IdentifierType, LiteralType {
+
+	private static final String DATE_FORMAT = "dd MMMM yyyy";
+
+	public Object get(ResultSet rs, String name) throws SQLException {
+		return rs.getDate(name);
+	}
+
+	public Class getReturnedClass() {
+		return java.util.Date.class;
+	}
+
+	public void set(PreparedStatement st, Object value, int index) throws SQLException {
+
+		Date sqlDate;
+		if ( value instanceof Date) {
+			sqlDate = (Date) value;
+		}
+		else {
+			sqlDate = new Date( ( (java.util.Date) value ).getTime() );
+		}
+		st.setDate(index, sqlDate);
+	}
+
+	public int sqlType() {
+		return Types.DATE;
+	}
+
+	public boolean isEqual(Object x, Object y) {
+
+		if (x==y) return true;
+		if (x==null || y==null) return false;
+
+		java.util.Date xdate = (java.util.Date) x;
+		java.util.Date ydate = (java.util.Date) y;
+		
+		if ( xdate.getTime()==ydate.getTime() ) return true;
+		
+		Calendar calendar1 = java.util.Calendar.getInstance();
+		Calendar calendar2 = java.util.Calendar.getInstance();
+		calendar1.setTime( xdate );
+		calendar2.setTime( ydate );
+
+		return Hibernate.CALENDAR_DATE.isEqual(calendar1, calendar2);
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode) {
+		Calendar calendar = java.util.Calendar.getInstance();
+		calendar.setTime( (java.util.Date) x );
+		return Hibernate.CALENDAR_DATE.getHashCode(calendar, entityMode);
+	}
+	
+	public String getName() { return "date"; }
+
+	public String toString(Object val) {
+		return new SimpleDateFormat(DATE_FORMAT).format( (java.util.Date) val );
+	}
+
+	public Object deepCopyNotNull(Object value) {
+		return new Date( ( (java.util.Date) value ).getTime() );
+	}
+
+	public Object stringToObject(String xml) throws Exception {
+		return DateFormat.getDateInstance().parse(xml);
+	}
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return '\'' + new Date( ( (java.util.Date) value ).getTime() ).toString() + '\'';
+	}
+
+	public Object fromStringValue(String xml) throws HibernateException {
+		try {
+			return new SimpleDateFormat(DATE_FORMAT).parse(xml);
+		}
+		catch (ParseException pe) {
+			throw new HibernateException("could not parse XML", pe);
+		}
+	}
+	
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/DbTimestampType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/DbTimestampType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/DbTimestampType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,130 @@
+// $Id: DbTimestampType.java 7830 2005-08-11 00:10:26Z oneovthafew $
+package org.hibernate.type;
+
+import java.sql.Timestamp;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.ResultSet;
+import java.sql.CallableStatement;
+
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.exception.JDBCExceptionHelper;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * <tt>dbtimestamp</tt>: An extension of {@link TimestampType} which
+ * maps to the database's current timestamp, rather than the jvm's
+ * current timestamp.
+ * <p/>
+ * Note: May/may-not cause issues on dialects which do not properly support
+ * a true notion of timestamp (Oracle < 8, for example, where only its DATE
+ * datatype is supported).  Depends on the frequency of DML operations...
+ *
+ * @author Steve Ebersole
+ */
+public class DbTimestampType extends TimestampType implements VersionType {
+
+	private static final Log log = LogFactory.getLog( DbTimestampType.class );
+	
+	public String getName() { return "dbtimestamp"; }
+
+	public Object seed(SessionImplementor session) {
+		if ( session == null ) {
+			log.trace( "incoming session was null; using current jvm time" );
+			return super.seed( session );
+		}
+		else if ( !session.getFactory().getDialect().supportsCurrentTimestampSelection() ) {
+			log.debug( "falling back to vm-based timestamp, as dialect does not support current timestamp selection" );
+			return super.seed( session );
+		}
+		else {
+			return getCurrentTimestamp( session );
+		}
+	}
+
+	private Timestamp getCurrentTimestamp(SessionImplementor session) {
+		Dialect dialect = session.getFactory().getDialect();
+		String timestampSelectString = dialect.getCurrentTimestampSelectString();
+		if ( dialect.isCurrentTimestampSelectStringCallable() ) {
+			return useCallableStatement( timestampSelectString, session );
+		}
+		else {
+			return usePreparedStatement( timestampSelectString, session );
+		}
+	}
+
+	private Timestamp usePreparedStatement(String timestampSelectString, SessionImplementor session) {
+		PreparedStatement ps = null;
+		try {
+			ps = session.getBatcher().prepareStatement( timestampSelectString );
+			ResultSet rs = session.getBatcher().getResultSet( ps );
+			rs.next();
+			Timestamp ts = rs.getTimestamp( 1 );
+			if ( log.isTraceEnabled() ) {
+				log.trace(
+				        "current timestamp retreived from db : " + ts +
+				        " (nanos=" + ts.getNanos() +
+				        ", time=" + ts.getTime() + ")"
+					);
+			}
+			return ts;
+		}
+		catch( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+			        session.getFactory().getSQLExceptionConverter(),
+			        sqle,
+			        "could not select current db timestamp",
+			        timestampSelectString
+				);
+		}
+		finally {
+			if ( ps != null ) {
+				try {
+					session.getBatcher().closeStatement( ps );
+				}
+				catch( SQLException sqle ) {
+					log.warn( "unable to clean up prepared statement", sqle );
+				}
+			}
+		}
+	}
+
+	private Timestamp useCallableStatement(String callString, SessionImplementor session) {
+		CallableStatement cs = null;
+		try {
+			cs = session.getBatcher().prepareCallableStatement( callString );
+			cs.registerOutParameter( 1, java.sql.Types.TIMESTAMP );
+			cs.execute();
+			Timestamp ts = cs.getTimestamp( 1 );
+			if ( log.isTraceEnabled() ) {
+				log.trace(
+				        "current timestamp retreived from db : " + ts +
+				        " (nanos=" + ts.getNanos() +
+				        ", time=" + ts.getTime() + ")"
+					);
+			}
+			return ts;
+		}
+		catch( SQLException sqle ) {
+			throw JDBCExceptionHelper.convert(
+			        session.getFactory().getSQLExceptionConverter(),
+			        sqle,
+			        "could not call current db timestamp function",
+			        callString
+				);
+		}
+		finally {
+			if ( cs != null ) {
+				try {
+					session.getBatcher().closeStatement( cs );
+				}
+				catch( SQLException sqle ) {
+					log.warn( "unable to clean up callable statement", sqle );
+				}
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/DiscriminatorType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/DiscriminatorType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/DiscriminatorType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+//$Id: DiscriminatorType.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.type;
+
+/**
+ * A <tt>Type</tt> that may be used for a discriminator column.
+ * @author Gavin King
+ */
+public interface DiscriminatorType extends IdentifierType, LiteralType {
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/DoubleType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/DoubleType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/DoubleType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+//$Id: DoubleType.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.type;
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.dialect.Dialect;
+
+/**
+ * <tt>double</tt>: A type that maps an SQL DOUBLE to a Java Double.
+ * @author Gavin King
+ */
+public class DoubleType extends PrimitiveType {
+
+	public Serializable getDefaultValue() {
+		return new Double(0.0);
+	}
+	
+	public Object get(ResultSet rs, String name) throws SQLException {
+		return new Double( rs.getDouble(name) );
+	}
+
+	public Class getPrimitiveClass() {
+		return double.class;
+	}
+
+	public Class getReturnedClass() {
+		return Double.class;
+	}
+
+	public void set(PreparedStatement st, Object value, int index)
+		throws SQLException {
+
+		st.setDouble( index, ( (Double) value ).doubleValue() );
+	}
+
+	public int sqlType() {
+		return Types.DOUBLE;
+	}
+	public String getName() { return "double"; }
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return value.toString();
+	}
+
+	public Object fromStringValue(String xml) {
+		return new Double(xml);
+	}
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/EmbeddedComponentType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/EmbeddedComponentType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/EmbeddedComponentType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+//$Id: EmbeddedComponentType.java 10119 2006-07-14 00:09:19Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.lang.reflect.Method;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.tuple.component.ComponentTuplizer;
+import org.hibernate.tuple.component.ComponentMetamodel;
+
+/**
+ * @author Gavin King
+ */
+public class EmbeddedComponentType extends ComponentType {
+
+	public boolean isEmbedded() {
+		return true;
+	}
+
+	public EmbeddedComponentType(ComponentMetamodel metamodel) {
+		super( metamodel );
+	}
+
+	public boolean isMethodOf(Method method) {
+		return ( ( ComponentTuplizer ) tuplizerMapping.getTuplizer(EntityMode.POJO) ).isMethodOf(method);
+	}
+
+	public Object instantiate(Object parent, SessionImplementor session)
+	throws HibernateException {
+		final boolean useParent = parent!=null &&
+		                          //TODO: Yuck! This is not quite good enough, it's a quick
+		                          //hack around the problem of having a to-one association
+		                          //that refers to an embedded component:
+		                          super.getReturnedClass().isInstance(parent);
+
+		return useParent ? parent : super.instantiate(parent, session);
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/type/EmbeddedComponentType.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/EntityType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/EntityType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/EntityType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,613 @@
+//$Id: EntityType.java 10777 2006-11-08 22:02:28Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map;
+
+import org.dom4j.Element;
+import org.dom4j.Node;
+import org.hibernate.AssertionFailure;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.EntityUniqueKey;
+import org.hibernate.engine.ForeignKeys;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.persister.entity.Joinable;
+import org.hibernate.persister.entity.UniqueKeyLoadable;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+import org.hibernate.tuple.ElementWrapper;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * Base for types which map associations to persistent entities.
+ *
+ * @author Gavin King
+ */
+public abstract class EntityType extends AbstractType implements AssociationType {
+
+	private final String associatedEntityName;
+	protected final String uniqueKeyPropertyName;
+	protected final boolean isEmbeddedInXML;
+	private final boolean eager;
+	private final boolean unwrapProxy;
+
+	private transient Class returnedClass;
+
+	/**
+	 * Constructs the requested entity type mapping.
+	 *
+	 * @param entityName The name of the associated entity.
+	 * @param uniqueKeyPropertyName The property-ref name, or null if we
+	 * reference the PK of the associated entity.
+	 * @param eager Is eager fetching enabled.
+	 * @param isEmbeddedInXML Should values of this mapping be embedded in XML modes?
+	 * @param unwrapProxy Is unwrapping of proxies allowed for this association; unwrapping
+	 * says to return the "implementation target" of lazy prooxies; typically only possible
+	 * with lazy="no-proxy".
+	 */
+	protected EntityType(
+			String entityName,
+			String uniqueKeyPropertyName,
+			boolean eager,
+			boolean isEmbeddedInXML,
+			boolean unwrapProxy) {
+		this.associatedEntityName = entityName;
+		this.uniqueKeyPropertyName = uniqueKeyPropertyName;
+		this.isEmbeddedInXML = isEmbeddedInXML;
+		this.eager = eager;
+		this.unwrapProxy = unwrapProxy;
+	}
+
+	/**
+	 * An entity type is a type of association type
+	 *
+	 * @return True.
+	 */
+	public boolean isAssociationType() {
+		return true;
+	}
+
+	/**
+	 * Explicitly, an entity type is an entity type ;)
+	 *
+	 * @return True.
+	 */
+	public final boolean isEntityType() {
+		return true;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public boolean isMutable() {
+		return false;
+	}
+
+	/**
+	 * Generates a string representation of this type.
+	 *
+	 * @return string rep
+	 */
+	public String toString() {
+		return getClass().getName() + '(' + getAssociatedEntityName() + ')';
+	}
+
+	/**
+	 * For entity types, the name correlates to the associated entity name.
+	 */
+	public String getName() {
+		return associatedEntityName;
+	}
+
+	/**
+	 * Does this association foreign key reference the primary key of the other table?
+	 * Otherwise, it references a property-ref.
+	 *
+	 * @return True if this association reference the PK of the associated entity.
+	 */
+	public boolean isReferenceToPrimaryKey() {
+		return uniqueKeyPropertyName==null;
+	}
+
+	public String getRHSUniqueKeyPropertyName() {
+		return uniqueKeyPropertyName;
+	}
+
+	public String getLHSPropertyName() {
+		return null;
+	}
+
+	public String getPropertyName() {
+		return null;
+	}
+
+	/**
+	 * The name of the associated entity.
+	 *
+	 * @return The associated entity name.
+	 */
+	public final String getAssociatedEntityName() {
+		return associatedEntityName;
+	}
+
+	/**
+	 * The name of the associated entity.
+	 *
+	 * @param factory The session factory, for resolution.
+	 * @return The associated entity name.
+	 */
+	public String getAssociatedEntityName(SessionFactoryImplementor factory) {
+		return getAssociatedEntityName();
+	}
+
+	/**
+	 * Retrieves the {@link Joinable} defining the associated entity.
+	 *
+	 * @param factory The session factory.
+	 * @return The associated joinable
+	 * @throws MappingException Generally indicates an invalid entity name.
+	 */
+	public Joinable getAssociatedJoinable(SessionFactoryImplementor factory) throws MappingException {
+		return ( Joinable ) factory.getEntityPersister( associatedEntityName );
+	}
+
+	/**
+	 * This returns the wrong class for an entity with a proxy, or for a named
+	 * entity.  Theoretically it should return the proxy class, but it doesn't.
+	 * <p/>
+	 * The problem here is that we do not necessarily have a ref to the associated
+	 * entity persister (nor to the session factory, to look it up) which is really
+	 * needed to "do the right thing" here...
+	 *
+	 * @return The entiyt class.
+	 */
+	public final Class getReturnedClass() {
+		if ( returnedClass == null ) {
+			returnedClass = determineAssociatedEntityClass();
+		}
+		return returnedClass;
+	}
+
+	private Class determineAssociatedEntityClass() {
+		try {
+			return ReflectHelper.classForName( getAssociatedEntityName() );
+		}
+		catch ( ClassNotFoundException cnfe ) {
+			return java.util.Map.class;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object owner)
+	throws HibernateException, SQLException {
+		return nullSafeGet( rs, new String[] {name}, session, owner );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public final Object nullSafeGet(
+			ResultSet rs,
+			String[] names,
+			SessionImplementor session,
+			Object owner) throws HibernateException, SQLException {
+		return resolve( hydrate(rs, names, session, owner), session, owner );
+	}
+
+	/**
+	 * Two entities are considered the same when their instances are the same.
+	 *
+	 * @param x One entity instance
+	 * @param y Another entity instance
+	 * @param entityMode The entity mode.
+	 * @return True if x == y; false otherwise.
+	 */
+	public final boolean isSame(Object x, Object y, EntityMode entityMode) {
+		return x == y;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public int compare(Object x, Object y, EntityMode entityMode) {
+		return 0; //TODO: entities CAN be compared, by PK, fix this! -> only if/when we can extract the id values....
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory) {
+		return value; //special case ... this is the leaf of the containment graph, even though not immutable
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Object replace(
+			Object original,
+			Object target,
+			SessionImplementor session,
+			Object owner,
+			Map copyCache) throws HibernateException {
+		if ( original == null ) {
+			return null;
+		}
+		Object cached = copyCache.get(original);
+		if ( cached != null ) {
+			return cached;
+		}
+		else {
+			if ( original == target ) {
+				return target;
+			}
+			Object id = getIdentifier( original, session );
+			if ( id == null ) {
+				throw new AssertionFailure("cannot copy a reference to an object with a null id");
+			}
+			id = getIdentifierOrUniqueKeyType( session.getFactory() )
+					.replace(id, null, session, owner, copyCache);
+			return resolve( id, session, owner );
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public int getHashCode(Object x, EntityMode entityMode, SessionFactoryImplementor factory) {
+		EntityPersister persister = factory.getEntityPersister(associatedEntityName);
+		if ( !persister.canExtractIdOutOfEntity() ) {
+			return super.getHashCode(x, entityMode);
+		}
+
+		final Serializable id;
+		if (x instanceof HibernateProxy) {
+			id = ( (HibernateProxy) x ).getHibernateLazyInitializer().getIdentifier();
+		}
+		else {
+			id = persister.getIdentifier(x, entityMode);
+		}
+		return persister.getIdentifierType().getHashCode(id, entityMode, factory);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public boolean isEqual(Object x, Object y, EntityMode entityMode, SessionFactoryImplementor factory) {
+		EntityPersister persister = factory.getEntityPersister(associatedEntityName);
+		if ( !persister.canExtractIdOutOfEntity() ) {
+			return super.isEqual(x, y, entityMode);
+		}
+
+		Serializable xid;
+		if (x instanceof HibernateProxy) {
+			xid = ( (HibernateProxy) x ).getHibernateLazyInitializer()
+					.getIdentifier();
+		}
+		else {
+			xid = persister.getIdentifier(x, entityMode);
+		}
+
+		Serializable yid;
+		if (y instanceof HibernateProxy) {
+			yid = ( (HibernateProxy) y ).getHibernateLazyInitializer()
+					.getIdentifier();
+		}
+		else {
+			yid = persister.getIdentifier(y, entityMode);
+		}
+
+		return persister.getIdentifierType()
+				.isEqual(xid, yid, entityMode, factory);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public boolean isEmbeddedInXML() {
+		return isEmbeddedInXML;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public boolean isXMLElement() {
+		return isEmbeddedInXML;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException {
+		if ( !isEmbeddedInXML ) {
+			return getIdentifierType(factory).fromXMLNode(xml, factory);
+		}
+		else {
+			return xml;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory) throws HibernateException {
+		if ( !isEmbeddedInXML ) {
+			getIdentifierType(factory).setToXMLNode(node, value, factory);
+		}
+		else {
+			Element elt = (Element) value;
+			replaceNode( node, new ElementWrapper(elt) );
+		}
+	}
+
+	public String getOnCondition(String alias, SessionFactoryImplementor factory, Map enabledFilters)
+	throws MappingException {
+		if ( isReferenceToPrimaryKey() ) { //TODO: this is a bit arbitrary, expose a switch to the user?
+			return "";
+		}
+		else {
+			return getAssociatedJoinable( factory ).filterFragment( alias, enabledFilters );
+		}
+	}
+
+	/**
+	 * Resolve an identifier or unique key value
+	 */
+	public Object resolve(Object value, SessionImplementor session, Object owner) throws HibernateException {
+		if ( isNotEmbedded( session ) ) {
+			return value;
+		}
+
+		if ( value == null ) {
+			return null;
+		}
+		else {
+			if ( isNull( owner, session ) ) {
+				return null; //EARLY EXIT!
+			}
+
+			if ( isReferenceToPrimaryKey() ) {
+				return resolveIdentifier( (Serializable) value, session );
+			}
+			else {
+				return loadByUniqueKey( getAssociatedEntityName(), uniqueKeyPropertyName, value, session );
+			}
+		}
+	}
+
+	public Type getSemiResolvedType(SessionFactoryImplementor factory) {
+		return factory.getEntityPersister( associatedEntityName ).getIdentifierType();
+	}
+
+	protected final Object getIdentifier(Object value, SessionImplementor session) throws HibernateException {
+		if ( isNotEmbedded(session) ) {
+			return value;
+		}
+
+		if ( isReferenceToPrimaryKey() ) {
+			return ForeignKeys.getEntityIdentifierIfNotUnsaved( getAssociatedEntityName(), value, session ); //tolerates nulls
+		}
+		else if ( value == null ) {
+			return null;
+		}
+		else {
+			EntityPersister entityPersister = session.getFactory().getEntityPersister( getAssociatedEntityName() );
+			Object propertyValue = entityPersister.getPropertyValue( value, uniqueKeyPropertyName, session.getEntityMode() );
+			// We now have the value of the property-ref we reference.  However,
+			// we need to dig a little deeper, as that property might also be
+			// an entity type, in which case we need to resolve its identitifier
+			Type type = entityPersister.getPropertyType( uniqueKeyPropertyName );
+			if ( type.isEntityType() ) {
+				propertyValue = ( ( EntityType ) type ).getIdentifier( propertyValue, session );
+			}
+
+			return propertyValue;
+		}
+	}
+
+	protected boolean isNotEmbedded(SessionImplementor session) {
+		return !isEmbeddedInXML && session.getEntityMode()==EntityMode.DOM4J;
+	}
+
+	/**
+	 * Get the identifier value of an instance or proxy.
+	 * <p/>
+	 * Intended only for loggin purposes!!!
+	 *
+	 * @param object The object from which to extract the identifier.
+	 * @param persister The entity persister
+	 * @param entityMode The entity mode
+	 * @return The extracted identifier.
+	 */
+	private static Serializable getIdentifier(Object object, EntityPersister persister, EntityMode entityMode) {
+		if (object instanceof HibernateProxy) {
+			HibernateProxy proxy = (HibernateProxy) object;
+			LazyInitializer li = proxy.getHibernateLazyInitializer();
+			return li.getIdentifier();
+		}
+		else {
+			return persister.getIdentifier( object, entityMode );
+		}
+	}
+
+	/**
+	 * Generate a loggable representation of an instance of the value mapped by this type.
+	 *
+	 * @param value The instance to be logged.
+	 * @param factory The session factory.
+	 * @return The loggable string.
+	 * @throws HibernateException Generally some form of resolution problem.
+	 */
+	public String toLoggableString(Object value, SessionFactoryImplementor factory) {
+		if ( value == null ) {
+			return "null";
+		}
+
+		EntityPersister persister = factory.getEntityPersister( associatedEntityName );
+		StringBuffer result = new StringBuffer().append( associatedEntityName );
+
+		if ( persister.hasIdentifierProperty() ) {
+			final EntityMode entityMode = persister.guessEntityMode( value );
+			final Serializable id;
+			if ( entityMode == null ) {
+				if ( isEmbeddedInXML ) {
+					throw new ClassCastException( value.getClass().getName() );
+				}
+				id = ( Serializable ) value;
+			}
+			else {
+				id = getIdentifier( value, persister, entityMode );
+			}
+
+			result.append( '#' )
+				.append( persister.getIdentifierType().toLoggableString( id, factory ) );
+		}
+
+		return result.toString();
+	}
+
+	public abstract boolean isOneToOne();
+
+	/**
+	 * Convenience method to locate the identifier type of the associated entity.
+	 *
+	 * @param factory The mappings...
+	 * @return The identifier type
+	 */
+	Type getIdentifierType(Mapping factory) {
+		return factory.getIdentifierType( getAssociatedEntityName() );
+	}
+
+	/**
+	 * Convenience method to locate the identifier type of the associated entity.
+	 *
+	 * @param session The originating session
+	 * @return The identifier type
+	 */
+	Type getIdentifierType(SessionImplementor session) {
+		return getIdentifierType( session.getFactory() );
+	}
+
+	/**
+	 * Determine the type of either (1) the identifier if we reference the
+	 * associated entity's PK or (2) the unique key to which we refer (i.e.
+	 * the property-ref).
+	 *
+	 * @param factory The mappings...
+	 * @return The appropriate type.
+	 * @throws MappingException Generally, if unable to resolve the associated entity name
+	 * or unique key property name.
+	 */
+	public final Type getIdentifierOrUniqueKeyType(Mapping factory) throws MappingException {
+		if ( isReferenceToPrimaryKey() ) {
+			return getIdentifierType(factory);
+		}
+		else {
+			Type type = factory.getReferencedPropertyType( getAssociatedEntityName(), uniqueKeyPropertyName );
+			if ( type.isEntityType() ) {
+				type = ( ( EntityType ) type).getIdentifierOrUniqueKeyType( factory );
+			}
+			return type;
+		}
+	}
+
+	/**
+	 * The name of the property on the associated entity to which our FK
+	 * refers
+	 *
+	 * @param factory The mappings...
+	 * @return The appropriate property name.
+	 * @throws MappingException Generally, if unable to resolve the associated entity name
+	 */
+	public final String getIdentifierOrUniqueKeyPropertyName(Mapping factory)
+	throws MappingException {
+		if ( isReferenceToPrimaryKey() ) {
+			return factory.getIdentifierPropertyName( getAssociatedEntityName() );
+		}
+		else {
+			return uniqueKeyPropertyName;
+		}
+	}
+
+	protected abstract boolean isNullable();
+
+	/**
+	 * Resolve an identifier via a load.
+	 *
+	 * @param id The entity id to resolve
+	 * @param session The orginating session.
+	 * @return The resolved identifier (i.e., loaded entity).
+	 * @throws org.hibernate.HibernateException Indicates problems performing the load.
+	 */
+	protected final Object resolveIdentifier(Serializable id, SessionImplementor session) throws HibernateException {
+		boolean isProxyUnwrapEnabled = unwrapProxy &&
+				session.getFactory()
+						.getEntityPersister( getAssociatedEntityName() )
+						.isInstrumented( session.getEntityMode() );
+
+		Object proxyOrEntity = session.internalLoad(
+				getAssociatedEntityName(),
+				id,
+				eager,
+				isNullable() && !isProxyUnwrapEnabled
+		);
+
+		if ( proxyOrEntity instanceof HibernateProxy ) {
+			( ( HibernateProxy ) proxyOrEntity ).getHibernateLazyInitializer()
+					.setUnwrap( isProxyUnwrapEnabled );
+		}
+
+		return proxyOrEntity;
+	}
+
+	protected boolean isNull(Object owner, SessionImplementor session) {
+		return false;
+	}
+
+	/**
+	 * Load an instance by a unique key that is not the primary key.
+	 *
+	 * @param entityName The name of the entity to load
+	 * @param uniqueKeyPropertyName The name of the property defining the uniqie key.
+	 * @param key The unique key property value.
+	 * @param session The originating session.
+	 * @return The loaded entity
+	 * @throws HibernateException generally indicates problems performing the load.
+	 */
+	public Object loadByUniqueKey(
+			String entityName,
+			String uniqueKeyPropertyName,
+			Object key,
+			SessionImplementor session) throws HibernateException {
+		final SessionFactoryImplementor factory = session.getFactory();
+		UniqueKeyLoadable persister = ( UniqueKeyLoadable ) factory.getEntityPersister( entityName );
+
+		//TODO: implement caching?! proxies?!
+
+		EntityUniqueKey euk = new EntityUniqueKey(
+				entityName,
+				uniqueKeyPropertyName,
+				key,
+				getIdentifierOrUniqueKeyType( factory ),
+				session.getEntityMode(),
+				session.getFactory()
+		);
+
+		final PersistenceContext persistenceContext = session.getPersistenceContext();
+		Object result = persistenceContext.getEntity( euk );
+		if ( result == null ) {
+			result = persister.loadByUniqueKey( uniqueKeyPropertyName, key, session );
+		}
+		return result == null ? null : persistenceContext.proxyFor( result );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/FloatType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/FloatType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/FloatType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,59 @@
+//$Id: FloatType.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.dialect.Dialect;
+
+/**
+ * <tt>float</tt>: A type that maps an SQL FLOAT to a Java Float.
+ * @author Gavin King
+ */
+public class FloatType extends PrimitiveType {
+
+	public Serializable getDefaultValue() {
+		return new Float(0.0);
+	}
+	
+	public Object get(ResultSet rs, String name) throws SQLException {
+		return new Float( rs.getFloat(name) );
+	}
+
+	public Class getPrimitiveClass() {
+		return float.class;
+	}
+
+	public Class getReturnedClass() {
+		return Float.class;
+	}
+
+	public void set(PreparedStatement st, Object value, int index)
+	throws SQLException {
+
+		st.setFloat( index, ( (Float) value ).floatValue() );
+	}
+
+	public int sqlType() {
+		return Types.FLOAT;
+	}
+
+	public String getName() { return "float"; }
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return value.toString();
+	}
+
+	public Object fromStringValue(String xml) {
+		return new Float(xml);
+	}
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/ForeignKeyDirection.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/ForeignKeyDirection.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/ForeignKeyDirection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+//$Id: ForeignKeyDirection.java 7019 2005-06-05 05:09:58Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+
+import org.hibernate.engine.Cascade;
+
+/**
+ * Represents directionality of the foreign key constraint
+ * @author Gavin King
+ */
+public abstract class ForeignKeyDirection implements Serializable {
+	protected ForeignKeyDirection() {}
+	/**
+	 * Should we cascade at this cascade point?
+	 * @see org.hibernate.engine.Cascade
+	 */
+	public abstract boolean cascadeNow(int cascadePoint);
+
+	/**
+	 * A foreign key from child to parent
+	 */
+	public static final ForeignKeyDirection FOREIGN_KEY_TO_PARENT = new ForeignKeyDirection() {
+		public boolean cascadeNow(int cascadePoint) {
+			return cascadePoint!=Cascade.BEFORE_INSERT_AFTER_DELETE;
+		}
+
+		public String toString() {
+			return "toParent";
+		}
+		
+		Object readResolve() {
+			return FOREIGN_KEY_TO_PARENT;
+		}
+	};
+	/**
+	 * A foreign key from parent to child
+	 */
+	public static final ForeignKeyDirection FOREIGN_KEY_FROM_PARENT = new ForeignKeyDirection() {
+		public boolean cascadeNow(int cascadePoint) {
+			return cascadePoint!=Cascade.AFTER_INSERT_BEFORE_DELETE;
+		}
+
+		public String toString() {
+			return "fromParent";
+		}
+		
+		Object readResolve() {
+			return FOREIGN_KEY_FROM_PARENT;
+		}
+	};
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/IdentifierBagType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/IdentifierBagType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/IdentifierBagType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: IdentifierBagType.java 10086 2006-07-05 18:17:27Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentIdentifierBag;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+
+public class IdentifierBagType extends CollectionType {
+
+	public IdentifierBagType(String role, String propertyRef, boolean isEmbeddedInXML) {
+		super(role, propertyRef, isEmbeddedInXML);
+	}
+
+	public PersistentCollection instantiate(
+		SessionImplementor session,
+		CollectionPersister persister, Serializable key)
+		throws HibernateException {
+
+		return new PersistentIdentifierBag(session);
+	}
+
+	public Object instantiate(int anticipatedSize) {
+		return anticipatedSize <= 0 ? new ArrayList() : new ArrayList( anticipatedSize + 1 );
+	}
+	
+	public Class getReturnedClass() {
+		return java.util.Collection.class;
+	}
+
+	public PersistentCollection wrap(SessionImplementor session, Object collection) {
+		return new PersistentIdentifierBag( session, (java.util.Collection) collection );
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/IdentifierType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/IdentifierType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/IdentifierType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+//$Id: IdentifierType.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.type;
+
+/**
+ * A <tt>Type</tt> that may be used as an identifier.
+ * @author Gavin King
+ */
+public interface IdentifierType extends Type {
+
+	/**
+	 * Convert the value from the mapping file to a Java object.
+	 * @param xml the value of <tt>discriminator-value</tt> or <tt>unsaved-value</tt> attribute
+	 * @return Object
+	 * @throws Exception
+	 */
+	public Object stringToObject(String xml) throws Exception;
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/ImmutableType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/ImmutableType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/ImmutableType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+//$Id: ImmutableType.java 5744 2005-02-16 12:50:19Z oneovthafew $
+package org.hibernate.type;
+
+import java.util.Map;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * Superclass of nullable immutable types.
+ * @author Gavin King
+ */
+public abstract class ImmutableType extends NullableType {
+
+	public final Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory) {
+		return value;
+	}
+
+	public final boolean isMutable() {
+		return false;
+	}
+
+	public Object replace(
+		Object original,
+		Object target,
+		SessionImplementor session,
+		Object owner, 
+		Map copyCache)
+	throws HibernateException {
+		return original;
+	}
+
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/IntegerType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/IntegerType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/IntegerType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,74 @@
+//$Id: IntegerType.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Comparator;
+
+import org.hibernate.util.ComparableComparator;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * <tt>integer</tt>: A type that maps an SQL INT to a Java Integer.
+ * @author Gavin King
+ */
+public class IntegerType extends PrimitiveType implements DiscriminatorType, VersionType {
+
+	private static final Integer ZERO = new Integer(0);
+
+	public Serializable getDefaultValue() {
+		return ZERO;
+	}
+	
+	public Object get(ResultSet rs, String name) throws SQLException {
+		return new Integer( rs.getInt(name) );
+	}
+
+	public Class getPrimitiveClass() {
+		return int.class;
+	}
+
+	public Class getReturnedClass() {
+		return Integer.class;
+	}
+
+	public void set(PreparedStatement st, Object value, int index)
+	throws SQLException {
+		st.setInt( index, ( (Integer) value ).intValue() );
+	}
+
+	public int sqlType() {
+		return Types.INTEGER;
+	}
+
+	public String getName() { return "integer"; }
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return value.toString();
+	}
+
+	public Object stringToObject(String xml) throws Exception {
+		return new Integer(xml);
+	}
+
+	public Object next(Object current, SessionImplementor session) {
+		return new Integer( ( (Integer) current ).intValue() + 1 );
+	}
+
+	public Object seed(SessionImplementor session) {
+		return ZERO;
+	}
+
+	public Comparator getComparator() {
+		return ComparableComparator.INSTANCE;
+	}
+	
+	public Object fromStringValue(String xml) {
+		return new Integer(xml);
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/ListType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/ListType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/ListType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+//$Id: ListType.java 10086 2006-07-05 18:17:27Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.dom4j.Element;
+import org.hibernate.EntityMode;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.collection.PersistentList;
+import org.hibernate.collection.PersistentListElementHolder;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+
+public class ListType extends CollectionType {
+
+	public ListType(String role, String propertyRef, boolean isEmbeddedInXML) {
+		super(role, propertyRef, isEmbeddedInXML);
+	}
+
+	public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister, Serializable key) {
+		if ( session.getEntityMode()==EntityMode.DOM4J ) {
+			return new PersistentListElementHolder(session, persister, key);
+		}
+		else {
+			return new PersistentList(session);
+		}
+	}
+
+	public Class getReturnedClass() {
+		return List.class;
+	}
+
+	public PersistentCollection wrap(SessionImplementor session, Object collection) {
+		if ( session.getEntityMode()==EntityMode.DOM4J ) {
+			return new PersistentListElementHolder( session, (Element) collection );
+		}
+		else {
+			return new PersistentList( session, (List) collection );
+		}
+	}
+
+	public Object instantiate(int anticipatedSize) {
+		return anticipatedSize <= 0 ? new ArrayList() : new ArrayList( anticipatedSize + 1 );
+	}
+	
+	public Object indexOf(Object collection, Object element) {
+		List list = (List) collection;
+		for ( int i=0; i<list.size(); i++ ) {
+			//TODO: proxies!
+			if ( list.get(i)==element ) return new Integer(i);
+		}
+		return null;
+	}
+	
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/LiteralType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/LiteralType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/LiteralType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+//$Id: LiteralType.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.type;
+
+import org.hibernate.dialect.Dialect;
+
+/**
+ * A type that may appear as an SQL literal
+ * @author Gavin King
+ */
+public interface LiteralType {
+	/**
+	 * String representation of the value, suitable for embedding in
+	 * an SQL statement.
+	 * @param value
+	 * @param dialect
+	 * @return String the value, as it appears in a SQL query
+	 * @throws Exception
+	 */
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception;
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/LocaleType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/LocaleType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/LocaleType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+//$Id: LocaleType.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.type;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+import org.hibernate.EntityMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * <tt>locale</tt>: A type that maps an SQL VARCHAR to a Java Locale.
+ * @author Gavin King
+ */
+public class LocaleType extends ImmutableType implements LiteralType {
+
+	public Object get(ResultSet rs, String name) throws HibernateException, SQLException {
+		return fromStringValue( (String) Hibernate.STRING.get(rs, name) );
+	}
+
+	public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
+		Hibernate.STRING.set(st, value.toString(), index);
+	}
+
+	public Object fromStringValue(String string) {
+		if (string == null) {
+			return null;
+		}
+		else {
+			StringTokenizer tokens = new StringTokenizer(string, "_");
+			String language = tokens.hasMoreTokens() ? tokens.nextToken() : "";
+			String country = tokens.hasMoreTokens() ? tokens.nextToken() : "";
+			// Need to account for allowable '_' within the variant
+			String variant = "";
+			String sep = "";
+			while ( tokens.hasMoreTokens() ) {
+				variant += sep + tokens.nextToken();
+				sep = "_";
+			}
+			return new Locale(language, country, variant);
+		}
+	}
+	
+	public int compare(Object x, Object y, EntityMode entityMode) {
+		return x.toString().compareTo( y.toString() );
+	}
+
+	public int sqlType() {
+		return Hibernate.STRING.sqlType();
+	}
+
+	public String toString(Object value) throws HibernateException {
+		return value.toString();
+	}
+
+	public Class getReturnedClass() {
+		return Locale.class;
+	}
+
+	public String getName() {
+		return "locale";
+	}
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return ( (LiteralType) Hibernate.STRING ).objectToSQLString( value.toString(), dialect );
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/LongType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/LongType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/LongType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,76 @@
+//$Id: LongType.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Comparator;
+
+import org.hibernate.util.ComparableComparator;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * <tt>long</tt>: A type that maps an SQL BIGINT to a Java Long.
+ * @author Gavin King
+ */
+public class LongType extends PrimitiveType implements DiscriminatorType, VersionType {
+
+	private static final Long ZERO = new Long(0);
+
+	public Serializable getDefaultValue() {
+		return ZERO;
+	}
+	
+	public Object get(ResultSet rs, String name) throws SQLException {
+		return new Long( rs.getLong(name) );
+	}
+
+	public Class getPrimitiveClass() {
+		return long.class;
+	}
+
+	public Class getReturnedClass() {
+		return Long.class;
+	}
+
+	public void set(PreparedStatement st, Object value, int index)
+	throws SQLException {
+
+		st.setLong( index, ( (Long) value ).longValue() );
+	}
+
+	public int sqlType() {
+		return Types.BIGINT;
+	}
+
+	public String getName() { return "long"; }
+
+	public Object stringToObject(String xml) throws Exception {
+		return new Long(xml);
+	}
+
+	public Object next(Object current, SessionImplementor session) {
+		return new Long( ( (Long) current ).longValue() + 1 );
+	}
+
+	public Object seed(SessionImplementor session) {
+		return ZERO;
+	}
+
+	public Comparator getComparator() {
+		return ComparableComparator.INSTANCE;
+	}
+	
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return value.toString();
+	}
+
+	public Object fromStringValue(String xml) {
+		return new Long(xml);
+	}
+
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/ManyToOneType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/ManyToOneType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/ManyToOneType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,248 @@
+//$Id: ManyToOneType.java 10020 2006-06-15 16:38:03Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Arrays;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.ForeignKeys;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * A many-to-one association to an entity.
+ *
+ * @author Gavin King
+ */
+public class ManyToOneType extends EntityType {
+	
+	private final boolean ignoreNotFound;
+
+	public ManyToOneType(String className) {
+		this( className, false );
+	}
+
+	public ManyToOneType(String className, boolean lazy) {
+		super( className, null, !lazy, true, false );
+		this.ignoreNotFound = false;
+	}
+
+	public ManyToOneType(
+			String entityName,
+			String uniqueKeyPropertyName,
+			boolean lazy,
+			boolean unwrapProxy,
+			boolean isEmbeddedInXML,
+			boolean ignoreNotFound) {
+		super( entityName, uniqueKeyPropertyName, !lazy, isEmbeddedInXML, unwrapProxy );
+		this.ignoreNotFound = ignoreNotFound;
+	}
+
+	protected boolean isNullable() {
+		return ignoreNotFound;
+	}
+
+	public boolean isAlwaysDirtyChecked() {
+		// If we have <tt>not-found="ignore"</tt> association mapped to a
+		// formula, we always need to dirty check it, so we can update the
+		// second-level cache
+		return ignoreNotFound;
+	}
+
+	public boolean isOneToOne() {
+		return false;
+	}
+	
+	public int getColumnSpan(Mapping mapping) throws MappingException {
+		// our column span is the number of columns in the PK
+		return getIdentifierOrUniqueKeyType( mapping ).getColumnSpan( mapping );
+	}
+
+	public int[] sqlTypes(Mapping mapping) throws MappingException {
+		return getIdentifierOrUniqueKeyType( mapping ).sqlTypes( mapping );
+	}
+
+	public void nullSafeSet(
+			PreparedStatement st,
+			Object value,
+			int index,
+			boolean[] settable,
+			SessionImplementor session) throws HibernateException, SQLException {
+		getIdentifierOrUniqueKeyType( session.getFactory() )
+				.nullSafeSet( st, getIdentifier( value, session ), index, settable, session );
+	}
+
+	public void nullSafeSet(
+			PreparedStatement st,
+			Object value,
+			int index,
+			SessionImplementor session) throws HibernateException, SQLException {
+		getIdentifierOrUniqueKeyType( session.getFactory() )
+				.nullSafeSet( st, getIdentifier( value, session ), index, session );
+	}
+
+	public ForeignKeyDirection getForeignKeyDirection() {
+		return ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT;
+	}
+
+	public Object hydrate(
+			ResultSet rs,
+			String[] names,
+			SessionImplementor session,
+			Object owner) throws HibernateException, SQLException {
+		// return the (fully resolved) identifier value, but do not resolve
+		// to the actual referenced entity instance
+		// NOTE: the owner of the association is not really the owner of the id!
+		Serializable id = (Serializable) getIdentifierOrUniqueKeyType( session.getFactory() )
+				.nullSafeGet( rs, names, session, null );
+		scheduleBatchLoadIfNeeded( id, session );
+		return id;
+	}
+
+	/**
+	 * Register the entity as batch loadable, if enabled
+	 */
+	private void scheduleBatchLoadIfNeeded(
+			Serializable id,
+			SessionImplementor session) throws MappingException {
+		//cannot batch fetch by unique key (property-ref associations)
+		if ( uniqueKeyPropertyName == null && id != null ) {
+			EntityPersister persister = session.getFactory().getEntityPersister( getAssociatedEntityName() );
+			EntityKey entityKey = new EntityKey( id, persister, session.getEntityMode() );
+			if ( !session.getPersistenceContext().containsEntity( entityKey ) ) {
+				session.getPersistenceContext()
+						.getBatchFetchQueue()
+						.addBatchLoadableEntityKey( entityKey );
+			}
+		}
+	}
+	
+	public boolean useLHSPrimaryKey() {
+		return false;
+	}
+
+	public boolean isModified(
+			Object old,
+			Object current,
+			boolean[] checkable,
+			SessionImplementor session) throws HibernateException {
+		if ( current == null ) {
+			return old!=null;
+		}
+		if ( old == null ) {
+			// we already know current is not null...
+			return true;
+		}
+		// the ids are fully resolved, so compare them with isDirty(), not isModified()
+		return getIdentifierOrUniqueKeyType( session.getFactory() )
+				.isDirty( old, getIdentifier( current, session ), session );
+	}
+
+	public Serializable disassemble(
+			Object value,
+			SessionImplementor session,
+			Object owner) throws HibernateException {
+
+		if ( isNotEmbedded( session ) ) {
+			return getIdentifierType( session ).disassemble( value, session, owner );
+		}
+		
+		if ( value == null ) {
+			return null;
+		}
+		else {
+			// cache the actual id of the object, not the value of the
+			// property-ref, which might not be initialized
+			Object id = ForeignKeys.getEntityIdentifierIfNotUnsaved( 
+					getAssociatedEntityName(), 
+					value, 
+					session
+			);
+			if ( id == null ) {
+				throw new AssertionFailure(
+						"cannot cache a reference to an object with a null id: " + 
+						getAssociatedEntityName()
+				);
+			}
+			return getIdentifierType( session ).disassemble( id, session, owner );
+		}
+	}
+
+	public Object assemble(
+			Serializable oid,
+			SessionImplementor session,
+			Object owner) throws HibernateException {
+		
+		//TODO: currently broken for unique-key references (does not detect
+		//      change to unique key property of the associated object)
+		
+		Serializable id = assembleId( oid, session );
+
+		if ( isNotEmbedded( session ) ) {
+			return id;
+		}
+		
+		if ( id == null ) {
+			return null;
+		}
+		else {
+			return resolveIdentifier( id, session );
+		}
+	}
+
+	private Serializable assembleId(Serializable oid, SessionImplementor session) {
+		//the owner of the association is not the owner of the id
+		return ( Serializable ) getIdentifierType( session ).assemble( oid, session, null );
+	}
+
+	public void beforeAssemble(Serializable oid, SessionImplementor session) {
+		scheduleBatchLoadIfNeeded( assembleId( oid, session ), session );
+	}
+	
+	public boolean[] toColumnNullness(Object value, Mapping mapping) {
+		boolean[] result = new boolean[ getColumnSpan( mapping ) ];
+		if ( value != null ) {
+			Arrays.fill( result, true );
+		}
+		return result;
+	}
+	
+	public boolean isDirty(
+			Object old,
+			Object current,
+			SessionImplementor session) throws HibernateException {
+		if ( isSame( old, current, session.getEntityMode() ) ) {
+			return false;
+		}
+		Object oldid = getIdentifier( old, session );
+		Object newid = getIdentifier( current, session );
+		return getIdentifierType( session ).isDirty( oldid, newid, session );
+	}
+
+	public boolean isDirty(
+			Object old,
+			Object current,
+			boolean[] checkable,
+			SessionImplementor session) throws HibernateException {
+		if ( isAlwaysDirtyChecked() ) {
+			return isDirty( old, current, session );
+		}
+		else {
+			if ( isSame( old, current, session.getEntityMode() ) ) {
+				return false;
+			}
+			Object oldid = getIdentifier( old, session );
+			Object newid = getIdentifier( current, session );
+			return getIdentifierType( session ).isDirty( oldid, newid, checkable, session );
+		}
+		
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/MapType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/MapType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/MapType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,92 @@
+//$Id: MapType.java 10086 2006-07-05 18:17:27Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.dom4j.Element;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.collection.PersistentMap;
+import org.hibernate.collection.PersistentMapElementHolder;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+
+
+public class MapType extends CollectionType {
+
+	public MapType(String role, String propertyRef, boolean isEmbeddedInXML) {
+		super(role, propertyRef, isEmbeddedInXML);
+	}
+
+	public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister, Serializable key) {
+		if ( session.getEntityMode()==EntityMode.DOM4J ) {
+			return new PersistentMapElementHolder(session, persister, key);
+		}
+		else {
+			return new PersistentMap(session);
+		}
+	}
+
+	public Class getReturnedClass() {
+		return Map.class;
+	}
+
+	public Iterator getElementsIterator(Object collection) {
+		return ( (java.util.Map) collection ).values().iterator();
+	}
+
+	public PersistentCollection wrap(SessionImplementor session, Object collection) {
+		if ( session.getEntityMode()==EntityMode.DOM4J ) {
+			return new PersistentMapElementHolder( session, (Element) collection );
+		}
+		else {
+			return new PersistentMap( session, (java.util.Map) collection );
+		}
+	}
+	
+	public Object instantiate(int anticipatedSize) {
+		return anticipatedSize <= 0 
+		       ? new HashMap()
+		       : new HashMap( anticipatedSize + (int)( anticipatedSize * .75f ), .75f );
+	}
+
+	public Object replaceElements(
+		final Object original,
+		final Object target,
+		final Object owner, 
+		final java.util.Map copyCache, 
+		final SessionImplementor session)
+		throws HibernateException {
+
+		CollectionPersister cp = session.getFactory().getCollectionPersister( getRole() );
+		
+		java.util.Map result = (java.util.Map) target;
+		result.clear();
+		
+		Iterator iter = ( (java.util.Map) original ).entrySet().iterator();
+		while ( iter.hasNext() ) {
+			java.util.Map.Entry me = (java.util.Map.Entry) iter.next();
+			Object key = cp.getIndexType().replace( me.getKey(), null, session, owner, copyCache );
+			Object value = cp.getElementType().replace( me.getValue(), null, session, owner, copyCache );
+			result.put(key, value);
+		}
+		
+		return result;
+		
+	}
+	
+	public Object indexOf(Object collection, Object element) {
+		Iterator iter = ( (Map) collection ).entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			//TODO: proxies!
+			if ( me.getValue()==element ) return me.getKey();
+		}
+		return null;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/MetaType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/MetaType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/MetaType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,139 @@
+//$Id: MetaType.java 7644 2005-07-25 06:53:09Z oneovthafew $
+package org.hibernate.type;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.dom4j.Node;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * @author Gavin King
+ */
+public class MetaType extends AbstractType {
+
+	private final Map values;
+	private final Map keys;
+	private final Type baseType;
+
+	public MetaType(Map values, Type baseType) {
+		this.baseType = baseType;
+		this.values = values;
+		keys = new HashMap();
+		Iterator iter = values.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			keys.put( me.getValue(), me.getKey() );
+		}
+	}
+
+	public int[] sqlTypes(Mapping mapping) throws MappingException {
+		return baseType.sqlTypes(mapping);
+	}
+
+	public int getColumnSpan(Mapping mapping) throws MappingException {
+		return baseType.getColumnSpan(mapping);
+	}
+
+	public Class getReturnedClass() {
+		return String.class;
+	}
+
+	public Object nullSafeGet(
+		ResultSet rs,
+		String[] names,
+		SessionImplementor session,
+		Object owner)
+	throws HibernateException, SQLException {
+		Object key = baseType.nullSafeGet(rs, names, session, owner);
+		return key==null ? null : values.get(key);
+	}
+
+	public Object nullSafeGet(
+		ResultSet rs,
+		String name,
+		SessionImplementor session,
+		Object owner)
+	throws HibernateException, SQLException {
+		Object key = baseType.nullSafeGet(rs, name, session, owner);
+		return key==null ? null : values.get(key);
+	}
+
+	public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session)
+	throws HibernateException, SQLException {
+		baseType.nullSafeSet(st, value==null ? null : keys.get(value), index, session);
+	}
+	
+	public void nullSafeSet(
+			PreparedStatement st,
+			Object value,
+			int index,
+			boolean[] settable, 
+			SessionImplementor session)
+	throws HibernateException, SQLException {
+		if ( settable[0] ) nullSafeSet(st, value, index, session);
+	}
+
+	public String toLoggableString(Object value, SessionFactoryImplementor factory) throws HibernateException {
+		return toXMLString(value, factory);
+	}
+	
+	public String toXMLString(Object value, SessionFactoryImplementor factory)
+		throws HibernateException {
+		return (String) value; //value is the entity name
+	}
+
+	public Object fromXMLString(String xml, Mapping factory)
+		throws HibernateException {
+		return xml; //xml is the entity name
+	}
+
+	public String getName() {
+		return baseType.getName(); //TODO!
+	}
+
+	public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory) 
+	throws HibernateException {
+		return value;
+	}
+
+	public Object replace(
+			Object original, 
+			Object target,
+			SessionImplementor session, 
+			Object owner, 
+			Map copyCache
+	) {
+		return original;
+	}
+	
+	public boolean isMutable() {
+		return false;
+	}
+
+	public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException {
+		return fromXMLString( xml.getText(), factory );
+	}
+
+	public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory) throws HibernateException {
+		node.setText( toXMLString(value, factory) );
+	}
+
+	public boolean[] toColumnNullness(Object value, Mapping mapping) {
+		throw new UnsupportedOperationException();
+	}
+
+	public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session) throws HibernateException {
+		return checkable[0] && isDirty(old, current, session);
+	}
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/MutableType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/MutableType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/MutableType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+//$Id: MutableType.java 6883 2005-05-24 16:22:15Z oneovthafew $
+package org.hibernate.type;
+
+import java.util.Map;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * Superclass for mutable nullable types
+ * @author Gavin King
+ */
+public abstract class MutableType extends NullableType {
+
+	public final boolean isMutable() {
+		return true;
+	}
+
+	protected abstract Object deepCopyNotNull(Object value) throws HibernateException;
+
+	public final Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory) 
+	throws HibernateException {
+		return (value==null) ? null : deepCopyNotNull(value);
+	}
+
+	public Object replace(
+		Object original,
+		Object target,
+		SessionImplementor session,
+		Object owner, 
+		Map copyCache)
+	throws HibernateException {
+		if ( isEqual( original, target, session.getEntityMode() ) ) return original;
+		return deepCopy( original, session.getEntityMode(), session.getFactory() );
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/NullableType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/NullableType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/NullableType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,236 @@
+//$Id: NullableType.java 11047 2007-01-16 15:26:09Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.Log;
+import org.dom4j.Node;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.util.EqualsHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Superclass of single-column nullable types.
+ * 
+ * @author Gavin King
+ */
+public abstract class NullableType extends AbstractType {
+
+	/**
+	 * This is the old scheme where logging of parameter bindings and value extractions
+	 * was controlled by the trace level enablement on the 'org.hibernate.type' package...
+	 * <p/>
+	 * Originally was cached such because of performance of looking up the logger each time
+	 * in order to check the trace-enablement.  Driving this via a central Log-specific class
+	 * would alleviate that performance hit, and yet still allow more "normal" logging usage/config.
+	 */
+	private static final boolean IS_VALUE_TRACING_ENABLED = LogFactory.getLog( StringHelper.qualifier( Type.class.getName() ) ).isTraceEnabled();
+	private transient Log log;
+
+	private Log log() {
+		if ( log == null ) {
+			log = LogFactory.getLog( getClass() );
+		}
+		return log;
+	}
+
+	/**
+	 * Get a column value from a result set, without worrying about the
+	 * possibility of null values.  Called from {@link #nullSafeGet} after
+	 * nullness checks have been performed.
+	 *
+	 * @param rs The result set from which to extract the value.
+	 * @param name The name of the value to extract.
+	 *
+	 * @return The extracted value.
+	 *
+	 * @throws org.hibernate.HibernateException Generally some form of mismatch error.
+	 * @throws java.sql.SQLException Indicates problem making the JDBC call(s).
+	 */
+	public abstract Object get(ResultSet rs, String name) throws HibernateException, SQLException;
+
+	/**
+	 * Set a parameter value without worrying about the possibility of null
+	 * values.  Called from {@link #nullSafeSet} after nullness checks have
+	 * been performed.
+	 *
+	 * @param st The statement into which to bind the parameter value.
+	 * @param value The parameter value to bind.
+	 * @param index The position or index at which to bind the param value.
+	 *
+	 * @throws org.hibernate.HibernateException Generally some form of mismatch error.
+	 * @throws java.sql.SQLException Indicates problem making the JDBC call(s).
+	 */
+	public abstract void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException;
+
+	/**
+	 * A convenience form of {@link #sqlTypes(org.hibernate.engine.Mapping)}, returning
+	 * just a single type value since these are explicitly dealing with single column
+	 * mappings.
+	 *
+	 * @return The {@link java.sql.Types} mapping value.
+	 */
+	public abstract int sqlType();
+
+	/**
+	 * A null-safe version of {@link #toString(Object)}.  Specifically we are
+	 * worried about null safeness in regards to the incoming value parameter,
+	 * not the return.
+	 *
+	 * @param value The value to convert to a string representation; may be null.
+	 * @return The string representation; may be null.
+	 * @throws HibernateException Thrown by {@link #toString(Object)}, which this calls.
+	 */
+	public String nullSafeToString(Object value) throws HibernateException {
+		return value == null ? null : toString( value );
+	}
+
+	public abstract String toString(Object value) throws HibernateException;
+
+	public abstract Object fromStringValue(String xml) throws HibernateException;
+
+	public final void nullSafeSet(
+			PreparedStatement st,
+			Object value,
+			int index,
+			boolean[] settable,
+			SessionImplementor session)
+	throws HibernateException, SQLException {
+		if ( settable[0] ) nullSafeSet(st, value, index);
+	}
+
+	public final void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session)
+	throws HibernateException, SQLException {
+		nullSafeSet(st, value, index);
+	}
+
+	public final void nullSafeSet(PreparedStatement st, Object value, int index)
+	throws HibernateException, SQLException {
+		try {
+			if ( value == null ) {
+				if ( IS_VALUE_TRACING_ENABLED ) {
+					log().trace( "binding null to parameter: " + index );
+				}
+
+				st.setNull( index, sqlType() );
+			}
+			else {
+				if ( IS_VALUE_TRACING_ENABLED ) {
+					log().trace( "binding '" + toString( value ) + "' to parameter: " + index );
+				}
+
+				set( st, value, index );
+			}
+		}
+		catch ( RuntimeException re ) {
+			log().info( "could not bind value '" + nullSafeToString( value ) + "' to parameter: " + index + "; " + re.getMessage() );
+			throw re;
+		}
+		catch ( SQLException se ) {
+			log().info( "could not bind value '" + nullSafeToString( value ) + "' to parameter: " + index + "; " + se.getMessage() );
+			throw se;
+		}
+	}
+
+	public final Object nullSafeGet(
+			ResultSet rs,
+			String[] names,
+			SessionImplementor session,
+			Object owner)
+	throws HibernateException, SQLException {
+		return nullSafeGet(rs, names[0]);
+	}
+
+	public final Object nullSafeGet(ResultSet rs, String[] names)
+	throws HibernateException, SQLException {
+		return nullSafeGet(rs, names[0]);
+	}
+
+	public final Object nullSafeGet(ResultSet rs, String name)
+	throws HibernateException, SQLException {
+		try {
+			Object value = get(rs, name);
+			if ( value == null || rs.wasNull() ) {
+				if ( IS_VALUE_TRACING_ENABLED ) {
+					log().trace( "returning null as column: " + name );
+				}
+				return null;
+			}
+			else {
+				if ( IS_VALUE_TRACING_ENABLED ) {
+					log().trace( "returning '" + toString( value ) + "' as column: " + name );
+				}
+				return value;
+			}
+		}
+		catch ( RuntimeException re ) {
+			log().info( "could not read column value from result set: " + name + "; " + re.getMessage() );
+			throw re;
+		}
+		catch ( SQLException se ) {
+			log().info( "could not read column value from result set: " + name + "; " + se.getMessage() );
+			throw se;
+		}
+	}
+
+	public final Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object owner)
+	throws HibernateException, SQLException {
+		return nullSafeGet(rs, name);
+	}
+
+	public final String toXMLString(Object value, SessionFactoryImplementor pc)
+	throws HibernateException {
+		return toString(value);
+	}
+
+	public final Object fromXMLString(String xml, Mapping factory) throws HibernateException {
+		return xml==null || xml.length()==0 ? null : fromStringValue(xml);
+	}
+
+	public final int getColumnSpan(Mapping session) {
+		return 1;
+	}
+
+	public final int[] sqlTypes(Mapping session) {
+		return new int[] { sqlType() };
+	}
+
+	public final boolean isEqual(Object x, Object y, EntityMode entityMode) {
+		return isEqual(x, y);
+	}
+
+	public boolean isEqual(Object x, Object y) {
+		return EqualsHelper.equals(x, y);
+	}
+
+	public String toLoggableString(Object value, SessionFactoryImplementor factory) {
+		return value == null ? "null" : toString(value);
+	}
+
+	public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException {
+		return fromXMLString( xml.getText(), factory );
+	}
+
+	public void setToXMLNode(Node xml, Object value, SessionFactoryImplementor factory)
+	throws HibernateException {
+		xml.setText( toXMLString(value, factory) );
+	}
+
+	public boolean[] toColumnNullness(Object value, Mapping mapping) {
+		return value==null ? ArrayHelper.FALSE : ArrayHelper.TRUE;
+	}
+
+	public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session)
+	throws HibernateException {
+		return checkable[0] && isDirty(old, current, session);
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/OneToOneType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/OneToOneType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/OneToOneType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,155 @@
+//$Id: OneToOneType.java 7644 2005-07-25 06:53:09Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * A one-to-one association to an entity
+ * @author Gavin King
+ */
+public class OneToOneType extends EntityType {
+
+	private final ForeignKeyDirection foreignKeyType;
+	private final String propertyName;
+	private final String entityName;
+	
+	public String getPropertyName() {
+		return propertyName;
+	}
+	
+	public boolean isNull(Object owner, SessionImplementor session) {
+		
+		if ( propertyName != null ) {
+			
+			EntityPersister ownerPersister = session.getFactory()
+					.getEntityPersister(entityName); 
+			Serializable id = session.getContextEntityIdentifier(owner);
+
+			EntityKey entityKey = new EntityKey( id, ownerPersister, session.getEntityMode() );
+			
+			return session.getPersistenceContext()
+					.isPropertyNull( entityKey, getPropertyName() );
+			
+		}
+		else {
+			return false;
+		}
+
+	}
+
+	public int getColumnSpan(Mapping session) throws MappingException {
+		return 0;
+	}
+
+	public int[] sqlTypes(Mapping session) throws MappingException {
+		return ArrayHelper.EMPTY_INT_ARRAY;
+	}
+
+	public boolean[] toColumnNullness(Object value, Mapping mapping) {
+		return ArrayHelper.EMPTY_BOOLEAN_ARRAY;
+	}
+
+	public OneToOneType(
+			String referencedEntityName, 
+			ForeignKeyDirection foreignKeyType, 
+			String uniqueKeyPropertyName,
+			boolean lazy,
+			boolean unwrapProxy,
+			boolean isEmbeddedInXML,
+			String entityName,
+			String propertyName
+	) {
+		super(
+				referencedEntityName, 
+				uniqueKeyPropertyName, 
+				!lazy, 
+				isEmbeddedInXML, 
+				unwrapProxy
+			);
+		this.foreignKeyType = foreignKeyType;
+		this.propertyName = propertyName;
+		this.entityName = entityName;
+	}
+
+	public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SessionImplementor session) {
+		//nothing to do
+	}
+
+	public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) {
+		//nothing to do
+	}
+
+	public boolean isOneToOne() {
+		return true;
+	}
+
+	public boolean isDirty(Object old, Object current, SessionImplementor session) {
+		return false;
+	}
+
+	public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session) {
+		return false;
+	}
+
+	public boolean isModified(Object old, Object current, boolean[] checkable, SessionImplementor session) {
+		return false;
+	}
+
+	public ForeignKeyDirection getForeignKeyDirection() {
+		return foreignKeyType;
+	}
+
+	public Object hydrate(
+		ResultSet rs,
+		String[] names,
+		SessionImplementor session,
+		Object owner)
+	throws HibernateException, SQLException {
+
+		return session.getContextEntityIdentifier(owner);
+	}
+
+	protected boolean isNullable() {
+		return foreignKeyType==ForeignKeyDirection.FOREIGN_KEY_TO_PARENT;
+	}
+
+	public boolean useLHSPrimaryKey() {
+		return true;
+	}
+
+	public Serializable disassemble(Object value, SessionImplementor session, Object owner)
+	throws HibernateException {
+		return null;
+	}
+
+	public Object assemble(Serializable oid, SessionImplementor session, Object owner)
+	throws HibernateException {
+		//this should be a call to resolve(), not resolveIdentifier(), 
+		//'cos it might be a property-ref, and we did not cache the
+		//referenced value
+		return resolve( session.getContextEntityIdentifier(owner), session, owner );
+	}
+	
+	/**
+	 * We don't need to dirty check one-to-one because of how 
+	 * assemble/disassemble is implemented and because a one-to-one 
+	 * association is never dirty
+	 */
+	public boolean isAlwaysDirtyChecked() {
+		//TODO: this is kinda inconsistent with CollectionType
+		return false; 
+	}
+	
+}
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/OrderedMapType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/OrderedMapType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/OrderedMapType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+//$Id: OrderedMapType.java 10100 2006-07-10 16:31:09Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import org.hibernate.util.LinkedHashCollectionHelper;
+
+public class OrderedMapType extends MapType {
+
+	public OrderedMapType(String role, String propertyRef, boolean isEmbeddedInXML) {
+		super( role, propertyRef, isEmbeddedInXML );
+	}
+
+	public Object instantiate(int anticipatedSize) {
+		return LinkedHashCollectionHelper.createLinkedHashMap( anticipatedSize );
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/type/OrderedMapType.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/OrderedSetType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/OrderedSetType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/OrderedSetType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+//$Id: OrderedSetType.java 10100 2006-07-10 16:31:09Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import org.hibernate.util.LinkedHashCollectionHelper;
+
+public class OrderedSetType extends SetType {
+
+	public OrderedSetType(String role, String propertyRef, boolean isEmbeddedInXML) {
+		super( role, propertyRef, isEmbeddedInXML );
+	}
+
+	public Object instantiate(int anticipatedSize) {
+		return LinkedHashCollectionHelper.createLinkedHashSet( anticipatedSize );
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/type/OrderedSetType.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/PrimitiveType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/PrimitiveType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/PrimitiveType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+//$Id: PrimitiveType.java 4582 2004-09-25 11:22:20Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+
+/**
+ * Superclass of primitive / primitive wrapper types.
+ * @author Gavin King
+ */
+public abstract class PrimitiveType extends ImmutableType implements LiteralType {
+
+	public abstract Class getPrimitiveClass();
+
+	public String toString(Object value) {
+		return value.toString();
+	}
+	
+	public abstract Serializable getDefaultValue();
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/SerializableType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/SerializableType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/SerializableType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,106 @@
+//$Id: SerializableType.java 10818 2006-11-16 05:12:01Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.hibernate.EntityMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.util.SerializationHelper;
+
+/**
+ * <tt>serializable</tt>: A type that maps an SQL VARBINARY to a
+ * serializable Java object.
+ * @author Gavin King
+ */
+public class SerializableType extends MutableType {
+
+	private final Class serializableClass;
+
+	public SerializableType(Class serializableClass) {
+		this.serializableClass = serializableClass;
+	}
+
+	public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
+		Hibernate.BINARY.set(st, toBytes(value), index);
+	}
+
+	public Object get(ResultSet rs, String name) throws HibernateException, SQLException {
+		byte[] bytes = (byte[]) Hibernate.BINARY.get(rs, name);
+		// Some JDBC drivers erroneously return an empty array here for a null DB value :/
+		if ( bytes == null || bytes.length == 0 ) {
+			return null;
+		}
+		else {
+			return fromBytes(bytes);
+		}
+	}
+
+	public Class getReturnedClass() {
+		return serializableClass;
+	}
+
+	public boolean isEqual(Object x, Object y) throws HibernateException {
+		if ( x == y ) {
+			return true;
+		}
+		if ( x == null || y == null ) {
+			return false;
+		}
+		return x.equals( y ) || Hibernate.BINARY.isEqual( toBytes( x ), toBytes( y ) );
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode) {
+		return Hibernate.BINARY.getHashCode( toBytes(x), entityMode );
+	}
+
+	public String toString(Object value) throws HibernateException {
+		return Hibernate.BINARY.toString( toBytes(value) );
+	}
+
+	public Object fromStringValue(String xml) throws HibernateException {
+		return fromBytes( (byte[]) Hibernate.BINARY.fromStringValue(xml) );
+	}
+
+	public String getName() {
+		return (serializableClass==Serializable.class) ? "serializable" : serializableClass.getName();
+	}
+
+	public Object deepCopyNotNull(Object value) throws HibernateException {
+		return fromBytes( toBytes(value) );
+	}
+
+	private static byte[] toBytes(Object object) throws SerializationException {
+		return SerializationHelper.serialize( (Serializable) object );
+	}
+
+	private static Object fromBytes( byte[] bytes ) throws SerializationException {
+		return SerializationHelper.deserialize(bytes);
+	}
+
+	public int sqlType() {
+		return Hibernate.BINARY.sqlType();
+	}
+
+	public Object assemble(Serializable cached, SessionImplementor session, Object owner)
+	throws HibernateException {
+		return (cached==null) ? null : fromBytes( (byte[]) cached );
+	}
+
+	public Serializable disassemble(Object value, SessionImplementor session, Object owner)
+	throws HibernateException {
+		return (value==null) ? null : toBytes(value);
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/SerializationException.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/SerializationException.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/SerializationException.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: SerializationException.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.type;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Thrown when a property cannot be serializaed/deserialized
+ * @author Gavin King
+ */
+public class SerializationException extends HibernateException {
+
+	public SerializationException(String message, Exception root) {
+		super(message, root);
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/SetType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/SetType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/SetType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: SetType.java 10086 2006-07-05 18:17:27Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.util.HashSet;
+
+import org.dom4j.Element;
+import org.hibernate.EntityMode;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.collection.PersistentElementHolder;
+import org.hibernate.collection.PersistentSet;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+
+public class SetType extends CollectionType {
+
+	public SetType(String role, String propertyRef, boolean isEmbeddedInXML) {
+		super(role, propertyRef, isEmbeddedInXML);
+	}
+
+	public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister, Serializable key) {
+		if ( session.getEntityMode()==EntityMode.DOM4J ) {
+			return new PersistentElementHolder(session, persister, key);
+		}
+		else {
+			return new PersistentSet(session);
+		}
+	}
+
+	public Class getReturnedClass() {
+		return java.util.Set.class;
+	}
+
+	public PersistentCollection wrap(SessionImplementor session, Object collection) {
+		if ( session.getEntityMode()==EntityMode.DOM4J ) {
+			return new PersistentElementHolder( session, (Element) collection );
+		}
+		else {
+			return new PersistentSet( session, (java.util.Set) collection );
+		}
+	}
+
+	public Object instantiate(int anticipatedSize) {
+		return anticipatedSize <= 0
+		       ? new HashSet()
+		       : new HashSet( anticipatedSize + (int)( anticipatedSize * .75f ), .75f );
+	}
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/ShortType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/ShortType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/ShortType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+//$Id: ShortType.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Comparator;
+
+import org.hibernate.util.ComparableComparator;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * <tt>short</tt>: A type that maps an SQL SMALLINT to a Java Short.
+ * @author Gavin King
+ */
+public class ShortType extends PrimitiveType  implements DiscriminatorType, VersionType {
+
+	private static final Short ZERO = new Short( (short) 0 );
+
+	public Serializable getDefaultValue() {
+		return ZERO;
+	}
+	
+	public Object get(ResultSet rs, String name) throws SQLException {
+		return new Short( rs.getShort(name) );
+	}
+
+	public Class getPrimitiveClass() {
+		return short.class;
+	}
+
+	public Class getReturnedClass() {
+		return Short.class;
+	}
+
+	public void set(PreparedStatement st, Object value, int index) throws SQLException {
+		st.setShort( index, ( (Short) value ).shortValue() );
+	}
+
+	public int sqlType() {
+		return Types.SMALLINT;
+	}
+
+	public String getName() { return "short"; }
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return value.toString();
+	}
+
+	public Object stringToObject(String xml) throws Exception {
+		return new Short(xml);
+	}
+
+	public Object next(Object current, SessionImplementor session) {
+		return new Short( (short) ( ( (Short) current ).shortValue() + 1 ) );
+	}
+
+	public Object seed(SessionImplementor session) {
+		return ZERO;
+	}
+
+	public Comparator getComparator() {
+		return ComparableComparator.INSTANCE;
+	}
+	
+	public Object fromStringValue(String xml) {
+		return new Short(xml);
+	}
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/SortedMapType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/SortedMapType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/SortedMapType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,61 @@
+//$Id: SortedMapType.java 10100 2006-07-10 16:31:09Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.TreeMap;
+
+import org.dom4j.Element;
+import org.hibernate.EntityMode;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.collection.PersistentElementHolder;
+import org.hibernate.collection.PersistentMapElementHolder;
+import org.hibernate.collection.PersistentSortedMap;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+
+
+public class SortedMapType extends MapType {
+
+	private final Comparator comparator;
+
+	public SortedMapType(String role, String propertyRef, Comparator comparator, boolean isEmbeddedInXML) {
+		super(role, propertyRef, isEmbeddedInXML);
+		this.comparator = comparator;
+	}
+
+	public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister, Serializable key) {
+		if ( session.getEntityMode()==EntityMode.DOM4J ) {
+			return new PersistentMapElementHolder(session, persister, key);
+		}
+		else {
+			PersistentSortedMap map = new PersistentSortedMap(session);
+			map.setComparator(comparator);
+			return map;
+		}
+	}
+
+	public Class getReturnedClass() {
+		return java.util.SortedMap.class;
+	}
+
+	public Object instantiate(int anticipatedSize) {
+		return new TreeMap(comparator);
+	}
+	
+	public PersistentCollection wrap(SessionImplementor session, Object collection) {
+		if ( session.getEntityMode()==EntityMode.DOM4J ) {
+			return new PersistentElementHolder( session, (Element) collection );
+		}
+		else {
+			return new PersistentSortedMap( session, (java.util.SortedMap) collection );
+		}
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/SortedSetType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/SortedSetType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/SortedSetType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,58 @@
+//$Id: SortedSetType.java 10100 2006-07-10 16:31:09Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.TreeSet;
+
+import org.dom4j.Element;
+import org.hibernate.EntityMode;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.collection.PersistentElementHolder;
+import org.hibernate.collection.PersistentSortedSet;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+
+public class SortedSetType extends SetType {
+
+	private final Comparator comparator;
+
+	public SortedSetType(String role, String propertyRef, Comparator comparator, boolean isEmbeddedInXML) {
+		super(role, propertyRef, isEmbeddedInXML);
+		this.comparator = comparator;
+	}
+
+	public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister, Serializable key) {
+		if ( session.getEntityMode()==EntityMode.DOM4J ) {
+			return new PersistentElementHolder(session, persister, key);
+		}
+		else {
+			PersistentSortedSet set = new PersistentSortedSet(session);
+			set.setComparator(comparator);
+			return set;
+		}
+	}
+
+	public Class getReturnedClass() {
+		return java.util.SortedSet.class;
+	}
+
+	public Object instantiate(int anticipatedSize) {
+		return new TreeSet(comparator);
+	}
+	
+	public PersistentCollection wrap(SessionImplementor session, Object collection) {
+		if ( session.getEntityMode()==EntityMode.DOM4J ) {
+			return new PersistentElementHolder( session, (Element) collection );
+		}
+		else {
+			return new PersistentSortedSet( session, (java.util.SortedSet) collection );
+		}
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/SpecialOneToOneType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/SpecialOneToOneType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/SpecialOneToOneType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,106 @@
+//$Id: SpecialOneToOneType.java 7246 2005-06-20 20:32:36Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.ForeignKeys;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * A one-to-one association that maps to specific formula(s)
+ * instead of the primary key column of the owning entity.
+ * 
+ * @author Gavin King
+ */
+public class SpecialOneToOneType extends OneToOneType {
+	
+	public SpecialOneToOneType(
+			String referencedEntityName,
+			ForeignKeyDirection foreignKeyType, 
+			String uniqueKeyPropertyName,
+			boolean lazy,
+			boolean unwrapProxy,
+			String entityName,
+			String propertyName
+	) {
+		super(
+				referencedEntityName, 
+				foreignKeyType, 
+				uniqueKeyPropertyName, 
+				lazy,
+				unwrapProxy,
+				true, 
+				entityName, 
+				propertyName
+			);
+	}
+	
+	public int getColumnSpan(Mapping mapping) throws MappingException {
+		return super.getIdentifierOrUniqueKeyType(mapping).getColumnSpan(mapping);
+	}
+	
+	public int[] sqlTypes(Mapping mapping) throws MappingException {
+		return super.getIdentifierOrUniqueKeyType(mapping).sqlTypes(mapping);
+	}
+
+	public boolean useLHSPrimaryKey() {
+		return false;
+	}
+	
+	public Object hydrate(ResultSet rs, String[] names, SessionImplementor session, Object owner)
+	throws HibernateException, SQLException {
+		return super.getIdentifierOrUniqueKeyType( session.getFactory() )
+			.nullSafeGet(rs, names, session, owner);
+	}
+	
+	// TODO: copy/paste from ManyToOneType
+
+	public Serializable disassemble(Object value, SessionImplementor session, Object owner)
+	throws HibernateException {
+
+		if ( isNotEmbedded(session) ) {
+			return getIdentifierType(session).disassemble(value, session, owner);
+		}
+		
+		if (value==null) {
+			return null;
+		}
+		else {
+			// cache the actual id of the object, not the value of the
+			// property-ref, which might not be initialized
+			Object id = ForeignKeys.getEntityIdentifierIfNotUnsaved( getAssociatedEntityName(), value, session );
+			if (id==null) {
+				throw new AssertionFailure(
+						"cannot cache a reference to an object with a null id: " + 
+						getAssociatedEntityName() 
+				);
+			}
+			return getIdentifierType(session).disassemble(id, session, owner);
+		}
+	}
+
+	public Object assemble(Serializable oid, SessionImplementor session, Object owner)
+	throws HibernateException {
+		//TODO: currently broken for unique-key references (does not detect
+		//      change to unique key property of the associated object)
+		Serializable id = (Serializable) getIdentifierType(session).assemble(oid, session, null); //the owner of the association is not the owner of the id
+
+		if ( isNotEmbedded(session) ) return id;
+		
+		if (id==null) {
+			return null;
+		}
+		else {
+			return resolveIdentifier(id, session);
+		}
+	}
+	
+
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/type/SpecialOneToOneType.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/StringType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/StringType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/StringType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,56 @@
+//$Id: StringType.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.type;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.dialect.Dialect;
+
+/**
+ * <tt>string</tt>: A type that maps an SQL VARCHAR to a Java String.
+ * @author Gavin King
+ */
+public class StringType extends ImmutableType implements DiscriminatorType {
+
+	public Object get(ResultSet rs, String name) throws SQLException {
+		return rs.getString(name);
+	}
+
+	public Class getReturnedClass() {
+		return String.class;
+	}
+
+	public void set(PreparedStatement st, Object value, int index) throws SQLException {
+		st.setString(index, (String) value);
+	}
+
+	public int sqlType() {
+		return Types.VARCHAR;
+	}
+
+	public String getName() { return "string"; }
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return '\'' + (String) value + '\'';
+	}
+
+	public Object stringToObject(String xml) throws Exception {
+		return xml;
+	}
+
+	public String toString(Object value) {
+		return (String) value;
+	}
+
+	public Object fromStringValue(String xml) {
+		return xml;
+	}
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/TextType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/TextType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/TextType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,84 @@
+//$Id: TextType.java 4582 2004-09-25 11:22:20Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.HibernateException;
+
+/**
+ * <tt>text</tt>: A type that maps an SQL CLOB to a Java String.
+ * @author Gavin King, Bertrand Renuart
+ */
+public class TextType extends ImmutableType {
+
+	public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
+		String str = (String) value;
+		st.setCharacterStream( index, new StringReader(str), str.length() );
+	}
+
+	public Object get(ResultSet rs, String name) throws HibernateException, SQLException {
+
+			// Retrieve the value of the designated column in the current row of this
+			// ResultSet object as a java.io.Reader object
+			Reader charReader = rs.getCharacterStream(name);
+
+			// if the corresponding SQL value is NULL, the reader we got is NULL as well
+			if (charReader==null) return null;
+
+			// Fetch Reader content up to the end - and put characters in a StringBuffer
+			StringBuffer sb = new StringBuffer();
+			try {
+				char[] buffer = new char[2048];
+				while (true) {
+					int amountRead = charReader.read(buffer, 0, buffer.length);
+					if ( amountRead == -1 ) break;
+					sb.append(buffer, 0, amountRead);
+				}
+			}
+			catch (IOException ioe) {
+				throw new HibernateException( "IOException occurred reading text", ioe );
+			}
+			finally {
+				try {
+					charReader.close();
+				}
+				catch (IOException e) {
+					throw new HibernateException( "IOException occurred closing stream", e );
+				}
+			}
+
+			// Return StringBuffer content as a large String
+			return sb.toString();
+	}
+
+	public int sqlType() {
+		return Types.CLOB; //or Types.LONGVARCHAR?
+	}
+
+	public Class getReturnedClass() {
+		return String.class;
+	}
+
+	public String getName() { return "text"; }
+
+	public String toString(Object val) {
+		return (String) val;
+	}
+	public Object fromStringValue(String xml) {
+		return xml;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/TimeType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/TimeType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/TimeType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,107 @@
+//$Id: TimeType.java 8891 2005-12-21 05:13:29Z oneovthafew $
+package org.hibernate.type;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Time;
+import java.sql.Types;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * <tt>time</tt>: A type that maps an SQL TIME to a Java
+ * java.util.Date or java.sql.Time.
+ * @author Gavin King
+ */
+public class TimeType extends MutableType implements LiteralType {
+
+	private static final String TIME_FORMAT = "HH:mm:ss";
+
+	public Object get(ResultSet rs, String name) throws SQLException {
+		return rs.getTime(name);
+	}
+	public Class getReturnedClass() {
+		return java.util.Date.class;
+	}
+	public void set(PreparedStatement st, Object value, int index) throws SQLException {
+
+		Time time;
+		if (value instanceof Time) {
+			time = (Time) value;
+		}
+		else {
+			time = new Time( ( (java.util.Date) value ).getTime() );
+		}
+		st.setTime(index, time);
+	}
+
+	public int sqlType() {
+		return Types.TIME;
+	}
+	public String getName() { return "time"; }
+
+	public String toString(Object val) {
+		return new SimpleDateFormat(TIME_FORMAT).format( (java.util.Date) val );
+	}
+	public boolean isEqual(Object x, Object y) {
+
+		if (x==y) return true;
+		if (x==null || y==null) return false;
+
+		Date xdate = (Date) x;
+		Date ydate = (Date) y;
+		
+		if ( xdate.getTime()==ydate.getTime() ) return true;
+		
+		Calendar calendar1 = java.util.Calendar.getInstance();
+		Calendar calendar2 = java.util.Calendar.getInstance();
+		calendar1.setTime( xdate );
+		calendar2.setTime( ydate );
+
+		return calendar1.get(Calendar.HOUR_OF_DAY) == calendar2.get(Calendar.HOUR_OF_DAY)
+			&& calendar1.get(Calendar.MINUTE) == calendar2.get(Calendar.MINUTE)
+			&& calendar1.get(Calendar.SECOND) == calendar2.get(Calendar.SECOND)
+			&& calendar1.get(Calendar.MILLISECOND) == calendar2.get(Calendar.MILLISECOND);
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode) {
+		Calendar calendar = java.util.Calendar.getInstance();
+		calendar.setTime( (java.util.Date) x );
+		int hashCode = 1;
+		hashCode = 31 * hashCode + calendar.get(Calendar.HOUR_OF_DAY);
+		hashCode = 31 * hashCode + calendar.get(Calendar.MINUTE);
+		hashCode = 31 * hashCode + calendar.get(Calendar.SECOND);
+		hashCode = 31 * hashCode + calendar.get(Calendar.MILLISECOND);
+		return hashCode;
+	}
+
+	public Object deepCopyNotNull(Object value) {
+		return  new Time( ( (java.util.Date) value ).getTime() );
+	}
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return '\'' + new Time( ( (java.util.Date) value ).getTime() ).toString() + '\'';
+	}
+
+	public Object fromStringValue(String xml) throws HibernateException {
+		try {
+			return new SimpleDateFormat(TIME_FORMAT).parse(xml);
+		}
+		catch (ParseException pe) {
+			throw new HibernateException("could not parse XML", pe);
+		}
+	}
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/TimeZoneType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/TimeZoneType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/TimeZoneType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+//$Id: TimeZoneType.java 7825 2005-08-10 20:23:55Z oneovthafew $
+package org.hibernate.type;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.TimeZone;
+
+import org.hibernate.EntityMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * <tt>timezone</tt>: A type that maps an SQL VARCHAR to a
+ * <tt>java.util.TimeZone</tt>
+ * @see java.util.TimeZone
+ * @author Gavin King
+ */
+public class TimeZoneType extends ImmutableType implements LiteralType {
+
+	public Object get(ResultSet rs, String name)
+	throws HibernateException, SQLException {
+		String id = (String) Hibernate.STRING.nullSafeGet(rs, name);
+		return (id==null) ? null : TimeZone.getTimeZone(id);
+	}
+
+
+	public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
+		Hibernate.STRING.set(st, ( (TimeZone) value ).getID(), index);
+	}
+
+	public int sqlType() {
+		return Hibernate.STRING.sqlType();
+	}
+
+	public String toString(Object value) throws HibernateException {
+		return ( (TimeZone) value ).getID();
+	}
+
+	public int compare(Object x, Object y, EntityMode entityMode) {
+		return ( (TimeZone) x ).getID().compareTo( ( (TimeZone) y ).getID() );
+	}
+
+	public Object fromStringValue(String xml) throws HibernateException {
+		return TimeZone.getTimeZone(xml);
+	}
+
+	public Class getReturnedClass() {
+		return TimeZone.class;
+	}
+
+	public String getName() {
+		return "timezone";
+	}
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return ( (LiteralType) Hibernate.STRING ).objectToSQLString(
+			( (TimeZone) value ).getID(), dialect
+		);
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/TimestampType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/TimestampType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/TimestampType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,135 @@
+//$Id: TimestampType.java 8891 2005-12-21 05:13:29Z oneovthafew $
+package org.hibernate.type;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Comparator;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.util.ComparableComparator;
+
+/**
+ * <tt>timestamp</tt>: A type that maps an SQL TIMESTAMP to a Java
+ * java.util.Date or java.sql.Timestamp.
+ * @author Gavin King
+ */
+public class TimestampType extends MutableType implements VersionType, LiteralType {
+
+	private static final String TIMESTAMP_FORMAT = "yyyy-MM-dd HH:mm:ss";
+
+	public Object get(ResultSet rs, String name) throws SQLException {
+		return rs.getTimestamp(name);
+	}
+	
+	public Class getReturnedClass() {
+		return java.util.Date.class;
+	}
+	
+	public void set(PreparedStatement st, Object value, int index) throws SQLException {
+		Timestamp ts;
+		if (value instanceof Timestamp) {
+			ts = (Timestamp) value;
+		}
+		else {
+			ts = new Timestamp( ( (java.util.Date) value ).getTime() );
+		}
+		st.setTimestamp(index, ts);
+	}
+
+	public int sqlType() {
+		return Types.TIMESTAMP;
+	}
+	
+	public String getName() { return "timestamp"; }
+
+	public String toString(Object val) {
+		return new SimpleDateFormat(TIMESTAMP_FORMAT).format( (java.util.Date) val );
+	}
+
+	public Object deepCopyNotNull(Object value) {
+		if ( value instanceof Timestamp ) {
+			Timestamp orig = (Timestamp) value;
+			Timestamp ts = new Timestamp( orig.getTime() );
+			ts.setNanos( orig.getNanos() );
+			return ts;
+		}
+		else {
+			java.util.Date orig = (java.util.Date) value;
+			return new java.util.Date( orig.getTime() );
+		}
+	}
+
+	public boolean isEqual(Object x, Object y) {
+
+		if (x==y) return true;
+		if (x==null || y==null) return false;
+
+		long xTime = ( (java.util.Date) x ).getTime();
+		long yTime = ( (java.util.Date) y ).getTime();
+		boolean xts = x instanceof Timestamp;
+		boolean yts = y instanceof Timestamp;
+		int xNanos = xts ? ( (Timestamp) x ).getNanos() : 0;
+		int yNanos = yts ? ( (Timestamp) y ).getNanos() : 0;
+		if ( !Environment.jvmHasJDK14Timestamp() ) {
+			xTime += xNanos / 1000000;
+			yTime += yNanos / 1000000;
+		}
+		if ( xTime!=yTime ) return false;
+		if (xts && yts) {
+			// both are Timestamps
+			int xn = xNanos % 1000000;
+			int yn = yNanos % 1000000;
+			return xn==yn;
+		}
+		else {
+			// at least one is a plain old Date
+			return true;
+		}
+
+	}
+
+	public int getHashCode(Object x, EntityMode entityMode) {
+		java.util.Date ts = (java.util.Date) x;
+		return new Long( ts.getTime() / 1000 ).hashCode();
+	}
+
+	public Object next(Object current, SessionImplementor session) {
+		return seed( session );
+	}
+
+	public Object seed(SessionImplementor session) {
+		return new Timestamp( System.currentTimeMillis() );
+	}
+
+	public Comparator getComparator() {
+		return ComparableComparator.INSTANCE;
+	}
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return '\'' + new Timestamp( ( (java.util.Date) value ).getTime() ).toString() + '\'';
+	}
+
+	public Object fromStringValue(String xml) throws HibernateException {
+		try {
+			return new Timestamp( new SimpleDateFormat(TIMESTAMP_FORMAT).parse(xml).getTime() );
+		}
+		catch (ParseException pe) {
+			throw new HibernateException("could not parse XML", pe);
+		}
+	}
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/TrueFalseType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/TrueFalseType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/TrueFalseType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+//$Id: TrueFalseType.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.type;
+
+/**
+ * <tt>true_false</tt>: A type that maps an SQL CHAR(1) to a Java Boolean.
+ * @author Gavin King
+ */
+public class TrueFalseType extends CharBooleanType {
+
+	protected final String getTrueString() {
+		return "T";
+	}
+	protected final String getFalseString() {
+		return "F";
+	}
+	public String getName() { return "true_false"; }
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/Type.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/Type.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/Type.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,427 @@
+//$Id: Type.java 7793 2005-08-10 05:06:40Z oneovthafew $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map;
+
+import org.dom4j.Node;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * Defines a mapping from a Java type to an JDBC datatype. This interface is intended to
+ * be implemented by applications that need custom types.<br>
+ * <br>
+ * Implementors should usually be immutable and <b>must</b> certainly be threadsafe.
+ *
+ * @author Gavin King
+ */
+public interface Type extends Serializable {
+
+	/**
+	 * Return true if the implementation is castable to
+	 * <tt>AssociationType</tt>. This does not necessarily imply that
+	 * the type actually represents an association.
+	 * @see AssociationType
+	 * @return boolean
+	 */
+	public boolean isAssociationType();
+	/**
+	 * Is this type a collection type.
+	 */
+	public boolean isCollectionType();
+
+	/**
+	 * Is this type a component type. If so, the implementation
+	 * must be castable to <tt>AbstractComponentType</tt>. A component
+	 * type may own collections or associations and hence must provide
+	 * certain extra functionality.
+	 * @see AbstractComponentType
+	 * @return boolean
+	 */
+	public boolean isComponentType();
+
+	/**
+	 * Is this type an entity type?
+	 * @return boolean
+	 */
+	public boolean isEntityType();
+
+	/**
+	 * Is this an "any" type.
+	 *
+	 * i.e. a reference to a persistent entity
+	 * that is not modelled as a (foreign key) association.
+	 */
+	public boolean isAnyType();
+	
+	public boolean isXMLElement();
+
+	/**
+	 * Return the SQL type codes for the columns mapped by this type. The codes
+	 * are defined on <tt>java.sql.Types</tt>.
+	 * @see java.sql.Types
+	 * @return the typecodes
+	 * @throws MappingException
+	 */
+	public int[] sqlTypes(Mapping mapping) throws MappingException;
+
+	/**
+	 * How many columns are used to persist this type.
+	 */
+	public int getColumnSpan(Mapping mapping) throws MappingException;
+
+	/**
+	 * The class returned by <tt>nullSafeGet()</tt> methods. This is used to 
+	 * establish the class of an array of this type.
+	 *
+	 * @return Class
+	 */
+	public Class getReturnedClass();
+
+	/**
+	 * Compare two instances of the class mapped by this type for persistence
+	 * "equality" - equality of persistent state - taking a shortcut for
+	 * entity references.
+	 * @param x
+	 * @param y
+	 * @param entityMode
+	 *
+	 * @return boolean
+	 * @throws HibernateException
+	 */
+	public boolean isSame(Object x, Object y, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Compare two instances of the class mapped by this type for persistence
+	 * "equality" - equality of persistent state.
+	 * @param x
+	 * @param y
+	 * @param entityMode 
+	 *
+	 * @return boolean
+	 * @throws HibernateException
+	 */
+	public boolean isEqual(Object x, Object y, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Compare two instances of the class mapped by this type for persistence
+	 * "equality" - equality of persistent state.
+	 * @param x
+	 * @param y
+	 * @param entityMode 
+	 *
+	 * @return boolean
+	 * @throws HibernateException
+	 */
+	public boolean isEqual(Object x, Object y, EntityMode entityMode, SessionFactoryImplementor factory) 
+	throws HibernateException;
+
+	/**
+	 * Get a hashcode, consistent with persistence "equality"
+	 * @param x
+	 * @param entityMode 
+	 */
+	public int getHashCode(Object x, EntityMode entityMode) throws HibernateException;
+
+	/**
+	 * Get a hashcode, consistent with persistence "equality"
+	 * @param x
+	 * @param entityMode 
+	 * @param factory
+	 */
+	public int getHashCode(Object x, EntityMode entityMode, SessionFactoryImplementor factory) 
+	throws HibernateException;
+	
+	/**
+	 * compare two instances of the type
+	 * @param entityMode 
+	 */
+	public int compare(Object x, Object y, EntityMode entityMode);
+
+	/**
+	 * Should the parent be considered dirty, given both the old and current field or 
+	 * element value?
+	 * 
+	 * @param old the old value
+	 * @param current the current value
+	 * @param session
+	 * @return true if the field is dirty
+	 */
+	public boolean isDirty(Object old, Object current, SessionImplementor session)
+	throws HibernateException;
+	/**
+	 * Should the parent be considered dirty, given both the old and current field or 
+	 * element value?
+	 * 
+	 * @param old the old value
+	 * @param current the current value
+	 * @param checkable which columns are actually updatable
+	 * @param session
+	 * @return true if the field is dirty
+	 */
+	public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session)
+	throws HibernateException;
+
+	/**
+	 * Has the parent object been modified, compared to the current database state?
+	 * @param oldHydratedState the database state, in a "hydrated" form, with identifiers unresolved
+	 * @param currentState the current state of the object
+	 * @param checkable which columns are actually updatable
+	 * @param session
+	 * @return true if the field has been modified
+	 */
+	public boolean isModified(Object oldHydratedState, Object currentState, boolean[] checkable, SessionImplementor session)
+	throws HibernateException;
+
+	/**
+	 * Retrieve an instance of the mapped class from a JDBC resultset. Implementors
+	 * should handle possibility of null values.
+	 *
+	 * @see Type#hydrate(ResultSet, String[], SessionImplementor, Object) alternative, 2-phase property initialization
+	 * @param rs
+	 * @param names the column names
+	 * @param session
+	 * @param owner the parent entity
+	 * @return Object
+	 * @throws HibernateException
+	 * @throws SQLException
+	 */
+	public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
+	throws HibernateException, SQLException;
+
+	/**
+	 * Retrieve an instance of the mapped class from a JDBC resultset. Implementations
+	 * should handle possibility of null values. This method might be called if the
+	 * type is known to be a single-column type.
+	 *
+	 * @param rs
+	 * @param name the column name
+	 * @param session
+	 * @param owner the parent entity
+	 * @return Object
+	 * @throws HibernateException
+	 * @throws SQLException
+	 */
+	public Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object owner)
+	throws HibernateException, SQLException;
+
+	/**
+	 * Write an instance of the mapped class to a prepared statement, ignoring some columns. 
+	 * Implementors should handle possibility of null values. A multi-column type should be 
+	 * written to parameters starting from <tt>index</tt>.
+	 * @param st
+	 * @param value the object to write
+	 * @param index statement parameter index
+	 * @param settable an array indicating which columns to ignore
+	 * @param session
+	 *
+	 * @throws HibernateException
+	 * @throws SQLException
+	 */
+	public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SessionImplementor session)
+	throws HibernateException, SQLException;
+
+	/**
+	 * Write an instance of the mapped class to a prepared statement. Implementors
+	 * should handle possibility of null values. A multi-column type should be written
+	 * to parameters starting from <tt>index</tt>.
+	 * @param st
+	 * @param value the object to write
+	 * @param index statement parameter index
+	 * @param session
+	 *
+	 * @throws HibernateException
+	 * @throws SQLException
+	 */
+	public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session)
+	throws HibernateException, SQLException;
+
+	/**
+	 * A representation of the value to be embedded in an XML element.
+	 *
+	 * @param value
+	 * @param factory
+	 * @return String
+	 * @throws HibernateException
+	 */
+	public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory)
+	throws HibernateException;
+
+	/**
+	 * A representation of the value to be embedded in a log file.
+	 *
+	 * @param value
+	 * @param factory
+	 * @return String
+	 * @throws HibernateException
+	 */
+	public String toLoggableString(Object value, SessionFactoryImplementor factory)
+	throws HibernateException;
+
+	/**
+	 * Parse the XML representation of an instance.
+	 * @param xml
+	 * @param factory
+	 *
+	 * @return an instance of the type
+	 * @throws HibernateException
+	 */
+	public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException;
+
+	/**
+	 * Returns the abbreviated name of the type.
+	 *
+	 * @return String the Hibernate type name
+	 */
+	public String getName();
+
+	/**
+	 * Return a deep copy of the persistent state, stopping at entities and at
+	 * collections.
+	 * @param value generally a collection element or entity field
+	 * @param entityMode 
+	 * @param factory
+	 * @return Object a copy
+	 */
+	public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory) 
+	throws HibernateException;
+
+	/**
+	 * Are objects of this type mutable. (With respect to the referencing object ...
+	 * entities and collections are considered immutable because they manage their
+	 * own internal state.)
+	 *
+	 * @return boolean
+	 */
+	public boolean isMutable();
+
+	/**
+	 * Return a cacheable "disassembled" representation of the object.
+	 * @param value the value to cache
+	 * @param session the session
+	 * @param owner optional parent entity object (needed for collections)
+	 * @return the disassembled, deep cloned state
+	 */
+	public Serializable disassemble(Object value, SessionImplementor session, Object owner) throws HibernateException;
+
+	/**
+	 * Reconstruct the object from its cached "disassembled" state.
+	 * @param cached the disassembled state from the cache
+	 * @param session the session
+	 * @param owner the parent entity object
+	 * @return the the object
+	 */
+	public Object assemble(Serializable cached, SessionImplementor session, Object owner)
+	throws HibernateException;
+	
+	/**
+	 * Called before assembling a query result set from the query cache, to allow batch fetching
+	 * of entities missing from the second-level cache.
+	 */
+	public void beforeAssemble(Serializable cached, SessionImplementor session);
+
+	/**
+	 * Retrieve an instance of the mapped class, or the identifier of an entity or collection, 
+	 * from a JDBC resultset. This is useful for 2-phase property initialization - the second 
+	 * phase is a call to <tt>resolveIdentifier()</tt>.
+	 * 
+	 * @see Type#resolve(Object, SessionImplementor, Object)
+	 * @param rs
+	 * @param names the column names
+	 * @param session the session
+	 * @param owner the parent entity
+	 * @return Object an identifier or actual value
+	 * @throws HibernateException
+	 * @throws SQLException
+	 */
+	public Object hydrate(ResultSet rs, String[] names, SessionImplementor session, Object owner)
+	throws HibernateException, SQLException;
+
+	/**
+	 * Map identifiers to entities or collections. This is the second phase of 2-phase property 
+	 * initialization.
+	 * 
+	 * @see Type#hydrate(ResultSet, String[], SessionImplementor, Object)
+	 * @param value an identifier or value returned by <tt>hydrate()</tt>
+	 * @param owner the parent entity
+	 * @param session the session
+	 * @return the given value, or the value associated with the identifier
+	 * @throws HibernateException
+	 */
+	public Object resolve(Object value, SessionImplementor session, Object owner)
+	throws HibernateException;
+	
+	/**
+	 * Given a hydrated, but unresolved value, return a value that may be used to
+	 * reconstruct property-ref associations.
+	 */
+	public Object semiResolve(Object value, SessionImplementor session, Object owner)
+	throws HibernateException;
+	
+	/**
+	 * Get the type of a semi-resolved value.
+	 */
+	public Type getSemiResolvedType(SessionFactoryImplementor factory);
+
+	/**
+	 * During merge, replace the existing (target) value in the entity we are merging to
+	 * with a new (original) value from the detached entity we are merging. For immutable
+	 * objects, or null values, it is safe to simply return the first parameter. For
+	 * mutable objects, it is safe to return a copy of the first parameter. For objects
+	 * with component values, it might make sense to recursively replace component values.
+	 *
+	 * @param original the value from the detached entity being merged
+	 * @param target the value in the managed entity
+	 * @return the value to be merged
+	 */
+	public Object replace(
+			Object original, 
+			Object target, 
+			SessionImplementor session, 
+			Object owner, 
+			Map copyCache)
+	throws HibernateException;
+	
+	/**
+	 * During merge, replace the existing (target) value in the entity we are merging to
+	 * with a new (original) value from the detached entity we are merging. For immutable
+	 * objects, or null values, it is safe to simply return the first parameter. For
+	 * mutable objects, it is safe to return a copy of the first parameter. For objects
+	 * with component values, it might make sense to recursively replace component values.
+	 *
+	 * @param original the value from the detached entity being merged
+	 * @param target the value in the managed entity
+	 * @return the value to be merged
+	 */
+	public Object replace(
+			Object original, 
+			Object target, 
+			SessionImplementor session, 
+			Object owner, 
+			Map copyCache, 
+			ForeignKeyDirection foreignKeyDirection)
+	throws HibernateException;
+	
+	/**
+	 * Given an instance of the type, return an array of boolean, indicating
+	 * which mapped columns would be null.
+	 * 
+	 * @param value an instance of the type
+	 */
+	public boolean[] toColumnNullness(Object value, Mapping mapping);
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/TypeFactory.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/TypeFactory.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/TypeFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,665 @@
+// $Id: TypeFactory.java 11496 2007-05-09 03:54:06Z steve.ebersole at jboss.com $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TimeZone;
+
+import org.hibernate.Hibernate;
+import org.hibernate.MappingException;
+import org.hibernate.classic.Lifecycle;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.intercept.LazyPropertyInitializer;
+import org.hibernate.property.BackrefPropertyAccessor;
+import org.hibernate.tuple.StandardProperty;
+import org.hibernate.usertype.CompositeUserType;
+import org.hibernate.usertype.UserType;
+import org.hibernate.usertype.ParameterizedType;
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * Used internally to obtain instances of <tt>Type</tt>. Applications should use static methods
+ * and constants on <tt>org.hibernate.Hibernate</tt>.
+ *
+ * @see org.hibernate.Hibernate
+ * @author Gavin King
+ */
+public final class TypeFactory {
+
+	private static final Map BASIC_TYPES;
+
+	static {
+		HashMap basics = new HashMap();
+		basics.put( boolean.class.getName(), Hibernate.BOOLEAN );
+		basics.put( long.class.getName(), Hibernate.LONG );
+		basics.put( short.class.getName(), Hibernate.SHORT );
+		basics.put( int.class.getName(), Hibernate.INTEGER );
+		basics.put( byte.class.getName(), Hibernate.BYTE );
+		basics.put( float.class.getName(), Hibernate.FLOAT );
+		basics.put( double.class.getName(), Hibernate.DOUBLE );
+		basics.put( char.class.getName(), Hibernate.CHARACTER );
+		basics.put( Hibernate.CHARACTER.getName(), Hibernate.CHARACTER );
+		basics.put( Hibernate.INTEGER.getName(), Hibernate.INTEGER );
+		basics.put( Hibernate.STRING.getName(), Hibernate.STRING );
+		basics.put( Hibernate.DATE.getName(), Hibernate.DATE );
+		basics.put( Hibernate.TIME.getName(), Hibernate.TIME );
+		basics.put( Hibernate.TIMESTAMP.getName(), Hibernate.TIMESTAMP );
+		basics.put( "dbtimestamp", new DbTimestampType() );
+		basics.put( Hibernate.LOCALE.getName(), Hibernate.LOCALE );
+		basics.put( Hibernate.CALENDAR.getName(), Hibernate.CALENDAR );
+		basics.put( Hibernate.CALENDAR_DATE.getName(), Hibernate.CALENDAR_DATE );
+		basics.put( Hibernate.CURRENCY.getName(), Hibernate.CURRENCY );
+		basics.put( Hibernate.TIMEZONE.getName(), Hibernate.TIMEZONE );
+		basics.put( Hibernate.CLASS.getName(), Hibernate.CLASS );
+		basics.put( Hibernate.TRUE_FALSE.getName(), Hibernate.TRUE_FALSE );
+		basics.put( Hibernate.YES_NO.getName(), Hibernate.YES_NO );
+		basics.put( Hibernate.BINARY.getName(), Hibernate.BINARY );
+		basics.put( Hibernate.TEXT.getName(), Hibernate.TEXT );
+		basics.put( Hibernate.BLOB.getName(), Hibernate.BLOB );
+		basics.put( Hibernate.CLOB.getName(), Hibernate.CLOB );
+		basics.put( Hibernate.BIG_DECIMAL.getName(), Hibernate.BIG_DECIMAL );
+		basics.put( Hibernate.BIG_INTEGER.getName(), Hibernate.BIG_INTEGER );
+		basics.put( Hibernate.SERIALIZABLE.getName(), Hibernate.SERIALIZABLE );
+		basics.put( Hibernate.OBJECT.getName(), Hibernate.OBJECT );
+		basics.put( Boolean.class.getName(), Hibernate.BOOLEAN );
+		basics.put( Long.class.getName(), Hibernate.LONG );
+		basics.put( Short.class.getName(), Hibernate.SHORT );
+		basics.put( Integer.class.getName(), Hibernate.INTEGER );
+		basics.put( Byte.class.getName(), Hibernate.BYTE );
+		basics.put( Float.class.getName(), Hibernate.FLOAT );
+		basics.put( Double.class.getName(), Hibernate.DOUBLE );
+		basics.put( Character.class.getName(), Hibernate.CHARACTER );
+		basics.put( String.class.getName(), Hibernate.STRING );
+		basics.put( java.util.Date.class.getName(), Hibernate.TIMESTAMP );
+		basics.put( Time.class.getName(), Hibernate.TIME );
+		basics.put( Timestamp.class.getName(), Hibernate.TIMESTAMP );
+		basics.put( java.sql.Date.class.getName(), Hibernate.DATE );
+		basics.put( BigDecimal.class.getName(), Hibernate.BIG_DECIMAL );
+		basics.put( BigInteger.class.getName(), Hibernate.BIG_INTEGER );
+		basics.put( Locale.class.getName(), Hibernate.LOCALE );
+		basics.put( Calendar.class.getName(), Hibernate.CALENDAR );
+		basics.put( GregorianCalendar.class.getName(), Hibernate.CALENDAR );
+		if ( CurrencyType.CURRENCY_CLASS != null ) {
+			basics.put( CurrencyType.CURRENCY_CLASS.getName(), Hibernate.CURRENCY );
+		}
+		basics.put( TimeZone.class.getName(), Hibernate.TIMEZONE );
+		basics.put( Object.class.getName(), Hibernate.OBJECT );
+		basics.put( Class.class.getName(), Hibernate.CLASS );
+		basics.put( byte[].class.getName(), Hibernate.BINARY );
+		basics.put( "byte[]", Hibernate.BINARY );
+		basics.put( Byte[].class.getName(), Hibernate.WRAPPER_BINARY );
+		basics.put( "Byte[]", Hibernate.WRAPPER_BINARY );
+		basics.put( char[].class.getName(), Hibernate.CHAR_ARRAY );
+		basics.put( "char[]", Hibernate.CHAR_ARRAY );
+		basics.put( Character[].class.getName(), Hibernate.CHARACTER_ARRAY );
+		basics.put( "Character[]", Hibernate.CHARACTER_ARRAY );
+		basics.put( Blob.class.getName(), Hibernate.BLOB );
+		basics.put( Clob.class.getName(), Hibernate.CLOB );
+		basics.put( Serializable.class.getName(), Hibernate.SERIALIZABLE );
+
+		Type type = new AdaptedImmutableType(Hibernate.DATE);
+		basics.put( type.getName(), type );
+		type = new AdaptedImmutableType(Hibernate.TIME);
+		basics.put( type.getName(), type );
+		type = new AdaptedImmutableType(Hibernate.TIMESTAMP);
+		basics.put( type.getName(), type );
+		type = new AdaptedImmutableType( new DbTimestampType() );
+		basics.put( type.getName(), type );
+		type = new AdaptedImmutableType(Hibernate.CALENDAR);
+		basics.put( type.getName(), type );
+		type = new AdaptedImmutableType(Hibernate.CALENDAR_DATE);
+		basics.put( type.getName(), type );
+		type = new AdaptedImmutableType(Hibernate.SERIALIZABLE);
+		basics.put( type.getName(), type );
+		type = new AdaptedImmutableType(Hibernate.BINARY);
+		basics.put( type.getName(), type );
+
+		BASIC_TYPES = Collections.unmodifiableMap( basics );
+	}
+
+	private TypeFactory() {
+		throw new UnsupportedOperationException();
+	}
+
+	/**
+	 * A one-to-one association type for the given class
+	 */
+	public static EntityType oneToOne(
+			String persistentClass,
+			ForeignKeyDirection foreignKeyType,
+			String uniqueKeyPropertyName,
+			boolean lazy,
+			boolean unwrapProxy,
+			boolean isEmbeddedInXML,
+			String entityName,
+			String propertyName
+	) {
+		return new OneToOneType(
+				persistentClass,
+				foreignKeyType,
+				uniqueKeyPropertyName,
+				lazy,
+				unwrapProxy,
+				isEmbeddedInXML,
+				entityName,
+				propertyName
+			);
+	}
+
+	/**
+	 * A many-to-one association type for the given class
+	 */
+	public static EntityType manyToOne(String persistentClass) {
+		return new ManyToOneType( persistentClass );
+	}
+
+	/**
+	 * A many-to-one association type for the given class
+	 */
+	public static EntityType manyToOne(String persistentClass, boolean lazy) {
+		return new ManyToOneType( persistentClass, lazy );
+	}
+
+	/**
+	 * A many-to-one association type for the given class
+	 */
+	public static EntityType manyToOne(
+			String persistentClass,
+			String uniqueKeyPropertyName,
+			boolean lazy,
+			boolean unwrapProxy,
+			boolean isEmbeddedInXML,
+			boolean ignoreNotFound
+	) {
+		return new ManyToOneType(
+				persistentClass,
+				uniqueKeyPropertyName,
+				lazy,
+				unwrapProxy,
+				isEmbeddedInXML,
+				ignoreNotFound
+			);
+	}
+
+	/**
+	 * Given the name of a Hibernate basic type, return an instance of
+	 * <tt>org.hibernate.type.Type</tt>.
+	 */
+	public static Type basic(String name) {
+		return (Type) BASIC_TYPES.get( name );
+	}
+
+	/**
+	 * Uses heuristics to deduce a Hibernate type given a string naming the type or Java class.
+	 * Return an instance of <tt>org.hibernate.type.Type</tt>.
+	 */
+	public static Type heuristicType(String typeName) throws MappingException {
+		return heuristicType( typeName, null );
+	}
+
+	/**
+	 * Uses heuristics to deduce a Hibernate type given a string naming the type or Java class.
+	 * Return an instance of <tt>org.hibernate.type.Type</tt>.
+	 */
+	public static Type heuristicType(String typeName, Properties parameters)
+			throws MappingException {
+		Type type = TypeFactory.basic( typeName );
+		if ( type == null ) {
+			Class typeClass;
+			try {
+				typeClass = ReflectHelper.classForName( typeName );
+			}
+			catch (ClassNotFoundException cnfe) {
+				typeClass = null;
+			}
+			if ( typeClass != null ) {
+				if ( Type.class.isAssignableFrom( typeClass ) ) {
+					try {
+						type = (Type) typeClass.newInstance();
+					}
+					catch (Exception e) {
+						throw new MappingException(
+								"Could not instantiate Type: " + typeClass.getName(),
+								e
+							);
+					}
+					injectParameters(type, parameters);
+				}
+				else if ( CompositeUserType.class.isAssignableFrom( typeClass ) ) {
+					type = new CompositeCustomType( typeClass, parameters );
+				}
+				else if ( UserType.class.isAssignableFrom( typeClass ) ) {
+					type = new CustomType( typeClass, parameters );
+				}
+				else if ( Lifecycle.class.isAssignableFrom( typeClass ) ) {
+					type = Hibernate.entity( typeClass );
+				}
+				else if ( Serializable.class.isAssignableFrom( typeClass ) ) {
+					type = Hibernate.serializable( typeClass );
+				}
+			}
+		}
+		return type;
+
+	}
+
+	/**
+	 * The legacy contract.
+	 *
+	 * @deprecated Use {@link #customCollection(String, java.util.Properties, String, String, boolean)} instead
+	 */
+	public static CollectionType customCollection(
+			String typeName,
+			String role,
+			String propertyRef,
+			boolean embedded) {
+		return customCollection( typeName, null, role, propertyRef, embedded );
+	}
+
+	public static CollectionType customCollection(
+			String typeName,
+			Properties typeParameters,
+			String role,
+			String propertyRef,
+			boolean embedded) {
+		Class typeClass;
+		try {
+			typeClass = ReflectHelper.classForName( typeName );
+		}
+		catch ( ClassNotFoundException cnfe ) {
+			throw new MappingException( "user collection type class not found: " + typeName, cnfe );
+		}
+		CustomCollectionType result = new CustomCollectionType( typeClass, role, propertyRef, embedded );
+		if ( typeParameters != null ) {
+			TypeFactory.injectParameters( result.getUserType(), typeParameters );
+		}
+		return result;
+	}
+
+	// Collection Types:
+
+	public static CollectionType array(String role, String propertyRef, boolean embedded,
+			Class elementClass) {
+		return new ArrayType( role, propertyRef, elementClass, embedded );
+	}
+
+	public static CollectionType list(String role, String propertyRef, boolean embedded) {
+		return new ListType( role, propertyRef, embedded );
+	}
+
+	public static CollectionType bag(String role, String propertyRef, boolean embedded) {
+		return new BagType( role, propertyRef, embedded );
+	}
+
+	public static CollectionType idbag(String role, String propertyRef, boolean embedded) {
+		return new IdentifierBagType( role, propertyRef, embedded );
+	}
+
+	public static CollectionType map(String role, String propertyRef, boolean embedded) {
+		return new MapType( role, propertyRef, embedded );
+	}
+
+	public static CollectionType orderedMap(String role, String propertyRef, boolean embedded) {
+		return new OrderedMapType( role, propertyRef, embedded );
+	}
+
+	public static CollectionType set(String role, String propertyRef, boolean embedded) {
+		return new SetType( role, propertyRef, embedded );
+	}
+
+	public static CollectionType orderedSet(String role, String propertyRef, boolean embedded) {
+		return new OrderedSetType( role, propertyRef, embedded );
+	}
+
+	public static CollectionType sortedMap(String role, String propertyRef, boolean embedded,
+			Comparator comparator) {
+		return new SortedMapType( role, propertyRef, comparator, embedded );
+	}
+
+	public static CollectionType sortedSet(String role, String propertyRef, boolean embedded,
+			Comparator comparator) {
+		return new SortedSetType( role, propertyRef, comparator, embedded );
+	}
+
+	public static void injectParameters(Object type, Properties parameters) {
+		if (type instanceof ParameterizedType) {
+			( (ParameterizedType) type ).setParameterValues(parameters);
+		}
+		else if ( parameters!=null && !parameters.isEmpty() ) {
+			throw new MappingException(
+					"type is not parameterized: " +
+					type.getClass().getName()
+				);
+		}
+	}
+
+
+	// convenience methods relating to operations across arrays of types...
+
+	/**
+	 * Deep copy a series of values from one array to another...
+	 *
+	 * @param values The values to copy (the source)
+	 * @param types The value types
+	 * @param copy an array indicating which values to include in the copy
+	 * @param target The array into which to copy the values
+	 * @param session The orginating session
+	 */
+	public static void deepCopy(
+			final Object[] values,
+			final Type[] types,
+			final boolean[] copy,
+			final Object[] target,
+			final SessionImplementor session) {
+		for ( int i = 0; i < types.length; i++ ) {
+			if ( copy[i] ) {
+				if ( values[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY
+					|| values[i] == BackrefPropertyAccessor.UNKNOWN ) {
+					target[i] = values[i];
+				}
+				else {
+					target[i] = types[i].deepCopy( values[i], session.getEntityMode(), session
+						.getFactory() );
+				}
+			}
+		}
+	}
+
+	/**
+	 * Apply the {@link Type#beforeAssemble} operation across a series of values.
+	 *
+	 * @param row The values
+	 * @param types The value types
+	 * @param session The orginating session
+	 */
+	public static void beforeAssemble(
+			final Serializable[] row,
+			final Type[] types,
+			final SessionImplementor session) {
+		for ( int i = 0; i < types.length; i++ ) {
+			if ( row[i] != LazyPropertyInitializer.UNFETCHED_PROPERTY
+				&& row[i] != BackrefPropertyAccessor.UNKNOWN ) {
+				types[i].beforeAssemble( row[i], session );
+			}
+		}
+	}
+
+	/**
+	 * Apply the {@link Type#assemble} operation across a series of values.
+	 *
+	 * @param row The values
+	 * @param types The value types
+	 * @param session The orginating session
+	 * @param owner The entity "owning" the values
+	 * @return The assembled state
+	 */
+	public static Object[] assemble(
+			final Serializable[] row,
+			final Type[] types,
+			final SessionImplementor session,
+			final Object owner) {
+		Object[] assembled = new Object[row.length];
+		for ( int i = 0; i < types.length; i++ ) {
+			if ( row[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY || row[i] == BackrefPropertyAccessor.UNKNOWN ) {
+				assembled[i] = row[i];
+			}
+			else {
+				assembled[i] = types[i].assemble( row[i], session, owner );
+			}
+		}
+		return assembled;
+	}
+
+	/**
+	 * Apply the {@link Type#disassemble} operation across a series of values.
+	 *
+	 * @param row The values
+	 * @param types The value types
+	 * @param nonCacheable An array indicating which values to include in the disassemled state
+	 * @param session The orginating session
+	 * @param owner The entity "owning" the values
+	 * @return The disassembled state
+	 */
+	public static Serializable[] disassemble(
+			final Object[] row,
+			final Type[] types,
+			final boolean[] nonCacheable,
+			final SessionImplementor session,
+			final Object owner) {
+		Serializable[] disassembled = new Serializable[row.length];
+		for ( int i = 0; i < row.length; i++ ) {
+			if ( nonCacheable!=null && nonCacheable[i] ) {
+				disassembled[i] = LazyPropertyInitializer.UNFETCHED_PROPERTY;
+			}
+			else if ( row[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY || row[i] == BackrefPropertyAccessor.UNKNOWN ) {
+				disassembled[i] = (Serializable) row[i];
+			}
+			else {
+				disassembled[i] = types[i].disassemble( row[i], session, owner );
+			}
+		}
+		return disassembled;
+	}
+
+	/**
+	 * Apply the {@link Type#replace} operation across a series of values.
+	 *
+	 * @param original The source of the state
+	 * @param target The target into which to replace the source values.
+	 * @param types The value types
+	 * @param session The orginating session
+	 * @param owner The entity "owning" the values
+	 * @param copyCache A map representing a cache of already replaced state
+	 * @return The replaced state
+	 */
+	public static Object[] replace(
+			final Object[] original,
+			final Object[] target,
+			final Type[] types,
+			final SessionImplementor session,
+			final Object owner,
+			final Map copyCache) {
+		Object[] copied = new Object[original.length];
+		for ( int i = 0; i < types.length; i++ ) {
+			if ( original[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY
+				|| original[i] == BackrefPropertyAccessor.UNKNOWN ) {
+				copied[i] = target[i];
+			}
+			else {
+				copied[i] = types[i].replace( original[i], target[i], session, owner, copyCache );
+			}
+		}
+		return copied;
+	}
+
+	/**
+	 * Apply the {@link Type#replace} operation across a series of values.
+	 *
+	 * @param original The source of the state
+	 * @param target The target into which to replace the source values.
+	 * @param types The value types
+	 * @param session The orginating session
+	 * @param owner The entity "owning" the values
+	 * @param copyCache A map representing a cache of already replaced state
+	 * @param foreignKeyDirection FK directionality to be applied to the replacement
+	 * @return The replaced state
+	 */
+	public static Object[] replace(
+			final Object[] original,
+			final Object[] target,
+			final Type[] types,
+			final SessionImplementor session,
+			final Object owner,
+			final Map copyCache,
+			final ForeignKeyDirection foreignKeyDirection) {
+		Object[] copied = new Object[original.length];
+		for ( int i = 0; i < types.length; i++ ) {
+			if ( original[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY
+				|| original[i] == BackrefPropertyAccessor.UNKNOWN ) {
+				copied[i] = target[i];
+			}
+			else {
+				copied[i] = types[i].replace( original[i], target[i], session, owner, copyCache, foreignKeyDirection );
+			}
+		}
+		return copied;
+	}
+
+	/**
+	 * Apply the {@link Type#replace} operation across a series of values, as
+	 * long as the corresponding {@link Type} is an association.
+	 * <p/>
+	 * If the corresponding type is a component type, then apply {@link #replaceAssociations}
+	 * accross the component subtypes but do not replace the component value itself.
+	 *
+	 * @param original The source of the state
+	 * @param target The target into which to replace the source values.
+	 * @param types The value types
+	 * @param session The orginating session
+	 * @param owner The entity "owning" the values
+	 * @param copyCache A map representing a cache of already replaced state
+	 * @param foreignKeyDirection FK directionality to be applied to the replacement
+	 * @return The replaced state
+	 */
+	public static Object[] replaceAssociations(
+			final Object[] original,
+			final Object[] target,
+			final Type[] types,
+			final SessionImplementor session,
+			final Object owner,
+			final Map copyCache,
+			final ForeignKeyDirection foreignKeyDirection) {
+		Object[] copied = new Object[original.length];
+		for ( int i = 0; i < types.length; i++ ) {
+			if ( original[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY
+					|| original[i] == BackrefPropertyAccessor.UNKNOWN ) {
+				copied[i] = target[i];
+			}
+			else if ( types[i].isComponentType() ) {
+				// need to extract the component values and check for subtype replacements...
+				AbstractComponentType componentType = ( AbstractComponentType ) types[i];
+				Type[] subtypes = componentType.getSubtypes();
+				Object[] origComponentValues = original[i] == null ? new Object[subtypes.length] : componentType.getPropertyValues( original[i], session );
+				Object[] targetComponentValues = componentType.getPropertyValues( target[i], session );
+				replaceAssociations( origComponentValues, targetComponentValues, subtypes, session, null, copyCache, foreignKeyDirection );
+				copied[i] = target[i];
+			}
+			else if ( !types[i].isAssociationType() ) {
+				copied[i] = target[i];
+			}
+			else {
+				copied[i] = types[i].replace( original[i], target[i], session, owner, copyCache, foreignKeyDirection );
+			}
+		}
+		return copied;
+	}
+
+	/**
+	 * Determine if any of the given field values are dirty, returning an array containing
+	 * indices of the dirty fields.
+	 * <p/>
+	 * If it is determined that no fields are dirty, null is returned.
+	 *
+	 * @param properties The property definitions
+	 * @param currentState The current state of the entity
+	 * @param previousState The baseline state of the entity
+	 * @param includeColumns Columns to be included in the dirty checking, per property
+	 * @param anyUninitializedProperties Does the entity currently hold any uninitialized property values?
+	 * @param session The session from which the dirty check request originated.
+	 * @return Array containing indices of the dirty properties, or null if no properties considered dirty.
+	 */
+	public static int[] findDirty(
+			final StandardProperty[] properties,
+			final Object[] currentState,
+			final Object[] previousState,
+			final boolean[][] includeColumns,
+			final boolean anyUninitializedProperties,
+			final SessionImplementor session) {
+		int[] results = null;
+		int count = 0;
+		int span = properties.length;
+
+		for ( int i = 0; i < span; i++ ) {
+			final boolean dirty = currentState[i] != LazyPropertyInitializer.UNFETCHED_PROPERTY
+					&& properties[i].isDirtyCheckable( anyUninitializedProperties )
+					&& properties[i].getType().isDirty( previousState[i], currentState[i], includeColumns[i], session );
+			if ( dirty ) {
+				if ( results == null ) {
+					results = new int[span];
+				}
+				results[count++] = i;
+			}
+		}
+
+		if ( count == 0 ) {
+			return null;
+		}
+		else {
+			int[] trimmed = new int[count];
+			System.arraycopy( results, 0, trimmed, 0, count );
+			return trimmed;
+		}
+	}
+
+	/**
+	 * Determine if any of the given field values are modified, returning an array containing
+	 * indices of the modified fields.
+	 * <p/>
+	 * If it is determined that no fields are dirty, null is returned.
+	 *
+	 * @param properties The property definitions
+	 * @param currentState The current state of the entity
+	 * @param previousState The baseline state of the entity
+	 * @param includeColumns Columns to be included in the mod checking, per property
+	 * @param anyUninitializedProperties Does the entity currently hold any uninitialized property values?
+	 * @param session The session from which the dirty check request originated.
+	 * @return Array containing indices of the modified properties, or null if no properties considered modified.
+	 */
+	public static int[] findModified(
+			final StandardProperty[] properties, 
+			final Object[] currentState,
+			final Object[] previousState,
+			final boolean[][] includeColumns,
+			final boolean anyUninitializedProperties,
+			final SessionImplementor session) {
+		int[] results = null;
+		int count = 0;
+		int span = properties.length;
+
+		for ( int i = 0; i < span; i++ ) {
+			final boolean modified = currentState[i]!=LazyPropertyInitializer.UNFETCHED_PROPERTY
+					&& properties[i].isDirtyCheckable(anyUninitializedProperties)
+					&& properties[i].getType().isModified( previousState[i], currentState[i], includeColumns[i], session );
+
+			if ( modified ) {
+				if ( results == null ) {
+					results = new int[span];
+				}
+				results[count++] = i;
+			}
+		}
+
+		if ( count == 0 ) {
+			return null;
+		}
+		else {
+			int[] trimmed = new int[count];
+			System.arraycopy( results, 0, trimmed, 0, count );
+			return trimmed;
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/VersionType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/VersionType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/VersionType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+//$Id: VersionType.java 7736 2005-08-03 20:03:34Z steveebersole $
+package org.hibernate.type;
+
+import java.util.Comparator;
+
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * A <tt>Type</tt> that may be used to version data.
+ * @author Gavin King
+ */
+public interface VersionType extends Type {
+	/**
+	 * Generate an initial version.
+	 *
+	 * @param session The session from which this request originates.
+	 * @return an instance of the type
+	 */
+	public Object seed(SessionImplementor session);
+
+	/**
+	 * Increment the version.
+	 *
+	 * @param session The session from which this request originates.
+	 * @param current the current version
+	 * @return an instance of the type
+	 */
+	public Object next(Object current, SessionImplementor session);
+
+	/**
+	 * Get a comparator for version values.
+	 *
+	 * @return The comparator to use to compare different version values.
+	 */
+	public Comparator getComparator();
+
+	/**
+	 * Are the two version values considered equal?
+	 *
+	 * @param x One value to check.
+	 * @param y The other value to check.
+	 * @return true if the values are equal, false otherwise.
+	 */
+	public boolean isEqual(Object x, Object y);
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/WrapperBinaryType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/WrapperBinaryType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/WrapperBinaryType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+//$Id: $
+package org.hibernate.type;
+
+import org.hibernate.HibernateException;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class WrapperBinaryType extends AbstractBynaryType {
+	protected Object toExternalFormat(byte[] bytes) {
+		if (bytes == null) return null;
+		int length = bytes.length;
+		Byte[] result = new Byte[length];
+		for ( int index = 0; index < length ; index++ ) {
+			result[index] = new Byte( bytes[index] );
+		}
+		return result;
+	}
+
+	protected byte[] toInternalFormat(Object val) {
+		if (val == null) return null;
+		Byte[] bytes = (Byte[]) val;
+		int length = bytes.length;
+		byte[] result = new byte[length];
+		for ( int i = 0; i < length ; i++ ) {
+			if (bytes[i] == null)
+				throw new HibernateException("Unable to store an Byte[] when one of its element is null");
+			result[i] = bytes[i].byteValue();
+		}
+		return result;
+	}
+
+	public Class getReturnedClass() {
+		return Byte[].class;
+	}
+
+	public String getName() {
+		//TODO find a decent name before documenting
+		return "wrapper-binary";
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/YesNoType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/YesNoType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/YesNoType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+//$Id: YesNoType.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.type;
+
+/**
+ * <tt>yes_no</tt>: A type that maps an SQL CHAR(1) to a Java Boolean.
+ * @author Gavin King
+ */
+public class YesNoType extends CharBooleanType {
+
+	protected final String getTrueString() {
+		return "Y";
+	}
+	protected final String getFalseString() {
+		return "N";
+	}
+	public String getName() { return "yes_no"; }
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/type/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/type/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/type/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+<head></head>
+<body>
+<p>
+	A Hibernate <tt>Type</tt> is a strategy for mapping a 
+	Java property type to a JDBC type or types.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/type/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/CompositeUserType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/CompositeUserType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/CompositeUserType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,184 @@
+//$Id: CompositeUserType.java 6471 2005-04-19 20:36:59Z oneovthafew $
+package org.hibernate.usertype;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * A <tt>UserType</tt> that may be dereferenced in a query.
+ * This interface allows a custom type to define "properties".
+ * These need not necessarily correspond to physical JavaBeans
+ * style properties.<br>
+ * <br>
+ * A <tt>CompositeUserType</tt> may be used in almost every way
+ * that a component may be used. It may even contain many-to-one
+ * associations.<br>
+ * <br>
+ * Implementors must be immutable and must declare a public
+ * default constructor.<br>
+ * <br>
+ * Unlike <tt>UserType</tt>, cacheability does not depend upon
+ * serializability. Instead, <tt>assemble()</tt> and
+ * <tt>disassemble</tt> provide conversion to/from a cacheable
+ * representation.
+ *
+ * @see UserType for more simple cases
+ * @see org.hibernate.type.Type
+ * @author Gavin King
+ */
+public interface CompositeUserType {
+
+	/**
+	 * Get the "property names" that may be used in a
+	 * query.
+	 *
+	 * @return an array of "property names"
+	 */
+	public String[] getPropertyNames();
+
+	/**
+	 * Get the corresponding "property types".
+	 *
+	 * @return an array of Hibernate types
+	 */
+	public Type[] getPropertyTypes();
+
+	/**
+	 * Get the value of a property.
+	 *
+	 * @param component an instance of class mapped by this "type"
+	 * @param property
+	 * @return the property value
+	 * @throws HibernateException
+	 */
+	public Object getPropertyValue(Object component, int property) throws HibernateException;
+
+	/**
+	 * Set the value of a property.
+	 *
+	 * @param component an instance of class mapped by this "type"
+	 * @param property
+	 * @param value the value to set
+	 * @throws HibernateException
+	 */
+	public void setPropertyValue(Object component, int property, Object value) throws HibernateException;
+
+	/**
+	 * The class returned by <tt>nullSafeGet()</tt>.
+	 *
+	 * @return Class
+	 */
+	public Class returnedClass();
+
+	/**
+	 * Compare two instances of the class mapped by this type for persistence "equality".
+	 * Equality of the persistent state.
+	 *
+	 * @param x
+	 * @param y
+	 * @return boolean
+	 * @throws HibernateException
+	 */
+	public boolean equals(Object x, Object y) throws HibernateException;
+	
+	/**
+	 * Get a hashcode for the instance, consistent with persistence "equality"
+	 */
+	public int hashCode(Object x) throws HibernateException;
+
+	/**
+	 * Retrieve an instance of the mapped class from a JDBC resultset. Implementors
+	 * should handle possibility of null values.
+	 *
+	 * @param rs a JDBC result set
+	 * @param names the column names
+	 * @param session
+	 * @param owner the containing entity
+	 * @return Object
+	 * @throws HibernateException
+	 * @throws SQLException
+	 */
+	public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) 
+	throws HibernateException, SQLException;
+
+	/**
+	 * Write an instance of the mapped class to a prepared statement. Implementors
+	 * should handle possibility of null values. A multi-column type should be written
+	 * to parameters starting from <tt>index</tt>.
+	 *
+	 * @param st a JDBC prepared statement
+	 * @param value the object to write
+	 * @param index statement parameter index
+	 * @param session
+	 * @throws HibernateException
+	 * @throws SQLException
+	 */
+	public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) 
+	throws HibernateException, SQLException;
+
+	/**
+	 * Return a deep copy of the persistent state, stopping at entities and at collections.
+	 *
+	 * @param value generally a collection element or entity field
+	 * @return Object a copy
+	 * @throws HibernateException
+	 */
+	public Object deepCopy(Object value) throws HibernateException;
+
+	/**
+	 * Check if objects of this type mutable.
+	 *
+	 * @return boolean
+	 */
+	public boolean isMutable();
+
+	/**
+	 * Transform the object into its cacheable representation. At the very least this
+	 * method should perform a deep copy. That may not be enough for some implementations,
+	 * however; for example, associations must be cached as identifier values. (optional
+	 * operation)
+	 *
+	 * @param value the object to be cached
+	 * @param session
+	 * @return a cachable representation of the object
+	 * @throws HibernateException
+	 */
+	public Serializable disassemble(Object value, SessionImplementor session) throws HibernateException;
+
+	/**
+	 * Reconstruct an object from the cacheable representation. At the very least this
+	 * method should perform a deep copy. (optional operation)
+	 *
+	 * @param cached the object to be cached
+	 * @param session
+	 * @param owner the owner of the cached object
+	 * @return a reconstructed object from the cachable representation
+	 * @throws HibernateException
+	 */
+	public Object assemble(Serializable cached, SessionImplementor session, Object owner) 
+	throws HibernateException;
+
+	/**
+	 * During merge, replace the existing (target) value in the entity we are merging to
+	 * with a new (original) value from the detached entity we are merging. For immutable
+	 * objects, or null values, it is safe to simply return the first parameter. For
+	 * mutable objects, it is safe to return a copy of the first parameter. However, since
+	 * composite user types often define component values, it might make sense to recursively 
+	 * replace component values in the target object.
+	 * 
+	 * @param original
+	 * @param target
+	 * @param session
+	 * @param owner
+	 * @return
+	 * @throws HibernateException
+	 */
+	public Object replace(Object original, Object target, SessionImplementor session, Object owner) 
+	throws HibernateException;
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/EnhancedUserType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/EnhancedUserType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/EnhancedUserType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+//$Id: EnhancedUserType.java 5956 2005-02-28 06:07:06Z oneovthafew $
+package org.hibernate.usertype;
+
+/**
+ * A custom type that may function as an identifier or
+ * discriminator type, or may be marshalled to and from
+ * an XML document
+ * 
+ * @author Gavin King
+ */
+public interface EnhancedUserType extends UserType {
+	/**
+	 * Return an SQL literal representation of the value
+	 */
+	public String objectToSQLString(Object value);
+	
+	/**
+	 * Return a string representation of this value, as it
+	 * should appear in an XML document
+	 */
+	public String toXMLString(Object value);
+	/**
+	 * Parse a string representation of this value, as it
+	 * appears in an XML document
+	 */
+	public Object fromXMLString(String xmlValue);
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/EnhancedUserType.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/LoggableUserType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/LoggableUserType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/LoggableUserType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+package org.hibernate.usertype;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Marker interface for user types which want to perform custom
+ * logging of their corresponding values
+ *
+ * @author Steve Ebersole
+ */
+public interface LoggableUserType {
+	/**
+	 * Generate a loggable string representation of the collection (value).
+	 *
+	 * @param value The collection to be logged; guarenteed to be non-null and initialized.
+	 * @param factory The factory.
+	 * @return The loggable string representation.
+	 */
+	public String toLoggableString(Object value, SessionFactoryImplementor factory);
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/ParameterizedType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/ParameterizedType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/ParameterizedType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+//$Id: ParameterizedType.java 4499 2004-09-05 04:32:54Z oneovthafew $
+package org.hibernate.usertype;
+
+import java.util.Properties;
+
+/**
+ * Support for parameterizable types. A UserType or CustomUserType may be
+ * made parameterizable by implementing this interface. Parameters for a
+ * type may be set by using a nested type element for the property element
+ * in the mapping file, or by defining a typedef.
+ *
+ * @author Michael Gloegl
+ */
+public interface ParameterizedType {
+
+	/**
+	 * Gets called by Hibernate to pass the configured type parameters to
+	 * the implementation.
+	 */
+	public void setParameterValues(Properties parameters);
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/UserCollectionType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/UserCollectionType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/UserCollectionType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,70 @@
+//$Id: UserCollectionType.java 10086 2006-07-05 18:17:27Z steve.ebersole at jboss.com $
+package org.hibernate.usertype;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+
+/**
+ * A custom type for mapping user-written classes that implement <tt>PersistentCollection</tt>
+ * 
+ * @see org.hibernate.collection.PersistentCollection
+ * @author Gavin King
+ */
+public interface UserCollectionType {
+	
+	/**
+	 * Instantiate an uninitialized instance of the collection wrapper
+	 */
+	public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister) 
+	throws HibernateException;
+	
+	/**
+	 * Wrap an instance of a collection
+	 */
+	public PersistentCollection wrap(SessionImplementor session, Object collection);
+	
+	/**
+	 * Return an iterator over the elements of this collection - the passed collection
+	 * instance may or may not be a wrapper
+	 */
+	public Iterator getElementsIterator(Object collection);
+
+	/**
+	 * Optional operation. Does the collection contain the entity instance?
+	 */
+	public boolean contains(Object collection, Object entity);
+	/**
+	 * Optional operation. Return the index of the entity in the collection.
+	 */
+	public Object indexOf(Object collection, Object entity);
+	
+	/**
+	 * Replace the elements of a collection with the elements of another collection
+	 */
+	public Object replaceElements(
+			Object original, 
+			Object target, 
+			CollectionPersister persister, 
+			Object owner, 
+			Map copyCache, 
+			SessionImplementor session)
+			throws HibernateException;
+
+	/**
+	 * Instantiate an empty instance of the "underlying" collection (not a wrapper),
+	 * but with the given anticipated size (i.e. accounting for initial size
+	 * and perhaps load factor).
+	 *
+	 * @param anticipatedSize The anticipated size of the instaniated collection
+	 * after we are done populating it.  Note, may be negative to indicate that
+	 * we not yet know anything about the anticipated size (i.e., when initializing
+	 * from a result set row by row).
+	 */
+	public Object instantiate(int anticipatedSize);
+	
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/UserCollectionType.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/UserType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/UserType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/UserType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,160 @@
+//$Id: UserType.java 6133 2005-03-21 16:53:58Z turin42 $
+package org.hibernate.usertype;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.hibernate.HibernateException;
+
+/**
+ * This interface should be implemented by user-defined "types".
+ * A "type" class is <em>not</em> the actual property type - it
+ * is a class that knows how to serialize instances of another
+ * class to and from JDBC.<br>
+ * <br>
+ * This interface
+ * <ul>
+ * <li>abstracts user code from future changes to the <tt>Type</tt>
+ * interface,</li>
+ * <li>simplifies the implementation of custom types and</li>
+ * <li>hides certain "internal" interfaces from user code.</li>
+ * </ul>
+ * <br>
+ * Implementors must be immutable and must declare a public
+ * default constructor.<br>
+ * <br>
+ * The actual class mapped by a <tt>UserType</tt> may be just
+ * about anything.<br>
+ * <br>
+ * <tt>CompositeUserType</tt> provides an extended version of
+ * this interface that is useful for more complex cases.<br>
+ * <br>
+ * Alternatively, custom types could implement <tt>Type</tt>
+ * directly or extend one of the abstract classes in
+ * <tt>org.hibernate.type</tt>. This approach risks future
+ * incompatible changes to classes or interfaces in that
+ * package.
+ *
+ * @see CompositeUserType for more complex cases
+ * @see org.hibernate.type.Type
+ * @author Gavin King
+ */
+public interface UserType {
+
+	/**
+	 * Return the SQL type codes for the columns mapped by this type. The
+	 * codes are defined on <tt>java.sql.Types</tt>.
+	 * @see java.sql.Types
+	 * @return int[] the typecodes
+	 */
+	public int[] sqlTypes();
+
+	/**
+	 * The class returned by <tt>nullSafeGet()</tt>.
+	 *
+	 * @return Class
+	 */
+	public Class returnedClass();
+
+	/**
+	 * Compare two instances of the class mapped by this type for persistence "equality".
+	 * Equality of the persistent state.
+	 *
+	 * @param x
+	 * @param y
+	 * @return boolean
+	 */
+	public boolean equals(Object x, Object y) throws HibernateException;
+
+	/**
+	 * Get a hashcode for the instance, consistent with persistence "equality"
+	 */
+	public int hashCode(Object x) throws HibernateException;
+
+	/**
+	 * Retrieve an instance of the mapped class from a JDBC resultset. Implementors
+	 * should handle possibility of null values.
+	 *
+	 * @param rs a JDBC result set
+	 * @param names the column names
+	 * @param owner the containing entity
+	 * @return Object
+	 * @throws HibernateException
+	 * @throws SQLException
+	 */
+	public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException;
+
+	/**
+	 * Write an instance of the mapped class to a prepared statement. Implementors
+	 * should handle possibility of null values. A multi-column type should be written
+	 * to parameters starting from <tt>index</tt>.
+	 *
+	 * @param st a JDBC prepared statement
+	 * @param value the object to write
+	 * @param index statement parameter index
+	 * @throws HibernateException
+	 * @throws SQLException
+	 */
+	public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException;
+
+	/**
+	 * Return a deep copy of the persistent state, stopping at entities and at
+	 * collections. It is not necessary to copy immutable objects, or null
+	 * values, in which case it is safe to simply return the argument.
+	 *
+	 * @param value the object to be cloned, which may be null
+	 * @return Object a copy
+	 */
+	public Object deepCopy(Object value) throws HibernateException;
+
+	/**
+	 * Are objects of this type mutable?
+	 *
+	 * @return boolean
+	 */
+	public boolean isMutable();
+
+	/**
+	 * Transform the object into its cacheable representation. At the very least this
+	 * method should perform a deep copy if the type is mutable. That may not be enough
+	 * for some implementations, however; for example, associations must be cached as
+	 * identifier values. (optional operation)
+	 *
+	 * @param value the object to be cached
+	 * @return a cachable representation of the object
+	 * @throws HibernateException
+	 */
+	public Serializable disassemble(Object value) throws HibernateException;
+
+	/**
+	 * Reconstruct an object from the cacheable representation. At the very least this
+	 * method should perform a deep copy if the type is mutable. (optional operation)
+	 *
+	 * @param cached the object to be cached
+	 * @param owner the owner of the cached object
+	 * @return a reconstructed object from the cachable representation
+	 * @throws HibernateException
+	 */
+	public Object assemble(Serializable cached, Object owner) throws HibernateException;
+
+	/**
+	 * During merge, replace the existing (target) value in the entity we are merging to
+	 * with a new (original) value from the detached entity we are merging. For immutable
+	 * objects, or null values, it is safe to simply return the first parameter. For
+	 * mutable objects, it is safe to return a copy of the first parameter. For objects
+	 * with component values, it might make sense to recursively replace component values.
+	 *
+	 * @param original the value from the detached entity being merged
+	 * @param target the value in the managed entity
+	 * @return the value to be merged
+	 */
+	public Object replace(Object original, Object target, Object owner) throws HibernateException;
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/UserVersionType.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/UserVersionType.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/UserVersionType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+//$Id: UserVersionType.java 7736 2005-08-03 20:03:34Z steveebersole $
+package org.hibernate.usertype;
+
+import java.util.Comparator;
+
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * A user type that may be used for a version property
+ * 
+ * @author Gavin King
+ */
+public interface UserVersionType extends UserType, Comparator {
+	/**
+	 * Generate an initial version.
+	 *
+	 * @param session The session from which this request originates.  May be
+	 * null; currently this only happens during startup when trying to determine
+	 * the "unsaved value" of entities.
+	 * @return an instance of the type
+	 */
+	public Object seed(SessionImplementor session);
+	/**
+	 * Increment the version.
+	 *
+	 * @param session The session from which this request originates.
+	 * @param current the current version
+	 * @return an instance of the type
+	 */
+	public Object next(Object current, SessionImplementor session);
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/UserVersionType.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>
+	Interfaces for user-defined custom types.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/usertype/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/ArrayHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/ArrayHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/ArrayHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,345 @@
+//$Id: ArrayHelper.java 7546 2005-07-19 18:17:15Z oneovthafew $
+package org.hibernate.util;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.LockMode;
+import org.hibernate.type.Type;
+
+public final class ArrayHelper {
+	
+	/*public static boolean contains(Object[] array, Object object) {
+		for ( int i=0; i<array.length; i++ ) {
+			if ( array[i].equals(object) ) return true;
+		}
+		return false;
+	}*/
+	
+	public static int indexOf(Object[] array, Object object) {
+		for ( int i=0; i<array.length; i++ ) {
+			if ( array[i].equals(object) ) return i;
+		}
+		return -1;
+	}
+	
+	/*public static Object[] clone(Class elementClass, Object[] array) {
+		Object[] result = (Object[]) Array.newInstance( elementClass, array.length );
+		System.arraycopy(array, 0, result, 0, array.length);
+		return result;
+	}*/
+
+	public static String[] toStringArray(Object[] objects) {
+		int length=objects.length;
+		String[] result = new String[length];
+		for (int i=0; i<length; i++) {
+			result[i] = objects[i].toString();
+		}
+		return result;
+	}
+
+	public static String[] fillArray(String value, int length) {
+		String[] result = new String[length];
+		Arrays.fill(result, value);
+		return result;
+	}
+
+	public static int[] fillArray(int value, int length) {
+		int[] result = new int[length];
+		Arrays.fill(result, value);
+		return result;
+	}
+
+	public static LockMode[] fillArray(LockMode lockMode, int length) {
+		LockMode[] array = new LockMode[length];
+		Arrays.fill(array, lockMode);
+		return array;
+	}
+
+	public static String[] toStringArray(Collection coll) {
+		return (String[]) coll.toArray(EMPTY_STRING_ARRAY);
+	}
+	
+	public static String[][] to2DStringArray(Collection coll) {
+		return (String[][]) coll.toArray( new String[ coll.size() ][] );
+	}
+	
+	public static int[][] to2DIntArray(Collection coll) {
+		return (int[][]) coll.toArray( new int[ coll.size() ][] );
+	}
+	
+	public static Type[] toTypeArray(Collection coll) {
+		return (Type[]) coll.toArray(EMPTY_TYPE_ARRAY);
+	}
+
+	public static int[] toIntArray(Collection coll) {
+		Iterator iter = coll.iterator();
+		int[] arr = new int[ coll.size() ];
+		int i=0;
+		while( iter.hasNext() ) {
+			arr[i++] = ( (Integer) iter.next() ).intValue();
+		}
+		return arr;
+	}
+
+	public static boolean[] toBooleanArray(Collection coll) {
+		Iterator iter = coll.iterator();
+		boolean[] arr = new boolean[ coll.size() ];
+		int i=0;
+		while( iter.hasNext() ) {
+			arr[i++] = ( (Boolean) iter.next() ).booleanValue();
+		}
+		return arr;
+	}
+
+	public static Object[] typecast(Object[] array, Object[] to) {
+		return java.util.Arrays.asList(array).toArray(to);
+	}
+
+	//Arrays.asList doesn't do primitive arrays
+	public static List toList(Object array) {
+		if ( array instanceof Object[] ) return Arrays.asList( (Object[]) array ); //faster?
+		int size = Array.getLength(array);
+		ArrayList list = new ArrayList(size);
+		for (int i=0; i<size; i++) {
+			list.add( Array.get(array, i) );
+		}
+		return list;
+	}
+
+	public static String[] slice(String[] strings, int begin, int length) {
+		String[] result = new String[length];
+		for ( int i=0; i<length; i++ ) {
+			result[i] = strings[begin+i];
+		}
+		return result;
+	}
+
+	public static Object[] slice(Object[] objects, int begin, int length) {
+		Object[] result = new Object[length];
+		for ( int i=0; i<length; i++ ) {
+			result[i] = objects[begin+i];
+		}
+		return result;
+	}
+
+	public static List toList(Iterator iter) {
+		List list = new ArrayList();
+		while ( iter.hasNext() ) {
+			list.add( iter.next() );
+		}
+		return list;
+	}
+
+	public static String[] join(String[] x, String[] y) {
+		String[] result = new String[ x.length + y.length ];
+		for ( int i=0; i<x.length; i++ ) result[i] = x[i];
+		for ( int i=0; i<y.length; i++ ) result[i+x.length] = y[i];
+		return result;
+	}
+
+	public static String[] join(String[] x, String[] y, boolean[] use) {
+		String[] result = new String[ x.length + countTrue(use) ];
+		for ( int i=0; i<x.length; i++ ) result[i] = x[i];
+		int k = x.length;
+		for ( int i=0; i<y.length; i++ ) {
+			if ( use[i] ) result[k++] = y[i];
+		}
+		return result;
+	}
+
+	public static int[] join(int[] x, int[] y) {
+		int[] result = new int[ x.length + y.length ];
+		for ( int i=0; i<x.length; i++ ) result[i] = x[i];
+		for ( int i=0; i<y.length; i++ ) result[i+x.length] = y[i];
+		return result;
+	}
+
+	public static final boolean[] TRUE = { true };
+	public static final boolean[] FALSE = { false };
+
+	private ArrayHelper() {}
+
+	public static String toString( Object[] array ) {
+		StringBuffer sb = new StringBuffer();
+		sb.append("[");
+		for (int i = 0; i < array.length; i++) {
+			sb.append( array[i] );
+			if( i<array.length-1 ) sb.append(",");
+		}
+		sb.append("]");
+		return sb.toString();
+	}
+
+	public static boolean isAllNegative(int[] array) {
+		for ( int i=0; i<array.length; i++ ) {
+			if ( array[i] >=0 ) return false;
+		}
+		return true;
+	}
+
+	public static boolean isAllTrue(boolean[] array) {
+		for ( int i=0; i<array.length; i++ ) {
+			if ( !array[i] ) return false;
+		}
+		return true;
+	}
+
+	public static int countTrue(boolean[] array) {
+		int result=0;
+		for ( int i=0; i<array.length; i++ ) {
+			if ( array[i] ) result++;
+		}
+		return result;
+	}
+
+	/*public static int countFalse(boolean[] array) {
+		int result=0;
+		for ( int i=0; i<array.length; i++ ) {
+			if ( !array[i] ) result++;
+		}
+		return result;
+	}*/
+
+	public static boolean isAllFalse(boolean[] array) {
+		for ( int i=0; i<array.length; i++ ) {
+			if ( array[i] ) return false;
+		}
+		return true;
+	}
+
+	public static void addAll(Collection collection, Object[] array) {
+		for ( int i=0; i<array.length; i++ ) {
+			collection.add( array[i] );
+		}
+	}
+
+	public static final String[] EMPTY_STRING_ARRAY = {};
+	public static final int[] EMPTY_INT_ARRAY = {};
+	public static final boolean[] EMPTY_BOOLEAN_ARRAY = {};
+	public static final Class[] EMPTY_CLASS_ARRAY = {};
+	public static final Object[] EMPTY_OBJECT_ARRAY = {};
+	public static final Type[] EMPTY_TYPE_ARRAY = {};
+	
+	public static int[] getBatchSizes(int maxBatchSize) {
+		int batchSize = maxBatchSize;
+		int n=1;
+		while ( batchSize>1 ) {
+			batchSize = getNextBatchSize(batchSize);
+			n++;
+		}
+		int[] result = new int[n];
+		batchSize = maxBatchSize;
+		for ( int i=0; i<n; i++ ) {
+			result[i] = batchSize;
+			batchSize = getNextBatchSize(batchSize);
+		}
+		return result;
+	}
+	
+	private static int getNextBatchSize(int batchSize) {
+		if (batchSize<=10) {
+			return batchSize-1; //allow 9,8,7,6,5,4,3,2,1
+		}
+		else if (batchSize/2 < 10) {
+			return 10;
+		}
+		else {
+			return batchSize / 2;
+		}
+	}
+
+	private static int SEED = 23;
+	private static int PRIME_NUMER = 37;
+
+	/**
+	 * calculate the array hash (only the first level)
+	 */
+	public static int hash(Object[] array) {
+		int length = array.length;
+		int seed = SEED;
+		for (int index = 0 ; index < length ; index++) {
+			seed = hash( seed, array[index] == null ? 0 : array[index].hashCode() );
+		}
+		return seed;
+	}
+
+	/**
+	 * calculate the array hash (only the first level)
+	 */
+	public static int hash(char[] array) {
+		int length = array.length;
+		int seed = SEED;
+		for (int index = 0 ; index < length ; index++) {
+			seed = hash( seed, (int) array[index] ) ;
+		}
+		return seed;
+	}
+
+	/**
+	 * calculate the array hash (only the first level)
+	 */
+	public static int hash(byte[] bytes) {
+		int length = bytes.length;
+		int seed = SEED;
+		for (int index = 0 ; index < length ; index++) {
+			seed = hash( seed, (int) bytes[index] ) ;
+		}
+		return seed;
+	}
+
+	private static int hash(int seed, int i) {
+		return PRIME_NUMER * seed + i;
+	}
+
+	/**
+	 * Compare 2 arrays only at the first level
+	 */
+	public static boolean isEquals(Object[] o1, Object[] o2) {
+		if (o1 == o2) return true;
+		if (o1 == null || o2 == null) return false;
+		int length = o1.length;
+		if (length != o2.length) return false;
+		for (int index = 0 ; index < length ; index++) {
+			if ( ! o1[index].equals( o2[index] ) ) return false;
+		}
+        return true;
+	}
+
+	/**
+	 * Compare 2 arrays only at the first level
+	 */
+	public static boolean isEquals(char[] o1, char[] o2) {
+		if (o1 == o2) return true;
+		if (o1 == null || o2 == null) return false;
+		int length = o1.length;
+		if (length != o2.length) return false;
+		for (int index = 0 ; index < length ; index++) {
+			if ( ! ( o1[index] == o2[index] ) ) return false;
+		}
+        return true;
+	}
+
+	/**
+	 * Compare 2 arrays only at the first level
+	 */
+	public static boolean isEquals(byte[] b1, byte[] b2) {
+		if (b1 == b2) return true;
+		if (b1 == null || b2 == null) return false;
+		int length = b1.length;
+		if (length != b2.length) return false;
+		for (int index = 0 ; index < length ; index++) {
+			if ( ! ( b1[index] == b2[index] ) ) return false;
+		}
+        return true;
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/BytesHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/BytesHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/BytesHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: BytesHelper.java 4597 2004-09-26 03:17:21Z oneovthafew $
+package org.hibernate.util;
+
+public final class BytesHelper {
+
+	private BytesHelper() {}
+
+	public static int toInt( byte[] bytes ) {
+		int result = 0;
+		for (int i=0; i<4; i++) {
+			result = ( result << 8 ) - Byte.MIN_VALUE + (int) bytes[i];
+		}
+		return result;
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/CalendarComparator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/CalendarComparator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/CalendarComparator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: CalendarComparator.java 4496 2004-09-04 13:01:55Z oneovthafew $
+package org.hibernate.util;
+
+import java.util.Calendar;
+import java.util.Comparator;
+
+/**
+ * @author Gavin King
+ */
+public class CalendarComparator implements Comparator {
+
+	public int compare(Object x, Object y) {
+		Calendar xcal = (Calendar) x;
+		Calendar ycal = (Calendar) y;
+		if ( xcal.before(ycal) ) return -1;
+		if ( xcal.after(ycal) ) return 1;
+		return 0;
+	}
+	
+	public static final Comparator INSTANCE = new CalendarComparator();
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/util/CalendarComparator.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/Cloneable.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/Cloneable.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/Cloneable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,139 @@
+//$Id: Cloneable.java 8670 2005-11-25 17:36:29Z epbernard $
+package org.hibernate.util;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import org.hibernate.HibernateException;
+
+/**
+ * An object that is shallow-coneable
+ * 
+ * @author Steve Ebersole
+ */
+public class Cloneable {
+	
+	private static final Object[] READER_METHOD_ARGS = new Object[0];
+
+	/**
+	 * Essentially performs a shallow copy of this SessionEventListenerConfig
+	 * instance; meaning the SessionEventListenerConfig itself is cloned, but
+	 * the individual listeners are <b>not</b> cloned.
+	 *
+	 * @return The SessionEventListenerConfig shallow copy.
+	 */
+	public Object shallowCopy() {
+		return AccessController.doPrivileged(
+		        new PrivilegedAction() {
+			        public Object run() {
+				        return copyListeners();
+			        }
+		        }
+			);
+	}
+
+	/**
+	 * Checks to ensure the SessionEventListenerConfig is fully
+	 * configured (basically, that none of the listeners is null).
+	 *
+	 * @throws HibernateException If the SessionEventListenerConfig
+	 * is not fully configured.
+	 */
+	public void validate() throws HibernateException {
+		AccessController.doPrivileged(
+		        new PrivilegedAction() {
+			        public Object run() {
+				        checkListeners();
+				        return null;
+			        }
+		        }
+			);
+
+	}
+
+	private Object copyListeners() {
+		Object copy = null;
+		BeanInfo beanInfo = null;
+		try {
+			beanInfo = Introspector.getBeanInfo( getClass(), Object.class );
+			internalCheckListeners( beanInfo );
+			copy = getClass().newInstance();
+			PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
+			for ( int i = 0, max = pds.length; i < max; i++ ) {
+				try {
+					pds[i].getWriteMethod().invoke(
+							copy,
+							new Object[] {
+								pds[i].getReadMethod().invoke( this, READER_METHOD_ARGS )
+							}
+						);
+				}
+				catch( Throwable t ) {
+					throw new HibernateException( "Unable copy copy listener [" + pds[i].getName() + "]" );
+				}
+			}
+		}
+		catch( Exception t ) {
+			throw new HibernateException( "Unable to copy listeners", t );
+		}
+		finally {
+			if ( beanInfo != null ) {
+				// release the jdk internal caches everytime to ensure this
+				// plays nicely with destroyable class-loaders
+				Introspector.flushFromCaches( getClass() );
+			}
+		}
+		
+		return copy;
+	}
+
+	private void checkListeners() {
+		BeanInfo beanInfo = null;
+		try {
+			beanInfo = Introspector.getBeanInfo( getClass(), Object.class );
+			internalCheckListeners( beanInfo );
+		}
+		catch( IntrospectionException t ) {
+			throw new HibernateException( "Unable to validate listener config", t );
+		}
+		finally {
+			if ( beanInfo != null ) {
+				// release the jdk internal caches everytime to ensure this
+				// plays nicely with destroyable class-loaders
+				Introspector.flushFromCaches( getClass() );
+			}
+		}
+	}
+
+	private void internalCheckListeners(BeanInfo beanInfo) {
+		PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
+		try {
+			for ( int i = 0, max = pds.length; i < max; i++ ) {
+				final Object listener = pds[i].getReadMethod().invoke( this, READER_METHOD_ARGS );
+				if ( listener == null ) {
+					throw new HibernateException( "Listener [" + pds[i].getName() + "] was null" );
+				}
+				if ( listener.getClass().isArray() ) {
+					Object[] listenerArray = (Object[]) listener;
+					int length = listenerArray.length;
+					for ( int index = 0 ; index < length ; index++ ) {
+						if ( listenerArray[index] == null ) {
+							throw new HibernateException( "Listener in [" + pds[i].getName() + "] was null" );
+						}
+					}
+				}
+			}
+		}
+		catch( HibernateException e ) {
+			throw e;
+		}
+		catch( Throwable t ) {
+			throw new HibernateException( "Unable to validate listener config" );
+		}
+	}
+	
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/util/Cloneable.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/CollectionHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/CollectionHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/CollectionHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: CollectionHelper.java 7516 2005-07-16 22:20:48Z oneovthafew $
+package org.hibernate.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Gavin King
+ */
+public final class CollectionHelper {
+
+	public static final List EMPTY_LIST = Collections.unmodifiableList( new ArrayList(0) );
+	public static final Collection EMPTY_COLLECTION = Collections.unmodifiableCollection( new ArrayList(0) );
+	public static final Map EMPTY_MAP = Collections.unmodifiableMap( new HashMap(0) );
+	
+	private CollectionHelper() {}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/util/CollectionHelper.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/ComparableComparator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/ComparableComparator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/ComparableComparator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+//$Id: ComparableComparator.java 4496 2004-09-04 13:01:55Z oneovthafew $
+package org.hibernate.util;
+
+import java.util.Comparator;
+
+/**
+ * Delegates to Comparable
+ * @author Gavin King
+ */
+public class ComparableComparator implements Comparator {
+
+	public int compare(Object x, Object y) {
+		return ( (Comparable) x ).compareTo(y);
+	}
+	
+	public static final Comparator INSTANCE = new ComparableComparator();
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/util/ComparableComparator.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/ConfigHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/ConfigHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/ConfigHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,181 @@
+// $Id: ConfigHelper.java 9972 2006-05-31 16:59:05Z steve.ebersole at jboss.com $
+package org.hibernate.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Environment;
+
+/**
+ * A simple class to centralize logic needed to locate config files on the system.
+ *
+ * @author Steve
+ */
+public final class ConfigHelper {
+	private static final Log log = LogFactory.getLog(ConfigHelper.class);
+
+	/** Try to locate a local URL representing the incoming path.  The first attempt
+	 * assumes that the incoming path is an actual URL string (file://, etc).  If this
+	 * does not work, then the next attempts try to locate this UURL as a java system
+	 * resource.
+	 *
+	 * @param path The path representing the config location.
+	 * @return An appropriate URL or null.
+	 */
+	public static final URL locateConfig(final String path) {
+		try {
+			return new URL(path);
+		}
+		catch(MalformedURLException e) {
+			return findAsResource(path);
+		}
+	}
+
+	/** 
+	 * Try to locate a local URL representing the incoming path.  
+	 * This method <b>only</b> attempts to locate this URL as a 
+	 * java system resource.
+	 *
+	 * @param path The path representing the config location.
+	 * @return An appropriate URL or null.
+	 */
+	public static final URL findAsResource(final String path) {
+		URL url = null;
+
+		// First, try to locate this resource through the current
+		// context classloader.
+		ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+		if (contextClassLoader!=null) {
+			url = contextClassLoader.getResource(path);
+		}
+		if (url != null)
+			return url;
+
+		// Next, try to locate this resource through this class's classloader
+		url = ConfigHelper.class.getClassLoader().getResource(path);
+		if (url != null)
+			return url;
+
+		// Next, try to locate this resource through the system classloader
+		url = ClassLoader.getSystemClassLoader().getResource(path);
+
+		// Anywhere else we should look?
+		return url;
+	}
+
+	/** Open an InputStream to the URL represented by the incoming path.  First makes a call
+	 * to {@link #locateConfig(java.lang.String)} in order to find an appropriate URL.
+	 * {@link java.net.URL#openStream()} is then called to obtain the stream.
+	 *
+	 * @param path The path representing the config location.
+	 * @return An input stream to the requested config resource.
+	 * @throws HibernateException Unable to open stream to that resource.
+	 */
+	public static final InputStream getConfigStream(final String path) throws HibernateException {
+		final URL url = ConfigHelper.locateConfig(path);
+
+		if (url == null) {
+			String msg = "Unable to locate config file: " + path;
+			log.fatal(msg);
+			throw new HibernateException(msg);
+		}
+
+		try {
+			return url.openStream();
+        }
+		catch(IOException e) {
+	        throw new HibernateException("Unable to open config file: " + path, e);
+        }
+	}
+
+	/** Open an Reader to the URL represented by the incoming path.  First makes a call
+	 * to {@link #locateConfig(java.lang.String)} in order to find an appropriate URL.
+	 * {@link java.net.URL#openStream()} is then called to obtain a stream, which is then
+	 * wrapped in a Reader.
+	 *
+	 * @param path The path representing the config location.
+	 * @return An input stream to the requested config resource.
+	 * @throws HibernateException Unable to open reader to that resource.
+	 */
+	public static final Reader getConfigStreamReader(final String path) throws HibernateException {
+		return new InputStreamReader( getConfigStream(path) );
+	}
+
+	/** Loads a properties instance based on the data at the incoming config location.
+	 *
+	 * @param path The path representing the config location.
+	 * @return The loaded properties instance.
+	 * @throws HibernateException Unable to load properties from that resource.
+	 */
+	public static final Properties getConfigProperties(String path) throws HibernateException {
+		try {
+			Properties properties = new Properties();
+			properties.load( getConfigStream(path) );
+			return properties;
+		}
+		catch(IOException e) {
+			throw new HibernateException("Unable to load properties from specified config file: " + path, e);
+		}
+	}
+	
+	private ConfigHelper() {}
+
+	public static InputStream getResourceAsStream(String resource) {
+		String stripped = resource.startsWith("/") ?
+				resource.substring(1) : resource;
+
+		InputStream stream = null;
+		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+		if (classLoader!=null) {
+			stream = classLoader.getResourceAsStream( stripped );
+		}
+		if ( stream == null ) {
+			stream = Environment.class.getResourceAsStream( resource );
+		}
+		if ( stream == null ) {
+			stream = Environment.class.getClassLoader().getResourceAsStream( stripped );
+		}
+		if ( stream == null ) {
+			throw new HibernateException( resource + " not found" );
+		}
+		return stream;
+	}
+
+
+	public static InputStream getUserResourceAsStream(String resource) {
+		boolean hasLeadingSlash = resource.startsWith( "/" );
+		String stripped = hasLeadingSlash ? resource.substring(1) : resource;
+
+		InputStream stream = null;
+
+		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+		if ( classLoader != null ) {
+			stream = classLoader.getResourceAsStream( resource );
+			if ( stream == null && hasLeadingSlash ) {
+				stream = classLoader.getResourceAsStream( stripped );
+			}
+		}
+
+		if ( stream == null ) {
+			stream = Environment.class.getClassLoader().getResourceAsStream( resource );
+		}
+		if ( stream == null && hasLeadingSlash ) {
+			stream = Environment.class.getClassLoader().getResourceAsStream( stripped );
+		}
+
+		if ( stream == null ) {
+			throw new HibernateException( resource + " not found" );
+		}
+
+		return stream;
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/DTDEntityResolver.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/DTDEntityResolver.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/DTDEntityResolver.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,89 @@
+//$Id: DTDEntityResolver.java 10033 2006-06-21 06:23:30Z christian.bauer at jboss.com $
+//Contributed by Markus Meissner
+package org.hibernate.util;
+
+import java.io.InputStream;
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+
+/**
+ * An {@link EntityResolver} implementation which attempts to resolve
+ * various systemId URLs to local classpath lookups<ol>
+ * <li>Any systemId URL beginning with <tt>http://hibernate.sourceforge.net/</tt> is
+ * searched for as a classpath resource in the classloader which loaded the
+ * Hibernate classes.</li>
+ * <li>Any systemId URL using <tt>classpath</tt> as the scheme (i.e. starting
+ * with <tt>classpath://</tt> is searched for as a classpath resource using first
+ * the current thread context classloader and then the classloader which loaded
+ * the Hibernate classes.
+ * </ol>
+ * <p/>
+ * Any entity references which cannot be resolved in relation to the above
+ * rules result in returning null, which should force the SAX reader to
+ * handle the entity reference in its default manner.
+ */
+public class DTDEntityResolver implements EntityResolver, Serializable {
+
+	private static final Log log = LogFactory.getLog( DTDEntityResolver.class );
+
+	private static final String HIBERNATE_NAMESPACE = "http://hibernate.sourceforge.net/";
+	private static final String USER_NAMESPACE = "classpath://";
+
+	public InputSource resolveEntity(String publicId, String systemId) {
+		if ( systemId != null ) {
+			log.debug( "trying to resolve system-id [" + systemId + "]" );
+			if ( systemId.startsWith( HIBERNATE_NAMESPACE ) ) {
+				log.debug( "recognized hibernate namespace; attempting to resolve on classpath under org/hibernate/" );
+				String path = "org/hibernate/" + systemId.substring( HIBERNATE_NAMESPACE.length() );
+				InputStream dtdStream = resolveInHibernateNamespace( path );
+				if ( dtdStream == null ) {
+					log.debug( "unable to locate [" + systemId + "] on classpath" );
+					if ( systemId.substring( HIBERNATE_NAMESPACE.length() ).indexOf( "2.0" ) > -1 ) {
+						log.error( "Don't use old DTDs, read the Hibernate 3.x Migration Guide!" );
+					}
+				}
+				else {
+					log.debug( "located [" + systemId + "] in classpath" );
+					InputSource source = new InputSource( dtdStream );
+					source.setPublicId( publicId );
+					source.setSystemId( systemId );
+					return source;
+				}
+			}
+			else if ( systemId.startsWith( USER_NAMESPACE ) ) {
+				log.debug( "recognized local namespace; attempting to resolve on classpath" );
+				String path = systemId.substring( USER_NAMESPACE.length() );
+				InputStream stream = resolveInLocalNamespace( path );
+				if ( stream == null ) {
+					log.debug( "unable to locate [" + systemId + "] on classpath" );
+				}
+				else {
+					log.debug( "located [" + systemId + "] in classpath" );
+					InputSource source = new InputSource( stream );
+					source.setPublicId( publicId );
+					source.setSystemId( systemId );
+					return source;
+				}
+			}
+		}
+		// use default behavior
+		return null;
+	}
+
+	protected InputStream resolveInHibernateNamespace(String path) {
+		return this.getClass().getClassLoader().getResourceAsStream( path );
+	}
+
+	protected InputStream resolveInLocalNamespace(String path) {
+		try {
+			return ConfigHelper.getUserResourceAsStream( path );
+		}
+		catch( Throwable t ) {
+			return null;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/EmptyIterator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/EmptyIterator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/EmptyIterator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+//$Id: EmptyIterator.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.util;
+
+import java.util.Iterator;
+
+/**
+ * @author Gavin King
+ */
+public final class EmptyIterator implements Iterator {
+
+	public static final Iterator INSTANCE = new EmptyIterator();
+
+	public boolean hasNext() {
+		return false;
+	}
+
+	public Object next() {
+		throw new UnsupportedOperationException();
+	}
+
+	public void remove() {
+		throw new UnsupportedOperationException();
+	}
+
+	private EmptyIterator() {}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/EqualsHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/EqualsHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/EqualsHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+//$Id: EqualsHelper.java 4582 2004-09-25 11:22:20Z oneovthafew $
+package org.hibernate.util;
+
+/**
+ * @author Gavin King
+ */
+public final class EqualsHelper {
+
+	public static boolean equals(Object x, Object y) {
+		return x==y || ( x!=null && y!=null && x.equals(y) );
+	}
+	
+	private EqualsHelper() {}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/ExternalSessionFactoryConfig.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/ExternalSessionFactoryConfig.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/ExternalSessionFactoryConfig.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,374 @@
+// $Id: ExternalSessionFactoryConfig.java 10860 2006-11-22 00:02:55Z steve.ebersole at jboss.com $
+package org.hibernate.util;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+
+import java.util.Properties;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashMap;
+import java.util.HashSet;
+
+/**
+ * Defines support for various externally configurable SessionFactory(s), for
+ * example, {@link org.hibernate.jmx.HibernateService JMX} or the JCA
+ * adapter.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class ExternalSessionFactoryConfig {
+
+	private String mapResources;
+	private String dialect;
+	private String defaultSchema;
+	private String defaultCatalog;
+	private String maximumFetchDepth;
+	private String jdbcFetchSize;
+	private String jdbcBatchSize;
+	private String batchVersionedDataEnabled;
+	private String jdbcScrollableResultSetEnabled;
+	private String getGeneratedKeysEnabled;
+	private String streamsForBinaryEnabled;
+	private String reflectionOptimizationEnabled;
+	private String querySubstitutions;
+	private String showSqlEnabled;
+	private String commentsEnabled;
+	private String cacheProviderClass;
+	private String cacheProviderConfig;
+	private String cacheRegionPrefix;
+	private String secondLevelCacheEnabled;
+	private String minimalPutsEnabled;
+	private String queryCacheEnabled;
+
+	private Map additionalProperties;
+	private Set excludedPropertyNames = new HashSet();
+	private Map customListeners;
+
+
+	protected Set getExcludedPropertyNames() {
+		return excludedPropertyNames;
+	}
+
+	public final String getMapResources() {
+		return mapResources;
+	}
+
+	public final void setMapResources(String mapResources) {
+		this.mapResources = mapResources;
+	}
+
+	public void addMapResource(String mapResource) {
+		if ( mapResources==null || mapResources.length()==0 ) {
+			mapResources = mapResource.trim();
+		}
+		else {
+			mapResources += ", " + mapResource.trim();
+		}
+	}
+
+	public final String getDialect() {
+		return dialect;
+	}
+
+	public final void setDialect(String dialect) {
+		this.dialect = dialect;
+	}
+
+	public final String getDefaultSchema() {
+		return defaultSchema;
+	}
+
+	public final void setDefaultSchema(String defaultSchema) {
+		this.defaultSchema = defaultSchema;
+	}
+
+	public final String getDefaultCatalog() {
+		return defaultCatalog;
+	}
+
+	public final void setDefaultCatalog(String defaultCatalog) {
+		this.defaultCatalog = defaultCatalog;
+	}
+
+	public final String getMaximumFetchDepth() {
+		return maximumFetchDepth;
+	}
+
+	public final void setMaximumFetchDepth(String maximumFetchDepth) {
+		verifyInt( maximumFetchDepth );
+		this.maximumFetchDepth = maximumFetchDepth;
+	}
+
+	public final String getJdbcFetchSize() {
+		return jdbcFetchSize;
+	}
+
+	public final void setJdbcFetchSize(String jdbcFetchSize) {
+		verifyInt( jdbcFetchSize );
+		this.jdbcFetchSize = jdbcFetchSize;
+	}
+
+	public final String getJdbcBatchSize() {
+		return jdbcBatchSize;
+	}
+
+	public final void setJdbcBatchSize(String jdbcBatchSize) {
+		verifyInt( jdbcBatchSize );
+		this.jdbcBatchSize = jdbcBatchSize;
+	}
+
+	public final String getBatchVersionedDataEnabled() {
+		return batchVersionedDataEnabled;
+	}
+
+	public final void setBatchVersionedDataEnabled(String batchVersionedDataEnabled) {
+		this.batchVersionedDataEnabled = batchVersionedDataEnabled;
+	}
+
+	public final String getJdbcScrollableResultSetEnabled() {
+		return jdbcScrollableResultSetEnabled;
+	}
+
+	public final void setJdbcScrollableResultSetEnabled(String jdbcScrollableResultSetEnabled) {
+		this.jdbcScrollableResultSetEnabled = jdbcScrollableResultSetEnabled;
+	}
+
+	public final String getGetGeneratedKeysEnabled() {
+		return getGeneratedKeysEnabled;
+	}
+
+	public final void setGetGeneratedKeysEnabled(String getGeneratedKeysEnabled) {
+		this.getGeneratedKeysEnabled = getGeneratedKeysEnabled;
+	}
+
+	public final String getStreamsForBinaryEnabled() {
+		return streamsForBinaryEnabled;
+	}
+
+	public final void setStreamsForBinaryEnabled(String streamsForBinaryEnabled) {
+		this.streamsForBinaryEnabled = streamsForBinaryEnabled;
+	}
+
+	public final String getReflectionOptimizationEnabled() {
+		return reflectionOptimizationEnabled;
+	}
+
+	public final void setReflectionOptimizationEnabled(String reflectionOptimizationEnabled) {
+		this.reflectionOptimizationEnabled = reflectionOptimizationEnabled;
+	}
+
+	public final String getQuerySubstitutions() {
+		return querySubstitutions;
+	}
+
+	public final void setQuerySubstitutions(String querySubstitutions) {
+		this.querySubstitutions = querySubstitutions;
+	}
+
+	public final String getShowSqlEnabled() {
+		return showSqlEnabled;
+	}
+
+	public final void setShowSqlEnabled(String showSqlEnabled) {
+		this.showSqlEnabled = showSqlEnabled;
+	}
+
+	public final String getCommentsEnabled() {
+		return commentsEnabled;
+	}
+
+	public final void setCommentsEnabled(String commentsEnabled) {
+		this.commentsEnabled = commentsEnabled;
+	}
+
+	public final String getSecondLevelCacheEnabled() {
+		return secondLevelCacheEnabled;
+	}
+
+	public final void setSecondLevelCacheEnabled(String secondLevelCacheEnabled) {
+		this.secondLevelCacheEnabled = secondLevelCacheEnabled;
+	}
+
+	public final String getCacheProviderClass() {
+		return cacheProviderClass;
+	}
+
+	public final void setCacheProviderClass(String cacheProviderClass) {
+		this.cacheProviderClass = cacheProviderClass;
+	}
+
+	public String getCacheProviderConfig() {
+		return cacheProviderConfig;
+	}
+
+	public void setCacheProviderConfig(String cacheProviderConfig) {
+		this.cacheProviderConfig = cacheProviderConfig;
+	}
+
+	public final String getCacheRegionPrefix() {
+		return cacheRegionPrefix;
+	}
+
+	public final void setCacheRegionPrefix(String cacheRegionPrefix) {
+		this.cacheRegionPrefix = cacheRegionPrefix;
+	}
+
+	public final String getMinimalPutsEnabled() {
+		return minimalPutsEnabled;
+	}
+
+	public final void setMinimalPutsEnabled(String minimalPutsEnabled) {
+		this.minimalPutsEnabled = minimalPutsEnabled;
+	}
+
+	public final String getQueryCacheEnabled() {
+		return queryCacheEnabled;
+	}
+
+	public final void setQueryCacheEnabled(String queryCacheEnabled) {
+		this.queryCacheEnabled = queryCacheEnabled;
+	}
+
+	public final Map getCustomListeners() {
+		return customListeners;
+	}
+
+	public void setCustomListeners(Map customListeners) {
+		this.customListeners = customListeners;
+	}
+
+	public void setCustomListenersAsString(String customListenersString) {
+		// Note : expected in the syntax:
+		//      type=listenerClass
+		//          ({sep}type=listenerClass)*
+		// where {sep} is any whitespace or comma
+		if ( StringHelper.isNotEmpty( customListenersString) ) {
+			String[] listenerEntries = PropertiesHelper.toStringArray( customListenersString, " ,\n\t\r\f" );
+			for ( int i = 0; i < listenerEntries.length; i++ ) {
+				final int keyValueSepPosition = listenerEntries[i].indexOf( '=' );
+				final String type = listenerEntries[i].substring( 0, keyValueSepPosition );
+				final String listenerClass = listenerEntries[i].substring( keyValueSepPosition + 1 );
+				setCustomListener( type, listenerClass );
+			}
+		}
+	}
+
+	public void setCustomListener(String type, String listenerClass) {
+		if ( customListeners == null ) {
+			customListeners = new HashMap();
+		}
+		customListeners.put( type, listenerClass );
+	}
+
+	public final void addAdditionalProperty(String name, String value) {
+		if ( !getExcludedPropertyNames().contains( name ) ) {
+			if ( additionalProperties == null ) {
+				additionalProperties = new HashMap();
+			}
+			additionalProperties.put( name, value );
+		}
+	}
+
+	protected final Configuration buildConfiguration() {
+
+		Configuration cfg = new Configuration().setProperties( buildProperties() );
+
+
+		String[] mappingFiles = PropertiesHelper.toStringArray( mapResources, " ,\n\t\r\f" );
+		for ( int i = 0; i < mappingFiles.length; i++ ) {
+			cfg.addResource( mappingFiles[i] );
+		}
+
+		if ( customListeners != null && !customListeners.isEmpty() ) {
+			Iterator entries = customListeners.entrySet().iterator();
+			while ( entries.hasNext() ) {
+				final Map.Entry entry = ( Map.Entry ) entries.next();
+				final String type = ( String ) entry.getKey();
+				final Object value = entry.getValue();
+				if ( value != null ) {
+					if ( String.class.isAssignableFrom( value.getClass() ) ) {
+						// Its the listener class name
+						cfg.setListener( type, ( ( String ) value ) );
+					}
+					else {
+						// Its the listener instance (or better be)
+						cfg.setListener( type, value );
+					}
+				}
+			}
+		}
+
+		return cfg;
+	}
+
+	protected final Properties buildProperties() {
+		Properties props = new Properties();
+		setUnlessNull( props, Environment.DIALECT, dialect );
+		setUnlessNull( props, Environment.DEFAULT_SCHEMA, defaultSchema );
+		setUnlessNull( props, Environment.DEFAULT_CATALOG, defaultCatalog );
+		setUnlessNull( props, Environment.MAX_FETCH_DEPTH, maximumFetchDepth );
+		setUnlessNull( props, Environment.STATEMENT_FETCH_SIZE, jdbcFetchSize );
+		setUnlessNull( props, Environment.STATEMENT_BATCH_SIZE, jdbcBatchSize );
+		setUnlessNull( props, Environment.BATCH_VERSIONED_DATA, batchVersionedDataEnabled );
+		setUnlessNull( props, Environment.USE_SCROLLABLE_RESULTSET, jdbcScrollableResultSetEnabled );
+		setUnlessNull( props, Environment.USE_GET_GENERATED_KEYS, getGeneratedKeysEnabled );
+		setUnlessNull( props, Environment.USE_STREAMS_FOR_BINARY, streamsForBinaryEnabled );
+		setUnlessNull( props, Environment.USE_REFLECTION_OPTIMIZER, reflectionOptimizationEnabled );
+		setUnlessNull( props, Environment.QUERY_SUBSTITUTIONS, querySubstitutions );
+		setUnlessNull( props, Environment.SHOW_SQL, showSqlEnabled );
+		setUnlessNull( props, Environment.USE_SQL_COMMENTS, commentsEnabled );
+		setUnlessNull( props, Environment.CACHE_PROVIDER, cacheProviderClass );
+		setUnlessNull( props, Environment.CACHE_PROVIDER_CONFIG, cacheProviderConfig );
+		setUnlessNull( props, Environment.CACHE_REGION_PREFIX, cacheRegionPrefix );
+		setUnlessNull( props, Environment.USE_MINIMAL_PUTS, minimalPutsEnabled );
+		setUnlessNull( props, Environment.USE_SECOND_LEVEL_CACHE, secondLevelCacheEnabled );
+		setUnlessNull( props, Environment.USE_QUERY_CACHE, queryCacheEnabled );
+
+		Map extraProperties = getExtraProperties();
+		if ( extraProperties != null ) {
+			addAll( props, extraProperties );
+		}
+
+		if ( additionalProperties != null ) {
+			addAll( props, additionalProperties );
+		}
+
+		return props;
+	}
+
+	protected void addAll( Properties target, Map source ) {
+		Iterator itr = source.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			final Map.Entry entry = ( Map.Entry ) itr.next();
+			final String propertyName = ( String ) entry.getKey();
+			final String propertyValue = ( String ) entry.getValue();
+			if ( propertyName != null && propertyValue != null ) {
+				// Make sure we don't override previous set values
+				if ( !target.keySet().contains( propertyName ) ) {
+					if ( !getExcludedPropertyNames().contains( propertyName) ) {
+						target.put( propertyName, propertyValue );
+					}
+				}
+			}
+		}
+	}
+
+	protected Map getExtraProperties() {
+		return null;
+	}
+
+	private void setUnlessNull(Properties props, String key, String value) {
+		if ( value != null ) {
+			props.setProperty( key, value );
+		}
+	}
+
+	private void verifyInt(String value)
+	{
+		if ( value != null ) {
+			Integer.parseInt( value );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/FastHashMap.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/FastHashMap.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/FastHashMap.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,368 @@
+//$Id: FastHashMap.java 3890 2004-06-03 16:31:32Z steveebersole $
+/*
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowlegement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache at apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+// This class was taken from Apache commons-collections -
+// I made it final + removed the "slow" mode...
+
+package org.hibernate.util;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * <p>A customized implementation of <code>java.util.HashMap</code> designed
+ * to operate in a multithreaded environment where the large majority of
+ * method calls are read-only, instead of structural changes.
+ * Read calls are non-synchronized and write calls perform the
+ * following steps:</p>
+ * <ul>
+ * <li>Clone the existing collection
+ * <li>Perform the modification on the clone
+ * <li>Replace the existing collection with the (modified) clone
+ * </ul>
+ * <p><strong>NOTE</strong>: If you are creating and accessing a
+ * <code>HashMap</code> only within a single thread, you should use
+ * <code>java.util.HashMap</code> directly (with no synchronization), for
+ * maximum performance.</p>
+ *
+ */
+
+public final class FastHashMap implements Map, Serializable {
+
+	// ----------------------------------------------------------- Constructors
+
+	/**
+	 * Construct a an empty map.
+	 */
+	public FastHashMap() {
+
+		super();
+		this.map = new HashMap();
+
+	}
+
+	/**
+	 * Construct an empty map with the specified capacity.
+	 *
+	 * @param capacity The initial capacity of the empty map
+	 */
+	public FastHashMap(int capacity) {
+
+		super();
+		this.map = new HashMap(capacity);
+
+	}
+
+	/**
+	 * Construct an empty map with the specified capacity and load factor.
+	 *
+	 * @param capacity The initial capacity of the empty map
+	 * @param factor The load factor of the new map
+	 */
+	public FastHashMap(int capacity, float factor) {
+
+		super();
+		this.map = new HashMap(capacity, factor);
+
+	}
+
+	/**
+	 * Construct a new map with the same mappings as the specified map.
+	 *
+	 * @param map The map whose mappings are to be copied
+	 */
+	public FastHashMap(Map map) {
+
+		super();
+		this.map = new HashMap(map);
+
+	}
+
+	// ----------------------------------------------------- Instance Variables
+
+	/**
+	 * The underlying map we are managing.
+	 */
+	private HashMap map = null;
+
+	// --------------------------------------------------------- Public Methods
+
+	/**
+	 * Remove all mappings from this map.
+	 */
+	public void clear() {
+
+		synchronized (this) {
+			HashMap temp = (HashMap) map.clone();
+			temp.clear();
+			map = temp;
+		}
+
+	}
+
+	/**
+	 * Return a shallow copy of this <code>FastHashMap</code> instance.
+	 * The keys and values themselves are not copied.
+	 */
+	public Object clone() {
+
+		return new FastHashMap(map);
+
+	}
+
+	/**
+	 * Return <code>true</code> if this map contains a mapping for the
+	 * specified key.
+	 *
+	 * @param key Key to be searched for
+	 */
+	public boolean containsKey(Object key) {
+
+		return map.containsKey(key);
+
+	}
+
+	/**
+	 * Return <code>true</code> if this map contains one or more keys mapping
+	 * to the specified value.
+	 *
+	 * @param value Value to be searched for
+	 */
+	public boolean containsValue(Object value) {
+
+		return map.containsValue(value);
+
+	}
+
+	/**
+	 * Return a collection view of the mappings contained in this map.  Each
+	 * element in the returned collection is a <code>Map.Entry</code>.
+	 */
+	public Set entrySet() {
+
+		return map.entrySet();
+
+	}
+
+	/**
+	 * Compare the specified object with this list for equality.  This
+	 * implementation uses exactly the code that is used to define the
+	 * list equals function in the documentation for the
+	 * <code>Map.equals</code> method.
+	 *
+	 * @param o Object to be compared to this list
+	 */
+	public boolean equals(Object o) {
+
+		// Simple tests that require no synchronization
+		if (o == this)
+			return true;
+		else if ( !(o instanceof Map) )
+			return false;
+		Map mo = (Map) o;
+
+		// Compare the two maps for equality
+
+		if ( mo.size() != map.size() )
+			return false;
+		java.util.Iterator i = map.entrySet().iterator();
+		while ( i.hasNext() ) {
+			Map.Entry e = (Map.Entry) i.next();
+			Object key = e.getKey();
+			Object value = e.getValue();
+			if (value == null) {
+				if ( !( mo.get(key) == null && mo.containsKey(key) ) )
+					return false;
+			}
+			else {
+				if ( !value.equals( mo.get(key) ) )
+					return false;
+			}
+		}
+		return true;
+
+	}
+
+	/**
+	 * Return the value to which this map maps the specified key.  Returns
+	 * <code>null</code> if the map contains no mapping for this key, or if
+	 * there is a mapping with a value of <code>null</code>.  Use the
+	 * <code>containsKey()</code> method to disambiguate these cases.
+	 *
+	 * @param key Key whose value is to be returned
+	 */
+	public Object get(Object key) {
+
+		return map.get(key);
+
+	}
+
+	/**
+	 * Return the hash code value for this map.  This implementation uses
+	 * exactly the code that is used to define the list hash function in the
+	 * documentation for the <code>Map.hashCode</code> method.
+	 */
+	public int hashCode() {
+
+		int h = 0;
+		java.util.Iterator i = map.entrySet().iterator();
+		while ( i.hasNext() )
+			h += i.next().hashCode();
+		return h;
+
+	}
+
+	/**
+	 * Return <code>true</code> if this map contains no mappings.
+	 */
+	public boolean isEmpty() {
+
+		return map.isEmpty();
+
+	}
+
+	/**
+	 * Return a set view of the keys contained in this map.
+	 */
+	public Set keySet() {
+
+		return map.keySet();
+
+	}
+
+	/**
+	 * Associate the specified value with the specified key in this map.
+	 * If the map previously contained a mapping for this key, the old
+	 * value is replaced and returned.
+	 *
+	 * @param key The key with which the value is to be associated
+	 * @param value The value to be associated with this key
+	 */
+	public Object put(Object key, Object value) {
+
+		synchronized (this) {
+			HashMap temp = (HashMap) map.clone();
+			Object result = temp.put(key, value);
+			map = temp;
+			return (result);
+		}
+
+	}
+
+	/**
+	 * Copy all of the mappings from the specified map to this one, replacing
+	 * any mappings with the same keys.
+	 *
+	 * @param in Map whose mappings are to be copied
+	 */
+	public void putAll(Map in) {
+
+		synchronized (this) {
+			HashMap temp = (HashMap) map.clone();
+			temp.putAll(in);
+			map = temp;
+		}
+
+	}
+
+	/**
+	 * Remove any mapping for this key, and return any previously
+	 * mapped value.
+	 *
+	 * @param key Key whose mapping is to be removed
+	 */
+	public Object remove(Object key) {
+
+		synchronized (this) {
+			HashMap temp = (HashMap) map.clone();
+			Object result = temp.remove(key);
+			map = temp;
+			return (result);
+		}
+
+	}
+
+	/**
+	 * Return the number of key-value mappings in this map.
+	 */
+	public int size() {
+
+		return map.size();
+
+	}
+
+	/**
+	 * Return a collection view of the values contained in this map.
+	 */
+	public Collection values() {
+
+		return map.values();
+
+	}
+
+	public String toString() { return map.toString(); }
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/FilterHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/FilterHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/FilterHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,81 @@
+// $Id: FilterHelper.java 9908 2006-05-08 20:59:20Z max.andersen at jboss.com $
+package org.hibernate.util;
+
+import org.hibernate.sql.Template;
+import org.hibernate.impl.FilterImpl;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.function.SQLFunctionRegistry;
+
+import java.util.Map;
+import java.util.Iterator;
+
+/**
+ * Implementation of FilterHelper.
+ *
+ * @author Steve Ebersole
+ */
+public class FilterHelper {
+
+	private final String[] filterNames;
+	private final String[] filterConditions;
+
+	/**
+	 * The map of defined filters.  This is expected to be in format
+	 * where the filter names are the map keys, and the defined
+	 * conditions are the values.
+	 *
+	 * @param filters The map of defined filters.
+	 * @param dialect The sql dialect
+	 * @param functionRegistry The SQL function registry
+	 */
+	public FilterHelper(Map filters, Dialect dialect, SQLFunctionRegistry functionRegistry) {
+		int filterCount = filters.size();
+		filterNames = new String[filterCount];
+		filterConditions = new String[filterCount];
+		Iterator iter = filters.entrySet().iterator();
+		filterCount = 0;
+		while ( iter.hasNext() ) {
+			final Map.Entry entry = (Map.Entry) iter.next();
+			filterNames[filterCount] = (String) entry.getKey();
+			filterConditions[filterCount] = Template.renderWhereStringTemplate(
+					(String) entry.getValue(),
+					FilterImpl.MARKER,
+					dialect,
+					functionRegistry
+				);
+			filterConditions[filterCount] = StringHelper.replace( filterConditions[filterCount],
+					":",
+					":" + filterNames[filterCount] + "." );
+			filterCount++;
+		}
+	}
+
+	public boolean isAffectedBy(Map enabledFilters) {
+		for ( int i = 0, max = filterNames.length; i < max; i++ ) {
+			if ( enabledFilters.containsKey( filterNames[i] ) ) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public String render(String alias, Map enabledFilters) {
+		StringBuffer buffer = new StringBuffer();
+		render( buffer, alias, enabledFilters );
+		return buffer.toString();
+	}
+
+	public void render(StringBuffer buffer, String alias, Map enabledFilters) {
+		if ( filterNames != null && filterNames.length > 0 ) {
+			for ( int i = 0, max = filterNames.length; i < max; i++ ) {
+				if ( enabledFilters.containsKey( filterNames[i] ) ) {
+					final String condition = filterConditions[i];
+					if ( StringHelper.isNotEmpty( condition ) ) {
+						buffer.append( " and " )
+								.append( StringHelper.replace( condition, FilterImpl.MARKER, alias ) );
+					}
+				}
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/GetGeneratedKeysHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/GetGeneratedKeysHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/GetGeneratedKeysHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,87 @@
+//$Id: GetGeneratedKeysHelper.java 9676 2006-03-22 17:38:55Z steve.ebersole at jboss.com $
+package org.hibernate.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.hibernate.AssertionFailure;
+
+/**
+ * @author Gavin King
+ */
+public final class GetGeneratedKeysHelper {
+
+	private GetGeneratedKeysHelper() {
+	}
+
+	private static final Integer RETURN_GENERATED_KEYS;
+	private static final Method PREPARE_STATEMENT_METHOD;
+	private static final Method GET_GENERATED_KEYS_METHOD;
+
+	static {
+		try {
+			int returnGeneratedKeysEnumValue = Statement.class
+					.getDeclaredField( "RETURN_GENERATED_KEYS" )
+					.getInt( PreparedStatement.class );
+			RETURN_GENERATED_KEYS = new Integer( returnGeneratedKeysEnumValue );
+			PREPARE_STATEMENT_METHOD = Connection.class.getMethod(
+					"prepareStatement",
+			        new Class[] { String.class, Integer.TYPE }
+			);
+			GET_GENERATED_KEYS_METHOD = Statement.class.getDeclaredMethod(
+					"getGeneratedKeys",
+			        null
+			);
+		}
+		catch ( Exception e ) {
+			throw new AssertionFailure( "could not initialize getGeneratedKeys() support", e );
+		}
+	}
+
+	public static PreparedStatement prepareStatement(Connection conn, String sql) throws SQLException {
+		Object[] args = new Object[] { sql, RETURN_GENERATED_KEYS } ;
+		try {
+			return ( PreparedStatement ) PREPARE_STATEMENT_METHOD.invoke( conn, args );
+		}
+		catch ( InvocationTargetException ite ) {
+			if ( ite.getTargetException() instanceof SQLException ) {
+				throw ( SQLException ) ite.getTargetException();
+			}
+			else if ( ite.getTargetException() instanceof RuntimeException ) {
+				throw ( RuntimeException ) ite.getTargetException();
+			}
+			else {
+				throw new AssertionFailure( "InvocationTargetException preparing statement capable of returning generated keys (JDBC3)", ite );
+			}
+		}
+		catch ( IllegalAccessException iae ) {
+			throw new AssertionFailure( "IllegalAccessException preparing statement capable of returning generated keys (JDBC3)", iae );
+		}
+	}
+
+	public static ResultSet getGeneratedKey(PreparedStatement ps) throws SQLException {
+		try {
+			return ( ResultSet ) GET_GENERATED_KEYS_METHOD.invoke( ps, null );
+		}
+		catch ( InvocationTargetException ite ) {
+			if ( ite.getTargetException() instanceof SQLException ) {
+				throw ( SQLException ) ite.getTargetException();
+			}
+			else if ( ite.getTargetException() instanceof RuntimeException ) {
+				throw ( RuntimeException ) ite.getTargetException();
+			}
+			else {
+				throw new AssertionFailure( "InvocationTargetException extracting generated keys (JDBC3)", ite );
+			}
+		}
+		catch ( IllegalAccessException iae ) {
+			throw new AssertionFailure( "IllegalAccessException extracting generated keys (JDBC3)", iae );
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/IdentityMap.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/IdentityMap.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/IdentityMap.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,264 @@
+//$Id: IdentityMap.java 9194 2006-02-01 19:59:07Z steveebersole $
+package org.hibernate.util;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections.SequencedHashMap;
+
+/**
+ * A <tt>Map</tt> where keys are compared by object identity,
+ * rather than <tt>equals()</tt>.
+ */
+
+public final class IdentityMap implements Map {
+
+	private final Map map;
+	private transient Map.Entry[] entryArray = new Map.Entry[0];
+	private transient boolean dirty = false;
+
+	/**
+	 * Return a new instance of this class, with an undefined
+	 * iteration order
+	 *
+	 * @return Map
+	 */
+	public static Map instantiate(int size) {
+		return new IdentityMap( new HashMap(size) );
+	}
+
+	/**
+	 * Return a new instance of this class, with iteration
+	 * order defined by the order that entries were added
+	 */
+	public static Map instantiateSequenced(int size) {
+		return new IdentityMap( new SequencedHashMap(size) );
+	}
+
+	private IdentityMap(Map underlyingMap) {
+		map = underlyingMap;
+		dirty = true;
+	}
+
+	/**
+	 * Return the map entries (as instances of <tt>Map.Entry</tt> in a collection that
+	 * is safe from concurrent modification). ie. we may safely add new instances to
+	 * the underlying <tt>Map</tt> during iteration of the <tt>entries()</tt>.
+	 *
+	 * @param map
+	 * @return Collection
+	 */
+	public static Map.Entry[] concurrentEntries(Map map) {
+		return ( (IdentityMap) map ).entryArray();
+	}
+
+	public static List entries(Map map) {
+		return ( (IdentityMap) map ).entryList();
+	}
+
+	public static Iterator keyIterator(Map map) {
+		return ( (IdentityMap) map ).keyIterator();
+	}
+
+	public Iterator keyIterator() {
+		return new KeyIterator( map.keySet().iterator() );
+	}
+
+	public static final class IdentityMapEntry implements java.util.Map.Entry {
+		IdentityMapEntry(Object key, Object value) {
+			this.key=key;
+			this.value=value;
+		}
+		private Object key;
+		private Object value;
+		public Object getKey() {
+			return key;
+		}
+
+		public Object getValue() {
+			return value;
+		}
+
+		public Object setValue(Object value) {
+			Object result = this.value;
+			this.value = value;
+			return result;
+		}
+	}
+
+	public static final class IdentityKey implements Serializable {
+		private Object key;
+
+		IdentityKey(Object key) {
+			this.key=key;
+		}
+		public boolean equals(Object other) {
+			return key == ( (IdentityKey) other ).key;
+		}
+		public int hashCode() {
+			return System.identityHashCode(key);
+		}
+		public String toString() {
+			return key.toString();
+		}
+		public Object getRealKey() {
+			return key;
+		}
+	}
+
+	public int size() {
+		return map.size();
+	}
+
+	public boolean isEmpty() {
+		return map.isEmpty();
+	}
+
+	public boolean containsKey(Object key) {
+		IdentityKey k = new IdentityKey(key);
+		return map.containsKey(k);
+	}
+
+	public boolean containsValue(Object val) {
+		return map.containsValue(val);
+	}
+
+	public Object get(Object key) {
+		IdentityKey k = new IdentityKey(key);
+		return map.get(k);
+	}
+
+	public Object put(Object key, Object value) {
+		dirty = true;
+		return map.put( new IdentityKey(key), value );
+	}
+
+	public Object remove(Object key) {
+		dirty = true;
+		IdentityKey k = new IdentityKey(key);
+		return map.remove(k);
+	}
+
+	public void putAll(Map otherMap) {
+		Iterator iter = otherMap.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			put( me.getKey(), me.getValue() );
+		}
+	}
+
+	public void clear() {
+		dirty = true;
+		entryArray = null;
+		map.clear();
+	}
+
+	public Set keySet() {
+		// would need an IdentitySet for this!
+		throw new UnsupportedOperationException();
+	}
+
+	public Collection values() {
+		return map.values();
+	}
+
+	public Set entrySet() {
+		Set set = new HashSet( map.size() );
+		Iterator iter = map.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			set.add( new IdentityMapEntry( ( (IdentityKey) me.getKey() ).key, me.getValue() ) );
+		}
+		return set;
+	}
+
+	public List entryList() {
+		ArrayList list = new ArrayList( map.size() );
+		Iterator iter = map.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			list.add( new IdentityMapEntry( ( (IdentityKey) me.getKey() ).key, me.getValue() ) );
+		}
+		return list;
+	}
+
+	public Map.Entry[] entryArray() {
+		if (dirty) {
+			entryArray = new Map.Entry[ map.size() ];
+			Iterator iter = map.entrySet().iterator();
+			int i=0;
+			while ( iter.hasNext() ) {
+				Map.Entry me = (Map.Entry) iter.next();
+				entryArray[i++] = new IdentityMapEntry( ( (IdentityKey) me.getKey() ).key, me.getValue() );
+			}
+			dirty = false;
+		}
+		return entryArray;
+	}
+
+	/**
+	 * Workaround for a JDK 1.4.1 bug where <tt>IdentityHashMap</tt>s are not
+	 * correctly deserialized.
+	 *
+	 * @param map
+	 * @return Object
+	 */
+	public static Object serialize(Map map) {
+		return ( (IdentityMap) map ).map;
+	}
+
+	/**
+	 * Workaround for a JDK 1.4.1 bug where <tt>IdentityHashMap</tt>s are not
+	 * correctly deserialized.
+	 *
+	 * @param o
+	 * @return Map
+	 */
+	public static Map deserialize(Object o) {
+		return new IdentityMap( (Map) o );
+	}
+	
+	public String toString() {
+		return map.toString();
+	}
+
+	public static Map invert(Map map) {
+		Map result = instantiate( map.size() );
+		Iterator iter = map.entrySet().iterator();
+		while ( iter.hasNext() ) {
+			Map.Entry me = (Map.Entry) iter.next();
+			result.put( me.getValue(), me.getKey() );
+		}
+		return result;
+	}
+
+	static final class KeyIterator implements Iterator {
+
+		private KeyIterator(Iterator iter) {
+			identityKeyIterator = iter;
+		}
+
+		private final Iterator identityKeyIterator;
+
+		public boolean hasNext() {
+			return identityKeyIterator.hasNext();
+		}
+
+		public Object next() {
+			return ( (IdentityKey) identityKeyIterator.next() ).key;
+		}
+
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+
+	}
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/IdentitySet.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/IdentitySet.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/IdentitySet.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,89 @@
+//$Id: IdentitySet.java 8807 2005-12-09 15:27:05Z epbernard $
+package org.hibernate.util;
+
+import java.util.Set;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Set implementation that use == instead of equals() as its comparison mechanism
+ * that base its implementation of IdentityMap
+ * 
+ * @author Emmanuel Bernard
+ */
+public class IdentitySet implements Set {
+	private Map map;
+	private static final Object DUMP_VALUE = new Object();
+
+	public IdentitySet() {
+		this.map = IdentityMap.instantiate( 10 );
+	}
+
+	public int size() {
+		return map.size();
+	}
+
+	public boolean isEmpty() {
+		return map.isEmpty();
+	}
+
+	public boolean contains(Object o) {
+		return map.get( o ) == DUMP_VALUE;
+	}
+
+	public Iterator iterator() {
+		return map.entrySet().iterator();
+	}
+
+	public Object[] toArray() {
+		return map.entrySet().toArray();
+	}
+
+	public Object[] toArray(Object[] a) {
+		return map.entrySet().toArray(a);
+	}
+
+	public boolean add(Object o) {
+		return map.put( o, DUMP_VALUE) == null;
+	}
+
+	public boolean remove(Object o) {
+		return map.remove( o ) == DUMP_VALUE;
+	}
+
+	public boolean containsAll(Collection c) {
+		Iterator it = c.iterator();
+		while ( it.hasNext() ) {
+			if ( ! map.containsKey( it.next() ) ) return false;
+		}
+		return true;
+	}
+
+	public boolean addAll(Collection c) {
+		Iterator it = c.iterator();
+		boolean changed = false;
+		while ( it.hasNext() ) {
+			if ( this.add( it.next() ) ) changed = true;
+		}
+		return changed;
+	}
+
+	public boolean retainAll(Collection c) {
+		//doable if needed
+		throw new UnsupportedOperationException();
+	}
+
+	public boolean removeAll(Collection c) {
+		Iterator it = c.iterator();
+		boolean changed = false;
+		while ( it.hasNext() ) {
+			if ( this.remove( it.next() ) ) changed = true;
+		}
+		return changed;
+	}
+
+	public void clear() {
+		map.clear();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/JDBCExceptionReporter.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/JDBCExceptionReporter.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/JDBCExceptionReporter.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,103 @@
+//$Id: JDBCExceptionReporter.java 10670 2006-10-31 21:30:15Z epbernard $
+package org.hibernate.util;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public final class JDBCExceptionReporter {
+
+	public static final Log log = LogFactory.getLog(JDBCExceptionReporter.class);
+	public static final String DEFAULT_EXCEPTION_MSG = "SQL Exception";
+	public static final String DEFAULT_WARNING_MSG = "SQL Warning";
+
+	private JDBCExceptionReporter() {}
+	
+	public static void logAndClearWarnings(Connection connection) {
+		if ( log.isWarnEnabled() ) {
+			try {
+				logWarnings( connection.getWarnings() );
+			}
+			catch (SQLException sqle) {
+				//workaround for WebLogic
+				log.debug("could not log warnings", sqle);
+			}
+		}
+		try {
+			//Sybase fail if we don't do that, sigh...
+			connection.clearWarnings();
+		}
+		catch (SQLException sqle) {
+			log.debug("could not clear warnings", sqle);
+		}
+	}
+
+	public static void logWarnings(SQLWarning warning) {
+		logWarnings(warning, null);
+	}
+
+	public static void logWarnings(SQLWarning warning, String message) {
+		if ( log.isWarnEnabled() ) {
+			if ( log.isDebugEnabled() && warning != null ) {
+				message = StringHelper.isNotEmpty(message) ? message : DEFAULT_WARNING_MSG;
+				log.debug( message, warning );
+			}
+			while (warning != null) {
+				StringBuffer buf = new StringBuffer(30)
+				        .append( "SQL Warning: ")
+						.append( warning.getErrorCode() )
+						.append( ", SQLState: ")
+						.append( warning.getSQLState() );
+				log.warn( buf.toString() );
+				log.warn( warning.getMessage() );
+				warning = warning.getNextWarning();
+			}
+		}
+	}
+
+	public static void logExceptions(SQLException ex) {
+		logExceptions(ex, null);
+	}
+
+	public static void logExceptions(SQLException ex, String message) {
+		if ( log.isErrorEnabled() ) {
+			if ( log.isDebugEnabled() ) {
+				message = StringHelper.isNotEmpty(message) ? message : DEFAULT_EXCEPTION_MSG;
+				log.debug( message, ex );
+			}
+			while (ex != null) {
+				StringBuffer buf = new StringBuffer(30)
+						.append( "SQL Error: " )
+				        .append( ex.getErrorCode() )
+				        .append( ", SQLState: " )
+				        .append( ex.getSQLState() );
+				log.warn( buf.toString() );
+				log.error( ex.getMessage() );
+				ex = ex.getNextException();
+			}
+		}
+	}
+
+//	public static JDBCException newJDBCException(String string, SQLException root, String sql) {
+//		string = string + " [" + sql + ']';
+//		log.error(string, root);
+//		logExceptions(root);
+//		return new JDBCException(string, root, sql);
+//	}
+//
+//	public static JDBCException newJDBCException(String string, SQLException root) {
+//		log.error(string, root);
+//		logExceptions(root);
+//		return new JDBCException(string, root);
+//	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/JTAHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/JTAHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/JTAHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+//$Id: JTAHelper.java 10068 2006-06-28 17:07:06Z steve.ebersole at jboss.com $
+package org.hibernate.util;
+
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.TransactionException;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * @author Gavin King
+ */
+public final class JTAHelper {
+
+	private JTAHelper() {}
+
+	public static boolean isRollback(int status) {
+		return status==Status.STATUS_MARKED_ROLLBACK ||
+		       status==Status.STATUS_ROLLING_BACK ||
+		       status==Status.STATUS_ROLLEDBACK;
+	}
+
+	public static boolean isInProgress(int status) {
+		return status==Status.STATUS_ACTIVE ||
+		       status==Status.STATUS_MARKED_ROLLBACK;
+	}
+
+	/**
+	 * Return true if a JTA transaction is in progress
+	 * and false in *every* other cases (including in a JDBC transaction).
+	 */
+	public static boolean isTransactionInProgress(SessionFactoryImplementor factory) {
+		TransactionManager tm = factory.getTransactionManager();
+		try {
+			return tm != null && isTransactionInProgress( tm.getTransaction() );
+		}
+		catch (SystemException se) {
+			throw new TransactionException( "could not obtain JTA Transaction", se );
+		}
+	}
+
+	public static boolean isTransactionInProgress(javax.transaction.Transaction tx) throws SystemException {
+		return tx != null && JTAHelper.isInProgress( tx.getStatus() );
+	}
+
+	public static boolean isMarkedForRollback(int status) {
+		return status == Status.STATUS_MARKED_ROLLBACK;
+	}
+
+	public static boolean isMarkedForRollback(javax.transaction.Transaction tx) throws SystemException {
+		return isMarkedForRollback( tx.getStatus() );
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/util/JTAHelper.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/JoinedIterator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/JoinedIterator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/JoinedIterator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,84 @@
+//$Id: JoinedIterator.java 3973 2004-06-28 23:58:08Z epbernard $
+package org.hibernate.util;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * An JoinedIterator is an Iterator that wraps a number of Iterators.
+ *
+ * This class makes multiple iterators look like one to the caller.
+ * When any method from the Iterator interface is called, the JoinedIterator
+ * will delegate to a single underlying Iterator. The JoinedIterator will
+ * invoke the Iterators in sequence until all Iterators are exhausted.
+ *
+ */
+public class JoinedIterator implements Iterator {
+
+	private static final Iterator[] ITERATORS = {};
+
+	// wrapped iterators
+	private Iterator[] iterators;
+
+	// index of current iterator in the wrapped iterators array
+	private int currentIteratorIndex;
+
+	// the current iterator
+	private Iterator currentIterator;
+
+	// the last used iterator
+	private Iterator lastUsedIterator;
+
+	public JoinedIterator(List iterators) {
+		this( (Iterator[]) iterators.toArray(ITERATORS) );
+	}
+
+	public JoinedIterator(Iterator[] iterators) {
+		if( iterators==null )
+			throw new NullPointerException("Unexpected NULL iterators argument");
+		this.iterators = iterators;
+	}
+
+	public JoinedIterator(Iterator first, Iterator second) {
+		this( new Iterator[] { first, second } );
+	}
+
+	public boolean hasNext() {
+		updateCurrentIterator();
+		return currentIterator.hasNext();
+	}
+
+	public Object next() {
+		updateCurrentIterator();
+		return currentIterator.next();
+	}
+
+	public void remove() {
+		updateCurrentIterator();
+		lastUsedIterator.remove();
+	}
+
+
+	// call this before any Iterator method to make sure that the current Iterator
+	// is not exhausted
+	protected void updateCurrentIterator() {
+
+		if (currentIterator == null) {
+			if( iterators.length==0  ) {
+				currentIterator = EmptyIterator.INSTANCE;
+			}
+			else {
+				currentIterator = iterators[0];
+			}
+			// set last used iterator here, in case the user calls remove
+			// before calling hasNext() or next() (although they shouldn't)
+			lastUsedIterator = currentIterator;
+		}
+
+		while (! currentIterator.hasNext() && currentIteratorIndex < iterators.length - 1) {
+			currentIteratorIndex++;
+			currentIterator = iterators[currentIteratorIndex];
+		}
+	}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/LazyIterator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/LazyIterator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/LazyIterator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: LazyIterator.java 7699 2005-07-30 04:56:09Z oneovthafew $
+package org.hibernate.util;
+
+import java.util.Iterator;
+import java.util.Map;
+
+public final class LazyIterator implements Iterator {
+	
+	private final Map map;
+	private Iterator iterator;
+	
+	private Iterator getIterator() {
+		if (iterator==null) {
+			iterator = map.values().iterator();
+		}
+		return iterator;
+	}
+
+	public LazyIterator(Map map) {
+		this.map = map;
+	}
+	
+	public boolean hasNext() {
+		return getIterator().hasNext();
+	}
+
+	public Object next() {
+		return getIterator().next();
+	}
+
+	public void remove() {
+		throw new UnsupportedOperationException();
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/util/LazyIterator.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/LinkedHashCollectionHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/LinkedHashCollectionHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/LinkedHashCollectionHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,95 @@
+//$Id: LinkedHashCollectionHelper.java 10100 2006-07-10 16:31:09Z steve.ebersole at jboss.com $
+package org.hibernate.util;
+
+import java.util.Map;
+import java.util.Set;
+import java.lang.reflect.Constructor;
+
+import org.hibernate.AssertionFailure;
+
+public final class LinkedHashCollectionHelper {
+
+	private static final Class SET_CLASS;
+	private static final Class MAP_CLASS;
+	private static final Class[] CAPACITY_CTOR_SIG = new Class[] { int.class, float.class };
+	private static final Constructor SET_CAPACITY_CTOR;
+	private static final Constructor MAP_CAPACITY_CTOR;
+	private static final float LOAD_FACTOR_V = .75f;
+	private static final Float LOAD_FACTOR = new Float( LOAD_FACTOR_V );
+
+	static {
+		Class setClass;
+		Class mapClass;
+		Constructor setCtor;
+		Constructor mapCtor;
+		try {
+			setClass = Class.forName( "java.util.LinkedHashSet" );
+			mapClass = Class.forName( "java.util.LinkedHashMap" );
+			setCtor = setClass.getConstructor( CAPACITY_CTOR_SIG );
+			mapCtor = mapClass.getConstructor( CAPACITY_CTOR_SIG );
+		}
+		catch ( Throwable t ) {
+			setClass = null;
+			mapClass = null;
+			setCtor = null;
+			mapCtor = null;
+		}
+		SET_CLASS = setClass;
+		MAP_CLASS = mapClass;
+		SET_CAPACITY_CTOR = setCtor;
+		MAP_CAPACITY_CTOR = mapCtor;
+	}
+
+	public static Set createLinkedHashSet() {
+		try {
+			return (Set) SET_CLASS.newInstance();
+		}
+		catch (Exception e) {
+			throw new AssertionFailure("Could not instantiate LinkedHashSet", e);
+		}
+	}
+
+	public static Set createLinkedHashSet(int anticipatedSize) {
+		if ( anticipatedSize <= 0 ) {
+			return createLinkedHashSet();
+		}
+		int initialCapacity = anticipatedSize + (int)( anticipatedSize * LOAD_FACTOR_V );
+		try {
+			return ( Set ) SET_CAPACITY_CTOR.newInstance( new Object[] { new Integer( initialCapacity ), LOAD_FACTOR  } );
+		}
+		catch (Exception e) {
+			throw new AssertionFailure("Could not instantiate LinkedHashSet", e);
+		}
+	}
+
+	public static Map createLinkedHashMap() {
+		try {
+			return (Map) MAP_CLASS.newInstance();
+		}
+		catch (Exception e) {
+			throw new AssertionFailure("Could not instantiate LinkedHashMap", e);
+		}
+	}
+
+	public static Map createLinkedHashMap(int anticipatedSize) {
+		if ( anticipatedSize <= 0 ) {
+			return createLinkedHashMap();
+		}
+		int initialCapacity = anticipatedSize + (int)( anticipatedSize * LOAD_FACTOR_V );
+		try {
+			return ( Map ) MAP_CAPACITY_CTOR.newInstance( new Object[] { new Integer( initialCapacity ), LOAD_FACTOR } );
+		}
+		catch (Exception e) {
+			throw new AssertionFailure("Could not instantiate LinkedHashMap", e);
+		}
+	}
+
+	private LinkedHashCollectionHelper() {}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/MarkerObject.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/MarkerObject.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/MarkerObject.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+//$Id: MarkerObject.java 4649 2004-10-07 00:14:29Z oneovthafew $
+package org.hibernate.util;
+
+/**
+ * @author Gavin King
+ */
+public class MarkerObject {
+	private String name;
+	
+	public MarkerObject(String name) {
+		this.name=name;
+	}
+	public String toString() {
+		return name;
+	}
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/util/MarkerObject.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/NamedGeneratedKeysHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/NamedGeneratedKeysHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/NamedGeneratedKeysHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,79 @@
+package org.hibernate.util;
+
+import org.hibernate.AssertionFailure;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.sql.Connection;
+import java.sql.Statement;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.ResultSet;
+
+/**
+ * @author Steve Ebersole
+ */
+public class NamedGeneratedKeysHelper {
+	private NamedGeneratedKeysHelper() {
+	}
+
+	private static final Method PREPARE_STATEMENT_METHOD;
+	private static final Method GET_GENERATED_KEYS_METHOD;
+
+	static {
+		try {
+			PREPARE_STATEMENT_METHOD = Connection.class.getMethod(
+					"prepareStatement",
+			        new Class[] { String.class, String[].class }
+			);
+			GET_GENERATED_KEYS_METHOD = Statement.class.getDeclaredMethod(
+					"getGeneratedKeys",
+			        null
+			);
+		}
+		catch ( Exception e ) {
+			throw new AssertionFailure( "could not initialize getGeneratedKeys() support", e );
+		}
+	}
+
+	public static PreparedStatement prepareStatement(Connection conn, String sql, String[] columnNames) throws SQLException {
+		Object[] args = new Object[] { sql, columnNames } ;
+		try {
+			return ( PreparedStatement ) PREPARE_STATEMENT_METHOD.invoke( conn, args );
+		}
+		catch ( InvocationTargetException ite ) {
+			if ( ite.getTargetException() instanceof SQLException ) {
+				throw ( SQLException ) ite.getTargetException();
+			}
+			else if ( ite.getTargetException() instanceof RuntimeException ) {
+				throw ( RuntimeException ) ite.getTargetException();
+			}
+			else {
+				throw new AssertionFailure( "InvocationTargetException preparing statement capable of returning generated keys (JDBC3)", ite );
+			}
+		}
+		catch ( IllegalAccessException iae ) {
+			throw new AssertionFailure( "IllegalAccessException preparing statement capable of returning generated keys (JDBC3)", iae );
+		}
+	}
+
+	public static ResultSet getGeneratedKey(PreparedStatement ps) throws SQLException {
+		try {
+			return ( ResultSet ) GET_GENERATED_KEYS_METHOD.invoke( ps, null );
+		}
+		catch ( InvocationTargetException ite ) {
+			if ( ite.getTargetException() instanceof SQLException ) {
+				throw ( SQLException ) ite.getTargetException();
+			}
+			else if ( ite.getTargetException() instanceof RuntimeException ) {
+				throw ( RuntimeException ) ite.getTargetException();
+			}
+			else {
+				throw new AssertionFailure( "InvocationTargetException extracting generated keys (JDBC3)", ite );
+			}
+		}
+		catch ( IllegalAccessException iae ) {
+			throw new AssertionFailure( "IllegalAccessException extracting generated keys (JDBC3)", iae );
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/NamingHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/NamingHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/NamingHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,121 @@
+//$Id: NamingHelper.java 8149 2005-09-11 21:10:52Z oneovthafew $
+package org.hibernate.util;
+
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.cfg.Environment;
+
+public final class NamingHelper {
+
+	private static final Log log = LogFactory.getLog(NamingHelper.class);
+
+	public static InitialContext getInitialContext(Properties props) throws NamingException {
+
+		Hashtable hash = getJndiProperties(props);
+		log.info("JNDI InitialContext properties:" + hash);
+		try {
+			return hash.size()==0 ?
+					new InitialContext() :
+					new InitialContext(hash);
+		}
+		catch (NamingException e) {
+			log.error("Could not obtain initial context", e);
+			throw e;
+		}
+	}
+
+	/**
+	 * Bind val to name in ctx, and make sure that all intermediate contexts exist.
+	 *
+	 * @param ctx the root context
+	 * @param name the name as a string
+	 * @param val the object to be bound
+	 * @throws NamingException
+	 */
+	public static void bind(Context ctx, String name, Object val) throws NamingException {
+		try {
+			log.trace("binding: " + name);
+			ctx.rebind(name, val);
+		}
+		catch (Exception e) {
+			Name n = ctx.getNameParser("").parse(name);
+			while ( n.size() > 1 ) {
+				String ctxName = n.get(0);
+
+				Context subctx=null;
+				try {
+					log.trace("lookup: " + ctxName);
+					subctx = (Context) ctx.lookup(ctxName);
+				}
+				catch (NameNotFoundException nfe) {}
+
+				if (subctx!=null) {
+					log.debug("Found subcontext: " + ctxName);
+					ctx = subctx;
+				}
+				else {
+					log.info("Creating subcontext: " + ctxName);
+					ctx = ctx.createSubcontext(ctxName);
+				}
+				n = n.getSuffix(1);
+			}
+			log.trace("binding: " + n);
+			ctx.rebind(n, val);
+		}
+		log.debug("Bound name: " + name);
+	}
+
+	/**
+	 * Transform JNDI properties passed in the form <tt>hibernate.jndi.*</tt> to the
+	 * format accepted by <tt>InitialContext</tt> by triming the leading "<tt>hibernate.jndi</tt>".
+	 */
+	public static Properties getJndiProperties(Properties properties) {
+
+		HashSet specialProps = new HashSet();
+		specialProps.add(Environment.JNDI_CLASS);
+		specialProps.add(Environment.JNDI_URL);
+
+		Iterator iter = properties.keySet().iterator();
+		Properties result = new Properties();
+		while ( iter.hasNext() ) {
+			String prop = (String) iter.next();
+			if ( prop.indexOf(Environment.JNDI_PREFIX) > -1 && !specialProps.contains(prop) ) {
+				result.setProperty(
+						prop.substring( Environment.JNDI_PREFIX.length()+1 ),
+						properties.getProperty(prop)
+					);
+			}
+		}
+
+		String jndiClass = properties.getProperty(Environment.JNDI_CLASS);
+		String jndiURL = properties.getProperty(Environment.JNDI_URL);
+		// we want to be able to just use the defaults,
+		// if JNDI environment properties are not supplied
+		// so don't put null in anywhere
+		if (jndiClass != null) result.put(Context.INITIAL_CONTEXT_FACTORY, jndiClass);
+		if (jndiURL != null) result.put(Context.PROVIDER_URL, jndiURL);
+
+		return result;
+	}
+
+	private NamingHelper() {}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/PropertiesHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/PropertiesHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/PropertiesHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,149 @@
+//$Id: PropertiesHelper.java 9712 2006-03-29 13:56:59Z steve.ebersole at jboss.com $
+package org.hibernate.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.Iterator;
+
+
+public final class PropertiesHelper {
+
+	private static final String PLACEHOLDER_START = "${";
+
+	public static boolean getBoolean(String property, Properties properties) {
+		String setting = properties.getProperty(property);
+		return setting != null && Boolean.valueOf( setting.trim() ).booleanValue();
+	}
+
+	public static boolean getBoolean(String property, Properties properties, boolean defaultValue) {
+		String setting = properties.getProperty(property);
+		return setting==null ? defaultValue : Boolean.valueOf( setting.trim() ).booleanValue();
+	}
+
+	public static int getInt(String property, Properties properties, int defaultValue) {
+		String propValue = properties.getProperty(property);
+		return propValue==null ? defaultValue : Integer.parseInt( propValue.trim() );
+	}
+
+	public static String getString(String property, Properties properties, String defaultValue) {
+		String propValue = properties.getProperty(property);
+		return propValue==null ? defaultValue : propValue;
+	}
+
+	public static Integer getInteger(String property, Properties properties) {
+		String propValue = properties.getProperty(property);
+		return propValue==null ? null : Integer.valueOf( propValue.trim() );
+	}
+
+	public static Map toMap(String property, String delim, Properties properties) {
+		Map map = new HashMap();
+		String propValue = properties.getProperty(property);
+		if (propValue!=null) {
+			StringTokenizer tokens = new StringTokenizer(propValue, delim);
+			while ( tokens.hasMoreTokens() ) {
+				map.put(
+					tokens.nextToken(),
+				    tokens.hasMoreElements() ? tokens.nextToken() : ""
+				);
+			}
+		}
+		return map;
+	}
+
+	public static String[] toStringArray(String property, String delim, Properties properties) {
+		return toStringArray( properties.getProperty(property), delim );
+	}
+
+	public static String[] toStringArray(String propValue, String delim) {
+		if (propValue!=null) {
+			return StringHelper.split(delim, propValue);
+		}
+		else {
+			return ArrayHelper.EMPTY_STRING_ARRAY;
+		}
+	}
+
+	/**
+	 * replace a property by a starred version
+	 *
+	 * @param props properties to check
+	 * @param key proeprty to mask
+	 * @return cloned and masked properties
+	 */
+	public static Properties maskOut(Properties props, String key) {
+		Properties clone = (Properties) props.clone();
+		if (clone.get(key) != null) {
+			clone.setProperty(key, "****");
+		}
+		return clone;
+	}
+
+	public static void resolvePlaceHolders(Properties properties) {
+		Iterator itr = properties.entrySet().iterator();
+		while ( itr.hasNext() ) {
+			final Map.Entry entry = ( Map.Entry ) itr.next();
+			final Object value = entry.getValue();
+			if ( value != null && String.class.isInstance( value ) ) {
+				final String resolved = resolvePlaceHolder( ( String ) value );
+				if ( !value.equals( resolved ) ) {
+					if ( resolved == null ) {
+						itr.remove();
+					}
+					else {
+						entry.setValue( resolved );
+					}
+				}
+			}
+		}
+	}
+
+	public static String resolvePlaceHolder(String property) {
+		if ( property.indexOf( PLACEHOLDER_START ) < 0 ) {
+			return property;
+		}
+		StringBuffer buff = new StringBuffer();
+		char[] chars = property.toCharArray();
+		for ( int pos = 0; pos < chars.length; pos++ ) {
+			if ( chars[pos] == '$' ) {
+				// peek ahead
+				if ( chars[pos+1] == '{' ) {
+					// we have a placeholder, spin forward till we find the end
+					String systemPropertyName = "";
+					int x = pos + 2;
+					for (  ; x < chars.length && chars[x] != '}'; x++ ) {
+						systemPropertyName += chars[x];
+						// if we reach the end of the string w/o finding the
+						// matching end, that is an exception
+						if ( x == chars.length - 1 ) {
+							throw new IllegalArgumentException( "unmatched placeholder start [" + property + "]" );
+						}
+					}
+					String systemProperty = extractFromSystem( systemPropertyName );
+					buff.append( systemProperty == null ? "" : systemProperty );
+					pos = x + 1;
+					// make sure spinning forward did not put us past the end of the buffer...
+					if ( pos >= chars.length ) {
+						break;
+					}
+				}
+			}
+			buff.append( chars[pos] );
+		}
+		String rtn = buff.toString();
+		return StringHelper.isEmpty( rtn ) ? null : rtn;
+	}
+
+	private static String extractFromSystem(String systemPropertyName) {
+		try {
+			return System.getProperty( systemPropertyName );
+		}
+		catch( Throwable t ) {
+			return null;
+		}
+	}
+
+
+	private PropertiesHelper() {}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/Range.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/Range.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/Range.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: Range.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.util;
+
+public final class Range {
+
+	public static int[] range(int begin, int length) {
+		int[] result = new int[length];
+		for ( int i=0; i<length; i++ ) {
+			result[i]=begin + i;
+		}
+		return result;
+	}
+
+	private Range() {}
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/ReflectHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/ReflectHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/ReflectHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,201 @@
+//$Id: ReflectHelper.java 10109 2006-07-12 15:39:59Z steve.ebersole at jboss.com $
+package org.hibernate.util;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.MappingException;
+import org.hibernate.PropertyNotFoundException;
+import org.hibernate.property.BasicPropertyAccessor;
+import org.hibernate.property.DirectPropertyAccessor;
+import org.hibernate.property.Getter;
+import org.hibernate.property.PropertyAccessor;
+import org.hibernate.type.PrimitiveType;
+import org.hibernate.type.Type;
+
+
+public final class ReflectHelper {
+
+	//TODO: this dependency is kinda Bad
+	private static final PropertyAccessor BASIC_PROPERTY_ACCESSOR = new BasicPropertyAccessor();
+	private static final PropertyAccessor DIRECT_PROPERTY_ACCESSOR = new DirectPropertyAccessor();
+
+	private static final Class[] NO_CLASSES = new Class[0];
+	private static final Class[] OBJECT = new Class[] { Object.class };
+	private static final Method OBJECT_EQUALS;
+	private static final Class[] NO_PARAM = new Class[] { };
+
+	private static final Method OBJECT_HASHCODE;
+	static {
+		Method eq;
+		Method hash;
+		try {
+			eq = Object.class.getMethod("equals", OBJECT);
+			hash = Object.class.getMethod("hashCode", NO_PARAM);
+		}
+		catch (Exception e) {
+			throw new AssertionFailure("Could not find Object.equals() or Object.hashCode()", e);
+		}
+		OBJECT_EQUALS = eq;
+		OBJECT_HASHCODE = hash;
+	}
+
+	public static boolean overridesEquals(Class clazz) {
+		Method equals;
+		try {
+			equals = clazz.getMethod("equals", OBJECT);
+		}
+		catch (NoSuchMethodException nsme) {
+			return false; //its an interface so we can't really tell anything...
+		}
+		return !OBJECT_EQUALS.equals(equals);
+	}
+
+	public static boolean overridesHashCode(Class clazz) {
+		Method hashCode;
+		try {
+			hashCode = clazz.getMethod("hashCode", NO_PARAM);
+		}
+		catch (NoSuchMethodException nsme) {
+			return false; //its an interface so we can't really tell anything...
+		}
+		return !OBJECT_HASHCODE.equals(hashCode);
+	}
+
+	public static Class reflectedPropertyClass(String className, String name) throws MappingException {
+		try {
+			Class clazz = ReflectHelper.classForName(className);
+			return getter(clazz, name).getReturnType();
+		}
+		catch (ClassNotFoundException cnfe) {
+			throw new MappingException("class " + className + " not found while looking for property: " + name, cnfe);
+		}
+	}
+
+	private static Getter getter(Class clazz, String name) throws MappingException {
+		try {
+			return BASIC_PROPERTY_ACCESSOR.getGetter(clazz, name);
+		}
+		catch (PropertyNotFoundException pnfe) {
+			return DIRECT_PROPERTY_ACCESSOR.getGetter(clazz, name);
+		}
+	}
+
+	public static Getter getGetter(Class theClass, String name) throws MappingException {
+		return BASIC_PROPERTY_ACCESSOR.getGetter(theClass, name);
+	}
+
+	public static Class classForName(String name) throws ClassNotFoundException {
+		try {
+			ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+			if ( contextClassLoader != null ) {
+				return contextClassLoader.loadClass(name);
+			}
+		}
+		catch ( Throwable t ) {
+		}
+		return Class.forName( name );
+	}
+
+	public static Class classForName(String name, Class caller) throws ClassNotFoundException {
+		try {
+			ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+			if ( contextClassLoader != null ) {
+				return contextClassLoader.loadClass( name );
+			}
+		}
+		catch ( Throwable e ) {
+		}
+		return Class.forName( name, true, caller.getClassLoader() );
+	}
+
+	public static boolean isPublic(Class clazz, Member member) {
+		return Modifier.isPublic( member.getModifiers() ) && Modifier.isPublic( clazz.getModifiers() );
+	}
+
+	public static Object getConstantValue(String name) {
+		Class clazz;
+		try {
+			clazz = classForName( StringHelper.qualifier( name ) );
+		}
+		catch ( Throwable t ) {
+			return null;
+		}
+		try {
+			return clazz.getField( StringHelper.unqualify( name ) ).get(null);
+		}
+		catch ( Throwable t ) {
+			return null;
+		}
+	}
+
+	public static Constructor getDefaultConstructor(Class clazz) throws PropertyNotFoundException {
+
+		if ( isAbstractClass(clazz) ) return null;
+
+		try {
+			Constructor constructor = clazz.getDeclaredConstructor(NO_CLASSES);
+			if ( !isPublic(clazz, constructor) ) {
+				constructor.setAccessible(true);
+			}
+			return constructor;
+		}
+		catch (NoSuchMethodException nme) {
+			throw new PropertyNotFoundException(
+				"Object class " + clazz.getName() +
+				" must declare a default (no-argument) constructor"
+			);
+		}
+
+	}
+
+	public static boolean isAbstractClass(Class clazz) {
+		int modifier = clazz.getModifiers();
+		return Modifier.isAbstract(modifier) || Modifier.isInterface(modifier);
+	}
+	
+	public static boolean isFinalClass(Class clazz) {
+		return Modifier.isFinal( clazz.getModifiers() );
+	}
+
+	public static Constructor getConstructor(Class clazz, Type[] types) throws PropertyNotFoundException {
+		final Constructor[] candidates = clazz.getConstructors();
+		for ( int i=0; i<candidates.length; i++ ) {
+			final Constructor constructor = candidates[i];
+			final Class[] params = constructor.getParameterTypes();
+			if ( params.length==types.length ) {
+				boolean found = true;
+				for ( int j=0; j<params.length; j++ ) {
+					final boolean ok = params[j].isAssignableFrom( types[j].getReturnedClass() ) || (
+						types[j] instanceof PrimitiveType &&
+						params[j] == ( (PrimitiveType) types[j] ).getPrimitiveClass()
+					);
+					if (!ok) {
+						found = false;
+						break;
+					}
+				}
+				if (found) {
+					if ( !isPublic(clazz, constructor) ) constructor.setAccessible(true);
+					return constructor;
+				}
+			}
+		}
+		throw new PropertyNotFoundException( "no appropriate constructor in class: " + clazz.getName() );
+	}
+	
+	public static Method getMethod(Class clazz, Method method) {
+		try {
+			return clazz.getMethod( method.getName(), method.getParameterTypes() );
+		}
+		catch (Exception e) {
+			return null;
+		}
+	}
+
+	private ReflectHelper() {}
+
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/SerializationHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/SerializationHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/SerializationHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,274 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowledgement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgement may appear in the software itself,
+ *    if and wherever such third-party acknowledgements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache at apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.hibernate.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.io.ObjectStreamClass;
+import java.io.ObjectInputStream;
+
+import org.hibernate.type.SerializationException;
+import org.hibernate.Hibernate;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * <p>Assists with the serialization process and performs additional functionality based
+ * on serialization.</p>
+ * <p>
+ * <ul>
+ * <li>Deep clone using serialization
+ * <li>Serialize managing finally and IOException
+ * <li>Deserialize managing finally and IOException
+ * </ul>
+ *
+ * <p>This class throws exceptions for invalid <code>null</code> inputs.
+ * Each method documents its behaviour in more detail.</p>
+ *
+ * @author <a href="mailto:nissim at nksystems.com">Nissim Karpenstein</a>
+ * @author <a href="mailto:janekdb at yahoo.co.uk">Janek Bogucki</a>
+ * @author <a href="mailto:dlr at finemaltcoding.com">Daniel Rall</a>
+ * @author Stephen Colebourne
+ * @author Jeff Varszegi
+ * @author Gary Gregory
+ * @since 1.0
+ * @version $Id: SerializationHelper.java 9180 2006-01-30 23:51:27Z steveebersole $
+ */
+public final class SerializationHelper {
+
+	private static final Log log = LogFactory.getLog(SerializationHelper.class);
+
+    private SerializationHelper() {}
+
+    // Clone
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Deep clone an <code>Object</code> using serialization.</p>
+     *
+     * <p>This is many times slower than writing clone methods by hand
+     * on all objects in your object graph. However, for complex object
+     * graphs, or for those that don't support deep cloning this can
+     * be a simple alternative implementation. Of course all the objects
+     * must be <code>Serializable</code>.</p>
+     *
+     * @param object  the <code>Serializable</code> object to clone
+     * @return the cloned object
+     * @throws SerializationException (runtime) if the serialization fails
+     */
+    public static Object clone(Serializable object) throws SerializationException {
+	    log.trace("Starting clone through serialization");
+        return deserialize( serialize(object) );
+    }
+
+    // Serialize
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Serializes an <code>Object</code> to the specified stream.</p>
+     *
+     * <p>The stream will be closed once the object is written.
+     * This avoids the need for a finally clause, and maybe also exception
+     * handling, in the application code.</p>
+     *
+     * <p>The stream passed in is not buffered internally within this method.
+     * This is the responsibility of your application if desired.</p>
+     *
+     * @param obj  the object to serialize to bytes, may be null
+     * @param outputStream  the stream to write to, must not be null
+     * @throws IllegalArgumentException if <code>outputStream</code> is <code>null</code>
+     * @throws SerializationException (runtime) if the serialization fails
+     */
+    public static void serialize(Serializable obj, OutputStream outputStream) throws SerializationException {
+        if (outputStream == null) {
+            throw new IllegalArgumentException("The OutputStream must not be null");
+        }
+
+	    if ( log.isTraceEnabled() ) {
+		    if ( Hibernate.isInitialized( obj ) ) {
+	            log.trace( "Starting serialization of object [" + obj + "]" );
+		    }
+		    else {
+			    log.trace( "Starting serialization of [uninitialized proxy]" );
+		    }
+	    }
+
+        ObjectOutputStream out = null;
+        try {
+            // stream closed in the finally
+            out = new ObjectOutputStream(outputStream);
+            out.writeObject(obj);
+
+        }
+        catch (IOException ex) {
+            throw new SerializationException("could not serialize", ex);
+        }
+        finally {
+            try {
+                if (out != null) out.close();
+            }
+            catch (IOException ignored) {}
+        }
+    }
+
+    /**
+     * <p>Serializes an <code>Object</code> to a byte array for
+     * storage/serialization.</p>
+     *
+     * @param obj  the object to serialize to bytes
+     * @return a byte[] with the converted Serializable
+     * @throws SerializationException (runtime) if the serialization fails
+     */
+    public static byte[] serialize(Serializable obj) throws SerializationException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
+        serialize(obj, baos);
+        return baos.toByteArray();
+    }
+
+    // Deserialize
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Deserializes an <code>Object</code> from the specified stream.</p>
+     *
+     * <p>The stream will be closed once the object is written. This
+     * avoids the need for a finally clause, and maybe also exception
+     * handling, in the application code.</p>
+     *
+     * <p>The stream passed in is not buffered internally within this method.
+     * This is the responsibility of your application if desired.</p>
+     *
+     * @param inputStream  the serialized object input stream, must not be null
+     * @return the deserialized object
+     * @throws IllegalArgumentException if <code>inputStream</code> is <code>null</code>
+     * @throws SerializationException (runtime) if the serialization fails
+     */
+    public static Object deserialize(InputStream inputStream) throws SerializationException {
+        if (inputStream == null) {
+            throw new IllegalArgumentException("The InputStream must not be null");
+        }
+
+		log.trace("Starting deserialization of object");
+
+        CustomObjectInputStream in = null;
+        try {
+            // stream closed in the finally
+            in = new CustomObjectInputStream(inputStream);
+            return in.readObject();
+
+        }
+        catch (ClassNotFoundException ex) {
+            throw new SerializationException("could not deserialize", ex);
+        }
+        catch (IOException ex) {
+            throw new SerializationException("could not deserialize", ex);
+        }
+        finally {
+            try {
+                if (in != null) in.close();
+            }
+            catch (IOException ex) {}
+        }
+    }
+
+    /**
+     * <p>Deserializes a single <code>Object</code> from an array of bytes.</p>
+     *
+     * @param objectData  the serialized object, must not be null
+     * @return the deserialized object
+     * @throws IllegalArgumentException if <code>objectData</code> is <code>null</code>
+     * @throws SerializationException (runtime) if the serialization fails
+     */
+    public static Object deserialize(byte[] objectData) throws SerializationException {
+        if (objectData == null) {
+            throw new IllegalArgumentException("The byte[] must not be null");
+        }
+        ByteArrayInputStream bais = new ByteArrayInputStream(objectData);
+        return deserialize(bais);
+    }
+
+
+	/**
+	 * Custom ObjectInputStream implementation to more appropriately handle classloading
+	 * within app servers (mainly jboss - hence this class inspired by jboss's class of
+	 * the same purpose).
+	 */
+	private static final class CustomObjectInputStream extends ObjectInputStream {
+
+		public CustomObjectInputStream(InputStream in) throws IOException {
+			super(in);
+		}
+
+		protected Class resolveClass(ObjectStreamClass v) throws IOException, ClassNotFoundException {
+			String className = v.getName();
+			Class resolvedClass = null;
+
+			log.trace("Attempting to locate class [" + className + "]");
+
+			ClassLoader loader = Thread.currentThread().getContextClassLoader();
+			try {
+				resolvedClass = loader.loadClass(className);
+				log.trace("Class resolved through context class loader");
+			}
+			catch(ClassNotFoundException e) {
+				log.trace("Asking super to resolve");
+				resolvedClass = super.resolveClass(v);
+			}
+
+			return resolvedClass;
+		}
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/SimpleMRUCache.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/SimpleMRUCache.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/SimpleMRUCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,58 @@
+package org.hibernate.util;
+
+import org.apache.commons.collections.LRUMap;
+
+import java.io.Serializable;
+import java.io.IOException;
+
+/**
+ * Cache following a "Most Recently Used" (MRU) algorithm for maintaining a
+ * bounded in-memory size; the "Least Recently Used" (LRU) entry is the first
+ * available for removal from the cache.
+ * <p/>
+ * This implementation uses a bounded MRU Map to limit the in-memory size of
+ * the cache.  Thus the size of this cache never grows beyond the stated size.
+ *
+ * @author Steve Ebersole
+ */
+public class SimpleMRUCache implements Serializable {
+
+	public static final int DEFAULT_STRONG_REF_COUNT = 128;
+
+	private final int strongReferenceCount;
+	private transient LRUMap cache;
+
+	public SimpleMRUCache() {
+		this( DEFAULT_STRONG_REF_COUNT );
+	}
+
+	public SimpleMRUCache(int strongReferenceCount) {
+		this.strongReferenceCount = strongReferenceCount;
+		init();
+	}
+
+	public synchronized Object get(Object key) {
+		return cache.get( key );
+	}
+
+	public synchronized Object put(Object key, Object value) {
+		return cache.put( key, value );
+	}
+
+	public synchronized int size() {
+		return cache.size();
+	}
+
+	private void init() {
+		cache = new LRUMap( strongReferenceCount );
+	}
+
+	private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
+		in.defaultReadObject();
+		init();
+	}
+
+	public synchronized void clear() {
+		cache.clear();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/SingletonIterator.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/SingletonIterator.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/SingletonIterator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+//$Id: SingletonIterator.java 6514 2005-04-26 06:37:54Z oneovthafew $
+package org.hibernate.util;
+
+import java.util.Iterator;
+
+/**
+ * @author Gavin King
+ */
+public final class SingletonIterator implements Iterator {
+
+	private Object value;
+	private boolean hasNext = true;
+
+	public boolean hasNext() {
+		return hasNext;
+	}
+
+	public Object next() {
+		if (hasNext) {
+			hasNext = false;
+			return value;
+		}
+		else {
+			throw new IllegalStateException();
+		}
+	}
+
+	public void remove() {
+		throw new UnsupportedOperationException();
+	}
+
+	public SingletonIterator(Object value) {
+		this.value = value;
+	}
+
+}


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/util/SingletonIterator.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/SoftLimitMRUCache.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/SoftLimitMRUCache.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/SoftLimitMRUCache.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,83 @@
+package org.hibernate.util;
+
+import org.apache.commons.collections.ReferenceMap;
+import org.apache.commons.collections.LRUMap;
+
+import java.io.Serializable;
+import java.io.IOException;
+
+/**
+ * Cache following a "Most Recently Used" (MRY) algorithm for maintaining a
+ * bounded in-memory size; the "Least Recently Used" (LRU) entry is the first
+ * available for removal from the cache.
+ * <p/>
+ * This implementation uses a "soft limit" to the in-memory size of the cache,
+ * meaning that all cache entries are kept within a completely
+ * {@link java.lang.ref.SoftReference}-based map with the most recently utilized
+ * entries additionally kept in a hard-reference manner to prevent those cache
+ * entries soft references from becoming enqueued by the garbage collector.
+ * Thus the actual size of this cache impl can actually grow beyond the stated
+ * max size bound as long as GC is not actively seeking soft references for
+ * enqueuement.
+ *
+ * @author Steve Ebersole
+ */
+public class SoftLimitMRUCache implements Serializable {
+
+	public static final int DEFAULT_STRONG_REF_COUNT = 128;
+
+	private final int strongReferenceCount;
+
+	// actual cache of the entries.  soft references are used for both the keys and the
+	// values here since the values pertaining to the MRU entries are kept in a
+	// seperate hard reference cache (to avoid their enqueuement/garbage-collection).
+	private transient ReferenceMap softReferenceCache = new ReferenceMap( ReferenceMap.SOFT, ReferenceMap.SOFT );
+	// the MRU cache used to keep hard references to the most recently used query plans;
+	// note : LRU here is a bit of a misnomer, it indicates that LRU entries are removed, the
+	// actual kept entries are the MRU entries
+	private transient LRUMap strongReferenceCache;
+
+	public SoftLimitMRUCache() {
+		this( DEFAULT_STRONG_REF_COUNT );
+	}
+
+	public SoftLimitMRUCache(int strongRefCount) {
+		this.strongReferenceCount = strongRefCount;
+		init();
+	}
+
+	public synchronized Object get(Object key) {
+		Object result = softReferenceCache.get( key );
+		if ( result != null ) {
+			strongReferenceCache.put( key, result );
+		}
+		return result;
+	}
+
+	public synchronized Object put(Object key, Object value) {
+		softReferenceCache.put( key, value );
+		return strongReferenceCache.put( key, value );
+	}
+
+	public synchronized int size() {
+		return strongReferenceCache.size();
+	}
+
+	public synchronized int softSize() {
+		return softReferenceCache.size();
+	}
+
+	private void init() {
+		strongReferenceCache = new LRUMap( strongReferenceCount );
+	}
+
+	private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
+		in.defaultReadObject();
+		init();
+	}
+
+	public synchronized void clear() {
+		strongReferenceCache.clear();
+		softReferenceCache.clear();
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/StringHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/StringHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/StringHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,393 @@
+//$Id: StringHelper.java 10315 2006-08-23 13:22:54Z steve.ebersole at jboss.com $
+package org.hibernate.util;
+
+import java.util.Iterator;
+import java.util.StringTokenizer;
+import java.util.ArrayList;
+
+public final class StringHelper {
+
+	private static final int ALIAS_TRUNCATE_LENGTH = 10;
+	public static final String WHITESPACE = " \n\r\f\t";
+
+	private StringHelper() { /* static methods only - hide constructor */
+	}
+	
+	/*public static boolean containsDigits(String string) {
+		for ( int i=0; i<string.length(); i++ ) {
+			if ( Character.isDigit( string.charAt(i) ) ) return true;
+		}
+		return false;
+	}*/
+
+	public static int lastIndexOfLetter(String string) {
+		for ( int i=0; i<string.length(); i++ ) {
+			char character = string.charAt(i);
+			if ( !Character.isLetter(character) /*&& !('_'==character)*/ ) return i-1;
+		}
+		return string.length()-1;
+	}
+
+	public static String join(String seperator, String[] strings) {
+		int length = strings.length;
+		if ( length == 0 ) return "";
+		StringBuffer buf = new StringBuffer( length * strings[0].length() )
+				.append( strings[0] );
+		for ( int i = 1; i < length; i++ ) {
+			buf.append( seperator ).append( strings[i] );
+		}
+		return buf.toString();
+	}
+
+	public static String join(String seperator, Iterator objects) {
+		StringBuffer buf = new StringBuffer();
+		if ( objects.hasNext() ) buf.append( objects.next() );
+		while ( objects.hasNext() ) {
+			buf.append( seperator ).append( objects.next() );
+		}
+		return buf.toString();
+	}
+
+	public static String[] add(String[] x, String sep, String[] y) {
+		String[] result = new String[x.length];
+		for ( int i = 0; i < x.length; i++ ) {
+			result[i] = x[i] + sep + y[i];
+		}
+		return result;
+	}
+
+	public static String repeat(String string, int times) {
+		StringBuffer buf = new StringBuffer( string.length() * times );
+		for ( int i = 0; i < times; i++ ) buf.append( string );
+		return buf.toString();
+	}
+
+
+	public static String replace(String template, String placeholder, String replacement) {
+		return replace( template, placeholder, replacement, false );
+	}
+
+	public static String[] replace(String templates[], String placeholder, String replacement) {
+		String[] result = new String[templates.length];
+		for ( int i =0; i<templates.length; i++ ) {
+			result[i] = replace( templates[i], placeholder, replacement );;
+		}
+		return result;
+	}
+
+	public static String replace(String template, String placeholder, String replacement, boolean wholeWords) {
+		int loc = template == null ? -1 : template.indexOf( placeholder );
+		if ( loc < 0 ) {
+			return template;
+		}
+		else {
+			final boolean actuallyReplace = !wholeWords ||
+					loc + placeholder.length() == template.length() ||
+					!Character.isJavaIdentifierPart( template.charAt( loc + placeholder.length() ) );
+			String actualReplacement = actuallyReplace ? replacement : placeholder;
+			return new StringBuffer( template.substring( 0, loc ) )
+					.append( actualReplacement )
+					.append( replace( template.substring( loc + placeholder.length() ),
+							placeholder,
+							replacement,
+							wholeWords ) ).toString();
+		}
+	}
+
+
+	public static String replaceOnce(String template, String placeholder, String replacement) {
+        int loc = template == null ? -1 : template.indexOf( placeholder );
+		if ( loc < 0 ) {
+			return template;
+		}
+		else {
+			return new StringBuffer( template.substring( 0, loc ) )
+					.append( replacement )
+					.append( template.substring( loc + placeholder.length() ) )
+					.toString();
+		}
+	}
+
+
+	public static String[] split(String seperators, String list) {
+		return split( seperators, list, false );
+	}
+
+	public static String[] split(String seperators, String list, boolean include) {
+		StringTokenizer tokens = new StringTokenizer( list, seperators, include );
+		String[] result = new String[ tokens.countTokens() ];
+		int i = 0;
+		while ( tokens.hasMoreTokens() ) {
+			result[i++] = tokens.nextToken();
+		}
+		return result;
+	}
+
+	public static String unqualify(String qualifiedName) {
+		int loc = qualifiedName.lastIndexOf(".");
+		return ( loc < 0 ) ? qualifiedName : qualifiedName.substring( qualifiedName.lastIndexOf(".") + 1 );
+	}
+
+	public static String qualifier(String qualifiedName) {
+		int loc = qualifiedName.lastIndexOf(".");
+		return ( loc < 0 ) ? "" : qualifiedName.substring( 0, loc );
+	}
+
+	public static String[] suffix(String[] columns, String suffix) {
+		if ( suffix == null ) return columns;
+		String[] qualified = new String[columns.length];
+		for ( int i = 0; i < columns.length; i++ ) {
+			qualified[i] = suffix( columns[i], suffix );
+		}
+		return qualified;
+	}
+
+	private static String suffix(String name, String suffix) {
+		return ( suffix == null ) ? name : name + suffix;
+	}
+
+	public static String root(String qualifiedName) {
+		int loc = qualifiedName.indexOf( "." );
+		return ( loc < 0 ) ? qualifiedName : qualifiedName.substring( 0, loc );
+	}
+
+	public static String unroot(String qualifiedName) {
+		int loc = qualifiedName.indexOf( "." );
+		return ( loc < 0 ) ? qualifiedName : qualifiedName.substring( loc+1, qualifiedName.length() );
+	}
+
+	public static boolean booleanValue(String tfString) {
+		String trimmed = tfString.trim().toLowerCase();
+		return trimmed.equals( "true" ) || trimmed.equals( "t" );
+	}
+
+	public static String toString(Object[] array) {
+		int len = array.length;
+		if ( len == 0 ) return "";
+		StringBuffer buf = new StringBuffer( len * 12 );
+		for ( int i = 0; i < len - 1; i++ ) {
+			buf.append( array[i] ).append(", ");
+		}
+		return buf.append( array[len - 1] ).toString();
+	}
+
+	public static String[] multiply(String string, Iterator placeholders, Iterator replacements) {
+		String[] result = new String[]{string};
+		while ( placeholders.hasNext() ) {
+			result = multiply( result, ( String ) placeholders.next(), ( String[] ) replacements.next() );
+		}
+		return result;
+	}
+
+	private static String[] multiply(String[] strings, String placeholder, String[] replacements) {
+		String[] results = new String[replacements.length * strings.length];
+		int n = 0;
+		for ( int i = 0; i < replacements.length; i++ ) {
+			for ( int j = 0; j < strings.length; j++ ) {
+				results[n++] = replaceOnce( strings[j], placeholder, replacements[i] );
+			}
+		}
+		return results;
+	}
+
+	public static int countUnquoted(String string, char character) {
+		if ( '\'' == character ) {
+			throw new IllegalArgumentException( "Unquoted count of quotes is invalid" );
+		}
+		if (string == null)
+			return 0;
+		// Impl note: takes advantage of the fact that an escpaed single quote
+		// embedded within a quote-block can really be handled as two seperate
+		// quote-blocks for the purposes of this method...
+		int count = 0;
+		int stringLength = string.length();
+		boolean inQuote = false;
+		for ( int indx = 0; indx < stringLength; indx++ ) {
+			char c = string.charAt( indx );
+			if ( inQuote ) {
+				if ( '\'' == c ) {
+					inQuote = false;
+				}
+			}
+			else if ( '\'' == c ) {
+				inQuote = true;
+			}
+			else if ( c == character ) {
+				count++;
+			}
+		}
+		return count;
+	}
+
+	public static int[] locateUnquoted(String string, char character) {
+		if ( '\'' == character ) {
+			throw new IllegalArgumentException( "Unquoted count of quotes is invalid" );
+		}
+		if (string == null) {
+			return new int[0];
+		}
+
+		ArrayList locations = new ArrayList( 20 );
+
+		// Impl note: takes advantage of the fact that an escpaed single quote
+		// embedded within a quote-block can really be handled as two seperate
+		// quote-blocks for the purposes of this method...
+		int stringLength = string.length();
+		boolean inQuote = false;
+		for ( int indx = 0; indx < stringLength; indx++ ) {
+			char c = string.charAt( indx );
+			if ( inQuote ) {
+				if ( '\'' == c ) {
+					inQuote = false;
+				}
+			}
+			else if ( '\'' == c ) {
+				inQuote = true;
+			}
+			else if ( c == character ) {
+				locations.add( new Integer( indx ) );
+			}
+		}
+		return ArrayHelper.toIntArray( locations );
+	}
+
+	public static boolean isNotEmpty(String string) {
+		return string != null && string.length() > 0;
+	}
+
+	public static boolean isEmpty(String string) {
+		return string == null || string.length() == 0;
+	}
+
+	public static String qualify(String prefix, String name) {
+		if ( name == null || prefix == null ) {
+			throw new NullPointerException();
+		}
+		return new StringBuffer( prefix.length() + name.length() + 1 )
+				.append(prefix)
+				.append('.')
+				.append(name)
+				.toString();
+	}
+
+	public static String[] qualify(String prefix, String[] names) {
+		if ( prefix == null ) return names;
+		int len = names.length;
+		String[] qualified = new String[len];
+		for ( int i = 0; i < len; i++ ) {
+			qualified[i] = qualify( prefix, names[i] );
+		}
+		return qualified;
+	}
+
+	public static int firstIndexOfChar(String sqlString, String string, int startindex) {
+		int matchAt = -1;
+		for ( int i = 0; i < string.length(); i++ ) {
+			int curMatch = sqlString.indexOf( string.charAt( i ), startindex );
+			if ( curMatch >= 0 ) {
+				if ( matchAt == -1 ) { // first time we find match!
+					matchAt = curMatch;
+				}
+				else {
+					matchAt = Math.min( matchAt, curMatch );
+				}
+			}
+		}
+		return matchAt;
+	}
+
+	public static String truncate(String string, int length) {
+		if ( string.length() <= length ) {
+			return string;
+		}
+		else {
+			return string.substring( 0, length );
+		}
+	}
+
+	public static String generateAlias(String description) {
+		return generateAliasRoot(description) + '_';
+	}
+
+	/**
+	 * Generate a nice alias for the given class name or collection role
+	 * name and unique integer. Subclasses of Loader do <em>not</em> have 
+	 * to use aliases of this form.
+	 * @return an alias of the form <tt>foo1_</tt>
+	 */
+	public static String generateAlias(String description, int unique) {
+		return generateAliasRoot(description) +
+			Integer.toString(unique) +
+			'_';
+	}
+
+	/**
+	 * Generates a root alias by truncating the "root name" defined by
+	 * the incoming decription and removing/modifying any non-valid
+	 * alias characters.
+	 *
+	 * @param description The root name from which to generate a root alias.
+	 * @return The generated root alias.
+	 */
+	private static String generateAliasRoot(String description) {
+		String result = truncate( unqualifyEntityName(description), ALIAS_TRUNCATE_LENGTH )
+				.toLowerCase()
+		        .replace( '/', '_' ) // entityNames may now include slashes for the representations
+				.replace( '$', '_' ); //classname may be an inner class
+		result = cleanAlias( result );
+		if ( Character.isDigit( result.charAt(result.length()-1) ) ) {
+			return result + "x"; //ick!
+		}
+		else {
+			return result;
+		}
+	}
+
+	/**
+	 * Clean the generated alias by removing any non-alpha characters from the
+	 * beginning.
+	 *
+	 * @param alias The generated alias to be cleaned.
+	 * @return The cleaned alias, stripped of any leading non-alpha characters.
+	 */
+	private static String cleanAlias(String alias) {
+		char[] chars = alias.toCharArray();
+		// short cut check...
+		if ( !Character.isLetter( chars[0] ) ) {
+			for ( int i = 1; i < chars.length; i++ ) {
+				// as soon as we encounter our first letter, return the substring
+				// from that position
+				if ( Character.isLetter( chars[i] ) ) {
+					return alias.substring( i );
+				}
+			}
+		}
+		return alias;
+	}
+
+	public static String unqualifyEntityName(String entityName) {
+		String result = unqualify(entityName);
+		int slashPos = result.indexOf( '/' );
+		if ( slashPos > 0 ) {
+			result = result.substring( 0, slashPos - 1 );
+		}
+		return result;
+	}
+	
+	public static String toUpperCase(String str) {
+		return str==null ? null : str.toUpperCase();
+	}
+	
+	public static String toLowerCase(String str) {
+		return str==null ? null : str.toLowerCase();
+	}
+
+	public static String moveAndToBeginning(String filter) {
+		if ( filter.trim().length()>0 ){
+			filter += " and ";
+			if ( filter.startsWith(" and ") ) filter = filter.substring(4);
+		}
+		return filter;
+	}
+	
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/XMLHelper.java
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/XMLHelper.java	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/XMLHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,91 @@
+//$Id: XMLHelper.java 8563 2005-11-10 15:58:59Z steveebersole $
+package org.hibernate.util;
+
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.dom4j.io.DOMReader;
+import org.dom4j.io.SAXReader;
+import org.dom4j.io.OutputFormat;
+import org.dom4j.io.XMLWriter;
+import org.dom4j.Element;
+import org.dom4j.DocumentFactory;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXParseException;
+
+/**
+ * Small helper class that lazy loads DOM and SAX reader and keep them for fast use afterwards.
+ *
+ *
+ *
+ */
+public final class XMLHelper {
+
+	private static final Log log = LogFactory.getLog(XMLHelper.class);
+	public static final EntityResolver DEFAULT_DTD_RESOLVER = new DTDEntityResolver();
+
+	private DOMReader domReader;
+	private SAXReader saxReader;
+
+	/**
+	 * Create a dom4j SAXReader which will append all validation errors
+	 * to errorList
+	 */
+	public SAXReader createSAXReader(String file, List errorsList, EntityResolver entityResolver) {
+		if (saxReader==null) saxReader = new SAXReader();
+		saxReader.setEntityResolver(entityResolver);
+		saxReader.setErrorHandler( new ErrorLogger(file, errorsList) );
+		saxReader.setMergeAdjacentText(true);
+		saxReader.setValidation(true);
+		return saxReader;
+	}
+
+	/**
+	 * Create a dom4j DOMReader
+	 */
+	public DOMReader createDOMReader() {
+		if (domReader==null) domReader = new DOMReader();
+		return domReader;
+	}
+
+	public static class ErrorLogger implements ErrorHandler {
+		private String file;
+		private List errors;
+		ErrorLogger(String file, List errors) {
+			this.file=file;
+			this.errors = errors;
+		}
+		public void error(SAXParseException error) {
+			log.error( "Error parsing XML: " + file + '(' + error.getLineNumber() + ") " + error.getMessage() );
+			errors.add(error);
+		}
+		public void fatalError(SAXParseException error) {
+			error(error);
+		}
+		public void warning(SAXParseException warn) {
+			log.warn( "Warning parsing XML: " + file + '(' + warn.getLineNumber() + ") " + warn.getMessage() );
+		}
+	}
+
+	public static Element generateDom4jElement(String elementName) {
+		return DocumentFactory.getInstance().createElement( elementName );
+	}
+
+	public static void dump(Element element) {
+		try {
+			// try to "pretty print" it
+			OutputFormat outformat = OutputFormat.createPrettyPrint();
+			XMLWriter writer = new XMLWriter( System.out, outformat );
+			writer.write( element );
+			writer.flush();
+			System.out.println( "" );
+		}
+		catch( Throwable t ) {
+			// otherwise, just dump it
+			System.out.println( element.asXML() );
+		}
+
+	}
+}

Added: trunk/Hibernate3/core/src/main/java/org/hibernate/util/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/java/org/hibernate/util/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/java/org/hibernate/util/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>
+	Utility classes.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/core/src/main/java/org/hibernate/util/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/core/src/main/javadoc/package.html
===================================================================
--- trunk/Hibernate3/core/src/main/javadoc/package.html	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/javadoc/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+<body>
+
+<h2>Hibernate API</h2>
+
+This documentation concentrates upon the following <b>Core API</b> interfaces:
+<li><tt>org.hibernate.Hibernate</tt></li>
+<li><tt>org.hibernate.Session</tt></li>
+<li><tt>org.hibernate.SessionFactory</tt></li>
+<li><tt>org.hibernate.Transaction</tt></li>
+<li><tt>org.hibernate.Query</tt></li>
+<li><tt>org.hibernate.Criteria</tt></li>
+<li><tt>org.hibernate.ScrollableResults</tt></li>
+<li><tt>org.hibernate.cfg.Configuration</tt></li>
+<li><tt>org.hibernate.expression.Expression</tt></li>
+<li><tt>org.hibernate.expression.Order</tt></li>
+<li><tt>org.hibernate.expression.Example</tt></li>
+These interfaces are fully intended to be exposed to application code.<br>
+<br>
+The <b>Extension API</b> is intended to be used by application programmers
+to extend Hibernate functionality. None of these interfaces are intended
+to be called by the application - they are called internally by Hibernate.
+This API is less stable than the Core API. The safest way to extend
+functionality is to contribute extensions back to the project; that way
+extensions will be updated when the Extension API changes.<br>
+<br>
+Full Hibernate documentation may be found at
+<a href="http://hibernate.org">hibernate.org</a>.
+ at see org.hibernate.Hibernate
+ at see org.hibernate.Session
+ at see org.hibernate.SessionFactory
+ at see org.hibernate.Transaction
+ at see org.hibernate.Query
+ at see org.hibernate.Criteria
+ at see org.hibernate.ScrollableResults
+ at see org.hibernate.cfg.Configuration
+ at see org.hibernate.expression.Expression
+ at see org.hibernate.expression.Order
+ at see org.hibernate.expression.Example
+</body>

Added: trunk/Hibernate3/core/src/main/resources/org/hibernate/checkstyle_checks.xml
===================================================================
--- trunk/Hibernate3/core/src/main/resources/org/hibernate/checkstyle_checks.xml	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/resources/org/hibernate/checkstyle_checks.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.1//EN" "http://www.puppycrawl.com/dtds/configuration_1_1.dtd">
+<module name="Checker">
+    <module name="TreeWalker">
+        <module name="com.puppycrawl.tools.checkstyle.checks.blocks.AvoidNestedBlocksCheck">
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.imports.AvoidStarImportCheck">
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.naming.ConstantNameCheck">
+            <property name="format" value="^[A-Z](_?[A-Z0-9]+)*$|log"/>
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.coding.EmptyStatementCheck">
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.coding.EqualsHashCodeCheck">
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.design.FinalClassCheck">
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.GenericIllegalRegexpCheck">
+            <property name="format" value="\(\(|\)\)"/>
+            <property name="ignoreCase" value="false"/>
+            <property name="message" value="stacked parentheses"/>
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck">
+            <property name="severity" value="warning"/>
+            <property name="tokens" value="VARIABLE_DEF"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.design.HideUtilityClassConstructorCheck">
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.coding.IllegalInstantiationCheck">
+            <property name="classes" value="{}"/>
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.coding.InnerAssignmentCheck">
+            <property name="severity" value="warning"/>
+            <property name="tokens" value="ASSIGN, BAND_ASSIGN, BOR_ASSIGN, BSR_ASSIGN, BXOR_ASSIGN, DIV_ASSIGN, MINUS_ASSIGN, MOD_ASSIGN, PLUS_ASSIGN, SL_ASSIGN, SR_ASSIGN, STAR_ASSIGN"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.design.InterfaceIsTypeCheck">
+            <property name="allowMarkerInterfaces" value="true"/>
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.blocks.LeftCurlyCheck">
+            <property name="maxLineLength" value="80"/>
+            <property name="option" value="eol"/>
+            <property name="severity" value="warning"/>
+            <property name="tokens" value="CLASS_DEF, CTOR_DEF, INTERFACE_DEF, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, METHOD_DEF"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.naming.LocalFinalVariableNameCheck">
+            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck">
+            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.naming.MemberNameCheck">
+            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.naming.MethodNameCheck">
+            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.ModifierOrderCheck">
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.blocks.NeedBracesCheck">
+            <property name="severity" value="warning"/>
+            <property name="tokens" value="LITERAL_DO, LITERAL_ELSE"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.naming.PackageNameCheck">
+            <property name="format" value="^[a-z]+(\.[a-zA-Z_][a-zA-Z0-9_]*)*$"/>
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.imports.RedundantImportCheck">
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.blocks.RightCurlyCheck">
+            <property name="option" value="alone"/>
+            <property name="severity" value="warning"/>
+            <property name="tokens" value="LITERAL_CATCH, LITERAL_ELSE, LITERAL_TRY"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.coding.SimplifyBooleanExpressionCheck">
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.coding.SimplifyBooleanReturnCheck">
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.naming.StaticVariableNameCheck">
+            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.naming.TypeNameCheck">
+            <property name="format" value="^[A-Z][a-zA-Z0-9]*$"/>
+            <property name="severity" value="warning"/>
+            <property name="tokens" value="CLASS_DEF, INTERFACE_DEF"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.imports.UnusedImportsCheck">
+            <property name="severity" value="warning"/>
+        </module>
+        <module name="com.puppycrawl.tools.checkstyle.checks.design.VisibilityModifierCheck">
+            <property name="packageAllowed" value="true"/>
+            <property name="protectedAllowed" value="true"/>
+            <property name="publicMemberPattern" value="^serialVersionUID"/>
+            <property name="severity" value="warning"/>
+        </module>
+    </module>
+</module>

Added: trunk/Hibernate3/core/src/main/resources/org/hibernate/hibernate-configuration-3.0.dtd
===================================================================
--- trunk/Hibernate3/core/src/main/resources/org/hibernate/hibernate-configuration-3.0.dtd	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/resources/org/hibernate/hibernate-configuration-3.0.dtd	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+<!-- Hibernate file-based configuration document.
+
+<!DOCTYPE hibernate-configuration PUBLIC
+	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+An instance of this document contains property settings and references
+to mapping files for a number of SessionFactory instances to be listed
+in JNDI.
+
+-->
+
+<!ELEMENT hibernate-configuration (session-factory,security?)>
+
+<!ELEMENT property (#PCDATA)>
+<!ATTLIST property name CDATA #REQUIRED>
+
+<!ELEMENT mapping EMPTY> <!-- reference to a mapping file -->
+<!ATTLIST mapping resource CDATA #IMPLIED>
+<!ATTLIST mapping file CDATA #IMPLIED>
+<!ATTLIST mapping jar CDATA #IMPLIED>
+<!ATTLIST mapping package CDATA #IMPLIED>
+<!ATTLIST mapping class CDATA #IMPLIED>
+
+<!ELEMENT class-cache EMPTY>
+<!ATTLIST class-cache class CDATA #REQUIRED>
+<!ATTLIST class-cache region CDATA #IMPLIED>
+<!ATTLIST class-cache usage (read-only|read-write|nonstrict-read-write|transactional) #REQUIRED>
+<!ATTLIST class-cache include (all|non-lazy) "all">
+
+<!ELEMENT collection-cache EMPTY>
+<!ATTLIST collection-cache collection CDATA #REQUIRED>
+<!ATTLIST collection-cache region CDATA #IMPLIED>
+<!ATTLIST collection-cache usage (read-only|read-write|nonstrict-read-write|transactional) #REQUIRED>
+
+<!ELEMENT event (listener*)>
+<!ATTLIST event type (auto-flush|merge|create|create-onflush|delete|dirty-check|evict|flush|flush-entity|load|load-collection|lock|refresh|replicate|save-update|save|update|pre-load|pre-update|pre-insert|pre-delete|post-load|post-update|post-insert|post-delete|post-commit-update|post-commit-insert|post-commit-delete) #REQUIRED>
+
+<!ELEMENT listener EMPTY>
+<!ATTLIST listener type (auto-flush|merge|create|create-onflush|delete|dirty-check|evict|flush|flush-entity|load|load-collection|lock|refresh|replicate|save-update|save|update|pre-load|pre-update|pre-insert|pre-delete|post-load|post-update|post-insert|post-delete|post-commit-update|post-commit-insert|post-commit-delete) #IMPLIED>
+<!ATTLIST listener class CDATA #REQUIRED>
+
+<!ELEMENT session-factory (property*, mapping*, (class-cache|collection-cache)*, event*, listener*)>
+<!ATTLIST session-factory name CDATA #IMPLIED> <!-- the JNDI name -->
+
+<!ELEMENT security (grant*)>
+<!ATTLIST security context CDATA #REQUIRED> <!--the JACC contextID-->
+
+<!ELEMENT grant EMPTY>
+<!ATTLIST grant role CDATA #REQUIRED>
+<!ATTLIST grant entity-name CDATA #REQUIRED>
+<!ATTLIST grant actions CDATA #REQUIRED>

Added: trunk/Hibernate3/core/src/main/resources/org/hibernate/hibernate-mapping-3.0.dtd
===================================================================
--- trunk/Hibernate3/core/src/main/resources/org/hibernate/hibernate-mapping-3.0.dtd	                        (rev 0)
+++ trunk/Hibernate3/core/src/main/resources/org/hibernate/hibernate-mapping-3.0.dtd	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1036 @@
+<!-- Hibernate Mapping DTD.
+
+<!DOCTYPE hibernate-mapping PUBLIC 
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+An instance of this XML document may contain mappings for an arbitrary 
+number of classes. The class mappings may contain associations to classes
+mapped in the same document or in another document. No class may be 
+mapped more than once. Each document may also contain definitions of an
+arbitrary number of queries, and import declarations of arbitrary classes. 
+
+-->
+
+<!--
+	The document root.
+ -->
+
+<!ELEMENT hibernate-mapping (
+	meta*, 
+	typedef*, 
+	import*, 
+	(class|subclass|joined-subclass|union-subclass)*,
+    resultset*,
+	(query|sql-query)*,
+	filter-def*,
+    database-object*
+)>
+	<!ATTLIST hibernate-mapping schema CDATA #IMPLIED>									<!-- default: none -->
+	<!ATTLIST hibernate-mapping catalog CDATA #IMPLIED>									<!-- default: none -->
+	<!ATTLIST hibernate-mapping default-cascade CDATA "none">
+	<!ATTLIST hibernate-mapping default-access CDATA "property">
+	<!ATTLIST hibernate-mapping default-lazy (true|false) "true">
+	<!ATTLIST hibernate-mapping auto-import (true|false) "true">
+	<!ATTLIST hibernate-mapping package CDATA #IMPLIED>									<!-- default: none -->
+
+<!--
+	META element definition; used to assign meta-level attributes to a class
+	or property.  Is currently used by codegenerator as a placeholder for
+	values that is not directly related to OR mappings.
+-->
+<!ELEMENT meta (#PCDATA)>
+	<!ATTLIST meta attribute CDATA #REQUIRED>
+	<!ATTLIST meta inherit (true|false) "true">
+
+<!--
+	TYPEDEF element definition; defines a new name for a Hibernate type. May
+	contain parameters for parameterizable types.
+-->
+<!ELEMENT typedef (param*)>
+	<!ATTLIST typedef class CDATA #REQUIRED>
+	<!ATTLIST typedef name CDATA #REQUIRED>
+
+<!--
+	IMPORT element definition; an explicit query language "import"
+-->
+<!ELEMENT import EMPTY>
+	<!ATTLIST import class CDATA #REQUIRED>
+	<!ATTLIST import rename CDATA #IMPLIED>	<!-- default: unqualified class name -->
+
+<!--
+	Root entity mapping.  Poorly named as entities do not have to be represented by 
+	classes at all.  Mapped entities may be represented via different methodologies 
+	(POJO, Map, Dom4j).
+-->
+<!ELEMENT class (
+ 	meta*,
+	subselect?,
+	cache?,
+	synchronize*,
+	comment?,
+    tuplizer*,
+	(id|composite-id),
+	discriminator?,
+	natural-id?,
+	(version|timestamp)?,
+	(property|many-to-one|one-to-one|component|dynamic-component|properties|any|map|set|list|bag|idbag|array|primitive-array)*,
+	((join*,subclass*)|joined-subclass*|union-subclass*),
+	loader?,sql-insert?,sql-update?,sql-delete?,
+	filter*,
+    resultset*,
+	(query|sql-query)*
+)>
+	<!ATTLIST class entity-name CDATA #IMPLIED>
+	<!ATTLIST class name CDATA #IMPLIED>                            <!-- this is the class name -->
+	<!ATTLIST class proxy CDATA #IMPLIED>							<!-- default: no proxy interface -->
+	<!ATTLIST class lazy (true|false) #IMPLIED>
+	<!ATTLIST class table CDATA #IMPLIED>							<!-- default: unqualified classname -->
+	<!ATTLIST class schema CDATA #IMPLIED>							<!-- default: none -->
+	<!ATTLIST class catalog CDATA #IMPLIED>							<!-- default: none -->
+	<!ATTLIST class subselect CDATA #IMPLIED>
+	<!ATTLIST class discriminator-value CDATA #IMPLIED>				<!-- default: unqualified class name | none -->
+	<!ATTLIST class mutable (true|false) "true">
+	<!ATTLIST class abstract (true|false) #IMPLIED>
+	<!ATTLIST class polymorphism (implicit|explicit) "implicit">
+	<!ATTLIST class where CDATA #IMPLIED>							<!-- default: none -->
+	<!ATTLIST class persister CDATA #IMPLIED>
+	<!ATTLIST class dynamic-update (true|false) "false">
+	<!ATTLIST class dynamic-insert (true|false) "false">
+	<!ATTLIST class batch-size CDATA #IMPLIED>
+	<!ATTLIST class select-before-update (true|false) "false">
+	<!ATTLIST class optimistic-lock (none|version|dirty|all) "version">
+	<!ATTLIST class check CDATA #IMPLIED>							<!-- default: none -->
+	<!ATTLIST class rowid CDATA #IMPLIED>
+	<!ATTLIST class node CDATA #IMPLIED>
+
+<!--
+    TUPLIZER element; defines tuplizer to use for a component/entity for a given entity-mode
+-->
+<!ELEMENT tuplizer EMPTY>
+    <!ATTLIST tuplizer entity-mode (pojo|dom4j|dynamic-map) #IMPLIED>   <!-- entity mode for which tuplizer is in effect -->
+    <!ATTLIST tuplizer class CDATA #REQUIRED>                           <!-- the tuplizer class to use -->
+
+<!--
+	FILTER-DEF element; top-level filter definition.
+-->
+<!ELEMENT filter-def (#PCDATA|filter-param)*>
+	<!ATTLIST filter-def name CDATA #REQUIRED> <!-- The filter name -->
+	<!ATTLIST filter-def condition CDATA #IMPLIED>
+
+<!--
+	FILTER-PARAM element; qualifies parameters found within a FILTER-DEF
+	condition.
+-->
+<!ELEMENT filter-param EMPTY>
+	<!ATTLIST filter-param name CDATA #REQUIRED> <!-- The parameter name -->
+	<!ATTLIST filter-param type CDATA #REQUIRED> <!-- The parameter type -->
+
+<!--
+	FILTER element; used to apply a filter.
+-->
+<!ELEMENT filter (#PCDATA)>
+	<!ATTLIST filter name CDATA #REQUIRED>
+	<!ATTLIST filter condition CDATA #IMPLIED>
+
+
+<!-- A join allows some properties of a class to be persisted to a second table -->
+
+<!ELEMENT join ( 
+	subselect?,
+	comment?,
+	key,
+	(property|many-to-one|component|dynamic-component|any)*,
+	sql-insert?,sql-update?,sql-delete?
+)>
+	<!ATTLIST join table CDATA #REQUIRED>
+	<!ATTLIST join schema CDATA #IMPLIED>						<!-- default: none -->
+	<!ATTLIST join catalog CDATA #IMPLIED>						<!-- default: none -->
+	<!ATTLIST join subselect CDATA #IMPLIED>
+	<!ATTLIST join fetch (join|select) "join">
+	<!ATTLIST join inverse (true|false) "false">
+	<!ATTLIST join optional (true|false) "false">
+
+<!-- A natural-id element allows declaration of the unique business key -->
+
+<!ELEMENT natural-id ( (property|many-to-one|component|dynamic-component|any)* )>
+	<!ATTLIST natural-id mutable (true|false) "false">
+
+<!-- Declares the id type, column and generation algorithm for an entity class.
+If a name attribut is given, the id is exposed to the application through the 
+named property of the class. If not, the id is only exposed to the application 
+via Session.getIdentifier() -->
+
+<!ELEMENT id (meta*,column*,type?,generator?)>
+	<!ATTLIST id name CDATA #IMPLIED>
+	<!ATTLIST id node CDATA #IMPLIED>
+	<!ATTLIST id access CDATA #IMPLIED>
+	<!ATTLIST id column CDATA #IMPLIED>
+	<!ATTLIST id type CDATA #IMPLIED>
+	<!ATTLIST id length CDATA #IMPLIED>
+	<!ATTLIST id unsaved-value CDATA #IMPLIED>					<!-- any|none|null|undefined|0|-1|... -->
+
+<!-- A composite key may be modelled by a java class with a property for each 
+key column. The class must implement java.io.Serializable and reimplement equals() 
+and hashCode(). -->
+
+<!ELEMENT composite-id ( meta*, (key-property|key-many-to-one)+ )>
+	<!ATTLIST composite-id class CDATA #IMPLIED>
+	<!ATTLIST composite-id mapped (true|false) "false">
+	<!ATTLIST composite-id name CDATA #IMPLIED>
+	<!ATTLIST composite-id node CDATA #IMPLIED>
+	<!ATTLIST composite-id access CDATA #IMPLIED>
+	<!ATTLIST composite-id unsaved-value (undefined|any|none) "undefined"> 
+
+<!-- Polymorphic data requires a column holding a class discriminator value. This
+value is not directly exposed to the application. -->
+
+<!ELEMENT discriminator ((column|formula)?)>
+	<!ATTLIST discriminator column CDATA #IMPLIED>				<!-- default: "class"|none -->
+	<!ATTLIST discriminator formula CDATA #IMPLIED>
+	<!ATTLIST discriminator type CDATA "string">
+	<!ATTLIST discriminator not-null (true|false) "true">
+	<!ATTLIST discriminator length CDATA #IMPLIED>
+	<!ATTLIST discriminator force (true|false) "false">
+	<!ATTLIST discriminator insert (true|false) "true">
+	
+<!-- Versioned data requires a column holding a version number. This is exposed to the
+application through a property of the Java class. -->
+
+<!ELEMENT version (meta*,column*)>
+	<!ATTLIST version name CDATA #REQUIRED>
+	<!ATTLIST version node CDATA #IMPLIED>
+	<!ATTLIST version access CDATA #IMPLIED>
+	<!ATTLIST version column CDATA #IMPLIED>
+	<!ATTLIST version type CDATA "integer">
+	<!ATTLIST version unsaved-value (null|negative|undefined) "undefined">
+    <!ATTLIST version generated (never|always) "never">
+    <!ATTLIST version insert (true|false) #IMPLIED>
+
+<!ELEMENT timestamp (meta*)>
+	<!ATTLIST timestamp name CDATA #REQUIRED>
+	<!ATTLIST timestamp node CDATA #IMPLIED>
+	<!ATTLIST timestamp column CDATA #IMPLIED>
+	<!ATTLIST timestamp access CDATA #IMPLIED>
+	<!ATTLIST timestamp unsaved-value (null|undefined) "null">
+    <!ATTLIST timestamp source (vm|db) "vm">
+    <!ATTLIST timestamp generated (never|always) "never">
+
+
+<!--
+	Subclass declarations are nested beneath the root class declaration to achieve
+	polymorphic persistence with the table-per-hierarchy mapping strategy.
+
+	See the note on the class element regarding <pojo/> vs. @name usage...
+-->
+<!ELEMENT subclass (
+ 	meta*,
+    tuplizer*,
+	synchronize*,
+	(property|many-to-one|one-to-one|component|dynamic-component|any|map|set|list|bag|idbag|array|primitive-array)*,
+	join*, 
+	subclass*,
+	loader?,sql-insert?,sql-update?,sql-delete?,
+    resultset*,
+	(query|sql-query)*
+)>
+	<!ATTLIST subclass entity-name CDATA #IMPLIED>
+	<!ATTLIST subclass name CDATA #IMPLIED>
+	<!ATTLIST subclass proxy CDATA #IMPLIED>							<!-- default: no proxy interface -->
+	<!ATTLIST subclass discriminator-value CDATA #IMPLIED>				<!-- default: unqualified class name | none -->
+	<!ATTLIST subclass dynamic-update (true|false) "false">
+	<!ATTLIST subclass dynamic-insert (true|false) "false">
+	<!ATTLIST subclass select-before-update (true|false) "false">
+	<!ATTLIST subclass extends CDATA #IMPLIED>							<!-- default: empty when a toplevel, otherwise the nearest class definition -->
+	<!ATTLIST subclass lazy (true|false) #IMPLIED>
+	<!ATTLIST subclass abstract (true|false) #IMPLIED>
+	<!ATTLIST subclass persister CDATA #IMPLIED>
+	<!ATTLIST subclass batch-size CDATA #IMPLIED>
+	<!ATTLIST subclass node CDATA #IMPLIED>
+
+<!--
+	Joined subclasses are used for the normalized table-per-subclass mapping strategy
+
+	See the note on the class element regarding <pojo/> vs. @name usage...
+-->
+<!ELEMENT joined-subclass (
+	meta*,
+	subselect?,
+	synchronize*,
+	comment?,
+    tuplizer*,
+	key,
+	(property|many-to-one|one-to-one|component|dynamic-component|properties|any|map|set|list|bag|idbag|array|primitive-array)*, 
+	joined-subclass*,
+	loader?,sql-insert?,sql-update?,sql-delete?,
+    resultset*,
+	(query|sql-query)*
+)>
+	<!ATTLIST joined-subclass entity-name CDATA #IMPLIED>
+	<!ATTLIST joined-subclass name CDATA #IMPLIED>
+	<!ATTLIST joined-subclass proxy CDATA #IMPLIED>				 		<!-- default: no proxy interface -->
+	<!ATTLIST joined-subclass table CDATA #IMPLIED>				 		<!-- default: unqualified class name -->
+	<!ATTLIST joined-subclass schema CDATA #IMPLIED>
+	<!ATTLIST joined-subclass catalog CDATA #IMPLIED>
+	<!ATTLIST joined-subclass subselect CDATA #IMPLIED>
+	<!ATTLIST joined-subclass dynamic-update (true|false) "false">
+	<!ATTLIST joined-subclass dynamic-insert (true|false) "false">
+	<!ATTLIST joined-subclass select-before-update (true|false) "false">
+	<!ATTLIST joined-subclass extends CDATA #IMPLIED>			 		<!-- default: none when toplevel, otherwise the nearest class definition -->
+	<!ATTLIST joined-subclass lazy (true|false) #IMPLIED>
+	<!ATTLIST joined-subclass abstract (true|false) #IMPLIED>
+	<!ATTLIST joined-subclass persister CDATA #IMPLIED>
+	<!ATTLIST joined-subclass check CDATA #IMPLIED>				 		<!-- default: none -->
+	<!ATTLIST joined-subclass batch-size CDATA #IMPLIED>
+	<!ATTLIST joined-subclass node CDATA #IMPLIED>
+
+<!--
+	Union subclasses are used for the table-per-concrete-class mapping strategy
+
+	See the note on the class element regarding <pojo/> vs. @name usage...
+-->
+<!ELEMENT union-subclass (
+ 	meta*,
+	subselect?,
+	synchronize*,
+	comment?,
+    tuplizer*,
+	(property|many-to-one|one-to-one|component|dynamic-component|properties|any|map|set|list|bag|idbag|array|primitive-array)*,
+	union-subclass*,
+	loader?,sql-insert?,sql-update?,sql-delete?,
+    resultset*,
+	(query|sql-query)*
+)>
+	<!ATTLIST union-subclass entity-name CDATA #IMPLIED>
+	<!ATTLIST union-subclass name CDATA #IMPLIED>
+	<!ATTLIST union-subclass proxy CDATA #IMPLIED>						<!-- default: no proxy interface -->
+	<!ATTLIST union-subclass table CDATA #IMPLIED>						<!-- default: unqualified class name -->
+	<!ATTLIST union-subclass schema CDATA #IMPLIED>
+	<!ATTLIST union-subclass catalog CDATA #IMPLIED>
+	<!ATTLIST union-subclass subselect CDATA #IMPLIED>
+	<!ATTLIST union-subclass dynamic-update (true|false) "false">
+	<!ATTLIST union-subclass dynamic-insert (true|false) "false">
+	<!ATTLIST union-subclass select-before-update (true|false) "false">
+	<!ATTLIST union-subclass extends CDATA #IMPLIED>					<!-- default: none when toplevel, otherwise the nearest class definition -->
+	<!ATTLIST union-subclass lazy (true|false) #IMPLIED>
+	<!ATTLIST union-subclass abstract (true|false) #IMPLIED>
+	<!ATTLIST union-subclass persister CDATA #IMPLIED>
+	<!ATTLIST union-subclass check CDATA #IMPLIED>						<!-- default: none -->
+	<!ATTLIST union-subclass batch-size CDATA #IMPLIED>
+	<!ATTLIST union-subclass node CDATA #IMPLIED>
+
+<!-- Property of an entity class or component, component-element, composite-id, etc. 
+JavaBeans style properties are mapped to table columns. -->
+
+<!ELEMENT property (meta*,(column|formula)*,type?)>
+	<!ATTLIST property name CDATA #REQUIRED>
+	<!ATTLIST property node CDATA #IMPLIED>
+	<!ATTLIST property access CDATA #IMPLIED>
+	<!ATTLIST property type CDATA #IMPLIED>
+	<!ATTLIST property column CDATA #IMPLIED>
+	<!ATTLIST property length CDATA #IMPLIED>
+	<!ATTLIST property precision CDATA #IMPLIED>
+	<!ATTLIST property scale CDATA #IMPLIED>
+	<!ATTLIST property not-null (true|false) #IMPLIED>
+	<!ATTLIST property unique (true|false) "false">
+	<!ATTLIST property unique-key CDATA #IMPLIED>
+	<!ATTLIST property index CDATA #IMPLIED>				<!-- include the columns spanned by this property in an index -->
+	<!ATTLIST property update (true|false) #IMPLIED>
+	<!ATTLIST property insert (true|false) #IMPLIED>
+	<!ATTLIST property optimistic-lock (true|false) "true">	<!-- only supported for properties of a class (not component) -->
+	<!ATTLIST property formula CDATA #IMPLIED>
+	<!ATTLIST property lazy (true|false) "false">
+    <!ATTLIST property generated (never|insert|always) "never">
+
+<!-- Declares the type of the containing property (overrides an eventually existing type
+attribute of the property). May contain param elements to customize a ParametrizableType. -->
+<!ELEMENT type (param*)>
+	<!ATTLIST type name CDATA #REQUIRED>
+	
+<!-- Declares an association between two entities (Or from a component, component element,
+etc. to an entity). -->
+
+<!ELEMENT many-to-one (meta*,(column|formula)*)>
+	<!ATTLIST many-to-one name CDATA #REQUIRED>
+	<!ATTLIST many-to-one access CDATA #IMPLIED>
+	<!ATTLIST many-to-one class CDATA #IMPLIED>
+	<!ATTLIST many-to-one entity-name CDATA #IMPLIED>
+	<!ATTLIST many-to-one column CDATA #IMPLIED>
+	<!ATTLIST many-to-one not-null (true|false) #IMPLIED>
+	<!ATTLIST many-to-one unique (true|false) "false">
+	<!ATTLIST many-to-one unique-key CDATA #IMPLIED>
+	<!ATTLIST many-to-one index CDATA #IMPLIED>
+	<!ATTLIST many-to-one cascade CDATA #IMPLIED>
+	<!ATTLIST many-to-one outer-join (true|false|auto) #IMPLIED>
+	<!ATTLIST many-to-one fetch (join|select) #IMPLIED>
+	<!ATTLIST many-to-one update (true|false) "true">
+	<!ATTLIST many-to-one insert (true|false) "true">
+	<!ATTLIST many-to-one optimistic-lock (true|false) "true">	<!-- only supported for properties of a class (not component) -->
+	<!ATTLIST many-to-one foreign-key CDATA #IMPLIED>
+	<!ATTLIST many-to-one property-ref CDATA #IMPLIED>
+	<!ATTLIST many-to-one formula CDATA #IMPLIED>
+	<!ATTLIST many-to-one lazy (false|proxy|no-proxy) #IMPLIED>
+	<!ATTLIST many-to-one not-found (exception|ignore) "exception">
+	<!ATTLIST many-to-one node CDATA #IMPLIED>
+	<!ATTLIST many-to-one embed-xml (true|false) "true">
+	
+<!-- Declares a one-to-one association between two entities (Or from a component, 
+component element, etc. to an entity). -->
+
+<!ELEMENT one-to-one (meta*,formula*)>
+	<!ATTLIST one-to-one name CDATA #REQUIRED>
+	<!ATTLIST one-to-one formula CDATA #IMPLIED>
+	<!ATTLIST one-to-one access CDATA #IMPLIED>
+	<!ATTLIST one-to-one class CDATA #IMPLIED>
+	<!ATTLIST one-to-one entity-name CDATA #IMPLIED>
+	<!ATTLIST one-to-one cascade CDATA #IMPLIED>
+	<!ATTLIST one-to-one outer-join (true|false|auto) #IMPLIED>
+	<!ATTLIST one-to-one fetch (join|select) #IMPLIED>
+	<!ATTLIST one-to-one constrained (true|false) "false">
+	<!ATTLIST one-to-one foreign-key CDATA #IMPLIED>
+	<!ATTLIST one-to-one property-ref CDATA #IMPLIED>
+	<!ATTLIST one-to-one lazy (false|proxy|no-proxy) #IMPLIED>
+	<!ATTLIST one-to-one node CDATA #IMPLIED>
+	<!ATTLIST one-to-one embed-xml (true|false) "true">
+	
+<!-- A property embedded in a composite identifier or map index (always not-null). -->
+
+<!ELEMENT key-property (meta*,column*,type?)>
+	<!ATTLIST key-property name CDATA #REQUIRED>
+	<!ATTLIST key-property access CDATA #IMPLIED>
+	<!ATTLIST key-property type CDATA #IMPLIED>
+	<!ATTLIST key-property column CDATA #IMPLIED>
+	<!ATTLIST key-property length CDATA #IMPLIED>
+	<!ATTLIST key-property node CDATA #IMPLIED>
+
+<!-- A many-to-one association embedded in a composite identifier or map index 
+(always not-null, never cascade). -->
+
+<!ELEMENT key-many-to-one (meta*,column*)>
+	<!ATTLIST key-many-to-one name CDATA #REQUIRED>
+	<!ATTLIST key-many-to-one access CDATA #IMPLIED>
+	<!ATTLIST key-many-to-one class CDATA #IMPLIED>
+	<!ATTLIST key-many-to-one entity-name CDATA #IMPLIED>
+	<!ATTLIST key-many-to-one column CDATA #IMPLIED>
+	<!ATTLIST key-many-to-one foreign-key CDATA #IMPLIED>
+	<!ATTLIST key-many-to-one lazy (false|proxy) #IMPLIED>
+
+<!-- An "any" association is a polymorphic association to any table with
+the given identifier type. The first listed column is a VARCHAR column 
+holding the name of the class (for that row). -->
+
+<!ELEMENT any (meta*,meta-value*,column,column+)>
+	<!ATTLIST any id-type CDATA #REQUIRED>
+	<!ATTLIST any meta-type CDATA #IMPLIED>			 	<!--- default: Hibernate.STRING -->
+	<!ATTLIST any name CDATA #REQUIRED>
+	<!ATTLIST any access CDATA #IMPLIED>
+	<!ATTLIST any insert (true|false) "true">
+	<!ATTLIST any update (true|false) "true">
+	<!ATTLIST any cascade CDATA #IMPLIED>
+	<!ATTLIST any index CDATA #IMPLIED>					<!-- include the columns spanned by this association in an index -->
+	<!ATTLIST any optimistic-lock (true|false) "true">	<!-- only supported for properties of a class (not component) -->
+	<!ATTLIST any lazy (true|false) "false">
+	<!ATTLIST any node CDATA #IMPLIED>
+	
+<!ELEMENT meta-value EMPTY>
+	<!ATTLIST meta-value value CDATA #REQUIRED>
+	<!ATTLIST meta-value class CDATA #REQUIRED>
+
+<!-- A component is a user-defined class, persisted along with its containing entity
+to the table of the entity class. JavaBeans style properties of the component are
+mapped to columns of the table of the containing entity. A null component reference
+is mapped to null values in all columns and vice versa. Components do not support
+shared reference semantics. -->
+
+<!ELEMENT component (
+	meta*,
+    tuplizer*,
+	parent?,
+	(property|many-to-one|one-to-one|component|dynamic-component|any|map|set|list|bag|array|primitive-array)*
+)>
+	<!ATTLIST component class CDATA #IMPLIED>
+	<!ATTLIST component name CDATA #REQUIRED>
+	<!ATTLIST component access CDATA #IMPLIED>
+	<!ATTLIST component unique (true|false) "false">
+	<!ATTLIST component update (true|false) "true">
+	<!ATTLIST component insert (true|false) "true">
+	<!ATTLIST component lazy (true|false) "false">
+	<!ATTLIST component optimistic-lock (true|false) "true">
+	<!ATTLIST component node CDATA #IMPLIED>
+	
+<!-- A dynamic-component maps columns of the database entity to a java.util.Map 
+at the Java level -->
+
+<!ELEMENT dynamic-component (
+	(property|many-to-one|one-to-one|component|dynamic-component|any|map|set|list|bag|array|primitive-array)*
+)>
+	<!ATTLIST dynamic-component name CDATA #REQUIRED>
+	<!ATTLIST dynamic-component access CDATA #IMPLIED>
+	<!ATTLIST dynamic-component unique (true|false) "false">
+	<!ATTLIST dynamic-component update (true|false) "true">
+	<!ATTLIST dynamic-component insert (true|false) "true">
+	<!ATTLIST dynamic-component optimistic-lock (true|false) "true">
+	<!ATTLIST dynamic-component node CDATA #IMPLIED>
+
+<!-- properties declares that the contained properties form an alternate key. The name
+attribute allows an alternate key to be used as the target of a property-ref. -->
+
+<!ELEMENT properties (
+	(property|many-to-one|component|dynamic-component)*
+)>
+	<!ATTLIST properties name CDATA #REQUIRED>
+	<!ATTLIST properties unique (true|false) "false">
+	<!ATTLIST properties insert (true|false) "true">
+	<!ATTLIST properties update (true|false) "true">
+	<!ATTLIST properties optimistic-lock (true|false) "true">
+	<!ATTLIST properties node CDATA #IMPLIED>
+	
+<!-- The parent element maps a property of the component class as a pointer back to
+the owning entity. -->
+
+<!ELEMENT parent EMPTY>
+	<!ATTLIST parent name CDATA #REQUIRED>
+
+<!-- Collection declarations nested inside a class declaration indicate a foreign key 
+relationship from the collection table to the enclosing class. -->
+
+<!ELEMENT map (
+	meta*,
+	subselect?,
+	cache?,
+	synchronize*,
+	comment?,
+	key, 
+	(map-key|composite-map-key|map-key-many-to-many|index|composite-index|index-many-to-many|index-many-to-any), 
+	(element|one-to-many|many-to-many|composite-element|many-to-any),
+	loader?,sql-insert?,sql-update?,sql-delete?,sql-delete-all?,
+	filter*
+)>
+	<!ATTLIST map name CDATA #REQUIRED>
+	<!ATTLIST map access CDATA #IMPLIED>
+	<!ATTLIST map table CDATA #IMPLIED>																<!-- default: name -->
+	<!ATTLIST map schema CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST map subselect CDATA #IMPLIED>
+	<!ATTLIST map catalog CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST map lazy (true|false|extra) #IMPLIED>
+	<!ATTLIST map mutable (true|false) "true">
+	<!ATTLIST map inverse (true|false) "false">
+	<!ATTLIST map sort CDATA "unsorted">														 	<!-- unsorted|natural|"comparator class", default: unsorted -->
+	<!ATTLIST map cascade CDATA #IMPLIED>
+	<!ATTLIST map order-by CDATA #IMPLIED>													 		<!-- default: none -->
+	<!ATTLIST map where CDATA #IMPLIED>																<!-- default: none -->
+	<!ATTLIST map batch-size CDATA #IMPLIED>
+	<!ATTLIST map outer-join (true|false|auto) #IMPLIED>
+	<!ATTLIST map fetch (join|select|subselect) #IMPLIED>
+	<!ATTLIST map check CDATA #IMPLIED>																<!-- default: none -->	
+	<!ATTLIST map persister CDATA #IMPLIED>														
+	<!ATTLIST map collection-type CDATA #IMPLIED>	
+	<!ATTLIST map optimistic-lock (true|false) "true">		<!-- only supported for properties of a class (not component) -->
+	<!ATTLIST map node CDATA #IMPLIED>
+	<!ATTLIST map embed-xml (true|false) "true">
+	
+<!ELEMENT set (
+	meta*,
+	subselect?,
+	cache?,
+	synchronize*,
+	comment?,
+	key, 
+	(element|one-to-many|many-to-many|composite-element|many-to-any),
+	loader?,sql-insert?,sql-update?,sql-delete?,sql-delete-all?,
+	filter*
+)>
+	<!ATTLIST set name CDATA #REQUIRED>
+	<!ATTLIST set access CDATA #IMPLIED>
+	<!ATTLIST set table CDATA #IMPLIED>																<!-- default: name -->
+	<!ATTLIST set schema CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST set catalog CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST set subselect CDATA #IMPLIED>
+	<!ATTLIST set lazy (true|false|extra) #IMPLIED>
+	<!ATTLIST set sort CDATA "unsorted">														 	<!-- unsorted|natural|"comparator class" -->
+	<!ATTLIST set inverse (true|false) "false">
+	<!ATTLIST set mutable (true|false) "true">
+	<!ATTLIST set cascade CDATA #IMPLIED>
+	<!ATTLIST set order-by CDATA #IMPLIED>													 		<!-- default: none -->
+	<!ATTLIST set where CDATA #IMPLIED>																<!-- default: none -->
+	<!ATTLIST set batch-size CDATA #IMPLIED>
+	<!ATTLIST set outer-join (true|false|auto) #IMPLIED>
+	<!ATTLIST set fetch (join|select|subselect) #IMPLIED>
+	<!ATTLIST set persister CDATA #IMPLIED>	
+	<!ATTLIST set collection-type CDATA #IMPLIED>														
+	<!ATTLIST set check CDATA #IMPLIED>																<!-- default: none -->
+	<!ATTLIST set optimistic-lock (true|false) "true">		<!-- only supported for properties of a class (not component) -->
+	<!ATTLIST set node CDATA #IMPLIED>
+	<!ATTLIST set embed-xml (true|false) "true">
+
+<!ELEMENT bag (
+	meta*,
+	subselect?,
+	cache?,
+	synchronize*,
+	comment?,
+	key, 
+	(element|one-to-many|many-to-many|composite-element|many-to-any),
+	loader?,sql-insert?,sql-update?,sql-delete?,sql-delete-all?,
+	filter*
+)>
+	<!ATTLIST bag name CDATA #REQUIRED>
+	<!ATTLIST bag access CDATA #IMPLIED>
+	<!ATTLIST bag table CDATA #IMPLIED>																<!-- default: name -->
+	<!ATTLIST bag schema CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST bag catalog CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST bag subselect CDATA #IMPLIED>
+	<!ATTLIST bag lazy (true|false|extra) #IMPLIED>
+	<!ATTLIST bag inverse (true|false) "false">
+	<!ATTLIST bag mutable (true|false) "true">
+	<!ATTLIST bag cascade CDATA #IMPLIED>
+	<!ATTLIST bag order-by CDATA #IMPLIED>													 		<!-- default: none -->
+	<!ATTLIST bag where CDATA #IMPLIED>																<!-- default: none -->
+	<!ATTLIST bag batch-size CDATA #IMPLIED>
+	<!ATTLIST bag outer-join (true|false|auto) #IMPLIED>
+	<!ATTLIST bag fetch (join|select|subselect) #IMPLIED>
+	<!ATTLIST bag persister CDATA #IMPLIED>															
+	<!ATTLIST bag collection-type CDATA #IMPLIED>	
+	<!ATTLIST bag check CDATA #IMPLIED>																<!-- default: none -->
+	<!ATTLIST bag optimistic-lock (true|false) "true">		<!-- only supported for properties of a class (not component) -->
+	<!ATTLIST bag node CDATA #IMPLIED>
+	<!ATTLIST bag embed-xml (true|false) "true">
+
+<!ELEMENT idbag (
+	meta*,
+	subselect?,
+	cache?,
+	synchronize*,
+	comment?,
+	collection-id,
+	key, 
+	(element|many-to-many|composite-element|many-to-any),
+	loader?,sql-insert?,sql-update?,sql-delete?,sql-delete-all?,
+	filter*
+)>
+	<!ATTLIST idbag name CDATA #REQUIRED>
+	<!ATTLIST idbag access CDATA #IMPLIED>
+	<!ATTLIST idbag table CDATA #IMPLIED>															<!-- default: name -->
+	<!ATTLIST idbag schema CDATA #IMPLIED>														 	<!-- default: none -->
+	<!ATTLIST idbag catalog CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST idbag subselect CDATA #IMPLIED>
+	<!ATTLIST idbag lazy (true|false|extra) #IMPLIED>
+	<!ATTLIST idbag mutable (true|false) "true">
+	<!ATTLIST idbag cascade CDATA #IMPLIED>
+	<!ATTLIST idbag order-by CDATA #IMPLIED>													 	<!-- default: none -->
+	<!ATTLIST idbag where CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST idbag batch-size CDATA #IMPLIED>
+	<!ATTLIST idbag outer-join (true|false|auto) #IMPLIED>
+	<!ATTLIST idbag fetch (join|select|subselect) #IMPLIED>
+	<!ATTLIST idbag persister CDATA #IMPLIED>															
+	<!ATTLIST idbag collection-type CDATA #IMPLIED>
+	<!ATTLIST idbag check CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST idbag optimistic-lock (true|false) "true">	<!-- only supported for properties of a class (not component) -->
+	<!ATTLIST idbag node CDATA #IMPLIED>
+	<!ATTLIST idbag embed-xml (true|false) "true">
+
+<!ELEMENT list (
+	meta*,
+	subselect?,
+	cache?,
+	synchronize*,
+	comment?,
+	key, 
+	(index|list-index), 
+	(element|one-to-many|many-to-many|composite-element|many-to-any),
+	loader?,sql-insert?,sql-update?,sql-delete?,sql-delete-all?,
+	filter*
+)>
+	<!ATTLIST list name CDATA #REQUIRED>
+	<!ATTLIST list access CDATA #IMPLIED>
+	<!ATTLIST list table CDATA #IMPLIED>														 	<!-- default: name -->
+	<!ATTLIST list schema CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST list catalog CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST list subselect CDATA #IMPLIED>
+	<!ATTLIST list lazy (true|false|extra) #IMPLIED>
+	<!ATTLIST list inverse (true|false) "false">
+	<!ATTLIST list mutable (true|false) "true">
+	<!ATTLIST list cascade CDATA #IMPLIED>
+	<!ATTLIST list where CDATA #IMPLIED>														 	<!-- default: none -->
+	<!ATTLIST list batch-size CDATA #IMPLIED>
+	<!ATTLIST list outer-join (true|false|auto) #IMPLIED>
+	<!ATTLIST list fetch (join|select|subselect) #IMPLIED>
+	<!ATTLIST list persister CDATA #IMPLIED>																
+	<!ATTLIST list collection-type CDATA #IMPLIED>
+	<!ATTLIST list check CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST list optimistic-lock (true|false) "true">		<!-- only supported for properties of a class (not component) -->
+	<!ATTLIST list node CDATA #IMPLIED>
+	<!ATTLIST list embed-xml (true|false) "true">
+
+<!ELEMENT array (
+	meta*,
+	subselect?,
+	cache?,
+	synchronize*,
+	comment?,
+	key, 
+	(index|list-index), 
+	(element|one-to-many|many-to-many|composite-element|many-to-any),
+	loader?,sql-insert?,sql-update?,sql-delete?,sql-delete-all?
+)>
+	<!ATTLIST array name CDATA #REQUIRED>
+	<!ATTLIST array access CDATA #IMPLIED>
+	<!ATTLIST array table CDATA #IMPLIED>															<!-- default: name -->
+	<!ATTLIST array schema CDATA #IMPLIED>													 		<!-- default: none -->
+	<!ATTLIST array catalog CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST array subselect CDATA #IMPLIED>
+	<!ATTLIST array inverse (true|false) "false">
+	<!ATTLIST array mutable (true|false) "true">
+	<!ATTLIST array element-class CDATA #IMPLIED>
+	<!ATTLIST array cascade CDATA #IMPLIED>
+	<!ATTLIST array where CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST array batch-size CDATA #IMPLIED>
+	<!ATTLIST array outer-join (true|false|auto) #IMPLIED>
+	<!ATTLIST array fetch (join|select|subselect) #IMPLIED>
+	<!ATTLIST array persister CDATA #IMPLIED>															
+	<!ATTLIST array collection-type CDATA #IMPLIED>
+	<!ATTLIST array check CDATA #IMPLIED>															<!-- default: none -->
+	<!ATTLIST array optimistic-lock (true|false) "true">	<!-- only supported for properties of a class (not component) -->
+	<!ATTLIST array node CDATA #IMPLIED>
+	<!ATTLIST array embed-xml (true|false) "true">
+
+<!ELEMENT primitive-array (
+	meta*, 
+	subselect?,
+	cache?, 
+	synchronize*,
+	comment?,
+	key, 
+	(index|list-index), 
+	element,
+	loader?,sql-insert?,sql-update?,sql-delete?,sql-delete-all?
+)>
+	<!ATTLIST primitive-array name CDATA #REQUIRED>
+	<!ATTLIST primitive-array access CDATA #IMPLIED>
+	<!ATTLIST primitive-array table CDATA #IMPLIED>									<!-- default: name -->
+	<!ATTLIST primitive-array schema CDATA #IMPLIED>								<!-- default: none -->
+	<!ATTLIST primitive-array catalog CDATA #IMPLIED>								<!-- default: none -->
+	<!ATTLIST primitive-array subselect CDATA #IMPLIED>
+	<!ATTLIST primitive-array mutable (true|false) "true">
+	<!ATTLIST primitive-array where CDATA #IMPLIED>									<!-- default: none -->
+	<!ATTLIST primitive-array batch-size CDATA #IMPLIED>
+	<!ATTLIST primitive-array outer-join (true|false|auto) #IMPLIED>
+	<!ATTLIST primitive-array fetch (join|select|subselect) #IMPLIED>
+	<!ATTLIST primitive-array persister CDATA #IMPLIED>																
+	<!ATTLIST primitive-array collection-type CDATA #IMPLIED>
+	<!ATTLIST primitive-array check CDATA #IMPLIED>									<!-- default: none -->
+	<!ATTLIST primitive-array optimistic-lock (true|false) "true">		<!-- only supported for properties of a class (not component) -->
+	<!ATTLIST primitive-array node CDATA #IMPLIED>
+	<!ATTLIST primitive-array embed-xml (true|false) "true">
+
+<!-- Declares the element type of a collection of basic type -->
+
+<!ELEMENT element ( (column|formula)*, type? )>
+	<!ATTLIST element column CDATA #IMPLIED>
+	<!ATTLIST element node CDATA #IMPLIED>
+	<!ATTLIST element formula CDATA #IMPLIED>
+	<!ATTLIST element type CDATA #IMPLIED>
+	<!ATTLIST element length CDATA #IMPLIED>
+	<!ATTLIST element precision CDATA #IMPLIED>
+	<!ATTLIST element scale CDATA #IMPLIED>
+	<!ATTLIST element not-null (true|false) "false">
+	<!ATTLIST element unique (true|false) "false">
+
+<!-- One to many association. This tag declares the entity-class
+element type of a collection and specifies a one-to-many relational model -->
+
+<!ELEMENT one-to-many EMPTY>
+	<!ATTLIST one-to-many class CDATA #IMPLIED>
+	<!ATTLIST one-to-many not-found (exception|ignore) "exception">
+	<!ATTLIST one-to-many node CDATA #IMPLIED>
+	<!ATTLIST one-to-many embed-xml (true|false) "true">
+	<!ATTLIST one-to-many entity-name CDATA #IMPLIED>
+	<!-- No column declaration attributes required in this case. The primary
+	key column of the associated class is already mapped elsewhere.-->
+
+<!-- Many to many association. This tag declares the entity-class
+element type of a collection and specifies a many-to-many relational model -->
+
+<!ELEMENT many-to-many (meta*,(column|formula)*,filter*)>
+	<!ATTLIST many-to-many class CDATA #IMPLIED>
+	<!ATTLIST many-to-many node CDATA #IMPLIED>
+	<!ATTLIST many-to-many embed-xml (true|false) "true">
+	<!ATTLIST many-to-many entity-name CDATA #IMPLIED>
+	<!ATTLIST many-to-many column CDATA #IMPLIED>
+	<!ATTLIST many-to-many formula CDATA #IMPLIED>
+	<!ATTLIST many-to-many not-found (exception|ignore) "exception">
+	<!ATTLIST many-to-many outer-join (true|false|auto) #IMPLIED>
+	<!ATTLIST many-to-many fetch (join|select) #IMPLIED>
+	<!ATTLIST many-to-many lazy (false|proxy) #IMPLIED>
+	<!ATTLIST many-to-many foreign-key CDATA #IMPLIED>
+	<!ATTLIST many-to-many unique (true|false) "false">
+	<!ATTLIST many-to-many where CDATA #IMPLIED>
+	<!ATTLIST many-to-many order-by CDATA #IMPLIED>
+	<!ATTLIST many-to-many property-ref CDATA #IMPLIED>
+
+<!-- A composite element allows a collection to hold instances of an arbitrary 
+class, without the requirement of joining to an entity table. Composite elements
+have component semantics - no shared references and ad hoc null value semantics. 
+Composite elements may not hold nested collections. -->
+
+<!ELEMENT composite-element ( 
+	(meta*),
+	parent?,
+	(property|many-to-one|any|nested-composite-element)* 
+)>
+	<!ATTLIST composite-element class CDATA #REQUIRED>
+	<!ATTLIST composite-element node CDATA #IMPLIED>
+
+<!ELEMENT nested-composite-element ( 
+	parent?,
+	(property|many-to-one|any|nested-composite-element)* 
+)>
+	<!ATTLIST nested-composite-element class CDATA #REQUIRED>
+	<!ATTLIST nested-composite-element name CDATA #REQUIRED>
+	<!ATTLIST nested-composite-element access CDATA #IMPLIED>
+	<!ATTLIST nested-composite-element node CDATA #IMPLIED>
+	
+<!-- Declares the column name of a foreign key. -->
+
+<!ELEMENT key (column*)>
+	<!ATTLIST key column CDATA #IMPLIED>
+	<!ATTLIST key property-ref CDATA #IMPLIED>
+	<!ATTLIST key foreign-key CDATA #IMPLIED>
+	<!ATTLIST key on-delete (cascade|noaction) "noaction">
+	<!ATTLIST key not-null (true|false) #IMPLIED>
+	<!ATTLIST key update (true|false) #IMPLIED>
+	<!ATTLIST key unique (true|false) #IMPLIED>
+	
+<!-- Declares the type and column mapping for a collection index (array or
+list index, or key of a map). -->
+
+<!ELEMENT list-index (column?)>
+	<!ATTLIST list-index column CDATA #IMPLIED>
+	<!ATTLIST list-index base CDATA "0">
+
+<!ELEMENT map-key ((column|formula)*)>
+	<!ATTLIST map-key column CDATA #IMPLIED>
+	<!ATTLIST map-key formula CDATA #IMPLIED>
+	<!ATTLIST map-key type CDATA #REQUIRED>
+	<!ATTLIST map-key length CDATA #IMPLIED>
+	<!ATTLIST map-key node CDATA #IMPLIED>
+
+<!ELEMENT index (column*)>
+	<!ATTLIST index column CDATA #IMPLIED>
+	<!ATTLIST index type CDATA #IMPLIED>			<!-- required for maps -->
+	<!ATTLIST index length CDATA #IMPLIED>
+
+<!-- Many to many association mapped to the key of a map. ie. a map keyed
+on entities. -->
+
+<!ELEMENT map-key-many-to-many ((column|formula)*)>
+	<!ATTLIST map-key-many-to-many class CDATA #IMPLIED>
+	<!ATTLIST map-key-many-to-many entity-name CDATA #IMPLIED>
+	<!ATTLIST map-key-many-to-many column CDATA #IMPLIED>
+	<!ATTLIST map-key-many-to-many formula CDATA #IMPLIED>
+	<!ATTLIST map-key-many-to-many foreign-key CDATA #IMPLIED>
+
+<!ELEMENT index-many-to-many (column*)>
+	<!ATTLIST index-many-to-many class CDATA #REQUIRED>
+	<!ATTLIST index-many-to-many entity-name CDATA #IMPLIED>
+	<!ATTLIST index-many-to-many column CDATA #IMPLIED>
+	<!ATTLIST index-many-to-many foreign-key CDATA #IMPLIED>
+
+<!-- Composite index of a map ie. a map keyed on components. -->
+
+<!ELEMENT composite-map-key ( (key-property|key-many-to-one)+ )>
+	<!ATTLIST composite-map-key class CDATA #REQUIRED>
+
+<!ELEMENT composite-index ( (key-property|key-many-to-one)+ )>
+	<!ATTLIST composite-index class CDATA #REQUIRED>
+
+<!-- A "many to any" defines a polymorphic association to any table 
+with the given identifier type. The first listed column is a VARCHAR column 
+holding the name of the class (for that row). -->
+
+<!ELEMENT many-to-any (meta-value*,column, column+)>
+	<!ATTLIST many-to-any id-type CDATA #REQUIRED>
+	<!ATTLIST many-to-any meta-type CDATA #IMPLIED>			<!--- default: Hibernate.CLASS -->
+
+<!ELEMENT index-many-to-any (column, column+)>
+	<!ATTLIST index-many-to-any id-type CDATA #REQUIRED>
+	<!ATTLIST index-many-to-any meta-type CDATA #IMPLIED>	<!--- default: Hibernate.CLASS -->
+
+<!ELEMENT collection-id (meta*, column*, generator)>
+	<!ATTLIST collection-id column CDATA #REQUIRED>
+	<!ATTLIST collection-id type CDATA #REQUIRED>
+	<!ATTLIST collection-id length CDATA #IMPLIED>
+	
+<!-- Generators generate unique identifiers. The class attribute specifies a Java 
+class implementing an id generation algorithm. -->
+
+<!ELEMENT generator (param*)>
+	<!ATTLIST generator class CDATA #REQUIRED>
+<!ELEMENT param (#PCDATA)>
+	<!ATTLIST param name CDATA #REQUIRED>
+
+<!-- The column element is an alternative to column attributes and required for 
+mapping associations to classes with composite ids. -->
+
+<!ELEMENT column (comment?)>
+	<!ATTLIST column name CDATA #REQUIRED>
+	<!ATTLIST column length CDATA #IMPLIED>						<!-- default: 255 -->
+	<!ATTLIST column precision CDATA #IMPLIED>
+	<!ATTLIST column scale CDATA #IMPLIED>
+	<!ATTLIST column not-null (true|false) #IMPLIED>		 	<!-- default: false (except for id properties) -->
+	<!ATTLIST column unique (true|false) #IMPLIED>			 	<!-- default: false (except for id properties) -->
+	<!ATTLIST column unique-key CDATA #IMPLIED>					<!-- default: no unique key -->
+	<!ATTLIST column sql-type CDATA #IMPLIED>					<!-- override default column type for hibernate type -->
+	<!ATTLIST column index CDATA #IMPLIED>
+	<!ATTLIST column check CDATA #IMPLIED>						<!-- default: no check constraint -->
+    <!ATTLIST column default CDATA #IMPLIED>                    <!-- default: no default value -->
+
+<!-- The formula and subselect elements allow us to map derived properties and 
+entities. -->
+
+<!ELEMENT formula (#PCDATA)>
+<!ELEMENT subselect (#PCDATA)>
+
+<!-- The cache element enables caching of an entity class. -->
+<!ELEMENT cache EMPTY>
+	<!ATTLIST cache usage (read-only|read-write|nonstrict-read-write|transactional) #REQUIRED>				
+	<!ATTLIST cache region CDATA #IMPLIED>						<!-- default: class or collection role name -->
+	<!ATTLIST cache include (all|non-lazy) "all">
+
+<!-- The comment element allows definition of a database table or column comment. -->
+
+<!ELEMENT comment (#PCDATA)>
+
+<!-- The loader element allows specification of a named query to be used for fetching
+an entity or collection -->
+
+<!ELEMENT loader EMPTY>
+	<!ATTLIST loader query-ref CDATA #REQUIRED>
+
+<!-- The query element declares a named Hibernate query string -->
+
+<!ELEMENT query (#PCDATA|query-param)*>
+	<!ATTLIST query name CDATA #REQUIRED>
+	<!ATTLIST query flush-mode (auto|never|always) #IMPLIED>
+	<!ATTLIST query cacheable (true|false) "false">
+	<!ATTLIST query cache-region CDATA #IMPLIED>
+	<!ATTLIST query fetch-size CDATA #IMPLIED>
+	<!ATTLIST query timeout CDATA #IMPLIED>
+	<!ATTLIST query cache-mode (get|ignore|normal|put|refresh) #IMPLIED>
+    <!ATTLIST query read-only (true|false) #IMPLIED>
+    <!ATTLIST query comment CDATA #IMPLIED>
+
+<!-- The sql-query element declares a named SQL query string -->
+
+<!ELEMENT sql-query (#PCDATA|return-scalar|return|return-join|load-collection|synchronize|query-param)*>
+	<!ATTLIST sql-query name CDATA #REQUIRED>
+    <!ATTLIST sql-query resultset-ref CDATA #IMPLIED>
+	<!ATTLIST sql-query flush-mode (auto|never|always) #IMPLIED>
+	<!ATTLIST sql-query cacheable (true|false) "false">
+	<!ATTLIST sql-query cache-region CDATA #IMPLIED>
+	<!ATTLIST sql-query fetch-size CDATA #IMPLIED>
+	<!ATTLIST sql-query timeout CDATA #IMPLIED>
+	<!ATTLIST sql-query cache-mode (get|ignore|normal|put|refresh) #IMPLIED>
+    <!ATTLIST sql-query read-only (true|false) #IMPLIED>
+    <!ATTLIST sql-query comment CDATA #IMPLIED>
+	<!ATTLIST sql-query callable (true|false) "false">
+
+<!-- The query-param element is used only by tools that generate
+finder methods for named queries -->
+
+<!ELEMENT query-param EMPTY>
+	<!ATTLIST query-param name CDATA #REQUIRED>
+	<!ATTLIST query-param type CDATA #REQUIRED>
+
+<!-- The resultset element declares a named resultset mapping definition for SQL queries -->
+<!ELEMENT resultset (return-scalar|return|return-join|load-collection)*>
+	<!ATTLIST resultset name CDATA #REQUIRED>
+
+<!--
+	Defines a return component for a sql-query.  Alias refers to the alias
+	used in the actual sql query; lock-mode specifies the locking to be applied
+	when the query is executed.  The class, collection, and role attributes are mutually exclusive;
+	class refers to the class name of a "root entity" in the object result; collection refers
+	to a collection of a given class and is used to define custom sql to load that owned collection
+	and takes the form "ClassName.propertyName"; role refers to the property path for an eager fetch
+	and takes the form "owningAlias.propertyName"
+-->
+<!ELEMENT return (return-discriminator?,return-property)*>
+	<!ATTLIST return alias CDATA #IMPLIED>
+	<!ATTLIST return entity-name CDATA #IMPLIED>
+	<!ATTLIST return class CDATA #IMPLIED>
+	<!ATTLIST return lock-mode (none|read|upgrade|upgrade-nowait|write) "read">	
+
+<!ELEMENT return-property (return-column*)> 
+	<!ATTLIST return-property name CDATA #REQUIRED>
+	<!ATTLIST return-property column CDATA #IMPLIED>
+
+<!ELEMENT return-column EMPTY> 
+	<!ATTLIST return-column name CDATA #REQUIRED>
+
+<!ELEMENT return-discriminator EMPTY> 
+	<!ATTLIST return-discriminator column CDATA #REQUIRED>
+	
+<!ELEMENT return-join (return-property)*> 
+	<!ATTLIST return-join alias CDATA #REQUIRED>
+	<!ATTLIST return-join property CDATA #REQUIRED>
+	<!ATTLIST return-join lock-mode (none|read|upgrade|upgrade-nowait|write) "read">
+
+<!ELEMENT load-collection (return-property)*> 
+	<!ATTLIST load-collection alias CDATA #REQUIRED>
+	<!ATTLIST load-collection role CDATA #REQUIRED>
+	<!ATTLIST load-collection lock-mode (none|read|upgrade|upgrade-nowait|write) "read">
+
+<!ELEMENT return-scalar EMPTY>
+	<!ATTLIST return-scalar column CDATA #REQUIRED>
+	<!ATTLIST return-scalar type CDATA #IMPLIED>
+
+<!ELEMENT synchronize EMPTY>
+	<!ATTLIST synchronize table CDATA #REQUIRED>
+	
+<!-- custom sql operations -->
+<!ELEMENT sql-insert (#PCDATA)>
+	<!ATTLIST sql-insert callable (true|false) "false">
+	<!ATTLIST sql-insert check (none|rowcount|param) #IMPLIED>
+
+<!ELEMENT sql-update (#PCDATA)>
+	<!ATTLIST sql-update callable (true|false) "false">
+	<!ATTLIST sql-update check (none|rowcount|param) #IMPLIED>
+
+<!ELEMENT sql-delete (#PCDATA)>
+	<!ATTLIST sql-delete callable (true|false) "false">
+	<!ATTLIST sql-delete check (none|rowcount|param) #IMPLIED>
+
+<!ELEMENT sql-delete-all (#PCDATA)>
+	<!ATTLIST sql-delete-all callable (true|false) "false">
+	<!ATTLIST sql-delete-all check (none|rowcount|param) #IMPLIED>
+
+<!--
+    Element for defining "auxiliary" database objects.  Must be one of two forms:
+
+    #1 :
+        <database-object>
+            <definition class="CustomClassExtendingAuxiliaryObject"/>
+        </database-object>
+
+    #2 :
+        <database-object>
+            <create>CREATE OR REPLACE ....</create>
+            <drop>DROP ....</drop>
+        </database-object>
+-->
+<!ELEMENT database-object ( (definition|(create,drop)), dialect-scope* )>
+
+<!ELEMENT definition EMPTY>
+    <!ATTLIST definition class CDATA #REQUIRED>
+
+<!ELEMENT create (#PCDATA)>
+<!ELEMENT drop (#PCDATA)>
+
+<!--
+    dialect-scope element allows scoping auxiliary-objects to a particular
+    Hibernate dialect implementation.
+-->
+<!ELEMENT dialect-scope (#PCDATA)>
+    <!ATTLIST dialect-scope name CDATA #REQUIRED>
+

Added: trunk/Hibernate3/documentation/manual/README
===================================================================
--- trunk/Hibernate3/documentation/manual/README	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/README	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,176 @@
+THE HIBERNATE DOCUMENTATION
+christian at hibernate.org
+
+COPYRIGHT NOTICE: This documentation system and all its source files are
+licensed under the GNU Lesser Public License (LGPL). Authors and translators
+retain the copyright of their work. All font and other build files (the DocBook
+system) are property of their respective copyright holders. Some of the files
+(especially font files) might require a license from the respective vendor; you
+are responsible to check and obtain these licenses as necessary before you use
+and/or distribute these files.
+
+
+Preface
+
+The Hibernate documentation is a modular documentation, it uses
+various XML files (written with the DocBook DTD) and a Java-based
+build process to generate HTML and PDF output. Use a simple text
+editor with XML support, such as JEdit, to edit the source files. You
+will need Java and Ant installed for the output generation. The toolset
+is Java only and should work on any operating system.
+
+Note: Always use 4 spaces to indent, no tabstops (code examples will
+be broken otherwise).
+
+
+1. How to get it
+
+Check out a copy of Hibernate from the repository. A regular
+Hibernate download will not contain the build process for the
+documentation, only the PDF/HTML output, use the repository!
+See http://www.hibernate.org/Download/DownloadOverview
+
+
+2. Working on the original language
+
+The original and master language is English, hence the "en" subdirectory
+in /doc/reference/ is authorative. We use "id" and "revision" attributes on
+XML elements to track changes. Here are the rules, they are mandatory:
+
+2a. Changing existing content involves an update of the "revision" of the XML
+element you are working on (e.g. a <sect1>, <sect2> or even a <para>).
+
+If a <sect1> has a revision="1", you update it to "2" after updating the
+content in that section.
+
+You can also add a revision attribute to an element if there is none,
+start with revision="1". You should not add a revision attribute to each
+paragraph, try to only add/use revision attributes to sections. You can'
+t add a revision attribute to elements without an "id" attribute!
+
+2b. Adding new content involves adding new elements (even new files), such
+as <sect1>, <para> and so on. Any new element (or its new parent element)
+needs an "id" attribute if the new content is to be included in the change
+tracking. If you add a section, give it a unique short text
+identifer, look at the parent element's identifier for the common prefix.
+
+2c. Deleting content involves removing old elements. Just remove them and
+make sure that the parent elements revision is updated, if the removed
+element did not itself have an identifer and a revision. If you remove an
+element with its own identifier, everything is fine and no other changes are
+necessary.
+
+
+3. Starting a new language
+
+If you start a translation for a new language, you have to copy
+the default language (English) and start an initial translation.
+
+3a. First, duplicate the default language "en" by duplicating the directory
+/doc/reference/en. For example, a new German translation
+will be a copy of that directory in /doc/reference/de. We use the ISO
+codes to name the language subdirectories.
+
+3b. You also have to add your new language to the language build file,
+/doc/reference/build.xml. Look for the lines that have a "TRANSLATOR"
+comment and duplicate them. Change the default "en" to your language
+code, every language listed here will be included in both the PDF/HTML
+generation and the revision diff change tracking reports (discussed later).
+
+
+4. The initial translation
+
+If you just copied the default language, start translating the DocBook
+XML modules and illustrations in the new language subdirectory. For
+example, all modules for German would be in /doc/reference/de/modules
+and all illustrations in /doc/reference/de/images, note that you also have
+to translate the master.xml in your language subdirectory.
+
+The initial translation is straightforward: Translate all modules and
+all illustrations, but don't add any files, don't add any new XML elements
+(like a section or a chapter, not even a paragraph). Simply translate
+sentence by sentence. This is very important.
+
+Note that every DocBook XML file needs an encoding, specific to a
+language. Add a line like this at the top of every file, if it doesn't exist:
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+You can use UTF-8 or any other character set, please experiment with
+the builds to see what works for you.
+
+If you need a new section or paragraph, because your translation requires
+more explanation, you can add it if you also add an "id" and a "revision"
+to that new section or paragraph.
+
+For example, if you add a new <para> element to the existing document,
+give it an identifier, a short unique string that extends the identifier
+string of the parent element: <para id="queryhql-projection-specialnote">
+would be a special paragraph in the <sect1 id="queryhql-projection">
+section in the chapter <chapter id="queryhql">.
+
+Never add a new element in a translated version without also adding a new
+unique identifier value! Also, you have to mark this new element as "only
+relevant in the translated version". Simply set the "revision" attribute of
+your new element to "-1". For example, set the previously created
+paragraph to "only relevant in the translation" by declaring
+<para id="queryhql-projection-specialnote" revision="-1">.
+Changes to that paragraph will not be tracked, it is your responsibility to
+watch out for neccessary updates. Any element with revision="-1" will not be
+tracked.
+
+
+5. Updating translated documentation
+
+Translators get updates by updating their working directory from the
+repository. As a translator you will get an e-mail from us when translation
+is required, you can then update your copy. Or, subscribe to the commit
+mailing list to get all updates automatically.
+
+The documentation tools can generate a report after you updated
+from the repository and show you what needs to be translated and/or removed
+in your local translation copy. To generate that report, run "ant all.revdiff"
+in the doc/reference/ subdirectory. Click on the generated HTML report
+file for your language and you will see what has to be updated and/or
+removed.
+
+If the report indicates that content in the original has been removed,
+simply remove the identified XML element from your language modules.
+
+If the report detects a new revision, open the file that has been updated
+in your translation, find the identified XML element and update/translate
+its contents. Important: Make sure you also update the "revision"
+attribute of that XML element by setting it to the same version as in
+the original file, hence both the original XML file and your translated
+file should have the same revision number for all elements. If an
+XML element in your translation doesn't have a revision, but the original
+file has, add a new "revision" attribute to your XML element.
+The HTML report shows the identifiers and revisions for both the original
+and the translated files, use it to compare.
+
+Rerun the "ant all.revdiff" report generation as often as you like until
+no more differences are detected. You should always try to get your
+copy clean, with all updated revisions and all identified elements
+synchronzied.
+
+
+6. Committing a translation
+
+All translators will be asked to submit their translated versions from
+time to time. This will be a manual process, you will get an e-mail from
+the Hibernate team and simply send your language subdirectory as
+a ZIP file to us. It will then be integrated in the main Hibernate
+distribution and on the website. Or, you can contact us for commit access
+to the repository, where you can maintain a translation directly.
+
+
+7. Generating PDF and HTML output
+
+The documentation is generated with the target 'ant all.doc'.
+
+To build the reference docs for a particular language only, use
+"ant -Dlang=en", for example, and call either lang.all, lang.docpdf,
+lang.dochtml, or lang.dochtmlsingle for the target of your choice.
+
+You can also call lang.section-check to track down missing identifiers in
+a particular language, or you can call lang.revdiff to get a difference
+report for a particular language, compared with the English reference.

Added: trunk/Hibernate3/documentation/manual/en-US/pom.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-manual</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>hibernate-manual-${translation}</artifactId>
+    <packaging>pom</packaging>
+    <name>Hibernate Manual (${translation})</name>
+
+    <properties>
+        <translation>en-US</translation>
+    </properties>
+
+</project>

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/master.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/master.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/master.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,183 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
+                      "../support/docbook-dtd/docbookx.dtd"
+[
+<!ENTITY tutorial               SYSTEM "modules/tutorial.xml">
+<!ENTITY architecture           SYSTEM "modules/architecture.xml">
+<!ENTITY configuration          SYSTEM "modules/configuration.xml">
+<!ENTITY persistent-classes     SYSTEM "modules/persistent_classes.xml">
+<!ENTITY basic-mapping          SYSTEM "modules/basic_mapping.xml">
+<!ENTITY collection-mapping     SYSTEM "modules/collection_mapping.xml">
+<!ENTITY association-mapping    SYSTEM "modules/association_mapping.xml">
+<!ENTITY component-mapping      SYSTEM "modules/component_mapping.xml">
+<!ENTITY inheritance-mapping    SYSTEM "modules/inheritance_mapping.xml">
+<!ENTITY session-api            SYSTEM "modules/session_api.xml">
+<!ENTITY transactions           SYSTEM "modules/transactions.xml">
+<!ENTITY events                 SYSTEM "modules/events.xml">
+<!ENTITY batch                  SYSTEM "modules/batch.xml">
+<!ENTITY query-hql              SYSTEM "modules/query_hql.xml">
+<!ENTITY query-criteria         SYSTEM "modules/query_criteria.xml">
+<!ENTITY query-sql              SYSTEM "modules/query_sql.xml">
+<!ENTITY filters                SYSTEM "modules/filters.xml">
+<!ENTITY xml                    SYSTEM "modules/xml.xml">
+<!ENTITY performance            SYSTEM "modules/performance.xml">
+<!ENTITY toolset-guide          SYSTEM "modules/toolset_guide.xml">
+<!ENTITY example-parentchild    SYSTEM "modules/example_parentchild.xml">
+<!ENTITY example-weblog         SYSTEM "modules/example_weblog.xml">
+<!ENTITY example-mappings       SYSTEM "modules/example_mappings.xml">
+<!ENTITY best-practices         SYSTEM "modules/best_practices.xml">
+]>
+
+<book lang="en">
+
+    <bookinfo>
+        <title>HIBERNATE - Relational Persistence for Idiomatic Java</title>
+        <subtitle>Hibernate Reference Documentation</subtitle>
+        <releaseinfo>3.2 cr3</releaseinfo>
+    </bookinfo>
+
+    <toc/>
+
+    <preface id="preface" revision="2">
+        <title>Preface</title>
+
+        <para>
+            Working with object-oriented software and a relational database can be cumbersome
+            and time consuming in today's enterprise environments. Hibernate is an object/relational
+            mapping tool for Java environments. The term object/relational mapping (ORM) refers to
+            the technique of mapping a data representation from an object model to a relational
+            data model with a SQL-based schema.
+        </para>
+
+        <para>
+            Hibernate not only takes care of the mapping from Java classes to
+            database tables (and from Java data types to SQL data types), but also provides data
+            query and retrieval facilities and can significantly reduce development time otherwise
+            spent with manual data handling in SQL and JDBC.
+        </para>
+
+        <para>
+            Hibernates goal is to relieve the developer from 95 percent of common data persistence
+            related programming tasks. Hibernate may not be the best solution for data-centric
+            applications that only use stored-procedures to implement the business logic in the
+            database, it is most useful with object-oriented domain models and business logic in
+            the Java-based middle-tier. However, Hibernate can certainly help you to remove or
+            encapsulate vendor-specific SQL code and will help with the common task of result set
+            translation from a tabular representation to a graph of objects.
+        </para>
+
+        <para>
+            If you are new to Hibernate and Object/Relational Mapping or even Java,
+            please follow these steps:
+        </para>
+
+        <orderedlist>
+            <listitem>
+                <para>
+                    Read <xref linkend="tutorial"/> for a tutorial with step-by-step
+                    instructions. The source code for the tutorial is included in the
+                    distribution in the <literal>doc/reference/tutorial/</literal>
+                    directory.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Read <xref linkend="architecture"/> to understand the environments where
+                    Hibernate can be used.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Have a look at the <literal>eg/</literal> directory in the Hibernate
+                    distribution, it contains a simple standalone application. Copy your
+                    JDBC driver to the <literal>lib/</literal> directory and edit
+                    <literal>etc/hibernate.properties</literal>, specifying correct values for
+                    your database. From a command prompt in the distribution directory,
+                    type <literal>ant eg</literal> (using Ant), or under Windows, type
+                    <literal>build eg</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Use this reference documentation as your primary source of information.
+                    Consider reading <emphasis>Hibernate in Action</emphasis>
+                    (http://www.manning.com/bauer) if you need more help with application
+                    design or if you prefer a step-by-step tutorial. Also visit
+                    http://caveatemptor.hibernate.org and download the example application
+                    for Hibernate in Action.
+                </para>
+            </listitem>
+            <listitem>
+				<para>
+					FAQs are answered on the Hibernate website.
+				</para>
+            </listitem>
+			<listitem>
+				<para>
+					Third party demos, examples, and tutorials are linked on the Hibernate
+					website.
+				</para>
+			</listitem>
+            <listitem>
+                <para>
+                    The Community Area on the Hibernate website is a good resource for
+                    design patterns and various integration solutions (Tomcat, JBoss AS,
+                    Struts, EJB, etc.).
+                </para>
+            </listitem>
+         </orderedlist>
+
+         <para>
+             If you have questions, use the user forum linked on the Hibernate website. We also
+             provide a JIRA issue trackings system for bug reports and feature requests. If you
+             are interested in the development of Hibernate, join the developer mailing list. If
+             you are interested in translating this documentation into your language, contact us
+             on the developer mailing list.
+         </para>
+
+         <para>
+             Commercial development support, production support, and training for Hibernate is
+             available through JBoss Inc. (see http://www.hibernate.org/SupportTraining/).
+             Hibernate is a Professional Open Source project and a critical component of the
+             JBoss Enterprise Middleware System (JEMS) suite of products.
+         </para>
+
+    </preface>
+
+    &tutorial;
+
+    &architecture;
+
+    &configuration;
+
+    &persistent-classes;
+
+    &basic-mapping;
+    &collection-mapping;
+    &association-mapping;
+    &component-mapping;
+    &inheritance-mapping;
+
+    &session-api;
+    &transactions;
+    &events;
+    &batch;
+
+    &query-hql;
+    &query-criteria;
+    &query-sql;
+    &filters;
+    &xml;
+
+    &performance;
+
+    &toolset-guide;
+
+    &example-parentchild;
+    &example-weblog;
+    &example-mappings;
+
+    &best-practices;
+
+</book>
+

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/architecture.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/architecture.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/architecture.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,355 @@
+<chapter id="architecture">
+
+    <title>Architecture</title>
+
+    <sect1 id="architecture-overview" revision="1">
+        <title>Overview</title>
+        
+        <para>
+            A (very) high-level view of the Hibernate architecture:
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/overview.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/overview.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            This diagram shows Hibernate using the database and configuration data to
+            provide persistence services (and persistent objects) to the application.
+        </para>
+
+        <para>
+            We would like to show a more detailed view of the runtime architecture.
+            Unfortunately, Hibernate is flexible and supports several approaches. We will
+            show the two extremes. The "lite" architecture has the application
+            provide its own JDBC connections and manage its own transactions. This approach
+            uses a minimal subset of Hibernate's APIs:
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/lite.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/lite.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            The "full cream" architecture abstracts the application away from the
+            underlying JDBC/JTA APIs and lets Hibernate take care of the details.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/full_cream.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/full_cream.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            Heres some definitions of the objects in the diagrams:
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
+                    <listitem>
+                        <para>
+                            A threadsafe (immutable) cache of compiled mappings for a single database.
+                            A factory for <literal>Session</literal> and a client of
+                            <literal>ConnectionProvider</literal>. Might hold an optional (second-level)
+                            cache of data that is reusable between transactions, at a
+                            process- or cluster-level.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Session (<literal>org.hibernate.Session</literal>)</term>
+                    <listitem>
+                        <para>
+                            A single-threaded, short-lived object representing a conversation between
+                            the application and the persistent store. Wraps a JDBC connection. Factory
+                            for <literal>Transaction</literal>. Holds a mandatory (first-level) cache
+                            of persistent objects, used when navigating the object graph or looking up
+                            objects by identifier.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Persistent objects and collections</term>
+                    <listitem>
+                        <para>
+                            Short-lived, single threaded objects containing persistent state and business
+                            function. These might be ordinary JavaBeans/POJOs, the only special thing about
+                            them is that they are currently associated with (exactly one)
+                            <literal>Session</literal>. As soon as the <literal>Session</literal> is closed,
+                            they will be detached and free to use in any application layer (e.g. directly
+                            as data transfer objects to and from presentation).
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Transient and detached objects and collections</term>
+                    <listitem>
+                        <para>
+                            Instances of persistent classes that are not currently associated with a
+                            <literal>Session</literal>. They may have been instantiated by
+                            the application and not (yet) persisted or they may have been instantiated by a
+                            closed <literal>Session</literal>.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
+                    <listitem>
+                        <para>
+                            (Optional) A single-threaded, short-lived object used by the application to
+                            specify atomic units of work. Abstracts application from underlying JDBC,
+                            JTA or CORBA transaction. A <literal>Session</literal> might span several
+                            <literal>Transaction</literal>s in some cases. However, transaction demarcation,
+                            either using the underlying API or <literal>Transaction</literal>, is never
+                            optional!
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
+                    <listitem>
+                        <para>
+                            (Optional) A factory for (and pool of) JDBC connections. Abstracts application from
+                            underlying <literal>Datasource</literal> or <literal>DriverManager</literal>.
+                            Not exposed to application, but can be extended/implemented by the developer.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
+                    <listitem>
+                        <para>
+                            (Optional) A factory for <literal>Transaction</literal> instances. Not exposed to the
+                            application, but can be extended/implemented by the developer.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><emphasis>Extension Interfaces</emphasis></term>
+                    <listitem>
+                        <para>
+                            Hibernate offers many optional extension interfaces you can implement to customize
+                            the behavior of your persistence layer. See the API documentation for details.
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+        </para>
+
+        <para>
+            Given a "lite" architecture, the application bypasses the
+            <literal>Transaction</literal>/<literal>TransactionFactory</literal> and/or
+            <literal>ConnectionProvider</literal> APIs to talk to JTA or JDBC directly.
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-states" revision="1">
+        <title>Instance states</title>
+        <para>
+            An instance of a persistent classes may be in one of three different states,
+            which are defined with respect to a <emphasis>persistence context</emphasis>.
+            The Hibernate <literal>Session</literal> object is the persistence context:
+        </para>
+        
+       <variablelist spacing="compact">
+            <varlistentry>
+                <term>transient</term>
+                <listitem>
+                    <para>
+                        The instance is not, and has never been associated with
+                        any persistence context. It has no persistent identity
+                        (primary key value).
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>persistent</term>
+                <listitem>
+                    <para>
+                        The instance is currently associated with a persistence 
+                        context. It has a persistent identity (primary key value)
+                        and, perhaps, a corresponding row in the database. For a
+                        particular persistence context, Hibernate 
+                        <emphasis>guarantees</emphasis> that persistent identity
+                        is equivalent to Java identity (in-memory location of the
+                        object).
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>detached</term>
+                <listitem>
+                    <para>
+                        The instance was once associated with a persistence
+                        context, but that context was closed, or the instance
+                        was serialized to another process. It has a persistent 
+                        identity and, perhaps, a corrsponding row in the database.
+                        For detached instances, Hibernate makes no guarantees 
+                        about the relationship between persistent identity and
+                        Java identity.
+                    </para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </sect1>    
+
+    <sect1 id="architecture-jmx" revision="1">
+        <title>JMX Integration</title>
+
+        <para>
+            JMX is the J2EE standard for management of Java components. Hibernate may be managed via
+            a JMX standard service. We provide an MBean implementation in the distribution,
+            <literal>org.hibernate.jmx.HibernateService</literal>.
+        </para>
+
+        <para>
+            For an example how to deploy Hibernate as a JMX service on the JBoss Application Server,
+            please see the JBoss User Guide. On JBoss AS, you also get these benefits if you deploy
+            using JMX:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>Session Management:</emphasis> The Hibernate <literal>Session</literal>'s lifecycle
+                    can be automatically bound to the scope of a JTA transaction. This means you no
+                    longer have to manually open and close the <literal>Session</literal>, this
+                    becomes the job of a JBoss EJB interceptor. You also don't have to worry about
+                    transaction demarcation in your code anymore (unless you'd like to write a portable
+                    persistence layer of course, use the optional Hibernate <literal>Transaction</literal>
+                    API for this). You call the <literal>HibernateContext</literal> to access a
+                    <literal>Session</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>HAR deployment:</emphasis> Usually you deploy the Hibernate JMX service using a JBoss
+                    service deployment descriptor (in an EAR and/or SAR file), it supports all the usual
+                    configuration options of a Hibernate <literal>SessionFactory</literal>. However, you still
+                    have to name all your mapping files in the deployment descriptor. If you decide to use
+                    the optional HAR deployment, JBoss will automatically detect all mapping files in your
+                    HAR file.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Consult the JBoss AS user guide for more information about these options.
+        </para>
+
+        <para>
+            Another feature available as a JMX service are runtime Hibernate statistics. See
+            <xref linkend="configuration-optional-statistics"/>.
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-jca" revision="1">
+        <title>JCA Support</title>
+        <para>
+            Hibernate may also be configured as a JCA connector. Please see the website for more
+            details. Please note that Hibernate JCA support is still considered experimental.
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-current-session" revision="2">
+        <title>Contextual Sessions</title>
+        <para>
+            Most applications using Hibernate need some form of "contextual" sessions, where a given
+            session is in effect throughout the scope of a given context. However, across applications
+            the definition of what constitutes a context is typically different; and different contexts
+            define different scopes to the notion of current. Applications using Hibernate prior
+            to version 3.0 tended to utilize either home-grown <literal>ThreadLocal</literal>-based
+            contextual sessions, helper classes such as <literal>HibernateUtil</literal>, or utilized
+            third-party frameworks (such as Spring or Pico) which provided proxy/interception-based contextual sessions.
+        </para>
+        <para>
+            Starting with version 3.0.1, Hibernate added the <literal>SessionFactory.getCurrentSession()</literal>
+            method.  Initially, this assumed usage of <literal>JTA</literal> transactions, where the
+            <literal>JTA</literal> transaction defined both the scope and context of a current session.
+            The Hibernate team maintains that, given the maturity of the numerous stand-alone
+            <literal>JTA TransactionManager</literal> implementations out there, most (if not all)
+            applications should be using <literal>JTA</literal> transaction management whether or not
+            they are deployed into a <literal>J2EE</literal> container.  Based on that, the
+            <literal>JTA</literal>-based contextual sessions is all you should ever need to use.
+        </para>
+        <para>
+            However, as of version 3.1, the processing behind
+            <literal>SessionFactory.getCurrentSession()</literal> is now pluggable.  To that
+            end, a new extension interface (<literal>org.hibernate.context.CurrentSessionContext</literal>)
+            and a new configuration parameter (<literal>hibernate.current_session_context_class</literal>)
+            have been added to allow pluggability of the scope and context of defining current sessions.
+        </para>
+        <para>
+            See the Javadocs for the <literal>org.hibernate.context.CurrentSessionContext</literal>
+            interface for a detailed discussion of its contract.  It defines a single method,
+            <literal>currentSession()</literal>, by which the implementation is responsible for
+            tracking the current contextual session.  Out-of-the-box, Hibernate comes with three
+            implementations of this interface.
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.context.JTASessionContext</literal> - current sessions
+                    are tracked and scoped by a <literal>JTA</literal> transaction.  The processing
+                    here is exactly the same as in the older JTA-only approach.  See the Javadocs
+                    for details.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.context.ThreadLocalSessionContext</literal> - current
+                    sessions are tracked by thread of execution. Again, see the Javadocs for details.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.context.ManagedSessionContext</literal> - current
+                    sessions are tracked by thread of execution. However, you are responsible to
+                    bind and unbind a <literal>Session</literal> instance with static methods
+                    on this class, it does never open, flush, or close a <literal>Session</literal>.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            The first two implementations provide a "one session - one database transaction" programming
+            model, also known and used as <emphasis>session-per-request</emphasis>. The beginning
+            and end of a Hibernate session is defined by the duration of a database transaction.
+            If you use programatic transaction demarcation in plain JSE without JTA, you are adviced to
+            use the Hibernate <literal>Transaction</literal> API to hide the underlying transaction system
+            from your code. If you use JTA, use the JTA interfaces to demarcate transactions. If you
+            execute in an EJB container that supports CMT, transaction boundaries are defined declaratively
+            and you don't need any transaction or session demarcation operations in your code.
+            Refer to <xref linkend="transactions"/> for more information and code examples.
+        </para>
+
+        <para>
+            The <literal>hibernate.current_session_context_class</literal> configuration parameter
+            defines which <literal>org.hibernate.context.CurrentSessionContext</literal> implementation
+            should be used.  Note that for backwards compatibility, if this config param is not set
+            but a <literal>org.hibernate.transaction.TransactionManagerLookup</literal> is configured,
+            Hibernate will use the <literal>org.hibernate.context.JTASessionContext</literal>.
+            Typically, the value of this parameter would just name the implementation class to
+            use; for the three out-of-the-box implementations, however, there are two corresponding
+            short names, "jta", "thread", and "managed".
+        </para>
+        
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/association_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/association_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/association_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,623 @@
+<chapter id="associations">
+
+    <title>Association Mappings</title>
+
+    <sect1 id="assoc-intro" revision="1">
+        <title>Introduction</title>
+        
+        <para>
+            Association mappings are the often most difficult thing to get right. In
+            this section we'll go through the canonical cases one by one, starting
+            with unidirectional mappings, and then considering the bidirectional cases.
+            We'll use <literal>Person</literal> and <literal>Address</literal> in all
+            the examples.
+        </para>
+        
+        <para>
+        	We'll classify associations by whether or not they map to an intervening
+        	join table, and by multiplicity.
+        </para>
+        
+        <para>
+        	Nullable foreign keys are not considered good practice in traditional data
+        	modelling, so all our examples use not null foreign keys. This is not a
+        	requirement of Hibernate, and the mappings will all work if you drop the
+        	nullability constraints.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="assoc-unidirectional" revision="1">
+        <title>Unidirectional associations</title>
+        
+        <sect2 id="assoc-unidirectional-m21">
+        <title>many to one</title>
+        
+        <para>
+            A <emphasis>unidirectional many-to-one association</emphasis> is the most 
+            common kind of unidirectional association.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-121">
+        <title>one to one</title>
+        
+        <para>
+            A <emphasis>unidirectional one-to-one association on a foreign key</emphasis>
+            is almost identical. The only difference is the column unique constraint.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId" 
+        unique="true"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        <para>
+            A <emphasis>unidirectional one-to-one association on a primary key</emphasis>
+            usually uses a special id generator. (Notice that we've reversed the direction
+            of the association in this example.)
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+</class>
+
+<class name="Address">
+    <id name="id" column="personId">
+        <generator class="foreign">
+            <param name="property">person</param>
+        </generator>
+    </id>
+    <one-to-one name="person" constrained="true"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+        <sect2 id="assoc-unidirectional-12m">
+        <title>one to many</title>
+        
+        <para>
+            A <emphasis>unidirectional one-to-many association on a foreign key</emphasis> 
+            is a very unusual case, and is not really recommended.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses">
+        <key column="personId" 
+            not-null="true"/>
+        <one-to-many class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( addressId bigint not null primary key, personId bigint not null )
+        ]]></programlisting>
+        
+        <para>
+            We think it's better to use a join table for this kind of association.
+        </para>
+        
+        </sect2>
+    
+    </sect1>
+
+    <sect1 id="assoc-unidirectional-join" revision="1">
+        <title>Unidirectional associations with join tables</title>
+        
+        <sect2 id="assoc-unidirectional-join-12m">
+        <title>one to many</title>
+        
+        <para>
+            A <emphasis>unidirectional one-to-many association on a join table</emphasis> 
+            is much preferred. Notice that by specifying <literal>unique="true"</literal>,
+            we have changed the multiplicity from many-to-many to one-to-many.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            unique="true"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-m21">
+        <title>many to one</title>
+        
+        <para>
+            A <emphasis>unidirectional many-to-one association on a join table</emphasis> 
+            is quite common when the association is optional.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-121">
+        <title>one to one</title>
+        
+        <para>
+            A <emphasis>unidirectional one-to-one association on a join table</emphasis> 
+            is extremely unusual, but possible.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-m2m">
+        <title>many to many</title>
+        
+        <para>
+            Finally, we have a <emphasis>unidirectional many-to-many association</emphasis>.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="assoc-bidirectional" revision="1">
+        <title>Bidirectional associations</title>
+        
+        <sect2 id="assoc-bidirectional-m21" revision="2">
+        <title>one to many / many to one</title>
+        
+        <para>
+            A <emphasis>bidirectional many-to-one association</emphasis> is the
+            most common kind of association. (This is the standard parent/child
+            relationship.)
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <set name="people" inverse="true">
+        <key column="addressId"/>
+        <one-to-many class="Person"/>
+    </set>
+</class>]]></programlisting>
+
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+
+        <para>
+            If you use a <literal>List</literal> (or other indexed collection) you need
+            to set the <literal>key</literal> column of the foreign key to <literal>not null</literal>,
+            and let Hibernate manage the association from the collections side to maintain the index
+            of each element (making the other side virtually inverse by setting
+            <literal>update="false"</literal> and <literal>insert="false"</literal>):
+        </para>
+
+        <programlisting><![CDATA[<class name="Person">
+   <id name="id"/>
+   ...
+   <many-to-one name="address"
+      column="addressId"
+      not-null="true"
+      insert="false"
+      update="false"/>
+</class>
+
+<class name="Address">
+   <id name="id"/>
+   ...
+   <list name="people">
+      <key column="addressId" not-null="true"/>
+      <list-index column="peopleIdx"/>
+      <one-to-many class="Person"/>
+   </list>
+</class>]]></programlisting>
+
+            <para>
+                It is important that you define <literal>not-null="true"</literal> on the
+                <literal>&lt;key&gt;</literal> element of the collection mapping if the
+                underlying foreign key column is <literal>NOT NULL</literal>. Don't only
+                declare <literal>not-null="true"</literal> on a possible nested
+                <literal>&lt;column&gt;</literal> element, but on the <literal>&lt;key&gt;</literal>
+                element.
+            </para>
+
+        </sect2>
+        
+        <sect2 id="assoc-bidirectional-121">
+        <title>one to one</title>
+        
+        <para>
+            A <emphasis>bidirectional one-to-one association on a foreign key</emphasis>
+            is quite common.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId" 
+        unique="true"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+   <one-to-one name="person" 
+        property-ref="address"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        <para>
+            A <emphasis>bidirectional one-to-one association on a primary key</emphasis>
+            uses the special id generator.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <one-to-one name="address"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="personId">
+        <generator class="foreign">
+            <param name="property">person</param>
+        </generator>
+    </id>
+    <one-to-one name="person" 
+        constrained="true"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="assoc-bidirectional-join" revision="1">
+        <title>Bidirectional associations with join tables</title>
+        
+        <sect2 id="assoc-bidirectional-join-12m">
+        <title>one to many / many to one</title>
+        
+        <para>
+            A <emphasis>bidirectional one-to-many association on a join table</emphasis>.
+            Note that the <literal>inverse="true"</literal> can go on either end of the
+            association, on the collection, or on the join.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" 
+        table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            unique="true"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        inverse="true" 
+        optional="true">
+        <key column="addressId"/>
+        <many-to-one name="person"
+            column="personId"
+            not-null="true"/>
+    </join>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+         <sect2 id="assoc-bidirectional-join-121">
+        <title>one to one</title>
+        
+        <para>
+            A <emphasis>bidirectional one-to-one association on a join table</emphasis> 
+            is extremely unusual, but possible.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true"
+        inverse="true">
+        <key column="addressId" 
+            unique="true"/>
+        <many-to-one name="person"
+            column="personId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+
+        </sect2>
+        
+        <sect2 id="assoc-bidirectional-join-m2m" revision="1">
+        <title>many to many</title>
+        
+        <para>
+            Finally, we have a <emphasis>bidirectional many-to-many association</emphasis>.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <set name="people" inverse="true" table="PersonAddress">
+        <key column="addressId"/>
+        <many-to-many column="personId"
+            class="Person"/>
+    </set>
+</class>]]></programlisting>
+
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+    </sect1>
+    
+    <sect1 id="assoc-complex">
+        <title>More complex association mappings</title>
+        
+        <para>
+            More complex association joins are <emphasis>extremely</emphasis> rare. 
+            Hibernate makes it possible to handle more complex situations using
+            SQL fragments embedded in the mapping document. For example, if a table
+            with historical account information data defines 
+            <literal>accountNumber</literal>, <literal>effectiveEndDate</literal> 
+            and <literal>effectiveStartDate</literal>columns, mapped as follows:
+        </para>
+        
+        <programlisting><![CDATA[<properties name="currentAccountKey">
+    <property name="accountNumber" type="string" not-null="true"/>
+    <property name="currentAccount" type="boolean">
+        <formula>case when effectiveEndDate is null then 1 else 0 end</formula>
+    </property>
+</properties>
+<property name="effectiveEndDate" type="date"/>
+<property name="effectiveStateDate" type="date" not-null="true"/>]]></programlisting>
+
+        <para>
+            Then we can map an association to the <emphasis>current</emphasis> instance 
+            (the one with null <literal>effectiveEndDate</literal>) using:
+        </para>
+        
+        <programlisting><![CDATA[<many-to-one name="currentAccountInfo" 
+        property-ref="currentAccountKey"
+        class="AccountInfo">
+    <column name="accountNumber"/>
+    <formula>'1'</formula>
+</many-to-one>]]></programlisting>
+
+        <para>
+            In a more complex example, imagine that the association between 
+            <literal>Employee</literal> and <literal>Organization</literal> is maintained
+            in an <literal>Employment</literal> table full of historical employment data.
+            Then an association to the employee's <emphasis>most recent</emphasis> employer
+            (the one with the most recent <literal>startDate</literal>) might be mapped this way:
+        </para>
+        
+        <programlisting><![CDATA[<join>
+    <key column="employeeId"/>
+    <subselect>
+        select employeeId, orgId 
+        from Employments 
+        group by orgId 
+        having startDate = max(startDate)
+    </subselect>
+    <many-to-one name="mostRecentEmployer" 
+            class="Organization" 
+            column="orgId"/>
+</join>]]></programlisting>
+
+        <para>
+            You can get quite creative with this functionality, but it is usually more practical 
+            to handle these kinds of cases using HQL or a criteria query.
+        </para>
+
+    </sect1>
+
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/association_mapping.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/basic_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/basic_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/basic_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,3560 @@
+<chapter id="mapping">
+    <title>Basic O/R Mapping</title>
+
+    <sect1 id="mapping-declaration" revision="2">
+        <title>Mapping declaration</title>
+
+        <para>
+            Object/relational mappings are usually defined in an XML document. The mapping
+            document is designed to be readable and hand-editable. The mapping language is
+            Java-centric, meaning that mappings are constructed around persistent class
+            declarations, not table declarations.
+        </para>
+
+        <para>
+            Note that, even though many Hibernate users choose to write the XML by hand,
+            a number of tools exist to generate the mapping document, including XDoclet,
+            Middlegen and AndroMDA.
+        </para>
+
+        <para>
+            Lets kick off with an example mapping:
+        </para>
+
+        <programlisting id="mapping-declaration-ex1" revision="1"><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+        <class name="Cat"
+            table="cats"
+            discriminator-value="C">
+
+                <id name="id">
+                        <generator class="native"/>
+                </id>
+
+                <discriminator column="subclass"
+                     type="character"/>
+
+                <property name="weight"/>
+
+                <property name="birthdate"
+                    type="date"
+                    not-null="true"
+                    update="false"/>
+
+                <property name="color"
+                    type="eg.types.ColorUserType"
+                    not-null="true"
+                    update="false"/>
+
+                <property name="sex"
+                    not-null="true"
+                    update="false"/>
+
+                <property name="litterId"
+                    column="litterId"
+                    update="false"/>
+
+                <many-to-one name="mother"
+                    column="mother_id"
+                    update="false"/>
+
+                <set name="kittens"
+                    inverse="true"
+                    order-by="litter_id">
+                        <key column="mother_id"/>
+                        <one-to-many class="Cat"/>
+                </set>
+
+                <subclass name="DomesticCat"
+                    discriminator-value="D">
+
+                        <property name="name"
+                            type="string"/>
+
+                </subclass>
+
+        </class>
+
+        <class name="Dog">
+                <!-- mapping for Dog could go here -->
+        </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+             We will now discuss the content of the mapping document. We will only describe the
+             document elements and attributes that are used by Hibernate at runtime. The mapping
+             document also contains some extra optional attributes and elements that affect the
+             database schemas exported by the schema export tool. (For example the <literal>
+             not-null</literal> attribute.)
+        </para>
+
+
+
+        <sect2 id="mapping-declaration-doctype" revision="3">
+            <title>Doctype</title>
+
+            <para>
+                All XML mappings should declare the doctype shown. The actual DTD may be found
+                at the URL above, in the directory <literal>hibernate-x.x.x/src/org/hibernate
+                </literal> or in <literal>hibernate3.jar</literal>. Hibernate will always look for
+                the DTD in its classpath first. If you experience lookups of the DTD using an
+                Internet connection, check your DTD declaration against the contents of your
+                claspath.
+            </para>
+
+            <sect3 id="mapping-declaration-entity-resolution">
+                <title>EntityResolver</title>
+                <para>
+                    As mentioned previously, Hibernate will first attempt to resolve DTDs in its classpath.  The
+                    manner in which it does this is by registering a custom <literal>org.xml.sax.EntityResolver</literal>
+                    implementation with the SAXReader it uses to read in the xml files.  This custom
+                    <literal>EntityResolver</literal> recognizes two different systemId namespaces.
+                </para>
+                <itemizedlist>
+                    <listitem>
+                        <para>
+                            a <literal>hibernate namespace</literal> is recognized whenever the
+                            resolver encounteres a systemId starting with
+                            <literal>http://hibernate.sourceforge.net/</literal>; the resolver
+                            attempts to resolve these entities via the classlaoder which loaded
+                            the Hibernate classes.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            a <literal>user namespace</literal> is recognized whenever the
+                            resolver encounteres a systemId using a <literal>classpath://</literal>
+                            URL protocol; the resolver will attempt to resolve these entities
+                            via (1) the current thread context classloader and (2) the
+                            classloader which loaded the Hibernate classes.
+                        </para>
+                    </listitem>
+                </itemizedlist>
+                <para>
+                    An example of utilizing user namespacing:
+                </para>
+                <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [
+    <!ENTITY types SYSTEM "classpath://your/domain/types.xml">
+]>
+
+<hibernate-mapping package="your.domain">
+    <class name="MyEntity">
+        <id name="id" type="my-custom-id-type">
+            ...
+        </id>
+    <class>
+    &types;
+</hibernate-mapping>]]></programlisting>
+                <para>
+                    Where <literal>types.xml</literal> is a resource in the <literal>your.domain</literal>
+                    package and contains a custom <xref linkend="mapping-types-custom">typedef</xref>.
+                </para>
+            </sect3>
+        </sect2>
+
+        <sect2 id="mapping-declaration-mapping" revision="3">
+            <title>hibernate-mapping</title>
+
+            <para>
+                This element has several optional attributes. The <literal>schema</literal> and
+                <literal>catalog</literal> attributes specify that tables referred to in this mapping
+                belong to the named schema and/or catalog. If specified, tablenames will be qualified
+                by the given schema and catalog names. If missing, tablenames will be unqualified.
+                The <literal>default-cascade</literal> attribute specifies what cascade style
+                should be assumed for properties and collections which do not specify a
+                <literal>cascade</literal> attribute. The <literal>auto-import</literal> attribute lets us
+                use unqualified class names in the query language, by default.
+            </para>
+
+             <programlistingco>
+                 <areaspec>
+                     <area id="hm1" coords="2 55"/>
+                     <area id="hm2" coords="3 55"/>
+                     <area id="hm3" coords="4 55"/>
+                     <area id="hm4" coords="5 55"/>
+                     <area id="hm5" coords="6 55"/>
+                     <area id="hm6" coords="7 55"/>
+                     <area id="hm7" coords="8 55"/>
+                 </areaspec>
+                 <programlisting><![CDATA[<hibernate-mapping
+         schema="schemaName"
+         catalog="catalogName"
+         default-cascade="cascade_style"
+         default-access="field|property|ClassName"
+         default-lazy="true|false"
+         auto-import="true|false"
+         package="package.name"
+ />]]></programlisting>
+                 <calloutlist>
+                     <callout arearefs="hm1">
+                         <para>
+                             <literal>schema</literal> (optional): The name of a database schema.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm2">
+                         <para>
+                             <literal>catalog</literal> (optional): The name of a database catalog.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm3">
+                         <para>
+                             <literal>default-cascade</literal> (optional - defaults to <literal>none</literal>):
+                             A default cascade style.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm4">
+                         <para>
+                             <literal>default-access</literal> (optional - defaults to <literal>property</literal>):
+                             The strategy Hibernate should use for accessing all properties. Can be a custom
+                             implementation of <literal>PropertyAccessor</literal>.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm5">
+                         <para>
+                             <literal>default-lazy</literal> (optional - defaults to <literal>true</literal>):
+                             The default value for unspecifed <literal>lazy</literal> attributes of class and
+                             collection mappings.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm6">
+                         <para>
+                             <literal>auto-import</literal> (optional - defaults to <literal>true</literal>):
+                             Specifies whether we can use unqualified class names (of classes in this mapping)
+                             in the query language.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm7">
+                         <para>
+                             <literal>package</literal> (optional): Specifies a package prefix to assume for
+                             unqualified class names in the mapping document.
+                         </para>
+                     </callout>
+                 </calloutlist>
+             </programlistingco>
+
+             <para>
+                 If you have two persistent classes with the same (unqualified) name, you should set
+                 <literal>auto-import="false"</literal>. Hibernate will throw an exception if you attempt
+                 to assign two classes to the same "imported" name.
+             </para>
+
+             <para>
+                 Note that the <literal>hibernate-mapping</literal> element allows you to nest
+                 several persistent <literal>&lt;class&gt;</literal> mappings, as shown above.
+                 It is however good practice (and expected by some tools) to map only a single
+                 persistent class (or a single class hierarchy) in one mapping file and name
+                 it after the persistent superclass, e.g. <literal>Cat.hbm.xml</literal>,
+                 <literal>Dog.hbm.xml</literal>, or if using inheritance,
+                 <literal>Animal.hbm.xml</literal>.
+             </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-class" revision="3">
+            <title>class</title>
+
+            <para>
+                You may declare a persistent class using the <literal>class</literal> element:
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="class1" coords="2 55"/>
+                    <area id="class2" coords="3 55" />
+                    <area id="class3" coords="4 55"/>
+                    <area id="class4" coords="5 55" />
+                    <area id="class5" coords="6 55"/>
+                    <area id="class6" coords="7 55" />
+                    <area id="class7" coords="8 55"/>
+                    <area id="class8" coords="9 55" />
+                    <area id="class9" coords="10 55" />
+                    <area id="class10" coords="11 55"/>
+                    <area id="class11" coords="12 55"/>
+                    <area id="class12" coords="13 55"/>
+                    <area id="class13" coords="14 55"/>
+                    <area id="class14" coords="15 55"/>
+                    <area id="class15" coords="16 55"/>
+                    <area id="class16" coords="17 55"/>
+                    <area id="class17" coords="18 55"/>
+                    <area id="class18" coords="19 55"/>
+                    <area id="class19" coords="20 55"/>
+                    <area id="class20" coords="21 55"/>
+                    <area id="class21" coords="22 55"/>
+                </areaspec>
+                <programlisting><![CDATA[<class
+        name="ClassName"
+        table="tableName"
+        discriminator-value="discriminator_value"
+        mutable="true|false"
+        schema="owner"
+        catalog="catalog"
+        proxy="ProxyInterface"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        select-before-update="true|false"
+        polymorphism="implicit|explicit"
+        where="arbitrary sql where condition"
+        persister="PersisterClass"
+        batch-size="N"
+        optimistic-lock="none|version|dirty|all"
+        lazy="true|false"
+        entity-name="EntityName"
+        check="arbitrary sql check condition"
+        rowid="rowid"
+        subselect="SQL expression"
+        abstract="true|false"
+        node="element-name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="class1">
+                        <para>
+                            <literal>name</literal> (optional): The fully qualified Java class name of the
+                            persistent class (or interface). If this attribute is missing, it is assumed
+                            that the mapping is for a non-POJO entity.
+                        </para>
+                    </callout>
+                    <callout arearefs="class2">
+                        <para>
+                            <literal>table</literal> (optional - defaults to the unqualified class name):  The
+                            name of its database table.
+                        </para>
+                    </callout>
+                    <callout arearefs="class3">
+                        <para>
+                            <literal>discriminator-value</literal> (optional - defaults to the class name): A value
+                            that distiguishes individual subclasses, used for polymorphic behaviour. Acceptable
+                            values include <literal>null</literal> and <literal>not null</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="class4">
+                        <para>
+                            <literal>mutable</literal> (optional, defaults to <literal>true</literal>): Specifies
+                            that instances of the class are (not) mutable.
+                        </para>
+                    </callout>
+                    <callout arearefs="class5">
+                        <para>
+                            <literal>schema</literal> (optional): Override the schema name specified by
+                            the root <literal>&lt;hibernate-mapping&gt;</literal> element.
+                        </para>
+                    </callout>
+                    <callout arearefs="class6">
+                        <para>
+                            <literal>catalog</literal> (optional): Override the catalog name specified by
+                            the root <literal>&lt;hibernate-mapping&gt;</literal> element.
+                        </para>
+                    </callout>
+                    <callout arearefs="class7">
+                        <para>
+                            <literal>proxy</literal> (optional): Specifies an interface to use for lazy
+                            initializing proxies. You may specify the name of the class itself.
+                        </para>
+                    </callout>
+                    <callout arearefs="class8">
+                        <para>
+                            <literal>dynamic-update</literal> (optional, defaults to <literal>false</literal>):
+                            Specifies that <literal>UPDATE</literal> SQL should be generated at runtime and
+                            contain only those columns whose values have changed.
+                        </para>
+                    </callout>
+                    <callout arearefs="class9">
+                        <para>
+                            <literal>dynamic-insert</literal> (optional, defaults to <literal>false</literal>):
+                            Specifies that <literal>INSERT</literal> SQL should be generated at runtime and
+                            contain only the columns whose values are not null.
+                        </para>
+                    </callout>
+                    <callout arearefs="class10">
+                        <para>
+                            <literal>select-before-update</literal> (optional, defaults to <literal>false</literal>):
+                            Specifies that Hibernate should <emphasis>never</emphasis> perform an SQL <literal>UPDATE</literal>
+                            unless it is certain that an object is actually modified. In certain cases (actually, only
+                            when a transient object has been associated with a new session using <literal>update()</literal>),
+                            this means that Hibernate will perform an extra SQL <literal>SELECT</literal> to determine
+                            if an <literal>UPDATE</literal> is actually required.
+                        </para>
+                    </callout>
+                    <callout arearefs="class11">
+                        <para>
+                            <literal>polymorphism</literal> (optional, defaults to <literal>implicit</literal>):
+                            Determines whether implicit or explicit query polymorphism is used.
+                        </para>
+                    </callout>
+                    <callout arearefs="class12">
+                        <para>
+                            <literal>where</literal> (optional) specify an arbitrary SQL <literal>WHERE</literal>
+                            condition to be used when retrieving objects of this class
+                        </para>
+                    </callout>
+                    <callout arearefs="class13">
+                        <para>
+                            <literal>persister</literal> (optional): Specifies a custom <literal>ClassPersister</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="class14">
+                        <para>
+                            <literal>batch-size</literal> (optional, defaults to <literal>1</literal>) specify a "batch size"
+                            for fetching instances of this class by identifier.
+                        </para>
+                    </callout>
+                   <callout arearefs="class15">
+                        <para>
+                            <literal>optimistic-lock</literal> (optional, defaults to <literal>version</literal>):
+                            Determines the optimistic locking strategy.
+                        </para>
+                    </callout>
+                    <callout arearefs="class16">
+                        <para>
+                            <literal>lazy</literal> (optional): Lazy fetching may be completely disabled by setting
+                            <literal>lazy="false"</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="class17">
+                        <para>
+                            <literal>entity-name</literal> (optional, defaults to the class name): Hibernate3
+                            allows a class to be mapped multiple times (to different tables, potentially),
+                            and allows entity mappings that are represented by Maps or XML at the Java level.
+                            In these cases, you should provide an explicit arbitrary name for the entity. See
+                            <xref linkend="persistent-classes-dynamicmodels"/> and <xref linkend="xml"/>
+                            for more information.
+                        </para>
+                    </callout>
+                    <callout arearefs="class18">
+                        <para>
+                            <literal>check</literal> (optional): A SQL expression used to generate a multi-row
+                            <emphasis>check</emphasis> constraint for automatic schema generation.
+                        </para>
+                    </callout>
+                    <callout arearefs="class19">
+                        <para>
+                            <literal>rowid</literal> (optional): Hibernate can use so called ROWIDs on databases
+                            which support. E.g. on Oracle, Hibernate can use the <literal>rowid</literal> extra
+                            column for fast updates if you set this option to <literal>rowid</literal>. A ROWID
+                            is an implementation detail and represents the physical location of a stored tuple.
+                        </para>
+                    </callout>
+                    <callout arearefs="class20">
+                        <para>
+                            <literal>subselect</literal> (optional): Maps an immutable and read-only entity
+                            to a database subselect. Useful if you want to have a view instead of a base table,
+                            but don't. See below for more information.
+                        </para>
+                    </callout>
+                    <callout arearefs="class21">
+                        <para>
+                            <literal>abstract</literal> (optional): Used to mark abstract superclasses in
+                            <literal>&lt;union-subclass&gt;</literal> hierarchies.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                It is perfectly acceptable for the named persistent class to be an interface. You would then
+                declare implementing classes of that interface using the <literal>&lt;subclass&gt;</literal>
+                element. You may persist any <emphasis>static</emphasis> inner class. You should specify the
+                class name using the standard form ie. <literal>eg.Foo$Bar</literal>.
+            </para>
+
+            <para>
+                Immutable classes, <literal>mutable="false"</literal>, may not be updated or deleted by the
+                application. This allows Hibernate to make some minor performance optimizations.
+            </para>
+
+            <para>
+                The optional <literal>proxy</literal> attribute enables lazy initialization of persistent
+                instances of the class. Hibernate will initially return CGLIB proxies which implement
+                the named interface. The actual persistent object will be loaded when a method of the
+                proxy is invoked. See "Proxies for Lazy Initialization" below.
+            </para>
+
+            <para><emphasis>Implicit</emphasis> polymorphism means that instances of the class will be returned
+                by a query that names any superclass or implemented interface or the class and that instances
+                of any subclass of the class will be returned by a query that names the class itself.
+                <emphasis>Explicit</emphasis> polymorphism means that class instances will be returned only
+                by queries that explicitly name that class and that queries that name the class will return
+                only instances of subclasses mapped inside this <literal>&lt;class&gt;</literal> declaration
+                as a <literal>&lt;subclass&gt;</literal> or <literal>&lt;joined-subclass&gt;</literal>. For
+                most purposes the default, <literal>polymorphism="implicit"</literal>, is appropriate.
+                Explicit polymorphism is useful when two different classes are mapped to the same table
+                (this allows a "lightweight" class that contains a subset of the table columns).
+            </para>
+
+            <para>
+                The <literal>persister</literal> attribute lets you customize the persistence strategy used for
+                the class. You may, for example, specify your own subclass of
+                <literal>org.hibernate.persister.EntityPersister</literal> or you might even provide a
+                completely new implementation of the interface
+                <literal>org.hibernate.persister.ClassPersister</literal> that implements persistence via,
+                for example, stored procedure calls, serialization to flat files or LDAP. See
+                <literal>org.hibernate.test.CustomPersister</literal> for a simple example (of "persistence"
+                to a <literal>Hashtable</literal>).
+            </para>
+
+            <para>
+                Note that the <literal>dynamic-update</literal> and <literal>dynamic-insert</literal>
+                settings are not inherited by subclasses and so may also be specified on the
+                <literal>&lt;subclass&gt;</literal> or <literal>&lt;joined-subclass&gt;</literal> elements.
+                These settings may increase performance in some cases, but might actually decrease
+                performance in others. Use judiciously.
+            </para>
+
+            <para>
+                Use of <literal>select-before-update</literal> will usually decrease performance. It is very
+                useful to prevent a database update trigger being called unnecessarily if you reattach a
+                graph of detached instances to a <literal>Session</literal>.
+            </para>
+
+            <para>
+                If you enable <literal>dynamic-update</literal>, you will have a choice of optimistic
+                locking strategies:
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <literal>version</literal> check the version/timestamp columns
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>all</literal> check all columns
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>dirty</literal> check the changed columns, allowing some concurrent updates
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>none</literal> do not use optimistic locking
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <para>
+                We <emphasis>very</emphasis> strongly recommend that you use version/timestamp
+                columns for optimistic locking with Hibernate. This is the optimal strategy with
+                respect to performance and is the only strategy that correctly handles modifications
+                made to detached instances (ie. when <literal>Session.merge()</literal> is used).
+            </para>
+
+            <para>
+                There is no difference between a view and a base table for a Hibernate mapping, as
+                expected this is transparent at the database level (note that some DBMS don't support
+                views properly, especially with updates). Sometimes you want to use a view, but can't
+                create one in the database (ie. with a legacy schema). In this case, you can map an
+                immutable and read-only entity to a given SQL subselect expression:
+            </para>
+
+            <programlisting><![CDATA[<class name="Summary">
+    <subselect>
+        select item.name, max(bid.amount), count(*)
+        from item
+        join bid on bid.item_id = item.id
+        group by item.name
+    </subselect>
+    <synchronize table="item"/>
+    <synchronize table="bid"/>
+    <id name="name"/>
+    ...
+</class>]]></programlisting>
+
+            <para>
+                Declare the tables to synchronize this entity with, ensuring that auto-flush happens
+                correctly, and that queries against the derived entity do not return stale data.
+                The <literal>&lt;subselect&gt;</literal> is available as both as an attribute and
+                a nested mapping element.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-id" revision="4">
+            <title>id</title>
+
+            <para>
+                Mapped classes <emphasis>must</emphasis> declare the primary key column of the database
+                table. Most classes will also have a JavaBeans-style property holding the unique identifier
+                of an instance. The <literal>&lt;id&gt;</literal> element defines the mapping from that
+                property to the primary key column.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="id1" coords="2 70"/>
+                    <area id="id2" coords="3 70" />
+                    <area id="id3" coords="4 70"/>
+                    <area id="id4" coords="5 70" />
+                    <area id="id5" coords="6 70" />
+                </areaspec>
+                <programlisting><![CDATA[<id
+        name="propertyName"
+        type="typename"
+        column="column_name"
+        unsaved-value="null|any|none|undefined|id_value"
+        access="field|property|ClassName">
+        node="element-name|@attribute-name|element/@attribute|."
+
+        <generator class="generatorClass"/>
+</id>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="id1">
+                        <para>
+                            <literal>name</literal> (optional): The name of the identifier property.
+                        </para>
+                    </callout>
+                    <callout arearefs="id2">
+                        <para>
+                            <literal>type</literal> (optional): A name that indicates the Hibernate type.
+                        </para>
+                    </callout>
+                    <callout arearefs="id3">
+                        <para>
+                            <literal>column</literal> (optional - defaults to the property name): The
+                            name of the primary key column.
+                        </para>
+                    </callout>
+                    <callout arearefs="id4">
+                        <para>
+                            <literal>unsaved-value</literal> (optional - defaults to a "sensible" value):
+                            An identifier property value that indicates that an instance is newly instantiated
+                            (unsaved), distinguishing it from detached instances that were saved or loaded
+                            in a previous session.
+                        </para>
+                    </callout>
+                   <callout arearefs="id5">
+                        <para>
+                            <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+                            strategy Hibernate should use for accessing the property value.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                If the <literal>name</literal> attribute is missing, it is assumed that the class has no
+                identifier property.
+            </para>
+
+            <para>
+                The <literal>unsaved-value</literal> attribute is almost never needed in Hibernate3.
+            </para>
+
+             <para>
+                There is an alternative <literal>&lt;composite-id&gt;</literal> declaration to allow access to
+                legacy data with composite keys. We strongly discourage its use for anything else.
+            </para>
+
+            <sect3 id="mapping-declaration-id-generator" revision="2">
+                <title>Generator</title>
+
+                <para>
+                    The optional <literal>&lt;generator&gt;</literal> child element names a Java class used
+                    to generate unique identifiers for instances of the persistent class. If any parameters
+                    are required to configure or initialize the generator instance, they are passed using the
+                    <literal>&lt;param&gt;</literal> element.
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="org.hibernate.id.TableHiLoGenerator">
+                <param name="table">uid_table</param>
+                <param name="column">next_hi_value_column</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                    All generators implement the interface <literal>org.hibernate.id.IdentifierGenerator</literal>.
+                    This is a very simple interface; some applications may choose to provide their own specialized
+                    implementations. However, Hibernate provides a range of built-in implementations. There are shortcut
+                    names for the built-in generators:
+
+                    <variablelist>
+                        <varlistentry>
+                        <term><literal>increment</literal></term>
+                        <listitem>
+                            <para>
+                                generates identifiers of type <literal>long</literal>, <literal>short</literal> or
+                                <literal>int</literal> that are unique only when no other process is inserting data
+                                into the same table.
+                                <emphasis>Do not use in a cluster.</emphasis>
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>identity</literal></term>
+                        <listitem>
+                            <para>
+                                supports identity columns in DB2, MySQL, MS SQL Server, Sybase and
+                                HypersonicSQL. The returned identifier is of type <literal>long</literal>,
+                                <literal>short</literal> or <literal>int</literal>.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>sequence</literal></term>
+                        <listitem>
+                            <para>
+                                uses a sequence in DB2, PostgreSQL, Oracle, SAP DB, McKoi or a generator
+                                in Interbase. The returned identifier is of type <literal>long</literal>,
+                                <literal>short</literal> or <literal>int</literal>
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>hilo</literal></term>
+                        <listitem>
+                            <para id="mapping-declaration-id-hilodescription" revision="1">
+                                uses a hi/lo algorithm to efficiently generate identifiers of
+                                type <literal>long</literal>, <literal>short</literal> or <literal>int</literal>,
+                                given a table and column (by default <literal>hibernate_unique_key</literal> and
+                                <literal>next_hi</literal> respectively) as a source of hi values. The hi/lo
+                                algorithm generates identifiers that are unique only for a particular database.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>seqhilo</literal></term>
+                        <listitem>
+                            <para>
+                                uses a hi/lo algorithm to efficiently generate identifiers of type
+                                <literal>long</literal>, <literal>short</literal> or <literal>int</literal>,
+                                given a named database sequence.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>uuid</literal></term>
+                        <listitem>
+                            <para>
+                                uses a 128-bit UUID algorithm to generate identifiers of type string,
+                                unique within a network (the IP address is used). The UUID is encoded
+                                as a string of hexadecimal digits of length 32.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>guid</literal></term>
+                        <listitem>
+                            <para>
+                                uses a database-generated GUID string on MS SQL Server and MySQL.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>native</literal></term>
+                        <listitem>
+                            <para>
+                                picks <literal>identity</literal>, <literal>sequence</literal> or
+                                <literal>hilo</literal> depending upon the capabilities of the
+                                underlying database.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>assigned</literal></term>
+                        <listitem>
+                            <para>
+                                lets the application to assign an identifier to the object before
+                                <literal>save()</literal> is called. This is the default strategy
+                                if no <literal>&lt;generator&gt;</literal> element is specified.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>select</literal></term>
+                        <listitem>
+                            <para>
+                                retrieves a primary key assigned by a database trigger by selecting
+                                the row by some unique key and retrieving the primary key value.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>foreign</literal></term>
+                        <listitem>
+                            <para>
+                                uses the identifier of another associated object. Usually used in conjunction
+                                with a <literal>&lt;one-to-one&gt;</literal> primary key association.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>sequence-identity</literal></term>
+                        <listitem>
+                            <para>
+                                a specialized sequence generation strategy which utilizes a
+                                database sequence for the actual value generation, but combines
+                                this with JDBC3 getGeneratedKeys to actually return the generated
+                                identifier value as part of the insert statement execution.  This
+                                strategy is only known to be supported on Oracle 10g drivers
+                                targetted for JDK 1.4.  Note comments on these insert statements
+                                are disabled due to a bug in the Oracle drivers.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                    </variablelist>
+
+                </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-hilo" revision="1">
+                <title>Hi/lo algorithm</title>
+                <para>
+                    The <literal>hilo</literal> and <literal>seqhilo</literal> generators provide two alternate
+                    implementations of the hi/lo algorithm, a favorite approach to identifier generation. The
+                    first implementation requires a "special" database table to hold the next available "hi" value.
+                    The second uses an Oracle-style sequence (where supported).
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="hilo">
+                <param name="table">hi_value</param>
+                <param name="column">next_value</param>
+                <param name="max_lo">100</param>
+        </generator>
+</id>]]></programlisting>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="seqhilo">
+                <param name="sequence">hi_value</param>
+                <param name="max_lo">100</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                    Unfortunately, you can't use <literal>hilo</literal> when supplying your own
+                    <literal>Connection</literal> to Hibernate. When Hibernate is using an application
+                    server datasource to obtain connections enlisted with JTA, you must properly configure
+                    the <literal>hibernate.transaction.manager_lookup_class</literal>.
+                </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-uuid">
+                <title>UUID algorithm</title>
+                <para>
+                    The UUID contains: IP address, startup time of the JVM (accurate to a quarter
+                    second), system time and a counter value (unique within the JVM). It's not
+                    possible to obtain a MAC address or memory address from Java code, so this is
+                    the best we can do without using JNI.
+                </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-sequences">
+            <title>Identity columns and sequences</title>
+                <para>
+                    For databases which support identity columns (DB2, MySQL, Sybase, MS SQL), you
+                    may use <literal>identity</literal> key generation. For databases that support
+                    sequences (DB2, Oracle, PostgreSQL, Interbase, McKoi, SAP DB) you may use
+                    <literal>sequence</literal> style key generation. Both these strategies require
+                    two SQL queries to insert a new object.
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+        <generator class="sequence">
+                <param name="sequence">person_id_sequence</param>
+        </generator>
+</id>]]></programlisting>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id" unsaved-value="0">
+        <generator class="identity"/>
+</id>]]></programlisting>
+
+                <para>
+                    For cross-platform development, the <literal>native</literal> strategy will
+                    choose from the <literal>identity</literal>, <literal>sequence</literal> and
+                    <literal>hilo</literal> strategies, dependant upon the capabilities of the
+                    underlying database.
+                </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-assigned">
+                <title>Assigned identifiers</title>
+                <para>
+                    If you want the application to assign identifiers (as opposed to having
+                    Hibernate generate them), you may use the <literal>assigned</literal> generator.
+                    This special generator will use the identifier value already assigned to the
+                    object's identifier property. This generator is used when the primary key
+                    is a natural key instead of a surrogate key. This is the default behavior
+                    if you do no specify a <literal>&lt;generator&gt;</literal> element.
+                </para>
+
+                <para>
+                    Choosing the <literal>assigned</literal> generator makes Hibernate use
+                    <literal>unsaved-value="undefined"</literal>, forcing Hibernate to go to
+                    the database to determine if an instance is transient or detached, unless
+                    there is a version or timestamp property, or you define
+                    <literal>Interceptor.isUnsaved()</literal>.
+                </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-select">
+                <title>Primary keys assigned by triggers</title>
+                <para>
+                    For legacy schemas only (Hibernate does not generate DDL with triggers).
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+        <generator class="select">
+                <param name="key">socialSecurityNumber</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                    In the above example, there is a unique valued property named
+                    <literal>socialSecurityNumber</literal> defined by the class, as a
+                    natural key, and a surrogate key named <literal>person_id</literal>
+                    whose value is generated by a trigger.
+                </para>
+
+            </sect3>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-id-enhanced">
+            <title>Enhanced identifier generators</title>
+
+            <para>
+                Starting with release 3.2.3, there are 2 new generators which represent a re-thinking of 2 different
+                aspects of identifier generation.  The first aspect is database portability; the second is optimization
+                (not having to query the database for every request for a new identifier value).  These two new
+                generators are intended to take the place of some of the named generators described above (starting
+                in 3.3.x); however, they are included in the current releases and can be referenced by FQN.
+            </para>
+
+            <para>
+                The first of these new generators is <literal>org.hibernate.id.enhanced.SequenceStyleGenerator</literal>
+                which is intended firstly as a replacement for the <literal>sequence</literal> generator and secondly as
+                a better portability generator than <literal>native</literal> (because <literal>native</literal>
+                (generally) chooses between <literal>identity</literal> and <literal>sequence</literal> which have
+                largely different semantics which can cause subtle isssues in applications eyeing portability).
+                <literal>org.hibernate.id.enhanced.SequenceStyleGenerator</literal> however achieves portability in
+                a different manner.  It chooses between using a table or a sequence in the database to store its
+                incrementing values depending on the capabilities of the dialect being used.  The difference between this
+                and <literal>native</literal> is that table-based and sequence-based storage have the same exact
+                semantic (in fact sequences are exactly what Hibernate tries to emmulate with its table-based
+                generators).  This generator has a number of configuration parameters:
+                <itemizedlist spacing="compact">
+                    <listitem>
+                        <para>
+                            <literal>sequence_name</literal> (optional, defaults to <literal>hibernate_sequence</literal>):
+                            The name of the sequence (or table) to be used.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>initial_value</literal> (optional, defaults to <literal>1</literal>): The initial
+                            value to be retrieved from the sequence/table.  In sequence creation terms, this is analogous
+                            to the clause typical named "STARTS WITH".
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>increment_size</literal> (optional, defaults to <literal>1</literal>): The value by
+                            which subsequent calls to the sequence/table should differ.  In sequence creation terms, this
+                            is analogous to the clause typical named "INCREMENT BY".
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>force_table_use</literal> (optional, defaults to <literal>false</literal>): Should
+                            we force the use of a table as the backing structure even though the dialect might support
+                            sequence?
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>value_column</literal> (optional, defaults to <literal>next_val</literal>): Only
+                            relevant for table structures!  The name of the column on the table which is used to
+                            hold the value.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>optimizer</literal> (optional, defaults to <literal>none</literal>):
+                            See <xref linkend="mapping-declaration-id-enhanced-optimizers"/>
+                        </para>
+                    </listitem>
+                </itemizedlist>
+            </para>
+            <para>
+                The second of these new generators is <literal>org.hibernate.id.enhanced.TableGenerator</literal> which
+                is intended firstly as a replacement for the <literal>table</literal> generator (although it actually
+                functions much more like <literal>org.hibernate.id.MultipleHiLoPerTableGenerator</literal>) and secondly
+                as a re-implementation of <literal>org.hibernate.id.MultipleHiLoPerTableGenerator</literal> utilizing the
+                notion of pluggable optimiziers.  Essentially this generator defines a table capable of holding
+                a number of different increment values simultaneously by using multiple distinctly keyed rows.  This
+                generator has a number of configuration parameters:
+                <itemizedlist spacing="compact">
+                    <listitem>
+                        <para>
+                            <literal>table_name</literal> (optional, defaults to <literal>hibernate_sequences</literal>):
+                            The name of the table to be used.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>value_column_name</literal> (optional, defaults to <literal>next_val</literal>):
+                            The name of the column on the table which is used to hold the value.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>segment_column_name</literal> (optional, defaults to <literal>sequence_name</literal>):
+                            The name of the column on the table which is used to hold the "segement key".  This is the
+                            value which distinctly identifies which increment value to use.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>segment_value</literal> (optional, defaults to <literal>default</literal>):
+                            The "segment key" value for the segment from which we want to pull increment values for
+                            this generator.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>segment_value_length</literal> (optional, defaults to <literal>255</literal>):
+                            Used for schema generation; the column size to create this segment key column.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>initial_value</literal> (optional, defaults to <literal>1</literal>):
+                            The initial value to be retrieved from the table.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>increment_size</literal> (optional, defaults to <literal>1</literal>):
+                            The value by which subsequent calls to the table should differ.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>optimizer</literal> (optional, defaults to <literal></literal>):
+                            See <xref linkend="mapping-declaration-id-enhanced-optimizers"/>
+                        </para>
+                    </listitem>
+                </itemizedlist>
+            </para>
+        </sect2>
+
+        <sect2 id="mapping-declaration-id-enhanced-optimizers">
+            <title>Identifier generator optimization</title>
+            <para>
+                For identifier generators which store values in the database, it is inefficient for them to hit the
+                database on each and every call to generate a new identifier value.  Instead, you'd ideally want to
+                group a bunch of them in memory and only hit the database when you have exhausted your in-memory
+                value group.  This is the role of the pluggable optimizers.  Currently only the two enhanced generators
+                (<xref linkend="mapping-declaration-id-enhanced"/> support this notion.
+                <itemizedlist spacing="compact">
+                    <listitem>
+                        <para>
+                            <literal>none</literal> (generally this is the default if no optimizer was specified):  This
+                            says to not perform any optimizations, and hit the database each and every request.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>hilo</literal>: applies a hi/lo algorithm around the database retrieved values.  The
+                            values from the database for this optimizer are expected to be sequential.  The values
+                            retrieved from the database structure for this optimizer indicates the "group number"; the
+                            <literal>increment_size</literal> is multiplied by that value in memory to define a group
+                            "hi value".
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>pooled</literal>: like was discussed for <literal>hilo</literal>, this optimizers
+                            attempts to minimize the number of hits to the database.  Here, however, we simply store
+                            the starting value for the "next group" into the database structure rather than a sequential
+                            value in combination with an in-memory grouping algorithm.  <literal>increment_size</literal>
+                            here refers to the values coming from the database.
+                        </para>
+                    </listitem>
+                </itemizedlist>
+            </para>
+        </sect2>
+
+        <sect2 id="mapping-declaration-compositeid" revision="3">
+            <title>composite-id</title>
+
+            <programlisting><![CDATA[<composite-id
+        name="propertyName"
+        class="ClassName"
+        mapped="true|false"
+        access="field|property|ClassName">
+        node="element-name|."
+
+        <key-property name="propertyName" type="typename" column="column_name"/>
+        <key-many-to-one name="propertyName class="ClassName" column="column_name"/>
+        ......
+</composite-id>]]></programlisting>
+
+            <para>
+                For a table with a composite key, you may map multiple properties of the class
+                as identifier properties. The <literal>&lt;composite-id&gt;</literal> element
+                accepts <literal>&lt;key-property&gt;</literal> property mappings and
+                <literal>&lt;key-many-to-one&gt;</literal> mappings as child elements.
+            </para>
+
+            <programlisting><![CDATA[<composite-id>
+        <key-property name="medicareNumber"/>
+        <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+            <para>
+                Your persistent class <emphasis>must</emphasis> override <literal>equals()</literal>
+                and <literal>hashCode()</literal> to implement composite identifier equality. It must
+                also implements <literal>Serializable</literal>.
+            </para>
+
+            <para>
+                Unfortunately, this approach to composite identifiers means that a persistent object
+                is its own identifier. There is no convenient "handle" other than the object itself.
+                You must instantiate an instance of the persistent class itself and populate its
+                identifier properties before you can <literal>load()</literal> the persistent state
+                associated with a composite key. We call this approach an <emphasis>embedded</emphasis>
+                composite identifier, and discourage it for serious applications.
+            </para>
+
+            <para>
+                A second approach is what we call a <emphasis>mapped</emphasis> composite identifier,
+                where the identifier properties named inside the <literal>&lt;composite-id&gt;</literal>
+                element are duplicated on both the persistent class and a separate identifier class.
+            </para>
+
+            <programlisting><![CDATA[<composite-id class="MedicareId" mapped="true">
+        <key-property name="medicareNumber"/>
+        <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+            <para>
+                In this example, both the composite identifier class, <literal>MedicareId</literal>,
+                and the entity class itself have properties named <literal>medicareNumber</literal>
+                and <literal>dependent</literal>. The identifier class must override
+                <literal>equals()</literal> and <literal>hashCode()</literal> and implement.
+                <literal>Serializable</literal>. The disadvantage of this approach is quite
+                obvious&mdash;code duplication.
+            </para>
+
+            <para>
+                The following attributes are used to specify a mapped composite identifier:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>mapped</literal> (optional, defaults to <literal>false</literal>):
+                        indicates that a mapped composite identifier is used, and that the contained
+                        property mappings refer to both the entity class and the composite identifier
+                        class.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>class</literal> (optional, but required for a mapped composite identifier):
+                        The class used as a composite identifier.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                We will describe a third, even more convenient approach where the composite identifier
+                is implemented as a component class in <xref linkend="components-compositeid"/>. The
+                attributes described below apply only to this alternative approach:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>name</literal> (optional, required for this approach): A property of
+                        component type that holds the composite identifier (see chapter 9).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>access</literal> (optional - defaults to <literal>property</literal>):
+                        The strategy Hibernate should use for accessing the property value.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>class</literal> (optional - defaults to the property type determined by
+                        reflection): The component class used as a composite identifier (see next section).
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                This third approach, an <emphasis>identifier component</emphasis> is the one we recommend
+                for almost all applications.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-discriminator" revision="3">
+            <title>discriminator</title>
+
+            <para>
+                The <literal>&lt;discriminator&gt;</literal> element is required for polymorphic persistence
+                using the table-per-class-hierarchy mapping strategy and declares a discriminator column of the
+                table. The discriminator column contains marker values that tell the persistence layer what
+                subclass to instantiate for a particular row. A restricted set of types may be used:
+                <literal>string</literal>, <literal>character</literal>, <literal>integer</literal>,
+                <literal>byte</literal>, <literal>short</literal>, <literal>boolean</literal>,
+                <literal>yes_no</literal>, <literal>true_false</literal>.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="discriminator1" coords="2 60"/>
+                    <area id="discriminator2" coords="3 60" />
+                    <area id="discriminator3" coords="4 60" />
+                    <area id="discriminator4" coords="5 60" />
+                    <area id="discriminator5" coords="6 60" />
+                </areaspec>
+                <programlisting><![CDATA[<discriminator
+        column="discriminator_column"
+        type="discriminator_type"
+        force="true|false"
+        insert="true|false"
+        formula="arbitrary sql expression"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="discriminator1">
+                        <para>
+                            <literal>column</literal> (optional - defaults to <literal>class</literal>) the
+                            name of the discriminator column.
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator2">
+                        <para>
+                            <literal>type</literal> (optional - defaults to <literal>string</literal>) a
+                            name that indicates the Hibernate type
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator3">
+                        <para>
+                            <literal>force</literal> (optional - defaults to <literal>false</literal>)
+                            "force" Hibernate to specify allowed discriminator values even when retrieving
+                            all instances of the root class.
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator4">
+                        <para>
+                            <literal>insert</literal> (optional - defaults to <literal>true</literal>)
+                            set this to <literal>false</literal> if your discriminator column is also part
+                            of a mapped composite identifier. (Tells Hibernate to not include the column
+                            in SQL <literal>INSERT</literal>s.)
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator5">
+                        <para>
+                            <literal>formula</literal> (optional) an arbitrary SQL expression that is
+                            executed when a type has to be evaluated. Allows content-based discrimination.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Actual values of the discriminator column are specified by the
+                <literal>discriminator-value</literal> attribute of the <literal>&lt;class&gt;</literal> and
+                <literal>&lt;subclass&gt;</literal> elements.
+            </para>
+
+            <para>
+                The <literal>force</literal> attribute is (only) useful if the table contains rows with
+                "extra" discriminator values that are not mapped to a persistent class. This will not
+                usually be the case.
+            </para>
+
+            <para>
+                Using the <literal>formula</literal> attribute you can declare an arbitrary SQL expression
+                that will be used to evaluate the type of a row:
+            </para>
+
+            <programlisting><![CDATA[<discriminator
+    formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
+    type="integer"/>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-version" revision="4">
+            <title>version (optional)</title>
+
+            <para>
+                The <literal>&lt;version&gt;</literal> element is optional and indicates that
+                the table contains versioned data. This is particularly useful if you plan to
+                use <emphasis>long transactions</emphasis> (see below).
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="version1" coords="2 70"/>
+                    <area id="version2" coords="3 70"/>
+                    <area id="version3" coords="4 70"/>
+                    <area id="version4" coords="5 70"/>
+                    <area id="version5" coords="6 70"/>
+                    <area id="version6" coords="7 70"/>
+                    <area id="version7" coords="8 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<version
+        column="version_column"
+        name="propertyName"
+        type="typename"
+        access="field|property|ClassName"
+        unsaved-value="null|negative|undefined"
+        generated="never|always"
+        insert="true|false"
+        node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="version1">
+                        <para>
+                            <literal>column</literal> (optional - defaults to the property name): The name
+                            of the column holding the version number.
+                        </para>
+                    </callout>
+                    <callout arearefs="version2">
+                        <para>
+                            <literal>name</literal>: The name of a property  of the persistent class.
+                        </para>
+                    </callout>
+                    <callout arearefs="version3">
+                        <para>
+                            <literal>type</literal> (optional - defaults to <literal>integer</literal>):
+                            The type of the version number.
+                        </para>
+                    </callout>
+                   <callout arearefs="version4">
+                        <para>
+                            <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+                            strategy Hibernate should use for accessing the property value.
+                        </para>
+                    </callout>
+                   <callout arearefs="version5">
+                        <para>
+                            <literal>unsaved-value</literal> (optional - defaults to <literal>undefined</literal>):
+                            A version property value that indicates that an instance is newly instantiated
+                            (unsaved), distinguishing it from detached instances that were saved or loaded
+                            in a previous session. (<literal>undefined</literal> specifies that the identifier
+                            property value should be used.)
+                        </para>
+                    </callout>
+                    <callout arearefs="version6">
+                        <para>
+                            <literal>generated</literal> (optional - defaults to <literal>never</literal>):
+                            Specifies that this version property value is actually generated by the database.
+                            See the discussion of <xref linkend="mapping-generated">generated properties</xref>.
+                        </para>
+                    </callout>
+                    <callout arearefs="version7">
+                        <para>
+                            <literal>insert</literal> (optional - defaults to <literal>true</literal>):
+                            Specifies whether the version column should be included in SQL insert statements.
+                            May be set to <literal>false</literal> if and only if the database column
+                            is defined with a default value of <literal>0</literal>.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Version numbers may be of Hibernate type <literal>long</literal>, <literal>integer</literal>,
+                <literal>short</literal>, <literal>timestamp</literal> or <literal>calendar</literal>.
+            </para>
+
+            <para>
+                A version or timestamp property should never be null for a detached instance, so
+                Hibernate will detact any instance with a null version or timestamp as transient,
+                no matter what other <literal>unsaved-value</literal> strategies are specified.
+                <emphasis>Declaring a nullable version or timestamp property is an easy way to avoid
+                any problems with transitive reattachment in Hibernate, especially useful for people
+                using assigned identifiers or composite keys!</emphasis>
+            </para>
+        </sect2>
+
+        <sect2 id="mapping-declaration-timestamp" revision="4" >
+            <title>timestamp (optional)</title>
+
+            <para>
+                The optional <literal>&lt;timestamp&gt;</literal> element indicates that the table contains
+                timestamped data. This is intended as an alternative to versioning. Timestamps are by nature
+                a less safe implementation of optimistic locking. However, sometimes the application might
+                use the timestamps in other ways.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="timestamp1" coords="2 70"/>
+                    <area id="timestamp2" coords="3 70" />
+                    <area id="timestamp3" coords="4 70" />
+                    <area id="timestamp4" coords="5 70" />
+                    <area id="timestamp5" coords="6 70" />
+                    <area id="timestamp6" coords="7 70" />
+                </areaspec>
+                <programlisting><![CDATA[<timestamp
+        column="timestamp_column"
+        name="propertyName"
+        access="field|property|ClassName"
+        unsaved-value="null|undefined"
+        source="vm|db"
+        generated="never|always"
+        node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="timestamp1">
+                        <para>
+                            <literal>column</literal> (optional - defaults to the property name): The name
+                            of a column holding the timestamp.
+                        </para>
+                    </callout>
+                    <callout arearefs="timestamp2">
+                        <para>
+                            <literal>name</literal>: The name of a JavaBeans style property of
+                            Java type <literal>Date</literal> or <literal>Timestamp</literal> of the
+                            persistent class.
+                        </para>
+                    </callout>
+                   <callout arearefs="timestamp3">
+                        <para>
+                            <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+                            strategy Hibernate should use for accessing the property value.
+                        </para>
+                    </callout>
+                   <callout arearefs="timestamp4">
+                        <para>
+                            <literal>unsaved-value</literal> (optional - defaults to <literal>null</literal>):
+                            A version property value that indicates that an instance is newly instantiated
+                            (unsaved), distinguishing it from detached instances that were saved or loaded
+                            in a previous session. (<literal>undefined</literal> specifies that the identifier
+                            property value should be used.)
+                        </para>
+                    </callout>
+                   <callout arearefs="timestamp5">
+                        <para>
+                            <literal>source</literal> (optional - defaults to <literal>vm</literal>):
+                            From where should Hibernate retrieve the timestamp value?  From the database,
+                            or from the current JVM?  Database-based timestamps incur an overhead because
+                            Hibernate must hit the database in order to determine the "next value",
+                            but will be safer for use in clustered environments.  Note also, that not
+                            all <literal>Dialect</literal>s are known to support retrieving of the
+                            database's current timestamp, while others might be unsafe for usage
+                            in locking due to lack of precision (Oracle 8 for example).
+                        </para>
+                    </callout>
+                    <callout arearefs="timestamp6">
+                        <para>
+                            <literal>generated</literal> (optional - defaults to <literal>never</literal>):
+                            Specifies that this timestamp property value is actually generated by the database.
+                            See the discussion of <xref linkend="mapping-generated">generated properties</xref>.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Note that <literal>&lt;timestamp&gt;</literal> is equivalent to
+                <literal>&lt;version type="timestamp"&gt;</literal>.  And
+                 <literal>&lt;timestamp source="db"&gt;</literal> is equivalent to
+                <literal>&lt;version type="dbtimestamp"&gt;</literal>
+            </para>
+        </sect2>
+
+
+        <sect2 id="mapping-declaration-property" revision="4">
+            <title>property</title>
+
+            <para>
+                The <literal>&lt;property&gt;</literal> element declares a persistent, JavaBean style
+                property of the class.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="property1" coords="2 70"/>
+                    <area id="property2" coords="3 70"/>
+                    <area id="property3" coords="4 70"/>
+                    <areaset id="property4-5" coords="">
+                        <area id="property4" coords='5 70'/>
+                        <area id="property5" coords='6 70'/>
+                    </areaset>
+                    <area id="property6" coords="7 70"/>
+                    <area id="property7" coords="8 70"/>
+                    <area id="property8" coords="9 70"/>
+                    <area id="property9" coords="10 70"/>
+                    <area id="property10" coords="11 70"/>
+                    <area id="property11" coords="12 70"/>
+                    <area id="property12" coords="13 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<property
+        name="propertyName"
+        column="column_name"
+        type="typename"
+        update="true|false"
+        insert="true|false"
+        formula="arbitrary SQL expression"
+        access="field|property|ClassName"
+        lazy="true|false"
+        unique="true|false"
+        not-null="true|false"
+        optimistic-lock="true|false"
+        generated="never|insert|always"
+        node="element-name|@attribute-name|element/@attribute|."
+        index="index_name"
+        unique_key="unique_key_id"
+        length="L"
+        precision="P"
+        scale="S"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="property1">
+                        <para>
+                            <literal>name</literal>: the name of the property, with an initial lowercase
+                            letter.
+                        </para>
+                    </callout>
+                    <callout arearefs="property2">
+                        <para>
+                            <literal>column</literal> (optional - defaults to the property name): the name
+                            of the mapped database table column. This may also be specified by nested
+                            <literal>&lt;column&gt;</literal> element(s).
+                        </para>
+                    </callout>
+                    <callout arearefs="property3">
+                        <para>
+                            <literal>type</literal> (optional): a name that indicates the Hibernate type.
+                        </para>
+                    </callout>
+                    <callout arearefs="property4-5">
+                        <para>
+                            <literal>update, insert</literal> (optional - defaults to <literal>true</literal>) :
+                            specifies that the mapped columns should be included in SQL <literal>UPDATE</literal>
+                            and/or <literal>INSERT</literal> statements. Setting both to <literal>false</literal>
+                            allows a pure "derived" property whose value is initialized from some other
+                            property that maps to the same colum(s) or by a trigger or other application.
+                        </para>
+                    </callout>
+                    <callout arearefs="property6">
+                        <para>
+                            <literal>formula</literal> (optional): an SQL expression that defines the value for a
+                            <emphasis>computed</emphasis> property. Computed properties do not have a column
+                            mapping of their own.
+                        </para>
+                    </callout>
+                    <callout arearefs="property7">
+                        <para>
+                            <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+                            strategy Hibernate should use for accessing the property value.
+                        </para>
+                    </callout>
+                    <callout arearefs="property8">
+                        <para>
+                            <literal>lazy</literal> (optional - defaults to <literal>false</literal>): Specifies
+                            that this property should be fetched lazily when the instance variable is first
+                            accessed (requires build-time bytecode instrumentation).
+                        </para>
+                    </callout>
+                    <callout arearefs="property9">
+                        <para>
+                            <literal>unique</literal> (optional): Enable the DDL generation of a unique
+                            constraint for the columns. Also, allow this to be the target of
+                            a <literal>property-ref</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="property10">
+                        <para>
+                            <literal>not-null</literal> (optional): Enable the DDL generation of a nullability
+                            constraint for the columns.
+                        </para>
+                    </callout>
+                    <callout arearefs="property11">
+                        <para>
+                            <literal>optimistic-lock</literal> (optional - defaults to <literal>true</literal>):
+                            Specifies that updates to this property do or do not require acquisition of the
+                            optimistic lock. In other words, determines if a version increment should occur when
+                            this property is dirty.
+                        </para>
+                    </callout>
+                    <callout arearefs="property12">
+                        <para>
+                            <literal>generated</literal> (optional - defaults to <literal>never</literal>):
+                            Specifies that this property value is actually generated by the database.
+                            See the discussion of <xref linkend="mapping-generated">generated properties</xref>.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                <emphasis>typename</emphasis> could be:
+            </para>
+
+            <orderedlist spacing="compact">
+                <listitem>
+                    <para>
+                        The name of a Hibernate basic type (eg. <literal>integer, string, character,
+                        date, timestamp, float, binary, serializable, object, blob</literal>).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        The name of a Java class with a default basic type (eg. <literal>int, float,
+                        char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob</literal>).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        The name of a serializable Java class.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        The class name of a custom type (eg. <literal>com.illflow.type.MyCustomType</literal>).
+                    </para>
+                </listitem>
+            </orderedlist>
+
+            <para>
+                If you do not specify a type, Hibernate will use reflection upon the named
+                property to take a guess at the correct Hibernate type. Hibernate will try to
+                interpret the name of the return class of the property getter using rules 2, 3,
+                4 in that order. However, this is not always enough.
+                In certain cases you will still need the <literal>type</literal>
+                attribute. (For example, to distinguish between <literal>Hibernate.DATE</literal> and
+                <literal>Hibernate.TIMESTAMP</literal>, or to specify a custom type.)
+            </para>
+
+            <para>
+                The <literal>access</literal> attribute lets you control how Hibernate will access
+                the property at runtime. By default, Hibernate will call the property get/set pair.
+                If you specify <literal>access="field"</literal>, Hibernate will bypass the get/set
+                pair and access the field directly, using reflection. You may specify your own
+                strategy for property access by naming a class that implements the interface
+                <literal>org.hibernate.property.PropertyAccessor</literal>.
+            </para>
+
+            <para>
+                An especially powerful feature are derived properties. These properties are by
+                definition read-only, the property value is computed at load time. You declare
+                the computation as a SQL expression, this translates to a <literal>SELECT</literal>
+                clause subquery in the SQL query that loads an instance:
+            </para>
+
+        <programlisting><![CDATA[
+<property name="totalPrice"
+    formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p
+                WHERE li.productId = p.productId
+                AND li.customerId = customerId
+                AND li.orderNumber = orderNumber )"/>]]></programlisting>
+
+            <para>
+                Note that you can reference the entities own table by not declaring an alias on
+                a particular column (<literal>customerId</literal> in the given example). Also note
+                that you can use the nested <literal>&lt;formula&gt;</literal> mapping element
+                if you don't like to use the attribute.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-manytoone" revision="5">
+            <title>many-to-one</title>
+
+            <para>
+                An ordinary association to another persistent class is declared using a
+                <literal>many-to-one</literal> element. The relational model is a
+                many-to-one association: a foreign key in one table is referencing
+                the primary key column(s) of the target table.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="manytoone1" coords="2 70"/>
+                    <area id="manytoone2" coords="3 70"/>
+                    <area id="manytoone3" coords="4 70"/>
+                    <area id="manytoone4" coords="5 70"/>
+                    <area id="manytoone5" coords="6 70"/>
+                    <areaset id="manytoone6-7" coords="">
+                        <area id="manytoone6" coords='7 70'/>
+                        <area id="manytoone7" coords='8 70'/>
+                    </areaset>
+                    <area id="manytoone8" coords="9 70"/>
+                    <area id="manytoone9" coords="10 70"/>
+                    <area id="manytoone10" coords="11 70"/>
+                    <area id="manytoone11" coords="12 70"/>
+                    <area id="manytoone12" coords="13 70"/>
+                    <area id="manytoone13" coords="14 70"/>
+                    <area id="manytoone14" coords="15 70"/>
+                    <area id="manytoone15" coords="16 70"/>
+                    <area id="manytoone16" coords="17 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<many-to-one
+        name="propertyName"
+        column="column_name"
+        class="ClassName"
+        cascade="cascade_style"
+        fetch="join|select"
+        update="true|false"
+        insert="true|false"
+        property-ref="propertyNameFromAssociatedClass"
+        access="field|property|ClassName"
+        unique="true|false"
+        not-null="true|false"
+        optimistic-lock="true|false"
+        lazy="proxy|no-proxy|false"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        formula="arbitrary SQL expression"
+        node="element-name|@attribute-name|element/@attribute|."
+        embed-xml="true|false"
+        index="index_name"
+        unique_key="unique_key_id"
+        foreign-key="foreign_key_name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="manytoone1">
+                        <para>
+                            <literal>name</literal>: The name of the property.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone2">
+                        <para>
+                            <literal>column</literal> (optional): The name of the foreign key column.
+                            This may also be specified by nested <literal>&lt;column&gt;</literal>
+                            element(s).
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone3">
+                        <para>
+                            <literal>class</literal> (optional - defaults to the property type
+                            determined by reflection): The name of the associated class.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone4">
+                        <para>
+                            <literal>cascade</literal> (optional): Specifies which operations should
+                            be cascaded from the parent object to the associated object.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone5">
+                        <para>
+                            <literal>fetch</literal> (optional - defaults to <literal>select</literal>):
+                            Chooses between outer-join fetching or sequential select fetching.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone6-7">
+                        <para>
+                            <literal>update, insert</literal> (optional - defaults to <literal>true</literal>)
+                            specifies that the mapped columns should be included in SQL <literal>UPDATE</literal>
+                            and/or <literal>INSERT</literal> statements. Setting both to <literal>false</literal>
+                            allows a pure "derived" association whose value is initialized from some other
+                            property that maps to the same colum(s) or by a trigger or other application.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone8">
+                        <para>
+                            <literal>property-ref</literal>: (optional) The name of a property of the associated
+                            class that is joined to this foreign key. If not specified, the primary key of
+                            the associated class is used.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone9">
+                        <para>
+                            <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+                            strategy Hibernate should use for accessing the property value.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone10">
+                        <para>
+                            <literal>unique</literal> (optional): Enable the DDL generation of a unique
+                            constraint for the foreign-key column. Also, allow this to be the target of
+                            a <literal>property-ref</literal>. This makes the association multiplicity
+                            effectively one to one.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone11">
+                        <para>
+                            <literal>not-null</literal> (optional): Enable the DDL generation of a nullability
+                            constraint for the foreign key columns.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone12">
+                        <para>
+                            <literal>optimistic-lock</literal> (optional - defaults to <literal>true</literal>):
+                            Specifies that updates to this property do or do not require acquisition of the
+                            optimistic lock. In other words, dertermines if a version increment should occur when
+                            this property is dirty.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone13">
+                        <para>
+                            <literal>lazy</literal> (optional - defaults to <literal>proxy</literal>):
+                            By default, single point associations are proxied. <literal>lazy="no-proxy"</literal>
+                            specifies that the property should be fetched lazily when the instance variable
+                            is first accessed (requires build-time bytecode instrumentation).
+                            <literal>lazy="false"</literal> specifies that the association will always
+                            be eagerly fetched.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone14">
+                        <para>
+                            <literal>not-found</literal> (optional - defaults to <literal>exception</literal>):
+                            Specifies how foreign keys that reference missing rows will be handled:
+                            <literal>ignore</literal> will treat a missing row as a null association.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone15">
+                        <para>
+                            <literal>entity-name</literal> (optional): The entity name of the associated class.
+                        </para>
+                    </callout>
+                </calloutlist>
+                    <callout arearefs="manytoone16">
+                        <para>
+                            <literal>formula</literal> (optional): an SQL expression that defines the value for a
+                            <emphasis>computed</emphasis> foreign key.
+                        </para>
+                    </callout>
+            </programlistingco>
+
+            <para>
+                Setting a value of the <literal>cascade</literal> attribute to any meaningful
+                value other than <literal>none</literal> will propagate certain operations to the
+                associated object. The meaningful values are the names of Hibernate's basic
+                operations, <literal>persist, merge, delete, save-update, evict, replicate, lock,
+                refresh</literal>, as well as the special values <literal>delete-orphan</literal>
+                and <literal>all</literal> and comma-separated combinations of operation
+                names, for example, <literal>cascade="persist,merge,evict"</literal> or
+                <literal>cascade="all,delete-orphan"</literal>. See <xref linkend="objectstate-transitive"/>
+                for a full explanation. Note that single valued associations (many-to-one and
+                one-to-one associations) do not support orphan delete.
+            </para>
+
+            <para>
+                A typical <literal>many-to-one</literal> declaration looks as simple as this:
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="product" class="Product" column="PRODUCT_ID"/>]]></programlisting>
+
+            <para>
+                The <literal>property-ref</literal> attribute should only be used for mapping legacy
+                data where a foreign key refers to a unique key of the associated table other than
+                the primary key. This is an ugly relational model. For example, suppose the
+                <literal>Product</literal> class had a unique serial number, that is not the primary
+                key. (The <literal>unique</literal> attribute controls Hibernate's DDL generation with
+                the SchemaExport tool.)
+            </para>
+
+            <programlisting><![CDATA[<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>]]></programlisting>
+
+            <para>
+                Then the mapping for <literal>OrderItem</literal> might use:
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>]]></programlisting>
+
+            <para>
+                This is certainly not encouraged, however.
+            </para>
+
+            <para>
+                If the referenced unique key comprises multiple properties of the associated entity, you should
+                map the referenced properties inside a named <literal>&lt;properties&gt;</literal> element.
+            </para>
+
+            <para>
+            	If the referenced unique key is the property of a component, you may specify a property path:
+            </para>
+
+           <programlisting><![CDATA[<many-to-one name="owner" property-ref="identity.ssn" column="OWNER_SSN"/>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-onetoone" revision="3">
+            <title>one-to-one</title>
+
+            <para>
+                A one-to-one association to another persistent class is declared using a
+                <literal>one-to-one</literal> element.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="onetoone1" coords="2 70"/>
+                    <area id="onetoone2" coords="3 70"/>
+                    <area id="onetoone3" coords="4 70"/>
+                    <area id="onetoone4" coords="5 70"/>
+                    <area id="onetoone5" coords="6 70"/>
+                    <area id="onetoone6" coords="7 70"/>
+                    <area id="onetoone7" coords="8 70"/>
+                    <area id="onetoone8" coords="9 70"/>
+                    <area id="onetoone9" coords="10 70"/>
+                    <area id="onetoone10" coords="11 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<one-to-one
+        name="propertyName"
+        class="ClassName"
+        cascade="cascade_style"
+        constrained="true|false"
+        fetch="join|select"
+        property-ref="propertyNameFromAssociatedClass"
+        access="field|property|ClassName"
+        formula="any SQL expression"
+        lazy="proxy|no-proxy|false"
+        entity-name="EntityName"
+        node="element-name|@attribute-name|element/@attribute|."
+        embed-xml="true|false"
+        foreign-key="foreign_key_name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="onetoone1">
+                        <para>
+                            <literal>name</literal>: The name of the property.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone2">
+                        <para>
+                            <literal>class</literal> (optional - defaults to the property type
+                            determined by reflection): The name of the associated class.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone3">
+                        <para>
+                            <literal>cascade</literal> (optional) specifies which operations should
+                            be cascaded from the parent object to the associated object.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone4">
+                        <para>
+                            <literal>constrained</literal> (optional) specifies that a foreign key constraint
+                            on the primary key of the mapped table references the table of the associated
+                            class. This option affects the order in which <literal>save()</literal> and
+                            <literal>delete()</literal> are cascaded, and determines whether the association
+                            may be proxied (it is also used by the schema export tool).
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone5">
+                        <para>
+                            <literal>fetch</literal> (optional - defaults to <literal>select</literal>):
+                            Chooses between outer-join fetching or sequential select fetching.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone6">
+                        <para>
+                            <literal>property-ref</literal>: (optional) The name of a property of the associated class
+                            that is joined to the primary key of this class. If not specified, the primary key of
+                            the associated class is used.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone7">
+                        <para>
+                            <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+                            strategy Hibernate should use for accessing the property value.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone8">
+                        <para>
+                            <literal>formula</literal> (optional): Almost all one to one associations map to the
+                            primary key of the owning entity. In the rare case that this is not the case, you may
+                            specify a some other column, columns or expression to join on using an SQL formula. (See
+                            <literal>org.hibernate.test.onetooneformula</literal> for an example.)
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone9">
+                        <para>
+                            <literal>lazy</literal> (optional - defaults to <literal>proxy</literal>):
+                            By default, single point associations are proxied. <literal>lazy="no-proxy"</literal>
+                            specifies that the property should be fetched lazily when the instance variable
+                            is first accessed (requires build-time bytecode instrumentation).
+                            <literal>lazy="false"</literal> specifies that the association will always
+                            be eagerly fetched. <emphasis>Note that if <literal>constrained="false"</literal>,
+                            proxying is impossible and Hibernate will eager fetch the association!</emphasis>
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone10">
+                        <para>
+                            <literal>entity-name</literal> (optional): The entity name of the associated class.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                There are two varieties of one-to-one association:
+            </para>
+            <itemizedlist>
+            <listitem><para>
+                primary key associations
+            </para></listitem>
+            <listitem><para>
+                unique foreign key associations
+            </para></listitem>
+            </itemizedlist>
+
+            <para>
+                Primary key associations don't need an extra table column; if two rows are related by
+                the association then the two table rows share the same primary key value. So if you want
+                two objects to be related by a primary key association, you must make sure that they
+                are assigned the same identifier value!
+            </para>
+
+            <para>
+                For a primary key association, add the following mappings to <literal>Employee</literal> and
+                <literal>Person</literal>, respectively.
+            </para>
+
+            <programlisting><![CDATA[<one-to-one name="person" class="Person"/>]]></programlisting>
+            <programlisting><![CDATA[<one-to-one name="employee" class="Employee" constrained="true"/>]]></programlisting>
+
+            <para>
+                Now we must ensure that the primary keys of related rows in the PERSON and
+                EMPLOYEE tables are equal. We use a special Hibernate identifier generation strategy
+                called <literal>foreign</literal>:
+            </para>
+
+            <programlisting><![CDATA[<class name="person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="foreign">
+            <param name="property">employee</param>
+        </generator>
+    </id>
+    ...
+    <one-to-one name="employee"
+        class="Employee"
+        constrained="true"/>
+</class>]]></programlisting>
+
+            <para>
+                A newly saved instance of <literal>Person</literal> is then assigned the same primary
+                key value as the <literal>Employee</literal> instance refered with the <literal>employee</literal>
+                property of that <literal>Person</literal>.
+            </para>
+
+            <para>
+                Alternatively, a foreign key with a unique constraint, from <literal>Employee</literal> to
+                <literal>Person</literal>, may be expressed as:
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/>]]></programlisting>
+
+            <para>
+                And this association may be made bidirectional by adding the following to the
+                <literal>Person</literal> mapping:
+            </para>
+
+           <programlisting><![CDATA[<one-to-one name"employee" class="Employee" property-ref="person"/>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-naturalid">
+            <title>natural-id</title>
+
+            <programlisting><![CDATA[<natural-id mutable="true|false"/>
+        <property ... />
+        <many-to-one ... />
+        ......
+</natural-id>]]></programlisting>
+
+            <para>
+                Even though we recommend the use of surrogate keys as primary keys, you should still try
+                to identify natural keys for all entities. A natural key is a property or combination of
+                properties that is unique and non-null. If it is also immutable, even better. Map the
+                properties of the natural key inside the <literal>&lt;natural-id&gt;</literal> element.
+                Hibernate will generate the necessary unique key and nullability constraints, and your
+                mapping will be more self-documenting.
+            </para>
+
+            <para>
+                We strongly recommend that you implement <literal>equals()</literal> and
+                <literal>hashCode()</literal> to compare the natural key properties of the entity.
+            </para>
+
+            <para>
+                This mapping is not intended for use with entities with natural primary keys.
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>mutable</literal> (optional, defaults to <literal>false</literal>):
+                        By default, natural identifier properties as assumed to be immutable (constant).
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-component" revision="2">
+            <title>component, dynamic-component</title>
+
+            <para>
+                The <literal>&lt;component&gt;</literal> element maps properties of a
+                child object to columns of the table of a parent class. Components may, in
+                turn, declare their own properties, components or collections. See
+                "Components" below.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="component1" coords="2 45"/>
+                    <area id="component2" coords="3 45"/>
+                    <area id="component3" coords="4 45"/>
+                    <area id="component4" coords="5 45"/>
+                    <area id="component5" coords="6 45"/>
+                    <area id="component6" coords="7 45"/>
+                    <area id="component7" coords="8 45"/>
+                    <area id="component8" coords="9 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<component
+        name="propertyName"
+        class="className"
+        insert="true|false"
+        update="true|false"
+        access="field|property|ClassName"
+        lazy="true|false"
+        optimistic-lock="true|false"
+        unique="true|false"
+        node="element-name|."
+>
+
+        <property ...../>
+        <many-to-one .... />
+        ........
+</component>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="component1">
+                        <para>
+                            <literal>name</literal>: The name of the property.
+                        </para>
+                    </callout>
+                    <callout arearefs="component2">
+                        <para>
+                            <literal>class</literal> (optional - defaults to the property type
+                            determined by reflection): The name of the component (child) class.
+                        </para>
+                    </callout>
+                    <callout arearefs="component3">
+                        <para>
+                            <literal>insert</literal>: Do the mapped columns appear in SQL
+                            <literal>INSERT</literal>s?
+                        </para>
+                    </callout>
+                    <callout arearefs="component4">
+                        <para>
+                            <literal>update</literal>: Do the mapped columns appear in SQL
+                            <literal>UPDATE</literal>s?
+                        </para>
+                    </callout>
+                    <callout arearefs="component5">
+                        <para>
+                            <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+                            strategy Hibernate should use for accessing the property value.
+                        </para>
+                    </callout>
+                   <callout arearefs="component6">
+                        <para>
+                            <literal>lazy</literal> (optional - defaults to <literal>false</literal>): Specifies
+                            that this component should be fetched lazily when the instance variable is first
+                            accessed (requires build-time bytecode instrumentation).
+                        </para>
+                    </callout>
+                    <callout arearefs="component7">
+                            <para>
+                                <literal>optimistic-lock</literal> (optional - defaults to <literal>true</literal>):
+                                Specifies that updates to this component do or do not require acquisition of the
+                                optimistic lock. In other words, determines if a version increment should occur when
+                                this property is dirty.
+                            </para>
+                    </callout>
+                    <callout arearefs="component8">
+                            <para>
+                                <literal>unique</literal> (optional - defaults to <literal>false</literal>):
+                                Specifies that a unique constraint exists upon all mapped columns of the
+                                component.
+                            </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                The child <literal>&lt;property&gt;</literal> tags map properties of the
+                child class to table columns.
+            </para>
+
+            <para>
+                The <literal>&lt;component&gt;</literal> element allows a <literal>&lt;parent&gt;</literal>
+                subelement that maps a property of the component class as a reference back to the
+                containing entity.
+            </para>
+
+            <para>
+                The <literal>&lt;dynamic-component&gt;</literal> element allows a <literal>Map</literal>
+                to be mapped as a component, where the property names refer to keys of the map, see
+                <xref linkend="components-dynamic"/>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-properties" revision="2">
+            <title>properties</title>
+
+            <para>
+                The <literal>&lt;properties&gt;</literal> element allows the definition of a named,
+                logical grouping of properties of a class. The most important use of the construct
+                is that it allows a combination of properties to be the target of a
+                <literal>property-ref</literal>. It is also a convenient way to define a multi-column
+                unique constraint.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="properties1" coords="2 45"/>
+                    <area id="properties2" coords="3 45"/>
+                    <area id="properties3" coords="4 45"/>
+                    <area id="properties4" coords="5 45"/>
+                    <area id="properties5" coords="6 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<properties
+        name="logicalName"
+        insert="true|false"
+        update="true|false"
+        optimistic-lock="true|false"
+        unique="true|false"
+>
+
+        <property ...../>
+        <many-to-one .... />
+        ........
+</properties>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="properties1">
+                        <para>
+                            <literal>name</literal>: The logical name of the grouping -
+                            <emphasis>not</emphasis> an actual property name.
+                        </para>
+                    </callout>
+                    <callout arearefs="properties2">
+                        <para>
+                            <literal>insert</literal>: Do the mapped columns appear in SQL
+                            <literal>INSERT</literal>s?
+                        </para>
+                    </callout>
+                    <callout arearefs="properties3">
+                        <para>
+                            <literal>update</literal>: Do the mapped columns appear in SQL
+                            <literal>UPDATE</literal>s?
+                        </para>
+                    </callout>
+                    <callout arearefs="properties4">
+                            <para>
+                                <literal>optimistic-lock</literal> (optional - defaults to <literal>true</literal>):
+                                Specifies that updates to these properties do or do not require acquisition of the
+                                optimistic lock. In other words, determines if a version increment should occur when
+                                these properties are dirty.
+                            </para>
+                    </callout>
+                    <callout arearefs="properties5">
+                            <para>
+                                <literal>unique</literal> (optional - defaults to <literal>false</literal>):
+                                Specifies that a unique constraint exists upon all mapped columns of the
+                                component.
+                            </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                For example, if we have the following <literal>&lt;properties&gt;</literal> mapping:
+            </para>
+
+            <programlisting><![CDATA[<class name="Person">
+    <id name="personNumber"/>
+    ...
+    <properties name="name"
+            unique="true" update="false">
+        <property name="firstName"/>
+        <property name="initial"/>
+        <property name="lastName"/>
+    </properties>
+</class>]]></programlisting>
+
+            <para>
+                Then we might have some legacy data association which refers to this unique key of
+                the <literal>Person</literal> table, instead of to the primary key:
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="person"
+         class="Person" property-ref="name">
+    <column name="firstName"/>
+    <column name="initial"/>
+    <column name="lastName"/>
+</many-to-one>]]></programlisting>
+
+            <para>
+                We don't recommend the use of this kind of thing outside the context of mapping
+                legacy data.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-subclass" revision="4">
+            <title>subclass</title>
+
+            <para>
+                Finally, polymorphic persistence requires the declaration of each subclass of
+                the root persistent class. For the table-per-class-hierarchy
+                mapping strategy, the <literal>&lt;subclass&gt;</literal> declaration is used.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="subclass1" coords="2 55"/>
+                    <area id="subclass2" coords="3 55"/>
+                    <area id="subclass3" coords="4 55"/>
+                    <area id="subclass4" coords="5 55"/>
+                </areaspec>
+                <programlisting><![CDATA[<subclass
+        name="ClassName"
+        discriminator-value="discriminator_value"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        entity-name="EntityName"
+        node="element-name"
+        extends="SuperclassName">
+
+        <property .... />
+        .....
+</subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="subclass1">
+                        <para>
+                            <literal>name</literal>: The fully qualified class name of the subclass.
+                        </para>
+                    </callout>
+                    <callout arearefs="subclass2">
+                        <para>
+                            <literal>discriminator-value</literal> (optional - defaults to the class name): A
+                            value that distiguishes individual subclasses.
+                        </para>
+                    </callout>
+                    <callout arearefs="subclass3">
+                        <para>
+                            <literal>proxy</literal> (optional): Specifies a class or interface to use for
+                            lazy initializing proxies.
+                        </para>
+                    </callout>
+                    <callout arearefs="subclass4">
+                        <para>
+                            <literal>lazy</literal> (optional, defaults to <literal>true</literal>): Setting
+                            <literal>lazy="false"</literal> disables the use of lazy fetching.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Each subclass should declare its own persistent properties and subclasses.
+                <literal>&lt;version&gt;</literal> and <literal>&lt;id&gt;</literal> properties
+                are assumed to be inherited from the root class. Each subclass in a heirarchy must
+                define a unique <literal>discriminator-value</literal>. If none is specified, the
+                fully qualified Java class name is used.
+            </para>
+
+            <para>
+                For information about inheritance mappings, see <xref linkend="inheritance"/>.
+            </para>
+
+        </sect2>
+
+         <sect2 id="mapping-declaration-joinedsubclass" revision="3">
+            <title>joined-subclass</title>
+
+            <para>
+                Alternatively, each subclass may be mapped to its own table (table-per-subclass
+                mapping strategy). Inherited state is retrieved by joining with the table of the
+                superclass. We use the <literal>&lt;joined-subclass&gt;</literal> element.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="joinedsubclass1" coords="2 45"/>
+                    <area id="joinedsubclass2" coords="3 45"/>
+                    <area id="joinedsubclass3" coords="4 45"/>
+                    <area id="joinedsubclass4" coords="5 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<joined-subclass
+        name="ClassName"
+        table="tablename"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        schema="schema"
+        catalog="catalog"
+        extends="SuperclassName"
+        persister="ClassName"
+        subselect="SQL expression"
+        entity-name="EntityName"
+        node="element-name">
+
+        <key .... >
+
+        <property .... />
+        .....
+</joined-subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="joinedsubclass1">
+                        <para>
+                            <literal>name</literal>: The fully qualified class name of the subclass.
+                        </para>
+                    </callout>
+                    <callout arearefs="joinedsubclass2">
+                        <para>
+                            <literal>table</literal>: The name of the subclass table.
+                        </para>
+                    </callout>
+                    <callout arearefs="joinedsubclass3">
+                        <para>
+                            <literal>proxy</literal> (optional): Specifies a class or interface to use
+                            for lazy initializing proxies.
+                        </para>
+                    </callout>
+                    <callout arearefs="joinedsubclass4">
+                        <para>
+                             <literal>lazy</literal> (optional, defaults to <literal>true</literal>): Setting
+                            <literal>lazy="false"</literal> disables the use of lazy fetching.
+                         </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                No discriminator column is required for this mapping strategy. Each subclass must,
+                however, declare a table column holding the object identifier using the
+                <literal>&lt;key&gt;</literal> element. The mapping at the start of the chapter
+                would be re-written as:
+            </para>
+
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+        <class name="Cat" table="CATS">
+                <id name="id" column="uid" type="long">
+                        <generator class="hilo"/>
+                </id>
+                <property name="birthdate" type="date"/>
+                <property name="color" not-null="true"/>
+                <property name="sex" not-null="true"/>
+                <property name="weight"/>
+                <many-to-one name="mate"/>
+                <set name="kittens">
+                        <key column="MOTHER"/>
+                        <one-to-many class="Cat"/>
+                </set>
+                <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
+                    <key column="CAT"/>
+                    <property name="name" type="string"/>
+                </joined-subclass>
+        </class>
+
+        <class name="eg.Dog">
+                <!-- mapping for Dog could go here -->
+        </class>
+
+</hibernate-mapping>]]></programlisting>
+
+             <para>
+                 For information about inheritance mappings, see <xref linkend="inheritance"/>.
+             </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-unionsubclass" revision="2">
+           <title>union-subclass</title>
+
+           <para>
+               A third option is to map only the concrete classes of an inheritance hierarchy
+               to tables, (the table-per-concrete-class strategy) where each table defines all
+               persistent state of the class, including inherited state. In Hibernate, it is
+               not absolutely necessary to explicitly map such inheritance hierarchies. You
+               can simply map each class with a separate <literal>&lt;class&gt;</literal>
+               declaration. However, if you wish use polymorphic associations (e.g. an association
+               to the superclass of your hierarchy), you need to
+               use the <literal>&lt;union-subclass&gt;</literal> mapping.
+           </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="unionsubclass1" coords="2 45"/>
+                    <area id="unionsubclass2" coords="3 45"/>
+                    <area id="unionsubclass3" coords="4 45"/>
+                    <area id="unionsubclass4" coords="5 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<union-subclass
+        name="ClassName"
+        table="tablename"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        schema="schema"
+        catalog="catalog"
+        extends="SuperclassName"
+        abstract="true|false"
+        persister="ClassName"
+        subselect="SQL expression"
+        entity-name="EntityName"
+        node="element-name">
+
+        <property .... />
+        .....
+</union-subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="unionsubclass1">
+                        <para>
+                            <literal>name</literal>: The fully qualified class name of the subclass.
+                        </para>
+                    </callout>
+                    <callout arearefs="unionsubclass2">
+                        <para>
+                            <literal>table</literal>: The name of the subclass table.
+                        </para>
+                    </callout>
+                    <callout arearefs="unionsubclass3">
+                        <para>
+                            <literal>proxy</literal> (optional): Specifies a class or interface to use
+                            for lazy initializing proxies.
+                        </para>
+                    </callout>
+                    <callout arearefs="unionsubclass4">
+                        <para>
+                            <literal>lazy</literal> (optional, defaults to <literal>true</literal>): Setting
+                            <literal>lazy="false"</literal> disables the use of lazy fetching.
+                         </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                No discriminator column or key column is required for this mapping strategy.
+            </para>
+
+            <para>
+                For information about inheritance mappings, see <xref linkend="inheritance"/>.
+            </para>
+
+        </sect2>
+
+   	<sect2 id="mapping-declaration-join" revision="3">
+            <title>join</title>
+
+            <para>
+                Using the <literal>&lt;join&gt;</literal> element, it is possible to map
+                properties of one class to several tables, when there's a 1-to-1 relationship between the tables.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="join1" coords="2 50"/>
+                    <area id="join2" coords="3 50"/>
+                    <area id="join3" coords="4 50"/>
+                    <area id="join4" coords="5 50"/>
+                    <area id="join5" coords="6 50"/>
+                    <area id="join6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<join
+        table="tablename"
+        schema="owner"
+        catalog="catalog"
+        fetch="join|select"
+        inverse="true|false"
+        optional="true|false">
+
+        <key ... />
+
+        <property ... />
+        ...
+</join>]]></programlisting>
+
+                <calloutlist>
+                    <callout arearefs="join1">
+                        <para>
+                            <literal>table</literal>: The name of the joined table.
+                        </para>
+                    </callout>
+                    <callout arearefs="join2">
+                        <para>
+                            <literal>schema</literal> (optional): Override the schema name specified by
+                            the root <literal>&lt;hibernate-mapping&gt;</literal> element.
+                        </para>
+                    </callout>
+                    <callout arearefs="join3">
+                        <para>
+                            <literal>catalog</literal> (optional): Override the catalog name specified by
+                            the root <literal>&lt;hibernate-mapping&gt;</literal> element.
+                        </para>
+                    </callout>
+                    <callout arearefs="join4">
+                        <para>
+                            <literal>fetch</literal> (optional - defaults to <literal>join</literal>):
+                            If set to <literal>join</literal>, the default, Hibernate will use an inner join
+                            to retrieve a <literal>&lt;join&gt;</literal> defined by a class or its superclasses
+                            and an outer join for a <literal>&lt;join&gt;</literal> defined by a subclass.
+                            If set to <literal>select</literal> then Hibernate will use a sequential select for
+                            a <literal>&lt;join&gt;</literal> defined on a subclass, which will be issued only
+                            if a row turns out to represent an instance of the subclass. Inner joins will still
+                            be used to retrieve a <literal>&lt;join&gt;</literal> defined by the class and its
+                            superclasses.
+                        </para>
+                    </callout>
+                    <callout arearefs="join5">
+                        <para>
+                            <literal>inverse</literal> (optional - defaults to <literal>false</literal>):
+                            If enabled, Hibernate will not try to insert or update the properties defined
+                            by this join.
+                        </para>
+                    </callout>
+                    <callout arearefs="join6">
+                        <para>
+                            <literal>optional</literal> (optional - defaults to <literal>false</literal>):
+                            If enabled, Hibernate will insert a row only if the properties defined by this
+                            join are non-null and will always use an outer join to retrieve the properties.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                For example, the address information for a person can be mapped to a separate
+                table (while preserving value type semantics for all properties):
+            </para>
+
+            <programlisting><![CDATA[<class name="Person"
+    table="PERSON">
+
+    <id name="id" column="PERSON_ID">...</id>
+
+    <join table="ADDRESS">
+        <key column="ADDRESS_ID"/>
+        <property name="address"/>
+        <property name="zip"/>
+        <property name="country"/>
+    </join>
+    ...]]></programlisting>
+
+            <para>
+                This feature is often only useful for legacy data models, we recommend fewer
+                tables than classes and a fine-grained domain model. However, it is useful
+                for switching between inheritance mapping strategies in a single hierarchy, as
+                explained later.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-key">
+            <title>key</title>
+
+            <para>
+                We've seen the <literal>&lt;key&gt;</literal> element crop up a few times
+                now. It appears anywhere the parent mapping element defines a join to
+                a new table, and defines the foreign key in the joined table, that references
+                the primary key of the original table.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="key1" coords="2 50"/>
+                    <area id="key2" coords="3 50"/>
+                    <area id="key3" coords="4 50"/>
+                    <area id="key4" coords="5 50"/>
+                    <area id="key5" coords="6 50"/>
+                    <area id="key6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<key
+        column="columnname"
+        on-delete="noaction|cascade"
+        property-ref="propertyName"
+        not-null="true|false"
+        update="true|false"
+        unique="true|false"
+/>]]></programlisting>
+
+                <calloutlist>
+                    <callout arearefs="key1">
+                        <para>
+                            <literal>column</literal> (optional): The name of the foreign key column.
+                            This may also be specified by nested <literal>&lt;column&gt;</literal>
+                            element(s).
+                        </para>
+                    </callout>
+                    <callout arearefs="key2">
+                        <para>
+                            <literal>on-delete</literal> (optional, defaults to <literal>noaction</literal>):
+                            Specifies whether the foreign key constraint has database-level cascade delete
+                            enabled.
+                        </para>
+                    </callout>
+                    <callout arearefs="key3">
+                        <para>
+                            <literal>property-ref</literal> (optional): Specifies that the foreign key refers
+                            to columns that are not the primary key of the orginal table. (Provided for
+                            legacy data.)
+                        </para>
+                    </callout>
+                    <callout arearefs="key4">
+                        <para>
+                            <literal>not-null</literal> (optional): Specifies that the foreign key columns
+                            are not nullable (this is implied whenever the foreign key is also part of the
+                            primary key).
+                        </para>
+                    </callout>
+                    <callout arearefs="key5">
+                        <para>
+                            <literal>update</literal> (optional): Specifies that the foreign key should never
+                            be updated (this is implied whenever the foreign key is also part of the primary
+                            key).
+                        </para>
+                    </callout>
+                    <callout arearefs="key6">
+                        <para>
+                            <literal>unique</literal> (optional): Specifies that the foreign key should have
+                            a unique constraint (this is implied whenever the foreign key is also the primary key).
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                We recommend that for systems where delete performance is important, all keys should be
+                defined <literal>on-delete="cascade"</literal>, and Hibernate will use a database-level
+                <literal>ON CASCADE DELETE</literal> constraint, instead of many individual
+                <literal>DELETE</literal> statements. Be aware that this feature bypasses Hibernate's
+                usual optimistic locking strategy for versioned data.
+            </para>
+
+            <para>
+                The <literal>not-null</literal> and <literal>update</literal> attributes are useful when
+                mapping a unidirectional one to many association. If you map a unidirectional one to many
+                to a non-nullable foreign key, you <emphasis>must</emphasis> declare the key column using
+                <literal>&lt;key not-null="true"&gt;</literal>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-column" revision="4">
+           <title>column and formula elements</title>
+           <para>
+               Any mapping element which accepts a <literal>column</literal> attribute will alternatively
+               accept a <literal>&lt;column&gt;</literal> subelement. Likewise, <literal>&lt;formula&gt;</literal>
+               is an alternative to the <literal>formula</literal> attribute.
+           </para>
+
+           <programlisting><![CDATA[<column
+        name="column_name"
+        length="N"
+        precision="N"
+        scale="N"
+        not-null="true|false"
+        unique="true|false"
+        unique-key="multicolumn_unique_key_name"
+        index="index_name"
+        sql-type="sql_type_name"
+        check="SQL expression"
+        default="SQL expression"/>]]></programlisting>
+
+            <programlisting><![CDATA[<formula>SQL expression</formula>]]></programlisting>
+
+            <para>
+                <literal>column</literal> and <literal>formula</literal> attributes may even be combined
+                within the same property or association mapping to express, for example, exotic join
+                conditions.
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="homeAddress" class="Address"
+        insert="false" update="false">
+    <column name="person_id" not-null="true" length="10"/>
+    <formula>'MAILING'</formula>
+</many-to-one>]]></programlisting>
+
+    </sect2>
+
+        <sect2 id="mapping-declaration-import">
+            <title>import</title>
+
+            <para>
+                Suppose your application has two persistent classes with the same name, and you don't want to
+                specify the fully qualified (package) name in Hibernate queries. Classes may be "imported"
+                explicitly, rather than relying upon <literal>auto-import="true"</literal>. You may even import
+                classes and interfaces that are not explicitly mapped.
+            </para>
+
+            <programlisting><![CDATA[<import class="java.lang.Object" rename="Universe"/>]]></programlisting>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="import1" coords="2 40"/>
+                    <area id="import2" coords="3 40"/>
+                </areaspec>
+                <programlisting><![CDATA[<import
+        class="ClassName"
+        rename="ShortName"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="import1">
+                        <para>
+                            <literal>class</literal>: The fully qualified class name of of any Java class.
+                        </para>
+                    </callout>
+                    <callout arearefs="import2">
+                        <para>
+                            <literal>rename</literal> (optional - defaults to the unqualified class name):
+                            A name that may be used in the query language.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+        </sect2>
+
+        <sect2 id="mapping-types-anymapping" revision="2">
+            <title>any</title>
+
+            <para>
+                There is one further type of property mapping. The <literal>&lt;any&gt;</literal> mapping element
+                defines a polymorphic association to classes from multiple tables. This type of mapping always
+                requires more than one column. The first column holds the type of the associated entity.
+                The remaining columns hold the identifier. It is impossible to specify a foreign key constraint
+                for this kind of association, so this is most certainly not meant as the usual way of mapping
+                (polymorphic) associations. You should use this only in very special cases (eg. audit logs,
+                user session data, etc).
+            </para>
+
+            <para>
+                 The <literal>meta-type</literal> attribute lets the application specify a custom type that
+                 maps database column values to persistent classes which have identifier properties of the
+                 type specified by <literal>id-type</literal>. You must specify the mapping from values of
+                 the meta-type to class names.
+            </para>
+
+            <programlisting><![CDATA[<any name="being" id-type="long" meta-type="string">
+    <meta-value value="TBL_ANIMAL" class="Animal"/>
+    <meta-value value="TBL_HUMAN" class="Human"/>
+    <meta-value value="TBL_ALIEN" class="Alien"/>
+    <column name="table_name"/>
+    <column name="id"/>
+</any>]]></programlisting>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="any1" coords="2 50"/>
+                    <area id="any2" coords="3 50"/>
+                    <area id="any3" coords="4 50"/>
+                    <area id="any4" coords="5 50"/>
+                    <area id="any5" coords="6 50"/>
+                    <area id="any6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<any
+        name="propertyName"
+        id-type="idtypename"
+        meta-type="metatypename"
+        cascade="cascade_style"
+        access="field|property|ClassName"
+        optimistic-lock="true|false"
+>
+        <meta-value ... />
+        <meta-value ... />
+        .....
+        <column .... />
+        <column .... />
+        .....
+</any>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="any1">
+                        <para>
+                            <literal>name</literal>: the property name.
+                        </para>
+                    </callout>
+                    <callout arearefs="any2">
+                        <para>
+                            <literal>id-type</literal>: the identifier type.
+                        </para>
+                    </callout>
+                    <callout arearefs="any3">
+                        <para>
+                            <literal>meta-type</literal> (optional - defaults to <literal>string</literal>):
+                            Any type that is allowed for a discriminator mapping.
+                        </para>
+                    </callout>
+                    <callout arearefs="any4">
+                        <para>
+                            <literal>cascade</literal> (optional- defaults to <literal>none</literal>):
+                            the cascade style.
+                        </para>
+                    </callout>
+                    <callout arearefs="any5">
+                        <para>
+                            <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+                            strategy Hibernate should use for accessing the property value.
+                        </para>
+                    </callout>
+                    <callout arearefs="any6">
+                        <para>
+                            <literal>optimistic-lock</literal> (optional - defaults to <literal>true</literal>):
+                            Specifies that updates to this property do or do not require acquisition of the
+                            optimistic lock. In other words, define if a version increment should occur if this
+                            property is dirty.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+      </sect2>
+
+    </sect1>
+
+    <sect1 id="mapping-types">
+        <title>Hibernate Types</title>
+
+        <sect2 id="mapping-types-entitiesvalues" revision="1">
+            <title>Entities and values</title>
+
+            <para>
+                To understand the behaviour of various Java language-level objects with respect
+                to the persistence service, we need to classify them into two groups:
+            </para>
+
+            <para>
+                An <emphasis>entity</emphasis> exists independently of any other objects holding
+                references to the entity. Contrast this with the usual Java model where an
+                unreferenced object is garbage collected. Entities must be explicitly saved and
+                deleted (except that saves and deletions may be <emphasis>cascaded</emphasis>
+                from a parent entity to its children). This is different from the ODMG model of
+                object persistence by reachablity - and corresponds more closely to how
+                application objects are usually used in large systems. Entities support
+                circular and shared references. They may also be versioned.
+            </para>
+
+            <para>
+                An entity's persistent state consists of references to other entities and
+                instances of <emphasis>value</emphasis> types. Values are primitives,
+                collections (not what's inside a collection), components and certain immutable
+                objects. Unlike entities, values (in particular collections and components)
+                <emphasis>are</emphasis> persisted and deleted by reachability. Since value
+                objects (and primitives) are persisted and deleted along with their containing
+                entity they may not be independently versioned. Values have no independent
+                identity, so they cannot be shared by two entities or collections.
+            </para>
+
+            <para>
+                Up until now, we've been using the term "persistent class" to refer to
+                entities. We will continue to do that. Strictly speaking, however, not all
+                user-defined classes with persistent state are entities. A
+                <emphasis>component</emphasis> is a user defined class with value semantics.
+                A Java property of type <literal>java.lang.String</literal> also has value
+                semantics. Given this definition, we can say that all types (classes) provided
+                by the JDK have value type semantics in Java, while user-defined types may
+                be mapped with entity or value type semantics. This decision is up to the
+                application developer. A good hint for an entity class in a domain model are
+                shared references to a single instance of that class, while composition or
+                aggregation usually translates to a value type.
+            </para>
+
+            <para>
+                We'll revisit both concepts throughout the documentation.
+            </para>
+
+            <para>
+                The challenge is to map the Java type system (and the developers' definition of
+                entities and value types) to the SQL/database type system. The bridge between
+                both systems is provided by Hibernate: for entities we use
+                <literal>&lt;class&gt;</literal>, <literal>&lt;subclass&gt;</literal> and so on.
+                For value types we use <literal>&lt;property&gt;</literal>,
+                <literal>&lt;component&gt;</literal>, etc, usually with a <literal>type</literal>
+                attribute. The value of this attribute is the name of a Hibernate
+                <emphasis>mapping type</emphasis>. Hibernate provides many mappings (for standard
+                JDK value types) out of the box. You can write your own mapping types and implement your
+                custom conversion strategies as well, as you'll see later.
+            </para>
+
+            <para>
+                All built-in Hibernate types except collections support null semantics.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-types-basictypes" revision="3">
+            <title>Basic value types</title>
+
+            <para>
+                The built-in <emphasis>basic mapping types</emphasis> may be roughly categorized into
+
+                <variablelist>
+                    <varlistentry>
+                        <term><literal>integer, long, short, float, double, character, byte,
+                            boolean, yes_no, true_false</literal></term>
+                        <listitem>
+                            <para>
+                                Type mappings from Java primitives or wrapper classes to appropriate
+                                (vendor-specific) SQL column types. <literal>boolean, yes_no</literal>
+                                and <literal>true_false</literal> are all alternative encodings for
+                                a Java <literal>boolean</literal> or <literal>java.lang.Boolean</literal>.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>string</literal></term>
+                        <listitem>
+                            <para>
+                                A type mapping from <literal>java.lang.String</literal> to
+                                <literal>VARCHAR</literal> (or Oracle <literal>VARCHAR2</literal>).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>date, time, timestamp</literal></term>
+                        <listitem>
+                            <para>
+                                Type mappings from <literal>java.util.Date</literal> and its subclasses
+                                to SQL types <literal>DATE</literal>, <literal>TIME</literal> and
+                                <literal>TIMESTAMP</literal> (or equivalent).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>calendar, calendar_date</literal></term>
+                        <listitem>
+                            <para>
+                                Type mappings from <literal>java.util.Calendar</literal> to
+                                SQL types <literal>TIMESTAMP</literal> and <literal>DATE</literal>
+                                (or equivalent).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>big_decimal, big_integer</literal></term>
+                        <listitem>
+                            <para>
+                                Type mappings from <literal>java.math.BigDecimal</literal> and
+                                <literal>java.math.BigInteger</literal> to <literal>NUMERIC</literal>
+                                (or Oracle <literal>NUMBER</literal>).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>locale, timezone, currency</literal></term>
+                        <listitem>
+                            <para>
+                                Type mappings from <literal>java.util.Locale</literal>,
+                                <literal>java.util.TimeZone</literal> and
+                                <literal>java.util.Currency</literal>
+                                to <literal>VARCHAR</literal> (or Oracle <literal>VARCHAR2</literal>).
+                                Instances of <literal>Locale</literal> and <literal>Currency</literal> are
+                                mapped to their ISO codes. Instances of <literal>TimeZone</literal> are
+                                mapped to their <literal>ID</literal>.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>class</literal></term>
+                        <listitem>
+                            <para>
+                                A type mapping from <literal>java.lang.Class</literal> to
+                                <literal>VARCHAR</literal> (or Oracle <literal>VARCHAR2</literal>).
+                                A <literal>Class</literal> is mapped to its fully qualified name.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>binary</literal></term>
+                        <listitem>
+                            <para>
+                                Maps byte arrays to an appropriate SQL binary type.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>text</literal></term>
+                        <listitem>
+                            <para>
+                                Maps long Java strings to a SQL <literal>CLOB</literal> or
+                                <literal>TEXT</literal> type.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>serializable</literal></term>
+                        <listitem>
+                            <para>
+                                Maps serializable Java types to an appropriate SQL binary type. You
+                                may also indicate the Hibernate type <literal>serializable</literal> with
+                                the name of a serializable Java class or interface that does not default
+                                to a basic type.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>clob, blob</literal></term>
+                        <listitem>
+                            <para>
+                                Type mappings for the JDBC classes <literal>java.sql.Clob</literal> and
+                                <literal>java.sql.Blob</literal>. These types may be inconvenient for some
+                                applications, since the blob or clob object may not be reused outside of
+                                a transaction. (Furthermore, driver support is patchy and inconsistent.)
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date,
+                            imm_serializable, imm_binary</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                Type mappings for what are usually considered mutable Java types, where
+                                Hibernate makes certain optimizations appropriate only for immutable
+                                Java types, and the application treats the object as immutable. For
+                                example, you should not call <literal>Date.setTime()</literal> for an
+                                instance mapped as <literal>imm_timestamp</literal>. To change the
+                                value of the property, and have that change made persistent, the
+                                application must assign a new (nonidentical) object to the property.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                </variablelist>
+
+            </para>
+
+            <para>
+                Unique identifiers of entities and collections may be of any basic type except
+                <literal>binary</literal>, <literal>blob</literal> and <literal>clob</literal>.
+                (Composite identifiers are also allowed, see below.)
+            </para>
+
+            <para>
+                The basic value types have corresponding <literal>Type</literal> constants defined on
+                <literal>org.hibernate.Hibernate</literal>. For example, <literal>Hibernate.STRING</literal>
+                represents the <literal>string</literal> type.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-types-custom" revision="2">
+            <title>Custom value types</title>
+
+            <para>
+                It is relatively easy for developers to create their own value types. For example,
+                you might want to persist properties of type <literal>java.lang.BigInteger</literal>
+                to <literal>VARCHAR</literal> columns. Hibernate does not provide a built-in type
+                for this. But custom types are not limited to mapping a property (or collection element)
+                to a single table column. So, for example, you might have a Java property
+                <literal>getName()</literal>/<literal>setName()</literal> of type
+                <literal>java.lang.String</literal> that is persisted to the columns
+                <literal>FIRST_NAME</literal>, <literal>INITIAL</literal>, <literal>SURNAME</literal>.
+            </para>
+
+            <para>
+                To implement a custom type, implement either <literal>org.hibernate.UserType</literal>
+                or <literal>org.hibernate.CompositeUserType</literal> and declare properties using the
+                fully qualified classname of the type. Check out
+                <literal>org.hibernate.test.DoubleStringType</literal> to see the kind of things that
+                are possible.
+            </para>
+
+            <programlisting><![CDATA[<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
+    <column name="first_string"/>
+    <column name="second_string"/>
+</property>]]></programlisting>
+
+            <para>
+                Notice the use of <literal>&lt;column&gt;</literal> tags to map a property to multiple
+                columns.
+            </para>
+
+            <para>
+                The <literal>CompositeUserType</literal>, <literal>EnhancedUserType</literal>,
+                <literal>UserCollectionType</literal>, and <literal>UserVersionType</literal>
+                interfaces provide support for more specialized uses.
+            </para>
+
+            <para>
+                You may even supply parameters to a <literal>UserType</literal> in the mapping file. To
+                do this, your <literal>UserType</literal> must implement the
+                <literal>org.hibernate.usertype.ParameterizedType</literal> interface. To supply parameters
+                to your custom type, you can use the <literal>&lt;type&gt;</literal> element in your mapping
+                files.
+            </para>
+
+            <programlisting><![CDATA[<property name="priority">
+    <type name="com.mycompany.usertypes.DefaultValueIntegerType">
+        <param name="default">0</param>
+    </type>
+</property>]]></programlisting>
+
+            <para>
+                The <literal>UserType</literal> can now retrieve the value for the parameter named
+                <literal>default</literal> from the <literal>Properties</literal> object passed to it.
+            </para>
+
+            <para>
+                If you use a certain <literal>UserType</literal> very often, it may be useful to define a
+                shorter name for it. You can do this using the <literal>&lt;typedef&gt;</literal> element.
+                Typedefs assign a name to a custom type, and may also contain a list of default
+                parameter values if the type is parameterized.
+            </para>
+
+            <programlisting><![CDATA[<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
+    <param name="default">0</param>
+</typedef>]]></programlisting>
+
+            <programlisting><![CDATA[<property name="priority" type="default_zero"/>]]></programlisting>
+
+            <para>
+                It is also possible to override the parameters supplied in a typedef on a case-by-case basis
+                by using type parameters on the property mapping.
+            </para>
+
+            <para>
+                Even though Hibernate's rich range of built-in types and support for components means you
+                will very rarely <emphasis>need</emphasis> to use a custom type, it is nevertheless
+                considered good form to use custom types for (non-entity) classes that occur frequently
+                in your application. For example, a <literal>MonetaryAmount</literal> class is a good
+                candidate for a <literal>CompositeUserType</literal>, even though it could easily be mapped
+                as a component. One motivation for this is abstraction. With a custom type, your mapping
+                documents would be future-proofed against possible changes in your way of representing
+                monetary values.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="mapping-entityname">
+        <title>Mapping a class more than once</title>
+        <para>
+            It is possible to provide more than one mapping for a particular persistent class. In this
+            case you must specify an <emphasis>entity name</emphasis> do disambiguate between instances
+            of the two mapped entities. (By default, the entity name is the same as the class name.)
+            Hibernate lets you specify the entity name when working with persistent objects, when writing
+            queries, or when mapping associations to the named entity.
+        </para>
+
+        <programlisting><![CDATA[<class name="Contract" table="Contracts"
+        entity-name="CurrentContract">
+    ...
+    <set name="history" inverse="true"
+            order-by="effectiveEndDate desc">
+        <key column="currentContractId"/>
+        <one-to-many entity-name="HistoricalContract"/>
+    </set>
+</class>
+
+<class name="Contract" table="ContractHistory"
+        entity-name="HistoricalContract">
+    ...
+    <many-to-one name="currentContract"
+            column="currentContractId"
+            entity-name="CurrentContract"/>
+</class>]]></programlisting>
+
+        <para>
+            Notice how associations are now specified using <literal>entity-name</literal> instead of
+            <literal>class</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="mapping-quotedidentifiers">
+            <title>SQL quoted identifiers</title>
+            <para>
+                You may force Hibernate to quote an identifier in the generated SQL by enclosing the table or
+                column name in backticks in the mapping document. Hibernate will use the correct quotation
+                style for the SQL <literal>Dialect</literal> (usually double quotes, but brackets for SQL
+                Server and backticks for MySQL).
+            </para>
+
+            <programlisting><![CDATA[<class name="LineItem" table="`Line Item`">
+    <id name="id" column="`Item Id`"/><generator class="assigned"/></id>
+    <property name="itemNumber" column="`Item #`"/>
+    ...
+</class>]]></programlisting>
+
+    </sect1>
+
+
+   	<sect1 id="mapping-alternatives">
+   	<title>Metadata alternatives</title>
+
+   	<para>
+   	    XML isn't for everyone, and so there are some alternative ways to define O/R mapping metadata in Hibernate.
+   	</para>
+
+    <sect2 id="mapping-xdoclet">
+        <title>Using XDoclet markup</title>
+
+        <para>
+            Many Hibernate users prefer to embed mapping information directly in sourcecode using
+            XDoclet <literal>@hibernate.tags</literal>. We will not cover this approach in this
+            document, since strictly it is considered part of XDoclet. However, we include the
+            following example of the <literal>Cat</literal> class with XDoclet mappings.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+/**
+ * @hibernate.class
+ *  table="CATS"
+ */
+public class Cat {
+    private Long id; // identifier
+    private Date birthdate;
+    private Cat mother;
+    private Set kittens
+    private Color color;
+    private char sex;
+    private float weight;
+
+    /*
+     * @hibernate.id
+     *  generator-class="native"
+     *  column="CAT_ID"
+     */
+    public Long getId() {
+        return id;
+    }
+    private void setId(Long id) {
+        this.id=id;
+    }
+
+    /**
+     * @hibernate.many-to-one
+     *  column="PARENT_ID"
+     */
+    public Cat getMother() {
+        return mother;
+    }
+    void setMother(Cat mother) {
+        this.mother = mother;
+    }
+
+    /**
+     * @hibernate.property
+     *  column="BIRTH_DATE"
+     */
+    public Date getBirthdate() {
+        return birthdate;
+    }
+    void setBirthdate(Date date) {
+        birthdate = date;
+    }
+    /**
+     * @hibernate.property
+     *  column="WEIGHT"
+     */
+    public float getWeight() {
+        return weight;
+    }
+    void setWeight(float weight) {
+        this.weight = weight;
+    }
+
+    /**
+     * @hibernate.property
+     *  column="COLOR"
+     *  not-null="true"
+     */
+    public Color getColor() {
+        return color;
+    }
+    void setColor(Color color) {
+        this.color = color;
+    }
+    /**
+     * @hibernate.set
+     *  inverse="true"
+     *  order-by="BIRTH_DATE"
+     * @hibernate.collection-key
+     *  column="PARENT_ID"
+     * @hibernate.collection-one-to-many
+     */
+    public Set getKittens() {
+        return kittens;
+    }
+    void setKittens(Set kittens) {
+        this.kittens = kittens;
+    }
+    // addKitten not needed by Hibernate
+    public void addKitten(Cat kitten) {
+        kittens.add(kitten);
+    }
+
+    /**
+     * @hibernate.property
+     *  column="SEX"
+     *  not-null="true"
+     *  update="false"
+     */
+    public char getSex() {
+        return sex;
+    }
+    void setSex(char sex) {
+        this.sex=sex;
+    }
+}]]></programlisting>
+
+        <para>
+            See the Hibernate web site for more examples of XDoclet and Hibernate.
+        </para>
+
+    </sect2>
+
+    <sect2 id="mapping-annotations" revision="2">
+        <title>Using JDK 5.0 Annotations</title>
+
+        <para>
+            JDK 5.0 introduced XDoclet-style annotations at the language level, type-safe and
+            checked at compile time. This mechnism is more powerful than XDoclet annotations and
+            better supported by tools and IDEs. IntelliJ IDEA, for example, supports auto-completion
+            and syntax highlighting of JDK 5.0 annotations. The new revision of the EJB specification
+            (JSR-220) uses JDK 5.0 annotations as the primary metadata mechanism for entity beans.
+            Hibernate3 implements the <literal>EntityManager</literal> of JSR-220 (the persistence API),
+            support for mapping metadata is available via the <emphasis>Hibernate Annotations</emphasis>
+            package, as a separate download. Both EJB3 (JSR-220) and Hibernate3 metadata is supported.
+        </para>
+
+        <para>
+            This is an example of a POJO class annotated as an EJB entity bean:
+        </para>
+
+        <programlisting><![CDATA[@Entity(access = AccessType.FIELD)
+public class Customer implements Serializable {
+
+    @Id;
+    Long id;
+
+    String firstName;
+    String lastName;
+    Date birthday;
+
+    @Transient
+    Integer age;
+
+    @Embedded
+    private Address homeAddress;
+
+    @OneToMany(cascade=CascadeType.ALL)
+    @JoinColumn(name="CUSTOMER_ID")
+    Set<Order> orders;
+
+    // Getter/setter and business methods
+}]]></programlisting>
+
+        <para>
+            Note that support for JDK 5.0 Annotations (and JSR-220) is still work in progress and
+            not completed. Please refer to the Hibernate Annotations module for more details.
+        </para>
+
+    </sect2>
+    </sect1>
+
+    <sect1 id="mapping-generated" revision="1">
+        <title>Generated Properties</title>
+        <para>
+            Generated properties are properties which have their values generated by the
+            database.  Typically, Hibernate applications needed to <literal>refresh</literal>
+            objects which contain any properties for which the database was generating values.
+            Marking properties as generated, however, lets the application delegate this
+            responsibility to Hibernate.  Essentially, whenever Hibernate issues an SQL INSERT
+            or UPDATE for an entity which has defined generated properties, it immediately
+            issues a select afterwards to retrieve the generated values.
+        </para>
+        <para>
+            Properties marked as generated must additionally be non-insertable and non-updateable.
+            Only <xref linkend="mapping-declaration-version">versions</xref>,
+            <xref linkend="mapping-declaration-timestamp">timestamps</xref>, and
+            <xref linkend="mapping-declaration-property">simple properties</xref> can be marked as
+            generated.
+        </para>
+	    <para>
+		    <literal>never</literal> (the default) - means that the given property value
+		    is not generated within the database.
+	    </para>
+	    <para>
+		    <literal>insert</literal> - states that the given property value is generated on
+		    insert, but is not regenerated on subsequent updates.  Things like created-date would
+		    fall into this category.  Note that even thought
+		    <xref linkend="mapping-declaration-version">version</xref> and
+		    <xref linkend="mapping-declaration-timestamp">timestamp</xref> properties can
+		    be marked as generated, this option is not available there...
+	    </para>
+	    <para>
+		    <literal>always</literal> - states that the property value is generated both
+		    on insert and on update.
+	    </para>
+    </sect1>
+
+    <sect1 id="mapping-database-object">
+        <title>Auxiliary Database Objects</title>
+        <para>
+            Allows CREATE and DROP of arbitrary database objects, in conjunction with
+            Hibernate's schema evolution tools, to provide the ability to fully define
+            a user schema within the Hibernate mapping files.  Although designed specifically
+            for creating and dropping things like triggers or stored procedures, really any
+            SQL command that can be run via a <literal>java.sql.Statement.execute()</literal>
+            method is valid here (ALTERs, INSERTS, etc).  There are essentially two modes for
+            defining auxiliary database objects...
+        </para>
+        <para>
+            The first mode is to explicitly list the CREATE and DROP commands out in the mapping
+            file:
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <create>CREATE TRIGGER my_trigger ...</create>
+        <drop>DROP TRIGGER my_trigger</drop>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+        <para>
+            The second mode is to supply a custom class which knows how to construct the
+            CREATE and DROP commands.  This custom class must implement the
+            <literal>org.hibernate.mapping.AuxiliaryDatabaseObject</literal> interface.
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <definition class="MyTriggerDefinition"/>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+        <para>
+            Additionally, these database objects can be optionally scoped such that they only
+            apply when certain dialects are used.
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <definition class="MyTriggerDefinition"/>
+        <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/>
+        <dialect-scope name="org.hibernate.dialect.OracleDialect"/>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+    </sect1>
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/batch.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/batch.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/batch.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,347 @@
+<chapter id="batch">
+    <title>Batch processing</title>
+    
+    <para>
+        A naive approach to inserting 100 000 rows in the database using Hibernate might 
+        look like this:
+    </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+for ( int i=0; i<100000; i++ ) {
+    Customer customer = new Customer(.....);
+    session.save(customer);
+}
+tx.commit();
+session.close();]]></programlisting>
+
+    <para>
+        This would fall over with an <literal>OutOfMemoryException</literal> somewhere 
+        around the 50 000th row. That's because Hibernate caches all the newly inserted 
+        <literal>Customer</literal> instances in the session-level cache. 
+    </para>
+
+    <para>
+        In this chapter we'll show you how to avoid this problem. First, however, if you
+        are doing batch processing, it is absolutely critical that you enable the use of
+        JDBC batching, if you intend to achieve reasonable performance. Set the JDBC batch 
+        size to a reasonable number (say, 10-50):
+    </para>
+    
+<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
+
+    <para id="disablebatching" revision="1">
+        Note that Hibernate disables insert batching at the JDBC level transparently if you
+        use an <literal>identiy</literal> identifier generator.
+    </para>
+
+    <para>
+        You also might like to do this kind of work in a process where interaction with 
+        the second-level cache is completely disabled:
+    </para>
+
+<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
+
+    <para>
+        However, this is not absolutely necessary, since we can explicitly set the
+        <literal>CacheMode</literal> to disable interaction with the second-level cache.
+    </para>
+
+    <sect1 id="batch-inserts">
+        <title>Batch inserts</title>
+
+        <para>
+            When making new objects persistent, you must <literal>flush()</literal> and 
+            then <literal>clear()</literal> the session regularly, to control the size of
+            the first-level cache.
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+   
+for ( int i=0; i<100000; i++ ) {
+    Customer customer = new Customer(.....);
+    session.save(customer);
+    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
+        //flush a batch of inserts and release memory:
+        session.flush();
+        session.clear();
+    }
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="batch-update" >
+        <title>Batch updates</title>
+
+        <para>
+            For retrieving and updating data the same ideas apply. In addition, you need to 
+            use <literal>scroll()</literal> to take advantage of server-side cursors for 
+            queries that return many rows of data.
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+   
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+    .setCacheMode(CacheMode.IGNORE)
+    .scroll(ScrollMode.FORWARD_ONLY);
+int count=0;
+while ( customers.next() ) {
+    Customer customer = (Customer) customers.get(0);
+    customer.updateStuff(...);
+    if ( ++count % 20 == 0 ) {
+        //flush a batch of updates and release memory:
+        session.flush();
+        session.clear();
+    }
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="batch-statelesssession">
+        <title>The StatelessSession interface</title>
+        <para>
+            Alternatively, Hibernate provides a command-oriented API that may be used for 
+            streaming data to and from the database in the form of detached objects. A 
+            <literal>StatelessSession</literal> has no persistence context associated
+            with it and does not provide many of the higher-level lifecycle semantics.
+            In particular, a stateless session does not implement a first-level cache nor
+            interact with any second-level or query cache. It does not implement 
+            transactional write-behind or automatic dirty checking. Operations performed
+            using a stateless session do not ever cascade to associated instances. Collections 
+            are ignored by a stateless session. Operations performed via a stateless session 
+            bypass Hibernate's event model and interceptors. Stateless sessions are vulnerable 
+            to data aliasing effects, due to the lack of a first-level cache. A stateless
+            session is a lower-level abstraction, much closer to the underlying JDBC.
+        </para>
+        
+<programlisting><![CDATA[StatelessSession session = sessionFactory.openStatelessSession();
+Transaction tx = session.beginTransaction();
+   
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+    .scroll(ScrollMode.FORWARD_ONLY);
+while ( customers.next() ) {
+    Customer customer = (Customer) customers.get(0);
+    customer.updateStuff(...);
+    session.update(customer);
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            Note that in this code example, the <literal>Customer</literal> instances returned
+            by the query are immediately detached. They are never associated with any persistence
+            context.
+        </para>
+        
+        <para>
+            The <literal>insert(), update()</literal> and <literal>delete()</literal> operations
+            defined by the <literal>StatelessSession</literal> interface are considered to be
+            direct database row-level operations, which result in immediate execution of a SQL
+            <literal>INSERT, UPDATE</literal> or <literal>DELETE</literal> respectively. Thus,
+            they have very different semantics to the <literal>save(), saveOrUpdate()</literal> 
+            and <literal>delete()</literal> operations defined by the <literal>Session</literal> 
+            interface.
+        </para>
+
+    </sect1>
+
+    <sect1 id="batch-direct" revision="3">
+        <title>DML-style operations</title>
+
+        <para>
+            As already discussed, automatic and transparent object/relational mapping is concerned
+            with the management of object state. This implies that the object state is available
+            in memory, hence manipulating (using the SQL <literal>Data Manipulation Language</literal>
+            (DML) statements: <literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal>)
+            data directly in the database will not affect in-memory state. However, Hibernate provides methods
+            for bulk SQL-style DML statement execution which are performed through the
+            Hibernate Query Language (<xref linkend="queryhql">HQL</xref>).
+        </para>
+
+	    <para>
+            The pseudo-syntax for <literal>UPDATE</literal> and <literal>DELETE</literal> statements
+            is: <literal>( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?</literal>.  Some
+            points to note:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    In the from-clause, the FROM keyword is optional
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    There can only be a single entity named in the from-clause; it can optionally be
+                    aliased.  If the entity name is aliased, then any property references must
+                    be qualified using that alias; if the entity name is not aliased, then it is
+                    illegal for any property references to be qualified.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    No <xref linkend="queryhql-joins-forms">joins</xref> (either implicit or explicit)
+	                can be specified in a bulk HQL query.  Sub-queries may be used in the where-clause;
+	                the subqueries, themselves, may contain joins.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    The where-clause is also optional.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            As an example, to execute an HQL <literal>UPDATE</literal>, use the
+            <literal>Query.executeUpdate()</literal> method (the method is named for
+            those familiar with JDBC's <literal>PreparedStatement.executeUpdate()</literal>):
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
+// or String hqlUpdate = "update Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+        .setString( "newName", newName )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            HQL <literal>UPDATE</literal> statements, by default do not effect the
+            <xref linkend="mapping-declaration-version">version</xref>
+            or the <xref linkend="mapping-declaration-timestamp">timestamp</xref> property values
+            for the affected entities; this is in keeping with the EJB3 specification.  However,
+            you can force Hibernate to properly reset the <literal>version</literal> or
+            <literal>timestamp</literal> property values through the use of a <literal>versioned update</literal>.
+            This is achieved by adding the <literal>VERSIONED</literal> keyword after the <literal>UPDATE</literal>
+            keyword.
+        </para>
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+        .setString( "newName", newName )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            Note that custom version types (<literal>org.hibernate.usertype.UserVersionType</literal>)
+            are not allowed in conjunction with a <literal>update versioned</literal> statement.
+        </para>
+
+        <para>
+            To execute an HQL <literal>DELETE</literal>, use the same <literal>Query.executeUpdate()</literal>
+            method:
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlDelete = "delete Customer c where c.name = :oldName";
+// or String hqlDelete = "delete Customer where name = :oldName";
+int deletedEntities = s.createQuery( hqlDelete )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            The <literal>int</literal> value returned by the <literal>Query.executeUpdate()</literal>
+            method indicate the number of entities effected by the operation.  Consider this may or may not
+            correlate to the number of rows effected in the database.  An HQL bulk operation might result in
+            multiple actual SQL statements being executed, for joined-subclass, for example.  The returned
+            number indicates the number of actual entities affected by the statement.  Going back to the
+            example of joined-subclass, a delete against one of the subclasses may actually result
+            in deletes against not just the table to which that subclass is mapped, but also the "root"
+            table and potentially joined-subclass tables further down the inheritence hierarchy.
+        </para>
+
+        <para>
+            The pseudo-syntax for <literal>INSERT</literal> statements is:
+            <literal>INSERT INTO EntityName properties_list select_statement</literal>.  Some
+            points to note:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Only the INSERT INTO ... SELECT ... form is supported; not the INSERT INTO ... VALUES ... form.
+                </para>
+                <para>
+                    The properties_list is analogous to the <literal>column speficiation</literal>
+                    in the SQL <literal>INSERT</literal> statement.  For entities involved in mapped
+                    inheritence, only properties directly defined on that given class-level can be
+                    used in the properties_list.  Superclass properties are not allowed; and subclass
+                    properties do not make sense.  In other words, <literal>INSERT</literal>
+                    statements are inherently non-polymorphic.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    select_statement can be any valid HQL select query, with the caveat that the return types
+                    must match the types expected by the insert.  Currently, this is checked during query
+                    compilation rather than allowing the check to relegate to the database.  Note however
+                    that this might cause problems between Hibernate <literal>Type</literal>s which are
+                    <emphasis>equivalent</emphasis> as opposed to <emphasis>equal</emphasis>.  This might cause
+                    issues with mismatches between a property defined as a <literal>org.hibernate.type.DateType</literal>
+                    and a property defined as a <literal>org.hibernate.type.TimestampType</literal>, even though the
+                    database might not make a distinction or might be able to handle the conversion.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    For the id property, the insert statement gives you two options.  You can either
+                    explicitly specify the id property in the properties_list (in which case its value
+                    is taken from the corresponding select expression) or omit it from the properties_list
+                    (in which case a generated value is used).  This later option is only available when
+                    using id generators that operate in the database; attempting to use this option with
+                    any "in memory" type generators will cause an exception during parsing.  Note that
+                    for the purposes of this discussion, in-database generators are considered to be
+                    <literal>org.hibernate.id.SequenceGenerator</literal> (and its subclasses) and
+                    any implementors of <literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>.
+                    The most notable exception here is <literal>org.hibernate.id.TableHiLoGenerator</literal>,
+                    which cannot be used because it does not expose a selectable way to get its values.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    For properties mapped as either <literal>version</literal> or <literal>timestamp</literal>,
+                    the insert statement gives you two options.  You can either specify the property in the
+                    properties_list (in which case its value is taken from the corresponding select expressions)
+                    or omit it from the properties_list (in which case the <literal>seed value</literal> defined
+                    by the <literal>org.hibernate.type.VersionType</literal> is used).
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            An example HQL <literal>INSERT</literal> statement execution:
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
+int createdEntities = s.createQuery( hqlInsert )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+</chapter>


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/batch.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/best_practices.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/best_practices.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/best_practices.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,223 @@
+<chapter id="best-practices" revision="3">
+    <title>Best Practices</title>
+
+    <variablelist spacing="compact">
+        <varlistentry>
+            <term>Write fine-grained classes and map them using <literal>&lt;component&gt;</literal>.</term>
+            <listitem>
+                <para>
+                    Use an <literal>Address</literal> class to encapsulate <literal>street</literal>,
+                    <literal>suburb</literal>, <literal>state</literal>, <literal>postcode</literal>.
+                    This encourages code reuse and simplifies refactoring.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Declare identifier properties on persistent classes.</term>
+            <listitem>
+                <para>
+                    Hibernate makes identifier properties optional. There are all sorts of reasons why
+                    you should use them. We recommend that identifiers be 'synthetic' (generated, with
+                    no business meaning).
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Identify natural keys.</term>
+            <listitem>
+                <para>
+                    Identify natural keys for all entities, and map them using 
+                    <literal>&lt;natural-id&gt;</literal>. Implement <literal>equals()</literal> and 
+                    <literal>hashCode()</literal> to compare the properties that make up the natural key.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Place each class mapping in its own file.</term>
+            <listitem>
+                <para>
+                     Don't use a single monolithic mapping document. Map <literal>com.eg.Foo</literal> in 
+                     the file <literal>com/eg/Foo.hbm.xml</literal>. This makes particularly good sense in 
+                     a team environment.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Load mappings as resources.</term>
+            <listitem>
+                <para>
+                    Deploy the mappings along with the classes they map.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Consider externalising query strings.</term>
+            <listitem>
+                <para>
+                    This is a good practice if your queries call non-ANSI-standard SQL functions. 
+                    Externalising the query strings to mapping files will make the application more 
+                    portable.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Use bind variables.</term>
+            <listitem>
+                <para>
+                     As in JDBC, always replace non-constant values by "?". Never use string manipulation to 
+                     bind a non-constant value in a query! Even better, consider using named parameters in
+                     queries.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Don't manage your own JDBC connections.</term>
+            <listitem>
+                <para>
+                    Hibernate lets the application manage JDBC connections. This approach should be considered 
+                    a last-resort. If you can't use the built-in connections providers, consider providing your 
+                    own implementation of <literal>org.hibernate.connection.ConnectionProvider</literal>.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Consider using a custom type.</term>
+            <listitem>
+                <para>
+                    Suppose you have a Java type, say from some library, that needs to be persisted but doesn't 
+                    provide the accessors needed to map it as a component. You should consider implementing
+                    <literal>org.hibernate.UserType</literal>. This approach frees the application
+                    code from implementing transformations to / from a Hibernate type.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Use hand-coded JDBC in bottlenecks.</term>
+            <listitem>
+                <para>
+                    In performance-critical areas of the system, some kinds of operations might benefit from 
+                    direct JDBC. But please, wait until you <emphasis>know</emphasis> something is a bottleneck. 
+                    And don't assume that direct JDBC is necessarily faster. If you need to use direct JDBC, it might 
+                    be worth opening a Hibernate <literal>Session</literal> and using that JDBC connection. That 
+                    way you can still use the same transaction strategy and underlying connection provider.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Understand <literal>Session</literal> flushing.</term>
+            <listitem>
+                <para>
+                    From time to time the Session synchronizes its persistent state with the database. Performance will
+                    be affected if this process occurs too often. You may sometimes minimize unnecessary flushing by 
+                    disabling automatic flushing or even by changing the order of queries and other operations within a 
+                    particular transaction.      
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>In a three tiered architecture, consider using detached objects.</term>
+            <listitem>
+                <para>
+                    When using a servlet / session bean architecture, you could pass persistent objects loaded in
+                    the session bean to and from the servlet / JSP layer. Use a new session to service each request. 
+                    Use <literal>Session.merge()</literal> or <literal>Session.saveOrUpdate()</literal> to 
+                    synchronize objects with the database.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>In a two tiered architecture, consider using long persistence contexts.</term>
+            <listitem>
+                <para>
+                    Database Transactions have to be as short as possible for best scalability. However, it is often
+                    neccessary to implement long running <emphasis>application transactions</emphasis>, a single 
+                    unit-of-work from the point of view of a user. An application transaction might span several 
+                    client request/response cycles. It is common to use detached objects to implement application
+                    transactions. An alternative, extremely appropriate in two tiered architecture, is to maintain
+                    a single open persistence contact (session) for the whole lifecycle of the application transaction 
+                    and simply disconnect from the JDBC connection at the end of each request and reconnect at the 
+                    beginning of the subsequent request. Never share a single session across more than one application 
+                    transaction, or you will be working with stale data.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Don't treat exceptions as recoverable.</term>
+            <listitem>
+                <para>
+                    This is more of a necessary practice than a "best" practice. When an exception occurs, roll back
+                    the <literal>Transaction</literal> and close the <literal>Session</literal>. If you don't, Hibernate
+                    can't guarantee that in-memory state accurately represents persistent state. As a special case of this,
+                    do not use <literal>Session.load()</literal> to determine if an instance with the given identifier 
+                    exists on the database; use <literal>Session.get()</literal> or a query instead.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Prefer lazy fetching for associations.</term>
+            <listitem>
+                <para>
+                    Use eager fetching sparingly. Use proxies and lazy collections for most associations to classes that 
+                    are not likely to be completely held in the second-level cache. For associations to cached classes, 
+                    where there is an a extremely high probability of a cache hit, explicitly disable eager fetching using 
+                    <literal>lazy="false"</literal>. When an join fetching is appropriate to a particular use
+                    case, use a query with a <literal>left join fetch</literal>.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>
+                Use the <emphasis>open session in view</emphasis> pattern, or a disciplined 
+                <emphasis>assembly phase</emphasis> to avoid problems with unfetched data.
+            </term>
+            <listitem>
+                <para>
+                    Hibernate frees the developer from writing tedious <emphasis>Data Transfer Objects</emphasis> (DTO). 
+                    In a traditional EJB architecture, DTOs serve dual purposes: first, they work around the problem
+                    that entity beans are not serializable; second, they implicitly define an assembly phase where
+                    all data to be used by the view is fetched and marshalled into the DTOs before returning control 
+                    to the presentation tier. Hibernate eliminates the first purpose. However, you will still need
+                    an assembly phase (think of your business methods as having a strict contract with the presentation
+                    tier about what data is available in the detached objects) unless you are prepared to hold the
+                    persistence context (the session) open across the view rendering process. This is not a limitation
+                    of Hibernate! It is a fundamental requirement of safe transactional data access.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Consider abstracting your business logic from Hibernate.</term>
+            <listitem>
+                <para>
+                    Hide (Hibernate) data-access code behind an interface. Combine the <emphasis>DAO</emphasis> and 
+                    <emphasis>Thread Local Session</emphasis> patterns. You can even have some classes persisted by
+                    handcoded JDBC, associated to Hibernate via a <literal>UserType</literal>. (This advice is 
+                    intended for "sufficiently large" applications; it is not appropriate for an application with
+                    five tables!)
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Don't use exotic association mappings.</term>
+            <listitem>
+                <para>
+                    Good usecases for a real many-to-many associations are rare. Most of the time you need
+                    additional information stored in the "link table". In this case, it is much better to
+                    use two one-to-many associations to an intermediate link class. In fact, we think that
+                    most associations are one-to-many and many-to-one, you should be careful when using any
+                    other association style and ask yourself if it is really neccessary.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Prefer bidirectional associations.</term>
+            <listitem>
+                <para>
+                    Unidirectional associations are more difficult to query. In a large application, almost
+                    all associations must be navigable in both directions in queries.
+                </para>
+            </listitem>
+        </varlistentry>
+    </variablelist>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/collection_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/collection_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/collection_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1231 @@
+<chapter id="collections">
+    <title>Collection Mapping</title>
+
+    <sect1 id="collections-persistent" revision="3">
+        <title>Persistent collections</title>
+        
+        <para>
+            Hibernate requires that persistent collection-valued fields be declared
+            as an interface type, for example:
+        </para>
+        
+        <programlisting><![CDATA[public class Product {
+    private String serialNumber;
+    private Set parts = new HashSet();
+    
+    public Set getParts() { return parts; }
+    void setParts(Set parts) { this.parts = parts; }
+    public String getSerialNumber() { return serialNumber; }
+    void setSerialNumber(String sn) { serialNumber = sn; }
+}]]></programlisting>
+        
+        <para>
+            The actual interface might be <literal>java.util.Set</literal>,
+            <literal>java.util.Collection</literal>, <literal>java.util.List</literal>,
+            <literal>java.util.Map</literal>, <literal>java.util.SortedSet</literal>,
+            <literal>java.util.SortedMap</literal> or ... anything you like! (Where 
+            "anything you like" means you will have to write an implementation of 
+            <literal>org.hibernate.usertype.UserCollectionType</literal>.)
+        </para>
+        
+        <para>
+            Notice how we initialized the instance variable with an instance of
+            <literal>HashSet</literal>. This is the best way to initialize collection
+            valued properties of newly instantiated (non-persistent) instances. When
+            you make the instance persistent - by calling <literal>persist()</literal>,
+            for example - Hibernate will actually replace the <literal>HashSet</literal>
+            with an instance of Hibernate's own implementation of <literal>Set</literal>.
+            Watch out for errors like this:
+        </para>
+        
+        <programlisting><![CDATA[Cat cat = new DomesticCat();
+Cat kitten = new DomesticCat();
+....
+Set kittens = new HashSet();
+kittens.add(kitten);
+cat.setKittens(kittens);
+session.persist(cat);
+kittens = cat.getKittens(); // Okay, kittens collection is a Set
+(HashSet) cat.getKittens(); // Error!]]></programlisting>
+
+        <para>
+            The persistent collections injected by Hibernate behave like
+            <literal>HashMap</literal>, <literal>HashSet</literal>,
+            <literal>TreeMap</literal>, <literal>TreeSet</literal> or
+            <literal>ArrayList</literal>, depending upon the interface type.
+        </para>
+
+        <para>
+            Collections instances have the usual behavior of value types. They are 
+            automatically persisted when referenced by a persistent object and 
+            automatically deleted when unreferenced. If a collection is passed from one
+            persistent object to another, its elements might be moved from one table to
+            another. Two entities may not share a reference to the same collection 
+            instance. Due to the underlying relational model, collection-valued properties
+            do not support null value semantics; Hibernate does not distinguish between 
+            a null collection reference and an empty collection.
+        </para>
+
+        <para>
+            You shouldn't have to worry much about any of this. Use persistent collections 
+            the same way you use ordinary Java collections. Just make sure you understand 
+            the semantics of bidirectional associations (discussed later).
+        </para>
+
+    </sect1>
+
+    <sect1 id="collections-mapping" revision="4">
+        <title>Collection mappings</title>
+
+        <para>
+            The Hibernate mapping element used for mapping a collection depends upon
+            the type of the interface. For example, a <literal>&lt;set&gt;</literal> 
+            element is used for mapping properties of type <literal>Set</literal>.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Product">
+    <id name="serialNumber" column="productSerialNumber"/>
+    <set name="parts">
+        <key column="productSerialNumber" not-null="true"/>
+        <one-to-many class="Part"/>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Apart from <literal>&lt;set&gt;</literal>, there is also 
+            <literal>&lt;list&gt;</literal>, <literal>&lt;map&gt;</literal>,
+            <literal>&lt;bag&gt;</literal>, <literal>&lt;array&gt;</literal> and
+            <literal>&lt;primitive-array&gt;</literal> mapping elements. The
+            <literal>&lt;map&gt;</literal> element is representative:
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="mappingcollection1" coords="2 65"/>
+                <area id="mappingcollection2" coords="3 65"/>
+                <area id="mappingcollection3" coords="4 65"/>
+                <area id="mappingcollection4" coords="5 65"/>
+                <area id="mappingcollection5" coords="6 65"/>
+                <area id="mappingcollection6" coords="7 65"/>
+                <area id="mappingcollection7" coords="8 65"/>
+                <area id="mappingcollection8" coords="9 65"/>
+                <area id="mappingcollection9" coords="10 65"/>
+                <area id="mappingcollection10" coords="11 65"/>
+                <area id="mappingcollection11" coords="12 65"/>
+                <area id="mappingcollection12" coords="13 65"/>
+                <area id="mappingcollection13" coords="14 65"/>
+                <area id="mappingcollection14" coords="15 65"/>
+            </areaspec>
+            <programlisting><![CDATA[<map
+    name="propertyName"
+    table="table_name"
+    schema="schema_name"
+    lazy="true|extra|false"
+    inverse="true|false"
+    cascade="all|none|save-update|delete|all-delete-orphan|delete-orphan"
+    sort="unsorted|natural|comparatorClass"
+    order-by="column_name asc|desc"
+    where="arbitrary sql where condition"
+    fetch="join|select|subselect"
+    batch-size="N"
+    access="field|property|ClassName"
+    optimistic-lock="true|false"
+    mutable="true|false"
+    node="element-name|."
+    embed-xml="true|false"
+>
+
+    <key .... />
+    <map-key .... />
+    <element .... />
+</map>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="mappingcollection1">
+                    <para>
+                        <literal>name</literal> the collection property name
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection2">
+                    <para>
+                        <literal>table</literal> (optional - defaults to property name) the
+                        name of the collection table (not used for one-to-many associations)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection3">
+                    <para>
+                        <literal>schema</literal> (optional) the name of a table schema to
+                        override the schema declared on the root element
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection4">
+                    <para>
+                        <literal>lazy</literal> (optional - defaults to <literal>true</literal>)
+                        may be used to disable lazy fetching and specify that the association is 
+                        always eagerly fetched, or to enable "extra-lazy" fetching where most 
+                        operations do not initialize the collection (suitable for very large 
+                        collections)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection5">
+                    <para>
+                        <literal>inverse</literal> (optional - defaults to <literal>false</literal>)
+                        mark this collection as the "inverse" end of a bidirectional association
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection6">
+                    <para>
+                        <literal>cascade</literal> (optional - defaults to <literal>none</literal>)
+                        enable operations to cascade to child entities
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection7">
+                    <para>
+                        <literal>sort</literal> (optional) specify a sorted collection with
+                        <literal>natural</literal> sort order, or a given comparator class
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection8">
+                    <para>
+                        <literal>order-by</literal> (optional, JDK1.4 only) specify a table column (or columns)
+                        that define the iteration order of the <literal>Map</literal>, <literal>Set</literal>
+                        or bag, together with an optional <literal>asc</literal> or <literal>desc</literal>
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection9">
+                    <para>
+                        <literal>where</literal> (optional) specify an arbitrary SQL <literal>WHERE</literal>
+                        condition to be used when retrieving or removing the collection (useful if the
+                        collection should contain only a subset of the available data)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection10">
+                    <para>
+                        <literal>fetch</literal> (optional, defaults to <literal>select</literal>) Choose
+                        between outer-join fetching, fetching by sequential select, and fetching by sequential
+                        subselect.
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection11">
+                    <para>
+                        <literal>batch-size</literal> (optional, defaults to <literal>1</literal>) specify a
+                        "batch size" for lazily fetching instances of this collection.
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection12">
+                    <para>
+                        <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+                        strategy Hibernate should use for accessing the collection property value.
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection13">
+                    <para>
+                        <literal>optimistic-lock</literal> (optional - defaults to <literal>true</literal>): 
+                        Species that changes to the state of the collection results in increment of the
+                        owning entity's version. (For one to many associations, it is often reasonable to
+                        disable this setting.)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection14">
+                    <para>
+                        <literal>mutable</literal> (optional - defaults to <literal>true</literal>): 
+                        A value of <literal>false</literal> specifies that the elements of the 
+                        collection never change (a minor performance optimization in some cases).
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <sect2 id="collections-foreignkeys" >
+           <title>Collection foreign keys</title>
+    
+            <para>
+                Collection instances are distinguished in the database by the foreign key of
+                the entity that owns the collection. This foreign key is referred to as the
+                <emphasis>collection key column</emphasis> (or columns) of the collection 
+                table. The collection key column is mapped by the <literal>&lt;key&gt;</literal> 
+                element. 
+            </para>
+    
+            <para>
+                There may be a nullability constraint on the foreign key column. For most
+                collections, this is implied. For unidirectional one to many associations,
+                the foreign key column is nullable by default, so you might need to specify
+                <literal>not-null="true"</literal>.
+            </para>
+    
+            <programlisting><![CDATA[<key column="productSerialNumber" not-null="true"/>]]></programlisting>
+    
+            <para>
+                The foreign key constraint may use <literal>ON DELETE CASCADE</literal>.
+            </para>
+    
+            <programlisting><![CDATA[<key column="productSerialNumber" on-delete="cascade"/>]]></programlisting>
+            
+            <para>
+                See the previous chapter for a full definition of the <literal>&lt;key&gt;</literal> 
+                element.
+            </para>
+            
+        </sect2>
+        
+        <sect2 id="collections-elements" >
+            <title>Collection elements</title>
+    
+            <para>
+                Collections may contain almost any other Hibernate type, including all basic types,
+                custom types, components, and of course, references to other entities. This is an
+                important distinction: an object in a collection might be handled with "value" 
+                semantics (its lifecycle fully depends on the collection owner) or it might be a
+                reference to another entity, with its own lifecycle. In the latter case, only the 
+                "link" between the two objects is considered to be state held by the collection. 
+            </para>
+                
+            <para>
+                The contained type is referred to as the <emphasis>collection element type</emphasis>. 
+                Collection elements are mapped by <literal>&lt;element&gt;</literal> or
+                <literal>&lt;composite-element&gt;</literal>, or in the case of entity references, 
+                with <literal>&lt;one-to-many&gt;</literal> or <literal>&lt;many-to-many&gt;</literal>. 
+                The first two map elements with value semantics, the next two are used to map entity 
+                associations.
+            </para>
+            
+        </sect2>
+        
+        <sect2 id="collections-indexed">
+            <title>Indexed collections</title>
+    
+            <para>
+                All collection mappings, except those with set and bag semantics, need an
+                <emphasis>index column</emphasis> in the collection table - a column that maps to an
+                array index, or <literal>List</literal> index, or <literal>Map</literal> key. The
+                index of a <literal>Map</literal> may be of any basic type, mapped with 
+                <literal>&lt;map-key&gt;</literal>, it may be an entity reference mapped with 
+                <literal>&lt;map-key-many-to-many&gt;</literal>, or it may be a composite type,
+                mapped with <literal>&lt;composite-map-key&gt;</literal>. The index of an array or 
+                list is always of type <literal>integer</literal> and is mapped using the 
+                <literal>&lt;list-index&gt;</literal> element. The mapped column contains 
+                sequential integers (numbered from zero, by default).
+            </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="index1" coords="2 45"/>
+                <area id="index2" coords="3 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<list-index 
+        column="column_name"
+        base="0|1|..."/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="index1">
+                    <para>
+                        <literal>column_name</literal> (required): The name of the column holding the
+                        collection index values.
+                    </para>
+                </callout>
+                <callout arearefs="index1">
+                    <para>
+                        <literal>base</literal> (optional, defaults to <literal>0</literal>): The value
+                        of the index column that corresponds to the first element of the list or array.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <programlistingco>
+            <areaspec>
+                <area id="mapkey1" coords="2 45"/>
+                <area id="mapkey2" coords="3 45"/>
+                <area id="mapkey3" coords="4 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<map-key 
+        column="column_name"
+        formula="any SQL expression"
+        type="type_name"
+        node="@attribute-name"
+        length="N"/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="mapkey1">
+                    <para>
+                        <literal>column</literal> (optional): The name of the column holding the
+                        collection index values.
+                    </para>
+                </callout>
+                <callout arearefs="mapkey2">
+                    <para>
+                        <literal>formula</literal> (optional): A SQL formula used to evaluate the
+                        key of the map.
+                    </para>
+                </callout>
+                <callout arearefs="mapkey3">
+                    <para>
+                        <literal>type</literal> (reguired): The type of the map keys.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <programlistingco>
+            <areaspec>
+                <area id="indexmanytomany1" coords="2 45"/>
+                <area id="indexmanytomany2" coords="3 45"/>
+                <area id="indexmanytomany3" coords="3 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<map-key-many-to-many
+        column="column_name"
+        formula="any SQL expression"
+        class="ClassName"
+/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="indexmanytomany1">
+                    <para>
+                        <literal>column</literal> (optional): The name of the foreign key
+                        column for the collection index values.
+                    </para>
+                </callout>
+                <callout arearefs="indexmanytomany2">
+                    <para>
+                        <literal>formula</literal> (optional): A SQL formula used to evaluate the
+                        foreign key of the map key.
+                    </para>
+                </callout>
+                <callout arearefs="indexmanytomany3">
+                    <para>
+                        <literal>class</literal> (required): The entity class used as the map key.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+
+            <para>
+                If your table doesn't have an index column, and you still wish to use <literal>List</literal> 
+                as the property type, you should map the property as a Hibernate <emphasis>&lt;bag&gt;</emphasis>.
+                A bag does not retain its order when it is retrieved from the database, but it may be 
+                optionally sorted or ordered.
+            </para>
+            
+        </sect2>
+
+        <para>
+            There are quite a range of mappings that can be generated for collections, covering 
+            many common relational models. We suggest you experiment with the schema generation tool 
+            to get a feeling for how various mapping declarations translate to database tables.
+        </para>
+
+    <sect2 id="collections-ofvalues" revision="2">
+        <title>Collections of values and many-to-many associations</title>
+
+        <para>
+            Any collection of values or many-to-many association requires a dedicated 
+            <emphasis>collection table</emphasis> with a foreign key column or columns, 
+            <emphasis>collection element column</emphasis> or columns and possibly 
+            an index column or columns.
+        </para>
+
+        <para>
+            For a collection of values, we use the <literal>&lt;element&gt;</literal> tag.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="element1b" coords="2 50"/>
+                <area id="element2b" coords="3 50"/>
+                <area id="element3b" coords="4 50"/>
+             </areaspec>
+            <programlisting><![CDATA[<element
+        column="column_name"
+        formula="any SQL expression"
+        type="typename"
+        length="L"
+        precision="P"
+        scale="S"
+        not-null="true|false"
+        unique="true|false"
+        node="element-name"
+/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="element1b">
+                    <para>
+                        <literal>column</literal> (optional): The name of the column holding the
+                        collection element values.
+                    </para>
+                </callout>
+                <callout arearefs="element2b">
+                    <para>
+                        <literal>formula</literal> (optional): An SQL formula used to evaluate the
+                        element.
+                    </para>
+                </callout>
+                <callout arearefs="element3b">
+                    <para>
+                        <literal>type</literal> (required): The type of the collection element.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <para>
+            A <emphasis>many-to-many association</emphasis> is specified using the 
+            <literal>&lt;many-to-many&gt;</literal> element.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="manytomany1" coords="2 60"/>
+                <area id="manytomany2" coords="3 60"/>
+                <area id="manytomany3" coords="4 60"/>
+                <area id="manytomany4" coords="5 60"/>
+                <area id="manytomany5" coords="6 60"/>
+                <area id="manytomany6" coords="7 60"/>
+                <area id="manytomany7" coords="8 60"/>
+                <area id="manytomany8" coords="9 60"/>
+            </areaspec>
+            <programlisting><![CDATA[<many-to-many
+        column="column_name"
+        formula="any SQL expression"
+        class="ClassName"
+        fetch="select|join"
+        unique="true|false"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        property-ref="propertyNameFromAssociatedClass"
+        node="element-name"
+        embed-xml="true|false"
+    />]]></programlisting>
+            <calloutlist>
+                <callout arearefs="manytomany1">
+                    <para>
+                        <literal>column</literal> (optional): The name of the element foreign key column.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany2">
+                    <para>
+                        <literal>formula</literal> (optional): An SQL formula used to evaluate the element
+                        foreign key value.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany3">
+                    <para>
+                        <literal>class</literal> (required): The name of the associated class.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany4">
+                    <para>
+                        <literal>fetch</literal> (optional - defaults to <literal>join</literal>):
+                        enables outer-join or sequential select fetching for this association. This
+                        is a special case; for full eager fetching (in a single <literal>SELECT</literal>)
+                        of an entity and its many-to-many relationships to other entities, you would
+                        enable <literal>join</literal> fetching not only of the collection itself,
+                        but also with this attribute on the <literal>&lt;many-to-many&gt;</literal>
+                        nested element.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany5">
+                    <para>
+                        <literal>unique</literal> (optional): Enable the DDL generation of a unique
+                        constraint for the foreign-key column. This makes the association multiplicity
+                        effectively one to many.
+                    </para>
+                </callout>
+	            <callout arearefs="manytomany6">
+	                <para>
+	                    <literal>not-found</literal> (optional - defaults to <literal>exception</literal>): 
+	                    Specifies how foreign keys that reference missing rows will be handled: 
+	                    <literal>ignore</literal> will treat a missing row as a null association.
+	                </para>
+	            </callout>
+                <callout arearefs="manytomany7">
+                    <para>
+                        <literal>entity-name</literal> (optional): The entity name of the associated class,
+                        as an alternative to <literal>class</literal>.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany8">
+                    <para>
+                        <literal>property-ref</literal>: (optional) The name of a property of the associated 
+                        class that is joined to this foreign key. If not specified, the primary key of
+                        the associated class is used.
+                    </para>                
+                </callout>                   
+            </calloutlist>
+        </programlistingco>
+
+        <para>
+            Some examples, first, a set of strings:
+        </para>
+
+        <programlisting><![CDATA[<set name="names" table="person_names">
+    <key column="person_id"/>
+    <element column="person_name" type="string"/>
+</set>]]></programlisting>
+
+        <para>
+            A bag containing integers (with an iteration order determined by the
+            <literal>order-by</literal> attribute):
+        </para>
+
+        <programlisting><![CDATA[<bag name="sizes" 
+        table="item_sizes" 
+        order-by="size asc">
+    <key column="item_id"/>
+    <element column="size" type="integer"/>
+</bag>]]></programlisting>
+
+        <para>
+            An array of entities - in this case, a many to many association:
+        </para>
+
+        <programlisting><![CDATA[<array name="addresses" 
+        table="PersonAddress" 
+        cascade="persist">
+    <key column="personId"/>
+    <list-index column="sortOrder"/>
+    <many-to-many column="addressId" class="Address"/>
+</array>]]></programlisting>
+
+        <para>
+            A map from string indices to dates:
+        </para>
+
+        <programlisting><![CDATA[<map name="holidays" 
+        table="holidays" 
+        schema="dbo" 
+        order-by="hol_name asc">
+    <key column="id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            A list of components (discussed in the next chapter):
+        </para>
+
+        <programlisting><![CDATA[<list name="carComponents" 
+        table="CarComponents">
+    <key column="carId"/>
+    <list-index column="sortOrder"/>
+    <composite-element class="CarComponent">
+        <property name="price"/>
+        <property name="type"/>
+        <property name="serialNumber" column="serialNum"/>
+    </composite-element>
+</list>]]></programlisting>
+
+    </sect2>
+
+    <sect2 id="collections-onetomany">
+        <title>One-to-many associations</title>
+
+        <para>
+            A <emphasis>one to many association</emphasis> links the tables of two classes
+            via a foreign key, with no intervening collection table. This mapping loses 
+            certain semantics of normal Java collections:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    An instance of the contained entity class may not belong to more than
+                    one instance of the collection
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    An instance of the contained entity class may not appear at more than
+                    one value of the collection index
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            An association from <literal>Product</literal> to <literal>Part</literal> requires 
+            existence of a foreign key column and possibly an index column to the <literal>Part</literal> 
+            table. A <literal>&lt;one-to-many&gt;</literal> tag indicates that this is a one to many 
+            association.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="onetomany1" coords="2 60"/>
+                <area id="onetomany2" coords="3 60"/>
+                <area id="onetomany3" coords="4 60"/>
+            </areaspec>
+            <programlisting><![CDATA[<one-to-many 
+        class="ClassName"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        node="element-name"
+        embed-xml="true|false"
+    />]]></programlisting>
+            <calloutlist>
+                <callout arearefs="onetomany1">
+                    <para>
+                        <literal>class</literal> (required): The name of the associated class.
+                    </para>
+                </callout>
+		        <callout arearefs="onetomany2">
+		            <para>
+		                <literal>not-found</literal> (optional - defaults to <literal>exception</literal>): 
+		                Specifies how cached identifiers that reference missing rows will be handled: 
+		                <literal>ignore</literal> will treat a missing row as a null association.
+		            </para>
+		        </callout>
+                <callout arearefs="onetomany3">
+                    <para>
+                        <literal>entity-name</literal> (optional): The entity name of the associated class,
+                        as an alternative to <literal>class</literal>.
+                    </para>
+                </callout>
+            </calloutlist>
+       </programlistingco>
+  
+        <para>
+            Notice that the <literal>&lt;one-to-many&gt;</literal> element does not need to
+            declare any columns. Nor is it necessary to specify the <literal>table</literal>
+            name anywhere.
+        </para>
+
+        <para>
+            <emphasis>Very important note:</emphasis> If the foreign key column of a 
+            <literal>&lt;one-to-many&gt;</literal> association is declared <literal>NOT NULL</literal>, 
+            you must declare the <literal>&lt;key&gt;</literal> mapping 
+            <literal>not-null="true"</literal> or <emphasis>use a bidirectional association</emphasis> 
+            with the collection mapping marked <literal>inverse="true"</literal>. See the discussion 
+            of bidirectional associations later in this chapter.
+        </para>
+        
+        <para>
+            This example shows a map of <literal>Part</literal> entities by name (where
+            <literal>partName</literal> is a persistent property of <literal>Part</literal>).
+            Notice the use of a formula-based index.
+        </para>
+
+        <programlisting><![CDATA[<map name="parts"
+        cascade="all">
+    <key column="productId" not-null="true"/>
+    <map-key formula="partName"/>
+    <one-to-many class="Part"/>
+</map>]]></programlisting>
+    </sect2>
+    
+    </sect1>
+
+    <sect1 id="collections-advancedmappings">
+        <title>Advanced collection mappings</title>
+
+    <sect2 id="collections-sorted" revision="2">
+        <title>Sorted collections</title>
+
+        <para>
+            Hibernate supports collections implementing <literal>java.util.SortedMap</literal> and
+            <literal>java.util.SortedSet</literal>. You must specify a comparator in the mapping file:
+        </para>
+
+        <programlisting><![CDATA[<set name="aliases" 
+            table="person_aliases" 
+            sort="natural">
+    <key column="person"/>
+    <element column="name" type="string"/>
+</set>
+
+<map name="holidays" sort="my.custom.HolidayComparator">
+    <key column="year_id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            Allowed values of the <literal>sort</literal> attribute are <literal>unsorted</literal>,
+            <literal>natural</literal> and the name of a class implementing
+            <literal>java.util.Comparator</literal>.
+        </para>
+
+        <para>
+            Sorted collections actually behave like <literal>java.util.TreeSet</literal> or
+            <literal>java.util.TreeMap</literal>.
+        </para>
+
+        <para>
+            If you want the database itself to order the collection elements use the
+            <literal>order-by</literal> attribute of <literal>set</literal>, <literal>bag</literal>
+            or <literal>map</literal> mappings. This solution is only available under
+            JDK 1.4 or higher (it is implemented using <literal>LinkedHashSet</literal> or
+            <literal>LinkedHashMap</literal>). This performs the ordering in the SQL query, 
+            not in memory.
+        </para>
+
+        <programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="lower(name) asc">
+    <key column="person"/>
+    <element column="name" type="string"/>
+</set>
+
+<map name="holidays" order-by="hol_date, hol_name">
+    <key column="year_id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            Note that the value of the <literal>order-by</literal> attribute is an SQL ordering, not
+            a HQL ordering!
+        </para>
+
+        <para>
+            Associations may even be sorted by some arbitrary criteria at runtime using a collection
+            <literal>filter()</literal>.
+        </para>
+
+        <programlisting><![CDATA[sortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list();]]></programlisting>
+
+    </sect2>
+
+     <sect2 id="collections-bidirectional" revision="1">
+        <title>Bidirectional associations</title>
+
+        <para>
+            A <emphasis>bidirectional association</emphasis> allows navigation from both
+            "ends" of the association. Two kinds of bidirectional association are
+            supported:
+
+            <variablelist>
+                <varlistentry>
+                    <term>one-to-many</term>
+                    <listitem>
+                        <para>
+                            set or bag valued at one end, single-valued at the other
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>many-to-many</term>
+                    <listitem>
+                        <para>
+                            set or bag valued at both ends
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+        </para>
+
+        <para>
+            You may specify a bidirectional many-to-many association simply by mapping two
+            many-to-many associations to the same database table and declaring one end as
+            <emphasis>inverse</emphasis> (which one is your choice, but it can not be an
+            indexed collection).
+        </para>
+
+        <para>
+            Here's an example of a bidirectional many-to-many association; each category can
+            have many items and each item can be in many categories:
+        </para>
+
+        <programlisting><![CDATA[<class name="Category">
+    <id name="id" column="CATEGORY_ID"/>
+    ...
+    <bag name="items" table="CATEGORY_ITEM">
+        <key column="CATEGORY_ID"/>
+        <many-to-many class="Item" column="ITEM_ID"/>
+    </bag>
+</class>
+
+<class name="Item">
+    <id name="id" column="CATEGORY_ID"/>
+    ...
+
+    <!-- inverse end -->
+    <bag name="categories" table="CATEGORY_ITEM" inverse="true">
+        <key column="ITEM_ID"/>
+        <many-to-many class="Category" column="CATEGORY_ID"/>
+    </bag>
+</class>]]></programlisting>
+
+        <para>
+            Changes made only to the inverse end of the association are <emphasis>not</emphasis>
+            persisted. This means that Hibernate has two representations in memory for every
+            bidirectional association, one link from A to B and another link from B to A. This
+            is easier to understand if you think about the Java object model and how we create
+            a many-to-many relationship in Java:
+        </para>
+
+        <programlisting><![CDATA[
+category.getItems().add(item);          // The category now "knows" about the relationship
+item.getCategories().add(category);     // The item now "knows" about the relationship
+
+session.persist(item);                   // The relationship won't be saved!
+session.persist(category);               // The relationship will be saved]]></programlisting>
+
+        <para>
+            The non-inverse side is used to save the in-memory representation to the database.
+        </para>
+
+        <para>
+            You may define a bidirectional one-to-many association by mapping a one-to-many association
+            to the same table column(s) as a many-to-one association and declaring the many-valued
+            end <literal>inverse="true"</literal>.
+        </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <set name="children" inverse="true">
+        <key column="parent_id"/>
+        <one-to-many class="Child"/>
+    </set>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        not-null="true"/>
+</class>]]></programlisting>
+
+        <para>
+            Mapping one end of an association with <literal>inverse="true"</literal> doesn't
+            affect the operation of cascades, these are orthogonal concepts!
+        </para>
+
+    </sect2>
+
+    <sect2 id="collections-indexedbidirectional">
+        <title>Bidirectional associations with indexed collections</title>
+        <para>
+            A bidirectional association where one end is represented as a <literal>&lt;list&gt;</literal>
+            or <literal>&lt;map&gt;</literal> requires special consideration. If there is a property of
+            the child class which maps to the index column, no problem, we can continue using 
+            <literal>inverse="true"</literal> on the collection mapping:
+        </para>
+        
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <map name="children" inverse="true">
+        <key column="parent_id"/>
+        <map-key column="name" 
+            type="string"/>
+        <one-to-many class="Child"/>
+    </map>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <property name="name" 
+        not-null="true"/>
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        not-null="true"/>
+</class>]]></programlisting>
+
+        <para>
+            But, if there is no such property on the child class, we can't think of the association as
+            truly bidirectional (there is information available at one end of the association that is
+            not available at the other end). In this case, we can't map the collection 
+            <literal>inverse="true"</literal>. Instead, we could use the following mapping:
+        </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <map name="children">
+        <key column="parent_id"
+            not-null="true"/>
+        <map-key column="name" 
+            type="string"/>
+        <one-to-many class="Child"/>
+    </map>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        insert="false"
+        update="false"
+        not-null="true"/>
+</class>]]></programlisting>
+
+       <para>
+           Note that in this mapping, the collection-valued end of the association is responsible for 
+           updates to the foreign key. TODO: Does this really result in some unnecessary update statements?
+       </para>
+
+    </sect2>
+    
+    <sect2 id="collections-ternary">
+        <title>Ternary associations</title>
+
+        <para>
+            There are three possible approaches to mapping a ternary association. One is to use a 
+            <literal>Map</literal> with an association as its index:
+        </para>
+
+        <programlisting><![CDATA[<map name="contracts">
+    <key column="employer_id" not-null="true"/>
+    <map-key-many-to-many column="employee_id" class="Employee"/>
+    <one-to-many class="Contract"/>
+</map>]]></programlisting>
+            
+            <programlisting><![CDATA[<map name="connections">
+    <key column="incoming_node_id"/>
+    <map-key-many-to-many column="outgoing_node_id" class="Node"/>
+    <many-to-many column="connection_id" class="Connection"/>
+</map>]]></programlisting>
+            
+        <para>
+            A second approach is to simply remodel the association as an entity class. This
+            is the approach we use most commonly.
+        </para>
+        
+        <para>
+            A final alternative is to use composite elements, which we will discuss later. 
+        </para>
+        
+    </sect2>
+    
+    <sect2 id="collections-idbag" revision="1">
+        <title><literal>Using an &lt;idbag&gt;</literal></title>
+
+        <para>
+            If you've fully embraced our view that composite keys are a bad thing and that
+            entities should have synthetic identifiers (surrogate keys), then you might
+            find it a bit odd that the many to many associations and collections of values
+            that we've shown so far all map to tables with composite keys! Now, this point
+            is quite arguable; a pure association table doesn't seem to benefit much from
+            a surrogate key (though a collection of composite values <emphasis>might</emphasis>).
+            Nevertheless, Hibernate provides a feature that allows you to map many to many
+            associations and collections of values to a table with a surrogate key.
+        </para>
+
+        <para>
+            The <literal>&lt;idbag&gt;</literal> element lets you map a <literal>List</literal>
+            (or <literal>Collection</literal>) with bag semantics.
+        </para>
+
+<programlisting><![CDATA[<idbag name="lovers" table="LOVERS">
+    <collection-id column="ID" type="long">
+        <generator class="sequence"/>
+    </collection-id>
+    <key column="PERSON1"/>
+    <many-to-many column="PERSON2" class="Person" fetch="join"/>
+</idbag>]]></programlisting>
+
+        <para>
+            As you can see, an <literal>&lt;idbag&gt;</literal> has a synthetic id generator,
+            just like an entity class! A different surrogate key is assigned to each collection
+            row. Hibernate does not provide any mechanism to discover the surrogate key value
+            of a particular row, however.
+        </para>
+
+        <para>
+            Note that the update performance of an <literal>&lt;idbag&gt;</literal> is
+            <emphasis>much</emphasis> better than a regular <literal>&lt;bag&gt;</literal>!
+            Hibernate can locate individual rows efficiently and update or delete them
+            individually, just like a list, map or set.
+        </para>
+
+        <para>
+            In the current implementation, the <literal>native</literal> identifier generation
+            strategy is not supported for <literal>&lt;idbag&gt;</literal> collection identifiers.
+        </para>
+
+    </sect2>
+
+    </sect1>
+    
+    <!--undocumenting this stuff -->
+    
+    <!--sect1 id="collections-heterogeneous">
+        <title>Heterogeneous Associations</title>
+
+        <para>
+            The <literal>&lt;many-to-any&gt;</literal> and <literal>&lt;index-many-to-any&gt;</literal>
+            elements provide for true heterogeneous associations. These mapping elements work in the
+            same way as the <literal>&lt;any&gt;</literal> element - and should also be used
+            rarely, if ever.
+        </para>
+
+    </sect1-->
+
+    <sect1 id="collections-example" revision="1">
+        <title>Collection examples</title>
+
+        <para>
+            The previous sections are pretty confusing. So lets look at an example. This
+            class:
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+
+public class Parent {
+    private long id;
+    private Set children;
+
+    public long getId() { return id; }
+    private void setId(long id) { this.id=id; }
+
+    private Set getChildren() { return children; }
+    private void setChildren(Set children) { this.children=children; }
+
+    ....
+    ....
+}]]></programlisting>
+
+        <para>
+            has a collection of <literal>Child</literal> instances. If each
+            child has at most one parent, the most natural mapping is a 
+            one-to-many association:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children">
+            <key column="parent_id"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            This maps to the following table definitions:
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255), parent_id bigint )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+        <para>
+            If the parent is <emphasis>required</emphasis>, use a bidirectional one-to-many
+            association:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children" inverse="true">
+            <key column="parent_id"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+        <many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Notice the <literal>NOT NULL</literal> constraint:
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null
+                     primary key,
+                     name varchar(255),
+                     parent_id bigint not null )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+        <para>
+            Alternatively, if you absolutely insist that this association should be unidirectional,
+            you can declare the <literal>NOT NULL</literal> constraint on the <literal>&lt;key&gt;</literal>
+            mapping:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children">
+            <key column="parent_id" not-null="true"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            On the other hand, if a child might have multiple parents, a many-to-many
+            association is appropriate:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children" table="childset">
+            <key column="parent_id"/>
+            <many-to-many class="Child" column="child_id"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Table definitions:
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255) )
+create table childset ( parent_id bigint not null,
+                        child_id bigint not null,
+                        primary key ( parent_id, child_id ) )
+alter table childset add constraint childsetfk0 (parent_id) references parent
+alter table childset add constraint childsetfk1 (child_id) references child]]></programlisting>
+
+        <para>
+            For more examples and a complete walk-through a parent/child relationship mapping,
+            see <xref linkend="example-parentchild"/>.
+        </para>
+        
+        <para>
+            Even more exotic association mappings are possible, we will catalog all possibilities
+            in the next chapter.
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/component_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/component_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/component_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,402 @@
+<chapter id="components">
+    <title>Component Mapping</title>
+
+    <para>
+        The notion of a <emphasis>component</emphasis> is re-used in several different contexts,
+        for different purposes, throughout Hibernate.
+    </para>
+
+    <sect1 id="components-dependentobjects" revision="2" >
+        <title>Dependent objects</title>
+
+        <para>
+            A component is a contained object that is persisted as a value type, not an entity
+            reference. The term "component" refers to the object-oriented notion of composition
+            (not to architecture-level components). For example, you might model a person like this:
+        </para>
+
+        <programlisting><![CDATA[public class Person {
+    private java.util.Date birthday;
+    private Name name;
+    private String key;
+    public String getKey() {
+        return key;
+    }
+    private void setKey(String key) {
+        this.key=key;
+    }
+    public java.util.Date getBirthday() {
+        return birthday;
+    }
+    public void setBirthday(java.util.Date birthday) {
+        this.birthday = birthday;
+    }
+    public Name getName() {
+        return name;
+    }
+    public void setName(Name name) {
+        this.name = name;
+    }
+    ......
+    ......
+}]]></programlisting>
+
+<programlisting><![CDATA[public class Name {
+    char initial;
+    String first;
+    String last;
+    public String getFirst() {
+        return first;
+    }
+    void setFirst(String first) {
+        this.first = first;
+    }
+    public String getLast() {
+        return last;
+    }
+    void setLast(String last) {
+        this.last = last;
+    }
+    public char getInitial() {
+        return initial;
+    }
+    void setInitial(char initial) {
+        this.initial = initial;
+    }
+}]]></programlisting>
+
+        <para>
+            Now <literal>Name</literal> may be persisted as a component of
+            <literal>Person</literal>. Notice that <literal>Name</literal> defines getter
+            and setter methods for its persistent properties, but doesn't need to declare
+            any interfaces or identifier properties.
+        </para>
+
+        <para>
+            Our Hibernate mapping would look like:
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Person" table="person">
+    <id name="Key" column="pid" type="string">
+        <generator class="uuid"/>
+    </id>
+    <property name="birthday" type="date"/>
+    <component name="Name" class="eg.Name"> <!-- class attribute optional -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </component>
+</class>]]></programlisting>
+
+        <para>
+            The person table would have the columns <literal>pid</literal>,
+            <literal>birthday</literal>,
+            <literal>initial</literal>,
+            <literal>first</literal> and
+            <literal>last</literal>.
+        </para>
+
+        <para>
+            Like all value types, components do not support shared references. In other words, two
+            persons could have the same name, but the two person objects would contain two independent
+            name ojects, only "the same" by value. The null value semantics of a component are
+            <emphasis>ad hoc</emphasis>. When reloading the containing object, Hibernate will assume
+            that if all component columns are null, then the entire component is null. This should
+            be okay for most purposes.
+        </para>
+
+        <para>
+            The properties of a component may be of any Hibernate type (collections, many-to-one 
+            associations, other components, etc). Nested components should <emphasis>not</emphasis> 
+            be considered an exotic usage. Hibernate is intended to support a very fine-grained 
+            object model.
+        </para>
+
+        <para>
+            The <literal>&lt;component&gt;</literal> element allows a <literal>&lt;parent&gt;</literal>
+            subelement that maps a property of the component class as a reference back to the
+            containing entity.
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Person" table="person">
+    <id name="Key" column="pid" type="string">
+        <generator class="uuid"/>
+    </id>
+    <property name="birthday" type="date"/>
+    <component name="Name" class="eg.Name" unique="true">
+        <parent name="namedPerson"/> <!-- reference back to the Person -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </component>
+</class>]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="components-incollections" revision="1">
+        <title>Collections of dependent objects</title>
+
+        <para>
+            Collections of components are supported (eg. an array of type
+            <literal>Name</literal>). Declare your component collection by
+            replacing the <literal>&lt;element&gt;</literal> tag with a
+            <literal>&lt;composite-element&gt;</literal> tag.
+        </para>
+
+        <programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
+    <key column="id"/>
+    <composite-element class="eg.Name"> <!-- class attribute required -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </composite-element>
+</set>]]></programlisting>
+
+        <para>
+            Note: if you define a <literal>Set</literal> of composite elements, it is 
+            very important to implement <literal>equals()</literal> and 
+            <literal>hashCode()</literal> correctly.
+        </para>
+
+        <para>
+            Composite elements may contain components but not collections. If your
+            composite element itself contains 
+            components, use the <literal>&lt;nested-composite-element&gt;</literal> 
+            tag. This is a pretty exotic case - a collection of components which 
+            themselves have components. By this stage you should be asking yourself 
+            if a one-to-many association is more appropriate. Try remodelling the 
+            composite element as an entity - but note that even though the Java model 
+            is the same, the relational model and persistence semantics are still 
+            slightly different.
+        </para>
+
+        <para>
+            Please note that a composite element mapping doesn't support null-able properties
+            if you're using a <literal>&lt;set&gt;</literal>. Hibernate
+            has to use each columns value to identify a record when deleting objects
+            (there is no separate primary key column in the composite element table),
+            which is not possible with null values. You have to either use only
+            not-null properties in a composite-element or choose a
+            <literal>&lt;list&gt;</literal>, <literal>&lt;map&gt;</literal>,
+            <literal>&lt;bag&gt;</literal> or <literal>&lt;idbag&gt;</literal>.
+        </para>
+
+        <para>
+            A special case of a composite element is a composite element with a nested
+            <literal>&lt;many-to-one&gt;</literal> element. A mapping like this allows
+            you to map extra columns of a many-to-many association table to the
+            composite element class. The following is a many-to-many association
+            from <literal>Order</literal> to <literal>Item</literal> where 
+            <literal>purchaseDate</literal>, <literal>price</literal> and
+            <literal>quantity</literal> are properties of the association:
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Order" .... >
+    ....
+    <set name="purchasedItems" table="purchase_items" lazy="true">
+        <key column="order_id">
+        <composite-element class="eg.Purchase">
+            <property name="purchaseDate"/>
+            <property name="price"/>
+            <property name="quantity"/>
+            <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Of course, there can't be a reference to the purchae on the other side, for
+            bidirectional association navigation. Remember that components are value types and
+            don't allow shared references. A single <literal>Purchase</literal> can be in the
+            set of an <literal>Order</literal>, but it can't be referenced by the <literal>Item</literal>
+            at the same time.
+        </para>
+
+        <para>Even ternary (or quaternary, etc) associations are possible:</para>
+
+        <programlisting><![CDATA[<class name="eg.Order" .... >
+    ....
+    <set name="purchasedItems" table="purchase_items" lazy="true">
+        <key column="order_id">
+        <composite-element class="eg.OrderLine">
+            <many-to-one name="purchaseDetails class="eg.Purchase"/>
+            <many-to-one name="item" class="eg.Item"/>
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Composite elements may appear in queries using the same syntax as
+            associations to other entities.
+        </para>
+
+    </sect1>
+
+    <sect1 id="components-asmapindex">
+        <title>Components as Map indices</title>
+
+        <para>
+            The <literal>&lt;composite-map-key&gt;</literal> element lets you map a
+            component class as the key of a <literal>Map</literal>. Make sure you override
+            <literal>hashCode()</literal> and <literal>equals()</literal> correctly on
+            the component class.
+        </para>
+    </sect1>
+
+    <sect1 id="components-compositeid" revision="1">
+        <title>Components as composite identifiers</title>
+
+        <para>
+            You may use a component as an identifier of an entity class. Your component
+            class must satisfy certain requirements:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    It must implement <literal>java.io.Serializable</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    It must re-implement <literal>equals()</literal> and
+                    <literal>hashCode()</literal>, consistently with the database's 
+                    notion of composite key equality.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            <emphasis>Note: in Hibernate3, the second requirement is not an absolutely hard
+            requirement of Hibernate. But do it anyway.</emphasis>
+        </para>
+
+        <para>
+            You can't use an <literal>IdentifierGenerator</literal> to generate composite keys.
+            Instead the application must assign its own identifiers.
+        </para>
+
+        <para>
+            Use the <literal>&lt;composite-id&gt;</literal> tag (with nested 
+            <literal>&lt;key-property&gt;</literal> elements) in place of the usual 
+            <literal>&lt;id&gt;</literal> declaration. For example, the
+            <literal>OrderLine</literal> class has a primary key that depends upon
+            the (composite) primary key of <literal>Order</literal>.
+        </para>
+
+        <programlisting><![CDATA[<class name="OrderLine">
+    
+    <composite-id name="id" class="OrderLineId">
+        <key-property name="lineId"/>
+        <key-property name="orderId"/>
+        <key-property name="customerId"/>
+    </composite-id>
+    
+    <property name="name"/>
+    
+    <many-to-one name="order" class="Order"
+            insert="false" update="false">
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </many-to-one>
+    ....
+    
+</class>]]></programlisting>
+
+        <para>
+            Now, any foreign keys referencing the <literal>OrderLine</literal> table are also 
+            composite. You must declare this in your mappings for other classes. An association 
+            to <literal>OrderLine</literal> would be mapped like this:
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
+<!-- the "class" attribute is optional, as usual -->
+    <column name="lineId"/>
+    <column name="orderId"/>
+    <column name="customerId"/>
+</many-to-one>]]></programlisting>
+
+        <para>
+            (Note that the <literal>&lt;column&gt;</literal> tag is an alternative to the 
+            <literal>column</literal> attribute everywhere.) 
+        </para>
+        
+        <para>
+            A <literal>many-to-many</literal> association to <literal>OrderLine</literal> also
+            uses the composite foreign key:
+        </para>
+    
+    <programlisting><![CDATA[<set name="undeliveredOrderLines">
+    <key column name="warehouseId"/>
+    <many-to-many class="OrderLine">
+        <column name="lineId"/>
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </many-to-many>
+</set>]]></programlisting>
+
+        <para>
+            The collection of <literal>OrderLine</literal>s in <literal>Order</literal> would 
+            use:
+        </para>
+
+    <programlisting><![CDATA[<set name="orderLines" inverse="true">
+    <key>
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </key>
+    <one-to-many class="OrderLine"/>
+</set>]]></programlisting>
+
+        <para>
+            (The <literal>&lt;one-to-many&gt;</literal> element, as usual, declares no columns.)
+        </para>
+        
+        <para>
+            If <literal>OrderLine</literal> itself owns a collection, it also has a composite 
+            foreign key.
+        </para>
+
+        <programlisting><![CDATA[<class name="OrderLine">
+    ....
+    ....
+    <list name="deliveryAttempts">
+        <key>   <!-- a collection inherits the composite key type -->
+            <column name="lineId"/>
+            <column name="orderId"/>
+            <column name="customerId"/>
+        </key>
+        <list-index column="attemptId" base="1"/>
+        <composite-element class="DeliveryAttempt">
+            ...
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="components-dynamic" revision="1">
+        <title>Dynamic components</title>
+
+        <para>
+            You may even map a property of type <literal>Map</literal>:
+        </para>
+
+    <programlisting><![CDATA[<dynamic-component name="userAttributes">
+    <property name="foo" column="FOO" type="string"/>
+    <property name="bar" column="BAR" type="integer"/>
+    <many-to-one name="baz" class="Baz" column="BAZ_ID"/>
+</dynamic-component>]]></programlisting>
+
+        <para>
+            The semantics of a <literal>&lt;dynamic-component&gt;</literal> mapping are identical
+            to <literal>&lt;component&gt;</literal>. The advantage of this kind of mapping is 
+            the ability to determine the actual properties of the bean at deployment time, just
+            by editing the mapping document. Runtime manipulation of the mapping document is 
+            also possible, using a DOM parser. Even better, you can access (and change) Hibernate's
+            configuration-time metamodel via the <literal>Configuration</literal> object.
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/configuration.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/configuration.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/configuration.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1738 @@
+<chapter id="session-configuration" revision="1">
+
+    <title>Configuration</title>
+    
+    <para>
+        Because Hibernate is designed to operate in many different environments, there
+        are a large number of configuration parameters. Fortunately, most have sensible
+        default values and Hibernate is distributed with an example 
+        <literal>hibernate.properties</literal> file in <literal>etc/</literal> that shows
+        the various options. Just put the example file in your classpath and customize it.
+    </para>
+
+    <sect1 id="configuration-programmatic" revision="1">
+        <title>Programmatic configuration</title>
+
+        <para>
+            An instance of <literal>org.hibernate.cfg.Configuration</literal>
+            represents an entire set of mappings of an application's Java types to an
+            SQL database. The <literal>Configuration</literal> is used to build an
+            (immutable) <literal>SessionFactory</literal>. The mappings are compiled
+            from various XML mapping files.
+        </para>
+
+        <para>
+            You may obtain a <literal>Configuration</literal> instance by instantiating 
+            it directly and specifying XML mapping documents. If the mapping files are
+            in the classpath, use <literal>addResource()</literal>:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addResource("Item.hbm.xml")
+    .addResource("Bid.hbm.xml");]]></programlisting>
+
+        <para>
+            An alternative (sometimes better) way is to specify the mapped class, and
+            let Hibernate find the mapping document for you:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addClass(org.hibernate.auction.Item.class)
+    .addClass(org.hibernate.auction.Bid.class);]]></programlisting>
+
+        <para>
+            Then Hibernate will look for mapping files named
+            <literal>/org/hibernate/auction/Item.hbm.xml</literal> and
+            <literal>/org/hibernate/auction/Bid.hbm.xml</literal> in the classpath.
+            This approach eliminates any hardcoded filenames.
+        </para>
+        
+        <para>
+            A <literal>Configuration</literal> also allows you to specify configuration
+            properties:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addClass(org.hibernate.auction.Item.class)
+    .addClass(org.hibernate.auction.Bid.class)
+    .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
+    .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
+    .setProperty("hibernate.order_updates", "true");]]></programlisting>
+    
+        <para>
+            This is not the only way to pass configuration properties to Hibernate. 
+            The various options include:
+        </para>
+
+        <orderedlist spacing="compact">
+            <listitem>
+                <para>
+                    Pass an instance of <literal>java.util.Properties</literal> to
+                    <literal>Configuration.setProperties()</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Place <literal>hibernate.properties</literal> in a root directory 
+                    of the classpath.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Set <literal>System</literal> properties using
+                    <literal>java -Dproperty=value</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Include <literal>&lt;property&gt;</literal> elements in
+                    <literal>hibernate.cfg.xml</literal> (discussed later).
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <para>
+            <literal>hibernate.properties</literal> is the easiest approach if you
+            want to get started quickly.
+        </para>
+
+        <para>
+            The <literal>Configuration</literal> is intended as a startup-time object, 
+            to be discarded once a <literal>SessionFactory</literal> is created.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="configuration-sessionfactory">
+        <title>Obtaining a SessionFactory</title>
+
+        <para>
+            When all mappings have been parsed by the <literal>Configuration</literal>, 
+            the application must obtain a factory for <literal>Session</literal> instances. 
+            This factory is intended to be shared by all application threads:
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sessions = cfg.buildSessionFactory();]]></programlisting>
+
+        <para>
+            Hibernate does allow your application to instantiate more than one
+            <literal>SessionFactory</literal>. This is useful if you are using more than 
+            one database.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-hibernatejdbc" revision="1">
+        <title>JDBC connections</title>
+
+        <para>
+            Usually, you want to have the <literal>SessionFactory</literal> create and pool JDBC 
+            connections for you. If you take this approach, opening a <literal>Session</literal> 
+            is as simple as:
+        </para>
+
+        <programlisting><![CDATA[Session session = sessions.openSession(); // open a new Session]]></programlisting>
+        
+        <para>
+            As soon as you do something that requires access to the database, a JDBC connection
+            will be obtained from the pool.
+        </para>
+
+        <para>
+            For this to work, we need to pass some JDBC connection properties to Hibernate.
+            All Hibernate property names and semantics are defined on the class 
+            <literal>org.hibernate.cfg.Environment</literal>. We will now describe the most
+            important settings for JDBC connection configuration.
+        </para>
+
+        <para>
+            Hibernate will obtain (and pool) connections using <literal>java.sql.DriverManager</literal> 
+            if you set the following properties:
+        </para>
+
+        <table frame="topbot">
+            <title>Hibernate JDBC Properties</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Property name</entry>
+                        <entry>Purpose</entry>
+                    </row>
+                </thead>
+            <tbody>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.driver_class</literal>
+                </entry>
+                <entry>
+                    <emphasis>jdbc driver class</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.url</literal>
+                </entry>
+                <entry>
+                    <emphasis>jdbc URL</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.username</literal>
+                </entry>
+                <entry>
+                    <emphasis>database user</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.password</literal>
+                </entry>
+                <entry>
+                    <emphasis>database user password</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.pool_size</literal>
+                </entry>
+                <entry>
+                    <emphasis>maximum number of pooled connections</emphasis>
+                </entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+            Hibernate's own connection pooling algorithm is however quite rudimentary. 
+            It is intended to help you get started and is <emphasis>not intended for use 
+            in a production system</emphasis> or even for performance testing. You should
+            use a third party pool for best performance and stability. Just replace the 
+            <literal>hibernate.connection.pool_size</literal> property with connection 
+            pool specific settings. This will turn off Hibernate's internal pool. For
+            example, you might like to use C3P0.
+        </para>
+
+        <para>
+            C3P0 is an open source JDBC connection pool distributed along with 
+            Hibernate in the <literal>lib</literal> directory. Hibernate will use its
+            <literal>C3P0ConnectionProvider</literal> for connection pooling if you set 
+            <literal>hibernate.c3p0.*</literal> properties. If you'd like to use Proxool
+            refer to the packaged <literal>hibernate.properties</literal> and the Hibernate
+            web site for more information.
+        </para>
+
+        <para>
+            Here is an example <literal>hibernate.properties</literal> file for C3P0:
+        </para>
+
+        <programlisting id="c3p0-configuration" revision="1"><![CDATA[hibernate.connection.driver_class = org.postgresql.Driver
+hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
+hibernate.connection.username = myuser
+hibernate.connection.password = secret
+hibernate.c3p0.min_size=5
+hibernate.c3p0.max_size=20
+hibernate.c3p0.timeout=1800
+hibernate.c3p0.max_statements=50
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+        <para>
+            For use inside an application server, you should almost always configure 
+            Hibernate to obtain connections from an application server  
+            <literal>Datasource</literal> registered in JNDI. You'll need to set at
+            least one of the following properties:
+        </para>
+
+        <table frame="topbot">
+            <title>Hibernate Datasource Properties</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Propery name</entry>
+                        <entry>Purpose</entry>
+                    </row>
+                </thead>
+            <tbody>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.datasource</literal>
+                </entry>
+                <entry>
+                    <emphasis>datasource JNDI name</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.jndi.url</literal>
+                </entry>
+                <entry>
+                    <emphasis>URL of the JNDI provider</emphasis> (optional)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.jndi.class</literal>
+                </entry>
+                <entry>
+                    <emphasis>class of the JNDI <literal>InitialContextFactory</literal></emphasis> (optional)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.username</literal>
+                </entry>
+                <entry>
+                    <emphasis>database user</emphasis> (optional)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.password</literal>
+                </entry>
+                <entry>
+                    <emphasis>database user password</emphasis> (optional)
+                </entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+            Here's an example <literal>hibernate.properties</literal> file for an
+            application server provided JNDI datasource:
+        </para>
+
+        <programlisting><![CDATA[hibernate.connection.datasource = java:/comp/env/jdbc/test
+hibernate.transaction.factory_class = \
+    org.hibernate.transaction.JTATransactionFactory
+hibernate.transaction.manager_lookup_class = \
+    org.hibernate.transaction.JBossTransactionManagerLookup
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+        <para>
+            JDBC connections obtained from a JNDI datasource will automatically participate
+            in the container-managed transactions of the application server.
+        </para>
+
+        <para>
+            Arbitrary connection properties may be given by prepending
+            "<literal>hibernate.connnection</literal>" to the property name. For example, you
+            may specify a <literal>charSet</literal> using <literal>hibernate.connection.charSet</literal>.
+        </para>
+
+        <para>
+            You may define your own plugin strategy for obtaining JDBC connections by implementing the
+            interface <literal>org.hibernate.connection.ConnectionProvider</literal>. You may select
+            a custom implementation by setting <literal>hibernate.connection.provider_class</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-optional" revision="1">
+        <title>Optional configuration properties</title>
+        
+        <para>
+            There are a number of other properties that control the behaviour of Hibernate
+            at runtime. All are optional and have reasonable default values.
+        </para>
+
+        <para>
+        	<emphasis>Warning: some of these properties are "system-level" only.</emphasis>
+            System-level properties can be set only via <literal>java -Dproperty=value</literal> or
+            <literal>hibernate.properties</literal>. They may <emphasis>not</emphasis> be set by
+            the other techniques described above.
+        </para>
+
+        <table frame="topbot" id="configuration-optional-properties" revision="8">
+            <title>Hibernate Configuration Properties</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Property name</entry>
+                        <entry>Purpose</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.dialect</literal>
+                        </entry>
+                        <entry>
+                            The classname of a Hibernate <literal>Dialect</literal> which 
+                            allows Hibernate to generate SQL optimized for a particular
+                            relational database.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>full.classname.of.Dialect</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.show_sql</literal>
+                        </entry>
+                        <entry>
+                            Write all SQL statements to console. This is an alternative
+                            to setting the log category <literal>org.hibernate.SQL</literal>
+                            to <literal>debug</literal>.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.format_sql</literal>
+                        </entry>
+                        <entry>
+                            Pretty print the SQL in the log and console.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_schema</literal>
+                        </entry>
+                        <entry>
+                            Qualify unqualified tablenames with the given schema/tablespace
+                            in generated SQL.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>SCHEMA_NAME</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_catalog</literal>
+                        </entry>
+                        <entry>
+                            Qualify unqualified tablenames with the given catalog
+                            in generated SQL.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>CATALOG_NAME</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.session_factory_name</literal>
+                        </entry>
+                        <entry>
+                            The <literal>SessionFactory</literal> will be automatically
+                            bound to this name in JNDI after it has been created.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>jndi/composite/name</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.max_fetch_depth</literal>
+                        </entry>
+                        <entry>
+                            Set a maximum "depth" for the outer join fetch tree
+                            for single-ended associations (one-to-one, many-to-one).
+                            A <literal>0</literal> disables default outer join fetching.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                recommended values between <literal>0</literal> and 
+                                <literal>3</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_batch_fetch_size</literal>
+                        </entry>
+                        <entry>
+                            Set a default size for Hibernate batch fetching of associations.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                recommended values <literal>4</literal>, <literal>8</literal>, 
+                                <literal>16</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_entity_mode</literal>
+                        </entry>
+                        <entry>
+                            Set a default mode for entity representation for all sessions
+                            opened from this <literal>SessionFactory</literal>
+                            <para>
+                                <literal>dynamic-map</literal>, <literal>dom4j</literal>,
+                                <literal>pojo</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.order_updates</literal>
+                        </entry>
+                        <entry>
+                            Force Hibernate to order SQL updates by the primary key value
+                            of the items being updated. This will result in fewer transaction
+                            deadlocks in highly concurrent systems.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.generate_statistics</literal>
+                        </entry>
+                        <entry>
+                            If enabled, Hibernate will collect statistics useful for
+                            performance tuning.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.use_identifer_rollback</literal>
+                        </entry>
+                        <entry>
+                            If enabled, generated identifier properties will be
+                            reset to default values when objects are deleted.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.use_sql_comments</literal>
+                        </entry>
+                        <entry>
+                            If turned on, Hibernate will generate comments inside the SQL, for
+                            easier debugging, defaults to <literal>false</literal>.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-jdbc-properties" revision="8">
+            <title>Hibernate JDBC and Connection Properties</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Property name</entry>
+                        <entry>Purpose</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.fetch_size</literal>
+                        </entry>
+                        <entry>
+                            A non-zero value determines the JDBC fetch size (calls
+                            <literal>Statement.setFetchSize()</literal>).
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.batch_size</literal>
+                        </entry>
+                        <entry>
+                            A non-zero value enables use of JDBC2 batch updates by Hibernate.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                recommended values between <literal>5</literal> and <literal>30</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.batch_versioned_data</literal>
+                        </entry>
+                        <entry>
+                            Set this property to <literal>true</literal> if your JDBC driver returns
+                            correct row counts from <literal>executeBatch()</literal> (it is usually
+                            safe to turn this option on). Hibernate will then use batched DML for
+                            automatically versioned data. Defaults to <literal>false</literal>.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.factory_class</literal>
+                        </entry>
+                        <entry>
+                            Select a custom <literal>Batcher</literal>. Most applications
+                            will not need this configuration property.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>classname.of.Batcher</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_scrollable_resultset</literal>
+                        </entry>
+                        <entry>
+                            Enables use of JDBC2 scrollable resultsets by Hibernate.
+                            This property is only necessary when using user supplied
+                            JDBC connections, Hibernate uses connection metadata otherwise.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_streams_for_binary</literal>
+                        </entry>
+                        <entry>
+                            Use streams when writing/reading <literal>binary</literal>
+                            or <literal>serializable</literal> types to/from JDBC
+                            (system-level property).
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_get_generated_keys</literal>
+                        </entry>
+                        <entry>
+                            Enable use of JDBC3 <literal>PreparedStatement.getGeneratedKeys()</literal>
+                            to retrieve natively generated keys after insert. Requires JDBC3+ driver
+                            and JRE1.4+, set to false if your driver has problems with the Hibernate
+                            identifier generators. By default, tries to determine the driver capabilites
+                            using connection metadata.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.provider_class</literal>
+                        </entry>
+                        <entry>
+                            The classname of a custom <literal>ConnectionProvider</literal> which provides
+                            JDBC connections to Hibernate.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>classname.of.ConnectionProvider</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                    <entry>
+                        <literal>hibernate.connection.isolation</literal>
+                    </entry>
+                    <entry>
+                        Set the JDBC transaction isolation level. Check
+                        <literal>java.sql.Connection</literal> for meaningful values but
+                        note that most databases do not support all isolation levels.
+                        <para>
+                            <emphasis role="strong">eg.</emphasis> 
+                            <literal>1, 2, 4, 8</literal>
+                        </para>
+                    </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.autocommit</literal>
+                        </entry>
+                        <entry>
+                            Enables autocommit for JDBC pooled connections (not recommended).
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.release_mode</literal>
+                        </entry>
+                        <entry>
+                            Specify when Hibernate should release JDBC connections. By default, 
+                            a JDBC connection is held until the session is explicitly closed or
+                            disconnected. For an application server JTA datasource, you should use
+                            <literal>after_statement</literal> to aggressively release connections
+                            after every JDBC call. For a non-JTA connection, it often makes sense to
+                            release the connection at the end of each transaction, by using
+                            <literal>after_transaction</literal>. <literal>auto</literal> will
+                            choose <literal>after_statement</literal> for the JTA and CMT transaction
+                            strategies and <literal>after_transaction</literal> for the JDBC 
+                            transaction strategy.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>auto</literal> (default) | <literal>on_close</literal> |
+                                <literal>after_transaction</literal> | <literal>after_statement</literal>
+                            </para>
+                            <para>
+                                Note that this setting only affects <literal>Session</literal>s returned from
+                                <literal>SessionFactory.openSession</literal>.  For <literal>Session</literal>s
+                                obtained through <literal>SessionFactory.getCurrentSession</literal>, the
+                                <literal>CurrentSessionContext</literal> implementation configured for use
+                                controls the connection release mode for those <literal>Session</literal>s.
+                                See <xref linkend="architecture-current-session"/>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                    <entry>
+                        <literal>hibernate.connection.<emphasis>&lt;propertyName&gt;</emphasis></literal>
+                    </entry>
+                    <entry>
+                        Pass the JDBC property <literal>propertyName</literal>
+                        to <literal>DriverManager.getConnection()</literal>.
+                    </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jndi.<emphasis>&lt;propertyName&gt;</emphasis></literal>
+                        </entry>
+                        <entry>
+                            Pass the property <literal>propertyName</literal> to
+                            the JNDI <literal>InitialContextFactory</literal>.
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-cache-properties" revision="7">
+            <title>Hibernate Cache Properties</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Property name</entry>
+                        <entry>Purpose</entry>
+                    </row>
+                </thead>
+                <tbody>
+                     <row>
+                        <entry>
+                            <literal>hibernate.cache.provider_class</literal>
+                        </entry>
+                        <entry>
+                            The classname of a custom <literal>CacheProvider</literal>.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>classname.of.CacheProvider</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_minimal_puts</literal>
+                        </entry>
+                        <entry>
+                            Optimize second-level cache operation to minimize writes, at the
+                            cost of more frequent reads. This setting is most useful for 
+                            clustered caches and, in Hibernate3, is enabled by default for
+                            clustered cache implementations.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_query_cache</literal>
+                        </entry>
+                        <entry>
+                            Enable the query cache, individual queries still have to be set cachable.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_second_level_cache</literal>
+                        </entry>
+                        <entry>
+                            May be used to completely disable the second level cache, which is enabled
+                            by default for classes which specify a <literal>&lt;cache&gt;</literal>
+                            mapping.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.query_cache_factory</literal>
+                        </entry>
+                        <entry>
+                            The classname of a custom <literal>QueryCache</literal> interface,
+                            defaults to the built-in <literal>StandardQueryCache</literal>.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>classname.of.QueryCache</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.region_prefix</literal>
+                        </entry>
+                        <entry>
+                            A prefix to use for second-level cache region names.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>prefix</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_structured_entries</literal>
+                        </entry>
+                        <entry>
+                            Forces Hibernate to store data in the second-level cache
+                            in a more human-friendly format.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-transaction-properties" revision="9">
+            <title>Hibernate Transaction Properties</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Property name</entry>
+                        <entry>Purpose</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.factory_class</literal>
+                        </entry>
+                        <entry>
+                            The classname of a <literal>TransactionFactory</literal>
+                            to use with Hibernate <literal>Transaction</literal> API
+                            (defaults to <literal>JDBCTransactionFactory</literal>).
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>classname.of.TransactionFactory</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>jta.UserTransaction</literal>
+                        </entry>
+                        <entry>
+                            A JNDI name used by <literal>JTATransactionFactory</literal> to
+                            obtain the JTA <literal>UserTransaction</literal> from the
+                            application server.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>jndi/composite/name</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.manager_lookup_class</literal>
+                        </entry>
+                        <entry>
+                            The classname of a <literal>TransactionManagerLookup</literal>
+                            - required when JVM-level caching is enabled or when using hilo 
+                            generator in a JTA environment.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>classname.of.TransactionManagerLookup</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.flush_before_completion</literal>
+                        </entry>
+                        <entry>
+                            If enabled, the session will be automatically flushed during the
+                            before completion phase of the transaction. Built-in and
+                            automatic session context management is preferred, see
+                            <xref linkend="architecture-current-session"/>.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.auto_close_session</literal>
+                        </entry>
+                        <entry>
+                            If enabled, the session will be automatically closed during the
+                            after completion phase of the transaction. Built-in and
+                            utomatic session context management is preferred, see
+                            <xref linkend="architecture-current-session"/>.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-misc-properties" revision="10">
+            <title>Miscellaneous Properties</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Property name</entry>
+                        <entry>Purpose</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.current_session_context_class</literal>
+                        </entry>
+                        <entry>
+                            Supply a (custom) strategy for the scoping of the "current"
+                            <literal>Session</literal>. See
+                            <xref linkend="architecture-current-session"/> for more
+                            information about the built-in strategies.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>jta</literal> | <literal>thread</literal> |
+                                <literal>managed</literal> | <literal>custom.Class</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.query.factory_class</literal>
+                        </entry>
+                        <entry>
+                            Chooses the HQL parser implementation.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> or
+                                <literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.query.substitutions</literal>
+                        </entry>
+                        <entry>
+                            Mapping from tokens in Hibernate queries to SQL tokens
+                            (tokens might be function or literal names, for example).
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.hbm2ddl.auto</literal>
+                        </entry>
+                        <entry>
+                            Automatically validate or export schema DDL to the database 
+                            when the <literal>SessionFactory</literal> is created. With
+                            <literal>create-drop</literal>, the database schema will be 
+                            dropped when the <literal>SessionFactory</literal> is closed 
+                            explicitly.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>validate</literal> | <literal>update</literal> | 
+                                <literal>create</literal> | <literal>create-drop</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cglib.use_reflection_optimizer</literal>
+                        </entry>
+                        <entry>
+                            Enables use of CGLIB instead of runtime reflection (System-level
+                            property). Reflection can sometimes be useful when troubleshooting,
+                            note that Hibernate always requires CGLIB even if you turn off the
+                            optimizer. You can not set this property in <literal>hibernate.cfg.xml</literal>.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <sect2 id="configuration-optional-dialects" revision="1">
+            <title>SQL Dialects</title>
+
+            <para>
+                You should always set the <literal>hibernate.dialect</literal> property to the correct
+                <literal>org.hibernate.dialect.Dialect</literal> subclass for your database. If you
+                specify a dialect, Hibernate will use sensible defaults for some of the
+                other properties listed above, saving you the effort of specifying them manually.
+            </para>
+
+            <table frame="topbot" id="sql-dialects" revision="2">
+                <title>Hibernate SQL Dialects (<literal>hibernate.dialect</literal>)</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>RDBMS</entry>
+                            <entry>Dialect</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry>DB2</entry> <entry><literal>org.hibernate.dialect.DB2Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>DB2 AS/400</entry> <entry><literal>org.hibernate.dialect.DB2400Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>DB2 OS390</entry> <entry><literal>org.hibernate.dialect.DB2390Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>PostgreSQL</entry> <entry><literal>org.hibernate.dialect.PostgreSQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL</entry> <entry><literal>org.hibernate.dialect.MySQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL with InnoDB</entry> <entry><literal>org.hibernate.dialect.MySQLInnoDBDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL with MyISAM</entry> <entry><literal>org.hibernate.dialect.MySQLMyISAMDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Oracle (any version)</entry> <entry><literal>org.hibernate.dialect.OracleDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Oracle 9i/10g</entry> <entry><literal>org.hibernate.dialect.Oracle9Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Sybase</entry> <entry><literal>org.hibernate.dialect.SybaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Sybase Anywhere</entry> <entry><literal>org.hibernate.dialect.SybaseAnywhereDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Microsoft SQL Server</entry> <entry><literal>org.hibernate.dialect.SQLServerDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>SAP DB</entry> <entry><literal>org.hibernate.dialect.SAPDBDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Informix</entry> <entry><literal>org.hibernate.dialect.InformixDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>HypersonicSQL</entry> <entry><literal>org.hibernate.dialect.HSQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Ingres</entry> <entry><literal>org.hibernate.dialect.IngresDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Progress</entry> <entry><literal>org.hibernate.dialect.ProgressDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Mckoi SQL</entry> <entry><literal>org.hibernate.dialect.MckoiDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Interbase</entry> <entry><literal>org.hibernate.dialect.InterbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Pointbase</entry> <entry><literal>org.hibernate.dialect.PointbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>FrontBase</entry> <entry><literal>org.hibernate.dialect.FrontbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Firebird</entry> <entry><literal>org.hibernate.dialect.FirebirdDialect</literal></entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-outerjoin" revision="4">
+            <title>Outer Join Fetching</title>
+
+            <para>
+                If your database supports ANSI, Oracle or Sybase style outer joins, <emphasis>outer join
+                fetching</emphasis> will often increase performance by limiting the number of round
+                trips to and from the database (at the cost of possibly more work performed by
+                the database itself). Outer join fetching allows a whole graph of objects connected
+                by many-to-one, one-to-many, many-to-many and one-to-one associations to be retrieved 
+                in a single SQL <literal>SELECT</literal>.
+            </para>
+
+            <para>
+                Outer join fetching may be disabled <emphasis>globally</emphasis> by setting
+                the property <literal>hibernate.max_fetch_depth</literal> to <literal>0</literal>.
+                A setting of <literal>1</literal> or higher enables outer join fetching for
+                one-to-one and many-to-one associations which have been mapped with 
+                <literal>fetch="join"</literal>.
+            </para>
+
+            <para>
+                See <xref linkend="performance-fetching"/> for more information.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-binarystreams" revision="1">
+            <title>Binary Streams</title>
+
+            <para>
+                Oracle limits the size of <literal>byte</literal> arrays that may
+                be passed to/from its JDBC driver. If you wish to use large instances of
+                <literal>binary</literal> or <literal>serializable</literal> type, you should
+                enable <literal>hibernate.jdbc.use_streams_for_binary</literal>.
+                <emphasis>This is a system-level setting only.</emphasis>
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-cacheprovider" revision="2">
+            <title>Second-level and query cache</title>
+
+            <para>
+                The properties prefixed by <literal>hibernate.cache</literal>
+                allow you to use a process or cluster scoped second-level cache system
+                with Hibernate. See the <xref linkend="performance-cache"/> for
+                more details.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-querysubstitution">
+            <title>Query Language Substitution</title>
+
+            <para>
+                You may define new Hibernate query tokens using <literal>hibernate.query.substitutions</literal>.
+                For example:
+            </para>
+
+            <programlisting>hibernate.query.substitutions true=1, false=0</programlisting>
+
+            <para>
+                would cause the tokens <literal>true</literal> and <literal>false</literal> to be translated to
+                integer literals in the generated SQL.
+            </para>
+
+            <programlisting>hibernate.query.substitutions toLowercase=LOWER</programlisting>
+
+            <para>
+                would allow you to rename the SQL <literal>LOWER</literal> function.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-statistics" revision="2">
+            <title>Hibernate statistics</title>
+
+            <para>
+                If you enable <literal>hibernate.generate_statistics</literal>, Hibernate will 
+                expose a number of metrics that are useful when tuning a running system via
+                <literal>SessionFactory.getStatistics()</literal>. Hibernate can even be configured
+                to expose these statistics via JMX. Read the Javadoc of the interfaces in
+                <literal>org.hibernate.stats</literal> for more information.
+            </para>
+
+        </sect2>
+    </sect1>
+
+    <sect1 id="configuration-logging">
+        <title>Logging</title>
+
+        <para>
+            Hibernate logs various events using Apache commons-logging.
+        </para>
+
+        <para>
+            The commons-logging service will direct output to either Apache Log4j
+            (if you include <literal>log4j.jar</literal> in your classpath) or
+            JDK1.4 logging (if running under JDK1.4 or above). You may download
+            Log4j from <literal>http://jakarta.apache.org</literal>.
+            To use Log4j you will need to place a <literal>log4j.properties</literal>
+            file in your classpath, an example properties file is distributed with
+            Hibernate in the <literal>src/</literal> directory.
+        </para>
+        
+        <para>
+            We strongly recommend that you familiarize yourself with Hibernate's log
+            messages. A lot of work has been put into making the Hibernate log as
+            detailed as possible, without making it unreadable. It is an essential
+            troubleshooting device. The most interesting log categories are the
+            following:
+        </para>
+        
+            <table frame="topbot" id="log-categories" revision="2">
+                <title>Hibernate Log Categories</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>Category</entry>
+                            <entry>Function</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>org.hibernate.SQL</literal></entry>
+                            <entry>Log all SQL DML statements as they are executed</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.type</literal></entry>
+                            <entry>Log all JDBC parameters</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.tool.hbm2ddl</literal></entry>
+                            <entry>Log all SQL DDL statements as they are executed</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.pretty</literal></entry>
+                            <entry>
+                                Log the state of all entities (max 20 entities) associated
+                                with the session at flush time
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.cache</literal></entry>
+                            <entry>Log all second-level cache activity</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction</literal></entry>
+                            <entry>Log transaction related activity</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.jdbc</literal></entry>
+                            <entry>Log all JDBC resource acquisition</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.hql.ast.AST</literal></entry>
+                            <entry>
+                                Log HQL and SQL ASTs during query parsing
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.secure</literal></entry>
+                            <entry>Log all JAAS authorization requests</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate</literal></entry>
+                            <entry>
+                                Log everything (a lot of information, but very useful for
+                                troubleshooting)
+                            </entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+            
+        <para>
+            When developing applications with Hibernate, you should almost always work with
+            <literal>debug</literal> enabled for the category <literal>org.hibernate.SQL</literal>,
+            or, alternatively, the property <literal>hibernate.show_sql</literal> enabled.
+        </para>
+                       
+        
+    </sect1>
+
+    <sect1 id="configuration-namingstrategy">
+        <title>Implementing a <literal>NamingStrategy</literal></title>
+
+        <para>
+            The interface <literal>org.hibernate.cfg.NamingStrategy</literal> allows you
+            to specify a "naming standard" for database objects and schema elements.
+        </para>
+
+        <para>
+            You may provide rules for automatically generating database identifiers from
+            Java identifiers or for processing "logical" column and table names given in
+            the mapping file into  "physical" table and column names. This feature helps
+            reduce the verbosity of the mapping document, eliminating repetitive noise
+            (<literal>TBL_</literal> prefixes, for example). The default strategy used by
+            Hibernate is quite minimal.
+        </para>
+
+        <para>
+            You may specify a different strategy by calling
+            <literal>Configuration.setNamingStrategy()</literal> before adding mappings:
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sf = new Configuration()
+    .setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
+    .addFile("Item.hbm.xml")
+    .addFile("Bid.hbm.xml")
+    .buildSessionFactory();]]></programlisting>
+    
+        <para>
+            <literal>org.hibernate.cfg.ImprovedNamingStrategy</literal> is a built-in
+            strategy that might be a useful starting point for some applications.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-xmlconfig" revision="2">
+        <title>XML configuration file</title>
+
+        <para>
+            An alternative approach to configuration is to specify a full configuration in
+            a file named <literal>hibernate.cfg.xml</literal>. This file can be used as a
+            replacement for the <literal>hibernate.properties</literal> file or, if both
+            are present, to override properties.
+        </para>
+
+        <para>
+            The XML configuration file is by default expected to be in the root o
+            your <literal>CLASSPATH</literal>. Here is an example:
+        </para>
+
+        <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+    "-//Hibernate/Hibernate Configuration DTD//EN"
+    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <!-- a SessionFactory instance listed as /jndi/name -->
+    <session-factory
+        name="java:hibernate/SessionFactory">
+
+        <!-- properties -->
+        <property name="connection.datasource">java:/comp/env/jdbc/MyDB</property>
+        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
+        <property name="show_sql">false</property>
+        <property name="transaction.factory_class">
+            org.hibernate.transaction.JTATransactionFactory
+        </property>
+        <property name="jta.UserTransaction">java:comp/UserTransaction</property>
+
+        <!-- mapping files -->
+        <mapping resource="org/hibernate/auction/Item.hbm.xml"/>
+        <mapping resource="org/hibernate/auction/Bid.hbm.xml"/>
+
+        <!-- cache settings -->
+        <class-cache class="org.hibernate.auction.Item" usage="read-write"/>
+        <class-cache class="org.hibernate.auction.Bid" usage="read-only"/>
+        <collection-cache collection="org.hibernate.auction.Item.bids" usage="read-write"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+            As you can see, the advantage of this approach is the externalization of the
+            mapping file names to configuration. The <literal>hibernate.cfg.xml</literal>
+            is also more convenient once you have to tune the Hibernate cache. Note that is
+            your choice to use either <literal>hibernate.properties</literal> or
+            <literal>hibernate.cfg.xml</literal>, both are equivalent, except for the above
+            mentioned benefits of using the XML syntax.
+        </para>
+
+       <para>
+           With the XML configuration, starting Hibernate is then as simple as
+       </para>
+
+       <programlisting><![CDATA[SessionFactory sf = new Configuration().configure().buildSessionFactory();]]></programlisting>
+
+       <para>
+           You can pick a different XML configuration file using
+       </para>
+
+       <programlisting><![CDATA[SessionFactory sf = new Configuration()
+    .configure("catdb.cfg.xml")
+    .buildSessionFactory();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="configuration-j2ee" revision="1">
+        <title>J2EE Application Server integration</title>
+
+        <para>
+            Hibernate has the following integration points for J2EE infrastructure:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>Container-managed datasources</emphasis>: Hibernate can use
+                JDBC connections managed by the container and provided through JNDI. Usually,
+                a JTA compatible <literal>TransactionManager</literal> and a
+                <literal>ResourceManager</literal> take care of transaction management (CMT),
+                esp. distributed transaction handling across several datasources. You may
+                of course also demarcate transaction boundaries programatically (BMT) or
+                you might want to use the optional Hibernate <literal>Transaction</literal>
+                API for this to keep your code portable.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>Automatic JNDI binding</emphasis>: Hibernate can bind its
+                <literal>SessionFactory</literal> to JNDI after startup.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>JTA Session binding:</emphasis> The Hibernate <literal>Session</literal>
+                may be automatically bound to the scope of JTA transactions. Simply
+                lookup the <literal>SessionFactory</literal> from JNDI and get the current
+                <literal>Session</literal>. Let Hibernate take care of flushing and closing the
+                <literal>Session</literal> when your JTA transaction completes. Transaction
+                demarcation is either declarative (CMT) or programmatic (BMT/UserTransaction).
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>JMX deployment:</emphasis> If you have a JMX capable application server
+                (e.g. JBoss AS), you can chose to deploy Hibernate as a managed MBean. This saves
+                you the one line startup code to build your <literal>SessionFactory</literal> from
+                a <literal>Configuration</literal>. The container will startup your
+                <literal>HibernateService</literal>, and ideally also take care of service
+                dependencies (Datasource has to be available before Hibernate starts, etc).
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Depending on your environment, you might have to set the configuration option
+            <literal>hibernate.connection.aggressive_release</literal> to true if your
+            application server shows "connection containment" exceptions.
+        </para>
+
+        <sect2 id="configuration-optional-transactionstrategy" revision="3">
+            <title>Transaction strategy configuration</title>
+
+            <para>
+                The Hibernate <literal>Session</literal> API is independent of any transaction
+                demarcation system in your architecture. If you let Hibernate use JDBC directly,
+                through a connection pool, you may begin and end your transactions by calling
+                the JDBC API. If you run in a J2EE application server, you might want to use bean-managed
+                transactions and call the JTA API and <literal>UserTransaction</literal> when needed.
+            </para>
+
+            <para>
+                To keep your code portable between these two (and other) environments we recommend the optional
+                Hibernate <literal>Transaction</literal> API, which wraps and hides the underlying system.
+                You have to specify a factory class for <literal>Transaction</literal> instances by setting the
+                Hibernate configuration property <literal>hibernate.transaction.factory_class</literal>.
+            </para>
+
+            <para>
+                There are three standard (built-in) choices:
+            </para>
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.JDBCTransactionFactory</literal></term>
+                    <listitem>
+                        <para>delegates to database (JDBC) transactions (default)</para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.JTATransactionFactory</literal></term>
+                    <listitem>
+                        <para>
+                            delegates to container-managed transaction if an existing transaction is
+                            underway in this context (e.g. EJB session bean method), otherwise
+                            a new transaction is started and bean-managed transaction are used.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.CMTTransactionFactory</literal></term>
+                    <listitem>
+                        <para>delegates to container-managed JTA transactions</para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+            <para>
+                You may also define your own transaction strategies (for a CORBA transaction service,
+                for example).
+            </para>
+
+            <para>
+                Some features in Hibernate (i.e. the second level cache, Contextual Sessions with JTA, etc.)
+                require access to the JTA <literal>TransactionManager</literal> in a managed environment.
+                In an application server you have to specify how Hibernate should obtain a reference to the
+                <literal>TransactionManager</literal>, since J2EE does not standardize a single mechanism:
+            </para>
+
+            <table frame="topbot" id="jtamanagerlookup" revision="1">
+                <title>JTA TransactionManagers</title>
+                <tgroup cols="2">
+                    <colspec colwidth="2.5*"/>
+                    <colspec colwidth="1*"/>
+                    <thead>
+                        <row>
+                            <entry>Transaction Factory</entry>
+                            <entry align="center">Application Server</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JBossTransactionManagerLookup</literal></entry>
+                            <entry align="center">JBoss</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WeblogicTransactionManagerLookup</literal></entry>
+                            <entry align="center">Weblogic</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WebSphereTransactionManagerLookup</literal></entry>
+                            <entry align="center">WebSphere</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</literal></entry>
+                            <entry align="center">WebSphere 6</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.OrionTransactionManagerLookup</literal></entry>
+                            <entry align="center">Orion</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.ResinTransactionManagerLookup</literal></entry>
+                            <entry align="center">Resin</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JOTMTransactionManagerLookup</literal></entry>
+                            <entry align="center">JOTM</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JOnASTransactionManagerLookup</literal></entry>
+                            <entry align="center">JOnAS</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JRun4TransactionManagerLookup</literal></entry>
+                            <entry align="center">JRun4</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.BESTransactionManagerLookup</literal></entry>
+                            <entry align="center">Borland ES</entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-jndi" revision="3">
+            <title>JNDI-bound <literal>SessionFactory</literal></title>
+
+            <para>
+                A JNDI bound Hibernate <literal>SessionFactory</literal> can simplify the lookup
+                of the factory and the creation of new <literal>Session</literal>s. Note that this
+                is not related to a JNDI bound <literal>Datasource</literal>, both simply use the
+                same registry!
+            </para>
+
+            <para>
+                If you wish to have the <literal>SessionFactory</literal> bound to a JNDI namespace, specify
+                a name (eg. <literal>java:hibernate/SessionFactory</literal>) using the property
+                <literal>hibernate.session_factory_name</literal>. If this property is omitted, the
+                <literal>SessionFactory</literal> will not be bound to JNDI. (This is especially useful in
+                environments with a read-only JNDI default implementation, e.g. Tomcat.)
+            </para>
+
+            <para>
+                When binding the <literal>SessionFactory</literal> to JNDI, Hibernate will use the values of
+                <literal>hibernate.jndi.url</literal>, <literal>hibernate.jndi.class</literal> to instantiate
+                an initial context. If they are not specified, the default <literal>InitialContext</literal>
+                will be used.
+            </para>
+
+            <para>
+                Hibernate will automatically place the <literal>SessionFactory</literal> in JNDI after
+                you call <literal>cfg.buildSessionFactory()</literal>. This means you will at least have
+                this call in some startup code (or utility class) in your application, unless you use
+                JMX deployment with the <literal>HibernateService</literal> (discussed later).
+            </para>
+
+            <para>
+                If you use a JNDI <literal>SessionFactory</literal>, an EJB or any other class may
+                obtain the  <literal>SessionFactory</literal> using a JNDI lookup.
+            </para>
+
+            <para>
+                We recommend that you bind the <literal>SessionFactory</literal> to JNDI in
+                a managend environment and use a <literal>static</literal> singleton otherwise.
+                To shield your application code from these details, we also recommend to hide the
+                actual lookup code for a <literal>SessionFactory</literal> in a helper class,
+                such as <literal>HibernateUtil.getSessionFactory()</literal>. Note that such a
+                class is also a convenient way to startup Hibernate&mdash;see chapter 1.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-j2ee-currentsession" revision="4">
+            <title>Current Session context management with JTA</title>
+
+            <para>
+                The easiest way to handle <literal>Session</literal>s and transactions is
+                Hibernates automatic "current" <literal>Session</literal> management.
+                See the discussion of <xref linkend="architecture-current-session">current sessions</xref>.
+                Using the <literal>"jta"</literal> session context, if there is no Hibernate
+                <literal>Session</literal> associated with the current JTA transaction, one will
+	            be started and associated with that JTA transaction the first time you call
+	            <literal>sessionFactory.getCurrentSession()</literal>. The <literal>Session</literal>s
+	            retrieved via <literal>getCurrentSession()</literal> in <literal>"jta"</literal> context
+	            will be set to automatically flush before the transaction completes, close
+	            after the transaction completes, and aggressively release JDBC connections
+	            after each statement.  This allows the <literal>Session</literal>s to
+	            be managed by the lifecycle of the JTA transaction to which it is associated,
+	            keeping user code clean of such management concerns. Your code can either use
+	            JTA programmatically through <literal>UserTransaction</literal>, or (recommended
+	            for portable code) use the Hibernate <literal>Transaction</literal> API to set
+	            transaction boundaries. If you run in an EJB container, declarative transaction
+	            demarcation with CMT is preferred.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-j2ee-jmx" revision="1">
+            <title>JMX deployment</title>
+
+            <para>
+                The line <literal>cfg.buildSessionFactory()</literal> still has to be executed
+                somewhere to get a <literal>SessionFactory</literal> into JNDI. You can do this
+                either in a <literal>static</literal> initializer block (like the one in
+                <literal>HibernateUtil</literal>) or you deploy Hibernate as a <emphasis>managed
+                service</emphasis>.
+            </para>
+
+            <para>
+                Hibernate is distributed with <literal>org.hibernate.jmx.HibernateService</literal>
+                for deployment on an application server with JMX capabilities, such as JBoss AS.
+                The actual deployment and configuration is vendor specific. Here is an example
+                <literal>jboss-service.xml</literal> for JBoss 4.0.x:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<server>
+
+<mbean code="org.hibernate.jmx.HibernateService"
+    name="jboss.jca:service=HibernateFactory,name=HibernateFactory">
+
+    <!-- Required services -->
+    <depends>jboss.jca:service=RARDeployer</depends>
+    <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends>
+
+    <!-- Bind the Hibernate service to JNDI -->
+    <attribute name="JndiName">java:/hibernate/SessionFactory</attribute>
+
+    <!-- Datasource settings -->
+    <attribute name="Datasource">java:HsqlDS</attribute>
+    <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>
+
+    <!-- Transaction integration -->
+    <attribute name="TransactionStrategy">
+        org.hibernate.transaction.JTATransactionFactory</attribute>
+    <attribute name="TransactionManagerLookupStrategy">
+        org.hibernate.transaction.JBossTransactionManagerLookup</attribute>
+    <attribute name="FlushBeforeCompletionEnabled">true</attribute>
+    <attribute name="AutoCloseSessionEnabled">true</attribute>
+
+    <!-- Fetching options -->
+    <attribute name="MaximumFetchDepth">5</attribute>
+
+    <!-- Second-level caching -->
+    <attribute name="SecondLevelCacheEnabled">true</attribute>
+    <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute>
+    <attribute name="QueryCacheEnabled">true</attribute>
+
+    <!-- Logging -->
+    <attribute name="ShowSqlEnabled">true</attribute>
+
+    <!-- Mapping files -->
+    <attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute>
+
+</mbean>
+
+</server>]]></programlisting>
+
+            <para>
+                This file is deployed in a directory called <literal>META-INF</literal> and packaged
+                in a JAR file with the extension <literal>.sar</literal> (service archive). You also need
+                to package Hibernate, its required third-party libraries, your compiled persistent classes,
+                as well as your mapping files in the same archive. Your enterprise beans (usually session
+                beans) may be kept in their own JAR file, but you may include this EJB JAR file in the
+                main service archive to get a single (hot-)deployable unit. Consult the JBoss AS
+                documentation for more information about JMX service and EJB deployment.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/events.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/events.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/events.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,265 @@
+<chapter id="events">
+    <title>Interceptors and events</title>
+
+    <para>
+        It is often useful for the application to react to certain events that occur
+        inside Hibernate. This allows implementation of certain kinds of generic 
+        functionality, and extension of Hibernate functionality.
+    </para>
+
+    <sect1 id="objectstate-interceptors" revision="3">
+        <title>Interceptors</title>
+
+        <para>
+            The <literal>Interceptor</literal> interface provides callbacks from the session to the 
+            application allowing the application to inspect and/or manipulate properties of a
+            persistent object before it is saved, updated, deleted or loaded. One 
+            possible use for this is to track auditing information. For example, the following 
+            <literal>Interceptor</literal> automatically sets the  <literal>createTimestamp</literal> 
+            when an <literal>Auditable</literal> is created and updates the 
+            <literal>lastUpdateTimestamp</literal> property when an <literal>Auditable</literal> is 
+            updated.
+        </para>
+
+        <para>
+            You may either implement <literal>Interceptor</literal> directly or (better) extend
+            <literal>EmptyInterceptor</literal>.
+        </para>
+
+        <programlisting><![CDATA[package org.hibernate.test;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.Transaction;
+import org.hibernate.type.Type;
+
+public class AuditInterceptor extends EmptyInterceptor {
+
+    private int updates;
+    private int creates;
+    private int loads;
+
+    public void onDelete(Object entity,
+                         Serializable id,
+                         Object[] state,
+                         String[] propertyNames,
+                         Type[] types) {
+        // do nothing
+    }
+
+    public boolean onFlushDirty(Object entity,
+                                Serializable id,
+                                Object[] currentState,
+                                Object[] previousState,
+                                String[] propertyNames,
+                                Type[] types) {
+
+        if ( entity instanceof Auditable ) {
+            updates++;
+            for ( int i=0; i < propertyNames.length; i++ ) {
+                if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
+                    currentState[i] = new Date();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean onLoad(Object entity,
+                          Serializable id,
+                          Object[] state,
+                          String[] propertyNames,
+                          Type[] types) {
+        if ( entity instanceof Auditable ) {
+            loads++;
+        }
+        return false;
+    }
+
+    public boolean onSave(Object entity,
+                          Serializable id,
+                          Object[] state,
+                          String[] propertyNames,
+                          Type[] types) {
+
+        if ( entity instanceof Auditable ) {
+            creates++;
+            for ( int i=0; i<propertyNames.length; i++ ) {
+                if ( "createTimestamp".equals( propertyNames[i] ) ) {
+                    state[i] = new Date();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void afterTransactionCompletion(Transaction tx) {
+        if ( tx.wasCommitted() ) {
+            System.out.println("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads);
+        }
+        updates=0;
+        creates=0;
+        loads=0;
+    }
+
+}]]></programlisting>
+
+        <para>
+            Interceptors come in two flavors: <literal>Session</literal>-scoped and
+            <literal>SessionFactory</literal>-scoped.
+        </para>
+
+        <para>
+            A <literal>Session</literal>-scoped interceptor is specified
+            when a session is opened using one of the overloaded SessionFactory.openSession()
+            methods accepting an <literal>Interceptor</literal>.
+        </para>
+
+        <programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
+
+        <para>
+            A <literal>SessionFactory</literal>-scoped interceptor is registered with the <literal>Configuration</literal>
+            object prior to building the <literal>SessionFactory</literal>.  In this case, the supplied interceptor
+            will be applied to all sessions opened from that <literal>SessionFactory</literal>; this is true unless
+            a session is opened explicitly specifying the interceptor to use.  <literal>SessionFactory</literal>-scoped
+            interceptors must be thread safe, taking care to not store session-specific state since multiple
+            sessions will use this interceptor (potentially) concurrently.
+        </para>
+    
+        <programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
+
+    </sect1>
+
+     <sect1 id="objectstate-events" revision="4">
+        <title>Event system</title>
+
+        <para>
+            If you have to react to particular events in your persistence layer, you may
+            also use the Hibernate3 <emphasis>event</emphasis> architecture. The event
+            system can be used in addition or as a replacement for interceptors.
+        </para>
+
+        <para>
+            Essentially all of the methods of the <literal>Session</literal> interface correlate
+            to an event. You have a <literal>LoadEvent</literal>, a <literal>FlushEvent</literal>, etc
+            (consult the XML configuration-file DTD or the <literal>org.hibernate.event</literal>
+            package for the full list of defined event types). When a request is made of one of
+            these methods, the Hibernate <literal>Session</literal> generates an appropriate
+            event and passes it to the configured event listeners for that type. Out-of-the-box,
+            these listeners implement the same processing in which those methods always resulted.
+            However, you are free to implement a customization of one of the listener interfaces
+            (i.e., the <literal>LoadEvent</literal> is processed by the registered implemenation
+            of the <literal>LoadEventListener</literal> interface), in which case their
+            implementation would be responsible for processing any <literal>load()</literal> requests
+            made of the <literal>Session</literal>.
+        </para>
+
+        <para>
+            The listeners should be considered effectively singletons; meaning, they are shared between
+            requests, and thus should not save any state as instance variables.
+        </para>
+
+        <para>
+            A custom listener should implement the appropriate interface for the event it wants to
+            process and/or extend one of the convenience base classes (or even the default event
+            listeners used by Hibernate out-of-the-box as these are declared non-final for this
+            purpose). Custom listeners can either be registered programmatically through the
+            <literal>Configuration</literal> object, or specified in the Hibernate configuration
+            XML (declarative configuration through the properties file is not supported). Here's an
+            example of a custom load event listener:
+        </para>
+
+        <programlisting><![CDATA[public class MyLoadListener implements LoadEventListener {
+    // this is the single method defined by the LoadEventListener interface
+    public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
+            throws HibernateException {
+        if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
+            throw MySecurityException("Unauthorized access");
+        }
+    }
+}]]></programlisting>
+
+        <para>
+            You also need a configuration entry telling Hibernate to use the listener in addition
+            to the default listener:
+        </para>
+
+<programlisting><![CDATA[<hibernate-configuration>
+    <session-factory>
+        ...
+        <event type="load">
+            <listener class="com.eg.MyLoadListener"/>
+            <listener class="org.hibernate.event.def.DefaultLoadEventListener"/>
+        </event>
+    </session-factory>
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+            Instead, you may register it programmatically:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration();
+LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() };
+cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
+
+        <para>
+            Listeners registered declaratively cannot share instances. If the same class name is
+            used in multiple <literal>&lt;listener/&gt;</literal> elements, each reference will
+            result in a separate instance of that class. If you need the capability to share
+            listener instances between listener types you must use the programmatic registration
+            approach.
+        </para>
+
+        <para>
+            Why implement an interface and define the specific type during configuration? Well, a
+            listener implementation could implement multiple event listener interfaces. Having the
+            type additionally defined during registration makes it easier to turn custom listeners on
+            or off during configuration.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="objectstate-decl-security" revision="2">
+        <title>Hibernate declarative security</title>
+        <para>
+            Usually, declarative security in Hibernate applications is managed in a session facade
+            layer. Now, Hibernate3 allows certain actions to be permissioned via JACC, and authorized 
+            via JAAS. This is optional functionality built on top of the event architecture.
+        </para>
+        
+        <para>
+            First, you must configure the appropriate event listeners, to enable the use of JAAS
+            authorization.
+        </para>
+        
+        <programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
+<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
+<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
+<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
+
+        <para>
+            Note that <literal>&lt;listener type="..." class="..."/&gt;</literal> is just a shorthand
+            for <literal>&lt;event type="..."&gt;&lt;listener class="..."/&gt;&lt;/event&gt;</literal>
+            when there is exactly one listener for a particular event type.
+        </para>
+
+        <para>
+            Next, still in <literal>hibernate.cfg.xml</literal>, bind the permissions to roles:
+        </para>
+        
+        <programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
+<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
+        
+        <para>
+            The role names are the roles understood by your JACC provider.
+        </para>
+       
+    </sect1>
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/events.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/example_mappings.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/example_mappings.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/example_mappings.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,658 @@
+<chapter id="example-mappings">
+    <title>Example: Various Mappings</title>
+    
+    <para>
+        This chapters shows off some more complex association mappings.
+    </para>
+    
+    <sect1 id="example-mappings-emp">
+        <title>Employer/Employee</title>
+
+        <para>
+            The following model of the relationship between <literal>Employer</literal> and 
+            <literal>Employee</literal> uses an actual entity class (<literal>Employment</literal>) 
+            to represent the association. This is done because there might be more than one
+            period of employment for the same two parties. Components are used to model monetary 
+            values and employee names.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/EmployerEmployee.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/EmployerEmployee.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            Heres a possible mapping document:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+        
+    <class name="Employer" table="employers">
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employer_id_seq</param>
+            </generator>
+        </id>
+        <property name="name"/>
+    </class>
+
+    <class name="Employment" table="employment_periods">
+
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employment_id_seq</param>
+            </generator>
+        </id>
+        <property name="startDate" column="start_date"/>
+        <property name="endDate" column="end_date"/>
+
+        <component name="hourlyRate" class="MonetaryAmount">
+            <property name="amount">
+                <column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>
+            </property>
+            <property name="currency" length="12"/>
+        </component>
+
+        <many-to-one name="employer" column="employer_id" not-null="true"/>
+        <many-to-one name="employee" column="employee_id" not-null="true"/>
+
+    </class>
+
+    <class name="Employee" table="employees">
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employee_id_seq</param>
+            </generator>
+        </id>
+        <property name="taxfileNumber"/>
+        <component name="name" class="Name">
+            <property name="firstName"/>
+            <property name="initial"/>
+            <property name="lastName"/>
+        </component>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        And heres the table schema generated by <literal>SchemaExport</literal>.
+    </para>
+
+    <programlisting><![CDATA[create table employers (
+    id BIGINT not null, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+create table employment_periods (
+    id BIGINT not null,
+    hourly_rate NUMERIC(12, 2),
+    currency VARCHAR(12), 
+    employee_id BIGINT not null, 
+    employer_id BIGINT not null, 
+    end_date TIMESTAMP, 
+    start_date TIMESTAMP, 
+    primary key (id)
+)
+
+create table employees (
+    id BIGINT not null, 
+    firstName VARCHAR(255), 
+    initial CHAR(1), 
+    lastName VARCHAR(255), 
+    taxfileNumber VARCHAR(255), 
+    primary key (id)
+)
+
+alter table employment_periods 
+    add constraint employment_periodsFK0 foreign key (employer_id) references employers
+alter table employment_periods 
+    add constraint employment_periodsFK1 foreign key (employee_id) references employees
+create sequence employee_id_seq
+create sequence employment_id_seq
+create sequence employer_id_seq]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="example-mappings-authorwork">
+        <title>Author/Work</title>
+
+        <para>
+            Consider the following model of the relationships between <literal>Work</literal>,
+            <literal>Author</literal> and <literal>Person</literal>. We represent the relationship
+            between <literal>Work</literal> and <literal>Author</literal> as a many-to-many
+            association. We choose to represent the relationship between <literal>Author</literal> 
+            and <literal>Person</literal> as one-to-one association. Another possibility would be to 
+            have <literal>Author</literal> extend <literal>Person</literal>.  
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/AuthorWork.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/AuthorWork.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            The following mapping document correctly represents these relationships:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Work" table="works" discriminator-value="W">
+
+        <id name="id" column="id">
+            <generator class="native"/>
+        </id>
+        <discriminator column="type" type="character"/>
+
+        <property name="title"/>
+        <set name="authors" table="author_work">
+            <key column name="work_id"/>
+            <many-to-many class="Author" column name="author_id"/>
+        </set>
+
+        <subclass name="Book" discriminator-value="B">
+            <property name="text"/>
+        </subclass>
+
+        <subclass name="Song" discriminator-value="S">
+            <property name="tempo"/>
+            <property name="genre"/>
+        </subclass>
+
+    </class>
+
+    <class name="Author" table="authors">
+
+        <id name="id" column="id">
+            <!-- The Author must have the same identifier as the Person -->
+            <generator class="assigned"/> 
+        </id>
+
+        <property name="alias"/>
+        <one-to-one name="person" constrained="true"/>
+
+        <set name="works" table="author_work" inverse="true">
+            <key column="author_id"/>
+            <many-to-many class="Work" column="work_id"/>
+        </set>
+
+    </class>
+
+    <class name="Person" table="persons">
+        <id name="id" column="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        There are four tables in this mapping. <literal>works</literal>, 
+        <literal>authors</literal> and <literal>persons</literal> hold work, author
+        and person data respectively. <literal>author_work</literal> is an association
+        table linking authors to works. Heres the table schema, as generated by
+        <literal>SchemaExport</literal>.
+    </para>
+
+    <programlisting><![CDATA[create table works (
+    id BIGINT not null generated by default as identity, 
+    tempo FLOAT, 
+    genre VARCHAR(255), 
+    text INTEGER, 
+    title VARCHAR(255), 
+    type CHAR(1) not null, 
+    primary key (id)
+)
+
+create table author_work (
+    author_id BIGINT not null, 
+    work_id BIGINT not null, 
+    primary key (work_id, author_id)
+)
+
+create table authors (
+    id BIGINT not null generated by default as identity, 
+    alias VARCHAR(255), 
+    primary key (id)
+)
+
+create table persons (
+    id BIGINT not null generated by default as identity, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+alter table authors 
+    add constraint authorsFK0 foreign key (id) references persons
+alter table author_work 
+    add constraint author_workFK0 foreign key (author_id) references authors
+alter table author_work
+    add constraint author_workFK1 foreign key (work_id) references works]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-mappings-customerorderproduct">
+        <title>Customer/Order/Product</title>
+
+        <para>
+            Now consider a model of the relationships between <literal>Customer</literal>,
+            <literal>Order</literal> and <literal>LineItem</literal> and <literal>Product</literal>.
+            There is a one-to-many association between <literal>Customer</literal> and
+            <literal>Order</literal>, but how should we represent <literal>Order</literal> / 
+            <literal>LineItem</literal> / <literal>Product</literal>? I've chosen to map
+            <literal>LineItem</literal> as an association class representing the many-to-many
+            association between <literal>Order</literal> and <literal>Product</literal>. In
+            Hibernate, this is called a composite element.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            The mapping document:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Customer" table="customers">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+        <set name="orders" inverse="true">
+            <key column="customer_id"/>
+            <one-to-many class="Order"/>
+        </set>
+    </class>
+
+    <class name="Order" table="orders">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="date"/>
+        <many-to-one name="customer" column="customer_id"/>
+        <list name="lineItems" table="line_items">
+            <key column="order_id"/>
+            <list-index column="line_number"/>
+            <composite-element class="LineItem">
+                <property name="quantity"/>
+                <many-to-one name="product" column="product_id"/>
+            </composite-element>
+        </list>
+    </class>
+
+    <class name="Product" table="products">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="serialNumber"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        <literal>customers</literal>, <literal>orders</literal>, <literal>line_items</literal> and 
+        <literal>products</literal> hold customer, order, order line item and product data
+        respectively. <literal>line_items</literal> also acts as an association table linking
+        orders with products.
+    </para>
+
+    <programlisting><![CDATA[create table customers (
+    id BIGINT not null generated by default as identity, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+create table orders (
+    id BIGINT not null generated by default as identity, 
+    customer_id BIGINT, 
+    date TIMESTAMP, 
+    primary key (id)
+)
+
+create table line_items (
+    line_number INTEGER not null, 
+    order_id BIGINT not null, 
+    product_id BIGINT, 
+    quantity INTEGER, 
+    primary key (order_id, line_number)
+)
+
+create table products (
+    id BIGINT not null generated by default as identity, 
+    serialNumber VARCHAR(255), 
+    primary key (id)
+)
+
+alter table orders 
+    add constraint ordersFK0 foreign key (customer_id) references customers
+alter table line_items
+    add constraint line_itemsFK0 foreign key (product_id) references products
+alter table line_items
+    add constraint line_itemsFK1 foreign key (order_id) references orders]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="misc">
+        <title>Miscellaneous example mappings</title>
+        
+        <para>
+            These examples are all taken from the Hibernate test suite. You
+            will find many other useful example mappings there. Look in the
+            <literal>test</literal> folder of the Hibernate distribution.
+        </para>
+        
+        <para>TODO: put words around this stuff</para>
+        
+        <sect2 id="example-mappings-typed-onetone">
+            <title>"Typed" one-to-one association</title>
+<programlisting><![CDATA[<class name="Person">
+    <id name="name"/>
+    <one-to-one name="address" 
+            cascade="all">
+        <formula>name</formula>
+        <formula>'HOME'</formula>
+    </one-to-one>
+    <one-to-one name="mailingAddress" 
+            cascade="all">
+        <formula>name</formula>
+        <formula>'MAILING'</formula>
+    </one-to-one>
+</class>
+
+<class name="Address" batch-size="2" 
+        check="addressType in ('MAILING', 'HOME', 'BUSINESS')">
+    <composite-id>
+        <key-many-to-one name="person" 
+                column="personName"/>
+        <key-property name="type" 
+                column="addressType"/>
+    </composite-id>
+    <property name="street" type="text"/>
+    <property name="state"/>
+    <property name="zip"/>
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="example-mappings-composite-key">
+            <title>Composite key example</title>
+<programlisting><![CDATA[<class name="Customer">
+
+    <id name="customerId"
+        length="10">
+        <generator class="assigned"/>
+    </id>
+
+    <property name="name" not-null="true" length="100"/>
+    <property name="address" not-null="true" length="200"/>
+
+    <list name="orders"
+            inverse="true"
+            cascade="save-update">
+        <key column="customerId"/>
+        <index column="orderNumber"/>
+        <one-to-many class="Order"/>
+    </list>
+
+</class>
+
+<class name="Order" table="CustomerOrder" lazy="true">
+    <synchronize table="LineItem"/>
+    <synchronize table="Product"/>
+    
+    <composite-id name="id" 
+            class="Order$Id">
+        <key-property name="customerId" length="10"/>
+        <key-property name="orderNumber"/>
+    </composite-id>
+    
+    <property name="orderDate" 
+            type="calendar_date"
+            not-null="true"/>
+    
+    <property name="total">
+        <formula>
+            ( select sum(li.quantity*p.price) 
+            from LineItem li, Product p 
+            where li.productId = p.productId 
+                and li.customerId = customerId 
+                and li.orderNumber = orderNumber )
+        </formula>
+    </property>
+    
+    <many-to-one name="customer"
+            column="customerId"
+            insert="false"
+            update="false" 
+            not-null="true"/>
+        
+    <bag name="lineItems"
+            fetch="join" 
+            inverse="true"
+            cascade="save-update">
+        <key>
+            <column name="customerId"/>
+            <column name="orderNumber"/>
+        </key>
+        <one-to-many class="LineItem"/>
+    </bag>
+    
+</class>
+    
+<class name="LineItem">
+    
+    <composite-id name="id" 
+            class="LineItem$Id">
+        <key-property name="customerId" length="10"/>
+        <key-property name="orderNumber"/>
+        <key-property name="productId" length="10"/>
+    </composite-id>
+    
+    <property name="quantity"/>
+    
+    <many-to-one name="order"
+            insert="false"
+            update="false" 
+            not-null="true">
+        <column name="customerId"/>
+        <column name="orderNumber"/>
+    </many-to-one>
+    
+    <many-to-one name="product"
+            insert="false"
+            update="false" 
+            not-null="true"
+            column="productId"/>
+        
+</class>
+
+<class name="Product">
+    <synchronize table="LineItem"/>
+
+    <id name="productId"
+        length="10">
+        <generator class="assigned"/>
+    </id>
+    
+    <property name="description" 
+        not-null="true" 
+        length="200"/>
+    <property name="price" length="3"/>
+    <property name="numberAvailable"/>
+    
+    <property name="numberOrdered">
+        <formula>
+            ( select sum(li.quantity) 
+            from LineItem li 
+            where li.productId = productId )
+        </formula>
+    </property>
+    
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="example-mappings-composite-key-manytomany">
+            <title>Many-to-many with shared composite key attribute</title>
+<programlisting><![CDATA[<class name="User" table="`User`">
+    <composite-id>
+        <key-property name="name"/>
+        <key-property name="org"/>
+    </composite-id>
+    <set name="groups" table="UserGroup">
+        <key>
+            <column name="userName"/>
+            <column name="org"/>
+        </key>
+        <many-to-many class="Group">
+            <column name="groupName"/>
+            <formula>org</formula>
+        </many-to-many>
+    </set>
+</class>
+    
+<class name="Group" table="`Group`">
+    <composite-id>
+        <key-property name="name"/>
+        <key-property name="org"/>
+    </composite-id>
+    <property name="description"/>
+    <set name="users" table="UserGroup" inverse="true">
+        <key>
+            <column name="groupName"/>
+            <column name="org"/>
+        </key>
+        <many-to-many class="User">
+            <column name="userName"/>
+            <formula>org</formula>
+        </many-to-many>
+    </set>
+</class>
+]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-content-discrimination">
+            <title>Content based discrimination</title>
+<programlisting><![CDATA[<class name="Person"
+    discriminator-value="P">
+    
+    <id name="id" 
+        column="person_id" 
+        unsaved-value="0">
+        <generator class="native"/>
+    </id>
+    
+            
+    <discriminator 
+        type="character">
+        <formula>
+            case 
+                when title is not null then 'E' 
+                when salesperson is not null then 'C' 
+                else 'P' 
+            end
+        </formula>
+    </discriminator>
+
+    <property name="name" 
+        not-null="true"
+        length="80"/>
+        
+    <property name="sex" 
+        not-null="true"
+        update="false"/>
+    
+    <component name="address">
+        <property name="address"/>
+        <property name="zip"/>
+        <property name="country"/>
+    </component>
+    
+    <subclass name="Employee" 
+        discriminator-value="E">
+            <property name="title"
+                length="20"/>
+            <property name="salary"/>
+            <many-to-one name="manager"/>
+    </subclass>
+    
+    <subclass name="Customer" 
+        discriminator-value="C">
+            <property name="comments"/>
+            <many-to-one name="salesperson"/>
+    </subclass>
+    
+</class>]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-association-alternatekeys" revision="2">
+            <title>Associations on alternate keys</title>
+<programlisting><![CDATA[<class name="Person">
+    
+    <id name="id">
+        <generator class="hilo"/>
+    </id>
+    
+    <property name="name" length="100"/>
+    
+    <one-to-one name="address" 
+        property-ref="person"
+        cascade="all"
+        fetch="join"/>
+    
+    <set name="accounts" 
+        inverse="true">
+        <key column="userId"
+            property-ref="userId"/>
+        <one-to-many class="Account"/>
+    </set>
+    
+    <property name="userId" length="8"/>
+
+</class>
+
+<class name="Address">
+
+    <id name="id">
+        <generator class="hilo"/>
+    </id>
+
+    <property name="address" length="300"/>
+    <property name="zip" length="5"/>
+    <property name="country" length="25"/>
+    <many-to-one name="person" unique="true" not-null="true"/>
+
+</class>
+
+<class name="Account">
+    <id name="accountId" length="32">
+        <generator class="uuid"/>
+    </id>
+    
+    <many-to-one name="user"
+        column="userId"
+        property-ref="userId"/>
+    
+    <property name="type" not-null="true"/>
+    
+</class>]]></programlisting>
+        </sect2>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/example_parentchild.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/example_parentchild.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/example_parentchild.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,361 @@
+<chapter id="example-parentchild">
+    <title>Example: Parent/Child</title>
+
+    <para>
+        One of the very first things that new users try to do with Hibernate is to model a parent / child type 
+        relationship. There are two different approaches to this. For various reasons the most convenient 
+        approach, especially for new users, is to model both <literal>Parent</literal> and <literal>Child</literal> 
+        as entity classes with a <literal>&lt;one-to-many&gt;</literal> association from <literal>Parent</literal> 
+        to <literal>Child</literal>. (The alternative approach is to declare the <literal>Child</literal> as a 
+        <literal>&lt;composite-element&gt;</literal>.) Now, it turns out that default semantics of a one to many 
+        association (in Hibernate) are much less close to the usual semantics of a parent / child relationship than 
+        those of a composite element mapping. We will explain how to use a <emphasis>bidirectional one to many 
+        association with cascades</emphasis> to model a parent / child relationship efficiently and elegantly. 
+        It's not at all difficult!
+    </para>
+    
+    <sect1 id="example-parentchild-collections">
+        <title>A note about collections</title>
+
+        <para>
+            Hibernate collections are considered to be a logical part of their owning entity; never of the
+            contained entities. This is a crucial distinction! It has the following consequences:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+            <para>
+                When we remove / add an object from / to a collection, the version number of the collection owner
+                is incremented.
+            </para>
+            </listitem>
+            <listitem>
+            <para>
+                If an object that was removed from a collection is an instance of a value type (eg, a composite
+                element), that object will cease to be persistent and its state will be completely removed from
+                the database. Likewise, adding a value type instance to the collection will cause its state to be
+                immediately persistent.
+            </para>
+            </listitem>
+            <listitem>
+            <para>
+                On the other hand, if an entity is removed from a collection (a one-to-many or many-to-many
+                association), it will not be deleted, by default. This behaviour is completely consistent - a
+                change to the internal state of another entity should not cause the associated entity to vanish!
+                Likewise, adding an entity to a collection does not cause that entity to become persistent, by
+                default.
+            </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Instead, the default behaviour is that adding an entity to a collection merely creates a link between
+            the two entities, while removing it removes the link. This is very appropriate for all sorts of cases.
+            Where it is not appropriate at all is the case of a parent / child relationship, where the life of the
+            child is bound to the lifecycle of the parent.
+        </para>
+    
+    </sect1>
+
+    <sect1 id="example-parentchild-bidir">
+        <title>Bidirectional one-to-many</title>
+
+        <para>
+            Suppose we start with a simple <literal>&lt;one-to-many&gt;</literal> association from
+            <literal>Parent</literal> to <literal>Child</literal>.
+        </para>
+
+        <programlisting><![CDATA[<set name="children">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+    
+        <para>
+            If we were to execute the following code
+        </para>
+
+        <programlisting><![CDATA[Parent p = .....;
+Child c = new Child();
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+    
+        <para>
+            Hibernate would issue two SQL statements:
+        </para>
+
+        <itemizedlist>
+        <listitem>
+            <para>an <literal>INSERT</literal> to create the record for <literal>c</literal></para>
+        </listitem>
+        <listitem>
+            <para>
+                an <literal>UPDATE</literal> to create the link from <literal>p</literal> to
+                <literal>c</literal>
+            </para>
+        </listitem>
+        </itemizedlist>
+    
+        <para>
+            This is not only inefficient, but also violates any <literal>NOT NULL</literal> constraint on the
+            <literal>parent_id</literal> column. We can fix the nullability constraint violation by specifying
+            <literal>not-null="true"</literal> in the collection mapping:
+        </para>
+
+        <programlisting><![CDATA[<set name="children">
+    <key column="parent_id" not-null="true"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+    
+        <para>
+        	However, this is not the recommended solution.
+       	</para>
+       	<para>
+            The underlying cause of this behaviour is that the link (the foreign key <literal>parent_id</literal>) 
+            from <literal>p</literal> to <literal>c</literal> is not considered part of the state of the 
+            <literal>Child</literal> object and is therefore not created in the <literal>INSERT</literal>. So the 
+            solution is to make the link part of the <literal>Child</literal> mapping.
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
+
+        <para>
+            (We also need to add the <literal>parent</literal> property to the <literal>Child</literal> class.)
+        </para>
+
+        <para>
+            Now that the <literal>Child</literal> entity is managing the state of the link, we tell the collection 
+            not to update the link. We use the <literal>inverse</literal> attribute.
+        </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+        <para>
+            The following code would be used to add a new <literal>Child</literal>
+        </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+        <para>
+            And now, only one SQL <literal>INSERT</literal> would be issued!
+        </para>
+
+        <para>
+            To tighten things up a bit, we could create an <literal>addChild()</literal> method of
+            <literal>Parent</literal>.
+        </para>
+
+        <programlisting><![CDATA[public void addChild(Child c) {
+    c.setParent(this);
+    children.add(c);
+}]]></programlisting>
+
+        <para>
+            Now, the code to add a <literal>Child</literal> looks like
+        </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+     </sect1>
+     
+     <sect1 id="example-parentchild-cascades">
+         <title>Cascading lifecycle</title>
+     
+         <para>
+             The explicit call to <literal>save()</literal> is still annoying. We will address this by
+             using cascades.
+         </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true" cascade="all">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+     
+         <para>
+             This simplifies the code above to
+         </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.flush();]]></programlisting>
+     
+         <para>
+             Similarly, we don't need to iterate over the children when saving or deleting a <literal>Parent</literal>.
+             The following removes <literal>p</literal> and all its children from the database.
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+session.delete(p);
+session.flush();]]></programlisting>
+     
+         <para>
+             However, this code
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+c.setParent(null);
+session.flush();]]></programlisting>
+     
+         <para>
+             will not remove <literal>c</literal> from the database; it will ony remove the link to <literal>p</literal>
+             (and cause a <literal>NOT NULL</literal> constraint violation, in this case). You need to explicitly
+             <literal>delete()</literal> the <literal>Child</literal>.
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+session.delete(c);
+session.flush();]]></programlisting>
+
+         <para>
+             Now, in our case, a <literal>Child</literal> can't really exist without its parent. So if we remove
+             a <literal>Child</literal> from the collection, we really do want it to be deleted. For this, we must
+             use <literal>cascade="all-delete-orphan"</literal>.
+         </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true" cascade="all-delete-orphan">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+         <para>
+             Note: even though the collection mapping specifies <literal>inverse="true"</literal>, cascades are 
+             still processed by iterating the collection elements. So if you require that an object be saved, 
+             deleted or updated by cascade, you must add it to the collection. It is not enough to simply call
+             <literal>setParent()</literal>.
+         </para>
+               
+     </sect1>
+     
+     <sect1 id="example-parentchild-update">
+         <title>Cascades and <literal>unsaved-value</literal></title>
+     
+         <para>
+             Suppose we loaded up a <literal>Parent</literal> in one <literal>Session</literal>, made some changes 
+             in a UI action and wish to persist these changes in a new session by calling <literal>update()</literal>. 
+             The <literal>Parent</literal> will contain a collection of childen and, since cascading update is enabled, 
+             Hibernate needs to know which children are newly instantiated and which represent existing rows in the 
+             database. Lets assume that both <literal>Parent</literal> and <literal>Child</literal> have genenerated
+             identifier properties of type <literal>Long</literal>. Hibernate will use the identifier and 
+             version/timestamp property value to determine which of the children are new. (See
+             <xref linkend="objectstate-saveorupdate"/>.) <emphasis>In Hibernate3, it is no longer necessary to specify
+             an <literal>unsaved-value</literal> explicitly.</emphasis>
+         </para>
+
+         <para>
+             The following code will update <literal>parent</literal> and <literal>child</literal> and insert 
+             <literal>newChild</literal>.
+         </para>
+
+         <programlisting><![CDATA[//parent and child were both loaded in a previous session
+parent.addChild(child);
+Child newChild = new Child();
+parent.addChild(newChild);
+session.update(parent);
+session.flush();]]></programlisting>
+     
+         <para>
+             Well, that's all very well for the case of a generated identifier, but what about assigned identifiers
+             and composite identifiers? This is more difficult, since Hibernate can't use the identifier property to
+             distinguish between a newly instantiated object (with an identifier assigned by the user) and an 
+             object loaded in a previous session. In this case, Hibernate will either use the timestamp or version 
+             property, or will actually query the second-level cache or, worst case, the database, to see if the 
+             row exists.
+         </para>
+         
+         <!-- undocumenting
+         <para>
+             There is one further possibility. The <literal>Interceptor</literal> method named 
+             <literal>isUnsaved()</literal> lets the application implement its own strategy for distinguishing
+             newly instantiated objects. For example, you could define a base class for your persistent classes.
+         </para>
+
+         <programlisting><![CDATA[public class Persistent {
+    private boolean _saved = false;
+    public void onSave() {
+        _saved=true;
+    }
+    public void onLoad() {
+        _saved=true;
+    }
+    ......
+    public boolean isSaved() {
+        return _saved;
+    }
+}]]></programlisting>
+     
+         <para>
+             (The <literal>saved</literal> property is non-persistent.)
+             Now implement <literal>isUnsaved()</literal>, along with <literal>onLoad()</literal>
+             and <literal>onSave()</literal> as follows.
+         </para>
+
+         <programlisting><![CDATA[public Boolean isUnsaved(Object entity) {
+    if (entity instanceof Persistent) {
+        return new Boolean( !( (Persistent) entity ).isSaved() );
+    }
+    else {
+        return null;
+    }
+}
+
+public boolean onLoad(Object entity, 
+    Serializable id,
+    Object[] state,
+    String[] propertyNames,
+    Type[] types) {
+
+    if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
+    return false;
+}
+
+public boolean onSave(Object entity,
+    Serializable id,
+    Object[] state,
+    String[] propertyNames,
+    Type[] types) {
+        
+    if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
+    return false;
+}]]></programlisting>
+
+		<para>
+			Don't worry; in Hibernate3 you don't need to write any of this kind of code if you don't want to.
+		</para>
+     -->
+     </sect1>
+
+     <sect1 id="example-parentchild-conclusion">
+         <title>Conclusion</title>
+
+         <para>
+             There is quite a bit to digest here and it might look confusing first time around. However, in practice, 
+             it all works out very nicely. Most Hibernate applications use the parent / child pattern in many places.
+         </para>
+
+         <para>
+             We mentioned an alternative in the first paragraph. None of the above issues exist in the case of
+             <literal>&lt;composite-element&gt;</literal> mappings, which have exactly the semantics of a parent / child
+             relationship. Unfortunately, there are two big limitations to composite element classes: composite elements 
+             may not own collections, and they should not be the child of any entity other than the unique parent.
+         </para>
+     
+     </sect1>
+     
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/example_weblog.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/example_weblog.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/example_weblog.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,430 @@
+<chapter id="example-weblog">
+    <title>Example: Weblog Application</title>
+
+    <sect1 id="example-weblog-classes">
+        <title>Persistent Classes</title>
+
+        <para>
+            The persistent classes represent a weblog, and an item posted
+            in a weblog. They are to be modelled as a standard parent/child
+            relationship, but we will use an ordered bag, instead of a set.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+import java.util.List;
+
+public class Blog {
+    private Long _id;
+    private String _name;
+    private List _items;
+
+    public Long getId() {
+        return _id;
+    }
+    public List getItems() {
+        return _items;
+    }
+    public String getName() {
+        return _name;
+    }
+    public void setId(Long long1) {
+        _id = long1;
+    }
+    public void setItems(List list) {
+        _items = list;
+    }
+    public void setName(String string) {
+        _name = string;
+    }
+}]]></programlisting>
+
+        <programlisting><![CDATA[package eg;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+
+public class BlogItem {
+    private Long _id;
+    private Calendar _datetime;
+    private String _text;
+    private String _title;
+    private Blog _blog;
+
+    public Blog getBlog() {
+        return _blog;
+    }
+    public Calendar getDatetime() {
+        return _datetime;
+    }
+    public Long getId() {
+        return _id;
+    }
+    public String getText() {
+        return _text;
+    }
+    public String getTitle() {
+        return _title;
+    }
+    public void setBlog(Blog blog) {
+        _blog = blog;
+    }
+    public void setDatetime(Calendar calendar) {
+        _datetime = calendar;
+    }
+    public void setId(Long long1) {
+        _id = long1;
+    }
+    public void setText(String string) {
+        _text = string;
+    }
+    public void setTitle(String string) {
+        _title = string;
+    }
+}]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-weblog-mappings">
+        <title>Hibernate Mappings</title>
+
+        <para>
+            The XML mappings should now be quite straightforward.
+        </para>
+        
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+    <class
+        name="Blog"
+        table="BLOGS">
+
+        <id
+            name="id"
+            column="BLOG_ID">
+
+            <generator class="native"/>
+
+        </id>
+
+        <property
+            name="name"
+            column="NAME"
+            not-null="true"
+            unique="true"/>
+
+        <bag
+            name="items"
+            inverse="true"
+            order-by="DATE_TIME"
+            cascade="all">
+
+            <key column="BLOG_ID"/>
+            <one-to-many class="BlogItem"/>
+
+        </bag>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+    <class
+        name="BlogItem"
+        table="BLOG_ITEMS"
+        dynamic-update="true">
+
+        <id
+            name="id"
+            column="BLOG_ITEM_ID">
+
+            <generator class="native"/>
+
+        </id>
+
+        <property
+            name="title"
+            column="TITLE"
+            not-null="true"/>
+
+        <property
+            name="text"
+            column="TEXT"
+            not-null="true"/>
+
+        <property
+            name="datetime"
+            column="DATE_TIME"
+            not-null="true"/>
+
+        <many-to-one
+            name="blog"
+            column="BLOG_ID"
+            not-null="true"/>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="example-weblog-code">
+        <title>Hibernate Code</title>
+
+        <para>
+            The following class demonstrates some of the kinds of things
+            we can do with these classes, using Hibernate.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+
+public class BlogMain {
+    
+    private SessionFactory _sessions;
+    
+    public void configure() throws HibernateException {
+        _sessions = new Configuration()
+            .addClass(Blog.class)
+            .addClass(BlogItem.class)
+            .buildSessionFactory();
+    }
+    
+    public void exportTables() throws HibernateException {
+        Configuration cfg = new Configuration()
+            .addClass(Blog.class)
+            .addClass(BlogItem.class);
+        new SchemaExport(cfg).create(true, true);
+    }
+    
+    public Blog createBlog(String name) throws HibernateException {
+        
+        Blog blog = new Blog();
+        blog.setName(name);
+        blog.setItems( new ArrayList() );
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.persist(blog);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return blog;
+    }
+    
+    public BlogItem createBlogItem(Blog blog, String title, String text)
+                        throws HibernateException {
+        
+        BlogItem item = new BlogItem();
+        item.setTitle(title);
+        item.setText(text);
+        item.setBlog(blog);
+        item.setDatetime( Calendar.getInstance() );
+        blog.getItems().add(item);
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.update(blog);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return item;
+    }
+    
+    public BlogItem createBlogItem(Long blogid, String title, String text)
+                        throws HibernateException {
+        
+        BlogItem item = new BlogItem();
+        item.setTitle(title);
+        item.setText(text);
+        item.setDatetime( Calendar.getInstance() );
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            Blog blog = (Blog) session.load(Blog.class, blogid);
+            item.setBlog(blog);
+            blog.getItems().add(item);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return item;
+    }
+    
+    public void updateBlogItem(BlogItem item, String text)
+                    throws HibernateException {
+        
+        item.setText(text);
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.update(item);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+    }
+    
+    public void updateBlogItem(Long itemid, String text)
+                    throws HibernateException {
+    
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            BlogItem item = (BlogItem) session.load(BlogItem.class, itemid);
+            item.setText(text);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+    }
+    
+    public List listAllBlogNamesAndItemCounts(int max)
+                    throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        List result = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "select blog.id, blog.name, count(blogItem) " +
+                "from Blog as blog " +
+                "left outer join blog.items as blogItem " +
+                "group by blog.name, blog.id " +
+                "order by max(blogItem.datetime)"
+            );
+            q.setMaxResults(max);
+            result = q.list();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return result;
+    }
+    
+    public Blog getBlogAndAllItems(Long blogid)
+                    throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        Blog blog = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "from Blog as blog " +
+                "left outer join fetch blog.items " +
+                "where blog.id = :blogid"
+            );
+            q.setParameter("blogid", blogid);
+            blog  = (Blog) q.uniqueResult();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return blog;
+    }
+    
+    public List listBlogsAndRecentItems() throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        List result = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "from Blog as blog " +
+                "inner join blog.items as blogItem " +
+                "where blogItem.datetime > :minDate"
+            );
+
+            Calendar cal = Calendar.getInstance();
+            cal.roll(Calendar.MONTH, false);
+            q.setCalendar("minDate", cal);
+            
+            result = q.list();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return result;
+    }
+}]]></programlisting>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/filters.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/filters.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/filters.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,146 @@
+<chapter id="filters">
+    <title>Filtering data</title>
+    
+    <para>
+        Hibernate3 provides an innovative new approach to handling data with "visibility" rules.
+        A <emphasis>Hibernate filter</emphasis> is a global, named, parameterized filter that may be 
+        enabled or disabled for a particular Hibernate session.
+    </para>
+
+    <sect1 id="objectstate-filters" revision="1">
+        <title>Hibernate filters</title>
+
+        <para>
+            Hibernate3 adds the ability to pre-define filter criteria and attach those filters at both
+            a class and a collection level. A filter criteria is the ability to define a restriction clause
+            very similiar to the existing "where" attribute available on the class and various collection
+            elements. Except these filter conditions can be parameterized. The application can then make
+            the decision at runtime whether given filters should be enabled and what their parameter
+            values should be. Filters can be used like database views, but parameterized inside the
+            application.
+        </para>
+
+        <para>
+            In order to use filters, they must first be defined and then attached to the appropriate
+            mapping elements. To define a filter, use the <literal>&lt;filter-def/&gt;</literal> element
+            within a <literal>&lt;hibernate-mapping/&gt;</literal> element:
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="myFilter">
+    <filter-param name="myFilterParam" type="string"/>
+</filter-def>]]></programlisting>
+
+        <para>
+            Then, this filter can be attached to a class:
+        </para>
+
+        <programlisting><![CDATA[<class name="myClass" ...>
+    ...
+    <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</class>]]></programlisting>
+
+        <para>
+            or, to a collection:
+        </para>
+
+        <programlisting><![CDATA[<set ...>
+    <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</set>]]></programlisting>
+
+        <para>
+            or, even to both (or multiples of each) at the same time.
+        </para>
+
+        <para>
+            The methods on <literal>Session</literal> are: <literal>enableFilter(String filterName)</literal>,
+            <literal>getEnabledFilter(String filterName)</literal>, and <literal>disableFilter(String filterName)</literal>.
+            By default, filters are <emphasis>not</emphasis> enabled for a given session; they must be explcitly
+            enabled through use of the <literal>Session.enabledFilter()</literal> method, which returns an
+            instance of the <literal>Filter</literal> interface. Using the simple filter defined above, this
+            would look like:
+        </para>
+
+        <programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
+
+        <para>
+            Note that methods on the org.hibernate.Filter interface do allow the method-chaining common to much of Hibernate.
+        </para>
+
+        <para>
+            A full example, using temporal data with an effective record date pattern:
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="effectiveDate">
+    <filter-param name="asOfDate" type="date"/>
+</filter-def>
+
+<class name="Employee" ...>
+...
+    <many-to-one name="department" column="dept_id" class="Department"/>
+    <property name="effectiveStartDate" type="date" column="eff_start_dt"/>
+    <property name="effectiveEndDate" type="date" column="eff_end_dt"/>
+...
+    <!--
+        Note that this assumes non-terminal records have an eff_end_dt set to
+        a max db date for simplicity-sake
+    -->
+    <filter name="effectiveDate"
+            condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+</class>
+
+<class name="Department" ...>
+...
+    <set name="employees" lazy="true">
+        <key column="dept_id"/>
+        <one-to-many class="Employee"/>
+        <filter name="effectiveDate"
+                condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Then, in order to ensure that you always get back currently effective records, simply
+            enable the filter on the session prior to retrieving employee data:
+        </para>
+
+<programlisting><![CDATA[Session session = ...;
+session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
+List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
+         .setLong("targetSalary", new Long(1000000))
+         .list();
+]]></programlisting>
+
+        <para>
+            In the HQL above, even though we only explicitly mentioned a salary constraint on the results,
+            because of the enabled filter the query will return only currently active employees who have
+            a salary greater than a million dollars.
+        </para>
+
+        <para>
+            Note: if you plan on using filters with outer joining (either through HQL or load fetching) be
+            careful of the direction of the condition expression.  Its safest to set this up for left
+            outer joining; in general, place the parameter first followed by the column name(s) after
+            the operator.
+        </para>
+
+        <para>
+            After being defined a filter might be attached to multiple entities and/or
+            collections each with its own condition.  That can be tedious when the
+            conditions are the same each time.  Thus <literal>&lt;filter-def/&gt;</literal>
+            allows defining a default condition, either as an attribute or CDATA:
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="myFilter" condition="abc > xyz">...</filter-def>
+<filter-def name="myOtherFilter">abc=xyz</filter-def>]]></programlisting>
+
+        <para>
+            This default condition will then be used whenever the filter is attached to something
+            without specifying a condition.  Note that this means you can give a specific condition
+            as part of the attachment of the filter which overrides the default condition in that
+            particular case.
+        </para>
+
+    </sect1>
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/filters.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/inheritance_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/inheritance_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/inheritance_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,491 @@
+<chapter id="inheritance">
+    <title>Inheritance Mapping</title>
+
+    <sect1 id="inheritance-strategies" revision="3">
+        <title>The Three Strategies</title>
+
+        <para>
+            Hibernate supports the three basic inheritance mapping strategies:
+        </para>
+
+        <itemizedlist>
+        <listitem>
+        <para>
+            table per class hierarchy
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            table per subclass
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            table per concrete class
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            In addition, Hibernate supports a fourth, slightly different kind of 
+            polymorphism:
+        </para>
+
+        <itemizedlist>
+        <listitem>
+        <para>
+            implicit polymorphism
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            It is possible to use different mapping strategies for different
+            branches of the same inheritance hierarchy, and then make use of implicit
+            polymorphism to achieve polymorphism across the whole hierarchy. However, 
+            Hibernate does not support mixing <literal>&lt;subclass&gt;</literal>,
+            and <literal>&lt;joined-subclass&gt;</literal> and 
+            <literal>&lt;union-subclass&gt;</literal> mappings under the same root
+            <literal>&lt;class&gt;</literal> element. It is possible to mix together
+            the table per hierarchy and table per subclass strategies, under the
+            the same <literal>&lt;class&gt;</literal> element, by combining the 
+            <literal>&lt;subclass&gt;</literal> and <literal>&lt;join&gt;</literal>
+            elements (see below).
+        </para>
+
+        <para>
+             It is possible to define <literal>subclass</literal>, <literal>union-subclass</literal>,
+             and <literal>joined-subclass</literal> mappings in separate mapping documents, directly beneath
+             <literal>hibernate-mapping</literal>. This allows you to extend a class hierachy just by adding
+             a new mapping file. You must specify an <literal>extends</literal> attribute in the subclass mapping,
+             naming a previously mapped superclass. Note: Previously this feature made the ordering of the mapping
+             documents important. Since Hibernate3, the ordering of mapping files does not matter when using the
+             extends keyword. The ordering inside a single mapping file still needs to be defined as superclasses
+             before subclasses.
+         </para>
+
+         <programlisting><![CDATA[
+ <hibernate-mapping>
+     <subclass name="DomesticCat" extends="Cat" discriminator-value="D">
+          <property name="name" type="string"/>
+     </subclass>
+ </hibernate-mapping>]]></programlisting>
+
+
+        <sect2 id="inheritance-tableperclass" >
+        <title>Table per class hierarchy</title>
+
+        <para>
+            Suppose we have an interface <literal>Payment</literal>, with implementors
+            <literal>CreditCardPayment</literal>, <literal>CashPayment</literal>,
+            <literal>ChequePayment</literal>. The table per hierarchy mapping would
+            look like:
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        ...
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        ...
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            Exactly one table is required. There is one big limitation of this mapping 
+            strategy: columns declared by the subclasses, such as <literal>CCTYPE</literal>, 
+            may not have <literal>NOT NULL</literal> constraints.
+        </para>
+        
+        </sect2>
+
+        <sect2 id="inheritance-tablepersubclass">
+        <title>Table per subclass</title>
+
+        <para>
+            A table per subclass mapping would look like:
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        ...
+    </joined-subclass>
+</class>]]></programlisting>
+
+        <para>
+            Four tables are required. The three subclass tables have primary
+            key associations to the superclass table (so the relational model
+            is actually a one-to-one association).
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-tablepersubclass-discriminator" revision="2">
+        <title>Table per subclass, using a discriminator</title>
+
+        <para>
+            Note that Hibernate's implementation of table per subclass requires
+            no discriminator column. Other object/relational mappers use a
+            different implementation of table per subclass which requires a type
+            discriminator column in the superclass table. The approach taken by
+            Hibernate is much more difficult to implement but arguably more
+            correct from a relational point of view. If you would like to use
+            a discriminator column with the table per subclass strategy, you
+            may combine the use of <literal>&lt;subclass&gt;</literal> and 
+            <literal>&lt;join&gt;</literal>, as follow:
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <join table="CREDIT_PAYMENT">
+            <key column="PAYMENT_ID"/>
+            <property name="creditCardType" column="CCTYPE"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        <join table="CASH_PAYMENT">
+            <key column="PAYMENT_ID"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        <join table="CHEQUE_PAYMENT" fetch="select">
+            <key column="PAYMENT_ID"/>
+            ...
+        </join>
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            The optional <literal>fetch="select"</literal> declaration tells Hibernate 
+            not to fetch the <literal>ChequePayment</literal> subclass data using an
+            outer join when querying the superclass.
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
+        <title>Mixing table per class hierarchy with table per subclass</title>
+
+        <para>
+            You may even mix the table per hierarchy and table per subclass strategies
+            using this approach:
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <join table="CREDIT_PAYMENT">
+            <property name="creditCardType" column="CCTYPE"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        ...
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        ...
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            For any of these mapping strategies, a polymorphic association to the root
+            <literal>Payment</literal> class is mapped using 
+            <literal>&lt;many-to-one&gt;</literal>.
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
+    
+        </sect2>
+
+        <sect2 id="inheritance-tableperconcrete" revision="2">
+        <title>Table per concrete class</title>
+
+        <para>
+            There are two ways we could go about mapping the table per concrete class
+            strategy. The first is to use <literal>&lt;union-subclass&gt;</literal>.
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="sequence"/>
+    </id>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </union-subclass>
+    <union-subclass name="CashPayment" table="CASH_PAYMENT">
+        ...
+    </union-subclass>
+    <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        ...
+    </union-subclass>
+</class>]]></programlisting>
+
+        <para>
+            Three tables are involved for the subclasses. Each table defines columns for
+            all properties of the class, including inherited properties.
+        </para>
+        
+        <para>
+            The limitation of this approach is that if a property is mapped on the 
+            superclass, the column name must be the same on all subclass tables.
+            (We might relax this in a future release of Hibernate.) The identity
+			generator strategy is not allowed in union subclass inheritance, indeed
+			the primary key seed has to be shared accross all unioned subclasses
+			of a hierarchy.
+        </para>
+
+        <para>
+            If your superclass is abstract, map it with <literal>abstract="true"</literal>.
+            Of course, if it is not abstract, an additional table (defaults to
+            <literal>PAYMENT</literal> in the example above) is needed to hold instances
+            of the superclass.
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-tableperconcreate-polymorphism">
+        <title>Table per concrete class, using implicit polymorphism</title>
+
+        <para>
+            An alternative approach is to make use of implicit polymorphism:
+        </para>
+
+        <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+    <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CREDIT_AMOUNT"/>
+    ...
+</class>
+
+<class name="CashPayment" table="CASH_PAYMENT">
+    <id name="id" type="long" column="CASH_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CASH_AMOUNT"/>
+    ...
+</class>
+
+<class name="ChequePayment" table="CHEQUE_PAYMENT">
+    <id name="id" type="long" column="CHEQUE_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CHEQUE_AMOUNT"/>
+    ...
+</class>]]></programlisting>
+           
+        <para>
+            Notice that nowhere do we mention the <literal>Payment</literal> interface 
+            explicitly. Also notice that properties of <literal>Payment</literal> are 
+            mapped in each of the subclasses. If you want to avoid duplication, consider
+            using XML entities
+            (e.g. <literal>[ &lt;!ENTITY allproperties SYSTEM "allproperties.xml"&gt; ]</literal>
+            in the <literal>DOCTYPE</literal> declartion and 
+            <literal>&amp;allproperties;</literal> in the mapping).
+        </para>
+        
+        <para>
+            The disadvantage of this approach is that Hibernate does not generate SQL
+            <literal>UNION</literal>s when performing polymorphic queries.
+        </para>
+
+        <para>
+            For this mapping strategy, a polymorphic association to <literal>Payment</literal> 
+            is usually mapped using <literal>&lt;any&gt;</literal>.
+        </para>
+
+        <programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
+    <meta-value value="CREDIT" class="CreditCardPayment"/>
+    <meta-value value="CASH" class="CashPayment"/>
+    <meta-value value="CHEQUE" class="ChequePayment"/>
+    <column name="PAYMENT_CLASS"/>
+    <column name="PAYMENT_ID"/>
+</any>]]></programlisting>
+           
+        </sect2>
+
+        <sect2 id="inheritace-mixingpolymorphism">
+        <title>Mixing implicit polymorphism with other inheritance mappings</title>
+
+        <para>
+            There is one further thing to notice about this mapping. Since the subclasses 
+            are each mapped in their own <literal>&lt;class&gt;</literal> element (and since
+            <literal>Payment</literal> is just an interface), each of the subclasses could 
+            easily be part of another inheritance hierarchy! (And you can still use polymorphic
+            queries against the <literal>Payment</literal> interface.)
+       </para>
+
+        <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+    <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="CREDIT_CARD" type="string"/>
+    <property name="amount" column="CREDIT_AMOUNT"/>
+    ...
+    <subclass name="MasterCardPayment" discriminator-value="MDC"/>
+    <subclass name="VisaPayment" discriminator-value="VISA"/>
+</class>
+
+<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
+    <id name="id" type="long" column="TXN_ID">
+        <generator class="native"/>
+    </id>
+    ...
+    <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="amount" column="CASH_AMOUNT"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="amount" column="CHEQUE_AMOUNT"/>
+        ...
+    </joined-subclass>
+</class>]]></programlisting>
+
+        <para>
+            Once again, we don't mention <literal>Payment</literal> explicitly. If we
+            execute a query against the <literal>Payment</literal> interface - for
+            example, <literal>from Payment</literal> - Hibernate
+            automatically returns instances of <literal>CreditCardPayment</literal>
+            (and its subclasses, since they also implement <literal>Payment</literal>),
+            <literal>CashPayment</literal> and <literal>ChequePayment</literal> but
+            not instances of <literal>NonelectronicTransaction</literal>.
+        </para>
+        
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="inheritance-limitations">
+        <title>Limitations</title>
+
+        <para>
+            There are certain limitations to the "implicit polymorphism" approach to
+            the table per concrete-class mapping strategy. There are somewhat less
+            restrictive limitations to <literal>&lt;union-subclass&gt;</literal>
+            mappings.
+        </para>
+
+        <para>
+            The following table shows the limitations of table per concrete-class
+            mappings, and of implicit polymorphism, in Hibernate.
+        </para>
+            
+        <table frame="topbot">
+            <title>Features of inheritance mappings</title>
+            <tgroup cols='8' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="1*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <colspec colname='c6' colwidth="1*"/>
+            <colspec colname='c7' colwidth="1*"/>
+            <colspec colname='c8' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Inheritance strategy</entry>
+              <entry>Polymorphic many-to-one</entry>
+              <entry>Polymorphic one-to-one</entry>
+              <entry>Polymorphic one-to-many</entry>
+              <entry>Polymorphic many-to-many</entry>
+              <entry>Polymorphic <literal>load()/get()</literal></entry>
+              <entry>Polymorphic queries</entry>
+              <entry>Polymorphic joins</entry>
+              <entry>Outer join fetching</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>table per class-hierarchy</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal></entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>supported</emphasis></entry>
+            </row>
+            <row>
+                <entry>table per subclass</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal></entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>supported</emphasis></entry>
+            </row>
+            <row>
+                <entry>table per concrete-class (union-subclass)</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal> (for <literal>inverse="true"</literal> only)</entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>supported</emphasis></entry>
+            </row>
+            <row>
+                <entry>table per concrete class (implicit polymorphism)</entry>
+                <entry><literal>&lt;any&gt;</literal></entry>
+                <entry><emphasis>not supported</emphasis></entry>
+                <entry><emphasis>not supported</emphasis></entry>
+                <entry><literal>&lt;many-to-any&gt;</literal></entry>
+                <entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><emphasis>not supported</emphasis></entry>
+                <entry><emphasis>not supported</emphasis></entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/performance.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/performance.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/performance.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1388 @@
+<chapter id="performance">
+    <title>Improving performance</title>
+
+    <sect1 id="performance-fetching" revision="2">
+        <title>Fetching strategies</title>
+
+        <para>
+            A <emphasis>fetching strategy</emphasis> is the strategy Hibernate will use for 
+            retrieving associated objects if the application needs to navigate the association. 
+            Fetch strategies may be declared in the O/R mapping metadata, or over-ridden by a 
+            particular HQL or <literal>Criteria</literal> query.
+        </para>
+
+        <para>
+            Hibernate3 defines the following fetching strategies:
+        </para>
+
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <emphasis>Join fetching</emphasis> - Hibernate retrieves the
+                    associated instance or collection in the same <literal>SELECT</literal>,
+                    using an <literal>OUTER JOIN</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Select fetching</emphasis> - a second <literal>SELECT</literal>
+                    is used to retrieve the associated entity or collection. Unless
+                    you explicitly disable lazy fetching by specifying <literal>lazy="false"</literal>, 
+                    this second select will only be executed when you actually access the
+                    association.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Subselect fetching</emphasis> - a second <literal>SELECT</literal>
+                    is used to retrieve the associated collections for all entities retrieved in a
+                    previous query or fetch. Unless you explicitly disable lazy fetching by specifying 
+                    <literal>lazy="false"</literal>, this second select will only be executed when you 
+                    actually access the association.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Batch fetching</emphasis> - an optimization strategy
+                    for select fetching - Hibernate retrieves a batch of entity instances 
+                    or collections in a single <literal>SELECT</literal>, by specifying 
+                    a list of primary keys or foreign keys.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            Hibernate also distinguishes between:
+        </para>
+
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <emphasis>Immediate fetching</emphasis> - an association, collection or
+                    attribute is fetched immediately, when the owner is loaded.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Lazy collection fetching</emphasis> - a collection is fetched 
+                    when the application invokes an operation upon that collection. (This
+                    is the default for collections.)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>"Extra-lazy" collection fetching</emphasis> - individual
+                    elements of the collection are accessed from the database as needed.
+                    Hibernate tries not to fetch the whole collection into memory unless
+                    absolutely needed (suitable for very large collections)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Proxy fetching</emphasis> - a single-valued association is 
+                    fetched when a method other than the identifier getter is invoked
+                    upon the associated object.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>"No-proxy" fetching</emphasis> - a single-valued association is 
+                    fetched when the instance variable is accessed. Compared to proxy fetching, 
+                    this approach is less lazy (the association is fetched even when only the 
+                    identifier is accessed) but more transparent, since no proxy is visible to 
+                    the application. This approach requires buildtime bytecode instrumentation 
+                    and is rarely necessary.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Lazy attribute fetching</emphasis> - an attribute or single
+                    valued association is fetched when the instance variable is accessed. 
+                    This approach requires buildtime bytecode instrumentation and is rarely 
+                    necessary.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            We have two orthogonal notions here: <emphasis>when</emphasis> is the association
+            fetched, and <emphasis>how</emphasis> is it fetched (what SQL is used). Don't
+            confuse them! We use <literal>fetch</literal> to tune performance. We may use 
+            <literal>lazy</literal> to define a contract for what data is always available 
+            in any detached instance of a particular class.
+        </para>
+ 
+        <sect2 id="performance-fetching-lazy">
+            <title>Working with lazy associations</title>
+            
+            <para>
+                By default, Hibernate3 uses lazy select fetching for collections and lazy proxy
+                fetching for single-valued associations. These defaults make sense for almost
+                all associations in almost all applications. 
+            </para>
+            
+            <para>
+                <emphasis>Note:</emphasis> if you set 
+                <literal>hibernate.default_batch_fetch_size</literal>, Hibernate will use the 
+                batch fetch optimization for lazy fetching (this optimization may also be enabled 
+                at a more granular level).
+            </para>
+            
+            <para>
+                However, lazy fetching poses one problem that you must be aware of. Access to a 
+                lazy association outside of the context of an open Hibernate session will result 
+                in an exception. For example:
+            </para>
+        
+            <programlisting><![CDATA[s = sessions.openSession();
+Transaction tx = s.beginTransaction();
+            
+User u = (User) s.createQuery("from User u where u.name=:userName")
+    .setString("userName", userName).uniqueResult();
+Map permissions = u.getPermissions();
+
+tx.commit();
+s.close();
+
+Integer accessLevel = (Integer) permissions.get("accounts");  // Error!]]></programlisting>
+
+            <para>
+                Since the permissions collection was not initialized when the 
+                <literal>Session</literal> was closed, the collection will not be able to 
+                load its state. <emphasis>Hibernate does not support lazy initialization 
+                for detached objects</emphasis>. The fix is to move the code that reads 
+                from the collection to just before the transaction is committed.
+            </para>
+    
+            <para>
+                Alternatively, we could use a non-lazy collection or association, 
+                by specifying <literal>lazy="false"</literal> for the association mapping.
+                However, it is intended that lazy initialization be used for almost all 
+                collections and associations. If you define too many non-lazy associations 
+                in your object model, Hibernate will end up needing to fetch the entire 
+                database into memory in every transaction!
+            </para>
+    
+            <para>
+                On the other hand, we often want to choose join fetching (which is non-lazy by 
+                nature) instead of select fetching in a particular transaction. We'll now see
+                how to customize the fetching strategy. In Hibernate3, the mechanisms for
+                choosing a fetch strategy are identical for single-valued associations and
+                collections.
+            </para>
+        
+        </sect2>
+        
+        <sect2 id="performance-fetching-custom" revision="4">
+            <title>Tuning fetch strategies</title>
+            
+            <para>
+                Select fetching (the default) is extremely vulnerable to N+1 selects problems, 
+                so we might want to enable join fetching in the mapping document:
+            </para>
+            
+            <programlisting><![CDATA[<set name="permissions" 
+            fetch="join">
+    <key column="userId"/>
+    <one-to-many class="Permission"/>
+</set]]></programlisting>
+
+           <programlisting><![CDATA[<many-to-one name="mother" class="Cat" fetch="join"/>]]></programlisting>
+
+            <para>
+                The <literal>fetch</literal> strategy defined in the mapping document affects:
+            </para>
+            
+        <itemizedlist>
+             <listitem>
+                <para>
+                    retrieval via <literal>get()</literal> or <literal>load()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    retrieval that happens implicitly when an association is navigated
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>Criteria</literal> queries
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    HQL queries if <literal>subselect</literal> fetching is used
+                </para>
+            </listitem>
+        </itemizedlist>
+
+            <para>
+                No matter what fetching strategy you use, the defined non-lazy graph is guaranteed
+                to be loaded into memory. Note that this might result in several immediate selects
+                being used to execute a particular HQL query.
+            </para>
+
+            <para>
+                Usually, we don't use the mapping document to customize fetching. Instead, we
+                keep the default behavior, and override it for a particular transaction, using 
+                <literal>left join fetch</literal> in HQL. This tells Hibernate to fetch 
+                the association eagerly in the first select, using an outer join. In the
+                <literal>Criteria</literal> query API, you would use
+                <literal>setFetchMode(FetchMode.JOIN)</literal>.
+            </para>
+            
+            <para>
+                If you ever feel like you wish you could change the fetching strategy used by
+                <literal>get()</literal> or <literal>load()</literal>, simply use a 
+                <literal>Criteria</literal> query, for example:
+            </para>
+            
+            <programlisting><![CDATA[User user = (User) session.createCriteria(User.class)
+                .setFetchMode("permissions", FetchMode.JOIN)
+                .add( Restrictions.idEq(userId) )
+                .uniqueResult();]]></programlisting>
+                
+            <para>
+                (This is Hibernate's equivalent of what some ORM solutions call a "fetch plan".)
+            </para>
+
+            <para>
+                A completely different way to avoid problems with N+1 selects is to use the 
+                second-level cache.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-proxies" revision="2">
+            <title>Single-ended association proxies</title>
+
+            <para>
+                Lazy fetching for collections is implemented using Hibernate's own implementation
+                of persistent collections. However, a different mechanism is needed for lazy
+                behavior in single-ended associations. The target entity of the association must
+                be proxied. Hibernate implements lazy initializing proxies for persistent objects
+                using runtime bytecode enhancement (via the excellent CGLIB library).
+            </para>
+
+            <para>
+                By default, Hibernate3 generates proxies (at startup) for all persistent classes
+                and uses them to enable lazy fetching of <literal>many-to-one</literal> and
+                <literal>one-to-one</literal> associations.
+            </para>
+
+            <para>
+                The mapping file may declare an interface to use as the proxy interface for that
+                class, with the <literal>proxy</literal> attribute. By default, Hibernate uses a subclass
+                of the class. <emphasis>Note that the proxied class must implement a default constructor
+                with at least package visibility. We recommend this constructor for all persistent classes!</emphasis>
+            </para>
+
+            <para>
+                There are some gotchas to be aware of when extending this approach to polymorphic
+                classes, eg.
+            </para>
+
+            <programlisting><![CDATA[<class name="Cat" proxy="Cat">
+    ......
+    <subclass name="DomesticCat">
+        .....
+    </subclass>
+</class>]]></programlisting>
+
+            <para>
+                Firstly, instances of <literal>Cat</literal> will never be castable to
+                <literal>DomesticCat</literal>, even if the underlying instance is an
+                instance of <literal>DomesticCat</literal>:
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id);  // instantiate a proxy (does not hit the db)
+if ( cat.isDomesticCat() ) {                  // hit the db to initialize the proxy
+    DomesticCat dc = (DomesticCat) cat;       // Error!
+    ....
+}]]></programlisting>
+
+            <para>
+                Secondly, it is possible to break proxy <literal>==</literal>.
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id);            // instantiate a Cat proxy
+DomesticCat dc = 
+        (DomesticCat) session.load(DomesticCat.class, id);  // acquire new DomesticCat proxy!
+System.out.println(cat==dc);                            // false]]></programlisting>
+
+            <para>
+                However, the situation is not quite as bad as it looks. Even though we now have two references
+                to different proxy objects, the underlying instance will still be the same object:
+            </para>
+
+            <programlisting><![CDATA[cat.setWeight(11.0);  // hit the db to initialize the proxy
+System.out.println( dc.getWeight() );  // 11.0]]></programlisting>
+
+            <para>
+                Third, you may not use a CGLIB proxy for a <literal>final</literal> class or a class
+                with any <literal>final</literal> methods.
+            </para>
+
+            <para>
+                Finally, if your persistent object acquires any resources upon instantiation (eg. in
+                initializers or default constructor), then those resources will also be acquired by
+                the proxy. The proxy class is an actual subclass of the persistent class.
+            </para>
+
+            <para>
+                These problems are all due to fundamental limitations in Java's single inheritance model.
+                If you wish to avoid these problems your persistent classes must each implement an interface
+                that declares its business methods. You should specify these interfaces in the mapping file. eg.
+            </para>
+
+            <programlisting><![CDATA[<class name="CatImpl" proxy="Cat">
+    ......
+    <subclass name="DomesticCatImpl" proxy="DomesticCat">
+        .....
+    </subclass>
+</class>]]></programlisting>
+
+            <para>
+                where <literal>CatImpl</literal> implements the interface <literal>Cat</literal> and
+                <literal>DomesticCatImpl</literal> implements the interface <literal>DomesticCat</literal>. Then
+                proxies for instances of <literal>Cat</literal> and <literal>DomesticCat</literal> may be returned
+                by <literal>load()</literal> or <literal>iterate()</literal>. (Note that <literal>list()</literal>
+                does not usually return proxies.)
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(CatImpl.class, catid);
+Iterator iter = session.iterate("from CatImpl as cat where cat.name='fritz'");
+Cat fritz = (Cat) iter.next();]]></programlisting>
+
+            <para>
+                Relationships are also lazily initialized. This means you must declare any properties to be of
+                type <literal>Cat</literal>, not <literal>CatImpl</literal>.
+            </para>
+
+            <para>
+                Certain operations do <emphasis>not</emphasis> require proxy initialization
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>equals()</literal>, if the persistent class does not override
+                        <literal>equals()</literal>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>hashCode()</literal>, if the persistent class does not override
+                        <literal>hashCode()</literal>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        The identifier getter method
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Hibernate will detect persistent classes that override <literal>equals()</literal> or
+                <literal>hashCode()</literal>.
+            </para>
+            
+            <para>
+                By choosing <literal>lazy="no-proxy"</literal> instead of the default 
+                <literal>lazy="proxy"</literal>, we can avoid the problems associated with typecasting.
+                However, we will require buildtime bytecode instrumentation, and all operations
+                will result in immediate proxy initialization.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-initialization" revision="1">
+            <title>Initializing collections and proxies</title>
+
+            <para>
+                A <literal>LazyInitializationException</literal> will be thrown by Hibernate if an uninitialized 
+                collection or proxy is accessed outside of the scope of the <literal>Session</literal>, ie. when 
+                the entity owning the collection or having the reference to the proxy is in the detached state.
+            </para>
+
+            <para>
+                Sometimes we need to ensure that a proxy or collection is initialized before closing the
+                <literal>Session</literal>. Of course, we can alway force initialization by calling
+                <literal>cat.getSex()</literal> or <literal>cat.getKittens().size()</literal>, for example.
+                But that is confusing to readers of the code and is not convenient for generic code.
+            </para>
+
+            <para>
+                The static methods <literal>Hibernate.initialize()</literal> and <literal>Hibernate.isInitialized()</literal>
+                provide the application with a convenient way of working with lazily initialized collections or
+                proxies. <literal>Hibernate.initialize(cat)</literal> will force the initialization of a proxy,
+                <literal>cat</literal>, as long as its <literal>Session</literal> is still open.
+                <literal>Hibernate.initialize( cat.getKittens() )</literal> has a similar effect for the collection
+                of kittens.
+            </para>
+
+            <para>
+                Another option is to keep the <literal>Session</literal> open until all needed
+                collections and proxies have been loaded. In some application architectures,
+                particularly where the code that accesses data using Hibernate, and the code that
+                uses it are in different application layers or different physical processes, it 
+                can be a problem to ensure that the <literal>Session</literal> is open when a 
+                collection is initialized. There are two basic ways to deal with this issue:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        In a web-based application, a servlet filter can be used to close the
+                        <literal>Session</literal> only at the very end of a user request, once
+                        the rendering of the view is complete (the <emphasis>Open Session in
+                        View</emphasis> pattern).  Of course, this places heavy demands on the 
+                        correctness of the exception handling of your application infrastructure. 
+                        It is vitally important that the <literal>Session</literal> is closed and the 
+                        transaction ended before returning to the user, even when an exception occurs 
+                        during rendering of the view. See the Hibernate Wiki for examples of this
+                        "Open Session in View" pattern.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        In an application with a separate business tier, the business logic must
+                        "prepare" all collections that will be needed by the web tier before
+                        returning. This means that the business tier should load all the data and
+                        return all the data already initialized to the presentation/web tier that
+                        is required for a particular use case. Usually, the application calls
+                        <literal>Hibernate.initialize()</literal> for each collection that will
+                        be needed in the web tier (this call must occur before the session is closed)
+                        or retrieves the collection eagerly using a Hibernate query with a
+                        <literal>FETCH</literal> clause or a <literal>FetchMode.JOIN</literal> in
+                        <literal>Criteria</literal>. This is usually easier if you adopt the
+                        <emphasis>Command</emphasis> pattern instead of a <emphasis>Session Facade</emphasis>.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        You may also attach a previously loaded object to a new <literal>Session</literal>
+                        with <literal>merge()</literal> or <literal>lock()</literal> before
+                        accessing uninitialized collections (or other proxies). No, Hibernate does not,
+                        and certainly <emphasis>should</emphasis> not do this automatically, since it 
+                        would introduce ad hoc transaction semantics!
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Sometimes you don't want to initialize a large collection, but still need some
+                information about it (like its size) or a subset of the data.
+            </para>
+
+            <para>
+                You can use a collection filter to get the size of a collection without initializing it:
+            </para>
+
+            <programlisting><![CDATA[( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()]]></programlisting>
+
+            <para>
+                The <literal>createFilter()</literal> method is also used to efficiently retrieve subsets
+                of a collection without needing to initialize the whole collection:
+            </para>
+
+            <programlisting><![CDATA[s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-batch">
+            <title>Using batch fetching</title>
+
+            <para>
+                Hibernate can make efficient use of batch fetching, that is, Hibernate can load several uninitialized
+                proxies if one proxy is accessed (or collections. Batch fetching is an optimization of the lazy select
+                fetching strategy. There are two ways you can tune batch fetching: on the class and the collection level.
+            </para>
+
+            <para>
+                Batch fetching for classes/entities is easier to understand. Imagine you have the following situation
+                at runtime: You have 25 <literal>Cat</literal> instances loaded in a <literal>Session</literal>, each
+                <literal>Cat</literal> has a reference to its <literal>owner</literal>, a <literal>Person</literal>.
+                The <literal>Person</literal> class is mapped with a proxy, <literal>lazy="true"</literal>. If you now
+                iterate through all cats and call <literal>getOwner()</literal> on each, Hibernate will by default
+                execute 25 <literal>SELECT</literal> statements, to retrieve the proxied owners. You can tune this
+                behavior by specifying a <literal>batch-size</literal> in the mapping of <literal>Person</literal>:
+            </para>
+
+            <programlisting><![CDATA[<class name="Person" batch-size="10">...</class>]]></programlisting>
+
+            <para>
+                Hibernate will now execute only three queries, the pattern is 10, 10, 5.
+            </para>
+
+            <para>
+                You may also enable batch fetching of collections. For example, if each <literal>Person</literal> has
+                a lazy collection of <literal>Cat</literal>s, and 10 persons are currently loaded in the
+                <literal>Sesssion</literal>, iterating through all persons will generate 10 <literal>SELECT</literal>s,
+                one for every call to <literal>getCats()</literal>. If you enable batch fetching for the
+                <literal>cats</literal> collection in the mapping of <literal>Person</literal>, Hibernate can pre-fetch
+                collections:
+            </para>
+
+            <programlisting><![CDATA[<class name="Person">
+    <set name="cats" batch-size="3">
+        ...
+    </set>
+</class>]]></programlisting>
+
+            <para>
+                With a <literal>batch-size</literal> of 8, Hibernate will load 3, 3, 3, 1 collections in four
+                <literal>SELECT</literal>s. Again, the value of the attribute depends on the expected number of
+                uninitialized collections in a particular <literal>Session</literal>.
+            </para>
+
+            <para>
+                Batch fetching of collections is particularly useful if you have a nested tree of items, ie.
+                the typical bill-of-materials pattern. (Although a <emphasis>nested set</emphasis> or a
+                <emphasis>materialized path</emphasis> might be a better option for read-mostly trees.)
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-subselect">
+            <title>Using subselect fetching</title>
+
+            <para>
+                If one lazy collection or single-valued proxy has to be fetched, Hibernate loads all of
+                them, re-running the original query in a subselect. This works in the same way as
+                batch-fetching, without the piecemeal loading.
+            </para>
+            
+            <!-- TODO: Write more about this -->
+
+        </sect2>
+        
+        <sect2 id="performance-fetching-lazyproperties">
+            <title>Using lazy property fetching</title>
+
+            <para>
+                Hibernate3 supports the lazy fetching of individual properties. This optimization technique
+                is also known as <emphasis>fetch groups</emphasis>. Please note that this is mostly a
+                marketing feature, as in practice, optimizing row reads is much more important than
+                optimization of column reads. However, only loading some properties of a class might
+                be useful in extreme cases, when legacy tables have hundreds of columns and the data model
+                can not be improved.
+            </para>
+
+            <para>
+                To enable lazy property loading, set the <literal>lazy</literal> attribute on your
+                particular property mappings:
+            </para>
+
+            <programlisting><![CDATA[<class name="Document">
+       <id name="id">
+        <generator class="native"/>
+    </id>
+    <property name="name" not-null="true" length="50"/>
+    <property name="summary" not-null="true" length="200" lazy="true"/>
+    <property name="text" not-null="true" length="2000" lazy="true"/>
+</class>]]></programlisting>
+
+            <para>
+                Lazy property loading requires buildtime bytecode instrumentation! If your persistent
+                classes are not enhanced, Hibernate will silently ignore lazy property settings and
+                fall back to immediate fetching.
+            </para>
+
+            <para>
+                For bytecode instrumentation, use the following Ant task:
+            </para>
+
+            <programlisting><![CDATA[<target name="instrument" depends="compile">
+    <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
+        <classpath path="${jar.path}"/>
+        <classpath path="${classes.dir}"/>
+        <classpath refid="lib.class.path"/>
+    </taskdef>
+
+    <instrument verbose="true">
+        <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
+            <include name="*.class"/>
+        </fileset>
+    </instrument>
+</target>]]></programlisting>
+
+            <para>
+                A different (better?) way to avoid unnecessary column reads, at least for
+                read-only transactions is to use the projection features of HQL or Criteria
+                queries. This avoids the need for buildtime bytecode processing and is
+                certainly a prefered solution.
+            </para>
+            
+            <para>
+                You may force the usual eager fetching of properties using <literal>fetch all
+                properties</literal> in HQL.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="performance-cache" revision="1">
+        <title>The Second Level Cache</title>
+
+        <para>
+            A Hibernate <literal>Session</literal> is a transaction-level cache of persistent data. It is
+            possible to configure a cluster or JVM-level (<literal>SessionFactory</literal>-level) cache on 
+            a class-by-class and collection-by-collection basis. You may even plug in a clustered cache. Be 
+            careful. Caches are never aware of changes made to the persistent store by another application 
+            (though they may be configured to regularly expire cached data).
+        </para>
+        
+        <para revision="1">
+            You have the option to tell Hibernate which caching implementation to use by
+            specifying the name of a class that implements <literal>org.hibernate.cache.CacheProvider</literal>
+            using the property <literal>hibernate.cache.provider_class</literal>.  Hibernate
+            comes bundled with a number of built-in integrations with open-source cache providers
+            (listed below); additionally, you could implement your own and plug it in as
+            outlined above.  Note that versions prior to 3.2 defaulted to use EhCache as the
+            default cache provider; that is no longer the case as of 3.2.
+        </para>
+
+        <table frame="topbot" id="cacheproviders" revision="1">
+            <title>Cache Providers</title>
+            <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="3*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Cache</entry>
+              <entry>Provider class</entry>
+              <entry>Type</entry>
+              <entry>Cluster Safe</entry>
+              <entry>Query Cache Supported</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>Hashtable (not intended for production use)</entry>
+                <entry><literal>org.hibernate.cache.HashtableCacheProvider</literal></entry>
+                <entry>memory</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>EHCache</entry>
+                <entry><literal>org.hibernate.cache.EhCacheProvider</literal></entry>
+                <entry>memory, disk</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>OSCache</entry>
+                <entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
+                <entry>memory, disk</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>SwarmCache</entry>
+                <entry><literal>org.hibernate.cache.SwarmCacheProvider</literal></entry>
+                <entry>clustered (ip multicast)</entry>
+                <entry>yes (clustered invalidation)</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>JBoss TreeCache</entry>
+                <entry><literal>org.hibernate.cache.TreeCacheProvider</literal></entry>
+                <entry>clustered (ip multicast), transactional</entry>
+                <entry>yes (replication)</entry>
+                <entry>yes (clock sync req.)</entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <sect2 id="performance-cache-mapping" revision="2">
+            <title>Cache mappings</title>
+
+            <para>
+                The <literal>&lt;cache&gt;</literal> element of a class or collection mapping has the
+                following form:
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="cache1" coords="2 70"/>
+                    <area id="cache2" coords="3 70"/>
+                    <area id="cache3" coords="4 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<cache 
+    usage="transactional|read-write|nonstrict-read-write|read-only"
+    region="RegionName"
+    include="all|non-lazy"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="cache1">
+                        <para>
+                            <literal>usage</literal> (required) specifies the caching strategy:
+                            <literal>transactional</literal>,
+                            <literal>read-write</literal>,
+                            <literal>nonstrict-read-write</literal> or
+                            <literal>read-only</literal>
+                        </para>
+                    </callout>                   
+                    <callout arearefs="cache2">
+                        <para>
+                            <literal>region</literal> (optional, defaults to the class or
+                            collection role name) specifies the name of the second level cache 
+                            region
+                        </para>
+                    </callout>                   
+                    <callout arearefs="cache3">
+                        <para>
+                            <literal>include</literal> (optional, defaults to <literal>all</literal>) 
+                            <literal>non-lazy</literal> specifies that properties of the entity mapped
+                            with <literal>lazy="true"</literal> may not be cached when attribute-level
+                            lazy fetching is enabled
+                        </para>
+                    </callout>                   
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                Alternatively (preferrably?), you may specify <literal>&lt;class-cache&gt;</literal> and 
+                <literal>&lt;collection-cache&gt;</literal> elements in <literal>hibernate.cfg.xml</literal>.
+            </para>
+            
+            <para>
+                The <literal>usage</literal> attribute specifies a <emphasis>cache concurrency strategy</emphasis>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-cache-readonly">
+            <title>Strategy: read only</title>
+
+            <para>
+                If your application needs to read but never modify instances of a persistent class, a 
+                <literal>read-only</literal> cache may be used. This is the simplest and best performing
+                strategy. It's even perfectly safe for use in a cluster.
+            </para>
+
+            <programlisting><![CDATA[<class name="eg.Immutable" mutable="false">
+    <cache usage="read-only"/>
+    ....
+</class>]]></programlisting>
+
+        </sect2>
+
+
+        <sect2 id="performance-cache-readwrite">
+            <title>Strategy: read/write</title>
+
+            <para>
+                If the application needs to update data, a <literal>read-write</literal> cache might be appropriate. 
+                This cache strategy should never be used if serializable transaction isolation level is required. 
+                If the cache is used in a JTA environment, you must specify the property 
+                <literal>hibernate.transaction.manager_lookup_class</literal>, naming a strategy for obtaining the 
+                JTA <literal>TransactionManager</literal>. In other environments, you should ensure that the transaction 
+                is completed when <literal>Session.close()</literal> or <literal>Session.disconnect()</literal> is called. 
+                If you wish to use this strategy in a cluster, you should ensure that the underlying cache implementation 
+                supports locking. The built-in cache providers do <emphasis>not</emphasis>.
+            </para>
+
+            <programlisting><![CDATA[<class name="eg.Cat" .... >
+    <cache usage="read-write"/>
+    ....
+    <set name="kittens" ... >
+        <cache usage="read-write"/>
+        ....
+    </set>
+</class>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-cache-nonstrict">
+            <title>Strategy: nonstrict read/write</title>
+
+            <para>
+                If the application only occasionally needs to update data (ie. if it is extremely unlikely that two 
+                transactions would try to update the same item simultaneously) and strict transaction isolation is
+                not required, a <literal>nonstrict-read-write</literal> cache might be appropriate. If the cache is 
+                used in a JTA environment, you must specify <literal>hibernate.transaction.manager_lookup_class</literal>. 
+                In other environments, you should ensure that the transaction is completed when 
+                <literal>Session.close()</literal> or <literal>Session.disconnect()</literal> is called.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-cache-transactional">
+            <title>Strategy: transactional</title>
+
+            <para>
+                The <literal>transactional</literal> cache strategy provides support for fully transactional cache
+                providers such as JBoss TreeCache. Such a cache may only be used in a JTA environment and you must 
+                specify <literal>hibernate.transaction.manager_lookup_class</literal>. 
+            </para>
+
+        </sect2>
+        
+        <para>
+            None of the cache providers support all of the cache concurrency strategies. The following table shows
+            which providers are compatible with which concurrency strategies.
+        </para>
+
+        <table frame="topbot">
+            <title>Cache Concurrency Strategy Support</title>
+            <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="1*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Cache</entry>
+              <entry>read-only</entry>
+              <entry>nonstrict-read-write</entry>
+              <entry>read-write</entry>
+              <entry>transactional</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>Hashtable (not intended for production use)</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>EHCache</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>OSCache</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>SwarmCache</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>JBoss TreeCache</entry>
+                <entry>yes</entry>
+                <entry></entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+    </sect1>
+
+    <sect1 id="performance-sessioncache" revision="2">
+        <title>Managing the caches</title>
+
+        <para>
+            Whenever you pass an object to <literal>save()</literal>, <literal>update()</literal>
+            or <literal>saveOrUpdate()</literal> and whenever you retrieve an object using 
+            <literal>load()</literal>, <literal>get()</literal>, <literal>list()</literal>, 
+            <literal>iterate()</literal> or <literal>scroll()</literal>, that object is added 
+            to the internal cache of the <literal>Session</literal>. 
+        </para>
+        <para>
+            When <literal>flush()</literal> is subsequently called, the state of that object will 
+            be synchronized with the database. If you do not want this synchronization to occur or 
+            if you are processing a huge number of objects and need to manage memory efficiently, 
+            the <literal>evict()</literal> method may be used to remove the object and its collections 
+            from the first-level cache.
+        </para>
+        
+        <programlisting><![CDATA[ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
+while ( cats.next() ) {
+    Cat cat = (Cat) cats.get(0);
+    doSomethingWithACat(cat);
+    sess.evict(cat);
+}]]></programlisting>
+        
+        <para>
+            The <literal>Session</literal> also provides a <literal>contains()</literal> method to determine 
+            if an instance belongs to the session cache.
+        </para>
+        
+        <para>
+            To completely evict all objects from the session cache, call <literal>Session.clear()</literal>
+        </para>
+        
+        <para>
+            For the second-level cache, there are methods defined on <literal>SessionFactory</literal> for 
+            evicting the cached state of an instance, entire class, collection instance or entire collection 
+            role.
+        </para>
+        
+        <programlisting><![CDATA[sessionFactory.evict(Cat.class, catId); //evict a particular Cat
+sessionFactory.evict(Cat.class);  //evict all Cats
+sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
+sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections]]></programlisting>
+
+        <para>
+            The <literal>CacheMode</literal> controls how a particular session interacts with the second-level
+            cache.
+        </para>
+        
+        <itemizedlist>
+        <listitem>
+        <para>
+            <literal>CacheMode.NORMAL</literal> - read items from and write items to the second-level cache
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.GET</literal> - read items from the second-level cache, but don't write to
+            the second-level cache except when updating data
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.PUT</literal> - write items to the second-level cache, but don't read from
+            the second-level cache
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.REFRESH</literal> - write items to the second-level cache, but don't read from
+            the second-level cache, bypass the effect of <literal>hibernate.cache.use_minimal_puts</literal>, forcing
+            a refresh of the second-level cache for all items read from the database
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            To browse the contents of a second-level or query cache region, use the <literal>Statistics</literal>
+            API:
+        </para>
+        
+        <programlisting><![CDATA[Map cacheEntries = sessionFactory.getStatistics()
+        .getSecondLevelCacheStatistics(regionName)
+        .getEntries();]]></programlisting>
+        
+        <para>
+            You'll need to enable statistics, and, optionally, force Hibernate to keep the cache entries in a
+            more human-understandable format:
+        </para>
+        
+        <programlisting><![CDATA[hibernate.generate_statistics true
+hibernate.cache.use_structured_entries true]]></programlisting>       
+                
+    </sect1>
+    
+    <sect1 id="performance-querycache" revision="1">
+        <title>The Query Cache</title>
+
+        <para>
+            Query result sets may also be cached. This is only useful for queries that are run
+            frequently with the same parameters. To use the query cache you must first enable it:
+        </para>
+
+        <programlisting><![CDATA[hibernate.cache.use_query_cache true]]></programlisting>       
+        
+        <para>
+            This setting causes the creation of two new cache regions - one holding cached query 
+            result sets (<literal>org.hibernate.cache.StandardQueryCache</literal>), the other 
+            holding timestamps of the most recent updates to queryable tables 
+            (<literal>org.hibernate.cache.UpdateTimestampsCache</literal>). Note that the query
+            cache does not cache the state of the actual entities in the result set; it caches 
+            only identifier values and results of value type. So the query cache should always be
+            used in conjunction with the second-level cache.
+        </para>
+        
+        <para>
+            Most queries do not benefit from caching, so by default queries are not cached. To
+            enable caching, call <literal>Query.setCacheable(true)</literal>. This call allows
+            the query to look for existing cache results or add its results to the cache when
+            it is executed.
+        </para>
+        
+        <para>
+            If you require fine-grained control over query cache expiration policies, you may
+            specify a named cache region for a particular query by calling 
+            <literal>Query.setCacheRegion()</literal>.
+        </para>
+        
+        <programlisting><![CDATA[List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
+    .setEntity("blogger", blogger)
+    .setMaxResults(15)
+    .setCacheable(true)
+    .setCacheRegion("frontpages")
+    .list();]]></programlisting>
+
+        <para>
+            If the query should force a refresh of its query cache region, you should call
+            <literal>Query.setCacheMode(CacheMode.REFRESH)</literal>. This is particularly useful 
+            in cases where underlying data may have been updated via a separate process (i.e., 
+            not modified through Hibernate) and allows the application to selectively refresh 
+            particular query result sets. This is a more efficient alternative to eviction of 
+            a query cache region via <literal>SessionFactory.evictQueries()</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="performance-collections">
+        <title>Understanding Collection performance</title>
+
+        <para>
+            We've already spent quite some time talking about collections.
+            In this section we will highlight a couple more issues about
+            how collections behave at runtime.
+        </para>
+
+        <sect2 id="performance-collections-taxonomy">
+            <title>Taxonomy</title>
+
+            <para>Hibernate defines three basic kinds of collections:</para>
+
+            <itemizedlist>
+            <listitem>
+                <para>collections of values</para>
+            </listitem>
+            <listitem>
+                <para>one to many associations</para>
+            </listitem>
+            <listitem>
+                <para>many to many associations</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                This classification distinguishes the various table and foreign key
+                relationships but does not tell us quite everything we need to know
+                about the relational model. To fully understand the relational structure
+                and performance characteristics, we must also consider the structure of
+                the primary key that is used by Hibernate to update or delete collection
+                rows. This suggests the following classification:
+            </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>indexed collections</para>
+            </listitem>
+            <listitem>
+                <para>sets</para>
+            </listitem>
+            <listitem>
+                <para>bags</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                All indexed collections (maps, lists, arrays) have a primary key consisting
+                of the <literal>&lt;key&gt;</literal> and <literal>&lt;index&gt;</literal>
+                columns. In this case collection updates are usually extremely efficient -
+                the primary key may be efficiently indexed and a particular row may be efficiently
+                located when Hibernate tries to update or delete it.
+            </para>
+                        
+            <para>
+                Sets have a primary key consisting of <literal>&lt;key&gt;</literal> and element
+                columns. This may be less efficient for some types of collection element, particularly
+                composite elements or large text or binary fields; the database may not be able to index
+                a complex primary key as efficently.  On the other hand, for one to many or many to many
+                associations, particularly in the case of synthetic identifiers, it is likely to be just
+                as efficient. (Side-note: if you want <literal>SchemaExport</literal> to actually create
+                the primary key of a <literal>&lt;set&gt;</literal> for you, you must declare all columns
+                as <literal>not-null="true"</literal>.)
+            </para>
+
+            <para>
+                <literal>&lt;idbag&gt;</literal> mappings define a surrogate key, so they are
+                always very efficient to update. In fact, they are the best case.
+            </para>
+            
+            <para>
+                Bags are the worst case. Since a bag permits duplicate element values and has no
+                index column, no primary key may be defined. Hibernate has no way of distinguishing
+                between duplicate rows. Hibernate resolves this problem by completely removing
+                (in a single <literal>DELETE</literal>) and recreating the collection whenever it
+                changes. This might be very inefficient.
+            </para>
+
+            <para>
+                Note that for a one-to-many association, the "primary key" may not be the physical
+                primary key of the database table - but even in this case, the above classification
+                is still useful. (It still reflects how Hibernate "locates" individual rows of the
+                collection.)
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-collections-mostefficientupdate">
+            <title>Lists, maps, idbags and sets are the most efficient collections to update</title>
+
+            <para>
+                From the discussion above, it should be clear that indexed collections
+                and (usually) sets allow the most efficient operation in terms of adding,
+                removing and updating elements.
+            </para>
+
+            <para>
+                There is, arguably, one more advantage that indexed collections have over sets for
+                many to many associations or collections of values. Because of the structure of a
+                <literal>Set</literal>, Hibernate doesn't ever <literal>UPDATE</literal> a row when
+                an element is "changed". Changes to a <literal>Set</literal> always work via
+                <literal>INSERT</literal> and <literal>DELETE</literal> (of individual rows). Once
+                again, this consideration does not apply to one to many associations.
+            </para>
+
+            <para>
+                After observing that arrays cannot be lazy, we would conclude that lists, maps and 
+                idbags are the most performant (non-inverse) collection types, with sets not far 
+                behind. Sets are expected to be the most common kind of collection in Hibernate 
+                applications. This is because the "set" semantics are most natural in the relational
+                model.
+            </para>
+
+            <para>
+                However, in well-designed Hibernate domain models, we usually see that most collections
+                are in fact one-to-many associations with <literal>inverse="true"</literal>. For these
+                associations, the update is handled by the many-to-one end of the association, and so
+                considerations of collection update performance simply do not apply.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-collections-mostefficentinverse">
+            <title>Bags and lists are the most efficient inverse collections</title>
+
+            <para>
+                Just before you ditch bags forever, there is a particular case in which bags (and also lists)
+                are much more performant than sets. For a collection with <literal>inverse="true"</literal>
+                (the standard bidirectional one-to-many relationship idiom, for example) we can add elements
+                to a bag or list without needing to initialize (fetch) the bag elements! This is because
+                <literal>Collection.add()</literal> or <literal>Collection.addAll()</literal> must always
+                return true for a bag or <literal>List</literal> (unlike a <literal>Set</literal>). This can
+                make the following common code much faster.
+            </para>
+
+            <programlisting><![CDATA[Parent p = (Parent) sess.load(Parent.class, id);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c);  //no need to fetch the collection!
+sess.flush();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-collections-oneshotdelete">
+            <title>One shot delete</title>
+
+            <para>
+                Occasionally, deleting collection elements one by one can be extremely inefficient. Hibernate
+                isn't completely stupid, so it knows not to do that in the case of an newly-empty collection
+                (if you called <literal>list.clear()</literal>, for example). In this case, Hibernate will
+                issue a single <literal>DELETE</literal> and we are done!
+            </para>
+
+            <para>
+                Suppose we add a single element to a collection of size twenty and then remove two elements.
+                Hibernate will issue one <literal>INSERT</literal> statement and two <literal>DELETE</literal>
+                statements (unless the collection is a bag). This is certainly desirable.
+            </para>
+
+            <para>
+                However, suppose that we remove eighteen elements, leaving two and then add thee new elements.
+                There are two possible ways to proceed
+            </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>delete eighteen rows one by one and then insert three rows</para>
+            </listitem>
+            <listitem>
+                <para>remove the whole collection (in one SQL <literal>DELETE</literal>) and insert
+                all five current elements (one by one)</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                Hibernate isn't smart enough to know that the second option is probably quicker in this case.
+                (And it would probably be undesirable for Hibernate to be that smart; such behaviour might
+                confuse database triggers, etc.)
+            </para>
+
+            <para>
+                Fortunately, you can force this behaviour (ie. the second strategy) at any time by discarding
+                (ie. dereferencing) the original collection and returning a newly instantiated collection with
+                all the current elements. This can be very useful and powerful from time to time.
+            </para>
+            
+            <para>
+                Of course, one-shot-delete does not apply to collections mapped <literal>inverse="true"</literal>.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="performance-monitoring" revision="1">
+        <title>Monitoring performance</title>
+
+        <para>
+            Optimization is not much use without monitoring and access to performance numbers.
+            Hibernate provides a full range of figures about its internal operations.
+            Statistics in Hibernate are available per <literal>SessionFactory</literal>.
+        </para>
+
+        <sect2 id="performance-monitoring-sf" revision="2">
+            <title>Monitoring a SessionFactory</title>
+
+            <para>
+                You can access <literal>SessionFactory</literal> metrics in two ways.
+                Your first option is to call <literal>sessionFactory.getStatistics()</literal> and
+                read or display the <literal>Statistics</literal> yourself.
+            </para>
+
+            <para>
+                Hibernate can also use JMX to publish metrics if you enable the
+                <literal>StatisticsService</literal> MBean. You may enable a single MBean for all your
+                <literal>SessionFactory</literal> or one per factory. See the following code for
+                minimalistic configuration examples:
+            </para>
+
+            <programlisting><![CDATA[// MBean service registration for a specific SessionFactory
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "myFinancialApp");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
+server.registerMBean(stats, on); // Register the Mbean on the server]]></programlisting>
+
+
+<programlisting><![CDATA[// MBean service registration for all SessionFactory's
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "all");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+server.registerMBean(stats, on); // Register the MBean on the server]]></programlisting>
+
+            <para>
+                TODO: This doesn't make sense: In the first case, we retrieve and use the MBean directly. In the second one, we must give
+                the JNDI name in which the session factory is held before using it. Use
+                <literal>hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")</literal>
+            </para>
+            <para>
+                You can (de)activate the monitoring for a <literal>SessionFactory</literal>
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        at configuration time, set <literal>hibernate.generate_statistics</literal> to <literal>false</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        at runtime: <literal>sf.getStatistics().setStatisticsEnabled(true)</literal>
+                        or <literal>hibernateStatsBean.setStatisticsEnabled(true)</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Statistics can be reset programatically using the <literal>clear()</literal> method.
+                A summary can be sent to a logger (info level) using the <literal>logSummary()</literal>
+                method.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-monitoring-metrics" revision="1">
+            <title>Metrics</title>
+
+            <para>
+                Hibernate provides a number of metrics, from very basic to the specialized information
+                only relevant in certain scenarios. All available counters are described in the
+                <literal>Statistics</literal> interface API, in three categories:
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        Metrics related to the general <literal>Session</literal> usage, such as
+                        number of open sessions, retrieved JDBC connections, etc.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Metrics related to he entities, collections, queries, and caches as a
+                        whole (aka global metrics),
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Detailed metrics related to a particular entity, collection, query or
+                        cache region.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                For exampl,e you can check the cache hit, miss, and put ratio of entities, collections
+                and queries, and the average time a query needs. Beware that the number of milliseconds
+                is subject to approximation in Java. Hibernate is tied to the JVM precision, on some
+                platforms this might even only be accurate to 10 seconds.
+            </para>
+
+            <para>
+                Simple getters are used to access the global metrics (i.e. not tied to a particular entity,
+                collection, cache region, etc.). You can access the metrics of a particular entity, collection
+                or cache region through its name, and through its HQL or SQL representation for queries. Please
+                refer to the <literal>Statistics</literal>, <literal>EntityStatistics</literal>,
+                <literal>CollectionStatistics</literal>, <literal>SecondLevelCacheStatistics</literal>,
+                and <literal>QueryStatistics</literal> API Javadoc for more information. The following
+                code shows a simple example:
+            </para>
+
+            <programlisting><![CDATA[Statistics stats = HibernateUtil.sessionFactory.getStatistics();
+
+double queryCacheHitCount  = stats.getQueryCacheHitCount();
+double queryCacheMissCount = stats.getQueryCacheMissCount();
+double queryCacheHitRatio =
+  queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
+
+log.info("Query Hit ratio:" + queryCacheHitRatio);
+
+EntityStatistics entityStats =
+  stats.getEntityStatistics( Cat.class.getName() );
+long changes =
+        entityStats.getInsertCount()
+        + entityStats.getUpdateCount()
+        + entityStats.getDeleteCount();
+log.info(Cat.class.getName() + " changed " + changes + "times"  );]]></programlisting>
+
+            <para>
+                To work on all entities, collections, queries and region caches, you can retrieve
+                the list of names of entities, collections, queries and region caches with the
+                following methods: <literal>getQueries()</literal>, <literal>getEntityNames()</literal>,
+                <literal>getCollectionRoleNames()</literal>, and
+                <literal>getSecondLevelCacheRegionNames()</literal>.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/persistent_classes.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/persistent_classes.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/persistent_classes.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,531 @@
+<chapter id="persistent-classes" revision="2">
+    <title>Persistent Classes</title>
+
+    <para>
+        Persistent classes are classes in an application that implement the entities
+        of the business problem (e.g. Customer and Order in an E-commerce application).
+        Not all instances of a persistent class are considered to be in the persistent 
+        state - an instance may instead be transient or detached.
+    </para>
+
+    <para>
+        Hibernate works best if these classes follow some simple rules, also known
+        as the Plain Old Java Object (POJO) programming model. However, none of these
+        rules are hard requirements. Indeed, Hibernate3 assumes very little about
+        the nature of your persistent objects. You may express a domain model in other 
+        ways: using trees of <literal>Map</literal> instances, for example.
+    </para>
+
+    <sect1 id="persistent-classes-pojo">
+        <title>A simple POJO example</title>
+
+        <para>
+            Most Java applications require a persistent class representing felines.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+public class Cat {
+    private Long id; // identifier
+
+    private Date birthdate;
+    private Color color;
+    private char sex;
+    private float weight;
+    private int litterId;
+
+    private Cat mother;
+    private Set kittens = new HashSet();
+
+    private void setId(Long id) {
+        this.id=id;
+    }
+    public Long getId() {
+        return id;
+    }
+
+    void setBirthdate(Date date) {
+        birthdate = date;
+    }
+    public Date getBirthdate() {
+        return birthdate;
+    }
+
+    void setWeight(float weight) {
+        this.weight = weight;
+    }
+    public float getWeight() {
+        return weight;
+    }
+
+    public Color getColor() {
+        return color;
+    }
+    void setColor(Color color) {
+        this.color = color;
+    }
+
+    void setSex(char sex) {
+        this.sex=sex;
+    }
+    public char getSex() {
+        return sex;
+    }
+
+    void setLitterId(int id) {
+        this.litterId = id;
+    }
+    public int getLitterId() {
+        return litterId;
+    }
+
+    void setMother(Cat mother) {
+        this.mother = mother;
+    }
+    public Cat getMother() {
+        return mother;
+    }
+    void setKittens(Set kittens) {
+        this.kittens = kittens;
+    }
+    public Set getKittens() {
+        return kittens;
+    }
+    
+    // addKitten not needed by Hibernate
+    public void addKitten(Cat kitten) {
+    	kitten.setMother(this);
+	kitten.setLitterId( kittens.size() ); 
+        kittens.add(kitten);
+    }
+}]]></programlisting>
+
+        <para>
+            There are four main rules to follow here:
+        </para>
+
+
+        <sect2 id="persistent-classes-pojo-constructor" revision="1">
+            <title>Implement a no-argument constructor</title>
+
+            <para>
+                <literal>Cat</literal> has a no-argument constructor. All persistent classes must 
+                have a default constructor (which may be non-public) so that Hibernate can instantiate 
+                them using <literal>Constructor.newInstance()</literal>. We strongly recommend having a 
+                default constructor with at least <emphasis>package</emphasis> visibility for runtime proxy 
+                generation in Hibernate.
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-identifier" revision="2">
+            <title>Provide an identifier property (optional)</title>
+
+            <para>
+                <literal>Cat</literal> has a property called <literal>id</literal>. This property 
+                maps to the primary key column of a database table. The property might have been called
+                anything, and its type might have been any primitive type, any primitive "wrapper" 
+                type, <literal>java.lang.String</literal> or <literal>java.util.Date</literal>. (If 
+                your legacy database table has composite keys, you can even use a user-defined class 
+                with properties of these types - see the section on composite identifiers later.)
+            </para>
+
+            <para>
+                The identifier property is strictly optional. You can leave them off and let Hibernate 
+                keep track of object identifiers internally. We do not recommend this, however.
+            </para>
+
+            <para>
+                In fact, some functionality is available only to classes which declare an
+                identifier property:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        Transitive reattachment for detached objects (cascade update or cascade
+                        merge) - see <xref linkend="objectstate-transitive"/>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session.saveOrUpdate()</literal>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session.merge()</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                We recommend you declare consistently-named identifier properties on persistent
+                classes. We further recommend that you use a nullable (ie. non-primitive) type.
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-final">
+            <title>Prefer non-final classes (optional)</title>
+            <para>
+                A central feature of Hibernate, <emphasis>proxies</emphasis>, depends upon the
+                persistent class being either non-final, or the implementation of an interface
+                that declares all public methods.
+            </para>
+            <para>
+                You can persist <literal>final</literal> classes that do not implement an interface
+                with Hibernate, but you won't be able to use proxies for lazy association fetching -
+                which will limit your options for performance tuning.
+            </para>
+            <para>
+                You should also avoid declaring <literal>public final</literal> methods on the 
+                non-final classes. If you want to use a class with a <literal>public final</literal> 
+                method, you must explicitly disable proxying by setting <literal>lazy="false"</literal>.
+            </para>
+        </sect2>
+        
+        <sect2 id="persistent-classes-pojo-accessors" revision="2">
+            <title>Declare accessors and mutators for persistent fields (optional)</title>
+
+            <para>
+                <literal>Cat</literal> declares accessor methods for all its persistent fields.
+                Many other ORM tools directly persist instance variables. We believe it is 
+                better to provide an indirection between the relational schema and internal
+                data structures of the class. By default, Hibernate persists JavaBeans style 
+                properties, and recognizes method names of the form <literal>getFoo</literal>, 
+                <literal>isFoo</literal> and <literal>setFoo</literal>. You may switch to direct 
+                field access for particular properties, if needed.
+            </para>
+
+            <para>
+                Properties need <emphasis>not</emphasis> be declared public - Hibernate can
+                persist a property with a default, <literal>protected</literal> or 
+                <literal>private</literal> get / set pair.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-inheritance">
+        <title>Implementing inheritance</title>
+
+        <para>
+            A subclass must also observe the first and second rules. It inherits its
+            identifier property from the superclass, <literal>Cat</literal>.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+public class DomesticCat extends Cat {
+        private String name;
+
+        public String getName() {
+                return name;
+        }
+        protected void setName(String name) {
+                this.name=name;
+        }
+}]]></programlisting>
+    </sect1>
+
+    <sect1 id="persistent-classes-equalshashcode" revision="1">
+        <title>Implementing <literal>equals()</literal> and <literal>hashCode()</literal></title>
+
+        <para>
+            You have to override the <literal>equals()</literal> and <literal>hashCode()</literal>
+            methods if you 
+        </para>
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    intend to put instances of persistent classes in a <literal>Set</literal>
+                    (the recommended way to represent many-valued associations) 
+                    <emphasis>and</emphasis>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    intend to use reattachment of detached instances
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Hibernate guarantees equivalence of persistent identity (database row) and Java identity
+            only inside a particular session scope. So as soon as we mix instances retrieved in
+            different sessions, we must implement <literal>equals()</literal> and
+            <literal>hashCode()</literal> if we wish to have meaningful semantics for
+            <literal>Set</literal>s.
+        </para>
+
+        <para>
+            The most obvious way is to implement <literal>equals()</literal>/<literal>hashCode()</literal>
+            by comparing the identifier value of both objects. If the value is the same, both must
+            be the same database row, they are therefore equal (if both are added to a <literal>Set</literal>,
+            we will only have one element in the <literal>Set</literal>). Unfortunately, we can't use that
+            approach with generated identifiers! Hibernate will only assign identifier values to objects 
+            that are persistent, a newly created instance will not have any identifier value! Furthermore,
+            if an instance is unsaved and currently in a <literal>Set</literal>, saving it will assign
+            an identifier value to the object. If <literal>equals()</literal> and <literal>hashCode()</literal>
+            are based on the identifier value, the hash code would change, breaking the contract of the
+            <literal>Set</literal>. See the Hibernate website for a full discussion of this problem. Note
+            that this is not a Hibernate issue, but normal Java semantics of object identity and equality.
+        </para>
+
+        <para>
+            We recommend  implementing <literal>equals()</literal> and <literal>hashCode()</literal>
+            using <emphasis>Business key equality</emphasis>. Business key equality means that the
+            <literal>equals()</literal> method compares only the properties that form the business
+            key, a key that would identify our instance in the real world (a
+            <emphasis>natural</emphasis> candidate key):
+        </para>
+
+        <programlisting><![CDATA[public class Cat {
+
+    ...
+    public boolean equals(Object other) {
+        if (this == other) return true;
+        if ( !(other instanceof Cat) ) return false;
+
+        final Cat cat = (Cat) other;
+
+        if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
+        if ( !cat.getMother().equals( getMother() ) ) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result;
+        result = getMother().hashCode();
+        result = 29 * result + getLitterId();
+        return result;
+    }
+
+}]]></programlisting>
+
+        <para>
+            Note that a business key does not have to be as solid as a database
+            primary key candidate (see <xref linkend="transactions-basics-identity"/>).
+            Immutable or unique properties are usually good
+            candidates for a business key.
+        </para>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-dynamicmodels">
+        <title>Dynamic models</title>
+
+        <para>
+            <emphasis>Note that the following features are currently considered
+            experimental and may change in the near future.</emphasis>
+        </para>
+
+        <para>
+            Persistent entities don't necessarily have to be represented as POJO classes
+            or as JavaBean objects at runtime. Hibernate also supports dynamic models
+            (using <literal>Map</literal>s of <literal>Map</literal>s at runtime) and the
+            representation of entities as DOM4J trees. With this approach, you don't
+            write persistent classes, only mapping files.
+        </para>
+
+        <para>
+            By default, Hibernate works in normal POJO mode. You may set a default entity
+            representation mode for a particular <literal>SessionFactory</literal> using the
+            <literal>default_entity_mode</literal> configuration option (see
+            <xref linkend="configuration-optional-properties"/>.
+        </para>
+
+        <para>
+            The following examples demonstrates the representation using <literal>Map</literal>s.
+            First, in the mapping file, an <literal>entity-name</literal> has to be declared
+            instead of (or in addition to) a class name:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class entity-name="Customer">
+
+        <id name="id"
+            type="long"
+            column="ID">
+            <generator class="sequence"/>
+        </id>
+
+        <property name="name"
+            column="NAME"
+            type="string"/>
+
+        <property name="address"
+            column="ADDRESS"
+            type="string"/>
+
+        <many-to-one name="organization"
+            column="ORGANIZATION_ID"
+            class="Organization"/>
+
+        <bag name="orders"
+            inverse="true"
+            lazy="false"
+            cascade="all">
+            <key column="CUSTOMER_ID"/>
+            <one-to-many class="Order"/>
+        </bag>
+
+    </class>
+    
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+
+            Note that even though associations are declared using target class names,
+            the target type of an associations may also be a dynamic entity instead
+            of a POJO.
+        </para>
+
+        <para>
+            After setting the default entity mode to <literal>dynamic-map</literal>
+            for the <literal>SessionFactory</literal>, we can at runtime work with
+            <literal>Map</literal>s of <literal>Map</literal>s:
+        </para>
+
+        <programlisting><![CDATA[Session s = openSession();
+Transaction tx = s.beginTransaction();
+Session s = openSession();
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+
+// Create an organization
+Map foobar = new HashMap();
+foobar.put("name", "Foobar Inc.");
+
+// Link both
+david.put("organization", foobar);
+
+// Save both
+s.save("Customer", david);
+s.save("Organization", foobar);
+
+tx.commit();
+s.close();]]></programlisting>
+
+        <para>
+            The advantages of a dynamic mapping are quick turnaround time for prototyping
+            without the need for entity class implementation. However, you lose compile-time
+            type checking and will very likely deal with many exceptions at runtime. Thanks
+            to the Hibernate mapping, the database schema can easily be normalized and sound,
+            allowing to add a proper domain model implementation on top later on.
+        </para>
+
+        <para>
+            Entity representation modes can also be set on a per <literal>Session</literal>
+            basis:
+        </para>
+
+        <programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+dynamicSession.save("Customer", david);
+...
+dynamicSession.flush();
+dynamicSession.close()
+...
+// Continue on pojoSession
+]]></programlisting>
+
+
+        <para>
+            Please note that the call to <literal>getSession()</literal> using an
+            <literal>EntityMode</literal> is on the <literal>Session</literal> API, not the
+            <literal>SessionFactory</literal>. That way, the new <literal>Session</literal>
+            shares the underlying JDBC connection, transaction, and other context
+            information. This means you don't have tocall <literal>flush()</literal>
+            and <literal>close()</literal> on the secondary <literal>Session</literal>, and
+            also leave the transaction and connection handling to the primary unit of work.
+        </para>
+
+        <para>
+            More information about the XML representation capabilities can be found
+            in <xref linkend="xml"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-tuplizers" revision="1">
+        <title>Tuplizers</title>
+
+        <para>
+            <literal>org.hibernate.tuple.Tuplizer</literal>, and its sub-interfaces, are responsible
+            for managing a particular representation of a piece of data, given that representation's
+            <literal>org.hibernate.EntityMode</literal>.  If a given piece of data is thought of as
+            a data structure, then a tuplizer is the thing which knows how to create such a data structure
+            and how to extract values from and inject values into such a data structure.  For example,
+            for the POJO entity mode, the correpsonding tuplizer knows how create the POJO through its
+            constructor and how to access the POJO properties using the defined property accessors.
+            There are two high-level types of Tuplizers, represented by the
+            <literal>org.hibernate.tuple.entity.EntityTuplizer</literal> and <literal>org.hibernate.tuple.component.ComponentTuplizer</literal>
+            interfaces.  <literal>EntityTuplizer</literal>s are responsible for managing the above mentioned
+            contracts in regards to entities, while <literal>ComponentTuplizer</literal>s do the same for
+            components.
+        </para>
+
+        <para>
+            Users may also plug in their own tuplizers.  Perhaps you require that a <literal>java.util.Map</literal>
+            implementation other than <literal>java.util.HashMap</literal> be used while in the
+            dynamic-map entity-mode; or perhaps you need to define a different proxy generation strategy
+            than the one used by default.  Both would be achieved by defining a custom tuplizer
+            implementation.  Tuplizers definitions are attached to the entity or component mapping they
+            are meant to manage.  Going back to the example of our customer entity:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+    <class entity-name="Customer">
+        <!--
+            Override the dynamic-map entity-mode
+            tuplizer for the customer entity
+        -->
+        <tuplizer entity-mode="dynamic-map"
+                class="CustomMapTuplizerImpl"/>
+
+        <id name="id" type="long" column="ID">
+            <generator class="sequence"/>
+        </id>
+
+        <!-- other properties -->
+        ...
+    </class>
+</hibernate-mapping>
+
+
+public class CustomMapTuplizerImpl
+        extends org.hibernate.tuple.entity.DynamicMapEntityTuplizer {
+    // override the buildInstantiator() method to plug in our custom map...
+    protected final Instantiator buildInstantiator(
+            org.hibernate.mapping.PersistentClass mappingInfo) {
+        return new CustomMapInstantiator( mappingInfo );
+    }
+
+    private static final class CustomMapInstantiator
+            extends org.hibernate.tuple.DynamicMapInstantitor {
+        // override the generateMap() method to return our custom map...
+	    protected final Map generateMap() {
+		    return new CustomMap();
+	    }
+    }
+}]]></programlisting>
+
+
+    </sect1>
+
+    <para>
+        TODO: Document user-extension framework in the property and proxy packages
+    </para>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/query_criteria.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/query_criteria.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/query_criteria.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,436 @@
+<chapter id="querycriteria">
+    <title>Criteria Queries</title>
+
+    <para>
+        Hibernate features an intuitive, extensible criteria query API.
+    </para>
+    
+    <sect1 id="querycriteria-creating">
+        <title>Creating a <literal>Criteria</literal> instance</title>
+
+        <para>
+            The interface <literal>org.hibernate.Criteria</literal> represents a query against
+            a particular persistent class. The <literal>Session</literal> is a factory for
+            <literal>Criteria</literal> instances.
+        </para>
+
+        <programlisting><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
+crit.setMaxResults(50);
+List cats = crit.list();]]></programlisting>
+
+    </sect1>
+     
+    <sect1 id="querycriteria-narrowing">
+        <title>Narrowing the result set</title>
+
+        <para>
+            An individual query criterion is an instance of the interface
+            <literal>org.hibernate.criterion.Criterion</literal>. The class
+            <literal>org.hibernate.criterion.Restrictions</literal> defines
+            factory methods for obtaining certain built-in
+            <literal>Criterion</literal> types.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .add( Restrictions.between("weight", minWeight, maxWeight) )
+    .list();]]></programlisting>
+    
+        <para>
+            Restrictions may be grouped logically.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .add( Restrictions.or(
+        Restrictions.eq( "age", new Integer(0) ),
+        Restrictions.isNull("age")
+    ) )
+    .list();]]></programlisting>
+    
+       <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
+    .add( Restrictions.disjunction()
+        .add( Restrictions.isNull("age") )
+        .add( Restrictions.eq("age", new Integer(0) ) )
+        .add( Restrictions.eq("age", new Integer(1) ) )
+        .add( Restrictions.eq("age", new Integer(2) ) )
+    ) )
+    .list();]]></programlisting>
+    
+        <para>
+            There are quite a range of built-in criterion types (<literal>Restrictions</literal>
+            subclasses), but one that is especially useful lets you specify SQL directly.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.sqlRestriction("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
+    .list();]]></programlisting>
+    
+        <para>
+            The <literal>{alias}</literal> placeholder with be replaced by the row alias
+            of the queried entity.
+        </para>
+        
+        <para>
+            An alternative approach to obtaining a criterion is to get it from a 
+            <literal>Property</literal> instance. You can create a <literal>Property</literal>
+            by calling <literal>Property.forName()</literal>.
+        </para>
+    
+        <programlisting><![CDATA[
+Property age = Property.forName("age");
+List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.disjunction()
+        .add( age.isNull() )
+        .add( age.eq( new Integer(0) ) )
+        .add( age.eq( new Integer(1) ) )
+        .add( age.eq( new Integer(2) ) )
+    ) )
+    .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
+    .list();]]></programlisting>
+    
+   </sect1>
+     
+    <sect1 id="querycriteria-ordering">
+        <title>Ordering the results</title>
+
+        <para>
+            You may order the results using <literal>org.hibernate.criterion.Order</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "F%")
+    .addOrder( Order.asc("name") )
+    .addOrder( Order.desc("age") )
+    .setMaxResults(50)
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Property.forName("name").like("F%") )
+    .addOrder( Property.forName("name").asc() )
+    .addOrder( Property.forName("age").desc() )
+    .setMaxResults(50)
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-associations" revision="2">
+        <title>Associations</title>
+
+        <para>
+            You may easily specify constraints upon related entities by navigating
+            associations using <literal>createCriteria()</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "F%") )
+    .createCriteria("kittens")
+        .add( Restrictions.like("name", "F%") )
+    .list();]]></programlisting>
+
+        <para>
+            note that the second <literal>createCriteria()</literal> returns a new
+            instance of <literal>Criteria</literal>, which refers to the elements of
+            the <literal>kittens</literal> collection.
+        </para>
+
+        <para>
+            The following, alternate form is useful in certain circumstances.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .createAlias("kittens", "kt")
+    .createAlias("mate", "mt")
+    .add( Restrictions.eqProperty("kt.name", "mt.name") )
+    .list();]]></programlisting>
+
+        <para>
+            (<literal>createAlias()</literal> does not create a new instance of
+            <literal>Criteria</literal>.)
+        </para>
+
+        <para>
+            Note that the kittens collections held by the <literal>Cat</literal> instances
+            returned by the previous two queries are <emphasis>not</emphasis> pre-filtered
+            by the criteria! If you wish to retrieve just the kittens that match the
+            criteria, you must use a <literal>ResultTransformer</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .createCriteria("kittens", "kt")
+        .add( Restrictions.eq("name", "F%") )
+    .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+    .list();
+Iterator iter = cats.iterator();
+while ( iter.hasNext() ) {
+    Map map = (Map) iter.next();
+    Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
+    Cat kitten = (Cat) map.get("kt");
+}]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="querycriteria-dynamicfetching" revision="1">
+        <title>Dynamic association fetching</title>
+
+        <para>
+            You may specify association fetching semantics at runtime using
+            <literal>setFetchMode()</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .setFetchMode("mate", FetchMode.EAGER)
+    .setFetchMode("kittens", FetchMode.EAGER)
+    .list();]]></programlisting>
+    
+        <para>
+            This query will fetch both <literal>mate</literal> and <literal>kittens</literal>
+            by outer join. See <xref linkend="performance-fetching"/> for more information.
+        </para>
+    
+    </sect1>
+     
+    <sect1 id="querycriteria-examples">
+        <title>Example queries</title>
+
+        <para>
+            The class <literal>org.hibernate.criterion.Example</literal> allows
+            you to construct a query criterion from a given instance.
+        </para>
+
+        <programlisting><![CDATA[Cat cat = new Cat();
+cat.setSex('F');
+cat.setColor(Color.BLACK);
+List results = session.createCriteria(Cat.class)
+    .add( Example.create(cat) )
+    .list();]]></programlisting>
+    
+        <para>
+           Version properties, identifiers and associations are ignored. By default,
+           null valued properties are excluded.
+        </para>
+
+        <para>
+           You can adjust how the <literal>Example</literal> is applied.
+        </para>
+
+        <programlisting><![CDATA[Example example = Example.create(cat)
+    .excludeZeroes()           //exclude zero valued properties
+    .excludeProperty("color")  //exclude the property named "color"
+    .ignoreCase()              //perform case insensitive string comparisons
+    .enableLike();             //use like for string comparisons
+List results = session.createCriteria(Cat.class)
+    .add(example)
+    .list();]]></programlisting>
+    
+        <para>
+            You can even use examples to place criteria upon associated objects.
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .add( Example.create(cat) )
+    .createCriteria("mate")
+        .add( Example.create( cat.getMate() ) )
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-projection">
+        <title>Projections, aggregation and grouping</title>
+        <para>
+            The class <literal>org.hibernate.criterion.Projections</literal> is a
+            factory for <literal>Projection</literal> instances. We apply a
+            projection to a query by calling <literal>setProjection()</literal>.
+        </para>
+        
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.rowCount() )
+    .add( Restrictions.eq("color", Color.BLACK) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount() )
+        .add( Projections.avg("weight") )
+        .add( Projections.max("weight") )
+        .add( Projections.groupProperty("color") )
+    )
+    .list();]]></programlisting>
+    
+        <para>
+            There is no explicit "group by" necessary in a criteria query. Certain
+            projection types are defined to be <emphasis>grouping projections</emphasis>,
+            which also appear in the SQL <literal>group by</literal> clause.
+        </para>
+    
+        <para>
+            An alias may optionally be assigned to a projection, so that the projected value
+            may be referred to in restrictions or orderings. Here are two different ways to
+            do this:
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
+    .addOrder( Order.asc("colr") )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.groupProperty("color").as("colr") )
+    .addOrder( Order.asc("colr") )
+    .list();]]></programlisting>
+    
+        <para>
+            The <literal>alias()</literal> and <literal>as()</literal> methods simply wrap a
+            projection instance in another, aliased, instance of <literal>Projection</literal>.
+            As a shortcut, you can assign an alias when you add the projection to a 
+            projection list:
+        </para>
+
+       <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount(), "catCountByColor" )
+        .add( Projections.avg("weight"), "avgWeight" )
+        .add( Projections.max("weight"), "maxWeight" )
+        .add( Projections.groupProperty("color"), "color" )
+    )
+    .addOrder( Order.desc("catCountByColor") )
+    .addOrder( Order.desc("avgWeight") )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Domestic.class, "cat")
+    .createAlias("kittens", "kit")
+    .setProjection( Projections.projectionList()
+        .add( Projections.property("cat.name"), "catName" )
+        .add( Projections.property("kit.name"), "kitName" )
+    )
+    .addOrder( Order.asc("catName") )
+    .addOrder( Order.asc("kitName") )
+    .list();]]></programlisting>
+    
+        <para>
+            You can also use <literal>Property.forName()</literal> to express projections:
+        </para>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Property.forName("name") )
+    .add( Property.forName("color").eq(Color.BLACK) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount().as("catCountByColor") )
+        .add( Property.forName("weight").avg().as("avgWeight") )
+        .add( Property.forName("weight").max().as("maxWeight") )
+        .add( Property.forName("color").group().as("color" )
+    )
+    .addOrder( Order.desc("catCountByColor") )
+    .addOrder( Order.desc("avgWeight") )
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-detachedqueries">
+        <title>Detached queries and subqueries</title>
+        <para>
+            The <literal>DetachedCriteria</literal> class lets you create a query outside the scope 
+            of a session, and then later execute it using some arbitrary <literal>Session</literal>.
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
+    .add( Property.forName("sex").eq('F') );
+    
+Session session = ....;
+Transaction txn = session.beginTransaction();
+List results = query.getExecutableCriteria(session).setMaxResults(100).list();
+txn.commit();
+session.close();]]></programlisting>
+
+        <para>
+            A <literal>DetachedCriteria</literal> may also be used to express a subquery. Criterion
+            instances involving subqueries may be obtained via <literal>Subqueries</literal> or
+            <literal>Property</literal>.            
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
+    .setProjection( Property.forName("weight").avg() );
+session.createCriteria(Cat.class)
+    .add( Property.forName("weight).gt(avgWeight) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
+    .setProjection( Property.forName("weight") );
+session.createCriteria(Cat.class)
+    .add( Subqueries.geAll("weight", weights) )
+    .list();]]></programlisting>
+    
+        <para>
+            Even correlated subqueries are possible:
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
+    .setProjection( Property.forName("weight").avg() )
+    .add( Property.forName("cat2.sex").eqProperty("cat.sex") );
+session.createCriteria(Cat.class, "cat")
+    .add( Property.forName("weight).gt(avgWeightForSex) )
+    .list();]]></programlisting>
+
+    </sect1>
+
+        <!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer allow returning arbitrary 
+                  user objects - similar to setResultClass in JDO2. General use of ResultTransformer 
+                  could also be explained. -->
+               
+    <sect1 id="query-criteria-naturalid">
+        <title>Queries by natural identifier</title>
+        
+        <para>
+            For most queries, including criteria queries, the query cache is not very efficient,
+            because query cache invalidation occurs too frequently. However, there is one special
+            kind of query where we can optimize the cache invalidation algorithm: lookups by a 
+            constant natural key. In some applications, this kind of query occurs frequently.
+            The criteria API provides special provision for this use case.
+        </para>
+        
+        <para>
+            First, you should map the natural key of your entity using 
+            <literal>&lt;natural-id&gt;</literal>, and enable use of the second-level cache.
+        </para>
+
+        <programlisting><![CDATA[<class name="User">
+    <cache usage="read-write"/>
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <natural-id>
+        <property name="name"/>
+        <property name="org"/>
+    </natural-id>
+    <property name="password"/>
+</class>]]></programlisting>
+    
+        <para>
+            Note that this functionality is not intended for use with entities with 
+            <emphasis>mutable</emphasis> natural keys.
+        </para>
+        
+        <para>
+            Next, enable the Hibernate query cache.
+        </para>
+        
+        <para>
+            Now, <literal>Restrictions.naturalId()</literal> allows us to make use of
+            the more efficient cache algorithm.
+        </para>
+       
+        <programlisting><![CDATA[session.createCriteria(User.class)
+    .add( Restrictions.naturalId()
+        .set("name", "gavin")
+        .set("org", "hb") 
+    ).setCacheable(true)
+    .uniqueResult();]]></programlisting>
+            
+    </sect1>
+    
+</chapter>

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/query_hql.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/query_hql.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/query_hql.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1234 @@
+<chapter id="queryhql" revision="1">
+    <title>HQL: The Hibernate Query Language</title>
+
+    <para>
+        Hibernate is equipped with an extremely powerful query language that (quite intentionally)
+        looks very much like SQL. But don't be fooled by the syntax; HQL is fully object-oriented,
+        understanding notions like inheritence, polymorphism and association.
+    </para>
+
+    <sect1 id="queryhql-casesensitivity">
+        <title>Case Sensitivity</title>
+
+        <para>
+            Queries are case-insensitive, except for names of Java classes and properties.
+            So <literal>SeLeCT</literal> is the same as
+            <literal>sELEct</literal> is the same as
+            <literal>SELECT</literal> but
+            <literal>org.hibernate.eg.FOO</literal> is not
+            <literal>org.hibernate.eg.Foo</literal> and
+            <literal>foo.barSet</literal> is not
+            <literal>foo.BARSET</literal>.
+        </para>
+
+        <para>
+            This manual uses lowercase HQL keywords. Some users find queries with uppercase keywords
+            more readable, but we find this convention ugly when embedded in Java code.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-from">
+        <title>The from clause</title>
+
+        <para>
+            The simplest possible Hibernate query is of the form:
+        </para>
+
+        <programlisting><![CDATA[from eg.Cat]]></programlisting>
+
+        <para>
+            which simply returns all instances of the class <literal>eg.Cat</literal>.
+            We don't usually need to qualify the class name, since <literal>auto-import</literal>
+            is the default. So we almost always just write:
+        </para>
+
+        <programlisting><![CDATA[from Cat]]></programlisting>
+
+        <para>
+            Most of the time, you will need to assign an <emphasis>alias</emphasis>, since
+            you will want to refer to the <literal>Cat</literal> in other parts of the
+            query.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+        <para>
+            This query assigns the alias <literal>cat</literal> to <literal>Cat</literal>
+            instances, so we could use that alias later in the query. The <literal>as</literal>
+            keyword is optional; we could also write:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat]]></programlisting>
+
+        <para>
+            Multiple classes may appear, resulting in a cartesian product or "cross" join.
+        </para>
+
+        <programlisting><![CDATA[from Formula, Parameter]]></programlisting>
+        <programlisting><![CDATA[from Formula as form, Parameter as param]]></programlisting>
+
+        <para>
+            It is considered good practice to name query aliases using an initial lowercase,
+            consistent with Java naming standards for local variables
+            (eg. <literal>domesticCat</literal>).
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-joins" revision="2">
+        <title>Associations and joins</title>
+
+        <para>
+            We may also assign aliases to associated entities, or even to elements of a
+            collection of values, using a <literal>join</literal>.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat
+    inner join cat.mate as mate
+    left outer join cat.kittens as kitten]]></programlisting>
+
+        <programlisting><![CDATA[from Cat as cat left join cat.mate.kittens as kittens]]></programlisting>
+
+        <programlisting><![CDATA[from Formula form full join form.parameter param]]></programlisting>
+
+        <para>
+            The supported join types are borrowed from ANSI SQL
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>inner join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>left outer join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>right outer join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>full join</literal> (not usually useful)
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            The <literal>inner join</literal>, <literal>left outer join</literal> and
+            <literal>right outer join</literal> constructs may be abbreviated.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat
+    join cat.mate as mate
+    left join cat.kittens as kitten]]></programlisting>
+
+        <para>
+            You may supply extra join conditions using the HQL <literal>with</literal>
+            keyword.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat
+    left join cat.kittens as kitten
+        with kitten.bodyWeight > 10.0]]></programlisting>
+
+        <para>
+            In addition, a "fetch" join allows associations or collections of values to be
+            initialized along with their parent objects, using a single select. This is particularly
+            useful in the case of a collection. It effectively overrides the outer join and
+            lazy declarations of the mapping file for associations and collections. See
+            <xref linkend="performance-fetching"/> for more information.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat
+    inner join fetch cat.mate
+    left join fetch cat.kittens]]></programlisting>
+
+        <para>
+            A fetch join does not usually need to assign an alias, because the associated objects
+            should not be used in the <literal>where</literal> clause (or any other clause). Also,
+            the associated objects are not returned directly in the query results. Instead, they may
+            be accessed via the parent object. The only reason we might need an alias is if we are
+            recursively join fetching a further collection:
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat
+    inner join fetch cat.mate
+    left join fetch cat.kittens child
+    left join fetch child.kittens]]></programlisting>
+
+        <para>
+            Note that the <literal>fetch</literal> construct may not be used in queries called using
+            <literal>iterate()</literal> (though <literal>scroll()</literal> can be used). Nor should
+            <literal>fetch</literal> be used together with <literal>setMaxResults()</literal> or
+            <literal>setFirstResult()</literal> as these operations are based on the result rows, which
+            usually contain duplicates for eager collection fetching, hence, the number of rows is not what
+            you'd expect.
+            Nor may <literal>fetch</literal> be used together with an ad hoc <literal>with</literal> condition.
+            It is possible to create a cartesian product by join fetching more than one collection in a
+            query, so take care in this case. Join fetching multiple collection roles also sometimes gives
+            unexpected results for bag mappings, so be careful about how you formulate your queries in this
+            case. Finally, note that <literal>full join fetch</literal> and <literal>right join fetch</literal>
+            are not meaningful.
+        </para>
+
+        <para>
+            If you are using property-level lazy fetching (with bytecode instrumentation), it is
+            possible to force Hibernate to fetch the lazy properties immediately (in the first
+            query) using <literal>fetch all properties</literal>.
+        </para>
+
+        <programlisting><![CDATA[from Document fetch all properties order by name]]></programlisting>
+        <programlisting><![CDATA[from Document doc fetch all properties where lower(doc.name) like '%cats%']]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-joins-forms">
+        <title>Forms of join syntax</title>
+
+	    <para>
+		    HQL supports two forms of association joining: <literal>implicit</literal> and <literal>explicit</literal>.
+		</para>
+
+	    <para>
+		    The queries shown in the previous section all use the <literal>explicit</literal> form where
+		    the join keyword is explicitly used in the from clause.  This is the recommended form.
+	    </para>
+
+	    <para>
+		    The <literal>implicit</literal> form does not use the join keyword.  Instead, the
+		    associations are "dereferenced" using dot-notation.  <literal>implicit</literal> joins
+		    can appear in any of the HQL clauses.  <literal>implicit</literal> join result
+		    in inner joins in the resulting SQL statement.
+	    </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.mate.name like '%s%']]></programlisting>
+	</sect1>
+
+    <sect1 id="queryhql-identifier-property">
+        <title>Refering to identifier property</title>
+
+        <para>
+            There are, generally speaking, 2 ways to refer to an entity's identifier property:
+        </para>
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    The special property (lowercase) <literal>id</literal> may be used to reference the identifier
+                    property of an entity <emphasis>provided that entity does not define a non-identifier property
+                    named id</emphasis>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    If the entity defines a named identifier property, you may use that property name.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            References to composite identifier properties follow the same naming rules.  If the
+            entity has a non-identifier property named id, the composite identifier property can only
+            be referenced by its defined named; otherwise, the special <literal>id</literal> property
+            can be used to rerference the identifier property.
+        </para>
+
+        <para>
+            Note: this has changed significantly starting in version 3.2.2.  In previous versions,
+            <literal>id</literal> <emphasis>always</emphasis> referred to the identifier property no
+            matter what its actual name.  A ramification of that decision was that non-identifier
+            properties named <literal>id</literal> could never be referenced in Hibernate queries.
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-select">
+        <title>The select clause</title>
+
+        <para>
+            The <literal>select</literal> clause picks which objects and properties to return in
+            the query result set. Consider:
+        </para>
+
+        <programlisting><![CDATA[select mate
+from Cat as cat
+    inner join cat.mate as mate]]></programlisting>
+
+        <para>
+            The query will select <literal>mate</literal>s of other <literal>Cat</literal>s.
+            Actually, you may express this query more compactly as:
+        </para>
+
+        <programlisting><![CDATA[select cat.mate from Cat cat]]></programlisting>
+
+        <para>
+            Queries may return properties of any value type including properties of component type:
+        </para>
+
+        <programlisting><![CDATA[select cat.name from DomesticCat cat
+where cat.name like 'fri%']]></programlisting>
+
+        <programlisting><![CDATA[select cust.name.firstName from Customer as cust]]></programlisting>
+
+        <para>
+            Queries may return multiple objects and/or properties as an array of type
+            <literal>Object[]</literal>,
+        </para>
+
+        <programlisting><![CDATA[select mother, offspr, mate.name
+from DomesticCat as mother
+    inner join mother.mate as mate
+    left outer join mother.kittens as offspr]]></programlisting>
+
+        <para>
+            or as a <literal>List</literal>,
+        </para>
+
+        <programlisting><![CDATA[select new list(mother, offspr, mate.name)
+from DomesticCat as mother
+    inner join mother.mate as mate
+    left outer join mother.kittens as offspr]]></programlisting>
+
+        <para>
+            or as an actual typesafe Java object,
+        </para>
+
+        <programlisting><![CDATA[select new Family(mother, mate, offspr)
+from DomesticCat as mother
+    join mother.mate as mate
+    left join mother.kittens as offspr]]></programlisting>
+
+        <para>
+            assuming that the class <literal>Family</literal> has an appropriate constructor.
+        </para>
+
+        <para>
+            You may assign aliases to selected expressions using <literal>as</literal>:
+        </para>
+
+        <programlisting><![CDATA[select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
+from Cat cat]]></programlisting>
+
+        <para>
+            This is most useful when used together with <literal>select new map</literal>:
+        </para>
+
+        <programlisting><![CDATA[select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
+from Cat cat]]></programlisting>
+
+        <para>
+            This query returns a <literal>Map</literal> from aliases to selected values.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-aggregation">
+        <title>Aggregate functions</title>
+
+        <para>
+            HQL queries may even return the results of aggregate functions on properties:
+        </para>
+
+        <programlisting><![CDATA[select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
+from Cat cat]]></programlisting>
+
+<!-- NO LONGER SUPPORTED
+        <para>
+            Collections may also appear inside aggregate functions in the <literal>select</literal>
+            clause.
+        </para>
+
+        <programlisting><![CDATA[select cat, count( elements(cat.kittens) )
+from Cat cat group by cat]]></programlisting>
+-->
+
+        <para>
+            The supported aggregate functions are
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>avg(...), sum(...), min(...), max(...)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>count(*)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>count(...), count(distinct ...), count(all...)</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            You may use arithmetic operators, concatenation, and recognized SQL functions
+            in the select clause:
+        </para>
+
+        <programlisting><![CDATA[select cat.weight + sum(kitten.weight)
+from Cat cat
+    join cat.kittens kitten
+group by cat.id, cat.weight]]></programlisting>
+
+        <programlisting><![CDATA[select firstName||' '||initial||' '||upper(lastName) from Person]]></programlisting>
+
+        <para>
+            The <literal>distinct</literal> and <literal>all</literal> keywords may be used and
+            have the same semantics as in SQL.
+        </para>
+
+        <programlisting><![CDATA[select distinct cat.name from Cat cat
+
+select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-polymorphism">
+        <title>Polymorphic queries</title>
+
+        <para>
+            A query like:
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+        <para>
+            returns instances not only of <literal>Cat</literal>, but also of subclasses like
+            <literal>DomesticCat</literal>. Hibernate queries may name <emphasis>any</emphasis> Java
+            class or interface in the <literal>from</literal> clause. The query will return instances
+            of all persistent classes that extend that class or implement the interface. The following
+            query would return all persistent objects:
+        </para>
+
+        <programlisting><![CDATA[from java.lang.Object o]]></programlisting>
+
+        <para>
+            The interface <literal>Named</literal> might be implemented by various persistent
+            classes:
+        </para>
+
+        <programlisting><![CDATA[from Named n, Named m where n.name = m.name]]></programlisting>
+
+        <para>
+            Note that these last two queries will require more than one SQL <literal>SELECT</literal>. This
+            means that the <literal>order by</literal> clause does not correctly order the whole result set.
+            (It also means you can't call these queries using <literal>Query.scroll()</literal>.)
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-where" revision="1">
+        <title>The where clause</title>
+
+        <para>
+            The <literal>where</literal> clause allows you to narrow the list of instances returned.
+            If no alias exists, you may refer to properties by name:
+        </para>
+
+        <programlisting><![CDATA[from Cat where name='Fritz']]></programlisting>
+
+        <para>
+        	If there is an alias, use a qualified property name:
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.name='Fritz']]></programlisting>
+
+        <para>
+            returns instances of <literal>Cat</literal> named 'Fritz'.
+        </para>
+
+        <programlisting><![CDATA[select foo
+from Foo foo, Bar bar
+where foo.startDate = bar.date]]></programlisting>
+
+        <para>
+            will return all instances of <literal>Foo</literal> for which
+            there exists an instance of <literal>bar</literal> with a
+            <literal>date</literal> property equal to the
+            <literal>startDate</literal> property of the
+            <literal>Foo</literal>. Compound path expressions make the
+            <literal>where</literal> clause extremely powerful. Consider:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.mate.name is not null]]></programlisting>
+
+        <para>
+            This query translates to an SQL query with a table (inner) join. If you were to write
+            something like
+        </para>
+
+        <programlisting><![CDATA[from Foo foo
+where foo.bar.baz.customer.address.city is not null]]></programlisting>
+
+        <para>
+            you would end up with a query that would require four table joins in SQL.
+        </para>
+
+        <para>
+            The <literal>=</literal> operator may be used to compare not only properties, but also
+            instances:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat, Cat rival where cat.mate = rival.mate]]></programlisting>
+
+        <programlisting><![CDATA[select cat, mate
+from Cat cat, Cat mate
+where cat.mate = mate]]></programlisting>
+
+        <para>
+            The special property (lowercase) <literal>id</literal> may be used to reference the
+            unique identifier of an object. See <xref linkend="queryhql-identifier-property"/>
+            for more information.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.id = 123
+
+from Cat as cat where cat.mate.id = 69]]></programlisting>
+
+        <para>
+            The second query is efficient. No table join is required!
+        </para>
+
+        <para>
+            Properties of composite identifiers may also be used. Suppose <literal>Person</literal>
+            has a composite identifier consisting of <literal>country</literal> and
+            <literal>medicareNumber</literal>.  Again, see <xref linkend="queryhql-identifier-property"/>
+            for more information regarding referencing identifier properties.
+        </para>
+
+        <programlisting><![CDATA[from bank.Person person
+where person.id.country = 'AU'
+    and person.id.medicareNumber = 123456]]></programlisting>
+
+        <programlisting><![CDATA[from bank.Account account
+where account.owner.id.country = 'AU'
+    and account.owner.id.medicareNumber = 123456]]></programlisting>
+
+        <para>
+            Once again, the second query requires no table join.
+        </para>
+
+        <para>
+            Likewise, the special property <literal>class</literal> accesses the discriminator value
+            of an instance in the case of polymorphic persistence. A Java class name embedded in the
+            where clause will be translated to its discriminator value.
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
+
+        <para>
+            You may also use components or composite user types, or properties of said
+            component types. See <xref linkend="queryhql-coomponents"/> for more details.
+        </para>
+
+        <para>
+            An "any" type has the special properties <literal>id</literal> and <literal>class</literal>,
+            allowing us to express a join in the following way (where <literal>AuditLog.item</literal>
+            is a property mapped with <literal>&lt;any&gt;</literal>).
+        </para>
+
+        <programlisting><![CDATA[from AuditLog log, Payment payment
+where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting>
+
+        <para>
+            Notice that <literal>log.item.class</literal> and <literal>payment.class</literal>
+            would refer to the values of completely different database columns in the above query.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-expressions">
+        <title>Expressions</title>
+
+        <para>
+            Expressions allowed in the <literal>where</literal> clause include
+            most of the kind of things you could write in SQL:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    mathematical operators <literal>+, -, *, /</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    binary comparison operators <literal>=, &gt;=, &lt;=, &lt;&gt;, !=, like</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    logical operations <literal>and, or, not</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Parentheses <literal>( )</literal>, indicating grouping
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>in</literal>,
+                    <literal>not in</literal>,
+                    <literal>between</literal>,
+                    <literal>is null</literal>,
+                    <literal>is not null</literal>,
+                    <literal>is empty</literal>,
+                    <literal>is not empty</literal>,
+                    <literal>member of</literal> and
+                    <literal>not member of</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                	"Simple" case, <literal>case ... when ... then ... else ... end</literal>, and
+                    "searched" case, <literal>case when ... then ... else ... end</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    string concatenation <literal>...||...</literal> or <literal>concat(...,...)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>current_date()</literal>, <literal>current_time()</literal>,
+                    <literal>current_timestamp()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+					<literal>second(...)</literal>, <literal>minute(...)</literal>,
+					<literal>hour(...)</literal>, <literal>day(...)</literal>,
+					<literal>month(...)</literal>, <literal>year(...)</literal>,
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Any function or operator defined by EJB-QL 3.0: <literal>substring(), trim(),
+                    lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>coalesce()</literal> and <literal>nullif()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>str()</literal> for converting numeric or temporal values to a
+                    readable string
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>cast(... as ...)</literal>, where the second argument is the name of
+                    a Hibernate type, and <literal>extract(... from ...)</literal> if ANSI
+                    <literal>cast()</literal> and <literal>extract()</literal> is supported by
+                    the underlying database
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    the HQL <literal>index()</literal> function, that applies to aliases of
+                    a joined indexed collection
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    HQL functions that take collection-valued path expressions: <literal>size(),
+                    minelement(), maxelement(), minindex(), maxindex()</literal>, along with the
+                    special <literal>elements()</literal> and <literal>indices</literal> functions
+                    which may be quantified using <literal>some, all, exists, any, in</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Any database-supported SQL scalar function like <literal>sign()</literal>,
+                    <literal>trunc()</literal>, <literal>rtrim()</literal>, <literal>sin()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    JDBC-style positional parameters <literal>?</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    named parameters <literal>:name</literal>, <literal>:start_date</literal>, <literal>:x1</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    SQL literals <literal>'foo'</literal>, <literal>69</literal>, <literal>6.66E+2</literal>,
+                    <literal>'1970-01-01 10:00:01.0'</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Java <literal>public static final</literal> constants <literal>eg.Color.TABBY</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>in</literal> and <literal>between</literal> may be used as follows:
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name between 'A' and 'B']]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+        <para>
+            and the negated forms may be written
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name not between 'A' and 'B']]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+        <para>
+            Likewise, <literal>is null</literal> and <literal>is not null</literal> may be used to test
+            for null values.
+        </para>
+
+        <para>
+            Booleans may be easily used in expressions by declaring HQL query substitutions in Hibernate
+            configuration:
+        </para>
+
+        <programlisting><![CDATA[<property name="hibernate.query.substitutions">true 1, false 0</property>]]></programlisting>
+
+        <para>
+            This will replace the keywords <literal>true</literal> and <literal>false</literal> with the
+            literals <literal>1</literal> and <literal>0</literal> in the translated SQL from this HQL:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.alive = true]]></programlisting>
+
+        <para>
+            You may test the size of a collection with the special property <literal>size</literal>, or
+            the special <literal>size()</literal> function.
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.kittens.size > 0]]></programlisting>
+
+        <programlisting><![CDATA[from Cat cat where size(cat.kittens) > 0]]></programlisting>
+
+        <para>
+            For indexed collections, you may refer to the minimum and maximum indices using
+            <literal>minindex</literal> and <literal>maxindex</literal> functions. Similarly,
+            you may refer to the minimum and maximum elements of a collection of basic type
+            using the <literal>minelement</literal> and <literal>maxelement</literal>
+            functions.
+        </para>
+
+        <programlisting><![CDATA[from Calendar cal where maxelement(cal.holidays) > current_date]]></programlisting>
+
+        <programlisting><![CDATA[from Order order where maxindex(order.items) > 100]]></programlisting>
+
+        <programlisting><![CDATA[from Order order where minelement(order.items) > 10000]]></programlisting>
+
+        <para>
+            The SQL functions <literal>any, some, all, exists, in</literal> are supported when passed the element
+            or index set of a collection (<literal>elements</literal> and <literal>indices</literal> functions)
+            or the result of a subquery (see below).
+        </para>
+
+        <programlisting><![CDATA[select mother from Cat as mother, Cat as kit
+where kit in elements(foo.kittens)]]></programlisting>
+
+        <programlisting><![CDATA[select p from NameList list, Person p
+where p.name = some elements(list.names)]]></programlisting>
+
+        <programlisting><![CDATA[from Cat cat where exists elements(cat.kittens)]]></programlisting>
+
+        <programlisting><![CDATA[from Player p where 3 > all elements(p.scores)]]></programlisting>
+
+        <programlisting><![CDATA[from Show show where 'fizard' in indices(show.acts)]]></programlisting>
+
+        <para>
+            Note that these constructs - <literal>size</literal>, <literal>elements</literal>,
+            <literal>indices</literal>, <literal>minindex</literal>, <literal>maxindex</literal>,
+            <literal>minelement</literal>, <literal>maxelement</literal> - may only be used in
+            the where clause in Hibernate3.
+        </para>
+
+        <para>
+            Elements of indexed collections (arrays, lists, maps) may be referred to by
+            index (in a where clause only):
+        </para>
+
+        <programlisting><![CDATA[from Order order where order.items[0].id = 1234]]></programlisting>
+
+        <programlisting><![CDATA[select person from Person person, Calendar calendar
+where calendar.holidays['national day'] = person.birthDay
+    and person.nationality.calendar = calendar]]></programlisting>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11]]></programlisting>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ maxindex(order.items) ] = item and order.id = 11]]></programlisting>
+
+        <para>
+            The expression inside <literal>[]</literal> may even be an arithmetic expression.
+        </para>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ size(order.items) - 1 ] = item]]></programlisting>
+
+        <para>
+            HQL also provides the built-in <literal>index()</literal> function, for elements
+            of a one-to-many association or collection of values.
+        </para>
+
+        <programlisting><![CDATA[select item, index(item) from Order order
+    join order.items item
+where index(item) < 5]]></programlisting>
+
+        <para>
+            Scalar SQL functions supported by the underlying database may be used
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like 'FRI%']]></programlisting>
+
+        <para>
+            If you are not yet convinced by all this, think how much longer and less readable the
+            following query would be in SQL:
+        </para>
+
+        <programlisting><![CDATA[select cust
+from Product prod,
+    Store store
+    inner join store.customers cust
+where prod.name = 'widget'
+    and store.location.name in ( 'Melbourne', 'Sydney' )
+    and prod = all elements(cust.currentOrder.lineItems)]]></programlisting>
+
+        <para>
+            <emphasis>Hint:</emphasis> something like
+        </para>
+
+        <programlisting><![CDATA[SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
+FROM customers cust,
+    stores store,
+    locations loc,
+    store_customers sc,
+    product prod
+WHERE prod.name = 'widget'
+    AND store.loc_id = loc.id
+    AND loc.name IN ( 'Melbourne', 'Sydney' )
+    AND sc.store_id = store.id
+    AND sc.cust_id = cust.id
+    AND prod.id = ALL(
+        SELECT item.prod_id
+        FROM line_items item, orders o
+        WHERE item.order_id = o.id
+            AND cust.current_order = o.id
+    )]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-ordering">
+        <title>The order by clause</title>
+
+        <para>
+            The list returned by a query may be ordered by any property of a returned class or components:
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat
+order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
+
+        <para>
+            The optional <literal>asc</literal> or <literal>desc</literal> indicate ascending or descending order
+            respectively.
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-grouping" revision="1">
+        <title>The group by clause</title>
+
+        <para>
+            A query that returns aggregate values may be grouped by any property of a returned class or components:
+        </para>
+
+        <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
+from Cat cat
+group by cat.color]]></programlisting>
+
+        <programlisting><![CDATA[select foo.id, avg(name), max(name)
+from Foo foo join foo.names name
+group by foo.id]]></programlisting>
+
+        <para>
+            A <literal>having</literal> clause is also allowed.
+        </para>
+
+        <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
+from Cat cat
+group by cat.color
+having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
+
+        <para>
+            SQL functions and aggregate functions are allowed in the <literal>having</literal>
+            and <literal>order by</literal> clauses, if supported by the underlying database
+            (eg. not in MySQL).
+        </para>
+
+        <programlisting><![CDATA[select cat
+from Cat cat
+    join cat.kittens kitten
+group by cat.id, cat.name, cat.other, cat.properties
+having avg(kitten.weight) > 100
+order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
+
+        <para>
+            Note that neither the <literal>group by</literal> clause nor the
+            <literal>order by</literal> clause may contain arithmetic expressions.
+            Also note that Hibernate currently does not expand a grouped entity,
+            so you can't write <literal>group by cat</literal> if all properties
+            of <literal>cat</literal> are non-aggregated. You have to list all
+            non-aggregated properties explicitly.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-subqueries" revision="3">
+        <title>Subqueries</title>
+
+        <para>
+            For databases that support subselects, Hibernate supports subqueries within queries. A subquery must
+            be surrounded by parentheses (often by an SQL aggregate function call). Even correlated subqueries
+            (subqueries that refer to an alias in the outer query) are allowed.
+        </para>
+
+        <programlisting><![CDATA[from Cat as fatcat
+where fatcat.weight > (
+    select avg(cat.weight) from DomesticCat cat
+)]]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat as cat
+where cat.name = some (
+    select name.nickName from Name as name
+)]]></programlisting>
+
+        <programlisting><![CDATA[from Cat as cat
+where not exists (
+    from Cat as mate where mate.mate = cat
+)]]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat as cat
+where cat.name not in (
+    select name.nickName from Name as name
+)]]></programlisting>
+
+        <programlisting><![CDATA[select cat.id, (select max(kit.weight) from cat.kitten kit)
+from Cat as cat]]></programlisting>
+
+        <para>
+            Note that HQL subqueries may occur only in the select or where clauses.
+        </para>
+
+        <para>
+            Note that subqueries can also utilize <literal>row value constructor</literal> syntax.  See
+            <xref linkend="queryhql-tuple"/> for more details.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-examples">
+        <title>HQL examples</title>
+
+        <para>
+            Hibernate queries can be quite powerful and complex. In fact, the power of the query language
+            is one of Hibernate's main selling points. Here are some example queries very similar to queries
+            that I used on a recent project. Note that most queries you will write are much simpler than these!
+        </para>
+
+        <para>
+            The following query returns the order id, number of items and total value of the order for all
+            unpaid orders for a particular customer and given minimum total value, ordering the results by
+            total value. In determining the prices, it uses the current catalog. The resulting SQL query,
+            against the <literal>ORDER</literal>, <literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>,
+            <literal>CATALOG</literal> and <literal>PRICE</literal> tables has four inner joins and an
+            (uncorrelated) subselect.
+        </para>
+
+        <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+    join order.lineItems as item
+    join item.product as product,
+    Catalog as catalog
+    join catalog.prices as price
+where order.paid = false
+    and order.customer = :customer
+    and price.product = product
+    and catalog.effectiveDate < sysdate
+    and catalog.effectiveDate >= all (
+        select cat.effectiveDate
+        from Catalog as cat
+        where cat.effectiveDate < sysdate
+    )
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+
+        <para>
+            What a monster! Actually, in real life, I'm not very keen on subqueries, so my query was
+            really more like this:
+        </para>
+
+        <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+    join order.lineItems as item
+    join item.product as product,
+    Catalog as catalog
+    join catalog.prices as price
+where order.paid = false
+    and order.customer = :customer
+    and price.product = product
+    and catalog = :currentCatalog
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+
+        <para>
+            The next query counts the number of payments in each status, excluding all payments in the
+            <literal>AWAITING_APPROVAL</literal> status where the most recent status change was made by the
+            current user. It translates to an SQL query with two inner joins and a correlated subselect
+            against the <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal> and
+            <literal>PAYMENT_STATUS_CHANGE</literal> tables.
+        </para>
+
+        <programlisting><![CDATA[select count(payment), status.name
+from Payment as payment
+    join payment.currentStatus as status
+    join payment.statusChanges as statusChange
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+    or (
+        statusChange.timeStamp = (
+            select max(change.timeStamp)
+            from PaymentStatusChange change
+            where change.payment = payment
+        )
+        and statusChange.user <> :currentUser
+    )
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+        <para>
+            If I would have mapped the <literal>statusChanges</literal> collection as a list, instead of a set,
+            the query would have been much simpler to write.
+        </para>
+
+        <programlisting><![CDATA[select count(payment), status.name
+from Payment as payment
+    join payment.currentStatus as status
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+    or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+        <para>
+            The next query uses the MS SQL Server <literal>isNull()</literal> function to return all
+            the accounts and unpaid payments for the organization to which the current user belongs.
+            It translates to an SQL query with three inner joins, an outer join and a subselect against
+            the <literal>ACCOUNT</literal>, <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal>,
+            <literal>ACCOUNT_TYPE</literal>, <literal>ORGANIZATION</literal> and
+            <literal>ORG_USER</literal> tables.
+        </para>
+
+        <programlisting><![CDATA[select account, payment
+from Account as account
+    left outer join account.payments as payment
+where :currentUser in elements(account.holder.users)
+    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+        <para>
+            For some databases, we would need to do away with the (correlated) subselect.
+        </para>
+
+        <programlisting><![CDATA[select account, payment
+from Account as account
+    join account.holder.users as user
+    left outer join account.payments as payment
+where :currentUser = user
+    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+   </sect1>
+
+    <sect1 id="queryhql-bulk" revision="2">
+        <title>Bulk update and delete</title>
+
+        <para>
+            HQL now supports <literal>update</literal>, <literal>delete</literal> and
+            <literal>insert ... select ...</literal> statements.
+            See <xref linkend="batch-direct"/> for details.
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-tipstricks">
+        <title>Tips &amp; Tricks</title>
+
+        <para>
+            You can count the number of query results without actually returning them:
+        </para>
+
+        <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue()]]></programlisting>
+
+        <para>
+            To order a result by the size of a collection, use the following query:
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+    left join usr.messages as msg
+group by usr.id, usr.name
+order by count(msg)]]></programlisting>
+
+        <para>
+            If your database supports subselects, you can place a condition upon selection
+            size in the where clause of your query:
+        </para>
+
+        <programlisting><![CDATA[from User usr where size(usr.messages) >= 1]]></programlisting>
+
+        <para>
+            If your database doesn't support subselects, use the following query:
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User usr.name
+    join usr.messages msg
+group by usr.id, usr.name
+having count(msg) >= 1]]></programlisting>
+
+        <para>
+            As this solution can't return a <literal>User</literal> with zero messages
+            because of the inner join, the following form is also useful:
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+    left join usr.messages as msg
+group by usr.id, usr.name
+having count(msg) = 0]]></programlisting>
+
+        <para>
+            Properties of a JavaBean can be bound to named query parameters:
+        </para>
+
+        <programlisting><![CDATA[Query q = s.createQuery("from foo Foo as foo where foo.name=:name and foo.size=:size");
+q.setProperties(fooBean); // fooBean has getName() and getSize()
+List foos = q.list();]]></programlisting>
+
+        <para>
+            Collections are pageable by using the <literal>Query</literal> interface with a filter:
+        </para>
+
+        <programlisting><![CDATA[Query q = s.createFilter( collection, "" ); // the trivial filter
+q.setMaxResults(PAGE_SIZE);
+q.setFirstResult(PAGE_SIZE * pageNumber);
+List page = q.list();]]></programlisting>
+
+        <para>
+            Collection elements may be ordered or grouped using a query filter:
+        </para>
+
+        <programlisting><![CDATA[Collection orderedCollection = s.filter( collection, "order by this.amount" );
+Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );]]></programlisting>
+
+        <para>
+            You can find the size of a collection without initializing it:
+        </para>
+
+        <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-components">
+        <title>Components</title>
+
+        <para>
+            Components might be used in just about every way that simple value types can be used in HQL
+            queries.  They can appear in the <literal>select</literal> clause:
+        </para>
+
+        <programlisting><![CDATA[select p.name from from Person p]]></programlisting>
+        <programlisting><![CDATA[select p.name.first from from Person p]]></programlisting>
+
+        <para>
+            where the Person's name property is a component.  Components can also be used
+            in the <literal>where</literal> clause:
+        </para>
+
+        <programlisting><![CDATA[from from Person p where p.name = :name]]></programlisting>
+        <programlisting><![CDATA[from from Person p where p.name.first = :firstName]]></programlisting>
+
+        <para>
+            Components can also be used in the <literal>order by</literal> clause:
+        </para>
+
+        <programlisting><![CDATA[from from Person p order by p.name]]></programlisting>
+        <programlisting><![CDATA[from from Person p order by p.name.first]]></programlisting>
+
+        <para>
+            Another common use of components is in <xref linkend="queryhql-tuple">row value constructors</xref>.
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-tuple">
+        <title>Row value constructor syntax</title>
+
+        <para>
+            HQL supports the use of ANSI SQL <literal>row value constructor</literal> syntax (sometimes
+            called <literal>tuple</literal> syntax), even though the underlying database may not support
+            that notion.  Here we are generally referring to multi-valued comparisons, typically associated
+            with components.  Consider an entity Person which defines a name component:
+        </para>
+
+        <programlisting><![CDATA[from Person p where p.name.first='John' and p.name.last='Jingleheimer-Schmidt']]></programlisting>
+
+        <para>
+            That's valid syntax, although a little verbose.  It be nice to make this a bit more concise and use
+            <literal>row value constructor</literal> syntax:
+        </para>
+
+        <programlisting><![CDATA[from Person p where p.name=('John', 'Jingleheimer-Schmidt')]]></programlisting>
+
+        <para>
+            It can also be useful to specify this in the <literal>select</literal> clause:
+        </para>
+
+        <programlisting><![CDATA[select p.name from from Person p]]></programlisting>
+
+        <para>
+            Another time using <literal>row value constructor</literal> syntax can be beneficial
+            is when using subqueries needing to compare against multiple values:
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat
+where not ( cat.name, cat.color ) in (
+    select cat.name, cat.color from DomesticCat cat
+)]]></programlisting>
+
+        <para>
+            One thing to consider when deciding if you want to use this syntax is that the query will
+            be dependent upon the ordering of the component sub-properties in the metadata.
+        </para>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/query_sql.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/query_sql.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/query_sql.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,758 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<chapter id="querysql" revision="2">
+  <title>Native SQL</title>
+
+  <para>You may also express queries in the native SQL dialect of your
+  database. This is useful if you want to utilize database specific features
+  such as query hints or the <literal>CONNECT</literal> keyword in Oracle. It
+  also provides a clean migration path from a direct SQL/JDBC based
+  application to Hibernate.</para>
+
+  <para>Hibernate3 allows you to specify handwritten SQL (including stored
+  procedures) for all create, update, delete, and load operations.</para>
+
+  <sect1 id="querysql-creating" revision="4">
+    <title>Using a <literal>SQLQuery</literal></title>
+
+    <para>Execution of native SQL queries is controlled via the
+    <literal>SQLQuery</literal> interface, which is obtained by calling
+    <literal>Session.createSQLQuery()</literal>. The following describes how
+    to use this API for querying.</para>
+
+    <sect2>
+      <title>Scalar queries</title>
+
+      <para>The most basic SQL query is to get a list of scalars
+      (values).</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").list();
+sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
+]]></programlisting>
+
+      <para>These will both return a List of Object arrays (Object[]) with
+      scalar values for each column in the CATS table. Hibernate will use
+      ResultSetMetadata to deduce the actual order and types of the returned
+      scalar values.</para>
+
+      <para>To avoid the overhead of using
+      <literal>ResultSetMetadata</literal> or simply to be more explicit in
+      what is returned one can use <literal>addScalar()</literal>.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME", Hibernate.STRING)
+ .addScalar("BIRTHDATE", Hibernate.DATE)
+]]></programlisting>
+
+      <para>This query specified:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>the SQL query string</para>
+        </listitem>
+
+        <listitem>
+          <para>the columns and types to return</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>This will still return Object arrays, but now it will not use
+      <literal>ResultSetMetdata</literal> but will instead explicitly get the
+      ID, NAME and BIRTHDATE column as respectively a Long, String and a Short
+      from the underlying resultset. This also means that only these three
+      columns will be returned, even though the query is using
+      <literal>*</literal> and could return more than the three listed
+      columns.</para>
+
+      <para>It is possible to leave out the type information for all or some
+      of the scalars.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME")
+ .addScalar("BIRTHDATE")
+]]></programlisting>
+
+      <para>This is essentially the same query as before, but now
+      <literal>ResultSetMetaData</literal> is used to decide the type of NAME
+      and BIRTHDATE where as the type of ID is explicitly specified.</para>
+
+      <para>How the java.sql.Types returned from ResultSetMetaData is mapped
+      to Hibernate types is controlled by the Dialect. If a specific type is
+      not mapped or does not result in the expected type it is possible to
+      customize it via calls to <literal>registerHibernateType</literal> in
+      the Dialect.</para>
+    </sect2>
+
+    <sect2>
+      <title>Entity queries</title>
+
+      <para>The above queries were all about returning scalar values,
+      basically returning the "raw" values from the resultset. The following
+      shows how to get entity objects from a native sql query via
+      <literal>addEntity()</literal>.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class);
+sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);
+]]></programlisting>
+
+      <para>This query specified:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>the SQL query string</para>
+        </listitem>
+
+        <listitem>
+          <para>the entity returned by the query</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>Assuming that Cat is mapped as a class with the columns ID, NAME
+      and BIRTHDATE the above queries will both return a List where each
+      element is a Cat entity.</para>
+
+      <para>If the entity is mapped with a <literal>many-to-one</literal> to
+      another entity it is required to also return this when performing the
+      native query, otherwise a database specific "column not found" error
+      will occur. The additional columns will automatically be returned when
+      using the * notation, but we prefer to be explicit as in the following
+      example for a <literal>many-to-one</literal> to a
+      <literal>Dog</literal>:</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);
+]]></programlisting>
+
+      <para>This will allow cat.getDog() to function properly.</para>
+    </sect2>
+
+    <sect2>
+      <title>Handling associations and collections</title>
+
+      <para>It is possible to eagerly join in the <literal>Dog</literal> to
+      avoid the possible extra roundtrip for initializing the proxy. This is
+      done via the <literal>addJoin()</literal> method, which allows you to
+      join in an association or collection.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dog");
+]]></programlisting>
+
+      <para>In this example the returned <literal>Cat</literal>'s will have
+      their <literal>dog</literal> property fully initialized without any
+      extra roundtrip to the database. Notice that we added a alias name
+      ("cat") to be able to specify the target property path of the join. It
+      is possible to do the same eager joining for collections, e.g. if the
+      <literal>Cat</literal> had a one-to-many to <literal>Dog</literal>
+      instead.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dogs");
+]]></programlisting>
+
+      <p>At this stage we are reaching the limits of what is possible with
+      native queries without starting to enhance the sql queries to make them
+      usable in Hibernate; the problems starts to arise when returning
+      multiple entities of the same type or when the default alias/column
+      names are not enough.</p>
+    </sect2>
+
+    <sect2>
+      <title>Returning multiple entities</title>
+
+      <para>Until now the result set column names are assumed to be the same
+      as the column names specified in the mapping document. This can be
+      problematic for SQL queries which join multiple tables, since the same
+      column names may appear in more than one table.</para>
+
+      <para>Column alias injection is needed in the following query (which
+      most likely will fail):</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT c.*, m.*  FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+]]></programlisting>
+
+      <para>The intention for this query is to return two Cat instances per
+      row, a cat and its mother. This will fail since there is a conflict of
+      names since they are mapped to the same column names and on some
+      databases the returned column aliases will most likely be on the form
+      "c.ID", "c.NAME", etc. which are not equal to the columns specificed in
+      the mappings ("ID" and "NAME").</para>
+
+      <para>The following form is not vulnerable to column name
+      duplication:</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT {cat.*}, {mother.*}  FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+]]></programlisting>
+
+      <para>This query specified:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>the SQL query string, with placeholders for Hibernate to
+          inject column aliases</para>
+        </listitem>
+
+        <listitem>
+          <para>the entities returned by the query</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>The {cat.*} and {mother.*} notation used above is a shorthand for
+      "all properties". Alternatively, you may list the columns explicity, but
+      even in this case we let Hibernate inject the SQL column aliases for
+      each property. The placeholder for a column alias is just the property
+      name qualified by the table alias. In the following example, we retrieve
+      Cats and their mothers from a different table (cat_log) to the one
+      declared in the mapping metadata. Notice that we may even use the
+      property aliases in the where clause if we like.</para>
+
+      <programlisting><![CDATA[String sql = "SELECT ID as {c.id}, NAME as {c.name}, " + 
+         "BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
+         "FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
+
+List loggedCats = sess.createSQLQuery(sql)
+        .addEntity("cat", Cat.class)
+        .addEntity("mother", Cat.class).list()
+]]></programlisting>
+
+      <sect3 id="querysql-aliasreferences" revision="2">
+        <title>Alias and property references</title>
+
+        <para>For most cases the above alias injection is needed, but for
+        queries relating to more complex mappings like composite properties,
+        inheritance discriminators, collections etc. there are some specific
+        aliases to use to allow Hibernate to inject the proper aliases.</para>
+
+        <para>The following table shows the different possibilities of using
+        the alias injection. Note: the alias names in the result are examples,
+        each alias will have a unique and probably different name when
+        used.</para>
+
+        <table frame="topbot" id="aliasinjection-summary">
+          <title>Alias injection names</title>
+
+          <tgroup cols="3">
+            <colspec colwidth="1*" />
+
+            <colspec colwidth="1*" />
+
+            <colspec colwidth="2.5*" />
+
+            <thead>
+              <row>
+                <entry>Description</entry>
+
+                <entry>Syntax</entry>
+
+                <entry>Example</entry>
+              </row>
+            </thead>
+
+            <tbody>
+              <row>
+                <entry>A simple property</entry>
+
+                <entry><literal>{[aliasname].[propertyname]</literal></entry>
+
+                <entry><literal>A_NAME as {item.name}</literal></entry>
+              </row>
+
+              <row>
+                <entry>A composite property</entry>
+
+                <entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
+
+                <entry><literal>CURRENCY as {item.amount.currency}, VALUE as
+                {item.amount.value}</literal></entry>
+              </row>
+
+              <row>
+                <entry>Discriminator of an entity</entry>
+
+                <entry><literal>{[aliasname].class}</literal></entry>
+
+                <entry><literal>DISC as {item.class}</literal></entry>
+              </row>
+
+              <row>
+                <entry>All properties of an entity</entry>
+
+                <entry><literal>{[aliasname].*}</literal></entry>
+
+                <entry><literal>{item.*}</literal></entry>
+              </row>
+
+              <row>
+                <entry>A collection key</entry>
+
+                <entry><literal>{[aliasname].key}</literal></entry>
+
+                <entry><literal>ORGID as {coll.key}</literal></entry>
+              </row>
+
+              <row>
+                <entry>The id of an collection</entry>
+
+                <entry><literal>{[aliasname].id}</literal></entry>
+
+                <entry><literal>EMPID as {coll.id}</literal></entry>
+              </row>
+
+              <row>
+                <entry>The element of an collection</entry>
+
+                <entry><literal>{[aliasname].element}</literal></entry>
+
+                <entry><literal>XID as {coll.element}</literal></entry>
+              </row>
+
+              <row>
+                <entry>roperty of the element in the collection</entry>
+
+                <entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
+
+                <entry><literal>NAME as {coll.element.name}</literal></entry>
+              </row>
+
+              <row>
+                <entry>All properties of the element in the collection</entry>
+
+                <entry><literal>{[aliasname].element.*}</literal></entry>
+
+                <entry><literal>{coll.element.*}</literal></entry>
+              </row>
+
+              <row>
+                <entry>All properties of the the collection</entry>
+
+                <entry><literal>{[aliasname].*}</literal></entry>
+
+                <entry><literal>{coll.*}</literal></entry>
+              </row>
+            </tbody>
+          </tgroup>
+        </table>
+      </sect3>
+    </sect2>
+
+    <sect2>
+      <title>Returning non-managed entities</title>
+
+      <para>It is possible to apply a ResultTransformer to native sql queries. Allowing it to e.g. return non-managed entities.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS")
+        .setResultTransformer(Transformers.aliasToBean(CatDTO.class))]]></programlisting>
+        
+              <para>This query specified:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>the SQL query string</para>
+        </listitem>
+
+        <listitem>
+          <para>a result transformer</para>
+        </listitem>
+      </itemizedlist>
+        
+        <para>
+        The above query will return a list of <literal>CatDTO</literal> which has been instantiated and injected the values of NAME and BIRTHNAME into its corresponding
+        properties or fields.
+        </para>
+    </sect2>
+
+    <sect2>
+      <title>Handling inheritance</title>
+
+      <para>Native sql queries which query for entities that is mapped as part
+      of an inheritance must include all properties for the baseclass and all
+      it subclasses.</para>
+    </sect2>
+
+    <sect2>
+      <title>Parameters</title>
+
+      <para>Native sql queries support positional as well as named
+      parameters:</para>
+
+      <programlisting><![CDATA[Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class);
+List pusList = query.setString(0, "Pus%").list();
+     
+query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like :name").addEntity(Cat.class);
+List pusList = query.setString("name", "Pus%").list();          ]]></programlisting>
+    </sect2>
+    
+    
+        
+  </sect1>
+
+  <sect1 id="querysql-namedqueries" revision="3">
+    <title>Named SQL queries</title>
+
+    <para>Named SQL queries may be defined in the mapping document and called
+    in exactly the same way as a named HQL query. In this case, we do
+    <emphasis>not</emphasis> need to call
+    <literal>addEntity()</literal>.</para>
+
+    <programlisting><![CDATA[<sql-query name="persons">
+    <return alias="person" class="eg.Person"/>
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex}
+    FROM PERSON person
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+    <programlisting><![CDATA[List people = sess.getNamedQuery("persons")
+    .setString("namePattern", namePattern)
+    .setMaxResults(50)
+    .list();]]></programlisting>
+
+    <para>The <literal>&lt;return-join&gt;</literal> and
+    <literal>&lt;load-collection&gt;</literal> elements are used to join
+    associations and define queries which initialize collections,
+    respectively.</para>
+
+    <programlisting><![CDATA[<sql-query name="personsWith">
+    <return alias="person" class="eg.Person"/>
+    <return-join alias="address" property="person.mailingAddress"/>
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex},
+           adddress.STREET AS {address.street},
+           adddress.CITY AS {address.city},
+           adddress.STATE AS {address.state},
+           adddress.ZIP AS {address.zip}
+    FROM PERSON person
+    JOIN ADDRESS adddress
+        ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+    <para>A named SQL query may return a scalar value. You must declare the
+    column alias and Hibernate type using the
+    <literal>&lt;return-scalar&gt;</literal> element:</para>
+
+    <programlisting><![CDATA[<sql-query name="mySqlQuery">
+    <return-scalar column="name" type="string"/>
+    <return-scalar column="age" type="long"/>
+    SELECT p.NAME AS name,
+           p.AGE AS age,
+    FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
+</sql-query>]]></programlisting>
+
+    <para>You can externalize the resultset mapping informations in a
+    <literal>&lt;resultset&gt;</literal> element to either reuse them accross
+    several named queries or through the
+    <literal>setResultSetMapping()</literal> API.</para>
+
+    <programlisting><![CDATA[<resultset name="personAddress">
+    <return alias="person" class="eg.Person"/>
+    <return-join alias="address" property="person.mailingAddress"/>
+</resultset>
+
+<sql-query name="personsWith" resultset-ref="personAddress">
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex},
+           adddress.STREET AS {address.street},
+           adddress.CITY AS {address.city},
+           adddress.STATE AS {address.state},
+           adddress.ZIP AS {address.zip}
+    FROM PERSON person
+    JOIN ADDRESS adddress
+        ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+    <para>You can alternatively use the resultset mapping information in your
+    hbm files directly in java code.</para>
+
+    <programlisting><![CDATA[List cats = sess.createSQLQuery(
+        "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
+    )
+    .setResultSetMapping("catAndKitten")
+    .list();]]></programlisting>
+
+    <sect2 id="propertyresults">
+      <title>Using return-property to explicitly specify column/alias
+      names</title>
+
+      <para>With <literal>&lt;return-property&gt;</literal> you can explicitly
+      tell Hibernate what column aliases to use, instead of using the
+      <literal>{}</literal>-syntax to let Hibernate inject its own
+      aliases.</para>
+
+      <programlisting><![CDATA[<sql-query name="mySqlQuery">
+    <return alias="person" class="eg.Person">
+        <return-property name="name" column="myName"/>
+        <return-property name="age" column="myAge"/>
+        <return-property name="sex" column="mySex"/>
+    </return>
+    SELECT person.NAME AS myName,
+           person.AGE AS myAge,
+           person.SEX AS mySex,
+    FROM PERSON person WHERE person.NAME LIKE :name
+</sql-query>
+]]></programlisting>
+
+      <para><literal>&lt;return-property&gt;</literal> also works with
+      multiple columns. This solves a limitation with the
+      <literal>{}</literal>-syntax which can not allow fine grained control of
+      multi-column properties.</para>
+
+      <programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
+    <return alias="emp" class="Employment">
+        <return-property name="salary">
+            <return-column name="VALUE"/>
+            <return-column name="CURRENCY"/>
+        </return-property>
+        <return-property name="endDate" column="myEndDate"/>
+    </return>
+        SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
+        STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+        REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
+        FROM EMPLOYMENT
+        WHERE EMPLOYER = :id AND ENDDATE IS NULL
+        ORDER BY STARTDATE ASC
+</sql-query>]]></programlisting>
+
+      <para>Notice that in this example we used
+      <literal>&lt;return-property&gt;</literal> in combination with the
+      <literal>{}</literal>-syntax for injection. Allowing users to choose how
+      they want to refer column and properties.</para>
+
+      <para>If your mapping has a discriminator you must use
+      <literal>&lt;return-discriminator&gt;</literal> to specify the
+      discriminator column.</para>
+    </sect2>
+
+    <sect2 id="sp_query" revision="1">
+      <title>Using stored procedures for querying</title>
+
+      <para>Hibernate 3 introduces support for queries via stored procedures
+      and functions. Most of the following documentation is equivalent for
+      both. The stored procedure/function must return a resultset as the first
+      out-parameter to be able to work with Hibernate. An example of such a
+      stored function in Oracle 9 and higher is as follows:</para>
+
+      <programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
+    RETURN SYS_REFCURSOR
+AS
+    st_cursor SYS_REFCURSOR;
+BEGIN
+    OPEN st_cursor FOR
+ SELECT EMPLOYEE, EMPLOYER,
+ STARTDATE, ENDDATE,
+ REGIONCODE, EID, VALUE, CURRENCY
+ FROM EMPLOYMENT;
+      RETURN  st_cursor;
+ END;]]></programlisting>
+
+      <para>To use this query in Hibernate you need to map it via a named
+      query.</para>
+
+      <programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
+    <return alias="emp" class="Employment">
+        <return-property name="employee" column="EMPLOYEE"/>
+        <return-property name="employer" column="EMPLOYER"/>
+        <return-property name="startDate" column="STARTDATE"/>
+        <return-property name="endDate" column="ENDDATE"/>
+        <return-property name="regionCode" column="REGIONCODE"/>
+        <return-property name="id" column="EID"/>
+        <return-property name="salary">
+            <return-column name="VALUE"/>
+            <return-column name="CURRENCY"/>
+        </return-property>
+    </return>
+    { ? = call selectAllEmployments() }
+</sql-query>]]></programlisting>
+
+      <para>Notice stored procedures currently only return scalars and
+      entities. <literal>&lt;return-join&gt;</literal> and
+      <literal>&lt;load-collection&gt;</literal> are not supported.</para>
+
+      <sect3 id="querysql-limits-storedprocedures" revision="1">
+        <title>Rules/limitations for using stored procedures</title>
+
+        <para>To use stored procedures with Hibernate the procedures/functions
+        have to follow some rules. If they do not follow those rules they are
+        not usable with Hibernate. If you still want to use these procedures
+        you have to execute them via <literal>session.connection()</literal>.
+        The rules are different for each database, since database vendors have
+        different stored procedure semantics/syntax.</para>
+
+        <para>Stored procedure queries can't be paged with
+        <literal>setFirstResult()/setMaxResults()</literal>.</para>
+
+        <para>Recommended call form is standard SQL92: <literal>{ ? = call
+        functionName(&lt;parameters&gt;) }</literal> or <literal>{ ? = call
+        procedureName(&lt;parameters&gt;}</literal>. Native call syntax is not
+        supported.</para>
+
+        <para>For Oracle the following rules apply:</para>
+
+        <itemizedlist spacing="compact">
+          <listitem>
+            <para>A function must return a result set. The first parameter of
+            a procedure must be an <literal>OUT</literal> that returns a
+            result set. This is done by using a
+            <literal>SYS_REFCURSOR</literal> type in Oracle 9 or 10. In Oracle
+            you need to define a <literal>REF CURSOR</literal> type, see
+            Oracle literature.</para>
+          </listitem>
+        </itemizedlist>
+
+        <para>For Sybase or MS SQL server the following rules apply:</para>
+
+        <itemizedlist spacing="compact">
+          <listitem>
+            <para>The procedure must return a result set. Note that since
+            these servers can/will return multiple result sets and update
+            counts, Hibernate will iterate the results and take the first
+            result that is a result set as its return value. Everything else
+            will be discarded.</para>
+          </listitem>
+
+          <listitem>
+            <para>If you can enable <literal>SET NOCOUNT ON</literal> in your
+            procedure it will probably be more efficient, but this is not a
+            requirement.</para>
+          </listitem>
+        </itemizedlist>
+      </sect3>
+    </sect2>
+  </sect1>
+
+  <sect1 id="querysql-cud">
+    <title>Custom SQL for create, update and delete</title>
+
+    <para>Hibernate3 can use custom SQL statements for create, update, and
+    delete operations. The class and collection persisters in Hibernate
+    already contain a set of configuration time generated strings (insertsql,
+    deletesql, updatesql etc.). The mapping tags
+    <literal>&lt;sql-insert&gt;</literal>,
+    <literal>&lt;sql-delete&gt;</literal>, and
+    <literal>&lt;sql-update&gt;</literal> override these strings:</para>
+
+    <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
+    <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
+    <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
+</class>]]></programlisting>
+
+    <para>The SQL is directly executed in your database, so you are free to
+    use any dialect you like. This will of course reduce the portability of
+    your mapping if you use database specific SQL.</para>
+
+    <para>Stored procedures are supported if the <literal>callable</literal>
+    attribute is set:</para>
+
+    <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
+    <sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
+    <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
+</class>]]></programlisting>
+
+    <para>The order of the positional parameters are currently vital, as they
+    must be in the same sequence as Hibernate expects them.</para>
+
+    <para>You can see the expected order by enabling debug logging for the
+    <literal>org.hibernate.persister.entity</literal> level. With this level
+    enabled Hibernate will print out the static SQL that is used to create,
+    update, delete etc. entities. (To see the expected sequence, remember to
+    not include your custom SQL in the mapping files as that will override the
+    Hibernate generated static sql.)</para>
+
+    <para>The stored procedures are in most cases (read: better do it than
+    not) required to return the number of rows inserted/updated/deleted, as
+    Hibernate has some runtime checks for the success of the statement.
+    Hibernate always registers the first statement parameter as a numeric
+    output parameter for the CUD operations:</para>
+
+    <programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
+    RETURN NUMBER IS
+BEGIN
+
+    update PERSON
+    set
+        NAME = uname,
+    where
+        ID = uid;
+
+    return SQL%ROWCOUNT;
+
+END updatePerson;]]></programlisting>
+  </sect1>
+
+  <sect1 id="querysql-load">
+    <title>Custom SQL for loading</title>
+
+    <para>You may also declare your own SQL (or HQL) queries for entity
+    loading:</para>
+
+    <programlisting><![CDATA[<sql-query name="person">
+    <return alias="pers" class="Person" lock-mode="upgrade"/>
+    SELECT NAME AS {pers.name}, ID AS {pers.id}
+    FROM PERSON
+    WHERE ID=?
+    FOR UPDATE
+</sql-query>]]></programlisting>
+
+    <para>This is just a named query declaration, as discussed earlier. You
+    may reference this named query in a class mapping:</para>
+
+    <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <loader query-ref="person"/>
+</class>]]></programlisting>
+
+    <para>This even works with stored procedures.</para>
+
+    <para>You may even define a query for collection loading:</para>
+
+    <programlisting><![CDATA[<set name="employments" inverse="true">
+    <key/>
+    <one-to-many class="Employment"/>
+    <loader query-ref="employments"/>
+</set>]]></programlisting>
+
+    <programlisting><![CDATA[<sql-query name="employments">
+    <load-collection alias="emp" role="Person.employments"/>
+    SELECT {emp.*}
+    FROM EMPLOYMENT emp
+    WHERE EMPLOYER = :id
+    ORDER BY STARTDATE ASC, EMPLOYEE ASC
+</sql-query>]]></programlisting>
+
+    <para>You could even define an entity loader that loads a collection by
+    join fetching:</para>
+
+    <programlisting><![CDATA[<sql-query name="person">
+    <return alias="pers" class="Person"/>
+    <return-join alias="emp" property="pers.employments"/>
+    SELECT NAME AS {pers.*}, {emp.*}
+    FROM PERSON pers
+    LEFT OUTER JOIN EMPLOYMENT emp
+        ON pers.ID = emp.PERSON_ID
+    WHERE ID=?
+</sql-query>]]></programlisting>
+  </sect1>
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/session_api.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/session_api.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/session_api.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1240 @@
+<chapter id="objectstate">
+    <title>Working with objects</title>
+
+    <para>
+        Hibernate is a full object/relational mapping solution that not only shields
+        the developer from the details of the underlying database management
+        system, but also offers <emphasis>state management</emphasis> of objects. This is,
+        contrary to the management of SQL <literal>statements</literal> in common JDBC/SQL
+        persistence layers, a very natural object-oriented view of persistence in Java
+        applications.
+    </para>
+
+    <para>
+        In other words, Hibernate application developers should always think about the
+        <emphasis>state</emphasis> of their objects, and not necessarily about the
+        execution of SQL statements. This part is taken care of by Hibernate and is only
+        relevant for the application developer when tuning the performance of the system.
+    </para>
+
+    <sect1 id="objectstate-overview">
+        <title>Hibernate object states</title>
+
+        <para>
+            Hibernate defines and supports the following object states:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>Transient</emphasis> - an object is transient if it has just
+                    been instantiated using the <literal>new</literal> operator, and it
+                    is not associated with a Hibernate <literal>Session</literal>. It has no
+                    persistent representation in the database and no identifier value has been
+                    assigned. Transient instances will be destroyed by the garbage collector if
+                    the application doesn't hold a reference anymore. Use the Hibernate
+                    <literal>Session</literal> to make an object persistent (and let Hibernate
+                    take care of the SQL statements that need to be executed for this transition).
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Persistent</emphasis> - a persistent instance has a representation
+                    in the database and an identifier value. It might just have been saved or loaded,
+                    however, it is by definition in the scope of a <literal>Session</literal>.
+                    Hibernate will detect any changes made to an object in persistent state and
+                    synchronize the state with the database when the unit of work completes.
+                    Developers don't execute manual <literal>UPDATE</literal> statements, or
+                    <literal>DELETE</literal> statements when an object should be made transient.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Detached</emphasis> - a detached instance is an object that has been
+                    persistent, but its <literal>Session</literal> has been closed. The reference
+                    to the object is still valid, of course, and the detached instance might even
+                    be modified in this state. A detached instance can be reattached to a new
+                    <literal>Session</literal> at a later point in time, making it (and all the
+                    modifications) persistent again. This feature enables a programming model for
+                    long running units of work that require user think-time. We call them
+                    <emphasis>application transactions</emphasis>, i.e. a unit of work from the
+                    point of view of the user.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            We'll now discuss the states and state transitions (and the Hibernate methods that
+            trigger a transition) in more detail.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-makingpersistent" revision="1">
+        <title>Making objects persistent</title>
+
+        <para>
+            Newly instantiated instances of a a persistent class are considered 
+            <emphasis>transient</emphasis> by Hibernate. We can make a transient 
+            instance <emphasis>persistent</emphasis> by associating it with a 
+            session:
+        </para>
+
+        <programlisting><![CDATA[DomesticCat fritz = new DomesticCat();
+fritz.setColor(Color.GINGER);
+fritz.setSex('M');
+fritz.setName("Fritz");
+Long generatedId = (Long) sess.save(fritz);]]></programlisting>
+
+        <para>
+            If <literal>Cat</literal> has a generated identifier, the identifier is
+            generated and assigned to the <literal>cat</literal> when <literal>save()</literal> 
+            is called. If <literal>Cat</literal> has an <literal>assigned</literal>
+            identifier, or a composite key, the identifier should be assigned to 
+            the <literal>cat</literal> instance before calling <literal>save()</literal>.
+            You may also use <literal>persist()</literal> instead of <literal>save()</literal>,
+            with the semantics defined in the EJB3 early draft.
+        </para>
+        
+        <para>
+            Alternatively, you may assign the identifier using an overloaded version
+            of <literal>save()</literal>.
+        </para>
+
+<programlisting><![CDATA[DomesticCat pk = new DomesticCat();
+pk.setColor(Color.TABBY);
+pk.setSex('F');
+pk.setName("PK");
+pk.setKittens( new HashSet() );
+pk.addKitten(fritz);
+sess.save( pk, new Long(1234) );]]></programlisting>
+        
+        <para>
+            If the object you make persistent has associated objects (e.g. the
+            <literal>kittens</literal> collection in the previous example),
+            these objects may be made persistent in any order you like unless you
+            have a <literal>NOT NULL</literal> constraint upon a foreign key column.
+            There is never a risk of violating foreign key constraints. However, you 
+            might violate a <literal>NOT NULL</literal> constraint if you
+            <literal>save()</literal> the objects in the wrong order.
+        </para>
+        
+        <para>
+            Usually you don't bother with this detail, as you'll very likely use Hibernate's
+            <emphasis>transitive persistence</emphasis> feature to save the associated
+            objects automatically. Then, even <literal>NOT NULL</literal>
+            constraint violations don't occur - Hibernate will take care of everything.
+            Transitive persistence is discussed later in this chapter.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="objectstate-loading">
+        <title>Loading an object</title>
+
+        <para>
+            The <literal>load()</literal> methods of <literal>Session</literal> gives you
+            a way to retrieve a persistent instance if you already know its identifier. 
+            <literal>load()</literal> takes a class object and will load the state into 
+            a newly instantiated instance of that class, in persistent state.
+        </para>
+
+        <programlisting><![CDATA[Cat fritz = (Cat) sess.load(Cat.class, generatedId);]]></programlisting>
+
+<programlisting><![CDATA[// you need to wrap primitive identifiers
+long id = 1234;
+DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id) );]]></programlisting>
+
+        <para>
+            Alternatively, you can load state into a given instance:
+        </para>
+
+<programlisting><![CDATA[Cat cat = new DomesticCat();
+// load pk's state into cat
+sess.load( cat, new Long(pkId) );
+Set kittens = cat.getKittens();]]></programlisting>
+
+        <para>
+            Note that <literal>load()</literal> will throw an unrecoverable exception if 
+            there is no matching database row. If the class is mapped with a proxy, 
+            <literal>load()</literal> just returns an uninitialized proxy and does not 
+            actually hit the database until you invoke a method of the proxy. This 
+            behaviour is very useful if you wish to create an association to an object
+            without actually loading it from the database. It also allows multiple
+            instances to be loaded as a batch if <literal>batch-size</literal> is
+            defined for the class mapping.
+        </para>
+        
+        <para>
+            If you are not certain that a matching row exists, you should use the 
+            <literal>get()</literal> method, which hits the database immediately and 
+            returns null if there is no matching row.
+        </para>
+        
+        <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id);
+if (cat==null) {
+    cat = new Cat();
+    sess.save(cat, id);
+}
+return cat;]]></programlisting>
+
+        <para>
+            You may even load an object using an SQL <literal>SELECT ... FOR UPDATE</literal>,
+            using a <literal>LockMode</literal>. See the API documentation for more information.
+        </para>
+
+        <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);]]></programlisting>
+        
+        <para>
+            Note that any associated instances or contained collections are 
+            <emphasis>not</emphasis> selected <literal>FOR UPDATE</literal>, unless you decide
+            to specify <literal>lock</literal> or <literal>all</literal> as a
+            cascade style for the association.
+        </para>
+        
+        <para>
+            It is possible to re-load an object and all its collections at any time, using the 
+            <literal>refresh()</literal> method. This is useful when database triggers are used to
+            initialize some of the properties of the object.
+        </para>
+        
+        <programlisting><![CDATA[sess.save(cat);
+sess.flush(); //force the SQL INSERT
+sess.refresh(cat); //re-read the state (after the trigger executes)]]></programlisting>
+
+        <para>
+            An important question usually appears at this point: How much does Hibernate load
+            from the database and how many SQL <literal>SELECT</literal>s will it use? This
+            depends on the <emphasis>fetching strategy</emphasis> and is explained in
+            <xref linkend="performance-fetching"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-querying" revision="1">
+        <title>Querying</title>
+
+        <para>
+            If you don't know the identifiers of the objects you are looking for, 
+            you need a query. Hibernate supports an easy-to-use but powerful object 
+            oriented query language (HQL). For programmatic query creation, Hibernate
+            supports a sophisticated Criteria and Example query feature (QBC and QBE).
+            You may also express your query in the native SQL of your database, with
+            optional support from Hibernate for result set conversion into objects.
+        </para>
+
+        <sect2 id="objectstate-querying-executing" revision="1">
+            <title>Executing queries</title>
+
+            <para>
+                HQL and native SQL queries are represented with an instance of <literal>org.hibernate.Query</literal>.
+                This interface offers methods for parameter binding, result set handling, and for the execution
+                of the actual query. You always obtain a <literal>Query</literal> using the current
+                <literal>Session</literal>:
+            </para>
+
+        <programlisting><![CDATA[List cats = session.createQuery(
+    "from Cat as cat where cat.birthdate < ?")
+    .setDate(0, date)
+    .list();
+
+List mothers = session.createQuery(
+    "select mother from Cat as cat join cat.mother as mother where cat.name = ?")
+    .setString(0, name)
+    .list();
+
+List kittens = session.createQuery(
+    "from Cat as cat where cat.mother = ?")
+    .setEntity(0, pk)
+    .list();
+
+Cat mother = (Cat) session.createQuery(
+    "select cat.mother from Cat as cat where cat = ?")
+    .setEntity(0, izi)
+    .uniqueResult();]]
+
+Query mothersWithKittens = (Cat) session.createQuery(
+    "select mother from Cat as mother left join fetch mother.kittens");
+Set uniqueMothers = new HashSet(mothersWithKittens.list());]]></programlisting>
+
+            <para>
+                A query is usually executed by invoking <literal>list()</literal>, the
+                result of the query will be loaded completely into a collection in memory.
+                Entity instances retrieved by a query are in persistent state. The
+                <literal>uniqueResult()</literal> method offers a shortcut if you
+                know your query will only return a single object. Note that queries that
+                make use of eager fetching of collections usually return duplicates of
+                the root objects (but with their collections initialized). You can filter
+                these duplicates simply through a <literal>Set</literal>.
+            </para>
+
+            <sect3 id="objectstate-querying-executing-iterate">
+                <title>Iterating results</title>
+
+                <para>
+                    Occasionally, you might be able to achieve better performance by
+                    executing the query using the <literal>iterate()</literal> method.
+                    This will only usually be the case if you expect that the actual
+                    entity instances returned by the query will already be in the session
+                    or second-level cache. If they are not already cached,
+                    <literal>iterate()</literal> will be slower than <literal>list()</literal>
+                    and might require many database hits for a simple query, usually
+                    <emphasis>1</emphasis> for the initial select which only returns identifiers,
+                    and <emphasis>n</emphasis> additional selects to initialize the actual instances.
+                </para>
+
+                <programlisting><![CDATA[// fetch ids
+Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate();
+while ( iter.hasNext() ) {
+    Qux qux = (Qux) iter.next();  // fetch the object
+    // something we couldnt express in the query
+    if ( qux.calculateComplicatedAlgorithm() ) {
+        // delete the current instance
+        iter.remove();
+        // dont need to process the rest
+        break;
+    }
+}]]></programlisting>
+            </sect3>
+            
+            <sect3 id="objectstate-querying-executing-tuples">
+                <title>Queries that return tuples</title>
+
+                <para>
+                    Hibernate queries sometimes return tuples of objects, in which case each tuple
+                    is returned as an array:
+                </para>
+
+                <programlisting><![CDATA[Iterator kittensAndMothers = sess.createQuery(
+            "select kitten, mother from Cat kitten join kitten.mother mother")
+            .list()
+            .iterator();
+
+while ( kittensAndMothers.hasNext() ) {
+    Object[] tuple = (Object[]) kittensAndMothers.next();
+    Cat kitten  = tuple[0];
+    Cat mother  = tuple[1];
+    ....
+}]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-scalar" revision="1">
+                <title>Scalar results</title>
+
+                <para>
+                    Queries may specify a property of a class in the <literal>select</literal> clause.
+                    They may even call SQL aggregate functions. Properties or aggregates are considered
+                    "scalar" results (and not entities in persistent state).
+                </para>
+
+                <programlisting><![CDATA[Iterator results = sess.createQuery(
+        "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
+        "group by cat.color")
+        .list()
+        .iterator();
+
+while ( results.hasNext() ) {
+    Object[] row = (Object[]) results.next();
+    Color type = (Color) row[0];
+    Date oldest = (Date) row[1];
+    Integer count = (Integer) row[2];
+    .....
+}]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-parameters">
+                <title>Bind parameters</title>
+
+                <para>
+                    Methods on <literal>Query</literal> are provided for binding values to
+                    named parameters or JDBC-style <literal>?</literal> parameters. 
+                    <emphasis>Contrary to JDBC, Hibernate numbers parameters from zero.</emphasis>
+                    Named parameters are identifiers of the form <literal>:name</literal> in 
+                    the query string. The advantages of named parameters are:
+                </para>
+
+                <itemizedlist spacing="compact">
+                    <listitem>
+                        <para>
+                            named parameters are insensitive to the order they occur in the
+                            query string
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            they may occur multiple times in the same query
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            they are self-documenting
+                        </para>
+                    </listitem>
+                </itemizedlist>
+
+                <programlisting><![CDATA[//named parameter (preferred)
+Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
+q.setString("name", "Fritz");
+Iterator cats = q.iterate();]]></programlisting>
+
+                <programlisting><![CDATA[//positional parameter
+Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
+q.setString(0, "Izi");
+Iterator cats = q.iterate();]]></programlisting>
+
+                <programlisting><![CDATA[//named parameter list
+List names = new ArrayList();
+names.add("Izi");
+names.add("Fritz");
+Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)");
+q.setParameterList("namesList", names);
+List cats = q.list();]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-pagination">
+                <title>Pagination</title>
+
+                <para>
+                    If you need to specify bounds upon your result set (the maximum number of rows
+                    you want to retrieve and / or the first row you want to retrieve) you should
+                    use methods of the <literal>Query</literal> interface:
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.createQuery("from DomesticCat cat");
+q.setFirstResult(20);
+q.setMaxResults(10);
+List cats = q.list();]]></programlisting>
+
+                <para>
+                    Hibernate knows how to translate this limit query into the native
+                    SQL of your DBMS.
+                </para>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-scrolling">
+                <title>Scrollable iteration</title>
+
+                <para>
+                    If your JDBC driver supports scrollable <literal>ResultSet</literal>s, the
+                    <literal>Query</literal> interface may be used to obtain a
+                    <literal>ScrollableResults</literal> object, which allows flexible
+                    navigation of the query results.
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
+                            "order by cat.name");
+ScrollableResults cats = q.scroll();
+if ( cats.first() ) {
+
+    // find the first name on each page of an alphabetical list of cats by name
+    firstNamesOfPages = new ArrayList();
+    do {
+        String name = cats.getString(0);
+        firstNamesOfPages.add(name);
+    }
+    while ( cats.scroll(PAGE_SIZE) );
+
+    // Now get the first page of cats
+    pageOfCats = new ArrayList();
+    cats.beforeFirst();
+    int i=0;
+    while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) );
+
+}
+cats.close()]]></programlisting>
+
+                <para>
+                    Note that an open database connection (and cursor) is required for this
+                    functionality, use <literal>setMaxResult()</literal>/<literal>setFirstResult()</literal>
+                    if you need offline pagination functionality.
+                </para>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-named" revision="1">
+                <title>Externalizing named queries</title>
+
+                <para>
+                    You may also define named queries in the mapping document. (Remember to use a
+                    <literal>CDATA</literal> section if your query contains characters that could
+                    be interpreted as markup.)
+                </para>
+
+                <programlisting><![CDATA[<query name="ByNameAndMaximumWeight"><![CDATA[
+    from eg.DomesticCat as cat
+        where cat.name = ?
+        and cat.weight > ?
+] ]></query>]]></programlisting>
+
+                <para>
+                    Parameter binding and executing is done programatically:
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.getNamedQuery("ByNameAndMaximumWeight");
+q.setString(0, name);
+q.setInt(1, minWeight);
+List cats = q.list();]]></programlisting>
+
+                <para>
+                    Note that the actual program code is independent of the query language that
+                    is used, you may also define native SQL queries in metadata, or migrate
+                    existing queries to Hibernate by placing them in mapping files.
+                </para>
+
+                <para>
+                    Also note that a query declaration inside a <literal>&lt;hibernate-mapping&gt;</literal>
+                    element requires a global unique name for the query, while a query declaration inside a
+                    <literal>&lt;class&gt;</literal> element is made unique automatically by prepending the
+                    fully qualified name of the class, for example
+                    <literal>eg.Cat.ByNameAndMaximumWeight</literal>.
+                </para>
+
+            </sect3>
+
+        </sect2>
+
+        <sect2 id="objectstate-filtering" revision="1">
+            <title>Filtering collections</title>
+            <para>
+                A collection <emphasis>filter</emphasis> is a special type of query that may be applied to
+                a persistent collection or array. The query string may refer to <literal>this</literal>,
+                meaning the current collection element.
+            </para>
+
+            <programlisting><![CDATA[Collection blackKittens = session.createFilter(
+    pk.getKittens(), 
+    "where this.color = ?")
+    .setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) )
+    .list()
+);]]></programlisting>
+        
+            <para>
+                The returned collection is considered a bag, and it's a copy of the given
+                collection. The original collection is not modified (this is contrary to
+                the implication of the name "filter", but consistent with expected behavior).
+            </para>
+
+            <para>
+                Observe that filters do not require a <literal>from</literal> clause (though they may have
+                one if required). Filters are not limited to returning the collection elements themselves.
+            </para>
+
+            <programlisting><![CDATA[Collection blackKittenMates = session.createFilter(
+    pk.getKittens(), 
+    "select this.mate where this.color = eg.Color.BLACK.intValue")
+    .list();]]></programlisting>
+
+            <para>
+                Even an empty filter query is useful, e.g. to load a subset of elements in a
+                huge collection:
+            </para>
+
+            <programlisting><![CDATA[Collection tenKittens = session.createFilter(
+    mother.getKittens(), "")
+    .setFirstResult(0).setMaxResults(10)
+    .list();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="objecstate-querying-criteria" revision="1">
+           <title>Criteria queries</title>
+
+            <para>
+                HQL is extremely powerful but some developers prefer to build queries dynamically,
+                using an object-oriented API, rather than building query strings. Hibernate provides
+                an intuitive <literal>Criteria</literal> query API for these cases:
+            </para>
+
+            <programlisting><![CDATA[Criteria crit = session.createCriteria(Cat.class);
+crit.add( Expression.eq( "color", eg.Color.BLACK ) );
+crit.setMaxResults(10);
+List cats = crit.list();]]></programlisting>
+    
+            <para>
+                The <literal>Criteria</literal> and the associated <literal>Example</literal>
+                API are discussed in more detail in <xref linkend="querycriteria"/>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="objectstate-querying-nativesql" revision="2">
+            <title>Queries in native SQL</title>
+
+            <para>
+                You may express a query in SQL, using <literal>createSQLQuery()</literal> and
+                let Hibernate take care of the mapping from result sets to objects. Note
+                that you may at any time call <literal>session.connection()</literal> and
+                use the JDBC <literal>Connection</literal> directly. If you chose to use the
+                Hibernate API, you must enclose SQL aliases in braces:
+            </para>
+
+            <programlisting><![CDATA[List cats = session.createSQLQuery(
+    "SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10",
+    "cat",
+    Cat.class
+).list();]]></programlisting>
+                
+            <programlisting><![CDATA[List cats = session.createSQLQuery(
+    "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
+           "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
+    "FROM CAT {cat} WHERE ROWNUM<10",
+    "cat",
+    Cat.class
+).list()]]></programlisting>
+
+            <para>
+                SQL queries may contain named and positional parameters, just like Hibernate queries.
+                More information about native SQL queries in Hibernate can be found in
+                <xref linkend="querysql"/>.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="objectstate-modifying" revision="1">
+        <title>Modifying persistent objects</title>
+
+        <para>
+            <emphasis>Transactional persistent instances</emphasis> (ie. objects loaded, saved, created or
+            queried by the <literal>Session</literal>) may be manipulated by the application
+            and any changes to persistent state will be persisted when the <literal>Session</literal>
+            is <emphasis>flushed</emphasis> (discussed later in this chapter). There is no need
+            to call a particular method (like <literal>update()</literal>, which has a different
+            purpose) to make your modifications persistent. So the most straightforward way to update
+            the state of an object is to <literal>load()</literal> it,
+            and then manipulate it directly, while the <literal>Session</literal> is open:
+        </para>
+
+        <programlisting><![CDATA[DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
+cat.setName("PK");
+sess.flush();  // changes to cat are automatically detected and persisted]]></programlisting>
+
+        <para>
+            Sometimes this programming model is inefficient since it would require both an SQL
+            <literal>SELECT</literal> (to load an object) and an SQL <literal>UPDATE</literal>
+            (to persist its updated state) in the same session. Therefore Hibernate offers an
+            alternate approach, using detached instances.
+        </para>
+
+        <para>
+            <emphasis>Note that Hibernate does not offer its own API for direct execution of
+            <literal>UPDATE</literal> or <literal>DELETE</literal> statements. Hibernate is a
+            <emphasis>state management</emphasis> service, you don't have to think in
+            <emphasis>statements</emphasis> to use it. JDBC is a perfect API for executing
+            SQL statements, you can get a JDBC <literal>Connection</literal> at any time
+            by calling <literal>session.connection()</literal>. Furthermore, the notion
+            of mass operations conflicts with object/relational mapping for online
+            transaction processing-oriented applications. Future versions of Hibernate
+            may however provide special mass operation functions. See <xref linkend="batch"/>
+            for some possible batch operation tricks.</emphasis>
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-detached" revision="2">
+        <title>Modifying detached objects</title>
+
+        <para>
+            Many applications need to retrieve an object in one transaction, send it to the
+            UI layer for manipulation, then save the changes in a new transaction.
+            Applications that use this kind of approach in a high-concurrency environment
+            usually use versioned  data to ensure isolation for the "long" unit of work.
+        </para>
+
+        <para>
+            Hibernate supports this model by providing for reattachment of detached instances
+            using the <literal>Session.update()</literal> or <literal>Session.merge()</literal>
+            methods:
+        </para>
+
+        <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catId);
+Cat potentialMate = new Cat();
+firstSession.save(potentialMate);
+
+// in a higher layer of the application
+cat.setMate(potentialMate);
+
+// later, in a new session
+secondSession.update(cat);  // update cat
+secondSession.update(mate); // update mate]]></programlisting>
+
+        <para>
+            If the <literal>Cat</literal> with identifier <literal>catId</literal> had already
+            been loaded  by <literal>secondSession</literal> when the application tried to
+            reattach it, an exception would have been thrown.
+        </para>
+
+        <para>
+            Use <literal>update()</literal> if you are sure that the session does
+            not contain an already persistent instance with the same identifier, and
+            <literal>merge()</literal> if you want to merge your modifications at any time
+            without consideration of the state of the session. In other words, <literal>update()</literal>
+            is usually the first method you would call in a fresh session, ensuring that
+            reattachment of your detached instances is the first operation that is executed.
+        </para>
+
+        <para>
+            The application should individually <literal>update()</literal> detached instances
+            reachable from the given detached instance if and <emphasis>only</emphasis> if it wants
+            their state also updated. This can be automated of course, using <emphasis>transitive
+            persistence</emphasis>, see <xref linkend="objectstate-transitive"/>.
+        </para>
+
+        <para>
+            The <literal>lock()</literal> method also allows an application to reassociate
+            an object with a new session. However, the detached instance has to be unmodified!
+        </para>
+
+        <programlisting><![CDATA[//just reassociate:
+sess.lock(fritz, LockMode.NONE);
+//do a version check, then reassociate:
+sess.lock(izi, LockMode.READ);
+//do a version check, using SELECT ... FOR UPDATE, then reassociate:
+sess.lock(pk, LockMode.UPGRADE);]]></programlisting>
+
+        <para>
+            Note that <literal>lock()</literal> can be used with various
+            <literal>LockMode</literal>s, see the API documentation and the
+            chapter on transaction handling for more information. Reattachment is not
+            the only usecase for <literal>lock()</literal>.
+        </para>
+
+        <para>
+            Other models for long units of work are discussed in <xref linkend="transactions-optimistic"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-saveorupdate">
+        <title>Automatic state detection</title>
+
+        <para>
+            Hibernate users have requested a general purpose method that either saves a
+            transient instance by generating a new identifier or updates/reattaches
+            the detached instances associated with its current identifier.
+            The <literal>saveOrUpdate()</literal> method implements this functionality.
+        </para>
+
+        <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catID);
+
+// in a higher tier of the application
+Cat mate = new Cat();
+cat.setMate(mate);
+
+// later, in a new session
+secondSession.saveOrUpdate(cat);   // update existing state (cat has a non-null id)
+secondSession.saveOrUpdate(mate);  // save the new instance (mate has a null id)]]></programlisting>
+
+        <para>
+            The usage and semantics of <literal>saveOrUpdate()</literal> seems to be confusing
+            for new users. Firstly, so long as you are not trying to use instances from one session
+            in another new session, you should not need to use <literal>update()</literal>,
+            <literal>saveOrUpdate()</literal>, or <literal>merge()</literal>. Some whole
+            applications will never use either of these methods.
+        </para>
+
+        <para>
+            Usually <literal>update()</literal> or <literal>saveOrUpdate()</literal> are used in
+            the following scenario:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    the application loads an object in the first session
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    the object is passed up to the UI tier
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    some modifications are made to the object
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    the object is passed back down to the business logic tier
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    the application persists these modifications by calling
+                    <literal>update()</literal> in a second session
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>saveOrUpdate()</literal> does the following:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    if the object is already persistent in this session, do nothing
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    if another object associated with the session has the same identifier, 
+                    throw an exception
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    if the object has no identifier property, <literal>save()</literal> it
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    if the object's identifier has the value assigned to a newly instantiated
+                    object, <literal>save()</literal> it
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    if the object is versioned (by a <literal>&lt;version&gt;</literal> or
+                    <literal>&lt;timestamp&gt;</literal>), and the version property value
+                    is the same value assigned to a newly instantiated object, 
+                    <literal>save()</literal> it
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    otherwise <literal>update()</literal> the object
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            and <literal>merge()</literal> is very different:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    if there is a persistent instance with the same identifier currently 
+                    associated with the session, copy the state of the given object onto 
+                    the persistent instance
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    if there is no persistent instance currently associated with the session, 
+                    try to load it from the database, or create a new persistent instance
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    the persistent instance is returned
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    the given instance does not become associated with the session, it
+                    remains detached
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect1>
+
+    <sect1 id="objectstate-deleting" revision="1">
+        <title>Deleting persistent objects</title>
+
+        <para>
+            <literal>Session.delete()</literal> will remove an object's state from the database.
+            Of course, your application might still hold a reference to a deleted object.
+            It's best to think of <literal>delete()</literal> as making a persistent instance
+            transient.
+        </para>
+
+        <programlisting><![CDATA[sess.delete(cat);]]></programlisting>
+
+        <para>
+            You may delete objects in any order you like, without risk of foreign key
+            constraint violations. It is still possible to violate a <literal>NOT
+            NULL</literal> constraint on a foreign key column by deleting objects in
+            the wrong order, e.g. if you delete the parent, but forget to delete the
+            children.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="objectstate-replicating" revision="1">
+    	<title>Replicating object between two different datastores</title>
+    	
+    	<para>
+    	    It is occasionally useful to be able to take a graph of persistent instances
+    	    and make them persistent in a different datastore, without regenerating identifier
+    	    values.
+    	</para>
+    	
+        <programlisting><![CDATA[//retrieve a cat from one database
+Session session1 = factory1.openSession();
+Transaction tx1 = session1.beginTransaction();
+Cat cat = session1.get(Cat.class, catId);
+tx1.commit();
+session1.close();
+
+//reconcile with a second database
+Session session2 = factory2.openSession();
+Transaction tx2 = session2.beginTransaction();
+session2.replicate(cat, ReplicationMode.LATEST_VERSION);
+tx2.commit();
+session2.close();]]></programlisting>
+
+        <para>
+            The <literal>ReplicationMode</literal> determines how <literal>replicate()</literal>
+            will deal with conflicts with existing rows in the database.
+        </para>
+        
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.IGNORE</literal> - ignore the object when there is
+                    an existing database row with the same identifier
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.OVERWRITE</literal> - overwrite any existing database 
+                    row with the same identifier
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.EXCEPTION</literal> - throw an exception if there is
+                    an existing database row with the same identifier
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.LATEST_VERSION</literal> - overwrite the row if its
+                    version number is earlier than the version number of the object, or ignore
+                    the object otherwise
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Usecases for this feature include reconciling data entered into different database
+            instances, upgrading system configuration information during product upgrades,
+            rolling back changes made during non-ACID transactions and more.
+        </para>
+    	
+    </sect1>
+
+    <sect1 id="objectstate-flushing">
+        <title>Flushing the Session</title>
+
+        <para>
+            From time to time the <literal>Session</literal> will execute the SQL statements 
+            needed to synchronize the JDBC connection's state with the state of objects held in 
+            memory. This process, <emphasis>flush</emphasis>, occurs by default at the following 
+            points
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    before some query executions
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    from <literal>org.hibernate.Transaction.commit()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    from <literal>Session.flush()</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            The SQL statements are issued in the following order
+        </para>
+
+        <orderedlist spacing="compact">
+            <listitem>
+                <para>
+                    all entity insertions, in the same order the corresponding objects
+                    were saved using <literal>Session.save()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    all entity updates
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    all collection deletions
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    all collection element deletions, updates and insertions
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    all collection insertions
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    all entity deletions, in the same order the corresponding objects
+                    were deleted using <literal>Session.delete()</literal>
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <para>
+            (An exception is that objects using <literal>native</literal> ID generation are 
+            inserted when they are saved.)
+        </para>
+
+        <para>
+            Except when you explicity <literal>flush()</literal>, there are absolutely no 
+            guarantees about <emphasis>when</emphasis> the <literal>Session</literal> executes 
+            the JDBC calls, only the <emphasis>order</emphasis> in which they are executed.
+            However, Hibernate does guarantee that the <literal>Query.list(..)</literal> 
+            will never return stale data; nor will they return the wrong data.
+        </para>
+
+        <para>
+            It is possible to change the default behavior so that flush occurs less frequently.
+            The <literal>FlushMode</literal> class defines three different modes: only flush
+            at commit time (and only when the Hibernate <literal>Transaction</literal> API
+            is used), flush automatically using the explained routine, or never flush unless
+            <literal>flush()</literal> is called explicitly. The last mode is useful for long running
+            units of work, where a <literal>Session</literal> is kept open and disconnected for
+            a long time (see <xref linkend="transactions-optimistic-longsession"/>).
+        </para>
+
+        <programlisting><![CDATA[sess = sf.openSession();
+Transaction tx = sess.beginTransaction();
+sess.setFlushMode(FlushMode.COMMIT); // allow queries to return stale state
+
+Cat izi = (Cat) sess.load(Cat.class, id);
+izi.setName(iznizi);
+
+// might return stale data
+sess.find("from Cat as cat left outer join cat.kittens kitten");
+
+// change to izi is not flushed!
+...
+tx.commit(); // flush occurs
+sess.close();]]></programlisting>
+
+        <para>
+            During flush, an exception might occur (e.g. if a DML operation violates a constraint).
+            Since handling exceptions involves some understanding of Hibernate's transactional 
+            behavior, we discuss it in <xref linkend="transactions"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-transitive" revision="1">
+        <title>Transitive persistence</title>
+
+        <para>
+            It is quite cumbersome to save, delete, or reattach individual objects,
+            especially if you deal with a graph of associated objects. A common case is
+            a parent/child relationship. Consider the following example:
+        </para>
+
+        <para>
+            If the children in a parent/child relationship would be value typed (e.g. a collection
+            of addresses or strings), their lifecycle would depend on the parent and no
+            further action would be required for convenient "cascading" of state changes.
+            When the parent is saved, the value-typed child objects are saved as
+            well, when the parent is deleted, the children will be deleted, etc. This
+            even works for operations such as the removal of a child from the collection;
+            Hibernate will detect this and, since value-typed objects can't have shared
+            references, delete the child from the database.
+        </para>
+
+        <para>
+            Now consider the same scenario with parent and child objects being entities,
+            not value-types (e.g. categories and items, or parent and child cats). Entities
+            have their own lifecycle, support shared references (so removing an entity from
+            the collection does not mean it can be deleted), and there is by default no
+            cascading of state from one entity to any other associated entities. Hibernate
+            does not implement <emphasis>persistence by reachability</emphasis> by default.
+        </para>
+
+        <para>
+            For each basic operation of the Hibernate session - including <literal>persist(), merge(),
+            saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate()</literal> - there is a 
+            corresponding cascade style. Respectively, the cascade styles are named <literal>create, 
+            merge, save-update, delete, lock, refresh, evict, replicate</literal>. If you want an 
+            operation to be cascaded along an association, you must indicate that in the mapping
+            document. For example:
+        </para>
+        
+        <programlisting><![CDATA[<one-to-one name="person" cascade="persist"/>]]></programlisting>
+        
+        <para>
+            Cascade styles my be combined:
+        </para>
+        
+        <programlisting><![CDATA[<one-to-one name="person" cascade="persist,delete,lock"/>]]></programlisting>
+        
+        <para>
+            You may even use <literal>cascade="all"</literal> to specify that <emphasis>all</emphasis>
+            operations should be cascaded along the association. The default <literal>cascade="none"</literal>
+            specifies that no operations are to be cascaded.
+        </para>
+        
+        <para>
+            A special cascade style, <literal>delete-orphan</literal>, applies only to one-to-many
+            associations, and indicates that the <literal>delete()</literal> operation should
+            be applied to any child object that is removed from the association.
+        </para>
+
+
+        <para>
+            Recommendations:
+        </para>
+
+       <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    It doesn't usually make sense to enable cascade on a <literal>&lt;many-to-one&gt;</literal>
+                    or <literal>&lt;many-to-many&gt;</literal> association. Cascade is often useful for 
+                    <literal>&lt;one-to-one&gt;</literal> and <literal>&lt;one-to-many&gt;</literal>
+                    associations.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    If the child object's lifespan is bounded by the lifespan of the of the parent
+                    object make it a <emphasis>lifecycle object</emphasis> by specifying
+                    <literal>cascade="all,delete-orphan"</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Otherwise, you might not need cascade at all. But if you think that you will often be
+                    working with the parent and children together in the same transaction, and you want to save 
+                    yourself some typing, consider using <literal>cascade="persist,merge,save-update"</literal>.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Mapping an association (either a single valued association, or a collection) with 
+            <literal>cascade="all"</literal> marks the association as a 
+            <emphasis>parent/child</emphasis> style relationship where save/update/delete of the 
+            parent results in save/update/delete of the child or children.
+        </para>
+        <para>
+            Futhermore, a mere reference to a child from a persistent parent will result in 
+            save/update of the child. This metaphor is incomplete, however. A child which becomes 
+            unreferenced by its parent is <emphasis>not</emphasis> automatically deleted, except 
+            in the case of a <literal>&lt;one-to-many&gt;</literal> association mapped with
+            <literal>cascade="delete-orphan"</literal>. The precise semantics of cascading 
+            operations for a parent/child relationship are as follows:
+        </para>
+
+       <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    If a parent is passed to <literal>persist()</literal>, all children are passed to 
+                    <literal>persist()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    If a parent is passed to <literal>merge()</literal>, all children are passed to 
+                    <literal>merge()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    If a parent is passed to <literal>save()</literal>, <literal>update()</literal> or 
+                    <literal>saveOrUpdate()</literal>, all children are passed to <literal>saveOrUpdate()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    If a transient or detached child becomes referenced by a persistent parent, 
+                    it is passed to <literal>saveOrUpdate()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    If a parent is deleted, all children are passed to <literal>delete()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    If a child is dereferenced by a persistent parent, <emphasis>nothing
+                    special happens</emphasis> - the application should explicitly delete 
+                    the child if necessary - unless <literal>cascade="delete-orphan"</literal>, 
+                    in which case the "orphaned" child is deleted.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Finally, note that cascading of operations can be applied to an object graph at
+            <emphasis>call time</emphasis> or at <emphasis>flush time</emphasis>. All operations,
+            if enabled, are cascaded to associated entities reachable when the operation is
+            executed. However, <literal>save-upate</literal> and <literal>delete-orphan</literal>
+            are transitive for all associated entities reachable during flush of the
+            <literal>Session</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-metadata">
+        <title>Using metadata</title>
+
+        <para>
+            Hibernate requires a very rich meta-level model of all entity and value types. From time
+            to time, this model is very useful to the application itself. For example, the application
+            might use Hibernate's metadata to implement a "smart" deep-copy algorithm that understands
+            which objects should be copied (eg. mutable value types) and which should not (eg. 
+            immutable value types and, possibly, associated entities).
+        </para>
+        <para>
+            Hibernate exposes metadata via the <literal>ClassMetadata</literal> and
+            <literal>CollectionMetadata</literal> interfaces and the <literal>Type</literal>
+            hierarchy. Instances of the metadata interfaces may be obtained from the 
+            <literal>SessionFactory</literal>.
+        </para>
+
+        <programlisting><![CDATA[Cat fritz = ......;
+ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class);
+
+Object[] propertyValues = catMeta.getPropertyValues(fritz);
+String[] propertyNames = catMeta.getPropertyNames();
+Type[] propertyTypes = catMeta.getPropertyTypes();
+
+// get a Map of all properties which are not collections or associations
+Map namedValues = new HashMap();
+for ( int i=0; i<propertyNames.length; i++ ) {
+    if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType() ) {
+        namedValues.put( propertyNames[i], propertyValues[i] );
+    }
+}]]></programlisting>
+        
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/toolset_guide.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/toolset_guide.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/toolset_guide.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,604 @@
+<chapter id="toolsetguide" revision="2">
+    <title>Toolset Guide</title>
+
+    <para>
+        Roundtrip engineering with Hibernate is possible using a set of Eclipse plugins,
+        commandline tools, as well as Ant tasks.
+    </para>
+
+    <para>
+        The <emphasis>Hibernate Tools</emphasis> currently include plugins for the Eclipse
+        IDE as well as Ant tasks for reverse engineering of existing databases:
+    </para>
+
+    <itemizedlist>
+        <listitem><para>
+            <emphasis>Mapping Editor:</emphasis> An editor for Hibernate XML mapping files,
+            supporting auto-completion and syntax highlighting. It also supports semantic
+            auto-completion for class names and property/field names, making it much more versatile than a normal XML editor.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Console:</emphasis> The console is a new view in Eclipse. In addition to
+            a tree overview of your console configurations, you also get an interactive view
+            of your persistent classes and their relationships. The console allows you to
+            execute HQL queries against your database and browse the result directly in
+            Eclipse.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Development Wizards:</emphasis> Several wizards are provided with the
+            Hibernate Eclipse tools; you can use a wizard to quickly generate Hibernate configuration
+            (cfg.xml) files, or you may even completely reverse engineer an existing database schema
+            into POJO source files and Hibernate mapping files. The reverse engineering wizard
+            supports customizable templates.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Ant Tasks:</emphasis>
+        </para></listitem>
+
+    </itemizedlist>
+
+    <para>
+        Please refer to the <emphasis>Hibernate Tools</emphasis> package and it's documentation
+        for more information.
+    </para>
+
+    <para>
+        However, the Hibernate main package comes bundled with an integrated tool (it can even
+        be used from "inside" Hibernate on-the-fly): <emphasis>SchemaExport</emphasis> aka
+        <literal>hbm2ddl</literal>.
+    </para>
+
+    <sect1 id="toolsetguide-s1" revision="2">
+        <title>Automatic schema generation</title>
+
+        <para>
+            DDL may be generated from your mapping files by a Hibernate utility. The generated
+            schema includes referential integrity constraints (primary and foreign keys) for
+            entity and collection tables. Tables and sequences are also created for mapped
+            identifier generators.
+        </para>
+        
+        <para>
+            You <emphasis>must</emphasis> specify a SQL <literal>Dialect</literal> via the 
+            <literal>hibernate.dialect</literal> property when using this tool, as DDL
+            is highly vendor specific.
+        </para>
+
+        <para>
+            First, customize your mapping files to improve the generated schema.
+        </para>
+
+        <sect2 id="toolsetguide-s1-2" revision="3">
+            <title>Customizing the schema</title>
+
+            <para>
+                Many Hibernate mapping elements define optional attributes named <literal>length</literal>,
+                <literal>precision</literal> and <literal>scale</literal>. You may set the length, precision 
+                and scale of a column with this attribute. 
+                
+            </para>
+
+            <programlisting><![CDATA[<property name="zip" length="5"/>]]></programlisting>
+            <programlisting><![CDATA[<property name="balance" precision="12" scale="2"/>]]></programlisting>
+
+            <para>
+                Some tags also accept a <literal>not-null</literal> attribute (for generating a 
+                <literal>NOT NULL</literal> constraint on table columns) and a <literal>unique</literal> 
+                attribute (for generating <literal>UNIQUE</literal> constraint on table columns).
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="bar" column="barId" not-null="true"/>]]></programlisting>
+
+            <programlisting><![CDATA[<element column="serialNumber" type="long" not-null="true" unique="true"/>]]></programlisting>
+
+            <para>
+                A <literal>unique-key</literal> attribute may be used to group columns in
+                a single unique key constraint. Currently, the specified value of the 
+                <literal>unique-key</literal> attribute is <emphasis>not</emphasis> used 
+                to name the constraint in the generated DDL, only to group the columns in 
+                the mapping file.
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="org" column="orgId" unique-key="OrgEmployeeId"/>
+<property name="employeeId" unique-key="OrgEmployee"/>]]></programlisting>
+
+            <para>
+                An <literal>index</literal> attribute specifies the name of an index that
+                will be created using the mapped column or columns. Multiple columns may be 
+                grouped into the same index, simply by specifying the same index name. 
+            </para>
+
+            <programlisting><![CDATA[<property name="lastName" index="CustName"/>
+<property name="firstName" index="CustName"/>]]></programlisting>
+
+            <para>
+                A <literal>foreign-key</literal> attribute may be used to override the name 
+                of any generated foreign key constraint.
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="bar" column="barId" foreign-key="FKFooBar"/>]]></programlisting>
+
+            <para>
+                Many mapping elements also accept a child <literal>&lt;column&gt;</literal> element. 
+                This is particularly useful for mapping multi-column types:
+            </para>
+
+            <programlisting><![CDATA[<property name="name" type="my.customtypes.Name"/>
+    <column name="last" not-null="true" index="bar_idx" length="30"/>
+    <column name="first" not-null="true" index="bar_idx" length="20"/>
+    <column name="initial"/>
+</property>]]></programlisting>
+
+            <para>
+                The <literal>default</literal> attribute lets you specify a default value for
+                a column (you should assign the same value to the mapped property before
+                saving a new instance of the mapped class).
+            </para>
+
+            <programlisting><![CDATA[<property name="credits" type="integer" insert="false">
+    <column name="credits" default="10"/>
+</property>]]></programlisting>
+
+            <programlisting><![CDATA[<version name="version" type="integer" insert="false">
+    <column name="version" default="0"/>
+</property>]]></programlisting>
+
+            <para>
+                The <literal>sql-type</literal> attribute allows the user to override the default 
+                mapping of a Hibernate type to SQL datatype.
+            </para>
+            
+            <programlisting><![CDATA[<property name="balance" type="float">
+    <column name="balance" sql-type="decimal(13,3)"/>
+</property>]]></programlisting>
+            
+            <para>
+                The <literal>check</literal> attribute allows you to specify a check constraint.
+            </para>
+            
+            <programlisting><![CDATA[<property name="foo" type="integer">
+    <column name="foo" check="foo > 10"/>
+</property>]]></programlisting>
+
+            <programlisting><![CDATA[<class name="Foo" table="foos" check="bar < 100.0">
+    ...
+    <property name="bar" type="float"/>
+</class>]]></programlisting>
+            
+
+            <table frame="topbot" id="schemattributes-summary" revision="2">
+                <title>Summary</title>
+                <tgroup cols="3">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>Attribute</entry>
+                            <entry>Values</entry>
+                            <entry>Interpretation</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>length</literal></entry>
+                            <entry>number</entry>
+                            <entry>column length</entry>
+                        </row>
+                        <row>
+                            <entry><literal>precision</literal></entry>
+                            <entry>number</entry>
+                            <entry>column decimal precision</entry>
+                        </row>
+                        <row>
+                            <entry><literal>scale</literal></entry>
+                            <entry>number</entry>
+                            <entry>column decimal scale</entry>
+                        </row>
+                        <row>
+                            <entry><literal>not-null</literal></entry>
+                            <entry><literal>true|false</literal></entry>
+                            <entry>specfies that the column should be non-nullable</entry>
+                        </row>
+                        <row>
+                            <entry><literal>unique</literal></entry>
+                            <entry><literal>true|false</literal></entry>
+                            <entry>specifies that the column should have a unique constraint</entry>
+                        </row>
+                        <row>
+                            <entry><literal>index</literal></entry>
+                            <entry><literal>index_name</literal></entry>
+                            <entry>specifies the name of a (multi-column) index</entry>
+                        </row>
+                        <row>
+                            <entry><literal>unique-key</literal></entry>
+                            <entry><literal>unique_key_name</literal></entry>
+                            <entry>specifies the name of a multi-column unique constraint</entry>
+                        </row>
+                        <row>
+                            <entry><literal>foreign-key</literal></entry>
+                            <entry><literal>foreign_key_name</literal></entry>
+                            <entry>
+                                specifies the name of the foreign key constraint generated
+                                for an association, for a <literal>&lt;one-to-one&gt;</literal>, 
+                                <literal>&lt;many-to-one&gt;</literal>, <literal>&lt;key&gt;</literal>, 
+                                or <literal>&lt;many-to-many&gt;</literal> mapping element. Note that
+                                <literal>inverse="true"</literal> sides will not be considered
+                                by <literal>SchemaExport</literal>.
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>sql-type</literal></entry>
+                            <entry><literal>SQL column type</literal></entry>
+                            <entry>
+                                overrides the default column type (attribute of 
+                                <literal>&lt;column&gt;</literal> element only)
+                            </entry>
+                       </row>
+                       <row>
+                            <entry><literal>default</literal></entry>
+                            <entry>SQL expression</entry>
+                            <entry>
+                                specify a default value for the column
+                            </entry>
+                       </row>
+                       <row>
+                            <entry><literal>check</literal></entry>
+                            <entry>SQL expression</entry>
+                            <entry>
+                                create an SQL check constraint on either column or table
+                            </entry>
+                       </row>
+                   </tbody>
+                </tgroup>
+            </table>
+            
+            <para>
+                The <literal>&lt;comment&gt;</literal> element allows you to specify comments
+                for the generated schema.
+            </para>
+            
+            <programlisting><![CDATA[<class name="Customer" table="CurCust">
+    <comment>Current customers only</comment>
+    ...
+</class>]]></programlisting>
+
+            <programlisting><![CDATA[<property name="balance">
+    <column name="bal">
+        <comment>Balance in USD</comment>
+    </column>
+</property>]]></programlisting>
+            
+            <para>
+                This results in a <literal>comment on table</literal> or 
+                <literal>comment on column</literal> statement in the generated
+                DDL (where supported).
+            </para>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-3" revision="2">
+            <title>Running the tool</title>
+
+            <para>
+                The <literal>SchemaExport</literal> tool writes a DDL script to standard out and/or
+                executes the DDL statements.
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaExport</literal> <emphasis>options mapping_files</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaExport</literal> Command Line Options</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Option</entry>
+                            <entry>Description</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--quiet</literal></entry>
+                            <entry>don't output the script to stdout</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--drop</literal></entry>
+                            <entry>only drop the tables</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--create</literal></entry>
+                            <entry>only create the tables</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--text</literal></entry>
+                            <entry>don't export to the database</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--output=my_schema.ddl</literal></entry>
+                            <entry>output the ddl script to a file</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>select a <literal>NamingStrategy</literal></entry>
+                        </row>
+                         <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry>read Hibernate configuration from an XML file</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>read database properties from a file</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--format</literal></entry>
+                            <entry>format the generated SQL nicely in the script</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--delimiter=;</literal></entry>
+                            <entry>set an end of line delimiter for the script</entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                You may even embed <literal>SchemaExport</literal> in your application:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaExport(cfg).create(false, true);]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-4">
+            <title>Properties</title>
+
+            <para>
+                Database properties may be specified
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>as system properties with <literal>-D</literal><emphasis>&lt;property&gt;</emphasis></para>
+                </listitem>
+                <listitem>
+                    <para>in <literal>hibernate.properties</literal></para>
+                </listitem>
+                <listitem>
+                    <para>in a named properties file with <literal>--properties</literal></para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                The needed properties are:
+            </para>
+
+            <table frame="topbot">
+                <title>SchemaExport Connection Properties</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Property Name</entry>
+                            <entry>Description</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                    <row>
+                        <entry><literal>hibernate.connection.driver_class</literal></entry>
+                        <entry>jdbc driver class</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.url</literal></entry>
+                        <entry>jdbc url</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.username</literal></entry>
+                        <entry>database user</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.password</literal></entry>
+                        <entry>user password</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.dialect</literal></entry>
+                        <entry>dialect</entry>
+                    </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-5">
+            <title>Using Ant</title>
+
+            <para>
+                You can call <literal>SchemaExport</literal> from your Ant build script:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemaexport">
+    <taskdef name="schemaexport"
+        classname="org.hibernate.tool.hbm2ddl.SchemaExportTask"
+        classpathref="class.path"/>
+    
+    <schemaexport
+        properties="hibernate.properties"
+        quiet="no"
+        text="no"
+        drop="no"
+        delimiter=";"
+        output="schema-export.sql">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaexport>
+</target>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-6" revision="2">
+            <title>Incremental schema updates</title>
+
+            <para>
+                The <literal>SchemaUpdate</literal> tool will update an existing schema with "incremental" changes.
+                Note that <literal>SchemaUpdate</literal> depends heavily upon the JDBC metadata API, so it will
+                not work with all JDBC drivers.
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>options mapping_files</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaUpdate</literal> Command Line Options</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Option</entry>
+                            <entry>Description</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--quiet</literal></entry>
+                            <entry>don't output the script to stdout</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--text</literal></entry>
+                            <entry>don't export the script to the database</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>select a <literal>NamingStrategy</literal></entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>read database properties from a file</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry>specify a <literal>.cfg.xml</literal> file</entry>
+                        </row>
+                     </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                You may embed <literal>SchemaUpdate</literal> in your application:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaUpdate(cfg).execute(false);]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-7">
+            <title>Using Ant for incremental schema updates</title>
+
+            <para>
+                You can call <literal>SchemaUpdate</literal> from the Ant script:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemaupdate">
+    <taskdef name="schemaupdate"
+        classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask"
+        classpathref="class.path"/>
+    
+    <schemaupdate
+        properties="hibernate.properties"
+        quiet="no">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaupdate>
+</target>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-8" revision="1">
+            <title>Schema validation</title>
+
+            <para>
+                The <literal>SchemaValidator</literal> tool will validate that the existing database schema "matches"
+                your mapping documents. Note that <literal>SchemaValidator</literal> depends heavily upon the JDBC 
+                metadata API, so it will not work with all JDBC drivers. This tool is extremely useful for testing.
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaValidator</literal> <emphasis>options mapping_files</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaValidator</literal> Command Line Options</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Option</entry>
+                            <entry>Description</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>select a <literal>NamingStrategy</literal></entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>read database properties from a file</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry>specify a <literal>.cfg.xml</literal> file</entry>
+                        </row>
+                     </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                You may embed <literal>SchemaValidator</literal> in your application:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaValidator(cfg).validate();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-9">
+            <title>Using Ant for schema validation</title>
+
+            <para>
+                You can call <literal>SchemaValidator</literal> from the Ant script:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemavalidate">
+    <taskdef name="schemavalidator"
+        classname="org.hibernate.tool.hbm2ddl.SchemaValidatorTask"
+        classpathref="class.path"/>
+    
+    <schemavalidator
+        properties="hibernate.properties">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaupdate>
+</target>]]></programlisting>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/transactions.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/transactions.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/transactions.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1109 @@
+<chapter id="transactions" revision="2">
+    <title>Transactions And Concurrency</title>
+
+    <para>
+        The most important point about Hibernate and concurrency control is that it is very
+        easy to understand. Hibernate directly uses JDBC connections and JTA resources without
+        adding any additional locking behavior. We highly recommend you spend some time with the
+        JDBC, ANSI, and transaction isolation specification of your database management system.
+    </para>
+
+    <para>
+        Hibernate does not lock objects in memory. Your application can expect the behavior as
+        defined by the isolation level of your database transactions. Note that thanks to the
+        <literal>Session</literal>, which is also a transaction-scoped cache, Hibernate
+        provides repeatable reads for lookup by identifier and entity queries (not
+        reporting queries that return scalar values).
+    </para>
+
+    <para>
+        In addition to versioning for automatic optimistic concurrency control, Hibernate also
+        offers a (minor) API for pessimistic locking of rows, using the
+        <literal>SELECT FOR UPDATE</literal> syntax. Optimistic concurrency control and
+        this API are discussed later in this chapter.
+    </para>
+
+    <para>
+        We start the discussion of concurrency control in Hibernate with the granularity of
+        <literal>Configuration</literal>, <literal>SessionFactory</literal>, and
+        <literal>Session</literal>, as well as database transactions and long conversations.
+    </para>
+
+    <sect1 id="transactions-basics" revision="1">
+        <title>Session and transaction scopes</title>
+
+        <para>
+            A <literal>SessionFactory</literal> is an expensive-to-create, threadsafe object 
+            intended to be shared by all application threads. It is created once, usually on
+            application startup, from a <literal>Configuration</literal> instance.
+        </para>
+
+        <para>
+            A <literal>Session</literal> is an inexpensive, non-threadsafe object that should be
+            used once, for a single request, a conversation, single unit of work, and then discarded.
+            A <literal>Session</literal> will not obtain a JDBC <literal>Connection</literal>
+            (or a <literal>Datasource</literal>) unless it is needed, hence consume no
+            resources until used.
+        </para>
+
+        <para>
+            To complete this picture you also have to think about database transactions. A
+            database transaction has to be as short as possible, to reduce lock contention in
+            the database. Long database transactions will prevent your application from scaling
+            to highly concurrent load. Hence, it is almost never good design to hold a
+            database transaction open during user think time, until the unit of work is
+            complete.
+        </para>
+
+        <para>
+            What is the scope of a unit of work? Can a single Hibernate <literal>Session</literal>
+            span several database transactions or is this a one-to-one relationship of scopes? When
+            should you open and close a <literal>Session</literal> and how do you demarcate the
+            database transaction boundaries?
+        </para>
+
+        <sect2 id="transactions-basics-uow" revision="1">
+            <title>Unit of work</title>
+
+            <para>
+                First, don't use the <emphasis>session-per-operation</emphasis> antipattern, that is,
+                don't open and close a <literal>Session</literal> for every simple database call in
+                a single thread! Of course, the same is true for database transactions. Database calls
+                in an application are made using a planned sequence, they are grouped into atomic
+                units of work. (Note that this also means that auto-commit after every single
+                SQL statement is useless in an application, this mode is intended for ad-hoc SQL
+                console work. Hibernate disables, or expects the application server to do so,
+                auto-commit mode immediately.) Database transactions are never optional, all
+                communication with a database has to occur inside a transaction, no matter if
+                you read or write data. As explained, auto-commit behavior for reading data
+                should be avoided, as many small transactions are unlikely to perform better than
+                one clearly defined unit of work. The latter is also much more maintainable
+                and extensible.
+            </para>
+
+            <para>
+                The most common pattern in a multi-user client/server application is
+                <emphasis>session-per-request</emphasis>. In this model, a request from the client
+                is send to the server (where the Hibernate persistence layer runs), a new Hibernate
+                <literal>Session</literal> is opened, and all database operations are executed in this unit
+                of work. Once the work has been completed (and the response for the client has been prepared),
+                the session is flushed and closed. You would also use a single database transaction to
+                serve the clients request, starting and committing it when you open and close the
+                <literal>Session</literal>. The relationship between the two is one-to-one and this
+                model is a perfect fit for many applications.
+            </para>
+
+            <para>
+                The challenge lies in the implementation. Hibernate provides built-in management of
+                the "current session" to simplify this pattern. All you have to do is start a
+                transaction when a server request has to be processed, and end the transaction
+                before the response is send to the client. You can do this in any way you
+                like, common solutions are <literal>ServletFilter</literal>, AOP interceptor with a
+                pointcut on the service methods, or a proxy/interception container. An EJB container
+                is a standardized way to implement cross-cutting aspects such as transaction
+                demarcation on EJB session beans, declaratively with CMT. If you decide to
+                use programmatic transaction demarcation, prefer the Hibernate <literal>Transaction</literal>
+                API shown later in this chapter, for ease of use and code portability.
+            </para>
+
+            <para>
+                Your application code can access a "current session" to process the request
+                by simply calling <literal>sessionFactory.getCurrentSession()</literal> anywhere
+                and as often as needed. You will always get a <literal>Session</literal> scoped
+                to the current database transaction. This has to be configured for either
+                resource-local or JTA environments, see <xref linkend="architecture-current-session"/>.
+            </para>
+
+            <para>
+                Sometimes it is convenient to extend the scope of a <literal>Session</literal> and
+                database transaction until the "view has been rendered". This is especially useful
+                in servlet applications that utilize a separate rendering phase after the request
+                has been processed. Extending the database transaction until view rendering is
+                complete is easy to do if you implement your own interceptor. However, it is not
+                easily doable if you rely on EJBs with container-managed transactions, as a
+                transaction will be completed when an EJB method returns, before rendering of any
+                view can start. See the Hibernate website and forum for tips and examples around
+                this <emphasis>Open Session in View</emphasis> pattern.
+             </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-apptx" revision="1">
+            <title>Long conversations</title>
+
+            <para>
+                The session-per-request pattern is not the only useful concept you can use to design
+                units of work. Many business processes require a whole series of interactions with the user
+                interleaved with database accesses. In web and enterprise applications it is
+                not acceptable for a database transaction to span a user interaction. Consider the following
+                example:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        The first screen of a dialog opens, the data seen by the user has been loaded in
+                        a particular <literal>Session</literal> and database transaction. The user is free to
+                        modify the objects.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        The user clicks "Save" after 5 minutes and expects his modifications to be made
+                        persistent; he also expects that he was the only person editing this information and
+                        that no conflicting modification can occur.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                We call this unit of work, from the point of view of the user, a long running
+                <emphasis>conversation</emphasis> (or <emphasis>application transaction</emphasis>).
+                There are many ways how you can implement this in your application.
+            </para>
+
+            <para>
+                A first naive implementation might keep the <literal>Session</literal> and database
+                transaction open during user think time, with locks held in the database to prevent
+                concurrent modification, and to guarantee isolation and atomicity. This is of course
+                an anti-pattern, since lock contention would not allow the application to scale with
+                the number of concurrent users.
+            </para>
+
+            <para>
+                Clearly, we have to use several database transactions to implement the converastion.
+                In this case, maintaining isolation of business processes becomes the
+                partial responsibility of the application tier. A single conversation
+                usually spans several database transactions. It will be atomic if only one of
+                these database transactions (the last one) stores the updated data, all others
+                simply read data (e.g. in a wizard-style dialog spanning several request/response
+                cycles). This is easier to implement than it might sound, especially if
+                you use Hibernate's features:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <emphasis>Automatic Versioning</emphasis> - Hibernate can do automatic
+                        optimistic concurrency control for you, it can automatically detect
+                        if a concurrent modification occured during user think time. Usually
+                        we only check at the end of the conversation.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <emphasis>Detached Objects</emphasis> - If you decide to use the already
+                        discussed <emphasis>session-per-request</emphasis> pattern, all loaded instances
+                        will be in detached state during user think time. Hibernate allows you to
+                        reattach the objects and persist the modifications, the pattern is called
+                        <emphasis>session-per-request-with-detached-objects</emphasis>. Automatic
+                        versioning is used to isolate concurrent modifications.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <emphasis>Extended (or Long) Session</emphasis> - The Hibernate
+                        <literal>Session</literal> may be disconnected from the underlying JDBC
+                        connection after the database transaction has been committed, and reconnected
+                        when a new client request occurs. This pattern is known as
+                        <emphasis>session-per-conversation</emphasis> and makes
+                        even reattachment unnecessary. Automatic versioning is used to isolate
+                        concurrent modifications and the <literal>Session</literal> is usually
+                        not allowed to be flushed automatically, but explicitely.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Both <emphasis>session-per-request-with-detached-objects</emphasis> and
+                <emphasis>session-per-conversation</emphasis> have advantages and disadvantages,
+                we discuss them later in this chapter in the context of optimistic concurrency control.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-identity">
+            <title>Considering object identity</title>
+
+            <para>
+                An application may concurrently access the same persistent state in two
+                different <literal>Session</literal>s. However, an instance of a persistent class
+                is never shared between two <literal>Session</literal> instances. Hence there are
+                two different notions of identity:
+            </para>
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term>Database Identity</term>
+                    <listitem>
+                        <para>
+                            <literal>foo.getId().equals( bar.getId() )</literal>
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>JVM Identity</term>
+                    <listitem>
+                        <para>
+                            <literal>foo==bar</literal>
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+            <para>
+                Then for objects attached to a <emphasis>particular</emphasis> <literal>Session</literal>
+                (i.e. in the scope of a <literal>Session</literal>) the two notions are equivalent, and
+                JVM identity for database identity is guaranteed by Hibernate. However, while the application
+                might concurrently access the "same" (persistent identity) business object in two different
+                sessions, the two instances will actually be "different" (JVM identity). Conflicts are
+                resolved using (automatic versioning) at flush/commit time, using an optimistic approach.
+            </para>
+
+            <para>
+                This approach leaves Hibernate and the database to worry about concurrency; it also provides
+                the best scalability, since guaranteeing identity in single-threaded units of work only doesn't
+                need expensive locking or other means of synchronization. The application never needs to
+                synchronize on any business object, as long as it sticks to a single thread per
+                <literal>Session</literal>. Within a <literal>Session</literal> the  application may safely use
+                <literal>==</literal> to compare objects.
+            </para>
+
+            <para>
+                However, an application that uses <literal>==</literal> outside of a <literal>Session</literal>,
+                might see unexpected results. This might occur even in some unexpected places, for example,
+                if you put two detached instances into the same <literal>Set</literal>. Both might have the same
+                database identity (i.e. they represent the same row), but JVM identity is by definition not
+                guaranteed for instances in detached state. The developer has to override the <literal>equals()</literal>
+                and <literal>hashCode()</literal> methods in persistent classes and implement
+                his own notion of object equality. There is one caveat: Never use the database
+                identifier to implement equality, use a business key, a combination of unique, usually
+                immutable, attributes. The database identifier will change if a transient object is made
+                persistent. If the transient instance (usually together with detached instances) is held in a
+                <literal>Set</literal>, changing the hashcode breaks the contract of the <literal>Set</literal>.
+                Attributes for business keys don't have to be as stable as database primary keys, you only
+                have to guarantee stability as long as the objects are in the same <literal>Set</literal>. See
+                the Hibernate website for a more thorough discussion of this issue. Also note that this is not
+                a Hibernate issue, but simply how Java object identity and equality has to be implemented.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-issues">
+            <title>Common issues</title>
+
+             <para>
+                 Never use the anti-patterns <emphasis>session-per-user-session</emphasis> or
+                 <emphasis>session-per-application</emphasis> (of course, there are rare exceptions to
+                 this rule). Note that some of the following issues might also appear with the recommended
+                 patterns, make sure you understand the implications before making a design decision:
+             </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        A <literal>Session</literal> is not thread-safe. Things which are supposed to work
+                        concurrently, like HTTP requests, session beans, or Swing workers, will cause race
+                        conditions if a <literal>Session</literal> instance would be shared. If you keep your
+                        Hibernate <literal>Session</literal> in your <literal>HttpSession</literal> (discussed
+                        later), you should consider synchronizing access to your Http session. Otherwise,
+                        a user that clicks reload fast enough may use the same <literal>Session</literal> in
+                        two concurrently running threads.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        An exception thrown by Hibernate means you have to rollback your database transaction
+                        and close the <literal>Session</literal> immediately (discussed later in more detail).
+                        If your <literal>Session</literal> is bound to the application, you have to stop
+                        the application. Rolling back the database transaction doesn't put your business
+                        objects back into the state they were at the start of the transaction. This means the
+                        database state and the business objects do get out of sync. Usually this is not a
+                        problem, because exceptions are not recoverable and you have to start over after
+                        rollback anyway.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        The <literal>Session</literal> caches every object that is in persistent state (watched
+                        and checked for dirty state by Hibernate). This means it grows endlessly until you
+                        get an OutOfMemoryException, if you keep it open for a long time or simply load too
+                        much data. One solution for this is to call <literal>clear()</literal> and <literal>evict()</literal>
+                        to manage the <literal>Session</literal> cache, but you most likely should consider a
+                        Stored Procedure if you need mass data operations. Some solutions are shown in
+                        <xref linkend="batch"/>. Keeping a <literal>Session</literal> open for the duration
+                        of a user session also means a high probability of stale data.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="transactions-demarcation">
+        <title>Database transaction demarcation</title>
+
+        <para>
+            Datatabase (or system) transaction boundaries are always necessary. No communication with
+            the database can occur outside of a database transaction (this seems to confuse many developers
+            who are used to the auto-commit mode). Always use clear transaction boundaries, even for
+            read-only operations. Depending on your isolation level and database capabilities this might not
+            be required but there is no downside if you always demarcate transactions explicitly. Certainly,
+            a single database transaction is going to perform better than many small transactions, even
+            for reading data.
+        </para>
+
+        <para>
+            A Hibernate application can run in non-managed (i.e. standalone, simple Web- or Swing applications)
+            and managed J2EE environments. In a non-managed environment, Hibernate is usually responsible for
+            its own database connection pool. The application developer has to manually set transaction
+            boundaries, in other words, begin, commit, or rollback database transactions himself. A managed environment
+            usually provides container-managed transactions (CMT), with the transaction assembly defined declaratively
+            in deployment descriptors of EJB session beans, for example. Programmatic transaction demarcation is
+            then no longer necessary.
+        </para>
+
+        <para>
+            However, it is often desirable to keep your persistence layer portable between non-managed
+            resource-local environments, and systems that can rely on JTA but use BMT instead of CMT.
+            In both cases you'd use programmatic transaction demaracation. Hibernate offers a wrapper
+            API called <literal>Transaction</literal> that translates into the native transaction system of
+            your deployment environment. This API is actually optional, but we strongly encourage its use
+            unless you are in a CMT session bean.
+        </para>
+
+        <para>
+            Usually, ending a <literal>Session</literal> involves four distinct phases:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    flush the session
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    commit the transaction
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    close the session
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    handle exceptions
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Flushing the session has been discussed earlier, we'll now have a closer look at transaction
+            demarcation and exception handling in both managed- and non-managed environments.
+        </para>
+
+
+        <sect2 id="transactions-demarcation-nonmanaged" revision="2">
+            <title>Non-managed environment</title>
+
+            <para>
+                If a Hibernate persistence layer runs in a non-managed environment, database connections
+                are usually handled by simple (i.e. non-DataSource) connection pools from which
+	            Hibernate obtains connections as needed. The session/transaction handling idiom looks
+	            like this:
+            </para>
+
+            <programlisting><![CDATA[// Non-managed environment idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+    tx = sess.beginTransaction();
+
+    // do some work
+    ...
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    if (tx != null) tx.rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+            <para>
+                You don't have to <literal>flush()</literal> the <literal>Session</literal> explicitly -
+                the call to <literal>commit()</literal> automatically triggers the synchronization (depending
+	            upon the <xref linkend="objectstate-flushing">FlushMode</xref> for the session.
+                A call to <literal>close()</literal> marks the end of a session. The main implication
+                of <literal>close()</literal> is that the JDBC connection will be relinquished by the
+                session. This Java code is portable and runs in both non-managed and JTA environments.
+            </para>
+
+           <para>
+                A much more flexible solution is Hibernate's built-in "current session" context
+                management, as described earlier:
+            </para>
+
+            <programlisting><![CDATA[// Non-managed environment idiom with getCurrentSession()
+try {
+    factory.getCurrentSession().beginTransaction();
+
+    // do some work
+    ...
+
+    factory.getCurrentSession().getTransaction().commit();
+}
+catch (RuntimeException e) {
+    factory.getCurrentSession().getTransaction().rollback();
+    throw e; // or display error message
+}]]></programlisting>
+
+            <para>
+                You will very likely never see these code snippets in a regular application;
+                fatal (system) exceptions should always be caught at the "top". In other words, the
+                code that executes Hibernate calls (in the persistence layer) and the code that handles
+                <literal>RuntimeException</literal> (and usually can only clean up and exit) are in
+                different layers. The current context management by Hibernate can significantly
+                simplify this design, as all you need is access to a <literal>SessionFactory</literal>.
+                Exception handling is discussed later in this chapter.
+            </para>
+
+           <para>
+                Note that you should select <literal>org.hibernate.transaction.JDBCTransactionFactory</literal>
+                (which is the default), and for the second example <literal>"thread"</literal> as your
+                <literal>hibernate.current_session_context_class</literal>.
+            </para>
+            
+        </sect2>
+
+        <sect2 id="transactions-demarcation-jta" revision="3">
+            <title>Using JTA</title>
+
+            <para>
+                If your persistence layer runs in an application server (e.g. behind EJB session beans),
+                every datasource connection obtained by Hibernate will automatically be part of the global
+                JTA transaction. You can also install a standalone JTA implementation and use it without
+                EJB. Hibernate offers two strategies for JTA integration.
+            </para>
+
+            <para>
+                If you use bean-managed transactions (BMT) Hibernate will tell the application server to start
+                and end a BMT transaction if you use the <literal>Transaction</literal> API. So, the
+                transaction management code is identical to the non-managed environment.
+            </para>
+            
+           <programlisting><![CDATA[// BMT idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+    tx = sess.beginTransaction();
+
+    // do some work
+    ...
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    if (tx != null) tx.rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+           <para>
+                If you want to use a transaction-bound <literal>Session</literal>, that is, the
+               <literal>getCurrentSession()</literal> functionality for easy context propagation,
+               you will have to use the JTA <literal>UserTransaction</literal> API directly:
+            </para>
+
+            <programlisting><![CDATA[// BMT idiom with getCurrentSession()
+try {
+    UserTransaction tx = (UserTransaction)new InitialContext()
+                            .lookup("java:comp/UserTransaction");
+
+    tx.begin();
+
+    // Do some work on Session bound to transaction
+    factory.getCurrentSession().load(...);
+    factory.getCurrentSession().persist(...);
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    tx.rollback();
+    throw e; // or display error message
+}]]></programlisting>
+
+            <para>
+                With CMT, transaction demarcation is done in session bean deployment descriptors, not programatically,
+                hence, the code is reduced to:
+            </para>
+
+            <programlisting><![CDATA[// CMT idiom
+ Session sess = factory.getCurrentSession();
+
+ // do some work
+ ...
+]]></programlisting>
+
+            <para>
+                In a CMT/EJB even rollback happens automatically, since an unhandled <literal>RuntimeException</literal>
+                thrown  by a session bean method tells the container to set the global transaction to rollback.
+                <emphasis>This means you do not need to use the Hibernate <literal>Transaction</literal> API at
+                all with BMT or CMT, and you get automatic propagation of the "current" Session bound to the
+                transaction.</emphasis>
+            </para>
+
+            <para>
+                Note that you should choose <literal>org.hibernate.transaction.JTATransactionFactory</literal>
+                if you use JTA directly (BMT), and <literal>org.hibernate.transaction.CMTTransactionFactory</literal>
+                in a CMT session bean, when you configure Hibernate's transaction factory. Remember to also set
+                <literal>hibernate.transaction.manager_lookup_class</literal>. Furthermore, make sure
+                that your <literal>hibernate.current_session_context_class</literal> is either unset (backwards
+                compatiblity), or set to <literal>"jta"</literal>.
+            </para>
+
+            <para>
+                The <literal>getCurrentSession()</literal> operation has one downside in a JTA environment.
+                There is one caveat to the use of <literal>after_statement</literal> connection release
+                mode, which is then used by default. Due to a silly limitation of the JTA spec, it is not
+                possible for Hibernate to automatically clean up any unclosed <literal>ScrollableResults</literal> or
+                <literal>Iterator</literal> instances returned by <literal>scroll()</literal> or 
+                <literal>iterate()</literal>. You <emphasis>must</emphasis> release the underlying database 
+                cursor by calling <literal>ScrollableResults.close()</literal> or 
+                <literal>Hibernate.close(Iterator)</literal> explicity from a <literal>finally</literal> 
+                block. (Of course, most applications can easily avoid using <literal>scroll()</literal> or 
+                <literal>iterate()</literal> at all from the JTA or CMT code.)
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-demarcation-exceptions">
+            <title>Exception handling</title>
+
+            <para>
+                If the <literal>Session</literal> throws an exception (including any
+                <literal>SQLException</literal>), you should immediately rollback the database
+                transaction, call <literal>Session.close()</literal> and discard the
+                <literal>Session</literal> instance. Certain methods of <literal>Session</literal>
+                will <emphasis>not</emphasis> leave the session in a consistent state. No
+                exception thrown by Hibernate can be treated as recoverable. Ensure that the
+                <literal>Session</literal> will be closed by calling <literal>close()</literal>
+                in a <literal>finally</literal> block.
+            </para>
+
+            <para>
+                The <literal>HibernateException</literal>, which wraps most of the errors that
+                can occur in a Hibernate persistence layer, is an unchecked exception (it wasn't
+                in older versions of Hibernate). In our opinion, we shouldn't force the application
+                developer to catch an unrecoverable exception at a low layer. In most systems, unchecked
+                and fatal exceptions are handled in one of the first frames of the method call
+                stack (i.e. in higher layers) and an error message is presented to the application
+                user (or some other appropriate action is taken). Note that Hibernate might also throw
+                other unchecked exceptions which are not a <literal>HibernateException</literal>. These 
+                are, again, not recoverable and appropriate action should be taken.
+            </para>
+
+            <para>
+                Hibernate wraps <literal>SQLException</literal>s thrown while interacting with the database
+                in a <literal>JDBCException</literal>. In fact, Hibernate will attempt to convert the eexception
+                into a more meningful subclass of <literal>JDBCException</literal>.  The underlying
+                <literal>SQLException</literal> is always available via <literal>JDBCException.getCause()</literal>.
+                Hibernate converts the <literal>SQLException</literal> into an appropriate 
+                <literal>JDBCException</literal> subclass using the <literal>SQLExceptionConverter</literal> 
+                attached to the <literal>SessionFactory</literal>. By default, the 
+                <literal>SQLExceptionConverter</literal> is defined by the configured dialect; however, it is
+                also possible to plug in a custom implementation (see the javadocs for the
+                <literal>SQLExceptionConverterFactory</literal> class for details).  The standard 
+                <literal>JDBCException</literal> subtypes are:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>JDBCConnectionException</literal> - indicates an error
+                        with the underlying JDBC communication.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>SQLGrammarException</literal> - indicates a grammar
+                        or syntax problem with the issued SQL.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>ConstraintViolationException</literal> - indicates some
+                        form of integrity constraint violation.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>LockAcquisitionException</literal> - indicates an error
+                        acquiring a lock level necessary to perform the requested operation.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>GenericJDBCException</literal> - a generic exception
+                        which did not fall into any of the other categories.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+        </sect2>
+
+        <sect2 id="transactions-demarcation-timeout">
+            <title>Transaction timeout</title>
+
+            <para>
+                One extremely important feature provided by a managed environment like EJB
+                that is never provided for non-managed code is transaction timeout. Transaction
+                timeouts ensure that no misbehaving transaction can indefinitely tie up 
+                resources while returning no response to the user. Outside a managed (JTA)
+                environment, Hibernate cannot fully provide this functionality. However,
+                Hibernate can at least control data access operations, ensuring that database
+                level deadlocks and queries with huge result sets are limited by a defined
+                timeout. In a managed environment, Hibernate can delegate transaction timeout
+                to JTA. This functioanlity is abstracted by the Hibernate 
+                <literal>Transaction</literal> object.
+            </para>
+            
+            <programlisting><![CDATA[
+Session sess = factory.openSession();
+try {
+    //set transaction timeout to 3 seconds
+    sess.getTransaction().setTimeout(3);
+    sess.getTransaction().begin();
+
+    // do some work
+    ...
+
+    sess.getTransaction().commit()
+}
+catch (RuntimeException e) {
+    sess.getTransaction().rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+            <para>
+                Note that <literal>setTimeout()</literal> may not be called in a CMT bean,
+                where transaction timeouts must be defined declaratively.
+            </para>
+            
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="transactions-optimistic">
+        <title>Optimistic concurrency control</title>
+
+        <para>
+            The only approach that is consistent with high concurrency and high
+            scalability is optimistic concurrency control with versioning. Version
+            checking uses version numbers, or timestamps, to detect conflicting updates
+            (and to prevent lost updates). Hibernate provides for three possible approaches
+            to writing application code that uses optimistic concurrency. The use cases
+            we show are in the context of long conversations, but version checking
+            also has the benefit of preventing lost updates in single database transactions.
+        </para>
+
+        <sect2 id="transactions-optimistic-manual">
+            <title>Application version checking</title>
+
+            <para>
+                In an implementation without much help from Hibernate, each interaction with the
+                database occurs in a new <literal>Session</literal> and the developer is responsible
+                for reloading all persistent instances from the database before manipulating them.
+                This approach forces the application to carry out its own version checking to ensure
+                conversation transaction isolation. This approach is the least efficient in terms of
+                database access. It is the approach most similar to entity EJBs.
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+
+int oldVersion = foo.getVersion();
+session.load( foo, foo.getKey() ); // load the current state
+if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();
+foo.setProperty("bar");
+
+t.commit();
+session.close();]]></programlisting>
+
+            <para>
+                The <literal>version</literal> property is mapped using <literal>&lt;version&gt;</literal>,
+                and Hibernate will automatically increment it during flush if the entity is
+                dirty.
+            </para>
+
+            <para>
+                Of course, if you are operating in a low-data-concurrency environment and don't
+                require version checking, you may use this approach and just skip the version
+                check. In that case, <emphasis>last commit wins</emphasis> will be the default
+                strategy for your long conversations. Keep in mind that this might
+                confuse the users of the application, as they might experience lost updates without
+                error messages or a chance to merge conflicting changes.
+            </para>
+
+            <para>
+                Clearly, manual version checking is only feasible in very trivial circumstances
+                and not practical for most applications. Often not only single instances, but
+                complete graphs of modified ojects have to be checked. Hibernate offers automatic
+                version checking with either an extended <literal>Session</literal> or detached instances
+                as the design paradigm.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-longsession">
+            <title>Extended session and automatic versioning</title>
+
+            <para>
+                A single <literal>Session</literal> instance and its persistent instances are
+                used for the whole conversation, known as <emphasis>session-per-conversation</emphasis>.
+                Hibernate checks instance versions at flush time, throwing an exception if concurrent
+                modification is detected. It's up to the developer to catch and handle this exception
+                (common options are the opportunity for the user to merge changes or to restart the
+                business conversation with non-stale data).
+            </para>
+
+            <para>
+                The <literal>Session</literal> is disconnected from any underlying JDBC connection
+                when waiting for user interaction. This approach is the most efficient in terms
+                of database access. The application need not concern itself with version checking or
+                with reattaching detached instances, nor does it have to reload instances in every
+                database transaction.
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded earlier by the old session
+Transaction t = session.beginTransaction(); // Obtain a new JDBC connection, start transaction
+
+foo.setProperty("bar");
+
+session.flush();    // Only for last transaction in conversation
+t.commit();         // Also return JDBC connection
+session.close();    // Only for last transaction in conversation]]></programlisting>
+            <para>
+                The <literal>foo</literal> object still knows which <literal>Session</literal> it was
+                loaded in. Beginning a new database transaction on an old session obtains a new connection
+                and resumes the session. Committing a database transaction disconnects a session
+                from the JDBC connection and returns the connection to the pool. After reconnection, to
+                force a version check on data  you aren't updating, you may call <literal>Session.lock()</literal>
+                with <literal>LockMode.READ</literal> on any objects that might have been updated by another
+                transaction. You don't need to lock any data that you <emphasis>are</emphasis> updating.
+                Usually you would set <literal>FlushMode.NEVER</literal> on an extended <literal>Session</literal>,
+                so that only the last database transaction cycle is allowed to actually persist all
+                modifications made in this conversation. Hence, only this last database transaction
+                would include the <literal>flush()</literal> operation, and then also
+                <literal>close()</literal> the session to end the conversation.
+            </para>
+            
+            <para>
+                This pattern is problematic if the <literal>Session</literal> is too big to
+                be stored during user think time, e.g. an <literal>HttpSession</literal> should
+                be kept as small as possible. As the <literal>Session</literal> is also the
+                (mandatory) first-level cache and contains all loaded objects, we can probably
+                use this strategy only for a few request/response cycles. You should use a
+                <literal>Session</literal> only for a single conversation, as it will soon also
+                have stale data.
+            </para>
+
+            <para>
+                (Note that earlier Hibernate versions required explicit disconnection and reconnection
+                of a <literal>Session</literal>. These methods are deprecated, as beginning and
+                ending a transaction has the same effect.)
+            </para>
+
+            <para>
+                Also note that you should keep the disconnected <literal>Session</literal> close
+                to the persistence layer. In other words, use an EJB stateful session bean to
+                hold the <literal>Session</literal> in a three-tier environment, and don't transfer
+                it to the web layer (or even serialize it to a separate tier) to store it in the
+                <literal>HttpSession</literal>.
+            </para>
+
+            <para>
+                The extended session pattern, or <emphasis>session-per-conversation</emphasis>, is
+                more difficult to implement with automatic current session context management.
+                You need to supply your own implementation of the <literal>CurrentSessionContext</literal>
+                for this, see the Hibernate Wiki for examples.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-detached">
+            <title>Detached objects and automatic versioning</title>
+
+            <para>
+                Each interaction with the persistent store occurs in a new <literal>Session</literal>.
+                However, the same persistent instances are reused for each interaction with the database.
+                The application manipulates the state of detached instances originally loaded in another
+                <literal>Session</literal> and then reattaches them using <literal>Session.update()</literal>,
+                <literal>Session.saveOrUpdate()</literal>, or <literal>Session.merge()</literal>.
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+foo.setProperty("bar");
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded already
+t.commit();
+session.close();]]></programlisting>
+
+            <para>
+                Again, Hibernate will check instance versions during flush, throwing an
+                exception if conflicting updates occured.
+            </para>
+
+            <para>
+                You may also call <literal>lock()</literal> instead of <literal>update()</literal>
+                and use <literal>LockMode.READ</literal> (performing a version check, bypassing all
+                caches) if you are sure that the object has not been modified.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-customizing">
+            <title>Customizing automatic versioning</title>
+
+            <para>
+                You may disable Hibernate's automatic version increment for particular properties and 
+                collections by setting the <literal>optimistic-lock</literal> mapping attribute to 
+                <literal>false</literal>. Hibernate will then no longer increment versions if the 
+                property is dirty.
+            </para>
+
+            <para>
+                Legacy database schemas are often static and can't be modified. Or, other applications
+                might also access the same database and don't know how to handle version numbers or
+                even timestamps. In both cases, versioning can't rely on a particular column in a table.
+                To force a version check without a version or timestamp property mapping, with a
+                comparison of the state of all fields in a row, turn on <literal>optimistic-lock="all"</literal>
+                in the <literal>&lt;class&gt;</literal> mapping. Note that this concepetually only works
+                if Hibernate can compare the old and new state, i.e. if you use a single long
+                <literal>Session</literal> and not session-per-request-with-detached-objects.
+            </para>
+
+            <para>
+                Sometimes concurrent modification can be permitted as long as the changes that have been
+                made don't overlap. If you set <literal>optimistic-lock="dirty"</literal> when mapping the
+                <literal>&lt;class&gt;</literal>, Hibernate will only compare dirty fields during flush.
+            </para>
+
+            <para>
+                In both cases, with dedicated version/timestamp columns or with full/dirty field
+                comparison, Hibernate uses a single <literal>UPDATE</literal> statement (with an
+                appropriate <literal>WHERE</literal> clause) per entity to execute the version check
+                and update the information. If you use transitive persistence to cascade reattachment
+                to associated entities, Hibernate might execute uneccessary updates. This is usually
+                not a problem, but <emphasis>on update</emphasis> triggers in the database might be
+                executed even when no changes have been made to detached instances. You can customize
+                this behavior by setting  <literal>select-before-update="true"</literal> in the
+                <literal>&lt;class&gt;</literal> mapping, forcing Hibernate to <literal>SELECT</literal>
+                the instance to ensure that changes did actually occur, before updating the row.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="transactions-locking">
+        <title>Pessimistic Locking</title>
+
+        <para>
+            It is not intended that users spend much time worring about locking strategies. Its usually
+            enough to specify an isolation level for the JDBC connections and then simply let the
+            database do all the work. However, advanced users may sometimes wish to obtain
+            exclusive pessimistic locks, or re-obtain locks at the start of a new transaction.
+        </para>
+
+        <para>
+            Hibernate will always use the locking mechanism of the database, never lock objects
+            in memory!
+        </para>
+
+        <para>
+            The <literal>LockMode</literal> class defines the different lock levels that may be acquired
+            by Hibernate. A lock is obtained by the following mechanisms:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>LockMode.WRITE</literal> is acquired automatically when Hibernate updates or inserts
+                    a row.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.UPGRADE</literal> may be acquired upon explicit user request using
+                    <literal>SELECT ... FOR UPDATE</literal> on databases which support that syntax.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.UPGRADE_NOWAIT</literal> may be acquired upon explicit user request using a
+                    <literal>SELECT ... FOR UPDATE NOWAIT</literal> under Oracle.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.READ</literal> is acquired automatically when Hibernate reads data
+                    under Repeatable Read or Serializable isolation level. May be re-acquired by explicit user
+                    request.
+                </para>
+            </listitem>
+        <listitem>
+        <para>
+            <literal>LockMode.NONE</literal> represents the absence of a lock. All objects switch to this
+            lock mode at the end of a <literal>Transaction</literal>. Objects associated with the session
+            via a call to <literal>update()</literal> or <literal>saveOrUpdate()</literal> also start out
+            in this lock mode.
+        </para>
+        </listitem>
+        </itemizedlist>
+
+        <para>
+            The "explicit user request" is expressed in one of the following ways:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    A call to <literal>Session.load()</literal>, specifying a <literal>LockMode</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    A call to <literal>Session.lock()</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    A call to <literal>Query.setLockMode()</literal>.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            If <literal>Session.load()</literal> is called with <literal>UPGRADE</literal> or
+            <literal>UPGRADE_NOWAIT</literal>, and the requested object was not yet loaded by
+            the session, the object is loaded using <literal>SELECT ... FOR UPDATE</literal>.
+            If <literal>load()</literal> is called for an object that is already loaded with
+            a less restrictive lock than the one requested, Hibernate calls
+            <literal>lock()</literal> for that object.
+        </para>
+
+        <para>
+            <literal>Session.lock()</literal> performs a version number check if the specified lock
+            mode is <literal>READ</literal>, <literal>UPGRADE</literal> or
+            <literal>UPGRADE_NOWAIT</literal>. (In the case of <literal>UPGRADE</literal> or
+            <literal>UPGRADE_NOWAIT</literal>, <literal>SELECT ... FOR UPDATE</literal> is used.)
+        </para>
+
+        <para>
+            If the database does not support the requested lock mode, Hibernate will use an appropriate
+            alternate mode (instead of throwing an exception). This ensures that applications will
+            be portable.
+        </para>
+
+    </sect1>
+
+    <sect1 id="transactions-connection-release">
+        <title>Connection Release Modes</title>
+
+        <para>
+            The legacy (2.x) behavior of Hibernate in regards to JDBC connection management
+            was that a <literal>Session</literal> would obtain a connection when it was first
+            needed and then hold unto that connection until the session was closed.
+            Hibernate 3.x introduced the notion of connection release modes to tell a session
+            how to handle its JDBC connections.  Note that the following discussion is pertinent
+            only to connections provided through a configured <literal>ConnectionProvider</literal>;
+            user-supplied connections are outside the breadth of this discussion.  The different
+            release modes are identified by the enumerated values of
+            <literal>org.hibernate.ConnectionReleaseMode</literal>:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>ON_CLOSE</literal> - is essentially the legacy behavior described above. The
+                    Hibernate session obatins a connection when it first needs to perform some JDBC access
+                    and holds unto that connection until the session is closed.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>AFTER_TRANSACTION</literal> - says to release connections after a
+                    <literal>org.hibernate.Transaction</literal> has completed.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>AFTER_STATEMENT</literal> (also referred to as aggressive release) - says to
+                    release connections after each and every statement execution. This aggressive releasing
+                    is skipped if that statement leaves open resources associated with the given session;
+                    currently the only situation where this occurs is through the use of
+                    <literal>org.hibernate.ScrollableResults</literal>.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            The configuration parameter <literal>hibernate.connection.release_mode</literal> is used
+            to specify which release mode to use.  The possible values:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>auto</literal> (the default) - this choice delegates to the release mode
+                    returned by the <literal>org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode()</literal>
+                    method.  For JTATransactionFactory, this returns ConnectionReleaseMode.AFTER_STATEMENT; for
+                    JDBCTransactionFactory, this returns ConnectionReleaseMode.AFTER_TRANSACTION.  It is rarely
+                    a good idea to change this default behavior as failures due to the value of this setting
+                    tend to indicate bugs and/or invalid assumptions in user code.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>on_close</literal> - says to use ConnectionReleaseMode.ON_CLOSE.  This setting
+                    is left for backwards compatibility, but its use is highly discouraged.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>after_transaction</literal> - says to use ConnectionReleaseMode.AFTER_TRANSACTION.
+                    This setting should not be used in JTA environments.  Also note that with
+                    ConnectionReleaseMode.AFTER_TRANSACTION, if a session is considered to be in auto-commit
+                    mode connections will be released as if the release mode were AFTER_STATEMENT.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>after_statement</literal> - says to use ConnectionReleaseMode.AFTER_STATEMENT.  Additionally,
+                    the configured <literal>ConnectionProvider</literal> is consulted to see if it supports this
+                    setting (<literal>supportsAggressiveRelease()</literal>).  If not, the release mode is reset
+                    to ConnectionReleaseMode.AFTER_TRANSACTION.  This setting is only safe in environments where
+                    we can either re-acquire the same underlying JDBC connection each time we make a call into
+                    <literal>ConnectionProvider.getConnection()</literal> or in auto-commit environments where
+                    it does not matter whether we get back the same connection.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/tutorial.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/tutorial.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/tutorial.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1554 @@
+<chapter id="tutorial">
+    <title>Introduction to Hibernate</title>
+    
+    <sect1 id="tutorial-intro" revision="1">
+        <title>Preface</title>
+        
+        <para>
+            This chapter is an introductory tutorial for new users of Hibernate. We start
+            with a simple command line application using an in-memory database and develop
+            it in easy to understand steps.
+        </para>
+
+        <para>
+            This tutorial is intended for new users of Hibernate but requires Java and
+            SQL knowledge. It is based on a tutorial by Michael Gloegl, the third-party
+            libraries we name are for JDK 1.4 and 5.0. You might need others for JDK 1.3.
+        </para>
+
+        <para>
+            The source code for the tutorial is included in the distribution in the
+            <literal>doc/reference/tutorial/</literal> directory.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="tutorial-firstapp" revision="2">
+        <title>Part 1 - The first Hibernate Application</title>
+
+        <para>
+            First, we'll create a simple console-based Hibernate application. We use an
+            Java database (HSQL DB), so we do not have to install any database server.
+        </para>
+
+        <para>
+            Let's assume we need a small database application that can store events we want to
+            attend, and information about the hosts of these events.
+        </para>
+            
+        <para>
+            The first thing we do, is set up our development directory and put all the
+            Java libraries we need into it. Download the Hibernate distribution from the
+            Hibernate website. Extract the package and place all required libraries
+            found in <literal>/lib</literal> into into the <literal>/lib</literal> directory
+            of your new development working directory. It should look like this:
+        </para>
+            
+        <programlisting><![CDATA[.
++lib
+  antlr.jar
+  cglib.jar
+  asm.jar
+  asm-attrs.jars
+  commons-collections.jar
+  commons-logging.jar
+  hibernate3.jar
+  jta.jar
+  dom4j.jar
+  log4j.jar ]]></programlisting>
+
+        <para>
+            This is the minimum set of required libraries (note that we also copied
+            hibernate3.jar, the main archive) for Hibernate <emphasis>at the time of writing</emphasis>.
+            The Hibernate release you are using might require more or less libraries. See the
+            <literal>README.txt</literal> file in the <literal>lib/</literal> directory of the
+            Hibernate distribution for more information about required and optional third-party
+            libraries. (Actually, Log4j is not required but preferred by many developers.)
+        </para>
+
+        <para>
+            Next we create a class that represents the event we want to store in database.
+        </para>
+      
+        <sect2 id="tutorial-firstapp-firstclass" revision="1">
+            <title>The first class</title>
+            
+            <para>
+                Our first persistent class is a simple JavaBean class with some properties:
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+import java.util.Date;
+
+public class Event {
+    private Long id;
+
+    private String title;
+    private Date date;
+
+    public Event() {}
+
+    public Long getId() {
+        return id;
+    }
+
+    private void setId(Long id) {
+        this.id = id;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+}]]></programlisting>
+
+            <para>
+                You can see that this class uses standard JavaBean naming conventions for property
+                getter and setter methods, as well as private visibility for the fields. This is
+                a recommended design - but not required. Hibernate can also access fields directly,
+                the benefit of accessor methods is robustness for refactoring. The no-argument
+                constructor is required to instantiate an object of this class through reflection.
+            </para>
+
+            <para>
+                The <literal>id</literal> property holds a unique identifier value for a particular event.
+                All persistent entity classes (there are less important dependent classes as well) will need
+                such an identifier property if we want to use the full feature set of Hibernate. In fact,
+                most applications (esp. web applications) need to distinguish objects by identifier, so you
+                should consider this a feature rather than a limitation. However, we usually don't manipulate
+                the identity of an object, hence the setter method should be private. Only Hibernate will assign
+                identifiers when an object is saved. You can see that Hibernate can access public, private,
+                and protected accessor methods, as well as (public, private, protected) fields directly. The
+                choice is up to you and you can match it to fit your application design.
+            </para>
+
+            <para>
+                The no-argument constructor is a requirement for all persistent classes; Hibernate
+                has to create objects for you, using Java Reflection. The constructor can be
+                private, however, package visibility is required for runtime proxy generation and
+                efficient data retrieval without bytecode instrumentation.
+            </para>
+
+            <para>
+                Place this Java source file in a directory called <literal>src</literal> in the
+                development folder, and in its correct package. The directory should now look like this:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java]]></programlisting>
+
+            <para>
+                In the next step, we tell Hibernate about this persistent class.
+            </para>
+                
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-mapping" revision="1">
+            <title>The mapping file</title>
+
+            <para>
+                Hibernate needs to know how to load and store objects of the persistent class.
+                This is where the Hibernate mapping file comes into play. The mapping file
+                tells Hibernate what table in the database it has to access, and what columns
+                in that table it should use.
+            </para>
+
+            <para>
+                The basic structure of a mapping file looks like this:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+[...]
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Note that the Hibernate DTD is very sophisticated. You can use it for
+                auto-completion of XML mapping elements and attributes in your editor or
+                IDE. You also should open up the DTD file in your text editor - it's the
+                easiest way to get an overview of all elements and attributes and to see
+                the defaults, as well as some comments. Note that Hibernate will not
+                load the DTD file from the web, but first look it up from the classpath
+                of the application. The DTD file is included in <literal>hibernate3.jar</literal>
+                as well as in the <literal>src/</literal> directory of the Hibernate distribution.
+            </para>
+
+            <para>
+                We will omit the DTD declaration in future examples to shorten the code. It is
+                of course not optional.
+            </para>
+
+            <para>
+                Between the two <literal>hibernate-mapping</literal> tags, include a
+                <literal>class</literal> element. All persistent entity classes (again, there
+                might be dependent classes later on, which are not first-class entities) need
+                such a mapping, to a table in the SQL database:
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                So far we told Hibernate how to persist and load object of class <literal>Event</literal>
+                to the table <literal>EVENTS</literal>, each instance represented by a row in that table.
+                Now we continue with a mapping of the unique identifier property to the tables primary key.
+                In addition, as we don't want to care about handling this identifier, we configure Hibernate's
+                identifier generation strategy for a surrogate primary key column:
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="native"/>
+        </id>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                The <literal>id</literal> element is the declaration of the identifer property,
+                <literal>name="id"</literal> declares the name of the Java property -
+                Hibernate will use the getter and setter methods to access the property.
+                The column attribute tells Hibernate which column of the
+                <literal>EVENTS</literal> table we use for this primary key. The nested
+                <literal>generator</literal> element specifies the identifier generation strategy,
+                in this case we used <literal>native</literal>, which picks the best strategy depending
+                on the configured database (dialect). Hibernate supports database generated, globally
+                unique, as well as application assigned identifiers (or any strategy you have written
+                an extension for).
+            </para>
+
+            <para>
+                Finally we include declarations for the persistent properties of the class in
+                the mapping file. By default, no properties of the class are considered
+                persistent:
+            </para>
+            
+            <programlisting><![CDATA[
+<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="native"/>
+        </id>
+        <property name="date" type="timestamp" column="EVENT_DATE"/>
+        <property name="title"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+            
+            <para>
+                Just as with the <literal>id</literal> element, the <literal>name</literal>
+                attribute of the <literal>property</literal> element tells Hibernate which getter
+                and setter methods to use. So, in this case, Hibernate will look for
+                <literal>getDate()/setDate()</literal>, as well as <literal>getTitle()/setTitle()</literal>.
+            </para>
+
+            <para>
+                Why does the <literal>date</literal> property mapping include the
+                <literal>column</literal> attribute, but the <literal>title</literal>
+                doesn't? Without the <literal>column</literal> attribute Hibernate
+                by default uses the property name as the column name. This works fine for
+                <literal>title</literal>. However, <literal>date</literal> is a reserved
+                keyword in most database, so we better map it to a different name.
+            </para>
+
+            <para>
+                The next interesting thing is that the <literal>title</literal> mapping also lacks
+                a <literal>type</literal> attribute. The types we declare and use in the mapping
+                files are not, as you might expect, Java data types. They are also not SQL
+                database types. These types are so called <emphasis>Hibernate mapping types</emphasis>,
+                converters which can translate from Java to SQL data types and vice versa. Again,
+                Hibernate will try to determine the correct conversion and mapping type itself if
+                the <literal>type</literal> attribute is not present in the mapping. In some cases this
+                automatic detection (using Reflection on the Java class) might not have the default you
+                expect or need. This is the case with the <literal>date</literal> property. Hibernate can't
+                know if the property (which is of <literal>java.util.Date</literal>) should map to a
+                SQL <literal>date</literal>, <literal>timestamp</literal>, or <literal>time</literal> column.
+                We preserve full date and time information by mapping the property with a
+                <literal>timestamp</literal> converter.
+            </para>
+
+            <para>
+                This mapping file should be saved as <literal>Event.hbm.xml</literal>, right in
+                the directory next to the <literal>Event</literal> Java class source file.
+                The naming of mapping files can be arbitrary, however the <literal>hbm.xml</literal>
+                suffix  is a convention in the Hibernate developer community. The directory structure
+                should now look like this:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java
+    Event.hbm.xml]]></programlisting>
+
+             <para>
+                 We continue with the main configuration of Hibernate.
+             </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-configuration" revision="2">
+            <title>Hibernate configuration</title>
+
+            <para>
+                We now have a persistent class and its mapping file in place. It is time to configure
+                Hibernate. Before we do this, we will need a database. HSQL DB, a java-based SQL DBMS,
+                can be downloaded from the HSQL DB website. Actually, you only need the <literal>hsqldb.jar</literal>
+                from this download. Place this file in the <literal>lib/</literal> directory of the
+                development folder.
+            </para>
+
+            <para>
+                Create a directory called <literal>data</literal> in the root of the development directory -
+                this is where HSQL DB will store its data files. Now start the database by running
+                <literal>java -classpath ../lib/hsqldb.jar org.hsqldb.Server</literal> in this data directory.
+                You can see it start up and bind to a TCP/IP socket, this is where our application
+                will connect later. If you want to start with a fresh database during this tutorial,
+                shutdown HSQL DB (press <literal>CTRL + C</literal> in the window), delete all files in the
+                <literal>data/</literal> directory, and start HSQL DB again.
+            </para>
+
+            <para>
+                Hibernate is the layer in your application which connects to this database, so it needs
+                connection information. The connections are made through a JDBC connection pool, which we
+                also have to configure. The Hibernate distribution contains several open source JDBC connection
+                pooling tools, but will use the Hibernate built-in connection pool for this tutorial. Note that
+                you have to copy the required library into your classpath and use different
+                connection pooling settings if you want to use a production-quality third party
+                JDBC pooling software.
+            </para>
+
+            <para>
+                For Hibernate's configuration, we can use a simple <literal>hibernate.properties</literal> file, a
+                slightly more sophisticated <literal>hibernate.cfg.xml</literal> file, or even complete
+                programmatic setup. Most users prefer the XML configuration file:
+            </para>
+
+            <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <session-factory>
+
+        <!-- Database connection settings -->
+        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
+        <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
+        <property name="connection.username">sa</property>
+        <property name="connection.password"></property>
+
+        <!-- JDBC connection pool (use the built-in) -->
+        <property name="connection.pool_size">1</property>
+
+        <!-- SQL dialect -->
+        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
+
+        <!-- Enable Hibernate's automatic session context management -->
+        <property name="current_session_context_class">thread</property>
+
+        <!-- Disable the second-level cache  -->
+        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
+
+        <!-- Echo all executed SQL to stdout -->
+        <property name="show_sql">true</property>
+
+        <!-- Drop and re-create the database schema on startup -->
+        <property name="hbm2ddl.auto">create</property>
+
+        <mapping resource="events/Event.hbm.xml"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+            <para>
+                Note that this XML configuration uses a different DTD. We configure
+                Hibernate's <literal>SessionFactory</literal> - a global factory responsible
+                for a particular database. If you have several databases, use several
+                <literal>&lt;session-factory&gt;</literal> configurations, usually in
+                several configuration files (for easier startup).
+            </para>
+
+            <para>
+                The first four <literal>property</literal> elements contain the necessary
+                configuration for the JDBC connection. The dialect <literal>property</literal>
+                element specifies the particular SQL variant Hibernate generates.
+                Hibernate's automatic session management for persistence contexts will
+                come in handy as you will soon see.
+                The <literal>hbm2ddl.auto</literal> option turns on automatic generation of
+                database schemas - directly into the database. This can of course also be turned
+                off (by removing the config option) or redirected to a file with the help of
+                the <literal>SchemaExport</literal> Ant task. Finally, we add the mapping file(s)
+                for persistent classes to the configuration.
+            </para>
+
+            <para>
+                Copy this file into the source directory, so it will end up in the
+                root of the classpath. Hibernate automatically looks for a file called
+                <literal>hibernate.cfg.xml</literal> in the root of the classpath, on startup.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-ant" revision="1">
+            <title>Building with Ant</title>
+
+            <para>
+                We'll now build the tutorial with Ant. You will need to have Ant installed - get
+                it from the <ulink url="http://ant.apache.org/bindownload.cgi">Ant download page</ulink>.
+                How to install Ant will not be covered here. Please refer to the
+                <ulink url="http://ant.apache.org/manual/index.html">Ant manual</ulink>. After you
+                have installed Ant, we can start to create the buildfile. It will be called
+                <literal>build.xml</literal> and placed directly in the development directory.
+            </para>
+
+            <para>
+                A basic build file looks like this:
+            </para>
+
+            <programlisting><![CDATA[<project name="hibernate-tutorial" default="compile">
+
+    <property name="sourcedir" value="${basedir}/src"/>
+    <property name="targetdir" value="${basedir}/bin"/>
+    <property name="librarydir" value="${basedir}/lib"/>
+
+    <path id="libraries">
+        <fileset dir="${librarydir}">
+            <include name="*.jar"/>
+        </fileset>
+    </path>
+
+    <target name="clean">
+        <delete dir="${targetdir}"/>
+        <mkdir dir="${targetdir}"/>
+    </target>
+
+    <target name="compile" depends="clean, copy-resources">
+      <javac srcdir="${sourcedir}"
+             destdir="${targetdir}"
+             classpathref="libraries"/>
+    </target>
+
+    <target name="copy-resources">
+        <copy todir="${targetdir}">
+            <fileset dir="${sourcedir}">
+                <exclude name="**/*.java"/>
+            </fileset>
+        </copy>
+    </target>
+
+</project>]]></programlisting>
+
+            <para>
+                This will tell Ant to add all files in the lib directory ending with <literal>.jar</literal>
+                to the classpath used for compilation. It will also copy all non-Java source files to the
+                target directory, e.g. configuration and Hibernate mapping files. If you now run Ant, you
+                should get this output:
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant
+Buildfile: build.xml
+
+copy-resources:
+     [copy] Copying 2 files to C:\hibernateTutorial\bin
+
+compile:
+    [javac] Compiling 1 source file to C:\hibernateTutorial\bin
+
+BUILD SUCCESSFUL
+Total time: 1 second ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-helpers" revision="3">
+            <title>Startup and helpers</title>
+
+            <para>
+                It's time to load and store some <literal>Event</literal> objects, but first
+                we have to complete the setup with some infrastructure code. We have to startup
+                Hibernate. This startup includes building a global <literal>SessionFactory</literal>
+                object and to store it somewhere for easy access in application code.
+                A <literal>SessionFactory</literal> can open up new <literal>Session</literal>'s.
+                A <literal>Session</literal> represents a single-threaded unit of work, the
+                <literal>SessionFactory</literal> is a thread-safe global object, instantiated once.
+            </para>
+
+            <para>
+                We'll create a <literal>HibernateUtil</literal> helper class which takes care
+                of startup and makes accessing a <literal>SessionFactory</literal> convenient.
+                Let's have a look at the implementation:
+            </para>
+
+            <programlisting><![CDATA[package util;
+
+import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+    private static final SessionFactory sessionFactory;
+
+    static {
+        try {
+            // Create the SessionFactory from hibernate.cfg.xml
+            sessionFactory = new Configuration().configure().buildSessionFactory();
+        } catch (Throwable ex) {
+            // Make sure you log the exception, as it might be swallowed
+            System.err.println("Initial SessionFactory creation failed." + ex);
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    public static SessionFactory getSessionFactory() {
+        return sessionFactory;
+    }
+
+}]]></programlisting>
+
+            <para>
+                This class does not only produce the global <literal>SessionFactory</literal> in
+                its static initializer (called once by the JVM when the class is loaded), but also
+                hides the fact that it uses a static singleton. It might as well lookup the
+                <literal>SessionFactory</literal> from JNDI in an application server.
+            </para>
+
+            <para>
+                If you give the <literal>SessionFactory</literal> a name in your configuration
+                file, Hibernate will in fact try to bind it to JNDI after it has been built.
+                To avoid this code completely you could also use JMX deployment and let the
+                JMX-capable container instantiate and bind a <literal>HibernateService</literal>
+                to JNDI. These advanced options are discussed in the Hibernate reference
+                documentation.
+            </para>
+
+            <para>
+                Place <literal>HibernateUtil.java</literal> in the development source directory, in
+                a package next to <literal>events</literal>:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java
+    Event.hbm.xml
+  +util
+    HibernateUtil.java
+  hibernate.cfg.xml
++data
+build.xml]]></programlisting>
+
+            <para>
+                This should again compile without problems. We finally need to configure a logging
+                system - Hibernate uses commons logging and leaves you the choice between Log4j and
+                JDK 1.4 logging. Most developers prefer Log4j: copy <literal>log4j.properties</literal>
+                from the Hibernate distribution (it's in the <literal>etc/</literal> directory) to
+                your <literal>src</literal> directory, next to <literal>hibernate.cfg.xml</literal>.
+                Have a look at the example configuration and change the settings if you like to have
+                more verbose output. By default, only Hibernate startup message are shown on stdout.
+            </para>
+
+            <para>
+                The tutorial infrastructure is complete - and we are ready to do some real work with
+                Hibernate.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-workingpersistence" revision="5">
+            <title>Loading and storing objects</title>
+
+            <para>
+                Finally, we can use Hibernate to load and store objects. We write an
+                <literal>EventManager</literal> class with a <literal>main()</literal> method:
+            </para>
+
+            <programlisting><![CDATA[package events;
+import org.hibernate.Session;
+
+import java.util.Date;
+
+import util.HibernateUtil;
+
+public class EventManager {
+
+    public static void main(String[] args) {
+        EventManager mgr = new EventManager();
+
+        if (args[0].equals("store")) {
+            mgr.createAndStoreEvent("My Event", new Date());
+        }
+
+        HibernateUtil.getSessionFactory().close();
+    }
+
+    private void createAndStoreEvent(String title, Date theDate) {
+
+        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+        session.beginTransaction();
+
+        Event theEvent = new Event();
+        theEvent.setTitle(title);
+        theEvent.setDate(theDate);
+
+        session.save(theEvent);
+
+        session.getTransaction().commit();
+    }
+
+}]]></programlisting>
+
+            <para>
+                We create a new <literal>Event</literal> object, and hand it over to Hibernate.
+                Hibernate now takes care of the SQL and executes <literal>INSERT</literal>s
+                on the database. Let's have a look at the <literal>Session</literal> and
+                <literal>Transaction</literal>-handling code before we run this.
+            </para>
+
+            <para>
+                A <literal>Session</literal> is a single unit of work. For now we'll keep things
+                simple and assume a one-to-one granularity between a Hibernate <literal>Session</literal>
+                and a database transaction. To shield our code from the actual underlying transaction
+                system (in this case plain JDBC, but it could also run with JTA) we use the
+                <literal>Transaction</literal> API that is available on the Hibernate <literal>Session</literal>.
+            </para>
+
+            <para>
+                What does <literal>sessionFactory.getCurrentSession()</literal> do? First, you can call it
+                as many times and anywhere you like, once you get hold of your <literal>SessionFactory</literal>
+                (easy thanks to <literal>HibernateUtil</literal>). The <literal>getCurrentSession()</literal>
+                method always returns the "current" unit of work. Remember that we switched the configuration
+                option for this mechanism to "thread" in <literal>hibernate.cfg.xml</literal>? Hence,
+                the current unit of work is bound to the current Java thread that executes our application.
+                However, this is not the full picture, you also have to consider scope, when a unit of work
+                begins and when it ends.
+            </para>
+
+            <para>
+                A <literal>Session</literal> begins when it is first needed, when the first call to
+                <literal>getCurrentSession()</literal> is made. It is then bound by Hibernate to the current
+                thread. When the transaction ends, either through commit or rollback, Hibernate automatically
+                unbinds the <literal>Session</literal> from the thread and closes it for you. If you call
+                <literal>getCurrentSession()</literal> again, you get a new <literal>Session</literal> and can
+                start a new unit of work. This <emphasis>thread-bound</emphasis> programming model is the most
+                popular way of using Hibernate, as it allows flexible layering of your code (transaction
+                demarcation code can be separated from data access code, we'll do this later in this tutorial).
+            </para>
+
+            <para>
+                Related to the unit of work scope, should the Hibernate <literal>Session</literal> be used to
+                execute one or several database operations? The above example uses one <literal>Session</literal>
+                for one operation. This is pure coincidence, the example is just not complex enough to show any
+                other approach. The scope of a Hibernate <literal>Session</literal> is flexible but you should
+                never design your application to use a new Hibernate <literal>Session</literal> for
+                <emphasis>every</emphasis> database operation. So even if you see it a few more times in
+                the following (very trivial) examples, consider <emphasis>session-per-operation</emphasis>
+                an anti-pattern. A real (web) application is shown later in this tutorial.
+            </para>
+
+            <para>
+                Have a look at <xref linkend="transactions"/> for more information
+                about transaction handling and demarcation. We also skipped any error handling and
+                rollback in the previous example.
+            </para>
+
+            <para>
+                To run this first routine we have to add a callable target to the Ant build file:
+            </para>
+
+            <programlisting><![CDATA[<target name="run" depends="compile">
+    <java fork="true" classname="events.EventManager" classpathref="libraries">
+        <classpath path="${targetdir}"/>
+        <arg value="${action}"/>
+    </java>
+</target>]]></programlisting>
+
+            <para>
+                The value of the <literal>action</literal> argument is set on the command line when
+                calling the target:
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant run -Daction=store]]></programlisting>
+
+            <para>
+                You should see, after compilation, Hibernate starting up and, depending on your
+                configuration, lots of log output. At the end you will find the following line:
+            </para>
+
+            <programlisting><![CDATA[[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)]]></programlisting>
+
+            <para>
+                This is the <literal>INSERT</literal> executed by Hibernate, the question marks
+                represent JDBC bind parameters. To see the values bound as arguments, or to reduce
+                the verbosity of the log, check your <literal>log4j.properties</literal>.
+            </para>
+
+            <para>
+                Now we'd like to list stored events as well, so we add an option to the main method:
+            </para>
+
+            <programlisting><![CDATA[if (args[0].equals("store")) {
+    mgr.createAndStoreEvent("My Event", new Date());
+}
+else if (args[0].equals("list")) {
+    List events = mgr.listEvents();
+    for (int i = 0; i < events.size(); i++) {
+        Event theEvent = (Event) events.get(i);
+        System.out.println("Event: " + theEvent.getTitle() +
+                           " Time: " + theEvent.getDate());
+    }
+}]]></programlisting>
+
+            <para>
+                We also add a new <literal>listEvents() method</literal>:
+            </para>
+
+            <programlisting><![CDATA[private List listEvents() {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+    session.beginTransaction();
+
+    List result = session.createQuery("from Event").list();
+
+    session.getTransaction().commit();
+
+    return result;
+}]]></programlisting>
+
+            <para>
+                What we do here is use an HQL (Hibernate Query Language) query to load all existing
+                <literal>Event</literal> objects from the database. Hibernate will generate the
+                appropriate SQL, send it to the database and populate <literal>Event</literal> objects
+                with the data. You can create more complex queries with HQL, of course.
+            </para>
+
+            <para>
+                Now, to execute and test all of this, follow these steps:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        Run <literal>ant run -Daction=store</literal> to store something into the database
+                        and, of course, to generate the database schema before through hbm2ddl.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Now disable hbm2ddl by commenting out the property in your <literal>hibernate.cfg.xml</literal>
+                        file. Usually you only leave it turned on in continous unit testing, but another
+                        run of hbm2ddl would <emphasis>drop</emphasis> everything you have stored - the
+                        <literal>create</literal> configuration setting actually translates into "drop all
+                        tables from the schema, then re-create all tables, when the SessionFactory is build".
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                If you now call Ant with <literal>-Daction=list</literal>, you should see the events
+                you have stored so far. You can of course also call the <literal>store</literal> action a few
+                times more.
+            </para>
+
+            <para>
+                Note: Most new Hibernate users fail at this point and we see questions about
+                <emphasis>Table not found</emphasis> error messages regularly. However, if you follow the
+                steps outlined above you will not have this problem, as hbm2ddl creates the database
+                schema on the first run, and subsequent application restarts will use this schema. If
+                you change the mapping and/or database schema, you have to re-enable hbm2ddl once again.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="tutorial-associations">
+        <title>Part 2 - Mapping associations</title>
+
+        <para>
+            We mapped a persistent entity class to a table. Let's build on this and add some class associations.
+            First we'll add people to our application, and store a list of events they participate in.
+        </para>
+
+        <sect2 id="tutorial-associations-mappinguser" revision="1">
+            <title>Mapping the Person class</title>
+
+            <para>
+                The first cut of the <literal>Person</literal> class is simple:
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+public class Person {
+
+    private Long id;
+    private int age;
+    private String firstname;
+    private String lastname;
+
+    public Person() {}
+
+    // Accessor methods for all properties, private setter for 'id'
+
+}]]></programlisting>
+
+            <para>
+                Create a new mapping file called <literal>Person.hbm.xml</literal> (don't forget the
+                DTD reference at the top):
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Person" table="PERSON">
+        <id name="id" column="PERSON_ID">
+            <generator class="native"/>
+        </id>
+        <property name="age"/>
+        <property name="firstname"/>
+        <property name="lastname"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Finally, add the new mapping to Hibernate's configuration:
+            </para>
+
+            <programlisting><![CDATA[<mapping resource="events/Event.hbm.xml"/>
+<mapping resource="events/Person.hbm.xml"/>]]></programlisting>
+
+            <para>
+                We'll now create an association between these two entities. Obviously, persons
+                can participate in events, and events have participants. The design questions
+                we have to deal with are: directionality, multiplicity, and collection
+                behavior.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-unidirset" revision="3">
+            <title>A unidirectional Set-based association</title>
+
+            <para>
+                We'll add a collection of events to the <literal>Person</literal> class. That way we can
+                easily navigate to the events for a particular person, without executing an explicit query -
+                by calling <literal>aPerson.getEvents()</literal>. We use a Java collection, a <literal>Set</literal>,
+                because the collection will not contain duplicate elements and the ordering is not relevant for us.
+            </para>
+
+            <para>
+                We need a unidirectional, many-valued associations, implemented with a <literal>Set</literal>.
+                Let's write the code for this in the Java classes and then map it:
+            </para>
+
+            <programlisting><![CDATA[public class Person {
+
+    private Set events = new HashSet();
+
+    public Set getEvents() {
+        return events;
+    }
+
+    public void setEvents(Set events) {
+        this.events = events;
+    }
+}]]></programlisting>
+
+            <para>
+                Before we map this association, think about the other side. Clearly, we could just keep this
+                unidirectional. Or, we could create another collection on the <literal>Event</literal>, if we
+                want to be able to navigate it bi-directional, i.e. <literal>anEvent.getParticipants()</literal>.
+                This is not necessary, from a functional perspective. You could always execute an explicit query
+                to retrieve the participants for a particular event. This is a design choice left to you, but what
+                is clear from this discussion is the multiplicity of the association: "many" valued on both sides,
+                we call this a <emphasis>many-to-many</emphasis> association. Hence, we use Hibernate's
+                many-to-many mapping:
+            </para>
+
+            <programlisting><![CDATA[<class name="events.Person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="native"/>
+    </id>
+    <property name="age"/>
+    <property name="firstname"/>
+    <property name="lastname"/>
+
+    <set name="events" table="PERSON_EVENT">
+        <key column="PERSON_ID"/>
+        <many-to-many column="EVENT_ID" class="events.Event"/>
+    </set>
+
+</class>]]></programlisting>
+
+            <para>
+                Hibernate supports all kinds of collection mappings, a <literal>&lt;set&gt;</literal> being most
+                common. For a many-to-many association (or <emphasis>n:m</emphasis> entity relationship), an
+                association table is needed. Each row in this table represents a link between a person and an event.
+                The table name is configured with the <literal>table</literal> attribute of the <literal>set</literal>
+                element. The identifier column name in the association, for the person's side, is defined with the
+                <literal>&lt;key&gt;</literal> element, the column name for the event's side with the
+                <literal>column</literal> attribute of the <literal>&lt;many-to-many&gt;</literal>. You also
+                have to tell Hibernate the class of the objects in your collection (correct: the class on the
+                other side of the collection of references).
+            </para>
+
+            <para>
+                The database schema for this mapping is therefore:
+            </para>
+
+            <programlisting><![CDATA[
+    _____________        __________________
+   |             |      |                  |       _____________
+   |   EVENTS    |      |   PERSON_EVENT   |      |             |
+   |_____________|      |__________________|      |    PERSON   |
+   |             |      |                  |      |_____________|
+   | *EVENT_ID   | <--> | *EVENT_ID        |      |             |
+   |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  |
+   |  TITLE      |      |__________________|      |  AGE        |
+   |_____________|                                |  FIRSTNAME  |
+                                                  |  LASTNAME   |
+                                                  |_____________|
+ ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-working" revision="2">
+            <title>Working the association</title>
+
+            <para>
+                Let's bring some people and events together in a new method in <literal>EventManager</literal>:
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    aPerson.getEvents().add(anEvent);
+
+    session.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                After loading a <literal>Person</literal> and an <literal>Event</literal>, simply
+                modify the collection using the normal collection methods. As you can see, there is no explicit call
+                to <literal>update()</literal> or <literal>save()</literal>, Hibernate automatically
+                detects that the collection has been modified and needs to be updated. This is called <emphasis>automatic
+                dirty checking</emphasis>, and you can also try it by modifying the name or the date property of
+                any of your objects. As long as they are in <emphasis>persistent</emphasis> state, that is, bound
+                to a particular Hibernate <literal>Session</literal> (i.e. they have been just loaded or saved in
+                a unit of work), Hibernate monitors any changes and executes SQL in a write-behind fashion. The
+                process of synchronizing the memory state with the database, usually only at the end of a unit of
+                work, is called <emphasis>flushing</emphasis>. In our code, the unit of work ends with a commit
+                (or rollback) of the database transaction - as defined by the <literal>thread</literal> configuration
+                option for the <literal>CurrentSessionContext</literal> class.
+            </para>
+
+            <para>
+                You might of course load person and event in different units of work. Or you modify an object
+                outside of a <literal>Session</literal>, when it is not in persistent state (if it was persistent
+                before, we call this state <emphasis>detached</emphasis>). You can even modify a collection when
+                it is detached:
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session
+            .createQuery("select p from Person p left join fetch p.events where p.id = :pid")
+            .setParameter("pid", personId)
+            .uniqueResult(); // Eager fetch the collection so we can use it detached
+
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    session.getTransaction().commit();
+
+    // End of first unit of work
+
+    aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached
+
+    // Begin second unit of work
+
+    Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
+    session2.beginTransaction();
+
+    session2.update(aPerson); // Reattachment of aPerson
+
+    session2.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                The call to <literal>update</literal> makes a detached object persistent again, you could
+                say it binds it to a new unit of work, so any modifications you made to it while detached
+                can be saved to the database. This includes any modifications (additions/deletions) you
+                made to a collection of that entity object.
+            </para>
+
+            <para>
+                Well, this is not much use in our current situation, but it's an important concept you can
+                design into your own application. For now, complete this exercise by adding a new action
+                to the <literal>EventManager</literal>'s main method and call it from the command line. If
+                you need the identifiers of a person and an event - the <literal>save()</literal> method
+                returns it (you might have to modify some of the previous methods to return that identifier):
+            </para>
+
+            <programlisting><![CDATA[else if (args[0].equals("addpersontoevent")) {
+    Long eventId = mgr.createAndStoreEvent("My Event", new Date());
+    Long personId = mgr.createAndStorePerson("Foo", "Bar");
+    mgr.addPersonToEvent(personId, eventId);
+    System.out.println("Added person " + personId + " to event " + eventId);
+}]]></programlisting>
+
+            <para>
+                This was an example of an association between two equally important classes, two entities.
+                As mentioned earlier, there are other classes and types in a typical model, usually "less
+                important". Some you have already seen, like an <literal>int</literal> or a <literal>String</literal>.
+                We call these classes <emphasis>value types</emphasis>, and their instances <emphasis>depend</emphasis>
+                on a particular entity. Instances of these types don't have their own identity, nor are they
+                shared between entities (two persons don't reference the same <literal>firstname</literal>
+                object, even if they have the same first name). Of course, value types can not only be found in
+                the JDK (in fact, in a Hibernate application all JDK classes are considered value types), but
+                you can also write dependent classes yourself, <literal>Address</literal> or <literal>MonetaryAmount</literal>,
+                for example.
+            </para>
+
+            <para>
+                You can also design a collection of value types. This is conceptually very different from a
+                collection of references to other entities, but looks almost the same in Java.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-valuecollections">
+            <title>Collection of values</title>
+
+            <para>
+                We add a collection of value typed objects to the <literal>Person</literal> entity. We want to
+                store email addresses, so the type we use is <literal>String</literal>, and the collection is
+                again a <literal>Set</literal>:
+            </para>
+            <programlisting><![CDATA[private Set emailAddresses = new HashSet();
+
+public Set getEmailAddresses() {
+    return emailAddresses;
+}
+
+public void setEmailAddresses(Set emailAddresses) {
+    this.emailAddresses = emailAddresses;
+}]]></programlisting>
+
+            <para>
+                The mapping of this <literal>Set</literal>:
+            </para>
+
+            <programlisting><![CDATA[<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
+    <key column="PERSON_ID"/>
+    <element type="string" column="EMAIL_ADDR"/>
+</set>]]></programlisting>
+
+            <para>
+                The difference compared with the earlier mapping is the <literal>element</literal> part, which tells Hibernate that the collection
+                does not contain references to another entity, but a collection of elements of type
+                <literal>String</literal> (the lowercase name tells you it's a Hibernate mapping type/converter).
+                Once again, the <literal>table</literal> attribute of the <literal>set</literal> element determines
+                the table name for the collection. The <literal>key</literal> element defines the foreign-key column
+                name in the collection table. The <literal>column</literal> attribute in the <literal>element</literal>
+                element defines the column name where the <literal>String</literal> values will actually be stored.
+            </para>
+
+            <para>
+                Have a look at the updated schema:
+            </para>
+
+            <programlisting><![CDATA[
+  _____________        __________________
+ |             |      |                  |       _____________
+ |   EVENTS    |      |   PERSON_EVENT   |      |             |       ___________________
+ |_____________|      |__________________|      |    PERSON   |      |                   |
+ |             |      |                  |      |_____________|      | PERSON_EMAIL_ADDR |
+ | *EVENT_ID   | <--> | *EVENT_ID        |      |             |      |___________________|
+ |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  | <--> |  *PERSON_ID       |
+ |  TITLE      |      |__________________|      |  AGE        |      |  *EMAIL_ADDR      |
+ |_____________|                                |  FIRSTNAME  |      |___________________|
+                                                |  LASTNAME   |
+                                                |_____________|
+ ]]></programlisting>
+
+            <para>
+                You can see that the primary key of the collection table is in fact a composite key,
+                using both columns. This also implies that there can't be duplicate email addresses
+                per person, which is exactly the semantics we need for a set in Java.
+            </para>
+
+            <para>
+                You can now try and add elements to this collection, just like we did before by
+                linking persons and events. It's the same code in Java:
+            </para>
+
+            <programlisting><![CDATA[private void addEmailToPerson(Long personId, String emailAddress) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+
+    // The getEmailAddresses() might trigger a lazy load of the collection
+    aPerson.getEmailAddresses().add(emailAddress);
+
+    session.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                This time we didnt' use a <emphasis>fetch</emphasis> query to initialize the collection.
+                Hence, the call to its getter method will trigger an additional select to initialize
+                it, so we can add an element to it. Monitor the SQL log and try to optimize this with
+                an eager fetch.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-bidirectional" revision="1">
+            <title>Bi-directional associations</title>
+
+            <para>
+                Next we are going to map a bi-directional association - making the association between
+                person and event work from both sides in Java. Of course, the database schema doesn't
+                change, we still have many-to-many multiplicity. A relational database is more flexible
+                than a network programming language, so it doesn't need anything like a navigation
+                direction - data can be viewed and retrieved in any possible way.
+            </para>
+
+            <para>
+                First, add a collection of participants to the <literal>Event</literal> Event class:
+            </para>
+
+            <programlisting><![CDATA[private Set participants = new HashSet();
+
+public Set getParticipants() {
+    return participants;
+}
+
+public void setParticipants(Set participants) {
+    this.participants = participants;
+}]]></programlisting>
+
+            <para>
+                Now map this side of the association too, in <literal>Event.hbm.xml</literal>.
+            </para>
+
+            <programlisting><![CDATA[<set name="participants" table="PERSON_EVENT" inverse="true">
+    <key column="EVENT_ID"/>
+    <many-to-many column="PERSON_ID" class="events.Person"/>
+</set>]]></programlisting>
+
+            <para>
+                As you see, these are normal <literal>set</literal> mappings in both mapping documents.
+                Notice that the column names in <literal>key</literal> and <literal>many-to-many</literal> are
+                swapped in both mapping documents. The most important addition here is the
+                <literal>inverse="true"</literal> attribute in the <literal>set</literal> element of the
+                <literal>Event</literal>'s collection mapping.
+            </para>
+
+            <para>
+                What this means is that Hibernate should take the other side - the <literal>Person</literal> class -
+                when it needs to find out information about the link between the two. This will be a lot easier to
+                understand once you see how the bi-directional link between our two entities is created .
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-usingbidir">
+            <title>Working bi-directional links</title>
+
+            <para>
+                First, keep in mind that Hibernate does not affect normal Java semantics. How did we create a
+                link between a <literal>Person</literal> and an <literal>Event</literal> in the unidirectional
+                example? We added an instance of <literal>Event</literal> to the collection of event references,
+                of an instance of <literal>Person</literal>. So, obviously, if we want to make this link working
+                bi-directional, we have to do the same on the other side - adding a <literal>Person</literal>
+                reference to the collection in an <literal>Event</literal>. This "setting the link on both sides"
+                is absolutely necessary and you should never forget doing it.
+            </para>
+
+            <para>
+                Many developers program defensive and create a link management methods to
+                correctly set both sides, e.g. in <literal>Person</literal>:
+            </para>
+
+            <programlisting><![CDATA[protected Set getEvents() {
+    return events;
+}
+
+protected void setEvents(Set events) {
+    this.events = events;
+}
+
+public void addToEvent(Event event) {
+    this.getEvents().add(event);
+    event.getParticipants().add(this);
+}
+
+public void removeFromEvent(Event event) {
+    this.getEvents().remove(event);
+    event.getParticipants().remove(this);
+}]]></programlisting>
+
+            <para>
+                Notice that the get and set methods for the collection are now protected - this allows classes in the
+                same package and subclasses to still access the methods, but prevents everybody else from messing
+                with the collections directly (well, almost). You should probably do the same with the collection
+                on the other side.
+            </para>
+
+            <para>
+                What about the <literal>inverse</literal> mapping attribute? For you, and for Java, a bi-directional
+                link is simply a matter of setting the references on both sides correctly. Hibernate however doesn't
+                have enough information to correctly arrange SQL <literal>INSERT</literal> and <literal>UPDATE</literal>
+                statements (to avoid constraint violations), and needs some help to handle bi-directional associations
+                properly. Making one side of the association <literal>inverse</literal> tells Hibernate to basically
+                ignore it, to consider it a <emphasis>mirror</emphasis> of the other side. That's all that is necessary
+                for Hibernate to work out all of the issues when transformation a directional navigation model to
+                a SQL database schema. The rules you have to remember are straightforward: All bi-directional associations
+                need one side as <literal>inverse</literal>. In a one-to-many association it has to be the many-side,
+                in many-to-many association you can pick either side, there is no difference.
+            </para>
+
+        </sect2>
+
+        <para>
+            Let's turn this into a small web application.
+        </para>
+
+    </sect1>
+
+    <sect1 id="tutorial-webapp">
+        <title>Part 3 - The EventManager web application</title>
+
+        <para>
+            A Hibernate web application uses <literal>Session</literal> and <literal>Transaction</literal>
+            almost like a standalone application. However, some common patterns are useful. We now write
+            an <literal>EventManagerServlet</literal>. This servlet can list all events stored in the
+            database, and it provides an HTML form to enter new events.
+        </para>
+
+        <sect2 id="tutorial-webapp-servlet" revision="2">
+            <title>Writing the basic servlet</title>
+
+            <para>
+                Create a new class in your source directory, in the <literal>events</literal>
+                package:
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+// Imports
+
+public class EventManagerServlet extends HttpServlet {
+
+    // Servlet code
+}]]></programlisting>
+
+            <para>
+                The servlet handles HTTP <literal>GET</literal> requests only, hence, the method
+                we implement is <literal>doGet()</literal>:
+            </para>
+
+            <programlisting><![CDATA[protected void doGet(HttpServletRequest request,
+                     HttpServletResponse response)
+        throws ServletException, IOException {
+
+    SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
+
+    try {
+        // Begin unit of work
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().beginTransaction();
+
+        // Process request and render page...
+
+        // End unit of work
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().getTransaction().commit();
+
+    } catch (Exception ex) {
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().getTransaction().rollback();
+        throw new ServletException(ex);
+    }
+
+}]]></programlisting>
+
+            <para>
+                The pattern we are applying here is called <emphasis>session-per-request</emphasis>.
+                When a request hits the servlet, a new Hibernate <literal>Session</literal> is
+                opened through the first call to <literal>getCurrentSession()</literal> on the
+                <literal>SessionFactory</literal>. Then a database transaction is started&mdash;all
+                data access as to occur inside a transaction, no matter if data is read or written
+                (we don't use the auto-commit mode in applications).
+            </para>
+
+            <para>
+                Do <emphasis>not</emphasis> use a new Hibernate <literal>Session</literal> for
+                every database operation. Use one Hibernate <literal>Session</literal> that is
+                scoped to the whole request. Use <literal>getCurrentSession()</literal>, so that
+                it is automatically bound to the current Java thread.
+            </para>
+
+            <para>
+                Next, the possible actions of the request are processed and the response HTML
+                is rendered. We'll get to that part soon.
+            </para>
+
+            <para>
+                Finally, the unit of work ends when processing and rendering is complete. If any
+                problem occured during processing or rendering, an exception will be thrown
+                and the database transaction rolled back. This completes the
+                <literal>session-per-request</literal> pattern. Instead of the transaction
+                demarcation code in every servlet you could also write a servlet filter.
+                See the Hibernate website and Wiki for more information about this pattern,
+                called <emphasis>Open Session in View</emphasis>&mdash;you'll need it as soon
+                as you consider rendering your view in JSP, not in a servlet.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-webapp-processing" revision="1">
+            <title>Processing and rendering</title>
+
+            <para>
+                Let's implement the processing of the request and rendering of the page.
+            </para>
+
+<programlisting><![CDATA[// Write HTML header
+PrintWriter out = response.getWriter();
+out.println("<html><head><title>Event Manager</title></head><body>");
+
+// Handle actions
+if ( "store".equals(request.getParameter("action")) ) {
+
+    String eventTitle = request.getParameter("eventTitle");
+    String eventDate = request.getParameter("eventDate");
+
+    if ( "".equals(eventTitle) || "".equals(eventDate) ) {
+        out.println("<b><i>Please enter event title and date.</i></b>");
+    } else {
+        createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
+        out.println("<b><i>Added event.</i></b>");
+    }
+}
+
+// Print page
+printEventForm(out);
+listEvents(out, dateFormatter);
+
+// Write HTML footer
+out.println("</body></html>");
+out.flush();
+out.close();]]></programlisting>
+
+            <para>
+                Granted, this coding style with a mix of Java and HTML would not scale
+                in a more complex application&mdash;keep in mind that we are only illustrating
+                basic Hibernate concepts in this tutorial. The code prints an HTML
+                header and a footer. Inside this page, an HTML form for event entry and
+                a list of all events in the database are printed. The first method is
+                trivial and only outputs HTML:
+            </para>
+
+            <programlisting><![CDATA[private void printEventForm(PrintWriter out) {
+    out.println("<h2>Add new event:</h2>");
+    out.println("<form>");
+    out.println("Title: <input name='eventTitle' length='50'/><br/>");
+    out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");
+    out.println("<input type='submit' name='action' value='store'/>");
+    out.println("</form>");
+}]]></programlisting>
+
+            <para>
+                The <literal>listEvents()</literal> method uses the Hibernate
+                <literal>Session</literal> bound to the current thread to execute
+                a query:
+            </para>
+
+            <programlisting><![CDATA[private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) {
+
+    List result = HibernateUtil.getSessionFactory()
+                    .getCurrentSession().createCriteria(Event.class).list();
+    if (result.size() > 0) {
+        out.println("<h2>Events in database:</h2>");
+        out.println("<table border='1'>");
+        out.println("<tr>");
+        out.println("<th>Event title</th>");
+        out.println("<th>Event date</th>");
+        out.println("</tr>");
+        for (Iterator it = result.iterator(); it.hasNext();) {
+            Event event = (Event) it.next();
+            out.println("<tr>");
+            out.println("<td>" + event.getTitle() + "</td>");
+            out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
+            out.println("</tr>");
+        }
+        out.println("</table>");
+    }
+}]]></programlisting>
+
+            <para>
+                Finally, the <literal>store</literal> action is dispatched to the
+                <literal>createAndStoreEvent()</literal> method, which also uses
+                the <literal>Session</literal> of the current thread:
+            </para>
+
+            <programlisting><![CDATA[protected void createAndStoreEvent(String title, Date theDate) {
+    Event theEvent = new Event();
+    theEvent.setTitle(title);
+    theEvent.setDate(theDate);
+
+    HibernateUtil.getSessionFactory()
+                    .getCurrentSession().save(theEvent);
+}]]></programlisting>
+
+            <para>
+                That's it, the servlet is complete. A request to the servlet will be processed
+                in a single <literal>Session</literal> and <literal>Transaction</literal>. As
+                earlier in the standalone application, Hibernate can automatically bind these
+                ojects to the current thread of execution. This gives you the freedom to layer
+                your code and access the <literal>SessionFactory</literal> in any way you like.
+                Usually you'd use a more sophisticated design and move the data access code
+                into data access objects (the DAO pattern). See the Hibernate Wiki for more
+                examples.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-webapp-deploy">
+            <title>Deploying and testing</title>
+
+            <para>
+                To deploy this application you have to create a web archive, a WAR. Add the
+                following Ant target to your <literal>build.xml</literal>:
+            </para>
+
+<programlisting><![CDATA[<target name="war" depends="compile">
+    <war destfile="hibernate-tutorial.war" webxml="web.xml">
+        <lib dir="${librarydir}">
+          <exclude name="jsdk*.jar"/>
+        </lib>
+
+        <classes dir="${targetdir}"/>
+    </war>
+</target>]]></programlisting>
+
+            <para>
+                This target creates a file called <literal>hibernate-tutorial.war</literal>
+                in your project directory. It packages all libraries and the <literal>web.xml</literal>
+                descriptor, which is expected in the base directory of your project:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+    xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+    <servlet>
+        <servlet-name>Event Manager</servlet-name>
+        <servlet-class>events.EventManagerServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Event Manager</servlet-name>
+        <url-pattern>/eventmanager</url-pattern>
+    </servlet-mapping>
+</web-app>]]></programlisting>
+
+            <para>
+                Before you compile and deploy the web application, note that an additional library
+                is required: <literal>jsdk.jar</literal>. This is the Java servlet development kit,
+                if you don't have this library already, get it from the Sun website and copy it to
+                your library directory. However, it will be only used for compliation and excluded
+                from the WAR package.
+            </para>
+
+            <para>
+                To build and deploy call <literal>ant war</literal> in your project directory
+                and copy the <literal>hibernate-tutorial.war</literal> file into your Tomcat
+                <literal>webapp</literal> directory. If you don't have Tomcat installed, download
+                it and follow the installation instructions. You don't have to change any Tomcat
+                configuration to deploy this application though.
+            </para>
+
+            <para>
+                Once deployed and Tomcat is running, access the application at
+                <literal>http://localhost:8080/hibernate-tutorial/eventmanager</literal>. Make
+                sure you watch the Tomcat log to see Hibernate initialize when the first
+                request hits your servlet (the static initializer in <literal>HibernateUtil</literal>
+                is called) and to get the detailed output if any exceptions occurs.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="tutorial-summary" revision="1">
+        <title>Summary</title>
+
+        <para>
+            This tutorial covered the basics of writing a simple standalone Hibernate application
+            and a small web application.
+        </para>
+
+        <para>
+            If you already feel confident with Hibernate, continue browsing through the reference
+            documentation table of contents for topics you find interesting - most asked are
+            transactional processing (<xref linkend="transactions"/>), fetch
+            performance (<xref linkend="performance"/>), or the usage of the API (<xref linkend="objectstate"/>)
+            and the query features (<xref linkend="objectstate-querying"/>).
+        </para>
+
+        <para>
+            Don't forget to check the Hibernate website for more (specialized) tutorials.
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/xml.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/xml.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/xml.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,286 @@
+<chapter id="xml">
+    <title>XML Mapping</title>
+
+    <para><emphasis>
+        Note that this is an experimental feature in Hibernate 3.0 and is under
+        extremely active development.
+    </emphasis></para>
+
+    <sect1 id="xml-intro" revision="1">
+        <title>Working with XML data</title>
+
+        <para>
+            Hibernate lets you work with persistent XML data in much the same way
+            you work with persistent POJOs. A parsed XML tree can be thought of
+            as just another way to represent the relational data at the object level,
+            instead of POJOs.
+        </para>
+
+        <para>
+            Hibernate supports dom4j as API for manipulating XML trees. You can write 
+            queries that retrieve dom4j trees from the database and have any 
+            modification you make to the tree automatically synchronized to the 
+            database. You can even take an XML document, parse it using dom4j, and
+            write it to the database with any of Hibernate's basic operations: 
+            <literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal> 
+            (merging is not yet supported).
+        </para>
+
+        <para>
+            This feature has many applications including data import/export, 
+            externalization of entity data via JMS or SOAP and XSLT-based reporting.
+        </para>
+        
+        <para>
+            A single mapping may be used to simultaneously map properties of a class
+            and nodes of an XML document to the database, or, if there is no class to map, 
+            it may be used to map just the XML.
+        </para>
+        
+        <sect2 id="xml-intro-mapping">
+            <title>Specifying XML and class mapping together</title>
+
+            <para>
+                Here is an example of mapping a POJO and XML simultaneously:
+            </para>
+            
+            <programlisting><![CDATA[<class name="Account" 
+        table="ACCOUNTS" 
+        node="account">
+        
+    <id name="accountId" 
+            column="ACCOUNT_ID" 
+            node="@id"/>
+            
+    <many-to-one name="customer" 
+            column="CUSTOMER_ID" 
+            node="customer/@id" 
+            embed-xml="false"/>
+            
+    <property name="balance" 
+            column="BALANCE" 
+            node="balance"/>
+            
+    ...
+    
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="xml-onlyxml">
+            <title>Specifying only an XML mapping</title>
+
+            <para>
+                Here is an example where there is no POJO class:
+            </para>
+            
+            <programlisting><![CDATA[<class entity-name="Account" 
+        table="ACCOUNTS" 
+        node="account">
+        
+    <id name="id" 
+            column="ACCOUNT_ID" 
+            node="@id" 
+            type="string"/>
+            
+    <many-to-one name="customerId" 
+            column="CUSTOMER_ID" 
+            node="customer/@id" 
+            embed-xml="false" 
+            entity-name="Customer"/>
+            
+    <property name="balance" 
+            column="BALANCE" 
+            node="balance" 
+            type="big_decimal"/>
+            
+    ...
+    
+</class>]]></programlisting>
+        
+            <para>
+                This mapping allows you to access the data as a dom4j tree, or as a graph of
+                property name/value pairs (java <literal>Map</literal>s). The property names
+                are purely logical constructs that may be referred to in HQL queries.
+            </para>
+
+        </sect2>
+        
+     </sect1>
+     
+    <sect1 id="xml-mapping" revision="1">
+        <title>XML mapping metadata</title>
+
+        <para>
+            Many Hibernate mapping elements accept the <literal>node</literal> attribute.
+            This let's you specify the name of an XML attribute or element that holds the
+            property or entity data. The format of the <literal>node</literal> attribute
+            must be one of the following:
+        </para>
+        
+        <itemizedlist spacing="compact">
+        <listitem>
+            <para><literal>"element-name"</literal> - map to the named XML element</para>
+        </listitem>
+        <listitem>
+            <para><literal>"@attribute-name"</literal> - map to the named XML attribute</para>
+        </listitem>
+        <listitem>
+            <para><literal>"."</literal> - map to the parent element</para>
+        </listitem>
+        <listitem>
+            <para>
+                <literal>"element-name/@attribute-name"</literal> - 
+                map to the named attribute of the named element
+            </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            For collections and single valued associations, there is an additional 
+            <literal>embed-xml</literal> attribute. If <literal>embed-xml="true"</literal>,
+            the default, the XML tree for the associated entity (or collection of value type) 
+            will be embedded directly in the XML tree for the entity that owns the association.
+            Otherwise, if <literal>embed-xml="false"</literal>, then only the referenced 
+            identifier value will appear in the XML for single point associations and 
+            collections will simply not appear at all.
+        </para>
+        
+        <para>
+            You should be careful not to leave <literal>embed-xml="true"</literal> for
+            too many associations, since XML does not deal well with circularity!
+        </para>
+        
+        <programlisting><![CDATA[<class name="Customer" 
+        table="CUSTOMER" 
+        node="customer">
+        
+    <id name="id" 
+            column="CUST_ID" 
+            node="@id"/>
+            
+    <map name="accounts" 
+            node="." 
+            embed-xml="true">
+        <key column="CUSTOMER_ID" 
+                not-null="true"/>
+        <map-key column="SHORT_DESC" 
+                node="@short-desc" 
+                type="string"/>
+        <one-to-many entity-name="Account"
+                embed-xml="false" 
+                node="account"/>
+    </map>
+    
+    <component name="name" 
+            node="name">
+        <property name="firstName" 
+                node="first-name"/>
+        <property name="initial" 
+                node="initial"/>
+        <property name="lastName" 
+                node="last-name"/>
+    </component>
+    
+    ...
+    
+</class>]]></programlisting>
+
+        <para>
+            in this case, we have decided to embed the collection of account ids, but not
+            the actual account data. The following HQL query:
+        </para>
+        
+        <programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
+        
+        <para>
+            Would return datasets such as this:
+        </para>
+        
+        <programlisting><![CDATA[<customer id="123456789">
+    <account short-desc="Savings">987632567</account>
+    <account short-desc="Credit Card">985612323</account>
+    <name>
+        <first-name>Gavin</first-name>
+        <initial>A</initial>
+        <last-name>King</last-name>
+    </name>
+    ...
+</customer>]]></programlisting>
+
+        <para>
+            If you set <literal>embed-xml="true"</literal> on the <literal>&lt;one-to-many&gt;</literal>
+            mapping, the data might look more like this:
+        </para>
+        
+        <programlisting><![CDATA[<customer id="123456789">
+    <account id="987632567" short-desc="Savings">
+        <customer id="123456789"/>
+        <balance>100.29</balance>
+    </account>
+    <account id="985612323" short-desc="Credit Card">
+        <customer id="123456789"/>
+        <balance>-2370.34</balance>
+    </account>
+    <name>
+        <first-name>Gavin</first-name>
+        <initial>A</initial>
+        <last-name>King</last-name>
+    </name>
+    ...
+</customer>]]></programlisting>
+       
+    </sect1>
+    
+    
+    <sect1 id="xml-manipulation" revision="1">
+        <title>Manipulating XML data</title>
+        
+        <para>
+            Let's rearead and update XML documents in the application. We do this by
+            obtaining a dom4j session:
+        </para>
+        
+       <programlisting><![CDATA[Document doc = ....;
+       
+Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+List results = dom4jSession
+    .createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")
+    .list();
+for ( int i=0; i<results.size(); i++ ) {
+    //add the customer data to the XML document
+    Element customer = (Element) results.get(i);
+    doc.add(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+       
+       <programlisting><![CDATA[Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+Element cust = (Element) dom4jSession.get("Customer", customerId);
+for ( int i=0; i<results.size(); i++ ) {
+    Element customer = (Element) results.get(i);
+    //change the customer name in the XML and database
+    Element name = customer.element("name");
+    name.element("first-name").setText(firstName);
+    name.element("initial").setText(initial);
+    name.element("last-name").setText(lastName);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            It is extremely useful to combine this feature with Hibernate's <literal>replicate()</literal>
+            operation to implement XML-based data import/export.
+        </para>
+       
+    </sect1>
+     
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/docbook/modules/xml.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/css/html.css
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/css/html.css	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/css/html.css	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,97 @@
+A {
+    color: #003399;
+}
+
+A:active {
+    color: #003399;
+}
+
+A:visited {
+    color: #888888;
+}
+
+P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
+    color: #000000;
+}
+
+TD, TH, SPAN {
+    color: #000000;
+}
+
+BLOCKQUOTE {
+    margin-right: 0px;
+}
+
+
+H1, H2, H3, H4, H5, H6    {
+    color: #000000;
+    font-weight:500;
+    margin-top:10px;
+    padding-top:15px;
+}
+
+TABLE  {
+    border-collapse: collapse;
+    border-spacing:0;
+    border: 1px thin black;
+    empty-cells: hide;
+}
+
+TD  {
+    padding: 4pt;
+}
+
+H1 { font-size: 150%; }
+H2 { font-size: 140%; }
+H3 { font-size: 110%; font-weight: bold; }
+H4 { font-size: 110%; font-weight: bold;}
+H5 { font-size: 100%; font-style: italic; }
+H6 { font-size: 100%; font-style: italic; }
+
+TT {
+font-size: 90%;
+    font-family: "Courier New", Courier, monospace;
+    color: #000000;
+}
+
+PRE {
+font-size: 100%;
+    padding: 5px;
+    border-style: solid;
+    border-width: 1px;
+    border-color: #CCCCCC;
+    background-color: #F4F4F4;
+}
+
+UL, OL, LI {
+    list-style: disc;
+}
+
+HR  {
+    width: 100%;
+    height: 1px;
+    background-color: #CCCCCC;
+    border-width: 0px;
+    padding: 0px;
+    color: #CCCCCC;
+}
+
+.variablelist { 
+    padding-top: 10; 
+    padding-bottom:10; 
+    margin:0;
+}
+
+.itemizedlist, UL { 
+    padding-top: 0; 
+    padding-bottom:0; 
+    margin:0; 
+}
+
+.term { 
+    font-weight:bold;
+}
+
+
+
+    

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/AuthorWork.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/AuthorWork.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/AuthorWork.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/AuthorWork.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/CustomerOrderProduct.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/CustomerOrderProduct.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/CustomerOrderProduct.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/CustomerOrderProduct.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/EmployerEmployee.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/EmployerEmployee.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/EmployerEmployee.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/EmployerEmployee.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/full_cream.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/full_cream.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/full_cream.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/full_cream.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/full_cream.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,429 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="354.331"
+   height="336.614"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+     style="font-size:12;"
+     id="g659">
+    <rect
+       width="212.257"
+       height="57.2441"
+       x="17.9576"
+       y="100.132"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       transform="matrix(0.743454,0,0,0.482981,6.46949,52.2178)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <rect
+     width="325.86"
+     height="63.6537"
+     x="17.4083"
+     y="15.194"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect136" />
+  <rect
+     width="325.86"
+     height="63.6537"
+     x="13.6713"
+     y="12.4966"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect126" />
+  <g
+     transform="matrix(1.14345,0,0,0.729078,-1.67818,105.325)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <text
+     x="170.824753"
+     y="58.402939"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="170.824997"
+       y="58.402901"
+       id="tspan360">
+Application</tspan>
+  </text>
+  <text
+     x="178.076340"
+     y="364.281433"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="178.076004"
+       y="364.281006"
+       id="tspan421">
+Database</tspan>
+  </text>
+  <text
+     x="68.605331"
+     y="138.524582"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="68.605301"
+       y="138.524994"
+       id="tspan384">
+SessionFactory</tspan>
+  </text>
+  <rect
+     width="67.0014"
+     height="101.35"
+     x="196.927"
+     y="89.2389"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect387" />
+  <rect
+     width="67.0014"
+     height="101.35"
+     x="194.633"
+     y="86.4389"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect388" />
+  <text
+     x="249.108841"
+     y="173.885559"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text389">
+    <tspan
+       x="249.108994"
+       y="173.886002"
+       id="tspan392">
+Session</tspan>
+  </text>
+  <rect
+     width="73.0355"
+     height="101.35"
+     x="270.995"
+     y="90.0018"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect395" />
+  <rect
+     width="73.0355"
+     height="101.35"
+     x="267.869"
+     y="87.2018"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect396" />
+  <text
+     x="328.593658"
+     y="174.715622"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text397">
+    <tspan
+       x="328.593994"
+       y="174.716003"
+       id="tspan563">
+Transaction</tspan>
+  </text>
+  <g
+     transform="matrix(0.29544,0,0,0.397877,9.70533,103.96)"
+     style="font-size:12;"
+     id="g565">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect566" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect567" />
+  </g>
+  <text
+     x="25.592752"
+     y="204.497803"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text568">
+    <tspan
+       x="25.592800"
+       y="204.498001"
+       id="tspan662">
+TransactionFactory</tspan>
+  </text>
+  <g
+     transform="matrix(0.298082,0,0,0.397877,99.6898,103.96)"
+     style="font-size:12;"
+     id="g573">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect574" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect575" />
+  </g>
+  <text
+     x="134.030670"
+     y="205.532791"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text576">
+    <tspan
+       x="134.031006"
+       y="205.533005"
+       id="tspan664">
+ConnectionProvider</tspan>
+  </text>
+  <g
+     transform="matrix(1.14345,0,0,0.729078,-1.67818,38.9539)"
+     style="font-size:12;"
+     id="g587">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect588" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect589" />
+  </g>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="25.6196"
+     y="206.028"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect594" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="24.4229"
+     y="204.135"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect595" />
+  <text
+     x="85.575645"
+     y="282.300354"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text596">
+    <tspan
+       x="85.575600"
+       y="282.299988"
+       id="tspan607">
+JNDI</tspan>
+  </text>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="236.937"
+     y="206.791"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect610" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="235.741"
+     y="204.898"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect611" />
+  <text
+     x="342.093201"
+     y="283.226410"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text612">
+    <tspan
+       x="342.092987"
+       y="283.226013"
+       id="tspan621">
+JTA</tspan>
+  </text>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="130.134"
+     y="206.791"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect616" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="128.937"
+     y="204.898"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect617" />
+  <text
+     x="212.445343"
+     y="283.226410"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text618">
+    <tspan
+       x="212.445007"
+       y="283.226013"
+       id="tspan623">
+JDBC</tspan>
+  </text>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,6.19341)"
+     style="font-size:12;"
+     id="g637">
+    <g
+       transform="matrix(0.499515,0,0,0.415467,-0.237339,5.61339)"
+       id="g167">
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="61.8805"
+         y="68.4288"
+         style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect134" />
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="59.2613"
+         y="65.8095"
+         style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect135" />
+    </g>
+    <text
+       x="33.749969"
+       y="50.589706"
+       style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+       id="text188">
+      <tspan
+         x="33.750000"
+         y="50.589699"
+         id="tspan635">
+Transient Objects</tspan>
+    </text>
+  </g>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+     style="font-size:12;"
+     id="g644">
+    <g
+       transform="matrix(0.297486,0,0,0.516482,230.251,36.9178)"
+       id="g364">
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="61.8805"
+         y="68.4288"
+         style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect365" />
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="59.2613"
+         y="65.8095"
+         style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect366" />
+    </g>
+    <text
+       x="277.123230"
+       y="85.155571"
+       style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+       id="text367">
+      <tspan
+         x="277.122986"
+         y="85.155602"
+         id="tspan631">
+Persistent</tspan>
+      <tspan
+         x="277.122986"
+         y="96.155602"
+         id="tspan633">
+Objects</tspan>
+    </text>
+  </g>
+</svg>

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/hibernate_logo_a.png
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/hibernate_logo_a.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/lite.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/lite.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/lite.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/lite.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/lite.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,334 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="318.898"
+   height="248.031"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <rect
+     width="291.837"
+     height="57.0074"
+     x="17.3169"
+     y="18.646"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect136" />
+  <rect
+     width="291.837"
+     height="57.0074"
+     x="13.9703"
+     y="16.2302"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect126" />
+  <g
+     transform="matrix(0.326107,0,0,0.765831,9.59261,8.98517)"
+     style="font-size:12;"
+     id="g161">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <g
+     transform="matrix(1.02406,0,0,0.652953,0.223384,39.9254)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <g
+     transform="matrix(0.449834,0,0,0.338463,-3.15909,9.73319)"
+     style="font-size:12;"
+     id="g167">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect134" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect135" />
+  </g>
+  <text
+     x="302.277679"
+     y="65.943230"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="302.277954"
+       y="65.943184"
+       id="tspan360">
+Application</tspan>
+  </text>
+  <text
+     x="36.235924"
+     y="63.796055"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text188">
+    <tspan
+       x="36.235950"
+       y="63.796051"
+       id="tspan427">
+Transient Objects</tspan>
+  </text>
+  <text
+     x="180.416245"
+     y="290.543701"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="180.415939"
+       y="290.543549"
+       id="tspan421">
+Database</tspan>
+  </text>
+  <text
+     x="25.037701"
+     y="179.154755"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="25.037655"
+       y="179.154648"
+       id="tspan384">
+SessionFactory</tspan>
+  </text>
+  <g
+     transform="matrix(0.252763,0,0,0.765831,109.104,8.98517)"
+     style="font-size:12;"
+     id="g386">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect387" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect388" />
+  </g>
+  <g
+     transform="matrix(0.297394,0,0,0.572692,101.502,21.6359)"
+     style="font-size:12;"
+     id="g364">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect365" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect366" />
+  </g>
+  <text
+     x="202.746506"
+     y="102.992203"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text367">
+    <tspan
+       x="202.746948"
+       y="102.992249"
+       id="tspan423">
+Persistent</tspan>
+    <tspan
+       x="202.746948"
+       y="116.992355"
+       id="tspan425">
+Objects</tspan>
+  </text>
+  <text
+     x="174.458496"
+     y="180.080795"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text389">
+    <tspan
+       x="174.458618"
+       y="180.080338"
+       id="tspan392">
+Session</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,188.675,8.98517)"
+     style="font-size:12;"
+     id="g394">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect395" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect396" />
+  </g>
+  <text
+     x="260.413269"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text397">
+    <tspan
+       x="260.412964"
+       y="179.154343"
+       id="tspan400">
+JDBC</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,229.156,8.98517)"
+     style="font-size:12;"
+     id="g405">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect406" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect407" />
+  </g>
+  <text
+     x="320.606903"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text408">
+    <tspan
+       x="320.606964"
+       y="179.154343"
+       id="tspan417">
+JNDI</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,269.281,8.98517)"
+     style="font-size:12;"
+     id="g411">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect412" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect413" />
+  </g>
+  <text
+     x="377.096313"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text414">
+    <tspan
+       x="377.096008"
+       y="179.154999"
+       id="tspan145">
+JTA</tspan>
+  </text>
+</svg>

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/overview.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/overview.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/overview.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/overview.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/en-US/src/main/resources/shared/images/overview.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,250 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="248.031"
+   height="248.031"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,-3.02123)"
+     style="font-size:12;"
+     id="g158">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="17.3527"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect136" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="15.3883"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect126" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,3.04452)"
+     style="font-size:12;"
+     id="g161">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,8.0993)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.543505,2.59104,21.1103)"
+     style="font-size:12;"
+     id="g167">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect134" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect135" />
+  </g>
+  <text
+     x="105.392174"
+     y="56.568123"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="105.392273"
+       y="56.568146"
+       id="tspan186">
+Application</tspan>
+  </text>
+  <text
+     x="81.820183"
+     y="103.149330"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:20;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text188">
+    <tspan
+       x="81.820213"
+       y="103.149727"
+       id="tspan206">
+Persistent Objects</tspan>
+  </text>
+  <text
+     x="111.548180"
+     y="278.927887"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="111.547874"
+       y="278.927551"
+       id="tspan200">
+Database</tspan>
+  </text>
+  <text
+     x="94.436180"
+     y="153.805740"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="94.436180"
+       y="153.805740"
+       id="tspan221">
+HIBERNATE</tspan>
+  </text>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,2.59083,1.02261)"
+     style="font-size:12;"
+     id="g254">
+    <g
+       transform="translate(4.58374,2.61928)"
+       id="g176">
+      <g
+         transform="matrix(0.571429,0,0,0.67347,-10.6174,117.093)"
+         id="g170">
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="61.8805"
+           y="68.4288"
+           style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect171" />
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="59.2613"
+           y="65.8095"
+           style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect172" />
+      </g>
+      <g
+         transform="matrix(0.571429,0,0,0.67347,138.682,117.093)"
+         id="g173">
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="61.8805"
+           y="68.4288"
+           style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect174" />
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="59.2613"
+           y="65.8095"
+           style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect175" />
+      </g>
+    </g>
+    <text
+       x="47.259438"
+       y="182.367538"
+       style="font-weight:bold;stroke-width:1pt;font-family:Courier;"
+       id="text191">
+      <tspan
+         x="47.259399"
+         y="182.367996"
+         id="tspan212">
+hibernate.</tspan>
+      <tspan
+         x="47.259399"
+         y="194.367996"
+         id="tspan214">
+properties</tspan>
+    </text>
+    <text
+       x="198.523010"
+       y="188.260941"
+       style="font-weight:normal;stroke-width:1pt;font-family:helvetica;"
+       id="text194">
+      <tspan
+         id="tspan195">
+XML Mapping</tspan>
+    </text>
+  </g>
+</svg>

Added: trunk/Hibernate3/documentation/manual/es-ES/pom.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-manual</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>hibernate-manual-${translation}</artifactId>
+    <packaging>pom</packaging>
+    <name>Hibernate Manual (${translation})</name>
+
+    <properties>
+        <translation>es-ES</translation>
+    </properties>
+
+</project>

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/master.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/master.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/master.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,203 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
+                      "../support/docbook-dtd/docbookx.dtd"
+[
+<!ENTITY quickstart             SYSTEM "modules/quickstart.xml">
+<!ENTITY tutorial               SYSTEM "modules/tutorial.xml">
+<!ENTITY architecture           SYSTEM "modules/architecture.xml">
+<!ENTITY configuration          SYSTEM "modules/configuration.xml">
+<!ENTITY persistent-classes     SYSTEM "modules/persistent_classes.xml">
+<!ENTITY basic-mapping          SYSTEM "modules/basic_mapping.xml">
+<!ENTITY collection-mapping     SYSTEM "modules/collection_mapping.xml">
+<!ENTITY association-mapping    SYSTEM "modules/association_mapping.xml">
+<!ENTITY component-mapping      SYSTEM "modules/component_mapping.xml">
+<!ENTITY inheritance-mapping    SYSTEM "modules/inheritance_mapping.xml">
+<!ENTITY session-api            SYSTEM "modules/session_api.xml">
+<!ENTITY transactions           SYSTEM "modules/transactions.xml">
+<!ENTITY events                 SYSTEM "modules/events.xml">
+<!ENTITY batch                  SYSTEM "modules/batch.xml">
+<!ENTITY query-hql              SYSTEM "modules/query_hql.xml">
+<!ENTITY query-criteria         SYSTEM "modules/query_criteria.xml">
+<!ENTITY query-sql              SYSTEM "modules/query_sql.xml">
+<!ENTITY filters                SYSTEM "modules/filters.xml">
+<!ENTITY xml                    SYSTEM "modules/xml.xml">
+<!ENTITY performance            SYSTEM "modules/performance.xml">
+<!ENTITY toolset-guide          SYSTEM "modules/toolset_guide.xml">
+<!ENTITY example-parentchild    SYSTEM "modules/example_parentchild.xml">
+<!ENTITY example-weblog         SYSTEM "modules/example_weblog.xml">
+<!ENTITY example-mappings       SYSTEM "modules/example_mappings.xml">
+<!ENTITY best-practices         SYSTEM "modules/best_practices.xml">
+]>
+
+<book lang="es">
+
+    <bookinfo>
+        <title>HIBERNATE - Persistencia Relacional para Java Idiom&#x00e1;tico</title>
+        <subtitle>Documentaci&#x00f3;n de Referencia de Hibernate</subtitle>
+        <releaseinfo>3.0.5</releaseinfo>
+    </bookinfo>
+
+    <toc/>
+
+    <preface id="preface" revision="2">
+        <title>Prefacio</title>
+
+        <para>
+            Advertencia! Esta es una versi&#x00f3;n traducida del ingl&#x00e9;s de
+            la documentaci&#x00e9;n de referencia de Hibernate. La versi&#x00f3;n 
+            traducida puede no estar actualizada! Sin embargo, las diferencias
+            deber&#x00ed;an ser s&#x00f3;lo menores. Consulta la documentaci&#x00f3;n
+            de referencia en ingl&#x00e9;s si est&#x00e1;s perdiendo informaci&#x00f3;n
+            o encuentras alg&#x00fa;n error de traducci&#x00f3;n. Si quieres colaborar con
+            una traducci&#x00f3;n en particular, cont&#x00e1;ctanos en la lista de correo
+            de desarrolladores de Hibernate.
+        </para>
+
+        <para>
+            Traductor(es): Bernardo Antonio Buffa Colom&#x00e9; &lt;kreimer at bbs.frc.utn.edu.ar&gt;
+<!--,
+            Antonio L&#x00f3;pez Gota &lt;antoniogota at gmail.com&gt; -->
+        </para>
+
+        <para>
+            Trabajar con software orientado a objetos y una base de datos relacional puede ser
+            inc&#x00f3;modo y consumir tiempo en los entornos de empresa de hoy. Hibernate es una
+            herramienta de mapeo objeto/relacional para entornos Java. El t&#x00e9;rmino mapeo
+            objeto/relacional (MOR) hace referencia a la t&#x00e9;cnica de mapear una
+            representaci&#x00f3;n de datos desde un modelo de objetos a un modelo de datos relacional
+            con un esquema basado en SQL.
+        </para>
+
+        <para>
+            Hibernate no s&#x00f3;lo se encarga de mapear de clases Java a tablas de base de datos
+            (y de tipos de datos de Java a tipos de datos SQL), sino que tambi&#x00e9;n provee
+            facilidades de consulta y recuperaci&#x00f3;n de datos y puede reducir significativamente
+            el tiempo de desarrollo que de otra forma se gasta en el manejo de los datos en SQL y JDBC.
+        </para>
+
+        <para>
+            La meta de Hibernate es relevar al desarrollador del 95 por ciento de las tareas comunes
+            relacionadas a la programaci&#x00f3;n de la persistencia de los datos.
+            Hibernate puede no ser la mejor soluci&#x00f3;n para aplicaciones que usan solamente
+            procedimientos almacenados para implementar la l&#x00f3;gica de negocio en la base de
+            datos, es mas &#x00fa;til con modelos de dominio orientados a objetos y l&#x00f3;gica de
+            negocio en middle-tier basada en Java. Sin embargo, Hibernate ciertamente puede ayudarte
+            a quitar o encapsular c&#x00f3;digo SQL espec&#x00ed;fico de vendedor y ayudar&#x00e1;
+            con la tarea com&#x00fa;n de traducci&#x00f3;n de resultados desde una representaci&#x00f3;n
+            tabular a un grafo de objetos.
+        </para>
+
+        <para>
+            Si eres nuevo en Hibernate y lo del Mapeo Objeto/Relacional o incluso en Java,
+            sigue por favor estos pasos:
+        </para>
+
+        <orderedlist>
+            <listitem>
+                <para>
+                    Lee <xref linkend="quickstart"/> para un tutorial de 30 minutos, usando Tomcat.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Lee <xref linkend="architecture"/> para entender los entornos en los que
+                    puede ser usado Hibernate.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Dale una mirada al directorio <literal>eg/</literal> en la distribuci&#x00f3;n
+                    de Hibernate, contiene una aplicaci&#x00f3;n independiente simple.
+                    Copia tu driver JDBC al directorio <literal>lib/</literal> y edita 
+                    <literal>etc/hibernate.properties</literal>, especificando los valores 
+                    correctos para tu base de datos. Desde l&#x00ed;nea de comandos en el
+                    directorio de la distribuci&#x00f3;n, tipea <literal>ant eg</literal>
+                    (usando Ant), o bajo Windows, tipea <literal>build eg</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Usa esta documentaci&#x00f3;n de referencia como tu fuente de informaci&#x00f3;n
+                    primaria. Ten en consideraci&#x00f3;n leer <emphasis>Hibernate in Action</emphasis>
+                    (http://www.manning.com/bauer) si necesitas mas ayuda con el dise&#x00f1;o
+                    de aplicaciones o si prefieres un tutorial paso a paso.
+                    Visita tambi&#x00e9;n http://caveatemptor.hibernate.org y descarga la aplicaci&#x00f3;n
+                    de ejemplo para Hibernate in Action.
+                </para>
+            </listitem>
+            <listitem>
+				<para>
+					Los FAQs son respondidos en el sitio web de Hibernate.
+				</para>
+            </listitem>
+			<listitem>
+				<para>
+                                        En el sitio web de Hibernate hay enlaces a demos de terceros, ejemplos
+                                        y tutoriales.
+				</para>
+			</listitem>
+            <listitem>
+                <para>
+                    El Area de Comunidad en el sitio web de Hibernate es una buena fuente
+                    de patrones de dise&#x00f1;o y varias soluciones de integraci&#x00f3;n
+                    (Tomcat, JBoss, Struts, EJB, etc.).
+                </para>
+            </listitem>
+         </orderedlist>
+
+         <para>
+             Si tienes preguntas, usa el foro de usuarios enlazado en el sitio web de Hibernate.
+             Tambi&#x00e9;n proveemos un sistema de seguimiento JIRA para reportes de defectos y
+             peticiones de nuevas caracter&#x00ed;sticas.
+             Si estas interesado en el desarrollo de Hibernate, &#x00fa;nete a la lista de correo
+             de desarrolladores. Si estas interesado en traducir esta documentaci&#x00f3;n a tu
+             lenguaje, cont&#x00e1;ctanos en la lista de correo de desarrolladores.
+         </para>
+
+         <para>
+             A trav&#x00e9;s de JBoss Inc. (see http://www.hibernate.org/SupportTraining/) hay
+             disponibilidad de soporte comercial de desarrollo, soporte de producci&#x00f3;n y
+             entrenamiento en Hibernate.
+             Hibernate es un proyecto de la suite de productos de c&#x00f3;digo abierto
+             JBoss Professional.
+         </para>
+
+    </preface>
+
+    &quickstart;
+    &tutorial;
+    &architecture;
+
+    &configuration;
+
+    &persistent-classes;
+
+    &basic-mapping;
+    &collection-mapping;
+    &association-mapping;
+    &component-mapping;
+    &inheritance-mapping;
+
+    &session-api;
+    &transactions;
+    &events;
+    &batch;
+
+    &query-hql;
+    &query-criteria;
+    &query-sql;
+    &filters;
+    &xml;
+
+    &performance;
+
+    &toolset-guide;
+
+    &example-parentchild;
+    &example-weblog;
+    &example-mappings;
+
+    &best-practices;
+
+</book>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/architecture.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/architecture.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/architecture.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,279 @@
+<chapter id="architecture">
+
+    <title>Arquitectura</title>
+
+    <sect1 id="architecture-overview" revision="1">
+        <title>Visi&#x00f3;n General</title>
+        
+        <para>
+            Una visi&#x00f3;n a (muy) alto nivel de la arquitectura de Hibernate:
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/overview.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/overview.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            Este diagrama muestra a Hibernate usando la base de datos y los datos de
+            configuraci&#x00f3;n para proveer servicios de persistencia (y objetos
+            persistentes) a la aplicaci&#x00f3;n.
+        </para>
+
+        <para>
+            Nos gustar&#x00ed;a mostrar una vista m&#x00e1;s detallada de la arquitectura de tiempo
+            de ejecuci&#x00f3;n. Desafortunadamente, Hibernate es flexible y soporta diferentes
+            enfoques. Mostraremos los dos extremos. En la arquitectura "sencilla", es la
+            aplicaci&#x00f3;n la que provee su propias conexiones JDBC y gestiona sus propias
+            transacciones. Este enfoque usa un m&#x00ed;nimo subconjunto de la API de Hibernate:
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/lite.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/lite.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            La arquitectura "full cream" abstrae a la aplicaci&#x00f3;n de las APIs
+            de JDBC/JTA y deja que Hibernate se encargue de los detalles.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/full_cream.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/full_cream.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            He aqu&#x00ed; algunas definiciones de los objetos en los diagramas:
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
+                    <listitem>
+                        <para>
+                            Cach&#x00e9; threadsafe (inmutable) de mapeos compilados para
+                            una sola base de datos. Es una f&#x00e1;brica de <literal>Session</literal>
+                            y un cliente de <literal>ConnectionProvider</literal>. Opcionalmente,
+                            puede mantener una cach&#x00e9; (de segundo nivel) de datos reusables
+                            entre transacciones, a un nivel de proceso o de cluster.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Session (<literal>org.hibernate.Session</literal>)</term>
+                    <listitem>
+                        <para>
+                            Objeto mono-hebra, de corta vida que representa una conversaci&#x00f3;n
+                            entre la aplicaci&#x00f3;n y el almacenamiento persistente. Envuelve una
+                            conexi&#x00f3;n JDBC. Es una f&#x00e1;brica de <literal>Transaction</literal>.
+                            Mantiene una cach&#x00e9; requerida (de primer nivel) de objetos persistentes,
+                            usada mientras se navega el grafo de objetos o se recuperen objetos por
+                            identificador.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Objetos y colecciones persistentes</term>
+                    <listitem>
+                        <para>
+                            Objetos de corta vida, mono-hebra conteniendo estado persistente y
+                            funci&#x00f3;nalidad de negocio. Estos pueden ser JavaBeans/POJOs
+                            (Plain Old Java Objects, o sea, cualquier objeto Java), la &#x00fa;nica
+                            cosa especial en ellos es que estan asociados actualmente con una
+                            (y s&#x00f3;lo una) <literal>Session</literal>. Tan pronto como la 
+                            <literal>Session</literal> sea cerrada, ser&#x00e1;n separados y
+                            estar&#x00e1;n libres para ser usados en cualquier capa de aplicaci&#x00f3;n.
+                            (por ejemplo, directamente como objetos de transferencia de datos hacia
+                            y desde la capa de presentaci&#x00f3;n).
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Objetos y colecciones transitorios y separados</term>
+                    <listitem>
+                        <para>
+                            Instancias de clases persistentes que no estan acutualmente asociadas
+                            con una <literal>Session</literal>. Pueden haber sido instanciadas por
+                            la aplicaci&#x00f3;n y (a&#x00fa;n) no haber sido hechas persistentes,
+                            o pueden haber sido instanciadas por una <literal>Session</literal> cerrada.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
+                    <listitem>
+                        <para>
+                            (Opcional) Un objeto de corta vida, mono-hebra, usado por la aplicaci&#x00f3;n
+                            para especificar unidades at&#x00f3;micas de trabajo. Abstrae a la aplicaci&#x00f3;n
+                            de las subyacentes transacciones JDBC, JTA o CORBA. En algunos casos, una
+                            <literal>Session</literal> puede extenderse sobre varias <literal>Transaction</literal>s.
+                            Sin embargo, la demarcaci&#x00f3;n de la transacci&#x00f3;n, ya sea usando la API
+                            subyacente o <literal>Transaction</literal>, nunca es opcional!
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
+                    <listitem>
+                        <para>
+                            (Opcional) Una f&#x00e1;brica (y pool) de conexiones JDBC. Abstrae a la aplicaci&#x00f3;n
+                            del <literal>Datasource</literal> o <literal>DriverManager</literal> subyacente.
+                            No se expone a la aplicaci&#x00f3;n, pero puede ser extendido/implementado por
+                            el desarrollador.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
+                    <listitem>
+                        <para>
+                            (Opcional) Una f&#x00e1;brica de instancias de <literal>Transaction</literal>.
+                            No se expone a la aplicaci&#x00f3;n, pero puede ser extendido/implementado por
+                            el desarrollador.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><emphasis>Interfaces de Extensi&#x00f3;n</emphasis></term>
+                    <listitem>
+                        <para>
+                            Hibernate ofrece muchas interfaces de extensi&#x00f3;n opcional que puedes
+                            implementar para modificar a medida el comportamiento de tu capa de persistencia.
+                            Para m&#x00e1;s detalles, mira la documentaci&#x00f3;n de la API.
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+        </para>
+
+        <para>
+            Dada una arquitectura "sencilla", la aplicaci&#x00f3;n pasa por alto las APIs
+            de <literal>Transaction</literal>/<literal>TransactionFactory</literal> y/o
+            <literal>ConnectionProvider</literal>, para hablar directamente a JTA o JDBC.
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-states" revision="1">
+        <title>Estados de instancia</title>
+        <para>
+            Una instancia de una clase persistente puede estar en uno de tres estados
+            diferentes, definidos respecto de su <emphasis>contexto de persistencia</emphasis>.
+            El objeto <literal>Session</literal> de Hibernate es el contexto de persistencia:
+        </para>
+        
+       <variablelist spacing="compact">
+            <varlistentry>
+                <term>transitorio</term>
+                <listitem>
+                    <para>
+                        La instancia no est&#x00e1; y nunca estuvo asociada con
+                        un contexto de persistencia. No tiene identidad persistente
+                        (valor de clave primaria).
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>persistente</term>
+                <listitem>
+                    <para>
+                        La instancia est&#x00e1; actualmente asociada con un
+                        contexto de persistencia. Tiene una identidad persistente
+                        (valor de clave primaria) y, quiz&#x00e1;s, una fila
+                        correspondiente en la base de datos. Para un contexto de
+                        persistencia en particular, Hibernate <emphasis>garantiza</emphasis>
+                        que la identidad persistente es equivalente a la identidad
+                        Java (localizaci&#x00f3;n en memoria del objeto).
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>separado</term>
+                <listitem>
+                    <para>
+                        La instancia estuvo una vez asociada con un contexto
+                        de persistencia, pero ese contexto fue cerrado, o la
+                        instancia fue serializada a otro proceso. Tiene una
+                        identidad persistente y, quiz&#x00e1;s, una fila correspondiente
+                        en la base de datos. Para las instancias separadas,
+                        Hibernate no establece ninguna garant&#x00ed;a sobre
+                        la relaci&#x00f3;n entre identidad persistente e identidad Java.
+                    </para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </sect1>    
+
+    <sect1 id="architecture-jmx" revision="1">
+        <title>Integraci&#x00f3;n JMX</title>
+
+        <para>
+            JMX es el est&#x00e1;ndar J2EE para la gesti&#x00f3;n de componentes Java. Hibernate
+            puede ser gestionado por medio de un servicio est&#x00e1;ndar JMX.
+            Proveemos una implementaci&#x00f3;n de MBean en la distribuci&#x00f3;n,
+            <literal>org.hibernate.jmx.HibernateService</literal>.
+        </para>
+
+        <para>
+            Para ejemplo de c&#x00f3;mo desplegar Hibernate como un servicio JMX en un Servidor
+            de Aplicaciones JBoss, por favor, mira la Gu&#x00ed;a del Usuario de JBoss.
+            En JBoss AS, tienes adem&#x00e1;s estos beneficios si despliegas usando JMX:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>Gesti&#x00f3;n de Sesi&#x00f3;n:</emphasis> El ciclo de vida de la <literal>Session</literal>
+                    de Hibernate puede estar autom&#x00e1;ticamente ligado al &#x00e1;mbito de una transacci&#x00f3;n
+                    JTA. Esto significa que ya no tienes que abrir ni cerrar la <literal>Session</literal> manualmente,
+                    esto pasa a ser trabajo de un interceptor EJB de JBoss. Adem&#x00e1;s tampoco tienes
+                    que preocuparte m&#x00e1;s de la demarcaci&#x00f3;n de la transacci&#x00f3;n (a menos que
+                    que quieras escribir una capa de persitencia portable, por supuesto, usa la API de
+                    <literal>Transaction</literal> de Hibernate para esto). Para acceder a una
+                    <literal>Session</literal> llama al <literal>HibernateContext</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Despliegue de HAR:</emphasis> Usualmente despliegas el servicio JMX de Hibernate
+                    usando un descriptor de despliegue de servicio de JBoss (en un fichero EAR y/o SAR), que soporta
+                    todas las opciones de configuraci&#x00f3;n usuales de una <literal>SessionFactory</literal> de
+                    Hibernate. Sin embargo, todav&#x00ed;a tienes que nombrar todos tus ficheros de mapeo en el
+                    descriptor de despliegue. Si decides usar el depliegue de HAR opcional, JBoss detectar&#x00e1;
+                    autom&#x00e1;ticamente todos los ficheros de mapeo en tu fichero HAR.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Para m&#x00e1;s informaci&#x00f3;n sobre estas opciones, consulta la
+            Gu&#x00ed;a de Usuario del JBoss AS.
+        </para>
+
+        <para>
+            Otra funcionalidad disponible como un servicio JMX son las estad&#x00ed;sticas en
+            tiempo de ejecuci&#x00f3;n de Hibernate. Mira <xref linkend="configuration-optional-statistics"/>.
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-jca" revision="1">
+        <title>Soporte JCA:</title>
+        <para>
+            Hiberate puede adem&#x00e1;s ser configurado como un conector JCA. Por favor mira el
+            sitio web para m&#x00e1;s detalles. Por favor ten en cuenta que el soporte de JCA
+            de Hibernate est&#x00e1; a&#x00fa;n considerado experimental.
+        </para>
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/association_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/association_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/association_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,527 @@
+<chapter id="associations">
+
+    <title>Mapeos de Asociaci&#x00f3;n</title>
+
+    <sect1 id="assoc-intro" revision="1">
+        <title>Introducci&#x00f3;n</title>
+        
+        <para>
+            Los mapeos de asociaci&#x00f3;n son frecuentemente las cosas mas dif&#x00ed;ciles
+            de hacer correctamente. En esta secci&#x00f3;n iremos a trav&#x00e9;s de los casos
+            can&#x00f3;nicos uno a uno, comenzando con los mapeos unidireccionales, y considerando
+            luego los casos bidireccionales. Usaremos <literal>Person</literal> y <literal>Address</literal>
+            en todos los ejemplos.
+        </para>
+        
+        <para>
+                Clasificaremos las asociaciones por cuanto mapeen o no a una tabla
+                de uni&#x00f3;n interviniente, y por su multiplicidad.
+        </para>
+        
+        <para>
+                Las claves for&#x00e1;neas que aceptan valores nulos (en adelante, nullables)
+                no son consideradas una buena pr&#x00e1;ctica en el modelado tradicional de datos,
+                as&#x00ed; que todos nuestros ejemplos usan claves for&#x00e1;neas no nullables.
+                Esto no es un requerimiento de Hibernate, y todos los mapeos funcionar&#x00e1;n
+                si quitas las restricciones de nulabilidad.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="assoc-unidirectional" revision="1">
+        <title>Asociaciones Unidireccionales</title>
+        
+        <sect2 id="assoc-unidirectional-m21">
+        <title>muchos a uno</title>
+        
+        <para>
+            Una <emphasis>asociaci&#x00f3;n unidireccional muchos-a-uno</emphasis> es el tipo
+            m&#x00e1;s com&#x00fa;n de asociaciones unidireccionales.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-121">
+        <title>uno a uno</title>
+        
+        <para>
+            Una <emphasis>asociaci&#x00f3;n unidireccional uno-a-uno en una clave primaria</emphasis>
+            es casi id&#x00e9;ntica. La &#x00fa;nica diferencia es la restricci&#x00f3;n de unicidad
+            de la columna.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId" 
+        unique="true"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        <para>
+            Usualmente, una <emphasis>asociaci&#x00f3;n unidireccional uno-a-uno en una
+            clave primaria</emphasis> usa un generador de id especial. (Observa que hemos
+            invertido el sentido de la asociaci&#x00f3;n en este ejemplo).
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+</class>
+
+<class name="Address">
+    <id name="id" column="personId">
+        <generator class="foreign">
+            <param name="property">person</param>
+        </generator>
+    </id>
+    <one-to-one name="person" constrained="true"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+        <sect2 id="assoc-unidirectional-12m">
+        <title>uno a muchos</title>
+        
+        <para>
+            Una <emphasis>asociaci&#x00f3;n unidireccional uno-a-muchos en una clave for&#x00e1;nea</emphasis>
+            es un caso muy inusual, y realmente no est&#x00e1; recomendada.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses">
+        <key column="personId" 
+            not-null="true"/>
+        <one-to-many class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( addressId bigint not null primary key, personId bigint not null )
+        ]]></programlisting>
+        
+        <para>
+            Creemos que es mejor usar una tabla de uni&#x00f3;n para este tipo de asociaci&#x00f3;n.
+        </para>
+        
+        </sect2>
+    
+    </sect1>
+
+    <sect1 id="assoc-unidirectional-join" revision="1">
+        <title>Asociaciones unidireccionales con tablas de uni&#x00f3;n</title>
+        
+        <sect2 id="assoc-unidirectional-join-12m">
+        <title>uno a muchos</title>
+        
+        <para>
+            Una <emphasis>asociaci&#x00f3;n unidireccional uno-a-muchos en una tabla de uni&#x00f3;n</emphasis>
+            es m&#x00e1;s preferible. Observa que especificando <literal>unique="true"</literal>, hemos
+            cambiado la multiplicidad de muchos-a-muchos a uno-a-muchos.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            unique="true"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-m21">
+        <title>muchos a uno</title>
+        
+        <para>
+            Una <emphasis>asociaci&#x00f3;n unidireccional muchos-a-uno en una tabla de uni&#x00f3;n</emphasis>
+            es bastante com&#x00fa;n cuando la asociaci&#x00f3;n es opcional.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-121">
+        <title>uno a uno</title>
+        
+        <para>
+            Una <emphasis>asociaci&#x00f3;n unidireccional uno-a-uno en una tabla de uni&#x00f3;n</emphasis>
+            es inusual en extremo, pero posible.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-m2m">
+        <title>muchos a muchos</title>
+        
+        <para>
+            Finalmente, tenemos una <emphasis>asociaci&#x00f3;n unidireccional muchos-a-muchos</emphasis>
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="assoc-bidirectional" revision="1">
+        <title>Asociaciones Bidireccionales</title>
+        
+        <sect2 id="assoc-bidirectional-m21">
+        <title>uno a muchos / muchos a uno</title>
+        
+        <para>
+            Una <emphasis>asociaci&#x00f3;n bidireccional muchos-a-uno</emphasis> es
+            el tipo m&#x00e1;s com&#x00fa;n de asociaci&#x00f3;n. (Esta es la relaci&#x00f3;n
+            est&#x00e1;ndar padre/hijo.)
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <set name="people" inverse="true">
+        <key column="addressId"/>
+        <one-to-many class="Person"/>
+    </set>
+</class>]]></programlisting>
+
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+        <sect2 id="assoc-bidirectional-121">
+        <title>uno a uno</title>
+        
+        <para>
+            Una <emphasis>asociaci&#x00f3;n bidireccional uno-a-uno en una clave for&#x00e1;nea</emphasis>
+            es bastante com&#x00fa;n.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId" 
+        unique="true"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+   <one-to-one name="person" 
+        property-ref="address"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        <para>
+            Una <emphasis>asociaci&#x00f3;n bidireccional uno-a-uno en una clave primaria</emphasis>
+            usa el generador de id especial.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <one-to-one name="address"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="personId">
+        <generator class="foreign">
+            <param name="property">person</param>
+        </generator>
+    </id>
+    <one-to-one name="person" 
+        constrained="true"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="assoc-bidirectional-join" revision="1">
+        <title>Asociaciones bidireccionales con tablas de uni&#x00f3;n</title>
+        
+        <sect2 id="assoc-bidirectional-join-12m">
+        <title>uno a muchos / muchos a uno</title>
+        
+        <para>
+            Una <emphasis>asociaci&#x00f3;n bidireccional uno-a-muchos en una tabla de uni&#x00f3;n</emphasis>.
+            Observa que el <literal>inverse="true"</literal> puede ir a cualquier lado de la asociaci&#x00f3;n,
+            en la colecci&#x00f3;n, o en la uni&#x00f3;n.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" 
+        table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            unique="true"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        inverse="true" 
+        optional="true">
+        <key column="addressId"/>
+        <many-to-one name="person"
+            column="personId"
+            not-null="true"/>
+    </join>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+         <sect2 id="assoc-bidirectional-join-121">
+        <title>uno a uno</title>
+        
+        <para>
+            Una <emphasis>asociaci&#x00f3;n bidireccional uno-a-uno en una tabla de uni&#x00f3;n</emphasis>
+            es inusual en extremo, pero posible.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true"
+        inverse="true">
+        <key column="addressId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="personId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+
+        </sect2>
+        
+        <sect2 id="assoc-bidirectional-join-m2m">
+        <title>muchos a muchos</title>
+        
+        <para>
+            Finalmente, tenemos una <emphasis>asociaci&#x00f3;n bidireccional muchos-a-muchos</emphasis>.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <set name="people" inverse="true">
+        <key column="addressId"/>
+        <many-to-many column="personId"
+            class="Person"/>
+    </set>
+</class>]]></programlisting>
+
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+    </sect1>
+
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/basic_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/basic_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/basic_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,3222 @@
+<chapter id="mapping">
+    <title>Mapeo O/R B&#x00e1;sico</title>
+
+    <sect1 id="mapping-declaration" revision="1">
+        <title>Declaraci&#x00f3;n de mapeo</title>
+
+        <para>
+            Los mapeos objeto/relacional se definen usualmente en un documento XML.
+            El documento de mapeo est&#x00e1; dise&#x00f1;ado para ser le&#x00ed;ble y 
+            editable a mano. El lenguaje de mapeo es Java-c&#x00e9;ntrico, o sea que los
+            mapeos se construyen alrededor de declaraciones de clases persistentes,
+            no declaraciones de tablas.
+        </para>
+        
+        <para>
+            Observa que, incluso aunque muchos usuarios de Hibernate eligen escribir el
+            XML a mano, existe una cantidad de herramientas para generar el documento de
+            mapeo, incluyendo XDoclet, Middlegen y AndroMDA.
+        </para>
+
+        <para>
+            Comencemos por un mapeo de ejemplo:
+        </para>
+
+        <programlisting id="mapping-declaration-ex1" revision="1"><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+        <class name="Cat" 
+            table="cats"
+            discriminator-value="C">
+                
+                <id name="id">
+                        <generator class="native"/>
+                </id>
+
+                <discriminator column="subclass" 
+                     type="character"/>
+
+                <property name="weight"/>
+
+                <property name="birthdate"
+                    type="date" 
+                    not-null="true" 
+                    update="false"/>
+
+                <property name="color"
+                    type="eg.types.ColorUserType"
+                    not-null="true"
+                    update="false"/>
+
+                <property name="sex"
+                    not-null="true" 
+                    update="false"/>
+
+                <property name="litterId"
+                    column="litterId"
+                    update="false"/>
+
+                <many-to-one name="mother"
+                    column="mother_id"
+                    update="false"/>
+
+                <set name="kittens"
+                    inverse="true"
+                    order-by="litter_id">
+                        <key column="mother_id"/>
+                        <one-to-many class="Cat"/>
+                </set>
+
+                <subclass name="DomesticCat"
+                    discriminator-value="D">
+
+                        <property name="name" 
+                            type="string"/>
+
+                </subclass>
+
+        </class>
+
+        <class name="Dog">
+                <!-- mapping for Dog could go here -->
+        </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+             Discutiremos ahora el contenido del documento de mapeo. Describiremos s&#x00f3;lo los
+             elementos y atributos que son usados por Hibernate en tiempo de ejecuci&#x00f3;n. El
+             documento de mapeo contiene adem&#x00e1;s algunos atributos y elementos extra opcionales
+             que afectan los esquemas de base de datos exportados por la herramienta de exportaci&#x00f3;n
+             de esquemas. (Por ejemplo, el atributo <literal>not-null</literal>.)
+        </para>
+
+
+
+        <sect2 id="mapping-declaration-doctype" revision="2">
+            <title>Doctype</title>
+
+            <para>
+                Todos los mapeos XML deben declarar el doctype mostrado. El DTD actual puede
+                ser encontrado en el URL mencionado arriba, en el directorio
+                <literal>hibernate-x.x.x/src/org/hibernate</literal>, o en <literal>hibernate3.jar</literal>.
+                Hibernate siempre buscar&#x00e1; el DTD primero en el classpath. Si experimentas
+                b&#x00fa;squedas del DTD usando una conexi&#x00f3;n de Internet, chequea tu declaraci&#x00f3;n
+                de DTD contra la contenida en el classpath.
+            </para>
+        </sect2>
+
+        <sect2 id="mapping-declaration-mapping" revision="3">
+            <title>hibernate-mapping</title>
+
+            <para>
+                Este elemento tiene muchos atributos opcionales. Los atributos <literal>schema</literal>
+                y <literal>catalog</literal> especifican que las tablas a las que se refiere en el mapeo
+                pertenecen al esquema y/o cat&#x00e1;logo mencionado(s). De especificarse, los nombres de
+                tablas ser&#x00e1;n cualificados por el nombre de esquema y cat&#x00e1;logo dados.
+                De omitirse, los nombres de tablas no ser&#x00e1;n cualificados. El atributo
+                <literal>default-cascade</literal> especifica qu&#x00e9; estilo de cascada debe asumirse
+                para las propiedades y colecciones que no especifican un atributo <literal>cascade</literal>.
+                El atributo <literal>auto-import</literal> nos permite usar nombres de clase sin cualificar
+                en el lenguaje de consulta, por defecto.
+            </para>
+ 
+             <programlistingco>
+                 <areaspec>
+                     <area id="hm1" coords="2 55"/>
+                     <area id="hm2" coords="3 55"/>
+                     <area id="hm3" coords="4 55"/>
+                     <area id="hm4" coords="5 55"/>
+                     <area id="hm5" coords="6 55"/>
+                     <area id="hm6" coords="7 55"/>
+                     <area id="hm7" coords="8 55"/>
+                 </areaspec>
+                 <programlisting><![CDATA[<hibernate-mapping
+         schema="schemaName"
+         catalog="catalogName"
+         default-cascade="cascade_style"
+         default-access="field|property|ClassName"
+         default-lazy="true|false"
+         auto-import="true|false"
+         package="package.name"
+ />]]></programlisting>
+                 <calloutlist>
+                     <callout arearefs="hm1">
+                         <para>
+                             <literal>schema</literal> (opcional): El nombre de un esquema de la base de datos.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm2">
+                         <para>
+                             <literal>catalog</literal> (opcional): El nombre de un cat&#x00e1;logo de la base de datos.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm3">
+                         <para>
+                             <literal>default-cascade</literal> (opcional - por defecto a <literal>none</literal>): 
+                             Un estilo de cascada por defecto.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm4">
+                         <para>
+                             <literal>default-access</literal> (opcional - por defecto a <literal>property</literal>):
+                             La estrategia que Hibernate debe usar para acceder a todas las propiedades.
+                             Puede ser una implementaci&#x00f3;n personalizada de <literal>PropertyAccessor</literal>.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm5">
+                         <para>
+                             <literal>default-lazy</literal> (opcional - por defecto a <literal>true</literal>):
+                             El valor por defecto para los atributos <literal>lazy</literal> de mapeos de clase
+                             y colleci&#x00f3;n no especificados.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm6">
+                         <para>
+                             <literal>auto-import</literal> (opcional - por defecto a <literal>true</literal>):
+                             Especifica si podemos usar nombres de clases no cualificados (de clases en este mapeo)
+                             en el lenguaje de consulta.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm7">
+                         <para>
+                             <literal>package</literal> (opcional): Especifica un prefijo de paquete a asumir
+                             para los nombres no cualificados de clase en el documento de mapeo.
+                         </para>
+                     </callout>
+                 </calloutlist>
+             </programlistingco>
+             
+             <para>
+                 Si tienes dos clases persistentes con el mismo nombre (sin cualificar), debes establecer
+                 <literal>auto-import="false"</literal>. Hibernate lanzar&#x00e1; una excepci&#x00f3;n si
+                 intentas asignar dos clases al mismo nombre "importado".
+             </para>
+
+             <para>
+                 Observa que el elemento <literal>hibernate-mapping</literal> te permite anidar
+                 muchos mapeos <literal>&lt;class&gt;</literal> persistentes, como se muestra arriba.
+                 Sin embargo, es una buena pr&#x00e1;ctica (y se espera de algunas herramientas) mapear
+                 s&#x00f3;lo a una sola clase persistente (o a una sola jerarqu&#x00ed;a de clases) en
+                 un fichero de mapeo y nombrarlo despu&#x00e9;s de la superclase persistente;
+                 por ejemplo, <literal>Cat.hbm.xml</literal>, <literal>Dog.hbm.xml</literal>,
+                 o, si se usa herencia, <literal>Animal.hbm.xml</literal>.
+             </para>
+ 
+        </sect2>
+
+        <sect2 id="mapping-declaration-class" revision="3">
+            <title>class</title>
+
+            <para>
+                Puedes declarar una clase persistente usando el elemento <literal>class</literal>:
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="class1" coords="2 55"/>
+                    <area id="class2" coords="3 55" />
+                    <area id="class3" coords="4 55"/>
+                    <area id="class4" coords="5 55" />
+                    <area id="class5" coords="6 55"/>
+                    <area id="class6" coords="7 55" />
+                    <area id="class7" coords="8 55"/>
+                    <area id="class8" coords="9 55" />
+                    <area id="class9" coords="10 55" />
+                    <area id="class10" coords="11 55"/>
+                    <area id="class11" coords="12 55"/>
+                    <area id="class12" coords="13 55"/>
+                    <area id="class13" coords="14 55"/>
+                    <area id="class14" coords="15 55"/>
+                    <area id="class15" coords="16 55"/>
+                    <area id="class16" coords="17 55"/>
+                    <area id="class17" coords="18 55"/>
+                    <area id="class18" coords="19 55"/>
+                    <area id="class19" coords="20 55"/>
+                    <area id="class20" coords="21 55"/>
+                    <area id="class21" coords="22 55"/>
+                </areaspec>
+                <programlisting><![CDATA[<class
+        name="ClassName"
+        table="tableName"
+        discriminator-value="discriminator_value"
+        mutable="true|false"
+        schema="owner"
+        catalog="catalog"
+        proxy="ProxyInterface"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        select-before-update="true|false"
+        polymorphism="implicit|explicit"
+        where="arbitrary sql where condition"
+        persister="PersisterClass"
+        batch-size="N"
+        optimistic-lock="none|version|dirty|all"
+        lazy="true|false"
+        entity-name="EntityName"
+        check="arbitrary sql check condition"
+        rowid="rowid"
+        subselect="SQL expression"
+        abstract="true|false"
+        node="element-name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="class1">
+                        <para>
+                            <literal>name</literal> (opcional): El nombre completamente cualificado de la clase
+                            Java persistente (o interface). Si este atributo es omitido, se asume que el mapeo
+                            es para una entidad non-POJO.
+                        </para>
+                    </callout>
+                    <callout arearefs="class2">
+                        <para>
+                            <literal>table</literal> (opcional - por defecto al nombre no cualificado de la clase):
+                            El nombre de su tabla en base de datos.
+                        </para>
+                    </callout>
+                    <callout arearefs="class3">
+                        <para>
+                            <literal>discriminator-value</literal> (opcional - por defecto al nombre de la clase):
+                            Un valor que distingue subclases individuales, usado para el comportamiento
+                            polim&#x00f3;rfico. Los valores aceptables incluyen <literal>null</literal>
+                            y <literal>not null</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="class4">
+                        <para>
+                            <literal>mutable</literal> (opcional, por defecto a <literal>true</literal>):
+                            Especifica que las instancias de la clase (no) son mutables.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class5">
+                        <para>
+                            <literal>schema</literal> (opcional): Sobreescribe el nombre de esquema especificado
+                            por el elemento ra&#x00ed;z <literal>&lt;hibernate-mapping&gt;</literal>.
+                        </para>
+                    </callout>                
+                    <callout arearefs="class6">
+                        <para>
+                            <literal>catalog</literal> (opcional): Sobreescribe el nombre de cat&#x00e1;logo
+                            especificado por el elemento ra&#x00ed;z <literal>&lt;hibernate-mapping&gt;</literal>.
+                        </para>
+                    </callout>                
+                    <callout arearefs="class7">
+                        <para>
+                            <literal>proxy</literal> (opcional): Especifica una interface a usar para proxies
+                            de inicializaci&#x00f3;n perezosa. Puedes especificar el nombre mismo de la clase.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class8">
+                        <para>
+                            <literal>dynamic-update</literal> (opcional, por defecto a <literal>false</literal>): 
+                            Especifica que el SQL <literal>UPDATE</literal> debe ser generado en tiempo de
+                            ejecuci&#x00f3;n y contener solamente aquellas columnas cuyo valor haya cambiado.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class9">
+                        <para>
+                            <literal>dynamic-insert</literal> (opcional, por defecto a <literal>false</literal>): 
+                            Especifica que el SQL <literal>INSERT</literal> debe ser generado en tiempo de
+                            ejecuci&#x00f3;n y contener solamente aquellas columnas cuyo valores no son nulos.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class10">
+                        <para>
+                            <literal>select-before-update</literal> (opcional, por defecto a <literal>false</literal>): 
+                            Especifica que Hibernate <emphasis>nunca</emphasis> debe realizar un SQL <literal>UPDATE</literal> 
+                            a menos que se tenga certeza que un objeto haya sido modificado realmente.
+                            En ciertos casos, (realmente, s&#x00f3;lo cuando un objeto transitorio ha sido asociado
+                            con una sesi&#x00f3;n nueva usando <literal>update()</literal>), esto significa que Hibernate
+                            realizar&#x00e1; una SQL <literal>SELECT</literal> extra para determinar si un
+                            <literal>UPDATE</literal> es realmente requerido.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class11">
+                        <para>
+                            <literal>polymorphism</literal> (opcional, por defecto a <literal>implicit</literal>): 
+                            Determina si se usa polimorfismo de consulta impl&#x00ed;cito o expl&#x00ed;cito.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class12">
+                        <para>
+                            <literal>where</literal> (opcional) especifica una condici&#x00f3;n SQL <literal>WHERE</literal>
+                            arbitraria paraa ser usada al recuperar objetos de esta clase.
+                        </para>
+                    </callout>                 
+                    <callout arearefs="class13">
+                        <para>
+                            <literal>persister</literal> (opcional): Especifica un <literal>ClassPersister</literal>
+                            personalizado.
+                        </para>
+                    </callout>                 
+                    <callout arearefs="class14">
+                        <para>
+                            <literal>batch-size</literal> (opcional, por defecto a <literal>1</literal>)
+                            especifica un "tama&#x00f1;o de lote" para traer instancias de esta clase por
+                            identificador.
+                        </para>
+                    </callout>                 
+                   <callout arearefs="class15">
+                        <para>
+                            <literal>optimistic-lock</literal> (opcional, por defecto a <literal>version</literal>):
+                            Determina la estrategia optimista de bloqueo.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class16">
+                        <para>
+                            <literal>lazy</literal> (opcional):
+                            La recuperaci&#x00f3;n perezosa puede ser deshabilitada por completo estableciendo
+                            <literal>lazy="false"</literal>.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class17">
+                        <para>
+                            <literal>entity-name</literal> (opcional): Hibernate3 permite que una clase sea
+                            mapeada varias veces (potencialmente a tablas diferentes), y permite que los mapeos
+                            de entidad sean representados por Maps o XML al nivel de Java. En estos casos,
+                            debes proveer un nombre expl&#x00ed;cito arbitrario para la entidad.
+                            Para m&#x00e1;s informaci&#x00f3;n, mira
+                            <xref linkend="persistent-classes-dynamicmodels"/> y <xref linkend="xml"/>.
+                        </para>
+                    </callout>
+                    <callout arearefs="class18">
+                        <para>
+                            <literal>check</literal> (opcional): Una expresi&#x00f3;n SQL usada para generar
+                            una restricci&#x00f3;n <emphasis>check</emphasis> multi-fila para la generaci&#x00f3;n
+                            autom&#x00e1;tica de esquema.
+                        </para>
+                    </callout>
+                    <callout arearefs="class19">
+                        <para>
+                            <literal>rowid</literal> (opcional): Hibernate puede usar los llamados ROWIDs en las
+                            bases de datos que los soporten. Por ejemplo, en Oracle, Hibernate puede usar la columna
+                            extra <literal>rowid</literal> para actualizaciones r&#x00e1;pidas si estableces esta
+                            opci&#x00f3;n a <literal>rowid</literal>. Un ROWID es un detalle de implementaci&#x00f3;n
+                            y representa la posici&#x00f3;n f&#x00ed;sica de la tupla almacenada.
+                        </para>
+                    </callout>
+                    <callout arearefs="class20">
+                        <para>
+                            <literal>subselect</literal> (opcional): Mapea una entidad inmutable y de s&#x00f3;lo
+                            lectura a una subselect de base de datos. Es &#x00fa;til si quieres tener una vista
+                            en vez de una tabla base, pero no tienes vistas. Mira debajo para m&#x00e1;s informaci&#x00f3;n.
+                        </para>
+                    </callout>
+                    <callout arearefs="class21">
+                        <para>
+                            <literal>abstract</literal> (opcional): Usado para marcar superclases abstractas en
+                            jerarqu&#x00ed;as <literal>&lt;union-subclass&gt;</literal>.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+           
+            <para>
+                Es perfectamente aceptable que la clase persistente mencionada sea una interface.
+                Entonces declarar&#x00ed;as clases que implementan esa interface usando el elemento
+                <literal>&lt;subclass&gt;</literal>. Puedes persistir cualquier clase interna
+                <emphasis>est&#x00e1;tica</emphasis>. Debes especificar el nombre de la clase usando la forma
+                est&#x00e1;ndar. Por ejemplo, <literal>eg.Foo$Bar</literal>.
+            </para>
+
+            <para>
+                Las clases inmutables, <literal>mutable="false"</literal>, no pueden ser actualizadas o
+                borradas por la aplicaci&#x00f3;n. Esto permite a Hibernate hacer ciertas optimizaciones
+                menores de rendimiento.
+            </para>
+            
+            <para>
+                El atributo opcional <literal>proxy</literal> habilita la inicializaci&#x00f3;n postergada
+                de instancias persistentes de la clase. Hibernate inicialmente retornar&#x00e1; proxies
+                CGLIB que implementan la interface mencionada. El objeto persistente real ser&#x00e1;
+                cargado cuando se invoque un m&#x00e9;todo del proxy. Mira "Proxies para Inicializaci&#x00f3;n
+                Postergada" debajo.
+            </para>
+            
+            <para>
+                Por polimorfismo <emphasis>impl&#x00ed;cito</emphasis> se entiende que las instancias de la clase
+                ser&#x00e1;n devueltas por una consulta que mencione cualquier superclase, o interface implementada,
+                o la clase misma; y que las instancias de cualquier subclase de la clase ser&#x00e1;n devueltas
+                por una clase que mencione a la clase en s&#x00ed;.
+                Por polimorfismo <emphasis>expl&#x00ed;cito</emphasis> se entiende que instancias de la clase
+                ser&#x00e1;n devueltas s&#x00f3;lo por consultas que mencionen expl&#x00ed;citamente la clase;
+                y que las consultas que mencionen la clase devolver&#x00e1;n s&#x00f3;lo instancias de subclases
+                mapeadas dentro de esta declaraci&#x00f3;n <literal>&lt;class&gt;</literal> como una
+                <literal>&lt;subclass&gt;</literal> o <literal>&lt;joined-subclass&gt;</literal>.
+                Para la mayor&#x00ed;a de los prop&#x00f3;sitos el defecto,
+                <literal>polymorphism="implicit"</literal>, resulta apropiado.
+                El polimorfismo expl&#x00ed;cito es &#x00fa;til cuando dos clases diferentes est&#x00e1;n
+                mapeadas a la misma tabla (esto permite tener una clase "liviana" que contenga un subconjunto
+                de columnas de la tabla).
+            </para>
+            
+            <para>
+                El atributo <literal>persister</literal> te permite personalizar la estrategia de persistencia
+                para la clase. Puedes, por ejemplo, especificar tu propia subclase de
+                <literal>org.hibernate.persister.EntityPersister</literal> o incluso puedes proveer una implementaci&#x00f3;n
+                completamente nueva de la interface <literal>org.hibernate.persister.ClassPersister</literal> que implemente
+                la persistencia por medio, por ejemplo, de llamadas a procedimientos almacenados, serializaci&#x00f3;n a
+                ficheros planos o LDAP. Para un ejemplo simple (de persistencia a una  <literal>Hashtable</literal>) mira 
+                <literal>org.hibernate.test.CustomPersister</literal>.
+            </para>
+            
+            <para>
+                Observa que los valores de <literal>dynamic-update</literal> y <literal>dynamic-insert</literal>
+                no son heredados por las subclases y por lo tanto deben especificarse en los elementos
+                <literal>&lt;subclass&gt;</literal> o <literal>&lt;joined-subclass&gt;</literal>.
+                Estos ajustes pueden incrementar el rendimiento en algunos casos, pero podr&#x00ed;an mermarlo en otros.
+                Ten juicio en su uso.
+            </para>
+            
+            <para>
+                Generalmente el uso de <literal>select-before-update</literal> disminuir&#x00e1; el rendimiento.
+                Es muy &#x00fa;til prevenir que se llame innecesariamente a un disparador de actualizaci&#x00f3;n de
+                base de datos al volver a unir un grafo de instancias separadas a una <literal>Session</literal>.
+            </para>
+            
+            <para>
+                Si habilitas <literal>dynamic-update</literal>, tendr&#x00e1;s opci&#x00f3;n de estrategias
+                de bloqueo optimistas:
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <literal>version</literal> chequea las columnas de versi&#x00f3;n/timestamp
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>all</literal> chequea todas las columnas
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>dirty</literal> chequea las columnas modificadas, permitiendo algunas
+                        actualizaciones concurrentes
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>none</literal> no usa bloqueo optimista
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <para>
+                Recomendamos <emphasis>muy</emphasis> fuertemente que uses columnas de
+                versi&#x00f3;n/timestamp para bloqueo optimista con Hibernate. Esta es la estrategia
+                &#x00f3;ptima con respecto al rendimiento y es la &#x00fa;nica estrategia que maneja
+                correctamente las modificaciones hechas a las instancias separadas.
+                (por ejemplo, cuando se usa <literal>Session.merge()</literal>).
+            </para>
+
+            <para>
+                Para un mapeo de Hibernate, no hay diferencia entre una vista y una tabla base.
+                Como se supone esto es transparente a nivel de base de datos (observa que algunos
+                DBMS no soportan correctamente las vistas, especialmente con las actualizaciones).
+                A veces quieres usar una vista, pero no puedes crear una en la base de datos
+                (por ejemplo, con un esquema heredado). En este caso, puedes mapear una entidad inmutable
+                de s&#x00f3;lo lectura a una expresi&#x00f3;n de subconsulta SQL dada.
+            </para>
+
+            <programlisting><![CDATA[<class name="Summary">
+    <subselect>
+        select item.name, max(bid.amount), count(*)
+        from item
+        join bid on bid.item_id = item.id
+        group by item.name
+    </subselect>
+    <synchronize table="item"/>
+    <synchronize table="bid"/>
+    <id name="name"/>
+    ...
+</class>]]></programlisting>
+
+            <para>
+                Declara las tablas con las que sincronizar esta entidad, asegurando que el auto-flush
+                ocurre correctamente, y que las consultas contra la entidad derivada no devuelven datos
+                desactualizados. El <literal>&lt;subselect&gt;</literal> est&#x00e1; disponible tanto
+                como un atributo o como un elemento anidado de mapeo.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-id" revision="3">
+            <title>id</title>
+
+            <para>
+                Las clases mapeadas <emphasis>deben</emphasis> declarar la columna de clave primaria de la tabla
+                de la base de datos. En la mayor&#x00ed;a de los casos tendr&#x00e1; tambi&#x00e9;n una propiedad
+                estilo Javabeans que tenga el identificador &#x00fa;nico de una instancia. El elemento
+                <literal>&lt;id&gt;</literal> define el mapeo de esa propiedad a la columna de clave primaria.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="id1" coords="2 70"/>
+                    <area id="id2" coords="3 70" />
+                    <area id="id3" coords="4 70"/>
+                    <area id="id4" coords="5 70" />
+                    <area id="id5" coords="6 70" />
+                </areaspec>
+                <programlisting><![CDATA[<id
+        name="propertyName"
+        type="typename"
+        column="column_name"
+        unsaved-value="null|any|none|undefined|id_value"
+        access="field|property|ClassName"
+        node="element-name|@attribute-name|element/@attribute|.">
+
+        <generator class="generatorClass"/>
+</id>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="id1">
+                        <para>
+                            <literal>name</literal> (opcional): El nombre de la propiedad del indentificador.
+                        </para>
+                    </callout>
+                    <callout arearefs="id2">
+                        <para>
+                            <literal>type</literal> (opcional): Un nombre que indica el tipo Hibernate.
+                        </para>
+                    </callout>
+                    <callout arearefs="id3">
+                        <para>
+                            <literal>column</literal> (opcional - por defecto al nombre de la propiedad): 
+                            El nombre de la columna de clave primaria.
+                        </para>
+                    </callout>
+                    <callout arearefs="id4">
+                        <para>
+                            <literal>unsaved-value</literal> (opcional - por defecto al valor "sensible"): 
+                            Una valor de la propiedad identificadora que indica que una instancia est&#x00e1;
+                            reci&#x00e9;n instanciada (sin salvar), distingui&#x00e9;ndola de instancias separadas
+                            que fueran salvadas o cargadas en una sesi&#x00f3;n previa.
+                        </para>
+                    </callout>            
+                   <callout arearefs="id5">
+                        <para>
+                            <literal>access</literal> (opcional - por defecto a <literal>property</literal>):
+                            La estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                Si se omite el atributo <literal>name</literal>, se asume que la clase no tiene propiedad
+                identificadora.
+            </para>
+            
+            <para>
+                El atributo <literal>unsaved-value</literal> es importante! Si la propiedad identificadora de tu
+                clase no tiene por defecto el valor por defecto normal de Java (null o cero), entonces debes especificar
+                el valor por defecto real.
+            </para>
+
+             <para>
+                Hay una declaraci&#x00f3;n <literal>&lt;composite-id&gt;</literal> alternativa para permitir acceso
+                a datos heredados con claves compuestas. Desalentamos fuertemente su uso para cualquier otra cosa.
+            </para>
+            
+            <sect3 id="mapping-declaration-id-generator" revision="2">
+                <title>Generator</title>
+
+                <para>
+                    El elemento hijo opcional <literal>&lt;generator&gt;</literal> nombra una clase Java
+                    usada en generar identificadores &#x00fa;nicos para instancias de la clase persistente.
+                    De requerirse alg&#x00fa;n par&#x00e1;metro para configurar o inicializar la instancia del generador,
+                    se pasa usando el elemento <literal>&lt;param&gt;</literal>.
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="org.hibernate.id.TableHiLoGenerator">
+                <param name="table">uid_table</param>
+                <param name="column">next_hi_value_column</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                    Todos los generadores implementan la interface <literal>org.hibernate.id.IdentifierGenerator</literal>.
+                    Esta es una interface muy simple; algunas aplicaciones pueden escoger proveer sus propias
+                    implementaciones especializadas. Sin embargo, Hibernate provee un rango de implementaciones
+                    prefabricadas. Hay nombres alias de atajo para los generadores prefabricados:
+                    <variablelist>
+                        <varlistentry>
+                        <term><literal>increment</literal></term>
+                        <listitem>
+                            <para>
+                                genera indentificadores de tipo <literal>long</literal>, <literal>short</literal> o
+                                <literal>int</literal> que s&#x00f3;lo son &#x00fa;nicos cuando ning&#x00fa;n otro proceso
+                                est&#x00e1; insertando datos en la misma tabla. <emphasis>No usar en un cluster.</emphasis>
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>identity</literal></term>
+                        <listitem>
+                            <para>
+                                soporta columnas de identidad en DB2, MySQL, MS SQL Server, Sybase y
+                                HypersonicSQL. El identificador devuelto es de tipo <literal>long</literal>,
+                                <literal>short</literal> o <literal>int</literal>.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>sequence</literal></term>
+                        <listitem>
+                            <para>
+                                usa una secuencia en DB2, PostgreSQL, Oracle, SAP DB, McKoi o un generador
+                                en Interbase. El identificador devuelto es de tipo <literal>long</literal>,
+                                <literal>short</literal> o <literal>int</literal>.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>hilo</literal></term>
+                        <listitem>
+                            <para id="mapping-declaration-id-hilodescription" revision="1">
+                                usa un algoritmo alto/bajo para generar eficientemente identificadores de tipo
+                                <literal>long</literal>, <literal>short</literal> o <literal>int</literal>,
+                                dada una tabla y columna como fuente de valores altos (por defecto
+                                <literal>hibernate_unique_key</literal> y <literal>next_hi</literal> respectivamente).
+                                El algoritmo alto/bajo genera identificadores que son &#x00fa;nicos s&#x00f3;lo para una
+                                base de datos particular.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>seqhilo</literal></term>
+                        <listitem>
+                            <para>
+                                usa un algoritmo alto/bajo para generar eficientemente identificadores de tipo
+                                <literal>long</literal>, <literal>short</literal> o <literal>int</literal>,
+                                dada una secuencia de base de datos.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>uuid</literal></term>
+                        <listitem>
+                            <para>
+                                usa un algoritmo UUID de 128 bits para generar identificadore de tipo
+                                cadena, &#x00fa;nicos en una ref (se usa la direcc&#x00f3;n IP). El UUID
+                                se codifica como una cadena hexadecimal de 32 d&#x00ed;gitos de largo.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>guid</literal></term>
+                        <listitem>
+                            <para>
+                                usa una cadena GUID generada por base de datos en MS SQL Server y MySQL.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>native</literal></term>
+                        <listitem>
+                            <para>
+                                selecciona <literal>identity</literal>, <literal>sequence</literal> o
+                                <literal>hilo</literal> dependiendo de las capacidades de la base de datos
+                                subyacente.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>assigned</literal></term>
+                        <listitem>
+                            <para>
+                                deja a la aplicaci&#x00f3;n asignar un identificador al objeto antes
+                                de que se llame a <literal>save()</literal>. Esta es la estrategia
+                                por defecto si no se especifica un elemento <literal>&lt;generator&gt;</literal>.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>select</literal></term>
+                        <listitem>
+                            <para>
+                                recupera una clave primaria asignada por un disparador de base de datos
+                                seleccionando la fila por alguna clave &#x00fa;nica y recuperando el valor de
+                                la clave primaria.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>foreign</literal></term>
+                        <listitem>
+                            <para>
+                                usa el identificador de otro objeto asociado. Generalmente usado en conjunc&#x00f3;n
+                                a una asociac&#x00f3;n de clave primaria <literal>&lt;uno-a-uno&gt;</literal>
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                    </variablelist>
+
+                </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-hilo" revision="1">
+                <title>Algoritmo alto/bajo</title>
+                <para>
+                    Los generadores <literal>hilo</literal> y <literal>seqhilo</literal> proveen dos implementaciones
+                    alternativas del algoritmo alto/bajo, un enfoque favorito en generaci&#x00f3;n de identificadores.
+                    La primera implementaci&#x00f3;n requiere de una tabla "especial" de base de datos para tener el siguiente
+                    valor "alto" disponible.
+                    La segunda usa una secuencia del estilo de Oracle (donde se soporte).
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="hilo">
+                <param name="table">hi_value</param>
+                <param name="column">next_value</param>
+                <param name="max_lo">100</param>
+        </generator>
+</id>]]></programlisting>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="seqhilo">
+                <param name="sequence">hi_value</param>
+                <param name="max_lo">100</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                    Desafortunadamente, no puedes usar <literal>hilo</literal> cuando le proveas tu propia
+                    <literal>Connection</literal> a Hibernate. Cuando Hibernate est&#x00e1; usando un datasource
+                    del servidor de aplicaciones para obtener conexiones alistadas con JTA, debes configurar
+                    correctamente el <literal>hibernate.transaction.manager_lookup_class</literal>.
+                </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-uuid">
+                <title>Algoritmo UUID</title>
+                <para>
+                    El UUID contiene: la direcci&#x00f3;n IP, el instante de arranque de la JVM
+                    (con una precisi&#x00f3;n de un cuarto de segundo), el tiempo de sistema y un valor
+                    de contador (&#x00fa;nico en la JVM). No es posible obtener una direcci&#x00f3;n MAC o
+                    una direcci&#x00f3;n de memoria desde c&#x00f3;digo Java, as&#x00ed; que esto es lo mejor
+                    que podemos hacer sin usar JNI.
+                </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-sequences">
+            <title>Columnas de identidad y secuencias</title>
+                <para>
+                    Para las bases de datos que soportan columnas de identidad (DB2, MySQL, Sybase, MS SQL),
+                    puedes usar generaci&#x00f3;n de claves <literal>identity</literal>. Para las bases de datos
+                    que soportan secuencias (DB2, Oracle, PostgreSQL, Interbase, McKoi, SAP DB) puedes usar la generaci&#x00f3;n
+                    de claves del estilo <literal>sequence</literal>. Ambas estrategias requieren dos consultas SQL
+                    para insertar un nuevo objeto.
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+        <generator class="sequence">
+                <param name="sequence">person_id_sequence</param>
+        </generator>
+</id>]]></programlisting>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id" unsaved-value="0">
+        <generator class="identity"/>
+</id>]]></programlisting>
+            
+                <para>
+                    Para desarrollos multiplataforma, la estrategia <literal>native</literal>
+                    eiligir&#x00e1; de entre las estrategias <literal>identity</literal>,
+                    <literal>sequence</literal> y <literal>hilo</literal>, dependiendo de las capacidades
+                    de la base de datos subyacentes.
+                </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-assigned">
+                <title>Identificadores asignados</title>
+                <para>
+                    Si quieres que la aplicaci&#x00f3;n asigne los identificadores (en contraposici&#x00f3;n
+                    a que los genere Hibernate), puedes usar el generador <literal>assigned</literal>.
+                    Este generador especial usar&#x00e1; el valor identificador ya asignado a la
+                    propiedad identificadora del objeto. Este generador se usa cuandola clave primaria es
+                    una clave natural en vez de una clave sustituta. Este es el comportamiento por defecto si
+                    no especificas un elemento <literal>&lt;generator&gt;</literal>.
+                </para>
+                
+                <para>
+                    Elegir el generador <literal>assigned</literal> hace que Hibernate use
+                    <literal>unsaved-value="undefined"</literal>, forzando a Hibernate a ir 
+                    a la base de datos para determinar si una instancia es transitoria o separada,
+                    a menos que haya una propiedad de versi&#x00f3;n o timestamp, o que tu definas 
+                    <literal>Interceptor.isUnsaved()</literal>.
+                </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-select">
+                <title>Claves primarias asignadas por disparadores</title>
+                <para>
+                    Para esquemas heredados solamente (Hibernate no genera DDL con disparadores).
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+        <generator class="select">
+                <param name="key">socialSecurityNumber</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                    En el ejemplo de arriba, hay una propiedad &#x00e1;nica llamada
+                    <literal>socialSecurityNumber</literal> definida por la clase, como 
+                    una clave natural, y una clave sustituta llamada <literal>person_id</literal>
+                    cuyo valor es generado por un disparador.
+                </para>
+                
+            </sect3>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-compositeid" revision="2">
+            <title>composite-id</title>
+
+            <programlisting><![CDATA[<composite-id
+        name="propertyName"
+        class="ClassName"
+        unsaved-value="undefined|any|none"
+        access="field|property|ClassName"
+        node="element-name|.">
+
+        <key-property name="propertyName" type="typename" column="column_name"/>
+        <key-many-to-one name="propertyName class="ClassName" column="column_name"/>
+        ......
+</composite-id>]]></programlisting>
+
+            <para>
+                Para una tabla con clave compuesta, puedes mapear m&#x00fa;ltiples propiedades
+                de la clase como propiedades identificadoras. El elemento <literal>&lt;composite-id&gt;</literal>
+                acepta los mapeos de propiedad <literal>&lt;key-property&gt;</literal> y
+                los mapeos <literal>&lt;key-many-to-one&gt;</literal> como elementos hijo.
+            </para>
+            
+            <programlisting><![CDATA[<composite-id>
+        <key-property name="medicareNumber"/>
+        <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+            <para>
+                Tu clase persistente <emphasis>debe</emphasis> sobreescribir <literal>equals()</literal>
+                y <literal>hashCode()</literal> para implementar igualdad de identificador compuesto.
+                Debe tambi&#x00e9;n implementar <literal>Serializable</literal>.
+            </para>
+
+            <para>
+                Desafortunadamente, este enfoque de identificadores compuestos significa que un objeto
+                persistente es su propio identificador. No existe otra "asa" conveniente m&#x00e1;s que el
+                objeto mismo. Debes instanciar una instancia de la clase misma y poblar sus propiedades
+                identificadoras antes que puedas <literal>load()</literal> el estado persistente asociado
+                a una clave compuesta. Describiremos un enfoque mucho m&#x00e1;s conveniente donde el identificador
+                compuesto est&#x00e1; implementado como una clase separada en <xref linkend="components-compositeid"/>.
+                Los atributos descriptos debajo solamente se aplican a este enfoque alternativo:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>name</literal> (opcional): Una propiedad de tipo componente que tiene el identificador
+                        compuesto (ver siguiente secci&#x00f3;n).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>class</literal> (opcional - por defecto al tipo de la propiedad determinado
+                        por reflecci&#x00f3;n): La clase del componente usado como identificador compuesto (ver siguiente secci&#x00f3;n).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>unsaved-value</literal> (opcional - por defecto a <literal>undefined</literal>): 
+                        Indica que las instancias transitorias deben ser consideradas como reci&#x00e9;n instanciadas,
+                        si se establece a <literal>any</literal>, o separadas, si se establece a <literal>none</literal>.
+                        Lo mejor
+                        
+                        Indicates that transient instances should be considered newly instantiated, if set 
+                        to <literal>any</literal>, or detached, if set to <literal>none</literal>.
+                        Lo mejor en todos los casos es dejar el valor por defecto.
+                    </para>
+                </listitem>
+            </itemizedlist>
+            
+        </sect2>
+        
+        <sect2 id="mapping-declaration-discriminator" revision="3">
+            <title>discriminator</title>
+
+            <para>
+                El elemento <literal>&lt;discriminator&gt;</literal> es requerido para la persistencia
+                polim&#x00f3;rfica usando la estrategia de mapeo de tabla-por-jerarqu&#x00ed;a-de-clases y
+                declara una columna discriminadora de la tabla. La columna discriminidora contiene valores
+                de marca que le dicen a la capa de persistencia qu&#x00e9; subclase instanciar para una fila
+                en particular. Un conjunto restringido de tipos puede ser usado:
+                <literal>string</literal>, <literal>character</literal>, <literal>integer</literal>, 
+                <literal>byte</literal>, <literal>short</literal>, <literal>boolean</literal>, 
+                <literal>yes_no</literal>, <literal>true_false</literal>.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="discriminator1" coords="2 60"/>
+                    <area id="discriminator2" coords="3 60" />
+                    <area id="discriminator3" coords="4 60" />
+                    <area id="discriminator4" coords="5 60" />
+                    <area id="discriminator5" coords="6 60" />
+                </areaspec>
+                <programlisting><![CDATA[<discriminator
+        column="discriminator_column"
+        type="discriminator_type"
+        force="true|false"
+        insert="true|false"
+        formula="arbitrary sql expression"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="discriminator1">
+                        <para>
+                            <literal>column</literal> (opcional - por defecto a <literal>class</literal>) el
+                            nombre de la columna discriminadora.
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator2">
+                        <para>
+                            <literal>type</literal> (opcional - por defecto a <literal>string</literal>) un
+                            nombre que indique el tipo Hibernate
+                        </para>
+                    </callout>          
+                    <callout arearefs="discriminator3">
+                        <para>
+                            <literal>force</literal> (optconal - por defecto a <literal>false</literal>) 
+                            "fuerza" a Hibernate a especificar valores discriminadores permitidos incluso
+                            cuando se recuperan todas las instancias de la clase ra&#x00ed;z.
+                        </para>
+                    </callout>          
+                    <callout arearefs="discriminator4">
+                        <para>
+                            <literal>insert</literal> (opcional - por defecto a <literal>true</literal>)
+                            establezca este a <literal>false</literal> si tu columna discriminadora es
+                            tambi&#x00e9;n parte de un identificador mapeado compuesto. (Le dice a Hibernate
+                            que no incluya la columna en los SQL <literal>INSERT</literal>s.)
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator5">
+                        <para>
+                            <literal>formula</literal> (opcional) una expresi&#x00f3;n SQL arbitraria que
+                            es ejecutada cuando un tipo tenga que ser evaluado. Permite dicriminaci&#x00f3;n
+                            basada en el contenido.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Los valores reales de la columna discriminadora est&#x00e1;n especificados por
+                el atributo <literal>discriminator-value</literal> de los elementos
+                <literal>&lt;class&gt;</literal> y <literal>&lt;subclass&gt;</literal>.
+            </para>
+            
+            <para>
+                El atributo <literal>force</literal> es (s&#x00f3;lo) &#x00fa;til si la tabla contiene
+                filas con valores discriminadores "extra" que no est&#x00e1;n mapeados a la clase
+                persistente. Generalmente este no es el caso.
+            </para>
+
+            <para>
+                Usando el atributo <literal>formula</literal> puedes declarar una expresi&#x00f3;n SQL
+                arbitraria que ser&#x00e1; usada para evaluar el tipo de una fila:
+            </para>
+
+            <programlisting><![CDATA[<discriminator
+    formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
+    type="integer"/>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-version" revision="1">
+            <title>version (opcional)</title>
+            
+            <para>
+                El elemento <literal>&lt;version&gt;</literal> es opcional e indica que la
+                tabla contiene datos versionados. Esto es particularmente &#x00fa;til si planeas
+                usar <emphasis>transacciones largas</emphasis> (ver debajo).
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="version1" coords="2 70"/>
+                    <area id="version2" coords="3 70"/>
+                    <area id="version3" coords="4 70"/>
+                    <area id="version4" coords="5 70"/>
+                    <area id="version5" coords="6 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<version
+        column="version_column"
+        name="propertyName"
+        type="typename"
+        access="field|property|ClassName"
+        unsaved-value="null|negative|undefined"
+        node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="version1">
+                        <para>
+                            <literal>column</literal> (opcional - por defecto al nombre de la propiedad): El nombre
+                            de la columna que tiene el n&#x00fa;mero de versi&#x00f3;n.
+                        </para>
+                    </callout>          
+                    <callout arearefs="version2">
+                        <para>
+                            <literal>name</literal>: El nombre de una propiedad de la clase persistente.
+                        </para>
+                    </callout>
+                    <callout arearefs="version3">
+                        <para>
+                            <literal>type</literal> (opcional - por defecto a <literal>integer</literal>): 
+                            El tipo del n&#x00fa;.mero de vesi&#x00f3;n.
+                        </para>
+                    </callout>          
+                   <callout arearefs="version4">
+                        <para>
+                            <literal>access</literal> (opcional - por defecto a <literal>property</literal>): La
+                            estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+                        </para>
+                    </callout>
+                   <callout arearefs="version5">
+                        <para>
+                            <literal>unsaved-value</literal> (opcional - por defecto a <literal>undefined</literal>):
+                            Un valor de la propiedad de versi&#x00f3;n que indica que una instancia est&#x00e1;
+                            reci&#x00e9;n instanciada (sin guardar), distingui&#x00e9;ndola de instancias
+                            separadas que fueran guardadas o cargadas en una sesi&#x00f3;n previa.
+                            (<literal>undefined</literal> especifica que debe usarse el valor de la
+                            propiedad identificadora.)
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                Los n&#x00fa;meros de versi&#x00f3;n deben ser de tipo <literal>long</literal>,
+                <literal>integer</literal>, <literal>short</literal>, <literal>timestamp</literal> o
+                <literal>calendar</literal> de Hibernate.
+            </para>
+            
+            <para>
+                Una propiedad de versi&#x00f3;n o timestamp nunca debe ser nula para una instancia
+                separada, de modo que Hibernate detectar&#x00e1; cualquier instancia con una versi&#x00f3;n
+                o timestamp nulo como transitoria, sin importar qu&#x00e9; otras estrategias
+                <literal>unsaved-value</literal> se hayan especificado.
+                <emphasis>Declarar una propiedad de vers&#x00f3;n o timestamp nulable es una forma
+                f&#x00e1;cil de evitar cualquier problema con la re-uni&#x00f3;n transitiva en Hibernate,
+                especialmente &#x00fa;til para que usa identificadores asignados o claves compuestas!</emphasis>
+            </para>
+        </sect2>
+        
+        <sect2 id="mapping-declaration-timestamp">
+            <title>timestamp (opcional)</title>
+
+            <para>
+                El elemento opcional <literal>&lt;timestamp&gt;</literal> indica que la tabla contiene
+                datos con sellos de tiempo. Esto esta concebido como una alternativa al versionado.
+                Los timestamps (sellos de tiempo) son por su naturaleza una implementaci&#x00f3;n menos
+                segura de bloqueo optimista. Sin embrago, a veces la aplicaci&#x00f3;n puede usar los
+                timestamps en otras formas.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="timestamp1" coords="2 70"/>
+                    <area id="timestamp2" coords="3 70" />
+                    <area id="timestamp3" coords="4 70" />
+                    <area id="timestamp4" coords="5 70" />
+                </areaspec>            
+                <programlisting><![CDATA[<timestamp
+        column="timestamp_column"
+        name="propertyName"
+        access="field|property|ClassName"
+        unsaved-value="null|undefined"
+        node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="timestamp1">
+                        <para>
+                            <literal>column</literal> (opcional - por defecto al nombre de la propiedad): El nombre
+                            de una columna que tiene el timestamp.
+                        </para>
+                    </callout>                   
+                    <callout arearefs="timestamp2">
+                        <para>
+                            <literal>name</literal>: El nombre de una propiedad del estilo JavaBeans de tipo
+                            Java <literal>Date</literal> o <literal>Timestamp</literal> de la clase persistente.
+                        </para>
+                    </callout>
+                   <callout arearefs="timestamp3">
+                        <para>
+                            <literal>access</literal> (opcional - por defecto a <literal>property</literal>): La
+                            estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+                        </para>
+                    </callout>
+                   <callout arearefs="timestamp4">
+                        <para>
+                            <literal>unsaved-value</literal> (opcional - por defecto a <literal>null</literal>): 
+                            Un valor de propiedad de versi&#x00f3;n que indica que una instancia est&#x00e1;
+                            reci&#x00e9;n instanciada (sin guardar), distingui&#x00e9;ndola de instancias separadas
+                            que hayan sido guardadas o cargadas en una sesi&#x00f3;n previa.
+                            (<literal>undefined</literal> especifica que debe usarse el valor de la propiedad
+                            identificadora.)
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                Note that <literal>&lt;timestamp&gt;</literal> is equivalent to 
+                <literal>&lt;version type="timestamp"&gt;</literal>.
+            </para>
+        </sect2>
+
+
+        <sect2 id="mapping-declaration-property" revision="2">
+            <title>property</title>
+
+            <para>
+                El elemento <literal>&lt;property&gt;</literal> declara una propiedad persistente estilo
+                JavaBean de la clase.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="property1" coords="2 70"/>
+                    <area id="property2" coords="3 70"/>
+                    <area id="property3" coords="4 70"/>
+                    <areaset id="property4-5" coords="">
+                        <area id="property4" coords='5 70'/>
+                        <area id="property5" coords='6 70'/>
+                    </areaset>
+                    <area id="property6" coords="7 70"/>
+                    <area id="property7" coords="8 70"/>
+                    <area id="property8" coords="9 70"/>
+                    <area id="property9" coords="10 70"/>
+                    <area id="property10" coords="11 70"/>
+                    <area id="property11" coords="12 70"/>
+                </areaspec>            
+                <programlisting><![CDATA[<property
+        name="propertyName"
+        column="column_name"
+        type="typename"
+        update="true|false"
+        insert="true|false"
+        formula="arbitrary SQL expression"
+        access="field|property|ClassName"
+        lazy="true|false"
+        unique="true|false"
+        not-null="true|false"
+        optimistic-lock="true|false"
+        node="element-name|@attribute-name|element/@attribute|."
+        index="index_name"
+        unique_key="unique_key_id"
+        length="L"
+        precision="P"
+        scale="S"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="property1">
+                        <para>
+                            <literal>name</literal>: el nombre de la propiedad, con la letra inicial
+                            en min&#x00fa;sculas.
+                        </para>
+                    </callout>                   
+                    <callout arearefs="property2">
+                        <para>
+                            <literal>column</literal> (opcional - por defecto al nombre de la propiedad): el nombre
+                            de la columna de tabla de base de datos mapeada. Esto puede tambi&#x00e9;n ser especificado
+                            con elemento(s) <literal>&lt;column&gt;</literal> anidado(s).
+                        </para>
+                    </callout>
+                    <callout arearefs="property3">
+                        <para>
+                            <literal>type</literal> (opcional): un nombre que indica el nobre Hibernate.
+                        </para>
+                    </callout>
+                    <callout arearefs="property4-5">
+                        <para>
+                            <literal>update, insert</literal> (opcional - por defecto a <literal>true</literal>) :
+                            especifica que las columnas mapeadas deben ser inclu&#x00ed;das en las sentencias SQL
+                            <literal>UPDATE</literal> y/o <literal>INSERT</literal> . Especificando ambas a 
+                            <literal>false</literal> permite una propiedad "derivada" cuyo valor es inicializado desde
+                            alguna otra propiedad que mapee a la misma columna (o columnas) o por un disparador u otra
+                            aplicaci&#x00f3;n.
+                        </para>
+                    </callout>
+                    <callout arearefs="property6">
+                        <para>
+                            <literal>formula</literal> (opcional): una expresi&#x00f3;n SQL que define el valor
+                            para una propiedad <emphasis>computada</emphasis>. Las propiedades computadas no tienen
+                            una columna mapeada propia.
+                        </para>
+                    </callout>
+                   <callout arearefs="property7">
+                        <para>
+                            <literal>access</literal> (opcional - por defecto a <literal>property</literal>): La
+                            estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+                        </para>
+                    </callout>
+                   <callout arearefs="property8">
+                        <para>
+                            <literal>lazy</literal> (opcional - por defecto a <literal>false</literal>): Especifica
+                            que esta propiedad debe ser tra&#x00ed;da perezosamente cuando la variable de instancia
+                            sea accedida por primera vez (requiere instrumentaci&#x00f3;n en tiempo de compilaci&#x00f3;n).
+                        </para>
+                    </callout>
+                    <callout arearefs="property9">
+                        <para>
+                            <literal>unique</literal> (opcional): Habilita la generaci&#x00f3; DDL de una restricci&#x00f3;n
+                            de unicidad para las columnas. Adem&#x00e1;s, permite que &#x00e9;sta sea un blanco objetivo de
+                            una <literal>property-ref</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="property10">
+                        <para>
+                            <literal>not-null</literal> (opcional): Habilita la generaci&#x00f3; DDL de una restricci&#x00f3;n
+                            de nulabilidad para las columnas.
+                        </para>
+                    </callout>
+                    <callout arearefs="property11">
+                        <para>
+                            <literal>optimistic-lock</literal> (opcional - por defecto a <literal>true</literal>): 
+                            Especifica que las actualizaciones a esta propiedad requieran o no de la obtenci&#x000f3;n
+                            de un bloqueo optimista. En otras palabras, determina si debe ocurrir un incremento de versi&#x00f3;n
+                            cuando la propiedad este sucia (desactualizada).
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                <emphasis>typename</emphasis> puede ser:
+            </para>
+
+            <orderedlist spacing="compact">
+                <listitem>
+                    <para>
+                        El nombre de un tipo b&#x00e1;sico Hibernate (por ejemplo, <literal>integer, string, character,
+                        date, timestamp, float, binary, serializable, object, blob</literal>).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        El nombre de una clase Java de tipo b&#x00e1;sico (por ejemplo, <literal>int, float,
+                        char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob</literal>).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        El nombre de una clase Java serializable.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        El nombre de un tipo personalizado (por ejemplo, <literal>com.illflow.type.MyCustomType</literal>).
+                    </para>
+                </listitem>
+            </orderedlist>
+
+            <para>
+                Si no especificas un tipo, Hibernate usar&#x00e1; reflecci&#x00f3;n sobre la 
+                propiedad mencionada para deducir el tipo Hibernate correcto. Hibernate intentar&#x00e1;
+                interpretar el nombre de la clase de retorno del getter de la propiedad usando las reglas
+                2, 3 y 4 en ese orden. Sin embargo, esto no siempre suficiente. En ciertos casos, necesitar&#x00e1;s
+                a&#x00fa;n el atributo <literal>type</literal>. (Por ejemplo, para distinguir entre
+                <literal>Hibernate.DATE</literal> y <literal>Hibernate.TIMESTAMP</literal>,
+                o especificar un tipo personalizado.)
+            </para>
+            
+            <para>
+                El atributo <literal>access</literal> te deja controlar c&#x00f3;mo Hibernate
+                acceder&#x00e1; a la propiedad en tiempo de ejecuci&#x00f3;n. Por defecto, Hibernate
+                llamar&#x00e1; al par de getter/setter de la propiedad. Si especificas
+                <literal>access="field"</literal>, Hibernate se saltar&#x00e1; el par get/set y 
+                acceder&#x00e1; al campo directamente usando reflecci&#x00f3;n. Puedes especificar tu
+                propia estrategia de acceso a la propiedad mencionando una clase que implemente
+                la interface <literal>org.hibernate.property.PropertyAccessor</literal>.
+            </para>
+
+            <para>
+                Una aspecto especialmente poderoso son las propiedades derivadas. Estas propiedades
+                son por definici&#x00f3;n de s&#x00f3;lo lectura, el valor de la propiedad es computado
+                en tiempo de carga. Tu declaras la computaci&#x00f3;n como una expresi&#x00f3;n SQL,
+                y &#x00e9;sta se traduce a cl&#x00e1;usula de subconsulta <literal>SELECT</literal>
+                en la consulta SQL que cargue una instancia:
+            </para>
+
+        <programlisting><![CDATA[
+<property name="totalPrice"
+    formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p
+                WHERE li.productId = p.productId
+                AND li.customerId = customerId
+                AND li.orderNumber = orderNumber )"/>]]></programlisting>
+
+            <para>
+                Observa que puedes referenciar la propia tabla de las entidades sin declarar un alias
+                o una columna particular (<literal>customerId</literal> en el ejemplo dado). Observa
+                adem&#x00e1;s que puedes usar el elemento anidado de mapeo <literal>&lt;formula&gt;</literal>
+                si no te gusta usar el atributo.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-manytoone" revision="3">
+            <title>many-to-one</title>
+
+            <para>
+                Una asociaci&#x00f3;n ordinaria a otra clase persistente se declara usando
+                el elemento <literal>many-to-one</literal>. El modelo relacional es una
+                asociaci&#x00f3;n muchos-a-uno: una clave for&#x00e1;nea en una tabla est&#x00e1;
+                referenciando la columna (o columnas) de la clave primaria de la tabla objetivo.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="manytoone1" coords="2 70"/>
+                    <area id="manytoone2" coords="3 70"/>
+                    <area id="manytoone3" coords="4 70"/>
+                    <area id="manytoone4" coords="5 70"/>
+                    <area id="manytoone5" coords="6 70"/>
+                    <areaset id="manytoone6-7" coords="">
+                        <area id="manytoone6" coords='7 70'/>
+                        <area id="manytoone7" coords='8 70'/>
+                    </areaset>
+                    <area id="manytoone8" coords="9 70"/>
+                    <area id="manytoone9" coords="10 70"/>
+                    <area id="manytoone10" coords="11 70"/>
+                    <area id="manytoone11" coords="12 70"/>
+                    <area id="manytoone12" coords="13 70"/>
+                    <area id="manytoone13" coords="14 70"/>
+                    <area id="manytoone14" coords="15 70"/>
+                    <area id="manytoone15" coords="16 70"/>
+                    <area id="manytoone16" coords="17 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<many-to-one
+        name="propertyName"
+        column="column_name"
+        class="ClassName"
+        cascade="cascade_style"
+        fetch="join|select"
+        update="true|false"
+        insert="true|false"
+        property-ref="propertyNameFromAssociatedClass"
+        access="field|property|ClassName"
+        unique="true|false"
+        not-null="true|false"
+        optimistic-lock="true|false"
+        lazy="true|proxy|false"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        formula="cualquier expresi&#x00f3;n SQL"
+        node="element-name|@attribute-name|element/@attribute|."
+        embed-xml="true|false"
+        index="index_name"
+        unique_key="unique_key_id"
+        foreign-key="foreign_key_name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="manytoone1">
+                        <para>
+                            <literal>name</literal>: El nombre de la propiedad.
+                        </para>                    
+                    </callout>                   
+                    <callout arearefs="manytoone2">
+                        <para>
+                            <literal>column</literal> (opcional): El nombre de la columna clave for&#x00e1;nea.
+                            Tambi&#x00e9;n puede ser especificado por uno o varios elementos anidados
+                            <literal>&lt;column&gt;</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone3">
+                        <para>
+                            <literal>class</literal> (opcional - por defecto al tipo de la propiedad
+                            determinado por reflecci&#x00f3;n): El nombre de la clase asociada.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone4">
+                        <para>
+                            <literal>cascade</literal> (opcional): Especifica qu&#x00e9; operaciones deben
+                            ir en cascada desde el objeto padre al objeto asociado
+                        </para>                    
+                    </callout>
+                    <callout arearefs="manytoone5">
+                        <para>
+                            <literal>fetch</literal> (opcional - por defecto a 1<literal>select</literal>): 
+                            Escoge entre recuperaci&#x00f3;n outer-join o por selecci&#x00f3;n secuencial.
+                        </para>                    
+                    </callout>
+                    <callout arearefs="manytoone6-7">
+                        <para>
+                            <literal>update, insert</literal> (opcional - por defecto a <literal>true</literal>)
+                            especifica que las columnas mapeadas deben ser inclu&#x00ed;das en las sentencias SQL
+                            <literal>UPDATE</literal> y/o <literal>INSERT</literal>. Establecer ambas a
+                            <literal>false</literal> permite una asociaci&#x00f3;n puramente "derivada" cuyo
+                            valor es inicializado desde alguna otra propiedad que mapea a las misma columna (o columnas),
+                            o por un disparador, o por otra aplicaci&#x00f3;n.
+                        </para>                    
+                    </callout>
+                    <callout arearefs="manytoone8">
+                        <para>
+                            <literal>property-ref</literal>: (opcional) El nombre de la propiedad de la clase
+                            asociada que est&#x00e1; unida a la clave for&#x00e1;nea. Si no se especifica, se usa
+                            la clave primaria de la clase asociada.
+                        </para>                
+                    </callout>                   
+                   <callout arearefs="manytoone9">
+                        <para>
+                            <literal>access</literal> (opcional - por defecto a <literal>property</literal>): La
+                            estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone10">
+                        <para>
+                            <literal>unique</literal> (opcional): Habilita la generaci&#x00f3;n DDL de una
+                            restricci&#x00f3;n de unicidad para la columna de clave for&#x00e1;nea. Adem&#x00e1;s,
+                            permite que &#x00e9;sta sea el objetivo de una <literal>property-ref</literal>.
+                            Esto hace efectivamente la multiplicidad de la asociaci&#x00f3;n uno a uno.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone11">
+                        <para>
+                            <literal>not-null</literal> (opcional): Habilita la generaci&#x00f3;n DDL de una
+                            restricci&#x00f3;n de nulabilidad para las columnas de clave for&#x00e1;nea. 
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone12">
+                        <para>
+                            <literal>optimistic-lock</literal> (opcional - por defecto a <literal>true</literal>): 
+                            Especifica que las actualizaciones a esta propiedad requieran o no la obtenci&#x00f3;n
+                            del bloqueo optimista. En otras palabras, determina si debe darse un incremento de versi&#x00f3;n
+                            cuando esta propiedad est&#x00e9; desactualizada.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone13">
+                        <para>
+                            <literal>lazy</literal> (opcional - por defecto a <literal>proxy</literal>):
+                            Por defecto, las asociaciones de punto &#x00fa;nico van con proxies.
+                            <literal>lazy="true"</literal> especifica que esta propiedad debe ser
+                            tra&#x00ed;da perezosamente cuando la variable de instancia sea accedida por primera
+                            vez (requiere instrumentaci&#x00f3;n del bytecode en tiempo de compilaci&#x00f3;n).
+                            <literal>lazy="false"</literal> especifica que la asociaci&#x00f3;n siempre ser&#x00e1;
+                            recuperada tempranamente.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone14">
+                        <para>
+                            <literal>not-found</literal> (opcional - por defecto a <literal>exception</literal>): 
+                            Especifica c&#x00f3;mo deben manejarse las claves for&#x00e1;neas que referencien
+                            filas inexistentes: <literal>ignore</literal> tratar&#x00e1; una fila perdida como
+                            una asociaci&#x00f3;n nula.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone15">
+                        <para>
+                            <literal>entity-name</literal> (opcional): El nombre de entidad de la clase
+                            asociada.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone16">
+                        <para>
+                            <literal>formula</literal> (opcional): una expresi&#x00f3;n SQL que define el valor
+                            para una clave for&#x00e1;nea <emphasis>computada</emphasis>.
+                        </para>
+                    </callout>
+
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Establecer el valor del atributo <literal>cascade</literal> a cualquier valor
+                significativo distinto de <literal>none</literal> propagar&#x00e1; ciertas
+                operaciones al objeto asociado. Los valores significativos son los nombres de las
+                operaciones b&#x00e1;sicas de Hibernate, <literal>persist, merge, delete, save-update,
+                evict, replicate, lock, refresh</literal>, as&#x00ed; como los valores especiales
+                <literal>delete-orphan</literal> y <literal>all</literal> y combinaciones de operaciones
+                separadas por coma, por ejemplo, <literal>cascade="persist,merge,evict"</literal> o
+                <literal>cascade="all,delete-orphan"</literal>. Para una explicaci&#x00f3;n completa,
+                ver <xref linkend="objectstate-transitive"/>.
+            </para>
+            
+            <para>
+                Una declaraci&#x00f3;n t&#x00ed;pica <literal>muchos-a-uno</literal> se parece a esto:
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="product" class="Product" column="PRODUCT_ID"/>]]></programlisting>
+            
+            <para>
+                El atributo <literal>property-ref</literal> debe ser usado solamente para el mapeo
+                de datos heredados donde una clave for&#x00e1;nea referencia una clave &#x00fa;nica de
+                la tabla asociada, distinta de la clave primaria. Este es un modelo relacional feo.
+                Por ejemplo, sup&#x00f3;n que la clase <literal>Product</literal> tuviera un n&#x00fa;mero
+                &#x00fa;nico serial que no es la clave primaria. (El atributo <literal>unique</literal>
+                controla la generaci&#x00f3;n de DDL con la herramienta SchemaExport.)
+            </para>
+            
+            <programlisting><![CDATA[<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>]]></programlisting>
+            
+            <para>
+                Entonces el mapeo para <literal>OrderItem</literal> deber&#x00ed;a usar:
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>]]></programlisting>
+            
+            <para>
+                Sin embargo, esto no esta ciertamente alentado.
+            </para>
+            
+            <para>
+                Si la clave &#x00fa;nica referenciada abarca m&#x00fa;ltiples propiedades de la entidad asociada,
+                debes mapear las propiedades dentro de un elemento <literal>&lt;properties&gt;</literal>.
+            </para>
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-onetoone" revision="2">
+            <title>one-to-one</title>
+
+            <para>
+                Una asociaci&#x00f3;n uno-a-uno a otra clase persistente se declara usando
+                un elemento <literal>one-to-one</literal>.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="onetoone1" coords="2 70"/>
+                    <area id="onetoone2" coords="3 70"/>
+                    <area id="onetoone3" coords="4 70"/>
+                    <area id="onetoone4" coords="5 70"/>
+                    <area id="onetoone5" coords="6 70"/>
+                    <area id="onetoone6" coords="7 70"/>
+                    <area id="onetoone7" coords="8 70"/>
+                    <area id="onetoone8" coords="9 70"/>
+                    <area id="onetoone9" coords="10 70"/>
+                    <area id="onetoone10" coords="11 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<one-to-one
+        name="propertyName"
+        class="ClassName"
+        cascade="cascade_style"
+        constrained="true|false"
+        fetch="join|select"
+        property-ref="propertyNameFromAssociatedClass"
+        access="field|property|ClassName"
+        formula="cualquier expresi&#x00f3;n SQL"
+        lazy="true|proxy|false"
+        entity-name="EntityName"
+        node="element-name|@attribute-name|element/@attribute|."
+        embed-xml="true|false"
+        foreign-key="foreign_key_name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="onetoone1">
+                        <para>
+                            <literal>name</literal>: El nombre de la propiedad.
+                        </para>                
+                    </callout>                   
+                    <callout arearefs="onetoone2">
+                        <para>
+                            <literal>class</literal> (opcional - por defecto al tipo de la propiedad
+                            determinado por reflecci&#x00f3;n): El nombre de la clase asociada.
+                        </para>                   
+                    </callout>
+                    <callout arearefs="onetoone3">
+                        <para>
+                            <literal>cascade</literal> (opcional) especifica qu&#x00e9; operaciones deben
+                            ir en cascada desde el objeto padre al objeto asociado.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone4">
+                        <para>
+                            <literal>constrained</literal> (opcional) especifica que una restricci&#x00f3;n
+                            de clave for&#x00e1;nea de la tabla mapeada referencia a la tabla de la clase
+                            asociada. Esta opci&#x00f3;n afecta el orden en que van en cascada
+                            <literal>save()</literal> y <literal>delete()</literal>, y determina cu&#x00e1;ndo
+                            la asociaci&#x00f3;n pueden ser virtualizados por proxies (es tambi&#x00e9;n usado por
+                            la herramienta de exportaci&#x00f3;n de esquemas).
+                        </para>                  
+                    </callout>
+                    <callout arearefs="onetoone5">
+                        <para>
+                            <literal>fetch</literal> (opcional - por defecto <literal>select</literal>): 
+                            Elige entre recuperaci&#x00f3;n outer-join o recuperaci&#x00f3;n por consulta secuencial.
+                        </para>              
+                    </callout>
+                    <callout arearefs="onetoone6">
+                        <para>
+                            <literal>property-ref</literal>: (opcional) El nombre de una propiedad de la clase
+                            asociada que est&#x00e9; unida a la clave primaria de esta clase. Si no se especifica,
+                            se usa la clave primaria de la clase asociada.
+                        </para>                
+                    </callout>                   
+                    <callout arearefs="onetoone7">
+                        <para>
+                            <literal>access</literal> (opcional - por defecto a <literal>property</literal>): La
+                            estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone8">
+                        <para>
+                            <literal>formula</literal> (opcional): Casi todas las asociaciones uno-a-uno mapean
+                            a la clave primaria de la entidad propietaria. En el raro caso en que este no sea el caso,
+                            puedes especificar alguna otra columna, o columnas, o expresi&#x00f3;n para unir usando una
+                            f&#x00f3;rmula SQL. (Para un ejemplo ver <literal>org.hibernate.test.onetooneformula</literal>).
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone9">
+                        <para>
+                            <literal>lazy</literal> (opcional - por defecto a <literal>proxy</literal>):
+                            Por defecto, las asociaciones de punto &#x00fa;nico van con proxies.
+                            <literal>lazy="true"</literal> especifica que esta propiedad debe ser
+                            tra&#x00ed;da perezosamente cuando la variable de instancia sea accedida por primera
+                            vez (requiere instrumentaci&#x00f3;n del bytecode en tiempo de compilaci&#x00f3;n).
+                            <literal>lazy="false"</literal> especifica que la asociaci&#x00f3;n siempre ser&#x00e1;
+                            recuperada tempranamente. <emphasis>Observa que si <literal>constrained="false"</literal>,
+                            la aplicaci&#x00f3;n de proxies es imposible e Hibernate traer&#x00e1; temprano la
+                            asociaci&#x00f3;n!</emphasis>
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+        
+            <para>
+                Hay dos variedades de asociaciones uno-a-uno:
+            </para>
+            <itemizedlist>
+            <listitem><para>
+                asociaciones de clave primaria
+            </para></listitem>
+            <listitem><para>
+                asociaciones de clave for&#x00e1;neas &#x00fa;nica
+            </para></listitem>
+            </itemizedlist>
+            
+            <para>
+                Las asociaciones de clave primaria no necesitan una columna de tabla extra; si dos filas
+                est&#x00e1;n relacionadas por la asociaci&#x00f3;n entonces las dos filas de tablas comparten
+                el mismo valor de clave primaria. Por lo tanto, si quieres que dos objetos est&#x00e9;n relacionados
+                por una asociaci&#x00f3;n de clave primaria, debes asegurarte que se les asigne el mismo valor de
+                identificador!
+            </para>
+            
+            <para>
+                Para una asociaci&#x00f3;n de clave primaria, a&#x00f1;ade los siguientes mapeos a
+                <literal>Employee</literal> y <literal>Person</literal>, respectivamente.
+            </para>
+
+            <programlisting><![CDATA[<one-to-one name="person" class="Person"/>]]></programlisting>
+            <programlisting><![CDATA[<one-to-one name="employee" class="Employee" constrained="true"/>]]></programlisting>
+
+            <para>
+                Ahora debemos asegurarnos que las claves primarias de las filas relacionadas en las tablas
+                PERSON y EMPLOYEE sean iguales. Usamos una estrategia especial de generaci&#x00f3;n de identificador
+                de Hibernate llamada <literal>foreign</literal>:
+            </para>
+
+            <programlisting><![CDATA[<class name="person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="foreign">
+            <param name="property">employee</param>
+        </generator>
+    </id>
+    ...
+    <one-to-one name="employee"
+        class="Employee"
+        constrained="true"/>
+</class>]]></programlisting>
+
+            <para>
+                A una instancia reci&#x00e9;n salvada de <literal>Person</literal> se le asigna entonces
+                el mismo valor de clave primaria con que la instancia  <literal>Employee</literal>
+                referida por la propiedad <literal>employee</literal> de esta <literal>Person</literal>.
+            </para>
+
+            <para>
+                Alternativamente, una clave for&#x00e1;nea con una restricci&#x00f3;n de unicidad, desde
+                <literal>Employee</literal> a <literal>Person</literal>, puede ser expresada como:
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/>]]></programlisting>
+            
+            <para>
+                Y esta asociaci&#x00f3;n puede hacerse bidireccional agregando lo siguiente al mapeo de
+                <literal>Person</literal> :
+            </para>
+            
+           <programlisting><![CDATA[<one-to-one name"employee" class="Employee" property-ref="person"/>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-naturalid">
+            <title>natural-id</title>
+
+            <programlisting><![CDATA[<natural-id mutable="true|false"/>
+        <property ... />
+        <many-to-one ... />
+        ......
+</natural-id>]]></programlisting>
+
+            <para>
+                Aunque recomendamos el uso de claves delegadas como claves primarias, todav&#x00ed;a debes
+                intentar identificar claves naturales para todas las entidades. Una clave natural es una
+                propiedad o combinaci&#x00f3;n de propiedades que es &#x00fa;nica y no nula. Si adem&#x00e1;s
+                es inmutable, mejor a&#x00fa;n. Mapea las propiedades de la clave natural dentro del elemento
+                <literal>&lt;natural-id&gt;</literal>. Hibernate generar&#x00e1; las restricciones de clave
+                &#x00fa;nica y nulabilidad necesarias, y tu mapeo ser&#x00e1; m&#x00e1;s auto-documentado.
+            </para>
+            
+            <para>
+                Recomendamos fuertemente que implementes <literal>equals()</literal> y
+                <literal>hashCode()</literal> para comparar las propiedades de clave natural
+                de la entidad.
+            </para>
+
+            <para>
+                Este mapeo no est&#x00e1; concebido para usar con entidades con claves
+                primarias naturales.
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>mutable</literal> (opcional, por defecto a <literal>false</literal>): 
+                        Por defecto, se asume que las propiedades de identificadores naturales son
+                        inmutables (constantes). 
+                    </para>
+                </listitem>
+            </itemizedlist>
+        </sect2>
+
+
+
+        <sect2 id="mapping-declaration-component" revision="2">
+            <title>component, dynamic-component</title>
+
+            <para>
+                El elemento <literal>&lt;component&gt;</literal> mapea propiedades de un objeto
+                hijo a columnas de la tabla de la clase padre. Los componentes pueden a su vez
+                declarar sus propias propiedades, componentes o colecciones. Ver debajo "Componentes".
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="component1" coords="2 45"/>
+                    <area id="component2" coords="3 45"/>
+                    <area id="component3" coords="4 45"/>
+                    <area id="component4" coords="5 45"/>
+                    <area id="component5" coords="6 45"/>
+                    <area id="component6" coords="7 45"/>
+                    <area id="component7" coords="8 45"/>
+                    <area id="component8" coords="9 45"/>
+                </areaspec>            
+                <programlisting><![CDATA[<component 
+        name="propertyName" 
+        class="className"
+        insert="true|false"
+        update="true|false"
+        access="field|property|ClassName"
+        lazy="true|false"
+        optimistic-lock="true|false"
+        unique="true|false"
+        node="element-name|."
+>
+        
+        <property ...../>
+        <many-to-one .... />
+        ........
+</component>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="component1">
+                        <para>
+                            <literal>name</literal>: El nombre de la propiedad.
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="component2">
+                        <para>
+                            <literal>class</literal> (opcional - por defecto al tipo de la propiedad
+                            determinado por reflecci&#x00f3;n): El nombre de la clase del componente (hijo).
+                        </para>                 
+                    </callout>
+                    <callout arearefs="component3">
+                        <para>
+                            <literal>insert</literal>: Aparecen las columnas mapeadas en
+                            <literal>INSERT</literal>s SQL?
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="component4">
+                        <para>
+                            <literal>update</literal>: Aparecen las columnas mapeadas en
+                            <literal>UPDATE</literal>s SQL?
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="component5">
+                        <para>
+                            <literal>access</literal> (opcional - por defecto a <literal>property</literal>): La
+                            estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+                        </para>
+                    </callout>
+                   <callout arearefs="component6">
+                        <para>
+                            <literal>lazy</literal> (opcional - por defecto a <literal>false</literal>): Especifica
+                            que este componente debe ser recuperado perezosamente cuando la variable de instancia
+                            sea accedida por primera vez (requiere instrumentaci&#x00f3;n de bytecode en tiempo de
+                            compilaci&#x00f3;n).
+                        </para>
+                    </callout>
+                    <callout arearefs="component7">
+                            <para>
+                                <literal>optimistic-lock</literal> (opcional - por defecto a <literal>true</literal>):
+                                Especifica si las actualizaciones de este componente requieren o no la
+                                adquisici&#x00f3;n de un bloqueo optimista. En otras palabras, determina si
+                                debe ocurrir un incremento de versi&#x00f3;n cuando esta propiedad est&#x00e1;
+                                desactualizada.
+                            </para>
+                    </callout>
+                    <callout arearefs="component8">
+                            <para>
+                                <literal>unique</literal> (opcional - por defecto a <literal>false</literal>):
+                                Especifica que existe una restricci&#x00f3;n de unicidad sobre todas las
+                                columnas mapeadas del componente.
+                            </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Las etiquetas hijas <literal>&lt;property&gt;</literal> mapean propiedades de la
+                clase hija columnas de la tabla.
+            </para>
+
+            <para>
+                El elemento <literal>&lt;component&gt;</literal> permite un subelemento
+                <literal>&lt;parent&gt;</literal> que mapea una propiedad de la clase del componente
+                como una referencia de regreso a la entidad contenedora.
+            </para>
+
+            <para>
+                El elemento <literal>&lt;dynamic-component&gt;</literal> permite que un 
+                <literal>Map</literal> sea mapeado como un componente, donde los nombres de
+                las propiedades se corresponden a las claves del mapa, ver <xref linkend="components-dynamic"/>.
+            </para>
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-properties" revision="2">
+            <title>properties</title>
+
+            <para>
+                El elemento <literal>&lt;properties&gt;</literal> permite la definici&#x00f3;n de
+                un grupo de propiedades l&#x00f3;gico con nombre de una clase. El uso m&#x00e1;s
+                importante de la contrucci&#x00f3;n es que permite que una combinaci&#x00f3;n
+                de propiedades sea objetivo de una <literal>property-ref</literal>. Es tambi&#x00e9;n
+                una forma conveniente de definir una restricci&#x00f3;n de unicidad multicolumna.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="properties1" coords="2 45"/>
+                    <area id="properties2" coords="3 45"/>
+                    <area id="properties3" coords="4 45"/>
+                    <area id="properties4" coords="5 45"/>
+                    <area id="properties5" coords="6 45"/>
+                </areaspec>            
+                <programlisting><![CDATA[<properties 
+        name="logicalName" 
+        insert="true|false"
+        update="true|false"
+        optimistic-lock="true|false"
+        unique="true|false"
+>
+        
+        <property ...../>
+        <many-to-one .... />
+        ........
+</properties>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="properties1">
+                        <para>
+                            <literal>name</literal>: El nombre l&#x00f3;gico del agrupamiento -
+                            <emphasis>no</emphasis> un nombre de propiedad real.
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="properties2">
+                        <para>
+                            <literal>insert</literal>: Aparecen las columnas mapeadas en 
+                            <literal>INSERT</literal>s SQL?
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="properties3">
+                        <para>
+                            <literal>update</literal>: Aparecen las columnas mapeadas en 
+                            <literal>UPDATE</literal>s SQL?
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="properties4">
+                            <para>
+                                <literal>optimistic-lock</literal> (opcional - por defecto a <literal>true</literal>):
+                                Especifica si las actualizaciones de estas propiedades requieren o no de la
+                                adquisici&#x00f3;n de un bloqueo optimista. En otras palabras, determina si
+                                debe ocurrir un incremento de versi&#x00f3;n cuando estas propiedades est&#x00e1;n
+                                desactualizadas.
+                            </para>
+                    </callout>
+                    <callout arearefs="properties5">
+                            <para>
+                                <literal>unique</literal> (opcional - por defecto a <literal>false</literal>):
+                                Especifica que existe una restricci&#x00f3;n de unicidad sobre todas las
+                                columnas mapeadas del componente.
+                            </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                Por ejemplo, si tenemos el siguiente mapeo de <literal>&lt;properties&gt;</literal>:
+            </para>
+            
+            <programlisting><![CDATA[<class name="Person">
+    <id name="personNumber"/>
+    ...
+    <properties name="name" 
+            unique="true" update="false">
+        <property name="firstName"/>
+        <property name="initial"/>
+        <property name="lastName"/>
+    </properties>
+</class>]]></programlisting>
+
+            <para>
+                Entonces puede que tengamos alguna asociaci&#x00f3;n de datos heredados que se refiera
+                a esta clave &#x00fa;nica de la tabla de <literal>Person</literal>, en vez de la clave
+                primaria:
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="person" 
+         class="Person" property-ref="name">
+    <column name="firstName"/>
+    <column name="initial"/>
+    <column name="lastName"/>
+</many-to-one>]]></programlisting>
+            
+            <para>
+                No recomendamos el uso de este tipo de cosas fuera del contexto del mapeo de
+                datos heredados.
+            </para>
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-subclass" revision="3">
+            <title>subclass</title>
+
+            <para>
+                Finalmente, la persistencia polim&#x00f3;rfica requiere la declaraci&#x00f3;n
+                de la clase persistente ra&#x00ed;z. Para la estrategia de mapeo
+                tabla-por-jerarqu&#x00ed;a-de-clases, se usa la declaraci&#x00f3;n de
+                <literal>&lt;subclass&gt;</literal>.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="subclass1" coords="2 55"/>
+                    <area id="subclass2" coords="3 55"/>
+                    <area id="subclass3" coords="4 55"/>
+                    <area id="subclass4" coords="5 55"/>
+                </areaspec>
+                <programlisting><![CDATA[<subclass
+        name="ClassName"
+        discriminator-value="discriminator_value"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        entity-name="EntityName"
+        node="element-name">
+
+        <property .... />
+        .....
+</subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="subclass1">
+                        <para>
+                            <literal>name</literal>: El nombre de clase cualificado completamente
+                            de la subclase.
+                        </para>              
+                    </callout>                   
+                    <callout arearefs="subclass2">
+                        <para>
+                            <literal>discriminator-value</literal> (opcional - por defecto al nombre de la clase):
+                            Un valor que distingue a subclases individuales.
+                        </para>               
+                    </callout>
+                    <callout arearefs="subclass3">
+                        <para>
+                            <literal>proxy</literal> (opcional): Especifica una clase o interface a usar para
+                            proxies de inicializaci&#x00f3;n perezosa.
+                        </para>               
+                    </callout>
+                    <callout arearefs="subclass4">
+                        <para>
+                            <literal>lazy</literal> (opcional, por defecto a <literal>true</literal>):
+                            Establecer <literal>lazy="false"</literal> deshabilita el uso de recuperaci&#x00f3;n
+                            perezosa.
+                        </para>
+                    </callout>    
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Cada subclase debe declarar sus propias propiedades persistentes y subclases.
+                Se asume que las propiedades <literal>&lt;version&gt;</literal> y <literal>&lt;id&gt;</literal>
+                son heredadas de la clase ra&#x00ed;z. Cada subclase en una jerarqu&#x00ed;a debe
+                definir un <literal>discriminator-value</literal> &#x00fa;nico. Si no se especifica ninguno,
+                se usa el nombre completamente cualificado de clase Java.
+            </para>
+            
+       <para>
+            Es posible definir mapeos <literal>subclass</literal>, <literal>union-subclass</literal>,
+            y <literal>joined-subclass</literal> en documentos de mapeo separados, directamente debajo
+            de <literal>hibernate-mapping</literal>. Esto te permite extender una jerarqu&#x00ed;a de clases
+            con s&#x00f3;lo agregar un nuevo fichero de mapeo. Debes especificar un atributo
+            <literal>extends</literal> en el mapeo de la subclase, mencionando una superclase previamente mapeada.
+            Nota: Previamente esta funcionalidad hac&#x00ed;a importante el orden de los documentos de mapeo.
+            Desde Hibernate3, el orden de los ficheros de mapeo no importa cuando se usa la palabra reservada
+            extends. El orden dentro de un mismo fichero de mapeo todav&#x00ed;a necesita ser definido como
+            superclases antes de subclases.
+        </para>
+    
+        <programlisting><![CDATA[
+<hibernate-mapping>
+    <subclass name="DomesticCat" extends="Cat" discriminator-value="D">
+         <property name="name" type="string"/>
+    </subclass>
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Para informaci&#x00f3;n acerca de mapeos de herencia, ver <xref linkend="inheritance"/>.
+            </para>
+
+        </sect2>
+
+         <sect2 id="mapping-declaration-joinedsubclass" revision="3">
+            <title>joined-subclass</title>
+
+            <para>
+                Alternativamente, cada subclase puede ser mapeada a su propia tabla
+                (estrategia de mapeo tabla-por-subclase). El estado heredado se recupera
+                uniendo con la tabla de la superclase.
+                Usamos el elemento <literal>&lt;joined-subclass&gt;</literal>.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="joinedsubclass1" coords="2 45"/>
+                    <area id="joinedsubclass2" coords="3 45"/>
+                    <area id="joinedsubclass3" coords="4 45"/>
+                    <area id="joinedsubclass4" coords="5 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<joined-subclass
+        name="ClassName"
+        table="tablename"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        schema="schema"
+        catalog="catalog"
+        extends="SuperclassName"
+        persister="ClassName"
+        subselect="SQL expression"
+        entity-name="EntityName"
+        node="element-name">
+
+        <key .... >
+
+        <property .... />
+        .....
+</joined-subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="joinedsubclass1">
+                        <para>
+                            <literal>name</literal>: El nombre de clase completamente cualificado de
+                            la subclase.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="joinedsubclass2">
+                        <para>
+                            <literal>table</literal>: El nombre de tabla de la subclase.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="joinedsubclass3">
+                        <para>
+                            <literal>proxy</literal> (opcional): Especifica una clase o interface a
+                            usar para proxies de inicializac&#x00f3;n perezosa.
+                        </para>              
+                    </callout>
+                    <callout arearefs="joinedsubclass4">
+                        <para>
+                             <literal>lazy</literal> (opcional, por defecto a <literal>true</literal>):
+                            Establecer <literal>lazy="false"</literal> deshabilita el uso de recuperaci&#x00f3;n
+                            perezosa.
+                         </para>
+                    </callout>    
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                No se requiere de una columna discriminadora para esta estrategia de mapeo. Cada subclase debe,
+                sin embargo, declarar una columna de tabla que tenga el identificador del objeto usando el
+                elemento <literal>&lt;key&gt;</literal>. El mapeo del comienzo del cap&#x00ed;tulo
+                deber&#x00ed;a ser reescrito como:
+            </para>
+            
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+        <class name="Cat" table="CATS">
+                <id name="id" column="uid" type="long">
+                        <generator class="hilo"/>
+                </id>
+                <property name="birthdate" type="date"/>
+                <property name="color" not-null="true"/>
+                <property name="sex" not-null="true"/>
+                <property name="weight"/>
+                <many-to-one name="mate"/>
+                <set name="kittens">
+                        <key column="MOTHER"/>
+                        <one-to-many class="Cat"/>
+                </set>
+                <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
+                    <key column="CAT"/>
+                    <property name="name" type="string"/>
+                </joined-subclass>
+        </class>
+
+        <class name="eg.Dog">
+                <!-- mapping for Dog could go here -->
+        </class>
+
+</hibernate-mapping>]]></programlisting>
+
+             <para>
+                 Para informaci&#x00f3;n acerca de mapeos de herencia, ver <xref linkend="inheritance"/>.
+             </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-unionsubclass" revision="2">
+           <title>union-subclass</title>
+
+           <para>
+               Una tercera opci&#x00f3;n es mapear s&#x00f3;lo las clases concretas de una
+               jerarqu&#x00ed;a de clases a tablas, (la estrategia tabla-por-clase-concreta)
+               donde cada tabla define todo el estado persistente de la clase, incluyendo el
+               estado heredado. En Hibernate, no es absolutamente necesario mapear dichas
+               jerarqu&#x00ed;as de herencia. Puedes simplemente mapear cada clase con una
+               declaraci&#x00f3;n <literal>&lt;class&gt;</literal> separada. Sin embargo,
+               si deseas usar asociaciones polim&#x00f3;rficas (por ejemplo, una asociaci&#x00f3;n
+               a la superclase de tu jerarqu&#x00ed;a), debes usar el mapeo
+               <literal>&lt;union-subclass&gt;</literal>.
+           </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="unionsubclass1" coords="2 45"/>
+                    <area id="unionsubclass2" coords="3 45"/>
+                    <area id="unionsubclass3" coords="4 45"/>
+                    <area id="unionsubclass4" coords="5 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<union-subclass
+        name="ClassName"
+        table="tablename"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        schema="schema"
+        catalog="catalog"
+        extends="SuperclassName"
+        abstract="true|false"
+        persister="ClassName"
+        subselect="SQL expression"
+        entity-name="EntityName"
+        node="element-name">
+
+        <property .... />
+        .....
+</union-subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="unionsubclass1">
+                        <para>
+                            <literal>name</literal>: El nombre de clase completamente cualificado de la subclase.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="unionsubclass2">
+                        <para>
+                            <literal>table</literal>: El nombre de tabla de la subclase.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="unionsubclass3">
+                        <para>
+                            <literal>proxy</literal> (optional): Especifica una clase o interface a
+                            usar para proxies de inicializac&#x00f3;n perezosa.
+                        </para>              
+                    </callout>
+                    <callout arearefs="unionsubclass4">
+                        <para>
+                            <literal>lazy</literal> (opcional, por defecto a <literal>true</literal>):
+                            Establecer <literal>lazy="false"</literal> deshabilita el uso de recuperaci&#x00f3;n
+                            perezosa.
+                         </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                No se requiere columna o columna clave discriminadora para esta estrategia de mapeo.
+            </para>
+
+            <para>
+                Para informaci&#x00f3;n acerca de mapeos de herencia, ver <xref linkend="inheritance"/>.
+            </para>
+
+        </sect2>
+
+   	<sect2 id="mapping-declaration-join" revision="3">
+            <title>join</title>
+
+            <para>
+                Usando el elemento <literal>&lt;join&gt;</literal>, es posible mapear
+                propiedades de una clase a varias tablas.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="join1" coords="2 50"/>
+                    <area id="join2" coords="3 50"/>
+                    <area id="join3" coords="4 50"/>
+                    <area id="join4" coords="5 50"/>
+                    <area id="join5" coords="6 50"/>
+                    <area id="join6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<join
+        table="tablename"
+        schema="owner"
+        catalog="catalog"
+        fetch="join|select"
+        inverse="true|false"
+        optional="true|false">
+        
+        <key ... />
+        
+        <property ... />
+        ...
+</join>]]></programlisting>
+
+                <calloutlist>
+                    <callout arearefs="join1">
+                        <para>
+                            <literal>table</literal>: El nombre de la clase unida.
+                        </para>
+                    </callout>
+                    <callout arearefs="join2">
+                        <para>
+                            <literal>schema</literal> (opcional): Sobrescribe el nombre de esquema
+                            especificado por el elemento ra&#x00ed;z <literal>&lt;hibernate-mapping&gt;</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="join3">
+                        <para>
+                            <literal>catalog</literal> (opcional): Sobrescribe el nombre de cat&#x00e1;logo
+                            especificado por el elemento ra&#x00ed;z <literal>&lt;hibernate-mapping&gt;</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="join4">
+                        <para>
+                            <literal>fetch</literal> (opcional - por defecto a <literal>join</literal>):
+                            Si se establece a <literal>join</literal>, por defecto, Hibernate usar&#x00e1;
+                            una uni&#x00f3;n interior (inner join) para recuperar un <literal>&lt;join&gt;</literal>
+                            definido por una clase o sus superclases y una uni&#x00f3;n externa (outer join)
+                            para un <literal>&lt;join&gt;</literal> definido por una subclase.
+                            Si se establece a <literal>select</literal>, entonces Hibernate usar&#x00e1; una
+                            select secuencial para un <literal>&lt;join&gt;</literal> definido en una subclase,
+                            que ser&#x00e1; publicada s&#x00f3;lo si una fila resulta representar una instancia
+                            de la subclase. Las uniones interiores todav&#x00ed;a ser&#x00e1;n usados para
+                            recuperar un <literal>&lt;join&gt;</literal> definido por la clase y sus superclases.
+                        </para>
+                    </callout>
+                    <callout arearefs="join5">
+                        <para>
+                            <literal>inverse</literal> (opcional - por defecto a <literal>false</literal>):
+                            De habilitarse, Hibernate no intentar&#x00e1; insertar o actualizar las propiedades
+                            definidas por esta uni&#x00f3;n.
+                        </para>
+                    </callout>
+                    <callout arearefs="join6">
+                        <para>
+                            <literal>optional</literal> (opcional - por defecto a <literal>false</literal>):
+                            De habilitarse, Hibernate insertar&#x00e1; una fila s&#x00f3;lo si las propiedades
+                            definidas por esta uni&#x00f3;n son no nulas y siempre usar&#x00e1; una uni&#x00f3;n
+                            externa para recuperar las propiedades.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Por ejemplo, la informaci&#x00f3;n domiciliaria de una persona puede ser mapeada
+                a una tabla separada (preservando a la vez la sem&#x00e1;ntica de tipo de valor para
+                todas las propiedades):
+            </para>
+
+            <programlisting><![CDATA[<class name="Person"
+    table="PERSON">
+
+    <id name="id" column="PERSON_ID">...</id>
+
+    <join table="ADDRESS">
+        <key column="ADDRESS_ID"/>
+        <property name="address"/>
+        <property name="zip"/>
+        <property name="country"/>
+    </join>
+    ...]]></programlisting>
+
+            <para>
+                Esta funcionalidad es a menudo solamente &#x00fa;til para modelos de datos
+                heredados; recomendamos menos tablas que clases un modelo de dominio m&#x00e1;s
+                granularizado. Sin embargo, es &#x00fa;til para cambiar entre estrategias de mapeo
+                de herencias en una misma jerarqu&#x00ed;a, como se explica luego.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-key">
+            <title>key</title>
+
+            <para>
+                Hasta ahora hemos visto el elemento <literal>&lt;key&gt;</literal> pocas veces.
+                Aparece en cualquier sitio en que el elemento padre de mapeo defina una uni&#x00f3;n
+                a una nueva tabla, y define la clave for&#x00e1;nea en la tabla unida,
+                que referencia la clave primaria de la tabla original.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="key1" coords="2 50"/>
+                    <area id="key2" coords="3 50"/>
+                    <area id="key3" coords="4 50"/>
+                    <area id="key4" coords="5 50"/>
+                    <area id="key5" coords="6 50"/>
+                    <area id="key6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<key
+        column="columnname"
+        on-delete="noaction|cascade"
+        property-ref="propertyName"
+        not-null="true|false"
+        update="true|false"
+        unique="true|false"
+/>]]></programlisting>
+
+                <calloutlist>
+                    <callout arearefs="key1">
+                        <para>
+                            <literal>column</literal> (opcional): El nombre de columna de la clave for&#x00e1;nea.
+                            Puede ser tambi&#x00e9;n especificado por elemento(s) anidado(s)
+                            <literal>&lt;column&gt;</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="key2">
+                        <para>
+                            <literal>on-delete</literal> (opcional, por defecto a <literal>noaction</literal>): 
+                            Especifica si la restricci&#x00f3;n de clave for&#x00e1;nea tiene el borrado en cascada
+                            habilitado a nivel de base de datos.
+                        </para>
+                    </callout>
+                    <callout arearefs="key3">
+                        <para>
+                            <literal>property-ref</literal> (opcional): Especifica que la clave for&#x00e1;nea
+                            referencia columnas que no son del la clave primaria de la tabla original.
+                            (Provisto para datos heredados.)
+                        </para>
+                    </callout>
+                    <callout arearefs="key4">
+                        <para>
+                            <literal>not-null</literal> (opcional): Especifica que las columnas de la clave
+                            for&#x00e1;nea son no nulables (esto est&#x00e1; implicado si la clave for&#x00e1;nea
+                            es tambi&#x00e9;n parte de la clave primaria).
+                        </para>
+                    </callout>
+                    <callout arearefs="key5">
+                        <para>
+                            <literal>update</literal> (opcional): Especifica que la clave for&#x00e1;nea nunca
+                            debe ser actualizada (esto est&#x00e1; implicado si la clave for&#x00e1;nea
+                            es tambi&#x00e9;n parte de la clave primaria).
+                        </para>
+                    </callout>
+                    <callout arearefs="key6">
+                        <para>
+                            <literal>unique</literal> (opcional): Especifica que la clave for&#x00e1;nea
+                            debe tener una restricci&#x00f3;n de unicidad (esto est&#x00e1; implicado si
+                            la clave for&#x00e1;nea es tambi&#x00e9;n la clave primaria).
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Recomendamos que, para los sistemas en donde el rendimiento sea importante, todas las
+                claves deben ser definidas <literal>on-delete="cascade"</literal>, e Hibernate usar&#x00e1;
+                una restricci&#x00f3;n <literal>ON CASCADE DELETE</literal> a nivel de base de datos,
+                en vez de muchas sentencias <literal>DELETE</literal> individuales. Ten en cuenta que
+                esta funcionalidad se salta la habitual estrategia de bloqueo optimista de Hibernate para
+                datos versionados.
+            </para>
+            
+            <para>
+                Los atributos <literal>not-null</literal> y <literal>update</literal> son &#x00fa;tiles
+                al mapear una asociaci&#x00f3;n uno a muchos unidireccional. Si mapeas una uno a muchos
+                unidireccional a una clave for&#x00e1;nea no nulable, <emphasis>debes</emphasis> declarar
+                la columna clave usando <literal>&lt;key not-null="true"&gt;</literal>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-column" revision="3">
+           <title>los elementos column y formula</title>
+           <para>
+               Cualquier elemento de mapeo que acepte un atributo <literal>column</literal> aceptar&#x00e1;
+               alternativamente un subelemento <literal>&lt;column&gt;</literal>. De forma similar,
+               <literal>&lt;formula&gt;</literal> es una alternativa al atributo <literal>formula</literal>.
+           </para>
+
+           <programlisting><![CDATA[<column
+        name="column_name"
+        length="N"
+        precision="N"
+        scale="N"
+        not-null="true|false"
+        unique="true|false"
+        unique-key="multicolumn_unique_key_name"
+        index="index_name"
+        sql-type="sql_type_name"
+        check="SQL expression"/>]]></programlisting>
+
+            <programlisting><![CDATA[<formula>expresi&#x00f3;n SQL</formula>]]></programlisting>
+        
+            <para>
+                Los atributos <literal>column</literal> y <literal>formula</literal> pueden
+                incluso ser combinados dentro del mismo mapeo de propiedad o asociaci&#x00f3;n para
+                expresar, por ejemplo, condiciones de uni&#x00f3;n ex&#x00f3;ticas.
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="homeAddress" class="Address"
+        insert="false" update="false">
+    <column name="person_id" not-null="true" length="10"/>
+    <formula>'MAILING'</formula>
+</many-to-one>]]></programlisting>
+
+    </sect2>  
+   	
+        <sect2 id="mapping-declaration-import">
+            <title>import</title>
+
+            <para>
+                Sup&#x00f3;n que tu aplicaci&#x00f3;n tiene dos clases persistentes con el mismo nombre,
+                y no quieres especificar el nombre completamenta cualificado (paquete) en las consultas
+                Hibernate. Las clases pueden ser "importadas" expl&#x00ed;citamente, en vez de confiar en
+                <literal>auto-import="true"</literal>. Puedes incluso importar clases e interfaces que
+                no est&#x00e9;n mapeadas expl&#x00ed;citamente.
+            </para>
+            
+            <programlisting><![CDATA[<import class="java.lang.Object" rename="Universe"/>]]></programlisting>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="import1" coords="2 40"/>
+                    <area id="import2" coords="3 40"/>
+                </areaspec>
+                <programlisting><![CDATA[<import
+        class="ClassName"
+        rename="ShortName"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="import1">
+                        <para>
+                            <literal>class</literal>: El nombre de clase completamente cualificado de
+                            cualquier clase Java.
+                        </para>              
+                    </callout>                   
+                    <callout arearefs="import2">
+                        <para>
+                            <literal>rename</literal> (opcional - por defecto al nombre de clase sin cualificar):
+                            Un nombre que ser&#x00e1; usado en el leguaje de consulta.
+                        </para>               
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+        </sect2>
+
+        <sect2 id="mapping-types-anymapping" revision="2">
+            <title>any</title>
+            
+            <para>
+                Hay un tipo m&#x00e1;s de mapeo de propiedad. El elemento de mapeo <literal>&lt;any&gt;</literal>
+                define una asociaci&#x00e1;n polim&#x00f3;rfica a clases desde m&#x00fa;ltiples tablas. Este tipo
+                de mapeo siempre requiere m&#x00e1;s de una columna. La primera columna contiene el tipo de la
+                entidad asociada. Las columnas restantes contienen el identificador. Es imposible especificar una
+                restricci&#x00f3;n de clave for&#x00e1;nea para este tipo de asociaci&#x00f3;n, por lo que
+                esto ciertamente no est&#x00e1; concebido como la forma habitual de mapear asociaciones
+                (polim&#x00f3;rficas). S&#x00f3;lo debes usar esto en casos muy especiales (por ejemplo,
+                trazas de auditor&#x00e9;a, datos de sesi&#x00f3;n de usuario, etc).
+            </para>
+
+            <para>
+                 El atributo <literal>meta-type</literal> permite a la aplicaci&#x00f3;n especificar un tipo
+                 personalizado que mapee columnas de base de datos a clases persistentes que tengan propiedades
+                 identificadoras del tipo especificado por <literal>id-type</literal>. Debes especificar el
+                 mapeo de valores del meta-type a nombres de clase.
+            </para>
+
+            <programlisting><![CDATA[<any name="being" id-type="long" meta-type="string">
+    <meta-value value="TBL_ANIMAL" class="Animal"/>
+    <meta-value value="TBL_HUMAN" class="Human"/>
+    <meta-value value="TBL_ALIEN" class="Alien"/>
+    <column name="table_name"/>
+    <column name="id"/>
+</any>]]></programlisting>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="any1" coords="2 50"/>
+                    <area id="any2" coords="3 50"/>
+                    <area id="any3" coords="4 50"/>
+                    <area id="any4" coords="5 50"/>
+                    <area id="any5" coords="6 50"/>
+                    <area id="any6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<any
+        name="propertyName"
+        id-type="idtypename"
+        meta-type="metatypename"
+        cascade="cascade_style"
+        access="field|property|ClassName"
+        optimistic-lock="true|false"
+>
+        <meta-value ... />
+        <meta-value ... />
+        .....
+        <column .... />
+        <column .... />
+        .....
+</any>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="any1">
+                        <para>
+                            <literal>name</literal>: el nombre de la propiedad.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any2">
+                        <para>
+                            <literal>id-type</literal>: el tipo del identificador.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any3">
+                        <para>
+                            <literal>meta-type</literal> (opcional - por defecto a <literal>string</literal>): 
+                            Cualquier tipo que sea permitido para un mapeo de discriminador.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any4">
+                        <para>
+                            <literal>cascade</literal> (opcional- por defecto a <literal>none</literal>): 
+                            el estilo de cascada.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any5">
+                        <para>
+                            <literal>access</literal> (opcional - por defecto a <literal>property</literal>): La
+                            estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+                        </para>
+                    </callout>
+                    <callout arearefs="any6">
+                        <para>
+                            <literal>optimistic-lock</literal> (opcional - por defecto a <literal>true</literal>):
+                            Especifica si las actualizaciones de esta propiedad requieren o no de la
+                            adquisici&#x00f3;n del bloqueo optimista. En otras palabras, determina si debe ocurrir
+                            un incremento de versi&#x00f3;n cuando esta propiedad est&#x00e1; desactualizada.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+      </sect2>
+
+    </sect1>
+
+    <sect1 id="mapping-types">
+        <title>Tipos de Hibernate</title>
+
+        <sect2 id="mapping-types-entitiesvalues" revision="1">
+            <title>Entidades y Valores</title>
+
+            <para>
+                Para entender el comportamiento de varios objetos a nivel de lenguaje Java
+                con respecto al servicio de persistencia, necesitamos clasificarlos en dos grupos:
+            </para>
+
+            <para>
+                Una <emphasis>entidad</emphasis> existe independientemente de cualquier otros
+                objetos que referencien a la entidad. Contrasta esto con el model habitual de Java
+                donde un objeto desreferenciado es recolectado como basura. Las entidades deben ser
+                salvadas y borradas expl&#x00ed;citamente (excepto que las grabaciones y borrados
+                puedan ser <emphasis>tratados en cascada</emphasis> desde una entidad padre a sus hijos).
+                Esto es diferente al modelo de persistencia de objetos por alcance - y se corresponde
+                m&#x00e1;s de cerca a c&#x00f3;mo los objetos de aplicaci&#x00f3;n son usados
+                habitualmente en grandes sistemas. Las entidades soportan referencias circulares y
+                compartidas, que tambi&#x00e9; pueden ser versionadas.
+            </para>
+
+            <para>
+                El estado persistente de una entidad consiste en referencias a otras entidades
+                e instancias de tipo <emphasis>valor</emphasis>. Los valores son primitivos,
+                colecciones (no lo que est&#x00e1; dentro de la colecci&#x00f3;n), componentes
+                y ciertos objetos inmutables. A diferencia de las entidades, los valores
+                (en particular las colecciones y los componentes) <emphasis>son</emphasis>
+                hechos persitentes y borrados por alcance. Como los objetos valor (y primitivos)
+                son persistidos y borrados junto a sus entidades contenedoras, no pueden ser
+                versionados independientemente. Los valores no tienen identidad independiente,
+                por los que no pueden ser compartidos por dos entidades o colleciones.
+            </para>
+
+            <para>
+                Hasta ahora, hemos estado usando el t&#x00e9;rmino "clase persistente"
+                para referirnos a entidades. Continuaremos haci&#x00e9;ndolo. Hablando
+                estrictamente, sin embargo, no todas la clases  con estado persistente
+                definidas por el usuario son entidades. Un <emphasis>componente</emphasis>
+                es una clase definida por el usuario con sem&#x00e1;ntica de valor.
+                Una propiedad Java de tipo <literal>java.lang.String</literal> tambi&#x00e9;n
+                tiene sem&#x00e1;ntica de valor. Dada esta definici&#x00f3;n, podemos decir
+                que todos los tipo (clases) provistos por el JDK tienen una sem&#x00e1;ntica
+                de tipo valor en Java, mientras que los tipos definidos por el usuario
+                pueden ser mapeados con sem&#x00e1;ntica de tipo valor o de entidad.
+                La desici&#x00f3;n corre por cuenta del desarrollador de la aplicaci&#x00f3;n.
+                Un buen consejo para una clase entidad en un modelo de dominio son las referencias
+                compartidas a una sola instancia de esa clase, mientras que la composici&#x00f3;n
+                o agregaci&#x00f3;n usualmente se traducen a un tipo de valor.
+            </para>
+
+            <para>
+                Volveremos a visitar ambos conceptos a lo largo de la documentaci&#x00f3;n.
+            </para>
+
+            <para>
+                EL desaf&#x00ed;o es mapear el sistema de tipos de Java (y la definici&#x00f3;n
+                de entidades y tipos de valor de los desarrolladores) al sistema de tipos de
+                SQL/base de datos. EL puente entre ambos sistemas es provisto por Hibernate:
+                para las entidades usamos <literal>&lt;class&gt;</literal>,
+                <literal>&lt;subclass&gt;</literal>, etc. Para los tipos de valor usamos
+                <literal>&lt;property&gt;</literal>, <literal>&lt;component&gt;</literal>, etc,
+                usualmente con un atributo <literal>type</literal>. El valor de este atributo
+                es el nombre de un <emphasis>tipo de mapeo</emphasis> de Hibernate. Hibernate
+                provee de f&#x00e1;brica muchos mapeos (para tipos de valores del JDK
+                est&#x00e1;ndar). Puedes escribir tus propios mapeos de tipo, as&#x00ed; como 
+                implementar tus estrategias de conversi&#x00f3;n personalizadas, como veremos luego.
+            </para>
+
+            <para>
+                Todos los tipos prefabricados de Hibernate soportan sem&#x00e1;ntica de nulos
+                excepto las colecciones.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-types-basictypes" revision="2">
+            <title>Tipos de valores b&#x00e1;sicos</title>
+
+            <para>
+                Los <emphasis>tipos de mapeo b&#x00e1;sicos</emphasis> prefabricados pueden ser
+                categorizado a grandes rasgos en:
+
+                <variablelist>
+                    <varlistentry>
+                        <term><literal>integer, long, short, float, double, character, byte,
+                            boolean, yes_no, true_false</literal></term>
+                        <listitem>
+                            <para>
+                                Mapeos de tipos primitivos de Java o clases de envoltura a
+                                la tipos de columna SQL (espec&#x00ed;cifica del vendedor).
+                                <literal>boolean, yes_no</literal> y <literal>true_false</literal>
+                                son codificaciones alternativas a <literal>boolean</literal> de
+                                Java o <literal>java.lang.Boolean</literal>.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>string</literal></term>
+                        <listitem>
+                            <para>
+                                Un mapeo del tipo <literal>java.lang.String</literal> a
+                                <literal>VARCHAR</literal> (u Oracle <literal>VAARCHAR2</literal>).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>date, time, timestamp</literal></term>
+                        <listitem>
+                            <para>
+                                Mapeos de tipo desde <literal>java.util.Date</literal> y sus subclases
+                                a tipos SQL <literal>DATE</literal>, <literal>TIME</literal> y
+                                <literal>TIMESTAMP</literal> (o equivalente).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>calendar, calendar_date</literal></term>
+                        <listitem>
+                            <para>
+                                Mapeos de tipo desde <literal>java.util.Date</literal> y sus subclases
+                                a tipos SQL <literal>TIMESTAMP</literal> y <literal>DATE</literal>
+                                (o equivalente).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>big_decimal, big_integer</literal></term>
+                        <listitem>
+                            <para>
+                                Mapeos de tipo desde <literal>java.math.BigDecimal</literal> y
+                                <literal>java.math.BigInteger</literal> a <literal>NUMERIC</literal> 
+                                (o <literal>NUMBER</literal> de Oracle).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>locale, timezone, currency</literal></term>
+                        <listitem>
+                            <para>
+                                Mapeos de tipo desde <literal>java.util.Locale</literal>,
+                                <literal>java.util.TimeZone</literal> y 
+                                <literal>java.util.Currency</literal> a 
+                                <literal>VARCHAR</literal> (o <literal>VARCHAR2</literal> de Oracle).
+                                Las instancias de <literal>Locale</literal> y <literal>Currency</literal>
+                                son mapeadas a sus c&#x00f3;digos ISO. Las instancias de
+                                <literal>TimeZone</literal> son mapeadas a sus <literal>ID</literal>.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>class</literal></term>
+                        <listitem>
+                            <para>
+                                Un mapeo de tipo <literal>java.lang.Class</literal> a
+                                <literal>VARCHAR</literal> (o <literal>VARCHAR2</literal> de Oracle).
+                                Una <literal>Class</literal> es mapeara a su nombre completamente
+                                cualificado.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>binary</literal></term>
+                        <listitem>
+                            <para>
+                                Mapea arreglos de bytes a un tipo binario SQL apropiado.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>text</literal></term>
+                        <listitem>
+                            <para>
+                                Mapea cadenas largas Java al tipo SQL <literal>CLOB</literal> o
+                                <literal>TEXT</literal>.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>serializable</literal></term>
+                        <listitem>
+                            <para>
+                                Mapea tipos serializables Java a un tipo binario SQL apropiado.
+                                Puedes adem&#x00e1;s indicar el tipo <literal>serializable</literal>
+                                de Hibernate con el nombre de una clase o interface serializable Java
+                                que no sea por defecto un tipo b&#x00e1;sico.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>clob, blob</literal></term>
+                        <listitem>
+                            <para>
+                                Mapeos de tipo para las clases JDBC <literal>java.sql.Clob</literal> y
+                                <literal>java.sql.Blob</literal>. Estos tipos pueden ser inconvenientes
+                                para algunas aplicaciones, pues el objeto blob o clob no puede ser reusado
+                                fuera de una transacci&#x00f3;n (Adem&#x00e1;s, el soporte del driver suele
+                                ser malo e inconsistente).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                </variablelist>
+            
+            </para>
+
+            <para>
+                Los identificadores &#x00fa;nicos de entidades y collecciones pueden ser de cualquier
+                tipo b&#x00e1;sico excepto <literal>binary</literal>, <literal>blob</literal>
+                y <literal>clob</literal>. 
+                (Los identificadores compuestos est&#x00e1;n tambi&#x00e9;n permitidos, ver debajo.)
+            </para>
+            
+            <para>
+                Los tipos de valor b&#x00e1;sicos tienen sus constantes <literal>Type</literal>
+                correspondientes definidas en <literal>org.hibernate.Hibernate</literal>. Por ejemplo,
+                <literal>Hibernate.STRING</literal> representa el tipo <literal>string</literal>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-types-custom" revision="2">
+            <title>Tipos de valor personalizados</title>
+
+            <para>
+                Es relativamente f&#x00e1;cil para los desarrolladores crear sus propios tipos de valor.
+                Por ejemplo, podr&#x00ed;as querer persistir propiedades del tipo <literal>java.lang.BigInteger</literal>
+                a columnas <literal>VARCHAR</literal>. Hibernate no provee un tipo de f&#x00e1;brica para esto.
+                Pero los tipos personalizados no est&#x00e1;n limitados a mapear una propiedad (o elemento de colecci&#x00f3;n)
+                a una sola columna de tabla. As&#x00ed;, por ejemplo, podr&#x00ed;as tener una propiedad Java
+                <literal>getName()</literal>/<literal>setName()</literal> de tipo <literal>java.lang.String</literal>
+                que fuera persistida a las columnas <literal>FIRST_NAME</literal>, <literal>INITIAL</literal>,
+                <literal>SURNAME</literal>.
+            </para>
+            
+            <para>
+                Para implementar un tipo personalizado, implementa bien <literal>org.hibernate.UserType</literal>
+                o <literal>org.hibernate.CompositeUserType</literal> y declara las propiedades usando el nombre
+                de clase completamente cualificado del tipo. Revisa <literal>org.hibernate.test.DoubleStringType</literal>
+                para ver qu&#x00e9; tipo de cosas son posibles.
+            </para>
+
+            <programlisting><![CDATA[<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
+    <column name="first_string"/>
+    <column name="second_string"/>
+</property>]]></programlisting>
+
+            <para>
+                Observa el uso de etiquetas <literal>&lt;column&gt;</literal> para mapear una propiedad
+                a m&#x00fa;ltiples columnas.
+            </para>
+            
+            <para>
+                Las interfaces <literal>CompositeUserType</literal>, <literal>EnhancedUserType</literal>,
+                <literal>UserCollectionType</literal>, y <literal>UserVersionType</literal> proveen
+                soporte a usos m&#x00e1;s especializados.
+            </para>
+            
+            <para>
+                Puedes incluso proveer de par&#x00e1;metros a un <literal>UserType</literal> en el 
+                fichero de mapeo. Para hacer esto, tu <literal>UserType</literal> debe implementar
+                la interface <literal>org.hibernate.usertype.ParameterizedType</literal>. Para
+                proveer de par&#x00e1;metros a tu tipo personalizado, puedes usar el elemento 
+                <literal>&lt;type&gt;</literal> en tus ficheros de mapeo.
+            </para>
+            
+            <programlisting><![CDATA[<property name="priority">
+    <type name="com.mycompany.usertypes.DefaultValueIntegerType">
+        <param name="default">0</param>
+    </type>
+</property>]]></programlisting>
+
+            <para>
+                Ahora el <literal>UserType</literal> puede recuperar el valor del par&#x00e1;metro
+                llamado <literal>default</literal> del objeto <literal>Properties</literal>
+                que se le pasa.
+            </para>
+            
+            <para>
+                Si usas cierto <literal>UserType</literal> muy frecuentemente, puede ser &#x00fa;til
+                definir un nombre corto para &#x00e9;. Puedes hacer esto usando el elemento
+                <literal>&lt;typedef&gt;</literal>. Los typedefs asignan un nombre a un tipo
+                personalizado, y pueden tambi&#x00e9;n contener una lista de valores por defecto
+                de par&#x00e1;metros si el tipo fuese parametrizado.
+            </para>
+            
+            <programlisting><![CDATA[<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
+    <param name="default">0</param>
+</typedef>]]></programlisting>
+
+            <programlisting><![CDATA[<property name="priority" type="default_zero"/>]]></programlisting>
+
+            <para>
+                tambi&#x00e9;n es posible sobrescribir los par&#x00e1;metros provistos en un typedef sobre
+                una base caso por caso usando par&#x00e1;metros de tipo en el mapeo de la propiedad.
+            </para>
+            
+            <para>
+                Aunque el rico espectro de tipos prefabricados y soporte de componentes de Hibernate
+                significa que raramente <emphasis>necesites</emphasis> usar un tipo personalizado;
+                sin embargo se considera una buena forma usar tipos personalizados para clases (no-entidades)
+                que aparezcan frecuentemente en tu aplicaci&#x00f3;n. Por ejemplo, una clase
+                <literal>MonetaryAmount</literal> es una buena candidata para un
+                <literal>CompositeUserType</literal>, incluso cuando puede ser facilmente mapeada como un
+                componente. Un motivo para esto es la abstracci&#x00f3;n. Con un tipo personalizado,
+                tus documentos de mapeo estar&#x00e1; impermeabilizados contra posibles cambios futuros en la
+                forma de representar valores monetarios.
+            </para>
+        </sect2>
+
+    </sect1>
+
+
+    <sect1 id="mapping-entityname">
+        <title>Mapeando una clase m&#x00e1;s de una vez</title>
+        <para>
+            Es posible proveer m&#x00e1;s de un mapeo para una clase persistente en particular. En este caso debes
+            especificar un <emphasis>nombre de entidad</emphasis> para desambiguar entr las instancias de las
+            dos entidades mapeadas. (Por defectom, el nombre de la entidad es el mismo que el nombre de la clase.)
+            Hibernate te deja especificar el nombre de entidad al trabajar con objetos persistentes, al escribir
+            consultas, o al mapear asociaciones a la entidad mencionada.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Contract" table="Contracts" 
+        entity-name="CurrentContract">
+    ...
+    <set name="history" inverse="true" 
+            order-by="effectiveEndDate desc">
+        <key column="currentContractId"/>
+        <one-to-many entity-name="HistoricalContract"/>
+    </set>
+</class>
+
+<class name="Contract" table="ContractHistory" 
+        entity-name="HistoricalContract">
+    ...
+    <many-to-one name="currentContract" 
+            column="currentContractId" 
+            entity-name="CurrentContract"/>
+</class>]]></programlisting>
+
+        <para>
+            Observa c&#x00f3;mo las asociaciones ahora se especifican usando <literal>entity-name</literal> en vez de
+            <literal>class</literal>.
+        </para>
+
+    </sect1>
+
+
+    <sect1 id="mapping-quotedidentifiers">
+            <title>identificadores SQL encomillados</title>
+            <para>
+                Puedes forzar a Hibernate a encomillar un identificador en el SQL generado encerrando el nombre
+                de tabla o columna entre backticks en el documento de mapeo. Hibernate usar&#x00e1; el estilo de
+                encomillado para el <literal>Dialect</literal> SQL (usualmente comillas dobles, excepto corchetes
+                para SQL Server y backsticks para MySQL).
+            </para>
+
+            <programlisting><![CDATA[<class name="LineItem" table="`Line Item`">
+    <id name="id" column="`Item Id`"/><generator class="assigned"/></id>
+    <property name="itemNumber" column="`Item #`"/>
+    ...
+</class>]]></programlisting>
+
+    </sect1>
+
+  	
+   	<sect1 id="mapping-alternatives">
+   	<title>Alternativas de metadatos</title>
+   	
+   	<para>
+            XML no es para todos, as&#x00e1; que hay algunas formas alternativas de definir metadatos de mapeo O/R
+            en Hibernate.
+   	</para>
+
+    <sect2 id="mapping-xdoclet">
+        <title>Usando marcado de XDoclet</title>
+
+        <para>
+            Muchos usuarios de Hibernate prefieren embeber la informaci&#x00f3;n de mapeo directamente
+            en el c&#x00f3;digo fuente usando las <literal>@hibernate.etiquetas</literal> XDoclet.
+            No cubriremos este enfoque en este documento, pues estrictamente es considerado parte
+            de XDoclet. Sin embargo, inclu&#x00ed;mos el siguiente ejemplo de la clase
+            <literal>Cat</literal> con mapeos XDoclet.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+/**
+ * @hibernate.class
+ *  table="CATS"
+ */
+public class Cat {
+    private Long id; // identifier
+    private Date birthdate;
+    private Cat mother;
+    private Set kittens
+    private Color color;
+    private char sex;
+    private float weight;
+
+    /*
+     * @hibernate.id
+     *  generator-class="native"
+     *  column="CAT_ID"
+     */
+    public Long getId() {
+        return id;
+    }
+    private void setId(Long id) {
+        this.id=id;
+    }
+
+    /**
+     * @hibernate.many-to-one
+     *  column="PARENT_ID"
+     */
+    public Cat getMother() {
+        return mother;
+    }
+    void setMother(Cat mother) {
+        this.mother = mother;
+    }
+
+    /**
+     * @hibernate.property
+     *  column="BIRTH_DATE"
+     */
+    public Date getBirthdate() {
+        return birthdate;
+    }
+    void setBirthdate(Date date) {
+        birthdate = date;
+    }
+    /**
+     * @hibernate.property
+     *  column="WEIGHT"
+     */
+    public float getWeight() {
+        return weight;
+    }
+    void setWeight(float weight) {
+        this.weight = weight;
+    }
+
+    /**
+     * @hibernate.property
+     *  column="COLOR"
+     *  not-null="true"
+     */
+    public Color getColor() {
+        return color;
+    }
+    void setColor(Color color) {
+        this.color = color;
+    }
+    /**
+     * @hibernate.set
+     *  inverse="true"
+     *  order-by="BIRTH_DATE"
+     * @hibernate.collection-key
+     *  column="PARENT_ID"
+     * @hibernate.collection-one-to-many
+     */
+    public Set getKittens() {
+        return kittens;
+    }
+    void setKittens(Set kittens) {
+        this.kittens = kittens;
+    }
+    // addKitten not needed by Hibernate
+    public void addKitten(Cat kitten) {
+        kittens.add(kitten);
+    }
+
+    /**
+     * @hibernate.property
+     *  column="SEX"
+     *  not-null="true"
+     *  update="false"
+     */
+    public char getSex() {
+        return sex;
+    }
+    void setSex(char sex) {
+        this.sex=sex;
+    }
+}]]></programlisting>
+
+        <para>
+            Para m&#x00e1;s ejemplos de XDoclet e Hibernate ver en el sitio web de Hibernate.
+        </para>
+
+    </sect2>
+
+    <sect2 id="mapping-annotations" revision="2">
+        <title>Usando anotaciones JDK 5.0</title>
+        <para>
+            El JDK 5.0 introdujo anotaciones del estilo XDoclet a nivel del lenguaje,
+            con chequeo seguro de tipos en tiempo de compilaci&#x00f3;n. Este mecanismo es m&#x00e1;s
+            potente y que las anotaciones XDoclet, y mejor soportado por herramientas e IDEs.
+            IntelliJ IDEA, por ejemplo, soporta auto-compleci&#x00f3;n y resaltado de sintaxis de anotaciones
+            JDK 5.0. La nueva revisi&#x00f3;n de la especificaci&#x00f3;n de EJB (JSR-220) usa anotaciones
+            JDK 5.0 como el mecanismo primario de metadatos para beans de entidad. Hibernate3 implementa
+            el <literal>EntityManager</literal> del JSR-220 (la API de persistencia), y el soporte para
+            metadatos de mapeo est&#x00e1; disponible v&#x00ed;a el paquete <emphasis>Hibernate Annotations</emphasis>,
+            como una descarga por separado. Tanto metadatos de EJB3 (JSR-220) como de Hibernate3 est&#x00e1;n soportados.
+        </para>
+
+        <para>
+            Este es un ejemplo de una clase POJO anotada como un bean de entidad EJB:
+        </para>
+
+        <programlisting><![CDATA[@Entity(access = AccessType.FIELD)
+public class Customer implements Serializable {
+
+    @Id;
+    Long id;
+
+    String firstName;
+    String lastName;
+    Date birthday;
+
+    @Transient
+    Integer age;
+
+    @Embedded
+    private Address homeAddress;
+
+    @OneToMany(cascade=CascadeType.ALL)
+
+    @JoinColumn(name="CUSTOMER_ID")
+    Set<Order> orders;
+
+    // Getter/setter and business methods
+}]]></programlisting>
+
+        <para>
+            Ten en cuenta que el soporte a anotaciones JDK 5.0 (y JSR-220) es todav&#x00ed;a un
+            trabajo en progreso y no completado. Por favor, para m&#x00e1;s detalles refi&#x00e9;rete al modulo
+            de Anotaciones de Hibernate.
+        </para>
+    
+    </sect2>
+    </sect1>
+
+</chapter>
+
+
+
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/batch.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/batch.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/batch.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,192 @@
+<chapter id="batch">
+    <title>Procesamiento por lotes</title>
+    
+    <para>
+        Un enfoque ingenuo para insertar 100.000 filas en la base de datos usando Hibernate podría verse así:
+    </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+for ( int i=0; i<100000; i++ ) {
+    Customer customer = new Customer(.....);
+    session.save(customer);
+}
+tx.commit();
+session.close();]]></programlisting>
+
+    <para>
+        Esto podría caer sobre una <literal>OutOfMemoryException</literal> en algún sitio
+        cerca de la fila 50.000. Esto es porque Hibernate tiene en caché todas las instancias
+        de <literal>Customer</literal> recién instanciadas en el caché de nivel de sesión.
+    </para>
+
+    <para>
+        En este capítulo te mostraremos cómo evitar este problema. Primero, sin embargo,
+        si estás haciendo procesamiento por lotes (batch processing), es absolutamente crítico
+        que habilites el uso de loteo JDBC, si pretendes lograr un rendimiento razonable.
+        Establece el tamaño de lote JDBC a un número razonable (digamos 10-50):
+    </para>
+    
+<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
+
+    <para>
+        Podrías además querer hacer este tipo de trabajo en un proceso donde la interacción con el caché de
+        segundo nivel esté completamente deshabilitado:
+    </para>
+
+<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
+
+    <sect1 id="batch-inserts">
+        <title>Inserciones en lote</title>
+
+        <para>
+            Al hacer persistentes objetos nuevos, debes limpiar con <literal>flush()</literal> y
+            llamar a <literal>clear()</literal> en la sesión regularmente, para controlar el tamaño
+            del caché de primer nivel.
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+   
+for ( int i=0; i<100000; i++ ) {
+    Customer customer = new Customer(.....);
+    session.save(customer);
+    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
+        //flush a batch of inserts and release memory:
+        session.flush();
+        session.clear();
+    }
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="batch-update" >
+        <title>Actualizaciones en lote</title>
+
+        <para>
+            Para recuperar y actualizar datos se aplican las mismas ideas. Adicionalmente, necesitas usar
+            <literal>scroll()</literal> para sacar ventaja de los cursores del lado del servidor en consultas
+            que devuelvan muchas filas de datos.
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+   
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+    .setCacheMode(CacheMode.IGNORE)
+    .scroll(ScrollMode.FORWARD_ONLY);
+int count=0;
+while ( customers.next() ) {
+    Customer customer = (Customer) customers.get(0);
+    customer.updateStuff(...);
+    if ( ++count % 20 == 0 ) {
+        //flush a batch of updates and release memory:
+        session.flush();
+        session.clear();
+    }
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="batch-direct">
+        <title>update/delete en masa</title>
+
+        <para>
+            Como ya se ha discutido, el mapeo objeto/relacional automático y transparente se refiere
+            al manejo de estado de objetos. Esto implica que el estado del objeto está disponible
+            en memoria, por lo tanto actualizar o borrar (usando <literal>UPDATE</literal> y
+            <literal>DELETE</literal> de SQL) datos directamente en la base de datos no afectará el
+            estado en memoria. Sin embargo, Hibernate provee métodos para la ejecución de sentencias
+            del estilo de <literal>UPDATE</literal> y <literal>DELETE</literal> de SQL que se realizan
+            a través del Lenguaje de Consulta de Hibernate (Hibernate Query Language o
+            <xref linkend="queryhql">HQL</xref>).
+        </para>
+
+	    <para>
+            La pseudo-sintáxis para sentencias <literal>UPDATE</literal> y <literal>DELETE</literal> es:
+            <literal>( UPDATE | DELETE ) FROM? ClassName (WHERE WHERE_CONDITIONS)?</literal>. Algunos puntos
+            a tener en cuenta:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    En la cláusula-from, la palabra clave FROM es opcional
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Puede haber sólo una clase mencionada en la cláusula-from, y <emphasis>no puede</emphasis>
+                    tener un alias.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    No puede especificarse ningún join (bien implícito o explícito) en una consulta masiva de HQL.
+                    Pueden usarse subconsultas en la cláusula-where.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    La cláusula-where es también opcional.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Como un ejemplo, para ejecutar un <literal>UPDATE</literal> HQL, usa el
+            método <literal>Query.executeUpdate()</literal>:
+        </para>
+
+        <programlisting><![CDATA[Session session = sessionFactory.openSession();
+        Transaction tx = session.beginTransaction();
+
+        String hqlUpdate = "update Customer set name = :newName where name = :oldName";
+        int updatedEntities = s.createQuery( hqlUpdate )
+                            .setString( "newName", newName )
+                            .setString( "oldName", oldName )
+                            .executeUpdate();
+        tx.commit();
+        session.close();]]></programlisting>
+
+        <para>
+            Para ejecutar un <literal>DELETE</literal> HQL, usa el mismo método <literal>Query.executeUpdate()</literal>
+            (el método está nombrado para aquellos familiarizados con
+            <literal>PreparedStatement.executeUpdate()</literal> de JDBC):
+        </para>
+
+        <programlisting><![CDATA[Session session = sessionFactory.openSession();
+        Transaction tx = session.beginTransaction();
+
+        String hqlDelete = "delete Customer where name = :oldName";
+        int deletedEntities = s.createQuery( hqlDelete )
+                            .setString( "oldName", oldName )
+                            .executeUpdate();
+        tx.commit();
+        session.close();]]></programlisting>
+
+        <para>
+            El valor <literal>int</literal> devuelto por el método <literal>Query.executeUpdate()</literal>
+            indica el número de entidades afectadas por la operación. Considera que esto puede o no
+            correlacionarse al número de filas afectadas en la base de datos. Una operación masiva HQL podría
+            resultar en que se ejecuten múltiples sentencias de SQL reales, para joined-subclass, por ejemplo.
+            El número devuelto indica el número de entidades reales afectadas por la sentencia. Volviendo al
+            ejemplo de joined-subclass, un borrado contra una de las subclases puede resultar realmente en
+            borrados contra no sólo la tabla a la que está mapeada esa subclase, sino también la tabla "raíz"
+            y potencialmente tablas de joined-subclass más debajo en la jerarquía de herencia.
+        </para>
+
+        <para>
+            Ten en cuenta que existen actualmente unas pocas limitaciones con las operaciones HQL masivas,
+            que serán atendidas en lanzamientos futuros; consulta la hoja de ruta de JIRA para más detalles.
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/best_practices.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/best_practices.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/best_practices.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,229 @@
+<chapter id="best-practices" revision="3">
+    <title>Mejores Pr&#x00e1;cticas</title>
+
+    <variablelist spacing="compact">
+        <varlistentry>
+            <term>Escribe clase finamente granularizadas y mapealas usando <literal>&lt;component&gt;</literal>.</term>
+            <listitem>
+                <para>
+                    Usa una clase <literal>Direcci&#x00f3;n</literal> para encapsular <literal>calle</literal>,
+                    <literal>distrito</literal>, <literal>estado</literal>, <literal>c&#x00f3;digo postal</literal>.
+                    Esto alienta la reutilizaci&#x00f3;n de c&#x00f3;digo y simplifica el refactoring.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Declara las propiedades identificadoras en clases persistentes.</term>
+            <listitem>
+                <para>
+                    Hibernate hace opcionales las propiedades identificadoras. Existen todo tipo de razones
+                    por las que debes usarlas. Recomendamos que los identificadores sean 'sint&#x00e9;ticos'
+                    (generados, sin ning&#x00fa;n significado de negocio).
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Identifica las claves naturales.</term>
+            <listitem>
+                <para>
+                    Identifica las claves naturales de todas las entidades, y mapealas usando
+                    <literal>&lt;natural-id&gt;</literal>. Implementa <literal>equals()</literal> y
+                    <literal>hashCode()</literal> para comparar las propiedades que componen la clave natural.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Coloca cada mapeo de clase en su propio fichero.</term>
+            <listitem>
+                <para>
+                     No uses un solo documento monol&#x00ed;tico de mapeo. Mapea <literal>com.eg.Foo</literal> en
+                     el fichero <literal>com/eg/Foo.hbm.xml</literal>. Esto tiene sentido particularmente en un
+                     ambiente de equipo.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Carga los mapeos como recursos.</term>
+            <listitem>
+                <para>
+                    Despliega los mapeos junto a las clases que mapean.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Considera externalizar las cadenas de consulta.</term>
+            <listitem>
+                <para>
+                    Esta es una buena pr&#x00e1;ctica si tus consultas llaman a funciones SQL que no son del
+                    est&#x00e1;ndar ANSI. Externalizar las cadenas de consulta a ficheros de mapeo har&#x00e1; la
+                    aplicaci&#x00f3;n m&#x00e1;s portable.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Usa variables de ligado.</term>
+            <listitem>
+                <para>
+                     Igual que en JDBC, siempre remplaza valores no constantes con "?". &#x00a1;Nunca uses manipulaci&#x00f3;n
+                     de cadenas para ligar un valor no constante en una consulta! Incluso mejor, considera usar
+                     par&#x00e1;metros con nombre en las consultas.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>No manejes tus propias conexiones JDBC.</term>
+            <listitem>
+                <para>
+                    Hibernate deja a la aplicaci&#x00f3;n administre las conexiones JDBC. Este enfoque debe considerarse
+                    como &#x00fa;ltimo recurso. Si no puedes usar los provedores de conexi&#x00f3;n prefabricados, considera
+                    prover tu propia implementaci&#x00f3;n de <literal>org.hibernate.connection.ConnectionProvider</literal>.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Considera usar un tipo personalizado.</term>
+            <listitem>
+                <para>
+                    Sup&#x00f3;n que tienes un tipo Java, digamos de alguna biblioteca, que necesita hacerse persistente
+                    pero no provee los m&#x00e9;todos de acceso necesarios para mapearlo como un componente. Debes considerar
+                    implementar <literal>org.hibernate.UserType</literal>. Este enfoque libera al c&#x00f3;digo de aplicaci&#x00f3;n
+                    de implementar transformaciones a / desde un tipo Hibernate.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Usa JDBC codificado a mano en cuellos de botella.</term>
+            <listitem>
+                <para>
+                    En &#x00e1;reas del sistema de rendimiento cr&#x00ed;tico, algunos tipos de operaciones podr&#x00ed;an beneficiarse
+                    del JDBC directo. Pero por favor, espero hasta que <emphasis>sepas</emphasis> que algo es
+                    un cuello de botella. Y no asumas que el JDBC directo es necesariamente m&#x00e1;s r&#x00e1;pido. Si necesitas
+                    usar JDBC directo, podr&#x00ed;a ser valioso abrir una <literal>Session</literal> de Hibernate y usar esa
+                    conexi&#x00f3;n JDBC. De esta forma puedes usar a&#x00fa;n la misma estrategia de transacci&#x00f3;n y el mismo
+                    proveedor de conexiones subyacente.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Comprende la limpieza (flushing) de <literal>Session</literal>.</term>
+            <listitem>
+                <para>
+                    De vez en cuando la sesi&#x00f3;n sincroniza su estado persistente con la base de datos. El rendimiento
+                    se ver&#x00e1; afectado si este proceso ocurre demasiado frecuentemente. A veces puedes minimizar
+                    limpieza innecesaria deshabilitando la limpieza autom&#x00e1;tica o incluso cambiando el orden de las
+                    consultas u otras operaciones en una transacci&#x00f3;n en particular.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>En una aplicaci&#x00f3;n en tres gradas, considera usar objetos separados.</term>
+            <listitem>
+                <para>
+                    Al usar una arquitectura de servlet / sesi&#x00f3;n, puedes pasar objetos persistentes en el bean de
+                    sesi&#x00f3;n hacia y desde la capa de servlet / JSP. Usa una sesi&#x00f3;n nueva para atender el servicio de cada
+                    petici&#x00f3;n. Usa <literal>Session.merge()</literal> o <literal>Session.saveOrUpdate()</literal> para
+                    sincronizar los objetos con la base de datos.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>En una arquitectura en dos gradas, considera usar contexto de persistencia largos.</term>
+            <listitem>
+                <para>
+                    Las transacciones de base de datos tienen que ser tan cortas como sea posible. Sin embargo,
+                    frecuentemente es necesario implementar <emphasis>transacciones de aplicaci&#x00f3;n</emphasis>
+                    ejecut&#x00e1;ndose en largo, una sola unidad de trabajo desde el punto de vista de un usuario.
+                    Una transacci&#x00f3;n de aplicaci&#x00f3;n puede abarcar muchos ciclos petici&#x00f3;n/respuesta del cliente.
+                    Es com&#x00fa;n usar objetos separados para implementar transacciones de aplicaci&#x00f3;n. Una alternativa,
+                    extremadamente apropiada en arquitecturas en dos gradas, es mantener un solo contacto de persistencia
+                    abierto (sesi&#x00f3;n) para todo el ciclo de vida de la transacci&#x00f3;n de aplicaci&#x00f3;n y simplemente
+                    desconectar de la conexi&#x00f3;n JDBC al final de cada petici&#x00f3;n, y reconectar al comienzo de la
+                    petici&#x00f3;n subsecuente. Nunca compartas una &#x00fa;nica sesi&#x00f3;n a trav&#x00e9;s de m&#x00e1;s de una transacci&#x00f3;n
+                    de aplicaci&#x00f3;n, o estar&#x00e1;s trabajando con datos añejos.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>No trates la excepciones como recuperables.</term>
+            <listitem>
+                <para>
+                    Esto es m&#x00e1;s una pr&#x00e1;ctica necesaria que una "mejor" pr&#x00e1;ctica. Cuando ocurra una excepci&#x00f3;n,
+                    deshaz (rollback) la <literal>Transaction</literal> y cierra la <literal>Session</literal>.
+                    Si no lo haces, Hibernate no puede garantizar que el estado en memoria representa con exactitud
+                    el estado persistente. Como un caso especial de esto, no uses <literal>Session.load()</literal>
+                    para determinar si una instancia con el identificador dado existe en la base de datos. En cambio,
+                    usa <literal>Session.get()</literal> o una consulta.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Prefiere la recuperaci&#x00f3;n perezosa para las asociaciones.</term>
+            <listitem>
+                <para>
+                    Usa escasamente la recuperaci&#x00f3;n temprana. Usa proxies y colecciones perezosas para la mayor&#x00ed;a
+                    de asociaciones a clases probablemente no est&#x00e9;n mantenidas en el cach&#x00e9; de segundo nivel. Para
+                    las asociaciones a clases en cach&#x00e9;, donde hay una probabilidad de acceso a cach&#x00e9; extremadamente
+                    alta, deshabilita expl&#x00ed;citamente la recuperaci&#x00f3;n temprana usando <literal>lazy="false"</literal>.
+                    Cuando sea apropiada la recuperaci&#x00f3;n por uni&#x00f3;n (join fetching) para un caso de uso en particular,
+                    usa una consulta con un <literal>left join fetch</literal>.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>
+                Usa el patr&#x00f3;n <emphasis>sesi&#x00f3;n abierta en vista</emphasis>, o una <emphasis>fase de ensamblado</emphasis>
+                disciplinada para evitar problemas con datos no recuperados.
+            </term>
+            <listitem>
+                <para>
+                    Hibernate liberal al desarrollador de escribir <emphasis>Objetos de Transferencia de Datos
+                    (Data Transfer Objects)</emphasis> (DTO). En una arquitectura tradicional de EJB, los DTOs tienen
+                    un prop&#x00f3;sito doble: primero, atacan el problema que los beans de entidad no son serializables.
+                    Segundo, definen impl&#x00ed;citamente una fase de ensamblado cuando se recuperan y se forman (marshalling)
+                    todos los datos a usar por la vista en los DTOs antes de devolver el control a la grada de
+                    presentaci&#x00f3;n. Hibernate elimina el primer prop&#x00f3;sito. Sin embargo, a&#x00fa;n necesitas una fase
+                    de ensamblado (piensa en tus m&#x00e9;todos de negocio como si tuviesen un contrato estricto con la grada
+                    de presentaci&#x00f3;n sobre qu&#x00e9; datos est&#x00e1;n disponibles en los objetos separados) a menos que est&#x00e9;s
+                    preparado para tener el contexto de persistencia (la sesi&#x00f3;n) abierto a trav&#x00e9;s del proceso
+                    de renderizaci&#x00f3;n de la vista. &#x00a1;Esta no es una limitaci&#x00f3;n de Hibernate! Es un requerimiento
+                    fundamental de acceso seguro a datos transaccionales.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Considera abstraer tu l&#x00f3;gica de negocio de Hibernate</term>
+            <listitem>
+                <para>
+                    Oculta el c&#x00f3;digo de acceso a datos (Hibernate) detr&#x00e1;s de una interface. Combina los patrones
+                    <emphasis>DAO</emphasis> y <emphasis>Sesi&#x00f3;n de Hebra Local</emphasis>. Incluso puedes tener
+                    algunas clases hechas persistentes por JDBC escrito a mano, asociadas a Hibernate por medio
+                    de un <literal>UserType</literal>. (Este consejo est&#x00e1; pensado para aplicaciones "suficientemente
+                    grandes"; &#x00a1;no es apropiado para una aplicaci&#x00f3;n con cinco tablas!)
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>No uses mapeos de asociaci&#x00f3;n ex&#x00f3;ticos.</term>
+            <listitem>
+                <para>
+                    Son raros los casos de uso de asociaciones reales muchos-a-muchos. La mayor parte del tiempo
+                    necesitas informaci&#x00f3;n adicional almacenada en una "tabla de enlace". En este caso, es mucho
+                    mejor usar dos asociaciones uno-a-muchos a una clase de enlace intermedia. De hecho, pensamos
+                    que la mayor&#x00ed;a de asociaciones son uno-a-muchos y muchos-a-uno, debes ser cuidadoso al usr
+                    cualquier otro estilo de asociaci&#x00f3;n y preguntarte si es realmente necesario.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Prefiere las asociaciones bidireccionales.</term>
+            <listitem>
+                <para>
+                    Las asociaciones unidireccionales son m&#x00e1;s dif&#x00ed;ciles de consultar. En una aplicaci&#x00f3;n grande,
+                    casi todas las asociaciones deben ser navegables en ambas direcciones en consultas.
+                </para>
+            </listitem>
+        </varlistentry>
+    </variablelist>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/collection_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/collection_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/collection_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1241 @@
+<chapter id="collections">
+    <title>Mapeo de Colecciones</title>
+
+    <sect1 id="collections-persistent" revision="3">
+        <title>Colecciones persistentes</title>
+        
+        <para>
+            Hibernate requiere que los campos valuados en colecci&#x00f3;n
+            persistentes sean declarados como un tipo de interface, por ejemplo:
+        </para>
+        
+        <programlisting><![CDATA[public class Product {
+    private String serialNumber;
+    private Set parts = new HashSet();
+    
+    public Set getParts() { return parts; }
+    void setParts(Set parts) { this.parts = parts; }
+    public String getSerialNumber() { return serialNumber; }
+    void setSerialNumber(String sn) { serialNumber = sn; }
+}]]></programlisting>
+        
+        <para>
+            La interface real podr&#x00ed;a ser <literal>java.util.Set</literal>,
+            <literal>java.util.Collection</literal>, <literal>java.util.List</literal>,
+            <literal>java.util.Map</literal>, <literal>java.util.SortedSet</literal>,
+            <literal>java.util.SortedMap</literal> o ... lo que te guste!
+            (Donde "lo que te guste" significa que tendr&#x00e1;s que escribir una
+            implementaci&#x00f3;n de <literal>org.hibernate.usertype.UserCollectionType</literal>.)
+        </para>
+        
+        <para>
+            Nota c&#x00f3;mo hemos inicializado la variable de instancia de
+            <literal>HashSet</literal>. Esta es la mejor forma de inicializar
+            propiedades valuadas en colecci&#x00f3;n de instancias reci&#x00e9;n
+            instanciadas (no persistentes). Cuando haces persistente la instancia
+            - llamando a <literal>persist()</literal>, por ejemplo - Hibernate realmente
+            remplazar&#x00e1; el <literal>HashSet</literal> con una instancia de una
+            implementaci&#x00f3;n de <literal>Set</literal> propia de Hibernate.
+             Observa errores como este:
+        </para>
+        
+        <programlisting><![CDATA[Cat cat = new DomesticCat();
+Cat kitten = new DomesticCat();
+....
+Set kittens = new HashSet();
+kittens.add(kitten);
+cat.setKittens(kittens);
+session.persist(cat);
+kittens = cat.getKittens(); // Okay, kittens collection is a Set
+(HashSet) cat.getKittens(); // Error!]]></programlisting>
+
+        <para>
+            Las colecciones persistentes inyectadas por Hibernate se comportan
+            como <literal>HashMap</literal>, <literal>HashSet</literal>,
+            <literal>TreeMap</literal>, <literal>TreeSet</literal> o
+            <literal>ArrayList</literal>, dependiendo del tipo de interface.
+        </para>
+
+        <para>
+            Las instancias de colecciones tienen el comportamiento usual de tipos de valor.
+            Son autom&#x00e1;ticamente persistidas al ser referenciadas por un objeto
+            persistente y autom&#x00e1;ticamente borradas al desreferenciarse. Si una
+            colecci&#x00f3;n es pasada de un objeto persistente a otro, sus elementos
+            ser&#x00ed;an movidos de una tabla a otra. Dos entidades pueden no
+            compartir una referencia a la misma instancia de colecci&#x00f3;n.
+            Debido al modelo relacional subyacente, las propiedades valuadas en
+            colecci&#x00f3;n no soportan la sem&#x00e1;ntica de valor nulo. Hibernate no
+            distingue entre una referencia de colecci&#x00f3;n nula y una colecci&#x00f3;n
+            vac&#x00ed;a.
+        </para>
+
+        <para>
+            No debes tener que preocuparte demasiado por esto. Usa las colecciones
+            persistentes de la misma forma en que usas colecciones de Java ordinarias.
+            S&#x00f3;lo aseg&#x00fa;rate que entiendes la sem&#x00e1;ntica de las asociaciones
+            bidireccionales (discutida luego).
+        </para>
+
+    </sect1>
+
+    <sect1 id="collections-mapping" revision="2">
+        <title>Mapeos de colecci&#x00f3;n</title>
+
+        <para>
+            El elemento de mapeo de Hibernate usado para mapear una colecci&#x00f3;n
+            depende del tipo de la interface. Por ejemplom un elemento
+            <literal>&lt;set&gt;</literal> se usa para mapear propiedades de tipo
+            <literal>Set</literal>.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Product">
+    <id name="serialNumber" column="productSerialNumber"/>
+    <set name="parts">
+        <key column="productSerialNumber" not-null="true"/>
+        <one-to-many class="Part"/>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Aparte de <literal>&lt;set&gt;</literal>, existen adem&#x00e1;s
+            los elementos de mapeo <literal>&lt;list&gt;</literal>,
+            <literal>&lt;map&gt;</literal>, <literal>&lt;bag&gt;</literal>,
+            <literal>&lt;array&gt;</literal> y <literal>&lt;primitive-array&gt;</literal>.
+            El elemento <literal>&lt;map&gt;</literal> es representativo:
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="mappingcollection1" coords="2 65"/>
+                <area id="mappingcollection2" coords="3 65"/>
+                <area id="mappingcollection3" coords="4 65"/>
+                <area id="mappingcollection4" coords="5 65"/>
+                <area id="mappingcollection5" coords="6 65"/>
+                <area id="mappingcollection6" coords="7 65"/>
+                <area id="mappingcollection7" coords="8 65"/>
+                <area id="mappingcollection8" coords="9 65"/>
+                <area id="mappingcollection9" coords="10 65"/>
+                <area id="mappingcollection10" coords="11 65"/>
+                <area id="mappingcollection11" coords="12 65"/>
+                <area id="mappingcollection12" coords="13 65"/>
+                <area id="mappingcollection13" coords="14 65"/>
+            </areaspec>
+            <programlisting><![CDATA[<map
+    name="propertyName"
+    table="table_name"
+    schema="schema_name"
+    lazy="true|false"
+    inverse="true|false"
+    cascade="all|none|save-update|delete|all-delete-orphan"
+    sort="unsorted|natural|comparatorClass"
+    order-by="column_name asc|desc"
+    where="arbitrary sql where condition"
+    fetch="join|select|subselect"
+    batch-size="N"
+    access="field|property|ClassName"
+    optimistic-lock="true|false"
+    node="element-name|."
+    embed-xml="true|false"
+>
+
+    <key .... />
+    <map-key .... />
+    <element .... />
+</map>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="mappingcollection1">
+                    <para>
+                        <literal>name</literal> el nombre de la propiedad de colecci&#x00f3;n
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection2">
+                    <para>
+                        <literal>table</literal> (opcional - por defecto al nombre de la propiedad)
+                        el nombre de la tabla de colecii&#x00f3;n (no usado para asociaciones
+                        uno-a-muchos)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection3">
+                    <para>
+                        <literal>schema</literal> (opcional) el nombre de un esquema de tablas
+                        para sobrescribir el esquema declarado en el elemento ra&#x00ed;z
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection4">
+                    <para>
+                        <literal>lazy</literal> (opcional - por defecto a <literal>true</literal>)
+                        puede ser usado para deshabilitar la recuperaci&#x00f3;n perezosa y
+                        especificar que la asociaci&#x00f3;n es siempre recuperada tempranamente
+                        (no disponible para arrays)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection5">
+                    <para>
+                        <literal>inverse</literal> (opcional - por defecto a <literal>false</literal>)
+                        marca esta colecci&#x00f3;n como el extremo "inverso" de una asociaci&#x00f3;n
+                        bidireccional.
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection6">
+                    <para>
+                        <literal>cascade</literal> (opcional - por defecto a <literal>none</literal>)
+                        habilita operaciones en cascada a entidades hijas
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection7">
+                    <para>
+                        <literal>sort</literal> (opcional) especifica una colecci&#x00f3;n
+                        con ordenamiento <literal>natural</literal>, o una clase comparadora
+                        dada
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection8">
+                    <para>
+                        <literal>order-by</literal> (opcional, s&#x00f3;lo JDK1.4) especifica una columna
+                        de tabla (o columnas) que definen el orden de iteraci&#x00f3;n del
+                        <literal>Map</literal>, <literal>Set</literal> o bag, junto a un
+                        <literal>asc</literal> o <literal>desc</literal> opcional.
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection9">
+                    <para>
+                        <literal>where</literal> (opcional) especifica una condici&#x00f3;n
+                        <literal>WHERE</literal> de SQL arbitrario para ser usada al recuperar o
+                        quitar la colecci&#x00f3;n (&#x00fa;til si la colecci&#x00f3;n debe
+                        contener s&#x00f3;lo un subconjunto de los datos disponibles)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection10">
+                    <para>
+                        <literal>fetch</literal> (opcional, por defecto a <literal>select</literal>)
+                        Elige entre recuperaci&#x00f3;n por uni&#x00f3;n externa (outer-join),
+                        recuperar por selecci&#x00f3;n secuencial, y recuperaci&#x00f3;n por
+                        subselecci&#x00f3;n secuencial.
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection11">
+                    <para>
+                        <literal>batch-size</literal> (opcional, por defecto a <literal>1</literal>)
+                        especifica un "tama&#x00f1;o de lote" para la recuperar
+                        perezosamente instancias de esta colecci&#x00f3;n.
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection12">
+                    <para>
+                        <literal>access</literal> (opcional - por defecto a <literal>property</literal>):
+                        La estrategia que debe usar Hibernate para acceder al valor de la
+                        propiedad.
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection12">
+                    <para>
+                        <literal>optimistic-lock</literal> (opcional - por defecto a <literal>true</literal>):
+                        Especifica que los cambios de estado de la colecci&#x00f3;n resultan en
+                        incrementos de versi&#x00f3;n de la entidad due&#x00f1;a. (Para asociaciones
+                        uno a muchos, frecuentemente es razonable deshabilitar esta opci&#x00f3;n.)
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <sect2 id="collections-foreignkeys" >
+           <title>Claves for&#x00e1;neas de collecci&#x00f3;n</title>
+    
+            <para>
+                Las instancias de colecci&#x00f3;n se distinguen en la base de datos por la
+                clave for&#x00e1;nea de la entidad que posee la colecci&#x00f3;n. Se hace
+                referencia a esta clave for&#x00e1;nea como la <emphasis>columna clave de
+                colecci&#x00f3;n</emphasis> (o columnas) de la tabla de colecci&#x00f3;n.
+                La columna clave de la colecci&#x00f3;n es mapeada por el elemento
+                <literal>&lt;key&gt;</literal>.
+            </para>
+    
+            <para>
+                Puede haber una restricci&#x00f3;n de nulabilidad sobre la columna de clave
+                for&#x00e1;nea. Para la mayor&#x00ed;a de colecciones, esto est&#x00e1; implicado.
+                Para asociaciones unidireccionales uno a muchos, la columna de clave
+                for&#x00e1;nea es nulable por defecto, de modo que podr&#x00ed;as necesitar
+                especificar <literal>not-null="true"</literal>.
+            </para>
+    
+            <programlisting><![CDATA[<key column="productSerialNumber" not-null="true"/>]]></programlisting>
+    
+            <para>
+                La restricci&#x00f3;n de clave for&#x00e1;nea puede usar
+                <literal>ON DELETE CASCADE</literal>.
+            </para>
+    
+            <programlisting><![CDATA[<key column="productSerialNumber" on-delete="cascade"/>]]></programlisting>
+            
+            <para>
+                Mira el cap&#x00ed;tulo anterior por una definici&#x00f3;n completa del
+                elemento <literal>&lt;key&gt;</literal>.
+            </para>
+            
+        </sect2>
+        
+        <sect2 id="collections-elements" >
+            <title>Elementos de collecci&#x00f3;n</title>
+    
+            <para>
+                Las colecciones pueden contener casi cualquier tipo de Hibernate, incluyendo
+                todos los tipos b&#x00e1;sicos, componentes, y por supuesto, referencias a otras
+                entidades. Esta es una distinci&#x00f3;n importante: un objeto en una colecci&#x00f3;n
+                puede ser manejado con una sem&#x00e1;ntica de "valor" (su ciclo de vida depende
+                completamente del propietario de la colecci&#x00f3;n) o podr&#x00ed;a ser una referencia
+                a otra entidad, con su propio ciclo de vida. En el &#x00fa;ltimo caso, s&#x00f3;lo
+                el estado del "enlace" entre los dos objetos se considera mantenido por la
+                colecci&#x00f3;n.
+            </para>
+                
+            <para>
+                Se hace referencia al tipo contenido como el <emphasis>tipo de elemento
+                de la colecci&#x00f3;n</emphasis>. Los elementos de colecci&#x00f3;n son
+                mapeados por <literal>&lt;element&gt;</literal> o
+                <literal>&lt;composite-element&gt;</literal>, o en el caso de referencias
+                de entidades, con <literal>&lt;one-to-many&gt;</literal> o
+                <literal>&lt;many-to-many&gt;</literal>. Las dos primeras mapean elementos
+                con sem&#x00e1;ntica de valor, los dos siguientes son usados para mapear
+                asociaciones de entidades.
+            </para>
+            
+        </sect2>
+        
+        <sect2 id="collections-indexed">
+            <title>Colecciones indexadas</title>
+    
+            <para>
+                Todos los mapeos de colecci&#x00f3;n, excepto aquellos con sem&#x00e1;ntica de
+                set o bag, necesitan una <emphasis>columna &#x00ed;ndice</emphasis> en la tabla
+                de colecci&#x00f3;n, una columna que mapea a un &#x00ed;ndice de array, o
+                &#x00ed;ndice de <literal>List</literal>, o clave de <literal>Map</literal>.
+                El &#x00ed;ndice de un <literal>Map</literal> puede ser de cualquier tipo
+                b&#x00e1;sico, mapeado con <literal>&lt;map-key&gt;</literal>, o puede ser
+                una referencia de entidad, mapeada con <literal>&lt;map-key-many-to-many&gt;</literal>,
+                o puede ser un tipo compuesto, mapeado con <literal>&lt;composite-map-key&gt;</literal>.
+                El &#x00ed;ndice de un array o lista es siempre de tipo <literal>integer</literal>
+                y se mapea usando el elemento <literal>&lt;list-index&gt;</literal>. La columna
+                mapeada contiene enteros secuenciales (numerados desde cero, por defecto).
+            </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="index1" coords="2 45"/>
+                <area id="index2" coords="3 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<list-index 
+        column="column_name"
+        base="0|1|..."/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="index1">
+                    <para>
+                        <literal>column_name</literal> (requerido): El nombre de la columna que tiene
+                        los valores &#x00ed;ndice de la colecci&#x00f3;n.
+                    </para>
+                </callout>
+                <callout arearefs="index1">
+                    <para>
+                        <literal>base</literal> (opcional, por defecto a <literal>0</literal>): El valor
+                        de la columna &#x00ed;ndice que corresponde al primer elemento de la lista o
+                        array.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <programlistingco>
+            <areaspec>
+                <area id="mapkey1" coords="2 45"/>
+                <area id="mapkey2" coords="3 45"/>
+                <area id="mapkey3" coords="4 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<map-key 
+        column="column_name"
+        formula="any SQL expression"
+        type="type_name"
+        node="@attribute-name"
+        length="N"/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="mapkey1">
+                    <para>
+                        <literal>column</literal> (opcional): El nombre de la columna que tiene
+                        los valores &#x00ed;ndice de la colecci&#x00f3;n.
+                    </para>
+                </callout>
+                <callout arearefs="mapkey2">
+                    <para>
+                        <literal>formula</literal> (opcional): Una f&#x00f3;rmula SQL usada para
+                        evaluar la clave del mapa.
+                    </para>
+                </callout>
+                <callout arearefs="mapkey3">
+                    <para>
+                        <literal>type</literal> (requerido): el tipo de las claves del mapa.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <programlistingco>
+            <areaspec>
+                <area id="indexmanytomany1" coords="2 45"/>
+                <area id="indexmanytomany2" coords="3 45"/>
+                <area id="indexmanytomany3" coords="3 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<map-key-many-to-many
+        column="column_name"
+        formula="any SQL expression"
+        class="ClassName"
+/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="indexmanytomany1">
+                    <para>
+                        <literal>column</literal> (opcional): El nombre de la columna clave
+                        for&#x00e1;nea para los valores &#x00ed;ndice de la colecci&#x00f3;n.
+                    </para>
+                </callout>
+                <callout arearefs="indexmanytomany2">
+                    <para>
+                        <literal>formula</literal> (opcional): Una f&#x00f3;rmula SQL usada para
+                        evaluar la clave for&#x00e1;nea de la clave del mapa.
+                    </para>
+                </callout>
+                <callout arearefs="indexmanytomany3">
+                    <para>
+                        <literal>class</literal> (requerido): La clase de entidad usada como clave del mapa.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+
+            <para>
+                Si tu tabla no tiene una columna &#x00ed;ndice, y deseas a&#x00fa;n usar <literal>List</literal> como
+                tipo de propiedad, debes mapear la propiedad como un <emphasis>&lt;bag&gt;</emphasis>
+                de Hibernate. Un bag (bolsa) no retiene su orden al ser recuperado de la base de datos,
+                pero puede ser ordenado o clasificado opcionalmente.
+            </para>
+            
+        </sect2>
+
+        <para>
+            Hay absolutamente un rango de mapeos que pueden ser generados para colecciones,
+            cubriendo muchos modelos relacionales comunes. Te sugerimos que experimentes con
+            la herramienta de generaci&#x00f3;n de esquemas para obtener una idea de c&#x00f3;mo varias
+            declaraciones de mapeo se traducen a tablas de base de datos.
+        </para>
+
+    <sect2 id="collections-ofvalues" revision="1">
+        <title>Colecciones de valores y asociaciones muchos-a-muchos</title>
+
+        <para>
+            Cualquier colecci&#x00f3;n de valores o asociaci&#x00f3;n muchos a muchos requiere una
+            <emphasis>tabla de colecci&#x00f3;n</emphasis> dedicada con una columna o columnas
+            de clave for&#x00e1;nea, <emphasis>columna de elemento de colecci&#x00f3;n</emphasis> o
+            columnas y posiblemente una columna o columnas &#x00ed;ndice.
+        </para>
+
+        <para>
+            Para una colecci&#x00f3;n de valores, usamos la etiqueta <literal>&lt;element&gt;</literal>.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="element1b" coords="2 50"/>
+                <area id="element2b" coords="3 50"/>
+                <area id="element3b" coords="4 50"/>
+             </areaspec>
+            <programlisting><![CDATA[<element
+        column="column_name"
+        formula="any SQL expression"
+        type="typename"
+        length="L"
+        precision="P"
+        scale="S"
+        not-null="true|false"
+        unique="true|false"
+        node="element-name"
+/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="element1b">
+                    <para>
+                        <literal>column</literal> (opcional): El nombre de la columna que tiene
+                        los valores de los elementos de la colecci&#x00f3;n.
+                    </para>
+                </callout>
+                <callout arearefs="element2b">
+                    <para>
+                        <literal>formula</literal> (opcional): Una f&#x00f3;rmula SQL usada para evaluar
+                        el elemento.
+                    </para>
+                </callout>
+                <callout arearefs="element3b">
+                    <para>
+                        <literal>type</literal> (requerido): El tipo del elemento de colecci&#x00f3;n.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <para>
+            Una <emphasis>asociaci&#x00f3;n muchos-a-muchos</emphasis> se especifica usando
+            el elemento <literal>&lt;many-to-many&gt;</literal>.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="manytomany1" coords="2 60"/>
+                <area id="manytomany2" coords="3 60"/>
+                <area id="manytomany3" coords="4 60"/>
+                <area id="manytomany4" coords="5 60"/>
+                <area id="manytomany5" coords="6 60"/>
+                <area id="manytomany6" coords="7 60"/>
+                <area id="manytomany7" coords="8 60"/>
+            </areaspec>
+            <programlisting><![CDATA[<many-to-many
+        column="column_name"
+        formula="any SQL expression"
+        class="ClassName"
+        fetch="select|join"
+        unique="true|false"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        node="element-name"
+        embed-xml="true|false"
+    />]]></programlisting>
+            <calloutlist>
+                <callout arearefs="manytomany1">
+                    <para>
+                        <literal>column</literal> (opcional): El nombre de la columna de clave
+                        for&#x00e1;nea del elemento.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany2">
+                    <para>
+                        <literal>formula</literal> (opcional): Una f&#x00f3;rmula SQL opcional usada
+                        para evaluar el valor de clave for&#x00e1;nea del elemento.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany3">
+                    <para>
+                        <literal>class</literal> (requerido): El nombre de la clase asociada.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany4">
+                    <para>
+                        <literal>fetch</literal> (opcional - por defecto a <literal>join</literal>):
+                        habilita la recuperaci&#x00f3;n por uni&#x00f3;n externa o selecci&#x00f3;n secuencial para esta
+                        asociaci&#x00f3;n. Este es un caso especial; para una recuperaci&#x00f3;n completamente
+                        temprana (en un solo <literal>SELECT</literal>) de una entidad y sus relaciones
+                        muchos-a-muchos a otras entidades, deber&#x00ed;as habilitar la recuperaci&#x00f3;n
+                        <literal>join</literal> no s&#x00f3;lo de la colecci&#x00f3;n misma, sino tambi&#x00e9;n con este
+                        atributo en el elemento anidado <literal>&lt;many-to-many&gt;</literal>.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany5">
+                    <para>
+                        <literal>unique</literal> (opcional): Habilita la generaci&#x00f3;n DDL de una
+                        restricci&#x00f3;n de unicidad para la columna clave for&#x00e1;nea. Esto hace la
+                        multiplicidad de la asociaci&#x00f3;n efectivamente uno a muchos.
+                    </para>
+                </callout>
+	            <callout arearefs="manytomany6">
+	                <para>
+	                    <literal>not-found</literal> (opcional - por defecto a <literal>exception</literal>): 
+                            Especifica c&#x00f3;mo ser&#x00e1;n manejadas las claves for&#x00e1;neas que referencian
+                            filas perdidas: <literal>ignore</literal> tratar&#x00e1; una fila perdida como
+                            una asociaci&#x00f3;n nula.
+	                </para>
+	            </callout>
+                <callout arearefs="manytomany7">
+                    <para>
+                        <literal>entity-name</literal> (opcional): El nombre de entidad de la clase
+                        asociada, como una alternativa a <literal>class</literal>.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <para>
+            Algunos ejemplos, primero, un conjunto de cadenas:
+        </para>
+
+        <programlisting><![CDATA[<set name="names" table="person_names">
+    <key column="person_id"/>
+    <element column="person_name" type="string"/>
+</set>]]></programlisting>
+
+        <para>
+            Un bag conteniendo enteros (con un orden de iteraci&#x00f3;n determinado por el
+            atributo <literal>order-by</literal>):
+        </para>
+
+        <programlisting><![CDATA[<bag name="sizes" 
+        table="item_sizes" 
+        order-by="size asc">
+    <key column="item_id"/>
+    <element column="size" type="integer"/>
+</bag>]]></programlisting>
+
+        <para>
+            Un array de entidades - en este caso, una asociaci&#x00f3;n muchos a muchos:
+        </para>
+
+        <programlisting><![CDATA[<array name="addresses" 
+        table="PersonAddress" 
+        cascade="persist">
+    <key column="personId"/>
+    <list-index column="sortOrder"/>
+    <many-to-many column="addressId" class="Address"/>
+</array>]]></programlisting>
+
+        <para>
+            Un mapa de &#x00ed;ndices de cadenas a fechas:
+        </para>
+
+        <programlisting><![CDATA[<map name="holidays" 
+        table="holidays" 
+        schema="dbo" 
+        order-by="hol_name asc">
+    <key column="id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            Una lista de componentes (discutidos en el pr&#x00f3;ximo cap&#x00ed;tulo):
+        </para>
+
+        <programlisting><![CDATA[<list name="carComponents" 
+        table="CarComponents">
+    <key column="carId"/>
+    <list-index column="sortOrder"/>
+    <composite-element class="CarComponent">
+        <property name="price"/>
+        <property name="type"/>
+        <property name="serialNumber" column="serialNum"/>
+    </composite-element>
+</list>]]></programlisting>
+
+    </sect2>
+
+    <sect2 id="collections-onetomany">
+        <title>Asociaciones uno-a-muchos</title>
+
+        <para>
+            Una <emphasis>asociaci&#x00f3;n uno a muchos</emphasis> enlaza las tablas de dos clases
+            por medio de una clave for&#x00e1;nea, sin intervenci&#x00f3;n de tabla de colecci&#x00f3;n alguna.
+            Este mapeo pierde cierta sem&#x00e1;ntica de colecciones Java normales:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Una instancia de la clase entidad contenida no puede pertenecer
+                    a m&#x00e1;s de una instancia de la colecci&#x00f3;n.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Una instancia de la clase entidad contenida no puede aparecer en m&#x00e1;s
+                    de un valor del &#x00ed;ndice de colecci&#x00f3;n.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Una asociaci&#x00f3;n de <literal>Product</literal> a <literal>Part</literal> requiere la
+            existencia de una columna clave for&#x00e1;nea y posiblemente una columna &#x00ed;ndice a la tabla
+            <literal>Part</literal>. Una etiqueta <literal>&lt;one-to-many&gt;</literal> indica
+            que &#x00e9;sta es una asociaci&#x00f3;n uno a muchos.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="onetomany1" coords="2 60"/>
+                <area id="onetomany2" coords="3 60"/>
+                <area id="onetomany3" coords="4 60"/>
+            </areaspec>
+            <programlisting><![CDATA[<one-to-many 
+        class="ClassName"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        node="element-name"
+        embed-xml="true|false"
+    />]]></programlisting>
+            <calloutlist>
+                <callout arearefs="onetomany1">
+                    <para>
+                        <literal>class</literal> (requerido): El nombre de la clase asociada.
+                    </para>
+                </callout>
+		        <callout arearefs="onetomany2">
+		            <para>
+		                <literal>not-found</literal> (opcional - por defecto a <literal>exception</literal>): 
+                                Especifica c&#x00f3;mo ser&#x00e1;n manejados los identificadores en cach&#x00e9; que referencien
+                                filas perdidas: <literal>ignore</literal> tratar&#x00e1; una fila perdida como una
+                                asociaci&#x00f3;n nula.
+		            </para>
+		        </callout>
+                <callout arearefs="onetomany3">
+                    <para>
+                        <literal>entity-name</literal> (opcional): El nombre de entidad de la clase
+                        asociada, como una alternativa a <literal>class</literal>.
+                    </para>
+                </callout>
+            </calloutlist>
+       </programlistingco>
+  
+        <para>
+            Observa que el elemento <literal>&lt;one-to-many&gt;</literal> no necesita
+            declarar ninguna columna. Ni es necesario especificar el nombre de <literal>table</literal>
+            en ning&#x00fa;n sitio.
+        </para>
+
+        <para>
+            <emphasis>Nota muy importante:</emphasis> Si la columna clave for&#x00e1;nea de una asociaci&#x00f3;n
+            <literal>&lt;one-to-many&gt;</literal> es declarada <literal>NOT NULL</literal>, debes
+            declarar el mapeo de <literal>&lt;key&gt;</literal> <literal>not-null="true"</literal>
+            o <emphasis>usar una asociaci&#x00f3;n bidireccional</emphasis> con el mapeo de colecci&#x00f3;n
+            marcado <literal>inverse="true"</literal>. Ver la discusi&#x00f3;n sobre asociaciones
+            bidireccionales m&#x00e1;s adelante en este cap&#x00ed;tulo.
+        </para>
+        
+        <para>
+            Este ejemplo muestra un mapa de entidades <literal>Part</literal> por nombre
+            (donde <literal>partName</literal> es una propiedad persistente de <literal>Part</literal>).
+            Observa el uso de un &#x00ed;ndice basado en f&#x00f3;rmula.
+        </para>
+
+        <programlisting><![CDATA[<map name="parts"
+        cascade="all">
+    <key column="productId" not-null="true"/>
+    <map-key formula="partName"/>
+    <one-to-many class="Part"/>
+</map>]]></programlisting>
+    </sect2>
+    
+    </sect1>
+
+    <sect1 id="collections-advancedmappings">
+        <title>Mapeos de colecci&#x00f3;n avanzados</title>
+
+    <sect2 id="collections-sorted" revision="2">
+        <title>Colecciones ordenadas</title>
+
+        <para>
+            Hibernate soporta colecciones implementando <literal>java.util.SortedMap</literal> y
+            <literal>java.util.SortedSet</literal>. Debes especificar un comparador en el fichero de
+            mapeo:
+        </para>
+
+        <programlisting><![CDATA[<set name="aliases" 
+            table="person_aliases" 
+            sort="natural">
+    <key column="person"/>
+    <element column="name" type="string"/>
+</set>
+
+<map name="holidays" sort="my.custom.HolidayComparator">
+    <key column="year_id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            Los valores permitidos del atributo <literal>sort</literal> son <literal>unsorted</literal>,
+            <literal>natural</literal> y el nombre de una clase que implemente
+            <literal>java.util.Comparator</literal>.
+        </para>
+
+        <para>
+            Las colecciones ordenadas realmente se comportan como <literal>java.util.TreeSet</literal> o
+            <literal>java.util.TreeMap</literal>.
+        </para>
+
+        <para>
+            Si quieres que la misma base de datos ordene los elementos de colecci&#x00f3;n usa el
+            atributo <literal>order-by</literal> de los mapeos <literal>set</literal>,
+            <literal>bag</literal> o <literal>map</literal>. Esta soluci&#x00f3;n est&#x00e1; disponible s&#x00f3;lo
+            bajo el JDK 1.4 o superior (est&#x00e1; implementado usando <literal>LinkedHashSet</literal> o
+            <literal>LinkedHashMap</literal>). Esto realiza la ordenaci&#x00f3;n en la consulta SQL,
+            no en memoria.
+        </para>
+
+        <programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="lower(name) asc">
+    <key column="person"/>
+    <element column="name" type="string"/>
+</set>
+
+<map name="holidays" order-by="hol_date, hol_name">
+    <key column="year_id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            Observa que el valor del atributo <literal>order-by</literal> es una ordenaci&#x00f3;n SQL, no
+            una ordenaci&#x00f3;n HQL!
+        </para>
+
+        <para>
+            Las asociaciones pueden incluso ser ordenadas por alg&#x00fa;n criterio arbitrario en tiempo de
+            ejecuci&#x00f3;n usando un <literal>filter()</literal> de colecci&#x00f3;n.
+        </para>
+
+        <programlisting><![CDATA[sortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list();]]></programlisting>
+
+    </sect2>
+
+     <sect2 id="collections-bidirectional" revision="1">
+        <title>Asociaciones bidireccionales</title>
+
+        <para>
+            Una <emphasis>asociaci&#x00f3;n bidireccional</emphasis> permite la nevegaci&#x00f3;n desde
+            ambos "extremos" de la asociaci&#x00f3;n. Son soportados dos tipos de asociaci&#x00f3;n
+            bidireccional:
+
+            <variablelist>
+                <varlistentry>
+                    <term>uno-a-muchos</term>
+                    <listitem>
+                        <para>
+                            set o bag valorados en un extremo, monovaluados al otro
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>muchos-a-muchos</term>
+                    <listitem>
+                        <para>
+                            set o bag valorados a ambos extremos
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+        </para>
+
+        <para>
+            Puedes especificar una asociaci&#x00f3;n bidireccional muchos-a-muchos simplemente
+            mapeando dos asociaciones muchos-a-muchos a la misma tabla de base de datos
+            y declarando un extremo como <emphasis>inverse</emphasis> (cu&#x00e1;l de ellos es tu
+            elecci&#x00f3;n, pero no puede ser una colecci&#x00f3;n indexada).
+        </para>
+
+        <para>
+            He aqu&#x00ed; un ejemplo de una asociaci&#x00f3;n bidireccional muchos-a-muchos; cada categor&#x00ed;a
+            puede tener muchos &#x00ed;tems y cada &#x00ed;tem puede estar en muchas categor&#x00ed;as:
+        </para>
+
+        <programlisting><![CDATA[<class name="Category">
+    <id name="id" column="CATEGORY_ID"/>
+    ...
+    <bag name="items" table="CATEGORY_ITEM">
+        <key column="CATEGORY_ID"/>
+        <many-to-many class="Item" column="ITEM_ID"/>
+    </bag>
+</class>
+
+<class name="Item">
+    <id name="id" column="CATEGORY_ID"/>
+    ...
+
+    <!-- inverse end -->
+    <bag name="categories" table="CATEGORY_ITEM" inverse="true">
+        <key column="ITEM_ID"/>
+        <many-to-many class="Category" column="CATEGORY_ID"/>
+    </bag>
+</class>]]></programlisting>
+
+        <para>
+            Los cambios hechos s&#x00f3;lo al extremo inverso de la asociaci&#x00f3;n <emphasis>no</emphasis>
+            son persistidos. Esto significa que Hibernate tiene dos representaciones en memoria
+            para cada asociaci&#x00f3;n bidireccional, una enlaza de A a B y otra enlaza de B a A.
+            Esto es m&#x00e1;s f&#x00e1;cil de entender si piensas en el modelo de objetos de Java y c&#x00f3;mo
+            creamos una relaci&#x00f3;n muchos-a-muchos en Java:
+        </para>
+
+        <programlisting><![CDATA[
+category.getItems().add(item);          // The category now "knows" about the relationship
+item.getCategories().add(category);     // The item now "knows" about the relationship
+
+session.persist(item);                   // The relationship won't be saved!
+session.persist(category);               // The relationship will be saved]]></programlisting>
+
+        <para>
+            El lado no-inverso se usa para salvar la representaci&#x00f3;n en memoria a la base de datos.
+        </para>
+
+        <para>
+            Puedes definir una asociaci&#x00f3;n bidireccional uno-a-muchos mapeando una asociaci&#x00f3;n uno-a-muchos
+            a la misma columna (o columnas) de tabla como una asociaci&#x00f3;n muchos-a-uno y declarando el
+            extremo multivaluado <literal>inverse="true"</literal>.
+        </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <set name="children" inverse="true">
+        <key column="parent_id"/>
+        <one-to-many class="Child"/>
+    </set>
+</class>
+
+<class name="eg.Child">
+    <id name="id" column="id"/>
+    ....
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        not-null="true"/>
+</class>]]></programlisting>
+
+        <para>
+            Mapear un extremo de una asociaci&#x00f3;n con <literal>inverse="true"</literal> no afecta
+            la operaci&#x00f3;n de cascadas; &#x00e9;stos son conceptos ortogonales!
+        </para>
+
+    </sect2>
+
+    <sect2 id="collections-indexedbidirectional">
+        <title>Asociaciones bidireccionales con colecciones indexadas</title>
+        <para>
+            Requiere especial consideraci&#x00f3;n una asociaci&#x00f3;n bidireccional donde un extremo est&#x00e9; representado
+            como una <literal>&lt;list&gt;</literal> o <literal>&lt;map&gt;</literal>. Si hay una propiedad
+            de la clase hija que mapee a la columna &#x00ed;ndice, no hay problema, podemos seguir usando
+            <literal>inverse="true"</literal> en el mapeo de la colecci&#x00f3;n:
+        </para>
+        
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <map name="children" inverse="true">
+        <key column="parent_id"/>
+        <map-key column="name" 
+            type="string"/>
+        <one-to-many class="Child"/>
+    </map>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <property name="name" 
+        not-null="true"/>
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        not-null="true"/>
+</class>]]></programlisting>
+
+        <para>
+            Pero, si no existe tal proiedad en la clase hija, no podemos pensar en la asociaci&#x00f3;n como
+            verdaderamente bidireccional (hay informaci&#x00f3;n en un extremo de la asociaci&#x00f3;n que no est&#x00e1;
+            disponible en el otro extremo). En este caso, no podemos mapear la colecci&#x00f3;n con
+            <literal>inverse="true"</literal>. En cambio, podr&#x00ed;amos usar el siguiente mapeo:
+        </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <map name="children">
+        <key column="parent_id"
+            not-null="true"/>
+        <map-key column="name" 
+            type="string"/>
+        <one-to-many class="Child"/>
+    </map>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        insert="false"
+        update="false"
+        not-null="true"/>
+</class>]]></programlisting>
+
+       <para>
+           Nota que, en este mapeo, el extremo de la asociaci&#x00f3;n valuado en colecci&#x00f3;n es responsable de las
+           actualizaciones a la clave for&#x00e1;nea.
+       </para>
+
+    </sect2>
+
+    <sect2 id="collections-ternary">
+        <title>Asociaciones ternarias</title>
+
+        <para>
+            Hay tres enfoques posibles para mapear una asociaci&#x00f3;n ternaria.
+            Una es usar un <literal>Map</literal> con una asociaci&#x00f3;n como su &#x00ed;ndice:
+        </para>
+
+        <programlisting><![CDATA[<map name="contracts">
+    <key column="employer_id" not-null="true"/>
+    <map-key-many-to-many column="employee_id" class="Employee"/>
+    <one-to-many class="Contract"/>
+</map>]]></programlisting>
+            
+            <programlisting><![CDATA[<map name="connections">
+    <key column="incoming_node_id"/>
+    <map-key-many-to-many column="outgoing_node_id" class="Node"/>
+    <many-to-many column="connection_id" class="Connection"/>
+</map>]]></programlisting>
+            
+        <para>
+            Un segundo enfoque es simplemente remodelar la asociaci&#x00f3;n como una clase de entidad.
+            Este es el enfoque que usamos m&#x00e1;s comunmente.
+        </para>
+        
+        <para>
+            Una alternativa final es usar elementos compuestos, que discutiremos m&#x00e1;s adelante.
+        </para>
+        
+    </sect2>
+    
+    <sect2 id="collections-idbag" revision="1">
+        <title><literal>Usando un &lt;idbag&gt;</literal></title>
+
+        <para>
+            Si has adoptado completamente nuestra visi&#x00f3;n de que las claves compuestas son una
+            cosa mala y que las entidades deben tener identificadores sit&#x00e9;ticos (claves delegadas),
+            entonces podr&#x00ed;as encontrar un poco raro que todas las asociaciones muchos a muchos y
+            las colecciones de valores que hemos mostrado hasta ahora mapeen a tablas con claves
+            compuestas! Ahora, este punto es discutible; una tabla de pura asociaci&#x00f3;n no parece
+            beneficiarse demasiado de una clave delegada (aunque s&#x00ed; <emphasis>podr&#x00ed;a</emphasis> una
+            colecci&#x00f3;n de valores compuestos). Sin embargo, Hibernate provee una funcionalidad que
+            te permite mapear asociaciones muchos a muchos y colecciones de valores a una tabla con
+            una clave delegada.
+        </para>
+
+        <para>
+            El elemento <literal>&lt;idbag&gt;</literal> te permite mapear una <literal>List</literal>
+            (o <literal>Collection</literal>) con sem&#x00e1;ntica de bag.
+        </para>
+
+<programlisting><![CDATA[<idbag name="lovers" table="LOVERS">
+    <collection-id column="ID" type="long">
+        <generator class="sequence"/>
+    </collection-id>
+    <key column="PERSON1"/>
+    <many-to-many column="PERSON2" class="Person" fetch="join"/>
+</idbag>]]></programlisting>
+
+        <para>
+            Como puedes ver, un <literal>&lt;idbag&gt;</literal> tiene un generador de id sint&#x00e9;tico,
+            igual que una clase de entidad! Una clave delegada diferente se asigna a cada fila
+            de la colecci&#x00f3;n. Hibernate no provee ning&#x00fa;n mecanismo para descubrir el valor de clave
+            delegada de una fila en particular, sin embargo.
+        </para>
+
+        <para>
+            Observa que el rendimiento de actualizaci&#x00f3;n de un <literal>&lt;idbag&gt;</literal> es
+            <emphasis>mucho</emphasis> mejor que el de un <literal>&lt;bag&gt;</literal> regular!
+            Hibernate puede localizar filas individuales eficientemente y actualizarlas o borrarlas
+            individualmente, igual que si fuese una lista, mapa o conjunto.
+        </para>
+
+        <para>
+            En la implementaci&#x00f3;n actual, la estrategia de generaci&#x00f3;n de identificador
+            <literal>native</literal> no est&#x00e1; soportada para identificadores de colecciones
+            <literal>&lt;idbag&gt;</literal>.
+        </para>
+
+    </sect2>
+
+    </sect1>
+    
+    <!--undocumenting this stuff -->
+    
+    <!--sect1 id="collections-heterogeneous">
+        <title>Heterogeneous Associations</title>
+
+        <para>
+            The <literal>&lt;many-to-any&gt;</literal> and <literal>&lt;index-many-to-any&gt;</literal>
+            elements provide for true heterogeneous associations. These mapping elements work in the
+            same way as the <literal>&lt;any&gt;</literal> element - and should also be used
+            rarely, if ever.
+        </para>
+
+    </sect1-->
+
+    <sect1 id="collections-example" revision="1">
+        <title>Ejemplos de colecci&#x00f3;n</title>
+
+        <para>
+            Las secciones previas son bastantes confusas. As&#x00ed; que miremos un ejemplo.
+            Esta clase:
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+
+public class Parent {
+    private long id;
+    private Set children;
+
+    public long getId() { return id; }
+    private void setId(long id) { this.id=id; }
+
+    private Set getChildren() { return children; }
+    private void setChildren(Set children) { this.children=children; }
+
+    ....
+    ....
+}]]></programlisting>
+
+        <para>
+            tiene una colecci&#x00f3;n de instancias de <literal>Child</literal>.
+            Si cada hijo tiene como mucho un padre, el mapeo m&#x00e1;s natural es
+            una asociaci&#x00f3;n uno-a-muchos:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children">
+            <key column="parent_id"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Esto mapea a las siguientes definiciones de tablas:
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255), parent_id bigint )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+        <para>
+            Si el padre es <emphasis>requerido</emphasis>, usa una asociaci&#x00f3;n bidireccional
+            uno-a-muchos:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children" inverse="true">
+            <key column="parent_id"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+        <many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Observa la restricci&#x00f3;n <literal>NOT NULL</literal>:
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null
+                     primary key,
+                     name varchar(255),
+                     parent_id bigint not null )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+        <para>
+            Alternativamente, si absolutamente insistes que esta asociaci&#x00f3;n debe ser unidireccional,
+            puedes declarar la restricci&#x00f3;n <literal>NOT NULL</literal> en el mapeo de
+            <literal>&lt;key&gt;</literal>:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children">
+            <key column="parent_id" not-null="true"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            En la otra mano, si un hijo pudiera tener m&#x00fa;ltiples padres, ser&#x00ed;a apropiada
+            una asociaci&#x00f3;n muchos-a-muchos:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children" table="childset">
+            <key column="parent_id"/>
+            <many-to-many class="Child" column="child_id"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Definiciones de tabla:
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255) )
+create table childset ( parent_id bigint not null,
+                        child_id bigint not null,
+                        primary key ( parent_id, child_id ) )
+alter table childset add constraint childsetfk0 (parent_id) references parent
+alter table childset add constraint childsetfk1 (child_id) references child]]></programlisting>
+
+        <para>
+            Para m&#x00e1;s ejemplos y un paseo completo a trav&#x00e9;s del mapeo de relaciones padre/hijo,
+            ver <xref linkend="example-parentchild"/>.
+        </para>
+        
+        <para>
+            Son posibles mapeos de asociaci&#x00f3;n a&#x00fa;n m&#x00e1;s complejos. Catalogaremos todas las posibilidades
+            en el pr&#x00f3;ximo cap&#x00ed;tulo.
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/component_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/component_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/component_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,403 @@
+<chapter id="components">
+    <title>Mapeo de Componentes</title>
+
+    <para>
+        La noci&#x00f3;n de un <emphasis>componente</emphasis> es reusada en muchos contextos diferentes,
+        para prop&#x00f3;sitos diferentes, a trav&#x00e9;s de Hibernate.
+    </para>
+
+    <sect1 id="components-dependentobjects">
+        <title>Objetos dependientes</title>
+
+        <para>
+            Un componente es un objeto contenido que es persistido como un tipo de valor, no una
+            referencia de entidad. El t&#x00e9;rmino "componente" hace referencia a la noci&#x00f3;n orientada a
+            objetos de composici&#x00f3;n (no a componentes a nivel de arquitectura). Por ejemplo, podr&#x00ed;as
+            modelar una persona como:
+        </para>
+
+        <programlisting><![CDATA[public class Person {
+    private java.util.Date birthday;
+    private Name name;
+    private String key;
+    public String getKey() {
+        return key;
+    }
+    private void setKey(String key) {
+        this.key=key;
+    }
+    public java.util.Date getBirthday() {
+        return birthday;
+    }
+    public void setBirthday(java.util.Date birthday) {
+        this.birthday = birthday;
+    }
+    public Name getName() {
+        return name;
+    }
+    public void setName(Name name) {
+        this.name = name;
+    }
+    ......
+    ......
+}]]></programlisting>
+
+<programlisting><![CDATA[public class Name {
+    char initial;
+    String first;
+    String last;
+    public String getFirst() {
+        return first;
+    }
+    void setFirst(String first) {
+        this.first = first;
+    }
+    public String getLast() {
+        return last;
+    }
+    void setLast(String last) {
+        this.last = last;
+    }
+    public char getInitial() {
+        return initial;
+    }
+    void setInitial(char initial) {
+        this.initial = initial;
+    }
+}]]></programlisting>
+
+        <para>
+            Ahora <literal>Name</literal> puede ser persistido como un componente de
+            <literal>Person</literal>. Observa que <literal>Name</literal> define m&#x00e9;todos
+            getter y setter para sus propiedades persistentes, pero no necesita declarar
+            ninguna interface ni propiedades identificadoras.
+        </para>
+
+        <para>
+            Nuestro mapeo de Hibernate se ver&#x00ed;a as&#x00ed;:
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Person" table="person">
+    <id name="Key" column="pid" type="string">
+        <generator class="uuid.hex"/>
+    </id>
+    <property name="birthday" type="date"/>
+    <component name="Name" class="eg.Name"> <!-- class attribute optional -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </component>
+</class>]]></programlisting>
+
+        <para>
+            La tabla person tendr&#x00ed;a las columnas <literal>pid</literal>,
+            <literal>birthday</literal>,
+            <literal>initial</literal>,
+            <literal>first</literal> y
+            <literal>last</literal>.
+        </para>
+
+        <para>
+            Como todos los tipos de valor, los componentes no soportan referencias compartidas.
+            En otras palabras, dos personas pueden tener el mismo nombre, pero los dos objetos
+            persona contendr&#x00ed;an dos objetos nombre independientes, s&#x00f3;lo "iguales" en valor.
+            La sem&#x00e1;ntica de valor nulo de un componente es <emphasis>ad hoc</emphasis>.
+            Cuando se recargue el objeto contenedor, Hibernate asumir&#x00e1; que si todas las columnas del
+            componente son nulas, el componente entero es nulo. Esto debe estar bien para la mayor&#x00ed;a
+            de prop&#x00f3;sitos.
+        </para>
+
+        <para>
+            Las propiedades de un componentes pueden ser de cualquier tipo de Hibernate
+            (colecciones, muchos-a-uno, asociaciones, otros componentes, etc). Los componentes
+            anidados <emphasis>no</emphasis> deben ser considerados un uso ex&#x00f3;tico. Hibernate est&#x00e1;
+            concebido para soportar un modelo de objetos granularizado en fino.
+        </para>
+
+        <para>
+            El elemento <literal>&lt;component&gt;</literal> permite un subelemento
+            <literal>&lt;parent&gt;</literal> que mapee una propiedad de la clase del componente
+            como una referencia de regreso a la entidad contenedora.
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Person" table="person">
+    <id name="Key" column="pid" type="string">
+        <generator class="uuid.hex"/>
+    </id>
+    <property name="birthday" type="date"/>
+    <component name="Name" class="eg.Name" unique="true">
+        <parent name="namedPerson"/> <!-- reference back to the Person -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </component>
+</class>]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="components-incollections" revision="1">
+        <title>Colecciones de objetos dependientes</title>
+
+        <para>
+            Las colecciones de componentes est&#x00e1;n soportadas (por ejemplo,
+            un array de tipo <literal>Name</literal>). Declara tu colecci&#x00f3;n
+            de componentes remplazando la etiqueta <literal>&lt;element&gt;</literal>
+            por una etiqueta <literal>&lt;composite-element&gt;</literal>.
+        </para>
+
+        <programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
+    <key column="id"/>
+    <composite-element class="eg.Name"> <!-- class attribute required -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </composite-element>
+</set>]]></programlisting>
+
+        <para>
+            Nota: si defines un <literal>Set</literal> de elementos compuestos, es muy
+            importante implementar <literal>equals()</literal> y <literal>hashCode()</literal>
+            correctamente.
+        </para>
+
+        <para>
+            Los elementos compuestos pueden contener componentes pero no colecciones.
+            Si tu elemento compuesto contiene a su vez componentes, usa la etiqueta
+            <literal>&lt;nested-composite-element&gt;</literal>. Este es un caso bastante
+            ex&#x00f3;tico - una colecci&#x00f3;n de componentes que a su vez tienen componentes. A esta
+            altura debes estar pregunt&#x00e1;ndote si una asociaci&#x00f3;n uno-a-muchos es m&#x00e1;s
+            apropiada. Intenta remodelar el elemento compuesto como una entidad - pero
+            observa que aunque el modelo Java es el mismo, el modelo relacional y la
+            sem&#x00e1;ntica de persistencia siguen siendo ligeramente diferentes.
+        </para>
+
+        <para>
+            Por favor observa que un mapeo de elemento compuesto no soporta
+            propiedades nulables si est&#x00e1;s usando un <literal>&lt;set&gt;</literal>.
+            Hibernate tiene que usar cada columna para identificar un registro
+            al borrar objetos (no hay una columna clave primaria separada en la tabla del
+            elemento compuesto), lo que es imposible con valores nulos. Tienes que, o bien usar
+            s&#x00f3;lo propiedades no nulas en un elemento compuesto o elegir un
+            <literal>&lt;list&gt;</literal>, <literal>&lt;map&gt;</literal>,
+            <literal>&lt;bag&gt;</literal> o <literal>&lt;idbag&gt;</literal>.
+        </para>
+
+        <para>
+            Un caso especial de un elemento compuesto es un elemento compuesto con un
+            elemento anidado <literal>&lt;many-to-one&gt;</literal>. Un mapeo como este
+            te permite mapear columnas extra de una tabla de asociaci&#x00f3;n muchos-a-muchos
+            a la clase del elemento compuesto. La siguiente es una asociaci&#x00f3;n muchos-a-muchos
+            de <literal>Order</literal> a <literal>Item</literal> donde
+            <literal>purchaseDate</literal>, <literal>price</literal> y
+            <literal>quantity</literal> son propiedades de la asociaci&#x00f3;n:
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Order" .... >
+    ....
+    <set name="purchasedItems" table="purchase_items" lazy="true">
+        <key column="order_id">
+        <composite-element class="eg.Purchase">
+            <property name="purchaseDate"/>
+            <property name="price"/>
+            <property name="quantity"/>
+            <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Por supuesto, no puede haber una referencia a la compra del otro lado para la
+            navegaci&#x00f3;n bidireccional de la asociaci&#x00f3;n. Recuerda que los componentes son tipos de
+            valor no permiten referencias compartidas. Una sola <literal>Purchase</literal> puede
+            estar en el conjunto de una <literal>Order</literal>, pero no puede ser referenciada
+            por el <literal>Item</literal> al mismo tiempo.
+        </para>
+
+        <para>Incluso son posibles las asociaciones ternarias (o cuaternarias, etc):</para>
+
+        <programlisting><![CDATA[<class name="eg.Order" .... >
+    ....
+    <set name="purchasedItems" table="purchase_items" lazy="true">
+        <key column="order_id">
+        <composite-element class="eg.OrderLine">
+            <many-to-one name="purchaseDetails class="eg.Purchase"/>
+            <many-to-one name="item" class="eg.Item"/>
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Los elementos compuestos pueden aparecer en consultas usando la misma
+            sint&#x00e1;xis que las asociaciones a otras entidades.
+        </para>
+
+    </sect1>
+
+    <sect1 id="components-asmapindex">
+        <title>Componentes como &#x00ed;ndices de Map</title>
+
+        <para>
+            El elemento <literal>&lt;composite-map-key&gt;</literal> te permite mapear
+            una clase componente como la clave de un <literal>Map</literal>. Aseg&#x00fa;rate que
+            sobrescribes <literal>hashCode()</literal> y <literal>equals()</literal>
+            correctamente en la clase componente.
+        </para>
+    </sect1>
+
+    <sect1 id="components-compositeid" revision="1">
+        <title>Componentes como identificadores compuestos</title>
+
+        <para>
+            Puedes usar un componente como un identidicador de una clase entidad. Tu clase
+            componente debe satisfacer ciertos requerimientos:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Debe implementar <literal>java.io.Serializable</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Debe re-implementar <literal>equals()</literal> y
+                    <literal>hashCode()</literal>, consistentemente con la
+                    noci&#x00f3;n de base de datos de igualdad de clave compuesta.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            <emphasis>Nota: en Hibernat3, el segundo requerimiento no es absolutamente un
+            requerimiento r&#x00ed;gido de Hibernate. Pero de todas formas, h&#x00e1;zlo.</emphasis>
+        </para>
+
+        <para>
+            No puedes usar un <literal>IdentifierGenerator</literal> para generar claves
+            compuestas. La aplicaci&#x00f3;n debe, en cambio, asignar sus propios identificadores.
+        </para>
+
+        <para>
+            Usa la etiqueta <literal>&lt;composite-id&gt;</literal> (con elementos
+            anidados <literal>&lt;key-property&gt;</literal>) en lugar de la usual
+            declaraci&#x00f3;n <literal>&lt;id&gt;</literal>. Por ejemplo, la clase
+            <literal>OrderLine</literal> tiene una clave primaria que depende de
+            la clave primaria (compuesta) de <literal>Order</literal>.
+        </para>
+
+        <programlisting><![CDATA[<class name="OrderLine">
+    
+    <composite-id name="id" class="OrderLineId">
+        <key-property name="lineId"/>
+        <key-property name="orderId"/>
+        <key-property name="customerId"/>
+    </composite-id>
+    
+    <property name="name"/>
+    
+    <many-to-one name="order" class="Order"
+            insert="false" update="false">
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </many-to-one>
+    ....
+    
+</class>]]></programlisting>
+
+        <para>
+            Ahora, cualquier clave for&#x00e1;nea que referencie la tabla de <literal>OrderLine</literal>
+            es tambi&#x00e9;n compuesta. Debes declarar esto en tus mapeos de otras clases. Una asociaci&#x00f3;n
+            a <literal>OrderLine</literal> ser&#x00ed;a mapeado as&#x00ed;:
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
+<!-- the "class" attribute is optional, as usual -->
+    <column name="lineId"/>
+    <column name="orderId"/>
+    <column name="customerId"/>
+</many-to-one>]]></programlisting>
+
+        <para>
+            (Nota que la etiqueta <literal>&lt;column&gt;</literal> es una alternativa al
+            atributo <literal>column</literal> en cualquier sitio.)
+        </para>
+        
+        <para>
+            Una asociaci&#x00f3;n <literal>muchos-a-muchos</literal> a <literal>OrderLine</literal>
+            tambi&#x00e9;n usa la clave for&#x00e1;nea compuesta:
+        </para>
+    
+    <programlisting><![CDATA[<set name="undeliveredOrderLines">
+    <key column name="warehouseId"/>
+    <many-to-many class="OrderLine">
+        <column name="lineId"/>
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </many-to-many>
+</set>]]></programlisting>
+
+        <para>
+            La colecci&#x00f3;n de <literal>OrderLine</literal>s en <literal>Order</literal> usar&#x00ed;a:
+        </para>
+
+    <programlisting><![CDATA[<set name="orderLines" inverse="true">
+    <key>
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </key>
+    <one-to-many class="OrderLine"/>
+</set>]]></programlisting>
+
+        <para>
+            (El elemento <literal>&lt;one-to-many&gt;</literal>, como es usual, no declara columnas.)
+        </para>
+        
+        <para>
+            Si <literal>OrderLine</literal> posee una colecci&#x00f3;n por s&#x00ed; misma, tiene tambi&#x00e9;n
+            una clave for&#x00e1;nea compuesta.
+        </para>
+
+        <programlisting><![CDATA[<class name="OrderLine">
+    ....
+    ....
+    <list name="deliveryAttempts">
+        <key>   <!-- a collection inherits the composite key type -->
+            <column name="lineId"/>
+            <column name="orderId"/>
+            <column name="customerId"/>
+        </key>
+        <list-index column="attemptId" base="1"/>
+        <composite-element class="DeliveryAttempt">
+            ...
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="components-dynamic" revision="1">
+        <title>Componentes din&#x00e1;micos</title>
+
+        <para>
+            Puedes incluso mapear una propiedad de tipo <literal>Map</literal>:
+        </para>
+
+    <programlisting><![CDATA[<dynamic-component name="userAttributes">
+    <property name="foo" column="FOO" type="string"/>
+    <property name="bar" column="BAR" type="integer"/>
+    <many-to-one name="baz" class="Baz" column="BAZ_ID"/>
+</dynamic-component>]]></programlisting>
+
+        <para>
+            La sem&#x00e1;ntica de un mapeo <literal>&lt;dynamic-component&gt;</literal> es &#x00ed;dentica
+            a la de <literal>&lt;component&gt;</literal>. La ventaja de este tipo de mapeos es
+            la habilidad para determinar las propiedades reales del bean en tiempo de despliegue,
+            s&#x00f3;lo con editar el documento de mapeo. La manipulaci&#x00f3;n del documento de mapeo en tiempo
+            de ejecuci&#x00f3;n es tambi&#x00e9;n posible, usando un analizador DOM. Incluso mejor, puedes acceder
+            (y cambiar) el metamodelo de tiempo de configuraci&#x00f3;n de Hibernate por medio del objeto
+            <literal>Configuration</literal>.
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/configuration.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/configuration.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/configuration.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1761 @@
+<chapter id="session-configuration" revision="1">
+
+    <title>Configuraci&#x00f3;n</title>
+    
+    <para>
+        Debido a que Hibernate est&#x00e1; dise&#x00f1;ado para operar en muchos entornos
+        diferentes, hay un gran n&#x00fa;mero de par&#x00e1;metros de configuraci&#x00f3;n.
+        Afortunadamente, la mayor&#x00ed;a tiene valores por defecto sensibles e Hibernate
+        se distribuye con un fichero <literal>hibernate.properties</literal> de ejemplo en 
+        <literal>etc/</literal> que muestra las diversas opciones. Tan s&#x00f3;lo pon el
+        fichero de ejemplo en tu classpath y personal&#x00ed;zalo.
+    </para>
+
+    <sect1 id="configuration-programmatic" revision="1">
+        <title>Configuraci&#x00f3;n program&#x00e1;tica</title>
+
+        <para>
+            Una instancia de <literal>org.hibernate.cfg.Configuration</literal>
+            representa un conjunto entero de mapeos de los tipos Java de una aplicaci&#x00f3;n
+            a una base de datos SQL. La <literal>Configuration</literal> es usada para
+            construir una <literal>SessionFactory</literal> (inmutable). Los mapeos se
+            compilan de varios ficheros de mapeo XML.
+        </para>
+
+        <para>
+            Puedes obtener una instancia de <literal>Configuration</literal> instanci&#x00e1;ndola
+            directamente y especificando documentos de mapeo XML. Si los ficheros de mapeo
+            est&#x00e1;n en el classpath, usa <literal>addResource()</literal>:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addResource("Item.hbm.xml")
+    .addResource("Bid.hbm.xml");]]></programlisting>
+
+        <para>
+            Una forma alternativa (a veces mejor) es especificar la clase mapeada,
+            y dejar que Hibernate encuentre el documento de mapeo por ti:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addClass(org.hibernate.auction.Item.class)
+    .addClass(org.hibernate.auction.Bid.class);]]></programlisting>
+
+        <para>
+            Entonces Hibernate buscar&#x00e1; ficheros de mapeo llamados
+            <literal>/org/hibernate/auction/Item.hbm.xml</literal> y
+            <literal>/org/hibernate/auction/Bid.hbm.xml</literal> en el classpath.
+            Este enfoque elimina cualquier nombre de fichero en el c&#x00f3;digo.
+        </para>
+        
+        <para>
+            Una <literal>Configuration</literal> tambi&#x00e9;n te permite especificar
+            propiedades de configuraci&#x00f3;n:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addClass(org.hibernate.auction.Item.class)
+    .addClass(org.hibernate.auction.Bid.class)
+    .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
+    .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
+    .setProperty("hibernate.order_updates", "true");]]></programlisting>
+    
+        <para>
+            Esta no es la &#x00fa;nica forma de pasar propiedades de configuraci&#x00f3;n
+            a Hibernate. La diversas opciones incluyen:
+        </para>
+
+        <orderedlist spacing="compact">
+            <listitem>
+                <para>
+                    Pasar una instancia de <literal>java.util.Properties</literal> a
+                    <literal>Configuration.setProperties()</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Colocar <literal>hibernate.properties</literal> en un directorio
+                    ra&#x00ed;z del classpath.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Establecer propiedades <literal>System</literal>
+                    usando <literal>java -Dproperty=value</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Incluir elementos <literal>&lt;property&gt;</literal>
+                    en <literal>hibernate.cfg.xml</literal> (discutido luego).
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <para>
+            <literal>hibernate.properties</literal> es el enfoque m&#x00e1;s f&#x00e1;cil
+            si quieres comenzar r&#x00e1;pido.
+        </para>
+
+        <para>
+            La <literal>Configuration</literal> est&#x00e1; concebida como un objeto
+            de tiempo de arranque, para ser descartado una vez que una
+            <literal>SessionFactory</literal> es creada.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="configuration-sessionfactory">
+        <title>Obteniendo una SessionFactory</title>
+
+        <para>
+            Cuando todos los mapeos han sido parseados por la <literal>Configuration</literal>, 
+            la aplicaci&#x00f3;n debe obtener una f&#x00e1;brica de instancias de <literal>Session</literal>.
+            Esta f&#x00e1;brica est&#x00e1; concebida para ser compartida por todas las hebras de
+            aplicaci&#x00f3;n:
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sessions = cfg.buildSessionFactory();]]></programlisting>
+
+        <para>
+            Hibernate permite que tu aplicaci&#x00f3;n instancie m&#x00e1;s de una
+            <literal>SessionFactory</literal>. Esto es &#x00fa;til si est&#x00e1;s usando
+            m&#x00e1;s de una base de datos.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-hibernatejdbc" revision="1">
+        <title>Conexiones JDBC</title>
+
+        <para>
+            Usualmente, quieres que la <literal>SessionFactory</literal> cree y almacene
+            en pool conexiones JDBC para ti. Si adoptas este enfoque, abrir una <literal>Session</literal> 
+            es tan simple como:
+        </para>
+
+        <programlisting><![CDATA[Session session = sessions.openSession(); // open a new Session]]></programlisting>
+        
+        <para>
+            En cuanto hagas algo que requiera acceso a la base de datos, se obtendr&#x00e1; una
+            conexi&#x00f3;n JDBC del pool.
+        </para>
+
+        <para>
+            Para que esto funcione, necesitamos pasar algunas propiedades de conexi&#x00f3;n
+            JDBC a Hibernate. Todos los nombres de propiedades y su sem&#x00e1;ntica
+            est&#x00e1;n definidas en la clase <literal>org.hibernate.cfg.Environment</literal>.
+            Describiremos ahora las configuraciones m&#x00e1;s importantes para la conexi&#x00f3;n
+            JDBC.
+        </para>
+
+        <para>
+            Hibernate obtendr&#x00e1; (y tendr&#x00e1; en pool) conexiones usando
+            <literal>java.sql.DriverManager</literal> si configuras las siguientes propiedades:
+        </para>
+
+        <table frame="topbot">
+            <title>Propiedades JDBC de Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nombre de propiedad</entry>
+                        <entry>Prop&#x00f3;sito</entry>
+                    </row>
+                </thead>
+            <tbody>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.driver_class</literal>
+                </entry>
+                <entry>
+                    <emphasis>clase del driver jdbc</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.url</literal>
+                </entry>
+                <entry>
+                    <emphasis>URL de jdbc</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.username</literal>
+                </entry>
+                <entry>
+                    <emphasis>usuario de base de datos</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.password</literal>
+                </entry>
+                <entry>
+                    <emphasis>contrase&#x00f1;a del usuario de base de datos</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.pool_size</literal>
+                </entry>
+                <entry>
+                    <emphasis>n&#x00fa;mero m&#x00e1;ximo de conexiones manejadas por pooling</emphasis>
+                </entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+            El algoritmo de pooling de conexiones propio de Hibernate es sin embargo
+            algo rudimentario. Est&#x00e1; concebido para ayudarte a comenzar y 
+            <emphasis>no est&#x00e1; concebido para usar en un sistema de producci&#x00f3;n</emphasis>
+            ni siquiera para pruebas de rendimiento. Debes usar un pool de terceros para
+            un mejor rendimiento y estabilidad. S&#x00f3;lo remplaza la propiedad
+            <literal>hibernate.connection.pool_size</literal> con configuraciones
+            espec&#x00ed;ficas del pool de conexiones. Esto desactivar&#x00e1; el pool
+            interno de Hibernate. Por ejemplo, podr&#x00ed;as querer usar C3P0.
+        </para>
+
+        <para>
+            C3P0 es un pool de conexiones JDBC de c&#x00f3;digo abierto distribuido
+            junto a Hibernate en el directorio <literal>lib</literal>.
+            Hibernate usar&#x00e1; su <literal>C3P0ConnectionProvider</literal>
+            para pooling de conexiones si estableces propiedades <literal>hibernate.c3p0.*</literal>.
+            Si quieres usar Proxool refi&#x00e9;rete al <literal>hibernate.properties</literal>
+            empaquetado y al sitio web de Hibernate para m&#x00e1;s informaci&#x00f3;n.
+        </para>
+
+        <para>
+            Aqu&#x00ed; hay un fichero <literal>hibernate.properties</literal> de ejemplo para C3P0:
+        </para>
+
+        <programlisting id="c3p0-configuration" revision="1"><![CDATA[hibernate.connection.driver_class = org.postgresql.Driver
+hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
+hibernate.connection.username = myuser
+hibernate.connection.password = secret
+hibernate.c3p0.min_size=5
+hibernate.c3p0.max_size=20
+hibernate.c3p0.timeout=1800
+hibernate.c3p0.max_statements=50
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+        <para>
+            Para su uso en un servidor de aplicaciones, casi siempre debes configurar
+            Hibernate para que obtenga conexiones de un <literal>Datasource</literal>
+            del servidor de aplicaciones registrado en JNDI. Necesitar&#x00e1;s establecer
+            al menos una de las siguientes propiedades:
+        </para>
+
+        <table frame="topbot">
+            <title>Propiedades de Datasource de Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nombre de propiedad</entry>
+                        <entry>Prop&#x00f3;sito</entry>
+                    </row>
+                </thead>
+            <tbody>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.datasource</literal>
+                </entry>
+                <entry>
+                    <emphasis>nombre del datasource JNDI</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.jndi.url</literal>
+                </entry>
+                <entry>
+                    <emphasis>URL del provedor JNDI</emphasis> (optional)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.jndi.class</literal>
+                </entry>
+                <entry>
+                    <emphasis>clase de la <literal>InitialContextFactory</literal> de JNDI</emphasis> (opcional)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.username</literal>
+                </entry>
+                <entry>
+                    <emphasis>usuario de base de datos</emphasis> (opcional)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.password</literal>
+                </entry>
+                <entry>
+                    <emphasis>contrase&#x00f1;a del usuario de base de datos</emphasis> (opcional)
+                </entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+            He aqu&#x00ed; un fichero <literal>hibernate.properties</literal> de ejemplo
+            para un un datasource JNDI provisto por un servidor de aplicaciones.
+        </para>
+
+        <programlisting><![CDATA[hibernate.connection.datasource = java:/comp/env/jdbc/test
+hibernate.transaction.factory_class = \
+    org.hibernate.transaction.JTATransactionFactory
+hibernate.transaction.manager_lookup_class = \
+    org.hibernate.transaction.JBossTransactionManagerLookup
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+        <para>
+            Las conexiones JDBC obtenidas de un datasource JNDI participar&#x00e1;n autom&#x00e1;ticamente
+            en las transacciones del servidor de aplicaciones manejadas por contenedor.
+        </para>
+
+        <para>
+            Pueden darse propiedades de conexi&#x00f3;n arbitrarias anteponiendo
+            "<literal>hibernate.connnection</literal>" al nombre de propiedad.
+            Por ejemplo, puedes especificar un <literal>charSet</literal> usando
+            <literal>hibernate.connection.charSet</literal>.
+        </para>
+
+        <para>
+            Puedes definir tu propia estrategia de plugin para obtener conexiones JDBC implementando
+            la interface <literal>org.hibernate.connection.ConnectionProvider</literal>. Puedes
+            seleccionar una implementaci&#x00f3;n personalizada estableciendo
+            <literal>hibernate.connection.provider_class</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-optional" revision="1">
+        <title>Par&#x00e1;metros de configuraci&#x00f3;n opcionales</title>
+        
+        <para>
+            Hay un n&#x00fa;mero de otras propiedades que controlan el comportamiento
+            de Hibernate en tiempo de ejecuci&#x00f3;n. Todas son opcionales y tienen
+            valores por defecto razonables.
+        </para>
+
+        <para>
+            <emphasis>Advertencia: algunas de estas propiedades son de "nivel-de-sistema"
+            solamente.</emphasis>. Las propiedades a nivel de sistema s&#x00f3;lo pueden ser
+            establecidas por medio de <literal>java -Dproperty=value</literal> o
+            <literal>hibernate.properties</literal>. <emphasis>No</emphasis> pueden
+            establecerse por medio de las otras t&#x00e9;cnicas arriba descritas.
+        </para>
+
+        <table frame="topbot" id="configuration-optional-properties" revision="8">
+            <title>Propiedades de Configuraci&#x00f3;n de Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nombre de propiedad</entry>
+                        <entry>Prop&#x00f3;sito</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.dialect</literal>
+                        </entry>
+                        <entry>
+                            El nombre de clase de un <literal>Dialect</literal>
+                            de Hibernate que permite a Hibernate generar SQL optimizado
+                            para una base de datos relacional en particular.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>full.classname.of.Dialect</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.show_sql</literal>
+                        </entry>
+                        <entry>
+                            Escribe todas las sentencias SQL a la consola.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_schema</literal>
+                        </entry>
+                        <entry>
+                            Cualifica, en el SQL generado, los nombres de tabla sin cualificar
+                            con el esquema/tablespace dado.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>SCHEMA_NAME</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_catalog</literal>
+                        </entry>
+                        <entry>
+                            Cualifica, en el SQL generado, los nombres de tabla sin cualificar
+                            con el cat&#x00e1;logo dado.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>CATALOG_NAME</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.session_factory_name</literal>
+                        </entry>
+                        <entry>
+                            La <literal>SessionFactory</literal> ser&#x00e1;
+                            ligada a este nombre en JNDI autom&#x00e1;ticamente
+                            despu&#x00e9;s de ser creada.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>jndi/composite/name</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.max_fetch_depth</literal>
+                        </entry>
+                        <entry>
+                            Establece una "profundidad" m&#x00e1;xima del
+                            &#x00e1;rbol de recuperaci&#x00f3;n por outer join
+                            para asociaciones de un extremo solo (uno-a-uno, muchos-a-uno).
+                            Un <literal>0</literal> deshabilita la recuperaci&#x00f3;n
+                            por outer join por defecto.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                valores recomendados entre <literal>0</literal> y
+                                <literal>3</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_batch_fetch_size</literal>
+                        </entry>
+                        <entry>
+                            Establece un tama&#x00f1;o por defecto para la recuperaci&#x00f3;n
+                            en lote de asociaciones de Hibernate.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                valores recomendados <literal>4</literal>, <literal>8</literal>, 
+                                <literal>16</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_entity_mode</literal>
+                        </entry>
+                        <entry>
+                            Establece un modo por defecto de representaci&#x00f3;n de
+                            entidades para todas las sesiones abiertas por esta
+                            <literal>SessionFactory</literal>
+                            <para>
+                                <literal>dynamic-map</literal>, <literal>dom4j</literal>,
+                                <literal>pojo</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.order_updates</literal>
+                        </entry>
+                        <entry>
+                            Fuerza a Hibernate a ordenar las actualizaciones SQL
+                            por el valor de la clave primaria de los items a actualizar.
+                            Esto resultar&#x00e1; en menos bloqueos muertos de transacci&#x00f3;n
+                            en sistemas altamente concurrentes.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.generate_statistics</literal>
+                        </entry>
+                        <entry>
+                            De habilitarse, Hibernate colectar&#x00e1; estad&#x00ed;sticas
+                            &#x00fa;tiles para la afinaci&#x00f3;n de rendimiento.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.use_identifer_rollback</literal>
+                        </entry>
+                        <entry>
+                            De habilitarse, las propiedades identificadoras
+                            generadas ser&#x00e1;n reseteadas a valores por
+                            defecto cuando los objetos sean borrados.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.use_sql_comments</literal>
+                        </entry>
+                        <entry>
+                            De activarse, Hibernate generar&#x00e1; comentarios dentro del SQL,
+                            para una m&#x00e1;s f&#x00e1;cil depuraci&#x00f3;n, por defecto a
+                            <literal>false</literal>.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-jdbc-properties" revision="8">
+            <title>Propiedades de JDBC y Conexiones de Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nombre de propiedad</entry>
+                        <entry>Propo&#x00f3;sito</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.fetch_size</literal>
+                        </entry>
+                        <entry>
+                            Un valor distinto de cero que determina el tama&#x00f1;o
+                            de recuperaci&#x00f3;n de JDBC (llama a
+                            <literal>Statement.setFetchSize()</literal>).
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.batch_size</literal>
+                        </entry>
+                        <entry>
+                            Un valor distinto de cero habilita el uso de actualizaciones
+                            en lote de JDBC2 por Hibernate.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis>
+                                valores recomendados entre <literal>5</literal> y <literal>30</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.batch_versioned_data</literal>
+                        </entry>
+                        <entry>
+                            Establece esta propiedad a <literal>true</literal> si tu driver JDBC
+                            devuelve cuentas correctas de filas desde <literal>executeBatch()</literal>
+                            (usualmente es seguro activar esta opci&#x00f3;n). Hibernate usar&#x00e1;
+                            DML en lote para versionar autom&#x00e1;ticamente los datos.
+                            Por defecto a <literal>false</literal>.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.factory_class</literal>
+                        </entry>
+                        <entry>
+                            Selecciona un <literal>Batcher</literal> personalizado.
+                            La mayor&#x00ed;a de las aplicaciones no necesitar&#x00e1;n
+                            esta propiedad de configuraci&#x00f3;n.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis>
+                                <literal>classname.of.Batcher</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_scrollable_resultset</literal>
+                        </entry>
+                        <entry>
+                            Habilita el uso de resultados scrollables de JDBC2 por Hibernate.
+                            Esta propiedad s&#x00f3;lo es necesaria cuando se usan conexiones
+                            JDBC provistas por el usuario, en caso contrario Hibernate usa los
+                            metadatos de conexi&#x00f3;n.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_streams_for_binary</literal>
+                        </entry>
+                        <entry>
+                            Usa flujos (streams) al escribir/leer tipos
+                            <literal>binary</literal> o <literal>serializable</literal>
+                            a/desde JDBC (propiedad a nivel de sistema).
+                            <para>
+                                <emphasis role="strong">ej.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_get_generated_keys</literal>
+                        </entry>
+                        <entry>
+                            Habilita el uso de <literal>PreparedStatement.getGeneratedKeys()</literal>
+                            de JDBC3 para traer claves generadas nativamente despu&#x00e9;s de insertar.
+                            Requiere un driver JDBC3+ y un JRE1.4+. Establ&#x00e9;cela a false si tu
+                            driver tiene problemas con los generadores de identificador de Hibernate.
+                            Por defecto, se intenta determinar las capacidades del driver usando los
+                            metadatos de conexi&#x00f3;n.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis>
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.provider_class</literal>
+                        </entry>
+                        <entry>
+                            EL nombre de clase de un <literal>ConnectionProvider</literal> personalizado
+                            que provea conexiones JDBC a Hibernate.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>classname.of.ConnectionProvider</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                    <entry>
+                        <literal>hibernate.connection.isolation</literal>
+                    </entry>
+                    <entry>
+                        Establece el nivel de aislamiento de transacci&#x00f3;n JDBC.
+                        Comprueba <literal>java.sql.Connection</literal> para valores
+                        significativos pero observa que la mayor&#x00ed;a de las bases de
+                        datos no soportan todos los niveles de aislamiento.
+                        <para>
+                            <emphasis role="strong">eg.</emphasis> 
+                            <literal>1, 2, 4, 8</literal>
+                        </para>
+                    </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.autocommit</literal>
+                        </entry>
+                        <entry>
+                            Habilita compromiso autom&#x00e1;tico (autocommit) para
+                            las conexiones JDBC en pool (no recomendado).
+                            <para>
+                                <emphasis role="strong">ej.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.release_mode</literal>
+                        </entry>
+                        <entry>
+                            Especifica cu&#x00e1;ndo Hibernate debe liberar las conexiones JDBC.
+                            Por defecto, una conexi&#x00f3;n JDBC es retenida hasta que la sesi&#x00f3;n
+                            es cerrada expl&#x00ed;citamente o desconectada. Para un datasource JTA
+                            del servidor de aplicaciones, debes usar <literal>after_statement</literal>
+                            para liberar agresivamente las conexiones despu&#x00e9;s de cada llamada
+                            JDBC. Para una conexi&#x00f3;n no JTA, frecuentemente tiene sentido liberar
+                            la conexi&#x00f3;n al final de cada transacci&#x00f3;n, usando
+                            <literal>after_transaction</literal>. <literal>auto</literal> eligir&#x00e1;
+                            <literal>after_statement</literal> para las estrategias JTA o CMT
+                            de transacci&#x00f3;n y <literal>after_transaction</literal> para la
+                            estrategia JDBC de transacci&#x00f3;n.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>on_close</literal> (por defecto)| <literal>after_transaction</literal> |
+                                <literal>after_statement</literal> | <literal>auto</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                    <entry>
+                        <literal>hibernate.connection.<emphasis>&lt;propertyName&gt;</emphasis></literal>
+                    </entry>
+                    <entry>
+                        Pasa la propiedad JDBC <literal>propertyName</literal>
+                        a <literal>DriverManager.getConnection()</literal>.
+                    </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jndi.<emphasis>&lt;propertyName&gt;</emphasis></literal>
+                        </entry>
+                        <entry>
+                            Pasa la propiedad <literal>propertyName</literal>
+                            a <literal>InitialContextFactory</literal> de JNDI.
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-cache-properties" revision="7">
+            <title>Propiedades de Cach&#x00e9; de Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nombre de propiedad</entry>
+                        <entry>Prop&#x00f3;sito</entry>
+                    </row>
+                </thead>
+                <tbody>
+                     <row>
+                        <entry>
+                            <literal>hibernate.cache.provider_class</literal>
+                        </entry>
+                        <entry>
+                            El nombre de clase de un <literal>CacheProvider</literal> personalizado.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>classname.of.CacheProvider</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_minimal_puts</literal>
+                        </entry>
+                        <entry>
+                            Optimiza la operaci&#x00f3;n del cach&#x00e9; de segundo nivel
+                            para minimizar escrituras, al costo de lecturas m&#x00e1;s frecuentes.
+                            Esto es m&#x00e1;s &#x00fa;til para cach&#x00e9;s en cluster y,
+                            en Hibernate3, est&#x00e1; habilitado por defecto para implementaciones
+                            de cach&#x00e9; en cluster.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_query_cache</literal>
+                        </entry>
+                        <entry>
+                            Habilita el cach&#x00e9; de lectura, consultas individuales todav&#x00ed;a
+                            tienen que ponerse cachables.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_second_level_cache</literal>
+                        </entry>
+                        <entry>
+                            Puede ser usado para deshabilitar completamente el cach&#x00e9;
+                            de segundo nivel, que est&#x00e1; habilitado por defecto para clases
+                            que especifican un mapeo <literal>&lt;cache&gt;</literal>.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.query_cache_factory</literal>
+                        </entry>
+                        <entry>
+                            El nombre de clase de una interface <literal>QueryCache</literal>
+                            personalizada, por defecto al <literal>StandardQueryCache</literal>
+                            prefabricado.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis>
+                                <literal>classname.of.QueryCache</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.region_prefix</literal>
+                        </entry>
+                        <entry>
+                            Un prefijo a usar para los nombres de regi&#x00f3;n
+                            del cach&#x00e9; de segundo nivel.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>prefix</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_structured_entries</literal>
+                        </entry>
+                        <entry>
+                            Fuerza a Hibernate a almacenar los datos en el cach&#x00e9;
+                            de segundo nivel en un formato m&#x00e1;s amigable al humano.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis>
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-transaction-properties" revision="8">
+            <title>Propiedades de Transacci&#x00f3;n de Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nombre de propiedad</entry>
+                        <entry>Prop&#x00f3;sito</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.factory_class</literal>
+                        </entry>
+                        <entry>
+                            El nombre de clase de un <literal>TransactionFactory</literal>
+                            a usar con la API de <literal>Transaction</literal> de Hibernate
+                            (por defectoa <literal>JDBCTransactionFactory</literal>).
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>classname.of.TransactionFactory</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>jta.UserTransaction</literal>
+                        </entry>
+                        <entry>
+                            Un nombre JNDI usado por <literal>JTATransactionFactory</literal> para
+                            obtener la <literal>UserTransaction</literal> JTA del servidor
+                            de aplicaciones.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>jndi/composite/name</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.manager_lookup_class</literal>
+                        </entry>
+                        <entry>
+                            El nombre de clase de un <literal>TransactionManagerLookup</literal>
+                            requerido cuando el chach&#x00e9; a nivel de JVM est&#x00e1;
+                            habilitado o cuando se usa un generador alto/bajo en un
+                            entorno JTA.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>classname.of.TransactionManagerLookup</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.flush_before_completion</literal>
+                        </entry>
+                        <entry>
+                            De habilitarse, la sesi&#x00f3;n se limpiar&#x00e1; (flushed)
+                            autom&#x00e1;ticamente durante la fase previa a la compleci&#x00f3;n
+                            de la transacci&#x00f3;n. (Muy &#x00fa;til cuando se usa Hibernate
+                            con CMT).
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.auto_close_session</literal>
+                        </entry>
+                        <entry>
+                            De habilitarse, la sesi&#x00f3;n ser&#x00e1; cerrada autom&#x00e1;ticamente
+                            durante la fase posterior a la compleci&#x00f3;n de la transacci&#x00f3;n.
+                            (Muy &#x00fa;til cuando se usa Hibernate con CMT).
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-misc-properties" revision="7">
+            <title>Propiedades Miscel&#x00e1;neas</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nombre de propiedad</entry>
+                        <entry>Prop&#x00f3;sito</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.query.factory_class</literal>
+                        </entry>
+                        <entry>
+                            Elige la implementaci&#x00f3;n de parser HQL.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> or
+                                <literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.query.substitutions</literal>
+                        </entry>
+                        <entry>
+                            Mapeos de s&#x00ed;mbolos en consultas Hibernate a 
+                            s&#x00ed;mbolos SQL. (los s&#x00ed;mbolos puedem ser
+                            nombres de funci&#x00f3;n o literales, por ejemplo).
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.hbm2ddl.auto</literal>
+                        </entry>
+                        <entry>
+                            Exporta autom&#x00e1;ticamente DDL de esquema cuando
+                            al crear la <literal>SessionFactory</literal>.
+                            Con <literal>create-drop</literal>, el esquema de
+                            base de datos ser&#x00e1; desechado cuando la
+                            <literal>SessionFactory</literal> se cierre expl&#x00ed;citamente.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>update</literal> | <literal>create</literal> | <literal>create-drop</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cglib.use_reflection_optimizer</literal>
+                        </entry>
+                        <entry>
+                            Habilita el uso de CGLIB en vez de reflecc&#x00f3;n en tiempo de
+                            ejecuci&#x00f3;n (propiedad a nivel de sistema). La reflecci&#x00f3;n
+                            a veces puede ser &#x00fa;til ante la aparici&#x00f3;n de problemas.
+                            Observa que Hibernate siempre requiere CGLIB incluso si desactivas
+                            el optimizador. No puedes establecer esta propiedad en
+                            <literal>hibernate.cfg.xml</literal>.
+                            <para>
+                                <emphasis role="strong">ej.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <sect2 id="configuration-optional-dialects" revision="1">
+            <title>SQL Dialects</title>
+
+            <para>
+                You should always set the <literal>hibernate.dialect</literal> property to the correct
+                <literal>org.hibernate.dialect.Dialect</literal> subclass for your database. If you
+                specify a dialect, Hibernate will use sensible defaults for some of the
+                other properties listed above, saving you the effort of specifying them manually.
+            </para>
+
+            <table frame="topbot" id="sql-dialects" revision="2">
+                <title>Dialectos SQL de Hibernate(<literal>hibernate.dialect</literal>)</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>RDBMS</entry>
+                            <entry>Dialecto</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry>DB2</entry> <entry><literal>org.hibernate.dialect.DB2Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>DB2 AS/400</entry> <entry><literal>org.hibernate.dialect.DB2400Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>DB2 OS390</entry> <entry><literal>org.hibernate.dialect.DB2390Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>PostgreSQL</entry> <entry><literal>org.hibernate.dialect.PostgreSQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL</entry> <entry><literal>org.hibernate.dialect.MySQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL con InnoDB</entry> <entry><literal>org.hibernate.dialect.MySQLInnoDBDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL con MyISAM</entry> <entry><literal>org.hibernate.dialect.MySQLMyISAMDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Oracle (cualquier versi&#x00f3;n)</entry> <entry><literal>org.hibernate.dialect.OracleDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Oracle 9i/10g</entry> <entry><literal>org.hibernate.dialect.Oracle9Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Sybase</entry> <entry><literal>org.hibernate.dialect.SybaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Sybase Anywhere</entry> <entry><literal>org.hibernate.dialect.SybaseAnywhereDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Microsoft SQL Server</entry> <entry><literal>org.hibernate.dialect.SQLServerDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>SAP DB</entry> <entry><literal>org.hibernate.dialect.SAPDBDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Informix</entry> <entry><literal>org.hibernate.dialect.InformixDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>HypersonicSQL</entry> <entry><literal>org.hibernate.dialect.HSQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Ingres</entry> <entry><literal>org.hibernate.dialect.IngresDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Progress</entry> <entry><literal>org.hibernate.dialect.ProgressDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Mckoi SQL</entry> <entry><literal>org.hibernate.dialect.MckoiDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Interbase</entry> <entry><literal>org.hibernate.dialect.InterbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Pointbase</entry> <entry><literal>org.hibernate.dialect.PointbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>FrontBase</entry> <entry><literal>org.hibernate.dialect.FrontbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Firebird</entry> <entry><literal>org.hibernate.dialect.FirebirdDialect</literal></entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-outerjoin" revision="4">
+            <title>Recuperaci&#x00f3;n por Uni&#x00f3;n Externa (Outer Join Fetching)</title>
+
+            <para>
+                Si tu base de datos soporta uniones externas del estilo ANSI, Oracle o Sybase, la
+                <emphasis>recuperaci&#x00f3;n por uni&#x00f3;n externa</emphasis> aumentar&#x00e1;
+                frecuentemente el rendimiento limitando el n&#x00fa;mero de llamadas a la base de datos
+                (al costo de m&#x00e1;s trabajo posiblemente realizado por la base de datos misma).
+                La recuperaci&#x00f3;n por uni&#x00f3;n externa permite que un grafo completo de objetos
+                conectados por asociaciones muchos-a-uno, uno-a-muchos, muchos-a-muchos y uno-a-uno sea
+                tra&#x00ed;do en una sola <literal>SELECT</literal> SQL.
+            </para>
+
+            <para>
+                La recuperaci&#x00f3;n por uni&#x00f3;n externa puede ser deshabilitada
+                <emphasis>globalmente</emphasis> estableciendo la propiedad
+                <literal>hibernate.max_fetch_depth</literal> a <literal>0</literal>.
+                Un valor de <literal>1</literal> o mayor habilita la recuperaci&#x00f3;n
+                por uni&#x00f3;n externa para asociaciones uno-a-uno y muchos-a-uno que
+                hayan sido mapeadas con <literal>fetch="join"</literal>.
+            </para>
+
+            <para>
+                Ver <xref linkend="performance-fetching"/> para m&#x00e1;s informaci&#x00f3;n.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-binarystreams" revision="1">
+            <title>Flujos Binarios</title>
+
+            <para>
+                Oracle limita el tama&#x00f1;o de arrays de <literal>byte</literal>
+                que puedan ser pasados a/desde su driver JDBC. Si deseas usar instancias
+                grandes de tipo <literal>binary</literal> o <literal>serializable</literal>,
+                debes habilitar <literal>hibernate.jdbc.use_streams_for_binary</literal>.
+                <emphasis>Esta es una propiedad a nivel de sistema solamente.</emphasis>
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-cacheprovider" revision="2">
+            <title>Cach&#x00e9; de segundo nivel y de lectura</title>
+
+            <para>
+                Las propiedades prefijadas por <literal>hibernate.cache</literal>
+                te permiten usar un sistema de cach&#x00e9; de segundo nivel
+                en el &#x00e1;mbito de un proceso o cluster con Hibernate.
+                Ver <xref linkend="performance-cache"/> para m&#x00e1;s detalles.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-querysubstitution">
+            <title>Sustituci&#x00f3;n de Lenguaje de Consulta</title>
+
+            <para>
+                Puedes definir nuevos s&#x00ed;mbolos de consulta de Hibernate usando
+                <literal>hibernate.query.substitutions</literal>. Por ejemplo:
+            </para>
+
+            <programlisting>hibernate.query.substitutions true=1, false=0</programlisting>
+
+            <para>
+                causar&#x00ed;a que los s&#x00ed;mbolos <literal>true</literal> y <literal>false</literal> sean
+                traducidos a literales enteros en el SQL generado.
+            </para>
+
+            <programlisting>hibernate.query.substitutions toLowercase=LOWER</programlisting>
+
+            <para>
+                te permitir&#x00ed;a renombrar la funci&#x00f3;n <literal>LOWER</literal> de SQL.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-statistics" revision="2">
+            <title>Hibernate statistics</title>
+
+            <para>
+                Si habilitas <literal>hibernate.generate_statistics</literal>, Hibernate
+                expondr&#x00e1; un n&#x00fa;mero de m&#x00e9;tricas que son &#x00fa;tiles
+                al afinar un sistema en ejecuci&#x00f3;n v&#x00ed;a
+                <literal>SessionFactory.getStatistics()</literal>. Hibernate puede incluso ser
+                configurado para exponer estas estad&#x00ed;sticas v&#x00ed;a JMX. Lee el
+                Javadoc de las interfaces en <literal>org.hibernate.stats</literal>
+                para m&#x00e1;s informaci&#x00f3;n.
+            </para>
+
+        </sect2>
+    </sect1>
+
+    <sect1 id="configuration-logging">
+        <title>Registros de mensajes (Logging)</title>
+
+        <para>
+            Hibernate registra varios eventos usando commons-logging
+            de Apache.
+        </para>
+
+        <para>
+            El servicio de commons-logging saldr&#x00e1; directamente ya sea a
+            Log4J (si incluyes <literal>log4j.jar</literal> in your classpath) o
+            JDK1.4 logging (al ejecutar bajo JDK1.4 o superior). Puedes descargar
+            Log4J desde <literal>http://logging.apache.org</literal>. Para usar
+            Log4J necesitar&#x00e1;s colocar un fichero <literal>log4j.properties</literal>
+            en tu classpath. Un fichero de propiedades de ejemplo se distribuye con
+            Hibernate en el directorio <literal>src/</literal>.
+        </para>
+        
+        <para>
+            Recomendamos fuertemente que te familiarices con los registros de mensajes
+            de Hibernate. Se ha puesto un gran trabajo en hacer los registros de Hibernate
+            tan detallados como se puede, sin hacerlos ilegibles. Es un dispositivo esencial
+            en la resoluci&#x00f3;n de problemas. Las categor&#x00ed;as de registro
+            m&#x00e1;s interesantes son las siguientes:
+        </para>
+        
+            <table frame="topbot" id="log-categories" revision="2">
+                <title>Categor&#x00ed;as de Registro de Hibernate</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>Categor&#x00ed;a</entry>
+                            <entry>Funci&#x00f3;n</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>org.hibernate.SQL</literal></entry>
+                            <entry>Registra todas las sentencias DML de SQL a
+                            medida que se ejecutan</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.type</literal></entry>
+                            <entry>Registra todos los par&#x00e1;metros JDBC</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.tool.hbm2ddl</literal></entry>
+                            <entry>Registra todas las sentencias DDL de SQL a
+                            medida que se ejecutan</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.pretty</literal></entry>
+                            <entry>
+                                Registra el estado de todas las entidades (m&#x00e1;ximo
+                                de 20 entidades) asociadas con la sesi&#x00f3;n en tiempo
+                                de limpieza (flush)
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.cache</literal></entry>
+                            <entry>Registra toda la actividad del cach&#x00e9; de segundo nivel</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction</literal></entry>
+                            <entry>Registra la actividad relacionada con la transacci&#x00f3;n</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.jdbc</literal></entry>
+                            <entry>Registra toda adquisici&#x00f3;n de recursos JDBC</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.hql.ast</literal></entry>
+                            <entry>Regista los ASTs de HQL y SQL, as&#x00ed; como
+                            otra informaci&#x00f3;n sobre an&#x00e1;lisis de consultas.</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.secure</literal></entry>
+                            <entry>Registra todas las peticiones de autorizaci&#x00f3;n JAAS</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate</literal></entry>
+                            <entry>
+                                Registra todo (mucha informaci&#x00f3;n, pero muy &#x00fa;til
+                                para la resoluci&#x00f3;n de problemas)
+                            </entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+            
+        <para>
+            Al desarrollar aplicacinoes con Hibernate, casi siempre debes trabajar con
+            <literal>debug</literal> habilitado para la categor&#x0ed;a <literal>org.hibernate.SQL</literal>
+            o, alternativamente, la propiedad <literal>hibernate.show_sql</literal> habilitada.
+        </para>
+                       
+        
+    </sect1>
+
+    <sect1 id="configuration-namingstrategy">
+        <title>Implementando una <literal>NamingStrategy</literal></title>
+
+        <para>
+            La interface <literal>org.hibernate.cfg.NamingStrategy</literal> te permite
+            especificar un "est&#x00e1;ndar de nombrado" para objetos de la base de datos
+            y elementos de esquema.
+        </para>
+
+        <para>
+            Puedes proveer reglas para generar autom&#x00e1;ticamente identificadores de
+            base de datos a partir de identificadores JDBC o para procesar nombres
+            "l&#x00f3;gicos" de columnas y tablas dados en el fichero de mapeo en nombres
+            "f&#x00ed;sicos" de columnas y tablas. Esta funcionalidad ayuda a reducir
+            la verborragia del documento de mapeo, eliminando ruido repetitivo
+            (prefijos <literal>TBL_</literal>, por ejemplo). La estrategia por defecto
+            usada por Hibernate m&#x00ed;nima en absoluto.
+        </para>
+
+        <para>
+            Puedes especificar una estrategia diferente llamando a 
+            <literal>Configuration.setNamingStrategy()</literal> antes de agregar los mapeos:
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sf = new Configuration()
+    .setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
+    .addFile("Item.hbm.xml")
+    .addFile("Bid.hbm.xml")
+    .buildSessionFactory();]]></programlisting>
+    
+        <para>
+            <literal>org.hibernate.cfg.ImprovedNamingStrategy</literal>
+            es una estrategia prefabricada que puede ser un punto de
+            partida &#x00fa;til para algunas aplicaciones.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-xmlconfig" revision="2">
+        <title>Fichero de configuraci&#x00f3;n XML</title>
+
+        <para>
+            Un enfoque alternativo de configuraci&#x00f3;n es especificar una
+            configuraci&#x00f3;n completa en un fichero llamado <literal>hibernate.cfg.xml</literal>.
+            Este fichero puede ser usado como un remplazo del fichero <literal>hibernate.properties</literal> o,
+            si ambos est&#x00e1;n presentes, para sobrescribir propiedades.
+        </para>
+
+        <para>
+            El fichero de configuraci&#x00f3;n XML se espera por defecto en la
+            ra&#x00ed;z o tu <literal>CLASSPATH</literal>. He aqu&#x00ed; un ejemplo:
+        </para>
+
+        <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+    "-//Hibernate/Hibernate Configuration DTD//EN"
+    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <!-- a SessionFactory instance listed as /jndi/name -->
+    <session-factory
+        name="java:hibernate/SessionFactory">
+
+        <!-- properties -->
+        <property name="connection.datasource">java:/comp/env/jdbc/MyDB</property>
+        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
+        <property name="show_sql">false</property>
+        <property name="transaction.factory_class">
+            org.hibernate.transaction.JTATransactionFactory
+        </property>
+        <property name="jta.UserTransaction">java:comp/UserTransaction</property>
+
+        <!-- mapping files -->
+        <mapping resource="org/hibernate/auction/Item.hbm.xml"/>
+        <mapping resource="org/hibernate/auction/Bid.hbm.xml"/>
+
+        <!-- cache settings -->
+        <class-cache class="org.hibernate.auction.Item" usage="read-write"/>
+        <class-cache class="org.hibernate.auction.Bid" usage="read-only"/>
+        <collection-cache collection="org.hibernate.auction.Item.bids" usage="read-write"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+            Como puedes ver, la ventaja de este enfoque es la externalizaci&#x00f3;n de los
+            nombres de los fichero de mapeo a configuraci&#x00f3;n. El
+            <literal>hibernate.cfg.xml</literal> es tambi&#x00e9;n m&#x00e1;s conveniente
+            una vez que hayas afinado el cach&#x00e9; de Hibernate. Observa que elecci&#x00f3;n
+            tuya usar ya sea <literal>hibernate.properties</literal> o
+            <literal>hibernate.cfg.xml</literal>, ambos son equivalentes, excepto por los
+            beneficios de usar la sintaxis XML arriba mencionados.
+        </para>
+
+       <para>
+           Con la configuraci&#x00f3;n XML, arrancar Hibernate es tan simple como
+       </para>
+
+       <programlisting><![CDATA[SessionFactory sf = new Configuration().configure().buildSessionFactory();]]></programlisting>
+
+       <para>
+           Puedes tomar un fichero XML diferente usando
+       </para>
+
+       <programlisting><![CDATA[SessionFactory sf = new Configuration()
+    .configure("catdb.cfg.xml")
+    .buildSessionFactory();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="configuration-j2ee" revision="1">
+        <title>Integraci&#x00f3; con Servidores de Aplicaciones J2EE</title>
+
+        <para>
+            Hibernate tiene los siguientes puntos de integraci&#x00f3;n con la
+            infraestructura J2EE:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>Datasources manejados por contenedor</emphasis>: Hibernate puede usar
+                conexiones JDBC manejadas por el contenedor y provistas a trav&#x00e9;s de JNDI.
+                Usualmente, un <literal>TransactionManager</literal> compatible con JTA y un
+                <literal>ResourceManager</literal> cuidan del manejo de transacciones (CMT),
+                esp. manejo de transacciones distribu&#x00ed;das a trav&#x00e9;s de varios
+                datasources. Puedes tambi&#x00e9;n, por supuesto, demarcar los l&#x00ed;mites
+                de las transacciones program&#x00e1;ticamente (BMT) o podr&#x00ed;as querer usar
+                para esto la API opcional de <literal>Transaction</literal> de Hibernate para
+                mantener tu c&#x00f3;digo portable.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>Ligamento Autom&#x00e1;tico JNDI</emphasis>: Hibernate puede ligar sus
+                <literal>SessionFactory</literal> a JNDI despu&#x00e9;s del arranque.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>Ligamento de Sesi&#x00f3;n JTA:</emphasis>
+                La <literal>Session</literal> de Hibernate puede ser ligada autom&#x00e1;ticamente
+                al &#x00e1;mbito de transacciones JTA si usas EJBs. Simplemente busca la
+                <literal>SessionFactory</literal> de JNDI y obt&#x00e9;n la <literal>Session</literal>
+                actual. Deja que Hibernate cuide de limpiar y cerrar la <literal>Session</literal>
+                cuando se complete tu transacci&#x00f3;n JTA. La demarcaci&#x00f3;n de transacci&#x00f3;n
+                es declarativa, en descriptores de despliegue de EJB.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>Despliegue JMX:</emphasis> Si tienes un servidor de aplicaciones capaz
+                de JMX (por ejemplo, JBoss AS), puedes optar por desplegar Hibernate como un MBean
+                manejado. Esto te ahorra el c&#x00f3;digo de una l&#x00ed;nea de arranque para
+                construir tu <literal>SessionFactory</literal> desde una <literal>Configuration</literal>.
+                El contenedor arrancar&#x00e1; tu <literal>HibernateService</literal>, e idealmente tambi&#x00e9;n
+                cuidar&#x00e1; de las dependencias entre servicios (El datasource debe estar
+                disponible antes que arranque Hibernate, etc).
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Dependiendo de tu entorno, podr&#x00ed;as tener que establecer la opci&#x00f3;n
+            de configuraci&#x00f3;n <literal>hibernate.connection.aggressive_release</literal>
+            a true si tu servidor de aplicaciones muestra excepciones "connection containment".
+        </para>
+
+        <sect2 id="configuration-optional-transactionstrategy" revision="3">
+            <title>Configuraci&#x00f3;n de la estrategia de transacci&#x00f3;n</title>
+
+            <para>
+                La API de <literal>Session</literal> de Hibernate es independiente de cualquier
+                demarcaci&#x00f3;n de transacci&#x00f3;n en tu arquitectura. Si dejas que Hibernate
+                use JDBC directamente, a trav&#x00e9;s de un pool de conexiones. puedes comenzar y
+                acabar tus transacciones llamando la API de JDBC. Si ejecutas en un servidor de
+                aplicaciones J2EE, podr&#x00e9;as querer usar transacciones manejadas por bean y
+                llamar la API de JTA y <literal>UserTransaction</literal> cuando sea necesario.
+            </para>
+
+            <para>
+                Para mantener tu c&#x00f3;digo portable entre estos dos (y otros) entornos recomendamos la API
+                de <literal>Transaction</literal> de Hibernate, que envuelve y oculta el sistema subyacente.
+                Tienes que especificar una clase f&#x00e1;brica para las instancias de <literal>Transaction</literal>
+                estableciendo la propiedad de configuraci&#x00f3;n <literal>hibernate.transaction.factory_class</literal>
+                de Hibernate.
+            </para>
+
+            <para>
+                Hay tres elecciones est&#x00e1;ndar (prefabricadas):
+            </para>
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.JDBCTransactionFactory</literal></term>
+                    <listitem>
+                        <para>delega a transacciones de base de datos (JDBC) (por defecto)</para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.JTATransactionFactory</literal></term>
+                    <listitem>
+                        <para>
+                            delega a transacciones manejadas por contenedor si una transacci&#x00f3;n
+                            existente est&#x00f3; por debajo en este contexto (ej. m&#x00e9;todo de un
+                            bean de sesi&#x00f3;n EJB), en otro caso una nueva transacci&#x00f3;n es
+                            comenzada y se usan transacciones manejadas por bean.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.CMTTransactionFactory</literal></term>
+                    <listitem>
+                        <para>delega a transacciones JTA manejadas por contenedor</para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+            <para>
+                Puedes definir tambi&#x00e9;n tus propias estrategias de transacci&#x00f3;n
+                (para un servicio de transacci&#x00f3;n CORBA, por ejemplo).
+            </para>
+
+            <para>
+                Algunas funcionalidades en Hibernate (ej, el cach&#x00e9; de segundo nivel, ligamento
+                autom&#x00e1;tico de JTA y Session, etc.) requieren acceso al <literal>TransactionManager</literal>
+                de JTA en un entorno manejado. En un servidor de aplicaciones tienes que especificar
+                c&#x00f3;mo Hibernate debe obtener una referencia al <literal>TransactionManager</literal>,
+                pues J2EE no estandariza un solo mecanismo:
+            </para>
+
+            <table frame="topbot" id="jtamanagerlookup" revision="1">
+                <title>TransactionManagers de JTA</title>
+                <tgroup cols="2">
+                    <colspec colwidth="2.5*"/>
+                    <colspec colwidth="1*"/>
+                    <thead>
+                        <row>
+                            <entry>Transaction Factory</entry>
+                            <entry align="center">Servidor de Aplicaciones</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JBossTransactionManagerLookup</literal></entry>
+                            <entry align="center">JBoss</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WeblogicTransactionManagerLookup</literal></entry>
+                            <entry align="center">Weblogic</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WebSphereTransactionManagerLookup</literal></entry>
+                            <entry align="center">WebSphere</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</literal></entry>
+                            <entry align="center">WebSphere 6</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.OrionTransactionManagerLookup</literal></entry>
+                            <entry align="center">Orion</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.ResinTransactionManagerLookup</literal></entry>
+                            <entry align="center">Resin</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JOTMTransactionManagerLookup</literal></entry>
+                            <entry align="center">JOTM</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JOnASTransactionManagerLookup</literal></entry>
+                            <entry align="center">JOnAS</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JRun4TransactionManagerLookup</literal></entry>
+                            <entry align="center">JRun4</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.BESTransactionManagerLookup</literal></entry>
+                            <entry align="center">Borland ES</entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-jndi" revision="2">
+            <title><literal>SessionFactory</literal> ligada a JNDI</title>
+
+            <para>
+                Una <literal>SessionFactory</literal> de Hibernate ligada a JNDI puede simplificar
+                la obtenci&#x00f3;n de la f&#x00e1;brica y la creaci&#x00f3;n de nuevas
+                <literal>Session</literal>s. Observa que esto no est&#x00e1; relacionado a un
+                <literal>Datasource</literal> ligado a JNDI, simplemente ambos usan el mismo
+                registro!
+            </para>
+
+            <para>
+                Si deseas tener la <literal>SessionFactory</literal> ligada a un espacio de nombres de JNDI,
+                especifica un nombre (ej. <literal>java:hibernate/SessionFactory</literal>) usando la
+                propiedad <literal>hibernate.session_factory_name</literal>. Si esta propiedad es omitida,
+                la <literal>SessionFactory</literal> no ser&#x00e1; ligada a JNDI (Esto es especialmente
+                &#x00fa;til en entornos con una implementaci&#x00f3; JNDI de s&#x00f3;lo lectura por defecto,
+                ej. Tomcat.)
+            </para>
+
+            <para>
+                Al ligar la <literal>SessionFactory</literal> a JNDI, Hibernate usar&#x00e1; los valores de
+                <literal>hibernate.jndi.url</literal>, <literal>hibernate.jndi.class</literal> para instanciar
+                un contexto inicial. Si &#x00e9;tos no se especifican, se usar&#x00e1; el
+                <literal>InitialContext</literal> por defecto.
+            </para>
+
+            <para>
+                Hibernate colocar&#x00e1; autom&#x00e1;ticamente la <literal>SessionFactory</literal>
+                en JNDI despu&#x00e9;s que llames a <literal>cfg.buildSessionFactory()</literal>.
+                Esto significa que tendr&#x00e1;s al menos esta llamada en alg&#x00fa;n c&#x00f3;digo
+                de arranque (o clase de utilidad) en tu aplicaci&#x00f3;n, a menos qie uses el despliegue
+                JMX con el <literal>HibernateService</literal> (discutido luego).
+            </para>
+
+            <para>
+                Si usas una <literal>SessionFactory</literal> de JNDI, un EJB o cualquier otra
+                clase puede obtener la <literal>SessionFactory</literal> usando una b&#x00fa;squeda
+                JNDI. Observa que esta configuraci&#x00f3;n no es necesaria si usas la clase de ayuda
+                <literal>HibernateUtil</literal> introducida en el cap&#x00ed;tulo uno, que act&#x00fa;a
+                como un registro Singleton. Sin embargo, <literal>HibernateUtil</literal> es m&#x00e1;s
+                com&#x00fa;n en un entorno no manejado.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-j2ee-currentsession" revision="1">
+            <title>Ligado autom&#x00e1;tico de JTA y Session</title>
+
+            <para>
+                Para entornos no manejados hemos sugerido <literal>HibernateUtil</literal> con una
+                <literal>SessionFactory</literal> est&#x00e1;tica, y administraci&#x00f3;n de la
+                <literal>Session</literal> de Hibernate. Este enfoque no es f&#x00e1;cil de usar
+                en un entorno EJB, al poder ejecutarse muchos EJBs dentro de la misma transacci&#x00f3;n
+                pero no en la misma hebra. Recomendados que ligues la <literal>SessionFactory</literal>
+                a JNDI en un entorno manejado.
+            </para>
+
+            <para>
+                En vez de rodar tu propia utilidad de <literal>ThreadLocal</literal>,
+                usa el m&#x00e9;todo <literal>getCurrentSession()</literal> en la
+                <literal>SessionFactory</literal> para obtener una <literal>Session</literal>
+                de Hibernate. Si no hubiese una <literal>Session</literal> de Hibernate en la
+                transacci&#x00f3;n JTA actual, se arrancar&#x00e1; y asignar&#x00e1; una.
+                Ambas opciones de configuraci&#x00f3;n <literal>hibernate.transaction.flush_before_completion</literal>
+                y <literal>hibernate.transaction.auto_close_session</literal>, ser&#x00e1;n establecidas
+                autom&#x00e1;ticamente para cada <literal>Session</literal> que obtengas con
+                <literal>getCurrentSession()</literal>, de modo que &#x00e9;stas ser&#x00e1;n
+                limpiadas (flushed) y cerradas autom&#x00e1;ticamente cuando el contenedor complete
+                las transacciones JTA.
+            </para>
+
+            <para>
+                Si tu, por ejemplo, usas el patr&#x00f3;n de dise&#x00f1;o DAO para escribir tu
+                capa de persistencia, todos los DAO's buscan la <literal>SessionFactory</literal>
+                cuando se necesite y abren la sesi&#x00f3;n "actual". No hay necesidad de pasar
+                las instancias de <literal>SessionFactory</literal> o <literal>Session</literal>
+                alrededor entre el c&#x00f3;digo de control y el c&#x00f3;digo DAO.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-j2ee-jmx" revision="1">
+            <title>Despliegue JMX</title>
+
+            <para>
+                La l&#x00ed;nea <literal>cfg.buildSessionFactory()</literal> todav&#x00ed;a tiene
+                que ser ejecutada en algun sitio para obtener una <literal>SessionFactory</literal>
+                en JNDI. Puedes hacer esto bien en un bloque inicializador <literal>static</literal>
+                (como aquel en <literal>HibernateUtil</literal>) o bien despliegas Hibernate como un
+                <emphasis>servicio manejado</emphasis>.
+            </para>
+
+            <para>
+                Hibernate se distribuye con <literal>org.hibernate.jmx.HibernateService</literal>
+                para despliegue en un servidor de aplicaciones con capacidades JMX, como JBoss AS.
+                El despliegue y la configurac&#x00f3;n reales son espec&#x00ed;ficos del vendedor.
+                He aqu&#x00ed; un <literal>jboss-service.xml</literal> de ejemplo para JBoss 4.0.x:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<server>
+
+<mbean code="org.hibernate.jmx.HibernateService"
+    name="jboss.jca:service=HibernateFactory,name=HibernateFactory">
+
+    <!-- Required services -->
+    <depends>jboss.jca:service=RARDeployer</depends>
+    <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends>
+
+    <!-- Bind the Hibernate service to JNDI -->
+    <attribute name="JndiName">java:/hibernate/SessionFactory</attribute>
+
+    <!-- Datasource settings -->
+    <attribute name="Datasource">java:HsqlDS</attribute>
+    <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>
+
+    <!-- Transaction integration -->
+    <attribute name="TransactionStrategy">
+        org.hibernate.transaction.JTATransactionFactory</attribute>
+    <attribute name="TransactionManagerLookupStrategy">
+        org.hibernate.transaction.JBossTransactionManagerLookup</attribute>
+    <attribute name="FlushBeforeCompletionEnabled">true</attribute>
+    <attribute name="AutoCloseSessionEnabled">true</attribute>
+
+    <!-- Fetching options -->
+    <attribute name="MaximumFetchDepth">5</attribute>
+
+    <!-- Second-level caching -->
+    <attribute name="SecondLevelCacheEnabled">true</attribute>
+    <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute>
+    <attribute name="QueryCacheEnabled">true</attribute>
+
+    <!-- Logging -->
+    <attribute name="ShowSqlEnabled">true</attribute>
+
+    <!-- Mapping files -->
+    <attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute>
+
+</mbean>
+
+</server>]]></programlisting>
+
+            <para>
+                Este fichero es desplegado en un directorio llamado <literal>META-INF</literal> y
+                empaquetado en un fichero JAR con la extensi&#x00f3;n <literal>.sar</literal>
+                (fichero de servicio). Tambi&#x00e9;n necesitas empaquetar Hibernate, sus bibliotecas
+                de terceros requeridas, tus clases persistentes compiladas, as&#x00ed; como tus ficheros de mapeo
+                en el mismo fichero. Tus beans de empresa (usualmente beans de sesi&#x00f3;n) pueden ser
+                mantenidos en su propio fichero JAR, pero debes incluir este fichero EJB JAR en el fichero
+                de servicio principal para obtener una unidad desplegable (en caliente). Consulta la documentaci&#x00f3;n
+                de JBoss AS para m&#x00e1;s informaci&#x00f3;n sobre el servicio JMX y despliegue de EJB.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/events.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/events.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/events.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,233 @@
+<chapter id="events">
+    <title>Interceptores y eventos</title>
+
+    <para>
+        Frecuentemente es &#x00fa;til para la aplicaci&#x00f3;n reaccionar a ciertos eventos que ocurran dentro de Hibernate.
+        Esto permite la implementaci&#x00f3;n de ciertos tipos de funcionalidade gen&#x00e9;rica, y extensi&#x00f3;n de la
+        funcionalidad de Hibernate.
+    </para>
+
+    <sect1 id="objectstate-interceptors" revision="1">
+        <title>Interceptores</title>
+
+        <para>
+            La interface <literal>Interceptor</literal> provee callbacks desde la sesi&#x00f3;n a la aplicaci&#x00f3;n
+            permitiendo a &#x00e9;sta &#x00fa;ltima inspeccionar y/o manipular las propiedades de un objeto persistente
+            antes que sea salvado, actualizado, borrado o cargado. Un uso posible de esto es seguir la pista
+            de informaci&#x00f3;n de auditor&#x00ed;a. Por ejemplo, el siguiente <literal>Interceptor</literal> establece
+            autom&#x00e1;ticamente el <literal>createTimestamp</literal> cuando un <literal>Auditable</literal> es
+            creado y actualiza la propiedad <literal>lastUpdateTimestamp</literal> cuando un
+            <literal>Auditable</literal> es acutalizado.
+        </para>
+
+        <programlisting><![CDATA[package org.hibernate.test;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.hibernate.Interceptor;
+import org.hibernate.type.Type;
+
+public class AuditInterceptor implements Interceptor, Serializable {
+
+    private int updates;
+    private int creates;
+
+    public void onDelete(Object entity,
+                         Serializable id,
+                         Object[] state,
+                         String[] propertyNames,
+                         Type[] types) {
+        // do nothing
+    }
+
+    public boolean onFlushDirty(Object entity,
+                                Serializable id,
+                                Object[] currentState,
+                                Object[] previousState,
+                                String[] propertyNames,
+                                Type[] types) {
+
+        if ( entity instanceof Auditable ) {
+            updates++;
+            for ( int i=0; i < propertyNames.length; i++ ) {
+                if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
+                    currentState[i] = new Date();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean onLoad(Object entity,
+                          Serializable id,
+                          Object[] state,
+                          String[] propertyNames,
+                          Type[] types) {
+        return false;
+    }
+
+    public boolean onSave(Object entity,
+                          Serializable id,
+                          Object[] state,
+                          String[] propertyNames,
+                          Type[] types) {
+
+        if ( entity instanceof Auditable ) {
+            creates++;
+            for ( int i=0; i<propertyNames.length; i++ ) {
+                if ( "createTimestamp".equals( propertyNames[i] ) ) {
+                    state[i] = new Date();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void postFlush(Iterator entities) {
+        System.out.println("Creations: " + creates + ", Updates: " + updates);
+    }
+
+    public void preFlush(Iterator entities) {
+        updates=0;
+        creates=0;
+    }
+
+    ...
+
+}]]></programlisting>
+
+        <para>
+            El interceptor podr&#x00ed;a ser especificado cuando se crea la sesi&#x00f3;n:
+        </para>
+
+        <programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
+
+        <para>
+            Puedes adem&#x00e1;s establecer un interceptor a un nivel global, usando la <literal>Configuration</literal>:
+        </para>
+    
+        <programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
+
+    </sect1>
+
+     <sect1 id="objectstate-events" revision="2">
+        <title>Sistema de eventos</title>
+
+        <para>
+            Si tienes que reaccionar a eventos particulares en tu capa de persistencia, puedes tambi&#x00e9;n la
+            arquitectura de <emphasis>eventos</emphasis> de Hibernate3. El sistema de eventos puede ser usado
+            en adici&#x00f3;n o como un remplazo a los interceptores.
+        </para>
+
+        <para>
+            Esencialmente todos los m&#x00e9;todos de la interface <literal>Session</literal> se correlacionan
+            con un evento. Tienes un <literal>LoadEvent</literal>, un <literal>FlushEvent</literal>, etc
+            (consulta el DTD del fichero de configuraci&#x00f3;n XML o el paquete <literal>org.hibernate.event</literal>
+            para la lista completa de tipos de evento definidos). Cuando se hace una petici&#x00f3;n de uno de estos
+            m&#x00e9;todos, la <literal>Session</literal> de Hibernate genera un evento apropiado y se lo pasa
+            al oyente (listener) de eventos configurado para ese tipo. De f&#x00e1;brica, estos oyentes implementan
+            el mismo procesamiento en los que siempre resultan aquellos m&#x00e9;todos. Sin embargo, eres libre de
+            implementar una personalizaci&#x00f3;n de una de las interfaces oyentes (es decir, el
+            <literal>LoadEvent</literal>  es procesado por la implementaci&#x00f3;n registrada de la interface
+            <literal>LoadEventListener</literal>), en cuyo caso su implementaci&#x00f3;n ser&#x00ed;a responsable
+            de procesar cualquier petici&#x00f3;n <literal>load()</literal> hecha a la <literal>Session</literal>.
+        </para>
+
+        <para>
+            Los oyentes deben ser considerados efectivamente singletons; quiere decir, que son compartidos
+            entre las peticiones, y por lo tanto no guardan ning&#x00fa;n estado en variables de instancia.
+        </para>
+
+        <para>
+            Un oyente personalizado debe implementar la interface apropiada para el evento que quiere procesar y/o
+            extender una de las clases base de conveniencia (o incluso los oyentes de eventos por defecto
+            usados por Hibernate de f&#x00e1;brica al ser &#x00e9;stos declarados non-final para este prop&#x00f3;sito). Los
+            oyentes personalizados pueden ser registrados program&#x00e1;ticamente a trav&#x00e9;s del objeto
+            <literal>Configuration</literal>, o especificados en el XML de configuraci&#x00f3;n de Hibernate
+            (la declaraci&#x00f3;n declarativa a trav&#x00e9;s del fichero de propiedades no est&#x00e1; soportada).
+            He aqu&#x00ed; un ejemplo de un oyente personalizado de eventos load:
+        </para>
+
+        <programlisting><![CDATA[public class MyLoadListener extends DefaultLoadEventListener {
+    // this is the single method defined by the LoadEventListener interface
+    public Object onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
+            throws HibernateException {
+        if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
+            throw MySecurityException("Unauthorized access");
+        }
+        return super.onLoad(event, loadType);
+    }
+}]]></programlisting>
+
+        <para>
+            Necesitas adem&#x00e1;s una entrada de configuraci&#x00f3;n dici&#x00e9;ndole a Hibernate que use el
+            oyente en vez del oyente por defecto:
+        </para>
+
+<programlisting><![CDATA[<hibernate-configuration>
+    <session-factory>
+        ...
+        <listener type="load" class="MyLoadListener"/>
+    </session-factory>
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+            En cambio, puedes registrarlo program&#x00e1;ticamente:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration();
+cfg.getSessionEventListenerConfig().setLoadEventListener( new MyLoadListener() );]]></programlisting>
+
+        <para>
+            Los oyentes registrados declarativamente no pueden compartir instancias. Si el mismo nombre de clase es
+            usado en m&#x00fa;ltiples elementos <literal>&lt;listener/&gt;</literal>, cada referencia resultar&#x00e1; en una instancia
+            separada de esa clase. Si necesitas la capacidad de compartir instancias de oyentes entre tipos de oyente
+            debes usar el enfoque de registraci&#x00f3;n program&#x00e1;tica.
+        </para>
+
+        <para>
+            &#x00bf;Por qu&#x00e9; implementar una interface y definir el tipo espc&#x00ed;fico durante la configuraci&#x00f3;n?
+            Bueno, una implementaci&#x00f3;n de oyente podr&#x00ed;a implementar m&#x00fa;ltiples interfaces de oyente
+            de eventos. Teniendo el tipo definido adicionalmente durante la registraci&#x00f3;n lo hace m&#x00e1;s
+            f&#x00e1;cil para activar o desactivar oyentes personalizados durante la configuraci&#x00f3;n.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="objectstate-decl-security">
+        <title>Seguridad declarativa de Hibernate</title>
+        <para>
+            Usualmente, la seguridad declarativa en aplicaciones Hibernate es manejada en una capa  de fachada
+            de sesi&#x00f3;n. Ahora, Hibernate3 permite que ciertas acciones sean permitidas v&#x00ed;a JACC, y autorizadas v&#x00ed;a
+            JAAS. Esta en una funcionalidad opcional constru&#x00ed;da encima de la arquitectura de eventos.
+        </para>
+        
+        <para>
+            Primero, debes configurar los oyentes de eventos apropiados, para habilitar el uso de
+            autorizaci&#x00f3;n JAAS.
+        </para>
+        
+        <programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
+<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
+<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
+<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
+
+        <para>
+            Seguido, a&#x00fa;n en <literal>hibernate.cfg.xml</literal>, liga los permisos a roles:
+        </para>
+        
+        <programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
+<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
+        
+        <para>
+            Los nombres de role son los roles entendidos por tu proveedor de JACC.
+        </para>
+       
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/example_mappings.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/example_mappings.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/example_mappings.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,654 @@
+<chapter id="example-mappings">
+    <title>Ejemplo: Varios Mapeos</title>
+    
+    <para>
+        Este cap&#x00ed;tulo muestra mapeos de asociaciones m&#x00e1;s complejos.
+    </para>
+    
+    <sect1 id="example-mappings-emp">
+        <title>Empleador/Empleado</title>
+
+        <para>
+            El siguiente modelo de la relaci&#x00f3;n entre <literal>Employer</literal> y <literal>Employee</literal> 
+            usa una clase de entidad real (<literal>Employment</literal>) para representar la asociaci&#x00f3;n.
+            Esto se ha hecho esto porque podr&#x00ed;a haber m&#x00e1;s de un per&#x00ed;odo de empleo para los mismos dos participantes.
+            Se usan componentes para modelar valores monetarios y nombres de empleado.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/EmployerEmployee.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/EmployerEmployee.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            He aqu&#x00ed; un documento de mapeo posible:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+        
+    <class name="Employer" table="employers">
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employer_id_seq</param>
+            </generator>
+        </id>
+        <property name="name"/>
+    </class>
+
+    <class name="Employment" table="employment_periods">
+
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employment_id_seq</param>
+            </generator>
+        </id>
+        <property name="startDate" column="start_date"/>
+        <property name="endDate" column="end_date"/>
+
+        <component name="hourlyRate" class="MonetaryAmount">
+            <property name="amount">
+                <column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>
+            </property>
+            <property name="currency" length="12"/>
+        </component>
+
+        <many-to-one name="employer" column="employer_id" not-null="true"/>
+        <many-to-one name="employee" column="employee_id" not-null="true"/>
+
+    </class>
+
+    <class name="Employee" table="employees">
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employee_id_seq</param>
+            </generator>
+        </id>
+        <property name="taxfileNumber"/>
+        <component name="name" class="Name">
+            <property name="firstName"/>
+            <property name="initial"/>
+            <property name="lastName"/>
+        </component>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        Y he aqu&#x00ed; el esquema de tablas generado por <literal>SchemaExport</literal>.
+    </para>
+
+    <programlisting><![CDATA[create table employers (
+    id BIGINT not null, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+create table employment_periods (
+    id BIGINT not null,
+    hourly_rate NUMERIC(12, 2),
+    currency VARCHAR(12), 
+    employee_id BIGINT not null, 
+    employer_id BIGINT not null, 
+    end_date TIMESTAMP, 
+    start_date TIMESTAMP, 
+    primary key (id)
+)
+
+create table employees (
+    id BIGINT not null, 
+    firstName VARCHAR(255), 
+    initial CHAR(1), 
+    lastName VARCHAR(255), 
+    taxfileNumber VARCHAR(255), 
+    primary key (id)
+)
+
+alter table employment_periods 
+    add constraint employment_periodsFK0 foreign key (employer_id) references employers
+alter table employment_periods 
+    add constraint employment_periodsFK1 foreign key (employee_id) references employees
+create sequence employee_id_seq
+create sequence employment_id_seq
+create sequence employer_id_seq]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="example-mappings-authorwork">
+        <title>Autor/Obra</title>
+
+        <para>
+            Considera el siguiente modelo de las relaciones entre <literal>Work</literal>,
+            <literal>Author</literal> y <literal>Person</literal>. Representamos la relaci&#x00f3;n entre <literal>Work</literal>
+            y <literal>Author</literal> como una asociaci&#x00f3;n muchos-a-muchos. Elegimos representar la relaci&#x00f3;n entre
+            <literal>Author</literal> y <literal>Person</literal> como una asociaci&#x00f3;n uno-a-uno. Otra posibilidad
+            hubiese sido que <literal>Author</literal> extendiera <literal>Person</literal>.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/AuthorWork.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/AuthorWork.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            El siguiente documento de mapeo representa estas relaciones correctamente:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Work" table="works" discriminator-value="W">
+
+        <id name="id" column="id">
+            <generator class="native"/>
+        </id>
+        <discriminator column="type" type="character"/>
+
+        <property name="title"/>
+        <set name="authors" table="author_work">
+            <key column name="work_id"/>
+            <many-to-many class="Author" column name="author_id"/>
+        </set>
+
+        <subclass name="Book" discriminator-value="B">
+            <property name="text"/>
+        </subclass>
+
+        <subclass name="Song" discriminator-value="S">
+            <property name="tempo"/>
+            <property name="genre"/>
+        </subclass>
+
+    </class>
+
+    <class name="Author" table="authors">
+
+        <id name="id" column="id">
+            <!-- The Author must have the same identifier as the Person -->
+            <generator class="assigned"/> 
+        </id>
+
+        <property name="alias"/>
+        <one-to-one name="person" constrained="true"/>
+
+        <set name="works" table="author_work" inverse="true">
+            <key column="author_id"/>
+            <many-to-many class="Work" column="work_id"/>
+        </set>
+
+    </class>
+
+    <class name="Person" table="persons">
+        <id name="id" column="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        Hay cuatro tablas en este mapeo. <literal>works</literal>, <literal>authors</literal> y <literal>persons</literal>
+        tienen los datos de obra, autor y persona respectivamente. <literal>author_work</literal> es una tabla de
+        asociaci&#x00f3;n enlazando autores a obras. He aqu&#x00ed; el esquema de tablas, tal como fue generado por
+        <literal>SchemaExport</literal>.
+    </para>
+
+    <programlisting><![CDATA[create table works (
+    id BIGINT not null generated by default as identity, 
+    tempo FLOAT, 
+    genre VARCHAR(255), 
+    text INTEGER, 
+    title VARCHAR(255), 
+    type CHAR(1) not null, 
+    primary key (id)
+)
+
+create table author_work (
+    author_id BIGINT not null, 
+    work_id BIGINT not null, 
+    primary key (work_id, author_id)
+)
+
+create table authors (
+    id BIGINT not null generated by default as identity, 
+    alias VARCHAR(255), 
+    primary key (id)
+)
+
+create table persons (
+    id BIGINT not null generated by default as identity, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+alter table authors 
+    add constraint authorsFK0 foreign key (id) references persons
+alter table author_work 
+    add constraint author_workFK0 foreign key (author_id) references authors
+alter table author_work
+    add constraint author_workFK1 foreign key (work_id) references works]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-mappings-customerorderproduct">
+        <title>Cliente/Orden/Producto</title>
+
+        <para>
+            Ahora considera un modelo de las relaciones entre <literal>Customer</literal>,
+            <literal>Order</literal> y <literal>LineItem</literal> y <literal>Product</literal>.
+            Hay una asociaci&#x00f3;n uno-a-muchos entre <literal>Customer</literal> y <literal>Order</literal>,
+            pero, &#x00bf;c&#x00f3;mo deber&#x00ed;amos representar <literal>Order</literal> / <literal>LineItem</literal> / <literal>Product</literal>? 
+            He elegido mapear <literal>LineItem</literal> como una clase de asociaci&#x00f3;n representando la
+            asociaci&#x00f3;n muchos-a-muchos entre <literal>Order</literal> y <literal>Product</literal>. En Hibernate,
+            esto se llama un elemento compuesto.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            El documento de mapeo:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Customer" table="customers">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+        <set name="orders" inverse="true">
+            <key column="customer_id"/>
+            <one-to-many class="Order"/>
+        </set>
+    </class>
+
+    <class name="Order" table="orders">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="date"/>
+        <many-to-one name="customer" column="customer_id"/>
+        <list name="lineItems" table="line_items">
+            <key column="order_id"/>
+            <list-index column="line_number"/>
+            <composite-element class="LineItem">
+                <property name="quantity"/>
+                <many-to-one name="product" column="product_id"/>
+            </composite-element>
+        </list>
+    </class>
+
+    <class name="Product" table="products">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="serialNumber"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        <literal>customers</literal>, <literal>orders</literal>, <literal>line_items</literal> y
+        <literal>products</literal> tienen los datos de cliente, orden, &#x00ed;tem de l&#x00ed;nea de orden y producto
+        respectivamente. Adem&#x00e1;s <literal>line_items</literal> act&#x00fa;a como una tabla de asociaci&#x00f3;n enlazando
+        &#x00f3;rdenes con productos.
+    </para>
+
+    <programlisting><![CDATA[create table customers (
+    id BIGINT not null generated by default as identity, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+create table orders (
+    id BIGINT not null generated by default as identity, 
+    customer_id BIGINT, 
+    date TIMESTAMP, 
+    primary key (id)
+)
+
+create table line_items (
+    line_number INTEGER not null, 
+    order_id BIGINT not null, 
+    product_id BIGINT, 
+    quantity INTEGER, 
+    primary key (order_id, line_number)
+)
+
+create table products (
+    id BIGINT not null generated by default as identity, 
+    serialNumber VARCHAR(255), 
+    primary key (id)
+)
+
+alter table orders 
+    add constraint ordersFK0 foreign key (customer_id) references customers
+alter table line_items
+    add constraint line_itemsFK0 foreign key (product_id) references products
+alter table line_items
+    add constraint line_itemsFK1 foreign key (order_id) references orders]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="misc">
+        <title>Mapeos miscel&#x00e1;neos de ejemplo</title>
+        
+        <para>
+            Todos estos ejemplos est&#x00e1;n tomados de la bater&#x00ed;a de pruebas de Hibernate.
+            Encontrar&#x00e1;s muchos otros mapeos de ejemplo &#x00fa;tiles all&#x00ed;. Mira en la carpeta
+            <literal>test</literal> de la distribuci&#x00f3;n de Hibernate.
+        </para>
+        
+        <para>POR HACER: poner palabras alrededor de este material</para>
+        
+        <sect2 id="example-mappings-typed-onetone">
+            <title>Asociaci&#x00f3;n uno-a-uno "Tipificada"</title>
+<programlisting><![CDATA[<class name="Person">
+    <id name="name"/>
+    <one-to-one name="address" 
+            cascade="all">
+        <formula>name</formula>
+        <formula>'HOME'</formula>
+    </one-to-one>
+    <one-to-one name="mailingAddress" 
+            cascade="all">
+        <formula>name</formula>
+        <formula>'MAILING'</formula>
+    </one-to-one>
+</class>
+
+<class name="Address" batch-size="2" 
+        check="addressType in ('MAILING', 'HOME', 'BUSINESS')">
+    <composite-id>
+        <key-many-to-one name="person" 
+                column="personName"/>
+        <key-property name="type" 
+                column="addressType"/>
+    </composite-id>
+    <property name="street" type="text"/>
+    <property name="state"/>
+    <property name="zip"/>
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="example-mappings-composite-key">
+            <title>Ejemplo de clave compuesta</title>
+<programlisting><![CDATA[<class name="Customer">
+
+    <id name="customerId"
+        length="10">
+        <generator class="assigned"/>
+    </id>
+
+    <property name="name" not-null="true" length="100"/>
+    <property name="address" not-null="true" length="200"/>
+
+    <list name="orders"
+            inverse="true"
+            cascade="save-update">
+        <key column="customerId"/>
+        <index column="orderNumber"/>
+        <one-to-many class="Order"/>
+    </list>
+
+</class>
+
+<class name="Order" table="CustomerOrder" lazy="true">
+    <synchronize table="LineItem"/>
+    <synchronize table="Product"/>
+    
+    <composite-id name="id" 
+            class="Order$Id">
+        <key-property name="customerId" length="10"/>
+        <key-property name="orderNumber"/>
+    </composite-id>
+    
+    <property name="orderDate" 
+            type="calendar_date"
+            not-null="true"/>
+    
+    <property name="total">
+        <formula>
+            ( select sum(li.quantity*p.price) 
+            from LineItem li, Product p 
+            where li.productId = p.productId 
+                and li.customerId = customerId 
+                and li.orderNumber = orderNumber )
+        </formula>
+    </property>
+    
+    <many-to-one name="customer"
+            column="customerId"
+            insert="false"
+            update="false" 
+            not-null="true"/>
+        
+    <bag name="lineItems"
+            fetch="join" 
+            inverse="true"
+            cascade="save-update">
+        <key>
+            <column name="customerId"/>
+            <column name="orderNumber"/>
+        </key>
+        <one-to-many class="LineItem"/>
+    </bag>
+    
+</class>
+    
+<class name="LineItem">
+    
+    <composite-id name="id" 
+            class="LineItem$Id">
+        <key-property name="customerId" length="10"/>
+        <key-property name="orderNumber"/>
+        <key-property name="productId" length="10"/>
+    </composite-id>
+    
+    <property name="quantity"/>
+    
+    <many-to-one name="order"
+            insert="false"
+            update="false" 
+            not-null="true">
+        <column name="customerId"/>
+        <column name="orderNumber"/>
+    </many-to-one>
+    
+    <many-to-one name="product"
+            insert="false"
+            update="false" 
+            not-null="true"
+            column="productId"/>
+        
+</class>
+
+<class name="Product">
+    <synchronize table="LineItem"/>
+
+    <id name="productId"
+        length="10">
+        <generator class="assigned"/>
+    </id>
+    
+    <property name="description" 
+        not-null="true" 
+        length="200"/>
+    <property name="price" length="3"/>
+    <property name="numberAvailable"/>
+    
+    <property name="numberOrdered">
+        <formula>
+            ( select sum(li.quantity) 
+            from LineItem li 
+            where li.productId = productId )
+        </formula>
+    </property>
+    
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="example-mappings-composite-key-manytomany">
+            <title>Muchos-a-muchos con atributo de clave compuesta compartido</title>
+<programlisting><![CDATA[<class name="User" table="`User`">
+    <composite-id>
+        <key-property name="name"/>
+        <key-property name="org"/>
+    </composite-id>
+    <set name="groups" table="UserGroup">
+        <key>
+            <column name="userName"/>
+            <column name="org"/>
+        </key>
+        <many-to-many class="Group">
+            <column name="groupName"/>
+            <formula>org</formula>
+        </many-to-many>
+    </set>
+</class>
+    
+<class name="Group" table="`Group`">
+    <composite-id>
+        <key-property name="name"/>
+        <key-property name="org"/>
+    </composite-id>
+    <property name="description"/>
+    <set name="users" table="UserGroup" inverse="true">
+        <key>
+            <column name="groupName"/>
+            <column name="org"/>
+        </key>
+        <many-to-many class="User">
+            <column name="userName"/>
+            <formula>org</formula>
+        </many-to-many>
+    </set>
+</class>
+]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-content-discrimination">
+            <title>Discriminaci&#x00f3;n basada en contenido</title>
+<programlisting><![CDATA[<class name="Person"
+    discriminator-value="P">
+    
+    <id name="id" 
+        column="person_id" 
+        unsaved-value="0">
+        <generator class="native"/>
+    </id>
+    
+            
+    <discriminator 
+        type="character">
+        <formula>
+            case 
+                when title is not null then 'E' 
+                when salesperson is not null then 'C' 
+                else 'P' 
+            end
+        </formula>
+    </discriminator>
+
+    <property name="name" 
+        not-null="true"
+        length="80"/>
+        
+    <property name="sex" 
+        not-null="true"
+        update="false"/>
+    
+    <component name="address">
+        <property name="address"/>
+        <property name="zip"/>
+        <property name="country"/>
+    </component>
+    
+    <subclass name="Employee" 
+        discriminator-value="E">
+            <property name="title"
+                length="20"/>
+            <property name="salary"/>
+            <many-to-one name="manager"/>
+    </subclass>
+    
+    <subclass name="Customer" 
+        discriminator-value="C">
+            <property name="comments"/>
+            <many-to-one name="salesperson"/>
+    </subclass>
+    
+</class>]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-association-alternatekeys" >
+            <title>Asociaciones sobre claves alternativas</title>
+<programlisting><![CDATA[<class name="Person">
+    
+    <id name="id">
+        <generator class="hilo"/>
+    </id>
+    
+    <property name="name" length="100"/>
+    
+    <one-to-one name="address" 
+        property-ref="person"
+        cascade="all"
+        fetch="join"/>
+    
+    <set name="accounts" 
+        inverse="true">
+        <key column="userId"
+            property-ref="userId"/>
+        <one-to-many class="Account"/>
+    </set>
+    
+    <property name="userId" length="8"/>
+
+</class>
+
+<class name="Address">
+
+    <id name="id">
+        <generator class="hilo"/>
+    </id>
+
+    <property name="address" length="300"/>
+    <property name="zip" length="5"/>
+    <property name="country" length="25"/>
+    <many-to-one name="person" unique="true" not-null="true"/>
+
+</class>
+
+<class name="Account">
+    <id name="accountId" length="32">
+        <generator class="uuid.hex"/>
+    </id>
+    
+    <many-to-one name="user"
+        column="userId"
+        property-ref="userId"/>
+    
+    <property name="type" not-null="true"/>
+    
+</class>]]></programlisting>
+        </sect2>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/example_parentchild.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/example_parentchild.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/example_parentchild.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,362 @@
+<chapter id="example-parentchild">
+    <title>Ejemplo: Padre/Hijo</title>
+
+    <para>
+        Una de las primer&#x00ed;simas cosas que los usuarios nuevos intentan hacer con Hibernate es modelar una relaci&#x00f3;n de
+        tipo padre / hijo. Para esto hay dos enfoques diferentes. Por varias razones, el enfoque m&#x00e1;s conveniente,
+        especialmente para usuarios nuevos, es modelar tanto <literal>Parent</literal> como <literal>Child</literal>
+        como clases de entidad con una asociaci&#x00f3;n <literal>&lt;one-to-many&gt;</literal> desde <literal>Parent</literal>
+        a <literal>Child</literal>. (El enfoque alternativo es declarar el <literal>Child</literal> como un
+        <literal>&lt;composite-element&gt;</literal>.) Ahora, resulta que la sem&#x00e1;ntica por defecto de una asociaci&#x00f3;n
+        uno a muchos (en Hibernate) es mucho menos cercana a la sem&#x00e1;ntica usual de una relaci&#x00f3;n padre / hijo que aquellas
+        de un mapeo de elementos compuestos. Explicaremos c&#x00f3;mo usar una <emphasis>asociaci&#x00f3;n uno a muchos bidireccional
+        con tratamiento en cascada</emphasis> para modelar una relaci&#x00f3;n padre / hijo eficiente y elegantemente.
+        &#x00a1;No es para nada dif&#x00ed;cil!
+    </para>
+    
+    <sect1 id="example-parentchild-collections">
+        <title>Una nota sobre las colecciones</title>
+
+        <para>
+            Se considera que las colecciones de Hibernate son una parte l&#x00f3;gica de la entidad que las posee; nunca de
+            las entidades contenidas. &#x00a1;Esta es una distinci&#x00f3;n crucial! Esto tiene las siguientes consecuencias:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+            <para>
+                Cuando se quita / a&#x00f1;ade un objeto desde / a una colecci&#x00f3;n, se incrementa el n&#x00fa;mero de versi&#x00f3;n del
+                due&#x00f1;o de la colecci&#x00f3;n.
+            </para>
+            </listitem>
+            <listitem>
+            <para>
+                Si un objeto que fue quitado de una colecci&#x00f3;n es una instancia de un tipo de valor (por ejemplo, un
+                elemento compuesto), ese objeta cesar&#x00e1; de ser persistente y su estado ser&#x00e1; completamente quitado de la
+                base de datos. Asimismo, a&#x00f1;adir una instancia de tipo de valor a la colecci&#x00f3;n causar&#x00e1; que su estado
+                sea inmediatamente persistente.
+            </para>
+            </listitem>
+            <listitem>
+            <para>
+                Por otro lado, si se quita una entidad de una colecci&#x00f3;n (una asociaci&#x00f3;n uno-a-muchos o muchos-a-muchos),
+                no ser&#x00e1; borrado, por defecto. Este comportamiento es completamente consistente. &#x00a1;Un cambio en el
+                estado interno de otra entidad no hace desaparecer la entidad asociada! Asimismo, a&#x00f1;adir una entidad a
+                una colecci&#x00f3;n no causa que la entidad se vuelva persistente, por defecto.
+            </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            En cambio, el comportamiento por defecto es que al a&#x00f1;adir una entidad a una colecci&#x00f3;n se crea meramente
+            un enlace entre las dos entidades, mientras que al quitarla se quita el enlace. Esto es muy apropiado para
+            todos los tipos de casos. Donde no es para nada apropiado es en el caso de una relaci&#x00f3;n padre / hijo. donde
+            la vida del hijo est&#x00e1; ligada al ciclo de vida del padre.
+        </para>
+    
+    </sect1>
+
+    <sect1 id="example-parentchild-bidir">
+        <title>Uno-a-muchos bidirectional</title>
+
+        <para>
+            Sup&#x00f3;n que empezamos con una asociaci&#x00f3;n simple <literal>&lt;one-to-many&gt;</literal> desde
+            <literal>Parent</literal> a <literal>Child</literal>.
+        </para>
+
+        <programlisting><![CDATA[<set name="children">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+    
+        <para>
+            Si ejecut&#x00e1;semos el siguiente c&#x00f3;digo
+        </para>
+
+        <programlisting><![CDATA[Parent p = .....;
+Child c = new Child();
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+    
+        <para>
+            Hibernate publicar&#x00ed;a dos sentencias SQL:
+        </para>
+
+        <itemizedlist>
+        <listitem>
+            <para>un <literal>INSERT</literal> para crear el registro de <literal>c</literal></para>
+        </listitem>
+        <listitem>
+            <para>
+                un <literal>UPDATE</literal> para crear el enlace desde <literal>p</literal> a
+                <literal>c</literal>
+            </para>
+        </listitem>
+        </itemizedlist>
+    
+        <para>
+            Esto no es s&#x00f3;lo ineficiente, sino que adem&#x00e1;s viola cualquier restricci&#x00f3;n <literal>NOT NULL</literal> en la
+            columna <literal>parent_id</literal>. Podemos reparar la violaci&#x00f3;n de restricci&#x00f3;n de nulabilidad
+            especificando <literal>not-null="true"</literal> en el mapeo de la colecci&#x00f3;n:
+        </para>
+
+        <programlisting><![CDATA[<set name="children">
+    <key column="parent_id" not-null="true"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+    
+        <para>
+            Sin embargo, esta no es la soluci&#x00f3;n recomendada.
+       	</para>
+       	<para>
+            El caso subyacente de este comportamiento es que el enlace (la clave for&#x00e1;nea <literal>parent_id</literal>)
+            de <literal>p</literal> a <literal>c</literal> no es considerado parte del estado del objeto
+            <literal>Child</literal> y por lo tanto no es creada en el <literal>INSERT</literal>. De modo que la
+            soluci&#x00f3;n es hacer el enlace parte del mapeo del <literal>Child</literal>.
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
+
+        <para>
+            (Necesitamos adem&#x00e1;s a&#x00f1;adir la propiedad <literal>parent</literal> a la clase <literal>Child</literal>.)
+        </para>
+
+        <para>
+            Ahora que la entidad <literal>Child</literal> est&#x00e1; gestionando el estado del enlace, le decimos a la
+            colecci&#x00f3;n que no actualice el enlace. Usamos el atributo <literal>inverse</literal>.
+        </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+        <para>
+            El siguiente c&#x00f3;digo podr&#x00ed;a ser usado para a&#x00f1;adir un nuevo <literal>Child</literal>
+        </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+        <para>
+            Y ahora, &#x00a1;S&#x00f3;lo se publicar&#x00ed;a un <literal>INSERT</literal> de SQL!
+        </para>
+
+        <para>
+            Para ajustar un poco m&#x00e1;s las cosas, podr&#x00ed;amos crear un m&#x00e9;todo <literal>addChild()</literal> en
+            <literal>Parent</literal>.
+        </para>
+
+        <programlisting><![CDATA[public void addChild(Child c) {
+    c.setParent(this);
+    children.add(c);
+}]]></programlisting>
+
+        <para>
+            Ahora, el c&#x00f3;digo para a&#x00f1;adir un <literal>Child</literal> se ve as&#x00ed;
+        </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+     </sect1>
+     
+     <sect1 id="example-parentchild-cascades">
+         <title>Ciclo de vida en cascada</title>
+     
+         <para>
+             La llamada expl&#x00ed;cita a <literal>save()</literal> es a&#x00fa;n molesta. Apuntaremos a esto usando tratamientos
+             en cascada.
+         </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true" cascade="all">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+     
+         <para>
+             Esto simplifica el c&#x00f3;digo anterior a 
+         </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.flush();]]></programlisting>
+     
+         <para>
+             Similarmente, no necesitamos iterar los hijos al salvar o borrar un <literal>Parent</literal>.
+             Lo siguiente quita <literal>p</literal> y todos sus hijos de la base de datos.
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+session.delete(p);
+session.flush();]]></programlisting>
+     
+         <para>
+             Sin embargo, este c&#x00f3;digo
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+c.setParent(null);
+session.flush();]]></programlisting>
+     
+         <para>
+             no quitar&#x00e1; <literal>c</literal> de la base de datos; s&#x00f3;lo quitar&#x00e1; el enlace a <literal>p</literal>
+             (y causar&#x00e1; una violaci&#x00f3;n a una restricci&#x00f3;n <literal>NOT NULL</literal>). Necesitas borrar el hijo
+             expl&#x00ed;citamente llamando a <literal>delete()</literal>.
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+session.delete(c);
+session.flush();]]></programlisting>
+
+         <para>
+             Ahora, en nuestro caso, un <literal>Child</literal> no puede existir realmente sin su padre. De modo que
+             si quitamos un <literal>Child</literal> de la colecci&#x00f3;n, realmente queremos que sea borrado. Para esto,
+             debemos usar <literal>cascade="all-delete-orphan"</literal>.
+         </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true" cascade="all-delete-orphan">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+         <para>
+             Nota: aunque el mapeo de la colecci&#x00f3;n especifique <literal>inverse="true"</literal>, el tratamiento en
+             cascada se procesa a&#x00fa;n al iterar los elementos de colecci&#x00f3;n. De modo que si requieres que un objeto sea
+             salvado, borrado o actualizado en cascada, debes a&#x00f1;adirlo a la colecci&#x00f3;n. No es suficiente con simplemente
+             llamar a <literal>setParent()</literal>.
+         </para>
+               
+     </sect1>
+     
+     <sect1 id="example-parentchild-update">
+         <title>Tratamiento en cascada y <literal>unsaved-value</literal></title>
+     
+         <para>
+             Sup&#x00f3;n que hemos cargado un <literal>Parent</literal> en una <literal>Session</literal>, hemos hecho algunos
+             cambios en una acci&#x00f3;n de UI y deseamos hacer persistentes estos cambios en una nueva sesi&#x00f3;n llamando a
+             <literal>update()</literal>. El <literal>Parent</literal> contendr&#x00e1; una colecci&#x00f3;n de hijos y, ya que
+             est&#x00e1; habilitado el tratamiento en cascada, Hibernate necesita saber qu&#x00e9; hijos est&#x00e1;n reci&#x00e9;n instanciados
+             y cu&#x00e1;les representan filas existentes en la base de datos. Asumamos que tanto <literal>Parent</literal> como
+             <literal>Child</literal> tienen propiedades identificadoras generadas de tipo <literal>Long</literal>.
+             Hibernate usar&#x00e1; el identificador y el valor de la propiedad de versi&#x00f3;n/timestamp para determinar cu&#x00e1;les de
+             los hijos son nuevos. (Ver <xref linkend="objectstate-saveorupdate"/>.) <emphasis>En Hibernate3, no es
+             m&#x00e1;s necesario especificar un <literal>unsaved-value</literal> expl&#x00ed;citamente.</emphasis>
+         </para>
+
+         <para>
+             The following code will update <literal>parent</literal> and <literal>child</literal> and insert 
+             <literal>newChild</literal>.
+         </para>
+
+         <programlisting><![CDATA[//parent and child were both loaded in a previous session
+parent.addChild(child);
+Child newChild = new Child();
+parent.addChild(newChild);
+session.update(parent);
+session.flush();]]></programlisting>
+     
+         <para>
+             Bueno, todo eso est&#x00e1; muy bien para el caso de un identificador generado, pero &#x00bf;qu&#x00e9; de los
+             identificadores asignados y de los identificadores compuestos? Esto es m&#x00e1;s dif&#x00ed;cil, ya que Hibernate
+             no puede usar la propiedad identificadora para distinguir entre un objeto reci&#x00e9;n instanciado (con un
+             identificador asignado por el usuario) y un objeto cargado en una sesi&#x00f3;n previa. En este caso, Hibernate
+             bien usar&#x00e1; la propiedad de versi&#x00f3;n o timestamp, o bien consultar&#x00e1; realmente el cach&#x00e9; de segundo nivel,
+             o bien, en el peor de los casos, la base de datos, para ver si existe la fila.
+         </para>
+         
+         <!-- undocumenting
+         <para>
+             There is one further possibility. The <literal>Interceptor</literal> method named 
+             <literal>isUnsaved()</literal> lets the application implement its own strategy for distinguishing
+             newly instantiated objects. For example, you could define a base class for your persistent classes.
+         </para>
+
+         <programlisting><![CDATA[public class Persistent {
+    private boolean _saved = false;
+    public void onSave() {
+        _saved=true;
+    }
+    public void onLoad() {
+        _saved=true;
+    }
+    ......
+    public boolean isSaved() {
+        return _saved;
+    }
+}]]></programlisting>
+     
+         <para>
+             (The <literal>saved</literal> property is non-persistent.)
+             Now implement <literal>isUnsaved()</literal>, along with <literal>onLoad()</literal>
+             and <literal>onSave()</literal> as follows.
+         </para>
+
+         <programlisting><![CDATA[public Boolean isUnsaved(Object entity) {
+    if (entity instanceof Persistent) {
+        return new Boolean( !( (Persistent) entity ).isSaved() );
+    }
+    else {
+        return null;
+    }
+}
+
+public boolean onLoad(Object entity, 
+    Serializable id,
+    Object[] state,
+    String[] propertyNames,
+    Type[] types) {
+
+    if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
+    return false;
+}
+
+public boolean onSave(Object entity,
+    Serializable id,
+    Object[] state,
+    String[] propertyNames,
+    Type[] types) {
+        
+    if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
+    return false;
+}]]></programlisting>
+
+		<para>
+			Don't worry; in Hibernate3 you don't need to write any of this kind of code if you don't want to.
+		</para>
+     -->
+     </sect1>
+
+     <sect1 id="example-parentchild-conclusion">
+         <title>Conclusi&#x00f3;n</title>
+
+         <para>
+             Hay que resumir un poco aqu&#x00ed; y podr&#x00ed;a parecer confuso a la primera vez. Sin embargo, en la pr&#x00e1;ctica,
+             todo funciona muy agradablemente. La mayor&#x00ed;a de las aplicaciones de Hibernate usan el patr&#x00f3;n
+             padre / hijo en muchos sitios.
+         </para>
+
+         <para>
+             Hemos mencionado una alternativa en el primer p&#x00e1;rrafo. Ninguno de los temas anteriores existe en el caso
+             de los mapeos <literal>&lt;composite-element&gt;</literal>, que tienen exactamente la sem&#x00e1;ntica de una
+             relaci&#x00f3;n padre / hijo. Desafortunadamente, hay dos grandes limitaciones para las clases de elementos
+             compuestos: los elementos compuestos no pueden poseer sus propias colecciones, y no deben ser el hijo
+             de cualquier otra entidad que no sea su padre &#x00fa;nico.
+         </para>
+     
+     </sect1>
+     
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/example_weblog.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/example_weblog.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/example_weblog.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,429 @@
+<chapter id="example-weblog">
+    <title>Ejemplo: Aplicaci&#x00f3;n de Weblog</title>
+
+    <sect1 id="example-weblog-classes">
+        <title>Clases Persistentes</title>
+
+        <para>
+            Las clases persistentes representan un weblog, y un &#x00ed;tem enviado a un weblog. Van a ser modelados como una
+            relaci&#x00f3;n padre/hijo est&#x00f1;ndar, pero usaremos un bag ordenado, en vez de un conjunto (set).
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+import java.util.List;
+
+public class Blog {
+    private Long _id;
+    private String _name;
+    private List _items;
+
+    public Long getId() {
+        return _id;
+    }
+    public List getItems() {
+        return _items;
+    }
+    public String getName() {
+        return _name;
+    }
+    public void setId(Long long1) {
+        _id = long1;
+    }
+    public void setItems(List list) {
+        _items = list;
+    }
+    public void setName(String string) {
+        _name = string;
+    }
+}]]></programlisting>
+
+        <programlisting><![CDATA[package eg;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+
+public class BlogItem {
+    private Long _id;
+    private Calendar _datetime;
+    private String _text;
+    private String _title;
+    private Blog _blog;
+
+    public Blog getBlog() {
+        return _blog;
+    }
+    public Calendar getDatetime() {
+        return _datetime;
+    }
+    public Long getId() {
+        return _id;
+    }
+    public String getText() {
+        return _text;
+    }
+    public String getTitle() {
+        return _title;
+    }
+    public void setBlog(Blog blog) {
+        _blog = blog;
+    }
+    public void setDatetime(Calendar calendar) {
+        _datetime = calendar;
+    }
+    public void setId(Long long1) {
+        _id = long1;
+    }
+    public void setText(String string) {
+        _text = string;
+    }
+    public void setTitle(String string) {
+        _title = string;
+    }
+}]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-weblog-mappings">
+        <title>Mapeos de Hibernate</title>
+
+        <para>
+            Los mapeos XML ahora deben ser absolutamente directos.
+        </para>
+        
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+    <class
+        name="Blog"
+        table="BLOGS">
+
+        <id
+            name="id"
+            column="BLOG_ID">
+
+            <generator class="native"/>
+
+        </id>
+
+        <property
+            name="name"
+            column="NAME"
+            not-null="true"
+            unique="true"/>
+
+        <bag
+            name="items"
+            inverse="true"
+            order-by="DATE_TIME"
+            cascade="all">
+
+            <key column="BLOG_ID"/>
+            <one-to-many class="BlogItem"/>
+
+        </bag>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+    <class
+        name="BlogItem"
+        table="BLOG_ITEMS"
+        dynamic-update="true">
+
+        <id
+            name="id"
+            column="BLOG_ITEM_ID">
+
+            <generator class="native"/>
+
+        </id>
+
+        <property
+            name="title"
+            column="TITLE"
+            not-null="true"/>
+
+        <property
+            name="text"
+            column="TEXT"
+            not-null="true"/>
+
+        <property
+            name="datetime"
+            column="DATE_TIME"
+            not-null="true"/>
+
+        <many-to-one
+            name="blog"
+            column="BLOG_ID"
+            not-null="true"/>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="example-weblog-code">
+        <title>C&#x00f3;digo Hibernate</title>
+
+        <para>
+            La siguiente clase demuestra algunos de los tipos de cosas que podemos haces con estas clases,
+            usando Hibernate.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+
+public class BlogMain {
+    
+    private SessionFactory _sessions;
+    
+    public void configure() throws HibernateException {
+        _sessions = new Configuration()
+            .addClass(Blog.class)
+            .addClass(BlogItem.class)
+            .buildSessionFactory();
+    }
+    
+    public void exportTables() throws HibernateException {
+        Configuration cfg = new Configuration()
+            .addClass(Blog.class)
+            .addClass(BlogItem.class);
+        new SchemaExport(cfg).create(true, true);
+    }
+    
+    public Blog createBlog(String name) throws HibernateException {
+        
+        Blog blog = new Blog();
+        blog.setName(name);
+        blog.setItems( new ArrayList() );
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.persist(blog);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return blog;
+    }
+    
+    public BlogItem createBlogItem(Blog blog, String title, String text)
+                        throws HibernateException {
+        
+        BlogItem item = new BlogItem();
+        item.setTitle(title);
+        item.setText(text);
+        item.setBlog(blog);
+        item.setDatetime( Calendar.getInstance() );
+        blog.getItems().add(item);
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.update(blog);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return item;
+    }
+    
+    public BlogItem createBlogItem(Long blogid, String title, String text)
+                        throws HibernateException {
+        
+        BlogItem item = new BlogItem();
+        item.setTitle(title);
+        item.setText(text);
+        item.setDatetime( Calendar.getInstance() );
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            Blog blog = (Blog) session.load(Blog.class, blogid);
+            item.setBlog(blog);
+            blog.getItems().add(item);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return item;
+    }
+    
+    public void updateBlogItem(BlogItem item, String text)
+                    throws HibernateException {
+        
+        item.setText(text);
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.update(item);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+    }
+    
+    public void updateBlogItem(Long itemid, String text)
+                    throws HibernateException {
+    
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            BlogItem item = (BlogItem) session.load(BlogItem.class, itemid);
+            item.setText(text);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+    }
+    
+    public List listAllBlogNamesAndItemCounts(int max)
+                    throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        List result = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "select blog.id, blog.name, count(blogItem) " +
+                "from Blog as blog " +
+                "left outer join blog.items as blogItem " +
+                "group by blog.name, blog.id " +
+                "order by max(blogItem.datetime)"
+            );
+            q.setMaxResults(max);
+            result = q.list();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return result;
+    }
+    
+    public Blog getBlogAndAllItems(Long blogid)
+                    throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        Blog blog = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "from Blog as blog " +
+                "left outer join fetch blog.items " +
+                "where blog.id = :blogid"
+            );
+            q.setParameter("blogid", blogid);
+            blog  = (Blog) q.uniqueResult();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return blog;
+    }
+    
+    public List listBlogsAndRecentItems() throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        List result = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "from Blog as blog " +
+                "inner join blog.items as blogItem " +
+                "where blogItem.datetime > :minDate"
+            );
+
+            Calendar cal = Calendar.getInstance();
+            cal.roll(Calendar.MONTH, false);
+            q.setCalendar("minDate", cal);
+            
+            result = q.list();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return result;
+    }
+}]]></programlisting>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/filters.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/filters.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/filters.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,130 @@
+<chapter id="filters">
+    <title>Filtrando datos</title>
+    
+    <para>
+        Hibernate3 provee un nuevo enfoque innovador para manejar datos con reglas de "visibilidad".
+        Un <emphasis>filtro de Hibernate</emphasis> es un filtro global, con nombre y parametrizado
+        que puede ser habilitado o deshabilitado para una sesión de Hibernate en particular.
+    </para>
+
+    <sect1 id="objectstate-filters">
+        <title>Filtros de Hibernate</title>
+
+        <para>
+            Hibernate3 añade la habilidad de predefinir criterios de filtros y unir esos filtros tanto a
+            nivel de una clase como de una colección. Un criterio de filtro es la habilidad de definir una
+            cláusula de restricción muy similar al atributo existente "where" disponible en el elemento
+            class y varios elementos de colección. Excepto en que estos filtros pueden ser parametrizados.
+            La aplicación puede tomar la decisión en tiempo de ejecución de qué filtros deben estar
+            habilitados y cuáles deben ser sus parámetros. Los filtros pueden ser usados como vistas de
+            base de datos, pero parametrizados dentro de la aplicación.
+        </para>
+
+        <para>
+            Para usar los filtros, éstos deben primero ser definidos y luego unidos a los elementos de mapeo
+            apropiados. Para definir un filtro, usa el elemento <literal>&lt;filter-def/&gt;</literal> dentro
+            de un elemento <literal>&lt;hibernate-mapping/&gt;</literal>:
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="myFilter">
+    <filter-param name="myFilterParam" type="string"/>
+</filter-def>]]></programlisting>
+
+        <para>
+            Entonces este filtro puede ser unido a una clase:
+        </para>
+
+        <programlisting><![CDATA[<class name="myClass" ...>
+    ...
+    <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</class>]]></programlisting>
+
+        <para>
+            o a una colección:
+        </para>
+
+        <programlisting><![CDATA[<set ...>
+    <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</set>]]></programlisting>
+
+        <para>
+            o incluso a ambos (o muchos de cada uno) al mismo tiempo.
+        </para>
+
+        <para>
+            Los métodos en <literal>Session</literal> son: <literal>enableFilter(String filterName)</literal>,
+            <literal>getEnabledFilter(String filterName)</literal>, y <literal>disableFilter(String filterName)</literal>.
+            Por defecto, los filtros <emphasis>no</emphasis> están habilitados para una sesión dada; deben ser
+            habilitados explícitamente por medio del uso del método <literal>Session.enableFilter()</literal>,
+            que devuelve una instancia de la interface <literal>Filter</literal>. Usando el filtro simple definido
+            arriba, esto se vería así:
+        </para>
+
+        <programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
+
+        <para>
+            Nota que los métodos en la interface org.hibernate.Filter permiten el encadenamiento de métodos
+            común en gran parte de Hibernate.
+        </para>
+
+        <para>
+            Un ejemplo completo, usando datos temporales con un patrón efectivo de fechas de registro:
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="effectiveDate">
+    <filter-param name="asOfDate" type="date"/>
+</filter-def>
+
+<class name="Employee" ...>
+...
+    <many-to-one name="department" column="dept_id" class="Department"/>
+    <property name="effectiveStartDate" type="date" column="eff_start_dt"/>
+    <property name="effectiveEndDate" type="date" column="eff_end_dt"/>
+...
+    <!--
+        Note that this assumes non-terminal records have an eff_end_dt set to
+        a max db date for simplicity-sake
+    -->
+    <filter name="effectiveDate"
+            condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+</class>
+
+<class name="Department" ...>
+...
+    <set name="employees" lazy="true">
+        <key column="dept_id"/>
+        <one-to-many class="Employee"/>
+        <filter name="effectiveDate"
+                condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Entonces, en orden de asegurar que siempre tendrás de vuelta registros actualmente efectivos,
+            simplemente habilita el filtro en la sesión previo a recuperar los datos de empleados:
+        </para>
+
+<programlisting><![CDATA[Session session = ...;
+session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
+List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
+         .setLong("targetSalary", new Long(1000000))
+         .list();
+]]></programlisting>
+
+        <para>
+            En el HQL de arriba, aunque sólo hemos mencionado explícitamente una restricción de salario en
+            los resultados, debido al filtro habilitado la consulta sólo devolverá empleados actualmente activos
+            que tengan un salario mayor que un millón de dólares.
+        </para>
+
+        <para>
+            Nota: si planeas usar filtros con unión externa (outer joining) (bien a través de HQL, o bien
+            de recuperación de carga) sé cuidadoso en la dirección de expresión de la condición. Lo más seguro
+            es establecer esto para unión externa izquierda (left outer joining). En general, coloca el primer
+            parámetro seguido del nombre(s) de columna(s) después del operador.
+        </para>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/inheritance_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/inheritance_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/inheritance_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,464 @@
+<chapter id="inheritance">
+    <title>Mapeo de Herencia</title>
+
+    <sect1 id="inheritance-strategies" revision="2">
+        <title>Las Tres Estrategias</title>
+
+        <para>
+            Hibernate soporta las tres estrategias b&#x00e1;sicas de mapeo de herencia:
+        </para>
+
+        <itemizedlist>
+        <listitem>
+        <para>
+            tabla por jerarqu&#x00ed;a de clases
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            tabla por subclase
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            tabla por clase concreta
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            En adici&#x00f3;n, Hibernate soporta un cuarto, ligeramente diferente tipo
+            de polimorfismo:
+        </para>
+
+        <itemizedlist>
+        <listitem>
+        <para>
+            polimorfismo impl&#x00ed;cito
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            Es posible usar estrategias de mapeo diferentes para diferentes
+            ramificaciones de la misma jerarqu&#x00ed;a de herencia, y entonces usar
+            polimorfismo impl&#x00ed;cito para conseguir polimorfismo a trav&#x00e9;s de
+            toda la jerarqu&#x00ed;a. Sin embargo, Hibernate no soporta la mezcla de
+            mapeos <literal>&lt;subclass&gt;</literal>,
+            y <literal>&lt;joined-subclass&gt;</literal>
+            y <literal>&lt;union-subclass&gt;</literal> bajo el mismo elemento
+            <literal>&lt;class&gt;</literal> ra&#x00ed;z. Es posible mezclar juntas las
+            estrategias de tabla por jerarqu&#x00ed;a y tabla por subclase, bajo el mismo
+            elemento <literal>&lt;class&gt;</literal>, combinando los elementos
+            <literal>&lt;subclass&gt;</literal> y <literal>&lt;join&gt;</literal>
+            (ver debajo).
+        </para>
+        
+        <sect2 id="inheritance-tableperclass" >
+        <title>Tabla por jerarqu&#x00ed;a de clases</title>
+
+        <para>
+            Sup&#x00f3;n que tenemos una interface <literal>Payment</literal>, con
+            los implementadores <literal>CreditCardPayment</literal>,
+            <literal>CashPayment</literal>, <literal>ChequePayment</literal>.
+            El mapeo de tabla por jerarqu&#x00ed;a se ver&#x00ed;a as&#x00ed;:
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        ...
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        ...
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            Se requiere exactamente una tabla. Hay una gran limitaci&#x00f3;n de esta estrategia de mapeo:
+            las columnas declaradas por las subclases, como <literal>CCTYPE</literal>, no pueden
+            tener restricciones <literal>NOT NULL</literal>.
+        </para>
+        
+        </sect2>
+
+        <sect2 id="inheritance-tablepersubclass">
+        <title>Tabla por subclase</title>
+
+        <para>
+            Un mapeo de tabla por sublclase se ver&#x00ed;a as&#x00ed;:
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        ...
+    </joined-subclass>
+</class>]]></programlisting>
+
+        <para>
+            Se requieren cuatro tablas. Las tres tablas de subclase tienen
+            asociaciones de clave primaria a la tabla de superclase (de modo
+            que en el modelo relacional es realmente una asociaci&#x00f3;n uno-a-uno).
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-tablepersubclass-discriminator" revision="2">
+        <title>Tabla por subclase, usando un discriminador</title>
+
+        <para>
+            Observa que la implementaci&#x00f3;n de Hibernate de tabla por subclase
+            no requiere ninguna columna discriminadora. Otros mapeadores
+            objeto/relacional usan una implementaci&#x00f3;n diferente de tabla por
+            subclase que requiere una columna discriminadora de tipo en la tabla
+            de superclase. Este enfoque es mucho m&#x00e1;s dif&#x00ed;cil de implementar
+            pero discutiblemente m&#x00e1;s correcto desde un punto de vista relacional.
+            Si quisieras usar una columna discriminadora con la estrategia de
+            tabla por subclase, puedes combinar el uso de <literal>&lt;subclass&gt;</literal>
+            y <literal>&lt;join&gt;</literal>, como sigue:
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <join table="CREDIT_PAYMENT">
+            <key column="PAYMENT_ID"/>
+            <property name="creditCardType" column="CCTYPE"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        <join table="CASH_PAYMENT">
+            <key column="PAYMENT_ID"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        <join table="CHEQUE_PAYMENT" fetch="select">
+            <key column="PAYMENT_ID"/>
+            ...
+        </join>
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            la declaraci&#x00f3;n opcional <literal>fetch="select"</literal> dice a Hibernate
+            que no recupere los datos de la subclase <literal>ChequePayment</literal>
+            usando una uni&#x00f3;n externa (outer join) al consultar la superclase.
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
+        <title>Mezclando tabla por jerarqu&#x00ed;a de clases con tabla por subclase</title>
+
+        <para>
+            Puedes incluso mezclar las estrategias de tabla po jerarqu&#x00ed;a y tabla por
+            subclase usando este enfoque:
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <join table="CREDIT_PAYMENT">
+            <property name="creditCardType" column="CCTYPE"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        ...
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        ...
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            Para cualquiera de estas estrategias de mapeo, una asociaci&#x00f3;n polim&#x00f3;rfica
+            a la clase ra&#x00ed;z <literal>Payment</literal> es mapeada usando <literal>&lt;many-to-one&gt;</literal>.
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
+    
+        </sect2>
+
+        <sect2 id="inheritance-tableperconcrete" revision="1">
+        <title>Tabla por clase concreta</title>
+
+        <para>
+            Podr&#x00ed;amos ir de dos maneras a la estrategia de mapeo de tabla por clase
+            concreta. La primera es usar <literal>&lt;union-subclass&gt;</literal>.
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="sequence"/>
+    </id>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </union-subclass>
+    <union-subclass name="CashPayment" table="CASH_PAYMENT">
+        ...
+    </union-subclass>
+    <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        ...
+    </union-subclass>
+</class>]]></programlisting>
+
+        <para>
+            Est&#x00e1;n implicadas tres tablas. Cada tabla define columnas para todas las
+            propiedades de la clase, inccluyendo las propiedades heredadas.
+        </para>
+        
+        <para>
+            La limitaci&#x00f3;n de este enfoque es que si una propiedad es mapeada en la
+            superclase, el nombre de columna debe ser el mismo en todas las tablas
+            de subclase. (Podr&#x00ed;amos relajar esto en un lanzamiento futuro de Hibernate.)
+            La estrategia de generador de indentidad no est&#x00e1; permitida en la herencia
+            de uni&#x00f3;n de subclase, de hecho la semilla de clave primaria tiene que ser
+            compartida a trav&#x00e9;s de todas las subclases unidas de una jerarqu&#x00ed;a.
+        </para>
+        
+        </sect2>
+
+        <sect2 id="inheritance-tableperconcreate-polymorphism">
+        <title>Tabla por clase concreta, usando polimorfismo impl&#x00ed;cito</title>
+
+        <para>
+            Un enfoque alternativo es hacer uso de polimorfismo impl&#x00ed;cito:
+        </para>
+
+        <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+    <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CREDIT_AMOUNT"/>
+    ...
+</class>
+
+<class name="CashPayment" table="CASH_PAYMENT">
+    <id name="id" type="long" column="CASH_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CASH_AMOUNT"/>
+    ...
+</class>
+
+<class name="ChequePayment" table="CHEQUE_PAYMENT">
+    <id name="id" type="long" column="CHEQUE_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CHEQUE_AMOUNT"/>
+    ...
+</class>]]></programlisting>
+           
+        <para>
+            Nota que en ning&#x00fa;n sitio mencionamos la interface <literal>Payment</literal>
+            expl&#x00ed;citamente. Nota adem&#x00e1;s que las propiedades de <literal>Payment</literal>
+            son mapeadas en cada una de las subclases. Si quieres evitar duplicaci&#x00f3;n,
+            considera usar entidades XML. (por ejemplo,
+            <literal>[ &lt;!ENTITY allproperties SYSTEM "allproperties.xml"&gt; ]</literal>
+            en la declaraci&#x00f3;n <literal>DOCTYPE</literal> y <literal>&amp;allproperties;</literal>
+            en el mapeo).
+        </para>
+        
+        <para>
+            La desventaja de este enfoque es que Hibernate no genera <literal>UNION</literal>s
+            de SQL al realizar consultas polim&#x00f3;rficas.
+        </para>
+
+        <para>
+            Para esta estrategia de mapeo, una asociaci&#x00f3;n polim&#x00f3;rfica a <literal>Payment</literal>
+            es mapeada generalmente usando <literal>&lt;any&gt;</literal>.
+        </para>
+
+        <programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
+    <meta-value value="CREDIT" class="CreditCardPayment"/>
+    <meta-value value="CASH" class="CashPayment"/>
+    <meta-value value="CHEQUE" class="ChequePayment"/>
+    <column name="PAYMENT_CLASS"/>
+    <column name="PAYMENT_ID"/>
+</any>]]></programlisting>
+           
+        </sect2>
+
+        <sect2 id="inheritace-mixingpolymorphism">
+        <title>Mezclando polimorfismo impl&#x00ed;cito con otros mapeos de herencia</title>
+
+        <para>
+            Hay una cosa m&#x00e1;s por notar acerca de este mapeo. Ya que las subclases se mapean
+            cada una en su propio elemento <literal>&lt;class&gt;</literal> (y ya que
+            <literal>Payment</literal> es s&#x00f3;lo una interface), cada una de las subclases
+            podr&#x00ed;a ser parte de otra jerarqu&#x00ed;a de herencia! (Y todav&#x00ed;a puedes seguir usando
+            consultas polim&#x00f3;rficas contra la interface <literal>Payment</literal>.)
+       </para>
+
+        <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+    <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="CREDIT_CARD" type="string"/>
+    <property name="amount" column="CREDIT_AMOUNT"/>
+    ...
+    <subclass name="MasterCardPayment" discriminator-value="MDC"/>
+    <subclass name="VisaPayment" discriminator-value="VISA"/>
+</class>
+
+<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
+    <id name="id" type="long" column="TXN_ID">
+        <generator class="native"/>
+    </id>
+    ...
+    <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="amount" column="CASH_AMOUNT"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="amount" column="CHEQUE_AMOUNT"/>
+        ...
+    </joined-subclass>
+</class>]]></programlisting>
+
+        <para>
+            Una vez m&#x00e1;s, no mencionamos a <literal>Payment</literal> expl&#x00ed;citamente.
+            Si ejecutamos una consulta contra la interface <literal>Payment</literal>
+            - por ejemplo, <literal>from Payment</literal> - Hibernate devuelve
+            autom&#x00e1;ticamente instancias de <literal>CreditCardPayment</literal>
+            (y sus subclases, ya que ellas tambi&#x00e9;n implementan <literal>Payment</literal>),
+            <literal>CashPayment</literal> y <literal>ChequePayment</literal> pero
+            no instancias de <literal>NonelectronicTransaction</literal>.
+        </para>
+        
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="inheritance-limitations">
+        <title>Limitaciones</title>
+
+        <para>
+            Existen ciertas limitaciones al enfoque de "polimorfismo impl&#x00ed;cito" en
+            la estrategia de mapeo de tabla por clase concreta. Existen limitaciones
+            algo menos restrictivas a los mapeos <literal>&lt;union-subclass&gt;</literal>.
+        </para>
+
+        <para>
+            La siguiente tabla muestra las limitaciones de mapeos de tabla por
+            clase concreta, y de polmorfismo impl&#x00ed;cito, en Hibernate.
+        </para>
+            
+        <table frame="topbot">
+            <title>Funcionalidades de mapeo de herencia</title>
+            <tgroup cols='8' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="1*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <colspec colname='c6' colwidth="1*"/>
+            <colspec colname='c7' colwidth="1*"/>
+            <colspec colname='c8' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Estrategia de herencia</entry>
+              <entry>muchos-a-uno polim&#x00f3;rfica</entry>
+              <entry>uno-a-uno polim&#x00f3;rfica</entry>
+              <entry>uno-a-muchos polim&#x00f3;rfica</entry>
+              <entry>mushos-a-muchos polim&#x00f3;rfica</entry>
+              <entry><literal>load()/get()</literal> polim&#x00f3;rficos</entry>
+              <entry>Consultas polim&#x00f3;rficas</entry>
+              <entry>Uniones polim&#x00f3;rficas</entry>
+              <entry>Recuperaci&#x00f3;n por uni&#x00f3;n externa (outer join)</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>tabla por jerarqu&#x00ed;a de clases</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal></entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>soportada</emphasis></entry>
+            </row>
+            <row>
+                <entry>tabla por subclase</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal></entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>soportada</emphasis></entry>
+            </row>
+            <row>
+                <entry>tabla por clase concreta (union-subclass)</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal> (para <literal>inverse="true"</literal> solamente)</entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>soportada</emphasis></entry>
+            </row>
+            <row>
+                <entry>tabla por clase concreta (polimorfismo impl&#x00ed;cito)</entry>
+                <entry><literal>&lt;any&gt;</literal></entry>
+                <entry><emphasis>no soportada</emphasis></entry>
+                <entry><emphasis>no soportada</emphasis></entry>
+                <entry><literal>&lt;many-to-any&gt;</literal></entry>
+                <entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><emphasis>no suportadas</emphasis></entry>
+                <entry><emphasis>no soportada</emphasis></entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/performance.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/performance.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/performance.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1334 @@
+<chapter id="performance">
+    <title>Mejorando el rendimiento</title>
+
+    <sect1 id="performance-fetching">
+        <title>Estrategias de recuperaci&#x00f3;n</title>
+
+        <para>
+            Una <emphasis>estrategia de recuperaci&#x00f3;n</emphasis> es la estrategia que usar&#x00e1; Hibernate para recuperar
+            los objetos asociados cuando la aplicaci&#x00f3;n necesite navegar la asociaci&#x00f3;n. Las estrategias de recuperaci&#x00f3;n
+            pueden ser declaradas en los metadatos de mapeo O/R, o sobrescritas por una consulta HQL o
+            <literal>Criteria</literal> en particular.
+        </para>
+
+        <para>
+            Hibernate3 define las siguientes estrategias de recuperaci&#x00f3;n:
+        </para>
+
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <emphasis>Recuperaci&#x00f3;n por uni&#x00f3;n (join fetching)</emphasis> - Hibernate recupera la
+                    instancia asociada o colecci&#x00f3;n en la misma <literal>SELECT</literal>, usando una
+                    <literal>OUTER JOIN</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Recuperaci&#x00f3;n por selecci&#x00f3;n (select fetching)</emphasis> - se usa una segunda
+                    <literal>SELECT</literal> para recuperar la entidad asociada o colecci&#x00f3;n. A menos que
+                    deshabilites expl&#x00ed;citamente la recuperaci&#x00f3;n perezosa especificando <literal>lazy="false"</literal>,
+                    la segunda selecci&#x00f3;n s&#x00f3;lo ser&#x00e1; ejecutada cuando realmente accedas a la asociaci&#x00f3;n.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Recuperaci&#x00f3;n por subselecci&#x00f3;n (subselect fetching)</emphasis> - se usa una segunda
+                    <literal>SELECT</literal> para recuperar las colecciones asociadas de todas las entidades
+                    recuperadas en una consulta o recuperaci&#x00f3;n previa. A menos que deshabilites expl&#x00ed;citamente la
+                    recuperaci&#x00f3;n perezosa especificando <literal>lazy="false"</literal>, esta segunda selecci&#x00f3;n s&#x00f3;lo
+                    ser&#x00e1; ejecutada cuando realmente accedas a la asociaci&#x00f3;n.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Recuperaci&#x00f3;n en lote</emphasis> - una estrategia de optimizaci&#x00f3;n para la recuperaci&#x00f3;n
+                    por selecci&#x00f3;n - Hibernate recupera un lote de instancias de entidad o colecciones en una sola
+                    <literal>SELECT</literal>, especificando una lista de claves primarias o de claves for&#x00e1;neas.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            Hibernate tambi&#x00e9;n distingue entre:
+        </para>
+
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <emphasis>Recuperaci&#x00f3;n inmediata</emphasis> - una asociaci&#x00f3;n, colecci&#x00f3;n o atributo es recuperado
+                    inmediatamente, cuando el due&#x00f1;o es cargado.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Recuperaci&#x00f3;n perezosa de colecciones</emphasis> - se recupera una colecci&#x00f3;n cuando la
+                    aplicaci&#x00f3;n invoca una operaci&#x00f3;n sobre la colecci&#x00f3;n. (Esto es por defecto para las colecciones.)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Recuperaci&#x00f3;n por proxy</emphasis> - se recupera una asociaci&#x00f3;n monovaluada cuando se
+                    invoca un m&#x00e9;todo que no sea el getter del identificador sobre el objeto asociado.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Recuperaci&#x00f3;n perezosa de atributos</emphasis> - se recupera un atributo o una asociaci&#x00f3;n
+                    monovaluada cuando se accede a la variable de instancia (requiere instrumentaci&#x00f3;n del bytecode en
+                    tiempo de ejecuci&#x00f3;n). Este enfoque es raramente necesario.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            Aqu&#x00ed; tenemos dos nociones ortogonales: <emphasis>cu&#x00e1;ndo</emphasis> se recupera la aplicaci&#x00f3;n,
+            y <emphasis>c&#x00f3;mo</emphasis> es recuperada (qu&#x00e9; SQL es usado). &#x00a1;No las confundas! Usamos 
+            <literal>fetch</literal> para afinar el rendimiento. Podemos usar <literal>lazy</literal> para
+            definir un contrato sobre qu&#x00e9; datos est&#x00e1;n siempre disponibles en cualquier instancia separada de
+            una clase en particular.
+        </para>
+ 
+        <sect2 id="performance-fetching-lazy">
+            <title>Trabajando con asociaciones perezosas</title>
+            
+            <para>
+                Por defecto, Hibernate3 usa una recuperaci&#x00f3;n perezosa por selecci&#x00f3;n para colecciones
+                y una recuperaci&#x00f3;n por proxy perezosa para asociaciones monovaluadas. Estas pol&#x00ed;ticas por
+                defecto tienen sentido para casi todas las asociaciones en casi todas las aplicaciones.
+            </para>
+            
+            <para>
+                <emphasis>Nota:</emphasis> si estableces <literal>hibernate.default_batch_fetch_size</literal>, Hibernate
+                usar&#x00e1; la optimizaci&#x00f3;n de recuperaci&#x00f3;n en lotes para recuperaci&#x00f3;n perezosa (esta optimizaci&#x00f3;n tambi&#x00e9;n puede
+                ser habilitada a un nivel m&#x00e1;s granularizado).
+            </para>
+            
+            <para>
+                Sin embargo, la recuperaci&#x00f3;n perezosa plantea un problema del que tienes que estar al tanto. Acceder
+                a una asociaci&#x00f3;n perezosa fuera del contexto de una sesi&#x00f3;n de Hibernate abierta resultar&#x00e1; en una
+                excepci&#x00f3;n. Por ejemplo:
+            </para>
+        
+            <programlisting><![CDATA[s = sessions.openSession();
+Transaction tx = s.beginTransaction();
+            
+User u = (User) s.createQuery("from User u where u.name=:userName")
+    .setString("userName", userName).uniqueResult();
+Map permissions = u.getPermissions();
+
+tx.commit();
+s.close();
+
+Integer accessLevel = (Integer) permissions.get("accounts");  // Error!]]></programlisting>
+
+            <para>
+                Ya que la colecci&#x00f3;n de permisos no fue inicializada cuando se cerr&#x00f3; la <literal>Session</literal>,
+                la colecci&#x00f3;n no ser&#x00e1; capaz de cargar su estado. <emphasis>Hibernate no soporta la inicializaci&#x00f3;n
+                perezosa de objetos separados</emphasis>. La soluci&#x00f3;n es mover el c&#x00f3;digo que lee de la colecci&#x00f3;n
+                a justo antes que la transacci&#x00f3;n sea comprometida.
+            </para>
+    
+            <para>
+                Alternativamente, podr&#x00ed;amos usar una colecci&#x00f3;n no perezosa o asociaci&#x00f3;n, especificando
+                <literal>lazy="false"</literal> para el mapeo de asociaci&#x00f3;n. Sin embargo, est&#x00e1; pensado
+                que la inicializaci&#x00f3;n perezosa sea usada para casi todas las colecciones y asociaciones.
+                &#x00a1;Si defines demasiadas asociaciones no perezosas en tu modelo de objetos, Hibernate terminar&#x00e1;
+                necesitando recuperar la base de datos entera en cada transacci&#x00f3;n!
+            </para>
+    
+            <para>
+                Por otro lado, frecuentemente necesitamos elegir la recuperaci&#x00f3;n por uni&#x00f3;n (que es no perezosa
+                por naturaleza) en vez de la recuperaci&#x00f3;n por selecci&#x00f3;n en una transacci&#x00f3;n en particular. Veremos
+                ahora c&#x00f3;mo personalizar la estrategia de recuperaci&#x00f3;n. En Hibernate3, los mecanismos para elegir una
+                estrategia de recuperaci&#x00f3;n son id&#x00e9;nticas a las de las asociaciones monovaluadas y colecciones.
+            </para>
+        
+        </sect2>
+        
+        <sect2 id="performance-fetching-custom" revision="3">
+            <title>Afinando las estrategias de recuperaci&#x00f3;n</title>
+            
+            <para>
+                La recuperaci&#x00f3;n por selecci&#x00f3;n (la preestablecida) es extremadamente vulnerable a problemas de
+                selecci&#x00f3;n N+1, de modo querr&#x00ed;amos habilitar la recuperaci&#x00f3;n por uni&#x00f3;n (join fetching) en el
+                documento de mapeo:
+            </para>
+            
+            <programlisting><![CDATA[<set name="permissions" 
+            fetch="join">
+    <key column="userId"/>
+    <one-to-many class="Permission"/>
+</set]]></programlisting>
+
+           <programlisting><![CDATA[<many-to-one name="mother" class="Cat" fetch="join"/>]]></programlisting>
+
+            <para>
+                La estrategia de recuperaci&#x00f3;n definida en el documento de mapeo afecta a:
+            </para>
+            
+        <itemizedlist>
+             <listitem>
+                <para>
+                    las recuperaciones v&#x00ed;a <literal>get()</literal> o <literal>load()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    las recuperaciones que ocurren impl&#x00ed;citamente cuando se navega una asociaci&#x00f3;n
+                    (recuperaci&#x00f3;n perezosa)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    las consultas de <literal>Criteria</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+            <para>
+                Usualmente, no usamos el documento de mapeo para personalizar la recuperaci&#x00f3;n. En cambio, mantenemos el
+                comportamiento por defecto, y lo sobrescribimos para una transacci&#x00f3;n en particular, usando
+                <literal>left join fetch</literal> en HQL. Esto le dice a Hibernate que recupere la asociaci&#x00f3;n
+                tempranamente en la primera selecci&#x00f3;n, usando una uni&#x00f3;n externa. En la API de consulta de
+                <literal>Criteria</literal>, usar&#x00ed;as <literal>setFetchMode(FetchMode.JOIN)</literal>.
+            </para>
+            
+            <para>
+                Si acaso lo deseases, podr&#x00ed;as cambiar la estrategia de recuperaci&#x00f3;n usada por
+                <literal>get()</literal> or <literal>load()</literal>; simplemente usa una consulta
+                <literal>Criteria</literal>, por ejemplo:
+            </para>
+            
+            <programlisting><![CDATA[User user = (User) session.createCriteria(User.class)
+                .setFetchMode("permissions", FetchMode.JOIN)
+                .add( Restrictions.idEq(userId) )
+                .uniqueResult();]]></programlisting>
+                
+            <para>
+                (Esto es el equivalente de Hibernate de lo que otras soluciones ORM llaman un "plan de recuperaci&#x00f3;n".)
+            </para>
+
+            <para>
+                Una forma completamente diferente de evitar problemas con selecciones N+1 es usar el cach&#x00e9; de
+                segundo nivel.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-proxies" revision="2">
+            <title>Proxies de asociaciones de un solo extremo</title>
+
+            <para>
+                La recuperaci&#x00f3;n perezosa de colecciones est&#x00e1; implementada usando la implementaci&#x00f3;n de colecciones
+                persistentes propia de Hibernate. Sin embargo, se necesita un mecanismo diferente para un comportamiento
+                perezoso en las asociaciones de un solo extremo. La entidad objetivo de la asociaci&#x00f3;n debe ser tratada
+                con proxies. Hibernate implementa proxies de inicializaci&#x00f3;n perezosa para objetos persistentes usando
+                mejora del bytecode en tiempo de ejecuci&#x00f3;n (por medio de la excelente biblioteca CGLIB).
+            </para>
+
+            <para>
+                Por defecto, Hibernate3 genera proxies (en el arranque) para todas las clases persistentes y los usa
+                para habilitar la recuperaci&#x00f3;n perezosa de asociaciones <literal>muchos-a-uno</literal> y
+                <literal>uno-a-uno</literal>.
+            </para>
+
+            <para>
+                El fichero de mapeo puede declarar una interface a usar como interface de proxy para esa clase,
+                con el atributo <literal>proxy</literal>. Por defecto, Hibernate usa una subclase de la clase.
+                <emphasis>Nota que la clase tratada con proxies debe implementar un constructor por defecto con al
+                menos visibilidad de paquete. &#x00a1;Recomendamos este constructor para todas las clases persistentes!</emphasis>
+            </para>
+
+            <para>
+                Hay algunos puntos a tener en cuenta al extender este enfoque a clases polim&#x00f3;rficas, por ejemplo.
+            </para>
+
+            <programlisting><![CDATA[<class name="Cat" proxy="Cat">
+    ......
+    <subclass name="DomesticCat">
+        .....
+    </subclass>
+</class>]]></programlisting>
+
+            <para>
+                Primero, las instancias de <literal>Cat</literal> nunca ser&#x00e1;n objeto de un cast a 
+                <literal>DomesticCat</literal>, incluso aunque la instancia subyacente sea instancia de
+                <literal>DomesticCat</literal>:
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id);  // instantiate a proxy (does not hit the db)
+if ( cat.isDomesticCat() ) {                  // hit the db to initialize the proxy
+    DomesticCat dc = (DomesticCat) cat;       // Error!
+    ....
+}]]></programlisting>
+
+            <para>
+                Segundo, es posible romper con el operador <literal>==</literal> de un proxy.
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id);            // instantiate a Cat proxy
+DomesticCat dc = 
+        (DomesticCat) session.load(DomesticCat.class, id);  // acquire new DomesticCat proxy!
+System.out.println(cat==dc);                            // false]]></programlisting>
+
+            <para>
+                Sin embargo, la situaci&#x00f3;n no en absoluta tan mala como parece. Aunque tenemos ahora dos referencias
+                a objetos proxy diferentes, la instancia subyacente ser&#x00e1; a&#x00fa;n el mismo objeto:
+            </para>
+
+            <programlisting><![CDATA[cat.setWeight(11.0);  // hit the db to initialize the proxy
+System.out.println( dc.getWeight() );  // 11.0]]></programlisting>
+
+            <para>
+                Tercero, no debes usar un proxy CGLIB para una clase <literal>final</literal> o una clase
+                con alg&#x00fa;n m&#x00e9;todo <literal>final</literal>.
+            </para>
+
+            <para>
+                Finalmente, si tu objeto persistente adquiere cualquier recurso bajo instanciaci&#x00f3;n
+                (por ejemplo, en inicializadores o constructores por defecto), entonces esos recursos
+                ser&#x00e1;n adquiridos tambi&#x00e9;n por el proxy. La clase del proxy es una subclase real de la clase
+                persistente.
+            </para>
+
+            <para>
+                Estos problemas se deben a limitaciones fundamentales en el modelo de herencia &#x00fa;nica de Java.
+                Si deseas evitar estos problemas cada una de tus clases persistentes deben implementar una
+                interface que declare sus m&#x00e9;todos de negocio. Debes especificar estas interfaces en el fichero
+                de mapeo. Por ejemplo:
+            </para>
+
+            <programlisting><![CDATA[<class name="CatImpl" proxy="Cat">
+    ......
+    <subclass name="DomesticCatImpl" proxy="DomesticCat">
+        .....
+    </subclass>
+</class>]]></programlisting>
+
+            <para>
+                donde <literal>CatImpl</literal> implementa la interface <literal>Cat</literal> y
+                <literal>DomesticCatImpl</literal> implementa la interface <literal>DomesticCat</literal>.
+                Entonces <literal>load()</literal> o <literal>iterate()</literal> pueden devolver instancias de
+                <literal>Cat</literal> y <literal>DomesticCat</literal>. (Nota que <literal>list()</literal>
+                usualmente no devuelve proxies.)
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(CatImpl.class, catid);
+Iterator iter = session.iterate("from CatImpl as cat where cat.name='fritz'");
+Cat fritz = (Cat) iter.next();]]></programlisting>
+
+            <para>
+                Las relaciones tambi&#x00e9;n son inicializadas perezosamente. Esto significa que debes declarar
+                cualquier propiedad como de tipo <literal>Cat</literal>, no <literal>CatImpl</literal>.
+            </para>
+
+            <para>
+                Ciertas operaciones <emphasis>no</emphasis> requieren inicializaci&#x00f3;n de proxies.
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>equals()</literal>, si la clase persistente no sobrescribe <literal>equals()</literal>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>hashCode()</literal>, si la clase persistente no sobrescribe
+                        <literal>hashCode()</literal>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        El m&#x00e9;todo getter del identificador
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Hibernate detectar&#x00e1; las clase persistentes que sobrescriban <literal>equals()</literal> o
+                <literal>hashCode()</literal>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-initialization">
+            <title>Inicializando colecciones y proxies</title>
+
+            <para>
+                Una <literal>LazyInitializationException</literal> ser&#x00e1; lanzada por Hibernate si una colecci&#x00f3;n
+                o proxy sin inicializar es accedido fuera del &#x00e1;mbito de la <literal>Session</literal>, es decir,
+                cuando la entidad que posee la colecci&#x00f3;n o que tiene la referencia al proxy est&#x00e9; en el estado
+                separada.
+            </para>
+
+            <para>
+                A veces necesitamos asegurarnos que un proxy o colecci&#x00f3;n est&#x00e9; inicializado antes de cerrar la
+                <literal>Session</literal>. Por supuesto, siempre podemos forzar la inicializaci&#x00f3;n llamando a
+                <literal>cat.getSex()</literal> o <literal>cat.getKittens().size()</literal>, por ejemplo.
+                Pero esto es confuso a lectores del c&#x00f3;digo y no es conveniente para c&#x00f3;digo gen&#x00e9;rico.
+            </para>
+
+            <para>
+                Los m&#x00e9;todos est&#x00e1;ticos <literal>Hibernate.initialize()</literal> y
+                <literal>Hibernate.isInitialized()</literal> proveen a la aplicaci&#x00f3;n de una forma conveniente de
+                trabajar con colecciones o proxies inicializados perezosamente.
+                <literal>Hibernate.initialize(cat)</literal> forzar&#x00e1; la inicializaci&#x00f3;n de un proxy,
+                <literal>cat</literal>, en tanto su <literal>Session</literal> est&#x00e9; todav&#x00ed;a abierta.
+                <literal>Hibernate.initialize( cat.getKittens() )</literal> tiene un efecto similar para la colecci&#x00f3;n
+                de gatitos.
+            </para>
+
+            <para>
+                Otra opci&#x00f3;n es mantener la <literal>Session</literal> abierta hasta que todas las colecciones
+                y proxies necesarios hayan sido cargados. En algunas arquitecturas de aplicaci&#x00f3;n, particularmente
+                en aquellas donde el c&#x00f3;digo que accede a los datos usando Hibernate, y el c&#x00f3;digo que los usa est&#x00e1;n
+                en capas de aplicaci&#x00f3;n diferentes o procesos f&#x00ed;sicos diferentes, puede ser un problema asegurar que
+                la <literal>Session</literal> est&#x00e9; abierta cuando se inicializa una colecci&#x00f3;n. Existen dos formas
+                b&#x00e1;sicas de tratar este tema:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        En una aplicaci&#x00f3;n basada web, puede usarse un filtro de servlets para cerrar la
+                        <literal>Session</literal> s&#x00f3;lo bien al final de una petici&#x00f3;n de usuario, una
+                        vez que el rendering de la vista est&#x00e9; completa (el patr&#x00f3;n <emphasis>Sesi&#x00f3;n Abierta en
+                        Vista (Open Session in View)</emphasis>). Por supuesto, estos sitios requieren una
+                        fuerte demanda de correcci&#x00f3;n del manejo de excepciones de tu infraestructura de
+                        aplicaci&#x00f3;n. Es de una importancia vital que la <literal>Session</literal> est&#x00e9;
+                        cerrada y la transacci&#x00f3;n terminada antes de volver al usuario, incluso cuando ocurra
+                        una excepci&#x00f3;n durante el rendering de la p&#x00e1;gina. Para este enfoque, el filtro de servlet tiene
+                        que ser capaz de accceder la <literal>Session</literal>. Recomendamos que se use una variable
+                        <literal>ThreadLocal</literal> para tener la <literal>Session</literal> actual (ver
+                        el cap&#x00ed;tulo 1, <xref linkend="quickstart-playingwithcats"/>, para una implementaci&#x00f3;n de ejemplo).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        En una aplciaci&#x00f3;n con una grada de negocios separada, la l&#x00f3;gica de negocio debe "preparar"
+                        todas las colecciones que se vayan a necesitar por la grada web antes de volver.
+                        Esto significa que la grada de negocios debe cargar todos los datos y devolver a la grada de
+                        presentaci&#x00f3;n web todos los datos que se requieran para un caso de uso en particular
+                        ya inicializados. Usualmente, la aplicaci&#x00f3;n llama a <literal>Hibernate.initialize()</literal>
+                        para cada colecci&#x00f3;n que se necesitar&#x00e1; en la grada web (esta llamada debe ocurrir antes que la
+                        sesi&#x00f3;n sea cerrada) o recupera la colecci&#x00f3;n tempranamente usando una consulta de Hibernate con una
+                        cl&#x00e1;usula <literal>FETCH</literal> o una <literal>FetchMode.JOIN</literal> en
+                        <literal>Criteria</literal>. Esto es usualmente m&#x00e1;s f&#x00e1;cil si adoptas el patr&#x00f3;n
+                        <emphasis>Comando</emphasis> en vez de un <emphasis>Fachada de Sesi&#x00f3;n</emphasis>.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Puedes tambi&#x00e9;n adjuntar un objeto cargado previamente a una nueva <literal>Session</literal>
+                        con <literal>merge()</literal> o <literal>lock()</literal> antes de acceder a colecciones
+                        no inicializadas (u otros proxies). &#x00a1;No, Hibernate no, y ciertamente <emphasis>no
+                        debe</emphasis> hacer esto autom&#x00e1;ticamente, ya que introducir&#x00ed;a sem&#x00e1;nticas de transacci&#x00f3;n ad hoc!
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                A veces no quieres inicializar una colecci&#x00f3;n grande, pero necesitas a&#x00fa;n alguna informacion sobre
+                ella (como su tama&#x00f1;o) o un subconjunto de los datos.
+            </para>
+
+            <para>
+                Puedes usar un filtro de colecciones para obtener el tama&#x00f1;o de una colecci&#x00f3;n sin inicializarla:
+            </para>
+
+            <programlisting><![CDATA[( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()]]></programlisting>
+
+            <para>
+                El m&#x00e9;todo <literal>createFilter()</literal> se usa tambi&#x00e9;n para recuperar eficientemente subconjuntos
+                de una colecci&#x00f3;n sin necesidad de inicializar toda la colecci&#x00f3;n:
+            </para>
+
+            <programlisting><![CDATA[s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-batch">
+            <title>Usando recuperaci&#x00f3;n en lotes</title>
+
+            <para>
+                Hibernate puede hacer un uso eficiente de la recuperaci&#x00f3;n en lotes, esto es, Hibernate puede cargar
+                muchos proxies sin inicializar si se accede a un proxy (o colecciones). La recuperaci&#x00f3;n en lotes es una
+                optimizaci&#x00f3;n de la estrategia de recuperaci&#x00f3;n por selecci&#x00f3;n perezosa. Hay dos formas en que puedes afinar
+                la recuperaci&#x00f3;n en lotes: a nivel de la clase o de la colecci&#x00f3;n.
+            </para>
+
+            <para>
+                La recuperaci&#x00f3;n en lotes para clases/entidades es m&#x00e1;s f&#x00e1;cil de entender. Imagina que tienes la siguiente
+                situaci&#x00f3;n en tiempo de ejecuci&#x00f3;n: Tienes 25 instancias de <literal>Cat</literal> cargadas en una
+                <literal>Session</literal>, cada <literal>Cat</literal> tiene una referencia a su <literal>owner</literal>,
+                una <literal>Person</literal>. La clase <literal>Person</literal> est&#x00e1; mapeada con un proxy,
+                <literal>lazy="true"</literal>. Si ahora iteras a trav&#x00e9;s de todos los gatos y llamas a
+                <literal>getOwner()</literal> para cada uno, Hibernate por defecto ejecutar&#x00e1; 25 sentencias
+                <literal>SELECT</literal> para traer los due&#x00f1;os tratados con proxies. Puedes afinar este comportamiento
+                especificando un <literal>batch-size</literal> en el mapeo de <literal>Person</literal>:
+            </para>
+
+            <programlisting><![CDATA[<class name="Person" batch-size="10">...</class>]]></programlisting>
+
+            <para>
+                Hibernate ahora ejecutar&#x00e1; s&#x00f3;lo tres consultas, el patr&#x00f3;n es 10, 10, 5.
+            </para>
+
+            <para>
+                Tambi&#x00e9;n puedes habilitar la recuperaci&#x00f3;n en lotes para colecciones. Por ejemplo, si cada
+                <literal>Person</literal> tiene una colecci&#x00f3;n perezosa de <literal>Cat</literal>s, y hay 10
+                personas actualmente cargadas en la <literal>Session</literal>, iterar a trav&#x00e9;s de las 10 personas
+                generar&#x00e1; 10 <literal>SELECT</literal>s, una para cada llamada a <literal>getCats()</literal>.
+                Si habilitas la recuperaci&#x00f3;n en lotes para la colecci&#x00f3;n de <literal>cats</literal> en el mapeo de
+                <literal>Person</literal>, Hibernate puede recuperar por adelantado las colecciones:
+            </para>
+
+            <programlisting><![CDATA[<class name="Person">
+    <set name="cats" batch-size="3">
+        ...
+    </set>
+</class>]]></programlisting>
+
+            <para>
+                Con un <literal>batch-size</literal> de 3, Hibernate cargar&#x00e1; 3, 3, 3, 1 colecciones en cuatro
+                <literal>SELECT</literal>s. Una vez m&#x00e1;s, el valor del atributo depende del n&#x00fa;mero esperado de
+                colecciones sin inicializar en una <literal>Session</literal> en particular.
+            </para>
+
+            <para>
+                La recuperaci&#x00f3;n de coleccione en lotes es particularmente &#x00fa;til si tienes un &#x00e1;rbol anidado de
+                &#x00ed;tems, es decir, el t&#x00ed;pico patr&#x00f3;n de cuenta de materiales. (Aunque un <emphasis>conjunto
+                anidado</emphasis> o una <emphasis>ruta materializada</emphasis> podr&#x00ed;a ser una mejor opci&#x00f3;n
+                para &#x00e1;rboles que sean de lectura en la mayor&#x00ed;a de los casos.)
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-subselect">
+            <title>Usando recuperaci&#x00f3;n por subselecci&#x00f3;n</title>
+
+            <para>
+                Si una colecci&#x00f3;n perezosa o proxy monovaluado tiene que ser recuperado, Hibernate los carga a todos,
+                volviendo a ejecutar la consulta original en una subselecci&#x00f3;n. Esto funciona de la misma forma que
+                la recuperaci&#x00f3;n en lotes, sin carga fragmentaria.
+            </para>
+            
+            <!-- TODO: Write more about this -->
+
+        </sect2>
+        
+        <sect2 id="performance-fetching-lazyproperties">
+            <title>Usando recuperaci&#x00f3;n perezosa de propiedades</title>
+
+            <para>
+                Hibernate3 soporta la recuperaci&#x00f3;n perezosa de propiedades individuales. Esta t&#x00e9;cnica de optimizaci&#x00f3;n
+                es tambi&#x00e9;n conocida como <emphasis>grupos de recuperaci&#x00f3;n (fetch groups)</emphasis>. Por favor, nota
+                que &#x00e9;ste es mayormente un aspecto de marketing, ya que en la pr&#x00e1;ctica, optimizar lecturas de filas es
+                mucho m&#x00e1;s importante que la optimizaci&#x00f3;n de lectura de columnas. Sin embargo, cargar s&#x00f3;lo algunas
+                propiedades de una clase podr&#x00ed;a ser &#x00fa;til en casos extremos, cuando tablas heredadas tienen cientos de
+                columnas y el modelo de datos no puede ser mejorado.
+            </para>
+
+            <para>
+                Para habilitar la carga perezosa de propiedades, establece el atributo <literal>lazy</literal> en tus
+                mapeos de propiedades:
+            </para>
+
+            <programlisting><![CDATA[<class name="Document">
+       <id name="id">
+        <generator class="native"/>
+    </id>
+    <property name="name" not-null="true" length="50"/>
+    <property name="summary" not-null="true" length="200" lazy="true"/>
+    <property name="text" not-null="true" length="2000" lazy="true"/>
+</class>]]></programlisting>
+
+            <para>
+                &#x00a1;La carga perezosa de propiedades requiere la instrumentaci&#x00f3;n del bytecode en tiempo
+                de construcci&#x00f3;n! Si tus clases persistentes no son mejoradas, Hibernate ignorar&#x00e1; silenciosamente
+                la configuraci&#x00f3;n perezosa de propiedades y caer&#x00e1; en recuperaci&#x00f3;n inmediata.
+            </para>
+
+            <para>
+                Para la instrumentaci&#x00f3;n del bytecode, usa la siguiente tarea Ant:
+            </para>
+
+            <programlisting><![CDATA[<target name="instrument" depends="compile">
+    <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
+        <classpath path="${jar.path}"/>
+        <classpath path="${classes.dir}"/>
+        <classpath refid="lib.class.path"/>
+    </taskdef>
+
+    <instrument verbose="true">
+        <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
+            <include name="*.class"/>
+        </fileset>
+    </instrument>
+</target>]]></programlisting>
+
+            <para>
+                Una forma diferente (&#x00bf;mejor?) de evitar lecturas innecesarias de columnas, al menos para
+                transacciones de s&#x00f3;lo lectura es usar las funcionalidades de proyecci&#x00f3;n de consultas HQL o Criteria.
+                Esto evita la necesidad de procesar el bytecode en tiempo de construcci&#x00f3;n y ciertamente es una soluci&#x00f3;n
+                preferida.
+            </para>
+            
+            <para>
+                Puedes forzar la usual recuperaci&#x00f3;n temprana de propiedades usando <literal>fetch all properties</literal>
+                en HQL.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="performance-cache" revision="1">
+        <title>El Cach&#x00e9; de Segundo Nivel</title>
+
+        <para>
+            Una <literal>Session</literal> de Hibernate es una cach&#x00e9; de datos persistentes a nivel de transacci&#x00f3;n.
+            Es posible configurar un cluster o cach&#x00e9; a nivel de JVM (a nivel de <literal>SessionFactory</literal>)
+            sobre una base de clase-a-clase o colecci&#x00f3;n-a-colecci&#x00f3;n. Puedes incluso enchufar una cach&#x00e9; en cluster.
+            S&#x00e9; cuidadoso. Las cach&#x00e9;s nunca est&#x00e1;n al tanto de los cambios hechos por otra aplicaci&#x00f3;n al almac&#x00e9;n persistente
+            (aunque pueden ser configurados para expirar regularmente los datos en cach&#x00e9;).
+        </para>
+        
+        <para>
+            Por defecto, Hibernate usa EHCache para caching a nivel de JVM. (El soporte a JCS ahora est&#x00e1; despreciado
+            y ser&#x00e1; quitado en una futura versi&#x00f3;n de Hibernate.) Puedes elegir una implementaci&#x00f3;n diferente estableciendo
+            el nombre de una clase que implemente <literal>org.hibernate.cache.CacheProvider</literal> usando la propiedad
+            <literal>hibernate.cache.provider_class</literal>.
+        </para>
+
+        <table frame="topbot" id="cacheproviders" revision="1">
+            <title>Proveedores de Cach&#x00e9;</title>
+            <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="3*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Cach&#x00e9;</entry>
+              <entry>clase del Provedor</entry>
+              <entry>Tipo</entry>
+              <entry>Cluster Seguro</entry>
+              <entry>Cach&#x00e9; de Consultas Soportado</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>Hashtable (no pensado para uso en producci&#x00f3;n)</entry>
+                <entry><literal>org.hibernate.cache.HashtableCacheProvider</literal></entry>
+                <entry>memoria</entry>
+                <entry></entry>
+                <entry>s&#x00ed;</entry>
+            </row>
+            <row>
+                <entry>EHCache</entry>
+                <entry><literal>org.hibernate.cache.EhCacheProvider</literal></entry>
+                <entry>memoria, disco</entry>
+                <entry></entry>
+                <entry>s&#x00ed;</entry>
+            </row>
+            <row>
+                <entry>OSCache</entry>
+                <entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
+                <entry>memoria, disco</entry>
+                <entry></entry>
+                <entry>s&#x00ed;</entry>
+            </row>
+            <row>
+                <entry>SwarmCache</entry>
+                <entry><literal>org.hibernate.cache.SwarmCacheProvider</literal></entry>
+                <entry>clusterizado (ip multicast)</entry>
+                <entry>s&#x00ed; (invalidaci&#x00f3;n en cluster)</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>TreeCache de JBoss</entry>
+                <entry><literal>org.hibernate.cache.TreeCacheProvider</literal></entry>
+                <entry>clusterizado (ip multicast), transaccional</entry>
+                <entry>s&#x00ed; (replicaci&#x00f3;n)</entry>
+                <entry>s&#x00ed; (requiere sincronizaci&#x00f3;n de reloj)</entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <sect2 id="performance-cache-mapping">
+            <title>Mapeos de cach&#x00e9;</title>
+
+            <para>
+                El elemento <literal>&lt;cache&gt;</literal> de una mapeo de clase o colecci&#x00f3;n tiene la siguiente
+                forma:
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="cache1" coords="2 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<cache 
+    usage="transactional|read-write|nonstrict-read-write|read-only"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="cache1">
+                        <para>
+                            <literal>usage</literal> especifica la estrategia de caching:
+                            <literal>transactional</literal>,
+                            <literal>read-write</literal>,
+                            <literal>nonstrict-read-write</literal> o
+                            <literal>read-only</literal>
+                        </para>
+                    </callout>                   
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                Alternativamente (&#x00bf;preferiblemente?), puedes especificar los elementos
+                <literal>&lt;class-cache&gt;</literal> y <literal>&lt;collection-cache&gt;</literal> en
+                <literal>hibernate.cfg.xml</literal>.
+            </para>
+            
+            <para>
+                El atributo <literal>usage</literal> especifica una <emphasis>estrategia de concurrencia al
+                cach&#x00e9;</emphasis>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-cache-readonly">
+            <title>Estrategia: s&#x00f3;lo lectura (read only)</title>
+
+            <para>
+                Si tu aplicaci&#x00f3;n necesita leer pero nunca modificar las instancias de una clase persistente,
+                puede usarse un cach&#x00e9; <literal>read-only</literal>. Esta es la mejor y m&#x00e1;s simple estrategia.
+                Es incluso perfectamente segura de usar en un cluster.
+            </para>
+
+            <programlisting><![CDATA[<class name="eg.Immutable" mutable="false">
+    <cache usage="read-only"/>
+    ....
+</class>]]></programlisting>
+
+        </sect2>
+
+
+        <sect2 id="performance-cache-readwrite">
+            <title>Estrategia: lectura/escritura (read/write)</title>
+
+            <para>
+                Si la aplicaci&#x00f3;n necesita actualizar datos, un cach&#x00e9; <literal>read-write</literal> podr&#x00ed;a ser apropiado.
+                Esta estrategia de cach&#x00e9; nunca debe ser usada si se requiere nivel de aislamiento serializable de
+                transacciones. Si el cach&#x00e9; es usado en un entorno JTA, debes especificar la propiedad
+                <literal>hibernate.transaction.manager_lookup_class</literal>, mencionando una estrategia para obtener
+                el <literal>TransactionManager</literal> de JTA. En otros entornos, debes asegurarte que la transacci&#x00f3;n
+                est&#x00e9; completada cuando se llame a <literal>Session.close()</literal> o
+                <literal>Session.disconnect()</literal>. Si deseas usar esta estrategia en un cluster, debes asegurarte
+                que la implementaci&#x00f3;n de cach&#x00e9; subyacente soporta bloqueos. Los provedores de cach&#x00e9; internos
+                predeterminados <emphasis>no</emphasis> no lo soportan.
+            </para>
+
+            <programlisting><![CDATA[<class name="eg.Cat" .... >
+    <cache usage="read-write"/>
+    ....
+    <set name="kittens" ... >
+        <cache usage="read-write"/>
+        ....
+    </set>
+</class>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-cache-nonstrict">
+            <title>Estrategia: lectura/escritura no estricta (nonstrict read/write)</title>
+
+            <para>
+                Si la aplicaci&#x00f3;n necesita s&#x00f3;lo ocasionalmente actualizar datos (es decir, es extremadamente inprobable
+                que dos transacciones intenten actualizar el mismo &#x00ed;tem simult&#x00e1;neamente) y no se requiere de un
+                aislamiento de transacciones estricto, un cach&#x00e9; <literal>nonstrict-read-write</literal> podr&#x00ed;a ser
+                apropiado. Si se usa el cach&#x00e9; en un entorno JTA, debes especificar
+                <literal>hibernate.transaction.manager_lookup_class</literal>. En otros entornos, debes asegurarte que la
+                transacci&#x00f3;n se haya completado cuando se llame a <literal>Session.close()</literal> o
+                <literal>Session.disconnect()</literal>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-cache-transactional">
+            <title>Estrategia: transaccional</title>
+
+            <para>
+                La estrategia de cach&#x00e9; <literal>transactional</literal> brinda soporte a provedores de cach&#x00e9;s
+                completamente transaccionales como TreeCache de JBoss. Un cach&#x00e9; as&#x00ed;, puede s&#x00f3;lo ser usado en un
+                entorno JTA y debes especificar <literal>hibernate.transaction.manager_lookup_class</literal>. 
+            </para>
+
+        </sect2>
+        
+        <para>
+            Ninguno de los provedores de cach&#x00e9; soporta todas las estrategias de concurrencia al cach&#x00e9;. La siguiente
+            tabla muestra qu&#x00e9; provedores son compatibles con qu&#x00e9; estrategias de concurrencia.
+        </para>
+
+        <table frame="topbot">
+            <title>Soporte a Estrategia de Concurrencia a Cach&#x00e9;</title>
+            <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="1*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Cach&#x00e9;</entry>
+              <entry>read-only</entry>
+              <entry>nonstrict-read-write</entry>
+              <entry>read-write</entry>
+              <entry>transactional</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>Hashtable (no pensado para uso en producci&#x00f3;n)</entry>
+                <entry>s&#x00ed;</entry>
+                <entry>s&#x00ed;</entry>
+                <entry>s&#x00ed;</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>EHCache</entry>
+                <entry>s&#x00ed;</entry>
+                <entry>s&#x00ed;</entry>
+                <entry>s&#x00ed;</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>OSCache</entry>
+                <entry>s&#x00ed;</entry>
+                <entry>s&#x00ed;</entry>
+                <entry>s&#x00ed;</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>SwarmCache</entry>
+                <entry>s&#x00ed;</entry>
+                <entry>s&#x00ed;</entry>
+                <entry></entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>JBoss TreeCache</entry>
+                <entry>s&#x00ed;</entry>
+                <entry></entry>
+                <entry></entry>
+                <entry>s&#x00ed;</entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+    </sect1>
+
+    <sect1 id="performance-sessioncache" revision="2">
+        <title>Gestionando los cach&#x00e9;s</title>
+
+        <para>
+            Siempre que pases un objeto a <literal>save()</literal>, <literal>update()</literal>
+            o <literal>saveOrUpdate()</literal> y siempre que recuperes un objeto usando
+            <literal>load()</literal>, <literal>get()</literal>, <literal>list()</literal>, 
+            <literal>iterate()</literal> o <literal>scroll()</literal>, ese objeto es agregado
+            al cach&#x00e9; interno de la <literal>Session</literal>.
+        </para>
+        <para>
+            Cuando subsecuentemente se llame a <literal>flush()</literal>, el estado de ese objeto ser&#x00e1;
+            sincronizado con la base de datos. Si no quieres que ocurra esta sincronizaci&#x00f3;n o si est&#x00e1;s
+            procesando un n&#x00fa;mero enorme de objetos y necesitas gestionar la memoria eficientemente,
+            puede usarse el m&#x00e9;todo <literal>evict()</literal> para quitar el objeto y sus colecciones
+            del cach&#x00e9; de primer nivel.
+        </para>
+        
+        <programlisting><![CDATA[ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
+while ( cats.next() ) {
+    Cat cat = (Cat) cats.get(0);
+    doSomethingWithACat(cat);
+    sess.evict(cat);
+}]]></programlisting>
+        
+        <para>
+            La <literal>Session</literal> tambi&#x00e9;n provee un m&#x00e9;todo <literal>contains()</literal> para determinar
+            si una instancia pertenece al cach&#x00e9; de la sesi&#x00f3;n.
+        </para>
+        
+        <para>
+            Para desahuciar (evict) todos los objetos del cach&#x00e9; de sesi&#x00f3;n, llama a <literal>Session.clear()</literal>.
+        </para>
+        
+        <para>
+            Para el cach&#x00e9; de segundo nivel, hay m&#x00e9;todos definidos en <literal>SessionFactory</literal> para
+            desahuciar el estado en cach&#x00e9; de una instancia, clase entera, instancia de colecci&#x00f3;n o rol
+            enter de colecci&#x00f3;n.
+        </para>
+        
+        <programlisting><![CDATA[sessionFactory.evict(Cat.class, catId); //evict a particular Cat
+sessionFactory.evict(Cat.class);  //evict all Cats
+sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
+sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections]]></programlisting>
+
+        <para>
+            El <literal>CacheMode</literal> controla c&#x00f3;mo una sesi&#x00f3;n en particular interact&#x00fa;a con el cach&#x00e9; de segundo
+            nivel.
+        </para>
+        
+        <itemizedlist>
+        <listitem>
+        <para>
+            <literal>CacheMode.NORMAL</literal> - lee &#x00ed;tems desde y escribe &#x00ed;tems hacia el cach&#x00e9; de segundo nivel
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.GET</literal> - lee &#x00ed;tems del cach&#x00e9; de segundo nivel, pero no escribe al cach&#x00e9; de
+            segundo nivel excepto al actualizar datos
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.PUT</literal> - escribe &#x00ed;tems al cach&#x00e9; de segundo nivel, pero no lee del cach&#x00e9; de segundo
+            nivel
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.REFRESH</literal> - escribe &#x00ed;tems al cach&#x00e9; de segundo nivel, pero no lee del cach&#x00e9; de
+            segundo nivel, salt&#x00e1;ndose el efecto de <literal>hibernate.cache.use_minimal_puts</literal>, forzando
+            un refresco del cach&#x00e9; de segundo nivel para todos los &#x00ed;tems le&#x00ed;dos de la base de datos
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            Para navegar por los contenidos de una regi&#x00f3;n de cach&#x00e9; de segundo nivel o de consultas, usa la API de
+            <literal>Statistics</literal>:
+        </para>
+        
+        <programlisting><![CDATA[Map cacheEntries = sessionFactory.getStatistics()
+        .getSecondLevelCacheStatistics(regionName)
+        .getEntries();]]></programlisting>
+        
+        <para>
+            Necesitar&#x00e1;s habilitar las estad&#x00ed;sticas y, opcionalmente, forzar a Hibernate para que guarde las
+            entradas del cach&#x00e9; en un formato m&#x00e1;s entendible por humanos:
+        </para>
+        
+        <programlisting><![CDATA[hibernate.generate_statistics true
+hibernate.cache.use_structured_entries true]]></programlisting>       
+                
+    </sect1>
+    
+    <sect1 id="performance-querycache" revision="1">
+        <title>El Cach&#x00e9; de Consultas</title>
+
+        <para>
+            Los conjuntos resultado de consultas tambi&#x00e9;n pueden tratarse en cach&#x00e9;. Esto s&#x00f3;lo es &#x00fa;til para
+            consultas que se ejecutan frecuentemente con los mismos par&#x00e1;metros. Para usar el cach&#x00e9; de consultas
+            primero debes habilitarlo:
+        </para>
+
+        <programlisting><![CDATA[hibernate.cache.use_query_cache true]]></programlisting>       
+        
+        <para>
+            Esta configuraci&#x00f3;n causa la creaci&#x00f3;n de dos nuevas regiones de cach&#x00e9; - una teniendo en cach&#x00e9;
+            conjuntos resultado de consulta (<literal>org.hibernate.cache.StandardQueryCache</literal>),
+            el otro teniendo timestamps de las actualizaciones m&#x00e1;s recientes a tablas consultables
+            (<literal>org.hibernate.cache.UpdateTimestampsCache</literal>). Nota que el cach&#x00e9; de consultas
+            no pone en cach&#x00e9; el estado de las entidades reales en el conjunto resultado; s&#x00f3;lo tiene en cach&#x00e9;
+            valores indentificadores y resultados de tipo de valor. De modo que el cach&#x00e9; de consultas siempre
+            debe ser usado en conjunci&#x00f3;n con el cach&#x00e9; de segundo nivel.
+        </para>
+        
+        <para>
+            La mayor&#x00ed;a de consultas no se benefician del tratamiento en cach&#x00e9;, de modo que por defecto las
+            consultas no son tratadas en cach&#x00e9;. Para habilitar el tratamiento en cach&#x00e9;, llama a
+            <literal>Query.setCacheable(true)</literal>. Esta llamada permite a la consulta buscar
+            resultados existentes en cach&#x00e9; o agregar sus resultados al cach&#x00e9; cuando se ejecuta.
+        </para>
+        
+        <para>
+            Si requieres un control finamente granularizado sobre las pol&#x00ed;ticas de expiraci&#x00f3;n del cach&#x00e9; de
+            consultas, puedes especificar una regi&#x00f3;n de cach&#x00e9; con nombre para una consulta en particular
+            llamando a <literal>Query.setCacheRegion()</literal>.
+        </para>
+        
+        <programlisting><![CDATA[List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
+    .setEntity("blogger", blogger)
+    .setMaxResults(15)
+    .setCacheable(true)
+    .setCacheRegion("frontpages")
+    .list();]]></programlisting>
+
+        <para>
+            Si la consulta debe forzar un refresco de si regi&#x00f3;n del cach&#x00e9; de consultas, debes llamar a
+            <literal>Query.setCacheMode(CacheMode.REFRESH)</literal>. Esto es particularmente &#x00fa;til en casos donde
+            los datos subyacentes pueden haber sido actualizados por medio de un proceso separado (es decir,
+            no modificados a trav&#x00e9;s de Hibernate) y permite a la aplicaci&#x00f3;n refrescar selectivamente conjuntos
+            resultado de consultas en particular. Esto es una alternativa m&#x00e1;s eficient al desahuciamiento de una
+            regi&#x00f3;n del cach&#x00e9; de consultas v&#x00ed;a <literal>SessionFactory.evictQueries()</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="performance-collections">
+        <title>Entendiendo el rendimiento de Colecciones</title>
+
+        <para>
+            Ya hemos llevado un buen tiempo hablando sobre colecciones.
+            En esta secci&#x00f3;n resaltaremos un par de temas m&#x00e1;s sobre c&#x00f3;mo las colecciones
+            se comportan en tiempo de ejecuci&#x00f3;n.
+        </para>
+
+        <sect2 id="performance-collections-taxonomy">
+            <title>Taxonomia</title>
+
+            <para>Hibernate define tres tipos b&#x00e1;sicos de colecciones:</para>
+
+            <itemizedlist>
+            <listitem>
+                <para>colecciones de valores</para>
+            </listitem>
+            <listitem>
+                <para>asociaciones uno a muchos</para>
+            </listitem>
+            <listitem>
+                <para>asociaciones muchos a muchos</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                Esta clasificaci&#x00f3;n distingue las varias tablas y relaciones de clave for&#x00e1;nea pero no nos
+                dice absolutamente todo lo que necesitamos saber sobre el modelo relacional. Para entender
+                completamente la estructura relacional y las caracter&#x00ed;sticas de rendimiento, debemos considerar
+                la estructura de la clave primaria que es usada por Hibernate para actualizar o borrar filas de
+                colecci&#x00f3;n. Esto sugiere la siguiente clasificaci&#x00f3;n:
+            </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>colecciones indexadas</para>
+            </listitem>
+            <listitem>
+                <para>conjuntos (sets)</para>
+            </listitem>
+            <listitem>
+                <para>bolsas (bags)</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                Todas las colecciones indexadas (mapas, listas, arrays) tienen una clave primaria
+                consistente de las columnas <literal>&lt;key&gt;</literal> y <literal>&lt;index&gt;</literal>.
+                En este caso las actualizaciones de colecciones son usualmente extremadamente eficientes.
+                La clave primaria puede ser indexada f&#x00e1;cilmente y una fila en particular puede ser localizada
+                cuando Hibernate intenta actualizarla o borrarla.
+            </para>
+                        
+            <para>
+                Los conjuntos (sets) tienen una clave primaria consistente en <literal>&lt;key&gt;</literal>
+                y columnas de elemento. Esto puede ser menos eficiente para algunos tipos de elemento de
+                colecci&#x00f3;n, particularmente elementos compuestos o texto largo, o campos binarios. La base de datos
+                puede no ser capaz de indexar una clave primaria compleja eficientemente. Por otra parte,
+                para asociaciones uno a muchos o muchos a muchos, particularmente en el caso de identificadores
+                sint&#x00e9;ticos, es probable que s&#x00f3;lo sea tan eficiente. (Nota al m&#x00e1;rgen: si quieres que
+                <literal>SchemaExport</literal> realmente cree la clave primaria de un <literal>&lt;set&gt;</literal>
+                por ti, debes declarar todas las columnas como <literal>not-null="true"</literal>.)
+            </para>
+
+            <para>
+                Los mapeos de <literal>&lt;idbag&gt;</literal> definen una clave delegada, de modo que siempre
+                resulten eficientes de actualizar. De hecho, son el mejor caso.
+            </para>
+            
+            <para>
+                Los bags son el peor caso. Ya que un bag permite valores de elementos duplicados y no tiene
+                ninguna columna &#x00ed;ndice, no puede definirse ninguna clave primaria. Hibernate no tiene forma de
+                distinguir entre filas duplicadas. Hibernate resuelve este problema quitando completamente
+                (en un solo <literal>DELETE</literal>) y recreando la colecci&#x00f3;n siempre que cambia.
+                Esto podr&#x00ed;a ser muy ineficiente.
+            </para>
+
+            <para>
+                Nota que para una asociaci&#x00f3;n uno-a-muchos, la "clave primaria" puede no ser la clave
+                primaria f&#x00ed;sica de la tabla de base de datos; pero incluso en este caso, la clasificaci&#x00f3;n
+                anterior es &#x00fa;til todav&#x00ed;a. (A&#x00fa;n refleja c&#x00f3;mo Hibernate "localiza" filas individuales de la
+                colecci&#x00f3;n.)
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-collections-mostefficientupdate">
+            <title>Las listas, mapas, idbags y conjuntos son las colecciones m&#x00e1;s eficientes de actualizar</title>
+
+            <para>
+                Desde la discusi&#x00f3;n anterior, debe quedar claro que las colecciones indexadas y
+                (usualmente) los conjuntos permiten la operaci&#x00f3;n m&#x00e1;s eficiente en t&#x00e9;rminos de a&#x00f1;adir,
+                quitar y actualizar elementos.
+            </para>
+
+            <para>
+                Hay, discutiblemente, una ventaja m&#x00e1;s que las colecciones indexadas tienen sobre otros
+                conjuntos para las asociaciones muchos a muchos o colecciones de valores.  Debido a la
+                estructura de un <literal>Set</literal>, Hibernate ni siquiera actualiza una fila con
+                <literal>UPDATE</literal> cuando se "cambia" un elemento. Los cambios a un <literal>Set</literal>
+                siempre funcionan por medio de <literal>INSERT</literal> y <literal>DELETE</literal>
+                (de filas individuales). Una vez m&#x00e1;s, esta consideraci&#x00f3;n no se aplica a las asociaciones
+                uno a muchos.
+            </para>
+
+            <para>
+                Despu&#x00e9;s de observar que los arrays no pueden ser perezosos, podr&#x00ed;amos concluir que las
+                listas, mapas e idbags son los tipos m&#x00e1;s eficientes de colecciones (no inversas), con los
+                conjuntos (sets) no muy por detr&#x00e1;s. Se espera que los sets sean el tipo m&#x00e1;s com&#x00fa;n de colecci&#x00f3;n
+                en las aplicaciones de Hibernate. Esto es debido a que la sem&#x00e1;ntica de los sets es la m&#x00e1;s
+                natural en el modelo relacional.
+            </para>
+
+            <para>
+                Sin embargo, en modelos de dominio de Hibernate bien die&#x00f1;ados, usualmente vemos que la mayor&#x00ed;a
+                de las colecciones son de hecho asociaciones uno-a-muchos con <literal>inverse="true"</literal>.
+                Para estas asociaciones, la actualizaci&#x00f3;n es manejada por el extremo muchos-a-uno de la asociaci&#x00f3;n,
+                y las consideraciones de este tipo sobre el rendimiento de actualizaci&#x00f3;n de colecciones simplemente
+                no se aplican.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-collections-mostefficentinverse">
+            <title>Los Bags y las listas son las colecciones inversas m&#x00e1;s eficientes</title>
+
+            <para>
+                Justo antes que tires a la zanja los bags para siempre, hay un caso en particular en el que
+                los bags son muchos m&#x00e1;s eficientes que los conjuntos. Para una colecci&#x00f3;n con
+                <literal>inverse="true"</literal> (el idioma est&#x00e1;ndar de relaciones uno-a-muchos bidireccionales,
+                por ejemplo) &#x00a1;podemos a&#x00f1;adir elementos a un bag o lista sin necesidad de inicializar (fetch)
+                los elementos del bag! Esto se debe a que <literal>Collection.add()</literal> o
+                <literal>Collection.addAll()</literal> siempre deben devolver true para un bag o <literal>List</literal>
+                (no como un <literal>Set</literal>). Esto puede hacer el siguiente c&#x00f3;digo com&#x00fa;n mucho m&#x00e1;s r&#x00e1;pido.
+            </para>
+
+            <programlisting><![CDATA[Parent p = (Parent) sess.load(Parent.class, id);
+    Child c = new Child();
+    c.setParent(p);
+    p.getChildren().add(c);  //no need to fetch the collection!
+    sess.flush();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-collections-oneshotdelete">
+            <title>Borrado de un solo tiro</title>
+
+            <para>
+                Ocasionalmente, borrar los elementos de una colecci&#x00f3;n uno a uno puede ser extremadamente ineficiente.
+                Hibernate no es completamente est&#x00fa;pido, de modo que sabe no hacer eso, en el caso de una colecci&#x00f3;n
+                nueva-vac&#x00ed;a (si has llamado a <literal>list.clear()</literal>, por ejemplo). En este caso, Hibernate
+                publicar&#x00e1; una sola <literal>DELETE</literal>, &#x00a1;y listo!
+            </para>
+
+            <para>
+                Sup&#x00f3;n que a&#x00f1;adimos un solo elemento a una colecci&#x00f3;n de tama&#x00f1;o veinte y luego quitamos dos elementos.
+                Hibernate publicar&#x00e1; una sentencia <literal>INSERT</literal> y dos sentencias <literal>DELETE</literal>
+                (a menos que la colecci&#x00f3;n sea un bag). Esto es ciertamente deseable.
+            </para>
+
+            <para>
+                Sin embargo, sup&#x00f3;n que quitamos dieciocho elementos, dejando dos y luego a&#x00f1;adimos tres nuevos elementos.
+                Hay dos formas posibles de proceder
+            </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>borrar dieciocho filas una a una y luego insertar tres filas</para>
+            </listitem>
+            <listitem>
+                <para>quitar toda la colecci&#x00f3;n (en un solo <literal>DELETE</literal> de SQL) e insertar todos los
+                cinco elementos actuales (uno a uno)</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                Hibernate no es lo suficientemente inteligente para saber que la segunda opci&#x00f3;n es probablemente m&#x00e1;s
+                r&#x00e1;pida en este caso. (Y que ser&#x00ed;a probablemente indeseable para Hibernate ser tan inteligente;
+                este comportamiento podr&#x00ed;a confundir a disparadores de base de datos, etc.)
+            </para>
+
+            <para>
+                Afortunadamente, puedes forzar este comportamiento (es decir, la segunda estrategia) en cualquier
+                momento descartando (es decir, desreferenciando) la colecci&#x00f3;n original y devolviendo una colecci&#x00f3;n
+                nuevamente instanciada con todos los elementos actuales. Esto puede ser muy &#x00fa;til y potente de vez en
+                cuando.
+            </para>
+            
+            <para>
+                Por supuesto, el borrado-de-un-solo-tiro no se aplica a colecciones mapeadas
+                <literal>inverse="true"</literal>.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="performance-monitoring" revision="1">
+        <title>Monitoreando el rendimiento</title>
+
+        <para>
+            La optimizaci&#x00f3;n no es de mucho uso sin el monitoreo y el acceso a n&#x00fa;meros de rendimiento. Hibernate provee
+            un rango completo de figuras sobre sus operaciones internas. Las estad&#x00ed;sticas en Hibernate est&#x00e1;n disponibles
+            por <literal>SessionFactory</literal>.
+        </para>
+
+        <sect2 id="performance-monitoring-sf" revision="2">
+            <title>Monitoreando una SessionFactory</title>
+
+            <para>
+                Puedes acceder a las m&#x00e9;tricas de <literal>SessionFactory</literal> de dos formas.
+                Tu primera opci&#x00f3;n es llamar a <literal>sessionFactory.getStatistics()</literal> y
+                leer o mostrar por pantalla la <literal>Statistics</literal> por ti mismo.
+            </para>
+
+            <para>
+                Hibernate puede tambi&#x00e9;n usar JMX para publicar las m&#x00e9;tricas si habilitas el MBean
+                <literal>StatisticsService</literal>. Puede habilitar un solo MBean para todas tus
+                <literal>SessionFactory</literal> o una por f&#x00e1;brica. Mira el siguiente c&#x00f3;digo para
+                ejemplos de configuraci&#x00f3;n minimalistas:
+            </para>
+
+            <programlisting><![CDATA[// MBean service registration for a specific SessionFactory
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "myFinancialApp");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
+server.registerMBean(stats, on); // Register the Mbean on the server]]></programlisting>
+
+
+<programlisting><![CDATA[// MBean service registration for all SessionFactory's
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "all");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+server.registerMBean(stats, on); // Register the MBean on the server]]></programlisting>
+
+            <para>
+                POR HACER: Esto no tiene sentido: En el primer caso, recuperamos y usamos el MBean directamente.
+                En el segundo, debemos proporcionar el nombre JNDI en el que se guarda la f&#x00e1;brica de sesiones antes
+                de usarlo. Usa <literal>hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")</literal>
+            </para>
+            <para>
+                Puedes (des)activar el monitoreo de una <literal>SessionFactory</literal>
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        en tiempo de configuraci&#x00f3;n, establece <literal>hibernate.generate_statistics</literal> a
+                        <literal>false</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        en tiempo de ejecuci&#x00f3;n: <literal>sf.getStatistics().setStatisticsEnabled(true)</literal>
+                        o <literal>hibernateStatsBean.setStatisticsEnabled(true)</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Las estad&#x00ed;sticas pueden ser reajustadas program&#x00e1;ticamente usando el m&#x00e9;todo <literal>clear()</literal>.
+                Puede enviarse un resumen a un logger (nivel info) usando el m&#x00e9;todo <literal>logSummary()</literal>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-monitoring-metrics" revision="1">
+            <title>M&#x00e9;tricas</title>
+
+            <para>
+                Hibernate provee un n&#x00fa;mero de m&#x00e9;tricas, desde informaci&#x00f3;n muy b&#x00e1;sica a la especializada
+                s&#x00f3;lo relevante en ciertos escenarios. Todos los contadores disponibles se describen en la
+                API de la interface <literal>Statistics</literal>, en tres categor&#x00ed;as:
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        M&#x00e9;tricas relacionadas al uso general de <literal>Session</literal> usage, tales como
+                        n&#x00fa;mero de sesiones abiertas, conexiones JDBC recuperadas, etc,
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        M&#x00e9;tricas relacionadas a las entidades, colecciones, consultas, y cach&#x00e9;s como un todo.
+                        (tambi&#x00e9;n conocidas como m&#x00e9;tricas globales).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        M&#x00e9;tricas detalladas relacionadas a una entidad, colecci&#x00f3;n, consulta o regi&#x00f3;n de cach&#x00e9;
+                        en particular.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Por ejemplo, puedes comprobar el acceso, p&#x00e9;rdida, y radio de colocaci&#x00f3;n de entidades, colecciones
+                y consultas en el cach&#x00e9;, y el tiempo promedio que necesita una consulta. Ten en cuenta que el n&#x00fa;mero
+                de milisegundos est&#x00e1; sujeto a aproximaci&#x00f3;n en Java. Hibernate est&#x00e1; pegado a la precisi&#x00f3;n de la JVM,
+                en algunas plataformas esto podr&#x00ed;a incuso ser tener s&#x00f3;lo una exactitud de 10 segundos.
+            </para>
+
+            <para>
+                Se usan getters simples para acceder a las m&#x00e9;tricas globales (es decir, no pegadas a una entidad,
+                colecci&#x00f3;n, regi&#x00f3;n de cach&#x00e9;, etc, en particular). Puedes acceder a las m&#x00e9;tricas de una entidad,
+                colecci&#x00f3;n, regi&#x00f3;n de cach&#x00e9; en particular a trav&#x00e9;s de su nombre, y a trav&#x00e9;s de su representaci&#x00f3;n HQL
+                o SQL para las consultas. Por favor refi&#x00e9;rete al Javadoc de la API de <literal>Statistics</literal>,
+                <literal>EntityStatistics</literal>, <literal>CollectionStatistics</literal>,
+                <literal>SecondLevelCacheStatistics</literal>, y <literal>QueryStatistics</literal> para m&#x00e1;s informaci&#x00f3;n.
+                El siguiente c&#x00f3;digo muestra un ejemplo sencillo:
+            </para>
+
+            <programlisting><![CDATA[Statistics stats = HibernateUtil.sessionFactory.getStatistics();
+
+double queryCacheHitCount  = stats.getQueryCacheHitCount();
+double queryCacheMissCount = stats.getQueryCacheMissCount();
+double queryCacheHitRatio =
+  queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
+
+log.info("Query Hit ratio:" + queryCacheHitRatio);
+
+EntityStatistics entityStats =
+  stats.getEntityStatistics( Cat.class.getName() );
+long changes =
+        entityStats.getInsertCount()
+        + entityStats.getUpdateCount()
+        + entityStats.getDeleteCount();
+log.info(Cat.class.getName() + " changed " + changes + "times"  );]]></programlisting>
+
+            <para>
+                Para trabajar sobre todas las entidades, colecciones, consultas y regiones de cach&#x00e9;s, puedes recuperar la
+                lista de nombres de entidades, colecciones, consultas y regiones de cach&#x00e9;s con los siguientes m&#x00e9;todos:
+                <literal>getQueries()</literal>, <literal>getEntityNames()</literal>,
+                <literal>getCollectionRoleNames()</literal>, y <literal>getSecondLevelCacheRegionNames()</literal>.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/persistent_classes.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/persistent_classes.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/persistent_classes.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,478 @@
+<chapter id="persistent-classes" revision="2">
+    <title>Clases Persistentes</title>
+
+    <para>
+        Clases presistentes son clases en una aplicaci&#x00f3;n que implementan las
+        entidades del problema de negocio (por ejemplo, Customer y Order en una
+        aplicaci&#x00f3;n de comercio electr&#x00f3;nico). No todas las instancias de una
+        clase persistente se considera que est&#x00e9;n en el estado persistente,
+        una instancia puede en cambio ser transitoria o estar separada.
+    </para>
+
+    <para>
+        Hibernate funciona mejor si las clases siguen algunas simples reglas, tambi&#x00e9;n
+        conocidas como el modelo de programaci&#x00f3;n de Viejas Clases Java Planas
+        (Plain Old Java Object o POJO). Sin embargo, ninguna de estas reglas son
+        requerimientos r&#x00ed;gidos. En cambio, Hibernate3 asume muy poco acerca de
+        la naturaleza de tus objetos persistentes. Puedes expresar un modelo de dominio en
+        otras formas: usando &#x00e1;rboles de instancias de <literal>Map</literal>,
+        por ejemplo.
+    </para>
+
+    <sect1 id="persistent-classes-pojo">
+        <title>Un ejemplo simple de POJO</title>
+
+        <para>
+            La mayor&#x00ed;a de aplicaciones Java requieren una clase
+            representando felinos.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+public class Cat {
+    private Long id; // identifier
+
+    private Date birthdate;
+    private Color color;
+    private char sex;
+    private float weight;
+    private int litterId;
+
+    private Cat mother;
+    private Set kittens = new HashSet();
+
+    private void setId(Long id) {
+        this.id=id;
+    }
+    public Long getId() {
+        return id;
+    }
+
+    void setBirthdate(Date date) {
+        birthdate = date;
+    }
+    public Date getBirthdate() {
+        return birthdate;
+    }
+
+    void setWeight(float weight) {
+        this.weight = weight;
+    }
+    public float getWeight() {
+        return weight;
+    }
+
+    public Color getColor() {
+        return color;
+    }
+    void setColor(Color color) {
+        this.color = color;
+    }
+
+    void setSex(char sex) {
+        this.sex=sex;
+    }
+    public char getSex() {
+        return sex;
+    }
+
+    void setLitterId(int id) {
+        this.litterId = id;
+    }
+    public int getLitterId() {
+        return litterId;
+    }
+
+    void setMother(Cat mother) {
+        this.mother = mother;
+    }
+    public Cat getMother() {
+        return mother;
+    }
+    void setKittens(Set kittens) {
+        this.kittens = kittens;
+    }
+    public Set getKittens() {
+        return kittens;
+    }
+    
+    // addKitten not needed by Hibernate
+    public void addKitten(Cat kitten) {
+    	kitten.setMother(this);
+	kitten.setLitterId( kittens.size() ); 
+        kittens.add(kitten);
+    }
+}]]></programlisting>
+
+        <para>
+            Aqu&#x00ed; hay cuatro reglas principales a seguir:
+        </para>
+
+        <sect2 id="persistent-classes-pojo-constructor" revision="1">
+            <title>Implementa un constructor sin argumentos</title>
+
+            <para>
+                <literal>Cat</literal> tiene un contructor sin argumentos. Todas las clases persistentes
+                deben tener un constructor por defecto (que puede no ser p&#x00fa;blico) de modo que Hibernate
+                pueda instanciarlas usando <literal>Constructor.newInstance()</literal>. Recomendamos fuertemente tener
+                un constructor por defecto con al menos visibilidad de <emphasis>package</emphasis> para la
+                generaci&#x00f3;n de proxies en tiempo de ejecuci&#x00f3;n en Hibernate.
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-identifier" revision="2">
+            <title>Provee una propiedad identificadora (opcional)</title>
+
+            <para>
+                <literal>Cat</literal> tiene una propiedad llamada <literal>id</literal>. Esta
+                propiedad mapea a la columna clave primaria de la tabla de base de datos. La propiedad
+                podr&#x00ed;a llamarse cualquierCosa, y su tipo podr&#x00ed;a haber sido cualquier tipo
+                primitivo, cualquier tipo de "envoltura" primitivo, <literal>java.lang.String</literal>
+                o <literal>java.util.Date</literal>. (Si tu tabla de base de datos heredada tiene claves
+                compuestas, puedes incluso usar una clase definida por el usuario con propiedades de
+                estos tipos, ver la secci&#x00f3;n sobre identificadores compuestos luego.)
+            </para>
+
+            <para>
+                La propiedad identificadora es estrictamente opcional. Puedes olvidarla y dejar que Hibernate
+                siga internamente la pista de los identificadores del objeto. Sin embargo, no recomendamos esto.
+            </para>
+
+            <para>
+                De hecho, alguna funcionalidad est&#x00e1; disponible s&#x00f3;lo para clases que
+                declaran una propiedad identificadora:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        Reasociaci&#x00f3;n transitiva de objetos separados (actualizaciones o
+                        fusiones en cascada) - ver <xref linkend="objectstate-transitive"/>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session.saveOrUpdate()</literal>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session.merge()</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Recomendamos que declares propiedades identificadoras nombradas-consistentemente
+                en clases persistentes. Mas a&#x00fa;n, recomendamos que uses un tipo nulable
+                (es decir, no primitivo).
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-final">
+            <title>Prefiere las clases no finales (opcional)</title>
+            <para>
+                Un aspecto central de Hibernate, <emphasis>proxies</emphasis>, depende de que
+                las clases persistentes sean ya no finales, o sean ya la implementaci&#x00f3;n
+                de una interface que declare todos los m&#x00e9;todos p&#x00fa;blicos.
+            </para>
+            <para>
+                Puedes persistir con Hibernate clases <literal>final</literal> que no implementen una
+                interface, pero no ser&#x00e1;s capaz de usar proxies para recuperaci&#x00f3;n perezosa
+                de asociaciones, lo que limitar&#x00e1; tus opciones para afinar el rendimiento.
+            </para>
+            <para>
+                Debes tambi&#x00e9;n evitar declarar m&#x00e9;todos <literal>public final</literal>
+                en clases non-final. Si quieres usar una clase con un m&#x00e9;todo <literal>public
+                final</literal>, debes deshabilitar expl&#x00ed;citamente el uso de proxies estableciendo
+                <literal>lazy="false"</literal>.
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-accessors" revision="2">
+            <title>Declara m&#x00e9;todos de acceso y modificaci&#x00f3;n para los campos persistentes (opcional)</title>
+            <para>
+                <literal>Cat</literal> declara m&#x00e9;todos de acceso para todos sus campos persistente.
+                Muchas otras herramientas ORM persisten directamente variables de instancia. Creemos que
+                es mejor proveer una indirecci&#x00f3;n entre el esquema relacional y las estructuras internas de la clase.
+                Por defecto, Hibernate persiste propiedades del estilo JavaBeans, y reconoce nombres de m&#x00e9;todo
+                de la forma <literal>getFoo</literal>, <literal>isFoo</literal> y <literal>setFoo</literal>.
+                Puedes cambiar a acceso directo a campos para propiedades en particular, de ser necesario.
+            </para>
+
+            <para>
+                Las propiedades <emphasis>no</emphasis> necesitan ser declaradas p&#x00fa;blicas. Hibernate puede
+                persistir una propiedad con un par get / set <literal>protected</literal> o <literal>private</literal>.
+            </para>
+        </sect2>
+    </sect1>
+
+    <sect1 id="persistent-classes-inheritance">
+        <title>Implementando herencia</title>
+
+        <para>
+            Una subclase puede a su vez observar la primera y segunda regla. Hereda su
+            propiedad identificadora de la superclase, <literal>Cat</literal>.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+public class DomesticCat extends Cat {
+        private String name;
+
+        public String getName() {
+                return name;
+        }
+        protected void setName(String name) {
+                this.name=name;
+        }
+}]]></programlisting>
+    </sect1>
+
+    <sect1 id="persistent-classes-equalshashcode" revision="1">
+        <title>Implementando <literal>equals()</literal> y <literal>hashCode()</literal></title>
+
+
+        <para> 
+            Tienes que sobrescribir los m&#x00e9;todos <literal>equals()</literal> y <literal>hashCode()</literal>
+            si :
+        </para>
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    piensas poner instancias de clases persistentes en un <literal>Set</literal>
+                    (la forma recomendada de representar asociaciones multivaluadas) 
+                    <emphasis>y</emphasis>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    piensas usar reasociaci&#x00f3;n de instancias separadas.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Hibernate garantiza la equivalencia de identidad persistente (fila de base de datos) y
+            identidad Java s&#x00f3;lo dentro del &#x00e1;mbito de una sesi&#x00f3;n en particular.
+            De modo que en el momento que mezclamos instancias recuperadas en sesiones diferentes,
+            debemos implementar <literal>equals()</literal> y <literal>hashCode()</literal> si
+            deseamos tener una sem&#x00e1;ntica significativa de <literal>Set</literal>s.
+        </para>
+
+        <para>
+            La forma m&#x00e1;s obvia es implementar <literal>equals()</literal>/<literal>hashCode()</literal>
+            comparando el valor identificador de ambos objetos. Si el valor es el mismo, ambos deben ser
+            la misma fila de base de datos, por lo tanto son iguales (si ambos son agregados a un
+            <literal>Set</literal>, s&#x00f3;lo tendremos un elemento en el <literal>Set</literal>).
+            Desafortunadamente, no podemos usar este enfoque con identificadores generados! Hibernate s&#x00f3;lo
+            asignar&#x00e1; valores identificadores a objetos que son persistentes, una instancia reci&#x00e9;n
+            creada no tendr&#x00e1; ning&#x00fa;n valor identificador! Adem&#x00e1;s, si una instancia no est&#x00e1;
+            salvada y est&#x00e1; actualmente en un <literal>Set</literal>, salvarla asignar&#x00e1; un
+            valor identificador al objeto. Si <literal>equals()</literal> and <literal>hashCode()</literal>
+            est&#x00e1;n basados en el valor identificador, el c&#x00f3;digo hash podr&#x00ed;a cambiar,
+            rompiendo el contrato de <literal>Set</literal>. Ver el sitio web de Hibernate para una
+            discusi&#x00f3;n completa de este problema. Observa que esto no es una incidencia de Hibernate,
+            sino la sem&#x00e1;ntica normal de Java de identidad de objeto e igualdad.
+        </para>
+
+        <para>
+            Recomendamos implementar <literal>equals()</literal> y <literal>hashCode()</literal>
+            usando <emphasis>igualdad de clave de negocio (Business key equality)</emphasis>.
+            Igualdad de clave de negocio significa que el m&#x00e9;todo <literal>equals()</literal>
+            compara s&#x00f3;lo las propiedades que forman la clave de negocio, una clave que podr&#x00ed;a
+            identificar nuestra instancia en el mundo real (una clave candidata
+            <emphasis>natural</emphasis>):
+        </para>
+
+        <programlisting><![CDATA[public class Cat {
+
+    ...
+    public boolean equals(Object other) {
+        if (this == other) return true;
+        if ( !(other instanceof Cat) ) return false;
+
+        final Cat cat = (Cat) other;
+
+        if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
+        if ( !cat.getMother().equals( getMother() ) ) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result;
+        result = getMother().hashCode();
+        result = 29 * result + getLitterId();
+        return result;
+    }
+
+}]]></programlisting>
+
+        <para>
+            Nota que una clave de negocio no tiene que ser tan s&#x00f3;lida como
+            una clave primaria candidata de base de datos (ver
+            <xref linkend="transactions-basics-identity"/>). Las propiedades inmutables o
+            &#x00fa;nicas son usualmente buenas candidatas para una clave de negocio.
+        </para>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-dynamicmodels">
+        <title>Modelos din&#x00e1;micos</title>
+
+        <para>
+            <emphasis>Ten en cuenta que las siguientes funcionalidades est&#x00e1;n
+            consideradas actualmente experimentales y pueden cambiar en el futuro
+            cercano.</emphasis>
+        </para>
+
+        <para>
+            Las entidades persistentes no necesariamente tienen que estar representadas
+            como clases POJO o como objetos JavaBean en tiempo de ejecuci&#x00f3;n. Hibernate
+            soporta adem&#x00e1;s modelos din&#x00e1;micos (usando <literal>Map</literal>s de
+            <literal>Map</literal>s en tiempo de ejecuci&#x00f3;n) y la representaci&#x00f3;n
+            de entidades como &#x00e1;rboles de DOM4J. Con este enfoque no escribes clases
+            persistentes, s&#x00f3;lo ficheros de mapeo.
+        </para>
+
+        <para>
+            Por defecto, Hibernate funciona en modo POJO normal. Puedes establecer una
+            representaci&#x00f3;n de entidad por defecto para una <literal>SessionFactory</literal>
+            en particular usando la opci&#x00f3;n de configuraci&#x00f3;n
+            <literal>default_entity_mode</literal>
+            (ver <xref linkend="configuration-optional-properties"/>).
+        </para>
+
+        <para>
+            Los siguientes ejemplos demuestran la representaci&#x00f3;n usando
+            <literal>Map</literal>s. Primero, en el fichero de mapeo,
+            tiene que declararse un <literal>entity-name</literal> en vez de
+            (o como agregado a) un nombre de clase:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class entity-name="Customer">
+
+        <id name="id"
+            type="long"
+            column="ID">
+            <generator class="sequence"/>
+        </id>
+
+        <property name="name"
+            column="NAME"
+            type="string"/>
+
+        <property name="address"
+            column="ADDRESS"
+            type="string"/>
+
+        <many-to-one name="organization"
+            column="ORGANIZATION_ID"
+            class="Organization"/>
+
+        <bag name="orders"
+            inverse="true"
+            lazy="false"
+            cascade="all">
+            <key column="CUSTOMER_ID"/>
+            <one-to-many class="Order"/>
+        </bag>
+
+    </class>
+    
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Ten en cuenta que aunque las asociaciones se declaran usando nombres
+            de clase objetivo, el tipo objetivo de una asociaci&#x00f3;n puede
+            ser adem&#x00e1;s una entidad din&#x00e1;mica en vez de un POJO. 
+        </para>
+
+        <para>
+            Despu&#x00e9;s de establecer el modo de entidad por defecto a
+            <literal>dynamic-map</literal> para la <literal>SessionFactory</literal>,
+            podemos trabajar en tiempo de ejecuci&#x00f3;n con <literal>Map</literal>s
+            de <literal>Map</literal>s:
+        </para>
+
+        <programlisting><![CDATA[Session s = openSession();
+Transaction tx = s.beginTransaction();
+Session s = openSession();
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+
+// Create an organization
+Map foobar = new HashMap();
+foobar.put("name", "Foobar Inc.");
+
+// Link both
+david.put("organization", foobar);
+
+// Save both
+s.save("Customer", david);
+s.save("Organization", foobar);
+
+tx.commit();
+s.close();]]></programlisting>
+
+        <para>
+            Las ventajas de un mapeo din&#x00e1;mico es r&#x00e1;pido tiempo de ciclo
+            de prototipado sin la necesidad de implementaci&#x00f3;n de clases de entidad.
+            Sin embargo, pierdes chequeo de tipos en tiempo de compilaci&#x00f3;n y
+            muy probablemente tratar&#x00e1;s con muchas excepciones en tiempo de ejecuci&#x00f3;n.
+            Gracias al mapeo de Hibernate, el esquema de base de datos puede estar facilmente
+            sano y normalizado, permitiendo agregar una implementaci&#x00f3;n apropiada del
+            modelo de dominio m&#x00e1;s tarde.
+        </para>
+
+        <para>
+            Los modos de representaci&#x00f3;n de entidad pueden ser establecidos
+            por <literal>Session</literal>:
+        </para>
+
+        <programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+dynamicSession.save("Customer", david);
+...
+dynamicSession.flush();
+dynamicSession.close()
+...
+// Continue on pojoSession
+]]></programlisting>
+
+
+        <para>
+            Por favor, ten en cuenta que la llamada a <literal>getSession()</literal>
+            usando un <literal>EntityMode</literal> est&#x00e1; en la API de
+            <literal>Session</literal>, no en la de <literal>SessionFactory</literal>.
+            De esta forma, la nueva <literal>Session</literal> comparte la conexi&#x00f3;n
+            JDBC, transacci&#x00f3;n y otra informaci&#x00f3;n de contexto. Esto significa
+            que no tienes que llamar a <literal>flush()</literal> ni a <literal>close()</literal>
+            en la <literal>Session</literal> secundaria, y tembi&#x00e9;n dejar el manejo
+            de la transacci&#x00f3;n y de la conexi&#x00f3;n a la unidad de trabajo primaria.
+        </para>
+
+        <para>
+            Puede encontrarse m&#x00e1;s informaci&#x00f3;n sobre las capacidades de
+            representaci&#x00f3;n XML en <xref linkend="xml"/>.
+        </para>
+
+    </sect1>
+
+    <para>
+        PORHACER: Documentar el framework de extensiones del usuario en los paquetes
+        de propiedad y proxies.
+    </para>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/query_criteria.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/query_criteria.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/query_criteria.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,431 @@
+<chapter id="querycriteria">
+    <title>Consultas por Criterios</title>
+
+    <para>
+        Acompa&#x00f1;a a Hibernate una API de consultas por criterios intuitiva y extensible.
+    </para>
+    
+    <sect1 id="querycriteria-creating">
+        <title>Creando una instancia de <literal>Criteria</literal></title>
+
+        <para>
+            La interface <literal>org.hibernate.Criteria</literal> representa una consulta contra
+            una clase persistente en particular. La <literal>Session</literal> es una f&#x00e1;brica de instancias
+            de <literal>Criteria</literal>.
+        </para>
+
+        <programlisting><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
+crit.setMaxResults(50);
+List cats = crit.list();]]></programlisting>
+
+    </sect1>
+     
+    <sect1 id="querycriteria-narrowing">
+        <title>Estrechando el conjunto resultado</title>
+
+        <para>
+            Un criterio individual de consulta es una instancia de la interface
+            <literal>org.hibernate.criterion.Criterion</literal>. La clase
+            <literal>org.hibernate.criterion.Restrictions</literal> define m&#x00e9;todos de f&#x00e1;brica para obtener ciertos tipos
+            prefabricados de <literal>Criterion</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .add( Restrictions.between("weight", minWeight, maxWeight) )
+    .list();]]></programlisting>
+    
+        <para>
+            Las restricciones pueden ser agrupadas l&#x00f3;gicamente.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .add( Restrictions.or(
+        Restrictions.eq( "age", new Integer(0) ),
+        Restrictions.isNull("age")
+    ) )
+    .list();]]></programlisting>
+    
+       <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
+    .add( Restrictions.disjunction()
+        .add( Restrictions.isNull("age") )
+        .add( Restrictions.eq("age", new Integer(0) ) )
+        .add( Restrictions.eq("age", new Integer(1) ) )
+        .add( Restrictions.eq("age", new Integer(2) ) )
+    ) )
+    .list();]]></programlisting>
+    
+        <para>
+            Hay un gran rango de tipos de criterio prefabricados (subclases de <literal>Restrictions</literal>),
+            pero uno que es especialmente útil te deja especificar SQL directamente.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.sql("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
+    .list();]]></programlisting>
+    
+        <para>
+            El sitio <literal>{alias}</literal> ser&#x00e1; remplazado por el alias de fila de la entidad consultada.
+        </para>
+        
+        <para>
+            Un enfoque alternativo para obtener un criterio es tomarlo de una instancia de
+            <literal>Property</literal>. Puedes crear una <literal>Property</literal> llamando a 
+            <literal>Property.forName()</literal>.
+        </para>
+    
+        <programlisting><![CDATA[
+Property age = Property.forName("age");
+List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.disjunction()
+        .add( age.isNull() )
+        .add( age.eq( new Integer(0) ) )
+        .add( age.eq( new Integer(1) ) )
+        .add( age.eq( new Integer(2) ) )
+    ) )
+    .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
+    .list();]]></programlisting>
+    
+   </sect1>
+     
+    <sect1 id="querycriteria-ordering">
+        <title>Ordenando los resultados</title>
+
+        <para>
+            Puedes ordenar los resultados usando <literal>org.hibernate.criterion.Order</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "F%")
+    .addOrder( Order.asc("name") )
+    .addOrder( Order.desc("age") )
+    .setMaxResults(50)
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Property.forName("name").like("F%") )
+    .addOrder( Property.forName("name").asc() )
+    .addOrder( Property.forName("age").desc() )
+    .setMaxResults(50)
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-associations">
+        <title>Asociaciones</title>
+
+        <para>
+            Puedes especificar f&#x00e1;cilmente restricciones sobre las entidades relacionadas al navegar asociaciones
+            usando <literal>createCriteria()</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "F%")
+    .createCriteria("kittens")
+        .add( Restrictions.like("name", "F%")
+    .list();]]></programlisting>
+
+        <para>
+            nota que el segundo <literal>createCriteria()</literal> devuelve una nueva instancia de
+            <literal>Criteria</literal>, que hace referencia a los elementos de la colecci&#x00f3;n
+            <literal>kittens</literal>.
+        </para>
+
+        <para>
+            La siguiente forma alternativa es útil en ciertas circunstancias.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .createAlias("kittens", "kt")
+    .createAlias("mate", "mt")
+    .add( Restrictions.eqProperty("kt.name", "mt.name") )
+    .list();]]></programlisting>
+
+        <para>
+            (<literal>createAlias()</literal> no crea una nueva instancia de
+            <literal>Criteria</literal>.)
+        </para>
+
+        <para>
+            &#x00a1;Observa que las colecciones de gatitos tenidas por las instancias de <literal>Cat</literal> devueltas
+            por las dos consultas previas <emphasis>no</emphasis> est&#x00e1;n prefiltradas por los criterios! Si deseas
+            recuperar s&#x00f3;lo los gatitos que emparejen los criterios, debes usar <literal>returnMaps()</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .createCriteria("kittens", "kt")
+        .add( Restrictions.eq("name", "F%") )
+    .returnMaps()
+    .list();
+Iterator iter = cats.iterator();
+while ( iter.hasNext() ) {
+    Map map = (Map) iter.next();
+    Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
+    Cat kitten = (Cat) map.get("kt");
+}]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="querycriteria-dynamicfetching" revision="1">
+        <title>Recuperaci&#x00f3;n din&#x00e1;mica de asociaciones</title>
+
+        <para>
+            Puedes especificar la sem&#x00e1;ntica de recuperaci&#x00f3;n de asociaciones en tiempo de ejecuci&#x00f3;n usando
+            <literal>setFetchMode()</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .setFetchMode("mate", FetchMode.EAGER)
+    .setFetchMode("kittens", FetchMode.EAGER)
+    .list();]]></programlisting>
+    
+        <para>
+            Esta consulta recuperar&#x00e1; tanto <literal>mate</literal> como <literal>kittens</literal> por
+            uni&#x00f3;n exterior (outer join). Ver <xref linkend="performance-fetching"/> para m&#x00e1;s informaci&#x00f3;n.
+        </para>
+    
+    </sect1>
+     
+    <sect1 id="querycriteria-examples">
+        <title>Consultas por ejemplos</title>
+
+        <para>
+            La clase <literal>org.hibernate.criterion.Example</literal> te permite construir un criterio de consulta
+            a partir de una instancia dada.
+        </para>
+
+        <programlisting><![CDATA[Cat cat = new Cat();
+cat.setSex('F');
+cat.setColor(Color.BLACK);
+List results = session.createCriteria(Cat.class)
+    .add( Example.create(cat) )
+    .list();]]></programlisting>
+    
+        <para>
+           Las propiedades de versi&#x00f3;n, los identificadores y las asociaciones son ignorados. Por defecto,
+           las propiedades valuadas a nulo son exclu&#x00ed;das.
+        </para>
+
+        <para>
+           Puedes ajustar c&#x00f3;mo se aplica el <literal>Example</literal>.
+        </para>
+
+        <programlisting><![CDATA[Example example = Example.create(cat)
+    .excludeZeroes()           //exclude zero valued properties
+    .excludeProperty("color")  //exclude the property named "color"
+    .ignoreCase()              //perform case insensitive string comparisons
+    .enableLike();             //use like for string comparisons
+List results = session.createCriteria(Cat.class)
+    .add(example)
+    .list();]]></programlisting>
+    
+        <para>
+            Puedes incluso usar ejemplos para colocar criterios sobre objetos asociados.
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .add( Example.create(cat) )
+    .createCriteria("mate")
+        .add( Example.create( cat.getMate() ) )
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-projection">
+        <title>Proyecciones, agregaci&#x00f3;n y agrupamiento</title>
+        <para>
+            La clase <literal>org.hibernate.criterion.Projections</literal> es una f&#x00e1;brica de instancias de
+            <literal>Projection</literal>. Aplicamos una proyecci&#x00f3;n a una consulta llamando a
+            <literal>setProjection()</literal>.
+        </para>
+        
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.rowCount() )
+    .add( Restrictions.eq("color", Color.BLACK) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount() )
+        .add( Projections.avg("weight") )
+        .add( Projections.max("weight") )
+        .add( Projections.groupProperty("color") )
+    )
+    .list();]]></programlisting>
+    
+        <para>
+            No es necesario ningún "group by" expl&#x00ed;cito en una consulta por criterios.
+            Ciertos tipos de proyecciones son definidos para ser <emphasis>proyecciones agrupadas</emphasis>,
+            que adem&#x00e1;s aparecen en la cl&#x00e1;usula SQL <literal>group by</literal>.
+        </para>
+    
+        <para>
+            Puede opcionalmente asignarse un alias a una proyecci&#x00f3;n, de modo que el valor proyectado pueda
+            ser referido en restricciones u ordenamientos. Aqu&#x00ed; hay dos formas diferentes de hacer esto:
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
+    .addOrder( Order.asc("colr") )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.groupProperty("color").as("colr") )
+    .addOrder( Order.asc("colr") )
+    .list();]]></programlisting>
+    
+        <para>
+            Los m&#x00e9;todos <literal>alias()</literal> y <literal>as()</literal> simplemente envuelven una instancia
+            de proyecci&#x00f3;n en otra instancia de <literal>Projection</literal> con alias. Como un atajo, puedes asignar
+            un alias cuando agregas la proyecci&#x00f3;n a una lista de proyecciones:
+        </para>
+
+       <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount(), "catCountByColor" )
+        .add( Projections.avg("weight"), "avgWeight" )
+        .add( Projections.max("weight"), "maxWeight" )
+        .add( Projections.groupProperty("color"), "color" )
+    )
+    .addOrder( Order.desc("catCountByColor") )
+    .addOrder( Order.desc("avgWeight") )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Domestic.class, "cat")
+    .createAlias("kittens", "kit")
+    .setProjection( Projections.projectionList()
+        .add( Projections.property("cat.name"), "catName" )
+        .add( Projections.property("kit.name"), "kitName" )
+    )
+    .addOrder( Order.asc("catName") )
+    .addOrder( Order.asc("kitName") )
+    .list();]]></programlisting>
+    
+        <para>
+            Puedes tambi&#x00e9;n usar <literal>Property.forName()</literal> para expresar proyecciones:
+        </para>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Property.forName("name") )
+    .add( Property.forName("color").eq(Color.BLACK) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount().as("catCountByColor") )
+        .add( Property.forName("weight").avg().as("avgWeight") )
+        .add( Property.forName("weight").max().as("maxWeight") )
+        .add( Property.forName("color").group().as("color" )
+    )
+    .addOrder( Order.desc("catCountByColor") )
+    .addOrder( Order.desc("avgWeight") )
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-detachedqueries">
+        <title>Consultas y subconsultas separadas</title>
+        <para>
+            La clase <literal>DetachedCriteria</literal> te deja crear una consulta fuera del &#x00e1;mbito de una sesi&#x00f3;n,
+            y entonces ejecutarla luego usando alguna <literal>Session</literal> arbitraria.
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
+    .add( Property.forName("sex").eq('F') );
+    
+Session session = ....;
+Transaction txn = session.beginTransaction();
+List results = query.getExecutableCriteria(session).setMaxResults(100).list();
+txn.commit();
+session.close();]]></programlisting>
+
+        <para>
+            Tambi&#x00e9;n una <literal>DetachedCriteria</literal> puede usarse para expresar una subconsulta.
+            Las instancias de Criterion implicando subconsultas pueden obtenerse v&#x00ed;a <literal>Subqueries</literal> o
+            <literal>Property</literal>.
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
+    .setProjection( Property.forName("weight").avg() );
+session.createCriteria(Cat.class)
+    .add( Property.forName("weight).gt(avgWeight) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
+    .setProjection( Property.forName("weight") );
+session.createCriteria(Cat.class)
+    .add( Subqueries.geAll("weight", weights) )
+    .list();]]></programlisting>
+    
+        <para>
+            Incluso son posibles las subconsultas correlacionadas:
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
+    .setProjection( Property.forName("weight").avg() )
+    .add( Property.forName("cat2.sex").eqProperty("cat.sex") );
+session.createCriteria(Cat.class, "cat")
+    .add( Property.forName("weight).gt(avgWeightForSex) )
+    .list();]]></programlisting>
+
+    </sect1>
+
+        <!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer allow returning arbitrary 
+                  user objects - similar to setResultClass in JDO2. General use of ResultTransformer 
+                  could also be explained. -->
+               
+    <sect1 id="query-criteria-naturalid">
+        <title>Consultas por identificador natural</title>
+        
+        <para>
+            Para la mayor&#x00ed;a de consultas, incluyendo las consultas por criterios, el cach&#x00e9; de consulta no es
+            muy eficiente, debido a que la invalidaci&#x00f3;n del cach&#x00e9; de consulta ocurre demasiado frecuentemente.
+            Sin embargo, hay un tipo especial de consulta donde podemos optimizar el algoritmo de invalidaci&#x00f3;n
+            de cach&#x00e9;: búsquedas por una clave natural constante. En algunas aplicaciones, este tipo de consulta,
+            ocurre frecuentemente. La API de criterios brinda especial provisi&#x00f3;n para este caso de uso.
+        </para>
+        
+        <para>
+            Primero, debes mapear la clave natural de tu entidad usando
+            <literal>&lt;natural-id&gt;</literal>, y habilitar el uso del cach&#x00e9; de segundo nivel.
+        </para>
+
+        <programlisting><![CDATA[<class name="User">
+    <cache usage="read-write"/>
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <natural-id>
+        <property name="name"/>
+        <property name="org"/>
+    </natural-id>
+    <property name="password"/>
+</class>]]></programlisting>
+    
+        <para>
+            Nota que esta funcionalidad no est&#x00e1; pensada para uso con entidades con claves naturales
+            <emphasis>mutable</emphasis>.
+        </para>
+        
+        <para>
+            Seguido, habilita el cach&#x00e9; de consulta de Hibernate.
+        </para>
+        
+        <para>
+            Ahora, <literal>Restrictions.naturalId()</literal> nos permite hacer uso de el algoritmo de cach&#x00e9;
+            m&#x00e1;s eficiente.
+        </para>
+       
+        <programlisting><![CDATA[session.createCriteria(User.class)
+    .add( Restrictions.naturalId()
+        .set("name", "gavin")
+        .set("org", "hb") 
+    ).setCacheable(true)
+    .uniqueResult();]]></programlisting>
+            
+    </sect1>
+    
+</chapter>

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/query_hql.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/query_hql.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/query_hql.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1107 @@
+<chapter id="queryhql">
+    <title>HQL: El Lenguaje de Consulta de Hibernate</title>
+    
+    <para>
+        Hibernate est&#x00e1; equipado con un lenguaje de consulta extremadamente potente que
+        (intencionalmente en absoluto) se parece much&#x00ed;simo a SQL. Pero no te enga&#x00f1;es por la sintaxis;
+        HQL es completamente orientado a objetos, entendiendo nociones como herencia, polimorfismo
+        y asociaci&#x00f3;n.
+    </para>
+
+    <sect1 id="queryhql-casesensitivity">
+        <title>Sensibilidad a May&#x00fa;sculas</title>
+
+        <para>
+            Las consultas son insensibles a may&#x00fa;sculas, excepto para nombres de clases Java y propiedades. De modo que
+            <literal>SeLeCT</literal> es lo mismo que <literal>sELEct</literal> e igual a <literal>SELECT</literal>,
+            pero <literal>org.hibernate.eg.FOO</literal> no lo es a <literal>org.hibernate.eg.Foo</literal> y
+            <literal>foo.barSet</literal> no es igual a <literal>foo.BARSET</literal>.
+        </para>
+        
+        <para>
+            Este manual usa palabras clave HQL en min&#x00fa;sculas. Algunos usuarios encuentran las consultas con
+            palabras clave en may&#x00fa;sculas m&#x00e1;s le&#x00ed;bles, pero encontramos esta convenci&#x00f3;n fea cuando se encaja
+            en c&#x00f3;digo Java.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-from">
+        <title>La cl&#x00e1;usula from</title>
+
+        <para>
+            La consulta m&#x00e1;s simple posible de Hibernate es de la forma:
+        </para>
+        
+        <programlisting><![CDATA[from eg.Cat]]></programlisting>
+        
+        <para>
+            que simplemente devuelve todas las instancias de la clase <literal>eg.Cat</literal>.
+            Usualmente no necesitamos cualificar el nombre de la clase, ya que <literal>auto-import</literal>
+            est&#x00e1; por defecto. De modo que casi siempre escribimos solamente:
+        </para>
+        
+        <programlisting><![CDATA[from Cat]]></programlisting>
+        
+        <para>
+            La mayor&#x00ed;a del tiempo, necesitar&#x00e1;s asignar un <emphasis>alias</emphasis>, ya que querr&#x00e1;s referirte al
+            <literal>Cat</literal> en otras partes de la consulta.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+        <para>
+            Esta consulta asigna el alias <literal>cat</literal> a las instancias de <literal>Cat</literal>,
+            de modo que podr&#x00ed;amos usar ese alias luego en la consulta. La palabra clave <literal>as</literal>
+            es opcional; tambi&#x00e9;n podr&#x00ed;amos escribir:
+        </para>
+        
+        <programlisting><![CDATA[from Cat cat]]></programlisting>
+        
+        <para>
+            Pueden aparecer m&#x00fa;ltiples clases, resultando en un producto cartesiano o uni&#x00f3;n "cruzada" (cross join).
+        </para>
+        
+        <programlisting><![CDATA[from Formula, Parameter]]></programlisting>
+        <programlisting><![CDATA[from Formula as form, Parameter as param]]></programlisting>
+        
+        <para>
+            Se considera buena pr&#x00e1;ctica el nombrar los alias de consulta usando una inicial en min&#x00fa;sculas,
+            consistente con los est&#x00e1;ndares de nombrado de Java para variables locales
+            (por ejemplo, <literal>domesticCat</literal>).
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-joins" revision="1">
+        <title>Asociaciones y uniones (joins)</title>
+
+        <para>
+            Podemos tambi&#x00e9;n asignar aliases a entidades asociadas, e incluso a elementos de una colecci&#x00f3;n de valores,
+            usando una <literal>join</literal>.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    inner join cat.mate as mate
+    left outer join cat.kittens as kitten]]></programlisting>
+
+        <programlisting><![CDATA[from Cat as cat left join cat.mate.kittens as kittens]]></programlisting>
+
+        <programlisting><![CDATA[from Formula form full join form.parameter param]]></programlisting>
+
+        <para>
+            Los tipos de join soportados son prestados de ANSI SQL
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>inner join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>left outer join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>right outer join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>full join</literal> (no &#x00fa;til usualmente)
+                </para>
+            </listitem>
+        </itemizedlist>
+    
+        <para>
+            Las construcciones <literal>inner join</literal>, <literal>left outer join</literal> y
+            <literal>right outer join</literal> pueden ser abreviadas.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    join cat.mate as mate
+    left join cat.kittens as kitten]]></programlisting>
+    
+        <para>
+            Puedes proveer condiciones de uni&#x00f3;n extra usando la palabra clave <literal>with</literal> de HQL.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    left join cat.kittens as kitten 
+        with kitten.bodyWeight > 10.0]]></programlisting>
+
+        <para>
+            En adici&#x00f3;n, un "fetch" join permite a las asociaciones o colecciones de valores ser inicializadas
+            junto a sus objetos padres, usando una sola selecci&#x00f3;n. Esto es particularmente &#x00fa;til en el case de una
+            colecci&#x00f3;n. Efectivamente sobrescribe el outer join y las declaraciones perezosas (lazy) del fichero
+            de mapeo para asociaciones y colecciones. Ver <xref linkend="performance-fetching"/> para m&#x00e1;s
+            informaci&#x00f3;n.
+        </para>
+    
+        <programlisting><![CDATA[from Cat as cat 
+    inner join fetch cat.mate
+    left join fetch cat.kittens]]></programlisting>
+    
+        <para>
+            Usualmente a un fetch join no se necesita asign&#x00e1;rsele un alias, porque los objetos asociados no deben
+            ser usados en la cl&#x00e1;usula <literal>where</literal> (ni en cualquier otra cl&#x00e1;usula). Adem&#x00e1;s, los objetos
+            asociados no son devueltos directamente en los resultados de consulta. En cambio, pueden ser accedidos
+            v&#x00ed;a el objeto padre. La &#x00fa;nica raz&#x00f3;n por la que necesitar&#x00ed;amos un alias es estamos uniendo recursivamente
+            otra colecci&#x00f3;n:
+        </para>
+        
+        <programlisting><![CDATA[from Cat as cat 
+    inner join fetch cat.mate
+    left join fetch cat.kittens child
+    left join fetch child.kittens]]></programlisting>
+    
+        <para>
+            Nota que la construcci&#x00f3;n <literal>fetch</literal> no puede usarse en consultas llamadas usando
+            <literal>scroll()</literal> o <literal>iterate()</literal>. Ni debe usarse <literal>fetch</literal>
+            junto con <literal>setMaxResults()</literal> o <literal>setFirstResult()</literal>. Tampoco puede usarse
+            <literal>fetch</literal> junto a una condici&#x00f3;n <literal>with</literal> ad hoc. Es posible crear
+            un producto cartesiano trayendo por join m&#x00e1;s de una colecci&#x00f3;n en una colecci&#x00f3;n, as&#x00ed; que ten cuidado en
+            este caso. Traer por join m&#x00fa;ltiples roles de colecci&#x00f3;n tambi&#x00e9;n da a veces resultados inesperados para mapeos
+            de bag, as&#x00ed; que s&#x00e9; cuidadoso sobre c&#x00f3;mo formular tus consultas en este caso. Finalmente, nota que
+            <literal>full join fetch</literal> y <literal>right join fetch</literal> no son significativos.
+        </para>
+        
+        <para>
+            Si est&#x00e1;s usando recuperaci&#x00f3;n perezosa a nivel de propiedad (con instrumentaci&#x00f3;n de bytecode), es posible
+            forzar a Hibernate a traer las propiedades perezosas inmediatamente (en la primera consulta) usando
+            <literal>fetch all properties</literal>.
+        </para>
+        
+        <programlisting><![CDATA[from Document fetch all properties order by name]]></programlisting>
+        <programlisting><![CDATA[from Document doc fetch all properties where lower(doc.name) like '%cats%']]></programlisting>
+            
+    </sect1>
+
+    <sect1 id="queryhql-select">
+        <title>La cl&#x00e1;usula select</title>
+
+        <para>
+            La cl&#x00e1;usula <literal>select</literal> escoge qu&#x00e9; objetos y propiedades devolver in el conjunto resultado
+            de la consulta. Considera:
+        </para>
+
+        <programlisting><![CDATA[select mate 
+from Cat as cat 
+    inner join cat.mate as mate]]></programlisting>
+
+        <para>
+            La consulta seleccionar&#x00e1; <literal>mate</literal>s de otros <literal>Cat</literal>s.
+            Realmente, puedes expresar esta consulta en un forma m&#x00e1;s compacta como:
+        </para>
+
+        <programlisting><![CDATA[select cat.mate from Cat cat]]></programlisting>
+
+        <para>
+            Las consultas pueden devolver propiedades de cualquier tipo de valor incluyendo propiedades de
+            tipo componente:
+        </para>
+
+        <programlisting><![CDATA[select cat.name from DomesticCat cat
+where cat.name like 'fri%']]></programlisting>
+
+        <programlisting><![CDATA[select cust.name.firstName from Customer as cust]]></programlisting>
+
+        <para>
+            Las consultas pueden devolver m&#x00fa;ltiples objetos y/o propiedades como un array de tipo
+            <literal>Object[]</literal>,
+        </para>
+
+        <programlisting><![CDATA[select mother, offspr, mate.name 
+from DomesticCat as mother
+    inner join mother.mate as mate
+    left outer join mother.kittens as offspr]]></programlisting>
+    
+        <para>
+            o como una <literal>List</literal>,
+        </para>
+        
+        <programlisting><![CDATA[select new list(mother, offspr, mate.name)
+from DomesticCat as mother
+    inner join mother.mate as mate
+    left outer join mother.kittens as offspr]]></programlisting>
+    
+        <para>
+            o como un objeto real Java de tipo seguro,
+        </para>
+        
+        <programlisting><![CDATA[select new Family(mother, mate, offspr)
+from DomesticCat as mother
+    join mother.mate as mate
+    left join mother.kittens as offspr]]></programlisting>
+        
+        <para>
+            asumiendo que la clase <literal>Family</literal> tiene un constructor apropiado.
+        </para>
+        
+        <para>
+            Puedes asignar aliases para seleccionar expresiones usando <literal>as</literal>:
+        </para>
+
+        <programlisting><![CDATA[select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
+from Cat cat]]></programlisting>
+
+        <para>
+            Esto es lo m&#x00e1;s &#x00fa;til cuando se usa junto con <literal>select new map</literal>:
+        </para>
+            
+        <programlisting><![CDATA[select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
+from Cat cat]]></programlisting>
+
+        <para>
+            Esta consulta devuelve un <literal>Map</literal> de aliases a valores seleccionados.
+        </para>
+         
+    </sect1>
+
+    <sect1 id="queryhql-aggregation">
+        <title>Funciones de agregaci&#x00f3;n</title>
+
+        <para>
+            Las consultas HQL pueden incluso devolver resultados de funciones de agregaci&#x00f3;n sobre propiedades:
+        </para>
+
+        <programlisting><![CDATA[select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
+from Cat cat]]></programlisting>
+
+<!-- NO LONGER SUPPORTED
+        <para>
+            Collections may also appear inside aggregate functions in the <literal>select</literal> 
+            clause.
+        </para>
+
+        <programlisting><![CDATA[select cat, count( elements(cat.kittens) ) 
+from Cat cat group by cat]]></programlisting>
+-->
+
+        <para>
+            Las funciones de agregaci&#x00f3;n soportadas son
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>avg(...), sum(...), min(...), max(...)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>count(*)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>count(...), count(distinct ...), count(all...)</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+    
+        <para>
+            Puedes usar operadores aritm&#x00e9;ticos, concatenaci&#x00f3;n, y funciones SQL reconocidas en la cl&#x00e1;usula select:
+        </para>
+        
+        <programlisting><![CDATA[select cat.weight + sum(kitten.weight) 
+from Cat cat 
+    join cat.kittens kitten
+group by cat.id, cat.weight]]></programlisting>
+    
+        <programlisting><![CDATA[select firstName||' '||initial||' '||upper(lastName) from Person]]></programlisting>
+    
+        <para>
+            Las palabras clave <literal>distinct</literal> y <literal>all</literal> pueden ser usadas y tienen las misma
+            sem&#x00e1;ntica que en SQL.
+        </para>
+
+        <programlisting><![CDATA[select distinct cat.name from Cat cat
+
+select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="queryhql-polymorphism">
+        <title>Consultas polim&#x00f3;rficas</title>
+
+        <para>
+            Una consulta como:
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+        <para>
+            devuelve instancias no s&#x00f3;lo de <literal>Cat</literal>, sino tambi&#x00e9;n de subclases como
+            <literal>DomesticCat</literal>. Las consultas de Hibernate pueden mencionar <emphasis>cualquier</emphasis>
+            clase o interface Java en la cl&#x00e1;usula <literal>from</literal>. La consulta devolver&#x00e1; instancias de todas
+            las clases persistentes que extiendan esa clase o implementen la interface. La siguiente consulta devolver&#x00ed;a
+            todos los objetos persistentes.
+        </para>
+        
+        <programlisting><![CDATA[from java.lang.Object o]]></programlisting>
+        
+        <para>
+            La interface <literal>Named</literal> podr&#x00ed;a ser implementada por varias clases persistentes:
+        </para>
+        
+        <programlisting><![CDATA[from Named n, Named m where n.name = m.name]]></programlisting>
+        
+        <para>
+            Nota que estas dos &#x00fa;ltimas consultas requerir&#x00e1;n m&#x00e1;s de un <literal>SELECT</literal> SQL. Esto significa
+            que la cl&#x00e1;usula <literal>order by</literal> no ordenar&#x00e1; correctamente todo el conjunto resultado.
+            (Significa adem&#x00e1;s que no puedes llamar estas consulta usando <literal>Query.scroll()</literal>.)
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-where">
+        <title>La cl&#x00e1;usula where</title>
+
+        <para>
+            La cl&#x00e1;usula where te permite estrechar la lista de instancias devueltas. Si no existe ning&#x00fa;n alias.
+            puedes referirte a las propiedades por nombre:
+        </para>
+
+        <programlisting><![CDATA[from Cat where name='Fritz']]></programlisting>
+        
+        <para>
+                Si existe un alias, usan un nombre cualificado de propiedad:
+        </para>
+        
+        <programlisting><![CDATA[from Cat as cat where cat.name='Fritz']]></programlisting>
+
+        <para>
+            devuelve las instancias de <literal>Cat</literal> llamadas 'Fritz'.
+        </para>
+
+        <programlisting><![CDATA[select foo 
+from Foo foo, Bar bar
+where foo.startDate = bar.date]]></programlisting>
+
+        <para>
+            devolver&#x00e1; todas las instancias de <literal>Foo</literal> para las cuales exista una instancia
+            de <literal>bar</literal> con una propiedad <literal>date</literal> igual a la propiedad
+            <literal>startDate</literal> del <literal>Foo</literal>. Las expresiones de ruta compuestas hacen
+            la cl&#x00e1;usula <literal>where</literal> extremadamente potente. Considera:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.mate.name is not null]]></programlisting>
+
+        <para>
+            Esta consulta se traduce en una consulta SQL con una uni&#x00f3;n de tabla (interna). Si fueses a escribir algo como
+        </para>
+
+        <programlisting><![CDATA[from Foo foo  
+where foo.bar.baz.customer.address.city is not null]]></programlisting>
+
+        <para>
+            terminar&#x00ed;as con una consulta que requerir&#x00ed;a cuatro uniones de tablas en SQL.
+        </para>
+
+        <para>
+            El operador <literal>=</literal> puede ser usado para comparar no s&#x00f3;lo propiedades, sino tambi&#x00e9;n instancias:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat, Cat rival where cat.mate = rival.mate]]></programlisting>
+
+        <programlisting><![CDATA[select cat, mate 
+from Cat cat, Cat mate
+where cat.mate = mate]]></programlisting>
+
+        <para>
+            La propiedad especial (en min&#x00fa;sculas) <literal>id</literal> puede ser usada para referenciar el identificador
+            &#x00fa;nico de un objeto. (Tambi&#x00e9;n puedes usar su nombre de propiedad.)
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.id = 123
+
+from Cat as cat where cat.mate.id = 69]]></programlisting>
+
+        <para>
+            La segunda consulta es eficiente. &#x00a1;No se requiere ninguna uni&#x00f3;n de tablas!
+        </para>
+
+        <para>
+            Tambi&#x00e9;n pueden ser usadas las propiedades de identificadores compuestos. Sup&#x00f3;n que <literal>Person</literal> 
+            tiene un identificador compuesto consistente en <literal>country</literal> y <literal>medicareNumber</literal>.
+        </para>
+
+        <programlisting><![CDATA[from bank.Person person
+where person.id.country = 'AU' 
+    and person.id.medicareNumber = 123456]]></programlisting>
+
+        <programlisting><![CDATA[from bank.Account account
+where account.owner.id.country = 'AU' 
+    and account.owner.id.medicareNumber = 123456]]></programlisting>
+
+        <para>
+            Una vez m&#x00e1;s, la segunda consulta no requiere ninguna uni&#x00f3;n de tablas.
+        </para>
+            
+        <para>
+            Asimismo, la propiedad especial <literal>class</literal> acccede al valor discriminador de una instancia en
+            el caso de persistencia polim&#x00f3;rfica. Un nombre de clase Java embebido en la cl&#x00e1;usula where ser&#x00e1;
+            traducido a su valor discriminador.
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
+        
+        <para>
+            Puedes tambi&#x00e9;n especificar propiedades de componentes o tipos compuestos de usuario (y de componentes
+            de componentes, etc). Nunca intentes usar una expresi&#x00f3;n de ruta que termine en una propiedad de tipo
+            componente (al contrario de una propiedad de un componente). Por ejemplo, si <literal>store.owner</literal>
+            es una entidad con un componente <literal>address</literal>
+        </para>
+
+        <programlisting><![CDATA[store.owner.address.city    // okay
+store.owner.address         // error!]]></programlisting>
+
+        <para>
+            Un tipo "any" tiene las propiedades especiales <literal>id</literal> y <literal>class</literal>,
+            permit&#x00e9;ndonos expresar un join en la siguiente forma (donde <literal>AuditLog.item</literal> es una
+            propiedad mapeada con <literal>&lt;any&gt;</literal>).
+        </para>
+       
+        <programlisting><![CDATA[from AuditLog log, Payment payment 
+where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting>
+    
+        <para>
+            Nota que <literal>log.item.class</literal> y <literal>payment.class</literal> har&#x00ed;an referencia a
+            los valores de columnas de base de datos completamente diferentes en la consulta anterior.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-expressions">
+        <title>Expresiones</title>
+
+        <para>
+            Las expresiones permitidas en la cl&#x00e1;usula <literal>where</literal> incluyen la mayor&#x00ed;a del tipo de cosas
+            que podr&#x00ed;as escribir en SQL:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    operadores matem&#x00e1;ticos <literal>+, -, *, /</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    operadores de comparaci&#x00f3;n binarios <literal>=, &gt;=, &lt;=, &lt;&gt;, !=, like</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    operadores l&#x00f3;gicos <literal>and, or, not</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Par&#x00e9;ntesis <literal>( )</literal>, indicando agrupaci&#x00f3;n
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>in</literal>,
+                    <literal>not in</literal>,
+                    <literal>between</literal>,
+                    <literal>is null</literal>,
+                    <literal>is not null</literal>,
+                    <literal>is empty</literal>,
+                    <literal>is not empty</literal>,
+                    <literal>member of</literal> y
+                    <literal>not member of</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Caso "simple", <literal>case ... when ... then ... else ... end</literal>,
+                    y caso "buscado", <literal>case when ... then ... else ... end</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    concatenaci&#x00f3;n de cadenas <literal>...||...</literal> o <literal>concat(...,...)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>current_date()</literal>, <literal>current_time()</literal>,
+                    <literal>current_timestamp()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+					<literal>second(...)</literal>, <literal>minute(...)</literal>, 
+					<literal>hour(...)</literal>, <literal>day(...)</literal>, 
+					<literal>month(...)</literal>, <literal>year(...)</literal>,
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Cualquier funci&#x00f3;n u operador definido por EJB-QL 3.0: <literal>substring(), trim(),
+                    lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>coalesce()</literal> y <literal>nullif()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>str()</literal> para convertir valores num&#x00e9;ricos o temporales a una cadena legible.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>cast(... as ...)</literal>, donde el segundo argumento es el nombre de un tipo Hibernate
+                    , y <literal>extract(... from ...)</literal> si <literal>cast()</literal> y
+                    <literal>extract()</literal> fuesen soportados por la base de datos subyacente.
+                </para>
+            </listitem>
+
+
+            <listitem>
+                <para>
+                    la funci&#x00f3;n <literal>index()</literal> de HQL, que se aplica a alias de una colecci&#x00f3;n
+                    indexada unida.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    funciones de HQL que tomen expresiones de ruta valuadas en colecciones: <literal>size(), 
+                    minelement(), maxelement(), minindex(), maxindex()</literal>, junto a las funciones especiales
+                    <literal>elements()</literal> and <literal>indices</literal> que pueden ser cuantificadas usando
+                    <literal>some, all, exists, any, in</literal>.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    Cualquier funci&#x00f3;n escalar SQL soportada por la base de datos como <literal>sign()</literal>, 
+                    <literal>trunc()</literal>, <literal>rtrim()</literal>, <literal>sin()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    par&#x00e1;metros posicionales JDBC <literal>?</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    par&#x00e1;metros con nombre <literal>:name</literal>, <literal>:start_date</literal>, <literal>:x1</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    literales SQL <literal>'foo'</literal>, <literal>69</literal>, <literal>6.66E+2</literal>,
+                    <literal>'1970-01-01 10:00:01.0'</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    constantes Java <literal>public static final</literal> <literal>eg.Color.TABBY</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>in</literal> y <literal>between</literal> pueden usarse como sigue:
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name between 'A' and 'B']]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+        <para>
+            y pueden escribirse las formas negadas
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name not between 'A' and 'B']]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+        <para>
+            Asimismo, <literal>is null</literal> y <literal>is not null</literal> pueden ser usadas para comprobar
+            valores nulos.
+        </para>
+
+        <para>
+            Los booleanos pueden ser f&#x00e1;cilmente usados en expresiones declarando substituciones de consulta HQL
+            en la configuraci&#x00f3;n de Hibernate:
+        </para>
+
+        <programlisting><![CDATA[<property name="hibernate.query.substitutions">true 1, false 0</property>]]></programlisting>
+
+        <para>
+            Esto remplazar&#x00e1; las palabras clave <literal>true</literal> y <literal>false</literal> con los literales
+            <literal>1</literal> y <literal>0</literal> en el SQL traducido de este HQL:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.alive = true]]></programlisting>
+
+        <para>
+            Puedes comprobar el tama&#x00f1;o de una colecci&#x00f3;n con la propiedad especial <literal>size</literal>, o la funci&#x00f3;n
+            especial <literal>size()</literal>.
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.kittens.size > 0]]></programlisting>
+
+        <programlisting><![CDATA[from Cat cat where size(cat.kittens) > 0]]></programlisting>
+
+        <para>
+            Para colecciones indexadas, puedes referirte a los &#x00ed;ndices m&#x00e1;ximo y m&#x00ed;nimo usando las funciones
+            <literal>minindex</literal> y <literal>maxindex</literal>. Similarmente, puedes referirte a los elementos
+            m&#x00e1;ximo y m&#x00ed;nimo de una colecci&#x00f3;n de tipo b&#x00e1;sico usando las funciones
+            <literal>minelement</literal> y <literal>maxelement</literal>.
+        </para>
+        
+        <programlisting><![CDATA[from Calendar cal where maxelement(cal.holidays) > current_date]]></programlisting>
+        
+        <programlisting><![CDATA[from Order order where maxindex(order.items) > 100]]></programlisting>
+
+        <programlisting><![CDATA[from Order order where minelement(order.items) > 10000]]></programlisting>
+        
+        <para>
+            Las funciones SQL <literal>any, some, all, exists, in</literal> est&#x00e1;n soportadas cuando se les pasa
+            el conjunto de elementos o &#x00ed;ndices de una colecci&#x00f3;n (funciones <literal>elements</literal> y
+            <literal>indices</literal>) o el resultado de una subconsulta (ver debajo).
+        </para>
+
+        <programlisting><![CDATA[select mother from Cat as mother, Cat as kit
+where kit in elements(foo.kittens)]]></programlisting>
+
+        <programlisting><![CDATA[select p from NameList list, Person p
+where p.name = some elements(list.names)]]></programlisting>
+
+        <programlisting><![CDATA[from Cat cat where exists elements(cat.kittens)]]></programlisting>
+
+        <programlisting><![CDATA[from Player p where 3 > all elements(p.scores)]]></programlisting>
+
+        <programlisting><![CDATA[from Show show where 'fizard' in indices(show.acts)]]></programlisting>
+
+        <para>
+            Nota que estas construcciones - <literal>size</literal>, <literal>elements</literal>,
+            <literal>indices</literal>, <literal>minindex</literal>, <literal>maxindex</literal>,
+            <literal>minelement</literal>, <literal>maxelement</literal> - pueden ser usadas solamente
+            en la cl&#x00e1;usula where en Hibernate3.
+        </para>
+        
+        <para>
+            Los elementos de colecciones indexadas (arrays, listas, mapas) pueden ser referidos por &#x00ed;ndice
+            (en una cl&#x00e1;usula where solamente):
+        </para>
+        
+        <programlisting><![CDATA[from Order order where order.items[0].id = 1234]]></programlisting>
+
+        <programlisting><![CDATA[select person from Person person, Calendar calendar
+where calendar.holidays['national day'] = person.birthDay
+    and person.nationality.calendar = calendar]]></programlisting>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11]]></programlisting>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ maxindex(order.items) ] = item and order.id = 11]]></programlisting>
+
+        <para>
+            La expresi&#x00f3;n dentro de <literal>[]</literal> puede incluso ser una expresi&#x00f3;n aritm&#x00e9;tica.
+        </para>
+        
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ size(order.items) - 1 ] = item]]></programlisting>
+        
+        <para>
+            HQL provee adem&#x00e1;s el funci&#x00f3;n prefabricada <literal>index()</literal>, para elementos de una
+            asociaci&#x00f3;n uno-a-muchos o colecci&#x00f3;n de valores.
+        </para>
+
+        <programlisting><![CDATA[select item, index(item) from Order order 
+    join order.items item
+where index(item) < 5]]></programlisting>
+
+        <para>
+            Pueden usarse las funciones SQL escalares soportadas por la base de datos subyacente
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like 'FRI%']]></programlisting>
+
+        <para>
+            Si a&#x00fa;n no est&#x00e1;s convencido de todo esto, piensa cu&#x00e1;nto m&#x00e1;s largo y menos le&#x00ed;ble ser&#x00ed;a la siguiente
+            consulta en SQL:
+        </para>
+
+        <programlisting><![CDATA[select cust
+from Product prod,
+    Store store
+    inner join store.customers cust
+where prod.name = 'widget'
+    and store.location.name in ( 'Melbourne', 'Sydney' )
+    and prod = all elements(cust.currentOrder.lineItems)]]></programlisting>
+
+        <para>
+            <emphasis>Ayuda:</emphasis> algo como
+        </para>
+
+        <programlisting><![CDATA[SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
+FROM customers cust,
+    stores store,
+    locations loc,
+    store_customers sc,
+    product prod
+WHERE prod.name = 'widget'
+    AND store.loc_id = loc.id
+    AND loc.name IN ( 'Melbourne', 'Sydney' )
+    AND sc.store_id = store.id
+    AND sc.cust_id = cust.id
+    AND prod.id = ALL(
+        SELECT item.prod_id
+        FROM line_items item, orders o
+        WHERE item.order_id = o.id
+            AND cust.current_order = o.id
+    )]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-ordering">
+        <title>La cl&#x00e1;usula order by</title>
+
+        <para>
+            La lista devuelta por una consulta puede ser ordenada por cualquier propiedad de una clase devuelta
+            o componentes:
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat
+order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
+
+        <para>
+            Los <literal>asc</literal> o <literal>desc</literal> opcionales indican ordenamiento ascendente o
+            descendente respectivamente.
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-grouping">
+        <title>La cl&#x00e1;usula group by</title>
+
+        <para>
+            Una consulta que devuelve valores agregados puede ser agrupada por cualquier propiedad de una clase
+            devuelta o componentes:
+        </para>
+
+        <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat) 
+from Cat cat
+group by cat.color]]></programlisting>
+
+        <programlisting><![CDATA[select foo.id, avg(name), max(name) 
+from Foo foo join foo.names name
+group by foo.id]]></programlisting>
+
+        <para>
+            Se permite tambi&#x00e9;n una cl&#x00e1;usula <literal>having</literal>.
+        </para>
+
+        <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat) 
+from Cat cat
+group by cat.color 
+having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
+
+        <para>
+            Las funciones y funciones de agregaci&#x00f3;n SQL est&#x00e1;n permitidas en las cl&#x00e1;usulas
+            <literal>having</literal> y <literal>order by</literal>, si est&#x00e1;n soportadas por la base de datos
+            subyacente (por ejemplo, no en MySQL).
+        </para>
+
+        <programlisting><![CDATA[select cat
+from Cat cat
+    join cat.kittens kitten
+group by cat
+having avg(kitten.weight) > 100
+order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
+
+        <para>
+            Nota que ni la cl&#x00e1;usula <literal>group by</literal> ni la cl&#x00e1;usula <literal>order by</literal> pueden
+            contener expresiones aritm&#x00e9;ticas.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="queryhql-subqueries">
+        <title>Subconsultas</title>
+        
+        <para>
+            Para bases de datos que soportan subconsultas, Hibernate soporta subconsultas dentro de consultas. Una
+            subconsulta debe ser encerrada entre par&#x00e9;ntesis (frecuentemente por una llamada a una funci&#x00f3;n de agregaci&#x00f3;n
+            SQL). Incluso se permiten subconsultas correlacionadas (subconsultas que hacen referencia a un alias en la
+            consulta exterior).
+        </para>
+
+        <programlisting><![CDATA[from Cat as fatcat 
+where fatcat.weight > ( 
+    select avg(cat.weight) from DomesticCat cat 
+)]]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat as cat 
+where cat.name = some ( 
+    select name.nickName from Name as name 
+)]]></programlisting>
+    
+        <programlisting><![CDATA[from Cat as cat 
+where not exists ( 
+    from Cat as mate where mate.mate = cat 
+)]]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat as cat 
+where cat.name not in ( 
+    select name.nickName from Name as name 
+)]]></programlisting>
+
+        <para>
+            Para las subconsultas con m&#x00e1;s de una expresi&#x00f3;n en la lista de selecci&#x00f3;n, puedes usar un constructor
+            de tuplas:
+        </para>
+        
+        <programlisting><![CDATA[from Cat as cat 
+where not ( cat.name, cat.color ) in ( 
+    select cat.name, cat.color from DomesticCat cat 
+)]]></programlisting>
+
+        <para>
+            Nota que en algunas bases de datos (pero no en Oracle o HSQL), puedes usar constructores de tuplar en
+            otros contextos, por ejemplo al consultar componentes o tipos de usuario compuestos:
+        </para>
+
+        <programlisting><![CDATA[from Person where name = ('Gavin', 'A', 'King')]]></programlisting>
+        
+        <para>
+            Que es equivalente a la m&#x00e1;s verborr&#x00e1;gica:
+        </para>
+        
+        <programlisting><![CDATA[from Person where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')]]></programlisting>
+
+        <para>
+            Existen dos buenas razones por las cuales podr&#x00ed;as no querer hacer este tipo de cosa: primero, no es
+            completamente portable entre plataformas de base de datos; segundo, la consulta ahora es dependiente
+            del orden de propiedades en el documento de mapeo.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-examples">
+        <title>Ejemplos de HQL</title>
+        
+        <para>
+            Las consultas de Hibernate pueden ser abolutamente potentes y complejas, De hecho, el poder del lenguaje
+            de consulta es uno de los puntos principales de venta de Hibernate. He aqu&#x00ed; algunos consultas de ejemplo
+            muy similares a consultas que he usado en un proyecto reciente. &#x00a1;Nota que la mayor&#x00ed;a de las consultas
+            que escribir&#x00e1;s som mucho m&#x00e1;s simples que estas!
+        </para>
+        
+        <para>
+            La siguiente consulta devuelve el order id, n&#x00fa;mero de items y valor total de la orden para todas
+            las ordenes inpagas de un cliente en particular y valor total m&#x00ed;nimo dados, ordenando los resultados
+            por valor total. Al determinar los precios, usa el cat&#x00e1;logo actual. La consulta SQL resultante,
+            contra las tablas <literal>ORDER</literal>, <literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>,
+            <literal>CATALOG</literal> and <literal>PRICE</literal> tiene cuatro joins interiores y una subselect
+            (no correlacionada).
+        </para>
+        
+        <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+    join order.lineItems as item
+    join item.product as product,
+    Catalog as catalog
+    join catalog.prices as price
+where order.paid = false
+    and order.customer = :customer
+    and price.product = product
+    and catalog.effectiveDate < sysdate
+    and catalog.effectiveDate >= all (
+        select cat.effectiveDate 
+        from Catalog as cat
+        where cat.effectiveDate < sysdate
+    )
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+        
+        <para>
+            &#x00a1;Qu&#x00e9; monstruo! Realmente, en la vida real, no estoy muy afilado en subconsultas, de modo que mi
+            consulta fue realmente algo como esto:
+        </para>
+        
+        <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+    join order.lineItems as item
+    join item.product as product,
+    Catalog as catalog
+    join catalog.prices as price
+where order.paid = false
+    and order.customer = :customer
+    and price.product = product
+    and catalog = :currentCatalog
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+        
+        <para>
+            La pr&#x00f3;xima consulta cuenta el n&#x00fa;mero de pagos en cada estado, excluyendo todos los pagos
+            en el estado <literal>AWAITING_APPROVAL</literal> donde el estado m&#x00e1;s reciente fue hecho por el
+            usuario actual. Se traduce en una consulta SQL con dos joins interiores y una subselect
+            correlacionada contra las tablas <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal> y
+            <literal>PAYMENT_STATUS_CHANGE</literal>.
+        </para>
+
+        <programlisting><![CDATA[select count(payment), status.name 
+from Payment as payment 
+    join payment.currentStatus as status
+    join payment.statusChanges as statusChange
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+    or (
+        statusChange.timeStamp = ( 
+            select max(change.timeStamp) 
+            from PaymentStatusChange change 
+            where change.payment = payment
+        )
+        and statusChange.user <> :currentUser
+    )
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+        <para>
+            Si hubiese mapeado la colecci&#x00f3;n <literal>statusChanges</literal> como una lista, en vez de un conjunto,
+            la consulta habr&#x00ed;a sido mucho m&#x00e1;s simple de escribir.
+        </para>
+    
+        <programlisting><![CDATA[select count(payment), status.name 
+from Payment as payment
+    join payment.currentStatus as status
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+    or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+        <para>
+            La pr&#x00f3;xima consulta usa la funci&#x00f3;n <literal>isNull()</literal> de MS SQL Server para devolver
+            todas las cuentas y pagos inpagos de la organizaci&#x00f3;n a la que pertenece el usuario actual.
+            Se traduce en una consulta SQL con tres joins interiores, un join exterior y una subconsulta
+            contra las tablas <literal>ACCOUNT</literal>, <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal>,
+            <literal>ACCOUNT_TYPE</literal>, <literal>ORGANIZATION</literal> y <literal>ORG_USER</literal>.
+        </para>
+
+        <programlisting><![CDATA[select account, payment
+from Account as account
+    left outer join account.payments as payment
+where :currentUser in elements(account.holder.users)
+    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+        <para> 
+            Para algunas bases de datos, necesitar&#x00ed;amos eliminar la subselect (correlacionada).
+        </para>
+
+        <programlisting><![CDATA[select account, payment
+from Account as account
+    join account.holder.users as user
+    left outer join account.payments as payment
+where :currentUser = user
+    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+   </sect1>
+
+    <sect1 id="queryhql-bulk">
+        <title>Sentencias UPDATE y DELETE masivas</title>
+
+        <para>
+            HQL soporta ahora sentencias UPDATE y DELETE en HQL.
+            Ver <xref linkend="batch-direct"/> para detalles.
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-tipstricks">
+        <title>Consejos y Trucos</title>
+
+        <para>
+            Puedes contar el n&#x00fa;mero de resultados de una consulta sin devolverlos realmente:
+        </para>
+
+        <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue()]]></programlisting>
+
+        <para>
+            Para ordenar un resultado por el tama&#x00f1;o de una colecci&#x00f3;n, usa la siguiente consulta:
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User as usr 
+    left join usr.messages as msg
+group by usr.id, usr.name
+order by count(msg)]]></programlisting>
+
+        <para>
+            Si tu base de datos soporta subselects, puedes colocar una condici&#x00f3;n sobre el tama&#x00f1;o de selecci&#x00f3;n
+            en la cl&#x00e1;usula where de tu consulta:
+        </para>
+
+        <programlisting><![CDATA[from User usr where size(usr.messages) >= 1]]></programlisting>
+
+        <para>
+            Si tu base de datos no soporta subselects, usa la siguiente consulta:
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User usr.name
+    join usr.messages msg
+group by usr.id, usr.name
+having count(msg) >= 1]]></programlisting>
+
+        <para>
+            Como esta soluci&#x00f3;n no puede devolver un <literal>User</literal> con cero mensajes debido a la uni&#x00f3;n interior,
+            la siguiente forma es tambi&#x00e9;n &#x00fa;til:
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+    left join usr.messages as msg
+group by usr.id, usr.name
+having count(msg) = 0]]></programlisting>
+
+        <para>
+            Las propiedades de un JavaBean pueden ser ligadas al par&#x00e1;metros de consulta con nombre:
+        </para>
+
+        <programlisting><![CDATA[Query q = s.createQuery("from foo Foo as foo where foo.name=:name and foo.size=:size");
+q.setProperties(fooBean); // fooBean has getName() and getSize()
+List foos = q.list();]]></programlisting>
+
+        <para>
+            Las colecciones son paginables usando la interface <literal>Query</literal> con un filtro:
+        </para>
+
+        <programlisting><![CDATA[Query q = s.createFilter( collection, "" ); // the trivial filter
+q.setMaxResults(PAGE_SIZE);
+q.setFirstResult(PAGE_SIZE * pageNumber);
+List page = q.list();]]></programlisting>
+
+        <para>
+            Los elementos de colecci&#x00f3;n pueden ser ordenados o agrupados usando un filtro de consulta:
+        </para>
+        
+        <programlisting><![CDATA[Collection orderedCollection = s.filter( collection, "order by this.amount" );
+Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );]]></programlisting>
+
+        <para>
+            Puedes hallar el tama&#x00f1;o de una colecci&#x00f3;n sin inicializarla:
+        </para>
+
+        <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue();]]></programlisting>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/query_sql.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/query_sql.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/query_sql.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,477 @@
+<chapter id="querysql" revision="2">
+    <title>SQL Nativo</title>
+
+    <para>
+        Puedes tambi&#x00e9;n expresar consultas en el dialecto SQL nativo de tu base de datos. Esto es &#x00fa;til si quieres
+        utilizar aspectos espec&#x00ed;ficos de base de datos tal como consejos (hints) de consulta o la palabra clave
+        <literal>CONNECT</literal> en Oracle. Provee adem&#x00e1;s una clara ruta de migraci&#x00f3;n desde una aplicaci&#x00f3;n
+        basada en SQL/JDBC directo a Hibernate.
+    </para>
+
+    <para>
+        Hibernate3 te permite especificar SQL escrito a mano (incluyendo procedimientos almacenados) para todas
+        las operaciones de creaci&#x00f3;n, actualizaci&#x00f3;n, borrado y carga.
+    </para>
+
+    <sect1 id="querysql-creating">
+        <title>Creando una <literal>Query</literal> de SQL nativo</title>
+
+        <para>
+            Las consultas SQL se controlan por medio de la interface <literal>SQLQuery</literal>, que se obtiene
+            llamando a <literal>Session.createSQLQuery()</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createSQLQuery("select {cat.*} from cats cat")
+    .addEntity("cat", Cat.class)
+    .setMaxResults(50)
+    .list();]]></programlisting>
+
+        <para>
+            Esta consulta especificada:
+        </para>
+
+        <itemizedlist>
+        <listitem>
+        <para>
+            la cadena de consulta SQL, con un lugar para que Hibernate inyecte los alias de columnas
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            la entidad devuelta por la consulta, y sus alias de tablas SQL
+        </para>
+        </listitem>
+        </itemizedlist>
+    
+        <para>
+            El m&#x00e9;todo <literal>addEntity()</literal> asocia alias de tablas SQL con clases de entidad,
+            y determina la forma del conjunto resultado de la consulta.
+        </para>
+        
+        <para>
+            El m&#x00e9;todo <literal>addJoin()</literal> puede ser usado para cargar asociaciones a otras entidades y
+            colecciones.
+        </para>
+        
+        <programlisting><![CDATA[List cats = sess.createSQLQuery(
+        "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
+    )
+    .addEntity("cat", Cat.class)
+    .addJoin("kitten", "cat.kittens")
+    .list();]]></programlisting>
+    
+        <para>
+            Una consulta SQL nativa podr&#x00ed;a devolver un valor escalar simple o una combinaci&#x00f3;n de escalares y entidades.
+        </para>
+
+        <programlisting><![CDATA[Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")
+        .addScalar("maxWeight", Hibernate.DOUBLE);
+        .uniqueResult();]]></programlisting>
+
+
+    </sect1>
+
+    <sect1 id="querysql-aliasreferences">
+        <title>Alias y referencias de propiedad</title>
+
+        <para>
+            La notaci&#x00f3;n <literal>{cat.*}</literal> usada arriba es un atajo para "todas las propiedades".
+            Alternativamente, puedes listar las columnas expl&#x00ed;citamente, pero incluso en este caso dejamos
+            que Hibernate inyecte los alias de columnas SQL para cada propiedad. El lugar para un alias de columna
+            es s&#x00f3;lo el nombre de propiedad cualificado por el alias de la tabla. En el siguiente ejemplo,
+            recuperamos <literal>Cat</literal>s de una tabla diferente (<literal>cat_log</literal>) a una
+            declarada en los metadatos de mapeo. Nota que podr&#x00ed;amos incluso usar los alias de propiedad en la
+            cl&#x00e1;usula where si quisieramos.
+        </para>
+        <para>
+            La sint&#x00e1;xis <literal>{}</literal> <emphasis>no</emphasis> es requerida para consultas con nombre.
+            Ver <xref linkend="querysql-namedqueries"/>
+        </para>
+
+        <programlisting><![CDATA[String sql = "select cat.originalId as {cat.id}, " +
+    "cat.mateid as {cat.mate}, cat.sex as {cat.sex}, " +
+    "cat.weight*10 as {cat.weight}, cat.name as {cat.name} " +
+    "from cat_log cat where {cat.mate} = :catId"
+    
+List loggedCats = sess.createSQLQuery(sql)
+    .addEntity("cat", Cat.class)
+    .setLong("catId", catId)
+    .list();]]></programlisting>
+
+        <para>
+            <emphasis>Nota:</emphasis> si listas cada propiedad expl&#x00ed;citamente, &#x00a1;debes incluir todas las
+            propiedades de la clase <emphasis>y sus subclases</emphasis>!
+        </para>
+
+    </sect1>
+    
+    <sect1 id="querysql-namedqueries" revision="2">
+        <title>Consultas SQL con nombre</title>
+
+        <para>
+            Las consultas SQL con nombre pueden definirse en el documento de mapeo y llamadas exactamente
+            en la misma forma en que a una consulta HQL con nombre. En este caso, <emphasis>no</emphasis>
+            necesitamos llamar a <literal>addEntity()</literal>.
+        </para>
+
+         <programlisting><![CDATA[<sql-query name="persons">
+    <return alias="person" class="eg.Person"/>
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex}
+    FROM PERSON person 
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+        <programlisting><![CDATA[List people = sess.getNamedQuery("persons")
+    .setString("namePattern", namePattern)
+    .setMaxResults(50)
+    .list();]]></programlisting>
+
+         <para>
+             Los elementos <literal>&lt;return-join&gt;</literal> y <literal>&lt;load-collection&gt;</literal>
+             se usan para unir asociaciones y definir consultas que inicialicen colecciones, respectivamente.
+         </para>
+         
+         <programlisting><![CDATA[<sql-query name="personsWith">
+    <return alias="person" class="eg.Person"/>
+    <return-join alias="address" property="person.mailingAddress"/>
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex},
+           adddress.STREET AS {address.street},
+           adddress.CITY AS {address.city},
+           adddress.STATE AS {address.state},
+           adddress.ZIP AS {address.zip}
+    FROM PERSON person 
+    JOIN ADDRESS adddress
+    	ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+        <para>
+            Una consulta SQL con nombre puede devolver un valor escalar. Debes especificar el alias de columna y
+            tipo Hibernate usando el elementp <literal>&lt;return-scalar&gt;</literal>:
+        </para>
+        
+        <programlisting><![CDATA[<sql-query name="mySqlQuery">
+    <return-scalar column="name" type="string"/>
+    <return-scalar column="age" type="long"/>
+    SELECT p.NAME AS name,
+           p.AGE AS age,
+    FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
+</sql-query>]]></programlisting>
+
+         <sect2 id="propertyresults">
+             <title>Usando return-property para especificar expl&#x00ed;citamente nombres de columna/alias</title>
+             
+             <para>
+                 Con <literal>&lt;return-property&gt;</literal> puedes decirle expl&#x00ed;citamente a Hibernate qu&#x00e9;
+                 alias de columna usar, en vez de usar la sint&#x00e1;xis <literal>{}</literal> para dejar que Hibernate
+                 inyecte sus propios alias.
+             </para>
+             
+            <programlisting><![CDATA[<sql-query name="mySqlQuery">
+    <return alias="person" class="eg.Person">
+        <return-property name="name" column="myName"/>
+        <return-property name="age" column="myAge"/>
+        <return-property name="sex" column="mySex"/>
+    </return>
+    SELECT person.NAME AS myName,
+           person.AGE AS myAge,
+           person.SEX AS mySex,
+    FROM PERSON person WHERE person.NAME LIKE :name
+</sql-query>
+]]></programlisting>
+             
+             <para>
+                 <literal>&lt;return-property&gt;</literal> tambi&#x00e9;n trabaja con m&#x00fa;ltiples columnas. Esto resuelve una
+                 limitaci&#x00f3;n de la sint&#x00e1;xis <literal>{}</literal>, la cual no puede permitir un control fino de propiedades
+                 multi-columna.
+             </para>
+             
+             <programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
+    <return alias="emp" class="Employment">            
+        <return-property name="salary"> 
+            <return-column name="VALUE"/>
+            <return-column name="CURRENCY"/>            
+        </return-property>
+        <return-property name="endDate" column="myEndDate"/>
+    </return>
+        SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer}, 
+        STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+        REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
+        FROM EMPLOYMENT
+        WHERE EMPLOYER = :id AND ENDDATE IS NULL
+        ORDER BY STARTDATE ASC
+</sql-query>]]></programlisting>
+             
+            <para>
+                Nota que en este ejemplo hemos usado <literal>&lt;return-property&gt;</literal> en combinaci&#x00f3;n con
+                la sint&#x00e1;xis <literal>{}</literal> para inyecci&#x00f3;n, permitiendo a los usuarios elejir c&#x00f3;mo quieren
+                referirse a las columnas y propiedades.
+            </para>
+
+            <para>
+                Si tu mapeo tiene un discriminador debes usar <literal>&lt;return-discriminator&gt;</literal>
+                para especificar la columna discriminadora.
+            </para>
+         </sect2>
+         
+         <sect2 id="sp_query">
+             <title>Usando procedimientos almacenados para consultar</title>
+             
+             <para>
+                 Hibernate3 introduce soporte para consultas v&#x00ed;a procedimientos almacenados. Los procedimientos
+                 almacenados deben devolver un conjunto resultado como el primer par&#x00e1;metro de salida para ser
+                 capaces de funcionar con Hibernate. Un ejemplo de uno procedimiento almacenado en Oracle 9
+                 o superior es as&#x00ed;:
+             </para>
+                 
+                 <programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments 
+    RETURN SYS_REFCURSOR 
+AS 
+    st_cursor SYS_REFCURSOR; 
+BEGIN 
+    OPEN st_cursor FOR 
+ SELECT EMPLOYEE, EMPLOYER, 
+ STARTDATE, ENDDATE, 
+ REGIONCODE, EID, VALUE, CURRENCY 
+ FROM EMPLOYMENT; 
+      RETURN  st_cursor; 
+ END;]]></programlisting>
+                 
+             <para>
+                 Para usar esta consulta en Hibernate necesitas mapearla por medio de una consulta con nombre.
+             </para>
+                 
+             <programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
+    <return alias="emp" class="Employment">
+        <return-property name="employee" column="EMPLOYEE"/>
+        <return-property name="employer" column="EMPLOYER"/>            
+        <return-property name="startDate" column="STARTDATE"/>
+        <return-property name="endDate" column="ENDDATE"/>            
+        <return-property name="regionCode" column="REGIONCODE"/>            
+        <return-property name="id" column="EID"/>                        
+        <return-property name="salary"> 
+            <return-column name="VALUE"/>
+            <return-column name="CURRENCY"/>            
+        </return-property>
+    </return>
+    { ? = call selectAllEmployments() }
+</sql-query>]]></programlisting>
+             
+             <para>
+               Nota que los procedimientos almacenados s&#x00f3;lo devuelven escalares y entidades.
+               No est&#x00e1;n soportados <literal>&lt;return-join&gt;</literal> y <literal>&lt;load-collection&gt;</literal>.
+             </para>
+             
+             <sect3 id="querysql-limits-storedprocedures">
+               <title>Reglas/limitaciones para usar procedimientos almacenados</title>
+               
+               <para>
+                   Para usar procedimientos almacenados con Hibernate los procedimientos tienen que seguir algunas reglas.
+                   Si no siguen esas reglas no son usables por Hibernate. Si a&#x00fa;n quisieras usar estos procedimientos
+                   tendr&#x00ed;as que ejecutarlos por medio de <literal>session.connection()</literal>. Las reglas son
+                   diferentes para cada base de datos, ya que los vendedores de base de datos tienen diferentes
+                   sem&#x00e1;nticas/sint&#x00e1;xis de procedimientos almacenados.
+               </para>
+
+                <para>
+                   Las consultas de procedimientos almacenados no pueden ser paginadas con 
+                   <literal>setFirstResult()/setMaxResults()</literal>.
+               </para>
+
+                 <para>
+                   Para Oracle se aplican las siguientes reglas:
+               </para>
+               
+               <itemizedlist spacing="compact">
+               <listitem>
+               <para>    
+                   El procedimiento debe devolver un conjunto resultado. Esto se hace devolviendo un
+                   <literal>SYS_REFCURSOR</literal> en Oracle 9 o 10. En Oracle necesitas definir un
+                   tipo <literal>REF CURSOR</literal>.
+               </para>
+               </listitem>    
+               <listitem>
+               <para>
+                   La forma recomendada es <literal>{ ? = call procName(&lt;parameters&gt;) }</literal> o
+                   <literal>{ ? = call procName }</literal> (esto es m&#x00e1;s una regla de Oracle que una regla de Hibernate).
+               </para>
+               </listitem>    
+              </itemizedlist>
+                           
+              <para>                   
+                   Para Sybase o MS SQL server se aplican las siguientes reglas:
+               </para>
+                   
+               <itemizedlist spacing="compact">
+               <listitem>
+               <para>    
+                   El procedimiento debe devolver un conjunto resultado. Nota que ya que estos servidores pueden
+                   y devolver&#x00e1;n m&#x00fa;ltiples conjuntos resultados y cuentas de actualizaci&#x00f3;n, Hibernate iterar&#x00e1;
+                   los resultados y tomar&#x00e1; el primer resultado que sea un conjunto resultado como su valor
+                   a devolver. Todo lo dem&#x00e1;s ser&#x00e1; descartado.
+               </para>
+               </listitem>    
+               <listitem>
+               <para>
+                   Si habilitas <literal>SET NOCOUNT ON</literal> en tu procedimiento ser&#x00e1; probablemente m&#x00e1;s
+                   eficiente, pero esto no es un requerimiento.
+               </para>
+               </listitem>    
+              </itemizedlist>
+              </sect3>
+         </sect2>
+
+    </sect1>
+
+    <sect1 id="querysql-cud">
+        <title>SQL personalizado para crear, actualizar y borrar</title>
+
+        <para>
+            Hibernate3 puede usar sentencias SQL personalizadas para las operaciones de
+            crear, actualizar y borrar. Los persistidores de clases y colecciones en Hibernate
+            ya contienen un conjunto de cadenas generadas en tiempo de configuraci&#x00f3;n (insertsql,
+            deletesql, updatesql, etc.). Las etiquetas de mapeo <literal>&lt;sql-insert&gt;</literal>,
+            <literal>&lt;sql-delete&gt;</literal>, y <literal>&lt;sql-update&gt;</literal> sobrescriben
+            estas cadenas:
+        </para>
+
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
+    <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
+    <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
+</class>]]></programlisting>
+
+        <para>
+            El SQL se ejecuta directamente en tu base de datos, de modo que eres libre de usar cualquier
+            dialecto que quieras. Esto reducir&#x00e1;, por supuesto, la portabilidad de tu mapeo si usas SQL
+            espec&#x00ed;fico de la base de datos.
+        </para>
+
+        <para>
+            Los procedimientos almacenados son soportados si est&#x00e1; establecido el atributo
+            <literal>callable</literal>:
+        </para>
+
+    <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
+    <sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
+    <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
+</class>]]></programlisting>
+
+        <para>
+          El orden de los par&#x00e1;metros posicionales son actualmente vitales, ya que deben estar en la
+          misma secuencia en que las espera Hibernate.
+        </para>
+        
+        <para>
+          Puedes ver el orden esperado habilitando el registro de depuraci&#x00f3;n para el nivel
+          <literal>org.hibernate.persister.entity</literal>. Con este nivel habilitado, Hibernate
+          imprimir&#x00e1; el SQL est&#x00e1;tico que se usa para crear, actualizar, borrar, etc. las entidades.
+          (Para ver la secuencia esperada, recuerda no incluir tu SQL personalizado en los ficheros
+          de mapeo ya que sobrescribir&#x00e1;n el sql est&#x00e1;tico generado por Hibernate.)
+        </para>
+
+        <para>
+            Los procedimientos almacenados son, en la mayor&#x00ed;a de los casos (l&#x00e9;ase, mejor hacerlo que no hacerlo),
+            obligados a devolver el n&#x00fa;mero de filas insertadas/actualizadas/borradas, ya que Hibernate tiene algunas
+            comprobaciones en tiempo de ejecuci&#x00f3;n del &#x00e9;xito de la sentencia. Hibernate siempre registra el primer
+            par&#x00e1;metro de la sentencia como un par&#x00e1;metro de salida num&#x00e9;rico para las operaciones CUD:
+        </para>
+
+        <programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
+    RETURN NUMBER IS
+BEGIN
+
+    update PERSON
+    set
+        NAME = uname,
+    where
+        ID = uid;
+
+    return SQL%ROWCOUNT;
+
+END updatePerson;]]></programlisting>
+
+        
+    </sect1>
+
+    <sect1 id="querysql-load">
+        <title>SQL personalizado para carga</title>
+
+        <para>
+            Puedes tambi&#x00e9;n declarar tu propias consultas SQL (o HQL) para cargar entidades:
+        </para>
+
+        <programlisting><![CDATA[<sql-query name="person">
+    <return alias="pers" class="Person" lock-mode="upgrade"/>
+    SELECT NAME AS {pers.name}, ID AS {pers.id} 
+    FROM PERSON 
+    WHERE ID=? 
+    FOR UPDATE
+</sql-query>]]></programlisting>
+
+        <para>
+            Esto es s&#x00f3;lo una declaraci&#x00f3;n de consulta con nombrem como se ha discutido anteriormente.
+            Puedes hacer referencia a esta consulta con nombre en un mapeo de clase:
+        </para>
+
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <loader query-ref="person"/>
+</class>]]></programlisting>
+    
+        <para>
+            Esto incluso funciona con procedimientos almacenados.
+        </para>
+
+        <para>
+            Puedes incluso definit una consulta para la carga de colecciones:
+        </para>
+
+<programlisting><![CDATA[<set name="employments" inverse="true">
+    <key/>
+    <one-to-many class="Employment"/>
+    <loader query-ref="employments"/>
+</set>]]></programlisting>
+		
+        <programlisting><![CDATA[<sql-query name="employments">
+    <load-collection alias="emp" role="Person.employments"/>
+    SELECT {emp.*}
+    FROM EMPLOYMENT emp
+    WHERE EMPLOYER = :id
+    ORDER BY STARTDATE ASC, EMPLOYEE ASC
+</sql-query>]]></programlisting>
+
+        <para>
+            Podr&#x00ed;as incluso definir un cargador de entidades que cargue una colecci&#x00f3;n por
+            recuperaci&#x00f3;n por uni&#x00f3;n (join fetching):
+        </para>
+
+        <programlisting><![CDATA[<sql-query name="person">
+    <return alias="pers" class="Person"/>
+    <return-join alias="emp" property="pers.employments"/> 
+    SELECT NAME AS {pers.*}, {emp.*}
+    FROM PERSON pers
+    LEFT OUTER JOIN EMPLOYMENT emp 
+        ON pers.ID = emp.PERSON_ID
+    WHERE ID=?
+</sql-query>]]></programlisting>
+
+    </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/quickstart.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/quickstart.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/quickstart.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,666 @@
+<chapter id="quickstart">
+    <title>Comienzo r&#x00e1;pido con Tomcat</title>
+
+    <sect1 id="quickstart-intro" revision="2">
+        <title>Empezando con Hibernate</title>
+
+        <para>
+            Este tutorial explica una instalaci&#x00f3;n de Hibernate con el
+            contenedor de servlets Apache Tomcat (hemos usado la versi&#x00f3;n 4.1,
+            las diferencias con la 5.0 deben ser m&#x00ed;nimas) para una aplicaci&#x00f3;n
+            basada en web. Hibernate trabaja bien en un entorno manejado con
+            todos los servidores de aplicaciones J2EE importantes, o incluso en aplicaciones
+            Java independientes. El sistema de base de datos es s&#x00f3;lo una cuesti&#x00f3;n
+            de cambiar la configuraci&#x00f3;n del dialecto SQL de Hibernate y las
+            propiedades de conexi&#x00f3;n.
+        </para>
+
+        <para>
+            Primero, tenemos que copiar todas las bibliotecas requeridas a la instalaci&#x00f3;n
+            de Tomcat. Usamos un contexto web separado (<literal>webapps/quickstart</literal>) 
+            para este tutorial, de modo que tenemos que considerar tanto la ruta de b&#x00fa;squeda
+            de bibliotecas global (<literal>TOMCAT/common/lib</literal>) como tambi&#x00e9;n
+            el cargador de clases a nivel de contexto en <literal>webapps/quickstart/WEB-INF/lib</literal>
+            (para ficheros JAR) y <literal>webapps/quickstart/WEB-INF/classes</literal>.
+            Nos referiremos a ambos niveles de cargador de clases como el classpath global y el classpath
+            de contexto, respectivamente.
+        </para>
+
+        <para>
+            Ahora, copia las bibliotecas a los dos classpaths:
+        </para>
+
+        <orderedlist>
+            <listitem>
+                <para>
+                    Copia el driver JDBC para la base de datos al classpath global. Esto se
+                    requiere para el software de pool de conexiones DBCP que se distribuye
+                    con Tomcat. Hibernate usa conexiones JDBC para ejecutar SQL sobre la base de
+                    datos, de modo que, o bien tienes que proveer conexiones JDBC en pool,
+                    o bien configurar Hibernate para que use uno de los pools soportados
+                    directamente (C3P0, Proxool). Para este tutorial, copia la biblioteca
+                    <literal>pg74jdbc3.jar</literal> (para PostgreSQL 7.4 y JDK 1.4) al
+                    classpath del cargador global. Si quisieras usar una base de datos diferente,
+                    simplemente copia su apropiado driver JDBC.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Nunca copies nada m&#x00e1;s dentro de la ruta del cargador de clases global
+                    en Tomcat, o tendr&#x00e1;s problemas con varias herramientas, incluyendo
+                    Log4J, commons-logging y otras. Siempre usa el classpath de contexto para
+                    cada aplicaci&#x00f3;n web, esto es, copia las bibliotecas a
+                    <literal>WEB-INF/lib</literal> y tus propias clases y ficheros de
+                    configuraci&#x00f3;n/propiedades a <literal>WEB-INF/classes</literal>.
+                    Ambos directorios est&#x00e1;n a nivel del classpath de contexto por defecto.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Hibernate est&#x00e1; empaquetado como una biblioteca JAR. El fichero
+                    <literal>hibernate3.jar</literal> debe ser copiado en el classpath de contexto
+                    junto a las otras clases de la aplicaci&#x00f3;n. Hibernate requiere algunas
+                    bibliotecas de terceros en tiempo de ejecuci&#x00f3;n; &#x00e9;stas vienen
+                    inclu&#x00ed;das con la distribuci&#x00f3;n de Hibernate en el directorio
+                    <literal>lib/</literal>. Ver <xref linkend="3rdpartylibs"/>. Copia las
+                    bibliotecas de terceros requeridas al classpath de contexto.
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <table frame="topbot" id="3rdpartylibs">
+            <title>
+                Bibliotecas de terceros de Hibernate
+            </title>
+            <tgroup cols="2" rowsep="1" colsep="1">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="2*"/>
+                <thead>
+                    <row>
+                        <entry align="center">
+                            Biblioteca
+                        </entry>
+                        <entry align="center">
+                            Descripci&#x00f3;n
+                        </entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            antlr (requerida)
+                        </entry>
+                        <entry>
+                            Hibernate usa ANTLR para producir analizadores de consultas,
+                            esta biblioteca tambi&#x00e9;n se necesita en tiempo de ejecuci&#x00f3;n.
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            dom4j (requerida)
+                        </entry>
+                        <entry>
+                            Hibernate usa dom4j para analizar ficheros de configuraci&#x00f3;n
+                            XML y ficheros de metadatos de mapeo XML.
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            CGLIB, asm (requerida)
+                        </entry>
+                        <entry>
+                            Hibernate usa la biblioteca de generaci&#x00f3;n de c&#x00f3;digo
+                            para aumentar las clases en tiempo de ejecuci&#x00f3;n
+                            (en combinaci&#x00f3;n con reflecci&#x00f3;n Java).
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            Commons Collections, Commons Logging (requeridas)
+                        </entry>
+                        <entry>
+                            Hibernate usa varias bibliotecas de utilidad del proyecto
+                            Jakarta Commons de Apache.
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            EHCache (requerida)
+                        </entry>
+                        <entry>
+                            Hibernate puede usar varios provedores de cach&#x00e9; para
+                            el cach&#x00e9; de segundo nivel. EHCache es el provedor de
+                            cach&#x00e9; por defecto si no se cambia en la configuraci&#x00f3;n.
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            Log4j (opcional)
+                        </entry>
+                        <entry>
+                            Hibernate usa la API de Commons Logging, que a su vez puede
+                            usar Log4J como el mecanismo de logging subyacente. Si la
+                            biblioteca Log4J est&#x00e1; disponible en el directorio de
+                            bibliotecas del contexto, Commons Logging usar&#x00e1; Log4J
+                            y la configuraci&#x00f3;n <literal>log4j.properties</literal>
+                            en el classpath de contexto. Un fichero de propiedades de ejemplo
+                            para Log4J se incluye con la distribuci&#x00f3;n de Hibernate.
+                            As&#x00ed; que copia log4j.jar y el fichero de configuraci&#x00f3;n
+                            (de <literal>src/</literal>) a tu classpath de contexto si quieres
+                            ver que ocurre tras esc&#x00e9;nas.
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            ¿Requerida o no?
+                        </entry>
+                        <entry>
+                            Echa una mirada al fichero <literal>lib/README.txt</literal> en la
+                            distribuci&#x00f3;n de Hibernate. Esta es una lista actualizada
+                            de bibliotecas de terceros distribu&#x00ed;das con Hibernate.
+                            Encontrar&#x00e1;s listadas ah&#x00ed; todas las bibliotecas
+                            requeridas y opcionales (Observa que "buildtame required" significa
+                            aqu&#x00ed; para la construcci&#x00f3;n de Hibernate, no de tu
+                            aplicaci&#x00f3;n).
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+            Ahora instalamos el pooling y modo compartido de conexiones de base de datos
+            tanto en Tomcat como Hibernate. Esto significa que Tomcat proveer&#x00e1;
+            conexiones JDBC en pool (usando su funcionalidad prefabricada de pooling DBCP).
+            Hibernate pide esas conexiones a trav&#x00e9;s de JNDI. Alternativamente,
+            puedes dejar que Hibernate maneje el pool de conexiones. Tomcat liga su pool
+            de conexiones a JNDI; agregamos una declaraci&#x00f3;n de recurso al fichero
+            de configuraci&#x00f3;n principal de Tomcat, <literal>TOMCAT/conf/server.xml</literal>:
+        </para>
+
+        <programlisting><![CDATA[<Context path="/quickstart" docBase="quickstart">
+    <Resource name="jdbc/quickstart" scope="Shareable" type="javax.sql.DataSource"/>
+    <ResourceParams name="jdbc/quickstart">
+        <parameter>
+            <name>factory</name>
+            <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
+        </parameter>
+
+        <!-- DBCP database connection settings -->
+        <parameter>
+            <name>url</name>
+            <value>jdbc:postgresql://localhost/quickstart</value>
+        </parameter>
+        <parameter>
+            <name>driverClassName</name><value>org.postgresql.Driver</value>
+        </parameter>
+        <parameter>
+            <name>username</name>
+            <value>quickstart</value>
+        </parameter>
+        <parameter>
+            <name>password</name>
+            <value>secret</value>
+        </parameter>
+
+        <!-- DBCP connection pooling options -->
+        <parameter>
+            <name>maxWait</name>
+            <value>3000</value>
+        </parameter>
+        <parameter>
+            <name>maxIdle</name>
+            <value>100</value>
+        </parameter>
+        <parameter>
+            <name>maxActive</name>
+            <value>10</value>
+        </parameter>
+    </ResourceParams>
+</Context>]]></programlisting>
+
+        <para>
+            El contexto que configuramos en este ejemplo se llama <literal>quickstart</literal>,
+            su base es el directorio <literal>TOMCAT/webapp/quickstart</literal>. Para acceder
+            a cualquier servlet, llama a la ruta <literal>http://localhost:8080/quickstart</literal>
+            en tu navegador (por supuesto, agregando el nombre del servlet como se mapee en tu
+            <literal>web.xml</literal>). Puedes tambi&#x00e9;n ir m&#x00e1;s all&#x00e1; y crear
+            ahora un servlet simple que tenga un m&#x00e9;todo <literal>process()</literal>
+            vac&#x00ed;o.
+        </para>
+
+        <para>
+            Tomcat provee ahora conexiones a trav&#x00e9;s de JNDI en
+            <literal>java:comp/env/jdbc/quickstart</literal>. Si tienes problemas obteniendo
+            el pool de conexiones en ejecuci&#x00f3;n, refi&#x00e9;rete a la documentaci&#x00f3;n
+            de Tomcat. Si obtienes mensajes de excepci&#x00f3;n del driver JDBC, intenta instalar
+            primero el pool de conexiones JDBC sin Hibernate. Hay disponibles en la Web
+            tutoriales de Tomcat y JDBC.
+        </para>
+
+        <para>
+            Tu pr&#x00f3;ximo paso es configurar Hibernate. Hibernate tiene que saber c&#x00f3;mo
+            debe obtener conexiones JDBC. Usamos la configuraci&#x00f3;n de Hibernate basada en XML.
+            El otro enfoque, usando un ficheros de propiedad, es casi equivalente pero pierde unas
+            pocas funcionalidades que s&#x00ed; permite la sintaxis XML. El fichero de configuraci&#x00f3;n
+            XML se ubica en el classpath de contexto (<literal>WEB-INF/classes</literal>), como
+            <literal>hibernate.cfg.xml</literal>:
+        </para>
+
+        <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+    "-//Hibernate/Hibernate Configuration DTD//EN"
+    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <session-factory>
+
+        <property name="connection.datasource">java:comp/env/jdbc/quickstart</property>
+        <property name="show_sql">false</property>
+        <property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
+
+        <!-- Mapping files -->
+        <mapping resource="Cat.hbm.xml"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+            Desactivamos el registro (logging) de comandos SQL y decimos a Hibernate
+            qu&#x00e9; dialecto SQL de base de datos se usa y d&#x00f3;nde obtener
+            conexiones JDBC (declarando la direcci&#x00f3;n JNDI del pool ligado a
+            Tomcat). El dialecto es una configuraci&#x00f3;n requerida, las bases de
+            datos difieren en su interpretaci&#x00f3;n del "est&#x00e1;ndar" de SQL.
+            Hibernate cuidar&#x00e1; de las diferencias y viene con dialectos inclu&#x00ed;dos
+            para todas las principales bases de datos comerciales y de c&#x00f3;digo
+            abierto.
+        </para>
+
+        <para>
+            Una <literal>SessionFactory</literal> es el concepto de Hibernate
+            de un almac&#x00e9;n de datos solo. Pueden usarse m&#x00fa;ltiples
+            bases de datos creando m&#x00fa;ltiples ficheros de configuraci&#x00f3;n
+            XML y creando m&#x00fa;ltiples objetos <literal>Configuration</literal>
+            y <literal>SessionFactory</literal> en tu aplicaci&#x00f3;n.
+        </para>
+
+        <para>
+            El &#x00fa;ltimo elemento del <literal>hibernate.cfg.xml</literal>
+            declara <literal>Cat.hbm.xml</literal> como el nombre de un fichero
+            de mapeo XML para la clase persistente <literal>Cat</literal>. Este
+            fichero contiene los metadatos para el mapeo de la clase POJO 
+            <literal>Cat</literal> a una tabla (o tablas) de base de datos.
+            Volveremos a este fichero pronto. Escribamos primero la clase POJO
+            y luego declaremos los metadatos de mapeo para ella.
+        </para>
+
+    </sect1>
+
+    <sect1 id="quickstart-persistentclass" revision="1">
+        <title>Primera clase persistente</title>
+
+        <para>
+            Hibernate trabaja mejor con el modelo de programaci&#x00f3;n de los 
+            Viejos Objetos Planos de Java (POJOs, a veces llamados Ordinarios Objetos Planos de Java)
+            para clases persistentes. Un POJO es como un JavaBean, con las propiedades
+            de la clase accesible v&#x00ed;a m&#x00e9;todos getter y setter,
+            encapsulando la representaci&#x00f3;n interna de la interfaz publicamente
+            visible (Hibernate puede tambi&#x00e9;n acceder a los campos directamente, si se
+            necesita):
+        </para>
+
+        <programlisting><![CDATA[package org.hibernate.examples.quickstart;
+
+public class Cat {
+
+    private String id;
+    private String name;
+    private char sex;
+    private float weight;
+
+    public Cat() {
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    private void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public char getSex() {
+        return sex;
+    }
+
+    public void setSex(char sex) {
+        this.sex = sex;
+    }
+
+    public float getWeight() {
+        return weight;
+    }
+
+    public void setWeight(float weight) {
+        this.weight = weight;
+    }
+
+}]]></programlisting>
+
+        <para>
+            Hibernate no est&#x00e1; restringido en su uso de tipos de propiedad, todos
+            los tipos y tipos primitivos del JDK de Java (como <literal>String</literal>,
+            <literal>char</literal> y <literal>Date</literal>) pueden ser mapeados, incluyendo
+            clases del framework de colecciones de Java. Puedes mapearlos como valores,
+            colecciones de valores, o asociaciones a otras entidades. El <literal>id</literal>
+            es una propiedad especial que representa el identificador de base de datos (clave
+            primaria) de la clase. Es altamente recomendado para entidades como un
+            <literal>Cat</literal>. Hibernate puede usar identificadores s&#x00f3;lo
+            internamente, pero perder&#x00ed;amos algo de la flexibilidad en nuestra
+            arquitectura de aplicaci&#x00f3;n.
+        </para>
+
+        <para>
+            No tiene que implementarse ninguna interface especial para las clases persistentes
+            ni tienes que subclasear de una clase persistente ra&#x00ed;z en especial. Hibernate
+            tampoco requiere ning&#x00fa;n procesamiento en tiempo de construcci&#x00f3;n, 
+            como manipulaci&#x00f3;n del byte-code. Se basa solamente en reflecci&#x00f3;n de Java
+            y aumentaci&#x00f3;n de clases en tiempo de ejecuci&#x00f3;n (a trav&#x00e9;s de CGLIB).
+            De modo que, sin ninguna dependencia de la clase POJO en Hibernate, podemos mapearla
+            a una tabla de base de datos.
+        </para>
+
+    </sect1>
+
+    <sect1 id="quickstart-mapping" revision="1">
+        <title>Mapeando el gato</title>
+
+        <para>
+            El fichero de mapeo <literal>Cat.hbm.xml</literal> contiene los
+            metadatos requeridos para el mapeo objeto/relacional. Los metadatos
+            incluyen la declaraci&#x00f3;n de clases persistentes y el mapeo de
+            propiedades (a columnas y relaciones de claves for&#x00e1;neas a otras
+            entidades) a tablas de base de datos.
+        </para>
+
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+
+    <class name="org.hibernate.examples.quickstart.Cat" table="CAT">
+
+        <!-- A 32 hex character is our surrogate key. It's automatically
+            generated by Hibernate with the UUID pattern. -->
+        <id name="id" type="string" unsaved-value="null" >
+            <column name="CAT_ID" sql-type="char(32)" not-null="true"/>
+            <generator class="uuid.hex"/>
+        </id>
+
+        <!-- A cat has to have a name, but it shouldn' be too long. -->
+        <property name="name">
+            <column name="NAME" length="16" not-null="true"/>
+        </property>
+
+        <property name="sex"/>
+
+        <property name="weight"/>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Cada clase persistente debe tener un atributo identificador (realmente, 
+            s&#x00f3;lo las clases que representen entidades, no las clases dependientes
+            de tipo-valor, que son mapeadas como componentes de una entidad). Esta propiedad
+            es usada para distinguir los objetos persistentes: Dos gatos son iguales si
+            <literal>catA.getId().equals(catB.getId())</literal> es verdadero. Este concepto
+            se llama <emphasis>identidad de base de datos (database identity)</emphasis>.
+            Hibernate viene empaquetado con varios generadores de identificador para diferentes
+            escenarios (incluyendo generadores nativos para secuencias de base de datos, tablas
+            de identificadores alto/bajo, e identificadores asignados por aplicaci&#x00f3;n).
+            Usamos el generador UUID (recomendado s&#x00f3;lo para pruebas, pues deben
+            preferirse las claves enteras delegadas generadas por la base de datos) y
+            tambi&#x00e9;n especificamos la columna <literal>CAT_ID</literal> de la tabla
+            <literal>CAT</literal> para el valor identificador generado por Hibernate
+            (como una clave primaria de la tabla).
+        </para>
+
+        <para>
+            Todas las dem&#x00e1;s propiedades de <literal>Cat</literal> son mapeadas a la
+            misma tabla. En el caso de la propiedad <literal>name</literal>, la hemos mapeado
+            con una declaraci&#x00f3;n expl&#x00ed;cita de columna de base de datos. Esto es
+            especialmente &#x00fa;til cuando el esquema de base de datos es generado
+            autom&#x00e1;ticamente (como sentencias DDL de SQL) desde la declaraci&#x00f3;n
+            de mapeo con la herramienta <emphasis>SchemaExport</emphasis> de Hibernate.
+            Todas las dem&#x00e1;s propiedades son mapeadas usando la configuraci&#x00f3;n
+            por defecto de Hibernate, que es lo que necesitas la mayor&#x00ed;a del tiempo.
+            La tabla <literal>CAT</literal> en la base de datos se ve as&#x00ed; como:
+        </para>
+
+        <programlisting><![CDATA[ Columna |         Tipo          | Modificadores
+--------+-----------------------+-----------
+ cat_id | character(32)         | not null
+ name   | character varying(16) | not null
+ sex    | character(1)          |
+ weight | real                  |
+Indexes: cat_pkey primary key btree (cat_id)]]></programlisting>
+
+        <para>
+            Ahora debes crear esta tabla manualmente en tu base de datos, y luego leer el
+            <xref linkend="toolsetguide"/> si quieres automatizar este paso con la
+            herramienta <literal>hbm2ddl</literal>. Esta herramienta puede crear un
+            DDL SQL completo, incluyendo definici&#x00f3;n de tablas, restricciones
+            personalizadas de tipo de columnas, restricciones de unicidad e &#x00ed;ndices.
+        </para>
+
+    </sect1>
+
+    <sect1 id="quickstart-playingwithcats" revision="2">
+        <title>Jugando con gatos</title>
+
+        <para>
+            Ahora estamos listos para comenzar la <literal>Session</literal> de Hibernate.
+            Es el <emphasis>manejador de persistencia</emphasis> que usamos para almacenar
+            y traer <literal>Cat</literal>s hacia y desde la base de datos. Pero primero,
+            tenemos que obtener una <literal>Session</literal> (unidad de trabajo de Hibernate)
+            de la <literal>SessionFactory</literal>:
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sessionFactory =
+            new Configuration().configure().buildSessionFactory();]]></programlisting>
+
+        <para>
+                        La llamada a <literal>configure()</literal> carga el fichero de
+                        configuraci&#x00f3;n <literal>hibernate.cfg.xml</literal> e
+                        inicializa la instancia de <literal>Configuration</literal>.
+                        Puedes establecer otras propiedades (e incluso cambiar los metadatos de mapeo)
+                        accediendo a la <literal>Configuration</literal> <emphasis>antes</emphasis>
+                        que construyas la <literal>SessionFactory</literal> (que es inmutable).
+                        ¿D&#x00f3;nde creamos la <literal>SessionFactory</literal> y c&#x00f3;mo
+                        accedemos a ella en nuestra aplicaci&#x00f3;n?
+        </para>
+
+        <para>
+            Una <literal>SessionFactory</literal> usualmente se construye una vez,
+            por ejemplo, al arrancar con un servlet <emphasis>load-on-startup</emphasis>.
+            Esto significa tambi&#x00e9;n que no debes mantenerla en una variable de instancia
+            en tus servlets, sino en alguna otro sitio. Adem&#x00e1;s, necesitamos alg&#x00fa;n
+            tipo de <emphasis>Singleton</emphasis>, de modo que podamos acceder a la
+            <literal>SessionFactory</literal> f&#x00e1;cilmente en el c&#x00f3;digo de
+            aplicaci&#x00f3;n. El siguiente enfoque mostrado resuelve ambos problemas:
+            configuraci&#x00f3;n de arranque y f&#x00e1;cil acceso a una
+            <literal>SessionFactory</literal>.
+        </para>
+
+		<para>
+                    Implementamos una clase de ayuda <literal>HibernateUtil</literal>:
+		</para>
+
+		<programlisting><![CDATA[import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+    private static Log log = LogFactory.getLog(HibernateUtil.class);
+
+    private static final SessionFactory sessionFactory;
+
+    static {
+        try {
+            // Create the SessionFactory
+            sessionFactory = new Configuration().configure().buildSessionFactory();
+        } catch (Throwable ex) {
+            // Make sure you log the exception, as it might be swallowed
+            log.error("Initial SessionFactory creation failed.", ex);
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    public static final ThreadLocal session = new ThreadLocal();
+
+    public static Session currentSession() {
+        Session s = (Session) session.get();
+        // Open a new Session, if this Thread has none yet
+        if (s == null) {
+            s = sessionFactory.openSession();
+            session.set(s);
+        }
+        return s;
+    }
+
+    public static void closeSession() {
+        Session s = (Session) session.get();
+        if (s != null)
+            s.close();
+        session.set(null);
+    }
+}]]></programlisting>
+
+        <para>
+            Esta clase no s&#x00f3;lo cuida de la <literal>SessionFactory</literal>
+            con su inicializador static, sino que adem&#x00e1;s tiene una variable
+            <literal>ThreadLocal</literal> que tiene la <literal>Session</literal>
+            para la hebra actual. Aseg&#x00fa;rate de entender el concepto Java de una
+            variable local a una hebra antes de intentar usar esta ayuda. Una clase
+            <literal>HibernateUtil</literal> m&#x00e1;s compleja y potente puede
+            encontrarse en <literal>CaveatEmptor</literal>, http://caveatemptor.hibernate.org/
+        </para>
+
+        <para>
+            Una <literal>SessionFactory</literal> es segura entre hebras, muchas hebras pueden
+            acceder a ella concurrentemente y pedirle <literal>Session</literal>s. Una
+            <literal>Session</literal> no es un objeto seguro entre hebras que representa
+            una sola unidad-de-trabajo con la base de datos. Las <literal>Session</literal>s
+            se abren desde una <literal>SessionFactory</literal> y son cerradas cuando
+            todo el trabajo est&#x00e1; completo. Un ejemplo en el m&#x00e9;todo
+            <literal>process()</literal> de tu servlet podr&#x00ed;a parecerse a esto
+            (sin manejo de excepciones):
+        </para>
+
+        <programlisting><![CDATA[Session session = HibernateUtil.currentSession();
+Transaction tx = session.beginTransaction();
+
+Cat princess = new Cat();
+princess.setName("Princess");
+princess.setSex('F');
+princess.setWeight(7.4f);
+
+session.save(princess);
+
+tx.commit();
+HibernateUtil.closeSession();]]></programlisting>
+
+        <para>
+            En una <literal>Session</literal>, cada operaci&#x00f3;n de base de datos
+            ocurre dentro de una transacci&#x00f3;n que a&#x00ed;sla las operaciones
+            de base de datos (incluso operaciones de s&#x00f3;lo lectura).
+            Usamos la API de <literal>Transaction</literal> de Hibernate para
+            abstraer de la estrategia de transacciones subyacente (en nuestro caso,
+            transacciones JDBC). Esto permite que nuestro c&#x00f3;digo sea desplegado
+            con transacciones manejadas por contenedor (usando JTA) sin cambio alguno.
+        </para>
+
+        <para>
+            Observa que puedes llamar <literal>HibernateUtil.currentSession();</literal>
+            tantas veces como quieras, siempre obtendr&#x00e1;s la <literal>Session</literal>
+            actual de esta hebra. Tienes que asegurarte que la <literal>Session</literal>
+            sea cerrada despu&#x00e9;s que se complete tu unidad-de-trabajo, ya sea en
+            c&#x00f3;digo de tu servlet o en un filtro de servlet antes que la respuesta HTTP
+            sea enviada. El bonito efecto colateral de la segunda opci&#x00f3;n es la
+            f&#x00e1;cil inicializaci&#x00f3;n perezosa: la <literal>Session</literal> todav&#x00ed;a
+            est&#x00e1; abierta cuando se dibuja la vista, de modo que Hibernate puede cargar
+            objetos no inicializados mientras navegas tu actual grafo de objetos.
+        </para>
+
+        <para>
+            Hibernate tiene varios m&#x00e9;todos que pueden ser usados para traer
+            objetos desde la base de datos. La forma m&#x00e1;s flexible es usando
+            el Lenguaje de Consulta de Hibernate (Hibernate Query Language o HQL),
+            que es una extensi&#x00f3;n orientada a objetos de SQL f&#x00e1;cil de
+            aprender:
+        </para>
+
+        <programlisting><![CDATA[Transaction tx = session.beginTransaction();
+
+Query query = session.createQuery("select c from Cat as c where c.sex = :sex");
+query.setCharacter("sex", 'F');
+for (Iterator it = query.iterate(); it.hasNext();) {
+    Cat cat = (Cat) it.next();
+    out.println("Female Cat: " + cat.getName() );
+}
+
+tx.commit();]]></programlisting>
+
+        <para>
+            Hibernate tambi&#x00e9;n ofrece una API <emphasis>consulta por criterios</emphasis>
+            orientada a objetos que puede ser usada para formular consultas de tipo seguro.
+            Por supuesto, Hibernate usa <literal>PreparedStatement</literal>s y ligado de
+            par&#x00e1;metros para toda la comunicaci&#x00f3;n SQL con la base de datos.
+            Tambi&#x00e9;n puedes usar la funcionalidad de consulta SQL directa de Hibernate
+            u obtener una conexi&#x00f3;n plana de JDBC de una <literal>Session</literal> 
+            en casos raros.
+        </para>
+
+    </sect1>
+
+    <sect1 id="quickstart-summary" revision="1">
+        <title>Finalmente</title>
+
+        <para>
+            Rasgu&#x00f1;amos solamente la superficie de Hibernate en este peque&#x00f1;o
+            tutorial. Por favor, observa que no incluimos ning&#x00fa;n c&#x00f3;digo
+            espec&#x00ed;fico de servlet en nuestros ejemplos. Tienes que crear un servlet
+            por t&#x00ed; mismo e insertar el c&#x00f3;digo de Hibernate como lo veas
+            ubicado.
+        </para>
+
+        <para>
+            Ten en mente que Hibernate, como capa de acceso a datos, est&#x00e1; firmemente
+            integrado dentro de tu aplicaci&#x00f3;n. Usualmente, todas las otras capas dependen
+            del mecanismo de persistencia. Aseg&#x00fa;rate de entender las implicaciones
+            de este dise&#x00f1;o.
+        </para>
+
+        <para>
+            Para un ejemplo de aplicaci&#x00f3;n m&#x00e1;s compleja, ver
+            http://caveatemptor.hibernate.org/ y echa una mirada a los
+            otros tutoriales con links en http://www.hibernate.org/Documentation
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/session_api.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/session_api.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/session_api.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1227 @@
+<chapter id="objectstate">
+    <title>Trabajando con objetos</title>
+
+    <para>
+        Hibernate es una soluci&#x00f3;n completa de mapeo objeto/relacional que no s&#x00f3;lo
+        abstrae al desarrollador de los detalles del sistema de manejo de base datos
+        subyacente, sino que adem&#x00e1;s ofrece <emphasis>manejo de estado</emphasis> de
+        objetos. Esto es, al contrario del manejo de <literal>sentencias</literal>
+        SQL en capas comunes de persistencia JDBC/SQL, una vista de la persistencia
+        en aplicaciones Java muy natural y orientada a objetos.
+    </para>
+
+    <para>
+        En otras palabras, los desarroladores de aplicaciones Hibernate deben siempre
+        pensar en el <emphasis>estado</emphasis> de sus objetos, y no necesariamente
+        en la ejecuci&#x00f3;n de sentencias SQL. Esta parte es cuidada por Hibernate y es
+        s&#x00f3;lo relevante para el desarrollador de la aplicaci&#x00f3;n al afinar el rendimiento
+        del sistema.
+    </para>
+
+    <sect1 id="objectstate-overview">
+        <title>Estados de objeto de Hibernate</title>
+
+        <para>
+            Hibernate define y soporta los siguientes estados de objeto:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>Transitorio</emphasis> - un objeto es transitorio si ha sido
+                    reci&#x00e9;n instanciado usando el operador <literal>new</literal>, y no est&#x00e1;
+                    asociado a una <literal>Session</literal> de Hibernate. No tiene una
+                    representaci&#x00f3;n persistente en la base de datos y no se le ha asignado un
+                    valor identificador. Las instancias transitorias ser&#x00e1;n destru&#x00ed;das por el
+                    recolector de basura si la aplicaci&#x00f3;n no mantiene m&#x00e1;s una referencia.
+                    Usa la <literal>Session</literal> de Hibernate para hacer un objeto
+                    persistente (y deja que Hibernate cuide de las sentencias SQL que necesitan
+                    ejecutarse para esta transici&#x00f3;n).
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Persistente</emphasis> - una instancia persistente tiene una
+                    representaci&#x00f3;n en la base de datos y un valor identificador. Puede haber
+                    sido salvado o cargado, sin embargo, est&#x00e1; por definici&#x00f3;n en el &#x00e1;mbito de
+                    una <literal>Session</literal>. Hibernate detectar&#x00e1; cualquier cambio hecho
+                    a un objeto en estado persistentey sincronizar&#x00e1; el estado con la base de
+                    datos cuando se complete la unidad de trabajo. Los desarrolladores no ejecutan
+                    sentencias <literal>UPDATE</literal> manuales, o sentencias <literal>DELETE</literal>
+                    cuando un objeto debe ser hecho transitorio.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Separado (detached)</emphasis> - una instancia separada es un objeto
+                    que ha sido hecho persistente, pero su <literal>Session</literal> ha sido cerrada.
+                    La referencia al objeto todav&#x00ed;a es v&#x00e1;lida, por supuesto, y la instancia separada
+                    podr&#x00ed;a incluso ser modificada en este estado. Una instancia separada puede ser
+                    re-unida a una nueva <literal>Session</literal> en un punto posterior en el tiempo,
+                    haci&#x00e9;ndola persistente de nuevo (con todas las modificaciones). Este aspecto
+                    habilita un modelo de programaci&#x00f3;n para unidades de trabajo de ejecuci&#x00f3;n larga
+                    que requieren tiempo-para-pensar del usuario. Las llamamos <emphasis>transaccciones
+                    de aplicaci&#x00f3;n</emphasis>, es decir, una unidad de trabajo desde el punto de vista
+                    del usuario.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Discutiremos ahora los estados y transiciones de estados (y los m&#x00e9;todos de Hibernate que
+            disparan una transici&#x00f3;n) en m&#x00e1;s detalle:
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-makingpersistent" revision="1">
+        <title>Haciendo los objetos persistentes</title>
+
+        <para>
+            Las instancias reci&#x00e9;n instanciadas de una clase persistente son consideradas
+            <emphasis>transitorias</emphasis> por Hibernate. Podemos hacer una instancia
+            transitoria <emphasis>persistente</emphasis> asoci&#x00e1;ndola con una sesi&#x00f3;n:
+        </para>
+
+        <programlisting><![CDATA[DomesticCat fritz = new DomesticCat();
+fritz.setColor(Color.GINGER);
+fritz.setSex('M');
+fritz.setName("Fritz");
+Long generatedId = (Long) sess.save(fritz);]]></programlisting>
+
+        <para>
+            Si <literal>Cat</literal> tiene un identificador generado, el identificador es
+            generado y asignado al <literal>cat</literal> cuando se llama a <literal>save()</literal>.
+            Si <literal>Cat</literal> tiene un identificador <literal>assigned</literal>,
+            o una clave compuesta, el identificador debe ser asignado a la instancia de
+            <literal>cat</literal> antes de llamar a <literal>save()</literal>. Puedes tambi&#x00e9;n
+            usar <literal>persist()</literal> en vez de <literal>save()</literal>, con la sem&#x00e1;ntica
+            definida en el temprano borrador de EJB3.
+        </para>
+        
+        <para>
+            Alternativamente, puedes asignar el identificador usando una versi&#x00f3;n sobrecargada
+            de <literal>save()</literal>.
+        </para>
+
+<programlisting><![CDATA[DomesticCat pk = new DomesticCat();
+pk.setColor(Color.TABBY);
+pk.setSex('F');
+pk.setName("PK");
+pk.setKittens( new HashSet() );
+pk.addKitten(fritz);
+sess.save( pk, new Long(1234) );]]></programlisting>
+        
+        <para>
+            Si el objeto que haces persistente tiene objetos asociados (por ejemplo,
+            la colecci&#x00f3;n <literal>kittens</literal> en el ejemplo anterior), estos
+            objetos pueden ser hechos persistentes en cualquier orden que quieras
+            a menos que tengas una restricci&#x00f3;n <literal>NOT NULL</literal> sobre una
+            columna clave for&#x00e1;nea. Nunca hay riesgo de violar restricciones de clave
+            for&#x00e1;nea. Sin embargo, podr&#x00ed;as violar una restricci&#x00f3;n <literal>NOT NULL</literal>
+            si llamas a <literal>save()</literal> sobre objetos en orden err&#x00f3;neo.
+        </para>
+        
+        <para>
+            Usualmente no te preocupas con este detalle, pues muy probablemente usar&#x00e1;s
+            la funcionalidad de <emphasis>persistencia transitiva</emphasis> de Hibernate
+            para salvar los objetos asociados autom&#x00e1;ticamente. Entonces, ni siquiera ocurren
+            violaciones de restricciones <literal>NOT NULL</literal> - Hibernate cuidar&#x00e1; de todo.
+            La persistencia transitiva se discute m&#x00e1;s adelante en este cap&#x00ed;tulo.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="objectstate-loading">
+        <title>Cargando un objeto</title>
+
+        <para>
+            Los m&#x00e9;todos <literal>load()</literal> de <literal>Session</literal> te brindan
+            una forma de traer una instancia persistente si ya saves su identificador.
+            <literal>load()</literal> toma un objeto clase y cargar&#x00e1; el estado dentro de
+            una instancia reci&#x00e9;n instanciada de esta clase, en estado persistente.
+        </para>
+
+        <programlisting><![CDATA[Cat fritz = (Cat) sess.load(Cat.class, generatedId);]]></programlisting>
+
+<programlisting><![CDATA[// you need to wrap primitive identifiers
+long id = 1234;
+DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id) );]]></programlisting>
+
+        <para>
+            Alternativamente, puedes cargar estado dentro de una instancia dada:
+        </para>
+
+<programlisting><![CDATA[Cat cat = new DomesticCat();
+// load pk's state into cat
+sess.load( cat, new Long(pkId) );
+Set kittens = cat.getKittens();]]></programlisting>
+
+        <para>
+            Nota que <literal>load()</literal> lanzar&#x00e1; una excepci&#x00f3;n irrecuperable si no
+            hay una fila correspondiente en base de datos. Si la clase es mapeada con un
+            proxy, <literal>load()</literal> s&#x00f3;lo devuelve un proxy no inicializado y no
+            llamar&#x00e1; realmente a la base de datos hasta que invoques un m&#x00e9;todo del proxy.
+            Este comportamiento es muy &#x00fa;til si deseas crear una asociaci&#x00f3;n a un objeto
+            sin cargarlo realmente de la base de datos. Permite adem&#x00e1;s que m&#x00fa;ltiples
+            instancias sean cargadas como un lote si se define <literal>batch-size</literal>
+            para el mapeo de la clase.
+        </para>
+        
+        <para>
+            Si no tienes certeza que exista una fila correspondiente, debes usar el
+            m&#x00e9;todo <literal>get()</literal>, que llama a la base de datos inmediatamente
+            y devuelve nulo si no existe una fila correspondiente.
+        </para>
+        
+        <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id);
+if (cat==null) {
+    cat = new Cat();
+    sess.save(cat, id);
+}
+return cat;]]></programlisting>
+
+        <para>
+            Puedes incluso cargar un objeto usando un <literal>SELECT ... FOR UPDATE</literal> de SQL,
+            usando un <literal>LockMode</literal>. Ver la documentaci&#x00f3;n de la API para m&#x00e1;s
+            informaci&#x00f3;n.
+        </para>
+
+        <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);]]></programlisting>
+        
+        <para>
+            Ten en cuenta que <emphasis>ninguna</emphasis> instancia asociada o colecci&#x00f3;n contenida es
+            selecciona <literal>FOR UPDATE</literal>, a menos que decidas especificar 
+            <literal>lock</literal> o <literal>all</literal> como un estilo de cascada para la
+            asociaci&#x00f3;n.
+        </para>
+        
+        <para>
+            Es posible volver a cargar un objeto y todas sus colecciones en cualquier momento,
+            usando el m&#x00e9;todo <literal>refresh()</literal>. Esto es &#x00fa;til cuando se usan disparadores de
+            base de datos para inicializar algunas de las propiedades del objeto.
+        </para>
+        
+        <programlisting><![CDATA[sess.save(cat);
+sess.flush(); //force the SQL INSERT
+sess.refresh(cat); //re-read the state (after the trigger executes)]]></programlisting>
+
+        <para>
+            Una cuesti&#x00f3;n importante aparece usualmente en este punto: ¿Cu&#x00e1;nto carga Hibernate de
+            la base de datos y cu&#x00e1;ntos <literal>SELECT</literal>s de SQL usar&#x00e1;? Esto depende de la
+            <emphasis>estrategia de recuperaci&#x00f3;n</emphasis> y se explica en <xref linkend="performance-fetching"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-querying" revision="1">
+        <title>Consultando</title>
+
+        <para>
+            Si no sabes los identificadores de los objetos que est&#x00e1;s buscando,
+            necesitas una consulta. Hibernate soporta un lenguaje de consulta
+            orientado a objetos (HQL) f&#x00e1;cil de usar pero potente. Para la creaci&#x00f3;n
+            de consultas program&#x00e1;ticas, Hibernate soporta una funcionalidad sofisticada
+            de consulta de Criteria y Example (QBC and QBE). Tambi&#x00e9;n puedes expresar tu
+            consulta en el SQL nativo de tu base de datos, con soporte opcional de Hibernate
+            para la conversi&#x00f3;n del conjunto resultado en objetos.
+        </para>
+
+        <sect2 id="objectstate-querying-executing">
+            <title>Ejecutando consultas</title>
+
+            <para>
+                Las consultas HQL y SQL nativas son representadas con una instancia de
+                <literal>org.hibernate.Query</literal>. Esta interface ofrece m&#x00e9;todos para
+                la ligaci&#x00f3;n de par&#x00e1;metros, manejo del conjunto resultado, y para la
+                ejecuci&#x00f3;n de la consulta real. Siempre obtienes una <literal>Query</literal>
+                usando la <literal>Session</literal> actual:
+            </para>
+
+        <programlisting><![CDATA[List cats = session.createQuery(
+    "from Cat as cat where cat.birthdate < ?")
+    .setDate(0, date)
+    .list();
+
+List mothers = session.createQuery(
+    "select mother from Cat as cat join cat.mother as mother where cat.name = ?")
+    .setString(0, name)
+    .list();
+
+List kittens = session.createQuery(
+    "from Cat as cat where cat.mother = ?")
+    .setEntity(0, pk)
+    .list();
+
+Cat mother = (Cat) session.createQuery(
+    "select cat.mother from Cat as cat where cat = ?")
+    .setEntity(0, izi)
+    .uniqueResult();]]></programlisting>
+
+            <para>
+                Una consulta se ejecuta usualmente invocando a <literal>list()</literal>,
+                el resultado de la consulta ser&#x00e1; cargado completamente dentro de una
+                colecci&#x00f3;n en memoria. Las instancias de entidad tra&#x00ed;das por una consulta
+                est&#x00e1;n en estado persistente. El m&#x00e9;todo <literal>uniqueResult()</literal>
+                ofrece un atajo si sabes que tu consulta devolver&#x00e1; s&#x00f3;lo un objeto.
+            </para>
+
+            <sect3 id="objectstate-querying-executing-iterate">
+                <title>Iterando los resultados</title>
+
+                <para>
+                    Ocasionalmente, podr&#x00ed;as ser capaz de lograr mejor rendimiento al ejecutar la consulta
+                    usando el m&#x00e9;todo <literal>iterate()</literal>. Esto s&#x00f3;lo ser&#x00e1; en el caso que esperes
+                    que las instancias reales de entidad devueltas por la consulta est&#x00e9;n ya en la sesi&#x00f3;n
+                    o cach&#x00e9; de segundo nivel. Si todav&#x00ed;a no est&#x00e1;n en cach&#x00e9;, <literal>iterate()</literal>
+                    ser&#x00e1; m&#x00e1;s lento que <literal>list()</literal> y podr&#x00ed;a requerir muchas llamadas a la
+                    base de datos para una consulta simple, usualmente <emphasis>1</emphasis> para la
+                    selecci&#x00f3;n inicial que solamente devuelve identificadores, y <emphasis>n</emphasis>
+                    selecciones adicionales para inicializar las instancias reales.
+                </para>
+
+                <programlisting><![CDATA[// fetch ids
+Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate();
+while ( iter.hasNext() ) {
+    Qux qux = (Qux) iter.next();  // fetch the object
+    // something we couldnt express in the query
+    if ( qux.calculateComplicatedAlgorithm() ) {
+        // delete the current instance
+        iter.remove();
+        // dont need to process the rest
+        break;
+    }
+}]]></programlisting>
+            </sect3>
+            
+            <sect3 id="objectstate-querying-executing-tuples">
+                <title>Consultas que devuelven tuplas</title>
+
+                <para>
+                    Las consultas de Hibernate a veces devuelven tuplas de objetos, en cuyo caso
+                    cada tupla se devuelve como un array:
+                </para>
+
+                <programlisting><![CDATA[Iterator kittensAndMothers = sess.createQuery(
+            "select kitten, mother from Cat kitten join kitten.mother mother")
+            .list()
+            .iterator();
+
+while ( kittensAndMothers.hasNext() ) {
+    Object[] tuple = (Object[]) kittensAndMothers.next();
+    Cat kitten  = tuple[0];
+    Cat mother  = tuple[1];
+    ....
+}]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-scalar">
+                <title>Resultados escalares</title>
+
+                <para>
+                    Las consultas pueden especificar una propiedad de una clase en la cl&#x00e1;usula
+                    <literal>select</literal>. Pueden incluso llamar a funciones de agregaci&#x00f3;n SQL.
+                    Las propiedades o agregaciones son considerados resultados "escalares"
+                    (y no entidades en estado persistente).
+                </para>
+
+                <programlisting><![CDATA[Iterator results = sess.createQuery(
+        "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
+        "group by cat.color")
+        .list()
+        .iterator();
+
+while ( results.hasNext() ) {
+    Object[] row = results.next();
+    Color type = (Color) row[0];
+    Date oldest = (Date) row[1];
+    Integer count = (Integer) row[2];
+    .....
+}]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-parameters">
+                <title>Ligaci&#x00f3;n de par&#x00e1;metros</title>
+
+                <para>
+                    Se proveen m&#x00e9;todos en <literal>Query</literal> para ligar valores a
+                    par&#x00e1;metros con nombre o par&#x00e1;metros <literal>?</literal> de estilo JDBC.
+                    <emphasis>Al contrario de JDBC, Hibernate numera los par&#x00e1;metros desde cero.</emphasis>
+                    Los par&#x00e1;metros con nombre son identificadores de la forma <literal>:name</literal>
+                    en la cadena de la consulta. Las ventajas de los par&#x00e1;metros con nombre son:
+                </para>
+
+                <itemizedlist spacing="compact">
+                    <listitem>
+                        <para>
+                            los par&#x00e1;metros con nombre son insensibles al orden en que aparecen
+                            en la cadena de consulta
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            pueden aparecer m&#x00fa;ltiples veces en la misma consulta
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            son auto-documentados
+                        </para>
+                    </listitem>
+                </itemizedlist>
+
+                <programlisting><![CDATA[//named parameter (preferred)
+Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
+q.setString("name", "Fritz");
+Iterator cats = q.iterate();]]></programlisting>
+
+                <programlisting><![CDATA[//positional parameter
+Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
+q.setString(0, "Izi");
+Iterator cats = q.iterate();]]></programlisting>
+
+                <programlisting><![CDATA[//named parameter list
+List names = new ArrayList();
+names.add("Izi");
+names.add("Fritz");
+Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)");
+q.setParameterList("namesList", names);
+List cats = q.list();]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-pagination">
+                <title>Paginaci&#x00f3;n</title>
+
+                <para>
+                    Si necesitas especificar l&#x00ed;mites sobre tu conjunto resultado (el n&#x00fa;mero m&#x00e1;ximo de filas
+                    que quieras traer y/o la primera fila que quieras traer) debes usar los m&#x00e9;todos de la
+                    interface <literal>Query</literal>:
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.createQuery("from DomesticCat cat");
+q.setFirstResult(20);
+q.setMaxResults(10);
+List cats = q.list();]]></programlisting>
+
+                <para>
+                    Hibernate sabe c&#x00f3;mo traducir este l&#x00ed;mite de consulta al SQL nativo de tu
+                    DBMS.
+                </para>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-scrolling">
+                <title>Iteraci&#x00f3;n scrollable</title>
+
+                <para>
+                    Si tu driver JDBC soporta <literal>ResultSet</literal>s scrollables, la
+                    interface <literal>Query</literal> puede ser usada para obtener un objeto
+                    <literal>ScrollableResults</literal>, que permite una navegaci&#x00f3;n flexible
+                    de los resultados de consulta.
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
+                            "order by cat.name");
+ScrollableResults cats = q.scroll();
+if ( cats.first() ) {
+
+    // find the first name on each page of an alphabetical list of cats by name
+    firstNamesOfPages = new ArrayList();
+    do {
+        String name = cats.getString(0);
+        firstNamesOfPages.add(name);
+    }
+    while ( cats.scroll(PAGE_SIZE) );
+
+    // Now get the first page of cats
+    pageOfCats = new ArrayList();
+    cats.beforeFirst();
+    int i=0;
+    while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) );
+
+}
+cats.close()]]></programlisting>
+
+                <para>
+                    Nota que se requiere una conexi&#x00f3;n de base de datos abierta (y cursor) para esta
+                    funcionalidad, usa <literal>setMaxResult()</literal>/<literal>setFirstResult()</literal>
+                    si necesitas la funcionalidad de paginaci&#x00f3;n fuera de l&#x00ed;nea.
+                </para>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-named">
+                <title>Externalizando consultas con nombre</title>
+
+                <para>
+                    Puedes adem&#x00e1;s definir consultas con nombre en el documento de mapeo.
+                    (Recuerda usar una secci&#x00f3;n <literal>CDATA</literal> si tu consulta
+                    contiene caracteres que puedan ser interpretados como etiquetado.)
+                </para>
+
+                <programlisting><![CDATA[<query name="eg.DomesticCat.by.name.and.minimum.weight"><![CDATA[
+    from eg.DomesticCat as cat
+        where cat.name = ?
+        and cat.weight > ?
+] ]></query>]]></programlisting>
+
+                <para>
+                    La ligaci&#x00f3;n de par&#x00e1;metros y ejecuci&#x00f3;n se hace program&#x00e1;ticamente:
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.getNamedQuery("eg.DomesticCat.by.name.and.minimum.weight");
+q.setString(0, name);
+q.setInt(1, minWeight);
+List cats = q.list();]]></programlisting>
+
+                <para>
+                    Nota que el c&#x00f3;digo real del programa es independiente del lenguaje de consulta
+                    usado; puedes adem&#x00e1;s definir consultas SQL nativas en metadatos, o migrar
+                    consultas existentes a Hibernate coloc&#x00e1;ndolas en ficheros de mapeo.
+                </para>
+
+            </sect3>
+
+        </sect2>
+
+        <sect2 id="objectstate-filtering" revision="1">
+            <title>Filtrando colecciones</title>
+            <para>
+                Un <emphasis>filtro</emphasis> de colecci&#x00f3;n es un tipo especial de consulta que puede ser
+                aplicado a una colecci&#x00f3;n persistente o array. La cadena de consulta puede referirse a
+                <literal>this</literal>, significando el elemento de colecci&#x00f3;n actual.
+            </para>
+
+            <programlisting><![CDATA[Collection blackKittens = session.createFilter(
+    pk.getKittens(), 
+    "where this.color = ?")
+    .setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) )
+    .list()
+);]]></programlisting>
+        
+            <para>
+                La colecci&#x00f3;n devuelta es considerada un bag, y es una copia de la colecci&#x00f3;n
+                dada. La colecci&#x00f3;n original no es modificada (esto es contrario a la implicaci&#x00f3;n
+                del nombre "filtro", pero consistente con el comportamiento esperado).
+            </para>
+
+            <para>
+                Observa que los filtros no requieren una cl&#x00e1;usula <literal>from</literal> (aunque pueden
+                tener uno si se requiere). Los filtros no est&#x00e1;n limitados a devolver los elementos de
+                colecci&#x00f3;n por s&#x00ed; mismos.
+            </para>
+
+            <programlisting><![CDATA[Collection blackKittenMates = session.createFilter(
+    pk.getKittens(), 
+    "select this.mate where this.color = eg.Color.BLACK.intValue")
+    .list();]]></programlisting>
+
+            <para>
+                Incluso una consulta de filtro vac&#x00ed;o es &#x00fa;til, por ejemplo, para cargar un
+                subconjunto de elementos en una colecci&#x00f3;n enorme:
+            </para>
+
+            <programlisting><![CDATA[Collection tenKittens = session.createFilter(
+    mother.getKittens(), "")
+    .setFirstResult(0).setMaxResults(10)
+    .list();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="objecstate-querying-criteria" revision="1">
+           <title>Consultas de criterios</title>
+
+            <para>
+                HQL es extremadamente potente pero algunos desarrolladores prefieren construir
+                consultas din&#x00e1;micamente usando una API orientada a objetos, en vez construir
+                cadenas de consulta. Hibernate provee una API intuitiva de consulta <literal>Criteria</literal>
+                para estos casos:
+            </para>
+
+            <programlisting><![CDATA[Criteria crit = session.createCriteria(Cat.class);
+crit.add( Expression.eq( "color", eg.Color.BLACK ) );
+crit.setMaxResults(10);
+List cats = crit.list();]]></programlisting>
+    
+            <para>
+                Las APIs de <literal>Criteria</literal> y la asociada <literal>Example</literal>
+                son discutidas en m&#x00e1;s detalle en <xref linkend="querycriteria"/>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="objectstate-querying-nativesql" revision="2">
+            <title>Consultas en SQL nativo</title>
+
+            <para>
+                Puedes expresar una consulta en SQL, usando <literal>createSQLQuery()</literal> y
+                dejando que Hibernate cuide del mapeo de los conjuntos resultado a objetos.
+                Nota que puedes llamar en cualquier momento a <literal>session.connection()</literal> y
+                usar la <literal>Connection</literal> JDBC directamente. Si eliges usar la API de
+                Hibernate, debes encerrar los alias de SQL entre llaves:
+            </para>
+
+            <programlisting><![CDATA[List cats = session.createSQLQuery(
+    "SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10",
+    "cat",
+    Cat.class
+).list();]]></programlisting>
+                
+            <programlisting><![CDATA[List cats = session.createSQLQuery(
+    "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
+           "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
+    "FROM CAT {cat} WHERE ROWNUM<10",
+    "cat",
+    Cat.class
+).list()]]></programlisting>
+
+            <para>
+                Las consultas SQL pueden contener par&#x00e1;metros con nombre y posicionales, al igual que
+                las consultas de Hibernate. Puede encontrarse m&#x00e1;s informaci&#x00f3;n sobre consultas en SQL
+                nativo en <xref linkend="querysql"/>.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="objectstate-modifying" revision="1">
+        <title>Modificando objetos persistentes</title>
+
+        <para>
+            Las <emphasis>instancias persistentes transaccionales</emphasis> (es decir, objetos cargados,
+            creados o consultados por la <literal>Session</literal>) pueden ser manipulados por la
+            aplicaci&#x00f3;n y cualquier cambio al estado persistente ser&#x00e1; persistido cuando la <literal>Session</literal>
+            sea <emphasis>limpiada (flushed)</emphasis> (discutido m&#x00e1;s adelante en este cap&#x00ed;tulo). No hay
+            necesidad de llamar un m&#x00e9;todo en particular (como <literal>update()</literal>, que tiene un
+            prop&#x00f3;sito diferente) para hacer persistentes tus modificaciones. De modo que la forma m&#x00e1;s
+            directa de actualizar el estado de un objeto es cargarlo con <literal>load()</literal>,
+            y entonces manipularlo directamente, mientras la <literal>Session</literal> est&#x00e1; abierta:
+        </para>
+
+        <programlisting><![CDATA[DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
+cat.setName("PK");
+sess.flush();  // changes to cat are automatically detected and persisted]]></programlisting>
+
+        <para>
+            A veces este modelo de programaci&#x00f3;n es ineficiente pues podr&#x00ed;a requerir una
+            <literal>SELECT</literal> de SQL (para cargar un objeto) y un <literal>UPDATE</literal>
+            de SQL (para hacer persistentes sus datos actualizados) en la misma sesi&#x00f3;n. Por lo tanto,
+            Hibernate ofrece un enfoque alternativo, usando instancias separadas (detached).
+        </para>
+
+        <para>
+            <emphasis>Nota que Hibernate no ofreve su propia API para ejecuci&#x00f3;n directa de
+            sentencias <literal>UPDATE</literal> o <literal>DELETE</literal>. Hibernate es un
+            servicio de <emphasis>gesti&#x00f3;n de estado</emphasis>, no tienes que pensar en
+            <literal>sentencias</literal> para usarlo. JDBC es una API perfecta para ejecutar
+            sentencias SQL; puedes obtener una <literal>Connection</literal> JDBC en cualquier
+            momento llamando a <literal>session.connection()</literal>. Adem&#x00e1;s, la noci&#x00f3;n de
+            operaciones masivas entra en conflicto con el mapeo objeto/relacional en aplicaciones
+            en l&#x00ed;nea orientadas al procesamiento de transacciones. Versiones futuras de Hibernate
+            pueden, sin embargo, proveer funciones de operaci&#x00f3;n masiva especiales. Ver
+            <xref linkend="batch"/> por algunos trucos de operaci&#x00f3;n en lote (batch) posibles.
+            </emphasis>
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-detached" revision="2">
+        <title>Modificando objetos separados</title>
+
+        <para>
+            Muchas aplicaciones necesitan recuperar un objeto en una transacci&#x00f3;n, enviarla
+            a la capa de UI para su manipulaci&#x00f3;n, y entonces salvar los cambios en una nueva
+            transacci&#x00f3;n. Las aplicaciones que usan este tipo de enfoque en un entorno de
+            alta concurrencia usualmente usan datos versionados para asegurar el aislamiento
+            de la unidad de trabajo "larga".
+        </para>
+
+        <para>
+            Hibernate soporta este modelo al proveer re-uni&#x00f3;n de instancias separadas usando
+            los m&#x00e9;todos <literal>Session.update()</literal> o <literal>Session.merge()</literal>:
+        </para>
+
+        <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catId);
+Cat potentialMate = new Cat();
+firstSession.save(potentialMate);
+
+// in a higher layer of the application
+cat.setMate(potentialMate);
+
+// later, in a new session
+secondSession.update(cat);  // update cat
+secondSession.update(mate); // update mate]]></programlisting>
+
+        <para>
+            Si el <literal>Cat</literal> con identificador <literal>catId</literal> ya hubiera
+            sido cargado por <literal>secondSession</literal> cuando la aplicaci&#x00f3;n intent&#x00f3;
+            volver a unirlo, se habr&#x00ed;a lanzado una excepci&#x00f3;n.
+        </para>
+
+        <para>
+            Usa <literal>update()</literal> si no est&#x00e1;s seguro que la sesi&#x00f3;n tenga
+            una instancia ya persistente con el mismo identificador, y <literal>merge()</literal>
+            si quieres fusionar tus modificaciones en cualquier momento sin consideraci&#x00f3;n del
+            estado de la sesi&#x00f3;n. En otras palabras, <literal>update()</literal> es usualmente
+            el primer m&#x00e9;todo que llamar&#x00ed;as en una sesi&#x00f3;n fresca, asegurando que la re-uni&#x00f3;n de
+            tus instancias separadas es la primera operaci&#x00f3;n que se ejecuta.
+        </para>
+
+        <para>
+            La aplicaci&#x00f3;n debe actualizar individualmente las instancias separadas alcanzables
+            por la instancia separada dada llamando a <literal>update()</literal>, si y
+            <emphasis>s&#x00f3;lo</emphasis> si quiere que sus estados sean tambi&#x00e9;n actualizados.
+            Esto puede, por supuesto, ser automatizado usando <emphasis>persistencia transitiva</emphasis>,
+            ver <xref linkend="objectstate-transitive"/>.
+        </para>
+
+        <para>
+            El m&#x00e9;todo <literal>lock()</literal> tambi&#x00e9;n permite a una aplicaci&#x00f3;n reasociar
+            un objeto con una sesi&#x00f3;n nueva. Sin embargo, la instancia separada no puede
+            haber sido modificada!
+        </para>
+
+        <programlisting><![CDATA[//just reassociate:
+sess.lock(fritz, LockMode.NONE);
+//do a version check, then reassociate:
+sess.lock(izi, LockMode.READ);
+//do a version check, using SELECT ... FOR UPDATE, then reassociate:
+sess.lock(pk, LockMode.UPGRADE);]]></programlisting>
+
+        <para>
+            Nota que <literal>lock()</literal> puede ser usado con varios <literal>LockMode</literal>s,
+            ver la documentaci&#x00f3;n de la API y el cap&#x00ed;tulo sobre manejo de transacciones para m&#x00e1;s
+            informaci&#x00f3;n. La re-uni&#x00f3;n no es el &#x00fa;nico caso de uso para <literal>lock()</literal>.
+        </para>
+
+        <para>
+            Se discuten otros modelos para unidades de trabajo largas en <xref linkend="transactions-optimistic"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-saveorupdate">
+        <title>Detecci&#x00f3;n autom&#x00e1;tica de estado</title>
+
+        <para>
+            Los usuarios de Hibernate han pedido un m&#x00e9;todo de prop&#x00f3;sito general que bien
+            salve una instancia transitoria generando un identificador nuevo, o bien
+            actualice/re&#x00fa;na las instancias separadas asociadas con su identificador actual.
+            El m&#x00e9;todo <literal>saveOrUpdate()</literal> implementa esta funcionalidad.
+        </para>
+
+        <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catID);
+
+// in a higher tier of the application
+Cat mate = new Cat();
+cat.setMate(mate);
+
+// later, in a new session
+secondSession.saveOrUpdate(cat);   // update existing state (cat has a non-null id)
+secondSession.saveOrUpdate(mate);  // save the new instance (mate has a null id)]]></programlisting>
+
+        <para>
+            El uso y sem&#x00e1;ntica de <literal>saveOrUpdate()</literal> parece ser confuso para
+            usuarios nuevos. Primeramente, en tanto no est&#x00e9;s intentando usar instancias de una
+            sesi&#x00f3;n en otra sesi&#x00f3;n nueva, no debes necesitar usar <literal>update()</literal>,
+            <literal>saveOrUpdate()</literal>, o <literal>merge()</literal>. Algunas aplicaciones
+            enteras nunca usar&#x00e1;n ninguno de estos m&#x00e9;todos.
+        </para>
+
+        <para>
+            Usualmente <literal>update()</literal> o <literal>saveOrUpdate()</literal> se usan en
+            el siguiente escenario:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    la aplicaci&#x00f3;n carga un objeto en la primera sesi&#x00f3;n
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    el objeto es pasado a la capa de UI
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    se hacen algunas modificaciones al objeto
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    el objeto se pasa abajo de regreso a la capa de negocio
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    la aplicaci&#x00f3;n hace estas modificaciones persistentes llamando
+                    a <literal>update()</literal> en una segunda sesi&#x00f3;n
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>saveOrUpdate()</literal> hace lo siguiente:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    si el objeto ya es persistente en esta sesi&#x00f3;n, no hace nada
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    si otro objeto asociado con la sesi&#x00f3;n tiene el mismo identificador,
+                    lanza una excepci&#x00f3;n
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    si el objeto no tiene ninguna propiedad identificadora, lo salva llamando a
+                    <literal>save()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    si el identificador del objeto tiene el valor asignado a un objeto reci&#x00e9;n
+                    instanciado, lo salva llamando a <literal>save()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    si el objeto est&#x00e1; versionado (por un <literal>&lt;version&gt;</literal> o
+                    <literal>&lt;timestamp&gt;</literal>), y el valor de la propiedad de versi&#x00f3;n
+                    es el mismo valor asignado a una objeto reci&#x00e9;n instanciado, lo salva llamando
+                    a <literal>save()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    en cualquier otro caso se actualiza el objeto llamando a <literal>update()</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            y <literal>merge()</literal> es muy diferente:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    si existe una instancia persistente con el mismo identificador asignado actualmente con la
+                    sesi&#x00f3;n, copia el estado del objeto dado en la instancia persistente
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    si no existe ninguna instancia persistente actualmente asociada a la sesi&#x00f3;n,
+                    intente cargarla de la base de datos, o crear una nueva instancia persistente
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    la instancia persistente es devuelta
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    la instancia dada no resulta ser asociada a la sesi&#x00f3;n, permanece separada
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect1>
+
+    <sect1 id="objectstate-deleting" revision="1">
+        <title>Borrando objetos persistentes</title>
+
+        <para>
+            <literal>Session.delete()</literal> quitar&#x00e1; el estado de un objeto de la base de datos.
+            Por supuesto, tu aplicaci&#x00f3;n podr&#x00ed;a tener a&#x00fa;n una referencia a un objeto borrado. Lo mejor
+            es pensar en <literal>delete()</literal> como hacer transitoria una instancia persistente.
+        </para>
+
+        <programlisting><![CDATA[sess.delete(cat);]]></programlisting>
+
+        <para>
+            Puedes borrar los objetos en el orden que gustes, sin riesgo de violaciones
+            de restricci&#x00f3;n de clave for&#x00e1;nea. A&#x00fa;n es posible violar una restricci&#x00f3;n
+            <literal>NOT NULL</literal> sobre una columna clave for&#x00e1;nea borrando objetos
+            en un orden err&#x00f3;neo, por ejemplo, si borras el padre, pero olvidas borrar los
+            hijos.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="objectstate-replicating" revision="1">
+    	<title>Replicando objetos entre dos almac&#x00e9;nes de datos diferentes</title>
+    	
+    	<para>
+            Es ocasionalmente &#x00fa;til ser capaz de tomar un grafo de instancias persistentes
+            y hacerlas persistentes en un almac&#x00e9;n de datos diferente, sin regenerar los valores
+            identificadores.
+    	</para>
+    	
+        <programlisting><![CDATA[//retrieve a cat from one database
+Session session1 = factory1.openSession();
+Transaction tx1 = session1.beginTransaction();
+Cat cat = session1.get(Cat.class, catId);
+tx1.commit();
+session1.close();
+
+//reconcile with a second database
+Session session2 = factory2.openSession();
+Transaction tx2 = session2.beginTransaction();
+session2.replicate(cat, ReplicationMode.LATEST_VERSION);
+tx2.commit();
+session2.close();]]></programlisting>
+
+        <para>
+            El <literal>ReplicationMode</literal> determina c&#x00f3;mo <literal>replicate()</literal>
+            tratar&#x00e1; los conflictos con filas existentes en la base de datos.
+        </para>
+        
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.IGNORE</literal> - ignora el objeto cuando existe una fila
+                    de base de datos con el mismo identificador
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.OVERWRITE</literal> - sobrescribe cualquier fila de base de
+                    datos existente con el mismo identificador
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.EXCEPTION</literal> - lanza una excepci&#x00f3;n si existe una fila
+                    de base de datos con el mismo identificador
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.LATEST_VERSION</literal> - sobrescribe la fila si su n&#x00fa;mero
+                    de versi&#x00f3;n es anterior al n&#x00fa;mero de versi&#x00f3;n del objeto, o en caso contrario ignora el objeto
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Los casos de uso para esta funcionalidad incluyen reconciliar datos ingresados en
+            instancias diferentes de bases de datos, actualizar informaci&#x00f3;n de configuraci&#x00f3;n de
+            sistema durante actualizaciones de producto, deshacer cambios producidos durante
+            transacciones no-ACID y m&#x00e1;s.
+        </para>
+    	
+    </sect1>
+
+    <sect1 id="objectstate-flushing">
+        <title>Limpiando (flushing) la sesi&#x00f3;n</title>
+
+        <para>
+            Cada tanto, la <literal>Session</literal> ejecutar&#x00e1; las sentencias SQL necesarias para
+            sincronizar el estado de la conexi&#x00f3;n JDBC con el estado de los objetos mantenidos en menoria.
+            Este proceso, <emphasis>limpieza (flush)</emphasis>, ocurre por defecto en los siguientes
+            puntos
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    antes de algunas ejecuciones de consulta
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    desde <literal>org.hibernate.Transaction.commit()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    desde <literal>Session.flush()</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Las sentencias SQL son liberadas en el siguiente orden
+        </para>
+
+        <orderedlist spacing="compact">
+            <listitem>
+                <para>
+                    todas las inserciones de entidades, en el mismo orden que los objetos
+                    correspondientes fueron salvados usando <literal>Session.save()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    todas las actualizaciones de entidades
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    todas los borrados de colecciones
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    todos los borrados, actualizaciones e inserciones de elementos de colecci&#x00f3;n
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    todas las inserciones de colecciones
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    todos los borrados de entidades, en el mismo orden que los objetos
+                    correspondientes fueron borrados usando <literal>Session.delete()</literal>
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <para>
+            (Una excepci&#x00f3;n es que los objetos que usan generaci&#x00f3;n de ID <literal>native</literal>
+            se insertan cuando son salvados.)
+        </para>
+
+        <para>
+            Excepto cuando llamas expl&#x00ed;citamente a <literal>flush()</literal>, no hay en absoluto
+            garant&#x00ed;as sobre <emphasis>cu&#x00e1;ndo</emphasis> la <literal>Session</literal> ejecuta las
+            llamadas JDBC. s&#x00f3;lo sobre el <emphasis>orden</emphasis> en que son ejecutadas. Sin embargo,
+            Hibernate garantiza que los m&#x00e9;todos <literal>Query.list(..)</literal> nunca devolver&#x00e1;n datos
+            a&#x00f1;ejos o err&#x00f3;neos.
+        </para>
+
+        <para>
+            Es posible cambiar el comportamiento por defecto de modo que la limpieza (flush)
+            ocurra menos frecuentemente. La clase <literal>FlushMode</literal> tres modos
+            diferentes: s&#x00f3;lo en tiempo de compromiso (y s&#x00f3;lo cuando se use la API de
+            <literal>Transaction</literal> de Hibernate), limpieza autom&#x00e1;tica usando la rutina
+            explicada, o nunca limpiar a menos que se llame a <literal>flush()</literal>
+            expl&#x00ed;citamente. El &#x00fa;ltimo modo es &#x00fa;til para unidades de trabajo largas, donde una
+            <literal>Session</literal> se mantiene abierta y desconectada por largo tiempo
+            (ver <xref linkend="transactions-optimistic-longsession"/>).
+        </para>
+
+        <programlisting><![CDATA[sess = sf.openSession();
+Transaction tx = sess.beginTransaction();
+sess.setFlushMode(FlushMode.COMMIT); // allow queries to return stale state
+
+Cat izi = (Cat) sess.load(Cat.class, id);
+izi.setName(iznizi);
+
+// might return stale data
+sess.find("from Cat as cat left outer join cat.kittens kitten");
+
+// change to izi is not flushed!
+...
+tx.commit(); // flush occurs]]></programlisting>
+
+        <para>
+            Durante la limpieza, puede ocurrir una excepci&#x00f3;n (por ejemplo, si una operaci&#x00f3;n DML
+            violase una restricci&#x00f3;n). Ya que el manejo de excepciones implica alguna comprensi&#x00f3;n
+            del comportamiento transaccional de Hibernate, lo discutimos en <xref linkend="transactions"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-transitive">
+        <title>Persistencia transitiva</title>
+
+        <para>
+            Es absolutamente inc&#x00f3;modo dalvar, borrar, o reunir objetos individuales,
+            especialmente si tratas con un grafo de objetos asociados. Un caso com&#x00fa;n es
+            una relaci&#x00f3;n padre/hijo. Considera el siguiente ejemplo:
+        </para>
+
+        <para>
+            Si los hijos en una relaci&#x00f3;n padre/hijo pudieran ser tipificados en valor
+            (por ejemplo, una colecci&#x00f3;n de direcciones o cadenas), sus ciclos de vida
+            depender&#x00ed;an del padre y se requerir&#x00ed;a ninguna otra acci&#x00f3;n para el tratamiento
+            en "cascada" de cambios de estado. Cuando el padre es salvado, los objetos hijo
+            tipificados en valor son salvados tambi&#x00e9;n, cuando se borra el padre, se borran
+            los hijos, etc. Esto funciona incluso para operaciones como el retiro de un
+            hijo de la colecci&#x00f3;n. Hibernate detectar&#x00e1; esto y, ya que los objetos tipificados
+            en valor no pueden tener referencias compartidas, borrar&#x00e1; el hijo de la base
+            de datos.
+        </para>
+
+        <para>
+            Ahora considera el mismo escenario con los objetos padre e hijos siendo entidades,
+            no tipos de valor (por ejemplo, categor&#x00ed;as e &#x00ed;tems, o gatos padre e hijos).
+            Las entidades tienen su propio ciclo de vida, soportan referencias compartidas
+            (de modo que quitar una entidad de una colecci&#x00f3;n no significa que sea borrada),
+            y no hay por defecto ning&#x00fa;n tratamiento en "cascada" de estado de una entidad
+            a otras entidades asociadas. Hibernate no implementa <emphasis>persistencia por
+            alcance</emphasis>.
+        </para>
+
+        <para>
+            Para cada operaci&#x00f3;n b&#x00e1;sica de la sesi&#x00f3;n de Hibernate - incluyendo <literal>persist(), merge(),
+            saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate()</literal> - hay un estilo
+            de cascada correspondiente. Respectivamente, los estilos de cascada se llaman <literal>create, 
+            merge, save-update, delete, lock, refresh, evict, replicate</literal>. Si quieres que una
+            operaci&#x00f3;n sea tratada en cascada a lo largo de una asociaci&#x00f3;n, debes indicar eso en el
+            documento de mapeo. Por ejemplo:
+        </para>
+        
+        <programlisting><![CDATA[<one-to-one name="person" cascade="persist"/>]]></programlisting>
+        
+        <para>
+            Los estilos de cascada pueden combinarse:
+        </para>
+        
+        <programlisting><![CDATA[<one-to-one name="person" cascade="persist,delete,lock"/>]]></programlisting>
+        
+        <para>
+            Puedes incluso usar <literal>cascade="all"</literal> para especificar que <emphasis>todas</emphasis>
+            las operaciones deben ser tratadas en cascada a lo largo de la asociaci&#x00f3;n. El por defecto
+            <literal>cascade="none"</literal> especifica que ninguna operaci&#x00f3;n ser&#x00e1; tratada en cascada.
+        </para>
+        
+        <para>
+            Un estilo de cascada especial, <literal>delete-orphan</literal>, se aplica s&#x00f3;lo a
+            asociaciones uno-a-muchos, e indica que la operaci&#x00f3;n <literal>delete()</literal> debe
+            aplicarse a cualquier objeto hijo que sea quitado de la asociaci&#x00f3;n.
+        </para>
+
+
+        <para>
+            Recomendaciones:
+        </para>
+
+       <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Usualmente no tiene sentido habilitar el tratamiento en cascada a una asociaci&#x00f3;n
+                    <literal>&lt;many-to-one&gt;</literal> o <literal>&lt;many-to-many&gt;</literal>.
+                    El tratamiento en cascada es frecuentemente &#x00fa;til para las asociaciones
+                    <literal>&lt;one-to-one&gt;</literal> y <literal>&lt;one-to-many&gt;</literal>.
+                    associations.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Si la esperanza de vida de los objetos hijos est&#x00e1; ligada a la eesperanza de
+                    vida del objeto padre, h&#x00e1;zlo un <emphasis>objeto de ciclo de vida</emphasis>
+                    especificando <literal>cascade="all,delete-orphan"</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    En otro caso, puede que no necesites tratamiento en cascada en absoluto. Pero
+                    si piensas que estar&#x00e1;s trabajando frecuentemente con padre e hijos juntos en la
+                    misma transacci&#x00f3;n, y quieres ahorrarte algo de tipeo, considera usar
+                    <literal>cascade="persist,merge,save-update"</literal>.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Mapear una asociaci&#x00f3;n (ya sea una asociaci&#x00f3;n monovaluada, o una colecci&#x00f3;n) con
+            <literal>cascade="all"</literal> marca la asociaci&#x00f3;n como una relaci&#x00f3;n del estilo
+            <emphasis>padre/hijo</emphasis> donde save/update/delete en el padre resulta
+            en save/update/delete del hijo o hijos.
+        </para>
+        <para>
+            Adem&#x00e1;s, una mera referencia a un hijo desde un padre persistente resultar&#x00e1; en
+            un save/update del hijo. Esta met&#x00e1;fora est&#x00e1; incompleta, sin embargo. Un hijo
+            que deje de ser referenciado por su padre <emphasis>no</emphasis> es borrado
+            autom&#x00e1;ticamente, excepto en el caso de una asociaci&#x00f3;n <literal>&lt;one-to-many&gt;</literal>
+            mapeada con <literal>cascade="delete-orphan"</literal>. La sem&#x00e1;ntica precisa de
+            las operaciones en cascada para una relaci&#x00f3;n padre/hijo es:
+        </para>
+
+       <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Si un padre le es pasado a <literal>persist()</literal>, todos los hijos le son
+                    pasados a <literal>persist()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Si un padre le es pasado a <literal>merge()</literal>, todos los hijos le son
+                    pasados a <literal>merge()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Si un padre le es pasado a <literal>save()</literal>, <literal>update()</literal> o
+                    <literal>saveOrUpdate()</literal>, todos los hijos le son pasados a <literal>saveOrUpdate()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Si un hijo transitorio o separado se vuelve referenciado por un padre
+                    persistente, le es pasado a <literal>saveOrUpdate()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Si un padre es borrado, todos los hijos le son pasados a <literal>delete()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Si un hijo deja de ser referenciado por un padre persistente,
+                    <emphasis>no ocurre nada especial</emphasis> - la aplicaci&#x00f3;n debe
+                    borrar expl&#x00ed;citamente el hijo de ser necesario - a menos que
+                    <literal>cascade="delete-orphan"</literal>, en cuyo caso el hijo
+                    "hu&#x00e9;rfano" es borrado.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect1>
+
+    <sect1 id="objectstate-metadata">
+        <title>Usando metadatos</title>
+
+        <para>
+            Hibernate requiere de un modelo de meta-nivel muy rico de todas las entidades y tipos de valor.
+            De vez en cuando, este modelo es muy &#x00fa;til para la aplicaci&#x00f3;n misma. Por ejemplo, la aplicaci&#x00f3;n
+            podr&#x00ed;a usar los metadatos de Hibernate para implementar un algoritmo "inteligente" de copia
+            en profundidad que entienda qu&#x00e9; objetos deben ser copiados (por ejemplo, tipo de valor mutables)
+            y cu&#x00e1;les no (por ejemplo, tipos de valor inmutables y, posiblemente, entidades asociadas).
+        </para>
+        <para>
+            Hibernate expone los metadatos v&#x00ed;a las interfaces <literal>ClassMetadata</literal> y
+            <literal>CollectionMetadata</literal> y la jerarqu&#x00ed;a <literal>Type</literal>. Las instancias
+            de las interfaces de metadatos pueden obtenerse de <literal>SessionFactory</literal>. 
+        </para>
+
+        <programlisting><![CDATA[Cat fritz = ......;
+ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class);
+
+Object[] propertyValues = catMeta.getPropertyValues(fritz);
+String[] propertyNames = catMeta.getPropertyNames();
+Type[] propertyTypes = catMeta.getPropertyTypes();
+
+// get a Map of all properties which are not collections or associations
+Map namedValues = new HashMap();
+for ( int i=0; i<propertyNames.length; i++ ) {
+    if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType() ) {
+        namedValues.put( propertyNames[i], propertyValues[i] );
+    }
+}]]></programlisting>
+        
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/toolset_guide.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/toolset_guide.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/toolset_guide.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,459 @@
+<chapter id="toolsetguide" revision="2">
+    <title>Gu&#x00ed;a del Conjunto de Herramientas</title>
+
+    <para>
+        La ingenier&#x00ed;a de ida y vuelta con Hibernate es posible usando un conjunto de plugins de Eclipse,
+        herramientas de l&#x00ed;nea de comandos, as&#x00ed; como tareas de Ant.
+    </para>
+
+    <para>
+        Las <emphasis>Herramientas de Hibernate</emphasis> actualmente incluyen plugins para la IDE de
+        Eclipse as&#x00ed; como tareas de Ant para la ingenier&#x00ed;a inversa de bases de datos existentes:
+    </para>
+
+    <itemizedlist>
+        <listitem><para>
+            <emphasis>Editor de Mapeo:</emphasis> Un editor de ficheros de mapeo XML, que soporta autocompleci&#x00f3;n
+            y resaltado de sint&#x00e1;xis. Soporta tambi&#x00e9;n autocompleci&#x00f3;n sem&#x00e1;ntica de nombres de clases y nombres de
+            campos/propiedades, haci&#x00e9;ndolo mucho m&#x00e1;s vers&#x00e1;til que un editor de XML normal.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Consola:</emphasis> La consola es una nueva vista en Eclipse. Adem&#x00e1;s de la vista de
+            &#x00e1;rbol de tus configuraciones de consola, tienes tambi&#x00e9;n una vista interactiva de tus clases
+            persistentes y sus relaciones. La console te permite ejecutar consultas HQL contra tu base de datos y
+            navegar el resultado directamente en Eclipse.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Asistentes de Desarrollo:</emphasis> Se proveen muchos asistentes con las herramientas
+            de Eclipse. Puedes usar un asistente para generar r&#x00e1;pidamente ficheros de configuraci&#x00f3;n de Hibernate
+            (cfg.xml), o incluso puedes haceruna ingenier&#x00ed;a inversa completa de un esquema de base de datos existente
+            en ficheros de c&#x00f3;digo de POJO y ficheros de mapeo de Hibernate. El asistente de ingenier&#x00ed;a inversa soporta
+            plantillas personalizables.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Tareas de Ant:</emphasis>
+        </para></listitem>
+
+    </itemizedlist>
+
+    <para>
+        Por favor refi&#x00e9;rete al paquete <emphasis>Herramientas de Hibernate</emphasis> y su documentaci&#x00f3;n para
+        m&#x00e1;s informaci&#x00f3;n.
+    </para>
+
+    <para>
+        Sin embargo, el paquete principal de Hibernate viene incluyendo una herramienta integrada
+        (puede ser usada incluso "dentro" de Hibernate on-the-fly): <emphasis>SchemaExport</emphasis>
+        tambi&#x00e9;n conocido como <literal>hbm2ddl</literal>.
+    </para>
+
+    <sect1 id="toolsetguide-s1" revision="2">
+        <title>Generaci&#x00f3;n autom&#x00e1;tica de esquemas</title>
+
+        <para>
+            Una utilidad de Hibernate puede generar DDL desde tus ficheros de mapeo. El esquema generado incluye
+            restricciones de integridad referencial (claves primarias y for&#x00e1;neas) para las tablas de entidades y
+            colecciones. Las tablas y secuencias tambi&#x00e9;n son creadas para los generadores de identificadores mapeados.
+        </para>
+        
+        <para>
+            <emphasis>Debes</emphasis> especificar un <literal>Dialecto</literal> SQL v&#x00ed;a la propiedad
+            <literal>hibernate.dialect</literal> al usar esta herramienta, ya que el DDL es altamente espec&#x00ed;fico del
+            vendedor.
+        </para>
+
+        <para>
+            First, customize your mapping files to improve the generated schema.
+        </para>
+
+        <sect2 id="toolsetguide-s1-2" revision="1">
+            <title>Personalizando el esquema</title>
+
+            <para>
+                Muchos elementos de mapeo de Hibernate definen un atributo opcional llamado <literal>length</literal>.
+                Con este atributo puedes establecer el tama&#x00f1;o de una columna. (O, para tipos de datos
+                num&#x00e9;ricos/decimales, la precisi&#x00f3;n.)
+            </para>
+
+            <para>
+                Algunas etiquetas tambi&#x00e9;n aceptan un atributo <literal>not-null</literal> (para generar una restricci&#x00f3;n
+                <literal>NOT NULL</literal> en columnas de tablas) y y un atributo <literal>unique</literal> (para generar
+                restricciones <literal>UNIQUE</literal> en columnas de tablas).
+            </para>
+
+            <para>
+                Algunas etiquetas aceptan un atributo <literal>index</literal> para especificar el nombre de un &#x00ed;ndice
+                para esa columna. Se puede usar un atributo <literal>unique-key</literal> para agrupar columnas en una
+                restricci&#x00f3;n de clave de una sola unidad. Actualmente, el valor especificado del atributo
+                <literal>unique-key</literal> <emphasis>no</emphasis> es usado para nombrar la restricci&#x00f3;n, s&#x00f3;lo para
+                agrupar las columnas en el fichero de mapeo.
+            </para>
+            
+            <para>
+                Ejemplos:
+            </para>
+
+            <programlisting><![CDATA[<property name="foo" type="string" length="64" not-null="true"/>
+
+<many-to-one name="bar" foreign-key="fk_foo_bar" not-null="true"/>
+
+<element column="serial_number" type="long" not-null="true" unique="true"/>]]></programlisting>
+
+            <para>
+                Alternativamente, estos elementos aceptan tamb&#x00ed;en un elemento hijo <literal>&lt;column&gt;</literal>.
+                Esto es particularmente &#x00fa;til para tipos multicolumnas:
+            </para>
+
+            <programlisting><![CDATA[<property name="foo" type="string">
+    <column name="foo" length="64" not-null="true" sql-type="text"/>
+</property>]]></programlisting>
+
+            <programlisting><![CDATA[<property name="bar" type="my.customtypes.MultiColumnType"/>
+    <column name="fee" not-null="true" index="bar_idx"/>
+    <column name="fi" not-null="true" index="bar_idx"/>
+    <column name="fo" not-null="true" index="bar_idx"/>
+</property>]]></programlisting>
+
+            <para>
+                El atributo <literal>sql-type</literal> permite al usuario sobrescribir el mapeo por defecto de
+                tipo Hibernate a tipo de datos SQL.
+            </para>
+            
+            <para>
+                El atributo <literal>check</literal> te permite especificar una comprobaci&#x00f3;n de restricci&#x00f3;n.
+            </para>
+            
+            <programlisting><![CDATA[<property name="foo" type="integer">
+    <column name="foo" check="foo > 10"/>
+</property>]]></programlisting>
+
+            <programlisting><![CDATA[<class name="Foo" table="foos" check="bar < 100.0">
+    ...
+    <property name="bar" type="float"/>
+</class>]]></programlisting>
+            
+
+            <table frame="topbot" id="schemattributes-summary" revision="2">
+                <title>Resumen</title>
+                <tgroup cols="3">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>Atributo</entry>
+                            <entry>Valores</entry>
+                            <entry>Interpretaci&#x00f3;n</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>length</literal></entry>
+                            <entry>number</entry>
+                            <entry>largo de columna/precisi&#x00f3;n decimal</entry>
+                        </row>
+                        <row>
+                            <entry><literal>not-null</literal></entry>
+                            <entry><literal>true|false</literal></entry>
+                            <entry>especifica que la columna debe ser no nulable</entry>
+                        </row>
+                        <row>
+                            <entry><literal>unique</literal></entry>
+                            <entry><literal>true|false</literal></entry>
+                            <entry>especifica que la columna debe tener una restricci&#x00f3;n de unicidad</entry>
+                        </row>
+                        <row>
+                            <entry><literal>index</literal></entry>
+                            <entry><literal>index_name</literal></entry>
+                            <entry>especifica el nombre de un &#x00ed;ndice (multicolumna)</entry>
+                        </row>
+                        <row>
+                            <entry><literal>unique-key</literal></entry>
+                            <entry><literal>unique_key_name</literal></entry>
+                            <entry>especifica el nombre de una restricci&#x00f3;n de unicidad multicolumna</entry>
+                        </row>
+                        <row>
+                            <entry><literal>foreign-key</literal></entry>
+                            <entry><literal>foreign_key_name</literal></entry>
+                            <entry>
+                                especifica el nombre de la restricci&#x00f3;n de clave for&#x00e1;nea generada por una
+                                asociaci&#x00f3;n, &#x00fa;salo en los elementos de mapeo &lt;one-to-one&gt;, &lt;many-to-one&gt;,
+                                &lt;key&gt;, y &lt;many-to-many&gt;. Nota que los lados
+                                <literal>inverse="true"</literal> no ser&#x00e1;n considerados por
+                                <literal>SchemaExport</literal>.
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>sql-type</literal></entry>
+                            <entry><literal>column_type</literal></entry>
+                            <entry>
+                                sobrescribe el tipo de columna por defecto (s&#x00f3;lo atributo del elemento
+                                <literal>&lt;column&gt;</literal>)
+                            </entry>
+                       </row>
+                       <row>
+                            <entry><literal>check</literal></entry>
+                            <entry>expresi&#x00f3;n SQL</entry>
+                            <entry>
+                                crea una restricci&#x00f3;n de comprobaci&#x00f3;n SQL en columna o  tabla
+                            </entry>
+                       </row>
+                   </tbody>
+                </tgroup>
+            </table>
+            
+            <para>
+                El elemento <literal>&lt;comment&gt;</literal> te permite especificar un comentario para el esquema
+                generado.
+            </para>
+            
+            <programlisting><![CDATA[<class name="Customer" table="CurCust">
+    <comment>Current customers only</comment>
+    ...
+</class>]]></programlisting>
+
+            <programlisting><![CDATA[<property name="balance">
+    <column name="bal">
+        <comment>Balance in USD</comment>
+    </column>
+</property>]]></programlisting>
+            
+            <para>
+                Esto resulta en una sentencia <literal>comment on table</literal> o <literal>comment on column</literal>
+                en el DDL generado (donde est&#x00e9; soportado).
+            </para>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-3">
+            <title>Ejecutando la herramienta</title>
+
+            <para>
+                La herramienta <literal>SchemaExport</literal> escribe un gui&#x00f3;n DDL a la salida est&#x00e1;ndar y/o
+                ejecuta las sentencias DDL.
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>classpaths_de_hibernate</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaExport</literal> <emphasis>opciones ficheros_de_mapeo</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title>Opciones de L&#x00ed;nea de Comandos de <literal>SchemaExport</literal></title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Opci&#x00f3;n</entry>
+                            <entry>Descripci&#x00f3;n</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--quiet</literal></entry>
+                            <entry>no enviar a salida est&#x00e1;ndar el gui&#x00f3;n</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--drop</literal></entry>
+                            <entry>s&#x00f3;lo desechar las tablas</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--text</literal></entry>
+                            <entry>no exportar a la base de datos</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--output=my_schema.ddl</literal></entry>
+                            <entry>enviar la salida del gui&#x00f3;n ddl a un fichero</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry>lee la configuraci&#x00f3;n de Hibernate de un fichero XML</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>lee las propiedades de base de datos de un fichero</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--format</literal></entry>
+                            <entry>formatea agradablemente el SQL generado en el gui&#x00f3;n</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--delimiter=x</literal></entry>
+                            <entry>establece un delimitador de fin de l&#x00ed;nea para el gui&#x00f3;n</entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                Puedes incluso encajar <literal>SchemaExport</literal> en tu aplicaci&#x00f3;n:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaExport(cfg).create(false, true);]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-4">
+            <title>Propiedades</title>
+
+            <para>
+                Las propiedades de base de datos pueden especificarse
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>como propiedades de sistema con <literal>-D</literal><emphasis>&lt;property&gt;</emphasis></para>
+                </listitem>
+                <listitem>
+                    <para>en <literal>hibernate.properties</literal></para>
+                </listitem>
+                <listitem>
+                    <para>en un fichero de propiedades mencionado con <literal>--properties</literal></para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Las propiedades necesarias son:
+            </para>
+
+            <table frame="topbot">
+                <title>Propiedades de Conexi&#x00f3;n de SchemaExport</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Nombre de Propiedad</entry>
+                            <entry>Descripci&#x00f3;n</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                    <row>
+                        <entry><literal>hibernate.connection.driver_class</literal></entry>
+                        <entry>clase del driver jdbc</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.url</literal></entry>
+                        <entry>url de jdbc</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.username</literal></entry>
+                        <entry>usuario de base de datos</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.password</literal></entry>
+                        <entry>contrase&#x00f1;a de usuario</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.dialect</literal></entry>
+                        <entry>dialecto</entry>
+                    </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-5">
+            <title>Usando Ant</title>
+
+            <para>
+                Puedes llamar a <literal>SchemaExport</literal> desde tu gui&#x00f3;n de construcci&#x00f3;n de Ant:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemaexport">
+    <taskdef name="schemaexport"
+        classname="org.hibernate.tool.hbm2ddl.SchemaExportTask"
+        classpathref="class.path"/>
+    
+    <schemaexport
+        properties="hibernate.properties"
+        quiet="no"
+        text="no"
+        drop="no"
+        delimiter=";"
+        output="schema-export.sql">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaexport>
+</target>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-6">
+            <title>Actualizaciones incrementales de esquema</title>
+
+            <para>
+                La herramienta <literal>SchemaUpdate</literal> actualizar&#x00e1; un esquema existente con cambios
+                "incrementales". Nota que <literal>SchemaUpdate</literal> depende fuertemente de la API de metadatos
+                de JDBC, de modo que no funcionar&#x00e1; con todos los drivers JDBC.
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>classpaths_de_hibernate</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>opciones ficheros_de_mapeo</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title>Opciones de L&#x00ed;nea de Comandos de <literal>SchemaUpdate</literal></title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Opci&#x00f3;n</entry>
+                            <entry>Descripci&#x00f3;n</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--quiet</literal></entry>
+                            <entry>no enviar a salida est&#x00e1;ndar el gui&#x00f3;n</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>lee las propiedades de base de datos de un fichero</entry>
+                        </row>
+                     </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                Puedes encajar <literal>SchemaUpdate</literal> en tu aplicaci&#x00f3;n:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaUpdate(cfg).execute(false);]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-7">
+            <title>Usando Ant para actualizaciones incrementales de esquema</title>
+
+            <para>
+                Puedes llamar a <literal>SchemaUpdate</literal> desde el gui&#x00f3;n de Ant:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemaupdate">
+    <taskdef name="schemaupdate"
+        classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask"
+        classpathref="class.path"/>
+    
+    <schemaupdate
+        properties="hibernate.properties"
+        quiet="no">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaupdate>
+</target>]]></programlisting>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/transactions.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/transactions.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/transactions.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,925 @@
+<chapter id="transactions" revision="1">
+    <title>Transacciones y Concurrencia</title>
+
+    <para>
+        El punto m&#x00e1;s importante sobre Hibernate y el control de concurrencia es que muy f&#x00e1;cil
+        de comprender. Hibernate usa directamente conexiones JDBC y recursos JTA sin agregar
+        ning&#x00fa;n comportamiento de bloqueo adicional. Recomendamos altamente que gastes algo de
+        tiempo con la especificaci&#x00f3;n de JDBC, ANSI, y el aislamiento de transacciones de tu sistema
+        de gesti&#x00f3;n de base de datos. Hibernate s&#x00f3;lo a&#x00f1;ade versionado autom&#x00e1;tico pero no bloquea
+        objetos en memoria ni cambia el nivel de aislamiento de tus transacciones de base de datos.
+        B&#x00e1;sicamente, usa Hibernate como usar&#x00ed;as JDBC directo (o JTA/CMT) con tus recursos de base de
+        datos.
+    </para>
+
+    <para>
+        Sin embargo, adem&#x00e1;s del versionado autom&#x00e1;tico, Hibernate ofrece una API (menor) para
+        bloqueo pesimista de filas, usando la sint&#x00e1;xis <literal>SELECT FOR UPDATE</literal>.
+        Esta API se discute m&#x00e1;s adelante en este cap&#x00ed;tulo:
+    </para>
+
+    <para>
+        Comenzamos la discusi&#x00f3;n del control de concurrencia en Hibernate con la granularidad
+        de <literal>Configuration</literal>, <literal>SessionFactory</literal>, y
+        <literal>Session</literal>, as&#x00ed; como la base de datos y las transacciones de aplicaci&#x00f3;n
+        largas.
+    </para>
+
+    <sect1 id="transactions-basics">
+        <title>&#x00c1;mbitos de sesi&#x00f3;n y de transacci&#x00f3;n</title>
+
+        <para>
+            Una <literal>SessionFactory</literal> es un objeto seguro entre hebras caro-de-crear
+            pensado para ser compartido por todas las hebras de la aplicaci&#x00f3;n. Es creado una sola vez,
+            usualmente en el arranque de la aplicaci&#x00f3;n, a partir de una instancia de <literal>Configuration</literal>.
+        </para>
+
+        <para>
+            Una <literal>Session</literal> es un objeto barato, inseguro entre hebras que debe
+            ser usado una sola vez, para un solo proceso de negocio, una sola unidad de trabajo,
+            y luego descartado. Una <literal>Session</literal> no obtendr&#x00e1; una <literal>Connection</literal>
+            JDBC (o un <literal>Datasource</literal>) a menos que sea necesario, de modo que puedas
+            abrir y cerrar seguramente una <literal>Session</literal> incluso si no est&#x00e1;s seguro
+            que se necesitar&#x00e1; acceso a los datos para servir una petici&#x00f3;n en particular. (Esto se
+            vuelve importante en cuanto est&#x00e9;s implementando alguno de los siguientes patrones usando
+            intercepci&#x00f3;n de peticiones).
+        </para>
+
+        <para>
+            Para completar este cuadro tienes que pensar tambi&#x00e9;n en las transacciones de base de
+            datos. Una transacci&#x00f3;n de base de datos tiene que ser tan corta como sea posible, para
+            reducir la contenci&#x00f3;n de bloqueos en la base de datos. Las transacciones largas de base de
+            datos prevendr&#x00e1;n a tu aplicaci&#x00f3;n de escalar a una carga altamente concurrente.
+        </para>
+
+        <para>
+            &#x00bf;Qu&#x00e9; es el &#x00e1;mbito de una unidad de trabajo? &#x00bf;Puede una sola <literal>Session</literal> de Hibernate
+            extenderse a trav&#x00e9;s de varias transacciones de base de datos o es &#x00e9;sta una relaci&#x00f3;n uno-a-uno
+            de &#x00e1;mbitos? &#x00bf;Cu&#x00e1;ndo debes abrir y cerrar una <literal>Session</literal> y c&#x00f3;mo demarcas los
+            l&#x00ed;mites de la transacci&#x00f3;n de base de datos?
+        </para>
+
+        <sect2 id="transactions-basics-uow">
+            <title>Unidad de trabajo</title>
+
+            <para>
+                Primero, no uses el antipatr&#x00f3;n <emphasis>sesi&#x00f3;n-por-operaci&#x00f3;n</emphasis>, esto es,
+                &#x00a1;no abras y cierres una <literal>Session</literal> para cada simple llamada a la base
+                de datos en una sola hebra! Por supuesto, lo mismo es verdad para transacciones de base de
+                datos. Las llamadas a base de datos en una aplicaci&#x00f3;n se hacen usando una secuencia
+                prevista, que est&#x00e1;n agrupadas dentro de unidades de trabajo at&#x00f3;micas. (Nota que esto
+                tambi&#x00e9;n significa que el auto-commit despu&#x00e9;s de cada una de las sentencias SQL es in&#x00fa;til
+                en una aplicaci&#x00f3;n, este modo est&#x00e1; pensado para trabajo ad-hoc de consola SQL.
+                Hibernate deshabilita, o espera que el servidor de aplicaciones lo haga, el modo
+                auto-commit inmediatamente.)
+            </para>
+
+            <para>
+                El patr&#x00f3;n m&#x00e1;s com&#x00fa;n en una aplicaci&#x00f3;n mutiusuario cliente/servidor es
+                <emphasis>sesi&#x00f3;n-por-petici&#x00f3;n</emphasis>. En este modelo, una petici&#x00f3;n del cliente
+                es enviada al servidor (en donde se ejecuta la capa de persistencia de Hibernate),
+                se abre una nueva <literal>Session</literal> de Hibernate, y todas las operaciones
+                de base de datos se ejecutan en esta unidad de trabajo. Una vez completado el trabajo
+                (y se ha preparado la respuesta para el cliente) la sesi&#x00f3;n es limpiada y cerrada.
+                Podr&#x00ed;as usar una sola transacci&#x00f3;n de base de datos para servir a petici&#x00f3;n del cliente,
+                comenz&#x00e1;ndola y comprometi&#x00e9;ndola cuando abres y cierras la <literal>Session</literal>.
+                La relaci&#x00f3;n entre las dos es uno-a-uno y este modelo es a la medida perfecta de muchas
+                aplicaciones.
+            </para>
+
+            <para>
+                El desaf&#x00ed;o yace en la implementaci&#x00f3;n: no s&#x00f3;lo tienen que comenzarse y terminarse correctamente
+                la <literal>Session</literal> y la transacci&#x00f3;n, sino que adem&#x00e1;s tienen que estar accesibles
+                para las operaciones de acceso a datos. La demarcaci&#x00f3;n de una unidad de trabajo se implementa
+                idealmente usando un interceptor que se ejecuta cuando una petici&#x00f3;n llama al servidor y anter que
+                la respuesta sea enviada (es decir, un <literal>ServletFilter</literal>). Recomendamos ligar la
+                <literal>Session</literal> a la hebra que atiende la petici&#x00f3;n, usando una variable
+                <literal>ThreadLocal</literal>. Esto permite un f&#x00e1;cil acceso (como acceder a una variable static)
+                en t&#x00f3;do el c&#x00f3;digo que se ejecuta en esta hebra. Dependiendo del mecanismo de demarcaci&#x00f3;n de
+                transacciones de base de datos que elijas, podr&#x00ed;as mantener tambi&#x00e9;n el contexto de la transacci&#x00f3;n
+                en una variable <literal>ThreadLocal</literal>. Los patrones de implementaci&#x00f3;n para esto son
+                conocidos como <emphasis>Sesi&#x00f3;n Local de Hebra (ThreadLocal Session)</emphasis> y
+                <emphasis>Sesi&#x00f3;n Abierta en Vista (Open Session in View)</emphasis>. Puedes extender f&#x00e1;cilmente
+                la clase de ayuda <literal>HibernateUtil</literal> mostrada anteriormente para encontrar
+                una forma de implementar un interceptor e instalarlo en tu entorno. Ver el sitio web de Hibernate
+                para consejos y ejemplos.
+             </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-apptx">
+            <title>Transacciones de aplicaci&#x00f3;n</title>
+
+            <para>
+                El patr&#x00f3;n sesi&#x00f3;n-por-petici&#x00f3;n no es el &#x00fa;nico concepto &#x00fa;til que puedes usar para dise&#x00f1;ar unidades
+                de trabajo. Muchos procesos de negocio requiere una serie completa de interacciones con el
+                usuario intercaladas con accesos a base de datos. En aplicaciones web y de empresa no es aceptable
+                que una transacci&#x00f3;n de base de datos se extienda a trav&#x00e9;s de la interacci&#x00f3;n de un usuario.
+                Considera el siguiente ejemplo:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        Se abre la primera pantalla de un di&#x00e1;logo, los datos vistos por el usuario han sido
+                        cargados en una <literal>Session</literal> y transacci&#x00f3;n de base de datos particular.
+                        El usuario es libre de modificar los objetos.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        El usuario hace click en "Salvar" despu&#x00e9;s de 5 minutos y espera que sus modificaciones
+                        sean hechas persistentes. Tambi&#x00e9;n espera que &#x00e9;l sea la &#x00fa;nica persona editando esta
+                        informaci&#x00f3;n y que no puede ocurrir ninguna modificaci&#x00f3;n en conflicto.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Llamamos a esto unidad de trabajo, desde el punto de vista del usuario, una larga
+                <emphasis>transacci&#x00f3;n de aplicaci&#x00f3;n</emphasis> ejecut&#x00e1;ndose. Hay muchas formas en
+                que puedes implementar esto en tu aplicaci&#x00f3;n.
+            </para>
+
+            <para>
+                Una primera implementaci&#x00f3;n ingenua podr&#x00ed;a mantener abierta la <literal>Session</literal>
+                y la transacci&#x00f3;n de base de datos durante el tiempo de pensar del usuario, con bloqueos
+                tomados en la base de datos para prevenir la modificaci&#x00f3;n concurrente, y para garantizar
+                aislamiento y atomicidad. Esto es, por supuesto, un antipatr&#x00f3;n, ya que la contenci&#x00f3;n de
+                bloqueo no permitir&#x00ed;a a la aplicaci&#x00f3;n escalar con el n&#x00fa;mero de usuarios concurrentes.
+            </para>
+
+            <para>
+                Claramente, tenemos que usar muchas transacciones de base de datos para implementar la transacci&#x00f3;n
+                de aplicaci&#x00f3;n. En este caso, mantener el aislamiento de los procesos de negocio se vuelve una
+                responsabilidad parcial de la capa de aplicaci&#x00f3;n. Una sola transacci&#x00f3;n de aplicaci&#x00f3;n usualmente
+                abarca varias transacciones de base de datos. Ser&#x00e1; at&#x00f3;mica si s&#x00f3;lo una de estas transacciones de
+                base de datos (la &#x00fa;ltima) almacena los datos actualizados, todas las otras simplemente leen datos
+                (por ejemplo, en un di&#x00e1;logo estilo-asistente abarcando muchos ciclos petici&#x00f3;n/respuesta).
+                Esto es m&#x00e1;s f&#x00e1;cil de implementar de lo que suena, especialmente si usas las funcionalidades de
+                Hibernate:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <emphasis>Versionado Autom&#x00e1;tico</emphasis> - Hibernate puede llevar un control autom&#x00e1;tico de
+                        concurrencia optimista por ti, puede detectar autom&#x00e1;ticamente si una modificaci&#x00f3;n concurrente
+                        ha ocurrido durante el tiempo de pensar del usuario.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <emphasis>Objetos Separados</emphasis> - Si decides usar el ya discutido patr&#x00f3;n
+                        de <emphasis>sesi&#x00f3;n-por-petici&#x00f3;n</emphasis>, todas las instancias cargadas estar&#x00e1;n
+                        en estado separado durante el tiempo de pensar del usuario. Hibernate te permite
+                        volver a unir los objetos y hacer persistentes las modificaciones. El patr&#x00f3;n se
+                        llama <emphasis>sesi&#x00f3;n-por-petici&#x00f3;n-con-objetos-separados</emphasis>. Se usa
+                        versionado autom&#x00e1;tico para aislar las modificaciones concurrentes. 
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <emphasis>Sesi&#x00f3;n Larga</emphasis> - La <literal>Session</literal> de Hibernate puede ser
+                        desconectada de la conexi&#x00f3;n JDBC subyacente despu&#x00e9;s que se haya sido comprometida la
+                        transacci&#x00f3;n de base de datos, y reconectada cuando ocurra una nueva petici&#x00f3;n del cliente.
+                        Este patr&#x00f3;n es conocido como <emphasis>sesi&#x00f3;n-por-transacci&#x00f3;n-de-aplicaci&#x00f3;n</emphasis>
+                        y hace la re-uni&#x00f3;n innecesaria. Para aislar las modificaciones concurrentes se usa el
+                        versionado autom&#x00e1;tico.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Tanto <emphasis>sesi&#x00f3;n-por-petici&#x00f3;n-con-objetos-separados</emphasis> como
+                <emphasis>sesi&#x00f3;n-por-transacci&#x00f3;n-de-aplicaci&#x00f3;n</emphasis>, ambas tienen 
+                ventajas y desventajas, las discutimos m&#x00e1;s adelante en este cap&#x00ed;tulo en el contexto
+                del control optimista de concurrencia.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-identity">
+            <title>Considerando la identidad del objeto</title>
+
+            <para>
+                Una aplicaci&#x00f3;n puede acceder concurrentemente a el mismo estado persistente en dos
+                <literal>Session</literal>s diferentes. Sin embargo, una instancia de una clase
+                persistente nunca se comparte entre dos instancias de <literal>Session</literal>.
+                Por lo tanto existen dos nociones diferentes de identidad:
+            </para>
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term>Identidad de Base de Datos</term>
+                    <listitem>
+                        <para>
+                            <literal>foo.getId().equals( bar.getId() )</literal>
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Identidad JVM</term>
+                    <listitem>
+                        <para>
+                            <literal>foo==bar</literal>
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+            <para>
+                Entonces para objetos unidos a una <literal>Session</literal> <emphasis>en particular</emphasis>
+                (es decir en el &#x00e1;mbito de una <literal>Session</literal>) las dos nociones son equivalentes, y
+                la identidad JVM para la identidad de base de datos est&#x00e1; garantizada por Hibernate. Sin embargo,
+                mientras la aplicaci&#x00f3;n acceda concurrentemente al "mismo" (identidad persistente) objeto de negocio
+                en dos sesiones diferentes, las dos instancias ser&#x00e1;n realmente "diferentes" (identidad JVM).
+                Los conflictos se resuelven (con versionado autom&#x00e1;tico) en tiempo de limpieza (flush) usando un
+                enfoque optimista.
+            </para>
+
+            <para>
+                Este enfoque deja que Hibernate y la base de datos se preocupen sobre la concurrencia. Adem&#x00e1;s
+                provee la mejor escalabilidad, ya que garantizando la identidad un unidades de trabajo monohebra
+                no se necesitan bloqueos caros u otros medios de sincronizaci&#x00f3;n. La aplicaci&#x00f3;n nunca necesita
+                sincronizar sobre ning&#x00fa;n objeto de negocio, siempre que se apegue a una sola hebra por
+                <literal>Session</literal>. Dentro de una <literal>Session</literal> la aplicaci&#x00f3;n puede usar
+                con seguridad <literal>==</literal> para comparar objetos.
+            </para>
+
+            <para>
+                Sin embargo, una aplicaci&#x00f3;n que usa <literal>==</literal> fuera de una <literal>Session</literal>,
+                podr&#x00ed;a ver resultados inesperados. Esto podr&#x00ed;a ocurrir incluso en sitios algo inesperados,
+                por ejemplo, si pones dos instancias separadas dentro del mismo <literal>Set</literal>.
+                Ambas podr&#x00ed;an tener la misma identidad de base de datos (es decir, representar la misma fila),
+                pero la identidad JVM, por definici&#x00f3;n, no est&#x00e1; garantizada para las instancias en estado separado.
+                El desarrollador tiene que sobrescribir los m&#x00e9;todos <literal>equals()</literal> y
+                <literal>hashCode()</literal> en las clases persistentes e implementar su propia noci&#x00f3;n de igualdad
+                de objetos. Hay una advertencia: Nunca uses el identificador de base de datos para implementar
+                la igualdad, usa una clave de negocio, una combinaci&#x00f3;n de atributos &#x00fa;nicos, usualmente inmutables.
+                El identificador de base de datos cambiar&#x00e1; si un objeto transitorio es hecho persistente.
+                Si la instancia transitoria (usualmente junta a instancias separadas) es mantenida en un
+                <literal>Set</literal>, cambiar el c&#x00f3;digo hash rompe el contrato del <literal>Set</literal>.
+                Los atributos para las claves de negocio no tienen que ser tan estables como las claves primarias
+                de base de datos, s&#x00f3;lo tienes que garantizar estabilidad en tanto los objetos est&#x00e9;n en el mismo
+                <literal>Set</literal>. Mira el sitio web de Hibernate para una discusi&#x00f3;n m&#x00e1;s cuidadosa de este
+                tema. Nota tambi&#x00e9;n que &#x00e9;ste no es un tema de Hibernate, sino simplemente c&#x00f3;mo la identidad y la igualdad
+                de los objetos Java tiene que ser implementada.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-issues">
+            <title>Temas comunes</title>
+
+             <para>
+                 Nunca uses los antipatrones <emphasis>sesi&#x00f3;n-por-sesi&#x00f3;n-de-usuario</emphasis> o
+                 <emphasis>sesi&#x00f3;n-por-aplicaci&#x00f3;n</emphasis> (por supuesto, hay raras excepciones a esta
+                 regla). Nota que algunis de los siguientes temas podr&#x00ed;an tambi&#x00e9;n aparecer con los patrones
+                 recomendados. Aseg&#x00fa;rate que entiendes las implicaciones antes de tomar una decisi&#x00f3;n de
+                 dise&#x00f1;o:
+             </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        Una <literal>Session</literal> no es segura entre hebras. Las cosas que se suponen
+                        que funcionan concurrentemente, como peticiones HTTP, beans de sesi&#x00f3;n, o workers de
+                        Swing, provocar&#x00e1;n condiciones de competencia si una instancia de <literal>Session</literal> 
+                        fuese compartida. Si guardas tu <literal>Session</literal> de Hibernate en tu
+                        <literal>HttpSession</literal> (discutido m&#x00e1;s adelante), debes considerar sincronizar
+                        el acceso a tu sesi&#x00f3;n HTTP. De otro modo, un usuario que hace click lo suficientemente
+                        r&#x00e1;pido puede llegar a usar la misma <literal>Session</literal> en dos hebras ejecut&#x00e1;ndose
+                        concurrentemente.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Una excepci&#x00f3;n lanzada por Hibernate significa que tienes que deshacer (rollback) tu
+                        transacci&#x00f3;n de base de datos y cerrar la <literal>Session</literal> inmediatamente
+                        (discutido en m&#x00e1;s detalle luego). Si tu <literal>Session</literal> est&#x00e1; ligada a la
+                        aplicaci&#x00f3;n, tienes que parar la aplicaci&#x00f3;n. Deshacer (rollback) la transacci&#x00f3;n de base
+                        de datos no pone a tus objetos de vuelta al estado en que estaban al comienzo de la
+                        transacci&#x00f3;n. Esto significa que el estado de la base de datos y los objetos de negocio
+                        quedan fuera de sincron&#x00ed;a. Usualmente esto no es un problema, pues las excepciones no
+                        son recuperables y tienes que volver a comenzar despu&#x00e9;s del rollback de todos modos.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        La <literal>Session</literal> pone en cach&#x00e9; todo objeto que est&#x00e9; en estado persistente
+                        (vigilado y chequeado por estado sucio por Hibernate). Esto significa que crece sin
+                        fin hasta que obtienes una OutOfMemoryException, si la mantienes abierta por un largo
+                        tiempo o simplemente cargas demasiados datos. Una soluci&#x00f3;n para esto es llamar a
+                        <literal>clear()</literal> y <literal>evict()</literal> para gestionar el cach&#x00e9; de la
+                        <literal>Session</literal>, pero probalemente debas considerar un procedimiento almacenado
+                        si necesitas operaciones de datos masivas. Se muestran algunas soluciones  en
+                        <xref linkend="batch"/>. Mantener una <literal>Session</literal> abierta por la duraci&#x00f3;n
+                        de una sesi&#x00f3;n de usuario significa tambi&#x00e9;n una alta probabilidad de datos a&#x00f1;ejos.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="transactions-demarcation">
+        <title>Demarcaci&#x00f3;n de la transacci&#x00f3;n de base de datos</title>
+
+        <para>
+            Los l&#x00ed;mites de las transacciones de base de datos (o sistema) son siempre necesarios. Ninguna comunicaci&#x00f3;n
+            con la base de datos puede darse fuera de una transacci&#x00f3;n de base de datos (esto parece confundir muchos
+            desarrolladores acostumbrados al modo auto-commit). Siempre usa l&#x00ed;mites de transacci&#x00f3;n claros, incluso
+            para las operaciones de s&#x00f3;lo lectura. Dependiendo del nivel de aislamiento y las capacidades de base de
+            datos, esto podr&#x00ed;a o no ser requerido, pero no hay un merma si siempre demarcas expl&#x00ed;citamente
+            las transacciones.
+        </para>
+
+        <para>
+            Una aplicaci&#x00f3;n Hibernate puede ejecutarse en entornos no manejados (es decir, como independiente,
+            Web simple, o aplicaciones Swing) y entornos manejados J2EE. En un entorno no manejado, Hibernate es
+            usualmente responsable de su propio pool de conexiones de base de datos. El desarrollador de aplicaciones
+            tiene que establecer manualmente los l&#x00ed;mites de transacci&#x00f3;n, en otras palabras, hacer begin, commit, o
+            rollback las transacciones de base de datos por s&#x00ed; mismo. Un entorno manejado usualmente provee transacciones
+            gestionadas por contenedor, con el ensamble de transacci&#x00f3;n definido declarativamente en descriptores de
+            despliegue de beans de sesi&#x00f3;n EJB, por ejemplo. La demarcaci&#x00f3;n program&#x00e1;tica de transacciones no es m&#x00e1;s
+            necesario, incluso limpiar (flush) la <literal>Session</literal> es hecho autom&#x00e1;ticamente.
+        </para>
+
+        <para>
+            Sin embargo, frecuentemente es deseable mantener portable tu capa de persistencia. Hibernate ofrece
+            una API de envoltura llamada <literal>Transaction</literal> que se traduce al sistema de transacciones
+            nativo de tu entorno de despliegue. Esta API es realmente opcional, pero recomendamos fuertemente su uso
+            salvo que est&#x00e9;s en un bean de sesi&#x00f3;n CMT.
+        </para>
+
+        <para>
+            Usualmente, finalizar una <literal>Session</literal> implica cuatro fases distintas:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    limpiar (flush) la sesi&#x00f3;n
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    comprometer la transacci&#x00f3;n
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    cerrar la sesi&#x00f3;n
+                </para>
+            </listitem>
+            <listitem>
+                <para> 
+                    manejar excepciones
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Limpiar la sesi&#x00f3;n ha sido discutido anteriormente, tendremos ahora una mirada m&#x00e1;s de cerca
+            a la demarcaci&#x00f3;n de transacciones y manejo de excepciones en sendos entornos manejado y no manejados.
+        </para>
+
+
+        <sect2 id="transactions-demarcation-nonmanaged">
+            <title>Entorno no manejado</title>
+
+            <para>
+                Si una capa de persistencia Hibernate se ejecuta en un entorno no manejado, las conexiones
+                de base de datos son manejadas usualmente por el mecanismo de pooling de Hibernate. El idioma
+                manejo de sesi&#x00f3;n/transacci&#x00f3;n se ve as&#x00ed;:
+            </para>
+
+            <programlisting><![CDATA[//Non-managed environment idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+    tx = sess.beginTransaction();
+
+    // do some work
+    ...
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    if (tx != null) tx.rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+            <para>
+                No tienes que limpiar con <literal>flush()</literal> la <literal>Session</literal> expl&#x00ed;citamente -
+                la llamada a <literal>commit()</literal> autom&#x00e1;ticamente dispara la sincronizaci&#x00f3;n.
+            </para>
+
+            <para>
+                Una llamada a <literal>close()</literal> marca el fin de una sesi&#x00f3;n. La principal implicaci&#x00f3;n
+                de <literal>close()</literal> es que la conexi&#x00f3;n JDBC ser&#x00e1; abandonada por la sesi&#x00f3;n.
+            </para>
+
+            <para>
+                Este c&#x00f3;digo Java es portable y se ejecuta tanto en entornos no manejados como en entornos JTA.
+            </para>
+
+            <para>
+                Muy probablemente nunca veas este idioma en c&#x00f3;digo de negocio en una aplicaci&#x00f3;n normal;
+                las excepciones fatales (sistema) deben siempre ser capturadas en la "cima". En otras palabras,
+                el c&#x00f3;digo que ejecuta las llamadas de Hibernate (en la capa de persistencia) y el c&#x00f3;digo que
+                maneja <literal>RuntimeException</literal> (y usualmente s&#x00f3;lo puede limpiar y salir) est&#x00e1;n en
+                capas diferentes. Esto puede ser un desaf&#x00ed;o de dise&#x00f1;arlo t&#x00fa; mismo y debes usar los servicios
+                de contenedor J2EE/EJB en cuanto estuviesen disponibles. El manejo de excepciones se dicute
+                m&#x00e1;s adelante en este cap&#x00ed;tulo.
+            </para>
+
+           <para>
+                Nota que debes seleccionar <literal>org.hibernate.transaction.JDBCTransactionFactory</literal>
+                (que es el por defecto).
+            </para>
+            
+        </sect2>
+
+        <sect2 id="transactions-demarcation-jta">
+            <title>Usando JTA</title>
+
+            <para>
+                Si tu capa de persistencia se ejecuta en un servidor de aplicaciones (por ejemplo, detr&#x00e1;s
+                de beans de sesi&#x00f3;n EJB), cada conexi&#x00f3;n de datasource obtenida por Hibernate ser&#x00e1; parte
+                autom&#x00e1;ticamente de la transacci&#x00f3;n JTA global. Hibernate ofrece dos estrategias para esta
+                integraci&#x00f3;n.
+            </para>
+
+            <para>
+                Si usas transacciones gestionadas-por-bean (BMT) Hibernate le dir&#x00e1; al servidor de aplicaciones
+                que comience y finalice una transacci&#x00f3;n BMT si usas la API de <literal>Transaction</literal>.
+                De modo que, el c&#x00f3;digo de gesti&#x00f3;n de la transacci&#x00f3;n es id&#x00e9;ntico al de un entorno no manejado.
+            </para>
+            
+           <programlisting><![CDATA[// BMT idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+    tx = sess.beginTransaction();
+
+    // do some work
+    ...
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    if (tx != null) tx.rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+            <para>
+                Con CMT, la demarcaci&#x00f3;n de la transacci&#x00f3;n se hace en descriptores de despliegue de beans de sesi&#x00f3;n,
+                no program&#x00e1;ticamente. Si no quieres limpiar (flush) y cerrar manualmente la <literal>Session</literal>
+                por ti mismo, solamente establece <literal>hibernate.transaction.flush_before_completion</literal> a
+                <literal>true</literal>, <literal>hibernate.connection.release_mode</literal> a
+                <literal>after_statement</literal> o <literal>auto</literal> y
+                <literal>hibernate.transaction.auto_close_session</literal> a <literal>true</literal>. Hibernate
+                limpiar&#x00e1; y cerrar&#x00e1; entonces autom&#x00e1;ticamente la <literal>Session</literal> para ti. Lo &#x00fa;nico que resta
+                es deshacer (rollback) la transacci&#x00f3;n cuando ocurra una excepci&#x00f3;n. Afortunadamente, en un bean CMT,
+                incluso esto ocurre autom&#x00e1;ticamente, ya que una <literal>RuntimeException</literal> no manejada
+                disparada por un m&#x00e9;todo de un bean de sesi&#x00f3;n le dice al contenedor que ponga a deshacer la transacci&#x00f3;n
+                global. <emphasis>Esto significa que, en CMT, no necesitas usar en absoluto la API de
+                <literal>Transaction</literal> de Hibernate.</emphasis>
+            </para>
+
+            <para>
+                Nota que debes elegir <literal>org.hibernate.transaction.JTATransactionFactory</literal> en un
+                bean de sesi&#x00f3;n BMT, y <literal>org.hibernate.transaction.CMTTransactionFactory</literal> en un
+                bean de sesi&#x00f3;n CMT, cuando configures la f&#x00e1;brica de transacciones de Hibernate. Recuerda adem&#x00e1;s
+                establecer <literal>org.hibernate.transaction.manager_lookup_class</literal>.
+            </para>
+
+            <para>
+                Si trabajas en un entorno CMT, y usas limpieza (flushing) y cierre autom&#x00e1;ticos de la sesi&#x00f3;n,
+                podr&#x00ed;as querer tambi&#x00e9;n usar la misma sesi&#x00f3;n en diferentes partes de tu c&#x00f3;digo. T&#x00ed;picamente,
+                en un entorno no manejado, usar&#x00ed;as una variable <literal>ThreadLocal</literal> para tener la sesi&#x00f3;n,
+                pero una sola petici&#x00f3;n de EJB puede ejecutarse en diferentes hebras (por ejemplo, un bean de sesi&#x00f3;n
+                llamando a otro bean de sesi&#x00f3;n). Si no quieres molestarte en pasar tu <literal>Session</literal>
+                por alrededor, la <literal>SessionFactory</literal> provee el m&#x00e9;todo
+                <literal>getCurrentSession()</literal>, que devuelve una sesi&#x00f3;n que est&#x00e1; pegada al contexto de
+                transacci&#x00f3;n JTA. &#x00a1;Esta es la forma m&#x00e1;s f&#x00e1;cil de integrar Hibernate en una aplicaci&#x00f3;n!
+                La sesi&#x00f3;n "actual" siempre tiene habilitados limpieza, cierre y liberaci&#x00f3;n de conexi&#x00f3;n autom&#x00e1;ticos
+                (sin importar la configuraci&#x00f3;n de las propiedades anteriores). Nuestra idioma de gesti&#x00f3;n de
+                sesi&#x00f3;n/transacci&#x00f3;n se reduce a:
+            </para>
+
+           <programlisting><![CDATA[// CMT idiom
+Session sess = factory.getCurrentSession();
+
+// do some work
+...
+
+]]></programlisting>
+
+            <para>
+                En otras palabras, todo lo que tienes que hacer en un entorno manejado, es llamar a 
+                <literal>SessionFactory.getCurrentSession()</literal>, hacer tu trabajo de acceso a datos,
+                y dejar el resto al contenedor. Los l&#x00ed;mites de transacci&#x00f3;n se establecen declarativamente
+                en los descriptores de despliegue de tu bean de sesi&#x00f3;n. El ciclo de vida de la sesi&#x00f3;n es
+                manejado completamente por Hibernate.
+            </para>
+            
+            <para>
+                Existe una advertencia al uso del modo de liberaci&#x00f3;n de conexi&#x00f3;n <literal>after_statement</literal>.
+                Debido a una limitaci&#x00f3;n tonta de la especificaci&#x00f3;n de JTA, no es posible para Hibernate
+                limpiar autom&#x00e1;ticamente ning&#x00fa;n <literal>ScrollableResults</literal> no cerrado ni
+                instancias de <literal>Iterator</literal> devueltas por  <literal>scroll()</literal> o
+                <literal>iterate()</literal>. <emphasis>Debes</emphasis> liberar el cursor de base de datos
+                subyacente llamando a <literal>ScrollableResults.close()</literal> o
+                <literal>Hibernate.close(Iterator)</literal> expl&#x00ed;citamente desde un bloque <literal>finally</literal>.
+                (Por supuesto, la mayor&#x00ed;a de las aplicaciones pueden evitarlo f&#x00e1;cilmente no usando en absoluto ning&#x00fa;n
+                <literal>scroll()</literal> o <literal>iterate()</literal> desde el c&#x00f3;digo CMT.)
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-demarcation-exceptions">
+            <title>Manejo de excepciones</title>
+
+            <para>
+                Si la <literal>Session</literal> lanza una excepci&#x00f3;n (incluyendo cualquier
+                <literal>SQLException</literal>), debes inmediatamente deshacer (rollback) la
+                transacci&#x00f3;n de base de datos, llamar a <literal>Session.close()</literal> y
+                descartar la instancia de <literal>Session</literal>. Ciertos m&#x00e9;todos de
+                <literal>Session</literal> <emphasis>no</emphasis> dejar&#x00e1;n la sesi&#x00f3;n en un
+                estado consistente. Ninguna excepci&#x00f3;n lanzada por Hibernate puede ser tratada
+                como recuperable. Aseg&#x00fa;rate que la <literal>Session</literal> sea cerrada llamando
+                a <literal>close()</literal> en un bloque <literal>finally</literal>.
+            </para>
+
+            <para>
+                La <literal>HibernateException</literal>, que envuelve la mayor&#x00ed;a de los errores que
+                pueden ocurrir en la capa de persistencia de Hibernate, en una excepci&#x00f3;n no chequeada
+                (no lo era en versiones anteriores de Hibernate). En nuestra opini&#x00f3;n, no debemos forzar
+                al desarrollador de aplicaciones a capturar una excepci&#x00f3;n irrecuperable en una capa baja.
+                En la mayor&#x00ed;a de los sistemas, las excepciones no chequeadas y fatales son manejadas
+                en uno de los primeros cuadros de la pila de llamadas a m&#x00e9;todos (es decir, en las capas
+                m&#x00e1;s altas) y se presenta un mensaje de error al usuario de la aplicaci&#x00f3;n (o se toma alguna
+                otra acci&#x00f3;n apropiada). Nota que Hibernate podr&#x00ed;a tambi&#x00e9;n lanzar otras excepciones no chequeadas
+                que no sean una <literal>HibernateException</literal>. Una vez m&#x00e1;s, no son recuperables y debe
+                tomarse una acci&#x00f3;n apropiada.
+            </para>
+
+            <para>
+                Hibernate envuelve <literal>SQLException</literal>s lanzadas mientras se interact&#x00fa;a con la base
+                de datos en una <literal>JDBCException</literal>. De hecho, Hibernate intentar&#x00e1; convertir la excepci&#x00f3;n
+                en una subclase de <literal>JDBCException</literal> m&#x00e1;s significativa. La <literal>SQLException</literal>
+                est&#x00e1; siempre disponible v&#x00ed;a <literal>JDBCException.getCause()</literal>. Hibernate convierte la 
+                <literal>SQLException</literal> en una subclase de <literal>JDBCException</literal> apropiada usando
+                el <literal>SQLExceptionConverter</literal> adjunto a la <literal>SessionFactory</literal>. Por defecto,
+                el <literal>SQLExceptionConverter</literal> est&#x00e1; definido para el dialecto configurado; sin embargo,
+                es tambi&#x00e9;n posible enchufar una implementaci&#x00f3;n personalizada (ver los javadocs de la clase
+                <literal>SQLExceptionConverterFactory</literal> para los detalles). Los subtipos est&#x00e1;ndar de
+                <literal>JDBCException</literal> son:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>JDBCConnectionException</literal> - indica un error con la comunicaci&#x00f3;n JDBC subyacente.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>SQLGrammarException</literal> - indica un problema de gram&#x00e1;tica o sint&#x00e1;xis con el
+                        SQL publicado.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>ConstraintViolationException</literal> - indica alguna forma de violaci&#x00f3;n de restricci&#x00f3;n
+                        de integridad.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>LockAcquisitionException</literal> - indica un error adquiriendo un nivel de bloqueo
+                        necesario para realizar una operaci&#x00f3;n solicitada.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>GenericJDBCException</literal> - una excepci&#x00f3;n gen&#x00e9;rica que no cay&#x00f3; en ninguna de las
+                        otras categor&#x00ed;as.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="transactions-optimistic">
+        <title>Control optimista de concurrencia</title>
+
+        <para>
+            El &#x00fa;nico enfoque que es consistente con alta concurrencia y alta escalabilidad es el control
+            optimista de concurrencia con versionamiento. El chuequeo de versi&#x00f3;n usa n&#x00fa;meros de versi&#x00f3;n,
+            o timestamps, para detectar actualizaciones en conflicto (y para prevenir actualizaciones perdidas).
+            Hibernate provee para tres enfoques posibles de escribir c&#x00f3;digo de aplicaci&#x00f3;n que use concurrencia
+            optimista. Los casos de uso que hemos mostrado est&#x00e1;n en el contexto de transacciones de aplicaci&#x00f3;n
+            largas pero el chequeo de versiones tiene adem&#x00e1;s el beneficio de prevenir actualizaciones perdidas
+            en transacciones de base de datos solas.
+        </para>
+
+        <sect2 id="transactions-optimistic-manual">
+            <title>Chequeo de versiones de aplicaci&#x00f3;n</title>
+
+            <para>
+                En una implementaci&#x00f3;n sin mucha ayuda de Hibernate, cada interacci&#x00f3;n con la base de datos ocurre en una
+                nueva <literal>Session</literal> y el desarrollador es responsable de recargar todas las intancias
+                persistentes desde la base de datos antes de manipularlas. Este enfoque fuerza a la aplicaci&#x00f3;n a
+                realizar su propio chequeo de versiones para asegurar el aislamiento de transacciones de base de datos.
+                Es el enfoque m&#x00e1;s similar a los EJBs de entidad.
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+int oldVersion = foo.getVersion();
+session.load( foo, foo.getKey() ); // load the current state
+if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();
+foo.setProperty("bar");
+t.commit();
+session.close();]]></programlisting>
+
+            <para>
+                La propiedad <literal>version</literal> se mapea usando <literal>&lt;version&gt;</literal>,
+                e Hibernate la incrementar&#x00e1; autom&#x00e1;ticamente durante la limpieza si la entidad est&#x00e1; sucia.
+            </para>
+
+            <para>
+                Por supuesto, si est&#x00e1;s operando un entorno de baja-concurrencia-de-datos y no requieres
+                chequeo de versiones, puedes usar este enfoque y simplemente saltar el chequeo de versiones.
+                En ese caso, <emphasis>el &#x00fa;ltimo compromiso (commit) gana</emphasis> ser&#x00e1; la estrategia por
+                defecto para tus transacciones de aplicaci&#x00f3;n largas. Ten en mente que esto podr&#x00ed;a confundir
+                a los usuarios de la aplicaci&#x00f3;n, pues podr&#x00ed;an experimentar actualizaciones perdidas sin
+                mensajes de error ni chance de fusionar los cambios conflictivos.
+            </para>
+
+            <para>
+                Claramente, el chequeo manual de versiones es factible solamente en circunstancias muy triviales,
+                y no es pr&#x00e1;ctico para la mayor&#x00ed;a de aplicaciones. Frecuentemente, no s&#x00f3;lo intancias solas, sino grafos
+                completos de objetos modificados tienen que ser chequeados. Hibernate ofrece chequeo de versiones
+                autom&#x00e1;tico con el paradigma de dise&#x00f1;o de <literal>Session</literal> larga o de instancias separadas.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-longsession">
+            <title>Sesi&#x00f3;n larga y versionado autom&#x00e1;tico</title>
+
+            <para>
+                Una sola instancia de <literal>Session</literal> y sus instancias persistentes
+                son usadas para toda la transacci&#x00f3;n de aplicaci&#x00f3;n. Hibernate chequea las versiones
+                de instancia en el momento de limpieza (flush), lanzando una excepci&#x00f3;n si se detecta
+                una modificaci&#x00f3;n concurrente. Concierne al desarrollador capturar y manejar esta excepci&#x00f3;n
+                (las opciones comunes son la oportunidad del usuario de fusionar los cambios, o recomenzar el
+                proceso de negocio sin datos a&#x00f1;ejos).
+            </para>
+
+            <para>
+                La <literal>Session</literal> se desconecta de cualquier conexi&#x00f3;n JDBC subyacente
+                al esperar por una interacci&#x00f3;n del usuario. Este enfoque es el m&#x00e1;s eficiente en t&#x00e9;rminos
+                de acceso a base de datos. La aplicaci&#x00f3;n no necesita tratar por s&#x00ed; misma con el chequeo de
+                versiones, ni re-uniendo instancias separadas, ni tiene que recargar instancias en cada
+                transacci&#x00f3;n de base de datos.
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded earlier by the Session
+session.reconnect(); // Obtain a new JDBC connection
+Transaction t = session.beginTransaction();
+foo.setProperty("bar");
+t.commit(); // End database transaction, flushing the change and checking the version
+session.disconnect(); // Return JDBC connection ]]></programlisting>
+
+            <para>
+                El objeto <literal>foo</literal> todav&#x00ed;a conoce en qu&#x00e9; <literal>Session</literal> fue cargado.
+                <literal>Session.reconnect()</literal> obtiene una nueva conexi&#x00f3;n (o puedes proveer una) y
+                reasume la sesi&#x00f3;n. El m&#x00e9;todo <literal>Session.disconnect()</literal> desconectar&#x00e1; la sesi&#x00f3;n
+                de la conexi&#x00f3;n JDBC y la devolver&#x00e1; la conexi&#x00f3;n al pool (a menos que hayas provisto la conexi&#x00f3;n).
+                Despu&#x00e9;s de la reconexi&#x00f3;n, para forzar un chequeo de versi&#x00f3;n en datos que no est&#x00e9;s actualizando,
+                puedes llamar a <literal>Session.lock()</literal> con <literal>LockMode.READ</literal> sobre
+                cualquier objeto que pudiese haber sido actualizado por otra transacci&#x00f3;n. No necesitas bloquear
+                ning&#x00fa;n dato que <emphasis>s&#x00ed; est&#x00e9;s</emphasis> actualizando.
+            </para>
+            
+            <para>
+                Si las llamadas expl&#x00ed;citas a <literal>disconnect()</literal> y <literal>reconnect()</literal>
+                son muy onerosas, puedes usar en cambio <literal>hibernate.connection.release_mode</literal>.
+            </para>
+
+            <para>
+                Este patr&#x00f3;n es problem&#x00e1;tico si la <literal>Session</literal> es demasiado grande para ser almacenada
+                durante el tiempo de pensar del usuario, por ejemplo, una <literal>HttpSession</literal> debe
+                mantenerse tan peque&#x00f1;a como sea posible. Ya que la <literal>Session</literal> es tambi&#x00e9;n el cach&#x00e9;
+                (obligatorio) de primer nivel y contiene todos los objetos cargados, podemos probablemente cargar
+                esta estrategia s&#x00f3;lo para unos pocos ciclos petici&#x00f3;n/respuesta. Esto est&#x00e1; de hecho recomendado, ya que
+                la <literal>Session</literal> tendr&#x00e1; pronto tambi&#x00e9;n datos a&#x00f1;ejos.
+            </para>
+
+            <para>
+                Nota tambi&#x00e9;n que debes mantener la <literal>Session</literal> desconectada pr&#x00f3;xima a la capa
+                de persistencia. En otras palabras, usa una sesi&#x00f3;n de EJB con estado para tener la
+                <literal>Session</literal> y no transferirla a la capa web para almacenarla en la
+                <literal>HttpSession</literal> (ni incluso serializarla a una capa separada).
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-detached">
+            <title>Objetos separados y versionado autom&#x00e1;tico</title>
+
+            <para>
+                Cada interacci&#x00f3;n con el almac&#x00e9;n persistente ocurre en una nueva <literal>Session</literal>.
+                Sin embargo, las mismas instancias persistentes son reusadas para cada interacci&#x00f3;n con la base de
+                datos. La aplicaci&#x00f3;n manipula el estado de las instancias separadas originalmente cargadas en otra
+                <literal>Session</literal> y luego las readjunta usando <literal>Session.update()</literal>,
+                <literal>Session.saveOrUpdate()</literal>, o <literal>Session.merge()</literal>.
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+foo.setProperty("bar");
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded already
+t.commit();
+session.close();]]></programlisting>
+
+            <para>
+                De nuevo, Hibernate chequear&#x00e1; las versiones de instancia durante la limpieza (flush),
+                lanzando una excepci&#x00f3;n si ocurrieron actualizaciones en conflicto.
+            </para>
+
+            <para>
+                Puedes tambi&#x00e9;n llamar a <literal>lock()</literal> en vez de <literal>update()</literal>
+                y usar <literal>LockMode.READ</literal> (realizando un chequeo de versi&#x00f3;n, puenteando
+                todos los cach&#x00e9;s) si est&#x00e1;s seguro que el objeto no ha sido modificado.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-customizing">
+            <title>Personalizando el versionado autom&#x00e1;tico</title>
+
+            <para>
+                Puedes deshabilitar el incremento de versi&#x00f3;n autom&#x00e1;tico de Hibernate para propiedades en particular
+                y colecciones estableciendo el atributo de mapeo <literal>optimistic-lock</literal> a 
+                <literal>false</literal>. Hibernate entonces no incrementar&#x00e1; ya m&#x00e1;s las versiones si la propiedad est&#x00e1;
+                sucia.
+            </para>
+
+            <para>
+                Los esquemas de base de datos heredados son frecuentemente est&#x00e1;ticos y no pueden ser modificados.
+                U otras aplicaciones podr&#x00ed;an tambi&#x00e9;n acceder la misma base de datos y no saber c&#x00f3;mo manejar los n&#x00fa;meros
+                de versi&#x00f3;n ni incluso timestamps. En ambos casos, el versionado no puede confiarse a una columna en
+                particular en una tabla. Para forzar un chequeo de versiones sin un mapeo de propiedad de versi&#x00f3;n o
+                timestamp, con una comparaci&#x00f3;n del estado de todos los campos en una fila, activa
+                <literal>optimistic-lock="all"</literal> en el mapeo de <literal>&lt;class&gt;</literal>.
+                Nota que esto conceptualmente funciona solamente si Hibernate puede comparar el estado viejo y nuevo,
+                es decir, si usas una sola <literal>Session</literal> larga y no
+                sesi&#x00f3;n-por-petici&#x00f3;n-con-instancias-separadas.
+            </para>
+
+            <para>
+                A veces las modificaciones concurrentes pueden permitirse, en cuanto los cambios que hayan sido
+                hechos no se traslapen. Si estableces <literal>optimistic-lock="dirty"</literal> al mapear la
+                <literal>&lt;class&gt;</literal>, Hibernate s&#x00f3;lo comparar&#x00e1; los campos sucios durante la limpieza.
+            </para>
+
+            <para>
+                En ambos casos, con columnas de versi&#x00f3;n/timestamp dedicadas o con comparaci&#x00f3;n de campos
+                completa/sucios, Hibernate usa una sola sentencia <literal>UPDATE</literal>
+                (con una cl&#x00e1;usula <literal>WHERE</literal> apropiada) por entidad para ejecutar el chequeo
+                de versiones y actualizar la informaci&#x00f3;n. Si usas persistencia transitiva para la re-uni&#x00f3;n
+                en cascada de entidades asociadas, Hibernate podr&#x00ed;a ejecutar actualizaciones innecesarias.
+                Esto usualmente no es un problema, pero podr&#x00ed;an ejecutarse disparadores (triggers) 
+                <emphasis>on update</emphasis> en la base de datos incluso cuando no se haya hecho ning&#x00fa;n cambio
+                a las instancias separadas. Puedes personalizar este comportamiento estableciendo
+                <literal>select-before-update="true"</literal> en el mapeo de <literal>&lt;class&gt;</literal>,
+                forzando a Hibernate a <literal>SELECT</literal> la instancia para asegurar que las actualizaciones
+                realmente ocurran, antes de actualizar la fila.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="transactions-locking">
+        <title>Bloqueo pesimista</title>
+
+        <para>
+            No se pretende que los usuarios gasten mucho tiempo preocup&#x00e1;ndose de las estrategias de bloqueo.
+            Usualmente es suficiente con especificar un nivel de aislamiento para las conexiones JDBC y entonces
+            simplemente dejar que la base de datos haga todo el trabajo. Sin embargo, los usuarios avanzados pueden
+            a veces obtener bloqueos exclusivos pesimistas, o reobtener bloqueos al comienzo de una nueva
+            transacci&#x00f3;n.
+        </para>
+
+        <para>
+            &#x00a1;Hibernate siempre usar&#x00e1; el mecanismo de bloqueo de la base de datos, nunca bloqueo
+            de objetos en memoria!
+        </para>
+
+        <para>
+            La clase <literal>LockMode</literal> define los diferentes niveles de bloqueo que pueden ser adquiridos
+            por Hibernate. Un bloqueo se obtiene por los siguientes mecanismos:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>LockMode.WRITE</literal> se adquiere autom&#x00e1;ticamente cuando Hibernate actualiza o
+                    inserta una fila.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.UPGRADE</literal> puede ser adquirido bajo petici&#x00f3;n expl&#x00ed;cita del usuario
+                    usando <literal>SELECT ... FOR UPDATE</literal> en base de datos que soporten esa sint&#x00e1;xis.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.UPGRADE_NOWAIT</literal> puede ser adquirido bajo petici&#x00f3;n expl&#x00ed;cita del usuario
+                    usando un <literal>SELECT ... FOR UPDATE NOWAIT</literal> bajo Oracle.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.READ</literal> es adquirido autom&#x00e1;ticamente cuando Hibernate lee datos
+                    bajo los niveles de aislamiento Repeatable Read o Serializable. Puede ser readquirido por
+                    pedido expl&#x00ed;cito del usuario.
+                </para>
+            </listitem>
+        <listitem>
+        <para>
+            <literal>LockMode.NONE</literal> representa la ausencia de un bloqueo. Todos los objetos se pasan
+            a este modo de bloqueo al final de una <literal>Transaction</literal>. Los objetos asociados con una
+            sesi&#x00f3;n v&#x00ed;a una llamada a <literal>update()</literal> o <literal>saveOrUpdate()</literal> tambi&#x00e9;n
+            comienzan en este modo de bloqueo.
+        </para>
+        </listitem>
+        </itemizedlist>
+
+        <para>
+            La "petici&#x00f3;n expl&#x00ed;cita del usuario" se expresa en una de las siguientes formas:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Una llamada a <literal>Session.load()</literal>, especificando un <literal>LockMode</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Una llamada a <literal>Session.lock()</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Una llamada a <literal>Query.setLockMode()</literal>.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Si se llama a <literal>Session.load()</literal> con <literal>UPGRADE</literal> o
+            <literal>UPGRADE_NOWAIT</literal>, y el objeto pedido no ha sido a&#x00fa;n cargado por la sesi&#x00f3;n, el objeto es
+            cargado usando <literal>SELECT ... FOR UPDATE</literal>. Si se llama a <literal>load()</literal> para
+            un objeto que ya est&#x00e9; cargado con un bloqueo menos restrictivo que el pedido, Hibernate llama a
+            <literal>lock()</literal> para ese objeto.
+        </para>
+
+        <para>
+            <literal>Session.lock()</literal> realiza un chequeo de n&#x00fa;mero de versi&#x00f3;n si el modo de bloqueo especificado
+            es <literal>READ</literal>, <literal>UPGRADE</literal> o <literal>UPGRADE_NOWAIT</literal>. (En el caso de
+            <literal>UPGRADE</literal> o <literal>UPGRADE_NOWAIT</literal>, se usa
+            <literal>SELECT ... FOR UPDATE</literal>.)
+        </para>
+
+        <para>
+            Si la base de datos no soporta el modo de bloqueo solicitado, Hibernate usar&#x00e1; un modo alternativo
+            apropiado (en vez de lanzar una excepci&#x00f3;n). Esto asegura que las aplicaciones ser&#x00e1;n portables.
+        </para>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/tutorial.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/tutorial.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/tutorial.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1270 @@
+<chapter id="tutorial">
+    <title>Introducci&#x00f3;n a Hibernate</title>
+    
+    <sect1 id="tutorial-intro">
+        <title>Prefacio</title>
+        
+        <para>
+            Este cap&#x00ed;tulo es un tutorial introductorio de Hibernate. Comenzamos con
+            una aplicaci&#x00f3;n simple de l&#x00ed;nea de comandos usando un base de datos
+            en-memoria y desarroll&#x00e1;ndola en f&#x00e1;cil para entender los pasos.
+        </para>
+
+        <para>
+            Este tutorial est&#x00e1; concebido para usuarios nuevos de Hibernate pero
+            requiere conocimiento en Java y SQL. Est&#x00e1; basado en un tutorial de
+            Michael Gloegl. Las bibliotecas de terceros que mencionamos son para JDK 1.4
+            y 5.0. Podr&#x00ed;as necesitar otras para JDK 1.3.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="tutorial-firstapp">
+        <title>Parte 1 - La primera Aplicaci&#x00f3;n Hibernate</title>
+
+        <para>
+            Primero, crearemos una aplicaci&#x00f3;n simple de Hibenate basada en consola.
+            Usamos usamos una base de datos en-memoria (HSQL DB), de modo que no necesitamos
+            instalar ning&#x00fa;n servidor de base de datos.
+        </para>
+
+        <para>
+            Asumamos que necesitamos una aplicaci&#x00f3;n peque&#x00f1;a de base de datos que
+            pueda almacenar eventos que queremos atender, e informaci&#x00f3;n acerca de los
+            hostales de estos eventos.
+        </para>
+            
+        <para>
+            La primera cosa que hacemos, es armar nuestro directorio de desarrollo y poner
+            en &#x00e9;l todas las bibliotecas Java que necesitamos. Descarga la distribuci&#x00f3;n
+            de Hibernate del sitio web de Hibernate. Extrae el paquete y coloca todas las
+            bibliotecas requeridas encontradas en <literal>/lib</literal> dentro del directorio
+            <literal>/lib</literal> de nuestro nuevo directorio de desarrollo de trabajo.
+            Debe asemejarse a esto:
+        </para>
+            
+        <programlisting><![CDATA[.
++lib
+  antlr.jar
+  cglib-full.jar
+  asm.jar
+  asm-attrs.jars
+  commons-collections.jar
+  commons-logging.jar
+  ehcache.jar
+  hibernate3.jar
+  jta.jar
+  dom4j.jar
+  log4j.jar ]]></programlisting>
+
+        <para>
+            Este es el conjunto m&#x00ed;nimo de bibliotecas requeridas para Hibernate (observa que
+            tambi&#x00e9;n hemos copiado hibernate3.jar, el fichero principal). Ver el fichero
+            <literal>README.txt</literal> en el directorio <literal>lib/</literal> de la distribuci&#x00f3;n
+            de Hibernate para m&#x00e1;s informaci&#x00f3;n sobre bibliotecas de terceros requeridas y
+            opcionales. (Realmente, Log4J no es requerida aunque preferida por muchos desarrolladores).
+        </para>
+
+        <para>
+            Por siguiente, creamos una clase que represente el evento que queremos
+            almacenar en base de datos.
+        </para>
+      
+        <sect2 id="tutorial-firstapp-firstclass">
+            <title>La primera clase</title>
+            
+            <para>
+                Nuestra primera clase persistente es un JavaBean simple con algunas propiedades:
+            </para>
+
+            <programlisting><![CDATA[import java.util.Date;
+
+public class Event {
+    private Long id;
+
+    private String title;
+    private Date date;
+
+    Event() {}
+
+    public Long getId() {
+        return id;
+    }
+
+    private void setId(Long id) {
+        this.id = id;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+}]]></programlisting>
+
+            <para>
+                Puedes ver que esta clase usa las convenciones de nombrado est&#x00e1;ndar de JavaBean
+                para m&#x00e9;todos getter y setter de propiedad, as&#x00ed; como visibilidad privada
+                para los campos. Esto es un dise&#x00f1;o recomendado, aunque no requerido. Hibernate
+                tambi&#x00e9;n puede acceder a los campos directamente; el beneficio de los m&#x00e9;todos
+                de acceso es la robustez para la refactorizaci&#x00f3;n.
+            </para>
+
+            <para>
+                La propiedad <literal>id</literal> tiene un valor &#x00fa;nico de identificador para
+                un evento en particular. Todas las clase de entidad persistentes ( tambi&#x00e9;n hay
+                clases dependientes menos importantes) necesitar&#x00e1;n una propiedad identificadora
+                similar si queremos usar el conjunto completo de funcionalidades de Hibernate. De hecho,
+                la mayor&#x00ed;a de las aplicaciones (esp. aplicaciones web) necesitan distinguir
+                objetos por identificador, de modo que debes considerar esto como un aspecto en vez de una
+                limitaci&#x00f3;n. Sin embargo, usualmente no manipulamos la identidad de un objeto, por
+                lo tanto el m&#x00e9;todo setter debe ser privado. S&#x00f3;lo Hibernate asignar&#x00e1;
+                identificadores cuando un objeto sea salvado. Puedes ver que Hibernate puede acceder a
+                m&#x00e9;todos de acceso p&#x00fa;blicos, privados y protegidos, tanto como directamente a
+                campos (p&#x00fa;blicos, privados y protegidos). La elecci&#x00f3;n est&#x00e1; en ti,
+                y puedes ajustarla a tu dise&#x00f1;o de aplicaci&#x00f3;n.
+            </para>
+
+            <para>
+                El constructor sin argumentos es un requerimiento para todas las clases persistentes.
+                Hibernate tiene que crear objetos para ti, usando reflecci&#x00f3;n Java. El constructor
+                puede ser privado, sin embargo, la visibilidad de paquete es requerida para la generaci&#x00f3;n
+                de proxies en tiempo de ejecuci&#x00f3;n y la recuperaci&#x00f3;n de datos sin
+                instrumentaci&#x00f3;n del bytecode.
+            </para>
+
+            <para>
+                Coloca este fichero de c&#x00f3;digo Java en un directorio llamado <literal>src</literal>
+                en la carpeta de desarrollo. El directorio ahora debe verse como esto:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  Event.java]]></programlisting>
+
+            <para>
+                En el pr&#x00f3;ximo paso, le decimos a Hibernate sobre esta clase persistente.
+            </para>
+                
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-mapping">
+            <title>El fichero de mapeo</title>
+
+            <para>
+                Hibernate necesita saber c&#x00f3;mo cargar y almacenar objetos de la
+                clase persistente. Aqu&#x00ed; es donde el fichero de mapeo de Hibernate
+                entra en juego. El fichero de mapeo le dice a Hibernate a qu&#x00e9; tabla en
+                la base de datos tiene que acceder, y qu&#x00e9; columnas en esta tabla debe usar.
+            </para>
+
+            <para>
+                La estructura b&#x00e1;sica de un fichero de mapeo se parece a esto:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+[...]
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Observa que el DTD de Hibernate es muy sofisticado. Puedes usarlo para
+                autocompleci&#x00f3;n de los elementos y atributos XML de mapeo en tu
+                editor o IDE. Debes tambi&#x00e9;n abrir el fichero DTD en tu editor de
+                texto. Es la forma m&#x00e1;s f&#x00e1;cil para tener un panorama de todos
+                los elementos y atributos y ver los valores por defectos, as&#x00ed; como
+                algunos comentarios. Nota que Hibernate no cargar&#x00e1; el fichero DTD de
+                la web, sino que primero buscar&#x00e1; en el classpath de la aplicaci&#x00f3;n.
+                El fichero DTD est&#x00e1; inclu&#x00ed;do en <literal>hibernate3.jar</literal>
+                as&#x00ed; como tambi&#x00e9;n en el directorio <literal>src/</literal> de la
+                distribuci&#x00f3;n de Hibernate.
+            </para>
+
+            <para>
+                Omitiremos la declaraci&#x00f3;n de DTD en futuros ejemplos para acortar
+                el c&#x00f3;digo. Por supuesto, no es opcional.
+            </para>
+
+            <para>
+                Entre las dos etiquetas <literal>hibernate-mapping</literal>, incluye
+                un elemento <literal>class</literal>. Todas las clases de entidad
+                persistentes (de nuevo, podr&#x00ed;a haber m&#x00e1;s adelante clases
+                dependientes, que no sean entidades de-primera-clase) necesitan dicho mapeo
+                a una tabla en la base de datos SQL:
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Event" table="EVENTS">
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Hasta ahora dijimos a Hibernate c&#x00f3;mo persistir y cargar el objeto
+                de clase <literal>Event</literal> a la tabla <literal>EVENTS</literal>,
+                cada instancia representada por una fila en esta tabla. Ahora continuamos con
+                un mapeo de la propiedad de identificado &#x00fa;nico a la clave primaria
+                de la tabla. Adem&#x00e1;s, como no queremos cuidar del manejo de este identificador,
+                configuramos la estrategia de generaci&#x00f3;n de identificadores para una columna
+                clave primaria delegada:
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="increment"/>
+        </id>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                El elemento <literal>id</literal> el la declaraci&#x00f3;n de la propiedad
+                identificadora, <literal>name="id"</literal> declara el nombre de la
+                propiedad Java. Hibernate usar&#x00e1; los m&#x00e9;todos getter y setter
+                para acceder a la propiedad. El attributo de columna dice a Hibernate cu&#x00e1;l
+                columna de la tabla <literal>EVENTS</literal> usamos para esta clave primaria.
+                El elemento anidado <literal>generator</literal> especifica la estrategia de
+                generaci&#x00f3;n de identificadores, en este caso usamos <literal>increment</literal>,
+                que es un m&#x00e9;todo muy simple de incremento de n&#x00fa;mero en-memoria
+                &#x00fa;til mayormente para testeo (y tutoriales). Hibernate tambi&#x0e9;n
+                soporta identificadores generados por base de datos, globalmente &#x00fa;nicos,
+                as&#x00ed; como tambi&#x00e9;n asignados por aplicaci&#x00f3;n (o cualquier
+                estrategia para la que hayas escrito una extensi&#x00f3;n).
+            </para>
+
+            <para>
+                Finalmente inclu&#x00ed;mos declaraciones para las propiedades persistentes
+                de la clases en el fichero de mapeo. Por defecto, ninguna propiedad de la clase
+                se considera persistente:
+            </para>
+            
+            <programlisting><![CDATA[
+<hibernate-mapping>
+
+    <class name="Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="increment"/>
+        </id>
+        <property name="date" type="timestamp" column="EVENT_DATE"/>
+        <property name="title"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+            
+            <para>
+                Al igual que con el elemento <literal>id</literal>, el atributo <literal>name</literal>
+                del elemento <literal>property</literal> dice a Hibernate c&#x00e1;les m&#x00e9;todos
+                getter y setter usar.
+            </para>
+
+            <para>
+                ¿Por qu&#x00e9; el mapeo de la propiedad <literal>date</literal>
+                incluye el atributo <literal>column</literal>, pero el de la de
+                <literal>title</literal> no? Sin el atributo <literal>column</literal>
+                Hibernate usa por defecto el nombre de propiedad como nombre de columna.
+                Esto funciona bien para <literal>title</literal>. Sin embargo,
+                However, <literal>date</literal> es una palabra reservada en la
+                mayor&#x00ed;a de las bases de datos, as&#x00ed; que mejor la mapeamos
+                a un nombre diferente.
+            </para>
+
+            <para>
+                La pr&#x00f3;xima cosa interesante es que el mapeo de <literal>title</literal> 
+                carece de un atributo <literal>type</literal>. Los tipos que declaramos y usamos
+                en el fichero de mapeo no son, como podr&#x00ed;as esperar, tipos de datos Java.
+                Tampoco son tipos de base de datos SQL. Estos tipos son los llamados as&#x00ed;
+                <emphasis>Tipos de mapeo de Hibernate</emphasis>, convertidores que pueden
+                traducir de tipos Java a SQL y vice versa. De nuevo, Hibernate intentar&#x00e1;
+                determinar la conversi&#x00f3;n y el mapeo mismo de tipo correctos si el atributo
+                <literal>type</literal> no estuviese presente en el mapeo. En algunos casos esta
+                detecci&#x00f3;n autom&#x00e1;tica (usando reflecci&#x00f3;n en la clase Java)
+                puede no tener lo que esperas o necesitas. Este es el caso de la propiedad
+                <literal>date</literal>. Hibernate no puede saber is la propiedad mapear&#x00e1;
+                a una columna <literal>date</literal>, <literal>timestamp</literal> o
+                <literal>time</literal>. Declaramos que queremos preservar la informaci&#x00f3;n
+                completa de fecha y hora mapeando la propiedad con un <literal>timestamp</literal>.
+            </para>
+
+            <para>
+                Este fichero de mapeo debe ser salvado como <literal>Event.hbm.xml</literal>,
+                justo en el directorio pr&#x00f3;ximo al fichero de c&#x00f3;digo fuente de
+                la clase Java <literal>Event</literal>. El nombrado de los ficheros de mapeo
+                puede ser arbitrario, sin embargo, el sufijo <literal>hbm.xml</literal> se ha
+                vuelto una convenci&#x00f3;n el la comunidad de desarrolladores de Hibernate.
+                La estructura de directorio debe ahora verse como esto:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  Event.java
+  Event.hbm.xml]]></programlisting>
+
+             <para>
+                 Continuamos con la configuraci&#x00f3;n principal de Hibernate.
+             </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-configuration">
+            <title>Configuraci&#x00f3;n de Hibernate</title>
+
+            <para>
+                Tenemos ahora una clase persistente y su fichero de mapeo en su sitio. Es momento de
+                configurar Hibernate. Antes que hagamos esto, necesitaremos una base de datos.
+                HSQL DB, un DBMS SQL en-memoria basado en Java, puede ser descargado del sitio web
+                de HSQL DB. Realmente, de esta descarga s&#x00f3;lo necesitas el <literal>hsqldb.jar</literal>.
+                Coloca este fichero en el directorio <literal>lib/</literal> de la carpeta de desarrollo.
+            </para>
+
+            <para>
+                Crea un directorio llamado <literal>data</literal> en la ra&#x00ed;z del directorio de
+                desarrollo. All&#x00ed; es donde HSQL DB almacenar&#x00e1; sus ficheros de datos.
+            </para>
+
+            <para>
+                Hibernate es la capa en tu aplicaci&#x00f3;n que se conecta a esta base de datos,
+                de modo que necesita informaci&#x00f3;n de conexi&#x00f3;n. Las conexiones se hacen
+                a trav&#x00e9;s de un pool de conexiones JDBC, que tamb&#x00e9;n tenemos que configurar.
+                La distribuci&#x00f3;n de Hibernate contiene muchas herramientas de pooling de conexiones
+                JDBC de c&#x00f3;digo abierto, pero para este tutorial usaremos el pool de conexiones
+                prefabricado dentro de Hibernate. Observa que tienes que copiar la biblioteca requerida
+                en tu classpath y usar diferentes configuraciones de pooling de conexiones si quieres
+                usar un software de pooling JDBC de terceros de calidad de producci&#x00f3;n.
+            </para>
+
+            <para>
+                Para la configuraci&#x00f3;n de Hibernate, podemos usar un fichero
+                <literal>hibernate.properties</literal> simple, un fichero <literal>hibernate.cfg.xml</literal>
+                ligeramente m&#x00e1;s sofisticado, o incluso una configuraci&#x00f3;n completamente
+                program&#x00e1;tica. La mayor&#x00ed;a de los usuarios prefieren el fichero de
+                configuraci&#x00f3;n XML:
+            </para>
+
+            <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <session-factory>
+
+        <!-- Database connection settings -->
+        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
+        <property name="connection.url">jdbc:hsqldb:data/tutorial</property>
+        <property name="connection.username">sa</property>
+        <property name="connection.password"></property>
+
+        <!-- JDBC connection pool (use the built-in) -->
+        <property name="connection.pool_size">1</property>
+
+        <!-- SQL dialect -->
+        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
+
+        <!-- Echo all executed SQL to stdout -->
+        <property name="show_sql">true</property>
+
+        <!-- Drop and re-create the database schema on startup -->
+        <property name="hbm2ddl.auto">create</property>
+
+        <mapping resource="Event.hbm.xml"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+            <para>
+                Observa que esta configuraci&#x00f3;n XML usa un DTD diferente.
+                Configuramos la <literal>SessionFactory</literal> de Hibernate, una
+                f&#x00e1;brica global responsable de una base de datos en particular.
+                Si tienes varias bases de datos, usa varias configuraciones
+                <literal>&lt;session-factory&gt;</literal> , usualmente en varios
+                ficheros de configuraci&#x00f3;n (para un arranque m&#x00e1;s f&#x00e1;cil).
+            </para>
+
+            <para>
+                Los primeros cuatro elementos <literal>property</literal> contienen la configuraci&#x00f3;n
+                necesaria para la conexi&#x00f3;n JDBC. El elemento de dialecto <literal>property</literal>
+                especifica la variante de SQL en particular que genera Hibernate. La opci&#x00f3;n
+                <literal>hbm2ddl.auto</literal> activa la generaci&#x00f3;n autom&#x00e1;tica de esquemas
+                de base de datos, directamente en la base de datos. Esto, por supuesto, puede desactivarse
+                (quitando la opci&#x00f3;n config) o redirigido a un fichero con la ayuda de la tarea
+                de Ant <literal>SchemaExport</literal>. Finalmente, agregamos el(los) fichero(s) de mapeo
+                para clases persistentes.
+            </para>
+
+            <para>
+                Copia este fichero dentro del directorio de c&#x00f3;digo fuente, de modo que
+                termine ubicado en la rai&#x00ed;z del classpath. Hibernate busca autom&#x00e1;ticamente
+                un fichero llamado <literal>hibernate.cfg.xml</literal> en la ra&#x00ed;z del classpath
+                al arrancar.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-ant">
+            <title>Construyendo con Ant</title>
+
+            <para>
+                Construiremos ahora el tutorial con Ant. Necesitar&#x00e1;s tener Ant instalado.
+                Obt&#x00e9;nlo de <ulink url="http://ant.apache.org/bindownload.cgi">P&#x00e1;gina
+                de descarga de Ant</ulink>. No se cubrir&#x00e1; aqu&#x00ed; c&#x00f3;mo instalar Ant.
+                Por favor refi&#x00e9;rete al <ulink url="http://ant.apache.org/manual/index.html">
+                Manual de Ant</ulink>. Despu&#x00e9;s que hayas instalado Ant, podemos comenzar a
+                crear el buildfile. Ser&#x00e1; llamado <literal>build.xml</literal> y colocado
+                directamente en el directorio de desarrollo.
+            </para>
+
+            <note>
+                <title>Reparar Ant</title>
+                <para>
+                    Observa que la distribuci&#x00f3;n de Ant est&#x00e1; por defecto rota
+                    (como se describe en el FAQ de Ant) y tiene que ser reparado por ti,
+                    por ejemplo, si quisieras usar JUnit desde dentro de tu fichero de construcci&#x00f3;n.
+                    Para hacer que funcione la tarea de JUnit (no lo necesitaremos en este tutorial),
+                    copia junit.jar a <literal>ANT_HOME/lib</literal> o quita el trozo de plugin
+                    <literal>ANT_HOME/lib/ant-junit.jar</literal>.
+                </para>
+            </note>
+
+            <para>
+                Un fichero de construcci&#x00f3;n b&#x00e1;sico se ve como esto:
+            </para>
+
+            <programlisting><![CDATA[<project name="hibernate-tutorial" default="compile">
+
+    <property name="sourcedir" value="${basedir}/src"/>
+    <property name="targetdir" value="${basedir}/bin"/>
+    <property name="librarydir" value="${basedir}/lib"/>
+
+    <path id="libraries">
+        <fileset dir="${librarydir}">
+            <include name="*.jar"/>
+        </fileset>
+    </path>
+
+    <target name="clean">
+        <delete dir="${targetdir}"/>
+        <mkdir dir="${targetdir}"/>
+    </target>
+
+    <target name="compile" depends="clean, copy-resources">
+      <javac srcdir="${sourcedir}"
+             destdir="${targetdir}"
+             classpathref="libraries"/>
+    </target>
+
+    <target name="copy-resources">
+        <copy todir="${targetdir}">
+            <fileset dir="${sourcedir}">
+                <exclude name="**/*.java"/>
+            </fileset>
+        </copy>
+    </target>
+
+</project>]]></programlisting>
+
+            <para>
+                Esto dir&#x00e1; a Ant que agregue todos los ficheros en el directorio lib que terminen con
+                <literal>.jar</literal> al classpath usado para la compilaci&#x00f3;n. Tambi&#x00e9;n copiar&#x00e1;
+                todos los ficheros que no sean c&#x00f3;digo Java al directorio objetivo, por ejemplo,
+                ficheros de configuraci&#x00f3;n y mapeos de Hibernate. Si ahora corres Ant, debes obtener
+                esta salida:
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant
+Buildfile: build.xml
+
+copy-resources:
+     [copy] Copying 2 files to C:\hibernateTutorial\bin
+
+compile:
+    [javac] Compiling 1 source file to C:\hibernateTutorial\bin
+
+BUILD SUCCESSFUL
+Total time: 1 second ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-helpers">
+            <title>Arranque y ayudantes</title>
+
+            <para>
+                Es momento de cargar y almacenar algunos objetos <literal>Event</literal>,
+                pero primero tenemos que completar la configuraci&#x00f3;n de alg&#x00fa;n
+                c&#x00f3;digo de infraestructura. Tenemos que arrancar Hibernate. Este
+                arranque incluye construir un objeto <literal>SessionFactory</literal> global
+                y almacenarlo en alg&#x00fa;n sitio de f&#x00e1;cil acceso en el c&#x00f3;digo
+                de aplicaci&#x00f3;n. Una <literal>SessionFactory</literal> puede abrir nuevas
+                <literal>Session</literal>'s. Una <literal>Session</literal> representa un unidad
+                de trabajo mono-hebra. La <literal>SessionFactory</literal> es un objeto global
+                seguro entre hebras, instanciado una sola vez.
+            </para>
+
+            <para>
+                Crearemos una clase de ayuda <literal>HibernateUtil</literal> que cuide del
+                arranque y haga conveniente el manejo de <literal>Session</literal>.
+                El as&#x00ed; llamado patr&#x00f3;n <emphasis>Sesi&#x00f3;n de Hebra Local
+                (ThreadLocal Session)</emphasis> es &#x00fa;til aqu&#x00ed;; mantenemos la unidad
+                de trabajo actual asociada a la hebra actual. Echemos una mirada a la implementaci&#x00f3;n:
+            </para>
+
+            <programlisting><![CDATA[import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+    public static final SessionFactory sessionFactory;
+
+    static {
+        try {
+            // Create the SessionFactory from hibernate.cfg.xml
+            sessionFactory = new Configuration().configure().buildSessionFactory();
+        } catch (Throwable ex) {
+            // Make sure you log the exception, as it might be swallowed
+            System.err.println("Initial SessionFactory creation failed." + ex);
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    public static final ThreadLocal session = new ThreadLocal();
+
+    public static Session currentSession() throws HibernateException {
+        Session s = (Session) session.get();
+        // Open a new Session, if this thread has none yet
+        if (s == null) {
+            s = sessionFactory.openSession();
+            // Store it in the ThreadLocal variable
+            session.set(s);
+        }
+        return s;
+    }
+
+    public static void closeSession() throws HibernateException {
+        Session s = (Session) session.get();
+        if (s != null)
+            s.close();
+        session.set(null);
+    }
+}]]></programlisting>
+
+            <para>
+                Esta clase no &#x00f3;lo produce la <literal>SessionFactory</literal> global en
+                su inicializador static (llamado s&#x00f3;lo una vez por la JVM al cargar la clase),
+                sino que tambi&#x00e9;n tiene una variable <literal>ThreadLocal</literal> para
+                tener la <literal>Session</literal> para la hebra actual. No importa cu&#x00e1;ndo
+                llames a <literal>HibernateUtil.currentSession()</literal>, siempre devolver&#x00e1;
+                la misma unidad de trabajo de Hibernate en la misma hebra. Una llamada a
+                <literal>HibernateUtil.closeSession()</literal> termina la unidad de trabajo actualmente
+                asociada a la hebra.
+            </para>
+
+            <para>
+                Aseg&#x00fa;rate de entender el concepto Java de una variable local a una hebra antes
+                de usar esta ayuda. Una clase <literal>HibernateUtil</literal> m&#x00e1;s potente puede
+                encontrarse en <literal>CaveatEmptor</literal>, http://caveatemptor.hibernate.org/, 
+                as&#x00ed; como en el libro "Hibernate in Action". Observa que esta clase no es necesaria
+                si despliegas Hibernate en un servidor de aplicaciones J2EE: una <literal>Session</literal>
+                ser&#x00e1; autom&#x00e1;ticamente ligada a la transacci&#x00f3;n JTA actual, y puedes
+                buscar la <literal>SessionFactory</literal> a trav&#x00e9;s de JNDI. Si usas JBoss AS,
+                Hibernate puede ser desplegado como un servicio de sistema manejado y autom&#x00e1;ticamente
+                ligar&#x00e1; la <literal>SessionFactory</literal> a un nombre JNDI.
+            </para>
+
+            <para>
+                Coloca <literal>HibernateUtil.java</literal> en el directorio de fuentes de desarrollo,
+                junto a <literal>Event.java</literal>:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  Event.java
+  Event.hbm.xml
+  HibernateUtil.java
+  hibernate.cfg.xml
++data
+build.xml]]></programlisting>
+
+            <para>
+                Esto tambi&#x00e9;n debe compilar sin problemas. Finalmente necesitamos configurar
+                un sistema de logging (registro). Hibernate usa commons logging y te deja la elecci&#x00f3;n
+                entre Log4J y logging de JDK 1.4. La mayor&#x00ed;a de los desarrolladores prefieren
+                Log4J: copia <literal>log4j.properties</literal> de la distribuci&#x00f3;n de Hibernate
+                (est&#x00e1; en el directorio <literal>etc/</literal>) a tu directorio <literal>src</literal>,
+                junto a <literal>hibernate.cfg.xml</literal>. Echa una mirada a la configuraci&#x00f3;n de
+                ejemplo y cambia los ajustes si te gusta tener una salida m&#x00e1;s verborr&#x00e1;gica.
+                Por defecto, s&#x00f3;lo se muestra el mensaje de arranque de Hibernate en la salida.
+            </para>
+
+            <para>
+                La infraestructura del tutorial est&#x00e1; completa, y estamos listos para hacer
+                alg&#x00fa;n trabajo real con Hibernate.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-workingpersistence">
+            <title>Cargando y almacenando objetos</title>
+
+            <para>
+                Finalmente, podemos usar Hibernate para cargar y almacenar objetos.
+                Escribimos una clase <literal>EventManager</literal> con un m&#x00e9;todo
+                <literal>main()</literal>:
+            </para>
+
+            <programlisting><![CDATA[import org.hibernate.Transaction;
+import org.hibernate.Session;
+
+import java.util.Date;
+
+public class EventManager {
+
+    public static void main(String[] args) {
+        EventManager mgr = new EventManager();
+
+        if (args[0].equals("store")) {
+            mgr.createAndStoreEvent("My Event", new Date());
+        }
+
+        HibernateUtil.sessionFactory.close();
+    }
+
+}]]></programlisting>
+
+            <para>
+                Leemos algunos argumentos de la l&#x00ed;nea de comandos, y si el primer
+                argumento es "store", creamos y almacenamos un nuevo Event:
+            </para>
+
+            <programlisting><![CDATA[private void createAndStoreEvent(String title, Date theDate) {
+    Session session = HibernateUtil.currentSession();
+    Transaction tx = session.beginTransaction();
+
+    Event theEvent = new Event();
+    theEvent.setTitle(title);
+    theEvent.setDate(theDate);
+
+    session.save(theEvent);
+
+    tx.commit();
+    HibernateUtil.closeSession();
+}]]></programlisting>
+
+            <para>
+                Creamos un nuevo objeto <literal>Event</literal>, y se lo damos a Hibernate.
+                Hibernate cuida ahora del SQL y ejecuta <literal>INSERT</literal>s en la base
+                de datos. Echemos una mirada al c&#x00f3;digo de manejo de <literal>Session</literal>
+                y <literal>Transaction</literal> antes de ejecutar esto.
+            </para>
+
+            <para>
+                Una <literal>Session</literal> es una sola unidad de trabajo. Podr&#x00ed;a sorprenderte
+                que tengamos una API adicional, <literal>Transaction</literal>. Esto implica que una unidad
+                de trabajo puede ser "m&#x00e1;s larga" que una sola transacci&#x00f3;n de base de datos;
+                imagina una unidad de trabajo que se abarca varios ciclos petici&#x00f3;n/respuesta HTTP
+                (por ejemplo, un di&#x00e1;logo asistente) en una aplicaci&#x00f3;n web. Separar las
+                transacciones de base de datos de "las unidades de trabajo de la aplicaci&#x00f3;n desde
+                el punto de vista del usuario" es uno de los conceptos b&#x00e1;sicos de dise&#x00f1;o de
+                Hibernate. Llamamos una unidad de trabajo larga <emphasis>Transacci&#x00f3;n de
+                Aplicaci&#x00f3;n</emphasis>, usualmente encapsulando varias transacciones de base de
+                datos m&#x00e1;s cortas. Por ahora mantendremos las cosas simples y asumiremos una
+                granularidad uno-a-uno entre una <literal>Session</literal> y una <literal>Transaction</literal>.
+            </para>
+
+            <para>
+                ¿Qu&#x00e9; es lo que hacen <literal>Transaction.begin()</literal> y <literal>commit()</literal>?
+                ¿D&#x00f3;nde est&#x00e1; el rollback en caso que algo vaya mal? La API de <literal>Transaction</literal>
+                de Hibernate es opcional realmente, pero la usamos por conveniencia y portabilidad. Si manejases
+                la transacci&#x00f3;n de base de datos por ti mismo (por ejemplo, llamando a 
+                <literal>session.connection.commit()</literal>), ligar&#x00ed;as el c&#x00f3;digo a un entorno
+                de despliegue particular, en este JDBC directo no manejado. Estableciendo la f&#x00e1;brica
+                de <literal>Transaction</literal> en tu configuraci&#x00f3;n de Hibernate puedes desplegar
+                tu capa de persistencia en cualquier sitio. Echa una mirada al <xref linkend="transactions"/>
+                para m&#x00e1;s informaci&#x00f3;n sobre manejo y demarcaci&#x00f3;n de transacciones.
+                Hemos saltado tambi&#x00e9;n cualquier manejo de excepciones y rollback en este ejemplo.
+            </para>
+
+            <para>
+                Para ejecutar la primera rutina tenemos que agregar un objetivo llamable al fichero
+                de construcci&#x00f3;n de Ant:
+            </para>
+
+            <programlisting><![CDATA[<target name="run" depends="compile">
+    <java fork="true" classname="EventManager" classpathref="libraries">
+        <classpath path="${targetdir}"/>
+        <arg value="${action}"/>
+    </java>
+</target>]]></programlisting>
+
+            <para>
+                El valor del argumento <literal>action</literal> es establecido por l&#x00ed;nea de
+                comandos al llamar al objetivo:
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant run -Daction=store]]></programlisting>
+
+            <para>
+                Debes ver, despu&#x00e9;s de la compilaci&#x00f3;n, a Hibernate arrancando y, dependiendo
+                de tu configuraci&#x00f3;n mucha salida de registro (log). Al final encontrar&#x00e1;s
+                la siguiente l&#x00ed;nea:
+            </para>
+
+            <programlisting><![CDATA[[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)]]></programlisting>
+
+            <para>
+                Esta es la <literal>INSERT</literal> ejecutada por Hibernate, los signos de preguntas
+                representan par&#x00e1;metros de ligado JDBC. Para ver los valores ligados como
+                argumentos, o para reducir la verborragia del registro, chequea tu
+                <literal>log4j.properties</literal>.
+            </para>
+
+            <para>
+                Ahora quisi&#x00e9;ramos listar acontecimientos almacenados tambi&#x00e9;n,
+                as&#x00ed; que agregamos una opci&#x00f3;n al m&#x00e9;todo principal:
+            </para>
+
+            <programlisting><![CDATA[if (args[0].equals("store")) {
+    mgr.createAndStoreEvent("My Event", new Date());
+}
+else if (args[0].equals("list")) {
+    List events = mgr.listEvents();
+    for (int i = 0; i < events.size(); i++) {
+        Event theEvent = (Event) events.get(i);
+        System.out.println("Event: " + theEvent.getTitle() +
+                           " Time: " + theEvent.getDate());
+    }
+}]]></programlisting>
+
+            <para>
+                Agregamos tambi&#x00e9;n un nuevo m&#x00e9;todo <literal>listEvents()</literal>:
+            </para>
+
+            <programlisting><![CDATA[private List listEvents() {
+    Session session = HibernateUtil.currentSession();
+    Transaction tx = session.beginTransaction();
+
+    List result = session.createQuery("from Event").list();
+
+    tx.commit();
+    session.close();
+
+    return result;
+}]]></programlisting>
+
+            <para>
+                Lo que hacemos aqu&#x00ed; es usar una consulta HQL (Lenguaje de Consulta de Hibernate
+                o Hibernate Query Language) para cargar todos los objetos <literal>Event</literal>
+                existentes de la base de datos. Hibernate generar&#x00e1; el SQL apropiado, lo enviar&#x00e1;
+                a la base de datosy poblar&#x00e1; los objetos <literal>Event</literal> con datos.
+                Puedes, por supuesto, crear consultas m&#x00e1;s complejas con HQL.
+            </para>
+
+            <para>
+                Si ahora llamas a Ant con <literal>-Daction=list</literal>, debes ver los eventos
+                que has almacenado hasta ahora. Puede sorprenderte que esto no funcione, al menos
+                si has seguido este tutorial paso por paso; el resultado siempre estar&#x00e1;
+                vac&#x00ed;o. La razon de esto es la opci&#x00f3;n <literal>hbm2ddl.auto</literal>
+                en la configuraci&#x00f3;n de Hibernate: Hibernate recrear&#x00e1; la base de datos
+                en cada ejecuci&#x00f3;n. Deshabil&#x00ed;tala quitando la opci&#x00f3;n, y ver&#x00e1;s
+                resultados en tu listado despu&#x00e9;s que llames a la acci&#x00f3;n <literal>store</literal>
+                unas cuantas veces. La generaci&#x00f3;n y exportaci&#x00f3;n de esquema es &#x00fa;til
+                mayormente en testeo unitario.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="tutorial-associations">
+        <title>Part 2 - Mapeando asociaciones</title>
+
+        <para>
+            Hemos mapeado un clase de entidad persistente a una tabla. Construyamos sobre esto y agreguemos
+            algunas asociaciones de clase. Primero agregaremos personas a nuestra aplicaci&#x00f3;n,
+            y almacenaremos una lista de eventos en las que participan.
+        </para>
+
+        <sect2 id="tutorial-associations-mappinguser">
+            <title>Mapeando la clase Person</title>
+
+            <para>
+                El primer corte de la clase <literal>Person</literal> es simple:
+            </para>
+
+            <programlisting><![CDATA[public class Person {
+
+    private Long id;
+    private int age;
+    private String firstname;
+    private String lastname;
+
+    Person() {}
+
+    // Accessor methods for all properties, private setter for 'id'
+
+}]]></programlisting>
+
+            <para>
+                Crea un fichero de mapeo llamado <literal>Person.hbm.xml</literal>:
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Person" table="PERSON">
+        <id name="id" column="PERSON_ID">
+            <generator class="increment"/>
+        </id>
+        <property name="age"/>
+        <property name="firstname"/>
+        <property name="lastname"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Finalmente, agrega el nuevo mapeo a la configuraci&#x00f3;n de Hibernate:
+            </para>
+
+            <programlisting><![CDATA[        <mapping resource="Event.hbm.xml"/>
+        <mapping resource="Person.hbm.xml"/>
+]]></programlisting>
+
+            <para>
+                Crearemos ahora una asociaci&#x00f3;n entre estas dos entidades. Obviamente,
+                las personas pueden participar en eventos, y los eventos tienen participantes.
+                Las cuestiones de dise&#x00f1;o con que tenemos que tratar son: direccionalidad,
+                multiplicidad y comportamiento de colecci&#x00f3;n.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-unidirset">
+            <title>Una asociaci&#x00f3;n unidireccional basada en Set</title>
+
+            <para>
+                Agregaremos una colecci&#x00f3;n de eventos a la clase <literal>Person</literal>.
+                De esta forma podemos navegar facilmente a los eventos de una persona en particular,
+                sin ejecutar una consulta expl&#x00ed;cita, llamando a <literal>aPerson.getEvents()</literal>.
+                Usamos una colecci&#x00f3;n Java, un <literal>Set</literal>, porque la colecci&#x00f3;n no
+                contendr&#x00e1; elementos duplicados y el ordenamiento no nos es relevante.
+            </para>
+
+            <para>
+                Hasta ahora hemos dise&#x00f1;ado asociaciones unidireccionales multivaluadas, implementadas con un
+                <literal>Set</literal>. Escribamos el c&#x00f3;digo para esto en las clases Java y luego lo
+                mapeemos:
+            </para>
+
+            <programlisting><![CDATA[public class Person {
+
+    private Set events = new HashSet();
+
+    public Set getEvents() {
+        return events;
+    }
+
+    public void setEvents(Set events) {
+        this.events = events;
+    }
+}]]></programlisting>
+
+            <para>
+                Antes que mapeemos esta asociaci&#x00f3;n, piensa sobre el otro lado. Claramente, podemos
+                mantener esto solamente unidireccional. O podemos crear otra colecci&#x00f3;n en el
+                <literal>Event</literal>, si queremos ser capaces de navegarlos bidireccionalmente;
+                por ejemplo, <literal>anEvent.getParticipants()</literal>. Esta es una elecci&#x00f3;n
+                de dise&#x00f1;o que recae en ti, pero lo que est&#x00e1; claro de esta discusi&#x00f3;n
+                es la multiplicidad de la asociaci&#x00f3;n: "multi" valuada a ambos lados, llamamos a esto
+                una asociaci&#x00f3;n <emphasis>muchos-a-muchos</emphasis>. Por lo tanto, usamos un mapeo
+                many-to-many de Hibernate:
+            </para>
+
+            <programlisting><![CDATA[<class name="Person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="increment"/>
+    </id>
+    <property name="age"/>
+    <property name="firstname"/>
+    <property name="lastname"/>
+
+    <set name="events" table="PERSON_EVENT">
+        <key column="PERSON_ID"/>
+        <many-to-many column="EVENT_ID" class="Event"/>
+    </set>
+
+</class>]]></programlisting>
+
+            <para>
+                Hibernate soporta todo tipo de mapeos de colecci&#x00f3;n, siendo el m&#x00e1;s com&#x00fa;n
+                un <literal>&lt;set&gt;</literal>. Para una asociaci&#x00f3;n muchos-a-muchos (o relaci&#x00f3;n
+                de entidad <emphasis>n:m</emphasis>), se necesita una tabla de asociaci&#x00f3;n. Cada fila en esta
+                tabla representa un enlace entre una persona y un evento. Esta tabla se configura con el atributo
+                <literal>table</literal> del elemento <literal>set</literal>. El nombre de la columna identificadora
+                en la asociaci&#x00f3;n, para el lado de la persona, se define con el elemento
+                <literal>&lt;key&gt;</literal>. El nombre de columna para el lado del evento se define con el atributo
+                <literal>column</literal> del <literal>&lt;many-to-many&gt;</literal>. Tambi&#x00e9;n tienes que decirle
+                a Hibernate la clase de los objetos en tu colecci&#x00f3;n (correcto: la clase del otro lado de la
+                colecci&#x00f3;n de referencias).
+            </para>
+
+            <para>
+                El esquema de base de datos para este mapeo es, por lo tanto:
+            </para>
+
+            <programlisting><![CDATA[
+    _____________        __________________
+   |             |      |                  |       _____________
+   |   EVENTS    |      |   PERSON_EVENT   |      |             |
+   |_____________|      |__________________|      |    PERSON   |
+   |             |      |                  |      |_____________|
+   | *EVENT_ID   | <--> | *EVENT_ID        |      |             |
+   |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  |
+   |  TITLE      |      |__________________|      |  AGE        |
+   |_____________|                                |  FIRSTNAME  |
+                                                  |  LASTNAME   |
+                                                  |_____________|
+ ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-working">
+            <title>Trabajando la asociaci&#x00f3;n</title>
+
+            <para>
+                Traigamos alguna gente y eventos juntos en un nuevo m&#x00e9;todo en
+                <literal>EventManager</literal>:
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+    Session session = HibernateUtil.currentSession();
+    Transaction tx = session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    aPerson.getEvents().add(anEvent);
+
+    tx.commit();
+    HibernateUtil.closeSession();
+}]]></programlisting>
+
+            <para>
+                Despu&#x00e9;s de cargar una <literal>Person</literal> y un <literal>Event</literal>, simplemente
+                modifica la colecci&#x00f3;n usando sus m&#x00e9;todos normales. Como puedes ver, no hay una llamada
+                expl&#x00ed;cita a <literal>update()</literal> o <literal>save()</literal>. Hibernate detecta
+                autom&#x00e1;ticamente que la colecci&#x00f3;n ha sido modificada y necesita ser salvada. Esto
+                es llamado <emphasis>chequeo sucio autom&#x00f3;tico (automatic dirty checking)</emphasis>, y
+                tambi&#x00e9;n puedes intentarlo modificando el nombre de la propiedad de fecha de cualquiera de tus
+                objetos. Mientras est&#x00e9;n en estado <emphasis>persistente</emphasis>, esto es, ligados a una
+                <literal>Session</literal> de Hibernate particular (es decir, justo han sido cargados o almacenados
+                en una unidad de trabajo), Hibernate monitoriza cualquier cambio y ejecuta SQL en estilo
+                escribe-por-detr&#x00e1;s. El proceso de sincronizaci&#x00f3;n del estado de memoria con la base
+                de datos, usualmente s&#x00f3;lo al final de una unidad de trabajo,
+                es llamado <emphasis>limpieza (flushing)</emphasis>.
+            </para>
+
+            <para>
+                Podr&#x00ed;as, por supuesto, cargar persona y evento en unidades de trabajo diferentes. O
+                modificas un objeto fuera de una <literal>Session</literal>, cuando no est&#x00e1; en estado
+                persistente (si antes era persistente llamamos a este estado <emphasis>separado (detached)
+                </emphasis>). En c&#x00f3;digo (no muy realista), esto se ver&#x00ed;a como sigue:
+            </para>
+
+            <programlisting><![CDATA[    private void addPersonToEvent(Long personId, Long eventId) {
+
+        Session session = HibernateUtil.currentSession();
+        Transaction tx = session.beginTransaction();
+
+        Person aPerson = (Person) session.load(Person.class, personId);
+        Event anEvent = (Event) session.load(Event.class, eventId);
+
+        tx.commit();
+        HibernateUtil.closeSession();
+
+        aPerson.getEvents().add(anEvent); // aPerson is detached
+
+        Session session2 = HibernateUtil.currentSession();
+        Transaction tx2 = session.beginTransaction();
+
+        session2.update(aPerson); // Reattachment of aPerson
+
+        tx2.commit();
+        HibernateUtil.closeSession();
+    }
+]]></programlisting>
+
+            <para>
+                La llamada a <literal>update</literal> hace a un objeto persistente de nuevo, podr&#x00ed;as
+                decir que la liga a una nueva unidad de trabajo, de modo que cualquier modificaci&#x00f3;n que
+                le hagas mientras est&#x00e9; separado puede ser salvada a base de datos.
+            </para>
+
+            <para>
+                Bueno, esto no es muy usado en nuestra situaci&#x00f3;n actual, pero es un concepto
+                importante que puedes dise&#x00f1;ar en tu propia aplicaci&#x00f3;n. Por ahora, completa
+                este ejercicio agregando una nueva acci&#x00f3;n al m&#x00e9;todo main de
+                <literal>EventManager</literal> y ll&#x00e1;mala desde la l&#x00ed;nea de comandos.
+                Si necesitas los identificadores de una persona o evento, el m&#x00e9;todo
+                <literal>save()</literal> los devuelve.
+            </para>
+
+            <para>
+                Esto fue un ejemplo de una asociaci&#x00f3;n entre dos clases igualmente importantes, dos entidades.
+                Como se ha mencionado anteriormente, hay otras clases y tipos en un modelo t&#x00ed;pico,
+                usualmente "menos importantes". Algunos ya los habr&#x00e1;s visto, como un <literal>int</literal>
+                o un <literal>String</literal>. Llamamos a estas clases <emphasis>tipos de valor (value types)</emphasis>,
+                y sus instancias <emphasis>dependen</emphasis> de una entidad en particular. Las instancias de estos
+                tipos no tienen su propia identidad, ni son compartidas entre entidades (dos personas no referencian
+                el mismo objeto <literal>firstname</literal>, incluso si tuvieran el mismo primer nombre). Por supuesto,
+                los tipos de valor no s&#x00f3;lo pueden encontrarse en el JDK (de hecho, en una aplicaci&#x00f3;n
+                Hibernate todas las clases del JDK son consideradas tipos de valor), sino que adem&#x00e1;s puedes
+                escribir por ti mismo clases dependientes, por ejemplo, <literal>Address</literal> o
+                <literal>MonetaryAmount</literal>.
+            </para>
+
+            <para>
+                Tambi&#x00e9;n puedes dise&#x00f1;ar una colecci&#x00f3;n de tipos de valor. Esto es conceptualmente
+                muy diferente de una colecci&#x00f3;n de referencias a otras entidades, pero se ve casi lo mismo en
+                Java.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-valuecollections">
+            <title>Colecci&#x00f3;n de valores</title>
+
+            <para>
+                Agregamos una colecci&#x00f3;n de objetos tipificados en valor a la entidad <literal>Person</literal>.
+                Queremos almacenar direcciones de email, de modo que el tipo que usamos es <literal>String</literal>,
+                y la colecci&#x00f3;n es nuevamente un <literal>Set</literal>:
+            </para>
+            <programlisting><![CDATA[private Set emailAddresses = new HashSet();
+
+public Set getEmailAddresses() {
+    return emailAddresses;
+}
+
+public void setEmailAddresses(Set emailAddresses) {
+    this.emailAddresses = emailAddresses;
+}]]></programlisting>
+
+            <para>
+                El mapeo de este <literal>Set</literal>:
+            </para>
+
+            <programlisting><![CDATA[<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
+    <key column="PERSON_ID"/>
+    <element type="string" column="EMAIL_ADDR"/>
+</set>]]></programlisting>
+
+            <para>
+                La diferencia comparada con el mapeo anterior es la parte <literal>element</literal>, que le dice
+                a Hibernate que la colecci&#x00f3;n no contiene referencias a otra entidad, sino una colecci&#x00f3;n
+                de elementos de tipo <literal>String</literal> (el nombre en min&#x00fa;sculas te dice que es un
+                tipo/conversor de mapeo de Hibernate). Una vez m&#x00e1;s, el atributo <literal>table</literal> del
+                elemento <literal>set</literal> determina el nombre de la tabla para la colecci&#x00f3;n. El elemento
+                <literal>key</literal> define el nombre de la columna clave for&#x00e1;nea en la tabla de colecci&#x00f3;n.
+                El atributo <literal>column</literal> en el elemento <literal>element</literal> define el nombre de
+                columna donde realmente ser&#x00e1;n almacenados los valores <literal>String</literal>.
+            </para>
+
+            <para>
+                Echa una mirada al esquema actualizado:
+            </para>
+
+            <programlisting><![CDATA[
+  _____________        __________________
+ |             |      |                  |       _____________
+ |   EVENTS    |      |   PERSON_EVENT   |      |             |       ___________________
+ |_____________|      |__________________|      |    PERSON   |      |                   |
+ |             |      |                  |      |_____________|      | PERSON_EMAIL_ADDR |
+ | *EVENT_ID   | <--> | *EVENT_ID        |      |             |      |___________________|
+ |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  | <--> |  *PERSON_ID       |
+ |  TITLE      |      |__________________|      |  AGE        |      |  *EMAIL_ADDR      |
+ |_____________|                                |  FIRSTNAME  |      |___________________|
+                                                |  LASTNAME   |
+                                                |_____________|
+ ]]></programlisting>
+
+            <para>
+                Puedes ver que la clave primaria de la tabla de colecci&#x00f3;n es de hecho una clave
+                compuesta, usando ambas columnas. Esto implica tambi&#x00e9;n que no pueden haber
+                direcciones de email duplicadas por persona, que es exactamente la sem&#x00e1;ntica
+                que necesitamos para un conjunto en Java.
+            </para>
+
+            <para>
+                Puedes ahora intentar y agregar elementos a esta colecci&#x00f3;n, al igual que
+                hicimos antes enlazando personas y eventos. Es el mismo c&#x00f3;digo en Java.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-bidirectional">
+            <title>Asociaciones bidireccionales</title>
+
+            <para>
+                A continuacion vamos a mapear una asociaci&#x00f3;n bidireccional, haciendo que la
+                asociaci&#x00f3;n entre persona y evento funcione desde ambos lados en Java. Por supuesto,
+                el esquema de base de datos no cambia; todav&#x00ed;a necesitamos multiplicidad muchos-a-muchos.
+                Una base de datos relacional es m&#x00e1;s flexible que un lenguaje de programaci&#x00f3;n
+                de red, as&#x00ed; que no necesita nada parecido a una direcci&#x00f3;n de navegaci&#x00f3;n;
+                los datos pueden ser vistos y recuperados en cualquier forma posible.
+            </para>
+
+            <para>
+                Primero agrega una colecci&#x00f3;n de participantes a la clase de eventos
+                <literal>Event</literal>:
+            </para>
+
+            <programlisting><![CDATA[private Set participants = new HashSet();
+
+public Set getParticipants() {
+    return participants;
+}
+
+public void setParticipants(Set participants) {
+    this.participants = participants;
+}]]></programlisting>
+
+            <para>
+                Ahora mapea este lado de la asociaci&#x00f3;n tambi&#x00e9;n, en
+                <literal>Event.hbm.xml</literal>.
+            </para>
+
+            <programlisting><![CDATA[<set name="participants" table="PERSON_EVENT" inverse="true">
+    <key column="EVENT_ID"/>
+    <many-to-many column="PERSON_ID" class="Person"/>
+</set>]]></programlisting>
+
+            <para>
+                Como ves, estos son mapeos normales de <literal>set</literal> en ambos documentos de
+                mapeo. Nota que los nombres de columnas en <literal>key</literal> y
+                <literal>many-to-many</literal> fueron permutados en ambos documentos de mapeo. Aqu&#x00ed; la
+                adici&#x00f3;n m&#x00e1;s importante es el atributo <literal>inverse="true"</literal> en el
+                elemento <literal>set</literal> del mapeo de colecci&#x00f3;n de <literal>Event</literal>.
+            </para>
+
+            <para>
+                Lo que esto significa es que Hibernate debe tomar el otro lado - la clase <literal>Person</literal> -
+                cuando necesite descubrir informaci&#x00f3;n sobre el enlace entre las dos. Esto ser&#x00e1; mucho
+                m&#x00e1;s f&#x00e1;cil de entender una vez que veas c&#x00f3;mo se crea el enlace bidireccional
+                entre nuestras dos entidades.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-usingbidir">
+            <title>Trabajando enlaces bidireccionales</title>
+
+            <para>
+                Primero, ten en mente que Hhibernate no afecta la sem&#x00e1;ntica normal de Java. ¿C&#x00f3;mo
+                hemos creado un enlace entre una <literal>Person</literal> y un <literal>Event</literal> en el
+                ejemplo unidireccional? Hemos agregado una instancia de <literal>Event</literal> a la colecci&#x00f3;n
+                de referencias de eventos de una instancia de <literal>Person</literal>. De modo que, obviamente,
+                si queremos que este enlace funcione bidireccionalmente, tenemos que hacer lo mismo del otro lado,
+                agregando una referencia a <literal>Person</literal> a la colecci&#x00f3;n en un <literal>Event</literal>.
+                Este "establecer el enlace a ambos lados" es absolutamente necesario y nunca debes olvidar hacerlo.
+            </para>
+
+            <para>
+                Muchos desarrolladores programan a la defensiva y crean m&#x00e9;todos de
+                manejo de un enlace para establecer correctamente ambos lados, por ejemplo
+                en <literal>Person</literal>:
+            </para>
+
+            <programlisting><![CDATA[protected Set getEvents() {
+    return events;
+}
+
+protected void setEvents(Set events) {
+    this.events = events;
+}
+
+public void addToEvent(Event event) {
+    this.getEvents().add(event);
+    event.getParticipants().add(this);
+}
+
+public void removeFromEvent(Event event) {
+    this.getEvents().remove(event);
+    event.getParticipants().remove(this);
+}]]></programlisting>
+
+            <para>
+                Nota que los m&#x00e9;todos get y set para esta colecci&#x00f3;n son ahora protegidos. Esto le
+                permite a clases en el mismo paquete y a subclases acceder a&#x00fa;n a los m&#x00e9;todos, pero
+                previene a cualquier otro de ensuciarse con la colecci&#x00f3;n directamente (bueno, casi).
+                Probablemente debas hacer lo mismo con la colecci&#x00f3;n al otro lado.
+            </para>
+
+            <para>
+                Y ¿qu&#x00e9; del atributo de mapeo <literal>inverse</literal>?  Para ti, y para Java, un enlace
+                bidireccional es simplemente cuesti&#x00f3;n de establecer correctamente las referencias a ambos
+                lados. Hibernate, sin embargo, no tiene suficiente informaci&#x00f3;n para arreglar correctamente
+                sentencias <literal>INSERT</literal> y <literal>UPDATE</literal> de SQL (para evitar violaci&#x00f3;n
+                de restricciones), y necesita alguna ayuda para manejar asociaciones bidireccionales apropiadamente.
+                El hacer un lado de la asociaci&#x00f3;n <literal>inverse</literal> le dice a Hibernate que basicamente
+                lo ignore, que lo considere un <emphasis>espejo</emphasis> del otro lado. Esto es todo lo necesario para
+                que Hibernate resuelva todas las incidencias al transformar un modelo de navegaci&#x00f3;n direccional a
+                un esquema SQL de base de datos. Las reglas que tienes que recordar son directas: Todas las asociaciones
+                bidireccionales necesitan uno de los lados como <literal>inverse</literal>. En una asociaci&#x00f3;n
+                uno-a-muchos debe ser el lado-de-muchos. En una asociaci&#x00f3;n muchos-a-muchos, puedes tomar cualquier
+                lado, no hay diferencia.
+            </para>
+<!--
+            <para>
+                In the next section we integrate Hibernate with Tomcat and WebWork - the <literal>EventManager</literal>
+                doesn't scale anymore with our growing application.
+            </para>
+-->
+        </sect2>
+    </sect1>
+
+    <sect1 id="tutorial-summary">
+        <title>Summary</title>
+
+        <para>
+            Este tutorial cubri&#x00f3; los fundamentos de escribir una simple aplicaci&#x00f3;n independiente
+            de Hibernate.
+        </para>
+
+        <para>
+            Si ya te sientes confidente con Hibernate, contin&#x00fa;a navegando a trav&#x00e9;s de la
+            tabla de contenidos de la documentaci&#x00f3;n de referencia para los temas que encuentres
+            interesantes. Los m&#x00e1;s consultados son procesamiento transaccional (<xref linkend="transactions"/>),
+            rendimiento de recuperaci&#x00f3;n (<xref linkend="performance"/>), o el uso de la API
+            (<xref linkend="objectstate"/>) y las funcionalidades de consulta (<xref linkend="objectstate-querying"/>).
+        </para>
+
+        <para>
+            No olvides chequear el sitio web de Hibernate por m&#x00e1;s (especializados) tutoriales.
+        </para>
+
+    </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/xml.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/xml.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/docbook/modules/xml.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,282 @@
+<chapter id="xml">
+    <title>Mapeo XML</title>
+
+    <para><emphasis>
+        Nota que esta es una funcionalidad experimental en Hibernate 3.0 y está
+        bajo un desarrollo extremadamente activo.
+    </emphasis></para>
+
+    <sect1 id="xml-intro" revision="1">
+        <title>Trabajando con datos XML</title>
+
+        <para>
+            Hibernate te permite trabajar con datos XML persistentes en casi la misma forma
+            que trabajas con POJOs persistentes. Un árbol XML analizado (parsed) puede ser
+            pensado como sólo otra forma de representar los datos relacionales a nivel de objetos,
+            en vez de POJOs.
+        </para>
+
+        <para>
+            Hibernate soporta dom4j como API para manipular árboles XML. Puedes escribir
+            consultas que traigan árboles dom4j de la base de datos y tener cualquier modificación
+            que hagas al árbol sincronizada automáticamente a la base de datos. Puedes incluso tomar 
+            un documento XML, analizarlo usando dom4j, y escribirlo a la base de datos con cualquiera
+            de las operaciones básicas de Hibernate: <literal>persist(), saveOrUpdate(), merge(),
+            delete(), replicate()</literal> (la fusión no está aún soportada).
+        </para>
+
+        <para>
+            Esta funcionalidad tiene muchas aplicaciones incluyendo la importación/exportación de datos,
+            externalización de datos de entidad vía JMS o SOAP y reportes basados en XSLT.
+        </para>
+        
+        <para>
+            Un solo mapeo puede ser usado para mapear simultáneamente las propiedades de una clase y los nodos de un
+            documento XML a la base de datos, o, si no hay ninguna clase a mapear, puede ser usado para mapear sólo
+            el XML.
+        </para>
+        
+        <sect2 id="xml-intro-mapping">
+            <title>Especificando los mapeos de XML y de clase juntos</title>
+
+            <para>
+                He aquí un ejemplo de mapear un POJO y XML simultáneamente:
+            </para>
+            
+            <programlisting><![CDATA[<class name="Account" 
+        table="ACCOUNTS" 
+        node="account">
+        
+    <id name="accountId" 
+            column="ACCOUNT_ID" 
+            node="@id"/>
+            
+    <many-to-one name="customer" 
+            column="CUSTOMER_ID" 
+            node="customer/@id" 
+            embed-xml="false"/>
+            
+    <property name="balance" 
+            column="BALANCE" 
+            node="balance"/>
+            
+    ...
+    
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="xml-onlyxml">
+            <title>Especificando sólo un mapeo XML</title>
+
+            <para>
+                He aquí un ejemplo donde no hay ninguna clase POJO:
+            </para>
+            
+            <programlisting><![CDATA[<class entity-name="Account" 
+        table="ACCOUNTS" 
+        node="account">
+        
+    <id name="id" 
+            column="ACCOUNT_ID" 
+            node="@id" 
+            type="string"/>
+            
+    <many-to-one name="customerId" 
+            column="CUSTOMER_ID" 
+            node="customer/@id" 
+            embed-xml="false" 
+            entity-name="Customer"/>
+            
+    <property name="balance" 
+            column="BALANCE" 
+            node="balance" 
+            type="big_decimal"/>
+            
+    ...
+    
+</class>]]></programlisting>
+        
+            <para>
+                Este mapeo te permite acceder a los datos como un árbol dom4j, o como un grafo de pares nombre/valor de
+                propiedad (<literal>Map</literal>s de Java). Los nombres de propiedades son construcciones puramente
+                lógicas a las que se puede hacer referencia en consultas HQL.
+            </para>
+
+        </sect2>
+        
+     </sect1>
+     
+    <sect1 id="xml-mapping" revision="1">
+        <title>Mapeo de metadatos XML</title>
+
+        <para>
+            Muchos elementos de mapeo de Hibernate aceptan el atributo <literal>node</literal>. Esto te permite espcificar
+            el nombre de un atributo o elemento XML que contenga los datos de la propiedad o entidad. El formato del
+            atributo <literal>node</literal> debe ser uno de los siguientes:
+        </para>
+        
+        <itemizedlist spacing="compact">
+        <listitem>
+            <para><literal>"element-name"</literal> - mapea al elemento XML mencionado</para>
+        </listitem>
+        <listitem>
+            <para><literal>"@attribute-name"</literal> - mapea al atributo XML mencionado</para>
+        </listitem>
+        <listitem>
+            <para><literal>"."</literal> - mapea al elemento padre</para>
+        </listitem>
+        <listitem>
+            <para>
+                <literal>"element-name/@attribute-name"</literal> - 
+                mapea al atributo mencionado del elemento mencionado
+            </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            Para las colecciones y asociaciones monovaluadas, existe un atributo adicional <literal>embed-xml</literal>.
+            Si <literal>embed-xml="true"</literal>, que es el valor por defecto, el árbol XML para la entidad
+            asociada (o colección de tipo de valor) será embebida directamente en el árbol XML para la entidad que
+            posee la asociación. En otro caso, si <literal>embed-xml="false"</literal>, sólo el valor identificador
+            referenciado aparecerá en el XML para asociaciones de punto único y para las colecciones simplemente
+            no aparecerá en absoluto.
+        </para>
+        
+        <para>
+            ¡Debes ser cuidadoso de no dejar <literal>embed-xml="true"</literal> para demasiadas asociaciones,
+            ya que XML no trata bien la circularidad!
+        </para>
+        
+        <programlisting><![CDATA[<class name="Customer" 
+        table="CUSTOMER" 
+        node="customer">
+        
+    <id name="id" 
+            column="CUST_ID" 
+            node="@id"/>
+            
+    <map name="accounts" 
+            node="." 
+            embed-xml="true">
+        <key column="CUSTOMER_ID" 
+                not-null="true"/>
+        <map-key column="SHORT_DESC" 
+                node="@short-desc" 
+                type="string"/>
+        <one-to-many entity-name="Account"
+                embed-xml="false" 
+                node="account"/>
+    </map>
+    
+    <component name="name" 
+            node="name">
+        <property name="firstName" 
+                node="first-name"/>
+        <property name="initial" 
+                node="initial"/>
+        <property name="lastName" 
+                node="last-name"/>
+    </component>
+    
+    ...
+    
+</class>]]></programlisting>
+
+        <para>
+            en este caso, hemos decidido embeber la colección de ids de cuenta, pero no los datos reales de cuenta.
+            La siguiente consulta HQL:
+        </para>
+        
+        <programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
+        
+        <para>
+            devolvería conjuntos de datos como estos:
+        </para>
+        
+        <programlisting><![CDATA[<customer id="123456789">
+    <account short-desc="Savings">987632567</account>
+    <account short-desc="Credit Card">985612323</account>
+    <name>
+        <first-name>Gavin</first-name>
+        <initial>A</initial>
+        <last-name>King</last-name>
+    </name>
+    ...
+</customer>]]></programlisting>
+
+        <para>
+            Si estableces <literal>embed-xml="true"</literal> en el mapeo <literal>&lt;one-to-many&gt;</literal>, los datos
+            podrían verse así:
+        </para>
+        
+        <programlisting><![CDATA[<customer id="123456789">
+    <account id="987632567" short-desc="Savings">
+        <customer id="123456789"/>
+        <balance>100.29</balance>
+    </account>
+    <account id="985612323" short-desc="Credit Card">
+        <customer id="123456789"/>
+        <balance>-2370.34</balance>
+    </account>
+    <name>
+        <first-name>Gavin</first-name>
+        <initial>A</initial>
+        <last-name>King</last-name>
+    </name>
+    ...
+</customer>]]></programlisting>
+       
+    </sect1>
+    
+    
+    <sect1 id="xml-manipulation" revision="1">
+        <title>Manipulando datos XML</title>
+        
+        <para>
+            Vamos a releer y actualizar documentos XML en la aplicación. Hacemos esto obteniendo una sesión dom4j:
+        </para>
+        
+       <programlisting><![CDATA[Document doc = ....;
+       
+Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+List results = dom4jSession
+    .createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")
+    .list();
+for ( int i=0; i<results.size(); i++ ) {
+    //add the customer data to the XML document
+    Element customer = (Element) results.get(i);
+    doc.add(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+       
+       <programlisting><![CDATA[Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+Element cust = (Element) dom4jSession.get("Customer", customerId);
+for ( int i=0; i<results.size(); i++ ) {
+    Element customer = (Element) results.get(i);
+    //change the customer name in the XML and database
+    Element name = customer.element("name");
+    name.element("first-name").setText(firstName);
+    name.element("initial").setText(initial);
+    name.element("last-name").setText(lastName);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            Es extremadamente útil combinar esta funcionalidad con la operación <literal>replicate()</literal>
+            de Hibernate para implementar la importación/exportación de datos basada en XML.
+        </para>
+       
+    </sect1>
+     
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/css/html.css
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/css/html.css	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/css/html.css	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,97 @@
+A {
+    color: #003399;
+}
+
+A:active {
+    color: #003399;
+}
+
+A:visited {
+    color: #888888;
+}
+
+P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
+    color: #000000;
+}
+
+TD, TH, SPAN {
+    color: #000000;
+}
+
+BLOCKQUOTE {
+    margin-right: 0px;
+}
+
+
+H1, H2, H3, H4, H5, H6    {
+    color: #000000;
+    font-weight:500;
+    margin-top:10px;
+    padding-top:15px;
+}
+
+TABLE  {
+    border-collapse: collapse;
+    border-spacing:0;
+    border: 1px thin black;
+    empty-cells: hide;
+}
+
+TD  {
+    padding: 4pt;
+}
+
+H1 { font-size: 150%; }
+H2 { font-size: 140%; }
+H3 { font-size: 110%; font-weight: bold; }
+H4 { font-size: 110%; font-weight: bold;}
+H5 { font-size: 100%; font-style: italic; }
+H6 { font-size: 100%; font-style: italic; }
+
+TT {
+font-size: 90%;
+    font-family: "Courier New", Courier, monospace;
+    color: #000000;
+}
+
+PRE {
+font-size: 100%;
+    padding: 5px;
+    border-style: solid;
+    border-width: 1px;
+    border-color: #CCCCCC;
+    background-color: #F4F4F4;
+}
+
+UL, OL, LI {
+    list-style: disc;
+}
+
+HR  {
+    width: 100%;
+    height: 1px;
+    background-color: #CCCCCC;
+    border-width: 0px;
+    padding: 0px;
+    color: #CCCCCC;
+}
+
+.variablelist { 
+    padding-top: 10; 
+    padding-bottom:10; 
+    margin:0;
+}
+
+.itemizedlist, UL { 
+    padding-top: 0; 
+    padding-bottom:0; 
+    margin:0; 
+}
+
+.term { 
+    font-weight:bold;
+}
+
+
+
+    

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/AuthorWork.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/AuthorWork.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/AuthorWork.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/AuthorWork.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/CustomerOrderProduct.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/CustomerOrderProduct.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/CustomerOrderProduct.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/CustomerOrderProduct.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/EmployerEmployee.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/EmployerEmployee.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/EmployerEmployee.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/EmployerEmployee.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/full_cream.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/full_cream.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/full_cream.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/full_cream.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/full_cream.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,429 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="354.331"
+   height="336.614"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+     style="font-size:12;"
+     id="g659">
+    <rect
+       width="212.257"
+       height="57.2441"
+       x="17.9576"
+       y="100.132"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       transform="matrix(0.743454,0,0,0.482981,6.46949,52.2178)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <rect
+     width="325.86"
+     height="63.6537"
+     x="17.4083"
+     y="15.194"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect136" />
+  <rect
+     width="325.86"
+     height="63.6537"
+     x="13.6713"
+     y="12.4966"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect126" />
+  <g
+     transform="matrix(1.14345,0,0,0.729078,-1.67818,105.325)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <text
+     x="170.824753"
+     y="58.402939"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="170.824997"
+       y="58.402901"
+       id="tspan360">
+Application</tspan>
+  </text>
+  <text
+     x="178.076340"
+     y="364.281433"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="178.076004"
+       y="364.281006"
+       id="tspan421">
+Database</tspan>
+  </text>
+  <text
+     x="68.605331"
+     y="138.524582"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="68.605301"
+       y="138.524994"
+       id="tspan384">
+SessionFactory</tspan>
+  </text>
+  <rect
+     width="67.0014"
+     height="101.35"
+     x="196.927"
+     y="89.2389"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect387" />
+  <rect
+     width="67.0014"
+     height="101.35"
+     x="194.633"
+     y="86.4389"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect388" />
+  <text
+     x="249.108841"
+     y="173.885559"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text389">
+    <tspan
+       x="249.108994"
+       y="173.886002"
+       id="tspan392">
+Session</tspan>
+  </text>
+  <rect
+     width="73.0355"
+     height="101.35"
+     x="270.995"
+     y="90.0018"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect395" />
+  <rect
+     width="73.0355"
+     height="101.35"
+     x="267.869"
+     y="87.2018"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect396" />
+  <text
+     x="328.593658"
+     y="174.715622"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text397">
+    <tspan
+       x="328.593994"
+       y="174.716003"
+       id="tspan563">
+Transaction</tspan>
+  </text>
+  <g
+     transform="matrix(0.29544,0,0,0.397877,9.70533,103.96)"
+     style="font-size:12;"
+     id="g565">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect566" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect567" />
+  </g>
+  <text
+     x="25.592752"
+     y="204.497803"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text568">
+    <tspan
+       x="25.592800"
+       y="204.498001"
+       id="tspan662">
+TransactionFactory</tspan>
+  </text>
+  <g
+     transform="matrix(0.298082,0,0,0.397877,99.6898,103.96)"
+     style="font-size:12;"
+     id="g573">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect574" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect575" />
+  </g>
+  <text
+     x="134.030670"
+     y="205.532791"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text576">
+    <tspan
+       x="134.031006"
+       y="205.533005"
+       id="tspan664">
+ConnectionProvider</tspan>
+  </text>
+  <g
+     transform="matrix(1.14345,0,0,0.729078,-1.67818,38.9539)"
+     style="font-size:12;"
+     id="g587">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect588" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect589" />
+  </g>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="25.6196"
+     y="206.028"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect594" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="24.4229"
+     y="204.135"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect595" />
+  <text
+     x="85.575645"
+     y="282.300354"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text596">
+    <tspan
+       x="85.575600"
+       y="282.299988"
+       id="tspan607">
+JNDI</tspan>
+  </text>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="236.937"
+     y="206.791"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect610" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="235.741"
+     y="204.898"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect611" />
+  <text
+     x="342.093201"
+     y="283.226410"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text612">
+    <tspan
+       x="342.092987"
+       y="283.226013"
+       id="tspan621">
+JTA</tspan>
+  </text>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="130.134"
+     y="206.791"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect616" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="128.937"
+     y="204.898"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect617" />
+  <text
+     x="212.445343"
+     y="283.226410"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text618">
+    <tspan
+       x="212.445007"
+       y="283.226013"
+       id="tspan623">
+JDBC</tspan>
+  </text>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,6.19341)"
+     style="font-size:12;"
+     id="g637">
+    <g
+       transform="matrix(0.499515,0,0,0.415467,-0.237339,5.61339)"
+       id="g167">
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="61.8805"
+         y="68.4288"
+         style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect134" />
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="59.2613"
+         y="65.8095"
+         style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect135" />
+    </g>
+    <text
+       x="33.749969"
+       y="50.589706"
+       style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+       id="text188">
+      <tspan
+         x="33.750000"
+         y="50.589699"
+         id="tspan635">
+Transient Objects</tspan>
+    </text>
+  </g>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+     style="font-size:12;"
+     id="g644">
+    <g
+       transform="matrix(0.297486,0,0,0.516482,230.251,36.9178)"
+       id="g364">
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="61.8805"
+         y="68.4288"
+         style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect365" />
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="59.2613"
+         y="65.8095"
+         style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect366" />
+    </g>
+    <text
+       x="277.123230"
+       y="85.155571"
+       style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+       id="text367">
+      <tspan
+         x="277.122986"
+         y="85.155602"
+         id="tspan631">
+Persistent</tspan>
+      <tspan
+         x="277.122986"
+         y="96.155602"
+         id="tspan633">
+Objects</tspan>
+    </text>
+  </g>
+</svg>

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/hibernate_logo_a.png
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/hibernate_logo_a.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/lite.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/lite.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/lite.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/lite.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/lite.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,334 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="318.898"
+   height="248.031"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <rect
+     width="291.837"
+     height="57.0074"
+     x="17.3169"
+     y="18.646"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect136" />
+  <rect
+     width="291.837"
+     height="57.0074"
+     x="13.9703"
+     y="16.2302"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect126" />
+  <g
+     transform="matrix(0.326107,0,0,0.765831,9.59261,8.98517)"
+     style="font-size:12;"
+     id="g161">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <g
+     transform="matrix(1.02406,0,0,0.652953,0.223384,39.9254)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <g
+     transform="matrix(0.449834,0,0,0.338463,-3.15909,9.73319)"
+     style="font-size:12;"
+     id="g167">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect134" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect135" />
+  </g>
+  <text
+     x="302.277679"
+     y="65.943230"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="302.277954"
+       y="65.943184"
+       id="tspan360">
+Application</tspan>
+  </text>
+  <text
+     x="36.235924"
+     y="63.796055"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text188">
+    <tspan
+       x="36.235950"
+       y="63.796051"
+       id="tspan427">
+Transient Objects</tspan>
+  </text>
+  <text
+     x="180.416245"
+     y="290.543701"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="180.415939"
+       y="290.543549"
+       id="tspan421">
+Database</tspan>
+  </text>
+  <text
+     x="25.037701"
+     y="179.154755"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="25.037655"
+       y="179.154648"
+       id="tspan384">
+SessionFactory</tspan>
+  </text>
+  <g
+     transform="matrix(0.252763,0,0,0.765831,109.104,8.98517)"
+     style="font-size:12;"
+     id="g386">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect387" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect388" />
+  </g>
+  <g
+     transform="matrix(0.297394,0,0,0.572692,101.502,21.6359)"
+     style="font-size:12;"
+     id="g364">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect365" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect366" />
+  </g>
+  <text
+     x="202.746506"
+     y="102.992203"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text367">
+    <tspan
+       x="202.746948"
+       y="102.992249"
+       id="tspan423">
+Persistent</tspan>
+    <tspan
+       x="202.746948"
+       y="116.992355"
+       id="tspan425">
+Objects</tspan>
+  </text>
+  <text
+     x="174.458496"
+     y="180.080795"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text389">
+    <tspan
+       x="174.458618"
+       y="180.080338"
+       id="tspan392">
+Session</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,188.675,8.98517)"
+     style="font-size:12;"
+     id="g394">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect395" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect396" />
+  </g>
+  <text
+     x="260.413269"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text397">
+    <tspan
+       x="260.412964"
+       y="179.154343"
+       id="tspan400">
+JDBC</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,229.156,8.98517)"
+     style="font-size:12;"
+     id="g405">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect406" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect407" />
+  </g>
+  <text
+     x="320.606903"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text408">
+    <tspan
+       x="320.606964"
+       y="179.154343"
+       id="tspan417">
+JNDI</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,269.281,8.98517)"
+     style="font-size:12;"
+     id="g411">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect412" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect413" />
+  </g>
+  <text
+     x="377.096313"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text414">
+    <tspan
+       x="377.096008"
+       y="179.154999"
+       id="tspan145">
+JTA</tspan>
+  </text>
+</svg>

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/overview.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/overview.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/overview.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/overview.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/es-ES/src/main/resources/shared/images/overview.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,250 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="248.031"
+   height="248.031"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,-3.02123)"
+     style="font-size:12;"
+     id="g158">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="17.3527"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect136" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="15.3883"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect126" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,3.04452)"
+     style="font-size:12;"
+     id="g161">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,8.0993)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.543505,2.59104,21.1103)"
+     style="font-size:12;"
+     id="g167">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect134" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect135" />
+  </g>
+  <text
+     x="105.392174"
+     y="56.568123"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="105.392273"
+       y="56.568146"
+       id="tspan186">
+Application</tspan>
+  </text>
+  <text
+     x="81.820183"
+     y="103.149330"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:20;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text188">
+    <tspan
+       x="81.820213"
+       y="103.149727"
+       id="tspan206">
+Persistent Objects</tspan>
+  </text>
+  <text
+     x="111.548180"
+     y="278.927887"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="111.547874"
+       y="278.927551"
+       id="tspan200">
+Database</tspan>
+  </text>
+  <text
+     x="94.436180"
+     y="153.805740"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="94.436180"
+       y="153.805740"
+       id="tspan221">
+HIBERNATE</tspan>
+  </text>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,2.59083,1.02261)"
+     style="font-size:12;"
+     id="g254">
+    <g
+       transform="translate(4.58374,2.61928)"
+       id="g176">
+      <g
+         transform="matrix(0.571429,0,0,0.67347,-10.6174,117.093)"
+         id="g170">
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="61.8805"
+           y="68.4288"
+           style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect171" />
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="59.2613"
+           y="65.8095"
+           style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect172" />
+      </g>
+      <g
+         transform="matrix(0.571429,0,0,0.67347,138.682,117.093)"
+         id="g173">
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="61.8805"
+           y="68.4288"
+           style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect174" />
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="59.2613"
+           y="65.8095"
+           style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect175" />
+      </g>
+    </g>
+    <text
+       x="47.259438"
+       y="182.367538"
+       style="font-weight:bold;stroke-width:1pt;font-family:Courier;"
+       id="text191">
+      <tspan
+         x="47.259399"
+         y="182.367996"
+         id="tspan212">
+hibernate.</tspan>
+      <tspan
+         x="47.259399"
+         y="194.367996"
+         id="tspan214">
+properties</tspan>
+    </text>
+    <text
+       x="198.523010"
+       y="188.260941"
+       style="font-weight:normal;stroke-width:1pt;font-family:helvetica;"
+       id="text194">
+      <tspan
+         id="tspan195">
+XML Mapping</tspan>
+    </text>
+  </g>
+</svg>

Added: trunk/Hibernate3/documentation/manual/fr-FR/pom.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-manual</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>hibernate-manual-${translation}</artifactId>
+    <packaging>pom</packaging>
+    <name>Hibernate Manual (${translation})</name>
+
+    <properties>
+        <translation>fr-FR</translation>
+    </properties>
+</project>

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/master.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/master.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/master.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,188 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
+                      "../support/docbook-dtd/docbookx.dtd"
+[
+<!ENTITY tutorial               SYSTEM "modules/tutorial.xml">
+<!ENTITY architecture           SYSTEM "modules/architecture.xml">
+<!ENTITY configuration          SYSTEM "modules/configuration.xml">
+<!ENTITY persistent-classes     SYSTEM "modules/persistent_classes.xml">
+<!ENTITY basic-mapping          SYSTEM "modules/basic_mapping.xml">
+<!ENTITY collection-mapping     SYSTEM "modules/collection_mapping.xml">
+<!ENTITY association-mapping    SYSTEM "modules/association_mapping.xml">
+<!ENTITY component-mapping      SYSTEM "modules/component_mapping.xml">
+<!ENTITY inheritance-mapping    SYSTEM "modules/inheritance_mapping.xml">
+<!ENTITY session-api            SYSTEM "modules/session_api.xml">
+<!ENTITY transactions           SYSTEM "modules/transactions.xml">
+<!ENTITY events                 SYSTEM "modules/events.xml">
+<!ENTITY batch                  SYSTEM "modules/batch.xml">
+<!ENTITY query-hql              SYSTEM "modules/query_hql.xml">
+<!ENTITY query-criteria         SYSTEM "modules/query_criteria.xml">
+<!ENTITY query-sql              SYSTEM "modules/query_sql.xml">
+<!ENTITY filters                SYSTEM "modules/filters.xml">
+<!ENTITY xml                    SYSTEM "modules/xml.xml">
+<!ENTITY performance            SYSTEM "modules/performance.xml">
+<!ENTITY toolset-guide          SYSTEM "modules/toolset_guide.xml">
+<!ENTITY example-parentchild    SYSTEM "modules/example_parentchild.xml">
+<!ENTITY example-weblog         SYSTEM "modules/example_weblog.xml">
+<!ENTITY example-mappings       SYSTEM "modules/example_mappings.xml">
+<!ENTITY best-practices         SYSTEM "modules/best_practices.xml">
+]>
+
+<book lang="fr">
+
+    <bookinfo>
+        <title>HIBERNATE - Persistance relationnelle en Java standard</title>
+        <subtitle>Documentation de référence d'Hibernate</subtitle>
+        <releaseinfo>3.3.0.beta1</releaseinfo>
+    </bookinfo>
+
+    <toc/>
+
+    <preface id="preface" revision="2">
+        <title>Préface</title>
+        <para>
+            Traducteur(s): Vincent Ricard, Sebastien Cesbron, Michael Courcy, Vincent Giguère, Baptiste Mathus, Emmanuel Bernard, Anthony Patricio
+        </para>
+        <para>
+            Travailler dans les deux univers que sont l'orienté objet et la base de données
+            relationnelle peut être lourd et consommateur en temps dans le monde de
+            l'entreprise d'aujourd'hui. Hibernate est un outil de  mapping objet/relationnel
+            pour le monde Java. Le terme mapping objet/relationnel (ORM) décrit la technique
+            consistant à faire le lien entre la représentation objet des données
+            et sa représentation relationnelle basée sur un schéma SQL.
+        </para>
+
+        <para>
+            Non seulement, Hibernate s'occupe du transfert des classes Java dans les tables
+            de la base de données (et des types de données Java dans les types de données SQL),
+            mais il permet de requêter les données et propose des moyens de les récupérer.
+            Il peut donc réduire de manière significative le temps de développement qui
+            aurait été autrement perdu dans une manipulation manuelle des données via SQL
+            et JDBC.
+        </para>
+
+        <para>
+            Le but d'Hibernate est de libérer le développeur de 95 pourcent des tâches de
+            programmation liées à la persistance des données communes. Hibernate n'est
+            probablement pas la meilleure solution pour les applications centrées sur les
+            données qui n'utilisent que les procédures stockées pour implémenter la logique
+            métier dans la base de données, il est le plus utile dans les modèles métier orientés
+            objets dont la logique métier est implémentée dans la couche Java dite intermédiaire.
+            Cependant, Hibernate vous aidera à supprimer ou à encapsuler le code SQL
+            spécifique à votre base de données et vous aidera sur la tâche commune qu'est
+            la transformation des données d'une représentation tabulaire à une
+            représentation sous forme de graphe d'objets.
+        </para>
+
+        <para>
+            Si vous êtes nouveau dans Hibernate et le mapping Objet/Relationnel voire même en Java,
+            suivez ces quelques étapes :
+        </para>
+
+        <orderedlist>
+            <listitem>
+                <para>
+                    Lisez <xref linkend="tutorial"/> pour un didacticiel plus long avec plus d'instructions étape par étape.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Lisez <xref linkend="architecture"/> pour comprendre les environnements dans lesquels
+                    Hibernate peut être utilisé.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Regardez le répertoire <literal>eg</literal> de la distribution Hibernate, il contient
+                    une application simple et autonome. Copiez votre pilote JDBC dans le répertoire
+                    <literal>lib/</literal> et éditez <literal>src/hibernate.properties</literal>, en
+                    positionnant correctement les valeurs pour votre base de données. A partir d'une
+                    invite de commande dans le répertoire de la distribution, tapez <literal>ant eg</literal>
+                    (cela utilise Ant), ou sous Windows tapez <literal>build eg</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Faîtes de cette documentation de référence votre principale source d'information.
+                    Pensez à lire <emphasis>Hibernate in Action</emphasis>
+                    (http://www.manning.com/bauer) si vous avez besoin de plus d'aide avec le design
+                    d'applications ou si vous préférez un tutoriel pas à pas. Visitez aussi
+                    http://caveatemptor.hibernate.org et téléchargez l'application exemple
+                    pour Hibernate in Action.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Les questions les plus fréquemment posées (FAQs) trouvent leur réponse sur le
+                    site web Hibernate.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Des démos, exemples et tutoriaux de tierces personnes sont référencés sur
+                    le site web Hibernate.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    La zone communautaire (Community Area) du site web Hibernate est une
+                    bonne source d'information sur les design patterns et sur différentes
+                    solutions d'intégration d'Hibernate (Tomcat, JBoss, Spring Framework, Struts,
+                    EJB, etc).
+                </para>
+            </listitem>
+         </orderedlist>
+
+         <para>
+             Si vous avez des questions, utilisez le forum utilisateurs du site web Hibernate.
+             Nous utilisons également l'outil de gestion des incidents JIRA pour tout ce qui
+             est rapports de bogue et demandes d'évolution. Si vous êtes intéressé par le
+             développement d'Hibernate, joignez-vous à la liste de diffusion de développement.
+         </para>
+
+         <para>
+             Le développement commercial, le support de production et les formations à Hibernate
+             sont proposés par JBoss Inc (voir http://www.hibernate.org/SupportTraining/). Hibernate
+             est un projet Open Source professionnel et un composant critique de la suite de produits
+             JBoss Enterprise Middleware System (JEMS).
+         </para>
+
+     </preface>
+
+    &tutorial;
+
+    &architecture;
+
+    &configuration;
+
+    &persistent-classes;
+
+    &basic-mapping;
+    &collection-mapping;
+    &association-mapping;
+    &component-mapping;
+    &inheritance-mapping;
+
+    &session-api;
+    &transactions;
+    &events;
+    &batch;
+
+    &query-hql;
+    &query-criteria;
+    &query-sql;
+    &filters;
+    &xml;
+
+    &performance;
+
+    &toolset-guide;
+
+    &example-parentchild;
+    &example-weblog;
+    &example-mappings;
+
+    &best-practices;
+
+</book>
+

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/architecture.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/architecture.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/architecture.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,351 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="architecture">
+
+    <title>Architecture</title>
+
+    <sect1 id="architecture-overview" revision="1">
+        <title>Généralités</title>
+        
+        <para>
+            Voici une vue (très) haut niveau de l'architecture d'Hibernate :
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/overview.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/overview.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            Ce diagramme montre Hibernate utilisant une base de données et des données
+            de configuration pour fournir un service de persistance (et des objets
+            persistants) à l'application.
+        </para>
+
+        <para>
+            Nous aimerions décrire une vue plus détaillée de l'architecture. Malheureusement,
+            Hibernate est flexible et supporte différentes approches. Nous allons en
+            montrer les deux extrêmes. L'architecture légère laisse l'application fournir
+            ses propres connexions JDBC et gérer ses propres transactions. Cette approche
+            utilise le minimum des APIs Hibernate :
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/lite.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/lite.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            L'architecture la plus complète abstrait l'application des APIs JDBC/JTA 
+            sous-jacentes et laisse Hibernate s'occuper des détails.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/full_cream.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/full_cream.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            Voici quelques définitions des objets des diagrammes :
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
+                    <listitem>
+                        <para>
+                            Un cache threadsafe (immuable) des mappings vers une (et une seule) base 
+                            de données. Une factory (fabrique) de <literal>Session</literal> et un client
+                            de <literal>ConnectionProvider</literal>. Peut contenir un cache optionnel de
+                            données (de second niveau) qui est réutilisable entre les différentes transactions
+                            que cela soit au sein du même processus (JVLM) ou par plusieurs n½uds d'un cluster.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Session (<literal>org.hibernate.Session</literal>)</term>
+                    <listitem>
+                        <para>
+                            Un objet mono-threadé, à durée de vie courte, qui représente une conversation
+                            entre l'application et l'entrepôt de persistance. Encapsule une connexion JDBC.
+                            Factory (fabrique) des objets <literal>Transaction</literal>. Contient un cache
+                            (de premier niveau) des objets persistants, ce cache est obligatoire. Il est 
+                            utilisé lors de la navigation dans le graphe d'objets ou lors de la récupération
+                            d'objets par leur identifiant.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Objets et Collections persistants</term>
+                    <listitem>
+                        <para>
+                            Objets mono-threadés à vie courte contenant l'état de persistance
+                            et la fonction métier. Ceux-ci sont en général les objets de type JavaBean
+                            (ou POJOs) ; la seule particularité est qu'ils sont associés avec une (et
+                            une seule) <literal>Session</literal>. Dès que la <literal>Session</literal>
+                            est fermée, ils seront détachés et libres d'être utilisés par n'importe laquelle
+                            des couches de l'application (ie. de et vers la présentation en tant que Data 
+                            Transfer Objects - DTO : objet de transfert de données).
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Objets et collections transients</term>
+                    <listitem>
+                        <para>
+                            Instances de classes persistantes qui ne sont actuellement pas associées à
+                            une <literal>Session</literal>. Elles ont pu être instanciées par l'application
+                            et ne pas avoir (encore) été persistées ou elle ont pu être instanciées par
+                            une <literal>Session</literal> fermée.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
+                    <listitem>
+                        <para>
+                            (Optionnel) Un objet mono-threadé à vie courte utilisé par l'application
+                            pour définir une unité de travail atomique. Abstrait l'application des
+                            transactions sous-jacentes qu'elles soient JDBC, JTA ou CORBA. Une
+                            <literal>Session</literal> peut fournir plusieurs <literal>Transaction</literal>s
+                            dans certains cas. Toutefois, la délimitation des transactions, via l'API d'Hibernate
+                            ou par la <literal>Transaction</literal> sous-jacente, n'est jamais optionnelle!
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
+                    <listitem>
+                        <para>
+                            (Optionnel) Une fabrique de (pool de) connexions JDBC. Abstrait l'application
+                            de la <literal>Datasource</literal> ou du <literal>DriverManager</literal> sous-jacent.
+                            Non exposé à l'application, mais peut être étendu/implémenté par le développeur.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
+                    <listitem>
+                        <para>
+                            (Optionnel) Une fabrique d'instances de <literal>Transaction</literal>. Non
+                            exposé à l'application, mais peut être étendu/implémenté par le développeur.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><emphasis>Interfaces d'extension</emphasis></term>
+                    <listitem>
+                        <para>
+                            Hibernate fournit de nombreuses interfaces d'extensions optionnelles que 
+                            vous pouvez implémenter pour personnaliser le comportement de votre couche de persistance.
+                            Reportez vous à la documentation de l'API pour plus de détails.
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+        </para>
+
+        <para>
+            Dans une architecture légère, l'application n'aura pas à utiliser les APIs
+            <literal>Transaction</literal>/<literal>TransactionFactory</literal>
+            et/ou n'utilisera pas les APIs <literal>ConnectionProvider</literal>
+            pour utiliser JTA ou JDBC.
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-states" revision="1">
+        <title>Etats des instances</title>
+        <para>
+            Une instance d'une classe persistante peut être dans l'un des trois états suivants,
+            définis par rapport à un <emphasis>contexte de persistance</emphasis>.
+            L'objet <literal>Session</literal> d'hibernate correspond à ce concept de 
+            contexte de persistance :
+        </para>
+        
+       <variablelist spacing="compact">
+            <varlistentry>
+                <term>passager (transient)</term>
+                <listitem>
+                    <para>
+                        L'instance n'est pas et n'a jamais été associée à un contexte
+                        de persistance. Elle ne possède pas d'identité persistante (valeur de clé primaire)
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>persistant</term>
+                <listitem>
+                    <para>
+                        L'instance est associée au contexte de persistance.
+                        Elle possède une identité persistante (valeur de clé primaire)
+                        et, peut-être, un enregistrement correspondant dans la base.
+                        Pour un contexte de persistance particulier, Hibernate
+                        <emphasis>garantit</emphasis> que l'identité persistante
+                        est équivalente à l'identité Java (emplacement mémoire de l'objet)
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>détaché</term>
+                <listitem>
+                    <para>
+                        L'instance a été associée au contexte de persistance mais ce
+                        contexte a été fermé, ou l'instance a été sérialisée vers un
+                        autre processus. Elle possède une identité persistante et
+                        peut-être un enregistrement correspondant dans la base.
+                        Pour des instances détachées, Hibernate ne donne aucune
+                        garantie sur la relation entre l'identité persistante et
+                        l'identité Java.
+                    </para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </sect1>    
+
+    <sect1 id="architecture-jmx" revision="1">
+        <title>Intégration JMX</title>
+        <para>
+            JMX est le standard J2EE de gestion des composants Java. 
+            Hibernate peut être géré via un service JMX standard. Nous fournissons une implémentation
+            d'un MBean dans la distribution : <literal>org.hibernate.jmx.HibernateService</literal>.
+        </para>
+        
+        <para>
+            Pour avoir un exemple sur la manière de déployer Hibernate en tant que service JMX dans le
+            serveur d'application JBoss Application Server, référez vous au guide utilisateur JBoss (JBoss User Guide).
+            Si vous déployez Hibernate via JMX sur JBoss AS, vous aurez également les bénéfices suivants :
+        </para>
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>Gestion de la session :</emphasis> Le cycle de vie de la <literal>Session</literal>
+                    Hibernate peut être automatiquement limitée à la portée d'une transaction JTA.
+                    Cela signifie que vous n'avez plus besoin d'ouvrir et de fermer la <literal>Session</literal>
+                    manuellement, cela devient le travail de l'intercepteur EJB de JBoss. Vous n'avez
+                    pas non plus à vous occuper des démarcations des transactions dans votre code (sauf
+                    si vous voulez écrire une couche de persistance qui soit portable, dans ce cas vous
+                    pouvez utiliser l'API optionnelle <literal>Transaction</literal> d'Hibernate).
+                    Vous appelez l'<literal>HibernateContext</literal> pour accéder à la <literal>Session</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Déploiement HAR :</emphasis> Habituellement vous déployez le service JMX
+                    Hibernate en utilisant le descripteur de déploiement de JBoss (dans un fichier EAR et/ou un SAR),
+                    il supporte toutes les options de configuration usuelles d'une <literal>SessionFactory</literal>
+                    Hibernate. Cependant, vous devez toujours nommer tous vos fichiers de mapping dans le
+                    descripteur de déploiement. Si vous décidez d'utiliser le déploiement optionnel sous forme
+                    de HAR, JBoss détectera automatiquement tous vos fichiers de mapping dans votre fichier HAR.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Consultez le guide d'utilisation de JBoss AS pour plus d'informations sur ces options.
+        </para>
+
+        <para>
+            Les statistiques pendant l'exécution d'Hibernate (au runtime) sont une 
+            autre fonctionnalité disponible en tant que service JMX. Voyez pour cela
+            <xref linkend="configuration-optional-statistics"/>.
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-jca" revision="1">
+        <title>Support JCA</title>
+        <para>
+            Hibernate peut aussi être configuré en tant que connecteur JCA. Référez-vous au site
+            web pour de plus amples détails. Il est important de noter que le support JCA d'Hibernate
+            est encore considéré comme expérimental.
+        </para>
+    </sect1>
+    
+    <sect1 id="architecture-current-session" revision="1">
+        <title>Sessions Contextuelles</title>
+        <para>
+            Certaines applications utilisant Hibernate ont besoin d'une sorte de session "contextuelle", où
+            une session est liée à la portée d'un contexte particulier. Cependant, les applications ne définissent
+            pas toutes la notion de contexte de la même manière, et différents contextes définissent différentes
+            portées à la notion de "courant". Les applications à base d'Hibernate, versions précédentes à la 3.0
+            utilisaient généralement un principe maison de sessions contextuelles basées sur le <literal>ThreadLocal</literal>,
+            ainsi que sur des classes utilitaires comme <literal>HibernateUtil</literal>, ou utilisaient des
+            framework tiers (comme Spring ou Pico) qui fournissaient des sessions contextuelles basées sur 
+            l'utilisation de proxy/interception.
+        </para>
+        <para>
+        	A partir de la version 3.0.1, Hibernate a ajouté la méthode <literal>SessionFactory.getCurrentSession()</literal>.
+        	Initialement, cela demandait l'usage de transactions <literal>JTA</literal>, où la
+        	transaction <literal>JTA</literal> définissait la portée et le contexte de la session courante.
+        	L'équipe Hibernate pense que, étant donnée la maturité des implémentations de <literal>JTA TransactionManager</literal> ,
+        	la plupart (sinon toutes) des applications devraient utiliser la gestion des transactions par <literal>JTA</literal> 
+        	qu'elles soient ou non déployées dans un conteneur <literal>J2EE</literal>. Par conséquent,
+        	vous devriez toujours contextualiser vos sessions, si vous en avez besoin, via la méthode basée sur JTA.
+        </para>
+        <para>
+            Cependant, depuis la version 3.1, la logique derrière
+            <literal>SessionFactory.getCurrentSession()</literal> est désormais branchable.  
+            A cette fin, une nouvelle interface d'extension (<literal>org.hibernate.context.CurrentSessionContext</literal>)
+            et un nouveau paramètre de configuration (<literal>hibernate.current_session_context_class</literal>)
+            ont été ajoutés pour permettre de configurer d'autres moyens de définir la portée et le contexte des
+            sessions courantes.
+        </para>
+        <para>
+            Allez voir les Javadocs de l'interface <literal>org.hibernate.context.CurrentSessionContext</literal>
+            pour une description détaillée de son contrat. Elle définit une seule méthode,
+            <literal>currentSession()</literal>, depuis laquelle l'implémentation est responsable
+            de traquer la session courante du contexte. Hibernate fournit deux implémentation 
+            de cette interface.
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.context.JTASessionContext</literal> - les sessions courantes sont
+                    associées à une transaction <literal>JTA</literal>.  La logique est la même que
+                    l'ancienne approche basée sur JTA. Voir les javadocs pour les détails.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.context.ThreadLocalSessionContext</literal> - les sessions
+                    courantes sont associées au thread d'exécution. Voir les javadocs pour les détails.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Les deux implémentations fournissent un modèle de programmation de type "une session - une transaction
+            à la base de données", aussi connu sous le nom de <emphasis>session-per-request</emphasis>. 
+            Le début et la fin d'une session Hibernate sont définis par la durée d'une transaction de base de données.
+            Si vous utilisez une démarcation programmatique de la transaction (par exemple sous J2SE ou JTA/UserTransaction/BMT),
+            nous vous conseillons d'utiliser l'API Hibernate <literal>Transaction</literal> pour masquer le système
+            de transaction utilisé. Si vous exécutez sous un conteneur EJB qui supporte CMT, vous n'avez besoin d'aucune
+            opérations de démarcations de session ou transaction dans votre code puisque tout
+            est géré de manière déclarative. Référez vous à <xref linkend="transactions"/> pour plus d'informations
+            et des exemples de code.
+        </para>
+
+        <para>
+            Le paramètre de configuration <literal>hibernate.current_session_context_class</literal> 
+            définit quelle implémentation de <literal>org.hibernate.context.CurrentSessionContext</literal> 
+            doit être utilisée. Notez que pour assurer la compatibilité avec les versions précédentes, si
+            ce paramètre n'est pas défini mais qu'un <literal>org.hibernate.transaction.TransactionManagerLookup</literal> 
+            est configuré, Hibernate utilisera le <literal>org.hibernate.context.JTASessionContext</literal>.
+            La valeur de ce paramètre devrait juste nommer la classe d'implémentation à utiliser, 
+            pour les deux implémentations fournies, il y a cependant deux alias correspondant: "jta" et "thread".
+        </para>
+        
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/association_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/association_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/association_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,623 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="associations">
+
+    <title>Mapper les associations</title>
+
+    <sect1 id="assoc-intro" revision="1">
+        <title>Introduction</title>
+        
+        <para>
+            Correctement mapper les associations est souvent la tâche la plus difficile.
+            Dans cette section nous traiterons les cas classiques les uns après les autres.
+            Nous commencerons d'abbord par les mappings unidirectionnels, puis nous aborderons
+            la question des mappings bidirectionnels. Nous illustrerons tous nos exemples 
+            avec les classes <literal>Person</literal> et <literal>Address</literal>.
+        </para>
+        
+        <para>
+        	Nous utiliserons deux critères pour classer les associations : le premier 
+        	sera de savoir si l'association est bâti sur une table supplémentaire d'association
+        	et le deuxieme sera basé sur la multiplicité de cette association.
+        </para>
+        
+        <para>
+        	Autoriser une clé étrangère nulle est considéré comme un mauvais choix dans 
+        	la construction d'un modèle de données. Nous supposerons donc que dans tous 
+        	les exemples qui vont suivre on aura interdit la valeur nulle pour les clés 
+        	étrangères. Attention, ceci ne veut pas dire que Hibernate ne supporte pas 
+        	les clés étrangères pouvant prendre des valeurs nulles, les exemples qui suivent 
+        	continueront de fonctionner si vous décidiez ne plus imposer la contrainte 
+        	de non-nullité sur les clés étrangères.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="assoc-unidirectional" revision="1">
+        <title>Association unidirectionnelle</title>
+        
+        <sect2 id="assoc-unidirectional-m21" >
+        <title>plusieurs à un</title>
+        
+        <para>
+            Une <emphasis>association plusieurs-à-un (many-to-one) unidirectionnelle </emphasis> 
+            est le type que l'on rencontre le plus souvent dans les associations unidirectionnelles.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-121">
+        <title>un à un</title>
+        
+        <para>
+            une <emphasis>association un-à-un (one-to-one) sur une clé étrangère</emphasis>
+            est presque identique. La seule différence est sur la contrainte d'unicité que
+            l'on impose à cette colonne.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId" 
+        unique="true"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        <para>
+            Une <emphasis>association un-à-un (one-to-one) unidirectionnelle sur une clé primaire</emphasis>
+            utilise un générateur d'identifiant particulier. (Remarquez que nous avons inversé le sens de cette
+            association dans cet exemple.)
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+</class>
+
+<class name="Address">
+    <id name="id" column="personId">
+        <generator class="foreign">
+            <param name="property">person</param>
+        </generator>
+    </id>
+    <one-to-one name="person" constrained="true"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+        <sect2 id="assoc-unidirectional-12m">
+        <title>un à plusieurs</title>
+        
+        <para>
+            Une <emphasis>association un-à-plusieurs (one-to-many) unidirectionnelle sur une 
+            clé étrangère</emphasis> est vraiment inhabituelle, et n'est pas vraiment recommandée.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses">
+        <key column="personId" 
+            not-null="true"/>
+        <one-to-many class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( addressId bigint not null primary key, personId bigint not null )
+        ]]></programlisting>
+        
+        <para>
+            Nous pensons qu'il est préférable d'utiliser une table de jointure pour ce type d'association.
+        </para>
+        
+        </sect2>
+    
+    </sect1>
+
+    <sect1 id="assoc-unidirectional-join" revision="1">
+        <title>Associations unidirectionnelles avec tables de jointure</title>
+        
+        <sect2 id="assoc-unidirectional-join-12m">
+        <title>un à plusieurs</title>
+        
+        <para>
+            Une <emphasis>association unidirectionnelle un-à-plusieurs (one-to-many) avec
+            une table de jointure</emphasis> est un bien meilleur choix. 
+            Remarquez qu'en spécifiant <literal>unique="true"</literal>,
+            on a changé la multiplicité plusieurs-à-plusieurs (many-to-many) pour 
+            un-à-plusieurs (one-to-many).
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            unique="true"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-m21">
+        <title>plusieurs à un</title>
+        
+        <para>
+            Une <emphasis>assiociation plusieurs-à-un (many-to-one) unidirectionnelle sur
+            une table de jointure</emphasis> est très fréquente quand l'association est optionnelle.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-121">
+        <title>un à un</title>
+        
+        <para>
+            Une <emphasis>association unidirectionnelle un-à-un (one-to-one) sur une table
+            de jointure</emphasis> est extrèmement rare mais envisageable.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-m2m">
+        <title>plusieurs à plusieurs</title>
+        
+        <para>
+            Finallement, nous avons <emphasis>l'association unidirectionnelle plusieurs-à-plusieurs (many-to-many)</emphasis>.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="assoc-bidirectional" revision="1">
+        <title>Associations bidirectionnelles</title>
+        
+        <sect2 id="assoc-bidirectional-m21" revision="2">
+        <title>un à plusieurs / plusieurs à un</title>
+        
+        <para>
+            Une <emphasis>association bidirectionnelle plusieurs à un (many-to-one)</emphasis>  
+            est le type d'association que l'on rencontre le plus souvent. (c'est la façon standard de créer
+            des relations parents/enfants.)
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <set name="people" inverse="true">
+        <key column="addressId"/>
+        <one-to-many class="Person"/>
+    </set>
+</class>]]></programlisting>
+
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        <para>
+            Si vous utilisez une <literal>List</literal> (ou toute autre collection indexée) vous devez
+            paramétrer la colonne <literal>key</literal> de la clé étrangère à <literal>not null</literal>,
+            et laisser Hibernate gérer l'association depuis l'extrémité collection pour maintenir l'index
+            de chaque élément (rendant l'autre extrémité virtuellement inverse en paramétrant
+            <literal>update="false"</literal> et <literal>insert="false"</literal>):
+        </para>
+
+        <programlisting><![CDATA[<class name="Person">
+   <id name="id"/>
+   ...
+   <many-to-one name="address"
+      column="addressId"
+      not-null="true"
+      insert="false"
+      update="false"/>
+</class>
+
+<class name="Address">
+   <id name="id"/>
+   ...
+   <list name="people">
+      <key column="addressId" not-null="true"/>
+      <list-index column="peopleIdx"/>
+      <one-to-many class="Person"/>
+   </list>
+</class>]]></programlisting>
+        
+        </sect2>
+        
+        <sect2 id="assoc-bidirectional-121">
+        <title>Un à un</title>
+        
+        <para>
+            Une <emphasis>association bidirectionnelle un à un (one-to-one) sur une clé étrangère</emphasis>
+            est aussi très fréquente.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId" 
+        unique="true"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+   <one-to-one name="person" 
+        property-ref="address"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        <para>
+            Une <emphasis>association bidirectionnelle un-à-un (one-to-one) sur une clé primaire</emphasis>
+            utilise un générateur particulier d'id.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <one-to-one name="address"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="personId">
+        <generator class="foreign">
+            <param name="property">person</param>
+        </generator>
+    </id>
+    <one-to-one name="person" 
+        constrained="true"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="assoc-bidirectional-join" revision="1">
+        <title>Associations bidirectionnelles avec table de jointure</title>
+        
+        <sect2 id="assoc-bidirectional-join-12m">
+        <title>un à plusieurs / plusieurs à un</title>
+        
+        <para>
+            Une <emphasis>association bidirectionnelle un-à-plusieurs (one-to-many) sur une table de jointure </emphasis>.
+            Remarquez que <literal>inverse="true"</literal> peut s'appliquer sur les deux extrémités de l'
+            association, sur la collection, ou sur la jointure.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" 
+        table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            unique="true"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        inverse="true" 
+        optional="true">
+        <key column="addressId"/>
+        <many-to-one name="person"
+            column="personId"
+            not-null="true"/>
+    </join>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+         <sect2 id="assoc-bidirectional-join-121">
+        <title>Un à un</title>
+        
+        <para>
+            Une <emphasis>association bidirectionnelle un-à-un (one-to-one) sur une table de jointure</emphasis> 
+            est extrèmement rare mais envisageable.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true"
+        inverse="true">
+        <key column="addressId" 
+            unique="true"/>
+        <many-to-one name="person"
+            column="personId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+
+        </sect2>
+        
+        <sect2 id="assoc-bidirectional-join-m2m" revision="1">
+        <title>plusieurs à plusieurs</title>
+        
+        <para>
+            Finallement nous avons <emphasis>l'association bidirectionnelle plusieurs à plusieurs</emphasis>.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <set name="people" inverse="true"  table="PersonAddress">
+        <key column="addressId"/>
+        <many-to-many column="personId"
+            class="Person"/>
+    </set>
+</class>]]></programlisting>
+
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+    </sect1>
+    
+    <sect1 id="assoc-complex">
+        <title>Des mappings plus complexes</title>
+        
+        <para>
+            Des associations encore plus complexes sont <emphasis>extrêmement</emphasis> rares. 
+            Hibernate permet de gérer des situations plus complexes en utilisant des
+            parties SQL dans les fichiers de mapping. Par exemple, si une table
+            avec l'historiques des informations d'un compte définit les colonnes
+            <literal>accountNumber</literal>, <literal>effectiveEndDate</literal> 
+            et <literal>effectiveStartDate</literal>, mappées de telle sorte:
+        </para>
+        
+        <programlisting><![CDATA[<properties name="currentAccountKey">
+    <property name="accountNumber" type="string" not-null="true"/>
+    <property name="currentAccount" type="boolean">
+        <formula>case when effectiveEndDate is null then 1 else 0 end</formula>
+    </property>
+</properties>
+<property name="effectiveEndDate" type="date"/>
+<property name="effectiveStateDate" type="date" not-null="true"/>]]></programlisting>
+
+        <para>
+            alors nous pouvons mapper une association à l'instance <emphasis>courante</emphasis>  
+            (celle avec une <literal>effectiveEndDate</literal>) nulle en utilisant:
+        </para>
+        
+        <programlisting><![CDATA[<many-to-one name="currentAccountInfo" 
+        property-ref="currentAccountKey"
+        class="AccountInfo">
+    <column name="accountNumber"/>
+    <formula>'1'</formula>
+</many-to-one>]]></programlisting>
+
+        <para>
+            Dans un exemple plus complexe, imaginez qu'une association entre
+            <literal>Employee</literal> et <literal>Organization</literal> est gérée
+            dans une table <literal>Employment</literal> pleines de données historiques.
+            Dans ce cas, une association vers l'employeur <emphasis>le plus récent</emphasis>
+            (celui avec la <literal>startDate</literal> la plus récente) pourrait être mappée comme cela:
+        </para>
+        
+        <programlisting><![CDATA[<join>
+    <key column="employeeId"/>
+    <subselect>
+        select employeeId, orgId 
+        from Employments 
+        group by orgId 
+        having startDate = max(startDate)
+    </subselect>
+    <many-to-one name="mostRecentEmployer" 
+            class="Organization" 
+            column="orgId"/>
+</join>]]></programlisting>
+
+        <para>
+            Vous pouvez être créatif grace à ces possibilités, mais il est généralement plus pratique
+            d'utiliser des requêtes HQL ou criteria dans ce genre de situation.
+        </para>
+
+    </sect1>
+
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/basic_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/basic_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/basic_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,3117 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<chapter id="mapping">
+    <title>Mapping O/R basique</title>
+    <sect1 id="mapping-declaration" revision="1">
+        <title>Déclaration de Mapping</title>
+        <para>
+            Les mappings Objet/relationnel sont généralement définis dans un document XML. 
+            Le document de mapping est conçu pour être lisible et éditable à la main. 
+            Le langage de mapping est Java-centrique, c'est à dire que les mappings sont construits 
+            à partir des déclarations des classes persistantes et non des déclarations des tables.
+        </para>
+        <para>
+            Remarquez que même si beaucoup d'utilisateurs de Hibernate préfèrent écrire les 
+            fichiers de mappings à la main, plusieurs outils existent pour générer ce document, 
+            notamment XDoclet, Middlegen et AndroMDA.
+        </para>
+        <para>Démarrons avec un exemple de mapping :</para>
+        <programlisting id="mapping-declaration-ex1" revision="1"><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+        <class name="Cat" 
+            table="cats"
+            discriminator-value="C">
+                
+                <id name="id">
+                        <generator class="native"/>
+                </id>
+
+                <discriminator column="subclass" 
+                     type="character"/>
+
+                <property name="weight"/>
+
+                <property name="birthdate"
+                    type="date" 
+                    not-null="true" 
+                    update="false"/>
+
+                <property name="color"
+                    type="eg.types.ColorUserType"
+                    not-null="true"
+                    update="false"/>
+
+                <property name="sex"
+                    not-null="true" 
+                    update="false"/>
+
+                <property name="litterId"
+                    column="litterId"
+                    update="false"/>
+
+                <many-to-one name="mother"
+                    column="mother_id"
+                    update="false"/>
+
+                <set name="kittens"
+                    inverse="true"
+                    order-by="litter_id">
+                        <key column="mother_id"/>
+                        <one-to-many class="Cat"/>
+                </set>
+
+                <subclass name="DomesticCat"
+                    discriminator-value="D">
+
+                        <property name="name" 
+                            type="string"/>
+
+                </subclass>
+
+        </class>
+
+        <class name="Dog">
+                <!-- mapping for Dog could go here -->
+        </class>
+
+</hibernate-mapping>]]></programlisting>
+        <para>
+             Etudions le contenu du document de mapping. Nous décrirons uniquement 
+             les éléments et attributs du document utilisés par Hibernate à l'exécution. 
+             Le document de mapping contient aussi des attributs et éléments optionnels 
+             qui agissent sur le schéma de base de données exporté par l'outil de 
+             génération de schéma. (Par exemple l'attribut <literal>not-null</literal>.)
+        </para>
+        <sect2 id="mapping-declaration-doctype" revision="2">
+            <title>Doctype</title>
+            <para>
+                Tous les mappings XML devraient utiliser le doctype indiqué. 
+                Ce fichier est présent à l'URL ci-dessus, dans le répertoire 
+                <literal>hibernate-x.x.x/src/org/hibernate</literal> ou dans <literal>hibernate3.jar</literal>. 
+                Hibernate va toujours chercher la DTD dans son classpath en premier lieu. Si vous constatez 
+                des recherches de la DTD sur Internet, vérifiez votre déclaration de DTD par rapport 
+                au contenu de votre classpath.
+            </para>
+        </sect2>
+        <sect2 id="mapping-declaration-mapping" revision="3">
+            <title>hibernate-mapping</title>
+            <para>
+                Cet élément a plusieurs attributs optionnels. Les attributs <literal>schema</literal> et <literal>catalog</literal> 
+                indiquent que les tables référencées par ce mapping appartiennent au schéma nommé et/ou au catalogue. 
+                S'ils sont spécifiés, les noms de tables seront qualifiés par les noms de schéma et catalogue. 
+                L'attribut <literal>default-cascade</literal> indique quel type de cascade sera utlisé par défaut 
+                pour les propriétés et collections qui ne précisent pas l'attribut <literal>cascade</literal>. 
+                L'attribut <literal>auto-import</literal> nous permet d'utiliser par défaut des noms de classes 
+                non qualifiés dans le langage de requête.
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="hm1" coords="2 55"/>
+                    <area id="hm2" coords="3 55"/>
+                    <area id="hm3" coords="4 55"/>
+                    <area id="hm4" coords="5 55"/>
+                    <area id="hm5" coords="6 55"/>
+                    <area id="hm6" coords="7 55"/>
+                    <area id="hm7" coords="8 55"/>
+                </areaspec>
+                <programlisting><![CDATA[<hibernate-mapping
+         schema="schemaName"
+         catalog="catalogName"
+         default-cascade="cascade_style"
+         default-access="field|property|ClassName"
+         default-lazy="true|false"
+         auto-import="true|false"
+         package="package.name"
+ />]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="hm1">
+                        <para>
+                            <literal>schema</literal> (optionnel) : Le nom d'un schéma de base de données.
+                         </para>
+                    </callout>
+                    <callout arearefs="hm2">
+                        <para>
+                            <literal>catalog</literal> (optionnel) : Le nom d'un catalogue de base de données.
+                         </para>
+                    </callout>
+                    <callout arearefs="hm3">
+                        <para>
+                            <literal>default-cascade</literal> (optionnel - par défaut vaut :  <literal>none</literal>) : 
+                             Un type de cascade par défaut.
+                         </para>
+                    </callout>
+                    <callout arearefs="hm4">
+                        <para>
+                            <literal>default-access</literal> (optionnel - par défaut vaut : <literal>property</literal>) :
+                            Comment hibernate accèdera aux propriétés. On peut aussi 
+                            redéfinir sa propre implémentation de <literal>PropertyAccessor</literal>.
+                         </para>
+                    </callout>
+                    <callout arearefs="hm5">
+                        <para>
+                            <literal>default-lazy</literal> (optionnel - par défaut vaut : <literal>true</literal>) :
+                             Valeur par défaut pour un attribut <literal>lazy</literal> 
+                             non spécifié : celui des mappings de classes et de collection.
+                         </para>
+                    </callout>
+                    <callout arearefs="hm6">
+                        <para>
+                            <literal>auto-import</literal> (optionnel - par défaut vaut : <literal>true</literal>) :
+                             Spécifie si l'on peut utiliser des noms de classes 
+                             non qualifiés (des classes de ce mapping) dans le langage de requête.
+                         </para>
+                    </callout>
+                    <callout arearefs="hm7">
+                        <para>
+                            <literal>package</literal> (optionnel) : Préfixe de package par défaut pour 
+                            les noms de classe non qualifiés du document de mapping.
+                             
+                         </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                 Si deux classes possèdent le même nom de classe (non qualifié), vous devez indiquer 
+                 <literal>auto-import="false"</literal>. Hibernate lancera une exception 
+                 si vous essayez d'assigner à deux classes le même nom importé.
+             </para>
+            <para>
+                 Notez que l'élément <literal>hibernate-mapping</literal> vous permet d'imbriquer plusieurs mappings de
+                 <literal>&lt;class&gt;</literal> persistantes, comme dans l'exemple ci-dessus.
+                 Cependant la bonne pratique (ce qui est attendu par certains outils) est 
+                 de mapper une seule classe (ou une seule hiérarchie de classes)
+                 par fichier de mapping et de nommer ce fichier d'après le nom de la superclasse, par exemple
+                 <literal>Cat.hbm.xml</literal>, <literal>Dog.hbm.xml</literal>, ou en cas d'héritage,
+                 <literal>Animal.hbm.xml</literal>.
+             </para>
+        </sect2>
+        <sect2 id="mapping-declaration-class" revision="3">
+            <title>class</title>
+            <para>
+                Déclarez une classe persistante avec l'élément <literal>class</literal> :
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="class1" coords="2 55"/>
+                    <area id="class2" coords="3 55"/>
+                    <area id="class3" coords="4 55"/>
+                    <area id="class4" coords="5 55"/>
+                    <area id="class5" coords="6 55"/>
+                    <area id="class6" coords="7 55"/>
+                    <area id="class7" coords="8 55"/>
+                    <area id="class8" coords="9 55"/>
+                    <area id="class9" coords="10 55"/>
+                    <area id="class10" coords="11 55"/>
+                    <area id="class11" coords="12 55"/>
+                    <area id="class12" coords="13 55"/>
+                    <area id="class13" coords="14 55"/>
+                    <area id="class14" coords="15 55"/>
+                    <area id="class15" coords="16 55"/>
+                    <area id="class16" coords="17 55"/>
+                    <area id="class17" coords="18 55"/>
+                    <area id="class18" coords="19 55"/>
+                    <area id="class19" coords="20 55"/>
+                    <area id="class20" coords="21 55"/>
+                    <area id="class21" coords="22 55"/>
+                </areaspec>
+                <programlisting><![CDATA[<class
+        name="ClassName"
+        table="tableName"
+        discriminator-value="discriminator_value"
+        mutable="true|false"
+        schema="owner"
+        catalog="catalog"
+        proxy="ProxyInterface"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        select-before-update="true|false"
+        polymorphism="implicit|explicit"
+        where="arbitrary sql where condition"
+        persister="PersisterClass"
+        batch-size="N"
+        optimistic-lock="none|version|dirty|all"
+        lazy="true|false"
+        entity-name="EntityName"
+        catalog="catalog"
+        check="arbitrary sql check condition"
+        rowid="rowid"
+        subselect="SQL expression"
+        abstract="true|false"
+        entity-name="EntityName"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="class1">
+                        <para>
+                            <literal>name</literal> (optionnel) : Le nom Java complet de la classe (ou interface) persistante.
+                             Si cet attribut est absent, il est supposé que ce mapping ne se rapporte pas à une entité POJO.
+                        </para>
+                    </callout>
+                    <callout arearefs="class2">
+                        <para>
+                            <literal>table</literal> (optionnel - par défaut le nom (non-qualifié) de la classe) :  Le 
+                            nom de sa table en base de données.
+                        </para>
+                    </callout>
+                    <callout arearefs="class3">
+                        <para>
+                            <literal>discriminator-value</literal> (optionnel - par défaut le nom de la classe) : 
+                            Une valeur permettant de distinguer les sous-classes dans le cas de l'utilisation du polymorphisme. 
+                            Les valeurs <literal>null</literal> et <literal>not null</literal> sont autorisées.
+                        </para>
+                    </callout>
+                    <callout arearefs="class4">
+                        <para>
+                            <literal>mutable</literal> (optionnel, vaut <literal>true</literal> par défaut) : Spécifie 
+                            que des instances de la classe sont (ou non) immuables.
+                        </para>
+                    </callout>
+                    <callout arearefs="class5">
+                        <para>
+                            <literal>schema</literal> (optionnel) : Surcharge le nom de schéma spécifié par 
+                            l'élément racine <literal>&lt;hibernate-mapping&gt;</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="class6">
+                        <para>
+                            <literal>catalog</literal> (optionnel) : Surcharge le nom du catalogue spécifié par
+                            l'élément racine <literal>&lt;hibernate-mapping&gt;</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="class7">
+                        <para>
+                            <literal>proxy</literal> (optionnel) : Spécifie une interface à utiliser pour l'initialisation différée (lazy loading)
+                            des proxies. Vous pouvez indiquer le nom de la classe elle-même.
+                        </para>
+                    </callout>
+                    <callout arearefs="class8">
+                        <para>
+                            <literal>dynamic-update</literal> (optionnel, par défaut à <literal>false</literal>) : 
+                            Spécifie que les  <literal>UPDATE</literal> SQL doivent être générés à l'exécution et contenir 
+                            uniquement les colonnes dont les valeurs ont été modifiées.
+                        </para>
+                    </callout>
+                    <callout arearefs="class9">
+                        <para>
+                            <literal>dynamic-insert</literal> (optionnel, par défaut à <literal>false</literal>): 
+                            Spécifie que les <literal>INSERT</literal> SQL doivent être générés à l'exécution et ne contenir 
+                            que les colonnes dont les valeurs sont non nulles.
+                        </para>
+                    </callout>
+                    <callout arearefs="class10">
+                        <para>
+                            <literal>select-before-update</literal> (optionnel, par défaut à <literal>false</literal>): 
+                            Spécifie que Hibernate ne doit <emphasis>jamais</emphasis> exécuter un <literal>UPDATE</literal> SQL 
+                            sans être certain qu'un objet a été réellement modifié. Dans certains cas, (en réalité, seulement 
+                            quand un objet transient a été associé à une nouvelle session par <literal>update()</literal>), 
+                            cela signifie que Hibernate exécutera un <literal>SELECT</literal> SQL pour s'assurer qu'un 
+                            <literal>UPDATE</literal> SQL est véritablement nécessaire.
+                        </para>
+                    </callout>
+                    <callout arearefs="class11">
+                        <para>
+                            <literal>polymorphism</literal> (optionnel, vaut <literal>implicit</literal> par défaut) : 
+                            Détermine si, pour cette classe, une requête polymorphique implicite ou explicite est utilisée.
+                        </para>
+                    </callout>
+                    <callout arearefs="class12">
+                        <para>
+                            <literal>where</literal> (optionnel) spécifie une clause SQL <literal>WHERE</literal> 
+                            à utiliser lorsque l'on récupère des objets de cette classe.
+                        </para>
+                    </callout>
+                    <callout arearefs="class13">
+                        <para>
+                            <literal>persister</literal> (optionnel) : Spécifie un <literal>ClassPersister</literal> particulier.
+                        </para>
+                    </callout>
+                    <callout arearefs="class14">
+                        <para>
+                            <literal>batch-size</literal> (optionnel, par défaut = <literal>1</literal>) : spécifie une taille de batch 
+                            pour remplir les instances de cette classe par identifiant en une seule requête.
+                        </para>
+                    </callout>
+                    <callout arearefs="class15">
+                        <para>
+                            <literal>optimistic-lock</literal> (optionnel, par défaut = <literal>version</literal>) : 
+                            Détermine la stratégie de verrou optimiste.
+                        </para>
+                    </callout>
+                    <callout arearefs="class16">
+                        <para>
+                            <literal>lazy</literal> (optionnel) : Déclarer <literal>lazy="true"</literal> est un raccourci
+                            pour spécifier le nom de la classe comme étant l'interface <literal>proxy</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="class17">
+                        <para>
+                            <literal>entity-name</literal> (optionnel) : Hibernate3 permet à une classe d'être
+                            mappée plusieurs fois (potentiellement à plusieurs tables), et permet aux mappings d'entité d'être
+                            représentés par des Maps ou du XML au niveau Java. Dans ces cas, vous devez indiquer un nom explicite arbitraire pour
+                            les entités. Voir <xref linkend="persistent-classes-dynamicmodels"/> et <xref linkend="xml"/>
+                            pour plus d'informations.
+                        </para>
+                    </callout>
+                    <callout arearefs="class18">
+                        <para>
+                            <literal>catalog</literal> (optionnel) : The name of a database catalog used for this
+                            class and its table.
+                        </para>
+                    </callout>
+                    <callout arearefs="class19">
+                        <para>
+                            <literal>check</literal> (optionnel) : expression SQL utilisée pour générer une contrainte 
+                            de vérification multi-lignes pour la génération automatique de schéma.
+                        </para>
+                    </callout>
+                    <callout arearefs="class20">
+                        <para>
+                            <literal>rowid</literal> (optionnel) : Hibernate peut utiliser des ROWID sur les bases de
+                            données qui utilisent ce mécanisme. Par exemple avec Oracle, Hibernate peut utiliser la colonne additionnelle 
+                            <literal>rowid</literal> pour des mises à jour rapides si cette option vaut  <literal>rowid</literal>. Un ROWID représente
+                            la localisation physique d'un tuple enregistré.
+                        </para>
+                    </callout>
+                    <callout arearefs="class21">
+                        <para>
+                            <literal>subselect</literal> (optionnel) : Permet de mapper une entité immuable en lecture-seule 
+                            sur un sous-select de base de données. Utile pour avoir une vue au lieu d'une table en base, mais à éviter. Voir plus bas 
+                            pour plus d'information.
+                        </para>
+                    </callout>
+                    <callout arearefs="class22">
+                        <para>
+                            <literal>abstract</literal> (optionnel) : Utilisé pour marquer des superclasses abstraites dans 
+                            des hiérarchies de <literal>&lt;union-subclass&gt;</literal>.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                Il est tout à fait possible d'utiliser une interface comme nom 
+                de classe persistante. Vous devez alors déclarer les classes implémentant
+                cette interface en utilisant l'élément <literal>&lt;subclass&gt;</literal>. 
+                Vous pouvez faire persister toute classe interne <emphasis>static</emphasis>. 
+                Vous devez alors spécifier le nom de la classe par la notation habituelle 
+                des classes internes c'est à dire <literal>eg.Foo$Bar</literal>.
+            </para>
+            <para>
+                Les classes immuables, <literal>mutable="false"</literal>, ne peuvent 
+                pas être modifiées ou supprimées par l'application. Cela permet 
+                à Hibernate de faire quelques optimisations mineures sur les performances.
+            </para>
+            <para>
+                L'attribut optionnnel <literal>proxy</literal> permet les intialisations 
+                différées des instances persistantes de la classe. Hibernate retournera 
+                initialement des proxies CGLIB qui implémentent l'interface nommée. 
+                Le véritable objet persistant ne sera chargé que lorsque une méthode du proxy 
+                sera appelée. Voir plus bas le paragraphe abordant les proxies et le chargement différé (lazy initialization).
+            </para>
+            <para>
+                Le polymorphisme <emphasis>implicite</emphasis> 
+                signifie que les instances de la classe seront retournées par une 
+                requête qui utilise les noms de la classe ou de chacune de ses 
+                superclasses ou encore des interfaces implémentées par cette classe 
+                ou ses superclasses. Les instances des classes filles seront retournées 
+                par une requête qui utilise le nom de la classe elle même. Le polymorphisme 
+                <emphasis>explicite</emphasis>   signifie que les instances de la classe 
+                ne seront retournées que par une requête qui utilise explicitement 
+                son nom et que seules les instances des classes filles déclarées dans les éléments 
+                <literal>&lt;subclass&gt;</literal> ou <literal>&lt;joined-subclass&gt;</literal> 
+                seront retournées. Dans la majorités des cas la valeur par défaut, 
+                <literal>polymorphism="implicit"</literal>,
+                est appropriée. Le polymorphisme explicite est utile lorsque deux 
+                classes différentes sont mappées à la même table (ceci permet d'écrire 
+                une classe "légère" qui ne contient qu'une partie des colonnes de 
+                la table - voir la partie design pattern du site communautaire). 
+            </para>
+            <para>
+                L'attribut <literal>persister</literal> vous permet de customiser 
+                la stratégie utilisée pour la classe. Vous pouvez, par exemple, spécifier 
+                votre propre sous-classe de <literal>org.hibernate.persister.EntityPersister</literal> ou 
+                vous pourriez aussi créer une nouvelle implémentation de l'interface <literal>org.hibernate.persister.ClassPersister</literal> 
+                qui proposerait une persistance via, par exemple, des appels de procédures 
+                stockées, de la sérialisation vers des fichiers plats ou un annuaire LDAP. 
+                Voir <literal>org.hibernate.test.CustomPersister</literal> pour un exemple simple (d'une "persistance" 
+                vers une <literal>Hashtable</literal>).
+            </para>
+            <para>
+                Notez que les paramètres <literal>dynamic-update</literal> et <literal>dynamic-insert</literal> 
+                ne sont pas hérités par les sous-classes et peuvent donc être spécifiés 
+                pour les éléments <literal>&lt;subclass&gt;</literal> ou <literal>&lt;joined-subclass&gt;</literal>
+                Ces paramètres peuvent améliorer les performances dans certains cas, 
+                mais peuvent aussi les amoindrir. A utiliser en connaissance de causes.
+            </para>
+            <para>
+                L'utilisation de <literal>select-before-update</literal> va généralement 
+                faire baisser les performances. Ce paramètre est pratique  
+                pour prévenir l'appel inutile d'un trigger sur modification quand on 
+                réattache un graphe d'instances à une <literal>Session</literal>.
+            </para>
+            <para>
+                Si vous utilisez le <literal>dynamic-update</literal>, les différentes 
+                stratégies de verrouillage optimiste (optimistic locking) sont les suivantes:
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <literal>version</literal> vérifie les colonnes version/timestamp
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>all</literal> vérifie toutes les colonnes
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>dirty</literal> vérifie les colonnes modifiées, permettant des updates concurrents
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>none</literal> pas de verrouillage optimiste
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <para>
+                Nous encourageons <emphasis>très</emphasis> fortement l'utilisation 
+                de colonnes de version/timestamp pour le verrouillage optimiste 
+                avec Hibernate. C'est la meilleure stratégie en regard des performances 
+                et la seule qui gère correctement les modifications sur les objets détachés 
+                (c'est à dire lorsqu'on utilise <literal>Session.merge()</literal>).
+            </para>
+            <para>
+                Il n'y a pas de différence entre table et vue pour le mapping Hibernate, 
+                tant que c'est transparent au niveau base de données (remarquez 
+                que certaines BDD ne supportent pas les vues correctement, notamment 
+                pour les updates). Vous rencontrerez peut-être des cas où vous 
+                souhaitez utiliser une vue mais ne pouvez pas en créer sur votre BDD 
+                (par exemple à cause de schémas anciens et figés). Dans ces cas, 
+                vous pouvez mapper une entité immuable en lecture seule sur un sous-select SQL donné:
+            </para>
+            <programlisting><![CDATA[<class name="Summary">
+    <subselect>
+        select item.name, max(bid.amount), count(*)
+        from item
+        join bid on bid.item_id = item.id
+        group by item.name
+    </subselect>
+    <synchronize table="item"/>
+    <synchronize table="bid"/>
+    <id name="name"/>
+    ...
+</class>]]></programlisting>
+            <para>
+                Déclarez les tables à synchroniser avec cette entité pour assurer 
+                que le flush automatique se produise correctement,
+                et pour que les requêtes sur l'entité dérivée ne renvoient pas des données périmées.    
+                Le litéral <literal>&lt;subselect&gt;</literal> est disponible 
+                comme attribut ou comme élément de mapping.
+            </para>
+        </sect2>
+        <sect2 id="mapping-declaration-id" revision="4">
+            <title>id</title>
+            <para>
+                Les classes mappées <emphasis>doivent</emphasis> déclarer la 
+                clef primaire de la table en base de données.
+                La plupart des classes auront aussi une propriété de type 
+                javabean présentant l'identifiant unique d'une instance.
+                L'élément <literal>&lt;id&gt;</literal> sert à définir le 
+                mapping entre cette propriété et la clef primaire en base.
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="id1" coords="2 65"/>
+                    <area id="id2" coords="3 65"/>
+                    <area id="id3" coords="4 65"/>
+                    <area id="id4" coords="5 65"/>
+                    <area id="id5" coords="6 65"/>
+                </areaspec>
+                <programlisting><![CDATA[<id
+        name="propertyName"
+        type="typename"
+        column="column_name"
+        unsaved-value="null|any|none|undefined|id_value"
+        access="field|property|ClassName">
+
+        <generator class="generatorClass"/>
+</id>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="id1">
+                        <para>
+                            <literal>name</literal> (optionnel) : Nom de la propriété qui sert d'identifiant.
+                        </para>
+                    </callout>
+                    <callout arearefs="id2">
+                        <para>
+                            <literal>type</literal> (optionnel) : Nom indiquant le type Hibernate.
+                        </para>
+                    </callout>
+                    <callout arearefs="id3">
+                        <para>
+                            <literal>column</literal> (optionnel - le nom de la propriété est pris par défaut) : Nom de la clef primaire.
+                        </para>
+                    </callout>
+                    <callout arearefs="id4">
+                        <para>
+                            <literal>unsaved-value</literal> (optionnel - par défaut une valeur "bien choisie") : 
+                            Une valeur de la propriété d'identifiant qui indique que l'instance est nouvellement
+                            instanciée (non sauvegardée), et qui la distingue des instances <literal>transient</literal>s qui ont
+                            été sauvegardées ou chargées dans une session précédente.
+                        </para>
+                    </callout>
+                    <callout arearefs="id5">
+                        <para>
+                            <literal>access</literal> (optionnel - par défaut <literal>property</literal>) : La stratégie que doit utiliser Hibernate 
+                            pour accéder aux valeurs des propriétés.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                Si l'attribut <literal>name</literal> est absent, Hibernate considère que la classe ne possède pas de propriété identifiant.
+            </para>
+            <para>
+                L'attribut <literal>unsaved-value</literal> est important ! Si 
+                l'identifiant de votre classe n'a pas une valeur par défaut compatible avec 
+                le comportement standard de Java (zéro ou null), vous devez alors préciser la valeur par défaut.
+            </para>
+            <para>
+                La déclaration alternative <literal>&lt;composite-id&gt;</literal> 
+                permet l'acccès aux données d'anciens systèmes qui utilisent des
+                clefs composées. Son utilisation est fortement déconseillée pour d'autres cas.
+            </para>
+            <sect3 id="mapping-declaration-id-generator" revision="2">
+                <title>Generator</title>
+                <para>
+                        L'élément fils <literal>&lt;generator&gt;</literal> nomme une classe Java utilisée pour générer 
+                        les identifiants uniques pour les instances des classes persistantes. Si des paramètres sont requis 
+                        pour configurer ou initialiser l'instance du générateur, ils sont passés en utilisant l'élément <literal>&lt;param&gt;</literal>.
+                </para>
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="org.hibernate.id.TableHiLoGenerator">
+                <param name="table">uid_table</param>
+                <param name="column">next_hi_value_column</param>
+        </generator>
+</id>]]></programlisting>
+                <para>
+                        Tous les générateurs doivent implémenter l'interface <literal>org.hibernate.id.IdentifierGenerator</literal>.
+                        C'est une interface très simple ; certaines applications peuvent proposer leur propre implémentations spécialisées. 
+                        Cependant, Hibernate propose une série d'implémentations intégrées. Il existe des noms raccourcis pour les générateurs intégrés :
+                    <variablelist>
+                        <varlistentry>
+                            <term>
+                                <literal>increment</literal>
+                            </term>
+                            <listitem>
+                                <para>
+                                    Génère des identifiants de type <literal>long</literal>, <literal>short</literal> ou
+                                    <literal>int</literal> qui ne sont uniques que si aucun autre processus n'insère de données dans la même table.
+                                    <emphasis>Ne pas utiliser en environnement clusterisé.</emphasis>
+                                </para>
+                            </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                            <term>
+                                <literal>identity</literal>
+                            </term>
+                            <listitem>
+                                <para>
+                                    Utilisation de la colonne identity de DB2, MySQL, MS SQL Server, Sybase et
+                                    HypersonicSQL. L'identifiant renvoyé est de type <literal>long</literal>,
+                                    <literal>short</literal> ou <literal>int</literal>.
+                            </para>
+                            </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                            <term>
+                                <literal>sequence</literal>
+                            </term>
+                            <listitem>
+                                <para>
+                                    Utilisation des séquences dans  DB2, PostgreSQL, Oracle, SAP DB, McKoi ou d'un générateur dans Interbase.
+                                    L'identifiant renvoyé est de type <literal>long</literal>,
+                                    <literal>short</literal> ou <literal>int</literal>
+                                </para>
+                            </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                            <term>
+                                <literal>hilo</literal>
+                            </term>
+                            <listitem>
+                                <para id="mapping-declaration-id-hilodescription" revision="1">
+                                    Utilise un algorithme hi/lo pour générer de façon efficace des identifiants de type
+                                    <literal>long</literal>, <literal>short</literal> ou <literal>int</literal>,
+                                    en prenant comme source de valeur "hi" une table et une colonne (par défaut 
+                                    <literal>hibernate_unique_key</literal> et
+                                    <literal>next_hi</literal> respectivement). L'algorithme hi/lo génère des identifiants uniques 
+                                    pour une base de données particulière seulement.
+                            </para>
+                            </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                            <term>
+                                <literal>seqhilo</literal>
+                            </term>
+                            <listitem>
+                                <para>
+                                    Utilise un algorithme hi/lo pour générer efficacement des identifiants de type                                      <literal>long</literal>, <literal>short</literal> ou <literal>int</literal>,
+                                    étant donné un nom de séquence en base.
+                            </para>
+                            </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                            <term>
+                                <literal>uuid</literal>
+                            </term>
+                            <listitem>
+                                <para>
+                                    Utilise un algorithme de type UUID 128 bits pour générer des identifiants de 
+                                    type string, unique au sein d'un réseau (l'adresse IP est utilisée). 
+                                    Le UUID en codé en une chaîne de nombre héxadécimaux de longueur 32.
+                            </para>
+                            </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                            <term>
+                                <literal>guid</literal>
+                            </term>
+                            <listitem>
+                                <para>
+                                    Utilise une chaîne GUID générée par la base pour MS SQL Server et MySQL.
+                            </para>
+                            </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                            <term>
+                                <literal>native</literal>
+                            </term>
+                            <listitem>
+                                <para>
+                                    Choisit <literal>identity</literal>, <literal>sequence</literal> ou
+                                    <literal>hilo</literal> selon les possibilités offertes par la base de données sous-jacente.
+                            </para>
+                            </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                            <term>
+                                <literal>assigned</literal>
+                            </term>
+                            <listitem>
+                                <para>
+                                    Laisse l'application affecter un identifiant à l'objet avant que la métode 
+                                    <literal>save()</literal> soit appelée. Il s'agit de la stratégie par défaut 
+                                    si aucun <literal>&lt;generator&gt;</literal> n'est spécifié.
+                            </para>
+                            </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                            <term>
+                                <literal>select</literal>
+                            </term>
+                            <listitem>
+                                <para>
+                                    Récupère une clef primaire assignée par un trigger en sélectionnant 
+                                    la ligne par une clef unique quelconque.
+                            </para>
+                            </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                            <term>
+                                <literal>foreign</literal>
+                            </term>
+                            <listitem>
+                                <para>
+                                    Utilise l'identifiant d'un objet associé. Habituellement utilisé en conjonction
+                                    avec une association <literal>&lt;one-to-one&gt;</literal> sur la clef primaire.
+                            </para>
+                            </listitem>
+                        </varlistentry>
+                    </variablelist>
+                </para>
+            </sect3>
+            <sect3 id="mapping-declaration-id-hilo" revision="1">
+                <title>algorithme Hi/lo</title>
+                <para>
+                    Les générateurs <literal>hilo</literal> et <literal>seqhilo</literal> proposent deux implémentations
+                    alternatives de l'algorithme hi/lo, une approche largement utilisée pour générer des identifiants. La 
+                    première implémentation nécessite une table "spéciale" en base pour héberger la prochaine valeur "hi" disponible.
+                    La seconde utilise une séquence de type Oracle (quand la base sous-jacente le propose).
+                </para>
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="hilo">
+                <param name="table">hi_value</param>
+                <param name="column">next_value</param>
+                <param name="max_lo">100</param>
+        </generator>
+</id>]]></programlisting>
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="seqhilo">
+                <param name="sequence">hi_value</param>
+                <param name="max_lo">100</param>
+        </generator>
+</id>]]></programlisting>
+                <para>
+                    Malheureusement, vous ne pouvez pas utilisez <literal>hilo</literal> quand vous apportez 
+                    votre propre <literal>Connection</literal> à Hibernate. Quand Hibernate utilise une datasource du serveur 
+                    d'application pour obtenir des connexions inscrites avec JTA, vous devez correctement configurer 
+                    <literal>hibernate.transaction.manager_lookup_class</literal>.
+                </para>
+            </sect3>
+            <sect3 id="mapping-declaration-id-uuid">
+                <title>UUID algorithm</title>
+                <para>
+                    Le contenu du UUID est : adresse IP, date de démarrage de la JVM (précis au quart de seconde), 
+                    l'heure système et un compteur (unique au sein de la JVM). Il n'est pas possible d'obtenir l'adresse 
+                    MAC ou une adresse mémoire à partir de Java, c'est donc le mieux que l'on puisse faire sans utiliser JNI.
+                </para>
+            </sect3>
+            <sect3 id="mapping-declaration-id-sequences">
+                <title>Colonnes identifiantes et séquences</title>
+                <para>
+                    Pour les bases qui implémentent les colonnes "identité" (DB2, MySQL, Sybase, MS SQL), 
+                    vous pouvez utiliser la génération de clef par <literal>identity</literal>. 
+                    Pour les bases qui implémentent les séquences (DB2, Oracle, PostgreSQL, Interbase, McKoi, SAP DB) 
+                    vous pouvez utiliser la génération de clef par <literal>sequence</literal>. Ces deux méthodes nécessitent
+                    deux requêtes SQL pour insérer un objet.
+                </para>
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+        <generator class="sequence">
+                <param name="sequence">person_id_sequence</param>
+        </generator>
+</id>]]></programlisting>
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id" unsaved-value="0">
+        <generator class="identity"/>
+</id>]]></programlisting>
+                   <para>Pour le développement multi-plateformes, la stratégie <literal>native</literal> choisira
+                    entre les méthodes <literal>identity</literal>, <literal>sequence</literal> et
+                    <literal>hilo</literal>, selon les possibilités offertes par la base sous-jacente.
+                </para>
+            </sect3>
+            <sect3 id="mapping-declaration-id-assigned">
+                <title>Identifiants assignés</title>
+                <para>
+                    Si vous souhaitez que l'application assigne des identifiants (par opposition 
+                    à la génération par Hibernate), vous pouvez utiliser le générateur  <literal>assigned</literal>.
+                    Ce générateur spécial utilisera une valeur d'identifiant déjà utilisé par la propriété identifiant l'objet.
+                    Ce générateur est utilisé quand la clef primaire est une clef naturelle plutôt qu'une clef secondaire.
+                    C'est le comportement par défaut si vous ne précisez pas d'élément <literal>&lt;generator&gt;</literal>.
+                </para>
+                <para>
+                    Choisir le générateur <literal>assigned</literal> fait utiliser
+                    <literal>unsaved-value="undefined"</literal> par Hibernate, le forçant à interroger
+                    la base pour déterminer si l'instance est transiente ou détachée, à moins d'utiliser 
+                    une propriété version ou timestamp, ou alors de définir 
+                    <literal>Interceptor.isUnsaved()</literal>.
+                </para>
+            </sect3>
+            <sect3 id="mapping-declaration-id-select">
+                <title>Clefs primaires assignées par trigger</title>
+                <para>
+                    Pour les schémas de base hérités d'anciens systèmes uniquement (Hibernate ne génère pas de DDL avec des triggers)  
+                </para>
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+        <generator class="select">
+                <param name="key">socialSecurityNumber</param>
+        </generator>
+</id>]]></programlisting>
+                <para>
+                    Dans l'exemple ci-dessus, <literal>socialSecurityNumber</literal> a une 
+                    valeur unique définie par la classe en tant que clef naturelle et <literal>person_id</literal> 
+                    est une clef secondaire dont la valeur est générée par trigger.
+                </para>
+            </sect3>
+        </sect2>
+        <sect2 id="mapping-declaration-compositeid" revision="3">
+            <title>composite-id</title>
+            <programlisting><![CDATA[<composite-id
+        name="propertyName"
+        class="ClassName"
+        mapped="true|false"
+        access="field|property|ClassName">
+        node="element-name|."
+
+        <key-property name="propertyName" type="typename" column="column_name"/>
+        <key-many-to-one name="propertyName class="ClassName" column="column_name"/>
+        ......
+</composite-id>]]></programlisting>
+            <para>
+               Pour une table avec clef composée, vous pouvez mapper plusieurs attributs de la classe 
+               comme propriétés identifiantes. L'élement <literal>&lt;composite-id&gt;</literal> accepte 
+               les mappings de propriétés <literal>&lt;key-property&gt;</literal> et les mappings 
+               <literal>&lt;key-many-to-one&gt;</literal> comme fils.
+            </para>
+            <programlisting><![CDATA[<composite-id>
+        <key-property name="medicareNumber"/>
+        <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+            <para>
+                Vos classes persistantes <emphasis>doivent</emphasis> surcharger les méthodes <literal>equals()</literal> 
+                et <literal>hashCode()</literal> pour implémenter l'égalité d'identifiant composé. Elles doivent aussi 
+                implenter l'interface <literal>Serializable</literal>.
+            </para>
+            <para>
+                Malheureusement cette approche sur les identifiants composés signifie qu'un objet persistant
+                est son propre identifiant. Il n'y a pas d'autre moyen pratique de manipuler l'objet que par l'objet lui-même.
+                Vous devez instancier une instance de la classe persistante elle-même et peupler ses attributs identifiants 
+                avant de pouvoir appeler la méthode <literal>load()</literal> pour charger son état persistant associé 
+                à une clef composée. Nous appelons cette approche "identifiant composé <emphasis>embarqué</emphasis>"
+                et ne la recommandons pas pour des applications complexes.
+            </para>
+            
+            <para>
+                Une seconde approche, appelée identifiant composé <emphasis>mappé</emphasis>,
+                consiste à encapsuler les propriétés identifiantes (celles contenues dans <literal>&lt;composite-id&gt;</literal>)
+                dans une classe particulière.
+            </para>
+                
+            <programlisting><![CDATA[<composite-id class="MedicareId" mapped="true">
+        <key-property name="medicareNumber"/>
+        <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+            <para>
+                Dans cet exemple, la classe d'identifiant composée,<literal>MedicareId</literal> et la classe mappée elle-même,
+                possèdent les propriétés <literal>medicareNumber</literal>
+                et <literal>dependent</literal>. La classe identifiante doit redéfinir
+                <literal>equals()</literal> et <literal>hashCode()</literal> et implémenter 
+                <literal>Serializable</literal>. Le désavantage de cette approche est la
+                duplication du code.
+            </para>
+            
+            <para>
+                Les attributs suivants servent à configurer un identifiant composé mappé :
+            </para>
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>mapped</literal> (optionnel, défaut à <literal>false</literal>) :
+                        indique qu'un identifiant composé mappé est utilisé, et que les propriétés
+                        contenues font référence aux deux classes (celle mappée et la classe identifiante).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>class</literal> (optionnel, mais requis pour un identifiant composé mappé) : 
+                        La classe composant utilisée comme identifiant composé.
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <para>
+                Nous décrirons une troisième approche beaucoup plus efficace ou l'identifiant composé
+                est implémenté comme une classe composant dans <xref linkend="components-compositeid"/>. 
+                Les attributs décrits ci dessous, ne s'appliquent que pour cette dernière approche :
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>name</literal> (optionnel, requis pour cette approche) : une propriété de type
+                        composant qui contient l'identifiant composé (voir chapitre 9).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>access</literal> (optionnel - défaut à <literal>property</literal>) :
+                        La stratégie qu'Hibernate utilisera pour accéder à la valeur de la propriété.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>class</literal> (optionnel - défaut au type de la propriété déterminé par réflexion) : 
+                        La classe composant utilisée comme identifiant (voir prochaine section).
+                    </para>
+                </listitem>
+            </itemizedlist>
+            
+            <para>
+                Cette dernière approche est celle que nous recommandons pour toutes vos applications.
+            </para>
+        </sect2>
+        <sect2 id="mapping-declaration-discriminator" revision="3">
+            <title>discriminator</title>
+            <para>
+                   L'élément <literal>&lt;discriminator&gt;</literal> est nécessaire pour la persistance polymorphique 
+                   qui utilise la stratégie de mapping de table par hiérarchie de classe. La colonne discriminante contient 
+                   une valeur marqueur qui permet à la couche de persistance de savoir quelle 
+                   sous-classe instancier pour une ligne particulière de table en base. Un nombre restreint de types 
+                   peuvent être utilisés :
+                <literal>string</literal>, <literal>character</literal>, <literal>integer</literal>, 
+                <literal>byte</literal>, <literal>short</literal>, <literal>boolean</literal>, 
+                <literal>yes_no</literal>, <literal>true_false</literal>.
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="discriminator1" coords="2 60"/>
+                    <area id="discriminator2" coords="3 60"/>
+                    <area id="discriminator3" coords="4 60"/>
+                    <area id="discriminator4" coords="5 60"/>
+                    <area id="discriminator5" coords="6 60"/>
+                </areaspec>
+                <programlisting><![CDATA[<discriminator
+        column="discriminator_column"
+        type="discriminator_type"
+        force="true|false"
+        insert="true|false"
+        formula="arbitrary sql expression"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="discriminator1">
+                        <para>
+                            <literal>column</literal> (optionnel - par défaut à <literal>class</literal>) le 
+                            nom de la colonne discriminante.
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator2">
+                        <para>
+                            <literal>type</literal> (optionnel - par défaut à <literal>string</literal>) un nom 
+                            indiquant le type Hibernate.
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator3">
+                        <para>
+                            <literal>force</literal> (optionnel - par défaut à <literal>false</literal>) 
+                                   "oblige" Hibernate à spécifier une valeur discriminante autorisée même quand on récupère 
+                                   toutes les instances de la classe de base.
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator4">
+                        <para>
+                            <literal>insert</literal> (optionnel - par défaut à <literal>true</literal>)
+                                   à passer à  <literal>false</literal> si la colonne discriminante fait aussi partie 
+                                   d'un identifiant composé mappé (Indique à Hibernate de ne pas inclure la colonne 
+                                   dans les <literal>INSERT</literal> SQL).
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator5">
+                        <para>
+                            <literal>formula</literal> (optionnel) une expression SQL arbitraire qui est exécutée 
+                            quand un type doit être évalué. Permet la discrimination basée sur le contenu.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                   Les véritables valeurs de la colonne discriminante sont spécifiées par l'attribut 
+                <literal>discriminator-value</literal> des éléments <literal>&lt;class&gt;</literal> et 
+                <literal>&lt;subclass&gt;</literal>.
+            </para>
+            <para>
+                L'attribut <literal>force</literal> n'est utile que si la table contient des lignes avec des 
+                valeurs "extra" discriminantes qui ne sont pas mappées à une classe persistante. Ce ne sera généralement pas le cas.
+            </para>
+            <para>
+                En utilisant l'attribut <literal>formula</literal> vous pouvez déclarer une expression SQL arbitraire 
+                qui sera utilisée pour évaluer le type d'une ligne :
+            </para>
+            <programlisting><![CDATA[<discriminator
+    formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
+    type="integer"/>]]></programlisting>
+        </sect2>
+        <sect2 id="mapping-declaration-version" revision="4">
+            <title>version (optionnel)</title>
+            <para>
+                   L'élément <literal>&lt;version&gt;</literal> est optionnel et indique que la table contient 
+                   des données versionnées. C'est particulièrement utile si vous avez l'intention d'utiliser 
+                   des <emphasis>transactions longues</emphasis> (voir plus-bas).   
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="version1" coords="2 60"/>
+                    <area id="version2" coords="3 60"/>
+                    <area id="version3" coords="4 60"/>
+                    <area id="version4" coords="5 60"/>
+                    <area id="version5" coords="6 60"/>
+                    <area id="version6" coords="7 70"/>
+                    <area id="version7" coords="8 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<version
+        column="version_column"
+        name="propertyName"
+        type="typename"
+        access="field|property|ClassName"
+        unsaved-value="null|negative|undefined"
+        generated="never|always"
+        insert="true|false"
+        node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="version1">
+                        <para>
+                            <literal>column</literal> (optionnel - par défaut égal au nom de la propriété) : Le nom de la colonne 
+                            contenant le numéro de version.
+                        </para>
+                    </callout>
+                    <callout arearefs="version2">
+                        <para>
+                            <literal>name</literal> : Le nom d'un attribut de la classe persistante.
+                        </para>
+                    </callout>
+                    <callout arearefs="version3">
+                        <para>
+                            <literal>type</literal> (optionnel - par défaut à <literal>integer</literal>) : 
+                            Le type du numéro de version.
+                        </para>
+                    </callout>
+                    <callout arearefs="version4">
+                        <para>
+                            <literal>access</literal> (optionnel - par défaut à <literal>property</literal>) : La stratégie 
+                            à utiliser par Hibernate pour accéder à la valeur de la propriété.
+                        </para>
+                    </callout>
+                    <callout arearefs="version5">
+                        <para>
+                            <literal>unsaved-value</literal> (optionnel - par défaut à <literal>undefined</literal>) : 
+                            Une valeur de la propriété d'identifiant qui indique que l'instance est nouvellement 
+                            instanciée (non sauvegardée), et qui la distingue des instances détachées qui ont 
+                            été sauvegardées ou chargées dans une session précédente (<literal>undefined</literal> indique 
+                            que la valeur de l'atribut identifiant devrait être utilisé).
+                        </para>
+                    </callout>
+                    <callout arearefs="version6">
+                        <para>
+                            <literal>generated</literal> (optional - défaut à <literal>never</literal>) :
+                            Indique que la valeur de la propriété version est générée par la base de données
+                            cf. <xref linkend="mapping-generated">generated properties</xref>.
+                        </para>
+                    </callout>
+                    <callout arearefs="version7">
+                        <para>
+                            <literal>insert</literal> (optionnel - défaut à <literal>true</literal>) :
+                            Indique si la colonne de version doit être incluse dans les ordres insert.
+                            Peut être à <literal>false</literal> si et seulement si la colonne de la
+                            base de données est définie avec une valeur par défaut à <literal>0</literal>.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                Les numéros de version doivent avoir les types Hibernate <literal>long</literal>, <literal>integer</literal>,
+                <literal>short</literal>, <literal>timestamp</literal> ou <literal>calendar</literal>.
+            </para>
+            <para>
+                   Une propriété de version ou un timestamp ne doit jamais être null pour une instance 
+                   détachée, ainsi Hibernate pourra détecter toute instance ayant une version ou un timestamp null 
+                   comme transient, quelles que soient les stratégies <literal>unsaved-value</literal> spécifiées.
+                   <emphasis>Déclarer un numéro de version ou un timestamp "nullable" est un moyen pratique d'éviter 
+                   tout problème avec les réattachements transitifs dans Hibernate, particulièrement utile pour ceux qui 
+                   utilisent des identifiants assignés ou des clefs composées !</emphasis>
+            </para>
+        </sect2>
+        <sect2 id="mapping-declaration-timestamp"  revision="3" >
+            <title>timestamp (optionnel)</title>
+            <para>
+                   L'élément optionnel <literal>&lt;timestamp&gt;</literal> indique que la table contient des données 
+                   horodatées (timestamp). Cela sert d'alternative à l'utilisation de numéros de version. Les timestamps (ou horodatage) 
+                   sont par nature une implémentation moins fiable pour l'optimistic locking. Cependant, l'application 
+                   peut parfois utiliser l'horodatage à d'autres fins.
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="timestamp1" coords="2 45"/>
+                    <area id="timestamp2" coords="3 45"/>
+                    <area id="timestamp3" coords="4 45"/>
+                    <area id="timestamp4" coords="5 45"/>
+                    <area id="timestamp5" coords="6 70" />
+                    <area id="timestamp6" coords="7 70" />
+                </areaspec>
+                <programlisting><![CDATA[<timestamp
+        column="timestamp_column"
+        name="propertyName"
+        access="field|property|ClassName"
+        unsaved-value="null|undefined"
+        source="vm|db"
+        generated="never|always"
+        node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="timestamp1">
+                        <para>
+                            <literal>column</literal> (optionnel - par défaut à le nom de la propriété) : Le nom d'une colonne 
+                            contenant le timestamp.
+                        </para>
+                    </callout>
+                    <callout arearefs="timestamp2">
+                        <para>
+                            <literal>name</literal> : Le nom d'une propriété au sens JavaBean de type 
+                            <literal>Date</literal> ou <literal>Timestamp</literal> de la classe persistante.
+                        </para>
+                    </callout>
+                    <callout arearefs="timestamp3">
+                        <para>
+                            <literal>access</literal> (optionnel - par défaut à <literal>property</literal>) : La stratégie 
+                            à utiliser par Hibernate pour accéder à la valeur de la propriété.
+                        </para>
+                    </callout>
+                    <callout arearefs="timestamp4">
+                        <para>
+                            <literal>unsaved-value</literal> (optionnel - par défaut à <literal>null</literal>) : 
+                              Propriété dont la valeur est un numéro de version qui indique que l'instance est nouvellement 
+                              instanciée (non sauvegardée), et qui la distingue des instances détachées qui ont 
+                              été sauvegardées ou chargées dans une session précédente (<literal>undefined</literal> indique 
+                              que la valeur de l'attribut identifiant devrait être utilisée).
+                        </para>
+                    </callout>
+                    <callout arearefs="timestamp5">
+                        <para>
+                            <literal>source</literal> (optionnel - par défaut à <literal>vm</literal>) :
+                            D'où Hibernate doit-il récupérer la valeur du timestamp? Depuis la base de données
+                            ou depuis la JVM d'exécution? Les valeurs de timestamp de la base de données provoquent
+                            une surcharge puisque Hibernate doit interroger la base pour déterminer la prochaine valeur
+                            mais cela est plus sûr lorsque vous fonctionnez dans un cluster. Remarquez aussi que
+                            certains des dialectes ne supportent pas cette fonction, et que d'autres l'implémentent
+                            mal, provoquant des erreurs de précision (Oracle 8 par exemple).
+                        </para>
+                    </callout>
+                    <callout arearefs="timestamp6">
+                        <para>
+                            <literal>generated</literal> (optional - défaut à <literal>never</literal>) :
+                            Indique que la valeur de ce timestamp est générée par la base de données
+                            cf. <xref linkend="mapping-generated">generated properties</xref>.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                Notez que <literal>&lt;timestamp&gt;</literal> est équivalent à 
+                <literal>&lt;version type="timestamp"&gt;</literal>.
+            </para>
+        </sect2>
+        <sect2 id="mapping-declaration-property" revision="4">
+            <title>property</title>
+            <para>
+                L'élément <literal>&lt;property&gt;</literal> déclare une propriété de la classe au sens JavaBean.
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="property1" coords="2 45"/>
+                    <area id="property2" coords="3 45"/>
+                    <area id="property3" coords="4 45"/>
+                    <areaset id="property4-5" coords="">
+                        <area id="property4" coords="5 45"/>
+                        <area id="property5" coords="6 45"/>
+                    </areaset>
+                    <area id="property6" coords="7 45"/>
+                    <area id="property7" coords="8 45"/>
+                    <area id="property8" coords="9 45"/>
+                    <area id="property9" coords="10 45"/>
+                    <area id="property10" coords="11 45"/>
+                    <area id="property11" coords="12 45"/>
+                    <area id="property12" coords="13 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<property
+        name="propertyName"
+        column="column_name"
+        type="typename"
+        update="true|false"
+        insert="true|false"
+        formula="arbitrary SQL expression"
+        access="field|property|ClassName"
+        lazy="true|false"
+        unique="true|false"
+        not-null="true|false"
+        optimistic-lock="true|false"
+        generated="never|insert|always"
+        node="element-name|@attribute-name|element/@attribute|."
+        index="index_name"
+        unique_key="unique_key_id"
+        length="L"
+        precision="P"
+        scale="S"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="property1">
+                        <para>
+                            <literal>name</literal> : nom de la propriété, avec une lettre initiale en minuscule.
+                        </para>
+                    </callout>
+                    <callout arearefs="property2">
+                        <para>
+                            <literal>column</literal> (optionnel - par défaut au nom de la propriété) : le nom 
+                                   de la colonne mappée. Cela peut aussi être indiqué dans le(s) sous-élément(s) 
+                            <literal>&lt;column&gt;</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="property3">
+                        <para>
+                            <literal>type</literal> (optionnel) : nom indiquant le type Hibernate.
+                        </para>
+                    </callout>
+                    <callout arearefs="property4-5">
+                        <para>
+                            <literal>update, insert</literal> (optionnel - par défaut à <literal>true</literal>) :
+                           indique que les colonnes mappées devraient être incluses dans des <literal>UPDATE</literal> SQL 
+                           et/ou des <literal>INSERT</literal>. Mettre les deux à <literal>false</literal> 
+                           empêche la propagation en base de données (utile si vous savez qu'un trigger affectera la valeur à la  colonne). 
+                        </para>
+                    </callout>
+                    <callout arearefs="property6">
+                        <para>
+                            <literal>formula</literal> (optionnel) : une expression SQL qui définit la valeur pour une propriété 
+                            <emphasis>calculée</emphasis>. Les propriétés calculées ne possède pas leur propre mapping.
+                        </para>
+                    </callout>
+                    <callout arearefs="property7">
+                        <para>
+                            <literal>access</literal> (optionnel - par défaut à <literal>property</literal>): Stratégie que Hibernate
+                             doit utiliser pour accéder à cette valeur.
+                        </para>
+                    </callout>
+                    <callout arearefs="property8">
+                        <para>
+                            <literal>lazy</literal> (optionnel - par défaut à <literal>false</literal>): Indique 
+                            que cette propriété devrait être chargée en différé (lazy loading) quand on accède à la variable 
+                            d'instance pour la première fois.
+                        </para>
+                    </callout>
+                    <callout arearefs="property9">
+                        <para>
+                            <literal>unique</literal> (optionnel): Génère le DDL d'une contrainte d'unicité pour les colonnes. 
+                            Permet aussi d'en faire la cible d'un <literal>property-ref</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="property10">
+                        <para>
+                            <literal>not-null</literal> (optionnel): Génère le DDL d'une contrainte de non nullité pour les colonnes.
+                        </para>
+                    </callout>
+                    <callout arearefs="property11">
+                        <para>
+                            <literal>optimistic-lock</literal> (optionnel - par défaut à <literal>true</literal>): 
+                            Indique que les mises à jour de cette propriété peuvent ou non nécessiter l'acquisition 
+                            d'un verrou optimiste. En d'autres termes, cela détermine s'il est nécessaire d'incrémenter 
+                            un numéro de version quand cette propriété est marquée obsolète (dirty).
+                        </para>                 
+                    </callout>
+                    <callout arearefs="property12">
+                        <para>
+                            <literal>generated</literal> (optional - défaut à<literal>never</literal>):
+                            Indique que la valeur de ce timestamp est générée par la base de données
+                            cf. <xref linkend="mapping-generated">generated properties</xref>.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                <emphasis>typename</emphasis> peut être:
+            </para>
+            <orderedlist spacing="compact">
+                <listitem>
+                    <para>
+                        Nom d'un type basique Hibernate (ex: <literal>integer, string, character,
+                        date, timestamp, float, binary, serializable, object, blob</literal>).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Nom d'une classe Java avec un type basique par défaut (ex: <literal>int, float,
+                        char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob</literal>).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Nom d'une classe Java sérialisable.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                       Nom d'une classe ayant un type spécifique (ex: <literal>com.illflow.type.MyCustomType</literal>).
+                    </para>
+                </listitem>
+            </orderedlist>
+            <para>
+                   Si vous n'indiquez pas un type, Hibernate utlisera la réflexion sur le nom de la propriété 
+                   pour tenter de trouver le type Hibernate correct. Hibernate essayera d'interprêter 
+                   le nom de la classe retournée par le getter de la propriété en utilisant les régles 2, 3, 
+                   4 dans cet ordre. Cependant, ce n'est pas toujours suffisant. Dans certains cas vous aurez 
+                   encore besoin de l'attribut <literal>type</literal> (Par exemple, pour distinguer 
+                   <literal>Hibernate.DATE</literal> et <literal>Hibernate.TIMESTAMP</literal>, ou pour préciser 
+                   un type spécifique).
+            </para>
+            <para>
+                   L'attribut <literal>access</literal> permet de contrôler comment Hibernate accèdera 
+                   à la propriété à l'exécution. Par défaut, Hibernate utilisera les méthodes set/get. 
+                   Si vous indiquez <literal>access="field"</literal>, Hibernate ignorera les getter/setter 
+                   et accèdera à la propriété directement en utilisant la réflexion. Vous pouvez spécifier 
+                   votre propre stratégie d'accès aux propriété en donnant une classe qui implémente l'interface 
+                <literal>org.hibernate.property.PropertyAccessor</literal>.
+            </para>
+            <para>
+                   Une fonctionnalité particulièrement intéressante est les propriétés dérivées.
+                   Ces propriétés sont par définition en lecture seule, la valeur de la propriété est calculée au chargement. 
+                   Le calcul est déclaré comme une expression SQL, qui se traduit par une sous-requête <literal>SELECT</literal> 
+                   dans la requête SQL qui charge une instance :
+            </para>
+            <programlisting><![CDATA[
+<property name="totalPrice"
+    formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p
+                WHERE li.productId = p.productId
+                AND li.customerId = customerId
+                AND li.orderNumber = orderNumber )"/>]]></programlisting>
+            <para>
+                   Remarquez que vous pouvez référencer la propre table des entités en ne déclarant pas un 
+                   alias sur une colonne particulière (<literal>customerId</literal> dans l'exemple donné). 
+                   Notez aussi que vous pouvez utiliser le sous-élément de mapping <literal>&lt;formula&gt;</literal> 
+                   plutôt que d'utiliser l'attribut si vous le souhaitez.
+            </para>
+        </sect2>
+        <sect2 id="mapping-declaration-manytoone" revision="5">
+            <title>many-to-one</title>
+            <para> Une association ordinaire vers une autre classe persistante est déclarée en utilisant 
+                   un élément <literal>many-to-one</literal>. Le modèle relationnel est une association 
+                   de type many-to-one : une clef étrangère dans une table référence la ou les clef(s) primaire(s) dans la table cible.
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="manytoone1" coords="2 60"/>
+                    <area id="manytoone2" coords="3 60"/>
+                    <area id="manytoone3" coords="4 60"/>
+                    <area id="manytoone4" coords="5 60"/>
+                    <area id="manytoone5" coords="6 60"/>
+                    <areaset id="manytoone6-7" coords="">
+                        <area id="manytoone6" coords="7 60"/>
+                        <area id="manytoone7" coords="8 60"/>
+                    </areaset>
+                    <area id="manytoone8" coords="9 60"/>
+                    <area id="manytoone9" coords="10 60"/>
+                    <area id="manytoone10" coords="11 60"/>
+                    <area id="manytoone11" coords="12 60"/>
+                    <area id="manytoone12" coords="13 60"/>
+                    <area id="manytoone13" coords="14 60"/>
+                    <area id="manytoone14" coords="15 60"/>
+                    <area id="manytoone14" coords="15 70"/>
+                    <area id="manytoone15" coords="16 70"/>
+                    <area id="manytoone16" coords="17 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<many-to-one
+        name="propertyName"
+        column="column_name"
+        class="ClassName"
+        cascade="cascade_style"
+        fetch="join|select"
+        update="true|false"
+        insert="true|false"
+        property-ref="propertyNameFromAssociatedClass"
+        access="field|property|ClassName"
+        unique="true|false"
+        not-null="true|false"
+        optimistic-lock="true|false"
+        lazy="proxy|no-proxy|false"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        formula="arbitrary SQL expression"
+        node="element-name|@attribute-name|element/@attribute|."
+        embed-xml="true|false"
+        index="index_name"
+        unique_key="unique_key_id"
+        foreign-key="foreign_key_name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="manytoone1">
+                        <para>
+                            <literal>name</literal> : Nom de la propriété.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone2">
+                        <para>
+                            <literal>column</literal> (optionnel) : Le nom de la clef étrangère. Cela peut être 
+                            aussi indiqué avec le sous-élément <literal>&lt;column&gt;</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone3">
+                        <para>
+                            <literal>class</literal> (optionnel - par défaut le type de la propriété déterminé 
+                            par réflexion) : Le nom de la classe associée.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone4">
+                        <para>
+                            <literal>cascade</literal> (optionnel) : Indique quelles opérations doivent 
+                            être propagées de l'objet père vers les objets associés.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone5">
+                        <para>
+                            <literal>fetch</literal> (optionnel - par défaut à <literal>select</literal>) : 
+                            Choisit entre le chargement de type outer-join ou le chargement par select successifs.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone6-7">
+                        <para>
+                            <literal>update, insert</literal> (optionnel - par défaut à <literal>true</literal>) :
+                           indique que les colonnes mappées devraient être incluses dans des <literal>UPDATE</literal> SQL 
+                           et/ou des <literal>INSERT</literal>. Mettre les deux à <literal>false</literal> 
+                           empêche la propagation en base de données (utile si vous savez qu'un trigger affectera la valeur à la  colonne).                         
+                         </para>
+                    </callout>
+                    <callout arearefs="manytoone8">
+                        <para>
+                            <literal>property-ref</literal> : (optionnel) Le nom d'une propriété de la classe 
+                            associée qui est liée à cette clef étrangère. Si ce n'est pas spécifié, la clef primaire de la 
+                            classe associée est utilisée.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone9">
+                        <para>
+                            <literal>access</literal> (optionnel - par défaut à <literal>property</literal>) : La 
+                            stratégie à utiliser par Hibernate pour accéder à la valeur de cette propriété.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone10">
+                        <para>
+                            <literal>unique</literal> (optionnel) : Génère le DDL d'une contrainte d'unicité pour la clef étrangère. 
+                            Permet aussi d'en faire la cible d'un <literal>property-ref</literal>. Cela permet de créer une véritable 
+                            association one-to-one.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone11">
+                        <para>
+                            <literal>not-null</literal> (optionnel) : Génère le DDL pour une contrainte de non nullité pour la clef étrangère.
+                       </para>
+                    </callout>
+                    <callout arearefs="manytoone12">
+                        <para>
+                            <literal>optimistic-lock</literal> (optionnel - par défaut à <literal>true</literal>) : 
+                            Indique que les mises à jour de cette propriété requièrent ou non l'acquisition 
+                            d'un verrou optimiste. En d'autres termes, détermine si un incrément de version doit 
+                            avoir lieu quand la propriété est marquée obsolète (dirty).
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone13">
+                        <para>
+                            <literal>lazy</literal> (optionnel - par défaut à <literal>false</literal>) : Indique 
+                            que cette propriété doit être chargée en différé (lazy loading) au premier accès 
+                            à la variable d'instance (nécessite une instrumentation du bytecode lors de la phase 
+                            de construction). Remarquez que cela n'influence pas le comportement du proxy 
+                            Hibernate - comme l'attribut <literal>lazy</literal> sur des classes ou des mappings 
+                            de collections, mais utilise l'interception pour le chargement différé.
+                            <literal>lazy="false"</literal> indique que l'association sera toujours chargée.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone14">
+                        <para>
+                            <literal>not-found</literal> (optionnel - par défaut à <literal>exception</literal>) : 
+                            Indique comment les clefs étrangères qui référencent des lignes manquantes doivent être manipulées :
+                            <literal>ignore</literal> traitera une ligne manquante comme une association nulle.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone15">
+                        <para>
+                            <literal>entity-name</literal> (optionnel) : Le nom de l'entité de la classe associée.
+                        </para>                   
+                    </callout>
+                    <callout arearefs="manytoone16">
+                        <para>
+                            <literal>formula</literal> (optionnel) : une expression SQL qui définit la valeur
+                            pour une clé étrangère calculée.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                Donner une valeur significative à l'attribut <literal>cascade</literal> autre que 
+                <literal>none</literal>  propagera certaines opérations à l'objet associé. Les valeurs 
+                significatives sont les noms des opérations Hibernate basiques,     
+                <literal>persist, merge, delete, save-update, evict, replicate, lock,
+                refresh</literal>, ainsi que les valeurs spéciales <literal>delete-orphan</literal> 
+                et <literal>all</literal> et des combinaisons de noms d'opérations séparées par des virgules,
+                comme par exemple <literal>cascade="persist,merge,evict"</literal> ou
+                <literal>cascade="all,delete-orphan"</literal>. Voir <xref linkend="objectstate-transitive"/>
+                pour une explication complète.
+                Notez que les assocations many-to-one et one-to-one ne supportent pas orphan delete.
+            </para>
+
+            <para>
+                Une déclaration <literal>many-to-one</literal> typique est aussi simple que :
+            </para>
+            <programlisting><![CDATA[<many-to-one name="product" class="Product" column="PRODUCT_ID"/>]]></programlisting>
+            <para>
+                L'attribut <literal>property-ref</literal> devrait être utilisé pour mapper seulement des données 
+                provenant d'un ancien système où les clefs étrangères font référence à une clef unique de la table associée 
+                et qui n'est pas la clef primaire. C'est un cas de mauvaise conception relationnelle.
+                Par exemple, supposez que la classe <literal>Product</literal> a un numéro de série unique qui n'est pas
+                la clef primaire. (L'attribut <literal>unique</literal> contrôle la génération DDL par Hibernate avec 
+                l'outil SchemaExport.)
+            </para>
+            <programlisting><![CDATA[<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>]]></programlisting>
+            <para>
+                Ainsi le mapping pour <literal>OrderItem</literal> peut utiliser :
+            </para>
+            <programlisting><![CDATA[<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>]]></programlisting>
+            <para>
+                bien que ce ne soit certainement pas encouragé.
+            </para>
+            <para>
+                Si la clef unique référencée comprend des propriétés multiples de l'entité associée, vous devez mapper
+                ces propriétés à l'intérieur d'un élément <literal>&lt;properties&gt;</literal>.
+            </para>
+        </sect2>
+        <sect2 id="mapping-declaration-onetoone" revision="3">
+            <title>one-to-one</title>
+            <para>
+                Une association one-to-one vers une autre classe persistante est déclarée avec l'élément
+                <literal>one-to-one</literal>.
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="onetoone1" coords="2 60"/>
+                    <area id="onetoone2" coords="3 60"/>
+                    <area id="onetoone3" coords="4 60"/>
+                    <area id="onetoone4" coords="5 60"/>
+                    <area id="onetoone5" coords="6 60"/>
+                    <area id="onetoone6" coords="7 60"/>
+                    <area id="onetoone7" coords="8 60"/>
+                    <area id="onetoone8" coords="9 60"/>
+                    <area id="onetoone9" coords="10 70"/>
+                    <area id="onetoone10" coords="11 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<one-to-one
+        name="propertyName"
+        class="ClassName"
+        cascade="cascade_style"
+        constrained="true|false"
+        fetch="join|select"
+        property-ref="propertyNameFromAssociatedClass"
+        access="field|property|ClassName"
+        formula="any SQL expression"
+        entity-name="EntityName"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="onetoone1">
+                        <para>
+                            <literal>name</literal> : Le nom de la propriété.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone2">
+                        <para>
+                            <literal>class</literal> (optionnel - par défaut du type de la propriété 
+                            déterminé par réflexion) : Le nom de la classe associée.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone3">
+                        <para>
+                            <literal>cascade</literal> (optionnel) :  Indique quelles opérations doivent 
+                            être cascadées de l'objet père vers l'objet associé.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone4">
+                        <para>
+                            <literal>constrained</literal> (optionnel) : Indique qu'une contrainte de clef étrangère 
+                            sur la clef primaire de la table mappée référence la table de la classe associée.
+                            Cette option affecte l'ordre dans lequel chaque <literal>save()</literal> et chaque
+                            <literal>delete()</literal> sont cascadés et détermine si l'association peut utiliser un proxy 
+                            (aussi utilisé par l'outil d'export de schéma).
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone5">
+                        <para>
+                            <literal>fetch</literal> (optionnel - par défaut à <literal>select</literal>) : 
+                            Choisit entre récupération par jointure externe ou select séquentiel.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone6">
+                        <para>
+                            <literal>property-ref</literal> (optionnel) : Le nom de la propriété de la classe associée qui est jointe à la clef
+                            primaire de cette classe. Si ce n'est pas spécifié, la clef primaire de la classe associée est utilisée.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone7">
+                        <para>
+                            <literal>access</literal> (optionnel - par défaut à <literal>property</literal>) : 
+                            La stratégie à utiliser par Hibernate pour accéder à la valeur de la propriété.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone8">
+                        <para>
+                            <literal>formula</literal> (optionnel) : Presque toutes les associations one-to-one pointent sur la clef primaire 
+                            de l'entité propriétaire. Dans les rares cas différents, vous devez donner une ou plusieurs 
+                            autres colonnes ou expression à joindre par une formule SQL (voir <literal>org.hibernate.test.onetooneformula</literal> pour un exemple).
+                        </para>                 
+                    </callout>
+                    <callout arearefs="onetoone9">
+                        <para>
+                            <literal>lazy</literal> (optionnel - par défaut <literal>proxy</literal>) : 
+                            Par défaut, les associations simples sont soumise à proxy. <literal>lazy="no-proxy"</literal>
+                            spécifie que la propriété doit être chargée à la demande au premier accès à l'instance.
+                            (nécessite l'intrumentation du bytecode à la construction). 
+                            <literal>lazy="false"</literal> indique que l'association sera toujours chargée
+                            agressivement. <emphasis>Notez que si <literal>constrained="false"</literal>,
+                            l'utilisation de proxy est impossible et Hibernate chargera automatiquement l'association !</emphasis>
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone10">
+                        <para>
+                            <literal>entity-name</literal> (optional) : The entity name of the associated class.
+                        </para>                   
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                Il existe deux types d'associations one-to-one :
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                associations par clef primaire
+            </para>
+                </listitem>
+                <listitem>
+                    <para>
+                association par clef étrangère unique
+            </para>
+                </listitem>
+            </itemizedlist>
+            <para>
+                Les associations par clef primaire ne nécessitent pas une colonne supplémentaire en table ; si deux lignes sont 
+                liés par l'association alors les deux lignes de la table partagent la même valeur de clef primaire. Donc si vous 
+                voulez que deux objets soient liés par une association par clef primaire, vous devez faire en sorte qu'on leur 
+                assigne la même valeur d'identifiant !
+            </para>
+            <para>
+                Pour une association par clef primaire, ajoutez les mappings suivants à <literal>Employee</literal> et 
+                <literal>Person</literal>, respectivement.
+            </para>
+            <programlisting><![CDATA[<one-to-one name="person" class="Person"/>]]></programlisting>
+            <programlisting><![CDATA[<one-to-one name="employee" class="Employee" constrained="true"/>]]></programlisting>
+            <para>
+                Maintenant, vous devez faire en sorte que les clefs primaires des lignes liées dans les tables PERSON et EMPLOYEE 
+                sont égales. On utilise une stratégie Hibernate spéciale de génération d'identifiants appelée 
+                <literal>foreign</literal> :
+            </para>
+            <programlisting><![CDATA[<class name="person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="foreign">
+            <param name="property">employee</param>
+        </generator>
+    </id>
+    ...
+    <one-to-one name="employee"
+        class="Employee"
+        constrained="true"/>
+</class>]]></programlisting>
+            <para>
+                Une instance fraîchement enregistrée de <literal>Person</literal> se voit alors assignée la même valeur 
+                de clef primaire que l'instance de <literal>Employee</literal> référencée par la propriété <literal>employee</literal> 
+                de cette <literal>Person</literal>.
+            </para>
+            <para>
+                Alternativement, une clef étrangère avec contrainte d'unicité de <literal>Employee</literal> vers 
+                <literal>Person</literal> peut être indiquée ainsi :
+            </para>
+            <programlisting><![CDATA[<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/>]]></programlisting>
+            <para>
+                Et cette association peut être rendue bidirectionnelle en ajoutant ceci au mapping de <literal>Person</literal> :
+            </para>
+            <programlisting><![CDATA[<one-to-one name"employee" class="Employee" property-ref="person"/>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="mapping-declaration-naturalid">
+            <title>natural-id</title>
+
+            <programlisting><![CDATA[<natural-id mutable="true|false"/>
+        <property ... />
+        <many-to-one ... />
+        ......
+</natural-id>]]></programlisting>
+
+            <para>
+                Bien que nous recommandions l'utilisation de clé primaire générée, vous devriez toujours
+                essayer d'identifier des clé métier (naturelles) pour toutes vos entités. Une clé naturelle
+                est une propriété ou une combinaison de propriétés uniques et non nulles. Si elle est aussi
+                immuable, c'est encore mieux. Mappez les propriétés de la clé naturelle dans l'élément
+                <literal>&lt;natural-id&gt;</literal>. Hibernate générera la clé unique nécessaire et les contraintes
+                de non-nullité, et votre mapping s'auto-documentera.
+            </para>
+            
+            <para>
+                Nous vous recommandons fortement d'implémenter <literal>equals()</literal> et 
+                <literal>hashCode()</literal> pour comparer les clés naturelles de l'entité.
+            </para>
+
+            <para>
+                Ce mapping n'est pas destiné à être utilisé avec des entités qui ont des clés naturelles.
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>mutable</literal> (optionel, par défaut à <literal>false</literal>) : 
+                        Par défaut, les identifiants naturels sont supposés être immuable (constants).
+                    </para>
+                </listitem>
+            </itemizedlist>
+            
+        </sect2>
+        <sect2 id="mapping-declaration-component" revision="2">
+            <title>component, dynamic-component</title>
+            <para>
+                L'élément <literal>&lt;component&gt;</literal> mappe les propriétés d'un objet fils 
+                aux colonnes d'une classe parente. Les composants peuvent en retour déclarer leurs propres 
+                propriétés, composants ou collections. Voir "Components" plus bas.
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="component1" coords="2 45"/>
+                    <area id="component2" coords="3 45"/>
+                    <area id="component3" coords="4 45"/>
+                    <area id="component4" coords="5 45"/>
+                    <area id="component5" coords="6 45"/>
+                    <area id="component6" coords="7 45"/>
+                    <area id="component7" coords="8 45"/>
+                    <area id="component8" coords="9 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<component 
+        name="propertyName" 
+        class="className"
+        insert="true|false"
+        update="true|false"
+        access="field|property|ClassName"
+        lazy="true|false"
+        optimistic-lock="true|false"
+        unique="true|false"
+>
+        
+        <property ...../>
+        <many-to-one .... />
+        ........
+</component>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="component1">
+                        <para>
+                            <literal>name</literal> : Nom de la propriété
+                        </para>
+                    </callout>
+                    <callout arearefs="component2">
+                        <para>
+                            <literal>class</literal> (optionnel - par défaut au type de la propriété déterminé par réflexion) : 
+                            le nom de la classe (fille) du composant.
+                        </para>
+                    </callout>
+                    <callout arearefs="component3">
+                        <para>
+                            <literal>insert</literal> : Est ce que les colonnes mappées apparaissent dans les 
+                            <literal>INSERT</literal>s ?
+                        </para>
+                    </callout>
+                    <callout arearefs="component4">
+                        <para>
+                            <literal>update</literal>: Est ce que les colonnes mappées apparaissent dans les 
+                            <literal>UPDATE</literal>s ?
+                        </para>
+                    </callout>
+                    <callout arearefs="component5">
+                        <para>
+                            <literal>access</literal> (optionnel - par défaut à <literal>property</literal>) : 
+                            La stratégie que Hibernate doit utiliser pour accéder à la valeur de cette propriété.
+                        </para>
+                    </callout>
+                    <callout arearefs="component6">
+                        <para>
+                            <literal>lazy</literal> (optionnel - par défaut à <literal>false</literal>) : 
+                            Indique que ce composant doit être chargé au premier accès 
+                            à la variable d'instance (nécessite une instrumentation du bytecode au moment du build).
+                        </para>
+                    </callout>
+                    <callout arearefs="component7">
+                        <para>
+                            <literal>optimistic-lock</literal> (optionnel - par défaut à <literal>true</literal>) :
+                                Indique que les mises à jour sur ce composant nécessitent ou non l'acquisition d'un 
+                                verrou optimiste. En d'autres termes, cela détermine si une incrémentation de version 
+                                doit avoir lieu quand la propriété est marquée obsolète (dirty).
+                            </para>
+                    </callout>
+                    <callout arearefs="component8">
+                        <para>
+                            <literal>unique</literal> (optionnel - par défaut à <literal>false</literal>) :
+                                Indique qu'une contrainte d'unicité existe sur toutes les colonnes mappées de ce composant.
+                            </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                Les tags fils <literal>&lt;property&gt;</literal> mappent les propriétés 
+                de la classe fille sur les colonnes de la table.
+            </para>
+            <para>
+                L'élément <literal>&lt;component&gt;</literal> permet de déclarer sous-élément <literal>&lt;parent&gt;</literal> qui associe une propriété
+                de la classe composant comme une référence arrière vers l'entité contenante.
+            </para>
+            <para>
+                L'élément <literal>&lt;dynamic-component&gt;</literal> permet à une <literal>Map</literal> d'être mappée 
+                comme un composant, quand les noms de la propriété font référence aux clefs de cette Map, voir 
+                <xref linkend="components-dynamic"/>.
+            </para>
+        </sect2>
+        <sect2 id="mapping-declaration-properties" revision="2">
+            <title>properties</title>
+            <para>
+                L'élément <literal>&lt;properties&gt;</literal> permet la définition d'un groupement logique nommé 
+                des propriétés d'une classe. L'utilisation la plus importante de cette construction est la possibilité 
+                pour une combinaison de propriétés d'être la cible d'un <literal>property-ref</literal>. C'est aussi 
+                un moyen pratique de définir une contrainte d'unicité multi-colonnes.
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="properties1" coords="2 45"/>
+                    <area id="properties2" coords="3 45"/>
+                    <area id="properties3" coords="4 45"/>
+                    <area id="properties4" coords="5 45"/>
+                    <area id="properties5" coords="6 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<properties 
+        name="logicalName" 
+        insert="true|false"
+        update="true|false"
+        optimistic-lock="true|false"
+        unique="true|false"
+>
+        
+        <property ...../>
+        <many-to-one .... />
+        ........
+</properties>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="properties1">
+                        <para>
+                            <literal>name</literal> : Le nom logique d'un regroupement et 
+                            <emphasis>non</emphasis> le véritable nom d'une propriété.
+                        </para>
+                    </callout>
+                    <callout arearefs="properties2">
+                        <para>
+                            <literal>insert</literal> : Est-ce que les colonnes mappées apparaissent dans les 
+                            <literal>INSERT</literal>s ?
+                        </para>
+                    </callout>
+                    <callout arearefs="properties3">
+                        <para>
+                            <literal>update</literal> : Est-ce que les colonnes mappées apparaissent dans les 
+                            <literal>UPDATE</literal>s ?
+                        </para>
+                    </callout>
+                    <callout arearefs="properties4">
+                        <para>
+                            <literal>optimistic-lock</literal> (optionnel - par défaut à <literal>true</literal>) :
+                                Indique que les mises à jour sur ce composant nécessitent ou non l'acquisition d'un 
+                                verrou optimiste. En d'autres termes, cela détermine si une incrémentation 
+                                de version doit avoir lieu quand la propriété est marquée obsolète (dirty).
+                            </para>
+                    </callout>
+                    <callout arearefs="properties5">
+                        <para>
+                            <literal>unique</literal> (optionnel - par défaut à <literal>false</literal>) :
+                            Indique qu'une contrainte d'unicité existe sur toutes les colonnes mappées de ce composant.
+                            </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                Par exemple, si nous avons le mapping de <literal>&lt;properties&gt;</literal> suivant :
+            </para>
+            <programlisting><![CDATA[<class name="Person">
+    <id name="personNumber"/>
+    ...
+    <properties name="name" 
+            unique="true" update="false">
+        <property name="firstName"/>
+        <property name="initial"/>
+        <property name="lastName"/>
+    </properties>
+</class>]]></programlisting>
+            <para>
+                Alors nous pourrions avoir une association sur des données d'un ancien système (legacy) qui font référence 
+                à cette clef unique de la table <literal>Person</literal> au lieu de la clef primaire :
+            </para>
+            <programlisting><![CDATA[<many-to-one name="person" 
+         class="Person" property-ref="name">
+    <column name="firstName"/>
+    <column name="initial"/>
+    <column name="lastName"/>
+</many-to-one>]]></programlisting>
+            <para>
+                Nous ne recommandons pas l'utilisation de ce genre de chose en dehors du contexte de mapping de données héritées 
+                d'anciens systèmes.
+            </para>
+        </sect2>
+        <sect2 id="mapping-declaration-subclass" revision="4">
+            <title>subclass</title>
+            <para>
+                Pour finir, la persistance polymorphique nécessite la déclaration de chaque sous-classe de la classe persistante de base. 
+                pour la stratégie de mapping de type table-per-class-hierarchy, on utilise la déclaration 
+                <literal>&lt;subclass&gt;</literal>.    
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="subclass1" coords="2 55"/>
+                    <area id="subclass2" coords="3 55"/>
+                    <area id="subclass3" coords="4 55"/>
+                    <area id="subclass4" coords="5 55"/>
+                </areaspec>
+                <programlisting><![CDATA[<subclass
+        name="ClassName"
+        discriminator-value="discriminator_value"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        entity-name="EntityName"
+        node="element-name"
+        extends="SuperclassName">
+
+        <property .... />
+        .....
+</subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="subclass1">
+                        <para>
+                            <literal>name</literal> : Le nom complet de la sous-classe.
+                        </para>
+                    </callout>
+                    <callout arearefs="subclass2">
+                        <para>
+                            <literal>discriminator-value</literal> (optionnel - par défaut le nom de la classe) : 
+                            une valeur qui distingue les différentes sous-classes.
+                        </para>
+                    </callout>
+                    <callout arearefs="subclass3">
+                        <para>
+                            <literal>proxy</literal> (optionnel) : Indique une classe ou interface à utiliser pour les chargements
+                            à la demande des proxies (lazy).
+                        </para>
+                    </callout>
+                    <callout arearefs="subclass4">
+                        <para>
+                            <literal>lazy</literal> (optionnel, par défaut à <literal>true</literal>) : Spécifier 
+                            <literal>lazy="false"</literal> désactive l'utilisation du chargement à la demande (lazy).
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                Chaque sous-classe devrait déclarer ses propres propriétés persistantes et sous-classes.
+                Les propriétés <literal>&lt;version&gt;</literal> et <literal>&lt;id&gt;</literal> 
+                sont implicitement hérités de la classe de base. Chaque sous-classe dans une hiérarchie doit 
+                définir une unique <literal>discriminator-value</literal>. Si aucune n'est spécifiée, 
+                le nom complet de la classe Java est utilisé.
+            </para>
+            <para>
+                Pour plus d'infos sur le mapping d'héritage, voir <xref linkend="inheritance"/>.
+        </para>
+            <programlisting><![CDATA[
+<hibernate-mapping>
+    <subclass name="DomesticCat" extends="Cat" discriminator-value="D">
+         <property name="name" type="string"/>
+    </subclass>
+</hibernate-mapping>]]></programlisting>
+            <para>
+                Pour des informations sur les mappings d'héritage, voir <xref linkend="inheritance"/>.
+            </para>
+        </sect2>
+        <sect2 id="mapping-declaration-joinedsubclass" revision="3">
+            <title>joined-subclass</title>
+            <para>
+                Une autre façon possible de faire est la suivante, chaque sous-classe peut être mappée vers sa propre table (stratégie 
+                de mapping de type table-per-subclass). L'état hérité est récupéré en joignant la table de la super-classe.
+                L'élément <literal>&lt;joined-subclass&gt;</literal> est utilisé.
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="joinedsubclass1" coords="2 45"/>
+                    <area id="joinedsubclass2" coords="3 45"/>
+                    <area id="joinedsubclass3" coords="4 45"/>
+                    <area id="joinedsubclass4" coords="5 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<joined-subclass
+        name="ClassName"
+        table="tablename"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        schema="schema"
+        catalog="catalog"
+        extends="SuperclassName"
+        persister="ClassName"
+        subselect="SQL expression"
+        entity-name="EntityName">
+
+        <key .... >
+
+        <property .... />
+        .....
+</joined-subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="joinedsubclass1">
+                        <para>
+                            <literal>name</literal> : Le nom Java complet de la sous-classe.
+                        </para>
+                    </callout>
+                    <callout arearefs="joinedsubclass2">
+                        <para>
+                            <literal>table</literal> : Le nom de la table de la sous-classe.
+                        </para>
+                    </callout>
+                    <callout arearefs="joinedsubclass3">
+                        <para>
+                            <literal>proxy</literal> (optionnel) : Indique une classe ou interface pour le chargement différé des proxies.
+                        </para>
+                    </callout>
+                    <callout arearefs="joinedsubclass4">
+                        <para>
+                            <literal>lazy</literal> (optionnel, par défaut à <literal>true</literal>) : Indiquer 
+                            <literal>lazy="false"</literal> désactive l'utilisation du chargement à la demande.
+                         </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                Aucune colonne discriminante n'est nécessaire pour cette stratégie de mapping. Cependant, 
+                chaque sous-classe doit déclarer une colonne de table contenant l'objet identifiant qui utilise l'élément 
+                <literal>&lt;key&gt;</literal>. Le mapping au début de ce chapitre serait ré-écrit ainsi :
+            </para>
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+        <class name="Cat" table="CATS">
+                <id name="id" column="uid" type="long">
+                        <generator class="hilo"/>
+                </id>
+                <property name="birthdate" type="date"/>
+                <property name="color" not-null="true"/>
+                <property name="sex" not-null="true"/>
+                <property name="weight"/>
+                <many-to-one name="mate"/>
+                <set name="kittens">
+                        <key column="MOTHER"/>
+                        <one-to-many class="Cat"/>
+                </set>
+                <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
+                    <key column="CAT"/>
+                    <property name="name" type="string"/>
+                </joined-subclass>
+        </class>
+
+        <class name="eg.Dog">
+                <!-- mapping for Dog could go here -->
+        </class>
+
+</hibernate-mapping>]]></programlisting>
+            <para>
+                 Pour des informations sur les mappings d'héritage, voir <xref linkend="inheritance"/>.
+             </para>
+        </sect2>
+        <sect2 id="mapping-declaration-unionsubclass" revision="2">
+            <title>union-subclass</title>
+            <para>
+               Une troisième option est de seulement mapper vers des tables les classes concrètes 
+               d'une hiérarchie d'héritage, (stratégie de type table-per-concrete-class) où 
+               chaque table définit tous les états persistants de la classe, y compris les états hérités. 
+               Dans Hibernate il n'est absolument pas nécessaire de mapper explicitement de telles hiérarchies 
+               d'héritage. Vous pouvez simplement mapper chaque classe avec une déclaration <literal>&lt;class&gt;</literal> 
+               différente. Cependant, si vous souhaitez utiliser des associations polymorphiques (càd une association 
+               vers la superclasse de la hiérarchie), vous devez utiliser le mapping <literal>&lt;union-subclass&gt;</literal>.
+           </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="unionsubclass1" coords="2 45"/>
+                    <area id="unionsubclass2" coords="3 45"/>
+                    <area id="unionsubclass3" coords="4 45"/>
+                    <area id="unionsubclass4" coords="5 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<union-subclass
+        name="ClassName"
+        table="tablename"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        schema="schema"
+        catalog="catalog"
+        extends="SuperclassName"
+        abstract="true|false"
+        persister="ClassName"
+        subselect="SQL expression"
+        entity-name="EntityName">
+
+        <property .... />
+        .....
+</union-subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="unionsubclass1">
+                        <para>
+                            <literal>name</literal> : Le nom Java complet de la sous-classe.
+                        </para>
+                    </callout>
+                    <callout arearefs="unionsubclass2">
+                        <para>
+                            <literal>table</literal> : nom de la table de la sous-classe.
+                        </para>
+                    </callout>
+                    <callout arearefs="unionsubclass3">
+                        <para>
+                            <literal>proxy</literal> (optionnel) : Indique une classe ou interface pour le chargement différé des proxies.
+                        </para>
+                    </callout>
+                    <callout arearefs="unionsubclass4">
+                        <para>
+                            <literal>lazy</literal> (optionnel, par défaut à <literal>true</literal>) : Indiquer 
+                            <literal>lazy="false"</literal> désactive l'utilisation du chargement à la demande.
+                         </para>
+
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                Aucune colonne discriminante ou colonne clef n'est requise pour cette stratégie de mapping.
+            </para>
+            <para>
+                Pour des informations sur les mappings d'héritage, voir <xref linkend="inheritance"/>.
+            </para>
+        </sect2>
+        <sect2 id="mapping-declaration-join" revision="3">
+            <title>join</title>
+            <para>
+                En utilisant l'élément <literal>&lt;join&gt;</literal>, il est possible de mapper 
+                des propriétés d'une classe sur plusieurs tables.
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="join1" coords="2 50"/>
+                    <area id="join2" coords="3 50"/>
+                    <area id="join3" coords="4 50"/>
+                    <area id="join4" coords="5 50"/>
+                    <area id="join5" coords="6 50"/>
+                    <area id="join6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<join
+        table="tablename"
+        schema="owner"
+        catalog="catalog"
+        fetch="join|select"
+        inverse="true|false"
+        optionnel="true|false">
+        
+        <key ... />
+        
+        <property ... />
+        ...
+</join>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="join1">
+                        <para>
+                            <literal>table</literal> : Le nom de la table jointe.
+                        </para>
+                    </callout>
+                    <callout arearefs="join2">
+                        <para>
+                            <literal>schema</literal> (optionnel) : court-circuite le nom de schéma spécifié par l'élément de base 
+                            <literal>&lt;hibernate-mapping&gt;</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="join3">
+                        <para>
+                            <literal>catalog</literal> (optionnel) : court-circuite le nom de catalogue spécifié par l'élément de base 
+                            <literal>&lt;hibernate-mapping&gt;</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="join4">
+                        <para>
+                            <literal>fetch</literal> (optionnel - par défaut à <literal>join</literal>) :
+                            Si positionné à <literal>join</literal>, Hibernate utilisera une jointure interne pour charger
+                            une <literal>jointure</literal> définie par une classe ou ses super-classes et une jointure externe
+                            pour une <literal>&lt;jointure&gt;</literal> définie par une sous-classe.
+                            Si positionné à <literal>select</literal> alors Hibernate utilisera un select séquentiel 
+                            pour une <literal>&lt;jointure&gt;</literal> définie sur une sous-classe, qui ne sera délivrée que
+                            si une ligne se représente une instance de la sous-classe. Les jointures internes seront quand même 
+                            utilisées pour charger une <literal>&lt;jointure&gt;</literal> définie par une classe et ses super-classes.
+                        </para>
+                    </callout>
+                    <callout arearefs="join5">
+                        <para>
+                            <literal>inverse</literal> (optionnel - par défaut à <literal>false</literal>) :
+                            Si positionné à true, Hibernate n'essaiera pas d'insérer ou de mettre à jour les 
+                            propriétés définies par cette jointure.
+                        </para>
+                    </callout>
+                    <callout arearefs="join6">
+                        <para>
+                            <literal>optionnel</literal> (optionnel - par défaut à <literal>false</literal>) :
+                            Si positionné à true, Hibernate insèrera une ligne seulement si les propriétés définies 
+                            par cette jointure sont non-nulles et utilisera toujours une jointure externe pour charger les propriétés.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                Par exemple, les informations d'adresse pour une personne peuvent être mappées vers une table 
+                séparée (tout en préservant des sémantiques de type valeur pour toutes ses propriétés) :
+            </para>
+            <programlisting><![CDATA[<class name="Person"
+    table="PERSON">
+
+    <id name="id" column="PERSON_ID">...</id>
+
+    <join table="ADDRESS">
+        <key column="ADDRESS_ID"/>
+        <property name="address"/>
+        <property name="zip"/>
+        <property name="country"/>
+    </join>
+    ...]]></programlisting>
+            <para>
+                Cette fonctionnalité est souvent seulement utile pour les modèles de données 
+                hérités d'anciens systèmes (legacy), nous recommandons d'utiliser moins de tables que de classes 
+                et un modèle de domaine à granularité fine. Cependant, c'est utile 
+                pour passer d'une stratégie de mapping d'héritage à une autre dans une hiérarchie simple ainsi qu'il est 
+                expliqué plus tard.
+            </para>
+        </sect2>
+        <sect2 id="mapping-declaration-key">
+            <title>key</title>
+            <para>
+                Nous avons rencontré l'élément <literal>&lt;key&gt;</literal> à plusieurs reprises maintenant. 
+                Il apparaît partout que l'élément de mapping parent définit une jointure sur une nouvele table, et 
+                définit la clef étrangère dans la table jointe, ce qui référence la clef primaire de la table d'origine.
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="key1" coords="2 50"/>
+                    <area id="key2" coords="3 50"/>
+                    <area id="key3" coords="4 50"/>
+                    <area id="key4" coords="5 50"/>
+                    <area id="key5" coords="6 50"/>
+                    <area id="key6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<key
+        column="columnname"
+        on-delete="noaction|cascade"
+        property-ref="propertyName"
+        not-null="true|false"
+        update="true|false"
+        unique="true|false"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="key1">
+                        <para>
+                            <literal>column</literal> (optionnel) : Le nom de la colonne de la clef étrangère
+                            Cela peut aussi être spécifié par l'élément(s) intégré(s) <literal>&lt;column&gt;</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="key2">
+                        <para>
+                            <literal>on-delete</literal> (optionnel, par défaut à <literal>noaction</literal>) :
+                            Indique si la contrainte de clef étrangère possède la possibilité au niveau base de données 
+                            de suppression en cascade.
+                        </para>
+                    </callout>
+                    <callout arearefs="key3">
+                        <para>
+                            <literal>property-ref</literal> (optionnel) : Indique que la clef étrangère fait 
+                            référence à des colonnes qui ne sont pas la clef primaire de la table d'origine 
+                            (Pour les données de systèmes legacy).
+                        </para>
+                    </callout>
+                    <callout arearefs="key4">
+                        <para>
+                            <literal>not-null</literal> (optionnel) : Indique que les colonnes des clefs étrangères ne 
+                            peuvent pas être nulles (c'est implicite si la clef étrangère fait partie de la clef primaire).
+                        </para>
+                    </callout>
+                    <callout arearefs="key5">
+                        <para>
+                            <literal>update</literal> (optionnel) : Indique que la clef étrangère ne devrait jamais être mise à jour 
+                            (implicite si celle-ci fait partie de la clef primaire).
+                        </para>
+                    </callout>
+                    <callout arearefs="key6">
+                        <para>
+                            <literal>unique</literal> (optionnel) : Indique que la clef étrangère doit posséder une contrainte 
+                            d'unicité (implicite si la clef étrangère est aussi la clef primaire).
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            <para>
+                Nous recommandons pour les systèmes où les suppressions doivent être performantes de définir toutes 
+                les clefs <literal>on-delete="cascade"</literal>, ainsi Hibernate utilisera une contrainte 
+                <literal>ON CASCADE DELETE</literal> au niveau base de données, plutôt que de nombreux
+                <literal>DELETE</literal> individuels. Attention, cette fonctionnalité court-circuite la stratégie 
+                habituelle de verrou optimiste pour les données versionnées.
+            </para>
+            <para>
+                Les attributs <literal>not-null</literal> et <literal>update</literal> sont utiles pour 
+                mapper une association one-to-many unidirectionnelle. Si vous mappez un one-to-many unidirectionnel 
+                vers une clef étrangère non nulle, vous <emphasis>devez</emphasis> déclarer la colonne de la clef 
+                en utilisant <literal>&lt;key not-null="true"&gt;</literal>.
+            </para>
+        </sect2>
+        <sect2 id="mapping-column" revision="4">
+            <title>éléments column et formula</title>
+            <para>
+               Tout élément de mapping qui accepte un attribut <literal>column</literal> acceptera alternativement 
+               un sous-élément <literal>&lt;column&gt;</literal>. De façon identique, <literal>&lt;formula&gt;</literal> 
+               est une alternative à l'attribut <literal>formula</literal>.
+           </para>
+            <programlisting><![CDATA[<column
+        name="column_name"
+        length="N"
+        precision="N"
+        scale="N"
+        not-null="true|false"
+        unique="true|false"
+        unique-key="multicolumn_unique_key_name"
+        index="index_name"
+        sql-type="sql_type_name"
+        check="SQL expression"/>]]></programlisting>
+            <programlisting><![CDATA[<formula>SQL expression</formula>]]></programlisting>
+            <para>
+                Les attributs <literal>column</literal> et <literal>formula</literal> peuvent même être combinés 
+                au sein d'une même propriété ou mapping d'association pour exprimer, par exemple, des conditions 
+                de jointure exotiques.
+            </para>
+            <programlisting><![CDATA[<many-to-one name="homeAddress" class="Address"
+        insert="false" update="false">
+    <column name="person_id" not-null="true" length="10"/>
+    <formula>'MAILING'</formula>
+</many-to-one>]]></programlisting>
+        </sect2>
+        <sect2 id="mapping-declaration-import">
+            <title>import</title>
+            <para>
+                Supposez que votre application possède deux classes persistantes du même nom, et vous ne voulez pas préciser 
+                le nom Java complet (packages inclus) dans les queries Hibernate. Les classes peuvent alors être "importées" 
+                explicitement plutôt que de compter sur <literal>auto-import="true"</literal>.Vous pouvez même importer 
+                des classes et interfaces qui ne sont pas mappées explicitement.
+            </para>
+            <programlisting><![CDATA[<import class="java.lang.Object" rename="Universe"/>]]></programlisting>
+            <programlistingco>
+                <areaspec>
+                    <area id="import1" coords="2 40"/>
+                    <area id="import2" coords="3 40"/>
+                </areaspec>
+                <programlisting><![CDATA[<import
+        class="ClassName"
+        rename="ShortName"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="import1">
+                        <para>
+                            <literal>class</literal> : Nom Java complet de la classe.
+                        </para>
+                    </callout>
+                    <callout arearefs="import2">
+                        <para>
+                            <literal>rename</literal> (optionnel - par défaut vaut le nom de la classe Java (sans package)) :
+                            Nom pouvant être utilisé dans le langage de requête.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+        </sect2>
+        <sect2 id="mapping-types-anymapping" revision="2">
+            <title>any</title>
+            <para>
+                Il existe encore un type de mapping de propriété. L'élément de mapping <literal>&lt;any&gt;</literal> 
+                définit une association polymorphique vers des classes de tables multiples. Ce type de mapping requiert 
+                toujours plus d'une colonne. La première colonne contient le type de l'entité associée. Les colonnes 
+                restantes contiennent l'identifiant. il est impossible de spécifier une contrainte de clef étrangère 
+                pour ce type d'association, donc ce n'est certainement pas considéré comme le moyen habituel de mapper 
+                des associations (polymorphiques). Vous devriez utiliser cela uniquement dans des cas particuliers 
+                (par exemple des logs d'audit, des données de session utilisateur, etc...).
+            </para>
+            <para>
+                 L'attribut <literal>meta-type</literal> permet à l'application de spécifier un type personnalisé qui mappe 
+                 des valeurs de colonnes de le base de données sur des classes persistantes qui ont un attribut identifiant 
+                 du type spécifié par <literal>id-type</literal>. Vous devez spécifier le mapping à partir de valeurs du 
+                 méta-type sur les noms des classes.
+            </para>
+            <programlisting><![CDATA[<any name="being" id-type="long" meta-type="string">
+    <meta-value value="TBL_ANIMAL" class="Animal"/>
+    <meta-value value="TBL_HUMAN" class="Human"/>
+    <meta-value value="TBL_ALIEN" class="Alien"/>
+    <column name="table_name"/>
+    <column name="id"/>
+</any>]]></programlisting>
+            <programlistingco>
+                <areaspec>
+                    <area id="any1" coords="2 50"/>
+                    <area id="any2" coords="3 50"/>
+                    <area id="any3" coords="4 50"/>
+                    <area id="any4" coords="5 50"/>
+                    <area id="any5" coords="6 50"/>
+                    <area id="any6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<any
+        name="propertyName"
+        id-type="idtypename"
+        meta-type="metatypename"
+        cascade="cascade_style"
+        access="field|property|ClassName"
+        optimistic-lock="true|false"
+>
+        <meta-value ... />
+        <meta-value ... />
+        .....
+        <column .... />
+        <column .... />
+        .....
+</any>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="any1">
+                        <para>
+                            <literal>name</literal> : le nom de la propriété.
+                        </para>
+                    </callout>
+                    <callout arearefs="any2">
+                        <para>
+                            <literal>id-type</literal> : le type identifiant.
+                        </para>
+                    </callout>
+                    <callout arearefs="any3">
+                        <para>
+                            <literal>meta-type</literal> (optionnel - par défaut à <literal>string</literal>) : 
+                            Tout type permis pour un mapping par discriminateur.
+                        </para>
+                    </callout>
+                    <callout arearefs="any4">
+                        <para>
+                            <literal>cascade</literal> (optionnel - par défaut à <literal>none</literal>) : 
+                            le style de cascade.
+                        </para>
+                    </callout>
+                    <callout arearefs="any5">
+                        <para>
+                            <literal>access</literal> (optionnel - par défaut à <literal>property</literal>) : La stratégie 
+                            à utiliser par Hibernate pour accéder à cette propriété.
+                        </para>
+                    </callout>
+                    <callout arearefs="any6">
+                        <para>
+                            <literal>optimistic-lock</literal> (optionnel - par défaut à <literal>true</literal>) : 
+                            Indique que les mises à jour sur cette propriété nécessitent ou non l'acquisition d'un 
+                            verrou optimiste. En d'autres termes, définit si un incrément de version doit avoir lieu 
+                            quand cette propriété est marquée dirty.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+        </sect2>
+    </sect1>
+    <sect1 id="mapping-types">
+        <title>Hibernate Types</title>
+        <sect2 id="mapping-types-entitiesvalues" revision="1">
+            <title>Entités et valeurs</title>
+            <para>
+                Pour comprendre le comportement des différents objets Java par rapport au service 
+                de persistance, nous avons besoin de les classer en deux groupes :
+            </para>
+            <para>
+                Une <emphasis>entité</emphasis> existe indépendamment de tout autre objet possédant 
+                une référence vers l'entité. Comparez cela avec le modèle Java habituel où un objet 
+                est supprimé par le garbage collector dès qu'il n'est plus référencé. Les entités 
+                doivent être explicitement enregistrées et supprimées (sauf dans les cas où 
+                sauvegardes et suppressions sont <emphasis>cascadées</emphasis> d'une entité mère 
+                vers ses enfants). C'est différent du modèle ODMG de persistance par 
+                atteignabilité - et correspond mieux à la façon dont les objets sont 
+                habituellement utilisés dans des grands systèmes. Les entités permettent les références 
+                circulaires et partagées. Elles peuvent aussi être versionnées.
+            </para>
+            <para>
+                L'état persistant d'une entité consiste en des références vers d'autres entités et 
+                instances de types <emphasis>valeurs</emphasis>. Ces valeurs sont des types primitifs, 
+                des collections (et non le contenu d'une collection), des composants de certains objets 
+                immuables. Contrairement aux entités, les valeurs (et en particulier les collections et 
+                composants) <emphasis>sont</emphasis> persistés par atteignabiliité. Comme les 
+                valeurs (et types primitifs) sont persistés et supprimés avec l'entité qui les contient, 
+                ils ne peuvent pas posséder leurs propres versions. Les valeurs n'ont pas d'identité 
+                indépendantes, ainsi elles ne peuvent pas être partagées par deux entités ou collections.
+            </para>
+            <para>
+                Jusqu'à présent nous avons utilisé le terme "classe persistante" pour parler d'entités. 
+                Nous allons continuer à faire ainsi. Cependant, au sens strict, toutes 
+                les classes définies par un utilisateur possédant un état persistant ne sont pas des 
+                entités. Un <emphasis>composant</emphasis> est une classe définie par un utilisateur 
+                avec les caractéristiques d'une valeur. Une propriété Java de type <literal>java.lang.String</literal>
+                a aussi les caractéristiques d'une valeur. 
+                
+                <!-- FIXME Baptiste MATHUS : J'ai remis le texte anglais pour que si la version est publiée
+                comme ça, au moins le lecteur puisse essayer lui aussi de comprendre la version anglaise... -->
+                
+                Given this definition, we can say that all types (classes) provided
+                by the JDK have value type semantics in Java, while user-defined types may
+                be mapped with entity or value type semantics. This decision is up to the
+                application developer. A good hint for an entity class in a domain model are
+                shared references to a single instance of that class, while composition or
+                aggregation usually translates to a value type.
+            </para>
+            <para>
+                Nous nous pencherons sur ces deux concepts tout au long de la documentation.
+            </para>
+            <para>
+                Le défi est de mapper les type Javas (et la définition des développeurs des 
+                entités et valeurs types) sur les types du SQL ou des bases de données. Le pont 
+                entre les deux systèmes est proposé par Hibernate : pour les entités nous utilisons 
+                <literal>&lt;class&gt;</literal>, <literal>&lt;subclass&gt;</literal> et ainsi de suite.
+                Pour les types valeurs nous utilisons <literal>&lt;property&gt;</literal>,
+                <literal>&lt;component&gt;</literal>, etc., habituellement avec un attribut <literal>type</literal>. 
+                La valeur de cet attribut est le nom d'un <emphasis>type de mapping</emphasis> Hibernate. 
+                Hibernate propose de base de nombreux mappings (pour les types de valeurs standards du JDK). 
+                Vous pouvez écrire vos propres types de mappings et implémenter aussi vos propres stratégies 
+                de conversion, nous le verrons plus tard.
+            </para>
+            <para>
+                Tous les types proposés de base par Hibernate à part les collections autorisent la valeur null.
+            </para>
+        </sect2>
+        <sect2 id="mapping-types-basictypes" revision="3">
+            <title>Basic value types</title>
+            <para>
+                Les <emphasis>types basiques de mapping</emphasis> proposés de base peuvent grossièrement être 
+                rangés dans les catégories suivantes :
+                <variablelist>
+                    <varlistentry>
+                        <term>
+                            <literal>integer, long, short, float, double, character, byte,
+                            boolean, yes_no, true_false</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                Les mappings de type des primitives Java ou leurs classes wrappers (ex: Integer 
+                                pour int) vers les types SQL (propriétaires) appropriés. <literal>boolean, 
+                                yes_no</literal>et <literal>true_false</literal> sont tous des alternatives 
+                                pour les types Java <literal>boolean</literal> ou <literal>java.lang.Boolean</literal>.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>string</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                Mapping de type de <literal>java.lang.String</literal> vers
+                                <literal>VARCHAR</literal> (ou le <literal>VARCHAR2</literal> Oracle).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>date, time, timestamp</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                Mappings de type pour <literal>java.util.Date</literal> et ses sous-classes  
+                                vers les types SQL <literal>DATE</literal>, <literal>TIME</literal> et
+                                <literal>TIMESTAMP</literal> (ou équivalent).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>calendar, calendar_date</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                Mappings de type pour <literal>java.util.Calendar</literal> vers les types SQL 
+                                <literal>TIMESTAMP</literal> et <literal>DATE</literal>
+                                (ou équivalent).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>big_decimal, big_integer</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                Mappings de type pour <literal>java.math.BigDecimal</literal> et
+                                <literal>java.math.BigInteger</literal> vers <literal>NUMERIC</literal> 
+                                (ou le <literal>NUMBER</literal> Oracle).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>locale, timezone, currency</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                Mappings de type pour <literal>java.util.Locale</literal>,
+                                <literal>java.util.TimeZone</literal> et 
+                                <literal>java.util.Currency</literal> 
+                                vers <literal>VARCHAR</literal> (ou le <literal>VARCHAR2</literal> Oracle).
+                                Les instances de <literal>Locale</literal> et <literal>Currency</literal> sont 
+                                mappées sur leurs codes ISO. Les instances de <literal>TimeZone</literal> sont
+                                mappées sur leur <literal>ID</literal>.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>class</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                Un type de mapping pour <literal>java.lang.Class</literal> vers
+                                <literal>VARCHAR</literal> (ou le <literal>VARCHAR2</literal> Oracle).
+                                Un objet <literal>Class</literal> est mappé sur son nom Java complet.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>binary</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                Mappe les tableaux de bytes vers le type binaire SQL approprié.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>text</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                Mappe les longues chaînes de caractères Java vers les types SQL 
+                                <literal>CLOB</literal> ou <literal>TEXT</literal>.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>serializable</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                Mappe les types Java sérialisables vers le type SQL binaire approprié. Vous pouvez 
+                                aussi indiquer le type Hibernate <literal>serializable</literal> avec le nom 
+                                d'une classe Java sérialisable ou une interface qui ne soit pas par défaut un type de base.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>clob, blob</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                Mappings de type pour les classes JDBC <literal>java.sql.Clob</literal> and
+                                <literal>java.sql.Blob</literal>. Ces types peuvent ne pas convenir pour certaines 
+                                applications car un objet blob ou clob peut ne pas être réutilisable en dehors 
+                                d'une transaction (de plus l'implémentation par les pilotes est moyennement bonne).
+                           </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date,
+                            imm_serializable, imm_binary</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                Mappings de type pour ceux qui sont habituellement modifiable, pour lesquels
+                                Hibernate effectue certains optimisations convenant seulement aux types Java immuables,
+                                et l'application les traite comme immuable. 
+                                Par exemple, vous ne devriez pas appeler <literal>Date.setTime()</literal> sur une instance
+                                mappée sur un <literal>imm_timestamp</literal>. Pour changer la valeur
+                                de la propriété, et faire que cette modification soit persistée, l'application
+                                doit assigner un nouvel (non identique) objet à la propriété.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                </variablelist>
+            </para>
+            <para>
+                Les identifiants uniques des entités et collections peuvent être de n'importe quel type de base excepté 
+                <literal>binary</literal>, <literal>blob</literal> et <literal>clob</literal> (les identifiants 
+                composites sont aussi permis, voir plus bas).
+            </para>
+            <para>
+                Les types de base des valeurs ont des <literal>Type</literal> constants correspondants définis 
+                dans <literal>org.hibernate.Hibernate</literal>. Par exemple, <literal>Hibernate.STRING</literal>
+                représenté le type <literal>string</literal>.
+            </para>
+        </sect2>
+        <sect2 id="mapping-types-custom" revision="2">
+            <title>Types de valeur définis par l'utilisateur</title>
+            <para>
+                Il est assez facile pour les développeurs de créer leurs propres types de valeurs. Par exemple, 
+                vous pourriez vouloir persister des propriétés du type <literal>java.lang.BigInteger</literal>
+                dans des colonnnes <literal>VARCHAR</literal>. Hibernate ne procure pas par défaut un type pour cela. 
+                Mais les types que vous pouvez créer ne se limitent pas à mapper des propriétés (ou élément collection) 
+                à une simple colonne d'une table. Donc, par exemple, vous pourriez avoir une propriété Java 
+                <literal>getName()</literal>/<literal>setName()</literal> de type 
+                <literal>java.lang.String</literal> persistée dans les colonnes  
+                <literal>FIRST_NAME</literal>, <literal>INITIAL</literal>, <literal>SURNAME</literal>.
+            </para>
+            <para>
+                Pour implémenter votre propre type, vous pouvez soit implémenter <literal>org.hibernate.UserType</literal> 
+                soit <literal>org.hibernate.CompositeUserType</literal> et déclarer des propriétés utilisant des 
+                noms de classes complets du type. Regardez <literal>org.hibernate.test.DoubleStringType</literal> 
+                pour voir ce qu'il est possible de faire.
+            </para>
+            <programlisting><![CDATA[<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
+    <column name="first_string"/>
+    <column name="second_string"/>
+</property>]]></programlisting>
+            <para>
+                Remarquez l'utilisation des tags <literal>&lt;column&gt;</literal> pour mapper une propriété sur des colonnes 
+                multiples.
+            </para>
+            <para>
+                Les interfaces <literal>CompositeUserType</literal>, <literal>EnhancedUserType</literal>,
+                <literal>UserCollectionType</literal>, et <literal>UserVersionType</literal> permettent des utilisations 
+                plus spécialisées.
+            </para>
+            <para>
+                Vous pouvez même donner des paramètres en indiquant <literal>UserType</literal> dans le fichier 
+                de mapping ; Pour cela, votre <literal>UserType</literal> doit implémenter l'interface 
+                <literal>org.hibernate.usertype.ParameterizedType</literal>. Pour spécifier des paramètres dans 
+                votre type propre, vous pouvez utiliser l'élément <literal>&lt;type&gt;</literal> dans vos fichiers de mapping.
+            </para>
+            <programlisting><![CDATA[<property name="priority">
+    <type name="com.mycompany.usertypes.DefaultValueIntegerType">
+        <param name="default">0</param>
+    </type>
+</property>]]></programlisting>
+            <para>
+                Le <literal>UserType</literal> permet maintenant de récupérer la valeur pour le paramètre nommé 
+                <literal>default</literal> à partir de l'objet <literal>Properties</literal> qui lui est passé.
+            </para>
+            <para>
+                Si vous utilisez fréquemment un <literal>UserType</literal>, cela peut être utile de lui définir un 
+                nom plus court. Vous pouvez faire cela en utilisant l'élément <literal>&lt;typedef&gt;</literal>. 
+                Les typedefs permettent d'assigner un nom à votre type propre et peuvent aussi contenir une liste de 
+                valeurs de paramètres par défaut si ce type est paramétré.
+            </para>
+            <programlisting><![CDATA[<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
+    <param name="default">0</param>
+</typedef>]]></programlisting>
+            <programlisting><![CDATA[<property name="priority" type="default_zero"/>]]></programlisting>
+            <para>
+                Il est aussi possible de redéfinir les paramètres par défaut du typedef au cas par cas en 
+                utilisant des paramètres type sur le mapping de la propriété. 
+            </para>
+            <para>
+                Bien que le fait que Hibernate propose de base une riche variété de types, et qu'il supporte les composants 
+                signifie que vous aurez très rarement <emphasis>besoin</emphasis> d'utiliser un nouveau type propre, 
+                il est néanmoins de bonne pratique d'utiliser des types propres pour les classes (non entités) qui 
+                apparaissent fréquemment dans votre application. Par exemple une classe <literal>MonetaryAmount</literal> 
+                est un bon candidat pour un <literal>CompositeUserType</literal> même s'il pourrait facilement 
+                être mappé comme un composant. Une motivation pour cela est l'abstraction. Avec un type propre 
+                vos documents de mapping sont à l'abri des changements futurs dans votre façon de représenter des 
+                valeurs monétaires.
+            </para>
+        </sect2>
+    </sect1>
+    
+        <sect1 id="mapping-entityname">
+        <title>Mapper une classe plus d'une fois</title>
+        <para>
+            Il est possible de proposer plus d'un mapping par classe persistante. Dans ce cas, vous
+            devez spécifier un <emphasis>nom d'entité</emphasis> pour lever l'ambiguité entre les instances
+            des entités mappées (par défaut, le nom de l'entité est celui de la classe). Hibernate
+            vous permet de spécifier le nom de l'entité lorsque vous utilisez des objets persistants, lorsque
+            vous écrivez des requêtes ou quand vous mappez des associations vers les entités nommées.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Contract" table="Contracts" 
+        entity-name="CurrentContract">
+    ...
+    <set name="history" inverse="true" 
+            order-by="effectiveEndDate desc">
+        <key column="currentContractId"/>
+        <one-to-many entity-name="HistoricalContract"/>
+    </set>
+</class>
+
+<class name="Contract" table="ContractHistory" 
+        entity-name="HistoricalContract">
+    ...
+    <many-to-one name="currentContract" 
+            column="currentContractId" 
+            entity-name="CurrentContract"/>
+</class>]]></programlisting>
+
+        <para>
+            Remarquez comment les associations sont désormais spécifiées en utilisant
+            <literal>entity-name</literal> au lieu de <literal>class</literal>.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="mapping-quotedidentifiers">
+        <title>SQL quoted identifiers</title>
+        <para>
+            Vous pouvez forcer Hibernate à mettre un identifiant entre quotes dans le SQL généré en mettant le nom 
+            de la table ou de la colonne entre backticks dans le 
+            document de mapping. Hibernate utilisera les bons styles de quotes pour le <literal>Dialect</literal> SQL 
+            (habituellement des doubles quotes, mais des parenthèses pour SQL server et des backticks pour MySQL).
+        </para>
+        <programlisting><![CDATA[<class name="LineItem" table="`Line Item`">
+    <id name="id" column="`Item Id`"/><generator class="assigned"/></id>
+    <property name="itemNumber" column="`Item #`"/>
+    ...
+</class>]]></programlisting>
+    </sect1>
+    <sect1 id="mapping-alternatives">
+        <title>alternatives Metadata</title>
+        <para>
+            XML ne convient pas à tout le monde, il y a donc des moyens alternatifs pour définir des metatda 
+            de mappings O/R dans Hibernate.
+        </para>
+        <sect2 id="mapping-xdoclet">
+            <title>utilisation de XDoclet</title>
+            <para>
+                De nombreux utilisateurs de Hibernate préfèrent embarquer les informations de mappings 
+                directement au sein du code source en utilisant les tags XDoclet <literal>@hibernate.tags</literal>. 
+                Nous ne couvrons pas cette approche dans ce document cependant, puisque c'est considéré comme faisant partie 
+                de XDoclet. Cependant, nous présentons l'exemple suivant de la classe <literal>Cat</literal> avec 
+                des mappings XDoclet.
+        </para>
+            <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+/**
+ * @hibernate.class
+ *  table="CATS"
+ */
+public class Cat {
+    private Long id; // identifier
+    private Date birthdate;
+    private Cat mother;
+    private Set kittens
+    private Color color;
+    private char sex;
+    private float weight;
+
+    /*
+     * @hibernate.id
+     *  generator-class="native"
+     *  column="CAT_ID"
+     */
+    public Long getId() {
+        return id;
+    }
+    private void setId(Long id) {
+        this.id=id;
+    }
+
+    /**
+     * @hibernate.many-to-one
+     *  column="PARENT_ID"
+     */
+    public Cat getMother() {
+        return mother;
+    }
+    void setMother(Cat mother) {
+        this.mother = mother;
+    }
+
+    /**
+     * @hibernate.property
+     *  column="BIRTH_DATE"
+     */
+    public Date getBirthdate() {
+        return birthdate;
+    }
+    void setBirthdate(Date date) {
+        birthdate = date;
+    }
+    /**
+     * @hibernate.property
+     *  column="WEIGHT"
+     */
+    public float getWeight() {
+        return weight;
+    }
+    void setWeight(float weight) {
+        this.weight = weight;
+    }
+
+    /**
+     * @hibernate.property
+     *  column="COLOR"
+     *  not-null="true"
+     */
+    public Color getColor() {
+        return color;
+    }
+    void setColor(Color color) {
+        this.color = color;
+    }
+    /**
+     * @hibernate.set
+     *  inverse="true"
+     *  order-by="BIRTH_DATE"
+     * @hibernate.collection-key
+     *  column="PARENT_ID"
+     * @hibernate.collection-one-to-many
+     */
+    public Set getKittens() {
+        return kittens;
+    }
+    void setKittens(Set kittens) {
+        this.kittens = kittens;
+    }
+    // addKitten not needed by Hibernate
+    public void addKitten(Cat kitten) {
+        kittens.add(kitten);
+    }
+
+    /**
+     * @hibernate.property
+     *  column="SEX"
+     *  not-null="true"
+     *  update="false"
+     */
+    public char getSex() {
+        return sex;
+    }
+    void setSex(char sex) {
+        this.sex=sex;
+    }
+}]]></programlisting>
+            <para>
+            Voyez le site web de Hibernate pour plus d'exemples sur XDoclet et Hibernate.
+        </para>
+        </sect2>
+        <sect2 id="mapping-annotations" revision="2">
+            <title>Utilisation des annotations JDK 5.0</title>
+            <para>
+                Le JDK 5.0 introduit des annotations proches de celles de XDoclet au niveau java, qui sont 
+                type-safe et vérifiées à la compilation. Ce mécanisme est plus puissant que XDoclet et mieux 
+                supporté par les outils et IDE. IntelliJ IDEA, par exemple, supporte l'auto-complétion et le 
+                surlignement syntaxique des annotations JDK 5.0. La nouvelle révision des spécifications des EJB 
+                (JSR-220) utilise les annotations JDK 5.0 comme mécanisme primaire pour les meta-données des beans entités. 
+                Hibernate3 implémente l'<literal>EntityManager</literal> de la JSR-220 (API de persistance), 
+                le support du mapping de meta-données est disponible via le package <emphasis>Hibernate Annotations</emphasis>, 
+                en tant que module séparé à télécharger. EJB3 (JSR-220) et les métadata Hibernate3 sont supportés.
+             </para>
+            <para>
+                Ceci est un exemple d'une classe POJO annotée comme un EJB entité :
+            </para>
+            <programlisting><![CDATA[@Entity(access = AccessType.FIELD)
+public class Customer implements Serializable {
+
+    @Id;
+    Long id;
+
+    String firstName;
+    String lastName;
+    Date birthday;
+
+    @Transient
+    Integer age;
+
+    @Embedded
+    private Address homeAddress;
+
+    @OneToMany(cascade=CascadeType.ALL)
+    @JoinColumn(name="CUSTOMER_ID")
+    Set<Order> orders;
+
+    // Getter/setter and business methods
+}]]></programlisting>
+            <para>
+                Notez que le support des annotations JDK 5.0 (et de la JSR-220) est encore en cours et n'est pas terminé.
+                Référez vous au module Hibernate Annotation pour plus de détails.
+            </para>
+        </sect2>
+    </sect1>
+    
+    <sect1 id="mapping-generated" revision="1">
+        <title>Propriétés générées</title>
+        <para>
+            Les propriétés générées sont des propriétés dont les valeurs sont générées par
+            la base de données. Typiquement, les applications Hibernate avaient besoin d'invoquer
+            <literal>refresh</literal> sur les instances qui contenaient des propriétés pour lesquelles
+            la base de données générait des valeurs. Marquer les propriétés comme générées permet à
+            l'application de déléguer cette responsabilité à Hibernate. Principalement, à chaque fois
+            qu'Hibernate réalise une insertion ou une mise à jour en base de données pour une entité
+            marquée comme telle, cela provoque immédiatement un select pour récupérer les valeurs générées.
+        </para>
+        <para>
+            Les propriétés marquées comme générées doivent de plus ne pas être insérables et modifiables 
+            Seuls <xref linkend="mapping-declaration-version">versions</xref>,
+            <xref linkend="mapping-declaration-timestamp">timestamps</xref>, et
+            <xref linkend="mapping-declaration-property">simple properties</xref> peuvent être marqués comme
+            générées.
+        </para>
+        <para>
+            <literal>never</literal> (par défaut) - indique la valeur de la propriété n'est pas générée
+            dans la base de données.
+        </para>
+        <para>
+            <literal>insert</literal> - indique que la valeur de la propriété donnée est
+            générée à l'insertion mais pas lors des futures mises à jour de l'enregistrement.
+            Les colonnes de type "date de création" sont le cas d'utilisation typique de cette option.
+            Notez que même les propriétés <xref linkend="mapping-declaration-version">version</xref> et
+            <xref linkend="mapping-declaration-timestamp">timestamp</xref> peuvent être
+            déclarées comme générées, cette option n'est pas disponible à cet endroit...
+        </para>
+        <para>
+            <literal>always</literal> - indique que la valeur de la propriété est générée à l'insert 
+            comme aux updates.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="mapping-database-object">
+        <title>Objets auxiliaires de la base de données</title>
+        <para>
+            Permettent les ordres CREATE et DROP d'objets arbitraire de la base de donnéées, en conjonction avec
+            les outils Hibernate d'évolutions de schéma, pour permettre de définir complètement
+            un schéma utilisateur au sein des fichiers de mapping Hibernate. Bien que conçu spécifiquement
+            pour créer et supprimer des objets tels que des triggers et des procédures stockées,
+            ou toute commande pouvant être exécutée via une méthode de <literal>java.sql.Statement.execute()</literal>
+            (ALTERs, INSERTS, etc). Il y a principalement deux modes pour définir les objets auxiliaires de base de données...
+        </para>
+        <para>
+            Le premier mode est de lister explicitement les commandes CREATE et DROP dans le fichier
+            de mapping:
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <create>CREATE TRIGGER my_trigger ...</create>
+        <drop>DROP TRIGGER my_trigger</drop>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+        <para>
+            Le second mode est de fournir une classe particulière qui connait comment construire
+            les commandes CREATE et DROP. Cette classe particulière doit implémenter l'interface
+            <literal>org.hibernate.mapping.AuxiliaryDatabaseObject</literal>.
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <definition class="MyTriggerDefinition"/>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+        <para>
+            Additionnellement, ces objets de base de données peuvent être optionnellement traités
+            selon l'utilisation de dialectes particuliers..
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <definition class="MyTriggerDefinition"/>
+        <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/>
+        <dialect-scope name="org.hibernate.dialect.OracleDialect"/>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+    </sect1>
+</chapter>

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/batch.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/batch.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/batch.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,329 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="batch">
+    <title>Traitement par paquet</title>
+
+    <para>
+        Une approche naïve pour insérer 100 000 lignes dans la base de données en utilisant
+        Hibernate pourrait ressembler à ça :
+    </para>
+
+    <programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+for ( int i=0; i<100000; i++ ) {
+    Customer customer = new Customer(.....);
+    session.save(customer);
+}
+tx.commit();
+session.close();]]></programlisting>
+
+    <para>
+        Ceci devrait s'écrouler avec une <literal>OutOfMemoryException</literal> quelque
+        part aux alentours de la 50 000ème ligne. C'est parce qu'Hibernate cache toutes
+        les instances de <literal>Customer</literal> nouvellement insérées dans le cache
+        de second niveau.
+    </para>
+
+    <para>
+        Dans ce chapitre nous montrerons comment éviter ce problème. D'abord, cependant,
+        si vous faites des traitements par batch, il est absolument critique que vous
+        activiez l'utilisation ds paquet JDBC (NdT : JDBC batching), si vous avez l'intention
+        d'obtenir des performances raisonnables. Configurez la taille du paquet JDBC avec un
+        nombre raisonnable (disons, 10-50) :
+    </para>
+
+    <programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
+
+    <para>
+        Vous pourriez aussi vouloir faire cette sorte de travail dans un traitement où
+        l'interaction avec le cache de second niveau est complètement désactivé :
+    </para>
+
+    <programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
+
+    <sect1 id="batch-inserts">
+        <title>Insertions en paquet</title>
+
+        <para>
+            Lorsque vous rendez des nouveaux objets persistants, vous devez régulièrement appeler
+            <literal>flush()</literal> et puis <literal>clear()</literal> sur la session,
+            pour contrôler la taille du cache de premier niveau.
+        </para>
+
+        <programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+for ( int i=0; i<100000; i++ ) {
+    Customer customer = new Customer(.....);
+    session.save(customer);
+    if ( i % 20 == 0 ) { //20, même taille que la taille du paquet JDBC
+        //flush un paquet d'insertions et libère la mémoire :
+        session.flush();
+        session.clear();
+    }
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="batch-update" >
+        <title>Paquet de mises à jour</title>
+
+        <para>
+            Pour récupérer et mettre à jour des données les mêmes idées s'appliquent. En plus,
+            vous avez besoin d'utiliser <literal>scroll()</literal> pour tirer partie des
+            curseurs côté serveur pour les requêtes qui retournent beaucoup de lignes de données.
+        </para>
+
+        <programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+    .setCacheMode(CacheMode.IGNORE)
+    .scroll(ScrollMode.FORWARD_ONLY);
+int count=0;
+while ( customers.next() ) {
+    Customer customer = (Customer) customers.get(0);
+    customer.updateStuff(...);
+    if ( ++count % 20 == 0 ) {
+        //flush un paquet de mises à jour et libère la mémoire :
+        session.flush();
+        session.clear();
+    }
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="batch-statelesssession">
+        <title>L'interface StatelessSession</title>
+        <para>
+            Alternativement, Hibernate fournit une API orientée commande qui peut être
+            utilisée avec des flux de données pour et en provenance de la base de données
+            sous la forme d'objets détachés. Une <literal>StatelessSession</literal> n'a pas
+            de contexte de persistance associé et ne fournit pas beaucoup de sémantique de
+            durée de vie de haut niveau. En particulier, une session sans état n'implémente
+            pas de cache de premier niveau et n'interagit pas non plus avec un cache de
+            seconde niveau ou un cache de requêtes. Elle n'implémente pas les transactions
+            ou la vérification sale automatique (NdT : automatic dirty checking). Les
+            opérations réalisées avec une session sans état ne sont jamais répercutées
+            en cascade sur les instances associées. Les collections sont ignorées par une
+            session sans état. Les opérations exécutées via une session sans état outrepasse
+            le modèle d'événements d'Hibernate et les intercepteurs. Les sessions sans état sont
+            vulnérables aux effets de modification des données, ceci est dû au manque de cache
+            de premier niveau. Une session sans état est une abstraction bas niveau, plus
+            proche de la couche JDBC sous-jacente.
+        </para>
+
+        <programlisting><![CDATA[StatelessSession session = sessionFactory.openStatelessSession();
+Transaction tx = session.beginTransaction();
+
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+    .scroll(ScrollMode.FORWARD_ONLY);
+while ( customers.next() ) {
+    Customer customer = (Customer) customers.get(0);
+    customer.updateStuff(...);
+    session.update(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            Notez que dans le code de l'exemple, les intances de <literal>Customer</literal>
+            retournées par la requête sont immédiatement détachées. Elles ne sont jamais
+            associées à un contexte de persistance.
+        </para>
+
+        <para>
+            Les opérations <literal>insert()</literal>, <literal>update()</literal> et
+            <literal>delete()</literal> définies par l'interface <literal>StatelessSession</literal>
+            sont considérées comme des opérations d'accès direct aux lignes de la base de données,
+            ce qui résulte en une exécution immédiate du SQL <literal>INSERT</literal>, <literal>UPDATE</literal>
+            ou <literal>DELETE</literal> respectif. De là, elles ont des sémantiques tres différentes des
+            opérations <literal>save()</literal>, <literal>saveOrUpdate()</literal>
+            et <literal>delete()</literal> définies par l'interface <literal>Session</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="batch-direct" revision="2">
+        <title>Opérations de style DML</title>
+
+        <para>
+            Comme déjà discuté avant, le mapping objet/relationnel automatique et transparent
+            est intéressé par la gestion de l'état de l'objet. Ceci implique que l'état de l'objet
+            est disponible en mémoire, d'où manipuler (en utilisant des expressions du langage de
+            manipulation de données - <literal>Data Manipulation Language</literal> (DML) - SQL)
+            les données directement dans la base n'affectera pas l'état en mémoire. Pourtant, Hibernate
+            fournit des méthodes pour l'exécution d'expression DML de style SQL lesquelles sont
+            réalisées à travers le langage de requête d'Hibernate (<xref linkend="queryhql">HQL</xref>).
+        </para>
+
+        <para>
+            La pseudo-syntaxe pour les expressions <literal>UPDATE</literal> et <literal>DELETE</literal>
+            est : <literal>( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?</literal>.
+            Certains points sont à noter :
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Dans la clause from, le mot-clef FROM est optionnel
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Il ne peut y avoir qu'une seule entité nommée dans la clause from ; elle peut
+                    optionnellement avoir un alias. Si le nom de l'entité a un alias, alors
+                    n'importe quelle référence de propriété doit être qualifiée en ayant un alias ;
+                    si le nom de l'entité n'a pas d'alias, alors il est illégal pour n'importe quelle
+                    référence de propriété d'être qualifiée.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Aucune jointure (implicite ou explicite) ne peut être spécifiée dans une requête HQL.
+                    Les sous-requêtes peuvent être utilisées dans la clause where ; les sous-requêtes,
+                    elles-mêmes, peuvent contenir des jointures.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    La clause where est aussi optionnelle.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Par exemple, pour exécuter un <literal>UPDATE</literal> HQL, utilisez la méthode
+            <literal>Query.executeUpdate()</literal> (la méthode est données pour ceux
+            qui sont familiers avec <literal>PreparedStatement.executeUpdate()</literal> de
+            JDBC) :
+        </para>
+
+        <programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
+// ou String hqlUpdate = "update Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+        .setString( "newName", newName )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            Pour exécuter un <literal>DELETE</literal> HQL, utilisez la même méthode
+            <literal>Query.executeUpdate()</literal> :
+        </para>
+
+        <programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlDelete = "delete Customer c where c.name = :oldName";
+// or String hqlDelete = "delete Customer where name = :oldName";
+int deletedEntities = s.createQuery( hqlDelete )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            La valeur du <literal>int</literal> retourné par la méthode <literal>Query.executeUpdate()</literal>
+            indique le nombre d'entités affectées par l'opération. Considérez que cela peut ou pas
+            corréler le nombre de lignes affectés dans la base de données. Une opération HQL
+            pourrait entraîner l'exécution de multiples expressions SQL réelles, pour des classes
+            filles mappées par jointure (NdT: join-subclass), par exemple. Le nombre retourné
+            indique le nombre d'entités réelles affectées par l'expression. Retour à l'exemple de la
+            classe fille mappée par jointure, un effacement d'une des classes filles peut réellement
+            entraîner des suppressions pas seulement dans la table qui mappe la classe fille, mais
+            aussi dans la table "racine" et potentillement dans les tables des classes filles plus bas
+            dans la hiérarchie d'héritage.
+        </para>
+
+        <para>
+            La pseudo-syntaxe pour l'expression <literal>INSERT</literal> est :
+            <literal>INSERT INTO EntityName properties_list select_statement</literal>. Quelques
+            points sont à noter :
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Seule la forme INSERT INTO ... SELECT ... est supportée ; pas la forme INSERT INTO ... VALUES ... .
+                </para>
+                <para>
+                    La properties_list est analogue à la <literal>spécification de la colonne</literal>
+
+                    The properties_list is analogous to the <literal>column speficiation</literal> dans
+                    l'expression SQL <literal>INSERT</literal>. Pour les entités impliquées dans
+                    un héritage mappé, seules les propriétés directement définies à ce niveau de classe
+                    donné peuvent être utilisées dans properties_list. Les propriétés de la classe mère
+                    ne sont pas permises ; et les propriétés des classes filles n'ont pas de sens. En
+                    d'autres mots, les expressions <literal>INSERT</literal> par nature non polymorphiques.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    select_statement peut être n'importe quelle requête de sélection HQl valide, avec
+                    l'avertissement que les types de retour doivent correspondre aux types attendus par
+                    l'insertion. Actuellement, c'est vérifié durant la compilation de la requête plutôt
+                    que la vérification soit reléguée à la base de données. Notez cependant que cela
+                    pourrait poser des problèmes entre les <literal>Type</literal>s d'Hibernate qui
+                    sont <emphasis>équivalents</emphasis> opposé à <emphasis>égaux</emphasis>. Cela
+                    pourrait poser des problèmes avec des disparités entre une propriété définie
+                    comme un <literal>org.hibernate.type.DateType</literal> et une propriété définie
+                    comme un <literal>org.hibernate.type.TimestampType</literal>, même si la base de données
+                    ne ferait pas de distinction ou ne serait pas capable de gérer la conversion.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Pour la propriéte id, l'expression d'insertion vous donne deux options. Vous
+                    pouvez soit spécifier explicitement la propriété id dans properties_list
+                    (auquel cas sa valeur est extraite de l'expression de sélection correspondante),
+                    soit l'omettre de properties_list (auquel cas une valeur générée est utilisée).
+                    Cette dernière option est seulement disponible en utilisant le générateur d'identifiant
+                    qui opère dans la base de données ; tenter d'utiliser cette option avec n'importe quel
+                    type de générateur "en mémoire" causera une exception durant l'analyse. Notez
+                    que pour les buts de cette discussion, les générateurs "en base" sont considérés
+                    être <literal>org.hibernate.id.SequenceGenerator</literal> (et ses classes filles)
+                    et n'importe quelles implémentations de
+                    <literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>.
+                    L'exception la plus notable ici est <literal>org.hibernate.id.TableHiLoGenerator</literal>,
+                    qu ne peut pas être utilisée parce qu'il ne propose pas un moyen de d'exposer ses valeurs
+                    par un select.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Pour des propriétés mappées comme <literal>version</literal> ou <literal>timestamp</literal>,
+                    l'expression d'insertion vous donne deux options. Vous pouvez soit spécifier la propriété dans
+                    properties_list (auquel cas sa valeur est extraite des expressions select correspondantes),
+                    soit l'omettre de properties_list (auquel cas la <literal>valeur de graine</literal>
+                    (NdT : seed value) définie par le <literal>org.hibernate.type.VersionType</literal> est utilisée).
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Un exemple d'exécution d'une expression <literal>INSERT</literal> HQL :
+        </para>
+
+        <programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
+int createdEntities = s.createQuery( hqlInsert )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/best_practices.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/best_practices.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/best_practices.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,240 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="best-practices" revision="3">
+    <title>Meilleures pratiques</title>
+
+    <variablelist spacing="compact">
+        <varlistentry>
+            <term>Découpez finement vos classes et mappez les en utilisant <literal>&lt;component&gt;</literal>.</term>
+            <listitem>
+                <para>
+                    Utilisez une classe <literal>Adresse</literal> pour encapsuler <literal>Rue</literal>,
+                    <literal>Region</literal>, <literal>CodePostal</literal>.
+                    Ceci permet la réutilisation du code et simplifie la maintenance.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Déclarez des propriétés d'identifiants dans les classes persistantes.</term>
+            <listitem>
+                <para>
+                    Hibernate rend les propriétés d'identifiants optionnelles. Il existe beaucoup de raisons
+                    pour lesquelles vous devriez les utiliser. Nous recommandons que vous utilisiez des identifiants
+		    techniques (générés, et sans connotation métier).
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Identifiez les clefs naturelles.</term>
+            <listitem>
+                <para>
+                    Identifiez les clefs naturelles pour toutes les entités, et mappez les avec
+                    <literal>&lt;natural-id&gt;</literal>. Implémentez <literal>equals()</literal> et
+                    <literal>hashCode()</literal> pour comparer les propriétés qui composent la clef naturelle.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Placez chaque mapping de classe dans son propre fichier.</term>
+            <listitem>
+                <para>
+                    N'utilisez pas un unique document de mapping. Mappez <literal>com.eg.Foo</literal> dans
+                    le fichier <literal>com/eg/Foo.hbm.xml</literal>. Cela prend tout son sens lors
+                    d'un travail en équipe.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Chargez les mappings comme des ressources.</term>
+            <listitem>
+                <para>
+                    Déployez les mappings en même temps que les classes qu'ils mappent.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Pensez à externaliser les chaînes de caractères.</term>
+            <listitem>
+                <para>
+                    Ceci est une bonne habitude si vos requêtes appellent des fonctions SQL qui ne sont
+                    pas au standard ANSI. Cette externalisation dans les fichiers de mapping rendra votre
+		    application plus portable.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Utilisez les variables "bindées".</term>
+            <listitem>
+                <para>
+                    Comme en JDBC, remplacez toujours les valeurs non constantes par "?". N'utilisez jamais
+                    la manipulation des chaînes de caractères pour remplacer des valeurs non constantes dans
+		     une requête ! Encore mieux, utilisez les paramètres nommés dans les requêtes.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Ne gérez pas vous même les connexions JDBC.</term>
+            <listitem>
+                <para>
+                    Hibernate laisse l'application gérer les connexions JDBC. Vous ne devriez gérer vos connexions
+                    qu'en dernier recours. Si vous ne pouvez pas utiliser les systèmes de connexions livrés,
+		    réfléchissez à l'idée de fournir votre propre implémentation de <literal>org.hibernate.connection.ConnectionProvider</literal>.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Pensez à utiliser les types utilisateurs.</term>
+            <listitem>
+                <para>
+                    Supposez que vous ayez une type Java, de telle bibliothèque, qui a besoin d'être persisté mais
+                    qui ne fournit pas les accesseurs nécessaires pour le mapper comme composant. Vous devriez
+		    implémenter
+                    <literal>org.hibernate.UserType</literal>.Cette approche libère le code de l'application
+                    de l'implémentation des transformations vers / depuis les types Hibernate.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Utilisez du JDBC pur dans les goulets d'étranglement.</term>
+            <listitem>
+                <para>
+                    Dans certaines parties critiques de votre système d'un point de vue performance, quelques opérations
+                    peuvent tirer partie d'un appel JDBC natif.
+                    Mais attendez de <emphasis>savoir</emphasis>
+                    que c'est un goulet d'étranglement. Ne supposez jamais qu'un appel JDBC sera forcément plus
+                    rapide. Si vous avez besoin d'utiliser JDBC directement, ouvrez une <literal>Session</literal>
+                    Hibernate et utilisez la connexion SQL sous-jacente. Ainsi vous pourrez utiliser la même stratégie
+                    de transation et la même gestion des connexions.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Comprendre le flush de <literal>Session</literal>.</term>
+            <listitem>
+                <para>
+                    De temps en temps la Session synchronise ses états persistants avec la base de données.
+                    Les performances seront affectées si ce processus arrive trop souvent. Vous pouvez parfois
+                    minimiser les flush non nécessaires en désactivant le flush automatique ou même en changeant
+                    l'ordre des opérations menées dans une transaction particulière.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Dans une architecture à trois couches, pensez à utiliser <literal>saveOrUpdate()</literal>.</term>
+            <listitem>
+                <para>
+                    Quand vous utilisez une architecture à base de servlet / session bean, vous pourriez passer
+                    des objets chargés dans le bean session vers et depuis la couche servlet / JSP. Utilisez
+		    une nouvelle session pour traiter chaque requête.
+                    Utilisez <literal>Session.merge()</literal> ou <literal>Session.saveOrUpdate()</literal> pour
+                    synchroniser les objets avec la base de données.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Dans une architecture à deux couches, pensez à utiliser la déconnexion de session.</term>
+            <listitem>
+                <para>
+                    Les transactions de bases de données doivent être aussi courtes que possible
+                    pour une meilleure montée en charge.Cependant, il est souvent nécessaire d'implémenter
+                    de longues <emphasis>transactions applicatives</emphasis>, une simple unité de travail du point de vue de
+                    l'utilisateur. Une transaction applicative
+                    peut s'étaler sur plusieurs cycles de requêtes/réponses du client.
+                    Il est commun d'utiliser des objets détachés pour implémenter des transactions applicatives.
+                    Une alternative, extrêmement appropriée dans une architecture à 2 couches, est de
+                    maintenir un seul contact de persistance ouvert (session) pour toute la durée de vie
+                    de la transaction applicative et simplement se déconnecter de la connexion JDBC à la fin de chaque requête,
+                    et se reconnecter au début de la requête suivante. Ne partagez jamais une seule
+                    session avec plus d'une transaction applicative, ou vous travaillerez avec des
+                    données périmées.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Considérez que les exceptions ne sont pas rattrapables.</term>
+            <listitem>
+                <para>
+                    Il s'agit plus d'une pratique obligatoire que d'une "meilleure pratique". Quand une exception
+                    intervient, il faut faire un rollback de la <literal>Transaction</literal> et
+                    fermer la <literal>Session</literal>.
+                    Sinon, Hibernate ne peut garantir l'intégrité des états persistants en mémoire. En particulier,
+                    n'utilisez pas <literal>Session.load()</literal> pour déterminer si une instance avec un identifiant
+                    donné existe en base de données, utilisez <literal>Session.get()</literal> ou un requête.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Préférez le chargement tardif des associations.</term>
+            <listitem>
+                <para>
+                    Utilisez le chargement complet avec modération.
+                    Utilisez les proxies et les collections chargées tardivement
+                    pour la plupart des associations vers des classes qui ne sont pas susceptibles
+                    d'être complètement retenues dans le cache de second niveau.
+                    Pour les assocations de classes en cache, où il y a une extrêmement
+                    forte probabilité que l'élément soit en cache, désactivez explicitement le chargement
+                    par jointures ouvertes en utilisant <literal>outer-join="false"</literal>.
+                    Lorsqu'un chargement par jointure ouverte est approprié pour un cas d'utilisation
+                    particulier, utilisez une requête avec un <literal>left join fetch</literal>.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>
+                Utilisez le pattern <emphasis>d'une ouverture de session dans une vue</emphasis>,
+                ou une <emphasis>phase d'assemblage</emphasis> disciplinée pour éviter des problèmes
+                avec des données non rapatriées.
+            </term>
+            <listitem>
+                <para>
+                    Hibernate libère les développeurs de l'écriture fastidieuse des <emphasis>objets de transfert
+                    de données (NdT : Data Transfer Objects)</emphasis> (DTO). Dans une architecture EJB traditionnelle,
+                    les DTOs ont deux buts : premièrement, ils contournent le problème des "entity bean" qui ne sont pas
+                    sérialisables ; deuxièmement, ils définissent implicitement une phase d'assemblage où toutes les
+                    données utilisées par la vue sont rapatriées et organisées dans les DTOs avant de retourner sous le
+                    contrôle de la couche de présentation. Hibernate élimine le premier but. Pourtant, vous aurez encore
+                    besoin d'une phase d'assemblage (pensez vos méthodes métier comme ayant un contrat strict avec la
+                    couche de présentation à propos de quelles données sont disponibles dans les objets détachés)
+                    à moins que vous soyez préparés à garder le contexte de
+                    persistance (la session) ouvert à travers tout le processus de rendu de la vue.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Pensez à abstraite votre logique métier d'Hibernate.</term>
+            <listitem>
+                <para>
+                    Cachez le mécanisme d'accès aux données (Hibernate) derrière une interface. Combinez les patterns
+                    <emphasis>DAO</emphasis> et <emphasis>Thread Local Session</emphasis>. Vous pouvez même avoir quelques
+                    classes persistées par du JDBC pur, associées à Hibernate via un <literal>UserType</literal> (ce conseil est
+                    valable pour des applications de taille respectables ; il n'est pas valable pour une application
+                    avec cinq tables).
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>N'utilisez pas d'associations de mapping exotiques.</term>
+            <listitem>
+                <para>
+                    De bons cas d'utilisation pour de vraies associations plusieurs-vers-plusieurs
+                    sont rares. La plupart du temps vous avez besoin d'informations additionnelles
+                    stockées dans la table d'association.
+                    Dans ce cas, il est préférable d'utiliser deux associations un-vers-plusieurs vers une classe
+                    de liaisons intermédiaire. En fait, nous pensons que la plupart des associations sont
+                    de type un-vers-plusieurs ou plusieurs-vers-un, vous devez être très attentifs lorsque
+                    vous utilisez autre chose et vous demander si c'est vraiment nécessaire.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Préférez les associations bidirectionnelles.</term>
+            <listitem>
+                <para>
+                    Les associations unidirectionnelles sont plus difficiles à questionner.
+                    Dans une grande application, la plupart des associations devraient être navigables dans les deux directions dans les requêtes.
+                </para>
+            </listitem>
+        </varlistentry>
+    </variablelist>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/collection_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/collection_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/collection_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1216 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="collections">
+    <title>Mapping des collections</title>
+
+    <sect1 id="collections-persistent" revision="3">
+        <title>Collections persistantes</title>
+
+        <para>
+            Hibernate requiert que les champs contenant des collections persistantes soient déclarés
+            comme des types d'interface, par exemple :
+        </para>
+
+        <programlisting><![CDATA[public class Product {
+    private String serialNumber;
+    private Set parts = new HashSet();
+
+    public Set getParts() { return parts; }
+    void setParts(Set parts) { this.parts = parts; }
+    public String getSerialNumber() { return serialNumber; }
+    void setSerialNumber(String sn) { serialNumber = sn; }
+}]]></programlisting>
+
+        <para>
+            L'interface réelle devrait être <literal>java.util.Set</literal>,
+            <literal>java.util.Collection</literal>, <literal>java.util.List</literal>,
+            <literal>java.util.Map</literal>, <literal>java.util.SortedSet</literal>,
+            <literal>java.util.SortedMap</literal> ou ... n'importe quoi d'autre ! (Où
+            "n'importe quoi d'autre" signifie que vous devrez écrire une implémentation de
+            <literal>org.hibernate.usertype.UserCollectionType</literal>.)
+        </para>
+
+        <para>
+            Notez comment nous avons initialisé les variables d'instance avec une instance de
+            <literal>HashSet</literal>. C'est le meilleur moyen pour initialiser les 
+            collections d'instances nouvellement créées (non persistantes). Quand
+            nous fabriquons l'instance persistante - en appelant <literal>persist()</literal>,
+            par exemple - Hibernate remplacera réellement le <literal>HashSet</literal>
+            avec une instance d'une implémentation propre à Hibernate de <literal>Set</literal>.
+            Prenez garde aux erreurs :
+        </para>
+
+        <programlisting><![CDATA[Cat cat = new DomesticCat();
+Cat kitten = new DomesticCat();
+....
+Set kittens = new HashSet();
+kittens.add(kitten);
+cat.setKittens(kittens);
+session.persist(cat);
+kittens = cat.getKittens(); // Ok, la collection kittens est un Set
+(HashSet) cat.getKittens(); // Erreur !]]></programlisting>
+
+        <para>
+            Les collections persistantes injectées par Hibernate se comportent de la même manière que
+            <literal>HashMap</literal>, <literal>HashSet</literal>,
+            <literal>TreeMap</literal>, <literal>TreeSet</literal> ou
+            <literal>ArrayList</literal>, selon le type de l'interface.
+        </para>
+
+        <para>
+            Les instances des collections ont le comportement habituel des types des valeurs.
+            Elles sont automatiquement persistées quand elles sont référencées par un objet persistant et
+            automatiquement effacées quand elles sont déréférencées. Si une collection est passée
+            d'un objet persistant à un autre, ses éléments pourraient être déplacés d'une table
+            à une autre. Deux entités ne peuvent pas partager une référence vers une même instance
+            d'une collection. Dû au modèle relationnel sous-jacent, les propriétés contenant des
+            collections ne supportent pas la sémantique de la valeur null ; Hibernate ne distingue pas
+            une référence vers une collection nulle d'une collection vide.
+        </para>
+
+        <para>
+            Vous ne devriez pas vous préoccuper trop de ça. Utilisez les collections persistantes de
+            la même manière que vous utilisez des collections Java ordinaires. Assurez-vous
+            de comprendre la sémantique des associations bidirectionnelles (traitée plus loin).
+        </para>
+
+    </sect1>
+
+    <sect1 id="collections-mapping" revision="4">
+        <title>Mapper une collection</title>
+
+        <para>
+            L'élément de mapping d'Hibernate utilisé pour mapper une collection dépend du type de
+            l'interface. Par exemple, un élément <literal>&lt;set&gt;</literal> est utilisé
+            pour mapper des propriétés de type <literal>Set</literal>.
+        </para>
+
+        <programlisting><![CDATA[<class name="Product">
+    <id name="serialNumber" column="productSerialNumber"/>
+    <set name="parts">
+        <key column="productSerialNumber" not-null="true"/>
+        <one-to-many class="Part"/>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            À part <literal>&lt;set&gt;</literal>, il y  aussi les éléments de mapping
+            <literal>&lt;list&gt;</literal>, <literal>&lt;map&gt;</literal>,
+            <literal>&lt;bag&gt;</literal>, <literal>&lt;array&gt;</literal> et
+            <literal>&lt;primitive-array&gt;</literal>.
+            L'élément <literal>&lt;map&gt;</literal> est représentatif :
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="mappingcollection1" coords="2 65"/>
+                <area id="mappingcollection2" coords="3 65"/>
+                <area id="mappingcollection3" coords="4 65"/>
+                <area id="mappingcollection4" coords="5 65"/>
+                <area id="mappingcollection5" coords="6 65"/>
+                <area id="mappingcollection6" coords="7 65"/>
+                <area id="mappingcollection7" coords="8 65"/>
+                <area id="mappingcollection8" coords="9 65"/>
+                <area id="mappingcollection9" coords="10 65"/>
+                <area id="mappingcollection10" coords="11 65"/>
+                <area id="mappingcollection11" coords="12 65"/>
+                <area id="mappingcollection12" coords="13 65"/>
+                <area id="mappingcollection13" coords="14 65"/>
+                <area id="mappingcollection14" coords="15 65"/>
+            </areaspec>
+            <programlisting><![CDATA[<map
+    name="nomDePropriete"
+    table="nom_de_table"
+    schema="nom_du_schema"
+    lazy="true|extra|false"
+    inverse="true|false"
+    cascade="all|none|save-update|delete|all-delete-orphan"
+    sort="unsorted|natural|ClasseDeComparateur"
+    order-by="nom_de_column asc|desc"
+    where="condition sql where quelcconque"
+    fetch="join|select|subselect"
+    batch-size="N"
+    access="field|property|NomDeClasse"
+    optimistic-lock="true|false"
+    mutable="true|false"
+    node="nom-d-element|."
+    embed-xml="true|false"
+>
+
+    <key .... />
+    <map-key .... />
+    <element .... />
+</map>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="mappingcollection1">
+                    <para>
+                        <literal>name</literal> : le nom de la propriété contenant la collection
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection2">
+                    <para>
+                        <literal>table</literal> (optionnel - par défaut = nom de la propriété) : le
+                        nom de la table de la collection (non utilisé pour les associations one-to-many)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection3">
+                    <para>
+                        <literal>schema</literal> (optionnel) : le nom du schéma pour surcharger le
+                        schéma déclaré dans l'élément racine
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection4">
+                    <para>
+                        <literal>lazy</literal> (optionnel - par défaut = <literal>true</literal>) :
+                        peut être utilisé pour désactiver l'initialisation tardive et spécifier
+                        que l'association est toujours rapportée, ou pour activer la
+                        récupération extra-paresseuse (NdT : extra-lazy) où la plupart des
+                        opérations n'initialisent pas la collection (approprié pour de très
+                        grosses collections)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection5">
+                    <para>
+                        <literal>inverse</literal> (optionnel - par défaut = <literal>false</literal>) :
+                        définit cette collection comme l'extrêmité "inverse" de l'association
+                        bidirectionnelle
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection6">
+                    <para>
+                        <literal>cascade</literal> (optionnel - par défaut = <literal>none</literal>) :
+                        active les opérations de cascade vers les entités filles
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection7">
+                    <para>
+                        <literal>sort</literal> (optionnel) : spécifie une collection triée via un ordre
+                        de tri <literal>naturel</literal>, ou via une classe comparateur donnée (implémentant Comparator)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection8">
+                    <para>
+                        <literal>order-by</literal> (optionnel, seulement à partir du JDK1.4) :
+                        spécifie une colonne de table
+                        (ou des colonnes) qui définit l'ordre d'itération de <literal>Map</literal>, <literal>Set</literal>
+                        ou Bag, avec en option <literal>asc</literal> ou <literal>desc</literal>
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection9">
+                    <para>
+                        <literal>where</literal> (optionnel) : spécifie une condition SQL arbitraire <literal>WHERE</literal>
+                        à utiliser au chargement ou à la suppression d'une collection (utile si la collection
+                        ne doit contenir qu'un sous ensemble des données disponibles)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection10">
+                    <para>
+                        <literal>fetch</literal> (optionnel, par défaut = <literal>select</literal>) :
+                        à choisir entre récupération par jointures externes, récupération par
+                        selects séquentiels, et récupération par sous-selects séquentiels
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection11">
+                    <para>
+                        <literal>batch-size</literal> (optionnel, par défaut = <literal>1</literal>) : une taille
+                        de batch (batch size) utilisée pour charger plusieurs instances de cette collection en
+                        initialisation tardive
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection12">
+                    <para>
+                        <literal>access</literal> (optionnel - par défaut = <literal>property</literal>) : La
+                        stratégie qu'Hibernate doit utiliser pour accéder à la valeur de la propriété
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection13">
+                    <para>
+                        <literal>optimistic-lock</literal> (optionnel - par défaut = <literal>true</literal>) :
+                        spécifie que changer l'état de la collection entraîne l'incrémentation
+                        de la version appartenant à l'entité (Pour une association un vers plusieurs,
+                        il est souvent raisonnable de désactiver ce paramètre)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection14">
+                    <para>
+                        <literal>mutable</literal> (optionnel - par défaut = <literal>true</literal>) :
+                        une valeur à <literal>false</literal> spécifie que les éléments de la
+                        collection ne changent jamais (une optimisation mineure dans certains cas)
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <sect2 id="collections-foreignkeys" >
+           <title>Les clefs étrangères d'une collection</title>
+
+            <para>
+                Les instances d'une collection sont distinguées dans la base par la clef étrangère
+                de l'entité qui possède la collection. Cette clef étrangère est référencée comme la(es)
+                <emphasis>colonne(s) de la clef de la collection</emphasis> de la table de la collection.
+                La colonne de la clef de la collection est mappée par l'élément <literal>&lt;key&gt;</literal>.
+            </para>
+
+            <para>
+                Il peut y avoir une contrainte de nullité sur la colonne de la clef étrangère. Pour les
+                associations unidirectionnelles un vers plusieurs, la colonne de la clef étrangère
+                peut être nulle par défaut, donc vous pourriez avoir besoin de spécifier
+                <literal>not-null="true"</literal>.
+            </para>
+
+            <programlisting><![CDATA[<key column="productSerialNumber" not-null="true"/>]]></programlisting>
+
+            <para>
+                La contraite de la clef étrangère peut utiliser <literal>ON DELETE CASCADE</literal>.
+            </para>
+
+            <programlisting><![CDATA[<key column="productSerialNumber" on-delete="cascade"/>]]></programlisting>
+
+            <para>
+                Voir le chapitre précédent pour une définition complète de l'élément <literal>&lt;key&gt;</literal>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="collections-elements" >
+            <title>Les éléments d'une collection</title>
+
+            <para>
+                Les collections peuvent contenir la plupart des autres types Hibernate, dont tous les types
+                basiques, les types utilisateur, les composants, et bien sûr, les références vers
+                d'autres entités. C'est une distinction importante : un objet dans une collection
+                pourrait être géré avec une sémantique de "valeur" (sa durée de vie dépend complètement
+                du propriétaire de la collection) ou il pourrait avoir une référence vers une autre
+                entité, avec sa propre durée de vie. Dans le dernier cas, seul le "lien" entre les 2 objets
+                est considéré être l'état retenu par la collection.
+            </para>
+
+            <para>
+                Le type contenu est référencé comme le <emphasis>type de l'élément de la collection</emphasis>.
+                Les éléments de la collections sont mappés par <literal>&lt;element&gt;</literal> ou
+                <literal>&lt;composite-element&gt;</literal>, ou dans le cas des références d'entité, avec
+                <literal>&lt;one-to-many&gt;</literal> ou <literal>&lt;many-to-many&gt;</literal>.
+                Les deux premiers mappent des éléments avec un sémantique de valeur, les deux suivants sont
+                utilisés pour mapper des associations d'entité.
+            </para>
+
+        </sect2>
+
+        <sect2 id="collections-indexed">
+            <title>Collections indexées</title>
+
+            <para>
+                Tous les mappings de collection, exceptés ceux avec les sémantiques d'ensemble (NdT : set) et
+                de sac (NdT : bag), ont besoin d'une <emphasis>colonne d'index</emphasis> dans la
+                table de la collection - une colonne qui mappe un index de tableau, ou un index de
+                <literal>List</literal>, ou une clef de <literal>Map</literal>. L'index d'une
+                <literal>Map</literal> peut être n'importe quel type basique, mappé avec
+                <literal>&lt;map-key&gt;</literal>, ça peut être une référence d'entité mappée avec
+                <literal>&lt;map-key-many-to-many&gt;</literal>, ou ça peut être un type composé, mappé avec
+                <literal>&lt;composite-map-key&gt;</literal>. L'index d'un tableau ou d'une liste est toujours
+                de type <literal>integer</literal> et est mappé en utilisant l'élément <literal>&lt;list-index&gt;</literal>.
+                Les colonnes mappées contiennent des entiers séquentiels (numérotés à partir de zéro par défaut).
+            </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="index1" coords="2 45"/>
+                <area id="index2" coords="3 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<list-index
+        column="nom_de_colonne"
+        base="0|1|..."/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="index1">
+                    <para>
+                        <literal>nom_de_colonne</literal> (requis) : le nom de la colonne contenant les valeurs de l'index de la collection
+                    </para>
+                </callout>
+                <callout arearefs="index1">
+                    <para>
+                        <literal>base</literal> (optionnel, par défaut = <literal>0</literal>) : la valeur
+                        de la colonne de l'index qui correspond au premier élément de la liste ou du tableau
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <programlistingco>
+            <areaspec>
+                <area id="mapkey1" coords="2 45"/>
+                <area id="mapkey2" coords="3 45"/>
+                <area id="mapkey3" coords="4 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<map-key
+        column="nom_de_colonne"
+        formula="n'importe quelle expression SQL"
+        type="nom_du_type"
+        node="@nom-d-attribut"
+        length="N"/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="mapkey1">
+                    <para>
+                        <literal>column</literal> (optionnel) :
+                        le nom de la colonne contenant les valeurs de l'index de la collection
+                    </para>
+                </callout>
+                <callout arearefs="mapkey2">
+                    <para>
+                        <literal>formula</literal> (optionnel) :
+                        une formule SQL utilisée pour évaluer la clef de la map
+                    </para>
+                </callout>
+                <callout arearefs="mapkey3">
+                    <para>
+                        <literal>type</literal> (reguis): le type des clefs de la map
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <programlistingco>
+            <areaspec>
+                <area id="indexmanytomany1" coords="2 45"/>
+                <area id="indexmanytomany2" coords="3 45"/>
+                <area id="indexmanytomany3" coords="3 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<map-key-many-to-many
+        column="nom_de_colonne"
+        formula="n'importe quelle expression SQL"
+        class="NomDeClasse"
+/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="indexmanytomany1">
+                    <para>
+                        <literal>column</literal> (optionnel) :
+                        le nom de la colonne de la clef étrangère pour les valeurs de l'index de la collection
+                    </para>
+                </callout>
+                <callout arearefs="indexmanytomany2">
+                    <para>
+                        <literal>formula</literal> (optionnel) :
+                        une formulre SQL utilisée pour évaluer la clef étrangère de la clef de la map
+                    </para>
+                </callout>
+                <callout arearefs="indexmanytomany3">
+                    <para>
+                        <literal>class</literal> (requis): la classe de l'entité utilisée comme clef de la map
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+            <para>
+                Si votre table n'a pas de colonne d'index, et que vous souhaitez tout de même utiliser
+                <literal>List</literal> comme type de propriété, vous devriez mapper la propriété comme un
+                <emphasis>&lt;bag&gt;</emphasis> Hibernate. Un sac (NdT : bag) ne garde pas son ordre quand
+                il est récupéré de la base de données, mais il peut être optionnellement trié ou ordonné.
+            </para>
+
+        </sect2>
+
+        <para>
+            Il y a pas mal de variétés de mappings qui peuvent être générés pour les collections,
+            couvrant beaucoup des modèles relationnels communs. Nous vous suggérons d'expérimenter avec l'outil de
+            génération de schéma pour avoir une idée de comment traduire les différentes déclarations de mapping vers des table de la base de données.
+        </para>
+
+    <sect2 id="collections-ofvalues" revision="2">
+        <title>Collections de valeurs et associations plusieurs-vers-plusieurs</title>
+
+        <para>
+            N'importe quelle collection de valeurs ou association plusieurs-vers-plusieurs requiert une
+            <emphasis>table de collection</emphasis> avec une(des) colonne(s) de clef étrangère, une(des)
+            <emphasis>colonne(s) d'élément de la collection</emphasis> ou des colonnes et possiblement
+            une(des) colonne(s) d'index.
+        </para>
+
+        <para>
+            Pour une collection de valeurs, nous utilisons la balise <literal>&lt;element&gt;</literal>.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="element1b" coords="2 50"/>
+                <area id="element2b" coords="3 50"/>
+                <area id="element3b" coords="4 50"/>
+             </areaspec>
+            <programlisting><![CDATA[<element
+        column="nom_de_colonne"
+        formula="n'importe quelle expression SQL"
+        type="nomDeType"
+        length="L"
+        precision="P"
+        scale="S"
+        not-null="true|false"
+        unique="true|false"
+        node="nom-d-element"
+/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="element1b">
+                    <para>
+                        <literal>column</literal> (optionnel) : le nom de la colonne contenant les valeurs de l'élément de la collection
+                    </para>
+                </callout>
+                <callout arearefs="element2b">
+                    <para>
+                        <literal>formula</literal> (optionnel) : une formule SQL utilisée pour évaluer l'élément
+                    </para>
+                </callout>
+                <callout arearefs="element3b">
+                    <para>
+                        <literal>type</literal> (requis) : le type de l'élément de la collection
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <para>
+            Une <emphasis>association plusieurs-vers-plusieurs</emphasis> est spécifiée en
+            utilisant l'élément <literal>&lt;many-to-many&gt;</literal>.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="manytomany1" coords="2 60"/>
+                <area id="manytomany2" coords="3 60"/>
+                <area id="manytomany3" coords="4 60"/>
+                <area id="manytomany4" coords="5 60"/>
+                <area id="manytomany5" coords="6 60"/>
+                <area id="manytomany6" coords="7 60"/>
+                <area id="manytomany7" coords="8 60"/>
+                <area id="manytomany8" coords="9 60"/>
+            </areaspec>
+            <programlisting><![CDATA[<many-to-many
+        column="nom_de_colonne"
+        formula="n'importe quelle expression SQL"
+        class="NomDeClasse"
+        fetch="select|join"
+        unique="true|false"
+        not-found="ignore|exception"
+        entity-name="NomDEntite"
+        property-ref="nomDeProprieteDeLaClasseAssociee"
+        node="nom-d-element"
+        embed-xml="true|false"
+    />]]></programlisting>
+            <calloutlist>
+                <callout arearefs="manytomany1">
+                    <para>
+                        <literal>column</literal> (optionnel) : le nom de la colonne de la clef étrangère de l'élément
+                    </para>
+                </callout>
+                <callout arearefs="manytomany2">
+                    <para>
+                        <literal>formula</literal> (optionnel) :
+                        une formule SQL utilisée pour évaluer la valeur de la clef étrangère de l'élément
+                    </para>
+                </callout>
+                <callout arearefs="manytomany3">
+                    <para>
+                        <literal>class</literal> (requis) : le nom de la classe associée
+                    </para>
+                </callout>
+                <callout arearefs="manytomany4">
+                    <para>
+                        <literal>fetch</literal> (optionnel - par défaut <literal>join</literal>) :
+                        active les récupérations par jointures externes ou par selects séquentiels pour cette association.
+                        C'est un cas spécial ; pour une récupération complète sans attente (dans un seul <literal>SELECT</literal>) d'une
+                        entité et de ses relations plusieurs-vers-plusieurs vers d'autres entités,
+                        vous devriez activer la récupération <literal>join</literal> non seulement sur
+                        la collection elle-même, mais aussi avec cet attribut sur l'élément imbriqué
+                        <literal>&lt;many-to-many&gt;</literal>.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany5">
+                    <para>
+                        <literal>unique</literal> (optionnel) : activer la génération DDL d'une
+                        contrainte d'unicité pour la colonne de la clef étrangère. Ça rend la pluralité
+                        de l'association effectivement un-vers-plusieurs.
+                    </para>
+                </callout>
+	            <callout arearefs="manytomany6">
+	                <para>
+	                    <literal>not-found</literal> (optionnel - par défaut <literal>exception</literal>) :
+                            spécifie comment les clefs étrangères qui référencent la lignes
+                            manquantes seront gérées : <literal>ignore</literal> traitera
+                            une ligne manquante comme une association nulle.
+	                </para>
+	            </callout>
+                <callout arearefs="manytomany7">
+                    <para>
+                        <literal>entity-name</literal> (optionnel) : le nom de l'entité de la classe associée, comme une alternative à <literal>class</literal>
+                    </para>
+                </callout>
+                <callout arearefs="manytomany8">
+                    <para>
+                        <literal>property-ref</literal> (optionnel) : le nom d'une propriété de
+                        la classe associée qui est jointe à cette clef étrangère. Si non spécifiée,
+                        la clef primaire de la classe associée est utilisée.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <para>
+            Quelques exemples, d'abord, un ensemble de chaînes de caractères :
+        </para>
+
+        <programlisting><![CDATA[<set name="names" table="person_names">
+    <key column="person_id"/>
+    <element column="person_name" type="string"/>
+</set>]]></programlisting>
+
+        <para>
+            Un bag contenant des entiers (avec un ordre d'itération déterminé par l'attribut <literal>order-by</literal>) :
+        </para>
+
+        <programlisting><![CDATA[<bag name="sizes"
+        table="item_sizes"
+        order-by="size asc">
+    <key column="item_id"/>
+    <element column="size" type="integer"/>
+</bag>]]></programlisting>
+
+        <para>
+            Un tableau d'entités - dans ce cas, une association plusieurs-vers-plusieurs :
+        </para>
+
+        <programlisting><![CDATA[<array name="addresses"
+        table="PersonAddress"
+        cascade="persist">
+    <key column="personId"/>
+    <list-index column="sortOrder"/>
+    <many-to-many column="addressId" class="Address"/>
+</array>]]></programlisting>
+
+        <para>
+            Une map de chaînes de caractères vers des dates :
+        </para>
+
+        <programlisting><![CDATA[<map name="holidays"
+        table="holidays"
+        schema="dbo"
+        order-by="hol_name asc">
+    <key column="id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            Une liste de composants (discute dans le prochain chapitre) :
+        </para>
+
+        <programlisting><![CDATA[<list name="carComponents"
+        table="CarComponents">
+    <key column="carId"/>
+    <list-index column="sortOrder"/>
+    <composite-element class="CarComponent">
+        <property name="price"/>
+        <property name="type"/>
+        <property name="serialNumber" column="serialNum"/>
+    </composite-element>
+</list>]]></programlisting>
+
+    </sect2>
+
+    <sect2 id="collections-onetomany">
+        <title>Association un-vers-plusieurs</title>
+
+        <para>
+            Une <emphasis>association un vers plusieurs</emphasis> lie les tables de deux classes
+            par une clef étrangère, sans l'intervention d'une table de collection. Ce mapping perd certaines sémantiques des collections Java normales :
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Une instance de la classe de l'entité contenue ne peut pas appartenir à plus d'une
+                    instance de la collection
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Une instance de la classe de l'entité contenue ne peut pas apparaître plus plus d'une valeur d'index de la collection
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Une association de <literal>Product</literal> vers <literal>Part</literal> requiert l'existence d'une
+            clef étrangère et possiblement une colonne d'index pour la table <literal>Part</literal>. Une balise
+            <literal>&lt;one-to-many&gt;</literal> indique que c'est une association un vers plusieurs.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="onetomany1" coords="2 60"/>
+                <area id="onetomany2" coords="3 60"/>
+                <area id="onetomany3" coords="4 60"/>
+            </areaspec>
+            <programlisting><![CDATA[<one-to-many
+        class="NomDeClasse"
+        not-found="ignore|exception"
+        entity-name="NomDEntite"
+        node="nom-d-element"
+        embed-xml="true|false"
+    />]]></programlisting>
+            <calloutlist>
+                <callout arearefs="onetomany1">
+                    <para>
+                        <literal>class</literal> (requis) : le nom de la classe associée
+                    </para>
+                </callout>
+                <callout arearefs="onetomany2">
+                    <para>
+                        <literal>not-found</literal> (optionnel - par défaut <literal>exception</literal>) :
+                        spécifie comment les identifiants cachés qui référencent des lignes manquantes seront gérés :
+                        <literal>ignore</literal> traitera une ligne manquante comme une association nulle
+                    </para>
+                </callout>
+                <callout arearefs="onetomany3">
+                    <para>
+                        <literal>entity-name</literal> (optionnel) : le nom de l'entité de la
+                        classe associée, comme une alternative à <literal>class</literal>.
+                    </para>
+                </callout>
+            </calloutlist>
+       </programlistingco>
+
+        <para>
+            Notez que l'élément <literal>&lt;one-to-many&gt;</literal> n'a pas besoin de déclarer de colonnes. Il n'est pas non plus nécessaire de spécifier le nom de la table nulle part.
+        </para>
+
+        <para>
+            <emphasis>Note très importante :</emphasis> si la colonne de la clef d'une association
+            <literal>&lt;one-to-many&gt;</literal> est déclarée <literal>NOT NULL</literal>, vous devez déclarer le
+            mapping de <literal>&lt;key&gt;</literal> avec <literal>not-null="true"</literal> ou
+            <emphasis>utiliser une association bidirectionnelle</emphasis> avec le mapping de la
+            collection marqué <literal>inverse="true"</literal>. Voir la discussion sur les associations bidirectionnelles plus tard dans ce chapitre.
+        </para>
+
+        <para>
+            Cet exemple montre une map d'entités <literal>Part</literal> par nom (où
+            <literal>partName</literal> est une propriété persistante de <literal>Part</literal>).
+            Notez l'utilisation d'un index basé sur une formule.
+        </para>
+
+        <programlisting><![CDATA[<map name="parts"
+        cascade="all">
+    <key column="productId" not-null="true"/>
+    <map-key formula="partName"/>
+    <one-to-many class="Part"/>
+</map>]]></programlisting>
+    </sect2>
+
+    </sect1>
+
+    <sect1 id="collections-advancedmappings">
+        <title>Mappings de collection avancés</title>
+
+    <sect2 id="collections-sorted" revision="2">
+        <title>Collections triées</title>
+
+        <para>
+            Hibernate supporte des collections implémentant <literal>java.util.SortedMap</literal> et
+            <literal>java.util.SortedSet</literal>. Vous devez spécifier un comparateur dans le fichier de mapping :
+        </para>
+
+        <programlisting><![CDATA[<set name="aliases"
+            table="person_aliases"
+            sort="natural">
+    <key column="person"/>
+    <element column="name" type="string"/>
+</set>
+
+<map name="holidays" sort="my.custom.HolidayComparator">
+    <key column="year_id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            Les valeurs permises pour l'attribut <literal>sort</literal> sont <literal>unsorted</literal>,
+            <literal>natural</literal> et le nom d'une classe implémentant
+            <literal>java.util.Comparator</literal>.
+        </para>
+
+        <para>
+            Les collections triées se comportent réellement comme <literal>java.util.TreeSet</literal> ou
+            <literal>java.util.TreeMap</literal>.
+        </para>
+
+        <para>
+            Si vous voulez que la base de données elle-même ordonne les éléments de la collection, utilisez l'attribut
+            <literal>order-by</literal> des mappings <literal>set</literal>, <literal>bag</literal>
+            ou <literal>map</literal>. Cette solution est seulement disponible à partir du JDK 1.4 (c'est
+            implémenté en utilisant <literal>LinkedHashSet</literal> ou
+            <literal>LinkedHashMap</literal>). Ceci exécute le tri dans la requête SQL, pas en mémoire.
+        </para>
+
+        <programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="lower(name) asc">
+    <key column="person"/>
+    <element column="name" type="string"/>
+</set>
+
+<map name="holidays" order-by="hol_date, hol_name">
+    <key column="year_id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            Notez que la valeur de l'attribut <literal>order-by</literal> est un ordre SQL, pas un ordre HQL !
+        </para>
+
+        <para>
+            Les associations peuvent même être triées sur des critères arbitraires à l'exécution en utilisant un <literal>filter()</literal> de collection.
+        </para>
+
+        <programlisting><![CDATA[sortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list();]]></programlisting>
+
+    </sect2>
+
+     <sect2 id="collections-bidirectional" revision="1">
+        <title>Associations bidirectionnelles</title>
+
+        <para>
+            Une <emphasis>association bidirectionnelle</emphasis> permet une navigation à
+            partir de la "fin" de l'association. Deux sortes d'associations bidirectionnelles sont supportées :
+            <variablelist>
+                <varlistentry>
+                    <term>un-vers-plusieurs (NdT : one-to-many)</term>
+                    <listitem>
+                        <para>
+                            ensemble ou sac à une extrémité, une seule valeur à l'autre
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>plusieurs-vers-plusieurs (NdT : many-to-many)</term>
+                    <listitem>
+                        <para>
+                            ensemble ou sac aux deux extrémités
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+        </para>
+
+        <para>
+            Vous pouvez spécifier une association plusieurs-vers-plusieurs bidirectionnelle simplement
+            en mappant deux associations plusieurs-vers-plusieurs vers la même table de base de données et en déclarant une extrémité comme <emphasis>inverse</emphasis> (celle de votre choix, mais ça ne peut pas être une collection indexée).
+        </para>
+
+        <para>
+            Voici un exemple d'association bidirectionnelle plusieurs-vers-plusieurs ; chaque catégorie peut
+            avoir plusieurs objets et chaque objet peut être dans plusieurs catégories :
+        </para>
+
+        <programlisting><![CDATA[<class name="Category">
+    <id name="id" column="CATEGORY_ID"/>
+    ...
+    <bag name="items" table="CATEGORY_ITEM">
+        <key column="CATEGORY_ID"/>
+        <many-to-many class="Item" column="ITEM_ID"/>
+    </bag>
+</class>
+
+<class name="Item">
+    <id name="id" column="CATEGORY_ID"/>
+    ...
+
+    <!-- inverse end -->
+    <bag name="categories" table="CATEGORY_ITEM" inverse="true">
+        <key column="ITEM_ID"/>
+        <many-to-many class="Category" column="CATEGORY_ID"/>
+    </bag>
+</class>]]></programlisting>
+
+        <para>
+            Les changements faits uniquement sur l'extréminté inverse de l'association <emphasis>ne sont pas</emphasis>
+            persistés. Ceci signifie qu'Hibernate a deux représentations en mémoire pour chaque
+            association bidirectionnelles, un lien de A vers B et un autre de B vers A. C'est
+            plus facile à comprendre si vous pensez au modèle objet de Java et comment nous
+            créons une relation plusieurs-vers-plusieurs en Java :
+        </para>
+
+        <programlisting><![CDATA[
+category.getItems().add(item);          // La catégorie est maintenant "au courant" de la relation
+item.getCategories().add(category);     // L'objet est maintenant "au courant" de la relation
+
+session.persist(item);                   // La relation ne sera pas sauvegardée !
+session.persist(category);               // La relation sera sauvegardée]]></programlisting>
+
+        <para>
+            La partie non-inverse est utilisée pour sauvegarder la représentation en mémoire dans la base de données.
+        </para>
+
+        <para>
+            Vous pouvez définir une association un-vers-plusieurs bidirectionnelle en mappant une
+            association un-vers-plusieurs vers la(es) même(s) colonne(s) de table qu'une association
+            plusieurs-vers-un et en déclarant l'extrémité pluri-valuée <literal>inverse="true"</literal>.
+        </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <set name="children" inverse="true">
+        <key column="parent_id"/>
+        <one-to-many class="Child"/>
+    </set>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <many-to-one name="parent"
+        class="Parent"
+        column="parent_id"
+        not-null="true"/>
+</class>]]></programlisting>
+
+        <para>
+            Mapper une extrémité d'une association avec <literal>inverse="true"</literal> n'affecte
+            pas l'opération de cascades, ce sont des concepts orthogonaux !
+        </para>
+
+    </sect2>
+
+    <sect2 id="collections-indexedbidirectional">
+        <title>Associations bidirectionnelles avec des collections indexées</title>
+        <para>
+            Une association bidirectionnelle où une extrémité est représentée comme une <literal>&lt;list&gt;</literal>
+            ou une <literal>&lt;map&gt;</literal> requiert une considération spéciale. Si il y a une
+            propriété de la classe enfant qui mappe la colonne de l'index, pas de problème, nous pouvons
+            continuer à utiliser <literal>inverse="true"</literal> sur le mapping de la collection :
+        </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <map name="children" inverse="true">
+        <key column="parent_id"/>
+        <map-key column="name"
+            type="string"/>
+        <one-to-many class="Child"/>
+    </map>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <property name="name"
+        not-null="true"/>
+    <many-to-one name="parent"
+        class="Parent"
+        column="parent_id"
+        not-null="true"/>
+</class>]]></programlisting>
+
+        <para>
+            Mais, si il n'y a pas de telle prorpriété sur la classe enfant, nous ne pouvons pas penser
+            à l'association comme vraiment bidirectionnelle (il y a des informations disponibles à une
+            extrémité de l'association qui ne sont pas disponibles à l'autre extrémité). Dans ce cas,
+            nous ne pouvons pas mapper la collection <literal>inverse="true"</literal>. À la place, nous
+            pourrions utiliser le mapping suivant :
+        </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <map name="children">
+        <key column="parent_id"
+            not-null="true"/>
+        <map-key column="name"
+            type="string"/>
+        <one-to-many class="Child"/>
+    </map>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <many-to-one name="parent"
+        class="Parent"
+        column="parent_id"
+        insert="false"
+        update="false"
+        not-null="true"/>
+</class>]]></programlisting>
+
+       <para>
+           Notez que dans ce mapping, l'extrémité de l'association contenant la collection est responsable
+           des mises à jour de la clef étrangère. À faire : cela entraîne-t-il réellement des expressions
+           updates inutiles ?
+       </para>
+
+    </sect2>
+
+    <sect2 id="collections-ternary">
+        <title>Associations ternaires</title>
+
+        <para>
+            Il y a trois approches possibles pour mapper une association ternaire. L'une est d'utiliser
+            une <literal>Map</literal> avec une association en tant qu'index :
+        </para>
+
+        <programlisting><![CDATA[<map name="contracts">
+    <key column="employer_id" not-null="true"/>
+    <map-key-many-to-many column="employee_id" class="Employee"/>
+    <one-to-many class="Contract"/>
+</map>]]></programlisting>
+
+            <programlisting><![CDATA[<map name="connections">
+    <key column="incoming_node_id"/>
+    <map-key-many-to-many column="outgoing_node_id" class="Node"/>
+    <many-to-many column="connection_id" class="Connection"/>
+</map>]]></programlisting>
+
+        <para>
+            Une seconde approche est simplement de remodeler l'association comme une classe d'entité. C'est
+            l'approche la plus commune.
+        </para>
+
+        <para>
+            Une alternative finale est d'utiliser des éléments composites, dont nous discuterons plus tard.
+        </para>
+
+    </sect2>
+
+    <sect2 id="collections-idbag" revision="1">
+        <title>Utiliser un <literal>&lt;idbag&gt;</literal></title>
+
+        <para>
+            Si vous embrassez pleinement notre vue que les clefs composées sont une mauvaise
+            chose et que des entités devraient avoir des identifiants artificiels (des clefs
+            subrogées), alors vous pourriez trouver un peu curieux que les associations
+            plusieurs-vers-plusieurs et les collections de valeurs que nous avons montré jusqu'ici
+            mappent toutes des tables avec des clefs composées ! Maintenant, ce point est assez
+            discutable ; une table d'association pure ne semble pas beaucoup bénéficier d'une clef
+            subrogée (bien qu'une collection de valeur composées le <emphasis>pourrait</emphasis>).
+            Néanmoins, Hibernate fournit une foncionnalité qui vous permet de mapper
+            des associations plusieurs-vers-plusieurs et des collections de valeurs vers une
+            table avec une clef subrogée.
+        </para>
+
+        <para>
+            L'élément <literal>&lt;idbag&gt;</literal> vous laisse mapper une <literal>List</literal>
+            (ou une <literal>Collection</literal>) avec une sémantique de sac.
+        </para>
+
+<programlisting><![CDATA[<idbag name="lovers" table="LOVERS">
+    <collection-id column="ID" type="long">
+        <generator class="sequence"/>
+    </collection-id>
+    <key column="PERSON1"/>
+    <many-to-many column="PERSON2" class="Person" fetch="join"/>
+</idbag>]]></programlisting>
+
+        <para>
+            Comme vous pouvez voir, un <literal>&lt;idbag&gt;</literal> a un généréteur d'id
+            artificiel, comme une classe d'entité ! Une clef subrogée différente est assignée
+            à chaque ligne de la collection. Cependant, Hibernate ne fournit pas de mécanisme pour
+            découvrir la valeur d'une clef subrogée d'une ligne particulière.
+        </para>
+
+        <para>
+            Notez que les performances de la mise à jour d'un <literal>&lt;idbag&gt;</literal>
+            sont <emphasis>bien</emphasis> meilleures qu'un <literal>&lt;bag&gt;</literal> ordinaire !
+            Hibernate peut localiser des lignes individuelles efficacement et les mettre à jour ou
+            les effacer individuellement, comme une liste, une map ou un ensemble.
+        </para>
+
+        <para>
+            Dans l'implémentation actuelle, la stratégie de la génération de l'identifiant <literal>native</literal>
+            n'est pas supportée pour les identifiants de collection <literal>&lt;idbag&gt;</literal>.
+        </para>
+
+    </sect2>
+
+    </sect1>
+
+    <!--undocumenting this stuff -->
+
+    <!--sect1 id="collections-heterogeneous">
+        <title>Heterogeneous Associations</title>
+
+        <para>
+            The <literal>&lt;many-to-any&gt;</literal> and <literal>&lt;index-many-to-any&gt;</literal>
+            elements provide for true heterogeneous associations. These mapping elements work in the
+            same way as the <literal>&lt;any&gt;</literal> element - and should also be used
+            rarely, if ever.
+        </para>
+
+    </sect1-->
+
+    <sect1 id="collections-example" revision="1">
+        <title>Exemples de collections</title>
+
+        <para>
+            Les sections précédentes sont assez confuses. Donc prenons un exemple. Cette classe :
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+
+public class Parent {
+    private long id;
+    private Set children;
+
+    public long getId() { return id; }
+    private void setId(long id) { this.id=id; }
+
+    private Set getChildren() { return children; }
+    private void setChildren(Set children) { this.children=children; }
+
+    ....
+    ....
+}]]></programlisting>
+
+        <para>
+            a une collection d'instances de <literal>Child</literal>. Si chaque enfant
+            a au plus un parent, le mapping le plus naturel est une association
+            un-vers-plusieurs :
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children">
+            <key column="parent_id"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Ceci mappe les définitions de tables suivantes :
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255), parent_id bigint )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+        <para>
+            Si le parent est <emphasis>requis</emphasis>, utilisez une association un-vers-plusieurs unidirectionnelle :
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children" inverse="true">
+            <key column="parent_id"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+        <many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Notez la contrainte <literal>NOT NULL</literal> :
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null
+                     primary key,
+                     name varchar(255),
+                     parent_id bigint not null )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+        <para>
+            Alternativement, si vous insistez absolument pour que cette association soit unidirectionnelle,
+            vous pouvez déclarer la contrainte <literal>NOT NULL</literal> sur le mapping <literal>&lt;key&gt;</literal> :
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children">
+            <key column="parent_id" not-null="true"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            D'un autre côté, si un enfant pouvait avoir plusieurs parent, une association
+            plusieurs-vers-plusieurs est plus appropriée :
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children" table="childset">
+            <key column="parent_id"/>
+            <many-to-many class="Child" column="child_id"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Définitions des tables :
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255) )
+create table childset ( parent_id bigint not null,
+                        child_id bigint not null,
+                        primary key ( parent_id, child_id ) )
+alter table childset add constraint childsetfk0 (parent_id) references parent
+alter table childset add constraint childsetfk1 (child_id) references child]]></programlisting>
+
+        <para>
+            Pour plus d'exemples et une revue complète du mapping de la relation parent/enfant, voir
+            see <xref linkend="example-parentchild"/>.
+        </para>
+
+        <para>
+            Des mappings d'association plus exotiques sont possibles, nous cataloguerons toutes les possibilités
+            dans le prochain chapitre.
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/component_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/component_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/component_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,402 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<chapter id="components">
+    <title>Mapping de composants</title>
+
+    <para>
+        La notion de <emphasis>composants</emphasis> est réutilisé dans différents contextes,
+        avec différents objectifs, à travers Hibernate.
+    </para>
+
+    <sect1 id="components-dependentobjects" revision="2" >
+        <title>Objects dépendants</title>
+
+        <para>
+            Le composant est un objet inclu dans un autre qui est sauvegardé comme une valeur, et
+            non pas comme une entité.
+            Le composant fait référence à la notion (au sens objet) de composition
+            (et non pas de composant au sens d'architecture de composants).
+            Par exemple on pourrait modélisé l'objet personne de cette façon:
+        </para>
+
+        <programlisting><![CDATA[public class Person {
+    private java.util.Date birthday;
+    private Name name;
+    private String key;
+    public String getKey() {
+        return key;
+    }
+    private void setKey(String key) {
+        this.key=key;
+    }
+    public java.util.Date getBirthday() {
+        return birthday;
+    }
+    public void setBirthday(java.util.Date birthday) {
+        this.birthday = birthday;
+    }
+    public Name getName() {
+        return name;
+    }
+    public void setName(Name name) {
+        this.name = name;
+    }
+    ......
+    ......
+}]]></programlisting>
+
+<programlisting><![CDATA[public class Name {
+    char initial;
+    String first;
+    String last;
+    public String getFirst() {
+        return first;
+    }
+    void setFirst(String first) {
+        this.first = first;
+    }
+    public String getLast() {
+        return last;
+    }
+    void setLast(String last) {
+        this.last = last;
+    }
+    public char getInitial() {
+        return initial;
+    }
+    void setInitial(char initial) {
+        this.initial = initial;
+    }
+}]]></programlisting>
+
+        <para>
+            Maintenant <literal>Name</literal> peut-être sauvegardé comme un composant de 
+            <literal>Person</literal>. Remarquer que <literal>Name</literal> définit des methodes 
+            d'accès et de modification pour ses propriétés persistantes, mais il n'a pas besoin 
+            des interfaces ou des propriétés d'identification ( par exemple getId() ) qui sont propres aux entités.
+        </para>
+
+        <para>
+            Nous serions alors amené à mapper ce composant de cette façon:
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Person" table="person">
+    <id name="Key" column="pid" type="string">
+        <generator class="uuid"/>
+    </id>
+    <property name="birthday" type="date"/>
+    <component name="Name" class="eg.Name"> <!-- class attribute optional -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </component>
+</class>]]></programlisting>
+
+        <para>
+            La table person aurai les colonnes <literal>pid</literal>,
+            <literal>birthday</literal>,
+            <literal>initial</literal>,
+            <literal>first</literal> and
+            <literal>last</literal>.
+        </para>
+
+        <para>
+            Comme tous les types valeurs, les composants ne supportent pas les références partagés.
+            En d'autres mots, deux instances de person peuvent avoir un même nom, mais ces noms sont
+			indépendants, ils peuvent être identiques si on les compare par valeur mais ils représentent
+			deux objets distincts en mémoire. La notion de nullité pour un composant est 
+            <emphasis>ad hoc</emphasis>. Quand il recharge l'objet qui contient le composant, Hibernate 
+            supposera que si tous les champs du composants sont nuls alors le composant sera positionné 
+            à la valeur null. Ce choix programmatif devrait être satisfaisant dans la plupart des cas.
+        </para>
+
+        <para>
+            Les propriétés d'un composant peuvent être de tous les types qu'Hibernate supporte habituellement
+            (collections, many-to-one associations, autres composants, etc). Les composants inclus ne doivent <emphasis>pas</emphasis> 
+            être vus comme quelque chose d'exotique. Hibernate a été conçu pour supporter un modèle objet très granulaire.
+        </para>
+
+        <para>
+            Le  <literal>&lt;component&gt;</literal> peut inclure dans la liste de ses propriétés
+            une référence au <literal>&lt;parent&gt;</literal> conteneur.
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Person" table="person">
+    <id name="Key" column="pid" type="string">
+        <generator class="uuid"/>
+    </id>
+    <property name="birthday" type="date"/>
+    <component name="Name" class="eg.Name" unique="true">
+        <parent name="namedPerson"/> <!-- référence arrière à Person -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </component>
+</class>]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="components-incollections" revision="1">
+        <title>Collection d'objets dépendants</title>
+
+        <para>
+            Les collections d'objets dépendants sont supportés (exemple: un tableau de type 
+            <literal>Name</literal>). Déclarer la collection de composants en remplaçant le tag <literal>&lt;element&gt;</literal> 
+            par le tag <literal>&lt;composite-element&gt;</literal>.
+        </para>
+
+        <programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
+    <key column="id"/>
+    <composite-element class="eg.Name"> <!-- class attribute required -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </composite-element>
+</set>]]></programlisting>
+
+        <para>
+            Remarque: Si vous définissez un <literal>Set</literal> d'élément composite,
+            il est très important d'implémenter la méthode <literal>equals()</literal> et 
+            <literal>hashCode()</literal> correctement.
+        </para>
+
+        <para>
+            Les élements composite peuvent aussi contenir des composants mais pas des collections.
+            Si votre élément composite contient aussi des composants, utilisez l'élément <literal>&lt;nested-composite-element&gt;</literal> 
+            . Une collections de composants qui ccontiennent eux-mêmes des composants est un cas très exotique.
+            A ce stade demandez-vous si une association un-à-plusieurs ne serait pas plus approprié.
+            Essayez de re remodeler votre élément composite comme une entité ( Dans ce cas même si le modèle
+            Java est le même la logique de persitence et de relation sont tout de même différentes)
+        </para>
+
+        <para>
+            Remarque, le mapping d'éléments composites ne supporte pas la nullité des 
+            propriétés lorsqu'on utilise un <literal>&lt;set&gt;</literal>. Hibernate
+            lorsqu'il supprime un objet utilise chaque colonne pour identifier un objet
+            (on ne peut pas utiliser des clés primaires distinctes dans une table d'éléments composites),
+            ce qui n'est pas possible avec des valeurs nulles. Vous devez donc choisir d'interdire la nullité
+            des propriétés d'un élément composite ou choisir un autre type de collection comme :
+            <literal>&lt;list&gt;</literal>, <literal>&lt;map&gt;</literal>,
+            <literal>&lt;bag&gt;</literal> ou <literal>&lt;idbag&gt;</literal>.
+        </para>
+
+        <para>
+            Un cas particulier d'élément composite est un élément composite qui inclut un élément
+            <literal>&lt;many-to-one&gt;</literal>. Un mapping comme celui-ci 
+            vous permet d'associer les colonnes d'une table d'association plusieurs à plusieurs (many-to-many)
+            à la classse de l'élément composite. L'exemple suivant est une association plusieurs à plusieurs
+            de <literal>Order</literal> à <literal>Item</literal> à 
+            <literal>purchaseDate</literal>, <literal>price</literal> et
+            <literal>quantity</literal> sont des propriétés de l'association.
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Order" .... >
+    ....
+    <set name="purchasedItems" table="purchase_items" lazy="true">
+        <key column="order_id">
+        <composite-element class="eg.Purchase">
+            <property name="purchaseDate"/>
+            <property name="price"/>
+            <property name="quantity"/>
+            <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Bien sûr, il ne peut pas y avoir de référence à l'achat (purchase) depuis l'article (item), pour 
+            pouvoir naviguer de façon bidirectionnelle dans l'association. N'oubliez pas que les composants 
+            sont de type valeurs et n'autorise pas les références partagées. 
+        </para>
+
+        <para>Même les associations ternaires ou quaternaires sont possibles:</para>
+
+        <programlisting><![CDATA[<class name="eg.Order" .... >
+    ....
+    <set name="purchasedItems" table="purchase_items" lazy="true">
+        <key column="order_id">
+        <composite-element class="eg.OrderLine">
+            <many-to-one name="purchaseDetails class="eg.Purchase"/>
+            <many-to-one name="item" class="eg.Item"/>
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Les éléments composites peuvent apparaître dans les requêtes en utilisant
+            la même syntaxe que associations
+        </para>
+
+    </sect1>
+
+    <sect1 id="components-asmapindex">
+        <title>Utiliser les composants comme index de map</title>
+
+        <para>
+            l'élément <literal>&lt;composite-map-key&gt;</literal> 
+            vous permet d'utiliser une classe de composant comme indice de 
+            <literal>Map</literal>. Assurez-vous d'avoir surdéfini 
+            <literal>hashCode()</literal> et <literal>equals()</literal> dans la 
+            classe du composant.
+        </para>
+    </sect1>
+
+    <sect1 id="components-compositeid" revision="1">
+        <title>Utiliser un composant comme identifiant</title>
+
+        <para>
+            Vous pouvez utiliser un composant comme identifiant d'une entité.
+            Mais pour cela la classe du composant doit respecter certaines règles.
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Elle doit implémenter <literal>java.io.Serializable</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Elle doit redéfinir <literal>equals()</literal> et
+                    <literal>hashCode()</literal>, de façon cohérente avec le 
+                    fait qu'elle définit une clé composite dans la base de 
+                    données.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            <emphasis>
+            Remarque: avec hibernate3, la seconde règle n'est plus absolument 
+            necessaire mais faîtes le quand même.</emphasis>
+        </para>
+
+        <para>
+        	Vous ne pouvez pas utiliser de <literal>IdentifierGenerator</literal> pour générer 
+        	une clé composite, l'application devra définir elle même ses propres identifiants.
+        </para>
+
+        <para>
+            Utiliser l'élément <literal>&lt;composite-id&gt;</literal>  (en incluant l'élément 
+            <literal>&lt;key-property&gt;</literal>) à la place de l'habituel déclaration 
+            <literal>&lt;id&gt;</literal>. Par exemple la classe
+            <literal>OrderLine</literal> qui dépend de la clé primaire 
+             (composite) de  <literal>Order</literal>.
+        </para>
+
+        <programlisting><![CDATA[<class name="OrderLine">
+    
+    <composite-id name="id" class="OrderLineId">
+        <key-property name="lineId"/>
+        <key-property name="orderId"/>
+        <key-property name="customerId"/>
+    </composite-id>
+    
+    <property name="name"/>
+    
+    <many-to-one name="order" class="Order"
+            insert="false" update="false">
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </many-to-one>
+    ....
+    
+</class>]]></programlisting>
+
+        <para>
+            Maintenant toutes clés étrangères référençant la table <literal>OrderLine</literal> 
+            devra aussi être composite. Vous devez en tenir compte lorsque vous écrivez vos mapping d'association pour les autres classes.
+            Une association à <literal>OrderLine</literal> devrait être mappé de la façon suivante :
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
+<!-- the "class" attribute is optional, as usual -->
+    <column name="lineId"/>
+    <column name="orderId"/>
+    <column name="customerId"/>
+</many-to-one>]]></programlisting>
+
+        <para>
+            (Remarque: l'élément <literal>&lt;column&gt;</literal> est une alternative à l'attribut 
+            <literal>column</literal> que l'on utilise partout.) 
+        </para>
+        
+        <para>
+            Une association <literal>plusieurs-à-plusieurs</literal> (many-to-many) à <literal>OrderLine</literal> 
+            utilisera aussi une clé étrangère composite:
+        </para>
+    
+    <programlisting><![CDATA[<set name="undeliveredOrderLines">
+    <key column name="warehouseId"/>
+    <many-to-many class="OrderLine">
+        <column name="lineId"/>
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </many-to-many>
+</set>]]></programlisting>
+
+        <para>
+            La collection des <literal>OrderLine</literal>s dans <literal>Order</literal>
+            utilisera:
+        </para>
+
+    <programlisting><![CDATA[<set name="orderLines" inverse="true">
+    <key>
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </key>
+    <one-to-many class="OrderLine"/>
+</set>]]></programlisting>
+
+        <para>
+            (L'élément <literal>&lt;one-to-many&gt;</literal>, comme d'habitude, ne déclare pas de colonne.)
+        </para>
+        
+        <para>
+            Si <literal>OrderLine</literal> lui-même possède une collection, celle-ci aura aussi 
+            une clé composite étrangère.
+        </para>
+
+        <programlisting><![CDATA[<class name="OrderLine">
+    ....
+    ....
+    <list name="deliveryAttempts">
+        <key>   <!-- a collection inherits the composite key type -->
+            <column name="lineId"/>
+            <column name="orderId"/>
+            <column name="customerId"/>
+        </key>
+        <list-index column="attemptId" base="1"/>
+        <composite-element class="DeliveryAttempt">
+            ...
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="components-dynamic" revision="1">
+        <title>Composant Dynamique</title>
+
+        <para>
+            Vous pouvez même mapper une propriété de type <literal>Map</literal>:
+        </para>
+
+    <programlisting><![CDATA[<dynamic-component name="userAttributes">
+    <property name="foo" column="FOO"/>
+    <property name="bar" column="BAR"/>
+    <many-to-one name="baz" class="Baz" column="BAZ_ID"/>
+</dynamic-component>]]></programlisting>
+
+        <para>
+            La sémantique de l'association à un <literal>&lt;dynamic-component&gt;</literal>
+            est identique à celle que l'on utilise pour les composants.
+            L'avantage de ce type de mapping est qu'il pemet de déterminer les véritables propriétés 
+            du bean au moment su déploiement en éditant simplement le document de mapping.
+            La manipulation du document de mapping pendant l'execution de l'application est aussi 
+            possible en utilisant un parser DOM. Il ya même mieux, vous pouvez accéder (et changer)
+            le metamodel de configuration d'hibernate en utilisant l'objet <literal>Configuration</literal>            
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/configuration.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/configuration.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/configuration.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1759 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<chapter id="session-configuration" revision="1">
+
+    <title>Configuration</title>
+    
+    <para>
+        Parce qu'Hibernate est conçu pour fonctionner dans différents environnements,
+        il existe beaucoup de paramètres de configuration. Heureusement, la plupart
+        ont des valeurs par défaut appropriées et la distribution d'Hibernate contient
+        un exemple de fichier <literal>hibernate.properties</literal> dans le répertoire
+        <literal>etc/</literal> qui montre les différentes options. Vous n'avez qu'à 
+        placer ce fichier dans votre classpath et à l'adapter.
+    </para>
+
+    <sect1 id="configuration-programmatic" revision="1">
+        <title>Configuration par programmation</title>
+
+        <para>
+            Une instance de <literal>org.hibernate.cfg.Configuration</literal>
+            représente un ensemble de mappings des classes Java d'une application vers
+            la base de données SQL. La <literal>Configuration</literal> est utilisée
+            pour construire un objet (immuable) <literal>SessionFactory</literal>.
+            Les mappings sont constitués d'un ensemble de fichiers de mapping XML.
+        </para>
+
+        <para>
+            Vous pouvez obtenir une instance de <literal>Configuration</literal>
+            en l'instanciant directement et en spécifiant la liste des documents 
+            XML de mapping. Si les fichiers de mapping sont dans le classpath, vous
+            pouvez le faire à l'aide de la méthode <literal>addResource()</literal> :
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addResource("Item.hbm.xml")
+    .addResource("Bid.hbm.xml");]]></programlisting>
+
+        <para>
+            Une alternative (parfois meilleure)  est de spécifier les classes mappées
+            et de laisser Hibernate trouver les documents de mapping pour vous :
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addClass(org.hibernate.auction.Item.class)
+    .addClass(org.hibernate.auction.Bid.class);]]></programlisting>
+
+        <para>
+            Hibernate va rechercher les fichiers de mappings 
+            <literal>/org/hibernate/auction/Item.hbm.xml</literal> et
+            <literal>/org/hibernate/auction/Bid.hbm.xml</literal> dans le classpath.
+            Cette approche élimine les noms de fichiers en dur.
+        </para>
+        
+        <para>
+            Une <literal>Configuration</literal> vous permet également de préciser des
+            propriétés de configuration :
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addClass(org.hibernate.auction.Item.class)
+    .addClass(org.hibernate.auction.Bid.class)
+    .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
+    .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
+    .setProperty("hibernate.order_updates", "true");]]></programlisting>
+
+        <para>
+            Ce n'est pas le seul moyen de passer des propriétés de configuration à Hibernate.
+            Les différentes options sont :
+        </para>
+
+        <orderedlist spacing="compact">
+            <listitem>
+                <para>
+                    Passer une instance de <literal>java.util.Properties</literal>
+                    à <literal>Configuration.setProperties()</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Placer <literal>hibernate.properties</literal> dans un répertoire racine
+                    du classpath
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Positionner les propriétés <literal>System</literal> en utilisant
+                    <literal>java -Dproperty=value</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Inclure des éléments <literal>&lt;property&gt;</literal> dans le
+                    fichier <literal>hibernate.cfg.xml</literal> (voir plus loin).
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <para>
+            L'utilisation d'<literal>hibernate.properties</literal> est l'approche la plus
+            simple si vous voulez démarrer rapidement
+        </para>
+        <para>
+            La <literal>Configuration</literal> est un objet de démarrage qui sera supprimé
+            une fois qu'une <literal>SessionFactory</literal> aura été créée.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="configuration-sessionfactory">
+        <title>Obtenir une SessionFactory</title>
+
+        <para>
+            Une fois que tous les mappings ont été parsés par la <literal>Configuration</literal>, 
+            l'application doit obtenir une fabrique d'instances de <literal>Session</literal>. 
+            Cette fabrique sera partagée entre tous les threads de l'application :
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sessions = cfg.buildSessionFactory();]]></programlisting>
+
+        <para>
+            Hibernate permet à votre application d'instancier plus d'une <literal>SessionFactory</literal>.
+            Cela est pratique lorsque vous utilisez plus d'une base de données.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-hibernatejdbc" revision="1">
+        <title>Connexions JDBC</title>
+
+        <para>
+            Habituellement, vous voulez que la <literal>SessionFactory</literal> crée les connexions JDBC et
+            les mette dans un pool pour vous. Si vous suivez cette approche, ouvrir une <literal>Session</literal> 
+            est aussi simple que :
+        </para>
+
+        <programlisting><![CDATA[Session session = sessions.openSession(); // open a new Session]]></programlisting>
+        
+        <para>
+            Dès que vous ferez quelquechose qui requiert un accès à la base de données, une connexion
+            JDBC sera récupérée dans le pool.
+        </para>
+
+        <para>
+            Pour faire cela, il faut passer les propriétés de la connexion JDBC à Hibernate.
+            Tous les noms des propriétés Hibernate et leur signification sont définies dans
+            la classe <literal>org.hibernate.cfg.Environment</literal>. Nous allons maintenant
+            décrire les paramètres de configuration des connexions JDBC les plus importants.
+        </para>
+
+         <para>
+            Hibernate obtiendra des connexions (et les mettra dans un pool) en utilisant 
+            <literal>java.sql.DriverManager</literal> si vous positionnez les paramètres de la manière
+            suivante :
+        </para>
+
+        <table frame="topbot">
+            <title>Propriétés JDBC d'Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nom de la propriété</entry>
+                        <entry>Fonction</entry>
+                    </row>
+                </thead>
+            <tbody>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.driver_class</literal>
+                </entry>
+                <entry>
+                    <emphasis>Classe du driver jdbc</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.url</literal>
+                </entry>
+                <entry>
+                    <emphasis>URL jdbc</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.username</literal>
+                </entry>
+                <entry>
+                    <emphasis>utilisateur de la base de données</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.password</literal>
+                </entry>
+                <entry>
+                    <emphasis>mot de passe de la base de données</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.pool_size</literal>
+                </entry>
+                <entry>
+                    <emphasis>nombre maximum de connexions dans le pool</emphasis>
+                </entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+            L'algorithme natif de pool de connexions d'Hibernate est plutôt rudimentaire. Il a été fait 
+            dans le but de vous aider à démarrer et <emphasis>n'est pas prévu pour un système en production</emphasis>
+            ou même pour un test de peformance. Utilisez plutôt un pool tiers pour de meilleures performances et une
+            meilleure stabilité : pour cela, remplacez la propriété <literal>hibernate.connection.pool_size</literal> avec les propriétés
+            spécifique au pool de connexions que vous avez choisi. Cela désactivera le pool de connexions interne
+            d'Hibernate. Vous pouvez par exemple utiliser C3P0.
+        </para>
+
+        <para>
+            C3P0 est un pool de connexions JDBC open source distribué avec Hibernate dans le répertoire
+            <literal>lib</literal>. Hibernate utilisera son provider <literal>C3P0ConnectionProvider</literal>
+            pour le pool de connexions si vous positionnez les propriétés <literal>hibernate.c3p0.*</literal>.
+            Si vous voulez utiliser Proxool, référez vous au groupe de propriétés d'<literal>hibernate.properties</literal>
+            correspondant et regardez sur le site web d'Hibernate pour plus d'informations.
+        </para>
+
+        <para>
+            Voici un exemple de fichier <literal>hibernate.properties</literal> pour C3P0:
+        </para>
+
+        <programlisting id="c3p0-configuration" revision="1"><![CDATA[hibernate.connection.driver_class = org.postgresql.Driver
+hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
+hibernate.connection.username = myuser
+hibernate.connection.password = secret
+hibernate.c3p0.min_size=5
+hibernate.c3p0.max_size=20
+hibernate.c3p0.timeout=1800
+hibernate.c3p0.max_statement=50
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+        <para>
+            Dans le cadre de l'utilisation au sein d'un serveur d'applications,
+            vous devriez quasiment toujours configurer Hibernate pour qu'il obtienne
+            ses connexions de la <literal>DataSource</literal> du serveur d'application
+            enregistrée dans le JNDI. Pour cela vous devrez définir au moins une des
+            propriétés suivantes :
+        </para>
+
+        <table frame="topbot">
+            <title>Propriété d'une Datasource Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nom d'une propriété</entry>
+                        <entry>fonction</entry>
+                    </row>
+                </thead>
+            <tbody>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.datasource</literal>
+                </entry>
+                <entry>
+                    <emphasis>Nom JNDI de la datasource</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.jndi.url</literal>
+                </entry>
+                <entry>
+                    <emphasis>URL du fournisseur JNDI</emphasis> (optionnelle)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.jndi.class</literal>
+                </entry>
+                <entry>
+                    <emphasis>Classe de l'<literal>InitialContextFactory</literal> du JNDI</emphasis> (optionnelle)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.username</literal>
+                </entry>
+                <entry>
+                    <emphasis>utilisateur de la base de données</emphasis> (optionnelle)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.password</literal>
+                </entry>
+                <entry>
+                    <emphasis>mot de passe de la base de données</emphasis> (optionnelle)
+                </entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+            Voici un exemple de fichier <literal>hibernate.properties</literal>
+            pour l'utilisation d'une datasource JNDI fournie par un serveur d'applications :
+        </para>
+
+        <programlisting><![CDATA[hibernate.connection.datasource = java:/comp/env/jdbc/test
+hibernate.transaction.factory_class = \
+    org.hibernate.transaction.JTATransactionFactory
+hibernate.transaction.manager_lookup_class = \
+    org.hibernate.transaction.JBossTransactionManagerLookup
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+        <para>
+            Les connexions JDBC obtenues à partir d'une datasource JNDI participeront automatiquement
+            aux transactions gérées par le conteneur du serveur d'applications.
+        </para>
+
+        <para>
+            Des propriétés supplémentaires de connexion peuvent être passées en préfixant
+            le nom de la propriété par "<literal>hibernate.connnection</literal>". Par exemple,
+            vous pouvez spécifier un jeu de caractères en utilisant 
+            <literal>hibernate.connection.charSet</literal>.
+        </para>
+
+        <para>
+            Vous pouvez fournir votre propre stratégie d'obtention des connexions JDBC en implémentant l'interface
+            <literal>org.hibernate.connection.ConnectionProvider</literal>. Vous pouvez sélectionner
+            une implémentation spécifique en positionnant <literal>hibernate.connection.provider_class</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-optional" revision="1">
+        <title>Propriétés de configuration optionnelles</title>
+        
+        <para>
+            Il y a un certain nombre d'autres propriétés qui contrôlent le fonctionnement 
+            d'Hibernate à l'exécution. Toutes sont optionnelles et ont comme valeurs par défaut
+            des valeurs "raisonnables" pour un fonctionnement nominal.
+        </para>
+
+        <para>
+            <emphasis>Attention : Certaines de ces propriétés sont uniquement de niveau System.</emphasis>
+            Les propriétés de niveau System ne peuvent être positionnées que via la ligne de commande
+            (<literal>java -Dproperty=value</literal>) ou être définies dans <literal>hibernate.properties</literal>.
+            Elle <emphasis>ne peuvent pas</emphasis> l'être via une des autres techniques décrites ci-dessus.
+        </para>
+
+        <table frame="topbot" id="configuration-optional-properties" revision="8">
+            <title>Propriétés de configuration d'Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nom de la propriété</entry>
+                        <entry>Fonction</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.dialect</literal>
+                        </entry>
+                        <entry>
+                            Le nom de la classe du <literal>Dialect</literal> Hibernate.
+                            qui permet à Hibernate de générer du SQL optimisé pour une
+                            base de données relationnelle particulière.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>nom.complet.de.ma.classe.de.Dialect</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.show_sql</literal>
+                        </entry>
+                        <entry>
+                            Ecrit toutes les requêtes SQL sur la console. Il s'agit d'une
+                            alternative au positionnement de la catégorie de log
+                            <literal>org.hibernate.SQL</literal> au niveau <literal>debug</literal>.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.format_sql</literal>
+                        </entry>
+                        <entry>
+                            Formate et indente le sql dans la console et dans le log
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_schema</literal>
+                        </entry>
+                        <entry>
+                            Positionne dans le SQL généré un schéma/tablespace par défaut pour les noms de
+                            table ne l'ayant pas surchargé.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>MON_SCHEMA</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_catalog</literal>
+                        </entry>
+                        <entry>
+                            Qualifie les noms de tables non qualifiées avec ce catalogue
+                            dans le SQL généré.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>CATALOG_NAME</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.session_factory_name</literal>
+                        </entry>
+                        <entry>
+                            La <literal>SessionFactory</literal> sera automatiquement
+                            liée à ce nom dans le JNDI après sa création.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>jndi/nom/hierarchique</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.max_fetch_depth</literal>
+                        </entry>
+                        <entry>
+                            Définit la profondeur maximale d'un arbre de chargement par
+                            jointures ouvertes pour les associations à cardinalité unitaire
+                            (un-à-un, plusieurs-à-un).
+                            Un <literal>0</literal> désactive le chargement par jointure
+                            ouverte.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                valeurs recommandées entre <literal>0</literal> et <literal>3</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_batch_fetch_size</literal>
+                        </entry>
+                        <entry>
+                            Définit une taille par défaut pour le chargement par lot des associations
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                Valeurs recommandées : <literal>4</literal>, <literal>8</literal>, 
+                                <literal>16</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_entity_mode</literal>
+                        </entry>
+                        <entry>
+                            Définit un mode de représentation par défaut des entités pour
+                            toutes les sessions ouvertes depuis cette <literal>SessionFactory</literal>
+                            <para>
+                                <literal>dynamic-map</literal>, <literal>dom4j</literal>,
+                                <literal>pojo</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.order_updates</literal>
+                        </entry>
+                        <entry>
+                            Force Hibernate à trier les updates SQL par la valeur de la clé
+                            primaire des éléments qui sont mis à jour. Cela permet de limiter
+                            les deadlocks de transaction dans les systèmes hautement concurents.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.generate_statistics</literal>
+                        </entry>
+                        <entry>
+                            Si activé, Hibernate va collecter des statistiques utiles
+                            pour le réglage des performances.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.use_identifer_rollback</literal>
+                        </entry>
+                        <entry>
+                            Si activé, les propriétés correspondant à l'identifiant
+                            des objets vont être remises aux valeurs par défaut lorsque
+                            les objets seront supprimés.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.use_sql_comments</literal>
+                        </entry>
+                        <entry>
+                            Si activé, Hibernate va générer des commentaires à l'intérieur
+                            des requêtes SQL pour faciliter le debogage., par défaut à <literal>false</literal>.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+         <table frame="topbot" id="configuration-jdbc-properties" revision="8">
+            <title>Propriétés Hibernate liées à JDBC et aux connexions</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nom de la propriété</entry>
+                        <entry>Fonction</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.fetch_size</literal>
+                        </entry>
+                        <entry>
+                            Une valeur non nulle détermine la taille de chargement
+                            des statements JDBC (appelle 
+                            <literal>Statement.setFetchSize()</literal>).
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.batch_size</literal>
+                        </entry>
+                        <entry>
+                            Une valeur non nulle active l'utilisation par Hibernate des mises 
+                            à jour par batch de JDBC2.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                les valeurs recommandées entre <literal>5</literal> et <literal>30</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.batch_versioned_data</literal>
+                        </entry>
+                        <entry>
+                            Paramétrez cette propriété à <literal>true</literal> si votre pilote JDBC
+                            retourne des row counts corrects depuis <literal>executeBatch()</literal> (il est 
+                            souvent approprié d'activer cette option). Hibernate utilisera alors le "batched DML" pour
+                            versionner automatiquement les données. Par défaut = <literal>false</literal>.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.factory_class</literal>
+                        </entry>
+                        <entry>
+                           Sélectionne un <literal>Batcher</literal> personnalisé. La
+                           plupart des applications n'auront pas besoin de cette propriété
+                           de configuration
+                            <para>
+                                <emphasis role="strong">ex.</emphasis>
+                                <literal>classname.of.Batcher</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_scrollable_resultset</literal>
+                        </entry>
+                        <entry>
+                            Active l'utilisation par Hibernate des resultsets scrollables 
+                            de JDBC2. Cette propriété est seulement nécessaire lorsque l'on
+                            utilise une connexion JDBC fournie par l'utilisateur. Autrement,
+                            Hibernate utilise les métadonnées de la connexion.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_streams_for_binary</literal>
+                        </entry>
+                        <entry>
+                            Utilise des flux lorsque l'on écrit/lit des types
+                            <literal>binary</literal> ou <literal>serializable</literal>
+                            vers et à partir de JDBC (propriété de niveau système).
+                            <para>
+                                <emphasis role="strong">ex.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_get_generated_keys</literal>
+                        </entry>
+                        <entry>
+                            Active l'utilisation de <literal>PreparedStatement.getGeneratedKeys()</literal> de JDBC3
+                            pour récupérer nativement les clés générées après insertion. Nécessite un pilote
+                            JDBC3+, le mettre à false si votre pilote a des problèmes avec les générateurs
+                            d'identifiant Hibernate. Par défaut, essaie de déterminer les possibilités du
+                            pilote en utilisant les meta données de connexion.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>                    
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.provider_class</literal>
+                        </entry>
+                        <entry>
+                            Le nom de la classe d'un <literal>ConnectionProvider</literal> personnalisé
+                            qui fournit des connexions JDBC à Hibernate
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>classname.of.ConnectionProvider</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                    <entry>
+                        <literal>hibernate.connection.isolation</literal>
+                    </entry>
+                    <entry>
+                        Définit le niveau d'isolation des transactions JDBC. Regardez
+                        <literal>java.sql.Connection</literal> pour connaître le
+                        sens des différentes valeurs mais notez également que la plupart
+                        des bases de données ne supportent pas tous les niveaux d'isolation.
+                        <para>
+                            <emphasis role="strong">ex.</emphasis> 
+                            <literal>1, 2, 4, 8</literal>
+                        </para>
+                    </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.autocommit</literal>
+                        </entry>
+                        <entry>
+                            Active le mode de commit automatique (autocommit) pour les connexions
+                            JDBC du pool (non recommandé).
+                            <para>
+                                <emphasis role="strong">ex.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.release_mode</literal>
+                        </entry>
+                        <entry>
+                            Spécifie à quel moment Hibernate doit relacher les connexion JDBC.
+                            Par défaut une connexion JDBC est conservée jusqu'à ce que la session
+                            soit explicitement fermée ou déconnectée. Pour une source de données
+                            JTA d'un serveur d'application, vous devriez utiliser <literal>after_statement</literal>
+                            pour libérer les connexions de manière plus agressive après chaque appel
+                            JDBC. Pour une connexion non JTA, il est souvent préférable de libérer
+                            la connexion à la fin de chaque transaction en utilisant <literal>after_transaction</literal>.
+                            <literal>auto</literal> choisira <literal>after_statement</literal> pour
+                            des transactions JTA et CMT et <literal>after_transaction</literal> pour
+                            des transactions JDBC.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>on_close</literal> (default) | <literal>after_transaction</literal> |
+                                <literal>after_statement</literal> | <literal>auto</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                    <entry>
+                        <literal>hibernate.connection.<emphasis>&lt;propertyName&gt;</emphasis></literal>
+                    </entry>
+                    <entry>
+                        Passe la propriété JDBC<literal>propertyName</literal>
+                        à <literal>DriverManager.getConnection()</literal>.
+                    </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jndi.<emphasis>&lt;propertyName&gt;</emphasis></literal>
+                        </entry>
+                        <entry>
+                           Passe la propriété <literal>propertyName</literal> à l'<literal>InitialContextFactory</literal>
+                           de JNDI.
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-cache-properties" revision="7">
+            <title>Propriétés du Cache d'Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nom de la propriété</entry>
+                        <entry>Fonction</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.provider_class</literal>
+                        </entry>
+                        <entry>
+                            Le nom de classe d'un <literal>CacheProvider</literal> 
+                            spécifique.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>nom.de.classe.du.CacheProvider</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_minimal_puts</literal>
+                        </entry>
+                        <entry>
+                            Optimise le cache de second niveau en minimisant les écritures,
+                            au prix de plus de lectures. Ce paramètre est surtout utile pour
+                            les caches en cluster et est activé par défaut dans hibernate3
+                            pour les implémentations de cache en cluster.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_query_cache</literal>
+                        </entry>
+                        <entry>
+                            Activer le cache de requête, les requêtes individuelles doivent tout
+                            de même être déclarées comme pouvant être mise en cache.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_second_level_cache</literal>
+                        </entry>
+                        <entry>
+                            Peut être utilisé pour désactiver complètement le cache de second niveau
+                            qui est activé par défaut pour les classes qui spécifient un élément
+                            <literal>&lt;cache&gt;</literal> dans leur mapping.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.query_cache_factory</literal>
+                        </entry>
+                        <entry>
+                            Le nom de classe d'une interface <literal>QueryCacheFactory</literal> ,
+                            par défaut = built-in <literal>StandardQueryCacheFactory</literal>.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis>
+                                <literal>nom.de.la.classe.de.QueryCacheFactory</literal>
+                            </para>
+                        </entry>
+                    </row>
+
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.region_prefix</literal>
+                        </entry>
+                        <entry>
+                            Un préfixe à utiliser pour le nom des régions du 
+                            cache de second niveau.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>prefix</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_structured_entries</literal>
+                        </entry>
+                        <entry>
+                            Force Hibernate à stocker les données dans le cache de
+                            second niveau dans un format plus adapté à la visualisation
+                            par un humain.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis>
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-transaction-properties" revision="9">
+            <title>Propriétés des transactions Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nom de la propriété</entry>
+                        <entry>Fonction</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.factory_class</literal>
+                        </entry>
+                        <entry>
+                            Le nom de classe d'une <literal>TransactionFactory</literal>
+                            qui sera utilisée par l'API <literal>Transaction</literal>
+                            d'Hibernate (la valeur par défaut est 
+                            <literal>JDBCTransactionFactory</literal>).
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>nom.de.classe.d.une.TransactionFactory</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>jta.UserTransaction</literal>
+                        </entry>
+                        <entry>
+                            Le nom JNDI utilisé par la <literal>JTATransactionFactory</literal>
+                            pour obtenir la <literal>UserTransaction</literal> JTA du serveur 
+                            d'applications.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>jndi/nom/compose</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.manager_lookup_class</literal>
+                        </entry>
+                        <entry>
+                            Le nom de la classe du <literal>TransactionManagerLookup</literal>
+                            - requis lorsque le cache de niveau JVM est activé ou lorsque l'on
+                            utilise un générateur hilo dans un environnement JTA.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>nom.de.classe.du.TransactionManagerLookup</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.flush_before_completion</literal>
+                        </entry>
+                        <entry>
+                            Si activé, la session sera automatiquement vidée durant la phase
+                            qui précède la fin de la transaction (before completion). 
+                            La gestion automatique de contexte fourni par Hibernate est
+                            recommandée, voir
+                            <xref linkend="architecture-current-session"/>.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.auto_close_session</literal>
+                        </entry>
+                        <entry>
+                            Si activé, la session sera automatiquement fermé pendant la phase 
+                            qui suit la fin de la transaction (after completion). 
+                            La gestion automatique de contexte fourni par Hibernate est
+                            recommandée, voir
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-misc-properties" revision="9">
+            <title>Propriétés diverses</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nom de la propriété</entry>
+                        <entry>Fonction</entry>
+                    </row>
+                </thead>
+                <tbody>
+                     <row>
+                        <entry>
+                            <literal>hibernate.current_session_context_class</literal>
+                        </entry>
+                        <entry>
+                            Fournit une stratégie particulière pour contextualiser
+                            la <literal>Session</literal> courante. Voir
+                            <xref linkend="architecture-current-session"/> pour plus
+                            d'informations sur les stratégies fournies.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>jta</literal> | <literal>thread</literal> |
+                                <literal>custom.Class</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.query.factory_class</literal>
+                        </entry>
+                        <entry>
+                            Choisi l'implémentation du parseur de requête
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> ou
+                                <literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.query.substitutions</literal>
+                        </entry>
+                        <entry>
+                            Lien entre les tokens de requêtes Hibernate et les 
+                            tokens SQL (les tokens peuvent être des fonctions ou des
+                            noms littéraux par exemple).
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.hbm2ddl.auto</literal>
+                        </entry>
+                        <entry>
+                            Valide ou exporte  automatiquement le schéma DDL vers la base de données
+                            lorsque la <literal>SessionFactory</literal> est créée.
+                            La valeur <literal>create-drop</literal> permet de supprimer 
+                            le schéma de base de données lorsque la <literal>SessionFactory</literal>
+                            est fermée explicitement.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>validate</literal> | <literal>update</literal> | 
+                                <literal>create</literal> | <literal>create-drop</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cglib.use_reflection_optimizer</literal>
+                        </entry>
+                        <entry>
+                            Active l'utilisation de CGLIB à la place de la réflexion à l'exécution
+                            (Propriété de niveau système). La réflexion peut parfois être utile pour
+                            résoudre des problèmes. Notez qu'Hibernate a tout de même toujours besoin
+                            de CGLIB même si l'optimiseur est désactivé. Cette optimisation ne peut être
+                            définie que dans le fichier <literal>hibernate.cfg.xml</literal>.
+                            <para>
+                                <emphasis role="strong">ex.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <sect2 id="configuration-optional-dialects" revision="1">
+            <title>Dialectes SQL</title>
+
+            <para>
+                Vous devriez toujours positionner la propriété <literal>hibernate.dialect</literal> à
+                la sous-classe de <literal>org.hibernate.dialect.Dialect</literal> appropriée à 
+                votre base de données. Si vous spécifiez un dialecte,
+                Hibernate utilisera des valeurs adaptées pour certaines autres
+                propriétés listées ci-dessus, vous évitant l'effort de le faire à la main.
+            </para>
+
+            <table frame="topbot" id="sql-dialects" revision="2">
+                <title>Dialectes SQL d'Hibernate (<literal>hibernate.dialect</literal>)</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>SGBD</entry>
+                            <entry>Dialecte</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry>DB2</entry> <entry><literal>org.hibernate.dialect.DB2Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>DB2 AS/400</entry> <entry><literal>org.hibernate.dialect.DB2400Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>DB2 OS390</entry> <entry><literal>org.hibernate.dialect.DB2390Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>PostgreSQL</entry> <entry><literal>org.hibernate.dialect.PostgreSQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL</entry> <entry><literal>org.hibernate.dialect.MySQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL with InnoDB</entry> <entry><literal>org.hibernate.dialect.MySQLInnoDBDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL with MyISAM</entry> <entry><literal>org.hibernate.dialect.MySQLMyISAMDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Oracle (any version)</entry> <entry><literal>org.hibernate.dialect.OracleDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Oracle 9i/10g</entry> <entry><literal>org.hibernate.dialect.Oracle9Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Sybase</entry> <entry><literal>org.hibernate.dialect.SybaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Sybase Anywhere</entry> <entry><literal>org.hibernate.dialect.SybaseAnywhereDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Microsoft SQL Server</entry> <entry><literal>org.hibernate.dialect.SQLServerDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>SAP DB</entry> <entry><literal>org.hibernate.dialect.SAPDBDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Informix</entry> <entry><literal>org.hibernate.dialect.InformixDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>HypersonicSQL</entry> <entry><literal>org.hibernate.dialect.HSQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Ingres</entry> <entry><literal>org.hibernate.dialect.IngresDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Progress</entry> <entry><literal>org.hibernate.dialect.ProgressDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Mckoi SQL</entry> <entry><literal>org.hibernate.dialect.MckoiDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Interbase</entry> <entry><literal>org.hibernate.dialect.InterbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Pointbase</entry> <entry><literal>org.hibernate.dialect.PointbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>FrontBase</entry> <entry><literal>org.hibernate.dialect.FrontbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Firebird</entry> <entry><literal>org.hibernate.dialect.FirebirdDialect</literal></entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-outerjoin" revision="4">
+            <title>Chargement par Jointure Ouverte</title>
+
+            <para>
+                Si votre base de données supporte les outer joins de type ANSI, Oracle ou Sybase, 
+                <emphasis>le chargement par jointure ouverte</emphasis> devrait améliorer les 
+                performances en limitant le nombre d'aller-retour avec la base de données (la
+                base de données effectuant donc potentiellement plus de travail). Le chargement par
+                jointure ouverte permet à un graphe entier d'objets connectés par une relation plusieurs-à-un,
+                un-à-plusieurs ou un-à-un d'être chargé en un seul <literal>SELECT</literal> SQL.
+            </para>
+
+            <para>
+                Le chargement par jointure ouverte peut être désactiver <emphasis>globalement</emphasis>
+                en mettant la propriété <literal>hibernate.max_fetch_depth</literal> à <literal>0</literal>.
+                Une valeur de <literal>1</literal> ou plus active le chargement par jointure ouverte
+                pour les associatiosn un-à-un et plusieurs-à-un qui ont été mappée avec
+                <literal>fetch="join"</literal>.
+            </para>
+
+            <para>
+                Reportez vous à <xref linkend="performance-fetching"/> pour plus d'information.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-binarystreams" revision="1">
+            <title>Flux binaires</title>
+
+            <para>
+                Oracle limite la taille d'un tableau de <literal>byte</literal> qui peuvent être
+                passées à et vers son pilote JDBC. Si vous souhaitez utiliser des instances larges
+                de type <literal>binary</literal> ou <literal>serializable</literal>, vous devez activer
+                la propriété <literal>hibernate.jdbc.use_streams_for_binary</literal>. <emphasis>C'est une 
+                fonctionalité de niveau système uniquement.</emphasis>
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-cacheprovider" revision="2">
+            <title>Cache de second niveau et cache de requêtes</title>
+
+            <para>
+                Les propriétés préfixées par <literal>hibernate.cache</literal>
+                vous permettent d'utiliser un système de cache de second niveau. Ce cache
+                peut avoir une portée dans le processus ou même être utilisable dans un
+                système distribué. Référez vous au chapitre <xref linkend="performance-cache"/> 
+                pour plus de détails.
+            </para>
+
+        </sect2>
+        
+        <sect2 id="configuration-optional-querysubstitution">
+            <title>Substitution dans le langage de requêtage</title>
+
+            <para>
+                Vous pouvez définir de nouveaux tokens dans les requêtes Hibernate en utilisant la propriété
+                <literal>hibernate.query.substitutions</literal>. Par exemple :
+            </para>
+
+            <programlisting>hibernate.query.substitutions vrai=1, faux=0</programlisting>
+
+            <para>
+                remplacerait les tokens <literal>vrai</literal> et <literal>faux</literal> par
+                des entiers dans le SQL généré.
+            </para>
+
+            <programlisting>hibernate.query.substitutions toLowercase=LOWER</programlisting>
+
+            <para>
+                permettrait de renommer la fonction SQL <literal>LOWER</literal> en <literal>toLowercase</literal>
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-statistics" revision="2">
+            <title>Statistiques Hibernate</title>
+
+            <para>
+                Si vous activez <literal>hibernate.generate_statistics</literal>, Hibernate va
+                fournir un certains nombre de métriques utiles pour régler les performances
+                d'une application qui tourne via <literal>SessionFactory.getStatistics()</literal>.
+                Hibernate peut aussi être configuré pour exposer ces statistiques via JMX.
+                Lisez les Javadoc des interfaces dans le package
+                <literal>org.hibernate.stats</literal> pour plus d'informations.
+            </para>
+
+        </sect2>
+    </sect1>
+
+    <sect1 id="configuration-logging">
+        <title>Tracer</title>
+
+        <para>
+            Hibernate trace divers évènements en utilisant Apache commons-logging.
+        </para>
+
+        <para>
+            Le service commons-logging délèguera directement à Apache Log4j
+            (si vous incluez <literal>log4j.jar</literal> dans votre classpath)
+            ou le système de trace du JDK 1.4 (si vous tournez sous le JDK 1.4
+            et supérieur). Vous pouvez télécharger Log4j à partir de
+            <literal>http://jakarta.apache.org</literal>. Pour utiliser Log4j,
+            vous devrez placer dans votre classpath un fichier 
+            <literal>log4j.properties</literal>. Un exemple de fichier est distribué
+            avec Hibernate dans le répertoire <literal>src/</literal>.
+        </para>
+        
+        <para>
+            Nous vous recommandons fortement de vous familiariser avec les messages des traces 
+            d'Hibernate. Beaucoup de soins a été apporté pour donner le plus de détails
+            possible sans les rendre illisibles. C'est un outil essentiel en cas de soucis.
+            Les catégories de trace les plus intéressantes sont les suivantes :
+        </para>
+        
+            <table frame="topbot" id="log-categories" revision="2">
+                <title>Catégories de trace d'Hibernate</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>Catégorie</entry>
+                            <entry>Fonction</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>org.hibernate.SQL</literal></entry>
+                            <entry>Trace toutes les requêts SQL de type DML (gestion des données) qui sont exécutées</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.type</literal></entry>
+                            <entry>Trace tous les paramètres JDBC</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.tool.hbm2ddl</literal></entry>
+                            <entry>Trace toutes les requêts SQL de type DDL (gestion de la structure de la base) qui sont exécutées</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.pretty</literal></entry>
+                            <entry>
+                                Trace l'état de toutes les entités (20 entités maximum) qui
+                                sont associées avec la session hibernate au moment du flush
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.cache</literal></entry>
+                            <entry>Trace toute l'activité du cache de second niveau</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction</literal></entry>
+                            <entry>Trace toute l'activité relative aux transactions</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.jdbc</literal></entry>
+                            <entry>Trace toute acquisition de ressource JDBC</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.hql.ast.AST</literal></entry>
+                            <entry>
+                                Trace l'arbre syntaxique des requêtes HQL et SQL durant l'analyse syntaxique des requêtes
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.secure</literal></entry>
+                            <entry>Trace toutes les demandes d'autorisation JAAS</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate</literal></entry>
+                            <entry>
+                                Trace tout (beaucoupe d'informations, mais très utile pour résoudre les problèmes).
+                            </entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+            
+        <para>
+            Lorsque vous développez des applications avec Hibernate, vous devriez quasiment toujours
+            travailler avec le niveau <literal>debug</literal> activé pour la catégorie
+            <literal>org.hibernate.SQL</literal>, ou sinon avec la propriété 
+            <literal>hibernate.show_sql</literal> activée.
+        </para>
+                       
+        
+    </sect1>
+
+    <sect1 id="configuration-namingstrategy">
+        <title>Implémenter une <literal>NamingStrategy</literal></title>
+
+        <para>
+            L'interface <literal>org.hibernate.cfg.NamingStrategy</literal> vous permet de
+            spécifier une "stratégie de nommage" des objets et éléments de la base de données.
+        </para>
+
+        <para>
+            Vous pouvez fournir des règles pour automatiquement générer les identifiants
+            de base de données à partir des identifiants Java, ou transformer une colonne
+            ou table "logique" donnée dans le fichier de mapping en une colonne ou table
+            "physique". Cette fonctionnalité aide à réduire la verbosité de documents
+            de mapping, en éliminant le bruit répétitif (les préfixes <literal>TBL_</literal>
+            par exemple). La stratégie par défaut utilisée par Hibernate est minimale.
+        </para>
+
+        <para>
+            Vous pouvez définir une stratégie différente en appelant
+            <literal>Configuration.setNamingStrategy()</literal> avant d'ajouter des
+            mappings :
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sf = new Configuration()
+    .setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
+    .addFile("Item.hbm.xml")
+    .addFile("Bid.hbm.xml")
+    .buildSessionFactory();]]></programlisting>
+    
+        <para>
+            <literal>net.sf.hibernate.cfg.ImprovedNamingStrategy</literal> est une 
+            stratégie fournie qui peut être utile comme point de départ de quelques
+            applications.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-xmlconfig" revision="2">
+        <title>Fichier de configuration XML</title>
+
+        <para>
+            Une approche alternative est de spécifier toute la configuration dans un
+            fichier nommé <literal>hibernate.cfg.xml</literal>. Ce fichier peut être 
+            utilisé à la place du fichier <literal>hibernate.properties</literal>, voire
+            même peut servir à surcharger les propriétés si les deux fichiers sont présents.
+        </para>
+
+        <para>
+            Le fichier de configuration XML doit par défaut se placer à la racine
+            du <literal>CLASSPATH</literal>. En voici un exemple :
+        </para>
+
+        <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+    "-//Hibernate/Hibernate Configuration DTD//EN"
+    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <!-- a SessionFactory instance listed as /jndi/name -->
+    <session-factory
+        name="java:hibernate/SessionFactory">
+
+        <!-- properties -->
+        <property name="connection.datasource">java:/comp/env/jdbc/MyDB</property>
+        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
+        <property name="show_sql">false</property>
+        <property name="transaction.factory_class">
+            org.hibernate.transaction.JTATransactionFactory
+        </property>
+        <property name="jta.UserTransaction">java:comp/UserTransaction</property>
+
+        <!-- mapping files -->
+        <mapping resource="org/hibernate/auction/Item.hbm.xml"/>
+        <mapping resource="org/hibernate/auction/Bid.hbm.xml"/>
+
+        <!-- cache settings -->
+        <class-cache class="org.hibernate.auction.Item" usage="read-write"/>
+        <class-cache class="org.hibernate.auction.Bid" usage="read-only"/>
+        <collection-cache collection="org.hibernate.auction.Item.bids" usage="read-write"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+       <para>
+          Commme vous pouvez le voir, l'avantage de cette approche est l'externalisation
+          des noms des fichiers de mapping de la configuration. Le fichier <literal>hibernate.cfg.xml</literal>
+          est également plus pratique quand on commence à régler le cache d'Hibernate. Notez
+          que vous pouvez choisir entre utiliser <literal>hibernate.properties</literal> ou
+          <literal>hibernate.cfg.xml</literal>, les deux sont équivalents, sauf en ce qui
+          concerne les bénéfices de l'utilisation de la syntaxe XML mentionnés ci-dessus.
+       </para>
+ 
+       <para>
+           Avec la configuration XML, démarrer Hibernate devient donc aussi simple que ceci :
+       </para>
+
+       <programlisting><![CDATA[SessionFactory sf = new Configuration().configure().buildSessionFactory();]]></programlisting>
+
+
+
+    </sect1>
+
+    <sect1 id="configuration-j2ee" revision="1">
+        <title>Intégration à un serveur d'application J2EE</title>
+
+        <para>
+            Hibernate possède les points suivants d'intégration à l'infrastructure J2EE :
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>Source de données gérée par le conteneur</emphasis> : Hibernate peut
+                utiliser des connexions JDBC gérées par le conteneur et fournie par l'intermédiaire
+                de JNDI. Souvent, un <literal>TransactionManager</literal> compatible JTA
+                et un <literal>ResourceManager</literal> s'occupent de la gestion des transactions (CMT).
+                Ils sont particulièrement prévus pour pouvoir gérer des transactions distribuées
+                sur plusieurs sources de données. Vous pouvez bien sûr également définir vos
+                limites de transaction dans votre programme (BMT) ou vous pouvez sinon aussi
+                utiliser l'API optionnelle <literal>Transaction</literal> d'Hibernate qui vous garantira
+                la portabilité de votre code entre plusieurs serveurs d'application.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>Association JNDI automatique</emphasis>: Hibernate peut associer sa
+                <literal>SessionFactory</literal> à JNDI après le démarrage.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>Association de la Session à JTA:</emphasis> La <literal>Session</literal> Hibernate
+                peut être associée automatiquement à une transaction JTA si vous utilisez les EJBs.
+                Vous avez juste à récupérer la <literal>SessionFactory</literal> depuis JNDI et
+                à récupérer la <literal>Session</literal> courante. Hibernate s'occupe de vider et
+                fermer la <literal>Session</literal> lorsque le transaction JTA se termine. La
+                démarcation des transactions se fait de manière déclarative dans les descripteurs de déploiement.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>Déploiement JMX :</emphasis>Si vous avez un serveur d'application compatible JMX
+                (JBoss AS par exemple), vous pouvez choisir de déployer Hibernate en temps que MBean géré par
+                le serveur. Cela vous évite de coder la ligne de démarrage qui permet de construire
+                la <literal>SessionFactory</literal> depuis la <literal>Configuration</literal>.
+                Le conteneur va démarrer votre <literal>HibernateService</literal>, et va idéalement
+                s'occuper des dépendances entre les services (la source de données doit être disponible
+                avant qu'Hibernate ne démarre, etc).
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            En fonction de votre environnement, vous devrez peut être mettre l'option de 
+            configuration <literal>hibernate.connection.aggressive_release</literal> à vrai si
+            le serveur d'application affiche des exceptions de type "connection containment".
+        </para>
+
+        <sect2 id="configuration-optional-transactionstrategy" revision="3">
+            <title>Configuration de la stratégie transactionnelle</title>
+
+            <para>
+                L'API de la <literal>Session</literal> Hibernate est indépendante de tout système
+                de démarcation des transactions qui peut être présent dans votre architecture. Si
+                vous laissez Hibernate utiliser l'API JDBC directement via un pool de connexion, vous
+                devrez commencer et terminer vos transactions en utilisant l'API JDBC. Si votre
+                application tourne à l'intérieur d'un serveur d'application J2EE, vous voudrez peut être
+                utiliser les transactions gérées par les beans (BMT) et appeller l'API JTA et 
+                <literal>UserTransaction</literal> lorsque cela est nécessaire.
+            </para>
+            <para>
+                Pour conserver votre code portable entre ces deux environnements (et d'autres éventuels)
+                nous vous recommandons d'utiliser l'API optionnelle <literal>Transaction</literal> d'Hibernate,
+                qui va encapsuler et masquer le système de transaction sous-jacent.
+                Pour cela, vous devez préciser une classe de fabrique d'instances de <literal>Transaction</literal>
+                en positionnant la propriété
+                <literal>hibernate.transaction.factory_class</literal>.
+            </para>
+
+            <para>
+                Il existe trois choix standards (fournis) :
+            </para>
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term><literal>net.sf.hibernate.transaction.JDBCTransactionFactory</literal></term>
+                    <listitem>
+                        <para>délègue aux transactions de la base de données (JDBC). Valeur par défaut.</para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.JTATransactionFactory</literal></term>
+                    <listitem>
+                        <para>
+                            délègue à CMT si une transaction existante est sous ce contexte (ex: méthode
+                            d'un EJB session), sinon une nouvelle transaction est entamée et
+                            une transaction gérée par le bean est utilisée.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.CMTTransactionFactory</literal></term>
+                    <listitem>
+                        <para>délègue à aux transactions JTA gérées par le conteneur</para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+            <para>
+                Vous pouvez également définir votre propre stratégie transactionnelle
+                (pour un service de transaction CORBA par exemple).
+            </para>
+
+            <para>
+                Certaines fonctionnalités d'Hibernate (i.e. le cache de second niveau, l'association
+                automatique des Session à JTA, etc.) nécessitent l'accès au <literal>TransactionManager</literal>
+                JTA dans un environnement "managé". Dans un serveur d'application, vous devez indiquer
+                comment Hibernate peut obtenir une référence vers le <literal>TransactionManager</literal>,
+                car J2EE ne fournit pas un seul mécanisme standard.
+            </para>
+
+            <table frame="topbot" id="jtamanagerlookup" revision="1">
+                <title>TransactionManagers JTA</title>
+                <tgroup cols="2">
+                    <colspec colwidth="2.5*"/>
+                    <colspec colwidth="1*"/>
+                    <thead>
+                        <row>
+                            <entry>Fabrique de Transaction</entry>
+                            <entry align="center">Serveur d'application</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JBossTransactionManagerLookup</literal></entry>
+                            <entry align="center">JBoss</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WeblogicTransactionManagerLookup</literal></entry>
+                            <entry align="center">Weblogic</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WebSphereTransactionManagerLookup</literal></entry>
+                            <entry align="center">WebSphere</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</literal></entry>
+                            <entry align="center">WebSphere 6</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.OrionTransactionManagerLookup</literal></entry>
+                            <entry align="center">Orion</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.ResinTransactionManagerLookup</literal></entry>
+                            <entry align="center">Resin</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JOTMTransactionManagerLookup</literal></entry>
+                            <entry align="center">JOTM</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JOnASTransactionManagerLookup</literal></entry>
+                            <entry align="center">JOnAS</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JRun4TransactionManagerLookup</literal></entry>
+                            <entry align="center">JRun4</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.BESTransactionManagerLookup</literal></entry>
+                            <entry align="center">Borland ES</entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-jndi" revision="3">
+            <title><literal>SessionFactory</literal> associée au JNDI</title>
+
+            <para>
+                Une <literal>SessionFactory</literal> Hibernate associée au JNDI peut 
+                simplifier l'accès à la fabrique et donc la création de nouvelles
+                <literal>Session</literal>s. Notez que cela n'est pas lié avec les <literal>Datasource</literal>
+                associées au JNDI, elles utilisent juste le même registre.
+            </para>
+
+            <para>
+                Si vous désirez associer la <literal>SessionFactory</literal> à un nom JNDI,
+                spécifiez un nom (ex. <literal>java:hibernate/SessionFactory</literal>) en
+                utilisant la propriété <literal>hibernate.session_factory_name</literal>.
+                Si cette propriété est omise, la <literal>SessionFactory</literal> ne sera pas
+                associée au JNDI (c'est particulièrement pratique dans les environnements ayant une
+                implémentation de JNDI en lecture seule, comme c'est le cas pour Tomcat).
+            </para>
+
+            <para>
+                Lorsqu'il associe la <literal>SessionFactory</literal> au JNDI, Hibernate utilisera 
+                les valeurs de <literal>hibernate.jndi.url</literal>, <literal>hibernate.jndi.class</literal>
+                pour instancier un contexte d'initialisation. S'ils ne sont pas spécifiés, 
+                l'<literal>InitialContext</literal> par défaut sera utilisé.
+            </para>
+            
+            <para>
+                Hibernate va automatiquement placer la <literal>SessionFactory</literal> dans JNDI
+                après avoir appelé <literal>cfg.buildSessionFactory()</literal>. Cela signifie que vous
+                devez avoir cet appel dans un code de démarrage (ou dans une classe utilitaire) dans
+                votre application sauf si vous utilisez le déploiement JMX avec le service
+                <literal>HibernateService</literal> présenté plus tard dans ce document.
+            </para>
+            <para>           
+                Si vous utilisez <literal>SessionFactory</literal> JNDI, un EJB ou n'importe quelle autre classe
+                peut obtenir la <literal>SessionFactory</literal> en utilisant un lookup JNDI.
+            </para>
+
+            <para>
+                Nous recommandons que vous liiez la <literal>SessionFactory</literal> à JNDI dans les
+                environnements managés et que vous utilisiez un singleton <literal>static</literal> si ce n'est pas le cas.
+                Pour isoler votre application de ces détails, nous vous recommandons aussi de masquer
+                le code de lookup actuel pour une <literal>SessionFactory</literal> dans une classe helper,
+                comme <literal>HibernateUtil.getSessionFactory()</literal>. Notez qu'une telle classe
+                est aussi un moyen efficace de démarrer Hibernate&mdash;voir chapitre 1.
+            </para>
+        </sect2>
+
+        <sect2 id="configuration-j2ee-currentsession" revision="4">
+            <title>Association automatique de la Session à JTA</title>
+
+            <para>
+                Le moyen le plus simple de gérer les <literal>Session</literal>s et transactions est
+                la gestion automatique de session "courante" offerte par Hibernate.
+                Voir détail à <xref linkend="architecture-current-session">current sessions</xref>.
+                En utilisant le contexte de session <literal>"jta"</literal> session context, s'il n'y a pas
+                de <literal>Session</literal> associée à la transaction JTA courante, une session sera
+                démarrée et associée à la transaction JTA courante la première fois que vous appelez
+                <literal>sessionFactory.getCurrentSession()</literal>. Les <literal>Session</literal>s
+                obtenue via <literal>getCurrentSession()</literal> dans une contexte <literal>"jta"</literal> 
+                seront automatiquement flushées avant la validation de la transaction, fermées une fois
+                la transaction complétée, et libéreront les connexions JDBC de manière aggressive
+                après chaque statement. Ceci permet aux <literal>Session</literal>s d'être
+                gérées par le cycle de vie de la transaction JTA à la quelle est sont associées, 
+                laissant le code de l'utilisateur propre de ce type de gestion. Votre code peut
+                soit utiliser JTA de manière programmatique via <literal>UserTransaction</literal>, ou (ce qui est recommandé
+                pour la portabilité du code) utiliser l'API <literal>Transaction</literal> API pour marquer
+                les limites. Si vous exécutez sous un conteneur EJB, la démarcation déclarative des transactions
+                avec CMT est recommandée.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-j2ee-jmx" revision="1">
+            <title>Déploiement JMX</title>
+
+            <para>
+                La ligne <literal>cfg.buildSessionFactory()</literal>  doit toujours être exécutée
+                quelque part pour avoir une <literal>SessionFactory</literal> dans JNDI. Vous pouvez
+                faire cela dans un bloc d'initialisation <literal>static</literal> (comme
+                celui qui se trouve dans la classe <literal>HibernateUtil</literal>) ou vous pouvez
+                déployer Hibernate en temps que <emphasis>service managé</emphasis>.
+            </para>
+
+            <para>
+                Hibernate est distribué avec <literal>org.hibernate.jmx.HibernateService</literal>
+                pour le déploiement sur un serveur d'application avec le support de JMX comme JBoss AS.
+                Le déploiement et la configuration sont spécifiques à chaque vendeur. Voici un fichier
+                <literal>jboss-service.xml</literal> d'exemple pour JBoss 4.0.x:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<server>
+
+<mbean code="org.hibernate.jmx.HibernateService"
+    name="jboss.jca:service=HibernateFactory,name=HibernateFactory">
+
+    <!-- Required services -->
+    <depends>jboss.jca:service=RARDeployer</depends>
+    <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends>
+
+    <!-- Bind the Hibernate service to JNDI -->
+    <attribute name="JndiName">java:/hibernate/SessionFactory</attribute>
+
+    <!-- Datasource settings -->
+    <attribute name="Datasource">java:HsqlDS</attribute>
+    <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>
+
+    <!-- Transaction integration -->
+    <attribute name="TransactionStrategy">
+        org.hibernate.transaction.JTATransactionFactory</attribute>
+    <attribute name="TransactionManagerLookupStrategy">
+        org.hibernate.transaction.JBossTransactionManagerLookup</attribute>
+    <attribute name="FlushBeforeCompletionEnabled">true</attribute>
+    <attribute name="AutoCloseSessionEnabled">true</attribute>
+
+    <!-- Fetching options -->
+    <attribute name="MaximumFetchDepth">5</attribute>
+
+    <!-- Second-level caching -->
+    <attribute name="SecondLevelCacheEnabled">true</attribute>
+    <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute>
+    <attribute name="QueryCacheEnabled">true</attribute>
+
+    <!-- Logging -->
+    <attribute name="ShowSqlEnabled">true</attribute>
+
+    <!-- Mapping files -->
+    <attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute>
+
+</mbean>
+
+</server>]]></programlisting>
+
+            <para>
+                Ce fichier est déployé dans un répertoire <literal>META-INF</literal> et est packagé
+                dans un fichier JAR avec l'extension <literal>.sar</literal> (service archive).
+                Vous devez également packager Hibernate, les librairies tierces requises, vos classes
+                persistantes compilées et vos fichiers de mapping dans la même archive. Vos beans
+                entreprise (souvent des EJBs session) peuvent rester dans leur propre fichier JAR mais
+                vous pouvez inclure ce fichier JAR dans le jar principal du service pour avoir une seule unité
+                déployable à chaud. Vous pouvez consulter la documentation de JBoss AS pour plus d'information
+                sur les services JMX et le déploiement des EJBs.
+            </para>
+
+        </sect2>
+
+
+    </sect1>
+
+
+
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/events.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/events.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/events.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="events">
+    <title>Les intercepteurs et les événements</title>
+
+    <para>
+        Il est souvent utile pour l'application de réagir à certains événements
+        qui surviennent dans Hibernate. Cela autorise l'implémentation de certaines sortes de
+        fonctionnalités génériques, et d'extensions de fonctionnalités d'Hibernate.
+    </para>
+
+    <sect1 id="objectstate-interceptors" revision="2">
+        <title>Intercepteurs</title>
+
+        <para>
+            L'interface <literal>Interceptor</literal> fournit des "callbacks" de la session vers l'application 
+            et permettent à l'application de consulter et/ou de manipuler des propriétés
+            d'un objet persistant avant qu'il soit sauvegardé, mis à jour, supprimé ou chargé.
+            Une utilisation possible de cette fonctionnalité est de tracer l'accès à l'information.
+            Par exemple, l'<literal>Interceptor</literal> suivant positionne
+            <literal>createTimestamp</literal> quand un <literal>Auditable</literal> est créé
+            et met à jour la propriété <literal>lastUpdateTimestamp</literal> quand un
+            <literal>Auditable</literal> est mis à jour.
+        </para>
+
+        <para>
+            Vous pouvez soit implémenter <literal>Interceptor</literal> directement ou (mieux)
+            étendre <literal>EmptyInterceptor</literal>.
+        </para>
+
+        <programlisting><![CDATA[package org.hibernate.test;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.Transaction;
+import org.hibernate.type.Type;
+
+public class AuditInterceptor extends EmptyInterceptor {
+
+    private int updates;
+    private int creates;
+    private int loads;
+
+    public void onDelete(Object entity,
+                         Serializable id,
+                         Object[] state,
+                         String[] propertyNames,
+                         Type[] types) {
+        // ne fait rien
+    }
+
+    public boolean onFlushDirty(Object entity,
+                                Serializable id,
+                                Object[] currentState,
+                                Object[] previousState,
+                                String[] propertyNames,
+                                Type[] types) {
+
+        if ( entity instanceof Auditable ) {
+            updates++;
+            for ( int i=0; i < propertyNames.length; i++ ) {
+                if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
+                    currentState[i] = new Date();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean onLoad(Object entity,
+                          Serializable id,
+                          Object[] state,
+                          String[] propertyNames,
+                          Type[] types) {
+        if ( entity instanceof Auditable ) {
+            loads++;
+        }
+        return false;
+    }
+
+    public boolean onSave(Object entity,
+                          Serializable id,
+                          Object[] state,
+                          String[] propertyNames,
+                          Type[] types) {
+
+        if ( entity instanceof Auditable ) {
+            creates++;
+            for ( int i=0; i<propertyNames.length; i++ ) {
+                if ( "createTimestamp".equals( propertyNames[i] ) ) {
+                    state[i] = new Date();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void postFlush(Iterator entities) {
+        System.out.println("Creations: " + creates + ", Updates: " + updates);
+    }
+
+    public void afterTransactionCompletion(Transaction tx) {
+        if ( tx.wasCommitted() ) {
+            System.out.println("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads);
+        }
+        updates=0;
+        creates=0;
+        loads=0;
+    }
+
+}]]></programlisting>
+
+        <para>
+            L'intercepteur doit être spécifié quand une session est créée.
+        </para>
+
+        <programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
+
+        <para>
+            Vous pouvez aussi mettre un intercepteur au niveau global, en utilisant l'objet <literal>Configuration</literal>.
+            Dans ce cas, l'intercepteur doit être "threadsafe".
+        </para>
+
+        <programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
+
+    </sect1>
+
+     <sect1 id="objectstate-events" revision="3">
+        <title>Système d'événements</title>
+
+        <para>
+            Si vous devez réagir à des événements particuliers dans votre couche de persistance,
+            vous pouvez aussi utiliser l'architecture d'<emphasis>événements</emphasis> d'Hibernate3.
+            Le système d'événements peut être utilisé en supplément ou en remplacement des interceptors.
+        </para>
+
+        <para>
+            Essentiellement toutes les méthodes de l'interface <literal>Session</literal> sont corrélées à
+            un événement. Vous avez un <literal>LoadEvent</literal>, un <literal>FlushEvent</literal>, etc
+            (consultez la DTD du fichier de configuration XML ou le paquet <literal>org.hibernate.event</literal>
+            pour avoir la liste complète des types d'événement définis).
+            Quand une requête est faite à partir d'une de ces méthodes, la
+            <literal>Session</literal> Hibernate génère un événement approprié et le passe
+            au listener configuré pour ce type.
+            Par défaut, ces listeners implémentent le même traitement dans lequel ces méthodes
+            aboutissent toujours.
+            Cependant, vous êtes libre d'implémenter une version personnalisée d'une de ces
+            interfaces de listener (c'est-à-dire, le <literal>LoadEvent</literal> est traité par
+            l'implémentation de l'interface <literal>LoadEventListener</literal> déclarée), dans
+            quel cas leur implémentation devrait être responsable du traitement des
+            requêtes <literal>load()</literal> faites par la <literal>Session</literal>.
+        </para>
+
+        <para>
+            Les listeners devraient effectivement être considérés comme des singletons ; dans le sens
+            où ils sont partagés entre des requêtes, et donc ne devraient pas sauvegarder des états
+            de variables d'instance.
+        </para>
+
+        <para>
+            Un listener personnalisé devrait implémenter l'interface appropriée pour l'événement
+            qu'il veut traiter et/ou étendre une des classes de base (ou même l'événement prêt à
+            l'emploi utilisé par Hibernate comme ceux déclarés non-finaux à cette intention). Les
+            listeners personnalisés peuvent être soit inscrits par programmation à travers l'objet
+            <literal>Configuration</literal>, ou spécifiés la configuration XML d'Hibernate
+            (la configuration déclarative à travers le fichier de propriétés n'est pas supportée).
+            Voici un exemple de listener personnalisé pour l'événement de chargement :
+        </para>
+
+        <programlisting><![CDATA[public class MyLoadListener implements LoadEventListener {
+    // C'est une simple méthode définie par l'interface LoadEventListener
+    public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
+            throws HibernateException {
+        if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
+            throw MySecurityException("Unauthorized access");
+        }
+    }
+}]]></programlisting>
+
+        <para>
+            Vous avez aussi besoin d'une entrée de configuration disant à Hibernate d'utiliser
+            ce listener en plus du listener par défaut :
+        </para>
+
+<programlisting><![CDATA[<hibernate-configuration>
+    <session-factory>
+        ...
+        <event type="load">
+            <listener class="com.eg.MyLoadListener"/>
+            <listener class="org.hibernate.event.def.DefaultLoadEventListener"/>
+        </event>
+    </session-factory>
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+            Vous pouvez aussi l'inscrire par programmation :
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration();
+LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() };
+cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
+
+        <para>
+            Les listeners inscrits déclarativement ne peuvent pas partager d'instances. Si le même
+            nom de classe est utilisée dans plusieurs éléments <literal>&lt;listener/&gt;</literal>,
+            chaque référence sera une instance distincte de cette classe. Si vous avez besoin de la
+            faculté de partager des instances de listener entre plusieurs types de listener, vous devez
+            utiliser l'approche d'inscription par programmation.
+        </para>
+
+        <para>
+            Pourquoi implémenter une interface et définir le type spécifique durant la configuration ?
+            Une implémentation de listener pourrait implémenter plusieurs interfaces de listener
+            d'événements. Avoir en plus le type défini durant l'inscription rend plus facile
+            l'activation ou la désactivation pendant la configuration.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-decl-security" revision="2">
+        <title>Sécurité déclarative d'Hibernate</title>
+        <para>
+            Généralement, la sécurité déclarative dans les applications Hibernate est gérée dans la
+            couche de session. Maintenant, Hibernate3 permet à certaines actions d'être approuvées
+            via JACC, et autorisées via JAAS. Cette fonctionnalité optionnelle est construite
+            au dessus de l'architecture d'événements.
+        </para>
+
+        <para>
+            D'abord, vous devez configurer les listeners d'événements appropriés pour permettre
+            l'utilisation d'autorisations JAAS.
+        </para>
+
+        <programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
+<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
+<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
+<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
+
+        <para>
+            Notez que <literal>&lt;listener type="..." class="..."/&gt;</literal> est juste un raccourci
+            pour <literal>&lt;event type="..."&gt;&lt;listener class="..."/&gt;&lt;/event&gt;</literal>
+            quand il y a exactement un listener pour un type d'événement particulier.
+        </para>
+
+        <para>
+            Ensuite, toujours dans <literal>hibernate.cfg.xml</literal>, lier les permissions aux rôles :
+        </para>
+
+        <programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
+<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
+
+        <para>
+            Les noms de rôle sont les rôles compris par votre fournisseur JAAC.
+        </para>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/example_mappings.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/example_mappings.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/example_mappings.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,657 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="example-mappings">
+    <title>Exemple : quelques mappings</title>
+
+    <para>
+        Ce chapitre montre quelques mappings plus complexes.
+    </para>
+
+    <sect1 id="example-mappings-emp">
+        <title>Employeur/Employé (Employer/Employee)</title>
+
+        <para>
+            Le modèle suivant de relation entre <literal>Employer</literal> et
+            <literal>Employee</literal> utilise une vraie classe entité (<literal>Employment</literal>)
+            pour représenter l'association. On a fait cela parce qu'il peut y avoir plus d'une période
+            d'emploi pour les deux mêmes parties. Des composants sont utilisés pour modéliser les
+            valeurs monétaires et les noms des employés.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/EmployerEmployee.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/EmployerEmployee.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            Voici un document de mapping possible :
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Employer" table="employers">
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employer_id_seq</param>
+            </generator>
+        </id>
+        <property name="name"/>
+    </class>
+
+    <class name="Employment" table="employment_periods">
+
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employment_id_seq</param>
+            </generator>
+        </id>
+        <property name="startDate" column="start_date"/>
+        <property name="endDate" column="end_date"/>
+
+        <component name="hourlyRate" class="MonetaryAmount">
+            <property name="amount">
+                <column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>
+            </property>
+            <property name="currency" length="12"/>
+        </component>
+
+        <many-to-one name="employer" column="employer_id" not-null="true"/>
+        <many-to-one name="employee" column="employee_id" not-null="true"/>
+
+    </class>
+
+    <class name="Employee" table="employees">
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employee_id_seq</param>
+            </generator>
+        </id>
+        <property name="taxfileNumber"/>
+        <component name="name" class="Name">
+            <property name="firstName"/>
+            <property name="initial"/>
+            <property name="lastName"/>
+        </component>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        Et voici le schéma des tables générées par <literal>SchemaExport</literal>.
+    </para>
+
+    <programlisting><![CDATA[create table employers (
+    id BIGINT not null,
+    name VARCHAR(255),
+    primary key (id)
+)
+
+create table employment_periods (
+    id BIGINT not null,
+    hourly_rate NUMERIC(12, 2),
+    currency VARCHAR(12),
+    employee_id BIGINT not null,
+    employer_id BIGINT not null,
+    end_date TIMESTAMP,
+    start_date TIMESTAMP,
+    primary key (id)
+)
+
+create table employees (
+    id BIGINT not null,
+    firstName VARCHAR(255),
+    initial CHAR(1),
+    lastName VARCHAR(255),
+    taxfileNumber VARCHAR(255),
+    primary key (id)
+)
+
+alter table employment_periods
+    add constraint employment_periodsFK0 foreign key (employer_id) references employers
+alter table employment_periods
+    add constraint employment_periodsFK1 foreign key (employee_id) references employees
+create sequence employee_id_seq
+create sequence employment_id_seq
+create sequence employer_id_seq]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-mappings-authorwork">
+        <title>Auteur/Travail (Author/Work)</title>
+
+        <para>
+            Soit le modèle de la relation entre <literal>Work</literal>, <literal>Author</literal>
+            et <literal>Person</literal>. Nous représentons la relation entre <literal>Work</literal>
+            et <literal>Author</literal> comme une association plusieurs-vers-plusieurs. Nous avons choisi de
+            représenter la relation entre <literal>Author</literal> et <literal>Person</literal>
+            comme une association un-vers-un. Une autre possibilité aurait été que
+            <literal>Author</literal> hérite de <literal>Person</literal>.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/AuthorWork.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/AuthorWork.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            Le mapping suivant représente exactement ces relations :
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Work" table="works" discriminator-value="W">
+
+        <id name="id" column="id">
+            <generator class="native"/>
+        </id>
+        <discriminator column="type" type="character"/>
+
+        <property name="title"/>
+        <set name="authors" table="author_work">
+            <key column name="work_id"/>
+            <many-to-many class="Author" column name="author_id"/>
+        </set>
+
+        <subclass name="Book" discriminator-value="B">
+            <property name="text"/>
+        </subclass>
+
+        <subclass name="Song" discriminator-value="S">
+            <property name="tempo"/>
+            <property name="genre"/>
+        </subclass>
+
+    </class>
+
+    <class name="Author" table="authors">
+
+        <id name="id" column="id">
+            <!-- The Author must have the same identifier as the Person -->
+            <generator class="assigned"/>
+        </id>
+
+        <property name="alias"/>
+        <one-to-one name="person" constrained="true"/>
+
+        <set name="works" table="author_work" inverse="true">
+            <key column="author_id"/>
+            <many-to-many class="Work" column="work_id"/>
+        </set>
+
+    </class>
+
+    <class name="Person" table="persons">
+        <id name="id" column="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        Il y a quatre tables dans ce mapping. <literal>works</literal>,
+        <literal>authors</literal> et <literal>persons</literal> qui contiennent
+        respectivement les données de work, author et person.
+        <literal>author_work</literal> est une table d'association qui lie authors
+        à works. Voici le schéma de tables, généré par <literal>SchemaExport</literal>.
+    </para>
+
+    <programlisting><![CDATA[create table works (
+    id BIGINT not null generated by default as identity,
+    tempo FLOAT,
+    genre VARCHAR(255),
+    text INTEGER,
+    title VARCHAR(255),
+    type CHAR(1) not null,
+    primary key (id)
+)
+
+create table author_work (
+    author_id BIGINT not null,
+    work_id BIGINT not null,
+    primary key (work_id, author_id)
+)
+
+create table authors (
+    id BIGINT not null generated by default as identity,
+    alias VARCHAR(255),
+    primary key (id)
+)
+
+create table persons (
+    id BIGINT not null generated by default as identity,
+    name VARCHAR(255),
+    primary key (id)
+)
+
+alter table authors
+    add constraint authorsFK0 foreign key (id) references persons
+alter table author_work
+    add constraint author_workFK0 foreign key (author_id) references authors
+alter table author_work
+    add constraint author_workFK1 foreign key (work_id) references works]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-mappings-customerorderproduct">
+        <title>Client/Commande/Produit (Customer/Order/Product)</title>
+
+        <para>
+            Imaginons maintenant le modèle de relation entre <literal>Customer</literal>,
+            <literal>Order</literal>, <literal>LineItem</literal> et <literal>Product</literal>.
+            Il y a une association un-vers-plusieurs entre <literal>Customer</literal> et
+            <literal>Order</literal>, mais comment devrions nous représenter <literal>Order</literal> /
+            <literal>LineItem</literal> / <literal>Product</literal>? J'ai choisi de mapper
+            <literal>LineItem</literal> comme une classe d'association représentant l'association
+            plusieurs-vers-plusieurs entre <literal>Order</literal> et <literal>Product</literal>. Dans
+            Hibernate, on appelle cela un élément composite.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            Le document de mapping :
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Customer" table="customers">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+        <set name="orders" inverse="true">
+            <key column="customer_id"/>
+            <one-to-many class="Order"/>
+        </set>
+    </class>
+
+    <class name="Order" table="orders">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="date"/>
+        <many-to-one name="customer" column="customer_id"/>
+        <list name="lineItems" table="line_items">
+            <key column="order_id"/>
+            <list-index column="line_number"/>
+            <composite-element class="LineItem">
+                <property name="quantity"/>
+                <many-to-one name="product" column="product_id"/>
+            </composite-element>
+        </list>
+    </class>
+
+    <class name="Product" table="products">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="serialNumber"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        <literal>customers</literal>, <literal>orders</literal>, <literal>line_items</literal> et
+        <literal>products</literal> contiennent les données de customer, order, order line item et product.
+        <literal>line_items</literal> est aussi la table d'association liant orders à products.
+    </para>
+
+    <programlisting><![CDATA[create table customers (
+    id BIGINT not null generated by default as identity,
+    name VARCHAR(255),
+    primary key (id)
+)
+
+create table orders (
+    id BIGINT not null generated by default as identity,
+    customer_id BIGINT,
+    date TIMESTAMP,
+    primary key (id)
+)
+
+create table line_items (
+    line_number INTEGER not null,
+    order_id BIGINT not null,
+    product_id BIGINT,
+    quantity INTEGER,
+    primary key (order_id, line_number)
+)
+
+create table products (
+    id BIGINT not null generated by default as identity,
+    serialNumber VARCHAR(255),
+    primary key (id)
+)
+
+alter table orders
+    add constraint ordersFK0 foreign key (customer_id) references customers
+alter table line_items
+    add constraint line_itemsFK0 foreign key (product_id) references products
+alter table line_items
+    add constraint line_itemsFK1 foreign key (order_id) references orders]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="misc">
+        <title>Divers mappings d'exemple</title>
+
+        <para>
+            Ces exemples sont tous pris de la suite de tests d'Hibernate. Vous en trouverez beaucoup d'autres.
+            Regardez dans le dossier <literal>test</literal> de la distribution d'Hibernate.
+        </para>
+
+        <para>TODO: put words around this stuff</para>
+
+        <sect2 id="example-mappings-typed-onetone">
+            <title>"Typed" one-to-one association</title>
+<programlisting><![CDATA[<class name="Person">
+    <id name="name"/>
+    <one-to-one name="address"
+            cascade="all">
+        <formula>name</formula>
+        <formula>'HOME'</formula>
+    </one-to-one>
+    <one-to-one name="mailingAddress"
+            cascade="all">
+        <formula>name</formula>
+        <formula>'MAILING'</formula>
+    </one-to-one>
+</class>
+
+<class name="Address" batch-size="2"
+        check="addressType in ('MAILING', 'HOME', 'BUSINESS')">
+    <composite-id>
+        <key-many-to-one name="person"
+                column="personName"/>
+        <key-property name="type"
+                column="addressType"/>
+    </composite-id>
+    <property name="street" type="text"/>
+    <property name="state"/>
+    <property name="zip"/>
+</class>]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-composite-key">
+            <title>Exemple de clef composée</title>
+<programlisting><![CDATA[<class name="Customer">
+
+    <id name="customerId"
+        length="10">
+        <generator class="assigned"/>
+    </id>
+
+    <property name="name" not-null="true" length="100"/>
+    <property name="address" not-null="true" length="200"/>
+
+    <list name="orders"
+            inverse="true"
+            cascade="save-update">
+        <key column="customerId"/>
+        <index column="orderNumber"/>
+        <one-to-many class="Order"/>
+    </list>
+
+</class>
+
+<class name="Order" table="CustomerOrder" lazy="true">
+    <synchronize table="LineItem"/>
+    <synchronize table="Product"/>
+
+    <composite-id name="id"
+            class="Order$Id">
+        <key-property name="customerId" length="10"/>
+        <key-property name="orderNumber"/>
+    </composite-id>
+
+    <property name="orderDate"
+            type="calendar_date"
+            not-null="true"/>
+
+    <property name="total">
+        <formula>
+            ( select sum(li.quantity*p.price)
+            from LineItem li, Product p
+            where li.productId = p.productId
+                and li.customerId = customerId
+                and li.orderNumber = orderNumber )
+        </formula>
+    </property>
+
+    <many-to-one name="customer"
+            column="customerId"
+            insert="false"
+            update="false"
+            not-null="true"/>
+
+    <bag name="lineItems"
+            fetch="join"
+            inverse="true"
+            cascade="save-update">
+        <key>
+            <column name="customerId"/>
+            <column name="orderNumber"/>
+        </key>
+        <one-to-many class="LineItem"/>
+    </bag>
+
+</class>
+
+<class name="LineItem">
+
+    <composite-id name="id"
+            class="LineItem$Id">
+        <key-property name="customerId" length="10"/>
+        <key-property name="orderNumber"/>
+        <key-property name="productId" length="10"/>
+    </composite-id>
+
+    <property name="quantity"/>
+
+    <many-to-one name="order"
+            insert="false"
+            update="false"
+            not-null="true">
+        <column name="customerId"/>
+        <column name="orderNumber"/>
+    </many-to-one>
+
+    <many-to-one name="product"
+            insert="false"
+            update="false"
+            not-null="true"
+            column="productId"/>
+
+</class>
+
+<class name="Product">
+    <synchronize table="LineItem"/>
+
+    <id name="productId"
+        length="10">
+        <generator class="assigned"/>
+    </id>
+
+    <property name="description"
+        not-null="true"
+        length="200"/>
+    <property name="price" length="3"/>
+    <property name="numberAvailable"/>
+
+    <property name="numberOrdered">
+        <formula>
+            ( select sum(li.quantity)
+            from LineItem li
+            where li.productId = productId )
+        </formula>
+    </property>
+
+</class>]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-composite-key-manytomany">
+            <title>Many-to-many avec une clef composée partagée</title>
+<programlisting><![CDATA[<class name="User" table="`User`">
+    <composite-id>
+        <key-property name="name"/>
+        <key-property name="org"/>
+    </composite-id>
+    <set name="groups" table="UserGroup">
+        <key>
+            <column name="userName"/>
+            <column name="org"/>
+        </key>
+        <many-to-many class="Group">
+            <column name="groupName"/>
+            <formula>org</formula>
+        </many-to-many>
+    </set>
+</class>
+
+<class name="Group" table="`Group`">
+    <composite-id>
+        <key-property name="name"/>
+        <key-property name="org"/>
+    </composite-id>
+    <property name="description"/>
+    <set name="users" table="UserGroup" inverse="true">
+        <key>
+            <column name="groupName"/>
+            <column name="org"/>
+        </key>
+        <many-to-many class="User">
+            <column name="userName"/>
+            <formula>org</formula>
+        </many-to-many>
+    </set>
+</class>
+]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-content-discrimination">
+            <title>Contenu basé sur une discrimination</title>
+<programlisting><![CDATA[<class name="Person"
+    discriminator-value="P">
+
+    <id name="id"
+        column="person_id"
+        unsaved-value="0">
+        <generator class="native"/>
+    </id>
+
+
+    <discriminator
+        type="character">
+        <formula>
+            case
+                when title is not null then 'E'
+                when salesperson is not null then 'C'
+                else 'P'
+            end
+        </formula>
+    </discriminator>
+
+    <property name="name"
+        not-null="true"
+        length="80"/>
+
+    <property name="sex"
+        not-null="true"
+        update="false"/>
+
+    <component name="address">
+        <property name="address"/>
+        <property name="zip"/>
+        <property name="country"/>
+    </component>
+
+    <subclass name="Employee"
+        discriminator-value="E">
+            <property name="title"
+                length="20"/>
+            <property name="salary"/>
+            <many-to-one name="manager"/>
+    </subclass>
+
+    <subclass name="Customer"
+        discriminator-value="C">
+            <property name="comments"/>
+            <many-to-one name="salesperson"/>
+    </subclass>
+
+</class>]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-association-alternatekeys" revision="2">
+            <title>Associations sur des clefs alternées</title>
+<programlisting><![CDATA[<class name="Person">
+
+    <id name="id">
+        <generator class="hilo"/>
+    </id>
+
+    <property name="name" length="100"/>
+
+    <one-to-one name="address"
+        property-ref="person"
+        cascade="all"
+        fetch="join"/>
+
+    <set name="accounts"
+        inverse="true">
+        <key column="userId"
+            property-ref="userId"/>
+        <one-to-many class="Account"/>
+    </set>
+
+    <property name="userId" length="8"/>
+
+</class>
+
+<class name="Address">
+
+    <id name="id">
+        <generator class="hilo"/>
+    </id>
+
+    <property name="address" length="300"/>
+    <property name="zip" length="5"/>
+    <property name="country" length="25"/>
+    <many-to-one name="person" unique="true" not-null="true"/>
+
+</class>
+
+<class name="Account">
+    <id name="accountId" length="32">
+        <generator class="uuid"/>
+    </id>
+
+    <many-to-one name="user"
+        column="userId"
+        property-ref="userId"/>
+
+    <property name="type" not-null="true"/>
+
+</class>]]></programlisting>
+        </sect2>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/example_parentchild.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/example_parentchild.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/example_parentchild.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,372 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="example-parentchild">
+    <title>Exemple : Père/Fils</title>
+
+    <para>
+        L'une des premières choses que les nouveaux utilisateurs essaient de faire avec Hibernate est de modéliser
+        une relation père/fils. Il y a deux approches différentes pour cela. Pour un certain nombre de raisons, la méthode la
+        plus courante, en particulier pour les nouveaux utilisateurs, est de modéliser les deux relations <literal>Père</literal>
+        et <literal>Fils</literal> comme des classes entités liées par une association <literal>&lt;one-to-many&gt;</literal> du
+        <literal>Père</literal> vers le <literal>Fils</literal> (l'autre approche est de déclarer le <literal>Fils</literal>
+        comme un <literal>&lt;composite-element&gt;</literal>). Il est évident que le sens de l'association un vers plusieurs
+        (dans Hibernate) est bien moins proche du sens habituel d'une relation père/fils que ne l'est celui d'un
+        élément cmposite. Nous allons vous expliquer comment utiliser une association <emphasis>un vers plusieurs bidirectionnelle
+        avec cascade</emphasis> afin de modéliser efficacement et élégamment une relation père/fils, ce n'est vraiment
+        pas difficile !
+    </para>
+
+    <sect1 id="example-parentchild-collections">
+        <title>Une note à propos des collections</title>
+
+        <para>
+            Les collections Hibernate sont considérées comme étant une partie logique
+            de l'entité dans laquelle elles sont contenues ; jamais des entités qu'elle
+            contient. C'est une distinction crutiale ! Les conséquences sont les suivantes :
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    Quand nous ajoutons / retirons un objet d'une collection, le numéro de version du
+                    propriétaire de la collection est incrémenté.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Si un objet qui a été enlevé d'une collection est une instance de type valeur (ex :
+                    élément composite), cet objet cessera d'être persistant et son état sera complètement effacé
+                    de la base de données. Par ailleurs, ajouter une instance de type valeur dans une collection
+                    aura pour conséquence que son état sera immédiatement persistant.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Si une entité est enlevée d'une collection (association un-vers-plusieurs
+                    ou plusieurs-vers-plusieurs), par défaut, elle ne sera pas effacée. Ce comportement
+                    est complètement logique - une modification de l'un des états internes d'une entité
+                    ne doit pas causer la disparition de l'entité associée !
+                    De même, l'ajout d'une entité dans une collection n'engendre pas,
+                    par défaut, la persistance de cette entité.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Le comportement par défaut est donc que l'ajout d'une entité dans une collection créé
+            simplement le lien entre les deux entités, et qu'effacer une entité supprime ce lien.
+            C'est le comportement le plus approprié dans la plupart des cas. Ce comportement n'est
+            cependant pas approprié lorsque la vie du fils est liée au cycle de vie du père.
+        </para>
+
+    </sect1>
+
+    <sect1 id="example-parentchild-bidir">
+        <title>un-vers-plusieurs bidirectionnel</title>
+
+        <para>
+            Supposons que nous ayons une simple association <literal>&lt;one-to-many&gt;</literal>
+            de <literal>Parent</literal> vers <literal>Child</literal>.
+        </para>
+
+        <programlisting><![CDATA[<set name="children">
+                <key column="parent_id"/>
+                <one-to-many class="Child"/>
+            </set>]]></programlisting>
+
+        <para>
+            Si nous executions le code suivant
+        </para>
+
+        <programlisting><![CDATA[Parent p = .....;
+Child c = new Child();
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+        <para>
+            Hibernate exécuterait deux ordres SQL:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>un <literal>INSERT</literal> pour créer l'enregistrement pour <literal>c</literal></para>
+            </listitem>
+            <listitem>
+                <para>
+                    un <literal>UPDATE</literal> pour créer le lien de <literal>p</literal> vers
+                    <literal>c</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Ceci est non seuleument inefficace, mais viole aussi toute contrainte <literal>NOT NULL</literal> sur
+            la colonne <literal>parent_id</literal>. Nous pouvons réparer la contrainte de nullité
+            en spécifiant <literal>not-null="true"</literal> dans le mapping de la collection :
+        </para>
+
+        <programlisting><![CDATA[<set name="children">
+    <key column="parent_id" not-null="true"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+        <para>
+            Cependant ce n'est pas la solution recommandée.
+        </para>
+
+        <para>
+            La cause sous jacente à ce comportement est que le lien (la clé étrangère <literal>parent_id</literal>) de
+            <literal>p</literal> vers <literal>c</literal> n'est pas considérée comme faisant partie de l'état
+            de l'objet <literal>Child</literal> et n'est donc pas créé par l'<literal>INSERT</literal>.
+            La solution est donc que ce lien fasse partie du mapping de <literal>Child</literal>.
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
+
+        <para>
+            (Nous avons aussi besoin d'ajouter la propriété <literal>parent</literal> dans la classe <literal>Child</literal>).
+        </para>
+
+        <para>
+            Maintenant que l'état du lien est géré par l'entité <literal>Child</literal>, nous spécifions à la
+            collection de ne pas mettre à jour le lien. Nous utilisons l'attribut <literal>inverse</literal>.
+        </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+        <para>
+            Le code suivant serait utilisé pour ajouter un nouveau <literal>Child</literal>
+        </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+        <para>
+            Maintenant, seul un <literal>INSERT</literal> SQL est nécessaire !
+        </para>
+
+        <para>
+            Pour alléger encore un peu les choses, nous devrions créer une méthode <literal>addChild()</literal>
+            dans <literal>Parent</literal>.
+        </para>
+
+        <programlisting><![CDATA[public void addChild(Child c) {
+    c.setParent(this);
+    children.add(c);
+}]]></programlisting>
+
+        <para>
+            Le code d'ajout d'un <literal>Child</literal> serait alors
+        </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-parentchild-cascades">
+        <title>Cycle de vie en cascade</title>
+
+        <para>
+            L'appel explicite de <literal>save()</literal> est un peu fastidieux. Nous pouvons
+            simplifier cela en utilisant les cascades.
+        </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true" cascade="all">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+        <para>
+            Simplifie le code précédent en
+        </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.flush();]]></programlisting>
+
+        <para>
+            De la même manière, nous n'avons pas à itérer sur les fils lorsque nous sauvons
+            ou effacons un <literal>Parent</literal>. Le code suivant efface <literal>p</literal>
+            et tous ses fils de la base de données.
+        </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+session.delete(p);
+session.flush();]]></programlisting>
+
+         <para>
+             Par contre, ce code
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+c.setParent(null);
+session.flush();]]></programlisting>
+
+         <para>
+             n'effacera pas <literal>c</literal> de la base de données, il enlèvera seulement
+             le lien vers  <literal>p</literal> (et causera une violation de contrainte
+             <literal>NOT NULL</literal>, dans ce cas).
+             Vous devez explicitement utiliser <literal>delete()</literal> sur <literal>Child</literal>.
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+session.delete(c);
+session.flush();]]></programlisting>
+
+        <para>
+            Dans notre cas, un <literal>Child</literal> ne peut pas vraiment exister sans son père. Si nous
+            effacons un <literal>Child</literal> de la collection, nous voulons vraiment qu'il soit effacé.
+            Pour cela, nous devons utiliser <literal>cascade="all-delete-orphan"</literal>.
+        </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true" cascade="all-delete-orphan">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+        <para>
+            A noter : même si le mapping de la collection spécifie <literal>inverse="true"</literal>, les cascades
+            sont toujours assurées par l'itération sur les éléments de la collection. Donc, si vous avez besoin
+            qu'un objet soit enregistré, effacé ou mis à jour par cascade, vous devez l'ajouter dans la colleciton.
+            Il ne suffit pas d'appeler explicitement <literal>setParent()</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="example-parentchild-update">
+        <title>Cascades et <literal>unsaved-value</literal></title>
+
+        <para>
+            Supposons que nous ayons chargé un <literal>Parent</literal> dans une <literal>Session</literal>,
+            que nous l'ayons ensuite modifié et que voulions persiter ces modifications dans une nouvelle session
+            en appelant <literal>update()</literal>.
+            Le <literal>Parent</literal> contiendra une collection de fils et, puisque la cascade est activée,
+            Hibernate a besoin de savoir quels fils viennent d'être instanciés et quels fils proviennent de la base
+            de données. Supposons aussi que <literal>Parent</literal> et <literal>Child</literal> ont tous deux
+            des identifiants du type <literal>Long</literal>.
+            Hibernate utilisera la propriété de l'identifiant et la propriété de la version/horodatage pour déterminer quels fils sont nouveaux
+            (vous pouvez aussi utiliser la propriété version ou timestamp, voir
+            <xref linkend="manipulatingdata-updating-detached"/>).
+            <emphasis>Dans Hibernate3, il n'est plus nécessaire de spécifier
+            une <literal>unsaved-value</literal> explicitement.</emphasis>
+        </para>
+
+        <para>
+            Le code suivant mettra à jour <literal>parent</literal> et <literal>child</literal>
+            et insérera <literal>newChild</literal>.
+        </para>
+
+        <programlisting><![CDATA[//parent et child ont été chargés dans une session précédente
+parent.addChild(child);
+Child newChild = new Child();
+parent.addChild(newChild);
+session.update(parent);
+session.flush();]]></programlisting>
+
+        <para>
+            Ceci est très bien pour des identifiants générés, mais qu'en est-il des identifiants assignés et des
+            identifiants composés ? C'est plus difficile,
+            puisqu'Hibernate ne peut pas utiliser la propriété de l'identifiant pour distinguer un objet
+            nouvellement instancié (avec un identifiant assigné par l'utilisateur) d'un objet chargé dans une session précédente.
+            Dans ce cas, Hibernate utilisera soit la propriété de version ou d'horodatage, soit effectuera vraiment une requête au cache
+            de second niveau, soit, dans le pire des cas, à la base de données, pour voir si la ligne existe.
+        </para>
+
+         <!-- undocumenting
+         <para>
+             There is one further possibility. The <literal>Interceptor</literal> method named
+             <literal>isUnsaved()</literal> lets the application implement its own strategy for distinguishing
+             newly instantiated objects. For example, you could define a base class for your persistent classes.
+         </para>
+
+         <programlisting><![CDATA[public class Persistent {
+    private boolean _saved = false;
+    public void onSave() {
+        _saved=true;
+    }
+    public void onLoad() {
+        _saved=true;
+    }
+    ......
+    public boolean isSaved() {
+        return _saved;
+    }
+}]]></programlisting>
+
+         <para>
+             (The <literal>saved</literal> property is non-persistent.)
+             Now implement <literal>isUnsaved()</literal>, along with <literal>onLoad()</literal>
+             and <literal>onSave()</literal> as follows.
+         </para>
+
+         <programlisting><![CDATA[public Boolean isUnsaved(Object entity) {
+    if (entity instanceof Persistent) {
+        return new Boolean( !( (Persistent) entity ).isSaved() );
+    }
+    else {
+        return null;
+    }
+}
+
+public boolean onLoad(Object entity,
+    Serializable id,
+    Object[] state,
+    String[] propertyNames,
+    Type[] types) {
+
+    if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
+    return false;
+}
+
+public boolean onSave(Object entity,
+    Serializable id,
+    Object[] state,
+    String[] propertyNames,
+    Type[] types) {
+
+    if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
+    return false;
+}]]></programlisting>
+
+        <para>
+            Don't worry; in Hibernate3 you don't need to write any of this kind of code if you don't want to.
+        </para>
+     -->
+    </sect1>
+
+    <sect1 id="example-parentchild-conclusion">
+        <title>Conclusion</title>
+
+        <para>
+            Il y a quelques principes à maîtriser dans ce chapitre et tout cela peut paraître déroutant la première fois.
+            Cependant, dans la pratique, tout fonctionne parfaitement. La plupart des applications Hibernate utilisent
+            le pattern père / fils.
+        </para>
+
+        <para>
+            Nous avons évoqué une alternative dans le premier paragraphe. Aucun des points traités précédemment n'existe
+            dans le cas d'un mapping <literal>&lt;composite-element&gt;</literal> qui possède exactement la sémantique
+            d'une relation père / fils. Malheureusement, il y a deux grandes limitations pour les classes éléments
+            composites : les éléments composites ne peuvent contenir de collections, et ils ne peuvent être les fils
+            d'entités autres que l'unique parent.
+        </para>
+
+     </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/example_weblog.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/example_weblog.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/example_weblog.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,432 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="example-weblog">
+    <title>Exemple : application Weblog</title>
+
+    <sect1 id="example-weblog-classes">
+        <title>Classes persistantes</title>
+
+        <para>
+            Les classes persistantes representent un weblog, et un article posté
+            dans un weblog. Il seront modélisés comme une relation père/fils
+            standard, mais nous allons utiliser un "bag" trié au lieu d'un set.
+
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+import java.util.List;
+
+public class Blog {
+    private Long _id;
+    private String _name;
+    private List _items;
+
+    public Long getId() {
+        return _id;
+    }
+    public List getItems() {
+        return _items;
+    }
+    public String getName() {
+        return _name;
+    }
+    public void setId(Long long1) {
+        _id = long1;
+    }
+    public void setItems(List list) {
+        _items = list;
+    }
+    public void setName(String string) {
+        _name = string;
+    }
+}]]></programlisting>
+
+        <programlisting><![CDATA[package eg;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+
+public class BlogItem {
+    private Long _id;
+    private Calendar _datetime;
+    private String _text;
+    private String _title;
+    private Blog _blog;
+
+    public Blog getBlog() {
+        return _blog;
+    }
+    public Calendar getDatetime() {
+        return _datetime;
+    }
+    public Long getId() {
+        return _id;
+    }
+    public String getText() {
+        return _text;
+    }
+    public String getTitle() {
+        return _title;
+    }
+    public void setBlog(Blog blog) {
+        _blog = blog;
+    }
+    public void setDatetime(Calendar calendar) {
+        _datetime = calendar;
+    }
+    public void setId(Long long1) {
+        _id = long1;
+    }
+    public void setText(String string) {
+        _text = string;
+    }
+    public void setTitle(String string) {
+        _title = string;
+    }
+}]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-weblog-mappings">
+        <title>Mappings Hibernate</title>
+
+        <para>
+            Le mapping XML doit maintenant être relativement simple à vos yeux.
+        </para>
+
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+    <class
+        name="Blog"
+        table="BLOGS">
+
+        <id
+            name="id"
+            column="BLOG_ID">
+
+            <generator class="native"/>
+
+        </id>
+
+        <property
+            name="name"
+            column="NAME"
+            not-null="true"
+            unique="true"/>
+
+        <bag
+            name="items"
+            inverse="true"
+            order-by="DATE_TIME"
+            cascade="all">
+
+            <key column="BLOG_ID"/>
+            <one-to-many class="BlogItem"/>
+
+        </bag>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+    <class
+        name="BlogItem"
+        table="BLOG_ITEMS"
+        dynamic-update="true">
+
+        <id
+            name="id"
+            column="BLOG_ITEM_ID">
+
+            <generator class="native"/>
+
+        </id>
+
+        <property
+            name="title"
+            column="TITLE"
+            not-null="true"/>
+
+        <property
+            name="text"
+            column="TEXT"
+            not-null="true"/>
+
+        <property
+            name="datetime"
+            column="DATE_TIME"
+            not-null="true"/>
+
+        <many-to-one
+            name="blog"
+            column="BLOG_ID"
+            not-null="true"/>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-weblog-code">
+        <title>Code Hibernate</title>
+
+        <para>
+            La classe suivante montre quelques utilisations que nous pouvons faire
+            de ces classes.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+
+public class BlogMain {
+
+    private SessionFactory _sessions;
+
+    public void configure() throws HibernateException {
+        _sessions = new Configuration()
+            .addClass(Blog.class)
+            .addClass(BlogItem.class)
+            .buildSessionFactory();
+    }
+
+    public void exportTables() throws HibernateException {
+        Configuration cfg = new Configuration()
+            .addClass(Blog.class)
+            .addClass(BlogItem.class);
+        new SchemaExport(cfg).create(true, true);
+    }
+
+    public Blog createBlog(String name) throws HibernateException {
+
+        Blog blog = new Blog();
+        blog.setName(name);
+        blog.setItems( new ArrayList() );
+
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.persist(blog);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return blog;
+    }
+
+    public BlogItem createBlogItem(Blog blog, String title, String text)
+                        throws HibernateException {
+
+        BlogItem item = new BlogItem();
+        item.setTitle(title);
+        item.setText(text);
+        item.setBlog(blog);
+        item.setDatetime( Calendar.getInstance() );
+        blog.getItems().add(item);
+
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.update(blog);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return item;
+    }
+
+    public BlogItem createBlogItem(Long blogid, String title, String text)
+                        throws HibernateException {
+
+        BlogItem item = new BlogItem();
+        item.setTitle(title);
+        item.setText(text);
+        item.setDatetime( Calendar.getInstance() );
+
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            Blog blog = (Blog) session.load(Blog.class, blogid);
+            item.setBlog(blog);
+            blog.getItems().add(item);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return item;
+    }
+
+    public void updateBlogItem(BlogItem item, String text)
+                    throws HibernateException {
+
+        item.setText(text);
+
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.update(item);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+    }
+
+    public void updateBlogItem(Long itemid, String text)
+                    throws HibernateException {
+
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            BlogItem item = (BlogItem) session.load(BlogItem.class, itemid);
+            item.setText(text);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+    }
+
+    public List listAllBlogNamesAndItemCounts(int max)
+                    throws HibernateException {
+
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        List result = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "select blog.id, blog.name, count(blogItem) " +
+                "from Blog as blog " +
+                "left outer join blog.items as blogItem " +
+                "group by blog.name, blog.id " +
+                "order by max(blogItem.datetime)"
+            );
+            q.setMaxResults(max);
+            result = q.list();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return result;
+    }
+
+    public Blog getBlogAndAllItems(Long blogid)
+                    throws HibernateException {
+
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        Blog blog = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "from Blog as blog " +
+                "left outer join fetch blog.items " +
+                "where blog.id = :blogid"
+            );
+            q.setParameter("blogid", blogid);
+            blog  = (Blog) q.uniqueResult();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return blog;
+    }
+
+    public List listBlogsAndRecentItems() throws HibernateException {
+
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        List result = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "from Blog as blog " +
+                "inner join blog.items as blogItem " +
+                "where blogItem.datetime > :minDate"
+            );
+
+            Calendar cal = Calendar.getInstance();
+            cal.roll(Calendar.MONTH, false);
+            q.setCalendar("minDate", cal);
+
+            result = q.list();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return result;
+    }
+}]]></programlisting>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/filters.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/filters.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/filters.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="filters">
+    <title>Filtrer les données</title>
+
+    <para>
+        Hibernate3 fournit une nouvelle approche innovatrice pour gérer des données
+        avec des règles de "visibilité". Un <emphasis>filtre Hibernate</emphasis> est un filtre
+        global, nommé, paramétré qui peut être activé ou désactivé pour une session Hibernate
+        particulière.
+    </para>
+
+    <sect1 id="objectstate-filters">
+        <title>Filtres Hibernate</title>
+
+        <para>
+            Hibernate3 ajoute la capacité de prédéfinir des critères de filtre et d'attacher ces
+            filtres à une classe ou à une collection. Un critère de filtre est la faculté de définir
+            une clause de restriction très similaire à l'attribut "where" existant disponible sur
+            une classe et divers éléments d'une collection. Mis à part que ces conditions de filtre
+            peuvent être paramétrées. L'application peut alors prendre la décision à l'exécution
+            si des filtres donnés devraient être activés et quels devraient être leurs paramètres.
+            Des filtres peuvent être utilisés comme des vues de base de données, mais paramétrées
+            dans l'application.
+        </para>
+
+        <para>
+            Afin d'utiliser des filtres, ils doivent d'abord être définis, puis attachés aux éléments
+            de mapping appropriés. Pour définir un filtre, utilisez l'élément <literal>&lt;filter-def/&gt;</literal>
+            dans un élément <literal>&lt;hibernate-mapping/&gt;</literal> :
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="myFilter">
+    <filter-param name="myFilterParam" type="string"/>
+</filter-def>]]></programlisting>
+
+        <para>
+            Puis, ce filtre peut être attaché à une classe :
+        </para>
+
+        <programlisting><![CDATA[<class name="myClass" ...>
+    ...
+    <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</class>]]></programlisting>
+
+        <para>
+            ou à une collection :
+        </para>
+
+        <programlisting><![CDATA[<set ...>
+    <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</set>]]></programlisting>
+
+        <para>
+            ou même aux deux (ou à plusieurs de chaque) en même temps.
+        </para>
+
+        <para>
+            Les méthodes sur <literal>Session</literal> sont : <literal>enableFilter(String filterName)</literal>,
+            <literal>getEnabledFilter(String filterName)</literal>, et <literal>disableFilter(String filterName)</literal>.
+            Par défaut, les filtres <emphasis>ne sont pas</emphasis> activés pour une session donnée ;
+            ils doivent être explicitement activés en appelant la méthode
+            <literal>Session.enabledFilter()</literal>, laquelle retourne une instance de l'interface
+            <literal>Filter</literal>. Utiliser le simple filtre défini au-dessus ressemblerait à :
+        </para>
+
+        <programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
+
+        <para>
+            Notez que des méthodes sur l'interface org.hibernate.Filter autorisent le chaînage de beaucoup
+            de méthodes communes d'Hibernate.
+        </para>
+
+        <para>
+            Un exemple complet, utilisant des données temporelles avec une structure de date
+            d'enregistrement effectif :
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="effectiveDate">
+    <filter-param name="asOfDate" type="date"/>
+</filter-def>
+
+<class name="Employee" ...>
+...
+    <many-to-one name="department" column="dept_id" class="Department"/>
+    <property name="effectiveStartDate" type="date" column="eff_start_dt"/>
+    <property name="effectiveEndDate" type="date" column="eff_end_dt"/>
+...
+    <!--
+        Note that this assumes non-terminal records have an eff_end_dt set to
+        a max db date for simplicity-sake
+    -->
+    <filter name="effectiveDate"
+            condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+</class>
+
+<class name="Department" ...>
+...
+    <set name="employees" lazy="true">
+        <key column="dept_id"/>
+        <one-to-many class="Employee"/>
+        <filter name="effectiveDate"
+                condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Puis, afin de s'assurer que vous pouvez toujours récupérer les enregistrements actuellement
+            effectifs, activez simplement le filtre sur la session avant de récupérer des données des
+            employés :
+        </para>
+
+<programlisting><![CDATA[Session session = ...;
+session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
+List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
+         .setLong("targetSalary", new Long(1000000))
+         .list();
+]]></programlisting>
+
+        <para>
+            Dans le HQL ci-dessus, bien que nous ayons seulement mentionné une contrainte de
+            salaire sur les resultats, à cause du filtre activé, la requête retournera seulement
+            les employés actuellement actifs qui ont un salaire supérieur à un million de dollars.
+        </para>
+
+        <para>
+            A noter : si vous prévoyez d'utiliser des filtres avec des jointures externes (soit
+            à travers HQL, soit par le chargement) faites attention à la direction de l'expression
+            de condition. Il est plus sûr de la positionner pour les jointures externes à gauche ;
+            en général, placez le paramètre d'abord, suivi du(des) nom(s) de colonne après l'opérateur.
+        </para>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/inheritance_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/inheritance_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/inheritance_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,483 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="inheritance">
+    <title>Mapping d'héritage de classe</title>
+
+    <sect1 id="inheritance-strategies" revision="3">
+        <title>Les trois stratégies</title>
+
+        <para>
+            Hibernate supporte les trois stratégies d'héritage de base :
+        </para>
+
+        <itemizedlist>
+        <listitem>
+        <para>
+            une table par hiérarchie de classe (table per class hierarchy)
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            une table par classe fille (table per subclass)
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            une table par classe concrète (table per concrete class)
+        </para>
+        </listitem>
+        </itemizedlist>
+
+        <para>
+            Hibernate supporte en plus une quatrièmestratégie, légèrement différente, qui supporte le polymorphisme :
+        </para>
+
+        <itemizedlist>
+        <listitem>
+        <para>
+            le polymorphisme implicite
+        </para>
+        </listitem>
+        </itemizedlist>
+
+        <para>
+            Il est possible d'utiliser différentes stratégies de mapping pour différentes branches d'une même
+            hiérarchie d'héritage, et alors d'employer le polymorphisme implicite pour réaliser le
+            polymorphisme à travers toute la hiérarchie. Pourtant, Hibernate ne supporte pas de mélanger
+            des mappings <literal>&lt;subclass&gt;</literal> et
+            <literal>&lt;joined-subclass&gt;</literal> et <literal>&lt;union-subclass&gt;</literal>
+            pour le même élément <literal>&lt;class&gt;</literal> racine.
+            Il est possible de mélanger ensemble les stratégies d'une table par hiérarchie et d'une
+            table par sous-classe, pour le même élément <literal>&lt;class&gt;</literal>, en combinant
+            les éléments <literal>&lt;subclass&gt;</literal> et <literal>&lt;join&gt;</literal> (voir dessous).
+        </para>
+
+        <para>
+            Il est possible de définir des mappings de <literal>subclass</literal>, <literal>union-subclass</literal>,
+            et <literal>joined-subclass</literal> dans des documents de mapping séparés, directement sous
+            <literal>hibernate-mapping</literal>. Ceci vous permet d'étendre une hiérarchie de classe juste en
+            ajoutant un nouveau fichier de mapping. Vous devez spécifier un attribut <literal>extends</literal>
+            dans le mapping de la sous-classe, en nommant une super-classe précédemment mappée. Note :
+            précédemment cette foncionnalité rendait l'ordre des documents de mapping important. Depuis
+            Hibernate3, l'ordre des fichier de mapping n'importe plus lors de l'utilisation du mot-clef "extends".
+            L'ordre à l'intérieur d'un simple fichier de mapping impose encore de définir les classes mères
+            avant les classes filles.
+         </para>
+
+         <programlisting><![CDATA[
+ <hibernate-mapping>
+     <subclass name="DomesticCat" extends="Cat" discriminator-value="D">
+          <property name="name" type="string"/>
+     </subclass>
+ </hibernate-mapping>]]></programlisting>
+
+
+        <sect2 id="inheritance-tableperclass" >
+        <title>Une table par hiérarchie de classe</title>
+
+        <para>
+            Supposons que nous ayons une interface <literal>Payment</literal>, implémentée
+            par <literal>CreditCardPayment</literal>, <literal>CashPayment</literal>,
+            <literal>ChequePayment</literal>. La stratégie une table par hiérarchie serait :
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        ...
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        ...
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            Une seule table est requise. Une grande limitation de cette
+            stratégie est que les colonnes déclarées par les classes filles, telles que <literal>CCTYPE</literal>,
+            ne peuvent avoir de contrainte <literal>NOT NULL</literal>.
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-tablepersubclass">
+        <title>Une table par classe fille</title>
+
+        <para>
+            La stratégie une table par classe fille serait :
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        ...
+    </joined-subclass>
+</class>]]></programlisting>
+
+        <para>
+            Quatre tables sont requises. Les trois tables des classes filles ont
+            une clé primaire associée à la table classe mère (le modèle relationnel
+            est une association un-vers-un).
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-tablepersubclass-discriminator" revision="2">
+        <title>Une table par classe fille, en utilisant un discriminant</title>
+
+        <para>
+            Notez que l'implémentation Hibernate de la stratégie un table par
+            classe fille ne nécessite pas de colonne discriminante dans la table
+            classe mère. D'autres implémentations de mappers Objet/Relationnel utilisent
+            une autre implémentation de la stratégie une table par classe fille qui nécessite
+            une colonne de type discriminant dans la table de la classe mère. L'approche
+            prise par Hibernate est plus difficile à implémenter mais plus correcte
+        d'une point de vue relationnel. Si vous aimeriez utiliser
+            une colonne discriminante avec la stratégie d'une table par classe fille, vous pourriez combiner
+            l'utilisation de <literal>&lt;subclass&gt;</literal> et
+            <literal>&lt;join&gt;</literal>, comme suit :
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <join table="CREDIT_PAYMENT">
+            <key column="PAYMENT_ID"/>
+            <property name="creditCardType" column="CCTYPE"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        <join table="CASH_PAYMENT">
+            <key column="PAYMENT_ID"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        <join table="CHEQUE_PAYMENT" fetch="select">
+            <key column="PAYMENT_ID"/>
+            ...
+        </join>
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            La déclaration optionnelle <literal>fetch="select"</literal> indique à Hibernate
+            de ne pas récupérer les données de la classe fille <literal>ChequePayment</literal> par une jointure externe lors des requêtes sur la classe mère.
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
+            <title>Mélange d'une table par hiérarchie de classe avec une table par classe fille</title>
+
+        <para>
+            Vous pouvez même mélanger les stratégies d'une table par hiérarchie de classe et d'une table par classe fille en utilisant cette approche :
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <join table="CREDIT_PAYMENT">
+            <property name="creditCardType" column="CCTYPE"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        ...
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        ...
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            Pour importe laquelle de ces stratégies, une association polymorphique vers la classe racine
+            <literal>Payment</literal> est mappée en utilisant <literal>&lt;many-to-one&gt;</literal>.
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="inheritance-tableperconcrete" revision="2">
+        <title>Une table par classe concrète</title>
+
+        <para>
+            Il y a deux manières d'utiliser la stratégie d'une table par classe concrète. La première
+            est d'employer <literal>&lt;union-subclass&gt;</literal>.
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="sequence"/>
+    </id>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </union-subclass>
+    <union-subclass name="CashPayment" table="CASH_PAYMENT">
+        ...
+    </union-subclass>
+    <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        ...
+    </union-subclass>
+</class>]]></programlisting>
+
+        <para>
+            Trois tables sont nécessaires pour les classes filles. Chaque table définit des colonnes
+            pour toutes les propriétés de la classe, incluant les propriétés héritéés.
+        </para>
+
+        <para>
+            La limitation de cette approche est que si une propriété est mappée sur la classe mère, le nom
+            de la colonne doit être le même pour toutes les classes filles. (Nous pourrions être plus souple
+            dans une future version d'Hibernate).
+            La stratégie du générateur d'identifiant n'est pas permise dans l'héritage de classes filles par
+            union, en effet la valeur (NdT : seed) de la clef primaire
+            doit être partagée par toutes les classes filles "union" d'une hiérarchie.
+        </para>
+
+        <para>
+            Si votre classe mère est abstraite, mappez la avec <literal>abstract="true"</literal>.
+            Bien sûr, si elle n'est pas abstraite, une table supplémentaire (par défaut,
+            <literal>PAYMENT</literal> dans l'exemple ci-dessus) est requise pour contenir des instances
+            de la classe mère.
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-tableperconcreate-polymorphism">
+        <title>Une table par classe concrète, en utilisant le polymorphisme implicite</title>
+
+        <para>
+            Une approche alternative est l'emploi du polymorphisme implicite :
+        </para>
+
+        <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+    <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CREDIT_AMOUNT"/>
+    ...
+</class>
+
+<class name="CashPayment" table="CASH_PAYMENT">
+    <id name="id" type="long" column="CASH_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CASH_AMOUNT"/>
+    ...
+</class>
+
+<class name="ChequePayment" table="CHEQUE_PAYMENT">
+    <id name="id" type="long" column="CHEQUE_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CHEQUE_AMOUNT"/>
+    ...
+</class>]]></programlisting>
+
+        <para>
+            Notez que nulle part nous ne mentionnons l'interface <literal>Payment</literal> explicitement.
+            Notez aussi que des propriétés de <literal>Payment</literal> sont mappées dans
+            chaque classe fille. Si vous voulez éviter des duplications, considérez l'utilisation des
+            entités XML (cf. <literal>[ &lt;!ENTITY allproperties SYSTEM "allproperties.xml"&gt; ]</literal>
+            dans la déclaration du <literal>DOCTYPE</literal> et <literal>&amp;allproperties;</literal> dans le mapping).
+        </para>
+
+        <para>
+            L'inconvénient de cette approche est qu'Hibernate ne génère pas d'<literal>UNION</literal>s SQL
+            lors de l'exécution des requêtes polymorphiques.
+        </para>
+
+        <para>
+            Pour cette stratégie de mapping, une association polymorphique pour <literal>Payment</literal>
+            est habituellement mappée en utilisant <literal>&lt;any&gt;</literal>.
+        </para>
+
+        <programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
+    <meta-value value="CREDIT" class="CreditCardPayment"/>
+    <meta-value value="CASH" class="CashPayment"/>
+    <meta-value value="CHEQUE" class="ChequePayment"/>
+    <column name="PAYMENT_CLASS"/>
+    <column name="PAYMENT_ID"/>
+</any>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="inheritace-mixingpolymorphism">
+        <title>Mélange du polymorphisme implicite avec d'autres mappings d'héritage</title>
+
+        <para>
+            Il y a une chose supplémentaire à noter à propos de ce mapping. Puisque les classes filles sont
+            chacune mappées avec leur propre élément <literal>&lt;class&gt;</literal> (et puisque
+            <literal>Payment</literal> est juste une interface), chaque classe fille pourrait
+            facilement faire partie d'une autre hiérarchie
+            d'héritage ! (Et vous pouvez encore faire des requêtes polymorphiques pour l'interface <literal>Payment</literal>).
+       </para>
+
+        <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+    <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="CREDIT_CARD" type="string"/>
+    <property name="amount" column="CREDIT_AMOUNT"/>
+    ...
+    <subclass name="MasterCardPayment" discriminator-value="MDC"/>
+    <subclass name="VisaPayment" discriminator-value="VISA"/>
+</class>
+
+<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
+    <id name="id" type="long" column="TXN_ID">
+        <generator class="native"/>
+    </id>
+    ...
+    <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="amount" column="CASH_AMOUNT"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="amount" column="CHEQUE_AMOUNT"/>
+        ...
+    </joined-subclass>
+</class>]]></programlisting>
+
+        <para>
+            Encore une fois, nous ne mentionnons pas explicitement <literal>Payment</literal>.
+            Si nous exécutons une requête sur l'interface <literal>Payment</literal> - par
+            exemple, <literal>from Payment</literal> - Hibernate retournera
+            automatiquement les instances de <literal>CreditCardPayment</literal>
+            (et ses classes filles puisqu'elles implémentent aussi <literal>Payment</literal>),
+            <literal>CashPayment</literal> et <literal>ChequePayment</literal> mais pas
+            les instances de <literal>NonelectronicTransaction</literal>.
+        </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="inheritance-limitations">
+        <title>Limitations</title>
+
+        <para>
+            Il y a certaines limitations à l'approche du "polymorphisme implicite"
+            pour la stratégie de mapping d'une table par classe concrète.
+            Il y a plutôt moins de limitations restrictives aux mappings <literal>&lt;union-subclass&gt;</literal>.
+        </para>
+
+        <para>
+            La table suivante montre les limitations des mappings d'une table par classe concrète, et du polymorphisme implicite, dans Hibernate.
+        </para>
+
+        <table frame="topbot">
+            <title>Caractéristiques du mapping d'héritage</title>
+            <tgroup cols='8' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="1*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <colspec colname='c6' colwidth="1*"/>
+            <colspec colname='c7' colwidth="1*"/>
+            <colspec colname='c8' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Stratégie d'héritage</entry>
+              <entry>many-to-one polymorphique</entry>
+              <entry>one-to-one polymorphique</entry>
+              <entry>one-to-many polymorphique</entry>
+              <entry>many-to-many polymorphique</entry>
+              <entry><literal>load()/get()</literal> polymorphique</entry>
+              <entry>Requêtes polymorphiques</entry>
+              <entry>Jointures polymorphiques</entry>
+              <entry>Récupération par jointure externe</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>une table par hiérarchie de classe</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal></entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>supportée</emphasis></entry>
+            </row>
+            <row>
+                <entry>une table par classe fille</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal></entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>supportée</emphasis></entry>
+            </row>
+            <row>
+                <entry>une table par classe concrète (union-subclass)</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal> (pour <literal>inverse="true"</literal> seulement)</entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>supportée</emphasis></entry>
+            </row>
+            <row>
+                <entry>une table par classe concrète (polymorphisme implicite)</entry>
+                <entry><literal>&lt;any&gt;</literal></entry>
+                <entry><emphasis>non supporté</emphasis></entry>
+                <entry><emphasis>non supporté</emphasis></entry>
+                <entry><literal>&lt;many-to-any&gt;</literal></entry>
+                <entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><emphasis>non supportées</emphasis></entry>
+                <entry><emphasis>non supportée</emphasis></entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/performance.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/performance.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/performance.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1451 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="performance">
+    <title>Améliorer les performances</title>
+
+    <sect1 id="performance-fetching" revision="2">
+        <title>Stratégies de chargement</title>
+
+        <para>
+            Une <emphasis>stratégie de chargement</emphasis> est une stratégie qu'Hibernate va
+            utiliser pour récupérer des objets associés si l'application à besoin de naviguer à 
+            travers une association.
+            Les stratégies de chargement peuvent être déclarées dans les méta-données de l'outil
+            de mapping objet relationnel ou surchargées par une requête de type HQL ou <literal>Criteria</literal>
+            particulière.
+        </para>
+
+        <para>
+            Hibernate3 définit les stratégies de chargement suivantes :
+        </para>
+
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <emphasis>Chargement par jointure</emphasis> - Hibernate récupère 
+                    l'instance associée ou la collection dans un même <literal>SELECT</literal>,
+                    en utilisant un <literal>OUTER JOIN</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Chargement par select</emphasis> - Un second <literal>SELECT</literal>
+                    est utilisé pour récupérer l'instance associée ou la collection. A moins
+                    que vous ne désactiviez explicitement le chargement tardif en spécifiant
+                    <literal>lazy="false"</literal>, ce second select ne sera exécuté que lorsque
+                    vous accéderez réellement à l'association.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Chargement par sous-select</emphasis> - Un second <literal>SELECT</literal>
+                    est utilisé pour récupérer les associations pour toutes les entités récupérées dans
+                    une requête ou un chargement préalable. A moins
+                    que vous ne désactiviez explicitement le chargement tardif en spécifiant
+                    <literal>lazy="false"</literal>, ce second select ne sera exécuté que lorsque
+                    vous accéderez réellement à l'association.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Chargement par lot</emphasis> - Il s'agit d'une stratégie d'optimisation
+                    pour le chargement par select - Hibernate récupère un lot
+                    d'instances ou de collections en un seul <literal>SELECT</literal> en spécifiant
+                    une liste de clé primaire ou de clé étrangère.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            Hibernate fait également la distinction entre :
+        </para>
+
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <emphasis>Chargement immédiat</emphasis> - Une association, une collection ou
+                    un attribut est chargé immédiatement lorsque l'objet auquel appartient cet
+                    élément est chargé.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Chargement tardif d'une collection</emphasis> - Une collection est
+                    chargée lorque l'application invoque une méthode sur cette collection (il s'agit
+                    du mode de chargement par défaut pour les collections).
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Chargement "super tardif" d'une collection</emphasis> - les
+                    éléments de la collection sont récupérés individuellement depuis la base de données
+                    lorsque nécessaire.
+                    Hibernate essaie de ne pas charger toute la collection en mémoire sauf si cela est
+                    absolument nécessaire (bien adapté aux très grandes collections).
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Chargement par proxy</emphasis> - une association vers un seul
+                    objet est chargée lorsqu'une méthode autre que le getter sur l'identifiant est
+                    appelée sur l'objet associé. 
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Chargement "sans proxy"</emphasis> - une association vers un seul objet
+                    est chargée lorsque l'on accède à cet objet. Par rapport au chargement par proxy,
+                    cette approche est moins tardif (l'association est quand même chargée même
+                    si on n'accède qu'à l'identifiant) mais plus transparente car il n'y a pas de proxy
+                    visible dans l'application. Cette approche requiert une instrumentation du bytecode
+                    à la compilation et est rarement nécessaire.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Chargement tardif des attributs</emphasis> - Un attribut ou un
+                    objet associé seul est chargé lorsque l'on y accède. Cette approche requiert 
+                    une instrumentation du bytecode à la compilation et est rarement nécessaire.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            Nous avons ici deux notions orthogonales : <emphasis>quand</emphasis> l'association est
+            chargée et <emphasis>comment</emphasis> (quelle requête SQL est utilisée). Il ne faut
+            pas confondre les deux. Le mode de chargement est utilisé pour améliorer les performances.
+            On peut utiliser le mode tardif pour définir un contrat sur quelles données sont toujours
+            accessibles sur une instance détachée d'une classe particulière.
+        </para>
+ 
+        <sect2 id="performance-fetching-lazy">
+            <title>Travailler avec des associations chargées tardivement</title>
+            
+            <para>
+                Par défaut, Hibernate3 utilise le chargement tardif par select pour les collections
+                et le chargement tardif par proxy pour les associations vers un seul objet.
+                Ces valeurs par défaut sont valables pour la plupart des associations dans la
+                plupart des applications.
+            </para>
+            
+            <para>
+                <emphasis>Note :</emphasis> si vous définissez
+                <literal>hibernate.default_batch_fetch_size</literal>, Hibernate va utiliser l'optimisation
+                du chargement par lot pour le chargement tardif (cette optimisation peut aussi
+                être activée à un niveau de granularité plus fin).
+            </para>
+            
+            <para>
+                Cependant, le chargement tardif pose un problème qu'il faut connaitre. L'accès à 
+                une association définie comme "tardive", hors du contexte d'une session hibernate
+                ouverte, va conduire à une exception. Par exemple :
+            </para>
+        
+            <programlisting><![CDATA[s = sessions.openSession();
+Transaction tx = s.beginTransaction();
+            
+User u = (User) s.createQuery("from User u where u.name=:userName")
+    .setString("userName", userName).uniqueResult();
+Map permissions = u.getPermissions();
+
+tx.commit();
+s.close();
+
+Integer accessLevel = (Integer) permissions.get("accounts");  // Error!]]></programlisting>
+
+            <para>
+                Etant donné que la collection des permissions n'a pas été initialisée
+                avant que la <literal>Session</literal> soit fermée, la collection n'est
+                pas capable de se charger. <emphasis>Hibernate ne supporte pas le chargement
+                tardif pour des objets détachés</emphasis>. La solution à ce problème est de
+                déplacer le code qui lit la collection avant le "commit" de la transaction.
+            </para>
+    
+            <para>
+                Une autre alternative est d'utiliser une collection ou une association non
+                "tardive" en spécifiant <literal>lazy="false"</literal> dans le mapping de
+                l'association.
+                Cependant il est prévu que le chargement tardif soit utilisé pour quasiment
+                toutes les collections ou associations. Si vous définissez trop d'associtions
+                non "tardives" dans votre modèle objet, Hibernate va finir par devoir charger
+                toute la base de données en mémoire à chaque transaction !
+            </para>
+    
+            <para>
+                D'un autre côté, on veut souvent choisir un chargement par jointure (qui est par
+                défaut non tardif) à la place du chargement par select dans une transaction particulière.
+                Nous allons maintenant voir comment adapter les stratégies de chargement. Dans Hibernate3
+                les mécanismes pour choisir une stratégie de chargement sont identiques que
+                l'on ait une association vers un objet simple ou vers une collection.
+            </para>
+        
+        </sect2>
+        
+        <sect2 id="performance-fetching-custom" revision="4">
+            <title>Personnalisation des stratégies de chargement</title>
+            
+            <para>
+                Le chargement par select (mode par défaut) est très vulnérable au problème du
+                N+1 selects, du coup vous pouvez avoir envie d'activer le chargement par jointure
+                dans les fichiers de mapping :
+            </para>
+            
+            <programlisting><![CDATA[<set name="permissions" 
+            fetch="join">
+    <key column="userId"/>
+    <one-to-many class="Permission"/>
+</set]]></programlisting>
+
+           <programlisting><![CDATA[<many-to-one name="mother" class="Cat" fetch="join"/>]]></programlisting>
+
+            <para>
+                La stratégie de chargement définie à l'aide du mot <literal>fetch</literal> dans les fichiers
+                de mapping affecte :
+            </para>
+            
+        <itemizedlist>
+             <listitem>
+                <para>
+                    La récupération via <literal>get()</literal> ou <literal>load()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    La récupération implicite lorsque l'on navigue à travers une association
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Les requêtes de type <literal>Criteria</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Les requêtes HQL si l'on utilise le chargement par <literal>subselect</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+            <para>
+                Quelle que soit la stratégie de chargement que vous utilisez, la partie du graphe
+                d'objets qui est définie comme non "tardive" sera chargée en mémoire. Cela peut
+                mener à l'exécution de plusieurs selects successifs pour une seule requête HQL.
+            </para>
+
+            <para>
+                On n'utilise pas souvent les documents de mapping pour adapter le chargement.
+                Au lieu de cela, on conserve le comportement par défaut et on le surcharge pour
+                une transaction particulière en utilisant <literal>left join fetch</literal>
+                dans les requêtes HQL. Cela indique à hibernate à Hibernate de charger l'association
+                de manière agressive lors du premier select en utilisant une jointure externe.
+                Dans l'API Criteria vous pouvez utiliser la méthode 
+                <literal>setFetchMode(FetchMode.JOIN)</literal>
+            </para>
+            
+            <para>
+                Si vous ne vous sentez pas prêt à modifier la stratégie de chargement utilisé
+                par <literal>get()</literal> ou <literal>load()</literal>, vous pouvez juste
+                utiliser une requête de type <literal>Criteria</literal>  comme par exemple :
+            </para>
+            
+            <programlisting><![CDATA[User user = (User) session.createCriteria(User.class)
+                .setFetchMode("permissions", FetchMode.JOIN)
+                .add( Restrictions.idEq(userId) )
+                .uniqueResult();]]></programlisting>
+                
+            <para>
+                (Il s'agit de l'équivalent pour Hibernate de ce que d'autres outils de mapping
+                appellent un "fetch plan" ou "plan de chargement")
+            </para>
+
+            <para>
+                Une autre manière complètement différente d'éviter le problème des N+1 selects
+                est d'utiliser le cache de second niveau.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-proxies" revision="2">
+            <title>Proxys pour des associations vers un seul objet</title>
+
+            <para>
+                Le chargement tardif des collections est implémenté par Hibernate en utilisant
+                ses propres implémentations pour des collections persistantes. Si l'on veut un
+                chargement tardif pour des associations vers un seul objet métier il faut utiliser
+                un autre mécanisme. L'entité qui est pointée par l'association doit être masquée
+                derrière un proxy. Hibernate implémente l'initialisation tardive des proxys sur des
+                objets persistents via une mise à jour à chaud du bytecode (à l'aide de l'excellente
+                librairie CGLIB).
+            </para>
+
+            <para>
+                Par défaut, Hibernate génère des proxys (au démarrage) pour toutes les classes
+                persistantes et les utilise pour activer le chargement tardif des associations
+                <literal>many-to-one</literal> et <literal>one-to-one</literal>.
+            </para>
+
+            <para>
+                Le fichier de mapping peut déclarer une interface qui sera utilisée par le proxy
+                d'interfaçage pour cette classe à l'aide de l'attribut <literal>proxy</literal>.
+                Par défaut Hibernate utilises une sous classe de la classe persistante.
+                <emphasis>Il faut que les classes pour lesquelles on ajoute un proxy implémentent
+                un constructeur par défaut de visibilité au moins package. Ce constructeur est
+                recommandé pour toutes les classes persistantes !</emphasis>
+            </para>
+
+
+
+            <para>
+                Il y a quelques précautions à prendre lorsque l'on étend cette approche à des classes
+          polymorphiques, exemple :
+            </para>
+
+            <programlisting><![CDATA[<class name="Cat" proxy="Cat">
+        ......
+        <subclass name="DomesticCat" proxy="DomesticCat">
+            .....
+        </subclass>
+    </class>]]></programlisting>
+
+        <para>
+            Tout d'abord, les instances de <literal>Cat</literal> ne pourront jamais être "castées"
+        en <literal>DomesticCat</literal>, même si l'instance sous jacente est une instance 
+        de <literal>DomesticCat</literal> :
+        </para>
+        
+        <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id);  // instancie un proxy (n'interroge pas la base de données)
+if ( cat.isDomesticCat() ) {                  // interroge la base de données pour initialiser le proxy
+    DomesticCat dc = (DomesticCat) cat;       // Erreur !
+    ....
+}]]></programlisting>
+    
+        <para>
+            Deuxièmement, il est possible de casser la notion d'<literal>==</literal> des proxy.
+        </para>
+            
+        <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id);            // instancie un proxy Cat
+DomesticCat dc = 
+    (DomesticCat) session.load(DomesticCat.class, id);  // acquiert un nouveau proxy DomesticCat
+System.out.println(cat==dc);                            // faux]]></programlisting>
+        
+        <para>
+            Cette situation n'est pas si mauvaise qu'il n'y parait. Même si nous avons deux
+        références à deux objets proxys différents, l'instance de base sera quand même le même objet :
+        </para>
+    
+        <programlisting><![CDATA[cat.setWeight(11.0);  // interroge la base de données pour initialiser le proxy
+System.out.println( dc.getWeight() );  // 11.0]]></programlisting>
+
+        <para>
+            Troisièmement, vous ne pourrez pas utiliser un proxy CGLIB pour une classe <literal>final</literal>
+        ou pour une classe contenant la moindre méthode <literal>final</literal>.
+        </para>
+        
+        <para>
+            Enfin, si votre objet persistant obtient une ressource à l'instanciation (par
+        example dans les initialiseurs ou dans le contructeur par défaut), alors ces ressources
+        seront aussi obtenues par le proxy. La classe proxy est vraiment une sous classe de la classe
+        persistante.
+        </para>
+        
+        <para>
+            Ces problèmes sont tous dus aux limitations fondamentales du modèle d'héritage unique de Java.
+        Si vous souhaitez éviter ces problèmes, vos classes persistantes doivent chacune implémenter
+        une interface qui déclare ses méthodes métier. Vous devriez alors spécifier ces interfaces
+        dans le fichier de mapping :
+        </para>
+
+        <programlisting><![CDATA[<class name="CatImpl" proxy="Cat">
+    ......
+    <subclass name="DomesticCatImpl" proxy="DomesticCat">
+        .....
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            où <literal>CatImpl</literal> implémente l'interface <literal>Cat</literal> et <literal>DomesticCatImpl</literal> 
+        implémente l'interface <literal>DomesticCat</literal>. Ainsi, des proxys pour les instances de 
+        <literal>Cat</literal> et <literal>DomesticCat</literal> pourraient être retournées par <literal>load()</literal> 
+        ou <literal>iterate()</literal> (Notez que <literal>list()</literal> ne retourne généralement pas de proxy).
+        </para>
+
+        <programlisting><![CDATA[Cat cat = (Cat) session.load(CatImpl.class, catid);
+Iterator iter = session.iterate("from CatImpl as cat where cat.name='fritz'");
+Cat fritz = (Cat) iter.next();]]></programlisting>
+        
+        <para>
+            Les relations sont aussi initialisées tardivement. Ceci signifie que vous 
+        devez déclarer chaque propriété comme étant de type <literal>Cat</literal>, 
+        et non <literal>CatImpl</literal>.
+        </para>
+        
+        <para>
+            Certaines opérations ne nécessitent pas l'initialisation du proxy
+        </para>
+        
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>equals()</literal>, si la classe persistante ne surcharge pas
+                    <literal>equals()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>hashCode()</literal>, si la classe persistante ne surcharge pas
+                    <literal>hashCode()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Le getter de l'identifiant
+                </para>
+            </listitem>
+        </itemizedlist>
+            
+        <para>
+            Hibernate détectera les classes qui surchargent <literal>equals()</literal> ou
+            <literal>hashCode()</literal>.
+        </para>
+
+        <para>
+            Eh choisissant <literal>lazy="no-proxy"</literal> au lieu de <literal>lazy="proxy"</literal>
+            qui est la valeur par défaut, il est possible d'éviter les problèmes liés au transtypage.
+            Il faudra alors une instrumentation du bytecode à la compilation et toutes les opérations
+            résulterons immédiatement en une initialisation du proxy.
+        </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-initialization"  revision="1">
+            <title>Initialisation des collections et des proxys</title>
+
+            <para>
+                Une exception de type <literal>LazyInitializationException</literal> sera renvoyée par hibernate
+                si une collection ou un proxy non initialisé est accédé en dehors de la portée de la <literal>Session</literal>,
+                e.g. lorsque l'entité à laquelle appartient la collection ou qui a une référence vers le proxy est
+                dans l'état "détachée".
+            </para>
+
+        <para>
+            Parfois, nous devons nous assurer qu'un proxy ou une collection est initialisée avant de 
+            fermer la <literal>Session</literal>. Bien sûr, nous pouvons toujours forcer l'initialisation
+            en appelant par exemple <literal>cat.getSex()</literal> ou <literal>cat.getKittens().size()</literal>.
+            Mais ceci n'est pas très lisible pour les personnes parcourant le code et n'est pas très générique.
+        </para>
+        
+        <para>
+            Les méthodes statiques <literal>Hibernate.initialize()</literal> et <literal>Hibernate.isInitialized()</literal>
+            fournissent à l'application un moyen de travailler avec des proxys ou des collections initialisés.
+            <literal>Hibernate.initialize(cat)</literal> forcera l'initialisation d'un proxy de <literal>cat</literal>, 
+            si tant est que sa <literal>Session</literal> est ouverte. <literal>Hibernate.initialize( cat.getKittens() )</literal> 
+            a le même effet sur la collection kittens. 
+        </para>
+
+            <para>
+                Une autre option est de conserver la <literal>Session</literal> ouverte jusqu'à
+                ce que toutes les collections et tous les proxys aient été chargés. Dans certaines
+                architectures applicatives, particulièrement celles ou le code d'accès aux données
+                via hiberante et le code qui utilise ces données sont dans des couches applicatives
+                différentes ou des processus physiques différents, il peut devenir problématique
+                de garantir que la <literal>Session</literal> est ouverte lorsqu'une collection
+                est initialisée. Il y a deux moyens de traiter ce problème :
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        Dans une application web, un filtre de servlet peut être utilisé pour
+                        fermer la <literal>Session</literal> uniquement lorsque la requête
+                        a été entièrement traitée, lorsque le rendu de la vue est fini
+                        (il s'agit du pattern <emphasis>Open Session in View</emphasis>).
+                        Bien sûr, cela demande plus d'attention à la bonne gestion des exceptions
+                        de l'application. Il est d'une importance vitale que la <literal>Session</literal>
+                        soit fermée et la transaction terminée avant que l'on rende la main à l'utilisateur
+                        même si une exception survient durant le traitement de la vue. 
+                        Voir le wiki Hibernate pour des exemples sur le pattern
+                        "Open Session in View".
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Dans une application avec une couche métier séparée, la couche contenant
+                        la logique métier doit "préparer" toutes les collections qui seront
+                        nécessaires à la couche web avant de retourner les données. Cela signifie
+                        que la couche métier doit charger toutes les données et retourner toutes
+                        les données déjà initialisées à la couche de présentation/web pour un
+                        cas d'utilisation donné. En général l'application appelle la méthode
+                        <literal>Hibernate.initialize()</literal> pour chaque collection nécessaire
+                        dans la couche web (cet appel doit être fait avant la fermeture de la session)
+                        ou bien récupère les collections de manière agressive à l'aide d'une requête
+                        HQL avec une clause <literal>FETCH</literal> ou à l'aide du mode
+                        <literal>FetchMode.JOIN</literal> pour une requête de type <literal>Criteria</literal>.
+                        Cela est en général plus facile si vous utilisez le pattern <emphasis>Command</emphasis>
+                        plutôt que <emphasis>Session Facade</emphasis>.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Vous pouvez également attacher à une <literal>Session</literal> un objet chargé
+                        au préalable à l'aide des méthodes <literal>merge()</literal> ou <literal>lock()</literal>
+                        avant d'accéder aux collections (ou aux proxys) non initialisés. Non, Hibernate ne
+                        fait pas, et ne doit pas faire, cela automatiquement car cela pourrait introduire
+                        une sémantique transactionnelle ad hoc.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Parfois, vous ne voulez pas initialiser une grande collection mais vous avez quand même
+                besoin d'informations sur elle (comme sa taille) ou un sous ensemble de ses données
+            </para>
+
+            <para>
+                Vous pouvez utiliser un filtre de collection pour récupérer sa taille sans l'initialiser :
+            </para>
+
+            <programlisting><![CDATA[( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()]]></programlisting>
+
+            <para>
+                La méthode <literal>createFilter()</literal> est également utilisée pour récupérer
+                de manière efficace des sous ensembles d'une collection sans avoir besoin de l'initialiser
+                dans son ensemble.
+            </para>
+
+            <programlisting><![CDATA[s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();]]></programlisting>
+
+        </sect2>
+
+
+      <sect2 id="performance-fetching-batch">
+        <title>Utiliser le chargement par lot</title>
+
+        <para>
+            Pour améliorer les performances, Hibernate peut utiliser le chargement par lot
+            ce qui veut dire qu'Hibernate peut charger plusieurs proxys (ou collections) non initialisés en une seule 
+            requête lorsque l'on accède à l'un de ces proxys. Le chargement par lot est une optimisation 
+            intimement liée à la stratégie de chargement tardif par select. Il y a deux moyens d'activer le  
+            chargement par lot : au niveau de la classe et au niveau de la collection.
+        </para>
+
+        <para>
+            Le chargement par lot pour les classes/entités est plus simple à comprendre. Imaginez que vous ayez la
+            situation suivante à l'exécution : vous avez 25 instances de <literal>Cat</literal> 
+            chargées dans une <literal>Session</literal>, chaque <literal>Cat</literal> a une référence 
+            à son <literal>owner</literal>, une <literal>Person</literal>.
+            La classe <literal>Person</literal> est mappée avec un proxy, <literal>lazy="true"</literal>. 
+            Si vous itérez sur tous les cats et appelez <literal>getOwner()</literal> sur chacun d'eux, 
+            Hibernate exécutera par défaut 25 <literal>SELECT</literal>, pour charger les owners
+            (initialiser le proxy). Vous pouvez paramétrer ce comportement en spécifiant une 
+            <literal>batch-size</literal> (taille du lot) dans le mapping de <literal>Person</literal> :
+        </para>
+
+            <programlisting><![CDATA[<class name="Person" batch-size="10">...</class>]]></programlisting>
+
+        <para>
+            Hibernate exécutera désormais trois requêtes, en chargeant respectivement 10, 
+            10, et 5 entités.
+        </para>
+
+        <para>
+            Vous pouvez aussi activer le chargement par lot pour les collections. Par exemple, 
+            si chaque <literal>Person</literal> a une collection chargée tardivement de 
+            <literal>Cat</literal>s, et que 10 personnes sont actuellement chargées dans la 
+            <literal>Session</literal>, itérer sur toutes les persons générera 10 <literal>SELECT</literal>s,
+            un pour chaque appel de <literal>getCats()</literal>. Si vous activez le chargement par lot pour la
+            collection <literal>cats</literal> dans le mapping de <literal>Person</literal>, Hibernate pourra
+            précharger les collections :
+        </para>
+
+        <programlisting><![CDATA[<class name="Person">
+    <set name="cats" batch-size="3">
+        ...
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Avec une taille de lot (<literal>batch-size</literal>) de 8, Hibernate chargera 
+        respectivement 3, 3, 3, et 1 collections en quatre <literal>SELECT</literal>s. 
+        Encore une fois, la valeur de l'attribut dépend du nombre de collections
+        non initialisées dans une <literal>Session</literal> particulière.
+        </para>
+
+        <para>
+            Le chargement par lot de collections est particulièrement utile si vous avez des 
+        arborescenses récursives d'éléments (typiquement, le schéma facture de 
+        matériels). (Bien qu'un <emphasis>sous ensemble</emphasis> ou un 
+        <emphasis>chemin matérialisé</emphasis> est sans doute une meilleure option pour
+        des arbres principalement en lecture.)
+        </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-subselect">
+            <title>Utilisation du chargement par sous select</title>
+
+            <para>
+                Si une collection ou un proxy vers un objet doit être chargé, Hibernate va tous les
+                charger en ré-exécutant la requête orignial dans un sous select. Cela fonctionne de la
+                même manière que le chargement par lot sans la possibilité de fragmenter le chargement.
+            </para>
+            
+            <!-- TODO: Write more about this -->
+
+        </sect2>
+        
+        <sect2 id="performance-fetching-lazyproperties">
+            <title>Utiliser le chargement tardif des propriétés</title>
+
+            <para>
+                Hibernate3 supporte le chargement tardif de propriétés individuelles. La technique
+                d'optimisation est également connue sous le nom de <emphasis>fetch groups</emphasis> (groupes
+                de chargement). Il faut noter qu'il s'agit principalement d'une fonctionnalité marketing
+                car en pratique l'optimisation de la lecture d'un enregistrement est beaucoup plus importante
+                que l'optimisation de la lecture d'une colonne. Cependant, la restriction du chargement à
+                certaines colonnes peut être pratique dans des cas extrèmes, lorsque des tables "legacy"
+                possèdent des centaines de colonnes et que le modèle de données ne peut pas être amélioré.
+            </para>
+
+            <para>
+                Pour activer le chargement tardif d'une propriété, il faut mettre l'attribut <literal>lazy</literal>
+                sur une propriété particulière du mapping :
+            </para>
+
+            <programlisting><![CDATA[<class name="Document">
+       <id name="id">
+        <generator class="native"/>
+    </id>
+    <property name="name" not-null="true" length="50"/>
+    <property name="summary" not-null="true" length="200" lazy="true"/>
+    <property name="text" not-null="true" length="2000" lazy="true"/>
+</class>]]></programlisting>
+
+            <para>
+                Le chargement tardif des propriétés requiert une instrumentation du bytecode lors de la
+                compilation ! Si les classes persistantes ne sont pas instrumentées, Hibernate ignorera de
+                manière silencieuse le mode tardif et retombera dans le mode de chargement immédiat.
+            </para>
+
+            <para>
+                Pour l'instrumentation du bytecode vous pouvez utiliser la tâche Ant suivante :
+            </para>
+
+            <programlisting><![CDATA[<target name="instrument" depends="compile">
+    <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
+        <classpath path="${jar.path}"/>
+        <classpath path="${classes.dir}"/>
+        <classpath refid="lib.class.path"/>
+    </taskdef>
+
+    <instrument verbose="true">
+        <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
+            <include name="*.class"/>
+        </fileset>
+    </instrument>
+</target>]]></programlisting>
+
+            <para>
+                Une autre façon (meilleure ?) pour éviter de lire plus de colonnes que
+                nécessaire au moins pour des transactions en lecture seule est d'utiliser
+                les fonctionnalités de projection des requêtes HQL ou Criteria. Cela évite
+                de devoir instrumenter le bytecode à la compilation et est certainement une
+                solution préférable.
+            </para>
+            
+            <para>
+                Vous pouvez forcer le mode de chargement agressif des propriétés en utilisant
+                <literal>fetch all properties</literal> dans les requêts HQL.
+            </para>
+
+        </sect2>
+    </sect1>    
+
+    <sect1 id="performance-cache" revision="1">
+        <title>Le cache de second niveau</title>
+
+        <para>
+            Une <literal>Session</literal> Hibernate est un cache de niveau transactionnel 
+        des données persistantes. Il est possible de configurer un cache de cluster ou de JVM 
+        (de niveau <literal>SessionFactory</literal> pour être exact) défini classe par classe 
+        et collection par collection. Vous pouvez même utiliser votr choix de cache
+        en implémentant le pourvoyeur (provider) associé.
+        Faites attention, les caches ne sont jamais avertis des modifications faites 
+        dans la base de données par d'autres applications (ils peuvent cependant être 
+        configurés pour régulièrement expirer les données en cache).
+        </para>
+        
+        <para>
+            Par défaut, Hibernate utilise EHCache comme cache de niveau JVM (le support 
+        de JCS est désormais déprécié et sera enlevé des futures versions d'Hibernate).
+        Vous pouvez choisir une autre implémentation en spécifiant le nom de la classe qui 
+        implémente <literal>org.hibernate.cache.CacheProvider</literal> en utilisant 
+        la propriété <literal>hibernate.cache.provider_class</literal>.
+        </para>
+
+        <table frame="topbot" id="cacheproviders" revision="1">
+            <title>Fournisseur de cache</title>
+            <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="3*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Cache</entry>
+              <entry>Classe pourvoyeuse</entry>
+              <entry>Type</entry>
+              <entry>Support en Cluster</entry>
+              <entry>Cache de requêtes supporté</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>Hashtable (ne pas utiliser en production)</entry>
+                <entry><literal>org.hibernate.cache.HashtableCacheProvider</literal></entry>
+                <entry>mémoire</entry>
+                <entry></entry>
+                <entry>oui</entry>
+            </row>
+            <row>
+                <entry>EHCache</entry>
+                <entry><literal>org.hibernate.cache.EhCacheProvider</literal></entry>
+                <entry>mémoire, disque</entry>
+                <entry></entry>
+                <entry>oui</entry>
+            </row>
+            <row>
+                <entry>OSCache</entry>
+                <entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
+                <entry>mémoire, disque</entry>
+                <entry></entry>
+                <entry>oui</entry>
+            </row>
+            <row>
+                <entry>SwarmCache</entry>
+                <entry><literal>org.hibernate.cache.SwarmCacheProvider</literal></entry>
+                <entry>en cluster (multicast ip)</entry>
+                <entry>oui (invalidation de cluster)</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>JBoss TreeCache</entry>
+                <entry><literal>org.hibernate.cache.TreeCacheProvider</literal></entry>
+                <entry>en cluster (multicast ip), transactionnel</entry>
+                <entry>oui (replication)</entry>
+                <entry>oui (horloge sync. nécessaire)</entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <sect2 id="performance-cache-mapping" revision="2">
+            <title>Mapping de Cache</title>
+
+            <para>
+                L'élément <literal>&lt;cache&gt;</literal> d'une classe ou d'une collection à
+        la forme suivante :
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="cache1" coords="2 70"/>
+                    <area id="cache2" coords="3 70"/>
+                    <area id="cache3" coords="4 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<cache 
+    usage="transactional|read-write|nonstrict-read-write|read-only"
+    region="RegionName"
+    include="all|non-lazy"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="cache1">
+                        <para>
+                            <literal>usage</literal> (requis) spécifie la stratégie de cache :
+                            <literal>transactionel</literal>,
+                            <literal>lecture-écriture</literal>,
+                            <literal>lecture-écriture non stricte</literal> ou
+                            <literal>lecture seule</literal>
+                        </para>
+                    </callout>                   
+                    <callout arearefs="cache2">
+                        <para>
+                            <literal>region</literal> (optionnel, par défaut il s'agit du nom
+                            de la classe ou du nom de role de la collection) spécifie le nom de la
+                            région du cache de second niveau
+                        </para>
+                    </callout>
+                    <callout arearefs="cache3">
+                        <para>
+                            <literal>include</literal> (optionnel, par défaut <literal>all</literal>)
+                            <literal>non-lazy</literal> spécifie que les propriétés des entités mappées avec 
+                            <literal>lazy="true"</literal> ne doivent pas être mises en cache lorsque
+                            le chargement tardif des attributs est activé.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                Alternativement (voir préférentiellement), vous pouvez spécifier les éléments 
+        <literal>&lt;class-cache&gt;</literal> et <literal>&lt;collection-cache&gt;</literal> 
+        dans <literal>hibernate.cfg.xml</literal>.
+            </para>
+            
+            <para>
+                L'attribut <literal>usage</literal> spécifie une <emphasis>stratégie de concurrence d'accès au cache</emphasis>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-cache-readonly">
+            <title>Strategie : lecture seule</title>
+
+            <para>
+                Si votre application a besoin de lire mais ne modifie jamais les instances d'une classe,
+        un cache <literal>read-only</literal> peut être utilisé. C'est la stratégie la plus simple
+        et la plus performante. Elle est même parfaitement sûre dans un cluster.
+            </para>
+
+            <programlisting><![CDATA[<class name="eg.Immutable" mutable="false">
+    <cache usage="read-only"/>
+    ....
+</class>]]></programlisting>
+
+        </sect2>
+
+
+        <sect2 id="performance-cache-readwrite">
+            <title>Stratégie : lecture/écriture</title>
+
+            <para>
+                Si l'application a besoin de mettre à jour des données, un cache <literal>read-write</literal> peut
+        être approprié. Cette stratégie ne devrait jamais être utilisée si votre application
+        nécessite un niveau d'isolation transactionnelle sérialisable. Si le cache est utilisé 
+        dans un environnement JTA, vous devez spécifier 
+        <literal>hibernate.transaction.manager_lookup_class</literal>, fournissant une stratégie pour obtenir
+        le <literal>TransactionManager</literal> JTA. Dans d'autres environnements, vous devriez vous assurer
+        que la transation est terminée à l'appel de <literal>Session.close()</literal> 
+        ou <literal>Session.disconnect()</literal>. Si vous souhaitez utiliser cette stratégie 
+        dans un cluster, vous devriez vous assurer que l'implémentation de cache utilisée supporte 
+        le vérrouillage. Ce que ne font <emphasis>pas</emphasis> les pourvoyeurs caches fournis.
+            </para>
+
+            <programlisting><![CDATA[<class name="eg.Cat" .... >
+    <cache usage="read-write"/>
+    ....
+    <set name="kittens" ... >
+        <cache usage="read-write"/>
+        ....
+    </set>
+</class>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-cache-nonstrict">
+            <title>Stratégie : lecture/écriture non stricte</title>
+
+            <para>
+                Si l'application besoin de mettre à jour les données de manière occasionnelle 
+        (qu'il est très peu probable que deux transactions essaient de mettre à jour le même 
+        élément simultanément) et qu'une isolation transactionnelle stricte n'est pas nécessaire, 
+        un cache <literal>nonstrict-read-write</literal> peut être approprié. Si le cache est 
+        utilisé dans un environnement JTA, vous devez spécifier
+        <literal>hibernate.transaction.manager_lookup_class</literal>. Dans d'autres 
+        environnements, vous devriez vous assurer que la transation est terminée à l'appel 
+        de <literal>Session.close()</literal> ou <literal>Session.disconnect()</literal> 
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-cache-transactional">
+            <title>Stratégie : transactionelle</title>
+
+            <para>
+                La stratégie de cache <literal>transactional</literal> supporte un cache 
+        complètement transactionnel comme, par exemple, JBoss TreeCache. Un tel cache ne 
+        peut être utilisé que dans un environnement JTA et vous devez spécifier 
+        <literal>hibernate.transaction.manager_lookup_class</literal>. 
+            </para>
+
+        </sect2>
+        
+        <para>
+            Aucun des caches livrés ne supporte toutes les stratégies de concurrence. Le tableau suivant montre
+        quels caches sont compatibles avec quelles stratégies de concurrence.       
+        </para>
+
+        <table frame="topbot">
+            <title>Stratégie de concurrence du cache</title>
+            <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="1*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Cache</entry>
+              <entry>read-only (lecture seule)</entry>
+              <entry>nonstrict-read-write (lecture-écriture non stricte)</entry>
+              <entry>read-write (lecture-ériture)</entry>
+              <entry>transactional (transactionnel)</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>Hashtable (ne pas utilser en production)</entry>
+                <entry>oui</entry>
+                <entry>oui</entry>
+                <entry>oui</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>EHCache</entry>
+                <entry>oui</entry>
+                <entry>oui</entry>
+                <entry>oui</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>OSCache</entry>
+                <entry>oui</entry>
+                <entry>oui</entry>
+                <entry>oui</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>SwarmCache</entry>
+                <entry>oui</entry>
+                <entry>oui</entry>
+                <entry></entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>JBoss TreeCache</entry>
+                <entry>oui</entry>
+                <entry></entry>
+                <entry></entry>
+                <entry>oui</entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+    </sect1>
+
+    <sect1 id="performance-sessioncache" revision="2">
+        <title>Gérer les caches</title>
+
+        <para>
+            A chaque fois que vous passez un objet à la méthode <literal>save()</literal>, 
+            <literal>update()</literal> ou <literal>saveOrUpdate()</literal> et à chaque fois
+            que vous récupérez un objet avec <literal>load()</literal>, <literal>get()</literal>,
+            <literal>list()</literal>, <literal>iterate()</literal> or <literal>scroll()</literal>, 
+            cet objet est ajouté au cache interne de la <literal>Session</literal>. 
+        </para>
+        <para>
+            Lorsqu'il y a un appel à la méthode <literal>flush()</literal>, l'état de cet objet
+            va être synchronisé avec la base de données. Si vous ne voulez pas que cette synchronisation
+            ait lieu ou si vous traitez un grand nombre d'objets et que vous avez besoin de gérer
+            la mémoire de manière efficace, vous pouvez utiliser la méthode <literal>evict()</literal>
+            pour supprimer l'objet et ses collections dépendantes du cache de la session
+        </para>
+        
+        <programlisting><![CDATA[ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
+while ( cats.next() ) {
+    Cat cat = (Cat) cats.get(0);
+    doSomethingWithACat(cat);
+    sess.evict(cat);
+}]]></programlisting>
+            
+        <para>
+          La <literal>Session</literal> dispose aussi de la méthode <literal>contains()</literal> pour déterminer
+            si une instance appartient au cache de la session.
+        </para>
+        
+        <para>
+            Pour retirer tous les objets du cache session, appelez <literal>Session.clear()</literal>
+        </para>
+        
+        <para>
+            Pour le cache de second niveau, il existe des méthodes définies dans 
+        <literal>SessionFactory</literal> pour retirer des instances du cache, 
+        la classe entière, une instance de collection ou
+        le rôle entier d'une collection.
+        </para>
+        
+        <programlisting><![CDATA[sessionFactory.evict(Cat.class, catId); //evict a particular Cat
+sessionFactory.evict(Cat.class);  //evict all Cats
+sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
+sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections]]></programlisting>
+
+        <para>
+            Le <literal>CacheMode</literal> contrôle comme une session particulière interragit avec le
+            cache de second niveau
+        </para>
+        
+        <itemizedlist>
+        <listitem>
+        <para>
+            <literal>CacheMode.NORMAL</literal> - lit et écrit les items dans le cache de second niveau
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.GET</literal> - lit les items dans le cache de second niveau mais ne
+            les écrit pas sauf dans le cache d'une mise à jour d'une donnée
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.PUT</literal> -  écrit les items dans le cache de second niveau mais ne les
+            lit pas dans le cache de second niveau
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.REFRESH</literal> - écrit les items dans le cache de second niveau mais ne les
+            lit pas dans le cache de second niveau, outrepasse l'effet de<literal>hibernate.cache.use_minimal_puts</literal>, 
+            en forçant un rafraîchissement du cache de second niveau pour chaque item lu dans la base
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            Pour parcourir le contenu du cache de second niveau ou la région du cache dédiée au requêtes, vous
+            pouvez utiliser l'API <literal>Statistics</literal>
+            API:
+        </para>
+        
+        <programlisting><![CDATA[Map cacheEntries = sessionFactory.getStatistics()
+        .getSecondLevelCacheStatistics(regionName)
+        .getEntries();]]></programlisting>
+        
+        <para>
+          Vous devez pour cela activer les statistiques et optionnellement forcer Hibernate à conserver les entrées dans le
+          cache sous un format plus compréhensible pour l'utilisateur :
+        </para>
+        
+        <programlisting><![CDATA[hibernate.generate_statistics true
+hibernate.cache.use_structured_entries true]]></programlisting>       
+                
+    </sect1>
+    
+    <sect1 id="performance-querycache" revision="1">
+        <title>Le cache de requêtes</title>
+
+        <para>
+          Les résultats d'une requête peuvent aussi être placés en cache. Ceci n'est utile
+            que pour les requêtes qui sont exécutées avec les mêmes paramètres. Pour utiliser
+            le cache de requêtes, vous devez d'abord l'activer :
+        </para>
+        
+        <programlisting><![CDATA[hibernate.cache.use_query_cache true]]></programlisting>       
+
+        <para>
+          Ce paramètre amène la création de deux nouvelles régions dans le cache, une qui va conserver
+          le résultat des requêtes mises en cache (<literal>org.hibernate.cache.StandardQueryCache</literal>)
+          et l'autre qui va conserver l'horodatage des mises à jour les plus récentes effectuées sur les
+          tables requêtables (<literal>org.hibernate.cache.UpdateTimestampsCache</literal>).
+          Il faut noter que le cache de requête ne conserve pas l'état des entités, il met en cache
+          uniquement les valeurs de l'identifiant et les valeurs de types de base (?). Le cache
+          de requête doit toujours être utilisé avec le cache de second niveau pour être efficace.
+        </para>
+        
+        <para>
+          La plupart des requêtes ne retirent pas de bénéfice pas du cache, 
+          donc par défaut les requêtes ne sont pas mises en cache. Pour activer le cache, 
+          appelez <literal>Query.setCacheable(true)</literal>. 
+            Cet appel permet de vérifier si les résultats sont en cache ou non, voire
+          d'ajouter ces résultats si la requête est exécutée.
+        </para>
+        
+        <para>
+          Si vous avez besoin de contrôler finement les délais d'expiration du cache, vous
+            pouvez spécifier une région de cache nommée pour une requête particulière en
+            appelant <literal>Query.setCacheRegion()</literal>.
+        </para>
+        
+        <programlisting><![CDATA[List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
+    .setEntity("blogger", blogger)
+    .setMaxResults(15)
+    .setCacheable(true)
+    .setCacheRegion("frontpages")
+    .list();]]></programlisting>
+    
+        <para>
+          Si une requête doit forcer le rafraîchissement de sa région de cache, vous devez
+          appeler <literal>Query.setCacheMode(CacheMode.REFRESH)</literal>. C'est particulièrement
+          utile lorsque les données peuvent avoir été mises à jour par un processus séparé (e.g. elles
+          n'ont pas été modifiées par Hibernate). Cela permet à l'application de rafraîchir de
+          manière sélective les résultats d'une requête particulière. Il s'agit d'une alternative plus
+          efficace à l'éviction d'une région du cache à l'aide de la méthode 
+          <literal>SessionFactory.evictQueries()</literal>.
+        </para>
+
+    </sect1>
+    <sect1 id="performance-collections">
+        <title>Comprendre les performances des Collections</title>
+
+        <para>
+            Nous avons déjà passé du temps à discuter des collections.
+        Dans cette section, nous allons traiter du comportement des
+        collections à l'exécution.
+        </para>
+
+        <sect2 id="performance-collections-taxonomy">
+            <title>Classification</title>
+
+            <para>Hibernate définit trois types de collections :</para>
+
+            <itemizedlist>
+            <listitem>
+                <para>les collections de valeurs</para>
+            </listitem>
+            <listitem>
+                <para>les associations un-vers-plusieurs</para>
+            </listitem>
+            <listitem>
+                <para>les associations plusieurs-vers-plusieurs</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                Cette classification distingue les différentes relations entre les tables
+        et les clés étrangères mais ne nous apprend rien de ce que nous devons savoir
+        sur le modèle relationnel. Pour comprendre parfaitement la structure relationnelle
+        et les caractéristiques des performances, nous devons considérer la structure
+        de la clé primaire qui est utilisée par Hibernate pour mettre à jour ou supprimer
+        les éléments des collections. Celà nous amène aux classifications suivantes :
+            </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>collections indexées</para>
+            </listitem>
+            <listitem>
+                <para>sets</para>
+            </listitem>
+            <listitem>
+                <para>bags</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                Toutes les collections indexées (maps, lists, arrays) ont une clé primaire constituée 
+        des colonnes clé (<literal>&lt;key&gt;</literal>) et <literal>&lt;index&gt;</literal>.
+        Avec ce type de clé primaire, la mise à jour de collection est en général très performante - la clé
+        primaire peut être indexées efficacement et un élément particulier peut être 
+        localisé efficacement lorsqu'Hibernate essaie de le mettre à jour ou de le supprimer.
+            </para>
+
+            <para>
+              Les Sets ont une clé primaire composée de <literal>&lt;key&gt;</literal> et des
+              colonnes représentant l'élément. Elle est donc moins efficace pour certains 
+              types de collections d'éléments, en particulier les éléments composites, 
+              les textes volumineux ou les champs binaires ; la base de données
+                  peut ne pas être capable d'indexer aussi efficacement une clé primaire 
+              aussi complexe. Cependant, pour les associations un-vers-plusieurs 
+              ou plusieurs-vers-plusieurs, spécialement lorsque l'on utilise des entités
+              ayant des identifiants techniques, il est probable que cela soit aussi efficace
+                  (note : si vous voulez que <literal>SchemaExport</literal> créé effectivement
+              la clé primaire   d'un <literal>&lt;set&gt;</literal> pour vous, vous devez 
+              déclarer toutes les colonnes avec <literal>not-null="true"</literal>).
+            </para>
+
+            <para>
+              Le mapping à l'aide d'<literal>&lt;idbag&gt;</literal> définit une clé
+              de substitution ce qui leur permet d'être très efficaces lors de la
+              mise à jour. En fait il s'agit du meilleur cas de mise à jour d'une collection
+            </para>
+
+            <para>
+              Le pire cas intervient pour les Bags. Dans la mesure où un bag permet 
+              la duplications des éléments et n'a pas de colonne d'index, aucune clé primaire 
+              ne peut être définie. Hibernate   n'a aucun moyen de distinguer des enregistrements 
+              dupliqués. Hibernate résout ce problème en supprimant complètement les 
+              enregistrements (via un simple <literal>DELETE</literal>), puis en recréant
+                  la collection chaque fois qu'elle change. Ce qui peut être très inefficace.
+            </para>
+
+            <para>
+              Notez que pour une relation un-vers-plusieurs, la "clé primaire" 
+              peut ne pas être la clé   primaire de la table en base de données - 
+              mais même dans ce cas, la classification ci-dessus reste utile 
+              (Elle explique comment Hibernate "localise" chaque enregistrement
+                  de la collection).
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-collections-mostefficientupdate">
+            <title>Les lists, les maps, les idbags et les sets sont les collections les plus efficaces pour la mise à jour</title>
+
+            <para>
+              La discussion précédente montre clairement que les collections indexées 
+              et (la plupart du temps) les sets, permettent de réaliser le plus efficacement 
+              les opérations d'ajout, de suppression ou de modification d'éléments.     
+            </para>
+
+            <para>
+              Il existe un autre avantage qu'ont les collections indexées sur les Sets 
+                  dans le cadre d'une association plusieurs vers plusieurs ou d'une collection de valeurs.
+                  A cause de la structure inhérente d'un <literal>Set</literal>, Hibernate n'effectue jamais  
+                  d'<literal>UPDATE</literal> quand un enregistrement est modifié. Les modifications
+                  apportées à un <literal>Set</literal> se font via un <literal>INSERT</literal> et <literal>DELETE</literal> 
+                  (de chaque enregistrement). Une fois de plus, ce cas ne s'applique pas aux associations
+                un vers plusieurs.
+            </para>
+
+            <para>
+              Après s'être rappelé que les tableaux ne peuvent pas être chargés tardivement,
+              nous pouvons conclure que les lists, les maps et les idbags sont les types de collections
+              (non inversées) les plus performants, avec les sets pas loin derrières.
+              Les sets son le type de collection le plus courant dans les applications Hibernate. Cela
+              est du au fait que la sémantique des "set" est la plus naturelle dans le modèle
+              relationnel.
+            </para>
+
+            <para>
+                Cependant, dans des modèles objet bien conçus avec Hibernate, on voit souvent que
+                la plupart des collections sont en fait des associations "un-vers-plusieurs" avec
+                <literal>inverse="true"</literal>. Pour ces associations, les mises à jour sont gérées
+                au niveau de l'association "plusieurs-vers-un" et les considérations de performance de
+                mise à jour des collections ne s'appliquent tout simplement pas dans ces cas là.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-collections-mostefficentinverse">
+            <title>Les Bags et les lists sont les plus efficaces pour les collections inverse</title>
+
+            <para>
+                Avant que vous n'oubliez les bags pour toujours, il y a un cas précis où les bags 
+        (et les lists) sont bien plus performants que les sets. Pour une collection marquée
+        comme <literal>inverse="true"</literal> (le choix le plus courant pour un relation
+        un vers plusieurs bidirectionnelle), nous pouvons ajouter des éléments à un bag 
+        ou une list sans avoir besoin de l'initialiser (fetch) les éléments du sac! 
+        Ceci parce que <literal>Collection.add()</literal> ou <literal>Collection.addAll()</literal> 
+        doit toujours retourner vrai pour un bag ou une <literal>List</literal>
+        (contrairement au <literal>Set</literal>). 
+        Cela peut rendre le code suivant beaucoup plus rapide.
+            </para>
+
+            <programlisting><![CDATA[Parent p = (Parent) sess.load(Parent.class, id);
+    Child c = new Child();
+    c.setParent(p);
+    p.getChildren().add(c);  //pas besoin de charger la collection !
+    sess.flush();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-collections-oneshotdelete">
+            <title>Suppression en un coup</title>
+
+            <para>
+                Parfois, effacer les éléments d'une collection un par un peut être extrêmement inefficace.
+        Hibernate n'est pas totalement stupide, il sait qu'il ne faut pas le faire dans le cas d'une
+        collection complètement vidée (lorsque vous appellez <literal>list.clear()</literal>, par exemple).
+        Dans ce cas, Hibernate fera un simple <literal>DELETE</literal> et le travail est fait !
+            </para>
+
+            <para>
+                Supposons que nous ajoutions un élément dans une collection de taille vingt et que nous
+        enlevions ensuite deux éléments. Hibernate effectuera un <literal>INSERT</literal> puis
+        deux <literal>DELETE</literal> (à moins que la collection ne soit un bag). Ce qui est
+        souhaitable.
+            </para>
+
+            <para>
+                Cependant, supposons que nous enlevions dix huit éléments, laissant ainsi deux éléments, puis
+        que nous ajoutions trois nouveaux éléments. Il y a deux moyens de procéder.
+            </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>effacer dix huit enregistrements un à un puis en insérer trois</para>
+            </listitem>
+            <listitem>
+                <para>effacer la totalité de la collection (en un <literal>DELETE</literal> SQL) puis insérer
+                les cinq éléments restant un à un</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                Hibernate n'est pas assez intelligent pour savoir que, dans ce cas, la seconde méthode est plus
+        rapide (Il plutôt heureux qu'Hibernate ne soit pas trop intelligent ; un tel comportement
+        pourrait rendre l'utilisation de triggers de bases de données plutôt aléatoire, etc...).
+            </para>
+
+            <para>
+                Heureusement, vous pouvez forcer ce comportement lorsque vous le souhaitez, en liberant 
+        (c'est-à-dire en déréférençant) la collection initiale et en retournant une collection
+        nouvellement instanciée avec les éléments restants. Ceci peut être très pratique et 
+        très puissant de temps en temps.
+            </para>
+
+            <para>
+              Bien sûr, la suppression en un coup ne s'applique pas pour les collections qui sont mappées
+              avec <literal>inverse="true"</literal>.
+            </para>
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="performance-monitoring" revision="1">
+        <title>Moniteur de performance</title>
+
+        <para>
+          L'optimisation n'est pas d'un grand intérêt sans le suivi et l'accès aux données de
+          performance. Hibernate fournit toute une panoplie de rapport sur ses opérations internes.
+          Les statistiques dans Hibernate sont fournies par <literal>SessionFactory</literal>.
+        </para>
+
+        <sect2 id="performance-monitoring-sf" revision="2">
+            <title>Suivi d'une SessionFactory</title>
+
+            <para>
+              Vous pouvez accéder au métriques d'une <literal>SessionFactory</literal> de deux
+              manières. La première option est d'appeler <literal>sessionFactory.getStatistics()</literal>
+              et de lire ou d'afficher les <literal>Statistics</literal> vous même.
+            </para>
+
+            <para>
+              Hibernate peut également utiliser JMX pour publier les métriques si vous activez
+              le MBean <literal>StatisticsService</literal>. Vous pouvez activer un seul MBean
+              pour toutes vos <literal>SessionFactory</literal> ou un par factory. Voici un code
+              qui montre un exemple de configuration minimaliste :
+            </para>
+
+            <programlisting><![CDATA[// MBean service registration for a specific SessionFactory
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "myFinancialApp");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
+server.registerMBean(stats, on); // Register the Mbean on the server]]></programlisting>
+
+
+<programlisting><![CDATA[// MBean service registration for all SessionFactory's
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "all");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+server.registerMBean(stats, on); // Register the MBean on the server]]></programlisting>
+
+            <para>
+              TODO: Cela n'a pas de sens : dans le premier cs on récupère et on utilise le MBean directement.
+              Dans le second, on doit fournir le nom JNDI sous lequel est retenu la fabrique de session avant de
+              l'utiliser. Pour cela il faut utiliser
+                <literal>hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")</literal>
+            </para>
+            <para>
+              Vous pouvez (dés)activer le suivi pour une <literal>SessionFactory</literal>
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        au moment de la configuration en mettant <literal>hibernate.generate_statistics</literal> à <literal>false</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        à chaud avec <literal>sf.getStatistics().setStatisticsEnabled(true)</literal>
+                        ou <literal>hibernateStatsBean.setStatisticsEnabled(true)</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+              Les statistiques peuvent être remises à zéro de manière programmatique à l'aide de la méthode
+              <literal>clear()</literal>
+              Un résumé peut être envoyé à un logger (niveau info) à l'aide de la méthode <literal>logSummary()</literal>
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-monitoring-metrics" revision="1">
+            <title>Métriques</title>
+
+            <para>
+              Hibernate fournit un certain nombre de métriques, qui vont des informations très basiques
+              aux informations très spécialisées qui ne sont appropriées que dans certains scenarii.
+              Tous les compteurs accessibles sont décrits dans l'API de l'interface
+              <literal>Statistics</literal> dans trois catégories :
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                      Les métriques relatives à l'usage général de la <literal>Session</literal>
+                      comme le nombre de sessions ouvertes, le nombre de connexions JDBC récupérées, etc...
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                      Les métriques relatives aux entités, collections, requêtes et caches dans
+                      leur ensemble (métriques globales),
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                      Les métriques détaillées relatives à une entité, une collection, une requête
+                      ou une région de cache particulière.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+              Par exemple, vous pouvez vérifier l'accès au cache ainsi que le taux d'éléments manquants et
+              de mise à jour des entités, collections et requêtes et le temps moyen que met une requête.
+              Il faut faire attention au fait que le nombre de millisecondes est sujet à approximation en
+              Java. Hibernate est lié à la précision de la machine virtuelle, sur certaines plateformes,
+              cela n'offre qu'une précision de l'ordre de 10 secondes.
+            </para>
+
+            <para>
+              Des accesseurs simples sont utilisés pour accéder aux métriques globales (e.g. celles qui ne
+              sont pas liées à une entité, collection ou région de cache particulière). Vous pouvez accéder
+              aux métriques d'une entité, collection, région de cache particulière à l'aide de son nom et à l'aide
+              de sa représentation HQL ou SQL pour une requête. Référez vous à la javadoc des APIS 
+              <literal>Statistics</literal>, <literal>EntityStatistics</literal>,
+              <literal>CollectionStatistics</literal>, <literal>SecondLevelCacheStatistics</literal>,
+              and <literal>QueryStatistics</literal> pour plus d'informations. Le code ci-dessous montre
+              un exemple simple :
+            </para>
+
+            <programlisting><![CDATA[Statistics stats = HibernateUtil.sessionFactory.getStatistics();
+
+double queryCacheHitCount  = stats.getQueryCacheHitCount();
+double queryCacheMissCount = stats.getQueryCacheMissCount();
+double queryCacheHitRatio =
+  queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
+
+log.info("Query Hit ratio:" + queryCacheHitRatio);
+
+EntityStatistics entityStats =
+  stats.getEntityStatistics( Cat.class.getName() );
+long changes =
+        entityStats.getInsertCount()
+        + entityStats.getUpdateCount()
+        + entityStats.getDeleteCount();
+log.info(Cat.class.getName() + " changed " + changes + "times"  );]]></programlisting>
+
+            <para>
+              Pour travailler sur toutes les entités, collections, requêtes et régions de cache, vous pouvez
+              récupérer la liste des noms des entités, collections, requêtes et régions de cache avec les
+              méthodes : <literal>getQueries()</literal>, <literal>getEntityNames()</literal>,
+                <literal>getCollectionRoleNames()</literal>, et
+                <literal>getSecondLevelCacheRegionNames()</literal>.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/persistent_classes.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/persistent_classes.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/persistent_classes.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,536 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<chapter id="persistent-classes" revision="2">
+    <title>Classes persistantes</title>
+
+    <para>
+        Les classes persistantes sont les classes d'une application qui implémentent
+        les entités d'un problème métier (ex. Client et Commande dans une application
+        de commerce électronique).
+        Toutes les instances d'une classe persistante ne sont pas forcément 
+        dans l'état persistant - au lieu de cela, une instance peut être éphémère (NdT : transient) ou détachée.
+    </para>
+
+    <para>
+        Hibernate fonctionne de manière optimale lorsque ces classes suivent quelques règles
+        simples, aussi connues comme le modèle de programmation Plain Old Java Object
+        (POJO). Cependant, aucune de ces règles ne sont des besoins absolus. En effet, Hibernate3 suppose très peu de choses à propos
+        de la nature de vos objets persistants. Vous pouvez exprimer un modèle de domaine par d'autres moyens : utiliser des arbres
+        d'instances de <literal>Map</literal>, par exemple.
+    </para>
+
+    <sect1 id="persistent-classes-pojo">
+        <title>Un exemple simple de POJO</title>
+
+        <para>
+            Toute bonne application Java nécessite une classe persistante
+            représentant les félins.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+public class Cat {
+    private Long id; // identifier
+
+    private Date birthdate;
+    private Color color;
+    private char sex;
+    private float weight;
+    private int litterId;
+
+    private Cat mother;
+    private Set kittens = new HashSet();
+
+    private void setId(Long id) {
+        this.id=id;
+    }
+    public Long getId() {
+        return id;
+    }
+
+    void setBirthdate(Date date) {
+        birthdate = date;
+    }
+    public Date getBirthdate() {
+        return birthdate;
+    }
+
+    void setWeight(float weight) {
+        this.weight = weight;
+    }
+    public float getWeight() {
+        return weight;
+    }
+
+    public Color getColor() {
+        return color;
+    }
+    void setColor(Color color) {
+        this.color = color;
+    }
+
+    void setSex(char sex) {
+        this.sex=sex;
+    }
+    public char getSex() {
+        return sex;
+    }
+
+    void setLitterId(int id) {
+        this.litterId = id;
+    }
+    public int getLitterId() {
+        return litterId;
+    }
+
+    void setMother(Cat mother) {
+        this.mother = mother;
+    }
+    public Cat getMother() {
+        return mother;
+    }
+    void setKittens(Set kittens) {
+        this.kittens = kittens;
+    }
+    public Set getKittens() {
+        return kittens;
+    }
+
+    // addKitten not needed by Hibernate
+    public void addKitten(Cat kitten) {
+        kitten.setMother(this);
+    kitten.setLitterId( kittens.size() );
+        kittens.add(kitten);
+    }
+}]]></programlisting>
+
+        <para>
+            Il y a quatre règles à suivre ici :
+        </para>
+
+
+        <sect2 id="persistent-classes-pojo-constructor" revision="1">
+            <title>Implémenter un constructeur sans argument</title>
+
+            <para>
+                <literal>Cat</literal> a un constructeur sans argument. Toutes les classes persistantes doivent avoir un
+                constructeur par défaut (lequel peut ne pas être public) pour qu'Hibernate puissent les instancier en utilisant
+                <literal>Constructor.newInstance()</literal>. Nous recommandons fortement d'avoir un constructeur par défaut avec 
+                au moins une visibilité <emphasis>paquet</emphasis> pour la génération du proxy à l'exécution dans Hibernate.
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-identifier" revision="2">
+            <title>Fournir une propriété d'indentifiant (optionnel)</title>
+
+            <para>
+                <literal>Cat</literal> possède une propriété appelée <literal>id</literal>.
+                Cette propriété mappe la valeur de la colonne de clé primaire de la table
+                d'une base de données.La propriété aurait pu s'appeler complètement autrement,
+                et son type aurait pu être n'importe quel type primitif, n'importe quel "encapsuleur"
+                de type primitif, <literal>java.lang.String</literal> ou <literal>java.util.Date</literal>.
+                (Si votre base de données héritée possède des clés composites, elles peuvent être mappées
+                en utilisant une classe définie par l'utilisateur et possédant les propriétés associées aux
+                types de la clé composite - voir la section concernant les identifiants composites plus tard).
+            </para>
+
+            <para>
+                La propriété d'identifiant est strictement optionnelle. Vous pouver l'oublier et laisser Hibernate
+                s'occuper des identifiants de l'objet en interne. Toutefois, nous ne le recommandons pas.
+            </para>
+
+            <para>
+                En fait, quelques fonctionnalités ne sont disponibles que pour les classes
+                déclarant un identifiant de propriété :
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        Les réattachements transitifs pour les objets détachés (mise à jour en cascade ou fusion en cascade) - 
+                        voir <xref linkend="objectstate-transitive"/>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session.saveOrUpdate()</literal>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session.merge()</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Nous recommandons que vous déclariez les propriétés d'identifiant de manière
+                uniforme. Nous recommandons également que vous utilisiez un type nullable
+                (ie. non primitif).
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-final">
+            <title>Favoriser les classes non finales (optionnel)</title>
+            <para>
+                Une fonctionnalité clef d'Hibernate, les <emphasis>proxies</emphasis>, nécessitent
+                que la classe persistente soit non finale ou qu'elle soit l'implémentation d'une
+                interface qui déclare toutes les méthodes publiques.
+            </para>
+            <para>
+                Vous pouvez persister, grâce à Hibernate, les classes <literal>final</literal>
+                qui n'implémentent pas d'interface, mais vous ne pourrez pas utiliser les proxies pour les chargements d'associations paresseuses
+                - ce qui limitera vos possibilités d'ajustement des performances.
+            </para>
+            <para>
+                Vous devriez aussi éviter de déclarer des méthodes <literal>public final</literal> sur des classes
+                non-finales. Si vous voulez utiliser une classe avec une méthode <literal>public final</literal>, vous devez
+                explicitement désactiver les proxies en paramétrant
+                <literal>lazy="false"</literal>.
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-accessors" revision="2">
+            <title>Déclarer les accesseurs et mutateurs des attributs persistants (optionnel)</title>
+
+            <para>
+                <literal>Cat</literal> déclare des mutateurs pour toutes ses champs persistants. Beaucoup d'autres
+                solutions de mapping Objet/relationnel persistent directement les variables d'instance. Nous pensons
+                qu'il est bien mieux de fournir une indirection entre le schéma relationnel et les structures de données internes de la classe.
+                Par défaut, Hibernate persiste les propriétés suivant le style JavaBean, et reconnaît les noms de méthodes de la forme <literal>
+                getFoo</literal>, <literal>isFoo</literal> et
+                <literal>setFoo</literal>. Nous pouvons changer pour un accès direct aux champs pour des propriétés particulières, si besoin est.
+            </para>
+
+            <para>
+                Les propriétés <emphasis>n'ont pas</emphasis> à être déclarées publiques -
+                Hibernate peut persister une propriété avec un paire de getter/setter de
+                visibilité par défault, <literal>protected</literal> ou <literal>
+                private</literal>.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-inheritance">
+        <title>Implémenter l'héritage</title>
+
+        <para>
+            Une sous-classe doit également suivre la première et la seconde règle.
+            Elle hérite sa propriété d'identifiant de <literal>Cat</literal>.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+public class DomesticCat extends Cat {
+        private String name;
+
+        public String getName() {
+                return name;
+        }
+        protected void setName(String name) {
+                this.name=name;
+        }
+}]]></programlisting>
+    </sect1>
+
+    <sect1 id="persistent-classes-equalshashcode" revision="1">
+        <title>Implémenter <literal>equals()</literal> et <literal>hashCode()</literal></title>
+
+        <para>
+            Vous devez surcharger les méthodes <literal>equals()</literal> et
+            <literal>hashCode()</literal> si vous
+        </para>
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    avez l'intention de mettre des instances de classes persistantes dans un <literal>Set</literal>
+                    (la manière recommandée pour représenter des associations pluri-valuées)
+                    <emphasis>et</emphasis>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    avez l'intention d'utiliser le réattachement d'instances détachées
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Hibernate garantit l'équivalence de l'identité persistante (ligne de base de données) et l'identité Java seulement
+            à l'intérieur de la portée d'une session particulière. Donc dès que nous mélangeons des instances venant de différentes
+            sessions, nous devons implémenter <literal>equals()</literal> et
+            <literal>hashCode()</literal> si nous souhaitons avoir une sémantique correcte pour les <literal>Set</literal>s.
+        </para>
+
+        <para>
+            La manière la plus évidente est d'implémenter <literal>equals()</literal>/<literal>hashCode()</literal>
+            en comparant la valeur de l'identifiant des deux objets. Si cette valeur est identique, les deux
+            doivent représenter la même ligne de base de données, ils sont donc égaux (si les deux sont
+            ajoutés à un <literal>Set</literal>, nous n'aurons qu'un seul élément dans le
+            <literal>Set</literal>). Malheureusement, nous ne pouvons pas utiliser cette approche avec 
+            des identifiants générés ! Hibernate n'assignera de
+            valeur d'identifiant qu'aux objets qui sont persistants, une instance nouvellement créée n'aura
+            donc pas de valeur d'identifiant ! De plus, si une instance est non sauvegardée et actuellement dans un <literal>Set</literal>,
+            le sauvegarder assignera une valeur d'identifiant à l'objet. Si <literal>equals()</literal> et <literal>hashCode()</literal>
+            sont basées sur la valeur de l'identifiant, le code de hachage devrait changer, rompant le contrat du <literal>Set</literal>. 
+            Regardez sur le site web d'Hibernate pour une discussion complète de ce problème. 
+            Notez que ceci n'est pas un problème d'Hibernate, mais la sémantique normale de Java pour l'identité d'un objet et l'égalité.
+        </para>
+
+        <para>
+            Nous recommandons donc d'implémenter
+            <literal>equals()</literal> et <literal>hashCode()</literal> en utilisant <emphasis>
+            l'égalité par clé métier</emphasis>.L'égalité par clé métier signifie que la méthode <literal>equals()</literal>
+            compare uniquement les propriétés qui forment une clé métier, une clé qui
+            identifierait notre instance dans le monde réel (une clé candidate
+            <emphasis>naturelle</emphasis>) :
+        </para>
+
+        <programlisting><![CDATA[public class Cat {
+
+    ...
+    public boolean equals(Object other) {
+        if (this == other) return true;
+        if ( !(other instanceof Cat) ) return false;
+
+        final Cat cat = (Cat) other;
+
+        if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
+        if ( !cat.getMother().equals( getMother() ) ) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result;
+        result = getMother().hashCode();
+        result = 29 * result + getLitterId();
+        return result;
+    }
+
+}]]></programlisting>
+
+        <para>
+            Notez qu'une clef métier ne doit pas être solide comme une clef primaire de base de données 
+            (voir <xref linkend="transactions-basics-identity"/>). Les propriétés
+            immuables ou uniques sont généralement de bonnes candidates pour une clef métier.
+        </para>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-dynamicmodels">
+        <title>Modèles dynamiques</title>
+
+        <para>
+            <emphasis>Notez que la fonctionnalités suivantes sont actuellement considérées
+            comme expérimentales et peuvent changer dans un futur proche.</emphasis>
+        </para>
+
+        <para>
+            Les entités persistantes ne doivent pas nécessairement être représentées comme
+            des classes POJO ou des objets JavaBean à l'exécution. Hibernate supporte aussi les
+            modèles dynamiques (en utilisant des <literal>Map</literal>s de <literal>Map</literal>s
+            à l'exécution) et la représentation des entités comme des arbres DOM4J. Avec cette
+            approche, vous n'écrivez pas de classes persistantes, seulement des fichiers de mapping.
+        </para>
+
+        <para>
+            Par défaut, Hibernate fonctionne en mode POJO normal. Vous pouvez paramétrer
+            un mode de représentation d'entité par défaut pour une <literal>SessionFactory</literal>
+            particulière en utilisant l'option de configuration <literal>default_entity_mode</literal>
+            (voir <xref linkend="configuration-optional-properties"/>).
+        </para>
+
+        <para>
+            Les exemples suivants démontrent la représentation utilisant des <literal>Map</literal>s.
+            D'abord, dans le fichier de mapping, un <literal>entity-name</literal> doit être déclaré
+            au lieu (ou en plus) d'un nom de classe :
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class entity-name="Customer">
+
+        <id name="id"
+            type="long"
+            column="ID">
+            <generator class="sequence"/>
+        </id>
+
+        <property name="name"
+            column="NAME"
+            type="string"/>
+
+        <property name="address"
+            column="ADDRESS"
+            type="string"/>
+
+        <many-to-one name="organization"
+            column="ORGANIZATION_ID"
+            class="Organization"/>
+
+        <bag name="orders"
+            inverse="true"
+            lazy="false"
+            cascade="all">
+            <key column="CUSTOMER_ID"/>
+            <one-to-many class="Order"/>
+        </bag>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Notez que même si des associations sont déclarées en utilisant des noms de classe cible,
+            le type de cible d'une association peut aussi être une entité dynamique au lieu d'un POJO.
+        </para>
+
+        <para>
+            Après avoir configuré le mode d'entité par défaut à <literal>dynamic-map</literal>
+            pour la <literal>SessionFactory</literal>, nous pouvons lors de l'exécution fonctionner
+            avec des <literal>Map</literal>s de <literal>Map</literal>s :
+        </para>
+
+        <programlisting><![CDATA[Session s = openSession();
+Transaction tx = s.beginTransaction();
+Session s = openSession();
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+
+// Create an organization
+Map foobar = new HashMap();
+foobar.put("name", "Foobar Inc.");
+
+// Link both
+david.put("organization", foobar);
+
+// Save both
+s.save("Customer", david);
+s.save("Organization", foobar);
+
+tx.commit();
+s.close();]]></programlisting>
+
+        <para>
+            Les avantages d'un mapping dynamique sont un gain de temps pour le prototypage
+            sans la nécessité d'implémenter les classes d'entité. Pourtant, vous perdez la
+            vérification du typage au moment de la compilation et aurez plus d'exceptions à
+            gérer lors de l'exécution. Grâce au mapping d'Hibernate, le schéma de la base de
+            données peut facilement être normalisé et solidifié, permettant de rajouter une
+            implémentation propre du modèle de domaine plus tard.
+        </para>
+
+        <para>
+            Les modes de représentation d'une entité peut aussi être configuré par <literal>Session</literal> :
+        </para>
+
+        <programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+dynamicSession.save("Customer", david);
+...
+dynamicSession.flush();
+dynamicSession.close()
+...
+// Continue on pojoSession
+]]></programlisting>
+
+
+        <para>
+            Veuillez noter que l'appel à <literal>getSession()</literal> en utilisant un
+            <literal>EntityMode</literal> se fait sur l'API <literal>Session</literal>, pas
+            <literal>SessionFactory</literal>. De cette manière, la nouvelle <literal>Session</literal>
+            partage les connexions JDBC, transactions et autres informations de contexte sous-jacentes.
+            Cela signifie que vous n'avez pas à appeler <literal>flush()</literal> et <literal>close()</literal>
+            sur la <literal>Session</literal> secondaire, et laissez aussi la gestion de la transaction
+            et de la connexion à l'unité de travail primaire.
+        </para>
+
+        <para>
+            Plus d'informations à propos de la représentation XML peuvent être trouvées dans
+            <xref linkend="xml"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-tuplizers" revision="0">
+        <title>Tuplizers</title>
+
+        <para>
+            <literal>org.hibernate.tuple.Tuplizer</literal>, et ses sous-interfaces, sont responsables
+            de la gestion d'une représentation particulière d'un morceau de données, en fonction du
+            <literal>org.hibernate.EntityMode</literal> de réprésentation. Si un morceau donné de données
+            est pensé comme une structure de données, alors un tuplizer est la chose qui sait comment
+            créer une telle structure de données, comment extraire des valeurs et injecter des valeurs dans
+            une telle structure de données. Par exemple, pour le mode d'entité POJO, le tuplizer correspondant
+            sait comment créer le POJO à travers son constructeur et comment accéder aux propriétés du POJO
+            utilisant les accesseurs de la propriété définie. Il y a deux types de Tuplizers haut niveau,
+            représenté par les interfaces <literal>org.hibernate.tuple.EntityTuplizer</literal> et
+            <literal>org.hibernate.tuple.ComponentTuplizer</literal>. Les <literal>EntityTuplizer</literal>s
+            sont responsables de la gestion des contrats mentionnés ci-dessus pour les entités, alors que
+            les <literal>ComponentTuplizer</literal>s s'occupent des composants.
+        </para>
+
+        <para>
+            Les utilisateurs peuvent aussi brancher leurs propres tuplizers. Peut-être vous est-il nécessaire qu'une
+            implémentation de <literal>java.util.Map</literal> autre que <literal>java.util.HashMap</literal>
+            soit utilisée dans le mode d'entité dynamic-map ; ou peut-être avez-vous besoin de définir une
+            statégie de génération de proxy différente de celle utilisée par défaut. Les deux devraient être
+            effectuées en définissant une implémentation de tuplizer utilisateur. Les définitions de tuplizers
+            sont attachées au mapping de l'entité ou du composant qu'ils sont censés gérer. Retour à l'exemple de
+            notre entité utilisateur :
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+    <class entity-name="Customer">
+        <!--
+            Override the dynamic-map entity-mode
+            tuplizer for the customer entity
+        -->
+        <tuplizer entity-mode="dynamic-map"
+                class="CustomMapTuplizerImpl"/>
+
+        <id name="id" type="long" column="ID">
+            <generator class="sequence"/>
+        </id>
+
+        <!-- other properties -->
+        ...
+    </class>
+</hibernate-mapping>
+
+
+public class CustomMapTuplizerImpl
+        extends org.hibernate.tuple.DynamicMapEntityTuplizer {
+    // override the buildInstantiator() method to plug in our custom map...
+    protected final Instantiator buildInstantiator(
+            org.hibernate.mapping.PersistentClass mappingInfo) {
+        return new CustomMapInstantiator( mappingInfo );
+    }
+
+    private static final class CustomMapInstantiator
+            extends org.hibernate.tuple.DynamicMapInstantitor {
+        // override the generateMap() method to return our custom map...
+        protected final Map generateMap() {
+            return new CustomMap();
+        }
+    }
+}]]></programlisting>
+
+
+    </sect1>
+
+    <para>
+        TODO: Document user-extension framework in the property and proxy packages
+    </para>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/query_criteria.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/query_criteria.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/query_criteria.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,443 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="querycriteria">
+    <title>Requêtes par critères</title>
+
+    <para>
+        Hibernate offre une API d'interrogation par critères intuitive et extensible.
+    </para>
+
+    <sect1 id="querycriteria-creating">
+        <title>Créer une instance de <literal>Criteria</literal></title>
+
+        <para>
+            L'interface <literal>net.sf.hibernate.Criteria</literal> représente une requête sur une
+            classe persistente donnée. La <literal>Session</literal> fournit les instances de
+            <literal>Criteria</literal>.
+        </para>
+
+        <programlisting><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
+crit.setMaxResults(50);
+List cats = crit.list();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="querycriteria-narrowing">
+        <title>Restriction du résultat</title>
+
+        <para>
+            Un criterion (critère de recherche) est une instance de l'interface
+            <literal>org.hibernate.criterion.Criterion</literal>. La classe
+            <literal>org.hibernate.criterion.Restrictions</literal> définit
+            des méthodes pour obtenir des types de <literal>Criterion</literal>
+            pré-définis.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .add( Restrictions.between("weight", minWeight, maxWeight) )
+    .list();]]></programlisting>
+
+        <para>
+            Les restrictions peuvent être goupées de manière logique.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .add( Restrictions.or(
+        Restrictions.eq( "age", new Integer(0) ),
+        Restrictions.isNull("age")
+    ) )
+    .list();]]></programlisting>
+
+       <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
+    .add( Restrictions.disjunction()
+        .add( Restrictions.isNull("age") )
+        .add( Restrictions.eq("age", new Integer(0) ) )
+        .add( Restrictions.eq("age", new Integer(1) ) )
+        .add( Restrictions.eq("age", new Integer(2) ) )
+    ) )
+    .list();]]></programlisting>
+
+        <para>
+            Il y a plusieurs types de criterion pré-définis (sous classes de <literal>Restriction</literal>),
+            mais l'une d'entre elle particulièrement utile vous permet de spécifier directement
+        du SQL.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.sql("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
+    .list();]]></programlisting>
+
+        <para>
+            La zone <literal>{alias}</literal> sera remplacée par l'alias de colonne de l'entité
+        que l'on souhaite intérroger.
+        </para>
+
+        <para>
+            Une autre approche pour obtenir un criterion est de le récupérer d'une instance de <literal>Property</literal>. 
+            Vous pouvez créer une <literal>Property</literal> en appelant <literal>Property.forName()</literal>.
+        </para>
+
+        <programlisting><![CDATA[
+Property age = Property.forName("age");
+List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.disjunction()
+        .add( age.isNull() )
+        .add( age.eq( new Integer(0) ) )
+        .add( age.eq( new Integer(1) ) )
+        .add( age.eq( new Integer(2) ) )
+    ) )
+    .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
+    .list();]]></programlisting>
+
+   </sect1>
+
+    <sect1 id="querycriteria-ordering">
+        <title>Trier les résultats</title>
+
+        <para>
+            Vous pouvez trier les résultats en utilisant <literal>org.hibernate.criterion.Order</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "F%")
+    .addOrder( Order.asc("name") )
+    .addOrder( Order.desc("age") )
+    .setMaxResults(50)
+    .list();]]></programlisting>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Property.forName("name").like("F%") )
+    .addOrder( Property.forName("name").asc() )
+    .addOrder( Property.forName("age").desc() )
+    .setMaxResults(50)
+    .list();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="querycriteria-associations" revision="2">
+        <title>Associations</title>
+
+        <para>
+            Vous pouvez facilement spécifier des contraintes sur des entités liées,
+        par des associations en utilisant <literal>createCriteria()</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "F%")
+    .createCriteria("kittens")
+        .add( Restrictions.like("name", "F%")
+    .list();]]></programlisting>
+
+        <para>
+            Notez que la seconde <literal>createCriteria()</literal> retourne une nouvelle
+            instance de <literal>Criteria</literal>, qui se rapporte aux éléments de la
+        collection <literal>kittens</literal>.
+        </para>
+
+        <para>
+            La forme alternative suivante est utile dans certains cas.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .createAlias("kittens", "kt")
+    .createAlias("mate", "mt")
+    .add( Restrictions.eqProperty("kt.name", "mt.name") )
+    .list();]]></programlisting>
+
+        <para>
+            (<literal>createAlias()</literal> ne crée pas de nouvelle instance de
+            <literal>Criteria</literal>.)
+        </para>
+
+        <para>
+            Notez que les collections kittens contenues dans les instances de <literal>Cat</literal>
+            retournées par les deux précédentes requêtes ne sont <emphasis>pas</emphasis> pré-filtrées
+            par les critères ! Si vous souhaitez récupérer uniquement les kittens qui correspondent à la
+            criteria, vous devez utiliser <literal>ResultTransformer</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .createCriteria("kittens", "kt")
+        .add( Restrictions.eq("name", "F%") )
+    .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+    .list();
+Iterator iter = cats.iterator();
+while ( iter.hasNext() ) {
+    Map map = (Map) iter.next();
+    Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
+    Cat kitten = (Cat) map.get("kt");
+}]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="querycriteria-dynamicfetching" revision="1">
+        <title>Peuplement d'associations de manière dynamique</title>
+
+        <para>
+            Vous pouvez spéficier au moment de l'exécution le peuplement d'une association en utilisant
+            <literal>setFetchMode()</literal> (c'est-à-dire le chargement de celle-ci).
+            Cela permet de surcharger les valeurs
+            "lazy" et "outer-join" du mapping.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .setFetchMode("mate", FetchMode.EAGER)
+    .setFetchMode("kittens", FetchMode.EAGER)
+    .list();]]></programlisting>
+
+        <para>
+            Cette requête recherchera <literal>mate</literal> et <literal>kittens</literal>
+            via les jointures externes. Voir <xref linkend="performance-fetching"/> pour plus d'informations.
+        </para>
+
+    </sect1>
+
+    <sect1 id="querycriteria-examples">
+        <title>Requêtes par l'exemple</title>
+
+        <para>
+            La classe <literal>org.hibernate.criterion.Example</literal> vous permet de
+            construire un critère suivant une instance d'objet donnée.
+        </para>
+
+        <programlisting><![CDATA[Cat cat = new Cat();
+cat.setSex('F');
+cat.setColor(Color.BLACK);
+List results = session.createCriteria(Cat.class)
+    .add( Example.create(cat) )
+    .list();]]></programlisting>
+
+        <para>
+            Les propriétés de type version, identifiant et association sont ignorées.
+       Par défaut, les valeurs null sont exclues.
+        </para>
+
+        <para>
+            Vous pouvez ajuster la stratégie d'utilisation de valeurs de
+           l'<literal>Exemple</literal>.
+        </para>
+
+        <programlisting><![CDATA[Example example = Example.create(cat)
+    .excludeZeroes()           //exclude zero valued properties
+    .excludeProperty("color")  //exclude the property named "color"
+    .ignoreCase()              //perform case insensitive string comparisons
+    .enableLike();             //use like for string comparisons
+List results = session.createCriteria(Cat.class)
+    .add(example)
+    .list();]]></programlisting>
+
+        <para>
+            Vous pouvez utiliser les "exemples" pour des critères sur les objets associés.
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .add( Example.create(cat) )
+    .createCriteria("mate")
+        .add( Example.create( cat.getMate() ) )
+    .list();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="querycriteria-projection">
+        <title>Projections, agrégation et regroupement</title>
+        <para>
+            La classe <literal>org.hibernate.criterion.Projections</literal> est une
+            fabrique d'instances de <literal>Projection</literal>. Nous appliquons une
+            projection sur une requête en appelant <literal>setProjection()</literal>.
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.rowCount() )
+    .add( Restrictions.eq("color", Color.BLACK) )
+    .list();]]></programlisting>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount() )
+        .add( Projections.avg("weight") )
+        .add( Projections.max("weight") )
+        .add( Projections.groupProperty("color") )
+    )
+    .list();]]></programlisting>
+
+        <para>
+            Il n'y a pas besoin de "group by" explicite dans une requête par critère.
+            Certains types de projection sont définis pour être des <emphasis>projections
+            de regroupement</emphasis>, lesquels apparaissent aussi dans la clause
+            <literal>group by</literal> SQL.
+        </para>
+
+        <para>
+            Un alias peut optionnellement être assigné à une projection, ainsi la valeur
+            projetée peut être référencée dans des restrictions ou des tris. Voici deux façons
+            différentes de faire ça :
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
+    .addOrder( Order.asc("colr") )
+    .list();]]></programlisting>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.groupProperty("color").as("colr") )
+    .addOrder( Order.asc("colr") )
+    .list();]]></programlisting>
+
+        <para>
+            Les méthodes <literal>alias()</literal> et <literal>as()</literal> enveloppe simplement
+            une instance de projection dans une autre instance (aliasée) de <literal>Projection</literal>.
+            Comme un raccourci, vous pouvez assignez un alias lorsque vous ajoutez la projection à la
+            liste de projections :
+        </para>
+
+       <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount(), "catCountByColor" )
+        .add( Projections.avg("weight"), "avgWeight" )
+        .add( Projections.max("weight"), "maxWeight" )
+        .add( Projections.groupProperty("color"), "color" )
+    )
+    .addOrder( Order.desc("catCountByColor") )
+    .addOrder( Order.desc("avgWeight") )
+    .list();]]></programlisting>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Domestic.class, "cat")
+    .createAlias("kittens", "kit")
+    .setProjection( Projections.projectionList()
+        .add( Projections.property("cat.name"), "catName" )
+        .add( Projections.property("kit.name"), "kitName" )
+    )
+    .addOrder( Order.asc("catName") )
+    .addOrder( Order.asc("kitName") )
+    .list();]]></programlisting>
+
+        <para>
+            Vous pouvez aussi utiliser <literal>Property.forName()</literal> pour formuler des projections :
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Property.forName("name") )
+    .add( Property.forName("color").eq(Color.BLACK) )
+    .list();]]></programlisting>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount().as("catCountByColor") )
+        .add( Property.forName("weight").avg().as("avgWeight") )
+        .add( Property.forName("weight").max().as("maxWeight") )
+        .add( Property.forName("color").group().as("color" )
+    )
+    .addOrder( Order.desc("catCountByColor") )
+    .addOrder( Order.desc("avgWeight") )
+    .list();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="querycriteria-detachedqueries">
+        <title>Requêtes et sous-requêtes détachées</title>
+        <para>
+            La classe <literal>DetachedCriteria</literal> vous laisse créer une requête en dehors de la
+            portée de la session, et puis l'exécuter plus tard en utilisant n'importe quelle <literal>Session</literal>
+            arbitraire.
+        </para>
+
+        <programlisting><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
+    .add( Property.forName("sex").eq('F') );
+
+Session session = ....;
+Transaction txn = session.beginTransaction();
+List results = query.getExecutableCriteria(session).setMaxResults(100).list();
+txn.commit();
+session.close();]]></programlisting>
+
+        <para>
+            Une <literal>DetachedCriteria</literal> peut aussi être utilisée pour exprimer une
+            sous-requête. Des instances de criterion impliquant des sous-requêtes peuvent être
+            obtenues via <literal>Subqueries</literal> ou <literal>Property</literal>.
+        </para>
+
+        <programlisting><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
+    .setProjection( Property.forName("weight").avg() );
+session.createCriteria(Cat.class)
+    .add( Property.forName("weight).gt(avgWeight) )
+    .list();]]></programlisting>
+
+        <programlisting><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
+    .setProjection( Property.forName("weight") );
+session.createCriteria(Cat.class)
+    .add( Subqueries.geAll("weight", weights) )
+    .list();]]></programlisting>
+
+        <para>
+            Même des requêtes corrélées sont possibles :
+        </para>
+
+        <programlisting><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
+    .setProjection( Property.forName("weight").avg() )
+    .add( Property.forName("cat2.sex").eqProperty("cat.sex") );
+session.createCriteria(Cat.class, "cat")
+    .add( Property.forName("weight).gt(avgWeightForSex) )
+    .list();]]></programlisting>
+
+    </sect1>
+
+        <!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer allow returning arbitrary
+                  user objects - similar to setResultClass in JDO2. General use of ResultTransformer
+                  could also be explained. -->
+
+    <sect1 id="query-criteria-naturalid">
+        <title>Requêtes par identifiant naturel</title>
+
+        <para>
+            Pour la plupart des requêtes, incluant les requêtes par critère, le cache de requêtes
+            n'est pas très efficace, parce que l'invalidation du cache de requêtes arrive trop
+            souvent. Cependant, il y a une sorte spéciale de requête où nous pouvons optimiser
+            l'algorithme d'invalidation du cache : les recherches sur une clef naturelle constante.
+            Dans certaines applications, cette sorte de requête se produit fréquemment. L'API de
+            critère fournit une provision spéciale pour ce cas d'utilisation.
+        </para>
+
+        <para>
+            D'abord vous devriez mapper la clef naturelle de votre entité en utilisant
+            <literal>&lt;natural-id&gt;</literal>, et activer l'utilisation du cache de second niveau.
+        </para>
+
+        <programlisting><![CDATA[<class name="User">
+    <cache usage="read-write"/>
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <natural-id>
+        <property name="name"/>
+        <property name="org"/>
+    </natural-id>
+    <property name="password"/>
+</class>]]></programlisting>
+
+        <para>
+            Notez que cette fonctionnalité n'est pas prévue pour l'utilisation avec des
+            entités avec des clefs naturelles <emphasis>mutables</emphasis>.
+        </para>
+
+        <para>
+            Ensuite, activez le cache de requête d'Hibernate.
+        </para>
+
+        <para>
+            Maintenant <literal>Restrictions.naturalId()</literal> nous permet de rendre
+            l'utilisation de l'algorithme de cache plus efficace.
+        </para>
+
+        <programlisting><![CDATA[session.createCriteria(User.class)
+    .add( Restrictions.naturalId()
+        .set("name", "gavin")
+        .set("org", "hb")
+    ).setCacheable(true)
+    .uniqueResult();]]></programlisting>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/query_hql.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/query_hql.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/query_hql.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1149 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="queryhql">
+    <title>HQL: Langage de requêtage d'Hibernate</title>
+
+    <para>
+        Hibernate fourni un langage d'interrogation extrêmement puissant qui
+        ressemble (et c'est voulu) au SQL. Mais ne soyez pas distraits par la syntaxe ;
+        HQL est totalement orienté objet, comprenant des notions d'héritage, de
+        polymorphisme et d'association.
+    </para>
+
+    <sect1 id="queryhql-casesensitivity">
+        <title>Sensibilité à la casse</title>
+
+        <para>
+            Les requêtes sont insensibles à la casse, à l'exception des noms des classes Java
+            et des propriétés.
+            Ainsi, <literal>SeLeCT</literal> est identique à
+            <literal>sELEct</literal> et à
+            <literal>SELECT</literal> mais
+            <literal>net.sf.hibernate.eg.FOO</literal> n'est pas identique
+            <literal>net.sf.hibernate.eg.Foo</literal> et
+            <literal>foo.barSet</literal> n'est pas identique à
+            <literal>foo.BARSET</literal>.
+        </para>
+
+        <para>
+            Ce guide utilise les mots clés HQL en minuscule. Certains utilisateurs trouvent les
+            requêtes écrites avec les mots clés en majuscule plus lisibles, mais nous trouvons
+            cette convention pénible lorsqu'elle est lue dans du code Java.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-from">
+        <title>La clause from</title>
+
+        <para>
+            La requête Hibernate la plus simple est de la forme :
+        </para>
+
+        <programlisting><![CDATA[from eg.Cat]]></programlisting>
+
+        <para>
+            qui retourne simplement toutes les instances de la classe <literal>eg.Cat</literal>. 
+            Nous n'avons pas besoin d'habitude de qualifier le nom de la classe, 
+            puisque <literal>auto-import</literal> est la valeur par défaut. Donc nous écrivons presque toujours :
+        </para>
+
+        <programlisting><![CDATA[from Cat]]></programlisting>
+
+        <para>
+            La plupart du temps, vous devrez assigner un <emphasis>alias</emphasis> puisque vous
+            voudrez faire référence à <literal>Cat</literal> dans d'autres parties de la requête.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+        <para>
+            Cette requête assigne l'alias <literal>cat</literal> à l'instance <literal>Cat</literal>,
+            nous pouvons donc utiliser cet alias ailleurs dans la requête. Le mot clé <literal>as</literal>
+            est optionnel ; nous aurions pu écrire :
+        </para>
+
+        <programlisting><![CDATA[from Cat cat]]></programlisting>
+
+        <para>
+            Plusieurs classes peuvent apparaître, ce qui conduira à un produit
+            cartésien (encore appelé jointures croisées).
+        </para>
+
+        <programlisting><![CDATA[from Formula, Parameter]]></programlisting>
+        <programlisting><![CDATA[from Formula as form, Parameter as param]]></programlisting>
+
+        <para>
+            C'est une bonne pratique que de nommer les alias dans les requêtes en utilisant l'initiale
+            en miniscule, ce qui a le mérite d'être en phase avec les standards de
+            nommage Java pour les variables locales (<literal>domesticCat</literal>).
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-joins" revision="1">
+        <title>Associations et jointures</title>
+
+        <para>
+            On peut aussi assigner des alias à des entités associées, ou même aux éléments d'une collection
+            de valeurs, en utilisant un <literal>join</literal> (jointure).
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat
+    inner join cat.mate as mate
+    left outer join cat.kittens as kitten]]></programlisting>
+
+        <programlisting><![CDATA[from Cat as cat left join cat.mate.kittens as kittens]]></programlisting>
+
+        <programlisting><![CDATA[from Formula form full join form.parameter param]]></programlisting>
+
+        <para>
+            Les types de jointures supportées sont celles de ANSI SQL
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>inner join</literal> (jointure fermée)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>left outer join</literal> (jointure ouverte par la gauche)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>right outer join</literal> (jointure ouverte par la droite)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>full join</literal> (jointure ouverte totalement - généralement inutile)
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Les constructions des jointures <literal>inner join</literal>, <literal>left outer join</literal>
+            et <literal>right outer join</literal> peuvent être abbrégées.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat
+    join cat.mate as mate
+    left join cat.kittens as kitten]]></programlisting>
+
+        <para>
+            Nous pouvons soumettre des conditions de jointure supplémentaires en utilisant le mot-clef HQL <literal>with</literal>.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat
+    left join cat.kittens as kitten
+        with kitten.bodyWeight > 10.0]]></programlisting>
+
+        <para>
+            Par ailleurs, une jointure "fetchée" (rapportée) permet d'initialiser
+            les associations ou collections de valeurs en même temps que leur objet parent,
+            le tout n'utilisant qu'un seul Select.
+            Ceci est particulièrement utile dans le cas des collections. Ce système permet de surcharger
+            les déclarations "lazy" et "outer-join" des fichiers de mapping pour les associations et
+            collections. Voir
+            <xref linkend="performance-fetching"/> pour plus d'informations.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat
+    inner join fetch cat.mate
+    left join fetch cat.kittens]]></programlisting>
+
+        <para>
+            Une jointure "fetchée" (rapportée) n'a généralement pas besoin de se voir assigner
+            un alias puisque les objets associés n'ont pas à être utilisés dans les autres clauses.
+            Notez aussi que les objets associés ne sont pas retournés directement dans le résultat de
+            la requête mais l'on peut y accéder via l'objet parent. La seule raison pour laquelle nous 
+            pourrions avoir besoin d'un alias est si nous récupérions récursivement une collection supplémentaire :
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat
+    inner join fetch cat.mate
+    left join fetch cat.kittens child
+    left join fetch child.kittens]]></programlisting>
+
+        <para>
+            Notez que la construction de <literal>fetch</literal> ne peut pas être utilisée dans les requêtes appelées par
+            <literal>scroll()</literal> ou <literal>iterate()</literal>.
+            <literal>fetch</literal> ne devrait pas non plus être utilisé avec <literal>setMaxResults()</literal> ou
+            <literal>setFirstResult()</literal>. <literal>fetch</literal> ne peut pas non plus être utilisé avec une 
+            condition <literal>with</literal> ad hoc. Il est
+            possible de créer un produit cartésien par jointure en récupérant plus d'une collection dans une requête, 
+            donc faites attention dans ce cas. Récupérer par jointure de multiples collections donne aussi parfois 
+            des résultats inattendus pour des mappings de bag, donc soyez prudent lorsque vous formulez vos requêtes dans de tels cas.
+            Finalement, notez que <literal>full join fetch</literal> et <literal>right join fetch</literal> ne sont pas utiles en général.
+        </para>
+
+        <para>
+            Si vous utilisez un chargement retardé pour les propriétés (avec une instrumentation par bytecode), il est possible 
+            de forcer Hibernate à récupérer les propriétés non encore chargées immédiatement (dans la première requête) 
+            en utilisant <literal>fetch all properties</literal>.
+        </para>
+
+        <programlisting><![CDATA[from Document fetch all properties order by name]]></programlisting>
+        <programlisting><![CDATA[from Document doc fetch all properties where lower(doc.name) like '%cats%']]></programlisting>
+
+    </sect1>
+    
+        <sect1 id="queryhql-joins-forms">
+        <title>Formes de syntaxes pour les jointures</title>
+
+        <para>
+            HQL supporte deux formes pour joindre les associations: <literal>implicite</literal> et <literal>explicite</literal>.
+        </para>
+
+        <para>
+            Les requêtes présentes dans la section précédente utilisent la forme <literal>explicite</literal> 
+            où le mode clé join est explicitement utilisé dans la clause from. C'est la forme recommandée.
+        </para>
+
+        <para>
+            La forme <literal>implicite</literal> n'utilise pas le mot clé join.
+            A la place, les associations sont "déréférencées" en utilisant le notation '.'. Ces
+            jointures peuvent apparaitre dans toutes les clauses. Les jointures <literal>implicites</literal> 
+            résultent en des inner join dans le SQL généré.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.mate.name like '%s%']]></programlisting>
+    </sect1>
+
+    <sect1 id="queryhql-select">
+        <title>La clause select</title>
+
+        <para>
+            La clause <literal>select</literal> sélectionne les objets et propriétés
+            qui doivent être retournés dans le résultat de la requête.
+        Soit :
+        </para>
+
+        <programlisting><![CDATA[select mate
+from Cat as cat
+    inner join cat.mate as mate]]></programlisting>
+
+        <para>
+            La requête recherchera les <literal>mate</literal>s liés aux <literal>Cat</literal>s.
+            Vous pouvez explimer la requête d'une manière plus compacte :
+        </para>
+
+        <programlisting><![CDATA[select cat.mate from Cat cat]]></programlisting>
+
+        <para>
+            Les requêtes peuvent retourner des propriétés de n'importe quel type, même celles de type
+        composant (component) :
+        </para>
+
+        <programlisting><![CDATA[select cat.name from DomesticCat cat
+where cat.name like 'fri%']]></programlisting>
+
+        <programlisting><![CDATA[select cust.name.firstName from Customer as cust]]></programlisting>
+
+        <para>
+            Les requêtes peuvent retourner plusieurs objets et/ou propriétés sous la forme
+        d'un tableau du type <literal>Object[]</literal>,
+        </para>
+
+        <programlisting><![CDATA[select mother, offspr, mate.name
+from DomesticCat as mother
+    inner join mother.mate as mate
+    left outer join mother.kittens as offspr]]></programlisting>
+
+        <para>
+            ou sous la forme d'une <literal>List</literal>,
+        </para>
+
+        <programlisting><![CDATA[select new list(mother, offspr, mate.name)
+from DomesticCat as mother
+    inner join mother.mate as mate
+    left outer join mother.kittens as offspr]]></programlisting>
+
+        <para>
+            ou sous la forme d'un objet Java typé,
+        </para>
+
+        <programlisting><![CDATA[select new Family(mother, mate, offspr)
+from DomesticCat as mother
+    join mother.mate as mate
+    left join mother.kittens as offspr]]></programlisting>
+
+        <para>
+            à condition que la classe <literal>Family</literal> possède le constructeur approprié.
+        </para>
+
+        <para>
+            Vous pouvez assigner des alias aux expressions sélectionnées en utilisant <literal>as</literal> :
+        </para>
+
+        <programlisting><![CDATA[select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
+from Cat cat]]></programlisting>
+
+        <para>
+            C'est surtout utile lorsque c'est utilisé avec
+            <literal>select new map</literal> :
+        </para>
+
+        <programlisting><![CDATA[select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
+from Cat cat]]></programlisting>
+
+        <para>
+            Cette requête retourne une <literal>Map</literal> à partir des alias vers les valeurs sélectionnées.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-aggregation">
+        <title>Fonctions d'aggrégation</title>
+
+        <para>
+            Les requêtes HQL peuvent aussi retourner le résultat de fonctions d'aggrégation
+            sur les propriétés :
+        </para>
+
+        <programlisting><![CDATA[select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
+from Cat cat]]></programlisting>
+
+<!-- NO LONGER SUPPORTED
+        <para>
+            Collections may also appear inside aggregate functions in the <literal>select</literal>
+            clause.
+        </para>
+
+        <programlisting><![CDATA[select cat, count( elements(cat.kittens) )
+from Cat cat group by cat]]></programlisting>
+-->
+
+        <para>
+            Les fonctions supportées sont
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>avg(...), sum(...), min(...), max(...)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>count(*)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>count(...), count(distinct ...), count(all...)</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Vous pouvez utiliser des opérateurs arithmétiques, la concaténation, et des fonctions SQL reconnues dans la clause select :
+        </para>
+
+        <programlisting><![CDATA[select cat.weight + sum(kitten.weight)
+from Cat cat
+    join cat.kittens kitten
+group by cat.id, cat.weight]]></programlisting>
+
+        <programlisting><![CDATA[select firstName||' '||initial||' '||upper(lastName) from Person]]></programlisting>
+
+        <para>
+            Les mots clé <literal>distinct</literal> et <literal>all</literal> peuvent être utilisés et ont
+        la même signification qu'en SQL.
+        </para>
+
+        <programlisting><![CDATA[select distinct cat.name from Cat cat
+
+select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-polymorphism">
+        <title>Requêtes polymorphiques</title>
+
+        <para>
+            Une requête comme:
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+        <para>
+            retourne non seuleument les instances de <literal>Cat</literal>, mais aussi celles des
+            sous classes comme <literal>DomesticCat</literal>. Les requêtes Hibernate peuvent nommer n'importe
+            quelle classe ou interface Java dans la clause <literal>from</literal>. La requête retournera les
+            instances de toutes les classes persistantes qui étendent cette classe ou implémente cette interface.
+        La requête suivante retournera tous les objets persistants :
+        </para>
+
+        <programlisting><![CDATA[from java.lang.Object o]]></programlisting>
+
+        <para>
+            L'interface <literal>Named</literal> peut être implémentée par plusieurs classes persistantes :
+        </para>
+
+        <programlisting><![CDATA[from Named n, Named m where n.name = m.name]]></programlisting>
+
+        <para>
+            Notez que ces deux dernières requêtes nécessitent plus d'un <literal>SELECT</literal> SQL.
+            Ce qui signifie que la clause <literal>order by</literal> ne trie pas correctement la totalité
+            des résultats (cela signifie aussi que vous ne pouvez exécuter ces requêtes en appelant
+        <literal>Query.scroll()</literal>).
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-where">
+        <title>La clause where</title>
+
+        <para>
+            La clause <literal>where</literal> vous permet de réduire la liste des instances retournées. 
+            Si aucun alias n'existe, vous pouvez vous référer aux propriétés par leur nom :
+        </para>
+
+        <programlisting><![CDATA[from Cat where name='Fritz']]></programlisting>
+
+        <para>
+            S'il y a un alias, utilisez un nom de propriété qualifié :
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.name='Fritz']]></programlisting>
+
+        <para>
+            retourne les instances de <literal>Cat</literal> dont name est égale à 'Fritz'.
+        </para>
+
+        <programlisting><![CDATA[select foo
+from Foo foo, Bar bar
+where foo.startDate = bar.date]]></programlisting>
+
+        <para>
+            retournera les instances de <literal>Foo</literal> pour lesquelles
+            il existe une instance de <literal>bar</literal> avec la
+            propriété <literal>date</literal> est égale à la
+            propriété <literal>startDate</literal> de <literal>Foo</literal>.
+            Les expressions utilisant la navigation rendent la clause <literal>where</literal>
+        extrêmement puissante. Soit :
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.mate.name is not null]]></programlisting>
+
+        <para>
+            Cette requête se traduit en SQL par une jointure interne à une table.
+        Si vous souhaitez écrire quelque chose comme :
+        </para>
+
+        <programlisting><![CDATA[from Foo foo
+where foo.bar.baz.customer.address.city is not null]]></programlisting>
+
+        <para>
+            vous finiriez avec une requête qui nécessiterait quatre jointures en SQL.
+        </para>
+
+        <para>
+            L'opérateur <literal>=</literal> peut être utilisé pour comparer aussi bien des propriétés que des instances :
+        </para>
+
+        <programlisting><![CDATA[from Cat cat, Cat rival where cat.mate = rival.mate]]></programlisting>
+
+        <programlisting><![CDATA[select cat, mate
+from Cat cat, Cat mate
+where cat.mate = mate]]></programlisting>
+
+        <para>
+            La propriété spéciale (en minuscule) <literal>id</literal> peut être utilisée
+            pour faire référence à l'identifiant d'un objet (vous pouvez aussi utiliser
+        le nom de cette propriété).
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.id = 123
+
+from Cat as cat where cat.mate.id = 69]]></programlisting>
+
+        <para>
+            La seconde requête est particulièrement efficace. Aucune jointure n'est nécessaire !
+        </para>
+
+        <para>
+            Les propriétés d'un identifiant composé peuvent aussi être utilisées. Supposez que
+            <literal>Person</literal> ait un identifiant composé de <literal>country</literal> et
+            <literal>medicareNumber</literal>.
+        </para>
+
+        <programlisting><![CDATA[from bank.Person person
+where person.id.country = 'AU'
+    and person.id.medicareNumber = 123456]]></programlisting>
+
+        <programlisting><![CDATA[from bank.Account account
+where account.owner.id.country = 'AU'
+    and account.owner.id.medicareNumber = 123456]]></programlisting>
+
+        <para>
+            Une fois de plus, la seconde requête ne nécessite pas de jointure.
+        </para>
+
+        <para>
+            De même, la propriété spéciale <literal>class</literal> interroge la valeur discriminante
+            d'une instance dans le cas d'une persistance polymorphique. Le nom d'une classe Java incorporée
+        dans la clause where sera traduite par sa valeur discriminante.
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
+
+        <para>
+            Vous pouvez aussi spécifier les propriétés des composants ou types utilisateurs composés
+            (components, composite user types etc). N'essayez jamais d'utiliser un expression de navigation
+            qui se terminerait par une propriété de type composant (qui est différent d'une propriété d'un
+            composant). Par exemple, si <literal>store.owner</literal> est une entité avec un composant
+        <literal>address</literal>
+        </para>
+
+        <programlisting><![CDATA[store.owner.address.city    // okay
+store.owner.address         // error!]]></programlisting>
+
+        <para>
+            Un type "any" possède les propriétés spéciales <literal>id</literal> et <literal>class</literal>,
+            qui nous permettent d'exprimer une jointure de la manière suivante (où <literal>AuditLog.item</literal>
+            est une propriété mappée avec <literal>&lt;any&gt;</literal>).
+        </para>
+
+        <programlisting><![CDATA[from AuditLog log, Payment payment
+where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting>
+
+        <para>
+            Dans la requête précédente, notez que <literal>log.item.class</literal> et <literal>payment.class</literal>
+            feraient référence à des valeurs de colonnes de la base de données complètement différentes.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-expressions">
+        <title>Expressions</title>
+
+        <para>
+            Les expressions permises dans la clause <literal>where</literal> incluent
+        la plupart des choses que vous pouvez utiliser en SQL :
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    opérateurs mathématiques <literal>+, -, *, /</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    opérateur de comparaison binaire <literal>=, &gt;=, &lt;=, &lt;&gt;, !=, like</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    opérateurs logiques <literal>and, or, not</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Parenthèses <literal>( )</literal>, indiquant un regroupement
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>in</literal>,
+                    <literal>not in</literal>,
+                    <literal>between</literal>,
+                    <literal>is null</literal>,
+                    <literal>is not null</literal>,
+                    <literal>is empty</literal>,
+                    <literal>is not empty</literal>,
+                    <literal>member of</literal> and
+                    <literal>not member of</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    "Simple" case, <literal>case ... when ... then ... else ... end</literal>, and
+                    "searched" case, <literal>case when ... then ... else ... end</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    concatenation de chaîne de caractères <literal>...||...</literal> ou <literal>concat(...,...)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>current_date()</literal>, <literal>current_time()</literal>,
+                    <literal>current_timestamp()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>second(...)</literal>, <literal>minute(...)</literal>,
+                    <literal>hour(...)</literal>, <literal>day(...)</literal>,
+                    <literal>month(...)</literal>, <literal>year(...)</literal>,
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    N'importe quel fonction ou opérateur défini par EJB-QL 3.0 : <literal>substring(), trim(),
+                    lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>coalesce()</literal> et <literal>nullif()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>str()</literal> pour convertir des valeurs numériques ou temporelles vers une chaîne de caractères lisible
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>cast(... as ...)</literal>, où le second argument est le nom d'un type Hibernate, et <literal>extract(... from ...)</literal> si le
+                    <literal>cast()</literal> ANSI et <literal>extract()</literal> sont supportés par la base de données sous-jacente
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    La fonction HQL <literal>index()</literal>, qui s'applique aux alias d'une collection indexée jointe
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Les fonctions HQL qui s'appliquent expressions représentant des collections : <literal>size(),
+                    minelement(), maxelement(), minindex(), maxindex()</literal>, ainsi que les fonctions spéciales <literal>elements()</literal> 
+                    et <literal>indices</literal> qui peuvent être quantifiées en utilisant <literal>some, all, exists, any, in</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    N'importe quelle fonction scalaire supportée par la base de données comme
+                    <literal>sign()</literal>,
+                    <literal>trunc()</literal>, <literal>rtrim()</literal>, <literal>sin()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Les paramètres positionnels de JDBC
+                    <literal>?</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    paramètres nommés <literal>:name</literal>, <literal>:start_date</literal>, <literal>:x1</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    littéral SQL <literal>'foo'</literal>, <literal>69</literal>, <literal>'1970-01-01 10:00:01.0'</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Constantes Java <literal>public static final</literal> <literal>eg.Color.TABBY</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>in</literal> et <literal>between</literal> peuvent être utilisés comme suit :
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name between 'A' and 'B']]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+        <para>
+            et la forme négative peut être écrite
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name not between 'A' and 'B']]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+        <para>
+            De même, <literal>is null</literal> et <literal>is not null</literal> peuvent être utilisés pour tester
+        les valeurs nulle.
+        </para>
+
+        <para>
+            Les booléens peuvent être facilement utilisés en déclarant les substitutions de requêtes dans la
+        configuration Hibernate :
+        </para>
+
+        <programlisting><![CDATA[<property name="hibernate.query.substitutions">true 1, false 0</property>]]></programlisting>
+
+        <para>
+            Ce qui remplacera les mots clés <literal>true</literal> et <literal>false</literal> par
+            <literal>1</literal> et <literal>0</literal> dans la traduction SQL du HQL suivant :
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.alive = true]]></programlisting>
+
+        <para>
+            Vous pouvez tester la taille d'une collection par la propriété spéciale <literal>size</literal>, ou
+            la fonction spéciale <literal>size()</literal>.
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.kittens.size > 0]]></programlisting>
+
+        <programlisting><![CDATA[from Cat cat where size(cat.kittens) > 0]]></programlisting>
+
+        <para>
+            Pour les collections indexées, vous pouvez faire référence aux indices minimum et maximum en
+            utilisant les fonctions <literal>minindex</literal> and <literal>maxindex</literal>. De manière similaire,
+            vous pouvez faire référence aux éléments minimum et maximum d'une collection de type basiques
+        en utilisant les fonctions <literal>minelement</literal> et <literal>maxelement</literal>.
+        </para>
+
+        <programlisting><![CDATA[from Calendar cal where maxelement(cal.holidays) > current date]]></programlisting>
+
+        <programlisting><![CDATA[from Order order where maxindex(order.items) > 100]]></programlisting>
+
+        <programlisting><![CDATA[from Order order where minelement(order.items) > 10000]]></programlisting>
+
+        <para>
+            Les fonctions SQL <literal>any, some, all, exists, in</literal> supportent que leur soient passées
+            l'élément, l'index d'une collection (fonctions <literal>elements</literal> et <literal>indices</literal>)
+        ou le résultat d'une sous requête (voir ci dessous).
+        </para>
+
+        <programlisting><![CDATA[select mother from Cat as mother, Cat as kit
+where kit in elements(foo.kittens)]]></programlisting>
+
+        <programlisting><![CDATA[select p from NameList list, Person p
+where p.name = some elements(list.names)]]></programlisting>
+
+        <programlisting><![CDATA[from Cat cat where exists elements(cat.kittens)]]></programlisting>
+
+        <programlisting><![CDATA[from Player p where 3 > all elements(p.scores)]]></programlisting>
+
+        <programlisting><![CDATA[from Show show where 'fizard' in indices(show.acts)]]></programlisting>
+
+        <para>
+            Notez que l'écriture de - <literal>size</literal>, <literal>elements</literal>,
+            <literal>indices</literal>, <literal>minindex</literal>, <literal>maxindex</literal>,
+            <literal>minelement</literal>, <literal>maxelement</literal> - peuvent seulement être utilisée dans la clause where dans Hibernate3.
+        </para>
+
+        <para>
+            Les éléments de collections indexées (arrays, lists, maps) peuvent être référencés via index
+        (dans une clause where seulement) :
+        </para>
+
+        <programlisting><![CDATA[from Order order where order.items[0].id = 1234]]></programlisting>
+
+        <programlisting><![CDATA[select person from Person person, Calendar calendar
+where calendar.holidays['national day'] = person.birthDay
+    and person.nationality.calendar = calendar]]></programlisting>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11]]></programlisting>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ maxindex(order.items) ] = item and order.id = 11]]></programlisting>
+
+        <para>
+            L'expression entre <literal>[]</literal> peut même être une expression arithmétique.
+        </para>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ size(order.items) - 1 ] = item]]></programlisting>
+
+        <para>
+            HQL propose aussi une fonction <literal>index()</literal> interne, pour les éléments
+        d'une association one-to-many ou d'une collections de valeurs.
+        </para>
+
+        <programlisting><![CDATA[select item, index(item) from Order order
+    join order.items item
+where index(item) < 5]]></programlisting>
+
+        <para>
+            Les fonctions SQL scalaires supportées par la base de données utilisée peuvent être utilisées
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like 'FRI%']]></programlisting>
+
+        <para>
+            Si vous n'êtes pas encore convaincu par tout cela, imaginez la taille et l'illisibilité qui caractériseraient
+        la transformation SQL de la requête HQL suivante :
+        </para>
+
+        <programlisting><![CDATA[select cust
+from Product prod,
+    Store store
+    inner join store.customers cust
+where prod.name = 'widget'
+    and store.location.name in ( 'Melbourne', 'Sydney' )
+    and prod = all elements(cust.currentOrder.lineItems)]]></programlisting>
+
+        <para>
+            <emphasis>Un indice :</emphasis> cela donnerait quelque chose comme
+        </para>
+
+        <programlisting><![CDATA[SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
+FROM customers cust,
+    stores store,
+    locations loc,
+    store_customers sc,
+    product prod
+WHERE prod.name = 'widget'
+    AND store.loc_id = loc.id
+    AND loc.name IN ( 'Melbourne', 'Sydney' )
+    AND sc.store_id = store.id
+    AND sc.cust_id = cust.id
+    AND prod.id = ALL(
+        SELECT item.prod_id
+        FROM line_items item, orders o
+        WHERE item.order_id = o.id
+            AND cust.current_order = o.id
+    )]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-ordering">
+        <title>La clause order by</title>
+
+        <para>
+            La liste retounée par la requête peut être triée par n'importe quelle propriété de la classe ou
+        du composant retourné :
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat
+order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
+
+        <para>
+            Le mot optionnel <literal>asc</literal> ou <literal>desc</literal> indique respectivement si le tri
+        doit être croissant ou décroissant.
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-grouping">
+        <title>La clause group by</title>
+
+        <para>
+            Si la requête retourne des valeurs aggrégées, celles ci peuvent être groupées par propriété ou composant :
+        </para>
+
+        <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
+from Cat cat
+group by cat.color]]></programlisting>
+
+        <programlisting><![CDATA[select foo.id, avg(name), max(name)
+from Foo foo join foo.names name
+group by foo.id]]></programlisting>
+
+        <para>
+            Une clause <literal>having</literal> est aussi permise.
+        </para>
+
+        <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
+from Cat cat
+group by cat.color
+having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
+
+        <para>
+            Les fonctions SQL et les fonctions d'aggrégations sont permises dans les clauses <literal>having</literal>
+            et <literal>order by</literal>, si elles sont supportées par la base de données (ce que ne fait pas MySQL par exemple).
+        </para>
+
+        <programlisting><![CDATA[select cat
+from Cat cat
+    join cat.kittens kitten
+group by cat
+having avg(kitten.weight) > 100
+order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
+
+        <para>
+            Notez que ni la clause <literal>group by</literal> ni la clause
+            <literal>order by</literal> ne peuvent contenir d'expressions arithmétiques.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-subqueries" revision="2">
+        <title>Sous-requêtes</title>
+
+        <para>
+            Pour les bases de données le supportant, Hibernate supporte les sous requêtes dans les requêtes.
+            Une sous requête doit être entre parenthèses (souvent pour un appel à une fonction d'agrégation SQL)
+            Même les sous requêtes corrélées (celles qui font référence à un alias de la requête principale) sont
+        supportées.
+        </para>
+
+        <programlisting><![CDATA[from Cat as fatcat
+where fatcat.weight > (
+    select avg(cat.weight) from DomesticCat cat
+)]]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat as cat
+where cat.name = some (
+    select name.nickName from Name as name
+)]]></programlisting>
+
+        <programlisting><![CDATA[from Cat as cat
+where not exists (
+    from Cat as mate where mate.mate = cat
+)]]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat as cat
+where cat.name not in (
+    select name.nickName from Name as name
+)]]></programlisting>
+
+        <programlisting><![CDATA[select cat.id, (select max(kit.weight) from cat.kitten kit)
+from Cat as cat]]></programlisting>
+
+        <para>
+            Notez que les sous-requêtes HQL peuvent arriver seulememnt dans les clauses select ou where.
+        </para>
+
+        <para>
+            Pour des sous-requêtes avec plus d'une expression dans le select, vous pouvez utiliser un constructeur de tuples :
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat
+where not ( cat.name, cat.color ) in (
+    select cat.name, cat.color from DomesticCat cat
+)]]></programlisting>
+
+        <para>
+            Notez que sur certaines bases de données (mais par Oracle ou HSQL), vous pouvez utiliser des constructeurs de tuples 
+            dans d'autres contextes, par exemple lors du requêtage de composants ou de types utilisateur composites :
+        </para>
+
+        <programlisting><![CDATA[from Person where name = ('Gavin', 'A', 'King')]]></programlisting>
+
+        <para>
+            Ce qui est équivalent à la forme plus verbeuse suivante :
+        </para>
+
+        <programlisting><![CDATA[from Person where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')]]></programlisting>
+
+        <para>
+            Il y a deux bonnes raisons que vous ne puissiez ne pas vouloir faire cette sorte de choses : d'abord, ce n'est
+            pas complètement portable entre les plateformes de base de données ; deuxièmement, la requête est maintenant
+            dépendante de l'ordre des propriétés dans le document de mapping.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-examples">
+        <title>Exemples HQL</title>
+
+        <para>
+            Les requêtes Hibernate peuvent être relativement puissantes et complexes. En fait, la puissance
+            du langage de requêtage est l'un des avantages principaux d'Hibernate. Voici quelques exemples
+            très similaires aux requêtes que nous avons utilisées lors d'un récent projet. Notez que la plupart
+        des requêtes que vous écrirez seront plus simples que les exemples suivantes !
+        </para>
+
+        <para>
+            La requête suivante retourne l'id de commande (order), le nombre d'articles (items) et la valeur
+            totale de la commande (order) pour toutes les commandes non payées d'un client (customer) particulier
+            pour un total minimum donné, le tout trié par la valeur totale. La requête SQL générée sur les tables
+            <literal>ORDER</literal>, <literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>,
+            <literal>CATALOG</literal> et <literal>PRICE</literal> est composée de quatre jointures interne ainsi que
+        d'une sous-requête (non corrélée).
+        </para>
+
+        <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+    join order.lineItems as item
+    join item.product as product,
+    Catalog as catalog
+    join catalog.prices as price
+where order.paid = false
+    and order.customer = :customer
+    and price.product = product
+    and catalog.effectiveDate < sysdate
+    and catalog.effectiveDate >= all (
+        select cat.effectiveDate
+        from Catalog as cat
+        where cat.effectiveDate < sysdate
+    )
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+
+        <para>
+            Quel monstre !
+            En principe, nous ne sommes pas très fan des sous-requêtes, la requête ressemblait donc plutôt
+        à cela :
+        </para>
+
+        <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+    join order.lineItems as item
+    join item.product as product,
+    Catalog as catalog
+    join catalog.prices as price
+where order.paid = false
+    and order.customer = :customer
+    and price.product = product
+    and catalog = :currentCatalog
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+
+        <para>
+            La requête suivante compte le nombre de paiements (payments) pour chaque status, en excluant
+            les paiements dans le status <literal>AWAITING_APPROVAL</literal> où le changement de status
+            le plus récent à été fait par l'utilisateur courant. En SQL, cette requête effectue deux
+            jointures internes et des sous requêtes corrélées sur les tables <literal>PAYMENT</literal>,
+        <literal>PAYMENT_STATUS</literal> et <literal>PAYMENT_STATUS_CHANGE</literal>.
+        </para>
+
+        <programlisting><![CDATA[select count(payment), status.name
+from Payment as payment
+    join payment.currentStatus as status
+    join payment.statusChanges as statusChange
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+    or (
+        statusChange.timeStamp = (
+            select max(change.timeStamp)
+            from PaymentStatusChange change
+            where change.payment = payment
+        )
+        and statusChange.user <> :currentUser
+    )
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+        <para>
+            Si nous avions mappé la collection <literal>statusChanges</literal> comme une liste, au lieu d'un ensemble,
+            la requête aurait été plus facile à écrire.
+        </para>
+
+        <programlisting><![CDATA[select count(payment), status.name
+from Payment as payment
+    join payment.currentStatus as status
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+    or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+        <para>
+            La requête qui suit utilise la fonction de MS SQL <literal>isNull()</literal> pour retourner
+            tous les comptes (accounts) et paiements (payments) impayés pour l'organisation à laquelle
+            l'uilisateur (user) courant appartient. Elle est traduite en SQL par trois jointures internes,
+            une jointure externe ainsi qu'une sous requête sur les tables <literal>ACCOUNT</literal>, <literal>PAYMENT</literal>,
+            <literal>PAYMENT_STATUS</literal>, <literal>ACCOUNT_TYPE</literal>, <literal>ORGANIZATION</literal> et
+            <literal>ORG_USER</literal>.
+        </para>
+
+        <programlisting><![CDATA[select account, payment
+from Account as account
+    left outer join account.payments as payment
+where :currentUser in elements(account.holder.users)
+    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+        <para>
+            Pour d'autres base de données, nous aurions dû faire sans la sous-requête (corrélée).
+        </para>
+
+        <programlisting><![CDATA[select account, payment
+from Account as account
+    join account.holder.users as user
+    left outer join account.payments as payment
+where :currentUser = user
+    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+   </sect1>
+
+    <sect1 id="queryhql-bulk" revision="2">
+        <title>Mise à jour et suppression</title>
+
+        <para>
+            HQL supporte maintenant les expressions <literal>update</literal>, <literal>delete</literal> et
+            <literal>insert ... select ...</literal>.
+            Voir <xref linkend="batch-direct"/> pour les détails.
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-tipstricks">
+        <title>Trucs &amp; Astuces</title>
+
+        <para>
+            Vous pouvez compter le nombre de résultats d'une requête sans les retourner :
+        </para>
+
+        <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue()]]></programlisting>
+
+        <para>
+            Pour trier les résultats par la taille d'une collection, utilisez la requête suivante :
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+    left join usr.messages as msg
+group by usr.id, usr.name
+order by count(msg)]]></programlisting>
+
+        <para>
+            Si votre base de données supporte les sous-requêtes, vous pouvez placer des
+        conditions sur la taille de la sélection dans la clause where de votre requête:
+        </para>
+
+        <programlisting><![CDATA[from User usr where size(usr.messages) >= 1]]></programlisting>
+
+        <para>
+            Si votre base de données ne supporte pas les sous-requêtes, utilisez la requête suivante :
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User usr.name
+    join usr.messages msg
+group by usr.id, usr.name
+having count(msg) >= 1]]></programlisting>
+
+        <para>
+            Cette solution ne peut pas retourner un <literal>User</literal> avec zéro message
+            à cause de la jointure interne, la forme suivante peut donc être utile :
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+    left join usr.messages as msg
+group by usr.id, usr.name
+having count(msg) = 0]]></programlisting>
+
+        <para>
+            Les propriétés d'un JavaBean peuvent être injectées dans les paramètres nommés d'un requête :
+        </para>
+
+        <programlisting><![CDATA[Query q = s.createQuery("from foo Foo as foo where foo.name=:name and foo.size=:size");
+q.setProperties(fooBean); // fooBean has getName() and getSize()
+List foos = q.list();]]></programlisting>
+
+        <para>
+            Les collections sont paginables via l'utilisation de l'interface <literal>Query</literal> avec un filtre :
+        </para>
+
+        <programlisting><![CDATA[Query q = s.createFilter( collection, "" ); // the trivial filter
+q.setMaxResults(PAGE_SIZE);
+q.setFirstResult(PAGE_SIZE * pageNumber);
+List page = q.list();]]></programlisting>
+
+        <para>
+            Les éléments d'une collection peuvent être triés ou groupés en utilisant un filtre de requête :
+        </para>
+
+        <programlisting><![CDATA[Collection orderedCollection = s.filter( collection, "order by this.amount" );
+Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );]]></programlisting>
+
+        <para>
+            Vous pouvez récupérer la taille d'une collection sans l'initialiser :
+        </para>
+
+        <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue();]]></programlisting>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/query_sql.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/query_sql.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/query_sql.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,606 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<chapter id="querysql" revision="2">
+    <title>SQL natif</title>
+
+    <para>
+        Vous pouvez aussi écrire vos requêtes dans le dialecte SQL natif de votre base de données.
+        Ceci est utile si vous souhaitez utiliser les fonctionnalités spécifiques de votre base de
+        données comme le mot clé <literal>CONNECT</literal> d'Oracle. Cette fonctionnalité offre par ailleurs un moyen
+        de migration plus propre et doux d'une application basée sur SQL/JDBC vers
+        une application Hibernate.
+    </para>
+
+  <para>Hibernate3 vous permet de spécifier du SQL écrit à la main (incluant les procédures stockées) 
+  pour toutes les opérations de création, mise à jour, suppression et chargement.</para>
+
+  <sect1 id="querysql-creating" revision="3">
+    <title>Utiliser une <literal>SQLQuery</literal></title>
+
+    <para>L'exécution des requêtes en SQL natif est contrôlée par l'interface <literal>SQLQuery</literal>,
+        laquelle est obtenue en appelant <literal>Session.createSQLQuery()</literal>.
+        Dans des cas extrêmement simples, nous pouvons utiliser la forme suivante :
+    </para>
+
+    <programlisting>List cats = sess.createSQLQuery("select * from cats")
+    .addEntity(Cat.class)
+    .list();</programlisting>
+
+    <para>Cette requête a spécifié :</para>
+
+    <itemizedlist>
+      <listitem>
+        <para>la requête SQL</para>
+      </listitem>
+
+      <listitem>
+        <para>l'entité retournée par la requête</para>
+      </listitem>
+    </itemizedlist>
+
+    <para>
+        Ici, les noms de colonne des résultats sont supposés être les mêmes que les noms de colonne spécifiés dans le
+        document de mapping. Cela peut être problématique pour des requêtes SQL qui joignent de multiple tables, puisque
+        les mêmes noms de colonne peuvent apparaître dans plus d'une table. La forme suivante n'est pas vulnérable à la
+        duplication des noms de colonne :
+    </para>
+
+    <programlisting>List cats = sess.createSQLQuery("select {cat.*} from cats cat")
+    .addEntity("cat", Cat.class)
+    .list();</programlisting>
+
+    <para>Cette requête a spécifié :</para>
+
+    <itemizedlist>
+      <listitem>
+        <para>la requête SQL, avec un paramètre fictif pour Hibernate pour injecter les alias de colonne</para>
+      </listitem>
+
+      <listitem>
+        <para>l'entité retournée par la requête, et son alias de table SQL</para>
+      </listitem>
+    </itemizedlist>
+
+    <para>
+        La méthode <literal>addEntity()</literal> associe l'alias de la table SQL
+        avec la classe de l'entité retournée, et détermine la forme de l'ensemble des résultats de la requête.
+    </para>
+
+    <para>
+        La méthode <literal>addJoin()</literal> peut être utilisée pour charger des associations vers d'autres
+        entités et collections.
+    </para>
+
+    <programlisting>List cats = sess.createSQLQuery(
+        "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
+    )
+    .addEntity("cat", Cat.class)
+    .addJoin("kitten", "cat.kittens")
+    .list();</programlisting>
+
+    <para>
+        Une requête SQL native pourrait retourner une simple valeur scalaire ou une combinaison de scalaires et d'entités.
+    </para>
+
+    <programlisting>Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")
+        .addScalar("maxWeight", Hibernate.DOUBLE);
+        .uniqueResult();</programlisting>
+
+    <para>Vous pouvez alternativement décrire les informations de mapping des résultats dans vos fichiers hbm 
+    et les utiliser pour vos requêtes.</para>
+
+    <programlisting>List cats = sess.createSQLQuery(
+        "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
+    )
+    .setResultSetMapping("catAndKitten")
+    .list();</programlisting>
+  </sect1>
+
+  <sect1 id="querysql-aliasreferences">
+      <title>Alias et références de propriété</title>
+
+    <para>
+        La notation <literal>{cat.*}</literal> utilisée au-dessus est un raccourci pour "toutes les propriétés".
+        Alternativement, vous pouvez lister explicitement les colonnes, mais même ce cas que nous laissons à Hibernate
+        injecte des alias de colonne SQL pour chaque propriété. Le remplaçant pour un alias de colonne 
+        est juste le nom de la propriété qualifié par l'alias de la table.
+        Dans l'exemple suivant, nous récupérons des <literal>Cat</literal>s à partir d'une table différente
+        (<literal>cat_log</literal>) de celle déclarée dans les méta-données de mapping.
+        Notez que nous pouvons même utiliser les alias de propriété dans la clause "where" si nous le souhaitons.
+    </para>
+
+    <para>
+        La syntaxe <literal>{}</literal> <emphasis>n'est pas</emphasis> requise pour le requêtes nommées. Voir
+        <xref linkend="querysql-namedqueries" />.
+    </para>
+
+    <programlisting>String sql = "select cat.originalId as {cat.id}, " +
+    "cat.mateid as {cat.mate}, cat.sex as {cat.sex}, " +
+    "cat.weight*10 as {cat.weight}, cat.name as {cat.name} " +
+    "from cat_log cat where {cat.mate} = :catId"
+
+List loggedCats = sess.createSQLQuery(sql)
+    .addEntity("cat", Cat.class)
+    .setLong("catId", catId)
+    .list();</programlisting>
+
+    <para>
+        <emphasis>À noter :</emphasis> si vous listez chaque propriété explicitement, vous devez inclure 
+        toutes les propriétés de la classe <emphasis>et ses sous-classes</emphasis> !
+    </para>
+
+    <para>
+        La table suivante montre les différentes possibilités d'utilisation de l'injection d'alias. À noter : les noms
+        des alias dans le résultat sont des exemples, chaque alias aura un nom unique et probablement différent lors de l'utilisation.
+    </para>
+
+    <table frame="topbot" id="aliasinjection-summary">
+      <title>Noms d'injection d'alias</title>
+
+      <tgroup cols="4">
+        <colspec colwidth="1*" />
+
+        <colspec colwidth="1*" />
+
+        <colspec colwidth="2.5*" />
+
+        <thead>
+          <row>
+            <entry>Description</entry>
+
+            <entry>Syntaxe</entry>
+
+            <entry>Exemple</entry>
+          </row>
+        </thead>
+
+        <tbody>
+          <row>
+            <entry>Une simple propriété</entry>
+
+            <entry><literal>{[aliasname].[propertyname]}</literal></entry>
+
+            <entry><literal>A_NAME as {item.name}</literal></entry>
+          </row>
+
+          <row>
+            <entry>Une propriété composée</entry>
+
+            <entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
+
+            <entry><literal>CURRENCY as {item.amount.currency}, VALUE as
+            {item.amount.value}</literal></entry>
+          </row>
+
+          <row>
+            <entry>Discriminant d'une entité</entry>
+
+            <entry><literal>{[aliasname].class}</literal></entry>
+
+            <entry><literal>DISC as {item.class}</literal></entry>
+          </row>
+
+          <row>
+            <entry>Toutes les propriétés d'une entité</entry>
+
+            <entry><literal>{[aliasname].*}</literal></entry>
+
+            <entry><literal>{item.*}</literal></entry>
+          </row>
+
+          <row>
+            <entry>Une clef de collection</entry>
+
+            <entry><literal>{[aliasname].key}</literal></entry>
+
+            <entry><literal>ORGID as {coll.key}</literal></entry>
+          </row>
+
+          <row>
+            <entry>L'identifiant d'une collection</entry>
+
+            <entry><literal>{[aliasname].id}</literal></entry>
+
+            <entry><literal>EMPID as {coll.id}</literal></entry>
+          </row>
+
+          <row>
+            <entry>L'élément d'une collection</entry>
+
+            <entry><literal>{[aliasname].element}</literal></entry>
+
+            <entry><literal>XID as {coll.element}</literal></entry>
+
+            <entry></entry>
+          </row>
+
+          <row>
+            <entry>Propriété de l'élément dans la collection</entry>
+
+            <entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
+
+            <entry><literal>NAME as {coll.element.name}</literal></entry>
+          </row>
+
+          <row>
+            <entry>Toutes les propriétés de l'élément dans la collection</entry>
+
+            <entry><literal>{[aliasname].element.*}</literal></entry>
+
+            <entry><literal>{coll.element.*}</literal></entry>
+          </row>
+
+          <row>
+            <entry>Toutes les propriétés de la collection</entry>
+
+            <entry><literal>{[aliasname].*}</literal></entry>
+
+            <entry><literal>{coll.*}</literal></entry>
+          </row>
+        </tbody>
+      </tgroup>
+    </table>
+  </sect1>
+
+  <sect1 id="querysql-namedqueries" revision="3">
+    <title>Requêtes SQL nommées</title>
+
+    <para>
+        Les requêtes SQL nommées peuvent être définies dans le document de mapping
+        et appelées exactement de la même manière qu'un requête HQL nommée. Dans ce
+        cas, nous <emphasis>n'avons pas besoin</emphasis> d'appeler <literal>addEntity()</literal>.
+    </para>
+
+    <programlisting>&lt;sql-query name="persons"&gt;
+    &lt;return alias="person" class="eg.Person"/&gt;
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex}
+    FROM PERSON person
+    WHERE person.NAME LIKE :namePattern
+&lt;/sql-query&gt;</programlisting>
+
+    <programlisting>List people = sess.getNamedQuery("persons")
+    .setString("namePattern", namePattern)
+    .setMaxResults(50)
+    .list();</programlisting>
+
+    <para>
+        Les éléments <literal>&lt;return-join&gt;</literal> et
+        <literal>&lt;load-collection&gt;</literal> sont respectivement utilisés pour lier
+        des associations et définir des requêtes qui initialisent des collections.
+    </para>
+
+    <programlisting>&lt;sql-query name="personsWith"&gt;
+    &lt;return alias="person" class="eg.Person"/&gt;
+    &lt;return-join alias="address" property="person.mailingAddress"/&gt;
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex},
+           adddress.STREET AS {address.street},
+           adddress.CITY AS {address.city},
+           adddress.STATE AS {address.state},
+           adddress.ZIP AS {address.zip}
+    FROM PERSON person
+    JOIN ADDRESS adddress
+        ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+    WHERE person.NAME LIKE :namePattern
+&lt;/sql-query&gt;</programlisting>
+
+    <para>
+        Une requête SQL nommée peut retourner une valeur scalaire. Vous devez
+        spécifier l'alias de colonne et le type Hibernate utilisant l'élément
+        <literal>&lt;return-scalar&gt;</literal> :</para>
+
+    <programlisting>&lt;sql-query name="mySqlQuery"&gt;
+    &lt;return-scalar column="name" type="string"/&gt;
+    &lt;return-scalar column="age" type="long"/&gt;
+    SELECT p.NAME AS name,
+           p.AGE AS age,
+    FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
+&lt;/sql-query&gt;</programlisting>
+
+    <para>
+        Vous pouvez externaliser les informations de mapping des résultats dans un
+        élément <literal>&lt;resultset&gt;</literal> pour soit les réutiliser
+        dans différentes requêtes nommées, soit à travers l'API
+        <literal>setResultSetMapping()</literal>.
+    </para>
+
+    <programlisting>&lt;resultset name="personAddress"&gt;
+    &lt;return alias="person" class="eg.Person"/&gt;
+    &lt;return-join alias="address" property="person.mailingAddress"/&gt;
+&lt;/resultset&gt;
+
+&lt;sql-query name="personsWith" resultset-ref="personAddress"&gt;
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex},
+           adddress.STREET AS {address.street},
+           adddress.CITY AS {address.city},
+           adddress.STATE AS {address.state},
+           adddress.ZIP AS {address.zip}
+    FROM PERSON person
+    JOIN ADDRESS adddress
+        ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+    WHERE person.NAME LIKE :namePattern
+&lt;/sql-query&gt;</programlisting>
+
+    <sect2 id="propertyresults">
+      <title>Utilisation de return-property pour spécifier explicitement les noms des colonnes/alias</title>
+
+      <para>
+          Avec <literal>&lt;return-property&gt;</literal> vous pouvez explicitement dire
+          à Hibernate quels alias de colonne utiliser, plutot que d'employer la syntaxe
+          <literal>{}</literal> pour laisser Hibernate injecter ses propres alias.
+      </para>
+
+      <programlisting>&lt;sql-query name="mySqlQuery"&gt;
+    &lt;return alias="person" class="eg.Person"&gt;
+        &lt;return-property name="name" column="myName"/&gt;
+        &lt;return-property name="age" column="myAge"/&gt;
+        &lt;return-property name="sex" column="mySex"/&gt;
+    &lt;/return&gt;
+    SELECT person.NAME AS myName,
+           person.AGE AS myAge,
+           person.SEX AS mySex,
+    FROM PERSON person WHERE person.NAME LIKE :name
+&lt;/sql-query&gt;
+</programlisting>
+
+      <para>
+          <literal>&lt;return-property&gt;</literal> fonctionne aussi avec de
+          multiple colonnes. Cela résout une limitation de la syntaxe <literal>{}</literal>
+          qui ne peut pas permettre une bonne granularité des propriétés multi-colonnes.
+      </para>
+
+      <programlisting>&lt;sql-query name="organizationCurrentEmployments"&gt;
+    &lt;return alias="emp" class="Employment"&gt;
+        &lt;return-property name="salary"&gt;
+            &lt;return-column name="VALUE"/&gt;
+            &lt;return-column name="CURRENCY"/&gt;
+        &lt;/return-property&gt;
+        &lt;return-property name="endDate" column="myEndDate"/&gt;
+    &lt;/return&gt;
+        SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
+        STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+        REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
+        FROM EMPLOYMENT
+        WHERE EMPLOYER = :id AND ENDDATE IS NULL
+        ORDER BY STARTDATE ASC
+&lt;/sql-query&gt;</programlisting>
+
+      <para>
+          Notez que dans cet exemple nous avons utilisé <literal>&lt;return-property&gt;</literal>
+          en combinaison avec la syntaxe <literal>{}</literal> pour l'injection. Cela autorise les
+          utilisateurs à choisir comment ils veulent référencer les colonnes et les propriétés.
+      </para>
+
+      <para>
+          Si votre mapping a un discriminant vous devez utiliser
+          <literal>&lt;return-discriminator&gt;</literal> pour spécifier la colonne
+          discriminante.
+      </para>
+    </sect2>
+
+    <sect2 id="sp_query" revision="1">
+      <title>Utilisation de procédures stockées pour les requêtes</title>
+
+      <para>
+          Hibernate 3 introduit le support des requêtes via procédures stockées et les fonctions. 
+          La documentation suivante est valable pour les deux.
+          Les procédures stockées/fonctions doivent retourner l'ensemble de résultats en tant que
+          premier paramètre sortant (NdT: "out-parameter") pour être capable de fonctionner
+          avec Hibernate. Un exemple d'une telle procédure stockée en Oracle 9 et
+          version supérieure :
+      </para>
+
+      <programlisting>CREATE OR REPLACE FUNCTION selectAllEmployments
+    RETURN SYS_REFCURSOR
+AS
+    st_cursor SYS_REFCURSOR;
+BEGIN
+    OPEN st_cursor FOR
+ SELECT EMPLOYEE, EMPLOYER,
+ STARTDATE, ENDDATE,
+ REGIONCODE, EID, VALUE, CURRENCY
+ FROM EMPLOYMENT;
+      RETURN  st_cursor;
+ END;</programlisting>
+
+      <para>Pour utiliser cette requête dans Hibernate vous avez besoin de la mapper via une requête nommée.</para>
+
+      <programlisting>&lt;sql-query name="selectAllEmployees_SP" callable="true"&gt;
+    &lt;return alias="emp" class="Employment"&gt;
+        &lt;return-property name="employee" column="EMPLOYEE"/&gt;
+        &lt;return-property name="employer" column="EMPLOYER"/&gt;
+        &lt;return-property name="startDate" column="STARTDATE"/&gt;
+        &lt;return-property name="endDate" column="ENDDATE"/&gt;
+        &lt;return-property name="regionCode" column="REGIONCODE"/&gt;
+        &lt;return-property name="id" column="EID"/&gt;
+        &lt;return-property name="salary"&gt;
+            &lt;return-column name="VALUE"/&gt;
+            &lt;return-column name="CURRENCY"/&gt;
+        &lt;/return-property&gt;
+    &lt;/return&gt;
+    { ? = call selectAllEmployments() }
+&lt;/sql-query&gt;</programlisting>
+
+      <para>
+          Notez que les procédures stockées retournent, pour le moment, seulement des
+          scalaires et des entités. <literal>&lt;return-join&gt;</literal> et
+          <literal>&lt;load-collection&gt;</literal> ne sont pas supportés.
+      </para>
+
+      <sect3 id="querysql-limits-storedprocedures" revision="1">
+        <title>Règles/limitations lors de l'utilisation des procédures stockées</title>
+
+        <para>
+            Pur utiliser des procédures stockées avec Hibernate, les procédures doivent
+            suivre certaines règles. Si elles ne suivent pas ces règles, elles ne sont pas
+            utilisables avec Hibernate. Si vous voulez encore utiliser ces procédures vous
+            devez les exécuter via <literal>session.connection()</literal>. Les règles
+            sont différentes pour chaque base de données, puisque les vendeurs de base
+            de données ont des sémantiques/syntaxes différentes pour les procédures stockées.
+        </para>
+
+        <para>Les requêtes de procédures stockées ne peuvent pas être paginées avec
+            <literal>setFirstResult()/setMaxResults()</literal>.</para>
+
+        <para>Pour Oracle les règles suivantes s'appliquent :</para>
+
+        <itemizedlist spacing="compact">
+          <listitem>
+            <para>
+                La procédure doit retourner un ensemble de résultats. Le
+                prmeier paramètre d'une procédure doit être un <literal>OUT</literal> 
+                qui retourne un ensemble de résultats. Ceci est fait en
+                retournant un <literal>SYS_REFCURSOR</literal> dans Oracle 9 ou 10. Dans
+                Oracle vous avez besoin de définir un type <literal>REF CURSOR</literal>.</para>
+          </listitem>
+
+        </itemizedlist>
+
+        <para>Pour Sybase ou MS SQL server les règles suivantes s'appliquent :</para>
+
+        <itemizedlist spacing="compact">
+          <listitem>
+            <para>La procédure doit retourner un ensemble de résultats. Notez que comme
+            ces serveurs peuvent retourner de multiples ensembles de résultats et mettre à jour
+            des compteurs, Hibernate itérera les résultats et prendra le premier résultat qui est
+            un ensemble de résultat comme valeur de retour. Tout le reste sera ignoré.</para>
+          </listitem>
+
+          <listitem>
+            <para>Si vous pouvez activer <literal>SET NOCOUNT ON</literal> dans votre procédure,
+                elle sera probablement plus efficace, mais ce n'est pas une obligation.</para>
+          </listitem>
+        </itemizedlist>
+      </sect3>
+    </sect2>
+  </sect1>
+
+  <sect1 id="querysql-cud">
+    <title>SQL personnalisé pour créer, mettre à jour et effacer</title>
+
+    <para>
+        Hibernate3 peut utiliser des expression SQL personnalisées pour des opérations de création,
+        de mise à jour, et de suppression. Les objets persistants les classes et les collections
+        dans Hibernate contiennent déjà un ensemble de chaînes de caractères générées lors de la
+        configuration (insertsql, deletesql, updatesql, etc). Les tages de mapping
+    <literal>&lt;sql-insert&gt;</literal>,
+    <literal>&lt;sql-delete&gt;</literal>, et
+    <literal>&lt;sql-update&gt;</literal> surchargent ces chaînes de caractères :</para>
+
+    <programlisting>&lt;class name="Person"&gt;
+    &lt;id name="id"&gt;
+        &lt;generator class="increment"/&gt;
+    &lt;/id&gt;
+    &lt;property name="name" not-null="true"/&gt;
+    &lt;sql-insert&gt;INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )&lt;/sql-insert&gt;
+    &lt;sql-update&gt;UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?&lt;/sql-update&gt;
+    &lt;sql-delete&gt;DELETE FROM PERSON WHERE ID=?&lt;/sql-delete&gt;
+&lt;/class&gt;</programlisting>
+
+    <para>Le SQL est directement exécuté dans votre base de données, donc vous êtes libre d'utiliser
+        le dialecte que vous souhaitez. Cela réduira bien sûr la portabilité de votre mapping si vous
+        utilisez du SQL spécifique à votre base de données.</para>
+
+    <para>Les procédures stockées sont supportées si l'attribut <literal>callable</literal> est paramétré :</para>
+
+    <programlisting>&lt;class name="Person"&gt;
+    &lt;id name="id"&gt;
+        &lt;generator class="increment"/&gt;
+    &lt;/id&gt;
+    &lt;property name="name" not-null="true"/&gt;
+    &lt;sql-insert callable="true"&gt;{call createPerson (?, ?)}&lt;/sql-insert&gt;
+    &lt;sql-delete callable="true"&gt;{? = call deletePerson (?)}&lt;/sql-delete&gt;
+    &lt;sql-update callable="true"&gt;{? = call updatePerson (?, ?)}&lt;/sql-update&gt;
+&lt;/class&gt;</programlisting>
+
+    <para>L'ordre des paramètres positionnels est actuellement vital, car ils doivent être dans la
+        même séquence qu'Hibernate les attend.</para>
+
+    <para>
+        Vous pouvez voir l'ordre attendu en activant les journaux de debug pour le
+        niveau <literal>org.hibernate.persister.entity</literal> level. Avec ce niveau activé,
+        Hibernate imprimera le SQL statique qui est utilisé pour créer, mettre à jour,
+        supprimer, etc. des entités. (Pour voir la séquence attendue, rappelez-vous de ne pas
+        inclure votre SQL personnalisé dans les fichiers de mapping de manière à surcharger le
+        SQL statique généré par Hibernate.)</para>
+
+    <para>Les procédures stockées sont dans la plupart des cas (lire : il vaut mieux le faire)
+    requises pour retourner le nombre de lignes insérées/mises à jour/supprimées, puisque
+    Hibernate fait quelques vérifications de succès lors de l'exécution de l'expression.
+    Hibernate inscrit toujours la première expression comme un paramètre de sortie numérique pour les
+    opérations CUD :</para>
+
+    <programlisting>CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
+    RETURN NUMBER IS
+BEGIN
+
+    update PERSON
+    set
+        NAME = uname,
+    where
+        ID = uid;
+
+    return SQL%ROWCOUNT;
+
+END updatePerson;</programlisting>
+  </sect1>
+
+  <sect1 id="querysql-load">
+    <title>SQL personnalisé pour le chargement</title>
+
+    <para>Vous pouvez aussi déclarer vos propres requêtes SQL (ou HQL) pour le chargement d'entité :</para>
+
+    <programlisting>&lt;sql-query name="person"&gt;
+    &lt;return alias="pers" class="Person" lock-mode="upgrade"/&gt;
+    SELECT NAME AS {pers.name}, ID AS {pers.id}
+    FROM PERSON
+    WHERE ID=?
+    FOR UPDATE
+&lt;/sql-query&gt;</programlisting>
+
+    <para>Ceci est juste une déclaration de requête nommée, comme vu plus tôt. Vous pouvez référencer
+    cette requête nommée dans un mapping de classe :</para>
+
+    <programlisting>&lt;class name="Person"&gt;
+    &lt;id name="id"&gt;
+        &lt;generator class="increment"/&gt;
+    &lt;/id&gt;
+    &lt;property name="name" not-null="true"/&gt;
+    &lt;loader query-ref="person"/&gt;
+&lt;/class&gt;</programlisting>
+
+    <para>Ceci fonctionne même avec des procédures stockées.</para>
+
+    <para>Vous pouvez même définir une requête pour le chargement d'une collection :</para>
+
+    <programlisting>&lt;set name="employments" inverse="true"&gt;
+    &lt;key/&gt;
+    &lt;one-to-many class="Employment"/&gt;
+    &lt;loader query-ref="employments"/&gt;
+&lt;/set&gt;</programlisting>
+
+    <programlisting>&lt;sql-query name="employments"&gt;
+    &lt;load-collection alias="emp" role="Person.employments"/&gt;
+    SELECT {emp.*}
+    FROM EMPLOYMENT emp
+    WHERE EMPLOYER = :id
+    ORDER BY STARTDATE ASC, EMPLOYEE ASC
+&lt;/sql-query&gt;</programlisting>
+
+    <para>Vous pourriez même définir un chargeur d'entité qui charge une collection par jointure :</para>
+
+    <programlisting>&lt;sql-query name="person"&gt;
+    &lt;return alias="pers" class="Person"/&gt;
+    &lt;return-join alias="emp" property="pers.employments"/&gt;
+    SELECT NAME AS {pers.*}, {emp.*}
+    FROM PERSON pers
+    LEFT OUTER JOIN EMPLOYMENT emp
+        ON pers.ID = emp.PERSON_ID
+    WHERE ID=?
+&lt;/sql-query&gt;</programlisting>
+  </sect1>
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/session_api.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/session_api.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/session_api.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1229 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<chapter id="objectstate">
+    <title>Travailler avec des objets</title>
+    <para>
+        Hibernate est une solution de mapping objet/relationnel complète qui ne masque pas
+        seulement au développpeur les détails du système de gestion de base de données sous-jacent,
+        mais offre aussi <emphasis>la gestion d'état</emphasis> des objets. C'est, contrairement
+        à la gestion de <literal>statements</literal> SQL dans les couches de persistance
+        habituelles JDBC/SQL, une vue orientée objet très naturelle de la persistance dans les
+        applications Java.
+    </para>
+
+	<para>
+        En d'autres mots, les développeurs d'applications Hibernate devrait toujours
+        réfléchir à <emphasis>l'état</emphasis> de leurs objets, et pas nécessairement à
+        l'exécution des expressions SQL. Cette part est prise en charge pas Hibernate et
+        seulement importante pour les développeurs d'applications lors du réglage de la
+        performance de leur système.
+    </para>
+
+    <sect1 id="objectstate-overview">
+        <title>États des objets Hibernate</title>
+
+        <para>
+            Hibernate définit et comprend les états suivants :
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>Éphémère</emphasis> (NdT : transient) - un objet est éphémère s'il a juste
+                    été instancié en utilisant l'opérateur <literal>new</literal>. Il n'a aucune
+                    représentation persistante dans la base de données et aucune valeur d'identifiant
+                    n'a été assignée. Les instances éphémères seront détruites par le ramasse-miettes
+                    si l'application n'en conserve aucune référence. Utilisez la <literal>Session</literal>
+                    d'Hibernate pour rendre un objet persistant (et laisser Hibernate s'occuper des
+                    expressions SQL qui ont besoin d'être exécutées pour cette transistion).
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Persistant</emphasis> - une instance persistante a une représentation dans la
+                    base de données et une valeur d'identifiant. Elle pourrait avoir juste été sauvegardée
+                    ou chargée, pourtant, elle est par définition dans la portée d'une <literal>Session</literal>.
+                    Hibernate détectera n'importe quels changements effectués sur un objet dans l'état
+                    persistant et synchronisera l'état avec la base de données lors de la fin l'unité de travail.
+                    Les développeurs n'exécutent pas d'expressions <literal>UPDATE</literal> ou
+                    <literal>DELETE</literal> manuelles lorsqu'un objet devrait être rendu éphémère.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Détaché</emphasis> - une instance détachée est un objet qui a été persistant,
+                    mais dont sa <literal>Session</literal> a été fermée. La référence à l'objet est
+                    encore valide, bien sûr, et l'instance détachée pourrait même être modifiée dans cet
+                    état. Une instance détachée peut être réattachée à une nouvelle <literal>Session</literal>
+                    plus tard dans le temps, la rendant (et toutes les modifications avec) de nouveau persistante.
+                    Cette fonctionnalité rend possible un modèle de programmation pour de longues unités de travail
+                    qui requièrent un temps de réflexion de l'utilisateur. Nous les appelons des <emphasis>conversations</emphasis>,
+                    c'est-à-dire une unité de travail du point de vue de l'utilisateur.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Nous alons maintenant dicuster des états et des transitions d'état (et des méthodes
+            d'Hibernate qui déclenchent une transition) plus en détails.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-makingpersistent" revision="1">
+        <title>Rendre des objets persistants</title>
+
+        <para>
+            Les instances nouvellement instanciées d'une classe persistante sont considérées
+            <emphasis>éphémères</emphasis> par Hibernate. Nous pouvons rendre une instance
+            éphémère <emphasis>persistante</emphasis> en l'associant avec une session :
+        </para>
+
+        <programlisting><![CDATA[DomesticCat fritz = new DomesticCat();
+fritz.setColor(Color.GINGER);
+fritz.setSex('M');
+fritz.setName("Fritz");
+Long generatedId = (Long) sess.save(fritz);]]></programlisting>
+
+        <para>
+            Si <literal>Cat</literal> a un identifiant généré, l'identifiant est généré et assigné
+            au <literal>cat</literal> lorsque <literal>save()</literal> est appelée. Si <literal>Cat</literal>
+            a un identifiant <literal>assigned</literal>, ou une clef composée, l'identifiant
+            devrait être assigné à l'instance de <literal>cat</literal> avant d'appeler <literal>save()</literal>.
+            Vous pouvez aussi utiliser <literal>persist()</literal> à la place de<literal>save()</literal>,
+            avec la sémantique définie plus tôt dans le brouillon d'EJB3.
+        </para>
+
+        <para>
+            Alternativement, vous pouvez assigner l'identifiant en utilisant une version
+            surchargée de <literal>save()</literal>.
+        </para>
+
+<programlisting><![CDATA[DomesticCat pk = new DomesticCat();
+pk.setColor(Color.TABBY);
+pk.setSex('F');
+pk.setName("PK");
+pk.setKittens( new HashSet() );
+pk.addKitten(fritz);
+sess.save( pk, new Long(1234) );]]></programlisting>
+
+        <para>
+            Si l'objet que vous rendez persistant a des objets associés (par exemple,
+            la collection <literal>kittens</literal> dans l'exemple précédent), ces objets
+            peuvent être rendus persistants dans n'importe quel ordre que vous souhaitez
+            à moins que vous ayez une contrainte <literal>NOT NULL</literal> sur la
+            colonne de la clef étrangère. Il n'y a jamais de risque de violer une
+            contrainte de clef étrangère. Cependant, vous pourriez violer une contrainte
+            <literal>NOT NULL</literal> si vous appeliez <literal>save()</literal> sur
+            les objets dans le mauvais ordre.
+        </para>
+
+        <para>
+            Habituellement, vous ne vous préoccupez pas de ce détail, puisque vous
+            utiliserez très probablement la fonctionnalité de <emphasis>persistance
+            transitive</emphasis> d'Hibernate pour sauvegarder les objets associés
+            automatiquement. Alors, même les violations de contrainte <literal>NOT NULL</literal>
+            n'ont plus lieu - Hibernate prendra soin de tout. La persistance transitive est
+            traitée plus loin dans ce chapitre.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-loading">
+        <title>Chargement d'un objet</title>
+
+        <para>
+            Les méthodes <literal>load()</literal> de <literal>Session</literal> vous donnent
+            un moyen de récupérer une instance persistante si vous connaissez déjà son identifiant.
+            <literal>load()</literal> prend un objet de classe et chargera l'état dans une instance
+            nouvellement instanciée de cette classe, dans un état persistant.
+        </para>
+
+        <programlisting><![CDATA[Cat fritz = (Cat) sess.load(Cat.class, generatedId);]]></programlisting>
+
+<programlisting><![CDATA[// vous avez besoin d'envelopper les identiants primitifs
+long pkId = 1234;
+DomesticCat pk = (DomesticCat) sess.load( Cat.class, new Long(pkId) );]]></programlisting>
+
+        <para>
+            Alternativement, vous pouvez charger un état dans une instance donnée :
+        </para>
+
+<programlisting><![CDATA[Cat cat = new DomesticCat();
+// load pk's state into cat
+sess.load( cat, new Long(pkId) );
+Set kittens = cat.getKittens();]]></programlisting>
+
+        <para>
+            Notez que <literal>load()</literal> lèvera une exception irrécupérable s'il
+            n'y a pas de ligne correspondante dans la base de données. Si la classe est mappée
+            avec un proxy, <literal>load()</literal> retourne juste un proxy non initialisé et
+            n'accède en fait pas à la base de données jusqu'à ce que vous invoquiez une
+            méthode du proxy. Ce comportement est très utile si vous souhaitez créer
+            une association vers un objet sans réellement le charger à partir de la base de
+            données. Cela permet aussi à de multiples instances d'être chargées comme un lot
+            si <literal>batch-size</literal> est défini pour le mapping de la classe.
+        </para>
+
+        <para>
+            Si vous n'êtes pas certain qu'une ligne correspondante existe, vous devriez
+            utiliser la méthode <literal>get()</literal>, laquelle accède à la base de
+            données immédiatement et retourne null s'il n'y a pas de ligne correspondante.
+        </para>
+
+        <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id);
+if (cat==null) {
+    cat = new Cat();
+    sess.save(cat, id);
+}
+return cat;]]></programlisting>
+
+        <para>
+            Vous pouvez même charger un objet en employant un <literal>SELECT ... FOR UPDATE</literal> SQL,
+            en utilisant un <literal>LockMode</literal>. Voir la documentation de l'API pour plus d'informations.
+        </para>
+
+        <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);]]></programlisting>
+
+        <para>
+            Notez que n'importe quelles instances associées ou collections contenues
+            <emphasis>ne sont pas</emphasis> sélectionnées par <literal>FOR UPDATE</literal>,
+            à moins que vous ne décidiez de spécifier <literal>lock</literal> ou <literal>all</literal>
+            en tant que style de cascade pour l'association.
+        </para>
+
+        <para>
+            Il est possible de re-charger un objet et toutes ses collections à n'importe quel moment,
+            en utilisant la méthode <literal>refresh()</literal>. C'est utile lorsque des "triggers" de
+            base de données sont utilisés pour initiliser certains propriétés de l'objet.
+        </para>
+
+        <programlisting><![CDATA[sess.save(cat);
+sess.flush(); //force the SQL INSERT
+sess.refresh(cat); //re-read the state (after the trigger executes)]]></programlisting>
+
+        <para>
+            Une question importante apparaît généralement à ce point : combien (NdT : de données) Hibernate
+            charge-t-il de la base de données et combient de <literal>SELECT</literal>s utilisera-t-il ?
+            Cela dépent de la <emphasis>stratégie de récupération</emphasis> et cela est expliqué dans
+            <xref linkend="performance-fetching"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-querying" revision="1">
+        <title>Requêtage</title>
+
+        <para>
+            Si vous ne connaissez par les identifiants des objets que vous recherchez, vous
+            avez besoin d'une requête. Hibernate supporte un langage de requêtes orientées objet
+            facile à utiliser mais puissant. Pour la création de requêtes par programmation,
+            Hibernate supporte une fonction de requêtage sophistiqué Criteria et Example (QBC et QBE).
+            Vous pouvez aussi exprimez votre requête dans le SQL natif de votre base de données,
+            avec un support optionnel d'Hibernate pour la conversion des ensembles de résultats en
+            objets.
+        </para>
+
+        <sect2 id="objectstate-querying-executing">
+            <title>Exécution de requêtes</title>
+
+            <para>
+                Les requêtes HQL et SQL natives sont représentées avec une instance de <literal>org.hibernate.Query</literal>.
+                L'interface offre des méthodes pour la liaison des paramètres, la gestion des ensembles de resultats, et pour
+                l'exécution de la requête réelle. Vous obtenez toujours une <literal>Query</literal> en utilisant la
+                <literal>Session</literal> courante :
+            </para>
+
+        <programlisting><![CDATA[List cats = session.createQuery(
+    "from Cat as cat where cat.birthdate < ?")
+    .setDate(0, date)
+    .list();
+
+List mothers = session.createQuery(
+    "select mother from Cat as cat join cat.mother as mother where cat.name = ?")
+    .setString(0, name)
+    .list();
+
+List kittens = session.createQuery(
+    "from Cat as cat where cat.mother = ?")
+    .setEntity(0, pk)
+    .list();
+
+Cat mother = (Cat) session.createQuery(
+    "select cat.mother from Cat as cat where cat = ?")
+    .setEntity(0, izi)
+    .uniqueResult();]]></programlisting>
+
+            <para>
+                Une requête est généralement exécutée en invoquant <literal>list()</literal>,
+                le résultat de la requête sera chargée complètement dans une collection en mémoire.
+                Les intances d'entités recupérées par une requête sont dans un état persistant.
+                La méthode <literal>uniqueResult()</literal> offre un raccourci si vous
+                savez que votre requête retournera seulement un seul objet.
+            </para>
+
+            <sect3 id="objectstate-querying-executing-iterate">
+                <title>Itération de résultats</title>
+
+                <para>
+                    Occasionnellement, vous pourriez être capable d'obtenir de meilleures
+                    performances en exécutant la requête avec la méthode <literal>iterate()</literal>.
+                    Ce sera généralement seulement le cas si vous espérez que les intances réelles
+                    d'entité retournées par la requête soient déjà chargées dans la session ou le
+                    cache de second niveau. Si elles ne sont pas cachées, <literal>iterate()</literal>
+                    sera plus lent que <literal>list()</literal> et pourrait nécessiter plusieurs
+                    accès à la base de données pour une simple requête, généralement <emphasis>1</emphasis>
+                    pour le select initial qui retourne seulement les identifiants, et <emphasis>n</emphasis>
+                    selects supplémentaires pour initialiser les instances réelles.
+                </para>
+
+                <programlisting><![CDATA[// fetch ids
+Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate();
+while ( iter.hasNext() ) {
+    Qux qux = (Qux) iter.next();  // fetch the object
+    // something we couldnt express in the query
+    if ( qux.calculateComplicatedAlgorithm() ) {
+        // delete the current instance
+        iter.remove();
+        // dont need to process the rest
+        break;
+    }
+}]]></programlisting>
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-tuples">
+                <title>Requêtes qui retournent des tuples</title>
+
+                <para>
+                    Les requêtes d'Hibernate retournent parfois des tuples d'objets, auquel cas chaque tuple
+                    est retourné comme un tableau :
+                </para>
+
+                <programlisting><![CDATA[Iterator kittensAndMothers = sess.createQuery(
+            "select kitten, mother from Cat kitten join kitten.mother mother")
+            .list()
+            .iterator();
+
+while ( kittensAndMothers.hasNext() ) {
+    Object[] tuple = (Object[]) kittensAndMothers.next();
+    Cat kitten  = tuple[0];
+    Cat mother  = tuple[1];
+    ....
+}]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-scalar"  revision="1">
+                <title>Résultats scalaires</title>
+
+                <para>
+                    Des requêtes peuvent spécifier une propriété d'une classe dans la clause <literal>select</literal>.
+                    Elles peuvent même appeler des fonctions d'aggrégat SQL. Les propriétés ou les aggrégats sont
+                    considérés comme des résultats "scalaires" (et pas des entités dans un état persistant).
+                </para>
+
+                <programlisting><![CDATA[Iterator results = sess.createQuery(
+        "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
+        "group by cat.color")
+        .list()
+        .iterator();
+
+while ( results.hasNext() ) {
+    Object[] row = (Object[]) results.next();
+    Color type = (Color) row[0];
+    Date oldest = (Date) row[1];
+    Integer count = (Integer) row[2];
+    .....
+}]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-parameters">
+                <title>Lier des paramètres</title>
+
+                <para>
+                    Des méthodes de <literal>Query</literal> sont fournies pour lier des
+                    valeurs à des paramètres nommés ou à des paramètres de style JDBC <literal>?</literal>.
+                    <emphasis>Contrairement à JDBC, les numéros des paramètres d'Hibernate commencent à zéro.</emphasis>
+                    Les paramètres nommés sont des identifiants de la forme <literal>:nom</literal> dans la chaîne de
+                    caractères de la requête. Les avantages des paramètres nommés sont :
+                </para>
+
+                <itemizedlist spacing="compact">
+                    <listitem>
+                        <para>
+                            les paramètres nommés sont insensibles à l'ordre de leur place dans la chaîne
+                            de la requête
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            ils peuvent apparaître plusieurs fois dans la même requête
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            ils sont auto-documentés
+                        </para>
+                    </listitem>
+                </itemizedlist>
+
+                <programlisting><![CDATA[//paramètre nomme (préféré)
+Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
+q.setString("name", "Fritz");
+Iterator cats = q.iterate();]]></programlisting>
+
+                <programlisting><![CDATA[//paramètre positionnel
+Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
+q.setString(0, "Izi");
+Iterator cats = q.iterate();]]></programlisting>
+
+                <programlisting><![CDATA[//liste de paramètres nommés
+List names = new ArrayList();
+names.add("Izi");
+names.add("Fritz");
+Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)");
+q.setParameterList("namesList", names);
+List cats = q.list();]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-pagination">
+                <title>Pagination</title>
+
+                <para>
+                    Si vous avez besoin de spécifier des liens sur votre ensemble de résultats (le nombre
+                    maximum de lignes que vous voulez récupérez et/ou la première ligne que vous voulez récupérer)
+                    vous devriez utiliser des méthodes de l'interface <literal>Query</literal> :
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.createQuery("from DomesticCat cat");
+q.setFirstResult(20);
+q.setMaxResults(10);
+List cats = q.list();]]></programlisting>
+
+                <para>
+                    Hibernate sait comment traduite cette requête de limite en SQL natif pour votre SGBD.
+                </para>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-scrolling">
+                <title>Itération "scrollable"</title>
+
+                <para>
+                    Si votre connecteur JDBC supporte les <literal>ResultSet</literal>s "scrollables",
+                    l'interface <literal>Query</literal> peut être utilisée pour obtenir un objet
+                    <literal>ScrollableResults</literal>, lequel permet une navigation flexible dans les
+                    résultats de la requête.
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
+                            "order by cat.name");
+ScrollableResults cats = q.scroll();
+if ( cats.first() ) {
+
+    // trouve le premier nom sur chaque page d'une liste alphabétique de noms de chats
+    firstNamesOfPages = new ArrayList();
+    do {
+        String name = cats.getString(0);
+        firstNamesOfPages.add(name);
+    }
+    while ( cats.scroll(PAGE_SIZE) );
+
+    // Maintenant, obtiens la première page de chats
+    pageOfCats = new ArrayList();
+    cats.beforeFirst();
+    int i=0;
+    while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) );
+
+}
+cats.close()]]></programlisting>
+
+                <para>
+                    Notez qu'une connexion ouverte (et un curseur) est requise pour cette fonctionnalité,
+                    utilisez <literal>setMaxResult()</literal>/<literal>setFirstResult()</literal> si vous
+                    avez besoin d'une fonctionnalité de pagination hors ligne.
+                </para>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-named">
+                <title>Externaliser des requêtes nommées</title>
+
+                <para>
+                    Vous pouvez aussi définir des requêtes nommées dans le document de mapping.
+                    (Souvenez-vous d'utiliser une section <literal>CDATA</literal> si votre requête
+                    contient des caractères qui pourraient être interprétés comme des éléments XML.)
+                </para>
+
+                <programlisting><![CDATA[<query name="eg.DomesticCat.by.name.and.minimum.weight"><![CDATA[
+    from eg.DomesticCat as cat
+        where cat.name = ?
+        and cat.weight > ?
+] ]></query>]]></programlisting>
+
+                <para>
+                    La liaison de paramètres et l'exécution sont fait par programmation :
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.getNamedQuery("eg.DomesticCat.by.name.and.minimum.weight");
+q.setString(0, name);
+q.setInt(1, minWeight);
+List cats = q.list();]]></programlisting>
+
+                <para>
+                    Notez que le code réel du programme est indépendant du langage de requête qui est
+                    utilisé, vous pouvez aussi définir des requêtes SQL nativez dans les méta-données, ou
+                    migrer des requêtes existantes vers Hibernate en les plaçant dans les fichiers de mapping.
+                </para>
+
+            </sect3>
+
+        </sect2>
+
+        <sect2 id="objectstate-filtering" revision="1">
+            <title>Filtrer des collections</title>
+            <para>
+                Un <emphasis>filtre</emphasis> de collection est un type spécial de requête qui peut être
+                appliqué à une collection persistante ou à un tableau. La chaîne de requête peut se référer à
+                <literal>this</literal>, correspondant à l'élément de la collection courant.
+            </para>
+
+            <programlisting><![CDATA[Collection blackKittens = session.createFilter(
+    pk.getKittens(),
+    "where this.color = ?")
+    .setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) )
+    .list()
+);]]></programlisting>
+
+            <para>
+                La collection retournée est considérée comme un bag, et c'est une copie de la
+                collection donnée. La collection originale n'est pas modifiée (c'est contraire
+                à l'implication du nom "filtre"; mais cohérent avec le comportement attendu).
+            </para>
+
+            <para>
+                Observez que les filtres ne nécessitent pas une clause <literal>from</literal> (bien qu'ils
+                puissent en avoir une si besoin est). Les filtres ne sont pas limités à retourner des
+                éléments de la collection eux-mêmes.
+            </para>
+
+            <programlisting><![CDATA[Collection blackKittenMates = session.createFilter(
+    pk.getKittens(),
+    "select this.mate where this.color = eg.Color.BLACK.intValue")
+    .list();]]></programlisting>
+
+            <para>
+                Même une requête de filtre vide est utile, par exemple pour charger un sous-ensemble
+                d'éléments dans une énorme collection :
+            </para>
+
+            <programlisting><![CDATA[Collection tenKittens = session.createFilter(
+    mother.getKittens(), "")
+    .setFirstResult(0).setMaxResults(10)
+    .list();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="objecstate-querying-criteria" revision="1">
+           <title>Requêtes Criteria</title>
+
+            <para>
+                HQL est extrêmement puissant mais certains développeurs préfèrent construire des
+                requêtes dynamiquement, en utilisant l'API orientée objet, plutôt que construire
+                des chaînes de requêtes. Hibernate fournit une API intuitive de requête <literal>Criteria</literal>
+                pour ces cas :
+            </para>
+
+            <programlisting><![CDATA[Criteria crit = session.createCriteria(Cat.class);
+crit.add( Expression.eq( "color", eg.Color.BLACK ) );
+crit.setMaxResults(10);
+List cats = crit.list();]]></programlisting>
+
+            <para>
+                Les APIs <literal>Criteria</literal> et <literal>Example</literal> associé sont
+                traitées plus en détail dans <xref linkend="querycriteria"/>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="objectstate-querying-nativesql" revision="2">
+            <title>Requêtes en SQL natif</title>
+
+            <para>
+                Vous pouvez exprimer une requête en SQL, en utilisant <literal>createSQLQuery()</literal>
+                et laisser Hibernate s'occuper du mapping des résultats vers des objets. Notez que vous
+                pouvez n'importe quand appeler <literal>session.connection()</literal> et utiliser
+                directement la <literal>Connection</literal> JDBC. Si vous choisissez d'utiliser
+                l'API Hibernate, vous devez mettre les alias SQL entre accolades :
+            </para>
+
+            <programlisting><![CDATA[List cats = session.createSQLQuery(
+    "SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10",
+    "cat",
+    Cat.class
+).list();]]></programlisting>
+
+            <programlisting><![CDATA[List cats = session.createSQLQuery(
+    "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
+           "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
+    "FROM CAT {cat} WHERE ROWNUM<10",
+    "cat",
+    Cat.class
+).list()]]></programlisting>
+
+            <para>
+                Les requêtes SQL peuvent contenir des paramètres nommés et positionnels, comme des
+                requêtes Hibernate. Plus d'informations à propos des requêtes SQL natives dans Hibernate
+                peuvent être trouvées dans <xref linkend="querysql"/>.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="objectstate-modifying" revision="1">
+        <title>Modifier des objets persistants</title>
+
+        <para>
+            Les <emphasis>instances persistantes transactionnelles</emphasis> (c'est-à-dire des objets
+            chargés, sauvegardés, créés ou requêtés par la <literal>Session</literal>) peuvent être
+            manipulées par l'application et n'importe quel changement vers l'état persistant sera
+            persisté lorsque la <literal>Session</literal> est <emphasis>"flushée"</emphasis> (traité
+            plus tard dans ce chapitre). Il n'y a pas besoin d'appeler une méthode particulière
+            (comme <literal>update()</literal>, qui a un but différent) pour rendre vos modifications
+            persistantes. Donc la manière la plus directe de mettre à jour l'état d'un objet est de
+            le charger avec <literal>load()</literal>, et puis le manipuler directement, tant que la
+            <literal>Session</literal> est ouverte :
+        </para>
+
+        <programlisting><![CDATA[DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
+cat.setName("PK");
+sess.flush();  // changes to cat are automatically detected and persisted]]></programlisting>
+
+        <para>
+            Parfois ce modèle de programmation est inefficace puisqu'il nécessiterait un
+            <literal>SELECT</literal> SQL (pour charger l'objet) et un <literal>UPDATE</literal>
+            SQL (pour persister son état mis à jour) dans la même session. Aussi Hibernate offre
+            une autre approche, en utilisant des instances détachées.
+        </para>
+
+        <para>
+            <emphasis>Notez que Hibernate n'offre par sa propre API pour l'exécution directe
+            d'expressions <literal>UPDATE</literal> ou <literal>DELETE</literal>. Hibernate
+            est un service de <emphasis>gestion d'état</emphasis>, vous n'avez pas à penser
+            aux <emphasis>expressions</emphasis> pour l'utiliser. JDBC est une API parfaite
+            pour exécuter des expressions SQL, vous pouvez obtenir une <literal>Connection</literal>
+            JDBC n'importe quand en appelant <literal>session.connection()</literal>. En outre,
+            la notion d'opérations de masse entre en conflit avec le mapping objet/relationnel
+            pour les applications orientées processus de transactions en ligne. Les futures
+            versions d'Hibernate peuvent cependant fournir des fonctions d'opération de masse.
+            Voir <xref linkend="batch"/> pour les astuces possibles d'opérations groupées.</emphasis>
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-detached" revision="2">
+        <title>Modifier des objets détachés</title>
+
+        <para>
+            Beaucoup d'applications ont besoin de récupérer un objet dans une transaction,
+            l'envoyer à la couche interfacée avec l'utilisateur pour les manipulations, puis
+            sauvegarder les changements dans une nouvelle transaction. Les applications
+            qui utilisent cette approche dans un environnement à haute concurrence utilisent
+            généralement des données versionnées pour assurer l'isolation pour les "longues"
+            unités de travail.
+        </para>
+
+        <para>
+            Hibernate supporte ce modèle en permettant pour le réattachement d'instances détachées
+            l'utilisation des méthodes <literal>Session.update()</literal> ou <literal>Session.merge()</literal> :
+        </para>
+
+        <programlisting><![CDATA[// dans la première session
+Cat cat = (Cat) firstSession.load(Cat.class, catId);
+Cat potentialMate = new Cat();
+firstSession.save(potentialMate);
+
+// dans une couche plus haute de l'application
+cat.setMate(potentialMate);
+
+// plus tard, dans une nouvelle session
+secondSession.update(cat);  // update cat
+secondSession.update(mate); // update mate]]></programlisting>
+
+        <para>
+            Si le <literal>Cat</literal> avec l'identifiant <literal>catId</literal> avait déjà
+            été chargé par <literal>secondSession</literal> lorsque l'application a essayé de le
+            réattacher, une exception aurait été levée.
+        </para>
+
+        <para>
+            Utilisez <literal>update()</literal> si vous êtes sure que la session ne contient pas
+            déjà une instance persistante avec le même identifiant, et <literal>merge()</literal>
+            si vous voulez fusionner vos modifications n'importe quand sans considérer l'état de
+            la session. En d'autres mots, <literal>update()</literal> est généralement la première méthode
+            que vous devriez appeler dans une session fraîche, pour s'assurer que le réattachement
+            de vos instances détachées est la première opération qui est exécutée.
+        </para>
+
+        <para>
+            L'application devrait individuellement <literal>update()</literal> (NdT : mettre à jour)
+            les instances détachées accessibles depuis l'instance détachée donnée si et
+            <emphasis>seulement</emphasis> si elle veut que leur état soit aussi mis à jour. Ceci
+            peut être automatisé bien sûr, en utilisant la <emphasis>persistance transitive</emphasis>,
+            voir <xref linkend="objectstate-transitive"/>.
+        </para>
+
+        <para>
+            La méthode <literal>lock()</literal> permet aussi à une application de réassocier un
+            objet avec une nouvelle session. Pourtant, l'instance détachée doit être non modifiée !
+        </para>
+
+        <programlisting><![CDATA[//réassocie :
+sess.lock(fritz, LockMode.NONE);
+//fait une vérification de version, puis réassocie :
+sess.lock(izi, LockMode.READ);
+//fait une vérification de version, en utilisant SELECT ... FOR UPDATE, puis réassocie :
+sess.lock(pk, LockMode.UPGRADE);]]></programlisting>
+
+        <para>
+            Notez que <literal>lock()</literal> peut être utilisé avec différents
+            <literal>LockMode</literal>s, voir la documentation de l'API documentation et le chapitre
+            sur la gestion des transactions pour plus d'informations. Le réattachement n'est pas le seul
+            cas d'utilisation pour <literal>lock()</literal>.
+        </para>
+
+        <para>
+            D'autres modèles pour de longues unités de travail sont traités dans <xref linkend="transactions-optimistic"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-saveorupdate">
+        <title>Détection automatique d'un état</title>
+
+        <para>
+            Les utilisateurs d'Hibernate ont demandé une méthode dont l'intention générale
+            serait soit de sauvegarder une instance éphémère en générant un nouvel identifiant,
+            soit mettre à jour/réattacher les instances détachées associées à l'identifiant courant.
+            La méthode <literal>saveOrUpdate()</literal> implémente cette fonctionnalité.
+        </para>
+
+        <programlisting><![CDATA[// dans la première session
+Cat cat = (Cat) firstSession.load(Cat.class, catID);
+
+// dans une partie plus haute de l'application
+Cat mate = new Cat();
+cat.setMate(mate);
+
+// plus tard, dans une nouvelle session
+secondSession.saveOrUpdate(cat);   // met à jour un état existant (cat a un identifiant non-null)
+secondSession.saveOrUpdate(mate);  // sauvegarde les nouvelles instances (mate a un identiant null)]]></programlisting>
+
+        <para>
+            L'usage et la sémantique de <literal>saveOrUpdate()</literal> semble être confuse pour les
+            nouveaux utilisateurs. Premièrement, aussi longtemps que vous n'essayez pas d'utiliser des
+            instances d'une session dans une autre, vous ne devriez pas avoir besoin d'utiliser <literal>update()</literal>,
+            <literal>saveOrUpdate()</literal>, ou <literal>merge()</literal>. Certaines applications
+            n'utiliseront jamais ces méthodes.
+        </para>
+
+        <para>
+            Généralement <literal>update()</literal> ou <literal>saveOrUpdate()</literal> sont utilisées dans
+            le scénario suivant :
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    l'application charge un objet dans la première session
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    l'objet est passé à la couche utilisateur
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    certaines modifications sont effectuées sur l'objet
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    l'objet est retourné à la couche logique métier
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    l'application persiste ces modifications en appelant
+                    <literal>update()</literal> dans une seconde sessin
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>saveOrUpdate()</literal> s'utilise dans le cas suivant :
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    si l'objet est déjà persistant dans cette session, ne rien faire
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    si un autre objet associé à la session a le même identifiant, lever une exception
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    si l'objet n'a pas de propriété d'identifiant, appeler <literal>save()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    si l'identifiant de l'objet a une valeur assignée à un objet nouvellement instancié,
+                    appeler <literal>save()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    si l'objet est versionné (par <literal>&lt;version&gt;</literal> ou
+                    <literal>&lt;timestamp&gt;</literal>), et la valeur de la propriété de version
+                    est la même valeur que celle assignée à un objet nouvellement instancié, appeler
+                    <literal>save()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    sinon mettre à jour l'objet avec <literal>update()</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            et <literal>merge()</literal> est très différent :
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    s'il y a une instance persistante avec le même identifiant couramment
+                    associée à la session, copier l'état de l'objet donné dans l'instance persistante
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    s'il n'y a pas d'instance persistante associée à cette session, essayer de le charger
+                    à partir de la base de données, ou créer une nouvelle instance persistante
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    l'instance persistante est retournée
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    l'instance donnée ne devient pas associée à la session, elle reste détachée
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect1>
+
+    <sect1 id="objectstate-deleting" revision="1">
+        <title>Suppression d'objets persistants</title>
+
+        <para>
+            <literal>Session.delete()</literal> supprimera l'état d'un objet de la base de données.
+            Bien sûr, votre application pourrait encore conserver une référence vers un objet effacé.
+            Il est mieux de penser à <literal>delete()</literal> comme rendant une instance persistante
+            éphémère.
+        </para>
+
+        <programlisting><![CDATA[sess.delete(cat);]]></programlisting>
+
+        <para>
+            Vous pouvez effacer des objets dans l'ordre que vous voulez, sans risque de violations
+            de contrainte de clef étrangère. Il est encore possible de violer une contrainte <literal>NOT
+            NULL</literal> sur une colonne de clef étrangère en effaçant des objets dans le
+            mauvais ordre, par exemple si vous effacer le parent, mais oubliez d'effacer les enfants.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-replicating" revision="1">
+        <title>Réplication d'objets entre deux entrepôts de données</title>
+
+        <para>
+            Il est occasionnellement utile de pouvoir prendre un graphe d'instances persistantes
+            et de les rendre persistantes dans un entrepôt différent, sans regénérer les valeurs
+            des identifiants.
+        </para>
+
+        <programlisting><![CDATA[//récupère un cat de la base de données
+Session session1 = factory1.openSession();
+Transaction tx1 = session1.beginTransaction();
+Cat cat = session1.get(Cat.class, catId);
+tx1.commit();
+session1.close();
+
+// réconcilie la seconde base de données
+Session session2 = factory2.openSession();
+Transaction tx2 = session2.beginTransaction();
+session2.replicate(cat, ReplicationMode.LATEST_VERSION);
+tx2.commit();
+session2.close();]]></programlisting>
+
+        <para>
+            Le <literal>ReplicationMode</literal> détermine comment <literal>replicate()</literal>
+            traitera les conflits avec les lignes existantes dans la base de données.
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.IGNORE</literal> - ignore l'objet s'il y a une ligne
+                    existante dans la base de données avec le même identifiant
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.OVERWRITE</literal> - écrase n'importe quelle ligne existante
+                    dans la base de données avec le même identifiant
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.EXCEPTION</literal> - lève une exception s'il y une ligne dans
+                    la base de données avec le même identifiant
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.LATEST_VERSION</literal> - écrase la ligne si son numéro de version
+                    est plus petit que le numéro de version de l'objet, ou ignore l'objet sinon
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Les cas d'utilisation de cette fonctionnalité incluent la réconciliation de données
+            entrées dans différentes base de données, l'extension des informations de configuration
+            du système durant une mise à jour du produit, retour en arrière sur les changements effectués
+            durant des transactions non-ACID, et plus.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-flushing">
+        <title>Flush de la session</title>
+
+        <para>
+            De temps en temps la <literal>Session</literal> exécutera les expressions SQL
+            requises pour syncrhoniser l'état de la connexion JDBC avec l'état des objets
+            retenus en mémoire. Ce processus, <emphasis>flush</emphasis>, arrive par défaut aux
+            points suivants :
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    lors de certaines exécutions de requête
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    lors d'un appel à <literal>org.hibernate.Transaction.commit()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    lors d'un appel à <literal>Session.flush()</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Les expressions SQL sont effectuées dans l'ordre suivant :
+        </para>
+
+        <orderedlist spacing="compact">
+            <listitem>
+                <para>
+                    insertion des entités, dans le même ordre que celui des
+                    objets correspondants sauvegardés par l'appel à <literal>Session.save()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    mise à jours des entités
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    suppression des collections
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    suppression, mise à jour et insertion des éléments des collections
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    insertion des collections
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    suppression des entités, dans le même ordre que celui des objets
+                    correspondants qui ont été supprimés par l'appel à <literal>Session.delete()</literal>
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <para>
+            (Une exception est que des objets utilisant la génération <literal>native</literal>
+            d'identifiants sont insérés lorsqu'ils sont sauvegardés.)
+        </para>
+
+        <para>
+            Excepté lorsque vous appelez <literal>flush()</literal> explicitement, il n'y
+            absolument aucune garantie à propos de <emphasis>quand</emphasis> la <literal>Session</literal>
+            exécute les appels JDBC, seulement sur l'<emphasis>ordre</emphasis> dans lequel ils sont
+            exécutés. Cependant, Hibernate garantit que <literal>Query.list(..)</literal> ne
+            retournera jamais de données périmées, ni des données fausses.
+        </para>
+
+        <para>
+            Il est possible de changer le comportement par défaut, donc que le flush se produise
+            moins fréquemment. La classe <literal>FlushMode</literal> définit trois modes différents :
+            flush seulement lors du commit (et seulement quand l'API <literal>Transaction</literal>
+            d'Hibernate est utilisée), flush automatiquement en utilisant la procédure expliquée, ou
+            jamais de flush à moins que <literal>flush()</literal> soit appelée explicitement.
+            Le dernier mode est utile pour l'exécution de longues unités de travail, où une
+            <literal>Session</literal> est gardée ouverte et déconnectée pour un long moment
+            (voir <xref linkend="transactions-optimistic-longsession"/>).
+        </para>
+
+        <programlisting><![CDATA[sess = sf.openSession();
+Transaction tx = sess.beginTransaction();
+sess.setFlushMode(FlushMode.COMMIT); // permet aux requêtes de retourner un état périmé
+
+Cat izi = (Cat) sess.load(Cat.class, id);
+izi.setName(iznizi);
+
+// pourrait retourner des données périmées
+sess.find("from Cat as cat left outer join cat.kittens kitten");
+
+// le changement pour izi n'est pas flushé !
+...
+tx.commit(); // le flush se produit]]></programlisting>
+
+        <para>
+            Durant le flush, une exception peut se produire (par exemple, si une opération de la
+            DML viole une contrainte). Puisque les exceptions de gestion impliquent une certaine
+            compréhension du comportement transactionnel d'Hibernate, nous le traitons dans
+            <xref linkend="transactions"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-transitive" revision="1">
+        <title>Persistance transitive</title>
+
+        <para>
+            Il est assez pénible de sauvegarder, supprimer, ou réattacher des objets
+            un par un, surtout si vous traitez un graphe d'objets associés. Un cas habituel
+            est une relation parent/enfant. Considérez l'exemple suivant :
+        </para>
+
+        <para>
+            Si les enfants de la relation parent/enfant étaient des types de valeur (par exemple,
+            une collection d'adresses ou de chaînes de caractères), leur cycle de vie dépendraient
+            du parent et aucune action ne serait requise pour "cascader" facilement les
+            changements d'état. Si le parent est sauvegardé, les objets enfants de type de valeur sont
+            sauvegardés également, si le parent est supprimé, les enfants sont supprimés, etc. Ceci
+            fonctionne même pour des opérations telles que la suppression d'un enfant de la collection ;
+            Hibernate détectera cela et, puisque les objets de type de valeur ne peuvent pas avoir
+            des références partagées, supprimera l'enfant de la base de données.
+        </para>
+
+        <para>
+            Maintenant considérez le même scénario avec un parent et dont les objets enfants
+            sont des entités, et non des types de valeur (par exemple, des catégories et des
+            objets, ou un parent et des chatons). Les entités ont leur propre cycle de vie,
+            supportent les références partagées (donc supprimer une entité de la collection
+            ne signifie pas qu'elle peut être supprimée), et il n'y a par défaut pas de
+            cascade d'état d'une entité vers n'importe quelle entité associée. Hibernate
+            n'implémente pas la <emphasis>persistance par accessibilité</emphasis> par défaut.
+        </para>
+
+        <para>
+            Pour chaque opération basique de la session d'Hibernate - incluant <literal>persist(), merge(),
+            saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate()</literal> - il y a un
+            style de cascade correspondant. Respectivement, les styles de cascade s'appellent <literal>persist,
+            merge, save-update, delete, lock, refresh, evict, replicate</literal>. Si vous voulez qu'une
+            opération soit cascadée le long d'une association, vous devez l'indiquer dans le document de
+            mapping. Par exemple :
+        </para>
+
+        <programlisting><![CDATA[<one-to-one name="person" cascade="persist"/>]]></programlisting>
+
+        <para>
+            Les styles de cascade peuvent être combinés :
+        </para>
+
+        <programlisting><![CDATA[<one-to-one name="person" cascade="persist,delete,lock"/>]]></programlisting>
+
+        <para>
+            Vous pouvez même utiliser <literal>cascade="all"</literal> pour spécifier que <emphasis>toutes</emphasis>
+            les opérations devraient être cascadées le long de l'association. La valeur par défaut
+            <literal>cascade="none"</literal> spécifie qu'aucune opération ne sera cascadée.
+        </para>
+
+        <para>
+            Une style de cascade spécial, <literal>delete-orphan</literal>, s'applique seulement
+            aux associations un-vers-plusieurs, et indique que l'opération <literal>delete()</literal>
+            devrait être appliquée à n'importe quel enfant qui est supprimé de l'association.
+        </para>
+
+
+        <para>
+            Recommandations :
+        </para>
+
+       <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Cela n'a généralement aucun sens d'activer la cascade sur une association
+                    <literal>&lt;many-to-one&gt;</literal> ou <literal>&lt;many-to-many&gt;</literal>. Les
+                    cascades sont souvent utiles pour des associations
+                    <literal>&lt;one-to-one&gt;</literal> et <literal>&lt;one-to-many&gt;</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Si la durée de vie de l'objet enfant est liée à la durée de vie de l'objet parent,
+                    faites en un <emphasis>objet du cycle de vie</emphasis> en spécifiant
+                    <literal>cascade="all,delete-orphan"</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Sinon, vous pourriez ne pas avoir besoin de cascade du tout. Mais si vous pensez que vous
+                    travaillerez souvent avec le parent et les enfants ensemble dans la même transaction, et
+                    que vous voulez vous éviter quelques frappes, considérez l'utilisation de
+                    <literal>cascade="persist,merge,save-update"</literal>.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Mapper une association (soit une simple association valuée, soit une collection) avec
+            <literal>cascade="all"</literal> marque l'association comme une relation de style
+            <emphasis>parent/enfant</emphasis> où la sauvegarde/mise à jour/suppression du parent
+            entraîne la sauvegarde/mise à jour/suppression de l'enfant ou des enfants.
+        </para>
+        <para>
+            En outre, une simple référence à un enfant d'un parent persistant aura pour conséquence
+            la sauvegarde/mise à jour de l'enfant. Cette métaphore est cependant incomplète. Un enfant
+            qui devient non référencé par son parent <emphasis>n'est pas</emphasis> automatiquement
+            supprimée, excepté dans le cas d'une association <literal>&lt;one-to-many&gt;</literal>
+            mappée avec <literal>cascade="delete-orphan"</literal>. La sémantique précise des opérations
+            de cascade pour une relation parent/enfant est la suivante :
+        </para>
+
+       <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Si un parent est passé à <literal>persist()</literal>, tous les enfant sont passés à
+                    <literal>persist()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Si un parent est passé à <literal>merge()</literal>, tous les enfants sont passés à
+                    <literal>merge()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Si un parent est passé à <literal>save()</literal>, <literal>update()</literal> ou
+                    <literal>saveOrUpdate()</literal>, tous les enfants sont passés à <literal>saveOrUpdate()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Si un enfant détaché ou éphémère devient référencé par un parent persistant,
+                    il est passé à <literal>saveOrUpdate()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Si un parent est supprimé, tous les enfants sont passés à <literal>delete()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Si un enfant est déréférencé par un parent persistant, <emphasis>rien de spécial
+                    n'arrive</emphasis> - l'application devrait explicitement supprimer l'enfant si nécessaire -
+                    à moins que <literal>cascade="delete-orphan"</literal> soit paramétré,
+                    au quel cas l'enfant "orphelin" est supprimé.
+                </para>
+            </listitem>
+        </itemizedlist>
+		
+		<para>
+            Enfin, la cascade des opérations peut être effectuée sur un graphe donné lors
+			de l'<emphasis>appel de l'opération</emphasis> or lors du <emphasis>flush</emphasis>
+			suivant. Toutes les opérations, lorsque cascadées, le sont sur toutes les entités
+			associées atteignables lorsque l'opétation est exécutée. Cependant 
+			<literal>save-upate</literal> et <literal>delete-orphan</literal> sont cascadées
+            à toutes les entités associées atteignables lors du flush de la 
+            <literal>Session</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-metadata">
+        <title>Utilisation des méta-données</title>
+
+        <para>
+            Hibernate requiert un modèle de méta-niveau très riche de toutes les entités et types valués.
+            De temps en temps, ce modèle est très utile à l'application elle même. Par exemple,
+            l'application pourrait utiliser les méta-données d'Hibernate pour implémenter un algorithme
+            de copie en profondeur "intelligent" qui comprendrait quels objets devraient copiés
+            (par exemple les types de valeur mutables) et lesquels ne devraient pas l'être (par exemple
+            les types de valeurs immutables et, possiblement, les entités associées).
+        </para>
+        <para>
+            Hibernate expose les méta-données via les interfaces <literal>ClassMetadata</literal>
+            et <literal>CollectionMetadata</literal> et la hiérarchie <literal>Type</literal>.
+            Les instances des interfaces de méta-données peuvent être obtenues à partir de la
+            <literal>SessionFactory</literal>.
+        </para>
+
+        <programlisting><![CDATA[Cat fritz = ......;
+ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class);
+
+Object[] propertyValues = catMeta.getPropertyValues(fritz);
+String[] propertyNames = catMeta.getPropertyNames();
+Type[] propertyTypes = catMeta.getPropertyTypes();
+
+// récupère une Map de toutes les propriétés qui ne sont pas des collections ou des associations
+Map namedValues = new HashMap();
+for ( int i=0; i<propertyNames.length; i++ ) {
+    if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType() ) {
+        namedValues.put( propertyNames[i], propertyValues[i] );
+    }
+}]]></programlisting>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/toolset_guide.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/toolset_guide.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/toolset_guide.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,594 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="toolsetguide" revision="2">
+    <title>Guide des outils</title>
+
+    <para>
+        Des outils en ligne de commande, des plugins Eclipse ainsu que des tâches Ant permettent de gérer de cycles de développement complet
+    de projets utilisant Hibernate.
+    </para>
+
+    <para>
+        Les <emphasis>outils Hibernate</emphasis> actuels incluent des plugins pour l'IDE Eclipse ainsi que des tâches Ant pour l'ingénierie 
+        inverse de bases de données existantes :
+    </para>
+
+    <itemizedlist>
+        <listitem><para>
+            <emphasis>Mapping Editor :</emphasis> un éditeur pour les fichiers de mapping XML Hibernate, supportant l'auto-complétion et la mise en valeur de la syntaxe.
+            Il supporte aussi l'auto-complétion automatique pour les noms de classes et les noms de propriété/champ,
+            le rendant beaucoup plus polyvalent qu'un éditeurXML normal.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Console :</emphasis> la console est une nouvelle vue d'Eclipse. En plus de la vue d'ensemble
+            arborescente de vos configurations de console, vous obtenez aussi une vue interactive de vos classes persistantes et de leurs relations.
+            La console vous permet d'exécuter des requête HQL dans votre base de données et de parcourir les résultats directement dans Eclipse.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Development Wizards :</emphasis> plusieurs assistants sont fournis avec les outils d'Hibernate
+            pour Eclipse ; vous pouvez utiliser un assistant pour générer rapidement les fichiers de configuration d'Hibernate (cfg.xml),
+            ou vous pouvez même complètement générer les fichiers de mapping Hibernate et les sources des POJOs à partir d'un schéma de base de données existant.
+            L'assistant d'ingénierie inverse supporte les modèles utilisateur.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Tâches Ant :</emphasis>
+        </para></listitem>
+
+    </itemizedlist>
+
+    <para>
+        Veuillez-vous référer au paquet <emphasis>outils Hibernate</emphasis> et sa documentation pour plus d'informations.
+    </para>
+
+    <para>
+        Pourtant, le paquet principal d'Hibernate arrive avec un lot d'outils intégrés (il peut même être utilisé de "l'intérieur" d'Hibernate à la volée) :
+        <emphasis>SchemaExport</emphasis> aussi connu comme
+        <literal>hbm2ddl</literal>.
+    </para>
+
+    <sect1 id="toolsetguide-s1" revision="2">
+        <title>Génération automatique du schéma</title>
+
+        <para>
+            La DDL peut être générée à partir de vos fichiers de mapping par un utilitaire d'Hibernate. Le schéma généré
+            inclut les contraintes d'intégrité référentielle (clefs primaires et étrangères) pour les tables d'entités
+            et de collections. Les tables et les séquences sont aussi créées pour les générateurs d'identifiant mappés.
+        </para>
+
+        <para>
+            Vous <emphasis>devez</emphasis> spécifier un <literal>Dialect</literal> SQL via la propriété
+            <literal>hibernate.dialect</literal> lors de l'utilisation de cet outils, puisque la DDL est
+            fortement dépendante de la base de données.
+        </para>
+
+        <para>
+            D'abord, personnalisez vos fichiers de mapping pour améliorer le schéma généré.
+        </para>
+
+        <sect2 id="toolsetguide-s1-2" revision="3">
+            <title>Personnaliser le schéma</title>
+
+            <para>
+                Plusieurs éléments du mapping hibernate définissent des attributs optionnels
+                nommés <literal>length</literal>, <literal>precision</literal> et <literal>scale</literal>.
+                Vous pouvez paramétrer la longueur, la précision,...  d'une colonne avec ces attributs.
+            </para>
+            
+            <programlisting><![CDATA[<property name="zip" length="5"/>]]></programlisting>
+            <programlisting><![CDATA[<property name="balance" precision="12" scale="2"/>]]></programlisting>
+
+            <para>
+                Certains éléments acceptent aussi un attribut <literal>not-null</literal>
+                (utilisé pour générer les contraintes de colonnes <literal>NOT NULL</literal>) et
+                un attribut <literal>unique</literal> (pour générer une contrainte de colonne
+                <literal>UNIQUE</literal>).
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="bar" column="barId" not-null="true"/>]]></programlisting>
+            <programlisting><![CDATA[<element column="serialNumber" type="long" not-null="true" unique="true"/>]]></programlisting>
+
+            <para>
+                Un attribut <literal>unique-key</literal> peut être utilisé pour grouper les colonnes
+                en une seule contrainte d'unicité. Actuellement, la valeur spécifiée par
+                l'attribut <literal>unique-key</literal> n'est <emphasis>pas</emphasis> utilisée pour
+                nommer la contrainte dans le DDL généré, elle sert juste à grouper les colonnes
+                dans le fichier de mapping.
+            </para>
+            <programlisting><![CDATA[<many-to-one name="org" column="orgId" unique-key="OrgEmployeeId"/>
+            <property name="employeeId" unique-key="OrgEmployee"/>]]></programlisting>
+
+            <para>
+                Un attribut <literal>index</literal> indique le nom d'un index qui sera
+                créé  en utilisant la ou les colonnes mappées. Plusieurs colonnes
+                peuvent être groupées dans un même index, en spécifiant le même
+                nom d'index. 
+            </para>
+
+            <programlisting><![CDATA[<property name="lastName" index="CustName"/>
+<property name="firstName" index="CustName"/>]]></programlisting>
+
+            <para>
+                Un attribut <literal>foreign-key</literal> peut être utilisé pour surcharger le nom
+                des clés étrangères générées.
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="bar" column="barId" foreign-key="FKFooBar"/>]]></programlisting>
+
+            <para>
+                Plusieurs éléments de mapping acceptent aussi un élément fils <literal>&lt;column&gt;</literal>. 
+                Ceci est utile pour les type multi-colonnes:
+            </para>
+
+            <programlisting><![CDATA[<property name="name" type="my.customtypes.Name"/>
+    <column name="last" not-null="true" index="bar_idx" length="30"/>
+    <column name="first" not-null="true" index="bar_idx" length="20"/>
+    <column name="initial"/>
+</property>]]></programlisting>
+
+            <para>
+                L'attribut <literal>default</literal> vous laisse spécifier une valeur par défaut pour
+                une colonnes (vous devriez assigner la même valeur à la propriété mappée avant de sauvegarder une nouvelle instance
+                de la classe mappée).
+            </para>
+
+            <programlisting><![CDATA[<property name="credits" type="integer" insert="false">
+    <column name="credits" default="10"/>
+</property>]]></programlisting>
+
+            <programlisting><![CDATA[<version name="version" type="integer" insert="false">
+    <column name="version" default="0"/>
+</property>]]></programlisting>
+
+            <para>
+                L'attribut <literal>sql-type</literal> laisse l'utilisateur surcharger le mapping
+                par défaut du type Hibernate vers un type SQL.
+            </para>
+            
+            <programlisting><![CDATA[<property name="balance" type="float">
+    <column name="balance" sql-type="decimal(13,3)"/>
+</property>]]></programlisting>
+            
+
+            <para>
+                L'attribut <literal>check</literal> permet de spécifier une contrainte de vérification.
+            </para>
+
+            <programlisting><![CDATA[<property name="foo" type="integer">
+    <column name="foo" check="foo > 10"/>
+</property>]]></programlisting>
+
+            <programlisting><![CDATA[<class name="Foo" table="foos" check="bar < 100.0">
+    ...
+    <property name="bar" type="float"/>
+</class>]]></programlisting>
+
+
+            <table frame="topbot" id="schemattributes-summary" revision="2">
+                <title>Summary</title>
+                <tgroup cols="3">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>Attribut</entry>
+                            <entry>Valeur</entry>
+                            <entry>Interprétation</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>length</literal></entry>
+                            <entry>numérique</entry>
+                            <entry>taille d'une colonne</entry>
+                        </row>
+                        <row>
+                            <entry><literal>precision</literal></entry>
+                            <entry>numérique</entry>
+                            <entry>précision décimale de la colonne</entry>
+                        </row>
+                        <row>
+                            <entry><literal>scale</literal></entry>
+                            <entry>numérique</entry>
+                            <entry>scale décimale de la colonne</entry>
+                        </row>
+                        <row>
+                            <entry><literal>not-null</literal></entry>
+                            <entry><literal>true|false</literal></entry>
+                            <entry>spécifie que la colonne doit être non-nulle</entry>
+                        </row>
+                        <row>
+                            <entry><literal>unique</literal></entry>
+                            <entry><literal>true|false</literal></entry>
+                            <entry>spécifie que la colonne doit avoir une contrainte d'unicité</entry>
+                        </row>
+                        <row>
+                            <entry><literal>index</literal></entry>
+                            <entry><literal>index_name</literal></entry>
+                            <entry>spécifie le nom d'un index (multi-colonnes)</entry>
+                        </row>
+                        <row>
+                            <entry><literal>unique-key</literal></entry>
+                            <entry><literal>unique_key_name</literal></entry>
+                            <entry>spécifie le nom d'une contrainte d'unicité multi-colonnes</entry>
+                        </row>
+                        <row>
+                            <entry><literal>foreign-key</literal></entry>
+                            <entry><literal>foreign_key_name</literal></entry>
+                            <entry>
+                                spécifie le nom d'une contrainte de clé étrangère générée pour
+                                une association, utilisez-la avec les éléments de mapping
+                                &lt;one-to-one&gt;, &lt;many-to-one&gt;, &lt;key&gt;, et &lt;many-to-many&gt;
+                                Notez que les extrêmités <literal>inverse="true"</literal>
+                                se seront pas prises en compte par <literal>SchemaExport</literal>.
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>sql-type</literal></entry>
+                            <entry><literal>SQL column_type</literal></entry>
+                            <entry>
+                                surcharge le type par défaut (attribut de
+                                l'élément <literal>&lt;column&gt;</literal> uniquement)
+                            </entry>
+                       </row>
+                       <row>
+                            <entry><literal>default</literal></entry>
+                            <entry>expression SQL</entry>
+                            <entry>
+                                spécifie une valeur par défaut pour la colonne
+                            </entry>
+                       </row>
+                       <row>
+                            <entry><literal>check</literal></entry>
+                            <entry>SQL expression</entry>
+                            <entry>
+                                crée une contrainte de vérification sur la table ou la colonne
+                            </entry>
+                       </row>
+                   </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                L'élément <literal>&lt;comment&gt;</literal> vous permet de spécifier un commentaire pour le schéma généré.
+            </para>
+
+            <programlisting><![CDATA[<class name="Customer" table="CurCust">
+    <comment>Current customers only</comment>
+    ...
+</class>]]></programlisting>
+
+            <programlisting><![CDATA[<property name="balance">
+    <column name="bal">
+        <comment>Balance in USD</comment>
+    </column>
+</property>]]></programlisting>
+
+            <para>
+                Ceci a pour résultat une expression
+                <literal>comment on table</literal> ou
+                <literal>comment on column</literal> dans la DDL générée (où supportée).
+            </para>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-3" revision="2">
+            <title>Exécuter l'outil</title>
+
+            <para>
+                L'outil <literal>SchemaExport</literal> génère un script DDL vers
+                la sortie standard et/ou exécute les ordres DDL.
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>classpath_hibernate</emphasis>
+                <literal>net.sf.hibernate.tool.hbm2ddl.SchemaExport</literal> <emphasis>options fichiers_de_mapping</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaExport</literal> Options de la ligne de commande</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Option</entry>
+                            <entry>Description</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--quiet</literal></entry>
+                            <entry>ne pas écrire le script vers la sortie standard</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--drop</literal></entry>
+                            <entry>supprime seuleument les tables</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--create</literal></entry>
+                            <entry>ne créé que les tables</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--text</literal></entry>
+                            <entry>ne pas exécuter sur la base de données</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--output=my_schema.ddl</literal></entry>
+                            <entry>écrit le script ddl vers un fichier</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>sélectionne une <literal>NamingStrategy</literal></entry>
+                        </row>
+                        <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry>lit la configuration Hibernate à partir d'un fichier XML</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>lit les propriétés de la base de données à partir d'un fichier</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--format</literal></entry>
+                            <entry>formatte proprement le SQL généré dans le script</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--delimiter=x</literal></entry>
+                            <entry>paramètre un délimiteur de fin de ligne pour le script</entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                Vous pouvez même intégrer <literal>SchemaExport</literal> dans votre application :
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaExport(cfg).create(false, true);]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-4">
+            <title>Propriétés</title>
+
+            <para>
+                Les propriétés de la base de données peuvent être spécifiées
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>comme propriétés système avec <literal>-D</literal><emphasis>&lt;property&gt;</emphasis></para>
+                </listitem>
+                <listitem>
+                    <para>dans <literal>hibernate.properties</literal></para>
+                </listitem>
+                <listitem>
+                    <para>dans un fichier de propriétés déclaré avec <literal>--properties</literal></para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Les propriétés nécessaires sont :
+            </para>
+
+            <table frame="topbot">
+                <title>SchemaExport Connection Properties</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Nom de la propriété</entry>
+                            <entry>Description</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                    <row>
+                        <entry><literal>hibernate.connection.driver_class</literal></entry>
+                        <entry>classe du driver JDBC</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.url</literal></entry>
+                        <entry>URL JDBC</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.username</literal></entry>
+                        <entry>utilisateur de la base de données</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.password</literal></entry>
+                        <entry>mot de passe de l'utilisateur</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.dialect</literal></entry>
+                        <entry>dialecte</entry>
+                    </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-5">
+            <title>Utiliser Ant</title>
+
+            <para>
+                Vous pouvez appeler <literal>SchemaExport</literal> depuis votre script
+                de construction Ant :
+            </para>
+
+            <programlisting><![CDATA[<target name="schemaexport">
+    <taskdef name="schemaexport"
+        classname="org.hibernate.tool.hbm2ddl.SchemaExportTask"
+        classpathref="class.path"/>
+
+    <schemaexport
+        properties="hibernate.properties"
+        quiet="no"
+        text="no"
+        drop="no"
+        delimiter=";"
+        output="schema-export.sql">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaexport>
+</target>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-6" revision="2">
+            <title>Mises à jour incrémentales du schéma</title>
+
+            <para>
+                L'outil <literal>SchemaUpdate</literal> mettra à jour un schéma existant
+                en effectuant les changement par "incrément".
+                Notez que <literal>SchemaUpdate</literal> dépends beaucoup de l'API JDBC
+                metadata, il ne fonctionnera donc pas avec tous les drivers JDBC.
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>classpath_hibernate</emphasis>
+                <literal>net.sf.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>options fichiers_de_mapping</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaUpdate</literal> Options de ligne de commande</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Option</entry>
+                            <entry>Description</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--quiet</literal></entry>
+                            <entry>ne pas écrire vers la sortie standard</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--text</literal></entry>
+                            <entry>ne pas exporter vers la base de données</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>choisit une <literal>NamingStrategy</literal></entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>lire les propriétés de la base de données à partir d'un fichier</entry>
+                        </row>
+                     </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                Vous pouvez intégrer <literal>SchemaUpdate</literal> dans votre application :
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaUpdate(cfg).execute(false);]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-7">
+            <title>Utiliser Ant pour des mises à jour de schéma par incrément</title>
+
+            <para>
+                Vous pouvez appeler <literal>SchemaUpdate</literal> depuis le script Ant :
+            </para>
+
+            <programlisting><![CDATA[<target name="schemaupdate">
+    <taskdef name="schemaupdate"
+        classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask"
+        classpathref="class.path"/>
+
+    <schemaupdate
+        properties="hibernate.properties"
+        quiet="no">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaupdate>
+</target>]]></programlisting>
+
+        <sect2 id="toolsetguide-s1-8" revision="1">
+            <title>Validation du schéma</title>
+
+            <para>
+                L'outil <literal>SchemaValidator</literal> validera que le schéma existant correspond à vos documents de mapping.
+                Notez que le <literal>SchemaValidator</literal> dépends de l'API metadata de JDBC, il ne fonctionnera
+                donc pas avec tous les drivers JDBC. Cet outil est extrêmement utile pour tester.
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaValidator</literal> <emphasis>options mapping_files</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaValidator</literal> Options de ligne de commande</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Option</entry>
+                            <entry>Description</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>Indique une <literal>NamingStrategy</literal></entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>lit les propriétés dela base de données depuis un fichier de propriétés</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry>indique un fichier <literal>.cfg.xml</literal></entry>
+                        </row>
+                     </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                Vous pouvez inclure <literal>SchemaValidator</literal> dans votre application:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaValidator(cfg).validate();]]></programlisting>
+
+        </sect2>
+
+        </sect2>
+        <sect2 id="toolsetguide-s1-9">
+            <title>Utiliser Ant pour la validation du Schéma</title>
+
+            <para>
+                Vous pouvez appeler <literal>SchemaValidator</literal> depuis le script Ant:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemavalidate">
+    <taskdef name="schemavalidator"
+        classname="org.hibernate.tool.hbm2ddl.SchemaValidatorTask"
+        classpathref="class.path"/>
+    
+    <schemavalidator
+        properties="hibernate.properties">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaupdate>
+</target>]]></programlisting>
+
+        </sect2>
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/transactions.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/transactions.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/transactions.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1074 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="transactions"  revision="2">
+    <title>Transactions et accès concurrents</title>
+
+    <para>
+        L'un des principaux avantages du mécanisme de contrôle des accès concurrents d'Hibernate est qu'il est très
+        facile à comprendre. Hibernate utilise directement les connexions JDBC ainsi que les ressources JTA sans y
+        ajouter davantage de mécanisme de blocage. Nous vous recommandons de vous familiariser avec les spécifications
+        JDBC, ANSI et d'isolement de transaction de la base de données que vous utilisez.
+    </para>
+
+    <para>
+        Hibernate ne vérouille pas vos objets en mémoire. Votre application peut suivre le
+        comportement défini par le niveau d'isolation de vos transactions de base de données.
+        Notez que grâce à la <literal>Session</literal>, qui est aussi un cache de scope transaction, Hibernate
+        fournit des lectures répétées pour les récupération par identifiants et les requêtes
+        d'entités (pas celle de valeurs scalaires).
+    </para>
+    
+    <para>
+        En addition au versionning pour le controle automatique de concurrence, Hibernate fournit
+        une API (mineure) pour le verrouillage perssimiste des enregistrements, en générant
+        une syntaxe <literal>SELECT FOR UPDATE</literal>. Le controle de concurrence optimiste
+        et cette API seront détaillés plus tard dans ce chapitre.
+    </para>
+
+    <para>
+        Nous aborderons la gestion des accès concurrents en discutant de la granularité des objets <literal>Configuration</literal>,
+        <literal>SessionFactory</literal>, et <literal>Session</literal>, ainsi que de certains concepts relatifs à la base de données
+        et aux longues transactions applicatives.
+    </para>
+
+    <sect1 id="transactions-basics" revision="1">
+        <title>Gestion de session et délimitation de transactions</title>
+
+        <para>Il est important de savoir qu'un objet <literal>SessionFactory</literal> est un objet complexe et optimisé pour
+            fonctionner avec les threads(thread- safe). Il est coûteux à créer et est ainsi prévu pour n'être instancié qu?une
+            seule fois via un objet <literal>Configuration</literal> au démarrage de l'application, 
+            et être partagé par tous les threads d'une application.
+        </para>
+
+        <para>Un objet <literal>Session</literal> est relativement simple et n'est threadsafe. Il est également peu
+            coûteux à créer. Il devrait n'être utilisé qu'une seule fois, pour un processus d'affaire ou une unité de
+            travail ou une conversation et ensuite être relâché. Un objet <literal>Session</literal> ne tentera pas 
+            d'obtenir de connexion ( <literal>Connection</literal> ) 
+            JDBC (ou de <literal>Datasource</literal> ) si ce n'est pas nécessaire.             
+        </para>
+
+        <para>Afin de compléter ce tableau, vous devez également penser aux transactions de base de données. Une
+            transaction de base de données se doit d'être la plus courte possible afin de réduire les risques de
+            collision sur des enregistrements verrouillés. De longues transactions à la base de données nuiront à
+            l'extensibilité de vos applications lorsque confrontées à de hauts niveaux de charge. Par conséquent,
+            il n'est jamais bon de maintenir une transaction ouverte pendant la durée de reflexion de l'utilisateur,
+            jusqu'a ce que l'unité de travail soit achevée.
+        </para>
+
+        <para>Maintenant, comment délimiter une unité de travail? Est-ce qu'une instance de <literal>Session</literal> peut avoir une durée
+            de vie dépassant plusieurs transactions à la base de données, ou bien est-ce que celles-ci doivent être liées une à une?
+            Quand faut-il ouvrir et fermer une <literal>Session</literal> ? Comment définir la démarcation de vos transactions à la base de données?
+        </para>
+
+        <sect2 id="transactions-basics-uow" revision="1">
+            <title>Unité de travail</title>
+
+            <para>
+                Il est important de mentionner que d'utiliser un paradigme <emphasis>session-par-operation</emphasis>
+                est un anti-pattern. Autrement dit: n'ouvrez et ne fermez pas la
+                <literal>Session</literal> à chacun de vos accès simples à la base de données dans un même thread! Bien sûr, le même raisonnement
+                s'applique sur la gestion des transactions à la base de données. Les appels à la base de données
+                devraient être faits en ordre et selon une séquence définie. Ils devraient également être regroupés en
+                des unités de travail atomiques. (Notez que l?utilisation d?une connexion auto-commit constitue le même
+                anti-pattern. Ce mode de fonctionnement existe pour les applications émettant des commandes SQL à partir
+                d?une console. Hibernate désengage le mode auto-commit et s'attend à ce qu'un serveur d'applications le
+                fasse également.)
+                Les transactions avec la base de données ne sont jamais optionnelles, toute communication
+                avec une base de données doit se dérouler dans une transaction, peu importe si vous lisez
+                ou écrivez des données. Comme évoqué, le comportement auto-commit pour lire les
+                données devrait être évité, puisque plusieurs petites transactions ne seront jamais
+                aussi efficaces qu'une seule plus grosse clairement définie comme unité de travail.
+                Ce dernier choix et en plus beaucoup plus facile a maintenir et à faire évoluer.
+            </para>
+
+            <para>
+                Le pattern d'utilisation le plus fréquemment rencontré dans des applications clients serveur
+                multi-usagers est le <emphasis>session-per-request</emphasis>
+                (littéralement : Session par requête). Dans ce modèle, la requête d'un client est envoyée à un serveur
+                (Où la couche de persistance est implémentée via Hibernate), une nouvelle
+                <literal>Session</literal> est ouverte et toutes les opérations d'accès à la base de données sont exécutées à l'intérieur de
+                celle-ci. Lorsque le travail est terminé (et que les réponses à envoyer au client ont été préparées), la
+                session est flushée et fermée. Une seule transaction à la base de données peut être utilisée pour répondre
+                à la requête du client. La transaction est démarrée et validée au même moment où la Session est ouverte 
+                et fermée. La relation entre la <literal>Session</literal> et la <literal>Transaction</literal> est donc one-to-one. 
+                Ce modèle permet de répondre parfaitement aux attentes de la grande majorité des
+                applications.
+            </para>
+
+            <para>
+                Le défi réside dans l'implémentation. Hibernate fournit une fonction de gestion de
+                la "session courante" pour simplifier ce pattern. Tout ce que vous devez faire
+                est démarrer une transaction lorsqu'une requête est traitée par le serveur, et
+                la terminer avant que la réponse ne soit envoyée au client. Vous pouvez le faire
+                de la manière que vous voulez, les solutions communes sont un <literal>ServletFilter</literal>, 
+                l'interception via AOP avec une pointcut sur les méthodes de type "service", ou un conteneur
+                avec interception/proxy. Un conteneur EJB est un moyen standard d'implémenter ce genre d'acpect
+                tranverse comme la démarcation des transactions sur les EJBs session, de manière déclarative
+                avec CMT. Si vous décidez d'utiliser la démarcation programmatique des transactions, préferrez
+                l'API Hibernate <literal>Transaction</literal> détaillée plus tard dans ce chapitre, afin de
+                facilité l'utilisation et la portabilité du code.
+            </para>
+
+            <para>
+                Votre application peut accéder la "session courante" pour exécuter une requête
+                en invoquant simplement <literal>sessionFactory.getCurrentSession()</literal> n'importe où
+                et autant de fois que souhaité. Vous obtiendrez toujours une <literal>Session</literal> 
+                dont le scope est la transaction courante avec la base de données. Ceci doit être configuré 
+                soit dans les ressources local ou dans l'environnement JTA, voir <xref linkend="architecture-current-session"/>.
+            </para>
+
+            <para>
+                Il est parfois utile d'étendre le scope d'une <literal>Session</literal> et d'une transaction
+                à la base de données jusqu'à ce que "la vue soit rendue". Ceci est particulièrement
+                utile dans des applications à base de servlet qui utilisent une phase de rendue séparée une fois
+                que la réponse a été préparée. Etendre la transaction avec la base de données jusqu'à la fin du
+                rendering de la vue est aisé si vous implémentez  votre propre intercepteur. Cependant,
+                ce n'est pas facile si vous vous appuyez sur les EJBs avec CMT, puisqu'une transaction sera
+                achevée au retour de la méthode EJB, avant le rendu de la vue. Rendez vous sur le site
+                Hibernate et sur le forum pour des astuces et des exemples sur le pattern
+                <emphasis>Open Session in View</emphasis> pattern..
+             </para>
+        </sect2>
+
+        <sect2 id="transactions-basics-apptx"  revision="1">
+            <title>Longue conversation</title>
+
+            <para>Le paradigme
+                <emphasis>session-per-request</emphasis>
+                n'est pas le seul élément à utiliser dans le design de vos unités de travail. Plusieurs processus
+                d'affaire requièrent toute une série d'interactions avec l'utilisateur, entrelacées d'accès à la base de
+                donnée. Dans une application Web ou une application d'entreprise, il serait inacceptable que la durée de
+                vie d'une transaction s'étale sur plusieurs interactions avec l'usager. Considérez l'exemple suivant:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>Un écran s'affiche. Les données vues par l'usager ont été chargées dans l'instance d'un objet
+                        <literal>Session</literal> , dans le cadre d'une transaction de base de données. L'usager est libre de modifier ces objets.
+                    </para>
+                </listitem>
+                <listitem>
+
+                    <para>L'usager clique "Sauvegarder" après 5 minutes et souhaite persister les modifications qu'il a
+                        apportées. Il s'attend à être la seule personne a avoir modifié ces données et qu'aucune
+                        modification conflictuelle ne se soit produite durant ce laps de temps.</para>
+                </listitem>
+            </itemizedlist>
+
+            <para>Ceci s'appelle une unité de travail. Du point de vue de l'utilisateur: une
+                <emphasis>conversation</emphasis> (ou <emphasis>transaction d'application</emphasis>).
+                Il y a plusieurs façon de mettre ceci en place dans votre application.
+            </para>
+
+            <para>Une première implémentation naïve pourrait consister à garder la
+                <literal>Session</literal> et la transaction à la base de données ouvertes durant le temps de travail de l'usager, à maintenir les
+                enregistrements verrouillés dans la base de données afin d'éviter des modifications concurrentes et de
+                maintenir l'isolation et l'atomicité de la transaction de l'usager. Ceci est un anti-pattern à éviter,
+                puisque le verrouillage des enregistrements dans la base de données ne permettrait pas à l'application
+                de gérer un grand nombre d'usagers concurrents.
+            </para>
+
+            <para>Il apparaît donc évident qu'il faille utiliser plusieurs transactions BDD afin d'implémenter la
+                conversation. Dans ce cas, maintenir l'isolation des processus d'affaire devient
+                partiellement la responsabilité de la couche applicative. Ainsi, la durée de vie d'une conversation
+                devrait englober celle d'une ou de plusieurs transactions de base de données. Celle-ci sera
+                atomique seulement si l'écriture des données mises à jour est faite exclusivement par la dernière
+                transaction BDD la composant. Toutes les autres sous transactions BD ne doivent faire que la lecture de
+                données. Ceci est relativement facile à mettre en place, surtout avec l'utilisation de certaines
+                fonctionnalités d'Hibernate:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <emphasis>Versionnage Automatique</emphasis>
+                        - Hibernate peut gérer automatiquement les accès concurrents de manière optimiste et détecter si
+                        une modification concurrente s'est produite durant le temps de réflexion d'un usager.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <emphasis>Objets Détachés</emphasis>
+                        - Si vous décidez d'utiliser le paradigme
+                        <emphasis>session-par-requête</emphasis>
+                        discuté plus haut, toutes les entités chargées en mémoire deviendront des objets détachés durant
+                        le temps de réflexion de l'usager. Hibernate vous permet de rattacher ces objets et de persister
+                        les modifications y ayant été apportées. Ce pattern est appelé:
+                        <emphasis>session-per- request-with-detached-objects</emphasis>
+                        (littéralement: session- par-requête-avec-objets-détachés). Le versionnage automatique est
+                        utilisé afin d'isoler les modifications concurrentes.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <emphasis>Session Longues (conversation)</emphasis>
+                        - Une
+                        <literal>Session</literal> Hibernate peut être déconnectée de la couche JDBC sous-jacente après que commit() ait été appelé
+                        sur une transaction à la base de données et reconnectée lors d'une nouvelle requête-client. Ce
+                        pattern s'appelle:
+                        <emphasis>session-per-conversation</emphasis>
+                        (Littéralement: session-par- conversation) et rend superflu le rattachement des
+                        objets. Le versionnage automatique est utilisé afin d'isoler les modifications concurrentes.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>Les deux patterns
+                <emphasis>session-per-request-with- detached- objects</emphasis>
+                (session-par-requête-avec-objets- détachés) et
+                <emphasis>session-per-conversation</emphasis>
+                (session-par-conversation) ont chacun leurs avantages et désavantages qui seront exposés
+                dans ce même chapitre, dans la section au sujet du contrôle optimiste de concurrence.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-identity">
+            <title>L'identité des objets</title>
+
+            <para>Une application peut accéder à la même entité persistante de manière concurrente dans deux
+                <literal>Session</literal> s différentes. Toutefois, une instance d'une classe persistante n'est jamais partagée par deux instances
+                distinctes de la classe
+                <literal>Session</literal> . Il existe donc deux notions de l'identité d'un objet:
+            </para>
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term>Identité BD</term>
+                    <listitem>
+                        <para>
+                            <literal>foo.getId().equals( bar.getId() )</literal> </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Identité JVM</term>
+                    <listitem>
+                        <para>
+                            <literal>foo==bar</literal> </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+            <para>Ainsi, pour des objets attachés à une
+                <literal>Session</literal> <emphasis>précise</emphasis>
+                (dans la cadre d'exécution (scope) d'une instance de
+                <literal>Session</literal> ), ces deux notions d'identité sont équivalentes et garanties par Hibernate. Par contre, si une
+                application peut accéder de manière concurrente à la même entité persistante dans deux sessions
+                différentes, les deux instances seront en fait différentes (en ce qui a trait à l'identité JVM). Les
+                conflits sont résolus automatiquement par approche optimiste grâce au système de versionnage automatique
+                lorsque
+                <literal>Session.flush()</literal> ou
+                <literal>Transaction.commit()</literal> est appelé.
+            </para>
+
+            <para>Cette approche permet de reléguer à Hibernate et à la base de données sous-jacente le soin de gérer
+                les problèmes d'accès concurrents. Cette manière de faire assure également une meilleure extensibilité
+                de l'application puisque assurer l'identité JVM dans un thread ne nécessite pas de mécanismes de
+                verrouillage coûteux ou d'autres dispositifs de synchronisation. Une application n'aura jamais le besoin
+                de synchroniser des objets d'affaire tant qu'elle peut garantir qu'un seul thread aura accès à une
+                instance de
+                <literal>Session</literal> . Dans le cadre d'exécution d'un objet
+                <literal>Session</literal> , l'application peut utiliser en toute sécurité <literal>==
+            </literal> pour comparer des objets.
+        </para>
+
+        <para>
+            Une application qui utiliserait <literal>==</literal> à l'extérieur du cadre d'exécution d'une <literal>Session</literal> 
+            pourrait obtenir des résultats inattendus et causer certains effets de bords. Par exemple, si vous mettez 2
+            objets dans le même <literal>Set</literal> , ceux-ci pourraient avoir la même identité BD (i.e. ils représentent le même enregistrement), mais leur
+            identité JVM pourrait être différente (elle ne peut, par définition, pas être garantie sur deux objets
+            détachés). Le développeur doit donc redéfinir l'implémentation des méthodes <literal>equals()</literal> et <literal>hashcode()</literal> 
+            dans les classes persistantes et y adjoindre sa propre notion d'identité. Il existe toutefois une
+            restriction: Il ne faut jamais utiliser uniquement l'identifiant de la base de données dans l'implémentation
+            de l'égalité; Il faut utiliser une clé d'affaire, généralement une combinaison de plusieurs attributs
+            uniques, si possible immuables. Les identifiants de base de données vont changer si un objet transitoire
+            (transient) devient persistant. Si une instance transitoire est contenue dans un <literal>Set</literal> ,
+            changer le hashcode brisera le contrat du <literal>Set</literal> . Les attributs pour les clés d'affaire 
+            n'ont pas à être aussi stables que des clés primaires de bases de
+            données. Il suffit simplement qu'elles soient stables tant et aussi longtemps que les objets sont dans le
+            même <literal>Set</literal> . Veuillez consulter le site web Hibernate pour des discussions plus pointues à ce sujet. Notez que ce
+            concept n'est pas propre à Hibernate mais bien général à l'implémentation de l'identité et de l'égalité en
+            Java.
+        </para>
+    </sect2>
+
+
+    <sect2 id="transactions-basics-issues">
+        <title>Problèmes communs</title>
+
+        <para>Bien qu'il puisse y avoir quelques rares exceptions à cette règle, il est recommandé de ne jamais utiliser
+            les anti-patterns
+            <emphasis>session-per- user-session</emphasis>
+            et
+            <emphasis>session-per-application</emphasis>
+            . Vous trouverez ici- bas quelques problèmes que vous risquez de rencontrer si vous en faite l?utilisation.
+            (Ces problèmes pourraient quand même survenir avec des patterns recommandés) Assurez-vous de bien comprendre
+            les implications de chacun des patterns avant de prendre votre décision.
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>L'objet
+                    <literal>Session</literal> n?est pas conçu pour être utilisé par de multiples threads. En conséquence, les objets
+                    potentiellement multi-thread comme les requêtes HTTP, les EJB Session et Swing Worker, risquent de
+                    provoquer des conditions de course dans la
+                    <literal>Session</literal> si celle-ci est partagée. Dans un environnement web classique, il serait préférable de synchroniser
+                    les accès à la session http afin d?éviter qu?un usager ne recharge une page assez rapidement pour
+                    que deux requêtes s?exécutant dans des threads concurrents n?utilisent la même
+                    <literal>Session</literal> .
+                </para>
+            </listitem>
+            <listitem>
+                <para>Lorsque Hibernate lance une exception, le roll back de la transaction en cours doit être effectué
+                    et la
+                    <literal>Session</literal> doit être immédiatement fermée. (Ceci sera exploré plus tard dans le chapitre.) Si la
+                    <literal>Session</literal> est directement associée à une application, il faut arrêter l?application. Le roll back de la
+                    transaction ne remettra pas les objets dans leur état du début de la transaction. Ainsi, ceux-ci
+                    pourraient être désynchronisés d?avec les enregistrements. (Généralement, cela ne cause pas de réels
+                    problèmes puisque la plupart des exceptions sont non traitables et requièrent la reprise du
+                    processus d?affaire ayant échoué.)
+                </para>
+            </listitem>
+            <listitem>
+                <para>La
+                    <literal>Session</literal> met en mémoire cache tous les objets persistants (les objets surveillés et dont l'état est géré par
+                    Hibernate.) Si la
+                    <literal>Session</literal> est ouverte indéfiniment ou si une trop grande quantité d'objets y est chargée, l?utilisation de la
+                    mémoire peut potentiellement croître jusqu?à atteindre le maximum allouable à l?application
+                    (java.lang.OutOfMemoryError.) Une solution à ce problème est d?appeler les méthodes
+                    <literal>Session.clear()</literal> et
+                    <literal>Session.evict()</literal> pour gérer la mémoire cache de la
+                    <literal>Session</literal> . Vous pouvez également utiliser des stored procedures si vous devez lancer des traitements sur de
+                    grandes quantités d?informations. Certaines solutions sont décrites ici :
+                    <xref linkend="batch"/>
+                    . Garder une
+                    <literal>Session</literal> ouverte pour toute la durée d?une session usager augmente également considérablement le risque de
+                    travailler avec de l?information périmée.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect2>
+</sect1>
+
+<sect1 id="transactions-demarcation">
+    <title>Démarcation des transactions</title>
+
+    <para>La démarcation des transactions est importante dans le design d?une application. Aucune communication avec la
+        base de données ne peut être effectuée à l?extérieur du cadre d?une transaction. (Il semble que ce concept soit
+        mal compris par plusieurs développeurs trop habitués à utiliser le mode auto-commit.) Même si certains niveaux
+        d'isolation et certaines possibilités offertes par les bases de données permettent de l?éviter, il n'est jamais
+        désavantageux de toujours explicitement indiquer les bornes de transaction pour les opérations complexes comme
+        pour les opérations simples de lecture.</para>
+
+    <para>Une application utilisant Hibernate peut s'exécuter dans un environnement léger n?offrant pas la gestion
+        automatique des transactions (application autonome, application web simple ou applications Swing) ou dans un
+        environnement J2EE offrant des services de gestion automatique des transactions JTA. Dans un environnement
+        simple, Hibernate a généralement la responsabilité de la gestion de son propre pool de connexions à la base de
+        données. Le développeur de l'application doit manuellement délimiter les transactions. En d'autres mots, il
+        appartient au développeur de gérer les appels à
+        <literal>Transaction.begin()</literal>
+        ,
+        <literal>Transaction.commit()</literal>
+        et
+        <literal>Transaction.rollback()</literal>
+        . Un environnement transactionnel J2EE (serveur d'application J2EE) doit offrir la gestion des transactions au
+        niveau du container J2EE. Les bornes de transaction peuvent normalement être définies de manière déclarative
+        dans les descripteurs de déploiement d'EJB Session, par exemple. La gestion programmatique des transactions n'y
+        est donc pas nécessaire. Même les appels à
+        <literal>Session.flush()</literal>
+        sont faits automatiquement.
+    </para>
+
+    <para>Il peut être requis d'avoir une couche de persistance portable. Hibernate offre donc une API appelée
+        <literal>Transaction</literal>
+        qui sert d'enveloppe pour le système de transaction natif de l'environnement de déploiement. Il n'est pas
+        obligatoire d'utiliser cette API mais il est fortement conseillé de le faire, sauf lors de l'utilisation de CMT
+        Session Bean (EJB avec transactions gérées automatiquement par le container EJB).
+    </para>
+
+    <para>Il existe quatre étapes disctinctes lors de la fermeture d'une
+        <literal>Session</literal>
+    </para>
+
+    <itemizedlist spacing="compact">
+        <listitem>
+            <para>flush de la session</para>
+        </listitem>
+        <listitem>
+            <para>commit de la transaction</para>
+        </listitem>
+        <listitem>
+            <para>Fermeture de la session (Close)</para>
+        </listitem>
+        <listitem>
+            <para>Gestion des exceptions</para>
+        </listitem>
+    </itemizedlist>
+
+    <para>La synchronisation de bdd depuis la session (flush) a déjà été expliqué, nous nous attarderons maintenant à la démarcation des
+        transactions et à la gestion des exceptions dans les environnements légers et les environnements J2EE.</para>
+
+
+    <sect2 id="transactions-demarcation-nonmanaged"  revision="2">
+        <title>Environnement non managé</title>
+
+        <para>
+            Si la couche de persistance Hibernate s'exécute dans un environnement non managé, les connexions à la base de
+            données seront généralement prises en charge par le mécanisme de pool d'Hibernate. La gestion de la session
+            et de la transaction se fera donc de la manière suivante:</para>
+
+            <programlisting><![CDATA[// Non-managed environment idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+    tx = sess.beginTransaction();
+
+    // do some work
+    ...
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    if (tx != null) tx.rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+            <para>
+                Vous n'avez pas à invoquer <literal>flush()</literal> explicitement sur la <literal>Session</literal> -
+                l'appel de <literal>commit()</literal> déclenchera automatiquement la synchronisation (selon le <xref linkend="objectstate-flushing">FlushMode</xref> 
+                de la session. Un appel à <literal>close()</literal> marque la fin de la session.
+                La conséquence directe est que la connexion à la base de données sera relachée par la session.
+                Ce code est portable est fonctionne dans les environnements non managé ET les environnements JTA.
+            </para>
+
+           <para>
+                Une solution plus flexible est la gestion par contexte fourni par Hibernate que nous avons
+                déjà rencontré:
+            </para>
+
+            <programlisting><![CDATA[// Non-managed environment idiom with getCurrentSession()
+try {
+    factory.getCurrentSession().beginTransaction();
+
+    // do some work
+    ...
+
+    factory.getCurrentSession().getTransaction().commit();
+}
+catch (RuntimeException e) {
+    factory.getCurrentSession().getTransaction().rollback();
+    throw e; // or display error message
+}]]></programlisting>
+
+            <para>
+                Vous ne verrez probablement jamais ces exemples de code dans les applications;
+                les exceptions fatales (exceptions du système) ne devraient être traitées que
+                dans la couche la plus "haute". En d'autres termes, le code qui exécute les appels
+                à Hibernate (à la couche de persistance) et le code qui gère les
+                <literal>RuntimeException</literal> (qui ne peut généralement effectuer qu'un nettoyage et une sortie) 
+                sont dans des couches différentes. La gestion du contexte courant par Hibernate peut
+                simplifier notablement ce design, puisque vous devez accéder à la gestion des exceptions
+                de la <literal>SessionFactory</literal>, ce qui est décrit plus tard dans ce chapitre.
+            </para>
+
+           <para>
+                Notez que vous devriez sélectionner <literal>org.hibernate.transaction.JDBCTransactionFactory</literal>
+                (le défaut), pour le second exemple <literal>"thread"</literal> comme
+                <literal>hibernate.current_session_context_class</literal>.
+            </para>
+
+    </sect2>
+
+    <sect2 id="transactions-demarcation-jta" revision="2">
+        <title>Utilisation de JTA</title>
+
+        <para>Si votre couche de persistance s'exécute dans un serveur d'application (par exemple, derrière un EJB
+            Session Bean), toutes les datasource utilisées par Hibernate feront automatiquement partie de transactions
+            JTA globales. Hibernate propose deux stratégies pour réussir cette intégration.</para>
+
+        <para>
+            Si vous utilisez des transactions gérées par un EJB (bean managed transactions - BMT), Hibernate informera
+            le serveur d'application du début et de la fin des transactions si vous utilisez l'API <literal>Transaction</literal> . 
+            Ainsi, le code de gestion des transactions sera identique dans les deux types d'environnements.
+        </para>
+
+           <programlisting><![CDATA[// BMT idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+    tx = sess.beginTransaction();
+
+    // do some work
+    ...
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    if (tx != null) tx.rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+        <para>Ou encore, avec la gestion automatique de contexte:</para>
+
+            <programlisting><![CDATA[// BMT idiom with getCurrentSession()
+try {
+    factory.getCurrentSession().beginTransaction();
+
+    // do some work
+    ...
+
+    factory.getCurrentSession().getTransaction().commit();
+}
+catch (RuntimeException e) {
+    factory.getCurrentSession().getTransaction().rollback();
+    throw e; // or display error message
+}]]></programlisting>
+
+        <para>
+            Avec CMT, la démarcation des transactions est faite dans les descripteurs de déploiement des Beans Sessions et non
+            de manière programmmatique, ceci réduit le code:
+        </para>
+        
+        <programlisting><![CDATA[// CMT idiom
+ Session sess = factory.getCurrentSession();
+
+ // do some work
+ ...
+]]></programlisting>
+        
+        <para>
+            Dans un EJB CMT même le rollback intervient automatiquement, puisqu'une <literal>RuntimeException</literal>
+            non traitée et soulevée par une méthode d'un bean session indique au conteneur d'annuler la transaction
+            globale. <emphasis>Ceci veut donc dire que vous n'avez pas à utiliser l'API <literal>Transaction</literal> d'Hibernate
+            dans CMT.</emphasis>
+        </para>
+       
+        <para>
+            Notez que le fichier de configuration Hibernate devrait contenir les valeurs 
+            <literal>org.hibernate.transaction.JTATransactionFactory</literal> dans un environnement BMT ou 
+            <literal>org.hibernate.transaction.CMTTransactionFactory</literal> dans un environnement CMT là  où vous
+            configurez votre transaction factory Hibernate. 
+            N'oubliez pas non plus de spécifier le paramètre <literal>org.hibernate.transaction.manager_lookup_class</literal> .
+            De plus, assurez vous de fixez votre <literal>hibernate.current_session_context_class</literal> soit à <literal>"jta"</literal>
+            ou de ne pas le configurer (compatibilité avec les versions précédentes).
+        </para>
+
+        <para>
+            La méthode <literal>getCurrentSession()</literal> a un inconvénient dans les environnement JTA.
+            Il y a une astuce qui est d'utiliser un mode de libération de connexion <literal>after_statement</literal> ,
+            qui est alors utilisé par défaut. Du à une étrange limitation de la spec JTA, il n'est pas possible
+            pour Hibernate de nettoyer et ferme automatiquement un <literal>ScrollableResults</literal> ouvert
+            ou une instance d'<literal>Iterator</literal> retournés <literal>scroll()</literal> ou
+            <literal>iterate()</literal>. Vous <emphasis>devez</emphasis> libérer le curseur base de données
+            sous jacent ou invoquer <literal>Hibernate.close(Iterator)</literal> explicitement depuis un
+            bloc <literal>finally</literal>. (Bien sur, la plupart des applications peuvent éviter
+            d'uiliser <literal>scroll()</literal> ou <literal>iterate()</literal> dans un code CMT.)
+        </para>
+
+    </sect2>
+
+    <sect2 id="transactions-demarcation-exceptions">
+        <title>Gestion des exceptions</title>
+
+        <para>
+            Si une <literal>Session</literal> lance une exception (incluant les exceptions du type <literal>SQLException</literal> 
+            ou d'un sous-type), vous devez immédiatement faire le rollback de la transaction, appeler <literal>Session.close()</literal> 
+            et relâcher les références sur l'objet <literal>Session</literal> . La <literal>Session</literal> contient des méthodes 
+            pouvant la mettre dans un état inutilisable. Vous devez considérer qu'<emphasis>aucune</emphasis>
+            exception lancée par Hibernate n'est traitable. Assurez-vous de fermer la session en faisant l'appel à 
+            <literal>close()</literal> dans un bloc <literal>finally</literal> .
+        </para>
+
+        <para>
+            L'exception <literal>HibernateException</literal> , qui englobe la plupart des exceptions pouvant survenir dans la 
+            couche de persistance Hibernate, est une exception non vérifiée (Ceci n'était pas le cas dans certaines versions antérieures de Hibernate.) Il est de
+            notre avis que nous ne devrions pas forcer un développeur à gérer une exception qu'il ne peut de toute façon
+            pas traiter dans une couche technique. Dans la plupart des applications, les exceptions non vérifiées et les
+            exceptions fatales sont gérées en amont du processus (dans les couches hautes) et un message d'erreur est
+            alors affiché à l'usager (ou un traitement alternatif est invoqué.) Veuillez noter qu'Hibernate peut
+            également lancer des exceptions non vérifiées d'un autre type que <literal>HibernateException</literal> . Celles-ci sont 
+            également non traitables et vous devez les traiter comme telles.
+        </para>
+
+        <para>
+            Hibernate englobe les <literal>SQLException</literal> s lancées lors des interactions directes avec la base de données 
+            dans des exceptions de type: <literal>JDBCException</literal> . En fait, Hibernate essaiera de convertir l'exception dans 
+            un sous-type plus significatif de <literal>JDBCException</literal> . L'exception <literal>SQLException</literal> sous-jacente 
+            est toujours disponible via la méthode <literal>JDBCException.getCause()</literal> . Cette conversion est faite par un objet 
+            de type <literal>SQLExceptionConverter</literal> , qui est rattaché à l'objet <literal>SessionFactory</literal> . 
+            Par défaut, le <literal>SQLExceptionConverter</literal> est associé au dialecte de BD configuré dans Hibernate. Toutefois, 
+            il est possible de fournir sa propre implémentation de l'interface. (Veuillez vous référer à la javadoc sur la classe 
+            <literal>SQLExceptionConverterFactory</literal> pour plus de détails. Les sous-types standard de <literal>JDBCException</literal> sont:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>JDBCConnectionException</literal> - Indique une erreur de communication avec la couche JDBC sous-jacente.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>SQLGrammarException</literal> - Indique un problème de grammaire ou de syntaxe avec la requête SQL envoyée.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ConstraintViolationException</literal> - Indique une violation de contrainte d'intégrité.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockAcquisitionException</literal> - Indique une erreur de verrouillage lors de l'éxécution de la requête.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>GenericJDBCException</literal> - Indique une erreur générique JDBC d'une autre catégorie.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect2>
+
+    <sect2 id="transactions-demarcation-timeout">
+        <title>Timeout de transaction</title>
+
+        <para>L'un des avantages fournis par les environnements transactionnels JTA (tels les containers EJB) est la
+            gestion du timeout de transaction. La gestion des dépassements de temps de transaction vise à s'assurer
+            qu'une transaction agissant incorrectement ne viendra pas bloquer indéfiniment les ressources de
+            l'application. Hibernate ne peut fournir cette fonctionnalité dans un environnement transactionnel non-JTA.
+            Par contre, Hibernate gère les opérations d'accès aux données en allouant un temps maximal aux requêtes pour
+            s'exécuter. Ainsi, une requête créant de l'inter blocage ou retournant de très grandes quantités
+            d'information pourrait être interrompue. Dans un environnement transactionnel JTA, Hibernate peut déléguer
+            au gestionnaire de transaction le soin de gérer les dépassements de temps. Cette fonctionnalité est
+            abstraite par l'objet <literal>Transaction</literal> .
+        </para>
+
+        <programlisting><![CDATA[
+        Session sess = factory.openSession();
+        try {
+            //mettre le timeout à 3 secondes.
+            sess.getTransaction().setTimeout(3);
+            sess.getTransaction().begin();
+
+            // Effectuer le travail ...
+
+            sess.getTransaction().commit()
+        }
+        catch (RuntimeException e) {
+            if ( sess.getTransaction().isActive() ) {
+                sess.getTransaction().rollback();
+            }
+            throw e;
+            // ou afficher le message d'erreur.
+        }
+        finally {
+            sess.close();
+        }]]></programlisting>
+
+
+        <para>
+            Notez que <literal>setTimeout()</literal> ne peut pas être appelé d'un EJB CMT, puisque le timeout 
+            des transaction doit être spécifié de manière déclarative.
+        </para>
+
+    </sect2>
+
+</sect1>
+
+<sect1 id="transactions-optimistic">
+    <title>Contrôle de consurrence optimiste</title>
+
+    <para>La gestion optimiste des accès concurrents avec versionnage est la seule approche pouvant garantir
+        l'extensibilité des applications à haut niveau de charge. Le système de versionnage utilise des numéros de
+        version ou l'horodatage pour détecter les mises à jour causant des conflits avec d'autres actualisations
+        antérieures. Hibernate propose trois approches pour l'écriture de code applicatif utilisant la gestion optimiste
+        d'accès concurrents. Le cas d'utilisation décrit plus bas fait mention de conversation,
+        mais le versionnage peut également améliorer la qualité d'une application en prévenant la perte de mises à
+        jour.</para>
+
+    <sect2 id="transactions-optimistic-manual">
+        <title>Gestion du versionnage au niveau applicatif</title>
+
+        <para>Dans cet exemple d'implémentation utilisant peu les fonctionnalités d'Hibernate, chaque interaction avec
+            la base de données se fait en utilisant une nouvelle <literal>Session</literal> et le développeur doit recharger 
+            les données persistantes à partir de la BD avant de les manipuler. Cette
+            implémentation force l'application à vérifier la version des objets afin de maintenir l'isolation
+            transactionnelle. Cette approche, semblable à celle retrouvée pour les EJB, est la moins efficace de celles
+            présentées dans ce chapitre.
+        </para>
+
+        <programlisting>
+            <![CDATA[// foo est une instance chargée antérieurement par une autre
+            Session session = factory.openSession();
+            Transaction t = session.beginTransaction();
+
+            int oldVersion = foo.getVersion();
+            session.load( foo, foo.getKey() ); // Charger l'état courant
+
+            if ( oldVersion!=foo.getVersion )
+                throw new StaleObjectStateException();
+
+            foo.setProperty("bar");
+            t.commit();
+            session.close();]]></programlisting>
+
+        <para>Le mapping de la propriété <literal>version</literal> est fait via <literal>&lt;version&gt;</literal> et 
+        Hibernate l'incrémentera automatiquement à chaque flush() si l'entité doit être mise à jour.
+        </para>
+
+
+        <para>Bien sûr, si votre application ne fait pas face à beaucoup d'accès concurrents et ne nécessite pas
+            l'utilisation du versionnage, cette approche peut également être utilisée, il n'y a qu'à ignorer le code
+            relié au versionnage. Dans ce cas, la stratégie du
+            <emphasis>last commit wins</emphasis>
+            (littéralement: le dernier commit l'emporte) sera utilisée pour les conversations (longues transactions applicatives).
+            Gardez à l'esprit que cette approche pourrait rendre perplexe les utilisateurs de l'application car ils
+            pourraient perdre des données mises à jour sans qu'aucun message d'erreur ne leur soit présenté et sans
+            avoir la possibilité de fusionner les données.
+        </para>
+
+        <para>Il est clair que la gestion manuelle de la vérification du versionnage des objets ne peut être effectuée
+            que dans certains cas triviaux et que cette approche n'est pas valable pour la plupart des applications. De
+            manière générale, les applications ne cherchent pas à actualiser de simples objets sans relations, elles le
+            font généralement pour de larges graphes d'objets. Pour toute application utilisant le paradigme des conversations
+             ou des objets détachés, Hibernate peut gérer automatiquement la vérification des versions
+            d'objets.</para>
+
+    </sect2>
+
+    <sect2 id="transactions-optimistic-longsession">
+        <title>Les sessions longues et le versionnage automatique.</title>
+
+        <para>Dans ce scénario, une seule instance de <literal>Session</literal> et des objets persistants est utilisée 
+            pour toute l'application. Hibernate vérifie la version des objets
+            persistants avant d'effectuer le flush() et lance une exception si une modification concurrente est
+            détectée. Il appartient alors au développeur de gérer l'exception. Les traitements alternatifs généralement
+            proposés sont alors de permettre à l'usager de faire la fusion des données ou de lui offrir de recommencer
+            son travail à partie des données les plus récentes dans la BD.
+        </para>
+
+        <para>Il est à noter que lorsqu'une application est en attente d'une action de la part de l?usager, La <literal>Session</literal> 
+            n'est pas connectée à la couche JDBC sous-jacente. C'est la manière la plus efficace de gérer les accès à la
+            base de données. L'application ne devrait pas se préoccuper du versionnage des objets, de la réassociation
+            des objets détachés, ni du rechargement de tous les objets à chaque transaction.
+        </para>
+
+        <programlisting>
+            <![CDATA[// foo est une instance chargée antérieurement par une autre session
+
+            session.reconnect();// Obtention d'une nouvelle connexion JDBC
+            Transaction t = session.beginTransaction();
+            foo.setProperty("bar");
+            t.commit(); //Terminer la transaction, propager les changements et vérifier les versions.
+            session.disconnect(); // Retourner la connexion JDBC
+            ]]></programlisting>
+
+
+        <para>L'objet <literal>foo</literal> sait quel objet <literal>Session</literal> l'a chargé. <literal>Session.reconnect()</literal> 
+            obtient une nouvelle connexion (celle-ci peut être également fournie) et permet à la session de continuer
+            son travail. La méthode <literal>Session.disconnect()</literal> déconnecte la session de la connexion JDBC et 
+            retourne celle-ci au pool de connexion (à moins que vous ne
+            lui ayez fourni vous même la connexion.) Après la reconnexion, afin de forcer la vérification du versionnage
+            de certaines entités que vous ne cherchez pas à actualiser, vous pouvez faire un appel à <literal>Session.lock()</literal> 
+            en mode <literal>LockMode.READ</literal> pour tout objet ayant pu être modifié par une autre transaction. Il n'est pas nécessaire de verrouiller les
+            données que vous désirez mettre à jour.
+        </para>
+
+        <para>Si des appels implicites aux méthodes <literal>disconnect()</literal> et <literal>reconnect()</literal> sont trop 
+        coûteux, vous pouvez les éviter en utilisant <literal>hibernate.connection.release_mode</literal> .
+        </para>
+
+        <para>Ce pattern peut présenter des problèmes si la <literal>Session</literal> est trop volumineuse pour être 
+            stockée entre les actions de l'usager. Plus spécifiquement, une session <literal>HttpSession</literal> se doit 
+            d'être la plus petite possible. Puisque la <literal>Session</literal> joue obligatoirement le rôle de mémoire 
+            cache de premier niveau et contient à ce titre tous les objets
+            chargés, il est préférable de n'utiliser cette stratégie que pour quelques cycles de requêtes car les objets
+            risquent d'y être rapidement périmés.
+        </para>
+
+        <para>Notez que la <literal>Session</literal> déconnectée devrait être conservée près de la couche de persistance. Autrement dit, utilisez un EJB stateful
+            pour conserver la <literal>Session</literal> et évitez de la sérialiser et de la transférer à la couche de présentation (i.e. Il est préférable de ne pas
+            la conserver dans la session <literal>HttpSession</literal> .)
+        </para>
+
+    </sect2>
+
+    <sect2 id="transactions-optimistic-detached">
+        <title>Les objets détachés et le versionnage automatique</title>
+
+        <para>Chaque interaction avec le système de persistance se fait via une nouvelle <literal>Session</literal> . 
+            Toutefois, les mêmes instances d'objets persistants sont réutilisées pour chacune de ces interactions.
+            L'application doit pouvoir manipuler l'état des instances détachées ayant été chargées antérieurement via
+            une autre session. Pour ce faire, ces objets persistants doivent être rattachés à la <literal>Session</literal> 
+            courante en utilisant <literal>Session.update()</literal> , <literal>Session.saveOrUpdate()</literal> , ou <literal>Session.merge()</literal> .
+        </para>
+
+        <programlisting>
+            <![CDATA[// foo est une instance chargée antérieurement par une autre session
+
+            foo.setProperty("bar");
+            session = factory.openSession();
+            Transaction t = session.beginTransaction();
+            session.saveOrUpdate(foo);  //Utiliser merge() si "foo" pourrait avoir été chargé précédement
+            t.commit();
+            session.close();]]> </programlisting>
+
+
+        <para>Encore une fois, Hibernate vérifiera la version des instances devant être actualisées durant le flush().
+            Une exception sera lancée si des conflits sont détectés.</para>
+
+        <para>Vous pouvez également utiliser <literal>lock()</literal> au lieu de <literal>update()</literal> et 
+            utiliser le mode <literal>LockMode.READ</literal> (qui lancera une vérification de version, en ignorant tous les niveaux de mémoire cache) si vous êtes
+            certain que l'objet n'a pas été modifié.
+        </para>
+
+    </sect2>
+
+    <sect2 id="transactions-optimistic-customizing">
+        <title>Personnaliser le versionnage automatique</title>
+
+        <para>Vous pouvez désactiver l'incrémentation automatique du numéro de version de certains attributs et
+            collections en mettant la valeur du paramètre de mapping <literal>optimistic-lock</literal> à
+            false. Hibernate cessera ainsi d'incrémenter leur numéro de version s'ils sont mis à jour.
+        </para>
+
+        <para>Certaines entreprises possèdent de vieux systèmes dont les schémas de bases de données sont statiques et
+            ne peuvent être modifiés. Il existe aussi des cas où plusieurs applications doivent accéder à la même base
+            de données, mais certaines d'entre elles ne peuvent gérer les numéros de version ou les champs horodatés.
+            Dans les deux cas, le versionnage ne peut être implanté par le rajout d'une colonne dans la base de données.
+            Afin de forcer la vérification de version dans un système sans en faire le mapping, mais en forçant une
+            comparaison des états de tous les attributs d'une entité, vous pouvez utiliser l'attribut <literal>optimistic- lock="all"</literal> 
+            sous l'élément <literal>&lt;class&gt;</literal> . Veuillez noter que cette manière de gérer le versionnage ne peut être utilisée que si l'application
+            utilises de longues sessions, lui permettant de comparer l'ancien état et le nouvel état d'une entité.
+            L'utilisation d'un pattern <literal>session-per-request-with-detached- objects</literal> devient alors impossible.
+        </para>
+
+        <para>Il peut être souhaitable de permettre les modifications concurrentes lorsque des champs distincts sont
+            modifiés. En mettant la propriété <literal>optimistic-lock="dirty"</literal> dans l'élément <literal>&lt;class&gt;</literal> , 
+            Hibernate ne fera la comparaison que des champs devant être actualisés lors du flush().
+        </para>
+
+        <para>Dans les deux cas: en utilisant une colonne de version/horodatée ou via la comparaison de l'état complet
+            de l'objet ou de ses champs modifiés, Hibernate ne créera qu'une seule commande d'UPDATE par entité avec la
+            clause WHERE appropriée pour mettre à jour l'entité
+            <emphasis>ET</emphasis>
+            en vérifier la version. Si vous utilisez la persistance transitive pour propager l'évènement de rattachement
+            à des entités associées, il est possible qu'Hibernate génère des commandes d'UPDATE inutiles. Ceci n'est
+            généralement pas un problème, mais certains déclencheurs
+            <emphasis>on update</emphasis>
+            dans la base de données pourraient être activés même si aucun changement n'était réellement persisté sur des
+            objets associés. Vous pouvez personnaliser ce comportement en indiquant <literal>select-before- update="true"</literal>
+            dans l'élément de mapping <literal>&lt;class&gt;</literal> . Ceci forcera Hibernate à faire le SELECT de l'instance 
+            afin de s'assurer que l'entité doit réellement être
+            actualisée avant de lancer la commande d'UPDATE.
+        </para>
+
+    </sect2>
+
+</sect1>
+
+<sect1 id="transactions-locking">
+    <title>Verouillage pessimiste</title>
+
+    <para>Il n'est nécessaire de s'attarder à la stratégie de verrouillage des entités dans une application utilisant
+        Hibernate. Il est généralement suffisant de définir le niveau d'isolation pour les connexions JDBC et de laisser
+        ensuite la base de donnée effectuer son travail. Toutefois, certains utilisateurs avancés peuvent vouloir
+        obtenir un verrouillage pessimiste exclusif sur un enregistrement et le réobtenir au lancement d'une nouvelle
+        transaction.</para>
+
+    <para>Hibernate utilisera toujours le mécanisme de verrouillage de la base de données et ne verrouillera jamais les
+        objets en mémoire!</para>
+
+    <para>La classe
+        <literal>LockMode</literal>
+        définit les différents niveaux de verrouillage pouvant être obtenus par Hibernate. Le verrouillage est obtenu
+        par les mécanismes suivants:
+    </para>
+
+    <itemizedlist spacing="compact">
+        <listitem>
+            <para>
+                <literal>LockMode.WRITE</literal> est obtenu automatiquement quand Hibernate actualise ou insert un enregistrement.
+            </para>
+        </listitem>
+        <listitem>
+            <para>
+                <literal>LockMode.UPGRADE</literal> peut être obtenu de manière explicite via la requête en utilisant
+                <literal>SELECT ... FOR UPDATE</literal> sur une base de données supportant cette syntaxe.
+            </para>
+        </listitem>
+        <listitem>
+            <para>
+                <literal>LockMode.UPGRADE_NOWAIT</literal> peut être obtenu de manière explicite en utilisant
+                <literal>SELECT ... FOR UPDATE NOWAIT</literal> sur Oracle.
+            </para>
+        </listitem>
+        <listitem>
+            <para>
+                <literal>LockMode.READ</literal> est obtenu automatiquement quand Hibernate lit des données dans un contexte d'isolation
+                <literal>Repeatable Read</literal> ou
+                <literal>Serializable</literal> . Peut être réobtenu explicitement via une requête.
+            </para>
+        </listitem>
+        <listitem>
+            <para>
+                <literal>LockMode.NONE</literal> représente l'absence de verouillage. Tous les objets migrent vers ce mode a la fin d'une
+                <literal>Transaction</literal> . Les objets associés à une session via un appel à
+                <literal>saveOrUpdate()</literal> commencent également leur cycle de vie dans cet état.
+            </para>
+        </listitem>
+    </itemizedlist>
+
+    <para>Les niveaux de verrouillage peuvent être explicitement obtenus de l'une des manières suivantes:</para>
+
+    <itemizedlist spacing="compact">
+        <listitem>
+            <para>Un appel à
+                <literal>Session.load()</literal> , en spécifiant un niveau verrouillage
+                <literal>LockMode</literal> .
+            </para>
+        </listitem>
+        <listitem>
+            <para>Un appel à
+                <literal>Session.lock()</literal> .
+            </para>
+        </listitem>
+        <listitem>
+            <para>Une appel à
+                <literal>Query.setLockMode()</literal> .
+            </para>
+        </listitem>
+    </itemizedlist>
+
+    <para>Si
+        <literal>Session.load()</literal>
+        est appelé avec le paramètre de niveau de verouillage
+        <literal>UPGRADE</literal>
+        ou
+        <literal>UPGRADE_NOWAIT</literal>
+        et que l'objet demandé n'est pas présent dans la session, celui-ci sera chargé à l'aide d'une requête
+        <literal>SELECT ... FOR UPDATE</literal>
+        . Si la méthode
+        <literal>load()</literal>
+        est appelée pour un objet déjà en session avec un verrouillage moindre que celui demandé, Hibernate appellera la
+        méthode
+        <literal>lock()</literal>
+        pour cet objet.
+    </para>
+
+    <para>
+        <literal>Session.lock()</literal>
+        effectue une vérification de version si le niveau de verrouillage est
+        <literal>READ</literal>
+        ,
+        <literal>UPGRADE</literal>
+        ou
+        <literal>UPGRADE_NOWAIT</literal>
+        . (Dans le cas des niveaux
+        <literal>UPGRADE</literal>
+        ou
+        <literal>UPGRADE_NOWAIT</literal>
+        , une requête
+        <literal>SELECT ... FOR UPDATE</literal>
+        sera utilisée.)
+    </para>
+
+    <para>Si une base de données ne supporte pas le niveau de verrouillage demandé, Hibernate utilisera un niveau
+        alternatif convenable au lieux de lancer une exception. Ceci assurera la portabilité de votre
+        application.</para>
+</sect1> 
+
+    <sect1 id="transactions-connection-release">
+        <title>Mode de libération de Connection</title>
+
+        <para>
+            Le comportement original (2.x) d'Hibernate pour la gestion des connexions JDBC
+            était que la <literal>Session</literal> obtenait une connexion dès qu'elle en avait
+            besoin et la libérait une fois la session fermée.
+            Hibernate 3 a introduit les modes de libération de connexion pour indiquer à la session
+            comment gérer les transactions JDBC. Notez que la discussion suivante n'est pertinente 
+            que pour des connexions fournies par un <literal>ConnectionProvider</literal>, celles gérées 
+            par l'utilisateur sont en dehors du scope de cette discussion. Les différents modes
+            sont définies par <literal>org.hibernate.ConnectionReleaseMode</literal>:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>ON_CLOSE</literal> - est essentiellement le comportement passé.
+                    La session Hibernate obtient une connexion lorsqu'elle en a besoin et la garde
+                    jusqu'à ce que la session se ferme.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>AFTER_TRANSACTION</literal> - indique de relacher la connexion après qu'une
+                    <literal>org.hibernate.Transaction</literal> se soit achevée.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>AFTER_STATEMENT</literal> (aussi appelé libération brutale) - indique de relacher
+                    les connexions après chaque exécution d'un statement. Ce relachement aggressif est annulé
+                    si ce statement laisse des ressources associées à une session donnée ouvertes, actuellement
+                    ceci n'arrive que lors de l'utilisation de <literal>org.hibernate.ScrollableResults</literal>.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Le paramètre de configuration <literal>hibernate.connection.release_mode</literal> est utilisé
+            pour spécifier quel mode de libération doit être utiliser. Les valeurs possibles sont:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>auto</literal> (valeur par défaut) - ce choix délègue le choix de libération
+                    à la méthode <literal>org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode()</literal>
+                    Pour la JTATransactionFactory, elle retourne ConnectionReleaseMode.AFTER_STATEMENT; pour
+                    JDBCTransactionFactory, elle retourne ConnectionReleaseMode.AFTER_TRANSACTION. C'est rarement
+                    une bonne idée de changer ce comportement par défaut puisque les erreurs soulevées par ce
+                    paramétrage tend à prouver une erreur dans le code de l'utilisateur.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>on_close</literal> - indique d'utiliser ConnectionReleaseMode.ON_CLOSE.  Ce paramétrage
+                    existe pour garantir la compatibilité avec les versions précédentes, mais ne devrait plus être utilisé.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>after_transaction</literal> - indique d'utiliser ConnectionReleaseMode.AFTER_TRANSACTION.
+                    Ne devrait pas être utilisé dans les environnements JTA. Notez aussi qu'avec 
+                    ConnectionReleaseMode.AFTER_TRANSACTION, si une session est considérée comme étant en mode auto-commit
+                    les connexions seront relachées comme si le mode était AFTER_STATEMENT.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>after_statement</literal> - indique d'utiliser ConnectionReleaseMode.AFTER_STATEMENT.
+                    Additonnellement, le <literal>ConnectionProvider</literal> utilisé est consulté pour savoir s'il supporte
+                    ce paramétrage (<literal>supportsAggressiveRelease()</literal>). Si ce n'est pas le cas, le mode de
+                    libération est ré initialisé à ConnectionReleaseMode.AFTER_TRANSACTION.  
+                    Ce paramétrage n'est sûr que dans les environnements où il est possible d'obtenir à nouveau
+                    la même connexion JDBC à chaque fois que l'on fait un appel de <literal>ConnectionProvider.getConnection()</literal> 
+                    ou dans les envrionnements auto-commit où il n'est pas important d'obtenir plusieurs fois la 
+                    même connexion.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/tutorial.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/tutorial.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/tutorial.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1575 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="tutorial">
+    <title>Introduction à Hibernate</title>
+
+    <sect1 id="tutorial-intro" revision="1">
+        <title>Préface</title>
+
+        <para>
+            Ce chapitre est un didacticiel introductif destiné aux nouveaux utilisateurs
+            d'Hibernate. Nous commençons avec une simple application en ligne de commande
+            utilisant une base de données en mémoire, et la développons en étapes faciles
+            à comprendre.
+        </para>
+
+        <para>
+            Ce didacticiel est destiné aux nouveaux utilisateurs d'Hibernate mais requiert
+            des connaissances Java et SQL. Il est basé sur un didacticiel de Michael Gloegl,
+            les bibliothèques tierces que nous nommons sont pour les JDK 1.4 et 5.0. Vous
+            pourriez avoir besoin d'autres bibliothèques pour le JDK 1.3.
+        </para>
+        
+        <para>
+            Le code source de ce tutoriel est inclus dans la distribution dans le répertoire
+            <literal>doc/reference/tutorial/</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="tutorial-firstapp" revision="1">
+        <title>Partie 1 - Première application Hibernate</title>
+
+        <para>
+            D'abord, nous créerons une simple application Hibernate en console. Nous utilisons
+            une base de données en mémoire (HSQL DB), donc nous n'avons pas à installer de
+            serveur de base de données.
+        </para>
+
+        <para>
+            Supposons que nous ayons besoin d'une petite application de base de données qui
+            puisse stocker des événements que nous voulons suivre, et des informations à propos
+            des hôtes de ces événements.
+        </para>
+
+        <para>
+            La première chose que nous faisons est de configurer notre répertoire de
+            développement et de mettre toutes les bibliothèques dont nous avons besoin dedans.
+            Téléchargez la distribution Hibernate à partir du site web d'Hibernate.
+            Extrayez le paquet et placez toutes les bibliothèques requises trouvées dans
+            <literal>/lib</literal> dans le répertoire <literal>/lib</literal> de votre
+            nouveau répertoire de travail. Il devrait ressembler à ça :
+        </para>
+
+        <programlisting><![CDATA[.
++lib
+  antlr.jar
+  cglib-full.jar
+  asm.jar
+  asm-attrs.jars
+  commons-collections.jar
+  commons-logging.jar
+  ehcache.jar
+  hibernate3.jar
+  jta.jar
+  dom4j.jar
+  log4j.jar ]]></programlisting>
+
+        <para>
+            Ceci est l'ensemble minimum de bibliothèques requises (notez que nous avons aussi
+            copié hibernate3.jar, l'archive principale) pour Hibernate. Lisez le fichier
+            <literal>README.txt</literal> dans le répertoire <literal>lib/</literal> de la
+            distribution Hibernate pour plus d'informations à propos des biliothèques tierces
+            requises et optionnelles. (En fait, log4j n'est pas requis mais préféré par beaucoup
+            de développeurs.)
+        </para>
+
+        <para>
+            Ensuite, nous créons une classe qui réprésente l'événement que nous voulons
+            stocker dans notre base de données.
+        </para>
+
+        <sect2 id="tutorial-firstapp-firstclass" revision="1">
+            <title>La première classe</title>
+
+            <para>
+                Notre première classe persistante est une simple classe JavaBean avec
+                quelques propriétés :
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+import java.util.Date;
+
+public class Event {
+    private Long id;
+
+    private String title;
+    private Date date;
+
+    public Event() {}
+
+    public Long getId() {
+        return id;
+    }
+
+    private void setId(Long id) {
+        this.id = id;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+}]]></programlisting>
+
+            <para>
+                Vous pouvez voir que cette classe utilise les conventions de nommage standard JavaBean
+                pour les méthodes getter/setter des propriétés, ainsi qu'une visibilité privée
+                pour les champs. Ceci est la conception recommandée - mais pas obligatoire. Hibernate peut
+                aussi accéder aux champs directement, le bénéfice des méthodes d'accès est la robustesse
+                pour la refonte de code. Le constructeur sans argument est requis pour instancier
+                un objet de cette classe via reflexion.
+            </para>
+
+            <para>
+                La propriété <literal>id</literal> contient la valeur d'un identifiant unique pour un
+                événement particulier. Toutes les classes d'entités persistantes (ainsi que les classes
+                dépendantes de moindre importance) auront besoin d'une telle propriété identifiante si nous
+                voulons utiliser l'ensemble complet des fonctionnalités d'Hibernate. En fait, la plupart des
+                applications (surtout les applications web) ont besoin de distinguer des objets par des
+                identifiants, donc vous devriez considérer ça comme une fonctionnalité plutôt que comme une
+                limitation. Cependant, nous ne manipulons généralement pas l'identité d'un objet, dorénavant
+                la méthode setter devrait être privée. Seul Hibernate assignera les identifiants lorsqu'un
+                objet est sauvegardé. Vous pouvez voir qu'Hibernate peut accéder aux méthodes publiques,
+                privées et protégées, ainsi qu'aux champs (publics, privés, protégés) directement. Le choix
+                vous est laissé, et vous pouvez l'ajuster à la conception de votre application.
+            </para>
+
+            <para>
+                Le constructeur sans argument est requis pour toutes les classes persistantes ;
+                Hibernate doit créer des objets pour vous en utilisant la réflexion Java. Le
+                constructeur peut être privé, cependant, la visibilité du paquet est requise
+                pour la génération de proxy à l'exécution et une récupération des données efficaces
+                sans instrumentation du bytecode.
+            </para>
+
+            <para>
+                Placez ce fichier source Java dans un répertoire appelé <literal>src</literal>
+                dans le dossier de développement. Ce répertoire devrait maintenant ressembler
+                à ça :
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate et bibliothèques tierces>
++src
+  +events
+    Event.java]]></programlisting>
+
+
+            <para>
+                Dans la prochaine étape, nous informons Hibernate de cette classe persistante.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-mapping" revision="1">
+            <title>Le fichier de mapping</title>
+
+            <para>
+                Hibernate a besoin de savoir comment charger et stocker des objets d'une classe
+                persistante. C'est là qu'intervient le fichier de mapping Hibernate. Le fichier
+                de mapping indique à Hibernate à quelle table dans la base de données il doit
+                accéder, et quelles colonnes de cette table il devra utiliser.
+            </para>
+
+            <para>
+                La structure basique de ce fichier de mapping ressemble à ça :
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+[...]
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Notez que la DTD Hibernate est très sophistiquée. Vous pouvez l'utiliser
+                pour l'auto-complétement des éléments et des attributs de mapping XML dans
+                votre éditeur ou votre IDE. Vous devriez aussi ouvrir le fichier DTD dans
+                votre éditeur de texte - c'est le moyen le plus facile d'obtenir une vue
+                d'ensemble de tous les éléments et attributs, et de voir les valeurs par
+                défaut, ainsi que quelques commentaires. Notez qu'Hibernate ne chargera
+                pas le fichier DTD à partir du web, mais regardera d'abord dans le classpath
+                de l'application. Le fichier DTD est inclus dans <literal>hibernate3.jar</literal>
+                ainsi que dans le répertoire <literal>src</literal> de la distribution
+                Hibernate.
+            </para>
+
+            <para>
+                Nous omettrons la déclaration de la DTD dans les exemples futurs pour
+                raccourcir le code. Bien sûr il n'est pas optionnel.
+            </para>
+
+            <para>
+                Entre les deux balises <literal>hibernate-mapping</literal>, incluez un
+                élément <literal>class</literal>. Toutes les classes d'entités persistantes
+                (encore une fois, il pourrait y avoir des classes dépendantes plus tard,
+                qui ne sont pas des entités mère) ont besoin d'un mapping vers une table
+                de la base de données SQL :
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Event" table="EVENTS">
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Plus loin, nous disons à Hibernate comment persister et charger un objet de la classe
+                <literal>Event</literal> dans la table <literal>EVENTS</literal>, chaque instance est
+                représentée par une ligne dans cette table. Maintenant nous continuons avec le mapping de
+                la propriété de l'identifiant unique vers la clef primaire de la table. De plus, comme
+                nous ne voulons pas nous occuper de la gestion de cet identifiant, nous utilisons une
+                stratégie de génération d'identifiant d'Hibernate pour la colonne de la clef primaire
+                subrogée :
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="increment"/>
+        </id>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                L'élément <literal>id</literal> est la déclaration de la propriété de l'identifiant,
+                <literal>name="id"</literal> déclare le nom de la propriété Java - Hibernate
+                utilisera les méthodes getter et setter pour accéder à la propriété. L'attribut
+                <literal>column</literal> indique à Hibernate quelle colonne de la table
+                <literal>EVENTS</literal> nous utilisons pour cette clef primaire. L'élément
+                <literal>generator</literal> imbriqué spécifie la stratégie de génération de
+                l'identifiant, dans ce cas nous avons utilisé <literal>increment</literal>,
+                laquelle est une méthode très simple utile surtout pour les tests
+                (et didacticiels). Hibernate supporte aussi les identifiants générés par les
+                bases de données, globalement uniques, ainsi que les identifiants assignés par
+                l'application (ou n'importe quelle stratégie que vous avez écrit en extension).
+            </para>
+
+            <para>
+                Finalement nous incluons des déclarations pour les propriétés persistantes de la classe
+                dans le fichier de mapping. Par défaut, aucune propriété de la classe n'est considérée
+                comme persistante :
+            </para>
+
+            <programlisting><![CDATA[
+<hibernate-mapping>
+
+    <class name="Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="increment"/>
+        </id>
+        <property name="date" type="timestamp" column="EVENT_DATE"/>
+        <property name="title"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Comme avec l'élément <literal>id</literal>, l'attribut <literal>name</literal>
+                de l'élément <literal>property</literal> indique à Hibernate quels getters/setters
+                utiliser.
+            </para>
+
+            <para>
+                Pourquoi le mapping de la propriété <literal>date</literal> inclut
+                l'attribut <literal>column</literal>, mais pas <literal>title</literal> ?
+                Sans l'attribut <literal>column</literal> Hibernate utilise par défaut
+                le nom de la propriété comme nom de colonne. Ca fonctionne bien pour
+                <literal>title</literal>. Cependant, <literal>date</literal> est un mot clef
+                réservé dans la plupart des bases de données, donc nous utilisons un nom
+                différent pour le mapping.
+            </para>
+
+            <para>
+                La prochaine chose intéressante est que le mapping de <literal>title</literal>
+                manque aussi d'un attribut <literal>type</literal>. Les types que nous déclarons
+                et utilisons dans les fichiers de mapping ne sont pas, comme vous pourriez vous
+                y attendre, des types de données Java. Ce ne sont pas, non plus, des types de
+                base de données SQL. Ces types sont donc appelés des <emphasis>types de mapping
+                Hibernate</emphasis>, des convertisseurs qui peuvent traduire des types Java en
+                types SQL et vice versa. De plus, Hibernate tentera de déterminer la bonne conversion
+                et le type de mapping lui-même si l'attribut <literal>type</literal> n'est pas
+                présent dans le mapping. Dans certains cas, cette détection automatique (utilisant
+                la réflexion sur la classe Java) pourrait ne pas donner la valeur attendue ou
+                dont vous avez besoin. C'est le cas avec la propriété <literal>date</literal>.
+                Hibernate ne peut pas savoir si la propriété "mappera" une colonne SQL de type
+                <literal>date</literal>, <literal>timestamp</literal> ou <literal>time</literal>.
+                Nous déclarons que nous voulons conserver des informations avec une date complète
+                et l'heure en mappant la propriété avec un <literal>timestamp</literal>.
+            </para>
+
+            <para>
+                Ce fichier de mapping devrait être sauvegardé en tant que <literal>Event.hbm.xml</literal>,
+                juste dans le répertoire à côté du fichier source de la classe Java <literal>Event</literal>.
+                Le nommage des fichiers de mapping peut être arbitraire, cependant le suffixe
+                <literal>hbm.xml</literal> est devenu une convention dans la communauté des
+                développeurs Hibernate. La structure du répertoire devrait ressembler à ça :
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate et bibliothèques tierces>
++src
+  Event.java
+  Event.hbm.xml]]></programlisting>
+
+             <para>
+                 Nous poursuivons avec la configuration principale d'Hibernate.
+             </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-configuration"  revision="1">
+            <title>Configuration d'Hibernate</title>
+
+            <para>
+                Nous avons maintenant une classe persistante et son fichier de mapping. Il est temps de
+                configurer Hibernate. Avant ça, nous avons besoin d'une base de données. HSQL DB, un
+                SGBD SQL basé sur Java et travaillant en mémoire, peut être téléchargé à partir du site
+                web de HSQL. En fait, vous avez seulement besoin de <literal>hsqldb.jar</literal>. Placez
+                ce fichier dans le répertoire <literal>lib/</literal> du dossier de développement.
+            </para>
+
+            <para>
+                Créez un répertoire appelé <literal>data</literal> à la racine du répertoire de développement - 
+                c'est là que HSQL DB stockera ses fichiers de données. Démarrez maintenant votre base de données
+                en exécutant <literal>java -classpath lib/hsqldb.jar org.hsqldb.Server</literal> dans votre répertoire de travail.
+                Vous observez qu'elle démarre et ouvre une socket TCP/IP, c'est là que notre application
+                se connectera plus tard. Si vous souhaitez démarrez à partir d'une nouvelle base de données
+                pour ce tutoriel (faites <literal>CTRL + C</literal> dans la fenêtre the window), effacez
+                le répertoire <literal>data/</literal> et redémarrez HSQL DB à nouveau.
+                
+            </para>
+
+            <para>
+                Hibernate est la couche de votre application qui se connecte à cette base de données,
+                donc il a besoin des informations de connexion. Les connexions sont établies à travers
+                un pool de connexions JDBC, que nous devons aussi configurer. La distribution Hibernate
+                contient différents outils de gestion de pools de connexions JDBC open source, mais
+                pour ce didacticiel nous utiliserons le pool de connexions intégré à Hibernate. Notez
+                que vous devez copier les bibliothèques requises dans votre classpath et utiliser
+                une configuration de pool de connexions différente si vous voulez utiliser
+                un logiciel de gestion de pools JDBC tiers avec une qualité de production.
+            </para>
+
+            <para>
+                Pour la configuration d'Hibernate, nous pouvons utiliser un simple fichier
+                <literal>hibernate.properties</literal>, un fichier <literal>hibernate.cfg.xml</literal>
+                légèrement plus sophistiqué, ou même une configuration complète par programmation. La
+                plupart des utilisateurs préfèrent le fichier de configuration XML :
+            </para>
+
+            <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <session-factory>
+
+        <!-- Database connection settings -->
+        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
+        <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
+        <property name="connection.username">sa</property>
+        <property name="connection.password"></property>
+
+        <!-- JDBC connection pool (use the built-in) -->
+        <property name="connection.pool_size">1</property>
+
+        <!-- SQL dialect -->
+        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
+
+        <!-- Enable Hibernate's automatic session context management -->
+        <property name="current_session_context_class">thread</property>
+
+        <!-- Disable the second-level cache  -->
+        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
+
+        <!-- Echo all executed SQL to stdout -->
+        <property name="show_sql">true</property>
+
+        <!-- Drop and re-create the database schema on startup -->
+        <property name="hbm2ddl.auto">create</property>
+
+        <mapping resource="events/Event.hbm.xml"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+            <para>
+                Notez que cette configuration XML utilise une DTD différente. Nous configurons
+                une <literal>SessionFactory</literal> d'Hibernate - une fabrique globale responsable
+                d'une base de données particulière. Si vous avez plusieurs base de données, utilisez
+                plusieurs configurations <literal>&lt;session-factory&gt;</literal>, généralement
+                dans des fichiers de configuration différents (pour un démarrage plus facile).
+            </para>
+
+            <para>
+                Les quatre premiers éléments <literal>property</literal> contiennent la configuration
+                nécessaire pour la connexion JDBC. L'élément <literal>property</literal> du dialecte
+                spécifie quelle variante du SQL Hibernate va générer.  La gestion automatique des sessions
+                d'Hibernate pour les contextes de persistance sera détaillée très vite.
+                L'option <literal>hbm2ddl.auto</literal> active la génération automatique des schémas de
+                base de données - directement dans la base de données. Cela peut bien sûr aussi être
+                désactivé (en supprimant l'option de configuration) ou redirigé vers un fichier avec
+                l'aide de la tâche Ant <literal>SchemaExport</literal>. Finalement, nous ajoutons
+                le(s) fichier(s) de mapping pour les classes persistantes.
+            </para>
+
+            <para>
+                Copiez ce fichier dans le répertoire source, il terminera dans la racine
+                du classpath. Hibernate cherchera automatiquement, au démarrage, un fichier appelé
+                <literal>hibernate.cfg.xml</literal> dans la racine du classpath.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-ant"  revision="1">
+            <title>Construction avec Ant</title>
+
+            <para>
+                Nous allons maintenant construire le didacticiel avec Ant. Vous aurez besoin d'avoir Ant
+                d'installé - récupérez-le à partir de <ulink url="http://ant.apache.org/bindownload.cgi"> la page
+                de téléchargement de Ant</ulink>. Comment installer Ant ne sera pas couvert ici. Référez-vous
+                au <ulink url="http://ant.apache.org/manual/index.html">manuel d'Ant</ulink>. Après que
+                vous aurez installé Ant, nous pourrons commencer à créer le fichier de construction. Il
+                s'appellera <literal>build.xml</literal> et sera placé directement dans le répertoire de
+                développement.
+            </para>
+
+           <para>
+                Un fichier de construction basique ressemble à ça :
+            </para>
+
+            <programlisting><![CDATA[<project name="hibernate-tutorial" default="compile">
+
+    <property name="sourcedir" value="${basedir}/src"/>
+    <property name="targetdir" value="${basedir}/bin"/>
+    <property name="librarydir" value="${basedir}/lib"/>
+
+    <path id="libraries">
+        <fileset dir="${librarydir}">
+            <include name="*.jar"/>
+        </fileset>
+    </path>
+
+    <target name="clean">
+        <delete dir="${targetdir}"/>
+        <mkdir dir="${targetdir}"/>
+    </target>
+
+    <target name="compile" depends="clean, copy-resources">
+      <javac srcdir="${sourcedir}"
+             destdir="${targetdir}"
+             classpathref="libraries"/>
+    </target>
+
+    <target name="copy-resources">
+        <copy todir="${targetdir}">
+            <fileset dir="${sourcedir}">
+                <exclude name="**/*.java"/>
+            </fileset>
+        </copy>
+    </target>
+
+</project>]]></programlisting>
+
+            <para>
+                Cela dira à Ant d'ajouter tous les fichiers du répertoire lib finissant par
+                <literal>.jar</literal> dans le classpath utilisé pour la compilation. Cela copiera aussi
+                tous les fichiers source non Java dans le répertoire cible, par exemple les fichiers de
+                configuration et de mapping d'Hibernate. Si vous lancez Ant maintenant, vous devriez
+                obtenir cette sortie :
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant
+Buildfile: build.xml
+
+copy-resources:
+     [copy] Copying 2 files to C:\hibernateTutorial\bin
+
+compile:
+    [javac] Compiling 1 source file to C:\hibernateTutorial\bin
+
+BUILD SUCCESSFUL
+Total time: 1 second ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-helpers" revision="3">
+            <title>Démarrage et aides</title>
+
+            <para>
+                Il est temps de charger et de stocker quelques objets <literal>Event</literal>,
+                mais d'abord nous devons compléter la configuration avec du code
+                d'infrastructure. Nous devons démarrer Hibernate. Ce démarrage inclut la construction
+                d'un objet <literal>SessionFactory</literal> global et le stocker quelque part
+                facile d'accès dans le code de l'application. Une <literal>SessionFactory</literal>
+                peut ouvrir des nouvelles <literal>Session</literal>s. Une <literal>Session</literal>
+                représente une unité de travail simplement "threadée", la <literal>SessionFactory</literal>
+                est un objet global "thread-safe", instancié une seule fois.
+            </para>
+
+            <para>
+                Nous créerons une classe d'aide <literal>HibernateUtil</literal> qui s'occupe du
+                démarrage et rend la gestion des <literal>Session</literal>s plus facile. 
+                Regardons l'implémentation :
+            </para>
+
+            <programlisting><![CDATA[package util;
+
+import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+    public static final SessionFactory sessionFactory;
+
+    static {
+        try {
+            // Création de la SessionFactory à partir de hibernate.cfg.xml
+            sessionFactory = new Configuration().configure().buildSessionFactory();
+        } catch (Throwable ex) {
+            // Make sure you log the exception, as it might be swallowed
+            System.err.println("Initial SessionFactory creation failed." + ex);
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    public static final ThreadLocal session = new ThreadLocal();
+
+    public static SessionFactory getSessionFactory() {
+        return sessionFactory;
+    }
+}]]></programlisting>
+
+            <para>
+                Cette classe ne produit pas seulement la <literal>SessionFactory</literal> globale
+                dans un initialiseur statique (appelé une seule fois par la JVM lorsque la classe
+                est chargée), elle masque le fait qu'elle exploite un singleton. Elle pourrait aussi
+                obtenir la <literal>SessionFactory</literal> depuis JNDI dans un serveur d'applications.
+            </para>
+
+            <para>
+                Si vous nommez la <literal>SessionFactory</literal> dans votre fichier de configuration,
+                Hibernate tentera la récupération depuis JNDI. Pour éviter ce code, vous pouvez aussi
+                utiliser un déploiement JMX et laisser le conteneur (compatible JMX) instancier et lier
+                un <literal>HibernateService</literal> à JNDI. Ces options avancées sont détaillées dans
+                la documentation de référence Hibernate.
+            </para>
+
+            <para>
+                Placez <literal>HibernateUtil.java</literal> dans le répertoire source de développement,
+                et ensuite <literal>Event.java</literal> :
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java
+    Event.hbm.xml
+  +util
+    HibernateUtil.java
+  hibernate.cfg.xml
++data
+build.xml]]></programlisting>
+
+            <para>
+                Cela devrait encore compiler sans problème. Nous avons finalement besoin de configurer
+                le système de "logs" - Hibernate utilise commons-logging et vous laisse le choix entre
+                log4j et le système de logs du JDK 1.4. La plupart des développeurs préfèrent log4j :
+                copiez <literal>log4j.properties</literal> de la distribution d'Hibernate (il est dans
+                le répertoire <literal>etc/</literal>) dans votre répertoire <literal>src</literal>,
+                puis faites de même avec <literal>hibernate.cfg.xml</literal>. Regardez la configuration
+                d'exemple et changez les paramètres si vous voulez une sortie plus verbeuse. Par défaut,
+                seul le message de démarrage d'Hibernate est affiché sur la sortie standard.
+            </para>
+
+            <para>
+                L'infrastructure de ce didacticiel est complète - et nous sommes prêts à effectuer un
+                travail réel avec Hibernate.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-workingpersistence" revision="4">
+            <title>Charger et stocker des objets</title>
+
+            <para>
+                Finalement nous pouvons utiliser Hibernate pour charger et stocker des objets.
+                Nous écrivons une classe <literal>EventManager</literal> avec une méthode
+                <literal>main()</literal> :
+            </para>
+
+            <programlisting><![CDATA[package events;
+import org.hibernate.Session;
+
+import java.util.Date;
+
+import util.HibernateUtil;
+
+public class EventManager {
+
+    public static void main(String[] args) {
+        EventManager mgr = new EventManager();
+
+        if (args[0].equals("store")) {
+            mgr.createAndStoreEvent("My Event", new Date());
+        }
+
+        HibernateUtil.getSessionFactory().close();
+    }
+
+    private void createAndStoreEvent(String title, Date theDate) {
+
+        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+        session.beginTransaction();
+
+        Event theEvent = new Event();
+        theEvent.setTitle(title);
+        theEvent.setDate(theDate);
+
+        session.save(theEvent);
+
+        session.getTransaction().commit();
+    }]]></programlisting>
+
+            <para>
+                Nous créons un nouvel objet <literal>Event</literal>, et le remettons à Hibernate.
+                Hibernate s'occupe maintenant du SQL et exécute les <literal>INSERT</literal>s
+                dans la base de données. Regardons le code de gestion de la <literal>Session</literal>
+                et de la <literal>Transaction</literal> avant de lancer ça.
+            </para>
+
+            <para>
+                Une <literal>Session</literal> est une unité de travail. Pour le moment, nous allons faire
+                les choses simplement et assumer une granularité un-un entre une <literal>Session</literal>
+                hibernate et une transaction à la base de données. Pour isoler notre code du système de transaction
+                sous-jacent (dans notre cas, du pure JDBC, mais cela pourrait être JTA), nous utilisons l'API
+                <literal>Transaction</literal> qui est disponible depuis la <literal>Session</literal> Hibernate.
+            </para>
+
+            <para>
+                Que fait <literal>sessionFactory.getCurrentSession()</literal> ? Premièrement, vous pouvez
+                l'invoquer autant de fois que vous le voulez et n'importe où du moment que vous avez votre
+                <literal>SessionFactory</literal> (facile grâce à <literal>HibernateUtil</literal>). 
+                La méthode <literal>getCurrentSession()</literal> renvoie toujours l'unité de travail courante.
+                Souvenez vous que nous avons basculé notre option de configuration au mécanisme basé sur le "thread"
+                dans <literal>hibernate.cfg.xml</literal>. Par conséquent, le scope de l'unité de travail
+                courante est le thread java courant d'exécution. Ceci n'est pas totalement vrai. Une
+                <literal>Session</literal> commence lorsqu'elle est vraiment utilisée la première fois,
+                Lorsque nous appelons pour la première fois <literal>getCurrentSession()</literal>.
+                Ensuite, elle est liée, par Hibernate, au thread courant. Lorsque la transaction s'achève
+                (commit ou rollback), Hibernate délie la <literal>Session</literal> du thread et la ferme
+                pour vous. Si vous invoquez <literal>getCurrentSession()</literal> une autre fois, vous obtenez
+                une nouvelle <literal>Session</literal> et pouvez entamer une nouvelle unité de travail.
+                Ce modèle de programmation "<emphasis>thread-bound</emphasis>" est le moyen le plus 
+                populaire d'utiliser Hibernate.
+            </para>
+            
+            <para>
+                Lisez <xref linkend="transactions"/> pour plus d'informations sur la gestion des transactions et leur démarcations.
+                Nous n'avons pas géré les erreurs et rollback sur l'exemple précédent.
+            </para>
+
+            <para>
+                Pour lancer cette première routine, nous devons ajouter une cible appelable dans
+                le fichier de construction de Ant :
+            </para>
+
+            <programlisting><![CDATA[<target name="run" depends="compile">
+    <java fork="true" classname="events.EventManager" classpathref="libraries">
+        <classpath path="${targetdir}"/>
+        <arg value="${action}"/>
+    </java>
+</target>]]></programlisting>
+
+            <para>
+                La valeur de l'argument <literal>action</literal> correspond à la ligne de commande
+                qui appelle la cible :
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant run -Daction=store]]></programlisting>
+
+            <para>
+                Vous devriez voir, après la compilation, Hibernate démarrer et, en fonction de votre
+                configuration, beaucoup de traces sur la sortie. À la fin vous trouverez la ligne suivante :
+            </para>
+
+            <programlisting><![CDATA[[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)]]></programlisting>
+
+            <para>
+                C'est l'<literal>INSERT</literal> exécuté par Hibernate, les points d'interrogation
+                représentent les paramètres JDBC liés. Pour voir les valeurs liées aux arguments, ou
+                pour réduire la verbosité des traces, vérifier votre <literal>log4j.properties</literal>.
+            </para>
+
+            <para>
+                Maintenant nous aimerions aussi lister les événements stockés, donc nous ajoutons une
+                option à la méthode principale :
+            </para>
+
+            <programlisting><![CDATA[if (args[0].equals("store")) {
+    mgr.createAndStoreEvent("My Event", new Date());
+}
+else if (args[0].equals("list")) {
+    List events = mgr.listEvents();
+    for (int i = 0; i < events.size(); i++) {
+        Event theEvent = (Event) events.get(i);
+        System.out.println("Event: " + theEvent.getTitle() +
+                           " Time: " + theEvent.getDate());
+    }
+}]]></programlisting>
+
+            <para>
+                Nous ajoutons aussi une nouvelle méthode <literal>listEvents()</literal> :
+            </para>
+
+            <programlisting><![CDATA[private List listEvents() {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+    session.beginTransaction();
+
+    List result = session.createQuery("from Event").list();
+
+    session.getTransaction().commit();
+
+    return result;
+}]]></programlisting>
+
+            <para>
+                Ce que nous faisons ici c'est utiliser une requête HQL (Hibernate Query Language) pour
+                charger tous les objets <literal>Event</literal> existants de la base de données.
+                Hibernate générera le SQL approprié, l'enverra à la base de données et peuplera des
+                objets <literal>Event</literal> avec les données. Vous pouvez créer des requêtes plus
+                complexes avec HQL, bien sûr.
+            </para>
+
+            <para>
+                Maintenant, pour exécuter et tester tout ça, suivez ces étapes :
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        Exécutez <literal>ant run -Daction=store</literal> pour stocker quelque
+                        chose dans la base de données et, bien sûr, pour générer, avant, le schéma
+                        de la base de données grâce à hbm2ddl.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Maintenant désactivez hbm2ddl en commentant la propriété dans votre fichier
+                        <literal>hibernate.cfg.xml</literal>. Généralement vous la laissez seulement
+                        activée dans des tests unitaires en continu, mais une autre exécution de hbm2ddl
+                        <emphasis>effacerait</emphasis> tout ce que vous avez stocké - le paramètre de
+                        configuration <literal>create</literal> se traduit en fait par "supprimer toutes les
+                        tables du schéma, puis re-créer toutes les tables, lorsque la SessionFactory est
+                        construite".
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Si maintenant vous appelez Ant avec <literal>-Daction=list</literal>, vous devriez voir
+                les événements que vous avez stockés jusque là. Vous pouvez bien sûr aussi appeler l'action
+                <literal>store</literal> plusieurs fois.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="tutorial-associations">
+        <title>Partie 2 - Mapper des associations</title>
+
+        <para>
+            Nous avons mappé une classe d'une entité persistante vers une table. Partons de là et
+            ajoutons quelques associations de classe. D'abord nous ajouterons des gens à notre
+            application, et stockerons une liste d'événements auxquels ils participent.
+        </para>
+
+        <sect2 id="tutorial-associations-mappinguser" revision="1">
+            <title>Mapper la classe Person</title>
+
+            <para>
+                La première version de la classe <literal>Person</literal> est simple :
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+public class Person {
+
+    private Long id;
+    private int age;
+    private String firstname;
+    private String lastname;
+
+    public Person() {}
+
+    // Accessor methods for all properties, private setter for 'id'
+
+}]]></programlisting>
+
+            <para>
+                Créez un nouveau fichier de mapping appelé <literal>Person.hbm.xml</literal> 
+                (n'oubliez pas la référence à la DTD)
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Person" table="PERSON">
+        <id name="id" column="PERSON_ID">
+            <generator class="native"/>
+        </id>
+        <property name="age"/>
+        <property name="firstname"/>
+        <property name="lastname"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Finalement, ajoutez la nouveau mapping à la configuration d'Hibernate :
+            </para>
+
+            <programlisting><![CDATA[<mapping resource="events/Event.hbm.xml"/>
+<mapping resource="events/Person.hbm.xml"/>]]></programlisting>
+            <para>
+                Nous allons maintenant créer une association entre ces deux entités. Évidemment,
+                des personnes peuvent participer aux événements, et des événements ont des participants.
+                Les questions de conception que nous devons traiter sont : direction, cardinalité et comportement
+                de la collection.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-unidirset" revision="2">
+            <title>Une association unidirectionnelle basée sur Set</title>
+
+            <para>
+                Nous allons ajouter une collection d'événements à la classe <literal>Person</literal>. De
+                cette manière nous pouvons facilement naviguer dans les événements d'une personne
+                particulière, sans exécuter une requête explicite - en appelant
+                <literal>aPerson.getEvents()</literal>. Nous utilisons une collection Java, un
+                <literal>Set</literal>, parce que la collection ne contiendra pas d'éléments dupliqués et
+                l'ordre ne nous importe pas.
+            </para>
+
+            <para>
+                Nous avons besoin d'une association unidirectionnelle, pluri-valuée, implémentée avec
+                un <literal>Set</literal>. Écrivons le code pour ça dans les classes Java et mappons les :
+            </para>
+
+            <programlisting><![CDATA[public class Person {
+
+    private Set events = new HashSet();
+
+    public Set getEvents() {
+        return events;
+    }
+
+    public void setEvents(Set events) {
+        this.events = events;
+    }
+}]]></programlisting>
+
+            <para>
+                D'abord nous mappons cette association, mais pensez à l'autre côté. Clairement, nous pouvons
+                la laisser unidirectionnelle. Ou alors, nous pourrions créer une autre collection sur
+                <literal>Event</literal>, si nous voulons être capable de la parcourir de manière
+                bidirectionnelle, c'est-à-dire avoir <literal>anEvent.getParticipants()</literal>.
+                Ce n'est pas nécessaire d'un point de vue fonctionnel. Vous pourrez toujours exécuter une requête
+                explicite pour récupérer les participants d'un "event" particulier. Ce choix de conception
+                vous est laissé, mais ce qui reste certains est la cardinalité de l'association: "plusieurs"
+                des deux côtés, nous appelons cela une association <emphasis>many-to-many</emphasis>. 
+                Par conséquent nous utilisons un mapping Hibernate many-to-many:
+            </para>
+
+            <programlisting><![CDATA[<class name="events.Person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="native"/>
+    </id>
+    <property name="age"/>
+    <property name="firstname"/>
+    <property name="lastname"/>
+
+    <set name="events" table="PERSON_EVENT">
+        <key column="PERSON_ID"/>
+        <many-to-many column="EVENT_ID" class="Event"/>
+    </set>
+
+</class>]]></programlisting>
+
+            <para>
+                Hibernate supporte toutes sortes de mapping de collection, un <literal>&lt;set&gt;</literal>
+                étant le plus commun. Pour une association many-to-many (ou une relation
+                d'entité <emphasis>n:m</emphasis>), une table d'association est requise. Chaque ligne dans cette table représente un lien entre une personne et un événement. Le nom de la table est
+                configuré avec l'attribut <literal>table</literal> de l'élément <literal>set</literal>. Le
+                nom de la colonne identifiant dans l'association, du côté de la personne, est défini avec
+                l'élément <literal>&lt;key&gt;</literal>, et le nom de la colonne pour l'événement dans
+                l'attribut <literal>column</literal> de <literal>&lt;many-to-many&gt;</literal>. Vous
+                devez aussi donner à Hibernate la classe des objets de votre collection (c'est-à-dire : la
+                classe de l'autre côté de la collection).
+            </para>
+
+            <para>
+                Le schéma de base de données pour ce mapping est donc :
+            </para>
+
+            <programlisting><![CDATA[
+    _____________        __________________
+   |             |      |                  |       _____________
+   |   EVENTS    |      |   PERSON_EVENT   |      |             |
+   |_____________|      |__________________|      |    PERSON   |
+   |             |      |                  |      |_____________|
+   | *EVENT_ID   | <--> | *EVENT_ID        |      |             |
+   |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  |
+   |  TITLE      |      |__________________|      |  AGE        |
+   |_____________|                                |  FIRSTNAME  |
+                                                  |  LASTNAME   |
+                                                  |_____________|
+ ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-working" revision="1">
+            <title>Travailler avec l'association</title>
+
+            <para>
+                Réunissons quelques personnes et quelques événements dans une nouvelle méthode dans
+                <literal>EventManager</literal> :
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    aPerson.getEvents().add(anEvent);
+
+    session.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                Après le chargement d'une <literal>Person</literal> et d'un <literal>Event</literal>, modifiez
+                simplement la collection en utilisant les méthodes normales de la collection. Comme vous
+                pouvez le voir, il n'y a pas d'appel explicite à <literal>update()</literal> ou
+                <literal>save()</literal>, Hibernate détecte automatiquement que la collection a été
+                modifiée et a besoin d'être mise à jour. Ceci est appelé <emphasis>la vérification sale
+                automatique</emphasis> (NdT : "automatic dirty checking"), et vous pouvez aussi l'essayer en
+                modifiant le nom ou la propriété date de n'importe lequel de vos objets. Tant qu'ils sont dans
+                un état <emphasis>persistant</emphasis>, c'est-à-dire, liés à une <literal>Session</literal> Hibernate
+                particulière (c-à-d qu'ils ont juste été chargés ou sauvegardés dans une unité de travail),
+                Hibernate surveille les changements et exécute le SQL correspondant. Le processus de
+                synchronisation de l'état de la mémoire avec la base de données, généralement seulement à la fin
+                d'une unité de travail, est appelé <emphasis>flushing</emphasis>. Dans notre code, l'unité de travail
+                s'achève par un commit (ou rollback) de la transaction avec la base de données - comme défini 
+                par notre option <literal>thread</literal> de configuration pour la classe <literal>CurrentSessionContext</literal>.
+            </para>
+
+            <para>
+                Vous pourriez bien sûr charger une personne et un événement dans différentes unités de travail. Ou
+                vous modifiez un objet à l'extérieur d'une <literal>Session</literal>, s'il n'est pas dans un état
+                persistant (s'il était persistant avant, nous appelons cet état <emphasis>détaché</emphasis>). 
+                Vous pouvez même modifier une collection lorsqu'elle est détachée:
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session
+            .createQuery("select p from Person p left join fetch p.events where p.id = :pid")
+            .setParameter("pid", personId)
+            .uniqueResult(); // Eager fetch the collection so we can use it detached
+
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    session.getTransaction().commit();
+
+    // End of first unit of work
+
+    aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached
+
+    // Begin second unit of work
+
+    Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
+    session2.beginTransaction();
+
+    session2.update(aPerson); // Reattachment of aPerson
+
+    session2.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                L'appel à <literal>update</literal> rend un objet détaché à nouveau persistant, vous pourriez
+                dire qu'il le lie à une unité de travail, ainsi toutes les modifications (ajout, suppression) que vous avez faites
+                pendant qu'il était détaché peuvent être sauvegardées dans la base de données
+                (il se peut que vous ayez besoin de modifier quelques unes des méthodes précédentes
+                pour retourner cet identifiant).
+            </para>
+
+            <programlisting><![CDATA[else if (args[0].equals("addpersontoevent")) {
+    Long eventId = mgr.createAndStoreEvent("My Event", new Date());
+    Long personId = mgr.createAndStorePerson("Foo", "Bar");
+    mgr.addPersonToEvent(personId, eventId);
+    System.out.println("Added person " + personId + " to event " + eventId);]]></programlisting>
+
+            <para>
+                Ce n'est pas très utile dans notre situation actuelle, mais c'est un concept important
+                que vous pouvez mettre dans votre propre application.
+                Pour le moment, complétez cet exercice en ajoutant une nouvelle action à la méthode
+                principale des <literal>EventManager</literal>s et appelez la à partir de la ligne de
+                commande. Si vous avez besoin des identifiants d'une personne et d'un événement - la
+                méthode <literal>save()</literal> les retourne.
+            </para>
+
+            <para>
+                C'était un exemple d'une association entre deux classes de même importance, deux entités.
+                Comme mentionné plus tôt, il y a d'autres classes et d'autres types dans un modèle typique,
+                généralement "moins importants". Vous en avez déjà vu certains, comme un <literal>int</literal>
+                ou une <literal>String</literal>. Nous appelons ces classes des <emphasis>types de valeur</emphasis>,
+                et leurs instances <emphasis>dépendent</emphasis> d'une entité particulière. Des instances de ces
+                types n'ont pas leur propre identité, elles ne sont pas non plus partagées entre des entités (deux
+                personnes ne référencent pas le même objet <literal>firstname</literal>, même si elles ont le
+                même prénom). Bien sûr, des types de valeur ne peuvent pas seulement être trouvés dans
+                le JDK (en fait, dans une application Hibernate toutes les classes du JDK sont considérées
+                comme des types de valeur), vous pouvez aussi écrire vous-même des classes dépendantes,
+                <literal>Address</literal> ou <literal>MonetaryAmount</literal>, par exemple.
+            </para>
+
+            <para>
+                Vous pouvez aussi concevoir une collection de types de valeur. C'est conceptuellement très
+                différent d'une collection de références vers d'autres entités, mais très ressemblant en Java.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-valuecollections">
+            <title>Collection de valeurs</title>
+
+            <para>
+                Nous ajoutons une collection d'objets de type de valeur à l'entité <literal>Person</literal>.
+                Nous voulons stocker des adresses email, donc le type que nous utilisons est <literal>String</literal>,
+                et la collection est encore un <literal>Set</literal> :
+            </para>
+            <programlisting><![CDATA[private Set emailAddresses = new HashSet();
+
+public Set getEmailAddresses() {
+    return emailAddresses;
+}
+
+public void setEmailAddresses(Set emailAddresses) {
+    this.emailAddresses = emailAddresses;
+}]]></programlisting>
+
+            <para>
+                Le mapping de ce <literal>Set</literal> :
+            </para>
+
+            <programlisting><![CDATA[<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
+    <key column="PERSON_ID"/>
+    <element type="string" column="EMAIL_ADDR"/>
+</set>]]></programlisting>
+
+            <para>
+                La différence comparée au mapping vu plus tôt est la partie <literal>element</literal>,
+                laquelle dit à Hibernate que la collection ne contient pas de références vers une autre entité,
+                mais une collection d'éléments de type <literal>String</literal> (le nom en minuscule vous
+                indique que c'est un type/convertisseur du mapping Hibernate). Une fois encore, l'attribut
+                <literal>table</literal> de l'élément <literal>set</literal> détermine le nom de la table pour la
+                collection. L'élément <literal>key</literal> définit le nom de la colonne de la clef étrangère
+                dans la table de la collection. L'attribut <literal>column</literal> dans l'élément
+                <literal>element</literal> définit le nom de la colonne où les valeurs de <literal>String</literal>
+                seront réellement stockées.
+            </para>
+
+            <para>
+                Regardons le schéma mis à jour :
+            </para>
+
+            <programlisting><![CDATA[
+  _____________        __________________
+ |             |      |                  |       _____________
+ |   EVENTS    |      |   PERSON_EVENT   |      |             |       ___________________
+ |_____________|      |__________________|      |    PERSON   |      |                   |
+ |             |      |                  |      |_____________|      | PERSON_EMAIL_ADDR |
+ | *EVENT_ID   | <--> | *EVENT_ID        |      |             |      |___________________|
+ |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  | <--> |  *PERSON_ID       |
+ |  TITLE      |      |__________________|      |  AGE        |      |  *EMAIL_ADDR      |
+ |_____________|                                |  FIRSTNAME  |      |___________________|
+                                                |  LASTNAME   |
+                                                |_____________|
+ ]]></programlisting>
+
+            <para>
+                Vous pouvez voir que la clef primaire de la table de la collection est en fait une
+                clef composée, utilisant deux colonnes. Ceci implique aussi qu'il ne peut pas y avoir
+                d'adresses email dupliquées par personne, ce qui est exactement la sémantique dont
+                nous avons besoin pour un ensemble en Java.
+            </para>
+
+            <para>
+                Vous pouvez maintenant tester et ajouter des éléments à cette collection, juste comme
+                nous l'avons fait avant en liant des personnes et des événements. C'est le même code
+                en Java.
+            </para>
+            
+                        <programlisting><![CDATA[private void addEmailToPerson(Long personId, String emailAddress) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+
+    // The getEmailAddresses() might trigger a lazy load of the collection
+    aPerson.getEmailAddresses().add(emailAddress);
+
+    session.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                Cette fois ci, nous n'avons pas utilisé une requête de chargement agressif (<emphasis>fetch</emphasis>)
+                pour initialiser la collection. Par conséquent, l'invocation du getter déclenchera un
+                select supplémentaire pour l'initialiser. Traquez les logs SQL et tentez d'optimiser
+                ce cas avec un chargement aggressif.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-bidirectional" revision="1">
+            <title>Associations bidirectionnelles</title>
+
+            <para>
+                Ensuite nous allons mapper une association bidirectionnelle - faire fonctionner
+                l'association entre une personne et un événement à partir des deux côtés en Java.
+                Bien sûr, le schéma de la base de données ne change pas, nous avons toujours une pluralité
+                many-to-many. Une base de données relationnelle est plus flexible qu'un langage de
+                programmation réseau, donc elle n'a pas besoin de direction de navigation - les données
+                peuvent être vues et récupérées de toutes les manières possibles.
+            </para>
+
+            <para>
+                D'abord, ajouter une collection de participants à la classe <literal>Event</literal> :
+            </para>
+
+            <programlisting><![CDATA[private Set participants = new HashSet();
+
+public Set getParticipants() {
+    return participants;
+}
+
+public void setParticipants(Set participants) {
+    this.participants = participants;
+}]]></programlisting>
+
+            <para>
+                Maintenant mapper ce côté de l'association aussi, dans <literal>Event.hbm.xml</literal>.
+            </para>
+
+            <programlisting><![CDATA[<set name="participants" table="PERSON_EVENT" inverse="true">
+    <key column="EVENT_ID"/>
+    <many-to-many column="PERSON_ID" class="events.Person"/>
+</set>]]></programlisting>
+
+            <para>
+                Comme vous le voyez, ce sont des mappings de <literal>set</literal>s normaux dans les
+                deux documents de mapping. Notez que les noms de colonne dans <literal>key</literal> et
+                <literal>many-to-many</literal> sont inversés dans les 2 documents de mapping. L'ajout
+                le plus important ici est l'attribut <literal>inverse="true"</literal> dans l'élément
+                <literal>set</literal> du mapping de la collection des <literal>Event</literal>s.
+            </para>
+
+            <para>
+                Ce que signifie qu'Hibernate devrait prendre l'autre côté - la classe <literal>Person</literal> -
+                s'il a besoin de renseigner des informations à propos du lien entre les deux. Ce sera
+                beaucoup plus facile à comprendre une fois que vous verrez comment le lien bidirectionnel
+                entre les deux entités est créé.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-usingbidir">
+            <title>Travailler avec des liens bidirectionnels</title>
+
+            <para>
+                Premièrement, gardez à l'esprit qu'Hibernate n'affecte pas la sémantique normale de Java.
+                Comment avons-nous créé un lien entre une <literal>Person</literal> et un <literal>Event</literal>
+                dans l'exemple unidirectionnel ? Nous avons ajouté une instance de <literal>Event</literal>
+                à la collection des références d'événement d'une instance de <literal>Person</literal>. Donc,
+                évidemment, si vous voulons rendre ce lien bidirectionnel, nous devons faire la même chose de
+                l'autre côté - ajouter une référence de <literal>Person</literal> à la collection d'un
+                <literal>Event</literal>. Cette "configuration du lien des deux côtés" est absolument
+                nécessaire et vous ne devriez jamais oublier de le faire.
+            </para>
+
+            <para>
+                Beaucoup de développeurs programment de manière défensive et créent des
+                méthodes de gestion de lien pour affecter correctement les deux côtés,
+                par exemple dans <literal>Person</literal> :
+            </para>
+
+            <programlisting><![CDATA[protected Set getEvents() {
+    return events;
+}
+
+protected void setEvents(Set events) {
+    this.events = events;
+}
+
+public void addToEvent(Event event) {
+    this.getEvents().add(event);
+    event.getParticipants().add(this);
+}
+
+public void removeFromEvent(Event event) {
+    this.getEvents().remove(event);
+    event.getParticipants().remove(this);
+}]]></programlisting>
+
+            <para>
+                Notez que les méthodes get et set pour la collection sont maintenant protégées - ceci permet à des
+                classes du même paquet et aux sous-classes d'accéder encore aux méthodes, mais empêche n'importe qui
+                d'autre de mettre le désordre directement dans les collections (enfin, presque). Vous devriez
+                probablement faire de même avec la collection de l'autre côté.
+            </para>
+
+            <para>
+                Et à propos de l'attribut de mapping <literal>inverse</literal> ? Pour vous, et pour Java, un lien
+                bidirectionnel est simplement une manière de configurer correctement les références des deux côtés.
+                Hibernate n'a cependant pas assez d'informations pour ordonner correctement les expressions SQL
+                <literal>INSERT</literal> et <literal>UPDATE</literal> (pour éviter les violations de contrainte), et
+                a besoin d'aide pour gérer proprement les associations bidirectionnelles. Rendre
+                <literal>inverse</literal> un côté d'une assocation dit à Hibernate de l'ignorer essentiellement, pour
+                le considérer comme un <emphasis>miroir</emphasis> de l'autre côté. C'est tout ce qui est nécessaire à
+                Hibernate pour découvrir tout des problèmes de transformation d'un modèle de navigation
+                directionnelle vers un schéma SQL de base de données. Les règles dont vous devez vous souvenir sont :
+                toutes les associations bidirectionnelles ont besoin d'un côté marqué <literal>inverse</literal>.
+                Dans une association un-vers-plusieurs vous pouvez choisir n'importe quel côté, il n'y a pas de
+                différence.
+            </para>
+<!--
+            <para>
+                In the next section we integrate Hibernate with Tomcat and WebWork - the <literal>EventManager</literal>
+                doesn't scale anymore with our growing application.
+            </para>
+-->
+        </sect2>
+    </sect1>
+    
+    <sect1 id="tutorial-webapp">
+        <title>Part 3 - L'application web EventManager</title>
+
+        <para>
+            Une application web Hibernate utilise la <literal>Session</literal> et <literal>Transaction</literal>
+            comme une application standalone. Cependant, quelques patterns sont utiles. Nous allons coder une
+            <literal>EventManagerServlet</literal>. Cette servlet peut lister tous les évènements stockés dans
+            la base de données, et fournir une formulaire HTML pour saisir d'autres évènements.
+        </para>
+
+        <sect2 id="tutorial-webapp-servlet">
+            <title>Ecrire la servlet de base</title>
+
+            <para>
+                Créons une nouvelle classe dans notre répertoire source, dans le package <literal>events</literal>:
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+// Imports
+
+public class EventManagerServlet extends HttpServlet {
+
+    private final SimpleDateFormat dateFormatter =
+                            new SimpleDateFormat("dd.MM.yyyy");
+
+    // Servlet code
+}]]></programlisting>
+
+            <para>
+                Le <literal>dateFormatter</literal> est un outil que nous utiliserons plus tard pour convertir les objets
+                <literal>Date</literal> depuis et vers des chaines de caractères. Il est propice de n'avoir qu'un
+                formatter comme membre de la servlet.
+            </para>
+
+            <para>
+                La servlet n'accepte que les requêtes HTTP <literal>GET</literal>, la méthode à implémenter est donc
+				<literal>doGet()</literal>:
+            </para>
+
+            <programlisting><![CDATA[protected void doGet(HttpServletRequest request,
+                     HttpServletResponse response)
+        throws ServletException, IOException {
+
+    try {
+        // Begin unit of work
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().beginTransaction();
+
+        // Process request and render page...
+
+        // End unit of work
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().getTransaction().commit();
+
+    } catch (Exception ex) {
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().getTransaction().rollback();
+        throw new ServletException(ex);
+    }
+
+}]]></programlisting>
+
+            <para>
+                La pattern que nous utilisons ici est appelé <emphasis>session-per-request</emphasis>.
+                Lorsqu'une requête touche la servlet, une nouvelle <literal>Session</literal> hibernate est
+                ouverte à l'invocationde <literal>getCurrentSession()</literal> sur la
+                <literal>SessionFactory</literal>. Ensuite, une transaction avec la base de données est démarrée&mdash;
+                tous les accès à la base de données interviennent au sein de la transactiton, peu importe que les données
+                soient lues ou écrites (nous n'utilisons pas le mode auto-commit dans les applications).
+            </para>
+
+            <para>
+                Ensuite, les actions possibles de la requêtes sont exécutées et la réponse HTML
+                est rendue. Nous en parlerons plus tard.
+            </para>
+
+            <para>
+                Enfin, l'unité de travail s'achève lorsque l'exécution et le rendu sont achevés.
+                Si un problème survient lors de ces deux phases, une exception est soulevée et la
+                transaction avec la base de données subit un rollback. Voila pour le pattern
+                <literal>session-per-request</literal>. Au lieu d'un code de démarcation de transaction
+                au sein de chaque servlet, vous pouvez écrire un filtre de servlet.
+                Voir le site Hibernate et le Wiki pour plus d'information sur ce pattern, appelé
+				<emphasis>Open Session in View</emphasis>&mdash; vous en aurez besoin dès que vous
+				utiliserez des JSPs et non plus des servlets pour le rendu de vos vues.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-webapp-processing">
+            <title>Procéder et rendre</title>
+
+            <para>
+                Implémentons l'exécution de la requête et le rendu de la page.                
+            </para>
+
+<programlisting><![CDATA[// Write HTML header
+PrintWriter out = response.getWriter();
+out.println("<html><head><title>Event Manager</title></head><body>");
+
+// Handle actions
+if ( "store".equals(request.getParameter("action")) ) {
+
+    String eventTitle = request.getParameter("eventTitle");
+    String eventDate = request.getParameter("eventDate");
+
+    if ( "".equals(eventTitle) || "".equals(eventDate) ) {
+        out.println("<b><i>Please enter event title and date.</i></b>");
+    } else {
+        createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
+        out.println("<b><i>Added event.</i></b>");
+    }
+}
+
+// Print page
+printEventForm(out);
+listEvents(out);
+
+// Write HTML footer
+out.println("</body></html>");
+out.flush();
+out.close();]]></programlisting>
+
+            <para>
+                Ce style de code avec un mix de Java et d'HTML ne serait pas scalable 
+                dans une application plus complexe&mdash;gardez à l'esprit que nous ne faisons qu'illustrer
+                les concepts basiques d'Hibernate dans ce tutoriel. Ce code affiche une en tête et un pied de page
+                HTML. Dans cette page, sont affichés un formulaire pour la saisie d'évènements ainsi
+                qu'une liste de tous les évènements de la base de données. La première méthode
+                est triviale est ne fait que sortir de l'HTML:
+            </para>
+
+            <programlisting><![CDATA[private void printEventForm(PrintWriter out) {
+    out.println("<h2>Add new event:</h2>");
+    out.println("<form>");
+    out.println("Title: <input name='eventTitle' length='50'/><br/>");
+    out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");
+    out.println("<input type='submit' name='action' value='store'/>");
+    out.println("</form>");
+}]]></programlisting>
+
+            <para>
+                La méthode <literal>listEvents()</literal> utilise la
+                <literal>Session</literal> Hibernate liée au thread courant pour exécuter la
+                requête:
+            </para>
+
+            <programlisting><![CDATA[private void listEvents(PrintWriter out) {
+    List result = HibernateUtil.getSessionFactory()
+                    .getCurrentSession().createCriteria(Event.class).list();
+    if (result.size() > 0) {
+        out.println("<h2>Events in database:</h2>");
+        out.println("<table border='1'>");
+        out.println("<tr>");
+        out.println("<th>Event title</th>");
+        out.println("<th>Event date</th>");
+        out.println("</tr>");
+        for (Iterator it = result.iterator(); it.hasNext();) {
+            Event event = (Event) it.next();
+            out.println("<tr>");
+            out.println("<td>" + event.getTitle() + "</td>");
+            out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
+            out.println("</tr>");
+        }
+        out.println("</table>");
+    }
+}]]></programlisting>
+
+            <para>
+                FEnfin, l'action <literal>store</literal> renvoie à la méthode
+                <literal>createAndStoreEvent()</literal>, qui utilise aussi la
+                <literal>Session</literal> du thread courant:
+            </para>
+
+            <programlisting><![CDATA[protected void createAndStoreEvent(String title, Date theDate) {
+    Event theEvent = new Event();
+    theEvent.setTitle(title);
+    theEvent.setDate(theDate);
+
+    HibernateUtil.getSessionFactory()
+                    .getCurrentSession().save(theEvent);
+}]]></programlisting>
+
+            <para>
+                La servlet est faite. Une requête à la servlet sera exécutée par une seule
+                <literal>Session</literal> et <literal>Transaction</literal>. Comme pour une application
+                standalone, Hibernate peut automatiquement lier ces objets au thread courant d'exécution.
+                Cela vous laisse la liberté de séparer votre code en couches et d'accéder à la
+				<literal>SessionFactory</literal> par le moyen que vous voulez.
+				Généralement, vous utiliserez des conceptions plus sophistiquées et déplacerez
+				le code d'accès aux données dans une couche DAO. Voir le wiki Hibernate pour plus
+				d'exemples.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-webapp-deploy">
+            <title>Déployer et tester</title>
+
+            <para>
+                Pour déployer cette application, vous devez créer une archive Web, un War. Ajoutez
+                la cible Ant suivante dans votre <literal>build.xml</literal>:
+            </para>
+
+<programlisting><![CDATA[<target name="war" depends="compile">
+    <war destfile="hibernate-tutorial.war" webxml="web.xml">
+        <lib dir="${librarydir}">
+          <exclude name="jsdk*.jar"/>
+        </lib>
+
+        <classes dir="${targetdir}"/>
+    </war>
+</target>]]></programlisting>
+
+            <para>
+                Cette cible créé un fichier nommé <literal>hibernate-tutorial.war</literal>
+                dans le répertoire de votre projet. Elle package les bibliothèques et le descripteur <literal>web.xml</literal>
+                qui est attendu dans le répertoire racine de votre projet:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+    xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+    <servlet>
+        <servlet-name>Event Manager</servlet-name>
+        <servlet-class>events.EventManagerServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Event Manager</servlet-name>
+        <url-pattern>/eventmanager</url-pattern>
+    </servlet-mapping>
+</web-app>]]></programlisting>
+
+            <para>
+                Avant de compiler et déployer l'application web, notez qu'une bibliothèque supplémentaire
+                est requise: <literal>jsdk.jar</literal>. C'est le kit de développement de Servlet Java,
+                si vous ne disposez pas de cette bibliothèque, prenez la sur le site de Sun et copiez la
+                dans votre répertoire des bibliothèques. Cependant, elle ne sera utilisée uniquement pour la
+                compilation et sera exclue du paackage WAR.
+            </para>
+
+            <para>
+                Pour construire et déployer, appelez <literal>ant war</literal> dans votre projet et
+                copier le fichier <literal>hibernate-tutorial.war</literal> dans le répertoire <literal>webapp</literal> de tomcat
+                Si vous n'avez pas installé Tomcat, téléchargez le et suivez la notice d'installation. 
+                Vous n'avez pas à modifier la configuration Tomcat pour déployer cette application.
+            </para>
+
+            <para>
+                Une fois l'application déployée et Tomcat lancé, accédez à l'application via
+                <literal>http://localhost:8080/hibernate-tutorial/eventmanager</literal>. 
+                Assurez vous de consulter les traces tomcat pour observer l'initialisation
+                d'Hibernate à la première requête touchant votre servlet (l'initialisation statique dans <literal>HibernateUtil</literal>
+                est invoquée) et pour vérifier qu'aucune exception ne survienne.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="tutorial-summary"  revision="1">
+        <title>Résumé</title>
+
+        <para>
+            Ce didacticiel a couvert les bases de l'écriture d'une simple application Hibernate ainsi qu'une petite application web.
+        </para>
+
+        <para>
+            Si vous êtes déjà confiants avec Hibernate, continuez à parcourir les sujets que vous trouvez
+            intéressants à travers la table des matières de la documentation de référence - les plus
+            demandés sont le traitement transactionnel (<xref linkend="transactions"/>), la performance
+            des récupérations d'information (<xref linkend="performance"/>), ou l'utilisation de l'API
+            (<xref linkend="objectstate"/>) et les fonctionnalités des requêtes (<xref linkend="objectstate-querying"/>).
+        </para>
+
+        <para>
+            N'oubliez pas de vérifier le site web d'Hibernate pour d'autres didacticiels (plus spécialisés).
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/xml.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/xml.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/docbook/modules/xml.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,292 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="xml">
+    <title>Mapping XML</title>
+
+    <para><emphasis>
+        Notez que cette fonctionnalité est expérimentale dans Hibernate 3.0 et
+        est en développement extrêmement actif.
+    </emphasis></para>
+
+    <sect1 id="xml-intro" revision="1">
+        <title>Travailler avec des données XML</title>
+
+        <para>
+            Hibernate vous laisse travailler avec des données XML persistantes de la
+            même manière que vous travaillez avec des POJOs persistants. Un arbre XML
+            peut être vu comme une autre manière de représenter les données relationnelles
+            au niveau objet, à la place des POJOs.
+        </para>
+
+        <para>
+            Hibernate supporte dom4j en tant qu'API pour la manipulation des arbres XML.
+            Vous pouvez écrire des requêtes qui récupèrent des arbres dom4j à partie de la
+            base de données, et avoir toutes les modifications que vous faites sur l'arbre
+            automatiquement synchronisées dans la base de données. Vous pouvez  même prendre
+            un document XML, l'analyser en utilisant dom4j, et l'écrire dans la base de
+            données via les opérations basiques d'Hibernate :
+            <literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal>
+            (merge() n'est pas encore supporté).
+        </para>
+
+        <para>
+            Cette fonctionnalité a plusieurs applications dont l'import/export de données,
+            l'externalisation d'entités via JMS ou SOAP et les rapports XSLT.
+        </para>
+
+        <para>
+            Un simple mapping peut être utilisé pour simultanément mapper les propriétés
+            d'une classe et les noeuds d'un document XML vers la base de données, ou,
+            si il n'y a pas de classe à mapper, il peut être utilisé juste pour mapper
+            le XML.
+        </para>
+
+        <sect2 id="xml-intro-mapping">
+            <title>Spécifier le mapping XML et le mapping d'une classe ensemble</title>
+
+            <para>
+                Voici un exemple de mapping d'un POJO et du XML simultanément :
+            </para>
+
+            <programlisting><![CDATA[<class name="Account"
+        table="ACCOUNTS"
+        node="account">
+
+    <id name="accountId"
+            column="ACCOUNT_ID"
+            node="@id"/>
+
+    <many-to-one name="customer"
+            column="CUSTOMER_ID"
+            node="customer/@id"
+            embed-xml="false"/>
+
+    <property name="balance"
+            column="BALANCE"
+            node="balance"/>
+
+    ...
+
+</class>]]></programlisting>
+        </sect2>
+
+        <sect2 id="xml-onlyxml">
+            <title>Spécifier seulement un mapping XML</title>
+
+            <para>
+                Voici un exemple dans lequel il n'y a pas de class POJO :
+            </para>
+
+            <programlisting><![CDATA[<class entity-name="Account"
+        table="ACCOUNTS"
+        node="account">
+
+    <id name="id"
+            column="ACCOUNT_ID"
+            node="@id"
+            type="string"/>
+
+    <many-to-one name="customerId"
+            column="CUSTOMER_ID"
+            node="customer/@id"
+            embed-xml="false"
+            entity-name="Customer"/>
+
+    <property name="balance"
+            column="BALANCE"
+            node="balance"
+            type="big_decimal"/>
+
+    ...
+
+</class>]]></programlisting>
+
+            <para>
+                Ce mapping vous permet d'accéder aux données comme un arbre dom4j, ou comme
+                un graphe de paire nom de propriété/valeur (<literal>Map</literal>s java). Les
+                noms des propriétés sont des constructions purement logiques qui peuvent être
+                référées des dans requêtes HQL.
+            </para>
+
+        </sect2>
+
+     </sect1>
+
+    <sect1 id="xml-mapping" revision="1">
+        <title>Métadonnées du mapping XML</title>
+
+        <para>
+            Plusieurs éléments du mapping Hibernate acceptent l'attribut <literal>node</literal>.
+            Ceci vous permet de spécifier le nom d'un attribut XML ou d'un élément qui
+            contient la propriété ou les données de l'entité. Le format de l'attribut
+            <literal>node</literal> doit être un des suivants :
+        </para>
+
+        <itemizedlist spacing="compact">
+        <listitem>
+            <para><literal>"element-name"</literal> - mappe vers l'élément XML nommé</para>
+        </listitem>
+        <listitem>
+            <para><literal>"@attribute-name"</literal> - mappe vers l'attribut XML nommé</para>
+        </listitem>
+        <listitem>
+            <para><literal>"."</literal> - mappe vers le parent de l'élément</para>
+        </listitem>
+        <listitem>
+            <para>
+                <literal>"element-name/@attribute-name"</literal> -
+                mappe vers l'élément nommé de l'attribut nommé
+            </para>
+        </listitem>
+        </itemizedlist>
+
+        <para>
+            Pour des collections et de simples associations valuées, il y a un attribut
+            <literal>embed-xml</literal> supplémentaire. Si <literal>embed-xml="true"</literal>,
+            qui est la valeur par défaut, l'arbre XML pour l'entité associée (ou la collection
+            des types de valeurs) sera embarquée directement dans l'arbre XML pour l'entité qui
+            possède l'association. Sinon, si <literal>embed-xml="false"</literal>, alors
+            seule la valeur de l'identifiant référencé apparaîtra dans le XML pour de simples
+            associations de points, et les collections n'appraîtront simplement pas.
+        </para>
+
+        <para>
+            Vous devriez faire attention à ne pas laisser <literal>embed-xml="true"</literal>
+            pour trop d'associations, puisque XML ne traite pas bien les liens circurlaires.
+        </para>
+
+        <programlisting><![CDATA[<class name="Customer"
+        table="CUSTOMER"
+        node="customer">
+
+    <id name="id"
+            column="CUST_ID"
+            node="@id"/>
+
+    <map name="accounts"
+            node="."
+            embed-xml="true">
+        <key column="CUSTOMER_ID"
+                not-null="true"/>
+        <map-key column="SHORT_DESC"
+                node="@short-desc"
+                type="string"/>
+        <one-to-many entity-name="Account"
+                embed-xml="false"
+                node="account"/>
+    </map>
+
+    <component name="name"
+            node="name">
+        <property name="firstName"
+                node="first-name"/>
+        <property name="initial"
+                node="initial"/>
+        <property name="lastName"
+                node="last-name"/>
+    </component>
+
+    ...
+
+</class>]]></programlisting>
+
+        <para>
+            dans ce cas, nous avons décidé d'embarquer la collection d'identifiants de compte,
+            mais pas les données actuelles du compte. La requête HQL suivante :
+        </para>
+
+        <programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
+
+        <para>
+            devrait retourner l'ensemble de données suivant :
+        </para>
+
+        <programlisting><![CDATA[<customer id="123456789">
+    <account short-desc="Savings">987632567</account>
+    <account short-desc="Credit Card">985612323</account>
+    <name>
+        <first-name>Gavin</first-name>
+        <initial>A</initial>
+        <last-name>King</last-name>
+    </name>
+    ...
+</customer>]]></programlisting>
+
+        <para>
+            Si vous positionnez <literal>embed-xml="true"</literal> sur le mapping
+            <literal>&lt;one-to-many&gt;</literal>, les données pourraient
+            ressembler plus à ça :
+        </para>
+
+        <programlisting><![CDATA[<customer id="123456789">
+    <account id="987632567" short-desc="Savings">
+        <customer id="123456789"/>
+        <balance>100.29</balance>
+    </account>
+    <account id="985612323" short-desc="Credit Card">
+        <customer id="123456789"/>
+        <balance>-2370.34</balance>
+    </account>
+    <name>
+        <first-name>Gavin</first-name>
+        <initial>A</initial>
+        <last-name>King</last-name>
+    </name>
+    ...
+</customer>]]></programlisting>
+
+    </sect1>
+
+
+    <sect1 id="xml-manipulation" revision="1">
+        <title>Manipuler des données XML</title>
+
+        <para>
+            Relisons et mettons à jour des documents XML dans l'application. Nous faisons
+            ça en obtenant une session dom4j :
+        </para>
+
+       <programlisting><![CDATA[Document doc = ....;
+
+Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+List results = dom4jSession
+    .createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")
+    .list();
+for ( int i=0; i<results.size(); i++ ) {
+    //add the customer data to the XML document
+    Element customer = (Element) results.get(i);
+    doc.add(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+       <programlisting><![CDATA[Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+Element cust = (Element) dom4jSession.get("Customer", customerId);
+for ( int i=0; i<results.size(); i++ ) {
+    Element customer = (Element) results.get(i);
+    //change the customer name in the XML and database
+    Element name = customer.element("name");
+    name.element("first-name").setText(firstName);
+    name.element("initial").setText(initial);
+    name.element("last-name").setText(lastName);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            Il est extrêmement utile de combiner cette fonctionnalité avec l'opération
+            <literal>replicate()</literal> d'Hibernate pour implémenter des imports/exports
+            de données XML.
+        </para>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/css/html.css
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/css/html.css	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/css/html.css	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,97 @@
+A {
+    color: #003399;
+}
+
+A:active {
+    color: #003399;
+}
+
+A:visited {
+    color: #888888;
+}
+
+P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
+    color: #000000;
+}
+
+TD, TH, SPAN {
+    color: #000000;
+}
+
+BLOCKQUOTE {
+    margin-right: 0px;
+}
+
+
+H1, H2, H3, H4, H5, H6    {
+    color: #000000;
+    font-weight:500;
+    margin-top:10px;
+    padding-top:15px;
+}
+
+TABLE  {
+    border-collapse: collapse;
+    border-spacing:0;
+    border: 1px thin black;
+    empty-cells: hide;
+}
+
+TD  {
+    padding: 4pt;
+}
+
+H1 { font-size: 150%; }
+H2 { font-size: 140%; }
+H3 { font-size: 110%; font-weight: bold; }
+H4 { font-size: 110%; font-weight: bold;}
+H5 { font-size: 100%; font-style: italic; }
+H6 { font-size: 100%; font-style: italic; }
+
+TT {
+font-size: 90%;
+    font-family: "Courier New", Courier, monospace;
+    color: #000000;
+}
+
+PRE {
+font-size: 100%;
+    padding: 5px;
+    border-style: solid;
+    border-width: 1px;
+    border-color: #CCCCCC;
+    background-color: #F4F4F4;
+}
+
+UL, OL, LI {
+    list-style: disc;
+}
+
+HR  {
+    width: 100%;
+    height: 1px;
+    background-color: #CCCCCC;
+    border-width: 0px;
+    padding: 0px;
+    color: #CCCCCC;
+}
+
+.variablelist { 
+    padding-top: 10; 
+    padding-bottom:10; 
+    margin:0;
+}
+
+.itemizedlist, UL { 
+    padding-top: 0; 
+    padding-bottom:0; 
+    margin:0; 
+}
+
+.term { 
+    font-weight:bold;
+}
+
+
+
+    

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/AuthorWork.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/AuthorWork.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/AuthorWork.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/AuthorWork.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/CustomerOrderProduct.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/CustomerOrderProduct.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/CustomerOrderProduct.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/CustomerOrderProduct.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/EmployerEmployee.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/EmployerEmployee.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/EmployerEmployee.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/EmployerEmployee.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/full_cream.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/full_cream.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/full_cream.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/full_cream.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/full_cream.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,429 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="354.331"
+   height="336.614"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+     style="font-size:12;"
+     id="g659">
+    <rect
+       width="212.257"
+       height="57.2441"
+       x="17.9576"
+       y="100.132"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       transform="matrix(0.743454,0,0,0.482981,6.46949,52.2178)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <rect
+     width="325.86"
+     height="63.6537"
+     x="17.4083"
+     y="15.194"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect136" />
+  <rect
+     width="325.86"
+     height="63.6537"
+     x="13.6713"
+     y="12.4966"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect126" />
+  <g
+     transform="matrix(1.14345,0,0,0.729078,-1.67818,105.325)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <text
+     x="170.824753"
+     y="58.402939"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="170.824997"
+       y="58.402901"
+       id="tspan360">
+Application</tspan>
+  </text>
+  <text
+     x="178.076340"
+     y="364.281433"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="178.076004"
+       y="364.281006"
+       id="tspan421">
+Database</tspan>
+  </text>
+  <text
+     x="68.605331"
+     y="138.524582"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="68.605301"
+       y="138.524994"
+       id="tspan384">
+SessionFactory</tspan>
+  </text>
+  <rect
+     width="67.0014"
+     height="101.35"
+     x="196.927"
+     y="89.2389"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect387" />
+  <rect
+     width="67.0014"
+     height="101.35"
+     x="194.633"
+     y="86.4389"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect388" />
+  <text
+     x="249.108841"
+     y="173.885559"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text389">
+    <tspan
+       x="249.108994"
+       y="173.886002"
+       id="tspan392">
+Session</tspan>
+  </text>
+  <rect
+     width="73.0355"
+     height="101.35"
+     x="270.995"
+     y="90.0018"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect395" />
+  <rect
+     width="73.0355"
+     height="101.35"
+     x="267.869"
+     y="87.2018"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect396" />
+  <text
+     x="328.593658"
+     y="174.715622"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text397">
+    <tspan
+       x="328.593994"
+       y="174.716003"
+       id="tspan563">
+Transaction</tspan>
+  </text>
+  <g
+     transform="matrix(0.29544,0,0,0.397877,9.70533,103.96)"
+     style="font-size:12;"
+     id="g565">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect566" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect567" />
+  </g>
+  <text
+     x="25.592752"
+     y="204.497803"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text568">
+    <tspan
+       x="25.592800"
+       y="204.498001"
+       id="tspan662">
+TransactionFactory</tspan>
+  </text>
+  <g
+     transform="matrix(0.298082,0,0,0.397877,99.6898,103.96)"
+     style="font-size:12;"
+     id="g573">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect574" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect575" />
+  </g>
+  <text
+     x="134.030670"
+     y="205.532791"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text576">
+    <tspan
+       x="134.031006"
+       y="205.533005"
+       id="tspan664">
+ConnectionProvider</tspan>
+  </text>
+  <g
+     transform="matrix(1.14345,0,0,0.729078,-1.67818,38.9539)"
+     style="font-size:12;"
+     id="g587">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect588" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect589" />
+  </g>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="25.6196"
+     y="206.028"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect594" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="24.4229"
+     y="204.135"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect595" />
+  <text
+     x="85.575645"
+     y="282.300354"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text596">
+    <tspan
+       x="85.575600"
+       y="282.299988"
+       id="tspan607">
+JNDI</tspan>
+  </text>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="236.937"
+     y="206.791"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect610" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="235.741"
+     y="204.898"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect611" />
+  <text
+     x="342.093201"
+     y="283.226410"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text612">
+    <tspan
+       x="342.092987"
+       y="283.226013"
+       id="tspan621">
+JTA</tspan>
+  </text>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="130.134"
+     y="206.791"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect616" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="128.937"
+     y="204.898"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect617" />
+  <text
+     x="212.445343"
+     y="283.226410"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text618">
+    <tspan
+       x="212.445007"
+       y="283.226013"
+       id="tspan623">
+JDBC</tspan>
+  </text>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,6.19341)"
+     style="font-size:12;"
+     id="g637">
+    <g
+       transform="matrix(0.499515,0,0,0.415467,-0.237339,5.61339)"
+       id="g167">
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="61.8805"
+         y="68.4288"
+         style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect134" />
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="59.2613"
+         y="65.8095"
+         style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect135" />
+    </g>
+    <text
+       x="33.749969"
+       y="50.589706"
+       style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+       id="text188">
+      <tspan
+         x="33.750000"
+         y="50.589699"
+         id="tspan635">
+Transient Objects</tspan>
+    </text>
+  </g>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+     style="font-size:12;"
+     id="g644">
+    <g
+       transform="matrix(0.297486,0,0,0.516482,230.251,36.9178)"
+       id="g364">
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="61.8805"
+         y="68.4288"
+         style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect365" />
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="59.2613"
+         y="65.8095"
+         style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect366" />
+    </g>
+    <text
+       x="277.123230"
+       y="85.155571"
+       style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+       id="text367">
+      <tspan
+         x="277.122986"
+         y="85.155602"
+         id="tspan631">
+Persistent</tspan>
+      <tspan
+         x="277.122986"
+         y="96.155602"
+         id="tspan633">
+Objects</tspan>
+    </text>
+  </g>
+</svg>

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/hibernate_logo_a.png
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/hibernate_logo_a.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/lite.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/lite.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/lite.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/lite.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/lite.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,334 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="318.898"
+   height="248.031"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <rect
+     width="291.837"
+     height="57.0074"
+     x="17.3169"
+     y="18.646"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect136" />
+  <rect
+     width="291.837"
+     height="57.0074"
+     x="13.9703"
+     y="16.2302"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect126" />
+  <g
+     transform="matrix(0.326107,0,0,0.765831,9.59261,8.98517)"
+     style="font-size:12;"
+     id="g161">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <g
+     transform="matrix(1.02406,0,0,0.652953,0.223384,39.9254)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <g
+     transform="matrix(0.449834,0,0,0.338463,-3.15909,9.73319)"
+     style="font-size:12;"
+     id="g167">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect134" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect135" />
+  </g>
+  <text
+     x="302.277679"
+     y="65.943230"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="302.277954"
+       y="65.943184"
+       id="tspan360">
+Application</tspan>
+  </text>
+  <text
+     x="36.235924"
+     y="63.796055"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text188">
+    <tspan
+       x="36.235950"
+       y="63.796051"
+       id="tspan427">
+Transient Objects</tspan>
+  </text>
+  <text
+     x="180.416245"
+     y="290.543701"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="180.415939"
+       y="290.543549"
+       id="tspan421">
+Database</tspan>
+  </text>
+  <text
+     x="25.037701"
+     y="179.154755"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="25.037655"
+       y="179.154648"
+       id="tspan384">
+SessionFactory</tspan>
+  </text>
+  <g
+     transform="matrix(0.252763,0,0,0.765831,109.104,8.98517)"
+     style="font-size:12;"
+     id="g386">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect387" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect388" />
+  </g>
+  <g
+     transform="matrix(0.297394,0,0,0.572692,101.502,21.6359)"
+     style="font-size:12;"
+     id="g364">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect365" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect366" />
+  </g>
+  <text
+     x="202.746506"
+     y="102.992203"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text367">
+    <tspan
+       x="202.746948"
+       y="102.992249"
+       id="tspan423">
+Persistent</tspan>
+    <tspan
+       x="202.746948"
+       y="116.992355"
+       id="tspan425">
+Objects</tspan>
+  </text>
+  <text
+     x="174.458496"
+     y="180.080795"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text389">
+    <tspan
+       x="174.458618"
+       y="180.080338"
+       id="tspan392">
+Session</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,188.675,8.98517)"
+     style="font-size:12;"
+     id="g394">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect395" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect396" />
+  </g>
+  <text
+     x="260.413269"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text397">
+    <tspan
+       x="260.412964"
+       y="179.154343"
+       id="tspan400">
+JDBC</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,229.156,8.98517)"
+     style="font-size:12;"
+     id="g405">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect406" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect407" />
+  </g>
+  <text
+     x="320.606903"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text408">
+    <tspan
+       x="320.606964"
+       y="179.154343"
+       id="tspan417">
+JNDI</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,269.281,8.98517)"
+     style="font-size:12;"
+     id="g411">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect412" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect413" />
+  </g>
+  <text
+     x="377.096313"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text414">
+    <tspan
+       x="377.096008"
+       y="179.154999"
+       id="tspan145">
+JTA</tspan>
+  </text>
+</svg>

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/overview.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/overview.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/overview.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/overview.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/fr-FR/src/main/resources/shared/images/overview.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,250 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="248.031"
+   height="248.031"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,-3.02123)"
+     style="font-size:12;"
+     id="g158">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="17.3527"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect136" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="15.3883"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect126" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,3.04452)"
+     style="font-size:12;"
+     id="g161">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,8.0993)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.543505,2.59104,21.1103)"
+     style="font-size:12;"
+     id="g167">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect134" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect135" />
+  </g>
+  <text
+     x="105.392174"
+     y="56.568123"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="105.392273"
+       y="56.568146"
+       id="tspan186">
+Application</tspan>
+  </text>
+  <text
+     x="81.820183"
+     y="103.149330"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:20;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text188">
+    <tspan
+       x="81.820213"
+       y="103.149727"
+       id="tspan206">
+Persistent Objects</tspan>
+  </text>
+  <text
+     x="111.548180"
+     y="278.927887"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="111.547874"
+       y="278.927551"
+       id="tspan200">
+Database</tspan>
+  </text>
+  <text
+     x="94.436180"
+     y="153.805740"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="94.436180"
+       y="153.805740"
+       id="tspan221">
+HIBERNATE</tspan>
+  </text>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,2.59083,1.02261)"
+     style="font-size:12;"
+     id="g254">
+    <g
+       transform="translate(4.58374,2.61928)"
+       id="g176">
+      <g
+         transform="matrix(0.571429,0,0,0.67347,-10.6174,117.093)"
+         id="g170">
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="61.8805"
+           y="68.4288"
+           style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect171" />
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="59.2613"
+           y="65.8095"
+           style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect172" />
+      </g>
+      <g
+         transform="matrix(0.571429,0,0,0.67347,138.682,117.093)"
+         id="g173">
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="61.8805"
+           y="68.4288"
+           style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect174" />
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="59.2613"
+           y="65.8095"
+           style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect175" />
+      </g>
+    </g>
+    <text
+       x="47.259438"
+       y="182.367538"
+       style="font-weight:bold;stroke-width:1pt;font-family:Courier;"
+       id="text191">
+      <tspan
+         x="47.259399"
+         y="182.367996"
+         id="tspan212">
+hibernate.</tspan>
+      <tspan
+         x="47.259399"
+         y="194.367996"
+         id="tspan214">
+properties</tspan>
+    </text>
+    <text
+       x="198.523010"
+       y="188.260941"
+       style="font-weight:normal;stroke-width:1pt;font-family:helvetica;"
+       id="text194">
+      <tspan
+         id="tspan195">
+XML Mapping</tspan>
+    </text>
+  </g>
+</svg>

Added: trunk/Hibernate3/documentation/manual/ja-JP/pom.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-manual</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>hibernate-manual-${translation}</artifactId>
+    <packaging>pom</packaging>
+    <name>Hibernate Manual (${translation})</name>
+
+    <properties>
+        <translation>ja-JP</translation>
+    </properties>
+
+</project>

Added: trunk/Hibernate3/documentation/manual/ja-JP/readme_ja.txt
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/readme_ja.txt	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/readme_ja.txt	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1 @@
+This is v3.2.0
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/master.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/master.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/master.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,231 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
+                      "../support/docbook-dtd/docbookx.dtd"
+[
+<!ENTITY tutorial               SYSTEM "modules/tutorial.xml">
+<!ENTITY architecture           SYSTEM "modules/architecture.xml">
+<!ENTITY configuration          SYSTEM "modules/configuration.xml">
+<!ENTITY persistent-classes     SYSTEM "modules/persistent_classes.xml">
+<!ENTITY basic-mapping          SYSTEM "modules/basic_mapping.xml">
+<!ENTITY collection-mapping     SYSTEM "modules/collection_mapping.xml">
+<!ENTITY association-mapping    SYSTEM "modules/association_mapping.xml">
+<!ENTITY component-mapping      SYSTEM "modules/component_mapping.xml">
+<!ENTITY inheritance-mapping    SYSTEM "modules/inheritance_mapping.xml">
+<!ENTITY session-api            SYSTEM "modules/session_api.xml">
+<!ENTITY transactions           SYSTEM "modules/transactions.xml">
+<!ENTITY events                 SYSTEM "modules/events.xml">
+<!ENTITY batch                  SYSTEM "modules/batch.xml">
+<!ENTITY query-hql              SYSTEM "modules/query_hql.xml">
+<!ENTITY query-criteria         SYSTEM "modules/query_criteria.xml">
+<!ENTITY query-sql              SYSTEM "modules/query_sql.xml">
+<!ENTITY filters                SYSTEM "modules/filters.xml">
+<!ENTITY xml                    SYSTEM "modules/xml.xml">
+<!ENTITY performance            SYSTEM "modules/performance.xml">
+<!ENTITY toolset-guide          SYSTEM "modules/toolset_guide.xml">
+<!ENTITY example-parentchild    SYSTEM "modules/example_parentchild.xml">
+<!ENTITY example-weblog         SYSTEM "modules/example_weblog.xml">
+<!ENTITY example-mappings       SYSTEM "modules/example_mappings.xml">
+<!ENTITY best-practices         SYSTEM "modules/best_practices.xml">
+]>
+
+<book lang="ja">
+
+    <bookinfo>
+        <title>HIBERNATE - Relational Persistence for Idiomatic Java</title>
+        <subtitle>Hibernate Reference Documentation</subtitle>
+        <releaseinfo>3.2 cr3</releaseinfo>
+    </bookinfo>
+
+    <toc/>
+
+    <preface id="preface" revision="2">
+        <title>‘O‘‚«</title>
+
+        <para>
+            ¡“ú‚ÌŠé‹ÆŠÂ‹«‚É‚¨‚¢‚āAƒIƒuƒWƒFƒNƒgŽwŒüƒ\ƒtƒgƒEƒFƒA‚ƃŠƒŒ[ƒVƒ‡ƒiƒ‹ƒf[ƒ^ƒx[ƒX‚ÉŠÖ‚í‚éì‹Æ‚Í
+            ”ÏŽG‚Å–c‘å‚ÈŽžŠÔ‚ð•K—v‚Æ‚µ‚Ü‚·B
+            Hibernate‚ÍJavaŠÂ‹«‚̃IƒuƒWƒFƒNƒg/ƒŠƒŒ[ƒVƒ‡ƒiƒ‹ƒ}ƒbƒsƒ“ƒOƒc[ƒ‹‚Å‚·B
+            ƒIƒuƒWƒFƒNƒg/ƒŠƒŒ[ƒVƒ‡ƒiƒ‹ƒ}ƒbƒsƒ“ƒOiORMj‚Ƃ́A
+            ƒIƒuƒWƒFƒNƒgƒ‚ƒfƒ‹‚©‚çSQLƒx[ƒXƒXƒL[ƒ}‚̃ŠƒŒ[ƒVƒ‡ƒiƒ‹ƒf[ƒ^ƒ‚ƒfƒ‹‚ւƁA
+            ƒf[ƒ^•\Œ»‚ðƒ}ƒbƒsƒ“ƒO‚·‚éi‘Ήž•t‚¯‚éj‹Zp‚Ì‚±‚Æ‚Å‚·B
+        </para>
+
+        <para>
+            Hibernate‚ÍJavaƒNƒ‰ƒX‚©‚çƒf[ƒ^ƒx[ƒXƒe[ƒuƒ‹‚ցi‚»‚µ‚ÄJavaƒf[ƒ^Œ^‚©‚çSQLƒf[ƒ^Œ^‚ցj
+            ‚̃}ƒbƒsƒ“ƒO‚ðˆ—‚·‚邾‚¯‚Å‚Í‚È‚­Aƒf[ƒ^‚̃NƒGƒŠ‚Æ•œŒ³‚ÌŽd‘g‚Ý‚à’ñ‹Ÿ‚µ‚Ü‚·B
+            ‚±‚Ì‚¨‚©‚°‚ÅSQL‚ÆJDBC‚ðŽg‚Á‚½Žèì‹Æ‚ł̃f[ƒ^ˆ—‚É”ï‚₳‚ê‚Ä‚¢‚½ŠJ”­ŽžŠÔ‚ð‘啝‚ɍ팸‚Å‚«‚Ü‚·B
+        </para>
+
+        <para>
+            Hibernate‚̍ŏI–Ú•W‚́Aƒf[ƒ^‚̉i‘±‰»‚ÉŠÖ‚í‚éˆê”Ê“I‚ȃvƒƒOƒ‰ƒ~ƒ“ƒOì‹Æ‚Ì95“‚©‚çŠJ”­ŽÒ‚ð‰ð•ú‚·‚邱‚Æ‚Å‚·B
+            Hibernate‚̓rƒWƒlƒXƒƒWƒbƒN‚ÌŽÀ‘•‚ɃXƒgƒAƒhƒvƒƒV[ƒWƒƒ‚ðŽg‚¤
+            ƒf[ƒ^’†SƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ɑ΂µ‚ẴxƒXƒgƒ\ƒŠƒ…[ƒVƒ‡ƒ“‚Å‚ ‚é‚É—¯‚Ü‚è‚Ü‚¹‚ñB
+            ƒIƒuƒWƒFƒNƒgŽwŒüƒhƒƒCƒ“ƒ‚ƒfƒ‹‚ÆJavaƒx[ƒX‚Ì’†ŠÔ‘w‚ł̃rƒWƒlƒXƒƒWƒbƒN‚ɑ΂µ‚čłà–ð‚É—§‚¿‚Ü‚·B
+            ‚µ‚©‚µHibernate‚̓xƒ“ƒ_ŒÅ—L‚ÌSQLƒR[ƒh‚ðíŒ¸‚Ü‚½‚̓JƒvƒZƒ‹‰»‚µ‚½‚èA
+            •\Œ`Ž®‚©‚çƒIƒuƒWƒFƒNƒg‚̃Oƒ‰ƒt‚ւƃŠƒUƒ‹ƒgƒZƒbƒg‚ð•ÏŠ·‚·‚é‚Ȃǂ́A
+            ˆê”Ê“I‚ȃ^ƒXƒN‚É‚à–𗧂‚łµ‚傤B
+        </para>
+
+        <para>
+            Hibernate‚âƒIƒuƒWƒFƒNƒg/ƒŠƒŒ[ƒVƒ‡ƒiƒ‹ƒ}ƒbƒsƒ“ƒOA
+            ‚³‚ç‚É‚ÍJava‚ª‰‚ß‚Ä‚Ì•û‚́AˆÈ‰º‚̃Xƒeƒbƒv‚ɏ]‚Á‚Ä‚­‚¾‚³‚¢F
+        </para>
+
+        <orderedlist>
+            <listitem>
+                <para>
+                    <xref linkend="tutorial"/> ‚ð“Ç‚ñ‚Å‚­‚¾‚³‚¢B
+                    ’iŠK“I‚ɉðà‚µ‚Ä‚¢‚«‚Ü‚·B
+                    ƒ`ƒ…[ƒgƒŠƒAƒ‹‚̃\[ƒXƒR[ƒh‚̓fƒBƒXƒgƒŠƒrƒ…[ƒVƒ‡ƒ“‚Ì 
+                    <literal>doc/reference/tutorial</literal> ƒfƒBƒŒƒNƒgƒŠ‚ÉŠÜ‚Ü‚ê‚Ä‚¢‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <xref linkend="architecture"/> ‚ð“Ç‚ñ‚ŁAHibernate‚ª—˜—p‰Â”\‚Ȋ‹«‚ð—‰ð‚µ‚Ä‚­‚¾‚³‚¢B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    HibernateƒfƒBƒXƒgƒŠƒrƒ…[ƒVƒ‡ƒ“‚Ì <literal>eg/</literal> ƒfƒBƒŒƒNƒgƒŠ‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+                    ŠÈ’P‚ȃXƒ^ƒ“ƒhƒAƒ[ƒ“‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚ª‚ ‚è‚Ü‚·B
+                    JDBCƒhƒ‰ƒCƒo‚ð <literal>lib/</literal> ƒfƒBƒŒƒNƒgƒŠ‚ɃRƒs[‚µ‚āA
+                    Ž©•ª‚̃f[ƒ^ƒx[ƒX‚ɍ‡‚¤³‚µ‚¢’l‚ðŽw’è‚·‚é‚悤‚É <literal>etc/hibernate.properties</literal> 
+                    ‚ð•ÒW‚µ‚Ä‚­‚¾‚³‚¢B
+                    ƒfƒBƒXƒgƒŠƒrƒ…[ƒVƒ‡ƒ“ƒfƒBƒŒƒNƒgƒŠ‚©‚çAƒRƒ}ƒ“ƒhƒvƒƒ“ƒvƒg‚Å
+                     <literal>ant eg</literal> ‚ƃ^ƒCƒv‚µ‚Ä‚­‚¾‚³‚¢iAnt‚ðŽg‚¢‚Ü‚·jB
+                    ‚Ü‚½WindowsŠÂ‹«‚Å‚Í <literal>build eg</literal> ‚ƃ^ƒCƒv‚µ‚Ä‚­‚¾‚³‚¢B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ‚±‚̃Šƒtƒ@ƒŒƒ“ƒXƒhƒLƒ…ƒƒ“ƒg‚ð‘æˆê‚̏î•ñŒ¹‚Æ‚µ‚Ä—˜—p‚µ‚Ä‚­‚¾‚³‚¢B
+                    ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ÝŒv‚ɂ‚¢‚Ä‚Ì‚³‚ç‚È‚éî•ñ‚â’iŠK“I‚ȃ`ƒ…[ƒgƒŠƒAƒ‹‚ð’T‚µ‚Ä‚¢‚é‚È‚çA
+                    <emphasis>Hibernate in Action</emphasis>ihttp://www.manning.com/bauerj
+                    ‚ð‚¨‚·‚·‚ß‚µ‚Ü‚·B
+                    ‚Ü‚½http://caveatemptor.hibernate.org‚©‚ç
+                    Hibernate in Action‚Ì—á‘è‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚ðƒ_ƒEƒ“ƒ[ƒh‚Å‚«‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    FAQ‚ÍHibernateƒEƒFƒuƒTƒCƒg‚É‚ ‚è‚Ü‚·B
+                </para>
+            </listitem>
+			<listitem>
+                <para>
+                    ƒT[ƒhƒp[ƒeƒB‚̃fƒ‚A—áAƒ`ƒ…[ƒgƒŠƒAƒ‹‚ÍHibernateƒEƒFƒuƒTƒCƒg‚ɃŠƒ“ƒN‚ª‚ ‚è‚Ü‚·B
+                </para>
+			</listitem>
+            <listitem>
+                <para>
+                    HibernateƒEƒFƒuƒTƒCƒg‚̃Rƒ~ƒ…ƒjƒeƒBƒGƒŠƒA‚́AƒfƒUƒCƒ“ƒpƒ^[ƒ“‚₳‚Ü‚´‚Ü‚È“‡ƒ\ƒŠƒ…[ƒVƒ‡ƒ“
+                    iTomcat, JBoss AS, Struts, EJB, “™j‚ɂ‚¢‚Ä‚Ì‚æ‚¢î•ñŒ¹‚Å‚·B
+                </para>
+            </listitem>
+         </orderedlist>
+
+         <para>
+             Ž¿–₪‚ ‚ê‚ÎHibernateƒEƒFƒuƒTƒCƒg‚̃†[ƒUƒtƒH[ƒ‰ƒ€‚ðŠˆ—p‚µ‚Ä‚­‚¾‚³‚¢B
+             ‚Ü‚½ƒoƒOƒŒƒ|[ƒg‚ƃtƒB[ƒ`ƒƒƒŠƒNƒGƒXƒg‚Ì‚½‚ßJIRA‰Û‘è’ǐՃVƒXƒeƒ€‚ð—pˆÓ‚µ‚Ä‚¢‚Ü‚·B
+             Hibernate‚ÌŠJ”­‚É‹»–¡‚ª‚ ‚ê‚΁AŠJ”­ŽÒƒ[ƒŠƒ“ƒOƒŠƒXƒg‚ÉŽQ‰Á‚µ‚Ä‚­‚¾‚³‚¢B
+             ‚±‚̃hƒLƒ…ƒƒ“ƒg‚ð‚ ‚È‚½‚̍‘‚ÌŒ¾—t‚É–|–󂵂½‚¢ê‡‚́A
+             ŠJ”­ŽÒƒ[ƒŠƒ“ƒOƒŠƒXƒg‚ÅŽ„‚½‚¿‚ɃRƒ“ƒ^ƒNƒg‚ðŽæ‚Á‚Ä‚­‚¾‚³‚¢B
+         </para>
+
+         <para>
+             ¤—pŠJ”­‚̃Tƒ|[ƒgA»•i‚̃Tƒ|[ƒgAHibernate‚̃gƒŒ[ƒjƒ“ƒO‚ÍJBoss Inc.‚ª’ñ‹Ÿ‚µ‚Ä‚¢‚Ü‚·
+             ihttp://www.hibernate.org/SupportTraining/‚ðŒ©‚Ä‚­‚¾‚³‚¢jB
+             Hibernate‚ÍProfessional Open SourceƒvƒƒWƒFƒNƒgA
+             ‚»‚µ‚ÄJBoss Enterprise Middleware SystemiJEMSjƒvƒƒ_ƒNƒgƒXƒC[ƒg‚̃NƒŠƒeƒBƒJƒ‹ƒRƒ“ƒ|[ƒlƒ“ƒg‚Å‚·B
+         </para>
+
+           <sect1 id="preface-s1" revision="-1">
+           
+               <title>“ú–{Œê–ó‚ɂ‚¢‚Ä</title>
+             
+               <para id="preface-s1-p1" revision="-1">
+                   ‚±‚Ì“ú–{Œê”ÅHibernate Reference DocumentiˆÈ‰ºA“ú–{Œê”Łj‚́A
+                   HibernateƒvƒƒWƒFƒNƒg‚Ì–|–óƒvƒƒZƒX‚ÉŠî‚¢‚č쐬‚³‚ê‚Ä‚¢‚Ü‚·B
+                   “ú–{Œê”Å‚È‚ç‚Ñ‚ÉŒ´•¶‚ÍLGPLƒ‰ƒCƒZƒ“ƒX‚ɏ€‚¶‚Ü‚·B
+               </para>
+             
+               <para id="preface-s1-p2" revision="-1">
+                   “ú–{Œê”Å‚Ì—˜—p‚É‚æ‚Á‚Ä‘æŽOŽÒ‚ª”í‚é‚ ‚ç‚ä‚é•s—˜‰v‚ɑ΂µ‚āA
+                   Œ´’˜ŽÒA–|–óŽÒ‚È‚ç‚Ñ‚É‚»‚Ì‘gD‚͈êØ‚Ì•ÛØ‚ð‚¢‚½‚µ‚©‚Ë‚Ü‚·B
+                   “ú–{Œê”Å‚ÍŒë‚è‚ðŠÜ‚މ”\«‚ª‚ ‚邱‚Æ‚ð”FŽ¯‚µ‚½ã‚Å‚²—˜—p‚­‚¾‚³‚¢B
+                   “à—e‚̐³Šm‚ȈӖ¡‚ð”cˆ¬‚·‚邽‚߂ɂ́AŒ´•¶‚ð“Ç‚Þ‚±‚Æ‚ð‚¨‚·‚·‚ß‚µ‚Ü‚·B
+                   ‚Ü‚½A‚à‚µ“ú–{Œê”Å‚ÉŒë‚è‚ðŒ©‚Â‚¯‚ç‚ꂽê‡‚́A–|–óŽÒ‚É‚²˜A—‚¢‚½‚¾‚¯‚ê‚΍K‚¢‚Å‚·B
+                   ‚½‚¾‚µ“à—e‚ÉŠÖ‚µ‚Ä‚Ì‚¨–â‚¢‡‚킹‚ɂ͉ž‚¶‚©‚Ë‚Ü‚·‚̂ŁA‚²—¹³‚­‚¾‚³‚¢B
+               </para>
+             
+               <sect2 id="preface-s1-1" revision="-1">
+               
+                   <title>“ú–{Œê”Å–|–óŽÒ‚ɂ‚¢‚Ä</title>
+               
+                   <para id="preface-s1-1-p4" revision="-1">
+                       “ú–{Œê”Ńo[ƒWƒ‡ƒ“3.2 cr3‚Ì–|–ó‚ÍŠ”Ž®‰ïŽÐƒGƒNƒT
+                       i<ulink url="http://www.exa-corp.co.jp">ƒz[ƒ€ƒy[ƒW‚Í‚±‚¿‚ç</ulink>j
+                       ‚̈ȉº‚̃ƒ“ƒo[‚ōs‚¢‚Ü‚µ‚½B
+                       –{ŠÔ—́i6,18,19,21,22,23Í’S“–jA
+                       LŒË—T‰îi‘O‘‚«,2,5,13,14,24,25Í’S“–jA
+                       •Žs³li7,8,9,10Í’S“–jA
+                       “ߐ{G’ji12,16,17Í’S“–jA
+                       ˆäŠÖ’m•¶i1,3,11Í’S“–jA
+                       ”Ñ“c_Žii4,15Í’S“–jA
+                       •½ŠÔŒ’ˆêi20Í’S“–jA
+                       X—´“ñiƒŒƒrƒ…[’S“–jB
+                       ‚È‚¨Œë–ó“™‚Ì‚²Žw“E‚Í–{ŠÔALŒË‚Ü‚Å‚¨Šè‚¢‚¢‚½‚µ‚Ü‚·B
+                       
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/mailaddr.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/mailaddr.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+                   </para>
+               </sect2>
+           </sect1>
+
+    </preface>
+
+    &tutorial;
+
+    &architecture;
+
+    &configuration;
+
+    &persistent-classes;
+
+    &basic-mapping;
+    &collection-mapping;
+    &association-mapping;
+    &component-mapping;
+    &inheritance-mapping;
+
+    &session-api;
+    &transactions;
+    &events;
+    &batch;
+
+    &query-hql;
+    &query-criteria;
+    &query-sql;
+    &filters;
+    &xml;
+
+    &performance;
+
+    &toolset-guide;
+
+    &example-parentchild;
+    &example-weblog;
+    &example-mappings;
+
+    &best-practices;
+
+</book>
+

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/architecture.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/architecture.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/architecture.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,375 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="architecture">
+
+    <title>ƒA[ƒLƒeƒNƒ`ƒƒ</title>
+
+    <sect1 id="architecture-overview" revision="1">
+        <title>ŠTŠÏ</title>
+        
+        <para>
+            HibernateƒA[ƒLƒeƒNƒ`ƒƒ‚́i”ñí‚Ɂj‚‚¢ƒŒƒxƒ‹‚©‚ç‚̃rƒ…[F
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/overview.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/overview.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            ‚±‚̐}‚ÍHibernate‚ªAƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ɑ΂µ‚ĉi‘±‰»ƒT[ƒrƒX
+            i‚Ɖi‘±ƒIƒuƒWƒFƒNƒgj‚ð’ñ‹Ÿ‚·‚邽‚߂ɁAƒf[ƒ^ƒx[ƒX‚Ɛݒèƒf[ƒ^‚ðŽg‚¤‚±‚Æ‚ð
+            Ž¦‚µ‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <para>
+            ‚±‚±‚ÅŽÀsŽžƒA[ƒLƒeƒNƒ`ƒƒ‚Ì‚æ‚èÚ×‚ȃrƒ…[‚ð‚¨Œ©‚¹‚µ‚Ü‚µ‚傤B
+            ‚ ‚¢‚É‚­AHibernate‚͏_“î‚Å‚ ‚èA‚¢‚ë‚¢‚ë‚ȃAƒvƒ[ƒ`‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·B
+            ‚±‚±‚ł́A2‚‚̋ɒ[‚È—á‚ð‚¨Œ©‚¹‚µ‚Ü‚·B
+            uŒy‚¢vƒA[ƒLƒeƒNƒ`ƒƒ‚ł́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ªŽ©‘O‚ÌJDBCƒRƒlƒNƒVƒ‡ƒ“‚ð—pˆÓ‚µA
+            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“Ž©g‚ªƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðŠÇ—‚µ‚Ü‚·B
+            ‚±‚Ì•û–@‚́AHibernate API‚̍ŏ¬ŒÀ‚̃TƒuƒZƒbƒg‚ðŽg‚¢‚Ü‚·F
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/lite.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/lite.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            ud‚¢vƒA[ƒLƒeƒNƒ`ƒƒ‚́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚©‚çA‚»‚̉º‚Ɉʒu‚·‚éJDBC‚âJTA‚ÌAPI‚ð
+            Žæ‚è•¥‚Á‚Ä’ŠÛ‰»‚µA‚»‚̏ڍׂ̖ʓ|‚ðHibernate‚ÉŒ©‚³‚¹‚Ü‚·B
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/full_cream.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/full_cream.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            ˆÈ‰º‚́Aã‚̐}‚ÉŠÜ‚Ü‚ê‚éƒIƒuƒWƒFƒNƒg‚Ì’è‹`‚Å‚·F
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
+                    <listitem>
+                        <para>
+                            1‚‚̃f[ƒ^ƒx[ƒX‚ɑ΂·‚éƒRƒ“ƒpƒCƒ‹‚³‚ꂽƒ}ƒbƒsƒ“ƒO‚Ì
+                            ƒXƒŒƒbƒhƒZ[ƒt‚ȁiXV•s”\‚́jƒLƒƒƒbƒVƒ…B
+                             <literal>Session</literal> ‚̃tƒ@ƒNƒgƒŠ‚Å‚ ‚èA
+                            <literal>ConnectionProvider</literal> ‚̃Nƒ‰ƒCƒAƒ“ƒgB
+                            ƒIƒvƒVƒ‡ƒ“‚Æ‚µ‚āAƒvƒƒZƒX‚Ü‚½‚̓Nƒ‰ƒXƒ^ƒŒƒxƒ‹‚É‚¨‚¢‚āA
+                            ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ŠÔ‚ōė˜—p‰Â”\‚ȃf[ƒ^‚́i“ñŽŸjƒLƒƒƒbƒVƒ…‚ðŽ‚¿‚Ü‚·B
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Session (<literal>org.hibernate.Session</literal>)</term>
+                    <listitem>
+                        <para>
+                            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚Ɖi‘±ƒXƒgƒA‚Ƃ̑Θb‚ð•\‚·A
+                            ƒVƒ“ƒOƒ‹ƒXƒŒƒbƒh‚Å’Z–½‚̃IƒuƒWƒFƒNƒgB
+                            JDBCƒRƒlƒNƒVƒ‡ƒ“‚ðƒ‰ƒbƒv‚µ‚Ü‚·B
+                             <literal>Transaction</literal> ‚̃tƒ@ƒNƒgƒŠ‚Å‚·B
+                            ‰i‘±ƒIƒuƒWƒFƒNƒg‚Ì•K{‚́iˆêŽŸjƒLƒƒƒbƒVƒ…‚ð•ÛŽ‚µ‚Ü‚·B
+                            ‚±‚̃LƒƒƒbƒVƒ…‚̓IƒuƒWƒFƒNƒgƒOƒ‰ƒt‚ðƒiƒrƒQ[ƒVƒ‡ƒ“‚·‚鎞‚âA
+                            Ž¯•ÊŽq‚ŃIƒuƒWƒFƒNƒg‚ðŒŸõ‚·‚鎞‚ÉŽg‚í‚ê‚Ü‚·B
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Persistent objects ‚Æ Collections</term>
+                    <listitem>
+                        <para>
+                            ‰i‘±‰»ó‘ԂƃrƒWƒlƒXƒƒ\ƒbƒh‚ðŽ‚ÂA’Z–½‚ŃVƒ“ƒOƒ‹ƒXƒŒƒbƒh‚̃IƒuƒWƒFƒNƒgB
+                            ‚±‚ê‚͒ʏí‚ÌJavaBeans/POJO‚Ì‚±‚Æ‚à‚ ‚è‚Ü‚·‚ªA“Á’¥“I‚È‚±‚Ƃ́A
+                            ‚»‚ÌŽž“_‚ł́i‚½‚¾1‚‚́j <literal>Session</literal> ‚ÆŠÖ˜A‚µ‚Ä‚¢‚邱‚Æ‚Å‚·B
+                             <literal>Session</literal> ‚ªƒNƒ[ƒY‚³‚ê‚é‚Æ‚·‚®‚ɁA
+                            ‚»‚ê‚ç‚͐؂藣‚³‚ê‚Ä‘¼‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‘w‚©‚玩—R‚ÉŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+                            i—Ⴆ‚΃f[ƒ^Eƒgƒ‰ƒ“ƒXƒtƒ@EƒIƒuƒWƒFƒNƒg‚Æ‚µ‚āA
+                            ƒvƒŒƒ[ƒ“ƒe[ƒVƒ‡ƒ“‘w‚©‚çA‚Ü‚½‚̓vƒŒƒ[ƒ“ƒe[ƒVƒ‡ƒ“‘w‚Ö’¼ÚŽg—p‚Å‚«‚Ü‚·Bj
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Transient ‚Æ detached ‚È objects ‚Æ Collections</term>
+                    <listitem>
+                        <para>
+                            Œ»Žž“_‚Å‚Í <literal>Session</literal> ‚ÆŠÖ˜A‚µ‚Ä‚¢‚È‚¢A
+                            ‰i‘±ƒNƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒXB
+                            ‚·‚łɃAƒvƒŠƒP[ƒVƒ‡ƒ“‘¤‚ŃCƒ“ƒXƒ^ƒ“ƒX‰»‚³‚ê‚Ä‚¢‚āA‚Ü‚¾‰i‘±‰»‚³‚ê‚Ä‚¢‚È‚¢‚©A
+                            ƒNƒ[ƒY‚³‚ꂽ <literal>Session</literal> ‚ŃCƒ“ƒXƒ^ƒ“ƒX‰»‚³‚ꂽ‚©‚Ì‚Ç‚¿‚ç‚©‚Å‚·B
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
+                    <listitem>
+                        <para>
+                            (ƒIƒvƒVƒ‡ƒ“)Œ´Žq«‚ðŽ‚Âì‹Æ’PˆÊ(Unit of Work)‚ðŽw’è‚·‚邽‚߂ɁAƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ªŽg—p‚·‚éA
+                            ƒVƒ“ƒOƒ‹ƒXƒŒƒbƒh‚Å’Z–½‚ȃIƒuƒWƒFƒNƒgB
+                            ‰º‚Ɉʒu‚·‚éJDBCAJTAACORBAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚©‚çƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚𒊏ۉ»‚µ‚Ü‚·B
+                             <literal>Session</literal> ‚́AŽž‚É‚Í
+                            ‚¢‚­‚‚©‚Ì <literal>Transaction</literal> ‚ð‚Ü‚½‚ª‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                            ‚µ‚©‚µA‰º‚Ì‘w‚ÌAPI‚ðŽg‚¤‚É‚¹‚æA <literal>Transaction</literal> ‚ðŽg‚¤‚É‚¹‚æA
+                            ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚ðÝ’è‚·‚邱‚Ƃ́AŒˆ‚µ‚ăIƒvƒVƒ‡ƒ“‚Å‚Í‚ ‚è‚Ü‚¹‚ñIB
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
+                    <listitem>
+                        <para>
+                            (ƒIƒvƒVƒ‡ƒ“)JDBCƒRƒlƒNƒVƒ‡ƒ“i‚Æ‚»‚̃v[ƒ‹j‚̃tƒ@ƒNƒgƒŠB
+                            ‰º‚Ì‘w‚Ɉʒu‚·‚é <literal>Datasource</literal> ‚â
+                             <literal>DriverManager</literal> ‚©‚çƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚𒊏ۉ»‚µ‚Ü‚·B
+                            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚ÍŒöŠJ‚³‚ê‚Ü‚¹‚ñ‚ªAŠJ”­ŽÒ‚ªŒp³‚Ü‚½‚ÍŽÀ‘•‚·‚邱‚Ƃ͉”\‚Å‚·B
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
+                    <listitem>
+                        <para>
+                            (ƒIƒvƒVƒ‡ƒ“) <literal>Transaction</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚̃tƒ@ƒNƒgƒŠB
+                            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚ÍŒöŠJ‚³‚ê‚Ü‚¹‚ñ‚ªAŠJ”­ŽÒ‚ªŒp³‚Ü‚½‚ÍŽÀ‘•‚·‚邱‚Ƃ͉”\‚Å‚·B
+                         </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><emphasis>Extension Interfaces</emphasis></term>
+                    <listitem>
+                        <para>
+                            Hibernate‚́A‰i‘±‘w‚̐U‚é•‘‚¢‚ðƒJƒXƒ^ƒ}ƒCƒY‚·‚邽‚߂ɁA
+                            ‘½‚­‚̃IƒvƒVƒ‡ƒ“Šg’£ƒCƒ“ƒ^ƒtƒF[ƒX‚ð—pˆÓ‚µ‚Ä‚¢‚Ü‚·B
+                            Ú×‚ÍAPIƒhƒLƒ…ƒƒ“ƒg‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+        </para>
+
+        <para>
+            uŒy‚¢vƒA[ƒLƒeƒNƒ`ƒƒ‚ł́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚Í’¼ÚJTA‚âJDBC‚ƑΘb‚·‚邽‚߂ɁA
+             <literal>Transaction</literal> ‚â <literal>TransactionFactory</literal> ‚â
+             <literal>ConnectionProvider</literal> ‚ðƒoƒCƒpƒX‚µ‚Ü‚·B
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-states" revision="1">
+        <title>ƒCƒ“ƒXƒ^ƒ“ƒX‚̏ó‘Ô</title>
+        <para>
+            ‰i‘±ƒNƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚́AŽŸ‚Ì‚R‚‚̈قȂéó‘Ô‚Ì‚Ç‚ê‚©‚É‚È‚è‚Ü‚·B
+            ‚»‚ê‚́A <emphasis>‰i‘±ƒRƒ“ƒeƒLƒXƒg</emphasis> ‚É‚æ‚Á‚ÄŒˆ‚Ü‚è‚Ü‚·B
+            Hibernate‚Ì <literal>Session</literal> ƒIƒuƒWƒFƒNƒg‚ªA‰i‘±ƒRƒ“ƒeƒLƒXƒg‚É‚È‚è‚Ü‚·B
+        </para>
+        
+       <variablelist spacing="compact">
+            <varlistentry>
+                <term>transient</term>
+                <listitem>
+                    <para>
+                        ‚±‚̏ó‘Ԃ̃Cƒ“ƒXƒ^ƒ“ƒX‚́AŒ»Ý‚à‚»‚µ‚ĉߋŽ‚É‚¨‚¢‚Ä‚àA
+                        ‰i‘±ƒRƒ“ƒeƒLƒXƒg‚ÉŠÖ˜A‚¢‚Ä‚¢‚Ü‚¹‚ñB‚Ü‚½A‰i‘±IDiŽåƒL[‚Ì’lj‚ð
+                        Ž‚Á‚Ä‚¢‚Ü‚¹‚ñB
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>persistent</term>
+                <listitem>
+                    <para>
+                        ‚±‚̏ó‘Ԃ̃Cƒ“ƒXƒ^ƒ“ƒX‚́A‚»‚ÌŽž“_‚ʼni‘±ƒRƒ“ƒeƒLƒXƒg‚ÉŠÖ˜A‚¢‚Ä‚¢‚Ü‚·B
+                        ‚Ü‚½A‰i‘±IDiŽåƒL[‚Ì’lj‚ðŽ‚¿A
+                        ‚½‚¢‚Ä‚¢‚̓f[ƒ^ƒx[ƒX‚ɑΉž‚·‚és‚ðŽ‚Á‚Ä‚¢‚é‚Å‚µ‚傤B
+                        ŒÂX‚̉i‘±ƒRƒ“ƒeƒLƒXƒg‚Ì‚È‚©‚ł́A‰i‘±ID‚ª
+                        Java‚ÌIDiƒIƒuƒWƒFƒNƒg‚̃ƒ‚ƒŠã‚̈ʒuj‚Æ“¯‚¶‚Å‚ ‚邱‚Æ‚ð
+                        Hibernate‚ª <emphasis>•ÛØ</emphasis> ‚µ‚Ü‚·B
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>detached</term>
+                <listitem>
+                    <para>
+                        ‚±‚̏ó‘Ԃ̃Cƒ“ƒXƒ^ƒ“ƒX‚́A‚©‚‚ĉi‘±ƒRƒ“ƒeƒLƒXƒg‚ÉŠÖ˜A‚¯‚ç‚ꂽ‚ªA
+                        ‚»‚̃Rƒ“ƒeƒLƒXƒg‚ªƒNƒ[ƒY‚³‚ꂽ‚©A‚ ‚é‚¢‚́A
+                        ‘¼‚̃vƒƒZƒX‚É‚»‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ªƒVƒŠƒAƒ‰ƒCƒY‚³‚ꂽ‚©‚Å‚·B
+                        ‚±‚̃Cƒ“ƒXƒ^ƒ“ƒX‚́A‰i‘±ID‚ðŽ‚¿A‚½‚¢‚Ä‚¢‚̓f[ƒ^ƒx[ƒX‚É
+                        ‘Ήž‚·‚és‚ðŽ‚Á‚Ä‚¢‚é‚Å‚µ‚傤B•ª—£ƒCƒ“ƒXƒ^ƒ“ƒX‚ɑ΂µ‚ẮA
+                        ‰i‘±ID‚ÆJava‚ÌID‚Æ‚ÌŠÖ˜A‚́AHibernate‚ª•ÛØ‚µ‚Ü‚¹‚ñB
+                    </para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </sect1>    
+
+    <sect1 id="architecture-jmx" revision="1">
+        <title>JMX‚Æ‚Ì“‡</title>
+
+        <para>
+            JMX‚ÍJavaƒRƒ“ƒ|[ƒlƒ“ƒgŠÇ—‚ÌJ2EE•W€‚Å‚·B
+            JMX•W€ƒT[ƒrƒX‚ð’Ê‚µ‚āAHibernate‚ÍŠÇ—‚³‚ê‚Ü‚·B
+            ƒfƒBƒXƒgƒŠƒrƒ…[ƒVƒ‡ƒ“‚Ì’†‚É <literal>org.hibernate.jmx.HibernateService</literal> ‚Æ‚¢‚¤
+            MBeanŽÀ‘•‚ð—pˆÓ‚µ‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <para>
+            JBoss ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo[ã‚ÉHibernate‚ðJMXƒT[ƒrƒX‚Æ‚µ‚ăfƒvƒƒC‚·‚é•û–@‚Ì—á‚Æ‚µ‚ẮA
+            JBoss ƒ†[ƒUƒKƒCƒh‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B JBoss ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo[‚É‚¨‚¢‚āA
+            JMX‚ðŽg‚Á‚ăfƒvƒƒC‚·‚é‚ƁAŽŸ‚̃ƒŠƒbƒg‚ª“¾‚ç‚ê‚Ü‚·B
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>ƒZƒbƒVƒ‡ƒ“ŠÇ—:</emphasis> Hibernate‚Ì <literal>Session</literal> ‚̃‰ƒCƒtƒTƒCƒNƒ‹‚́A
+                    Ž©“®“I‚ÉJTAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̃XƒR[ƒv‚ÉŒ‹‚т‚¯‚ç‚ê‚Ü‚·B‚±‚ê‚́A‚à‚Í‚âŽè“®‚Å
+                     <literal>Session</literal> ‚ðƒI[ƒvƒ“‚µ‚½‚èAƒNƒ[ƒY‚µ‚½‚è‚·‚é•K—v‚ª‚È‚¢‚±‚Æ‚ðˆÓ–¡‚µ‚Ü‚·B
+                    ‚±‚ê‚́AJBoss EJB ƒCƒ“ƒ^[ƒZƒvƒ^‚ÌŽdŽ–‚É‚È‚è‚Ü‚·B
+                    ‚Ü‚½AƒR[ƒh‚Ì‚Ç‚±‚Ńgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚ðÝ’è‚·‚é‚©‚ɂ‚¢‚āA
+                    ‚à‚Í‚â”Y‚Þ•K—v‚ª‚ ‚è‚Ü‚¹‚ñi‚à‚¿‚ë‚ñˆÚA‰Â”\‚ȉi‘±‘w‚ð‘‚©‚©‚È‚­‚Ä‚¢‚¢‚Ì‚È‚ç‚΁A
+                    ƒIƒvƒVƒ‡ƒ“‚ÌHibernate‚Ì <literal>Transaction</literal> ‚ðŽg—p‚µ‚Ä‚­‚¾‚³‚¢Bj
+                    <literal>Session</literal> ‚ɃAƒNƒZƒX‚·‚邽‚߂ɂ́A <literal>HibernateContext</literal> ‚ð
+                    ƒR[ƒ‹‚µ‚Ä‚­‚¾‚³‚¢B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>HAR ƒfƒvƒƒC:</emphasis> ’ʏíA(EAR ‚Ü‚½‚Í SAR ƒtƒ@ƒCƒ‹‚É‚ ‚éjJBoss ƒT[ƒrƒX
+                    ƒfƒvƒƒCƒƒ“ƒgƒfƒBƒXƒNƒŠƒvƒ^‚ðŽg‚Á‚āAHibernate JMX ƒT[ƒrƒX‚ðƒfƒvƒƒC‚µ‚Ü‚·B
+                    ‚»‚ê‚́AHibernate‚Ì <literal>SessionFactory</literal> ‚Ì‘S‚Ă̈ê”Ê“I‚ȐݒèƒIƒvƒVƒ‡ƒ“‚ð
+                    ƒTƒ|[ƒg‚µ‚Ü‚·B‚µ‚©‚µˆË‘R‚Æ‚µ‚ăfƒvƒƒCƒƒ“ƒgƒfƒBƒXƒNƒŠƒvƒ^‚Ì‚È‚©‚É‚·‚ׂẴ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚Ì
+                    –¼‘O‚ð‹“‚°‚é•K—v‚ª‚ ‚è‚Ü‚·B
+                    ‚à‚µAƒIƒvƒVƒ‡ƒ“‚ÌHARƒfƒvƒƒCƒƒ“ƒg‚ðŽg‚¤‚±‚Æ‚ðŒˆ‚ß‚½‚È‚çA
+                    JBoss‚ÍŽ©“®“I‚ÉHARƒtƒ@ƒCƒ‹‚Ì‚È‚©‚Ì‘S‚Ẵ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ðŒŸo‚µ‚Ü‚·B
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            ‚±‚ê‚ç‚̃IƒvƒVƒ‡ƒ“‚ɂ‚¢‚Ă̏ڍׂȏî•ñ‚́AJBossƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒoƒ†[ƒUƒKƒCƒh‚ð
+            ŽQl‚É‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <para>
+            JMXƒT[ƒrƒX‚Æ‚µ‚Ä—˜—p‰Â”\‚È‘¼‚Ì‹@”\‚ɁAHibernateŽÀsŽž“Œvî•ñ‚ª‚ ‚è‚Ü‚·B
+             <xref linkend="configuration-optional-statistics"/> ‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-jca" revision="1">
+        <title>JCA ƒTƒ|[ƒg</title>
+        <para>
+            Hibernate ‚Í JCA ƒRƒlƒNƒ^‚Æ‚µ‚Ä‚àÝ’è‚Å‚«‚Ü‚·BÚ×‚ɂ‚¢‚ẮAWebƒTƒCƒg‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+            Hibernate JCA ƒTƒ|[ƒg‚́A¡‚Ì‚Æ‚±‚ëŽÀŒ±’iŠK‚Æ‚µ‚čl‚¦‚ç‚ê‚Ä‚¢‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-current-session" revision="2">
+        <title>ƒRƒ“ƒeƒLƒXƒgã‚̃ZƒbƒVƒ‡ƒ“</title>
+        <para>
+            Hibernate ‚ðŽg‚Á‚½ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚́A‚Ù‚Æ‚ñ‚ǁA‚È‚ñ‚ç‚©‚ÌŒ`‚Å"ƒRƒ“ƒeƒLƒXƒgã‚Ì"ƒZƒbƒVƒ‡ƒ“‚ª•K—v‚É‚È‚è‚Ü‚·B
+            uƒRƒ“ƒeƒLƒXƒgã‚̃ZƒbƒVƒ‡ƒ“v‚́A“Á’è‚̃Rƒ“ƒeƒLƒXƒg‚̃XƒR[ƒv‚Ì‚È‚©‚Å—LŒø‚ȃZƒbƒVƒ‡ƒ“‚Ì‚±‚Æ‚Å‚·B
+            ‚µ‚©‚µA’ʏíƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚²‚ƂɃRƒ“ƒeƒLƒXƒg‚ð\¬‚·‚é‚à‚Ì‚Ì’è‹`‚͈قȂè‚Ü‚·B
+            ‚µ‚©‚àAˆÙ‚È‚é•¡”‚̃Rƒ“ƒeƒLƒXƒg‚́AŒ»Žž“_‚ɑ΂µ‚ĈقȂéƒXƒR[ƒv‚ð’è‹`‚µ‚Ü‚·B
+            ƒo[ƒWƒ‡ƒ“3.0‚æ‚è‘O‚Ì Hibernate ‚ł́AŽ©ì‚Ì <literal>ThreadLocal</literal> ƒx[ƒX‚́uƒRƒ“ƒeƒLƒXƒgã‚̃ZƒbƒVƒ‡ƒ“v‚ð
+            —˜—p‚·‚é‚©A <literal>HibernateUtil</literal> ‚̂悤‚ȃwƒ‹ƒp[ƒNƒ‰ƒX‚ð—˜—p‚·‚é‚©A
+            proxy/interception ƒx[ƒX‚́uƒRƒ“ƒeƒLƒXƒgã‚̃ZƒbƒVƒ‡ƒ“v‚ð’ñ‹Ÿ‚·‚é
+            iSpring ‚â Pico ‚̂悤‚ȁjƒT[ƒhƒp[ƒeƒB‚̃tƒŒ[ƒ€ƒ[ƒN‚ð—˜—p‚·‚é‚©‚Ì‚¢‚¸‚ê‚©‚Å‚µ‚½B
+        </para>
+
+        <para>
+            ƒo[ƒWƒ‡ƒ“ 3.0.1 ‚©‚çAHibernate ‚É‚Í <literal>SessionFactory.getCurrentSession()</literal> ‚ª
+            ‰Á‚í‚è‚Ü‚µ‚½B ‚±‚ê‚́A <literal>JTA</literal> ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÌŽg—p‚ð‘O’ñ‚É‚µ‚Ä‚¢‚Ü‚·B
+            <literal>JTA</literal> ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚́AŒ»Ý‚̃ZƒbƒVƒ‡ƒ“‚̃XƒR[ƒv‚ƃRƒ“ƒeƒLƒXƒg‚Ì—¼•û‚ð’è‹`‚µ‚Ü‚·B
+            Hibernate ƒ`[ƒ€‚́AŽŸ‚Ì‚±‚Æ‚ðŽå’£‚µ‚Ü‚·B
+            ‹‘å‚ȃXƒ^ƒ“ƒhƒAƒƒ“‚Ì <literal>JTA TransactionManager</literal> ŽÀ‘•‚ª¬n‚µ‚½‚çA
+            <literal>J2EE</literal> ƒRƒ“ƒeƒiã‚ɃfƒvƒƒC‚³‚ê‚é‚©‚Ç‚¤‚©‚É‚©‚©‚í‚炸A
+            ‚Ù‚Æ‚ñ‚ǂ́i‚·‚ׂĂƂ͌¾‚í‚È‚¢‚ªjƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ªA
+            <literal>JTA</literal> ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ŠÇ—‚ðŽg—p‚·‚ׂ«‚Å‚ ‚é‚ƁB
+            ‚±‚̍l‚¦‚ÉŠî‚­‚ƁA <literal>JTA</literal> ƒx[ƒX‚́uƒRƒ“ƒeƒLƒXƒgã‚̃ZƒbƒVƒ‡ƒ“v‚ð
+            Žg‚¤‚µ‚©‚È‚¢‚Å‚µ‚傤B
+        </para>
+
+        <para>
+            ‚µ‚©‚µAƒo[ƒWƒ‡ƒ“ 3.1 ‚©‚ç‚́A <literal>SessionFactory.getCurrentSession()</literal> ‚ÌŒã‚̏ˆ—‚ªA
+            ƒvƒ‰ƒKƒuƒ‹‚É‚È‚è‚Ü‚µ‚½B
+            ‚±‚ê‚ðŽó‚¯‚āAŒ»Ý‚̃ZƒbƒVƒ‡ƒ“‚ð’è‹`‚·‚éƒXƒR[ƒv‚ƃRƒ“ƒeƒLƒXƒg‚̃vƒ‰ƒKƒrƒŠƒeƒB‚ð‰Â”\‚É‚·‚邽‚߂ɁA
+            V‚µ‚¢Šg’£ƒCƒ“ƒ^ƒtƒF[ƒX ( <literal>org.hibernate.context.CurrentSessionContext</literal> ) ‚Æ
+            V‚µ‚¢\¬ƒpƒ‰ƒ[ƒ^ ( <literal>hibernate.current_session_context_class</literal> ) ‚ª’ljÁ‚³‚ê‚Ü‚µ‚½B
+        </para>
+
+        <para>
+            <literal>org.hibernate.context.CurrentSessionContext</literal> ƒCƒ“ƒ^ƒtƒF[ƒX‚Ì‹K–ñ‚ɂ‚¢‚Ä‚Ì
+            Ú×‚È“à—e‚Í Javadoc ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚»‚ê‚ɂ́A <literal>currentSession()</literal> ‚Æ‚¢‚¤1‚‚̃ƒ\ƒbƒh‚ª’è‹`‚³‚ê‚Ä‚¨‚èA
+            ‚»‚ÌŽÀ‘•‚́AŒ»Ý‚́uƒRƒ“ƒeƒLƒXƒgã‚̃ZƒbƒVƒ‡ƒ“v‚ð’ǐՂ·‚邱‚ƂɐӔC‚ðŽ‚¿‚Ü‚·B
+            ‚»‚Ì‚Ü‚ÜŽg‚¦‚é‚悤‚ɁAHibernate‚Í‚±‚̃Cƒ“ƒ^ƒtƒF[ƒX‚ÌŽÀ‘•‚ð2‚Â’ñ‹Ÿ‚µ‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.context.JTASessionContext</literal> - 
+                    <literal>JTA</literal> ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚É‚æ‚Á‚āAŒ»Ý‚̃ZƒbƒVƒ‡ƒ“‚ª’ǐՂ³‚êA
+                    ƒXƒR[ƒv‚ðŒˆ‚ß‚ç‚ê‚Ü‚·B‚±‚̏ˆ—‚́AŒÃ‚¢JTA‚¾‚¯‚̃Aƒvƒ[ƒ`‚Æ‚Ü‚Á‚½‚­“¯‚¶‚Å‚·B
+                    Ú×‚ÍJavadoc‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.context.ThreadLocalSessionContext</literal> -
+                    ƒXƒŒƒbƒh‚ÌŽÀs‚É‚æ‚Á‚āAŒ»Ý‚̃ZƒbƒVƒ‡ƒ“‚ª’ǐՂ³‚ê‚Ü‚·B
+                    Ú×‚ÍJavadoc‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                	<literal>org.hibernate.context.ManagedSessionContext</literal> - 
+                	ƒXƒŒƒbƒh‚ÌŽÀs‚É‚æ‚Á‚āAŒ»Ý‚̃ZƒbƒVƒ‡ƒ“‚ª’ǐՂ³‚ê‚Ü‚·B
+                	‚µ‚©‚µA‚±‚̃Nƒ‰ƒX‚Ìstaticƒƒ\ƒbƒh‚Å <literal>Session</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚ð
+                	ƒoƒCƒ“ƒh/ƒAƒ“ƒoƒCƒ“ƒh‚·‚éÓ”C‚Í‚ ‚È‚½‚É‚ ‚è‚Ü‚·B
+                	‚±‚ê‚ÍŒˆ‚µ‚Ä <literal>Session</literal> ‚ðƒI[ƒvƒ“Aƒtƒ‰ƒbƒVƒ…AƒNƒ[ƒY‚µ‚Ü‚¹‚ñB
+                </para>               
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Žn‚ß‚Ì2‚‚̎À‘•‚́A"1ƒZƒbƒVƒ‡ƒ“ - 1ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“" ƒvƒƒOƒ‰ƒ~ƒ“ƒOƒ‚ƒfƒ‹‚ð’ñ‹Ÿ‚µ‚Ü‚·B
+            ‚±‚ê‚Í <emphasis>ƒŠƒNƒGƒXƒg‚²‚Ƃ̃ZƒbƒVƒ‡ƒ“isession-per-requestj</emphasis> ‚Æ‚µ‚Ä‚à’m‚ç‚ê‚Ä‚¨‚èAŽg‚í‚ê‚Ä‚¢‚Ü‚·B
+            Hibernate ƒZƒbƒVƒ‡ƒ“‚ÌŠJŽn‚ƏI—¹‚́Aƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÌŠúŠÔ‚ÅŒˆ‚Ü‚è‚Ü‚·B
+            JTA‚ðŽg‚í‚È‚¢•’Ê‚ÌJSE‚ŁAƒvƒƒOƒ‰ƒ€ã‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠEÝ’è‚ðs‚¤‚È‚çA
+            ƒR[ƒh‚©‚çŠî‘b‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ƒVƒXƒeƒ€‚ð‰B•Á‚·‚邽‚߂ɁA
+            Hibernate <literal>Transaction</literal> API‚ðŽg‚¤‚Æ‚æ‚¢‚Å‚µ‚傤B
+            JTA‚ðŽg‚¤‚È‚çAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Ì‹«ŠEÝ’è‚ɂ́AJTAƒCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢B
+            CMT‚ðƒTƒ|[ƒg‚·‚éEJBƒRƒ“ƒeƒi‚ÅŽÀs‚·‚é‚‚à‚è‚È‚çAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚͐錾“I‚É’è‹`‚Å‚«‚邽‚߁A
+            ƒR[ƒhã‚Ńgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚âƒZƒbƒVƒ‡ƒ“‚Ì‹«ŠE‚ðÝ’è‚·‚é•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+            ‚³‚ç‚ɏڍׂȏî•ñ‚âƒR[ƒh‚Ì—á‚́A <xref linkend="transactions"/> ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <para>
+            <literal>hibernate.current_session_context_class</literal> Ý’èƒpƒ‰ƒ[ƒ^‚́A
+            <literal>org.hibernate.context.CurrentSessionContext</literal> ‚Ì‚Ç‚ÌŽÀ‘•‚ðŽg‚¤‚©‚ðŽw’肵‚Ü‚·B
+            ‰ºˆÊŒÝŠ·«‚Ì‚½‚߁A‚±‚̃pƒ‰ƒ[ƒ^‚ªÝ’肳‚ꂸ
+            <literal>org.hibernate.transaction.TransactionManagerLookup</literal> ‚ªÝ’肳‚ê‚Ä‚¢‚½ê‡A
+            Hibernate‚Í <literal>org.hibernate.context.JTASessionContext</literal> ‚ðŽg‚¤‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ’ʏ킱‚̃pƒ‰ƒ[ƒ^‚Ì’l‚ɂ́A3‚‚̎À‘•‚Ì’†‚©‚çŽg—p‚·‚éŽÀ‘•ƒNƒ‰ƒX‚Ì–¼‘O‚𒼐ڎw’肵‚Ü‚·B
+            ‚µ‚©‚µA"jta", "thread", "managed"‚Æ‚¢‚¤‚»‚ꂼ‚ê‚̏ȗª–¼‚à—pˆÓ‚³‚ê‚Ä‚¢‚Ü‚·B
+        </para>
+        
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/association_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/association_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/association_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,620 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="associations">
+
+    <title>ŠÖ˜Aƒ}ƒbƒsƒ“ƒO</title>
+
+    <sect1 id="assoc-intro" revision="1">
+        <title>ƒCƒ“ƒgƒƒ_ƒNƒVƒ‡ƒ“</title>
+        
+        <para>
+            ŠÖ˜Aƒ}ƒbƒsƒ“ƒO‚Í‚µ‚΂µ‚ǝ‰ð‚ªÅ‚à“‚¢‚à‚Ì‚É‚È‚è‚Ü‚·B
+            ‚±‚̏͂ł́AŠî–{“I‚Ȉꂈꂂ̃P[ƒX‚ɂ‚¢‚ďq‚ׂ܂·B
+            ’P•ûŒü‚̃}ƒbƒsƒ“ƒO‚©‚çŽn‚߁A‚»‚ê‚©‚ç‘o•ûŒü‚̃P[ƒX‚ɂ‚¢‚čl‚¦‚Ä‚¢‚«‚Ü‚·B
+            —á‚Æ‚µ‚āA<literal>Person</literal> ‚Æ <literal>Address</literal> ‚ð—p‚¢‚Ü‚·B
+        </para>
+        
+        <para>
+                ŠÖ˜A‚́AŒ‹‡ƒe[ƒuƒ‹‚ð“ü‚ê‚é‚©‚©‚Ç‚¤‚©‚ƁA
+                ‘½d“x‚É‚æ‚Á‚Ä•ª—Þ‚·‚邱‚Æ‚É‚µ‚Ü‚·B
+        </para>
+        
+        <para>
+                ‚·‚ׂĂ̗á‚Ånot null‚ÌŠO•”ƒL[‚ðŽg—p‚µ‚Ü‚·B
+                ‚±‚ê‚ÍHibernate‚Ì—vŒ‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+                not null§–ñ‚ðŠO‚µ‚½‚Æ‚µ‚Ä‚àAƒ}ƒbƒsƒ“ƒO‚Í–â‘è‚È‚­“®ì‚µ‚Ü‚·B
+        </para>
+        
+    </sect1>
+
+    <sect1 id="assoc-unidirectional" revision="1">
+        <title>’P•ûŒüŠÖ˜A</title>
+        
+        <sect2 id="assoc-unidirectional-m21">
+        <title>‘½‘Έê</title>
+        
+        <para>
+            <emphasis>’P•ûŒü‘½‘ΈêŠÖ˜A</emphasis> ‚Í’P•ûŒüŠÖ˜A‚Ì’†‚ōłàˆê”Ê“I‚È‚à‚Ì‚Å‚·B
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-121">
+        <title>ˆê‘Έê</title>
+        
+        <para>
+            <emphasis>ŠO•”ƒL[‚Ì’P•ûŒüˆê‘ΈêŠÖ˜A</emphasis> ‚Í‚Ù‚Æ‚ñ‚Ç“¯‚¶‚à‚Ì‚Å‚·B
+            —Bˆêˆá‚¤‚̂́AƒJƒ‰ƒ€‚̃†ƒj[ƒN‚Ȑ§–ñ‚Å‚·B
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId" 
+        unique="true"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        <para>
+            <emphasis>ŽåƒL[‚Ì’P•ûŒüˆê‘ΈêŠÖ˜A</emphasis> ‚͒ʏíA“Á•Ê‚ÈIDƒWƒFƒlƒŒ[ƒ^‚ðŽg‚¢‚Ü‚·B
+            i‚±‚Ì—á‚Å‚ÍŠÖ˜A‚Ì•ûŒü‚ª‹t‚É‚È‚Á‚Ä‚¢‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢j
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+</class>
+
+<class name="Address">
+    <id name="id" column="personId">
+        <generator class="foreign">
+            <param name="property">person</param>
+        </generator>
+    </id>
+    <one-to-one name="person" constrained="true"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+        <sect2 id="assoc-unidirectional-12m">
+        <title>ˆê‘Α½</title>
+        
+        <para>
+            <emphasis>ŠO•”ƒL[‚Ì’P•ûŒüˆê‘Α½ŠÖ˜A</emphasis> ‚Í‚Æ‚Ä‚à“ÁŽê‚ȃP[ƒX‚ŁA
+            ‚ ‚܂萄§‚³‚ê‚Ä‚¢‚Ü‚¹‚ñB
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses">
+        <key column="personId" 
+            not-null="true"/>
+        <one-to-many class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( addressId bigint not null primary key, personId bigint not null )
+        ]]></programlisting>
+        
+        <para>
+            ‚±‚̂悤‚ÈŠÖ˜A‚Ì‚½‚ß‚ÉŒ‹‡ƒe[ƒuƒ‹‚ðŽg‚¤‚±‚Æ‚ð‚¨‘E‚ß‚µ‚Ü‚·B
+        </para>
+        
+        </sect2>
+    
+    </sect1>
+
+    <sect1 id="assoc-unidirectional-join" revision="1">
+        <title>Œ‹‡ƒe[ƒuƒ‹‚ðŽg‚Á‚½’P•ûŒüŠÖ˜A</title>
+        
+        <sect2 id="assoc-unidirectional-join-12m">
+        <title>ˆê‘Α½</title>
+        
+        <para>
+            <emphasis>Œ‹‡ƒe[ƒuƒ‹‚ðŽg‚Á‚½’P•ûŒüˆê‘Α½ŠÖ˜A</emphasis> 
+            ‚Í‚æ‚èD‚Ü‚µ‚¢‚Å‚·B
+            <literal>unique="true"</literal> ‚ÌŽw’è‚É‚æ‚èA‘½d“x‚ª‘½‘Α½‚©‚çˆê‘Α½
+            ‚É•Ï‚í‚Á‚½‚±‚Æ‚É’ˆÓ‚µ‚ĉº‚³‚¢B
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            unique="true"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-m21">
+        <title>‘½‘Έê</title>
+        
+        <para>
+            <emphasis>Œ‹‡ƒe[ƒuƒ‹‚Ì’P•ûŒü‘½‘ΈêŠÖ˜A</emphasis> ‚Í
+            ŠÖ˜A‚ª”CˆÓ‚Å‚ ‚é‚Æ‚«‚É”ñí‚Ɉê”Ê“I‚È‚à‚Ì‚Å‚·B
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-121">
+        <title>ˆê‘Έê</title>
+        
+        <para>
+            <emphasis>Œ‹‡ƒe[ƒuƒ‹‚Ì’P•ûŒüˆê‘ΈêŠÖ˜A</emphasis> ‚́A–{“–‚É“ÁŽê‚Å‚·‚ª
+            •s‰Â”\‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-m2m">
+        <title>‘½‘Α½</title>
+        
+        <para>
+            ÅŒã‚ɁA<emphasis>’P•ûŒü‘½‘Α½ŠÖ˜A</emphasis> ‚ðŽ¦‚µ‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="assoc-bidirectional" revision="1">
+        <title>‘o•ûŒüŠÖ˜A</title>
+        
+        <sect2 id="assoc-bidirectional-m21" revision="2">
+        <title>ˆê‘Α½/‘½‘Έê</title>
+        
+        <para>
+            <emphasis>‘o•ûŒü‘½‘ΈêŠÖ˜A</emphasis> ‚͍łàˆê”Ê“I‚ÈŠÖ˜A‚Å‚·B
+            i•W€“I‚ȐeŽqŠÖŒW‚Å‚·j
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <set name="people" inverse="true">
+        <key column="addressId"/>
+        <one-to-many class="Person"/>
+    </set>
+</class>]]></programlisting>
+
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        <para>
+            <literal>List</literal> i‚Ü‚½‚Í‘¼‚̃Cƒ“ƒfƒbƒNƒX•t‚«‚̃RƒŒƒNƒVƒ‡ƒ“j‚ðŽg‚¤‚È‚çA
+            ŠO•”ƒL[‚Ì <literal>key</literal> ƒJƒ‰ƒ€‚ð <literal>not null</literal> ‚ɐݒ肵A
+            ƒRƒŒƒNƒVƒ‡ƒ“‘¤‚ªŠe—v‘f‚̃Cƒ“ƒfƒbƒNƒX‚ðƒƒ“ƒeƒiƒ“ƒX‚·‚é‚悤‚ɁA
+            ŠÖ˜A‚ðˆµ‚¤•K—v‚ª‚ ‚è‚Ü‚·
+            i<literal>update="false"</literal> ‚©‚ <literal>insert="false"</literal> 
+            ‚Ɛݒ肵‚āA”½‘Α¤‚ð‰¼‘z“I‚Éinverse‚É‚µ‚Ü‚·jF
+        </para>
+
+        <programlisting><![CDATA[<class name="Person">
+   <id name="id"/>
+   ...
+   <many-to-one name="address"
+      column="addressId"
+      not-null="true"
+      insert="false"
+      update="false"/>
+</class>
+
+<class name="Address">
+   <id name="id"/>
+   ...
+   <list name="people">
+      <key column="addressId" not-null="true"/>
+      <list-index column="peopleIdx"/>
+      <one-to-many class="Person"/>
+   </list>
+</class>]]></programlisting>
+
+            <para>
+                ‚à‚µŠO•”ƒL[ƒJƒ‰ƒ€‚ª <literal>NOT NULL</literal> ‚Å‚ ‚é‚È‚ç‚΁A
+                ƒRƒŒƒNƒVƒ‡ƒ“ƒ}ƒbƒsƒ“ƒO‚Ì <literal>&lt;key&gt;</literal> —v‘f‚ð 
+                <literal>not-null="true"</literal> ‚É‚·‚邱‚Ƃ͏d—v‚Å‚·B
+                “ü‚êŽq‚É‚È‚Á‚½ <literal>&lt;column&gt;</literal> —v‘f‚¾‚¯‚Å‚Í‚È‚­A
+                <literal>&lt;key&gt;</literal> —v‘f‚à <literal>not-null="true"</literal> 
+                ‚Æ’è‹`‚µ‚È‚¢‚悤‚É‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+        </sect2>
+        
+        <sect2 id="assoc-bidirectional-121">
+        <title>ˆê‘Έê</title>
+        
+        <para>
+            <emphasis>ŠO•”ƒL[‚Ì‘o•ûŒüˆê‘ΈêŠÖ˜A</emphasis> ‚Í”ñí‚Ɉê”Ê“I‚Å‚·B
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId" 
+        unique="true"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+   <one-to-one name="person" 
+        property-ref="address"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        <para>
+            <emphasis>ŽåƒL[‚Ì‘o•ûŒüˆê‘ΈêŠÖ˜A</emphasis> ‚Í“ÁŽê‚ÈIDƒWƒFƒlƒŒ[ƒ^‚ðŽg‚¢‚Ü‚·B
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <one-to-one name="address"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="personId">
+        <generator class="foreign">
+            <param name="property">person</param>
+        </generator>
+    </id>
+    <one-to-one name="person" 
+        constrained="true"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="assoc-bidirectional-join" revision="1">
+        <title>Œ‹‡ƒe[ƒuƒ‹‚ðŽg‚Á‚½‘o•ûŒüŠÖ˜A</title>
+        
+        <sect2 id="assoc-bidirectional-join-12m">
+        <title>ˆê‘Α½/‘½‘Έê</title>
+        
+        <para>
+            <emphasis>Œ‹‡ƒe[ƒuƒ‹‚Ì‘o•ûŒüˆê‘Α½ŠÖ˜A</emphasis> ‚Å‚·B
+            <literal>inverse="true"</literal> ‚ªŠÖ˜A’[AƒRƒŒƒNƒVƒ‡ƒ“AŒ‹‡‚Ì‚¢‚¸‚ê‚©‚É
+            Ý’è‚Å‚«‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" 
+        table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            unique="true"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        inverse="true" 
+        optional="true">
+        <key column="addressId"/>
+        <many-to-one name="person"
+            column="personId"
+            not-null="true"/>
+    </join>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+         <sect2 id="assoc-bidirectional-join-121">
+        <title>ˆê‘Έê</title>
+        
+        <para>
+            <emphasis>Œ‹‡ƒe[ƒuƒ‹‚Ì‘o•ûŒüˆê‘ΈêŠÖ˜A</emphasis> 
+            ‚Í”ñí‚É“ÁŽê‚Å‚·‚ªA‰Â”\‚Å‚·B
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true"
+        inverse="true">
+        <key column="addressId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="personId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+
+        </sect2>
+        
+        <sect2 id="assoc-bidirectional-join-m2m" revision="1">
+        <title>‘½‘Α½</title>
+        
+        <para>
+            ÅŒã‚ɁA<emphasis>‘o•ûŒü‘½‘Α½ŠÖ˜A</emphasis> ‚ðŽ¦‚µ‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <set name="people" inverse="true" table="PersonAddress">
+        <key column="addressId"/>
+        <many-to-many column="personId"
+            class="Person"/>
+    </set>
+</class>]]></programlisting>
+
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="assoc-complex">
+        <title>‚æ‚è•¡ŽG‚ÈŠÖ˜Aƒ}ƒbƒsƒ“ƒO</title>
+        
+        <para>
+            ‚æ‚è•¡ŽG‚ÈŠÖ˜AŒ‹‡‚Í <emphasis>‹É‚ß‚Ä</emphasis> ‹H‚Å‚·B
+            ƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚ÉSQL•¶‚𖄂ߍž‚Þ‚±‚ƂŁA
+            ‚³‚ç‚É•¡ŽG‚Èó‹µ‚ðˆµ‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+            —Ⴆ‚΁A<literal>accountNumber</literal>, <literal>effectiveEndDate</literal>, 
+            <literal>effectiveStartDate</literal> ƒJƒ‰ƒ€‚ðŽ‚ÂaccountiŒûÀjî•ñ‚Ì—š—ð‚ðˆµ‚¤ƒe[ƒuƒ‹‚́A
+            ˆÈ‰º‚̂悤‚Ƀ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[<properties name="currentAccountKey">
+    <property name="accountNumber" type="string" not-null="true"/>
+    <property name="currentAccount" type="boolean">
+        <formula>case when effectiveEndDate is null then 1 else 0 end</formula>
+    </property>
+</properties>
+<property name="effectiveEndDate" type="date"/>
+<property name="effectiveStateDate" type="date" not-null="true"/>]]></programlisting>
+
+        <para>
+            ‚»‚µ‚āAŠÖ˜A‚ð <emphasis>Œ»Žž“_‚Ì</emphasis> ƒCƒ“ƒXƒ^ƒ“ƒX
+            i<literal>effectiveEndDate</literal> ‚ªnull‚Å‚ ‚é‚à‚́j‚Ƀ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+            ˆÈ‰º‚̂悤‚É‚È‚è‚Ü‚·F
+        </para>
+        
+        <programlisting><![CDATA[<many-to-one name="currentAccountInfo" 
+        property-ref="currentAccountKey"
+        class="AccountInfo">
+    <column name="accountNumber"/>
+    <formula>'1'</formula>
+</many-to-one>]]></programlisting>
+
+        <para>
+            ‚³‚ç‚É•¡ŽG‚È—á‚ł́A<literal>Employeei]‹Æˆõj</literal> ‚Æ <literal>Organizationi‘gDj</literal> 
+            ŠÔ‚ÌŠÖ˜A‚ª <literal>EmploymentiŒÙ—pj</literal> ƒe[ƒuƒ‹‚Å•ÛŽ‚³‚ê‚éê‡‚ð‘z‘œ‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚±‚̃e[ƒuƒ‹‚ɂ͌ٗpƒf[ƒ^‚Ì—š—ð‚ª‚·‚ׂĊ܂܂ê‚Ü‚·B
+            ‚·‚é‚Ə]‹Æˆõ‚Ì <emphasis>Å‚àÅ‹ß‚Ì</emphasis> ŒÙ—pŽÒ‚ð•\‚·ŠÖ˜A
+            iÅ‚àÅ‹ß‚Ì <literal>startDate</literal> ‚ðŽ‚Â‚à‚́j‚́A‚±‚̂悤‚Ƀ}ƒbƒsƒ“ƒO‚Å‚«‚Ü‚·F
+        </para>
+        
+        <programlisting><![CDATA[<join>
+    <key column="employeeId"/>
+    <subselect>
+        select employeeId, orgId 
+        from Employments 
+        group by orgId 
+        having startDate = max(startDate)
+    </subselect>
+    <many-to-one name="mostRecentEmployer" 
+            class="Organization" 
+            column="orgId"/>
+</join>]]></programlisting>
+
+        <para>
+            ‚±‚Ì‹@”\‚Í”ñí‚É‹­—Í‚Å‚·B
+            ‚µ‚©‚µ‚±‚̂悤‚ȏꍇA•’Ê‚ÍHQL‚âcriteriaƒNƒGƒŠ‚ðŽg‚¤•û‚ª‚æ‚èŽÀ‘H“I‚Å‚·B
+        </para>
+
+    </sect1>
+
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/basic_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/basic_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/basic_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,3485 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+
+<chapter id="mapping">
+    <title>Šî–{“I‚ÈO/Rƒ}ƒbƒsƒ“ƒO</title>
+
+    <sect1 id="mapping-declaration" revision="1">
+        <title>ƒ}ƒbƒsƒ“ƒO’è‹`</title>
+
+        <para>
+            ƒIƒuƒWƒFƒNƒg/ƒŠƒŒ[ƒVƒ‡ƒiƒ‹ƒ}ƒbƒsƒ“ƒO‚͒ʏíXMLƒhƒLƒ…ƒƒ“ƒg‚Å’è‹`‚µ‚Ü‚·B
+            ƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚́A“Ç‚Ý‚â‚·‚­Žèì‹Æ‚ŕҏW‚µ‚â‚·‚¢‚悤‚ɃfƒUƒCƒ“‚³‚ê‚Ä‚¢‚Ü‚·B
+            ƒ}ƒbƒsƒ“ƒOŒ¾Œê‚ÍJava’†SA‚‚܂èƒe[ƒuƒ‹’è‹`‚Å‚Í‚È‚­‰i‘±ƒNƒ‰ƒX‚Ì’è‹`‚ÉŠî‚¢‚č\’z‚³‚ê‚Ä‚¢‚Ü‚·B
+        </para>
+        
+        <para>
+            ‘½‚­‚ÌHibernateƒ†[ƒU‚ÍXMLƒ}ƒbƒsƒ“ƒO‚Ì‹Lq‚ðŽèì‹Æ‚ōs‚¢‚Ü‚·‚ªA
+            XDoclet, Middlegen, AndroMDA‚Æ‚¢‚¤‚悤‚ȃ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚𐶐¬‚·‚éƒc[ƒ‹‚ª
+            ‚¢‚­‚‚©‘¶Ý‚µ‚Ü‚·B
+        </para>
+
+        <para>
+            ƒTƒ“ƒvƒ‹‚̃}ƒbƒsƒ“ƒO‚©‚çŽn‚ß‚Ü‚µ‚傤F
+        </para>
+
+        <programlisting id="mapping-declaration-ex1" revision="1"><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+        <class name="Cat" 
+            table="cats"
+            discriminator-value="C">
+                
+                <id name="id">
+                        <generator class="native"/>
+                </id>
+
+                <discriminator column="subclass" 
+                     type="character"/>
+
+                <property name="weight"/>
+
+                <property name="birthdate"
+                    type="date" 
+                    not-null="true" 
+                    update="false"/>
+
+                <property name="color"
+                    type="eg.types.ColorUserType"
+                    not-null="true"
+                    update="false"/>
+
+                <property name="sex"
+                    not-null="true" 
+                    update="false"/>
+
+                <property name="litterId"
+                    column="litterId"
+                    update="false"/>
+
+                <many-to-one name="mother"
+                    column="mother_id"
+                    update="false"/>
+
+                <set name="kittens"
+                    inverse="true"
+                    order-by="litter_id">
+                        <key column="mother_id"/>
+                        <one-to-many class="Cat"/>
+                </set>
+
+                <subclass name="DomesticCat"
+                    discriminator-value="D">
+
+                        <property name="name" 
+                            type="string"/>
+
+                </subclass>
+
+        </class>
+
+        <class name="Dog">
+                <!-- ‚±‚±‚ÉDog—p‚̃}ƒbƒsƒ“ƒO‘‚«‚Ü‚· -->
+        </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+             ƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚Ì“à—e‚ðà–¾‚µ‚Ü‚·BB
+            ‚½‚¾‚µA‚±‚±‚Å‚ÍHibernate‚ªŽÀsŽž‚ÉŽg‚¤ƒhƒLƒ…ƒƒ“ƒg—v‘f‚Æ‘®«‚ɂ‚¢‚Ä‚Ì‚Ýà–¾‚µ‚Ü‚·B
+            ƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚́A‚¢‚­‚‚©‚̃IƒvƒVƒ‡ƒ“‘®«‚Æ—v‘f‚ðŠÜ‚ñ‚Å‚¢‚Ü‚·i—Ⴆ‚Î <literal>not-null</literal> ‘®«jB
+            ‚»‚ê‚ç‚̓XƒL[ƒ}ƒGƒNƒXƒ|[ƒgƒc[ƒ‹‚ªo—Í‚·‚éƒf[ƒ^ƒx[ƒXƒXƒL[ƒ}‚ɉe‹¿‚ð—^‚¦‚é‚à‚Ì‚Å‚·B
+            
+        </para>
+
+
+
+        <sect2 id="mapping-declaration-doctype" revision="3">
+            <title>Doctype</title>
+
+            <para>
+                XMLƒ}ƒbƒsƒ“ƒO‚ł́A‚¨Œ©‚¹‚µ‚½‚悤‚ȃhƒLƒ…ƒƒ“ƒgŒ^‚ð•K‚¸’è‹`‚·‚ׂ«‚Å‚·B
+                ŽÀÛ‚ÌDTD‚́Aã‹L‚ÌURL‚Ì <literal>hibernate-x.x.x/src/org/hibernate</literal> ƒfƒBƒŒƒNƒgƒŠA ‚Ü‚½‚Í 
+                <literal>hibernate.jar</literal> “à‚É‚ ‚è‚Ü‚·B
+                Hibernate‚͏í‚ɁA‚»‚̃Nƒ‰ƒXƒpƒX“à‚ÅDTD‚ð’T‚µŽn‚ß‚Ü‚·B
+                ƒCƒ“ƒ^[ƒlƒbƒg‚É‚ ‚éDTDƒtƒ@ƒCƒ‹‚ð’T‚»‚¤‚Æ‚µ‚½‚È‚çA
+                ƒNƒ‰ƒXƒpƒX‚Ì“à—e‚ðŒ©‚ÄADTDéŒ¾‚ðŠm”F‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+            
+            
+            
+            <sect3 id="mapping-declaration-entity-resolution">
+                <title>
+                ƒGƒ“ƒeƒBƒeƒBEƒŠƒ]ƒ‹ƒo
+                </title>
+                <para>
+                    ‘Oq‚µ‚½‚悤‚ɁAHibernate‚Í‚Ü‚¸ƒNƒ‰ƒXƒpƒX“à‚ÅDTD‚ð‰ðŒˆ‚µ‚悤‚Æ‚µ‚Ü‚·B
+                    <literal>org.xml.sax.EntityResolver</literal> ‚̃JƒXƒ^ƒ€ŽÀ‘•‚ð
+                    XMLƒtƒ@ƒCƒ‹‚ð“ǂݍž‚Þ‚½‚ß‚ÌSAXReader‚É“o˜^‚·‚邱‚Æ‚É‚æ‚Á‚āADTD‚ð‰ðŒˆ‚µ‚Ü‚·B
+                    ‚±‚̃JƒXƒ^ƒ€‚Ì <literal>EntityResolver</literal> ‚Í2‚‚̈قȂéƒVƒXƒeƒ€ID–¼‘O‹óŠÔ‚ð”FŽ¯‚µ‚Ü‚·B
+                    
+                </para>
+                <itemizedlist>
+                    <listitem>
+                        <para>
+                            <literal>Hibernate–¼‘O‹óŠÔ</literal> ‚́AƒŠƒ]ƒ‹ƒo‚ª 
+                            <literal>http://hibernate.sourceforge.net/</literal> ‚ÅŽn‚Ü‚éƒVƒXƒeƒ€ID‚É“ž’B‚µ‚½‚Æ‚«‚ɁA
+                            ”FŽ¯‚³‚ê‚Ü‚·B
+                            ‚»‚µ‚ăŠƒ]ƒ‹ƒo‚́AHibernate‚̃Nƒ‰ƒX‚ðƒ[ƒh‚µ‚½ƒNƒ‰ƒXƒ[ƒ_‚ð—p‚¢‚āA
+                            ‚±‚ê‚ç‚̃Gƒ“ƒeƒBƒeƒB‚ð‰ðŒˆ‚µ‚悤‚Æ‚µ‚Ü‚·B
+                        
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                          <literal>ƒ†[ƒU–¼‘O‹óŠÔ</literal> ‚́AƒŠƒ]ƒ‹ƒo‚ª
+                          URLƒvƒƒgƒRƒ‹‚Ì <literal>classpath://</literal> ‚ðŽg‚Á‚½ƒVƒXƒeƒ€ID‚É“ž’B‚µ‚½‚Æ‚«‚ɁA
+                          ”FŽ¯‚³‚ê‚Ü‚·B‚»‚µ‚ăŠƒ]ƒ‹ƒo‚́A(1)ƒJƒŒƒ“ƒgƒXƒŒƒbƒh‚̃Rƒ“ƒeƒLƒXƒgƒNƒ‰ƒXƒ[ƒ_[A
+                          ‚Ü‚½‚Í(2)Hibernate‚̃Nƒ‰ƒX‚ðƒ[ƒh‚µ‚½ƒNƒ‰ƒXƒ[ƒ_‚ðŽg‚Á‚āA
+                          ‚±‚ê‚ç‚̃Gƒ“ƒeƒBƒeƒB‚ð‰ðŒˆ‚µ‚悤‚Æ‚µ‚Ü‚·B
+                        
+                        </para>
+                    </listitem>
+                </itemizedlist>
+                <para>
+                ‰º‹L‚́Aƒ†[ƒU–¼‘O‹óŠÔ‚ðŽg‚Á‚½—á‚Å‚·F
+                
+                </para>
+                <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [
+    <!ENTITY types SYSTEM "classpath://your/domain/types.xml">
+]>
+
+<hibernate-mapping package="your.domain">
+    <class name="MyEntity">
+        <id name="id" type="my-custom-id-type">
+            ...
+        </id>
+    <class>
+    &types;
+</hibernate-mapping>]]></programlisting>
+                <para>
+                ‚±‚±‚Å <literal>types.xml</literal> ‚Í <literal>your.domain</literal> ƒpƒbƒP[ƒW“à‚̃Šƒ\[ƒX‚Å‚ ‚èA
+                ƒJƒXƒ^ƒ€ <xref linkend="mapping-types-custom">typedef</xref> ‚ðŠÜ‚Þ‚Ü‚·B
+                </para>
+            </sect3>            
+            
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-mapping" revision="3">
+            <title>hibernate-mapping</title>
+
+            <para>
+                ‚±‚Ì—v‘f‚É‚Í‚¢‚­‚‚©ƒIƒvƒVƒ‡ƒ“‘®«‚ª‚ ‚è‚Ü‚·B<literal>schema</literal> ‘®«‚Æ <literal>catalog</literal> ‘®«‚́A
+                ‚±‚̃}ƒbƒsƒ“ƒO‚ªŽQÆ‚·‚éƒe[ƒuƒ‹‚ªA‚±‚Ì‘®«‚É‚æ‚Á‚ÄŽw’肳‚ꂽƒXƒL[ƒ}‚Æ(‚Ü‚½‚Í)ƒJƒ^ƒƒO‚É‘®‚·‚邱‚Æ‚ðŽw’肵‚Ü‚·B
+                ‚±‚Ì‘®«‚ªŽw’肳‚ê‚é‚ƁAƒe[ƒuƒ‹–¼‚Í—^‚¦‚ç‚ꂽƒXƒL[ƒ}–¼‚ƃJƒ^ƒƒO–¼‚ŏCü‚³‚ê‚Ü‚·B‚±‚ê‚ç‚Ì‘®«‚ªŽw’肳‚ê‚Ä‚¢‚È‚¯‚ê‚΁A
+                ƒe[ƒuƒ‹–¼‚͏Cü‚³‚ê‚Ü‚¹‚ñB<literal>default-cascade</literal> ‘®«‚́A
+                <literal>cascade</literal> ‘®«‚ðŽw’肵‚Ä‚¢‚È‚¢ƒvƒƒpƒeƒB‚âƒRƒŒƒNƒVƒ‡ƒ“‚ɁA
+                ‚ǂ̃JƒXƒP[ƒhƒXƒ^ƒCƒ‹‚ðŠ„‚è“–‚Ä‚é‚©‚ðŽw’肵‚Ü‚·B
+                <literal>auto-import</literal> ‘®«‚́A
+                ƒNƒGƒŠŒ¾Œê“à‚ŏCü‚³‚ê‚Ä‚¢‚È‚¢ƒNƒ‰ƒX–¼‚ðAƒfƒtƒHƒ‹ƒg‚ÅŽg‚¦‚é‚悤‚É‚µ‚Ü‚·B
+            </para>
+ 
+             <programlistingco>
+                 <areaspec>
+                     <area id="hm1" coords="2 55"/>
+                     <area id="hm2" coords="3 55"/>
+                     <area id="hm3" coords="4 55"/>
+                     <area id="hm4" coords="5 55"/>
+                     <area id="hm5" coords="6 55"/>
+                     <area id="hm6" coords="7 55"/>
+                     <area id="hm7" coords="8 55"/>
+                 </areaspec>
+                 <programlisting><![CDATA[<hibernate-mapping
+         schema="schemaName"
+         catalog="catalogName"
+         default-cascade="cascade_style"
+         default-access="field|property|ClassName"
+         default-lazy="true|false"
+         auto-import="true|false"
+         package="package.name"
+ />]]></programlisting>
+                 <calloutlist>
+                     <callout arearefs="hm1">
+                         <para>
+                             <literal>schema</literal>iƒIƒvƒVƒ‡ƒ“jFƒf[ƒ^ƒx[ƒXƒXƒL[ƒ}‚Ì–¼‘OB
+                         </para>
+                     </callout>
+                     <callout arearefs="hm2">
+                         <para>
+                             <literal>catalog</literal> iƒIƒvƒVƒ‡ƒ“jFƒf[ƒ^ƒx[ƒXƒJƒ^ƒƒO‚Ì–¼‘OB
+                         </para>
+                     </callout>
+                     <callout arearefs="hm3">
+                         <para>
+                            <literal>default-cascade</literal> iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>none</literal>jF
+                             ƒfƒtƒHƒ‹ƒg‚̃JƒXƒP[ƒhƒXƒ^ƒCƒ‹B
+                         </para>
+                     </callout>
+                     <callout arearefs="hm4">
+                         <para>
+                             <literal>default-access</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>property</literal> jF
+                             Hibernate‚ªƒvƒƒpƒeƒB‚ɃAƒNƒZƒX‚·‚éÛ‚ɍ̂é‚ׂ«í—ªB <literal>PropertyAccessor</literal> 
+                             ‚ðŽÀ‘•‚·‚邱‚ƂŃJƒXƒ^ƒ}ƒCƒY‰Â”\B
+                             
+                         </para>
+                     </callout>
+                     <callout arearefs="hm5">
+                         <para>
+                             <literal>default-lazy</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal> )F
+                              <literal>lazy</literal> ‘®«‚ªŽw’肳‚ê‚Ä‚¢‚È‚¢ƒNƒ‰ƒX‚âƒRƒŒƒNƒVƒ‡ƒ“ƒ}ƒbƒsƒ“ƒO‚ɑ΂·‚éƒfƒtƒHƒ‹ƒg’lB
+                         </para>
+                     </callout>
+                     <callout arearefs="hm6">
+                         <para>
+                             <literal>auto-import</literal> iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal>jF
+                             ƒNƒGƒŠŒ¾Œê“à‚ŁAi‚±‚̃}ƒbƒsƒ“ƒO“à‚̃Nƒ‰ƒX‚́jCü‚³‚ê‚Ä‚¢‚È‚¢ƒNƒ‰ƒX–¼‚ðŽg‚¦‚é‚©‚Ç‚¤‚©‚ðŽw’肵‚Ü‚·B
+                         </para>
+                     </callout>
+                     <callout arearefs="hm7">
+                         <para>
+                             <literal>package</literal> (ƒIƒvƒVƒ‡ƒ“): ƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg“à‚ŏCü‚³‚ê‚Ä‚¢‚È‚¢ƒNƒ‰ƒX–¼‚ɑ΂µ‚ÄŠ„‚è“–‚Ä‚éA
+                             ƒpƒbƒP[ƒW‚̐ړªŽ«(prefix)‚ðŽw’肵‚Ü‚·B
+                         </para>
+                     </callout>
+                 </calloutlist>
+             </programlistingco>
+             
+             <para>
+                 iCü‚³‚ê‚Ä‚¢‚È‚¢j“¯‚¶–¼‘O‚̉i‘±ƒNƒ‰ƒX‚ª2‚‚ ‚é‚È‚çA
+                 <literal>auto-import="false"</literal> ‚ðÝ’è‚·‚ׂ«‚Å‚·B
+                 2‚‚̃Nƒ‰ƒX‚ɁhƒCƒ“ƒ|[ƒg‚³‚ꂽh“¯‚¶–¼‘O‚ðŠ„‚è“–‚Ă悤‚Æ‚·‚é‚ƁAHibernate‚Í—áŠO‚ð“Š‚°‚Ü‚·B
+             </para>
+
+             <para>
+                 <literal>hibernate-mapping</literal> —v‘f‚́AÅ‰‚Ì—á‚ÅŽ¦‚µ‚½‚悤‚É‚¢‚­‚‚©‚̉i‘± <literal>&lt;class&gt;</literal> 
+                 ƒ}ƒbƒsƒ“ƒO‚ðƒlƒXƒg‚Å‚«‚Ü‚·B
+                 ‚µ‚©‚µA‚P‚‚̃}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚Å‚Í‚½‚¾‚ЂƂ‚̉i‘±ƒNƒ‰ƒX(‚Ü‚½‚͂ЂƂ‚̃Nƒ‰ƒXŠK‘w)‚Ƀ}ƒbƒsƒ“ƒO‚·‚é‚悤‚É‚µA
+                 ‚³‚ç‚ɉi‘±ƒX[ƒp[ƒNƒ‰ƒX‚ÌŒã‚ÅŽw’è‚·‚é‚ׂ«‚Å‚µ‚傤(‚¢‚­‚‚©‚̃c[ƒ‹‚Í‚±‚̂悤‚ȃ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ð‘z’肵‚Ä‚¢‚Ü‚·)B
+                 —Ⴆ‚ÎŽŸ‚̂悤‚É‚È‚è‚Ü‚·BF <literal>Cat.hbm.xml</literal> ,
+                  <literal>Dog.hbm.xml</literal> , ‚Ü‚½‚ÍŒp³‚ðŽg‚¤‚È‚ç <literal>Animal.hbm.xml</literal> B
+             </para>
+ 
+        </sect2>
+
+        <sect2 id="mapping-declaration-class" revision="3">
+            <title>class</title>
+
+            <para>
+                <literal>class</literal> —v‘f‚ðŽg‚Á‚āA‰i‘±ƒNƒ‰ƒX‚ðéŒ¾‚Å‚«‚Ü‚·B
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="class1" coords="2 55"/>
+                    <area id="class2" coords="3 55" />
+                    <area id="class3" coords="4 55"/>
+                    <area id="class4" coords="5 55" />
+                    <area id="class5" coords="6 55"/>
+                    <area id="class6" coords="7 55" />
+                    <area id="class7" coords="8 55"/>
+                    <area id="class8" coords="9 55" />
+                    <area id="class9" coords="10 55" />
+                    <area id="class10" coords="11 55"/>
+                    <area id="class11" coords="12 55"/>
+                    <area id="class12" coords="13 55"/>
+                    <area id="class13" coords="14 55"/>
+                    <area id="class14" coords="15 55"/>
+                    <area id="class15" coords="16 55"/>
+                    <area id="class16" coords="17 55"/>
+                    <area id="class17" coords="18 55"/>
+                    <area id="class18" coords="19 55"/>
+                    <area id="class19" coords="20 55"/>
+                    <area id="class20" coords="21 55"/>
+                    <area id="class21" coords="22 55"/>
+
+                </areaspec>
+                <programlisting><![CDATA[<class
+        name="ClassName"
+        table="tableName"
+        discriminator-value="discriminator_value"
+        mutable="true|false"
+        schema="owner"
+        catalog="catalog"
+        proxy="ProxyInterface"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        select-before-update="true|false"
+        polymorphism="implicit|explicit"
+        where="arbitrary sql where condition"
+        persister="PersisterClass"
+        batch-size="N"
+        optimistic-lock="none|version|dirty|all"
+        lazy="true|false"
+        entity-name="EntityName"
+        check="arbitrary sql check condition"
+        rowid="rowid"
+        subselect="SQL expression"
+        abstract="true|false"
+        entity-name="EntityName"
+        node="element-name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="class1">
+                        <para>
+                            <literal>name</literal> (ƒIƒvƒVƒ‡ƒ“)F‰i‘±ƒNƒ‰ƒXi‚Ü‚½‚̓Cƒ“ƒ^[ƒtƒFƒCƒXj‚ÌŠ®‘SCüJavaƒNƒ‰ƒX–¼B
+                            ‚à‚µ‚±‚Ì‘®«‚ðŽw’肵‚È‚¯‚ê‚΁APOJO‚Å‚Í‚È‚¢ƒGƒ“ƒeƒBƒeƒB‚ɑ΂·‚éƒ}ƒbƒsƒ“ƒO‚Æ‚µ‚Ĉµ‚í‚ê‚Ü‚·B
+                            
+                        </para>
+                    </callout>
+                    <callout arearefs="class2">
+                        <para>
+                           <literal>table</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚͏Cü‚³‚ê‚Ä‚¢‚È‚¢ƒNƒ‰ƒX–¼)Fƒf[ƒ^ƒx[ƒXƒe[ƒuƒ‹‚Ì–¼‘O
+                        </para>
+                    </callout>
+                    <callout arearefs="class3">
+                        <para>
+                            <literal>discriminator-value</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚̓Nƒ‰ƒX–¼)F
+                            ƒ|ƒŠƒ‚[ƒtƒBƒbƒN‚ȐU‚é•‘‚¢‚ÉŽg‚í‚ê‚éŒÂX‚̃TƒuƒNƒ‰ƒX‚ðŽ¯•Ê‚·‚邽‚ß‚Ì’lB
+                            ’l‚Í <literal>null</literal> ‚© <literal>not null</literal> ‚Ì‚¢‚¸‚ê‚©‚ðŽæ‚è‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="class4">
+                        <para>
+                            <literal>mutable</literal> (ƒIƒvƒVƒ‡ƒ“A ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal> )F
+                            ‚»‚̃Nƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ªXV‰Â”\i‚Ü‚½‚Í•s‰Â”\j‚Å‚ ‚邱‚Æ‚ðŽw’肵‚Ü‚·B
+                        </para>
+                    </callout>    
+                    <callout arearefs="class5">
+                        <para>
+                            <literal>schema</literal> iƒIƒvƒVƒ‡ƒ“jF
+                            ƒ‹[ƒg‚Ì <literal>&lt;hibernate-mapping&gt;</literal> —v‘f‚ÅŽw’肳‚ꂽƒXƒL[ƒ}–¼‚ðƒI[ƒo[ƒ‰ƒCƒh‚µ‚Ü‚·B
+                        </para>
+                    </callout>                
+                    <callout arearefs="class6">
+                        <para>
+                            <literal>catalog</literal> iƒIƒvƒVƒ‡ƒ“jFƒ‹[ƒg‚Ì <literal>&lt;hibernate-mapping&gt;</literal> 
+                            —v‘f‚ÅŽw’肳‚ꂽƒJƒ^ƒƒO–¼‚ðƒI[ƒo[ƒ‰ƒCƒh‚µ‚Ü‚·B
+                        </para>
+                    </callout>                
+                    <callout arearefs="class7">
+                        <para>
+                            <literal>proxy</literal> iƒIƒvƒVƒ‡ƒ“jF’x‰„‰Šú‰»ƒvƒƒLƒV‚ÉŽg‚¤ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽw’肵‚Ü‚·B
+                            ‰i‘±‰»‚·‚éƒNƒ‰ƒX–¼‚»‚Ì‚à‚Ì‚ðŽw’è‚·‚邱‚Æ‚à‰Â”\‚Å‚·B
+                        </para>
+                    </callout>    
+                    <callout arearefs="class8">
+                        <para>
+                            <literal>dynamic-update</literal> iƒIƒvƒVƒ‡ƒ“A ƒfƒtƒHƒ‹ƒg‚Í <literal>false</literal> jF
+                            ’l‚ª•ÏX‚³‚ꂽƒJƒ‰ƒ€‚¾‚¯‚ðŠÜ‚ÞSQL‚Ì <literal>UPDATE</literal> •¶‚ðAŽÀsŽž‚ɐ¶¬‚·‚邱‚Æ‚ðŽw’肵‚Ü‚·B
+                        </para>
+                    </callout>    
+                    <callout arearefs="class9">
+                        <para>
+                            <literal>dynamic-insert</literal> iƒIƒvƒVƒ‡ƒ“, ƒfƒtƒHƒ‹ƒg‚Í <literal>false</literal> jF
+                            ’l‚ªnull‚Å‚Í‚È‚¢ƒJƒ‰ƒ€‚¾‚¯‚ðŠÜ‚ÞSQL‚Ì <literal>INSERT</literal> •¶‚ðAŽÀsŽž‚ɐ¶¬‚·‚邱‚Æ‚ðŽw’肵‚Ü‚·B
+                        </para>
+                    </callout>    
+                    <callout arearefs="class10">
+                        <para>
+                            <literal>select-before-update</literal> (ƒIƒvƒVƒ‡ƒ“, ƒfƒtƒHƒ‹ƒg‚Í <literal>false</literal>): 
+                            ƒIƒuƒWƒFƒNƒg‚ª•ÏX‚³‚ꂽ‚Ì‚ªŠmŽÀ‚Å‚È‚¢‚È‚ç‚΁AHibernate‚ªSQL‚Ì <literal>UPDATE</literal> ‚ð 
+                            <emphasis>Œˆ‚µ‚ÄŽÀs‚µ‚È‚¢</emphasis> ‚±‚Æ‚ðŽw’肵‚Ü‚·B
+                            ‚ ‚é“Á’è‚̏ꍇ(ŽÀÛ“I‚ɂ́AˆêŽžƒIƒuƒWƒFƒNƒg‚ª <literal>update()</literal> ‚ðŽg‚¢A
+                            V‚µ‚¢ƒZƒbƒVƒ‡ƒ“‚ÆŠÖ˜A•t‚¯‚ç‚ꂽŽž‚¾‚¯)A<literal>UPDATE</literal> ‚ªŽÀÛ‚É•K—v‚©‚Ç‚¤‚©‚ðŒˆ’è‚·‚邽‚߂ɁA
+                            Hibernate‚ª—]•ª‚ÈSQL‚Ì <literal>SELECT</literal> •¶‚ðŽÀs‚·‚邱‚Æ‚ðˆÓ–¡‚µ‚Ü‚·B
+                        </para>
+                    </callout>    
+                    <callout arearefs="class11">
+                        <para>
+                            (optional, ƒfƒtƒHƒ‹ƒg‚Å‚Í <literal>implicit</literal> ): implicitiˆÃ–فj‚©expliciti–¾Ž¦j‚́A
+                            ‚Ç‚¿‚ç‚̃NƒGƒŠƒ|ƒŠƒ‚[ƒtƒBƒYƒ€‚ðŽg‚¤‚©Œˆ’肵‚Ü‚·B
+                        </para>
+                    </callout>    
+                    <callout arearefs="class12">
+                        <para>
+                            <literal>where</literal> iƒIƒvƒVƒ‡ƒ“jF
+                            ‚±‚̃Nƒ‰ƒX‚̃IƒuƒWƒFƒNƒg‚ðŒŸõ‚·‚é‚Æ‚«‚ÉŽg—p‚·‚éA”CˆÓ‚ÌSQL‚Ì <literal>WHERE</literal>  ðŒ‚ðŽw’肵‚Ü‚·B
+                        </para>
+                    </callout>                 
+                    <callout arearefs="class13">
+                        <para>
+                            <literal>persister</literal> iƒIƒvƒVƒ‡ƒ“jFƒJƒXƒ^ƒ€ <literal>ClassPersister</literal> ‚ðŽw’肵‚Ü‚·B
+                        </para>
+                    </callout>                 
+                    <callout arearefs="class14">
+                        <para>
+                            <literal>batch-size</literal> iƒIƒvƒVƒ‡ƒ“, ƒfƒtƒHƒ‹ƒg‚Í <literal>1</literal> jF
+                            Ž¯•ÊŽq‚Å‚±‚̃Nƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚𕜌³‚·‚é‚Æ‚«‚́uƒoƒbƒ`ƒTƒCƒYv‚ðŽw’肵‚Ü‚·B
+                        </para>
+                    </callout>                 
+                   <callout arearefs="class15">
+                        <para>
+                            <literal>optimistic-lock</literal> iƒIƒvƒVƒ‡ƒ“,ƒfƒtƒHƒ‹ƒg‚Í <literal>version</literal> jF
+                            ŠyŠÏƒƒbƒNí—ª‚ðŒˆ’è‚µ‚Ü‚·B
+                        </para>
+                    </callout>    
+                    <callout arearefs="class16">
+                        <para>
+                            <literal>lazy</literal> iƒIƒvƒVƒ‡ƒ“jF <literal>lazy="false"</literal> ‚Ɛݒ肷‚邱‚ƂŁA
+                            ’x‰„ƒtƒFƒbƒ`‚ª‚Å‚«‚È‚­‚È‚è‚Ü‚·B
+                        </para>
+                    </callout>    
+                    <callout arearefs="class17">
+                        <para>
+                            <literal>entity-name</literal> iƒIƒvƒVƒ‡ƒ“AƒfƒtƒHƒ‹ƒg‚̓Nƒ‰ƒX–¼jF
+                            Hibernate3‚ł̓Nƒ‰ƒX‚ª•¡”‰ñƒ}ƒbƒsƒ“ƒO‚Å‚«iê‡‚É‚æ‚Á‚Ă͈Ⴄƒe[ƒuƒ‹‚ɑ΂µ‚Ä‚àjA
+                            JavaƒŒƒxƒ‹‚ÅMap‚âXML‚Å•\Œ»‚³‚ê‚éƒGƒ“ƒeƒBƒeƒBƒ}ƒbƒsƒ“ƒO‚ª‰Â”\‚Å‚·B
+                            ‚±‚ê‚ç‚̏ꍇAƒGƒ“ƒeƒBƒeƒB‚ɑ΂µ‚Ä”CˆÓ‚Ì–¼‘O‚ðA–¾Ž¦“I‚É•t‚¯‚È‚­‚Ä‚Í‚È‚è‚Ü‚¹‚ñB
+                            Ú‚µ‚­‚Í <xref linkend="persistent-classes-dynamicmodels"/> ‚Æ <xref linkend="xml"/> ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                        </para>
+                    </callout>
+                    <callout arearefs="class18">
+                        <para>
+                            <literal>check</literal> iƒIƒvƒVƒ‡ƒ“jFŽ©“®“I‚ɃXƒL[ƒ}‚𐶐¬‚·‚邽‚߂ɁA
+                            •¡”s‚Ì <emphasis>check</emphasis> §–ñ‚𐶐¬‚·‚éSQLŽ®B
+                        </para>
+                    </callout>
+                    <callout arearefs="class19">
+                        <para>
+                            <literal>rowid</literal> iƒIƒvƒVƒ‡ƒ“jFHibernate‚́A‚»‚ê‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚éƒf[ƒ^ƒx[ƒX‚ÅROWID‚Æ
+                            ŒÄ‚΂ê‚é‚à‚Ì‚ðŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+                            —Ⴆ‚ÎOracle‚ðŽg‚Á‚Ä‚¢‚é‚Æ‚«A‚±‚̃IƒvƒVƒ‡ƒ“‚É <literal>rowid</literal> ‚ðÝ’è‚·‚ê‚΁A
+                            Hiberante‚Íupdate‚ð‚‘¬‰»‚·‚邽‚ß‚É <literal>rowid</literal> ‚Æ‚¢‚¤“Á•Ê‚ȃJƒ‰ƒ€‚ðŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+                            ROWID‚͏ڍׂȎÀ‘•‚Å‚ ‚èA•Û‘¶‚³‚ꂽƒ^ƒvƒ‹‚Ì•¨—“I‚Ȉʒu‚ð•\‚µ‚Ä‚¢‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="class20">
+                        <para>
+                            <literal>subselect</literal> iƒIƒvƒVƒ‡ƒ“jF•s•Ï‚©‚“ǂݎæ‚èê—p‚Å‚ ‚éƒGƒ“ƒeƒBƒeƒB‚ð
+                            ƒf[ƒ^ƒx[ƒX‚Ì•›–⍇‚¹isubselectj‚Ƀ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+                            ‚à‚µŒ³‚̃e[ƒuƒ‹‚Ì‘ã‚í‚è‚Ƀrƒ…[‚ðŽ‚¿‚½‚¯‚ê‚ΗL—p‚Å‚·‚ªA
+                            ‚»‚¤‚Å‚È‚¢‚Ì‚È‚ç—L—p‚Å‚Í‚ ‚è‚Ü‚¹‚ñB‚æ‚èÚ‚µ‚¢î•ñ‚͉º‹L‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                        </para>
+                    </callout>
+                    <callout arearefs="class21">
+                        <para>
+                            <literal>abstract</literal> iƒIƒvƒVƒ‡ƒ“jF
+                            <literal>&lt;union-subclass&gt;</literal> ŠK‘w“à‚Ì’ŠÛƒX[ƒp[ƒNƒ‰ƒX‚Ƀ}[ƒN‚·‚邽‚ß‚ÉŽg‚¢‚Ü‚·B
+                        </para>
+                    </callout>
+
+                </calloutlist>
+            </programlistingco>
+           
+            <para>
+                ‰i‘±ƒNƒ‰ƒX‚Ì–¼‘O‚ɃCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽw’肵‚Ä‚à‚Ü‚Á‚½‚­–â‘è‚ ‚è‚Ü‚¹‚ñB
+                ‚»‚Ì‚Æ‚«‚Í <literal>&lt;subclass&gt;</literal> —v‘f‚ðŽg‚Á‚āA
+                ‚»‚̃Cƒ“ƒ^[ƒtƒFƒCƒX‚ðŽÀ‘•‚·‚éƒNƒ‰ƒX‚ð’è‹`‚µ‚Ä‚­‚¾‚³‚¢B
+                <emphasis>static</emphasis> ‚È“à•”ƒNƒ‰ƒX‚Å‚à‰i‘±‰»‚Å‚«‚Ü‚·B
+                ‚»‚Ì‚Æ‚«‚Í•W€Œ`Ž®A—Ⴆ‚Î <literal>eg.Foo$Bar</literal> ‚ðŽg‚Á‚ăNƒ‰ƒX–¼‚ðŽw’肵‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <para>
+                <literal>mutable="false"</literal> Žw’è‚ð‚µ‚½•s•ÏƒNƒ‰ƒX‚́A
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚æ‚éXV‚âíœ‚ªo—ˆ‚È‚¢‚±‚Æ‚ª‚ ‚è‚Ü‚·B
+                ‚±‚ê‚É‚æ‚èAHibernate‚ªƒpƒtƒH[ƒ}ƒ“ƒX‚ð­‚µ‰ü‘P‚µ‚Ü‚·B
+            </para>
+            
+            <para>
+                ƒIƒvƒVƒ‡ƒ“‚Ì <literal>proxy</literal> ‘®«‚É‚æ‚èAƒNƒ‰ƒX‚̉i‘±ƒCƒ“ƒXƒ^ƒ“ƒX‚Ì’x‰„‰Šú‰»‚ª‰Â”\‚É‚È‚è‚Ü‚·B
+                Hibernate‚͍ŏ‰‚ɁAŽw’肵‚½ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽÀ‘•‚µ‚½CGLIBƒvƒƒLƒV‚ð•Ô‚µ‚Ü‚·B
+                ŽÀÛ‚̉i‘±ƒIƒuƒWƒFƒNƒg‚̓vƒƒLƒV‚̃ƒ\ƒbƒh‚ðŒÄ‚яo‚·‚Æ‚«‚Ƀ[ƒh‚µ‚Ü‚·B
+                ˆÈ‰º‚́u’x‰„‰Šú‰»‚Ì‚½‚߂̃vƒƒLƒVv‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+            
+            <para>
+                <emphasis>ˆÃ–Ù“I</emphasis> ƒ|ƒŠƒ‚[ƒtƒBƒYƒ€‚Ƃ́AŽŸ‚Ì“ñ‚‚ðˆÓ–¡‚µ‚Ä‚¢‚Ü‚·B
+                ˆê‚‚̓Nƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ªAƒX[ƒp[ƒNƒ‰ƒX‚âŽÀ‘•‚µ‚½ƒCƒ“ƒ^[ƒtƒFƒCƒXA‚Ü‚½‚»‚̃Nƒ‰ƒX‚ðŽw’è‚·‚éƒNƒGƒŠ‚É‚æ‚Á‚Ä•Ô‚³‚ê‚邱‚ƂŁA
+                ‚à‚¤ˆê‚‚͂»‚̃Nƒ‰ƒX‚̃TƒuƒNƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ªA‚»‚̃Nƒ‰ƒXŽ©g‚ðŽw’肵‚½ƒNƒGƒŠ‚É‚æ‚Á‚Ä•Ô‚³‚ê‚邱‚Æ‚Å‚·B
+                ‚Ü‚½A<emphasis>–¾Ž¦“I</emphasis> ƒ|ƒŠƒ‚[ƒtƒBƒYƒ€‚Ƃ́AŽŸ‚Ì“ñ‚‚ðˆÓ–¡‚µ‚Ä‚¢‚Ü‚·B
+                ˆê‚‚̓Nƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ªA‚»‚̃Nƒ‰ƒX‚𖾎¦“I‚ÉŽw’肵‚½ƒNƒGƒŠ‚É‚æ‚Á‚Ä‚Ì‚Ý•Ô‚³‚ê‚邱‚ƂŁA
+                ‚à‚¤ˆê‚‚̓Nƒ‰ƒX‚ðŽw’肵‚½ƒNƒGƒŠ‚ªA<literal>&lt;class&gt;</literal> —v‘f‚Ì’†‚Å <literal>&lt;subclass&gt;</literal> ‚â 
+                <literal>&lt;joined-subclass&gt;</literal> ‚ƃ}ƒbƒsƒ“ƒO‚³‚ê‚Ä‚¢‚éƒTƒuƒNƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚¾‚¯‚ð•Ô‚·‚±‚Æ‚Å‚·B
+                ‚Ù‚Æ‚ñ‚Ç‚Ì—p“r‚ł̓fƒtƒHƒ‹ƒg‚Ì <literal>polymorphism="implicit"</literal> ‚ª“KØ‚Å‚·B
+                –¾Ž¦“I‚ȃ|ƒŠƒ‚[ƒtƒBƒYƒ€‚́A2‚‚̈á‚Á‚½ƒNƒ‰ƒX‚ª“¯‚¶ƒe[ƒuƒ‹‚Ƀ}ƒbƒsƒ“ƒO‚³‚ê‚Ä‚¢‚é‚Æ‚«‚É—L—p‚Å‚·
+                i‚±‚ê‚É‚æ‚Á‚ăe[ƒuƒ‹ƒJƒ‰ƒ€‚̃TƒuƒZƒbƒg‚ðŠÜ‚ށAuŒy—ʂȁvƒNƒ‰ƒX‚ª‰Â”\‚É‚È‚è‚Ü‚·jB
+            </para>
+            
+            <para>
+                <literal>persister</literal> ‘®«‚ðŽw’è‚·‚邱‚ƂŁAƒNƒ‰ƒX‚̉i‘±‰»í—ª‚ðƒJƒXƒ^ƒ}ƒCƒY‚Å‚«‚Ü‚·B
+                —Ⴆ‚Î <literal>org.hibernate.persister.EntityPersister</literal> Ž©g‚̃TƒuƒNƒ‰ƒX‚ðŽw’肵‚½‚èA
+                ‚Ü‚½—Ⴆ‚΃XƒgƒAƒhƒvƒƒV[ƒWƒƒƒR[ƒ‹Aƒtƒ‰ƒbƒgƒtƒ@ƒCƒ‹‚ÖƒVƒŠƒAƒ‰ƒCƒYA
+                LDAP‚È‚Ç‚ð’Ê‚µ‚½‰i‘±«‚ðŽÀ‘•‚·‚é <literal>org.hibernate.persister.ClassPersister</literal> 
+                ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ÌŠ®‘S‚ɐV‚µ‚¢ŽÀ‘•‚ð’ñ‹Ÿ‚Å‚«‚Ü‚·BŠÈ’P‚È—á‚Æ‚µ‚Ä <literal>org.hibernate.test.CustomPersister</literal> 
+                ‚ðŒ©‚Ä‚­‚¾‚³‚¢i‚±‚ê‚Í <literal>Hashtable</literal> ‚́u‰i‘±‰»v‚Å‚·jB
+                
+            </para>
+            
+            <para>
+                <literal>dynamic-update</literal> ‚Æ <literal>dynamic-insert</literal> ‚̐ݒè‚̓TƒuƒNƒ‰ƒX‚ÉŒp³‚³‚ê‚Ü‚¹‚ñB
+                ‚»‚Ì‚½‚ß <literal>&lt;subclass&gt;</literal> ‚â <literal>&lt;joined-subclass&gt;</literal> —v‘f‚ðŽw’è‚·‚邱‚Æ‚ào—ˆ‚Ü‚·B
+                ‚±‚ê‚ç‚̐ݒè‚̓pƒtƒH[ƒ}ƒ“ƒX‚ðŒüã‚³‚¹‚鎖‚à‚ ‚è‚Ü‚·‚ªA—Ž‚Æ‚·‚±‚Æ‚à‚ ‚è‚Ü‚·‚̂ŁATd‚ÉŽg—p‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+            
+            <para>
+                <literal>select-before-update</literal> ‚ÌŽg—p‚͒ʏíƒpƒtƒH[ƒ}ƒ“ƒX‚ð—Ž‚Æ‚µ‚Ü‚·B
+                ‚à‚µ <literal>Session</literal> ‚Ö•ª—£ƒCƒ“ƒXƒ^ƒ“ƒX‚̃Oƒ‰ƒt‚ðÄ’ljÁ‚·‚é‚È‚çA
+                ƒf[ƒ^ƒx[ƒXXV‚̃gƒŠƒK‚ð•s•K—v‚ɌĂяo‚·‚Ì‚ð”ð‚¯‚é‚Æ‚¢‚¤“_‚ŁA”ñí‚É—L—p‚Å‚·B
+            </para>
+            
+            <para>
+                <literal>dynamic-update</literal> ‚ð—LŒø‚É‚·‚ê‚΁AŠyŠÏƒƒbƒNí—ª‚ð‘I‚Ô‚±‚Æ‚É‚È‚è‚Ü‚·B
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <literal>version</literal> ƒo[ƒWƒ‡ƒ“/ƒ^ƒCƒ€ƒXƒ^ƒ“ƒvƒJƒ‰ƒ€‚ðƒ`ƒFƒbƒN‚µ‚Ü‚·
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>all</literal> ‚·‚ׂẴJƒ‰ƒ€‚ðƒ`ƒFƒbƒN‚µ‚Ü‚·B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>dirty</literal> •ÏX‚µ‚½ƒJƒ‰ƒ€‚ðƒ`ƒFƒbƒN‚µA“¯ŽžXV‚Å‚«‚é‚悤‚É‚µ‚Ü‚·B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>none</literal> ŠyŠÏƒƒbƒN‚ðŽg—p‚µ‚Ü‚¹‚ñ
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <para>
+                Hibernate‚ÅŠyŠÏ“IƒƒbƒNí—ª‚ðŽg‚¤‚È‚çAƒo[ƒWƒ‡ƒ“/ƒ^ƒCƒ€ƒXƒ^ƒ“ƒvƒJƒ‰ƒ€‚ðŽg‚¤‚±‚Æ‚ð
+                 <emphasis> ”ñí‚É</emphasis> ‹­‚­‚¨Š©‚ß‚µ‚Ü‚·B
+                ŠyŠÏ“IƒƒbƒN‚̓pƒtƒH[ƒ}ƒ“ƒX‚ÌŠÏ“_‚©‚ç‚àÅ“K‚Å‚ ‚èA‚³‚ç‚É•ª—£ƒCƒ“ƒXƒ^ƒ“ƒX‚ւ̏C³
+                i‚‚܂è <literal>Session.marge()</literal> ‚ªŽg‚í‚ê‚é‚Æ‚«j
+                ‚𐳊m‚Ɉµ‚¤‚±‚Æ‚Ì‚Å‚«‚é—Bˆê‚̐헪‚Å‚à‚ ‚è‚Ü‚·B
+            </para>
+            
+            <para>
+                Hibernate‚̃}ƒbƒsƒ“ƒO‚É‚Æ‚Á‚ărƒ…[‚Æ•’ʂ̃e[ƒuƒ‹‚̊ԂɈႢ‚Í‚È‚­A
+                ƒf[ƒ^ƒx[ƒXƒŒƒxƒ‹‚Å‚Í“§‰ß“I‚Å‚·
+                i‚½‚¾‚µƒrƒ…[‚ðŠ®‘S‚ɂ̓Tƒ|[ƒg‚µ‚Ä‚¢‚È‚¢DBMS‚à‚ ‚è‚Ü‚·B
+                “Á‚ɁAXV‚Ì‚ ‚éƒrƒ…[‚ɑ΂µ‚Ä‚Í‚»‚¤‚Å‚·jB
+                ƒrƒ…[‚ðŽg‚¢‚½‚­‚Ä‚àAƒf[ƒ^ƒx[ƒX‚ō쐬‚Å‚«‚È‚¢‚±‚Æ‚ª‚ ‚è‚Ü‚·
+                i—Ⴆ‚΁AƒŒƒKƒV[ƒXƒL[ƒ}‚̏ꍇjB
+                ‚±‚̏ꍇ‚ɂ́A•s•Ï‚©‚“ǂݎæ‚èê—p‚̃Gƒ“ƒeƒBƒeƒB‚É—^‚¦‚ç‚ꂽSQL‚Ì•›–⍇‚¹•¶‚ðƒ}ƒbƒv‚Å‚«‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[<class name="Summary">
+    <subselect>
+        select item.name, max(bid.amount), count(*)
+        from item
+        join bid on bid.item_id = item.id
+        group by item.name
+    </subselect>
+    <synchronize table="item"/>
+    <synchronize table="bid"/>
+    <id name="name"/>
+    ...
+</class>]]></programlisting>
+
+            <para>
+                ƒe[ƒuƒ‹‚ð‚±‚ÌƒGƒ“ƒeƒBƒeƒB‚Æ“¯Šú‚·‚é‚悤‚É’è‹`‚µ‚Ä‚­‚¾‚³‚¢B
+                ƒI[ƒgƒtƒ‰ƒbƒVƒ…‚ªŠmŽÀ‚É‹N‚±‚é‚悤‚ɁA‚Ü‚½“±oƒGƒ“ƒeƒBƒeƒB‚ɑ΂·‚éƒNƒGƒŠ‚ªŒÃ‚¢ƒf[ƒ^‚ð
+                •Ô‚³‚È‚¢‚悤‚É‚·‚邽‚ß‚Å‚·B
+                <literal>&lt;subselect&gt;</literal> ‚Í‘®«‚ƃlƒXƒg‚µ‚½ƒ}ƒbƒsƒ“ƒO‘®«‚Ì‚Ç‚¿‚ç‚Å‚à—˜—p‚Å‚«‚Ü‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-id" revision="4">
+            <title>id</title>
+
+            <para>
+                ƒ}ƒbƒv‚³‚ꂽƒNƒ‰ƒX‚̓f[ƒ^ƒx[ƒXƒe[ƒuƒ‹‚ÌŽåƒL[ƒJƒ‰ƒ€‚ð’è‹` <emphasis>‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ</emphasis> B
+                ‚Ù‚Æ‚ñ‚ǂ̃Nƒ‰ƒX‚ɂ̓Cƒ“ƒXƒ^ƒ“ƒX‚̃†ƒj[ƒN‚ÈŽ¯•ÊŽq‚ð•ÛŽ‚·‚éJavaBeansƒXƒ^ƒCƒ‹‚̃vƒƒpƒeƒB‚à‚ ‚è‚Ü‚·B
+                <literal>&lt;id&gt;</literal> —v‘f‚́A‚»‚̃vƒƒpƒeƒB‚©‚çŽåƒL[ƒJƒ‰ƒ€‚ւ̃}ƒbƒsƒ“ƒO‚ð’è‹`‚µ‚Ü‚·B
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="id1" coords="2 70"/>
+                    <area id="id2" coords="3 70" />
+                    <area id="id3" coords="4 70"/>
+                    <area id="id4" coords="5 70" />
+                    <area id="id5" coords="6 70" />
+                </areaspec>
+                <programlisting><![CDATA[<id
+        name="propertyName"
+        type="typename"
+        column="column_name"
+        unsaved-value="null|any|none|undefined|id_value"
+        access="field|property|ClassName">
+        node="element-name|@attribute-name|element/@attribute|."
+
+        <generator class="generatorClass"/>
+</id>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="id1">
+                        <para>
+                            <literal>name</literal>iƒIƒvƒVƒ‡ƒ“jFŽ¯•ÊŽqƒvƒƒpƒeƒB‚Ì–¼‘OB
+                        </para>
+                    </callout>
+                    <callout arearefs="id2">
+                        <para>
+                            <literal>type</literal>iƒIƒvƒVƒ‡ƒ“jFHibernate‚ÌŒ^‚ðŽ¦‚·–¼‘OB
+                        </para>
+                    </callout>
+                    <callout arearefs="id3">
+                        <para>
+                             <literal>column</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚̓vƒƒpƒeƒB–¼jF
+                            ŽåƒL[ƒJƒ‰ƒ€‚Ì–¼‘OB
+                        </para>
+                    </callout>
+                    <callout arearefs="id4">
+                        <para>
+                            <literal>unsaved-value</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Ì’l‚ÍsensiblejF
+                            ƒCƒ“ƒXƒ^ƒ“ƒX‚ªV‚µ‚­ƒCƒ“ƒXƒ^ƒ“ƒX‰»‚³‚ꂽ
+                            iƒZ[ƒu‚³‚ê‚Ä‚¢‚È‚¢j‚±‚Æ‚ðŽ¦‚·AŽ¯•ÊŽqƒvƒƒpƒeƒB‚Ì’lB
+                            ˆÈ‘O‚ÌSession‚ŃZ[ƒu‚Ü‚½‚̓[ƒh‚³‚ꂽˆêŽž“IƒCƒ“ƒXƒ^ƒ“ƒX‚Æ‹æ•Ê‚·‚邽‚ß‚É
+                            Žg‚¢‚Ü‚·B
+                        </para>
+                    </callout>            
+                   <callout arearefs="id5">
+                        <para>
+                            <literal>access</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>property</literal> jF
+                            ƒvƒƒpƒeƒB‚Ì’l‚ÖƒAƒNƒZƒX‚·‚邽‚ß‚ÉHibernate‚ªŽg‚¤í—ª‚Å‚·B
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                 <literal>name</literal> ‘®«‚ª‚È‚¯‚ê‚΁AƒNƒ‰ƒX‚É‚ÍŽ¯•ÊŽqƒvƒƒpƒeƒB‚ª‚È‚¢‚à‚Ì‚Æ‚Ý‚È‚³‚ê‚Ü‚·B
+            </para>
+            
+            <para>
+                <literal>unsaved-value</literal> ‘®«‚ÍHibernate3‚Å‚Í‚Ù‚Æ‚ñ‚ǂ̏ꍇA•K—v‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+            </para>
+
+             <para>
+                •¡‡ƒL[‚ðŽ‚ÂƒŒƒKƒV[ƒf[ƒ^‚ɃAƒNƒZƒX‚Å‚«‚é‚悤‚ɁA
+                <literal>&lt;composite-id&gt;</literal> ‚Æ‚¢‚¤‘ã‘ւ̃}ƒbƒsƒ“ƒO’è‹`‚ª‚ ‚è‚Ü‚·B
+                ‚µ‚©‚µ‘¼‚Ì—p“r‚Ö‚ÌŽg—p‚Í‘S‚­‚¨‚·‚·‚ß‚Å‚«‚Ü‚¹‚ñB
+            </para>
+            
+            <sect3 id="mapping-declaration-id-generator" revision="2">
+                <title>ƒWƒFƒlƒŒ[ƒ^</title>
+
+                <para>
+                    ƒIƒvƒVƒ‡ƒ“‚Ì <literal>&lt;generator&gt;</literal> Žq—v‘f‚́A
+                    ‰i‘±ƒNƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚̃†ƒj[ƒN‚ÈŽ¯•ÊŽq‚𐶐¬‚·‚邽‚ß‚ÉŽg‚¤AJavaƒNƒ‰ƒX‚ðŽw’肵‚Ü‚·B
+                    ƒWƒFƒlƒŒ[ƒ^ƒCƒ“ƒXƒ^ƒ“ƒX‚̐ݒèA‚à‚µ‚­‚͏‰Šú‰»‚Ƀpƒ‰ƒ[ƒ^‚ª•K—v‚Å‚ ‚ê‚΁A<literal>&lt;param&gt;</literal> 
+                    —v‘f‚ðŽg‚Á‚Ä“n‚·‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="org.hibernate.id.TableHiLoGenerator">
+                <param name="table">uid_table</param>
+                <param name="column">next_hi_value_column</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                    ‚·‚ׂẴWƒFƒlƒŒ[ƒ^‚́AƒCƒ“ƒ^[ƒtƒFƒCƒX 
+                    <literal>org.hibernate.id.IdentifierGenerator</literal> ‚ðŽÀ‘•‚µ‚Ü‚·B
+                    ‚±‚ê‚Í‚Æ‚Ä‚à’Pƒ‚ȃCƒ“ƒ^[ƒtƒFƒCƒX‚Ȃ̂ŁA“Á•Ê‚ÈŽÀ‘•‚ð“ÆŽ©‚É—pˆÓ‚·‚éƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚à‚ ‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                    ‚µ‚©‚µHibernate‚Í‘g‚ݍž‚Ý‚ÌŽÀ‘•‚ð‚¢‚­‚‚à—pˆÓ‚µ‚Ä‚¢‚Ü‚·B
+                    ‘g‚ݍž‚݂̃WƒFƒlƒŒ[ƒ^‚ɂ͈ȉº‚̃Vƒ‡[ƒgƒJƒbƒg–¼‚ª‚ ‚è‚Ü‚·F
+
+                    <variablelist>
+                        <varlistentry>
+                        <term><literal>increment</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>long</literal> , <literal>short</literal> , 
+                                <literal>int</literal> Œ^‚ÌŽ¯•ÊŽq‚𐶐¬‚µ‚Ü‚·B
+                                ‚±‚ê‚ç‚Í‘¼‚̃vƒƒZƒX‚ª“¯‚¶ƒe[ƒuƒ‹‚Ƀf[ƒ^‚ð‘}“ü‚µ‚È‚¢‚Æ‚«‚¾‚¯ƒ†ƒj[ƒN‚Å‚·B
+                                <emphasis>ƒNƒ‰ƒXƒ^“à‚Å‚ÍŽg‚í‚È‚¢‚Å‚­‚¾‚³‚¢</emphasis> B
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>identity</literal></term>
+                        <listitem>
+                            <para>
+                                DB2, MySQL, MS SQL Server, Sybase, HypersonicSQL‚ÌŽ¯•ÊŽqƒJƒ‰ƒ€‚ð
+                                ƒTƒ|[ƒg‚µ‚Ü‚·B
+                                •Ô‚³‚ê‚鎯•ÊŽq‚ÌŒ^‚Í <literal>long</literal> , <literal>short</literal> , 
+                                <literal>int</literal> ‚Ì‚¢‚¸‚ê‚©‚Å‚·B
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>sequence</literal></term>
+                        <listitem>
+                            <para>
+                                  DB2, PostgreSQL, Oracle, SAP DB, McKoi‚̃V[ƒPƒ“ƒX‚âAInterbase‚̃WƒFƒlƒŒ[ƒ^‚ðŽg—p‚µ‚Ü‚·B
+                                  •Ô‚³‚ê‚鎯•ÊŽq‚ÌŒ^‚Í <literal>long</literal> , <literal>short</literal> , 
+                                <literal>int</literal> ‚Ì‚¢‚¸‚ê‚©‚Å‚·B
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>hilo</literal></term>
+                        <listitem>
+                            <para id="mapping-declaration-id-hilodescription" revision="1">
+                                 <literal>long</literal> , <literal>short</literal> , 
+                                <literal>int</literal> Œ^‚ÌŽ¯•ÊŽq‚ðŒø—¦“I‚ɐ¶¬‚·‚éhi/loƒAƒ‹ƒSƒŠƒYƒ€‚ðŽg‚¢‚Ü‚·B
+                                hi’l‚̃\[ƒX‚Æ‚µ‚āAƒe[ƒuƒ‹‚ƃJƒ‰ƒ€‚ð—^‚¦‚Ü‚·(ƒfƒtƒHƒ‹ƒg‚Å‚Í‚»‚ꂼ‚ê <literal>hibernate_unique_key</literal> ‚Æ 
+                                <literal>next_hi</literal> )B
+                               
+                                hi/loƒAƒ‹ƒSƒŠƒYƒ€‚Í“Á’è‚̃f[ƒ^ƒx[ƒX‚ɑ΂µ‚Ă̂݃†ƒj[ƒN‚ÈŽ¯•ÊŽq‚𐶐¬‚µ‚Ü‚·B
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>seqhilo</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>long</literal> , <literal>short</literal> , 
+                                <literal>int</literal> Œ^‚ÌŽ¯•ÊŽq‚ðŒø—¦“I‚ɐ¶¬‚·‚éhi/loƒAƒ‹ƒSƒŠƒYƒ€‚ðŽg‚¢‚Ü‚·B
+                                Žw’肳‚ꂽƒf[ƒ^ƒx[ƒXƒV[ƒPƒ“ƒX‚ð—^‚¦‚Ü‚·B
+                                
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>uuid</literal></term>
+                        <listitem>
+                            <para>
+                                (IPƒAƒhƒŒƒX‚ªŽg—p‚³‚ê‚é)ƒlƒbƒgƒ[ƒN“à‚цƒj[ƒN‚È•¶Žš—ñŒ^‚ÌŽ¯•ÊŽq‚𐶐¬‚·‚邽‚߂ɁA
+                                128ƒrƒbƒg‚ÌUUIDƒAƒ‹ƒSƒŠƒYƒ€‚ðŽg—p‚µ‚Ü‚·BUUID‚Í’·‚³32‚Ì16i”Žš‚Ì•¶Žš—ñ‚Æ‚µ‚ăGƒ“ƒR[ƒh‚³‚ê‚Ü‚·B
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>guid</literal></term>
+                        <listitem>
+                            <para>
+                                MS SQLƒT[ƒo‚ÆMySQL‚Ńf[ƒ^ƒx[ƒX‚ª¶¬‚·‚éGUID•¶Žš—ñ‚ðŽg—p‚µ‚Ü‚·B
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>native</literal></term>
+                        <listitem>
+                            <para>
+                                Žg—p‚·‚éƒf[ƒ^ƒx[ƒX‚̐«”\‚É‚æ‚è <literal>identity</literal> , <literal>sequence</literal> , 
+                                <literal>hilo</literal> ‚Ì‚¢‚¸‚ê‚©‚ª‘I‚΂ê‚Ü‚·B
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>assigned</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>save()</literal> ‚ªŒÄ‚΂ê‚é‘O‚ɁA
+                                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ªƒIƒuƒWƒFƒNƒg‚ÉŽ¯•ÊŽq‚ð‘ã“ü‚Å‚«‚é‚悤‚É‚µ‚Ü‚·B
+                                <literal>&lt;generator&gt;</literal> ‚ªŽw’肳‚ê‚Ä‚¢‚È‚¯‚ê‚΁A‚±‚ꂪƒfƒtƒHƒ‹ƒg‚̐헪‚É‚È‚è‚Ü‚·B
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>select</literal></term>
+                        <listitem>
+                            <para>
+                                ‚ ‚郆ƒj[ƒNƒL[‚É‚æ‚és‚Ì‘I‘ð‚ÆŽåƒL[‚Ì’l‚Ì•œŒ³‚É‚æ‚èA
+                                ƒf[ƒ^ƒx[ƒXƒgƒŠƒK‚ªŠ„‚è“–‚Ä‚½ŽåƒL[‚ðŽæ“¾‚µ‚Ü‚·B
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>foreign</literal></term>
+                        <listitem>
+                            <para>
+                                ‘¼‚ÌŠÖ˜AƒIƒuƒWƒFƒNƒg‚ÌŽ¯•ÊŽq‚ðŽg‚¢‚Ü‚·B
+                                •’ʂ́A<literal>&lt;one-to-one&gt;</literal> ŽåƒL[ŠÖ˜A‚Æ‘g‚ݍ‡‚킹‚ÄŽg‚¢‚Ü‚·B
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                    </variablelist>
+
+                </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-hilo" revision="1">
+                <title>Hi/lo ƒAƒ‹ƒSƒŠƒYƒ€</title>
+                <para>
+                    <literal>hilo</literal> ‚Æ <literal>seqhilo</literal> ƒWƒFƒlƒŒ[ƒ^‚́A
+                    Ž¯•ÊŽq¶¬‚Ì‘ã•\“I‚ȃAƒvƒ[ƒ`‚Å‚ ‚éhi/loƒAƒ‹ƒSƒŠƒYƒ€‚Ì2‚‚̑ã‘ÖŽÀ‘•‚ð’ñ‹Ÿ‚µ‚Ü‚·B
+                    
+                    1”Ô–Ú‚ÌŽÀ‘•‚́AŽŸ‰ñ‚É—˜—p‚³‚ê‚é"hi"’l‚ð•ÛŽ‚·‚éu“Á•Ê‚ȁvƒf[ƒ^ƒx[ƒXƒe[ƒuƒ‹‚ð
+                    •K—v‚Æ‚µ‚Ü‚·B
+                    2”Ô–Ú‚ÌŽÀ‘•‚́AOracleƒXƒ^ƒCƒ‹‚̃V[ƒPƒ“ƒX‚ðŽg‚¢‚Ü‚·iƒTƒ|[ƒg‚³‚ê‚Ä‚¢‚éê‡jB
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="hilo">
+                <param name="table">hi_value</param>
+                <param name="column">next_value</param>
+                <param name="max_lo">100</param>
+        </generator>
+</id>]]></programlisting>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="seqhilo">
+                <param name="sequence">hi_value</param>
+                <param name="max_lo">100</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                    Žc”O‚È‚ª‚çHibernate‚Ö‚Ì“ÆŽ©‚Ì <literal>Connection</literal> ‚ð’ñ‹Ÿ‚·‚é‚Æ‚«‚ɂ́A<literal>hilo</literal> ‚ðŽg‚¦‚Ü‚¹‚ñB
+                    Hibernate‚ªJTA‚ŃŠƒXƒg‚³‚ê‚Ä‚¢‚éÚ‘±‚ðŽæ“¾‚·‚邽‚߂ɃAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo[‚̃f[ƒ^ƒ\[ƒX‚ðŽg—p‚µ‚Ä‚¢‚é‚Æ‚«‚ɂ́A
+                    <literal>hibernate.transaction.manager_lookup_class</literal> ‚ð“KØ‚ɐݒ肵‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-uuid">
+                <title>UUID ƒAƒ‹ƒSƒŠƒYƒ€</title>
+                <para>
+                    UUID‚ɂ͈ȉº‚Ì‚à‚Ì‚ªŠÜ‚Ü‚ê‚Ü‚·F
+                    IPƒAƒhƒŒƒXAJVM‚̃Xƒ^[ƒgƒAƒbƒvƒ^ƒCƒ€i4•ª‚Ì1•b‚̐³Šm‚³jA
+                    ƒVƒXƒeƒ€ŽžŠÔAiJVM‚ɑ΂µ‚ă†ƒj[ƒN‚ȁjƒJƒEƒ“ƒ^’lB
+                    JavaƒR[ƒh‚©‚çMACƒAƒhƒŒƒX‚⃁ƒ‚ƒŠƒAƒhƒŒƒX‚ðŽæ“¾‚·‚邱‚Æ‚Í‚Å‚«‚È‚¢‚̂ŁA
+                    JNI‚ªŽg‚¦‚È‚¢‚Æ‚«‚̍ŗǂ̕û–@‚Å‚·B
+                </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-sequences">
+            <title>Ž¯•ÊŽqƒJƒ‰ƒ€‚ƃV[ƒPƒ“ƒX</title>
+                <para>
+                    Ž¯•ÊŽqƒJƒ‰ƒ€‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚éƒf[ƒ^ƒx[ƒXiDB2, MySQL, Sybase, MS SQLj‚ł́A
+                    <literal>identity</literal> ƒL[¶¬‚ðŽg‚¦‚Ü‚·B
+                    ƒV[ƒPƒ“ƒX‚ðƒTƒ|[ƒg‚·‚éƒf[ƒ^ƒx[ƒXiDB2, Oracle, PostgreSQL, Interbase, McKoi, SAP DBj‚ł́A
+                    <literal>sequence</literal> ƒXƒ^ƒCƒ‹‚̃L[¶¬‚ðŽg‚¦‚Ü‚·B
+                    ‚Ç‚¿‚ç‚̐헪‚àAV‚µ‚¢ƒIƒuƒWƒFƒNƒg‚ð‘}“ü‚·‚邽‚߂ɁASQLƒNƒGƒŠ‚ð2‚•K—v‚Æ‚µ‚Ü‚·B
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+        <generator class="sequence">
+                <param name="sequence">person_id_sequence</param>
+        </generator>
+</id>]]></programlisting>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id" unsaved-value="0">
+        <generator class="identity"/>
+</id>]]></programlisting>
+            
+                <para>
+                    ƒNƒƒXƒvƒ‰ƒbƒgƒtƒH[ƒ€‚ÌŠJ”­‚ł́A<literal>native</literal> í—ª‚Í 
+                    <literal>identity</literal> , <literal>sequence</literal> , 
+                    <literal>hilo</literal> í—ª‚Ì’†‚©‚ç1‚‚ð‘I‘ð‚µ‚Ü‚·‚ªA
+                    ‚±‚ê‚ÍŽg—p‚µ‚Ä‚¢‚éƒf[ƒ^ƒx[ƒX‚Ì”\—͂Ɉˑ¶‚µ‚Ü‚·B
+                </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-assigned">
+                <title>Ž¯•ÊŽq‚ÌŠ„‚è“–‚Ä</title>
+                <para>
+                   ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ÉŽ¯•ÊŽq‚ðŠ„‚è“–‚Ä‚³‚¹‚½‚¢‚Ì‚Å‚ ‚ê‚Î(Hibernate‚ª¶¬‚·‚é‚à‚Ì‚Å‚Í‚È‚­jA
+                    <literal>assigned</literal> ƒWƒFƒlƒŒ[ƒ^‚ðŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+                    ‚±‚Ì“Á•Ê‚ȃWƒFƒlƒŒ[ƒ^‚́A‚·‚łɃIƒuƒWƒFƒNƒg‚ÌŽ¯•ÊŽqƒvƒƒpƒeƒB‚É‘ã“ü‚³‚ꂽ’l‚ð
+                    Ž¯•ÊŽq‚ÉŽg‚¢‚Ü‚·B‚±‚̃WƒFƒlƒŒ[ƒ^‚ÍŽåƒL[‚ª‘㗝ƒL[‚Ì‘ã‚í‚è‚ÉŽ©‘RƒL[‚Å‚ ‚éê‡‚ÉŽg—p‚µ‚Ü‚·B
+                    <literal>&lt;generator&gt;</literal> —v‘f‚ðŽw’肵‚È‚¢ê‡‚̃fƒtƒHƒ‹ƒg‚Ì“®ì‚É‚È‚è‚Ü‚·B
+                </para>
+                
+                <para>
+                    <literal>assigned</literal> ƒWƒFƒlƒŒ[ƒ^‚ð‘I‘ð‚·‚é‚ƁA
+                    Hibernate‚Í <literal>unsaved-value="undefined"</literal> ‚ðŽg—p‚µ‚Ü‚·B
+                    ‚»‚µ‚āAƒo[ƒWƒ‡ƒ“‚âƒ^ƒCƒ€ƒXƒ^ƒ“ƒv‚̃vƒƒpƒeƒB‚ª‚È‚¢ê‡‚â <literal>Interceptor.isUnsaved()</literal> 
+                    ‚ð’è‹`‚µ‚È‚©‚Á‚½ê‡‚ɂ́AƒCƒ“ƒXƒ^ƒ“ƒX‚ªˆêŽž“I(transient)‚È‚à‚Ì‚Å‚ ‚é‚Ì‚©A
+                    ‚Ü‚½‚̓ZƒbƒVƒ‡ƒ“‚©‚番—£(detached)‚µ‚½‚à‚Ì‚©‚Ç‚¤‚©‚ðŒˆ‚ß‚é‚½‚߂ɁAƒf[ƒ^ƒx[ƒX‚𒲂ׂ܂·B
+                </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-select">
+                <title>ƒgƒŠƒK‚É‚æ‚芄‚è“–‚Ä‚ç‚ꂽŽåƒL[</title>
+                <para>
+                    ƒŒƒKƒV[ƒXƒL[ƒ}‚Ì‚½‚ß‚É‚Ì‚ÝŽw’肵‚Ü‚·(Hibernate‚̓gƒŠƒK‚ðŽg‚Á‚ÄDDL‚𐶐¬‚µ‚Ü‚¹‚ñ)B
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+        <generator class="select">
+                <param name="key">socialSecurityNumber</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                    ã‚Ì—á‚Ì’†‚ŁAƒNƒ‰ƒX‚ÅŽ©‘RƒL[‚Æ‚µ‚Ä’è‹`‚³‚ꂽ
+                    <literal>socialSecurityNumber</literal> ‚Æ‚¢‚¤–¼‘O‚̃†ƒj[ƒN‚È’l‚̃vƒƒpƒeƒB‚ƁA
+                    ’l‚ªƒgƒŠƒK‚É‚æ‚萶¬‚³‚ê‚é <literal>person_id</literal> ‚Æ‚¢‚¤–¼‘O‚̑㗝ƒL[‚ª‚ ‚è‚Ü‚·B
+                </para>
+                
+            </sect3>
+
+        </sect2>
+        
+        <sect2 id="mapping-declaration-compositeid" revision="3">
+            <title>composite-id</title>
+
+            <programlisting><![CDATA[<composite-id
+        name="propertyName"
+        class="ClassName"
+        mapped="true|false"
+        access="field|property|ClassName">
+        node="element-name|."
+
+        <key-property name="propertyName" type="typename" column="column_name"/>
+        <key-many-to-one name="propertyName class="ClassName" column="column_name"/>
+        ......
+</composite-id>]]></programlisting>
+
+            <para>
+                •¡‡ƒL[‚Ì‚ ‚éƒe[ƒuƒ‹‚ɑ΂µA
+                Ž¯•ÊŽqƒvƒƒpƒeƒB‚Æ‚µ‚ăNƒ‰ƒX‚Ì•¡”‚̃vƒƒpƒeƒB‚ðƒ}ƒbƒsƒ“ƒO‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+                <literal>&lt;composite-id&gt;</literal> —v‘f‚́AŽq—v‘f‚Æ‚µ‚Ä 
+                <literal>&lt;key-property&gt;</literal> ƒvƒƒpƒeƒBƒ}ƒbƒsƒ“ƒO‚Æ 
+                <literal>&lt;key-many-to-one&gt;</literal> ƒ}ƒbƒsƒ“ƒO‚ðŽó‚¯“ü‚ê‚Ü‚·B
+            </para>
+            
+            <programlisting><![CDATA[<composite-id>
+        <key-property name="medicareNumber"/>
+        <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+            <para>
+                 •¡‡Ž¯•ÊŽq‚Ì“™‰¿«‚ðŽÀ‘•‚·‚邽‚߂ɂ́A‰i‘±ƒNƒ‰ƒX‚ª <literal>equals()</literal> ‚Æ 
+                <literal>hashCode()</literal> ‚ðƒI[ƒo[ƒ‰ƒCƒh <emphasis>‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ</emphasis> B
+                ‚Ü‚½ <literal>Serializable</literal> ‚àŽÀ‘•‚µ‚È‚¯‚ê‚΂¢‚¯‚Ü‚¹‚ñB
+            </para>
+
+            <para>
+                Žc”O‚È‚ª‚ç•¡‡Ž¯•ÊŽq‚Ì‚½‚ß‚Ì‚±‚Ì•û–@‚́A
+                ‰i‘±ƒIƒuƒWƒFƒNƒg‚ªŽ©g‚ÌŽ¯•ÊŽq‚Å‚ ‚邱‚Æ‚ðˆÓ–¡‚µ‚Ä‚¢‚Ü‚·B
+                ƒIƒuƒWƒFƒNƒgŽ©g‚ðŽ¯•ÊŽq‚Æ‚·‚éˆÈã‚Ì•Ö—˜‚ȁuˆµ‚¢•ûv‚Í‚ ‚è‚Ü‚¹‚ñB
+                •¡‡ƒL[‚ÉŠÖ˜A‚µ‚½‰i‘±ó‘Ô‚ð <literal>load()</literal> o—ˆ‚é‚悤‚É‚È‚é‘O‚ɁA
+                ‰i‘±ƒNƒ‰ƒXŽ©g‚ðƒCƒ“ƒXƒ^ƒ“ƒX‰»‚µAŽ¯•ÊŽqƒvƒƒpƒeƒB‚ðÝ’肵‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                <emphasis> ‘g‚ݍž‚Ý‚Ì</emphasis> •¡‡Ž¯•ÊŽq‚ƌĂ΂ê‚邱‚̃Aƒvƒ[ƒ`‚́A
+                –{Ši“I‚ȃAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚ÍŒü‚¢‚Ä‚¢‚Ü‚¹‚ñB
+                
+                
+            </para>
+            
+            <para>
+                2‚–ڂ̕û–@‚Í <emphasis> ƒ}ƒbƒv‚³‚ꂽ</emphasis> •¡‡Ž¯•ÊŽq‚ƌĂ΂ê‚é‚à‚̂ŁA
+                <literal>&lt;composite-id&gt;</literal>ƒGƒŒƒƒ“ƒg“à‚ÅŽw’肵‚½Ž¯•ÊƒvƒƒpƒeƒB‚ª
+                ‰i‘±ƒNƒ‰ƒX‚Æ•ª—£‚µ‚½Ž¯•ÊŽqƒNƒ‰ƒX‚Ì—¼•û‚ɏd•¡‚µ‚Ä‘¶Ý‚µ‚Ü‚·B
+            </para>
+                
+            <programlisting><![CDATA[<composite-id class="MedicareId" mapped="true">
+        <key-property name="medicareNumber"/>
+        <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+            <para>
+                ‚±‚Ì—á‚ł́A•¡‡Ž¯•ÊŽqƒNƒ‰ƒXi <literal>MedicareId</literal> j‚ƃGƒ“ƒeƒBƒeƒBƒNƒ‰ƒXŽ©g‚Ì—¼•û‚ªA
+                <literal>medicareNumber</literal> ‚Æ <literal>dependent</literal> ‚Æ‚¢‚¤–¼‘O‚̃vƒƒpƒeƒB‚ðŽ‚¿‚Ü‚·B
+                Ž¯•ÊŽqƒNƒ‰ƒX‚́A<literal>equals()</literal> ‚Æ <literal>hashCode()</literal> ‚ðƒI[ƒoƒ‰ƒCƒh‚µA
+                <literal>Serializable</literal> ‚ðŽÀ‘•‚µ‚È‚­‚Ä‚Í‚È‚è‚Ü‚¹‚ñB
+                ‚±‚Ì•û–@‚ɂ́A–¾‚ç‚©‚ɃR[ƒh‚ªd•¡‚·‚é‚Æ‚¢‚¤•s“s‡‚ª‚ ‚è‚Ü‚·B
+            </para>
+            
+            <para>
+                ŽŸ‚Ì‘®«‚̓}ƒbƒsƒ“ƒO‚µ‚½•¡‡Ž¯•ÊŽq‚ðŽw’è‚·‚邽‚ß‚ÉŽg—p‚µ‚Ü‚·B
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>mapped</literal> (ƒIƒvƒVƒ‡ƒ“AƒfƒtƒHƒ‹ƒg‚Í <literal>false</literal> ):
+                        ƒ}ƒbƒsƒ“ƒO‚µ‚½•¡‡Ž¯•ÊŽq‚ªŽg—p‚³‚ê‚邱‚ƂƁA•ïŠÜ‚³‚ꂽƒvƒƒpƒeƒB‚̃}ƒbƒsƒ“ƒO‚ªA
+                        ƒGƒ“ƒeƒBƒeƒBƒNƒ‰ƒX‚Æ•¡‡Ž¯•ÊŽqƒNƒ‰ƒX‚Ì—¼•û‚ðŽQÆ‚·‚邱‚Æ‚ðŽ¦‚µ‚Ü‚·B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>class</literal> (ƒIƒvƒVƒ‡ƒ“,‚½‚¾‚µƒ}ƒbƒsƒ“ƒO‚µ‚½•¡‡Ž¯•ÊŽq‚É‚Í•K{): 
+                        •¡‡Ž¯•ÊŽq‚Æ‚µ‚ÄŽg—p‚·‚éƒNƒ‰ƒXB
+                        
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                3‚–ڂ̂³‚ç‚É•Ö—˜‚È•û–@‚́A•¡‡Ž¯•ÊŽq‚ð<xref linkend="components-compositeid"/>“à‚Ì
+                ƒRƒ“ƒ|[ƒlƒ“ƒgƒNƒ‰ƒX‚Æ‚µ‚ÄŽÀ‘•‚·‚邱‚Æ‚Å‚·B
+                ‰º‚Å‹Lq‚µ‚Ä‚¢‚é‘®«‚́A‚±‚Ì‘ã‘Ö•û–@‚É‚Ì‚Ý“K—p‚³‚ê‚Ü‚·B
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>name</literal> (ƒIƒvƒVƒ‡ƒ“, ‚±‚̃Aƒvƒ[ƒ`‚Å‚Í•K{): 
+                        •¡‡Ž¯•ÊŽq‚ð•ÛŽ‚·‚éƒRƒ“ƒ|[ƒlƒ“ƒgƒ^ƒCƒv‚̃vƒƒpƒeƒB(9Í‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>access</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>property</literal> ): 
+                        Hibernate‚ªƒvƒƒpƒeƒB‚Ì’l‚ɃAƒNƒZƒX‚·‚邽‚ß‚ÉŽg—p‚·‚ׂ«í—ªB
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>class</literal> 
+                        iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚̓ŠƒtƒŒƒNƒVƒ‡ƒ“‚É‚æ‚茈’肳‚ê‚éƒvƒƒpƒeƒB‚ÌŒ^jF
+                        •¡‡Ž¯•ÊŽq‚Æ‚µ‚ÄŽg‚í‚ê‚éƒRƒ“ƒ|[ƒlƒ“ƒg‚̃Nƒ‰ƒXiŽŸ‚Ìß‚ðŒ©‚Ä‚­‚¾‚³‚¢jB
+                    </para>
+                </listitem>
+            </itemizedlist>
+            
+            <para>
+                ‚±‚Ì3‚–ڂ̕û–@‚Í <emphasis> Ž¯•ÊŽqƒRƒ“ƒ|[ƒlƒ“ƒg</emphasis> ‚ƌĂсA
+                ‚Ù‚Æ‚ñ‚Ç‚·‚ׂẴAƒvƒŠƒP[ƒVƒ‡ƒ“‚ɑ΂µ‚Đ„§‚·‚é•û–@‚Å‚·B
+            </para>
+            
+        </sect2>        
+        
+        <sect2 id="mapping-declaration-discriminator" revision="3">
+            <title>discriminator</title>
+
+            <para>
+                <literal>&lt;discriminator&gt;</literal> —v‘f‚́A
+                table-per-class-hierarchyƒ}ƒbƒsƒ“ƒOí—ª‚ðŽg‚¤ƒ|ƒŠƒ‚[ƒtƒBƒbƒN‚ȉi‘±‰»‚É•K—v‚Å‚ ‚èA
+                ƒe[ƒuƒ‹‚ÌŽ¯•ÊƒJƒ‰ƒ€‚ð’è‹`‚µ‚Ü‚·B
+                Ž¯•ÊƒJƒ‰ƒ€‚́A‚ ‚és‚ɑ΂µ‚ĉi‘±‘w‚ª‚ǂ̃TƒuƒNƒ‰ƒX‚ðƒCƒ“ƒXƒ^ƒ“ƒX‰»‚·‚é‚©‚ð
+                “`‚¦‚éƒ}[ƒJ[’l‚ðŠÜ‚ñ‚Å‚¢‚Ü‚·B
+                ˆÈ‰º‚̂悤‚ÈŒ^‚ɐ§ŒÀ‚³‚ê‚Ü‚·F <literal>string</literal> , <literal>character</literal> , 
+                <literal>integer</literal>, 
+                <literal>byte</literal> , <literal>short</literal> , <literal>boolean</literal> , 
+                <literal>yes_no</literal> , <literal>true_false</literal>. 
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="discriminator1" coords="2 60"/>
+                    <area id="discriminator2" coords="3 60" />
+                    <area id="discriminator3" coords="4 60" />
+                    <area id="discriminator4" coords="5 60" />
+                    <area id="discriminator5" coords="6 60" />
+                </areaspec>
+                <programlisting><![CDATA[<discriminator
+        column="discriminator_column"
+        type="discriminator_type"
+        force="true|false"
+        insert="true|false"
+        formula="arbitrary sql expression"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="discriminator1">
+                        <para>
+                            <literal>column</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>class</literal> jF
+                            Ž¯•ÊƒJƒ‰ƒ€‚Ì–¼‘OB
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator2">
+                        <para>
+                            <literal>type</literal> 
+                            iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>string</literal> jFHibernate‚ÌŒ^‚ðŽ¦‚·–¼‘OB
+                        </para>
+                    </callout>          
+                    <callout arearefs="discriminator3">
+                        <para>
+                            <literal>force</literal> 
+                            iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>false</literal> jF
+                            ƒ‹[ƒgƒNƒ‰ƒX‚Ì‚·‚ׂẴCƒ“ƒXƒ^ƒ“ƒX‚ðŒŸõ‚·‚éê‡‚Å‚ ‚Á‚Ä‚àA
+                            Hibernate‚ªŽg—p‚Å‚«‚鎯•ÊƒJƒ‰ƒ€‚ÌŽw’è‚ðu‹­§v‚µ‚Ü‚·B
+                        </para>
+                    </callout>          
+                    <callout arearefs="discriminator4">
+                        <para>
+                            <literal>insert</literal> 
+                            iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal> jF
+                            ‚à‚µŽ¯•ÊƒJƒ‰ƒ€‚ªƒ}ƒbƒsƒ“ƒO‚·‚é•¡‡Ž¯•ÊŽq‚̈ꕔ‚È‚ç‚΁A<literal>false</literal> ‚Ɛݒ肵‚Ä‚­‚¾‚³‚¢B
+                            (Hibernate‚ÉSQL‚Ì <literal>INSERT</literal> ‚É‚ÍŠÜ‚Ü‚ê‚È‚¢‚±‚Æ‚ð’m‚点‚é)
+                            
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator5">
+                        <para>
+                            <literal>formula</literal> (ƒIƒvƒVƒ‡ƒ“)Œ^‚ª•]‰¿‚³‚ê‚é‚Æ‚«‚ÉŽÀs‚³‚ê‚é”CˆÓ‚ÌSQLŽ®B
+                            ƒRƒ“ƒeƒ“ƒcƒx[ƒX‚ÌŽ¯•Ê‚ð‰Â”\‚É‚µ‚Ü‚·B
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Ž¯•ÊƒJƒ‰ƒ€‚ÌŽÀÛ‚Ì’l‚́A <literal>&lt;class&gt;</literal> ‚Æ 
+                <literal>&lt;subclass&gt;</literal> —v‘f‚Ì 
+                <literal>discriminator-value</literal> ‘®«‚ÅŽw’肳‚ê‚Ü‚·B
+            </para>
+            
+            <para>
+                ‰i‘±ƒNƒ‰ƒX‚Öƒ}ƒbƒsƒ“ƒO‚³‚ê‚È‚¢¢—]•ª‚ȁvŽ¯•Ê’l‚ðŽ‚Âs‚ª
+                ƒe[ƒuƒ‹‚É‚ ‚ê‚΁Ai‚»‚Ì‚Æ‚«‚ÉŒÀ‚èj<literal>force</literal> ‘®«‚Í—LŒø‚Å‚·B
+                ‚½‚¾‚µA•’Ê‚Í‚»‚¤‚¢‚¤‚±‚Æ‚Í‚ ‚è‚Ü‚¹‚ñB
+            </para>
+
+            <para>
+                <literal>formula</literal> ‘®«‚ðŽg‚¤‚ƁAs‚ÌŒ^‚ð•]‰¿‚·‚邽‚ß‚É”CˆÓ‚ÌSQLŽ®‚ðéŒ¾‚Å‚«‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[<discriminator
+    formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
+    type="integer"/>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-version" revision="4">
+            <title>versioniƒIƒvƒVƒ‡ƒ“j</title>
+            
+            <para>
+                <literal>&lt;version&gt;</literal> —v‘f‚̓IƒvƒVƒ‡ƒ“‚Å‚ ‚èA
+                ƒe[ƒuƒ‹‚ªƒo[ƒWƒ‡ƒ“ƒf[ƒ^‚ðŠÜ‚Þ‚±‚Æ‚ðŽ¦‚µ‚Ü‚·B
+                ‚±‚ê‚Í <emphasis>ƒƒ“ƒOƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“</emphasis>  
+                ‚ðŽg‚¤‚‚à‚è‚È‚çA“Á‚ɖ𗧂¿‚Ü‚·iˆÈ‰º‚ðŒ©‚Ä‚­‚¾‚³‚¢jB
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="version1" coords="2 70"/>
+                    <area id="version2" coords="3 70"/>
+                    <area id="version3" coords="4 70"/>
+                    <area id="version4" coords="5 70"/>
+                    <area id="version5" coords="6 70"/>
+                    <area id="version6" coords="7 70"/>
+                    <area id="version7" coords="8 70"/>                    
+                </areaspec>
+                <programlisting><![CDATA[<version
+        column="version_column"
+        name="propertyName"
+        type="typename"
+        access="field|property|ClassName"
+        unsaved-value="null|negative|undefined"
+        generated="never|always"
+        insert="true|false"
+        node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="version1">
+                        <para>
+                            <literal>column</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚̓vƒƒpƒeƒB–¼j:
+                            ƒo[ƒWƒ‡ƒ“”ԍ†‚ð•ÛŽ‚·‚éƒJƒ‰ƒ€‚Ì–¼‘OB
+                        </para>
+                    </callout>          
+                    <callout arearefs="version2">
+                        <para>
+                            <literal>name</literal> F‰i‘±ƒNƒ‰ƒX‚̃vƒƒpƒeƒB‚Ì–¼‘OB
+                        </para>
+                    </callout>
+                    <callout arearefs="version3">
+                        <para>
+                            <literal>type</literal> 
+                            iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>integer</literal> jFƒo[ƒWƒ‡ƒ“”ԍ†‚ÌŒ^B
+                        </para>
+                    </callout>          
+                   <callout arearefs="version4">
+                        <para>
+                            <literal>access</literal> 
+                            iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>property</literal> jF
+                            ƒvƒƒpƒeƒB‚Ì’l‚ւ̃AƒNƒZƒX‚ÉHibernate‚ªŽg‚¤í—ªB
+                        </para>
+                    </callout>
+                   <callout arearefs="version5">
+                        <para>
+                            <literal>unsaved-value</literal> 
+                            iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>undefined</literal> jF
+                            ƒCƒ“ƒXƒ^ƒ“ƒX‚ªV‚µ‚­ƒCƒ“ƒXƒ^ƒ“ƒX‰»‚³‚ꂽ‚±‚Æ‚ðŽ¦‚·
+                            iƒZ[ƒu‚³‚ê‚Ä‚¢‚È‚¢‚±‚Æ‚ðŽ¦‚·jƒo[ƒWƒ‡ƒ“ƒvƒƒpƒeƒB‚Ì’lB
+                            ˆÈ‘O‚ÌSession‚ŃZ[ƒu‚Ü‚½‚̓[ƒh‚³‚ꂽˆêŽž“I‚ȃCƒ“ƒXƒ^ƒ“ƒX‚Æ‹æ•Ê‚·‚邽‚ß‚É
+                            Žg‚¢‚Ü‚·B
+                            i <literal>undefined</literal> ‚ÍŽ¯•ÊŽqƒvƒƒpƒeƒB‚Ì’l‚ªŽg‚í‚ê‚邱‚Æ‚ðŽw’肵‚Ü‚·Bj
+                        </para>
+                    </callout>
+                    
+                    <callout arearefs="version6">
+                        <para>
+                            <literal>generated</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>never</literal> ):
+                            ‚±‚̃o[ƒWƒ‡ƒ“‚̃vƒƒpƒeƒB‚Ì’l‚ªAƒf[ƒ^ƒx[ƒX‚É‚æ‚Á‚ж¬‚³‚ꂽ‚±‚Æ‚ðŽw’肵‚Ü‚·B
+                            <xref linkend="mapping-generated">¶¬ƒvƒƒpƒeƒB</xref> ‚Ì‹c˜_‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+                        </para>
+                    </callout>
+                    <callout arearefs="version7">
+                        <para>
+                            <literal>insert</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal> ):
+                            SQL‚Ìinsert•¶‚Ƀo[ƒWƒ‡ƒ“EƒJƒ‰ƒ€‚ðŠÜ‚ß‚é‚ׂ«‚©‚Ç‚¤‚©‚ðŽw’肵‚Ü‚·B
+                            ‚à‚µƒf[ƒ^ƒx[ƒXEƒJƒ‰ƒ€‚̃fƒtƒHƒ‹ƒg’l‚ª <literal>0</literal> ‚Æ’è‹`‚³‚ê‚é‚Æ‚«‚ɂ́A
+                            <literal>false</literal> ‚ɐݒ肷‚é‚Æ—Ç‚¢‚Å‚µ‚傤B
+                        </para>
+                    </callout>                    
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                ƒo[ƒWƒ‡ƒ“”ԍ†‚Í Hibernate‚Ì <literal>long</literal> , <literal>integer</literal> , 
+                <literal>short</literal> , <literal>timestamp</literal> , 
+                <literal>calendar</literal> Œ^‚Ì‚¢‚¸‚ê‚©‚Å‚·B
+            </para>
+            
+            <para>
+                ƒo[ƒWƒ‡ƒ“‚âƒ^ƒCƒ€ƒXƒ^ƒ“ƒv‚̃vƒƒpƒeƒB‚́A•ª—£‚³‚ꂽƒCƒ“ƒXƒ^ƒ“ƒX‚ɑ΂µ‚Änull‚Å‚ ‚Á‚Ä‚Í‚È‚è‚Ü‚¹‚ñB
+                ‚»‚Ì‚½‚߂ǂ̂悤‚È <literal>unsaved-value</literal> í—ª‚ªŽw’肳‚ê‚Ä‚àA
+                Hibernate‚Ínull‚̃o[ƒWƒ‡ƒ“‚âƒ^ƒCƒ€ƒXƒ^ƒ“ƒv‚ðŽ‚Á‚½‚·‚ׂẴCƒ“ƒXƒ^ƒ“ƒX‚ðA
+                ˆêŽž“I‚È‚à‚Ì‚Å‚ ‚é‚Æ”»’f‚µ‚Ü‚·B
+                
+                 <emphasis> null‚ð‹–—e‚·‚éƒo[ƒWƒ‡ƒ“‚âƒ^ƒCƒ€ƒXƒ^ƒ“ƒv‚̃vƒƒpƒeƒB‚ð’è‹`‚·‚邱‚Ƃ́A
+                ‰ß“n“I‚ɈꎞƒIƒuƒWƒFƒNƒg‚Æ‚·‚邱‚Æ‚ð–h‚®ŠÈ’P‚È•û–@‚Å‚·B
+                “Á‚ÉŽ¯•ÊŽq‚ÌŠ„‚è“–‚Ä‚â•¡‡ƒL[‚ðŽg—p‚µ‚Ä‚¢‚é‚Æ‚«‚É‚Í“Á‚É—L—p‚Å‚·B</emphasis> 
+            </para>
+        </sect2>
+        
+        <sect2 id="mapping-declaration-timestamp" revision="4">
+            <title>timestampiƒIƒvƒVƒ‡ƒ“j</title>
+
+            <para>
+                ƒIƒvƒVƒ‡ƒ“‚Ì <literal>&lt;timestamp&gt;</literal> —v‘f‚́A
+                ƒe[ƒuƒ‹‚ªƒ^ƒCƒ€ƒXƒ^ƒ“ƒvƒf[ƒ^‚ðŠÜ‚Þ‚±‚Æ‚ðŽ¦‚µ‚Ü‚·B
+                ‚±‚ê‚̓o[ƒWƒ‡ƒ“•t‚¯‚Ì‘ã‚í‚è‚Ì•û–@‚Æ‚µ‚Ä—pˆÓ‚³‚ê‚Ä‚¢‚Ü‚·B
+                ƒ^ƒCƒ€ƒXƒ^ƒ“ƒv‚Í‚à‚Æ‚à‚ÆŠyŠÏ“IƒƒbƒN‚É‚¨‚¯‚éˆÀ‘S«‚Ì’á‚¢ŽÀ‘•‚Å‚·B
+                ‚µ‚©‚µƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚͈قȂé—p“r‚ÅŽg‚¤‚±‚Æ‚à‚ ‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="timestamp1" coords="2 70"/>
+                    <area id="timestamp2" coords="3 70" />
+                    <area id="timestamp3" coords="4 70" />
+                    <area id="timestamp4" coords="5 70" />
+                    <area id="timestamp5" coords="6 70" />
+                    <area id="timestamp6" coords="7 70" />                    
+                </areaspec>            
+                <programlisting><![CDATA[<timestamp
+        column="timestamp_column"
+        name="propertyName"
+        access="field|property|ClassName"
+        unsaved-value="null|undefined"
+        source="vm|db"
+        generated="never|always"
+        node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="timestamp1">
+                        <para>
+                            <literal>column</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚̓vƒƒpƒeƒB–¼jF
+                            ƒ^ƒCƒ€ƒXƒ^ƒ“ƒv‚ð•ÛŽ‚·‚éƒJƒ‰ƒ€‚Ì–¼‘OB
+                        </para>
+                    </callout>                   
+                    <callout arearefs="timestamp2">
+                        <para>
+                            <literal>name</literal> F
+                            ‰i‘±ƒNƒ‰ƒX‚Å‚ ‚éJava ‚Ì <literal>Date</literal >Œ^ ‚Ü‚½‚Í 
+                            <literal>Timestamp</literal> Œ^ ‚́AJavaBeansƒXƒ^ƒCƒ‹ƒvƒƒpƒeƒB‚Ì–¼‘OB
+                        </para>
+                    </callout>
+                   <callout arearefs="timestamp3">
+                        <para>
+                            <literal>access</literal>
+                            iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>property</literal> jF
+                            ƒvƒƒpƒeƒB‚Ì’l‚ւ̃AƒNƒZƒX‚ÉHibernate‚ªŽg‚¤í—ªB
+                        </para>
+                    </callout>
+                   <callout arearefs="timestamp4">
+                        <para>
+                            <literal>unsaved-value</literal> 
+                            iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>null</literal> jF
+                            ƒCƒ“ƒXƒ^ƒ“ƒX‚ªV‚µ‚­ƒCƒ“ƒXƒ^ƒ“ƒX‰»‚³‚ꂽ
+                            iƒZ[ƒu‚³‚ê‚Ä‚¢‚È‚¢j‚±‚Æ‚ðŽ¦‚·ƒo[ƒWƒ‡ƒ“ƒvƒƒpƒeƒB‚Ì’lB
+                            ˆÈ‘O‚ÌSession‚ŃZ[ƒu‚Ü‚½‚̓[ƒh‚³‚ꂽˆêŽž“I‚ȃCƒ“ƒXƒ^ƒ“ƒX‚Æ
+                            ‹æ•Ê‚·‚邽‚ß‚ÉŽg‚í‚ê‚Ü‚·B
+                            i <literal>undefined</literal> ‚ÆŽw’è‚·‚é‚ƁA
+                            Ž¯•ÊŽqƒvƒƒpƒeƒB‚Ì’l‚ªŽg‚í‚ê‚Ü‚·Bj
+                        </para>
+                    </callout>
+                    
+                    <callout arearefs="timestamp5">
+                        <para>
+                            <literal>source</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>vm</literal> ):
+                            Hibernate‚Í‚Ç‚±‚©‚çƒ^ƒCƒ€ƒXƒ^ƒ“ƒv‚Ì’l‚ðŽæ“¾‚·‚é‚ׂ«‚Å‚µ‚傤‚©H
+                            ƒf[ƒ^ƒx[ƒX‚©‚ç‚Å‚µ‚傤‚©AŒ»Ý‚ÌJVM‚©‚ç‚Å‚µ‚傤‚©H
+                            ƒf[ƒ^ƒx[ƒX‚É‚æ‚éƒ^ƒCƒ€ƒXƒ^ƒ“ƒv‚́AHibernate‚ª"ŽŸ‚Ì’l"‚ðŒˆ’è‚·‚邽‚ß‚É
+                            ƒf[ƒ^ƒx[ƒX‚ðƒqƒbƒg‚µ‚È‚¯‚ê‚΂Ȃç‚È‚¢‚½‚߁AƒI[ƒoƒwƒbƒh‚ðµ‚«‚Ü‚·B
+                            ‚µ‚©‚µƒNƒ‰ƒXƒ^ŠÂ‹«‚Å‚ÍJVM‚©‚çŽæ“¾‚·‚é‚æ‚èˆÀ‘S‚Å‚·B
+                            ƒf[ƒ^ƒx[ƒX‚ÌŒ»Ý‚̃^ƒCƒ€ƒXƒ^ƒ“ƒv‚̎擾‚ðƒTƒ|[ƒg‚·‚é
+                            ‚·‚×‚Ä‚Ì <literal>ƒf[ƒ^ƒx[ƒX•ûŒ¾</literal> ‚ª’m‚ç‚ê‚Ä‚¢‚é‚킯‚Å‚Í‚È‚¢‚±‚Æ‚É
+                            ’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B‚Ü‚½ˆê•û‚ŁA¸–§‚³‚ðŒ‡‚­‚½‚߂ɁA
+                            ƒƒbƒN‚ÅŽg—p‚·‚é‚ɂ͈À‘S‚Å‚È‚¢‚à‚Ì‚à‚ ‚è‚Ü‚·(—Ⴆ‚ÎOracle 8)B
+                        </para>
+                    </callout>
+                    <callout arearefs="timestamp6">
+                        <para>
+                            <literal>generated</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>never</literal> ):
+                            ‚±‚̃^ƒCƒ€ƒXƒ^ƒ“ƒvEƒvƒƒpƒeƒB‚Ì’l‚ªAƒf[ƒ^ƒx[ƒX‚É‚æ‚Á‚ж¬‚³‚ê‚邱‚Æ‚ðŽw’肵‚Ü‚·B
+                            <xref linkend="mapping-generated">¶¬ƒvƒƒpƒeƒB</xref> ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                 <literal>&lt;timestamp&gt;</literal> ‚Í 
+                <literal>&lt;version type="timestamp"&gt;</literal> ‚Æ“™‰¿‚Å‚ ‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                <literal>&lt;timestamp source="db"&gt;</literal> ‚Í
+                <literal>&lt;version type="dbtimestamp"&gt;</literal> ‚Æ“™‰¿‚Å‚ ‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+        </sect2>
+        
+        <sect2 id="mapping-declaration-property" revision="4">
+            <title>property</title>
+
+            <para>
+                <literal>&lt;property&gt;</literal> —v‘f‚́AƒNƒ‰ƒX‚̉i‘±“I‚ÈJavaBeanƒXƒ^ƒCƒ‹‚̃vƒƒpƒeƒB‚ð’è‹`‚µ‚Ü‚·B
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="property1" coords="2 70"/>
+                    <area id="property2" coords="3 70"/>
+                    <area id="property3" coords="4 70"/>
+                    <areaset id="property4-5" coords="">
+                        <area id="property4" coords='5 70'/>
+                        <area id="property5" coords='6 70'/>
+                    </areaset>
+                    <area id="property6" coords="7 70"/>
+                    <area id="property7" coords="8 70"/>
+                    <area id="property8" coords="9 70"/>
+                    <area id="property9" coords="10 70"/>
+                    <area id="property10" coords="11 70"/>
+                    <area id="property11" coords="12 70"/>
+                    <area id="property12" coords="13 70"/>
+                </areaspec>            
+                <programlisting><![CDATA[<property
+        name="propertyName"
+        column="column_name"
+        type="typename"
+        update="true|false"
+        insert="true|false"
+        formula="arbitrary SQL expression"
+        access="field|property|ClassName"
+        lazy="true|false"
+        unique="true|false"
+        not-null="true|false"
+        optimistic-lock="true|false"
+        generated="never|insert|always"
+        node="element-name|@attribute-name|element/@attribute|."
+        index="index_name"
+        unique_key="unique_key_id"
+        length="L"
+        precision="P"
+        scale="S"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="property1">
+                        <para>
+                            <literal>name</literal>F¬•¶Žš‚ÅŽn‚Ü‚éƒvƒƒpƒeƒB–¼B
+                        </para>
+                    </callout>                   
+                    <callout arearefs="property2">
+                        <para>
+                            <literal>column</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚̓vƒƒpƒeƒB–¼jF
+                            ƒ}ƒbƒsƒ“ƒO‚³‚ꂽƒf[ƒ^ƒx[ƒXƒe[ƒuƒ‹‚̃Jƒ‰ƒ€‚Ì–¼‘OB
+                            ƒlƒXƒg‚µ‚½ <literal>&lt;column&gt;</literal> —v‘f‚Å‚àŽw’è‚Å‚«‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="property3">
+                        <para>
+                            <literal>type</literal>iƒIƒvƒVƒ‡ƒ“jFHibernate‚ÌŒ^‚ðŽ¦‚·–¼‘OB
+                        </para>
+                    </callout>
+                    <callout arearefs="property4-5">
+                        <para>
+                            <literal>update, insert</literal> 
+                            iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal> jF
+                            ƒ}ƒbƒsƒ“ƒO‚³‚ꂽƒJƒ‰ƒ€‚ªSQL‚Ì 
+                            <literal>UPDATE</literal> ‚â <literal>INSERT</literal> ‚ÉŠÜ‚Ü‚ê‚邱‚Æ‚ðŽw’肵‚Ü‚·B
+                            —¼•û‚Æ‚à <literal>false</literal> ‚ɐݒ肷‚é‚ƁA
+                            “¯‚¶ƒJƒ‰ƒ€‚Ƀ}ƒbƒsƒ“ƒO‚³‚ꂽ‘¼‚̃vƒƒpƒeƒB‚âƒgƒŠƒK‚â
+                            ‘¼‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚æ‚Á‚ú‰»‚³‚ꂽƒˆ‚ȁu“±ovƒvƒƒpƒeƒB‚ª‰Â”\‚É‚È‚è‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="property6">
+                        <para>
+                            <literal>formula</literal>iƒIƒvƒVƒ‡ƒ“jF
+                            <emphasis>ŒvŽZ</emphasis> ƒvƒƒpƒeƒB‚Ì‚½‚ß‚Ì’l‚ð’è‹`‚·‚éSQLŽ®B
+                            ŒvŽZ‚³‚ꂽƒvƒƒpƒeƒB‚ÍŽ©g‚̃Jƒ‰ƒ€‚ւ̃}ƒbƒsƒ“ƒO‚ª‚ ‚è‚Ü‚¹‚ñB
+                        </para>
+                    </callout>
+                    <callout arearefs="property7">
+                        <para>
+                            <literal>access</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>property</literal> jF
+                            ƒvƒƒpƒeƒB‚Ì’l‚ւ̃AƒNƒZƒX‚ÉHibernate‚ªŽg‚¤í—ªB
+                        </para>
+                    </callout>
+                    <callout arearefs="property8">
+                        <para>
+                            <literal>lazy</literal> (optional - ƒfƒtƒHƒ‹ƒg‚Í <literal>false</literal> ):
+                           ƒCƒ“ƒXƒ^ƒ“ƒX•Ï”‚ɍŏ‰‚ɃAƒNƒZƒX‚µ‚½‚Æ‚«‚ɁAƒvƒƒpƒeƒB‚ð’x‰„‚µ‚Ď擾‚·‚é‚悤Žw’肵‚Ü‚·B
+                           (ƒoƒCƒgƒR[ƒhŽÀ‘•‚ðì¬‚·‚鎞ŠÔ‚ª•K—v‚É‚È‚è‚Ü‚·)B
+                        </para>
+                    </callout>
+                    <callout arearefs="property9">
+                        <para>
+                            <literal>unique</literal> (ƒIƒvƒVƒ‡ƒ“):ƒJƒ‰ƒ€‚Ƀ†ƒj[ƒN§–ñ‚ð‚‚¯‚éDDL‚̐¶¬‚ð‰Â”\‚É‚µ‚Ü‚·B
+                            ‚Ü‚½A<literal>property-ref</literal> ‚̃^[ƒQƒbƒg‚Æ‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="property10">
+                        <para>
+                            <literal>not-null</literal> (ƒIƒvƒVƒ‡ƒ“):ƒJƒ‰ƒ€‚Énull’l‚ð‹–‰Â‚·‚éDDL‚̐¶¬‚ð‰Â”\‚É‚µ‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="property11">
+                        <para>
+                            <literal>optimistic-lock</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal> ):
+                            ‚±‚̃vƒƒpƒeƒB‚̍XV‚ÉŠyŠÏƒƒbƒN‚̎擾‚ð—v‹‚·‚é‚©‚Ç‚¤‚©‚ðŽw’肵‚Ü‚·B
+                            Œ¾‚¢Š·‚¦‚ê‚΁A‚±‚̃vƒƒpƒeƒB‚ªƒ_[ƒeƒB‚Å‚ ‚é‚Æ‚«‚Ƀo[ƒWƒ‡ƒ“‚𑝂₷‚ׂ«‚©‚ðŒˆ’è‚µ‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="property12">
+                        <para>
+                            <literal>generated</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>never</literal> ):
+                            ƒvƒƒpƒeƒB‚Ì’l‚ªAƒf[ƒ^ƒx[ƒX‚É‚æ‚Á‚ж¬‚³‚ꂽ‚±‚Æ‚ðŽw’肵‚Ü‚·B
+                            <xref linkend="mapping-generated">¶¬ƒvƒƒpƒeƒB</xref> ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                <emphasis>typename</emphasis> ‚ɂ͈ȉº‚Ì’l‚ª‰Â”\‚Å‚·F
+            </para>
+
+            <orderedlist spacing="compact">
+                <listitem>
+                    <para>
+                        Hibernate‚ÌŠî–{Œ^‚Ì–¼‘Oi—á  <literal>integer, string, character,
+                        date, timestamp, float, binary, serializable, object, blob</literal> jB
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        ƒfƒtƒHƒ‹ƒg‚ÌŠî–{Œ^‚ÌJavaƒNƒ‰ƒX–¼ i—á <literal>int, float,
+                        char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob</literal> jB
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        ƒVƒŠƒAƒ‰ƒCƒY‰Â”\‚ÈJavaƒNƒ‰ƒX‚Ì–¼‘OB
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        ƒJƒXƒ^ƒ€Œ^‚̃Nƒ‰ƒX–¼i—á <literal>com.illflow.type.MyCustomType</literal> jB
+                    </para>
+                </listitem>
+            </orderedlist>
+
+            <para>
+                Œ^‚ðŽw’肵‚È‚¯‚ê‚΁AHibernate‚͐³‚µ‚¢Hibernate‚ÌŒ^‚𐄑ª‚·‚邽‚߂ɁA
+                Žw’肳‚ꂽƒvƒƒpƒeƒB‚ɑ΂µ‚ăŠƒtƒŒƒNƒVƒ‡ƒ“‚ðŽg‚¢‚Ü‚·B
+                Hibernate‚̓‹[ƒ‹2, 3, 4‚ð‚»‚Ì‡˜‚ÉŽg‚¢A
+                getterƒvƒƒpƒeƒB‚Ì•Ô‚è’l‚̃Nƒ‰ƒX‚Ì–¼‘O‚ð‰ðŽß‚µ‚悤‚Æ‚µ‚Ü‚·B
+                ‚µ‚©‚µ‚±‚ê‚ŏí‚ɏ\•ª‚Å‚ ‚é‚Æ‚ÍŒÀ‚è‚Ü‚¹‚ñB
+                ê‡‚É‚æ‚Á‚ẮA<literal>type</literal> ‘®«‚ª•K—v‚ȏꍇ‚ª‚ ‚è‚Ü‚·B
+                i—Ⴆ‚Î <literal>Hibernate.DATE</literal> ‚Æ <literal>Hibernate.TIMESTAMP</literal> ‚ð‹æ•Ê‚·‚邽‚߁A
+                ‚Ü‚½‚̓JƒXƒ^ƒ€Œ^‚ðŽw’è‚·‚邽‚ß‚È‚Ç‚Å‚·Bj
+            </para>
+            
+            <para>
+                <literal>access</literal> ‘®«‚ŁA
+                ŽÀsŽž‚ÉHibernate‚ª‚ǂ̂悤‚ɃvƒƒpƒeƒB‚ɃAƒNƒZƒX‚·‚é‚©‚𐧌ä‚Å‚«‚Ü‚·B
+                ƒfƒtƒHƒ‹ƒg‚Å‚ÍHibernate‚̓vƒƒpƒeƒB‚Ìget/set‚̃yƒA‚ðƒR[ƒ‹‚µ‚Ü‚·B
+                <literal>access="field"</literal> ‚ÆŽw’è‚·‚ê‚΁A
+                Hibernate‚̓ŠƒtƒŒƒNƒVƒ‡ƒ“‚ðŽg‚¢get/set‚̃yƒA‚ð‰î‚³‚¸‚ɁA’¼ÚƒtƒB[ƒ‹ƒh‚ɃAƒNƒZƒX‚µ‚Ü‚·B
+                ƒCƒ“ƒ^[ƒtƒFƒCƒX <literal>org.hibernate.property.PropertyAccessor</literal> ‚ð
+                ŽÀ‘•‚·‚éƒNƒ‰ƒX‚ðŽw’è‚·‚邱‚ƂŁAƒvƒƒpƒeƒB‚ւ̃AƒNƒZƒX‚É“ÆŽ©‚̐헪‚ðŽw’è‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            </para>
+
+            <para>
+                “Á‚É‹­—Í‚È“Á’¥‚͐¶¬ƒvƒƒpƒeƒB‚Å‚·B
+                ‚±‚ê‚ç‚̃vƒƒpƒeƒB‚Í“–‘R“Ç‚ÝŽæ‚èê—p‚Å‚ ‚èAƒvƒƒpƒeƒB‚Ì’l‚̓[ƒhŽž‚ÉŒvŽZ‚³‚ê‚Ü‚·B
+                ŒvŽZ‚ðSQLŽ®‚Æ‚µ‚Đ錾‚·‚é‚ƁA‚±‚̃vƒƒpƒeƒB‚Í
+                ƒCƒ“ƒXƒ^ƒ“ƒX‚ðƒ[ƒh‚·‚éSQLƒNƒGƒŠ‚Ì <literal>SELECT</literal> ‹å‚̃TƒuƒNƒGƒŠ‚É•ÏŠ·‚³‚ê‚Ü‚·B
+            </para>
+
+        <programlisting><![CDATA[
+<property name="totalPrice"
+    formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p
+                WHERE li.productId = p.productId
+                AND li.customerId = customerId
+                AND li.orderNumber = orderNumber )"/>]]></programlisting>
+
+            <para>
+                “Á’è‚̃Jƒ‰ƒ€(—á‚Å‚Í <literal>customerId</literal> ‚ª‚»‚ê‚É‚ ‚½‚è‚Ü‚·)‚̃GƒCƒŠƒAƒX‚ðéŒ¾‚·‚邱‚Æ‚È‚­A
+                ƒGƒ“ƒeƒBƒeƒBŽ©g‚̃e[ƒuƒ‹‚ðŽQÆ‚Å‚«‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚à‚µ‘®«‚ðŽg—p‚µ‚½‚­‚È‚¯‚ê‚΁A
+                ƒlƒXƒg‚µ‚½ <literal>&lt;formula&gt;</literal> ƒ}ƒbƒsƒ“ƒO—v‘f‚ðŽg‚¦‚邱‚Æ‚É‚à’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-manytoone" revision="5">
+            <title>many-to-one</title>
+
+            <para>
+                ‘¼‚̉i‘±ƒNƒ‰ƒX‚ւ̒ʏí‚ÌŠÖ˜A‚Í <literal>many-to-one</literal> —v‘f‚ðŽg‚Á‚Ä’è‹`‚µ‚Ü‚·B
+                ƒŠƒŒ[ƒVƒ‡ƒiƒ‹ƒ‚ƒfƒ‹‚Í‘½‘ΈêŠÖ˜A‚Å‚·B
+                ‚‚܂肠‚éƒe[ƒuƒ‹‚ÌŠO•”ƒL[‚́Aƒ^[ƒQƒbƒg‚Æ‚È‚éƒe[ƒuƒ‹‚ÌŽåƒL[ƒJƒ‰ƒ€‚ðŽQÆ‚µ‚Ä‚¢‚Ü‚·B
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="manytoone1" coords="2 70"/>
+                    <area id="manytoone2" coords="3 70"/>
+                    <area id="manytoone3" coords="4 70"/>
+                    <area id="manytoone4" coords="5 70"/>
+                    <area id="manytoone5" coords="6 70"/>
+                    <areaset id="manytoone6-7" coords="">
+                        <area id="manytoone6" coords='7 70'/>
+                        <area id="manytoone7" coords='8 70'/>
+                    </areaset>
+                    <area id="manytoone8" coords="9 70"/>
+                    <area id="manytoone9" coords="10 70"/>
+                    <area id="manytoone10" coords="11 70"/>
+                    <area id="manytoone11" coords="12 70"/>
+                    <area id="manytoone12" coords="13 70"/>
+                    <area id="manytoone13" coords="14 70"/>
+                    <area id="manytoone14" coords="15 70"/>
+                    <area id="manytoone15" coords="16 70"/>
+                    <area id="manytoone16" coords="17 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<many-to-one
+        name="propertyName"
+        column="column_name"
+        class="ClassName"
+        cascade="cascade_style"
+        fetch="join|select"
+        update="true|false"
+        insert="true|false"
+        property-ref="propertyNameFromAssociatedClass"
+        access="field|property|ClassName"
+        unique="true|false"
+        not-null="true|false"
+        optimistic-lock="true|false"
+        lazy="proxy|no-proxy|false"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        formula="arbitrary SQL expression"
+        node="element-name|@attribute-name|element/@attribute|."
+        embed-xml="true|false"
+        index="index_name"
+        unique_key="unique_key_id"
+        foreign-key="foreign_key_name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="manytoone1">
+                        <para>
+                            <literal>name</literal>FƒvƒƒpƒeƒB–¼B
+                        </para>                    
+                    </callout>                   
+                    <callout arearefs="manytoone2">
+                        <para>
+                            <literal>column</literal> (ƒIƒvƒVƒ‡ƒ“):ŠO•”ƒL[ƒJƒ‰ƒ€‚Ì–¼‘OB
+                            ƒlƒXƒg‚µ‚½ <literal>&lt;column&gt;</literal> —v‘f‚Å‚àŽw’è‚Å‚«‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone3">
+                        <para>
+                            <literal>class</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚́A
+                            ƒŠƒtƒŒƒNƒVƒ‡ƒ“‚É‚æ‚茈’肳‚ê‚éƒvƒƒpƒeƒB‚ÌŒ^jFŠÖ˜AƒNƒ‰ƒX‚Ì–¼‘OB
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone4">
+                        <para>
+                            <literal>cascade</literal>iƒIƒvƒVƒ‡ƒ“jF
+                            ‚Ç‚Ì‘€ì‚ðAeƒIƒuƒWƒFƒNƒg‚©‚çŠÖ˜AƒIƒuƒWƒFƒNƒg‚ւƃJƒXƒP[ƒh‚³‚¹‚é‚©‚ðŽw’肵‚Ü‚·B
+                        </para>                    
+                    </callout>
+                    <callout arearefs="manytoone5">
+                        <para>
+                            <literal>fetch</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>select</literal> ): 
+                               ŠO•”Œ‹‡ƒtƒFƒbƒ`‚©‡ŽŸ‘I‘ðƒtƒFƒbƒ`isequential select fetchj‚ð‘I‘ð‚µ‚Ü‚·B
+                        </para>                    
+                    </callout>
+                    <callout arearefs="manytoone6-7">
+                        <para>
+                            <literal>update, insert</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal> jF
+                            ƒ}ƒbƒsƒ“ƒO‚³‚ꂽƒJƒ‰ƒ€‚ªSQL‚Ì <literal>UPDATE</literal> ‚Ü‚½‚Í 
+                            <literal>INSERT</literal> •¶‚ÉŠÜ‚Ü‚ê‚邱‚Æ‚ðŽw’肵‚Ü‚·B
+                            —¼•û‚Æ‚à <literal>false</literal> ‚ɐݒ肷‚é‚ƁA
+                            ‚»‚Ì’l‚ª“¯‚¶ƒJƒ‰ƒ€‚Ƀ}ƒbƒsƒ“ƒO‚³‚ꂽ‘¼‚̃vƒƒpƒeƒB‚âƒgƒŠƒK‚â
+                            ‘¼‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚æ‚Á‚ú‰»‚³‚ꂽƒˆ‚ȁu“±ovƒvƒƒpƒeƒB‚ª‰Â”\‚É‚È‚è‚Ü‚·B
+                        </para>                    
+                    </callout>
+                    <callout arearefs="manytoone8">
+                        <para>
+                            <literal>property-ref</literal>iƒIƒvƒVƒ‡ƒ“jF
+                            ‚±‚ÌŠO•”ƒL[‚ÉŒ‹‡‚³‚ꂽŠÖ˜AƒNƒ‰ƒX‚̃vƒƒpƒeƒB–¼B
+                            ‰½‚àŽw’肵‚È‚¯‚ê‚΁AŠÖ˜AƒNƒ‰ƒX‚ÌŽåƒL[‚ªŽg‚í‚ê‚Ü‚·B
+                        </para>                
+                    </callout>                   
+                    <callout arearefs="manytoone9">
+                        <para>
+                            <literal>access</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>property</literal> jF
+                            ƒvƒƒpƒeƒB‚Ì’l‚ւ̃AƒNƒZƒX‚ÉHibernate‚ªŽg‚¤í—ªB
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone10">
+                        <para>
+                            <literal>unique</literal>iƒIƒvƒVƒ‡ƒ“jF
+                             ŠO•”ƒL[ƒJƒ‰ƒ€‚ɑ΂µ‚ă†ƒj[ƒN§–ñ‚ð‚‚¯‚½DDL‚̐¶¬‚ð‰Â”\‚É‚µ‚Ü‚·B
+                             ‚Ü‚½A<literal>property-ref</literal> ‚̃^[ƒQƒbƒg‚É‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+                             ‚±‚ê‚É‚æ‚èŠÖ˜A‚Ì‘½d“x‚ðŒø‰Ê“I‚Ɉê‘Έê‚É‚µ‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone11">
+                        <para>
+                            <literal>not-null</literal> (ƒIƒvƒVƒ‡ƒ“):ŠO•”ƒL[ƒJƒ‰ƒ€‚ɑ΂µ‚āA
+                            null’l‚ð‹–‰Â‚·‚éDDL‚̐¶¬‚ð‰Â”\‚É‚µ‚Ü‚·
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone12">
+                        <para>
+                            <literal>optimistic-lock</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal> ):
+                            ‚±‚̃vƒƒpƒeƒB‚̍XV‚ÉŠyŠÏ“IƒƒbƒN‚̎擾‚ð—v‹‚·‚é‚©‚Ç‚¤‚©‚ðŽw’肵‚Ü‚·B
+                            Œ¾‚¢Š·‚¦‚ê‚΁A‚±‚̃vƒƒpƒeƒB‚ªƒ_[ƒeƒB‚Å‚ ‚é‚Æ‚«‚Ƀo[ƒWƒ‡ƒ“‚𑝂₷‚ׂ«‚©‚ðŒˆ’è‚µ‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone13">
+                        <para>
+                            <literal>lazy</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>proxy</literal> ): 
+                            ƒfƒtƒHƒ‹ƒg‚ł́A‘½d“x‚P‚ÌŠÖ˜A‚ªƒvƒƒLƒV‚Æ‚È‚è‚Ü‚·B
+                            <literal>lazy="no-proxy"</literal> ‚́AƒCƒ“ƒXƒ^ƒ“ƒX•Ï”‚ɍŏ‰‚ɃAƒNƒZƒX‚µ‚½‚Æ‚«‚ɁA
+                            ƒvƒƒpƒeƒB‚ð’x‰„ƒtƒFƒbƒ`‚·‚é‚悤Žw’肵‚Ü‚·
+                            (ƒrƒ‹ƒhŽž‚ɃoƒCƒgƒR[ƒhŽÀ‘•‚ª•K—v‚É‚È‚è‚Ü‚·)B
+                            <literal>lazy="false"</literal> ‚ÍŠÖ˜A‚ðí‚É‘¦Žž‚ɃtƒFƒbƒ`‚·‚é‚悤Žw’肵‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone14">
+                        <para>
+                            <literal>not-found</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>exception</literal> ):
+                            Œ‡—Ž‚µ‚½s‚ðŽQÆ‚·‚éŠO•”ƒL[‚ð‚ǂ̂悤‚Ɉµ‚¤‚©‚ðŽw’肵‚Ü‚·B
+                            <literal>ignore</literal> ‚ÍŒ‡—Ž‚µ‚½s‚ðnullŠÖ˜A‚Æ‚µ‚Ĉµ‚¢‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone15">
+                        <para>
+                            <literal>entity-name</literal> (ƒIƒvƒVƒ‡ƒ“):ŠÖ˜A‚µ‚½ƒNƒ‰ƒX‚̃Gƒ“ƒeƒBƒeƒB–¼B
+                        </para>                   
+                    </callout>
+                </calloutlist>
+                    <callout arearefs="manytoone16">
+                        <para>
+                            <literal>formula</literal> (ƒIƒvƒVƒ‡ƒ“):
+                             <emphasis> ŒvŽZ‚³‚ꂽ</emphasis> ŠO•”ƒL[‚ɑ΂µ‚Ä’l‚ð’è‹`‚·‚éSQLŽ®
+                        </para>
+                    </callout>
+            </programlistingco>
+
+            <para>
+                <literal>cascade</literal> ‘®«‚É <literal>none</literal> ˆÈŠO‚̈Ӗ¡‚Ì‚ ‚é’l‚ð‚ðÝ’è‚·‚é‚ƁA
+                ŠÖ˜AƒIƒuƒWƒFƒNƒg‚Ö‚ ‚é‘€ì‚ª“`”d‚·‚邱‚Æ‚É‚È‚è‚Ü‚·B
+                ˆÓ–¡‚Ì‚ ‚é’l‚Æ‚ÍHibernate‚ÌŠî–{‘€ì‚Ì–¼‘O‚Ì‚±‚ƂŁA
+                <literal>delete-orphan</literal> ‚Æ <literal>all</literal> A‘€ì–¼‚ðƒJƒ“ƒ}‚Å‹æØ‚Á‚½‘g‚ݍ‡‚킹
+                i—Ⴆ‚Î <literal>cascade="persist,merge,evict"</literal> ‚â
+                <literal>cascade="all,delete-orphan"</literal>jA
+                ‚Ü‚½‚»‚ꂾ‚¯‚Å‚È‚­ <literal>persist, merge, delete, save-update, evict, replicate, lock,
+                refresh</literal> ‚Ì‚±‚Æ‚ðŽw‚µ‚Ü‚·B
+                Ú‚µ‚¢à–¾‚Í <xref linkend="objectstate-transitive"/> ‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+                ’l‚ªˆê‚‚̊֘A(many-to-one‚Æone-to-oneŠÖ˜A)‚́A
+                ’P“Ƃł̍폜iorphan delete)‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+            
+            <para>
+                “TŒ^“I‚È <literal>many-to-one</literal> éŒ¾‚ÍŽŸ‚̂悤‚ɃVƒ“ƒvƒ‹‚Å‚·BF
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="product" class="Product" column="PRODUCT_ID"/>]]></programlisting>
+            
+            <para>
+                <literal>property-ref</literal> ‘®«‚́AŠO•”ƒL[‚ªŠÖ˜A•t‚¯‚ç‚ꂽƒe[ƒuƒ‹‚́AŽåƒL[‚Å‚È‚¢
+                ƒ†ƒj[ƒNƒL[‚ðŽQÆ‚µ‚Ä‚¢‚郌ƒKƒV[ƒf[ƒ^‚ðƒ}ƒbƒv‚·‚邽‚ß‚É‚¾‚¯Žg‚¤‚ׂ«‚Å‚·B
+                ‚±‚ê‚͏X‚¢ƒŠƒŒ[ƒVƒ‡ƒiƒ‹ƒ‚ƒfƒ‹‚Å‚·B
+                —Ⴆ‚Î <literal>Product</literal> ƒNƒ‰ƒX‚ªA
+                ŽåƒL[‚Å‚È‚¢ƒ†ƒj[ƒN‚ȃVƒŠƒAƒ‹ƒiƒ“ƒo[‚ðŽ‚Á‚Ä‚¢‚é‚Ɖ¼’肵‚Ä‚Ý‚Ä‚­‚¾‚³‚¢B
+                i <literal>unique</literal> ‘®«‚ÍSchemaExportƒc[ƒ‹‚ðŽg‚Á‚½Hibernate‚ÌDDL¶¬‚𐧌䂵‚Ü‚·Bj
+            </para>
+            
+            <programlisting><![CDATA[<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>]]></programlisting>
+            
+            <para>
+                ˆÈ‰º‚̂悤‚É <literal>OrderItem</literal> ‚ɑ΂µ‚ă}ƒbƒsƒ“ƒO‚ðŽg‚¦‚Ü‚·F
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>]]></programlisting>
+            
+            <para>
+                ‚µ‚©‚µA‚±‚ê‚ÍŒˆ‚µ‚Đ„§‚Å‚«‚Ü‚¹‚ñB
+            </para>
+            
+            <para>
+                ŽQÆ‚µ‚½ƒ†ƒj[ƒNƒL[‚ªAŠÖ˜A‚·‚éƒGƒ“ƒeƒBƒeƒB‚Ì‘½”‚̃vƒƒpƒeƒB‚©‚ç\¬‚³‚ê‚éê‡A
+                Žw’肵‚½ <literal>&lt;properties&gt;</literal> —v‘f“à‚ŁAŽQÆ‚·‚éƒvƒƒpƒeƒB‚ðƒ}ƒbƒsƒ“ƒO‚·‚é‚ׂ«‚Å‚·B
+            </para>
+            
+            <para>
+                ‚à‚µŽQÆ‚µ‚½ƒ†ƒj[ƒNƒL[‚ªƒRƒ“ƒ|[ƒlƒ“ƒg‚̃vƒƒpƒeƒB‚Å‚ ‚éê‡‚́AƒvƒƒpƒeƒB‚̃pƒX‚ðŽw’è‚Å‚«‚Ü‚·B
+            </para>
+            
+           <programlisting><![CDATA[<many-to-one name="owner" property-ref="identity.ssn" column="OWNER_SSN"/>]]></programlisting>           
+            
+            
+        </sect2>
+        
+
+        <sect2 id="mapping-declaration-onetoone" revision="3">
+            <title>one-to-one</title>
+
+            <para>
+                ‘¼‚̉i‘±ƒNƒ‰ƒX‚ւ̈ê‘ΈêŠÖ˜A‚́A<literal>one-to-one</literal> —v‘f‚Å’è‹`‚µ‚Ü‚·B
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="onetoone1" coords="2 70"/>
+                    <area id="onetoone2" coords="3 70"/>
+                    <area id="onetoone3" coords="4 70"/>
+                    <area id="onetoone4" coords="5 70"/>
+                    <area id="onetoone5" coords="6 70"/>
+                    <area id="onetoone6" coords="7 70"/>
+                    <area id="onetoone7" coords="8 70"/>
+                    <area id="onetoone8" coords="9 70"/>
+                    <area id="onetoone9" coords="10 70"/>
+                    <area id="onetoone10" coords="11 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<one-to-one
+        name="propertyName"
+        class="ClassName"
+        cascade="cascade_style"
+        constrained="true|false"
+        fetch="join|select"
+        property-ref="propertyNameFromAssociatedClass"
+        access="field|property|ClassName"
+        formula="any SQL expression"
+        lazy="proxy|no-proxy|false"
+        entity-name="EntityName"
+        node="element-name|@attribute-name|element/@attribute|."
+        embed-xml="true|false"
+        foreign-key="foreign_key_name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="onetoone1">
+                        <para>
+                            <literal>name</literal>FƒvƒƒpƒeƒB–¼B
+                        </para>                
+                    </callout>                   
+                    <callout arearefs="onetoone2">
+                        <para>
+                            <literal>class</literal>iƒIƒvƒVƒ‡ƒ“ - 
+                            ƒfƒtƒHƒ‹ƒg‚̓ŠƒtƒŒƒNƒVƒ‡ƒ“‚É‚æ‚茈’肳‚ê‚éƒvƒƒpƒeƒB‚ÌŒ^jF
+                            ŠÖ˜AƒNƒ‰ƒX‚Ì–¼‘OB
+                        </para>                   
+                    </callout>
+                    <callout arearefs="onetoone3">
+                        <para>
+                            <literal>cascade</literal>iƒIƒvƒVƒ‡ƒ“jF
+                            eƒIƒuƒWƒFƒNƒg‚©‚çŠÖ˜AƒIƒuƒWƒFƒNƒg‚ցA‚Ç‚Ì‘€ì‚ðƒJƒXƒP[ƒh‚·‚é‚©‚ðŽw’肵‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone4">
+                        <para>
+                            <literal>constrained</literal>iƒIƒvƒVƒ‡ƒ“jF
+                            ƒ}ƒbƒsƒ“ƒO‚³‚ꂽƒe[ƒuƒ‹‚ÌŽåƒL[‚ɑ΂·‚éŠO•”ƒL[§–ñ‚ªA
+                            ŠÖ˜AƒNƒ‰ƒX‚̃e[ƒuƒ‹‚ðŽQÆ‚·‚邱‚Æ‚ðŽw’肵‚Ü‚·B
+                            ‚±‚̃IƒvƒVƒ‡ƒ“‚Í <literal>save()</literal> ‚Æ 
+                            <literal>delete()</literal> ‚ªƒJƒXƒP[ƒh‚³‚ê‚鏇˜‚ɉe‹¿‚µA
+                            ‚»‚µ‚ÄŠÖ˜A‚ªƒvƒƒLƒV‚³‚ê‚é‚©‚Ç‚¤‚©‚É‚à‰e‹¿‚µ‚Ü‚·
+                            i‚»‚µ‚ăXƒL[ƒ}ƒGƒNƒXƒ|[ƒgƒc[ƒ‹‚É‚àŽg‚í‚ê‚Ü‚·jB
+                        </para>                  
+                    </callout>
+                    <callout arearefs="onetoone5">
+                        <para>
+                            <literal>fetch</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>select</literal> jF
+                            ŠO•”Œ‹‡ƒtƒFƒbƒ`‚Ə‡ŽŸ‘I‘ðƒtƒFƒbƒ`isequential select fetchj‚Ì‚Ç‚¿‚ç‚©‚ð‘I‘ð‚µ‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone6">
+                        <para>
+                            <literal>property-ref</literal>iƒIƒvƒVƒ‡ƒ“jF
+                            ‚±‚̃Nƒ‰ƒX‚ÌŽåƒL[‚ÉŒ‹‡‚³‚ꂽŠÖ˜AƒNƒ‰ƒX‚̃vƒƒpƒeƒB–¼B
+                            Žw’肳‚ê‚È‚¯‚ê‚΁AŠÖ˜AƒNƒ‰ƒX‚ÌŽåƒL[‚ªŽg‚í‚ê‚Ü‚·B
+                        </para>                
+                    </callout>                   
+                    <callout arearefs="onetoone7">
+                        <para>
+                            <literal>access</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>property</literal> jF
+                            ƒvƒƒpƒeƒB‚Ì’l‚ւ̃AƒNƒZƒX‚ÉHibernate‚ªŽg‚¤í—ªB
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone8">
+                        <para>
+                            <literal>formula</literal> (ƒIƒvƒVƒ‡ƒ“):
+                            ‚Ù‚Æ‚ñ‚Ç‚·‚ׂĂ̈ê‘ΈêŠÖ˜A‚̓I[ƒi[‚̃Gƒ“ƒeƒBƒeƒB‚ÌŽåƒL[‚ւƃ}ƒbƒsƒ“ƒO‚³‚ê‚Ü‚·B
+                            ‚±‚êˆÈŠO‚Ì‹H‚ȏꍇ‚́A
+                            ‘¼‚̃Jƒ‰ƒ€‚âA•¡”‚̃Jƒ‰ƒ€ASQL\•¶‚ðŽg‚Á‚½Œ‹‡‚·‚邽‚ß‚ÌŽ®‚ðŽw’è‚Å‚«‚Ü‚·B
+                            i—á‚Í <literal>org.hibernate.test.onetooneformula</literal> ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢Bj
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone9">
+                        <para>
+                            <literal>lazy</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>proxy</literal> ): 
+                            ƒfƒtƒHƒ‹ƒg‚ł́A‘½d“x‚P‚ÌŠÖ˜A‚ªƒvƒƒLƒV‚Æ‚È‚è‚Ü‚·B
+                            <literal>lazy="no-proxy"</literal> ‚́AƒCƒ“ƒXƒ^ƒ“ƒX•Ï”‚ɍŏ‰‚ɃAƒNƒZƒX‚µ‚½‚Æ‚«‚ɁA
+                            ƒvƒƒpƒeƒB‚ð’x‰„ƒtƒFƒbƒ`‚·‚é‚悤Žw’肵‚Ü‚·
+                            (ƒrƒ‹ƒhŽž‚ɃoƒCƒgƒR[ƒhŽÀ‘•‚ª•K—v‚É‚È‚è‚Ü‚·)B
+                            <literal>lazy="false"</literal> ‚ÍŠÖ˜A‚ðí‚É‘¦Žž‚ɃtƒFƒbƒ`‚·‚é‚悤Žw’肵‚Ü‚·B
+                            <emphasis>‚à‚µ <literal>constrained="false"</literal> ‚È‚ç‚΁A
+                            ƒvƒƒLƒV‚ÍŽg—p•s‰Â”\‚Æ‚È‚èAŠÖ˜A‚𑦎ž‚ɃtƒFƒbƒ`‚·‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢I</emphasis> 
+                            
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone10">
+                        <para>
+                            <literal>entity-name</literal> (ƒIƒvƒVƒ‡ƒ“):ŠÖ˜AƒNƒ‰ƒX‚̃Gƒ“ƒeƒBƒeƒB–¼
+                        </para>                   
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+        
+            <para>
+                ˆê‘ΈêŠÖ˜A‚É‚Í2Ží—Þ‚ ‚è‚Ü‚·F
+            </para>
+            <itemizedlist>
+            <listitem><para>
+                ŽåƒL[ŠÖ˜A
+            </para></listitem>
+            <listitem><para>
+                ƒ†ƒj[ƒNŠO•”ƒL[ŠÖ˜A
+            </para></listitem>
+            </itemizedlist>
+            
+            <para>
+                ŽåƒL[ŠÖ˜A‚ɂ́A“Á•Ê‚ȃe[ƒuƒ‹ƒJƒ‰ƒ€‚Í•K—v‚ ‚è‚Ü‚¹‚ñB
+                ‚à‚µ2‚‚̍s‚ªŠÖ˜A‚É‚æ‚èŠÖŒW‚µ‚Ä‚¢‚ê‚΁A2‚‚̃e[ƒuƒ‹‚Í“¯‚¶ŽåƒL[‚Ì’l‚ð‹¤—L‚µ‚Ü‚·B
+                ‚»‚Ì‚½‚ß2‚‚̃IƒuƒWƒFƒNƒg‚ðŽåƒL[ŠÖ˜A‚É‚æ‚Á‚ÄŠÖ˜A•t‚¯‚½‚¢‚Ì‚Å‚ ‚ê‚΁A
+                ŠmŽÀ‚É“¯‚¶Ž¯•ÊŽq‚Ì’l‚ð‘ã“ü‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            </para>
+            
+            <para>
+                 ŽåƒL[ŠÖ˜A‚ðs‚¤‚½‚߂ɂ́AˆÈ‰º‚̃}ƒbƒsƒ“ƒO‚ð <literal>Employee</literal> ‚Æ 
+                <literal>Person</literal> ‚Ì‚»‚ꂼ‚ê‚ɒljÁ‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <programlisting><![CDATA[<one-to-one name="person" class="Person"/>]]></programlisting>
+            <programlisting><![CDATA[<one-to-one name="employee" class="Employee" constrained="true"/>]]></programlisting>
+
+            <para>
+                ‚±‚±‚ŁAPERSON‚ÆEMPLOYEEƒe[ƒuƒ‹‚ÌŠÖŒW‚·‚és‚ÌŽåƒL[‚ª“¯‚¶‚Å‚ ‚邱‚Æ‚ðŠmŽÀ‚É‚µ‚È‚¯‚ê‚΂¢‚¯‚Ü‚¹‚ñB
+                ‚±‚±‚ł́A<literal>foreign</literal> ‚Æ‚¢‚¤“ÁŽê‚ÈHibernateŽ¯•ÊŽq¶¬í—ª‚ðŽg‚¢‚Ü‚·F
+            </para>
+
+            <programlisting><![CDATA[<class name="person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="foreign">
+            <param name="property">employee</param>
+        </generator>
+    </id>
+    ...
+    <one-to-one name="employee"
+        class="Employee"
+        constrained="true"/>
+</class>]]></programlisting>
+
+            <para>
+                <literal>Employee</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚ªA<literal>Person</literal> ‚Ì 
+                <literal>employee</literal> ƒvƒƒpƒeƒB‚ÅŽQÆ‚³‚ê‚é‚悤‚ɁA
+                V‚µ‚­ƒZ[ƒu‚³‚ꂽ <literal>Person</literal> ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚É‚Í“¯‚¶ŽåƒL[‚Ì’l‚ª‘ã“ü‚³‚ê‚Ü‚·B
+                
+                V‚µ‚­ƒZ[ƒu‚·‚é <literal>Person</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚́A
+                ‚»‚Ì <literal>Person</literal> ‚Ì <literal>employee</literal> ƒvƒƒpƒeƒB‚ªŽQÆ‚·‚é 
+                <literal>Employee</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚Æ‚µ‚Ä“¯‚¶ŽåƒL[‚ªŠ„‚è“–‚Ä‚ç‚ê‚Ü‚·B
+            </para>
+
+            <para>
+                ‚à‚¤1‚‚̕û–@‚Æ‚µ‚āA<literal>Employee</literal> ‚©‚ç <literal>Person</literal> ‚Ö‚Ì
+                ƒ†ƒj[ƒN§–ñ‚ðŽg‚Á‚½ŠO•”ƒL[ŠÖ˜A‚͈ȉº‚̂悤‚É•\Œ»‚³‚ê‚Ü‚·F
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/>]]></programlisting>
+            
+            <para>
+                ‚»‚µ‚Ä‚±‚ÌŠÖ˜A‚́A
+                ˆÈ‰º‚Ì‹Lq‚ð <literal>Person</literal> ‚̃}ƒbƒsƒ“ƒO‚ɒljÁ‚·‚邱‚Æ‚Å‘o•ûŒü‚É‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·F
+            </para>
+            
+           <programlisting><![CDATA[<one-to-one name"employee" class="Employee" property-ref="person"/>]]></programlisting>
+
+        </sect2>
+        
+        <sect2 id="mapping-declaration-naturalid">
+            <title>natural-id</title>
+
+            <programlisting><![CDATA[<natural-id mutable="true|false"/>
+        <property ... />
+        <many-to-one ... />
+        ......
+</natural-id>]]></programlisting>
+
+            <para>
+                ŽåƒL[‚Æ‚µ‚đ㗝ƒL[‚ÌŽg—p‚𐄏§‚µ‚Ü‚·‚ªA
+                ‚·‚ׂẴGƒ“ƒeƒBƒeƒB‚ɑ΂µ‚ÄŽ©‘RƒL[‚ðŽ¯•Ê‚·‚é‚悤‚É‚·‚ׂ«‚Å‚·B
+                Ž©‘RƒL[‚̓†ƒj[ƒN‚©‚”ñnull‚Ȉê‚‚̃vƒƒpƒeƒBA‚Ü‚½‚̓vƒƒpƒeƒB‚̘AŒ‹‚Å‚·B
+                •s•Ï‚Å‚ ‚ê‚΂³‚ç‚É—Ç‚¢‚Å‚·B
+                <literal>&lt;natural-id&gt;</literal> —v‘f“à‚ÅŽ©‘RƒL[‚̃vƒƒpƒeƒB‚ðƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+                Hibernate‚Í•K‘R“I‚Ƀ†ƒj[ƒN‚©‚Ânull’l‚ð‹–‰Â‚·‚鐧–ñ‚𐶐¬‚µA
+                ‚±‚¤‚µ‚ă}ƒbƒsƒ“ƒO‚Í‚æ‚莩ŒÈ‹Lq“I‚É‚È‚è‚Ü‚·B
+            </para>
+            
+            <para>
+                ƒGƒ“ƒeƒBƒeƒB‚ÌŽ©‘RƒL[ƒvƒƒpƒeƒB‚Ì”äŠr‚ɂ́A
+                <literal>equals()</literal> ‚Æ <literal>hashCode()</literal> ‚ÌŽÀ‘•‚ð‹­‚­‚¨Š©‚ß‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                ‚±‚̃}ƒbƒsƒ“ƒO‚ÍŽ©‘RŽåƒL[‚ðŽg‚Á‚½ƒGƒ“ƒeƒBƒeƒB‚Å‚ÌŽg—p‚ðˆÓ}‚µ‚Ä‚¢‚Ü‚¹‚ñB
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>mutable</literal> (ƒIƒvƒVƒ‡ƒ“, ƒfƒtƒHƒ‹ƒg‚Í <literal>false</literal> ): 
+                        ƒfƒtƒHƒ‹ƒg‚ł́AŽ©‘RŽ¯•ÊŽqƒvƒƒpƒeƒB‚Í•s•Ï(’萔)‚Æ‘z’肳‚ê‚Ä‚¢‚Ü‚·B
+                    </para>
+                </listitem>
+            </itemizedlist>
+            
+        </sect2>
+        
+        <sect2 id="mapping-declaration-component" revision="2">
+            <title>component, dynamic-component</title>
+
+            <para>
+                <literal>&lt;component&gt;</literal> —v‘f‚́A
+                ŽqƒIƒuƒWƒFƒNƒg‚̃vƒƒpƒeƒB‚ðeƒNƒ‰ƒX‚̃e[ƒuƒ‹‚̃Jƒ‰ƒ€‚Öƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+                ƒRƒ“ƒ|[ƒlƒ“ƒg‚ÍŽ©•ª‚̃vƒƒpƒeƒBAƒRƒ“ƒ|[ƒlƒ“ƒgAƒRƒŒƒNƒVƒ‡ƒ“‚̏‡‚É’è‹`‚Å‚«‚Ü‚·B
+                ˆÈ‰º‚́uƒRƒ“ƒ|[ƒlƒ“ƒgv‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="component1" coords="2 45"/>
+                    <area id="component2" coords="3 45"/>
+                    <area id="component3" coords="4 45"/>
+                    <area id="component4" coords="5 45"/>
+                    <area id="component5" coords="6 45"/>
+                    <area id="component6" coords="7 45"/>
+                    <area id="component7" coords="8 45"/>
+                    <area id="component8" coords="9 45"/>
+                </areaspec>            
+                <programlisting><![CDATA[<component 
+        name="propertyName" 
+        class="className"
+        insert="true|false"
+        update="true|false"
+        access="field|property|ClassName"
+        lazy="true|false"
+        optimistic-lock="true|false"
+        unique="true|false"
+        node="element-name|."
+>
+        
+        <property ...../>
+        <many-to-one .... />
+        ........
+</component>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="component1">
+                        <para>
+                            <literal>name</literal>FƒvƒƒpƒeƒB–¼B
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="component2">
+                        <para>
+                            <literal>class</literal> 
+                            iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚̓ŠƒtƒŒƒNƒVƒ‡ƒ“‚É‚æ‚茈’肳‚ê‚éƒvƒƒpƒeƒB‚ÌŒ^jF
+                            ƒRƒ“ƒ|[ƒlƒ“ƒgiŽqjƒNƒ‰ƒX‚Ì–¼‘OB
+                        </para>                 
+                    </callout>
+                    <callout arearefs="component3">
+                        <para>
+                            <literal>insert</literal> Fƒ}ƒbƒsƒ“ƒO‚³‚ꂽƒJƒ‰ƒ€‚ªSQL‚Ì 
+                            <literal>INSERT</literal> ‚ÉŒ»‚ê‚é‚悤‚É‚·‚é‚Ç‚¤‚©‚ðŽw’肵‚Ü‚·B
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="component4">
+                        <para>
+                            <literal>update</literal> : ƒ}ƒbƒsƒ“ƒO‚³‚ꂽƒJƒ‰ƒ€‚ªSQL ‚Ì 
+                            <literal>UPDATE</literal> ‚ÉŒ»‚ê‚é‚悤‚É‚·‚é‚©‚Ç‚¤‚©‚ðŽw’肵‚Ü‚·B
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="component5">
+                        <para>
+                             <literal>access</literal> iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>property</literal> jF
+                            ƒvƒƒpƒeƒB‚Ì’l‚ւ̃AƒNƒZƒX‚ÉHibernate‚ªŽg‚¤í—ªB
+                        </para>
+                    </callout>
+                   <callout arearefs="component6">
+                        <para>
+                            <literal>lazy</literal> (optional - ƒfƒtƒHƒ‹ƒg‚Í <literal>false</literal> ):
+                           ƒCƒ“ƒXƒ^ƒ“ƒX•Ï”‚ɍŏ‰‚ɃAƒNƒZƒX‚µ‚½‚Æ‚«‚ɁA
+                           ƒRƒ“ƒ|[ƒlƒ“ƒg‚ð’x‰„‚µ‚ătƒFƒbƒ`‚·‚é‚悤Žw’肵‚Ü‚·B
+                           (ƒoƒCƒgƒR[ƒhŽÀ‘•‚ðì¬‚·‚鎞ŠÔ‚ª•K—v‚É‚È‚è‚Ü‚·)
+                        </para>
+                    </callout>
+                    <callout arearefs="component7">
+                            <para>
+                                <literal>optimistic-lock</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal> ):
+                            ‚±‚̃vƒƒpƒeƒB‚̍XV‚ɁAŠyŠÏƒƒbƒN‚̎擾‚ð—v‹‚·‚é‚©‚Ç‚¤‚©‚ðŽw’肵‚Ü‚·B
+                            Œ¾‚¢Š·‚¦‚ê‚΁A‚±‚̃vƒƒpƒeƒB‚ªƒ_[ƒeƒB‚Å‚ ‚é‚Æ‚«‚Ƀo[ƒWƒ‡ƒ“‚𑝂₷‚ׂ«‚©‚ðŒˆ’è‚µ‚Ü‚·B
+                            </para>
+                    </callout>
+                    <callout arearefs="component8">
+                            <para>
+                                <literal>unique</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>false</literal> ):
+                                ƒRƒ“ƒ|[ƒlƒ“ƒg‚Ì‚·‚ׂẴ}ƒbƒsƒ“ƒO‚·‚éƒJƒ‰ƒ€‚ɁAƒ†ƒj[ƒN§–ñ‚ª‘¶Ý‚·‚é‚©‚ðŽw’肵‚Ü‚·B
+                            </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Žq‚Ì <literal>&lt;property&gt;</literal> ƒ^ƒO‚ŁA
+                Žq‚̃Nƒ‰ƒX‚̃vƒƒpƒeƒB‚ðƒe[ƒuƒ‹ƒJƒ‰ƒ€‚Ƀ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                <literal>&lt;component&gt;</literal> —v‘f‚́AeƒGƒ“ƒeƒBƒeƒB‚Ö–ß‚éŽQÆ‚Æ‚µ‚āA
+                ƒRƒ“ƒ|[ƒlƒ“ƒg‚̃Nƒ‰ƒX‚̃vƒƒpƒeƒB‚ðƒ}ƒbƒsƒ“ƒO‚·‚é <literal>&lt;parent&gt;</literal> ƒTƒu—v‘f‚ð‹–‰Â‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                <literal>&lt;dynamic-component&gt;</literal> —v‘f‚́A
+                <literal>Map</literal> ‚ªƒRƒ“ƒ|[ƒlƒ“ƒg‚Æ‚µ‚ă}ƒbƒsƒ“ƒO‚³‚ê‚邱‚Æ‚ð‰Â”\‚É‚µ‚Ü‚·B
+                ƒvƒƒpƒeƒB–¼‚Ímap‚̃L[‚ðŽQÆ‚µ‚Ü‚·B<xref linkend="components-dynamic"/> ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                
+            </para>
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-properties" revision="2">
+            <title>properties</title>
+
+            <para>
+                <literal>&lt;properties&gt;</literal> —v‘f‚̓Nƒ‰ƒX‚̃vƒƒpƒeƒB‚ÌŽw’肳‚ꂽA
+                ˜_—“I‚ȃOƒ‹[ƒsƒ“ƒO‚ð‰Â”\‚É‚µ‚Ü‚·B
+                ‚±‚̍\‘¢‚̍łàd—v‚ÈŽg—p•û–@‚́A
+                <literal>property-ref</literal> ‚̃^[ƒQƒbƒg‚É‚È‚éƒvƒƒpƒeƒB‚ÌŒ‹‡‚ð‹–‰Â‚·‚邱‚Æ‚Å‚·B
+                ‚»‚ê‚Í‚Ü‚½A•¡”ƒJƒ‰ƒ€‚̃†ƒj[ƒN§–ñ‚ð’è‹`‚·‚éŠÈ’P‚È•û–@‚Å‚à‚ ‚è‚Ü‚·B
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="properties1" coords="2 45"/>
+                    <area id="properties2" coords="3 45"/>
+                    <area id="properties3" coords="4 45"/>
+                    <area id="properties4" coords="5 45"/>
+                    <area id="properties5" coords="6 45"/>
+                </areaspec>            
+                <programlisting><![CDATA[<properties 
+        name="logicalName" 
+        insert="true|false"
+        update="true|false"
+        optimistic-lock="true|false"
+        unique="true|false"
+>
+        
+        <property ...../>
+        <many-to-one .... />
+        ........
+</properties>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="properties1">
+                        <para>
+                            <literal>name</literal> : ƒOƒ‹[ƒsƒ“ƒO‚̘_—–¼B
+                            ŽÀÛ‚̃vƒƒpƒeƒB–¼‚Å‚Í <emphasis>‚ ‚è‚Ü‚¹‚ñ</emphasis> B
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="properties2">
+                        <para>
+                            <literal>insert</literal>Fƒ}ƒbƒsƒ“ƒO‚³‚ꂽƒJƒ‰ƒ€‚ªSQL‚Ì 
+                            <literal>INSERT</literal> ‚ÉŒ»‚ê‚é‚悤‚É‚·‚é‚©‚Ç‚¤‚©‚ðŽw’肵‚Ü‚·B
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="properties3">
+                        <para>
+                            <literal>update</literal>Fƒ}ƒbƒsƒ“ƒO‚³‚ꂽƒJƒ‰ƒ€‚ªSQL‚Ì 
+                            <literal>UPDATE</literal> ‚ÉŒ»‚ê‚é‚悤‚É‚·‚é‚©‚Ç‚¤‚©‚ðŽw’肵‚Ü‚·B
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="properties4">
+                            <para>
+                                <literal>optimistic-lock</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal> ):
+                            ‚±‚ê‚ç‚̃vƒƒpƒeƒB‚̍XV‚ÉŠyŠÏ“IƒƒbƒN‚̎擾‚ð—v‹‚·‚é‚©‚Ç‚¤‚©‚ðŽw’肵‚Ü‚·B
+                            Œ¾‚¢Š·‚¦‚ê‚΁A‚±‚̃vƒƒpƒeƒB‚ªƒ_[ƒeƒB‚Å‚ ‚é‚Æ‚«‚Ƀo[ƒWƒ‡ƒ“‚𑝂₷‚ׂ«‚©‚ðŒˆ’è‚µ‚Ü‚·B
+                            </para>
+                    </callout>
+                    <callout arearefs="properties5">
+                            <para>
+                                <literal>unique</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>false</literal> ):
+                                ƒRƒ“ƒ|[ƒlƒ“ƒg‚Ì‚·‚ׂẴ}ƒbƒsƒ“ƒO‚·‚éƒJƒ‰ƒ€‚ɁAƒ†ƒj[ƒN§–ñ‚ª‘¶Ý‚·‚é‚©‚ðŽw’肵‚Ü‚·B
+                            </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                —Ⴆ‚΁A‚à‚µˆÈ‰º‚̂悤‚È <literal>&lt;properties&gt;</literal> ƒ}ƒbƒsƒ“ƒO‚ª‚ ‚Á‚½ê‡F
+            </para>
+            
+            <programlisting><![CDATA[<class name="Person">
+    <id name="personNumber"/>
+    ...
+    <properties name="name" 
+            unique="true" update="false">
+        <property name="firstName"/>
+        <property name="initial"/>
+        <property name="lastName"/>
+    </properties>
+</class>]]></programlisting>
+
+            <para>
+                ŽåƒL[‚Ì‘ã‚í‚è‚É <literal>Person</literal> ƒe[ƒuƒ‹‚̃†ƒj[ƒNƒL[‚Ö‚ÌŽQÆ‚ðŽ‚ÂA
+                ƒŒƒKƒV[ƒf[ƒ^‚ÌŠÖ˜A‚ðŽ‚Â‚©‚à‚µ‚ê‚Ü‚¹‚ñBF
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="person" 
+         class="Person" property-ref="name">
+    <column name="firstName"/>
+    <column name="initial"/>
+    <column name="lastName"/>
+</many-to-one>]]></programlisting>
+            
+            <para>
+                ‚µ‚©‚µA‚±‚̂悤‚ȃŒƒKƒV[ƒf[ƒ^ƒ}ƒbƒsƒ“ƒO‚̃Rƒ“ƒeƒLƒXƒgŠO‚Ö‚ÌŽg—p‚͐„§‚µ‚Ü‚¹‚ñB
+            </para>
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-subclass" revision="4">
+            <title>subclass</title>
+
+            <para>
+                ÅŒã‚Ƀ|ƒŠƒ‚[ƒtƒBƒbƒN‚ȉi‘±‰»‚ɂ́Aƒ‹[ƒg‚̉i‘±ƒNƒ‰ƒX‚ÌŠeƒTƒuƒNƒ‰ƒX‚Ì’è‹`‚ª•K—v‚Å‚·B
+                table-per-class-hierarchyƒ}ƒbƒsƒ“ƒOí—ª‚ł́A
+                <literal>&lt;subclass&gt;</literal> ’è‹`‚ªŽg‚í‚ê‚Ü‚·B
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="subclass1" coords="2 55"/>
+                    <area id="subclass2" coords="3 55"/>
+                    <area id="subclass3" coords="4 55"/>
+                    <area id="subclass4" coords="5 55"/>
+                </areaspec>
+                <programlisting><![CDATA[<subclass
+        name="ClassName"
+        discriminator-value="discriminator_value"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        entity-name="EntityName"
+        node="element-name"
+        extends="SuperclassName">
+
+        <property .... />
+        .....
+</subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="subclass1">
+                        <para>
+                            <literal>name</literal>FƒTƒuƒNƒ‰ƒX‚ÌŠ®‘SCü‚³‚ꂽƒNƒ‰ƒX–¼B
+                        </para>              
+                    </callout>                   
+                    <callout arearefs="subclass2">
+                        <para>
+                            <literal>discriminator-value</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚̓Nƒ‰ƒX–¼jF
+                            ŒÂX‚̃TƒuƒNƒ‰ƒX‚ð‹æ•Ê‚·‚邽‚ß‚Ì’lB
+                        </para>               
+                    </callout>
+                    <callout arearefs="subclass3">
+                        <para>
+                            <literal>proxy</literal>iƒIƒvƒVƒ‡ƒ“jF
+                            ’x‰„‰Šú‰»ƒvƒƒLƒV‚ÉŽg‚¤ƒNƒ‰ƒX‚âƒCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽw’肵‚Ü‚·B
+                        </para>               
+                    </callout>
+                    <callout arearefs="subclass4">
+                        <para>
+                            <literal>lazy</literal>iƒIƒvƒVƒ‡ƒ“, ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal> jF 
+                            <literal>lazy="false"</literal> ‚Ɛݒ肷‚é‚ƁA’x‰„ƒtƒFƒbƒ`‚ªŽg—p‚Å‚«‚Ü‚¹‚ñB
+                        </para>
+                    </callout>    
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                ŠeƒTƒuƒNƒ‰ƒX‚ł́A‰i‘±ƒvƒƒpƒeƒB‚ƃTƒuƒNƒ‰ƒX‚ð’è‹`‚µ‚Ü‚·B  
+                <literal>&lt;version&gt;</literal> ‚Æ <literal>&lt;id&gt;</literal> ƒvƒƒpƒeƒB‚́A
+                ƒ‹[ƒgƒNƒ‰ƒX‚©‚çŒp³‚³‚ê‚é‚Ɖ¼’肳‚ê‚Ü‚·B
+                ŠK‘w\‘¢‚É‚¨‚¯‚éƒTƒuƒNƒ‰ƒX‚́A
+                ƒ†ƒj[ƒN‚È <literal>discriminator-value</literal> ‚ð’è‹`‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                none‚ªŽw’肳‚ê‚é‚ƁAŠ®‘SCü‚³‚ꂽJavaƒNƒ‰ƒX–¼‚ªŽg‚í‚ê‚Ü‚·B
+            </para>
+            
+<!--
+       <para>
+            It is possible to define <literal>subclass</literal>, <literal>union-subclass</literal>,
+            and <literal>joined-subclass</literal> mappings in separate mapping documents, directly beneath
+            <literal>hibernate-mapping</literal>. This allows you to extend a class hierachy just by adding
+            a new mapping file. You must specify an <literal>extends</literal> attribute in the subclass mapping,
+            naming a previously mapped superclass. Note: Previously this feature made the ordering of the mapping
+            documents important. Since Hibernate3, the ordering of mapping files does not matter when using the
+            extends keyword. The ordering inside a single mapping file still needs to be defined as superclasses
+            before subclasses.
+            
+            <literal>subclass</literal> A<literal>union-subclass</literal> A
+            <literal>joined-subclass</literal> ƒ}ƒbƒsƒ“ƒO‚ð 
+            <literal>hibernate-mapping</literal> ’¼‰º‚̕ʂ̃}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg“à‚Ő錾‚Å‚«‚Ü‚·B
+            ‚±‚ê‚É‚æ‚èAV‚µ‚¢ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ð’ljÁ‚·‚邾‚¯‚ŃNƒ‰ƒXŠK‘w‚ðŠg’£‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            ‚ ‚ç‚©‚¶‚߃}ƒbƒsƒ“ƒO‚·‚éƒX[ƒp[ƒNƒ‰ƒX‚ðŽw’肵‚½ƒTƒuƒNƒ‰ƒXƒ}ƒbƒsƒ“ƒO“à‚ŁA
+            <literal>extends</literal> ‘®«‚ðŽw’肵‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            ’ˆÓF‚±‚Ì“Á«‚̓}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚̏‡”Ô•t‚¯‚ªd—v‚É‚È‚è‚Ü‚·B
+            Hibernate3‚ł́AŠg’£ƒL[ƒ[ƒh‚ðŽg‚¤‚Æ‚«‚ɂ́Aƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚̏‡˜•t‚¯‚Í–â‘è‚É‚È‚è‚Ü‚¹‚ñB
+            ˆê‚‚̃}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹“à‚ł̏‡˜•t‚¯‚Í–¢‚¾‚ɁAƒTƒuƒNƒ‰ƒX‚Ì‘O‚ɃX[ƒp[ƒNƒ‰ƒX‚Æ‚µ‚Ä’è‹`‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+        </para>
+        
+    
+        <programlisting><![CDATA[
+<hibernate-mapping>
+    <subclass name="DomesticCat" extends="Cat" discriminator-value="D">
+         <property name="name" type="string"/>
+    </subclass>
+</hibernate-mapping>]]></programlisting>
+-->
+
+            <para>
+                Œp³‚̃}ƒbƒsƒ“ƒO‚ÉŠÖ‚·‚éî•ñ‚Í <xref linkend="inheritance"/> ‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+        </sect2>
+        
+
+         <sect2 id="mapping-declaration-joinedsubclass" revision="3">
+            <title>joined-subclass</title>
+
+            <para>
+                ‚à‚¤1‚‚̕û–@‚Æ‚µ‚āAŠeƒTƒuƒNƒ‰ƒX‚ðŽ©g‚̃e[ƒuƒ‹‚Öƒ}ƒbƒsƒ“ƒO‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·
+                (table-per-subclass mapping strategy)B
+                Œp³‚µ‚½ó‘Ԃ̓X[ƒp[ƒNƒ‰ƒX‚̃e[ƒuƒ‹‚ðŽg‚Á‚½Œ‹‡‚ÅŒŸõ‚µ‚Ü‚·B
+                <literal>&lt;joined-subclass&gt;</literal> —v‘f‚ðŽg—p‚µ‚Ü‚·B
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="joinedsubclass1" coords="2 45"/>
+                    <area id="joinedsubclass2" coords="3 45"/>
+                    <area id="joinedsubclass3" coords="4 45"/>
+                    <area id="joinedsubclass4" coords="5 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<joined-subclass
+        name="ClassName"
+        table="tablename"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        schema="schema"
+        catalog="catalog"
+        extends="SuperclassName"
+        persister="ClassName"
+        subselect="SQL expression"
+        entity-name="EntityName"
+        node="element-name">
+
+        <key .... >
+
+        <property .... />
+        .....
+</joined-subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="joinedsubclass1">
+                        <para>
+                            <literal>name</literal>FƒTƒuƒNƒ‰ƒX‚ÌŠ®‘SCü‚³‚ꂽƒNƒ‰ƒX–¼B
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="joinedsubclass2">
+                        <para>
+                            <literal>table</literal> :ƒTƒuƒNƒ‰ƒXƒe[ƒuƒ‹‚Ì–¼‘OB
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="joinedsubclass3">
+                        <para>
+                            <literal>proxy</literal> (ƒIƒvƒVƒ‡ƒ“):
+                            ’x‰„‰Šú‰»ƒvƒƒLƒV‚ÉŽg—p‚·‚éƒNƒ‰ƒX‚âƒCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽw’肵‚Ü‚·B
+                        </para>              
+                    </callout>
+                    <callout arearefs="joinedsubclass4">
+                        <para>
+                            <literal>lazy</literal> (ƒIƒvƒVƒ‡ƒ“, ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal> ): 
+                            <literal>lazy="false"</literal> ‚Æ‚·‚é‚ƁA’x‰„ƒtƒFƒbƒ`‚ªŽg—p‚Å‚«‚Ü‚¹‚ñB
+                         </para>
+                    </callout>    
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                ‚±‚̃}ƒbƒsƒ“ƒOí—ª‚ɂ́AŽ¯•ÊƒJƒ‰ƒ€‚Í•K—v‚ ‚è‚Ü‚¹‚ñB
+                ‚µ‚©‚µŠeƒTƒuƒNƒ‰ƒX‚Í <literal>&lt;key&gt;</literal> —v‘f‚ðŽg‚¢A
+                ƒIƒuƒWƒFƒNƒgŽ¯•ÊŽq‚ð•ÛŽ‚·‚éƒe[ƒuƒ‹ƒJƒ‰ƒ€‚ð’è‹`‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                ‚±‚̏͂̏‰‚߂̃}ƒbƒsƒ“ƒO‚͈ȉº‚̂悤‚ɏ‘‚«’¼‚¹‚Ü‚·F
+            </para>
+            
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+        <class name="Cat" table="CATS">
+                <id name="id" column="uid" type="long">
+                        <generator class="hilo"/>
+                </id>
+                <property name="birthdate" type="date"/>
+                <property name="color" not-null="true"/>
+                <property name="sex" not-null="true"/>
+                <property name="weight"/>
+                <many-to-one name="mate"/>
+                <set name="kittens">
+                        <key column="MOTHER"/>
+                        <one-to-many class="Cat"/>
+                </set>
+                <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
+                    <key column="CAT"/>
+                    <property name="name" type="string"/>
+                </joined-subclass>
+        </class>
+
+        <class name="eg.Dog">
+                <!-- ‚±‚±‚ÉDog‚̃}ƒbƒsƒ“ƒO‚ð‘‚«‚Ü‚· -->
+        </class>
+
+</hibernate-mapping>]]></programlisting>
+
+             <para>
+                 Œp³‚̃}ƒbƒsƒ“ƒO‚ÉŠÖ‚·‚éî•ñ‚Í <xref linkend="inheritance"/> ‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+             </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-unionsubclass" revision="2">
+           <title>union-subclass</title>
+
+           <para>
+               3‚–ڂ̑I‘ðŽˆ‚ÍAŒp³ŠK‘w‚Ì‹ïÛƒNƒ‰ƒX‚Ì‚Ý‚ðƒe[ƒuƒ‹‚Ƀ}ƒbƒsƒ“ƒO‚·‚邱‚Æ‚Å‚·
+               (the table-per-concrete-classí—ª)B
+               ‚»‚ꂼ‚ê‚̃e[ƒuƒ‹‚ÍŒp³‚̏ó‘Ô‚ðŠÜ‚ß‚·‚ׂẴNƒ‰ƒX‚̉i‘±ó‘Ô‚ð’è‹`‚µ‚Ü‚·B
+               Hibernate‚Å‚Í‚»‚Ì—l‚ÈŒp³ŠK‘w‚ª•K‚¸‚µ‚à•K—v‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+               ’Pƒ‚É‚»‚ꂼ‚ê‚̃Nƒ‰ƒX‚ðA
+               •ÊX‚Ì <literal>&lt;class&gt;</literal> éŒ¾‚ðŽg‚Á‚ă}ƒbƒsƒ“ƒO‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+               ‚µ‚©‚µƒ|ƒŠƒ‚[ƒtƒBƒbƒN‚ÈŠÖ˜A(—Ⴆ‚Î ŠK‘w‚̃X[ƒp[ƒNƒ‰ƒX‚Ö‚ÌŠÖ˜A)‚ðŽg‚¢‚½‚¢‚È‚çA
+               <literal>&lt;union-subclass&gt;</literal> ƒ}ƒbƒsƒ“ƒO‚ðŽg‚¤•K—v‚ª‚ ‚è‚Ü‚·B
+               
+           </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="unionsubclass1" coords="2 45"/>
+                    <area id="unionsubclass2" coords="3 45"/>
+                    <area id="unionsubclass3" coords="4 45"/>
+                    <area id="unionsubclass4" coords="5 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<union-subclass
+        name="ClassName"
+        table="tablename"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        schema="schema"
+        catalog="catalog"
+        extends="SuperclassName"
+        abstract="true|false"
+        persister="ClassName"
+        subselect="SQL expression"
+        entity-name="EntityName"
+        node="element-name">
+
+        <property .... />
+        .....
+</union-subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="unionsubclass1">
+                        <para>
+                            <literal>name</literal>FƒTƒuƒNƒ‰ƒX‚ÌŠ®‘SCü‚³‚ꂽƒNƒ‰ƒX–¼B
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="unionsubclass2">
+                        <para>
+                            <literal>table</literal> :ƒTƒuƒNƒ‰ƒXƒe[ƒuƒ‹‚Ì–¼‘OB
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="unionsubclass3">
+                        <para>
+                            <literal>proxy</literal> (ƒIƒvƒVƒ‡ƒ“):
+                            ’x‰„‰Šú‰»ƒvƒƒLƒV‚ÉŽg—p‚·‚éƒNƒ‰ƒX‚âƒCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽw’肵‚Ü‚·B
+                        </para>              
+                    </callout>
+                    <callout arearefs="unionsubclass4">
+                        <para>
+                            <literal>lazy</literal> (ƒIƒvƒVƒ‡ƒ“, ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal> ): 
+                            <literal>lazy="false"</literal> ‚Æ‚·‚é‚ƁA’x‰„ƒtƒFƒbƒ`‚ªŽg—p‚Å‚«‚Ü‚¹‚ñB
+                         </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                ‚±‚̃}ƒbƒsƒ“ƒOí—ª‚Å‚ÍŽ¯•ÊƒJƒ‰ƒ€‚âƒL[ƒJƒ‰ƒ€‚Í•K—v‚ ‚è‚Ü‚¹‚ñB
+            </para>
+
+            <para>
+                Œp³‚̃}ƒbƒsƒ“ƒO‚ÉŠÖ‚·‚éî•ñ‚Í <xref linkend="inheritance"/> ‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+        </sect2>
+
+       <sect2 id="mapping-declaration-join" revision="3">
+            <title>join</title>
+
+            <para>
+                <literal>&lt;join&gt;</literal> —v‘f‚ðŽg‚¤‚±‚ƂŁA
+                ‚P‚‚̃Nƒ‰ƒX‚̃vƒƒpƒeƒB‚ð‚¢‚­‚‚à‚̃e[ƒuƒ‹‚Ƀ}ƒbƒsƒ“ƒO‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="join1" coords="2 50"/>
+                    <area id="join2" coords="3 50"/>
+                    <area id="join3" coords="4 50"/>
+                    <area id="join4" coords="5 50"/>
+                    <area id="join5" coords="6 50"/>
+                    <area id="join6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<join
+        table="tablename"
+        schema="owner"
+        catalog="catalog"
+        fetch="join|select"
+        inverse="true|false"
+        optional="true|false">
+        
+        <key ... />
+        
+        <property ... />
+        ...
+</join>]]></programlisting>
+
+                <calloutlist>
+                    <callout arearefs="join1">
+                        <para>
+                            <literal>table</literal> :Œ‹‡‚µ‚½ƒe[ƒuƒ‹‚Ì–¼‘O
+                        </para>
+                    </callout>
+                    <callout arearefs="join2">
+                        <para>
+                           <literal>schema</literal> (ƒIƒvƒVƒ‡ƒ“):
+                           ƒ‹[ƒg‚Ì <literal>&lt;hibernate-mapping&gt;</literal> —v‘f‚ÅŽw’肵‚½ƒXƒL[ƒ}–¼‚ð
+                           ƒI[ƒo[ƒ‰ƒCƒh‚µ‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="join3">
+                        <para>
+                            <literal>catalog</literal> (ƒIƒvƒVƒ‡ƒ“):
+                            ƒ‹[ƒg‚Ì <literal>&lt;hibernate-mapping&gt;</literal> —v‘f‚ÅŽw’肵‚½ƒJƒ^ƒƒO–¼‚ð
+                            ƒI[ƒo[ƒ‰ƒCƒh‚µ‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="join4">
+                        <para>
+                            <literal>fetch</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>join</literal> ): 
+                            <literal>join</literal> ‚ðÝ’肵‚½ê‡A
+                            Hibernate‚̓fƒtƒHƒ‹ƒg‚ŁAƒNƒ‰ƒX‚âƒX[ƒp[ƒNƒ‰ƒX‚Å’è‹`‚³‚ꂽ <literal>&lt;join&gt;</literal> 
+                            ‚ðŒŸõ‚·‚é‚Ì‚É“à•”Œ‹‡‚ðŽg‚¢AƒTƒuƒNƒ‰ƒX‚Å’è‹`‚³‚ꂽ <literal>&lt;join&gt;</literal> 
+                            ‚ðŒŸõ‚·‚é‚Ì‚ÉŠO•”Œ‹‡‚ðŽg‚¢‚Ü‚·B
+                            <literal>select</literal> ‚ðÝ’肵‚½ê‡‚ɂ́A
+                            Hibernate‚̓TƒuƒNƒ‰ƒX‚Å’è‹`‚³‚ꂽ <literal>&lt;join&gt;</literal> 
+                            ‚Ì‘I‘ð‚ɏ‡ŽŸ‘I‘ð‚ðŽg‚¢‚Ü‚·B‚±‚̏ꍇA
+                            s‚ªƒTƒuƒNƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ð‘ã•\‚·‚邱‚Æ‚ª‚í‚©‚Á‚½ê‡‚É‚Ì‚Ý”­s‚³‚ê‚Ü‚·B
+                            “à•”Œ‹‡‚̓Nƒ‰ƒX‚â‚»‚̃X[ƒp[ƒNƒ‰ƒX‚Å’è‹`‚³‚ꂽ <literal>&lt;join&gt;</literal> ‚ðŒŸõ
+                            ‚·‚邽‚ß‚ÉŽg—p‚µ‚Ü‚·B                            
+                        </para>
+                    </callout>
+                    <callout arearefs="join5">
+                        <para>
+                            <literal>inverse</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>false</literal> ):
+                            ‚à‚µ‰Â”\‚Å‚ ‚ê‚΁AHibernate‚Í‚±‚ÌŒ‹‡‚Å’è‹`‚³‚ê‚Ä‚¢‚éƒvƒƒpƒeƒB‚ɑ΂µ
+                            ‘}“ü‚âXV‚ðs‚¢‚Ü‚¹‚ñB
+                        </para>
+                    </callout>
+                    <callout arearefs="join6">
+                        <para>
+                            <literal>optional</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>false</literal> ):
+                            ‚à‚µ‰Â”\‚Å‚ ‚ê‚΁AHibernate‚Í‚±‚ÌŒ‹‡‚Å’è‹`‚³‚ꂽƒvƒƒpƒeƒB‚ªnull‚Å‚È‚¢ê‡‚É‚Ì‚Ý
+                            s‚ð‘}“ü‚µA‚»‚̃vƒƒpƒeƒB‚ÌŒŸõ‚ɂ͏í‚ÉŠO•”Œ‹‡‚ðŽg—p‚µ‚Ü‚·B
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                —Ⴆ‚ΐl‚̃AƒhƒŒƒX‚̏î•ñ‚𕪗£‚µ‚½ƒe[ƒuƒ‹‚Ƀ}ƒbƒsƒ“ƒO‚·‚邱‚Æ‚ª‰Â”\‚Å‚·
+                (‚·‚ׂẴvƒƒpƒeƒB‚ɑ΂µ‚Ä’lŒ^‚̃Zƒ}ƒ“ƒeƒBƒNƒX‚ð•ÛŽ‚µ‚Ü‚·)B
+            </para>
+
+            <programlisting><![CDATA[<class name="Person"
+    table="PERSON">
+
+    <id name="id" column="PERSON_ID">...</id>
+
+    <join table="ADDRESS">
+        <key column="ADDRESS_ID"/>
+        <property name="address"/>
+        <property name="zip"/>
+        <property name="country"/>
+    </join>
+    ...]]></programlisting>
+
+            <para>
+                ‚±‚Ì“Á’¥‚Í‚µ‚΂µ‚΃ŒƒKƒV[ƒf[ƒ^ƒ‚ƒfƒ‹‚ɑ΂µ‚Ä‚Ì‚Ý—L—p‚Å‚·‚ªA
+                ƒNƒ‰ƒX‚æ‚è‚à­‚È‚¢ƒe[ƒuƒ‹‚ƁA‚«‚߂ׂ̍©‚¢ƒhƒƒCƒ“ƒ‚ƒfƒ‹‚𐄏§‚µ‚Ü‚·B
+                ‚µ‚©‚µŒã‚Åà–¾‚·‚é‚悤‚ɁA‚P‚‚̃Nƒ‰ƒXŠK‘w‚ÅŒp³‚̃}ƒbƒsƒ“ƒOí—ª‚ðØ‚è‘Ö‚¦‚鎞‚É‚Í—L—p‚Å‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-key">
+            <title>key</title>
+
+            <para>
+                ¡‚܂ʼn½“x‚© <literal>&lt;key&gt;</literal> —v‘f‚ªo‚Ä‚«‚Ü‚µ‚½B
+                ‚±‚Ì—v‘f‚͐V‚µ‚¢ƒe[ƒuƒ‹‚Ö‚ÌŒ‹‡‚ð’è‹`‚µ‚½‚èA
+                Œ‹‡ƒe[ƒuƒ‹‚ÅŠO•”ƒL[‚ð’è‹`‚µ‚½‚è‚·‚ée—v‘f‚Ì‚Ç‚±‚É‚Å‚àŒ»‚êA
+                ƒIƒŠƒWƒiƒ‹ƒe[ƒuƒ‹‚ÌŽåƒL[‚ðŽQÆ‚µ‚Ü‚·B
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="key1" coords="2 50"/>
+                    <area id="key2" coords="3 50"/>
+                    <area id="key3" coords="4 50"/>
+                    <area id="key4" coords="5 50"/>
+                    <area id="key5" coords="6 50"/>
+                    <area id="key6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<key
+        column="columnname"
+        on-delete="noaction|cascade"
+        property-ref="propertyName"
+        not-null="true|false"
+        update="true|false"
+        unique="true|false"
+/>]]></programlisting>
+
+                <calloutlist>
+                    <callout arearefs="key1">
+                        <para>
+                             <literal>column</literal> (ƒIƒvƒVƒ‡ƒ“):ŠO•”ƒL[ƒJƒ‰ƒ€‚Ì–¼‘OB
+                             ƒlƒXƒg‚µ‚½ <literal>&lt;column&gt;</literal> ƒJƒ‰ƒ€‚É‚æ‚Á‚Ä‚àŽw’肳‚ê‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="key2">
+                        <para>
+                             <literal>on-delete</literal> (ƒIƒvƒVƒ‡ƒ“, ƒfƒtƒHƒ‹ƒg‚Í <literal>noaction</literal>):
+                            ŠO•”ƒL[§–ñ‚ªƒf[ƒ^ƒx[ƒXƒŒƒxƒ‹‚ŃJƒXƒP[ƒhíœ‚ª‰Â”\‚©‚Ç‚¤‚©‚ðŽw’肵‚Ü‚·B
+                        </para>
+                    </callout>
+                    <callout arearefs="key3">
+                        <para>
+                             <literal>property-ref</literal> (ƒIƒvƒVƒ‡ƒ“):
+                             ƒIƒŠƒWƒiƒ‹ƒe[ƒuƒ‹‚ÌŽåƒL[‚Å‚Í‚È‚¢ƒJƒ‰ƒ€‚ðŽQÆ‚·‚éŠO•”ƒL[‚ðŽw’肵‚Ü‚·
+                             (ƒŒƒKƒV[ƒf[ƒ^‚ɑ΂µ‚Ä’ñ‹Ÿ‚³‚ê‚Ü‚·)B
+                        </para>
+                    </callout>
+                    <callout arearefs="key4">
+                        <para>
+                           <literal>not-null</literal> (ƒIƒvƒVƒ‡ƒ“):
+                           ŠO•”ƒL[ƒJƒ‰ƒ€‚ªnull’l‚ð‹–—e‚µ‚È‚¢‚±‚Æ‚ðŽw’肵‚Ü‚·
+                           (‚±‚Ì‚±‚Æ‚ÍŠO•”ƒL[‚ªŽåƒL[‚̈ꕔ‚Å‚ ‚邱‚Æ‚ðˆÃ–Ù“I‚ÉŽ¦‚µ‚Ü‚·)B
+                        </para>
+                    </callout>
+                    <callout arearefs="key5">
+                        <para>
+                            <literal>update</literal> (ƒIƒvƒVƒ‡ƒ“):
+                            ŠO•”ƒL[‚ðŒˆ‚µ‚čXV‚µ‚Ä‚Í‚È‚ç‚È‚¢‚±‚Æ‚ðŽw’肵‚Ü‚·
+                            (‚±‚Ì‚±‚Æ‚ÍŠO•”ƒL[‚ªŽåƒL[‚̈ꕔ‚Å‚ ‚邱‚Æ‚ðˆÃ–Ù“I‚ÉŽ¦‚µ‚Ü‚·)B
+                            
+                        </para>
+                    </callout>
+                    <callout arearefs="key6">
+                        <para>
+                            <literal>unique</literal> (ƒIƒvƒVƒ‡ƒ“):
+                            ŠO•”ƒL[‚ªƒ†ƒj[ƒN§–ñ‚ðŽ‚Â‚×‚«‚Å‚ ‚邱‚Æ‚ðŽw’肵‚Ü‚·
+                            (‚±‚Ì‚±‚Æ‚ÍŠO•”ƒL[‚ªŽåƒL[‚̈ꕔ‚Å‚ ‚邱‚Æ‚ðˆÃ–Ù“I‚ÉŽ¦‚µ‚Ü‚·)B
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                íœ‚̃pƒtƒH[ƒ}ƒ“ƒX‚ªd—v‚Å‚ ‚éƒVƒXƒeƒ€‚ɂ́A
+                ‚·‚ׂẴL[‚ð <literal>on-delete="cascade"</literal> ‚Æ’è‹`‚·‚邱‚Ƃ𐄏§‚µ‚Ü‚·B
+                ‚»‚¤‚·‚邱‚Æ‚ÅHibernate‚́A<literal>DELETE</literal> •¶‚𖈉ñ”­s‚·‚é‘ã‚í‚è‚ɁA
+                ƒf[ƒ^ƒx[ƒXƒŒƒxƒ‹‚Ì <literal>ON CASCADE DELETE</literal> §–ñ‚ðŽg—p‚µ‚Ü‚·B
+                ‚±‚Ì“Á’¥‚̓o[ƒWƒ‡ƒ“•t‚¯‚ç‚ꂽƒf[ƒ^‚ɑ΂·‚éHibernate‚̒ʏí‚ÌŠyŠÏ“IƒƒbƒNí—ª‚ð
+                –³Ž‹‚·‚é‚Æ‚¢‚¤‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+            
+            <para>
+                <literal>not-null</literal> ‚Æ <literal>update</literal> ‘®«‚́A’P•ûŒüˆê‘Α½ŠÖ˜A‚ÌŽž‚É‚Í—L—p‚Å‚·B
+                ’P•ûŒüˆê‘Α½ŠÖ˜A‚ðnull‚ð‹–—e‚µ‚È‚¢ŠO•”ƒL[‚Ƀ}ƒbƒsƒ“ƒO‚·‚é‚Æ‚«‚́A
+                <literal>&lt;key not-null="true"&gt;</literal> ‚ðŽg‚Á‚ăL[ƒJƒ‰ƒ€‚ðéŒ¾
+                 <emphasis> ‚µ‚È‚­‚Ä‚Í‚È‚è‚Ü‚¹‚ñ</emphasis> B
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-column" revision="4">
+           <title>column ‚Æ formula —v‘f</title>
+           <para>
+               <literal>column</literal> ‘®«‚ð‹Lq‚Å‚«‚é”CˆÓ‚̃}ƒbƒsƒ“ƒO—v‘f‚Í‚Ü‚½A
+               <literal>&lt;column&gt;</literal> ƒTƒu—v‘f‚à‹Lq‚Å‚«‚Ü‚·B
+               “¯—l‚É <literal>&lt;formula&gt;</literal> ‚à <literal>formula</literal> ‘®«‚Ì‘ã‘ÖŽè’i‚Å‚·B
+           </para>
+
+           <programlisting><![CDATA[<column
+        name="column_name"
+        length="N"
+        precision="N"
+        scale="N"
+        not-null="true|false"
+        unique="true|false"
+        unique-key="multicolumn_unique_key_name"
+        index="index_name"
+        sql-type="sql_type_name"
+        check="SQL expression"
+        default="SQL expression"/>]]></programlisting>
+
+            <programlisting><![CDATA[<formula>SQL expression</formula>]]></programlisting>
+        
+            <para>
+                “¯‚¶ƒvƒƒpƒeƒB‚âŠÖ˜A‚̃}ƒbƒsƒ“ƒO‚Ì’†‚ŁA
+                <literal>column</literal> ‚Æ <literal>formula</literal> ‘®«‚ð‘g‚ݍ‡‚킹‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+                —Ⴆ‚΁A“ÁŽê‚ÈŒ‹‡ðŒ‚È‚Ç‚Å‚·B
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="homeAddress" class="Address"
+        insert="false" update="false">
+    <column name="person_id" not-null="true" length="10"/>
+    <formula>'MAILING'</formula>
+</many-to-one>]]></programlisting>
+
+    </sect2>  
+    
+        <sect2 id="mapping-declaration-import">
+            <title>import</title>
+
+            <para>
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É“¯‚¶–¼‘O‚Ì2‚‚̉i‘±ƒNƒ‰ƒX‚ª‚ ‚èA
+                HibernateƒNƒGƒŠ‚ÅŠ®‘SCü‚³‚ꂽiƒpƒbƒP[ƒW‚́j–¼‘O‚ðŽw’肵‚½‚­‚È‚¢‚Ɖ¼’肵‚Ü‚·B
+                ‚»‚̂悤‚ȏꍇ‚Í <literal>auto-import="true"</literal> ‚É—Š‚炸A
+                ƒNƒ‰ƒX‚ªuƒCƒ“ƒ|[ƒgv‚³‚ꂽ‚à‚Ì‚Å‚ ‚é‚Æ–¾Ž¦‚Å‚«‚Ü‚·B
+                –¾Ž¦“I‚Ƀ}ƒbƒsƒ“ƒO‚³‚ê‚Ä‚¢‚È‚¢ƒNƒ‰ƒX‚âƒCƒ“ƒ^[ƒtƒFƒCƒX‚Å‚³‚¦‚àƒCƒ“ƒ|[ƒg‚Å‚«‚Ü‚·B
+            </para>
+            
+            <programlisting><![CDATA[<import class="java.lang.Object" rename="Universe"/>]]></programlisting>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="import1" coords="2 40"/>
+                    <area id="import2" coords="3 40"/>
+                </areaspec>
+                <programlisting><![CDATA[<import
+        class="ClassName"
+        rename="ShortName"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="import1">
+                        <para>
+                            <literal>class</literal>FJavaƒNƒ‰ƒX‚ÌŠ®‘SCü‚³‚ꂽƒNƒ‰ƒX–¼B
+                        </para>              
+                    </callout>                   
+                    <callout arearefs="import2">
+                        <para>
+                            <literal>rename</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚͏Cü‚³‚ê‚Ä‚¢‚È‚¢ƒNƒ‰ƒX–¼jF
+                            ƒNƒGƒŠŒ¾Œê‚ÅŽg‚í‚ê‚é–¼‘OB
+                        </para>               
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+        </sect2>
+
+        <sect2 id="mapping-types-anymapping" revision="2">
+            <title>any</title>
+            
+            <para>
+                ƒvƒƒpƒeƒBƒ}ƒbƒsƒ“ƒO‚É‚Í‚³‚ç‚É‚à‚¤1‚‚̌^‚ª‚ ‚è‚Ü‚·B
+                <literal>&lt;any&gt;</literal> ƒ}ƒbƒsƒ“ƒO—v‘f‚́A
+                •¡”‚̃e[ƒuƒ‹‚©‚çƒNƒ‰ƒX‚ւ̃|ƒŠƒ‚[ƒtƒBƒbƒN‚ÈŠÖ˜A‚ð’è‹`‚µ‚Ü‚·B
+                ‚±‚ÌŒ^‚̃}ƒbƒsƒ“ƒO‚É‚Í•K‚¸•¡”‚̃Jƒ‰ƒ€‚ª•K—v‚Å‚·B1”Ԗڂ̃Jƒ‰ƒ€‚ÍŠÖ˜AƒGƒ“ƒeƒBƒeƒB‚ÌŒ^‚ð•ÛŽ‚µ‚Ü‚·B
+                Žc‚è‚̃Jƒ‰ƒ€‚ÍŽ¯•ÊŽq‚ð•ÛŽ‚µ‚Ü‚·B‚±‚ÌŽí—Þ‚ÌŠÖ˜A‚É‚ÍŠO•”ƒL[§–ñ‚ðŽw’è‚·‚邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñB
+                ‚»‚Ì‚½‚ß‚±‚ê‚͍łàŽg‚í‚ê‚邱‚Æ‚Ì‚È‚¢iƒ|ƒŠƒ‚[ƒtƒBƒbƒN‚ȁjŠÖ˜A‚̃}ƒbƒsƒ“ƒO•û–@‚Å‚·B
+                ”ñí‚É“Á•Ê‚ȏꍇi—Ⴆ‚΁AŒŸ¸ƒƒO‚⃆[ƒUƒZƒbƒVƒ‡ƒ“ƒf[ƒ^‚È‚Ç)‚ÉŒÀ‚Á‚āA‚±‚ê‚ðŽg‚¤‚ׂ«‚Å‚·B
+            </para>
+
+            <para>
+                 <literal>meta-type</literal> ‚É‚æ‚èA
+                 ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̓JƒXƒ^ƒ€Œ^‚ðŽw’è‚Å‚«‚Ü‚·B‚±‚̃JƒXƒ^ƒ€Œ^‚Í
+                 ƒf[ƒ^ƒx[ƒXƒJƒ‰ƒ€‚Ì’l‚ðA<literal>id-type</literal> ‚ÅŽw’肵‚½Œ^‚Ì
+                 Ž¯•ÊŽqƒvƒƒpƒeƒB‚ðŽ‚Á‚½‰i‘±ƒNƒ‰ƒX‚Öƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+                 meta-type‚Ì’l‚©‚çƒNƒ‰ƒX–¼‚ւ̃}ƒbƒsƒ“ƒO‚ðŽw’肵‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            </para>
+
+            <programlisting><![CDATA[<any name="being" id-type="long" meta-type="string">
+    <meta-value value="TBL_ANIMAL" class="Animal"/>
+    <meta-value value="TBL_HUMAN" class="Human"/>
+    <meta-value value="TBL_ALIEN" class="Alien"/>
+    <column name="table_name"/>
+    <column name="id"/>
+</any>]]></programlisting>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="any1" coords="2 50"/>
+                    <area id="any2" coords="3 50"/>
+                    <area id="any3" coords="4 50"/>
+                    <area id="any4" coords="5 50"/>
+                    <area id="any5" coords="6 50"/>
+                    <area id="any6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<any
+        name="propertyName"
+        id-type="idtypename"
+        meta-type="metatypename"
+        cascade="cascade_style"
+        access="field|property|ClassName"
+        optimistic-lock="true|false"
+>
+        <meta-value ... />
+        <meta-value ... />
+        .....
+        <column .... />
+        <column .... />
+        .....
+</any>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="any1">
+                        <para>
+                            <literal>name</literal>FƒvƒƒpƒeƒB–¼B
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any2">
+                        <para>
+                            <literal>id-type</literal>FŽ¯•ÊŽq‚ÌŒ^B
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any3">
+                        <para>
+                            <literal>meta-type</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>string</literal> jF
+                            ƒfƒBƒXƒNƒŠƒ~ƒl[ƒ^ƒ}ƒbƒsƒ“ƒO‚Å‹–‚³‚ꂽŒ^
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any4">
+                        <para>
+                            <literal>cascade</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>none</literal> jF
+                            ƒJƒXƒP[ƒh‚̃Xƒ^ƒCƒ‹B
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any5">
+                        <para>
+                            <literal>access</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>property</literal> jF
+                            ƒvƒƒpƒeƒB‚Ì’l‚ւ̃AƒNƒZƒX‚ÉHibernate‚ªŽg‚¤í—ªB
+                        </para>
+                    </callout>
+                    <callout arearefs="any6">
+                        <para>
+                            <literal>optimistic-lock</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal> ):
+                            ‚±‚̃vƒƒpƒeƒB‚̍XV‚ÉŠyŠÏƒƒbƒN‚̎擾‚ð—v‹‚·‚é‚©‚Ç‚¤‚©‚ðŽw’肵‚Ü‚·B
+                            Œ¾‚¢Š·‚¦‚ê‚΁A‚±‚̃vƒƒpƒeƒB‚ªƒ_[ƒeƒB‚Å‚ ‚é‚Æ‚«‚Ƀo[ƒWƒ‡ƒ“‚𑝂₷‚ׂ«‚©‚ð’è‹`‚µ‚Ü‚·B
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+      </sect2>
+
+    </sect1>
+
+    <sect1 id="mapping-types">
+        <title>Hibernate‚ÌŒ^</title>
+
+        <sect2 id="mapping-types-entitiesvalues" revision="1">
+            <title>ƒGƒ“ƒeƒBƒeƒB‚Æ’l</title>
+
+            <para>
+                ‰i‘±ƒT[ƒrƒX‚ÉŠÖ‚í‚é—lX‚ÈJavaŒ¾ŒêƒŒƒxƒ‹‚̃IƒuƒWƒFƒNƒg‚̐U‚é•‘‚¢‚ð—‰ð‚·‚é‚½‚߂ɂ́A
+                ƒIƒuƒWƒFƒNƒg‚ð2‚‚̃Oƒ‹[ƒv‚É•ª‚¯‚é•K—v‚ª‚ ‚è‚Ü‚·F
+            </para>
+
+            <para>
+                 <emphasis> ƒGƒ“ƒeƒBƒeƒB</emphasis> ‚̓Gƒ“ƒeƒBƒeƒB‚Ö‚ÌŽQÆ‚ð•ÛŽ‚·‚éA
+                ‘¼‚Ì‚·‚ׂẴIƒuƒWƒFƒNƒg‚©‚ç“Æ—§‚µ‚Ä‘¶Ý‚µ‚Ü‚·B
+                ŽQÆ‚³‚ê‚È‚¢ƒIƒuƒWƒFƒNƒg‚ªƒKƒx[ƒWƒRƒŒƒNƒg‚³‚ê‚Ä‚µ‚Ü‚¤«Ž¿‚ðŽ‚Â’Êí‚ÌJavaƒ‚ƒfƒ‹‚ƁA
+                ‚±‚ê‚ð”ä‚ׂĂ݂Ă­‚¾‚³‚¢B
+                ieƒGƒ“ƒeƒBƒeƒB‚©‚çŽq‚ցAƒZ[ƒu‚ƍ폜‚ª <emphasis>ƒJƒXƒP[ƒh</emphasis> ‚³‚ꂤ‚邱‚Æ‚ðœ‚¢‚āj
+                ƒGƒ“ƒeƒBƒeƒB‚Í–¾Ž¦“I‚ɃZ[ƒu‚Ü‚½‚͍폜‚³‚ê‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                ‚±‚ê‚Í“ž’B‰Â”\«‚É‚æ‚éƒIƒuƒWƒFƒNƒg‰i‘±‰»‚ÌODMGƒ‚ƒfƒ‹‚Ƃ͈قȂÁ‚Ä‚¢‚Ü‚·B
+                ‘å‹K–͂ȃVƒXƒeƒ€‚ŃAƒvƒŠƒP[ƒVƒ‡ƒ“ƒIƒuƒWƒFƒNƒg‚ª•’ʂǂ̂悤‚ÉŽg‚í‚ê‚é‚©‚É‚æ‚è–§Ú‚ɑΉž‚µ‚Ü‚·B
+                ƒGƒ“ƒeƒBƒeƒB‚͏zŠÂ‚ÆŽQÆ‚Ì‹¤—L‚ðƒTƒ|[ƒg‚µ‚Ü‚·B
+                ‚Ü‚½‚»‚ê‚ç‚̓o[ƒWƒ‡ƒ“•t‚¯‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+                
+            </para>
+
+            <para>
+                ƒGƒ“ƒeƒBƒeƒB‚̉i‘±ó‘Ô‚Í‘¼‚̃Gƒ“ƒeƒBƒeƒB‚â <emphasis>’l</emphasis> Œ^‚Ì
+                ƒCƒ“ƒXƒ^ƒ“ƒX‚Ö‚ÌŽQÆ‚©‚ç\¬‚³‚ê‚Ü‚·B
+                ’l‚̓vƒŠƒ~ƒeƒBƒuAƒRƒŒƒNƒVƒ‡ƒ“(ƒRƒŒƒNƒVƒ‡ƒ“‚Ì“à•”‚Å‚Í‚È‚­)A
+                ƒRƒ“ƒ|[ƒlƒ“ƒgA•s•ÏƒIƒuƒWƒFƒNƒg‚Å‚·B
+                ƒGƒ“ƒeƒBƒeƒB‚Ƃ͈ႢA’l‚́i“Á‚ɃRƒŒƒNƒVƒ‡ƒ“‚ƃRƒ“ƒ|[ƒlƒ“ƒg‚É‚¨‚¢‚ājA
+                “ž’B‰Â”\«‚É‚æ‚é‰i‘±‰»‚âíœ‚ª <emphasis>s‚í‚ê‚Ü‚·</emphasis> B
+                ’lƒIƒuƒWƒFƒNƒgi‚ƃvƒŠƒ~ƒeƒBƒuj‚́A•ïŠÜ‚·‚éƒGƒ“ƒeƒBƒeƒB‚ƈꏏ‚ɉi‘±‰»‚âíœ‚ªs‚í‚ê‚é‚̂ŁA
+                ‚»‚ê‚ç‚ð“Æ—§‚Ƀo[ƒWƒ‡ƒ“•t‚¯‚·‚邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñB
+                ’l‚É‚Í“Æ—§‚µ‚½ƒAƒCƒfƒ“ƒeƒBƒeƒB‚ª‚È‚¢‚̂ŁA
+                •¡”‚̃Gƒ“ƒeƒBƒeƒB‚âƒRƒŒƒNƒVƒ‡ƒ“‚ª‚±‚ê‚ð‹¤—L‚·‚邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñB
+            </para>
+
+            <para>
+                ‚±‚ê‚܂Łu‰i‘±ƒNƒ‰ƒXv‚Æ‚¢‚¤Œ¾—t‚ðƒGƒ“ƒeƒBƒeƒB‚̈Ӗ¡‚ÅŽg‚Á‚Ä‚«‚Ü‚µ‚½B
+                ‚±‚ê‚©‚ç‚à‚»‚¤‚µ‚Ä‚¢‚«‚Ü‚·B
+                Œµ–§‚ÉŒ¾‚¤‚ƁA‰i‘±ó‘Ô‚ðŽ‚Âƒ†[ƒU’è‹`‚̃Nƒ‰ƒX‚Ì‚·‚ׂĂª
+                ƒGƒ“ƒeƒBƒeƒB‚Æ‚¢‚¤‚킯‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+                <emphasis>ƒRƒ“ƒ|[ƒlƒ“ƒg</emphasis> ‚Í’l‚̃Zƒ}ƒ“ƒeƒBƒNƒX‚ðŽ‚Âƒ†[ƒU’è‹`ƒNƒ‰ƒX‚Å‚·B
+                <literal>java.lang.String</literal> Œ^‚̃vƒƒpƒeƒB‚à‚Ü‚½’l‚̃Zƒ}ƒ“ƒeƒBƒNƒX‚ðŽ‚¿‚Ü‚·B
+                ’è‹`‚·‚é‚È‚çAJDK‚Å’ñ‹Ÿ‚³‚ê‚Ä‚¢‚é‚·‚ׂĂÌJava‚ÌŒ^(ƒNƒ‰ƒX)‚ª’l‚̃Zƒ}ƒ“ƒeƒBƒNƒX‚ðŽ‚Â‚Æ‚¢‚¦‚Ü‚·B
+                ˆê•ûƒ†[ƒU’è‹`Œ^‚́AƒGƒ“ƒeƒBƒeƒB‚â’lŒ^‚̃Zƒ}ƒ“ƒeƒBƒNƒX‚Æ‚Æ‚à‚Ƀ}ƒbƒsƒ“ƒO‚Å‚«‚Ü‚·B
+                ‚±‚ÌŒˆ’è‚̓AƒvƒŠƒP[ƒVƒ‡ƒ“ŠJ”­ŽÒŽŸ‘æ‚Å‚·B
+                ‚»‚̃Nƒ‰ƒX‚Ì‚P‚‚̃Cƒ“ƒXƒ^ƒ“ƒX‚Ö‚Ì‹¤—LŽQÆ‚́A
+                ƒhƒƒCƒ“ƒ‚ƒfƒ‹“à‚̃Gƒ“ƒeƒBƒeƒBƒNƒ‰ƒX‚ɑ΂·‚é—Ç‚¢ƒqƒ“ƒg‚É‚È‚è‚Ü‚·B
+                ˆê•û‡¬W–ñ‚âW–ñ‚́A’ʏí’lŒ^‚Ö•ÏŠ·‚³‚ê‚Ü‚·B
+                
+            </para>
+
+            <para>
+                –{ƒhƒLƒ…ƒƒ“ƒg‚ð’Ê‚µ‚āA‰½“x‚à‚±‚ÌŠT”O‚ðŽæ‚èã‚°‚Ü‚·B
+            </para>
+
+            <para>
+                JavaŒ^‚̃VƒXƒeƒ€(‚à‚µ‚­‚ÍŠJ”­ŽÒ‚ª’è‹`‚µ‚½ƒGƒ“ƒeƒBƒeƒB‚Æ’lŒ^)‚ð
+                SQL/ƒf[ƒ^ƒx[ƒXŒ^‚̃VƒXƒeƒ€‚Ƀ}ƒbƒsƒ“ƒO‚·‚邱‚Ƃ͓‚¢‚Å‚·B
+                Hibernate‚Í‚Q‚‚̃VƒXƒeƒ€‚̉˂¯‹´‚ð’ñ‹Ÿ‚µ‚Ü‚·B
+                ƒGƒ“ƒeƒBƒeƒB‚ɑ΂µ‚Ä‚Í 
+                <literal>&lt;class&gt;</literal> ‚â <literal>&lt;subclass&gt;</literal> ‚È‚Ç‚ðŽg—p‚µ‚Ü‚·B
+                ’lŒ^‚ɑ΂µ‚Ä‚Í <literal>&lt;property&gt;</literal> ‚â 
+                <literal>&lt;component&gt;</literal> ‚È‚Ç‚ðA’ʏí <literal>type</literal> ‚Æ‚Æ‚à‚ÉŽg‚¢‚Ü‚·B
+                ‚±‚Ì‘®«‚Ì’l‚ÍHibernate‚Ì <emphasis>ƒ}ƒbƒsƒ“ƒOŒ^</emphasis> ‚Ì–¼‘O‚Å‚·B
+                Hibernate‚Í(•W€JDK‚Ì’lŒ^‚ɑ΂µ‚Ä)‘½‚­‚ÌŽ©—R‚ȃ}ƒbƒsƒ“ƒO‚ð’ñ‹Ÿ‚µ‚Ü‚·B
+                Œã‚ÅŒ©‚é‚悤‚ɁAŽ©g‚̃}ƒbƒsƒ“ƒOŒ^‚ð‹Lq‚µA“¯—l‚ɃJƒXƒ^ƒ€‚Ì•ÏŠ·í—ª‚ðŽÀ‘•‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            </para>
+
+            <para>
+                ƒRƒŒƒNƒVƒ‡ƒ“‚ðœ‚­‘g‚ݍž‚Ý‚ÌHibernate‚ÌŒ^‚Í‚·‚ׂāAnullƒZƒ}ƒ“ƒeƒBƒNƒX‚ðƒTƒ|[ƒg‚µ‚Ü‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-types-basictypes" revision="3">
+            <title>Šî–{“I‚ÈŒ^</title>
+
+            <para>
+                ‘g‚ݍž‚Ý‚Ì <emphasis>Šî–{“I‚ȃ}ƒbƒsƒ“ƒOŒ^</emphasis> ‚Í‘å‚Ü‚©‚Ɉȉº‚̂悤‚É•ª‚¯‚ç‚ê‚Ü‚·B
+
+                <variablelist>
+                    <varlistentry>
+                        <term><literal>integer, long, short, float, double, character, byte,
+                            boolean, yes_no, true_false</literal></term>
+                        <listitem>
+                            <para>
+                                Java‚̃vƒŠƒ~ƒeƒBƒu‚⃉ƒbƒp[ƒNƒ‰ƒX‚©‚ç“KØ‚ȁiƒxƒ“ƒ_[ŒÅ—L‚́j
+                                SQLƒJƒ‰ƒ€Œ^‚Ö‚ÌŒ^ƒ}ƒbƒsƒ“ƒOB
+                                <literal>boolean, yes_no</literal> ‚Æ <literal>true_false</literal> ‚́A
+                                ‚·‚ׂÄJava‚Ì <literal>boolean</literal> 
+                                ‚Ü‚½‚Í <literal>java.lang.Boolean</literal> ‚Ì‘ã‘ÖƒGƒ“ƒR[ƒh‚Å‚·B
+                                
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>string</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>java.lang.String</literal> ‚©‚ç <literal>VARCHAR</literal> 
+                                i‚Ü‚½‚ÍOracle‚Ì <literal>VARCHAR2</literal> j‚Ö‚ÌŒ^ƒ}ƒbƒsƒ“ƒOB
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>date, time, timestamp</literal></term>
+                        <listitem>
+                            <para>
+                                 <literal>java.util.Date</literal> ‚Æ‚»‚̃TƒuƒNƒ‰ƒX‚©‚çSQLŒ^‚Ì <literal>DATE</literal>, 
+                                <literal>TIME</literal> , <literal>TIMESTAMP</literal> i‚Ü‚½‚Í‚»‚ê‚ç‚Æ“™‰¿‚È‚à‚́j
+                                ‚Ö‚ÌŒ^ƒ}ƒbƒsƒ“ƒOB
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>calendar, calendar_date</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>java.util.Calendar</literal> ‚©‚çSQLŒ^ ‚́u <literal>TIMESTAMP</literal> , 
+                                 <literal>DATE</literal> (‚Ü‚½‚Í‚»‚ê‚ç‚Æ“™‰¿‚È‚à‚́j‚Ö‚ÌŒ^ƒ}ƒbƒsƒ“ƒOB
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>big_decimal, big_integer</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>java.math.BigDecimal</literal> ‚Æ <literal>java.math.BigInteger</literal> 
+                                ‚©‚ç <literal>NUMERIC</literal>i‚Ü‚½‚ÍOracle‚Ì <literal>NUMBER</literal> j‚Ö‚ÌŒ^ƒ}ƒbƒsƒ“ƒOB
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>locale, timezone, currency</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>java.util.Locale</literal> , <literal>java.util.TimeZone</literal> , 
+                                <literal>java.util.Currency</literal> ‚©‚ç <literal>VARCHAR</literal> 
+                                i‚Ü‚½‚ÍOracle‚Ì <literal>VARCHAR2</literal> j‚Ö‚ÌŒ^ƒ}ƒbƒsƒ“ƒOB
+                                <literal>Locale</literal> ‚Æ <literal>Currency</literal> ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚́A
+                                ‚»‚ê‚ç‚ÌISOƒR[ƒh‚Ƀ}ƒbƒsƒ“ƒO‚³‚ê‚Ü‚·B 
+                                <literal>TimeZone</literal> ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚́A
+                                ‚»‚ê‚ç‚Ì <literal>ID</literal> ‚Ƀ}ƒbƒsƒ“ƒO‚³‚ê‚Ü‚·B
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>class</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>java.lang.Class</literal> ‚©‚ç <literal>VARCHAR</literal> 
+                                i‚Ü‚½‚ÍOracle‚Ì <literal>VARCHAR2</literal> j‚Ö‚ÌŒ^ƒ}ƒbƒsƒ“ƒOB
+                                <literal>Class</literal> ‚Í‚»‚ÌŠ®‘SCü‚³‚ꂽ–¼‘O‚Ƀ}ƒbƒsƒ“ƒO‚³‚ê‚Ü‚·B
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>binary</literal></term>
+                        <listitem>
+                            <para>
+                                 ƒoƒCƒg”z—ñ‚́A“KØ‚ÈSQL‚̃oƒCƒiƒŠŒ^‚Ƀ}ƒbƒsƒ“ƒO‚³‚ê‚Ü‚·B
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>text</literal></term>
+                        <listitem>
+                            <para>
+                                ’·‚¢Java•¶Žš—ñ‚́ASQL‚Ì <literal>CLOB</literal> ‚Ü‚½‚Í 
+                                <literal>TEXT</literal> Œ^‚Ƀ}ƒbƒsƒ“ƒO‚³‚ê‚Ü‚·B
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>serializable</literal></term>
+                        <listitem>
+                            <para>
+                                ƒVƒŠƒAƒ‰ƒCƒY‰Â”\‚ÈJavaŒ^‚́A“KØ‚ÈSQL‚̃oƒCƒiƒŠŒ^‚Ƀ}ƒbƒsƒ“ƒO‚³‚ê‚Ü‚·B
+                                ƒfƒtƒHƒ‹ƒg‚ÅŠî–{Œ^‚Å‚Í‚È‚¢ƒVƒŠƒAƒ‰ƒCƒY‰Â”\‚ÈJavaƒNƒ‰ƒX‚â
+                                ƒCƒ“ƒ^[ƒtƒFƒCƒX‚Ì–¼‘O‚ðŽw’è‚·‚邱‚ƂŁA
+                                Hibernate‚ÌŒ^‚ð <literal>serializable</literal> ‚Æ‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>clob, blob</literal></term>
+                        <listitem>
+                            <para>
+                                JDBCƒNƒ‰ƒX <literal>java.sql.Clob</literal> ‚Æ <literal>java.sql.Blob</literal> 
+                                ‚ɑ΂·‚éŒ^ƒ}ƒbƒsƒ“ƒOB
+                                blob‚âclobƒIƒuƒWƒFƒNƒg‚̓gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÌŠO‚ł͍ė˜—p‚Å‚«‚È‚¢‚½‚߁A
+                                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚æ‚Á‚Ä‚Í•s•Ö‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                                i‚³‚ç‚ɂ̓hƒ‰ƒCƒoƒTƒ|[ƒg‚ªˆêŠÑ‚µ‚Ä‚¢‚Ü‚¹‚ñBj
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    
+                    <varlistentry>
+                        <term>
+                            <literal>imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date,
+                            imm_serializable, imm_binary</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                ‚Ù‚Æ‚ñ‚ǂ̏ꍇ‚ɉ•ςł ‚éJava‚ÌŒ^‚ɑ΂·‚éŒ^ƒ}ƒbƒsƒ“ƒOB
+                                Hibernate‚Í•s•Ï‚ÈJava‚ÌŒ^‚ɑ΂µ‚Ă͍œK‰»‚ðs‚¢A
+                                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚Í‚»‚ê‚ð•s•ÏƒIƒuƒWƒFƒNƒg‚Æ‚µ‚Ĉµ‚¢‚Ü‚·B
+                                —Ⴆ‚Î <literal>imm_timestamp</literal> ‚Æ‚µ‚ă}ƒbƒv‚µ‚½ƒCƒ“ƒXƒ^ƒ“ƒX‚ɑ΂µ‚āA
+                                <literal>Date.setTime()</literal> ‚ðŒÄ‚яo‚µ‚Ä‚Í‚È‚è‚Ü‚¹‚ñB
+                                ƒvƒƒpƒeƒB‚Ì’l‚ð•ÏX‚µ‚»‚̕ύX‚ð‰i‘±‰»‚·‚邽‚߂ɂ́A
+                                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̓vƒƒpƒeƒB‚ɑ΂µ‚ĐV‚µ‚¢(“¯ˆê‚Å‚È‚¢)ƒIƒuƒWƒFƒNƒg‚ðŠ„‚è“–‚Ä‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                            </para>
+                        </listitem>
+                    </varlistentry>                    
+                </variablelist>
+            
+            </para>
+
+            <para>
+                ƒGƒ“ƒeƒBƒeƒB‚ƃRƒŒƒNƒVƒ‡ƒ“‚̃†ƒj[ƒN‚ÈŽ¯•ÊŽq‚́A<literal>binary</literal> , <literal>blob</literal> , 
+                <literal>clob</literal> ‚ðœ‚­A‚Ç‚ñ‚ÈŠî–{Œ^‚Å‚à\‚¢‚Ü‚¹‚ñB
+                i•¡‡Ž¯•ÊŽq‚Å‚à\‚¢‚Ü‚¹‚ñBˆÈ‰º‚ðŒ©‚Ä‚­‚¾‚³‚¢Bj
+            </para>
+            
+            <para>
+                Šî–{“I‚È’lŒ^‚ɂ́A<literal>org.hibernate.Hibernate</literal> ‚Å’è‹`‚³‚ꂽ 
+                <literal>Type</literal> ’萔‚ª‚»‚ꂼ‚ê‚ ‚è‚Ü‚·B
+                —Ⴆ‚΁A<literal>Hibernate.STRING</literal> ‚Í <literal>string</literal> Œ^‚ð•\Œ»‚µ‚Ä‚¢‚Ü‚·B
+            </para>
+
+        </sect2>
+        
+        <sect2 id="mapping-types-custom" revision="2">
+            <title>ƒJƒXƒ^ƒ€Œ^</title>
+
+            <para>
+                  ŠJ”­ŽÒ‚ª“ÆŽ©‚Ì’lŒ^‚ðì¬‚·‚邱‚Ƃ́A”äŠr“IŠÈ’P‚Å‚·B
+                —Ⴆ‚΁A<literal>java.lang.BigInteger</literal> Œ^‚̃vƒƒpƒeƒB‚ð 
+                <literal>VARCHAR</literal> ƒJƒ‰ƒ€‚ɉi‘±‰»‚µ‚½‚¢‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                Hibernate‚Í‚±‚Ì‚½‚ß‚Ì‘g‚ݍž‚ÝŒ^‚ð—pˆÓ‚µ‚Ä‚¢‚Ü‚¹‚ñB
+                ‚µ‚©‚µƒJƒXƒ^ƒ€Œ^‚́AƒvƒƒpƒeƒBi‚Ü‚½‚̓RƒŒƒNƒVƒ‡ƒ“‚Ì—v‘fj‚ð1‚‚̃e[ƒuƒ‹ƒJƒ‰ƒ€‚É
+                ƒ}ƒbƒsƒ“ƒO‚·‚é‚̂ɐ§ŒÀ‚Í‚ ‚è‚Ü‚¹‚ñB
+                ‚»‚Ì‚½‚ߗႦ‚΁A<literal>java.lang.String</literal> Œ^‚Ì 
+                <literal>getName()</literal> / <literal>setName()</literal> 
+                JavaƒvƒƒpƒeƒB‚ð <literal>FIRST_NAME</literal> , <literal>INITIAL</literal>, <literal>SURNAME</literal> 
+                ƒJƒ‰ƒ€‚ɉi‘±‰»‚Å‚«‚Ü‚·B
+            </para>
+            
+            <para>
+                ƒJƒXƒ^ƒ€Œ^‚ðŽÀ‘•‚·‚é‚ɂ́A<literal>org.hibernate.UserType</literal> ‚Ü‚½‚Í 
+                <literal>org.hibernate.CompositeUserType</literal> ‚ðŽÀ‘•‚µA
+                Œ^‚ÌŠ®‘SCü‚³‚ꂽ–¼‘O‚ðŽg‚Á‚ăvƒƒpƒeƒB‚ð’è‹`‚µ‚Ü‚·B
+                ‚ǂ̂悤‚ÈŽí—Þ‚Ì‚à‚Ì‚ª‰Â”\‚©‚𒲂ׂé‚ɂ́A
+                <literal>org.hibernate.test.DoubleStringType</literal> ‚ðŠm”F‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <programlisting><![CDATA[<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
+    <column name="first_string"/>
+    <column name="second_string"/>
+</property>]]></programlisting>
+
+            <para>
+                <literal>&lt;column&gt;</literal> ƒ^ƒO‚ŁA
+                ƒvƒƒpƒeƒB‚𕡐”‚̃Jƒ‰ƒ€‚Öƒ}ƒbƒsƒ“ƒO‚Å‚«‚邱‚Æ‚É’–Ú‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+            
+            <para>
+                <literal>CompositeUserType</literal> , <literal>EnhancedUserType</literal> ,
+                <literal>UserCollectionType</literal> , <literal>UserVersionType</literal> 
+                ƒCƒ“ƒ^[ƒtƒFƒCƒX‚́A‚æ‚è“ÁŽê‚ÈŽg—p–@‚ɑ΂µ‚ẴTƒ|[ƒg‚ð’ñ‹Ÿ‚µ‚Ü‚·B
+            </para>
+            
+            <para>
+                ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹“à‚Å <literal>UserType</literal> ‚Öƒpƒ‰ƒ[ƒ^‚ð’ñ‹Ÿ‚Å‚«‚Ü‚·B
+                ‚±‚Ì‚½‚߂ɂ́A<literal>UserType</literal> ‚Í 
+                <literal>org.hibernate.usertype.ParameterizedType</literal> ‚ðŽÀ‘•‚µ‚È‚­‚Ä‚Í‚È‚è‚Ü‚¹‚ñB
+                ƒJƒXƒ^ƒ€Œ^ƒpƒ‰ƒ[ƒ^‚ð’ñ‹Ÿ‚·‚邽‚߂ɁA
+                ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹“à‚Å <literal>&lt;type&gt;</literal> —v‘f‚ðŽg—p‚Å‚«‚Ü‚·B
+            </para>
+            
+            <programlisting><![CDATA[<property name="priority">
+    <type name="com.mycompany.usertypes.DefaultValueIntegerType">
+        <param name="default">0</param>
+    </type>
+</property>]]></programlisting>
+
+            <para>
+                <literal>UserType</literal> ‚́A
+                ˆø”‚Æ‚µ‚Ä“n‚³‚ꂽ <literal>Properties</literal> ƒIƒuƒWƒFƒNƒg‚©‚çA
+                <literal>default</literal> ‚ÅŽw’肵‚½ƒpƒ‰ƒ[ƒ^‚ɑ΂·‚é’l‚ðŒŸõ‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            </para>
+            
+            <para>
+                “Á’è‚Ì <literal>UserType</literal> ‚ð•p”É‚ÉŽg—p‚·‚é‚È‚ç‚΁A’Z‚¢–¼‘O‚ð’è‹`‚·‚é‚Æ•Ö—˜‚É‚È‚é‚Å‚µ‚傤B
+                <literal>&lt;typedef&gt;</literal> —v‘f‚ðŽg‚Á‚Ä‚±‚̂悤‚È‚±‚Æ‚ªs‚¦‚Ü‚·B
+                Typedefs‚̓JƒXƒ^ƒ€Œ^‚É–¼‘O‚ðŠ„‚è“–‚Ä‚Ü‚·B
+                ‚»‚ÌŒ^‚ªƒpƒ‰ƒ[ƒ^‚ðŽ‚Â‚È‚ç‚΁A
+                ƒpƒ‰ƒ[ƒ^‚̃fƒtƒHƒ‹ƒg’l‚̃ŠƒXƒg‚ðŠÜ‚Þ‚±‚Æ‚à‚Å‚«‚Ü‚·B
+            </para>
+            
+            <programlisting><![CDATA[<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
+    <param name="default">0</param>
+</typedef>]]></programlisting>
+
+            <programlisting><![CDATA[<property name="priority" type="default_zero"/>]]></programlisting>
+
+            <para>
+                ƒvƒƒpƒeƒB‚̃}ƒbƒsƒ“ƒO‚ÅŒ^ƒpƒ‰ƒ[ƒ^‚ðŽg‚¤‚±‚ƂŁA
+                typedef‚Å’ñ‹Ÿ‚³‚ꂽƒpƒ‰ƒ[ƒ^‚ð‚»‚Ì“s“xƒI[ƒo[ƒ‰ƒCƒh‚·‚邱‚Æ‚ª‰Â”\‚Å‚·B
+                
+            </para>
+            
+            <para>
+                Hibernate‚Ì•L‚¢‘g‚ݍž‚ÝŒ^‚ƃRƒ“ƒ|[ƒlƒ“ƒg‚ɑ΂·‚éƒTƒ|[ƒg‚́A
+                ƒJƒXƒ^ƒ€Œ^‚ð‚ß‚Á‚½‚É <emphasis>Žg‚í‚È‚¢</emphasis> ‚Æ‚¢‚¤‚±‚Æ‚ðˆÓ–¡‚µ‚Ü‚·B
+                ‚»‚ê‚Å‚à‚È‚¨AƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚Å•po‚·‚é(ƒGƒ“ƒeƒBƒeƒB‚Å‚Í‚È‚¢)ƒNƒ‰ƒX‚ɑ΂·‚éƒJƒXƒ^ƒ€Œ^‚ÌŽg—p‚́A
+                ‚æ‚¢‚â‚è•û‚Å‚ ‚é‚Æ‚Ý‚È‚³‚ê‚Ü‚·B
+                —Ⴆ‚Î <literal>MonetaryAmount</literal> ƒNƒ‰ƒX‚̓Rƒ“ƒ|[ƒlƒ“ƒg‚Æ‚µ‚ÄŠÈ’P‚Ƀ}ƒbƒsƒ“ƒO‚Å‚«‚Ü‚·‚ªA
+                <literal>CompositeUserType</literal> ‚Ì—Ç‚¢Œó•â‚Å‚·B
+                ƒJƒXƒ^ƒ€Œ^‚ðŽg—p‚·‚é“®‹@‚Ì1‚‚͒ŠÛ‰»‚Å‚·B
+                ƒJƒXƒ^ƒ€Œ^‚ðŽg‚¤‚±‚ƂŁA’ʉ݂ð‚ǂ̂悤‚É•\Œ»‚µ‚悤‚Æ‚à
+                ƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚Í‹N‚±‚肤‚é•Ï‰»‚ɑΉž‚Å‚«‚Ü‚·B
+            </para>
+
+        </sect2>
+        
+    </sect1>
+    
+    
+    <sect1 id="mapping-entityname">
+        <title>‚P‚‚̃Nƒ‰ƒX‚É‚P‚ˆȏã‚̃}ƒbƒsƒ“ƒO</title>
+        <para>
+            ‚ ‚é‰i‘±ƒNƒ‰ƒX‚ɁAˆê‚ˆȏã‚̃}ƒbƒsƒ“ƒO‚ð’ñ‹Ÿ‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B
+            ‚±‚̏ꍇAƒ}ƒbƒsƒ“ƒO‚·‚é‚Q‚‚̃Gƒ“ƒeƒBƒeƒB‚̃Cƒ“ƒXƒ^ƒ“ƒX‚𖾊m‚É‚·‚邽‚߂ɁA
+            <emphasis>ƒGƒ“ƒeƒBƒeƒB–¼</emphasis> ‚ðŽw’肵‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ
+            (ƒfƒtƒHƒ‹ƒg‚ł̓Gƒ“ƒeƒBƒeƒB–¼‚̓Nƒ‰ƒX–¼‚Æ“¯‚¶‚Å‚·B)B
+            ‰i‘±ƒIƒuƒWƒFƒNƒg‚ðˆµ‚¤‚Æ‚«AƒNƒGƒŠ‚ð‘‚«ž‚Þ‚Æ‚«A
+            Žw’肳‚ꂽƒGƒ“ƒeƒBƒeƒB‚Ö‚ÌŠÖ˜A‚ðƒ}ƒbƒsƒ“ƒO‚·‚é‚Æ‚«‚ɂ́A
+            Hibernate‚ł̓Gƒ“ƒeƒBƒeƒB–¼‚ðŽw’肵‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+        </para>
+        
+        <programlisting><![CDATA[<class name="Contract" table="Contracts" 
+        entity-name="CurrentContract">
+    ...
+    <set name="history" inverse="true" 
+            order-by="effectiveEndDate desc">
+        <key column="currentContractId"/>
+        <one-to-many entity-name="HistoricalContract"/>
+    </set>
+</class>
+
+<class name="Contract" table="ContractHistory" 
+        entity-name="HistoricalContract">
+    ...
+    <many-to-one name="currentContract" 
+            column="currentContractId" 
+            entity-name="CurrentContract"/>
+</class>]]></programlisting>
+
+        <para>
+            ŠÖ˜A‚ª<literal>class</literal> ‚Ì‘ã‚í‚è‚É <literal>entity-name</literal> ‚ðŽg‚Á‚āA
+            ‚ǂ̂悤‚ÉŽw’肳‚ê‚é‚Ì‚©‚É’–Ú‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+    </sect1>
+
+    <sect1 id="mapping-quotedidentifiers">
+            <title>ƒoƒbƒNƒNƒH[ƒg‚ň͂ñ‚¾ SQL Ž¯•ÊŽq</title>
+            <para>
+                ƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚Ńe[ƒuƒ‹‚âƒJƒ‰ƒ€‚Ì–¼‘O‚ðƒoƒbƒNƒNƒH[ƒg‚ň͂ނ±‚ƂŁA
+                Hibernate‚Ő¶¬‚³‚ꂽSQL’†‚ÌŽ¯•ÊŽq‚ðˆø—p‚³‚¹‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+                Hibernate‚ÍSQL‚Ì <literal>Dialect</literal> ‚ɑΉž‚·‚éA³‚µ‚¢ˆø—pƒXƒ^ƒCƒ‹‚ðŽg‚¢‚Ü‚·
+                i•’ʂ̓_ƒuƒ‹ƒNƒH[ƒg‚Å‚·‚ªASQL Server‚Å‚Í‚©‚¬Š‡ŒÊAMySQL‚ł̓oƒbƒNƒNƒH[ƒg‚Å‚·jB
+            </para>
+
+            <programlisting><![CDATA[<class name="LineItem" table="`Line Item`">
+    <id name="id" column="`Item Id`"/><generator class="assigned"/></id>
+    <property name="itemNumber" column="`Item #`"/>
+    ...
+</class>]]></programlisting>
+
+    </sect1>
+
+      
+       <sect1 id="mapping-alternatives">
+       <title>ƒƒ^ƒf[ƒ^‚Ì‘ã‘ÖŽè’i</title>
+       
+       <para>
+            XML‚Ì‹LqˆÈŠO‚ɁA
+            Hibernate‚Å‚ÍO/Rƒ}ƒbƒsƒ“ƒO‚̃ƒ^ƒf[ƒ^‚ð’è‹`‚·‚é‘ã‘Ö•û–@‚ª‚ ‚è‚Ü‚·B
+       </para>
+
+    <sect2 id="mapping-xdoclet">
+        <title>XDoclet ƒ}[ƒNƒAƒbƒv‚ÌŽg—p</title>
+
+        <para>
+            ‘½‚­‚ÌHibernateƒ†[ƒU‚ÍXDoclet‚Ì <literal>@hibernate.tags</literal> ‚ðŽg‚Á‚āA
+            ƒ\[ƒXƒR[ƒh“à‚É’¼Úƒ}ƒbƒsƒ“ƒOî•ñ‚𖄂ߍž‚Þ‚±‚Æ‚ðD‚Ý‚Ü‚·B
+            ‚±‚ê‚ÍŒµ–§‚ÉŒ¾‚¦‚ÎXDoclet‚Ì•ª–ì‚Ȃ̂ŁA–{ƒhƒLƒ…ƒƒ“ƒg‚Å‚Í‚±‚Ì•û–@‚ð‘ΏۂƂ͂µ‚Ü‚¹‚ñB
+            ‚µ‚©‚µXDoclet‚ðŽg‚Á‚½ˆÈ‰º‚Ì <literal>Cat</literal> ƒ}ƒbƒsƒ“ƒO‚Ì—á‚ðŽ¦‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+/**
+ * @hibernate.class
+ *  table="CATS"
+ */
+public class Cat {
+    private Long id; // identifier
+    private Date birthdate;
+    private Cat mother;
+    private Set kittens
+    private Color color;
+    private char sex;
+    private float weight;
+
+    /*
+     * @hibernate.id
+     *  generator-class="native"
+     *  column="CAT_ID"
+     */
+    public Long getId() {
+        return id;
+    }
+    private void setId(Long id) {
+        this.id=id;
+    }
+
+    /**
+     * @hibernate.many-to-one
+     *  column="PARENT_ID"
+     */
+    public Cat getMother() {
+        return mother;
+    }
+    void setMother(Cat mother) {
+        this.mother = mother;
+    }
+
+    /**
+     * @hibernate.property
+     *  column="BIRTH_DATE"
+     */
+    public Date getBirthdate() {
+        return birthdate;
+    }
+    void setBirthdate(Date date) {
+        birthdate = date;
+    }
+    /**
+     * @hibernate.property
+     *  column="WEIGHT"
+     */
+    public float getWeight() {
+        return weight;
+    }
+    void setWeight(float weight) {
+        this.weight = weight;
+    }
+
+    /**
+     * @hibernate.property
+     *  column="COLOR"
+     *  not-null="true"
+     */
+    public Color getColor() {
+        return color;
+    }
+    void setColor(Color color) {
+        this.color = color;
+    }
+    /**
+     * @hibernate.set
+     *  inverse="true"
+     *  order-by="BIRTH_DATE"
+     * @hibernate.collection-key
+     *  column="PARENT_ID"
+     * @hibernate.collection-one-to-many
+     */
+    public Set getKittens() {
+        return kittens;
+    }
+    void setKittens(Set kittens) {
+        this.kittens = kittens;
+    }
+    // addKitten not needed by Hibernate
+    public void addKitten(Cat kitten) {
+        kittens.add(kitten);
+    }
+
+    /**
+     * @hibernate.property
+     *  column="SEX"
+     *  not-null="true"
+     *  update="false"
+     */
+    public char getSex() {
+        return sex;
+    }
+    void setSex(char sex) {
+        this.sex=sex;
+    }
+}]]></programlisting>
+
+        <para>
+            Hibernate‚̃EƒFƒuƒTƒCƒg‚ɂ́AXDoclet‚ÆHibernate‚ÉŠÖ‚·‚éƒTƒ“ƒvƒ‹‚ª‘½”‚ ‚è‚Ü‚·B
+        </para>
+
+    </sect2>
+
+    <sect2 id="mapping-annotations" revision="2">
+        <title>JDK 5.0 ƒAƒmƒe[ƒVƒ‡ƒ“‚ÌŽg—p</title>
+
+        <para>
+            JDK5.0‚ł̓^ƒCƒvƒZ[ƒt‚©‚ƒRƒ“ƒpƒCƒ‹Žž‚Ƀ`ƒFƒbƒN‚Å‚«‚éA
+            Œ¾ŒêƒŒƒxƒ‹‚ÌXDocletƒXƒ^ƒCƒ‹‚̃Aƒmƒe[ƒVƒ‡ƒ“‚𓱓ü‚µ‚Ü‚µ‚½B
+            ‚±‚̃ƒJƒjƒYƒ€‚ÍXDoclet‚̃Aƒmƒe[ƒVƒ‡ƒ“‚æ‚è‚à‹­—͂ŁAƒc[ƒ‹‚âIDE‚à‘½‚­‚ªƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·B
+            —Ⴆ‚ÎIntelliJ IDEA‚́AJDK5.0‚ɃAƒmƒe[ƒVƒ‡ƒ“‚ÌŽ©“®•âŠ®‚ƍ\•¶‚Ì‹­’²•\Ž¦‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·B
+            EJBŽd—l (JSR-220)‚̐V‚µ‚¢ƒo[ƒWƒ‡ƒ“‚ł́AƒGƒ“ƒeƒBƒeƒBƒr[ƒ“‚ɑ΂·‚éŽå—v‚ȃƒ^ƒf[ƒ^ƒƒJƒjƒYƒ€‚Æ‚µ‚Ä
+            JDK5.0‚̃Aƒmƒe[ƒVƒ‡ƒ“‚ðŽg—p‚µ‚Ä‚¢‚Ü‚·B
+            Hibernate3‚Å‚ÍJSR-220 (‰i‘±‰»API)‚Ì <literal>EntityManager</literal> ‚ðŽÀ‘•‚µA
+            ƒƒ^ƒf[ƒ^ƒ}ƒbƒsƒ“ƒO‚ɑ΂·‚éƒTƒ|[ƒg‚́A
+            •Êƒ_ƒEƒ“ƒ[ƒh‚Ì <emphasis>Hibernate Annotations</emphasis> ƒpƒbƒP[ƒW‚É‚æ‚è—˜—p‰Â”\‚Å‚·B
+            ‚±‚ê‚ÍEJB3(JSR-220)‚ÆHibernate3‚̃ƒ^ƒf[ƒ^‚ð‚Ç‚¿‚ç‚àƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·B
+            
+        </para>
+
+        <para>
+            ˆÈ‰º‚ÍEJB‚̃Gƒ“ƒeƒBƒeƒBƒr[ƒ“‚Æ‚µ‚Ä’Žß‚³‚ꂽPOJOƒNƒ‰ƒX‚Ì—á‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[@Entity(access = AccessType.FIELD)
+public class Customer implements Serializable {
+
+    @Id;
+    Long id;
+
+    String firstName;
+    String lastName;
+    Date birthday;
+
+    @Transient
+    Integer age;
+
+    @Embedded
+    private Address homeAddress;
+
+    @OneToMany(cascade=CascadeType.ALL)
+    @JoinColumn(name="CUSTOMER_ID")
+    Set<Order> orders;
+
+    // Getter/setter and business methods
+}]]></programlisting>
+
+        <para>
+            JDK5.0‚̃Aƒmƒe[ƒVƒ‡ƒ“(‚ÆJSR-220)‚̃Tƒ|[ƒg‚͐is’†‚̍ì‹Æ‚Å‚ ‚èAŠ®‘S‚Å‚Í‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚³‚ç‚ɏڂµ‚¢î•ñ‚ÍHibernate‚̃Aƒmƒe[ƒVƒ‡ƒ“Eƒ‚ƒWƒ…[ƒ‹‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+    
+    </sect2>
+    
+    </sect1>
+
+
+    <sect1 id="mapping-generated" revision="1">
+        <title>¶¬ƒvƒƒpƒeƒB</title>
+        <para>
+            ¶¬ƒvƒƒpƒeƒB‚Ƃ́Aƒf[ƒ^ƒx[ƒX‚É‚æ‚Á‚ж¬‚³‚ꂽ’l‚ðŽ‚ÂƒvƒƒpƒeƒB‚Å‚·B
+            ’ʏíAHibernateƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚́Aƒf[ƒ^ƒx[ƒX‚ª’l‚𐶐¬‚µ‚½ƒvƒƒpƒeƒB‚ðŠÜ‚ÞƒIƒuƒWƒFƒNƒg‚ð
+            <literal>ƒŠƒtƒŒƒbƒVƒ…</literal> ‚·‚é•K—v‚ª‚ ‚è‚Ü‚µ‚½B
+            ‚µ‚©‚µAƒvƒƒpƒeƒB‚ª¶¬‚³‚ꂽ‚Æ‚¢‚¤‚±‚Æ‚ðƒ}[ƒN‚·‚邱‚ƂŁA
+            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̓ŠƒtƒŒƒbƒVƒ…‚̐ӔC‚ðHibernate‚ɈϏ÷‚µ‚Ü‚·B
+            
+            Šî–{“I‚ɁA¶¬ƒvƒƒpƒeƒB‚ðŽ‚Â‚Æ’è‹`‚µ‚½ƒGƒ“ƒeƒBƒeƒB‚ɑ΂µ‚Ä
+            Hibernate‚ªINSERT‚âUPDATE‚ÌSQL‚𔭍s‚µ‚½Œã‚·‚®‚ɁA
+            ¶¬‚³‚ꂽ’l‚ð“ǂݍž‚Þ‚½‚ß‚Ì SELECT SQL ‚ª”­s‚³‚ê‚Ü‚·B
+        </para>
+        <para>
+            ¶¬ƒvƒƒpƒeƒB‚́A‘}“ü•s‰Â”\‚©‚XV•s‰Â”\‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            <xref linkend="mapping-declaration-version">versions</xref> A
+            <xref linkend="mapping-declaration-timestamp">timestamps</xref> A
+            <xref linkend="mapping-declaration-property">simple properties</xref> ‚¾‚¯‚ª¶¬‚³‚ꂽ‚ƃ}[ƒN‚Å‚«‚Ü‚·B
+        </para>
+        <para>
+            <literal>never</literal> (ƒfƒtƒHƒ‹ƒg) - —^‚¦‚ç‚ꂽƒvƒƒpƒeƒB‚Ì’l‚́A
+            ƒf[ƒ^ƒx[ƒX‚©‚琶¬‚³‚ê‚È‚¢‚±‚Æ‚ðˆÓ–¡‚µ‚Ü‚·B
+        </para>
+        <para>
+            <literal>insert</literal> - —^‚¦‚ç‚ꂽƒvƒƒpƒeƒB‚Ì’l‚Í‘}“üŽž‚ɐ¶¬‚³‚ê‚邪A
+            ‘±‚¢‚Ä‹N‚±‚éXVŽž‚ɂ͐¶¬‚³‚ê‚È‚¢‚±‚ÆŽ¦‚µ‚Ü‚·B
+            ì¬‚³‚ꂽ“ú•t‚Ȃǂ́A‚±‚̃JƒeƒSƒŠ‚É•ª—Þ‚³‚ê‚Ü‚·B
+            <xref linkend="mapping-declaration-version">version</xref> ‚â
+            <xref linkend="mapping-declaration-timestamp">timestamp</xref> ‚Ì
+            ƒvƒƒpƒeƒB‚͐¶¬‚³‚ꂽ‚ƃ}[ƒN‚Å‚«‚Ü‚·‚ªA‚±‚̃IƒvƒVƒ‡ƒ“‚Í—˜—p‚Å‚«‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+        <para>
+            <literal>always</literal> - ‘}“üŽž‚àXVŽž‚àƒvƒƒpƒeƒB‚Ì’l‚ª¶¬‚³‚ê‚邱‚Æ‚ðŽ¦‚µ‚Ü‚·B
+        </para>
+    </sect1>
+
+    <sect1 id="mapping-database-object" revision="0">
+        <title>•â•“I‚ȃf[ƒ^ƒx[ƒXEƒIƒuƒWƒFƒNƒg</title>
+        <para>
+            Hibernate‚̃XƒL[ƒ}EƒGƒ{ƒŠƒ…[ƒVƒ‡ƒ“ƒc[ƒ‹‚ƘA“®‚·‚邱‚ƂŁA
+            ”CˆÓ‚̃f[ƒ^ƒx[ƒXEƒIƒuƒWƒFƒNƒgiƒgƒŠƒK[‚âƒXƒgƒAƒhƒvƒƒV[ƒWƒƒ‚Ȃǁj‚ÌCREATE‚ÆDROP‚É‚æ‚èA
+            Hibernate‚̃}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹“à‚̃†[ƒUEƒXƒL[ƒ}‚ð‚·‚×‚Ä’è‹`‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B
+            Žå‚ɃgƒŠƒK‚âƒXƒgƒAƒhƒvƒƒV[ƒWƒƒ‚̂悤‚ȃf[ƒ^ƒx[ƒXEƒIƒuƒWƒFƒNƒg‚𐶐¬‚âíœ‚·‚邱‚Æ‚ðˆÓ}‚µ‚Ä‚¢‚Ü‚·‚ªA
+            ŽÀÛ‚É‚Í <literal>java.sql.Statement.execute()</literal> ƒƒ\ƒbƒh‚É‚æ‚Á‚ÄŽÀs‚Å‚«‚é
+            ”CˆÓ‚ÌSQLƒRƒ}ƒ“ƒhiALTERAINSERT‚Ȃǁj‚ªŽÀs‚Å‚«‚Ü‚·B
+            •â•“I‚ȃf[ƒ^ƒx[ƒXEƒIƒuƒWƒFƒNƒg‚ð’è‹`‚·‚邽‚߂́A2‚‚̊î–{“I‚È•û–@‚ª‚ ‚è‚Ü‚·B
+        </para>
+        <para>
+            1‚–ڂ̕û–@‚́ACREATE‚ÆDROPƒRƒ}ƒ“ƒh‚ðƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ÌŠO‚ɁA–¾Ž¦“I‚É‹LÚ‚·‚邱‚Æ‚Å‚·B
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <create>CREATE TRIGGER my_trigger ...</create>
+        <drop>DROP TRIGGER my_trigger</drop>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+        <para>
+            2‚–ڂ̕û–@‚́ACREATE‚ÆDROPƒRƒ}ƒ“ƒh‚Ì‘g‚Ý—§‚Ä•û‚ð’m‚Á‚Ä‚¢‚éƒJƒXƒ^ƒ€ƒNƒ‰ƒX‚ð’ñ‹Ÿ‚·‚邱‚Æ‚Å‚·B
+            ‚±‚̃JƒXƒ^ƒ€ƒNƒ‰ƒX‚Í <literal>org.hibernate.mapping.AuxiliaryDatabaseObject</literal> ƒCƒ“ƒ^ƒtƒF[ƒX‚ð
+            ŽÀ‘•‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <definition class="MyTriggerDefinition"/>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+        <para>
+            ‚³‚ç‚ɁA‚ ‚éƒf[ƒ^ƒx[ƒX•ûŒ¾‚ªŽg—p‚³‚ê‚鎞‚É‚¾‚¯“K—p‚·‚é‚Æ‚¢‚Á‚½‚悤‚ɁA
+            ƒf[ƒ^ƒx[ƒXEƒIƒuƒWƒFƒNƒg‚ªŽg‚í‚ê‚éƒP[ƒX‚ðŒÀ’è‚Å‚«‚Ü‚·B
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <definition class="MyTriggerDefinition"/>
+        <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/>
+        <dialect-scope name="org.hibernate.dialect.OracleDialect"/>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/batch.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/batch.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/batch.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,386 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="batch">
+    <title>ƒoƒbƒ`ˆ—</title>
+    
+    <para>
+        Hibernate‚ðŽg‚Á‚ăf[ƒ^ƒx[ƒX‚É100,000s‚ð‘}“ü‚·‚é‹ð’¼‚È•û–@‚́A‚±‚̂悤‚È‚à‚Ì‚Å‚·F
+    </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+for ( int i=0; i<100000; i++ ) {
+    Customer customer = new Customer(.....);
+    session.save(customer);
+}
+tx.commit();
+session.close();]]></programlisting>
+
+    <para>
+        ‚±‚ê‚Í50,000”Ԗڂ̍s‚Ì‚ ‚½‚è‚Å <literal>OutOfMemoryException</literal> ‚ÅŽ¸”s‚·‚é‚Å‚µ‚傤B
+        Hibernate‚ªƒZƒbƒVƒ‡ƒ“ƒŒƒxƒ‹ƒLƒƒƒbƒVƒ…‚ŁA
+        V‚µ‚­‘}“ü‚³‚ꂽ‚·‚×‚Ä‚Ì <literal>Customer</literal> 
+        ƒCƒ“ƒXƒ^ƒ“ƒX‚ðƒLƒƒƒbƒVƒ…‚·‚é‚©‚ç‚Å‚·B
+    </para>
+
+    <para>
+        ‚±‚̏͂ł́A‚±‚Ì–â‘è‚ð‰ñ”ð‚·‚é•û–@‚ðÐ‰î‚µ‚Ü‚·B
+        ‚µ‚©‚µƒoƒbƒ`ˆ—‚ð‚·‚é‚È‚çAJDBCƒoƒbƒ`‚ªŽg—p‰Â”\‚Å‚ ‚邱‚Æ‚ª”ñí‚ɏd—v‚Å‚·B
+        ‚»‚¤‚Å‚È‚¯‚ê‚Ύ荠‚ȃpƒtƒH[ƒ}ƒ“ƒX‚ª“¾‚ç‚ê‚Ü‚¹‚ñB
+        JDBCƒoƒbƒ`ƒTƒCƒY‚ðŽè ‚Ȑ”’li—Ⴆ‚΁A10‚©‚ç50j‚ɐݒ肵‚Ä‚­‚¾‚³‚¢F
+    </para>
+    
+<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
+
+    <para>
+        ‚Ü‚½“ñŽŸƒLƒƒƒbƒVƒ…‚ª‘S‚­Œø‚©‚È‚¢ƒvƒƒZƒX‚ŁA
+        ‚±‚̂悤‚ȍì‹Æ‚ð‚µ‚½‚¢‚ÆŽv‚¤‚©‚à‚µ‚ê‚Ü‚¹‚ñF
+    </para>
+
+<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
+
+    <para>
+        ‚µ‚©‚µA‚±‚ê‚͐â‘΂ɕK—v‚Æ‚¢‚¤‚킯‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+        ‚È‚º‚È‚ç–¾Ž¦“I‚É <literal>CacheMode</literal> ‚ðÝ’肵‚āA
+        “ñŽŸƒLƒƒƒbƒVƒ…‚Æ‚Ì‘ŠŒÝì—p‚𖳌ø‚É‚·‚邱‚Æ‚ª‚Å‚«‚é‚©‚ç‚Å‚·B
+       
+    </para>
+
+    <sect1 id="batch-inserts">
+        <title>ƒoƒbƒ`‘}“ü</title>
+
+        <para>
+            V‚µ‚¢ƒIƒuƒWƒFƒNƒg‚ð‰i‘±‰»‚·‚é‚Æ‚«AˆêŽŸƒLƒƒƒbƒVƒ…‚̃TƒCƒY‚𐧌À‚·‚邽‚߁A
+            ƒZƒbƒVƒ‡ƒ“‚ð <literal>flush()</literal> ‚µ‚Ä <literal>clear()</literal> 
+            ‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+   
+for ( int i=0; i<100000; i++ ) {
+    Customer customer = new Customer(.....);
+    session.save(customer);
+    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
+        //flush a batch of inserts and release memory:
+        session.flush();
+        session.clear();
+    }
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="batch-update" >
+        <title>ƒoƒbƒ`XV</title>
+
+        <para>
+            ƒf[ƒ^‚𕜌³‚µ‚½‚èXV‚µ‚½‚è‚·‚é‚É‚Í“¯‚¶ƒAƒCƒfƒBƒA‚ð“K—p‚µ‚Ü‚·B
+            ‚»‚ê‚ɉÁ‚¦‚āAƒf[ƒ^‚̍s‚𑽂­•Ô‚·ƒNƒGƒŠ‚ɑ΂µ‚Ä—LŒø‚È
+            ƒT[ƒo[ƒTƒCƒh‚̃J[ƒ\ƒ‹‚Ì—˜“_‚𐶂©‚µ‚½‚¯‚ê‚Î 
+            <literal>scroll()</literal> ‚ðŽg‚¤•K—v‚ª‚ ‚è‚Ü‚·B
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+   
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+    .setCacheMode(CacheMode.IGNORE)
+    .scroll(ScrollMode.FORWARD_ONLY);
+int count=0;
+while ( customers.next() ) {
+    Customer customer = (Customer) customers.get(0);
+    customer.updateStuff(...);
+    if ( ++count % 20 == 0 ) {
+        //flush a batch of updates and release memory:
+        session.flush();
+        session.clear();
+    }
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="batch-statelesssession">
+        <title>
+        StatelessSessionƒCƒ“ƒ^[ƒtƒFƒCƒX
+        </title>
+        
+        <para>
+            ‚Ü‚½•Ê‚Ì•û–@‚Æ‚µ‚āAHibernate‚̓Rƒ}ƒ“ƒhŽwŒü‚ÌAPI‚ð—pˆÓ‚µ‚Ä‚¢‚Ü‚·B
+            ‚±‚ê‚Í•ª—£ƒIƒuƒWƒFƒNƒg‚ÌŒ`‚ŁA
+            ƒf[ƒ^ƒx[ƒX‚Ƃ̃f[ƒ^ƒXƒgƒŠ[ƒ€‚Ì‚â‚èŽæ‚è‚ÉŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+            <literal>StatelessSession</literal> ‚ÍŠÖ˜A‚·‚é‰i‘±ƒRƒ“ƒeƒLƒXƒg‚ðŽ‚½‚¸A
+            ‚ƒŒƒxƒ‹‚̃‰ƒCƒtƒTƒCƒNƒ‹ƒZƒ}ƒ“ƒeƒBƒNƒX‚Ì‘½‚­‚ð’ñ‹Ÿ‚µ‚Ü‚¹‚ñB
+            “Á‚ɃXƒe[ƒgƒŒƒXƒZƒbƒVƒ‡ƒ“‚́AˆêŽžƒLƒƒƒbƒVƒ…‚ðŽÀ‘•‚¹‚¸A
+            ‚Ü‚½‚ǂ̂悤‚È“ñŽŸƒLƒƒƒbƒVƒ…‚âƒNƒGƒŠƒLƒƒƒbƒVƒ…‚Æ‚à‘ŠŒÝì—p‚µ‚Ü‚¹‚ñB
+            ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒiƒ‹‚Èwrite-behind‚⎩“®ƒ_[ƒeƒBƒ`ƒFƒbƒN‚àŽÀ‘•‚µ‚Ü‚¹‚ñB
+            ƒXƒe[ƒgƒŒƒXƒZƒbƒVƒ‡ƒ“‚ðŽg‚Á‚čs‚í‚ê‚é‘€ì‚ªA
+            ŠÖ˜A‚·‚éƒCƒ“ƒXƒ^ƒ“ƒX‚ÖƒJƒXƒP[ƒh‚³‚ê‚邱‚Æ‚ÍŒˆ‚µ‚Ä‚ ‚è‚Ü‚¹‚ñB
+            ƒRƒŒƒNƒVƒ‡ƒ“‚́AƒXƒe[ƒgƒŒƒXƒZƒbƒVƒ‡ƒ“‚©‚ç‚Í–³Ž‹‚³‚ê‚Ü‚·B
+            ƒXƒe[ƒgƒŒƒXƒZƒbƒVƒ‡ƒ“‚ð’Ê‚µ‚čs‚í‚ê‚é‘€ì‚́A
+            Hibernate‚̃Cƒxƒ“ƒgƒ‚ƒfƒ‹‚âƒCƒ“ƒ^[ƒZƒvƒ^‚̉e‹¿‚ðŽó‚¯‚Ü‚¹‚ñB
+            ˆêŽžƒLƒƒƒbƒVƒ…‚ðŽ‚½‚È‚¢‚½‚߁A
+            ƒXƒe[ƒgƒŒƒXƒZƒbƒVƒ‡ƒ“‚Í•Ê–¼‚ðŽ‚Âƒf[ƒ^‚ɏãŽè‚­‘Ώˆ‚Å‚«‚Ü‚¹‚ñB
+            ƒXƒe[ƒgƒŒƒXƒZƒbƒVƒ‡ƒ“‚͒჌ƒxƒ‹‚Ì’ŠÛ‰»‚Å‚ ‚èAJDBC‚É”ñí‚É‚æ‚­Ž—‚Ä‚¢‚Ü‚·B
+            
+        </para>
+
+<programlisting><![CDATA[StatelessSession session = sessionFactory.openStatelessSession();
+Transaction tx = session.beginTransaction();
+   
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+    .scroll(ScrollMode.FORWARD_ONLY);
+while ( customers.next() ) {
+    Customer customer = (Customer) customers.get(0);
+    customer.updateStuff(...);
+    session.update(customer);
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            ‚±‚̃R[ƒh—á‚ł́AƒNƒGƒŠ‚ª•Ô‚· <literal>Customer</literal> 
+            ƒCƒ“ƒXƒ^ƒ“ƒX‚Í‘¦À‚ɁiƒZƒbƒVƒ‡ƒ“‚©‚çj•ª—£‚³‚ê‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚±‚ê‚́A‚ǂ̂悤‚ȉi‘±ƒRƒ“ƒeƒLƒXƒg‚Æ‚àŒˆ‚µ‚ÄŠÖ˜A‚µ‚Ü‚¹‚ñB
+            
+        </para>
+        
+        <para>
+            <literal>StatelessSession</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚Å’è‹`‚³‚ê‚Ä‚¢‚é 
+            <literal>insert(), update(), delete()</literal> ‚́A
+            ’჌ƒxƒ‹‚Ì’¼Ú“I‚ȃf[ƒ^ƒx[ƒX‘€ì‚ƍl‚¦‚ç‚ê‚Ü‚·B
+            Œ‹‰Ê‚Æ‚µ‚āASQL‚Ì <literal>INSERT, UPDATE, DELETE</literal> ‚ª‚»‚ꂼ‚ꑦÀ‚ÉŽÀs‚³‚ê‚Ü‚·B
+            ‚±‚̂悤‚ɁA‚±‚ê‚ç‚Í <literal>Session</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚Å’è‹`‚³‚ê‚Ä‚¢‚é 
+            <literal>save(), saveOrUpdate(), delete()</literal> 
+            ‚Æ‚Í”ñí‚ɈقȂéˆÓ–¡‚ðŽ‚¿‚Ü‚·B
+            
+        </para>
+
+    </sect1>
+
+    <sect1 id="batch-direct" revision="3">
+        <title>
+        DMLƒXƒ^ƒCƒ‹‚Ì‘€ì
+        </title>
+
+        <para>
+            ‚·‚Å‚É‹c˜_‚µ‚½‚悤‚ɁAŽ©“®“I‚©‚“§‰ß“I‚ȃIƒuƒWƒFƒNƒg/ƒŠƒŒ[ƒVƒ‡ƒiƒ‹ƒ}ƒbƒsƒ“ƒO‚́A
+            ƒIƒuƒWƒFƒNƒg‚̏ó‘Ô‚ÌŠÇ—‚Å‚ ‚é‚ƍl‚¦‚ç‚ê‚Ü‚·B
+            ‚±‚ê‚̓ƒ‚ƒŠ“à‚̃IƒuƒWƒFƒNƒg‚̏ó‘Ô‚ð—˜—p‚Å‚«‚é‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+            ‚»‚Ì‚½‚߁iSQL‚Ì <literal>ƒf[ƒ^‘€ìŒ¾Œê</literal> (DML) •¶F
+            <literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal> 
+            ‚ðŽg‚Á‚ājƒf[ƒ^ƒx[ƒX“à‚̃f[ƒ^‚𒼐ڑ€ì‚µ‚Ä‚àA
+            ƒƒ‚ƒŠ“à‚̏ó‘Ԃɂ͉e‹¿‚ð—^‚¦‚Ü‚¹‚ñB
+            ‚µ‚©‚µHibernate‚́Aƒoƒ‹ƒNSQLƒXƒ^ƒCƒ‹‚ÌDML•¶ŽÀs‚ɑΉž‚·‚郁ƒ\ƒbƒh‚ð—pˆÓ‚µ‚Ä‚¢‚Ü‚·B
+            ‚±‚ê‚ÍHibernateƒNƒGƒŠŒ¾Œêi<xref linkend="queryhql">HQL</xref>j
+            ‚ð’Ê‚µ‚ÄŽÀs‚³‚ê‚Ü‚·B
+            
+        </para>
+
+        <para>
+            <literal>UPDATE</literal> ‚Æ <literal>DELETE</literal> •¶‚Ì‹^Ž—\•¶‚́F
+            <literal>( UPDATE | DELETE ) FROM? ƒGƒ“ƒeƒBƒeƒB–¼ (WHERE ðŒß)?</literal> ‚Å‚·B
+            ’ˆÓ‚·‚ׂ«“_‚ª‚¢‚­‚‚©‚ ‚è‚Ü‚·F
+            
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    fromß‚É‚¨‚¢‚āAFROMƒL[ƒ[ƒh‚̓IƒvƒVƒ‡ƒ“‚Å‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    fromß‚Å‚Í’Pˆê‚̃Gƒ“ƒeƒBƒeƒB–¼‚¾‚¯‚ª‰Â”\‚ŁA
+                    ”CˆÓ‚Å•Ê–¼‚ð•t‚¯‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+                    ƒGƒ“ƒeƒBƒeƒB–¼‚É•Ê–¼‚ª—^‚¦‚ç‚ê‚é‚ƁA‚ǂ̂悤‚ȃvƒƒpƒeƒBŽQÆ‚àA
+                    ‚»‚Ì•Ê–¼‚ðŽg‚Á‚ďCü‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                    ‚à‚µƒGƒ“ƒeƒBƒeƒB–¼‚É•Ê–¼‚ª—^‚¦‚ç‚ê‚È‚¯‚ê‚΁A
+                    ‚ǂ̂悤‚ȃvƒƒpƒeƒBŽQÆ‚àCü‚µ‚Ä‚Í‚È‚è‚Ü‚¹‚ñB
+                    
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                iˆÃ–Ù“I‚Å‚ ‚ê–¾Ž¦“I‚Å‚ ‚êj<xref linkend="queryhql-joins-forms">Œ‹‡</xref> 
+                ‚ðƒoƒ‹ƒNHQLƒNƒGƒŠ“à‚ÅŽw’è‚·‚邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñB
+                ƒTƒuƒNƒGƒŠ‚Íwhereß‚ÅŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·
+                ƒTƒuƒNƒGƒŠ‚»‚Ì‚à‚̂́AŒ‹‡‚ðŠÜ‚ß‚ç‚ê‚Ü‚·B
+                
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    whereß‚̓IƒvƒVƒ‡ƒ“‚Å‚·B
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            —á‚Æ‚µ‚āAHQL‚Ì <literal>UPDATE</literal> ‚ðŽÀs‚·‚é‚ɂ́A
+            <literal>Query.executeUpdate()</literal> ƒƒ\ƒbƒh‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢B
+            i‚±‚̃ƒ\ƒbƒh‚Í‚¨‚È‚¶‚Ý‚ÌJDBC <literal>PreparedStatement.executeUpdate()</literal> 
+            ‚©‚ç–¼•t‚¯‚ç‚ê‚Ü‚µ‚½jF
+            d
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
+// or String hqlUpdate = "update Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+        .setString( "newName", newName )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            HQL‚Ì <literal>UPDATE</literal> •¶‚́AƒfƒtƒHƒ‹ƒg‚ł́Aì—p‚·‚éƒGƒ“ƒeƒBƒeƒB‚Ì 
+            <xref linkend="mapping-declaration-version">version</xref> ‚â 
+            <xref linkend="mapping-declaration-timestamp">timestamp</xref> 
+            ƒvƒƒpƒeƒB‚Ì’l‚ɂ͉e‹¿‚µ‚Ü‚¹‚ñB
+            ‚±‚ê‚ÍEJB3‚ÌŽd—l‚É‚àŽó‚¯Œp‚ª‚ê‚Ä‚¢‚Ü‚·B
+            ‚µ‚©‚µ <literal>versioned update</literal> ‚ðŽg‚Á‚āA
+            <literal>version</literal> ‚â <literal>timestamp</literal> 
+            ƒvƒƒpƒeƒB‚Ì’l‚ð‹­§“I‚ɃŠƒZƒbƒg‚³‚¹‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            ‚±‚ê‚Í <literal>UPDATE</literal> ƒL[ƒ[ƒh‚ÌŒã‚É <literal>VERSIONED</literal> 
+            ƒL[ƒ[ƒh‚ð’ljÁ‚·‚邱‚Ƃōs‚¦‚Ü‚·B
+            
+        </para>
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+        .setString( "newName", newName )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            ƒJƒXƒ^ƒ€ƒo[ƒWƒ‡ƒ“Œ^i<literal>org.hibernate.usertype.UserVersionType</literal>j
+            ‚Í <literal>update versioned</literal> •¶‚ƈꏏ‚ÉŽg‚¦‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <para>
+            HQL‚Ì <literal>DELETE</literal> ‚ðŽÀs‚·‚é‚ɂ́A
+            “¯‚¶ <literal>Query.executeUpdate()</literal> ƒƒ\ƒbƒh‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢F
+            
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlDelete = "delete Customer c where c.name = :oldName";
+// or String hqlDelete = "delete Customer where name = :oldName";
+int deletedEntities = s.createQuery( hqlDelete )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            <literal>Query.executeUpdate()</literal> ƒƒ\ƒbƒh‚ª•Ô‚· <literal>int</literal> 
+            ‚Ì’l‚́A‚±‚Ì‘€ì‚ª‰e‹¿‚ð‹y‚Ú‚µ‚½ƒGƒ“ƒeƒBƒeƒB‚̐”‚Å‚·B
+            ‚±‚ꂪ‰e‹¿‚·‚éƒf[ƒ^ƒx[ƒX“à‚̍s”‚ƁA‘ŠŒÝ‚ÉŠÖŒW‚·‚é‚©‚Ç‚¤‚©‚ðl‚¦‚Ä‚Ý‚Ä‚­‚¾‚³‚¢B
+            HQLƒoƒ‹ƒN‘€ì‚́AŒ‹‰Ê‚Æ‚µ‚āAŽÀÛ‚ÌSQL•¶‚ª•¡”ŽÀs‚³‚ê‚邱‚Æ‚É‚È‚è‚Ü‚·B
+            —Ⴆ‚Îjoined-subclass‚Å‚·B
+            •Ô‚³‚ê‚鐔‚́A‚»‚Ì•¶‚É‚æ‚Á‚ĉe‹¿‚³‚ꂽŽÀÛ‚̃Gƒ“ƒeƒBƒeƒB‚̐”‚ðŽ¦‚µ‚Ü‚·B
+            joined-subclass‚Ì—á‚É–ß‚é‚ƁAƒTƒuƒNƒ‰ƒX‚̈ê‚‚ɑ΂·‚éíœ‚́A
+            ‚»‚̃TƒuƒNƒ‰ƒX‚ªƒ}ƒbƒsƒ“ƒO‚³‚ꂽƒe[ƒuƒ‹‚¾‚¯‚Å‚Í‚È‚­A
+            uƒ‹[ƒgvƒe[ƒuƒ‹‚ÆŒp³ŠK‘w‚ð‚³‚ç‚ɉº‚Á‚½joined-subclass‚̃e[ƒuƒ‹‚̍폜‚É‚È‚è‚Ü‚·B
+        </para>
+
+        <para>
+            <literal>INSERT</literal> •¶‚Ì‹^Ž—\•¶‚́F
+            <literal>INSERT INTO ƒGƒ“ƒeƒBƒeƒB–¼ ƒvƒƒpƒeƒBƒŠƒXƒg select•¶</literal> ‚Å‚·B
+            ’ˆÓ‚·‚ׂ«“_‚ª‚¢‚­‚‚©‚ ‚è‚Ü‚·F
+            
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    INSERT INTO ... SELECT ... ‚ÌŒ`Ž®‚¾‚¯‚ªƒTƒ|[ƒg‚³‚ê‚Ä‚¢‚Ü‚·B
+                    INSERT INTO ... VALUES ... ‚ÌŒ`Ž®‚̓Tƒ|[ƒg‚³‚ê‚Ä‚¢‚Ü‚¹‚ñB
+                </para>
+                <para>
+                    ƒvƒƒpƒeƒBƒŠƒXƒg‚́ASQL‚Ì <literal>INSERT</literal> •¶‚É‚¨‚¯‚é <literal>ƒJƒ‰ƒ€‚ÌŽd—l</literal> 
+                    ‚É—ÞŽ—‚µ‚Ä‚¢‚Ü‚·B
+                    Œp³‚̃}ƒbƒsƒ“ƒO‚ÉŠÜ‚Ü‚ê‚éƒGƒ“ƒeƒBƒeƒB‚ɑ΂µ‚āA
+                    ƒNƒ‰ƒXƒŒƒxƒ‹‚Å’¼Ú’è‹`‚³‚ꂽƒvƒƒpƒeƒB‚¾‚¯‚ªAƒvƒƒpƒeƒBƒŠƒXƒg‚ÉŽg‚¦‚Ü‚·B
+                    ƒX[ƒp[ƒNƒ‰ƒX‚̃vƒƒpƒeƒB‚Í”F‚ß‚ç‚ꂸAƒTƒuƒNƒ‰ƒX‚̃vƒƒpƒeƒB‚ÍŒø‰Ê‚ª‚ ‚è‚Ü‚¹‚ñB
+                    Œ¾‚¢Š·‚¦‚é‚Æ <literal>INSERT</literal> •¶‚́A–{Ž¿“I‚Ƀ|ƒŠƒ‚[ƒtƒBƒbƒN‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+                    
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    select•¶‚Ì•Ô‚è’l‚ÌŒ^‚ªinsert•¶‚ªŠú‘Ò‚·‚éŒ^‚ƃ}ƒbƒ`‚µ‚Ä‚¢‚ê‚΁A
+                    ‚»‚Ìselect•¶‚͑Ó–‚ÈHQL selectƒNƒGƒŠ‚ƂȂ肦‚Ü‚·B
+                    Œ»Ý‚±‚̃`ƒFƒbƒN‚ðƒf[ƒ^ƒx[ƒX‚Ö”C‚¹‚é‚Ì‚Å‚Í‚È‚­AƒNƒGƒŠ‚̃Rƒ“ƒpƒCƒ‹Žž‚Ƀ`ƒFƒbƒN‚µ‚Ü‚·B
+                    ‚±‚Ì‚±‚Ƃ́A<emphasis>equal</emphasis>‚Ƃ͈ႢA
+                    Hibernate‚Ì <literal>Type</literal> ŠÔ‚Ì <emphasis>equivalent</emphasis> ‚ÉŠÖ‚·‚é
+                    –â‘è‚ðˆø‚«‹N‚±‚·‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                    ‚±‚ê‚Í <literal>org.hibernate.type.DataType</literal> ‚Æ‚µ‚Ä’è‹`‚³‚ꂽƒvƒƒpƒeƒB‚ƁA
+                    <literal>org.hibernate.type.TimestampType</literal> 
+                    ‚Æ‚µ‚Ä’è‹`‚³‚ꂽƒvƒƒpƒeƒB‚̊Ԃ̃~ƒXƒ}ƒbƒ`‚Ì–â‘è‚ðˆø‚«‹N‚±‚µ‚Ü‚·B
+                    ƒf[ƒ^ƒx[ƒX‚ª‚»‚ê‚ç‚ð‹æ•Ê‚Å‚«‚È‚­‚Ä‚àA•ÏŠ·‚·‚邱‚Æ‚ª‚Å‚«‚Ä‚àA‚±‚Ì–â‘è‚Í”­¶‚µ‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    idƒvƒƒpƒeƒB‚ɑ΂µ‚āAinsert•¶‚É‚Í“ñ‚‚̑I‘ðŽˆ‚ª‚ ‚è‚Ü‚·B
+                    ƒvƒƒpƒeƒBƒŠƒXƒg‚Å–¾Ž¦“I‚ÉidƒvƒƒpƒeƒB‚ðŽw’è‚·‚é‚©
+                    i‚±‚̏ꍇA‘Ήž‚·‚éselectŽ®‚©‚ç’l‚ªŽæ‚ç‚ê‚Ü‚·jA
+                    ƒvƒƒpƒeƒBƒŠƒXƒg‚©‚珜ŠO‚·‚é‚©
+                    i‚±‚̏ꍇA¶¬‚³‚ê‚é’l‚ªŽg‚í‚ê‚Ü‚·j‚Ì‚¢‚¸‚ê‚©‚Å‚·B
+                    ŒãŽÒ‚Ì‘I‘ðŽˆ‚ÍAƒf[ƒ^ƒx[ƒX“à‚𑀍삷‚éidƒWƒFƒlƒŒ[ƒ^‚ðŽg‚¤‚Æ‚«‚̂݁A—˜—p‰Â”\‚Å‚·B
+                    ‚±‚Ì‘I‘ðŽˆ‚ðÌ‚éê‡AuƒCƒ“ƒƒ‚ƒŠvŒ^‚̃WƒFƒlƒŒ[ƒ^‚ðŽg‚¤‚ƁA\•¶‰ðÍŽž‚É—áŠO‚ª”­¶‚µ‚Ü‚·B
+                    ‚±‚Ì‹c˜_‚ł́AƒCƒ“ƒf[ƒ^ƒx[ƒXŒ^ƒWƒFƒlƒŒ[ƒ^‚Í <literal>org.hibernate.id.SequenceGenerator</literal> 
+                    i‚Æ‚»‚̃TƒuƒNƒ‰ƒXj‚ƁA<literal>org.hibernate.id.PostInsertIdentifierGenerator</literal> 
+                    ‚ÌŽÀ‘•‚Å‚ ‚é‚ƍl‚¦‚Ä‚¢‚Ü‚·B
+                    ‚±‚±‚ÅÅ‚à’ˆÓ‚·‚ׂ«—áŠO‚́A<literal>org.hibernate.id.TableHiLoGenerator</literal> ‚Å‚·B
+                    ’l‚ðŽæ“¾‚·‚é‘I‘ð‰Â”\‚È•û–@‚ª‚È‚¢‚½‚߁A‚±‚̃WƒFƒlƒŒ[ƒ^‚ðŽg‚¤‚±‚Æ‚Í‚Å‚«‚Ü‚¹‚ñB
+                    
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>version</literal> ‚â <literal>timestamp</literal> ‚Æ‚µ‚ă}ƒbƒsƒ“ƒO‚³‚ê‚éƒvƒƒpƒeƒB‚ɑ΂µ‚āA
+                    insert•¶‚É‚Í“ñ‚‚̑I‘ðŽˆ‚ª‚ ‚è‚Ü‚·B
+                    ƒvƒƒpƒeƒBƒŠƒXƒg‚Å–¾Ž¦“I‚ɃvƒƒpƒeƒB‚ðŽw’è‚·‚é‚©
+                    i‚±‚̏ꍇA‘Ήž‚·‚éselectŽ®‚©‚ç’l‚ªŽæ‚ç‚ê‚Ü‚·jA
+                    ƒvƒƒpƒeƒBƒŠƒXƒg‚©‚珜ŠO‚·‚é‚©
+                    i‚±‚̏ꍇA<literal>org.hibernate.type.VersionType</literal> ‚Å’è‹`‚³‚ꂽ 
+                    <literal>ƒV[ƒh’l</literal> ‚ªŽg‚í‚ê‚Ü‚·j‚Ì‚¢‚¸‚ê‚©‚Å‚·B
+                    
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            HQL‚Ì <literal>INSERT</literal> •¶‚ÌŽÀs—á‚Å‚·F
+            
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
+int createdEntities = s.createQuery( hqlInsert )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/best_practices.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/best_practices.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/best_practices.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="best-practices" revision="3">
+    <title>ƒxƒXƒgƒvƒ‰ƒNƒeƒBƒX</title>
+
+    <variablelist spacing="compact">
+        <varlistentry>
+            <term>
+            ƒNƒ‰ƒX‚ׂ͍©‚¢—±“x‚ŏ‘‚« <literal>&lt;component&gt;</literal> ‚Ń}ƒbƒsƒ“ƒO‚µ‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                    <literal>street</literal>i’Ê‚èj, <literal>suburb</literal>
+                    i“sŽsj, <literal>state</literal>iBj, <literal>postcode</literal> 
+                    i—X•Ö”ԍ†j‚ðƒJƒvƒZƒ‹‰»‚·‚é <literal>Address</literal>iZŠjƒNƒ‰ƒX‚ðŽg‚¢‚Ü‚µ‚傤B
+                    ‚»‚¤‚·‚ê‚΃R[ƒh‚ªÄ—˜—p‚µ‚â‚·‚­‚È‚èAƒŠƒtƒ@ƒNƒ^ƒŠƒ“ƒO‚àŠÈ’P‚É‚È‚è‚Ü‚·B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>
+            ‰i‘±ƒNƒ‰ƒX‚É‚ÍŽ¯•ÊŽqƒvƒƒpƒeƒB‚ð’è‹`‚µ‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                    Hibernate‚Å‚ÍŽ¯•ÊŽqƒvƒƒpƒeƒB‚̓IƒvƒVƒ‡ƒ“‚Å‚·‚ªA
+                    Žg—p‚·‚ׂ«——R‚ª‚½‚­‚³‚ñ‚ ‚è‚Ü‚·B
+                    Ž¯•ÊŽq‚́ulH“Ivi¶¬‚³‚ꂽA‹Æ–±“I‚ȈӖ¡‚ðŽ‚½‚È‚¢j
+                    ‚È‚à‚Ì‚É‚·‚邱‚Æ‚ð‚¨‚·‚·‚ß‚µ‚Ü‚·B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Ž©‘RƒL[‚ðŒ©‚Â‚¯‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                    ‚·‚ׂẴGƒ“ƒeƒBƒeƒB‚ɑ΂µ‚ÄŽ©‘RƒL[‚ðŒ©‚Â‚¯‚āA
+                    <literal>&lt;natural-id&gt;</literal> ‚Ń}ƒbƒsƒ“ƒO‚µ‚Ü‚µ‚傤B
+                    Ž©‘RƒL[‚ð\¬‚·‚éƒvƒƒpƒeƒB‚ð”äŠr‚·‚邽‚߂ɁA
+                    <literal>equals()</literal> ‚Æ <literal>hashCode()</literal> ‚ðŽÀ‘•‚µ‚Ü‚µ‚傤B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>ƒNƒ‰ƒX‚̃}ƒbƒsƒ“ƒO‚Í‚»‚ꂼ‚ê‚̃Nƒ‰ƒXê—p‚̃tƒ@ƒCƒ‹‚ɏ‘‚«‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                     ’Pˆê‚Ì‹‘å‚ȃ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚ðŽg—p‚µ‚È‚¢‚Å‚­‚¾‚³‚¢B
+                     <literal>com.eg.Foo</literal> ƒNƒ‰ƒX‚È‚ç 
+                     <literal>com/eg/Foo.hbm.xml</literal> ƒtƒ@ƒCƒ‹‚Ƀ}ƒbƒsƒ“ƒO‚µ‚Ü‚µ‚傤B
+                     ‚±‚Ì‚±‚Ƃ́A“Á‚Ƀ`[ƒ€‚Å‚ÌŠJ”­‚ɈӖ¡‚ª‚ ‚è‚Ü‚·B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>ƒŠƒ\[ƒX‚Æ‚µ‚ă}ƒbƒsƒ“ƒO‚ðƒ[ƒh‚µ‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                    ƒ}ƒbƒsƒ“ƒO‚ðA‚»‚ê‚炪ƒ}ƒbƒsƒ“ƒO‚·‚é‚·‚éƒNƒ‰ƒX‚ƈꏏ‚É”z’u‚µ‚Ü‚µ‚傤B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>ƒNƒGƒŠ•¶Žš—ñ‚ðŠO•”‚É’u‚­‚±‚Æ‚ðl‚¦‚Ü‚µ‚傤</term>
+            <listitem>
+                <para>
+                    ƒNƒGƒŠ‚ªANSI•W€‚Å‚È‚¢SQLŠÖ”‚ðŒÄ‚ñ‚Å‚¢‚é‚È‚çA‚±‚ê‚Í‚æ‚¢ƒvƒ‰ƒNƒeƒBƒX‚Å‚·B
+                    ƒNƒGƒŠ•¶Žš—ñ‚ðƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ÖŠOo‚µ‚·‚ê‚΃AƒvƒŠƒP[ƒVƒ‡ƒ“‚ªƒ|[ƒ^ƒuƒ‹‚É‚È‚è‚Ü‚·B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>ƒoƒCƒ“ƒh•Ï”‚ðŽg‚¢‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                     JDBC‚̏ꍇ‚Æ“¯‚¶‚悤‚ɁA’萔‚Å‚È‚¢’l‚Í•K‚¸"?"‚Å’u‚«Š·‚¦‚Ü‚µ‚傤B
+                     ’萔‚Å‚È‚¢’l‚ðƒoƒCƒ“ƒh‚·‚邽‚߂ɁAƒNƒGƒŠ‚Å•¶Žš—ñ‘€ì‚ðŽg‚Á‚Ä‚Í‚¢‚¯‚Ü‚¹‚ñB
+                     –¼‘O•t‚«‚̃pƒ‰ƒ[ƒ^‚ðŽg‚¤‚悤‚É‚·‚é‚Æ‚³‚ç‚É—Ç‚¢‚Å‚·B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>JDBCƒRƒlƒNƒVƒ‡ƒ“‚ðŠÇ—‚µ‚Ä‚Í‚¢‚¯‚Ü‚¹‚ñB</term>
+            <listitem>
+                <para>
+                    Hibernate‚ł̓AƒvƒŠƒP[ƒVƒ‡ƒ“‚ªJDBCƒRƒlƒNƒVƒ‡ƒ“‚ðŠÇ—‚·‚邱‚Æ‚ª‹–‚³‚ê‚Ä‚¢‚Ü‚·B
+                    ‚µ‚©‚µ‚±‚ê‚͍ŏIŽè’i‚¾‚ÆŽv‚Á‚Ä‚­‚¾‚³‚¢B
+                    ‘g‚ݍž‚݂̃RƒlƒNƒVƒ‡ƒ“ƒvƒƒoƒCƒ_‚ðŽg‚¤‚±‚Æ‚ª‚Å‚«‚È‚¯‚ê‚΁A
+                    <literal>org.hibernate.connection.ConnectionProvider</literal> ‚ðŽÀ‘•‚·‚邱‚Æ‚ðl‚¦‚Ä‚­‚¾‚³‚¢B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>ƒJƒXƒ^ƒ€Œ^‚ÌŽg—p‚ðl‚¦‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                    ‚ ‚郉ƒCƒuƒ‰ƒŠ‚©‚玝‚Á‚Ä‚«‚½JavaŒ^‚ð‰i‘±‰»‚·‚é•K—v‚ª‚ ‚é‚Æ‚µ‚Ü‚µ‚傤B
+                    ‚µ‚©‚µ‚»‚ÌŒ^‚ɂ́AƒRƒ“ƒ|[ƒlƒ“ƒg‚Æ‚µ‚ă}ƒbƒsƒ“ƒO‚·‚邽‚ß‚É•K—v‚ȃAƒNƒZƒT‚ª‚È‚¢‚Æ‚µ‚Ü‚·B
+                    ‚±‚̂悤‚ȏꍇ‚Í <literal>org.hibernate.UserType</literal> ‚ÌŽÀ‘•‚ðl‚¦‚é‚ׂ«‚Å‚·B
+                    ‚»‚¤‚·‚ê‚ÎHibernateŒ^‚Æ‚ÌŽÀ‘••ÏŠ·‚ðS”z‚¹‚¸‚ɃAƒvƒŠƒP[ƒVƒ‡ƒ“‚̃R[ƒh‚ðˆµ‚¦‚Ü‚·B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>ƒ{ƒgƒ‹ƒlƒbƒN‚ð‰ðÁ‚·‚é‚É‚ÍJDBC‚ðƒnƒ“ƒhƒR[ƒh‚µ‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                    ƒVƒXƒeƒ€‚̃pƒtƒH[ƒ}ƒ“ƒXƒNƒŠƒeƒBƒJƒ‹‚ȗ̈æ‚ł́A
+                    ‚ ‚éŽí‚Ì‘€ì‚ÉJDBC‚𒼐ڎg‚¤‚Æ—Ç‚¢‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                    ‚µ‚©‚µ‰½‚ªƒ{ƒgƒ‹ƒlƒbƒN‚É‚È‚Á‚Ä‚¢‚é‚© <emphasis>‚Í‚Á‚«‚è‚·‚é</emphasis> ‚Ü‚Å‚Í‘Ò‚Á‚Ä‚­‚¾‚³‚¢B
+                    ‚Ü‚½JDBC‚𒼐ڎg‚¤‚©‚ç‚Æ‚¢‚Á‚āA•K‚¸‚µ‚à‘¬‚­‚È‚é‚Æ‚ÍŒÀ‚ç‚È‚¢‚±‚Æ‚à—‰ð‚µ‚Ä‚­‚¾‚³‚¢B
+                    JDBC‚𒼐ڎg‚¤•K—v‚ª‚ ‚ê‚΁AHibernate‚Ì <literal>Session</literal> ‚ðƒI[ƒvƒ“‚µ‚āA
+                    JDBCƒRƒlƒNƒVƒ‡ƒ“‚ðŽg‚¤‚Æ—Ç‚¢‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                    ˆË‘R‚Æ‚µ‚Ä“¯‚¶ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“í—ª‚ƃRƒlƒNƒVƒ‡ƒ“ƒvƒƒoƒCƒ_‚ªŽg‚¦‚é‚©‚ç‚Å‚·B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term><literal>Session</literal> ‚̃tƒ‰ƒbƒVƒ…‚ð—‰ð‚µ‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                    Session‚ª‰i‘±ó‘Ô‚ðƒf[ƒ^ƒx[ƒX‚Æ“¯Šú‚³‚¹‚邱‚Æ‚ª‚Æ‚«‚Ç‚«‚ ‚è‚Ü‚·B
+                    ‚µ‚©‚µ‚±‚ꂪ‚ ‚Ü‚è‚É•p”É‚É‹N‚±‚é‚悤‚¾‚ƁAƒpƒtƒH[ƒ}ƒ“ƒX‚ɉe‹¿‚ªo‚Ä‚«‚Ü‚·B
+                    Ž©“®ƒtƒ‰ƒbƒVƒ…‚𖳌ø‚É‚µ‚½‚èA“Á’è‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̃NƒGƒŠ‚â‘€ì‚̏‡”Ô‚ð•ÏX‚·‚邱‚ƂŁA
+                    •s•K—v‚ȃtƒ‰ƒbƒVƒ…‚ðÅ¬ŒÀ‚É‚Å‚«‚Ü‚·B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>3‘wƒA[ƒLƒeƒNƒ`ƒƒ‚Å‚Í•ª—£ƒIƒuƒWƒFƒNƒg‚ÌŽg—p‚ðl‚¦‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                    ƒT[ƒuƒŒƒbƒg / ƒZƒbƒVƒ‡ƒ“ƒr[ƒ“ƒA[ƒLƒeƒNƒ`ƒƒ‚ðŽg‚¤‚Æ‚«A
+                    ƒT[ƒuƒŒƒbƒg‘w / JSP‘wŠÔ‚ŃZƒbƒVƒ‡ƒ“ƒr[ƒ“‚э[ƒh‚µ‚½‰i‘±ƒIƒuƒWƒFƒNƒg‚ð‚â‚èŽæ‚è‚Å‚«‚Ü‚·B
+                    ‚»‚̍ۃŠƒNƒGƒXƒg‚²‚ƂɐV‚µ‚¢Session‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢B
+                    ‚Ü‚½ <literal>Session.merge()</literal> ‚â <literal>Session.saveOrUpdate()</literal> 
+                    ‚ðŽg‚Á‚āAƒIƒuƒWƒFƒNƒg‚ƃf[ƒ^ƒx[ƒX‚𓯊ú‚³‚¹‚Ä‚­‚¾‚³‚¢B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>2‘wƒA[ƒLƒeƒNƒ`ƒƒ‚Å‚Í’·‚¢‰i‘±ƒRƒ“ƒeƒLƒXƒg‚ÌŽg—p‚ðl‚¦‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                    Å‚‚̃XƒP[ƒ‰ƒrƒŠƒeƒB‚𓾂é‚ɂ́A
+                    ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ð‚Å‚«‚邾‚¯’Z‚­‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                    ‚µ‚©‚µ’·‚¢ŠÔŽÀs‚·‚é <emphasis>ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“</emphasis> 
+                    ‚ÌŽÀ‘•‚ª•K—v‚È‚±‚Æ‚Í‚µ‚΂µ‚΂ł·B
+                    ‚±‚ê‚̓†[ƒU‚ÌŽ‹“_‚©‚ç‚Í1ŒÂ‚̍ì‹Æ’PˆÊiunit of workj‚É‚È‚è‚Ü‚·B
+                    ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Í‚¢‚­‚‚©‚̃Nƒ‰ƒCƒAƒ“ƒg‚̃ŠƒNƒGƒXƒg/ƒŒƒXƒ|ƒ“ƒXƒTƒCƒNƒ‹‚É‚Ü‚½‚ª‚è‚Ü‚·B
+                    ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÌŽÀ‘•‚É•ª—£ƒIƒuƒWƒFƒNƒg‚ðŽg‚¤‚͈̂ê”Ê“I‚Å‚·B
+                    
+                    ‚»‚¤‚Å‚È‚¯‚ê‚΁A2‘wƒA[ƒLƒeƒNƒ`ƒƒ‚̏ꍇ‚Í“Á‚É“KØ‚È‚±‚Æ‚Å‚·‚ªA
+                    ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̃‰ƒCƒtƒTƒCƒNƒ‹‘S‘̂ɑ΂µ‚Ä
+                    ’Pˆê‚̃I[ƒvƒ“‚ȉi‘±‰»ƒRƒ“ƒeƒLƒXƒgiƒZƒbƒVƒ‡ƒ“j‚ðˆÛŽ‚µ‚Ä‚­‚¾‚³‚¢B
+                    ‚»‚µ‚Ä’Pƒ‚ɃŠƒNƒGƒXƒg‚̍Ōã‚ÉJDBCƒRƒlƒNƒVƒ‡ƒ“‚©‚çØ’f‚µA
+                    ŽŸ‚̃ŠƒNƒGƒXƒg‚̍ŏ‰‚ɍĐڑ±‚µ‚Ü‚·B
+                    
+                    Œˆ‚µ‚Ä•¡”‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ƒ†[ƒXƒP[ƒX‚É“n‚Á‚Ä
+                    1ŒÂ‚ÌSession‚ðŽg‚¢‰ñ‚³‚È‚¢‚Å‚­‚¾‚³‚¢B
+                    ‚»‚¤‚Å‚È‚¯‚ê‚΁AŒÃ‚¢ƒf[ƒ^‚ōì‹Æ‚·‚邱‚Æ‚É‚È‚è‚Ü‚·B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>—áŠO‚𕜋A‰Â”\‚È‚à‚Ì‚Æ‚µ‚Ĉµ‚Á‚Ä‚Í‚¢‚¯‚Ü‚¹‚ñB</term>
+            <listitem>
+                <para>
+                    ‚±‚ê‚́uƒxƒXƒgvƒvƒ‰ƒNƒeƒBƒXˆÈã‚́A•K{‚̃vƒ‰ƒNƒeƒBƒX‚Å‚·B
+                    —áŠO‚ª”­¶‚µ‚½‚Æ‚«‚Í <literal>Transaction</literal> ‚ðƒ[ƒ‹ƒoƒbƒN‚µ‚āA
+                    <literal>Session</literal> ‚ðƒNƒ[ƒY‚µ‚Ä‚­‚¾‚³‚¢B
+                    ‚»‚¤‚µ‚È‚¢‚ÆHibernate‚̓ƒ‚ƒŠ‚̏ó‘Ô‚ª‰i‘±ó‘Ԃ𐳊m‚É•\Œ»‚µ‚Ä‚¢‚邱‚Æ‚ð•ÛØ‚Å‚«‚Ü‚¹‚ñB
+                    ‚±‚Ì“Á•Ê‚ȏꍇ‚Æ‚µ‚āA—^‚¦‚ç‚ꂽŽ¯•ÊŽq‚ðŽ‚ÂƒCƒ“ƒXƒ^ƒ“ƒX‚ªƒf[ƒ^ƒx[ƒX‚É‘¶Ý‚·‚é‚©‚Ç‚¤‚©‚ð”»’è‚·‚邽‚߂ɁA
+                    <literal>Session.load()</literal> ‚ðŽg‚¤‚±‚Æ‚Í‚â‚ß‚Ä‚­‚¾‚³‚¢B
+                    ‚»‚Ì‘ã‚í‚è‚É <literal>Session.get()</literal> ‚©ƒNƒGƒŠ‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>ŠÖ˜A‚É‚Í‚È‚é‚ׂ­’x‰„ƒtƒFƒbƒ`‚ðŽg‚¢‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                    ‘¦ŽžƒtƒFƒbƒ`‚͍T‚¦‚ß‚É‚µ‚Ü‚µ‚傤B
+                    “ñŽŸƒLƒƒƒbƒVƒ…‚É‚ÍŠ®‘S‚É•ÛŽ‚³‚ê‚È‚¢‚悤‚ȃNƒ‰ƒX‚ÌŠÖ˜A‚ɂ́A
+                    ƒvƒƒLƒV‚Æ’x‰„ƒRƒŒƒNƒVƒ‡ƒ“‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢B
+                    ƒLƒƒƒbƒVƒ…‚³‚ê‚éƒNƒ‰ƒX‚ÌŠÖ˜AA‚‚܂èƒLƒƒƒbƒVƒ…‚ªƒqƒbƒg‚·‚é‰Â”\«‚ª”ñí‚ɍ‚‚¢ŠÖ˜A‚́A
+                    <literal>lazy="false"</literal> ‚ŐϋɓI‚ȃtƒFƒbƒ`‚𖾎¦“I‚É–³Œø‚É‚µ‚Ä‚­‚¾‚³‚¢B
+                    Œ‹‡ƒtƒFƒbƒ`‚ª“KØ‚È“Á’è‚̃†[ƒXƒP[ƒX‚ɂ́A
+                    ƒNƒGƒŠ‚Å <literal>left join fetch</literal> ‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>
+                ƒtƒFƒbƒ`‚³‚ê‚Ä‚¢‚È‚¢ƒf[ƒ^‚ÉŠÖ‚í‚é–â‘è‚ð”ð‚¯‚é‚½‚߂ɁA
+                <emphasis>ƒrƒ…[‚Ì’†‚ŃI[ƒvƒ“ƒZƒbƒVƒ‡ƒ“‚ðŽg‚¤(open session in view)</emphasis> 
+                ƒpƒ^[ƒ“‚©A“§‚³‚ꂽ <emphasis>‘g‚Ý—§‚ătƒF[ƒY(assembly phase)</emphasis> ‚ðŽg‚¢‚Ü‚µ‚傤B
+            </term>
+            <listitem>
+                <para>
+                    Hibernate‚Í <emphasis>Data Transfer Objects</emphasis> (DTO)‚ð‘‚­‘Þ‹ü‚ȍì‹Æ‚©‚çŠJ”­ŽÒ‚ð‰ð•ú‚µ‚Ü‚·B
+                    “`““I‚ÈEJBƒA[ƒLƒeƒNƒ`ƒƒ‚Å‚ÍDTO‚Í“ñ‚–ړI‚ª‚ ‚è‚Ü‚·F
+                    1‚–ڂ́AƒGƒ“ƒeƒBƒeƒBƒr[ƒ“‚ªƒVƒŠƒAƒ‰ƒCƒY‚³‚ê‚È‚¢–â‘è‚ւ̑΍ô‚Å‚·B
+                    2‚–ڂ́AƒvƒŒƒ[ƒ“ƒe[ƒVƒ‡ƒ“‘w‚ɐ§Œä‚ª–ß‚é‘O‚ɁA
+                    ƒrƒ…[‚ÉŽg‚í‚ê‚é‚·‚ׂẴf[ƒ^‚ªƒtƒFƒbƒ`‚³‚ê‚āADTO‚É•œŒ³‚³‚ê‚é‚悤‚È‘g‚Ý—§‚ătƒF[ƒY‚ðˆÃ–Ù“I‚É’è‹`‚µ‚Ü‚·B
+                    Hibernate‚Å‚Í1‚–ڂ̖ړI‚ª•s—v‚É‚È‚è‚Ü‚·B
+                    ‚µ‚©‚µƒrƒ…[‚̃Œƒ“ƒ_ƒŠƒ“ƒOˆ—‚̊ԁA‰i‘±ƒRƒ“ƒeƒLƒXƒgiƒZƒbƒVƒ‡ƒ“j‚ðƒI[ƒvƒ“‚É‚µ‚½‚Ü‚Ü‚É‚µ‚È‚¯‚ê‚΁A
+                    ‘g‚Ý—§‚ătƒF[ƒY‚Í‚Ü‚¾•K—v‚Å‚·i•ª—£ƒIƒuƒWƒFƒNƒg‚Ì’†‚̂ǂ̃f[ƒ^‚ª—˜—p‰Â”\‚©‚ɂ‚¢‚āA
+                    ƒvƒŒƒ[ƒ“ƒe[ƒVƒ‡ƒ“‘w‚ÆŒµ–§‚ÈŽæ‚茈‚ß‚ð‚µ‚Ä‚¢‚éƒrƒWƒlƒXƒƒ\ƒbƒh‚ðl‚¦‚Ä‚Ý‚Ä‚­‚¾‚³‚¢jB
+                    ‚±‚ê‚ÍHibernate‘¤‚Ì–â‘è‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+                    ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ““à‚ňÀ‘S‚Ƀf[ƒ^ƒAƒNƒZƒX‚·‚邽‚ß‚ÌŠî–{“I‚È—vŒ‚Å‚·B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Hibernate‚©‚çƒrƒWƒlƒXƒƒWƒbƒN‚𒊏ۉ»‚·‚邱‚Æ‚ðl‚¦‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                    ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ŁiHibernate‚́jƒf[ƒ^ƒAƒNƒZƒXƒR[ƒh‚ð‰B•Á‚µ‚Ü‚µ‚傤B
+                    <emphasis>DAO</emphasis> ‚Æ <emphasis>Thread Local Session</emphasis> ƒpƒ^[ƒ“‚ð‘g‚ݍ‡‚킹‚Ü‚µ‚傤B
+                    <literal>UserType</literal> ‚ÅHibernate‚ÉŠÖ˜A•t‚¯‚é‚ƁA
+                    ƒnƒ“ƒhƒR[ƒh‚µ‚½JDBC‚ʼni‘±‰»‚·‚éƒNƒ‰ƒX‚ðŽ‚Â‚±‚Æ‚à‚Å‚«‚Ü‚·B
+                    i‚±‚̃AƒhƒoƒCƒX‚́u\•ª‘å‚«‚ȁvƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ɑ΂µ‚Ä‚Ì‚à‚Ì‚Å‚·B
+                    ƒe[ƒuƒ‹‚ª5ŒÂ‚µ‚©‚È‚¢‚悤‚ȃAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚Í“–‚Ä‚Í‚Ü‚è‚Ü‚¹‚ñBj
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>’¿‚µ‚¢ŠÖ˜Aƒ}ƒbƒsƒ“ƒO‚ÍŽg‚í‚È‚¢‚悤‚É‚µ‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                    ‚æ‚¢ƒ†[ƒXƒP[ƒX‚É–{“–‚Ì‘½‘Α½ŠÖ˜A‚ª‚ ‚邱‚Æ‚Í‹Hi‚Ü‚êj‚Å‚·B
+                    ‚Ù‚Æ‚ñ‚ǂ̏ꍇuƒŠƒ“ƒNƒe[ƒuƒ‹v‚Ì•t‰Á“I‚ȏî•ñ‚ª•K—v‚É‚È‚è‚Ü‚·B
+                    ‚±‚̏ꍇAƒŠƒ“ƒNƒNƒ‰ƒX‚É2‚‚Ì1‘Α½ŠÖ˜A‚ðŽg‚¤•û‚ª‚¸‚Á‚Æ—Ç‚¢‚Å‚·B
+                    ŽÀÛ‚Ù‚Æ‚ñ‚ǂ̏ꍇŠÖ˜A‚Í1‘Α½‚Æ‘½‘Î1‚Ȃ̂ŁA
+                    ‘¼‚̃Xƒ^ƒCƒ‹‚ÌŠÖ˜A‚ðŽg‚¤‚Æ‚«‚Í–{“–‚É•K—v‚©‚Ç‚¤‚©‚ðl‚¦‚Ä‚Ý‚Ä‚­‚¾‚³‚¢B
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>‚È‚é‚ׂ­‘o•ûŒüŠÖ˜A‚É‚µ‚Ü‚µ‚傤B</term>
+            <listitem>
+                <para>
+                    ’P•ûŒüŠÖ˜A‚Í‘o•ûŒü‚É”ä‚ׂČŸõ‚ª“‚­‚È‚è‚Ü‚·B
+                    ‘å‚«‚ȃAƒvƒŠƒP[ƒVƒ‡ƒ“‚ł́A
+                    ‚Ù‚Æ‚ñ‚Ç‚·‚ׂĂ̊֘A‚ª‘o•ûŒü‚ɃiƒrƒQ[ƒVƒ‡ƒ“‚Å‚«‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                </para>
+            </listitem>
+        </varlistentry>
+    </variablelist>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/collection_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/collection_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/collection_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1226 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="collections">
+    <title>ƒRƒŒƒNƒVƒ‡ƒ“‚̃}ƒbƒsƒ“ƒO</title>
+
+    <sect1 id="collections-persistent" revision="3">
+        <title>ƒRƒŒƒNƒVƒ‡ƒ“‚̉i‘±‰»</title>
+        
+        <para>
+            ƒRƒŒƒNƒVƒ‡ƒ“Œ^‚̃tƒB[ƒ‹ƒh‚ð‰i‘±‰»‚·‚é‚ɂ́A
+            ‚»‚̃RƒŒƒNƒVƒ‡ƒ“Œ^‚ªƒCƒ“ƒ^[ƒtƒFƒCƒXŒ^‚Å‚ ‚é•K—v‚ª‚ ‚è‚Ü‚·B
+            —Ⴆ‚΁A
+        </para>
+        
+        <programlisting><![CDATA[public class Product {
+    private String serialNumber;
+    private Set parts = new HashSet();
+    
+    public Set getParts() { return parts; }
+    void setParts(Set parts) { this.parts = parts; }
+    public String getSerialNumber() { return serialNumber; }
+    void setSerialNumber(String sn) { serialNumber = sn; }
+}]]></programlisting>
+        
+        <para>
+            ŽÀÝ‚·‚éƒCƒ“ƒ^[ƒtƒFƒCƒX‚É‚Í <literal>java.util.Set</literal>A
+            <literal>java.util.Collection</literal>A<literal>java.util.List</literal>A
+            <literal>java.util.Map</literal>A<literal>java.util.SortedSet</literal>A
+            <literal>java.util.SortedMap</literal> ‚È‚Ç‚ª‚ ‚è‚Ü‚·B
+            ‚Ü‚½‚́A”CˆÓ‚̃Cƒ“ƒ^[ƒtƒFƒCƒX‚ªŽg‚¦‚Ü‚·I
+            i‚½‚¾‚µA”CˆÓ‚̃Cƒ“ƒ^[ƒtƒFƒCƒX‚ðŽg—p‚·‚éê‡‚́A
+            <literal>org.hibernate.usertype.UserCollectionType</literal>
+            ‚ÌŽÀ‘•ƒNƒ‰ƒX‚ðì¬‚·‚é•K—v‚ª‚ ‚è‚Ü‚·Bj
+        </para>
+        
+        <para>
+            <literal>HashSet</literal> ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ðŽ‚ÂƒCƒ“ƒXƒ^ƒ“ƒX•Ï”‚ª
+            ‚ǂ̂悤‚ɏ‰Šú‰»‚³‚ê‚é‚©‚É’–Ú‚µ‚Ä‚Ý‚Ü‚µ‚傤B
+            ‚±‚ê‚͐V‚½‚ɐ¶¬‚³‚ꂽi‰i‘±‰»‚³‚ê‚Ä‚¢‚È‚¢jƒRƒŒƒNƒVƒ‡ƒ“Œ^‚̃vƒƒpƒeƒB‚ð
+            ‰Šú‰»‚·‚éÅ“K‚È•û–@‚Å‚·B
+            i—Ⴆ‚Î <literal>persist()</literal> ‚É‚æ‚èjƒCƒ“ƒXƒ^ƒ“ƒX‚ð‰i‘±‰»‚µ‚悤‚Æ‚µ‚½‚Æ‚«A
+            Hibernate‚Í <literal>HashSet</literal> ‚ðHibernate“ÆŽ©‚Ì <literal>Set</literal>
+            ‚ÌŽÀ‘•ƒNƒ‰ƒX‚É’u‚«Š·‚¦‚Ü‚·B
+            ‚±‚Ì‚½‚߁AŽŸ‚̂悤‚ȃGƒ‰[‚É‚Í’ˆÓ‚ª•K—v‚Å‚·B
+        </para>
+        
+        <programlisting><![CDATA[Cat cat = new DomesticCat();
+Cat kitten = new DomesticCat();
+....
+Set kittens = new HashSet();
+kittens.add(kitten);
+cat.setKittens(kittens);
+session.persist(cat);
+kittens = cat.getKittens(); // Okay, kittens collection is a Set
+(HashSet) cat.getKittens(); // Error!]]></programlisting>
+
+        <para>
+            Hibernate‚É‚æ‚蒍“ü‚³‚ꂽ‰i‘±«ƒRƒŒƒNƒVƒ‡ƒ“‚́AƒCƒ“ƒ^[ƒtƒFƒCƒXŒ^‚ɉž‚¶‚āA
+            <literal>HashMap</literal> ‚â <literal>HashSet</literal>A
+            <literal>TreeMap</literal>A <literal>TreeSet</literal>A
+            <literal>ArrayList</literal> ‚̂悤‚ɐU•‘‚¢‚Ü‚·B
+         </para>
+
+        <para>
+            ƒRƒŒƒNƒVƒ‡ƒ“ƒCƒ“ƒXƒ^ƒ“ƒX‚́A’lŒ^‚Æ‚µ‚Ä•’ʂɐU•‘‚¢‚Ü‚·B
+            ‰i‘±‰»ƒIƒuƒWƒFƒNƒg‚ÉŽQÆ‚³‚ꂽ‚Æ‚«‚ÉŽ©“®“I‚ɉi‘±‰»‚³‚êA
+            ŽQÆ‚ª‚È‚­‚È‚Á‚½‚Æ‚«‚ÉŽ©“®“I‚ɍ폜‚³‚ê‚Ü‚·B
+            ‚à‚µ‚ ‚é‰i‘±‰»ƒIƒuƒWƒFƒNƒg‚©‚ç•Ê‚̉i‘±‰»ƒIƒuƒWƒFƒNƒg‚É“n‚³‚ꂽ‚çA
+            ‚»‚Ì—v‘f‚ÍŒ»Ý‚̃e[ƒuƒ‹‚©‚ç•Ê‚̃e[ƒuƒ‹‚Ɉړ®‚·‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+            ‚Q‚‚̃Gƒ“ƒeƒBƒeƒB‚ª“¯‚¶ƒRƒŒƒNƒVƒ‡ƒ“ƒCƒ“ƒXƒ^ƒ“ƒX‚ð‹¤—L‚µ‚Ä‚Í‚¢‚¯‚Ü‚¹‚ñB
+            ƒŠƒŒ[ƒVƒ‡ƒiƒ‹ƒ‚ƒfƒ‹‚ðƒx[ƒX‚É‚µ‚Ä‚¢‚邽‚߁AƒRƒŒƒNƒVƒ‡ƒ“Œ^‚̃vƒƒpƒeƒB‚É
+            null’l‚ð‘ã“ü‚µ‚Ä‚àˆÓ–¡‚ª‚ ‚è‚Ü‚¹‚ñB
+            ‚‚܂èHibernate‚ÍŽQÆæ‚Ì‚È‚¢ƒRƒŒƒNƒVƒ‡ƒ“‚Æ‹ó‚̃RƒŒƒNƒVƒ‡ƒ“‚ð‹æ•Ê‚µ‚Ü‚¹‚ñB
+        </para>
+
+        <para>
+            ‚µ‚©‚µ‚»‚ê‚قǐS”z‚µ‚È‚­‚Ä‚à\‚¢‚Ü‚¹‚ñB
+            •’iŽg‚Á‚Ä‚¢‚éJava‚̃RƒŒƒNƒVƒ‡ƒ“‚Æ“¯‚¶‚悤‚ɁA‰i‘±‰»ƒRƒŒƒNƒVƒ‡ƒ“‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢B
+            ‘o•ûŒüŠÖ˜A‚̈Ӗ¡‚ð—‰ð‚·‚ê‚΂悢‚Ì‚Å‚·i‚±‚ê‚ÍŒã‚Ù‚Çà–¾‚µ‚Ü‚·jB
+        </para>
+
+    </sect1>
+
+    <sect1 id="collections-mapping" revision="4">
+        <title>ƒRƒŒƒNƒVƒ‡ƒ“‚̃}ƒbƒsƒ“ƒO</title>
+
+        <para>
+            ƒRƒŒƒNƒVƒ‡ƒ“‚ðƒ}ƒbƒsƒ“ƒO‚·‚邽‚߂̃}ƒbƒsƒ“ƒO—v‘f‚́AƒCƒ“ƒ^[ƒtƒFƒCƒX‚ÌŒ^‚Ɉˑ¶‚µ‚Ü‚·B
+            —Ⴆ‚΁A<literal>&lt;set&gt;</literal> —v‘f‚Í <literal>Set</literal> Œ^‚ð
+            ƒ}ƒbƒsƒ“ƒO‚·‚邽‚ß‚ÉŽg‚¢‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[<class name="Product">
+    <id name="serialNumber" column="productSerialNumber"/>
+    <set name="parts">
+        <key column="productSerialNumber" not-null="true"/>
+        <one-to-many class="Part"/>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            ƒ}ƒbƒsƒ“ƒO—v‘f‚É‚Í <literal>&lt;set&gt;</literal> ‚Ì‘¼‚É <literal>&lt;list&gt;</literal>A
+            <literal>&lt;map&gt;</literal>A<literal>&lt;bag&gt;</literal>A
+            <literal>&lt;array&gt;</literal>A<literal>&lt;primitive-array&gt;</literal> ‚ª‚ ‚è‚Ü‚·B
+            ‘ã•\‚Æ‚µ‚āA<literal>&lt;map&gt;</literal> —v‘f‚ð‰º‹L‚ÉŽ¦‚µ‚Ü‚·B
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="mappingcollection1" coords="2 65"/>
+                <area id="mappingcollection2" coords="3 65"/>
+                <area id="mappingcollection3" coords="4 65"/>
+                <area id="mappingcollection4" coords="5 65"/>
+                <area id="mappingcollection5" coords="6 65"/>
+                <area id="mappingcollection6" coords="7 65"/>
+                <area id="mappingcollection7" coords="8 65"/>
+                <area id="mappingcollection8" coords="9 65"/>
+                <area id="mappingcollection9" coords="10 65"/>
+                <area id="mappingcollection10" coords="11 65"/>
+                <area id="mappingcollection11" coords="12 65"/>
+                <area id="mappingcollection12" coords="13 65"/>
+                <area id="mappingcollection13" coords="14 65"/>
+                <area id="mappingcollection14" coords="15 65"/>
+            </areaspec>
+            <programlisting><![CDATA[<map
+    name="propertyName"
+    table="table_name"
+    schema="schema_name"
+    lazy="true|extra|false"
+    inverse="true|false"
+    cascade="all|none|save-update|delete|all-delete-orphan|delete-orphan"
+    sort="unsorted|natural|comparatorClass"
+    order-by="column_name asc|desc"
+    where="arbitrary sql where condition"
+    fetch="join|select|subselect"
+    batch-size="N"
+    access="field|property|ClassName"
+    optimistic-lock="true|false"
+    mutable="true|false"
+    node="element-name|."
+    embed-xml="true|false"
+>
+
+    <key .... />
+    <map-key .... />
+    <element .... />
+</map>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="mappingcollection1">
+                    <para>
+                        <literal>name</literal> ƒRƒŒƒNƒVƒ‡ƒ“Œ^‚Å‚ ‚éƒvƒƒpƒeƒB‚Ì–¼‘O
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection2">
+                    <para>
+                        <literal>table</literal> iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚̓vƒƒpƒeƒB–¼jƒRƒŒƒNƒVƒ‡ƒ“ƒe[ƒuƒ‹‚Ì–¼‘O
+                       iˆê‘Α½ŠÖ˜A‚Å‚ÍŽg—p‚µ‚Ü‚¹‚ñjB
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection3">
+                    <para>
+                        <literal>schema</literal> iƒIƒvƒVƒ‡ƒ“jƒe[ƒuƒ‹ƒXƒL[ƒ}‚Ì–¼‘OB
+                        ƒ‹[ƒg—v‘f‚Ő錾‚³‚ê‚Ä‚¢‚éƒXƒL[ƒ}‚æ‚è—Dæ‚³‚ê‚Ü‚·B
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection4">
+                    <para>
+                        <literal>lazy</literal> iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal>j
+                        ’x‰„ƒtƒFƒbƒ`‚𖳌ø‚É‚µAŠÖ˜A‚ðí‚É‘¦Žž‚ɃtƒFƒbƒ`‚É‚·‚邽‚ß‚ÉŽg—p‚µ‚Ü‚·B
+                        ‚Ü‚½‚́Auextra-lazyvƒtƒFƒbƒ`‚ð—LŒø‚É‚·‚邽‚ß‚ÉŽg—p‚µ‚Ü‚·B
+                        uextra-lazyvƒtƒFƒbƒ`‚́A‚Ù‚Æ‚ñ‚Ç‚Ì‘€ì‚ł̓RƒŒƒNƒVƒ‡ƒ“‚ð‰Šú‰»‚µ‚Ü‚¹‚ñ
+                        i”ñí‚É‘å‚«‚ȃRƒŒƒNƒVƒ‡ƒ“‚É“K‚µ‚Ä‚¢‚Ü‚·jB
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection5">
+                    <para>
+                        <literal>inverse</literal> iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>false</literal>j
+                        ‚±‚̃RƒŒƒNƒVƒ‡ƒ“‚ª‘o•ûŒüŠÖ˜A‚́u‹tv‘¤‚Å‚ ‚é‚ƃ}[ƒN‚µ‚Ü‚·B
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection6">
+                    <para>
+                        <literal>cascade</literal> iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>none</literal>j
+                        ŽqƒGƒ“ƒeƒBƒeƒB‚ւ̃JƒXƒP[ƒh‘€ì‚ð—LŒø‚É‚µ‚Ü‚·B
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection7">
+                    <para>
+                        <literal>sort</literal> iƒIƒvƒVƒ‡ƒ“jƒRƒŒƒNƒVƒ‡ƒ“‚ðŽ©‘R‚ȏ‡˜‚Ń\[ƒg‚·‚éê‡‚Í
+                        <literal>natural</literal> ‚ðŽw’肵‚Ü‚·B
+                        ‚ ‚é‚¢‚ÍComparatorƒNƒ‰ƒX‚ðŽw’肵‚Ü‚·B
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection8">
+                    <para>
+                        <literal>order-by</literal> iƒIƒvƒVƒ‡ƒ“AJDK1.4‚̂݁j
+                        <literal>Map</literal>A<literal>Set</literal>Abag‚̃CƒeƒŒ[ƒVƒ‡ƒ“‡˜‚ð’è‹`‚·‚é
+                        ƒe[ƒuƒ‹ƒJƒ‰ƒ€‚ðŽw’è‚·‚é‚Æ‹¤‚ɁA
+                        ƒIƒvƒVƒ‡ƒ“‚Æ‚µ‚Ä <literal>asc</literal>A<literal>desc</literal> ‚ðŽw’肵‚Ü‚·B
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection9">
+                    <para>
+                        <literal>where</literal> iƒIƒvƒVƒ‡ƒ“jƒRƒŒƒNƒVƒ‡ƒ“‚ÌŒŸõ‚âíœ‚̍ۂɎg‚¤
+                        ”CˆÓ‚ÌSQL‚Ì<literal>WHERE</literal> ðŒ‚ðŽw’肵‚Ü‚·
+                        i—˜—p‰Â”\‚ȃf[ƒ^‚̈ꕔ•ª‚¾‚¯‚ðƒRƒŒƒNƒVƒ‡ƒ“‚ªŠÜ‚ނׂ«‚Æ‚«‚ɁA‚±‚ê‚Í—L—p‚Å‚·jB
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection10">
+                    <para>
+                        <literal>fetch</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>select</literal>j
+                        ŠO•”Œ‹‡‚É‚æ‚éƒtƒFƒbƒ`A‡ŽŸ‘I‘ðƒtƒFƒbƒ`isequential select fetchjA
+                        ‡ŽŸƒTƒuƒZƒŒƒNƒgƒtƒFƒbƒ`isequential subselect fetchj‚Ì‚Ç‚ê‚©‚ð‘I‘ð‚µ‚Ä‚­‚¾‚³‚¢B
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection11">
+                    <para>
+                        <literal>batch-size</literal> iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>1</literal>j
+                        ƒRƒŒƒNƒVƒ‡ƒ“‚̃Cƒ“ƒXƒ^ƒ“ƒX‚Ì’x‰„ƒtƒFƒbƒ`‚Ì‚½‚߂́uƒoƒbƒ`ƒTƒCƒYv‚ðŽw’肵‚Ü‚·B
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection12">
+                    <para>
+                        <literal>access</literal> iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>property</literal>j
+                        ƒRƒŒƒNƒVƒ‡ƒ“Œ^ƒvƒƒpƒeƒB‚Ì’l‚ɃAƒNƒZƒX‚·‚邽‚ß‚ÉŽg—p‚·‚éí—ª‚Å‚·B
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection13">
+                    <para>
+                        <literal>optimistic-lock</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal>j
+                        ƒRƒŒƒNƒVƒ‡ƒ“‚̏ó‘Ô‚ð•Ï‚¦‚邱‚Æ‚É‚æ‚Á‚āA
+                        ‚»‚̃I[ƒi[‚Å‚ ‚éƒGƒ“ƒeƒBƒeƒB‚̃o[ƒWƒ‡ƒ“‚ªƒCƒ“ƒNƒŠƒƒ“ƒg‚³‚ê‚é‚©‚ðŽw’肵‚Ü‚·B
+                        iˆê‘Α½ŠÖ˜A‚ł́A‚Ù‚Æ‚ñ‚ǂ̏ꍇ‚É‚¨‚¢‚Ä–³Œø‚ɐݒ肷‚é‚Ì‚ª‘Ó–‚Å‚·Bj
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection14">
+                    <para>
+                        <literal>mutable</literal>iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>true</literal>j
+                        <literal>false</literal> ’l‚́AƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f‚ª•ÏX‚³‚ê‚È‚¢‚±‚Æ‚ð•\‚µ‚Ü‚·
+                        i‚ ‚éê‡‚ɂ́A­‚µƒpƒtƒH[ƒ}ƒ“ƒX‚ð‚‚ß‚Ü‚·jB
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <sect2 id="collections-foreignkeys" >
+           <title>ƒRƒŒƒNƒVƒ‡ƒ“‚ÌŠO•”ƒL[</title>
+    
+            <para>
+                ƒRƒŒƒNƒVƒ‡ƒ“‚̃Cƒ“ƒXƒ^ƒ“ƒX‚́Aƒf[ƒ^ƒx[ƒX“à‚ł́A
+                ‚»‚̃RƒŒƒNƒVƒ‡ƒ“‚ðŠ—L‚·‚éƒGƒ“ƒeƒBƒeƒB‚ÌŠO•”ƒL[‚É‚æ‚Á‚ÄŽ¯•Ê‚³‚ê‚Ü‚·B
+                ‚±‚ÌŠO•”ƒL[‚̓RƒŒƒNƒVƒ‡ƒ“ƒe[ƒuƒ‹‚Ì <emphasis>ƒRƒŒƒNƒVƒ‡ƒ“ƒL[ƒJƒ‰ƒ€</emphasis> ‚ƌĂ΂ê‚Ü‚·B
+                ƒRƒŒƒNƒVƒ‡ƒ“ƒL[ƒJƒ‰ƒ€‚Í <literal>&lt;key&gt;</literal> —v‘f‚É‚æ‚èƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+            </para>
+    
+            <para>
+                ŠO•”ƒL[ƒJƒ‰ƒ€‚É‚ÍnullÝ’萧–ñ‚ª‚ ‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                ‚Ù‚Æ‚ñ‚ǂ̃RƒŒƒNƒVƒ‡ƒ“‚É“–‚Ä‚Í‚Ü‚é‚Å‚µ‚傤B
+                ’P•ûŒü‚̈ê‘Α½ŠÖ˜A‚É‚¨‚¢‚āAŠO•”ƒL[ƒJƒ‰ƒ€‚̓fƒtƒHƒ‹ƒg‚Ånull‚ð‹–‚·Ý’è‚É‚È‚Á‚Ä‚¢‚Ü‚·B
+                ‚æ‚Á‚āA<literal>not-null="true"</literal> ‚ðŽw’è‚·‚é•K—v‚ª‚ ‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+            </para>
+    
+            <programlisting><![CDATA[<key column="productSerialNumber" not-null="true"/>]]></programlisting>
+    
+            <para>
+                ŠO•”ƒL[‚̐§–ñ‚ª <literal>ON DELETE CASCADE</literal> ‚ðŽg‚¤‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+            </para>
+    
+            <programlisting><![CDATA[<key column="productSerialNumber" on-delete="cascade"/>]]></programlisting>
+            
+            <para>
+                <literal>&lt;key&gt;</literal> —v‘f‚Ì‚·‚ׂĂ̒è‹`‚ɂ‚¢‚Ä‚Í‘O‚̏͂ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+            
+        </sect2>
+        
+        <sect2 id="collections-elements" >
+            <title>ƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f</title>
+    
+            <para>
+                ƒRƒŒƒNƒVƒ‡ƒ“‚Í‘¼‚ÌHibernate‚ÌŒ^‚Ì‚Ù‚Æ‚ñ‚ǁi‚·‚ׂĂ̊î–{Œ^AƒJƒXƒ^ƒ€Œ^AƒRƒ“ƒ|[ƒlƒ“ƒgA
+                ‘¼‚̃Gƒ“ƒeƒBƒeƒB‚Ö‚ÌŽQÆj‚ðŠi”[‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+                ŽŸ‚Ì“_‚͏d—v‚ȈႢ‚É‚È‚è‚Ü‚·B
+                ƒRƒŒƒNƒVƒ‡ƒ“‚ÉŠi”[‚³‚ꂽƒIƒuƒWƒFƒNƒg‚ªu’lvƒZƒ}ƒ“ƒeƒBƒNƒX‚Æ‚µ‚Ĉµ‚í‚ê‚é‚Ì‚©
+                iƒ‰ƒCƒtƒTƒCƒNƒ‹‚̓RƒŒƒNƒVƒ‡ƒ“‚̃I[ƒi[‚ÉŠ®‘S‚Ɉˑ¶‚µ‚Ü‚·jA
+                ‚à‚µ‚­‚Í‚»‚ꎩg‚̃‰ƒCƒtƒTƒCƒNƒ‹‚ðŽ‚Á‚½•Ê‚̃Gƒ“ƒeƒBƒeƒB‚Ö‚ÌŽQÆ‚Å‚ ‚é‚©‚Ì‚©‚Æ‚¢‚¤ˆá‚¢‚Å‚·B
+                ŒãŽÒ‚́A2‚‚̃IƒuƒWƒFƒNƒgŠÔ‚́uƒŠƒ“ƒNv‚ðƒRƒŒƒNƒVƒ‡ƒ“‚É•ÛŽ‚µ‚Ä‚¢‚é‚ÆŒ©‚È‚µ‚Ä‚¢‚邾‚¯‚Å‚·B
+            </para>
+                
+            <para>
+                Ši”[‚³‚ê‚éŒ^‚Í <emphasis>ƒRƒŒƒNƒVƒ‡ƒ“—v‘fŒ^</emphasis> ‚ƌĂ΂ê‚Ü‚·B
+                ƒRƒŒƒNƒVƒ‡ƒ“—v‘f‚́A<literal>&lt;element&gt;</literal> ‚Ü‚½‚Í <literal>&lt;composite-element&gt;</literal>
+                ‚É‚æ‚èƒ}ƒbƒsƒ“ƒO‚³‚êAƒGƒ“ƒeƒBƒeƒB‚Ö‚ÌŽQÆ‚̏ꍇ‚É‚Í
+                <literal>&lt;one-to-many&gt;</literal> ‚Ü‚½‚Í <literal>&lt;many-to-many&gt;</literal>
+                ‚É‚æ‚èƒ}ƒbƒsƒ“ƒO‚³‚ê‚Ü‚·B
+                Å‰‚Ì“ñ‚‚͒l‚Æ‚µ‚Ä—v‘f‚ðƒ}ƒbƒsƒ“ƒO‚µAŽŸ‚Ì“ñ‚‚̓Gƒ“ƒeƒBƒeƒB‚ÌŠÖ˜A‚ðƒ}ƒbƒsƒ“ƒO‚·‚é‚Ì‚ÉŽg‚í‚ê‚Ü‚·B
+            </para>
+            
+        </sect2>
+        
+        <sect2 id="collections-indexed">
+            <title>ƒCƒ“ƒfƒbƒNƒX•t‚«‚̃RƒŒƒNƒVƒ‡ƒ“</title>
+    
+            <para>
+                set‚Æbag‚ðœ‚­‘S‚ẴRƒŒƒNƒVƒ‡ƒ“ƒ}ƒbƒsƒ“ƒO‚ɂ́A
+                ƒRƒŒƒNƒVƒ‡ƒ“ƒe[ƒuƒ‹‚Ì’†‚É <emphasis>ƒCƒ“ƒfƒbƒNƒX—p‚̃Jƒ‰ƒ€</emphasis> ‚ª•K—v‚Å‚·B
+                ‚»‚̃Jƒ‰ƒ€‚ɁA”z—ñ‚â <literal>List</literal> ‚̃Cƒ“ƒfƒbƒNƒXA
+                ‚à‚µ‚­‚Í <literal>Map</literal> ‚̃L[‚ðƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+                <literal>Map</literal> ‚̃Cƒ“ƒfƒbƒNƒX‚́A
+                <literal>&lt;map-key&gt;</literal> ‚É‚æ‚èƒ}ƒbƒsƒ“ƒO‚³‚ꂽŠî–{Œ^‚©A
+                <literal>&lt;map-key-many-to-many&gt;</literal> ‚É‚æ‚èƒ}ƒbƒsƒ“ƒO‚³‚ꂽƒGƒ“ƒeƒBƒeƒB‚ÌŠÖ˜A‚©A
+                ‚ ‚é‚¢‚Í <literal>&lt;composite-map-key&gt;</literal> ‚É‚æ‚èƒ}ƒbƒsƒ“ƒO‚³‚ꂽƒRƒ“ƒ|ƒWƒbƒgŒ^‚É‚È‚è‚Ü‚·B
+                ”z—ñ‚©ƒŠƒXƒg‚̃Cƒ“ƒfƒbƒNƒX‚́Aí‚É <literal>integer</literal> Œ^‚ŁA
+                <literal>&lt;list-index&gt;</literal> —v‘f‚É‚æ‚èƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+                ƒ}ƒbƒsƒ“ƒO‚³‚ꂽƒJƒ‰ƒ€‚ɂ̓V[ƒPƒ“ƒVƒƒƒ‹‚Ȑ®”‚ðŠi”[‚µ‚Ü‚·iƒfƒtƒHƒ‹ƒg‚Å‚Í0‚©‚ç”ԍ†‚ª•t‚¯‚ç‚ê‚Ü‚·jB
+            </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="index1" coords="2 45"/>
+                <area id="index2" coords="3 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<list-index 
+        column="column_name"
+        base="0|1|..."/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="index1">
+                    <para>
+                        <literal>column_name</literal>i•K{j:ƒRƒŒƒNƒVƒ‡ƒ“ƒCƒ“ƒfƒbƒNƒX‚Ì’l‚ð•ÛŽ‚·‚éƒJƒ‰ƒ€‚Ì–¼‘OB
+                    </para>
+                </callout>
+                <callout arearefs="index2">
+                    <para>
+                        <literal>base</literal>iƒIƒvƒVƒ‡ƒ“AƒfƒtƒHƒ‹ƒg‚Í <literal>0</literal>j:
+                        ƒŠƒXƒg‚à‚µ‚­‚Í”z—ñ‚̍ŏ‰‚Ì—v‘f‚ÉŠY“–‚·‚éƒCƒ“ƒfƒbƒNƒXƒJƒ‰ƒ€‚Ì’lB
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <programlistingco>
+            <areaspec>
+                <area id="mapkey1" coords="2 45"/>
+                <area id="mapkey2" coords="3 45"/>
+                <area id="mapkey3" coords="4 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<map-key 
+        column="column_name"
+        formula="any SQL expression"
+        type="type_name"
+        node="@attribute-name"
+        length="N"/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="mapkey1">
+                    <para>
+                        <literal>column</literal>iƒIƒvƒVƒ‡ƒ“j: ƒRƒŒƒNƒVƒ‡ƒ“ƒCƒ“ƒfƒbƒNƒX‚Ì’l‚ð•ÛŽ‚·‚éƒJƒ‰ƒ€‚Ì–¼‘OB
+                    </para>
+                </callout>
+                <callout arearefs="mapkey2">
+                    <para>
+                        <literal>formula</literal>iƒIƒvƒVƒ‡ƒ“j: Map‚̃L[‚ð•]‰¿‚·‚é‚Ì‚ÉŽg‚í‚ê‚éSQLŽ®B
+                    </para>
+                </callout>
+                <callout arearefs="mapkey3">
+                    <para>
+                        <literal>type</literal>i•K{j: Map‚̃L[‚ÌŒ^B
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <programlistingco>
+            <areaspec>
+                <area id="indexmanytomany1" coords="2 45"/>
+                <area id="indexmanytomany2" coords="3 45"/>
+                <area id="indexmanytomany3" coords="4 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<map-key-many-to-many
+        column="column_name"
+        formula="any SQL expression"
+        class="ClassName"
+/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="indexmanytomany1">
+                    <para>
+                        <literal>column</literal> iƒIƒvƒVƒ‡ƒ“j:
+                        ƒRƒŒƒNƒVƒ‡ƒ“ƒCƒ“ƒfƒbƒNƒX‚Ì’l‚Ì‚½‚ß‚ÌŠO•”ƒL[ƒJƒ‰ƒ€‚Ì–¼‘OB
+                    </para>
+                </callout>
+                <callout arearefs="indexmanytomany2">
+                    <para>
+                        <literal>formula</literal> iƒIƒvƒVƒ‡ƒ“j:
+                        Map‚̃L[‚Ì‚½‚ß‚ÌŠO•”ƒL[‚ð•]‰¿‚·‚邽‚ß‚ÉŽg‚¤SQLŽ®B
+                    </para>
+                </callout>
+                <callout arearefs="indexmanytomany3">
+                    <para>
+                        <literal>class</literal> i•K{j:
+                        Map‚̃L[‚Æ‚µ‚ÄŽg‚í‚ê‚éƒGƒ“ƒeƒBƒeƒBƒNƒ‰ƒXB
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+
+            <para>
+                ‚à‚µƒe[ƒuƒ‹‚ɃCƒ“ƒfƒbƒNƒXƒJƒ‰ƒ€‚ª‚È‚­‚Ä‚àAƒvƒƒpƒeƒBŒ^‚Æ‚µ‚Ä <literal>List</literal> ‚ðŽg‚¢‚½‚¯‚ê‚΁A
+                Hibernate‚Ì <emphasis>&lt;bag&gt;</emphasis> ‚Æ‚µ‚ăvƒƒpƒeƒB‚ðƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+                bag‚̓f[ƒ^ƒx[ƒX‚©‚ç•œŒ³‚³‚ê‚鎞A‡˜‚ð•ÛŽ‚µ‚Ü‚¹‚ñB
+                ‚µ‚©‚µAiƒƒ‚ƒŠã‚Łjƒ\[ƒg‚µ‚½‚èAiSQL‚Łj‡˜•t‚¯‚µ‚½‚èiorder byj‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+            </para>
+            
+        </sect2>
+
+        <para>
+            ‘½‚­‚̈ê”Ê“I‚ȃŠƒŒ[ƒVƒ‡ƒiƒ‹ƒ‚ƒfƒ‹‚ðƒJƒo[‚µ‚½‚½‚߂ɁA
+            ƒRƒŒƒNƒVƒ‡ƒ“‚Ì‚½‚ß‚É—˜—p‚Å‚«‚éƒ}ƒbƒsƒ“ƒO‚É‚Í‚©‚È‚è‚Ì•‚ª‚ ‚è‚Ü‚·B
+            —lX‚ȃ}ƒbƒsƒ“ƒOéŒ¾‚ª‚ǂ̂悤‚Ƀf[ƒ^ƒx[ƒXƒe[ƒuƒ‹‚É•ÏŠ·‚³‚ê‚é‚©‚ð’m‚邽‚߂ɁA
+            ƒXƒL[ƒ}¶¬ƒc[ƒ‹‚ðŽg‚Á‚Ä‚Ý‚é‚Æ—Ç‚¢‚Å‚µ‚傤B
+        </para>
+
+    <sect2 id="collections-ofvalues" revision="2">
+        <title>’l‚̃RƒŒƒNƒVƒ‡ƒ“‚Æ‘½‘Α½ŠÖ˜A</title>
+
+        <para>
+            ’l‚̃RƒŒƒNƒVƒ‡ƒ“‚⑽‘Α½ŠÖ˜A‚́Aê—p‚Ì <emphasis>ƒRƒŒƒNƒVƒ‡ƒ“ƒe[ƒuƒ‹</emphasis> ‚ª•K—v‚Å‚·B
+            ‚±‚̃e[ƒuƒ‹‚́AŠO•”ƒL[ƒJƒ‰ƒ€‚ƁA
+            <emphasis>ƒRƒŒƒNƒVƒ‡ƒ“—v‘f‚̃Jƒ‰ƒ€</emphasis> ‚ƁA
+            ê‡‚É‚æ‚Á‚Ă̓Cƒ“ƒfƒbƒNƒXƒJƒ‰ƒ€‚ðŽ‚¿‚Ü‚·B
+        </para>
+
+        <para>
+            ’l‚̃RƒŒƒNƒVƒ‡ƒ“‚Ì‚½‚߂ɁA<literal>&lt;element&gt;</literal>ƒ^ƒO‚ðŽg—p‚µ‚Ü‚·B
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="element1b" coords="2 50"/>
+                <area id="element2b" coords="3 50"/>
+                <area id="element3b" coords="4 50"/>
+             </areaspec>
+            <programlisting><![CDATA[<element
+        column="column_name"
+        formula="any SQL expression"
+        type="typename"
+        length="L"
+        precision="P"
+        scale="S"
+        not-null="true|false"
+        unique="true|false"
+        node="element-name"
+/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="element1b">
+                    <para>
+                        <literal>column</literal> iƒIƒvƒVƒ‡ƒ“j: ƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f‚Ì’l‚ð•ÛŽ‚·‚éƒJƒ‰ƒ€‚Ì–¼‘OB
+                    </para>
+                </callout>
+                <callout arearefs="element2b">
+                    <para>
+                        <literal>formula</literal> iƒIƒvƒVƒ‡ƒ“j: —v‘f‚ð•]‰¿‚·‚邽‚ß‚ÉŽg‚¤SQLŽ®B
+                    </para>
+                </callout>
+                <callout arearefs="element3b">
+                    <para>
+                        <literal>type</literal> i•K{jƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f‚ÌŒ^B
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <para>
+            <emphasis>‘½‘Α½ŠÖ˜A</emphasis> ‚Í <literal>&lt;many-to-many&gt;</literal> —v‘f‚ÅŽw’肵‚Ü‚·B
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="manytomany1" coords="2 60"/>
+                <area id="manytomany2" coords="3 60"/>
+                <area id="manytomany3" coords="4 60"/>
+                <area id="manytomany4" coords="5 60"/>
+                <area id="manytomany5" coords="6 60"/>
+                <area id="manytomany6" coords="7 60"/>
+                <area id="manytomany7" coords="8 60"/>
+                <area id="manytomany8" coords="9 60"/>
+            </areaspec>
+            <programlisting><![CDATA[<many-to-many
+        column="column_name"
+        formula="any SQL expression"
+        class="ClassName"
+        fetch="select|join"
+        unique="true|false"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        property-ref="propertyNameFromAssociatedClass"
+        node="element-name"
+        embed-xml="true|false"
+    />]]></programlisting>
+            <calloutlist>
+                <callout arearefs="manytomany1">
+                    <para>
+                        <literal>column</literal> iƒIƒvƒVƒ‡ƒ“j: ŠO•”ƒL[ƒJƒ‰ƒ€‚Ì—v‘f‚Ì–¼‘OB
+                    </para>
+                </callout>
+                <callout arearefs="manytomany2">
+                    <para>
+                        <literal>formula</literal> iƒIƒvƒVƒ‡ƒ“j: ŠO•”ƒL[’l‚Ì—v‘f‚ð•]‰¿‚·‚邽‚ß‚ÉŽg‚¤SQLŽ®B
+                    </para>
+                </callout>
+                <callout arearefs="manytomany3">
+                    <para>
+                        <literal>class</literal> i•K{j: ŠÖ˜AƒNƒ‰ƒX‚Ì–¼‘OB
+                    </para>
+                </callout>
+                <callout arearefs="manytomany4">
+                    <para>
+                        <literal>fetch</literal> (ƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>join</literal>):
+                        ŠÖ˜A‚Ì‚½‚߂ɁAŠO•”Œ‹‡‚©‡ŽŸ‘I‘ðƒtƒFƒbƒ`‚ð—LŒø‚É‚µ‚Ü‚·B
+                        ‚±‚ê‚Í“ÁŽê‚ȃP[ƒX‚Å‚·‚ªAƒGƒ“ƒeƒBƒeƒB‚Æ‘¼‚̃Gƒ“ƒeƒBƒeƒB‚Æ‚Ì‘½‘Α½ŠÖŒW‚ð
+                        i‚P‚Â‚Ì <literal>SELECT</literal> ‚É‚æ‚èjŠ®‘S‚É‘¦Žž‚ɃtƒFƒbƒ`‚·‚邽‚߂ɂ́A
+                        ‚»‚̃RƒŒƒNƒVƒ‡ƒ“Ž©‘Ì‚¾‚¯‚Å‚È‚­A
+                        ƒlƒXƒg‚µ‚½—v‘f‚Å‚ ‚é <literal>&lt;many-to-many&gt;</literal> ‚Ì‚±‚Ì‘®«‚ɂ‚¢‚Ä‚à
+                        <literal>join</literal> ƒtƒFƒbƒ`‚ð—LŒø‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+                    </para>
+                </callout>
+                <callout arearefs="manytomany5">
+                    <para>
+                        <literal>unique</literal> iƒIƒvƒVƒ‡ƒ“j:
+                        ŠO•”ƒL[ƒJƒ‰ƒ€‚̃†ƒj[ƒN§–ñ‚ÌDDL¶¬‚ð—LŒø‚É‚µ‚Ü‚·B
+                        ‚±‚ê‚́AŠÖ˜A‚Ì‘½d“x‚ðŽ–ŽÀãˆê‘Α½‚É‚µ‚Ü‚·B
+                    </para>
+                </callout>
+                    <callout arearefs="manytomany6">
+                        <para>
+                            <literal>not-found</literal> iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>exception</literal>j
+                            ŽQÆæ‚̍s‚ª‚È‚¢ŠO•”ƒL[‚ð‚ǂ̂悤‚Ɉµ‚¤‚©‚ðŽw’肵‚Ü‚·B
+                            <literal>ignore</literal> ‚É‚·‚é‚ƁAs‚ª‚È‚¢‚±‚Æ‚ðŠÖ˜A‚ª–³‚¢‚à‚Ì‚Æ‚µ‚Ĉµ‚¢‚Ü‚·B
+                        </para>
+                    </callout>
+                <callout arearefs="manytomany7">
+                    <para>
+                        <literal>entity-name</literal> iƒIƒvƒVƒ‡ƒ“j:
+                        <literal>class</literal> ‚Ì‘ã‘Ö‚Å‚ ‚éŠÖ˜AƒNƒ‰ƒX‚̃Gƒ“ƒeƒBƒeƒB–¼B
+                        <literal>class</literal> ‚Ì‘ã‚í‚è‚ÉŽw’è‚·‚éAŠÖ˜AƒNƒ‰ƒX‚̃Gƒ“ƒeƒBƒeƒB–¼B
+                    </para>
+                </callout>
+                <callout arearefs="manytomany8">
+                    <para>
+                        <literal>property-ref</literal>: iƒIƒvƒVƒ‡ƒ“j
+                        ‚±‚ÌŠO•”ƒL[‚ÉŒ‹‡‚·‚éŠÖ˜AƒNƒ‰ƒX‚̃vƒƒpƒeƒB–¼B
+                        Žw’肵‚È‚©‚Á‚½ê‡‚́AŠÖ˜AƒNƒ‰ƒX‚ÌŽåƒL[‚ðŽg‚¢‚Ü‚·B
+                    </para>                
+                </callout>                   
+            </calloutlist>
+        </programlistingco>
+
+        <para>
+            ˆÈ‰º‚É‚¢‚­‚‚©—á‚ðŽ¦‚µ‚Ü‚·B
+            ‚Ü‚¸‚ÍString‚Ìset‚ÉŠÖ‚µ‚Ä‚Ì—á‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[<set name="names" table="person_names">
+    <key column="person_id"/>
+    <element column="person_name" type="string"/>
+</set>]]></programlisting>
+
+        <para>
+            ®”’l‚ðŠÜ‚Þbagibag‚Í <literal>order-by</literal> ‘®«‚É‚æ‚Á‚Ä”½•œ‡˜‚ª’è‹`‚³‚ê‚Ä‚¢‚Ü‚·j
+        </para>
+
+        <programlisting><![CDATA[<bag name="sizes" 
+        table="item_sizes" 
+        order-by="size asc">
+    <key column="item_id"/>
+    <element column="size" type="integer"/>
+</bag>]]></programlisting>
+
+        <para>
+            ƒGƒ“ƒeƒBƒeƒB‚Ì”z—ñ - ‚±‚̏ꍇA‘½‘Α½‚ÌŠÖ˜A‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[<array name="addresses" 
+        table="PersonAddress" 
+        cascade="persist">
+    <key column="personId"/>
+    <list-index column="sortOrder"/>
+    <many-to-many column="addressId" class="Address"/>
+</array>]]></programlisting>
+
+        <para>
+            •¶Žš—ñ‚Æ“ú•t‚Ìmap
+        </para>
+
+        <programlisting><![CDATA[<map name="holidays" 
+        table="holidays" 
+        schema="dbo" 
+        order-by="hol_name asc">
+    <key column="id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            ƒRƒ“ƒ|[ƒlƒ“ƒg‚ÌlistiŽŸ‚̏͂ŏڂµ‚­à–¾‚µ‚Ü‚·j
+        </para>
+
+        <programlisting><![CDATA[<list name="carComponents" 
+        table="CarComponents">
+    <key column="carId"/>
+    <list-index column="sortOrder"/>
+    <composite-element class="CarComponent">
+        <property name="price"/>
+        <property name="type"/>
+        <property name="serialNumber" column="serialNum"/>
+    </composite-element>
+</list>]]></programlisting>
+
+    </sect2>
+
+    <sect2 id="collections-onetomany">
+        <title>ˆê‘Α½ŠÖ˜A</title>
+
+        <para>
+            <emphasis>ˆê‘Α½ŠÖ˜A</emphasis> ‚́AƒRƒŒƒNƒVƒ‡ƒ“¥ƒe[ƒuƒ‹‚ð‰î‚³‚¸A
+            ŠO•”ƒL[‚É‚æ‚è2‚‚̃Nƒ‰ƒX‚̃e[ƒuƒ‹‚ðŠÖ˜A•t‚¯‚Ü‚·B
+            ‚±‚̃}ƒbƒsƒ“ƒO‚Í•W€“I‚ÈJava‚̃RƒŒƒNƒVƒ‡ƒ“‚̃Zƒ}ƒ“ƒeƒBƒNƒX‚ð‚¢‚­‚‚©Ž¸‚¢‚Ü‚·B
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    ƒGƒ“ƒeƒBƒeƒBƒNƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚́A
+                    2‚ˆȏã‚̃RƒŒƒNƒVƒ‡ƒ“‚̃Cƒ“ƒXƒ^ƒ“ƒX‚É‘®‚µ‚Ä‚Í‚¢‚¯‚Ü‚¹‚ñB
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ƒRƒŒƒNƒVƒ‡ƒ“‚ÉŠÜ‚Ü‚ê‚éƒGƒ“ƒeƒBƒeƒBƒNƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚́A
+                    ƒRƒŒƒNƒVƒ‡ƒ“ƒCƒ“ƒfƒbƒNƒX‚Ì’l‚Æ‚µ‚Ä2“xˆÈãŒ»‚ê‚Ä‚Í‚¢‚¯‚Ü‚¹‚ñB
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>Product</literal> ‚©‚ç <literal>Part</literal> ‚Ö‚ÌŠÖ˜A‚́A
+            <literal>Part</literal> ƒe[ƒuƒ‹‚Ö‚ÌŠO•”ƒL[ƒJƒ‰ƒ€‚ƁAê‡‚É‚æ‚Á‚Ă̓Cƒ“ƒfƒbƒNƒXƒJƒ‰ƒ€‚ª•K—v‚Å‚·B
+            <literal>&lt;one-to-many&gt;</literal> ƒ^ƒO‚́A‚±‚ꂪˆê‘Α½ŠÖ˜A‚Å‚ ‚邱‚Æ‚ð•\‚µ‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="onetomany1" coords="2 60"/>
+                <area id="onetomany2" coords="3 60"/>
+                <area id="onetomany3" coords="4 60"/>
+            </areaspec>
+            <programlisting><![CDATA[<one-to-many 
+        class="ClassName"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        node="element-name"
+        embed-xml="true|false"
+    />]]></programlisting>
+            <calloutlist>
+                <callout arearefs="onetomany1">
+                    <para>
+                        <literal>class</literal> i•K{j: ŠÖ˜AƒNƒ‰ƒX‚Ì–¼‘OB
+                    </para>
+                </callout>
+                        <callout arearefs="onetomany2">
+                            <para>
+                                <literal>not-found</literal> iƒIƒvƒVƒ‡ƒ“ - ƒfƒtƒHƒ‹ƒg‚Í <literal>exception</literal>j:
+                                ŽQÆæ‚̍s‚ª‚È‚¢ƒLƒƒƒbƒVƒ…‚³‚ꂽŽ¯•ÊŽq‚ð‚ǂ̂悤‚Ɉµ‚¤‚©‚ðŽw’肵‚Ü‚·B
+                                <literal>ignore</literal> ‚ðŽw’è‚·‚é‚ƁAs‚ª‚È‚¢‚±‚Æ‚ðŠÖ˜A‚ª‚È‚¢‚à‚Ì‚Æ‚µ‚Ĉµ‚¢‚Ü‚·B
+                            </para>
+                        </callout>
+                <callout arearefs="onetomany3">
+                    <para>
+                        <literal>entity-name</literal> iƒIƒvƒVƒ‡ƒ“j:
+                        <literal>class</literal> ‚Ì‘ã‘Ö‚Å‚ ‚éŠÖ˜AƒNƒ‰ƒX‚̃Gƒ“ƒeƒBƒeƒB–¼B
+                        <literal>class</literal> ‚Ì‘ã‚í‚è‚ÉŽw’è‚·‚éAŠÖ˜AƒNƒ‰ƒX‚̃Gƒ“ƒeƒBƒeƒB–¼B
+                    </para>
+                </callout>
+            </calloutlist>
+       </programlistingco>
+  
+        <para>
+            <literal>&lt;one-to-many&gt;</literal> —v‘f‚̓Jƒ‰ƒ€‚ðéŒ¾‚·‚é•K—v‚ª‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            “¯—l‚É <literal>ƒe[ƒuƒ‹</literal> –¼‚ðŽw’è‚·‚é•K—v‚à‚ ‚è‚Ü‚¹‚ñB
+        </para>
+
+        <para>
+            <emphasis>‚Æ‚Ä‚àd—v‚È’ˆÓ:</emphasis> ‚à‚µ <literal>&lt;one-to-many&gt;</literal>
+            ŠÖ˜A‚ÌŠO•”ƒL[ƒJƒ‰ƒ€‚ª <literal>NOT NULL</literal>‚Ɛ錾‚³‚ꂽê‡A
+            <literal>&lt;key&gt;</literal> ƒ}ƒbƒsƒ“ƒO‚É <literal>not-null="true"</literal> ‚ðéŒ¾‚·‚é‚©A
+            ƒRƒŒƒNƒVƒ‡ƒ“ƒ}ƒbƒsƒ“ƒO‚É <literal>inverse="true"</literal> ‚ð•t‚¯‚½ã‚ŁA
+            <emphasis>‘o•ûŒüŠÖ˜A‚ðŽg‚¤</emphasis> •K—v‚ª‚ ‚è‚Ü‚·B
+            ‘o•ûŒüŠÖ˜A‚ɂ‚¢‚Ä‚Í‚±‚̏͂̌ã‚Ì‚Ù‚¤‚Åà–¾‚µ‚Ü‚·B
+        </para>
+        
+        <para>
+            ŽŸ‚Ì—á‚́A–¼Ìi<literal>Part</literal> ‚̉i‘±“I‚ȃvƒƒpƒeƒB‚Å‚ ‚é <literal>partName</literal>j
+            ‚É‚æ‚é <literal>Part</literal> ƒGƒ“ƒeƒBƒeƒB‚Ìmap‚ð•\‚µ‚Ä‚¢‚Ü‚·B
+            formula‚É‚æ‚éƒCƒ“ƒfƒbƒNƒX‚ðŽg‚Á‚Ä‚¢‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <programlisting><![CDATA[<map name="parts"
+        cascade="all">
+    <key column="productId" not-null="true"/>
+    <map-key formula="partName"/>
+    <one-to-many class="Part"/>
+</map>]]></programlisting>
+    </sect2>
+    
+    </sect1>
+
+    <sect1 id="collections-advancedmappings">
+        <title>‚“x‚ȃRƒŒƒNƒVƒ‡ƒ“¥ƒ}ƒbƒsƒ“ƒO</title>
+
+    <sect2 id="collections-sorted" revision="2">
+        <title>ƒ\[ƒg‚³‚ꂽƒRƒŒƒNƒVƒ‡ƒ“</title>
+
+        <para>
+            Hibernate‚Í <literal>java.util.SortedMap</literal> ‚Æ <literal>java.util.SortedSet</literal>
+            ‚ðŽÀ‘•‚µ‚½ƒRƒŒƒNƒVƒ‡ƒ“‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·B
+            ŠJ”­ŽÒ‚̓}ƒbƒsƒ“ƒO’è‹`ƒtƒ@ƒCƒ‹‚ɃRƒ“ƒpƒŒ[ƒ^‚ðŽw’肵‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+        </para>
+
+        <programlisting><![CDATA[<set name="aliases" 
+            table="person_aliases" 
+            sort="natural">
+    <key column="person"/>
+    <element column="name" type="string"/>
+</set>
+
+<map name="holidays" sort="my.custom.HolidayComparator">
+    <key column="year_id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            <literal>sort</literal> ‘®«‚ɐݒè‚Å‚«‚é’l‚Í <literal>unsorted</literal> ‚Æ <literal>natural</literal>
+            ‚¨‚æ‚сA<literal>java.util.Comparator</literal> ‚ðŽÀ‘•‚µ‚½ƒNƒ‰ƒX‚Ì–¼‘O‚Å‚·B
+        </para>
+
+        <para>
+            ƒ\[ƒg‚³‚ꂽƒRƒŒƒNƒVƒ‡ƒ“‚ÍŽÀŽ¿“I‚É‚Í <literal>java.util.TreeSet</literal> ‚â
+            <literal>java.util.TreeMap</literal> ‚̂悤‚ɐU•‘‚¢‚Ü‚·B
+        </para>
+
+        <para>
+            ‚à‚µƒf[ƒ^ƒx[ƒXŽ©g‚ɃRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f‚ð•À‚ׂ³‚¹‚½‚¢‚È‚çA
+            <literal>set</literal> ‚â <literal>bag</literal>A<literal>map</literal> ‚Ì
+            <literal>order-by</literal> ‘®«‚ðŽg‚¢‚Ü‚·B
+            ‚±‚Ì‰ðŒˆ–@‚ÍJDK1.4A‚à‚µ‚­‚Í‚»‚êˆÈã‚̃o[ƒWƒ‡ƒ“‚Å—˜—p‰Â”\‚Å‚·
+            i<literal>LinkedHashSet</literal> ‚Ü‚½‚Í <literal>LinkedHashMap</literal>‚ðŽg‚Á‚ÄŽÀ‘•‚³‚ê‚Ä‚¢‚Ü‚·jB
+            ®—ñ‚̓ƒ‚ƒŠã‚Å‚Í‚È‚­ASQLƒNƒGƒŠ“à‚ÅŽÀs‚³‚ê‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="lower(name) asc">
+    <key column="person"/>
+    <element column="name" type="string"/>
+</set>
+
+<map name="holidays" order-by="hol_date, hol_name">
+    <key column="year_id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            <literal>order-by</literal> ‘®«‚Ì’l‚ªSQL–½—ß‚Å‚ ‚Á‚āAHQL–½—ß‚Å‚Í‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢I
+        </para>
+
+        <para>
+            ŠÖ˜A‚́AƒRƒŒƒNƒVƒ‡ƒ“‚Ì <literal>filter()</literal> ‚ðŽg‚¤‚±‚ƂŁA
+            ŽÀsŽž‚É”CˆÓ‚Ìcriteria‚É‚æ‚Á‚ă\[ƒg‚·‚邱‚Æ‚à‰Â”\‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[sortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list();]]></programlisting>
+
+    </sect2>
+
+     <sect2 id="collections-bidirectional" revision="1">
+        <title>‘o•ûŒüŠÖ˜A</title>
+
+        <para>
+            <emphasis>‘o•ûŒüŠÖ˜A</emphasis> ‚ÍŠÖ˜A‚Ì‚Ç‚¿‚çu‘¤v‚©‚ç‚Å‚àƒiƒrƒQ[ƒVƒ‡ƒ“‚Å‚«‚Ü‚·B
+            2Ží—Þ‚Ì‘o•ûŒüŠÖ˜A‚ªƒTƒ|[ƒg‚³‚ê‚Ä‚¢‚Ü‚·B
+
+            <variablelist>
+                <varlistentry>
+                    <term>one-to-many</term>
+                    <listitem>
+                        <para>
+                            •Ð‘¤‚ªset‚©bagA‚à‚¤•Ð•û‚ª’Pˆê’l‚Å‚·B
+                       </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>many-to-many</term>
+                    <listitem>
+                        <para>
+                            —¼‘¤‚ªset‚©bag‚Å‚·B
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+        </para>
+
+        <para>
+            2‚‚̑½‘Α½ŠÖ˜A‚Å“¯‚¶ƒf[ƒ^ƒx[ƒXƒe[ƒuƒ‹‚ðƒ}ƒbƒsƒ“ƒO‚µA
+            •Ð•û‚ð <emphasis>inverse</emphasis> ‚Æ‚µ‚Đ錾‚·‚邱‚ƂŁA
+            ‘o•ûŒü‚Ì‘½‘Α½ŠÖ˜A‚ðŽw’è‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·
+            i‚Ç‚¿‚ç‚ðinverse‚É‘I‚ñ‚¾‚Æ‚µ‚Ä‚àA‚»‚¿‚瑤‚ɂ̓Cƒ“ƒfƒbƒNƒX•t‚«‚̃RƒŒƒNƒVƒ‡ƒ“‚ÍŽg‚¦‚Ü‚¹‚ñjB
+        </para>
+
+        <para>
+            ŽŸ‚É‘o•ûŒü‚Ì‘½‘Α½ŠÖ˜A‚Ì—á‚ðŽ¦‚µ‚Ü‚·B
+            ŠeƒJƒeƒSƒŠ‚Í‘½”‚̃AƒCƒeƒ€‚ðŽ‚Â‚±‚Æ‚ª‚Å‚«AŠeƒAƒCƒeƒ€‚Í‘½‚­‚̃JƒeƒSƒŠ‚É‘®‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="Category">
+    <id name="id" column="CATEGORY_ID"/>
+    ...
+    <bag name="items" table="CATEGORY_ITEM">
+        <key column="CATEGORY_ID"/>
+        <many-to-many class="Item" column="ITEM_ID"/>
+    </bag>
+</class>
+
+<class name="Item">
+    <id name="id" column="CATEGORY_ID"/>
+    ...
+
+    <!-- inverse end -->
+    <bag name="categories" table="CATEGORY_ITEM" inverse="true">
+        <key column="ITEM_ID"/>
+        <many-to-many class="Category" column="CATEGORY_ID"/>
+    </bag>
+</class>]]></programlisting>
+
+        <para>
+            ŠÖ˜A‚Ìinverse‘¤‚ɂ̂ݍs‚í‚ꂽ•ÏX‚͉i‘±‰» <emphasis>‚³‚ê‚Ü‚¹‚ñ</emphasis>B
+            ‚±‚ê‚́AHibernate‚Í‘S‚Ä‚Ì‘o•ûŒüŠÖ˜A‚ɂ‚¢‚āAƒƒ‚ƒŠã‚É‚Q‚‚̕\Œ»‚ðŽ‚Á‚Ä‚¢‚é‚Æ‚¢‚¤ˆÓ–¡‚Å‚·B
+            ‚‚܂èˆê‚‚ÍA‚©‚çB‚ւ̃Šƒ“ƒN‚ŁA‚à‚¤ˆê‚‚ÍB‚©‚çA‚ւ̃Šƒ“ƒN‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+            Java‚̃IƒuƒWƒFƒNƒgƒ‚ƒfƒ‹‚ɂ‚¢‚čl‚¦AJava‚Å‘o•ûŒüŠÖŒW‚ð‚Ç‚¤‚â‚Á‚čì‚é‚©‚ðl‚¦‚ê‚΁A
+            ‚±‚ê‚Í—‰ð‚µ‚â‚·‚¢‚Å‚·B‰º‹L‚ɁAJava‚Å‚Ì‘o•ûŒüŠÖ˜A‚ðŽ¦‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[
+category.getItems().add(item);          // The category now "knows" about the relationship
+item.getCategories().add(category);     // The item now "knows" about the relationship
+
+session.persist(item);                   // The relationship won't be saved!
+session.persist(category);               // The relationship will be saved]]></programlisting>
+
+        <para>
+            ŠÖ˜A‚Ìinverse‚Å‚Í‚È‚¢‘¤‚́Aƒƒ‚ƒŠã‚Ì•\Œ»‚ðƒf[ƒ^ƒx[ƒX‚É•Û‘¶‚·‚é‚Ì‚ÉŽg‚í‚ê‚Ü‚·B
+        </para>
+
+        <para>
+            ‘o•ûŒü‚̈ê‘Α½ŠÖ˜A‚ð’è‹`‚·‚é‚ɂ́A
+            ˆê‘Α½ŠÖ˜A‚𑽑ΈêŠÖ˜A‚Æ“¯‚¶ƒe[ƒuƒ‹‚̃Jƒ‰ƒ€‚Ƀ}ƒbƒsƒ“ƒO‚µA
+            ‘½‘¤‚É <literal>inverse="true"</literal> ‚Ɛ錾‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <set name="children" inverse="true">
+        <key column="parent_id"/>
+        <one-to-many class="Child"/>
+    </set>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        not-null="true"/>
+</class>]]></programlisting>
+
+        <para>
+            ŠÖ˜A‚̕Б¤‚É <literal>inverse="true"</literal> ‚ðÝ’肵‚Ä‚àA
+            ƒJƒXƒP[ƒh‘€ì‚ɉe‹¿‚ð—^‚¦‚Ü‚¹‚ñB‚±‚ê‚ç‚Í’¼Œð‚µ‚½ŠT”O‚Å‚·I
+        </para>
+
+    </sect2>
+
+    <sect2 id="collections-indexedbidirectional">
+        <title>ƒCƒ“ƒfƒbƒNƒX•t‚«ƒRƒŒƒNƒVƒ‡ƒ“‚Æ‘o•ûŒüŠÖ˜A</title>
+        <para>
+            •Ð‘¤‚ª <literal>&lt;list&gt;</literal> ‚â <literal>&lt;map&gt;</literal> ‚Å‚ ‚é
+            ‘o•ûŒüŠÖ˜A‚́A“Á‚É‚æ‚­l‚¦‚é•K—v‚ª‚ ‚è‚Ü‚·B
+            ƒCƒ“ƒfƒbƒNƒXƒJƒ‰ƒ€‚Ƀ}ƒbƒv‚³‚ê‚éŽqƒNƒ‰ƒX‚̃vƒƒpƒeƒB‚ª‚ ‚éê‡‚́A–â‘è‚È‚¢‚Å‚·B
+            ƒRƒŒƒNƒVƒ‡ƒ“‚̃}ƒbƒsƒ“ƒO‚Å <literal>inverse="true"</literal> ‚ðŽg‚¢‘±‚¯‚ç‚ê‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <map name="children" inverse="true">
+        <key column="parent_id"/>
+        <map-key column="name" 
+            type="string"/>
+        <one-to-many class="Child"/>
+    </map>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <property name="name" 
+        not-null="true"/>
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        not-null="true"/>
+</class>]]></programlisting>
+
+        <para>
+            ‚µ‚©‚µAŽqƒNƒ‰ƒX‚É‚»‚̂悤‚ȃvƒƒpƒeƒB‚ª‚È‚¢ê‡‚́A
+            ŠÖ˜A‚ð^‚É‘o•ûŒü‚Å‚ ‚é‚ƍl‚¦‚邱‚Æ‚ª‚Å‚«‚Ü‚¹‚ñ
+            iŠÖ˜A‚̕Б¤‚É—˜—p‚Å‚«‚éî•ñ‚ª‚ ‚è‚Ü‚·‚ªA‚à‚¤ˆê•û‚É‚Í‚ ‚è‚Ü‚¹‚ñjB
+            ‚±‚̏ꍇ‚́AƒRƒŒƒNƒVƒ‡ƒ“‚É <literal>inverse="true"</literal> ‚ðƒ}ƒbƒsƒ“ƒO‚Å‚«‚Ü‚¹‚ñB
+            ‘ã‚í‚è‚ɁAŽŸ‚̂悤‚ȃ}ƒbƒsƒ“ƒO‚ªŽg‚¦‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <map name="children">
+        <key column="parent_id"
+            not-null="true"/>
+        <map-key column="name" 
+            type="string"/>
+        <one-to-many class="Child"/>
+    </map>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        insert="false"
+        update="false"
+        not-null="true"/>
+</class>]]></programlisting>
+
+       <para>
+           ’ˆÓF ‚±‚̃}ƒbƒsƒ“ƒO‚ł́AŠÖ˜A‚̃RƒŒƒNƒVƒ‡ƒ“’l‚Ì‘¤‚́A
+           ŠO•”ƒL[‚ðƒAƒbƒvƒf[ƒg‚·‚éÓ”C‚ª‚ ‚è‚Ü‚·B
+           <!-- TODO: Does this really result in some unnecessary update statements? -->
+       </para>
+
+    </sect2>
+
+    <sect2 id="collections-ternary">
+        <title>3€ŠÖ˜A</title>
+
+        <para>
+            3€ŠÖ˜A‚̃}ƒbƒsƒ“ƒO‚É‚Í3‚‚̃Aƒvƒ[ƒ`‚ª‚ ‚è‚Ü‚·B
+            1‚–ڂ͊֘A‚ðƒCƒ“ƒfƒbƒNƒX‚Æ‚µ‚Ä <literal>Map</literal> ‚ðŽg—p‚·‚éƒAƒvƒ[ƒ`‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[<map name="contracts">
+    <key column="employer_id" not-null="true"/>
+    <map-key-many-to-many column="employee_id" class="Employee"/>
+    <one-to-many class="Contract"/>
+</map>]]></programlisting>
+            
+            <programlisting><![CDATA[<map name="connections">
+    <key column="incoming_node_id"/>
+    <map-key-many-to-many column="outgoing_node_id" class="Node"/>
+    <many-to-many column="connection_id" class="Connection"/>
+</map>]]></programlisting>
+            
+        <para>
+            2‚–ڂ͒Pƒ‚ÉŠÖ˜A‚ðƒGƒ“ƒeƒBƒeƒB¥ƒNƒ‰ƒX‚Æ‚µ‚ă‚ƒfƒ‹‚ðì‚è’¼‚·ƒAƒvƒ[ƒ`‚ŁA
+            •p”É‚ÉŽg‚í‚ê‚Ü‚·B
+        </para>
+        
+        <para>
+            ÅŒã‚Ícomposite—v‘f‚ðŽg‚¤ƒAƒvƒ[ƒ`‚Å‚·B‚±‚ê‚ÉŠÖ‚·‚é‹c˜_‚ÍŒã‚قǍs‚¢‚Ü‚·B
+        </para>
+        
+    </sect2>
+    
+    <sect2 id="collections-idbag" revision="1">
+        <title><literal>&lt;idbag&gt;</literal>‚ÌŽg—p</title>
+
+        <para>
+            •¡‡ƒL[‚͈«‚¢‚à‚̂ŁAƒGƒ“ƒeƒBƒeƒB‚͐lH‚ÌŽ¯•ÊŽq(‘㗝ƒL[)‚ðŽ‚Â‚×‚«‚Å‚ ‚é‚Æ‚¢‚¤l‚¦•û‚©‚ç‚́A
+            ‘½‘Α½ŠÖ˜A‚Æ’l‚̃RƒŒƒNƒVƒ‡ƒ“‚𕡍‡ƒL[‚ð—p‚¢‚½ƒe[ƒuƒ‹‚Öƒ}ƒbƒsƒ“ƒO‚·‚é‚̂͏­‚µŠï–­‚ÉŠ´‚¶‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñI
+            Šm‚©‚É‚±‚̍l‚¦•û‚É‚Í‹c˜_‚Ì—]’n‚ª‚ ‚è‚Ü‚·B
+            ƒˆ‚ÈŠÖ˜Aƒe[ƒuƒ‹‚͑㗝ƒL[‚ðŽg‚Á‚Ä‚à—˜‰v‚𓾂ç‚ê‚È‚¢‚悤‚ÉŽv‚¦‚é‚©‚ç‚Å‚·
+            i‡¬’l‚̃RƒŒƒNƒVƒ‡ƒ“‚Í—˜‰v‚ª‚ ‚é <emphasis>‚©‚à</emphasis> ‚µ‚ê‚Ü‚¹‚ñ‚ªjB
+            ‚Æ‚Í‚¢‚¦AHibernate‚͑㗝ƒL[‚ðŽ‚Âƒe[ƒuƒ‹‚Ö‘½‘Α½ŠÖ˜A‚Æ’l‚̃RƒŒƒNƒVƒ‡ƒ“‚ð
+            ƒ}ƒbƒsƒ“ƒO‚·‚é‹@”\‚à”õ‚¦‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <para>
+            bag‚̃Zƒ}ƒ“ƒeƒBƒbƒNƒX‚ðŽ‚Á‚½ <literal>List</literal>i‚Ü‚½‚Í <literal>Collection</literal>j‚ð
+            <literal>&lt;idbag&gt;</literal> —v‘f‚Ƀ}ƒbƒsƒ“ƒO‚Å‚«‚Ü‚·B
+        </para>
+
+<programlisting><![CDATA[<idbag name="lovers" table="LOVERS">
+    <collection-id column="ID" type="long">
+        <generator class="sequence"/>
+    </collection-id>
+    <key column="PERSON1"/>
+    <many-to-many column="PERSON2" class="Person" fetch="join"/>
+</idbag>]]></programlisting>
+
+        <para>
+            ‚²‘¶’m‚̂悤‚É <literal>&lt;idbag&gt;</literal> ‚̓Gƒ“ƒeƒBƒeƒB¥ƒNƒ‰ƒX‚̂悤‚É
+            lH“I‚ÈidƒWƒFƒlƒŒ[ƒ^‚ðŽ‚Á‚Ä‚¢‚Ü‚·I
+            ˆÙ‚È‚é‘㗝ƒL[‚ð‚»‚ê‚¼‚ê‚̃RƒŒƒNƒVƒ‡ƒ“‚Ì—ñ‚ÉŠ„‚è“–‚Ä‚Ü‚·B
+            ‚µ‚©‚µ‚È‚ª‚çAHibernate‚Í‚ ‚és‚̑㗝ƒL[‚Ì’l‚ðŒ©‚Â‚¯o‚·‹@\‚ðŽ‚Á‚Ä‚¢‚Ü‚¹‚ñB
+        </para>
+
+        <para>
+            <literal>&lt;idbag&gt;</literal> ‚ðXV‚·‚éƒpƒtƒH[ƒ}ƒ“ƒX‚Í
+            ’ʏí‚Ì <literal>&lt;bag&gt;</literal> ‚æ‚è‚à—Ç‚¢‚±‚Æ‚É’–Ú‚µ‚Ä‚­‚¾‚³‚¢I
+            Hibernate‚͌X‚̍s‚ðŒø‰Ê“I‚ÉŒ©‚‚¯‚邱‚Æ‚ª‚Å‚«A
+            list‚âmapAset‚̂悤‚Ɍ•ʂɂ»‚̍s‚ðXVAíœ‚Å‚«‚Ü‚·B
+        </para>
+
+        <para>
+            Œ»Ý‚ÌŽÀ‘•‚ł́A<literal>native</literal> ‚Æ‚¢‚¤id¶¬í—ª‚ð
+            <literal>&lt;idbag&gt;</literal> ƒRƒŒƒNƒVƒ‡ƒ“‚ÌŽ¯•ÊŽq‚ɑ΂µ‚ÄŽg‚¦‚Ü‚¹‚ñB
+        </para>
+
+    </sect2>
+
+    </sect1>
+    
+    <!--undocumenting this stuff -->
+    
+    <!--sect1 id="collections-heterogeneous">
+        <title>Heterogeneous Associations</title>
+
+        <para>
+            The <literal>&lt;many-to-any&gt;</literal> and <literal>&lt;index-many-to-any&gt;</literal>
+            elements provide for true heterogeneous associations. These mapping elements work in the
+            same way as the <literal>&lt;any&gt;</literal> element - and should also be used
+            rarely, if ever.
+        </para>
+
+    </sect1-->
+
+    <sect1 id="collections-example" revision="1">
+        <title>ƒRƒŒƒNƒVƒ‡ƒ“‚Ì—á</title>
+
+        <para>
+            ‚±‚ê‚Ü‚Å‚Ìß‚Ìà–¾‚Å‚Í—‰ð‚µ‚É‚­‚¢‚̂ŁAˆÈ‰º‚Ì—á‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+
+public class Parent {
+    private long id;
+    private Set children;
+
+    public long getId() { return id; }
+    private void setId(long id) { this.id=id; }
+
+    private Set getChildren() { return children; }
+    private void setChildren(Set children) { this.children=children; }
+
+    ....
+    ....
+}]]></programlisting>
+
+        <para>
+            ‚±‚̃Nƒ‰ƒX‚Í <literal>Child</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚̃RƒŒƒNƒVƒ‡ƒ“‚ðŽ‚Á‚Ä‚¢‚Ü‚·B
+            ‚à‚µŠeX‚Ìchild‚ªÅ‘å‚Å‚àˆê‚‚Ìparent‚ðŽ‚Á‚Ä‚¢‚é‚È‚ç‚΁AÅ‚àŽ©‘R‚ȃ}ƒbƒsƒ“ƒO‚͈ê‘Α½ŠÖ˜A‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children">
+            <key column="parent_id"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            ‚±‚ê‚͈ȉº‚̃e[ƒuƒ‹’è‹`‚Ƀ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255), parent_id bigint )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+        <para>
+            ‚à‚µparent‚ª <emphasis>—v‹</emphasis> ‚³‚ê‚é‚È‚çA‘o•ûŒü‚̈ê‘Α½ŠÖ˜A‚ðŽg—p‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children" inverse="true">
+            <key column="parent_id"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+        <many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            <literal>NOT NULL</literal> §–ñ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null
+                     primary key,
+                     name varchar(255),
+                     parent_id bigint not null )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+        <para>
+            ‚ ‚é‚¢‚́A‚à‚µ‚±‚ÌŠÖ˜A‚Í’P•ûŒü‚Å‚ ‚é‚ׂ«‚Æ‹­‚­Žå’£‚·‚é‚Ì‚Å‚ ‚ê‚΁A
+            <literal>&lt;key&gt;</literal> ‚É <literal>NOT NULL</literal> §–ñ‚ðéŒ¾‚Å‚«‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children">
+            <key column="parent_id" not-null="true"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            ˆê•û‚ŁA‚à‚µchild‚ª•¡”‚Ìparent‚ðŽ‚Ä‚é‚È‚ç‚΁A‘½‘Α½ŠÖ˜A‚ª‘Ó–‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children" table="childset">
+            <key column="parent_id"/>
+            <many-to-many class="Child" column="child_id"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            ƒe[ƒuƒ‹’è‹`‚͈ȉº‚̂悤‚É‚È‚è‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255) )
+create table childset ( parent_id bigint not null,
+                        child_id bigint not null,
+                        primary key ( parent_id, child_id ) )
+alter table childset add constraint childsetfk0 (parent_id) references parent
+alter table childset add constraint childsetfk1 (child_id) references child]]></programlisting>
+
+        <para>
+            parent/childŠÖŒW‚̃}ƒbƒsƒ“ƒO‚ɂ‚¢‚Ä‚Ì‚æ‚葽‚­‚Ì—á‚⊮‘S‚Ȏ菇‚ª•K—v‚Å‚ ‚ê‚΁A
+            <xref linkend="example-parentchild"/> ‚ð‚²——‚­‚¾‚³‚¢B
+        </para>
+        
+        <para>
+            ‚Ü‚½A‚³‚ç‚É“ÁŽê‚ÈŠÖ˜Aƒ}ƒbƒsƒ“ƒO‚à‰Â”\‚Å‚·BŽŸ‚̏͂ŏڂµ‚­q‚ׂ܂·B
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/component_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/component_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/component_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,396 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="components">
+    <title>ƒRƒ“ƒ|[ƒlƒ“ƒg‚̃}ƒbƒsƒ“ƒO</title>
+
+    <para>
+        <emphasis>ƒRƒ“ƒ|[ƒlƒ“ƒg</emphasis> ‚ÌŠT”O‚́AHibernate‚ð’Ê‚µ‚Ä—lX‚ȏ󋵂̒†‚Å
+        ˆÙ‚È‚é–Ú“I‚Ì‚½‚߂ɍė˜—p‚³‚ê‚Ü‚·B
+    </para>
+
+    <sect1 id="components-dependentobjects" revision="2" >
+        <title>ˆË‘¶ƒIƒuƒWƒFƒNƒg</title>
+
+        <para>
+            ƒRƒ“ƒ|[ƒlƒ“ƒg‚́AƒGƒ“ƒeƒBƒeƒB‚ÌŽQÆ‚Å‚Í‚È‚­’lŒ^‚Æ‚µ‚ĉi‘±‰»‚³‚ꂽA
+            •ïŠÜ‚³‚ꂽƒIƒuƒWƒFƒNƒg‚Å‚·BƒRƒ“ƒ|[ƒlƒ“ƒg‚Æ‚¢‚¤Œ¾—t‚ɂ‚¢‚ẮAƒRƒ“ƒ|ƒWƒVƒ‡ƒ“‚Æ‚¢‚¤
+            ƒIƒuƒWƒFƒNƒgŽwŒü‚ÌŠT”O‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢iƒA[ƒLƒeƒNƒ`ƒƒƒŒƒxƒ‹‚̃Rƒ“ƒ|[ƒlƒ“ƒg‚Å‚Í‚ ‚è‚Ü‚¹‚ñjB
+            —Ⴆ‚΁AˆÈ‰º‚ÌPersonƒ‚ƒfƒ‹‚̂悤‚È‚à‚Ì‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[public class Person {
+    private java.util.Date birthday;
+    private Name name;
+    private String key;
+    public String getKey() {
+        return key;
+    }
+    private void setKey(String key) {
+        this.key=key;
+    }
+    public java.util.Date getBirthday() {
+        return birthday;
+    }
+    public void setBirthday(java.util.Date birthday) {
+        this.birthday = birthday;
+    }
+    public Name getName() {
+        return name;
+    }
+    public void setName(Name name) {
+        this.name = name;
+    }
+    ......
+    ......
+}]]></programlisting>
+
+<programlisting><![CDATA[public class Name {
+    char initial;
+    String first;
+    String last;
+    public String getFirst() {
+        return first;
+    }
+    void setFirst(String first) {
+        this.first = first;
+    }
+    public String getLast() {
+        return last;
+    }
+    void setLast(String last) {
+        this.last = last;
+    }
+    public char getInitial() {
+        return initial;
+    }
+    void setInitial(char initial) {
+        this.initial = initial;
+    }
+}]]></programlisting>
+
+        <para>
+            ‚¢‚܁A<literal>Name</literal> ‚Í <literal>Person</literal> ‚̃Rƒ“ƒ|[ƒlƒ“ƒg‚Æ‚µ‚Ä
+            ‰i‘±‰»‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B‚±‚±‚Å <literal>Name</literal> ‚͉i‘±‰»‘®«‚ɑ΂µ‚ÄgetterA
+            setterƒƒ\ƒbƒh‚ð’è‹`‚µ‚Ü‚·‚ªAƒCƒ“ƒ^[ƒtƒFƒCƒX‚⎯•ÊŽqƒvƒƒpƒeƒB‚ð’è‹`‚·‚é•K—v‚ª
+            ‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚ĉº‚³‚¢B
+        </para>
+
+        <para>
+            ƒ}ƒbƒsƒ“ƒO’è‹`‚͈ȉº‚̂悤‚É‚È‚è‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Person" table="person">
+    <id name="Key" column="pid" type="string">
+        <generator class="uuid"/>
+    </id>
+    <property name="birthday" type="date"/>
+    <component name="Name" class="eg.Name"> <!-- class attribute optional -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </component>
+</class>]]></programlisting>
+
+        <para>
+            Personƒe[ƒuƒ‹‚Í <literal>pid</literal>A
+            <literal>birthday</literal>A
+            <literal>initial</literal>A
+            <literal>first</literal>A
+            <literal>last</literal> ƒJƒ‰ƒ€‚ðŽ‚¿‚Ü‚·B
+        </para>
+
+        <para>
+            ‘S‚Ä‚Ì’lŒ^‚̂悤‚ɁAƒRƒ“ƒ|[ƒlƒ“ƒg‚ÍŽQÆ‚Ì‹¤—L‚ð‚·‚é‚±‚Æ‚ª‚Å‚«‚Ü‚¹‚ñB
+            Œ¾‚¢Š·‚¦‚é‚ƁA“ñl‚ÌPerson‚Í“¯‚¶–¼‘O‚ðŽ‚Â‚±‚Æ‚ª‚Å‚«‚Ü‚·‚ªA“ñ‚‚ÌPersonƒIƒuƒWƒFƒNƒg‚Í
+            "’l‚ª“¯‚¶‚¾‚¯"‚̕ʁX‚ÌnameƒIƒuƒWƒFƒNƒg‚ðŠÜ‚ñ‚Å‚¢‚é‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+            ƒRƒ“ƒ|[ƒlƒ“ƒg‚Ìnull’l‚̃Zƒ}ƒ“ƒeƒBƒNƒX‚Í <emphasis>ƒAƒhƒzƒbƒN</emphasis> ‚Å‚·B
+            ƒRƒ“ƒ|[ƒlƒ“ƒg‚̃IƒuƒWƒFƒNƒg‚ðÄ“ǂݍž‚Ý‚·‚éÛAHibernate‚̓Rƒ“ƒ|[ƒlƒ“ƒg‚Ì‚·‚ׂẴJƒ‰ƒ€‚ª
+            null‚Å‚ ‚é‚È‚çƒRƒ“ƒ|[ƒlƒ“ƒgŽ©‘Ì‚ªnull‚Å‚ ‚é‚ƍl‚¦‚Ü‚·B
+            ‚±‚ê‚Í‘å’ï‚̏ꍇ–â‘è‚ ‚è‚Ü‚¹‚ñB
+
+        </para>
+
+        <para>
+            ƒRƒ“ƒ|[ƒlƒ“ƒg‚Ì‘®«‚Í‚Ç‚ñ‚ÈHibernate‚ÌŒ^‚Å‚à\‚¢‚Ü‚¹‚ñiƒRƒŒƒNƒVƒ‡ƒ“Amany-to-oneŠÖ˜AA
+            ‘¼‚̃Rƒ“ƒ|[ƒlƒ“ƒg‚ȂǁjBƒlƒXƒg‚³‚ꂽƒRƒ“ƒ|[ƒlƒ“ƒg‚Í–Å‘½‚ÉŽg‚í‚È‚¢‚ƍl‚¦‚é‚ׂ«‚Å‚Í
+             <emphasis>‚ ‚è‚Ü‚¹‚ñ</emphasis> BHibernate‚Í”ñí‚É‚«‚߂ׂ̍©‚¢ƒIƒuƒWƒFƒNƒgƒ‚ƒfƒ‹‚ðƒTƒ|[ƒg‚·‚é‚悤‚ɈӐ}‚³‚ê‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <para>
+            <literal>&lt;component&gt;</literal> —v‘f‚͐eƒGƒ“ƒeƒBƒeƒB‚Ö‚Ì‹tŽQÆ‚Æ‚µ‚āAƒRƒ“ƒ|[ƒlƒ“ƒgƒNƒ‰ƒX‚Ì
+            ‘®«‚ðƒ}ƒbƒsƒ“ƒO‚·‚é <literal>&lt;parent&gt;</literal> ƒTƒu—v‘f‚ðŽg—p‚Å‚«‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Person" table="person">
+    <id name="Key" column="pid" type="string">
+        <generator class="uuid"/>
+    </id>
+    <property name="birthday" type="date"/>
+    <component name="Name" class="eg.Name" unique="true">
+        <parent name="namedPerson"/> <!-- reference back to the Person -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </component>
+</class>]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="components-incollections" revision="1">
+        
+        <title>]‘®‚·‚éƒIƒuƒWƒFƒNƒg‚̃RƒŒƒNƒVƒ‡ƒ“</title>
+
+        <para>
+            Hibernate‚̓Rƒ“ƒ|[ƒlƒ“ƒg‚̃RƒŒƒNƒVƒ‡ƒ“‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·i—Ⴆ‚Î <literal>Name</literal> Œ^‚Ì”z—ñjB
+            <literal>&lt;element&gt;</literal> ƒ^ƒO‚ð <literal>&lt;composite-element&gt;</literal> ƒ^ƒO‚ÉŽæ‚è‘Ö‚¦‚邱‚Æ‚É‚æ‚è
+            ƒRƒ“ƒ|[ƒlƒ“ƒgƒRƒŒƒNƒVƒ‡ƒ“‚ðéŒ¾‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
+    <key column="id"/>
+    <composite-element class="eg.Name"> <!-- class attribute required -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </composite-element>
+</set>]]></programlisting>
+
+        <para>
+            ’ˆÓ: ƒRƒ“ƒ|ƒWƒbƒgƒGƒŒƒƒ“ƒg‚Ì <literal>Set</literal> ‚ð’è‹`‚µ‚½‚È‚çA
+            <literal>equals()</literal> ‚Æ <literal>hashCode()</literal> ‚𐳂µ‚­ŽÀ‘•‚·‚邱‚Æ‚ªd—v‚Å‚·B
+        </para>
+
+        <para>
+            ƒRƒ“ƒ|ƒWƒbƒgƒGƒŒƒƒ“ƒg‚̓RƒŒƒNƒVƒ‡ƒ“‚ðŠÜ‚Ü‚¸AƒRƒ“ƒ|[ƒlƒ“ƒg‚ðŠÜ‚Þ‚±‚Æ‚à‚ ‚è‚Ü‚·B
+            ƒRƒ“ƒ|ƒWƒbƒgƒGƒŒƒƒ“ƒgŽ©g‚ªƒRƒ“ƒ|[ƒlƒ“ƒg‚ðŠÜ‚ñ‚Å‚¢‚éê‡‚Í <literal>&lt;nested-composite-element&gt;</literal> ‚ð
+            Žg—p‚µ‚Ä‚­‚¾‚³‚¢BƒRƒ“ƒ|[ƒlƒ“ƒg‚̃RƒŒƒNƒVƒ‡ƒ“Ž©g‚ªƒRƒ“ƒ|[ƒlƒ“ƒg‚ðŽ‚Â‚Æ‚¢‚¤ƒP[ƒX‚Í‚ß‚Á‚½‚É‚ ‚è‚Ü‚¹‚ñB
+            ‚±‚Ì’iŠK‚܂łɁAone-to-manyŠÖ˜A‚Ì•û‚ª‚æ‚è“KØ‚Å‚È‚¢‚©‚Ənl‚µ‚Ä‚­‚¾‚³‚¢B
+            ƒRƒ“ƒ|ƒWƒbƒgƒGƒŒƒƒ“ƒg‚ðƒGƒ“ƒeƒBƒeƒB‚Æ‚µ‚čēxƒ‚ƒfƒŠƒ“ƒO‚µ‚Ä‚Ý‚Ä‚­‚¾‚³‚¢B
+            ‚µ‚©‚µ‚±‚ê‚ÍJava‚̃‚ƒfƒ‹‚Æ‚µ‚Ä‚Í“¯‚¶‚Å‚·‚ªAƒŠƒŒ[ƒVƒ‡ƒiƒ‹ƒ‚ƒfƒ‹‚Ɖi‘±“®ì‚Í‚Ü‚¾ŽáŠ±ˆÙ‚Ȃ邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <para>
+            ‚à‚µ <literal>&lt;set&gt;</literal> ‚ðŽg—p‚·‚é‚Ì‚Å‚ ‚ê‚΁AƒRƒ“ƒ|ƒWƒbƒgƒGƒŒƒƒ“ƒg‚̃}ƒbƒsƒ“ƒO‚ªnull’l‚ª‰Â”\‚È
+            ‘®«‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢BHibernate‚̓IƒuƒWƒFƒNƒg‚ðíœ‚·‚é‚Æ‚«A
+            ƒŒƒR[ƒh‚ðŽ¯•Ê‚·‚邽‚ß‚É‚»‚ꂼ‚ê‚̃Jƒ‰ƒ€‚Ì’l‚ðŽg—p‚·‚é•K—v‚ª‚ ‚邽‚߁Anull’l‚ðŽ‚Â‚±‚Æ‚ªo—ˆ‚Ü‚¹‚ñ
+            iƒRƒ“ƒ|ƒWƒbƒgƒGƒŒƒƒ“ƒgƒe[ƒuƒ‹‚É‚Í•Ê‚ÌŽåƒL[ƒJƒ‰ƒ€‚Í‚ ‚è‚Ü‚¹‚ñjB
+            ƒRƒ“ƒ|ƒWƒbƒgƒGƒŒƒƒ“ƒg‚Énot-null‚Ì‘®«‚Ì‚Ý‚ðŽg—p‚·‚é‚©A‚Ü‚½‚Í <literal>&lt;list&gt;</literal>A<literal>&lt;map&gt;</literal>A
+            <literal>&lt;bag&gt;</literal>A<literal>&lt;idbag&gt;</literal> ‚ð‘I‘ð‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+        </para>
+
+        <para>
+            ƒRƒ“ƒ|ƒWƒbƒgƒGƒŒƒƒ“ƒg‚Ì“Á•Ê‚ȃP[ƒX‚Æ‚µ‚āAƒlƒXƒg‚³‚ꂽ <literal>&lt;many-to-one&gt;</literal> ‘®«‚ðŽ‚Â
+            ƒRƒ“ƒ|ƒWƒbƒgƒGƒŒƒƒ“ƒg‚ª‚ ‚è‚Ü‚·B
+            ‚±‚̃}ƒbƒsƒ“ƒO‚́AƒRƒ“ƒ|ƒWƒbƒgƒGƒŒƒƒ“ƒgƒNƒ‰ƒX‚𑽑Α½ŠÖ˜Aƒe[ƒuƒ‹‚Ì
+            —]•ª‚ȃJƒ‰ƒ€‚Öƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+            ŽŸ‚Ì—á‚Í <literal>Order</literal> ‚©‚çA<literal>Item</literal> ‚Ö‚Ì‘½‘Α½ŠÖ˜A‚Å‚·B
+             <literal>purchaseDate</literal>A<literal>price</literal>A<literal>quantity</literal> ‚ÍŠÖ˜A‚Ì‘®«‚Æ‚È‚è‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Order" .... >
+    ....
+    <set name="purchasedItems" table="purchase_items" lazy="true">
+        <key column="order_id">
+        <composite-element class="eg.Purchase">
+            <property name="purchaseDate"/>
+            <property name="price"/>
+            <property name="quantity"/>
+            <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            ‚à‚¿‚ë‚ñA‘o•ûŒüŠÖ˜A‚̃iƒrƒQ[ƒVƒ‡ƒ“‚Ì‚½‚ß‚É”½‘Α¤‚©‚çpurchase‚Ö‚ÌŽQÆ‚ðì‚邱‚Ƃ͏o—ˆ‚Ü‚¹‚ñB
+            ƒRƒ“ƒ|[ƒlƒ“ƒg‚Í’lŒ^‚Å‚ ‚èAŽQÆ‚ð‹¤—L‚Å‚«‚È‚¢‚±‚Æ‚ðŠo‚¦‚Ä‚¨‚¢‚Ä‚­‚¾‚³‚¢B
+            ˆê‚Â‚Ì <literal>Purchase</literal> ‚͈ê‚Â‚Ì <literal>Order</literal> ‚Ìset‚É‘¶Ý‚Å‚«‚Ü‚·‚ªA
+            “¯Žž‚É <literal>Item</literal> ‚©‚çŽQÆ‚·‚邱‚Ƃ͏o—ˆ‚Ü‚¹‚ñB
+        </para>
+
+        <para>
+              3€ŠÖ˜Ai‚ ‚é‚¢‚Í4€‚Ȃǁj‚à‰Â”\‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Order" .... >
+    ....
+    <set name="purchasedItems" table="purchase_items" lazy="true">
+        <key column="order_id">
+        <composite-element class="eg.OrderLine">
+            <many-to-one name="purchaseDetails" class="eg.Purchase"/>
+            <many-to-one name="item" class="eg.Item"/>
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            ƒRƒ“ƒ|ƒWƒbƒgƒGƒŒƒƒ“ƒg‚Í‘¼‚̃Gƒ“ƒeƒBƒeƒB‚Ö‚ÌŠÖ˜A‚Æ‚µ‚āA
+            “¯‚¶ƒVƒ“ƒ^ƒbƒNƒX‚ðŽg‚Á‚Ä‚¢‚éƒNƒGƒŠ“à‚ÅŽg—p‚Å‚«‚Ü‚·B
+        </para>
+
+    </sect1>
+
+    <sect1 id="components-asmapindex">
+        <title>Map‚̃Cƒ“ƒfƒbƒNƒX‚Æ‚µ‚ẴRƒ“ƒ|[ƒlƒ“ƒg</title>
+
+        <para>
+            <literal>&lt;composite-map-key&gt;</literal> —v‘f‚Í <literal>Map</literal> ‚̃L[‚Æ‚µ‚ăRƒ“ƒ|[ƒlƒ“ƒgƒNƒ‰ƒX‚ð
+            ƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·BƒRƒ“ƒ|[ƒlƒ“ƒgƒNƒ‰ƒXã‚Å <literal>hashCode()</literal> ‚Æ <literal>equals()</literal>
+            ‚𐳊m‚ɃI[ƒo[ƒ‰ƒCƒh‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+    </sect1>
+
+    <sect1 id="components-compositeid" revision="1">
+        <title>•¡‡Ž¯•ÊŽq‚Æ‚µ‚ẴRƒ“ƒ|[ƒlƒ“ƒg</title>
+
+        <para>
+            ƒRƒ“ƒ|[ƒlƒ“ƒg‚ðƒGƒ“ƒeƒBƒeƒBƒNƒ‰ƒX‚ÌŽ¯•ÊŽq‚Æ‚µ‚ÄŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+            ƒRƒ“ƒ|[ƒlƒ“ƒgƒNƒ‰ƒX‚͈ȉº‚ÌðŒ‚ð–ž‚½‚·•K—v‚ª‚ ‚è‚Ü‚·B
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>java.io.Serializable</literal> ‚ðŽÀ‘•‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ƒf[ƒ^ƒx[ƒXã‚Ì•¡‡ƒL[‚Ì“™‰¿«‚Æ–µ‚‚Ì‚È‚¢‚悤‚ɁA<literal>equals()</literal> 
+                    ‚Æ <literal>hashCode()</literal> ‚ðÄŽÀ‘•‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            <emphasis>’ˆÓ: Hibernate3‚É‚¨‚¢‚āA2”Ô–Ú‚ÌðŒ‚Íâ‘ΓI‚ÈðŒ‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+                  ‚µ‚©‚µ‚Æ‚É‚©‚­ðŒ‚ð–ž‚½‚µ‚Ä‚­‚¾‚³‚¢B
+            </emphasis> 
+
+        </para>
+
+        <para>
+            •¡‡ƒL[‚𐶐¬‚·‚邽‚ß‚É <literal>IdentifierGenerator</literal> ‚ðŽg—p‚·‚邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñB
+            ‘ã‚í‚è‚ɃAƒvƒŠƒP[ƒVƒ‡ƒ“‚ªŽ¯•ÊŽq‚ðŠ„‚è“–‚Ä‚È‚­‚Ä‚Í‚È‚è‚Ü‚¹‚ñB
+        </para>
+
+        <para>
+            ’ʏí‚Ì <literal>&lt;id&gt;</literal> éŒ¾‚Ì‘ã‚í‚è‚É <literal>&lt;composite-id&gt;</literal> ƒ^ƒO‚ð
+            iƒlƒXƒg‚³‚ꂽ <literal>&lt;key-property&gt;</literal> ‘®«‚Æ‹¤‚ɁjŽg‚¢‚Ü‚·B
+            ˆÈ‰º‚Ì—á‚ł́A<literal>OrderLine</literal> ƒNƒ‰ƒX‚Í <literal>Order</literal> ‚́i•¡‡jŽåƒL[‚É
+            ˆË‘¶‚µ‚½ŽåƒL[‚ðŽ‚Á‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="OrderLine">
+    
+    <composite-id name="id" class="OrderLineId">
+        <key-property name="lineId"/>
+        <key-property name="orderId"/>
+        <key-property name="customerId"/>
+    </composite-id>
+    
+    <property name="name"/>
+    
+    <many-to-one name="order" class="Order"
+            insert="false" update="false">
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </many-to-one>
+    ....
+    
+</class>]]></programlisting>
+
+        <para>
+            ‚±‚Ì‚Æ‚«A<literal>OrderLine</literal> ƒe[ƒuƒ‹‚ÖŠÖ˜A‚·‚éŠO•”ƒL[‚à‚Ü‚½•¡‡‚Å‚·B
+            ‘¼‚̃Nƒ‰ƒX‚̃}ƒbƒsƒ“ƒO‚Å‚±‚ê‚ðéŒ¾‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            <literal>OrderLine</literal> ‚Ö‚ÌŠÖ˜A‚ÍŽŸ‚̂悤‚Ƀ}ƒbƒsƒ“ƒO‚³‚ê‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
+<!-- the "class" attribute is optional, as usual -->
+    <column name="lineId"/>
+    <column name="orderId"/>
+    <column name="customerId"/>
+</many-to-one>]]></programlisting>
+
+        <para>
+            i<literal>&lt;column&gt;</literal> ƒ^ƒO‚Í‚Ç‚±‚Å‚ ‚Á‚Ä‚à <literal>column</literal> ‘®«‚Ì
+              ‘ã‚í‚è‚É‚È‚è‚Ü‚·Bj
+        </para>
+        
+        <para>
+            <literal>OrderLine</literal> ‚Ö‚Ì <literal>many-to-many</literal> ŠÖ˜A‚à
+            •¡‡ŠO•”ƒL[‚ðŽg‚¢‚Ü‚·B
+        </para>
+    
+    <programlisting><![CDATA[<set name="undeliveredOrderLines">
+    <key column name="warehouseId"/>
+    <many-to-many class="OrderLine">
+        <column name="lineId"/>
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </many-to-many>
+</set>]]></programlisting>
+
+        <para>
+            <literal>Order</literal> ‚É‚ ‚é <literal>OrderLine</literal> ‚̃RƒŒƒNƒVƒ‡ƒ“‚Í
+            ŽŸ‚Ì‚à‚Ì‚ðŽg—p‚µ‚Ü‚·B
+        </para>
+
+    <programlisting><![CDATA[<set name="orderLines" inverse="true">
+    <key>
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </key>
+    <one-to-many class="OrderLine"/>
+</set>]]></programlisting>
+
+        <para>
+            i<literal>&lt;one-to-many&gt;</literal> ‘®«‚́A—á‚É‚æ‚Á‚ăJƒ‰ƒ€‚ðéŒ¾‚µ‚Ü‚¹‚ñj
+        </para>
+        
+        <para>
+            <literal>OrderLine</literal> Ž©g‚ªƒRƒŒƒNƒVƒ‡ƒ“‚ðŽ‚Á‚Ä‚¢‚éê‡A
+            “¯Žž‚É•¡‡ŠO•”ƒL[‚àŽ‚Á‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="OrderLine">
+    ....
+    ....
+    <list name="deliveryAttempts">
+        <key>   <!-- a collection inherits the composite key type -->
+            <column name="lineId"/>
+            <column name="orderId"/>
+            <column name="customerId"/>
+        </key>
+        <list-index column="attemptId" base="1"/>
+        <composite-element class="DeliveryAttempt">
+            ...
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="components-dynamic" revision="1">
+        <title>“®“IƒRƒ“ƒ|[ƒlƒ“ƒg</title>
+
+        <para>
+            <literal>Map</literal> Œ^‚̃vƒƒpƒeƒB‚̃}ƒbƒsƒ“ƒO‚à‰Â”\‚Å‚·B
+        </para>
+
+    <programlisting><![CDATA[<dynamic-component name="userAttributes">
+    <property name="foo" column="FOO" type="string"/>
+    <property name="bar" column="BAR" type="integer"/>
+    <many-to-one name="baz" class="Baz" column="BAZ_ID"/>
+</dynamic-component>]]></programlisting>
+
+        <para>
+            <literal>&lt;dynamic-component&gt;</literal> ƒ}ƒbƒsƒ“ƒO‚̃Zƒ}ƒ“ƒeƒBƒNƒX‚Í <literal>&lt;component&gt;</literal> 
+            ‚Æ“¯ˆê‚Ì‚à‚Ì‚Å‚·B‚±‚ÌŽí‚̃}ƒbƒsƒ“ƒO‚Ì—˜“_‚́Aƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚̕ҏW‚É‚æ‚èA”z’uŽž‚Ébean‚Ì‘®«‚ð
+            Œˆ’è‚Å‚«‚é“_‚Å‚·B‚Ü‚½ADOMƒp[ƒT‚ð—˜—p‚µ‚āAƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚̃‰ƒ“ƒ^ƒCƒ€‘€ì‚ª‰Â”\‚Å‚·B
+            ‚³‚ç‚ɁA<literal>Configuration</literal> ƒIƒuƒWƒFƒNƒgŒo—R‚ÅHibernate‚̃Rƒ“ƒtƒBƒOƒŒ[ƒVƒ‡ƒ“Žž‚̃ƒ^ƒ‚ƒfƒ‹‚É
+            ƒAƒNƒZƒXi‚Ü‚½‚͕ύXj‚ª‰Â”\‚Å‚·B
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/configuration.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/configuration.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/configuration.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1725 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="session-configuration" revision="1">
+
+    <title>Ý’è</title>
+    
+    <para>
+        Hibernate‚Í‚³‚Ü‚´‚܂Ȋ‹«‚Å“®ì‚·‚é‚悤‚ɃfƒUƒCƒ“‚³‚ê‚Ä‚¢‚邽‚߁A”ñí‚É‘½‚­‚̐ݒè—v‘f‚ª‚ ‚è‚Ü‚·B
+        K‚¢‚È‚±‚ƂɁAHibernate‚́AŒöŠJ‚³‚ê‚Ä‚¢‚éƒpƒbƒP[ƒW‚Ì <literal>etc/</literal> ƒtƒHƒ‹ƒ_‚Ì <literal>hibernate.properties</literal> 
+        ‚ɁA‚Ù‚Æ‚ñ‚ǂ̐ݒè—v‘f‚Ì“KØ‚ȃfƒtƒHƒ‹ƒg’l‚ª‹Lq‚³‚ê‚Ä‚¢‚Ü‚·B
+        ‚±‚Ì <literal>hibernate.properties</literal> ‚ðƒNƒ‰ƒXƒpƒX‚ɐݒ肵AÝ’è—v‘f‚ðƒJƒXƒ^ƒ}ƒCƒY‚·‚邾‚¯‚Å‚·B
+    </para>
+
+    <sect1 id="configuration-programmatic" revision="1">
+        <title>ƒvƒƒOƒ‰ƒ€ã‚̐ݒè</title>
+
+        <para>
+             <literal>org.hibernate.cfg.Configuration</literal> ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚́A
+            Java‚ÌŒ^‚ÆSQLƒf[ƒ^ƒx[ƒX‚̃}ƒbƒsƒ“ƒOî•ñ‚ð‚·‚×‚ÄŽ‚Á‚Ä‚¢‚Ü‚·B
+            The  <literal>Configuration</literal> ‚́Ai•s•Ï‚́j <literal>SessionFactory</literal> 
+            ‚𐶐¬‚·‚é‚Æ‚«‚ÉŽg—p‚µ‚Ü‚·B
+            •¡”‚ÌXMLƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ð•ÏŠ·‚µAƒ}ƒbƒsƒ“ƒOî•ñ‚É‚µ‚Ü‚·B
+        </para>
+
+        <para>
+            ’ʏíA<literal>Configuration</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚́A“Á’è‚ÌXMLƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹
+            ‚É‚æ‚Á‚Ä’¼Ú‰Šú‰»‚³‚ê‚Ü‚·B‚à‚µAƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ªƒNƒ‰ƒXƒpƒX‚ɐݒ肳‚ê‚Ä‚¢‚éê‡A
+            ŽŸ‚̃ƒ\ƒbƒh‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢B <literal>addResource()</literal> :
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addResource("Item.hbm.xml")
+    .addResource("Bid.hbm.xml");]]></programlisting>
+
+        <para>
+            ‘ã‘ÖˆÄ(‚±‚¿‚ç‚Ì‚Ù‚¤‚ª—Ç‚¢‚Æ‚«‚à‚ ‚è‚Ü‚·)‚Æ‚µ‚ă}ƒbƒsƒ“ƒOƒNƒ‰ƒX‚ðŽw’è‚·‚é•û–@‚à‚ ‚è‚Ü‚·BHibernate‚ɁAƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ð
+            Œ©‚‚¯‚³‚¹‚Ä‚­‚¾‚³‚¢F
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addClass(org.hibernate.auction.Item.class)
+    .addClass(org.hibernate.auction.Bid.class);]]></programlisting>
+
+        <para>
+            Hibernate‚́AƒNƒ‰ƒXƒpƒX‚É‚ ‚éˆÈ‰º‚̂悤‚È–¼‘O‚̃}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ðŒ©‚Â‚¯‚Ü‚·B
+            <literal>/org/hibernate/auction/Item.hbm.xml</literal> A
+            <literal>/org/hibernate/auction/Bid.hbm.xml</literal> B
+            ‚±‚Ì•û–@‚¾‚ƁAƒn[ƒhƒR[ƒfƒBƒ“ƒO‚³‚ꂽƒtƒ@ƒCƒ‹–¼‚ð”rœ‚Å‚«‚Ü‚·B
+        </para>
+        
+        <para>
+            <literal>Configuration</literal> ‚́AÝ’èƒvƒƒpƒeƒB‚ðŽw’è‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·F
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addClass(org.hibernate.auction.Item.class)
+    .addClass(org.hibernate.auction.Bid.class)
+    .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
+    .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
+    .setProperty("hibernate.order_updates", "true");]]></programlisting>
+    
+        <para>
+            Hibernate‚ɐݒèƒvƒƒpƒeƒB‚ð’Ê‚·•û–@‚Í1‚‚ł͂ ‚è‚Ü‚¹‚ñB
+            ‚³‚Ü‚´‚܂ȃIƒvƒVƒ‡ƒ“‚ð—pˆÓ‚µ‚Ä‚¢‚Ü‚·F
+        </para>
+
+        <orderedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>java.util.Properties</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚ð
+                    <literal>Configuration.setProperties()</literal> ‚É“n‚µ‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>hibernate.properties</literal> ‚ð
+                    ƒNƒ‰ƒXƒpƒX‚̃‹[ƒgƒfƒBƒŒƒNƒgƒŠ‚É’u‚«‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>System</literal> ƒvƒƒpƒeƒB‚ª
+                    <literal>java -Dproperty=value</literal> ‚ðŽg‚¤‚悤‚ɐݒ肵‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>&lt;property&gt;</literal> —v‘f‚ð
+                    <literal>hibernate.cfg.xml</literal> iŒãqj‚ɐݒ肵‚Ü‚·B
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <para>
+            ¡‚·‚®Žn‚ß‚½‚¢‚Ì‚È‚çA<literal>hibernate.properties</literal> 
+            ‚ðŽg‚¤‚Ì‚ªˆê”Ô‚Ì‹ß“¹‚Å‚·B
+        </para>
+
+        <para>
+            <literal>Configuration</literal> ‚́A‹N“®Žž‚É‚¾‚¯‚ ‚éƒIƒuƒWƒFƒNƒg‚Å‚ ‚èA
+            ˆê“x <literal>SessionFactory</literal> ‚𐶐¬‚µ‚½Œã‚́A”jŠü‚³‚ê‚邱‚Æ‚ðˆÓ}‚µ‚Ä‚¢‚Ü‚·B
+        </para>
+
+    </sect1>
+    
+    <sect1 id="configuration-sessionfactory">
+        <title>SessionFactory‚ðŽæ“¾‚·‚é</title>
+
+        <para>
+            <literal>Configuration</literal> ‚ª‚·‚ׂẴ}ƒbƒsƒ“ƒOî•ñ‚ð‰ðÍ‚µ‚½‚çA
+            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚́A <literal>Session</literal> ƒtƒ@ƒNƒgƒŠƒCƒ“ƒXƒ^ƒ“ƒX‚ðŽæ“¾‚µ‚Ü‚·B
+            ‚±‚ÌSessionFactory‚́AHibernate‚ðŽg—p‚·‚é‚·‚ׂẴXƒŒƒbƒh‚Å‹¤—L‚³‚ê‚é‚ׂ«‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sessions = cfg.buildSessionFactory();]]></programlisting>
+
+        <para>
+            Hibernate‚́A <literal>SessionFactory</literal> ‚𕡐”¶¬‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            ‚±‚ê‚́A•¡”‚̃f[ƒ^ƒx[ƒX‚ðŽg—p‚·‚éê‡‚É•Ö—˜‚Å‚·B
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-hibernatejdbc" revision="1">
+        <title>JDBCƒRƒlƒNƒVƒ‡ƒ“</title>
+
+        <para>
+            ’ʏíAŠJ”­ŽÒ‚Í <literal>SessionFactory</literal> ‚𐶐¬‚µASessionFactory‚ÅJDBCƒRƒlƒNƒVƒ‡ƒ“‚ðƒv[ƒŠƒ“ƒO‚µ‚½‚¢‚ƍl‚¦‚Ü‚·B
+            ‚»‚̃Aƒvƒ[ƒ`‚ðÌ—p‚·‚éê‡A’Pƒ‚É <literal>Session</literal> ‚ðƒI[ƒvƒ“‚µ‚Ä‚­‚¾‚³‚¢F
+        </para>
+
+        <programlisting><![CDATA[Session session = sessions.openSession(); // open a new Session]]></programlisting>
+        
+        <para>
+            ‚±‚ꂾ‚¯‚ŁAƒv[ƒŠƒ“ƒO‚µ‚½JDBCƒRƒlƒNƒVƒ‡ƒ“‚ðŽg‚Á‚Ä–Ú“I‚̃f[ƒ^ƒx[ƒX
+            ‚ɃAƒNƒZƒX‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+        </para>
+
+        <para>
+            ‚»‚Ì‚½‚߂ɂ́AJDBCƒRƒlƒNƒVƒ‡ƒ“‚̃vƒƒpƒeƒB‚ðHibernate‚ɐݒ肷‚é•K—v‚ª‚ ‚è‚Ü‚·B
+            ‚·‚ׂĂÌHibernateƒvƒƒpƒeƒB–¼‚ƃZƒ}ƒ“ƒeƒBƒNƒX‚Í
+            <literal>org.hibernate.cfg.Environment</literal> ƒNƒ‰ƒX‚É’è‹`‚³‚ê‚Ä‚¢‚Ü‚·B
+            ‚±‚̐ݒè‚ÍJDBCƒRƒlƒNƒVƒ‡ƒ“Ý’è‚Ì’†‚ňê”ԏd—v‚È‚à‚Ì‚Å‚·B
+        </para>
+
+        <para>
+            ‚à‚µAˆÈ‰º‚̃vƒƒpƒeƒB‚ðÝ’è‚·‚é‚ƁAHibernate‚̓RƒlƒNƒVƒ‡ƒ“‚ðŽæ“¾‚·‚éiƒv[ƒ‹‚àj‚½‚ß‚É
+            <literal>java.sql.DriverManager</literal> ‚ðŽg‚¢‚Ü‚·B
+        </para>
+
+        <table frame="topbot">
+            <title>Hibernate JDBCƒvƒƒpƒeƒB</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>ƒvƒƒpƒeƒB–¼</entry>
+                        <entry>ˆÓ–¡</entry>
+                    </row>
+                </thead>
+            <tbody>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.driver_class</literal>
+                </entry>
+                <entry>
+                    <emphasis>JDBCƒhƒ‰ƒCƒoƒNƒ‰ƒX</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.url</literal>
+                </entry>
+                <entry>
+                    <emphasis>jdbc URL</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.username</literal>
+                </entry>
+                <entry>
+                    <emphasis>database user</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.password</literal>
+                </entry>
+                <entry>
+                    <emphasis>database user password</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.pool_size</literal>
+                </entry>
+                <entry>
+                    <emphasis>ƒv[ƒ‹‚·‚éƒRƒlƒNƒVƒ‡ƒ“‚̍ő吔</emphasis>
+                </entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+            Hibernate‚̃RƒlƒNƒVƒ‡ƒ“ƒv[ƒ‹ƒAƒ‹ƒSƒŠƒYƒ€‚Í”ñí‚ɏ‰•à“I‚È‚à‚Ì‚Å‚·B
+            ‚±‚ê‚Í‚·‚®‚ÉŽn‚ß‚ç‚ê‚é‚悤‚É‚Æ—pˆÓ‚³‚ꂽ‚à‚̂ŁA<emphasis>»•i‚Æ‚µ‚ÄŽg—p‚·‚邱‚Æ‚ðˆÓ}‚µ‚Ä‚¢‚Ü‚¹‚ñ</emphasis> B
+            ‚Ü‚½AƒpƒtƒH[ƒ}ƒ“ƒX‚̃eƒXƒg‚Ì‚½‚ß‚Ì‚à‚Ì‚Å‚à‚ ‚è‚Ü‚¹‚ñB
+            Å‚‚̃pƒtƒH[ƒ}ƒ“ƒX‚ƈÀ’萫‚ðŽ‚Á‚½ƒv[ƒ‹‚ðŽÀŒ»‚µ‚½‚¯‚ê‚΁AƒT[ƒhƒp[ƒeƒB‚̃c[ƒ‹‚ð‚¨Š©‚ß‚µ‚Ü‚·B
+            <literal>hibernate.connection.pool_size</literal> ƒvƒƒpƒeƒB‚É
+            “KØ‚ȃRƒlƒNƒVƒ‡ƒ“ƒv[ƒ‹ƒTƒCƒY‚ð‹Lq‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚±‚Ì‚Ü‚Ü‚¾‚ÆHibernate‚̃RƒlƒNƒVƒ‡ƒ“ƒv[ƒ‹‚ðŽg‚¢‚Ü‚·B
+            —Ⴆ‚ÎŽŸ‚̂悤‚ÉC3P0‚ðŽg‚¢‚Ü‚·B
+        </para>
+
+        <para>
+            C3P0‚̓I[ƒvƒ“ƒ\[ƒXJDBCƒRƒlƒNƒVƒ‡ƒ“ƒv[ƒ‹‚ŁAHibernate‚Ì <literal>lib</literal> 
+            ƒfƒBƒŒƒNƒgƒŠ‚É‚ ‚è‚Ü‚·B‚à‚µA<literal>hibernate.c3p0.*</literal> ƒvƒƒpƒeƒB‚ð
+            ƒZƒbƒg‚·‚ê‚΁AHibernate‚́A <literal>C3P0ConnectionProvider</literal> ‚ðŽg‚¢‚Ü‚·B
+            ‚à‚µProxool‚ðŽg‚¢‚½‚¢ê‡‚́A <literal>hibernate.properties</literal> ƒpƒbƒP[ƒW‚ð
+            ŽQÆ‚µ‚½‚èAHibernate‚ÌWebƒTƒCƒg‚Å‚æ‚葽‚­‚̏î•ñ‚ðŽæ“¾‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <para>
+            C3P0—p‚Ì <literal>hibernate.properties</literal> ƒtƒ@ƒCƒ‹‚ð—á‚Æ‚µ‚ÄŽ¦‚µ‚Ü‚·F
+        </para>
+
+        <programlisting id="c3p0-configuration" revision="1"><![CDATA[hibernate.connection.driver_class = org.postgresql.Driver
+hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
+hibernate.connection.username = myuser
+hibernate.connection.password = secret
+hibernate.c3p0.min_size=5
+hibernate.c3p0.max_size=20
+hibernate.c3p0.timeout=1800
+hibernate.c3p0.max_statements=50
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+        <para>
+            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒoã‚ÅŽg‚¤ê‡‚́AHibernate‚ðÝ’肵A
+            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo‚©‚çƒRƒlƒNƒVƒ‡ƒ“‚ðŽæ“¾‚·‚é‚悤‚É‚µ‚Ä‚­‚¾‚³‚¢B
+            <literal>Datasource</literal> ‚ðJNDI‚É“o˜^‚µ‚Ü‚·B‚»‚µ‚Ä
+            ƒvƒƒpƒeƒB‚ðˆÈ‰º‚̂悤‚ɐݒ肵‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <table frame="topbot">
+            <title>Hibernate ƒf[ƒ^ƒ\[ƒXƒvƒƒpƒeƒB</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>ƒvƒƒpƒeƒB–¼</entry>
+                        <entry>ˆÓ–¡</entry>
+                    </row>
+                </thead>
+            <tbody>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.datasource</literal>
+                </entry>
+                <entry>
+                    <emphasis>ƒf[ƒ^ƒ\[ƒX‚ÌJNDI–¼</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.jndi.url</literal>
+                </entry>
+                <entry>
+                    <emphasis>JNDIƒvƒƒoƒCƒ_‚ÌURL</emphasis> (ƒIƒvƒVƒ‡ƒ“)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.jndi.class</literal>
+                </entry>
+                <entry>
+                    <emphasis>JNDIƒNƒ‰ƒX <literal>InitialContextFactory</literal> </emphasis> (ƒIƒvƒVƒ‡ƒ“) 
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.username</literal>
+                </entry>
+                <entry>
+                    <emphasis>database user</emphasis> (ƒIƒvƒVƒ‡ƒ“)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.password</literal>
+                </entry>
+                <entry>
+                    <emphasis>database user password</emphasis> (ƒIƒvƒVƒ‡ƒ“)
+                </entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo‚©‚ç’ñ‹Ÿ‚³‚ꂽJNDIƒf[ƒ^ƒ\[ƒX‚ðŽg‚¤
+            <literal>hibernate.properties</literal> ƒtƒ@ƒCƒ‹‚Ì—á‚ðŽ¦‚µ‚Ü‚·F
+        </para>
+
+        <programlisting><![CDATA[hibernate.connection.datasource = java:/comp/env/jdbc/test
+hibernate.transaction.factory_class = \
+    org.hibernate.transaction.JTATransactionFactory
+hibernate.transaction.manager_lookup_class = \
+    org.hibernate.transaction.JBossTransactionManagerLookup
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+        <para>
+            JNDIƒf[ƒ^ƒ\[ƒX‚©‚çŽæ“¾‚µ‚½JDBCƒRƒlƒNƒVƒ‡ƒ“‚́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo‚Ì
+            ƒRƒ“ƒeƒiŠÇ—ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÉŽ©“®“I‚ÉŽQ‰Á‚µ‚Ü‚·B
+        </para>
+
+        <para>
+            ”CˆÓ‚̃RƒlƒNƒVƒ‡ƒ“ƒvƒƒpƒeƒB‚́A—^‚¦‚ç‚ꂽh <literal>hibernate.connnection</literal> h
+            ƒvƒƒpƒeƒB–¼‚É‚æ‚Á‚Ä—^‚¦‚ç‚ê‚Ü‚·B—Ⴆ‚΁A <literal>charSet</literal> ‚ðÝ’肵‚½‚¢ê‡‚́A
+            <literal>hibernate.connection.charSet</literal> ‚ðŽg‚¢‚Ü‚·B
+        </para>
+
+        <para>
+            JDBCƒRƒlƒNƒVƒ‡ƒ“‚ðŽæ“¾‚·‚éí—ª‚ðŽ‚Â“ÆŽ©‚̃vƒ‰ƒOƒCƒ“‚ð’è‹`‚·‚éê‡‚́A
+            <literal>org.hibernate.connection.ConnectionProvider</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ð
+            ŽÀ‘•‚µ‚Ä‚­‚¾‚³‚¢B‚»‚µ‚āAŽÀ‘•ƒNƒ‰ƒX‚ð <literal>hibernate.connection.provider_class</literal> 
+            ‚ɐݒ肵‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-optional" revision="1">
+        <title>ƒIƒvƒVƒ‡ƒ“Ý’èƒvƒƒpƒeƒB</title>
+        
+        <para>
+            ‚±‚ê‚ç‚̃vƒƒpƒeƒB‚ÍHibernate‚Ì‹““®‚𐧌䂷‚é‚à‚Ì‚Å‚·B
+            ‚±‚ê‚ç‚̃vƒƒpƒeƒB‚Í‚·‚ׂđÓ–‚ȃfƒtƒHƒ‹ƒg’l‚ª‚ ‚èA”CˆÓ‚Őݒ肵‚Ü‚·B
+        </para>
+
+        <para>
+            <emphasis>’ˆÓF‚±‚ê‚ç‚̃vƒƒpƒeƒB‚Í"ƒVƒXƒeƒ€ƒŒƒxƒ‹"‚Ì‚Ý‚Å‚·B</emphasis> 
+            ƒVƒXƒeƒ€ƒŒƒxƒ‹ƒvƒƒpƒeƒB‚Í <literal>java -Dproperty=value</literal>  A‚à‚µ‚­‚Í
+            <literal>hibernate.properties</literal> ‚ł̂ݐݒè‰Â”\‚Å‚·B
+            ‚»‚êˆÈŠO‚̐ݒè•û–@‚Í <emphasis>‚ ‚è‚Ü‚¹‚ñ</emphasis> B
+        </para>
+
+        <table frame="topbot" id="configuration-optional-properties" revision="8">
+            <title>HibernateÝ’èƒvƒƒpƒeƒB</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>ƒvƒƒpƒeƒB–¼</entry>
+                        <entry>ˆÓ–¡</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.dialect</literal>
+                        </entry>
+                        <entry>
+                            Hibernate <literal>Dialect</literal> ƒNƒ‰ƒX–¼‚ª“ü‚è‚Ü‚·B
+                            ‚±‚ê‚̓ŠƒŒ[ƒVƒ‡ƒiƒ‹ƒf[ƒ^ƒx[ƒX‚²‚ƂɍœK‰»‚³‚ꂽSQL‚𐶐¬‚µ‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>full.classname.of.Dialect</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.show_sql</literal>
+                        </entry>
+                        <entry>
+                            ”­s‚³‚ꂽ‚·‚ׂĂÌSQL‚ðƒRƒ“ƒ\[ƒ‹‚ɏo—Í‚µ‚Ü‚·B
+                            ‚±‚ê‚̓ƒOƒJƒeƒSƒŠ‚Ì <literal>org.hibernate.SQL</literal> 
+                            ‚É <literal>debug</literal> ‚ðÝ’è‚·‚é•û–@‚Ì‘ã‘ÖŽè’i‚Å‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.format_sql</literal>
+                        </entry>
+                        <entry>
+                            ƒƒO‚ƃRƒ“ƒ\[ƒ‹‚ÌSQL‚ð”ü‚µ‚­•\Ž¦‚µ‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_schema</literal>
+                        </entry>
+                        <entry>
+                            ¶¬‚³‚ê‚éSQL•¶‚̃e[ƒuƒ‹‚ɐݒ肷‚éƒXƒL[ƒ}/ƒe[ƒuƒ‹ƒXƒy[ƒX‚Å‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>SCHEMA_NAME</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_catalog</literal>
+                        </entry>
+                        <entry>
+                            ¶¬‚³‚ê‚éSQL•¶‚̃e[ƒuƒ‹‚ɐݒ肷‚éƒJƒ^ƒƒO‚Å‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>CATALOG_NAME</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.session_factory_name</literal>
+                        </entry>
+                        <entry>
+                            <literal>SessionFactory</literal> ‚͐¶¬ŒãA‚±‚Ì–¼‘O‚ÅJNDI‚É“o˜^‚³‚ê‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>jndi/composite/name</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.max_fetch_depth</literal>
+                        </entry>
+                        <entry>
+                            ŠO•”Œ‹‡ƒtƒFƒbƒ`‚̍őå[“x‚ðÝ’肵‚Ü‚·BŒ‹‡‚·‚éŠÖ˜A‚Í
+                            ‘ΈêŠÖ˜A‚̂݁iˆê‘ΈêA‘½‘Έêj‚Å‚·B
+                            <literal>0</literal> ‚ðŽw’è‚·‚é‚ÆŠO•”Œ‹‡ƒtƒFƒbƒ`‚Í–³Œø‚É‚È‚è‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                „§‚·‚é’l‚Í <literal>0</literal> ‚©‚ç <literal>3</literal> ‚Å‚·B
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_batch_fetch_size</literal>
+                        </entry>
+                        <entry>
+                            ŠÖ˜AƒtƒFƒbƒ`‚̃fƒtƒHƒ‹ƒgƒoƒbƒ`ƒTƒCƒY‚ðŽw’肵‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                „§‚·‚é’l‚Í <literal>4</literal> , <literal>8</literal> , <literal>16</literal> ‚Å‚·B
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_entity_mode</literal>
+                        </entry>
+                        <entry>
+                            <literal>SessionFactory</literal> ‚©‚çƒZƒbƒVƒ‡ƒ“‚ðƒI[ƒvƒ“‚µ‚½‚Æ‚«‚É
+                            Žg—p‚·‚éƒGƒ“ƒeƒBƒeƒB‚̃fƒtƒHƒ‹ƒgƒ‚[ƒh‚ðÝ’肵‚Ü‚·B
+                            <para>
+                                <literal>dynamic-map</literal>, <literal>dom4j</literal>,
+                                <literal>pojo</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.order_updates</literal>
+                        </entry>
+                        <entry>
+                            €–Ú‚ªXV‚³‚ꂽ‚Æ‚«‚ɁA•Ê‚ÌSQL‚ÅŽåƒL[‚ðXV‚·‚邱‚Æ‚ð‹­§‚µ‚Ü‚·B
+                            ‚±‚̏ꍇA“¯ŽžŽÀs‰Â”\‚ȃVƒXƒeƒ€‚ł́A‚Ü‚ê‚ɃfƒbƒhƒƒbƒN‚ª”­¶‚·‚é‰Â”\«‚ª‚ ‚è‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.generate_statistics</literal>
+                        </entry>
+                        <entry>
+                            —LŒø‚̏ꍇAHibernate‚̓pƒtƒH[ƒ}ƒ“ƒXƒ`ƒ…[ƒjƒ“ƒO‚É
+                            —LŒø‚È“Œvî•ñ‚ðŽûW‚µ‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.use_identifer_rollback</literal>
+                        </entry>
+                        <entry>
+                            —LŒø‚̏ꍇAƒIƒuƒWƒFƒNƒg‚ªíœ‚³‚ꂽ‚Æ‚«‚É
+                            Ž¯•ÊŽqƒvƒƒpƒeƒB‚ðƒŠƒZƒbƒg‚µAƒfƒtƒHƒ‹ƒg’l‚É‚µ‚½‚à‚̂𐶐¬‚µ‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.use_sql_comments</literal>
+                        </entry>
+                        <entry>
+                            —LŒø‚̏ꍇASQL“à‚ɃRƒƒ“ƒg‚𐶐¬‚µ‚Ü‚·B‚±‚ê‚̓fƒoƒbƒN‚ð—eˆÕ‚É‚µ‚Ü‚·B
+                            ƒfƒtƒHƒ‹ƒg‚Ì’l‚Í <literal>false</literal> ‚Å‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-jdbc-properties" revision="8">
+            <title>Hibernate JDBC ‚ƃRƒlƒNƒVƒ‡ƒ“ƒvƒƒpƒeƒB</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>ƒvƒƒpƒeƒB–¼</entry>
+                        <entry>ˆÓ–¡</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.fetch_size</literal>
+                        </entry>
+                        <entry>
+                            ’l‚ª0‚Å‚È‚¢ê‡AJDBCƒtƒFƒbƒ`ƒTƒCƒY‚ðŒˆ’è‚µ‚Ü‚·
+                            ( <literal>Statement.setFetchSize()</literal> ‚ðŒÄ‚Ñ‚Ü‚·)B
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.batch_size</literal>
+                        </entry>
+                        <entry>
+                            ’l‚ª0‚Å‚È‚¢ê‡AHibernate‚ªJDBC2ƒoƒbƒ`XV‚ðŽg—p‚µ‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis>
+                                „§‚·‚é’l‚Í <literal>5</literal> ‚©‚ç <literal>30</literal> ‚Å‚·B
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.batch_versioned_data</literal>
+                        </entry>
+                        <entry>
+                            ‚à‚µJDBCƒhƒ‰ƒCƒo‚ª <literal>executeBatch()</literal> ‚É‚æ‚Á‚Đ³Šm‚ȍs”‚ð
+                            •Ô‚·ê‡A‚±‚̃vƒƒpƒeƒB‚ð <literal>true</literal> ‚É‚µ‚Ä‚­‚¾‚³‚¢
+                            i’ʏí‚Í‚±‚̃IƒvƒVƒ‡ƒ“‚ðON‚É‚µ‚Ü‚·jB
+                            Hibernate‚́AŽ©“®ƒo[ƒWƒ‡ƒ“ƒf[ƒ^‚Ì‚½‚߃oƒbƒ`DML‚ðŽg‚¢‚Ü‚·B
+                            ƒfƒtƒHƒ‹ƒg‚Ì’l‚Í <literal>false</literal> ‚Å‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.factory_class</literal>
+                        </entry>
+                        <entry>
+                            ƒJƒXƒ^ƒ€ <literal>Batcher</literal> ‚ð‘I‚Ñ‚Ü‚·B
+                            ‚Ù‚Æ‚ñ‚ǂ̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚ɁA‚±‚̐ݒè‚Í•K—v‚ ‚è‚Ü‚¹‚ñB
+                            <para>
+                                <emphasis role="strong">—áF</emphasis>
+                                <literal>classname.of.Batcher</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_scrollable_resultset</literal>
+                        </entry>
+                        <entry>
+                            ƒXƒNƒ[ƒ‹‰Â”\‚ȃŠƒUƒ‹ƒgƒZƒbƒg‚ðAHibernate‚ªŽg—p‚µ‚Ü‚·B
+                            ‚±‚̃vƒƒpƒeƒB‚́AJDBCƒRƒlƒNƒVƒ‡ƒ“‚ªƒRƒlƒNƒVƒ‡ƒ“ƒƒ^ƒf[ƒ^‚ð
+                            ƒTƒ|[ƒg‚µ‚Ä‚¢‚邱‚Æ‚ª•K{ðŒ‚É‚È‚è‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_streams_for_binary</literal>
+                        </entry>
+                        <entry>
+                            JDBC‚Ö/‚©‚ç <literal>binary</literal> ‚â <literal>serializable</literal> 
+                            ‚̏‘‚«ž‚Ý/“ǂݍž‚݃XƒgƒŠ[ƒ€‚ðŽg‚¢‚Ü‚·(ƒVƒXƒeƒ€ƒŒƒxƒ‹‚̃vƒƒpƒeƒB)B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_get_generated_keys</literal>
+                        </entry>
+                        <entry>
+                            ‘}“ü‚ÌŒã‚ÉŽ©“®¶¬‚³‚ꂽŽåƒL[‚ðŽæ“¾‚·‚邽‚ß‚Ì 
+                            JDBC3 <literal>PreparedStatement.getGeneratedKeys()</literal> ‚ÌŽg—p‚ð—LŒø‚É‚µ‚Ü‚·B
+                            ‚±‚ê‚ÍJDBC3+ƒhƒ‰ƒCƒo‚ÆJRE1.4+‚ð•K—v‚Æ‚µA
+                            ‚à‚µHibernate‚ÌŽ¯•ÊŽqƒWƒFƒlƒŒ[ƒ^‚É–â‘肪”­¶‚·‚é‚悤‚È‚çfalse‚ɐݒ肵‚Ä‚­‚¾‚³‚¢B
+                            ƒfƒtƒHƒ‹ƒg‚ł̓RƒlƒNƒVƒ‡ƒ“ƒƒ^ƒf[ƒ^‚ðŽg‚¢ƒhƒ‰ƒCƒo‚Ì”\—Í‚ðŒˆ’è‚µ‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis>
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.provider_class</literal>
+                        </entry>
+                        <entry>
+                            JDBCƒRƒlƒNƒVƒ‡ƒ“‚ðHibernate‚É’ñ‹Ÿ‚·‚é“ÆŽ©‚Ì <literal>ConnectionProvider</literal> ‚Ì
+                            –¼‘O‚ðŽw’肵‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>classname.of.ConnectionProvider</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                    <entry>
+                        <literal>hibernate.connection.isolation</literal>
+                    </entry>
+                    <entry>
+                        JDBCƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“•ª—£ƒŒƒxƒ‹‚ðÝ’肵‚Ü‚·B
+                        ‘Ó–‚È’l‚𒲂ׂ邽‚ß‚É‚Í <literal>java.sql.Connection</literal> ‚ðƒ`ƒFƒbƒN‚µ‚Ä‚­‚¾‚³‚¢B
+                        ‚µ‚©‚µŽg—p‚·‚éƒf[ƒ^ƒx[ƒX‚ªA‚·‚ׂĂ̕ª—£ƒŒƒxƒ‹‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚é‚Æ‚ÍŒÀ‚è‚Ü‚¹‚ñB
+                        <para>
+                            <emphasis role="strong">—áF</emphasis> 
+                            <literal>1, 2, 4, 8</literal>
+                        </para>
+                    </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.autocommit</literal>
+                        </entry>
+                        <entry>
+                            ƒv[ƒ‹‚³‚ê‚Ä‚¢‚éJDBCƒRƒlƒNƒVƒ‡ƒ“‚ÌŽ©“®ƒRƒ~ƒbƒg‚ð—LŒø‚É‚·‚éi”ñ„§jB
+                            <para>
+                                <emphasis role="strong">—áF</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.release_mode</literal>
+                        </entry>
+                        <entry>
+                            Hibernate‚ªJDBCƒRƒlƒNƒVƒ‡ƒ“‚ðƒŠƒŠ[ƒX‚·‚é‚©‚ðŽw’肵‚Ü‚·BƒfƒtƒHƒ‹ƒg‚Å‚Í
+                            ƒZƒbƒVƒ‡ƒ“‚ª–¾Ž¦“I‚ɃNƒ[ƒY‚Ü‚½‚͐ؒf‚³‚ê‚Ä‚àƒRƒlƒNƒVƒ‡ƒ“‚Í•ÛŽ‚µ‚Ü‚·B
+                            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo‚ÌJTAƒf[ƒ^ƒ\[ƒX‚̏ꍇA
+                            ‚·‚ׂĂÌJDBCƒR[ƒ‹‚ÌŒãA‹­§“I‚ɃRƒlƒNƒVƒ‡ƒ“‚ðƒŠƒŠ[ƒX‚·‚邽‚ß‚É <literal>after_statement</literal> ‚ð
+                            Žg‚Á‚Ä‚­‚¾‚³‚¢B
+                            ”ñJTAƒRƒlƒNƒVƒ‡ƒ“‚̏ꍇAŠeƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ªI—¹‚µ‚½‚Æ‚«‚É <literal>after_transaction</literal> 
+                            ‚ðŽg‚¢AƒRƒlƒNƒVƒ‡ƒ“‚ðƒŠƒŠ[ƒX‚µ‚Ä‚­‚¾‚³‚¢B
+                            <literal>auto</literal> ‚É‚·‚é‚ƁA
+                            JTA‚âCMTƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̏ꍇA <literal>after_statement</literal> ‚ŃNƒ[ƒY‚µA
+                            JDBCƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̏ꍇA <literal>after_transaction</literal> ‚ŃNƒ[ƒY‚µ‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>auto</literal> (default) | <literal>on_close</literal> |
+                                <literal>after_transaction</literal> | <literal>after_statement</literal>
+                            </para>
+                            <para>
+                                ’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B‚±‚̐ݒè‚Í <literal>SessionFactory.openSession</literal> ‚©‚ç
+                                Žæ“¾‚µ‚½ <literal>Session</literal> ‚¾‚¯‚ÉŒø‰Ê‚ª‚ ‚è‚Ü‚·B
+                                <literal>SessionFactory.getCurrentSession</literal> ‚ð’Ê‚¶‚Ď擾‚µ‚½
+                                <literal>Session</literal> ‚ł́A<literal>CurrentSessionContext</literal> 
+                                ‚ÌŽÀ‘•‚É‚æ‚Á‚āAƒRƒlƒNƒVƒ‡ƒ“‚̃ŠƒŠ[ƒXƒ‚[ƒh‚ðÝ’肵‚Ü‚·B
+                                <xref linkend="architecture-current-session"/> ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                    <entry>
+                        <literal>hibernate.connection.<emphasis>&lt;propertyName&gt;</emphasis></literal>
+                    </entry>
+                    <entry>
+                        JDBC‚Ì <literal>propertyName</literal> ƒvƒƒpƒeƒB‚ðA
+                        <literal>DriverManager.getConnection()</literal> ‚É“n‚µ‚Ü‚·B
+                    </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jndi.<emphasis>&lt;propertyName&gt;</emphasis></literal>
+                        </entry>
+                        <entry>
+                            <literal>propertyName</literal> ƒvƒƒpƒeƒB‚ðA
+                            JNDI <literal>InitialContextFactory</literal> ‚É“n‚µ‚Ü‚·B
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-cache-properties" revision="7">
+            <title>Hibernate ƒLƒƒƒbƒVƒ…ƒvƒƒpƒeƒB</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>ƒvƒƒpƒeƒB–¼</entry>
+                        <entry>ˆÓ–¡</entry>
+                    </row>
+                </thead>
+                <tbody>
+                     <row>
+                        <entry>
+                            <literal>hibernate.cache.provider_class</literal>
+                        </entry>
+                        <entry>
+                            ƒJƒXƒ^ƒ€ <literal>CacheProvider</literal> ‚̃Nƒ‰ƒX–¼‚Å‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>classname.of.CacheProvider</literal> 
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_minimal_puts</literal>
+                        </entry>
+                        <entry>
+                            ‘‚«ž‚Ý‚ðÅ¬ŒÀ‚É‚·‚邽‚߂ɁA“ñŽŸƒLƒƒƒbƒVƒ…‚Ì‘€ì‚ðÅ“K‰»‚µ‚Ü‚·B
+                            ‚»‚Ì‘ã‚í‚è‚ɁA“ǂݍž‚Ý‚ª‚æ‚è•p”É‚É”­¶‚·‚é‚悤‚É‚È‚è‚Ü‚·B
+                            ‚±‚̃ZƒbƒeƒBƒ“ƒO‚̓Nƒ‰ƒXƒ^ƒLƒƒƒbƒVƒ…‚Å–ð‚É—§‚¿‚Ü‚·B
+                            Hibernate3‚ł̓Nƒ‰ƒXƒ^ƒLƒƒƒbƒVƒ…ŽÀ‘•—p‚ɃfƒtƒHƒ‹ƒg‚Å‚Í—LŒø‚É‚È‚Á‚Ä‚¢‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_query_cache</literal>
+                        </entry>
+                        <entry>
+                            “Á’è‚̃NƒGƒŠ‚ªƒLƒƒƒbƒVƒ…‰Â”\‚ȏꍇ‚ɁAƒNƒGƒŠƒLƒƒƒbƒVƒ…‚ð—LŒø‚É‚µ‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_second_level_cache</literal>
+                        </entry>
+                        <entry>
+                            “ñŽŸƒLƒƒƒbƒVƒ…‚ðŠ®‘S‚É–³Œø‚É‚·‚éê‡‚ÉŽg‚¢‚Ü‚·B
+                            ƒfƒtƒHƒ‹ƒg‚Å‚Í—LŒø‚ŁAƒNƒ‰ƒX‚Ì <literal>&lt;cache&gt;</literal> ƒ}ƒbƒsƒ“ƒO
+                            ‚Ő§Œä‚µ‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.query_cache_factory</literal>
+                        </entry>
+                        <entry>
+                            ƒJƒXƒ^ƒ€ <literal>QueryCache</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚̃Nƒ‰ƒX–¼‚ð
+                            Žw’肵‚Ü‚·BƒfƒtƒHƒ‹ƒg‚Å‚Í <literal>StandardQueryCache</literal> ‚É‚È‚è‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis>
+                                <literal>classname.of.QueryCache</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.region_prefix</literal>
+                        </entry>
+                        <entry>
+                            “ñŽŸƒLƒƒƒbƒVƒ…‚̗̈於‚̐ړªŽ«‚Å‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>prefix</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_structured_entries</literal>
+                        </entry>
+                        <entry>
+                            “ñŽŸƒLƒƒƒbƒVƒ…‚ÉŠi”[‚·‚éƒf[ƒ^‚ðAl‚ª—‰ð‚µ‚â‚·‚¢ƒtƒH[ƒ}ƒbƒg‚É‚µ‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis>
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-transaction-properties" revision="9">
+            <title>Hibernate ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ƒvƒƒpƒeƒB</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>ƒvƒƒpƒeƒB–¼</entry>
+                        <entry>ˆÓ–¡</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.factory_class</literal>
+                        </entry>
+                        <entry>
+                            Hibernate  <literal>Transaction</literal> API‚ƈꏏ‚ÉŽg‚í‚ê‚é 
+                            <literal>TransactionFactory</literal> ‚̃Nƒ‰ƒX–¼‚Å‚·B
+                            iƒfƒtƒHƒ‹ƒg‚Å‚Í <literal>JDBCTransactionFactory</literal> ‚Å‚·jB
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>classname.of.TransactionFactory</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>jta.UserTransaction</literal>
+                        </entry>
+                        <entry>
+                            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo‚©‚çJTA <literal>UserTransaction</literal> ‚ðŽæ“¾‚·‚邽‚ß‚É 
+                            <literal>JTATransactionFactory</literal> ‚ÉŽg‚í‚ê‚éJNDI–¼‚Å‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>jndi/composite/name</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.manager_lookup_class</literal>
+                        </entry>
+                        <entry>
+                            <literal>TransactionManagerLookup</literal>  ‚̃Nƒ‰ƒX–¼‚Å‚·B
+                            JTAŠÂ‹«‚É‚¨‚¢‚āAJVMƒŒƒxƒ‹‚̃LƒƒƒbƒVƒ…‚ð—LŒø‚É‚·‚邽‚ß‚É•K—v‚Å‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>classname.of.TransactionManagerLookup</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.flush_before_completion</literal>
+                        </entry>
+                        <entry>
+                            —LŒø‚̏ꍇAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÌcompletionƒtƒF[ƒY‚Ì‘O‚ÉŽ©“®“I‚É
+                            ƒZƒbƒVƒ‡ƒ“‚ðƒtƒ‰ƒbƒVƒ…‚µ‚Ü‚·B“à‘Ÿ‚ÌŽ©“®ƒZƒbƒVƒ‡ƒ“ƒRƒ“ƒeƒLƒXƒgŠÇ—‚É“K‚µ‚Ä‚¢‚Ü‚·B
+                            <xref linkend="architecture-current-session"/>‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.auto_close_session</literal>
+                        </entry>
+                        <entry>
+                            —LŒø‚̏ꍇAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÌcompletionƒtƒF[ƒY‚ÌŒã‚É
+                            ƒZƒbƒVƒ‡ƒ“‚ðŽ©“®“I‚ɃNƒ[ƒY‚µ‚Ü‚·B“à‘Ÿ‚ÌŽ©“®ƒZƒbƒVƒ‡ƒ“ƒRƒ“ƒeƒLƒXƒgŠÇ—‚É“K‚µ‚Ä‚¢‚Ü‚·B
+                            <xref linkend="architecture-current-session"/>‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-misc-properties" revision="10">
+            <title>‚»‚Ì‘¼‚̃vƒƒpƒeƒB</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>ƒvƒƒpƒeƒB–¼</entry>
+                        <entry>ˆÓ–¡</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.current_session_context_class</literal>
+                        </entry>
+                        <entry>
+                            uŒ»Ý‚́v<literal>Session</literal> ‚Ì‚½‚߂́iƒJƒXƒ^ƒ€jí—ª‚ð’ñ‹Ÿ‚µ‚Ü‚·B
+                            ƒrƒ‹ƒgƒCƒ“ƒXƒgƒ‰ƒeƒW[‚ÉŠÖ‚·‚é‚»‚Ì‘¼‚̏î•ñ‚ɂ‚¢‚Ä‚Í
+                            <xref linkend="architecture-current-session"/>‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis>
+                                <literal>jta</literal> | <literal>thread</literal> |
+                                <literal>managed</literal> | <literal>custom.Class</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.query.factory_class</literal>
+                        </entry>
+                        <entry>
+                            HQLƒp[ƒT[‚ÌŽÀ‘•‚ð‘I‘ð‚µ‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> or
+                                <literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.query.substitutions</literal>
+                        </entry>
+                        <entry>
+                            HQL‚ÆSQL‚̃g[ƒNƒ“‚ðƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+                            i—Ⴆ‚΁Aƒg[ƒNƒ“‚͊֐”‚⃊ƒeƒ‰ƒ‹–¼‚Å‚·jB
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.hbm2ddl.auto</literal>
+                        </entry>
+                        <entry>
+                            <literal>SessionFactory</literal> ‚𐶐¬‚µ‚½‚Æ‚«‚ɁA
+                            Ž©“®“I‚ɃXƒL[ƒ}DDL‚ðDB‚ɏo—Í‚µ‚Ü‚·B
+                            <literal>create-drop</literal> ‚̏ꍇA <literal>SessionFactory</literal> ‚ð
+                            ƒNƒ[ƒY‚µ‚½‚Æ‚«‚ɁAƒf[ƒ^ƒx[ƒXƒXƒL[ƒ}‚ðƒhƒƒbƒv‚µ‚Ü‚·B
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>validate</literal> | <literal>update</literal> | 
+                                <literal>create</literal> | <literal>create-drop</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cglib.use_reflection_optimizer</literal>
+                        </entry>
+                        <entry>
+                            ŽÀsŽžƒŠƒtƒŒƒNƒVƒ‡ƒ“‚Ì‘ã‚í‚è‚ÌCGLIB‚ÌŽg—p‚ð—LŒø‚É‚µ‚Ü‚·
+                            iƒVƒXƒeƒ€ƒŒƒxƒ‹‚̃vƒƒpƒeƒBj
+                            ƒŠƒtƒŒƒNƒVƒ‡ƒ“‚̓gƒ‰ƒuƒ‹ƒVƒ…[ƒeƒBƒ“ƒO‚Ì‚Æ‚«‚ɖ𗧂‚±‚Æ‚ª‚ ‚è‚Ü‚·B
+                            ƒIƒvƒeƒBƒ}ƒCƒU‚ðƒIƒt‚É‚µ‚Ä‚¢‚é‚Æ‚«‚Å‚³‚¦A
+                            Hibernate‚É‚Í•K‚¸CGLIB‚ª•K—v‚È‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                            ‚±‚̃vƒƒpƒeƒB‚Í <literal>hibernate.cfg.xml</literal> ‚Őݒè‚Å‚«‚Ü‚¹‚ñB
+                            <para>
+                                <emphasis role="strong">—áF</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <sect2 id="configuration-optional-dialects" revision="1">
+            <title>SQL •ûŒ¾iDialectj</title>
+
+            <para>
+                <literal>hibernate.dialect</literal> ƒvƒƒpƒeƒB‚ɂ́A
+                Žg—p‚·‚éƒf[ƒ^ƒx[ƒX‚̐³‚µ‚¢ <literal>org.hibernate.dialect.Dialect</literal> ‚̃TƒuƒNƒ‰ƒX‚ðA
+                •K‚¸Žw’è‚·‚ׂ«‚Å‚·B
+                ‚µ‚©‚µ•ûŒ¾‚ðŽw’è‚·‚ê‚΁AHibernate‚͏ãq‚µ‚½ƒvƒƒpƒeƒB‚Ì‚¢‚­‚‚©‚ɂ‚¢‚āA
+                ‚æ‚è“KØ‚ȃfƒtƒHƒ‹ƒg’l‚ðŽg‚¢‚Ü‚·B
+                ‚»‚¤‚·‚ê‚΁A‚»‚ê‚ç‚ðŽèì‹Æ‚Őݒ肷‚éŽèŠÔ‚ªÈ‚¯‚Ü‚·B
+            </para>
+
+            <table frame="topbot" id="sql-dialects" revision="2">
+                <title>Hibernate SQL Dialects (<literal>hibernate.dialect</literal>)</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>RDBMS</entry>
+                            <entry>Dialect</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry>DB2</entry> <entry><literal>org.hibernate.dialect.DB2Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>DB2 AS/400</entry> <entry><literal>org.hibernate.dialect.DB2400Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>DB2 OS390</entry> <entry><literal>org.hibernate.dialect.DB2390Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>PostgreSQL</entry> <entry><literal>org.hibernate.dialect.PostgreSQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL</entry> <entry><literal>org.hibernate.dialect.MySQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL with InnoDB</entry> <entry><literal>org.hibernate.dialect.MySQLInnoDBDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL with MyISAM</entry> <entry><literal>org.hibernate.dialect.MySQLMyISAMDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Oracle (any version)</entry> <entry><literal>org.hibernate.dialect.OracleDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Oracle 9i/10g</entry> <entry><literal>org.hibernate.dialect.Oracle9Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Sybase</entry> <entry><literal>org.hibernate.dialect.SybaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Sybase Anywhere</entry> <entry><literal>org.hibernate.dialect.SybaseAnywhereDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Microsoft SQL Server</entry> <entry><literal>org.hibernate.dialect.SQLServerDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>SAP DB</entry> <entry><literal>org.hibernate.dialect.SAPDBDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Informix</entry> <entry><literal>org.hibernate.dialect.InformixDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>HypersonicSQL</entry> <entry><literal>org.hibernate.dialect.HSQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Ingres</entry> <entry><literal>org.hibernate.dialect.IngresDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Progress</entry> <entry><literal>org.hibernate.dialect.ProgressDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Mckoi SQL</entry> <entry><literal>org.hibernate.dialect.MckoiDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Interbase</entry> <entry><literal>org.hibernate.dialect.InterbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Pointbase</entry> <entry><literal>org.hibernate.dialect.PointbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>FrontBase</entry> <entry><literal>org.hibernate.dialect.FrontbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Firebird</entry> <entry><literal>org.hibernate.dialect.FirebirdDialect</literal></entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-outerjoin" revision="4">
+            <title>ŠO•”Œ‹‡ƒtƒFƒbƒ`</title>
+
+            <para>
+                ‚à‚µDB‚ªANSI‚©AOracle‚©SybaseƒXƒ^ƒCƒ‹‚ÌŠO•”Œ‹‡‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚éê‡A
+                <emphasis>outer join fetching</emphasis> ‚́ADB‚ÌSQL”­s‰ñ”‚ðß–ñ‚µ
+                ƒpƒtƒH[ƒ}ƒ“ƒX‚ð—Ç‚­‚µ‚Ü‚·BiDB“à‚Å‚æ‚葽‚­‚̏ˆ—ƒRƒXƒg‚ª”­¶‚µ‚Ü‚·j
+                ŠO•”Œ‹‡ƒtƒFƒbƒ`‚́A‘½‘ΈêAˆê‘Α½A‘½‘Α½Aˆê‘Έê‚̃IƒuƒWƒFƒNƒgŠÖ˜A‚Å
+                ƒOƒ‹[ƒvƒIƒuƒWƒFƒNƒg‚ð1‚‚ÌSQL‚Å <literal>SELECT</literal> ‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                <literal>hibernate.max_fetch_depth</literal> ƒvƒƒpƒeƒB‚Ì’l‚ð <literal>0</literal> ‚É‚·‚é‚Æ
+                Outer join fetching‚ð <emphasis>‚·‚ׂÄ</emphasis> –³Œø‚É‚·‚邱‚Æ‚É‚È‚è‚Ü‚·B
+                <literal>1</literal> ‚â‚»‚êˆÈã‚Ì’l‚ðÝ’è‚·‚é‚ƁAŠO•”Œ‹‡ƒtƒFƒbƒ`‚ª—LŒø‚É‚È‚èA
+                ˆê‘Έê‚Æ‘½‘ΈêŠÖ˜A‚ª <literal>fetch="join"</literal> ‚Æ‚µ‚ă}ƒbƒsƒ“ƒO‚³‚ê‚Ü‚·B
+            </para>
+
+            <para>
+                See <xref linkend="performance-fetching"/> for more information.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-binarystreams" revision="1">
+            <title>ƒoƒCƒiƒŠƒXƒgƒŠ[ƒ€</title>
+
+            <para>
+                Oracle‚ÍJDBCƒhƒ‰ƒCƒo‚Æ‚ÌŠÔ‚Å‚â‚è‚Ƃ肳‚ê‚é <literal>byte</literal>  ”z—ñ‚̃TƒCƒY‚𐧌À‚µ‚Ü‚·B
+                <literal>binary</literal> ‚â <literal>serializable</literal> Œ^‚Ì‘å‚«‚ȃCƒ“ƒXƒ^ƒ“ƒX‚ðŽg‚¢‚½‚¯‚ê‚΁A
+                <literal>hibernate.jdbc.use_streams_for_binary</literal> ‚ð—LŒø‚É‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚½‚¾‚µ <emphasis>‚±‚ê‚̓VƒXƒeƒ€ƒŒƒxƒ‹‚̐ݒ肾‚¯‚Å‚·</emphasis> B
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-cacheprovider" revision="2">
+            <title>2ŽŸƒLƒƒƒbƒVƒ…‚ƃNƒGƒŠ[ƒLƒƒƒbƒVƒ…</title>
+
+            <para>
+                <literal>hibernate.cache</literal> ƒvƒƒpƒeƒBÚ“ªŽ«‚Í
+                Hibernate‚ŃvƒƒZƒX‚âƒNƒ‰ƒXƒ^“ñŽŸƒLƒƒƒbƒVƒ…‚ðŽg‚¤‚Æ‚±‚Æ‚ð‹–‰Â‚µ‚Ü‚·B
+                <xref linkend="performance-cache"/>‚É‚æ‚葽‚­‚̏ڍׂª‚ ‚è‚Ü‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-querysubstitution">
+            <title>ƒNƒGƒŠ[Œ¾Œê‚Ì’u‚«Š·‚¦</title>
+
+            <para>
+                <literal>hibernate.query.substitutions</literal> ‚ðŽg‚¤‚±‚ƂŁA
+                V‚µ‚¢HibernateƒNƒGƒŠƒg[ƒNƒ“‚ð’è‹`‚Å‚«‚Ü‚·B
+                —áF
+            </para>
+
+            <programlisting>hibernate.query.substitutions true=1, false=0</programlisting>
+
+            <para>
+                ‚±‚ê‚̓g[ƒNƒ“ <literal>true</literal> ‚Æ <literal>false</literal> ‚ðA
+                ¶¬‚³‚ê‚éSQL‚É‚¨‚¢‚Đ®”ƒŠƒeƒ‰ƒ‹‚É–|–󂵂܂·B                
+            </para>
+
+            <programlisting>hibernate.query.substitutions toLowercase=LOWER</programlisting>
+
+            <para>
+                ‚±‚ê‚ÍSQL‚Ì <literal>LOWER</literal> ŠÖ”‚Ì–¼‘O‚Ì•t‚¯‘Ö‚¦‚ð‰Â”\‚É‚µ‚Ü‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-statistics" revision="2">
+            <title>Hibernate “Œv</title>
+
+            <para>
+                <literal>hibernate.generate_statistics</literal> ‚ð—LŒø‚É‚µ‚½ê‡A
+                “®ì‚µ‚Ä‚¢‚éƒVƒXƒeƒ€‚ðƒ`ƒ…[ƒjƒ“ƒO‚·‚é‚Æ‚«‚ɁA<literal>SessionFactory.getStatistics()</literal> 
+                ‚ðŒo—R‚µ‚āAHibernate‚Í•Ö—˜‚È“Œvî•ñ‚ðo—Í‚µ‚Ü‚·B
+                JMX‚ðŒo—R‚µ‚Ä“Œvî•ñ‚ðo—Í‚·‚邱‚Æ‚à‰Â”\‚Å‚·B
+                Javadoc‚Ì <literal>org.hibernate.stats</literal> ƒpƒbƒP[ƒW“à‚Ì
+                ƒCƒ“ƒ^[ƒtƒFƒCƒX‚É‚Í‚æ‚葽‚­‚̏î•ñ‚ª‚ ‚è‚Ü‚·B
+            </para>
+
+        </sect2>
+    </sect1>
+
+    <sect1 id="configuration-logging">
+        <title>ƒƒMƒ“ƒO</title>
+
+        <para>
+            Hibernate‚ÍApache commons-loggin‚ðŽg‚Á‚āA‚³‚Ü‚´‚܂ȃCƒxƒ“ƒg‚ðƒƒO‚Æ‚µ‚Ä
+            o—Í‚µ‚Ü‚·B
+        </para>
+
+        <para>
+            commons-loggingƒT[ƒrƒX‚́iƒNƒ‰ƒXƒpƒX‚É <literal>log4j.jar</literal> ‚ðŠÜ‚ß‚ê‚΁jApache Log4j‚ɁA
+            ‚Ü‚½iJDK1.4‚©‚»‚êˆÈã‚ÅŽÀs‚³‚¹‚ê‚΁jJDK1.4 logging‚É’¼Úo—Í‚µ‚Ü‚·B
+            Log4j‚Í  <literal>http://jakarta.apache.org</literal> ‚©‚çƒ_ƒEƒ“ƒ[ƒh‚Å‚«‚Ü‚·B
+            Log4j‚ðŽg‚¤‚½‚߂ɂ́AƒNƒ‰ƒXƒpƒX‚É  <literal>log4j.properties</literal> ƒtƒ@ƒCƒ‹‚ð”z’u‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+            —á‚̃vƒƒpƒeƒBƒtƒ@ƒCƒ‹‚ÍHibernate‚ƈꏏ‚É”z•z‚³‚êA‚»‚ê‚Í <literal>src/</literal> ƒfƒBƒŒƒNƒgƒŠ‚É‚ ‚è‚Ü‚·B
+        </para>
+        
+        <para>
+            Hibernate‚̃ƒOƒƒbƒZ[ƒW‚ÉŠµ‚ê‚邱‚Æ‚ð‹­‚­‚¨‚·‚·‚ß‚µ‚Ü‚·B
+            Hibernate‚̃ƒO‚Í“Ç‚Ý‚â‚·‚­A‚Å‚«‚éŒÀ‚èÚ×‚É‚È‚é‚悤‚É“w—Í‚³‚ê‚Ä‚¢‚Ü‚·B
+            ‚±‚ê‚Í•K{‚̃gƒ‰ƒuƒ‹ƒVƒ…[ƒeƒBƒ“ƒOƒfƒoƒCƒX‚Å‚·B
+            ˆÈ‰º‚ɏd—v‚ȃƒO‚̃JƒeƒSƒŠ‚ðŽ¦‚µ‚Ü‚·B
+        </para>
+        
+            <table frame="topbot" id="log-categories" revision="2">
+                <title>Hibernate ƒƒOƒJƒeƒSƒŠ</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>ƒJƒeƒSƒŠ</entry>
+                            <entry>‹@”\</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>org.hibernate.SQL</literal></entry>
+                            <entry>ŽÀs‚µ‚½‚·‚ׂĂÌSQLiDDLjƒXƒe[ƒgƒƒ“ƒg‚ðƒƒMƒ“ƒO‚µ‚Ü‚·B</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.type</literal></entry>
+                            <entry>‚·‚ׂĂÌJDBCƒpƒ‰ƒ[ƒ^‚ðƒƒMƒ“ƒO‚µ‚Ü‚·B</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.tool.hbm2ddl</literal></entry>
+                            <entry>ŽÀs‚µ‚½‚·‚ׂĂÌSQLiDDLjƒXƒe[ƒgƒƒ“ƒg‚ðƒƒMƒ“ƒO‚µ‚Ü‚·B</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.pretty</literal></entry>
+                            <entry>
+                                session‚ÉŠÖ˜A‚·‚é‚·‚ׂẴGƒ“ƒeƒBƒeƒBiÅ‘å‚Q‚Oj‚̃tƒ‰ƒbƒVƒ…ŽžŠÔ‚ðƒƒMƒ“ƒO‚µ‚Ü‚·B
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.cache</literal></entry>
+                            <entry>‚·‚ׂĂ̂QŽŸƒLƒƒƒbƒVƒ…‚Ì“®ì‚ðƒƒMƒ“ƒO‚µ‚Ü‚·B</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction</literal></entry>
+                            <entry>ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÉŠÖ˜A‚·‚é“®ì‚ðƒƒMƒ“ƒO‚µ‚Ü‚·B</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.jdbc</literal></entry>
+                            <entry>JDBCƒŠƒ\[ƒXŽæ“¾‚ðƒƒMƒ“ƒO‚µ‚Ü‚·B</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.hql.ast.AST</literal></entry>
+                            <entry>
+                                HQL‚ÆSQL‚ÌAST‚̃NƒGƒŠ[ƒp[ƒX‚ðƒƒMƒ“ƒO‚µ‚Ü‚·B
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.secure</literal></entry>
+                            <entry>‚·‚ׂĂÌJAAS•ªÍ‚ðƒƒMƒ“ƒO‚µ‚Ü‚·B</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate</literal></entry>
+                            <entry>
+                                ‚·‚×‚Ä‚ðƒƒMƒ“ƒO‚µ‚Ü‚·Biî•ñ‚ª‘å—Ê‚É‚È‚è‚Ü‚·‚ªAƒgƒ‰ƒuƒ‹ƒVƒ…[ƒeƒBƒ“ƒO‚É‚Í•Ö—˜‚Å‚·j
+                            </entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+            
+        <para>
+            Hibernate‚ŃAƒvƒŠƒP[ƒVƒ‡ƒ“‚ðì¬‚·‚é‚Æ‚«‚́A<literal>org.hibernate.SQL</literal>
+            ƒJƒeƒSƒŠ‚Ì <literal>debug</literal> ‚ðí‚É—LŒø‚É‚µ‚Ä‚¨‚¢‚½‚Ù‚¤‚ª—Ç‚¢‚Å‚µ‚傤B
+            ‘ã‘Ö•û–@‚Æ‚µ‚āA<literal>hibernate.show_sql</literal> ‚ð—LŒø‚É‚·‚é•û–@‚ª‚ ‚è‚Ü‚·B
+        </para>
+                       
+        
+    </sect1>
+
+    <sect1 id="configuration-namingstrategy">
+        <title><literal>NamingStrategy</literal> ‚ÌŽÀ‘•</title>
+
+        <para>
+            ƒCƒ“ƒ^[ƒtƒFƒCƒX <literal>net.sf.hibernate.cfg.NamingStrategy</literal> ‚ðŽg‚¤‚Æ
+            ƒf[ƒ^ƒx[ƒXƒIƒuƒWƒFƒNƒg‚ƃXƒL[ƒ}—v‘f‚Ì‚½‚߂́u–½–¼•W€v‚ðŽw’è‚Å‚«‚Ü‚·B
+        </para>
+
+        <para>
+            Java‚ÌŽ¯•ÊŽq‚©‚çƒf[ƒ^ƒx[ƒX‚ÌŽ¯•ÊŽq‚ðŽ©“®¶¬‚·‚邽‚߂̃‹[ƒ‹‚âA
+            ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚Å—^‚¦‚½u˜_—“I‚ȁvƒJƒ‰ƒ€‚ƃe[ƒuƒ‹–¼‚©‚ç
+            u•¨—“I‚ȁvƒe[ƒuƒ‹‚ƃJƒ‰ƒ€–¼‚𐶐¬‚·‚邽‚߂̃‹[ƒ‹‚ð—pˆÓ‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            ‚±‚Ì‹@”\‚ÍŒJ‚è•Ô‚µ‚ÌŽG‰¹i—Ⴆ‚Î <literal>TBL_</literal> ƒvƒŠƒtƒBƒbƒNƒXj‚ðŽæ‚菜‚«A
+            ƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚̏璷‚³‚ðŒ¸‚ç‚·‚±‚Ƃɖ𗧂¿‚Ü‚·B
+            Hibernate‚ªŽg‚¤ƒfƒtƒHƒ‹ƒg‚̐헪‚Í‚©‚È‚èÅ¬ŒÀ‚É‹ß‚¢‚à‚Ì‚Å‚·B
+        </para>
+
+        <para>
+            ƒ}ƒbƒsƒ“ƒO‚ð’ljÁ‚·‚é‘O‚É <literal>Configuration.setNamingStrategy()</literal> ‚ðŒÄ‚Ô‚±‚Æ‚Å
+            ˆÈ‰º‚̂悤‚ɈقȂéí—ª‚ðŽw’è‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·F
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sf = new Configuration()
+    .setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
+    .addFile("Item.hbm.xml")
+    .addFile("Bid.hbm.xml")
+    .buildSessionFactory();]]></programlisting>
+    
+        <para>
+            <literal>org.hibernate.cfg.ImprovedNamingStrategy</literal> ‚Í‘g‚ݍž‚݂̐헪‚Å‚·B
+            ‚±‚ê‚Í‚¢‚­‚‚©‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚Æ‚Á‚Ä—L—p‚ÈŠJŽn“_‚Æ‚È‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-xmlconfig" revision="2">
+        <title>XMLÝ’èƒtƒ@ƒCƒ‹</title>
+
+        <para>
+            ‚à‚¤1‚‚̕û–@‚Í <literal>hibernate.cfg.xml</literal> ‚Æ‚¢‚¤–¼‘O‚̃tƒ@ƒCƒ‹‚Å
+            \•ª‚Ȑݒè‚ðŽw’è‚·‚é•û–@‚Å‚·B
+            ‚±‚̃tƒ@ƒCƒ‹‚Í <literal>hibernate.properties</literal> ƒtƒ@ƒCƒ‹‚Ì‘ã‚í‚è‚Æ‚È‚è‚Ü‚·B
+            ‚à‚µ—¼•û‚̃tƒ@ƒCƒ‹‚ª‚ ‚ê‚΁AƒvƒƒpƒeƒB‚ª’u‚«Š·‚¦‚ç‚ê‚Ü‚·B
+        </para>
+
+        <para>
+            XMLÝ’èƒtƒ@ƒCƒ‹‚͏‰ŠúÝ’è‚Å <literal>CLASSPATH</literal> ‚É”z’u‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚±‚ꂪ—á‚Å‚·F
+        </para>
+
+        <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+    "-//Hibernate/Hibernate Configuration DTD//EN"
+    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <!-- a SessionFactory instance listed as /jndi/name -->
+    <!-- /jndi/name‚̂悤‚ɃŠƒXƒgƒAƒbƒv‚³‚ꂽSessionFactoryƒCƒ“ƒXƒ^ƒ“ƒX -->
+    <session-factory
+        name="java:hibernate/SessionFactory">
+
+        <!-- properties -->
+        <property name="connection.datasource">java:/comp/env/jdbc/MyDB</property>
+        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
+        <property name="show_sql">false</property>
+        <property name="transaction.factory_class">
+            org.hibernate.transaction.JTATransactionFactory
+        </property>
+        <property name="jta.UserTransaction">java:comp/UserTransaction</property>
+
+        <!-- mapping files -->
+        <mapping resource="org/hibernate/auction/Item.hbm.xml"/>
+        <mapping resource="org/hibernate/auction/Bid.hbm.xml"/>
+
+        <!-- cache settings -->
+        <class-cache class="org.hibernate.auction.Item" usage="read-write"/>
+        <class-cache class="org.hibernate.auction.Bid" usage="read-only"/>
+        <collection-cache collection="org.hibernate.auction.Item.bids" usage="read-write"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+            Œ©‚Ä‚Ì‚Æ‚¨‚èA‚±‚Ì•û–@‚Ì—DˆÊ«‚͐ݒè‚Ì‚½‚߂̃}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹–¼‚ðŠOo‚µ‚É‚Å‚«‚邱‚Æ‚Å‚·B
+            HibernateƒLƒƒƒbƒVƒ…‚ðƒ`ƒ…[ƒjƒ“ƒO‚µ‚È‚¯‚ê‚΂Ȃç‚È‚¢‚Ì‚Å‚ ‚ê‚΁A
+            <literal>hibernate.cfg.xml</literal> ‚Í‚æ‚è•Ö—˜‚Å‚·B
+            <literal>hibernate.properties</literal> ‚Æ <literal>hibernate.cfg.xml</literal> ‚Ì
+            ‚Ç‚¿‚ç‚©‚ðŽg‚¦‚邱‚Æ‚ðŠo‚¦‚Ä‚¨‚¢‚Ä‚­‚¾‚³‚¢B
+            “ñ‚‚͓¯‚¶‚à‚̂ŁAˆá‚¤‚Æ‚±‚ë‚Æ‚¢‚¦‚ÎXML\•¶‚ðŽg‚¤‚±‚Æ‚Ì—˜“_‚¾‚¯‚Å‚·B
+        </para>
+
+       <para>
+           XMLÝ’è‚ðŽg‚¤‚±‚ƂŁAHibernate‚͈ȉº‚̂悤‚ɃVƒ“ƒvƒ‹‚É‚È‚è‚Ü‚·B
+       </para>
+
+       <programlisting><![CDATA[SessionFactory sf = new Configuration().configure().buildSessionFactory();]]></programlisting>
+
+       <para>
+           ˆá‚¤XMLÝ’èƒtƒ@ƒCƒ‹‚ðŽg‚¤‚±‚Æ‚à‚Å‚«‚Ü‚·B
+       </para>
+
+       <programlisting><![CDATA[SessionFactory sf = new Configuration()
+    .configure("catdb.cfg.xml")
+    .buildSessionFactory();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="configuration-j2ee" revision="1">
+        <title>J2EEƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo‚Æ‚Ì“‡</title>
+
+        <para>
+            Hibernate‚ÍJ2EE\‘¢‚Æ“‡‚·‚éƒ|ƒCƒ“ƒg‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>ƒRƒ“ƒeƒiŠÇ—ƒf[ƒ^ƒ\[ƒX</emphasis>FHibernate‚Í
+                JNDI‚ª’ñ‹Ÿ‚µAƒRƒ“ƒeƒi‚ªŠÇ—‚·‚éJDBCƒRƒlƒNƒVƒ‡ƒ“‚ðŽg—p‚Å‚«‚Ü‚·B
+                ’ʏíAJTA€‹’‚Ì <literal>TransactionManager</literal> ‚Æ
+                <literal>ResourceManager</literal> ‚ªƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ŠÇ—(CMT)A
+                “Á‚É—lX‚ȃf[ƒ^ƒ\[ƒX‚É‚Ü‚½‚ª‚镪ŽUƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðˆµ‚¢‚Ü‚·B
+                “–‘RƒvƒƒOƒ‰ƒ€‚Ńgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚ðŽw’è‚Å‚«‚Ü‚·(BMT)B
+                ‚ ‚é‚¢‚́A‹Lq‚µ‚½ƒR[ƒh‚̃|[ƒ^ƒrƒŠƒeƒB‚ð•Û‚‚½‚߂ɁA
+                ƒIƒvƒVƒ‡ƒ“‚ÌHibernate‚Ì <literal>Transaction</literal> API‚ðŽg‚¢‚½‚­‚È‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>Ž©“®JNDIƒoƒCƒ“ƒfƒBƒ“ƒO</emphasis>FHibernate‚ÍJNDI‚ª—§‚¿ã‚ª‚Á‚½Œã‚É
+                <literal>SessionFactory</literal> ‚𐶐¬‚µ‚Ü‚·B
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>JTAƒZƒbƒVƒ‡ƒ“ƒoƒCƒ“ƒfƒBƒ“ƒO</emphasis> F
+                Hibernate <literal>Session</literal> ‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚ÍJTAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Æ“¯‚¶‚É‚È‚è‚Ü‚·B
+                ’Pƒ‚É <literal>SessionFactory</literal> ‚ðJNDI‚©‚çlookup‚µ‚āA
+                Œ»Ý‚Ì <literal>Session</literal> ‚ðŽæ“¾‚µ‚Ü‚·B
+                JTAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ªŠ®—¹‚µ‚½‚Æ‚«‚ɁAHibernate‚ª <literal>Session</literal> ‚ðƒtƒ‰ƒbƒVƒ…‚µAƒNƒ[ƒY‚µ‚Ü‚·B
+                EJBƒfƒvƒƒCƒƒ“ƒgƒfƒBƒXƒNƒŠƒvƒ^‚Ì’†‚ɁAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚ðéŒ¾‚µ‚Ü‚·B
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>JMXƒfƒvƒƒC:</emphasis> ‚à‚µJMX‚ªŽg—p‰Â”\‚ȃAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒoi—Ⴆ‚ÎJBOSSj
+                ‚ª‚ ‚éê‡AHibernate‚ðMBean‚Æ‚µ‚ăfƒvƒƒC‚·‚邱‚Æ‚ð‘I‚ׂ܂·B
+                ‚±‚ê‚Í <literal>Configuration</literal> ‚©‚ç <literal>SessionFactory</literal> ‚ð
+                ¶¬‚·‚éƒR[ƒh‚𖳂­‚·‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+                ƒRƒ“ƒeƒi‚Í <literal>HibernateService</literal> ‚ð‹N“®‚µA
+                ƒT[ƒrƒX‚̈ˑ¶‚𗝑z“I‚ÉŠÇ—‚µ‚Ü‚·iƒf[ƒ^ƒ\[ƒX‚ÍHibernate‚â‚»‚Ì‘¼‚ª‹N“®‚·‚é‘O‚É
+                Žg—p‚Å‚«‚é‚悤‚É‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñjB
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            ŠÂ‹«‚Ɉˑ¶‚µ‚Ü‚·‚ªA‚à‚µAƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo‚ª"connection containment"‚Ì—áŠO‚ðƒXƒ[‚·‚é‚È‚ç
+            Ý’è‚̃IƒvƒVƒ‡ƒ“ <literal>hibernate.connection.aggressive_release</literal> 
+            ‚ðtrue‚É‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <sect2 id="configuration-optional-transactionstrategy" revision="3">
+            <title>ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“í—ªÝ’è</title>
+
+            <para>
+                Hibernate  <literal>Session</literal> API‚́AƒA[ƒLƒeƒNƒ`ƒƒ“à‚̃VƒXƒeƒ€‚ÌŠÇŠ‚Å‚ ‚é
+                ‚ ‚ç‚ä‚éƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Ɉˑ¶‚µ‚Ü‚¹‚ñB
+                ‚à‚µƒRƒlƒNƒVƒ‡ƒ“ƒv[ƒ‹‚ÌJDBC‚𒼐ڎg‚¢‚½‚¢ê‡AJDBC API‚©‚ç
+                ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðŒÄ‚Ô‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+                ‚à‚µAJ2EEƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo‚Å“®ì‚³‚¹‚é‚È‚çABeanŠÇ—ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðŽg‚¢A
+                •K—v‚ɉž‚¶‚Ä <literal>UserTransaction</literal> ‚ðJTA API‚©‚çŒÄ‚Ô‚±‚Æ‚É‚È‚é‚Å‚µ‚傤B
+            </para>
+
+            <para>
+                2‚i‚»‚êˆÈãj‚̊‹«‚Ō݊·«‚Ì‚ ‚éƒR[ƒh‚ðˆÛŽ‚·‚邽‚߂ɁAƒIƒvƒVƒ‡ƒ“‚Æ‚µ‚čª–{“I‚ȃVƒXƒeƒ€‚ð
+                ƒ‰ƒbƒsƒ“ƒO‚·‚éHibernate <literal>Transaction</literal> API‚𐄏§‚µ‚Ü‚·B
+                HibernateÝ’èƒvƒƒpƒeƒB‚Ì <literal>hibernate.transaction.factory_class</literal> ‚ðÝ’è‚·‚邱‚Æ‚Å
+                ‚ ‚é“Á’è‚Ì <literal>Transaction</literal> ƒNƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ðŽ‚Â‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+            </para>
+
+            <para>
+                3‚‚̊î–{“I‚ȁiŠù‚É‚ ‚éj‘I‘ð‚ð‹“‚°‚Ü‚·F
+            </para>
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.JDBCTransactionFactory</literal></term>
+                    <listitem>
+                        <para>ƒf[ƒ^ƒx[ƒX(JDBC)ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ɈϏ÷‚µ‚Ü‚·iƒfƒtƒHƒ‹ƒgj</para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.JTATransactionFactory</literal></term>
+                    <listitem>
+                        <para>
+                            ‚à‚µA‚±‚̃Rƒ“ƒeƒLƒXƒgi—Ⴆ‚΁AEJBƒZƒbƒVƒ‡ƒ“Beanƒƒ\ƒbƒhj‚Őis’†‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ª‘¶Ý‚·‚éA‚à‚µ‚­‚Í
+                            V‚µ‚¢ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ªŠJŽn‚³‚ê‚Ä‚¨‚èABeanŠÇ—ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ªŽg‚í‚ê‚Ä‚¢‚éê‡A
+                            ƒRƒ“ƒeƒiŠÇ—ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ɈϏ÷‚µ‚Ü‚·B
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.CMTTransactionFactory</literal></term>
+                    <listitem>
+                        <para>ƒRƒ“ƒeƒiŠÇ—JTAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ɈϏ÷‚µ‚Ü‚·</para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+            <para>
+                Ž©•ªŽ©g‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“í—ªi—Ⴆ‚΁ACORBAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ƒT[ƒrƒXj‚ð’è‹`‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+            </para>
+
+            <para>
+                Hibernate‚Ì‚¢‚­‚‚©‚Ì‹@”\i—Ⴆ‚΁A“ñŽŸƒLƒƒƒbƒVƒ…AJTA‚É‚æ‚éƒRƒ“ƒeƒLƒXƒgƒZƒbƒVƒ‡ƒ“ “™j‚Í
+                ŠÇ—‚³‚ꂽŠÂ‹«‚Ì’†‚ÌJTA <literal>TransactionManager</literal> ‚ւ̃AƒNƒZƒX‚ð—v‹‚µ‚Ü‚·B
+                J2EE‚ª‚ЂƂ‚̃ƒJƒjƒYƒ€‚É‹KŠi‰»‚³‚ê‚Ä‚¢‚È‚¢‚̂ŁA
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo‚É‚¨‚¢‚āAHibernate‚ª <literal>TransactionManager</literal> ‚̃Šƒtƒ@ƒŒƒ“ƒX
+                ‚ðŽæ“¾‚·‚é•û–@‚𖾊m‚É‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+            </para>
+
+            <table frame="topbot" id="jtamanagerlookup" revision="1">
+                <title>JTA ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ƒ}ƒl[ƒWƒƒ</title>
+                <tgroup cols="2">
+                    <colspec colwidth="2.5*"/>
+                    <colspec colwidth="1*"/>
+                    <thead>
+                        <row>
+                            <entry>Transaction Factory</entry>
+                            <entry align="center">Application Server</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JBossTransactionManagerLookup</literal></entry>
+                            <entry align="center">JBoss</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WeblogicTransactionManagerLookup</literal></entry>
+                            <entry align="center">Weblogic</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WebSphereTransactionManagerLookup</literal></entry>
+                            <entry align="center">WebSphere</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</literal></entry>
+                            <entry align="center">WebSphere 6</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.OrionTransactionManagerLookup</literal></entry>
+                            <entry align="center">Orion</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.ResinTransactionManagerLookup</literal></entry>
+                            <entry align="center">Resin</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JOTMTransactionManagerLookup</literal></entry>
+                            <entry align="center">JOTM</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JOnASTransactionManagerLookup</literal></entry>
+                            <entry align="center">JOnAS</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JRun4TransactionManagerLookup</literal></entry>
+                            <entry align="center">JRun4</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.BESTransactionManagerLookup</literal></entry>
+                            <entry align="center">Borland ES</entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-jndi" revision="3">
+            <title><literal>SessionFactory</literal> ‚ÌJNDI‚Ö‚Ì“o˜^</title>
+
+            <para>
+                JNDI‚É“o˜^‚µ‚½Hibernate <literal>SessionFactory</literal> ‚Í’Pƒ‚É
+                ƒtƒ@ƒNƒgƒŠ‚ðƒ‹ƒbƒNƒAƒbƒv‚µAV‚µ‚¢ <literal>Session</literal> ‚ðì‚è‚Ü‚·B
+                ‚±‚ê‚ÍJNDI‚É“o˜^‚³‚ꂽ <literal>Datasource</literal> ‚É‚ÍŠÖ˜A‚¹‚¸A
+                ‚¨ŒÝ‚¢‚ɃVƒ“ƒvƒ‹‚É‚±‚ê‚ç‚Ì“o˜^‚ðŽg‚¤‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <para>
+                ‚à‚µ <literal>SessionFactory</literal> ‚ðJNDIƒl[ƒ€ƒXƒy[ƒX‚É“o˜^‚µ‚½‚¢ê‡A
+                “Á•Ê‚È–¼‘Oi—Ⴆ‚΁A <literal>java:hibernate/SessionFactory</literal> j‚ð
+                <literal>hibernate.session_factory_name</literal> ƒvƒƒpƒeƒB‚ÉŽg‚Á‚Ä‚­‚¾‚³‚¢
+                ‚à‚µ‚±‚̃vƒƒpƒeƒB‚ðÈ—ª‚µ‚½ê‡A <literal>SessionFactory</literal> ‚Í
+                JNDI‚É“o˜^‚³‚ê‚Ü‚¹‚ñBi‚±‚ê‚ÍTomcat‚̂悤‚ȃfƒtƒHƒ‹ƒgŽÀ‘•‚ÅJNDI‚ª“Ç‚Ý‚æ‚èê—p‚̊‹«‚̏ꍇ“Á‚É•Ö—˜‚Å‚·Bj
+            </para>
+
+            <para>
+                <literal>SessionFactory</literal> ‚ðJNDI‚É“o˜^‚·‚é‚Æ‚«AHibernate‚Í
+                <literal>hibernate.jndi.url</literal> ‚Ì’l‚ðŽg—p‚µA<literal>hibernate.jndi.class</literal> 
+                ‚ðƒCƒjƒVƒƒƒ‹ƒRƒ“ƒeƒLƒXƒg‚Æ‚µ‚Ä‹ï‘̉»‚µ‚Ü‚·B
+                ‚à‚µ‰½‚àÝ’肵‚È‚¢ê‡‚́AƒfƒtƒHƒ‹ƒg‚Ì <literal>InitialContext</literal> ‚ðŽg—p‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                <literal>cfg.buildSessionFactory()</literal> ‚ðƒR[ƒ‹Œã
+                Hibernate‚ÍŽ©“®“I‚É <literal>SessionFactory</literal> ‚ðJNDI‚É”z’u‚µ‚Ü‚·B
+                <literal>HibernateService</literal> ‚ƈꏏ‚ÉJMXƒfƒvƒƒCƒƒ“ƒg‚ðŽg‚í‚È‚¢ŒÀ‚èA
+                ‚±‚ê‚Í‚±‚̌Ăяo‚µ‚ðƒAƒvƒŠƒP[ƒVƒ‡ƒ““à‚̉½‚ç‚©‚̃Xƒ^[ƒgƒAƒbƒvƒR[ƒhi‚à‚µ‚­‚̓†[ƒeƒBƒŠƒeƒBƒNƒ‰ƒXj
+                ‚É”z’u‚µ‚È‚¯‚ê‚΂Ȃç‚È‚¢‚±‚Æ‚ðˆÓ–¡‚µ‚Ü‚·BiŒã‚Å‹c˜_‚µ‚Ü‚·j
+            </para>
+
+            <para>
+                ‚à‚µJNDI <literal>SessionFactory</literal> ‚ðŽg‚¤ê‡AEJB‚⑼‚̃Nƒ‰ƒX‚Í
+                JNDIƒ‹ƒbƒNƒAƒbƒv‚ðŽg‚Á‚Ä <literal>SessionFactory</literal> ‚ðŽæ“¾‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                ŠÇ—‚³‚ꂽŠÂ‹«‚Å‚Í <literal>SessionFactory</literal> ‚ðJNDI‚ɃoƒCƒ“ƒh‚µA
+                ‚»‚¤‚Å‚È‚¯‚ê‚Î <literal>static</literal> ƒVƒ“ƒOƒ‹ƒgƒ“‚ðŽg‚¤‚±‚Ƃ𐄏§‚µ‚Ü‚·B
+                ‚±‚¤‚¢‚Á‚½Ú×‚©‚çƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒR[ƒh‚ð•ÛŒì‚·‚邽‚߂ɁA
+                <literal>HibernateUtil.getSessionFactory()</literal> ‚̂悤‚ȃwƒ‹ƒp[ƒNƒ‰ƒX‚Ì’†‚ɁA
+                <literal>SessionFactory</literal> ‚ðƒ‹ƒbƒNƒAƒbƒv‚·‚éƒR[ƒh‚ð‰B‚·‚±‚Ƃ𐄏§‚µ‚Ü‚·B
+                ‚±‚̂悤‚ȃwƒ‹ƒp[ƒNƒ‰ƒX‚ÍHibernate‚ðŠJŽn‚·‚é•Ö—˜‚ÈŽè’i‚Å‚à‚ ‚è‚Ü‚·B
+                &mdash;‚PÍ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-j2ee-currentsession" revision="4">
+            <title>JTA‚É‚æ‚錻Ý‚̃ZƒbƒVƒ‡ƒ“ƒRƒ“ƒeƒLƒXƒgƒ}ƒl[ƒWƒƒ“ƒg</title>
+
+            <para>
+                ‚à‚Á‚Æ‚àŠÈ’P‚É <literal>Session</literal> ‚ƃgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðˆµ‚¤•û–@‚́A
+                Hibernate‚ªŽ©“®“I‚ɁuŒ»Ý‚́v <literal>Session</literal> ‚ðŠÇ—‚·‚邱‚Æ‚Å‚·B
+                <xref linkend="architecture-current-session">ƒJƒŒƒ“ƒgƒZƒbƒVƒ‡ƒ“</xref> ‚Ìà–¾‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚à‚µ <literal>uJTAv</literal> ƒZƒbƒVƒ‡ƒ“ƒRƒ“ƒeƒLƒXƒg‚ðŽg‚Á‚½ã‚ŁA
+                Œ»Ý‚ÌJTAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÆHibernate <literal>Session</literal> ‚ªŠÖ˜A‚µ‚Ä‚¢‚È‚¢ê‡‚́A
+                Å‰‚É <literal>sessionFactory.getCurrentSession()</literal> ‚ðƒR[ƒ‹‚µA
+                JTAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Æ‚ÌŠÖ˜A•t‚¯‚ðs‚Á‚Ä‚­‚¾‚³‚¢B
+                <literal>uJTAv</literal> ƒRƒ“ƒeƒLƒXƒg‚Ì <literal>getCurrentSession()</literal> ‚ð
+                ’Ê‚¶‚Ď擾‚µ‚½ <literal>Session</literal> ‚́Aƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ªŠ®—¹‚·‚é‘O‚É
+                Ž©“®“I‚Ƀtƒ‰ƒbƒVƒ…‚µAŠ®—¹‚µ‚½Œã‚É‚ÍŽ©“®“I‚ɃNƒ[ƒY‚µ‚Ü‚·B
+                ‚Ü‚½AŠeƒXƒe[ƒgƒƒ“ƒgŒã‚ÉJDBCƒRƒlƒNƒVƒ‡ƒ“‚ðÏ‹É“I‚ɃŠƒŠ[ƒX‚µ‚Ü‚·B
+                ‚±‚ê‚É‚æ‚èJTAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̃‰ƒCƒtƒTƒCƒNƒ‹‚Å <literal>Session</literal> ‚ðŠÇ—‚·‚邱‚Æ‚ª‚Å‚«A
+                ƒ†[ƒU[‚̃R[ƒh‚©‚ç‚»‚̂悤‚ÈŠÇ—‚ð‚·‚éƒR[ƒh‚ð”rœ‚Å‚«‚Ü‚·B
+                <literal>UserTransaction</literal> ‚ð’Ê‚¶‚ÄJTA‚ðƒvƒƒOƒ‰ƒ€‚ÅŠÇ—‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+                ‚Ü‚½‚́Aiƒ|[ƒ^ƒuƒ‹‚ȃR[ƒh‚Å‚ ‚ê‚΁jHibernate <literal>Transaction</literal> API‚ð
+                ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚Æ‚µ‚ÄŽg‚¤‚±‚Æ‚à‚Å‚«‚Ü‚·B
+                EJBƒRƒ“ƒeƒi‚ðŽg‚¤‚Æ‚«‚́ACMT‚É‚æ‚ééŒ¾“Iƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚ªD‚Ü‚µ‚¢‚Å‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-j2ee-jmx" revision="1">
+            <title>JMXƒfƒvƒƒCƒƒ“ƒg</title>
+
+            <para>
+                <literal>SessionFactory</literal> ‚ðJNDI‚©‚çŽæ“¾‚·‚邽‚ß‚É‚Í
+                <literal>cfg.buildSessionFactory()</literal> s‚ð‚Ç‚±‚©‚ÅŽÀs‚µ‚Ä‚¢‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                ‚ ‚È‚½‚Í‚±‚ê‚ðA<literal>static</literal> ‰Šú‰»ƒuƒƒbƒN“ài <literal>HibernateUtil</literal> ‚̂悤‚ȁj‚©
+                <emphasis>managed service</emphasis> ‚Æ‚µ‚ÄHibernate‚ðƒfƒvƒƒC‚·‚é‚©A‚Ç‚¿‚ç‚©‚ÅŽÀs‚Å‚«‚Ü‚·B
+            </para>
+
+            <para>
+               JBOSS‚̂悤‚ÈJMX‚Ì‹@”\‚ŃAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo‚ɃfƒvƒƒC‚·‚邽‚ß‚É
+               <literal>org.hibernate.jmx.HibernateService</literal> ‚ðŽg‚Á‚āA”z’u‚µ‚Ü‚·B
+               ŽÀÛ‚̃fƒvƒƒCƒƒ“ƒg‚Ɛݒè‚̓xƒ“ƒ_[“Á—L‚Å‚·B
+               ‚±‚±‚Å—á‚Æ‚µ‚ÄJBOSS 4.0.x—p‚Ì <literal>jboss-service.xml</literal> ‚ðŽ¦‚µ‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<server>
+
+<mbean code="org.hibernate.jmx.HibernateService"
+    name="jboss.jca:service=HibernateFactory,name=HibernateFactory">
+
+    <!-- Required services -->
+    <depends>jboss.jca:service=RARDeployer</depends>
+    <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends>
+
+    <!-- Bind the Hibernate service to JNDI -->
+    <attribute name="JndiName">java:/hibernate/SessionFactory</attribute>
+
+    <!-- Datasource settings -->
+    <attribute name="Datasource">java:HsqlDS</attribute>
+    <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>
+
+    <!-- Transaction integration -->
+    <attribute name="TransactionStrategy">
+        org.hibernate.transaction.JTATransactionFactory</attribute>
+    <attribute name="TransactionManagerLookupStrategy">
+        org.hibernate.transaction.JBossTransactionManagerLookup</attribute>
+    <attribute name="FlushBeforeCompletionEnabled">true</attribute>
+    <attribute name="AutoCloseSessionEnabled">true</attribute>
+
+    <!-- Fetching options -->
+    <attribute name="MaximumFetchDepth">5</attribute>
+
+    <!-- Second-level caching -->
+    <attribute name="SecondLevelCacheEnabled">true</attribute>
+    <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute>
+    <attribute name="QueryCacheEnabled">true</attribute>
+
+    <!-- Logging -->
+    <attribute name="ShowSqlEnabled">true</attribute>
+
+    <!-- Mapping files -->
+    <attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute>
+
+</mbean>
+
+</server>]]></programlisting>
+
+            <para>
+                ‚±‚̃tƒ@ƒCƒ‹‚Í <literal>META-INF</literal> ƒfƒBƒŒƒNƒgƒŠ‚É”z’u‚³‚êA
+                JARƒtƒ@ƒCƒ‹‚ðŠg’£‚µ‚½ <literal>.sar</literal>  (service archive)‚ŃpƒbƒP[ƒW‰»‚³‚ê‚Ü‚·B
+                “¯—l‚ÉHibernateƒpƒbƒP[ƒW‚à•K—v‚Å‚·B‚Ü‚½AHibernate‚̓T[ƒhƒp[ƒeƒB‚̃‰ƒCƒuƒ‰ƒŠ‚à—v‹‚µ‚Ü‚·B
+                ƒRƒ“ƒpƒCƒ‹‚µ‚½‰i‘±‰»ƒNƒ‰ƒX‚Æ‚»‚̃}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚à“¯—l‚ɃA[ƒJƒCƒui.sarƒtƒ@ƒCƒ‹j‚É“ü‚ê‚Ü‚·B
+                ƒGƒ“ƒ^[ƒvƒ‰ƒCƒYbeani’ʏí‚̓ZƒbƒVƒ‡ƒ“beanj‚ÍŽ©g‚ÌJARƒtƒ@ƒCƒ‹‚ð•ÛŽ‚µ‚Ü‚·‚ªA
+                1‰ñ‚ŁiƒzƒbƒgjƒfƒvƒƒC‰Â”\‚ȃ†ƒjƒbƒg‚Ì‚½‚߂ɃƒCƒ“ƒT[ƒrƒXƒA[ƒJƒCƒu‚Æ‚µ‚Ä‚±‚ÌEJB JARƒtƒ@ƒCƒ‹‚ðƒCƒ“ƒNƒ‹[ƒh‚·‚é
+                ‚±‚Æ‚ª‚Å‚«‚Ü‚·BJBossƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo‚̃hƒLƒ…ƒƒ“ƒg‚ÉJXMƒT[ƒrƒX‚Æ
+                EJBƒfƒvƒƒCƒƒ“ƒg‚Ì‚æ‚葽‚­‚̏î•ñ‚ª‚ ‚è‚Ü‚·B
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/events.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/events.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/events.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,274 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="events">
+    <title>ƒCƒ“ƒ^[ƒZƒvƒ^‚ƃCƒxƒ“ƒg</title>
+
+    <para>
+        ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ªHibernate‚Ì“à•”‚Å”­¶‚·‚éƒCƒxƒ“ƒg‚ɑΉž‚Å‚«‚é‚Æ–ð‚É—§‚‚±‚Æ‚ª‚ ‚è‚Ü‚·B
+        ‚ ‚éŽí‚̈ê”Ê“I‚È‹@”\‚ðŽÀ‘•‚Å‚«‚é‚悤‚É‚È‚èA
+        ‚Ü‚½Hibernate‚Ì‹@”\‚ðŠg’£‚·‚邱‚Æ‚à‚Å‚«‚é‚悤‚É‚È‚è‚Ü‚·B
+    </para>
+
+    <sect1 id="objectstate-interceptors" revision="3">
+        <title>ƒCƒ“ƒ^[ƒZƒvƒ^</title>
+
+        <para>
+            <literal>Interceptor</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽg‚Á‚āA
+            ƒZƒbƒVƒ‡ƒ“‚©‚çƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ÖƒR[ƒ‹ƒoƒbƒN‚ð‚·‚é‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+            ‚±‚ê‚É‚æ‚è‰i‘±ƒIƒuƒWƒFƒNƒg‚Ì•Û‘¶AXVAíœA“ǂݍž‚Ý‚Ì‘O‚ɁA
+            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ªƒvƒƒpƒeƒB‚ðŒŸ¸‚µ‚½‚è‘€ì‚µ‚½‚è‚Å‚«‚é‚悤‚É‚È‚è‚Ü‚·B
+            ‚±‚ê‚͊踏î•ñ‚̒ǐՂɗ˜—p‚Å‚«‚Ü‚·B
+            ‰º‚Ì—á‚Å <literal>Interceptor</literal> ‚Í <literal>Auditable</literal> 
+            ‚ªì¬‚³‚ê‚é‚ÆŽ©“®“I‚É <literal>createTimestamp</literal> ‚ðÝ’肵A
+            <literal>Auditable</literal> ‚ªXV‚³‚ê‚é‚ÆŽ©“®“I‚É 
+            <literal>lastUpdateTimestamp</literal> ƒvƒƒpƒeƒB‚ðXV‚µ‚Ü‚·B
+        </para>
+        
+        <para>
+            <literal>Interceptor</literal> ‚𒼐ڎÀ‘•‚µ‚½‚èA
+            i‚³‚ç‚É‚æ‚¢‚̂́j<literal>EmptyInterceptor</literal> ‚ðŠg’£‚µ‚½‚è‚Å‚«‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[package org.hibernate.test;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.Transaction;
+import org.hibernate.type.Type;
+
+public class AuditInterceptor extends EmptyInterceptor {
+
+    private int updates;
+    private int creates;
+    private int loads;
+
+    public void onDelete(Object entity,
+                         Serializable id,
+                         Object[] state,
+                         String[] propertyNames,
+                         Type[] types) {
+        // do nothing
+    }
+
+    public boolean onFlushDirty(Object entity,
+                                Serializable id,
+                                Object[] currentState,
+                                Object[] previousState,
+                                String[] propertyNames,
+                                Type[] types) {
+
+        if ( entity instanceof Auditable ) {
+            updates++;
+            for ( int i=0; i < propertyNames.length; i++ ) {
+                if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
+                    currentState[i] = new Date();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean onLoad(Object entity,
+                          Serializable id,
+                          Object[] state,
+                          String[] propertyNames,
+                          Type[] types) {
+        if ( entity instanceof Auditable ) {
+            loads++;
+        }
+        return false;
+    }
+
+    public boolean onSave(Object entity,
+                          Serializable id,
+                          Object[] state,
+                          String[] propertyNames,
+                          Type[] types) {
+
+        if ( entity instanceof Auditable ) {
+            creates++;
+            for ( int i=0; i<propertyNames.length; i++ ) {
+                if ( "createTimestamp".equals( propertyNames[i] ) ) {
+                    state[i] = new Date();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void afterTransactionCompletion(Transaction tx) {
+        if ( tx.wasCommitted() ) {
+            System.out.println("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads);
+        }
+        updates=0;
+        creates=0;
+        loads=0;
+    }
+
+}]]></programlisting>
+
+        <para>
+            ƒCƒ“ƒ^[ƒZƒvƒ^‚É‚Í“ñŽí—Þ‚ ‚è‚Ü‚·F
+            <literal>Session</literal> ƒXƒR[ƒv‚Ì‚à‚Ì‚Æ 
+            <literal>SessionFactory</literal> ƒXƒR[ƒv‚Ì‚à‚Ì‚Å‚·B
+        </para>
+
+        <para>
+            <literal>Session</literal> ƒXƒR[ƒv‚̃Cƒ“ƒ^[ƒZƒvƒ^‚́A
+            ƒZƒbƒVƒ‡ƒ“‚ðƒI[ƒvƒ“‚·‚é‚Æ‚«‚ÉŽw’肵‚Ü‚·B
+            <literal>Interceptor</literal> ‚ðˆø”‚ÉŽæ‚éSessionFactory.openSession()
+            ‚̃I[ƒo[ƒ[ƒhƒƒ\ƒbƒh‚̈ê‚‚ðŽg‚¢‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
+
+        <para>
+            <literal>SessionFactory</literal> ƒXƒR[ƒv‚̃Cƒ“ƒ^[ƒZƒvƒ^‚Í <literal>Configuration</literal> 
+            ƒIƒuƒWƒFƒNƒg‚ðŽg‚Á‚Ä“o˜^‚µ‚Ü‚·B
+            ‚±‚ê‚Í <literal>SessionFactory</literal> ‚̍\’z‚æ‚è‚à—Dæ‚³‚ê‚Ü‚·B
+            ‚±‚̏ꍇA’ñ‹Ÿ‚³‚ê‚éƒCƒ“ƒ^[ƒZƒvƒ^‚Í <literal>SessionFactory</literal> 
+            ‚©‚çƒI[ƒvƒ“‚³‚ꂽ‚·‚ׂẴZƒbƒVƒ‡ƒ“‚É“K—p‚³‚ê‚Ü‚·B
+            ‚±‚ê‚ÍŽg—p‚·‚éƒCƒ“ƒ^[ƒZƒvƒ^‚𖾎¦“I‚ÉŽw’肵‚ăZƒbƒVƒ‡ƒ“‚ðƒI[ƒvƒ“‚µ‚È‚¢ŒÀ‚èA‚»‚¤‚È‚è‚Ü‚·B
+            <literal>SessionFactory</literal> ƒXƒR[ƒv‚̃Cƒ“ƒ^[ƒZƒvƒ^‚̓XƒŒƒbƒhƒZ[ƒt‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            •¡”‚̃ZƒbƒVƒ‡ƒ“‚ªiöÝ“I‚Ɂj‚±‚̃Cƒ“ƒ^[ƒZƒvƒ^‚𓯎ž•Às‚ÅŽg—p‚·‚邱‚ƂɂȂ邽‚߁A
+            ƒZƒbƒVƒ‡ƒ“ŒÅ—L‚̏ó‘Ô‚ðŠi”[‚µ‚È‚¢‚悤‚É‹C‚ð‚‚¯‚Ä‚­‚¾‚³‚¢B
+        </para>
+    
+        <programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
+        
+    </sect1>
+
+     <sect1 id="objectstate-events" revision="4">
+        <title>ƒCƒxƒ“ƒgƒVƒXƒeƒ€</title>
+
+        <para>
+            ‰i‘±‰»‘w‚Å“Á’è‚̃Cƒxƒ“ƒg‚ɑΉž‚µ‚È‚¯‚ê‚΂Ȃç‚È‚¢ê‡A
+            Hibernate3‚Ì <emphasis>ƒCƒxƒ“ƒg</emphasis> ƒA[ƒLƒeƒNƒ`ƒƒ‚ðŽg‚¤‚±‚Æ‚à‚Å‚«‚Ü‚·B
+            ƒCƒxƒ“ƒgƒVƒXƒeƒ€‚̓Cƒ“ƒ^[ƒZƒvƒ^‚ƈꏏ‚ÉŽg‚¤‚©A‚Ü‚½‚̓Cƒ“ƒ^[ƒZƒvƒ^‚Ì‘ã‚í‚è‚Æ‚µ‚ÄŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+        </para>
+
+        <para>
+            –{Ž¿“I‚É <literal>Session</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚Ì‚·‚ׂẴƒ\ƒbƒh‚́A
+            1ŒÂ‚̃Cƒxƒ“ƒg‚Æ‘ŠŒÝ‚ÉŠÖ˜A‚µ‚Ü‚·B
+            —Ⴆ‚Î <literal>LoadEvent</literal>A<literal>FlushEvent</literal> ‚È‚Ç‚ª‚ ‚è‚Ü‚·
+            i’è‹`Ï‚݂̃Cƒxƒ“ƒgŒ^‚̈ꗗ‚ɂ‚¢‚ẮAXMLÝ’èƒtƒ@ƒCƒ‹‚ÌDTD‚â 
+            <literal>org.hibernate.event</literal> ƒpƒbƒP[ƒW‚𒲂ׂĂ­‚¾‚³‚¢jB
+            ƒŠƒNƒGƒXƒg‚ª‚±‚ê‚ç‚̃ƒ\ƒbƒh‚Ì1‚‚©‚çì‚ç‚ê‚é‚Æ‚«A
+            Hibernate‚Ì <literal>Session</literal> ‚Í“KØ‚ȃCƒxƒ“ƒg‚𐶐¬‚µA
+            ‚»‚̃Cƒxƒ“ƒgŒ^‚ɐݒ肳‚ꂽƒCƒxƒ“ƒgƒŠƒXƒi‚É“n‚µ‚Ü‚·B
+            ‚·‚΂炵‚¢‚±‚ƂɁA‚±‚ê‚ç‚̃ŠƒXƒi‚Í‚»‚̃ƒ\ƒbƒh‚Æ“¯‚¶ˆ—‚ðŽÀ‘•‚µ‚Ü‚·B
+            ‚Æ‚Í‚¢‚¦AƒŠƒXƒiƒCƒ“ƒ^[ƒtƒFƒCƒX‚̈ê‚Â‚ðŽ©—R‚ɃJƒXƒ^ƒ€ŽÀ‘•‚Å‚«‚Ü‚·
+            i‚‚܂èA<literal>LoadEvent</literal> ‚Í“o˜^‚³‚ꂽ <literal>LoadEventListener</literal> 
+            ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ÌŽÀ‘•‚É‚æ‚菈—‚³‚ê‚Ü‚·jB
+            ‚»‚̏ꍇA‚»‚ÌŽÀ‘•‚É‚Í <literal>Session</literal> ‚©‚çì‚ç‚ꂽ‚ǂ̂悤‚È <literal>load()</literal> 
+            ƒŠƒNƒGƒXƒg‚ð‚àˆ—‚·‚éÓ”C‚ª‚ ‚è‚Ü‚·B
+        </para>
+
+        <para>
+            ƒŠƒXƒi‚ÍŽ–ŽÀãƒVƒ“ƒOƒ‹ƒgƒ“‚Å‚ ‚é‚ÆŒ©‚È‚¹‚Ü‚·B
+            ‚‚܂胊ƒXƒi‚̓ŠƒNƒGƒXƒgŠÔ‚Å‹¤—L‚³‚ê‚邽‚߁A
+            ƒCƒ“ƒXƒ^ƒ“ƒX•Ï”‚Æ‚µ‚ďó‘Ô‚ð•ÛŽ‚·‚é‚ׂ«‚Å‚Í‚È‚¢‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+        </para>
+
+        <para>
+            ƒJƒXƒ^ƒ€ƒŠƒXƒi‚͏ˆ—‚µ‚½‚¢ƒCƒxƒ“ƒg‚ɂ‚¢‚Ä“KØ‚ȃCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽÀ‘•‚·‚é‚ׂ«‚Å‚·B
+            •Ö—˜‚ÈŠî’êƒNƒ‰ƒX‚Ì‚¤‚¿‚̈ê‚‚ðŒp³‚µ‚Ä‚à‚æ‚¢‚Å‚·
+            i‚Ü‚½‚ÍHibernate‚ªƒfƒtƒHƒ‹ƒg‚ÅŽg—p‚·‚éƒCƒxƒ“ƒgƒŠƒXƒi‚ðŒp³‚µ‚Ä‚à‚æ‚¢‚Å‚·B
+            ‚·‚΂炵‚¢‚±‚ƂɁA‚±‚Ì–Ú“I‚Ì‚½‚ß‚É”ñfinal‚Æ‚µ‚Đ錾‚³‚ê‚Ä‚¢‚Ü‚·jB
+            ƒJƒXƒ^ƒ€ƒŠƒXƒi‚Í <literal>Configuration</literal> ƒIƒuƒWƒFƒNƒg‚ðŽg‚Á‚ăvƒƒOƒ‰ƒ€‚©‚ç“o˜^‚·‚é‚©A
+            Hibernate‚ÌXMLÝ’èƒtƒ@ƒCƒ‹‚ÅŽw’è‚Å‚«‚Ü‚·
+            iƒvƒƒpƒeƒBƒtƒ@ƒCƒ‹‚Ő錾“I‚ɐݒ肷‚é•û–@‚̓Tƒ|[ƒg‚³‚ê‚Ä‚¢‚Ü‚¹‚ñjB
+            ƒJƒXƒ^ƒ€ƒ[ƒhƒCƒxƒ“ƒgƒŠƒXƒi‚Ì—á‚ðŽ¦‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[public class MyLoadListener implements LoadEventListener {
+    // this is the single method defined by the LoadEventListener interface
+    public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
+            throws HibernateException {
+        if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
+            throw MySecurityException("Unauthorized access");
+        }
+    }
+}]]></programlisting>
+
+        <para>
+            ƒfƒtƒHƒ‹ƒgƒŠƒXƒiˆÈŠO‚̃ŠƒXƒi‚ðŽg‚¤‚ɂ́AHibernate‚ւ̐ݒè‚à•K—v‚Å‚·F
+        </para>
+
+<programlisting><![CDATA[<hibernate-configuration>
+    <session-factory>
+        ...
+        <event type="load">
+            <listener class="com.eg.MyLoadListener"/>
+            <listener class="org.hibernate.event.def.DefaultLoadEventListener"/>
+        </event>
+    </session-factory>
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+            ‚Ü‚½‚»‚Ì‘¼‚ɁAƒvƒƒOƒ‰ƒ€‚Å“o˜^‚·‚é•û–@‚à‚ ‚è‚Ü‚·F
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration();
+LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() };
+cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
+
+        <para>
+            ƒŠƒXƒi‚ðéŒ¾“I‚É“o˜^‚·‚é‚ƁA‚»‚̃ŠƒXƒi‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ð‹¤—L‚Å‚«‚Ü‚¹‚ñB
+            •¡”‚Ì <literal>&lt;listener/&gt;</literal> —v‘f‚Å“¯‚¶ƒNƒ‰ƒX–¼‚ªŽg‚í‚ê‚é‚ƁA
+            ‚»‚ꂼ‚ê‚ÌŽQÆ‚Í‚»‚̃Nƒ‰ƒX‚̕ʁX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ðŽw‚·‚±‚Æ‚É‚È‚è‚Ü‚·B
+            ƒŠƒXƒiŒ^‚̊ԂŃŠƒXƒiƒCƒ“ƒXƒ^ƒ“ƒX‚ð‹¤—L‚·‚é•K—v‚ª‚ ‚ê‚΁A
+            ƒvƒƒOƒ‰ƒ€‚Å“o˜^‚·‚é•û–@‚ðÌ‚ç‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+        </para>
+
+        <para>
+            ‚È‚ºƒCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽÀ‘•‚µ‚āA“Á‰»‚µ‚½Œ^‚ðÝ’莞‚ÉŽw’è‚·‚é‚Ì‚Å‚µ‚傤‚©H
+            ƒŠƒXƒi‚ÌŽÀ‘•ƒNƒ‰ƒX‚ɁA•¡”‚̃Cƒxƒ“ƒgƒŠƒXƒiƒCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽÀ‘•‚Å‚«‚é‚©‚ç‚Å‚·B
+            “o˜^Žž‚ɒljÁ‚ÅŒ^‚ðŽw’è‚·‚邱‚ƂŁAƒJƒXƒ^ƒ€ƒŠƒXƒi‚Ìon/off‚ðÝ’莞‚ÉŠÈ’P‚ɐ؂è‘Ö‚¦‚ç‚ê‚Ü‚·B
+        </para>
+
+    </sect1>
+    
+    <sect1 id="objectstate-decl-security" revision="2">
+        <title>Hibernate‚̐錾“I‚ȃZƒLƒ…ƒŠƒeƒB</title>
+        <para>
+            ˆê”Ê“I‚ÉHibernateƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̐錾“I‚ȃZƒLƒ…ƒŠƒeƒB‚́AƒZƒbƒVƒ‡ƒ“ƒtƒ@ƒT[ƒh‘w‚ÅŠÇ—‚µ‚Ü‚·B
+            Œ»ÝAHiberenate3‚ÍJACC‚Å‹–‰Â‚µ‚©‚AJAAS‚Å”FØ‚µ‚½ƒAƒNƒVƒ‡ƒ“‚ð‹–‚µ‚Ä‚¢‚Ü‚·B
+            ‚±‚ê‚̓Cƒxƒ“ƒgƒA[ƒLƒeƒNƒ`ƒƒ‚̍ŏãˆÊ‚É‘g‚ݍž‚Ü‚ê‚Ä‚¢‚éƒIƒvƒVƒ‡ƒ“‚Ì‹@”\‚Å‚·B
+        </para>
+        
+        <para>
+            ‚Ü‚¸Å‰‚ɁA“KØ‚ȃCƒxƒ“ƒgƒŠƒXƒi‚ðÝ’肵‚ÄJAAS”FØ‚ðŽg‚¦‚é‚悤‚É‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+        </para>
+        
+        <programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
+<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
+<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
+<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
+
+        <para>
+            “Á’è‚̃Cƒxƒ“ƒgŒ^‚ɑ΂µ‚Ä‚¿‚傤‚Ljê‚‚̃ŠƒXƒi‚ª‚ ‚é‚Æ‚«A
+            <literal>&lt;listener type="..." class="..."/&gt;</literal> 
+            ‚Í <literal>&lt;event type="..."&gt;&lt;listener class="..."/&gt;&lt;/event&gt;</literal> 
+            ‚ÌŠÈ—ªŒ`‚ɉ߂¬‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <para>
+            ŽŸ‚ɁA“¯‚¶‚­ <literal>hibernate.cfg.xml</literal> ‚э[ƒ‹‚Ƀp[ƒ~ƒbƒVƒ‡ƒ“‚ð—^‚¦‚Ä‚­‚¾‚³‚¢F
+        </para>
+        
+        <programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
+<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
+        
+        <para>
+            ‚±‚̃[ƒ‹–¼‚ÍŽg—p‚·‚éJACCƒvƒƒoƒCƒ_‚É—‰ð‚³‚ê‚郍[ƒ‹‚Å‚·B
+        </para>
+       
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/example_mappings.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/example_mappings.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/example_mappings.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,657 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="example-mappings">
+    <title>—áF‚¢‚ë‚¢‚ë‚ȃ}ƒbƒsƒ“ƒO</title>
+    
+    <para>
+        ‚±‚̏͂ł́A‚æ‚è•¡ŽG‚ÈŠÖ˜A‚̃}ƒbƒsƒ“ƒO‚ð‚¢‚­‚‚©Ð‰î‚µ‚Ü‚·B
+    </para>
+    
+    <sect1 id="example-mappings-emp">
+        <title>ŒÙ—pŽÒ/]‹Æˆõ</title>
+
+        <para>
+            <literal>Employer</literal> ‚Æ <literal>Employee</literal> ‚ÌŠÖŒW‚ð•\‚·ˆÈ‰º‚̃‚ƒfƒ‹‚́A
+            ŠÖ˜A‚Ì•\Œ»‚ÉŽÀÛ‚̃Gƒ“ƒeƒBƒeƒBƒNƒ‰ƒXi <literal>Employment</literal> j
+            ‚ðŽg‚¢‚Ü‚·B
+            ‚È‚º‚È‚çA“¯‚¶2‚‚̃p[ƒeƒB‚É•¡”‚ÌŠúŠÔŒÙ—p‚³‚ê‚é‚Æ‚¢‚¤‚±‚Æ‚ª‚ ‚肦‚é‚©‚ç‚Å‚·B
+            ‚¨‹à‚Ì’l‚Ə]‹Æˆõ‚Ì–¼‘O‚ðƒ‚ƒfƒ‹‰»‚·‚邽‚߂ɃRƒ“ƒ|[ƒlƒ“ƒg‚ðŽg‚Á‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/EmployerEmployee.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/EmployerEmployee.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            ƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚̈ê—á‚Å‚·F
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+        
+    <class name="Employer" table="employers">
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employer_id_seq</param>
+            </generator>
+        </id>
+        <property name="name"/>
+    </class>
+
+    <class name="Employment" table="employment_periods">
+
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employment_id_seq</param>
+            </generator>
+        </id>
+        <property name="startDate" column="start_date"/>
+        <property name="endDate" column="end_date"/>
+
+        <component name="hourlyRate" class="MonetaryAmount">
+            <property name="amount">
+                <column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>
+            </property>
+            <property name="currency" length="12"/>
+        </component>
+
+        <many-to-one name="employer" column="employer_id" not-null="true"/>
+        <many-to-one name="employee" column="employee_id" not-null="true"/>
+
+    </class>
+
+    <class name="Employee" table="employees">
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employee_id_seq</param>
+            </generator>
+        </id>
+        <property name="taxfileNumber"/>
+        <component name="name" class="Name">
+            <property name="firstName"/>
+            <property name="initial"/>
+            <property name="lastName"/>
+        </component>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        <literal>SchemaExport</literal> ‚Ő¶¬‚µ‚½ƒe[ƒuƒ‹ƒXƒL[ƒ}‚Å‚·B
+    </para>
+
+    <programlisting><![CDATA[create table employers (
+    id BIGINT not null, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+create table employment_periods (
+    id BIGINT not null,
+    hourly_rate NUMERIC(12, 2),
+    currency VARCHAR(12), 
+    employee_id BIGINT not null, 
+    employer_id BIGINT not null, 
+    end_date TIMESTAMP, 
+    start_date TIMESTAMP, 
+    primary key (id)
+)
+
+create table employees (
+    id BIGINT not null, 
+    firstName VARCHAR(255), 
+    initial CHAR(1), 
+    lastName VARCHAR(255), 
+    taxfileNumber VARCHAR(255), 
+    primary key (id)
+)
+
+alter table employment_periods 
+    add constraint employment_periodsFK0 foreign key (employer_id) references employers
+alter table employment_periods 
+    add constraint employment_periodsFK1 foreign key (employee_id) references employees
+create sequence employee_id_seq
+create sequence employment_id_seq
+create sequence employer_id_seq]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="example-mappings-authorwork">
+        <title>ìŽÒ/ì•i</title>
+
+        <para>
+            <literal>Work</literal> , <literal>Author</literal> ‚»‚µ‚Ä <literal>Person</literal> 
+            ‚ÌŠÖŒW‚ð•\‚·ˆÈ‰º‚̃‚ƒfƒ‹‚ðl‚¦‚Ä‚Ý‚Ä‚­‚¾‚³‚¢B
+            <literal>Work</literal> ‚Æ <literal>Author</literal> ‚ÌŠÖŒW‚𑽑Α½ŠÖ˜A‚Å•\‚µ‚Ä‚¢‚Ü‚·B
+            <literal>Author</literal> ‚Æ <literal>Person</literal> ‚ÌŠÖŒW‚͈ê‘ΈêŠÖ˜A‚Æ‚µ‚Ä•\‚µ‚Ä‚¢‚Ü‚·B
+            ‘¼‚É‚Í <literal>Author</literal> ‚ª <literal>Person</literal> ‚ðŠg’£‚·‚é‚Æ‚¢‚¤•û–@‚à‚ ‚è‚Ü‚·B
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/AuthorWork.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/AuthorWork.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            ˆÈ‰º‚̃}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚Í‚±‚̂悤‚ÈŠÖŒW‚𐳊m‚É•\Œ»‚µ‚Ä‚¢‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Work" table="works" discriminator-value="W">
+
+        <id name="id" column="id">
+            <generator class="native"/>
+        </id>
+        <discriminator column="type" type="character"/>
+
+        <property name="title"/>
+        <set name="authors" table="author_work">
+            <key column name="work_id"/>
+            <many-to-many class="Author" column name="author_id"/>
+        </set>
+
+        <subclass name="Book" discriminator-value="B">
+            <property name="text"/>
+        </subclass>
+
+        <subclass name="Song" discriminator-value="S">
+            <property name="tempo"/>
+            <property name="genre"/>
+        </subclass>
+
+    </class>
+
+    <class name="Author" table="authors">
+
+        <id name="id" column="id">
+            <!-- The Author must have the same identifier as the Person -->
+            <generator class="assigned"/> 
+        </id>
+
+        <property name="alias"/>
+        <one-to-one name="person" constrained="true"/>
+
+        <set name="works" table="author_work" inverse="true">
+            <key column="author_id"/>
+            <many-to-many class="Work" column="work_id"/>
+        </set>
+
+    </class>
+
+    <class name="Person" table="persons">
+        <id name="id" column="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        ‚±‚̃}ƒbƒsƒ“ƒO‚É‚Í4‚‚̃e[ƒuƒ‹‚ª‚ ‚è‚Ü‚·B
+        <literal>works</literal> , <literal>authors</literal> , <literal>persons</literal> 
+        ‚Í‚»‚ꂼ‚êAŽdŽ–AìŽÒAl‚̃f[ƒ^‚ð•ÛŽ‚µ‚Ü‚·B
+        <literal>author_work</literal> ‚͍ìŽÒ‚ƍì•i‚ðƒŠƒ“ƒN‚·‚éŠÖ˜Aƒe[ƒuƒ‹‚Å‚·B
+        ˆÈ‰º‚Í <literal>SchemaExport</literal> ‚Ő¶¬‚µ‚½ƒe[ƒuƒ‹ƒXƒL[ƒ}‚Å‚·B
+    </para>
+
+    <programlisting><![CDATA[create table works (
+    id BIGINT not null generated by default as identity, 
+    tempo FLOAT, 
+    genre VARCHAR(255), 
+    text INTEGER, 
+    title VARCHAR(255), 
+    type CHAR(1) not null, 
+    primary key (id)
+)
+
+create table author_work (
+    author_id BIGINT not null, 
+    work_id BIGINT not null, 
+    primary key (work_id, author_id)
+)
+
+create table authors (
+    id BIGINT not null generated by default as identity, 
+    alias VARCHAR(255), 
+    primary key (id)
+)
+
+create table persons (
+    id BIGINT not null generated by default as identity, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+alter table authors 
+    add constraint authorsFK0 foreign key (id) references persons
+alter table author_work 
+    add constraint author_workFK0 foreign key (author_id) references authors
+alter table author_work
+    add constraint author_workFK1 foreign key (work_id) references works]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-mappings-customerorderproduct">
+        <title>ŒÚ‹q/’•¶/»•i</title>
+
+        <para>
+            ‚³‚āA <literal>Customer</literal> , <literal>Order</literal> , <literal>LineItem</literal> 
+            <literal>Product</literal> ‚ÌŠÖŒW‚ð•\‚·ƒ‚ƒfƒ‹‚ðl‚¦‚Ä‚Ý‚Ü‚µ‚傤B
+            <literal>Customer</literal> ‚Æ <literal>Order</literal> ‚͈ê‘Α½‚ÌŠÖ˜A‚Å‚·‚ªA
+            <literal>Order</literal> / <literal>LineItem</literal> / <literal>Product</literal> 
+            ‚͂ǂ̂悤‚É•\Œ»‚·‚é‚ׂ«‚Å‚µ‚傤‚©H
+            <literal>LineItem</literal> ‚ðA<literal>Order</literal> ‚Æ <literal>Product</literal> 
+            ‚Ì‘½‘Α½ŠÖ˜A‚ð•\Œ»‚·‚éŠÖ˜AƒNƒ‰ƒX‚Æ‚µ‚ă}ƒbƒsƒ“ƒO‚µ‚Ü‚µ‚½B
+            Hibernate‚Å‚Í‚±‚ê‚ðƒRƒ“ƒ|ƒWƒbƒg—v‘f‚ƌĂт܂·B
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            ƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒgF
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Customer" table="customers">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+        <set name="orders" inverse="true">
+            <key column="customer_id"/>
+            <one-to-many class="Order"/>
+        </set>
+    </class>
+
+    <class name="Order" table="orders">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="date"/>
+        <many-to-one name="customer" column="customer_id"/>
+        <list name="lineItems" table="line_items">
+            <key column="order_id"/>
+            <list-index column="line_number"/>
+            <composite-element class="LineItem">
+                <property name="quantity"/>
+                <many-to-one name="product" column="product_id"/>
+            </composite-element>
+        </list>
+    </class>
+
+    <class name="Product" table="products">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="serialNumber"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        <literal>customers</literal> , <literal>orders</literal> , <literal>line_items</literal> , 
+        <literal>products</literal> ‚Í‚»‚ꂼ‚êAŒÚ‹qA’•¶A’•¶–¾×A»•i‚̃f[ƒ^‚ð•ÛŽ‚µ‚Ü‚·B
+        <literal>line_items</literal> ‚Í’•¶‚Ɛ»•i‚ðƒŠƒ“ƒN‚·‚éŠÖ˜Aƒe[ƒuƒ‹‚Æ‚µ‚Ä‚à“­‚«‚Ü‚·B
+    </para>
+
+    <programlisting><![CDATA[create table customers (
+    id BIGINT not null generated by default as identity, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+create table orders (
+    id BIGINT not null generated by default as identity, 
+    customer_id BIGINT, 
+    date TIMESTAMP, 
+    primary key (id)
+)
+
+create table line_items (
+    line_number INTEGER not null, 
+    order_id BIGINT not null, 
+    product_id BIGINT, 
+    quantity INTEGER, 
+    primary key (order_id, line_number)
+)
+
+create table products (
+    id BIGINT not null generated by default as identity, 
+    serialNumber VARCHAR(255), 
+    primary key (id)
+)
+
+alter table orders 
+    add constraint ordersFK0 foreign key (customer_id) references customers
+alter table line_items
+    add constraint line_itemsFK0 foreign key (product_id) references products
+alter table line_items
+    add constraint line_itemsFK1 foreign key (order_id) references orders]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="misc">
+        <title>ŽíXŽG‘½‚ȃ}ƒbƒsƒ“ƒO—á</title>
+        
+        <para>
+            ‚±‚±‚É‚ ‚é—á‚Í‚·‚ׂÄHibernate‚̃eƒXƒgƒXƒC[ƒg‚©‚çŽæ‚è‚Ü‚µ‚½B
+            ‚»‚±‚ɂ́A‘¼‚É‚à‚½‚­‚³‚ñ‚̃}ƒbƒsƒ“ƒO‚̗Ⴊ‚ ‚è‚Ü‚·B
+            HibernateƒfƒBƒXƒgƒŠƒrƒ…[ƒVƒ‡ƒ“‚Ì <literal>test</literal> ƒtƒHƒ‹ƒ_‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+        </para>
+        
+        <para>TODO: ‚±‚±‚É•¶Í‚ð–„‚ß‚é</para>
+        
+        <sect2 id="example-mappings-typed-onetone">
+            <title>uŒ^•t‚¯‚³‚ꂽvˆê‘ΈêŠÖ˜A</title>
+<programlisting><![CDATA[<class name="Person">
+    <id name="name"/>
+    <one-to-one name="address" 
+            cascade="all">
+        <formula>name</formula>
+        <formula>'HOME'</formula>
+    </one-to-one>
+    <one-to-one name="mailingAddress" 
+            cascade="all">
+        <formula>name</formula>
+        <formula>'MAILING'</formula>
+    </one-to-one>
+</class>
+
+<class name="Address" batch-size="2" 
+        check="addressType in ('MAILING', 'HOME', 'BUSINESS')">
+    <composite-id>
+        <key-many-to-one name="person" 
+                column="personName"/>
+        <key-property name="type" 
+                column="addressType"/>
+    </composite-id>
+    <property name="street" type="text"/>
+    <property name="state"/>
+    <property name="zip"/>
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="example-mappings-composite-key">
+            <title>•¡‡ƒL[‚Ì—á</title>
+<programlisting><![CDATA[<class name="Customer">
+
+    <id name="customerId"
+        length="10">
+        <generator class="assigned"/>
+    </id>
+
+    <property name="name" not-null="true" length="100"/>
+    <property name="address" not-null="true" length="200"/>
+
+    <list name="orders"
+            inverse="true"
+            cascade="save-update">
+        <key column="customerId"/>
+        <index column="orderNumber"/>
+        <one-to-many class="Order"/>
+    </list>
+
+</class>
+
+<class name="Order" table="CustomerOrder" lazy="true">
+    <synchronize table="LineItem"/>
+    <synchronize table="Product"/>
+    
+    <composite-id name="id" 
+            class="Order$Id">
+        <key-property name="customerId" length="10"/>
+        <key-property name="orderNumber"/>
+    </composite-id>
+    
+    <property name="orderDate" 
+            type="calendar_date"
+            not-null="true"/>
+    
+    <property name="total">
+        <formula>
+            ( select sum(li.quantity*p.price) 
+            from LineItem li, Product p 
+            where li.productId = p.productId 
+                and li.customerId = customerId 
+                and li.orderNumber = orderNumber )
+        </formula>
+    </property>
+    
+    <many-to-one name="customer"
+            column="customerId"
+            insert="false"
+            update="false" 
+            not-null="true"/>
+        
+    <bag name="lineItems"
+            fetch="join" 
+            inverse="true"
+            cascade="save-update">
+        <key>
+            <column name="customerId"/>
+            <column name="orderNumber"/>
+        </key>
+        <one-to-many class="LineItem"/>
+    </bag>
+    
+</class>
+    
+<class name="LineItem">
+    
+    <composite-id name="id" 
+            class="LineItem$Id">
+        <key-property name="customerId" length="10"/>
+        <key-property name="orderNumber"/>
+        <key-property name="productId" length="10"/>
+    </composite-id>
+    
+    <property name="quantity"/>
+    
+    <many-to-one name="order"
+            insert="false"
+            update="false" 
+            not-null="true">
+        <column name="customerId"/>
+        <column name="orderNumber"/>
+    </many-to-one>
+    
+    <many-to-one name="product"
+            insert="false"
+            update="false" 
+            not-null="true"
+            column="productId"/>
+        
+</class>
+
+<class name="Product">
+    <synchronize table="LineItem"/>
+
+    <id name="productId"
+        length="10">
+        <generator class="assigned"/>
+    </id>
+    
+    <property name="description" 
+        not-null="true" 
+        length="200"/>
+    <property name="price" length="3"/>
+    <property name="numberAvailable"/>
+    
+    <property name="numberOrdered">
+        <formula>
+            ( select sum(li.quantity) 
+            from LineItem li 
+            where li.productId = productId )
+        </formula>
+    </property>
+    
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="example-mappings-composite-key-manytomany">
+            <title>•¡‡ƒL[‘®«‚ð‹¤—L‚·‚鑽‘Α½</title>
+<programlisting><![CDATA[<class name="User" table="`User`">
+    <composite-id>
+        <key-property name="name"/>
+        <key-property name="org"/>
+    </composite-id>
+    <set name="groups" table="UserGroup">
+        <key>
+            <column name="userName"/>
+            <column name="org"/>
+        </key>
+        <many-to-many class="Group">
+            <column name="groupName"/>
+            <formula>org</formula>
+        </many-to-many>
+    </set>
+</class>
+    
+<class name="Group" table="`Group`">
+    <composite-id>
+        <key-property name="name"/>
+        <key-property name="org"/>
+    </composite-id>
+    <property name="description"/>
+    <set name="users" table="UserGroup" inverse="true">
+        <key>
+            <column name="groupName"/>
+            <column name="org"/>
+        </key>
+        <many-to-many class="User">
+            <column name="userName"/>
+            <formula>org</formula>
+        </many-to-many>
+    </set>
+</class>
+]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-content-discrimination">
+            <title>discrimination‚ÉŠî‚­“à—e</title>
+<programlisting><![CDATA[<class name="Person"
+    discriminator-value="P">
+    
+    <id name="id" 
+        column="person_id" 
+        unsaved-value="0">
+        <generator class="native"/>
+    </id>
+    
+            
+    <discriminator 
+        type="character">
+        <formula>
+            case 
+                when title is not null then 'E' 
+                when salesperson is not null then 'C' 
+                else 'P' 
+            end
+        </formula>
+    </discriminator>
+
+    <property name="name" 
+        not-null="true"
+        length="80"/>
+        
+    <property name="sex" 
+        not-null="true"
+        update="false"/>
+    
+    <component name="address">
+        <property name="address"/>
+        <property name="zip"/>
+        <property name="country"/>
+    </component>
+    
+    <subclass name="Employee" 
+        discriminator-value="E">
+            <property name="title"
+                length="20"/>
+            <property name="salary"/>
+            <many-to-one name="manager"/>
+    </subclass>
+    
+    <subclass name="Customer" 
+        discriminator-value="C">
+            <property name="comments"/>
+            <many-to-one name="salesperson"/>
+    </subclass>
+    
+</class>]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-association-alternatekeys" revision="2">
+            <title>‘ã‘ÖƒL[‚ÌŠÖ˜A</title>
+<programlisting><![CDATA[<class name="Person">
+    
+    <id name="id">
+        <generator class="hilo"/>
+    </id>
+    
+    <property name="name" length="100"/>
+    
+    <one-to-one name="address" 
+        property-ref="person"
+        cascade="all"
+        fetch="join"/>
+    
+    <set name="accounts" 
+        inverse="true">
+        <key column="userId"
+            property-ref="userId"/>
+        <one-to-many class="Account"/>
+    </set>
+    
+    <property name="userId" length="8"/>
+
+</class>
+
+<class name="Address">
+
+    <id name="id">
+        <generator class="hilo"/>
+    </id>
+
+    <property name="address" length="300"/>
+    <property name="zip" length="5"/>
+    <property name="country" length="25"/>
+    <many-to-one name="person" unique="true" not-null="true"/>
+
+</class>
+
+<class name="Account">
+    <id name="accountId" length="32">
+        <generator class="uuid"/>
+    </id>
+    
+    <many-to-one name="user"
+        column="userId"
+        property-ref="userId"/>
+    
+    <property name="type" not-null="true"/>
+    
+</class>]]></programlisting>
+        </sect2>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/example_parentchild.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/example_parentchild.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/example_parentchild.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,362 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="example-parentchild">
+    <title>—áFe/Žq‹Ÿ
+    </title>
+
+    <para>
+        V‹Kƒ†[ƒU‚ªHibernate‚ðŽg‚Á‚Ä‚Ü‚¸Å‰‚Ɉµ‚¤ƒ‚ƒfƒ‹‚̈ê‚‚ɁAeŽqŒ^‚̃‚ƒfƒ‹‰»‚ª‚ ‚è‚Ü‚·B
+        ‚±‚̃‚ƒfƒ‹‰»‚É‚Í“ñ‚‚̃Aƒvƒ[ƒ`‚ª‘¶Ý‚µ‚Ü‚·B‚Æ‚è‚킯V‹Kƒ†[ƒU‚É‚Æ‚Á‚āA
+        ‚³‚Ü‚´‚Ü‚È——R‚©‚çÅ‚à•Ö—˜‚¾‚ÆŽv‚í‚ê‚éƒAƒvƒ[ƒ`‚́A<literal>e</literal> ‚©‚ç <literal>Žq‹Ÿ</literal> 
+        ‚Ö‚Ì <literal>&lt;one-to-many&gt;</literal> ŠÖ˜A‚É‚æ‚è <literal>e</literal> ‚Æ <literal>Žq‹Ÿ</literal> 
+        ‚Ì—¼•û‚ðƒGƒ“ƒeƒBƒeƒBƒNƒ‰ƒX‚Æ‚µ‚ă‚ƒfƒŠƒ“ƒO‚·‚é•û–@‚Å‚·
+        i‚à‚¤ˆê‚‚̕û–@‚́A<literal>Žq‹Ÿ</literal> ‚ð <literal>&lt;composite-element&gt;</literal> ‚Æ‚µ‚Ä’è‹`‚·‚é‚à‚Ì‚Å‚·jB
+        ‚±‚ê‚ŁiHibernate‚É‚¨‚¯‚éjˆê‘Α½ŠÖ˜A‚̃fƒtƒHƒ‹ƒg‚̃Zƒ}ƒ“ƒeƒBƒNƒX‚ªA’ʏí‚Ì•¡‡—v‘f‚̃}ƒbƒsƒ“ƒO‚æ‚è‚àA
+        eŽqŠÖŒW‚̃Zƒ}ƒ“ƒeƒBƒNƒX‚©‚牓‚¢‚±‚Æ‚ª‚í‚©‚è‚Ü‚·B
+        ‚»‚ê‚ł͐eŽqŠÖŒW‚ðŒø—¦“I‚©‚ƒGƒŒƒKƒ“ƒg‚Ƀ‚ƒfƒŠƒ“ƒO‚·‚邽‚߂ɁA
+        <emphasis>ƒJƒXƒP[ƒh‘€ì‚ðŽg‚Á‚½‘o•ûŒüˆê‘Α½ŠÖ˜A</emphasis> ‚̈µ‚¢•û‚ðà–¾‚µ‚Ü‚·B‚±‚ê‚Í‚Ü‚Á‚½‚­“‚¢‚à‚Ì‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+        
+    </para>
+    
+    <sect1 id="example-parentchild-collections">
+        <title>ƒRƒŒƒNƒVƒ‡ƒ“‚ÉŠÖ‚·‚钍ˆÓ</title>
+
+        <para>
+            Hibernate‚̃RƒŒƒNƒVƒ‡ƒ“‚ÍŽ©g‚̃Gƒ“ƒeƒBƒeƒB‚̘_—“I‚È•”•ª‚ƍl‚¦‚ç‚êA
+            Œˆ‚µ‚Ä•ïŠÜ‚·‚éƒGƒ“ƒeƒBƒeƒB‚Ì‚à‚Ì‚Å‚Í‚ ‚è‚Ü‚¹‚ñB‚±‚ê‚Í’v–½“I‚ȈႢ‚Å‚·I
+            ‚±‚ê‚͈ȉº‚̂悤‚ÈŒ‹‰Ê‚É‚È‚è‚Ü‚·F
+        </para>
+
+        <itemizedlist>
+            <listitem>
+            <para>
+                ƒIƒuƒWƒFƒNƒg‚ðƒRƒŒƒNƒVƒ‡ƒ“‚©‚çíœA‚Ü‚½‚̓RƒŒƒNƒVƒ‡ƒ“‚ɒljÁ‚·‚é‚Æ‚«A
+                ƒRƒŒƒNƒVƒ‡ƒ“‚̃I[ƒi[‚̃o[ƒWƒ‡ƒ“”ԍ†‚̓Cƒ“ƒNƒŠƒƒ“ƒg‚³‚ê‚Ü‚·B
+            </para>
+            </listitem>
+            <listitem>
+            <para>
+                ‚à‚µƒRƒŒƒNƒVƒ‡ƒ“‚©‚çíœ‚³‚ꂽƒIƒuƒWƒFƒNƒg‚ª’lŒ^‚̃Cƒ“ƒXƒ^ƒ“ƒX
+                i—Ⴆ‚΃Rƒ“ƒ|ƒWƒbƒgƒGƒŒƒƒ“ƒg)‚¾‚Á‚½‚È‚ç‚΁A‚»‚̃IƒuƒWƒFƒNƒg‚͉i‘±“I‚Å‚Í‚È‚­‚È‚èA
+                ‚»‚̏ó‘Ԃ̓f[ƒ^ƒx[ƒX‚©‚犮‘S‚ɍ폜‚³‚ê‚Ü‚·B
+                “¯‚¶‚悤‚ɁA’lŒ^‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ðƒRƒŒƒNƒVƒ‡ƒ“‚ɒljÁ‚·‚é‚ƁA‚»‚̏ó‘Ô‚Í‚·‚®‚ɉi‘±“I‚É‚È‚è‚Ü‚·B
+            </para>
+            </listitem>
+            <listitem>
+            <para>
+                ˆê•ûA‚à‚µƒGƒ“ƒeƒBƒeƒB‚ªƒRƒŒƒNƒVƒ‡ƒ“iˆê‘Α½‚Ü‚½‚Í‘½‘Α½ŠÖ˜A)‚©‚çíœ‚³‚ê‚Ä‚àA
+                ƒfƒtƒHƒ‹ƒg‚Å‚Í‚»‚ê‚͍폜‚³‚ê‚Ü‚¹‚ñB‚±‚Ì“®ì‚ÍŠ®‘S‚ɈêŠÑ‚µ‚Ä‚¢‚Ü‚·B
+                ‚·‚È‚í‚¿A‘¼‚̃Gƒ“ƒeƒBƒeƒB‚Ì“à•”ó‘Ô‚ð•ÏX‚µ‚Ä‚àAŠÖ˜A‚·‚éƒGƒ“ƒeƒBƒeƒB‚ªÁ–Å‚·‚ׂ«‚Å‚Í‚È‚¢‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+                “¯—l‚ɁAƒGƒ“ƒeƒBƒeƒB‚ªƒRƒŒƒNƒVƒ‡ƒ“‚ɒljÁ‚³‚ê‚Ä‚àAƒfƒtƒHƒ‹ƒg‚Å‚Í‚»‚̃Gƒ“ƒeƒBƒeƒB‚͉i‘±“I‚É‚Í‚È‚è‚Ü‚¹‚ñB
+            </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            ‚»‚Ì‘ã‚í‚è‚ɁAƒfƒtƒHƒ‹ƒg‚Ì“®ì‚ł́AƒGƒ“ƒeƒBƒeƒB‚ðƒRƒŒƒNƒVƒ‡ƒ“‚ɒljÁ‚·‚é‚Æ’P‚É“ñ‚‚̃Gƒ“ƒeƒBƒeƒBŠÔ‚̃Šƒ“ƒN‚ðì¬‚µA
+            ˆê•ûƒGƒ“ƒeƒBƒeƒB‚ðíœ‚·‚é‚ƃŠƒ“ƒN‚àíœ‚µ‚Ü‚·B‚±‚ê‚Í‚·‚ׂẴP[ƒX‚É‚¨‚¢‚Ä”ñí‚É“KØ‚Å‚·B
+            ‚±‚ꂪ“KØ‚Å‚È‚¢‚̂͐e/ŽqŠÖŒW‚̏ꍇ‚Å‚·B‚±‚̏ꍇŽq‹Ÿ‚̐¶‘¶‚͐e‚̃‰ƒCƒtƒTƒCƒNƒ‹‚ɐ§ŒÀ‚³‚ê‚é‚©‚ç‚Å‚·B
+        </para>
+    
+    </sect1>
+
+    <sect1 id="example-parentchild-bidir">
+        <title>‘o•ûŒüˆê‘Α½
+        </title>
+
+        <para>
+            <literal>Parent</literal> ‚©‚ç <literal>Child</literal> ‚Ö‚Ì’Pƒ‚È <literal>&lt;one-to-many&gt;</literal> ŠÖ˜A‚©‚çŽn‚ß‚é‚Æ‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<set name="children">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+    
+        <para>
+            ˆÈ‰º‚̃R[ƒh‚ðŽÀs‚·‚é‚ƁA
+        </para>
+
+        <programlisting><![CDATA[Parent p = .....;
+Child c = new Child();
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+    
+        <para>
+            Hibernate‚Í“ñ‚‚ÌSQL•¶‚𔭍s‚µ‚Ü‚·:
+        </para>
+
+        <itemizedlist>
+        <listitem>
+            <para>
+            <literal>c</literal>‚ɑ΂·‚郌ƒR[ƒh‚𐶐¬‚·‚é<literal>INSERT</literal>
+            </para>
+        </listitem>
+        <listitem>
+            <para>
+            <literal>p</literal>‚©‚ç<literal>c</literal>‚ւ̃Šƒ“ƒN‚ðì¬‚·‚é<literal>UPDATE</literal>
+            </para>
+        </listitem>
+        </itemizedlist>
+    
+        <para>
+            ‚±‚ê‚Í”ñŒø—¦“I‚È‚¾‚¯‚Å‚Í‚È‚­A<literal>parent_id</literal> ƒJƒ‰ƒ€‚É‚¨‚¢‚Ä <literal>NOT NULL</literal> §–ñ‚Ɉᔽ‚µ‚Ü‚·B
+            ƒRƒŒƒNƒVƒ‡ƒ“‚̃}ƒbƒsƒ“ƒO‚Å <literal>not-null="true"</literal> ‚ÆŽw’è‚·‚邱‚ƂŁAnull§–ñˆá”½‚ð‰ðŒˆ‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·:
+        </para>
+
+        <programlisting><![CDATA[<set name="children">
+    <key column="parent_id" not-null="true"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+    
+        <para>
+            ‚µ‚©‚µ‚±‚Ì‰ðŒˆô‚͐„§‚Å‚«‚Ü‚¹‚ñB
+        </para>
+        <para>
+            ‚±‚Ì“®ì‚̍ª–{“I‚ÈŒ´ˆö‚́A<literal>p</literal> ‚©‚ç <literal>c</literal> ‚ւ̃Šƒ“ƒN
+            iŠO•”ƒL[ <literal>parent_id</literal>)‚Í <literal>Child</literal> ƒIƒuƒWƒFƒNƒg‚̏ó‘Ԃ̈ꕔ‚Ƃ͍l‚¦‚ç‚ꂸA
+            ‚»‚Ì‚½‚ß <literal>INSERT</literal> ‚É‚æ‚Á‚ăŠƒ“ƒN‚ª¶¬‚³‚ê‚È‚¢‚±‚Æ‚Å‚·B
+            ‚Å‚·‚©‚çA‰ðŒˆô‚̓Šƒ“ƒN‚ðChildƒ}ƒbƒsƒ“ƒO‚̈ꕔ‚É‚·‚邱‚Æ‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
+
+        <para>
+            (‚Ü‚½ <literal>Child</literal> ƒNƒ‰ƒX‚É <literal>parent</literal> ƒvƒƒpƒeƒB‚ð’ljÁ‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B)
+        </para>
+
+        <para>
+            ‚»‚ê‚Å‚Í <literal>Child</literal> ƒGƒ“ƒeƒBƒeƒB‚ªƒŠƒ“ƒN‚̏ó‘Ԃ𐧌䂷‚é‚悤‚É‚È‚Á‚½‚̂ŁA
+            ƒRƒŒƒNƒVƒ‡ƒ“‚ªƒŠƒ“ƒN‚ðXV‚µ‚È‚¢‚悤‚É‚µ‚Ü‚µ‚傤B‚»‚ê‚É‚Í <literal>inverse</literal> ‘®«‚ðŽg‚¢‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+        <para>
+            ˆÈ‰º‚̃R[ƒh‚ðŽg‚¦‚΁AV‚µ‚¢ <literal>Child</literal> ‚ð’ljÁ‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+        <para>
+            ‚±‚ê‚É‚æ‚èASQL‚Ì <literal>INSERT</literal> •¶‚ªˆê‚‚¾‚¯‚ª”­s‚³‚ê‚é‚悤‚É‚È‚è‚Ü‚µ‚½I
+        </para>
+
+        <para>
+            ‚à‚¤­‚µ‹­‰»‚·‚é‚ɂ́A<literal>Parent</literal> ‚Ì <literal>addChild()</literal> ƒƒ\ƒbƒh‚ðì¬‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[public void addChild(Child c) {
+    c.setParent(this);
+    children.add(c);
+}]]></programlisting>
+
+        <para>
+            <literal>Child</literal> ‚ð’ljÁ‚·‚éƒR[ƒh‚Í‚±‚̂悤‚É‚È‚è‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+     </sect1>
+     
+     <sect1 id="example-parentchild-cascades">
+         <title>ƒ‰ƒCƒtƒTƒCƒNƒ‹‚̃JƒXƒP[ƒh</title>
+     
+         <para>
+              –¾Ž¦“I‚É <literal>save()</literal> ‚ðƒR[ƒ‹‚·‚é‚Ì‚Í‚Ü‚¾”ς킵‚¢‚à‚Ì‚Å‚·B‚±‚ê‚ðƒJƒXƒP[ƒh‚ðŽg‚Á‚đΏˆ‚µ‚Ü‚·B
+         </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true" cascade="all">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+     
+         <para>
+             ‚±‚ê‚É‚æ‚èæ‚قǂ̃R[ƒh‚ð‚±‚Ì‚æ‚¤‚É’Pƒ‰»‚µ‚Ü‚·
+         </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.flush();]]></programlisting>
+     
+         <para>
+             “¯—l‚É <literal>Parent</literal> ‚ð•Û‘¶‚Ü‚½‚͍폜‚·‚é‚Æ‚«‚ɁAŽq‹Ÿ‚ðˆê‚ˆê‚ÂŽæ‚èo‚µ‚Ĉµ‚¤•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+             ˆÈ‰º‚̃R[ƒh‚Í <literal>p</literal> ‚ðíœ‚µA‚»‚µ‚ăf[ƒ^ƒx[ƒX‚©‚ç‚»‚ÌŽq‹Ÿ‚ð‚·‚×‚Äíœ‚µ‚Ü‚·B
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+session.delete(p);
+session.flush();]]></programlisting>
+     
+         <para>
+             ‚µ‚©‚µ‚±‚̃R[ƒh‚Í
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+c.setParent(null);
+session.flush();]]></programlisting>
+     
+         <para>
+             ƒf[ƒ^ƒx[ƒX‚©‚ç <literal>c</literal> ‚ðíœ‚µ‚Ü‚¹‚ñB<literal>p</literal> ‚ւ̃Šƒ“ƒN‚ðíœ‚·‚é
+             i‚»‚µ‚Ä‚±‚̃P[ƒX‚Å‚Í <literal>NOT NULL</literal> §–ñˆá”½‚ðˆø‚«‹N‚±‚·j‚¾‚¯‚Å‚·B
+             <literal>Child</literal> ‚Ì <literal>delete()</literal> ‚𖾎¦‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+session.delete(c);
+session.flush();]]></programlisting>
+
+         <para>
+             ¡‚±‚̃P[ƒX‚Å‚ÍŽÀÛ‚É <literal>Child</literal> ‚ªe‚È‚µ‚Å‚Í‘¶Ý‚Å‚«‚È‚¢‚悤‚É‚È‚è‚Ü‚µ‚½B
+             ‚»‚Ì‚½‚߁A‚à‚µƒRƒŒƒNƒVƒ‡ƒ“‚©‚ç <literal>Child</literal> ‚ðŽæ‚菜‚­ê‡A‚±‚ê‚àíœ‚µ‚½‚¢‚Å‚·B
+             ‚»‚Ì‚½‚ß‚É‚Í <literal>cascade="all-delete-orphan"</literal> ‚ðŽg‚í‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+         </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true" cascade="all-delete-orphan">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+         <para>
+             ’ˆÓFƒRƒŒƒNƒVƒ‡ƒ“‚̃}ƒbƒsƒ“ƒO‚Å <literal>inverse="true"</literal> ‚ÆŽw’肵‚Ä‚àA
+             ƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f‚̃CƒeƒŒ[ƒVƒ‡ƒ“‚É‚æ‚Á‚āAˆË‘RƒJƒXƒP[ƒh‚ªŽÀs‚³‚ê‚Ü‚·B
+             ‚»‚Ì‚½‚ß‚à‚µƒJƒXƒP[ƒh‚ŃIƒuƒWƒFƒNƒg‚ðƒZ[ƒuAíœAXV‚·‚é•K—v‚ª‚ ‚é‚È‚çA
+             ‚»‚ê‚ðƒRƒŒƒNƒVƒ‡ƒ“‚ɒljÁ‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB’P‚É <literal>setParent()</literal> ‚ðŒÄ‚Ô‚¾‚¯‚Å‚Í•s\•ª‚Å‚·B
+         </para>
+               
+     </sect1>
+     
+     <sect1 id="example-parentchild-update">
+         <title>ƒJƒXƒP[ƒh‚Æ <literal>unsaved-value</literal></title>
+     
+         <para>
+             <literal>Parent</literal> ‚ªA‚ ‚é <literal>Session</literal> ‚э[ƒh‚³‚êAUI‚̃AƒNƒVƒ‡ƒ“‚ŕύX‚ª‰Á‚¦‚ç‚êA
+             <literal>update()</literal> ‚ðŒÄ‚ñ‚Å‚±‚̕ύX‚ðV‚µ‚¢ƒZƒbƒVƒ‡ƒ“‚ʼni‘±‰»‚µ‚½‚¢‚Æ‚µ‚Ü‚·B
+             <literal>Parent</literal> ‚ªŽq‹Ÿ‚̃RƒŒƒNƒVƒ‡ƒ“‚ðŽ‚¿AƒJƒXƒP[ƒhXV‚ª—LŒø‚É‚È‚Á‚Ä‚¢‚邽‚߁A
+             Hibernate‚Í‚Ç‚ÌŽq‹Ÿ‚ªV‚µ‚­ƒCƒ“ƒXƒ^ƒ“ƒX‰»‚³‚ꂽ‚©A‚ǂꂪƒf[ƒ^ƒx[ƒX‚ÌŠù‘¶‚̍s‚É‘Š“–‚·‚é‚Ì‚©‚ð’m‚é•K—v‚ª‚ ‚è‚Ü‚·B
+              <literal>Parent</literal> ‚Æ <literal>Child</literal> ‚Ì—¼•û‚ª <literal>java.lang.Long</literal> 
+             Œ^‚ÌŽ¯•ÊƒvƒƒpƒeƒB‚𐶐¬‚µ‚½‚Æ‚µ‚Ü‚µ‚傤B
+             Hibernate‚Í‚Ç‚ÌŽq‹Ÿ‚ªV‚µ‚¢‚à‚Ì‚©‚ðŒˆ’è‚·‚邽‚ß‚ÉŽ¯•ÊƒvƒƒpƒeƒB‚Ì’l‚ðŽg‚¢‚Ü‚·(version‚âtimestampƒvƒƒpƒeƒB‚àŽg‚¦‚Ü‚·B
+             <xref linkend="manipulatingdata-updating-detached"/> ŽQÆ)BHibernate3‚É‚È‚Á‚āA
+             –¾Ž¦“I‚É <literal>unsaved-value</literal> ‚ðŽw’è‚·‚é•K—v‚Í‚È‚­‚È‚è‚Ü‚µ‚½B
+         </para>
+
+         <para>
+             ˆÈ‰º‚̃R[ƒh‚Í <literal>parent</literal> ‚Æ <literal>child</literal> ‚ðXV‚µA<literal>newChild</literal> ‚ð‘}“ü‚µ‚Ü‚·B
+         </para>
+
+         <programlisting><![CDATA[//parent and child were both loaded in a previous session
+//parent‚Æchild‚Í—¼•û‚Æ‚àAˆÈ‘O‚ÌSession‚э[ƒh‚³‚ê‚Ä‚¢‚Ü‚·
+parent.addChild(child);
+Child newChild = new Child();
+parent.addChild(newChild);
+session.update(parent);
+session.flush();]]></programlisting>
+     
+         <para>
+             ‚±‚ê‚ç‚͐¶¬‚³‚ꂽŽ¯•ÊŽq‚̏ꍇ‚É‚Í”ñí‚É—Ç‚¢‚Ì‚Å‚·‚ªAŠ„‚è“–‚Ä‚ç‚ꂽŽ¯•ÊŽq‚Æ•¡‡Ž¯•ÊŽq‚̏ꍇ‚Í‚Ç‚¤‚Å‚µ‚傤‚©H
+             ‚±‚ê‚ÍHibernate‚ªAiƒ†[ƒU‚É‚æ‚芄‚è“–‚Ä‚ç‚ꂽŽ¯•ÊŽq‚ðŽ‚ÂjV‚µ‚­ƒCƒ“ƒXƒ^ƒ“ƒX‰»‚³‚ꂽƒIƒuƒWƒFƒNƒg‚ƁA
+             ˆÈ‘O‚ÌSession‚э[ƒh‚³‚ꂽƒIƒuƒWƒFƒNƒg‚ð‹æ•Ê‚Å‚«‚È‚¢‚½‚߁A‚æ‚è“‚¢‚Å‚·B
+             ‚±‚̏ꍇAHibernate‚̓^ƒCƒ€ƒXƒ^ƒ“ƒv‚©ƒo[ƒWƒ‡ƒ“‚̃vƒƒpƒeƒB‚Ì‚Ç‚¿‚ç‚©‚ðŽg‚¤‚©A“ñŽŸƒLƒƒƒbƒVƒ…‚É–â‚¢‡‚킹‚Ü‚·B
+             Åˆ«‚̏ꍇAs‚ª‘¶Ý‚·‚é‚©‚Ç‚¤‚©ƒf[ƒ^ƒx[ƒX‚ðŒ©‚Ü‚·B
+         </para>
+         
+         <!-- undocumenting
+         <para>
+             There is one further possibility. The <literal>Interceptor</literal> method named 
+             <literal>isUnsaved()</literal> lets the application implement its own strategy for distinguishing
+             newly instantiated objects. For example, you could define a base class for your persistent classes.
+         </para>
+
+         <programlisting><![CDATA[public class Persistent {
+    private boolean _saved = false;
+    public void onSave() {
+        _saved=true;
+    }
+    public void onLoad() {
+        _saved=true;
+    }
+    ......
+    public boolean isSaved() {
+        return _saved;
+    }
+}]]></programlisting>
+     
+         <para>
+             (The <literal>saved</literal> property is non-persistent.)
+             Now implement <literal>isUnsaved()</literal>, along with <literal>onLoad()</literal>
+             and <literal>onSave()</literal> as follows.
+         </para>
+
+         <programlisting><![CDATA[public Boolean isUnsaved(Object entity) {
+    if (entity instanceof Persistent) {
+        return new Boolean( !( (Persistent) entity ).isSaved() );
+    }
+    else {
+        return null;
+    }
+}
+
+public boolean onLoad(Object entity, 
+    Serializable id,
+    Object[] state,
+    String[] propertyNames,
+    Type[] types) {
+
+    if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
+    return false;
+}
+
+public boolean onSave(Object entity,
+    Serializable id,
+    Object[] state,
+    String[] propertyNames,
+    Type[] types) {
+        
+    if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
+    return false;
+}]]></programlisting>
+
+        <para>
+            Don't worry; in Hibernate3 you don't need to write any of this kind of code if you don't want to.
+        </para>
+     -->
+     </sect1>
+
+     <sect1 id="example-parentchild-conclusion">
+         <title>Œ‹˜_
+         </title>
+
+         <para>
+             ‚±‚±‚Å‚Í‚©‚È‚è‚Ì—Ê‚ð—v–ñ‚µ‚½‚̂ŁAÅ‰‚̍ ‚͍¬—‚µ‚Ä‚¢‚é‚悤‚ÉŽv‚í‚ê‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+             ‚µ‚©‚µŽÀÛ‚́A‚·‚ׂĔñí‚É—Ç‚­“®ì‚µ‚Ü‚·B‚Ù‚Æ‚ñ‚Ç‚ÌHibernateƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ł́A‘½‚­‚̏ê–ʂŐeŽqƒpƒ^[ƒ“‚ðŽg—p‚µ‚Ü‚·B
+         </para>
+
+         <para>
+             Å‰‚Ì’i—Ž‚Å‘ã‘Ö•û–@‚ɂ‚¢‚ĐG‚ê‚Ü‚µ‚½Bã‹L‚̂悤‚È–â‘è‚Í <literal>&lt;composite-element&gt;</literal> ƒ}ƒbƒsƒ“ƒO‚̏ꍇ‚Í‘¶Ý‚¹‚¸A
+             ‚É‚à‚©‚©‚í‚炸‚»‚ê‚ÍŠm‚©‚ɐeŽqŠÖŒW‚̃Zƒ}ƒ“ƒeƒBƒNƒX‚ðŽ‚¿‚Ü‚·B
+             ‚µ‚©‚µŽc”O‚È‚ª‚çA•¡‡—v‘fƒNƒ‰ƒX‚É‚Í“ñ‚‚̑傫‚Ȑ§ŒÀ‚ª‚ ‚è‚Ü‚·F
+             1‚‚͕¡‡—v‘f‚̓RƒŒƒNƒVƒ‡ƒ“‚ðŽ‚Â‚±‚Æ‚ª‚Å‚«‚È‚¢‚±‚Æ‚Å‚·B‚à‚¤‚ЂƂ‚́A
+             ƒ†ƒj[ƒN‚Ȑe‚Å‚Í‚È‚¢ƒGƒ“ƒeƒBƒeƒB‚ÌŽq‹Ÿ‚Æ‚È‚é‚ׂ«‚Å‚Í‚È‚¢‚Æ‚¢‚¤‚±‚Æ‚Å‚·
+         </para>
+     
+     </sect1>
+     
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/example_weblog.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/example_weblog.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/example_weblog.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,433 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="example-weblog">
+    <title>—á: WeblogƒAƒvƒŠƒP[ƒVƒ‡ƒ“</title>
+
+    <sect1 id="example-weblog-classes">
+        <title>‰i‘±ƒNƒ‰ƒX
+        </title>
+
+        <para>
+            ‰i‘±ƒNƒ‰ƒX‚ªƒEƒFƒuƒƒO‚ƁAƒEƒFƒuƒƒO‚ÉŒfŽ¦‚³‚ꂽ€–Ú‚ð•\‚µ‚Ä‚¢‚Ü‚·B
+            ‚»‚ê‚ç‚͒ʏí‚̐eŽqŠÖŒW‚Æ‚µ‚ă‚ƒfƒŠƒ“ƒO‚³‚ê‚Ü‚·‚ªA
+            set‚Å‚Í‚È‚­‡˜‚ðŽ‚Á‚½bag‚ðŽg—p‚·‚邱‚Æ‚É‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+import java.util.List;
+
+public class Blog {
+    private Long _id;
+    private String _name;
+    private List _items;
+
+    public Long getId() {
+        return _id;
+    }
+    public List getItems() {
+        return _items;
+    }
+    public String getName() {
+        return _name;
+    }
+    public void setId(Long long1) {
+        _id = long1;
+    }
+    public void setItems(List list) {
+        _items = list;
+    }
+    public void setName(String string) {
+        _name = string;
+    }
+}]]></programlisting>
+
+        <programlisting><![CDATA[package eg;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+
+public class BlogItem {
+    private Long _id;
+    private Calendar _datetime;
+    private String _text;
+    private String _title;
+    private Blog _blog;
+
+    public Blog getBlog() {
+        return _blog;
+    }
+    public Calendar getDatetime() {
+        return _datetime;
+    }
+    public Long getId() {
+        return _id;
+    }
+    public String getText() {
+        return _text;
+    }
+    public String getTitle() {
+        return _title;
+    }
+    public void setBlog(Blog blog) {
+        _blog = blog;
+    }
+    public void setDatetime(Calendar calendar) {
+        _datetime = calendar;
+    }
+    public void setId(Long long1) {
+        _id = long1;
+    }
+    public void setText(String string) {
+        _text = string;
+    }
+    public void setTitle(String string) {
+        _title = string;
+    }
+}]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-weblog-mappings">
+        <title>Hibernate‚̃}ƒbƒsƒ“ƒO
+        </title>
+
+        <para>
+            XMLƒ}ƒbƒsƒ“ƒO‚́A¡‚Å‚Í‚Æ‚Ä‚àŠÈ’P‚È‚Í‚¸‚Å‚·B
+        </para>
+        
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+    <class
+        name="Blog"
+        table="BLOGS">
+
+        <id
+            name="id"
+            column="BLOG_ID">
+
+            <generator class="native"/>
+
+        </id>
+
+        <property
+            name="name"
+            column="NAME"
+            not-null="true"
+            unique="true"/>
+
+        <bag
+            name="items"
+            inverse="true"
+            order-by="DATE_TIME"
+            cascade="all">
+
+            <key column="BLOG_ID"/>
+            <one-to-many class="BlogItem"/>
+
+        </bag>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+    <class
+        name="BlogItem"
+        table="BLOG_ITEMS"
+        dynamic-update="true">
+
+        <id
+            name="id"
+            column="BLOG_ITEM_ID">
+
+            <generator class="native"/>
+
+        </id>
+
+        <property
+            name="title"
+            column="TITLE"
+            not-null="true"/>
+
+        <property
+            name="text"
+            column="TEXT"
+            not-null="true"/>
+
+        <property
+            name="datetime"
+            column="DATE_TIME"
+            not-null="true"/>
+
+        <many-to-one
+            name="blog"
+            column="BLOG_ID"
+            not-null="true"/>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="example-weblog-code">
+        <title>Hibernate‚̃R[ƒh</title>
+
+        <para>
+            ˆÈ‰º‚̃Nƒ‰ƒX‚́A
+            Hibernate‚Å‚±‚ê‚ç‚̃Nƒ‰ƒX‚ðŽg‚Á‚Ä‚Å‚«‚邱‚Æ‚ð‚¢‚­‚‚©Ž¦‚µ‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+
+public class BlogMain {
+    
+    private SessionFactory _sessions;
+    
+    public void configure() throws HibernateException {
+        _sessions = new Configuration()
+            .addClass(Blog.class)
+            .addClass(BlogItem.class)
+            .buildSessionFactory();
+    }
+    
+    public void exportTables() throws HibernateException {
+        Configuration cfg = new Configuration()
+            .addClass(Blog.class)
+            .addClass(BlogItem.class);
+        new SchemaExport(cfg).create(true, true);
+    }
+    
+    public Blog createBlog(String name) throws HibernateException {
+        
+        Blog blog = new Blog();
+        blog.setName(name);
+        blog.setItems( new ArrayList() );
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.persist(blog);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return blog;
+    }
+    
+    public BlogItem createBlogItem(Blog blog, String title, String text)
+                        throws HibernateException {
+        
+        BlogItem item = new BlogItem();
+        item.setTitle(title);
+        item.setText(text);
+        item.setBlog(blog);
+        item.setDatetime( Calendar.getInstance() );
+        blog.getItems().add(item);
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.update(blog);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return item;
+    }
+    
+    public BlogItem createBlogItem(Long blogid, String title, String text)
+                        throws HibernateException {
+        
+        BlogItem item = new BlogItem();
+        item.setTitle(title);
+        item.setText(text);
+        item.setDatetime( Calendar.getInstance() );
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            Blog blog = (Blog) session.load(Blog.class, blogid);
+            item.setBlog(blog);
+            blog.getItems().add(item);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return item;
+    }
+    
+    public void updateBlogItem(BlogItem item, String text)
+                    throws HibernateException {
+        
+        item.setText(text);
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.update(item);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+    }
+    
+    public void updateBlogItem(Long itemid, String text)
+                    throws HibernateException {
+    
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            BlogItem item = (BlogItem) session.load(BlogItem.class, itemid);
+            item.setText(text);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+    }
+    
+    public List listAllBlogNamesAndItemCounts(int max)
+                    throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        List result = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "select blog.id, blog.name, count(blogItem) " +
+                "from Blog as blog " +
+                "left outer join blog.items as blogItem " +
+                "group by blog.name, blog.id " +
+                "order by max(blogItem.datetime)"
+            );
+            q.setMaxResults(max);
+            result = q.list();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return result;
+    }
+    
+    public Blog getBlogAndAllItems(Long blogid)
+                    throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        Blog blog = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "from Blog as blog " +
+                "left outer join fetch blog.items " +
+                "where blog.id = :blogid"
+            );
+            q.setParameter("blogid", blogid);
+            blog  = (Blog) q.uniqueResult();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return blog;
+    }
+    
+    public List listBlogsAndRecentItems() throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        List result = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "from Blog as blog " +
+                "inner join blog.items as blogItem " +
+                "where blogItem.datetime > :minDate"
+            );
+
+            Calendar cal = Calendar.getInstance();
+            cal.roll(Calendar.MONTH, false);
+            q.setCalendar("minDate", cal);
+            
+            result = q.list();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return result;
+    }
+}]]></programlisting>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/filters.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/filters.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/filters.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="filters">
+    <title>ƒf[ƒ^‚̃tƒBƒ‹ƒ^ƒŠƒ“ƒO</title>
+    
+    <para>
+        Hibernate3‚ł́u‰ÂŽ‹«vƒ‹[ƒ‹‚ÉŠî‚¢‚ăf[ƒ^‚ðˆµ‚¤‚½‚߂̉æŠú“I‚È•û–@‚ð—pˆÓ‚µ‚Ä‚¢‚Ü‚·B
+        <emphasis>Hibernate filter</emphasis> ‚̓Oƒ[ƒoƒ‹‚ŁA–¼‘O•t‚«‚ŁAƒpƒ‰ƒ[ƒ^‰»‚³‚ꂽƒtƒBƒ‹ƒ^‚Å‚·B
+        ‚±‚ê‚ÍHibernateƒZƒbƒVƒ‡ƒ“‚²‚Æ‚É—LŒø–³Œø‚ðØ‚è‘Ö‚¦‚ç‚ê‚Ü‚·B
+    </para>
+
+    <sect1 id="objectstate-filters">
+        <title>Hibernate‚̃tƒBƒ‹ƒ^</title>
+
+        <para>
+            Hibernate3‚̓tƒBƒ‹ƒ^ƒNƒ‰ƒCƒeƒŠƒA‚ð‚ ‚ç‚©‚¶‚ß’è‹`‚µA
+            ‚±‚ê‚ç‚̃tƒBƒ‹ƒ^‚ðƒNƒ‰ƒX‚âƒRƒŒƒNƒVƒ‡ƒ“ƒŒƒxƒ‹‚ɉÁ‚¦‚é‹@”\‚ð‰Á‚¦‚Ü‚µ‚½B
+            ƒtƒBƒ‹ƒ^ƒNƒ‰ƒCƒeƒŠƒA‚͐§–ñß‚ð’è‹`‚·‚é‹@”\‚Å‚·B
+            ‚±‚ê‚ç‚̃tƒBƒ‹ƒ^ðŒ‚̓pƒ‰ƒ[ƒ^‰»‚Å‚«‚é‚Æ‚¢‚¤‚±‚Æ‚ðœ‚«A
+            ƒNƒ‰ƒX‚₳‚Ü‚´‚܂ȃRƒŒƒNƒVƒ‡ƒ“—v‘f‚Å—˜—p‰Â”\‚È¢where£‹å‚É”ñí‚É‚æ‚­Ž—‚Ä‚¢‚Ü‚·B
+            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚́A—^‚¦‚ç‚ꂽƒtƒBƒ‹ƒ^‚ð‰Â”\‚É‚·‚ׂ«‚©A
+            ‚»‚µ‚Ä‚»‚̃pƒ‰ƒ[ƒ^’l‚ð‰½‚É‚·‚ׂ«‚©‚ðŽÀsŽž‚ÉŒˆ’è‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            ƒtƒBƒ‹ƒ^‚̓f[ƒ^ƒx[ƒXƒrƒ…[‚̂悤‚ÉŽg—p‚³‚ê‚Ü‚·‚ªAƒAƒvƒŠƒP[ƒVƒ‡ƒ““à‚ł̓pƒ‰ƒ[ƒ^‰»‚³‚ê‚Ü‚·B
+            
+        </para>
+
+        <para>
+            ƒtƒBƒ‹ƒ^‚ðŽg‚¤‚½‚ß‚É‚Í‚Ü‚¸A“KØ‚ȃ}ƒbƒsƒ“ƒO—v‘f‚É’è‹`A’ljÁ‚µ‚È‚­‚Ä‚Í‚È‚è‚Ü‚¹‚ñB
+            ƒtƒBƒ‹ƒ^‚ð’è‹`‚·‚邽‚߂ɂ́A
+            <literal>&lt;hibernate-mapping/&gt;</literal> —v‘f“à‚Å <literal>&lt;filter-def/&gt;</literal> —v‘f‚ðŽg—p‚µ‚Ü‚·BF
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="myFilter">
+    <filter-param name="myFilterParam" type="string"/>
+</filter-def>]]></programlisting>
+
+        <para>
+            ‚»‚¤‚µ‚ătƒBƒ‹ƒ^‚̓Nƒ‰ƒX‚Ö‚ÆŒ‹‚Ñ•t‚¯‚ç‚ê‚Ü‚·BF
+        </para>
+
+        <programlisting><![CDATA[<class name="myClass" ...>
+    ...
+    <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</class>]]></programlisting>
+
+        <para>
+            ‚Ü‚½AƒRƒŒƒNƒVƒ‡ƒ“‚ɑ΂µ‚Ä‚ÍŽŸ‚̂悤‚É‚È‚è‚Ü‚·BF
+        </para>
+
+        <programlisting><![CDATA[<set ...>
+    <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</set>]]></programlisting>
+
+        <para>
+            ‚Ç‚¿‚ç‚ɑ΂µ‚Ä‚à(‚Ü‚½A‚»‚ꂼ‚ê‚𕡐”)“¯Žž‚ɐݒ肷‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+        </para>
+
+        <para>
+            <literal>Session</literal> ã‚̃ƒ\ƒbƒh‚Í <literal>enableFilter(String filterName)</literal>,
+            <literal>getEnabledFilter(String filterName)</literal>, <literal>disableFilter(String filterName)</literal> ‚Å‚·B
+            ƒfƒtƒHƒ‹ƒg‚ł́AƒtƒBƒ‹ƒ^‚Í—^‚¦‚ç‚ꂽƒZƒbƒVƒ‡ƒ“‚ɑ΂µ‚ÄŽg—p <emphasis>‚Å‚«‚Ü‚¹‚ñ</emphasis> B
+            <literal>Filter</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚ð•Ô‚è’l‚Æ‚·‚é <literal>Session.enabledFilter()</literal> ƒƒ\ƒbƒh‚ðŽg‚¤‚±‚ƂŁA
+            ƒtƒBƒ‹ƒ^‚Í–¾Ž¦“I‚ÉŽg—p‰Â”\‚Æ‚È‚è‚Ü‚·B
+            ã‚Å’è‹`‚µ‚½’Pƒ‚ȃtƒBƒ‹ƒ^‚ÌŽg—p‚́A‚±‚̂悤‚É‚È‚è‚Ü‚·BF
+        </para>
+
+        <programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
+
+        <para>
+            org.hibernate.FilterƒCƒ“ƒ^[ƒtƒFƒCƒX‚̃ƒ\ƒbƒh‚́A
+            Hibernate‚Ì‘½‚­‚É‹¤’Ê‚µ‚Ä‚¢‚郁ƒ\ƒbƒh˜A½‚ð‹–‚µ‚Ä‚¢‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <para>
+            —LŒø‚ȃŒƒR[ƒhƒf[ƒ^ƒpƒ^[ƒ“‚ðŽ‚ÂˆêŽžƒf[ƒ^‚ðŽg‚Á‚½Š®‘S‚È—á‚Å‚·F
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="effectiveDate">
+    <filter-param name="asOfDate" type="date"/>
+</filter-def>
+
+<class name="Employee" ...>
+...
+    <many-to-one name="department" column="dept_id" class="Department"/>
+    <property name="effectiveStartDate" type="date" column="eff_start_dt"/>
+    <property name="effectiveEndDate" type="date" column="eff_end_dt"/>
+...
+    <!--
+        Note that this assumes non-terminal records have an eff_end_dt set to
+        a max db date for simplicity-sake
+        
+
+    -->
+    <filter name="effectiveDate"
+            condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+</class>
+
+<class name="Department" ...>
+...
+    <set name="employees" lazy="true">
+        <key column="dept_id"/>
+        <one-to-many class="Employee"/>
+        <filter name="effectiveDate"
+                condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            í‚ÉŒ»Ý‚Ì—LŒøƒŒƒR[ƒh‚ð•Ô‹p‚·‚邱‚Æ‚ð•ÛØ‚·‚邽‚߂ɁA
+            ’Pƒ‚ɁAŽÐˆõƒf[ƒ^‚ÌŒŸõ‚æ‚è‘O‚ɃZƒbƒVƒ‡ƒ“ã‚̃tƒBƒ‹ƒ^‚ð—LŒø‚É‚µ‚Ü‚·B
+            
+            
+        </para>
+
+<programlisting><![CDATA[Session session = ...;
+session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
+List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
+         .setLong("targetSalary", new Long(1000000))
+         .list();
+]]></programlisting>
+
+        <para>
+            ã‹L‚ÌHQL‚ł́AŒ‹‰Ê‚Ì‹‹—¿‚̐§–ñ‚ɂ‚¢‚Ä–¾Ž¦“I‚ɐG‚ꂽ‚¾‚¯‚Å‚·‚ªA
+            —LŒø‚É‚È‚Á‚Ä‚¢‚éƒtƒBƒ‹ƒ^‚Ì‚¨‚©‚°‚ŁA‚±‚̃NƒGƒŠ‚Í‹‹—¿‚ª100–œƒhƒ‹ˆÈã‚ÌŒ»–ð‚̎Јõ‚¾‚¯‚ð•Ô‚µ‚Ü‚·B
+        </para>
+
+        <para>
+            (HQL‚©ƒ[ƒhƒtƒFƒbƒ`‚ŁjŠO•”Œ‹‡‚ðŽ‚ÂƒtƒBƒ‹ƒ^‚ðŽg‚¤‚‚à‚è‚È‚çA
+            ðŒŽ®‚Ì•ûŒü‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            
+            ‚±‚ê‚͍¶ŠO•”Œ‹‡‚Ì‚½‚߂ɐݒ肷‚é‚Ì‚ªÅ‚àˆÀ‘S‚Å‚·B
+            ˆê”Ê“I‚ɁA‰‰ŽZŽq‚ÌŒãƒJƒ‰ƒ€–¼‚É‘±‚¯‚čŏ‰‚̃pƒ‰ƒ[ƒ^‚ð”z’u‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/inheritance_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/inheritance_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/inheritance_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,487 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="inheritance">
+    <title>Œp³ƒ}ƒbƒsƒ“ƒO</title>
+
+    <sect1 id="inheritance-strategies" revision="3">
+        <title>3‚‚̐헪</title>
+
+        <para>
+            Hibernate‚Í3‚‚̊î–{“I‚ÈŒp³‚̃}ƒbƒsƒ“ƒOí—ª‚ðƒTƒ|[ƒg‚µ‚Ü‚·B
+        </para>
+
+        <itemizedlist>
+        <listitem>
+        <para>
+            ƒNƒ‰ƒXŠK‘w‚²‚Ƃ̃e[ƒuƒ‹itable-per-class-hierarchyj
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            ƒTƒuƒNƒ‰ƒX‚²‚Ƃ̃e[ƒuƒ‹itable-per-subclassj
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            ‹ïÛƒNƒ‰ƒX‚²‚Ƃ̃e[ƒuƒ‹itable-per-concrete-classj
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            ‰Á‚¦‚Ä4‚–ڂɁAHibernate‚͂킸‚©‚ɈقȂ鐫Ž¿‚ðŽ‚Á‚½ƒ|ƒŠƒ‚[ƒtƒBƒYƒ€‚ðƒTƒ|[ƒg‚µ‚Ü‚·B
+        </para>
+
+        <itemizedlist>
+        <listitem>
+        <para>
+            ˆÃ–Ù“Iƒ|ƒŠƒ‚[ƒtƒBƒYƒ€
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            “¯ˆê‚ÌŒp³ŠK‘w‚̈قȂéƒuƒ‰ƒ“ƒ`‚ɑ΂µ‚ĈقȂéƒ}ƒbƒsƒ“ƒOí—ª‚ðŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+            ‚»‚̏ꍇ‚É‚Í‘S‘Ì‚ÌŠK‘w‚É“n‚éƒ|ƒŠƒ‚[ƒtƒBƒYƒ€‚ðŽÀŒ»‚·‚邽‚߂ɈÖٓIƒ|ƒŠƒ‚[ƒtƒBƒYƒ€‚ðŽg—p‚µ‚Ü‚·B
+            ‚µ‚©‚µAHibernate‚Í“¯‚¶ƒ‹[ƒg <literal>&lt;class&gt;</literal> —v‘f“à‚Å
+            <literal>&lt;subclass&gt;</literal> ƒ}ƒbƒsƒ“ƒOA<literal>&lt;joined-subclass&gt;</literal> ƒ}ƒbƒsƒ“ƒOA
+            <literal>&lt;union-subclass&gt;</literal> ƒ}ƒbƒsƒ“ƒO‚Ì“¯ŽžŽg—p‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚¹‚ñB
+            <literal>&lt;subclass&gt;</literal> —v‘f‚Æ <literal>&lt;join&gt;</literal> —v‘f‚ð‘g‚ݍ‡‚킹‚邱‚ƂŁA
+            “¯ˆê <literal>&lt;class&gt;</literal> —v‘f“à‚Å‚Ì table-per-hierarchy í—ª‚Æ
+            table-per-subclass í—ª‚Ì“¯ŽžŽg—p‚͉”\‚Å‚·BŽŸ‚Ì—á‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <para>
+             <literal>subclass</literal>, <literal>union-subclass</literal> ‚Æ 
+             <literal>joined-subclass</literal> ƒ}ƒbƒsƒ“ƒO‚𕡐”‚̃}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚É’è‹`‚·‚邱‚Æ‚ªo—ˆA
+             <literal>hibernate-mapping</literal> ‚Ì’¼‰º‚É”z’u‚µ‚Ü‚·B
+             ‚±‚ê‚͐V‚µ‚¢ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ð’ljÁ‚·‚邾‚¯‚ŁAƒNƒ‰ƒXŠK‘w‚ðŠg’£‚Å‚«‚é‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+             ‚ ‚ç‚©‚¶‚߃}ƒbƒv‚µ‚½ƒX[ƒp[ƒNƒ‰ƒX‚ðŽw’肵‚āAƒTƒuƒNƒ‰ƒXƒ}ƒbƒsƒ“ƒO‚É <literal>extends</literal> 
+             ‘®«‚ð‹Lq‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+             ’ˆÓF‚±‚Ì“Á’¥‚É‚æ‚èAˆÈ‘O‚̓}ƒbƒsƒ“ƒOEƒhƒLƒ…ƒƒ“ƒg‚̏‡”Ô‚ªd—v‚Å‚µ‚½B
+             Hibernate3‚©‚ç‚́AextendsƒL[ƒ[ƒh‚ðŽg‚¤ê‡Aƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚̏‡”Ô‚Í–â‘è‚É‚È‚è‚Ü‚¹‚ñB
+             
+             ‚P‚‚̃}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹“à‚ŏ‡”Ô•t‚¯‚ðs‚¤‚Æ‚«‚́A
+             ˆË‘R‚Æ‚µ‚āAƒTƒuƒNƒ‰ƒX‚ð’è‹`‚·‚é‘O‚ɃX[ƒp[ƒNƒ‰ƒX‚ð’è‹`‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B)
+         </para>
+
+         <programlisting><![CDATA[
+ <hibernate-mapping>
+     <subclass name="DomesticCat" extends="Cat" discriminator-value="D">
+          <property name="name" type="string"/>
+     </subclass>
+ </hibernate-mapping>]]></programlisting>
+
+
+        <sect2 id="inheritance-tableperclass" >
+        <title>ƒNƒ‰ƒXŠK‘w‚²‚Ƃ̃e[ƒuƒ‹itable-per-class-hierarchyj</title>
+
+        <para>
+            —Ⴆ‚΁AƒCƒ“ƒ^[ƒtƒFƒCƒX <literal>Payment</literal> ‚ƁA‚»‚ê‚ðŽÀ‘•‚µ‚½
+            <literal>CreditCardPayment</literal>A<literal>CashPayment</literal>A
+            <literal>ChequePayment</literal> ‚ª‚ ‚é‚Æ‚µ‚Ü‚·BŠK‘w‚²‚Ƃ̃e[ƒuƒ‹ƒ}ƒbƒsƒ“ƒO‚Í
+            ˆÈ‰º‚̂悤‚É‚È‚è‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        ...
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        ...
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            ‚¿‚傤‚Ljê‚‚̃e[ƒuƒ‹‚ª•K—v‚Å‚·B
+            ‚±‚̃}ƒbƒsƒ“ƒOí—ª‚ɂ͈ê‚‘傫‚Ȑ§ŒÀ‚ª‚ ‚è‚Ü‚·B
+            <literal>CCTYPE</literal> ‚̂悤‚ȁAƒTƒuƒNƒ‰ƒX‚Ő錾‚³‚ꂽƒJƒ‰ƒ€‚Í <literal>NOT NULL</literal> 
+            §–ñ‚ðŽ‚Ä‚Ü‚¹‚ñB
+        </para>
+        
+        </sect2>
+
+        <sect2 id="inheritance-tablepersubclass">
+        <title>ƒTƒuƒNƒ‰ƒX‚²‚Ƃ̃e[ƒuƒ‹itable-per-subclassj</title>
+
+        <para>
+            table-per-subclass ƒ}ƒbƒsƒ“ƒO‚͈ȉº‚̂悤‚É‚È‚è‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        ...
+    </joined-subclass>
+</class>]]></programlisting>
+
+        <para>
+            ‚±‚̃}ƒbƒsƒ“ƒO‚É‚Í4‚‚̃e[ƒuƒ‹‚ª•K—v‚Å‚·B3‚‚̃TƒuƒNƒ‰ƒXƒe[ƒuƒ‹‚Í
+            ƒX[ƒp[ƒNƒ‰ƒXƒe[ƒuƒ‹‚Æ‚ÌŠÖ˜A‚ðŽ¦‚·ŽåƒL[‚ðŽ‚Á‚Ä‚¢‚Ü‚·
+            iŽÀÛAŠÖŒWƒ‚ƒfƒ‹ã‚͈ê‘ΈêŠÖ˜A‚Å‚·jB
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-tablepersubclass-discriminator" revision="2">
+        <title>•Ù•ÊŽq‚ð—p‚¢‚½ table-per-subclass</title>
+
+        <para>
+            Hibernate‚Ì table-per-subclass ŽÀ‘•‚́AdiscriminatorƒJƒ‰ƒ€‚ð•K—v‚Æ‚µ‚È‚¢‚±‚Æ‚ðŠo‚¦‚Ä‚¨‚¢‚Ä‚­‚¾‚³‚¢B
+            HibernateˆÈŠO‚ÌO/Rƒ}ƒbƒp[‚́Atable-per-subclass ‚ɈقȂéŽÀ‘•‚ð—p‚¢‚Ü‚·B
+            ‚»‚ê‚́AƒX[ƒp[ƒNƒ‰ƒX‚̃e[ƒuƒ‹‚Ƀ^ƒCƒvdiscriminatorƒJƒ‰ƒ€‚ð•K—v‚Æ‚µ‚Ü‚·B
+            ‚±‚̃Aƒvƒ[ƒ`‚ÍŽÀ‘•‚ª¢“ï‚É‚È‚è‚Ü‚·‚ªAŠÖŒW‚ÌŽ‹“_‚©‚猩‚é‚ƁA‚æ‚萳Šm‚È‚à‚Ì‚Å‚·B
+            table-per-subclass í—ª‚ÅdiscriminatorƒJƒ‰ƒ€‚ðŽg‚¢‚½‚¯‚ê‚΁A
+            <literal>&lt;subclass&gt;</literal> ‚Æ <literal>&lt;join&gt;</literal> 
+            ‚ðˆÈ‰º‚̂悤‚É‘g‚ݍ‡‚킹‚ÄŽg‚Á‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <join table="CREDIT_PAYMENT">
+            <key column="PAYMENT_ID"/>
+            <property name="creditCardType" column="CCTYPE"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        <join table="CASH_PAYMENT">
+            <key column="PAYMENT_ID"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        <join table="CHEQUE_PAYMENT" fetch="select">
+            <key column="PAYMENT_ID"/>
+            ...
+        </join>
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            ƒIƒvƒVƒ‡ƒ“‚Ì <literal>fetch="select"</literal> éŒ¾‚́A
+            ƒX[ƒp[ƒNƒ‰ƒX‚̃NƒGƒŠŽÀsŽž‚ÉŠO•”Œ‹‡‚ðŽg‚Á‚āA
+            ƒTƒuƒNƒ‰ƒX‚Ì <literal>ChequePayment</literal> ƒf[ƒ^‚ðŽæ“¾‚µ‚È‚¢‚悤‚ÉŽw’è‚·‚邽‚ß‚Ì‚à‚Ì‚Å‚·B
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
+        <title>table-per-subclass ‚Æ table-per-class-hierarchy ‚̍¬‡</title>
+
+        <para>
+            ‚±‚̃Aƒvƒ[ƒ`‚ðŽg—p‚·‚é‚ƁAtable-per-hierarchy ‚Æ table-per-subclass í—ª‚ð
+            ‘g‚ݍ‡‚킹‚鎖‚à‰Â”\‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <join table="CREDIT_PAYMENT">
+            <property name="creditCardType" column="CCTYPE"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        ...
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        ...
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            ‚¢‚¸‚ê‚̃}ƒbƒsƒ“ƒOí—ª‚Å‚ ‚Á‚Ä‚àAƒ‹[ƒg‚Å‚ ‚é <literal>Payment</literal> ƒNƒ‰ƒX‚Ö‚Ì
+            ƒ|ƒŠƒ‚[ƒtƒBƒbƒN‚ÈŠÖ˜A‚Í <literal>&lt;many-to-one&gt;</literal> ‚ðŽg‚Á‚ă}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
+    
+        </sect2>
+
+        <sect2 id="inheritance-tableperconcrete" revision="2">
+        <title>‹ïÛƒNƒ‰ƒX‚²‚Ƃ̃e[ƒuƒ‹itable-per-concrete-classj</title>
+
+        <para>
+            table-per-concrete-class í—ª‚̃}ƒbƒsƒ“ƒO‚ɑ΂·‚éƒAƒvƒ[ƒ`‚́A2‚‚ ‚è‚Ü‚·B
+            1‚Â–Ú‚Í <literal>&lt;union-subclass&gt;</literal> ‚ð—˜—p‚·‚é•û–@‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="sequence"/>
+    </id>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </union-subclass>
+    <union-subclass name="CashPayment" table="CASH_PAYMENT">
+        ...
+    </union-subclass>
+    <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        ...
+    </union-subclass>
+</class>]]></programlisting>
+
+        <para>
+            ƒTƒuƒNƒ‰ƒX‚²‚Æ‚É3‚‚̃e[ƒuƒ‹‚ª•K—v‚Å‚·B‚»‚ꂼ‚ê‚̃e[ƒuƒ‹‚́AŒp³ƒvƒƒpƒeƒB‚ðŠÜ‚ñ‚¾A
+            ƒNƒ‰ƒX‚Ì‘S‚ẴvƒƒpƒeƒB‚ɑ΂·‚éƒJƒ‰ƒ€‚ð’è‹`‚µ‚Ü‚·B
+        </para>
+        
+        <para>
+            ‚±‚̃Aƒvƒ[ƒ`‚ɂ͐§ŒÀ‚ª‚ ‚è‚Ü‚·B
+            ‚»‚ê‚́AƒvƒƒpƒeƒB‚ªƒX[ƒp[ƒNƒ‰ƒX‚Ƀ}ƒbƒsƒ“ƒO‚³‚ê‚Ä‚¢‚½ê‡A
+            ‘S‚ẴTƒuƒNƒ‰ƒX‚É‚¨‚¢‚ăJƒ‰ƒ€–¼‚ª“¯‚¶‚Å‚È‚¯‚ê‚΂Ȃç‚È‚¢‚Æ‚¢‚¤‚à‚Ì‚Å‚·B
+           iHibernate‚̍¡Œã‚̃ŠƒŠ[ƒX‚Ŋɘa‚³‚ê‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñjB
+            &lt;union-subclass&gt; ‚ðŽg‚Á‚½ table-per-concrete-class í—ª‚Å‚ÍŽ¯•ÊŽq¶¬í—ª‚ðŽg—p‚Å‚«‚Ü‚¹‚ñB
+            ŽåƒL[‚𐶐¬‚·‚邽‚߂̃V[ƒh‚́A‘S‚Ä‚Ì union subclass ‚ÌŠK‘w“à‚Å‹¤—L‚·‚é•K—v‚ª‚ ‚é‚©‚ç‚Å‚·B
+        </para>
+
+        <para>
+            ‚à‚µƒX[ƒp[ƒNƒ‰ƒX‚ª’ŠÛƒNƒ‰ƒX‚È‚çA<literal>abstract="true"</literal>‚ƃ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+            ‚à‚¿‚ë‚ñAƒX[ƒp[ƒNƒ‰ƒX‚ª’ŠÛƒNƒ‰ƒX‚Å‚È‚¢‚È‚çAƒX[ƒp[ƒNƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ð
+            •ÛŽ‚·‚邽‚߂̃e[ƒuƒ‹‚̒ljÁ‚ª•K—v‚Æ‚È‚è‚Ü‚·(ã‚Ì—á‚ł̃fƒtƒHƒ‹ƒg‚Í <literal>PAYMENT</literal> )B
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-tableperconcreate-polymorphism">
+        <title>ˆÃ–Ù“Iƒ|ƒŠƒ‚[ƒtƒBƒYƒ€‚ð—p‚¢‚½ table-per-concrete-class</title>
+
+        <para>
+            ‚à‚¤ˆê‚‚̃Aƒvƒ[ƒ`‚͈ÖٓIƒ|ƒŠƒ‚[ƒtƒBƒYƒ€‚ÌŽg—p‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+    <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CREDIT_AMOUNT"/>
+    ...
+</class>
+
+<class name="CashPayment" table="CASH_PAYMENT">
+    <id name="id" type="long" column="CASH_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CASH_AMOUNT"/>
+    ...
+</class>
+
+<class name="ChequePayment" table="CHEQUE_PAYMENT">
+    <id name="id" type="long" column="CHEQUE_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CHEQUE_AMOUNT"/>
+    ...
+</class>]]></programlisting>
+           
+        <para>
+            <literal>Payment</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ª‚Ç‚±‚É‚à–¾Ž¦“I‚ÉŽ¦‚³‚ê‚Ä‚¢‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚»‚µ‚āA<literal>Payment</literal> ƒvƒƒpƒeƒB‚ª‚»‚ꂼ‚ê‚̃TƒuƒNƒ‰ƒX‚Ƀ}ƒbƒsƒ“ƒO‚³‚ê‚Ä‚¢‚邱‚Æ‚É‚à’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚à‚µd•¡‚ð”ð‚¯‚½‚¢‚Ì‚Å‚ ‚ê‚΁AXMLƒGƒ“ƒeƒBƒeƒB‚Ì—˜—p‚ðl‚¦‚Ä‚­‚¾‚³‚¢B
+            i—áF <literal>DOCTYPE</literal> éŒ¾‚É‚¨‚¯‚é <literal>[ &lt;!ENTITY allproperties SYSTEM "allproperties.xml"&gt; ]</literal>
+              ‚ƁAƒ}ƒbƒsƒ“ƒO‚É‚¨‚¯‚é <literal>&amp;allproperties;</literal>j
+        </para>
+        
+        <para>
+            ‚±‚̃Aƒvƒ[ƒ`‚ÌŒ‡“_‚́AHibernate‚ªƒ|ƒŠƒ‚[ƒtƒBƒbƒN‚ȃNƒGƒŠ‚ÌŽÀsŽž‚ÉSQL <literal>UNION</literal> 
+            ‚𐶐¬‚µ‚È‚¢“_‚Å‚·B
+        </para>
+
+        <para>
+            ‚±‚̃}ƒbƒsƒ“ƒOí—ª‚ɑ΂µ‚ẮA<literal>Payment</literal> ‚ւ̃|ƒŠƒ‚[ƒtƒBƒbƒN‚ÈŠÖ˜A‚Í
+            ’ʏíA<literal>&lt;any&gt;</literal> ‚ðŽg‚Á‚ă}ƒbƒsƒ“ƒO‚³‚ê‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
+    <meta-value value="CREDIT" class="CreditCardPayment"/>
+    <meta-value value="CASH" class="CashPayment"/>
+    <meta-value value="CHEQUE" class="ChequePayment"/>
+    <column name="PAYMENT_CLASS"/>
+    <column name="PAYMENT_ID"/>
+</any>]]></programlisting>
+           
+        </sect2>
+
+        <sect2 id="inheritace-mixingpolymorphism">
+        <title>‘¼‚ÌŒp³ƒ}ƒbƒsƒ“ƒO‚ƈÖٓIƒ|ƒŠƒ‚[ƒtƒBƒYƒ€‚Ì‘g‚ݍ‡‚킹</title>
+
+        <para>
+            ‚±‚̃}ƒbƒsƒ“ƒO‚ɂ‚¢‚Ă̍X‚Ȃ钍ˆÓ“_‚ª‚ ‚è‚Ü‚·B
+            ƒTƒuƒNƒ‰ƒX‚ªŽ©g‚ð <literal>&lt;class&gt;</literal> —v‘f‚Æ‚µ‚ă}ƒbƒsƒ“ƒO‚µ‚Ä‚¢‚é‚̂ŁA
+            i‚©‚ <literal>Payment</literal> ‚Í’P‚È‚éƒCƒ“ƒ^[ƒtƒFƒCƒX‚Ȃ̂ŁjA
+            ‚»‚ꂼ‚ê‚̃TƒuƒNƒ‰ƒX‚ÍŠÈ’P‚É‚»‚Ì‘¼‚ÌŒp³ŠK‘w‚̈ꕔ‚Æ‚È‚è‚Ü‚·B
+            i‚µ‚©‚àA¡‚Ü‚Å‚Ç‚¨‚è <literal>Payment</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ɑ΂·‚éƒ|ƒŠƒ‚[ƒtƒBƒbƒN‚ȃNƒGƒŠ
+            ‚ðŽg—p‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·j
+       </para>
+
+        <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+    <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="CREDIT_CARD" type="string"/>
+    <property name="amount" column="CREDIT_AMOUNT"/>
+    ...
+    <subclass name="MasterCardPayment" discriminator-value="MDC"/>
+    <subclass name="VisaPayment" discriminator-value="VISA"/>
+</class>
+
+<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
+    <id name="id" type="long" column="TXN_ID">
+        <generator class="native"/>
+    </id>
+    ...
+    <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="amount" column="CASH_AMOUNT"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="amount" column="CHEQUE_AMOUNT"/>
+        ...
+    </joined-subclass>
+</class>]]></programlisting>
+
+        <para>
+            ‚à‚¤ˆê“xq‚ׂ܂·‚ªA<literal>Payment</literal> ‚Í–¾Ž¦“I‚É’è‹`‚³‚ê‚Ü‚¹‚ñB
+            ‚à‚µA<literal>Payment</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ɑ΂µ‚ăNƒGƒŠ‚ðŽÀs‚·‚é‚È‚ç
+            i—Ⴆ‚Î <literal>from Payment</literal> ß‚ðŽg‚Á‚ājA
+            Hibernate‚ÍŽ©“®“I‚É <literal>CreditCardPayment</literal> 
+            i‚ÆCreditCardPayment‚̃TƒuƒNƒ‰ƒXA<literal>Payment</literal> ‚ÌŽÀ‘•‚Å‚ ‚邽‚߁jA
+            ‚¨‚æ‚сA<literal>CashPayment</literal> A<literal>ChequePayment</literal> 
+            ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ð•Ô‚µ‚Ü‚·B
+            <literal>NonelectronicTransaction</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚Í•Ô‚µ‚Ü‚¹‚ñB
+        </para>
+        
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="inheritance-limitations">
+        <title>§ŒÀ</title>
+
+        <para>
+            table-per-concrete-class ƒ}ƒbƒsƒ“ƒOí—ª‚ւ́uˆÃ–Ù“Iƒ|ƒŠƒ‚[ƒtƒBƒYƒ€vƒAƒvƒ[ƒ`‚É‚Í
+            ‚¢‚­‚‚©‚̐§ŒÀ‚ª‚ ‚è‚Ü‚·B<literal>&lt;union-subclass&gt;</literal> ƒ}ƒbƒsƒ“ƒO‚ɑ΂µ‚Ä‚à
+            ­‚µŽã‚߂̐§ŒÀ‚ª‚ ‚è‚Ü‚·B
+        </para>
+
+        <para>
+            ŽŸ‚̃e[ƒuƒ‹‚ɁAHibernate‚É‚¨‚¯‚étable-per-concrete-classƒ}ƒbƒsƒ“ƒO‚Ì
+            §ŒÀ‚âˆÃ–Ù“Iƒ|ƒŠƒ‚[ƒtƒBƒYƒ€‚̐§ŒÀ‚ðŽ¦‚µ‚Ü‚·B
+        </para>
+            
+        <table frame="topbot">
+            <title>Œp³ƒ}ƒbƒsƒ“ƒO‚Ì‹@”\</title>
+            <tgroup cols='8' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="1*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <colspec colname='c6' colwidth="1*"/>
+            <colspec colname='c7' colwidth="1*"/>
+            <colspec colname='c8' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Œp³í—ª</entry>
+              <entry>‘½‘Έê‚̃|ƒŠƒ‚[ƒtƒBƒYƒ€</entry>
+              <entry>ˆê‘Έê‚̃|ƒŠƒ‚[ƒtƒBƒYƒ€</entry>
+              <entry>ˆê‘Α½‚̃|ƒŠƒ‚[ƒtƒBƒYƒ€</entry>
+              <entry>‘½‘Α½‚̃|ƒŠƒ‚[ƒtƒBƒYƒ€</entry>
+              <entry>ƒ|ƒŠƒ‚[ƒtƒBƒYƒ€‚ðŽg‚Á‚½<literal>load()/get()</literal></entry>
+              <entry>ƒ|ƒŠƒ‚[ƒtƒBƒYƒ€‚ðŽg‚Á‚½ƒNƒGƒŠ</entry>
+              <entry>ƒ|ƒŠƒ‚[ƒtƒBƒYƒ€‚ðŽg‚Á‚½Œ‹‡</entry>
+              <entry>ŠO•”Œ‹‡‚É‚æ‚éƒtƒFƒbƒ`</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>table per class-hierarchy</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal></entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>ƒTƒ|[ƒg</emphasis></entry>
+            </row>
+            <row>
+                <entry>table per subclass</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal></entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>ƒTƒ|[ƒg</emphasis></entry>
+            </row>
+            <row>
+                <entry>table per concrete-class (union-subclass)</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal> (for <literal>inverse="true"</literal> only)</entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>ƒTƒ|[ƒg</emphasis></entry>
+            </row>
+            <row>
+                <entry>table per concrete class (implicit polymorphism)</entry>
+                <entry><literal>&lt;any&gt;</literal></entry>
+                <entry><emphasis>ƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚¹‚ñ</emphasis></entry>
+                <entry><emphasis>ƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚¹‚ñ</emphasis></entry>
+                <entry><literal>&lt;many-to-any&gt;</literal></entry>
+                <entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><emphasis>ƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚¹‚ñ</emphasis></entry>
+                <entry><emphasis>ƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚¹‚ñ</emphasis></entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/performance.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/performance.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/performance.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1378 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="performance">
+    <title>ƒpƒtƒH[ƒ}ƒ“ƒX‚̉ü‘P</title>
+
+    <sect1 id="performance-fetching" revision="2">
+        <title>ƒtƒFƒbƒ`í—ª</title>
+
+        <para>
+            <emphasis>ƒtƒFƒbƒ`í—ª</emphasis> ‚́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ªŠÖ˜A‚ðƒiƒrƒQ[ƒg‚·‚é•K—v‚ª‚ ‚é
+            ‚Æ‚«‚ɁAHibernate‚ªŠÖ˜AƒIƒuƒWƒFƒNƒg‚𕜌³‚·‚邽‚ß‚ÉŽg—p‚·‚éí—ª‚Å‚·BƒtƒFƒbƒ`í—ª‚ÍO/Rƒ}ƒbƒsƒ“ƒO‚Ì
+            ƒƒ^ƒf[ƒ^‚ɐ錾‚·‚é‚©A“Á’è‚ÌHQLA <literal>Criteria</literal> ƒNƒGƒŠ‚ŃI[ƒo[ƒ‰ƒCƒh‚µ‚Ü‚·B
+        </para>
+
+        <para>
+            Hibernate3‚ÍŽŸ‚ÉŽ¦‚·ƒtƒFƒbƒ`í—ª‚ð’è‹`‚µ‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <emphasis>Œ‹‡ƒtƒFƒbƒ`</emphasis> - Hibernate‚Í <literal>OUTER JOIN</literal> ‚ðŽg‚Á‚āA
+                    ŠÖ˜A‚·‚éƒCƒ“ƒXƒ^ƒ“ƒX‚âƒRƒŒƒNƒVƒ‡ƒ“‚ð‚P‚Â‚Ì <literal>SELECT</literal> 
+                    ‚Å•œŒ³‚µ‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>ƒZƒŒƒNƒgƒtƒFƒbƒ`</emphasis> - 2‰ñ–Ú‚Ì <literal>SELECT</literal>
+                    ‚ÅŠÖ˜A‚·‚éƒGƒ“ƒeƒBƒeƒB‚âƒRƒŒƒNƒVƒ‡ƒ“‚𕜌³‚µ‚Ü‚·B <literal>lazy="false"</literal> 
+                    ‚Å–¾Ž¦“I‚É’x‰„ƒtƒFƒbƒ`‚𖳌ø‚É‚µ‚È‚¯‚ê‚΁A‚±‚Ì2‰ñ–Ú‚Ìselect‚ÍŽÀÛ‚É
+                    ŠÖ˜A‚ɃAƒNƒZƒX‚µ‚½‚Æ‚«‚Ì‚ÝŽÀs‚³‚ê‚é‚Å‚µ‚傤B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>ƒTƒuƒZƒŒƒNƒgƒtƒFƒbƒ`</emphasis> - 2‰ñ–Ú‚Ì <literal>SELECT</literal> 
+                    ‚ŁA’¼‘O‚̃NƒGƒŠ‚âƒtƒFƒbƒ`‚Å•œŒ³‚µ‚½‚·‚ׂĂ̗v‘f‚ÉŠÖ˜A‚·‚éƒRƒŒƒNƒVƒ‡ƒ“‚ð
+                    •œŒ³‚µ‚Ü‚·B <literal>lazy="false"</literal> 
+                    ‚Å–¾Ž¦“I‚É’x‰„ƒtƒFƒbƒ`‚𖳌ø‚É‚µ‚È‚¯‚ê‚΁A‚±‚Ì2‰ñ–Ú‚Ìselect‚ÍŽÀÛ‚É
+                    ŠÖ˜A‚ɃAƒNƒZƒX‚µ‚½‚Æ‚«‚Ì‚ÝŽÀs‚³‚ê‚é‚Å‚µ‚傤B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>ƒoƒbƒ`ƒtƒFƒbƒ`</emphasis> - ƒZƒŒƒNƒgƒtƒFƒbƒ`‚Ì‚½‚߂̍œK‰»‚³‚ꂽí—ª
+                     - Hibernate‚̓Gƒ“ƒeƒBƒeƒB‚̃Cƒ“ƒXƒ^ƒ“ƒX‚âƒRƒŒƒNƒVƒ‡ƒ“‚̈êŒQ‚ð1‰ñ‚Ì
+                    <literal>SELECT</literal> ‚Å•œŒ³‚µ‚Ü‚·B‚±‚ê‚ÍŽåƒL[‚âŠO•”ƒL[‚̃ŠƒXƒg‚ðŽw’è‚·‚邱‚Æ‚É
+                    ‚É‚æ‚ès‚¢‚Ü‚·B
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            Hibernate‚ÍŽŸ‚ÉŽ¦‚·í—ª‚Æ‚à‹æ•Ê‚ð‚µ‚Ü‚·B
+        </para>
+
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <emphasis>‘¦ŽžƒtƒFƒbƒ`</emphasis> - Š—LŽÒ‚̃IƒuƒWƒFƒNƒg‚ªƒ[ƒh‚³‚ꂽ‚Æ‚«‚ɁA
+                    ŠÖ˜AAƒRƒŒƒNƒVƒ‡ƒ“‚Í‘¦Žž‚ɃtƒFƒbƒ`‚³‚ê‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>’x‰„ƒRƒŒƒNƒVƒ‡ƒ“ƒtƒFƒbƒ`</emphasis> - ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ªƒRƒŒƒNƒVƒ‡ƒ“‚É
+                    ‘΂µ‚Ä‘€ì‚ðs‚Á‚½‚Æ‚«‚ɃRƒŒƒNƒVƒ‡ƒ“‚ðƒtƒFƒbƒ`‚µ‚Ü‚·B
+                    (‚±‚ê‚̓RƒŒƒNƒVƒ‡ƒ“‚ɑ΂·‚éƒfƒtƒHƒ‹ƒg‚Ì“®ì‚Å‚·)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>"“Á•Ê‚È’x‰„"ƒRƒŒƒNƒVƒ‡ƒ“ƒtƒFƒbƒ`</emphasis> - ƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f
+                    ‚P‚‚P‚‚ª“Æ—§‚µ‚āA•K—v‚È‚Æ‚«‚Ƀf[ƒ^ƒx[ƒX‚©‚çŽæ“¾‚³‚ê‚Ü‚·B
+                    Hibernate‚Í•K—v‚È‚¢‚È‚ç‚΁AƒRƒŒƒNƒVƒ‡ƒ“‘S‘Ì‚ðƒƒ‚ƒŠ‚ɃtƒFƒbƒ`‚·‚邱‚Æ‚Í
+                    ”ð‚¯‚Ü‚·i‚Æ‚Ä‚à‘å‚«‚ȃRƒŒƒNƒVƒ‡ƒ“‚É“K‚µ‚Ä‚¢‚Ü‚·jB
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>ƒvƒƒLƒVƒtƒFƒbƒ`</emphasis> - ’Pˆê’lŠÖ˜A‚́AŽ¯•ÊŽq‚ÌgetterˆÈŠO‚Ì
+                    ƒƒ\ƒbƒh‚ªŠÖ˜AƒIƒuƒWƒFƒNƒg‚ŌĂяo‚³‚ê‚é‚Æ‚«‚ɃtƒFƒbƒ`‚³‚ê‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>"ƒvƒƒLƒV‚È‚µ"ƒtƒFƒbƒ`</emphasis> - ’Pˆê’lŠÖ˜A‚́AƒCƒ“ƒXƒ^ƒ“ƒX•Ï”‚É
+                    ƒAƒNƒZƒX‚³‚ꂽ‚Æ‚«‚ɃtƒFƒbƒ`‚³‚ê‚Ü‚·BƒvƒƒLƒVƒtƒFƒbƒ`‚Æ”äŠr‚·‚é‚ƁA‚±‚Ì•û–@‚Í
+                    ’x‰„‚Ì“x‡‚¢‚ª­‚È‚¢iŠÖ˜A‚ÍŽ¯•ÊŽq‚ɃAƒNƒZƒX‚µ‚½‚¾‚¯‚Å‚àƒtƒFƒbƒ`‚³‚ê‚Ü‚·j
+                    ‚Å‚·‚ªA‚æ‚蓧‰ß“I‚ŁAƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ɃvƒƒLƒV‚ª‘¶Ý‚µ‚È‚¢‚悤‚ÉŒ©‚¹‚Ü‚·B
+                    ‚±‚Ì•û–@‚̓rƒ‹ƒhŽž‚̃oƒCƒgƒR[ƒh‘g‚ݍž‚Ý‚ª•K—v‚É‚È‚èAŽg‚¤ê–Ê‚Í‚Ü‚ê‚Å‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>’x‰„‘®«ƒtƒFƒbƒ`</emphasis> - ‘®«‚â’Pˆê’lŠÖ˜A‚́AƒCƒ“ƒXƒ^ƒ“ƒX•Ï”‚ɃAƒNƒZƒX‚µ‚½
+                    ‚Æ‚«‚ɃtƒFƒbƒ`‚³‚ê‚Ü‚·B‚±‚Ì•û–@‚̓rƒ‹ƒhŽž‚̃oƒCƒgƒR[ƒh‘g‚ݍž‚Ý‚ª•K—v‚É‚È‚èA
+                    Žg‚¤ê–Ê‚Í‚Ü‚ê‚Å‚·B
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            “ñ‚‚̒¼s‚·‚éŠT”O‚ª‚ ‚è‚Ü‚·: <emphasis>‚¢‚Â</emphasis> ŠÖ˜A‚ðƒtƒFƒbƒ`‚·‚é‚©A
+            ‚»‚µ‚āA <emphasis>‚Ç‚¤‚â‚Á‚Ä</emphasis> ƒtƒFƒbƒ`‚·‚é‚©i‚Ç‚ñ‚ÈSQL‚ðŽg‚Á‚ājB
+            ‚±‚ê‚ç‚ð¬“¯‚µ‚È‚¢‚Å‚­‚¾‚³‚¢I <literal>fetch</literal> ‚̓pƒtƒH[ƒ}ƒ“ƒXƒ`ƒ…[ƒjƒ“ƒO‚ÉŽg‚¢‚Ü‚·B
+            <literal>lazy</literal> ‚Í‚ ‚éƒNƒ‰ƒX‚Ì•ª—£‚³‚ꂽƒCƒ“ƒXƒ^ƒ“ƒX‚Ì‚¤‚¿A‚ǂ̃f[ƒ^‚ðí‚É
+            Žg—p‰Â”\‚É‚·‚é‚©‚ÌŽæ‚茈‚ß‚ð’è‹`‚µ‚Ü‚·B
+        </para>
+ 
+        <sect2 id="performance-fetching-lazy">
+            <title>’x‰„ŠÖ˜A‚Ì“­‚«</title>
+            
+            <para>
+                ƒfƒtƒHƒ‹ƒg‚ł́AHibernate3‚̓RƒŒƒNƒVƒ‡ƒ“‚ɑ΂µ‚Ä‚Í’x‰„ƒZƒŒƒNƒgƒtƒFƒbƒ`‚ðŽg‚¢A
+                ’Pˆê’lŠÖ˜A‚É‚Í’x‰„ƒvƒƒLƒVƒtƒFƒbƒ`‚ðŽg‚¢‚Ü‚·B‚±‚ê‚ç‚̃fƒtƒHƒ‹ƒg“®ì‚Í‚Ù‚Ú‚·‚ׂĂÌ
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚Ì‚Ù‚Ú‚·‚ׂĂ̊֘A‚ňӖ¡‚ª‚ ‚è‚Ü‚·B
+            </para>
+            
+            <para>
+                <emphasis>’:</emphasis>
+                <literal>hibernate.default_batch_fetch_size</literal> ‚ðƒZƒbƒg‚µ‚½‚Æ‚«‚́AHibernate‚Í
+                ’x‰„ƒtƒFƒbƒ`‚Ì‚½‚߂̃oƒbƒ`ƒtƒFƒbƒ`Å“K‰»‚ðŽg‚¤‚Å‚µ‚傤
+                i‚±‚̍œK‰»‚Í‚æ‚è×‚©‚¢ƒŒƒxƒ‹‚Å—LŒø‚É‚·‚邱‚Æ‚ào—ˆ‚Ü‚·jB
+            </para>
+            
+            <para>
+                ‚µ‚©‚µA’x‰„ƒtƒFƒbƒ`‚Í’m‚Á‚Ä‚¨‚©‚È‚¯‚ê‚΂Ȃç‚È‚¢ˆê‚‚̖â‘肪‚ ‚è‚Ü‚·B
+                Hibernate‚Ìsession‚ðƒI[ƒvƒ“‚µ‚Ä‚¢‚éƒRƒ“ƒeƒLƒXƒg‚ÌŠO‚©‚ç’x‰„ŠÖ˜A‚ɃAƒNƒZƒX‚·‚é‚ƁA
+                —áŠO‚ª”­¶‚µ‚Ü‚·B—áF
+            </para>
+        
+            <programlisting><![CDATA[s = sessions.openSession();
+Transaction tx = s.beginTransaction();
+            
+User u = (User) s.createQuery("from User u where u.name=:userName")
+    .setString("userName", userName).uniqueResult();
+Map permissions = u.getPermissions();
+
+tx.commit();
+s.close();
+
+Integer accessLevel = (Integer) permissions.get("accounts");  // Error!]]></programlisting>
+
+            <para>
+                <literal>Session</literal> ‚ªƒNƒ[ƒY‚³‚ꂽ‚Æ‚«ApermissionsƒRƒŒƒNƒVƒ‡ƒ“‚Í
+                ‰Šú‰»‚³‚ê‚Ä‚¢‚È‚¢‚½‚߁A‚±‚̃RƒŒƒNƒVƒ‡ƒ“‚ÍŽ©g‚̏ó‘Ô‚ðƒ[ƒh‚Å‚«‚Ü‚¹‚ñB
+                <emphasis>Hibernate‚͐؂藣‚³‚ꂽƒIƒuƒWƒFƒNƒg‚Ì’x‰„‰Šú‰»‚̓Tƒ|[ƒg
+                ‚µ‚Ä‚¢‚Ü‚¹‚ñ</emphasis> BC³•û–@‚Æ‚µ‚āAƒRƒŒƒNƒVƒ‡ƒ“‚©‚ç“ǂݍž‚Ý‚ðs‚¤ƒR[ƒh‚ð
+                ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðƒRƒ~ƒbƒg‚·‚é’¼‘O‚Ɉړ®‚³‚¹‚Ü‚·B
+            </para>
+    
+            <para>
+                ˆê•û‚ŁA <literal>lazy="false"</literal> ‚ðŠÖ˜Aƒ}ƒbƒsƒ“ƒO‚ÉŽw’è‚·‚邱‚ƂŁA
+                ’x‰„ˆ—‚ð‚µ‚È‚¢ƒRƒŒƒNƒVƒ‡ƒ“‚âŠÖ˜A‚ðŽg‚¤‚±‚Æ‚ªo—ˆ‚Ü‚·B 
+                ‚µ‚©‚µ‚È‚ª‚çA’x‰„‰Šú‰»‚Í‚Ù‚Ú‚·‚ׂẴRƒŒƒNƒVƒ‡ƒ“‚âŠÖ˜A‚ÅŽg‚í‚ê‚邱‚Æ‚ð
+                ˆÓ}‚µ‚Ä‚¢‚Ü‚·B‚à‚µ‚ ‚È‚½‚̃IƒuƒWƒFƒNƒgƒ‚ƒfƒ‹‚Ì’†‚É’x‰„ˆ—‚ð‚µ‚È‚¢ŠÖ˜A‚ð
+                ‘½‚­’è‹`‚µ‚Ä‚µ‚Ü‚¤‚ƁAHibernate‚͍ŏI“I‚ɂ̓gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“–ˆ‚É
+                ‚Ù‚ÚŠ®‘S‚ȃf[ƒ^ƒx[ƒX‚ðƒƒ‚ƒŠ‚Ì’†‚ɃtƒFƒbƒ`‚·‚邱‚Æ‚É‚È‚é‚Å‚µ‚傤I
+            </para>
+    
+            <para>
+                ‘¼•û‚ł́A“Á’è‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚É‚¨‚¢‚ăZƒŒƒNƒgƒtƒFƒbƒ`‚Ì‘ã‚í‚è‚É
+                Œ‹‡ƒtƒFƒbƒ`i“–‘R‚±‚ê‚Í’x‰„ˆ—‚Å‚Í‚È‚­‚È‚è‚Ü‚·j‚ð‘I‘ð‚µ‚½‚¢‚±‚Æ‚ª
+                ŽžX‚ ‚è‚Ü‚·B‚±‚ê‚©‚çƒtƒFƒbƒ`í—ª‚ðƒJƒXƒ^ƒ}ƒCƒY‚·‚é•û–@‚ð‚¨Œ©‚¹‚µ‚Ü‚·B
+                Hibernate3‚ł́AƒtƒFƒbƒ`í—ª‚ð‘I‘ð‚·‚éŽd‘g‚Ý‚Í’Pˆê’lŠÖ˜A‚ƃRƒŒƒNƒVƒ‡ƒ“‚Å
+                •Ï‚í‚è‚Í‚ ‚è‚Ü‚¹‚ñB
+            </para>
+        
+        </sect2>
+        
+        <sect2 id="performance-fetching-custom" revision="4">
+            <title>ƒtƒFƒbƒ`í—ª‚̃`ƒ…[ƒjƒ“ƒO</title>
+            
+            <para>
+                ƒZƒŒƒNƒgƒtƒFƒbƒ`iƒfƒtƒHƒ‹ƒgj‚ÍN+1ƒZƒŒƒNƒg–â‘è‚Æ‚¢‚¤‘å‚«‚ÈŽã“_‚ª‚ ‚邽‚߁A
+                ƒ}ƒbƒsƒ“ƒO’è‹`‚ÅŒ‹‡ƒtƒFƒbƒ`‚ð—LŒø‚É‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            </para>
+            
+            <programlisting><![CDATA[<set name="permissions" 
+            fetch="join">
+    <key column="userId"/>
+    <one-to-many class="Permission"/>
+</set]]></programlisting>
+
+           <programlisting><![CDATA[<many-to-one name="mother" class="Cat" fetch="join"/>]]></programlisting>
+
+            <para>
+                ƒ}ƒbƒsƒ“ƒO’è‹`‚Å’è‹`‚µ‚½ <literal>ƒtƒFƒbƒ`</literal> í—ª‚ÍŽŸ‚Ì‚à‚̂ɉe‹¿‚µ‚Ü‚·B
+            </para>
+            
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <literal>get()</literal> ‚â <literal>load()</literal> ‚É‚æ‚é•œŒ³
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+
+                    ŠÖ˜A‚ɃiƒrƒQ[ƒg‚µ‚½‚Æ‚«‚É”­¶‚·‚éˆÃ–Ù“I‚È•œŒ³
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>Criteria</literal> ƒNƒGƒŠ
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ƒTƒuƒZƒŒƒNƒg</literal> ƒtƒFƒbƒ`‚ðŽg‚¤HQLƒNƒGƒŠ
+                </para>
+            </listitem>
+        </itemizedlist>
+
+            <para>
+                ‚½‚Æ‚¦‚Ç‚ñ‚ȃtƒFƒbƒ`í—ª‚ðŽg‚Á‚½‚Æ‚µ‚Ä‚àA’x‰„‚Å‚Í‚È‚¢ƒOƒ‰ƒt‚̓ƒ‚ƒŠ‚ɓǂݍž‚Ü‚ê‚邱‚Æ‚ª
+                •ÛØ‚³‚ê‚Ü‚·B‚‚܂èA“Á’è‚ÌHQLƒNƒGƒŠ‚ðŽÀs‚·‚邽‚ß‚É‚¢‚­‚‚©‚ÌSELECT•¶‚ª‘¦ŽžŽÀs‚³‚ê‚é
+                ‚±‚Æ‚ª‚ ‚é‚Ì‚Å’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <para>
+                ’ʏí‚́Aƒ}ƒbƒsƒ“ƒO’è‹`‚ŃtƒFƒbƒ`‚̃JƒXƒ^ƒ}ƒCƒY‚͍s‚¢‚Ü‚¹‚ñB
+                ‘ã‚í‚è‚ɁAƒfƒtƒHƒ‹ƒg‚Ì“®ì‚Ì‚Ü‚Ü‚É‚µ‚Ä‚¨‚¢‚āAHQL‚Å <literal>left join fetch</literal> ‚ð
+                Žw’è‚·‚邱‚Æ‚Å“Á’è‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Å“®ì‚ðƒI[ƒo[ƒ‰ƒCƒh‚µ‚Ü‚·B
+                ‚±‚ê‚ÍHibernate‚ɏ‰‰ñ‚̃ZƒŒƒNƒg‚ÅŠO•”Œ‹‡‚ðŽg‚Á‚ÄŠÖ˜A‚ðæ‚ɃtƒFƒbƒ`‚·‚é‚悤‚ÉŽw’肵‚Ä‚¢‚Ü‚·B
+                <literal>Criteria</literal> ƒNƒGƒŠ‚ÌAPI‚ł́A
+                <literal>setFetchMode(FetchMode.JOIN)</literal> ‚ðŽg‚¤‚±‚Æ‚ªo—ˆ‚Ü‚·B
+            </para>
+            
+            <para>
+                ‚à‚µ <literal>get()</literal> ‚â <literal>load()</literal> ‚ÅŽg‚í‚ê‚é
+                ƒtƒFƒbƒ`í—ª‚ð•Ï‚¦‚½‚¢‚ÆŠ´‚¶‚½‚Æ‚«‚ɂ́A’Pƒ‚É
+                <literal>Criteria</literal> ƒNƒGƒŠ‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢B—áF
+            </para>
+            
+            <programlisting><![CDATA[User user = (User) session.createCriteria(User.class)
+                .setFetchMode("permissions", FetchMode.JOIN)
+                .add( Restrictions.idEq(userId) )
+                .uniqueResult();]]></programlisting>
+                
+            <para>
+                i‚±‚ê‚Í‚¢‚­‚‚©‚ÌORMƒ\ƒŠƒ…[ƒVƒ‡ƒ“‚ª"fetch plan"‚ƌĂñ‚Å‚¢‚é‚à‚Ì‚Æ“¯‚¶‚Å‚·Bj
+            </para>
+
+            <para>
+                N+1ƒZƒŒƒNƒg–â‘è‚ð”ð‚¯‚é‚½‚ß‚Ì‚Ü‚Á‚½‚­ˆá‚¤•û–@‚́A‘æ2ƒŒƒxƒ‹ƒLƒƒƒbƒVƒ…‚ðŽg‚¤‚±‚Æ‚Å‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-proxies" revision="2">
+            <title>’Pˆê’[ŠÖ˜AƒvƒƒLƒV</title>
+
+            <para>
+                ƒRƒŒƒNƒVƒ‡ƒ“‚Ì’x‰„ƒtƒFƒbƒ`‚́AHibernateŽ©g‚ÌŽÀ‘•‚É‚æ‚é‰i‘±ƒRƒŒƒNƒVƒ‡ƒ“‚ðŽg‚Á‚Ä
+                ŽÀŒ»‚µ‚Ä‚¢‚Ü‚·B‚µ‚©‚µA’Pˆê’[ŠÖ˜A‚É‚¨‚¯‚é’x‰„ˆ—‚ł́Aˆá‚¤Žd‘g‚Ý‚ª
+                •K—v‚Å‚·B‘Ώۂ̊֘AƒGƒ“ƒeƒBƒeƒB‚̓vƒƒLƒV‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñBHibernate‚Í
+                i‚·‚΂炵‚¢CGLIBƒ‰ƒCƒuƒ‰ƒŠ‚É‚æ‚éjŽÀsŽž‚̃oƒCƒgƒR[ƒhŠg’£‚ð
+                Žg‚Á‚ĉi‘±ƒIƒuƒWƒFƒNƒg‚Ì’x‰„‰Šú‰»ƒvƒƒLƒV‚ðŽÀŒ»‚µ‚Ä‚¢‚Ü‚·B
+            </para>
+
+            <para>
+                ƒfƒtƒHƒ‹ƒg‚ł́AHibernate3‚́iŠJŽnŽž‚Ɂj‚·‚ׂẲi‘±ƒNƒ‰ƒX‚̃vƒƒLƒV‚𐶐¬‚µA
+                ‚»‚ê‚ç‚ðŽg‚Á‚āA <literal>many-to-one</literal> ‚â <literal>one-to-one</literal> ŠÖ˜A‚Ì
+                ’x‰„ƒtƒFƒbƒ`‚ð‰Â”\‚É‚µ‚Ä‚¢‚Ü‚·B
+            </para>
+
+            <para>
+                ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚Å <literal>proxy</literal> ‘®«‚É‚æ‚Á‚āAƒNƒ‰ƒX‚̃vƒƒLƒVƒCƒ“ƒ^[ƒtƒFƒCƒX‚Æ‚µ‚Ä
+                Žg‚¤ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ðéŒ¾‚Å‚«‚Ü‚·BƒfƒtƒHƒ‹ƒg‚ł́AHibernate‚Í‚»‚̃Nƒ‰ƒX‚̃TƒuƒNƒ‰ƒX‚ðŽg‚¢‚Ü‚·B
+                <emphasis>ƒvƒƒLƒVƒNƒ‰ƒX‚͏­‚È‚­‚Æ‚àƒpƒbƒP[ƒW‰ÂŽ‹‚ŃfƒtƒHƒ‹ƒgƒRƒ“ƒXƒgƒ‰ƒNƒ^‚ðŽÀ‘•‚µ‚È‚¯‚ê‚Î
+                ‚È‚ç‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B‚·‚ׂẲi‘±ƒNƒ‰ƒX‚É‚±‚̃Rƒ“ƒXƒgƒ‰ƒNƒ^‚𐄏§‚µ‚Ü‚·I</emphasis>
+            </para>
+
+            <para>
+                ƒ|ƒŠƒ‚[ƒtƒBƒYƒ€‚̃Nƒ‰ƒX‚ɑ΂µ‚Ä‚±‚Ì•û–@‚ð“K—p‚·‚é‚Æ‚«‚É‚¢‚­‚‚©l—¶‚·‚邱‚Æ‚ª‚ ‚è‚Ü‚·B
+                —áF
+            </para>
+
+            <programlisting><![CDATA[<class name="Cat" proxy="Cat">
+    ......
+    <subclass name="DomesticCat">
+        .....
+    </subclass>
+</class>]]></programlisting>
+
+            <para>
+                ‘æˆê‚ɁA <literal>Cat</literal> ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚Í <literal>DomesticCat</literal> 
+                ‚ɃLƒƒƒXƒg‚Å‚«‚Ü‚¹‚ñB‚½‚Æ‚¦Šî‚Æ‚È‚éƒCƒ“ƒXƒ^ƒ“ƒX‚ª <literal>DomesticCat</literal> 
+                ‚Å‚ ‚Á‚½‚Æ‚µ‚Ä‚à‚Å‚·B
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id);  // instantiate a proxy (does not hit the db)
+if ( cat.isDomesticCat() ) {                  // hit the db to initialize the proxy
+    DomesticCat dc = (DomesticCat) cat;       // Error!
+    ....
+}]]></programlisting>
+
+            <para>
+                ‘æ“ñ‚ɁAƒvƒƒLƒV‚Ì <literal>==</literal> ‚͐¬—§‚µ‚È‚¢‚±‚Æ‚ª‚ ‚è‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id);            // instantiate a Cat proxy
+DomesticCat dc = 
+        (DomesticCat) session.load(DomesticCat.class, id);  // acquire new DomesticCat proxy!
+System.out.println(cat==dc);                            // false]]></programlisting>
+
+            <para>
+                ‚µ‚©‚µA‚±‚ê‚ÍŒ©‚©‚¯‚قLj«‚¢ó‹µ‚Æ‚¢‚¤‚킯‚Å‚Í‚ ‚è‚Ü‚¹‚ñB‚½‚Æ‚¦ˆÙ‚È‚Á‚½ƒvƒƒLƒVƒIƒuƒWƒFƒNƒg‚Ö‚Ì
+                “ñ‚‚̎QÆ‚ª‚ ‚Á‚½‚Æ‚µ‚Ä‚àAŠî‚Æ‚È‚éƒCƒ“ƒXƒ^ƒ“ƒX‚Í“¯‚¶ƒIƒuƒWƒFƒNƒg‚Å‚·B
+            </para>
+
+            <programlisting><![CDATA[cat.setWeight(11.0);  // hit the db to initialize the proxy
+System.out.println( dc.getWeight() );  // 11.0]]></programlisting>
+
+            <para>
+                ‘æŽO‚ɁA <literal>final</literal> ƒNƒ‰ƒX‚â <literal>final</literal> ƒƒ\ƒbƒh‚ðŽ‚ÂƒNƒ‰ƒX‚É
+                CGLIBƒvƒƒLƒV‚ðŽg‚¦‚Ü‚¹‚ñB
+            </para>
+
+            <para>
+                ÅŒã‚ɁA‚à‚µ‰i‘±ƒIƒuƒWƒFƒNƒg‚̃Cƒ“ƒXƒ^ƒ“ƒX‰»Žž(—Ⴆ‚΁A‰Šú‰»ˆ—‚âƒfƒtƒHƒ‹ƒgƒRƒ“ƒXƒgƒ‰ƒNƒ^‚Ì’†‚Å)
+                ‚É‚È‚ñ‚ç‚©‚̃Šƒ\[ƒX‚ª•K—v‚Æ‚È‚é‚È‚çA‚»‚̃Šƒ\[ƒX‚à‚Ü‚½ƒvƒƒLƒV‚ð’Ê‚µ‚Ď擾‚³‚ê‚Ü‚·B
+                ŽÀÛ‚ɂ́AƒvƒƒLƒVƒNƒ‰ƒX‚͉i‘±ƒNƒ‰ƒX‚̃TƒuƒNƒ‰ƒX‚Å‚·B 
+            </para>
+
+            <para>
+                ‚±‚ê‚ç‚Ì–â‘è‚ÍJava‚Ì’PˆêŒp³ƒ‚ƒfƒ‹‚ÌŒ´—ã‚̐§ŒÀ‚Ì‚½‚ß‚Å‚·B‚à‚µ‚±‚ê‚ç‚Ì–â‘è‚ð”ð‚¯‚½‚¢‚Ì‚È‚çA
+                ƒrƒWƒlƒXƒƒ\ƒbƒh‚ðéŒ¾‚µ‚½ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ð‚»‚ê‚¼‚ê‰i‘±ƒNƒ‰ƒX‚ÅŽÀ‘•‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚Å‚±‚ê‚ç‚̃Cƒ“ƒ^[ƒtƒFƒCƒX‚ðŽw’è‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B—áF
+            </para>
+
+            <programlisting><![CDATA[<class name="CatImpl" proxy="Cat">
+    ......
+    <subclass name="DomesticCatImpl" proxy="DomesticCat">
+        .....
+    </subclass>
+</class>]]></programlisting>
+
+            <para>
+                <literal>CatImpl</literal> ‚Í <literal>Cat</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽÀ‘•‚·‚é‚̂ɑ΂µA
+                <literal>DomesticCatImpl</literal> ‚Í <literal>DomesticCat</literal> ‚ðŽÀ‘•‚µ‚Ü‚·B
+                ‚·‚é‚ƁA <literal>load()</literal> ‚â <literal>iterate()</literal> ‚́A
+                <literal>Cat</literal> ‚â <literal>DomesticCat</literal> ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚̃vƒƒLƒV‚ð
+                •Ô‚µ‚Ü‚·Bi <literal>list()</literal> ‚͒ʏí‚̓vƒƒLƒV‚ð•Ô‚³‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢Bj
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(CatImpl.class, catid);
+Iterator iter = session.iterate("from CatImpl as cat where cat.name='fritz'");
+Cat fritz = (Cat) iter.next();]]></programlisting>
+
+            <para>
+                ŠÖ˜A‚à’x‰„‰Šú‰»‚³‚ê‚Ü‚·B‚±‚ê‚̓vƒƒpƒeƒB‚ð <literal>Cat</literal> Œ^‚Ő錾‚µ‚È‚¯‚ê‚Î
+                ‚È‚ç‚È‚¢‚±‚Æ‚ðˆÓ–¡‚µ‚Ü‚·B <literal>CatImpl</literal> ‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+            </para>
+
+            <para>
+                ƒvƒƒLƒV‚̏‰Šú‰»‚ð <emphasis>•K—v‚Æ‚µ‚È‚¢</emphasis> ‘€ì‚à‘¶Ý‚µ‚Ü‚·B
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>equals()</literal> i‰i‘±ƒNƒ‰ƒX‚ª <literal>equals()</literal> ‚ð
+                        ƒI[ƒo[ƒ‰ƒCƒh‚µ‚È‚¢‚Æ‚«j
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>hashCode()</literal> i‰i‘±ƒNƒ‰ƒX‚ª <literal>hashCode()</literal> ‚ð
+                        ƒI[ƒo[ƒ‰ƒCƒh‚µ‚È‚¢‚Æ‚«j
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Ž¯•ÊŽq‚Ìgetterƒƒ\ƒbƒh
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Hibernate‚Í <literal>equals()</literal> ‚â <literal>hashCode()</literal> ‚ðƒI[ƒo[ƒ‰ƒCƒh‚µ‚½
+                ‰i‘±ƒNƒ‰ƒX‚ðŒŸo‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                ƒfƒtƒHƒ‹ƒg‚Ì <literal>lazy="proxy"</literal> ‚Ì‘ã‚í‚è‚ɁA <literal>lazy="no-proxy"</literal> ‚ð
+                ‘I‚ñ‚¾‚±‚ƂŁAŒ^•ÏŠ·‚ÉŠÖ˜A‚·‚é–â‘è‚ð‰ñ”ð‚·‚é‚±‚Æ‚ªo—ˆ‚Ü‚·B
+                ‚µ‚©‚µAƒrƒ‹ƒhŽž‚̃oƒCƒgƒR[ƒh‘g‚ݍž‚Ý‚ª•K—v‚É‚È‚èA‚ǂ̂悤‚È‘€ì‚Å‚ ‚Á‚Ä‚àA
+                ‚½‚¾‚¿‚ɃvƒƒLƒV‚̏‰Šú‰»‚ðs‚¤‚±‚Æ‚É‚È‚é‚Å‚µ‚傤B
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-initialization" revision="1">
+            <title>ƒRƒŒƒNƒVƒ‡ƒ“‚ƃvƒƒLƒV‚̏‰Šú‰»</title>
+
+            <para>
+                <literal>LazyInitializationException</literal> ‚́A <literal>Session</literal> ‚̃XƒR[ƒvŠO‚©‚ç
+                ‰Šú‰»‚µ‚Ä‚¢‚È‚¢ƒRƒŒƒNƒVƒ‡ƒ“‚âƒvƒƒLƒV‚ɃAƒNƒZƒX‚³‚ꂽ‚Æ‚«‚ɁAHibernate‚É‚æ‚Á‚ăXƒ[‚³‚ê‚Ü‚·B
+                ‚·‚È‚í‚¿AƒRƒŒƒNƒVƒ‡ƒ“‚âƒvƒƒLƒV‚Ö‚ÌŽQÆ‚ðŽ‚ÂƒGƒ“ƒeƒBƒeƒB‚ª•ª—£‚³‚ꂽó‘Ô‚ÌŽž‚Å‚·B
+            </para>
+
+            <para>
+                <literal>Session</literal> ‚ðƒNƒ[ƒY‚·‚é‘O‚ɃvƒƒLƒV‚âƒRƒŒƒNƒVƒ‡ƒ“‚̏‰Šú‰»‚ðŠmŽÀ‚É
+                s‚¢‚½‚¢‚Æ‚«‚ª‚ ‚è‚Ü‚·B‚à‚¿‚ë‚ñA <literal>cat.getSex()</literal> 
+                ‚â <literal>cat.getKittens().size()</literal> ‚È‚Ç‚ðí‚ɌĂяo‚·‚±‚Ƃŏ‰Šú‰»‚ð‹­§‚·‚邱‚Æ‚Í‚Å‚«‚Ü‚·B
+                ‚µ‚©‚µ‚±‚ê‚̓R[ƒh‚ð“ǂސl‚ð¬—‚³‚¹A”Ä—p“I‚ȃR[ƒh‚Æ‚¢‚¤“_‚©‚ç‚à•s•Ö‚Å‚·B
+            </para>
+
+            <para>
+                staticƒƒ\ƒbƒh‚Ì <literal>Hibernate.initialize()</literal> ‚â <literal>Hibernate.isInitialized()</literal> 
+                ‚Í’x‰„‰Šú‰»‚̃RƒŒƒNƒVƒ‡ƒ“‚âƒvƒƒLƒV‚ðˆµ‚¤‚Æ‚«‚É•Ö—˜‚È•û–@‚ðƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É’ñ‹Ÿ‚µ‚Ü‚·B
+                <literal>Hibernate.initialize(cat)</literal> ‚́A <literal>Session</literal> ‚ªƒI[ƒvƒ“‚µ‚Ä‚¢‚éŒÀ‚è‚Í
+                <literal>cat</literal> ƒvƒƒLƒV‚ð‹­§“I‚ɏ‰Šú‰»‚µ‚Ü‚·B
+                <literal>Hibernate.initialize( cat.getKittens() )</literal> ‚ÍkittensƒRƒŒƒNƒVƒ‡ƒ“‚ɑ΂µ‚Ä“¯—l‚Ì
+                Œø‰Ê‚ª‚ ‚è‚Ü‚·B
+            </para>
+
+            <para>
+                •Ê‚Ì‘I‘ðŽˆ‚Æ‚µ‚āA•K—v‚È‚·‚ׂẴRƒŒƒNƒVƒ‡ƒ“‚âƒvƒƒLƒV‚ªƒ[ƒh‚³‚ê‚é‚Ü‚Å
+                <literal>Session</literal> ‚ðƒI[ƒvƒ“‚É‚µ‚Ä‚¨‚­•û–@‚ª‚ ‚è‚Ü‚·B‚¢‚­‚‚©‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚Ì
+                ƒA[ƒLƒeƒNƒ`ƒƒ‚ł́A“Á‚ÉHibernate‚É‚æ‚éƒf[ƒ^ƒAƒNƒZƒX‚ðs‚¤ƒR[ƒh‚ƁA‚»‚ê‚ðŽg‚¤
+                ƒR[ƒh‚ªˆÙ‚È‚éƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̃ŒƒCƒ„[‚âA•¨—“I‚ɈقȂéƒvƒƒZƒbƒT‚Ì‚Æ‚«‚ɂ́A
+                ƒRƒŒƒNƒVƒ‡ƒ“‚ª‰Šú‰»‚³‚ê‚é‚Æ‚«‚É <literal>Session</literal> ‚ªƒI[ƒvƒ“‚µ‚Ä‚¢‚邱‚Æ‚ð
+                •ÛØ‚·‚é–â‘肪‚ ‚è‚Ü‚·B‚±‚Ì–â‘è‚ɑ΂µ‚Ä‚Í2‚‚̊î–{“I‚È•û–@‚ª‚ ‚è‚Ü‚·B
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+
+                        Webƒx[ƒX‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚ł́A
+                        ƒrƒ…[‚̃Œƒ“ƒ_ƒŠƒ“ƒO‚ªŠ®—¹‚µAƒŠƒNƒGƒXƒg‚ªI‚í‚éˆê”ԍŌã‚Å <literal>Session</literal> 
+                        ‚ðƒNƒ[ƒY‚·‚邽‚߂ɁAƒT[ƒuƒŒƒbƒgƒtƒBƒ‹ƒ^‚ðŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·i <emphasis>Open Session in View</emphasis> 
+                        ƒpƒ^[ƒ“‚Å‚·jB‚à‚¿‚ë‚ñAƒAƒvƒŠƒP[ƒVƒ‡ƒ“Šî”Õ‚Ì—áŠOˆ—‚̐³Šm«‚ª”ñí‚ɏd—v‚É‚È‚è‚Ü‚·B
+                        ƒrƒ…[‚̃Œƒ“ƒ_ƒŠƒ“ƒO’†‚É—áŠO‚ª”­¶‚µ‚½‚Æ‚«‚Å‚³‚¦Aƒ†[ƒU‚ɏˆ—‚ª–ß‚é‘O‚É
+                        <literal>Session</literal> ‚̃Nƒ[ƒY‚ƃgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̏I—¹‚ðs‚¤
+                        ‚±‚Æ‚ª•s‰ÂŒ‡‚É‚È‚è‚Ü‚·B
+                        Hibernate‚ÌWiki‚ɍڂÁ‚Ä‚¢‚é"Open Session in View"ƒpƒ^[ƒ“‚Ì—á‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        ƒrƒWƒlƒX‘w‚ª•ª—£‚µ‚Ä‚¢‚éƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ł́AƒrƒWƒlƒXƒƒWƒbƒN‚Í
+                        Web‘w‚Å•K—v‚É‚È‚é‚·‚ׂẴRƒŒƒNƒVƒ‡ƒ“‚ðŽ–‘O‚É"€”õ"‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+                        ‚±‚ê‚Í“Á’è‚̃†[ƒXƒP[ƒX‚Å•K—v‚Æ‚È‚éƒvƒŒƒ[ƒ“ƒe[ƒVƒ‡ƒ“/Web‘w‚ɑ΂µA
+                        ƒrƒWƒlƒX‘w‚ª‚·‚ׂẴf[ƒ^‚ðƒ[ƒh‚µA‚·‚ׂẴf[ƒ^‚ð‰Šú‰»‚µ‚Ä•Ô‚·‚ׂ«‚Æ
+                        ‚¢‚¤‚±‚Æ‚ðˆÓ–¡‚µ‚Ä‚¢‚Ü‚·B’ʏí‚́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ÍWeb‘w‚Å•K—v‚ȃRƒŒƒNƒVƒ‡ƒ“
+                        ‚»‚ꂼ‚ê‚ɑ΂µ‚Ä <literal>Hibernate.initialize()</literal> ‚ðŒÄ‚яo‚·‚©
+                        i‚±‚̌Ăяo‚µ‚̓ZƒbƒVƒ‡ƒ“‚ðƒNƒ[ƒY‚·‚é‘O‚ɍs‚¤•K—v‚ª‚ ‚è‚Ü‚·jA
+                        HibernateƒNƒGƒŠ‚Ì <literal>FETCH</literal> ß‚â <literal>Criteria</literal> 
+                        ‚Ì <literal>FetchMode.JOIN</literal> ‚ðŽg‚Á‚ăRƒŒƒNƒVƒ‡ƒ“‚ðæ‚É•œŒ³‚µ‚Ü‚·B
+                        •’Ê‚Í <emphasis>Session Facade</emphasis> ƒpƒ^[ƒ“‚Ì‘ã‚í‚è‚É
+                        <emphasis>Command</emphasis> ƒpƒ^[ƒ“‚ðÌ—p‚·‚é‚Ù‚¤‚ª‚æ‚èŠÈ’P‚Å‚·B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        ‰Šú‰»‚³‚ê‚Ä‚¢‚È‚¢ƒRƒŒƒNƒVƒ‡ƒ“i‚à‚µ‚­‚Í‘¼‚̃vƒƒLƒVj‚ɃAƒNƒZƒX‚·‚é‘O‚ɁA
+                        <literal>merge()</literal> ‚â <literal>lock()</literal> ‚ðŽg‚Á‚ĐV‚µ‚¢
+                        <literal>Session</literal> ‚ɈȑO‚Ƀ[ƒh‚³‚ꂽƒIƒuƒWƒFƒNƒg‚ð’ljÁ‚·‚邱‚Æ‚ào—ˆ‚Ü‚·B
+                        ƒAƒhƒzƒbƒN‚ȃgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̃Zƒ}ƒ“ƒeƒBƒNƒX‚𓱓ü‚µ‚½‚̂ŁAHibernate‚Í
+                        ‚±‚ê‚ðŽ©“®“I‚ɍs‚킸A <emphasis>s‚¤‚ׂ«‚Å‚à‚ ‚è‚Ü‚¹‚ñ</emphasis> I
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                ‘å‚«‚ȃRƒŒƒNƒVƒ‡ƒ“‚ð‰Šú‰»‚µ‚½‚­‚Í‚È‚¢‚ªAƒRƒŒƒNƒVƒ‡ƒ“‚ɂ‚¢‚Ä‚Ì‚È‚ñ‚ç‚©‚̏î•ñiƒTƒCƒY‚̂悤‚ȁj
+                ‚âƒf[ƒ^‚̃TƒuƒZƒbƒg‚ð•K—v‚Æ‚·‚邱‚Æ‚ª‚ ‚è‚Ü‚·B
+            </para>
+
+            <para>
+                ƒRƒŒƒNƒVƒ‡ƒ“ƒtƒBƒ‹ƒ^‚ðŽg‚¤‚±‚ƂŁA‰Šú‰»‚¹‚¸‚ɃRƒŒƒNƒVƒ‡ƒ“‚̃TƒCƒY‚ðŽæ“¾‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()]]></programlisting>
+
+            <para>
+                <literal>createFilter()</literal> ƒƒ\ƒbƒh‚́AƒRƒŒƒNƒVƒ‡ƒ“‘S‘Ì‚ð‰Šú‰»‚·‚é•K—v‚È‚µ‚ɁAƒRƒŒƒNƒVƒ‡ƒ“‚Ì
+                ƒTƒuƒZƒbƒg‚𕜌³‚·‚邽‚ß‚ÉŒø‰Ê“I‚ÉŽg‚¦‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-batch">
+            <title>ƒoƒbƒ`ƒtƒFƒbƒ`‚ÌŽg—p</title>
+
+            <para>
+                Hibernate‚̓oƒbƒ`ƒtƒFƒbƒ`‚ðŒø—¦“I‚ÉŽg—p‚Å‚«‚Ü‚·Bˆê‚‚̃vƒƒLƒVi‚à‚µ‚­‚̓RƒŒƒNƒVƒ‡ƒ“j‚ªƒAƒNƒZƒX
+                ‚³‚ê‚é‚ƁAHibernate‚Í‚¢‚­‚‚©‚̏‰Šú‰»‚µ‚Ä‚¢‚È‚¢ƒvƒƒLƒV‚ðƒ[ƒh‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·Bƒoƒbƒ`ƒtƒFƒbƒ`‚Í
+                ’x‰„ƒZƒŒƒNƒgƒtƒFƒbƒ`í—ª‚ɑ΂·‚éÅ“K‰»‚Å‚·Bƒoƒbƒ`ƒtƒFƒbƒ`‚Ì’²®‚É‚Í‚Q‚‚̕û–@‚ª‚ ‚è‚Ü‚·B
+                ƒNƒ‰ƒXƒŒƒxƒ‹‚ƃRƒŒƒNƒVƒ‡ƒ“ƒŒƒxƒ‹‚Å‚·B
+            </para>
+
+            <para>
+                ƒNƒ‰ƒXA—v‘f‚̃oƒbƒ`ƒtƒFƒbƒ`‚Í—‰ð‚ªŠÈ’P‚Å‚·BŽÀsŽž‚ÌŽŸ‚̏ê–Ê‚ð‘z‘œ‚µ‚Ä‚­‚¾‚³‚¢B
+                <literal>Session</literal> ‚Ƀ[ƒh‚³‚ꂽ25ŒÂ‚Ì <literal>Cat</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚ª‘¶Ý‚µA
+                ‚»‚ꂼ‚ê‚Ì <literal>Cat</literal> ‚Í <literal>owner</literal> ‚Å‚ ‚é <literal>Person</literal> ‚Ö‚ÌŠÖ˜A‚ðŽ‚¿‚Ü‚·B
+                <literal>Person</literal> ƒNƒ‰ƒX‚Í <literal>lazy="true"</literal> ‚̃vƒƒLƒV‚Ń}ƒbƒsƒ“ƒO‚³‚ê‚Ä‚¢‚Ü‚·B
+                ‚à‚µ¡‚·‚ׂĂÌCat‚ɑ΂µ‚ÄŒJ‚è•Ô‚µ <literal>getOwner()</literal> ‚ðŒÄ‚яo‚·‚ƁAHibernate‚Í
+                ƒfƒtƒHƒ‹ƒg‚Å‚Í25‰ñ‚Ì <literal>SELECT</literal> ‚ðŽÀs‚µAownerƒvƒƒLƒV‚Ì•œŒ³‚ð‚µ‚Ü‚·B
+                ‚±‚̐U‚é•‘‚¢‚ð <literal>Person</literal> ‚̃}ƒbƒsƒ“ƒO‚Ì <literal>batch-size</literal> 
+                ‚ÌŽw’è‚Å’²®‚Å‚«‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[<class name="Person" batch-size="10">...</class>]]></programlisting>
+
+            <para>
+                Hibernate‚̓NƒGƒŠ‚ð‚R‰ñ‚¾‚¯‚ðŽÀs‚·‚é‚悤‚É‚È‚è‚Ü‚·Bƒpƒ^[ƒ“‚Í10, 10, 5‚Å‚·B
+            </para>
+
+            <para>
+                ƒRƒŒƒNƒVƒ‡ƒ“‚̃oƒbƒ`ƒtƒFƒbƒ`‚à—LŒø‚É‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B—á‚Æ‚µ‚āA‚»‚ꂼ‚ê‚Ì
+                <literal>Person</literal> ‚ª <literal>Cat</literal> ‚Ì’x‰„ƒRƒŒƒNƒVƒ‡ƒ“‚ðŽ‚Á‚Ä‚¨‚èA
+                10ŒÂ‚ÌPerson‚ª <literal>Sesssion</literal> ‚Ƀ[ƒh‚³‚ꂽ‚Æ‚·‚é‚ƁA‚·‚ׂĂÌPerson‚É
+                ‘΂µ‚ÄŒJ‚è•Ô‚µ <literal>getCats()</literal> ‚ðŒÄ‚яo‚·‚±‚ƂŁAŒv10‰ñ‚Ì <literal>SELECT</literal> 
+                ‚ª”­¶‚µ‚Ü‚·B‚à‚µ <literal>Person</literal> ‚̃}ƒbƒsƒ“ƒO‚Å <literal>cats</literal> 
+                ƒRƒŒƒNƒVƒ‡ƒ“‚̃oƒbƒ`ƒtƒFƒbƒ`‚ð—LŒø‚É‚·‚ê‚΁AHibernate‚̓RƒŒƒNƒVƒ‡ƒ“‚ÌŽ–‘OƒtƒFƒbƒ`‚ªo—ˆ‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[<class name="Person">
+    <set name="cats" batch-size="3">
+        ...
+    </set>
+</class>]]></programlisting>
+
+            <para>
+                <literal>batch-size</literal> ‚ª3‚Ȃ̂ŁAHibernate‚Í4‰ñ‚Ì <literal>SELECT</literal> 
+                ‚Å3ŒÂA3ŒÂA3ŒÂA1ŒÂ‚ðƒ[ƒh‚µ‚Ü‚·BŒJ‚è•Ô‚·‚ƁA‘®«‚Ì’l‚Í“Á’è‚Ì <literal>Session</literal> 
+                ‚Ì’†‚̏‰Šú‰»‚³‚ê‚Ä‚¢‚È‚¢ƒRƒŒƒNƒVƒ‡ƒ“‚ÌŠú‘Ґ”‚Ɉˑ¶‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                ƒRƒŒƒNƒVƒ‡ƒ“‚̃oƒbƒ`ƒtƒFƒbƒ`‚̓AƒCƒeƒ€‚̃lƒXƒg‚µ‚½ƒcƒŠ[A ‚·‚È‚í‚¿A‘ã•\“I‚È•”•i•\‚̃pƒ^[ƒ“‚ª
+                ‚ ‚éê‡‚É“Á‚É—L—p‚Å‚·Bi‚µ‚©‚µA“ǂݍž‚Ý‚ª‘½‚¢ƒcƒŠ[‚Å‚Í <emphasis>ƒlƒXƒg‚µ‚½set</emphasis> 
+                ‚â <emphasis>‹ï‘̉»‚µ‚½ƒpƒX</emphasis> ‚ª‚æ‚è‚æ‚¢‘I‘ð‚É‚È‚è‚Ü‚·Bj
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-subselect">
+            <title>ƒTƒuƒZƒŒƒNƒgƒtƒFƒbƒ`‚ÌŽg—p</title>
+
+            <para>
+                ˆê‚‚̒x‰„ƒRƒŒƒNƒVƒ‡ƒ“‚â’Pˆê’lƒvƒƒLƒV‚ªƒtƒFƒbƒ`‚³‚ê‚È‚¯‚ê‚΂¢‚¯‚È‚¢‚Æ‚«AHibernate‚Í
+                ‚»‚ê‚ç‚·‚×‚Ä‚ðƒ[ƒh‚µAƒTƒuƒZƒŒƒNƒg‚̃IƒŠƒWƒiƒ‹ƒNƒGƒŠ‚ªÄ“xŽÀs‚³‚ê‚Ü‚·B‚±‚ê‚Í
+                ƒoƒbƒ`ƒtƒFƒbƒ`‚Æ“¯‚¶•û–@‚Å“®‚«A­‚µ‚¸‚‚̃[ƒh‚͍s‚¢‚Ü‚¹‚ñB
+            </para>
+            
+            <!-- TODO: Write more about this -->
+            <!-- ‘‚­‘‚¯‚æ -->
+        </sect2>
+        
+        <sect2 id="performance-fetching-lazyproperties">
+            <title>’x‰„ƒvƒƒpƒeƒBƒtƒFƒbƒ`‚ÌŽg—p</title>
+
+            <para>
+                Hibernate3‚̓vƒƒpƒeƒB‚²‚Æ‚Ì’x‰„ƒtƒFƒbƒ`‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·B‚±‚̍œK‰»Žè–@‚Í
+                <emphasis>ƒOƒ‹[ƒv‚̃tƒFƒbƒ`</emphasis> ‚Æ‚µ‚Ä‚à’m‚ç‚ê‚Ä‚¢‚Ü‚·B‚±‚ê‚Í‚Ù‚Æ‚ñ‚Ç
+                —v–]‚©‚ço‚½‹@”\‚Å‚ ‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢BŽÀÛ‚É‚Í—ñ“ǂݍž‚݂̍œK‰»‚æ‚è‚àA
+                s“ǂݍž‚݂̍œK‰»‚ª”ñí‚ɏd—v‚Å‚·B
+                ‚µ‚©‚µAƒNƒ‰ƒX‚Ì‚¢‚­‚‚©‚̃vƒƒpƒeƒB‚¾‚¯‚ð“ǂݍž‚Þ‚±‚Ƃ́AŠù‘¶‚̃e[ƒuƒ‹‚ª‰½•S‚à‚Ì—ñ‚ðŽ‚¿A
+                ƒf[ƒ^ƒ‚ƒfƒ‹‚ð‰ü‘P‚Å‚«‚È‚¢‚È‚Ç‚Ì‹É’[‚ȏꍇ‚É‚Í—L—p‚Å‚·B
+            </para>
+
+            <para>
+                ’x‰„ƒvƒƒpƒeƒB“ǂݍž‚Ý‚ð—LŒø‚É‚·‚é‚ɂ́A‘Ώۂ̃vƒƒpƒeƒB‚̃}ƒbƒsƒ“ƒO‚Å <literal>lazy</literal> 
+                ‘®«‚ðƒZƒbƒg‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <programlisting><![CDATA[<class name="Document">
+       <id name="id">
+        <generator class="native"/>
+    </id>
+    <property name="name" not-null="true" length="50"/>
+    <property name="summary" not-null="true" length="200" lazy="true"/>
+    <property name="text" not-null="true" length="2000" lazy="true"/>
+</class>]]></programlisting>
+
+            <para>
+                ’x‰„ƒvƒƒpƒeƒB“ǂݍž‚݂̓rƒ‹ƒhŽž‚̃oƒCƒgƒR[ƒh‘g‚ݍž‚Ý‚ð•K—v‚Æ‚µ‚Ü‚·I‚à‚µ
+                ‰i‘±ƒNƒ‰ƒX‚É‘g‚ݍž‚Ý‚ª‚³‚ê‚Ä‚¢‚È‚¢‚È‚çAHibernate‚Í–Ù‚Á‚Ä’x‰„ƒvƒƒpƒeƒB‚̐ݒè‚𖳎‹‚µ‚āA
+                ‘¦ŽžƒtƒFƒbƒ`‚É–ß‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                ƒoƒCƒgƒR[ƒh‘g‚ݍž‚݂͈ȉº‚ÌAntƒ^ƒXƒN‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <programlisting><![CDATA[<target name="instrument" depends="compile">
+    <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
+        <classpath path="${jar.path}"/>
+        <classpath path="${classes.dir}"/>
+        <classpath refid="lib.class.path"/>
+    </taskdef>
+
+    <instrument verbose="true">
+        <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
+            <include name="*.class"/>
+        </fileset>
+    </instrument>
+</target>]]></programlisting>
+
+            <para>
+                •s—v‚È—ñ‚ð“ǂݍž‚Ü‚È‚¢‚½‚߂́A•Ê‚́i‚æ‚è‚æ‚¢Hj•û–@‚́A­‚È‚­‚Æ‚à
+                “ǂݍž‚݂݂̂̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚É‚¨‚¢‚ẮAHQL‚âCriteriaƒNƒGƒŠ‚̎ˉe
+                ‹@”\‚ðŽg‚¤‚±‚Æ‚Å‚·B‚±‚Ì•û–@‚̓rƒ‹ƒhŽž‚̃oƒCƒgƒR[ƒh‘g‚ݍž‚Ý‚ª•s—v‚É‚È‚èA
+                ‚æ‚è—Ç‚¢‰ðŒˆ•û–@‚Å‚·B
+            </para>
+            
+            <para>
+                HQL‚Å <literal>fetch all properties</literal> ‚ðŽg‚¤‚±‚ƂŁA•’Ê‚Ç‚¨‚è‚Ì
+                ƒvƒƒpƒeƒB‚Ì‘¦ŽžƒtƒFƒbƒ`ƒ“ƒO‚ð‹­§‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="performance-cache" revision="1">
+        <title>‘æ2ƒŒƒxƒ‹ƒLƒƒƒbƒVƒ…</title>
+
+        <para>
+            Hibernate‚Ì <literal>Session</literal> ‚͉i‘±ƒf[ƒ^‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ƒŒƒxƒ‹‚̃LƒƒƒbƒVƒ…‚Å‚·B
+            class-by-class‚Æcollection-by-collection‚²‚Ƃ́AƒNƒ‰ƒXƒ^ƒŒƒxƒ‹‚âJVMƒŒƒxƒ‹
+            i <literal>SessionFactory</literal> ƒŒƒxƒ‹j‚̃LƒƒƒbƒVƒ…‚ðÝ’è‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B
+            ƒNƒ‰ƒXƒ^‰»‚³‚ꂽƒLƒƒƒbƒVƒ…‚ɂ‚Ȃ®‚±‚Æ‚³‚¦o—ˆ‚Ü‚·B‚µ‚©‚µ’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ƒLƒƒƒbƒVƒ…‚Í‘¼‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚æ‚é‰i‘±‘w‚̕ύX‚ð
+            l—¶‚µ‚Ü‚¹‚ñiƒLƒƒƒbƒVƒ…ƒf[ƒ^‚ð’èŠú“I‚ÉŠúŒÀØ‚ê‚É‚·‚éÝ’è‚͏o—ˆ‚Ü‚·jB
+        </para>
+        
+        <para revision="1">
+            Hibernate‚ªŽg—p‚·‚éƒLƒƒƒbƒVƒ…ŽÀ‘•‚́A<literal>hibernate.cache.provider_class</literal> ƒvƒƒpƒeƒB‚É
+            <literal>org.hibernate.cache.CacheProvider</literal> ‚ðŽÀ‘•‚µ‚½ƒNƒ‰ƒX–¼‚ðŽw’è‚·‚邱‚ƂŕύX‚Å‚«‚Ü‚·B
+            Hibernate‚Í‘½‚­‚̃I[ƒvƒ“ƒ\[ƒX‚̃LƒƒƒbƒVƒ…ƒvƒƒoƒCƒ_‚ðƒrƒ‹ƒgƒCƒ“ŽÀ‘•‚ÅŽ‚Á‚Ä‚¢‚Ü‚·iŒã‚ɃŠƒXƒg‚ª‚ ‚è‚Ü‚·jB
+            ‰Á‚¦‚āA‘O‚Éà–¾‚µ‚½‚悤‚ɁA‚ ‚È‚½Ž©g‚ª“ÆŽ©‚ÌŽÀ‘•‚ð‚µ‚ÄA‚»‚ê‚ð‘g‚ݍž‚Þ‚±‚Æ‚ào—ˆ‚Ü‚·B
+            ƒo[ƒWƒ‡ƒ“3.2‚æ‚è‘O‚Å‚ÍEhCache‚ªƒfƒtƒHƒ‹ƒg‚̃LƒƒƒbƒVƒ…ƒvƒƒoƒCƒ_‚Å‚ ‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ƒo[ƒWƒ‡ƒ“3.2‚Å‚Í‚±‚ê‚Í“–‚Ä‚Í‚Ü‚è‚Ü‚¹‚ñB
+        </para>
+
+        <table frame="topbot" id="cacheproviders" revision="1">
+            <title>ƒLƒƒƒbƒVƒ…ƒvƒƒoƒCƒ_</title>
+            <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="3*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>ƒLƒƒƒbƒVƒ…</entry>
+              <entry>ƒvƒƒoƒCƒ_ƒNƒ‰ƒX</entry>
+              <entry>ƒ^ƒCƒv</entry>
+              <entry>ƒNƒ‰ƒXƒ^ƒZ[ƒt</entry>
+              <entry>ƒNƒGƒŠƒLƒƒƒbƒVƒ…‚̃Tƒ|[ƒg</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>Hashtablei»•i—p‚Æ‚µ‚ĈӐ}‚µ‚Ä‚¢‚Ü‚¹‚ñj</entry>
+                <entry><literal>org.hibernate.cache.HashtableCacheProvider</literal></entry>
+                <entry>ƒƒ‚ƒŠ</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>EHCache</entry>
+                <entry><literal>org.hibernate.cache.EhCacheProvider</literal></entry>
+                <entry>ƒƒ‚ƒŠAƒfƒBƒXƒN</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>OSCache</entry>
+                <entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
+                <entry>ƒƒ‚ƒŠAƒfƒBƒXƒN</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>SwarmCache</entry>
+                <entry><literal>org.hibernate.cache.SwarmCacheProvider</literal></entry>
+                <entry>ƒNƒ‰ƒXƒ^iipƒ}ƒ‹ƒ`ƒLƒƒƒXƒgj</entry>
+                <entry>yesiƒNƒ‰ƒXƒ^–³Œø‰»j</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>JBoss TreeCache</entry>
+                <entry><literal>org.hibernate.cache.TreeCacheProvider</literal></entry>
+                <entry>ƒNƒ‰ƒXƒ^iipƒ}ƒ‹ƒ`ƒLƒƒƒXƒgjAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒiƒ‹</entry>
+                <entry>yesi•¡»j</entry>
+                <entry>yesiŽž“¯Šú‚ª•K—vj</entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <sect2 id="performance-cache-mapping" revision="2">
+            <title>ƒLƒƒƒbƒVƒ…‚̃}ƒbƒsƒ“ƒO</title>
+
+            <para>
+                ƒNƒ‰ƒX‚âƒRƒŒƒNƒVƒ‡ƒ“‚̃}ƒbƒsƒ“ƒO‚Ì <literal>&lt;cache&gt;</literal> —v‘f‚͈ȉº‚ÌŒ`Ž®‚Å‚·B
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="cache1" coords="2 70"/>
+                    <area id="cache2" coords="3 70"/>
+                    <area id="cache3" coords="4 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<cache 
+    usage="transactional|read-write|nonstrict-read-write|read-only"
+    region="RegionName"
+    include="all|non-lazy"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="cache1">
+                        <para>
+                            <literal>usage</literal> (required) specifies the caching strategy:
+                            <literal>transactional</literal>,
+                            <literal>read-write</literal>,
+                            <literal>nonstrict-read-write</literal> or
+                            <literal>read-only</literal>
+                        </para>
+                    </callout>                   
+                    <callout arearefs="cache2">
+                        <para>
+                            <literal>region</literal> (optional, defaults to the class or
+                            collection role name) specifies the name of the second level cache 
+                            region
+                        </para>
+                    </callout>                   
+                    <callout arearefs="cache3">
+                        <para>
+                            <literal>include</literal> (optional, defaults to <literal>all</literal>) 
+                            <literal>non-lazy</literal> specifies that properties of the entity mapped
+                            with <literal>lazy="true"</literal> may not be cached when attribute-level
+                            lazy fetching is enabled
+                        </para>
+                    </callout>                   
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                ‚Ü‚½‚́i‚æ‚è‚æ‚¢•û–@‚Æ‚µ‚āHjA <literal>hibernate.cfg.xml</literal> ‚É <literal>&lt;class-cache&gt;</literal> 
+                ‚Æ <literal>&lt;collection-cache&gt;</literal> —v‘f‚ðŽw’è‚·‚邱‚Æ‚ào—ˆ‚Ü‚·B
+            </para>
+            
+            <para>
+                <literal>usage</literal> ‘®«‚Í <emphasis>ƒLƒƒƒbƒVƒ…‚Ì•À—ñ«í—ª</emphasis> ‚ðŽw’肵‚Ü‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-cache-readonly">
+            <title>read onlyí—ª</title>
+
+            <para>
+                ‚à‚µƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ª“ǂݍž‚Ý‚Ì‚Ý•K—v‚ŁA‰i‘±ƒNƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ð•ÏX‚µ‚È‚¢‚È‚çA
+                <literal>read-only</literal> ƒLƒƒƒbƒVƒ…‚ðŽg‚¤‚±‚Æ‚ªo—ˆ‚Ü‚·B‚±‚ê‚Í‚à‚Á‚Æ‚à’Pƒ‚Å
+                ‚à‚Á‚Æ‚àƒpƒtƒH[ƒ}ƒ“ƒX‚Ì—Ç‚¢í—ª‚Å‚·BƒNƒ‰ƒXƒ^‚Å‚ÌŽg—p‚àŠ®‘S‚ɈÀ‘S‚Å‚·B
+            </para>
+
+            <programlisting><![CDATA[<class name="eg.Immutable" mutable="false">
+    <cache usage="read-only"/>
+    ....
+</class>]]></programlisting>
+
+        </sect2>
+
+
+        <sect2 id="performance-cache-readwrite">
+            <title>read/writeí—ª</title>
+
+            <para>
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ªƒf[ƒ^‚ðXV‚·‚é•K—v‚ª‚ ‚é‚È‚çA <literal>read-write</literal> ƒLƒƒƒbƒVƒ…‚ª“K“–‚©‚à
+                ‚µ‚ê‚Ü‚¹‚ñB‚±‚̃LƒƒƒbƒVƒ…í—ª‚́AƒVƒŠƒAƒ‰ƒCƒUƒuƒ‹‚ȃgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“•ª—£ƒŒƒxƒ‹‚ª—v‹‚³‚ê‚é‚È‚çA
+                Œˆ‚µ‚ÄŽg‚¤‚ׂ«‚Å‚Í‚ ‚è‚Ü‚¹‚ñB‚à‚µƒLƒƒƒbƒVƒ…‚ªJTAŠÂ‹«‚ÅŽg‚í‚ê‚é‚È‚çAJTA <literal>TransactionManager</literal> 
+                ‚ðŽæ“¾‚·‚邽‚ß‚Ì•û–@‚ðŽ¦‚· <literal>hibernate.transaction.manager_lookup_class</literal> 
+                ƒvƒƒpƒeƒB‚ðŽw’肵‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB‘¼‚̊‹«‚ł́A <literal>Session.close()</literal> 
+                ‚â <literal>Session.disconnect()</literal> ‚ªŒÄ‚΂ꂽ‚Æ‚«‚ɁAŠmŽÀ‚Ƀgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ªŠ®—¹
+                ‚µ‚Ä‚¢‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                ‚à‚µƒNƒ‰ƒXƒ^‚Å‚±‚̐헪‚ðŽg‚¢‚½‚¢‚È‚çAŠî‚Æ‚È‚éƒLƒƒƒbƒVƒ…‚ÌŽÀ‘•‚ªƒƒbƒN‚ðƒTƒ|[ƒg
+                ‚µ‚Ä‚¢‚邱‚Æ‚ð•ÛØ‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                ‘g‚ݍž‚݂̃LƒƒƒbƒVƒ…ƒvƒƒoƒCƒ_‚Í <emphasis>ƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚¹‚ñ</emphasis> B
+            </para>
+
+            <programlisting><![CDATA[<class name="eg.Cat" .... >
+    <cache usage="read-write"/>
+    ....
+    <set name="kittens" ... >
+        <cache usage="read-write"/>
+        ....
+    </set>
+</class>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-cache-nonstrict">
+            <title>Œµ–§‚Å‚Í‚È‚¢read/writeí—ª</title>
+
+            <para>
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ª‚½‚Ü‚É‚µ‚©ƒf[ƒ^‚ðXV‚·‚é•K—v‚Í‚È‚­i‚·‚È‚í‚¿“ñ‚‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ª
+                “¯Žž‚É“¯‚¶ƒAƒCƒeƒ€‚ðXV‚µ‚悤‚Æ‚·‚邱‚Æ‚Í‚Ù‚Æ‚ñ‚Ç‹N‚±‚ç‚È‚¢jAŒµ–§‚ȃgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“•ª—£‚ª
+                —v‹‚³‚ê‚È‚¢‚È‚çA <literal>nonstrict-read-write</literal> ƒLƒƒƒbƒVƒ…‚ª“K“–‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                ‚à‚µƒLƒƒƒbƒVƒ…‚ªJTAŠÂ‹«‚ÅŽg‚í‚ê‚é‚È‚çA <literal>hibernate.transaction.manager_lookup_class</literal> 
+                ‚ðŽw’肵‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB‘¼‚̊‹«‚ł́A <literal>Session.close()</literal> 
+                ‚â <literal>Session.disconnect()</literal> ‚ªŒÄ‚΂ꂽ‚Æ‚«‚ɁAŠmŽÀ‚Ƀgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ªŠ®—¹
+                ‚µ‚Ä‚¢‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-cache-transactional">
+            <title>transactionalí—ª</title>
+
+            <para>
+                <literal>transactional</literal> ƒLƒƒƒbƒVƒ…í—ª‚ÍJBoss TreeCache‚̂悤‚ÈŠ®‘S‚ȃgƒ‰ƒ“ƒUƒNƒVƒ‡ƒiƒ‹
+                ƒLƒƒƒbƒVƒ…ƒvƒƒoƒCƒ_‚̃Tƒ|[ƒg‚ð’ñ‹Ÿ‚µ‚Ü‚·B
+                ‚±‚̂悤‚ȃLƒƒƒbƒVƒ…‚ÍJTAŠÂ‹«‚Å‚Ì‚ÝŽg—p‰Â”\‚ŁA <literal>hibernate.transaction.manager_lookup_class</literal> 
+                ‚ðŽw’肵‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            </para>
+
+        </sect2>
+        
+        <para>
+            ‚·‚ׂĂ̓¯Žž•Às«ƒLƒƒƒbƒVƒ…í—ª‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚éƒLƒƒƒbƒVƒ…ƒvƒƒoƒCƒ_‚Í‚ ‚è‚Ü‚¹‚ñB
+            ˆÈ‰º‚Ì•\‚͂ǂ̃vƒƒoƒCƒ_‚ª‚Ç‚Ì“¯Žž•À—ñ«í—ª‚ɑΉž‚·‚é‚©‚ð•\‚µ‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <table frame="topbot">
+            <title>“¯Žž•Às«ƒLƒƒƒbƒVƒ…í—ª‚̃Tƒ|[ƒg</title>
+            <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="1*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>ƒLƒƒƒbƒVƒ…</entry>
+              <entry>read-only</entry>
+              <entry>Œµ–§‚Å‚Í‚È‚¢read-write</entry>
+              <entry>read-write</entry>
+              <entry>transactional</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>Hashtablei»•i—p‚Æ‚µ‚ĈӐ}‚µ‚Ä‚¢‚Ü‚¹‚ñj</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>EHCache</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>OSCache</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>SwarmCache</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>JBoss TreeCache</entry>
+                <entry>yes</entry>
+                <entry></entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+    </sect1>
+
+    <sect1 id="performance-sessioncache" revision="2">
+        <title>ƒLƒƒƒbƒVƒ…‚ÌŠÇ—</title>
+
+        <para>
+            ƒIƒuƒWƒFƒNƒg‚ð <literal>save()</literal> A <literal>update()</literal> A <literal>saveOrUpdate()</literal> 
+            ‚É“n‚·‚Æ‚«A‚»‚µ‚Ä <literal>load()</literal> A <literal>get()</literal> A <literal>list()</literal> A
+            <literal>iterate()</literal> A <literal>scroll()</literal> ‚ðŽg‚Á‚ăIƒuƒWƒFƒNƒg‚𕜌³‚·‚é‚Æ‚«‚ɂ͏í‚ɁA
+            ‚»‚̃IƒuƒWƒFƒNƒg‚Í <literal>Session</literal> ‚Ì“à•”ƒLƒƒƒbƒVƒ…‚ɒljÁ‚³‚ê‚Ü‚·B
+        </para>
+        <para>
+            ŽŸ‚É <literal>flush()</literal> ‚ªŒÄ‚΂ê‚é‚ƁAƒIƒuƒWƒFƒNƒg‚̏ó‘Ԃ̓f[ƒ^ƒx[ƒX‚Æ“¯Šú‰»‚³‚ê‚Ü‚·B
+            ‚à‚µ‚±‚Ì“¯Šú‚ª‹N‚±‚邱‚Æ‚ð–]‚Ü‚È‚¢‚Æ‚«‚âA–c‘å‚Ȑ”‚̃IƒuƒWƒFƒNƒg‚ðˆ—‚µ‚Ä‚¢‚ăƒ‚ƒŠ‚ðŒø—¦“I‚É
+            ˆµ‚¤•K—v‚ª‚ ‚é‚Æ‚«‚́A <literal>evict()</literal> ƒƒ\ƒbƒh‚ðŽg‚Á‚ĈꎟƒLƒƒƒbƒVƒ…‚©‚ç
+            ƒIƒuƒWƒFƒNƒg‚âƒRƒŒƒNƒVƒ‡ƒ“‚ðíœ‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
+while ( cats.next() ) {
+    Cat cat = (Cat) cats.get(0);
+    doSomethingWithACat(cat);
+    sess.evict(cat);
+}]]></programlisting>
+        
+        <para>
+            <literal>Session</literal> ‚̓Cƒ“ƒXƒ^ƒ“ƒX‚ªƒZƒbƒVƒ‡ƒ“ƒLƒƒƒbƒVƒ…‚ÉŠÜ‚Ü‚ê‚é‚©‚Ç‚¤‚©‚ð”»’f‚·‚邽‚ß‚Ì
+            <literal>contains()</literal> ƒƒ\ƒbƒh‚à’ñ‹Ÿ‚µ‚Ü‚·B
+        </para>
+        
+        <para>
+            ‚·‚ׂẴIƒuƒWƒFƒNƒg‚ðƒZƒbƒVƒ‡ƒ“ƒLƒƒƒbƒVƒ…‚©‚犮‘S‚ÉŽæ‚菜‚­‚ɂ́A<literal>Session.clear()</literal> 
+            ‚ðŒÄ‚яo‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+        
+        <para>
+            “ñŽŸƒLƒƒƒbƒVƒ…‚Ì‚½‚߂ɁA <literal>SessionFactory</literal> ‚É‚Í
+            ƒCƒ“ƒXƒ^ƒ“ƒXAƒNƒ‰ƒX‘S‘́AƒRƒŒƒNƒVƒ‡ƒ“‚̃Cƒ“ƒXƒ^ƒ“ƒXAƒRƒŒƒNƒVƒ‡ƒ“‘S‘Ì‚ðƒLƒƒƒbƒVƒ…‚©‚ç
+            íœ‚·‚邽‚߂̃ƒ\ƒbƒh‚ª‚»‚ꂼ‚ê’è‹`‚³‚ê‚Ä‚¢‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[sessionFactory.evict(Cat.class, catId); //evict a particular Cat
+sessionFactory.evict(Cat.class);  //evict all Cats
+sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
+sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections]]></programlisting>
+
+        <para>
+            <literal>CacheMode</literal> ‚Í“Á’è‚̃ZƒbƒVƒ‡ƒ“‚ª“ñŽŸƒLƒƒƒbƒVƒ…‚Ƃǂ̂悤‚É‘ŠŒÝì—p‚·‚é‚©‚ð
+            Žw’肵‚Ü‚·B
+        </para>
+        
+        <itemizedlist>
+        <listitem>
+        <para>
+            <literal>CacheMode.NORMAL</literal> - ƒAƒCƒeƒ€‚̓ǂݍž‚݂Ə‘‚«ž‚Ý‚Å“ñŽŸƒLƒƒƒbƒVƒ…‚ðŽg‚¢‚Ü‚·
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.GET</literal> - “ǂݍž‚Ý‚Í“ñŽŸƒLƒƒƒbƒVƒ…‚©‚çs‚¢‚Ü‚·‚ªAƒf[ƒ^‚ð
+            XV‚µ‚½ê‡‚ðœ‚¢‚Ä“ñŽŸƒLƒƒƒbƒVƒ…‚ɏ‘‚«ž‚Ý‚ð‚µ‚Ü‚¹‚ñB
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.PUT</literal> - “ñŽŸƒLƒƒƒbƒVƒ…‚ɃAƒCƒeƒ€‚ð‘‚«ž‚Ý‚Ü‚·‚ªA“ǂݍž‚Ý‚É‚Í
+            “ñŽŸƒLƒƒƒbƒVƒ…‚ðŽg‚¢‚Ü‚¹‚ñB
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.REFRESH</literal> - “ñŽŸƒLƒƒƒbƒVƒ…‚ɃAƒCƒeƒ€‚ð‘‚«ž‚Ý‚Ü‚·‚ªA“ǂݍž‚Ý‚É‚Í
+            “ñŽŸƒLƒƒƒbƒVƒ…‚ðŽg‚킸A <literal>hibernate.cache.use_minimal_puts</literal> 
+            ‚̉e‹¿‚ðŽó‚¯‚¸‚ɁAƒf[ƒ^ƒx[ƒX‚©‚ç“ǂݍž‚Þ‚·‚ׂẴAƒCƒeƒ€‚Ì“ñŽŸƒLƒƒƒbƒVƒ…‚ð‹­§“I‚ɃŠƒtƒŒƒbƒVƒ…‚µ‚Ü‚·B
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            “ñŽŸƒLƒƒƒbƒVƒ…‚Ì“à—e‚âƒNƒGƒŠƒLƒƒƒbƒVƒ…—̈æ‚ðŒ©‚é‚½‚߂ɁA <literal>Statistics</literal> API‚ð
+            Žg‚Á‚Ä‚­‚¾‚³‚¢B
+        </para>
+        
+        <programlisting><![CDATA[Map cacheEntries = sessionFactory.getStatistics()
+        .getSecondLevelCacheStatistics(regionName)
+        .getEntries();]]></programlisting>
+        
+        <para>
+            “Œvî•ñ‚ð—LŒø‚É‚µ‚āA‚³‚ç‚ɃIƒvƒVƒ‡ƒ“‚Æ‚µ‚āAƒLƒƒƒbƒVƒ…ƒGƒ“ƒgƒŠ‚ð
+            l‚ª‚æ‚藝‰ð‰Â”\‚ÈŒ`Ž®‚Å•ÛŽ‚·‚邱‚Æ‚ðHibernate‚É‹­§‚µ‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[hibernate.generate_statistics true
+hibernate.cache.use_structured_entries true]]></programlisting>       
+                
+    </sect1>
+    
+    <sect1 id="performance-querycache" revision="1">
+        <title>ƒNƒGƒŠƒLƒƒƒbƒVƒ…</title>
+
+        <para>
+            ƒNƒGƒŠ‚̃ŠƒUƒ‹ƒgƒZƒbƒg‚àƒLƒƒƒbƒVƒ…o—ˆ‚Ü‚·B‚±‚ê‚Í“¯‚¶ƒpƒ‰ƒ[ƒ^‚ʼn½“x‚àŽÀs‚³‚ê‚é
+            ƒNƒGƒŠ‚ɑ΂µ‚Ä‚Ì‚Ý—L—p‚Å‚·BƒNƒGƒŠƒLƒƒƒbƒVƒ…‚ðŽg‚¤‚ɂ́A‚Ü‚¸Ý’è‚Å—LŒø‚É‚µ‚È‚­‚Ä‚Í‚È‚è‚Ü‚¹‚ñB
+        </para>
+
+        <programlisting><![CDATA[hibernate.cache.use_query_cache true]]></programlisting>       
+        
+        <para>
+            ‚±‚̐ݒè‚͐V‚½‚É“ñ‚‚̃LƒƒƒbƒVƒ…—̈æ‚̍쐬‚ðs‚¢‚Ü‚·Bˆê‚‚̓NƒGƒŠ‚̃ŠƒUƒ‹ƒgƒZƒbƒg‚Ì
+            ƒLƒƒƒbƒVƒ…i <literal>org.hibernate.cache.StandardQueryCache</literal> j‚ð•ÛŽ‚µA
+            ‚à‚¤1‚‚̓NƒGƒŠ‰Â”\‚ȃe[ƒuƒ‹‚ւ̍ŐV‚̍XVƒ^ƒCƒ€ƒXƒ^ƒ“ƒv
+           i <literal>org.hibernate.cache.UpdateTimestampsCache</literal> j‚ð•ÛŽ‚µ‚Ü‚·B
+            ƒNƒGƒŠƒLƒƒƒbƒVƒ…‚̓ŠƒUƒ‹ƒgƒZƒbƒg‚ÌŽÀÛ‚Ì—v‘f‚̏ó‘Ԃ̓LƒƒƒbƒVƒ…‚µ‚È‚¢‚±‚Æ‚É
+            ’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢BƒLƒƒƒbƒVƒ…‚·‚é‚Ì‚ÍŽ¯•ÊŽq‚Ì’l‚ƁA’lŒ^‚ÌŒ‹‰Ê‚Ì‚Ý‚Å‚·B
+            ‚»‚Ì‚½‚߁AƒNƒGƒŠƒLƒƒƒbƒVƒ…‚͏í‚É“ñŽŸƒLƒƒƒbƒVƒ…‚ƈꏏ‚ÉŽg‚¤‚ׂ«‚Å‚·B
+        </para>
+        
+        <para>
+            ‚Ù‚Æ‚ñ‚ǂ̃NƒGƒŠ‚̓LƒƒƒbƒVƒ…‚̉¶Œb‚ðŽó‚¯‚È‚¢‚̂ŁAƒfƒtƒHƒ‹ƒg‚ł̓NƒGƒŠ‚̓LƒƒƒbƒVƒ…‚³‚ê‚Ü‚¹‚ñB
+            ƒLƒƒƒbƒVƒ…‚ð—LŒø‚É‚·‚é‚ɂ́A <literal>Query.setCacheable(true)</literal> ‚ðŒÄ‚яo‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚»‚¤‚·‚ê‚΃NƒGƒŠ‚ªŠù‘¶‚̃LƒƒƒbƒVƒ…Œ‹‰Ê‚ð’T‚µAƒNƒGƒŠŽÀsŽž‚É‚»‚ÌŒ‹‰Ê‚ðƒLƒƒƒbƒVƒ…‚ɒljÁ‚·‚é
+            ‚悤‚É‚È‚è‚Ü‚·B
+        </para>
+        
+        <para>
+            ƒNƒGƒŠƒLƒƒƒbƒVƒ…‚Ì”jŠüƒ|ƒŠƒV[‚ð×‚©‚­§Œä‚µ‚½‚¢‚Æ‚«‚́A <literal>Query.setCacheRegion()</literal> 
+            ‚ðŒÄ‚яo‚µ‚Ä“Á’è‚̃NƒGƒŠ‚ɑ΂·‚éƒLƒƒƒbƒVƒ…—̈æ‚ðŽw’è‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
+    .setEntity("blogger", blogger)
+    .setMaxResults(15)
+    .setCacheable(true)
+    .setCacheRegion("frontpages")
+    .list();]]></programlisting>
+
+        <para>
+            ƒNƒGƒŠ‚ªŽ©g‚̃NƒGƒŠƒLƒƒƒbƒVƒ…—̈æ‚̃ŠƒtƒŒƒbƒVƒ…‚ð‹­§‚µ‚È‚¯‚ê‚΂Ȃç‚È‚¢‚È‚çA
+            <literal>Query.setCacheMode(CacheMode.REFRESH)</literal> ‚ðŒÄ‚яo‚·‚ׂ«‚Å‚·B‚±‚ê‚Í
+            Œ³‚Æ‚È‚éƒf[ƒ^‚ª•Ê‚̃vƒƒZƒX‚É‚æ‚Á‚čXV‚³‚ꂽ‚èi‚·‚È‚í‚¿Hibernate‚ð’Ê‚¶‚čXV‚³‚ê‚È‚¢jA
+            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É“Á’è‚̃NƒGƒŠƒŠƒUƒ‹ƒgƒZƒbƒg‚ð‘I‘ð‚µ‚ÄƒŠƒtƒŒƒbƒVƒ…‚³‚¹‚éê‡‚É“Á‚É—L—p‚Å‚·B
+            ‚³‚ç‚É—L—p‚È‚à‚¤ˆê‚‚̕û–@‚́A <literal>SessionFactory.evictQueries()</literal> 
+            ‚É‚æ‚Á‚ăNƒGƒŠƒLƒƒƒbƒVƒ…—̈æ‚ðÁ‹Ž‚·‚邱‚Æ‚Å‚·B
+        </para>
+
+    </sect1>
+™14.1
+    <sect1 id="performance-collections">
+        <title>ƒRƒŒƒNƒVƒ‡ƒ“‚̃pƒtƒH[ƒ}ƒ“ƒX‚Ì—‰ð</title>
+
+        <para>
+            ƒRƒŒƒNƒVƒ‡ƒ“‚̘b‘è‚É‚Í‚·‚Å‚É‘½‚­‚ÌŽžŠÔ‚ðŽg‚¢‚Ü‚µ‚½B‚±‚̐߂łÍ
+            ƒRƒŒƒNƒVƒ‡ƒ“‚ªŽÀsŽž‚ɂǂ̂悤‚ɐU•‘‚¤‚©‚ɂ‚¢‚Ă̘b‘è‚ð2A3Žæ‚èã‚°‚Ü‚·B
+        </para>
+
+        <sect2 id="performance-collections-taxonomy">
+            <title>•ª—Þ</title>
+
+            <para>Hibernate‚Í3‚‚̊î–{“I‚ȃRƒŒƒNƒVƒ‡ƒ“‚ÌŽí—Þ‚ð’è‹`‚µ‚Ä‚¢‚Ü‚·B
+                  </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>’l‚̃RƒŒƒNƒVƒ‡ƒ“</para>
+            </listitem>
+            <listitem>
+                <para>ˆê‘Α½ŠÖ˜A</para>
+            </listitem>
+            <listitem>
+                <para>‘½‘Α½ŠÖ˜A</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                ‚±‚Ì•ª—Þ‚Í‚³‚Ü‚´‚܂ȃe[ƒuƒ‹‚âŠO•”ƒL[ŠÖ˜A‚ð‹æ•Ê‚µ‚Ü‚·‚ªAŽ„‚½‚¿‚ª’m‚é•K—v‚Ì‚ ‚é
+                ŠÖ˜Aƒ‚ƒfƒ‹‚ɂ‚¢‚Ä‚Ù‚Æ‚ñ‚Ç‚È‚É‚à‹³‚¦‚Ä‚­‚ê‚Ü‚¹‚ñBŠÖ˜A\‘¢‚âƒpƒtƒH[ƒ}ƒ“ƒX‚Ì“Á’¥‚ð
+                Š®‘S‚É—‰ð‚·‚é‚ɂ́AHibernate‚ªƒRƒŒƒNƒVƒ‡ƒ“‚̍s‚ðXVAíœ‚·‚邽‚ß‚ÉŽg‚¤ŽåƒL[‚Ì
+                \‘¢‚à‚Ü‚½l‚¦‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB‚±‚ê‚͈ȉº‚Ì•ª—Þ‚ð’ñŽ¦‚µ‚Ü‚·B
+            </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>ƒCƒ“ƒfƒbƒNƒX•t‚«ƒRƒŒƒNƒVƒ‡ƒ“</para>
+            </listitem>
+            <listitem>
+                <para>set</para>
+            </listitem>
+            <listitem>
+                <para>bag</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                ‚·‚ׂẴCƒ“ƒfƒbƒNƒX•t‚«ƒRƒŒƒNƒVƒ‡ƒ“imapAlistA”z—ñj‚Í <literal>&lt;key&gt;</literal> 
+                ‚Æ <literal>&lt;index&gt;</literal> ƒJƒ‰ƒ€‚©‚ç‚È‚éŽåƒL[‚ðŽ‚Á‚Ä‚¢‚Ü‚·B‚±‚̏ꍇ‚Í
+                ƒRƒŒƒNƒVƒ‡ƒ“‚̍XV‚Í”ñí‚ÉŒø—¦“I‚Å‚·BŽåƒL[‚Í—L—p‚ȃCƒ“ƒfƒbƒNƒX‚É‚È‚èAHibernate‚ª
+                “Á’è‚̍s‚ðXV‚Ü‚½‚͍폜‚·‚é‚Æ‚«‚ɁA‚»‚̍s‚ðŒø—¦“I‚ÉŒ©‚‚¯‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            </para>
+                        
+            <para>
+                set‚Í <literal>&lt;key&gt;</literal> ‚©‚ç‚È‚éŽåƒL[‚Æ—v‘f‚̃Jƒ‰ƒ€‚ðŽ‚Á‚Ä‚¢‚Ü‚·B
+                ‚±‚ê‚̓RƒŒƒNƒVƒ‡ƒ“—v‘f‚Ì‚¢‚­‚‚©‚ÌŒ^‚ɂ‚¢‚Ä‚ÍŒø—¦“I‚Å‚Í‚È‚¢‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                “Á‚É•¡‡—v‘fA‘å‚«‚ȃeƒLƒXƒgAƒoƒCƒiƒŠƒtƒB[ƒ‹ƒh‚Å‚Í”ñŒø—¦‚Å‚·Bƒf[ƒ^ƒx[ƒX‚Í
+                •¡‡ŽåƒL[‚ÉŒø—¦“I‚ɃCƒ“ƒfƒbƒNƒX‚ð•t‚¯‚邱‚Æ‚ª‚Å‚«‚È‚¢‚©‚ç‚Å‚·Bˆê•ûA1‘Α½‚⑽‘Α½ŠÖ˜A‚É‚¨‚¢‚āA
+                “Á‚ɐlHŽ¯•ÊŽq‚̏ꍇ‚Í“¯‚¶‚®‚ç‚¢Œø—¦“I‚Å‚·Bi—]’kF <literal>SchemaExport</literal> 
+                ‚ÅŽÀÛ‚É <literal>&lt;set&gt;</literal> ‚ÌŽåƒL[‚ðì‚肽‚¢‚È‚çA‚·‚ׂẴJƒ‰ƒ€‚Å
+                 <literal>not-null="true"</literal> ‚ðéŒ¾‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñBj
+            </para>
+
+            <para>
+                <literal>&lt;idbag&gt;</literal> ƒ}ƒbƒsƒ“ƒO‚͑㗝ƒL[‚ð’è‹`‚µ‚Ü‚·B‚»‚Ì‚½‚ß
+                XV‚͏í‚É”ñí‚ÉŒø—¦“I‚Å‚·BŽ–ŽÀãA‚±‚ê‚͍őP‚̃P[ƒX‚Å‚·B
+            </para>
+            
+            <para>
+                bag‚͍ň«‚̃P[ƒX‚Å‚·Bbag‚Í—v‘f‚Ì’l‚̏d•¡‚ª‰Â”\‚ŁAƒCƒ“ƒfƒbƒNƒXƒJƒ‰ƒ€‚ðŽ‚½‚È‚¢‚½‚߁A
+                ŽåƒL[‚Í’è‹`‚³‚ê‚È‚¢‚©‚à‚µ‚ê‚Ü‚¹‚ñBHibernate‚ɂ͏d•¡‚µ‚½s‚ð‹æ•Ê‚·‚é•û–@‚ª‚ ‚è‚Ü‚¹‚ñB
+                Hibernate‚Í‚±‚Ì–â‘è‚Ì‰ðŒˆ‚Ì‚½‚߂ɁA•ÏX‚ª‚ ‚Á‚½‚Æ‚«‚ɂ͏í‚ÉŠ®‘S‚ȍ폜
+                iˆê‚Â‚Ì <literal>DELETE</literal> ‚É‚æ‚éj‚ðs‚¢AƒRƒŒƒNƒVƒ‡ƒ“‚̍č쐬‚ðs‚¢‚Ü‚·B
+                ‚±‚ê‚Í”ñí‚É”ñŒø—¦“I‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+            </para>
+
+            <para>
+                1‘Α½ŠÖ˜A‚ł́AuŽåƒL[v‚̓f[ƒ^ƒx[ƒX‚̃e[ƒuƒ‹‚Ì•¨—“I‚È
+                ŽåƒL[‚Å‚Í‚È‚¢‚©‚à‚µ‚ê‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B‚µ‚©‚µ‚±‚̏ꍇ‚Å‚³‚¦Aã‹L‚Ì•ª—Þ‚Í‚Ü‚¾—L—p‚Å‚·B
+                iHibernate‚ªƒRƒŒƒNƒVƒ‡ƒ“‚̌X‚̍s‚ð‚Ç‚¤‚â‚Á‚āuŒ©‚‚¯‚é‚©v‚ð•\‚µ‚Ä‚¢‚Ü‚·Bj
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-collections-mostefficientupdate">
+            <title>XV‚É‚à‚Á‚Æ‚àŒø—¦“I‚ȃRƒŒƒNƒVƒ‡ƒ“ listAmapAidbagAset</title>
+
+            <para>
+                ã‚Å‚Ì‹c˜_‚©‚çAƒCƒ“ƒfƒbƒNƒX•t‚«ƒRƒŒƒNƒVƒ‡ƒ“‚Ɓi•’ʂ́jset‚Í—v‘f‚̒ljÁAíœA
+                XV‚Å‚à‚Á‚Æ‚àŒø—¦“I‚È‘€ì‚ªo—ˆ‚邱‚Æ‚Í–¾‚ç‚©‚Å‚·B
+            </para>
+
+            <para>
+                ‚قڊԈႢ‚È‚­A‘½‘Α½ŠÖ˜A‚â’l‚̃RƒŒƒNƒVƒ‡ƒ“‚É‚¨‚¢‚āAƒCƒ“ƒfƒbƒNƒX•t‚«ƒRƒŒƒNƒVƒ‡ƒ“‚ª
+                set‚æ‚è‚à—D‚ê‚Ä‚¢‚é“_‚ªˆê‚ˆȏ゠‚è‚Ü‚·B <literal>Set</literal> ‚Í‚»‚Ì
+                \‘¢‚Ì‚½‚߂ɁAHibernate‚Í—v‘f‚ªu•ÏXv‚³‚ꂽ‚Æ‚«‚ɍs‚ðŒˆ‚µ‚Ä <literal>UPDATE</literal> 
+                ‚µ‚Ü‚¹‚ñB <literal>Set</literal> ‚ւ̕ύX‚͏í‚ɁiŒÂX‚̍s‚́j<literal>INSERT</literal> 
+                ‚Æ <literal>DELETE</literal> ‚É‚æ‚Á‚čs‚¢‚Ü‚·BŒJ‚è•Ô‚µ‚Ü‚·‚ªA‚±‚ê‚͈ê‘Α½ŠÖ˜A‚É‚Í
+                “–‚Ä‚Í‚Ü‚è‚Ü‚¹‚ñB
+            </para>
+
+            <para>
+                ”z—ñ‚Í’x‰„ˆ—‚ª‚Å‚«‚È‚¢‚Æ‚¢‚¤Œˆ‚Ü‚è‚Ȃ̂ŁAŒ‹˜_‚Æ‚µ‚āAlistAmapAidbag‚ª‚à‚Á‚Æ‚à
+                ƒpƒtƒH[ƒ}ƒ“ƒX‚Ì—Ç‚¢iinverse‚Å‚Í‚È‚¢jƒRƒŒƒNƒVƒ‡ƒ“ƒ^ƒCƒv‚Æ‚È‚è‚Ü‚·Bset‚à
+                ‚»‚ê‚قLjႢ‚Í‚ ‚è‚Ü‚¹‚ñBHibernate‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚ł́Aset‚̓RƒŒƒNƒVƒ‡ƒ“‚Ì‚à‚Á‚Æ‚à
+                ‹¤’Ê‚ÌŽí—Þ‚Æ‚µ‚ÄŠú‘Ò‚³‚ê‚Ü‚·Bset‚Ì•\Œ»‚ÍŠÖ˜Aƒ‚ƒfƒ‹‚Å‚Í‚à‚Á‚Æ‚àŽ©‘R‚¾‚©‚ç‚Å‚·B
+            </para>
+
+            <para>
+                ‚µ‚©‚µA‚æ‚­ƒfƒUƒCƒ“‚³‚ꂽHibernate‚̃hƒƒCƒ“ƒ‚ƒfƒ‹‚ł́A’ʏí‚à‚Á‚Æ‚à‘½‚¢ƒRƒŒƒNƒVƒ‡ƒ“‚Í
+                Ž–ŽÀã <literal>inverse="true"</literal> ‚ðŽw’肵‚½1‘Α½ŠÖ˜A‚Å‚·B‚±‚ê‚ç‚ÌŠÖ˜A‚ł́A
+                XV‚Í‘½‘Έê‚ÌŠÖ˜A’[‚ňµ‚í‚êAƒRƒŒƒNƒVƒ‡ƒ“‚̍XVƒpƒtƒH[ƒ}ƒ“ƒX‚Ì–â‘è‚Í“–‚Ä‚Í‚Ü‚è‚Ü‚¹‚ñB
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-collections-mostefficentinverse">
+            <title>inverseƒRƒŒƒNƒVƒ‡ƒ“‚É‚à‚Á‚Æ‚àÅ“K‚Èbag‚Ælist</title>
+
+            <para>
+                bag‚ðŒ©•ú‚µ‚Ä‚µ‚Ü‚¤‘O‚ɁAbagi‚»‚µ‚Älist‚àj‚ªset‚æ‚è‚à‚¸‚Á‚ƃpƒtƒH[ƒ}ƒ“ƒX‚ª—Ç‚¢“Á•Ê‚ȃP[ƒX‚ð
+                Ð‰î‚µ‚Ü‚·B <literal>inverse="true"</literal> ‚̃RƒŒƒNƒVƒ‡ƒ“iˆê”Ê“I‚È1‘Α½ŠÖ˜A‚ÌŽg‚¢•û‚Ȃǁj‚ŁA
+                bag‚Ì—v‘f‚ð‰Šú‰»iƒtƒFƒbƒ`j‚·‚é•K—v‚È‚­bag‚âlist‚É—v‘f‚ð’ljÁ‚Å‚«‚Ü‚·I
+                ‚±‚ê‚Í <literal>Collection.add()</literal> ‚â <literal>Collection.addAll()</literal> 
+                ‚Íbag‚â <literal>List</literal> ‚ł͏í‚Étrue‚ð•Ô‚³‚È‚¯‚ê‚΂Ȃç‚È‚¢‚©‚ç‚Å‚·
+                i <literal>Set</literal> ‚Ƃ͈قȂè‚Ü‚·jB
+                ‚±‚ê‚͈ȉº‚Ì‹¤’ʏˆ—‚ð‚æ‚葬‚­‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[Parent p = (Parent) sess.load(Parent.class, id);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c);  //no need to fetch the collection!
+sess.flush();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-collections-oneshotdelete">
+            <title>ˆêŠ‡íœ</title>
+
+            <para>
+                ŽžXAƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f‚ðˆê‚ˆê‚폜‚·‚邱‚Æ‚Í‹É‚ß‚Ä”ñŒø—¦“I‚ɂȂ邱‚Æ‚ª‚ ‚è‚Ü‚·B
+                Hibernate‚Í‹ð‚©‚Å‚Í‚È‚¢‚̂ŁAV‚µ‚¢‹ó‚̃RƒŒƒNƒVƒ‡ƒ“‚̏ꍇi <literal>list.clear()</literal> 
+                ‚ðŒÄ‚яo‚µ‚½ê‡‚Ȃǁj‚Å‚Í‚±‚ê‚ð‚·‚×‚«‚Å‚È‚¢‚±‚Æ‚ð’m‚Á‚Ä‚¢‚Ü‚·B‚±‚̏ꍇ‚́AHibernate‚Í
+                 <literal>DELETE</literal> ‚ðˆê‰ñ”­s‚µ‚āA‚»‚ê‚Å‚·‚ׂďI‚í‚è‚Ü‚·I
+            </para>
+
+            <para>
+                ƒTƒCƒY20‚̃RƒŒƒNƒVƒ‡ƒ“‚Ɉê‚‚̗v‘f‚ð’ljÁ‚µA‚»‚ê‚©‚ç“ñ‚‚̗v‘f‚ðíœ‚·‚é‚Æ‚µ‚Ü‚·B
+                Hibernate‚͈ê‚Â‚Ì <literal>INSERT</literal> •¶‚Æ“ñ‚Â‚Ì <literal>DELETE</literal> •¶‚𔭍s‚µ‚Ü‚·
+                iƒRƒŒƒNƒVƒ‡ƒ“‚ªbag‚Å‚È‚¯‚ê‚΁jB‚±‚ê‚ÍŠm‚©‚É–]‚Ü‚µ‚¢“®ì‚Å‚·B
+            </para>
+
+            <para>
+                ‚µ‚©‚µA18ŒÂ‚Ì—v‘f‚ðíœ‚µ‚Ä2‚‚ðŽc‚µA‚»‚ê‚©‚ç3‚V‚µ‚¢—v‘f‚ð’ljÁ‚·‚é‚Æ‚µ‚Ü‚·B
+                ‚±‚Ì‚Æ‚«“ñ‚‚̕û–@‚ª‚ ‚è‚Ü‚·B
+            </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>
+                18s‚ðˆê‚ˆê‚폜‚µ‚āA3s‚ð’ljÁ‚·‚é
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                ƒRƒŒƒNƒVƒ‡ƒ“‘S‘Ì‚ðíœi <literal>DELETE</literal> ‚ÌSQL‚ðˆê‰ñj‚µA‚»‚µ‚Ä5‚‚̗v‘f‚·‚ׂĂð
+                iˆê‚‚¸‚j’ljÁ‚·‚é
+                </para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                Hibernate‚Í‚±‚̏ꍇ‚É2”Ô–Ú‚Ì•û–@‚ª‚æ‚葬‚¢‚¾‚낤‚Æ‚í‚©‚é‚Ù‚ÇŒ«‚­‚Í‚ ‚è‚Ü‚¹‚ñB
+                i‚»‚µ‚ÄHibernate‚ª‚±‚̂悤‚ÉŒ«‚¢‚±‚Æ‚à–]‚Ü‚µ‚­‚È‚¢‚Å‚µ‚傤B‚±‚̂悤‚ȐU‚é•‘‚¢‚Í
+                ƒf[ƒ^ƒx[ƒX‚̃gƒŠƒK‚È‚Ç‚ð¬—‚³‚¹‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñBj
+            </para>
+
+            <para>
+                K‚¢‚É‚àAŒ³‚̃RƒŒƒNƒVƒ‡ƒ“‚ðŽÌ‚āi‚‚܂èŽQÆ‚ð‚â‚߂ājAŒ»Ý‚Ì—v‘f‚ð‚·‚×‚ÄŽ‚V‚µ‚¢ƒRƒŒƒNƒVƒ‡ƒ“‚Ì
+                ƒCƒ“ƒXƒ^ƒ“ƒX‚ð•Ô‚·‚±‚ƂŁA‚¢‚Â‚Å‚à‚±‚̐U‚é•‘‚¢i2”Ԗڂ̐헪j‚ð‹­§‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B
+                Žž‚É‚±‚ê‚Í‚Æ‚Ä‚à•Ö—˜‚Å‹­—Í‚Å‚·B
+            </para>
+            
+            <para>
+                ‚à‚¿‚ë‚ñAˆêŠ‡íœ‚Í <literal>inverse="true"</literal> ‚ðŽw’肵‚½ƒRƒŒƒNƒVƒ‡ƒ“‚ɂ͍s‚¢‚Ü‚¹‚ñB
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="performance-monitoring" revision="1">
+        <title>ƒpƒtƒH[ƒ}ƒ“ƒX‚̃‚ƒjƒ^ƒŠƒ“ƒO</title>
+
+        <para>
+            Å“K‰»‚̓‚ƒjƒ^ƒŠƒ“ƒO‚âƒpƒtƒH[ƒ}ƒ“ƒX‚ðŽ¦‚·”’l‚ª‚È‚¯‚ê‚Ώ\•ª‚ɍs‚¦‚Ü‚¹‚ñB
+            Hibernate‚Í“à•”ˆ—‚Ì‚·‚ׂĂ͈̔͂̐”’l‚ð’ñ‹Ÿ‚µ‚Ü‚·B
+            Hibernate‚Ì“Œvî•ñ‚Í <literal>SessionFactory</literal> ’PˆÊ‚Ŏ擾‰Â”\‚Å‚·B
+        </para>
+
+        <sect2 id="performance-monitoring-sf" revision="2">
+            <title>SessionFactory‚̃‚ƒjƒ^ƒŠƒ“ƒO</title>
+
+            <para>
+                <literal>SessionFactory</literal> ‚̃ƒgƒŠƒNƒX‚ɃAƒNƒZƒX‚·‚é‚É‚Í2‚‚̕û–@‚ª‚ ‚è‚Ü‚·B
+                Å‰‚Ì•û–@‚́A <literal>sessionFactory.getStatistics()</literal> ‚ðŒÄ‚яo‚µA
+                Ž©•ª‚Å <literal>Statistics</literal> ‚̓ǂݍž‚Ý‚â•\Ž¦‚ðs‚¢‚Ü‚·B
+            </para>
+
+            <para>
+                <literal>StatisticsService</literal> MBean‚ð—LŒø‚É‚µ‚Ä‚¢‚ê‚΁AHibernate‚ÍJMX‚ðŽg‚Á‚Ä
+                ƒƒgƒŠƒNƒX‚𔭍s‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B1‚‚ÌMBean‚ð‚·‚×‚Ä‚Ì <literal>SessionFactory</literal> 
+                ‚ɑ΂µ‚Ä—LŒø‚É‚·‚é‚©ASessionFactory‚²‚ƂɈê‚‚ÌMBean‚ð—LŒø‚É‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B
+                Å¬ŒÀ‚̐ݒè—á‚Å‚ ‚éˆÈ‰º‚̃R[ƒh‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <programlisting><![CDATA[// MBean service registration for a specific SessionFactory
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "myFinancialApp");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
+server.registerMBean(stats, on); // Register the Mbean on the server]]></programlisting>
+
+
+<programlisting><![CDATA[// MBean service registration for all SessionFactory's
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "all");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+server.registerMBean(stats, on); // Register the MBean on the server]]></programlisting>
+
+            <para>
+                TODO: ‚±‚ê‚͈Ӗ¡‚ª‚ ‚è‚Ü‚¹‚ñBÅ‰‚̃P[ƒX‚́AMBean‚𒼐ڕœŒ³‚µ‚ÄŽg—p‚µ‚Ü‚·B2”Ԗڂ̃P[ƒX‚́A
+                Žg‚¤‘O‚Ésession factory‚ªŽ‚Á‚Ä‚¢‚éJNDI–¼‚ð“n‚³‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                <literal>hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")</literal> ‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢B
+            </para>
+            <para>
+                <literal>SessionFactory</literal> ‚ɑ΂µ‚ă‚ƒjƒ^ƒŠƒ“ƒO‚ÌŠJŽniI—¹j‚ðs‚¤‚±‚Æ‚ªo—ˆ‚Ü‚·B
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        Ý’莞‚ɂ́A <literal>hibernate.generate_statistics</literal> ‚ð <literal>false</literal> ‚É‚µ‚Ü‚·
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        ŽÀsŽž‚ɁA <literal>sf.getStatistics().setStatisticsEnabled(true)</literal> ‚Ü‚½‚Í
+                         <literal>hibernateStatsBean.setStatisticsEnabled(true)</literal> ‚ðŒÄ‚яo‚µ‚Ü‚·
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                “Œv‚Í <literal>clear()</literal> ƒƒ\ƒbƒh‚ðŽg‚Á‚ÄŽè“®‚ŃŠƒZƒbƒg‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B
+                ƒTƒ}ƒŠ‚Í <literal>logSummary()</literal> ƒƒ\ƒbƒh‚ðŽg‚Á‚Älogger‚É‘—‚邱‚Æ‚ªo—ˆ‚Ü‚·
+                iinfoƒŒƒxƒ‹‚Å‚·jB
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-monitoring-metrics" revision="1">
+            <title>ƒƒgƒŠƒNƒX</title>
+
+            <para>
+                ‘½‚­‚Ì‚à‚Ì‚ª‚ ‚è‚Ü‚·B‚·‚ׂĂ̎g—p‰Â”\‚ȃJƒEƒ“ƒ^‚Í <literal>Statistics</literal> 
+                ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ÌAPI‚ɏ‘‚©‚ê‚Ä‚¨‚èA3‚‚̕ª—Þ‚ª‚ ‚è‚Ü‚·B
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        ƒƒgƒŠƒNƒX‚͈ê”Ê“I‚È <literal>Session</literal> ‚ÌŽg‚¢•û‚ÆŠÖŒW‚µ‚Ä‚¢‚Ü‚·B
+                        ƒI[ƒvƒ“‚µ‚½ƒZƒbƒVƒ‡ƒ“‚̐”‚ªJDBCƒRƒlƒNƒVƒ‡ƒ“‚ÆŠÖ˜A‚µ‚Ä‚¢‚é‚Ì‚Æ“¯‚¶‚Å‚·B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        ƒƒgƒŠƒNƒX‚Í—v‘fAƒRƒŒƒNƒVƒ‡ƒ“AƒNƒGƒŠ‚âƒLƒƒƒbƒVƒ…‚È‚Ç‘S‘Ì‚É
+                        ŠÖŒW‚µ‚Ä‚¢‚Ü‚·i•Ê–¼‚̓Oƒ[ƒoƒ‹ƒƒgƒŠƒNƒX‚Å‚·jB
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        ƒƒgƒŠƒNƒX‚̏ڍׂ͓Á’è‚̃Gƒ“ƒeƒBƒeƒBAƒRƒŒƒNƒVƒ‡ƒ“AƒNƒGƒŠAƒLƒƒƒbƒVƒ…—̈æ‚ÉŠÖŒW‚µ‚Ä‚¢‚Ü‚·B
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                —á‚Æ‚µ‚āAƒLƒƒƒbƒVƒ…‚̃qƒbƒgAƒqƒbƒgƒ~ƒX‚âA—v‘fAƒRƒŒƒNƒVƒ‡ƒ“AƒNƒGƒŠ‚ÌŠ„‡AƒNƒGƒŠ‚ÌŽÀs‚É
+                •K—v‚È•½‹ÏŽžŠÔ‚ðŠm”F‚Å‚«‚Ü‚·Bƒ~ƒŠ•b‚̐”’l‚ÍJava‚̋ߎ—‚ðŽó‚¯‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                Hibernate‚ÍJVM‚̐¸“x‚ɐ§ŒÀ‚³‚êAƒvƒ‰ƒbƒgƒtƒH[ƒ€‚É‚æ‚Á‚Ä‚Í10•b’PˆÊ‚Å‚µ‚©³Šm‚Å‚È‚¢‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+            </para>
+
+            <para>
+                ’Pƒ‚Ègetter‚̓Oƒ[ƒoƒ‹ƒƒgƒŠƒNƒXi‚·‚È‚í‚¿“Á’è‚̃Gƒ“ƒeƒBƒeƒBAƒRƒŒƒNƒVƒ‡ƒ“AƒLƒƒƒbƒVƒ…—̈æ‚È‚Ç‚É”›‚ç‚ê‚È‚¢j
+                ‚ɃAƒNƒZƒX‚·‚邽‚ß‚ÉŽg‚¢‚Ü‚·B“Á’è‚̃Gƒ“ƒeƒBƒeƒBAƒRƒŒƒNƒVƒ‡ƒ“AƒLƒƒƒbƒVƒ…—̈æ‚̃ƒgƒŠƒNƒX‚́A
+                ‚»‚ê‚ç‚Ì–¼‘O‚âAƒNƒGƒŠ‚ÌHQLASQL•\Œ»‚É‚æ‚Á‚ăAƒNƒZƒX‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B‚³‚ç‚ɏڂµ‚¢î•ñ‚́A
+                <literal>Statistics</literal> A <literal>EntityStatistics</literal> A <literal>CollectionStatistics</literal> 
+                A <literal>SecondLevelCacheStatistics</literal> A <literal>QueryStatistics</literal> API‚Ìjavadoc‚ð
+                ŽQÆ‚µ‚Ä‚­‚¾‚³‚¢BˆÈ‰º‚̃R[ƒh‚ÍŠÈ’P‚È—á‚Å‚·B
+            </para>
+
+            <programlisting><![CDATA[Statistics stats = HibernateUtil.sessionFactory.getStatistics();
+
+double queryCacheHitCount  = stats.getQueryCacheHitCount();
+double queryCacheMissCount = stats.getQueryCacheMissCount();
+double queryCacheHitRatio =
+  queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
+
+log.info("Query Hit ratio:" + queryCacheHitRatio);
+
+EntityStatistics entityStats =
+  stats.getEntityStatistics( Cat.class.getName() );
+long changes =
+        entityStats.getInsertCount()
+        + entityStats.getUpdateCount()
+        + entityStats.getDeleteCount();
+log.info(Cat.class.getName() + " changed " + changes + "times"  );]]></programlisting>
+
+            <para>
+                ‚·‚ׂẴGƒ“ƒeƒBƒeƒBAƒRƒŒƒNƒVƒ‡ƒ“AƒNƒGƒŠAƒLƒƒƒbƒVƒ…—̈æ‚ɑ΂µ‚čs‚¤ê‡‚́A
+                <literal>getQueries()</literal> A <literal>getEntityNames()</literal>A 
+                <literal>getCollectionRoleNames()</literal> A <literal>getSecondLevelCacheRegionNames()</literal> ƒƒ\ƒbƒh‚Å
+                ‚»‚ꂼ‚ê‚Ì–¼‘O‚̃ŠƒXƒg‚ðŽæ“¾‚·‚邱‚Æ‚ªo—ˆ‚Ü‚·B
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/persistent_classes.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/persistent_classes.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/persistent_classes.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,539 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="persistent-classes" revision="2">
+    <title>‰i‘±ƒNƒ‰ƒX</title>
+
+    <para>
+        ‰i‘±ƒNƒ‰ƒX‚̓rƒWƒlƒXã‚Ì–â‘è‚̃Gƒ“ƒeƒBƒeƒBi—Ⴆ‚΁AEƒRƒ}[ƒXƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̌ڋq‚⒍•¶j
+        ‚ðŽÀ‘•‚·‚éƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̃Nƒ‰ƒX‚Å‚·B
+        ‰i‘±ƒNƒ‰ƒX‚Ì‚·‚ׂẴCƒ“ƒXƒ^ƒ“ƒX‚ª‰i‘±ó‘Ô‚Å‚ ‚é‚ÆŒ©‚È‚³‚ê‚é‚킯‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+        ƒCƒ“ƒXƒ^ƒ“ƒX‚Í‹t‚Ɉꎞ“Iitransientj‚Å‚ ‚Á‚½‚èA•ª—£ó‘ԁidetachedj‚Å‚ ‚Á‚½‚è‚·‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+    </para>
+
+    <para>
+        Plain Old Java Object (POJO)ƒvƒƒOƒ‰ƒ~ƒ“ƒOƒ‚ƒfƒ‹‚Æ‚µ‚Ä‚à’m‚ç‚ê‚é
+        ‚¢‚­‚‚©‚Ì’Pƒ‚ȃ‹[ƒ‹‚ɏ]‚¤‚È‚çAHibernate‚͍łà‚æ‚­“­‚«‚Ü‚·B
+        ‚µ‚©‚µ‚±‚ê‚ç‚̃‹[ƒ‹‚͓‚¢‚à‚Ì‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+        ŽÀÛHibernate3‚͉i‘±ƒIƒuƒWƒFƒNƒg‚̐«Ž¿‚É‚Ù‚Æ‚ñ‚lj½‚Ì‘O’ñ‚à’u‚¢‚Ä‚¢‚Ü‚¹‚ñB
+        ƒhƒƒCƒ“ƒ‚ƒfƒ‹‚Í‘¼‚Ì•û–@‚Å•\Œ»‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+        —Ⴆ‚Î <literal>Map</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚̃cƒŠ[‚ðŽg‚¤•û–@‚ª‚ ‚è‚Ü‚·B
+    </para>
+
+    <sect1 id="persistent-classes-pojo">
+        <title>’Pƒ‚ÈPOJO‚Ì—á</title>
+
+        <para>
+            ‚Ù‚Æ‚ñ‚Ç‚ÌJavaƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ɂ̓lƒR‰È‚Ì“®•¨‚ð•\Œ»‚·‚é‰i‘±ƒNƒ‰ƒX‚ª•K—v‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+public class Cat {
+    private Long id; // identifier
+
+    private Date birthdate;
+    private Color color;
+    private char sex;
+    private float weight;
+    private int litterId;
+
+    private Cat mother;
+    private Set kittens = new HashSet();
+
+    private void setId(Long id) {
+        this.id=id;
+    }
+    public Long getId() {
+        return id;
+    }
+
+    void setBirthdate(Date date) {
+        birthdate = date;
+    }
+    public Date getBirthdate() {
+        return birthdate;
+    }
+
+    void setWeight(float weight) {
+        this.weight = weight;
+    }
+    public float getWeight() {
+        return weight;
+    }
+
+    public Color getColor() {
+        return color;
+    }
+    void setColor(Color color) {
+        this.color = color;
+    }
+
+    void setSex(char sex) {
+        this.sex=sex;
+    }
+    public char getSex() {
+        return sex;
+    }
+
+    void setLitterId(int id) {
+        this.litterId = id;
+    }
+    public int getLitterId() {
+        return litterId;
+    }
+
+    void setMother(Cat mother) {
+        this.mother = mother;
+    }
+    public Cat getMother() {
+        return mother;
+    }
+    void setKittens(Set kittens) {
+        this.kittens = kittens;
+    }
+    public Set getKittens() {
+        return kittens;
+    }
+    
+    // addKitten not needed by Hibernate
+    public void addKitten(Cat kitten) {
+        kitten.setMother(this);
+        kitten.setLitterId( kittens.size() ); 
+        kittens.add(kitten);
+    }
+}]]></programlisting>
+
+        <para>
+            ]‚¤‚ׂ«4‚‚̃‹[ƒ‹‚ª‚ ‚è‚Ü‚·F
+        </para>
+        
+        <sect2 id="persistent-classes-pojo-constructor" revision="1">
+            <title>ˆø”‚Ì‚È‚¢ƒRƒ“ƒXƒgƒ‰ƒNƒ^‚ðŽÀ‘•‚·‚é</title>
+
+            <para>
+                <literal>Cat</literal> ‚ɂ͈ø”‚Ì‚È‚¢ƒRƒ“ƒXƒgƒ‰ƒNƒ^‚ª‚ ‚è‚Ü‚·B
+                Hibernate‚ª <literal>Constructor.newInstance()</literal> ‚ðŽg‚Á‚ĉi‘±ƒNƒ‰ƒX‚Ì
+                ƒCƒ“ƒXƒ^ƒ“ƒX‰»‚ðs‚¦‚é‚悤‚ɁA‚·‚ׂẲi‘±ƒNƒ‰ƒX‚ɂ̓fƒtƒHƒ‹ƒgƒRƒ“ƒXƒgƒ‰ƒNƒ^
+                ipublic‚Å‚È‚­‚Ä‚à\‚¢‚Ü‚¹‚ñj‚ª‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                Hibernate‚ÌŽÀsŽžƒvƒƒLƒV¶¬‚Ì‚½‚߂ɁA­‚È‚­‚Æ‚à <emphasis>package</emphasis> 
+                ‚̉Ž‹«‚ðŽ‚ÂƒfƒtƒHƒ‹ƒgƒRƒ“ƒXƒgƒ‰ƒNƒ^‚ð‹­‚­‚¨Š©‚ß‚µ‚Ü‚·B
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-identifier" revision="2">
+            <title>Ž¯•ÊŽqƒvƒƒpƒeƒB‚ð—pˆÓ‚·‚éiƒIƒvƒVƒ‡ƒ“j</title>
+
+            <para>
+                <literal>Cat</literal> ‚É‚Í <literal>id</literal> ‚Æ‚¢‚¤ƒvƒƒpƒeƒB‚ª‚ ‚è‚Ü‚·B
+                ‚±‚̃vƒƒpƒeƒB‚̓f[ƒ^ƒx[ƒXƒe[ƒuƒ‹‚ÌŽåƒL[ƒJƒ‰ƒ€‚Öƒ}ƒbƒsƒ“ƒO‚³‚ê‚Ü‚·B
+                ‚±‚̃vƒƒpƒeƒB‚Ì–¼‘O‚͉½‚Å‚à\‚¢‚Ü‚¹‚ñ‚µAŒ^‚͂ǂ̂悤‚ȃvƒŠƒ~ƒeƒBƒuŒ^‚Å‚àA
+                ƒvƒŠƒ~ƒeƒBƒu‚́uƒ‰ƒbƒp[vŒ^‚Å‚àA<literal>java.lang.String</literal> ‚â 
+                <literal>java.util.Date</literal> ‚Å‚à\‚¢‚Ü‚¹‚ñB
+                i‚à‚µƒŒƒKƒV[ƒf[ƒ^ƒx[ƒXƒe[ƒuƒ‹‚ª•¡‡ƒL[‚ðŽ‚Â‚È‚ç‚΁A
+                ¡q‚ׂ½‚悤‚ÈŒ^‚̃vƒƒpƒeƒB‚ðŽ‚Âƒ†[ƒU’è‹`‚̃Nƒ‰ƒX‚ðŽg‚¤‚±‚Æ‚³‚¦‰Â”\‚Å‚·B
+                Œã‚Å•¡‡Ž¯•ÊŽq‚Ìß‚ðŒ©‚Ä‚­‚¾‚³‚¢Bj
+            </para>
+
+            <para>
+                Ž¯•ÊŽqƒvƒƒpƒeƒB‚ÍŒµ–§‚ɂ̓IƒvƒVƒ‡ƒ“‚Å‚·B
+                ‚±‚ê‚ðÈ—ª‚µ‚āAHibernate‚É“à•”“I‚ɃIƒuƒWƒFƒNƒg‚ÌŽ¯•ÊŽq‚ð’ǐՂ³‚¹‚邱‚Ƃ͉”\‚Å‚·B
+                ‚µ‚©‚µ‚¨‚·‚·‚ß‚Í‚µ‚Ü‚¹‚ñB
+            </para>
+
+            <para>
+                ŽÀÛ‚ɁAŽ¯•ÊŽqƒvƒƒpƒeƒB‚ðéŒ¾‚·‚éƒNƒ‰ƒX‚¾‚¯‚ª—˜—p‰Â”\‚È‹@”\‚ª‚¢‚­‚‚©‚ ‚è‚Ü‚·F
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        •ª—£ƒIƒuƒWƒFƒNƒg‚̘A½“I‚ȍĒljÁiƒJƒXƒP[ƒhXV‚âƒJƒXƒP[ƒhƒ}[ƒWjB
+                         <xref linkend="objectstate-transitive"/> ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session.saveOrUpdate()</literal>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session.merge()</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                ‰i‘±ƒNƒ‰ƒX‚ɂ́AˆêŠÑ‚µ‚½–¼‘O‚ÌŽ¯•ÊŽqƒvƒƒpƒeƒB‚ð’è‹`‚·‚邱‚Æ‚ð‚¨Š©‚ß‚µ‚Ü‚·B
+                ‚³‚ç‚Énull’l‚ðŽæ‚ê‚é(‚‚܂èƒvƒŠƒ~ƒeƒBƒu‚Å‚Í‚È‚¢)Œ^‚ðŽg‚Á‚½•û‚ª‚æ‚¢‚Å‚µ‚傤B
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-final">
+            <title>finalƒNƒ‰ƒX‚É‚µ‚È‚¢iƒIƒvƒVƒ‡ƒ“j</title>
+            <para>
+                Hibernate‚Ì’†S“I‚È“Á’¥‚Å‚ ‚é <emphasis>ƒvƒƒLƒV</emphasis> ‚́A
+                ‰i‘±ƒNƒ‰ƒX‚ªfinal‚Å‚È‚¢‚±‚ƁA‚Ü‚½‚̓ƒ\ƒbƒh‚ð‘S•”public‚Ő錾‚µ‚Ä‚¢‚é
+                ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ªŽÀ‘•‚³‚ê‚Ä‚¢‚é‚©‚Ɉˑ¶‚µ‚Ä‚¢‚Ü‚·B
+            </para>
+            <para>
+                Hibernate‚ŃCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽÀ‘•‚µ‚Ä‚¢‚È‚¢ <literal>final</literal> ƒNƒ‰ƒX‚ð‰i‘±‰»‚·‚邱‚Æ‚Í‚Å‚«‚Ü‚·‚ªA
+                ’x‰„ŠÖ˜AƒtƒFƒbƒ`‚ɑ΂µ‚ăvƒƒLƒV‚ðŽg‚¤‚±‚Æ‚Í‚Å‚«‚È‚­‚È‚è‚Ü‚·B
+                ‚±‚ê‚̓pƒtƒH[ƒ}ƒ“ƒXƒ`ƒ…[ƒjƒ“ƒO‚Ö‚Ì‘I‘ðŽˆ‚ð‹·‚ß‚é‚±‚Æ‚É‚È‚è‚Ü‚·B
+            </para>
+            <para>
+                final‚Å‚Í‚È‚¢ƒNƒ‰ƒX‚Å <literal>public final</literal> ƒƒ\ƒbƒh‚ð’è‹`‚·‚邱‚Æ‚à”ð‚¯‚é‚ׂ«‚Å‚·B
+                <literal>public final</literal> ƒƒ\ƒbƒh‚ðŽ‚ÂƒNƒ‰ƒX‚ðŽg‚¢‚½‚¯‚ê‚΁A
+                <literal>lazy="false"</literal> ‚Ɛݒ肵‚Ä–¾Ž¦“I‚ɃvƒƒLƒV‚𖳌ø‚É‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-accessors" revision="2">
+            <title>‰i‘±ƒtƒB[ƒ‹ƒh‚ɑ΂·‚éƒAƒNƒZƒT‚ƃ~ƒ…[ƒe[ƒ^‚ð’è‹`‚·‚éiƒIƒvƒVƒ‡ƒ“j</title>
+
+            <para>
+                <literal>Cat</literal> ‚Å‚Í‚·‚ׂẲi‘±ƒtƒB[ƒ‹ƒh‚ɑ΂µ‚ăAƒNƒZƒTƒƒ\ƒbƒh‚ð’è‹`‚µ‚Ä‚¢‚Ü‚·B
+                ‘¼‚Ì‘½‚­‚ÌORMƒc[ƒ‹‚́A‰i‘±ƒCƒ“ƒXƒ^ƒ“ƒX•Ï”‚𒼐ډi‘±‰»‚µ‚Ü‚·B
+                Ž„‚½‚¿‚̓ŠƒŒ[ƒVƒ‡ƒiƒ‹ƒXƒL[ƒ}‚ƃNƒ‰ƒX‚Ì“à•”\‘¢‚𕪗£‚·‚é•û‚ª—Ç‚¢‚ƐM‚¶‚Ä‚¢‚Ü‚·B
+                ƒfƒtƒHƒ‹ƒg‚ł́AHibernate‚ÍJavaBeanƒXƒ^ƒCƒ‹‚̃vƒƒpƒeƒB‚ð‰i‘±‰»‚µA
+                <literal>getFoo</literal>, <literal>isFoo</literal>, <literal>setFoo</literal> 
+                Œ`Ž®‚̃ƒ\ƒbƒh–¼‚ð”FŽ¯‚µ‚Ü‚·B
+                ‚µ‚©‚µ•K—v‚È‚çA“Á’è‚̃vƒƒpƒeƒB‚ɑ΂µ‚āA’¼Ú‚̃tƒB[ƒ‹ƒhƒAƒNƒZƒX‚ɐ؂è‘Ö‚¦‚邱‚Ƃ͉”\‚Å‚·B
+            </para>
+
+            <para>
+                ƒvƒƒpƒeƒB‚Ípublic‚Ő錾‚·‚é•K—v‚Í <emphasis>‚ ‚è‚Ü‚¹‚ñ</emphasis> B
+                Hibernate‚̓fƒtƒHƒ‹ƒgA<literal>protected</literal> ‚à‚µ‚­‚Í <literal>private</literal> 
+                ‚Ìget / set‚̃yƒA‚ðŽ‚ÂƒvƒƒpƒeƒB‚ð‰i‘±‰»‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-inheritance">
+        <title>Œp³‚ÌŽÀ‘•</title>
+
+        <para>
+            ƒTƒuƒNƒ‰ƒX‚à1”Ô–Ú‚Æ2”Ԗڂ̃‹[ƒ‹‚ðŽç‚ç‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            ƒTƒuƒNƒ‰ƒX‚̓X[ƒp[ƒNƒ‰ƒX <literal>Cat</literal> ‚©‚环•ÊŽqƒvƒƒpƒeƒB‚ðŒp³‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+public class DomesticCat extends Cat {
+        private String name;
+
+        public String getName() {
+                return name;
+        }
+        protected void setName(String name) {
+                this.name=name;
+        }
+}]]></programlisting>
+    </sect1>
+
+    <sect1 id="persistent-classes-equalshashcode" revision="1">
+        <title><literal>equals()</literal> ‚Æ <literal>hashCode()</literal> ‚ÌŽÀ‘•</title>
+
+        <para>
+            ˆÈ‰º‚ÌðŒ‚Ìê‡A
+            <literal>equals()</literal> ‚Æ <literal>hashCode()</literal> ƒƒ\ƒbƒh‚ðƒI[ƒo[ƒ‰ƒCƒh‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñA
+        </para>
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    ‰i‘±ƒNƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ð <literal>Set</literal> ‚É’u‚­ê‡B
+                    i‚±‚ê‚Í‘½’l‚ÌŠÖ˜A‚ð•\Œ»‚·‚邨‚·‚·‚ß‚Ì•û–@‚Å‚·j
+                    <emphasis>‚»‚µ‚Ä“¯Žž‚É</emphasis>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    •ª—£ƒCƒ“ƒXƒ^ƒ“ƒX‚ðƒZƒbƒVƒ‡ƒ“‚֍ĒljÁ‚·‚éê‡B
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Hibernate‚́A‰i‘±IDiƒf[ƒ^ƒx[ƒX‚̍sj‚ƁA“Á’è‚̃ZƒbƒVƒ‡ƒ“ƒXƒR[ƒv“à‚É
+            ŒÀ’è‚Å‚·‚ªJavaID‚Æ‚ª“™‰¿‚Å‚ ‚邱‚Æ‚ð•ÛØ‚µ‚Ü‚·B
+            ‚Å‚·‚©‚çˆÙ‚È‚éƒZƒbƒVƒ‡ƒ“‚ÅŒŸõ‚µ‚½ƒCƒ“ƒXƒ^ƒ“ƒX‚ð‘g‚ݍ‡‚킹‚éê‡A
+            <literal>Set</literal> ‚ɈӖ¡‚Ì‚ ‚éƒZƒ}ƒ“ƒeƒBƒNƒX‚ðŽ‚½‚¹‚悤‚ÆŽv‚Á‚Ä‚¢‚é‚È‚ç
+            ‚·‚®‚É<literal>equals()</literal> ‚Æ <literal>hashCode()</literal> 
+            ‚ðŽÀ‘•‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+        </para>
+
+        <para>
+            Å‚à–¾”’‚È•û–@‚́A—¼•û‚̃IƒuƒWƒFƒNƒg‚ÌŽ¯•ÊŽq‚Ì’l‚Ì”äŠr‚É‚æ‚Á‚Ä <literal>equals()</literal>‚Æ
+            <literal>hashCode()</literal> ‚ðŽÀ‘•‚·‚é•û–@‚Å‚·B
+            ’l‚ª“¯‚¶‚È‚çA—¼ŽÒ‚̓f[ƒ^ƒx[ƒX‚Ì“¯‚¶s‚Å‚È‚¯‚ê‚΂Ȃç‚È‚¢‚½‚ß“™‚µ‚­‚È‚è‚Ü‚·B
+            i—¼ŽÒ‚ª <literal>Set</literal> ‚ɒljÁ‚³‚ê‚Ä‚àA
+            <literal>Set</literal> ‚É‚Í1ŒÂ‚Ì—v‘f‚µ‚©‚È‚¢‚±‚Æ‚É‚È‚è‚Ü‚·j
+            Žc”O‚È‚±‚ƂɁA¶¬‚³‚ꂽŽ¯•ÊŽq‚É‚Í‚±‚̃Aƒvƒ[ƒ`‚ðŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚¹‚ñB
+            Hibernate‚͉i‘±‰»‚³‚ꂽƒIƒuƒWƒFƒNƒg‚ÖŽ¯•ÊŽq‚Ì’l‚ð‘ã“ü‚·‚邾‚¯‚Å‚ ‚èA
+            V‚µ‚­ì¬‚³‚ꂽƒCƒ“ƒXƒ^ƒ“ƒX‚͂ǂ̂悤‚ÈŽ¯•ÊŽq‚Ì’l‚àŽ‚Á‚Ä‚¢‚Ü‚¹‚ñB
+            ‚³‚ç‚ɁAƒCƒ“ƒXƒ^ƒ“ƒX‚ªƒZ[ƒu‚³‚ê‚Ä‚¨‚炸AŒ»Ý <literal>Set</literal> ‚Ì’†‚É‚ ‚ê‚΁A
+            ƒZ[ƒu‚·‚é‚ƃIƒuƒWƒFƒNƒg‚ÖŽ¯•ÊŽq‚Ì’l‚ð‘ã“ü‚·‚邱‚Æ‚É‚È‚è‚Ü‚·B
+            ‚à‚µ <literal>equals()</literal> ‚Æ <literal>hashCode()</literal> ‚ªŽ¯•ÊŽq‚Ì’l‚ÉŠî‚¢‚Ä‚¢‚é‚È‚çA
+            ƒnƒbƒVƒ…ƒR[ƒh‚ª•ÏX‚³‚ê‚é‚Æ <literal>Set</literal> ‚Ì‹K–ñ‚ª”j‚ç‚ê‚Ü‚·B
+            ‚±‚Ì–â‘è‚ɂ‚¢‚Ä‚ÌŠ®‘S‚È‹c˜_‚́AHibernate‚̃EƒFƒuƒTƒCƒg‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+            ‚±‚ê‚ÍHibernate‚Ì–â‘è‚Å‚Í‚È‚­AƒIƒuƒWƒFƒNƒg‚Ì“¯ˆê«‚Æ“™‰¿«‚ɂ‚¢‚ẮA
+            ’ʏí‚ÌJava‚̃Zƒ}ƒ“ƒeƒBƒNƒX‚Å‚ ‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <para>
+            <emphasis>ƒrƒWƒlƒXƒL[‚Ì“™‰¿«</emphasis> ‚ðŽg‚Á‚āA
+            <literal>equals()</literal> ‚Æ <literal>hashCode()</literal> ‚ðŽÀ‘•‚·‚邱‚Æ‚ð‚¨Š©‚ß‚µ‚Ü‚·B
+            ƒrƒWƒlƒXƒL[‚Ì“™‰¿«‚Ƃ́A<literal>equals()</literal> ƒƒ\ƒbƒh‚ªAƒrƒWƒlƒXƒL[A
+            ‚‚܂茻ŽÀ‚̐¢ŠE‚É‚¨‚¢‚ăCƒ“ƒXƒ^ƒ“ƒX‚ð“Á’è‚·‚éƒL[i<emphasis>Ž©‘R</emphasis> Œó•âƒL[j
+            ‚ðŒ`¬‚·‚éƒvƒƒpƒeƒB‚¾‚¯‚ð”äŠr‚·‚邱‚Æ‚ðˆÓ–¡‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[public class Cat {
+
+    ...
+    public boolean equals(Object other) {
+        if (this == other) return true;
+        if ( !(other instanceof Cat) ) return false;
+
+        final Cat cat = (Cat) other;
+
+        if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
+        if ( !cat.getMother().equals( getMother() ) ) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result;
+        result = getMother().hashCode();
+        result = 29 * result + getLitterId();
+        return result;
+    }
+
+}]]></programlisting>
+
+        <para>
+            ƒrƒWƒlƒXƒL[‚̓f[ƒ^ƒx[ƒX‚ÌŽåƒL[Œó•â‚قLjÀ’è‚Å‚ ‚é•K—v‚Í‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢
+            i<xref linkend="transactions-basics-identity"/> ‚ðŒ©‚Ä‚­‚¾‚³‚¢jB
+            XV•s‰Â‚ȃvƒƒpƒeƒB‚⃆ƒj[ƒN‚ȃvƒƒpƒeƒB‚́A’ʏíƒrƒWƒlƒXƒL[‚Ì‚æ‚¢Œó•â‚Å‚·B
+        </para>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-dynamicmodels">
+        <title>“®“Iƒ‚ƒfƒ‹</title>
+
+        <para>
+            <emphasis>ˆÈ‰º‚Ì‹@”\‚ÍŒ»ÝŽÀŒ±’iŠK‚É‚ ‚é‚ÆŒ©‚È‚³‚ê‚Ä‚¨‚èA
+            ‹ß‚¢«—ˆ•ÏX‚³‚ê‚é‰Â”\«‚ª‚ ‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B</emphasis>
+        </para>
+
+        <para>
+            ‰i‘±ƒGƒ“ƒeƒBƒeƒB‚́A•K‚¸‚µ‚àŽÀsŽž‚ÉPOJOƒNƒ‰ƒX‚âJavaBeanƒIƒuƒWƒFƒNƒg‚Å•\Œ»‚·‚é•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+            Hibernate‚́iŽÀsŽž‚É <literal>Map</literal> ‚Ì <literal>Map</literal> ‚ðŽg‚¤j“®“Iƒ‚ƒfƒ‹‚ƁA
+            DOM4JƒcƒŠ[‚Æ‚µ‚ẴGƒ“ƒeƒBƒeƒB‚Ì•\Œ»‚àƒTƒ|[ƒg‚µ‚Ü‚·B
+            ‚±‚̃Aƒvƒ[ƒ`‚ðŽg‚¤‚Ɖi‘±ƒNƒ‰ƒX‚ð‘‚©‚¸Aƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚¾‚¯‚ð‘‚­‚±‚Æ‚É‚È‚è‚Ü‚·B
+        </para>
+
+        <para>
+            ƒfƒtƒHƒ‹ƒg‚ł́AHibernate‚͒ʏí‚ÌPOJOƒ‚[ƒh‚Å“®ì‚µ‚Ü‚·B
+            <literal>default_entity_mode</literal> Ý’èƒIƒvƒVƒ‡ƒ“‚ðŽg‚Á‚āA
+            “Á’è‚Ì <literal>SessionFactory</literal> ‚ɑ΂·‚éƒfƒtƒHƒ‹ƒg‚̃Gƒ“ƒeƒBƒeƒB•\Œ»ƒ‚[ƒh‚ðÝ’è‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·
+            i<xref linkend="configuration-optional-properties"/> ‚ðŒ©‚Ä‚­‚¾‚³‚¢jB
+        </para>
+
+        <para>
+            ˆÈ‰º‚Ì—á‚Å‚Í <literal>Map</literal> ‚ðŽg‚Á‚½•\Œ»‚ðÐ‰î‚µ‚Ü‚·B
+            ‚Ü‚¸ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ŁAƒNƒ‰ƒX–¼‚Ì‘ã‚í‚è‚Ɂi‚Ü‚½‚Í‚»‚ê‚ɉÁ‚¦‚āj
+            <literal>entity-name</literal> ‚ð’è‹`‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñF
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class entity-name="Customer">
+
+        <id name="id"
+            type="long"
+            column="ID">
+            <generator class="sequence"/>
+        </id>
+
+        <property name="name"
+            column="NAME"
+            type="string"/>
+
+        <property name="address"
+            column="ADDRESS"
+            type="string"/>
+
+        <many-to-one name="organization"
+            column="ORGANIZATION_ID"
+            class="Organization"/>
+
+        <bag name="orders"
+            inverse="true"
+            lazy="false"
+            cascade="all">
+            <key column="CUSTOMER_ID"/>
+            <one-to-many class="Order"/>
+        </bag>
+
+    </class>
+    
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            ŠÖ˜A‚ªƒ^[ƒQƒbƒg‚̃Nƒ‰ƒX–¼‚ðŽg‚Á‚Ä’è‹`‚µ‚Ä‚¢‚½‚Æ‚µ‚Ä‚àA
+            ŠÖ˜A‚̃^[ƒQƒbƒgŒ^‚àPOJO‚Å‚Í‚È‚­“®“I‚ȃGƒ“ƒeƒBƒeƒB‚Å‚à\‚í‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <para>
+            <literal>SessionFactory</literal> ‚ɑ΂µ‚ăfƒtƒHƒ‹ƒg‚̃Gƒ“ƒeƒBƒeƒBƒ‚[ƒh‚ð 
+            <literal>dynamic-map</literal> ‚ɐݒ肵‚½ŒãA
+            ŽÀsŽž‚É <literal>Map</literal> ‚Ì <literal>Map</literal> ‚ðŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·F
+        </para>
+
+        <programlisting><![CDATA[Session s = openSession();
+Transaction tx = s.beginTransaction();
+Session s = openSession();
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+
+// Create an organization
+Map foobar = new HashMap();
+foobar.put("name", "Foobar Inc.");
+
+// Link both
+david.put("organization", foobar);
+
+// Save both
+s.save("Customer", david);
+s.save("Organization", foobar);
+
+tx.commit();
+s.close();]]></programlisting>
+
+        <para>
+            “®“I‚ȃ}ƒbƒsƒ“ƒO‚Ì—˜“_‚́AƒGƒ“ƒeƒBƒeƒBƒNƒ‰ƒX‚ÌŽÀ‘•‚ð•K—v‚Æ‚µ‚È‚¢‚½‚߁A
+            ƒvƒƒgƒ^ƒCƒsƒ“ƒO‚É—v‚·‚éƒ^[ƒ“ƒAƒ‰ƒEƒ“ƒhƒ^ƒCƒ€‚ª‘‚¢‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+            ‚µ‚©‚µƒRƒ“ƒpƒCƒ‹Žž‚ÌŒ^ƒ`ƒFƒbƒN‚ª‚È‚¢‚̂ŁAŽÀsŽž‚É”ñí‚É‘½‚­‚Ì—áŠOˆ—‚ðˆµ‚í‚È‚¯‚ê‚΂Ȃç‚È‚¢‚Å‚µ‚傤B
+            Hibernateƒ}ƒbƒsƒ“ƒO‚Ì‚¨‚©‚°‚ŁAƒf[ƒ^ƒx[ƒXƒXƒL[ƒ}‚Í—eˆÕ‚ɐ³‹K‰»‚Å‚«AŒ’‘S‚É‚È‚èA
+            Œã‚Å“KØ‚ȃhƒƒCƒ“ƒ‚ƒfƒ‹‚ÌŽÀ‘•‚ð’ljÁ‚·‚邱‚Æ‚ª‰Â”\‚É‚È‚è‚Ü‚·B
+        </para>
+
+        <para>
+            ƒGƒ“ƒeƒBƒeƒB•\Œ»ƒ‚[ƒh‚Í <literal>Session</literal> ‚²‚Ƃɐݒ肷‚邱‚Æ‚à‰Â”\‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+dynamicSession.save("Customer", david);
+...
+dynamicSession.flush();
+dynamicSession.close()
+...
+// Continue on pojoSession
+]]></programlisting>
+
+
+        <para>
+            <literal>EntityMode</literal> ‚ðŽg‚Á‚½ <literal>getSession()</literal> 
+            ‚̌Ăяo‚µ‚Í <literal>SessionFactory</literal> ‚Å‚Í‚È‚­ <literal>Session</literal> 
+            API‚É‚ ‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚»‚Ì•û–@‚ł́AV‚µ‚¢ <literal>Session</literal> ‚́Aƒx[ƒX‚Æ‚È‚éJDBCƒRƒlƒNƒVƒ‡ƒ“A
+            ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“A‚»‚Ì‘¼‚̃Rƒ“ƒeƒLƒXƒgî•ñ‚ð‹¤—L‚µ‚Ü‚·B
+            ‚±‚ê‚Í2”Ô–Ú‚Ì <literal>Session</literal> ‚Å‚Í <literal>flush()</literal> ‚Æ <literal>close()</literal> 
+            ‚ðŒÄ‚Ô•K—v‚ª‚È‚¢‚Æ‚¢‚¤‚±‚ƁA‚»‚Ì‚½‚߃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ƃRƒlƒNƒVƒ‡ƒ“‚ÌŠÇ—‚ð
+            1”Ԗڂ̍ì‹Æ’PˆÊ(Unit of Work)‚É”C‚¹‚邱‚Æ‚ª‚Å‚«‚é‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+        </para>
+
+        <para>
+            XML•\Œ»‚Ì”\—͂ɂ‚¢‚Ä‚Ì‚³‚ç‚È‚éî•ñ‚Í <xref linkend="xml"/> ‚ÅŒ©‚‚©‚è‚Ü‚·B
+        </para>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-tuplizers" revision="1">
+        <title>Tuplizer</title>
+
+        <para>
+            <literal>org.hibernate.tuple.Tuplizer</literal> ‚Æ‚»‚̃TƒuƒCƒ“ƒ^[ƒtƒFƒCƒX‚́A
+            •\Œ»‚Ì <literal>org.hibernate.EntityMode</literal> ‚ð—˜—p‚µ‚āA
+            ƒf[ƒ^’f•Ð‚Ì‚ ‚é•\Œ»‚ÌŠÇ—‚ɐӔC‚ðŽ‚¿‚Ü‚·B
+            —^‚¦‚ç‚ꂽƒf[ƒ^’f•Ð‚ðƒf[ƒ^\‘¢‚Æ‚µ‚čl‚¦‚é‚È‚çATuplizer‚Í‚»‚̂悤‚ȃf[ƒ^\‘¢‚ð
+            ‚ǂ̂悤‚ɍ쐬‚·‚é‚©‚ð’m‚èA‚»‚̂悤‚ȃf[ƒ^\‘¢‚©‚ç‚ǂ̂悤‚É’l‚𒊏o‚µA
+            ’“ü‚·‚é‚©‚ð’m‚Á‚Ä‚¢‚Ü‚·B
+            —Ⴆ‚ÎPOJOƒGƒ“ƒeƒBƒeƒBƒ‚[ƒh‚ł́A‘Ήž‚·‚éTuplizer‚̓Rƒ“ƒXƒgƒ‰ƒNƒ^‚ð’Ê‚µ‚āA
+            POJO‚ð‚ǂ̂悤‚ɍ쐬‚·‚é‚©A’è‹`‚³‚ꂽƒvƒƒpƒeƒBƒAƒNƒZƒT‚ðŽg‚¢A
+            POJOƒvƒƒpƒeƒB‚ɂǂ̂悤‚ɃAƒNƒZƒX‚·‚é‚©‚ð’m‚è‚Ü‚·B
+            Tuplizer‚É‚Í“ñ‚‚̃nƒCƒŒƒxƒ‹‚ÌŒ^‚ª‚ ‚è‚Ü‚·B
+            ‚»‚ê‚ç‚́A<literal>org.hibernate.tuple.EntityTuplizer</literal> ‚Æ 
+            <literal>org.hibernate.tuple.ComponentTuplizer</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚Å•\Œ»‚³‚ê‚Ü‚·B
+            <literal>EntityTuplizer</literal> ‚͏ã‚ŏq‚ׂ½‚悤‚ȃGƒ“ƒeƒBƒeƒB‚ÉŠÖ‚·‚éŒ_–ñ‚ÌŠÇ—‚ɐӔC‚ðŽ‚¿‚Ü‚·B
+            ˆê•ûA<literal>ComponentTuplizer</literal> ‚̓Rƒ“ƒ|[ƒlƒ“ƒg‚ÉŠÖ‚·‚éŒ_–ñ‚ÌŠÇ—‚ɐӔC‚ðŽ‚¿‚Ü‚·B
+        </para>
+
+        <para>
+            ƒ†[ƒU‚Í“ÆŽ©‚ÌTuplizer‚ɍ·‚µ‘Ö‚¦‚邱‚Æ‚à‰Â”\‚Å‚·B
+            ‚¨‚»‚ç‚­dynamic-map entity-mode‚ÌÛ‚É <literal>java.util.HashMap</literal> ‚ðŽg‚¤‚Ì‚Å‚Í‚È‚­A
+            <literal>java.util.Map</literal> ‚ÌŽÀ‘•‚ª•K—v‚Å‚µ‚傤B
+            ‚à‚µ‚­‚́A‚¨‚»‚ç‚­ƒfƒtƒHƒ‹ƒg‚Ì‚à‚Ì‚Å‚Í‚È‚­A•Ê‚̃vƒƒLƒV¶¬í—ª‚Ì’è‹`‚ª•K—v‚Å‚µ‚傤B
+            —¼ŽÒ‚Æ‚àAƒJƒXƒ^ƒ€‚ÌTuplizerŽÀ‘•‚ð’è‹`‚·‚邱‚Æ‚Å’B¬‚³‚ê‚Ü‚·B
+            Tuplizer‚Ì’è‹`‚́AŠÇ—‚µ‚悤‚Æ‚·‚éƒGƒ“ƒeƒBƒeƒB‚âƒRƒ“ƒ|[ƒlƒ“ƒg‚̃}ƒbƒsƒ“ƒO‚ÉŒ‹‚Ñ•t‚¯‚ç‚ê‚Ü‚·B
+            ŒÚ‹qƒGƒ“ƒeƒBƒeƒB‚Ì—á‚É–ß‚é‚ƁF
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+    <class entity-name="Customer">
+        <!--
+            Override the dynamic-map entity-mode
+            tuplizer for the customer entity
+        -->
+        <tuplizer entity-mode="dynamic-map"
+                class="CustomMapTuplizerImpl"/>
+
+        <id name="id" type="long" column="ID">
+            <generator class="sequence"/>
+        </id>
+
+        <!-- other properties -->
+        ...
+    </class>
+</hibernate-mapping>
+
+
+public class CustomMapTuplizerImpl
+        extends org.hibernate.tuple.entity.DynamicMapEntityTuplizer {
+    // override the buildInstantiator() method to plug in our custom map...
+    protected final Instantiator buildInstantiator(
+            org.hibernate.mapping.PersistentClass mappingInfo) {
+        return new CustomMapInstantiator( mappingInfo );
+    }
+
+    private static final class CustomMapInstantiator
+            extends org.hibernate.tuple.DynamicMapInstantitor {
+        // override the generateMap() method to return our custom map...
+        protected final Map generateMap() {
+            return new CustomMap();
+        }
+    }
+}]]></programlisting>
+
+
+    </sect1>
+
+    <para>
+        TODO: ƒvƒƒpƒeƒB‚ƃvƒƒLƒVƒpƒbƒP[ƒW‚̃†[ƒUŠg’£ƒtƒŒ[ƒ€ƒ[ƒN‚𕶏‘‰»‚·‚邱‚Æ
+    </para>
+
+</chapter>
+
+

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/query_criteria.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/query_criteria.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/query_criteria.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,448 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="querycriteria">
+    <title>CriteriaƒNƒGƒŠ</title>
+
+    <para>
+        Hibernate‚ɂ́A’¼Š´“I‚ÅŠg’£‰Â”\‚ÈcriteriaƒNƒGƒŠAPI‚ª—pˆÓ‚³‚ê‚Ä‚¢‚Ü‚·B
+    </para>
+    
+    <sect1 id="querycriteria-creating">
+        <title> <literal>Criteria</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚̍쐬</title>
+
+        <para>
+            <literal>org.hibernate.Criteria</literal>
+            ƒCƒ“ƒ^[ƒtƒFƒCƒX‚Í“Á’è‚̉i‘±«ƒNƒ‰ƒX‚ɑ΂·‚éƒNƒGƒŠ‚ð•\Œ»‚µ‚Ü‚·B
+            <literal>Session</literal> ‚Í <literal>Criteria</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚̃tƒ@ƒNƒgƒŠ‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
+crit.setMaxResults(50);
+List cats = crit.list();]]></programlisting>
+
+    </sect1>
+     
+    <sect1 id="querycriteria-narrowing">
+        <title>ƒŠƒUƒ‹ƒgƒZƒbƒg‚̍iž‚Ý</title>
+
+        <para>
+            <literal>org.hibernate.criterion.Criterion</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚́A
+            ŒÂ•Ê‚̃NƒGƒŠƒNƒ‰ƒCƒeƒŠƒIƒ“i–â‚¢‡‚킹‚Ì”»’èŠî€j‚ð•\‚µ‚Ü‚·B
+            <literal>org.hibernate.criterion.Restrictions</literal>
+            ƒNƒ‰ƒX‚́A‚ ‚é‘g‚ݍž‚Ý‚Ì <literal>Criterion</literal>
+            Œ^‚ðŽæ“¾‚·‚邽‚߂̃tƒ@ƒNƒgƒŠƒƒ\ƒbƒh‚ðŽ‚Á‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .add( Restrictions.between("weight", minWeight, maxWeight) )
+    .list();]]></programlisting>
+    
+        <para>
+            RestrictioniŒÀ’èj‚́A˜_—“I‚ɃOƒ‹[ƒv‰»‚Å‚«‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .add( Restrictions.or(
+        Restrictions.eq( "age", new Integer(0) ),
+        Restrictions.isNull("age")
+    ) )
+    .list();]]></programlisting>
+    
+       <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
+    .add( Restrictions.disjunction()
+        .add( Restrictions.isNull("age") )
+        .add( Restrictions.eq("age", new Integer(0) ) )
+        .add( Restrictions.eq("age", new Integer(1) ) )
+        .add( Restrictions.eq("age", new Integer(2) ) )
+    ) )
+    .list();]]></programlisting>
+    
+        <para>
+            Œ³X‚ ‚éCriterionŒ^i<literal>Restrictions</literal> ‚̃TƒuƒNƒ‰ƒXj
+            ‚Í‚©‚È‚è‚͈̔͂ɋy‚Ñ‚Ü‚·‚ªA“Á‚É—L—p‚È‚Ì‚ÍSQL‚𒼐ڎw’è‚Å‚«‚é‚à‚Ì‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.sqlRestriction("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
+    .list();]]></programlisting>
+    
+        <para>
+            <literal>{alias}</literal> ‚Æ‚¢‚¤ƒvƒŒ[ƒXƒzƒ‹ƒ_‚́A
+            –â‚¢‡‚킹‚ðŽó‚¯‚½ƒGƒ“ƒeƒBƒeƒB‚̍s‚Ì•Ê–¼‚É‚æ‚Á‚Ä’u‚«Š·‚¦‚ç‚ê‚Ü‚·B
+        </para>
+        
+        <para>
+            criterion‚𓾂é•Ê‚ÌŽè’i‚́A
+            <literal>Property</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚©‚çŽæ“¾‚·‚邱‚Æ‚Å‚·B
+            <literal>Property.forName()</literal> ‚ðŒÄ‚яo‚µ‚āA
+            <literal>Property</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚ðì¬‚Å‚«‚Ü‚·B
+        </para>
+    
+        <programlisting><![CDATA[
+Property age = Property.forName("age");
+List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.disjunction()
+        .add( age.isNull() )
+        .add( age.eq( new Integer(0) ) )
+        .add( age.eq( new Integer(1) ) )
+        .add( age.eq( new Integer(2) ) )
+    ) )
+    .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
+    .list();]]></programlisting>
+    
+   </sect1>
+     
+    <sect1 id="querycriteria-ordering">
+        <title>Œ‹‰Ê‚̐®—ñ</title>
+
+        <para>
+            <literal>org.hibernate.criterion.Order</literal>
+            ‚ðŽg‚Á‚ÄŒ‹‰Ê‚ð•À‚Ñ‘Ö‚¦‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "F%")
+    .addOrder( Order.asc("name") )
+    .addOrder( Order.desc("age") )
+    .setMaxResults(50)
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Property.forName("name").like("F%") )
+    .addOrder( Property.forName("name").asc() )
+    .addOrder( Property.forName("age").desc() )
+    .setMaxResults(50)
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-associations" revision="2">
+        <title>ŠÖ˜A</title>
+
+        <para>
+            <literal>createCriteria()</literal> ‚ðŽg‚¢AŠÖ˜A‚ðƒiƒrƒQ[ƒg‚·‚邱‚ƂŁA
+            —eˆÕ‚ÉŠÖŒW‚·‚éƒGƒ“ƒeƒBƒeƒB‚ɐ§–ñ‚ðŽw’è‚Å‚«‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "F%") )
+    .createCriteria("kittens")
+        .add( Restrictions.like("name", "F%") )
+    .list();]]></programlisting>
+
+        <para>
+            2”Ô–Ú‚Ì <literal>createCriteria()</literal> ‚́A<literal>kittens</literal>
+            ƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f‚ðŽQÆ‚·‚éV‚µ‚¢ <literal>Criteria</literal>
+            ƒCƒ“ƒXƒ^ƒ“ƒX‚ð•Ô‚·‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <para>
+            ˆÈ‰º‚̂悤‚È•û–@‚àAó‹µ‚É‚æ‚è—L—p‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .createAlias("kittens", "kt")
+    .createAlias("mate", "mt")
+    .add( Restrictions.eqProperty("kt.name", "mt.name") )
+    .list();]]></programlisting>
+
+        <para>
+            i<literal>createAlias()</literal> ‚͐V‚µ‚¢
+            <literal>Criteria</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚ðì¬‚µ‚Ü‚¹‚ñBj
+        </para>
+
+        <para>
+            ‘O‚Ì2‚‚̃NƒGƒŠ‚É‚æ‚Á‚Ä•Ô‚³‚ê‚é <literal>Cat</literal>
+            ƒCƒ“ƒXƒ^ƒ“ƒX‚É‚æ‚Á‚Ä•ÛŽ‚³‚ê‚ékittensƒRƒŒƒNƒVƒ‡ƒ“‚́A
+            criteria‚É‚æ‚Á‚ÄŽ–‘O‚ɃtƒBƒ‹ƒ^ƒŠƒ“ƒO <emphasis>‚³‚ê‚È‚¢</emphasis>
+            ‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚à‚µcriteria‚É“K‡‚·‚ékitten‚ðŽæ“¾‚µ‚½‚¢‚È‚çA
+            <literal>ResultTransformer</literal> ‚ðŽg‚í‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .createCriteria("kittens", "kt")
+        .add( Restrictions.eq("name", "F%") )
+    .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+    .list();
+Iterator iter = cats.iterator();
+while ( iter.hasNext() ) {
+    Map map = (Map) iter.next();
+    Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
+    Cat kitten = (Cat) map.get("kt");
+}]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="querycriteria-dynamicfetching" revision="1">
+        <title>ŠÖ˜A‚Ì“®“IƒtƒFƒbƒ`</title>
+
+        <para>
+            <literal>setFetchMode()</literal> ‚ðŽg‚¢A
+            ŽÀsŽž‚ÉŠÖ˜A‚Ì•œŒ³•û–@‚ðŽw’肵‚Ä‚à‚æ‚¢‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .setFetchMode("mate", FetchMode.EAGER)
+    .setFetchMode("kittens", FetchMode.EAGER)
+    .list();]]></programlisting>
+    
+        <para>
+            ‚±‚̃NƒGƒŠ‚ÍŠO•”Œ‹‡‚É‚æ‚è <literal>mate</literal> ‚Æ
+            <literal>kittens</literal> ‚Ì—¼•û‚ðƒtƒFƒbƒ`‚µ‚Ü‚·B
+            ‚æ‚葽‚­‚̏î•ñ‚Í <xref linkend="performance-fetching"/> ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+    
+    </sect1>
+     
+    <sect1 id="querycriteria-examples">
+        <title>ƒNƒGƒŠ‚Ì—á</title>
+
+        <para>
+            <literal>org.hibernate.criterion.Example</literal> ƒNƒ‰ƒX‚́A
+            —^‚¦‚ç‚ꂽƒCƒ“ƒXƒ^ƒ“ƒX‚©‚çƒNƒGƒŠƒNƒ‰ƒCƒeƒŠƒIƒ“‚ð\’z‚Å‚«‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[Cat cat = new Cat();
+cat.setSex('F');
+cat.setColor(Color.BLACK);
+List results = session.createCriteria(Cat.class)
+    .add( Example.create(cat) )
+    .list();]]></programlisting>
+    
+        <para>
+           ƒo[ƒWƒ‡ƒ“ƒvƒƒpƒeƒBAŽ¯•ÊŽqAŠÖ˜A‚Í–³Ž‹‚³‚ê‚Ü‚·B
+           ƒfƒtƒHƒ‹ƒg‚Å‚Ínull’l‚̃vƒƒpƒeƒB‚͏œŠO‚³‚ê‚Ü‚·B
+        </para>
+
+        <para>
+           ‚ǂ̂悤‚É <literal>Example</literal> ‚ð“K—p‚·‚é‚©
+           ’²®‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[Example example = Example.create(cat)
+    .excludeZeroes()           //exclude zero valued properties
+    .excludeProperty("color")  //exclude the property named "color"
+    .ignoreCase()              //perform case insensitive string comparisons
+    .enableLike();             //use like for string comparisons
+List results = session.createCriteria(Cat.class)
+    .add(example)
+    .list();]]></programlisting>
+    
+        <para>
+            ŠÖ˜AƒIƒuƒWƒFƒNƒg‚Écriteria‚ðŽw’è‚·‚邽‚߂ɁAExample‚ðŽg‚¤‚±‚Æ‚à‰Â”\‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .add( Example.create(cat) )
+    .createCriteria("mate")
+        .add( Example.create( cat.getMate() ) )
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-projection">
+        <title>ŽË‰eAW–ñAƒOƒ‹[ƒv‰»</title>
+        <para>
+            <literal>org.hibernate.criterion.Projections</literal> ƒNƒ‰ƒX‚Í
+            <literal>Projection</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚̃tƒ@ƒNƒgƒŠ‚Å‚·B
+            <literal>setProjection()</literal> ‚ðŒÄ‚яo‚·‚±‚ƂŁA
+            ƒNƒGƒŠ‚Ɏˉe‚ð“K—p‚µ‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.rowCount() )
+    .add( Restrictions.eq("color", Color.BLACK) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount() )
+        .add( Projections.avg("weight") )
+        .add( Projections.max("weight") )
+        .add( Projections.groupProperty("color") )
+    )
+    .list();]]></programlisting>
+    
+        <para>
+            •K—v‚Å‚ ‚Á‚Ä‚àAcriteriaƒNƒGƒŠ‚Ɂugroup byv‚𖾎¦‚·‚é•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+            ‚ ‚éŽí‚ÌProjectionŒ^‚Í <emphasis>ƒOƒ‹[ƒv‰»ŽË‰e</emphasis> ‚Æ‚µ‚Ä’è‹`‚³‚êA
+            SQL‚Ì <literal>group by</literal> ß‚É‚àŒ»‚ê‚Ü‚·B
+        </para>
+    
+        <para>
+            ”CˆÓ‚Ŏˉe‚É•Ê–¼‚ð•t‚¯‚ç‚ê‚邽‚߁AŽË‰e‚³‚ê‚é’l‚Írestriction‚âordering“à‚©‚çŽQÆ‚Å‚«‚Ü‚·B
+            •Ê–¼‚ð‚‚¯‚é‚Q‚‚̈قȂé•û–@‚ðŽ¦‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
+    .addOrder( Order.asc("colr") )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.groupProperty("color").as("colr") )
+    .addOrder( Order.asc("colr") )
+    .list();]]></programlisting>
+    
+        <para>
+            <literal>alias()</literal> ‚Æ <literal>as()</literal> ƒƒ\ƒbƒh‚́A
+            ProjectionƒCƒ“ƒXƒ^ƒ“ƒX‚ð•Ê‚Ì–¼‘O‚Ì <literal>Projection</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚Å
+            ƒ‰ƒbƒv‚·‚邾‚¯‚Å‚·B
+            ƒVƒ‡[ƒgƒJƒbƒg‚Æ‚µ‚āAŽË‰e‚ðŽË‰eƒŠƒXƒg‚ɒljÁ‚·‚éÛ‚ɁA•Ê–¼‚ð‚‚¯‚ç‚ê‚Ü‚·B
+        </para>
+
+       <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount(), "catCountByColor" )
+        .add( Projections.avg("weight"), "avgWeight" )
+        .add( Projections.max("weight"), "maxWeight" )
+        .add( Projections.groupProperty("color"), "color" )
+    )
+    .addOrder( Order.desc("catCountByColor") )
+    .addOrder( Order.desc("avgWeight") )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Domestic.class, "cat")
+    .createAlias("kittens", "kit")
+    .setProjection( Projections.projectionList()
+        .add( Projections.property("cat.name"), "catName" )
+        .add( Projections.property("kit.name"), "kitName" )
+    )
+    .addOrder( Order.asc("catName") )
+    .addOrder( Order.asc("kitName") )
+    .list();]]></programlisting>
+    
+        <para>
+            ŽË‰e‚ÌŽ®‚É <literal>Property.forName()</literal> ‚àŽg—p‚Å‚«‚Ü‚·B
+        </para>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Property.forName("name") )
+    .add( Property.forName("color").eq(Color.BLACK) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount().as("catCountByColor") )
+        .add( Property.forName("weight").avg().as("avgWeight") )
+        .add( Property.forName("weight").max().as("maxWeight") )
+        .add( Property.forName("color").group().as("color" )
+    )
+    .addOrder( Order.desc("catCountByColor") )
+    .addOrder( Order.desc("avgWeight") )
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-detachedqueries">
+        <title>ƒNƒGƒŠ‚¨‚æ‚уTƒuƒNƒGƒŠ‚Ì•ª—£</title>
+        <para>
+            <literal>DetachedCriteria</literal> ƒNƒ‰ƒX‚É‚æ‚èA
+            ƒZƒbƒVƒ‡ƒ“ƒXƒR[ƒvŠO‚ɃNƒGƒŠ‚ðì¬‚Å‚«‚Ü‚·B
+            Œã‚ŁA”CˆÓ‚Ì <literal>Session</literal> ‚ðŽg‚Á‚āAŽÀs‚Å‚«‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
+    .add( Property.forName("sex").eq('F') );
+    
+Session session = ....;
+Transaction txn = session.beginTransaction();
+List results = query.getExecutableCriteria(session).setMaxResults(100).list();
+txn.commit();
+session.close();]]></programlisting>
+
+        <para>
+            <literal>DetachedCriteria</literal> ‚́AƒTƒuƒNƒGƒŠ‚ð•\Œ»‚·‚邽‚ß‚É‚àŽg‚¦‚Ü‚·B
+            ƒTƒuƒNƒGƒŠ‚𔺂¤CriterionƒCƒ“ƒXƒ^ƒ“ƒX‚́A
+            <literal>Subqueries</literal> ‚à‚µ‚­‚Í <literal>Property</literal> ‚©‚瓾‚ç‚ê‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
+    .setProjection( Property.forName("weight").avg() );
+session.createCriteria(Cat.class)
+    .add( Property.forName("weight).gt(avgWeight) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
+    .setProjection( Property.forName("weight") );
+session.createCriteria(Cat.class)
+    .add( Subqueries.geAll("weight", weights) )
+    .list();]]></programlisting>
+    
+        <para>
+            ‘ŠŒÝŠÖŒW‚ª‚ ‚éƒTƒuƒNƒGƒŠ‚Å‚³‚¦‚à‰Â”\‚Å‚·B
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
+    .setProjection( Property.forName("weight").avg() )
+    .add( Property.forName("cat2.sex").eqProperty("cat.sex") );
+session.createCriteria(Cat.class, "cat")
+    .add( Property.forName("weight).gt(avgWeightForSex) )
+    .list();]]></programlisting>
+
+    </sect1>
+
+        <!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer allow returning arbitrary 
+                  user objects - similar to setResultClass in JDO2. General use of ResultTransformer 
+                  could also be explained. -->
+               
+    <sect1 id="query-criteria-naturalid">
+        <title>Ž©‘RŽ¯•ÊŽq‚É‚æ‚éƒNƒGƒŠ</title>
+        
+        <para>
+            criteriaƒNƒGƒŠ‚ðŠÜ‚Þ‚½‚¢‚Ä‚¢‚̃NƒGƒŠ‚É‚Æ‚Á‚āA
+            ƒNƒGƒŠƒLƒƒƒbƒVƒ…‚Í‚ ‚Ü‚èŒø—¦‚ª‚æ‚­‚È‚¢‚Å‚·B
+            ‚È‚º‚È‚çAƒNƒGƒŠƒLƒƒƒbƒVƒ…‚ª•p”É‚É–³Œø‚ɂȂ邽‚ß‚Å‚·B
+            ‚µ‚©‚µ‚È‚ª‚çAƒLƒƒƒbƒVƒ…‚𖳌ø‚É‚·‚éƒAƒ‹ƒSƒŠƒYƒ€‚ðÅ“K‰»‚Å‚«‚é
+            “Á•Ê‚ȃNƒGƒŠ‚ÌŽí—Þ‚ª‚P‚‚ ‚è‚Ü‚·B
+            XV‚³‚ê‚È‚¢Ž©‘RƒL[‚É‚æ‚錟õ‚Å‚·B
+            ‚¢‚­‚‚©‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚ł́A‚±‚ÌŽí—ނ̃NƒGƒŠ‚ª•p”É‚ÉŒ»‚ê‚Ü‚·B
+            ‚±‚̂悤‚ÈŽg‚í‚ê•û‚Ì‚½‚߂ɁAcriteria API‚Í“Á•Ê‚ȑ΍ô‚ð’ñ‹Ÿ‚µ‚Ü‚·B
+        </para>
+        
+        <para>
+            Å‰‚ɁA<literal>&lt;natural-id&gt;</literal> ‚ðŽg‚Á‚āA
+            ƒGƒ“ƒeƒBƒeƒB‚ÌŽ©‘RƒL[‚ðƒ}ƒbƒv‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚»‚µ‚āA“ñŽŸƒLƒƒƒbƒVƒ…‚ð—LŒø‚É‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[<class name="User">
+    <cache usage="read-write"/>
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <natural-id>
+        <property name="name"/>
+        <property name="org"/>
+    </natural-id>
+    <property name="password"/>
+</class>]]></programlisting>
+    
+        <para>
+            ’ˆÓF <emphasis>•ÏX‚³‚ê‚é</emphasis> Ž©‘RƒL[‚ðŽ‚ÂƒGƒ“ƒeƒBƒeƒB‚É
+            ‚±‚Ì‹@”\‚ðŽg‚¤‚̂́AˆÓ}‚³‚ê‚Ä‚¢‚È‚¢Žg‚¢•û‚Å‚·B
+        </para>
+        
+        <para>
+            ŽŸ‚ɁAHibernateƒNƒGƒŠƒLƒƒƒbƒVƒ…‚ð—LŒø‚É‚µ‚Ü‚·B
+        </para>
+        
+        <para>
+            ‚±‚ê‚ŁA<literal>Restrictions.naturalId()</literal> ‚É‚æ‚èA
+            ‚æ‚èŒø—¦“I‚ȃLƒƒƒbƒVƒ…ƒAƒ‹ƒSƒŠƒYƒ€‚ðŽg—p‚Å‚«‚Ü‚·B
+        </para>
+       
+        <programlisting><![CDATA[session.createCriteria(User.class)
+    .add( Restrictions.naturalId()
+        .set("name", "gavin")
+        .set("org", "hb") 
+    ).setCacheable(true)
+    .uniqueResult();]]></programlisting>
+            
+    </sect1>
+    
+</chapter>

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/query_hql.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/query_hql.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/query_hql.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1131 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="queryhql">
+    <title>HQL: The Hibernate Query Language</title>
+    
+    <para>
+        Hibernate‚ÍSQL‚É”ñí‚É‚æ‚­Ž—‚½(ˆÓ}“I‚ÉŽ—‚¹‚½)‹­—Í‚È–â‚¢‡‚킹Œ¾Œê‚ð”õ‚¦‚Ä‚¢‚Ü‚·B
+        ‚µ‚©‚µSQL‚ÉŽ—‚½\•¶‚ɘf‚킳‚ê‚È‚¢‚Å‚­‚¾‚³‚¢BHQL‚ÍŠ®‘S‚ɃIƒuƒWƒFƒNƒgŽwŒü‚Å‚ ‚èA
+        Œp³Aƒ|ƒŠƒ‚[ƒtƒBƒYƒ€AŠÖ˜A‚Æ‚¢‚Á‚½ŠT”O‚ð—‰ð‚µ‚Ü‚·B
+    </para>
+
+    <sect1 id="queryhql-casesensitivity">
+        <title>‘啶Žš‚Ə¬•¶Žš‚Ì‹æ•Ê</title>
+
+        <para>
+            ƒNƒGƒŠ‚ÍJava‚̃Nƒ‰ƒX–¼‚ƃvƒƒpƒeƒB–¼‚ðœ‚¢‚đ啶ŽšA¬•¶Žš‚ð‹æ•Ê‚µ‚Ü‚¹‚ñB
+            ]‚Á‚Ä <literal>SeLeCT</literal> ‚Í
+            <literal>sELEct</literal> ‚Æ“¯‚¶‚ŁA‚©‚Â
+            <literal>SELECT</literal> ‚Æ‚à“¯‚¶‚Å‚·‚ª
+            <literal>net.sf.hibernate.eg.FOO</literal> ‚Í
+            <literal>net.sf.hibernate.eg.Foo</literal> ‚Ƃ͈ႢA‚©‚Â
+            <literal>foo.barSet</literal> ‚Í
+            <literal>foo.BARSET</literal> ‚Æ‚àˆá‚¢‚Ü‚·B
+        </para>
+        
+        <para>
+            ‚±‚̃}ƒjƒ…ƒAƒ‹‚ł͏¬•¶Žš‚ÌHQLƒL[ƒ[ƒh‚ðŽg—p‚µ‚Ü‚·B
+            ‘啶Žš‚̃L[ƒ[ƒh‚̃NƒGƒŠ‚Ì•û‚ª“Ç‚Ý‚â‚·‚¢‚ÆŠ´‚¶‚郆[ƒU[‚à‚¢‚é‚ÆŽv‚¢‚Ü‚·B
+            ‚Å‚·‚ªAJavaƒR[ƒh“à‚É–„‚ߍž‚܂ꂽ‚Æ‚«‚É‚ÍŒ©‚Â炢‚ÆŽv‚¢‚Ü‚·B
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-from">
+        <title>fromß</title>
+
+        <para>
+            ‚à‚Á‚Æ‚à’Pƒ‚ÈHibernateƒNƒGƒŠ‚ÍŽŸ‚ÌŒ`Ž®‚Å‚·B
+        </para>
+        
+        <programlisting><![CDATA[from eg.Cat]]></programlisting>
+        
+        <para>
+            ‚±‚ê‚Í’Pƒ‚Ɂ@<literal>eg.Cat</literal>@ƒNƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ð‚·‚×‚Ä•Ô‚µ‚Ü‚·B
+            •K‚¸‚µ‚àƒNƒ‰ƒX–¼‚ðCü‚·‚éiƒNƒ‰ƒX‚ɃpƒbƒP[ƒW–¼‚ð•t‚¯‚éj•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+            ‚Æ‚¢‚¤‚Ì‚àA<literal>auto-import</literal> ‚ªƒfƒtƒHƒ‹ƒg‚É‚È‚Á‚Ä‚¢‚é‚©‚ç‚Å‚·B
+            ‚»‚Ì‚½‚ß‚Ù‚Æ‚ñ‚ǂ̏ꍇA‚±‚̂悤‚ɏ‘‚­‚¾‚¯‚ŏ\•ª‚Å‚·B
+        </para>
+        
+        <programlisting><![CDATA[from Cat]]></programlisting>
+        
+        <para>
+            ‚Ù‚Æ‚ñ‚ǂ̏ꍇƒNƒGƒŠ‚Ì‚Ù‚©‚Ì•”•ª‚Ł@<literal>Cat</literal>@‚ðŽQÆ‚·‚é‚̂ŁA•Ê–¼‚ðŠ„‚è“–‚Ä‚é•K—v‚ª‚ ‚é‚Å‚µ‚傤B
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+        <para>
+            ‚±‚̃NƒGƒŠ‚Å‚Í <literal>Cat</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚É <literal>cat</literal> 
+            ‚Æ‚¢‚¤•Ê–¼‚ð•t‚¯‚Ä‚¢‚Ü‚·B
+            ‚»‚Ì‚½‚߁AŒã‚Å‚±‚̃NƒGƒŠ“à‚ŁA‚±‚Ì•Ê–¼‚ðŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+            <literal>as</literal> ƒL[ƒ[ƒh‚̓IƒvƒVƒ‡ƒ“‚Å‚·B‚‚܂肱‚̂悤‚ɏ‘‚­‚±‚Æ‚à‚Å‚«‚Ü‚·F
+        </para>
+        
+        <programlisting><![CDATA[from Cat cat]]></programlisting>
+        
+        <para>
+            ’¼ÏA‚ ‚é‚¢‚̓NƒƒXŒ‹‡‚É‚æ‚Á‚Ä‘½”‚̃Nƒ‰ƒX‚ªoŒ»‚·‚邱‚Æ‚à‚ ‚è‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[from Formula, Parameter]]></programlisting>
+        <programlisting><![CDATA[from Formula as form, Parameter as param]]></programlisting>
+        
+        <para>
+            ƒ[ƒJƒ‹•Ï”‚ÌJava‚̃l[ƒ~ƒ“ƒOŠî€‚ƈê’v‚µ‚½A
+            “ª•¶Žš‚ɏ¬•¶Žš‚ðŽg‚Á‚½ƒNƒGƒŠ‚Ì•Ê–¼‚ð•t‚¯‚邱‚Æ‚Í‚¢‚¢KŠµ‚Å‚·(—Ⴆ‚Î <literal>domesticCat</literal> )B
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-joins" revision="2">
+        <title>ŠÖ˜A‚ÆŒ‹‡</title>
+
+        <para>
+            ŠÖ˜A‚·‚éƒGƒ“ƒeƒBƒeƒB‚ ‚é‚¢‚Í’lƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f‚É‚àA<literal>Œ‹‡</literal> ‚ðŽg‚Á‚Ä•Ê–¼‚ðŠ„‚è“–‚Ă邱‚Æ‚ªo—ˆ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    inner join cat.mate as mate
+    left outer join cat.kittens as kitten]]></programlisting>
+
+        <programlisting><![CDATA[from Cat as cat left join cat.mate.kittens as kittens]]></programlisting>
+
+        <programlisting><![CDATA[from Formula form full join form.parameter param]]></programlisting>
+
+        <para>
+            ƒTƒ|[ƒg‚µ‚Ä‚¢‚錋‡‚̃^ƒCƒv‚ÍANSI SQL‚Æ“¯‚¶‚Å‚·B
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>inner join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>left outer join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>right outer join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>full join</literal> (‚½‚¢‚Ä‚¢‚̏ꍇŽg‚¢‚Â炢)
+                </para>
+            </listitem>
+        </itemizedlist>
+    
+        <para>
+            <literal>inner join</literal>A<literal>left outer join</literal>A<literal>right outer join</literal>‚ɂ͏ȗªŒ`‚ðŽg‚¤‚±‚Æ‚à‚Å‚«‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    join cat.mate as mate
+    left join cat.kittens as kitten]]></programlisting>
+    
+        <para>
+            HQL‚Ì <literal>with</literal> ƒL[ƒ[ƒh‚ðŽg‚¤‚ƁAŒ‹‡ðŒ‚ð•t‚¯‰Á‚¦‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    left join cat.kittens as kitten 
+        with kitten.bodyWeight > 10.0]]></programlisting>
+
+        <para>
+            ‰Á‚¦‚āAuƒtƒFƒbƒ`vŒ‹‡‚ÍŠÖ˜A‚â’l‚̃RƒŒƒNƒVƒ‡ƒ“‚ðeƒIƒuƒWƒFƒNƒg‚ƈꏏ‚É1“x‚Ìselect‹å‚ŏ‰Šú‰»‚µ‚Ü‚·B
+            ‚±‚ê‚Í“Á‚ɃRƒŒƒNƒVƒ‡ƒ“‚̏ꍇ‚É—L—p‚Å‚·B‚±‚ê‚ÍŽÀŽ¿ãAŠÖ˜A‚ƃRƒŒƒNƒVƒ‡ƒ“‚ɑ΂·‚éƒ}ƒbƒsƒ“ƒO’è‹`ƒtƒ@ƒCƒ‹‚ÌŠO•”Œ‹‡‚Ælazy‰Šú‰»‚Ì’è‹`‚ðã‘‚«‚·‚邱‚Æ‚É‚È‚è‚Ü‚·B
+            
+            <xref linkend="performance-fetching"/> ‚É‚æ‚葽‚­‚̏î•ñ‚ª‚ ‚è‚Ü‚·B
+        </para>
+    
+        <programlisting><![CDATA[from Cat as cat 
+    inner join fetch cat.mate
+    left join fetch cat.kittens]]></programlisting>
+    
+        <para>
+            Œ‹‡‚É‚æ‚éƒtƒFƒbƒ`‚ÍŠÖ˜A‚·‚éƒIƒuƒWƒFƒNƒg‚ª <literal>where</literal> ß(‚Ü‚½‚Í‘¼‚Ì‚Ç‚ñ‚Ȑ߂łà)
+            ‚ÅŽg‚í‚ê‚Ä‚Í‚È‚ç‚È‚¢‚̂ŁA’ʏí•Ê–¼‚ðŠ„‚è“–‚Ä‚é•K—v‚ª‚ ‚è‚Ü‚¹‚ñB‚Ü‚½ŠÖ˜AƒIƒuƒWƒFƒNƒg‚Í–â‚¢‡‚킹Œ‹‰Ê‚Æ‚µ‚Ä
+            ’¼Ú•Ô‚³‚ê‚Ü‚¹‚ñB‘ã‚í‚è‚ɐeƒIƒuƒWƒFƒNƒg‚ð’Ê‚µ‚ăAƒNƒZƒX‚Å‚«‚Ü‚·B
+            ƒRƒŒƒNƒVƒ‡ƒ“‚ðÄ‹A“I‚ÉŒ‹‡ƒtƒFƒbƒ`‚·‚éê‡‚̂݁A•Ê–¼‚ª•K—v‚É‚È‚è‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[from Cat as cat 
+    inner join fetch cat.mate
+    left join fetch cat.kittens child
+    left join fetch child.kittens]]></programlisting>
+    
+        <para>
+            <literal>fetch</literal> \•¶‚Í <literal>iterate()</literal> 
+            ‚ðŽg‚Á‚½ƒNƒGƒŠŒÄ‚яo‚µ‚ÅŽg—p‚Å‚«‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢
+            iˆê•û‚Å <literal>scroll()</literal> ‚ÍŽg—p‚Å‚«‚Ü‚·jB
+            
+            ‚Ü‚½A‚±‚ê‚ç‚Ì‘€ì‚ÍŒ‹‰Ê‚̍s‚ÉŠî‚¢‚Ä‚¢‚邽‚߁A
+            <literal>fetch</literal> ‚Í <literal>setMaxResults()</literal> ‚â <literal>setFirstResult()</literal> 
+            ‚ƈꏏ‚ÉŽg—p‚·‚ׂ«‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+            ’ʏíeager‚ȃRƒŒƒNƒVƒ‡ƒ“ƒtƒFƒbƒ`‚ð‚·‚é‚Əd•¡‚ªo‚Ä‚µ‚Ü‚¤‚½‚߁A‚ ‚È‚½‚ªŠú‘Ò‚·‚é‚悤‚ȍs”‚É‚Í‚È‚ç‚È‚¢‚Ì‚Å‚·B
+                             
+            ‚»‚µ‚Ä‚Ü‚½ <literal>fetch</literal> ‚́AƒAƒhƒzƒbƒN‚È <literal>with</literal> ðŒ‚ð
+            ˆê‚ÉŽg‚¤‚±‚Æ‚à‚Å‚«‚Ü‚¹‚ñB
+            ˆê‚‚̃NƒGƒŠ‚Å•¡”‚̃RƒŒƒNƒVƒ‡ƒ“‚ðŒ‹‡ƒtƒFƒbƒ`‚·‚邱‚Æ‚É‚æ‚è’¼Ï‚ðì¬‚Å‚«‚é‚̂ŁA‚±‚̏ꍇ’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚Ü‚½A•¡”‚̃RƒŒƒNƒVƒ‡ƒ“‚ɑ΂·‚錋‡ƒtƒFƒbƒ`‚Íbagƒ}ƒbƒsƒ“ƒO‚ɑ΂µ‚Ä—\Šú‚¹‚ÊŒ‹‰Ê‚ð‚à‚½‚ç‚·‚±‚Æ‚ª‚ ‚é‚̂ŁA
+            ‚±‚̏ꍇ‚̃NƒGƒŠ‚̍쐬‚É‚Í’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ÅŒã‚É <literal>‘SŠO•”Œ‹‡‚É‚æ‚éƒtƒFƒbƒ`</literal> ‚Æ
+            <literal>‰EŠO•”Œ‹‡‚É‚æ‚éƒtƒFƒbƒ`</literal> ‚Í—L—p‚Å‚Í‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+        
+        <para>
+            ‚à‚µƒvƒƒpƒeƒBƒŒƒxƒ‹‚Ì’x‰„ƒtƒFƒbƒ`‚ðŽg‚¤ê‡i“à•”“I‚ɃoƒCƒgƒR[ƒhˆ—‚ð‚·‚éê‡jA
+            <literal>fetch all properties</literal> ‚ðŽg‚¤‚±‚Æ‚Å
+            Hibernate‚É’x‰„ƒvƒƒpƒeƒB‚𑬂₩‚ɁiÅ‰‚̃NƒGƒŠ‚ŁjƒtƒFƒbƒ`‚³‚¹‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[from Document fetch all properties order by name]]></programlisting>
+        <programlisting><![CDATA[from Document doc fetch all properties where lower(doc.name) like '%cats%']]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-joins-forms">
+        <title>Œ‹‡\•¶‚ÌŒ`Ž®</title>
+
+        <para>
+            HQL‚Í‚Q‚‚̊֘AŒ‹‡Œ`Ž®‚ðƒTƒ|[ƒg‚µ‚Ü‚·F<literal>ˆÃ–Ù“I</literal> ‚Æ <literal>–¾Ž¦“I</literal>B
+        </para>
+
+        <para>
+            ‚±‚ê‚܂ł̃ZƒNƒVƒ‡ƒ“‚Å‚¨Œ©‚¹‚µ‚½Žg‚¢•û‚Í‚·‚×‚Ä <literal>–¾Ž¦“I‚È</literal> Œ`Ž®‚ŁA
+            fromß‚Å–¾Ž¦“I‚ÉjoinƒL[ƒ[ƒh‚ðŽg‚Á‚Ä‚¢‚Ü‚·B
+            ‚±‚ÌŒ`Ž®‚ð‚¨‚·‚·‚ß‚µ‚Ü‚·B
+        </para>
+
+        <para>
+            <literal>ˆÃ–Ù“I</literal> ƒtƒH[ƒ€‚́AjoinƒL[ƒ[ƒh‚ðŽg‚¢‚Ü‚¹‚ñB‘ã‚í‚è‚ɁAŽQÆ‚·‚éŠÖ˜A‚É
+            ƒhƒbƒg•\‹L‚ðŽg‚¢‚Ü‚·B<literal>ˆÃ–Ù“I</literal> Œ‹‡‚́A‚³‚Ü‚´‚Ü‚ÈHQL‚ɏo‚Ä‚«‚Ü‚·B
+            <literal>ˆÃ–Ù“I</literal> Œ‹‡‚ÌŒ‹‰Ê‚́ASQLƒXƒe[ƒgƒƒ“ƒg‚Ì“à•”Œ‹‡Œ‹‰Ê‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.mate.name like '%s%']]></programlisting>
+    </sect1>
+
+    <sect1 id="queryhql-select">
+        <title>Selectß</title>
+
+        <para>
+            <literal>select</literal> ß‚͈ȉº‚̂悤‚ɂǂ̃IƒuƒWƒFƒNƒg‚Æ‘®«‚ðƒNƒGƒŠƒŠƒUƒ‹ƒgƒZƒbƒg‚É•Ô‚·‚©‚ð‘I‘ð‚µ‚Ü‚·B:
+        </para>
+
+        <programlisting><![CDATA[select mate 
+from Cat as cat 
+    inner join cat.mate as mate]]></programlisting>
+
+        <para>
+            ã‹L‚̃NƒGƒŠ‚Í‘¼‚Ì <literal>Cat</literal> ‚Ì <literal>mate</literal> ‚ð‘I‘ð‚µ‚Ü‚·B
+            ŽÀÛ‚É‚ÍŽŸ‚̂悤‚ɁA‚æ‚èŠÈŒ‰‚É•\Œ»‚Å‚«‚Ü‚·B: 
+        </para>
+
+        <programlisting><![CDATA[select cat.mate from Cat cat]]></programlisting>
+
+        <para>
+            ƒNƒGƒŠ‚̓Rƒ“ƒ|[ƒlƒ“ƒgŒ^‚̃vƒƒpƒeƒB‚ðŠÜ‚ށA‚ ‚ç‚ä‚é’lŒ^‚̃vƒƒpƒeƒB‚à•Ô‚¹‚Ü‚·B:
+        </para>
+
+        <programlisting><![CDATA[select cat.name from DomesticCat cat
+where cat.name like 'fri%']]></programlisting>
+
+        <programlisting><![CDATA[select cust.name.firstName from Customer as cust]]></programlisting>
+
+        <para>
+            ƒNƒGƒŠ‚Í•¡”‚̃IƒuƒWƒFƒNƒg‚Æ(‚Ü‚½‚Í)ƒvƒƒpƒeƒB‚ð <literal>Object[]</literal> Œ^‚Ì”z—ñ‚Æ‚µ‚Ä•Ô‚¹‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[select mother, offspr, mate.name 
+from DomesticCat as mother
+    inner join mother.mate as mate
+    left outer join mother.kittens as offspr]]></programlisting>
+    
+        <para>
+            ‚à‚µ‚­‚Í <literal>List</literal> ‚Æ‚µ‚āA
+        </para>
+        
+        <programlisting><![CDATA[select new list(mother, offspr, mate.name)
+from DomesticCat as mother
+    inner join mother.mate as mate
+    left outer join mother.kittens as offspr]]></programlisting>
+    
+        <para>
+            ‚Ü‚½‚́Aƒ^ƒCƒvƒZ[ƒt‚ÈJavaƒIƒuƒWƒFƒNƒg‚ð•Ô‚¹‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[select new Family(mother, mate, offspr)
+from DomesticCat as mother
+    join mother.mate as mate
+    left join mother.kittens as offspr]]></programlisting>
+        
+        <para>
+            ‚ ‚é‚¢‚Í <literal>Family</literal> ƒNƒ‰ƒX‚ª“KØ‚ȃRƒ“ƒXƒgƒ‰ƒNƒ^‚ðŽ‚Á‚Ä‚¢‚é‚Æ‚·‚é‚È‚ç‚΁A
+        </para>
+        
+        <para>
+            selectß‚É <literal>as</literal> ‚ðŽg‚Á‚Ä•Ê–¼‚ð‚‚¯‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
+from Cat cat]]></programlisting>
+
+        <para>
+            <literal>select new map</literal> ‚ƈꏏ‚ÉŽg‚¤‚Æ‚«‚ɍłà–𗧂¿‚Ü‚·F
+        </para>
+            
+        <programlisting><![CDATA[select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
+from Cat cat]]></programlisting>
+
+        <para>
+            ‚±‚̃NƒGƒŠ‚Í•Ê–¼‚©‚çselect‚µ‚½’l‚Ö <literal>Map</literal> ‚ð•Ô‚µ‚Ü‚·B
+        </para>
+         
+    </sect1>
+
+    <sect1 id="queryhql-aggregation">
+        <title>W–ñŠÖ”</title>
+
+        <para>
+            HQL‚̃NƒGƒŠ‚̓vƒƒpƒeƒB‚̏W–ñŠÖ”‚ÌŒ‹‰Ê‚à•Ô‚¹‚Ü‚·F
+        </para>
+
+        <programlisting><![CDATA[select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
+from Cat cat]]></programlisting>
+
+<!-- NO LONGER SUPPORTED
+        <para>
+            Collections may also appear inside aggregate functions in the <literal>select</literal> 
+            clause.
+        </para>
+
+        <programlisting><![CDATA[select cat, count( elements(cat.kittens) ) 
+from Cat cat group by cat]]></programlisting>
+-->
+
+        <para>
+            ƒTƒ|[ƒg‚µ‚Ä‚¢‚éW–ñŠÖ”‚͈ȉº‚Ì‚à‚Ì‚Å‚·B
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>avg(...), sum(...), min(...), max(...)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>count(*)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>count(...), count(distinct ...), count(all...)</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+    
+        <para>
+            selectß‚É‚¨‚¢‚ÄŽZp‘€ìA˜AŒ‹‚Ə³”F‚³‚ꂽSQLŠÖ”‚ðŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[select cat.weight + sum(kitten.weight) 
+from Cat cat 
+    join cat.kittens kitten
+group by cat.id, cat.weight]]></programlisting>
+    
+        <programlisting><![CDATA[select firstName||' '||initial||' '||upper(lastName) from Person]]></programlisting>
+    
+        <para>
+            SQL‚Æ“¯‚¶ˆÓ–¡‚ðŽ‚Â <literal>distinct</literal> ‚Æ <literal>all</literal> ƒL[ƒ[ƒh‚ðŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[select distinct cat.name from Cat cat
+
+select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="queryhql-polymorphism">
+        <title>ƒ|ƒŠƒ‚[ƒtƒBƒbƒN‚ȃNƒGƒŠ</title>
+
+        <para>
+            ŽŸ‚̂悤‚ȃNƒGƒŠF
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+        <para>
+            <literal>Cat</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚¾‚¯‚Å‚Í‚È‚­A<literal>DomesticCat</literal> 
+            ‚̂悤‚ȃTƒuƒNƒ‰ƒX‚à•Ô‚³‚ê‚Ü‚·BHibernateƒNƒGƒŠ‚Í <emphasis>‚Ç‚ñ‚È</emphasis>
+            JavaƒNƒ‰ƒX‚âƒCƒ“ƒ^[ƒtƒFƒCƒX‚à <literal>from</literal> ß‚É“ü‚ê‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            ƒNƒGƒŠ‚Í‚»‚̃Nƒ‰ƒX‚ðŠg’£‚µ‚½A‚à‚µ‚­‚̓Cƒ“ƒ^[ƒtƒFƒCƒX‚ðŽÀ‘•‚µ‚½‘S‚Ẳi‘±ƒNƒ‰ƒX‚ð•Ô‚µ‚Ü‚·B
+            ŽŸ‚̃NƒGƒŠ‚͉i‘±ƒIƒuƒWƒFƒNƒg‚ð‚·‚×‚Ä•Ô‚µ‚Ü‚·:
+        </para>
+        
+        <programlisting><![CDATA[from java.lang.Object o]]></programlisting>
+        
+        <para>
+            <literal>Named</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚Í—lX‚ȉi‘±ƒNƒ‰ƒX‚É‚æ‚Á‚ÄŽÀ‘•‚³‚ê‚Ü‚·B: 
+        </para>
+        
+        <programlisting><![CDATA[from Named n, Named m where n.name = m.name]]></programlisting>
+        
+        <para>
+            ÅŒã‚Ì“ñ‚‚̃NƒGƒŠ‚́A“ñ‚ˆȏã‚ÌSQL <literal>SELECT</literal> ‚ð—v‹‚µ‚Ä‚¢‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚±‚Ì‚±‚Æ‚Í <literal>order by</literal> ß‚ªƒŠƒUƒ‹ƒgƒZƒbƒg‘S‘̂𐳊m‚ɂ͐®—ñ‚µ‚È‚¢‚±‚Æ‚ðˆÓ–¡‚µ‚Ü‚·
+            (‚³‚ç‚É‚»‚ê‚́A<literal>Query.scroll()</literal> ‚ðŽg—p‚µ‚Ä‚±‚ê‚ç‚̃NƒGƒŠ‚ðŒÄ‚Ô‚±‚Æ‚ª‚Å‚«‚È‚¢‚±‚Æ‚ðˆÓ–¡‚µ‚Ü‚·B)B 
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-where">
+        <title>whereß</title>
+
+        <para>
+            <literal>where</literal> ß‚Í•Ô‚³‚ê‚éƒCƒ“ƒXƒ^ƒ“ƒX‚̃ŠƒXƒg‚ði‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            ‚à‚µ•Ê–¼‚ª‚È‚¢ê‡A–¼‘O‚ŃvƒƒpƒeƒB‚ðŽQÆ‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[from Cat where name='Fritz']]></programlisting>
+        
+        <para>
+            ‚à‚µ•Ê–¼‚ª‚ ‚éê‡ACü–¼‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢B
+        </para>
+        
+        <programlisting><![CDATA[from Cat as cat where cat.name='Fritz']]></programlisting>
+
+        <para>
+            –¼‘O‚ª'Fritz'‚Æ‚¢‚¤ <literal>Cat</literal> ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ð•Ô‚µ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[select foo 
+from Foo foo, Bar bar
+where foo.startDate = bar.date]]></programlisting>
+
+        <para>
+            ã‚ÌHQL‚́A<literal>Foo</literal> ‚Ì <literal>startDate</literal> ƒvƒƒpƒeƒB‚Æ“™‚µ‚¢
+            <literal>date</literal> ƒvƒƒpƒeƒB‚ðŽ‚Á‚½ <literal>bar</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚ª‘¶Ý‚·‚éA
+            ‚·‚×‚Ä‚Ì <literal>Foo</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚ð•Ô‚µ‚Ü‚·B
+            ƒRƒ“ƒpƒEƒ“ƒhƒpƒXŽ®i—Ⴆ‚΁ucat.mate.namevj‚Í <literal>where</literal> ß‚ð”ñí‚É‹­—Í‚É‚µ‚Ü‚·B’–ځF
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.mate.name is not null]]></programlisting>
+
+        <para>
+            ‚±‚̃NƒGƒŠ‚̓e[ƒuƒ‹Œ‹‡i“à•”Œ‹‡j‚ðŽ‚ÂSQLƒNƒGƒŠ‚É•ÏŠ·‚³‚ê‚Ü‚·B
+            ‚»‚Ì‘ã‚í‚è‚Ɉȉº‚̂悤‚ɏ‘‚­‚ƁA
+        </para>
+
+        <programlisting><![CDATA[from Foo foo  
+where foo.bar.baz.customer.address.city is not null]]></programlisting>
+
+        <para>
+            ‚à‚µã‚̃NƒGƒŠ‚ð‹Lq‚µ‚½‚çƒNƒGƒŠ“à‚É4‚‚̃e[ƒuƒ‹Œ‹‡‚ð•K—v‚Æ‚·‚éSQLƒNƒGƒŠ‚É•ÏŠ·‚³‚ê‚Ü‚·B
+        </para>
+
+        <para>
+            <literal>=</literal> ‰‰ŽZŽq‚͈ȉº‚̂悤‚ɁAƒvƒƒpƒeƒB‚¾‚¯‚Å‚È‚­ƒCƒ“ƒXƒ^ƒ“ƒX‚ð”äŠr‚·‚邽‚ß‚É‚àŽg‚í‚ê‚Ü‚·BF
+        </para>
+
+        <programlisting><![CDATA[from Cat cat, Cat rival where cat.mate = rival.mate]]></programlisting>
+
+        <programlisting><![CDATA[select cat, mate 
+from Cat cat, Cat mate
+where cat.mate = mate]]></programlisting>
+
+        <para>
+            <literal>id</literal> (¬•¶Žš)‚Í“Á•Ê‚ȃvƒƒpƒeƒB‚Å‚ ‚èA
+            ƒIƒuƒWƒFƒNƒg‚̃†ƒj[ƒN‚ÈŽ¯•ÊŽq‚ðŽQÆ‚·‚邽‚ß‚ÉŽg—p‚Å‚«‚Ü‚·B(‚³‚ç‚ɁA‚»‚̃vƒƒpƒeƒB–¼‚ðŽg—p‚Å‚«‚Ü‚·B) 
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.id = 123
+
+from Cat as cat where cat.mate.id = 69]]></programlisting>
+
+        <para>
+            2”Ԗڂ̃NƒGƒŠ‚ÍŒø—¦“I‚Å‚·Bƒe[ƒuƒ‹Œ‹‡‚ª•K—v‚ ‚è‚Ü‚¹‚ñI
+        </para>
+
+        <para>
+            ‚Ü‚½•¡‡Ž¯•ÊŽq‚̃vƒƒpƒeƒB‚àŽg—p‚Å‚«‚Ü‚·B‚±‚±‚Å <literal>Person</literal> ‚ª
+            <literal>country</literal> ‚Æ <literal>medicareNumber</literal> ‚©‚ç‚È‚é•¡‡Ž¯•ÊŽq‚ðŽ‚Â‚Æ‰¼’肵‚Ü‚·B 
+        </para>
+
+        <programlisting><![CDATA[from bank.Person person
+where person.id.country = 'AU' 
+    and person.id.medicareNumber = 123456]]></programlisting>
+
+        <programlisting><![CDATA[from bank.Account account
+where account.owner.id.country = 'AU' 
+    and account.owner.id.medicareNumber = 123456]]></programlisting>
+
+        <para>
+            ‚à‚¤ˆê“xŒ¾‚¢‚Ü‚·‚ªA2”Ԗڂ̃NƒGƒŠ‚ɂ̓e[ƒuƒ‹Œ‹‡‚ª•K—v‚ ‚è‚Ü‚¹‚ñB
+        </para>
+            
+        <para>
+            “¯—l‚É <literal>class</literal> ‚Í“Á•Ê‚ȃvƒƒpƒeƒB‚Å‚ ‚èA
+            ƒ|ƒŠƒ‚[ƒtƒBƒbƒN‚ȉi‘±‰»‚É‚¨‚¯‚éƒCƒ“ƒXƒ^ƒ“ƒX‚Ìdiscriminator’l‚ɃAƒNƒZƒX‚µ‚Ü‚·B
+            whereß‚É–„‚ߍž‚܂ꂽJava‚̃Nƒ‰ƒX–¼‚Í‚»‚Ìdiscriminator’l‚É•ÏŠ·‚³‚ê‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
+        
+        <para>
+            ‚Ü‚½ƒRƒ“ƒ|[ƒlƒ“ƒg‚â•¡‡ƒ†[ƒUŒ^(‚Ü‚½‚»‚̃Rƒ“ƒ|[ƒlƒ“ƒg‚̃Rƒ“ƒ|[ƒlƒ“ƒg‚È‚Ç)‚̃vƒƒpƒeƒB‚àŽw’è‚Å‚«‚Ü‚·B
+            
+            ‚µ‚©‚µŒˆ‚µ‚āiƒRƒ“ƒ|[ƒlƒ“ƒg‚̃vƒƒpƒeƒB‚Å‚Í‚È‚­jƒRƒ“ƒ|[ƒlƒ“ƒgŒ^‚̃vƒƒpƒeƒB‚ŏI—¹‚·‚éƒpƒXŽ®‚ðŽg‚í‚È‚¢‚Å‚­‚¾‚³‚¢B
+            —Ⴆ‚Î‚à‚µ <literal>store.owner</literal> ‚ª <literal>address</literal> 
+            ƒRƒ“ƒ|[ƒlƒ“ƒg‚ðŽ‚ÂƒGƒ“ƒeƒBƒeƒB‚È‚ç‚Έȉº‚̂悤‚ÈŒ‹‰Ê‚Æ‚È‚è‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[store.owner.address.city    // okay
+store.owner.address         // error!]]></programlisting>
+
+        <para>
+            "any"Œ^‚Í“Á•Ê‚ȃvƒƒpƒeƒB‚Å‚ ‚é <literal>id</literal> ‚Æ <literal>class</literal> ‚ðŽ‚¿A
+            ˆÈ‰º‚Ì•û–@‚ÅŒ‹‡‚ð•\Œ»‚·‚邱‚Æ‚ð‰Â”\‚É‚µ‚Ü‚·(<literal>AuditLog.item</literal> ‚Í
+            <literal>&lt;any&gt;</literal> ‚Ń}ƒbƒsƒ“ƒO‚³‚ꂽƒvƒƒpƒeƒB‚Å‚·)B 
+        </para>
+       
+        <programlisting><![CDATA[from AuditLog log, Payment payment 
+where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting>
+    
+        <para>
+            <literal>log.item.class</literal> ‚Æ <literal>payment.class</literal> ‚ª
+            ã‹L‚̃NƒGƒŠ’†‚Å‘S‚­ˆÙ‚È‚éƒf[ƒ^ƒx[ƒXƒJƒ‰ƒ€‚Ì’l‚ðŽQÆ‚·‚é‚Æ‚¢‚¤‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-expressions">
+        <title>Expressions Ž®</title>
+
+        <para>
+            SQL‚Ì <literal>where</literal> ß‚Å‹Lq‚·‚邱‚Æ‚ªo—ˆ‚鎮‚Ì‚Ù‚Æ‚ñ‚Ç‚ðHQL‚Å‚à‹Lq‚Å‚«‚Ü‚·B:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    ŽZp‰‰ŽZŽqF<literal>+, -, *, /</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    2€”äŠr‰‰ŽZŽqF<literal>=, &gt;=, &lt;=, &lt;&gt;, !=, like</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ˜_—‰‰ŽZŽqF<literal>and, or, not</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ƒOƒ‹[ƒv•ª‚¯‚ð•\‚·Š‡ŒÊF<literal>( )</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>in</literal>,
+                    <literal>not in</literal>,
+                    <literal>between</literal>,
+                    <literal>is null</literal>,
+                    <literal>is not null</literal>,
+                    <literal>is empty</literal>,
+                    <literal>is not empty</literal>,
+                    <literal>member of</literal> and 
+                    <literal>not member of</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    "ƒVƒ“ƒvƒ‹"‚Ècase <literal>case ... when ... then ... else ... end</literal>A
+                    "’Tõ“I"‚Ècase <literal>case when ... then ... else ... end</literal> 
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ƒXƒgƒŠƒ“ƒO‚̘AŒ‹ <literal>...||...</literal> ‚Ü‚½‚Í <literal>concat(...,...)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>current_date()</literal>, <literal>current_time()</literal>,
+                    <literal>current_timestamp()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>second(...)</literal>, <literal>minute(...)</literal>, 
+                    <literal>hour(...)</literal>, <literal>day(...)</literal>, 
+                    <literal>month(...)</literal>, <literal>year(...)</literal>,
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    EJB-QL 3.0‚Å’è‹`‚³‚ê‚Ä‚¢‚éŠÖ”‚≉ŽZŽq: <literal>substring(), trim(),
+                    lower(), upper(), length(), locate(), abs(), sqrt(), bit_length()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>coalesce()</literal> ‚Æ <literal>nullif()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ”Žš‚⎞ŠÔ‚Ì’l‚ðString‚ɃRƒ“ƒo[ƒg‚·‚é <literal>str()</literal>j
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    2”Ԗڂ̈ø”‚ªHibernateŒ^‚Ì–¼‘O‚Å‚ ‚é <literal>cast(... as ...)</literal> ‚Æ 
+                    <literal>extract(... from ...)</literal>B
+                    ‚½‚¾‚µŽg—p‚·‚éƒf[ƒ^ƒx[ƒX‚ªANSI <literal>cast()</literal> ‚Æ <literal>extract()</literal> 
+                    ‚ðƒTƒ|[ƒg‚·‚éê‡‚ÉŒÀ‚è‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Œ‹‡‚µ‚½ƒCƒ“ƒfƒbƒNƒX•t‚«‚̃RƒŒƒNƒVƒ‡ƒ“‚Ì•Ê–¼‚É“K—p‚³‚ê‚éHQL‚Ì 
+                    <literal>index()</literal> ŠÖ”B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ƒRƒŒƒNƒVƒ‡ƒ“’l‚̃pƒXŽ®‚ðŽæ‚éHQLŠÖ”F <literal>size(), minelement(), maxelement(), 
+                    minindex(), maxindex()</literal> B
+                    <literal>some, all, exists, any, in</literal> ‚ðŽg‚Á‚ďCü‚·‚邱‚Æ‚ª‚Å‚«‚é“Á•Ê‚È 
+                    <literal>elements()</literal> ‚Æ <literal>indices</literal> ŠÖ”‚ƈꏏ‚ÉŽg‚¢‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>sign()</literal>, <literal>trunc()</literal>, <literal>rtrim()</literal>, <literal>sin()</literal> 
+                    ‚̂悤‚ȃf[ƒ^ƒx[ƒX‚ªƒTƒ|[ƒg‚·‚éSQLƒXƒJƒ‰ŠÖ”B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    JDBCƒXƒ^ƒCƒ‹‚̈ʒuƒpƒ‰ƒ[ƒ^ <literal>?</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    –¼‘O•t‚«ƒpƒ‰ƒ[ƒ^: <literal>:name</literal>, <literal>:start_date</literal>, <literal>:x1</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    SQLƒŠƒeƒ‰ƒ‹F<literal>'foo'</literal>, <literal>69</literal>, <literal>6.66E+2</literal>,
+                    <literal>'1970-01-01 10:00:01.0'</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Java‚Ì <literal>public static final</literal> ’萔F<literal>eg.Color.TABBY</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>in</literal> ‚Æ <literal>between</literal> ‚͈ȉº‚̂悤‚ÉŽg—p‚Å‚«‚Ü‚·B: 
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name between 'A' and 'B']]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+        <para>
+            ‚Ü‚½A”Û’èŒ`‚Å‹Lq‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name not between 'A' and 'B']]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+        <para>
+            “¯—l‚É <literal>is null</literal> ‚â <literal>is not null</literal> ‚Ínull’l‚ðƒeƒXƒg‚·‚邽‚ß‚ÉŽg—p‚Å‚«‚Ü‚·B
+        </para>
+
+        <para>
+            HibernateÝ’èƒtƒ@ƒCƒ‹‚ÅHQL query substitutions‚ð’è‹`‚·‚ê‚΁Aboolean’l‚ðŽ®‚Ì’†‚ÅŠÈ’P‚ÉŽg—p‚Å‚«‚܁BF
+        </para>
+
+        <programlisting><![CDATA[<property name="hibernate.query.substitutions">true 1, false 0</property>]]></programlisting>
+
+        <para>
+            ‚±‚¤‚·‚邱‚Ƃʼnº‹L‚ÌHQL‚ðSQL‚É•ÏŠ·‚·‚é‚Æ‚«‚É <literal>true</literal> ,
+             <literal>false</literal> ƒL[ƒ[ƒh‚Í <literal>1</literal> , <literal>0</literal> ‚É’u‚«Š·‚¦‚ç‚ê‚Ü‚·B:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.alive = true]]></programlisting>
+
+        <para>
+            “Á•Ê‚ȃvƒƒpƒeƒB <literal>size</literal>A‚Ü‚½‚Í“Á•Ê‚Ȋ֐” <literal>size()</literal> 
+            ‚ðŽg‚Á‚ăRƒŒƒNƒVƒ‡ƒ“‚̃TƒCƒY‚ðƒeƒXƒg‚Å‚«‚Ü‚·B:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.kittens.size > 0]]></programlisting>
+
+        <programlisting><![CDATA[from Cat cat where size(cat.kittens) > 0]]></programlisting>
+
+        <para>
+            ƒCƒ“ƒfƒbƒNƒX•t‚«‚̃RƒŒƒNƒVƒ‡ƒ“‚ł́A<literal>minindex</literal> ‚Æ <literal>maxindex</literal> 
+            ŠÖ”‚ðŽg‚Á‚āAƒCƒ“ƒfƒbƒNƒX‚̍ŏ¬’l‚ƍőå’l‚ðŽQÆ‚Å‚«‚Ü‚·B
+            “¯—l‚ɁA<literal>minelement</literal> ‚Æ <literal>maxelement</literal> ‚ðŽg‚Á‚āA
+            Šî–{Œ^‚̃RƒŒƒNƒVƒ‡ƒ“—v‘f‚̍ŏ¬’l‚ƍőå’l‚ðŽQÆ‚Å‚«‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[from Calendar cal where maxelement(cal.holidays) > current_date]]></programlisting>
+        
+        <programlisting><![CDATA[from Order order where maxindex(order.items) > 100]]></programlisting>
+
+        <programlisting><![CDATA[from Order order where minelement(order.items) > 10000]]></programlisting>
+        
+        <para>
+            ƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f‚âƒCƒ“ƒfƒbƒNƒX‚̃Zƒbƒgi<literal>elements</literal> ‚Æ <literal>indices</literal> 
+            ŠÖ”jA‚Ü‚½‚Í•›–â‚¢‡‚킹iŒãqj‚ÌŒ‹‰Ê‚ªŽó‚¯Žæ‚ê‚é‚Æ‚«‚́A
+            SQLŠÖ” <literal>any, some, all, exists, in</literal> ‚ªƒTƒ|[ƒg‚³‚ê‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[select mother from Cat as mother, Cat as kit
+where kit in elements(foo.kittens)]]></programlisting>
+
+        <programlisting><![CDATA[select p from NameList list, Person p
+where p.name = some elements(list.names)]]></programlisting>
+
+        <programlisting><![CDATA[from Cat cat where exists elements(cat.kittens)]]></programlisting>
+
+        <programlisting><![CDATA[from Player p where 3 > all elements(p.scores)]]></programlisting>
+
+        <programlisting><![CDATA[from Show show where 'fizard' in indices(show.acts)]]></programlisting>
+
+        <para>
+            <literal>size</literal>, <literal>elements</literal>, <literal>indices</literal>, 
+            <literal>minindex</literal>, <literal>maxindex</literal>, <literal>minelement</literal>, 
+            <literal>maxelement</literal> ‚ÍHibernate3‚Ìwhereß‚¾‚¯‚Å—˜—p‰Â”\‚Å‚ ‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+        
+        <para>
+            ƒCƒ“ƒfƒbƒNƒX•t‚«‚̃RƒŒƒNƒVƒ‡ƒ“iarrays, lists, mapsj‚Ì—v‘f‚́A
+            ƒCƒ“ƒfƒbƒNƒX‚ÅŽQÆ‚Å‚«‚Ü‚·iwhereß“à‚ł̂݁jB
+        </para>
+        
+        <programlisting><![CDATA[from Order order where order.items[0].id = 1234]]></programlisting>
+
+        <programlisting><![CDATA[select person from Person person, Calendar calendar
+where calendar.holidays['national day'] = person.birthDay
+    and person.nationality.calendar = calendar]]></programlisting>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11]]></programlisting>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ maxindex(order.items) ] = item and order.id = 11]]></programlisting>
+
+        <para>
+            <literal>[]</literal> “à•”‚ÌŽ®‚́AŽZpŽ®‚Å‚à\‚¢‚Ü‚¹‚ñB
+        </para>
+        
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ size(order.items) - 1 ] = item]]></programlisting>
+        
+        <para>
+            ˆê‘Α½ŠÖ˜A‚â’l‚̃RƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f‚ɑ΂µ‚ẮAHQL‚Í‘g‚ݍž‚Ý‚Ì <literal>index()</literal> ŠÖ”‚à—pˆÓ‚µ‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[select item, index(item) from Order order 
+    join order.items item
+where index(item) < 5]]></programlisting>
+
+        <para>
+            ƒx[ƒX‚Æ‚È‚éƒf[ƒ^ƒx[ƒX‚ªƒTƒ|[ƒg‚µ‚Ä‚¢‚éƒXƒJƒ‰[SQLŠÖ”‚ªŽg—p‚Å‚«‚Ü‚·
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like 'FRI%']]></programlisting>
+
+        <para>
+            ‚à‚µ‚Ü‚¾‘S‚Ä‚ð—‰ð‚µ‚Ä‚¢‚È‚¢‚È‚çA‰º‚̃NƒGƒŠ‚ðSQL‚łǂꂾ‚¯’·‚­A“ǂ݂Â炭o—ˆ‚é‚©l‚¦‚Ä‚­‚¾‚³‚¢B: 
+            
+        </para>
+
+        <programlisting><![CDATA[select cust
+from Product prod,
+    Store store
+    inner join store.customers cust
+where prod.name = 'widget'
+    and store.location.name in ( 'Melbourne', 'Sydney' )
+    and prod = all elements(cust.currentOrder.lineItems)]]></programlisting>
+
+        <para>
+            <emphasis>ƒqƒ“ƒg:</emphasis> —Ⴆ‚΂±‚̂悤‚ɏo—ˆ‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
+FROM customers cust,
+    stores store,
+    locations loc,
+    store_customers sc,
+    product prod
+WHERE prod.name = 'widget'
+    AND store.loc_id = loc.id
+    AND loc.name IN ( 'Melbourne', 'Sydney' )
+    AND sc.store_id = store.id
+    AND sc.cust_id = cust.id
+    AND prod.id = ALL(
+        SELECT item.prod_id
+        FROM line_items item, orders o
+        WHERE item.order_id = o.id
+            AND cust.current_order = o.id
+    )]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-ordering">
+        <title>order byß</title>
+
+        <para>
+            ƒNƒGƒŠ‚ª•Ô‚·list‚́A•Ô‚³‚ê‚éƒNƒ‰ƒX‚âƒRƒ“ƒ|[ƒlƒ“ƒg‚Ì”CˆÓ‚Ì‘®«‚É‚æ‚Á‚Ä•À‚בւ¦‚ç‚ê‚Ü‚·BF
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat
+order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
+
+        <para>
+            ƒIƒvƒVƒ‡ƒ“‚Ì <literal>asc</literal> ‚Æ <literal>desc</literal> ‚Í‚»‚ꂼ‚ꏸ‡‚©~‡‚̐®—ñ‚ðŽ¦‚µ‚Ü‚·B
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-grouping">
+        <title>group byß</title>
+
+        <para>
+           W–ñ’l‚ð•Ô‚·ƒNƒGƒŠ‚́A•Ô‚³‚ê‚éƒNƒ‰ƒX‚âƒRƒ“ƒ|[ƒlƒ“ƒg‚Ì”CˆÓ‚̃vƒƒpƒeƒB‚É‚æ‚Á‚ăOƒ‹[ƒv‰»‚Å‚«‚Ü‚·B:
+        </para>
+
+        <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat) 
+from Cat cat
+group by cat.color]]></programlisting>
+
+        <programlisting><![CDATA[select foo.id, avg(name), max(name) 
+from Foo foo join foo.names name
+group by foo.id]]></programlisting>
+
+        <para>
+            <literal>having</literal> ß‚àŽg‚¦‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat) 
+from Cat cat
+group by cat.color 
+having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
+
+        <para>
+            ‚à‚µŽg—p‚·‚éƒf[ƒ^ƒx[ƒX‚ªƒTƒ|[ƒg‚µ‚Ä‚¢‚é‚È‚çA
+            <literal>having</literal> ‚Æ <literal>order by</literal> ß‚ÅSQLŠÖ”‚ƏW–ñŠÖ”‚ªŽg‚¦‚Ü‚·
+            i—Ⴆ‚ÎMySQL‚É‚Í‚ ‚è‚Ü‚¹‚ñjB
+        </para>
+
+        <programlisting><![CDATA[select cat
+from Cat cat
+    join cat.kittens kitten
+group by cat
+having avg(kitten.weight) > 100
+order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
+
+        <para>
+            <literal>group by</literal> ß‚â <literal>order by</literal> ß‚É
+            ŽZpŽ®‚ðŠÜ‚Þ‚±‚Æ‚ª‚Å‚«‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+    </sect1>
+    
+    <sect1 id="queryhql-subqueries" revision="2">
+        <title>•›–â‚¢‡‚킹</title>
+        
+        <para>
+            ƒTƒuƒZƒŒƒNƒg‚ðƒTƒ|[ƒg‚·‚éƒf[ƒ^ƒx[ƒX‚Ì‚½‚߁AHibernate‚Í•›–â‚¢‡‚킹‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·B
+            •›–â‚¢‡‚킹‚ÍŠ‡ŒÊ‚ň͂܂Ȃ¯‚ê‚΂Ȃè‚Ü‚¹‚ñiSQL‚̏W–ñŠÖ”ŒÄ‚яo‚µ‚É‚æ‚鎖‚ª‘½‚¢‚Å‚·jB
+            ŠÖ˜A•›–â‚¢‡‚킹(ŠO•”ƒNƒGƒŠ’†‚Ì•Ê–¼‚ðŽQÆ‚·‚é•›–â‚¢‡‚킹‚Ì‚±‚Æ)‚³‚¦‹–‰Â‚³‚ê‚Ü‚·B 
+        </para>
+
+        <programlisting><![CDATA[from Cat as fatcat 
+where fatcat.weight > ( 
+    select avg(cat.weight) from DomesticCat cat 
+)]]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat as cat 
+where cat.name = some ( 
+    select name.nickName from Name as name 
+)]]></programlisting>
+    
+        <programlisting><![CDATA[from Cat as cat 
+where not exists ( 
+    from Cat as mate where mate.mate = cat 
+)]]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat as cat 
+where cat.name not in ( 
+    select name.nickName from Name as name 
+)]]></programlisting>
+
+        <programlisting><![CDATA[select cat.id, (select max(kit.weight) from cat.kitten kit) 
+from Cat as cat]]></programlisting>
+
+        <para>
+            HQL•›–â‚¢‡‚킹‚́Aselect‚Ü‚½‚Íwhereß‚¾‚¯‚ÅŽg‚í‚ê‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <para>
+            selectƒŠƒXƒg‚É•¡”‚ÌŽ®‚ðŽ‚Â•›–â‚¢‡‚킹‚ɂ́Aƒ^ƒvƒ‹‚ðŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[from Cat as cat 
+where not ( cat.name, cat.color ) in ( 
+    select cat.name, cat.color from DomesticCat cat 
+)]]></programlisting>
+
+        <para>
+            ‚¢‚­‚‚©‚̃f[ƒ^ƒx[ƒXiOracle‚âHSQL‚É‚Í‚ ‚è‚Ü‚¹‚ñj‚ł́A
+            ‘¼‚̃Rƒ“ƒeƒLƒXƒg‚Å‚àƒ^ƒvƒ‹‚ªŽg‚¦‚Ü‚·B
+            —Ⴆ‚΁AƒNƒGƒŠƒRƒ“ƒ|[ƒlƒ“ƒg‚â•¡‡ƒ†[ƒUŒ^‚É‚¨‚¢‚Ä‚Å‚·B
+        </para>
+
+        <programlisting><![CDATA[from Person where name = ('Gavin', 'A', 'King')]]></programlisting>
+        
+        <para>
+            “¯“™‚Å‚·‚ªA‚æ‚èç’·‚ȃNƒGƒŠ‚Å‚·F
+        </para>
+        
+        <programlisting><![CDATA[from Person where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')]]></programlisting>
+
+        <para>
+            ‚±‚̂悤‚È‚±‚Æ‚ð‚µ‚½‚­‚È‚¢‚Ì‚É‚Í2‚‚̗—R‚ª‚ ‚è‚Ü‚·F
+            1‚–ڂ́Aƒf[ƒ^ƒx[ƒXƒvƒ‰ƒbƒgƒtƒH[ƒ€ŠÔ‚ÅŠ®‘S‚Ȍ݊·«‚Í‚È‚¢‚©‚ç‚Å‚·B
+            2‚–ڂ́AƒNƒGƒŠ‚ªƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚̃vƒƒpƒeƒB‚̏‡˜‚Ɉˑ¶‚·‚é‚©‚ç‚Å‚·B
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-examples">
+        <title>HQL‚Ì—á</title>
+        
+        <para>
+            HibernateƒNƒGƒŠ‚Í”ñí‚É‹­—Í‚Å•¡ŽG‚É‚Å‚«‚Ü‚·BŽÀÛAƒNƒGƒŠŒ¾Œê‚̈З͂ÍHibernate‚ÌŽå—v‚ȃZ[ƒ‹ƒXƒ|ƒCƒ“ƒg‚̈ê‚‚ł·B
+            ‚±‚±‚ɍŋ߂̃vƒƒWƒFƒNƒg‚ÅŽg—p‚µ‚½ƒNƒGƒŠ‚Æ”ñí‚É‚æ‚­Ž—‚½—Ⴊ‚ ‚è‚Ü‚·B
+            ‚Ù‚Æ‚ñ‚ǂ̃NƒGƒŠ‚Í‚±‚ê‚ç‚Ì—á‚æ‚èŠÈ’P‚É‹Lq‚Å‚«‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢!
+        </para>
+        
+        <para>
+            ˆÈ‰º‚̃NƒGƒŠ‚Í“Á’è‚̌ڋq‚Æ—^‚¦‚ç‚ꂽÅ¬‚̍‡Œv’l‚ɑ΂·‚é–¢•¥‚¢’•¶‚Ì’•¶IDA
+            ¤•i‚̐”A’•¶‚̍‡Œv‚ð‡Œv’l‚Ő®—ñ‚µ‚Ä•Ô‚µ‚Ü‚·B
+            ‰¿Ši‚ðŒˆ’è‚·‚éÛAŒ»Ý‚̃Jƒ^ƒƒO‚ðŽg‚¢‚Ü‚·BŒ‹‰Ê‚Æ‚µ‚Ä•Ô‚³‚ê‚éSQLƒNƒGƒŠ‚Í
+            <literal>ORDER</literal>, <literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>,
+            <literal>CATALOG</literal> ‚¨‚æ‚Ñ <literal>PRICE</literal> ƒe[ƒuƒ‹‚ɑ΂µ4‚Â‚Ì“à•”Œ‹‡‚Æ
+            (ŠÖ˜A‚µ‚È‚¢)•›–â‚¢‡‚킹‚ðŽ‚¿‚Ü‚·B
+        </para>
+        
+        <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+    join order.lineItems as item
+    join item.product as product,
+    Catalog as catalog
+    join catalog.prices as price
+where order.paid = false
+    and order.customer = :customer
+    and price.product = product
+    and catalog.effectiveDate < sysdate
+    and catalog.effectiveDate >= all (
+        select cat.effectiveDate 
+        from Catalog as cat
+        where cat.effectiveDate < sysdate
+    )
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+        
+        <para>
+            ‰½‚Ä‹‘å‚ȃNƒGƒŠ‚È‚Ì‚Å‚µ‚傤! •’iŽ„‚Í•›–â‚¢‡‚킹‚ð‚ ‚Ü‚èŽg‚¢‚Ü‚¹‚ñB‚µ‚½‚ª‚Á‚ÄŽ„‚̃NƒGƒŠ‚ÍŽÀÛ‚ɂ͈ȉº‚̂悤‚É‚È‚è‚Ü‚·B:
+        </para>
+        
+        <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+    join order.lineItems as item
+    join item.product as product,
+    Catalog as catalog
+    join catalog.prices as price
+where order.paid = false
+    and order.customer = :customer
+    and price.product = product
+    and catalog = :currentCatalog
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+        
+        <para>
+            ŽŸ‚̃NƒGƒŠ‚ÍŠeƒXƒe[ƒ^ƒX‚ÌŽx•¥‚¢”‚𐔂¦‚Ü‚·B‚½‚¾‚µ‚·‚ׂĂ̎x•¥‚¢‚ªŒ»Ý‚Ì—˜—pŽÒ‚É‚æ‚é
+            ÅV‚̃Xƒe[ƒ^ƒX•ÏX‚Å‚ ‚é <literal>AWAITING_APPROVAL</literal> ‚Å‚ ‚éê‡‚ðœ‚«‚Ü‚·B
+            ‚±‚̃NƒGƒŠ‚Í2‚Â‚Ì“à•”Œ‹‡‚Æ <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal> ‚¨‚æ‚Ñ 
+            <literal>PAYMENT_STATUS_CHANGE</literal> ƒe[ƒuƒ‹‚ɑ΂·‚éŠÖ˜A•›–â‚¢‡‚킹‚ð”õ‚¦‚½SQLƒNƒGƒŠ‚É•ÏŠ·‚³‚ê‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[select count(payment), status.name 
+from Payment as payment 
+    join payment.currentStatus as status
+    join payment.statusChanges as statusChange
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+    or (
+        statusChange.timeStamp = ( 
+            select max(change.timeStamp) 
+            from PaymentStatusChange change 
+            where change.payment = payment
+        )
+        and statusChange.user <> :currentUser
+    )
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+        <para>
+            ‚à‚µŽ„‚ªset‚Ì‘ã‚í‚è‚Élist‚Æ‚µ‚Ä <literal>statusChanges</literal> ƒRƒŒƒNƒVƒ‡ƒ“‚ð
+            ƒ}ƒbƒsƒ“ƒO‚µ‚½‚È‚ç‚΁A‚Í‚é‚©‚ÉŠÈ’P‚ɃNƒGƒŠ‚ð‹Lq‚Å‚«‚é‚Å‚µ‚傤B
+        </para>
+    
+        <programlisting><![CDATA[select count(payment), status.name 
+from Payment as payment
+    join payment.currentStatus as status
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+    or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+        <para>
+            ŽŸ‚̃NƒGƒŠ‚ÍŒ»Ý‚̃†[ƒU‚ªŠ‘®‚·‚é‘gD‚ɑ΂·‚éƒAƒJƒEƒ“ƒg‚¨‚æ‚Ñ–¢•¥‚¢‚ÌŽx•¥‚¢‚ð
+            ‚·‚ׂĕԂ·MS SQL Server
+            ‚Ì <literal>isNull()</literal> ŠÖ”‚ðŽg—p‚µ‚Ä‚¢‚Ü‚·B
+            ‚±‚̃NƒGƒŠ‚Í3‚Â‚Ì“à•”Œ‹‡‚Æ1‚‚̊O•”Œ‹‡ A
+            ‚»‚µ‚Ä <literal>ACCOUNT</literal>, <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal>,
+            <literal>ACCOUNT_TYPE</literal>, <literal>ORGANIZATION</literal> ‚¨‚æ‚Ñ 
+            <literal>ORG_USER</literal> ƒe[ƒuƒ‹‚ɑ΂·‚é•›–â‚¢‡‚킹Ž‚Á‚½SQL‚É•ÏŠ·‚³‚ê‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[select account, payment
+from Account as account
+    left outer join account.payments as payment
+where :currentUser in elements(account.holder.users)
+    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+        <para>
+            ‚¢‚­‚‚©‚̃f[ƒ^ƒx[ƒX‚ɂ‚¢‚ẮA(ŠÖ˜A‚³‚¹‚ç‚ꂽ)•›–â‚¢‡‚킹‚ÌŽg—p‚ð”ð‚¯‚é•K—v‚ª‚ ‚é‚Å‚µ‚傤B
+        </para>
+
+        <programlisting><![CDATA[select account, payment
+from Account as account
+    join account.holder.users as user
+    left outer join account.payments as payment
+where :currentUser = user
+    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+   </sect1>
+
+    <sect1 id="queryhql-bulk" revision="2">
+        <title>‘å—Ê‚ÌUPDATE‚ÆDELETE</title>
+
+        <para>
+            HQL‚͍¡‚Í <literal>update</literal> ‚Æ <literal>delete</literal>A<literal>insert ... select ...</literal>
+            ƒXƒe[ƒgƒƒ“ƒg‚ðHQL‚É“ü‚ê‚邱‚Æ‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·B
+            <xref linkend="batch-direct"/> ‚ɏڍׂª‚ ‚è‚Ü‚·B
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-tipstricks">
+        <title>Tips &amp; Tricks</title>
+
+        <para>
+            ŽÀÛ‚ÉŒ‹‰Ê‚ð•Ô‚³‚È‚­‚Ä‚àƒNƒGƒŠ‚ÌŒ‹‰Ê”‚𐔂¦‚邱‚Æ‚ª‚Å‚«‚Ü‚·B:
+        </para>
+
+        <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue()]]></programlisting>
+
+        <para>
+            ƒRƒŒƒNƒVƒ‡ƒ“‚̃TƒCƒY‚É‚æ‚茋‰Ê‚ð•À‚בւ¦‚邽‚߂ɂ͈ȉº‚̃NƒGƒŠ‚ðŽg—p‚µ‚Ü‚·B:
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User as usr 
+    left join usr.messages as msg
+group by usr.id, usr.name
+order by count(msg)]]></programlisting>
+
+        <para>
+            Žg—p‚µ‚Ä‚¢‚éƒf[ƒ^ƒx[ƒX‚ªƒTƒuƒZƒŒƒNƒg‚ðƒTƒ|[ƒg‚·‚éê‡AƒNƒGƒŠ‚Ìwhereß‚ŃTƒCƒY‚É‚æ‚é‘I‘ððŒ‚ðÝ’è‚Å‚«‚Ü‚·:
+        </para>
+
+        <programlisting><![CDATA[from User usr where size(usr.messages) >= 1]]></programlisting>
+
+        <para>
+            Žg—p‚µ‚Ä‚¢‚éƒf[ƒ^ƒx[ƒX‚ªƒTƒuƒZƒŒƒNƒg‚ðƒTƒ|[ƒg‚µ‚È‚¢ê‡‚́AŽŸ‚̃NƒGƒŠ‚ðŽg—p‚µ‚Ä‚­‚¾‚³‚¢:  
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User usr.name
+    join usr.messages msg
+group by usr.id, usr.name
+having count(msg) >= 1]]></programlisting>
+
+        <para>
+            “à•”Œ‹‡‚ð‚µ‚Ä‚¢‚邹‚¢‚ŏã‚Ì‰ðŒˆ–@‚ªmessage‚ÌŒ”‚ª
+            ƒ[ƒ‚Ì <literal>User</literal> ‚ð•Ô‚·‚±‚Æ‚ª‚Å‚«‚È‚¢‚È‚ç‚΁AˆÈ‰º‚ÌŒ`Ž®‚ªŽg‚¦‚Ü‚·B
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+    left join usr.messages as msg
+group by usr.id, usr.name
+having count(msg) = 0]]></programlisting>
+
+        <para>
+            JavaBean‚̃vƒƒpƒeƒB‚́A–¼‘O•t‚«‚̃NƒGƒŠƒpƒ‰ƒ[ƒ^‚ÉŒ‹‚т‚¯‚邱‚Æ‚ªo—ˆ‚Ü‚·BF
+        </para>
+
+        <programlisting><![CDATA[Query q = s.createQuery("from foo Foo as foo where foo.name=:name and foo.size=:size");
+q.setProperties(fooBean); // fooBean has getName() and getSize()
+List foos = q.list();]]></programlisting>
+
+        <para>
+            ƒRƒŒƒNƒVƒ‡ƒ“‚̓tƒBƒ‹ƒ^•t‚« <literal>Query</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽg—p‚·‚邱‚ƂŃy[ƒW‚ð‚‚¯‚邱‚Æ‚ª‚Å‚«‚Ü‚·B:
+        </para>
+
+        <programlisting><![CDATA[Query q = s.createFilter( collection, "" ); // the trivial filter
+q.setMaxResults(PAGE_SIZE);
+q.setFirstResult(PAGE_SIZE * pageNumber);
+List page = q.list();]]></programlisting>
+
+        <para>
+            ƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f‚̓NƒGƒŠƒtƒBƒ‹ƒ^‚ðŽg‚Á‚āA•À‚בւ¦‚âƒOƒ‹[ƒv•ª‚¯‚ªo—ˆ‚Ü‚·B:
+        </para>
+        
+        <programlisting><![CDATA[Collection orderedCollection = s.filter( collection, "order by this.amount" );
+Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );]]></programlisting>
+
+        <para>
+            ƒRƒŒƒNƒVƒ‡ƒ“‚ð‰Šú‰»‚¹‚¸‚ɃRƒŒƒNƒVƒ‡ƒ“‚̃TƒCƒY‚𓾂邱‚Æ‚ª‚Å‚«‚Ü‚·B: 
+        </para>
+
+        <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue();]]></programlisting>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/query_sql.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/query_sql.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/query_sql.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,724 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="querysql" revision="2">
+  <title>ƒlƒCƒeƒBƒuSQL</title>
+
+  <para>ƒf[ƒ^ƒx[ƒX‚̃lƒCƒeƒBƒuSQL•ûŒ¾‚ðŽg‚Á‚ăNƒGƒŠ‚ð•\Œ»‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+  ƒNƒGƒŠƒqƒ“ƒg‚âOracle‚Ì <literal>CONNECT</literal> ƒL[ƒ[ƒh‚̂悤‚ɁA
+  ƒf[ƒ^ƒx[ƒX“ÆŽ©‚Ì‹@”\‚ð—˜—p‚µ‚½‚¢‚Æ‚«‚ÉŽg‚¦‚Ü‚·B
+  SQL/JDBC‚𒼐ڎg—p‚µ‚Ä‚¢‚éƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚©‚çHibernate‚ւ̈ڍs‚à—eˆÕ‚É‚µ‚Ä‚¢‚Ü‚·B</para>
+
+  <para>Hibernate3‚ł́A¶¬AXVAíœA“ǂݍž‚ݏˆ—‚̂悤‚È‚·‚ׂĂÌ
+  SQLiƒXƒgƒAƒhƒvƒƒV[ƒWƒƒ‚ðŠÜ‚ށj‚ðŽè‘‚«‚Å‚«‚Ü‚·B</para>
+
+  <sect1 id="querysql-creating" revision="4">
+    <title><literal>SQLQuery</literal> ‚ÌŽg—p</title>
+
+    <para>ƒlƒCƒeƒBƒu‚ÈSQLƒNƒGƒŠ‚ÌŽÀs‚Í <literal>SQLQuery</literal>
+    ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ð’Ê‚µ‚ЧŒä‚µ‚Ü‚·B
+    <literal>SQLQuery</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚Í
+    <literal>Session.createSQLQuery()</literal> ‚ðŒÄ‚яo‚µ‚Ď擾‚µ‚Ü‚·B
+    ‚±‚ÌAPI‚ðŽg‚Á‚Ä–â‚¢‡‚킹‚·‚é•û–@‚ðˆÈ‰º‚Åà–¾‚µ‚Ü‚·B</para>
+
+    <sect2>
+      <title>ƒXƒJƒ‰[‚̃NƒGƒŠ</title>
+
+      <para>Å‚àŠî–{“I‚ÈSQLƒNƒGƒŠ‚̓XƒJƒ‰[i’lj‚̃ŠƒXƒg‚𓾂邱‚Æ‚Å‚·B</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").list();
+sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
+]]></programlisting>
+
+      <para>‚±‚ê‚ç‚Í‚Ç‚¿‚ç‚àACATSƒe[ƒuƒ‹‚ÌŠeƒJƒ‰ƒ€‚̃XƒJƒ‰[’l‚ðŠÜ‚Þ
+      Object”z—ñiObject[]j‚̃ŠƒXƒg‚ð•Ô‚µ‚Ü‚·B
+      •Ô‚·ƒXƒJƒ‰[’l‚ÌŽÀÛ‚̏‡”Ô‚ÆŒ^‚𐄒肷‚邽‚߂ɁA
+      Hibernate‚ÍResultSetMetadata‚ðŽg—p‚µ‚Ü‚·B</para>
+
+      <para><literal>ResultSetMetadata</literal> ‚ðŽg—p‚·‚éƒI[ƒo[ƒwƒbƒh‚ð”ð‚¯‚é‚½‚߁A
+      ‚à‚µ‚­‚Í’P‚ɉ½‚ª•Ô‚³‚ê‚é‚©–¾Šm‚É‚·‚邽‚߁A<literal>addScalar()</literal>
+      ‚ðŽg‚¦‚Ü‚·B</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME", Hibernate.STRING)
+ .addScalar("BIRTHDATE", Hibernate.DATE)
+]]></programlisting>
+
+      <para>‚±‚̃NƒGƒŠ‚ÅŽw’肳‚ê‚Ä‚¢‚é‚à‚Ì‚ð‰º‹L‚ÉŽ¦‚µ‚Ü‚·B</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>SQLƒNƒGƒŠ•¶Žš—ñ</para>
+        </listitem>
+
+        <listitem>
+          <para>•Ô‚³‚ê‚éƒJƒ‰ƒ€‚ÆŒ^</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>‚±‚ê‚Í‚Ü‚¾Object”z—ñ‚ð•Ô‚µ‚Ü‚·‚ªA
+      <literal>ResultSetMetdata</literal> ‚ðŽg—p‚µ‚Ü‚¹‚ñB
+      ‚½‚¾‚µA‚»‚Ì‘ã‚í‚è‚ÉŠî‘b‚É‚ ‚郊ƒUƒ‹ƒgƒZƒbƒg‚©‚ç
+      IDANAMEABIRTHDATE ƒJƒ‰ƒ€‚ð‚»‚ê‚¼‚ê
+      LongAStringAShort ‚Æ‚µ‚Ä–¾Ž¦“I‚Ɏ擾‚µ‚Ü‚·B
+      ‚±‚ê‚Í‚R‚‚̃Jƒ‰ƒ€‚ð•Ô‚·‚Ì‚Ý‚Å‚ ‚邱‚Æ‚àˆÓ–¡‚µ‚Ü‚·B
+      ‚½‚Æ‚¦AƒNƒGƒŠ‚ª <literal>*</literal> ‚ðŽg—p‚µA
+      —ñ‹“‚µ‚½‚R‚‚æ‚葽‚­‚̃Jƒ‰ƒ€‚ð•Ô‚¹‚é‚Æ‚µ‚Ä‚à‚Å‚·B</para>
+
+      <para>ƒXƒJƒ‰[‚ÌŒ^î•ñ‚ðÈ‚­‚±‚Æ‚à‚Å‚«‚Ü‚·B</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME")
+ .addScalar("BIRTHDATE")
+]]></programlisting>
+
+      <para>
+      ‚±‚ê‚Í–{Ž¿“I‚É‘O‚Æ“¯‚¶ƒNƒGƒŠ‚Å‚·‚ªAA
+      NAME ‚Æ BIRTHDATE ‚ÌŒ^‚ðŒˆ‚ß‚é‚½‚ß‚É <literal>ResultSetMetaData</literal>
+      ‚ðŽg—p‚µ‚Ü‚·Bˆê•ûAID ‚ÌŒ^‚Í–¾Ž¦“I‚ÉŽw’肳‚ê‚Ä‚¢‚Ü‚·B
+      </para>
+
+      <para>
+      ResultSetMetaData ‚©‚ç•Ô‚³‚ê‚é java.sql.Types ‚ð Hibernate ‚ÌŒ^‚É
+      ƒ}ƒbƒsƒ“ƒO‚·‚邱‚Ƃ́ADialect ‚ª§Œä‚µ‚Ü‚·B
+      –¾Ž¦‚³‚ꂽŒ^‚ªƒ}ƒbƒsƒ“ƒO‚³‚ê‚Ä‚¢‚È‚¢‚©AŒ‹‰Ê‚ÌŒ^‚ªŠú‘Ò‚µ‚½‚à‚̂ƈقȂéê‡A
+      Dialect ‚Ì <literal>registerHibernateType</literal> ‚ðŒÄ‚яo‚µA
+      ƒJƒXƒ^ƒ}ƒCƒY‚Å‚«‚Ü‚·B
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>ƒGƒ“ƒeƒBƒeƒB‚̃NƒGƒŠ</title>
+
+      <para>‚±‚±‚܂ł̃NƒGƒŠ‚́A‚·‚ׂăXƒJƒ‰[’l‚ð•Ô‚·‚à‚Ì‚Å‚µ‚½B
+      Šî–{“I‚ɁAƒŠƒUƒ‹ƒgƒZƒbƒg‚©‚çu–¢‰ÁHv‚Ì’l‚ð•Ô‚µ‚Ü‚·B
+      ˆÈ~‚ł́A<literal>addEntity()</literal> ‚É‚æ‚èAƒlƒCƒeƒBƒuSQLƒNƒGƒŠ‚©‚ç
+      ƒGƒ“ƒeƒBƒeƒBƒIƒuƒWƒFƒNƒg‚ðŽæ“¾‚·‚é•û–@‚ðŽ¦‚µ‚Ü‚·B</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class);
+sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);
+]]></programlisting>
+
+      <para>‚±‚̃NƒGƒŠ‚ÅŽw’肳‚ê‚Ä‚¢‚é‚à‚Ì‚ð‰º‹L‚ÉŽ¦‚µ‚Ü‚·B</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>SQLƒNƒGƒŠ•¶Žš—ñ</para>
+        </listitem>
+
+        <listitem>
+          <para>ƒNƒGƒŠ‚ª•Ô‚·ƒGƒ“ƒeƒBƒeƒB‚ÆSQLƒe[ƒuƒ‹‚Ì•Ê–¼
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>Cat‚ªID, NAME, BIRTHDATE‚̃Jƒ‰ƒ€‚ðŽg‚Á‚ăNƒ‰ƒX‚Ƀ}ƒbƒsƒ“ƒO‚³‚ê‚éê‡A
+      ã‹L‚̃NƒGƒŠ‚Í‚Ç‚¿‚ç‚àA—v‘f‚ªCatƒGƒ“ƒeƒBƒeƒB‚Å‚ ‚郊ƒXƒg‚ð•Ô‚µ‚Ü‚·B</para>
+
+      <para>ƒGƒ“ƒeƒBƒeƒB‚ð•Ê‚̃Gƒ“ƒeƒBƒeƒB‚É <literal>‘½‘Έê</literal> ‚Ń}ƒbƒsƒ“ƒO‚µ‚Ä‚¢‚éê‡‚́A
+      ƒlƒCƒeƒBƒuƒNƒGƒŠ‚ðŽÀs‚·‚éÛ‚ɁA‚±‚̕ʂ̃Gƒ“ƒeƒBƒeƒB‚ð•Ô‚·‚±‚Æ‚à—v‹‚µ‚Ü‚·B
+      ‚³‚à‚È‚¯‚ê‚΁Aƒf[ƒ^ƒx[ƒXŒÅ—L‚́ucolumn not found(ƒJƒ‰ƒ€‚ªŒ©‚‚©‚è‚Ü‚¹‚ñ)vƒGƒ‰[‚ª”­¶‚µ‚Ü‚·B
+      * •\‹L‚ðŽg—p‚µ‚½Û‚́A’ljÁ‚̃Jƒ‰ƒ€‚ªŽ©“®“I‚É•Ô‚³‚ê‚Ü‚·‚ªA
+      ŽŸ‚Ì—á‚̂悤‚ɁA<literal>Dog</literal> ‚É <literal>‘½‘Έê</literal> ‚Å‚ ‚邱‚Æ‚ð
+      –¾Ž¦‚·‚邱‚Æ‚ðŽ„‚½‚¿‚͍D‚Ý‚Ü‚·B</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);
+]]></programlisting>
+
+      <para>‚±‚ê‚É‚æ‚è cat.getDog() ‚ª³‚µ‚­‹@”\‚µ‚Ü‚·B</para>
+    </sect2>
+
+    <sect2>
+      <title>ŠÖ˜A‚ƃRƒŒƒNƒVƒ‡ƒ“‚Ì‘€ì</title>
+
+      <para>ƒvƒƒLƒV‚ð‰Šú‰»‚·‚邽‚ß‚Ì—]•ª‚ȏˆ—‚ð”ð‚¯‚é‚½‚߁A
+      <literal>Dog</literal> ‚Ì’†‚Å‘¦ŽžŒ‹‡‚Å‚«‚Ü‚·B
+      ‚±‚ê‚Í <literal>addJoin()</literal> ƒƒ\ƒbƒh‚É‚æ‚ès‚¢‚Ü‚·B
+      ŠÖ˜A‚à‚µ‚­‚̓RƒŒƒNƒVƒ‡ƒ“‚ÉŒ‹‡‚Å‚«‚Ü‚·B
+      </para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dog");
+]]></programlisting>
+
+      <para>‚±‚Ì—á‚Ì’†‚ŁA•Ô‚³‚ê‚é <literal>Cat</literal> ‚́A
+      ƒf[ƒ^ƒx[ƒX‚Ö‚Ì—]•ªˆ—‚È‚µ‚ŁA
+      Š®‘S‚ɏ‰Šú‰»‚³‚ꂽ <literal>dog</literal> ƒvƒƒpƒeƒB‚ðŽ‚¿‚Ü‚·B
+      Œ‹‡‘Ώۂ̃vƒƒpƒeƒB‚ւ̃pƒX‚ðŽw’è‚Å‚«‚é‚悤‚ɁA
+      •Ê–¼iucatvj‚ð’ljÁ‚µ‚½‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+      ƒRƒŒƒNƒVƒ‡ƒ“‚Ì‘¦ŽžŒ‹‡‚à“¯‚¶‚悤‚É‚Å‚«‚Ü‚·B
+      ‚½‚Æ‚¦‚΁A<literal>Cat</literal> ‚ªˆê‘Α½‚Å <literal>Dog</literal>
+      ‚ðŽ‚Á‚Ä‚¢‚½ê‡AŽŸ‚̂悤‚É‚È‚è‚Ü‚·B</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dogs");
+]]></programlisting>
+
+      <para>Œ»Ý‚Ì‚Æ‚±‚ëA
+      Hibernate‚ÅŽg‚¢‚â‚·‚­‚·‚邽‚ß‚ÌSQLƒNƒGƒŠ‚ÌŠg’£‚È‚µ‚ɁA
+      ƒlƒCƒeƒBƒuƒNƒGƒŠ‚ʼn½‚©‚ð‰Â”\‚É‚·‚éŒÀŠE‚É—ˆ‚Ä‚¢‚Ü‚·B
+      “¯‚¶Œ^‚̃Gƒ“ƒeƒBƒeƒB‚𕡐”•Ô‚·Û‚âAƒfƒtƒHƒ‹ƒg‚Ì•Ê–¼‚â—ñ–¼‚ŏ\•ª‚Å‚Í‚È‚¢ê‡‚ɁA
+      –â‘è‚Í‹N‚±‚èŽn‚ß‚Ü‚·B      
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>•¡”ƒGƒ“ƒeƒBƒeƒB‚̎擾</title>
+
+      <para>‚±‚±‚܂ł́AƒŠƒUƒ‹ƒgƒZƒbƒg‚̃Jƒ‰ƒ€–¼‚́A
+      ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ÅŽw’肳‚ꂽƒJƒ‰ƒ€–¼‚Æ“¯‚¶‚Å‚ ‚é‚Ɖ¼’肵‚Ä‚¢‚Ü‚µ‚½B
+      •¡”‚̃e[ƒuƒ‹‚ª“¯‚¶ƒJƒ‰ƒ€–¼‚ðŽ‚Âê‡‚ª‚ ‚邽‚߁A
+      •¡”ƒe[ƒuƒ‹‚ðŒ‹‡‚·‚éSQLƒNƒGƒŠ‚Å–â‘è‚Æ‚È‚éê‡‚ª‚ ‚è‚Ü‚·B</para>
+
+      <para>‰º‹L‚̂悤‚ȁiŽ¸”s‚µ‚»‚¤‚ȁjƒNƒGƒŠ‚ł́A
+      ƒJƒ‰ƒ€•Ê–¼ƒCƒ“ƒWƒFƒNƒVƒ‡ƒ“icolumn alias injectionj‚ª•K—v‚Å‚·B</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT c.*, m.*  FROM CATS c, CATS m WHERE c.MOTHER_ID = m.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+]]></programlisting>
+
+      <para>‚±‚̃NƒGƒŠ‚̈Ӑ}‚́A
+      ‚Ps‚²‚Æ‚É‚Q‚‚ÌCatƒCƒ“ƒXƒ^ƒ“ƒXA‚‚܂è”L‚Æ‚»‚Ì•êe‚ð•Ô‚·‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+      “¯‚¶ƒJƒ‰ƒ€–¼‚Ƀ}ƒbƒsƒ“ƒO‚·‚邱‚Æ‚É‚æ‚è–¼‘O‚ªÕ“Ë‚·‚邽‚߁A‚±‚̃NƒGƒŠ‚ÍŽ¸”s‚µ‚Ü‚·B
+      ƒx[ƒ^ƒx[ƒX‚É‚æ‚Á‚ẮA•Ô‚³‚ê‚éƒJƒ‰ƒ€‚Ì•Ê–¼‚ª "c.ID"A"c.NAME" ‚È‚Ç‚ÌŒ`Ž®‚Å‚ ‚èA
+      ƒ}ƒbƒsƒ“ƒO‚ÅŽw’肳‚ꂽƒJƒ‰ƒ€i"ID" ‚Æ "NAME"j‚Æ“™‚µ‚­‚È‚¢‚½‚߁AŽ¸”s‚µ‚Ü‚·B</para>
+
+
+      <para>‰º‹L‚ÌŒ`Ž®‚́AƒJƒ‰ƒ€–¼‚ªd•¡‚µ‚Ä‚à‘åä•v‚Å‚·B</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT {cat.*}, {mother.*}  FROM CATS c, CATS m WHERE c.MOTHER_ID = m.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+]]></programlisting>
+
+      <para>‚±‚̃NƒGƒŠ‚ÅŽw’肳‚ê‚Ä‚¢‚é‚à‚Ì‚ð‰º‹L‚ÉŽ¦‚µ‚Ü‚·B</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>SQLƒNƒGƒŠ•¶Žš—ñ
+                iHibernate‚ªƒJƒ‰ƒ€‚Ì•Ê–¼‚ð‘}“ü‚·‚邽‚߂̃vƒŒ[ƒXƒzƒ‹ƒ_‚ðŠÜ‚ށj</para>
+        </listitem>
+
+        <listitem>
+          <para>ƒNƒGƒŠ‚É‚æ‚Á‚Ä•Ô‚³‚ê‚éƒGƒ“ƒeƒBƒeƒB</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>ã‹L‚ÅŽg—p‚µ‚Ä‚¢‚é {cat.*} ‚Æ {mother.*} ‚Æ‚¢‚¤•\‹L‚́A
+      u‚·‚ׂẴvƒƒpƒeƒBv‚ð•\‚·È—ªŒ`‚Å‚·B
+      ‘ã‚í‚è‚ɁA–¾Ž¦“I‚ɃJƒ‰ƒ€‚ð—ñ‹“‚µ‚Ä‚à‚æ‚¢‚Å‚·‚ªA
+      ‚»‚̏ꍇ‚́AHibernate‚ÉŠeƒvƒƒpƒeƒB‚ɑΉž‚·‚éSQLƒJƒ‰ƒ€‚Ì•Ê–¼‚ð‘}“ü‚³‚¹‚é‚ׂ«‚Å‚µ‚傤B
+      ƒJƒ‰ƒ€‚Ì•Ê–¼‚Ì‚½‚߂̃vƒŒ[ƒXƒzƒ‹ƒ_‚́Aƒe[ƒuƒ‹‚Ì•Ê–¼‚É‚æ‚Á‚ďCü‚³‚ꂽƒvƒƒpƒeƒB–¼‚Å‚·B
+      ‰º‹L‚Ì—á‚ł́A•Ê‚̃e[ƒuƒ‹ cat_log ‚©‚ç
+      ƒ}ƒbƒsƒ“ƒOƒƒ^ƒf[ƒ^‚Å’è‹`‚³‚ꂽ Cat ‚Æ‚»‚Ì•êe‚𕜌³‚µ‚Ü‚·B
+      ‚à‚µD‚Þ‚È‚çAwhereß‚Ì’†‚Å‚àAƒvƒƒpƒeƒB‚Ì•Ê–¼‚ðŽg‚¦‚Ü‚·B</para>
+
+      <programlisting><![CDATA[String sql = "SELECT ID as {c.id}, NAME as {c.name}, " + 
+         "BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
+         "FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
+
+List loggedCats = sess.createSQLQuery(sql)
+        .addEntity("cat", Cat.class)
+        .addEntity("mother", Cat.class).list()
+]]></programlisting>
+
+      <sect3 id="querysql-aliasreferences" revision="2">
+        <title>•Ê–¼‚ƃvƒƒpƒeƒB‚̃Šƒtƒ@ƒŒƒ“ƒX</title>
+
+        <para>‘½‚­‚̏ꍇAã‹L‚̂悤‚È•Ê–¼ƒCƒ“ƒWƒFƒNƒVƒ‡ƒ“‚ª•K—v‚Å‚·B
+        ‚½‚¾‚µA•¡‡ƒvƒƒpƒeƒBAŒp³Ž¯•ÊŽqAƒRƒŒƒNƒVƒ‡ƒ“‚Ȃǂ̂悤‚È
+        ‚æ‚è•¡ŽG‚ȃ}ƒbƒsƒ“ƒO‚ÆŠÖ˜A‚·‚éƒNƒGƒŠ‚ª‚È‚¯‚ê‚΂ł·B
+        ‚ ‚é“Á’è‚Ì•Ê–¼‚ðŽg—p‚·‚邱‚Æ‚É‚æ‚èAHibernate‚Í“KØ‚È•Ê–¼‚ð‘}“ü‚Å‚«‚Ü‚·B</para>
+
+        <para>•Ê–¼ƒCƒ“ƒWƒFƒNƒVƒ‡ƒ“‚Æ‚µ‚ÄŽg—p‚Å‚«‚é‚à‚Ì‚ð‰º•\‚ÉŽ¦‚µ‚Ü‚·B
+        ’ˆÓF‰º•\‚Ì•Ê–¼‚͈ê—á‚Å‚·B
+        ‚»‚ꂼ‚ê‚Ì•Ê–¼‚͈êˆÓ‚Å‚ ‚èAŽg—p‚·‚éÛ‚É‚Í‚¨‚»‚ç‚­ˆÙ‚È‚é–¼‘O‚ðŽ‚¿‚Ü‚·B</para>
+ 
+        <table frame="topbot" id="aliasinjection-summary">
+          <title>•Ê–¼‚É‘}“ü‚·‚é–¼‘O</title>
+
+          <tgroup cols="3">
+            <colspec colwidth="1*" />
+
+            <colspec colwidth="1*" />
+
+            <colspec colwidth="2.5*" />
+
+            <thead>
+              <row>
+                <entry>à–¾</entry>
+                <entry>\•¶</entry>
+                <entry>—á</entry>
+              </row>
+            </thead>
+            <tbody>
+              <row>
+                <entry>’Pƒ‚ȃvƒƒpƒeƒB</entry>
+                <entry><literal>{[aliasname].[propertyname]}</literal></entry>
+                <entry><literal>A_NAME as {item.name}</literal></entry>
+              </row>
+              <row>
+                <entry>•¡‡ƒvƒƒpƒeƒB</entry>
+                <entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
+                <entry><literal>CURRENCY as {item.amount.currency}, VALUE as
+                {item.amount.value}</literal></entry>
+              </row>
+              <row>
+                <entry>ƒGƒ“ƒeƒBƒeƒB‚̃Nƒ‰ƒX‚ðŽ¯•Ê‚·‚é’l</entry>
+                <entry><literal>{[aliasname].class}</literal></entry>
+                <entry><literal>DISC as {item.class}</literal></entry>
+              </row>
+              <row>
+                <entry>ƒGƒ“ƒeƒBƒeƒB‚Ì‘SƒvƒƒpƒeƒB</entry>
+                <entry><literal>{[aliasname].*}</literal></entry>
+                <entry><literal>{item.*}</literal></entry>
+              </row>
+              <row>
+                <entry>ƒRƒŒƒNƒVƒ‡ƒ“‚̃L[</entry>
+                <entry><literal>{[aliasname].key}</literal></entry>
+                <entry><literal>ORGID as {coll.key}</literal></entry>
+              </row>
+              <row>
+                <entry>ƒRƒŒƒNƒVƒ‡ƒ“‚ÌID</entry>
+                <entry><literal>{[aliasname].id}</literal></entry>
+                <entry><literal>EMPID as {coll.id}</literal></entry>
+              </row>
+              <row>
+                <entry>ƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f</entry>
+                <entry><literal>{[aliasname].element}</literal></entry>
+                <entry><literal>XID as {coll.element}</literal></entry>
+              </row>
+              <row>
+                <entry>ƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f‚̃vƒƒpƒeƒB</entry>
+                <entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
+                <entry><literal>NAME as {coll.element.name}</literal></entry>
+              </row>
+              <row>
+                <entry>ƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f‚Ì‘SƒvƒƒpƒeƒB</entry>
+                <entry><literal>{[aliasname].element.*}</literal></entry>
+                <entry><literal>{coll.element.*}</literal></entry>
+              </row>
+              <row>
+                <entry>ƒRƒŒƒNƒVƒ‡ƒ“‚Ì‘SƒvƒƒpƒeƒB</entry>
+                <entry><literal>{[aliasname].*}</literal></entry>
+                <entry><literal>{coll.*}</literal></entry>
+              </row>
+            </tbody>
+          </tgroup>
+        </table>
+      </sect3>
+    </sect2>
+
+    <sect2>
+      <title>ŠÇ—‚³‚ê‚Ä‚¢‚È‚¢ƒGƒ“ƒeƒBƒeƒB‚̎擾</title>
+
+      <para>ƒlƒCƒeƒBƒuSQLƒNƒGƒŠ‚É ResultTransformer ‚ð“K—p‚Å‚«‚Ü‚·B
+      ‰º‹L‚̂悤‚ɁA—Ⴆ‚΁AŠÇ—‚³‚ê‚Ä‚¢‚È‚¢ƒGƒ“ƒeƒBƒeƒB‚ð•Ô‚µ‚Ü‚·B</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS")
+        .setResultTransformer(Transformers.aliasToBean(CatDTO.class))]]></programlisting>
+
+      <para>‚±‚̃NƒGƒŠ‚ÅŽw’肳‚ê‚Ä‚¢‚é‚à‚Ì‚ð‰º‹L‚ÉŽ¦‚µ‚Ü‚·B</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>SQLƒNƒGƒŠ•¶Žš—ñ</para>
+        </listitem>
+
+        <listitem>
+          <para>Œ‹‰Ê‚ð•ÏŠ·‚µ‚½‚à‚Ì</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>ã‹L‚̃NƒGƒŠ‚́AƒCƒ“ƒXƒ^ƒ“ƒX‰»‚µANAME ‚Æ BIRTHDATE ‚Ì’l‚ð
+      ‘Ήž‚·‚éƒvƒƒpƒeƒB‚à‚µ‚­‚̓tƒB[ƒ‹ƒh‚É‘}“ü‚µ‚½ <literal>CatDTO</literal>
+      ‚̃ŠƒXƒg‚ð•Ô‚µ‚Ü‚·B</para>
+    </sect2>
+
+    <sect2>
+      <title>Œp³‚̐§Œä</title>
+
+      <para>Œp³‚̈ꕔ‚Æ‚µ‚ă}ƒbƒsƒ“ƒO‚³‚ꂽƒGƒ“ƒeƒBƒeƒB‚ð–â‚¢‡‚킹‚éƒlƒCƒeƒBƒuSQLƒNƒGƒŠ‚́A
+      ƒx[ƒX‚̃Nƒ‰ƒX‚Æ‚»‚Ì‚·‚ׂẴTƒuƒNƒ‰ƒX‚̃vƒƒpƒeƒB‚·‚ׂĂðŠÜ‚Ü‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB</para>
+    </sect2>
+
+    <sect2>
+      <title>ƒpƒ‰ƒ[ƒ^</title>
+
+      <para>ƒlƒCƒeƒBƒuSQLƒNƒGƒŠ‚́AˆÈ‰º‚̂悤‚ɁA
+      –¼‘O•t‚«ƒpƒ‰ƒ[ƒ^i:namej‚Æ“¯—l‚Ɉʒuƒpƒ‰ƒ[ƒ^‚ðƒTƒ|[ƒg‚µ‚Ü‚·B</para>
+
+      <programlisting><![CDATA[Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class);
+List pusList = query.setString(0, "Pus%").list();
+     
+query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like :name").addEntity(Cat.class);
+List pusList = query.setString("name", "Pus%").list();          ]]></programlisting>
+    </sect2>
+
+  </sect1>
+
+  <sect1 id="querysql-namedqueries" revision="3">
+    <title>–¼‘O•t‚«SQLƒNƒGƒŠ</title>
+
+    <para>–¼‘O•t‚«SQLƒNƒGƒŠ‚̓}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚Å’è‹`‚·‚邱‚Æ‚ª‚Å‚«A
+    –¼‘O•t‚«HQLƒNƒGƒŠ‚Æ‘S‚­“¯‚¶•û–@‚ŌĂԂ±‚Æ‚ª‚Å‚«‚Ü‚·B
+    ‚±‚̏ꍇA<literal>addEntity()</literal> ‚ðŒÄ‚яo‚·•K—v‚Í <emphasis>‚È‚¢</emphasis> ‚Å‚·B</para>
+
+    <programlisting><![CDATA[<sql-query name="persons">
+    <return alias="person" class="eg.Person"/>
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex}
+    FROM PERSON person
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+    <programlisting><![CDATA[List people = sess.getNamedQuery("persons")
+    .setString("namePattern", namePattern)
+    .setMaxResults(50)
+    .list();]]></programlisting>
+
+    <para>ŠÖ˜A‚ðŒ‹‡‚·‚邽‚߂ƃRƒŒƒNƒVƒ‡ƒ“‚ð‰Šú‰»‚·‚éƒNƒGƒŠ‚ð’è‹`‚·‚邽‚߂ɁA‚»‚ꂼ‚ê
+    <literal>&lt;return-join&gt;</literal> ‚Æ <literal>&lt;load-collection&gt;</literal>
+    —v‘f‚ðŽg‚¢‚Ü‚·B</para>
+
+    <programlisting><![CDATA[<sql-query name="personsWith">
+    <return alias="person" class="eg.Person"/>
+    <return-join alias="address" property="person.mailingAddress"/>
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex},
+           adddress.STREET AS {address.street},
+           adddress.CITY AS {address.city},
+           adddress.STATE AS {address.state},
+           adddress.ZIP AS {address.zip}
+    FROM PERSON person
+    JOIN ADDRESS adddress
+        ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+    <para>–¼‘O•t‚«SQLƒNƒGƒŠ‚̓XƒJƒ‰’l‚ð•Ô‚·‚±‚Æ‚à‚Å‚«‚Ü‚·B
+    <literal>&lt;return-scalar&gt;</literal> —v‘f‚ðŽg‚Á‚āA
+    —ñ‚Ì•Ê–¼‚ÆHibernate‚ÌŒ^‚ðéŒ¾‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB</para>
+
+    <programlisting><![CDATA[<sql-query name="mySqlQuery">
+    <return-scalar column="name" type="string"/>
+    <return-scalar column="age" type="long"/>
+    SELECT p.NAME AS name,
+           p.AGE AS age,
+    FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
+</sql-query>]]></programlisting>
+
+
+    <para>ƒŠƒUƒ‹ƒgƒZƒbƒg‚̃}ƒbƒsƒ“ƒOî•ñ‚ð <literal>&lt;resultset&gt;</literal>
+    ‚ÉŠOo‚µ‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+    •¡”‚Ì–¼‘O•t‚«ƒNƒGƒŠ‚ōė˜—p‚µ‚½‚èA<literal>setResultSetMapping()</literal>
+    API‚ð’Ê‚µ‚čė˜—p‚µ‚½‚è‚Å‚«‚Ü‚·B
+    </para>
+
+    <programlisting><![CDATA[<resultset name="personAddress">
+    <return alias="person" class="eg.Person"/>
+    <return-join alias="address" property="person.mailingAddress"/>
+</resultset>
+
+<sql-query name="personsWith" resultset-ref="personAddress">
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex},
+           adddress.STREET AS {address.street},
+           adddress.CITY AS {address.city},
+           adddress.STATE AS {address.state},
+           adddress.ZIP AS {address.zip}
+    FROM PERSON person
+    JOIN ADDRESS adddress
+        ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+    <para>‘ã‚í‚è‚ɁAhbmƒtƒ@ƒCƒ‹“à‚̃ŠƒUƒ‹ƒgƒZƒbƒg‚̃}ƒbƒsƒ“ƒOî•ñ‚ð
+    ’¼ÚJavaƒR[ƒh‚Ì’†‚ÅŽg—p‚Å‚«‚Ü‚·B</para>
+
+    <programlisting><![CDATA[List cats = sess.createSQLQuery(
+        "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
+    )
+    .setResultSetMapping("catAndKitten")
+    .list();]]></programlisting>
+
+    <sect2 id="propertyresults">
+      <title>—ñ‚Æ—ñ‚Ì•Ê–¼‚𖾎¦“I‚ÉŽw’è‚·‚邽‚ß‚É return-property ‚ðŽg‚¤</title>
+
+      <para>•Ê–¼‚ð‘}“ü‚·‚邽‚ß‚É <literal>{}</literal> \•¶‚ðŽg‚¤‘ã‚í‚è‚ɁA
+      <literal>&lt;return-property&gt;</literal> ‚ðŽg‚¢A
+      ‚Ç‚Ì—ñ‚Ì•Ê–¼‚ðŽg‚¤‚Ì‚©‚𖾎¦‚Å‚«‚Ü‚·B</para>
+
+      <programlisting><![CDATA[<sql-query name="mySqlQuery">
+    <return alias="person" class="eg.Person">
+        <return-property name="name" column="myName"/>
+        <return-property name="age" column="myAge"/>
+        <return-property name="sex" column="mySex"/>
+    </return>
+    SELECT person.NAME AS myName,
+           person.AGE AS myAge,
+           person.SEX AS mySex,
+    FROM PERSON person WHERE person.NAME LIKE :name
+</sql-query>
+]]></programlisting>
+
+      <para><literal>&lt;return-property&gt;</literal> ‚Í•¡”‚Ì—ñ‚àˆµ‚¦‚Ü‚·B
+      ‚±‚ê‚́A•¡”—ñ‚̃vƒƒpƒeƒB‚ð‚«‚ß×‚©‚­§Œä‚Å‚«‚È‚¢‚Æ‚¢‚¤A
+      <literal>{}</literal> \•¶‚̐§ŒÀ‚ð‰ðŒˆ‚µ‚Ü‚·B</para>
+
+      <programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
+    <return alias="emp" class="Employment">
+        <return-property name="salary">
+            <return-column name="VALUE"/>
+            <return-column name="CURRENCY"/>
+        </return-property>
+        <return-property name="endDate" column="myEndDate"/>
+    </return>
+        SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
+        STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+        REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
+        FROM EMPLOYMENT
+        WHERE EMPLOYER = :id AND ENDDATE IS NULL
+        ORDER BY STARTDATE ASC
+</sql-query>]]></programlisting>
+
+      <para>‚±‚Ì—á‚ł́A‘}“ü‚Ì‚½‚ß‚Ì <literal>{}</literal> \•¶‚Æ‚¢‚Á‚µ‚å‚ɁA
+      <literal>&lt;return-property&gt;</literal> ‚ðŽg‚Á‚Ä‚¢‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+      —ñ‚ƃvƒƒpƒeƒB‚ð‚ǂ̂悤‚ÉŽQÆ‚·‚é‚©‚ð‘I‚ׂ܂·B</para>
+
+      <para>ƒ}ƒbƒsƒ“ƒO‚É discriminator ‚ªŠÜ‚Ü‚ê‚Ä‚¢‚éê‡A
+      discriminator ‚Ì—ñ‚ðŽw’è‚·‚邽‚߂ɁA&lt;return-discriminator&gt;
+      ‚ðŽg‚í‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB</para>
+    </sect2>
+
+    <sect2 id="sp_query" revision="1">
+      <title>–â‚¢‡‚킹‚·‚邽‚߂ɃXƒgƒAƒhƒvƒƒV[ƒWƒƒ‚ðŽg‚¤</title>
+
+      <para>Hibernate‚̓o[ƒWƒ‡ƒ“3‚©‚çAƒXƒgƒAƒhƒvƒƒV[ƒWƒƒ‚ƃXƒgƒAƒhŠÖ”Œo—R‚Ì–â‚¢‡‚킹‚ª
+      ƒTƒ|[ƒg‚³‚ê‚Ü‚µ‚½B
+      ˆÈ~‚Ì•¶‘‚Ì‘½‚­‚́A—¼•û‚É“–‚Ä‚Í‚Ü‚è‚Ü‚·B
+      ƒXƒgƒAƒhƒvƒƒV[ƒWƒƒ‚âƒXƒgƒAƒhŠÖ”‚ðHibernate‚ÅŽg‚¤‚½‚߂ɂ́A
+      1”Ԗڂ̏o—̓pƒ‰ƒ[ƒ^‚Æ‚µ‚ăŠƒUƒ‹ƒgƒZƒbƒg‚ð•Ô‚³‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+      Oracle 9i‚à‚µ‚­‚Í‚»‚êˆÈã‚̃o[ƒWƒ‡ƒ“j‚̃XƒgƒAƒhƒvƒƒV[ƒWƒƒ‚Ì—á‚ðˆÈ‰º‚ÉŽ¦‚µ‚Ü‚·B</para>
+
+      <programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
+    RETURN SYS_REFCURSOR
+AS
+    st_cursor SYS_REFCURSOR;
+BEGIN
+    OPEN st_cursor FOR
+ SELECT EMPLOYEE, EMPLOYER,
+ STARTDATE, ENDDATE,
+ REGIONCODE, EID, VALUE, CURRENCY
+ FROM EMPLOYMENT;
+      RETURN  st_cursor;
+ END;]]></programlisting>
+
+      <para>Hibernate‚Å‚±‚̃NƒGƒŠ‚ðŽg‚¤‚½‚߂ɂ́A
+      –¼‘O•t‚«ƒNƒGƒŠ‚Ń}ƒbƒsƒ“ƒO‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B</para>
+
+      <programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
+    <return alias="emp" class="Employment">
+        <return-property name="employee" column="EMPLOYEE"/>
+        <return-property name="employer" column="EMPLOYER"/>
+        <return-property name="startDate" column="STARTDATE"/>
+        <return-property name="endDate" column="ENDDATE"/>
+        <return-property name="regionCode" column="REGIONCODE"/>
+        <return-property name="id" column="EID"/>
+        <return-property name="salary">
+            <return-column name="VALUE"/>
+            <return-column name="CURRENCY"/>
+        </return-property>
+    </return>
+    { ? = call selectAllEmployments() }
+</sql-query>]]></programlisting>
+
+      <para>’ˆÓF¡‚Ì‚Æ‚±‚ëAƒXƒgƒAƒhƒvƒƒV[ƒWƒƒ‚̓XƒJƒ‰‚ƃGƒ“ƒeƒBƒeƒB‚ð•Ô‚·‚Ì‚Ý‚Å‚·B
+      <literal>&lt;return-join&gt;</literal> ‚Æ <literal>&lt;load-collection&gt;</literal>
+      ‚̓Tƒ|[ƒg‚³‚ê‚Ä‚¢‚Ü‚¹‚ñB</para>
+
+      <sect3 id="querysql-limits-storedprocedures" revision="1">
+        <title>ƒXƒgƒAƒhƒvƒƒV[ƒWƒƒ‚ðŽg‚¤ã‚ł̃‹[ƒ‹‚Ɛ§ŒÀ</title>
+
+        <para>Hibernate‚ŃXƒgƒAƒhƒvƒƒV[ƒWƒƒ‚âŠÖ”‚ðŽg‚¤‚½‚߂ɂ́A
+        ‚»‚̃vƒƒV[ƒWƒƒ‚Í‚¢‚­‚‚©‚̃‹[ƒ‹‚ɏ€‹’‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+        ƒ‹[ƒ‹‚ɏ€‹’‚µ‚Ä‚¢‚È‚¢ƒvƒƒV[ƒWƒƒ‚́AHibernate‚ÅŽg‚¤‚±‚Æ‚Í‚Å‚«‚Ü‚¹‚ñB
+        ‚»‚ê‚Å‚àA€‹’‚µ‚Ä‚¢‚È‚¢ƒvƒƒV[ƒWƒƒ‚ðŽg‚¢‚½‚¢‚Ì‚Å‚ ‚ê‚΁A
+        <literal>session.connection()</literal> ‚ð’Ê‚¶‚ÄŽÀs‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+        ƒ‹[ƒ‹‚̓f[ƒ^ƒx[ƒX‚²‚ƂɈقȂè‚Ü‚·B
+        ƒXƒgƒAƒhƒvƒƒV[ƒWƒƒ‚̃Zƒ}ƒ“ƒeƒBƒbƒNƒX‚ƃVƒ“ƒ^ƒbƒNƒX‚́A
+        ƒf[ƒ^ƒx[ƒXƒxƒ“ƒ_‚²‚ƂɈقȂ邽‚ß‚Å‚·B</para>
+
+        <para><literal>setFirstResult()/setMaxResults()</literal> ‚ðŽg‚Á‚āA
+        ƒXƒgƒAƒhƒvƒƒV[ƒWƒƒƒNƒGƒŠ‚ðƒy[ƒW•ª‚¯‚·‚邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñB</para>
+
+        <para>„§‚·‚éŒÄ‚яo‚µ•û‚́A•W€‚Å‚ ‚éSQL92‚ɏ]‚¤‚±‚Æ‚Å‚·B
+        <literal>{ ? = call functionName(&lt;parameters&gt;) }</literal> ‚â
+        <literal>{ ? = call procedureName(&lt;parameters&gt;) }</literal> ‚Å‚·B
+        ƒlƒCƒeƒBƒu‚ȌĂяo‚µ\•¶‚̓Tƒ|[ƒg‚³‚ê‚Ä‚¢‚Ü‚¹‚ñB</para>
+
+        <para>Oracle‚ɂ͉º‹L‚̃‹[ƒ‹‚ª“K—p‚³‚ê‚Ü‚·B</para>
+
+        <itemizedlist spacing="compact">
+          <listitem>
+            <para>ŠÖ”‚̓ŠƒUƒ‹ƒgƒZƒbƒg‚ð•Ô‚³‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            ƒvƒƒV[ƒWƒƒ‚Ì‘æˆêˆø”‚̓ŠƒUƒ‹ƒgƒZƒbƒg‚ð•Ô‚·‚½‚߁A
+            <literal>OUT</literal> ‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            Oracle 9‚Æ10‚ł́A<literal>SYS_REFCURSOR</literal> ‚ðŽg‚¤‚±‚Æ‚É‚æ‚Á‚Ä‚Å‚«‚Ü‚·B
+            Oracle‚Å‚Í <literal>REF CURSOR</literal> Œ^‚ð’è‹`‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+            Oracle‚Ì•¶Œ£‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B</para>
+          </listitem>
+        </itemizedlist>
+
+        <para>Sybase‚ÆMS SQLƒT[ƒo[‚É“K—p‚³‚ê‚郋[ƒ‹‚ð‰º‹L‚ÉŽ¦‚µ‚Ü‚·B</para>
+
+        <itemizedlist spacing="compact">
+          <listitem>
+            <para>ƒvƒƒV[ƒWƒƒ‚̓ŠƒUƒ‹ƒgƒZƒbƒg‚ð•Ô‚³‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            ƒT[ƒo[‚Í•¡”‚̃ŠƒUƒ‹ƒgƒZƒbƒg‚ƍXVƒJƒEƒ“ƒg‚ð•Ô‚µ‚Ü‚·‚ªA
+            Hibernate‚Í1‚–ڂ̃ŠƒUƒ‹ƒgƒZƒbƒg‚¾‚¯‚ð•Ô‚·‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚»‚Ì‘¼‚Í‚·‚ׂĎ̂Ăç‚ê‚Ü‚·B</para>
+          </listitem>
+
+          <listitem>
+            <para>ƒvƒƒV[ƒWƒƒ‚Ì’†‚Å <literal>SET NOCOUNT ON</literal> ‚ð—LŒø‚É‚Å‚«‚ê‚΁A
+            ‚¨‚»‚ç‚­Œø—¦‚ª‚æ‚­‚È‚é‚Å‚µ‚傤B
+            ‚µ‚©‚µA‚±‚ê‚Í•K—vðŒ‚Å‚Í‚ ‚è‚Ü‚¹‚ñB</para>
+          </listitem>
+        </itemizedlist>
+      </sect3>
+    </sect2>
+  </sect1>
+
+  <sect1 id="querysql-cud">
+    <title>ì¬AXVAíœ‚Ì‚½‚߂̃JƒXƒ^ƒ€SQL</title>
+
+    <para>Hibernate3‚͍쐬AXVAíœˆ—‚Ì‚½‚߂̃JƒXƒ^ƒ€SQL•¶‚ðŽg—p‚Å‚«‚Ü‚·B
+    ƒNƒ‰ƒX‚ƃRƒŒƒNƒVƒ‡ƒ“‚̉i‘±‰»‹@\‚́AƒRƒ“ƒtƒBƒOƒŒ[ƒVƒ‡ƒ“Žž‚ɐ¶¬‚³‚ꂽ•¶Žš—ñ
+    iinsertsqlAdeletesqlAupdatesql‚Ȃǁj‚̃Zƒbƒg‚ð‚·‚Å‚É•ÛŽ‚µ‚Ä‚¢‚Ü‚·B
+    ‚±‚ê‚ç‚Ì•¶Žš—ñ‚æ‚èA
+    <literal>&lt;sql-insert&gt;</literal>A
+    <literal>&lt;sql-delete&gt;</literal>A
+    <literal>&lt;sql-update&gt;</literal> ‚Æ‚¢‚¤ƒ}ƒbƒsƒ“ƒOƒ^ƒO‚ª—Dæ‚³‚ê‚Ü‚·B</para>
+
+    <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
+    <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
+    <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
+</class>]]></programlisting>
+
+    <para>SQL‚𒼐ڃf[ƒ^ƒx[ƒX‚ÅŽÀs‚·‚邽‚߁AD‚Ý‚Ì•ûŒ¾‚ðŽ©—R‚ÉŽg—p‚Å‚«‚Ü‚·B
+    ƒf[ƒ^ƒx[ƒX“ÆŽ©‚ÌSQL‚ðŽg‚¦‚΁A“–‘Rƒ}ƒbƒsƒ“ƒO‚̃|[ƒ^ƒrƒŠƒeƒB‚ª‰º‚ª‚è‚Ü‚·B</para>
+
+    <para><literal>callable</literal> ‘®«‚ðƒZƒbƒg‚·‚ê‚΁A
+    ƒXƒgƒAƒhƒvƒƒV[ƒWƒƒ‚ðŽg—p‚Å‚«‚Ü‚·B</para>
+
+    <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
+    <sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
+    <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
+</class>]]></programlisting>
+
+    <para>¡‚Ì‚Æ‚±‚ëAˆÊ’uƒpƒ‰ƒ[ƒ^‚̏‡”Ô‚Í‚Æ‚Ä‚àd—v‚Å‚·B
+    ‚·‚È‚í‚¿AHibernate‚ªŠú‘Ò‚·‚鏇˜‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB</para>
+
+    <para><literal>org.hiberante.persister.entity</literal> ƒŒƒxƒ‹‚̃fƒoƒbƒOƒƒO‚ð
+    —LŒø‚É‚·‚邱‚Æ‚É‚æ‚Á‚āAŠú‘Ò‚³‚ê‚鏇”Ô‚ðŠm‚©‚ß‚ç‚ê‚Ü‚·B
+    ‚±‚̃Œƒxƒ‹‚ð—LŒø‚É‚·‚邱‚Æ‚É‚æ‚èAƒGƒ“ƒeƒBƒeƒB‚̍쐬AXVAíœ‚È‚Ç‚Å
+    Žg—p‚³‚ê‚éÃ“I‚ÈSQL‚ªo—Í‚³‚ê‚Ü‚·B
+    iŠú‘Ò‚³‚ê‚鏇˜‚ðŠm”F‚·‚邽‚߂ɂ́AHibernate‚ª¶¬‚·‚éÃ“I‚ÈSQL‚ðƒI[ƒo[ƒ‰ƒCƒh‚·‚é
+    ƒJƒXƒ^ƒ€SQL‚ðƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ÉŠÜ‚ß‚È‚¢‚±‚Æ‚ð–Y‚ê‚È‚¢‚Å‚­‚¾‚³‚¢Bj</para>
+
+    <para>ƒXƒgƒAƒhƒvƒƒV[ƒWƒƒ‚Í‘}“ü/XV/íœ‚³‚ꂽs”‚ð•Ô‚·•K—v‚ª‚ ‚è‚Ü‚·
+    i“ǂݍž‚݂̏ꍇ‚́A•Ô‚³‚È‚¢‚æ‚è‚Í•Ô‚·•û‚ª‚æ‚¢‚Å‚·jB
+    ŽÀsŽž‚ÉHibernate‚ªSQL•¶‚̐¬Œ÷‚ðƒ`ƒFƒbƒN‚·‚é‚©‚ç‚Å‚·B
+    Hibernate‚́ACUDˆ—‚Ì‚½‚߂̐”’l‚̏o—̓pƒ‰ƒ[ƒ^‚Æ‚µ‚āA
+    SQL•¶‚̍ŏ‰‚̃pƒ‰ƒ[ƒ^‚ð‚¢‚Â‚à‹L˜^‚µ‚Ü‚·B</para>
+
+    <programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
+    RETURN NUMBER IS
+BEGIN
+
+    update PERSON
+    set
+        NAME = uname,
+    where
+        ID = uid;
+
+    return SQL%ROWCOUNT;
+
+END updatePerson;]]></programlisting>
+  </sect1>
+
+  <sect1 id="querysql-load">
+    <title>ƒ[ƒh‚Ì‚½‚߂̃JƒXƒ^ƒ€SQL</title>
+
+    <para>ƒGƒ“ƒeƒBƒeƒB‚ð“ǂݍž‚Þ‚½‚ß‚Ì“ÆŽ©‚ÌSQLi‚à‚µ‚­‚ÍHQLjƒNƒGƒŠ‚àéŒ¾‚Å‚«‚Ü‚·B</para>
+
+    <programlisting><![CDATA[<sql-query name="person">
+    <return alias="pers" class="Person" lock-mode="upgrade"/>
+    SELECT NAME AS {pers.name}, ID AS {pers.id}
+    FROM PERSON
+    WHERE ID=?
+    FOR UPDATE
+</sql-query>]]></programlisting>
+
+    <para>‚±‚ê‚́A‚Ü‚³‚ɁiˆÈ‘O‹c˜_‚µ‚½j–¼‘O•t‚«ƒNƒGƒŠ‚̐錾‚Å‚·B
+    ‚±‚Ì–¼‘O•t‚«ƒNƒGƒŠ‚ðƒNƒ‰ƒX‚̃}ƒbƒsƒ“ƒO‚©‚çŽQÆ‚Å‚«‚Ü‚·B</para>
+
+    <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <loader query-ref="person"/>
+</class>]]></programlisting>
+    
+
+    <para>‚±‚ê‚̓XƒgƒAƒhƒvƒƒV[ƒWƒƒ‚Å‚³‚¦‚à“®ì‚µ‚Ü‚·B</para>
+
+    <para>ŽŸ‚̂悤‚ɁAƒRƒŒƒNƒVƒ‡ƒ“‚ðƒ[ƒh‚·‚邽‚߂̃NƒGƒŠ‚³‚¦’è‹`‚µ‚Ä‚æ‚¢‚Å‚·B</para>
+
+    <programlisting><![CDATA[<set name="employments" inverse="true">
+    <key/>
+    <one-to-many class="Employment"/>
+    <loader query-ref="employments"/>
+</set>]]></programlisting>
+
+    <programlisting><![CDATA[<sql-query name="employments">
+    <load-collection alias="emp" role="Person.employments"/>
+    SELECT {emp.*}
+    FROM EMPLOYMENT emp
+    WHERE EMPLOYER = :id
+    ORDER BY STARTDATE ASC, EMPLOYEE ASC
+</sql-query>]]></programlisting>
+
+    <para>ŽŸ‚̂悤‚ɁAŒ‹‡ƒtƒFƒbƒ`‚É‚æ‚èƒRƒŒƒNƒVƒ‡ƒ“‚ðƒ[ƒh‚·‚é
+    ƒGƒ“ƒeƒBƒeƒBƒ[ƒ_[‚ð’è‹`‚Å‚«‚Ü‚·B</para>
+
+    <programlisting><![CDATA[<sql-query name="person">
+    <return alias="pers" class="Person"/>
+    <return-join alias="emp" property="pers.employments"/>
+    SELECT NAME AS {pers.*}, {emp.*}
+    FROM PERSON pers
+    LEFT OUTER JOIN EMPLOYMENT emp
+        ON pers.ID = emp.PERSON_ID
+    WHERE ID=?
+</sql-query>]]></programlisting>
+  </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/session_api.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/session_api.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/session_api.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1125 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="objectstate">
+    <title>ƒIƒuƒWƒFƒNƒg‚ðˆµ‚¤</title>
+    
+    <para> 
+        Hibernate ‚ÍŠ®‘S‚ȃIƒuƒWƒFƒNƒg/ƒŠƒŒ[ƒVƒ‡ƒiƒ‹ƒ}ƒbƒsƒ“ƒOƒ\ƒŠƒ…[ƒVƒ‡ƒ“‚Å‚ ‚èA
+        ƒf[ƒ^ƒx[ƒXŠÇ—ƒVƒXƒeƒ€‚̏ڍׂðŠJ”­ŽÒ‚©‚ç‰B•Á‚·‚邾‚¯‚Å‚È‚­A ƒIƒuƒWƒFƒNƒg‚Ì <emphasis>ó‘ÔŠÇ—</emphasis> ‚às‚¢‚Ü‚·B
+        ‚±‚ê‚́AJDBC/SQL‰i‘±‘w‚Æ“¯‚¶‚悤‚ÈSQL <literal>•¶</literal> ‚ÌŠÇ—‚Ƃ͈قȂèA
+        JavaƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚¨‚¯‚é‰i‘±‰»‚ɑ΂·‚éA‚Æ‚Ä‚àŽ©‘R‚ȃIƒuƒWƒFƒNƒgŽwŒü‚̍l‚¦•û‚ð’ñ‹Ÿ‚µ‚Ü‚·B 
+        </para>
+    
+    <para> 
+        Œ¾‚¢‚©‚¦‚ê‚΁AHibernate‚ð—p‚¢‚éƒAƒvƒŠƒP[ƒVƒ‡ƒ“ŠJ”­ŽÒ‚́AƒIƒuƒWƒFƒNƒg‚Ì <emphasis>ó‘Ô</emphasis> ‚ɂ‚¢‚Ä‚Í
+        í‚Ɉӎ¯‚·‚ׂ«‚Å‚ ‚èASQL•¶‚ÌŽÀs‚ɂ‚¢‚Ä‚Í•K‚¸‚µ‚à‚»‚¤‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+        ‚±‚Ì•”•ª‚́A’ʏíAHibernate‚ªˆ—‚µAƒVƒXƒeƒ€‚̃pƒtƒH[ƒ}ƒ“ƒX‚ðƒ`ƒ…[ƒjƒ“ƒO‚·‚é‚Æ‚«‚É‚¾‚¯A –â‘è‚É‚È‚Á‚Ä‚«‚Ü‚·B 
+    </para>
+    
+    <sect1 id="objectstate-overview">
+        <title>Hibernate‚É‚¨‚¯‚éƒIƒuƒWƒFƒNƒg‚̏ó‘Ô</title>
+        
+        <para>
+            Hibernate‚ÍŽŸ‚̂悤‚ȃIƒuƒWƒFƒNƒg‚̏ó‘Ô‚ð’è‹`‚µAƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·B
+        </para>
+        
+        <itemizedlist>
+            <listitem>
+                <para> 
+                    <emphasis> ˆêŽž“I(Transient) </emphasis> - <literal>new</literal>
+                     ‰‰ŽZŽq‚ðŽg‚Á‚Ä ƒCƒ“ƒXƒ^ƒ“ƒX‰»‚³‚ꂽ‚¾‚¯‚ŁA Hibernate‚Ì <literal>Session</literal> 
+                    ‚ÉŠÖ˜A•t‚¯‚ç‚ê‚Ä‚¢‚È‚¢ƒIƒuƒWƒFƒNƒg‚́A ˆêŽž“I(transient)‚Å‚·B
+                    ‚»‚ê‚́Aƒf[ƒ^ƒx[ƒX‚ɉi‘±“I‚È•\Œ»‚ðŽ‚½‚¸AŽ¯•ÊŽq‚Æ‚È‚é’l‚ÍŠ„‚è“–‚Ä‚ç‚ê‚Ä‚¢‚Ü‚¹‚ñB
+                    ˆêŽž“I‚ȃCƒ“ƒXƒ^ƒ“ƒX‚́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ª‚»‚ÌŽQÆ‚ð‚Ç‚±‚É‚à•ÛŽ‚µ‚È‚¢ê‡‚ɁA ƒKƒx[ƒWƒRƒŒƒNƒ^‚É‚æ‚Á‚Ä”jŠü‚³‚ê‚Ü‚·B
+                    ƒIƒuƒWƒFƒNƒg‚ð‰i‘±“I(persistent)‚ȏó‘Ô‚É‚·‚邽‚߂ɂ́AHibernate‚Ì
+                     <literal>Session</literal> ‚ðŽg‚¢‚Ü‚µ‚傤B
+                    i‚±‚̏ó‘Ô‘JˆÚ‚É•K—v‚Æ‚È‚éSQL•¶‚Ì”­s‚́AHibernate‚É”C‚¹‚Ü‚µ‚傤Bj 
+                </para>
+            </listitem>
+            <listitem>
+                <para> 
+                    <emphasis>‰i‘±“I(Persistent)</emphasis> -
+                    ‰i‘±“I‚ȃCƒ“ƒXƒ^ƒ“ƒX‚̓f[ƒ^ƒx[ƒX‚É ‰i‘±“I‚È•\Œ»‚ðŽ‚¿AŽ¯•ÊŽq‚Æ‚È‚é’l‚ðŽ‚Á‚Ä‚¢‚Ü‚·B
+                    ‚»‚ê‚́AƒZ[ƒu‚³‚ꂽ‚èAƒ[ƒh‚³‚ꂽ‚è‚·‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñ‚ªA
+                    ’è‹`ã‚́A <literal>Session</literal> ‚̃XƒR[ƒv‚Ì’†‚É‘¶Ý‚µ‚Ä‚¢‚Ü‚·B
+                    Hibernate‚́Aì‹Æ’PˆÊiUnit of workj‚ªŠ®—¹‚µ‚½‚Æ‚«‚ɁA ‰i‘±ó‘Ԃ̃IƒuƒWƒFƒNƒg‚ɉÁ‚¦‚ç‚ꂽ•ÏX‚ðŒŸo‚µA
+                    ƒIƒuƒWƒFƒNƒg‚̏ó‘Ԃƃf[ƒ^ƒx[ƒX‚𓯊ú‚µ‚Ü‚·B ƒIƒuƒWƒFƒNƒg‚ðˆêŽž“I(transient)‚É‚·‚é‚Æ‚«‚́AŠJ”­ŽÒ‚́AŽèì‹Æ‚Å
+                     <literal>UPDATE</literal> •¶‚â <literal>DELETE</literal>
+                    •¶‚ðŽÀs‚µ‚Ü‚¹‚ñB 
+                </para>
+            </listitem>
+            <listitem>
+                <para> 
+                    <emphasis>•ª—£(Detached)</emphasis> - •ª—£‚³‚ꂽƒCƒ“ƒXƒ^ƒ“ƒX‚Ƃ́A‰i‘±‰»‚³‚ê‚Ä‚¢‚邪A
+                    ‚»‚ê‚ÆŠÖ˜A•t‚¢‚Ä‚¢‚½ <literal>Session</literal> ‚ªƒNƒ[ƒY‚³‚ê‚Ä‚¢‚éƒIƒuƒWƒFƒNƒg‚Ì‚±‚Æ‚Å‚·B
+                    ‚»‚̃IƒuƒWƒFƒNƒg‚Ö‚ÌŽQÆ‚́AˆË‘R‚Æ‚µ‚Ä—LŒø‚Å‚·B
+                    ‚»‚µ‚āA‚à‚¿‚ë‚ñA•ª—£‚³‚ꂽó‘Ô‚É‚ ‚éƒIƒuƒWƒFƒNƒg‚́AC³‚·‚邱‚Æ‚³‚¦‚Å‚«‚Ü‚·B
+                    •ª—£‚³‚ꂽƒCƒ“ƒXƒ^ƒ“ƒX‚́A‚à‚¤ˆê“x‰i‘±‰»‚µ‚½‚¢i‚»‚µ‚āA‚·‚ׂĂ̕ύX‚ð‰i‘±‰»‚µ‚½‚¢j‚Æ‚«‚ɁA V‚µ‚¢
+                     <literal>Session</literal> ‚ɍĒljÁ‚Å‚«‚Ü‚·B
+                    ‚±‚Ì‹@”\‚́Aƒ†[ƒU‚ªl‚¦‚鎞ŠÔ‚ð•K—v‚Æ‚·‚é‚悤‚ȁA’·ŠúŠÔ‚É‹y‚ԍì‹Æ’PˆÊ‚ɑ΂·‚é ƒvƒƒOƒ‰ƒ~ƒ“ƒOƒ‚ƒfƒ‹‚ð‰Â”\‚É‚µ‚Ü‚·B
+                    ‰äX‚́A‚±‚ê‚ð <emphasis>ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“iapplication
+                    transactionsj</emphasis> ‚ƌĂñ‚Å‚¢‚Ü‚·B ‚·‚È‚í‚¿Aƒ†[ƒU‚©‚猩‚½ì‹Æ’PˆÊ‚¾‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para> 
+            ‚±‚ê‚©‚çAó‘ԂƏó‘Ô‘JˆÚi‚»‚µ‚āA‘JˆÚ‚Ì‚«‚Á‚©‚¯‚Æ‚È‚éHibernate‚̃ƒ\ƒbƒhj‚ɂ‚¢‚Ä AÚ×‚ɏq‚ׂ܂·B 
+        </para>
+        
+    </sect1>
+    
+    <sect1 id="objectstate-makingpersistent" revision="1">
+        <title>ƒIƒuƒWƒFƒNƒg‚ð‰i‘±ó‘Ô‚É‚·‚é</title>
+        
+        <para>
+            V‚µ‚­ƒCƒ“ƒXƒ^ƒ“ƒX‰»‚³‚ꂽ‰i‘±ƒNƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚́A Hibernate‚Å‚Í
+             <emphasis>ˆêŽž“I(transient)</emphasis> ‚ÆŒ©‚È‚³‚ê‚Ü‚·B
+            ˆÈ‰º‚̂悤‚ɁAƒZƒbƒVƒ‡ƒ“‚ÆŠÖ˜A‚¯‚邱‚ƂŁAˆêŽž“I‚ȃCƒ“ƒXƒ^ƒ“ƒX‚ð
+             <emphasis>‰i‘±ó‘Ô(persistent)</emphasis> ‚É‚Å‚«‚Ü‚·B 
+         </para>
+        
+        
+        <programlisting><![CDATA[DomesticCat fritz = new DomesticCat();
+fritz.setColor(Color.GINGER);
+fritz.setSex('M');
+fritz.setName("Fritz");
+Long generatedId = (Long) sess.save(fritz);]]></programlisting>
+        
+        <para> 
+            <literal>Cat</literal> ƒNƒ‰ƒX‚ÌŽ¯•ÊŽq‚ªŽ©“®¶¬‚³‚ê‚é‚Ì‚Å‚ ‚ê‚΁A
+            <literal>save()</literal> ‚ªŒÄ‚΂ê‚é‚Æ‚«‚ɁA Ž¯•ÊŽq‚ª¶¬‚³‚êA <literal>cat</literal>
+            ƒCƒ“ƒXƒ^ƒ“ƒX‚ÉŠ„‚è“–‚Ä‚ç‚ê‚Ü‚·B <literal>Cat</literal> 
+            ‚ÌŽ¯•ÊŽq‚ª‘¼‚©‚犄‚è“–‚Ä‚ç‚ê‚éi <literal>assigned</literal> Ž¯•ÊŽq‚ðŽ‚Âj‚©A•¡‡ƒL[‚Å‚ ‚é‚È‚çA
+             <literal>save()</literal> ‚ðŒÄ‚яo‚·‘O‚ɁAŽ¯•ÊŽq‚ðŠ„‚è“–‚Ä‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+             <literal>save()</literal> ‚Ì‘ã‚í‚è‚ɁAEJB3 ‚̏‰Šúƒhƒ‰ƒtƒg‚Å’è‹`‚³‚ꂽ
+             <literal>persist()</literal> ‚ðŽg‚¤‚±‚Æ‚à‰Â”\‚Å‚·B 
+         </para>
+        
+        <para> 
+             ‘ã‚í‚è‚ɁAŽ¯•ÊŽq‚ðˆø”‚É‚Æ‚é <literal>save()</literal>
+            ƒƒ\ƒbƒh‚ðŽg‚Á‚āA Ž¯•ÊŽq‚ðŠ„‚è“–‚Ă邱‚Æ‚à‚Å‚«‚Ü‚·B 
+        </para>
+        
+        
+        <programlisting><![CDATA[DomesticCat pk = new DomesticCat();
+pk.setColor(Color.TABBY);
+pk.setSex('F');
+pk.setName("PK");
+pk.setKittens( new HashSet() );
+pk.addKitten(fritz);
+sess.save( pk, new Long(1234) );]]></programlisting>
+        
+        <para> 
+            ‰i‘±‰»‚·‚éƒIƒuƒWƒFƒNƒg‚ªŠÖ˜AƒIƒuƒWƒFƒNƒg‚ðŽ‚Á‚Ä‚¢‚éê‡ i—Ⴆ‚΁A‘O‚Ì—á‚É‚¨‚¯‚é
+             <literal>kittens</literal> ƒRƒŒƒNƒVƒ‡ƒ“‚̂悤‚ɁjA ŠO•”ƒL[ƒJƒ‰ƒ€‚ɁA <literal>NOT
+            NULL</literal> §–ñ‚ð‚‚¯‚È‚¢ŒÀ‚è‚́A ‚±‚ê‚ç‚̈ê˜A‚̃IƒuƒWƒFƒNƒg‚ð‚Ç‚ñ‚ȏ‡”Ԃʼni‘±‰»‚µ‚Ä‚à‚©‚Ü‚¢‚Ü‚¹‚ñB
+            ŠO•”ƒL[§–ñ‚ðˆá”½‚·‚é‹°‚ê‚Í‚ ‚è‚Ü‚¹‚ñB ‚µ‚©‚µA <literal>NOT NULL</literal> 
+            §–ñ‚ª‚ ‚éê‡AŠÔˆá‚Á‚½‡”ԂŃIƒuƒWƒFƒNƒg‚ð <literal>save()</literal> ‚µ‚Ä‚µ‚Ü‚¤‚ƁA
+            §–ñ‚Ɉᔽ‚·‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB </para>
+        
+        <para>
+            ŠÖ˜A‚·‚éƒIƒuƒWƒFƒNƒg‚ðŽ©“®“I‚É•Û‘¶‚·‚éA Hibernate‚Ì <emphasis>‘JˆÚ“I‚ȉi‘±‰»(transitive
+            persistence)</emphasis> ‹@”\‚ð Žg‚¤‚‚à‚è‚È‚ç‚΁A‚»‚̂悤‚ȏڍׂð‹C‚É‚·‚é•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+            ‚»‚µ‚āA <literal>NOT NULL</literal> §–ñ‚̈ᔽ‚·‚ç‹N‚±‚è‚Ü‚¹‚ñB
+            Hibernate‚ª‚·‚ׂĖʓ|‚ð‚Ý‚Ä‚­‚ê‚Ü‚·B‘JˆÚ“I‚ȉi‘±‰»‚́A‚±‚̏͂̌㔼‚ɏ‘‚©‚ê‚Ä‚¢‚Ü‚·B </para>
+        
+    </sect1>
+    
+    <sect1 id="objectstate-loading">
+        <title>ƒIƒuƒWƒFƒNƒg‚̃[ƒh</title>
+        
+        <para>
+            ‰i‘±‰»‚³‚ꂽƒCƒ“ƒXƒ^ƒ“ƒX‚ÌŽ¯•ÊŽq‚ª‚ ‚ç‚©‚¶‚ß•ª‚©‚Á‚Ä‚¢‚é‚È‚çA <literal>Session</literal> ‚Ì
+             <literal>load()</literal> ƒƒ\ƒbƒh‚ðŽg‚Á‚āA•œŒ³‚Å‚«‚Ü‚·B <literal>load()</literal> 
+            ‚́AClass ƒIƒuƒWƒFƒNƒg‚ðˆø”‚É‚Æ‚èA ‚»‚̃Nƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ðV‚½‚ɐ¶¬‚µAó‘Ô‚ðƒ[ƒh‚µ‚Ü‚·B
+            ‚»‚̃Cƒ“ƒXƒ^ƒ“ƒX‚̏ó‘Ԃ́A‰i‘±(persistent)ó‘Ô‚Å‚·B </para>
+        
+        
+        <programlisting><![CDATA[Cat fritz = (Cat) sess.load(Cat.class, generatedId);]]></programlisting>
+        
+        
+        <programlisting><![CDATA[// you need to wrap primitive identifiers
+long id = 1234;
+DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id) );]]></programlisting>
+        <para>
+            ‚ ‚é‚¢‚́AˆÈ‰º‚̂悤‚ɁAŠù‘¶‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ɏó‘Ô‚ðƒ[ƒh‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B </para>
+        
+        
+        <programlisting><![CDATA[Cat cat = new DomesticCat();
+// load pk's state into cat
+sess.load( cat, new Long(pkId) );
+Set kittens = cat.getKittens();]]></programlisting>
+        
+        <para> 
+            DB‚ÉŠY“–‚·‚és‚ª–³‚¢ê‡A <literal>load()</literal> ‚͉ñ•œ•s‰Â”\‚È—áŠO‚ð “Š‚°‚邱‚Æ‚É’ˆÓ‚µ‚Ü‚µ‚傤B
+            ‚»‚̃Nƒ‰ƒX‚ªƒvƒƒLƒV‚ðŽg‚Á‚ă}ƒbƒsƒ“ƒO‚³‚ê‚Ä‚¢‚éê‡A <literal>load()</literal> 
+            ‚͏‰Šú‰»‚³‚ê‚Ä‚¢‚È‚¢ƒvƒƒLƒV‚ð•Ô‚µAƒvƒƒLƒV‚̃ƒ\ƒbƒh‚ªŒÄ‚΂ê‚é‚Ü‚ÅŽÀÛ‚É‚Í ƒf[ƒ^ƒx[ƒX‚ɃAƒNƒZƒX‚µ‚Ü‚¹‚ñB
+            ‚à‚µAŽÀÛ‚Ƀf[ƒ^ƒx[ƒX‚©‚烍[ƒh‚¹‚¸‚ɁAƒIƒuƒWƒFƒNƒg‚ɑ΂·‚éŠÖ˜A‚ðì‚肽‚¢ê‡A ‚±‚̐U‚é•‘‚¢‚Í‚Æ‚Ä‚à–𗧂¿‚Ü‚·B
+             <literal>batch-size</literal> ‚ªƒNƒ‰ƒXƒ}ƒbƒsƒ“ƒO‚É’è‹`‚³‚ê‚Ä‚¢‚é‚È‚ç‚΁A
+            •¡”‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ðˆêŠ‡‚э[ƒh‚·‚邱‚Æ‚ª‰Â”\‚Å‚·B </para>
+        
+        <para>
+            ŠY“–‚·‚és‚ª‘¶Ý‚·‚邱‚Æ‚ðŠmM‚Å‚«‚È‚¢ê‡‚́A <literal>get()</literal> ƒƒ\ƒbƒh‚ðŽg‚¤‚ׂ«‚Å‚·B
+            ‚»‚ê‚́Aƒf[ƒ^ƒx[ƒX‚É‚·‚®‚ɃAƒNƒZƒX‚µAŠY“–‚·‚és‚ª–³‚¢ê‡‚Ínull‚ð•Ô‚µ‚Ü‚·B </para>
+        
+        
+        <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id);
+if (cat==null) {
+    cat = new Cat();
+    sess.save(cat, id);
+}
+return cat;]]></programlisting>
+        
+        <para>
+            <literal>LockMode</literal> ‚ðŽg‚¦‚΁A
+             <literal>SELECT ... FOR UPDATE</literal>‚Æ‚¢‚¤SQL‚ð Žg‚Á‚ăIƒuƒWƒFƒNƒg‚ðƒ[ƒh‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            Ú×‚ȏî•ñ‚́AAPIƒhƒLƒ…ƒƒ“ƒg‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B </para>
+        
+        
+        <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);]]></programlisting>
+        
+        <para>
+            ŠÖ˜A‚ɑ΂·‚éƒJƒXƒP[ƒh•û–@‚Æ‚µ‚Ä
+             <literal>lock</literal> ‚â <literal>all</literal> ‚ð
+            Žw’肵‚È‚¢ŒÀ‚èAŠÖ˜A‚·‚éƒCƒ“ƒXƒ^ƒ“ƒX‚âŠÜ‚Ü‚ê‚éƒRƒŒƒNƒVƒ‡ƒ“‚Í <literal>FOR UPDATE</literal> ‚Å•œŒ³
+             <emphasis>‚³‚ê‚È‚¢</emphasis> ‚±‚Æ‚É’ˆÓ‚µ‚Ü‚µ‚傤B </para>
+        
+        <para>
+            <literal>refresh()</literal> ƒƒ\ƒbƒh‚ðŽg‚¤‚±‚ƂŁA‚Ç‚ñ‚È‚Æ‚«‚Å‚àAƒIƒuƒWƒFƒNƒg‚â‚»‚̃RƒŒƒNƒVƒ‡ƒ“‚ð
+            ƒŠƒ[ƒh‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B ƒf[ƒ^ƒx[ƒX‚̃gƒŠƒK‚ªƒe[ƒuƒ‹‚ðXV‚µ‚½Û‚ɁA
+            ‚»‚̃e[ƒuƒ‹‚ɑΉž‚·‚éƒIƒuƒWƒFƒNƒg‚̃vƒƒpƒeƒB‚𓯊ú‚·‚éê‡A‚±‚̃ƒ\ƒbƒh‚ª–ð‚É—§‚¿‚Ü‚·B </para>
+        
+        
+        <programlisting><![CDATA[sess.save(cat);
+sess.flush(); //force the SQL INSERT
+sess.refresh(cat); //re-read the state (after the trigger executes)]]></programlisting>
+        <para>
+            ‘åØ‚È–â‘è‚́A‚¢‚Â‚àŽŸ‚Ì“_‚ÉŠÖ‚·‚é‚à‚Ì‚Å‚·B‚»‚ê‚́AHibernate‚ªƒf[ƒ^ƒx[ƒX‚©‚çA
+            ‚Ç‚Ì‚­‚ç‚¢‚̗ʂ𕜌³‚·‚é‚Ì‚©‚ƁA‚Ç‚Ì‚­‚ç‚¢‚̐”‚ÌSQL‚Ì <literal>SELECT</literal> •¶‚ªŽg‚í‚ê‚é‚Ì‚©‚Å‚·B
+            ‚±‚ê‚́A <emphasis>ƒtƒFƒbƒ`‚̐헪</emphasis> ‚É‚æ‚è‚Ü‚·B‚±‚ê‚ɂ‚¢‚ẮA<xref linkend="performance-fetching"/> ‚Åà–¾‚µ‚Ä‚¢‚Ü‚·B </para>
+        
+    </sect1>
+    
+    <sect1 id="objectstate-querying" revision="1">
+        <title>ƒNƒGƒŠ</title>
+        
+        <para>
+            ’T‚µ‚½‚¢ƒIƒuƒWƒFƒNƒg‚ÌŽ¯•ÊŽq‚ª•ª‚©‚ç‚È‚¢ê‡‚́AƒNƒGƒŠ‚ª•K—v‚É‚È‚è‚Ü‚·B
+            Hibernate‚ÍŽg‚¢‚â‚·‚­‚Ä‹­—͂ȃIƒuƒWƒFƒNƒgŽwŒü‚̃NƒGƒŠŒ¾Œê (HQL)‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·B
+            ƒvƒƒOƒ‰ƒ€‚É‚æ‚Á‚ăNƒGƒŠ‚ªì¬‚Å‚«‚é‚悤‚ɁAHibernate‚͐ô—û‚³‚ꂽCriteria‚ÆExampleƒNƒGƒŠ‹@”\(QBC‚ÆQBEj‚ð
+            ƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·BResultSet‚ðƒIƒuƒWƒFƒNƒg‚É•ÏŠ·‚·‚éHibernate‚̃IƒvƒVƒ‡ƒ“‹@”\‚ðŽg‚¤‚±‚ƂŁA
+            ƒf[ƒ^ƒx[ƒX‚̃lƒCƒeƒBƒu‚ÈSQL‚ŃNƒGƒŠ‚ð•\Œ»‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B </para>
+        
+        <sect2 id="objectstate-querying-executing" revision="1">
+            <title>ƒNƒGƒŠ‚ÌŽÀs</title>
+            
+            <para>
+                HQL‚âƒlƒCƒeƒBƒu‚ÈSQLƒNƒGƒŠ‚́A <literal>org.hibernate.Query</literal> 
+                ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚Æ‚µ‚Ä•\Œ»‚³‚ê‚Ü‚·B ‚±‚̃Cƒ“ƒ^ƒtƒF[ƒX‚́Aƒpƒ‰ƒ[ƒ^ƒoƒCƒ“ƒfƒBƒ“ƒO‚âResultSet‚̃nƒ“ƒhƒŠƒ“ƒO‚â
+                ƒNƒGƒŠ‚ÌŽÀs‚ðs‚¤ƒƒ\ƒbƒh‚ð—pˆÓ‚µ‚Ä‚¢‚Ü‚·B ’ʏíA <literal>Query</literal> ‚́AˆÈ‰º‚ÉŽ¦‚·‚悤‚ɁA
+                ‚»‚ÌŽž“_‚Ì <literal>Session</literal> ‚ðŽg‚Á‚Ď擾‚µ‚Ü‚·B </para>
+            
+            
+            <programlisting><![CDATA[List cats = session.createQuery(
+    "from Cat as cat where cat.birthdate < ?")
+    .setDate(0, date)
+    .list();
+
+List mothers = session.createQuery(
+    "select mother from Cat as cat join cat.mother as mother where cat.name = ?")
+    .setString(0, name)
+    .list();
+
+List kittens = session.createQuery(
+    "from Cat as cat where cat.mother = ?")
+    .setEntity(0, pk)
+    .list();
+
+Cat mother = (Cat) session.createQuery(
+    "select cat.mother from Cat as cat where cat = ?")
+    .setEntity(0, izi)
+    .uniqueResult();]]
+
+Query mothersWithKittens = (Cat) session.createQuery(
+    "select mother from Cat as mother left join fetch mother.kittens");
+Set uniqueMothers = new HashSet(mothersWithKittens.list());
+
+			]]></programlisting>
+            
+            <para> 
+                ƒNƒGƒŠ‚́A•’ʁA <literal>list()</literal> ‚ðŒÄ‚яo‚·‚±‚Æ‚É‚æ‚Á‚ÄŽÀs‚³‚ê‚Ü‚·B
+                ƒNƒGƒŠ‚ÌŒ‹‰Ê‚́Aƒƒ‚ƒŠã‚É‚ ‚éƒRƒŒƒNƒVƒ‡ƒ“‚É‚·‚ׂ㍁[ƒh‚³‚ê‚Ü‚·B
+                ƒNƒGƒŠ‚É‚æ‚Á‚Ä•œŒ³‚³‚ꂽƒGƒ“ƒeƒBƒeƒB‚̃Cƒ“ƒXƒ^ƒ“ƒX‚́A‰i‘±ó‘Ô‚Å‚·B
+                ‚à‚µAƒNƒGƒŠ‚ª‚½‚Á‚½1ŒÂ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ð•Ô‚·‚Æ•ª‚©‚Á‚Ä‚¢‚é‚È‚çA
+                 <literal>uniqueResult()</literal> ƒƒ\ƒbƒh‚ªŽè‚ÁŽæ‚葁‚¢•û–@‚Å‚·B
+                ‘¦ŽžƒtƒFƒbƒ`‚ð—˜—p‚µ‚½ƒNƒGƒŠ‚̏ꍇA‚ӂ‚¤A“¾‚ç‚ꂽƒRƒŒƒNƒVƒ‡ƒ“‚ɂ́A
+                ƒ‹[ƒg‚̃IƒuƒWƒFƒNƒg‚ªd•¡‚µ‚ÄŠÜ‚Ü‚ê‚Ä‚¢‚Ü‚·
+                i‚µ‚©‚µAƒ‹[ƒg‚ªŽ‚ƒRƒŒƒNƒVƒ‡ƒ“‚͏‰Šú‰»(ƒ[ƒhj‚³‚ê‚Ä‚¢‚Ü‚·jB 
+                ‚±‚̏d•¡‚Í <literal>Set</literal> ‚ðŽg‚Á‚ÄŽæ‚菜‚­‚±‚Æ‚ª‚Å‚«‚Ü‚·B</para>
+            
+            <sect3 id="objectstate-querying-executing-iterate">
+                <title>Œ‹‰Ê‚ðƒCƒeƒŒ[ƒg‚·‚é</title>
+                
+                <para> 
+                    ŽžXA <literal>iterate()</literal> ƒƒ\ƒbƒh‚ðŽg‚Á‚ăNƒGƒŠ‚ðŽÀs‚·‚邱‚ƂŁA
+                    ‚æ‚è—Ç‚¢ƒpƒtƒH[ƒ}ƒ“ƒX‚𓾂邱‚Æ‚ª‚Å‚«‚Ü‚·B ‚±‚ê‚́A’ʏíAƒNƒGƒŠ‚É‚æ‚Á‚Ä“¾‚ç‚ꂽŽÀÛ‚̃Gƒ“ƒeƒBƒeƒB‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ªA
+                    ‚·‚łɃZƒbƒVƒ‡ƒ“‚Ü‚½‚Í“ñŽŸƒLƒƒƒbƒVƒ…‚É‘¶Ý‚·‚邱‚Æ‚ªŠú‘Ò‚Å‚«‚éê‡‚¾‚¯‚Å‚·B
+                    ‚»‚ê‚炪A‚Ü‚¾ƒLƒƒƒbƒVƒ…‚³‚ê‚Ä‚¢‚È‚¢‚È‚çA <literal>iterate()</literal> ‚́A
+                     <literal>list()</literal> ‚æ‚è‚à’x‚­AŠÈ’P‚ȃNƒGƒŠ‚ɑ΂µ‚Ä‚à‘½‚­‚̃f[ƒ^ƒx[ƒXƒAƒNƒZƒX‚ð
+                    •K—v‚Æ‚µ‚Ü‚·B‚»‚̃AƒNƒZƒX‚Ƃ́AŽ¯•ÊŽq‚¾‚¯‚ðŽæ“¾‚·‚邽‚߂̍ŏ‰‚Ìselect‚P‰ñ‚ƁA
+                    ŽÀÛ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ð‰Šú‰»‚·‚邽‚߂Ɍォ‚çs‚¤n‰ñ‚Ìselect‚Ì‚±‚Æ‚Å‚·B </para>
+                
+                
+                <programlisting><![CDATA[// fetch ids
+Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate();
+while ( iter.hasNext() ) {
+    Qux qux = (Qux) iter.next();  // fetch the object  
+    // something we couldnt express in the query  
+    if ( qux.calculateComplicatedAlgorithm() ) {
+        // delete the current instance  
+        iter.remove();
+        // dont need to process the rest  
+        break;
+    }
+}]]></programlisting>
+            </sect3>
+            
+            <sect3 id="objectstate-querying-executing-tuples">
+                <title>ƒIƒuƒWƒFƒNƒg‚Ì‘gituplej‚ð•Ô‚·ƒNƒGƒŠ</title>
+                <para>
+                    Hibernate‚̃NƒGƒŠ‚ł́AŽžXAƒIƒuƒWƒFƒNƒg‚Ì‘g‚ð•Ô‚·‚±‚Æ‚ª‚ ‚è‚Ü‚·B ‚»‚̏ꍇ‚́AŠeƒ^ƒvƒ‹‚Í”z—ñ‚Æ‚µ‚Ä•Ô‚³‚ê‚Ü‚·B
+                    </para>
+                
+                
+                <programlisting><![CDATA[Iterator kittensAndMothers = sess.createQuery(
+            "select kitten, mother from Cat kitten join kitten.mother mother")
+            .list()
+            .iterator();
+
+while ( kittensAndMothers.hasNext() ) {
+    Object[] tuple = (Object[]) kittensAndMothers.next();
+    Cat kitten  = tuple[0];
+    Cat mother  = tuple[1];
+    ....
+}]]></programlisting>
+                
+            </sect3>
+            
+            <sect3 id="objectstate-querying-executing-scalar" revision="1">
+                <title>ƒXƒJƒ‰[‚ÌŒ‹‰Ê</title>
+                
+                <para>
+                    ƒNƒGƒŠ‚ł́A <literal>select</literal> ß‚ŃNƒ‰ƒX‚̃vƒƒpƒeƒB‚ðŽw’è‚Å‚«‚Ü‚·B
+                    SQL‚̏W‡ŠÖ”‚ðŒÄ‚Ô‚±‚Æ‚à‚Å‚«‚Ü‚·BƒvƒƒpƒeƒB‚âW‡ŠÖ”‚́A
+                    i‰i‘±ó‘Ԃ̃Gƒ“ƒeƒBƒeƒB‚Å‚Í‚È‚­juƒXƒJƒ‰[’lv‚Å‚ ‚é‚ÆŒ©‚È‚³‚ê‚Ü‚·B </para>
+                
+                
+                <programlisting><![CDATA[Iterator results = sess.createQuery(
+        "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
+        "group by cat.color")
+        .list()
+        .iterator();
+
+while ( results.hasNext() ) {
+    Object[] row = (Object[]) results.next();
+    Color type = (Color) row[0];
+    Date oldest = (Date) row[1];
+    Integer count = (Integer) row[2];
+    .....
+}]]></programlisting>
+                
+            </sect3>
+            
+            <sect3 id="objectstate-querying-executing-parameters">
+                <title>ƒpƒ‰ƒ[ƒ^‚̃oƒCƒ“ƒh</title>
+                
+                <para>
+                    <literal>Query</literal>
+                    ‚́A–¼‘O•t‚«‚̃pƒ‰ƒ[ƒ^‚âJDBCƒXƒ^ƒCƒ‹‚Ì <literal>?</literal> 
+                    ƒpƒ‰ƒ[ƒ^‚É’l‚ðƒoƒCƒ“ƒh‚·‚邽‚߂̃ƒ\ƒbƒh‚ðŽ‚Á‚Ä‚¢‚Ü‚·B
+                    <emphasis>JDBC‚Ƃ͈ႢAHibernate‚̓pƒ‰ƒ[ƒ^‚Ƀ[ƒ‚©‚ç”ԍ†‚ðU‚Á‚Ä‚¢‚«‚Ü‚·B</emphasis> 
+                    –¼‘O•t‚«‚̃pƒ‰ƒ[ƒ^‚Ƃ́AƒNƒGƒŠ•¶Žš—ñ‚Ì‚È‚©‚É‚ ‚é <literal>:name</literal> Œ`Ž®‚ÌŽ¯•ÊŽq‚Å‚·B
+                    –¼‘O•t‚«ƒpƒ‰ƒ[ƒ^‚Ì—˜“_‚ÍŽŸ‚Ì’Ê‚è‚Å‚·B </para>
+                
+                <itemizedlist spacing="compact">
+                    <listitem>
+                        <para>  –¼‘O•t‚«ƒpƒ‰ƒ[ƒ^‚́AƒNƒGƒŠ•¶Žš—ñ‚É“oê‚·‚鏇”Ô‚Æ–³ŠÖŒW‚Å‚· </para>
+                    </listitem>
+                    <listitem>
+                        <para> “¯‚¶ƒNƒGƒŠ“à‚É•¡”‰ñ“oê‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚· </para>
+                    </listitem>
+                    <listitem>
+                        <para> Ž©•ªŽ©g‚ðà–¾‚µ‚Ü‚· </para>
+                    </listitem>
+                </itemizedlist>
+                
+                
+                <programlisting><![CDATA[//named parameter (preferred)
+Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
+q.setString("name", "Fritz");
+Iterator cats = q.iterate();]]></programlisting>
+                
+                
+                <programlisting><![CDATA[//positional parameter
+Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
+q.setString(0, "Izi");
+Iterator cats = q.iterate();]]></programlisting>
+                
+                
+                <programlisting><![CDATA[//named parameter list
+List names = new ArrayList();
+names.add("Izi");
+names.add("Fritz");
+Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)");
+q.setParameterList("namesList", names);
+List cats = q.list();]]></programlisting>
+                
+            </sect3>
+            
+            <sect3 id="objectstate-querying-executing-pagination">
+                <title>ƒy[ƒW•ª‚¯
+                </title>
+                
+                <para>
+                    ResultSet‚ɐ§ŒÀi•œŒ³‚µ‚½‚¢Å‘ås”‚â•œŒ³‚µ‚½‚¢Å‰‚̍sj‚ð‰Á‚¦‚é•K—v‚ª‚ ‚ê‚΁A
+                    ˆÈ‰º‚̂悤‚ɁA <literal>Query</literal> ƒCƒ“ƒ^[ƒtƒFƒCƒX‚̃ƒ\ƒbƒh‚ðŽg‚¢‚Ü‚·B </para>
+                
+                
+                <programlisting><![CDATA[Query q = sess.createQuery("from DomesticCat cat");
+q.setFirstResult(20);
+q.setMaxResults(10);
+List cats = q.list();]]></programlisting>
+                
+                <para>  §ŒÀ•t‚«‚̃NƒGƒŠ‚ðDBMS‚̃lƒCƒeƒBƒu‚ÈSQL‚É•ÏŠ·‚·‚é•û–@‚ðAHibernate‚Í’m‚Á‚Ä‚¢‚Ü‚·B
+                    </para>
+                
+            </sect3>
+            
+            <sect3 id="objectstate-querying-executing-scrolling">
+                <title>ƒXƒNƒ[ƒ‹‰Â”\‚ȃCƒeƒŒ[ƒVƒ‡ƒ“</title>
+                
+                <para>
+                    JDBCƒhƒ‰ƒCƒo‚ªƒXƒNƒ[ƒ‹‰Â”\‚È <literal>ResultSet</literal> ‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚ê‚΁A
+                     <literal>Query</literal> 
+                    ƒCƒ“ƒ^[ƒtƒFƒCƒX‚ðŽg‚Á‚āA <literal>ScrollableResults</literal> ƒIƒuƒWƒFƒNƒg‚ð
+                    Žæ“¾‚Å‚«‚Ü‚·B‚»‚ê‚ðŽg‚¤‚ƁAƒNƒGƒŠ‚ÌŒ‹‰Ê‚ɑ΂µ‚ď_“î‚ɃiƒrƒQ[ƒVƒ‡ƒ“‚Å‚«‚Ü‚·B </para>
+                
+                
+                <programlisting><![CDATA[Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
+                            "order by cat.name");
+ScrollableResults cats = q.scroll();
+if ( cats.first() ) {
+
+    // find the first name on each page of an alphabetical list of cats by name
+    firstNamesOfPages = new ArrayList();
+    do {
+        String name = cats.getString(0);
+        firstNamesOfPages.add(name);
+    }
+    while ( cats.scroll(PAGE_SIZE) );
+
+    // Now get the first page of cats
+    pageOfCats = new ArrayList();
+    cats.beforeFirst();
+    int i=0;
+    while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) );
+
+}
+cats.close()]]></programlisting>
+                
+                <para>
+                    ‚±‚Ì‹@”\‚ɂ̓I[ƒvƒ“ó‘Ԃ̃f[ƒ^ƒx[ƒXƒRƒlƒNƒVƒ‡ƒ“‚ª•K—v‚Å‚ ‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                    ‚à‚µAƒIƒtƒ‰ƒCƒ“‚̃y[ƒW•ª‚¯‹@”\‚ª•K—v‚Å‚ ‚ê‚΁A <literal>setMaxResult()</literal> /
+                     <literal>setFirstResult()</literal> ‚ðŽg‚¢‚Ü‚µ‚傤B </para>
+                
+            </sect3>
+            
+            <sect3 id="objectstate-querying-executing-named" revision="1">
+                <title>–¼‘O•t‚«ƒNƒGƒŠ‚ÌŠOo‚µ</title>
+                
+                <para> 
+                    ƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚É–¼‘O•t‚«‚̃NƒGƒŠ‚ð’è‹`‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+                    iƒ}[ƒNƒAƒbƒv‚ƉðŽß‚³‚ê‚镶Žš‚ªƒNƒGƒŠ‚ÉŠÜ‚Ü‚ê‚é‚È‚çA <literal>CDATA</literal> ƒZƒNƒVƒ‡ƒ“‚ð
+                    Žg‚¤‚±‚Æ‚ð–Y‚ê‚È‚¢‚悤‚É‚µ‚Ü‚µ‚傤Bj </para>
+                
+                
+                <programlisting><![CDATA[<query name="ByNameAndMaximumWeight"><![CDATA[
+    from eg.DomesticCat as cat
+        where cat.name = ?
+        and cat.weight > ?
+] ]></query>]]></programlisting>
+                
+                <para>ƒpƒ‰ƒ[ƒ^‚̃oƒCƒ“ƒfƒBƒ“ƒO‚ÆŽÀs‚́AˆÈ‰º‚̂悤‚ȃvƒƒOƒ‰ƒ€‚ōs‚í‚ê‚Ü‚·B </para>
+                
+                
+                <programlisting><![CDATA[Query q = sess.getNamedQuery("ByNameAndMaximumWeight");
+q.setString(0, name);
+q.setInt(1, minWeight);
+List cats = q.list();]]></programlisting>
+                
+                <para> ŽÀÛ‚̃vƒƒOƒ‰ƒ€ƒR[ƒh‚́AŽg‚í‚ê‚éƒNƒGƒŠŒ¾Œê‚Ɉˑ¶‚µ‚Ä‚¢‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ü‚µ‚傤B
+                    ƒƒ^ƒf[ƒ^‚ɂ́AƒlƒCƒeƒBƒuSQLƒNƒGƒŠ‚ð’è‹`‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B ‚Ü‚½AŠù‘¶‚̃NƒGƒŠ‚ðƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚Ɉڂ·‚±‚ƂŁA
+                    Hibernate‚Ɉڍs‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B </para>
+                <para>
+                    <literal>&lt;hibernate-mapping&gt;</literal> ‚Ì’†‚̃NƒGƒŠ’è‹`‚́AƒNƒGƒŠ‚ɑ΂·‚é
+                    ƒ†ƒj[ƒN‚È–¼‘O‚ª•K—v‚È‚±‚Æ‚É‚à’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B‚»‚ê‚ɑ΂µ‚āA <literal>&lt;class&gt;</literal> ‚Ì’†‚Ì
+                    ƒNƒGƒŠ’è‹`‚́AƒNƒ‰ƒX‚ÌŠ®‘SŒÀ’è–¼‚ª‘O‚É•t‚¯‚ç‚ê‚é‚̂ŁAŽ©“®“I‚Ƀ†ƒj[ƒN‚È–¼‘O‚É‚È‚è‚Ü‚·B
+                    —áF <literal>eg.Cat.ByNameAndMaximumWeight</literal>
+                </para>
+            </sect3>
+        </sect2>
+        
+        <sect2 id="objectstate-filtering" revision="1">
+            <title>ƒRƒŒƒNƒVƒ‡ƒ“‚̃tƒBƒ‹ƒ^ƒŠƒ“ƒO</title>
+            <para> ƒRƒŒƒNƒVƒ‡ƒ“ <emphasis>ƒtƒBƒ‹ƒ^</emphasis> ‚́A‰i‘±‰»‚³‚ê‚Ä‚¢‚éƒRƒŒƒNƒVƒ‡ƒ“‚â”z—ñ‚É“K—p‚³‚ê‚é
+                “ÁŽê‚ȃ^ƒCƒv‚̃NƒGƒŠ‚Å‚·B‚»‚̃NƒGƒŠ•¶Žš—ñ‚ł́AƒRƒŒƒNƒVƒ‡ƒ“‚Ì‚»‚ÌŽž“_‚Å‚Ì—v‘f‚ðˆÓ–¡‚·‚é
+                <literal>this</literal> ‚ðŽg‚¢‚Ü‚·B </para>
+            
+            
+            <programlisting><![CDATA[Collection blackKittens = session.createFilter(
+    pk.getKittens(), 
+    "where this.color = ?")
+    .setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) )
+    .list()
+);]]></programlisting>
+            
+            <para>  •Ô‚³‚ê‚éƒRƒŒƒNƒVƒ‡ƒ“‚ÍBag‚Æ‚Ý‚È‚³‚ê‚Ü‚·B‚»‚µ‚āA‚»‚ê‚Í‚à‚Ƃ̃RƒŒƒNƒVƒ‡ƒ“‚̃Rƒs[‚É‚È‚è‚Ü‚·B
+                Œ³‚̃RƒŒƒNƒVƒ‡ƒ“‚͏C³‚³‚ê‚Ü‚¹‚ñi‚±‚ê‚́A"filter"‚Æ‚¢‚¤–¼‘O‚̈Ӗ¡‚Ƃ͈قȂè‚Ü‚·‚ªA Šú‘Ò‚³‚ê‚é“®‚«‚Ƃ͈ê’v‚µ‚Ä‚¢‚Ü‚·jB
+                </para>
+            
+            <para> ƒtƒBƒ‹ƒ^‚É‚Í <literal>from</literal> 
+                ß‚ª•s—v‚Å‚ ‚邱‚Æ‚É‹C‚­‚Å‚µ‚傤i•K—v‚È‚çAŽ‚‚±‚Æ‚à‰Â”\‚Å‚·‚ªjB ƒtƒBƒ‹ƒ^‚́AƒRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘fŽ©‘Ì‚ð•Ô‚µ‚č\‚¢‚Ü‚¹‚ñB
+                </para>
+            
+            
+            <programlisting><![CDATA[Collection blackKittenMates = session.createFilter(
+    pk.getKittens(), 
+    "select this.mate where this.color = eg.Color.BLACK.intValue")
+    .list();]]></programlisting>
+            
+            <para>  ƒNƒGƒŠ‚ðŠÜ‚Ü‚È‚¢ƒtƒBƒ‹ƒ^‚à–ð‚É—§‚¿‚Ü‚·B
+                —Ⴆ‚΁A”ñí‚É‘å‚«‚ȃRƒŒƒNƒVƒ‡ƒ“‚Ì•”•ªW‡‚ðƒ[ƒh‚·‚邽‚ß‚ÉŽg‚¦‚Ü‚·B </para>
+            
+            
+            <programlisting><![CDATA[Collection tenKittens = session.createFilter(
+    mother.getKittens(), "")
+    .setFirstResult(0).setMaxResults(10)
+    .list();]]></programlisting>
+            
+        </sect2>
+        
+        <sect2 id="objecstate-querying-criteria" revision="1">
+            <title>ƒNƒ‰ƒCƒeƒŠƒA‚̃NƒGƒŠ</title>
+            
+            <para> HQL‚Í”ñí‚É‹­—Í‚Å‚·‚ªAƒNƒGƒŠ•¶Žš—ñ‚ðì‚é‚æ‚è‚àAƒIƒuƒWƒFƒNƒgŽwŒü‚ÌAPI‚ðŽg‚Á‚Ä
+                “®“I‚ɃNƒGƒŠ‚ðì‚é•û‚ðD‚ÞŠJ”­ŽÒ‚à‚¢‚Ü‚·B ‚±‚¤‚¢‚Á‚½ê‡‚Ì‚½‚߂ɁAHibernate‚Í’¼Š´“I‚È
+                 <literal>Criteria</literal> ƒNƒGƒŠAPI‚ð’ñ‹Ÿ‚µ‚Ä‚¢‚Ü‚·B </para>
+            
+            
+            <programlisting><![CDATA[Criteria crit = session.createCriteria(Cat.class);
+crit.add( Expression.eq( "color", eg.Color.BLACK ) );
+crit.setMaxResults(10);
+List cats = crit.list();]]></programlisting>
+            
+            <para>  <literal>Criteria</literal> ‚Æ
+                 <literal>Example</literal> API‚̏ڍׂ́A <xref linkend="querycriteria"/>
+                 ‚ɏq‚ׂç‚ê‚Ä‚¢‚Ü‚·B </para>
+            
+        </sect2>
+        
+        <sect2 id="objectstate-querying-nativesql" revision="2">
+            <title>ƒlƒCƒeƒBƒuSQL‚̃NƒGƒŠ</title>
+            
+            <para> 
+                <literal>createSQLQuery()</literal> ‚ðŽg‚Á‚āASQL‚ŃNƒGƒŠ‚ð•\Œ»‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+                ‚»‚µ‚āAHibernate‚ɁAResultSet ‚©‚çƒIƒuƒWƒFƒNƒg‚ւ̃}ƒbƒsƒ“ƒO‚ð‚Ü‚©‚¹‚Ü‚·B
+                 <literal>session.connection()</literal> ‚ðŒÄ‚ׂ΂ǂñ‚È‚Æ‚«‚Å‚àA’¼ÚAJDBC
+                 <literal>Connection</literal> ‚ðŽg—p‚Å‚«‚邱‚Æ‚ðŠo‚¦‚Ä‚¨‚«‚Ü‚µ‚傤B ‚à‚µAHibernate
+                API‚ðŽg‚¤‚Ì‚Å‚ ‚ê‚΁A‰º‹L‚̂悤‚ÉSQL‚Ì•Ê–¼‚ðŠ‡ŒÊ‚Å‚­‚­‚ç‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB </para>
+            
+            
+            <programlisting><![CDATA[List cats = session.createSQLQuery(
+    "SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10",
+    "cat",
+    Cat.class
+).list();]]></programlisting>
+            
+            
+            <programlisting><![CDATA[List cats = session.createSQLQuery(
+    "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
+           "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
+    "FROM CAT {cat} WHERE ROWNUM<10",
+    "cat",
+    Cat.class
+).list()]]></programlisting>
+            
+            <para> 
+                SQLƒNƒGƒŠ‚́AHibernateƒNƒGƒŠ‚Æ“¯‚¶‚悤‚ɁA–¼‘O•t‚«‚̃pƒ‰ƒ[ƒ^‚ƈʒuƒpƒ‰ƒ[ƒ^‚ðŽ‚Â‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+                Hibernate‚É‚¨‚¯‚éƒlƒCƒeƒBƒu‚ÈSQLƒNƒGƒŠ‚̏ڍׂɂ‚¢‚ẮA <xref linkend="querysql"/> 
+                ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B </para>
+            
+        </sect2>
+        
+    </sect1>
+    
+    <sect1 id="objectstate-modifying" revision="1">
+        <title>‰i‘±ƒIƒuƒWƒFƒNƒg‚̏C³</title>
+        
+        <para> 
+             <emphasis>ˆ—’†‚̉i‘±ƒCƒ“ƒXƒ^ƒ“ƒX</emphasis>
+            i—áF <literal>Session</literal> ‚É‚æ‚Á‚āA
+            ƒ[ƒhAƒZ[ƒuAì¬AƒNƒGƒŠ‚³‚ꂽƒIƒuƒWƒFƒNƒgj‚́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‘€ì‚³‚ê‚Ü‚·B
+            ‚»‚̍ۂɕύX‚³‚ꂽ‰i‘±ó‘Ԃ́A <literal>Session</literal> ‚ª <emphasis>ƒtƒ‰ƒbƒVƒ…</emphasis>
+            ‚³‚ê‚é‚Æ‚«‚ɁA‰i‘±‰»‚³‚ê‚Ü‚·i‚±‚ê‚́A‚±‚̏͂̌㔼‚ŏq‚ׂĂ¢‚Ü‚·jB
+            •ÏX‚ð‰i‘±‰»‚·‚邽‚߂ɁA“ÁŽê‚ȃƒ\ƒbƒhi <literal>update()</literal> 
+            ‚̂悤‚È‚à‚́B‚±‚ê‚́A•Ê‚Ì–Ú“I‚ÅŽg—p‚µ‚Ü‚·j‚ð ŒÄ‚Ô•K—v‚Í‚ ‚è‚Ü‚¹‚ñB ƒIƒuƒWƒFƒNƒg‚̏ó‘Ô‚ðXV‚·‚éˆê”ÔŠÈ’P‚È•û–@‚́AƒIƒuƒWƒFƒNƒg‚ð
+             <literal>load()</literal> ‚µA <literal>Session</literal> 
+            ‚ðƒI[ƒvƒ“‚É‚µ‚Ä‚¢‚éŠÔ‚ɁA’¼Ú‘€ì‚·‚邱‚Æ‚Å‚·B </para>
+        
+        
+        <programlisting><![CDATA[DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
+cat.setName("PK");
+sess.flush();  // changes to cat are automatically detected and persisted
+]]></programlisting>
+        
+        <para> 
+            iƒIƒuƒWƒFƒNƒg‚ðƒ[ƒh‚·‚邽‚߂́jSQL‚Ì <literal>SELECT</literal> ‚ƁiXV‚³‚ꂽó‘Ô‚ð‰i‘±‰»‚·‚邽‚߂́j
+            SQL‚Ì <literal>UPDATE</literal> ‚ª“¯‚¶ƒZƒbƒVƒ‡ƒ“‚Å•K—v‚Æ‚È‚é‚̂ŁA‚±‚̃vƒƒOƒ‰ƒ~ƒ“ƒOƒ‚ƒfƒ‹‚́A
+            Œø—¦‚ªˆ«‚­‚È‚éê‡‚ª‚ ‚è‚Ü‚·B
+            ‚»‚Ì‚½‚߁AHibernate‚Í•Ê‚Ì•û–@‚ð—pˆÓ‚µ‚Ä‚¢‚Ü‚·B‚»‚ê‚́AƒCƒ“ƒXƒ^ƒ“ƒX‚𕪗£‚·‚éidetachedj•û–@‚Å‚·B </para>
+        
+        <para> 
+            <emphasis>Hibernate‚́A <literal>UPDATE</literal> •¶‚â 
+            <literal>DELETE</literal> •¶‚𒼐ڎÀs‚·‚éAPI‚ð—pˆÓ‚µ‚Ä‚¢‚Ü‚¹‚ñB
+            Hibernate‚́A <emphasis>ó‘ÔŠÇ—</emphasis> ƒT[ƒrƒX‚Å‚ ‚èAŽg‚í‚ê‚éSQL
+             <emphasis>•¶</emphasis> ‚Ì‚±‚Æ‚ðŠJ”­ŽÒ‚ªl‚¦‚é•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+            JDBC‚ÍSQL•¶‚ðŽÀs‚·‚銮àø‚ÈAPI‚Å‚ ‚èA <literal>session.connection()</literal>
+             ‚ðŒÄ‚Ô‚±‚Æ‚Å ‚¢‚‚łàAJDBC <literal>Connection</literal> ‚ðŠJ”­ŽÒ‚͎擾‚Å‚«‚Ü‚·B
+            ‚³‚ç‚ɁA‘å—ʂ̃f[ƒ^‘€ì‚̍l‚¦•û‚́AƒIƒ“ƒ‰ƒCƒ“ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ˆ—Œü‚«ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚Ì
+            ƒIƒuƒWƒFƒNƒg/ƒŠƒŒ[ƒVƒ‡ƒiƒ‹ƒ}ƒbƒsƒ“ƒO‚ƏՓ˂µ‚Ü‚·B
+            ‚µ‚©‚µAHibernate‚̍¡Œã‚̃o[ƒWƒ‡ƒ“‚ł́A‘å—ʃf[ƒ^‚ðˆ—‚·‚é“Á•Ê‚È‹@”\‚ð’ñ‹Ÿ‚·‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+            ƒoƒbƒ`‘€ì‚É—˜—p‚Å‚«‚é‚¢‚­‚‚©‚̍H•v‚ɂ‚¢‚ẮA <xref linkend="batch"/> ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B </emphasis>
+            </para>
+        
+    </sect1>
+    
+    <sect1 id="objectstate-detached" revision="2">
+        <title>•ª—£ƒIƒuƒWƒFƒNƒg‚̏C³</title>
+        
+        <para>
+            ‘½‚­‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚Å‚ÍŽŸ‚Ì‚±‚Æ‚ª•K—v‚É‚È‚è‚Ü‚·B
+            ‚»‚ê‚́A‚ ‚éƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ŃIƒuƒWƒFƒNƒg‚𕜌³‚µA‘€ì‚·‚邽‚ß‚É‚»‚ê‚ðUI‘w‚É‘—‚èA
+            ‚»‚ÌŒã‚ɁAV‚µ‚¢ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ŕύX‚ðƒZ[ƒu‚·‚é‚Æ‚¢‚Á‚½‚±‚Æ‚Å‚·B
+            •Às«‚̍‚‚¢ŠÂ‹«‚ŁA‚±‚̃^ƒCƒv‚̃Aƒvƒ[ƒ`‚ðŽg‚¤ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ł́A "ŠúŠÔ‚Ì’·‚¢"
+            ì‹Æ’PˆÊ‚ÌŠu—£«‚ð•ÛØ‚·‚邽‚߂ɁAƒo[ƒWƒ‡ƒ“ƒf[ƒ^‚ª’ʏíŽg‚í‚ê‚Ü‚·B </para>
+        
+        <para> 
+            Hibernate‚́A <literal>Session.update()</literal> ‚â
+             <literal>Session.merge()</literal> ƒƒ\ƒbƒh‚ð
+            Žg‚Á‚āA•ª—£ƒCƒ“ƒXƒ^ƒ“ƒX‚ðÄ’ljÁ‚·‚邱‚ƂŁA‚±‚̃‚ƒfƒ‹‚ɑΉž‚µ‚Ü‚·B </para>
+        
+        
+        <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catId);
+Cat potentialMate = new Cat();
+firstSession.save(potentialMate);
+
+// in a higher layer of the application
+cat.setMate(potentialMate);
+
+// later, in a new session
+secondSession.update(cat);  // update cat
+secondSession.update(mate); // update mate]]></programlisting>
+        
+        <para> 
+             Ž¯•ÊŽq<literal>catId</literal> ‚ðŽ‚Â <literal>Cat</literal> ‚ªAŠù‚É
+             <literal>secondSession</literal> ‚э[ƒh‚³‚ê‚Ä‚¢‚½ê‡‚́AÄ’ljÁ‚µ‚悤‚Æ‚µ‚½‚Æ‚«‚ɁA—áŠO‚ª“Š‚°‚ç‚ê‚Ü‚·B
+            </para>
+        
+        <para> 
+            “¯‚¶Ž¯•ÊŽq‚ðŽ‚Â‰i‘±ƒCƒ“ƒXƒ^ƒ“ƒX‚ðƒZƒbƒVƒ‡ƒ“‚ªŠù‚É•ÛŽ‚µ‚Ä‚¢‚È‚¢‚±‚Æ‚ð
+            ŠmM‚Å‚«‚é‚È‚ç <literal>update()</literal> ‚ðŽg‚¢‚Ü‚µ‚傤B
+            ‚»‚µ‚āAƒZƒbƒVƒ‡ƒ“‚̏ó‘Ô‚ðl‚¦‚¸‚ɁA‚Ç‚ñ‚ȏꍇ‚Å‚à•ÏX‚ðƒ}[ƒW‚µ‚½‚¢ê‡‚́A <literal>merge()</literal> 
+            ‚ðŽg‚¢‚Ü‚µ‚傤B ‚·‚È‚í‚¿A•ª—£ƒIƒuƒWƒFƒNƒg‚̍ĒljÁ‘€ì‚ªAÅ‰‚ÉŽÀs‚³‚ê‚邱‚Æ‚ðŠmŽÀ‚É‚·‚邽‚߂ɁA ’ʏí‚Í
+             <literal>update()</literal> ‚ªV‚µ‚¢ƒZƒbƒVƒ‡ƒ“‚Ì‚È‚©‚ōŏ‰‚ɌĂ΂ê‚郁ƒ\ƒbƒh‚É‚È‚è‚Ü‚·B </para>
+        
+        <para> 
+            •ª—£ƒCƒ“ƒXƒ^ƒ“ƒX‚©‚ç“ž’B‰Â”\‚ȁA•ª—£ƒCƒ“ƒXƒ^ƒ“ƒX‚ðƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ÍŒÂ•Ê‚É <literal>update()</literal>
+             ‚·‚ׂ«‚Å‚·B‚»‚ê‚́A‚»‚̏ó‘Ô‚ðXV‚µ‚½‚¢ê‡‚É <emphasis>ŒÀ‚è</emphasis> ‚Ü‚·B
+             <emphasis>‘JˆÚ“I‚ȉi‘±‰»</emphasis> ‚ðŽg‚¦‚΁A‚à‚¿‚ë‚ñŽ©“®‰»‚Å‚«‚Ü‚·B <xref
+                linkend="objectstate-transitive"/> ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B </para>
+        
+        <para>
+            ƒƒ\ƒbƒh‚Å‚à‚Ü‚½AV‚µ‚¢ƒZƒbƒVƒ‡ƒ“‚ɃIƒuƒWƒFƒNƒg‚ðÄŠÖ˜A•t‚¯‚Å‚«‚Ü‚·B ‚µ‚©‚µA•ª—£ƒCƒ“ƒXƒ^ƒ“ƒX‚Í–³C³‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            </para>
+        
+        
+        <programlisting><![CDATA[//just reassociate:
+sess.lock(fritz, LockMode.NONE);
+//do a version check, then reassociate:
+sess.lock(izi, LockMode.READ);
+//do a version check, using SELECT ... FOR UPDATE, then reassociate:
+sess.lock(pk, LockMode.UPGRADE);]]></programlisting>
+        
+        <para>
+            <literal>lock()</literal> ‚́A‚³‚Ü‚´‚Ü‚È
+             <literal>LockMode</literal> ‚Æ‚Æ‚à‚ÉŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+            Ú×‚́AAPIƒhƒLƒ…ƒƒ“ƒg‚ƃgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ˆ—‚̏͂ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+            Ä’ljÁ‚Ì‚Æ‚«‚É‚¾‚¯A <literal>lock()</literal> ‚ªŽg‚í‚ê‚é‚킯‚Å‚Í‚ ‚è‚Ü‚¹‚ñB </para>
+        
+        <para>
+         ŠúŠÔ‚Ì’·‚¢ì‹Æ’PˆÊ‚́A‚»‚Ì‘¼‚̃‚ƒfƒ‹‚́A<xref linked="transactions-optimistic"/> ‚ŏq‚ׂĂ¢‚Ü‚·B </para>
+        
+    </sect1>
+    
+    <sect1 id="objectstate-saveorupdate">
+        <title>Ž©“®“I‚ȏó‘ÔŒŸo</title>
+        
+        <para>
+            Hibernate‚̃†[ƒU‚ÍŽŸ‚Ì2‚‚̃P[ƒX‚Ì‚Ç‚¿‚ç‚É‚àŽg‚¦‚é”Ä—p“I‚ȃƒ\ƒbƒh‚ð—v‹‚µ‚Ä‚¢‚Ü‚µ‚½B
+            ‚»‚ê‚́AV‚µ‚¢Ž¯•ÊŽq‚𐶐¬‚µ‚Ĉꎞ“I‚ȃCƒ“ƒXƒ^ƒ“ƒX‚ðƒZ[ƒu‚·‚邱‚ƂƁA
+            ‚»‚ÌŽž“_‚ÌŽ¯•ÊŽq‚ÆŠÖ˜A‚¢‚Ä‚¢‚镪—£ƒCƒ“ƒXƒ^ƒ“ƒX‚ðXV/Ä’ljÁ‚·‚邱‚Æ‚Ì‚Å‚«‚郁ƒ\ƒbƒh‚Å‚·B
+             <literal>saveOrUpdate()</literal> ‚Í‚±‚̂悤‚È‹@”\‚ðŽÀŒ»‚µ‚½ƒƒ\ƒbƒh‚Å‚·B </para>
+        
+        
+        <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catID);
+
+// in a higher tier of the application
+Cat mate = new Cat();
+cat.setMate(mate);
+
+// later, in a new session
+secondSession.saveOrUpdate(cat);   // update existing state (cat has a non-null id)
+secondSession.saveOrUpdate(mate);  // save the new instance (mate has a null id)]]></programlisting>
+        
+        <para>
+            <literal>saveOrUpdate()</literal> ‚ÌŽg—p•û–@‚ƈӖ¡‚́A
+            V‚µ‚¢ƒ†[ƒU‚É‚Æ‚Á‚謗‚ðµ‚­‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+            ‚Ü‚¸‘æˆê‚ɁA‚ ‚éƒZƒbƒVƒ‡ƒ“‚ÅŽg—p‚µ‚½ƒCƒ“ƒXƒ^ƒ“ƒX‚ð•Ê‚̐V‚µ‚¢ƒZƒbƒVƒ‡ƒ“‚ÅŽg‚¨‚¤‚Æ‚µ‚È‚¢ŒÀ‚èA
+            <literal>update()</literal> ‚â <literal>saveOrUpdate()</literal> ‚â
+             <literal>merge()</literal> ‚ðŽg‚¤•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‘S‘Ì‚ð’Ê‚¶‚āA‚±‚ê‚ç‚̃ƒ\ƒbƒh‚ð‘S‚­Žg‚í‚È‚¢‚±‚Æ‚à‚ ‚è‚Ü‚·B </para>
+        
+        <para>
+            ’ʏíA <literal>update()</literal> ‚â <literal>saveOrUpdate()</literal>
+             ‚ÍŽŸ‚̃VƒiƒŠƒI‚Å Žg‚í‚ê‚Ü‚·B </para>
+        
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ªÅ‰‚̃ZƒbƒVƒ‡ƒ“‚ŃIƒuƒWƒFƒNƒg‚ðƒ[ƒh‚µ‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para>ƒIƒuƒWƒFƒNƒg‚ªUI‘w‚É‘—‚ç‚ê‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para>ƒIƒuƒWƒFƒNƒg‚ɑ΂µ‚ĕύX‚ª‰Á‚¦‚ç‚ê‚Ü‚·B
+                    </para>
+            </listitem>
+            <listitem>
+                <para> ƒIƒuƒWƒFƒNƒg‚ªƒrƒWƒlƒXƒƒWƒbƒN‘w‚É‘—‚ç‚ê‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para> 
+                    ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚́A2”Ԗڂ̃ZƒbƒVƒ‡ƒ“‚Å <literal>update()</literal>
+                     ‚ðŒÄ‚Ô‚±‚ƂŁA‚±‚ê‚ç‚̕ύX‚ð‰i‘±‰»‚µ‚Ü‚·B </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para> <literal>saveOrUpdate()</literal> ‚͈ȉº‚Ì‚±‚Æ‚ðs‚¢‚Ü‚·B </para>
+        
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>ƒIƒuƒWƒFƒNƒg‚ª‚±‚̃ZƒbƒVƒ‡ƒ“‚ŁA‚·‚łɉi‘±‰»‚³‚ê‚Ä‚¢‚ê‚΁A‰½‚à‚µ‚Ü‚¹‚ñB </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ‚»‚̃ZƒbƒVƒ‡ƒ“‚ÉŠÖ˜A‚¢‚Ä‚¢‚é•Ê‚̃IƒuƒWƒFƒNƒg‚ª“¯‚¶Ž¯•ÊŽq‚ðŽ‚Á‚Ä‚¢‚é‚È‚çA —áŠO‚ð“Š‚°‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ƒIƒuƒWƒFƒNƒg‚ÌŽ¯•ÊŽq‚ª’l‚ðŽ‚½‚È‚¢‚È‚ç‚΁A <literal>save()</literal> ‚µ‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ƒIƒuƒWƒFƒNƒg‚ÌŽ¯•ÊŽq‚ª’l‚ðŽ‚¿A‚»‚Ì’l‚ªV‚½‚ɃCƒ“ƒXƒ^ƒ“ƒX‰»‚³‚ꂽƒIƒuƒWƒFƒNƒg‚Ì‚½‚ß‚Ì’l‚Å‚ ‚éê‡A ‚»‚̃IƒuƒWƒFƒNƒg‚ð
+                     <literal>save()</literal> ‚µ‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ƒIƒuƒWƒFƒNƒg‚ªi <literal>&lt;version&gt;</literal> ‚â
+                     <literal>&lt;timestamp&gt;</literal> ‚É‚æ‚Á‚āj
+                    ƒo[ƒWƒ‡ƒ“‚¯‚³‚ê‚Ä‚¢‚āAƒo[ƒWƒ‡ƒ“‚̃vƒƒpƒeƒB‚ª’l‚ðŽ‚¿A
+                    ‚»‚Ì’l‚ªV‚µ‚­ƒCƒ“ƒXƒ^ƒ“ƒX‰»‚³‚ꂽƒIƒuƒWƒFƒNƒg‚Ì‚½‚ß‚Ì’l‚Å‚ ‚éê‡A ‚»‚̃IƒuƒWƒFƒNƒg‚ð
+                     <literal>save()</literal> ‚µ‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ‚»‚¤‚Å‚È‚¢ê‡‚́A‚»‚̃IƒuƒWƒFƒNƒg‚ð <literal>update()</literal> ‚µ‚Ü‚·B </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            ‚»‚µ‚āA <literal>merge()</literal> ‚͈ȉº‚̂悤‚É‚Æ‚Ä‚àˆÙ‚È‚è‚Ü‚·B </para>
+        
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    “¯‚¶Ž¯•ÊŽq‚ðŽ‚Â‰i‘±‰»ƒCƒ“ƒXƒ^ƒ“ƒX‚ª‚»‚ÌŽž“_‚ŃZƒbƒVƒ‡ƒ“‚ÆŠÖ˜A•t‚¢‚Ä‚¢‚é‚È‚ç‚΁A
+                    ˆø”‚Ŏ󂯎æ‚Á‚½ƒIƒuƒWƒFƒNƒg‚̏ó‘Ô‚ð‰i‘±‰»ƒCƒ“ƒXƒ^ƒ“ƒX‚ɃRƒs[‚µ‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ‰i‘±‰»ƒCƒ“ƒXƒ^ƒ“ƒX‚ª‚»‚ÌŽž“_‚ŃZƒbƒVƒ‡ƒ“‚ÉŠÖ˜A•t‚¢‚Ä‚¢‚È‚¢‚È‚çA
+                    ƒf[ƒ^ƒx[ƒX‚©‚ç‚»‚ê‚ðƒ[ƒh‚·‚é‚©A‚ ‚é‚¢‚́AV‚µ‚¢‰i‘±‰»ƒCƒ“ƒXƒ^ƒ“ƒX‚ðì¬‚µ‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para>‰i‘±‰»ƒCƒ“ƒXƒ^ƒ“ƒX‚ª•Ô‚³‚ê‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para> ˆø”‚Æ‚µ‚Ä—^‚¦‚½ƒCƒ“ƒXƒ^ƒ“ƒX‚̓ZƒbƒVƒ‡ƒ“‚ÆŠÖ˜A‚ðŽ‚¿‚Ü‚¹‚ñB ‚»‚ê‚́A•ª—£ó‘Ô‚Ì‚Ü‚Ü‚Å‚·B
+                    </para>
+            </listitem>
+        </itemizedlist>
+        
+    </sect1>
+    
+    <sect1 id="objectstate-deleting" revision="1">
+        <title>‰i‘±ƒIƒuƒWƒFƒNƒg‚̍폜</title>
+        
+        <para>
+            <literal>Session.delete()</literal> 
+            ‚̓IƒuƒWƒFƒNƒg‚̏ó‘Ô‚ðƒf[ƒ^ƒx[ƒX‚©‚çíœ‚µ‚Ü‚·B ‚à‚¿‚ë‚ñAíœ‚µ‚½ƒIƒuƒWƒFƒNƒg‚ðƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ª•ÛŽ‚µ‚½‚Ü‚Ü‚Å‚à‚æ‚¢‚Å‚·B
+            ‚»‚Ì‚½‚߁A <literal>delete()</literal> ‚͉i‘±ƒCƒ“ƒXƒ^ƒ“ƒX‚ðˆêŽž“I‚É‚·‚é‚à‚̂ƍl‚¦‚é‚Ì‚ªˆê”Ô‚Å‚·B </para>
+        
+        <programlisting><![CDATA[sess.delete(cat);]]></programlisting>
+        
+        <para>
+            ŠO•”ƒL[§–ñ‚Ɉᔽ‚·‚郊ƒXƒN‚à‚È‚­AD‚«‚ȏ‡”ԂŃIƒuƒWƒFƒNƒg‚ðíœ‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            ‚½‚¾‚µAŠÔˆá‚Á‚½‡”ԂŃIƒuƒWƒFƒNƒg‚ðíœ‚·‚é‚ƁAŠO•”ƒL[ƒJƒ‰ƒ€‚Ì <literal>NOT NULL</literal> 
+            §–ñ‚Ɉᔽ‚·‚é‰Â”\«‚ª‚ ‚è‚Ü‚·B —Ⴆ‚΁AeƒIƒuƒWƒFƒNƒg‚ðíœ‚µ‚½‚Æ‚«‚ɁAŽq‹ŸƒIƒuƒWƒFƒNƒg‚ðíœ‚µ–Y‚ꂽê‡‚Å‚·B </para>
+        
+    </sect1>
+    
+    <sect1 id="objectstate-replicating" revision="1">
+        <title>ˆÙ‚È‚é“ñ‚‚̃f[ƒ^ƒXƒgƒAŠÔ‚ł̃IƒuƒWƒFƒNƒg‚̃ŒƒvƒŠƒP[ƒVƒ‡ƒ“</title>
+        
+        <para> 
+            ‰i‘±ƒCƒ“ƒXƒ^ƒ“ƒX‚̃Oƒ‰ƒt‚ð•Ê‚̃f[ƒ^ƒXƒgƒA‚ɉi‘±‰»‚·‚éê‡‚ɁA
+            Ž¯•ÊŽq‚Ì’l‚ðÄ¶¬‚¹‚¸‚É‚·‚Þ‚Æ•Ö—˜‚ȏꍇ‚ª‚ ‚è‚Ü‚·B </para>
+        
+        
+        <programlisting><![CDATA[//retrieve a cat from one database
+Session session1 = factory1.openSession();
+Transaction tx1 = session1.beginTransaction();
+Cat cat = session1.get(Cat.class, catId);
+tx1.commit();
+session1.close();
+
+//reconcile with a second database
+Session session2 = factory2.openSession();
+Transaction tx2 = session2.beginTransaction();
+session2.replicate(cat, ReplicationMode.LATEST_VERSION);
+tx2.commit();
+session2.close();]]></programlisting>
+        
+        <para>
+            ƒŒƒvƒŠƒP[ƒVƒ‡ƒ“æ‚̃f[ƒ^ƒx[ƒX‚ɍs‚ªŠù‚É‚ ‚éê‡A <literal>replicate()</literal>
+             ‚ªÕ“Ë‚ð‚ǂ̂悤‚Ɉµ‚¤‚©‚ð <literal>ReplicationMode</literal> ‚ÅŽw’肵‚Ü‚·B </para>
+        
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.IGNORE</literal> -
+                    “¯‚¶Ž¯•ÊŽq‚ðŽ‚Âs‚ªƒf[ƒ^ƒx[ƒX‚É‘¶Ý‚·‚é‚È‚çA ‚»‚̃IƒuƒWƒFƒNƒg‚𖳎‹‚µ‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.OVERWRITE</literal> - “¯‚¶Ž¯•ÊŽq‚ðŽ‚ÂŠù‘¶‚̍s‚ð
+                    ‚·‚ׂď㏑‚«‚µ‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.EXCEPTION</literal> -
+                    “¯‚¶Ž¯•ÊŽq‚ðŽ‚Âs‚ªƒf[ƒ^ƒx[ƒX‚É‘¶Ý‚·‚é‚È‚çA —áŠO‚ð“Š‚°‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para> 
+                    <literal>ReplicationMode.LATEST_VERSION</literal> -
+                    s‚É•Û‘¶‚³‚ê‚Ä‚¢‚éƒo[ƒWƒ‡ƒ“”ԍ†‚ªA ˆø”‚̃IƒuƒWƒFƒNƒg‚̃o[ƒWƒ‡ƒ“”ԍ†‚æ‚èŒÃ‚¢‚È‚ç‚΁A‚»‚̍s‚ðã‘‚«‚µ‚Ü‚·B
+                    </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            ŽŸ‚̂悤‚ȃP[ƒX‚ŁA‚±‚Ì‹@”\‚ðŽg—p‚µ‚Ü‚·B ˆÙ‚È‚éƒf[ƒ^ƒx[ƒXƒCƒ“ƒXƒ^ƒ“ƒX‚É“ü‚ê‚ç‚ꂽƒf[ƒ^‚Ì“¯ŠúA
+            »•iXVŽž‚É‚¨‚¯‚éƒVƒXƒeƒ€Ý’èî•ñ‚̍XVA”ñACIDƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Ì‚È‚©‚ʼnÁ‚¦‚ç‚ꂽ•ÏX‚̃[ƒ‹ƒoƒbƒN‚È‚Ç‚Å‚·B </para>
+        
+    </sect1>
+    
+    <sect1 id="objectstate-flushing">
+        <title>ƒZƒbƒVƒ‡ƒ“‚̃tƒ‰ƒbƒVƒ…</title>
+        
+        <para>
+            JDBCƒRƒlƒNƒVƒ‡ƒ“‚̏ó‘Ԃƃƒ‚ƒŠã‚̃IƒuƒWƒFƒNƒg‚̏ó‘Ԃ𓯊ú‚³‚¹‚邽‚ß‚É•K—v‚È
+            SQL•¶‚ð <literal>Session</literal> ‚ªŽÀs‚·‚邱‚Æ‚ª‚Æ‚«‚Ç‚«‚ ‚è‚Ü‚·B ‚±‚̏ˆ—
+             <emphasis>flush</emphasis> ‚́AƒfƒtƒHƒ‹ƒg‚Å‚ÍŽŸ‚Ì‚Æ‚«‚É‹N‚±‚è‚Ü‚·B </para>
+        
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para> ƒNƒGƒŠ‚ðŽÀs‚·‚é‘O </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.Transaction.commit()</literal> ‚ðŽÀs‚µ‚½‚Æ‚«
+                    </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>Session.flush()</literal> ‚ðŽÀs‚µ‚½‚Æ‚« </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>  SQL•¶‚͈ȉº‚̏‡”Ô‚Å”­s‚³‚ê‚Ü‚·B
+            </para>
+        
+        <orderedlist spacing="compact">
+            <listitem>
+                <para>
+                    ‚·‚ׂẴGƒ“ƒeƒBƒeƒB‚Ì‘}“üB‚±‚ê‚́A <literal>Session.save()</literal> ‚ðŽg‚Á‚ăZ[ƒu‚µ‚½
+                    ƒIƒuƒWƒFƒNƒg‚̏‡‚ÉŽÀs‚µ‚Ä‚¢‚«‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para> ‚·‚ׂẴGƒ“ƒeƒBƒeƒB‚̍XV </para>
+            </listitem>
+            <listitem>
+                <para> ‚·‚ׂẴRƒŒƒNƒVƒ‡ƒ“‚̍폜 </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ‚·‚ׂẴRƒŒƒNƒVƒ‡ƒ“‚Ì—v‘f‚ɑ΂·‚éíœAXVA‘}“ü </para>
+            </listitem>
+            <listitem>
+                <para>‚·‚ׂẴRƒŒƒNƒVƒ‡ƒ“‚Ì‘}“ü </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ‚·‚ׂẴGƒ“ƒeƒBƒeƒB‚̍폜B‚±‚ê‚́A<literal>Session.delete()</literal> ‚ðŽg‚Á‚Ä
+                    íœ‚µ‚½ƒIƒuƒWƒFƒNƒg‚̏‡‚ÉŽÀs‚µ‚Ä‚¢‚«‚Ü‚·B </para>
+            </listitem>
+        </orderedlist>
+        
+        <para>
+            (‚P‚—áŠO‚ª‚ ‚è‚Ü‚·B <literal>native</literal> ID ¶¬‚ðŽg‚Á‚½ƒIƒuƒWƒFƒNƒg‚́A
+            ‚»‚ê‚炪ƒZ[ƒu‚³‚ꂽ‚Æ‚«‚É‘}“ü‚³‚ê‚Ü‚·Bj </para>
+        
+        <para>
+             –¾Ž¦“I‚É
+             <literal>flush()</literal> ‚·‚é‚Æ‚«‚ðœ‚¢‚āA <emphasis>‚¢‚Â</emphasis>
+            <literal>Session</literal> ‚ªJDBC‚ðƒR[ƒ‹‚·‚é‚Ì‚©‚ɂ‚¢‚Ä
+             â‘ΓI‚ȕۏ؂͂ ‚è‚Ü‚¹‚ñB‚½‚¾‚µA‚»‚ê‚炪ŽÀs‚³‚ê‚é <emphasis>‡”Ô</emphasis> ‚¾‚¯‚Í •ÛØ‚³‚ê‚Ü‚·B
+            ‚Ü‚½AHibernate ‚́A <literal>Query.list(..)</literal> ‚ªŒÃ‚¢ƒf[ƒ^‚âŠÔˆá‚Á‚½ƒf[ƒ^•Ô‚³‚È‚¢‚±‚Æ‚ð
+            •ÛØ‚µ‚Ä‚¢‚Ü‚·B </para>
+        
+        <para>
+            ƒtƒ‰ƒbƒVƒ…‚ª•p”É‚É‹N‚±‚ç‚È‚¢‚悤‚ɃfƒtƒHƒ‹ƒg‚̐U‚é•‘‚¢‚ð•Ï‚¦‚邱‚Æ‚ª‚Å‚«‚Ü‚·B <literal>FlushMode</literal>
+            ƒNƒ‰ƒX‚Í3‚‚̈قȂ郂[ƒh‚ð’è‹`‚µ‚Ü‚·B ‚»‚ê‚́AƒRƒ~ƒbƒgŽž‚É‚¾‚¯ƒtƒ‰ƒbƒVƒ…‚·‚郂[ƒh iHibernate‚Ì
+             <literal>Transaction</literal> API‚ªŽg‚í‚ê‚éê‡‚¾‚¯‚Å‚·jA
+            à–¾‚Ì‚ ‚Á‚½ˆ—‡‚ÉŠî‚¢‚ÄŽ©“®‚Ńtƒ‰ƒbƒVƒ…‚·‚郂[ƒhA <literal>flush()</literal> 
+            ‚ª–¾Ž¦“I‚ɌĂ΂ê‚È‚¢ŒÀ‚èƒtƒ‰ƒbƒVƒ…‚µ‚È‚¢ƒ‚[ƒh‚Ì‚R‚‚ł·B ÅŒã‚̃‚[ƒh‚́Aì‹Æ’PˆÊ‚ª’·ŠúŠÔ‚É‹y‚ԏꍇ‚É–ð‚É—§‚¿‚Ü‚· ( <xref
+                linkend="transactions-optimistic-longsession"/> ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢)B
+            </para>
+        
+        
+        <programlisting><![CDATA[sess = sf.openSession();
+Transaction tx = sess.beginTransaction();
+sess.setFlushMode(FlushMode.COMMIT); // allow queries to return stale state
+
+Cat izi = (Cat) sess.load(Cat.class, id);
+izi.setName(iznizi);
+
+// might return stale data
+sess.find("from Cat as cat left outer join cat.kittens kitten");
+
+// change to izi is not flushed!
+...
+tx.commit(); // flush occurs
+sess.close();]]></programlisting>
+        
+        <para>ƒtƒ‰ƒbƒVƒ…‚Ì‚Æ‚«A—áŠO‚ª”­¶‚·‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+            i—Ⴆ‚΁ADML‘€ì‚ª§–ñ‚ðˆá”½‚·‚é‚悤‚ȏꍇ‚Å‚·Bj
+            —áŠOˆ—‚ð—‰ð‚·‚é‚½‚߂ɂ́AHibernate‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̐U‚é•‘‚¢‚ð—‰ð‚·‚é•K—v‚ª‚ ‚邽‚߁A <xref
+                linkend="transactions"/> ‚Åà–¾‚µ‚Ü‚·B </para>
+        
+    </sect1>
+    
+    <sect1 id="objectstate-transitive" revision="1">
+        <title>˜A½“I‚ȉi‘±‰»</title>
+        
+        <para>
+            ŒÂX‚̃IƒuƒWƒFƒNƒg‚ðƒZ[ƒu‚µ‚½‚èAíœ‚µ‚½‚èAÄ’ljÁ‚µ‚½‚è‚·‚邱‚Æ‚Í
+            ‚©‚È‚è–Ê“|‚Å‚·B“Á‚ɁAŠÖ˜A‚·‚éƒIƒuƒWƒFƒNƒg‚ðˆµ‚¤‚悤‚ȏꍇ‚ɂ͍ۗ§‚¿‚Ü‚·B ‚æ‚­‚ ‚é‚̂́AeŽqŠÖŒW‚ðˆµ‚¤ƒP[ƒX‚Å‚·B
+            ˆÈ‰º‚Ì—á‚ðl‚¦‚Ä‚Ý‚Ü‚µ‚傤B </para>
+        
+        <para>
+            ‚à‚µAeŽqŠÖŒW‚ÌŽq‚ª’lŒ^‚È‚çi—Ⴆ‚΁AZŠ‚╶Žš—ñ‚̃RƒŒƒNƒVƒ‡ƒ“jA
+            ‚»‚ê‚ç‚̃‰ƒCƒtƒTƒCƒNƒ‹‚͐e‚Ɉˑ¶‚µ‚Ä‚¨‚èA•Ö—˜‚ȏó‘ԕω»‚Ì"ƒJƒXƒP[ƒh"‚ðŽg‚¤‚½‚߂ɁA ’ljÁ‚̍ì‹Æ‚Í•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+            e‚ªƒZ[ƒu‚³‚ꂽ‚Æ‚«A’lŒ^‚ÌŽqƒIƒuƒWƒFƒNƒg‚à“¯‚¶‚悤‚ɃZ[ƒu‚³‚ê‚Ü‚·‚µA e‚ªíœ‚³‚ꂽ‚Æ‚«‚́AŽq‚àíœ‚³‚ê‚Ü‚·B‚»‚Ì‘¼‚Ì‘€ì‚à“¯‚¶‚Å‚·B
+            ƒRƒŒƒNƒVƒ‡ƒ“‚©‚ç1‚‚̎q‚ðíœ‚·‚é‚悤‚È‘€ì‚Å‚à‚¤‚Ü‚­‚¢‚«‚Ü‚·B ‚·‚È‚í‚¿AHibernate‚Í‚±‚̍폜‘€ì‚ðŒŸo‚·‚é‚ƁA
+            ’lŒ^‚̃IƒuƒWƒFƒNƒg‚ÍŽQÆ‚ð‹¤—L‚Å‚«‚È‚¢‚̂ŁAƒf[ƒ^ƒx[ƒX‚©‚ç‚»‚ÌŽq‹Ÿ‚ðíœ‚µ‚Ü‚·B </para>
+        
+        <para>‚±‚±‚ŁAe‚ÆŽq‚ª’lŒ^‚Å‚È‚­ƒGƒ“ƒeƒBƒeƒB‚Å‚ ‚é‚Æ‚µ‚Ä“¯‚¶ƒVƒiƒŠƒI‚ðl‚¦‚Ä‚Ý‚Ü‚µ‚傤B
+            i—Ⴆ‚΁AƒJƒeƒSƒŠ[‚Æ•i–Ú‚ÌŠÖŒW‚âe‚ÆŽq‚Ì”L‚ÌŠÖŒW‚Å‚·Bj ƒGƒ“ƒeƒBƒeƒB‚́A‚»‚ꎩg‚ªƒ‰ƒCƒtƒTƒCƒNƒ‹‚ðŽ‚¿AŽQÆ‚Ì‹¤—L‚ðƒTƒ|[ƒg‚µ‚Ü‚·B
+            i‚»‚Ì‚½‚߁AƒRƒŒƒNƒVƒ‡ƒ“‚©‚çƒGƒ“ƒeƒBƒeƒB‚ðíœ‚·‚邱‚Ƃ́A ƒGƒ“ƒeƒBƒeƒBŽ©g‚̍폜‚ðˆÓ–¡‚µ‚Ü‚¹‚ñBj
+            ‚Ü‚½AƒGƒ“ƒeƒBƒeƒB‚́AƒfƒtƒHƒ‹ƒg‚ł́AŠÖ˜A‚·‚鑼‚̃Gƒ“ƒeƒBƒeƒB‚Ö ó‘Ô‚ðƒJƒXƒP[ƒh‚·‚邱‚Æ‚Í‚ ‚è‚Ü‚¹‚ñB Hibernate‚Í
+             <emphasis>“ž’B‰Â”\«‚É‚æ‚é‰i‘±‰»</emphasis> ‚ðƒfƒtƒHƒ‹ƒg‚Å‚ÍŽÀs‚µ‚Ü‚¹‚ñB </para>
+        
+        <para>
+            Hibernate‚ÌSession‚ÌŠî–{‘€ìi <literal>persist(), merge(), saveOrUpdate(),
+            delete(), lock(), refresh(), evict(), replicate()</literal> ‚ªŠÜ‚Ü‚ê‚Ü‚·j‚ɑ΂µ‚āA
+            ‚»‚ꂼ‚ê‚ɑΉž‚·‚éƒJƒXƒP[ƒhƒXƒ^ƒCƒ‹‚ª‚ ‚è‚Ü‚·B ‚»‚ꂼ‚ê‚̃JƒXƒP[ƒhƒXƒ^ƒCƒ‹‚ɂ́A <literal>create, merge,
+            save-update, delete, lock, refresh, evict, replicate</literal> 
+            ‚Æ‚¢‚¤–¼‘O‚ª‚‚¢‚Ä‚¢‚Ü‚·B ‚à‚µAŠÖ˜A‚ɉˆ‚Á‚ăJƒXƒP[ƒh‚³‚¹‚½‚¢‘€ì‚ª‚ ‚é‚È‚çAƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚É‚»‚¤Žw’肵‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            —Ⴆ‚΁AˆÈ‰º‚̂悤‚É‚µ‚Ü‚·B </para>
+        
+        
+        <programlisting><![CDATA[<one-to-one name="person" cascade="persist"/>]]></programlisting>
+        
+        <para> ƒJƒXƒP[ƒhƒXƒ^ƒCƒ‹‚́A‘g‚ݍ‡‚킹‚邱‚Æ‚ª‚Å‚«‚Ü‚·B </para>
+        
+        
+        <programlisting><![CDATA[<one-to-one name="person" cascade="persist,delete,lock"/>]]></programlisting>
+        
+        <para>
+            <emphasis>‚·‚ׂĂÌ</emphasis>
+            ‘€ì‚ðŠÖ˜A‚ɉˆ‚Á‚ăJƒXƒP[ƒh‚·‚é‚悤Žw’è‚·‚é‚Æ‚«‚́A <literal>cascade="all"</literal> ‚ðŽg‚¢‚Ü‚·B
+            ƒfƒtƒHƒ‹ƒg‚Ì <literal>cascade="none"</literal> ‚́A‚Ç‚Ì‘€ì‚àƒJƒXƒP[ƒh‚µ‚È‚¢‚±‚Æ‚ðˆÓ–¡‚µ‚Ü‚·B
+            </para>
+        
+        <para>
+             “ÁŽê‚ȃJƒXƒP[ƒhƒXƒ^ƒCƒ‹
+             <literal>delete-orphan</literal> ‚́Aˆê‘Α½ŠÖ˜A‚É‚¾‚¯ “K—p‚Å‚«‚Ü‚·B
+            ‚±‚ê‚́AŠÖ˜A‚©‚çíœ‚³‚ꂽŽq‹Ÿ‚̃IƒuƒWƒFƒNƒg‚ɑ΂µ‚āA <literal>delete()</literal> 
+            ‘€ì‚ª“K—p‚³‚ê‚邱‚Æ‚ðˆÓ–¡‚µ‚Ü‚·B </para>
+        
+        <para>‚¨‚·‚·‚߁F </para>
+        
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para> 
+                    •’ʁA <literal>&lt;many-to-one&gt;</literal> ‚â
+                     <literal>&lt;many-to-many&gt;</literal> ŠÖ˜A‚ɑ΂µ‚ẮA
+                    ƒJƒXƒP[ƒh‚ðÝ’è‚·‚éˆÓ–¡‚Í‚ ‚è‚Ü‚¹‚ñB <literal>&lt;one-to-one&gt;</literal> ‚Æ
+                     <literal>&lt;one-to-many&gt;</literal> ŠÖ˜A‚ɑ΂µ‚ẮA
+                    ƒJƒXƒP[ƒh‚ª–ð‚É—§‚‚±‚Æ‚ª‚ ‚è‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para> 
+                    Žq‹ŸƒIƒuƒWƒFƒNƒg‚ÌŽõ–½‚ªeƒIƒuƒWƒFƒNƒg‚ÌŽõ–½‚ɐ§ŒÀ‚ðŽó‚¯‚é‚È‚ç‚΁A
+                     <literal>cascade="all,delete-orphan"</literal> ‚ðŽw’肵A Žq‹ŸƒIƒuƒWƒFƒNƒg‚ð
+                     <emphasis>ƒ‰ƒCƒtƒTƒCƒNƒ‹ƒIƒuƒWƒFƒNƒg</emphasis> ‚É‚µ‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para> .
+                    ‚»‚êˆÈŠO‚̏ꍇ‚́AƒJƒXƒP[ƒh‚Í‚Ù‚Æ‚ñ‚Ç•K—v‚È‚¢‚Å‚µ‚傤B
+                    ‚µ‚©‚µA“¯‚¶ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Ì‚È‚©‚Őe‚ÆŽq‚ªˆê‚É“®ì‚·‚邱‚Æ‚ª‘½‚¢‚ÆŽv‚¢A
+                    ‚¢‚­‚ç‚©‚̃R[ƒh‚ð‘‚­ŽèŠÔ‚ðÈ‚«‚½‚¢‚Ì‚Å‚ ‚ê‚΁A
+                     <literal>cascade="persist,merge,save-update"</literal>
+                     ‚ðŽg‚¤‚±‚Æ‚ðl‚¦‚Ü‚µ‚傤B </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para> <literal>cascade="all"</literal> ‚Ń}ƒbƒsƒ“ƒO‚µ‚½ŠÖ˜Ai’P’lŠÖ˜A‚âƒRƒŒƒNƒVƒ‡ƒ“j‚́A
+            <emphasis>eŽq</emphasis> ƒXƒ^ƒCƒ‹‚ÌŠÖ˜A‚ƃ}[ƒN‚³‚ê‚Ü‚·B
+            ‚»‚ê‚́Ae‚̃Z[ƒu/XV/íœ‚ªAŽq‚̃Z[ƒu/XV/íœ‚ðˆø‚«‹N‚±‚·ŠÖŒW‚Ì‚±‚Æ‚Å‚·B </para>
+            
+        <para>
+            ‚³‚ç‚ɁA‰i‘±‰»‚³‚ꂽe‚ªŽq‚ð’P‚ÉŽQÆ‚µ‚Ä‚¢‚邾‚¯‚ŁAŽq‚̃Z[ƒu/XV‚ðˆø‚«‹N‚±‚µ‚Ü‚·B
+            ‚µ‚©‚µA‚±‚̃ƒ^ƒtƒ@[‚Í•sŠ®‘S‚Å‚·Be‚©‚çŽQÆ‚³‚ê‚È‚­‚È‚Á‚½Žq‚́AŽ©“®“I‚ɍ폜 <emphasis>‚³‚ê‚Ü‚¹‚ñ</emphasis> B
+            ‚½‚¾‚µA <literal>cascade="delete-orphan"</literal> ‚Ń}ƒbƒsƒ“ƒO‚³‚ꂽ
+            <literal>&lt;one-to-many&gt;</literal> ŠÖ˜A‚𠏜‚¢‚Ä‚Å‚·B
+            eŽqŠÖŒW‚̃JƒXƒP[ƒh‘€ì‚̐³Šm‚ȈӖ¡‚͈ȉº‚̂悤‚É‚È‚è‚Ü‚·B </para>
+        
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                     e‚ª
+                     <literal>persist()</literal> ‚É“n‚³‚ꂽ‚È‚ç‚΁A ‚·‚ׂĂ̎q‚Í
+                     <literal>persist()</literal> ‚É“n‚³‚ê‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para> 
+                     <literal>merge()</literal> ‚É“n‚³‚ꂽ‚È‚ç‚΁A ‚·‚ׂĂ̎q‚Í
+                     <literal>merge()</literal> ‚É“n‚³‚ê‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para>
+                     e‚ª <literal>save()</literal>
+                     A <literal>update()</literal>
+                     A <literal>saveOrUpdate()</literal> ‚É“n‚³‚ꂽ‚È‚ç‚΁A‚·‚ׂĂ̎q‚Í
+                     <literal>saveOrUpdate()</literal> ‚É“n‚³‚ê‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ˆêŽž“I‚Ü‚½‚Í•ª—£ó‘Ô‚ÌŽq‚ªA‰i‘±‰»‚³‚ꂽe‚ÉŽQÆ‚³‚ꂽ‚È‚ç‚΁A
+                     <literal>saveOrUpdate()</literal> ‚É“n‚³‚ê‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para>
+                    e‚ªíœ‚³‚ꂽ‚È‚ç‚΁A‚·‚ׂĂ̎q‚́A <literal>delete()</literal> ‚É“n‚³‚ê‚Ü‚·B </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Žq‚ª‰i‘±‰»‚³‚ꂽe‚©‚çŽQÆ‚³‚ê‚È‚­‚È‚Á‚½‚Æ‚«‚́A <emphasis>“Á‚ɉ½‚à‹N‚±‚è‚Ü‚¹‚ñ</emphasis> B
+                    ‚æ‚Á‚āAƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ª•K—v‚Å‚ ‚ê‚΁A–¾Ž¦“I‚ɍ폜‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+                    ‚½‚¾‚µA <literal>cascade="delete-orphan"</literal> ‚̏ꍇ‚ðœ‚«‚Ü‚·B
+                    ‚±‚̏ꍇAue‚Ì‚È‚¢vŽq‚͍폜‚³‚ê‚Ü‚·B </para>
+            </listitem>
+        </itemizedlist>
+        <para>
+            ÅŒã‚ɁA‘€ì‚̃JƒXƒP[ƒh‚ªƒIƒuƒWƒFƒNƒgƒOƒ‰ƒt‚É“K—p‚³‚ê‚é‚̂́A <emphasis>ƒR[ƒ‹‚µ‚½Žž</emphasis>
+             ‚ ‚é‚¢‚́A <emphasis>flush‚µ‚½Žž</emphasis> ‚Å‚ ‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚·‚ׂĂ̑€ì‚́A‚»‚Ì‘€ì‚ªŽÀs‚³‚ꂽ‚Æ‚«‚ɁA“ž’B‰Â”\‚ÈŠÖ˜A‚·‚éƒGƒ“ƒeƒBƒeƒB‚ɑ΂µ‚Ä 
+            ƒJƒXƒP[ƒh‚ª‰Â”\‚È‚çƒJƒXƒP[ƒh‚µ‚Ü‚·B
+            ‚µ‚©‚µA <literal>save-upate</literal> ‚Æ
+             <literal>delete-orphan</literal> ‚́A <literal>Session</literal> 
+            ‚ªflush‚µ‚Ä‚¢‚éŠÔ‚ɁA ‚·‚ׂĂ̓ž’B‰Â”\‚ÈŠÖ˜A‚·‚éƒGƒ“ƒeƒBƒeƒB‚É“`”d‚µ‚Ü‚·B</para>
+    </sect1>
+    
+    <sect1 id="objectstate-metadata">
+        <title>ƒƒ^ƒf[ƒ^‚ÌŽg—p</title>
+        
+        <para>
+             Hibernate‚́A‚·‚ׂẴGƒ“ƒeƒBƒeƒB‚Æ’lŒ^‚Ì”ñí‚ɃŠƒbƒ`‚ȃƒ^ƒŒƒxƒ‹‚̃‚ƒfƒ‹‚ð•K—v‚Æ‚µ‚Ü‚·B
+            ‚Æ‚«‚Ç‚«A‚±‚̃‚ƒfƒ‹‚̓AƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚Æ‚Á‚Ä‚Æ‚Ä‚à–ð‚É—§‚¿‚Ü‚·B
+            —Ⴆ‚΁AƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚́AHibernate‚̃ƒ^ƒf[ƒ^‚ðŽg‚Á‚āA"Œ«‚¢" ƒfƒB[ƒvƒRƒs[ƒAƒ‹ƒSƒŠƒYƒ€‚ð
+            ŽÀ‘•‚Å‚«‚é‚©‚à‚µ‚Ü‚¹‚ñB‚»‚̃Aƒ‹ƒSƒŠƒYƒ€‚Ƃ́A‚ǂ̃IƒuƒWƒFƒNƒg‚ªƒRƒs[‚³‚ê‚é‚ׂ«‚©i—áF‰Â•Ï‚Ì’lŒ^j‚â
+            ‚ǂ̃IƒuƒWƒFƒNƒg‚̓Rƒs[‚³‚ê‚È‚¢‚ׂ«‚©i—áF•s•Ï‚È’lŒ^‚â‰Â”\‚È‚çŠÖ˜A‚·‚éƒGƒ“ƒeƒBƒeƒBj‚ð ”»’f‚Å‚«‚é‚à‚Ì‚Å‚·B </para>
+            
+            
+        <para> 
+            Hibernate‚Í<literal>ClassMetadata</literal>
+            ‚Æ<literal>CollectionMetadata</literal> ƒCƒ“ƒ^ƒtƒF[ƒX‚Æ
+             <literal>Type</literal> ŠK‘w‚ð’Ê‚µ‚ăƒ^ƒf[ƒ^‚ðŒöŠJ‚µ‚Ü‚·B
+            ƒƒ^ƒf[ƒ^ƒCƒ“ƒ^[ƒtƒFƒCƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚́A <literal>SessionFactory</literal> ‚©‚瓾‚ç‚ê‚Ü‚·B
+            </para>
+        
+        
+        <programlisting><![CDATA[Cat fritz = ......;
+ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class);
+
+Object[] propertyValues = catMeta.getPropertyValues(fritz);
+String[] propertyNames = catMeta.getPropertyNames();
+Type[] propertyTypes = catMeta.getPropertyTypes();
+
+// get a Map of all properties which are not collections or associations
+Map namedValues = new HashMap();
+for ( int i=0; i<propertyNames.length; i++ ) {
+    if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType() ) {
+        namedValues.put( propertyNames[i], propertyValues[i] );
+    }
+}]]></programlisting>
+        
+    </sect1>
+    
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/toolset_guide.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/toolset_guide.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/toolset_guide.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,634 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="toolsetguide" revision="2">
+    <title>Toolset Guide
+    
+    ƒc[ƒ‹ƒZƒbƒgƒKƒCƒh
+    </title>
+
+    <para>
+         Hibernate‚ðŽg‚Á‚½ƒ‰ƒEƒ“ƒhƒgƒŠƒbƒvƒGƒ“ƒWƒjƒAƒŠƒ“ƒO‚́A
+         Eclipseƒvƒ‰ƒOƒCƒ“‚âƒRƒ}ƒ“ƒhƒ‰ƒCƒ“ƒc[ƒ‹A‚à‚¿‚ë‚ñAntƒ^ƒXƒN‚ðŽg‚¤‚±‚Ƃʼn”\‚Å‚·B
+    </para>
+
+    <para>
+         <emphasis>Hibernate Tools</emphasis> ‚ÍŒ»ÝAŠù‘¶ƒf[ƒ^ƒx[ƒX‚̃Šƒo[ƒXƒGƒ“ƒWƒjƒAƒŠƒ“ƒO‚ÌAntƒ^ƒXƒN‚ɉÁ‚¦‚āAEclipseIDE‚̃vƒ‰ƒOƒCƒ“‚ðŠÜ‚Ý‚Ü‚·B
+    </para>
+
+    <itemizedlist>
+        <listitem><para>
+             <emphasis>ƒ}ƒbƒsƒ“ƒOƒGƒfƒBƒ^:</emphasis> 
+            Hibernate‚ÌXMLƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹—p‚̃GƒfƒBƒ^‚ŁA
+            Ž©“®•âŠ®‚ƍ\•¶‹­’²•\Ž¦‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·BƒNƒ‰ƒX–¼‚âƒvƒƒpƒeƒB/ƒtƒB[ƒ‹ƒh–¼‚ɑ΂·‚鎩“®•âŠ®‚àƒTƒ|[ƒg‚µA
+            ’ʏí‚ÌXMLƒGƒfƒBƒ^‚æ‚è‚à‹­—Í‚Å‚·B
+        </para></listitem>
+        <listitem><para>
+             <emphasis>Console:</emphasis> 
+            ƒRƒ“ƒ\[ƒ‹‚̓GƒNƒŠƒvƒX‚̐V‚µ‚¢ƒrƒ…[‚Å‚·B
+            ƒRƒ“ƒ\[ƒ‹ƒRƒ“ƒtƒBƒMƒ…ƒŒ[ƒVƒ‡ƒ“‚̃cƒŠ[ƒI[ƒo[ƒrƒ…[‚ɉÁ‚¦‚āA‰i‘±ƒNƒ‰ƒX‚Æ‚»‚ÌŠÖ˜A‚Ì‘ŠŒÝì—pƒrƒ…[‚à“¾‚ç‚ê‚Ü‚·B
+            ƒf[ƒ^ƒx[ƒX‚ÉHQL‚ðŽÀs‚µAŒ‹‰Ê‚𒼐ڃGƒNƒŠƒvƒXã‚ÅŒ©‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+        </para></listitem>
+        <listitem><para>
+             <emphasis>ŠJ”­ƒEƒBƒU[ƒh</emphasis> 
+            Hibernate‚ÌEclipseƒc[ƒ‹‚Í‚¢‚­‚‚©‚̃EƒBƒU[ƒh‚ð’ñ‹Ÿ‚µ‚Ü‚·B
+            ƒEƒBƒU[ƒh‚ðŽg‚Á‚ÄHibernate‚̐ݒèƒtƒ@ƒCƒ‹(cfg.xml)‚ð‚·‚Î‚â‚­¶¬‚µ‚½‚èA
+            Šù‘¶‚̃f[ƒ^ƒx[ƒXƒXƒL[ƒ}‚ðPOJO‚̃\[ƒXƒtƒ@ƒCƒ‹‚ÆHibernate‚̃}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ւƁA
+            Š®‘S‚ɃŠƒo[ƒXƒGƒ“ƒWƒjƒAƒŠƒ“ƒO‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            ƒŠƒo[ƒXƒGƒ“ƒWƒjƒAƒŠƒ“ƒOƒEƒBƒU[ƒh‚̓JƒXƒ^ƒ}ƒCƒY‰Â”\‚ȃeƒ“ƒvƒŒ[ƒg‚ðƒTƒ|[ƒg‚µ‚Ü‚·B
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Ant Tasks:</emphasis> 
+        </para></listitem>
+
+    </itemizedlist>
+
+    <para>
+        ‚æ‚èÚ‚µ‚¢î•ñ‚Í <emphasis>Hibernate Tools</emphasis>  ƒpƒbƒP[ƒW‚Æ‚»‚̃hƒLƒ…ƒƒ“ƒg‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+    </para>
+
+    <para>
+        ‚µ‚©‚µAHibernate‚̃ƒCƒ“ƒpƒbƒP[ƒW‚Í <emphasis>SchemaExport</emphasis> A
+        •Ê–¼ <literal>hbm2ddl</literal> ‚àŠÜ‚Ý‚Ü‚·(Hibernate“à‚ŃIƒ“ƒUƒtƒ‰ƒC‚ÅŽg—p‚Å‚«‚Ü‚·)B
+    </para>
+
+    <sect1 id="toolsetguide-s1" revision="2">
+        <title>ƒXƒL[ƒ}‚ÌŽ©“®¶¬</title>
+
+        <para>
+            DDL‚ÍHibernateƒ†[ƒeƒBƒŠƒeƒB‚É‚æ‚èƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚©‚琶¬‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            ¶¬‚³‚ꂽƒXƒL[ƒ}‚̓Gƒ“ƒeƒBƒeƒB‚âƒRƒŒƒNƒVƒ‡ƒ“‚̃e[ƒuƒ‹‚ɑ΂·‚éŽQÆ®‡«§–ñ(ŽåƒL[‚ÆŠO•”ƒL[)‚ðŠÜ‚Ý‚Ü‚·B
+            ƒe[ƒuƒ‹‚ƃV[ƒPƒ“ƒX‚̓}ƒbƒsƒ“ƒO‚·‚鎯•ÊŽqƒWƒFƒlƒŒ[ƒ^‚ɑ΂µ‚ж¬‚³‚ê‚Ü‚·B
+        </para>
+        
+        <para>
+            DDL‚̓xƒ“ƒ_[ˆË‘¶‚Ȃ̂ŁA‚±‚̃c[ƒ‹‚ðŽg‚¤‚Æ‚«‚́A<literal>hibernate.dialect</literal>  
+            ƒvƒƒpƒeƒB‚ÅSQL‚Ì <literal>•ûŒ¾</literal>  ‚ðŽw’è <emphasis>‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ</emphasis>  B
+        </para>
+
+        <para>
+            ‚Ü‚¸A¶¬‚³‚ê‚éƒXƒL[ƒ}‚ð‰ü‘P‚·‚é‚悤‚ɁAƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ðƒJƒXƒ^ƒ}ƒCƒY‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+        <sect2 id="toolsetguide-s1-2" revision="3">
+            <title>ƒXƒL[ƒ}‚̃JƒXƒ^ƒ}ƒCƒY</title>
+
+            <para>
+                ‘½‚­‚ÌHibernate‚̃}ƒbƒsƒ“ƒO—v‘f‚ł́AƒIƒvƒVƒ‡ƒ“‚Ì <literal>length</literal>  ‚Æ‚¢‚¤–¼‚Ì‘®«‚ð’è‹`‚µ‚Ä‚¢‚Ü‚·B
+                ‚±‚Ì‘®«‚ŃJƒ‰ƒ€’·‚ðÝ’è‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·(‚Ü‚½‚ÍNUMERIC/DECIMALŒ^‚̃f[ƒ^‚̐¸“x‚ðÝ’è‚Å‚«‚Ü‚·)B
+            </para>
+
+            <para>
+                <literal>not-null</literal>  ‘®«iƒe[ƒuƒ‹‚̃Jƒ‰ƒ€‚Ö <literal>NOT NULL</literal>  §–ñ‚𐶐¬‚·‚éj‚Æ 
+                <literal>unique</literal>  ‘®«iƒe[ƒuƒ‹‚̃Jƒ‰ƒ€‚Ö <literal>UNIQUE</literal>  §–ñ‚𐶐¬‚·‚éj‚ªÝ’è‚Å‚«‚éƒ^ƒO‚à‚ ‚è‚Ü‚·B
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="bar" column="barId" not-null="true"/>]]></programlisting>
+
+            <programlisting><![CDATA[<element column="serialNumber" type="long" not-null="true" unique="true"/>]]></programlisting>
+
+            <para>
+                <literal>unique-key</literal>  ‘®«‚̓Jƒ‰ƒ€‚ðƒOƒ‹[ƒv‰»‚µ‚Ĉê‚‚̃L[§–ñ‚É‚·‚邽‚ß‚ÉŽg‚í‚ê‚Ü‚·B
+                Œ»ÝA<literal>unique-key</literal>  ‘®«‚ÅŽw’肳‚ꂽ’l‚͐§–ñ‚ÌŽw’è‚É‚Í  <emphasis>Žg‚í‚ꂸ</emphasis> A
+                ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ŃJƒ‰ƒ€‚ðƒOƒ‹[ƒv‰»‚·‚邱‚Æ‚É‚Ì‚ÝŽg‚í‚ê‚Ü‚·B 
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="org" column="orgId" unique-key="OrgEmployeeId"/>
+<property name="employeeId" unique-key="OrgEmployee"/>]]></programlisting>
+
+            
+
+            <para>
+                <literal>index</literal> ‘®«‚̓}ƒbƒsƒ“ƒO‚·‚éƒJƒ‰ƒ€‚ðŽg‚Á‚ж¬‚µ‚½ƒCƒ“ƒfƒbƒNƒX‚Ì–¼‘O‚ðŽw’肵‚Ü‚·B
+                •¡”ƒJƒ‰ƒ€‚ð‚P‚‚̃Cƒ“ƒfƒbƒNƒX‚ɃOƒ‹[ƒv‰»‚Å‚«‚Ü‚·B’P‚ɁA“¯‚¶ƒCƒ“ƒfƒbƒNƒX–¼‚ðŽw’è‚·‚邾‚¯‚Å‚·B
+            </para>
+            
+<programlisting><![CDATA[<property name="lastName" index="CustName"/>
+<property name="firstName" index="CustName"/>]]></programlisting>
+
+            <para>
+                <literal>foreign-key</literal> ‘®«‚́A¶¬‚³‚ꂽŠO•”ƒL[§–ñ‚Ì–¼‘O‚ðƒI[ƒo[ƒ‰ƒCƒh‚·‚邽‚ß‚ÉŽg—p‚Å‚«‚Ü‚·B
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="bar" column="barId" foreign-key="FKFooBar"/>]]></programlisting>
+
+            <para>
+                ‘½‚­‚̃}ƒbƒsƒ“ƒO—v‘f‚́AŽq <literal>&lt;column&gt;</literal>  —v‘f‚ð‹Lq‚Å‚«‚Ü‚·B‚±‚ê‚Í•¡”ƒJƒ‰ƒ€Œ^‚̃}ƒbƒsƒ“ƒO‚É‚Í“Á‚É—L—p‚Å‚·B
+            </para>
+
+            <programlisting><![CDATA[<property name="name" type="my.customtypes.Name"/>
+    <column name="last" not-null="true" index="bar_idx" length="30"/>
+    <column name="first" not-null="true" index="bar_idx" length="20"/>
+    <column name="initial"/>
+</property>]]></programlisting>
+
+            <para>
+                 <literal>default</literal> ‘®«‚̓Jƒ‰ƒ€‚̃fƒtƒHƒ‹ƒg’l‚ðŽw’肵‚Ü‚·
+                 (ƒ}ƒbƒsƒ“ƒO‚µ‚½ƒNƒ‰ƒX‚̐V‚µ‚¢ƒCƒ“ƒXƒ^ƒ“ƒX‚ð•Û‘¶‚·‚é‘O‚ɁA
+                 ƒ}ƒbƒsƒ“ƒO‚µ‚½ƒvƒƒpƒeƒB‚Ö“¯‚¶’l‚ð‘ã“ü‚·‚ׂ«‚Å‚·)B
+            </para>
+
+            <programlisting><![CDATA[<property name="credits" type="integer" insert="false">
+    <column name="credits" default="10"/>
+</property>]]></programlisting>
+
+            <programlisting><![CDATA[<version name="version" type="integer" insert="false">
+    <column name="version" default="0"/>
+</property>]]></programlisting>
+
+            <para>
+                <literal>sql-type</literal>  ‘®«‚ŁAƒfƒtƒHƒ‹ƒg‚ÌHibernateŒ^‚©‚çSQL‚̃f[ƒ^Œ^‚ւ̃}ƒbƒsƒ“ƒO‚ðƒI[ƒo[ƒ‰ƒCƒh‚Å‚«‚Ü‚·B
+            </para>
+            
+            
+         <programlisting><![CDATA[<property name="balance" type="float">
+    <column name="balance" sql-type="decimal(13,3)"/>
+</property>]]></programlisting>
+            
+            
+            <para>
+                <literal>check</literal>  ‘®«‚Ń`ƒFƒbƒN§–ñ‚ðŽw’è‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            </para>
+            
+            <programlisting><![CDATA[<property name="foo" type="integer">
+    <column name="foo" check="foo > 10"/>
+</property>]]></programlisting>
+
+            <programlisting><![CDATA[<class name="Foo" table="foos" check="bar < 100.0">
+    ...
+    <property name="bar" type="float"/>
+</class>]]></programlisting>
+            
+
+            <table frame="topbot" id="schemattributes-summary" revision="2">
+                <title>‚Ü‚Æ‚ß</title>
+                <tgroup cols="3">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>‘®«</entry>
+                            <entry>’l</entry>
+                            <entry>à–¾</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>length</literal></entry>
+                            <entry>”’l</entry>
+                            <entry>ƒJƒ‰ƒ€‚Ì’·‚³</entry>
+                        </row>
+                        
+                        <row>
+                            <entry><literal>precision</literal></entry>
+                            <entry>”’l</entry>
+                            <entry>ƒJƒ‰ƒ€‚ÌDECIMALŒ^‚̐¸“xiprecisionj</entry>
+                        </row>                        
+                        
+                        <row>
+                            <entry><literal>scale</literal></entry>
+                            <entry>”’l</entry>
+                            <entry>ƒJƒ‰ƒ€‚ÌDECIMALŒ^‚̃XƒP[ƒ‹iscalej</entry>
+                        </row>                        
+                        
+                        <row>
+                            <entry><literal>not-null</literal></entry>
+                            <entry><literal>true|false</literal></entry>
+                            <entry>ƒJƒ‰ƒ€‚ªnull’l‚ðŽæ‚ç‚È‚¢‚±‚Æ‚ðŽw’肵‚Ü‚·
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>unique</literal></entry>
+                            <entry><literal>true|false</literal></entry>
+                            <entry>ƒJƒ‰ƒ€‚ªƒ†ƒj[ƒN§–ñ‚ðŽ‚Â‚±‚Æ‚ðŽw’肵‚Ü‚·
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>index</literal></entry>
+                            <entry><literal>ƒCƒ“ƒfƒbƒNƒX–¼</literal> </entry>
+                            <entry>(•¡”ƒJƒ‰ƒ€‚Ì)ƒCƒ“ƒfƒbƒNƒX‚Ì–¼‘O‚ðŽw’肵‚Ü‚·
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>unique-key</literal></entry>
+                            <entry><literal>ƒ†ƒj[ƒNƒL[–¼</literal></entry>
+                            <entry>•¡”ƒJƒ‰ƒ€‚̃†ƒj[ƒN§–ñ‚Ì–¼‘O‚ðŽw’肵‚Ü‚·
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>foreign-key</literal></entry>
+                            <entry><literal>ŠO•”ƒL[–¼</literal></entry>
+                            <entry>
+                                &lt;one-to-one&gt;A&lt;many-to-one&gt;A&lt;many-to-many&gt;ƒ}ƒbƒsƒ“ƒO—v‘f‚ðŽg‚Á‚āA
+                                ŠÖ˜A‚ɑ΂µ¶¬‚³‚ꂽŠO•”ƒL[§–ñ‚Ì–¼‘O‚ðŽw’肵‚Ü‚·B
+                                <literal>SchemaExport</literal>  ‚Í <literal>inverse="true"</literal>  ‘¤‚ðl—¶‚µ‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>sql-type</literal></entry>
+                            <entry><literal>SQL‚̃Jƒ‰ƒ€Œ^</literal></entry>
+                            
+                            <entry>
+                                ƒfƒtƒHƒ‹ƒg‚̃Jƒ‰ƒ€Œ^‚ðƒI[ƒo[ƒ‰ƒCƒh‚µ‚Ü‚·( <literal>&lt;column&gt;</literal>  —v‘f‚Ì‘®«‚Ì‚Ý) 
+                            </entry>
+                       </row>
+                       
+                       <row>
+                            <entry><literal>default</literal></entry>
+                            <entry>SQLŽ®</entry>
+                            
+                            <entry>
+                                ƒJƒ‰ƒ€‚̃fƒtƒHƒ‹ƒg’l‚ðŽw’肵‚Ü‚·
+                            </entry>
+                       </row>                       
+                       
+                       <row>
+                            <entry><literal>check</literal></entry>
+                            <entry>SQLŽ®</entry>
+                            
+                            <entry>
+                                ƒJƒ‰ƒ€‚©ƒe[ƒuƒ‹‚ÉSQL‚̃`ƒFƒbƒN§–ñ‚ðì¬‚µ‚Ü‚·
+                            </entry>
+                       </row>
+                   </tbody>
+                </tgroup>
+            </table>
+            
+            <para>
+                 <literal>&lt;comment&gt;</literal>  —v‘f‚Ő¶¬‚·‚éƒXƒL[ƒ}‚ɃRƒƒ“ƒg‚ðŽw’è‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+                
+            </para>
+            
+            <programlisting><![CDATA[<class name="Customer" table="CurCust">
+    <comment>Current customers only</comment>
+    ...
+</class>]]></programlisting>
+
+            <programlisting><![CDATA[<property name="balance">
+    <column name="bal">
+        <comment>Balance in USD</comment>
+    </column>
+</property>]]></programlisting>
+            
+            <para>
+                ‚±‚ê‚É‚æ‚èA¶¬‚µ‚½DDL‚É <literal>comment on table</literal>  ‚â <literal>comment on column</literal>  •¶‚ª‘‚©‚ê‚Ü‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-3" revision="2">
+            <title>ƒc[ƒ‹‚ÌŽÀs</title>
+
+            <para>
+                 <literal>SchemaExport</literal>  ‚Í•W€o—͂ɑ΂µ‚ÄDDLƒXƒNƒŠƒvƒg‚ð‘‚«o‚µADDL•¶‚ðŽÀs‚µ‚½‚è‚à‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                <literal>java -cp </literal>  <emphasis>hibernate_classpaths</emphasis> 
+                <literal>org.hibernate.tool.hbm2ddl.SchemaExport</literal>   <emphasis>options mapping_files</emphasis> 
+            </para>
+
+            <table frame="topbot">
+                <title> <literal>SchemaExport</literal>  Command Line Options
+                
+                 <literal>SchemaExport</literal>  ‚̃Rƒ}ƒ“ƒhƒ‰ƒCƒ“ƒIƒvƒVƒ‡ƒ“
+                </title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>ƒIƒvƒVƒ‡ƒ“</entry>
+                            <entry>à–¾</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry> <literal>--quiet</literal> </entry>
+                            <entry>ƒXƒNƒŠƒvƒg‚ð•W€o—͂ɏo—Í‚µ‚Ü‚¹‚ñ</entry>
+                        </row>
+                        <row>
+                            <entry> <literal>--drop</literal> </entry>
+                            <entry>ƒe[ƒuƒ‹‚̍폜‚¾‚¯‚ðs‚¢‚Ü‚·</entry>
+                        </row>
+                        
+                        <row>
+                            <entry> <literal>--create</literal> </entry>
+                            <entry>ƒe[ƒuƒ‹‚̐¶¬‚Ì‚Ý‚ðs‚¢‚Ü‚·B
+                            </entry>
+                        </row>                        
+                        
+                        <row>
+                            <entry> <literal>--text</literal> </entry>
+                            <entry>ƒf[ƒ^ƒx[ƒX‚ɃGƒNƒXƒ|[ƒg‚µ‚Ü‚¹‚ñ</entry>
+                        </row>
+                        <row>
+                            <entry> <literal>--output=my_schema.ddl</literal> </entry>
+                            <entry> DDLƒXƒNƒŠƒvƒg‚ðƒtƒ@ƒCƒ‹‚ɏo—Í‚µ‚Ü‚·</entry>
+                        </row>
+                        
+                        <row>
+                            <entry> <literal>--naming=eg.MyNamingStrategy</literal> </entry>
+                            <entry> <literal>NamingStrategy</literal> ‚ð‘I‘ð‚µ‚Ü‚·
+                            </entry>
+                        </row>                        
+                        
+                        <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal> </entry>
+                            <entry>XMLƒtƒ@ƒCƒ‹‚©‚çHibernate‚Ì’è‹`î•ñ‚ð“ǂݍž‚Ý‚Ü‚·</entry>
+                        </row>
+                        <row>
+                            <entry> <literal>--properties=hibernate.properties</literal> </entry>
+                            <entry>ƒtƒ@ƒCƒ‹‚©‚çƒf[ƒ^ƒx[ƒXƒvƒƒpƒeƒB‚ð“ǂݍž‚Ý‚Ü‚·</entry>
+                        </row>
+                        <row>
+                            <entry> <literal>--format</literal> </entry>
+                            <entry>ƒXƒNƒŠƒvƒg“à‚ɐ¶¬‚·‚éSQL‚ð“Ç‚Ý‚â‚·‚¢‚悤‚ɃtƒH[ƒ}ƒbƒg‚µ‚Ü‚·</entry>
+                        </row>
+                        <row>
+                            <entry> <literal>--delimiter=x</literal> </entry>
+                            <entry>ƒXƒNƒŠƒvƒg‚̍s‹æØ‚蕶Žš‚ðÝ’肵‚Ü‚·</entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É <literal>SchemaExport</literal>  ‚ð‘g‚ݍž‚Þ‚±‚Æ‚à‚Å‚«‚Ü‚·F
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaExport(cfg).create(false, true);]]></programlisting>
+
+        </sect2>
+
+
+        <sect2 id="toolsetguide-s1-4">
+            <title>ƒvƒƒpƒeƒB</title>
+
+            <para>
+                ŽŸ‚̂悤‚ɁAƒf[ƒ^ƒx[ƒX‚̃vƒƒpƒeƒB‚ðŽw’è‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para><literal>-D</literal>  <emphasis>&lt;property&gt;</emphasis>  ‚ðŽg‚Á‚āAƒVƒXƒeƒ€ƒvƒƒpƒeƒB‚Æ‚µ‚Ä
+                    </para>
+                </listitem>
+                <listitem>
+                    <para><literal>hibernate.properties</literal>  ƒtƒ@ƒCƒ‹“à‚Å
+                    </para>
+                </listitem>
+                <listitem>
+                    <para> <literal>--properties</literal> ‚ðŽg‚Á‚ÄŽw’肵‚½ƒvƒƒpƒeƒBƒtƒ@ƒCƒ‹“à‚Å
+
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                •K—v‚ȃvƒƒpƒeƒB‚͈ȉº‚Ì‚à‚Ì‚Å‚·F
+            </para>
+
+            <table frame="topbot">
+                <title>SchemaExportƒRƒlƒNƒVƒ‡ƒ“ƒvƒƒpƒeƒB</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>ƒvƒƒpƒeƒB–¼
+                            </entry>
+                            <entry>à–¾
+                            </entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                    <row>
+                        <entry> <literal>hibernate.connection.driver_class</literal> </entry>
+                        <entry>jdbc‚̃hƒ‰ƒCƒo[ƒNƒ‰ƒX
+                        </entry>
+                    </row>
+                    <row>
+                        <entry> <literal>hibernate.connection.url</literal> </entry>
+                        <entry>jdbc‚Ìurl
+                        </entry>
+                    </row>
+                    <row>
+                        <entry> <literal>hibernate.connection.username</literal> </entry>
+                        <entry>ƒf[ƒ^ƒx[ƒX‚̃†[ƒU
+                        </entry>
+                    </row>
+                    <row>
+                        <entry> <literal>hibernate.connection.password</literal> </entry>
+                        <entry>ƒ†[ƒUƒpƒXƒ[ƒh
+                        </entry>
+                    </row>
+                    <row>
+                        <entry> <literal>hibernate.dialect</literal> </entry>
+                        <entry>ƒf[ƒ^ƒx[ƒX•ûŒ¾
+                        </entry>
+                    </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-5">
+            <title>Ant‚ðŽg—p‚·‚é</title>
+
+            <para>
+                Ant‚̃rƒ‹ƒhƒXƒNƒŠƒvƒg‚©‚ç <literal>SchemaExport</literal>  ‚ðŒÄ‚яo‚·‚±‚Æ‚ª‚Å‚«‚Ü‚·B:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemaexport">
+    <taskdef name="schemaexport"
+        classname="org.hibernate.tool.hbm2ddl.SchemaExportTask"
+        classpathref="class.path"/>
+    
+    <schemaexport
+        properties="hibernate.properties"
+        quiet="no"
+        text="no"
+        drop="no"
+        delimiter=";"
+        output="schema-export.sql">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaexport>
+</target>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-6" revision="2">
+            <title>ƒCƒ“ƒNƒŠƒƒ“ƒ^ƒ‹‚ȃXƒL[ƒ}XV
+            </title>
+
+            <para>
+                 <literal>SchemaUpdate</literal>  ƒc[ƒ‹‚ÍŠù‘¶‚̃XƒL[ƒ}‚ðƒCƒ“ƒNƒŠƒƒ“ƒ^ƒ‹‚ɍXV‚µ‚Ü‚·B
+                <literal>SchemaUpdate</literal>  ‚ÍJDBC‚̃ƒ^ƒf[ƒ^API‚É‹­‚­ˆË‘¶‚µ‚Ü‚·B
+                ‚»‚Ì‚½‚߁A‚·‚ׂĂÌJDBCƒhƒ‰ƒCƒo‚Å‚¤‚Ü‚­‚¢‚­‚Æ‚ÍŒÀ‚ç‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <para>
+                <literal>java -cp </literal>  <emphasis>hibernate_classpaths</emphasis> 
+                <literal>org.hibernate.tool.hbm2ddl.SchemaUpdate</literal>   <emphasis>options mapping_files</emphasis> 
+            </para>
+
+            <table frame="topbot">
+                <title> <literal>SchemaUpdate</literal>  ‚̃Rƒ}ƒ“ƒhƒ‰ƒCƒ“¥ƒIƒvƒVƒ‡ƒ“</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>ƒIƒvƒVƒ‡ƒ“</entry>
+                            <entry>à–¾</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry> <literal>--quiet</literal> </entry>
+                            <entry>•W€o—͂ɃXƒNƒŠƒvƒg‚ðo—Í‚µ‚Ü‚¹‚ñ</entry>
+                        </row>
+                        
+                        <row>
+                            <entry> <literal>--text</literal> </entry>
+                            <entry>ƒf[ƒ^ƒx[ƒX‚ɃXƒNƒŠƒvƒg‚ðƒGƒNƒXƒ|[ƒg‚µ‚Ü‚¹‚ñ
+                            </entry>
+                        </row>
+                        <row>
+                            <entry> <literal>--naming=eg.MyNamingStrategy</literal> </entry>
+                            <entry><literal>NamingStrategy</literal> ‚ð‘I‘ð‚µ‚Ü‚·B
+                            </entry>
+                        </row>                        
+                        
+                        <row>
+                            <entry> <literal>--properties=hibernate.properties</literal> </entry>
+                            <entry>ƒtƒ@ƒCƒ‹‚©‚çƒf[ƒ^ƒx[ƒXƒvƒƒpƒeƒB‚ð“ǂݍž‚Ý‚Ü‚·
+                            </entry>
+                        </row>
+                        
+                        <row>
+                            <entry> <literal>--config=hibernate.cfg.xml</literal> </entry>
+                            <entry><literal>.cfg.xml</literal> ƒtƒ@ƒCƒ‹‚ðŽw’肵‚Ü‚·
+                            </entry>
+                        </row>                        
+                        
+                     </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É <literal>SchemaUpdate</literal>  ‚ð‘g‚ݍž‚Þ‚±‚Æ‚ª‚Å‚«‚Ü‚·BF
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaUpdate(cfg).execute(false);]]></programlisting>
+
+        </sect2>
+        
+
+        <sect2 id="toolsetguide-s1-7">
+            <title>ƒCƒ“ƒNƒŠƒƒ“ƒ^ƒ‹‚ȃXƒL[ƒ}XV‚ɑ΂·‚éAnt‚ÌŽg—p</title>
+
+            <para>
+                AntƒXƒNƒŠƒvƒg‚©‚ç <literal>SchemaUpdate</literal>  ‚ðŒÄ‚яo‚·‚±‚Æ‚ª‚Å‚«‚Ü‚·F
+            </para>
+
+            <programlisting><![CDATA[<target name="schemaupdate">
+    <taskdef name="schemaupdate"
+        classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask"
+        classpathref="class.path"/>
+    
+    <schemaupdate
+        properties="hibernate.properties"
+        quiet="no">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaupdate>
+</target>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-8" revision="1">
+            <title>Schema validation</title>
+
+            <para>
+                 <literal>SchemaValidator</literal> ƒc[ƒ‹‚́AŠù‘¶‚̃f[ƒ^ƒx[ƒXƒXƒL[ƒ}‚ƍ쐬‚µ‚½ƒ}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚ª"ˆê’v‚·‚é"‚±‚Æ‚ðŒŸØ‚µ‚Ü‚·B <literal>SchemaValidator</literal> ‚ÍJDBC‚̃ƒ^ƒf[ƒ^API‚É‹­‚­ˆË‘¶‚·‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B‚»‚Ì‚½‚߁A‚·‚ׂĂÌJDBCƒhƒ‰ƒCƒo[‚ō쓮‚·‚é‚à‚Ì‚Å‚Í‚ ‚è‚Ü‚¹‚ñB‚±‚̃c[ƒ‹‚̓eƒXƒgŽž‚É”ñí‚É—L—p‚Å‚·B
+            </para>
+
+            <para>
+                <literal>java -cp </literal>  <emphasis>hibernate_classpaths</emphasis> 
+                <literal>org.hibernate.tool.hbm2ddl.SchemaValidator</literal>   <emphasis>options mapping_files</emphasis> 
+            </para>
+
+            <table frame="topbot">
+                <title> <literal>SchemaValidator</literal> ‚̃Rƒ}ƒ“ƒhƒ‰ƒCƒ“EƒIƒvƒVƒ‡ƒ“
+                </title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>ƒIƒvƒVƒ‡ƒ“</entry>
+                            <entry>à–¾</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry> <literal>--naming=eg.MyNamingStrategy</literal> </entry>
+                            <entry><literal>NamingStrategy</literal> ‚ð‘I‘ð‚µ‚Ü‚·
+                            </entry>
+                        </row>
+                        <row>
+                            <entry> <literal>--properties=hibernate.properties</literal> </entry>
+                            <entry>ƒtƒ@ƒCƒ‹‚©‚çƒf[ƒ^ƒx[ƒX‚̃vƒƒpƒeƒB‚ð“ǂݍž‚Ý‚Ü‚·
+                            </entry>
+                        </row>
+                        <row>
+                            <entry> <literal>--config=hibernate.cfg.xml</literal> </entry>
+                            <entry><literal>.cfg.xml</literal> ƒtƒ@ƒCƒ‹‚ðŽw’肵‚Ü‚·
+                            </entry>
+                        </row>
+                     </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                 <literal>SchemaValidator</literal> ‚ðƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‘g‚ݍž‚Þ‚±‚Æ‚ªo—ˆ‚Ü‚·:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaValidator(cfg).validate();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-9">
+            <title>ƒXƒL[ƒ}‚̃oƒŠƒf[ƒVƒ‡ƒ“‚ÉAnt‚ðŽg—p‚µ‚Ü‚·</title>
+
+            <para>
+                AntƒXƒNƒŠƒvƒg‚©‚ç <literal>SchemaValidator</literal> ‚ðŒÄ‚яo‚¹‚Ü‚·:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemavalidate">
+    <taskdef name="schemavalidator"
+        classname="org.hibernate.tool.hbm2ddl.SchemaValidatorTask"
+        classpathref="class.path"/>
+    
+    <schemavalidator
+        properties="hibernate.properties">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaupdate>
+</target>]]></programlisting>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/transactions.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/transactions.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/transactions.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1276 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="transactions" revision="2">
+    <title>ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Æ•Às«</title>
+
+    <para>
+        Hibernate‚Æ“¯ŽžŽÀs§Œä‚ɂ‚¢‚čłàd—v‚È“_‚́A—eˆÕ‚É—‰ð‚Å‚«‚邱‚Æ‚Å‚·B
+        Hibernate‚͐V‚½‚ȃƒbƒN‚̐U‚é•‘‚¢‚ð’ljÁ‚µ‚Ä‚¨‚炸A’¼ÚJDBCƒRƒlƒNƒVƒ‡ƒ“‚ÆJTAƒŠƒ\[ƒX‚ðŽg—p‚µ‚Ü‚·B
+        JDBCAANSIA‚¨‚æ‚уf[ƒ^ƒx[ƒXŠÇ—ƒVƒXƒeƒ€iDBMSj‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“•ª—£‚ÌŽd—l‚ð
+        ­‚µŽžŠÔ‚ð‚©‚¯‚ĕ׋­‚·‚邱‚Æ‚ð‹­‚­„§‚µ‚Ü‚·B
+    </para>
+
+    <para>
+        Hibernate‚̓ƒ‚ƒŠ“à‚̃IƒuƒWƒFƒNƒg‚ðƒƒbƒN‚µ‚Ü‚¹‚ñB
+        ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚́Aƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Ì•ª—£ƒŒƒxƒ‹‚Å
+        ’è‹`‚µ‚½U‚é•‘‚¢‚ðŠú‘Ò‚Å‚«‚Ü‚·B
+        ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ƒXƒR[ƒv‚̃LƒƒƒbƒVƒ…‚Å‚à‚ ‚é <literal>Session</literal> ‚Ì‚¨‰A‚ŁA
+        Ž¯•ÊŽq‚âƒNƒGƒŠ‚É‚æ‚茟õ‚µ‚½ƒGƒ“ƒeƒBƒeƒB‚̓Šƒs[ƒ^ƒuƒ‹ƒŠ[ƒh‚É‚È‚è‚Ü‚·
+        iƒXƒJƒ‰[’l‚ð•Ô‚·‚悤‚ȃŒƒ|[ƒgƒNƒGƒŠ‚͈Ⴂ‚Ü‚·jB
+    </para>
+
+    <para>
+        ƒo[ƒWƒ‡ƒjƒ“ƒO‚É‚æ‚鎩“®“I‚ÈŠyŠÏ“I“¯ŽžŽÀs§Œä‚ɉÁ‚¦‚āA
+        <literal>SELECT FOR UPDATE</literal> •¶‚ðŽg—p‚µ‚āA
+        s‚ð”ߊϓIƒƒbƒN‚·‚邽‚߂́iƒ}ƒCƒi[‚ȁjAPI‚à’ñ‹Ÿ‚µ‚Ü‚·B
+        ŠyŠÏ“I“¯ŽžŽÀs§Œä‚Æ‚±‚ÌAPI‚ɂ‚¢‚ẮA‚±‚̏͂̌ã‚Ì‚Ù‚¤‚Å‹c˜_‚µ‚Ü‚·B
+    </para>
+
+    <para>
+        ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚â’·‚¢‘ΘbiconversationAƒƒ“ƒOƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“j‚¾‚¯‚Å‚È‚­A
+        <literal>Configuration</literal>A<literal>SessionFactory</literal>A‚¨‚æ‚Ñ
+        <literal>Session</literal>
+        ‚Æ‚¢‚¤—±“x‚ÅHibernate‚ªs‚¤“¯ŽžŽÀs§Œä‚Ì‹c˜_‚ðŽn‚ß‚Ü‚·B
+    </para>
+
+    <sect1 id="transactions-basics" revision="1">
+        <title>sessionƒXƒR[ƒv‚ÆtransactionƒXƒR[ƒv</title>
+
+        <para>
+            <literal>SessionFactory</literal> ‚͐¶¬‚·‚邱‚Æ‚ª‚‰¿‚ŁA
+            ƒXƒŒƒbƒhƒZ[ƒt‚ȃIƒuƒWƒFƒNƒg‚Å‚·B
+            ‚æ‚Á‚āAƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚Ì‚·‚ׂẴXƒŒƒbƒh‚Å‹¤—L‚·‚ׂ«‚Å‚·B
+            ’ʏíAƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚Ì‹N“®Žž‚ɁA
+            <literal>Configuration</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚©‚ç‚P“x‚¾‚¯¶¬‚µ‚Ü‚·B
+        </para>
+
+        <para>
+            <literal>Session</literal> ‚͍‚‰¿‚Å‚Í‚È‚­AƒXƒŒƒbƒhƒZ[ƒt‚ȃIƒuƒWƒFƒNƒg‚Å‚à‚ ‚è‚Ü‚¹‚ñB
+            ‚æ‚Á‚āA‚P‚‚̗v‹‚â‚P‚‚̑ΘbA‚P‚‚̍ì‹Æ’PˆÊiunit of workj‚ɑ΂µ‚Ä‚P“x‚¾‚¯Žg‚¢A
+            ‚»‚ÌŒã‚ÅŽÌ‚Ä‚é‚ׂ«‚Å‚·B
+            <literal>Session</literal> ‚Í•K—v‚É‚È‚é‚܂ŁA
+            JDBC <literal>Connection</literal>i‚à‚µ‚­‚Í <literal>DataSource</literal>j‚ðŠl“¾‚µ‚Ü‚¹‚ñB
+            ‚䂦‚ɁAŽÀÛ‚ÉŽg—p‚·‚é‚Æ‚«‚܂ŃŠƒ\[ƒX‚ðÁ”‚Ü‚¹‚ñB
+        </para>
+
+        <para>
+            ‚±‚Ìó‹µ‚ðŠ®—¹‚³‚¹‚邽‚߂ɁA ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ɂ‚¢‚Ä‚àl‚¦‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            ƒf[ƒ^ƒx[ƒX“à‚̃ƒbƒN‚Ì‹£‡‚ð­‚È‚­‚·‚邽‚߂ɁA
+            ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚͉”\‚ÈŒÀ‚è’Z‚­‚·‚é‚ׂ«‚Å‚·B
+            ’·‚¢ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̍‚‚¢•À—ñŽÀs«‚ð‘jŠQ‚µ‚Ü‚·B
+            ‚䂦‚ɁAƒ†[ƒU[‚ªl‚¦‚Ä‚¢‚éŠÔiì‹Æ’PˆÊ‚ªŠ®—¹‚·‚é‚܂Łjƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ð
+            ŠJ‚¢‚½‚Ü‚Ü‚É‚·‚é‚̂́A‚½‚¢‚Ä‚¢‚̏ꍇ‚æ‚¢ÝŒv‚Æ‚Í‚¢‚¦‚Ü‚¹‚ñB
+        </para>
+
+        <para>
+            ì‹Æ’PˆÊ‚Æ‚¢‚¤ƒXƒR[ƒv‚Ƃ͉½‚Å‚µ‚傤‚©H
+            ‚P‚‚ÌHibernate <literal>Session</literal> ‚́A
+            ‚¢‚­‚‚©‚̃f[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ð‚Ü‚½‚ª‚邱‚Æ‚ª‚Å‚«‚é‚Å‚µ‚傤‚©H
+            ‚Ü‚½‚́AƒXƒR[ƒv‚ƈê‘Έê‚ÌŠÖŒW‚Å‚µ‚傤‚©H
+            ‚¢‚ <literal>Session</literal> ‚ðŠJ‚«A•Â‚¶‚é‚ׂ«‚Å‚µ‚傤‚©H
+            ‚»‚µ‚āAƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚ð‚ǂ̂悤‚É•ª‚¯‚é‚Ì‚Å‚µ‚傤‚©H
+        </para>
+
+        <sect2 id="transactions-basics-uow" revision="1">
+            <title>ì‹Æ’PˆÊiUnit of workj</title>
+
+            <para>
+                ‚P‚–ڂ́A<emphasis>session-per-operation</emphasis> ƒAƒ“ƒ`ƒpƒ^[ƒ“‚ðŽg‚Á‚Ä‚Í‚¢‚¯‚Ü‚¹‚ñB
+                ‚·‚È‚í‚¿A‚P‚‚̃XƒŒƒbƒh‚Ì’†‚ŁA’Pƒ‚ȃf[ƒ^ƒx[ƒXŒÄ‚яo‚µ‚Ì‚½‚Ñ‚É
+                <literal>Session</literal> ‚ðŠJ‚¢‚āA•Â‚¶‚Ä‚Í‚¢‚¯‚Ü‚¹‚ñI
+                ‚à‚¿‚ë‚ñAƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ɂ‚¢‚Ä‚à“¯—l‚Å‚·B
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“’†‚̃f[ƒ^ƒx[ƒXŒÄ‚яo‚µ‚́A
+                Œv‰æ‚³‚ꂽƒV[ƒPƒ“ƒXiplanned sequencej‚ðŽg‚¢A
+                ƒAƒgƒ~ƒbƒN‚ȍì‹Æ’PˆÊ‚É•ª—Þ‚³‚ê‚Ü‚·B
+                i‚P‚‚ÌSQL•¶‚²‚ƂɃRƒ~ƒbƒg‚·‚鎩“®ƒRƒ~ƒbƒg‚ªA
+                Žg‚í‚ê‚È‚¢‚Æ‚¢‚¤ˆÓ–¡‚Å‚à‚ ‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                Ž©“®ƒRƒ~ƒbƒg‚́ASQLƒRƒ“ƒ\[ƒ‹‚ŃAƒhƒzƒbƒN‚ȍì‹Æ‚ð‚·‚éÛ‚ÉŽg‚¤‚à‚Ì‚Å‚·B
+                Hibernate‚Í’¼‚¿‚ÉŽ©“®ƒRƒ~ƒbƒgƒ‚[ƒh‚𖳌ø‚É‚µ‚Ü‚·B
+                ‚à‚µ‚­‚́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo[‚ª–³Œø‰»‚·‚邱‚Æ‚ðŠú‘Ò‚µ‚Ü‚·Bj
+                ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̓IƒvƒVƒ‡ƒ“‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+                ƒf[ƒ^ƒx[ƒX‚Æ‚Ì‚·‚ׂĂ̒ʐM‚́Aƒf[ƒ^‚̓ǂݍž‚Ý‚Å‚ ‚Á‚Ä‚àA‘‚«ž‚Ý‚Å‚ ‚Á‚Ä‚àA
+                ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Ì’†‚ōs‚í‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                à–¾‚·‚é‚ƁAƒf[ƒ^“ǂݍž‚݂ɑ΂µ‚āAŽ©“®ƒRƒ~ƒbƒg‚Í”ð‚¯‚é‚ׂ«‚Å‚·B
+                ‚È‚º‚È‚çA‘½”‚̏¬‚³‚ȃgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚́A–¾Šm‚É’è‹`‚³‚ꂽ‚P‚‚̍ì‹Æ’PˆÊ‚Æ”ä‚ׂāA
+                ƒpƒtƒH[ƒ}ƒ“ƒX‚ª‚æ‚­‚Ȃ邱‚Æ‚Í‚ ‚è‚Ü‚¹‚ñB
+                ŒãŽÒ‚͕ێ琫‚âŠg’£«‚à‚æ‚è‚·‚®‚ê‚Ä‚¢‚Ü‚·B
+            </para>
+
+            <para>
+                ƒ}ƒ‹ƒ`ƒ†[ƒU[‚̃Nƒ‰ƒCƒAƒ“ƒg^ƒT[ƒo[ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚Ì’†‚ŁA
+                Å‚à‚æ‚­Žg‚í‚ê‚éƒpƒ^[ƒ“‚́A<emphasis>session-per-request</emphasis> ‚Å‚·B
+                ‚±‚̃‚ƒfƒ‹‚Ì’†‚ł́A
+                ƒNƒ‰ƒCƒAƒ“ƒg‚©‚çiHibernate‰i‘±‰»‘w‚ª“®ì‚·‚éjƒT[ƒo[‚ÖƒŠƒNƒGƒXƒg‚ª‘—‚ç‚êA
+                V‚µ‚¢Hibernate <literal>Session</literal> ‚ªŠJ‚©‚ê‚Ü‚·B
+                ‚»‚µ‚āA‚±‚̍ì‹Æ’PˆÊ‚Ì’†‚Å‚·‚ׂẴf[ƒ^ƒx[ƒXˆ—‚ªŽÀs‚³‚ê‚Ü‚·B
+                ì‹Æ‚ªŠ®—¹‚µ‚½i‚»‚µ‚āAƒNƒ‰ƒCƒAƒ“ƒg‚ւ̃ŒƒXƒ|ƒ“ƒX‚ª€”õ‚Å‚«‚½jŽž“_‚ŁA
+                session ‚ðƒtƒ‰ƒbƒVƒ…‚µA•Â‚¶‚Ü‚·B
+                ƒNƒ‰ƒCƒAƒ“ƒg‚Ì—v‹‚ðˆ—‚·‚邽‚߂ɁA‚P‚‚̃f[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðŽg—p‚·‚é‚Å‚µ‚傤B
+                <literal>Session</literal> ‚ðŠJ‚«A•Â‚¶‚éÛ‚ɁA
+                ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðŠJŽn‚µAƒRƒ~ƒbƒg‚µ‚Ü‚·B
+                “ñ‚‚̊֌W‚͈ê‘Έê‚Å‚·B
+                ‚±‚̃‚ƒfƒ‹‚Í‘½‚­‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚ÉŠ®‘S‚É“K‡‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                ˆÈ~‚ÌŽÀ‘•‚Ƀ`ƒƒƒŒƒ“ƒW‚µ‚Ä‚­‚¾‚³‚¢B
+                <literal>Session</literal> ‚ðŽ‚¿Aƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚𐳊m‚ÉŠJŽn‚µAI‚í‚点‚邾‚¯‚Å‚È‚­A
+                ƒf[ƒ^ƒAƒNƒZƒX‘€ì‚à“¾‚â‚·‚­‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+                ƒŠƒNƒGƒXƒg‚ªƒT[ƒo[‚Ƀqƒbƒg‚µ‚½Û‚ƁAƒŒƒXƒ|ƒ“ƒX‚𑗐M‚·‚é‘O‚ɁAŽÀs‚³‚ê‚éinterceptor
+                i—Ⴆ‚΁A<literal>ServletFilter</literal>j‚ðŽg‚Á‚āAì‹Æ’PˆÊ‚Ì‹«ŠE‚ðŽÀ‘•‚·‚é‚Ì‚ª—‘z“I‚Å‚·B
+                <literal>ThreadLocal</literal> •Ï”‚ðŽg‚Á‚āA
+                ƒŠƒNƒGƒXƒg‚ðˆ—‚·‚éƒXƒŒƒbƒh‚É <literal>Session</literal> ‚ðŒ‹‚Ñ‚Â‚¯‚邱‚Ƃ𐄏§‚µ‚Ü‚·B
+                ‚±‚ê‚É‚æ‚èAƒXƒŒƒbƒh“à‚ÅŽÀs‚³‚ê‚é‚·‚ׂẴR[ƒh‚ŁA
+                istatic•Ï”‚ɃAƒNƒZƒX‚·‚é‚悤‚ɁjŠÈ’P‚É <literal>Session</literal> ‚ɃAƒNƒZƒX‚Å‚«‚é‚悤‚É‚È‚è‚Ü‚·B
+                ‘I‘ð‚µ‚½ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚Ì‹@\ŽŸ‘æ‚ŁA<literal>ThreadLocal</literal>
+                •Ï”‚Ì’†‚Ƀgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ƒRƒ“ƒeƒLƒXƒg‚ð•ÛŽ‚·‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                ‚±‚ÌŽÀ‘•ƒpƒ^[ƒ“‚́A<emphasis>ThreadLocal Session</emphasis> ‚¨‚æ‚Ñ
+                <emphasis>Open Session in View</emphasis> ‚Æ‚¢‚¤–¼‘O‚Å’m‚ç‚ê‚Ä‚¢‚Ü‚·B
+                –{ƒhƒLƒ…ƒƒ“ƒg‚Őæ‚ÉŒ©‚¹‚½ <literal>HibernateUtil</literal> ƒwƒ‹ƒp[ƒNƒ‰ƒX‚ðŠg’£‚·‚邱‚ƂŁA
+                ‚±‚̃pƒ^[ƒ“‚ð—eˆÕ‚ÉŽÀ‘•‚Å‚«‚Ü‚·B
+                ‚à‚¿‚ë‚ñAinterceptor ‚ðŽÀ‘•‚·‚é•û–@‚ðŒ©‚Â‚¯AŠÂ‹«‚ðƒZƒbƒgƒAƒbƒv‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+                Hibernate‚ÌWebƒTƒCƒg‚É‚ ‚étips‚Æ—á‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+             </para>
+
+            <para>
+                ˆÈ~‚ÌŽÀ‘•‚Ƀ`ƒƒƒŒƒ“ƒW‚µ‚Ä‚­‚¾‚³‚¢B
+                Hibernate‚Í’Pƒ‚È‚±‚̃pƒ^[ƒ“‚Ì‚½‚߂ɁA—\‚ß‘g‚ݍž‚܂ꂽ
+                ucurrent sessionv‚ÌŠÇ—‚ð’ñ‹Ÿ‚µ‚Ü‚·B
+                ƒT[ƒo[ƒŠƒNƒGƒXƒg‚ðˆ—‚·‚éÛ‚̓gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðŠJŽn‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                ‚»‚µ‚āAƒŒƒXƒ|ƒ“ƒX‚ðƒNƒ‰ƒCƒAƒ“ƒg‚É‘—M‚·‚é‘O‚Ƀgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðI‚í‚点‚Ü‚·B
+                D‚«‚È•û–@‚ÅŽÀŒ»‚Å‚«‚Ü‚·Bˆê”Ê“I‚È‰ðŒˆô‚Í <literal>ServletFilter</literal> ‚â
+                ƒT[ƒrƒXƒƒ\ƒbƒh‚ðƒ|ƒCƒ“ƒgƒJƒbƒg‚µ‚ÄAOPƒCƒ“ƒ^[ƒZƒvƒ^[A
+                proxy/interception ƒRƒ“ƒeƒi‚Å‚·B
+                EJBƒRƒ“ƒeƒi‚ÍEJBƒZƒbƒVƒ‡ƒ“ƒr[ƒ“‚ðƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚Æ‚µ‚Ä
+                ƒAƒXƒyƒNƒg‚ðƒNƒƒXƒJƒbƒg‚·‚éŽÀ‘•‚Ì•W€“I‚È•û–@‚Å‚·iCMT‚É‚æ‚ééŒ¾“IjB
+                ƒvƒƒOƒ‰ƒ€‚É‚æ‚éƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚ðŽg‚¤‚ÆŒˆ‚ß‚½ê‡A
+                ŠÈ’P‚ÉŽg‚¤‚½‚߁AŒÝŠ·«‚Ì‚ ‚éƒR[ƒh‚É‚·‚邽‚߂ɁA
+                ‚±‚̏͂̌ã‚Ì‚Ù‚¤‚É‚ ‚éHibernate <literal>Transaction</literal> API‚Ì‚Ù‚¤‚ª‚æ‚¢‚Å‚·B
+            </para>
+
+            <para>
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̃R[ƒh‚́A•K—v‚È‚Æ‚«‚É‚Ç‚±‚Å‚àA‰½‰ñ‚Å‚àA
+                ’P‚É <literal>sessionFactory.getCurrentSession()</literal> ‚ðŒÄ‚яo‚·‚¾‚¯‚Å
+                uŒ»Ý‚̃ZƒbƒVƒ‡ƒ“v‚ɃAƒNƒZƒX‚Å‚«‚Ü‚·B
+                Œ»Ý‚̃f[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Ö‚Ì <literal>ƒZƒbƒVƒ‡ƒ“</literal> ‚ðí‚Ɏ擾‚µ‚Ü‚·B
+                ƒŠƒ\[ƒXEƒ[ƒJƒ‹‚Ȋ‹«A‚à‚µ‚­‚ÍJTAŠÂ‹«‚ð\¬‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ
+                i<xref linkend="architecture-current-session"/> ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢jB
+            </para>
+
+            <para>
+                ‚Æ‚«‚Ç‚«Auƒrƒ…[‚ð•`‰æ‚·‚év‚Ü‚Å <literal>ƒZƒbƒVƒ‡ƒ“</literal>
+                ‚ƃf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̃XƒR[ƒv‚ðŠg’£‚·‚é‚Æ•Ö—˜‚È‚±‚Æ‚ª‚ ‚è‚Ü‚·B
+                ‚±‚ê‚́A—v‹‚̏ˆ—‚Æ•`‰æ‚̃tƒF[ƒY‚𕪂¯‚Ä‚¢‚é
+                ƒT[ƒuƒŒƒbƒgƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚¨‚¢‚Ä“Á‚ɖ𗧂¿‚Ü‚·B
+                “ÆŽ©‚̃Cƒ“ƒ^[ƒZƒvƒ^‚ðŽÀ‘•‚·‚ê‚΁A
+                ƒrƒ…[‚ð•`‰æ‚·‚é‚܂Ńf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðŠg’£‚·‚é‚Ì‚ÍŠÈ’P‚Å‚·B
+                ‚µ‚©‚µAƒRƒ“ƒeƒiŠÇ—ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÌEJB‚É—Š‚éê‡‚́AŠÈ’P‚É‚Í‚Å‚«‚Ü‚¹‚ñB
+                ‚È‚º‚È‚çAƒrƒ…[‚Ì•`‰æ‚ðŠJŽn‚·‚é‘O‚ɁAEJB‚̃ƒ\ƒbƒh‚ªƒŠƒ^[ƒ“‚µ‚½Û‚ɁA
+                ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ªŠ®—¹‚·‚邽‚ß‚Å‚·B
+                ‚±‚Ì <emphasis>Open Session in View</emphasis> ƒpƒ^[ƒ“‚ÉŠÖ˜A‚·‚éƒqƒ“ƒg‚Æ—á‚ɂ‚¢‚ẮA
+                Hibernate‚ÌWebƒTƒCƒg‚âƒtƒH[ƒ‰ƒ€‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+             </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-apptx" revision="1">
+            <title>’·‚¢‘Θb</title>
+
+            <para>
+                session-per-requestƒpƒ^[ƒ“‚́Aì‹Æ’PˆÊ‚ðÝŒv‚·‚éÛ‚ɖ𗧂l‚¦‚Æ‚¢‚¤‚¾‚¯‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+                ‘½‚­‚̃rƒWƒlƒXƒvƒƒZƒX‚́Aƒ†[ƒU[‚Ƃ̈ê˜A‚Ì‘ŠŒÝì—p‘S‘Ì‚ð—v‹‚µ‚Ü‚·B
+                ‚»‚Ì‘ŠŒÝì—p‚ɂ́Aƒf[ƒ^ƒx[ƒXƒAƒNƒZƒX‚ªŠÜ‚Ü‚ê‚Ü‚·B
+                
+                Web‚ƃGƒ“ƒ^[ƒvƒ‰ƒCƒYƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ł́Aƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ª
+                ƒ†[ƒU‚Æ‚Ì‘ŠŒÝì—p‚É‚Ü‚Å“n‚邱‚Æ‚Í‹–‚³‚ê‚Ü‚¹‚ñB
+                
+                ŽŸ‚Ì—á‚ð‚æ‚­l‚¦‚Ä‚Ý‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        ƒ_ƒCƒAƒƒO‚̍ŏ‰‚̉æ–Ê‚ªŠJ‚«AŒÂX‚Ì <literal>Session</literal>
+                        ‚ƃf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Ì’†‚э[ƒh‚³‚ꂽƒf[ƒ^‚ðƒ†[ƒU[‚ÉŒ©‚¹‚Ü‚·B
+                        ƒ†[ƒU[‚̓IƒuƒWƒFƒNƒg‚ðŽ©—R‚ɏC³‚Å‚«‚Ü‚·B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        5•ªŒã‚Ƀ†[ƒU[‚́uSavev‚ðƒNƒŠƒbƒN‚µAC³‚ª‰i‘±‰»‚³‚ê‚é‚Ì‚ðŠú‘Ò‚µ‚Ü‚·B
+                        ‚Ü‚½A‚±‚̏î•ñ‚ð•ÒW‚µ‚½‚Ì‚ÍŽ©•ª‚Pl‚¾‚¯‚ŁA
+                        C³‚̃Rƒ“ƒtƒŠƒNƒg‚Í”­¶‚µ‚È‚¢‚ÆŠú‘Ò‚µ‚Ü‚·B
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                ‚±‚̍ì‹Æ’PˆÊ‚ðiƒ†[ƒU[‚ÌŽ‹“_‚Łj’·Šú‚Ì <emphasis>‘Θb</emphasis>
+                i‚à‚µ‚­‚́A<emphasis>ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“</emphasis> j‚ƌĂт܂·B
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚±‚ê‚ðŽÀ‘•‚·‚é•û–@‚Í‚½‚­‚³‚ñ‚ ‚è‚Ü‚·B
+            </para>
+
+            <para>
+                Å‰‚ÉŽv‚¢‚‚­ŽÀ‘•‚́Aƒ†[ƒU[‚ªl‚¦‚Ä‚¢‚éŠÔA<literal>Session</literal>
+                ‚ƃf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðŠJ‚¢‚½‚Ü‚Ü‚É‚µ‚Ä‚¨‚­‚±‚Æ‚Å‚·B
+                “¯Žž‚ɏC³‚³‚ꂸA•ª—£‚ÆŒ´Žq«‚ª•ÛØ‚³‚ê‚é‚悤‚ɁA
+                ƒf[ƒ^ƒx[ƒX“à‚̃ƒbƒN‚Í•ÛŽ‚µ‚½‚Ü‚Ü‚É‚µ‚Ü‚·B
+                ‚à‚¿‚ë‚ñA‚±‚ê‚̓Aƒ“ƒ`ƒpƒ^[ƒ“‚Å‚·B
+                ‚È‚º‚È‚çAƒƒbƒN‚Ì‹£‡‚ª”­¶‚·‚é‚ƁA
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ª“¯Žžƒ†[ƒU[”‚ɉž‚¶‚ăXƒP[ƒ‹ƒAƒbƒv‚Å‚«‚È‚­‚È‚é‚©‚ç‚Å‚·B
+            </para>
+
+            <para>
+                –¾‚ç‚©‚ɁA‘Θb‚ðŽÀ‘•‚·‚邽‚߂ɂ́A
+                ‚¢‚­‚‚©‚̃f[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðŽg—p‚·‚é‚ׂ«‚Å‚·B
+                ‚±‚̏ꍇAƒrƒWƒlƒXƒvƒƒZƒX‚Ì•ª—£‚ðˆÛŽ‚·‚邱‚Ƃ́A
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‘w‚̐Ӗ±‚Ì‚P‚‚ɂȂè‚Ü‚·B
+                ‚P‚‚̑Θb‚́A
+                ’ʏ킢‚­‚‚©‚̃f[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚É‹y‚Ñ‚Ü‚·B
+                ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Ì‚P‚‚̂݁iÅŒã‚Ì‚P‚j‚ªXV‚µ‚½ƒf[ƒ^‚ð•Û‘¶‚µA
+                ‘¼‚̓f[ƒ^‚ð“Ç‚Þ‚¾‚¯‚Å‚ ‚ê‚΁A‚»‚ê‚̓Aƒgƒ~ƒbƒN‚Å‚·
+                i—Ⴆ‚΁A‚¢‚­‚‚©‚Ì—v‹^‰ž“š‚ðŒJ‚è•Ô‚·ƒEƒBƒU[ƒhŒ`Ž®‚̃_ƒCƒAƒƒOjB
+                ‚±‚ê‚Í•·‚­‚æ‚èAŽÀ‘•‚µ‚½‚Ù‚¤‚ªŠÈ’P‚Å‚·B
+                Hibernate‚Ì‹@”\‚ðŽg‚¤‚Ì‚Å‚ ‚ê‚΁A“Á‚ÉŠÈ’P‚Å‚·B
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <emphasis>Ž©“®ƒo[ƒWƒ‡ƒjƒ“ƒO</emphasis>
+                        - Hibernate‚ÍŽ©“®“I‚ÉŠyŠÏ“I“¯ŽžŽÀs§Œä‚ª‚Å‚«‚Ü‚·B
+                        ƒ†[ƒU[‚ªl‚¦‚Ä‚¢‚éŠÔ‚É“¯Žž‚ɏC³‚ª‚¨‚«‚½ê‡AŽ©“®“I‚ÉŒŸo‚Å‚«‚Ü‚·B
+                        ’ʏíA‘Θb‚̏I—¹Žž‚Ƀ`ƒFƒbƒN‚·‚邾‚¯‚Å‚·B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <emphasis>•ª—£iDetachedjƒIƒuƒWƒFƒNƒg</emphasis> - ‚·‚Å‚É‹c˜_‚µ‚½
+                        <emphasis>session-per-request</emphasis> ƒpƒ^[ƒ“‚ðŽg‚¤‚ÆŒˆ’肵‚½ê‡A
+                        ƒ[ƒh‚³‚ꂽ‚·‚ׂẴCƒ“ƒXƒ^ƒ“ƒX‚́Aƒ†[ƒU‚ªl‚¦‚Ä‚¢‚éŠÔ‚́A
+                        ƒZƒbƒVƒ‡ƒ“‚©‚番—£‚³‚ꂽó‘Ô‚É‚È‚è‚Ü‚·B
+                        ƒIƒuƒWƒFƒNƒg‚ðƒZƒbƒVƒ‡ƒ“‚ɍĒljÁ‚µAC³‚ð‰i‘±‰»‚Å‚«‚Ü‚·B
+                        ‚±‚ê‚ð <emphasis>session-per-request-with-detached-objects</emphasis>
+                        ƒpƒ^[ƒ“‚ƌĂт܂·B
+                        Ž©“®ƒo[ƒWƒ‡ƒjƒ“ƒO‚ðŽg‚¤‚±‚ƂŁA“¯Žž‚ɍs‚í‚ê‚éC³‚𕪗£‚Å‚«‚Ü‚·B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <emphasis>Šg’£i‚à‚µ‚­‚́A’·‚¢jƒZƒbƒVƒ‡ƒ“</emphasis>
+                        - Hibernate‚Ì <literal>Session</literal> ‚́A
+                        ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðƒRƒ~ƒbƒg‚µ‚½ŒãA
+                        — ‚ÅŒ‹‚т‚¢‚Ä‚¢‚éJDBCƒRƒlƒNƒVƒ‡ƒ“‚ðØ’f‚Å‚«‚Ü‚·B
+                        ‚»‚µ‚āAƒNƒ‰ƒCƒAƒ“ƒg‚©‚ç‚̐V‚µ‚¢—v‹‚ª”­¶‚µ‚½Û‚ɁAÄÚ‘±‚Å‚«‚Ü‚·B
+                        ‚±‚̃pƒ^[ƒ“‚́A<emphasis>session-per-conversation</emphasis>
+                        ‚Æ‚¢‚¤–¼‚Å’m‚ç‚ê‚Ä‚¨‚èAƒIƒuƒWƒFƒNƒg‚ðƒZƒbƒVƒ‡ƒ“‚֍ĒljÁ‚·‚邱‚Æ‚³‚¦•s—v‚É‚µ‚Ü‚·B
+                        Ž©“®ƒo[ƒWƒ‡ƒjƒ“ƒO‚ðŽg‚¤‚±‚ƂŁA“¯Žž‚ɍs‚í‚ê‚éC³‚𕪗£‚Å‚«‚Ü‚·B
+                        
+                        ’ʏí <literal>Session</literal> ‚ðŽ©“®“I‚Ƀtƒ‰ƒbƒVƒ…‚³‚¹‚¸A
+                        –¾Ž¦“I‚Ƀtƒ‰ƒbƒVƒ…‚µ‚Ü‚·B
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                <emphasis>session-per-request-with-detached-objects</emphasis> ‚Æ
+                <emphasis>session-per-conversation</emphasis> ‚Ì‚Q‚‚́A
+                —˜“_‚ÆŒ‡“_‚ðŽ‚Á‚Ä‚¢‚Ü‚·B
+                ‚±‚ê‚ɂ‚¢‚ẮA‚±‚̏͂̌ã‚Ì‚Ù‚¤‚ŁAŠyŠÏ“I“¯ŽžŽÀs§Œä‚Ì•¶–¬‚Ì’†‚Å‹c˜_‚µ‚Ü‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-identity">
+            <title>ƒIƒuƒWƒFƒNƒgŽ¯•ÊŽq‚ðl‚¦‚é</title>
+
+            <para>
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚́A‚Q‚‚̈قȂé <literal>Session</literal> ‚©‚ç
+                “¯‚¶‰i‘±ó‘Ô‚É“¯Žž‚ɃAƒNƒZƒX‚Å‚«‚Ü‚·B
+                ‚µ‚©‚µA‚Q‚Â‚Ì <literal>Session</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚ª
+                ‰i‘±«ƒNƒ‰ƒX‚Ì‚P‚‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ð‹¤—L‚·‚邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñB
+                ‚䂦‚ɁAŽ¯•ÊŽq‚É‚Í‚Q‚‚̈قȂéŠT”O‚ª‚ ‚é‚Æ‚¢‚¤‚±‚Æ‚É‚È‚è‚Ü‚·B
+            </para>
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term>ƒf[ƒ^ƒx[ƒXŽ¯•ÊŽq</term>
+                    <listitem>
+                        <para>
+                            <literal>foo.getId().equals( bar.getId() )</literal>
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>JVMŽ¯•ÊŽq</term>
+                    <listitem>
+                        <para>
+                            <literal>foo==bar</literal>
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+            <para>
+                <emphasis>ŒÂX‚Ì</emphasis> <literal>Session</literal> ‚ɒljÁ‚³‚ꂽƒIƒuƒWƒFƒNƒg‚É‚Æ‚Á‚Ä
+                i‚·‚È‚í‚¿A‚P‚Â‚Ì <literal>Session</literal> ‚̃XƒR[ƒv‚Ì’†‚ł́jA‚Q‚‚̊T”O‚Í“¯‚¶‚Å‚·B
+                ƒf[ƒ^ƒx[ƒX“¯ˆê«‚ÆJVM“¯ˆê«‚ªˆê’v‚·‚邱‚Æ‚ðAHibernate‚ª•ÛØ‚µ‚Ü‚·B
+                ‚µ‚©‚µAƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ª‚Q‚‚̈قȂéƒZƒbƒVƒ‡ƒ“‚©‚ç
+                u“¯‚¶vi‰i‘±«Ž¯•ÊŽq‚́jƒrƒWƒlƒXƒIƒuƒWƒFƒNƒg‚É“¯Žž‚ɃAƒNƒZƒX‚·‚éŒÀ‚èA
+                ‚Q‚‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ÍŽÀÛ‚ɁiJVMŽ¯•ÊŽq‚ªjuˆÙ‚È‚èv‚Ü‚·B
+                ŠyŠÏ“IƒAƒvƒ[ƒ`‚É‚æ‚Á‚āAiŽ©“®ƒo[ƒWƒ‡ƒjƒ“ƒO‚́jƒtƒ‰ƒbƒVƒ…^ƒRƒ~ƒbƒgŽž‚É
+                ƒRƒ“ƒtƒŠƒNƒg‚ª‰ðŒˆ‚³‚ê‚Ü‚·B
+            </para>
+
+            <para>
+                ‚±‚̃Aƒvƒ[ƒ`‚ł́AHibernate‚ƃf[ƒ^ƒx[ƒX‚É“¯ŽžŽÀs‚ɂ‚¢‚Ă̐S”z‚ªŽc‚è‚Ü‚·B
+                ˆê•û‚ŁAÅ‚‚̃XƒP[ƒ‰ƒrƒŠƒeƒB‚ª’ñ‹Ÿ‚³‚ê‚Ü‚·B
+                ‚È‚º‚È‚çA‚PƒXƒŒƒbƒh‚̍ì‹Æ’PˆÊ‚Ì’†‚ňêˆÓ«‚ª•ÛØ‚³‚ê‚ê‚΁A
+                ‚‰¿‚ȃƒbƒN‚⓯Šú‰»‚ª•s—v‚ɂȂ邽‚ß‚Å‚·B
+                <literal>Session</literal> ‚²‚Æ‚É‚P‚‚̃XƒŒƒbƒh‚ð“\‚è•t‚¯‚éŒÀ‚èA
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̓rƒWƒlƒXƒIƒuƒWƒFƒNƒg‚ðsynchronize‚·‚é•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+                <literal>Session</literal> “à‚ł́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̓IƒuƒWƒFƒNƒg‚ð”äŠr‚·‚邽‚߂ɁA
+                <literal>==</literal> ‚ðˆÀ‘S‚ÉŽg—p‚Å‚«‚Ü‚·B
+            </para>
+
+            <para>
+                ‚¯‚ê‚Ç‚àA<literal>Session</literal> ‚ÌŠO‚Å <literal>==</literal>
+                ‚ðŽg‚¤ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚́A—\Šú‚µ‚È‚¢Œ‹‰Ê‚É‘˜‹ö‚µ‚Ü‚·B
+                ‚±‚ê‚Í—\Šú‚µ‚È‚¢êŠ‚Å‹N‚±‚肦‚Ü‚·B
+                —Ⴆ‚΁A‚Q‚‚̕ª—£ƒCƒ“ƒXƒ^ƒ“ƒX‚𓯂¶ <literal>Set</literal> ‚É
+                put‚µ‚½‚Æ‚«‚È‚Ç‚Å‚·B
+                —¼•û‚Æ‚à“¯‚¶ƒf[ƒ^ƒx[ƒXŽ¯•ÊŽq‚ðŽ‚¿‚Ü‚·i‚·‚È‚í‚¿A“¯‚¶s‚ð•\‚µ‚Ü‚·jB
+                ‚µ‚©‚µA•ª—£ó‘Ԃ̃Cƒ“ƒXƒ^ƒ“ƒX‚ÌJVMŽ¯•ÊŽq‚Í“–‘R•ÛØ‚³‚ê‚Ü‚¹‚ñB
+                ŠJ”­ŽÒ‚́A‰i‘±«ƒNƒ‰ƒX‚Ì <literal>equals()</literal> ‚Æ <literal>hashCode()</literal>
+                ƒƒ\ƒbƒh‚ðƒI[ƒo[ƒ‰ƒCƒh‚µAƒIƒuƒWƒFƒNƒg“™‰¿«‚ÌŠT”O‚ðŽÀ‘•‚·‚ׂ«‚Å‚·B
+                Œx‚ª‚P‚‚ ‚è‚Ü‚·B“™‰¿«‚ÌŽÀ‘•‚Ƀf[ƒ^ƒx[ƒXŽ¯•ÊŽq‚ðŽg‚í‚È‚¢‚Å‚­‚¾‚³‚¢B
+                ƒ†ƒj[ƒN‚ȁi•’Ê‚Í•s•Ï‚́j‘®«‚Ì‘g‚ݍ‡‚킹‚Å‚ ‚éƒrƒWƒlƒXƒL[‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢B
+                ‚à‚µAˆêŽžƒIƒuƒWƒFƒNƒg‚ª‰i‘±‰»‚³‚ꂽê‡Aƒf[ƒ^ƒx[ƒXŽ¯•ÊŽq‚ª•Ï‚í‚è‚Ü‚·B
+                ˆêŽžƒIƒuƒWƒFƒNƒg‚ði’ʏ핪—£ƒCƒ“ƒXƒ^ƒ“ƒX‚Æ‹¤‚Ɂj <literal>Set</literal>
+                ‚É•ÛŽ‚·‚éê‡AƒnƒbƒVƒ…ƒR[ƒh‚ª•Ï‚í‚é‚Æ‚¢‚¤‚±‚Ƃ́A<literal>Set</literal>
+                ‚ÌŒ_–ñ‚ð”j‚é‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+                ƒrƒWƒlƒXƒL[‚Ì‚½‚ß‚Ì‘®«‚́Aƒf[ƒ^ƒx[ƒX‚ÌŽåƒL[‚قLjÀ’è‚·‚ׂ«‚Å‚Í‚È‚¢‚Å‚·B
+                ƒIƒuƒWƒFƒNƒg‚ª“¯‚¶ <literal>Set</literal> ‚Ì’†‚É‚¢‚éŠÔ‚¾‚¯AˆÀ’è‚ð•ÛØ‚·‚ׂ«‚Å‚·B
+                ‚±‚Ì–â‘è‚Ì‚æ‚è“O’ê“I‚È‹c˜_‚́AHibernate‚ÌWebƒTƒCƒg‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚Ü‚½A‚±‚ê‚ÍHibernate‚Ì–â‘è‚Å‚Í‚È‚­A’P‚ÉJavaƒIƒuƒWƒFƒNƒg‚ÌŽ¯•ÊŽq‚â“™‰¿«‚ð
+                ‚ǂ̂悤‚ÉŽÀ‘•‚·‚ׂ«‚©‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-issues">
+            <title>ˆê”Ê“I‚È–â‘è</title>
+
+             <para>
+                 <emphasis>session-per-user-session</emphasis> ‚Æ
+                 <emphasis>session-per-application</emphasis> ƒAƒ“ƒ`ƒpƒ^[ƒ“
+                 ‚ÍŽg‚Á‚Ä‚Í‚¢‚¯‚Ü‚¹‚ñi‚à‚¿‚ë‚ñA‚Ü‚ê‚É—áŠO‚ª‚ ‚è‚Ü‚·jB
+                 ’ˆÓF‰º‹L‚Ì–â‘è‚Ì‚¢‚­‚‚©‚́A„§‚³‚ê‚éƒpƒ^[ƒ“‚Æ‚µ‚Ä‚àoŒ»‚µ‚Ü‚·B
+                 ÝŒv‚ðŒˆ’è‚·‚é‘O‚ɁA— ‚̈Ӗ¡‚ð—‰ð‚·‚é‚悤‚É‚µ‚Ä‚­‚¾‚³‚¢B
+             </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <literal>Session</literal> ‚̓XƒŒƒbƒhƒZ[ƒt‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+                        HTTPƒŠƒNƒGƒXƒgAƒZƒbƒVƒ‡ƒ“BeanASwingƒ[ƒJ[‚̂悤‚ɁA
+                        “¯ŽžŽÀs‚ª‰Â”\‚È‚à‚Ì‚ª <literal>Session</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚ð‹¤—L‚·‚é‚ƁA
+                        ‹£‡ó‘Ô‚ðˆø‚«‹N‚±‚µ‚Ü‚·B
+                        iŒã‚Å‹c˜_‚·‚éj<literal>HttpSession</literal> ‚Ì’†‚Å
+                        Hibernate <literal>Session</literal> ‚ð•ÛŽ‚·‚éê‡A
+                        HttpSession‚ւ̃AƒNƒZƒX‚𓯊ú‰»‚·‚邱‚Æ‚ðl—¶‚·‚ׂ«‚Å‚·B
+                        ‚³‚à‚È‚¯‚ê‚΁Aƒ†[ƒU[‚ª\•ª‘‚­ƒŠƒ[ƒh‚ðƒNƒŠƒbƒN‚·‚é‚ƁA
+                        “¯Žž‚É‘–‚é‚Q‚‚̃XƒŒƒbƒh‚Ì’†‚ŁA“¯‚¶ <literal>Session</literal> ‚ªŽg‚í‚ê‚Ü‚·B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Hibernate‚ª—áŠO‚ð“Š‚°‚½ê‡‚́Aƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðƒ[ƒ‹ƒoƒbƒN‚µA
+                        ’¼‚¿‚É <literal>Session</literal> ‚ð•Â‚¶‚é‚ׂ«‚Å‚·iÚ×‚ðŒã‚Å‹c˜_‚µ‚Ü‚·jB
+                        <literal>Session</literal> ‚ªƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ÉŒ‹‚Ñ•t‚¯‚ç‚ê‚Ä‚¢‚é‚Ì‚Å‚ ‚ê‚΁A
+                        ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ð’âŽ~‚·‚ׂ«‚Å‚·B
+                        ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðƒ[ƒ‹ƒoƒbƒN‚µ‚Ä‚àAƒrƒWƒlƒXƒIƒuƒWƒFƒNƒg‚Í
+                        ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðŠJŽn‚µ‚½‚Æ‚«‚̏ó‘Ô‚É–ß‚è‚Ü‚¹‚ñB
+                        ‚±‚ê‚́Aƒf[ƒ^ƒx[ƒX‚̏ó‘ԂƃrƒWƒlƒXƒIƒuƒWƒFƒNƒg‚Í“¯Šú‚µ‚Ä‚¢‚È‚¢‚±‚Æ‚ðˆÓ–¡‚µ‚Ü‚·B
+                        ’ʏ킱‚ê‚Í–â‘è‚É‚È‚è‚Ü‚¹‚ñB
+                        ‚È‚º‚È‚çA—áŠO‚͉ñ•œ‚Å‚«‚È‚¢‚©‚ç‚Å‚·B
+                        ‚Æ‚É‚©‚­ƒ[ƒ‹ƒoƒbƒN‚µ‚½Œã‚É‚â‚è’¼‚·‚ׂ«‚Å‚·B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session</literal> ‚͉i‘±ipersistentjó‘Ô‚Ì‚·‚ׂẴIƒuƒWƒFƒNƒg‚ð
+                        ƒLƒƒƒbƒVƒ…‚µ‚Ü‚·iHibernate‚ÍŠÄŽ‹‚µAƒ_[ƒeƒBó‘Ô‚©ƒ`ƒFƒbƒN‚µ‚Ü‚·jB
+                        ‚±‚ê‚́A’·‚¢ŠÔƒZƒbƒVƒ‡ƒ“‚ðŠJ‚¢‚½‚Ü‚Ü‚É‚·‚é‚©A
+                        ”ñí‚É‘½‚­‚̃f[ƒ^‚ðƒ[ƒh‚µ‘±‚¯‚é‚©‚µ‚½ê‡‚́A
+                        OutOfMemoryException‚ª”­¶‚·‚é‚Ü‚Å–³ŒÀ‚É‘å‚«‚­‚Ȃ邱‚Æ‚ðˆÓ–¡‚µ‚Ü‚·B
+                        ‰ðŒˆô‚Ì‚P‚‚́A<literal>Session</literal> ƒLƒƒƒbƒVƒ…‚ðŠÇ—‚·‚邽‚߂ɁA
+                        <literal>clear()</literal> ‚© <literal>evict()</literal> ‚ðŒÄ‚Ô‚±‚Æ‚Å‚·B
+                        ‚µ‚©‚µA‘å‚«‚ȃf[ƒ^‚ðˆ—‚·‚é•K—v‚ª‚ ‚é‚È‚çA
+                        ‚½‚Ô‚ñƒXƒgƒAƒhƒvƒƒV[ƒWƒƒ‚ðl—¶‚·‚é‚ׂ«‚Å‚µ‚傤B
+                        ‚¢‚­‚‚©‚Ì‰ðŒˆô‚́A<xref linkend="batch"/> ‚ŏЉ‚ê‚Ä‚¢‚Ü‚·B
+                        ƒ†[ƒU[ƒZƒbƒVƒ‡ƒ“‚̊ԁA<literal>Session</literal> ‚ðŠJ‚¢‚½‚Ü‚Ü‚É‚·‚é‚Æ‚¢‚¤‚±‚Ƃ́A
+                        ƒf[ƒ^‚ªV‘N‚Å‚È‚­‚È‚éŠm—¦‚ª‚‚­‚Ȃ邱‚Æ‚ðˆÓ–¡‚µ‚Ü‚·B
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="transactions-demarcation">
+        <title>ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE</title>
+
+        <para>
+            ƒf[ƒ^ƒx[ƒXi‚à‚µ‚­‚̓VƒXƒeƒ€jƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Ì‹«ŠE‚́Aí‚É•K—v‚Å‚·B
+            ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÌŠO‚ŁAƒf[ƒ^ƒx[ƒX‚Ƃ̒ʐM‚Í‹N‚«‚Ü‚¹‚ñ
+            i‚±‚ê‚ÍŽ©“®ƒRƒ~ƒbƒgƒ‚[ƒh‚ÉŠµ‚ê‚Ä‚¢‚鑽‚­‚ÌŠJ”­ŽÒ‚ð¬—‚³‚¹‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñjB
+            “ǂݍž‚Þ‚¾‚¯‚Ì‘€ì‚É‚Å‚àA‚¢‚Â‚à–¾Šm‚ȃgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚ðŽg—p‚µ‚Ä‚­‚¾‚³‚¢B
+            •ª—£ƒŒƒxƒ‹‚ƃf[ƒ^ƒx[ƒX‚Ì”\—ÍŽŸ‘æ‚ŁA‚±‚ê‚Í•K—v‚È‚¢‚©‚à‚µ‚ê‚Ü‚¹‚ñ‚ªA
+            í‚Ƀgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚𖾎¦“I‚ÉŽw’肵‚Ä‚àAƒ}ƒCƒiƒX–Ê‚Í‘S‚­‚ ‚è‚Ü‚¹‚ñB
+            
+            Šm‚©‚ɁA‚P‚‚̃f[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Í‘½”‚̏¬‚³‚ȃgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚æ‚è
+            iƒf[ƒ^‚̓ǂݍž‚Ý‚Å‚ ‚Á‚Ä‚àjƒpƒtƒH[ƒ}ƒ“ƒX‚ª‚·‚®‚ê‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <para>
+            J2EEŠÂ‹«‚ÉŠÇ—‚³‚ê‚Ä‚¢‚È‚¢ó‘Ô
+            i‚·‚È‚í‚¿AƒXƒ^ƒ“ƒhƒAƒƒ“A’Pƒ‚ÈWeb‚âSwingƒAƒvƒŠƒP[ƒVƒ‡ƒ“j‚Å‚àA
+            ŠÇ—‚³‚ꂽó‘Ô‚Å‚àAHibernateƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ðŽÀs‚Å‚«‚Ü‚·B
+            ŠÇ—‚³‚ê‚Ä‚¢‚È‚¢ŠÂ‹«‚ł́AHiberante‚ªƒf[ƒ^ƒx[ƒX‚̃RƒlƒNƒVƒ‡ƒ“ƒv[ƒ‹‚ð’ñ‹Ÿ‚µ‚Ü‚·B
+            ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ŠJ”­ŽÒ‚́Aƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚ðŽè“®‚Őݒ肵‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            Œ¾‚¢Š·‚¦‚é‚ƁAƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÌŠJŽnAƒRƒ~ƒbƒgAƒ[ƒ‹ƒoƒbƒN‚ð
+            ŠJ”­ŽÒŽ©g‚ªÝ’è‚·‚é•K—v‚ª‚ ‚é‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+            
+            ’ʏíAŠÇ—‚³‚ꂽŠÂ‹«‚ł́AƒRƒ“ƒeƒiŠÇ—‚É‚æ‚éƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“iCMTj‚ª’ñ‹Ÿ‚³‚ê‚Ü‚·B
+            —Ⴆ‚΁AƒZƒbƒVƒ‡ƒ“Bean‚̃fƒvƒƒCƒƒ“ƒgƒfƒBƒXƒNƒŠƒvƒ^‚Ő錾“I‚É’è‹`‚µA
+            ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ð‘g‚Ý—§‚Ä‚Ü‚·B
+            ƒvƒƒOƒ‰ƒ€‚É‚æ‚éƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚Í‚à‚¤•K—v‚ ‚è‚Ü‚¹‚ñB
+        </para>
+
+        <para>
+            ‚µ‚©‚µ‚È‚ª‚çAŠÇ—‚³‚ê‚Ä‚¢‚È‚¢ƒŠƒ\[ƒXEƒ[ƒJƒ‹‚Ȋ‹«‚Æ
+            JTA‚Ɉˑ¶‚µ‚½ƒVƒXƒeƒ€iCMT‚Å‚Í‚È‚­BMTj‚Ì—¼•û‚ɁA
+            ‰i‘±‰»‘w‚ðƒ|[ƒ^ƒuƒ‹‚ɕۂ‚̂́A‚µ‚΂µ‚Ζ]‚Ü‚µ‚¢‚±‚Æ‚Å‚·B
+            
+            ƒfƒvƒƒCŠÂ‹«‚̃lƒCƒeƒBƒu‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ƒVƒXƒeƒ€‚ðŒÄ‚яo‚·
+            <literal>Transaction</literal> ‚Æ‚¢‚¤ƒ‰ƒbƒp[API‚ðHibernate‚ª’ñ‹Ÿ‚µ‚Ü‚·B
+            ‚±‚ÌAPI‚ðŽg‚¤‚©‚Í”CˆÓ‚Å‚·‚ªACMT‚̃ZƒbƒVƒ‡ƒ“Bean‚ðŽg‚í‚È‚¢‚Ì‚Å‚ ‚ê‚΁AŽg‚¤‚±‚Æ‚ð‹­‚­„§‚µ‚Ü‚·B
+        </para>
+
+        <para>
+            ’ʏíA<literal>Session</literal> I—¹‚́A‚S‚‚̈قȂéƒtƒF[ƒY‚ðŠÜ‚Ý‚Ü‚·B
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    ƒZƒbƒVƒ‡ƒ“‚̃tƒ‰ƒbƒVƒ…
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̃Rƒ~ƒbƒg
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    ƒZƒbƒVƒ‡ƒ“‚̃Nƒ[ƒY
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    —áŠO‚̃nƒ“ƒhƒŠƒ“ƒO
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            ƒZƒbƒVƒ‡ƒ“‚̃tƒ‰ƒbƒVƒ…‚ɂ‚¢‚ẮA‘O‚Ì‚Ù‚¤‚Å‚·‚Å‚É‹c˜_‚µ‚Ü‚µ‚½B
+            ŠÇ—‚³‚ꂽŠÂ‹«‚ÆŠÇ—‚³‚ê‚Ä‚¢‚È‚¢ŠÂ‹«‚Ì—¼•û‚ɂ‚¢‚āA
+            ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚Æ—áŠOƒnƒ“ƒhƒŠƒ“ƒO‚ð‚à‚Á‚Əڂµ‚­Œ©‚Ä‚¢‚«‚Ü‚µ‚傤B
+        </para>
+
+
+        <sect2 id="transactions-demarcation-nonmanaged" revision="2">
+            <title>ŠÇ—‚³‚ê‚Ä‚¢‚È‚¢ŠÂ‹«</title>
+
+            <para>
+                Hibernate‰i‘±‰»‘w‚ðŠÇ—‚³‚ê‚Ä‚¢‚È‚¢ŠÂ‹«‚ÅŽÀ‘•‚·‚éê‡‚́A
+                
+                ’ʏí’Pƒ‚ȃRƒlƒNƒVƒ‡ƒ“ƒv[ƒ‹i‚·‚È‚í‚¿DataSource‚Å‚Í‚È‚¢j‚É‚æ‚Á‚āA
+                ƒf[ƒ^ƒx[ƒXƒRƒlƒNƒVƒ‡ƒ“‚𐧌䂵‚Ü‚·B
+                Hibernate‚Í‚»‚̃RƒlƒNƒVƒ‡ƒ“ƒv[ƒ‹‚©‚ç•K—v‚ȃRƒlƒNƒVƒ‡ƒ“‚ðŽæ“¾‚µ‚Ü‚·B
+                
+                ƒZƒbƒVƒ‡ƒ“^ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“§Œä‚̃CƒfƒBƒIƒ€‚ÍŽŸ‚̂悤‚É‚È‚è‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[// Non-managed environment idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+    tx = sess.beginTransaction();
+
+    // do some work
+    ...
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    if (tx != null) tx.rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+            <para>
+                –¾Ž¦“I‚É <literal>Session</literal> ‚Ì <literal>flush()</literal> ‚ðŒÄ‚яo‚·‚ׂ«‚Å‚Í‚È‚­A
+                <literal>commit()</literal> ‚ðŒÄ‚яo‚·‚±‚Æ‚É‚æ‚èAŽ©“®“I‚É“¯Šú‰»ˆ—‚ªŽÀs‚³‚ê‚Ü‚·
+                iƒZƒbƒVƒ‡ƒ“‚Ì <xref linkend="objectstate-flushing">FlushMode</xref> ‚Ɉˑ¶‚µ‚Ä‚¢‚éjB
+                
+                <literal>close()</literal> ‚ðŒÄ‚яo‚·‚±‚Æ‚É‚æ‚èAƒZƒbƒVƒ‡ƒ“‚̏I‚í‚è‚𖾊m‚É‚µ‚Ü‚·B
+                <literal>close()</literal> ‚ªˆÃ–Ù“I‚ɍs‚¤Žå‚È‚±‚Ƃ́A
+                ƒZƒbƒVƒ‡ƒ“‚ªJDBCƒRƒlƒNƒVƒ‡ƒ“‚ðŠJ•ú‚·‚邱‚Æ‚Å‚·B
+                
+                ã‹L‚ÌJavaƒR[ƒh‚̓|[ƒ^ƒuƒ‹‚Å‚ ‚èAŠÇ—‚³‚ê‚Ä‚¢‚È‚¢ŠÂ‹«‚ÆJTAŠÂ‹«‚Ì—¼•û‚ÅŽÀs‚Å‚«‚Ü‚·B
+            </para>
+
+           <para>
+                ‚æ‚è“K‰ž«‚Ì‚ ‚é‰ðŒˆô‚́AHibernate‚É—\‚ß‘g‚ݍž‚Ü‚ê‚Ä‚¢‚é
+                ucurrent sessionvƒRƒ“ƒeƒLƒXƒgŠÇ—‚Å‚·B
+                Œ¾—t‚Åà–¾‚·‚é‚æ‚艺‹L‚ðŒ©‚½‚Ù‚¤‚ª‘¬‚¢‚Å‚µ‚傤B
+            </para>
+
+            <programlisting><![CDATA[// Non-managed environment idiom with getCurrentSession()
+try {
+    factory.getCurrentSession().beginTransaction();
+
+    // do some work
+    ...
+
+    factory.getCurrentSession().getTransaction().commit();
+}
+catch (RuntimeException e) {
+    factory.getCurrentSession().getTransaction().rollback();
+    throw e; // or display error message
+}]]></programlisting>
+
+            <para>
+                ³‹K‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚Ì’†‚ł́A‚±‚̂悤‚ȃR[ƒh‚̐؂ê’[‚ðŒˆ‚µ‚ÄŒ©‚È‚¢‚Å‚µ‚傤B
+                ’v–½“I‚ȁiƒVƒXƒeƒ€j—áŠO‚́Aí‚ɁuÅãˆÊv‚ŃLƒƒƒbƒ`‚·‚ׂ«‚Å‚·B
+                Œ¾‚¢Š·‚¦‚ê‚΁Ai‰i‘±‰»‘w‚ŁjHibernateŒÄ‚яo‚µ‚ðŽÀs‚·‚éƒR[ƒh‚ƁA
+                <literal>RuntimeException</literal> ‚𐧌䂷‚é
+                i’ʏí‚̓NƒŠ[ƒ“ƒAƒbƒv‚ƏI—¹‚̂ݍs‚¤‚±‚Æ‚ª‚Å‚«‚éjƒR[ƒh‚́A•ÊX‚Ì‘w‚Ì’†‚É‚ ‚è‚Ü‚·B
+                Hibernate‚É‚æ‚éƒJƒŒƒ“ƒgƒRƒ“ƒeƒLƒXƒgŠÇ—‚́A‚±‚̐݌v‚ð‚©‚È‚è’Pƒ‚É‚µ‚Ü‚·B
+                •K—v‚Ȃ̂́A<literal>SessionFactory</literal> ‚ɃAƒNƒZƒX‚·‚邱‚Æ‚¾‚¯‚Å‚·B
+                —áŠOˆ—‚́A‚±‚̏͂̌ã‚Ì‚Ù‚¤‚Å‹c˜_‚µ‚Ü‚·B
+            </para>
+
+           <para>
+                ’ˆÓFiƒfƒtƒHƒ‹ƒg‚Å‚·‚ªj
+                <literal>org.hibernate.transaction.JDBCTransactionFactory</literal>
+                ‚ð‘I‘ð‚·‚é‚ׂ«‚Å‚·B
+                ‘æ2‚Ì—p—á‚Æ‚µ‚ẮA
+                <literal>hibernate.current_session_context_class</literal> ‚ð
+                <literal>"thread"</literal> ‚Æ‚·‚é‚Æ‚æ‚¢‚Å‚µ‚傤B
+            </para>
+            
+        </sect2>
+
+        <sect2 id="transactions-demarcation-jta" revision="3">
+            <title>JTA‚ðŽg—p‚·‚é</title>
+
+            <para>
+                ‰i‘±‰»‘w‚ðƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo[i—Ⴆ‚΁AEJBƒZƒbƒVƒ‡ƒ“Bean‚Ì”wŒãj‚ÅŽÀs‚·‚éê‡A
+                Hibernate‚©‚çŽæ“¾‚·‚é‚·‚ׂẴf[ƒ^ƒ\[ƒXƒRƒlƒNƒVƒ‡ƒ“‚́A
+                Ž©“®“I‚ɃOƒ[ƒoƒ‹JTAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̈ꕔ‚É‚È‚è‚Ü‚·B
+                
+                EJB‚ðŽg‚킸‚ɁAƒXƒ^ƒ“ƒhƒAƒƒ“‚ÌJTAŽÀ‘•‚𓱓ü‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+                JTA“‡‚Ì‚½‚߂ɁAHibernate‚Í‚Q‚‚̐헪‚ð’ñ‹Ÿ‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                BeanŠÇ—ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“iBMTj‚ðŽg‚¢A<literal>Transaction</literal> API‚ðŽg‚¤ê‡A
+                Hibernate‚̓AƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo[‚ÉBMTƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÌŠJŽn‚ƏI‚í‚è‚ð‚°‚Ü‚·B
+                ‚·‚È‚í‚¿Aƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ŠÇ—‚̃R[ƒh‚́AŠÇ—‚³‚ê‚È‚¢ŠÂ‹«‚Æ“¯‚¶‚É‚È‚è‚Ü‚·B
+            </para>
+            
+           <programlisting><![CDATA[// BMT idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+    tx = sess.beginTransaction();
+
+    // do some work
+    ...
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    if (tx != null) tx.rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+           <para>
+               ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚Æ‚µ‚Ä <literal>Session</literal> ‚ðŽg‚¢‚½‚¢ê‡A
+               ŠÈ’P‚ɃRƒ“ƒeƒLƒXƒg‚ð“`”d‚·‚é‹@”\‚Å‚ ‚é <literal>getCurrentSession()</literal> ‚ª‚ ‚é‚̂ŁA
+               JTA‚Ì <literal>UserTransaction</literal> API‚𒼐ڎg—p‚·‚ׂ«‚Å‚µ‚傤B
+            </para>
+
+            <programlisting><![CDATA[// BMT idiom with getCurrentSession()
+try {
+    UserTransaction tx = (UserTransaction)new InitialContext()
+                            .lookup("java:comp/UserTransaction");
+
+    tx.begin();
+
+    // Do some work on Session bound to transaction
+    factory.getCurrentSession().load(...);
+    factory.getCurrentSession().persist(...);
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    tx.rollback();
+    throw e; // or display error message
+}]]></programlisting>
+
+            <para>
+                CMT‚ł́Aƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚ðƒZƒbƒVƒ‡ƒ“Bean‚̃fƒvƒƒCƒƒ“ƒgƒfƒBƒXƒNƒŠƒvƒ^‚Å’è‹`‚µA
+                ƒvƒƒOƒ‰ƒ€‚ł͍s‚¢‚Ü‚¹‚ñB
+                ‚䂦‚ɁAƒR[ƒh‚ÍŽŸ‚̂悤‚ɏ­‚È‚­‚È‚è‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[// CMT idiom
+ Session sess = factory.getCurrentSession();
+
+ // do some work
+ ...
+]]></programlisting>
+
+            <para>
+                CMT/EJB‚Ì’†‚ł́Aí‚Ƀ[ƒ‹ƒoƒbƒN‚ªŽ©“®“I‚ÉŽÀŽ{‚³‚ê‚Ü‚·B
+                ‚È‚º‚È‚çAƒZƒbƒVƒ‡ƒ“ƒr[ƒ“‚̃ƒ\ƒbƒh‚É‚æ‚è“Š‚°‚ç‚ꂽ§Œä‚³‚ê‚Ä‚¢‚È‚¢
+                <literal>RuntimeException</literal> ‚́AƒOƒ[ƒoƒ‹ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ð
+                ƒ[ƒ‹ƒoƒbƒN‚·‚é‚悤‚ɃRƒ“ƒeƒi‚É“`‚¦‚邽‚ß‚Å‚·B
+                <emphasis>‚±‚ê‚́ABMT‚à‚µ‚­‚ÍCMT‚Æ‚¢‚Á‚µ‚å‚ÉHibernate <literal>Transaction</literal>
+                API‚ðŽg‚¤•K—v‚͏­‚µ‚à‚È‚¢‚Æ‚¢‚¤ˆÓ–¡‚Å‚·B</emphasis>
+            </para>
+
+            <para>
+                Hibernate‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ƒtƒ@ƒNƒgƒŠ‚ðÝ’è‚·‚éÛ‚ɁA
+                JTA‚𒼐ڎg‚¤iBMT‚́jê‡‚Í <literal>org.hibernate.transaction.JTATransactionFactory</literal> ‚ðA
+                CMTƒZƒbƒVƒ‡ƒ“ƒr[ƒ“‚Ì’†‚Å‚Í <literal>org.hibernate.transaction.CMTTransactionFactory</literal> ‚ð
+                ‘I‘ð‚·‚×‚«‚¾‚Æ‚¢‚¤‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                <literal>hibernate.transaction.manager_lookup_class</literal>
+                ‚ðƒZƒbƒg‚·‚邱‚Æ‚àŽv‚¢o‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚È‚¨A<literal>hibernate.current_session_context_class</literal> ‚́A
+                ƒZƒbƒg‚µ‚È‚¢‚©iŒã•ûŒÝŠ·jA<literal>"jta"</literal> ‚ðƒZƒbƒg‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+            
+            <para>
+                <literal>getCurrentSession()</literal> ƒIƒyƒŒ[ƒVƒ‡ƒ“‚́AJTAŠÂ‹«‚Å‚Í‚P‚‚̌‡“_‚ðŽ‚¿‚Ü‚·B
+                
+                ƒfƒtƒHƒ‹ƒg‚ÅŽg‚í‚ê‚é <literal>after_statement</literal> ƒRƒlƒNƒVƒ‡ƒ“ƒŠƒŠ[ƒXƒ‚[ƒh‚ðŽg—p‚·‚éã‚ŁA
+                Œx‚ª‚P‚‚ ‚è‚Ü‚·B
+                
+                JTAŽd—l‚Ì‹ð‚©‚È§–ñ‚Ì‚½‚߂ɁA
+                <literal>scroll()</literal> ‚Ü‚½‚Í <literal>iterate()</literal> ‚ª•Ô‚µ‚½A
+                •Â‚¶‚ç‚ê‚Ä‚¢‚È‚¢ <literal>ScrollableResults</literal> ‚Ü‚½‚Í <literal>Iterator</literal>
+                ƒCƒ“ƒXƒ^ƒ“ƒX‚ðHibernate‚ªŽ©“®“I‚ɃNƒŠ[ƒ“ƒAƒbƒv‚·‚邱‚Æ‚Í‚Å‚«‚Ü‚¹‚ñB
+                
+                <literal>finally</literal> ƒuƒƒbƒN‚Ì’†‚ŁA
+                <literal>ScrollableResults.close()</literal> ‚Ü‚½‚Í
+                <literal>Hibernate.close(Iterator)</literal> ‚𖾎¦“I‚ɌĂяo‚µ‚āA
+                — ‚ɐö‚ñ‚¾ƒf[ƒ^ƒx[ƒXƒJ[ƒ\ƒ‹‚ð‰ð•ú <emphasis>‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ</emphasis>B
+                
+                i‚à‚¿‚ë‚ñA‘½‚­‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚ł́AJTA‚©CMTƒR[ƒh‚Å <literal>scroll()</literal>
+                ‚â <literal>iterate()</literal> ‚ÌŽg—p‚ð”ð‚¯‚é‚Ì‚Í—eˆÕ‚Å‚·Bj
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-demarcation-exceptions">
+            <title>—áŠOƒnƒ“ƒhƒŠƒ“ƒO</title>
+
+            <para>
+                <literal>Session</literal> ‚ª—áŠOi<literal>SQLException</literal>‚ðŠÜ‚ށj‚ð“Š‚°‚½ê‡A
+                ’¼‚¿‚ɁAƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðƒ[ƒ‹ƒoƒbƒN‚µA<literal>Session.close()</literal>
+                ‚ðŒÄ‚сA<literal>Session</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚ð”jŠü‚·‚ׂ«‚Å‚·B
+                <literal>Session</literal> ‚Ì‚¢‚­‚‚©‚̃ƒ\ƒbƒh‚́A
+                ƒZƒbƒVƒ‡ƒ“‚̏ó‘Ô‚ð <emphasis>–µ‚‚µ‚½‚Ü‚Ü</emphasis> ‚É‚µ‚Ü‚·B
+                Hibernate‚ª“Š‚°‚½—áŠO‚ðA‰ñ•œ‚Å‚«‚é‚à‚Ì‚Æ‚µ‚Ĉµ‚¤‚±‚Æ‚Í‚Å‚«‚Ü‚¹‚ñB
+                <literal>finally</literal> ƒuƒƒbƒN‚Ì’†‚Å <literal>close()</literal> ‚ðŒÄ‚ñ‚ŁA
+                <literal>Session</literal> ‚ðŠmŽÀ‚ɕ‚¶‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <para>
+                <literal>HibernateException</literal> ‚́AHibernate‰i‘±‰»‘w‚Ì’†‚Å”­¶‚·‚鑽‚­‚̃Gƒ‰[‚ð
+                ƒ‰ƒbƒv‚·‚éAŒŸ¸‚³‚ê‚È‚¢—áŠO‚Å‚·iHibernate‚̌¢ƒo[ƒWƒ‡ƒ“‚͈Ⴂ‚Ü‚µ‚½jB
+                Ž„‚½‚¿‚̈ӌ©‚́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“ŠJ”­ŽÒ‚ɉñ•œ•s‰Â”\‚È—áŠO‚ð
+                ‰º‘w‚ŃLƒƒƒbƒ`‚·‚邱‚Æ‚ð‹­—v‚·‚ׂ«‚Å‚Í‚È‚¢‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+                ‘½‚­‚̃VƒXƒeƒ€‚ł́AŒŸ¸‚³‚ê‚È‚¢—áŠO‚Æ’v–½“I‚È—áŠO‚́A
+                ƒR[ƒ‹ƒXƒ^ƒbƒN‚̍ŏ‰‚̃tƒŒ[ƒ€‚Ì‚P‚i—Ⴆ‚΁AÅãˆÊ‚Ì‘w‚Łj‚Ńnƒ“ƒhƒŠƒ“ƒO‚µA
+                ƒGƒ‰[ƒƒbƒZ[ƒW‚ðƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒ†[ƒU[‚É•\Ž¦‚µ‚Ü‚·
+                i‚à‚µ‚­‚́A‘¼‚Ì“KØ‚ȏˆ—‚ðŽÀŽ{‚µ‚Ü‚·jB
+                Hibernate‚́A<literal>HibernateException</literal> ˆÈŠO‚ÌŒŸ¸‚³‚ê‚È‚¢—áŠO‚à
+                “Š‚°‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚±‚ê‚ç‚à‚Ü‚½A‰ñ•œ•s‰Â”\‚Å‚ ‚èA“KØ‚ȏˆ—‚ðŽÀŽ{‚·‚ׂ«‚Å‚·B
+            </para>
+
+            <para>
+                Hibernate‚́Aƒf[ƒ^ƒx[ƒX‚Ƃ̑Θb’†‚É“Š‚°‚ç‚ꂽ <literal>SQLException</literal> ‚ð
+                <literal>JDBCException</literal> ‚щƒbƒv‚µ‚Ü‚·B
+                ŽÀ‚́A—áŠO‚ð‚æ‚èˆÓ–¡‚Ì‚ ‚é <literal>JDBCException</literal> ‚̃TƒuƒNƒ‰ƒX‚É
+                •ÏŠ·‚µ‚悤‚ÆŽŽ‚Ý‚Ü‚·B
+                Œ³‚Ì <literal>SQLException</literal> ‚́A<literal>JDBCException.getCause()</literal>
+                ‚É‚æ‚è‚¢‚Â‚Å‚à“¾‚ç‚ê‚Ü‚·B
+                Hibernate‚́A<literal>SessionFactory</literal> ‚ɒljÁ‚³‚ê‚Ä‚¢‚é
+                <literal>SQLExceptionConverter</literal> ‚ðŽg‚¢A<literal>SQLException</literal> ‚ð
+                “K“–‚È <literal>JDBCException</literal> ƒTƒuƒNƒ‰ƒX‚É•ÏŠ·‚µ‚Ü‚·B
+                ƒfƒtƒHƒ‹ƒg‚ł́A<literal>SQLExceptionConverter</literal> ‚͐ݒ肳‚ê‚Ä‚¢‚éSQL•ûŒ¾‚É‚æ‚è
+                ’è‹`‚³‚ê‚Ü‚·B
+                ˆê•û‚ŁA“ÆŽ©‚ÌŽÀ‘•‚ɍ·‚µ‘Ö‚¦‚邱‚Æ‚à‚Å‚«‚Ü‚·
+                iÚ×‚́A<literal>SQLExceptionConverterFactory</literal> ƒNƒ‰ƒX‚ÌJavadoc‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢jB
+                •W€“I‚È <literal>JDBCException</literal> ‚̃Tƒuƒ^ƒCƒv‚ð‰º‹L‚ÉŽ¦‚µ‚Ü‚·B
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>JDBCConnectionException</literal> -
+                        Šî‘b‚Æ‚È‚éJDBC’ʐM‚̃Gƒ‰[‚ð•\‚µ‚Ü‚·B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>SQLGrammarException</literal> -
+                        ”­s‚·‚éSQL‚Ì•¶–@‚à‚µ‚­‚͍\•¶‚Ì–â‘è‚ð•\‚µ‚Ü‚·B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>ConstraintViolationException</literal> -
+                        ‰½‚ç‚©‚ÌŒ`Ž®‚ÌŠ®‘S«§–ñˆá”½‚ð•\‚µ‚Ü‚·B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>LockAcquisitionException</literal> -
+                        —v‹‚³‚ꂽ‘€ì‚ðŽÀŽ{‚·‚é‚Ì‚É•K—v‚ȃƒbƒNƒŒƒxƒ‹‚𓾂éÛ‚̃Gƒ‰[‚ð•\‚µ‚Ü‚·B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>GenericJDBCException</literal> -
+                        ‘¼‚̃JƒeƒSƒŠ‚Ɉê’v‚µ‚È‚©‚Á‚½ˆê”Ê“I‚È—áŠO‚Å‚·B
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+        </sect2>
+
+        <sect2 id="transactions-demarcation-timeout">
+            <title>ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̃^ƒCƒ€ƒAƒEƒg</title>
+
+            <para>
+                EJB‚̂悤‚ÈŠÇ—‚³‚ꂽŠÂ‹«‚ª’ñ‹Ÿ‚·‚é‚«‚í‚߂ďd—v‚È“Á’¥‚Ì‚P‚‚́A
+                ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̃^ƒCƒ€ƒAƒEƒg‚Å‚·B
+                ‚±‚ê‚ÍŠÇ—‚³‚ê‚Ä‚¢‚È‚¢ƒR[ƒh‚É‚Í’ñ‹Ÿ‚Å‚«‚Ü‚¹‚ñB
+                ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ƒ^ƒCƒ€ƒAƒEƒg‚́A•s•is‚ȃgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ª
+                ƒ†[ƒU[‚ɃŒƒXƒ|ƒ“ƒX‚ð•Ô‚³‚È‚¢‚܂܁A–³ŠúŒÀ‚ɃŠƒ\[ƒX‚ðŽg‚¢‘±‚¯‚È‚¢
+                ‚±‚Æ‚ð•Ûá‚µ‚Ü‚·B
+                ŠÇ—‚³‚ꂽŠÂ‹«iJTAj‚ÌŠO‚ł́AHibernate‚Í‚±‚Ì‹@”\‚ðƒtƒ‹‚É’ñ‹Ÿ‚Å‚«‚Ü‚¹‚ñB
+                ‚µ‚©‚µ‚È‚ª‚çAHibernate‚ÍŽŸ‚̂悤‚ȃf[ƒ^ƒAƒNƒZƒX‘€ì‚̐§Œä‚­‚ç‚¢‚Í‚Å‚«‚Ü‚·B
+                ƒf[ƒ^ƒx[ƒXƒŒƒxƒ‹‚̃fƒbƒhƒƒbƒN‚â‘å‚«‚ȃŠƒUƒ‹ƒgƒZƒbƒg‚ð•Ô‚·ƒNƒGƒŠ‚ð
+                ’è‹`‚³‚ꂽƒ^ƒCƒ€ƒAƒEƒg‚É‚æ‚Á‚ÄŠmŽÀ‚ɐ§ŒÀ‚µ‚Ü‚·B
+                ŠÇ—‚³‚ꂽŠÂ‹«‚ł́AHibernate‚̓gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ƒ^ƒCƒ€ƒAƒEƒg‚ðJTA‚ɈϏ÷‚µ‚Ü‚·B
+                ‚±‚Ì‹@”\‚́AHibernate‚Ì <literal>Transaction</literal> ƒIƒuƒWƒFƒNƒg‚É
+                ‚æ‚Á‚Ä’ŠÛ‰»‚³‚ê‚Ä‚¢‚Ü‚·B
+            </para>
+            
+            <programlisting><![CDATA[
+Session sess = factory.openSession();
+try {
+    //set transaction timeout to 3 seconds
+    sess.getTransaction().setTimeout(3);
+    sess.getTransaction().begin();
+
+    // do some work
+    ...
+
+    sess.getTransaction().commit()
+}
+catch (RuntimeException e) {
+    sess.getTransaction().rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+            <para>
+                CMTƒr[ƒ“‚Ì’†‚Å‚Í <literal>setTimeout()</literal> ‚ð
+                ŒÄ‚яo‚¹‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ƒ^ƒCƒ€ƒAƒEƒg‚͐錾“I‚É’è‹`‚³‚ê‚é‚ׂ«‚Å‚·B
+            </para>
+            
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="transactions-optimistic">
+        <title>ŠyŠÏ“I“¯ŽžŽÀs§Œä</title>
+
+        <para>
+            ‚‚¢•À—ñ«‚ƍ‚‚¢ƒXƒP[ƒ‰ƒrƒŠƒeƒB‚Ì—¼•û‚ðŽÀŒ»‚·‚éƒAƒvƒ[ƒ`‚́A
+            ƒo[ƒWƒ‡ƒjƒ“ƒO‚ðŽg‚Á‚½ŠyŠÏ“I“¯ŽžŽÀs§Œä‚Ì‚Ý‚Å‚·B
+            XV‚ÌÕ“Ë‚ðŒ©‚Â‚¯‚邽‚߂Ɂi‚¨‚æ‚сAXV‚ªŽ¸‚í‚ê‚é‚Ì‚ð–h‚®‚½‚߂ɁjA
+            ƒo[ƒWƒ‡ƒ“”ԍ†‚à‚µ‚­‚̓^ƒCƒ€ƒXƒ^ƒ“ƒv‚ðŽg‚Á‚āAƒo[ƒWƒ‡ƒ“‚ðƒ`ƒFƒbƒN‚µ‚Ü‚·B
+            Hibernate‚́AŠyŠÏ“I“¯ŽžŽÀs‚ðs‚¤ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒR[ƒh‚ð‘‚­‚½‚ß‚Ì
+            ƒAƒvƒ[ƒ`‚ð‚R‚Â’ñ‹Ÿ‚µ‚Ü‚·B
+            Ž„‚½‚¿‚ªŒ©‚¹‚郆[ƒXƒP[ƒX‚́A’·‚¢‘Θb‚ðŽ‚¿‚Ü‚·‚ªA
+            ƒo[ƒWƒ‡ƒ“ƒ`ƒFƒbƒN‚Í‚Ü‚¾‚P‚‚̃f[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Ì’†‚ōXV‚ðŽ¸‚¤‚±‚Æ‚ð–h‚®
+            —˜“_‚àŽ‚Á‚Ä‚¢‚Ü‚·B
+        </para>
+
+        <sect2 id="transactions-optimistic-manual">
+            <title>ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚æ‚éƒo[ƒWƒ‡ƒ“ƒ`ƒFƒbƒN</title>
+
+            <para>
+                Hibernate‚É‚Ù‚Æ‚ñ‚Ǐ•‚¯‚Ä‚à‚ç‚킸‚ÉŽÀ‘•‚·‚éƒP[ƒX‚Å‚·B
+                ƒf[ƒ^ƒx[ƒX‚Æ‚Ì‚â‚èŽæ‚è‚́A‚»‚ꂼ‚êV‚µ‚¢ <literal>Session</literal> ‚Ì’†‚Å‹N‚±‚è‚Ü‚·B
+                ŠJ”­ŽÒ‚́A‚·‚ׂẲi‘±«ƒCƒ“ƒXƒ^ƒ“ƒX‚𑀍삷‚é‘O‚ɁA
+                ƒf[ƒ^ƒx[ƒX‚©‚çÄ“ǂݍž‚Ý‚·‚éÓ–±‚ª‚ ‚è‚Ü‚·B
+                ‚±‚̃Aƒvƒ[ƒ`‚ł́A‘Θbƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Ì•ª—£‚ðŽç‚邽‚߂ɁA
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“Ž©g‚ªƒo[ƒWƒ‡ƒ“ƒ`ƒFƒbƒN‚ðs‚¤•K—v‚ª‚ ‚è‚Ü‚·B
+                ‚±‚̃Aƒvƒ[ƒ`‚́Aƒf[ƒ^ƒx[ƒXƒAƒNƒZƒX‚Ì’†‚ł́AÅ‚à”ñŒø—¦‚Å‚·B
+                ƒGƒ“ƒeƒBƒeƒBEJB‚ÆÅ‚àŽ—‚Ä‚¢‚éƒAƒvƒ[ƒ`‚Å‚·B
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+
+int oldVersion = foo.getVersion();
+session.load( foo, foo.getKey() ); // load the current state
+if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();
+foo.setProperty("bar");
+
+t.commit();
+session.close();]]></programlisting>
+
+            <para>
+                <literal>&lt;version&gt;</literal> ‚ðŽg‚Á‚āA<literal>version</literal>
+                ƒvƒƒpƒeƒB‚ðƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+                Hibernate‚́AƒGƒ“ƒeƒBƒeƒB‚ªƒ_[ƒeƒB‚Å‚ ‚éê‡Aƒtƒ‰ƒbƒVƒ…‚µA
+                ‚»‚ÌŠÔ‚É <literal>version</literal> ƒvƒƒpƒeƒB‚ðŽ©“®“I‚ɃCƒ“ƒNƒŠƒƒ“ƒg‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                ‚à‚¿‚ë‚ñAƒf[ƒ^‚Ì•À—ñ«‚ª’á‚¢ŠÂ‹«‚ʼn^—p‚µ‚Ä‚¨‚èAƒo[ƒWƒ‡ƒ“ƒ`ƒFƒbƒN‚ª•s—v‚È‚çA
+                ‚±‚̃Aƒvƒ[ƒ`‚ðŽg‚¢Aƒo[ƒWƒ‡ƒ“ƒ`ƒFƒbƒN‚ðƒXƒLƒbƒv‚·‚邾‚¯‚Å‚·B
+                ‚»‚̏ꍇ‚́A’·‚¢‘Θb‚ɂ́A
+                <emphasis>uÅŒã‚ɃRƒ~ƒbƒg‚µ‚½‚à‚Ì‚ªŸ‚v</emphasis> ‚ªƒfƒtƒHƒ‹ƒg‚̐헪‚Å‚µ‚傤B
+                ‚±‚̃Aƒvƒ[ƒ`‚́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̃†[ƒU[‚ð¬—‚³‚¹‚é‚©‚à‚µ‚ê‚È‚¢‚±‚Æ‚ð
+                S‚É—¯‚ß‚Ä’u‚¢‚Ä‚­‚¾‚³‚¢B‚»‚ê‚́AƒGƒ‰[ƒƒbƒZ[ƒW‚â‹£‡‚µ‚½•ÏX‚ðƒ}[ƒW‚·‚é‹@‰ï‚ª
+                ‚È‚¢‚܂܁AXV‚ðŽ¸‚¤ŒoŒ±‚ð‚·‚é‚½‚ß‚Å‚·B
+            </para>
+
+            <para>
+                Šm‚©‚ɁAƒ}ƒjƒ…ƒAƒ‹‚É‚æ‚éƒo[ƒWƒ‡ƒ“ƒ`ƒFƒbƒN‚́A±×‚È‹VŽ®‚¾‚¯‚ÅŽÀs‚Å‚«‚Ü‚·‚ªA
+                ‘½‚­‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚Æ‚Á‚ÄŽÀ—p“I‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+                ‚µ‚΂µ‚΁A‚P‚‚̃Cƒ“ƒXƒ^ƒ“ƒX‚¾‚¯‚Å‚È‚­A
+                C³‚³‚ꂽƒIƒuƒWƒFƒNƒg‚ÌŠ®‘S‚ȃOƒ‰ƒt‚ðƒ`ƒFƒbƒN‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                Hibernate‚́AÝŒvƒpƒ‰ƒ_ƒCƒ€‚Æ‚µ‚āAŠg’£ <literal>Session</literal> ‚©
+                •ª—£‚³‚ꂽƒCƒ“ƒXƒ^ƒ“ƒX‚ðŽ©“®“I‚Ƀo[ƒWƒ‡ƒ“ƒ`ƒFƒbƒN‚µ‚Ü‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-longsession">
+            <title>Šg’£ƒZƒbƒVƒ‡ƒ“‚ÆŽ©“®ƒo[ƒWƒ‡ƒjƒ“ƒO</title>
+
+            <para>
+                ‚P‚Â‚Ì <literal>Session</literal> ƒCƒ“ƒXƒ^ƒ“ƒX‚Æ‚»‚̉i‘±«ƒCƒ“ƒXƒ^ƒ“ƒX‚́A
+                <emphasis>session-per-conversation</emphasis> ‚Æ‚µ‚Ä’m‚ç‚ê‚éA
+                ‘Θb‘S‘Ì‚ÅŽg‚í‚ê‚Ü‚·B
+                Hibernate‚̓tƒ‰ƒbƒVƒ…‚·‚éÛ‚ɁAƒCƒ“ƒXƒ^ƒ“ƒX‚̃o[ƒWƒ‡ƒ“‚ðƒ`ƒFƒbƒN‚µ‚Ü‚·B
+                “¯Žž‚ɏC³‚³‚ꂽ‚±‚Æ‚ðŒŸo‚·‚é‚ƁA—áŠO‚ð“Š‚°‚Ü‚·B
+                ‚±‚Ì—áŠO‚ðƒLƒƒƒbƒ`‚µ‚Ĉµ‚¤‚̂́AŠJ”­ŽÒ‚̐ӔC‚Å‚·
+                iˆê”Ê“I‚È‘I‘ðŽˆ‚ÍA•ÏX‚ðƒ}[ƒW‚·‚é‚©ŒÃ‚­‚È‚¢ƒf[ƒ^‚ŃrƒWƒlƒX‘Θb‚ð
+                ÄƒXƒ^[ƒg‚·‚é‹@‰ï‚ðƒ†[ƒU[‚É’ñ‹Ÿ‚·‚邱‚Æ‚Å‚·jB
+            </para>
+
+            <para>
+                ƒ†[ƒU[‚̑Θb‚ð‘Ò‚Á‚Ä‚¢‚é‚Æ‚«‚́A
+                <literal>Session</literal> ‚ðŠî‘b‚Æ‚È‚éJDBCƒRƒlƒNƒVƒ‡ƒ“‚©‚çØ‚è—£‚µ‚Ü‚·B
+                ‚±‚̃Aƒvƒ[ƒ`‚́Aƒf[ƒ^ƒx[ƒXƒAƒNƒZƒX‚Ì’†‚ł́AÅ‚àŒø—¦“I‚Å‚·B
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚́Aƒo[ƒWƒ‡ƒ“ƒ`ƒFƒbƒN‚╪—£‚³‚ꂽƒCƒ“ƒXƒ^ƒ“ƒX‚ðÄ’ljÁ‚·‚邱‚Æ
+                ‚Ɋ֐S‚ðŽ‚Â•K—v‚Í‚ ‚è‚Ü‚¹‚ñB‚Ü‚½A‚ ‚ç‚ä‚éƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Ì’†‚Å
+                ƒCƒ“ƒXƒ^ƒ“ƒX‚ðÄ“ǂݍž‚Ý‚·‚é•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded earlier by the old session
+Transaction t = session.beginTransaction(); // Obtain a new JDBC connection, start transaction
+
+foo.setProperty("bar");
+
+session.flush();    // Only for last transaction in conversation
+t.commit();         // Also return JDBC connection
+session.close();    // Only for last transaction in conversation]]></programlisting>
+
+            <para>
+                <literal>foo</literal> ƒIƒuƒWƒFƒNƒg‚́AŽ©•ª‚ðƒ[ƒh‚µ‚½ <literal>Session</literal>
+                ‚ð‚Ü‚¾’m‚Á‚Ä‚¢‚Ü‚·B
+                ŒÃ‚¢ƒZƒbƒVƒ‡ƒ“‚̏ã‚ŐV‚µ‚¢ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðŠJŽn‚·‚邱‚ƂŁA
+                V‚µ‚¢ƒRƒlƒNƒVƒ‡ƒ“‚ðŽæ“¾‚µA‚»‚̃ZƒbƒVƒ‡ƒ“‚ªÄŠJ‚³‚ê‚Ü‚·B
+                ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðƒRƒ~ƒbƒg‚·‚邱‚ƂŁA
+                ƒZƒbƒVƒ‡ƒ“‚©‚çJDBCƒRƒlƒNƒVƒ‡ƒ“‚ðØ’f‚µAƒRƒlƒNƒVƒ‡ƒ“‚ðƒv[ƒ‹‚É•Ô‚µ‚Ü‚·B
+                ÄÚ‘±‚µ‚½ŒãAXV‚µ‚Ä‚¢‚È‚¢ƒf[ƒ^‚̃o[ƒWƒ‡ƒ“ƒ`ƒFƒbƒN‚ð‹­§‚·‚邽‚߂ɁA
+                ‘¼‚̃gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚É‚æ‚èXV‚³‚ê‚Ä‚¢‚é‚©‚à‚µ‚ê‚È‚¢ƒIƒuƒWƒFƒNƒg‚ÉŠÖ‚µ‚āA
+                <literal>LockMode.READ</literal> ‚ð‚‚¯‚Ä <literal>Session.lock()</literal>
+                ‚ðŒÄ‚яo‚·‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+                XV‚µ‚Ä <emphasis>‚¢‚é</emphasis> ƒf[ƒ^‚ðƒƒbƒN‚·‚é•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+                
+                ’ʏíAŠg’£ <literal>Session</literal> ‚É <literal>FlushMode.NEVER</literal>
+                ‚ðƒZƒbƒg‚µ‚Ü‚·B
+                ÅŒã‚̃f[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÌŽüŠú‚ł̂݁A
+                ‘Θb‚Ì’†‚ŕύX‚³‚ꂽ‚·‚ׂĂðŽÀÛ‚ɉi‘±‰»‚³‚¹‚邽‚ß‚Å‚·B
+                ‚䂦‚ɁAÅŒã‚̃f[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚Ì‚Ý <literal>flush()</literal>
+                ƒIƒyƒŒ[ƒVƒ‡ƒ“‚ðŠÜ‚Ý‚Ü‚·B‚»‚µ‚āA‘Θb‚ðI‚í‚点‚邽‚߂ɁA
+                ƒZƒbƒVƒ‡ƒ“‚à <literal>close()</literal> ‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                ƒ†[ƒU[‚ªl—¶’†‚ɁAŠi”[‚·‚邱‚Æ‚ª‚Å‚«‚È‚¢‚­‚ç‚¢ <literal>Session</literal>
+                ‚ª‘å‚«‚¢‚Ì‚Å‚ ‚ê‚΁A‚±‚̃pƒ^[ƒ“‚Í–â‘肪‚ ‚è‚Ü‚·B
+                —Ⴆ‚΁A<literal>HttpSession</literal> ‚͉”\‚ÈŒÀ‚菬‚³‚­•Û‚‚ׂ«‚Å‚·B
+                <literal>Session</literal> ‚́i‹­§“I‚Ɂj‚PŽŸƒLƒƒƒbƒVƒ…‚Å‚à‚ ‚èA
+                ƒ[ƒh‚µ‚½ƒIƒuƒWƒFƒNƒg‚ð‚·‚×‚Ä•ÛŽ‚µ‚Ü‚·B
+                ‚¨‚»‚ç‚­AƒŠƒNƒGƒXƒg^ƒŒƒXƒ|ƒ“ƒX‚̃TƒCƒNƒ‹‚ª”‰ñ‚Å‚ ‚ê‚΁A‚±‚̐헪‚ªŽg‚¦‚Ü‚·B
+                
+                ‚P‚‚̑Θb‚Ì‚½‚ß‚¾‚¯‚É <literal>Session</literal> ‚ðŽg‚¤‚ׂ«‚Å‚·B
+                ‚È‚º‚È‚çA‚·‚®‚ɐV‘N‚Å‚È‚¢ƒf[ƒ^‚ðŽ‚Â‚½‚ß‚Å‚·B
+            </para>
+
+            <para>
+                iHibernate‚̈ȑO‚̃o[ƒWƒ‡ƒ“‚́A–¾Ž¦“I‚È <literal>Session</literal> ‚Ì
+                Ø’f‚ƍĐڑ±‚ª•K—v‚¾‚Á‚½‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚±‚ê‚ç‚̃ƒ\ƒbƒh‚Í”ñ„§‚É‚È‚è‚Ü‚µ‚½B
+                ‚È‚º‚È‚çAƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ÌŠJŽn‚ƏI—¹‚Í“¯‚¶Œø‰Ê‚ª‚ ‚邽‚ß‚Å‚·Bj
+            </para>
+
+            <para>
+                Ø’f‚µ‚½ <literal>Session</literal> ‚ð‰i‘±‰»‘w‚Ì‹ß‚­‚Å•ÛŽ‚·‚ׂ«‚Å‚ ‚邱‚Æ‚É
+                ’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                Œ¾‚¢Š·‚¦‚é‚ƁA‚R‘wŠÂ‹«‚Ì’†‚Å <literal>Session</literal> ‚ð•ÛŽ‚·‚邽‚߂ɁA
+                EJBƒXƒe[ƒgƒtƒ‹ƒZƒbƒVƒ‡ƒ“Bean‚ðŽg‚Á‚Ä‚­‚¾‚³‚¢B
+                <literal>HttpSession</literal> ‚ÉŠi”[‚·‚邽‚߂ɁAWeb‘w‚É“]‘—‚µ‚È‚¢‚Å‚­‚¾‚³‚¢
+                i•Ê‚Ì‘w‚ւ̃VƒŠƒAƒ‰ƒCƒY‚à‚µ‚È‚¢‚Å‚­‚¾‚³‚¢jB
+            </para>
+
+            <para>
+                Šg’£ƒZƒbƒVƒ‡ƒ“ƒpƒ^[ƒ“i‚à‚µ‚­‚́A<emphasis>session-per-conversation</emphasis>j‚́A
+                Ž©“®“I‚ȃJƒŒƒ“ƒgƒZƒbƒVƒ‡ƒ“ƒRƒ“ƒeƒLƒXƒgŠÇ—‚ðŽÀŽ{‚·‚é‚æ‚è“‚¢B
+                ‚±‚Ì‚½‚߂ɁA‚ ‚È‚½‚Í <literal>CurrentSessionContext</literal> ‚ÌŽÀ‘•‚ð‹Ÿ‹‹‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+                Hibernate Wiki‚É‚ ‚é—á‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-detached">
+            <title>ƒfƒ^ƒbƒ`‚³‚ꂽƒIƒuƒWƒFƒNƒg‚ÆŽ©“®ƒo[ƒWƒ‡ƒjƒ“ƒO</title>
+
+            <para>
+                V‚µ‚¢ <literal>Session</literal>‚É‚æ‚èA‰i‘±‰»ƒXƒgƒAi–󒍁F‚c‚aj‚Ƃ̑Θb‚ª”­¶‚µ‚Ü‚·B
+                ‚Ü‚½ˆê•ûA“¯‚¶‰i‘±«ƒCƒ“ƒXƒ^ƒ“ƒX‚ªAƒf[ƒ^ƒx[ƒX‚Ƃ̑Θb‚²‚Ƃɍė˜—p‚³‚ê‚Ü‚·B
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚́AŒ³X‚Í‘¼‚Ì <literal>Session</literal> ‚э[ƒh‚³‚êA
+                ƒfƒ^ƒbƒ`‚³‚ꂽƒCƒ“ƒXƒ^ƒ“ƒX‚̏ó‘Ԃ𑀍삵‚Ü‚·B
+                ‚»‚µ‚āA<literal>Session.update()</literal> ‚à‚µ‚­‚́A<literal>Session.saveOrUpdate()</literal>A
+                <literal>Session.merge()</literal> ‚ðŽg‚Á‚āA‚»‚ê‚ç‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ðÄ’ljÁ‚µ‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+foo.setProperty("bar");
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded already
+t.commit();
+session.close();]]></programlisting>
+
+            <para>
+                ‚±‚̏ꍇ‚à‚â‚Í‚èAHibernate‚̓tƒ‰ƒbƒVƒ…‚·‚éÛ‚ɁAƒCƒ“ƒXƒ^ƒ“ƒX‚̃o[ƒWƒ‡ƒ“‚ðƒ`ƒFƒbƒN‚µ‚Ü‚·B
+                XV‚Ì‹£‡‚ª”­¶‚µ‚½ê‡‚ɂ́A—áŠO‚ð“Š‚°‚Ü‚·B
+            </para>
+
+            <para>
+                ƒIƒuƒWƒFƒNƒg‚ªC³‚³‚ê‚Ä‚¢‚È‚¢‚±‚Æ‚ðŠmM‚µ‚Ä‚¢‚éê‡‚́A
+                <literal>update()</literal> ‚Ì‘ã‚í‚è‚ɁA<literal>LockMode.READ</literal> ‚ðŽg‚Á‚āA
+                <literal>lock()</literal> ‚ðŒÄ‚яo‚·‚±‚Æ‚à‚Å‚«‚Ü‚·
+                i‚·‚ׂẴLƒƒƒbƒVƒ…‚ð‰I‰ñ‚µAƒo[ƒWƒ‡ƒ“ƒ`ƒFƒbƒN‚ðŽÀŽ{‚µ‚Ü‚·jB
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-customizing">
+            <title>Ž©“®ƒo[ƒWƒ‡ƒjƒ“ƒO‚̃JƒXƒ^ƒ}ƒCƒY</title>
+
+            <para>
+                ƒ}ƒbƒsƒ“ƒO‚Ì <literal>optimistic-lock</literal> ‘®«‚É <literal>false</literal>
+                ‚ðÝ’è‚·‚邱‚Æ‚É‚æ‚èA“Á’è‚̃vƒƒpƒeƒB‚âƒRƒŒƒNƒVƒ‡ƒ“‚Ì‚½‚ß‚É
+                Ž©“®ƒo[ƒWƒ‡ƒ“ƒCƒ“ƒNƒŠƒƒ“ƒg‚𖳌ø‚É‚Å‚«‚Ü‚·B
+                ƒvƒƒpƒeƒB‚ªƒ_[ƒeƒB‚Å‚ ‚Á‚Ä‚àAƒo[ƒWƒ‡ƒ“‚ðƒCƒ“ƒNƒŠƒƒ“ƒg‚µ‚Ü‚¹‚ñB
+            </para>
+
+            <para>
+                ƒŒƒKƒV[‚̃f[ƒ^ƒx[ƒXƒXƒL[ƒ}‚́A‚µ‚΂µ‚ΌŒè“I‚Å‚ ‚èA•ÏX‚Å‚«‚Ü‚¹‚ñB
+                ‚Ü‚½‚́A‘¼‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚ª“¯‚¶ƒf[ƒ^ƒx[ƒX‚ɃAƒNƒZƒX‚µ‚È‚¯‚ê‚΂Ȃ炸A
+                ‚»‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚̓o[ƒWƒ‡ƒ“”ԍ†‚âƒ^ƒCƒ€ƒXƒ^ƒ“ƒv‚³‚¦‘€ì‚·‚é•û–@‚ð’m‚è‚Ü‚¹‚ñB
+                ‚Ç‚¿‚ç‚̏ꍇ‚àAƒe[ƒuƒ‹‚Ì“Á’è‚̃Jƒ‰ƒ€‚ð“–‚Ä‚É‚µ‚āAƒo[ƒWƒ‡ƒjƒ“ƒO‚ðs‚¦‚Ü‚¹‚ñB
+                ƒo[ƒWƒ‡ƒ“‚âƒ^ƒCƒ€ƒXƒ^ƒ“ƒv‚̃vƒƒpƒeƒB‚ðƒ}ƒbƒsƒ“ƒO‚¹‚¸‚ɁAƒo[ƒWƒ‡ƒ“ƒ`ƒFƒbƒN‚³‚¹‚邽‚߂ɁA
+                <literal>&lt;class&gt;</literal> ƒ}ƒbƒsƒ“ƒO‚É <literal>optimistic-lock="all"</literal> ‚ð
+                Žw’肵‚Ä‚­‚¾‚³‚¢B
+                s‚Ì‚·‚ׂẴtƒB[ƒ‹ƒh‚̏ó‘Ô‚ð”äŠr‚·‚é‚悤‚É‚È‚è‚Ü‚·B
+                ‚±‚ê‚́AHibernate‚ªŒÃ‚¢ó‘ԂƐV‚µ‚¢ó‘Ô‚ð”äŠr‚Å‚«‚éê‡‚ɁA
+                —˜_“I‚É“®ì‚·‚邾‚¯‚Å‚ ‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                —Ⴆ‚΁Asession-per-request-with-detached-objects ‚Å‚Í‚È‚­A
+                ‚P‚‚̒·‚¢ <literal>Session</literal> ‚ðŽg‚¤ê‡‚Å‚·B
+            </para>
+
+            <para>
+                ‚Æ‚«‚Ç‚«As‚í‚ꂽ•ÏX‚ªd‚È‚ç‚È‚¢ŒÀ‚èA“¯Žž‚ɍs‚í‚ꂽ•ÏX‚ðŽó‚¯“ü‚ê‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+                <literal>&lt;class&gt;</literal> ƒ}ƒbƒsƒ“ƒO‚É <literal>optimistic-lock="dirty"</literal>
+                ‚ðÝ’肵‚½ê‡Aƒtƒ‰ƒbƒVƒ…‚·‚éÛ‚ɁAHibernate‚̓_[ƒeƒBƒtƒB[ƒ‹ƒh‚Ì‚Ý‚ð”äŠr‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                ê—p‚̃o[ƒWƒ‡ƒ“^ƒ^ƒCƒ€ƒXƒ^ƒ“ƒv‚̃Jƒ‰ƒ€‚ðŽg‚¤ê‡A
+                ‚à‚µ‚­‚Í‚·‚ׂā^ƒ_[ƒeƒB‚̃tƒB[ƒ‹ƒh‚ð”äŠr‚·‚éê‡‚Ç‚¿‚ç‚Å‚ ‚Á‚Ä‚àA
+                Hibernate‚̓Gƒ“ƒeƒBƒeƒB‚²‚Æ‚É1‚Â‚Ì <literal>UPDATE</literal> •¶‚ð
+                i“KØ‚È <literal>WHERE</literal> ß‚Æ‹¤‚ɁjŽg‚¢A
+                ƒo[ƒWƒ‡ƒ“ƒ`ƒFƒbƒN‚Əî•ñ‚̍XV‚ðs‚¢‚Ü‚·B
+                ŠÖ˜A‚·‚éƒGƒ“ƒeƒBƒeƒB‚̍ĒljÁ‚ðƒJƒXƒP[ƒh‚·‚邽‚߂ɁA
+                ˜A½“I‚ȉi‘±‰»‚ðŽg—p‚µ‚½ê‡A•s•K—v‚ȍXV‚ðŽÀs‚·‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                ‚±‚ê‚͒ʏí–â‘è‚É‚È‚è‚Ü‚¹‚ñB
+                ‚µ‚©‚µA•ª—£‚µ‚½ƒCƒ“ƒXƒ^ƒ“ƒX‚ð•ÏX‚µ‚Ä‚¢‚È‚­‚Æ‚àA
+                ƒf[ƒ^ƒx[ƒX‚Ì <emphasis>on update</emphasis> ƒgƒŠƒK[‚ªŽÀs‚³‚ê‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                <literal>&lt;class&gt;</literal> ƒ}ƒbƒsƒ“ƒO‚É
+                <literal>select-before-update="true"</literal> ‚ðÝ’è‚·‚邱‚Æ‚É‚æ‚Á‚āA
+                ‚±‚̐U‚é•‘‚¢‚ðƒJƒXƒ^ƒ}ƒCƒY‚Å‚«‚Ü‚·B
+                ŠmŽÀ‚ɕύX‚³‚ꂽ‚©‚ðŠm”F‚·‚邽‚߂ɁAs‚ðXV‚·‚é‘O‚ɁA
+                •K‚¸ƒCƒ“ƒXƒ^ƒ“ƒX‚ð <literal>SELECT</literal> ‚µ‚Ü‚·B
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="transactions-locking">
+        <title>”ߊϓIƒƒbƒN</title>
+
+        <para>
+            ƒ†[ƒU‚ªƒƒbƒNí—ª‚É”Y‚Þ‚Ì‚É‘½‚­‚ÌŽžŠÔ‚ð”ï‚â‚·‚±‚Æ‚ðˆÓ}‚µ‚Ä‚¢‚Ü‚¹‚ñB
+            ’ʏí‚́AJDBCƒRƒlƒNƒVƒ‡ƒ“‚É•ª—£ƒŒƒxƒ‹‚ðŽw’肵A
+            ’P‚Ƀf[ƒ^ƒx[ƒX‚É‚·‚ׂĂ̎dŽ–‚ð‚³‚¹‚ê‚Ώ\•ª‚Å‚·B
+            ‚µ‚©‚µ‚È‚ª‚çA‚“x‚ȃ†[ƒU‚́A”r‘¼“I‚ȔߊϓIƒƒbƒN‚ðŠl“¾‚·‚邱‚Æ‚©A
+            V‚µ‚¢ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ªŠJŽn‚³‚ê‚éÛ‚ɃƒbƒN‚ðÄŠl“¾‚·‚邱‚Æ‚ð
+            ‚Æ‚«‚Ç‚«–]‚Þ‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+        </para>
+
+        <para>
+            Hibernate‚Í‚¢‚‚àƒf[ƒ^ƒx[ƒX‚̃ƒbƒN‚ÌŽd‘g‚Ý‚ðŽg‚¢‚Ü‚·B
+            ƒƒ‚ƒŠ“à‚̃IƒuƒWƒFƒNƒg‚ðŒˆ‚µ‚ăƒbƒN‚µ‚Ü‚¹‚ñI
+        </para>
+
+        <para>
+            <literal>LockMode</literal> ƒNƒ‰ƒX‚́AHibernate‚ªŠl“¾‚Å‚«‚éˆÙ‚Ȃ郍ƒbƒNƒŒƒxƒ‹‚ð’è‹`‚µ‚Ü‚·B
+            ˆÈ‰º‚ÌŽd‘g‚Ý‚É‚æ‚èAƒƒbƒN‚ðŠl“¾‚Å‚«‚Ü‚·B
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>LockMode.WRITE</literal> ‚́A
+                    Hibernate‚ªs‚ðXV‚à‚µ‚­‚Í‘}“ü‚·‚éÛ‚ÉŽ©“®“I‚É“¾‚ç‚ê‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.UPGRADE</literal> ‚́A
+                    ƒf[ƒ^ƒx[ƒX‚ŃTƒ|[ƒg‚³‚ê‚Ä‚¢‚镶–@ <literal>SELECT ... FOR UPDATE</literal>
+                    ‚ðŽg‚Á‚½A–¾Ž¦“I‚ȃ†[ƒU[—v‹‚É‚æ‚蓾‚ç‚ê‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.UPGRADE_NOWAIT</literal> ‚́A
+                    Oracle ‚Å <literal>SELECT ... FOR UPDATE NOWAIT</literal> ‚ðŽg‚Á‚½A
+                    –¾Ž¦“I‚ȃ†[ƒU[—v‹‚É‚æ‚蓾‚ç‚ê‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.READ</literal> ‚́A
+                    Repeatable Read‚à‚µ‚­‚ÍSerializable‚Ì•ª—£ƒŒƒxƒ‹‚ŁAƒf[ƒ^‚ð“Ç‚ñ‚¾Û‚ÉŽ©“®“I‚É“¾‚ç‚ê‚Ü‚·B
+                    ‚¨‚»‚ç‚­A–¾Ž¦“I‚ȃ†[ƒU[—v‹‚É‚æ‚èAÄŽæ“¾‚³‚ê‚Ü‚·B
+                </para>
+            </listitem>
+        <listitem>
+        <para>
+            <literal>LockMode.NONE</literal> ‚́AƒƒbƒN‚µ‚È‚¢‚±‚Æ‚ð•\‚µ‚Ü‚·B
+            <literal>Transaction</literal> ‚̏I‚í‚è‚ɁA
+            ‚·‚ׂẴIƒuƒWƒFƒNƒg‚Í‚±‚̃ƒbƒNƒ‚[ƒh‚ɐ؂è‘Ö‚í‚è‚Ü‚·B
+            <literal>update()</literal> ‚â <literal>saveOrUpdate()</literal> ‚ðŒÄ‚яo‚·‚±‚Æ‚É‚æ‚Á‚āA
+            ƒZƒbƒVƒ‡ƒ“‚ÉŠÖ˜A•t‚¯‚ç‚ꂽƒIƒuƒWƒFƒNƒg‚àA‚±‚̃ƒbƒNƒ‚[ƒh‚ŏo”­‚µ‚Ü‚·B
+        </para>
+        </listitem>
+        </itemizedlist>
+
+        <para>
+            u–¾Ž¦“I‚ȃ†[ƒU[—v‹v‚Ƃ́A‰º‹L‚Ì•û–@‚Ì‚P‚‚Ō¾‚¢•\‚¹‚Ü‚·B
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>LockMode</literal> ‚ðŽw’肵‚½ <literal>Session.load()</literal> ‚̌Ăяo‚µB
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>Session.lock()</literal> ‚̌Ăяo‚µB
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>Query.setLockMode()</literal> ‚̌Ăяo‚µB
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>UPGRADE</literal> ‚à‚µ‚­‚Í <literal>UPGRADE_NOWAIT</literal> ‚ªŽw’肳‚ꂽ
+            <literal>Session.load()</literal> ‚ªŒÄ‚яo‚³‚êA
+            ‚©‚—v‹‚³‚ꂽƒIƒuƒWƒFƒNƒg‚ªƒZƒbƒVƒ‡ƒ“‚É‚æ‚Á‚Ä‚Ü‚¾ƒ[ƒh‚³‚ê‚Ä‚¢‚È‚©‚Á‚½ê‡‚́A
+            <literal>SELECT ... FOR UPDATE</literal> ‚ðŽg‚Á‚āAƒIƒuƒWƒFƒNƒg‚ªƒ[ƒh‚³‚ê‚Ü‚·B
+            <literal>load()</literal> ‚ŌĂяo‚³‚ꂽƒIƒuƒWƒFƒNƒg‚ªA
+            —v‹‚³‚ê‚Ä‚¢‚é‚æ‚萧ŒÀ‚ª­‚È‚¢ƒƒbƒN‚Å‚·‚łɃ[ƒh‚³‚ê‚Ä‚¢‚½ê‡‚́A
+            Hibernate‚Í‚»‚̃IƒuƒWƒFƒNƒg‚Ì‚½‚߂ɁA<literal>lock()</literal> ‚ðŒÄ‚яo‚µ‚Ü‚·B
+        </para>
+
+        <para>
+            Žw’肳‚ꂽƒƒbƒNƒ‚[ƒh‚ª <literal>READ</literal> ‚à‚µ‚­‚́A<literal>UPGRADE</literal>A
+            <literal>UPGRADE_NOWAIT</literal> ‚¾‚Á‚½ê‡A<literal>Session.lock()</literal>
+            ‚́Aƒo[ƒWƒ‡ƒ“”ԍ†‚̃`ƒFƒbƒN‚ðŽÀŽ{‚µ‚Ü‚·B
+            i<literal>UPGRADE</literal> ‚à‚µ‚­‚Í <literal>UPGRADE_NOWAIT</literal> ‚̏ꍇA
+            <literal>SELECT ... FOR UPDATE</literal> ‚ªŽg‚í‚ê‚Ü‚·Bj
+        </para>
+
+        <para>
+            ƒf[ƒ^ƒx[ƒX‚ª—v‹‚³‚ꂽƒƒbƒNƒ‚[ƒh‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚È‚¢ê‡A
+            Hibernate‚́i—áŠO‚ð“Š‚°‚é‘ã‚í‚è‚ɁAj“KØ‚È‘ã‚í‚è‚̃‚[ƒh‚ðŽg‚¢‚Ü‚·B
+            ‚±‚ê‚́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ªƒ|[ƒ^ƒuƒ‹‚Å‚ ‚邱‚Æ‚ð•ÛØ‚µ‚Ü‚·B
+        </para>
+
+    </sect1>
+
+    <sect1 id="transactions-connection-release">
+        <title>ƒRƒlƒNƒVƒ‡ƒ“ŠJ•úƒ‚[ƒh</title>
+
+        <para>
+            Hibernate‚̃ŒƒKƒV[i2.xj‚ÌJDBCƒRƒlƒNƒVƒ‡ƒ“ŠÇ—‚ÉŠÖ‚·‚éU‚é•‘‚¢‚́A
+            Å‰‚É•K—v‚Æ‚µ‚½Û‚É <literal>Session</literal> ‚ªƒRƒlƒNƒVƒ‡ƒ“‚𓾂é‚Æ‚¢‚¤‚à‚Ì‚Å‚µ‚½B
+            ‚»‚µ‚āAƒZƒbƒVƒ‡ƒ“‚ª•Â‚¶‚ç‚ê‚é‚܂ŁA‚»‚̃RƒlƒNƒVƒ‡ƒ“‚ð•ÛŽ‚µ‚Ü‚µ‚½B
+            Hibernate 3.x‚́AƒZƒbƒVƒ‡ƒ“‚ÉJDBCƒRƒlƒNƒVƒ‡ƒ“‚ð‚ǂ̂悤‚ɐ§Œä‚·‚é‚©‚ð“`‚¦‚é
+            ƒRƒlƒNƒVƒ‡ƒ“ŠJ•úƒ‚[ƒh‚Æ‚¢‚¤ŠT”O‚𓱓ü‚µ‚Ü‚µ‚½B
+            ˆÈ~‚Ì‹c˜_‚́A\¬‚³‚ꂽ <literal>ConnectionProvider</literal> ‚ð’Ê‚µ‚Ä’ñ‹Ÿ‚³‚ê‚é
+            ƒRƒlƒNƒVƒ‡ƒ“‚É“KØ‚Å‚ ‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            ˆÙ‚È‚éŠJ•úƒ‚[ƒh‚́A<literal>org.hibernate.ConnectionReleaseMode</literal> ‚É
+            —ñ‹“‚³‚ꂽ’l‚É‚æ‚èŠm”F‚³‚ê‚Ü‚·B
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>ON_CLOSE</literal> - –{Ž¿“I‚ɏã‹L‚ŏq‚ׂ½ƒŒƒKƒV[‚̐U‚é•‘‚¢‚Å‚·B
+                    HibernateƒZƒbƒVƒ‡ƒ“‚͍ŏ‰‚ÉJDBCƒAƒNƒZƒX‚ðŽÀs‚·‚é•K—v‚ª‚ ‚éÛ‚ɃRƒlƒNƒVƒ‡ƒ“‚𓾂܂·B
+                    ‚»‚µ‚āAƒZƒbƒVƒ‡ƒ“‚ª•Â‚¶‚ç‚ê‚é‚܂ŁAƒRƒlƒNƒVƒ‡ƒ“‚ð•ÛŽ‚µ‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>AFTER_TRANSACTION</literal> - 
+                    <literal>org.hibernate.Transaction</literal> ‚ªŠ®—¹‚µ‚½ŒãA
+                    ƒRƒlƒNƒVƒ‡ƒ“‚ðŠJ•ú‚µ‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>AFTER_STATEMENT</literal> iÏ‹É“I‚ÈŠJ•ú‚Æ‚àŒÄ‚΂ê‚éj -
+                    ‚·‚ׂẴXƒe[ƒgƒƒ“ƒg‚ª‚»‚ꂼ‚êŽÀs‚³‚ꂽŒãAƒRƒlƒNƒVƒ‡ƒ“‚ªŠJ•ú‚³‚ê‚Ü‚·B
+                    ƒXƒe[ƒgƒƒ“ƒg‚ªƒZƒbƒVƒ‡ƒ“‚ÉŠÖ˜A‚·‚郊ƒ\[ƒX‚ðŠJ‚¢‚½‚Ü‚Ü‚É‚·‚éê‡‚́A
+                    ‚±‚̐ϋɓI‚ÈŠJ•ú‚̓XƒLƒbƒv‚³‚ê‚Ü‚·B
+                    ¡‚Ì‚Æ‚±‚ëA‚±‚ꂪ‹N‚±‚é‚Ì‚Í <literal>org.hibernate.ScrollableResults</literal>
+                    ‚ªŽg‚í‚ê‚éê‡‚Ì‚Ý‚Å‚·B
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            ƒRƒ“ƒtƒBƒOƒŒ[ƒVƒ‡ƒ“ƒpƒ‰ƒ[ƒ^‚Ì <literal>hibernate.connection.release_mode</literal>
+            ‚́AŽg—p‚·‚éŠJ•úƒ‚[ƒh‚ðŽw’è‚·‚邽‚ß‚ÉŽg‚¢‚Ü‚·B
+            Žw’è‚Å‚«‚é’l‚ÍŽŸ‚Ì’Ê‚è‚Å‚·B
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>auto</literal> iƒfƒtƒHƒ‹ƒgj - ‚±‚ê‚ð‘I‘ð‚·‚é‚Æ
+                    <literal>org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode()</literal>
+                    ƒƒ\ƒbƒh‚É‚æ‚Á‚Ä•Ô‚³‚ê‚éŠJ•úƒ‚[ƒh‚ɈϏ÷‚³‚ê‚Ü‚·B
+                    ‚±‚̃ƒ\ƒbƒh‚́A
+                    JTATransactionFactory‚É‚ÍConnectionReleaseMode.AFTER_STATEMENT‚ð•Ô‚µA
+                    JDBCTransactionFactory‚É‚ÍConnectionReleaseMode.AFTER_TRANSACTION‚ð•Ô‚µ‚Ü‚·B
+                    ‚±‚̃fƒtƒHƒ‹ƒg‚̐U‚é•‘‚¢‚ð•Ï‚¦‚Ä‚¤‚Ü‚­‚¢‚Á‚½ŽŽ‚µ‚ª‚ ‚è‚Ü‚¹‚ñB
+                    ‚»‚ê‚́A‚±‚̐ݒè’l‚ªŒ´ˆö‚Å‹N‚±‚éáŠQ‚́A
+                    ƒ†[ƒUƒR[ƒh‚Ì’†‚ŃoƒO‚âŠÔˆá‚Á‚½ðŒ‚É‚È‚è‚â‚·‚¢‚©‚ç‚Å‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>on_close</literal> - ConnectionReleaseMode.ON_CLOSE‚ðŽg‚¢‚Ü‚·B
+                    ‚±‚̐ݒè‚ÍŒã•ûŒÝŠ·‚Ì‚½‚ß‚ÉŽc‚³‚ê‚Ä‚¢‚Ü‚·‚ªAŽg‚í‚È‚¢‚±‚Æ‚ð‹­‚­Š©‚ß‚Ü‚·B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>after_transaction</literal> - ConnectionReleaseMode.AFTER_TRANSACTION‚ðŽg‚¢‚Ü‚·B
+                    ‚±‚̐ݒè‚ÍJTAŠÂ‹«‚Ì’†‚Å‚ÍŽg‚¤‚ׂ«‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+                    ConnectionReleaseMode.AFTER_TRANSACTION‚ðŽw’肵AŽ©“®ƒRƒ~ƒbƒgƒ‚[ƒh‚Ì’†‚ł́A
+                    ŠJ•úƒ‚[ƒh‚ªAFTER_STATEMENT‚Å‚ ‚é‚©‚̂悤‚ɁAƒRƒlƒNƒVƒ‡ƒ“‚ÍŠJ•ú‚³‚ê‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>after_statement</literal> - ConnectionReleaseMode.AFTER_STATEMENT‚ðŽg‚¢‚Ü‚·B
+                    ‚³‚ç‚ɁAÝ’肳‚ꂽ <literal>ConnectionProvider</literal> ‚́A
+                    ‚±‚̐ݒè (<literal>supportsAggressiveRelease()</literal>) ‚ðƒTƒ|[ƒg‚·‚é‚©‚Ç‚¤‚©
+                    ‚𒲂ׂ邽‚ß‚ÉŽg—p‚µ‚Ü‚·B
+                    ‚à‚µ‚»‚¤‚Å‚È‚¢ê‡AŠJ•úƒ‚[ƒh‚ÍConnectionReleaseMode.AFTER_TRANSACTION
+                    ‚ɃŠƒZƒbƒg‚³‚ê‚Ü‚·B
+                    ‚±‚̐ݒè‚ÍŽŸ‚̊‹«‚ł݈̂À‘S‚Å‚·B
+                    ‚»‚ê‚́A<literal>ConnectionProvider.getConnection()</literal> ‚ðŒÄ‚яo‚·‚½‚Ñ‚É
+                    Šî”Õ‚Æ‚È‚éJDBCƒRƒlƒNƒVƒ‡ƒ“‚ª“¯‚¶‚à‚Ì‚ðŽæ“¾‚Å‚«‚é‚©A
+                    “¯‚¶ƒRƒlƒNƒVƒ‡ƒ“‚ª“¾‚ç‚ê‚邱‚Æ‚ª–â‘è‚Æ‚È‚ç‚È‚¢Ž©“®ƒRƒ~ƒbƒgŠÂ‹«‚Ì’†‚Å‚·B
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/tutorial.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/tutorial.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/tutorial.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1600 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="tutorial">
+    <title>Hibernate‚Ì“±“ü</title>
+    
+    <sect1 id="tutorial-intro" revision="1">
+        <title>‘O‘‚«</title>
+        
+        <para>
+            ‚±‚̏͂ÍHibernate‚ð‰‚ß‚ÄŽg‚¤ƒ†[ƒUŒü‚¯‚Ì“ü–å“I‚ȃ`ƒ…[ƒgƒŠƒAƒ‹‚Å‚·B
+            ƒCƒ“ƒƒ‚ƒŠƒf[ƒ^ƒx[ƒX‚ðŽg‚¤ŠÈ’P‚ȃRƒ}ƒ“ƒhƒ‰ƒCƒ“ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚©‚çŽn‚߁A
+            ˆê•àˆê•à‚í‚©‚è‚â‚·‚¢‚â‚è•û‚ÅŠJ”­‚ði‚ß‚Ü‚·B
+        </para>
+
+        <para>
+            ‚±‚̃`ƒ…[ƒgƒŠƒAƒ‹‚ÍHibernate‚ð‰‚ß‚ÄŽg‚¤ƒ†[ƒU‚ð‘z’肵‚Ä‚¢‚Ü‚·‚ªA
+            —‰ð‚·‚é‚É‚ÍJava‚ÆSQL‚ɂ‚¢‚Ä‚Ì’mŽ¯‚ª•K—v‚Å‚·B
+            ‚±‚ê‚ÍMichael Gloegl‚ÌŽè‚É‚æ‚éƒ`ƒ…[ƒgƒŠƒAƒ‹‚ð‰º•~‚«‚É‚µ‚Ä‚¢‚Ü‚·‚ªA
+            ‚±‚±‚ŃT[ƒhƒp[ƒeƒBƒ‰ƒCƒuƒ‰ƒŠ‚ÆŒ¾‚Á‚Ä‚¢‚é‚̂́AJDK 1.4‚Æ5.0—p‚Ì‚à‚Ì‚Å‚·B
+            JDK 1.3‚ð—˜—p‚·‚é‚Ì‚Å‚ ‚ê‚Α¼‚̃‰ƒCƒuƒ‰ƒŠ‚ª•K—v‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+        </para>
+
+        <para>
+             ƒ`ƒ…[ƒgƒŠƒAƒ‹‚̃\[ƒXƒR[ƒh‚ÍHibernateƒfƒBƒXƒgƒŠƒrƒ…[ƒVƒ‡ƒ“‚Ì 
+             <literal>doc/reference/tutorial/</literal> ‚É‚ ‚è‚Ü‚·B
+        </para>
+
+    </sect1>
+    
+    <sect1 id="tutorial-firstapp" revision="2">
+        <title>ƒp[ƒg1 - ‰‚ß‚Ä‚ÌHibernateƒAƒvƒŠƒP[ƒVƒ‡ƒ“</title>
+
+        <para>
+            Å‰‚ɃRƒ“ƒ\[ƒ‹ƒx[ƒX‚ÌŠÈ’P‚ÈHibernateƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ðì¬‚µ‚Ü‚·B
+            Javaƒf[ƒ^ƒx[ƒXiHSQL DBj‚ð—˜—p‚·‚é‚̂ŁA
+            ƒf[ƒ^ƒx[ƒXƒT[ƒo‚ðƒCƒ“ƒXƒg[ƒ‹‚·‚é•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+        </para>
+
+        <para>
+            ‰¼‚ɏ¬‚³‚ȃf[ƒ^ƒx[ƒXƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ª•K—v‚¾‚Æ‚µ‚Ü‚µ‚傤B
+            ‚»‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚ɂ͏oÈ‚µ‚½‚¢ƒCƒxƒ“ƒg‚ƁA
+            ‚»‚̃Cƒxƒ“ƒg‚̃zƒXƒg‚ɂ‚¢‚Ă̏î•ñ‚ðŠi”[‚·‚é‚à‚Ì‚Æ‚µ‚Ü‚·B
+        </para>
+            
+        <para>
+            ‚Ü‚¸Å‰‚É‚·‚邱‚Æ‚ÍŠJ”­—p‚̃fƒBƒŒƒNƒgƒŠ‚ðƒZƒbƒgƒAƒbƒv‚µ‚āA
+            •K—v‚Æ‚È‚é‚·‚ׂĂÌJavaƒ‰ƒCƒuƒ‰ƒŠ‚ð”z’u‚·‚邱‚Æ‚Å‚·B
+            HibernateƒEƒFƒuƒTƒCƒg‚©‚çHibernateƒfƒBƒXƒgƒŠƒrƒ…[ƒVƒ‡ƒ“‚ðƒ_ƒEƒ“ƒ[ƒh‚µ‚Ä‚­‚¾‚³‚¢B
+            ƒtƒ@ƒCƒ‹‚ð‰ð“€‚µ‚Ä <literal>/lib</literal> ‚É‚ ‚é•K—v‚ȃ‰ƒCƒuƒ‰ƒŠ‚Ì‚·‚ׂĂðA
+            V‚µ‚¢ŠJ”­—pƒfƒBƒŒƒNƒgƒŠ‚Ì <literal>/lib</literal> ƒfƒBƒŒƒNƒgƒŠ‚É”z’u‚µ‚Ä‚­‚¾‚³‚¢B
+            ‚±‚̂悤‚É‚È‚Á‚Ä‚¢‚é‚Í‚¸‚Å‚·F
+        </para>
+            
+        <programlisting><![CDATA[.
++lib
+  antlr.jar
+  cglib.jar
+  asm.jar
+  asm-attrs.jars
+  commons-collections.jar
+  commons-logging.jar
+  hibernate3.jar
+  jta.jar
+  dom4j.jar
+  log4j.jar ]]></programlisting>
+
+        <para>
+            ‚±‚ꂪ <emphasis>–{ƒhƒLƒ…ƒƒ“ƒgŽ·•MŽž“_‚Å‚Ì</emphasis> Hibernate‚Ì•K—vÅ’áŒÀ‚̃‰ƒCƒuƒ‰ƒŠ‚Å‚·
+            iƒƒCƒ“ƒA[ƒJƒCƒu‚Ìhibernate3.jar‚àƒRƒs[‚µ‚Ä‚¢‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢jB
+            Hibernate‚̃o[ƒWƒ‡ƒ“‚É‚æ‚Á‚Ä‚Í‚³‚ç‚É•K—v‚ȃ‰ƒCƒuƒ‰ƒŠ‚âA•s—v‚ȃ‰ƒCƒuƒ‰ƒŠ‚ª‚ ‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+            HibernateƒfƒBƒXƒgƒŠƒrƒ…[ƒVƒ‡ƒ“‚Ì <literal>lib/</literal> ƒfƒBƒŒƒNƒgƒŠ‚É‚ ‚é 
+            <literal>README.txt</literal> ƒtƒ@ƒCƒ‹‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+            •K{‚Ü‚½‚̓IƒvƒVƒ‡ƒ“‚̃T[ƒhƒp[ƒeƒBƒ‰ƒCƒuƒ‰ƒŠ‚ɂ‚¢‚Ă̏î•ñ‚ðÚ‚¹‚Ä‚¢‚Ü‚·
+            iŽÀÛLog4j‚Í•K{‚Å‚Í‚ ‚è‚Ü‚¹‚ñ‚ªA‘½‚­‚ÌŠJ”­ŽÒ‚ªD‚ñ‚Å‚¢‚Ü‚·jB
+        </para>
+
+        <para>
+            ŽŸ‚Ƀf[ƒ^ƒx[ƒX‚ÉŠi”[‚·‚éƒCƒxƒ“ƒg‚ð•\‚·ƒNƒ‰ƒX‚ðì¬‚µ‚Ü‚·B
+        </para>
+      
+        <sect2 id="tutorial-firstapp-firstclass" revision="1">
+            <title>Å‰‚̃Nƒ‰ƒX</title>
+            
+            <para>
+				Å‰‚̉i‘±ƒNƒ‰ƒX‚́AƒvƒƒpƒeƒB‚ð‚¢‚­‚‚©Ž‚ƒVƒ“ƒvƒ‹‚ÈJavaBean‚Å‚·F
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+import java.util.Date;
+
+public class Event {
+    private Long id;
+
+    private String title;
+    private Date date;
+
+    public Event() {}
+
+    public Long getId() {
+        return id;
+    }
+
+    private void setId(Long id) {
+        this.id = id;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+}]]></programlisting>
+
+            <para>
+                ‚²——‚Ì‚Æ‚¨‚èA‚±‚̃Nƒ‰ƒX‚̓tƒB[ƒ‹ƒh‚ªprivate‚̉Ž‹«‚ðŽ‚Á‚Ä‚¢‚é‚Ì‚Æ“¯Žž‚ɁA
+                JavaBean•W€‚̃Qƒbƒ^[AƒZƒbƒ^[ƒƒ\ƒbƒh‚Ì–½–¼‹K–ñ‚ɏ]‚Á‚Ä‚¢‚Ü‚·B
+                ‚±‚̂悤‚Ȑ݌v‚͐„§‚³‚ê‚Ä‚¢‚Ü‚·‚ª•K{‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+                ƒAƒNƒZƒTƒƒ\ƒbƒh‚ðÝ‚¯‚é‚̂̓Šƒtƒ@ƒNƒ^ƒŠƒ“ƒO‚ðl‚¦‚½ŠæŒ’«‚Ì‚½‚߂ŁA
+                Hibernate‚̓tƒB[ƒ‹ƒh‚É’¼ÚƒAƒNƒZƒX‚·‚邱‚Æ‚à‰Â”\‚Å‚·B
+                ˆø”‚Ì‚È‚¢ƒRƒ“ƒXƒgƒ‰ƒNƒ^‚́AƒŠƒtƒŒƒNƒVƒ‡ƒ“‚Å‚±‚̃Nƒ‰ƒX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ðì¬‚·‚邽‚ß‚É
+                •K—v‚Å‚·B
+            </para>
+
+            <para>
+                <literal>id</literal> ƒvƒƒpƒeƒB‚́A‚ ‚é“Á’è‚̃Cƒxƒ“ƒg‚ɑ΂·‚郆ƒj[ƒN‚ÈŽ¯•ÊŽq‚Ì’l‚ð•ÛŽ‚µ‚Ü‚·B
+                Hibernate‚ÌŠ®‘S‚È‹@”\‚ðŽg‚¢‚½‚¯‚ê‚΁A‚·‚ׂẲi‘±ƒGƒ“ƒeƒBƒeƒBƒNƒ‰ƒX
+                i‚»‚ê‚قǏd—v‚Å‚Í‚È‚¢ˆË‘¶ƒNƒ‰ƒX‚Æ‚¢‚¤‚à‚Ì‚à‚ ‚è‚Ü‚·j
+                ‚É‚±‚̂悤‚ÈŽ¯•ÊŽqƒvƒƒpƒeƒB‚ª•K—v‚É‚È‚è‚Ü‚·B
+                Ž–ŽÀã‚Ù‚Æ‚ñ‚ǂ̃AƒvƒŠƒP[ƒVƒ‡ƒ“i“Á‚ÉwebƒAƒvƒŠƒP[ƒVƒ‡ƒ“j‚ł́A
+                Ž¯•ÊŽq‚ŃIƒuƒWƒFƒNƒg‚ð‹æ•Ê‚·‚é•K—v‚ª‚ ‚邽‚߁A‚±‚ê‚͐§ŒÀ‚Æ‚¢‚¤‚æ‚è‚à“Á’¥‚Å‚ ‚é‚ƍl‚¦‚é‚ׂ«‚Å‚·B
+                ‚µ‚©‚µ’ʏíƒIƒuƒWƒFƒNƒg‚ÌID‚𑀍삷‚é‚悤‚È‚±‚Æ‚Í‚µ‚Ü‚¹‚ñB
+                ‚»‚Ì‚½‚߃Zƒbƒ^[ƒƒ\ƒbƒh‚Íprivate‚É‚·‚é‚ׂ«‚Å‚·B
+                Hibernate‚¾‚¯‚ªƒIƒuƒWƒFƒNƒg‚ªƒZ[ƒu‚³‚ꂽ‚Æ‚«‚ÉŽ¯•ÊŽq‚Ö’l‚ð‘ã“ü‚µ‚Ü‚·B
+                Hibernate‚ªipublic, private, protectedjƒtƒB[ƒ‹ƒh‚É’¼ÚƒAƒNƒZƒX‚Å‚«‚é‚Ì‚Æ“¯—l‚ɁA
+                public, private, protected‚̃AƒNƒZƒTƒƒ\ƒbƒh‚ɃAƒNƒZƒX‚Å‚«‚é‚Æ‚¢‚¤‚±‚Æ‚ª‚í‚©‚é‚Å‚µ‚傤B
+                ‘I‘ð‚Í‚ ‚È‚½‚É”C‚³‚ê‚Ä‚¢‚é‚̂ŁA‚ ‚È‚½‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚̐݌v‚ɍ‡‚킹‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+            </para>
+
+            <para>
+                ˆø”‚Ì‚È‚¢ƒRƒ“ƒXƒgƒ‰ƒNƒ^‚Í‚·‚ׂẲi‘±ƒNƒ‰ƒX‚É•K{‚Å‚·B
+                ‚±‚ê‚ÍHibernate‚ªJava‚̃ŠƒtƒŒƒNƒVƒ‡ƒ“‚ðŽg‚Á‚āAƒIƒuƒWƒFƒNƒg‚ðì¬‚µ‚È‚¯‚ê‚΂Ȃç‚È‚¢‚½‚ß‚Å‚·B
+                ƒRƒ“ƒXƒgƒ‰ƒNƒ^‚ðprivate‚É‚·‚邱‚Ƃ͉”\‚Å‚·‚ªA
+                ŽÀsŽž‚̃vƒƒLƒV¶¬‚ƁAƒoƒCƒgƒR[ƒh‘€ì‚È‚µ‚ÌŒø—¦“I‚ȃf[ƒ^‚Ì’Šo‚ɂ́A
+                package‰ÂŽ‹«‚ª•K—v‚Å‚·B
+            </para>
+
+            <para>
+                ŠJ”­ƒtƒHƒ‹ƒ_‚Ì <literal>src</literal> ‚Æ‚¢‚¤ƒfƒBƒŒƒNƒgƒŠ‚Ì“KØ‚ȃpƒbƒP[ƒW‚ɁA
+                ‚±‚ÌJavaƒ\[ƒXƒtƒ@ƒCƒ‹‚ð”z’u‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚±‚ÌŽž“_‚ŃfƒBƒŒƒNƒgƒŠ‚͈ȉº‚̂悤‚É‚È‚Á‚Ä‚¢‚é‚Í‚¸‚Å‚·F
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java]]></programlisting>
+
+            <para>
+                ŽŸ‚̃Xƒeƒbƒv‚ł́AHibernate‚É‚±‚̉i‘±ƒNƒ‰ƒX‚̏î•ñ‚ð‹³‚¦‚Ü‚·B
+            </para>
+                
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-mapping" revision="1">
+            <title>ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹</title>
+
+            <para>
+                Hibernate‚́A‚ǂ̂悤‚ɉi‘±ƒNƒ‰ƒX‚̃IƒuƒWƒFƒNƒg‚ðƒ[ƒh‚µŠi”[‚·‚ê‚΂悢‚©‚ð’m‚é•K—v‚ª‚ ‚è‚Ü‚·B
+                ‚±‚±‚ÅHibernateƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ª“oê‚µ‚Ü‚·B
+                ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚́Aƒf[ƒ^ƒx[ƒX“à‚̂ǂ̃e[ƒuƒ‹‚ɃAƒNƒZƒX‚µ‚È‚¯‚ê‚΂Ȃç‚È‚¢‚©A
+                ‚»‚̃e[ƒuƒ‹‚̂ǂ̃Jƒ‰ƒ€‚ðŽg‚¤‚ׂ«‚©‚ðAHibernate‚É‹³‚¦‚Ü‚·B
+            </para>
+
+            <para>
+                ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ÌŠî–{“I‚ȍ\‘¢‚Í‚±‚̂悤‚É‚È‚è‚Ü‚·F
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+[...]
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Hibernate DTD‚ª”ñí‚ɐô—û‚³‚ê‚Ä‚¢‚邱‚Æ‚É’–Ú‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚±‚ÌDTD‚́AƒGƒfƒBƒ^‚âIDE‚Å‚ÌXMLƒ}ƒbƒsƒ“ƒO—v‘f‚Æ‘®«‚̃I[ƒgƒRƒ“ƒvƒŠ[ƒVƒ‡ƒ“‹@”\‚É—˜—p‚Å‚«‚Ü‚·B
+                ‚Ü‚½DTDƒtƒ@ƒCƒ‹‚ðƒeƒLƒXƒgƒGƒfƒBƒ^‚ÅŠJ‚¯‚Ä‚Ý‚Ä‚­‚¾‚³‚¢B
+                ‚Æ‚¢‚¤‚Ì‚àA‚·‚ׂĂ̗v‘f‚Æ‘®«‚ðŠTŠÏ‚µA
+                ƒRƒƒ“ƒg‚âƒfƒtƒHƒ‹ƒg‚Ì’l‚ðŒ©‚é‚ɂ͈ê”ÔŠÈ’P‚È•û–@‚¾‚©‚ç‚Å‚·B
+                Hibernate‚́Aweb‚©‚çDTDƒtƒ@ƒCƒ‹‚ðƒ[ƒh‚¹‚¸‚ɁA
+                ‚Ü‚¸ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̃Nƒ‰ƒXƒpƒX‚©‚炱‚ê‚ð’T‚µo‚»‚¤‚Æ‚·‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                DTDƒtƒ@ƒCƒ‹‚ÍHibernateƒfƒBƒXƒgƒŠƒrƒ…[ƒVƒ‡ƒ“‚Ì <literal>src/</literal> 
+                ƒfƒBƒŒƒNƒgƒŠ‚Æ“¯—lA<literal>hibernate3.jar</literal> ‚É‚àŠÜ‚Ü‚ê‚Ä‚¢‚Ü‚·B
+            </para>
+
+            <para>
+                ˆÈ~‚Ì—á‚ł̓R[ƒh‚ð’Z‚­‚·‚邽‚ß‚ÉDTDéŒ¾‚ðÈ—ª‚µ‚Ü‚·B
+                “–‘R‚Å‚·‚ª‚±‚ê‚̓IƒvƒVƒ‡ƒ“‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+            </para>
+
+            <para>
+                2‚Â‚Ì <literal>hibernate-mapping</literal> ƒ^ƒO‚ÌŠÔ‚É
+                <literal>class</literal> —v‘f‚ðŠÜ‚ß‚Ä‚­‚¾‚³‚¢B
+                ‚·‚ׂẲi‘±ƒGƒ“ƒeƒBƒeƒBƒNƒ‰ƒXi”O‚ð‰Ÿ‚µ‚Ü‚·‚ªA
+                ƒtƒ@[ƒXƒgƒNƒ‰ƒX‚̃Gƒ“ƒeƒBƒeƒB‚Å‚Í‚È‚¢ˆË‘¶ƒNƒ‰ƒX‚Æ‚¢‚¤‚à‚Ì‚ªŒã‚Ù‚Ç“oê‚µ‚Ü‚·j
+                ‚ÍSQLƒf[ƒ^ƒx[ƒX“à‚̃e[ƒuƒ‹‚Ö‚Ì‚±‚̂悤‚ȃ}ƒbƒsƒ“ƒO‚ð•K—v‚Æ‚µ‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                ‚±‚ê‚Ü‚ÅŽ„‚½‚¿‚́A<literal>Event</literal> ƒNƒ‰ƒX‚̃IƒuƒWƒFƒNƒg‚ð
+                <literal>EVENTS</literal> ƒe[ƒuƒ‹‚ɑ΂µ‚āA‚ǂ̂悤‚ɉi‘±‰»‚µ‚½‚胍[ƒh‚µ‚½‚è‚·‚é‚Ì‚©‚ð
+                Hibernate‚É‹³‚¦‚Ä‚«‚Ü‚µ‚½B‚»‚µ‚ȁX‚̃Cƒ“ƒXƒ^ƒ“ƒX‚̓e[ƒuƒ‹‚̍s‚Æ‚µ‚Ä•\Œ»‚³‚ê‚Ü‚·B
+                ‚»‚ê‚ł͈ø‚«‘±‚«ƒe[ƒuƒ‹‚ÌŽåƒL[‚ɑ΂·‚郆ƒj[ƒN‚ÈŽ¯•ÊŽqƒvƒƒpƒeƒB‚ðƒ}ƒbƒsƒ“ƒO‚µ‚Ä‚¢‚«‚Ü‚·B
+                ‚³‚ç‚ɁA‚±‚ÌŽ¯•ÊŽq‚̈µ‚¢‚É‹C‚ðŽg‚¢‚½‚­‚È‚©‚Á‚½‚Ì‚Æ“¯—l‚ɁA
+                ‘㗝‚ÌŽåƒL[ƒJƒ‰ƒ€‚ɑ΂·‚éHibernate‚ÌŽ¯•ÊŽq¶¬í—ª‚ðÝ’肵‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="native"/>
+        </id>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                <literal>id</literal> —v‘f‚ÍŽ¯•ÊŽqƒvƒƒpƒeƒB‚̐錾‚Å‚ ‚èA
+                <literal>name="id"</literal> ‚ÅJavaƒvƒƒpƒeƒB‚Ì–¼‘O‚ðéŒ¾‚µ‚Ü‚·B
+                Hibernate‚Í‚±‚̃vƒƒpƒeƒB‚ÖƒAƒNƒZƒX‚·‚邽‚߂ɃQƒbƒ^[AƒZƒbƒ^[ƒƒ\ƒbƒh‚ðŽg‚¢‚Ü‚·B
+                ƒJƒ‰ƒ€‘®«‚Å‚Í <literal>EVENTS</literal> ƒe[ƒuƒ‹‚̂ǂ̃Jƒ‰ƒ€‚ðŽåƒL[‚Æ‚µ‚ÄŽg‚¤‚Ì‚©‚ð
+                Hibernate‚É‹³‚¦‚Ü‚·B
+                “ü‚êŽq‚É‚È‚Á‚Ä‚¢‚é <literal>generator</literal> —v‘f‚́AŽ¯•ÊŽq‚𐶐¬‚·‚鎞‚̐헪‚ðŽw’肵‚Ü‚·B
+                i‚±‚Ì—á‚Å‚Í <literal>native</literal> ‚ð—p‚¢‚Ü‚µ‚½jB
+                ‚±‚Ì—v‘f‚́AÝ’肵‚½ƒf[ƒ^ƒx[ƒXidialectj‚ɑ΂·‚éÅ—Ç‚ÈŽ¯•ÊŽq¶¬í—ª‚ð‘I’è‚·‚é‚à‚Ì‚Å‚·B
+                Hibernate‚́AƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚Å’l‚ðŠ„‚è“–‚Ä‚éí—ªi‚à‚µ‚­‚Í“ÆŽ©‚ÉŠg’£‚µ‚½í—ªj‚Æ“¯—l‚ɁA
+                ƒOƒ[ƒoƒ‹‚Ƀ†ƒj[ƒN‚È’l‚ðƒf[ƒ^ƒx[ƒX‚ɐ¶¬‚³‚¹‚éí—ª‚àƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·B
+            </para>
+
+            <para>
+                ÅŒã‚ɃNƒ‰ƒX‚̉i‘±ƒvƒƒpƒeƒB‚̐錾‚ðƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ÉŠÜ‚ß‚Ü‚·B
+                ƒfƒtƒHƒ‹ƒg‚ł́AƒNƒ‰ƒX‚̃vƒƒpƒeƒB‚͉i‘±‚ÆŒ©‚È‚³‚ê‚Ü‚¹‚ñF
+            </para>
+            
+            <programlisting><![CDATA[
+<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="native"/>
+        </id>
+        <property name="date" type="timestamp" column="EVENT_DATE"/>
+        <property name="title"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+            
+            <para>
+                <literal>id</literal> —v‘f‚̏ꍇ‚Æ“¯—l‚ɁA <literal>property</literal> —v‘f‚Ì 
+                <literal>name</literal> ‘®«‚ŁA‚ǂ̃Qƒbƒ^[‚ƃZƒbƒ^[ƒƒ\ƒbƒh‚ðŽg‚¤‚ׂ«‚©‚ðHibernate‚É‹³‚¦‚Ü‚·B
+                ‚±‚Ì—á‚ł́AHibernate‚Í <literal>getDate()/setDate()</literal> ‚Æ <literal>getTitle()/setTitle()</literal> ‚ð
+                ’T‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                ‚È‚º <literal>date</literal> ƒvƒƒpƒeƒB‚̃}ƒbƒsƒ“ƒO‚É‚Í <literal>column</literal> 
+                ‘®«‚ª‚ ‚èA<literal>title</literal> ƒvƒƒpƒeƒB‚É‚Í‚È‚¢‚Ì‚Å‚µ‚傤‚©H
+                <literal>column</literal> ‘®«‚ª‚È‚¯‚ê‚΁AHibernate‚̓vƒƒpƒeƒB–¼‚ðƒJƒ‰ƒ€–¼‚Æ‚µ‚ÄŽg‚¢‚Ü‚·B
+                ‚±‚ê‚Í <literal>title</literal> ‚ł͏ãŽè‚­s‚«‚Ü‚·B
+                ‚µ‚©‚µ <literal>date</literal> ‚Í‚Ù‚Æ‚ñ‚ǂ̃f[ƒ^ƒx[ƒX‚Å—\–ñŒê‚Ȃ̂ŁA
+                ˆá‚¤–¼‘O‚Ń}ƒbƒsƒ“ƒO‚µ‚½•û‚ª‚æ‚¢‚Ì‚Å‚·B
+            </para>
+
+            <para>
+                ŽŸ‚É‹»–¡[‚¢‚Ì‚Í <literal>title</literal> ƒ}ƒbƒsƒ“ƒO‚ª <literal>type</literal> 
+                ‘®«‚ð‚àŒ‡‚¢‚Ä‚¢‚é“_‚Å‚·B
+                ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚Ő錾‚µ‚ÄŽg‚¤type‚́A‚¨‚í‚©‚è‚©‚à‚µ‚ê‚Ü‚¹‚ñ‚ªJava‚̃f[ƒ^Œ^‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+                SQLƒf[ƒ^ƒx[ƒX‚ÌŒ^‚Å‚à‚ ‚è‚Ü‚¹‚ñB
+                ‚±‚ê‚Í <emphasis>Hibernateƒ}ƒbƒsƒ“ƒOŒ^</emphasis> ‚ƌĂ΂ê‚éA
+                Java‚©‚çSQLƒf[ƒ^‚ÌŒ^‚Ö‚Ü‚½‚ÍSQL‚©‚çJavaƒf[ƒ^Œ^‚Ö–|–ó‚·‚éƒRƒ“ƒo[ƒ^‚Å‚·B
+                ŒJ‚è•Ô‚µ‚É‚È‚è‚Ü‚·‚ªAHibernate‚Í <literal>type</literal> ‘®«‚ªƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹“à‚É‚È‚¯‚ê‚΁A
+                ³‚µ‚¢ƒRƒ“ƒo[ƒWƒ‡ƒ“‚ƃ}ƒbƒsƒ“ƒOŒ^‚ðŽ©•ª‚Å‰ðŒˆ‚µ‚悤‚Æ‚µ‚Ü‚·B
+                iJavaƒNƒ‰ƒX‚̃ŠƒtƒŒƒNƒVƒ‡ƒ“‚ðŽg‚Á‚½j‚±‚ÌŽ©“®ŒŸ’m‚́A
+                ê‡‚É‚æ‚Á‚Ä‚Í‚ ‚È‚½‚ªŠú‘Ò‚Ü‚½‚Í•K—v‚Æ‚·‚éƒfƒtƒHƒ‹ƒg’l‚É‚È‚ç‚È‚¢‚©‚à‚µ‚ê‚Ü‚¹‚ñB
+                <literal>date</literal> ƒvƒƒpƒeƒB‚̏ꍇ‚ª‚»‚¤‚Å‚µ‚½B
+                Hibernate‚Í‚±‚́i <literal>java.util.Date</literal> ‚́jƒvƒƒpƒeƒB‚ð
+                SQL‚Ì <literal>date</literal> , <literal>timestamp</literal> , 
+                <literal>time</literal> ‚Ì‚¤‚¿A‚ǂ̃Jƒ‰ƒ€‚Ƀ}ƒbƒsƒ“ƒO‚·‚é‚ׂ«‚È‚Ì‚©‚í‚©‚è‚Ü‚¹‚ñB
+                <literal>timestamp</literal> ƒRƒ“ƒo[ƒ^‚ŃvƒƒpƒeƒB‚ðƒ}ƒbƒsƒ“ƒO‚·‚邱‚Æ‚É‚æ‚èAŠ®‘S‚È“úŽž‚ð•Û‘¶‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                ‚±‚̃}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚́A<literal>Event.hbm.xml</literal> ‚Æ‚µ‚Ä <literal>Event</literal> 
+                JavaƒNƒ‰ƒXƒ\[ƒXƒtƒ@ƒCƒ‹‚Ì‚·‚®—ׂɃZ[ƒu‚·‚é‚ׂ«‚Å‚·B
+                ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚Ì–½–¼•û–@‚Í”CˆÓ‚Å‚·‚ªA<literal>hbm.xml</literal> 
+                ƒTƒtƒBƒbƒNƒX‚ªHibernate‚ÌŠJ”­ŽÒ‚̃Rƒ~ƒ…ƒjƒeƒB“à‚ł̏KŠµ‚Æ‚È‚Á‚Ä‚¢‚Ü‚·B
+                Œ»ÝƒfƒBƒŒƒNƒgƒŠ\‘¢‚Í‚±‚̂悤‚É‚È‚Á‚Ä‚¢‚é‚Í‚¸‚Å‚·F
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java
+    Event.hbm.xml]]></programlisting>
+
+             <para>
+                 Hibernate‚ÌŽå—v‚Ȑݒè‚𑱂¯‚Ü‚·B
+             </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-configuration" revision="2">
+            <title>Hibernate‚̐ݒè</title>
+
+            <para>
+                ‚±‚±‚܂łʼni‘±ƒNƒ‰ƒX‚ƃ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ª‘µ‚¢‚Ü‚µ‚½B‚±‚ê‚©‚çHibernate‚̐ݒè‚ðs‚¢‚Ü‚·‚ªA
+                ‚»‚Ì‘O‚Ƀf[ƒ^ƒx[ƒX‚ª•K—v‚Å‚·B
+                HSQL DB‚ÍJavaƒx[ƒX‚̃Cƒ“ƒƒ‚ƒŠSQL DBMS‚Å‚ ‚èAHSQL DBƒEƒFƒuƒTƒCƒg‚©‚çƒ_ƒEƒ“ƒ[ƒh‚Å‚«‚Ü‚·B
+                ŽÀÛ‚ɂ̓_ƒEƒ“ƒ[ƒh‚µ‚½’†‚Ì <literal>hsqldb.jar</literal> ‚¾‚¯‚ª•K—v‚Å‚·B
+                ‚±‚̃tƒ@ƒCƒ‹‚ðŠJ”­ƒtƒHƒ‹ƒ_‚Ì <literal>lib/</literal> ƒfƒBƒŒƒNƒgƒŠ‚É”z’u‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <para>
+                <literal>data</literal> ‚Æ‚¢‚¤ƒfƒBƒŒƒNƒgƒŠ‚ðŠJ”­ƒfƒBƒŒƒNƒgƒŠ‚̃‹[ƒg‚ɍ쐬‚µ‚Ä‚­‚¾‚³‚¢B
+                HSQL DB‚Í‚±‚±‚Ƀf[ƒ^ƒtƒ@ƒCƒ‹‚ðŠi”[‚µ‚Ü‚·B
+                ‚±‚̃f[ƒ^ƒfƒBƒŒƒNƒgƒŠ‚É‚¨‚¢‚Ä <literal>java -classpath lib/hsqldb.jar org.hsqldb.Server</literal> ‚ðŽÀs‚µA
+                ƒf[ƒ^ƒx[ƒX‚ð‹N“®‚³‚¹‚Ä‚­‚¾‚³‚¢B
+                “®ì‚ÌŠJŽn‚ƁATCP/IPƒ\ƒPƒbƒg‚̃oƒCƒ“ƒh‚ªŠm”F‚Å‚«‚Ü‚·B
+                Œã‚قǍ쐬‚·‚éƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚Í‚±‚±‚ɐڑ±‚µ‚Ü‚·B
+                ‚à‚µ‚±‚̃`ƒ…[ƒgƒŠƒAƒ‹’†‚Ƀf[ƒ^ƒx[ƒX‚ð‰Šú‰»‚µ‚½‚¯‚ê‚΁A
+                HSQL DB‚ðƒVƒƒƒbƒgƒ_ƒEƒ“‚µ‚āiì‹ÆƒEƒBƒ“ƒhƒE‚Å <literal>CTRL + C</literal> ‚ð‰Ÿ‚µ‚Ü‚·j
+                <literal>data/</literal> ƒfƒBƒŒƒNƒgƒŠ“à‚̃tƒ@ƒCƒ‹‚ð‘S‚ďÁ‹Ž‚µ‚½ŒãA
+                HSQL DB‚ðÄ‹N“®‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                Hibernate‚̓AƒvƒŠƒP[ƒVƒ‡ƒ“‚̃f[ƒ^ƒx[ƒX‚ɐڑ±‚·‚é‘w‚Ȃ̂ŁA
+                ƒRƒlƒNƒVƒ‡ƒ“‚̏î•ñ‚ª•K—v‚É‚È‚è‚Ü‚·B
+                ƒRƒlƒNƒVƒ‡ƒ“‚ÍJDBCƒRƒlƒNƒVƒ‡ƒ“ƒv[ƒ‹‚ð’Ê‚¶‚čs‚í‚ê‚Ü‚·‚ªA‚±‚ê‚àÝ’è‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+                HibernateƒfƒBƒXƒgƒŠƒrƒ…[ƒVƒ‡ƒ“‚É‚Í‚¢‚­‚‚©‚̃I[ƒvƒ“ƒ\[ƒX‚ÌJDBCƒRƒlƒNƒVƒ‡ƒ“ƒv[ƒ‹ƒc[ƒ‹‚ªŠÜ‚Ü‚ê‚Ä‚¢‚Ü‚·‚ªA
+                ‚±‚̃`ƒ…[ƒgƒŠƒAƒ‹‚Å‚ÍHibernate‚É‘g‚ݍž‚܂ꂽƒRƒlƒNƒVƒ‡ƒ“ƒv[ƒ‹‚ðŽg‚¢‚Ü‚·B
+                ‚à‚µ»•iƒŒƒxƒ‹‚Ì•iŽ¿‚̃T[ƒhƒp[ƒeƒBJDBCƒRƒlƒNƒVƒ‡ƒ“ƒv[ƒ‹ƒ\ƒtƒgƒEƒFƒA‚ðŽg‚¢‚½‚¯‚ê‚΁A
+                ƒNƒ‰ƒXƒpƒX‚É•K—v‚ȃ‰ƒCƒuƒ‰ƒŠ‚ðƒRƒs[‚µ‚āAˆÙ‚È‚éƒRƒlƒNƒVƒ‡ƒ“ƒv[ƒ‹‚ðÝ’肵‚È‚¯‚ê‚Î
+                ‚È‚ç‚È‚¢‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <para>
+                Hibernate‚̐ݒè‚ł́A’Pƒ‚È <literal>hibernate.properties</literal> ƒtƒ@ƒCƒ‹A
+                ‚»‚ê‚æ‚菭‚µô—û‚³‚ê‚Ä‚¢‚é <literal>hibernate.cfg.xml</literal> ƒtƒ@ƒCƒ‹A
+                ‚Ü‚½‚ÍŠ®‘S‚ɃvƒƒOƒ‰ƒ€ã‚ŃZƒbƒgƒAƒbƒv‚·‚é•û–@‚ª—˜—p‚Å‚«‚Ü‚·B
+                ‚Ù‚Æ‚ñ‚ǂ̃†[ƒU‚ªD‚Þ‚Ì‚ÍXMLÝ’èƒtƒ@ƒCƒ‹‚Å‚·F
+            </para>
+
+            <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <session-factory>
+
+        <!-- Database connection settings -->
+        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
+        <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
+        <property name="connection.username">sa</property>
+        <property name="connection.password"></property>
+
+        <!-- JDBC connection pool (use the built-in) -->
+        <property name="connection.pool_size">1</property>
+
+        <!-- SQL dialect -->
+        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
+
+        <!-- Enable Hibernate's automatic session context management -->
+        <property name="current_session_context_class">thread</property>
+
+        <!-- Disable the second-level cache  -->
+        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
+
+        <!-- Echo all executed SQL to stdout -->
+        <property name="show_sql">true</property>
+
+        <!-- Drop and re-create the database schema on startup -->
+        <property name="hbm2ddl.auto">create</property>
+
+        <mapping resource="events/Event.hbm.xml"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+            <para>
+                ‚±‚ÌXML‚̐ݒ肪ˆÙ‚È‚éDTD‚ðŽg‚¤‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                “Á’è‚̃f[ƒ^ƒx[ƒX‚ðŽó‚¯Ž‚ƒOƒ[ƒoƒ‹ƒtƒ@ƒNƒgƒŠ‚Å‚ ‚éHibernate‚Ì 
+                <literal>SessionFactory</literal> ‚ðÝ’肵‚Ü‚·B
+                ‚à‚µ•¡”‚̃f[ƒ^ƒx[ƒX‚ª‚ ‚éê‡‚ɂ́A
+                iƒXƒ^[ƒgƒAƒbƒv‚ðŠÈ’P‚É‚·‚邽‚߁j’ʏ킢‚­‚‚©‚̐ݒèƒtƒ@ƒCƒ‹“à‚ŁA
+                ‚¢‚­‚‚©‚Ì <literal>&lt;session-factory&gt;</literal> ‚ðŽg‚¤Ý’è‚É‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <para>
+                Å‰‚Ì4‚Â‚Ì <literal>property</literal> —v‘f‚ÍJDBCƒRƒlƒNƒVƒ‡ƒ“‚É•K—v‚Ȑݒè‚ðŠÜ‚ñ‚Å‚¢‚Ü‚·B
+                dialect‚Æ‚¢‚¤–¼‘O‚Ì <literal>property</literal> —v‘f‚́AHibernate‚ª¶¬‚·‚é“Á’è‚ÌSQL•ûŒ¾‚ðŽw’肵‚Ü‚·B
+                ‰i‘±“I‚ȃRƒ“ƒeƒLƒXƒg‚ɑ΂·‚éHibernate‚̃ZƒbƒVƒ‡ƒ“‚ÌŽ©“®ŠÇ—‚́AŒã‚Ì—á‚Å‚·‚®‚É‚í‚©‚é‚悤‚ɁA–ð‚É—§‚‚±‚Æ‚Å‚µ‚傤B
+                <literal>hbm2ddl.auto</literal> ƒIƒvƒVƒ‡ƒ“‚̓f[ƒ^ƒx[ƒXƒXƒL[ƒ}‚ÌŽ©“®¶¬‚ðon‚É‚µ‚Ü‚·B
+                ‚±‚ê‚Í’¼Úƒf[ƒ^ƒx[ƒX‚ɑ΂µ‚ж¬‚³‚ê‚Ü‚·B
+                “–‘RiconfigƒIƒvƒVƒ‡ƒ“‚ðíœ‚µ‚ājoff‚É‚µ‚½‚èA
+                <literal>SchemaExport</literal> ‚Æ‚¢‚¤Antƒ^ƒXƒN‚̏•‚¯‚ðŽØ‚è‚ătƒ@ƒCƒ‹‚ɃŠƒ_ƒCƒŒƒNƒg‚µ‚½‚è‚Å‚«‚Ü‚·B
+                ÅŒã‚ɉi‘±ƒNƒ‰ƒX‚Ì‚½‚߂̃}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ðÝ’è‚ɒljÁ‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                ‚±‚̃tƒ@ƒCƒ‹‚ðƒ\[ƒXƒfƒBƒŒƒNƒgƒŠ‚ɃRƒs[‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚·‚é‚Æ‚±‚ê‚̓Nƒ‰ƒXƒpƒX‚̃‹[ƒg‚É‚ ‚邱‚Æ‚É‚È‚è‚Ü‚·B
+                Hibernate‚́AƒXƒ^[ƒgƒAƒbƒvŽž‚ɃNƒ‰ƒXƒpƒX‚̃‹[ƒg‚Å <literal>hibernate.cfg.xml</literal> 
+                ‚Æ‚¢‚¤ƒtƒ@ƒCƒ‹‚ðŽ©“®“I‚É’T‚µ‚Ü‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-ant" revision="1">
+            <title>Ant‚É‚æ‚éƒrƒ‹ƒh</title>
+
+            <para>
+                ‚»‚ê‚Å‚ÍAnt‚ðŽg‚Á‚ă`ƒ…[ƒgƒŠƒAƒ‹‚ðƒrƒ‹ƒh‚µ‚Ü‚µ‚傤B
+                ‚»‚ê‚É‚ÍAnt‚ªƒCƒ“ƒXƒg[ƒ‹‚³‚ê‚Ä‚¢‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                <ulink url="http://ant.apache.org/bindownload.cgi">Antƒ_ƒEƒ“ƒ[ƒhƒy[ƒW</ulink> 
+                ‚©‚çƒ_ƒEƒ“ƒ[ƒh‚µ‚Ä‚­‚¾‚³‚¢B
+                Ant‚̃Cƒ“ƒXƒg[ƒ‹•û–@‚Í‚±‚±‚Å‚Íà–¾‚µ‚Ü‚¹‚ñ‚̂ŁA
+                <ulink url="http://ant.apache.org/manual/index.html">Antƒ}ƒjƒ…ƒAƒ‹</ulink> 
+                ‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                Ant‚ðƒCƒ“ƒXƒg[ƒ‹‚·‚ê‚΁Aƒrƒ‹ƒhƒtƒ@ƒCƒ‹‚̍쐬‚ðŠJŽn‚Å‚«‚Ü‚·B
+                ‚±‚̃tƒ@ƒCƒ‹‚Í <literal>build.xml</literal> ‚ƌĂ΂êAŠJ”­ƒfƒBƒŒƒNƒgƒŠ‚É’¼Ú”z’u‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                Šî–{“I‚ȃrƒ‹ƒhƒtƒ@ƒCƒ‹‚Í‚±‚̂悤‚É‚È‚è‚Ü‚·F
+            </para>
+
+            <programlisting><![CDATA[<project name="hibernate-tutorial" default="compile">
+
+    <property name="sourcedir" value="${basedir}/src"/>
+    <property name="targetdir" value="${basedir}/bin"/>
+    <property name="librarydir" value="${basedir}/lib"/>
+
+    <path id="libraries">
+        <fileset dir="${librarydir}">
+            <include name="*.jar"/>
+        </fileset>
+    </path>
+
+    <target name="clean">
+        <delete dir="${targetdir}"/>
+        <mkdir dir="${targetdir}"/>
+    </target>
+
+    <target name="compile" depends="clean, copy-resources">
+      <javac srcdir="${sourcedir}"
+             destdir="${targetdir}"
+             classpathref="libraries"/>
+    </target>
+
+    <target name="copy-resources">
+        <copy todir="${targetdir}">
+            <fileset dir="${sourcedir}">
+                <exclude name="**/*.java"/>
+            </fileset>
+        </copy>
+    </target>
+
+</project>]]></programlisting>
+
+            <para>
+                ‚±‚ê‚Í <literal>.jar</literal> ‚ŏI‚í‚élibƒfƒBƒŒƒNƒgƒŠ‚Ì‚·‚ׂẴtƒ@ƒCƒ‹‚ðA
+                ƒRƒ“ƒpƒCƒ‹‚ÉŽg—p‚·‚éƒNƒ‰ƒXƒpƒX‚ɒljÁ‚·‚邱‚Æ‚ðAnt‚É‹³‚¦‚Ü‚·B
+                ‚Ü‚½AJavaƒ\[ƒXƒtƒ@ƒCƒ‹‚Å‚È‚¢‚·‚ׂẴtƒ@ƒCƒ‹‚ðƒ^[ƒQƒbƒgƒfƒBƒŒƒNƒgƒŠ‚ɃRƒs[‚·‚é‚Æ‚¢‚¤‚±‚Æ‚Å‚à‚ ‚è‚Ü‚·B
+                —Ⴆ‚ΐݒèƒtƒ@ƒCƒ‹‚âHibernateƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚È‚Ç‚Å‚·B
+                ¡Ant‚ðŽÀs‚·‚é‚ƁA‚±‚̂悤‚ȏo—Í‚ª‚ ‚é‚Í‚¸‚Å‚·F
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant
+Buildfile: build.xml
+
+copy-resources:
+     [copy] Copying 2 files to C:\hibernateTutorial\bin
+
+compile:
+    [javac] Compiling 1 source file to C:\hibernateTutorial\bin
+
+BUILD SUCCESSFUL
+Total time: 1 second ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-helpers" revision="3">
+            <title>ƒXƒ^[ƒgƒAƒbƒv‚ƃwƒ‹ƒp</title>
+
+            <para>
+                ‚³‚Ä <literal>Event</literal> ƒIƒuƒWƒFƒNƒg‚ðƒ[ƒh‚µ‚½‚èŠi”[‚µ‚½‚è‚·‚鏀”õ‚ª‚Å‚«‚Ü‚µ‚½B
+                ‚µ‚©‚µ‚Ü‚¸‚̓Cƒ“ƒtƒ‰ƒXƒgƒ‰ƒNƒ`ƒƒ‚̃R[ƒh‚ð‘‚¢‚āAƒZƒbƒgƒAƒbƒv‚ðŠ®—¹‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+                ‚Ü‚¸‚ÍHibernate‚ðƒXƒ^[ƒgƒAƒbƒv‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                ‚±‚̃Xƒ^[ƒgƒAƒbƒv‚ɂ́AƒOƒ[ƒoƒ‹‚Ì <literal>SessionFactory</literal> ƒIƒuƒWƒFƒNƒg‚𐶐¬‚µ‚āA
+                ‚»‚ê‚ðƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̃R[ƒh‚ŃAƒNƒZƒX‚µ‚â‚·‚¢êŠ‚ÉŠi”[‚·‚邱‚Æ‚ªŠÜ‚Ü‚ê‚Ü‚·B
+                <literal>SessionFactory</literal> ‚͐V‚µ‚­ <literal>Session</literal> ‚ðƒI[ƒvƒ“‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+                <literal>Session</literal> ‚̓Vƒ“ƒOƒ‹ƒXƒŒƒbƒh‚̍ì‹Æ’PˆÊ(Unit of Work)‚ð•\Œ»‚µ‚Ü‚·B
+                ‚»‚ê‚ɑ΂µ<literal>SessionFactory</literal> ‚̓XƒŒƒbƒhƒZ[ƒt‚̃Oƒ[ƒoƒ‹ƒIƒuƒWƒFƒNƒg‚Å‚ ‚èA
+                ˆê“x‚¾‚¯ƒCƒ“ƒXƒ^ƒ“ƒX‰»‚³‚ê‚Ü‚·B
+            </para>
+
+            <para>
+                ‚±‚±‚ŃXƒ^[ƒgƒAƒbƒv‚ðs‚¢A •Ö—˜‚É <literal>SessionFactory</literal> ‚ÖƒAƒNƒZƒX‚·‚é
+                <literal>HibernateUtil</literal> ƒwƒ‹ƒpƒNƒ‰ƒX‚ðì¬‚µ‚Ü‚·B
+                ŽÀ‘•‚ðŒ©‚Ä‚Ý‚Ü‚µ‚傤F
+            </para>
+
+            <programlisting><![CDATA[package util;
+
+import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+    private static final SessionFactory sessionFactory;
+
+    static {
+        try {
+            // Create the SessionFactory from hibernate.cfg.xml
+            sessionFactory = new Configuration().configure().buildSessionFactory();
+        } catch (Throwable ex) {
+            // Make sure you log the exception, as it might be swallowed
+            System.err.println("Initial SessionFactory creation failed." + ex);
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    public static SessionFactory getSessionFactory() {
+        return sessionFactory;
+    }
+
+}]]></programlisting>
+
+            <para>
+                ‚±‚̃Nƒ‰ƒX‚͐ÓI‰Šú‰»ƒuƒƒbƒNiƒNƒ‰ƒX‚ªƒ[ƒh‚³‚ê‚é‚Æ‚«‚ÉJVM‚É‚æ‚Á‚Ĉê“x‚¾‚¯ŒÄ‚΂ê‚éj
+                ‚ŃOƒ[ƒoƒ‹‚Ì <literal>SessionFactory</literal> ‚𐶐¬‚·‚邾‚¯‚Å‚Í‚È‚­A
+                Ã“IƒVƒ“ƒOƒ‹ƒgƒ“‚ÌŽg—p‚ð‰B•Á‚µ‚Ü‚·B
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“ƒT[ƒo[‚ÌJNDI‚©‚ç <literal>SessionFactory</literal> ‚ð
+                ƒ‹ƒbƒNƒAƒbƒv‚·‚é‚Ì‚Æ“¯—l‚Å‚·B
+           </para>
+
+            <para>
+                Ý’èƒtƒ@ƒCƒ‹“à‚Å <literal>SessionFactory</literal> ‚É–¼‘O‚ð—^‚¦‚é‚ƁA
+                Hibernate‚Í <literal>SessionFactory</literal> \’zŒã‚ÉJNDI‚ɑ΂µƒoƒCƒ“ƒh‚ðs‚¨‚¤‚Æ‚µ‚Ü‚·B
+                ‚±‚̃R[ƒh‚ðŠ®‘S‚É”rœ‚·‚邽‚߂ɂ́A
+                JMXƒfƒvƒƒCƒƒ“ƒg‚ð—˜—p‚µ‚Ä
+                JMX‚ð—˜—p‚Å‚«‚éƒRƒ“ƒeƒi‚ðƒCƒ“ƒXƒ^ƒ“ƒX‰»‚µA
+                <literal>HibernateService</literal> ‚ðJNDI‚ÖƒoƒCƒ“ƒh‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+                ‚±‚ê‚ç‚̍‚“x‚ȃIƒvƒVƒ‡ƒ“‚́AHibernate‚̃Šƒtƒ@ƒŒƒ“ƒXƒhƒLƒ…ƒƒ“ƒg‚Åà–¾‚³‚ê‚Ä‚¢‚Ü‚·B
+            </para>
+
+            <para>
+                <literal>HibernateUtil.java</literal> ‚ðŠJ”­ƒ\[ƒXƒfƒBƒŒƒNƒgƒŠ‚É‚ ‚é <literal>events</literal> ƒpƒbƒP[ƒW‚Ì
+                —ׂɔz’u‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java
+    Event.hbm.xml
+  +util
+    HibernateUtil.java
+  hibernate.cfg.xml
++data
+build.xml]]></programlisting>
+
+            <para>
+                ‚±‚ê‚Í–â‘è‚È‚­ÄƒRƒ“ƒpƒCƒ‹‚Å‚«‚é‚Í‚¸‚Å‚·B
+                ÅŒã‚ɃƒMƒ“ƒOƒVƒXƒeƒ€‚ðÝ’è‚·‚é•K—v‚ª‚ ‚è‚Ü‚·B
+                Hibernate‚Ícommons logging‚ðŽg‚¤‚½‚߁ALog4j‚ÆJDK 1.4 logging‚Ì‘I‘ð‚ð‚·‚é•K—v‚ª‚ ‚è‚Ü‚¹‚ñB
+                ‚Ù‚Æ‚ñ‚Ç‚ÌŠJ”­ŽÒ‚ªD‚Þ‚Ì‚ÍLog4j‚Å‚·B
+                HibernateƒfƒBƒXƒgƒŠƒrƒ…[ƒVƒ‡ƒ“i‚Ì<literal>etc/</literal> ƒfƒBƒŒƒNƒgƒŠj‚©‚ç 
+                <literal>log4j.properties</literal> ‚ð‚ ‚È‚½‚Ì <literal>src</literal> ƒfƒBƒŒƒNƒgƒŠ“à‚Ì
+                <literal>hibernate.cfg.xml</literal> ‚ׂ̗ɃRƒs[‚µ‚Ä‚­‚¾‚³‚¢B
+                Ý’è—á‚ðŒ©‚ÄAç’·‚ȏo—Í‚ª‚悯‚ê‚ΐݒè‚ð•ÏX‚µ‚Ä‚­‚¾‚³‚¢B
+                ƒfƒtƒHƒ‹ƒg‚Å‚ÍHibernate‚̃Xƒ^[ƒgƒAƒbƒvƒƒbƒZ[ƒW‚¾‚¯‚ª•W€o—Í‚É•\Ž¦‚³‚ê‚Ü‚·B
+            </para>
+
+            <para>
+                ƒ`ƒ…[ƒgƒŠƒAƒ‹‚̃Cƒ“ƒtƒ‰‚ÍŠ®‘S‚Å‚·B
+                Hibernate‚ðŽg‚Á‚ÄŽÀÛ‚̍ì‹Æ‚ð‚·‚é€”õ‚ª®‚¢‚Ü‚µ‚½B
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-workingpersistence" revision="4">
+            <title>ƒIƒuƒWƒFƒNƒg‚̃[ƒh‚ÆŠi”[</title>
+
+            <para>
+                ‚‚¢‚ɃIƒuƒWƒFƒNƒg‚̃[ƒh‚ÆŠi”[‚ÉHibernate‚ðŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+                <literal>main()</literal> ƒƒ\ƒbƒh‚ðŽ‚Â <literal>EventManager</literal> 
+                ƒNƒ‰ƒX‚ð‘‚«‚Ü‚·F
+            </para>
+
+            <programlisting><![CDATA[package events;
+import org.hibernate.Session;
+
+import java.util.Date;
+
+import util.HibernateUtil;
+
+public class EventManager {
+
+    public static void main(String[] args) {
+        EventManager mgr = new EventManager();
+
+        if (args[0].equals("store")) {
+            mgr.createAndStoreEvent("My Event", new Date());
+        }
+
+        HibernateUtil.getSessionFactory().close();
+    }
+
+    private void createAndStoreEvent(String title, Date theDate) {
+
+        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+        session.beginTransaction();
+
+        Event theEvent = new Event();
+        theEvent.setTitle(title);
+        theEvent.setDate(theDate);
+
+        session.save(theEvent);
+
+        session.getTransaction().commit();
+    }
+
+}]]></programlisting>
+
+            <para>
+                V‚µ‚¢ <literal>Event</literal> ƒIƒuƒWƒFƒNƒg‚𐶐¬‚µA‚»‚ê‚ðHibernate‚É“n‚µ‚Ü‚·B
+                ¡‚Å‚ÍHibernate‚ªSQL‚ðˆ—‚µAƒf[ƒ^ƒx[ƒX‚Å <literal>INSERT</literal> ‚ðŽÀs‚µ‚Ü‚·B
+                ŽÀs‘O‚É <literal>Session</literal> ‚Æ <literal>Transaction</literal> 
+                ‚ðˆ—‚·‚éƒR[ƒh‚ðŠm”F‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <para>
+                <literal>Session</literal> ‚Í1‚‚̍ì‹Æ’PˆÊ(Unit of Work)‚Å‚·B
+                “–•ª‚̊ԁA˜b‚ðŠÈ’P‚É‚·‚邽‚߂ɁA
+                <literal>Session</literal> ‚Æ <literal>Transaction</literal> ‚̑Ήž‚ðˆê‘Έê‚Ɖ¼’肵‚Ü‚·B
+                Žg—p‚µ‚Ä‚¢‚éƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“EƒVƒXƒeƒ€i‚±‚̃P[ƒX‚Å‚ÍJTA‚Æ‹¤‘¶‚Å‚«‚é’Pƒ‚ÈJDBCj‚©‚çƒR[ƒh‚ð•ÛŒì‚·‚邽‚߂ɁA
+                Hibernate <literal>Session</literal> ã‚Å—˜—p‰Â”\‚È <literal>Transaction</literal> API‚ðŽg—p‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                <literal>sessionFactory.getCurrentSession()</literal> ‚Í‚È‚É‚ð‚·‚é‚Ì‚Å‚µ‚傤‚©H
+                ‚Ü‚¸A‚¢‚Á‚½‚ñ <literal>SessionFactory</literal> ‚ðŽæ“¾‚µ•ÛŽ‚·‚ê‚Î
+                i <literal>HibernateUtil</literal> ‚Ì‚¨‚©‚°‚ÅŠÈ’P‚Å‚·jA‚±‚̃ƒ\ƒbƒh‚ð‰½“x‚Å‚àA
+                ‚Ç‚±‚©‚ç‚Å‚àŒÄ‚яo‚·‚±‚Æ‚ªo—ˆ‚Ü‚·B
+                <literal>getCurrentSession()</literal> ƒƒ\ƒbƒh‚͏í‚ɁuŒ»Ý‚́vì‹Æ’PˆÊ(Unit of Work)‚ð•Ô‚µ‚Ü‚·B
+                <literal>hibernate.cfg.xml</literal> ‚Ì‚±‚Ì‹@”\‚̐ݒè‚ŁA"thread"‚ðŽw’肵‚½‚±‚Æ‚ðŽv‚¢o‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚±‚Ì‚½‚ߌ»Ý‚̍ì‹Æ’PˆÊ‚̃XƒR[ƒv‚́A‚±‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚ðŽÀs‚·‚錻Ý‚ÌJavaƒXƒŒƒbƒh‚Å‚·B
+                ‚µ‚©‚µ‚±‚ê‚Å‘S‚Ä‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+                <literal>Session</literal> ‚͍ŏ‰‚É•K—v‚Æ‚È‚Á‚½‚Æ‚«A‚‚܂èÅ‰‚É <literal>getCurrentSession()</literal> ‚ª
+                ŒÄ‚΂ꂽ‚Æ‚«‚ÉŠJŽn‚µ‚Ü‚·B
+                ‚»‚Ì‚Æ‚«Hibernate‚É‚æ‚茻Ý‚̃XƒŒƒbƒh‚ÉŒ‹‚Ñ•t‚¯‚ç‚ê‚Ü‚·B
+                ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ªI—¹iƒRƒ~ƒbƒg‚à‚µ‚­‚̓[ƒ‹ƒoƒbƒNj‚µ‚½‚Æ‚«A
+                Hibernate‚àƒXƒŒƒbƒh‚©‚ç <literal>Session</literal> ‚ðØ‚è—£‚µAƒNƒ[ƒY‚µ‚Ü‚·B
+                Ä‚Ñ <literal>getCurrentSession()</literal> ‚ðŒÄ‚ԂƁA
+                V‚µ‚¢ <literal>Session</literal> ‚ðŽæ“¾‚µ‚ĐV‚µ‚¢ì‹Æ’PˆÊ‚ðƒXƒ^[ƒg‚Å‚«‚Ü‚·B
+                ‚±‚Ì <emphasis>thread-bound</emphasis> ƒvƒƒOƒ‰ƒ~ƒ“ƒOEƒ‚ƒfƒ‹‚ÍHibernate‚ð—˜—p‚·‚éã‚ōłàl‹C‚ª‚ ‚è‚Ü‚·B
+            </para>
+
+            <para>
+                ƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̈µ‚¢‚Æ‹«ŠE‚̏ڂµ‚¢î•ñ‚ɂ‚¢‚ẮA
+                <xref linkend="transactions"/> ‚ðŒ©‚Ä‚­‚¾‚³‚¢B
+                ‚±‚Ì—á‚ł̓Gƒ‰[ˆ—‚⃍[ƒ‹ƒoƒbƒN‚àŠ„ˆ¤‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                ‚±‚̍ŏ‰‚̃‹[ƒ`ƒ“‚ðŽÀs‚·‚é‚ɂ́AAnt‚̃rƒ‹ƒhƒtƒ@ƒCƒ‹‚ɌĂяo‚µ‰Â”\‚ȃ^[ƒQƒbƒg‚ð
+                ’ljÁ‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñF
+            </para>
+
+            <programlisting><![CDATA[<target name="run" depends="compile">
+    <java fork="true" classname="events.EventManager" classpathref="libraries">
+        <classpath path="${targetdir}"/>
+        <arg value="${action}"/>
+    </java>
+</target>]]></programlisting>
+
+            <para>
+                <literal>action</literal> ˆø”‚Ì’l‚́Aƒ^[ƒQƒbƒg‚ðŒÄ‚Ô‚Æ‚«‚ɃRƒ}ƒ“ƒhƒ‰ƒCƒ“‚Őݒ肵‚Ü‚·F
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant run -Daction=store]]></programlisting>
+
+            <para>
+                ƒRƒ“ƒpƒCƒ‹‚·‚é‚ƁAHibernate‚ªƒXƒ^[ƒg‚µA‚ ‚È‚½‚̐ݒè‚É‚æ‚è‚Ü‚·‚ªA
+                ‘½‚­‚̃ƒOo—Í‚ª‚ ‚é‚Í‚¸‚Å‚·B
+                ‚»‚̍Ōã‚ɂ͈ȉº‚̍s‚ª‚ ‚é‚Å‚µ‚傤F
+            </para>
+
+            <programlisting><![CDATA[[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)]]></programlisting>
+
+            <para>
+                ‚±‚ê‚ÍHibernate‚ªŽÀs‚·‚é <literal>INSERT</literal> ‚ŁA
+                ƒNƒGƒXƒ`ƒ‡ƒ“ƒ}[ƒN‚ÍJDBCƒoƒCƒ“ƒhƒpƒ‰ƒ[ƒ^‚ð•\‚µ‚Ä‚¢‚Ü‚·B
+                ˆø”‚Æ‚µ‚ăoƒCƒ“ƒh‚³‚ê‚é’l‚ðŒ©‚é‚½‚߁A‚ ‚é‚¢‚̓ƒO‚̏璷«‚ðŒ¸‚ç‚·‚½‚߂ɂ́A
+                <literal>log4j.properties</literal> ‚ðƒ`ƒFƒbƒN‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <para>
+                ‚»‚ê‚Å‚Í“¯‚¶‚悤‚ÉŠi”[‚³‚ꂽƒCƒxƒ“ƒg‚̈ꗗ‚ðŒ©‚æ‚¤‚ÆŽv‚¢‚Ü‚·B
+                ‚»‚Ì‚½‚߃ƒCƒ“ƒƒ\ƒbƒh‚ɃIƒvƒVƒ‡ƒ“‚ð’ljÁ‚µ‚Ü‚·F
+            </para>
+
+            <programlisting><![CDATA[if (args[0].equals("store")) {
+    mgr.createAndStoreEvent("My Event", new Date());
+}
+else if (args[0].equals("list")) {
+    List events = mgr.listEvents();
+    for (int i = 0; i < events.size(); i++) {
+        Event theEvent = (Event) events.get(i);
+        System.out.println("Event: " + theEvent.getTitle() +
+                           " Time: " + theEvent.getDate());
+    }
+}]]></programlisting>
+
+            <para>
+                V‚µ‚¢ <literal>listEvents()ƒƒ\ƒbƒh</literal> ‚à’ljÁ‚µ‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[private List listEvents() {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+    session.beginTransaction();
+
+    List result = session.createQuery("from Event").list();
+
+    session.getTransaction().commit();
+
+    return result;
+}]]></programlisting>
+
+            <para>
+                ‚±‚±‚Å‚·‚邱‚Ƃ́Aƒf[ƒ^ƒx[ƒX‚©‚瑶Ý‚·‚é‚·‚×‚Ä‚Ì <literal>Event</literal> 
+                ƒIƒuƒWƒFƒNƒg‚ðƒ[ƒh‚·‚éHQL (Hibernate Query Language) ƒNƒGƒŠ‚ðŽg‚¤‚±‚Æ‚Å‚·B
+                Hibernate‚Í“KØ‚ÈSQL‚𐶐¬‚µA‚»‚ê‚ðƒf[ƒ^ƒx[ƒX‚É‘—‚èA
+                ‚»‚̃f[ƒ^‚ðŽg‚Á‚Ä <literal>Event</literal> ƒIƒuƒWƒFƒNƒg‚𐶐¬‚µ‚Ü‚·B
+                “–‘RHQL‚Å‚³‚ç‚É•¡ŽG‚ȃNƒGƒŠ‚ðì¬‚Å‚«‚Ü‚·B
+            </para>
+
+            <para>
+                 ˆÈ‰º‚̃Xƒeƒbƒv‚ŁA‚·‚ׂĂ̎Às‚ƃeƒXƒg‚ðs‚¢‚Ü‚·B
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        hbm2ddl‚ð’Ê‚·‘O‚Ƀf[ƒ^ƒx[ƒX‚̃f[ƒ^‚ðì¬‚µAƒf[ƒ^ƒx[ƒXƒXƒL[ƒ}‚𐶐¬‚·‚邽‚߂ɁA
+                         <literal>ant run -Daction=store</literal> ‚ðŽÀs‚µ‚Ä‚­‚¾‚³‚¢B
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        ¡‚Í <literal>hibernate.cfg.xml</literal> ƒtƒ@ƒCƒ‹‚̃vƒƒpƒeƒB‚ðƒRƒƒ“ƒgƒAƒEƒg‚µ‚Ähbm2ddl‚𖳌ø‚É‚µ‚Ä‚­‚¾‚³‚¢B
+                        ’ʏí‚ÍŒp‘±“I‚É’P‘̃eƒXƒg‚ð‚µ‚Ä‚¢‚éŠÔ‚Íhbm2ddl‚ð—LŒø‚É‚µ‚Ä‚¨‚­‚Ì‚Å‚·‚ªA
+                        ‚»‚êˆÈŠO‚̏ꍇ‚Éhbm2ddl‚ð‹N“®‚·‚é‚ÆŠi”[‚µ‚Ä‚¨‚¢‚½‘S‚Ẵf[ƒ^‚ð <emphasis>ƒhƒƒbƒv</emphasis> ‚·‚é‚Å‚µ‚傤B
+                        Ý’è‚ð <literal>create</literal> ‚É‚·‚é‚ƁAŒ‹‰Ê‚Æ‚µ‚Ä
+                       uSessionFactory¶¬‚̍ہAƒXƒL[ƒ}‚©‚ç‘S‚Ẵe[ƒuƒ‹‚ðƒhƒƒbƒv‚µ‚čč쐬‚·‚év‚Æ‚¢‚¤Ý’è‚É‚È‚è‚Ü‚·B
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                ¡ <literal>-Daction=list</literal> ‚ÆŽw’肵‚ÄAnt‚ðŒÄ‚ԂƁA
+                ‚±‚ê‚Ü‚ÅŠi”[‚µ‚½ƒCƒxƒ“ƒg‚ªŒ©‚¦‚é‚Í‚¸‚Å‚·B
+                <literal>store</literal> ƒAƒNƒVƒ‡ƒ“‚𐔉ñˆÈãŒÄ‚Ô‚±‚Æ‚à‰Â”\‚Å‚·B
+            </para>
+
+            <para>
+                ’ˆÓF‰‚ß‚ÄHibernate‚ɐG‚ê‚élX‚Ì‘½‚­‚ª‚±‚±‚ÅŽ¸”s‚·‚邽‚߁A<emphasis>Table not found</emphasis> ƒGƒ‰[ƒƒbƒZ[ƒW‚É
+                ŠÖ‚·‚鎿–â‚ð’èŠú“I‚ÉŒ©‚©‚¯‚Ü‚·B
+                ‚µ‚©‚µã‹L‚̃Xƒeƒbƒv‚ɏ]‚¦‚΁Ahbm2ddl‚ªÅ‰‚ÉŽÀs‚³‚ꂽ‚Æ‚«‚Ƀf[ƒ^ƒx[ƒXƒXƒL[ƒ}‚ðì¬‚µA
+                ‚»‚ÌŒã‚ÌŽÀs‚É‚¨‚¢‚Ä‚à‚±‚̃XƒL[ƒ}‚ðŽg—p‚·‚é‚̂ŁA–â‘è‚Í‹N‚±‚ç‚È‚¢‚Å‚µ‚傤B
+                ƒ}ƒbƒsƒ“ƒO‚âƒf[ƒ^ƒx[ƒXƒXƒL[ƒ}‚ð•ÏX‚µ‚½‚Æ‚«‚́A‚à‚¤ˆê“xhbm2ddl‚ð—LŒø‚É‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="tutorial-associations">
+        <title>ƒp[ƒg2 - ŠÖ˜A‚̃}ƒbƒsƒ“ƒO</title>
+
+        <para>
+            ‰i‘±ƒGƒ“ƒeƒBƒeƒBƒNƒ‰ƒX‚ðƒe[ƒuƒ‹‚Ƀ}ƒbƒsƒ“ƒO‚µ‚Ü‚µ‚½B
+            ‚³‚ç‚É‚±‚̏ã‚É‚¢‚­‚‚©‚̃Nƒ‰ƒX‚ÌŠÖ˜A‚ð’ljÁ‚µ‚Ü‚µ‚傤B
+            ‚Ü‚¸‰‚߂ɃAƒvƒŠƒP[ƒVƒ‡ƒ“‚ɐlX‚ð’ljÁ‚µA”ނ炪ŽQ‰Á‚·‚éƒCƒxƒ“ƒg‚̃ŠƒXƒg‚ðŠi”[‚µ‚Ü‚·B
+        </para>
+
+        <sect2 id="tutorial-associations-mappinguser" revision="1">
+            <title>PersonƒNƒ‰ƒX‚̃}ƒbƒsƒ“ƒO</title>
+
+            <para>
+                Å‰‚Ì <literal>Person</literal> ƒNƒ‰ƒX‚Í’Pƒ‚Å‚·F
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+public class Person {
+
+    private Long id;
+    private int age;
+    private String firstname;
+    private String lastname;
+
+    public Person() {}
+
+    // Accessor methods for all properties, private setter for 'id'
+
+}]]></programlisting>
+
+            <para>
+                <literal>Person.hbm.xml</literal> ‚Æ‚¢‚¤V‚µ‚¢ƒ}ƒbƒsƒ“ƒOƒtƒ@ƒCƒ‹‚ðì¬‚µ‚Ä‚­‚¾‚³‚¢
+                iƒtƒ@ƒCƒ‹‚̍ŏ‰‚ÉDTD‚Ö‚ÌŽQÆ‚ð–Y‚ꂸ‚É“ü‚ê‚Ä‚­‚¾‚³‚¢jF
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Person" table="PERSON">
+        <id name="id" column="PERSON_ID">
+            <generator class="native"/>
+        </id>
+        <property name="age"/>
+        <property name="firstname"/>
+        <property name="lastname"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                ÅŒã‚ÉHibernate‚̐ݒè‚ɐV‚µ‚¢ƒ}ƒbƒsƒ“ƒO‚ð’ljÁ‚µ‚Ä‚­‚¾‚³‚¢F
+            </para>
+
+            <programlisting><![CDATA[<mapping resource="events/Event.hbm.xml"/>
+<mapping resource="events/Person.hbm.xml"/>]]></programlisting>
+
+            <para>
+                ‚»‚ê‚Å‚Í‚±‚ê‚ç2‚‚̃Gƒ“ƒeƒBƒeƒBŠÔ‚ÌŠÖ˜A‚ðì¬‚µ‚Ü‚·B
+                lX‚ªƒCƒxƒ“ƒg‚ÉŽQ‰Á‚Å‚«AƒCƒxƒ“ƒg‚ªŽQ‰ÁŽÒ‚ðŽ‚Â‚Ì‚Í–¾‚ç‚©‚Å‚·B
+                ˆµ‚í‚È‚¯‚ê‚΂Ȃç‚È‚¢ÝŒv‚Ì–â‘è‚́A•ûŒüA‘½d“xAƒRƒŒƒNƒVƒ‡ƒ“‚̐U‚é•‘‚¢‚Å‚·B
+            </para>
+        </sect2>
+
+        <sect2 id="tutorial-associations-unidirset" revision="3">
+            <title>’P•ûŒüSetƒx[ƒXŠÖ˜A</title>
+
+            <para>
+                ƒCƒxƒ“ƒg‚̃RƒŒƒNƒVƒ‡ƒ“‚ð <literal>Person</literal> ƒNƒ‰ƒX‚ɒljÁ‚µ‚Ü‚·B
+                ‚±‚¤‚µ‚Ä‚¨‚­‚ƁA–¾Ž¦“I‚ȃNƒGƒŠA‚‚܂è‚í‚´‚í‚´<literal>aPerson.getEvents()</literal>‚ðŒÄ‚яo‚³‚¸‚ɁA
+                “Á’è‚̐l‚É•R•t‚­ƒCƒxƒ“ƒg‚ðŠÈ’P‚ɃiƒrƒQ[ƒg‚·‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+                Ž„‚½‚¿‚ÍJava‚̃RƒŒƒNƒVƒ‡ƒ“A<literal>Set</literal> ‚ðŽg‚¢‚Ü‚·B
+                ƒRƒŒƒNƒVƒ‡ƒ“‚͏d•¡—v‘f‚ðŽ‚½‚È‚¢‚µA‡”Ô‚ÍŽ„‚½‚¿‚ɂ͈Ӗ¡‚ª‚È‚¢‚©‚ç‚Å‚·B
+            </para>
+
+            <para>
+                <literal>Set</literal> ‚ÅŽÀ‘•‚³‚ê‚é’P•ûŒüA‘½’lŠÖ˜A‚ª•K—v‚Å‚·B
+                JavaƒNƒ‰ƒX“à‚ɑΉž‚·‚éƒR[ƒh‚ð‘‚¢‚ă}ƒbƒsƒ“ƒO‚µ‚Ü‚µ‚傤F
+            </para>
+
+            <programlisting><![CDATA[public class Person {
+
+    private Set events = new HashSet();
+
+    public Set getEvents() {
+        return events;
+    }
+
+    public void setEvents(Set events) {
+        this.events = events;
+    }
+}]]></programlisting>
+
+            <para>
+                ‚±‚ÌŠÖ˜A‚ðƒ}ƒbƒsƒ“ƒO‚·‚é‘O‚ɁA”½‘Α¤‚ɂ‚¢‚čl‚¦‚Ä‚­‚¾‚³‚¢B
+                –¾‚ç‚©‚È‚±‚Æ‚Å‚·‚ªA¡‚Í‚±‚ê‚ð’P•ûŒü‚É‚µ‚½‚¾‚¯‚Å‚·B
+                ‹t‚ɁA <literal>Event</literal> ‘¤‚É‚à•Ê‚̃RƒŒƒNƒVƒ‡ƒ“‚ðì‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+                —Ⴆ‚Î <literal>anEvent.getParticipants()</literal> ‚̂悤‚ɁA
+                ‘o•ûŒü‚ɃiƒrƒQ[ƒg‚µ‚½‚¯‚ê‚΁A‚»‚¤‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+                ‚±‚ê‚Í‹@”\“I‚É‚Ý‚Ä•K—v‚Å‚Í‚ ‚è‚Ü‚¹‚ñB
+                “Á’è‚̃Cƒxƒ“ƒg‚ÉŠÖŒW‚·‚éƒf[ƒ^‚ðŽæ“¾‚·‚é–¾Šm‚ȃNƒGƒŠ‚ðA‚¢‚‚łàŽÀs‚·‚邱‚Æ‚ªo—ˆ‚Ü‚µ‚½B
+                ‚±‚̐݌v‚Ì‘I‘ð‚ÍŠJ”­ŽÒ‚É”C‚³‚ê‚Ä‚¢‚āA‚±‚Ì‹c˜_‚É‚æ‚è–¾‚ç‚©‚È‚Ì‚ÍŠÖ˜A‚Ì‘½d“x‚Å‚·B
+                ‚‚܂藼‘¤‚ðu‘½v’l‚É‚·‚éA <emphasis>‘½‘Α½</emphasis> ‚ƌĂ΂ê‚éŠÖ˜A‚Å‚·B
+                ‚»‚Ì‚½‚ßHibernate‚Ìmany-to-manyƒ}ƒbƒsƒ“ƒO‚ðŽg‚¢‚Ü‚·F
+            </para>
+
+            <programlisting><![CDATA[<class name="events.Person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="native"/>
+    </id>
+    <property name="age"/>
+    <property name="firstname"/>
+    <property name="lastname"/>
+
+    <set name="events" table="PERSON_EVENT">
+        <key column="PERSON_ID"/>
+        <many-to-many column="EVENT_ID" class="events.Event"/>
+    </set>
+
+</class>]]></programlisting>
+
+            <para>
+                Hibernate‚Í‚ ‚è‚Æ‚ ‚ç‚ä‚éŽí—ނ̃RƒŒƒNƒVƒ‡ƒ“ƒ}ƒbƒsƒ“ƒO‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·‚ªA
+                Å‚àˆê”Ê“I‚È‚à‚Ì‚ª <literal>&lt;set&gt;</literal> ‚Å‚·B
+                ‘½‘Α½ŠÖ˜Ai‚Ü‚½‚Í <emphasis>n:m</emphasis> ƒGƒ“ƒeƒBƒeƒBƒŠƒŒ[ƒVƒ‡ƒ“ƒVƒbƒvj‚ɂ́A
+                ŠÖ˜Aƒe[ƒuƒ‹‚ª•K—v‚Å‚·B
+                ‚±‚̃e[ƒuƒ‹‚Ì‚»‚ꂼ‚ê‚̍s‚́Al‚ƃCƒxƒ“ƒgŠÔ‚̃Šƒ“ƒN‚ð•\Œ»‚µ‚Ü‚·B
+                ƒe[ƒuƒ‹–¼‚Í <literal>set</literal> —v‘f‚Ì <literal>table</literal> ‘®«‚Őݒ肵‚Ü‚·B
+                l‘¤‚ÌŠÖ˜A‚ÌŽ¯•ÊŽqƒJƒ‰ƒ€–¼‚Í <literal>&lt;key&gt;</literal> —v‘f‚ŁA
+                ƒCƒxƒ“ƒg‘¤‚̃Jƒ‰ƒ€–¼‚Í <literal>&lt;many-to-many&gt;</literal> ‚Ì <literal>column</literal> 
+                ‘®«‚Å’è‹`‚µ‚Ü‚·B
+                Hibernate‚ɃRƒŒƒNƒVƒ‡ƒ“‚̃IƒuƒWƒFƒNƒg‚̃Nƒ‰ƒX
+                i³Šm‚ɂ́AŽQÆ‚̃RƒŒƒNƒVƒ‡ƒ“‚Ì”½‘Α¤‚̃Nƒ‰ƒXj‚ð‹³‚¦‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+            </para>
+
+            <para>
+                ‚»‚Ì‚½‚ß‚±‚̃}ƒbƒsƒ“ƒO‚̃f[ƒ^ƒx[ƒXƒXƒL[ƒ}‚͈ȉº‚̂悤‚É‚È‚è‚Ü‚·BF
+            </para>
+
+            <programlisting><![CDATA[
+    _____________        __________________
+   |             |      |                  |       _____________
+   |   EVENTS    |      |   PERSON_EVENT   |      |             |
+   |_____________|      |__________________|      |    PERSON   |
+   |             |      |                  |      |_____________|
+   | *EVENT_ID   | <--> | *EVENT_ID        |      |             |
+   |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  |
+   |  TITLE      |      |__________________|      |  AGE        |
+   |_____________|                                |  FIRSTNAME  |
+                                                  |  LASTNAME   |
+                                                  |_____________|
+ ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-working" revision="2">
+            <title>ŠÖ˜A‚ð“­‚©‚¹‚é</title>
+
+            <para>
+                <literal>EventManager</literal> ‚̐V‚µ‚¢ƒƒ\ƒbƒh‚ŐlX‚ƃCƒxƒ“ƒg‚ðˆê‚É‚µ‚Ü‚µ‚傤F
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    aPerson.getEvents().add(anEvent);
+
+    session.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                <literal>Person</literal> ‚Æ <literal>Event</literal> ‚ðƒ[ƒh‚µ‚½ŒãA
+                •’ʂ̃RƒŒƒNƒVƒ‡ƒ“ƒƒ\ƒbƒh‚ðŽg‚Á‚Ä’Pƒ‚É‚»‚̃RƒŒƒNƒVƒ‡ƒ“‚ðC³‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚²——‚Ì‚Æ‚¨‚è <literal>update()</literal> ‚â <literal>save()</literal> 
+                ‚Ì–¾Ž¦“I‚ȌĂяo‚µ‚Í‚ ‚è‚Ü‚¹‚ñB
+                Hibernate‚́AC³‚³‚ꂽ‚±‚Æ‚É‚æ‚èXV‚·‚é•K—v‚Ì‚ ‚éƒRƒŒƒNƒVƒ‡ƒ“‚ðŽ©“®“I‚ÉŒŸ’m‚µ‚Ü‚·B
+                ‚±‚ê‚Í <emphasis>Ž©“®ƒ_[ƒeƒBƒ`ƒFƒbƒN</emphasis> ‚ƌĂ΂êA
+                ƒIƒuƒWƒFƒNƒg‚Ì–¼‘O‚âdateƒvƒƒpƒeƒB‚ðC³‚·‚邱‚Æ‚ÅŽŽ‚·‚±‚Æ‚à‰Â”\‚Å‚·B
+                ‚»‚ê‚炪 <emphasis>‰i‘±</emphasis> ó‘Ô‚É‚ ‚éŒÀ‚èA
+                ‚‚܂è“Á’è‚ÌHibernate <literal>Session</literal> ‚ɃoƒCƒ“ƒh‚³‚ê‚Ä‚¢‚éŒÀ‚è
+                i—Ⴆ‚΍ì‹Æ’PˆÊ(Unit of Work)‚Ì’†‚Å’P‚Ƀ[ƒh‚Ü‚½‚̓Z[ƒu‚³‚ꂽjA
+                Hibernate‚Í‚Ç‚ñ‚ȕύX‚àƒ‚ƒjƒ^[‚µA’x‰„‘‚«ž‚Ý(write-behind)‚ÅSQL‚ðŽÀs‚µ‚Ü‚·B
+                ’ʏíAì‹Æ’PˆÊ(Unit of Work)‚̍Ōã‚É‚¾‚¯s‚í‚ê‚éƒf[ƒ^ƒx[ƒX‚ƃƒ‚ƒŠ‚̏ó‘Ԃ𓯊ú‚³‚¹‚鏈—‚́A
+                <emphasis>ƒtƒ‰ƒbƒVƒ…</emphasis> ‚ƌĂ΂ê‚Ü‚·B
+                ‚±‚̃R[ƒh‚ł́Aì‹Æ’PˆÊ(Unit of Work)‚̓f[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚̃Rƒ~ƒbƒgi‚à‚µ‚­‚̓[ƒ‹ƒoƒbƒNj‚ŏI—¹‚µ‚Ü‚·B
+                ‚±‚ê‚́A <literal>CurrentSessionContext</literal> ƒNƒ‰ƒX‚ɑ΂µ‚Ä <literal>thread</literal> ‚ðÝ’肵‚½‚½‚ß‚Å‚·B
+            </para>
+
+            <para>
+                ˆÙ‚È‚éì‹Æ’PˆÊ(Unit of Work)‚ŐlX‚ƃCƒxƒ“ƒg‚ðƒ[ƒh‚·‚邱‚Æ‚à“–‘R‚Å‚«‚Ü‚·B
+                ‚»‚¤‚Å‚È‚¯‚ê‚΁A‰i‘±ó‘Ô‚É‚È‚¢‚Æ‚«iˆÈ‘O‚ɉi‘±‚Å‚ ‚Á‚½‚È‚çA‚±‚̏ó‘Ô‚ð <emphasis>•ª—£idetachedj</emphasis> 
+                ‚ƌĂт܂·jA <literal>Session</literal> ‚ÌŠO•”‚ŃIƒuƒWƒFƒNƒg‚ðC³‚µ‚Ü‚·B
+                •ª—£‚³‚ê‚é‚Æ‚«‚ɂ̓RƒŒƒNƒVƒ‡ƒ“‚ð•ÏX‚·‚邱‚Æ‚à‰Â”\‚Å‚·F
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session
+            .createQuery("select p from Person p left join fetch p.events where p.id = :pid")
+            .setParameter("pid", personId)
+            .uniqueResult(); // Eager fetch the collection so we can use it detached
+
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    session.getTransaction().commit();
+
+    // End of first unit of work
+
+    aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached
+
+    // Begin second unit of work
+
+    Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
+    session2.beginTransaction();
+
+    session2.update(aPerson); // Reattachment of aPerson
+
+    session2.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                <literal>update</literal> ‚̌Ăяo‚µ‚Í•ª—£ƒIƒuƒWƒFƒNƒg‚ðÄ‚щi‘±‰»‚µ‚Ü‚·B
+                ‚±‚ê‚́AV‚µ‚¢ì‹Æ’PˆÊ(Unit of Work)‚ɃoƒCƒ“ƒh‚·‚é‚ÆŒ¾‚¦‚é‚Å‚µ‚傤B
+                ‚»‚Ì‚½‚ß•ª—£‚̊ԂɉÁ‚¦‚ç‚ꂽ‚ǂ̂悤‚ȏC³‚àƒf[ƒ^ƒx[ƒX‚ɃZ[ƒu‚Å‚«‚Ü‚·B
+                ƒGƒ“ƒeƒBƒeƒBƒIƒuƒWƒFƒNƒg‚̃RƒŒƒNƒVƒ‡ƒ“‚ւ̏C³i’ljÁ¥íœj‚à“¯—l‚ɃZ[ƒu‚Å‚«‚Ü‚·B
+            </para>
+
+            <para>
+                ‚±‚ê‚͍¡‚Í‚ ‚Ü‚èŽg‚¢‚Ý‚¿‚ª‚ ‚è‚Ü‚¹‚ñ‚ªA
+                Ž©•ª‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚̐݌v‚É‘g‚ݍž‚Þ‚±‚Æ‚ª‚Å‚«‚éd—v‚ȃRƒ“ƒZƒvƒg‚Å‚·B
+                ‚»‚ê‚Å‚Í‚±‚̃GƒNƒTƒTƒCƒY‚̍Ōã‚ɁA
+                <literal>EventManager</literal> ‚̃ƒCƒ“ƒƒ\ƒbƒh‚ɐV‚µ‚¢ƒAƒNƒVƒ‡ƒ“‚ð’ljÁ‚µ‚Ä
+                ƒRƒ}ƒ“ƒhƒ‰ƒCƒ“‚©‚çŒÄ‚яo‚µ‚Ä‚Ý‚Ü‚µ‚傤B
+                l‚âƒCƒxƒ“ƒg‚ÌŽ¯•ÊŽq‚ª•K—v‚È‚çA <literal>save()</literal> ƒƒ\ƒbƒh‚ª•Ô‚µ‚Ä‚­‚ê‚Ü‚·
+                iê‡‚É‚æ‚Á‚Ä‚ÍŽ¯•ÊŽq‚ð•Ô‚·‚½‚߂Ƀƒ\ƒbƒh‚ðC³‚·‚é•K—v‚ª‚ ‚é‚©‚à‚µ‚ê‚Ü‚¹‚ñjB
+            </para>
+
+            <programlisting><![CDATA[else if (args[0].equals("addpersontoevent")) {
+    Long eventId = mgr.createAndStoreEvent("My Event", new Date());
+    Long personId = mgr.createAndStorePerson("Foo", "Bar");
+    mgr.addPersonToEvent(personId, eventId);
+    System.out.println("Added person " + personId + " to event " + eventId);
+}]]></programlisting>
+
+            <para>
+                ‚±‚ê‚Í“¯‚¶‚悤‚ɏd—v‚È2‚‚̃Nƒ‰ƒXA‚‚܂è2‚‚̃Gƒ“ƒeƒBƒeƒBŠÔ‚ÌŠÖ˜A‚Ì—á‚Å‚µ‚½B
+                ‘O‚ɏq‚ׂ½‚悤‚ɁA“TŒ^“I‚ȃ‚ƒfƒ‹‚ɂ́A•’ʁu”äŠr“Id—v‚Å‚Í‚È‚¢v‘¼‚̃Nƒ‰ƒX‚ÆŒ^‚ª‚ ‚è‚Ü‚·B
+                ‚±‚ê‚Ü‚Å‚ÉŒ©‚½‚悤‚È <literal>int</literal> ‚â <literal>String</literal> ‚̂悤‚È‚à‚Ì‚Å‚·B
+                ‚±‚̂悤‚ȃNƒ‰ƒX‚ð <emphasis>’lŒ^</emphasis> ‚ÆŒ¾‚¢‚Ü‚·B
+                ‚±‚̃Cƒ“ƒXƒ^ƒ“ƒX‚Í“Á’è‚̃Gƒ“ƒeƒBƒeƒB‚É <emphasis>ˆË‘¶</emphasis> ‚µ‚Ü‚·B
+                ‚±‚ÌŒ^‚̃Cƒ“ƒXƒ^ƒ“ƒX‚Í“ÆŽ©‚ÌID‚ðŽ‚¿‚Ü‚¹‚ñ‚µA
+                ƒGƒ“ƒeƒBƒeƒBŠÔ‚Å‹¤—L‚³‚ê‚邱‚Æ‚à‚ ‚è‚Ü‚¹‚ñ
+                iƒtƒ@[ƒXƒgƒl[ƒ€‚ª“¯‚¶‚¾‚Á‚½‚Æ‚µ‚Ä‚àA2l‚̐l‚Í“¯‚¶ <literal>firstname</literal> 
+                ƒIƒuƒWƒFƒNƒg‚ðŽQÆ‚µ‚Ü‚¹‚ñjB
+                ’lŒ^‚Í‚à‚¿‚ë‚ñJDK“à‚ÉŒ©‚‚©‚è‚Ü‚·‚ªA‚»‚ꂾ‚¯‚Å‚Í‚È‚­
+                iŽÀÛAHibernateƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚¨‚¢‚Ä‚·‚ׂĂÌJDKƒNƒ‰ƒX‚Í’lŒ^‚ÆŒ©‚È‚¹‚Ü‚·jA
+                —Ⴆ‚Î <literal>Address</literal> ‚â <literal>MonetaryAmount</literal> 
+                ‚̂悤‚È“ÆŽ©‚̈ˑ¶ƒNƒ‰ƒX‚ð‘‚­‚±‚Æ‚à‚Å‚«‚Ü‚·B
+            </para>
+
+            <para>
+                ’lŒ^‚̃RƒŒƒNƒVƒ‡ƒ“‚ðÝŒv‚·‚邱‚Æ‚à‚Å‚«‚Ü‚·B
+                ‚±‚ê‚Í‘¼‚̃Gƒ“ƒeƒBƒeƒB‚Ö‚ÌŽQÆ‚̃RƒŒƒNƒVƒ‡ƒ“‚Æ‚ÍŠT”O“I‚É”ñí‚ɈقȂè‚Ü‚·‚ªA
+                Java‚Å‚Í‚Ù‚Æ‚ñ‚Ç“¯‚¶‚悤‚ÉŒ©‚¦‚Ü‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-valuecollections">
+            <title>’l‚̃RƒŒƒNƒVƒ‡ƒ“</title>
+
+            <para>
+                ’lŒ^ƒIƒuƒWƒFƒNƒg‚̃RƒŒƒNƒVƒ‡ƒ“‚ð <literal>Person</literal> ƒGƒ“ƒeƒBƒeƒB‚֒ljÁ‚µ‚Ü‚·B
+                Eƒ[ƒ‹ƒAƒhƒŒƒX‚ðŠi”[‚µ‚½‚¢‚Ì‚Å‚·‚ªA<literal>String</literal> Œ^‚ðŽg‚Á‚Ä‚¢‚é‚̂ŁA
+                ƒRƒŒƒNƒVƒ‡ƒ“‚ÍÄ‚Ñ <literal>Set</literal> ‚Å‚·F
+            </para>
+            <programlisting><![CDATA[private Set emailAddresses = new HashSet();
+
+public Set getEmailAddresses() {
+    return emailAddresses;
+}
+
+public void setEmailAddresses(Set emailAddresses) {
+    this.emailAddresses = emailAddresses;
+}]]></programlisting>
+
+            <para>
+                ‚±‚Ì <literal>Set</literal> ‚̃}ƒbƒsƒ“ƒO‚Å‚·F
+            </para>
+
+            <programlisting><![CDATA[<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
+    <key column="PERSON_ID"/>
+    <element type="string" column="EMAIL_ADDR"/>
+</set>]]></programlisting>
+
+            <para>
+                ‘O‚̃}ƒbƒsƒ“ƒO‚Æ”ä‚ׂĈႤ‚Ì‚Í <literal>element</literal> ‚Ì•”•ª‚Å‚·‚ªA
+                Hibernate‚É‚±‚̃RƒŒƒNƒVƒ‡ƒ“‚ª‘¼‚̃Gƒ“ƒeƒBƒeƒB‚Ö‚ÌŽQÆ‚ðŠÜ‚Ü‚¸A
+                <literal>String</literal> Œ^‚Ì—v‘f‚̃RƒŒƒNƒVƒ‡ƒ“‚ðŠÜ‚Þ‚±‚Æ‚ð‹³‚¦‚Ü‚·B
+                i¬•¶Žš‚Ì–¼‘O(string)‚ÍHibernate‚̃}ƒbƒsƒ“ƒOŒ^‚Ü‚½‚̓Rƒ“ƒo[ƒ^‚Å‚ ‚é‚Æ‚¢‚¤‚±‚Æ‚Å‚·jB
+                ŒJ‚è•Ô‚µ‚Ü‚·‚ªA<literal>set</literal> —v‘f‚Ì <literal>table</literal> ‘®«‚́A
+                ƒRƒŒƒNƒVƒ‡ƒ“‚Ì‚½‚߂̃e[ƒuƒ‹–¼‚ðŽw’肵‚Ü‚·B
+                <literal>key</literal> —v‘f‚̓RƒŒƒNƒVƒ‡ƒ“ƒe[ƒuƒ‹‚ÌŠO•”ƒL[ƒJƒ‰ƒ€–¼‚ð’è‹`‚µ‚Ü‚·B
+                <literal>element</literal> —v‘f‚Ì <literal>column</literal> ‘®«‚Í <literal>String</literal> 
+                ‚Ì’l‚ªŽÀÛ‚ÉŠi”[‚³‚ê‚éƒJƒ‰ƒ€‚Ì–¼‘O‚ð’è‹`‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                XV‚µ‚½ƒXƒL[ƒ}‚ðŒ©‚Ä‚­‚¾‚³‚¢F
+            </para>
+
+            <programlisting><![CDATA[
+  _____________        __________________
+ |             |      |                  |       _____________
+ |   EVENTS    |      |   PERSON_EVENT   |      |             |       ___________________
+ |_____________|      |__________________|      |    PERSON   |      |                   |
+ |             |      |                  |      |_____________|      | PERSON_EMAIL_ADDR |
+ | *EVENT_ID   | <--> | *EVENT_ID        |      |             |      |___________________|
+ |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  | <--> |  *PERSON_ID       |
+ |  TITLE      |      |__________________|      |  AGE        |      |  *EMAIL_ADDR      |
+ |_____________|                                |  FIRSTNAME  |      |___________________|
+                                                |  LASTNAME   |
+                                                |_____________|
+ ]]></programlisting>
+
+            <para>
+                ƒRƒŒƒNƒVƒ‡ƒ“ƒe[ƒuƒ‹‚ÌŽåƒL[‚́AŽÀÛ‚Í—¼•û‚̃Jƒ‰ƒ€‚ðŽg‚Á‚½•¡‡ƒL[‚Å‚ ‚邱‚Æ‚ª‚í‚©‚è‚Ü‚·B
+                ‚±‚ê‚͐l‚²‚Æ‚ÉEƒ[ƒ‹ƒAƒhƒŒƒX‚ªd•¡‚Å‚«‚È‚¢‚Æ‚¢‚¤‚±‚ƂŁA
+                Java‚Ìset‚É—v‹‚³‚ê‚éƒZƒ}ƒ“ƒeƒBƒNƒX‚»‚Ì‚à‚Ì‚Å‚·B
+            </para>
+
+            <para>
+                ˆÈ‘Ol‚ƃCƒxƒ“ƒg‚ðŠÖ˜A‚¯‚½‚Æ‚«‚Æ‘S‚­“¯‚¶‚悤‚ɁA
+                ¡‚⎎‚µ‚ɃRƒŒƒNƒVƒ‡ƒ“‚É—v‘f‚ð’ljÁ‚·‚邱‚Æ‚ª‚Å‚«‚é‚悤‚É‚È‚è‚Ü‚µ‚½B
+                —¼•û‚Æ‚àJava‚Å‚Í“¯‚¶ƒR[ƒh‚Å‚·B
+            </para>
+
+            <programlisting><![CDATA[private void addEmailToPerson(Long personId, String emailAddress) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+
+    // The getEmailAddresses() might trigger a lazy load of the collection
+    aPerson.getEmailAddresses().add(emailAddress);
+
+    session.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                ¡‰ñAƒRƒŒƒNƒVƒ‡ƒ“‚̏‰Šú‰»‚É <emphasis>fetch</emphasis> ƒNƒGƒŠ‚ðŽg—p‚µ‚Ü‚¹‚ñ‚Å‚µ‚½B
+                ‚»‚Ì‚½‚߁Agetterƒƒ\ƒbƒh‚̌Ăяo‚µ‚É‚æ‚Á‚ăRƒŒƒNƒVƒ‡ƒ“‚ð‰Šú‰»‚·‚邽‚ß‚ÌSELECT‚ª
+                ŽÀs‚³‚ê‚é‚̂ŁAƒRƒŒƒNƒVƒ‡ƒ“‚É—v‘f‚ð’ljÁ‚Å‚«‚Ü‚·B
+                SQL‚̃ƒO‚ðŠÄŽ‹‚µ‚āA‘¦ŽžƒtƒFƒbƒ`‚ðŽg‚Á‚čœK‰»‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-bidirectional" revision="1">
+            <title>‘o•ûŒüŠÖ˜A</title>
+
+            <para>
+                ŽŸ‚É‘o•ûŒüŠÖ˜A‚ðƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·B
+                Java‚Å—¼‘¤‚©‚çl‚ƃCƒxƒ“ƒg‚ÌŠÖ˜A‚𓮍삳‚¹‚Ü‚·B
+                ‚à‚¿‚ë‚ñAƒf[ƒ^ƒx[ƒXƒXƒL[ƒ}‚Í•Ï‚í‚è‚Ü‚¹‚ñ‚ªA‘½d“x‚Í‘½‘Α½‚Ì‚Ü‚Ü‚Å‚·B
+                ƒŠƒŒ[ƒVƒ‡ƒiƒ‹ƒf[ƒ^ƒx[ƒX‚̓lƒbƒgƒ[ƒNƒvƒƒOƒ‰ƒ~ƒ“ƒOŒ¾Œê‚æ‚è‚à_“î‚Ȃ̂ŁA
+                ƒiƒrƒQ[ƒVƒ‡ƒ“‚Ì•ûŒü‚̂悤‚È‚à‚Ì‚ð•K—v‚Æ‚µ‚Ü‚¹‚ñB
+                ƒf[ƒ^‚Í‚ ‚ç‚ä‚é‚Ì•û–@‚ÅŒ©‚½‚è•œŒ³‚Å‚«‚é‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+            </para>
+
+            <para>
+                ‚Ü‚¸ <literal>Event</literal> ƒCƒxƒ“ƒgƒNƒ‰ƒX‚ÉŽQ‰ÁŽÒ‚̃RƒŒƒNƒVƒ‡ƒ“‚ð’ljÁ‚µ‚Ü‚·F
+            </para>
+
+            <programlisting><![CDATA[private Set participants = new HashSet();
+
+public Set getParticipants() {
+    return participants;
+}
+
+public void setParticipants(Set participants) {
+    this.participants = participants;
+}]]></programlisting>
+
+            <para>
+                ‚»‚ê‚Å‚Í <literal>Event.hbm.xml</literal> ‚ÅŠÖ˜A‚Ì‚±‚¿‚瑤‚ðƒ}ƒbƒsƒ“ƒO‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <programlisting><![CDATA[<set name="participants" table="PERSON_EVENT" inverse="true">
+    <key column="EVENT_ID"/>
+    <many-to-many column="PERSON_ID" class="events.Person"/>
+</set>]]></programlisting>
+
+            <para>
+                ‚²——‚Ì‚Æ‚¨‚èA‚¢‚¸‚ê‚̃}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg(XMLƒtƒ@ƒCƒ‹)‚Å‚àA•’Ê‚Ì <literal>set</literal> 
+                ƒ}ƒbƒsƒ“ƒO‚ðŽg‚Á‚Ä‚¢‚Ü‚·B
+                <literal>key</literal> ‚Æ <literal>many-to-many</literal> ‚̃Jƒ‰ƒ€–¼‚ªA
+                —¼•û‚̃}ƒbƒsƒ“ƒOƒhƒLƒ…ƒƒ“ƒg‚Å“ü‚ê‘Ö‚¦‚É‚È‚Á‚Ä‚¢‚邱‚Æ‚É’–Ú‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚±‚±‚ōłàd—v‚ȒljÁ€–ڂ́A <literal>Event</literal> ‚̃RƒŒƒNƒVƒ‡ƒ“ƒ}ƒbƒsƒ“ƒO‚Ì <literal>set</literal> 
+                —v‘f‚É‚ ‚é <literal>inverse="true"</literal> ‘®«‚Å‚·B
+            </para>
+
+            <para>
+                ‚±‚ÌŽw’è‚̈Ӗ¡‚́A2‚‚̊Ԃ̃Gƒ“ƒeƒBƒeƒBŠÔ‚̃Šƒ“ƒN‚ɂ‚¢‚Ă̏î•ñ‚ð’T‚·•K—v‚ª‚ ‚é‚Æ‚«A
+                Hibernate‚Í”½‘Α¤‚̃Gƒ“ƒeƒBƒeƒBA‚‚܂è <literal>Person</literal> ƒNƒ‰ƒX‚©‚ç’T‚·‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+                ˆê“x2‚‚̃Gƒ“ƒeƒBƒeƒBŠÔ‚Ì‘o•ûŒüƒŠƒ“ƒN‚ª‚ǂ̂悤‚ɍ쐬‚³‚ê‚é‚©‚ª‚í‚©‚ê‚΁A
+                ‚±‚ê‚ð—‰ð‚·‚é‚±‚Æ‚Í‚Æ‚Ä‚àŠÈ’P‚Å‚·B
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-usingbidir">
+            <title>‘o•ûŒüƒŠƒ“ƒN‚Ì“®ì</title>
+
+            <para>
+                ‚Ü‚¸AHibernate‚ª’ʏí‚ÌJava‚̃Zƒ}ƒ“ƒeƒBƒNƒX‚ɉe‹¿‚ð‹y‚Ú‚³‚È‚¢‚±‚Æ‚ðS‚É—¯‚ß‚Ä‚¨‚¢‚Ä‚­‚¾‚³‚¢B
+                Ž„‚½‚¿‚́A’P•ûŒü‚Ì—á‚Æ‚µ‚Ăǂ̂悤‚É <literal>Person</literal> ‚Æ <literal>Event</literal> 
+                ‚̊Ԃ̃Šƒ“ƒN‚ðì¬‚µ‚½‚Å‚µ‚傤‚©H
+                <literal>Person</literal> ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚̃Cƒxƒ“ƒg‚Ö‚ÌŽQÆ‚̃RƒŒƒNƒVƒ‡ƒ“‚É
+                <literal>Event</literal> ‚̃Cƒ“ƒXƒ^ƒ“ƒX‚ð’ljÁ‚µ‚Ü‚µ‚½B
+                ‚»‚Ì‚½‚ß‚±‚̃Šƒ“ƒN‚ð‘o•ûŒü‚É‚µ‚½‚¯‚ê‚΁A
+                “–‚½‚è‘O‚Å‚·‚ª”½‘Α¤‚É‚à“¯‚¶‚±‚Æ‚ð‚µ‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                <literal>Event</literal> ‚̃RƒŒƒNƒVƒ‡ƒ“‚É <literal>Person</literal> ‚Ö‚Ì
+                ŽQÆ‚ð’ljÁ‚·‚é‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+                ‚±‚́u—¼‘¤‚ŃŠƒ“ƒN‚ðÝ’è‚·‚邱‚Ɓv‚͐â‘΂ɕK—v‚Ȃ̂ŁAŒˆ‚µ‚Ä–Y‚ê‚È‚¢‚Å‚­‚¾‚³‚¢B
+            </para>
+
+            <para>
+                ‘½‚­‚ÌŠJ”­ŽÒ‚͐Td‚ɃvƒƒOƒ‰ƒ€‚·‚é‚̂ŁA
+                ƒGƒ“ƒeƒBƒeƒB‚Ì—¼‘¤‚ɐ³‚µ‚­ŠÖ˜A‚ðÝ’è‚·‚郊ƒ“ƒNŠÇ—ƒƒ\ƒbƒh‚ðì¬‚µ‚Ü‚·B
+                —Ⴆ‚Î <literal>Person</literal> ‚ł͈ȉº‚̂悤‚É‚È‚è‚Ü‚·BF
+            </para>
+
+            <programlisting><![CDATA[protected Set getEvents() {
+    return events;
+}
+
+protected void setEvents(Set events) {
+    this.events = events;
+}
+
+public void addToEvent(Event event) {
+    this.getEvents().add(event);
+    event.getParticipants().add(this);
+}
+
+public void removeFromEvent(Event event) {
+    this.getEvents().remove(event);
+    event.getParticipants().remove(this);
+}]]></programlisting>
+
+            <para>
+                ƒRƒŒƒNƒVƒ‡ƒ“‚̃Qƒbƒg‚ƃZƒbƒgƒƒ\ƒbƒh‚ªŒ»Ýprotected‚É‚È‚Á‚Ä‚¢‚邱‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚±‚ê‚Í“¯‚¶ƒpƒbƒP[ƒW‚̃Nƒ‰ƒX‚âƒTƒuƒNƒ‰ƒX‚̃ƒ\ƒbƒh‚͈ˑRƒAƒNƒZƒX‚ª‰Â”\‚Å‚·‚ªA
+                i‚Ù‚Æ‚ñ‚ǁj‚»‚̃pƒbƒP[ƒWŠO‚̂ǂ̃Nƒ‰ƒX‚Å‚à’¼Ú‚»‚̃RƒŒƒNƒVƒ‡ƒ“‚ð‘ä–³‚µ‚É‚·‚邱‚Æ‚ð–h‚¬‚Ü‚·B
+                ‚¨‚»‚ç‚­”½‘Α¤‚̃RƒŒƒNƒVƒ‡ƒ“‚É‚à“¯‚¶‚±‚Æ‚ð‚µ‚½•û‚ª‚¢‚¢‚Å‚µ‚傤B
+            </para>
+
+            <para>
+                <literal>inverse</literal> ƒ}ƒbƒsƒ“ƒO‘®«‚Æ‚Í‚¢‚Á‚½‚¢‰½‚Å‚µ‚傤‚©H
+                ŠJ”­ŽÒ‚ÆJava‚É‚Æ‚Á‚ẮA‘o•ûŒüƒŠƒ“ƒN‚Í’P‚É—¼‘¤‚ÌŽQÆ‚𐳂µ‚­Ý’è‚·‚é‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+                ‚µ‚©‚µHibernate‚́i§–ñˆá”½‚ð”ð‚¯‚é‚½‚߂ɁjSQL‚Ì <literal>INSERT</literal> ‚Æ <literal>UPDATE</literal> 
+                •¶‚𐳊m‚ɕύX‚·‚邽‚߂̏\•ª‚ȏî•ñ‚ðŽ‚Á‚Ä‚¢‚È‚¢‚̂ŁA
+                ‘o•ûŒüŠÖ˜AƒvƒƒpƒeƒB‚ðˆµ‚¤‚½‚߂̉½‚ç‚©‚̏•‚¯‚ð•K—v‚Æ‚µ‚Ü‚·B
+                ŠÖ˜A‚̕Б¤‚ð <literal>inverse</literal> ‚ɐݒ肷‚邱‚ƂŁAHibernate‚ÍŠî–{“I‚ɂ͐ݒ肵‚½‘¤‚𖳎‹‚µA
+                ”½‘Α¤‚Ì <emphasis>‹¾</emphasis> ‚Æ‚µ‚čl‚¦‚Ü‚·B
+                ‚±‚ꂾ‚¯‚ŁAHibernate‚Í•ûŒü‚ðŽ‚ÂƒiƒrƒQ[ƒVƒ‡ƒ“ƒ‚ƒfƒ‹‚ðSQLƒf[ƒ^ƒx[ƒXƒXƒL[ƒ}‚Ö•ÏŠ·‚·‚é‚Æ‚«‚Ì
+                ‚·‚ׂĂ̖â‘è‚É‚¤‚Ü‚­‘Ώˆ‚Å‚«‚Ü‚·B
+                Šo‚¦‚Ä‚¨‚©‚È‚¯‚ê‚΂Ȃç‚È‚¢ƒ‹[ƒ‹‚ÍŠÈ’P‚Å‚·B
+                ‘o•ûŒüŠÖ˜A‚Í•K‚¸•Ð‘¤‚ð <literal>inverse</literal> ‚É‚·‚é•K—v‚ª‚ ‚é‚Æ‚¢‚¤‚±‚Æ‚Å‚·B
+                ˆê‘Α½ŠÖ˜A‚Å‚Í‚»‚ê‚Í‘½‘¤‚Å‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñB
+                ‘½‘Α½ŠÖ˜A‚Å‚Í‚Ç‚¿‚瑤‚Å‚à\‚¢‚Ü‚¹‚ñB‚Ç‚¿‚ç‚Å‚àˆá‚¢‚Í‚ ‚è‚Ü‚¹‚ñB
+            </para>
+
+        </sect2>
+
+        <para>
+             ‚Å‚Í‚±‚ê‚ð¬‚³‚ÈWebƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚µ‚Ä‚Ý‚Ü‚µ‚傤B
+        </para>
+
+    </sect1>
+
+    <sect1 id="tutorial-webapp">
+        <title>ƒp[ƒg3 - EventManager WebƒAƒvƒŠƒP[ƒVƒ‡ƒ“</title>
+
+        <para>
+             Hibernate‚ÌWebƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚́AƒXƒ^ƒ“ƒhƒAƒ[ƒ“‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚̂悤‚É
+             <literal>Session</literal> ‚Æ <literal>Transaction</literal> ‚ðŽg—p‚µ‚Ü‚·B
+             ‚µ‚©‚µ‚¢‚­‚‚©‚̈ê”Ê“I‚ȃpƒ^[ƒ“‚ª–𗧂¿‚Ü‚·B
+             ‚±‚±‚Å <literal>EventManagerServlet</literal> ‚ðì¬‚µ‚Ü‚·B‚±‚̃T[ƒuƒŒƒbƒg‚́A
+             ƒf[ƒ^ƒx[ƒX‚ÉŠi”[‚µ‚½‘S‚ẴCƒxƒ“ƒg‚ðƒŠƒXƒg‚É‚Å‚«A‚³‚ç‚ÉHTMLƒtƒH[ƒ€‚©‚çV‚µ‚¢ƒCƒxƒ“ƒg‚ð“ü—Í‚Å‚«‚é‚à‚Ì‚Å‚·B
+        </para>
+
+        <sect2 id="tutorial-webapp-servlet" revision="1">
+            <title>Šî–{“I‚ÈServlet‚Ì‹Lq</title>
+
+            <para>
+                V‚µ‚¢ƒNƒ‰ƒX‚ðAƒ\[ƒXƒfƒBƒŒƒNƒgƒŠ‚Ì <literal>events</literal> ƒpƒbƒP[ƒW‚ɍ쐬‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+// Imports
+
+public class EventManagerServlet extends HttpServlet {
+
+    // Servlet code
+}]]></programlisting>
+
+            <para>
+                Servlet‚ÍHTTP‚Ì <literal>GET</literal> ƒŠƒNƒGƒXƒg‚Ì‚Ý‚ðˆ—‚·‚é‚̂ŁA
+                 <literal>doGet()</literal> ‚ðŽÀ‘•‚µ‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[protected void doGet(HttpServletRequest request,
+                     HttpServletResponse response)
+        throws ServletException, IOException {
+
+    SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
+
+    try {
+        // Begin unit of work
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().beginTransaction();
+
+        // Process request and render page...
+
+        // End unit of work
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().getTransaction().commit();
+
+    } catch (Exception ex) {
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().getTransaction().rollback();
+        throw new ServletException(ex);
+    }
+
+}]]></programlisting>
+
+            <para>
+                ‚±‚ê‚Í <emphasis>session-per-request</emphasis> ‚Æ‚¢‚¤ƒpƒ^[ƒ“‚Å‚·B
+                Servlet‚ªƒŠƒNƒGƒXƒg‚ðŽó‚¯Žæ‚é‚ƁA <literal>SessionFactory</literal> ‚Ì
+                <literal>getCurrentSession()</literal> ‚̍ŏ‰‚̌Ăяo‚µ‚ŁA
+                Hibernate‚̐V‚µ‚¢ <literal>Session</literal> ‚ªŠJ‚©‚ê‚Ü‚·B
+                ‚»‚Ì‚Æ‚«ƒf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ªŠJŽn‚³‚ê‚Ü‚·B
+                ƒf[ƒ^‚̓ǂݏ‘‚«‚ÉŠÖ‚í‚炸A‚·‚ׂẴf[ƒ^ƒAƒNƒZƒX‚̓gƒ‰ƒ“ƒUƒNƒVƒ‡ƒ““à‚ōs‚¢‚Ü‚·B
+                iƒAƒvƒŠƒP[ƒVƒ‡ƒ““à‚ł̓I[ƒgƒRƒ~ƒbƒgƒ‚[ƒh‚ðŽg—p‚µ‚Ü‚¹‚ñjB
+            </para>
+
+            <para>
+                ŽŸ‚ɁAƒŠƒNƒGƒXƒg‚̃AƒNƒVƒ‡ƒ“‚͏ˆ—‚³‚êAƒŒƒXƒ|ƒ“ƒX‚Å‚ ‚éHTML‚ª•`‰æ‚³‚ê‚Ü‚·B
+                ‚±‚ê‚ɂ‚¢‚Ä‚Í‚·‚®‚Éà–¾‚µ‚Ü‚·B
+            </para>
+
+            <para>
+                ÅŒã‚ɃŠƒNƒGƒXƒg‚̏ˆ—‚ÆHTML•`‰æ‚ªŠ®—¹‚µ‚½‚Æ‚«‚ɁAì‹Æ’PˆÊ(Unit of Work)‚ðI—¹‚µ‚Ü‚·B
+                ‚à‚µˆ—‚â•`‰æ’†‚É–â‘肪”­¶‚µ‚½ê‡Aexception‚ª“Š‚°‚ç‚ê‚ăf[ƒ^ƒx[ƒXƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‚ðƒ[ƒ‹ƒoƒbƒN‚µ‚Ü‚·B
+                ‚±‚ê‚Å <literal>session-per-request</literal> ƒpƒ^[ƒ“‚ªŠ®—¹‚µ‚Ü‚·B
+                ‘S‚ẴT[ƒuƒŒƒbƒg‚Ƀgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“‹«ŠE‚̃R[ƒh‚ð‘‚­‘ã‚í‚è‚ɁAƒT[ƒuƒŒƒbƒgƒtƒBƒ‹ƒ^‚É‹Lq‚·‚邱‚Æ‚à‰Â”\‚Å‚·B
+                <emphasis>Open Session in View</emphasis> ‚ƌĂ΂ê‚邱‚̃pƒ^[ƒ“‚ɂ‚¢‚ẮA
+                Hibernate‚ÌWebƒTƒCƒg‚âWiki‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+                ƒT[ƒuƒŒƒbƒg‚Å‚Í‚È‚­JSP‚ÅHTML•`‰æ‚ð‚µ‚æ‚¤‚Æ‚·‚é‚ƁA‚·‚®‚É‚±‚̃pƒ^[ƒ“‚ɂ‚¢‚Ă̏î•ñ‚ª•K—v‚É‚È‚é‚Å‚µ‚傤B
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-webapp-processing" revision="1">
+            <title>ˆ—‚Æ•`‰æ</title>
+
+            <para>
+                 ‚ł́AƒŠƒNƒGƒXƒg‚̏ˆ—‚ƃy[ƒW‚Ì•`‰æ‚ðŽÀ‘•‚µ‚Ü‚·B
+            </para>
+
+<programlisting><![CDATA[// Write HTML header
+PrintWriter out = response.getWriter();
+out.println("<html><head><title>Event Manager</title></head><body>");
+
+// Handle actions
+if ( "store".equals(request.getParameter("action")) ) {
+
+    String eventTitle = request.getParameter("eventTitle");
+    String eventDate = request.getParameter("eventDate");
+
+    if ( "".equals(eventTitle) || "".equals(eventDate) ) {
+        out.println("<b><i>Please enter event title and date.</i></b>");
+    } else {
+        createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
+        out.println("<b><i>Added event.</i></b>");
+    }
+}
+
+// Print page
+printEventForm(out);
+listEvents(out, dateFormatter);
+
+// Write HTML footer
+out.println("</body></html>");
+out.flush();
+out.close();]]></programlisting>
+
+            <para>
+                Java‚ÆHTML‚ª¬Ý‚·‚éƒR[ƒfƒBƒ“ƒOƒXƒ^ƒCƒ‹‚́A‚æ‚è•¡ŽG‚ȃAƒvƒŠƒP[ƒVƒ‡ƒ“‚É‚Í“K‚µ‚Ä‚¢‚È‚¢‚Å‚µ‚傤
+                i‚±‚̃`ƒ…[ƒgƒŠƒAƒ‹‚ł́AŠî–{“I‚ÈHibernate‚̃Rƒ“ƒZƒvƒg‚ðŽ¦‚µ‚Ä‚¢‚邾‚¯‚Å‚ ‚邱‚Æ‚ðŠo‚¦‚Ä‚¨‚¢‚Ä‚­‚¾‚³‚¢jB
+                ‚±‚̃R[ƒh‚ÍHTML‚̃wƒbƒ_[‚ƃtƒbƒ^[‚Ì‹Lq‚Å‚·B
+                ‚±‚̃y[ƒW‚ɂ́AƒCƒxƒ“ƒg‚ð“ü—Í‚·‚éHTMLƒtƒH[ƒ€‚ƁAƒf[ƒ^ƒx[ƒX‚É‚ ‚é‘S‚ẴCƒxƒ“ƒg‚̃ŠƒXƒg‚ª•\Ž¦‚³‚ê‚Ü‚·B
+                Å‰‚̃ƒ\ƒbƒh‚Í‚²‚­’Pƒ‚ÈHTMLo—Í‚Å‚·B
+            </para>
+
+            <programlisting><![CDATA[private void printEventForm(PrintWriter out) {
+    out.println("<h2>Add new event:</h2>");
+    out.println("<form>");
+    out.println("Title: <input name='eventTitle' length='50'/><br/>");
+    out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");
+    out.println("<input type='submit' name='action' value='store'/>");
+    out.println("</form>");
+}]]></programlisting>
+
+            <para>
+                 <literal>listEvents()</literal> ƒƒ\ƒbƒh‚́AŒ»Ý‚̃XƒŒƒbƒh‚ÉŒ‹‚т‚­
+                 Hibernate‚Ì <literal>Session</literal> ‚ðŽg—p‚µ‚āAƒNƒGƒŠ‚ðŽÀs‚µ‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) {
+
+    List result = HibernateUtil.getSessionFactory()
+                    .getCurrentSession().createCriteria(Event.class).list();
+    if (result.size() > 0) {
+        out.println("<h2>Events in database:</h2>");
+        out.println("<table border='1'>");
+        out.println("<tr>");
+        out.println("<th>Event title</th>");
+        out.println("<th>Event date</th>");
+        out.println("</tr>");
+        for (Iterator it = result.iterator(); it.hasNext();) {
+            Event event = (Event) it.next();
+            out.println("<tr>");
+            out.println("<td>" + event.getTitle() + "</td>");
+            out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
+            out.println("</tr>");
+        }
+        out.println("</table>");
+    }
+}]]></programlisting>
+
+            <para>
+                ÅŒã‚ɁA <literal>store</literal> ƒAƒNƒVƒ‡ƒ“‚ª <literal>createAndStoreEvent()</literal> ƒƒ\ƒbƒh‚ð
+                ŒÄ‚яo‚µ‚Ü‚·B‚±‚̃ƒ\ƒbƒh‚Å‚àŒ»Ý‚̃XƒŒƒbƒh‚Ì <literal>Session</literal> ‚ð—˜—p‚µ‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[protected void createAndStoreEvent(String title, Date theDate) {
+    Event theEvent = new Event();
+    theEvent.setTitle(title);
+    theEvent.setDate(theDate);
+
+    HibernateUtil.getSessionFactory()
+                    .getCurrentSession().save(theEvent);
+}]]></programlisting>
+
+            <para>
+                ‚±‚ê‚ŃT[ƒuƒŒƒbƒg‚ÌŠ®¬‚Å‚·B
+                ƒT[ƒuƒŒƒbƒg‚ւ̃ŠƒNƒGƒXƒg‚́Aˆê‚Â‚Ì <literal>Session</literal> ‚Æ 
+                <literal>Transaction</literal> ‚ŏˆ—‚³‚ê‚é‚Å‚µ‚傤B
+                Å‰‚̃Xƒ^ƒ“ƒhƒAƒ[ƒ“‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚̂悤‚ɁA
+                Hibernate‚ÍŽ©“®“I‚É‚±‚ê‚ç‚̃IƒuƒWƒFƒNƒg‚ðŽÀs‚·‚éƒXƒŒƒbƒh‚ÉŒ‹‚Ñ•t‚¯‚邱‚Æ‚ª‚Å‚«‚Ü‚·B
+                ‚±‚ê‚É‚æ‚èAŠJ”­ŽÒ‚ªŽ©—R‚ɃR[ƒh‚ðƒŒƒCƒ„[•ª‚¯‚Å‚«A
+                D‚«‚È•û–@‚Å <literal>SessionFactory</literal> ‚ւ̃AƒNƒZƒX‚ª‚Å‚«‚é‚悤‚É‚È‚è‚Ü‚·B
+                ’ʏíAŠJ”­ŽÒ‚Í‚æ‚èô—û‚³‚ꂽƒfƒUƒCƒ“‚ðŽg—p‚µ‚āAƒf[ƒ^ƒAƒNƒZƒX‚̃R[ƒh‚ð
+                ƒf[ƒ^ƒAƒNƒZƒXƒIƒuƒWƒFƒNƒg‚Ɉړ®‚·‚é‚Å‚µ‚傤iDAOƒpƒ^[ƒ“jB
+                ‚æ‚葽‚­‚Ì—á‚́AHibernate‚ÌWiki‚ðŽQÆ‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-webapp-deploy">
+            <title>ƒfƒvƒƒC‚ƃeƒXƒg</title>
+
+            <para>
+                ‚±‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚̃fƒvƒƒC‚Ì‚½‚߂ɁAWebƒA[ƒJƒCƒuiWARj‚ðì¬‚µ‚Ä‚­‚¾‚³‚¢B
+                ˆÈ‰º‚ÌAntƒ^[ƒQƒbƒg‚ð <literal>build.xml</literal> ‚ɉÁ‚¦‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+<programlisting><![CDATA[<target name="war" depends="compile">
+    <war destfile="hibernate-tutorial.war" webxml="web.xml">
+        <lib dir="${librarydir}">
+          <exclude name="jsdk*.jar"/>
+        </lib>
+
+        <classes dir="${targetdir}"/>
+    </war>
+</target>]]></programlisting>
+
+            <para>
+                ‚±‚̃^[ƒQƒbƒg‚Í <literal>hibernate-tutorial.war</literal> ‚Æ‚¢‚¤ƒtƒ@ƒCƒ‹‚ð
+                ƒvƒƒWƒFƒNƒgƒfƒBƒŒƒNƒgƒŠ‚ɍ쐬‚µ‚Ü‚·B
+                ‚±‚̃tƒ@ƒCƒ‹‚Í‚·‚ׂẴ‰ƒCƒuƒ‰ƒŠ‚Æ <literal>web.xml</literal> ‹LqŽq‚ðŠÜ‚ñ‚Å‚¨‚èA
+                ƒvƒƒWƒFƒNƒg‚̃x[ƒXƒfƒBƒŒƒNƒgƒŠ‚É’u‚©‚ê‚邱‚Æ‚ðŠú‘Ò‚³‚ê‚Ü‚·B
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+    xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+    <servlet>
+        <servlet-name>Event Manager</servlet-name>
+        <servlet-class>events.EventManagerServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Event Manager</servlet-name>
+        <url-pattern>/eventmanager</url-pattern>
+    </servlet-mapping>
+</web-app>]]></programlisting>
+
+            <para>
+                WebƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̃Rƒ“ƒpƒCƒ‹‚ƃfƒvƒƒC‚Ì‘O‚ɁA <literal>jsdk.jar</literal> ‚Æ‚¢‚¤
+                ’ljÁ‚̃‰ƒCƒuƒ‰ƒŠ‚ª•K—v‚È‚±‚Æ‚É’ˆÓ‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚±‚ê‚ÍJavaƒT[ƒuƒŒƒbƒg‚ÌŠJ”­ƒLƒbƒg‚Å‚·B
+                ‚à‚µ‚Ü‚¾‚±‚̃‰ƒCƒuƒ‰ƒŠ‚ðŽ‚Á‚Ä‚¢‚È‚¢‚È‚çASun‚̃EƒFƒuƒTƒCƒg‚Å“üŽè‚µ‚āA
+                ƒ‰ƒCƒuƒ‰ƒŠƒfƒBƒŒƒNƒgƒŠ‚ɃRƒs[‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚µ‚©‚µA‚±‚ê‚̓Rƒ“ƒpƒCƒ‹‚É‚Ì‚ÝŽg—p‚³‚êAWARƒpƒbƒP[ƒW‚©‚ç‚͏œŠO‚³‚ê‚Ü‚·B
+            </para>
+
+            <para>
+                ƒrƒ‹ƒh‚ƃfƒvƒƒC‚Ì‚½‚߂ɁAƒvƒƒWƒFƒNƒgƒfƒBƒŒƒNƒgƒŠ‚Å <literal>ant war</literal> ‚ðŒÄ‚яo‚µA
+                <literal>hibernate-tutorial.war</literal> ƒtƒ@ƒCƒ‹‚ðTomcat‚Ì <literal>webapp</literal> 
+                ƒfƒBƒŒƒNƒgƒŠ‚ɃRƒs[‚µ‚Ä‚­‚¾‚³‚¢B
+                ‚Ü‚¾Tomcat‚ðƒCƒ“ƒXƒg[ƒ‹‚µ‚Ä‚¢‚È‚¯‚ê‚΁Aƒ_ƒEƒ“ƒ[ƒh‚µ‚āAˆÈ‰º‚̃Cƒ“ƒXƒg[ƒ‹ƒKƒCƒh‚ɏ]‚Á‚Ä‚­‚¾‚³‚¢B
+                ‚µ‚©‚µA‚±‚̃AƒvƒŠƒP[ƒVƒ‡ƒ“‚̃fƒvƒƒC‚·‚邽‚߂ɁATomcat‚̐ݒè‚ð•ÏX‚·‚é•K—v‚Í‚ ‚è‚Ü‚¹‚ñB
+            </para>
+
+            <para>
+                ˆê“xƒfƒvƒƒC‚µ‚ÄTomcat‚ð‹N“®‚·‚ê‚΁A <literal>http://localhost:8080/hibernate-tutorial/eventmanager</literal> ‚Å
+                ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ւ̃AƒNƒZƒX‚ª‰Â”\‚Å‚·B
+                Å‰‚̃ŠƒNƒGƒXƒg‚ªì¬‚µ‚½ƒT[ƒuƒŒƒbƒg‚É“n‚Á‚½‚Æ‚«‚ɁATomcat‚̃ƒO‚Å
+                Hibernate‚̏‰Šú‰»ˆ—‚ðŠm”F‚µ‚Ä‚­‚¾‚³‚¢
+               i <literal>HibernateUtil</literal> “à‚̐ÓI‰Šú‰»ƒuƒƒbƒN‚ªŒÄ‚΂ê‚Ä‚¢‚Ü‚·jB
+                ‚Ü‚½Aexception‚ª”­¶‚µ‚½‚È‚çÚ×‚ðŠm”F‚µ‚Ä‚­‚¾‚³‚¢B
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="tutorial-summary" revision="1">
+        <title>—v–ñ</title>
+
+        <para>
+            ‚±‚̃`ƒ…[ƒgƒŠƒAƒ‹‚ł́AŠÈ’P‚ȃXƒ^ƒ“ƒhƒAƒ[ƒ“‚ÌHibernateƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚Æ
+            ¬‹K–Í‚ÌWebƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚ð‘‚­‚½‚ß‚ÌŠî–{‚ðÐ‰î‚µ‚Ü‚µ‚½B
+        </para>
+
+        <para>
+            ‚à‚¤Hibernate‚ÉŽ©M‚ª‚ ‚ê‚΁AƒŠƒtƒ@ƒŒƒ“ƒXƒhƒLƒ…ƒƒ“ƒg‚Ì–ÚŽŸ‚É–Ú‚ð’Ê‚µ‚āA
+            –Ê”’‚»‚¤‚¾‚ÆŽv‚¤ƒgƒsƒbƒN‚ð’T‚µ‚Ä‚­‚¾‚³‚¢B
+            Å‚à•p”É‚ÉŽ¿–₪‚ ‚é‚̂́Aƒgƒ‰ƒ“ƒUƒNƒVƒ‡ƒ“ˆ—i<xref linkend="transactions"/>jA
+            ƒtƒFƒbƒ`‚̃pƒtƒH[ƒ}ƒ“ƒXi<xref linkend="performance"/>jA
+            API‚ÌŽg‚¢•ûi<xref linkend="objectstate"/>j‚ƃNƒGƒŠ
+            i<xref linkend="objectstate-querying"/>j‚Å‚·B
+        </para>
+
+        <para>
+            ‚³‚ç‚Ɂi“Á•Ê‚ȁjƒ`ƒ…[ƒgƒŠƒAƒ‹‚ª•K—v‚È‚çAHibernateƒEƒFƒuƒTƒCƒg‚ð–Y‚ꂸ‚Ƀ`ƒFƒbƒN‚µ‚Ä‚­‚¾‚³‚¢B
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/xml.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/xml.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/docbook/modules/xml.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,299 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<chapter id="xml">
+    <title>XMLƒ}ƒbƒsƒ“ƒO</title>
+
+    <para><emphasis>XMLƒ}ƒbƒsƒ“ƒO‚ÍHibernate3.0‚Å‚ÍŽŽŒ±“I‚È‹@”\‚Å‚ ‚èA”ñí‚ÉŠˆ“®“I‚ÉŠJ”­’†‚Å‚·B</emphasis></para>
+
+    <sect1 id="xml-intro" revision="1">
+        <title>XMLƒf[ƒ^‚ł̍ì‹Æ</title>
+
+        <para>
+            Hibernate‚ł͉i‘±«‚ÌPOJO‚ðŽg‚Á‚čì‹Æ‚·‚é‚Ì‚Æ‚Ù‚Ú“¯‚¶‚悤‚È‚â‚è•û‚ŁA
+            ‰i‘±«‚ÌXMLƒf[ƒ^‚ðŽg‚Á‚čì‹Æ‚Å‚«‚Ü‚·B
+        </para>
+
+        <para>
+            Hibernate‚ÍXMLƒcƒŠ[‚𑀍삷‚邽‚ß‚ÌAPI‚Æ‚µ‚Ädom4j‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚·B
+            ƒf[ƒ^ƒx[ƒX‚©‚çdom4j‚̃cƒŠ[‚𕜌³‚·‚éƒNƒGƒŠ‚ð‘‚­‚±‚Æ‚ª‚Å‚«A
+            ƒcƒŠ[‚ɑ΂µ‚čs‚Á‚½C³‚ÍŽ©“®“I‚Ƀf[ƒ^ƒx[ƒX‚Æ“¯Šú‚³‚ê‚Ü‚·B
+            
+            ‚Ü‚½XMLƒhƒLƒ…ƒƒ“ƒg‚ðŽæ“¾‚·‚邱‚Æ‚ª‚Å‚«Adom4j‚ðŽg‚Á‚ăhƒLƒ…ƒƒ“ƒg‚ðƒp[ƒX‚µA
+            Hibernate‚Ì”CˆÓ‚ÌŠî–{‘€ì‚ðŽg‚Á‚ăf[ƒ^ƒx[ƒX‚֏‘‚«ž‚Þ‚±‚Æ‚ª‚Å‚«‚Ü‚·BF
+            ‚‚܂èA<literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal>
+            ‘€ì‚Å‚·(ƒ}[ƒW‚Í‚Ü‚¾ƒTƒ|[ƒg‚µ‚Ä‚¢‚Ü‚¹‚ñ)B
+           
+        </para>
+
+        <para>
+            ƒf[ƒ^‚̃Cƒ“ƒ|[ƒg/ƒGƒNƒXƒ|[ƒgA
+            JMS‚É‚æ‚éƒGƒ“ƒeƒBƒeƒBƒf[ƒ^‚ÌŠO•”‰»‚âSOAPAXSLTƒx[ƒX‚̃Œƒ|[ƒg‚ȂǁA
+            ‚±‚Ì‹@”\‚É‚Í‘½‚­‚Ì—p“r‚ª‚ ‚è‚Ü‚·B
+        </para>
+        
+        <para>
+            ’Pˆê‚̃}ƒbƒsƒ“ƒO‚́AƒNƒ‰ƒX‚̃vƒƒpƒeƒB‚ÆXMLƒhƒLƒ…ƒƒ“ƒg‚̃m[ƒh‚ð
+            “¯Žž‚Ƀf[ƒ^ƒx[ƒX‚Öƒ}ƒbƒsƒ“ƒO‚·‚邽‚ß‚ÉŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+            ‚Ü‚½ƒ}ƒbƒsƒ“ƒO‚·‚éƒNƒ‰ƒX‚ª‚È‚¯‚ê‚΁A
+            XML‚¾‚¯‚ðƒ}ƒbƒsƒ“ƒO‚·‚邽‚ß‚ÉŽg‚¤‚±‚Æ‚ª‚Å‚«‚Ü‚·B
+            
+        </para>
+        
+        <sect2 id="xml-intro-mapping">
+            <title>XML‚ƃNƒ‰ƒX‚̃}ƒbƒsƒ“ƒO‚𓯎ž‚ÉŽw’è‚·‚é</title>
+
+            <para>
+                ‚±‚ê‚ÍPOJO‚ÆXML‚𓯎ž‚Ƀ}ƒbƒsƒ“ƒO‚·‚é—á‚Å‚·BF
+            </para>
+            
+            <programlisting><![CDATA[<class name="Account" 
+        table="ACCOUNTS" 
+        node="account">
+        
+    <id name="accountId" 
+            column="ACCOUNT_ID" 
+            node="@id"/>
+            
+    <many-to-one name="customer" 
+            column="CUSTOMER_ID" 
+            node="customer/@id" 
+            embed-xml="false"/>
+            
+    <property name="balance" 
+            column="BALANCE" 
+            node="balance"/>
+            
+    ...
+    
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="xml-onlyxml">
+            <title>XMLƒ}ƒbƒsƒ“ƒO‚¾‚¯‚ðŽw’è‚·‚é</title>
+
+            <para>
+                ‚±‚ê‚ÍPOJOƒNƒ‰ƒX‚ª‚È‚¢ƒ}ƒbƒsƒ“ƒO‚Ì—á‚Å‚·BF
+            </para>
+            
+            <programlisting><![CDATA[<class entity-name="Account" 
+        table="ACCOUNTS" 
+        node="account">
+        
+    <id name="id" 
+            column="ACCOUNT_ID" 
+            node="@id" 
+            type="string"/>
+            
+    <many-to-one name="customerId" 
+            column="CUSTOMER_ID" 
+            node="customer/@id" 
+            embed-xml="false" 
+            entity-name="Customer"/>
+            
+    <property name="balance" 
+            column="BALANCE" 
+            node="balance" 
+            type="big_decimal"/>
+            
+    ...
+    
+</class>]]></programlisting>
+        
+            <para>
+                ‚±‚̃}ƒbƒsƒ“ƒO‚É‚æ‚èAdom4jƒcƒŠ[‚©A
+                ƒvƒƒpƒeƒB–¼/’l‚Ì‘g‚̃Oƒ‰ƒtijava‚Ì <literal>Map</literal>j‚Æ‚µ‚Ä
+                ƒf[ƒ^‚ɃAƒNƒZƒX‚Å‚«‚Ü‚·B
+                
+                ƒvƒƒpƒeƒB‚Ì–¼‘O‚́AHQLƒNƒGƒŠ[“à‚ÅŽQÆ‚Å‚«‚鏃ˆ‚Ș_—\‘¢‚Å‚·B
+            </para>
+
+        </sect2>
+        
+     </sect1>
+     
+    <sect1 id="xml-mapping" revision="1">
+        <title>XMLƒ}ƒbƒsƒ“ƒO‚̃ƒ^ƒf[ƒ^</title>
+
+        <para>
+            ‘½‚­‚ÌHibernate‚̃}ƒbƒsƒ“ƒO—v‘f‚́@<literal>node</literal>@‘®«‚ªŽg—p‚Å‚«‚Ü‚·B
+            ‚±‚ê‚É‚æ‚èXML‘®«‚Ì–¼‘O‚âƒvƒƒpƒeƒB‚âƒGƒ“ƒeƒBƒeƒBƒf[ƒ^‚ð•ÛŽ‚·‚é—v‘f‚ðŽw’è‚Å‚«‚Ü‚·B
+            <literal>node</literal>@‘®«‚̃tƒH[ƒ}ƒbƒg‚͈ȉº‚Ì’†‚Ì1‚‚łȂ¯‚ê‚΂Ȃè‚Ü‚¹‚ñBF
+        </para>
+        
+        <itemizedlist spacing="compact">
+        <listitem>
+            <para>
+            <literal>"element-name"</literal> - Žw’肵‚½XML—v‘f‚Öƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·
+            </para>
+        </listitem>
+        <listitem>
+            <para>
+            <literal>"@attribute-name"</literal> - Žw’肵‚½XML‘®«‚Öƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·
+            </para>
+        </listitem>
+        <listitem>
+            <para>
+            <literal>"."</literal> -@e—v‘f‚Öƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·
+            </para>
+        </listitem>
+        <listitem>
+            <para>
+                <literal>"element-name/@attribute-name"</literal> - 
+                Žw’肵‚½ƒGƒŒƒƒ“ƒg‚ÌŽw’肵‚½‘®«‚Öƒ}ƒbƒsƒ“ƒO‚µ‚Ü‚·
+            </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            ƒRƒŒƒNƒVƒ‡ƒ“‚Æ’Pˆê‚Ì’l‚ÌŠÖ˜A‚ɑ΂µ‚āA
+            ‚¨‚Ü‚¯‚Ì <literal>embed-xml</literal> ‘®«‚ª‚ ‚è‚Ü‚·B
+            ƒfƒtƒHƒ‹ƒg‚Ì <literal>embed-xml="true"</literal> ‚Ɛݒ肵‚½ê‡A
+            ŠÖ˜A‚·‚éƒGƒ“ƒeƒBƒeƒB(’lŒ^‚̃RƒŒƒNƒVƒ‡ƒ“)‚ÌXMLƒcƒŠ[‚́A
+            ’¼ÚŠÖ˜A‚ðŠ—L‚·‚éƒGƒ“ƒeƒBƒeƒB‚ÌXMLƒcƒŠ[“à‚É–„‚ߍž‚Ü‚ê‚Ü‚·B
+            ”½‘΂ɁA<literal>embed-xml="false"</literal> ‚Ɛݒ肵‚½ê‡A
+            ŽQÆ‚³‚ê‚鎯•ÊŽq‚Ì’l‚¾‚¯‚ª‘½d“x‚P‘¤‚ÌŠÖ˜A‚ɑ΂·‚éXML‚ÉŒ»‚êA
+            ’Pƒ‚ɃRƒŒƒNƒVƒ‡ƒ“‚Í‚Ü‚Á‚½‚­Œ»‚ê‚È‚­‚È‚è‚Ü‚·B
+        </para>
+        
+        <para>
+            ‚ ‚Ü‚è‚É‘½‚­‚ÌŠÖ˜A‚ɑ΂µ‚Ä
+            <literal>embed-xml="true"</literal> ‚Æ‚µ‚½‚Ü‚Ü‚É‚·‚é‚Ì‚Í’ˆÓ‚·‚ׂ«‚Å‚·B
+            XML‚͏zŠÂ‚ð‚¤‚Ü‚­ˆµ‚¦‚Ü‚¹‚ñB
+        </para>
+        
+        <programlisting><![CDATA[<class name="Customer" 
+        table="CUSTOMER" 
+        node="customer">
+        
+    <id name="id" 
+            column="CUST_ID" 
+            node="@id"/>
+            
+    <map name="accounts" 
+            node="." 
+            embed-xml="true">
+        <key column="CUSTOMER_ID" 
+                not-null="true"/>
+        <map-key column="SHORT_DESC" 
+                node="@short-desc" 
+                type="string"/>
+        <one-to-many entity-name="Account"
+                embed-xml="false" 
+                node="account"/>
+    </map>
+    
+    <component name="name" 
+            node="name">
+        <property name="firstName" 
+                node="first-name"/>
+        <property name="initial" 
+                node="initial"/>
+        <property name="lastName" 
+                node="last-name"/>
+    </component>
+    
+    ...
+    
+</class>]]></programlisting>
+
+        <para>
+            ‚±‚Ì—á‚ł́AŽÀÛ‚Ìaccount‚̃f[ƒ^‚Å‚Í‚È‚­A
+            account‚Ìid‚̃RƒŒƒNƒVƒ‡ƒ“‚𖄂ߍž‚Þ‚±‚Æ‚É‚µ‚Ü‚µ‚½B
+            ‘±‚«‚ÌHQLƒNƒGƒŠ‚Å‚·F
+        </para>
+        
+        <programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
+        
+        <para>
+            ‚±‚̂悤‚ȃf[ƒ^ƒZƒbƒg‚ð•Ô‚·‚Å‚µ‚傤
+        </para>
+        
+        <programlisting><![CDATA[<customer id="123456789">
+    <account short-desc="Savings">987632567</account>
+    <account short-desc="Credit Card">985612323</account>
+    <name>
+        <first-name>Gavin</first-name>
+        <initial>A</initial>
+        <last-name>King</last-name>
+    </name>
+    ...
+</customer>]]></programlisting>
+
+        <para>
+            <literal>&lt;one-to-many&gt;</literal> ƒ}ƒbƒsƒ“ƒO‚Å
+            <literal>embed-xml="true"</literal> ‚Ɛݒ肵‚½ê‡A
+            ƒf[ƒ^‚Í‚±‚̂悤‚É‚È‚é‚Å‚µ‚傤B
+        </para>
+        
+        <programlisting><![CDATA[<customer id="123456789">
+    <account id="987632567" short-desc="Savings">
+        <customer id="123456789"/>
+        <balance>100.29</balance>
+    </account>
+    <account id="985612323" short-desc="Credit Card">
+        <customer id="123456789"/>
+        <balance>-2370.34</balance>
+    </account>
+    <name>
+        <first-name>Gavin</first-name>
+        <initial>A</initial>
+        <last-name>King</last-name>
+    </name>
+    ...
+</customer>]]></programlisting>
+       
+    </sect1>
+    
+    
+    <sect1 id="xml-manipulation" revision="1">
+        <title>XMLƒf[ƒ^‚ðˆµ‚¤</title>
+        
+        <para>
+            XMLƒhƒLƒ…ƒƒ“ƒg‚ðAƒAƒvƒŠƒP[ƒVƒ‡ƒ““à‚ōēǂݍž‚Ý‚âXV‚ð‚µ‚Ä‚Ý‚Ü‚µ‚傤B
+            ˆÈ‰º‚Å‚Ídom4j‚̃ZƒbƒVƒ‡ƒ“‚ðŽæ“¾‚·‚邱‚Ƃōs‚¢‚Ü‚·BF
+        </para>
+        
+       <programlisting><![CDATA[Document doc = ....;
+       
+Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+List results = dom4jSession
+    .createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")
+    .list();
+for ( int i=0; i<results.size(); i++ ) {
+    //add the customer data to the XML document
+    Element customer = (Element) results.get(i);
+    doc.add(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+       
+       <programlisting><![CDATA[Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+Element cust = (Element) dom4jSession.get("Customer", customerId);
+for ( int i=0; i<results.size(); i++ ) {
+    Element customer = (Element) results.get(i);
+    //change the customer name in the XML and database
+    Element name = customer.element("name");
+    name.element("first-name").setText(firstName);
+    name.element("initial").setText(initial);
+    name.element("last-name").setText(lastName);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            XMLƒx[ƒX‚̃f[ƒ^‚̃Cƒ“ƒ|[ƒg/ƒGƒNƒXƒ|[ƒg‚ðŽÀ‘•‚·‚邽‚߂ɁA
+            Hibernate‚Ì <literal>replicate()</literal> ‘€ì‚ð‚±‚Ì‹@”\‚ðŒ‹‚Ñ‚Â‚¯‚é‚Ì‚Í
+            ‹É‚ß‚Ä—LŒø‚Å‚·B
+        </para>
+       
+    </sect1>
+     
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/css/html.css
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/css/html.css	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/css/html.css	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,97 @@
+A {
+    color: #003399;
+}
+
+A:active {
+    color: #003399;
+}
+
+A:visited {
+    color: #888888;
+}
+
+P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
+    color: #000000;
+}
+
+TD, TH, SPAN {
+    color: #000000;
+}
+
+BLOCKQUOTE {
+    margin-right: 0px;
+}
+
+
+H1, H2, H3, H4, H5, H6    {
+    color: #000000;
+    font-weight:500;
+    margin-top:10px;
+    padding-top:15px;
+}
+
+TABLE  {
+    border-collapse: collapse;
+    border-spacing:0;
+    border: 1px thin black;
+    empty-cells: hide;
+}
+
+TD  {
+    padding: 4pt;
+}
+
+H1 { font-size: 150%; }
+H2 { font-size: 140%; }
+H3 { font-size: 110%; font-weight: bold; }
+H4 { font-size: 110%; font-weight: bold;}
+H5 { font-size: 100%; font-style: italic; }
+H6 { font-size: 100%; font-style: italic; }
+
+TT {
+font-size: 90%;
+    font-family: "Courier New", Courier, monospace;
+    color: #000000;
+}
+
+PRE {
+font-size: 100%;
+    padding: 5px;
+    border-style: solid;
+    border-width: 1px;
+    border-color: #CCCCCC;
+    background-color: #F4F4F4;
+}
+
+UL, OL, LI {
+    list-style: disc;
+}
+
+HR  {
+    width: 100%;
+    height: 1px;
+    background-color: #CCCCCC;
+    border-width: 0px;
+    padding: 0px;
+    color: #CCCCCC;
+}
+
+.variablelist { 
+    padding-top: 10; 
+    padding-bottom:10; 
+    margin:0;
+}
+
+.itemizedlist, UL { 
+    padding-top: 0; 
+    padding-bottom:0; 
+    margin:0; 
+}
+
+.term { 
+    font-weight:bold;
+}
+
+
+
+    

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/AuthorWork.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/AuthorWork.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/AuthorWork.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/AuthorWork.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/CustomerOrderProduct.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/CustomerOrderProduct.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/CustomerOrderProduct.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/CustomerOrderProduct.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/EmployerEmployee.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/EmployerEmployee.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/EmployerEmployee.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/EmployerEmployee.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/full_cream.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/full_cream.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/full_cream.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/full_cream.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/full_cream.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,429 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="354.331"
+   height="336.614"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+     style="font-size:12;"
+     id="g659">
+    <rect
+       width="212.257"
+       height="57.2441"
+       x="17.9576"
+       y="100.132"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       transform="matrix(0.743454,0,0,0.482981,6.46949,52.2178)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <rect
+     width="325.86"
+     height="63.6537"
+     x="17.4083"
+     y="15.194"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect136" />
+  <rect
+     width="325.86"
+     height="63.6537"
+     x="13.6713"
+     y="12.4966"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect126" />
+  <g
+     transform="matrix(1.14345,0,0,0.729078,-1.67818,105.325)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <text
+     x="170.824753"
+     y="58.402939"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="170.824997"
+       y="58.402901"
+       id="tspan360">
+Application</tspan>
+  </text>
+  <text
+     x="178.076340"
+     y="364.281433"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="178.076004"
+       y="364.281006"
+       id="tspan421">
+Database</tspan>
+  </text>
+  <text
+     x="68.605331"
+     y="138.524582"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="68.605301"
+       y="138.524994"
+       id="tspan384">
+SessionFactory</tspan>
+  </text>
+  <rect
+     width="67.0014"
+     height="101.35"
+     x="196.927"
+     y="89.2389"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect387" />
+  <rect
+     width="67.0014"
+     height="101.35"
+     x="194.633"
+     y="86.4389"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect388" />
+  <text
+     x="249.108841"
+     y="173.885559"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text389">
+    <tspan
+       x="249.108994"
+       y="173.886002"
+       id="tspan392">
+Session</tspan>
+  </text>
+  <rect
+     width="73.0355"
+     height="101.35"
+     x="270.995"
+     y="90.0018"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect395" />
+  <rect
+     width="73.0355"
+     height="101.35"
+     x="267.869"
+     y="87.2018"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect396" />
+  <text
+     x="328.593658"
+     y="174.715622"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text397">
+    <tspan
+       x="328.593994"
+       y="174.716003"
+       id="tspan563">
+Transaction</tspan>
+  </text>
+  <g
+     transform="matrix(0.29544,0,0,0.397877,9.70533,103.96)"
+     style="font-size:12;"
+     id="g565">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect566" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect567" />
+  </g>
+  <text
+     x="25.592752"
+     y="204.497803"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text568">
+    <tspan
+       x="25.592800"
+       y="204.498001"
+       id="tspan662">
+TransactionFactory</tspan>
+  </text>
+  <g
+     transform="matrix(0.298082,0,0,0.397877,99.6898,103.96)"
+     style="font-size:12;"
+     id="g573">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect574" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect575" />
+  </g>
+  <text
+     x="134.030670"
+     y="205.532791"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text576">
+    <tspan
+       x="134.031006"
+       y="205.533005"
+       id="tspan664">
+ConnectionProvider</tspan>
+  </text>
+  <g
+     transform="matrix(1.14345,0,0,0.729078,-1.67818,38.9539)"
+     style="font-size:12;"
+     id="g587">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect588" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect589" />
+  </g>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="25.6196"
+     y="206.028"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect594" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="24.4229"
+     y="204.135"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect595" />
+  <text
+     x="85.575645"
+     y="282.300354"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text596">
+    <tspan
+       x="85.575600"
+       y="282.299988"
+       id="tspan607">
+JNDI</tspan>
+  </text>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="236.937"
+     y="206.791"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect610" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="235.741"
+     y="204.898"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect611" />
+  <text
+     x="342.093201"
+     y="283.226410"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text612">
+    <tspan
+       x="342.092987"
+       y="283.226013"
+       id="tspan621">
+JTA</tspan>
+  </text>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="130.134"
+     y="206.791"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect616" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="128.937"
+     y="204.898"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect617" />
+  <text
+     x="212.445343"
+     y="283.226410"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text618">
+    <tspan
+       x="212.445007"
+       y="283.226013"
+       id="tspan623">
+JDBC</tspan>
+  </text>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,6.19341)"
+     style="font-size:12;"
+     id="g637">
+    <g
+       transform="matrix(0.499515,0,0,0.415467,-0.237339,5.61339)"
+       id="g167">
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="61.8805"
+         y="68.4288"
+         style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect134" />
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="59.2613"
+         y="65.8095"
+         style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect135" />
+    </g>
+    <text
+       x="33.749969"
+       y="50.589706"
+       style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+       id="text188">
+      <tspan
+         x="33.750000"
+         y="50.589699"
+         id="tspan635">
+Transient Objects</tspan>
+    </text>
+  </g>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+     style="font-size:12;"
+     id="g644">
+    <g
+       transform="matrix(0.297486,0,0,0.516482,230.251,36.9178)"
+       id="g364">
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="61.8805"
+         y="68.4288"
+         style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect365" />
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="59.2613"
+         y="65.8095"
+         style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect366" />
+    </g>
+    <text
+       x="277.123230"
+       y="85.155571"
+       style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+       id="text367">
+      <tspan
+         x="277.122986"
+         y="85.155602"
+         id="tspan631">
+Persistent</tspan>
+      <tspan
+         x="277.122986"
+         y="96.155602"
+         id="tspan633">
+Objects</tspan>
+    </text>
+  </g>
+</svg>

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/hibernate_logo_a.png
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/hibernate_logo_a.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/lite.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/lite.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/lite.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/lite.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/lite.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,334 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="318.898"
+   height="248.031"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <rect
+     width="291.837"
+     height="57.0074"
+     x="17.3169"
+     y="18.646"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect136" />
+  <rect
+     width="291.837"
+     height="57.0074"
+     x="13.9703"
+     y="16.2302"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect126" />
+  <g
+     transform="matrix(0.326107,0,0,0.765831,9.59261,8.98517)"
+     style="font-size:12;"
+     id="g161">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <g
+     transform="matrix(1.02406,0,0,0.652953,0.223384,39.9254)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <g
+     transform="matrix(0.449834,0,0,0.338463,-3.15909,9.73319)"
+     style="font-size:12;"
+     id="g167">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect134" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect135" />
+  </g>
+  <text
+     x="302.277679"
+     y="65.943230"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="302.277954"
+       y="65.943184"
+       id="tspan360">
+Application</tspan>
+  </text>
+  <text
+     x="36.235924"
+     y="63.796055"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text188">
+    <tspan
+       x="36.235950"
+       y="63.796051"
+       id="tspan427">
+Transient Objects</tspan>
+  </text>
+  <text
+     x="180.416245"
+     y="290.543701"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="180.415939"
+       y="290.543549"
+       id="tspan421">
+Database</tspan>
+  </text>
+  <text
+     x="25.037701"
+     y="179.154755"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="25.037655"
+       y="179.154648"
+       id="tspan384">
+SessionFactory</tspan>
+  </text>
+  <g
+     transform="matrix(0.252763,0,0,0.765831,109.104,8.98517)"
+     style="font-size:12;"
+     id="g386">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect387" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect388" />
+  </g>
+  <g
+     transform="matrix(0.297394,0,0,0.572692,101.502,21.6359)"
+     style="font-size:12;"
+     id="g364">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect365" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect366" />
+  </g>
+  <text
+     x="202.746506"
+     y="102.992203"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text367">
+    <tspan
+       x="202.746948"
+       y="102.992249"
+       id="tspan423">
+Persistent</tspan>
+    <tspan
+       x="202.746948"
+       y="116.992355"
+       id="tspan425">
+Objects</tspan>
+  </text>
+  <text
+     x="174.458496"
+     y="180.080795"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text389">
+    <tspan
+       x="174.458618"
+       y="180.080338"
+       id="tspan392">
+Session</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,188.675,8.98517)"
+     style="font-size:12;"
+     id="g394">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect395" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect396" />
+  </g>
+  <text
+     x="260.413269"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text397">
+    <tspan
+       x="260.412964"
+       y="179.154343"
+       id="tspan400">
+JDBC</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,229.156,8.98517)"
+     style="font-size:12;"
+     id="g405">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect406" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect407" />
+  </g>
+  <text
+     x="320.606903"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text408">
+    <tspan
+       x="320.606964"
+       y="179.154343"
+       id="tspan417">
+JNDI</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,269.281,8.98517)"
+     style="font-size:12;"
+     id="g411">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect412" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect413" />
+  </g>
+  <text
+     x="377.096313"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text414">
+    <tspan
+       x="377.096008"
+       y="179.154999"
+       id="tspan145">
+JTA</tspan>
+  </text>
+</svg>

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/overview.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/overview.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/overview.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/overview.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/main/resources/shared/images/overview.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,250 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="248.031"
+   height="248.031"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,-3.02123)"
+     style="font-size:12;"
+     id="g158">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="17.3527"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect136" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="15.3883"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect126" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,3.04452)"
+     style="font-size:12;"
+     id="g161">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,8.0993)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.543505,2.59104,21.1103)"
+     style="font-size:12;"
+     id="g167">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect134" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect135" />
+  </g>
+  <text
+     x="105.392174"
+     y="56.568123"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="105.392273"
+       y="56.568146"
+       id="tspan186">
+Application</tspan>
+  </text>
+  <text
+     x="81.820183"
+     y="103.149330"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:20;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text188">
+    <tspan
+       x="81.820213"
+       y="103.149727"
+       id="tspan206">
+Persistent Objects</tspan>
+  </text>
+  <text
+     x="111.548180"
+     y="278.927887"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="111.547874"
+       y="278.927551"
+       id="tspan200">
+Database</tspan>
+  </text>
+  <text
+     x="94.436180"
+     y="153.805740"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="94.436180"
+       y="153.805740"
+       id="tspan221">
+HIBERNATE</tspan>
+  </text>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,2.59083,1.02261)"
+     style="font-size:12;"
+     id="g254">
+    <g
+       transform="translate(4.58374,2.61928)"
+       id="g176">
+      <g
+         transform="matrix(0.571429,0,0,0.67347,-10.6174,117.093)"
+         id="g170">
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="61.8805"
+           y="68.4288"
+           style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect171" />
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="59.2613"
+           y="65.8095"
+           style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect172" />
+      </g>
+      <g
+         transform="matrix(0.571429,0,0,0.67347,138.682,117.093)"
+         id="g173">
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="61.8805"
+           y="68.4288"
+           style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect174" />
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="59.2613"
+           y="65.8095"
+           style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect175" />
+      </g>
+    </g>
+    <text
+       x="47.259438"
+       y="182.367538"
+       style="font-weight:bold;stroke-width:1pt;font-family:Courier;"
+       id="text191">
+      <tspan
+         x="47.259399"
+         y="182.367996"
+         id="tspan212">
+hibernate.</tspan>
+      <tspan
+         x="47.259399"
+         y="194.367996"
+         id="tspan214">
+properties</tspan>
+    </text>
+    <text
+       x="198.523010"
+       y="188.260941"
+       style="font-weight:normal;stroke-width:1pt;font-family:helvetica;"
+       id="text194">
+      <tspan
+         id="tspan195">
+XML Mapping</tspan>
+    </text>
+  </g>
+</svg>

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/sazanami-gothic.ttf
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/sazanami-gothic.ttf
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/sazanami-gothic.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/sazanami-gothic.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/sazanami-gothic.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="utf-8"?><font-metrics type="TYPE0"><font-name>SazanamiGothic,Gothic-Regular</font-name><embed/><cap-height>0</cap-height><x-height>0</x-height><ascender>995</ascender><descender>-203</descender><bbox><left>-50</left><bottom>-203</bottom><right>1041</right><top>995</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><ttc-name>Sazanami Gothic</ttc-name><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="0" ue="0" us="0"/><bf gi="3" ue="126" us="32"/><bf gi="98" ue="255" us="160"/><bf gi="194" ue="305" us="305"/><bf gi="195" ue="322" us="321"/><bf gi="197" ue="331" us="331"/><bf gi="198" ue="339" us="338"/><bf gi="200" ue="402" us="402"/><bf gi="201" ue="593" us="593"/><bf gi="202" ue="602" us="602"/><bf gi="203" ue="658" us="658"/><bf gi="204" ue="711" us="710"/><bf gi="206" ue="715" us="714"/><bf gi="208" ue="728" us="728"/><bf gi="209" ue="730" us="730!
 "/><bf gi="210" ue="732" us="732"/><bf gi="211" ue="929" us="913"/><bf gi="228" ue="937" us="931"/><bf gi="235" ue="969" us="945"/><bf gi="260" ue="977" us="977"/><bf gi="261" ue="981" us="981"/><bf gi="262" ue="1025" us="1025"/><bf gi="263" ue="1103" us="1040"/><bf gi="327" ue="1105" us="1105"/><bf gi="328" ue="8195" us="8195"/><bf gi="329" ue="8208" us="8208"/><bf gi="330" ue="8217" us="8213"/><bf gi="335" ue="8221" us="8220"/><bf gi="337" ue="8225" us="8224"/><bf gi="339" ue="8230" us="8229"/><bf gi="341" ue="8240" us="8240"/><bf gi="342" ue="8243" us="8242"/><bf gi="344" ue="8251" us="8251"/><bf gi="345" ue="8254" us="8254"/><bf gi="346" ue="8364" us="8364"/><bf gi="347" ue="8451" us="8451"/><bf gi="348" ue="8467" us="8467"/><bf gi="349" ue="8470" us="8470"/><bf gi="350" ue="8481" us="8481"/><bf gi="351" ue="8491" us="8491"/><bf gi="352" ue="8553" us="8544"/><bf gi="362" ue="8595" us="8592"/><bf gi="366" ue="8658" us="8658"/><bf gi="367" ue="8660" us="8660"/><bf gi="368!
 " ue="8704" us="8704"/><bf gi="369" ue="8707" us="8706"/><bf gi="371" 
ue="8712" us="8711"/><bf gi="373" ue="8715" us="8715"/><bf gi="374" ue="8722" us="8722"/><bf gi="375" ue="8730" us="8730"/><bf gi="376" ue="8736" us="8733"/><bf gi="380" ue="8741" us="8741"/><bf gi="381" ue="8750" us="8743"/><bf gi="389" ue="8757" us="8756"/><bf gi="391" ue="8765" us="8765"/><bf gi="392" ue="8771" us="8771"/><bf gi="393" ue="8786" us="8786"/><bf gi="394" ue="8801" us="8800"/><bf gi="396" ue="8807" us="8806"/><bf gi="398" ue="8811" us="8810"/><bf gi="400" ue="8819" us="8818"/><bf gi="402" ue="8835" us="8834"/><bf gi="404" ue="8839" us="8838"/><bf gi="406" ue="8869" us="8869"/><bf gi="407" ue="8895" us="8895"/><bf gi="408" ue="8978" us="8978"/><bf gi="409" ue="9331" us="9312"/><bf gi="429" ue="9475" us="9472"/><bf gi="433" ue="9484" us="9484"/><bf gi="434" ue="9488" us="9487"/><bf gi="436" ue="9492" us="9491"/><bf gi="438" ue="9496" us="9495"/><bf gi="440" ue="9501" us="9499"/><bf gi="443" ue="9504" us="9504"/><bf gi="444" ue="9509" us="9507"/><bf gi="447" ue=!
 "9512" us="9512"/><bf gi="448" ue="9516" us="9515"/><bf gi="450" ue="9520" us="9519"/><bf gi="452" ue="9524" us="9523"/><bf gi="454" ue="9528" us="9527"/><bf gi="456" ue="9532" us="9531"/><bf gi="458" ue="9535" us="9535"/><bf gi="459" ue="9538" us="9538"/><bf gi="460" ue="9547" us="9547"/><bf gi="461" ue="9634" us="9632"/><bf gi="464" ue="9651" us="9650"/><bf gi="466" ue="9661" us="9660"/><bf gi="468" ue="9671" us="9670"/><bf gi="470" ue="9675" us="9675"/><bf gi="471" ue="9679" us="9678"/><bf gi="473" ue="9711" us="9711"/><bf gi="474" ue="9734" us="9733"/><bf gi="476" ue="9792" us="9792"/><bf gi="477" ue="9794" us="9794"/><bf gi="478" ue="9826" us="9825"/><bf gi="480" ue="9828" us="9828"/><bf gi="481" ue="9831" us="9831"/><bf gi="482" ue="9834" us="9834"/><bf gi="483" ue="9837" us="9837"/><bf gi="484" ue="9839" us="9839"/><bf gi="485" ue="12291" us="12288"/><bf gi="489" ue="12309" us="12293"/><bf gi="506" ue="12316" us="12316"/><bf gi="507" ue="12341" us="12339"/><bf gi="51!
 0" ue="12438" us="12353"/><bf gi="596" ue="12446" us="12443"/><bf gi="
600" ue="12542" us="12449"/><bf gi="694" ue="12850" us="12849"/><bf gi="696" ue="12857" us="12857"/><bf gi="697" ue="12968" us="12964"/><bf gi="702" ue="13059" us="13059"/><bf gi="703" ue="13069" us="13069"/><bf gi="704" ue="13076" us="13076"/><bf gi="705" ue="13080" us="13080"/><bf gi="706" ue="13091" us="13090"/><bf gi="708" ue="13095" us="13094"/><bf gi="710" ue="13099" us="13099"/><bf gi="711" ue="13110" us="13110"/><bf gi="712" ue="13115" us="13115"/><bf gi="713" ue="13130" us="13129"/><bf gi="715" ue="13133" us="13133"/><bf gi="716" ue="13137" us="13137"/><bf gi="717" ue="13143" us="13143"/><bf gi="718" ue="13182" us="13179"/><bf gi="722" ue="13199" us="13198"/><bf gi="724" ue="13214" us="13212"/><bf gi="727" ue="13217" us="13217"/><bf gi="728" ue="13252" us="13252"/><bf gi="729" ue="13259" us="13259"/><bf gi="730" ue="13261" us="13261"/><bf gi="731" ue="19973" us="19968"/><bf gi="737" ue="19982" us="19975"/><bf gi="745" ue="19986" us="19984"/><bf gi="748" ue="19993" u!
 s="19988"/><bf gi="754" ue="19999" us="19998"/><bf gi="756" ue="20001" us="20001"/><bf gi="757" ue="20004" us="20003"/><bf gi="759" ue="20006" us="20006"/><bf gi="760" ue="20008" us="20008"/><bf gi="761" ue="20011" us="20010"/><bf gi="763" ue="20018" us="20013"/><bf gi="769" ue="20022" us="20021"/><bf gi="771" ue="20025" us="20024"/><bf gi="773" ue="20028" us="20027"/><bf gi="775" ue="20037" us="20031"/><bf gi="782" ue="20039" us="20039"/><bf gi="783" ue="20043" us="20043"/><bf gi="784" ue="20047" us="20045"/><bf gi="787" ue="20049" us="20049"/><bf gi="788" ue="20058" us="20053"/><bf gi="794" ue="20063" us="20060"/><bf gi="798" ue="20067" us="20066"/><bf gi="800" ue="20073" us="20072"/><bf gi="802" ue="20081" us="20081"/><bf gi="803" ue="20085" us="20083"/><bf gi="806" ue="20089" us="20089"/><bf gi="807" ue="20096" us="20094"/><bf gi="810" ue="20098" us="20098"/><bf gi="811" ue="20102" us="20101"/><bf gi="813" ue="20110" us="20104"/><bf gi="820" ue="20114" us="20113"/><bf g!
 i="822" ue="20121" us="20116"/><bf gi="828" ue="20130" us="20123"/><bf
 gi="836" ue="20134" us="20132"/><bf gi="839" ue="20136" us="20136"/><bf gi="840" ue="20144" us="20139"/><bf gi="846" ue="20147" us="20147"/><bf gi="847" ue="20150" us="20150"/><bf gi="848" ue="20154" us="20153"/><bf gi="850" ue="20164" us="20160"/><bf gi="855" ue="20167" us="20166"/><bf gi="857" ue="20171" us="20170"/><bf gi="859" ue="20176" us="20173"/><bf gi="863" ue="20187" us="20180"/><bf gi="871" ue="20197" us="20189"/><bf gi="880" ue="20200" us="20200"/><bf gi="881" ue="20211" us="20205"/><bf gi="888" ue="20215" us="20213"/><bf gi="891" ue="20227" us="20219"/><bf gi="900" ue="20242" us="20232"/><bf gi="911" ue="20247" us="20245"/><bf gi="914" ue="20250" us="20249"/><bf gi="916" ue="20253" us="20252"/><bf gi="918" ue="20273" us="20270"/><bf gi="922" ue="20286" us="20275"/><bf gi="934" ue="20288" us="20288"/><bf gi="935" ue="20291" us="20290"/><bf gi="937" ue="20297" us="20294"/><bf gi="941" ue="20320" us="20299"/><bf gi="963" ue="20323" us="20323"/><bf gi="964" ue="203!
 30" us="20329"/><bf gi="966" ue="20332" us="20332"/><bf gi="967" ue="20337" us="20334"/><bf gi="971" ue="20339" us="20339"/><bf gi="972" ue="20351" us="20341"/><bf gi="983" ue="20358" us="20353"/><bf gi="989" ue="20372" us="20360"/><bf gi="1002" ue="20379" us="20374"/><bf gi="1008" ue="20385" us="20381"/><bf gi="1013" ue="20395" us="20395"/><bf gi="1014" ue="20399" us="20397"/><bf gi="1017" ue="20402" us="20402"/><bf gi="1018" ue="20407" us="20405"/><bf gi="1021" ue="20409" us="20409"/><bf gi="1022" ue="20422" us="20411"/><bf gi="1034" ue="20434" us="20424"/><bf gi="1045" ue="20436" us="20436"/><bf gi="1046" ue="20440" us="20439"/><bf gi="1048" ue="20445" us="20442"/><bf gi="1052" ue="20453" us="20447"/><bf gi="1059" ue="20464" us="20462"/><bf gi="1062" ue="20467" us="20466"/><bf gi="1064" ue="20470" us="20469"/><bf gi="1066" ue="20472" us="20472"/><bf gi="1067" ue="20474" us="20474"/><bf gi="1068" ue="20481" us="20476"/><bf gi="1074" ue="20487" us="20484"/><bf gi="1078" ue!
 ="20500" us="20489"/><bf gi="1090" ue="20511" us="20502"/><bf gi="1100
" ue="20526" us="20513"/><bf gi="1114" ue="20528" us="20528"/><bf gi="1115" ue="20531" us="20530"/><bf gi="1117" ue="20534" us="20533"/><bf gi="1119" ue="20537" us="20537"/><bf gi="1120" ue="20539" us="20539"/><bf gi="1121" ue="20547" us="20544"/><bf gi="1125" ue="20554" us="20549"/><bf gi="1131" ue="20556" us="20556"/><bf gi="1132" ue="20563" us="20558"/><bf gi="1138" ue="20567" us="20565"/><bf gi="1141" ue="20570" us="20569"/><bf gi="1143" ue="20572" us="20572"/><bf gi="1144" ue="20576" us="20575"/><bf gi="1146" ue="20579" us="20578"/><bf gi="1148" ue="20583" us="20581"/><bf gi="1151" ue="20586" us="20586"/><bf gi="1152" ue="20589" us="20588"/><bf gi="1154" ue="20594" us="20592"/><bf gi="1157" ue="20598" us="20596"/><bf gi="1160" ue="20600" us="20600"/><bf gi="1161" ue="20605" us="20605"/><bf gi="1162" ue="20609" us="20608"/><bf gi="1164" ue="20614" us="20611"/><bf gi="1168" ue="20618" us="20618"/><bf gi="1169" ue="20628" us="20621"/><bf gi="1177" ue="20630" us="20630"/><b!
 f gi="1178" ue="20636" us="20632"/><bf gi="1183" ue="20642" us="20638"/><bf gi="1188" ue="20650" us="20650"/><bf gi="1189" ue="20653" us="20652"/><bf gi="1191" ue="20656" us="20655"/><bf gi="1193" ue="20661" us="20658"/><bf gi="1197" ue="20663" us="20663"/><bf gi="1198" ue="20666" us="20665"/><bf gi="1200" ue="20670" us="20669"/><bf gi="1202" ue="20672" us="20672"/><bf gi="1203" ue="20677" us="20674"/><bf gi="1207" ue="20679" us="20679"/><bf gi="1208" ue="20682" us="20681"/><bf gi="1210" ue="20689" us="20684"/><bf gi="1216" ue="20694" us="20691"/><bf gi="1220" ue="20696" us="20696"/><bf gi="1221" ue="20698" us="20698"/><bf gi="1222" ue="20703" us="20700"/><bf gi="1226" ue="20713" us="20706"/><bf gi="1234" ue="20719" us="20717"/><bf gi="1237" ue="20722" us="20721"/><bf gi="1239" ue="20726" us="20724"/><bf gi="1242" ue="20731" us="20729"/><bf gi="1245" ue="20734" us="20734"/><bf gi="1246" ue="20740" us="20736"/><bf gi="1251" ue="20745" us="20742"/><bf gi="1255" ue="20750" us=!
 "20747"/><bf gi="1259" ue="20752" us="20752"/><bf gi="1260" ue="20754"
 us="20754"/><bf gi="1261" ue="20767" us="20756"/><bf gi="1273" ue="20769" us="20769"/><bf gi="1274" ue="20771" us="20771"/><bf gi="1275" ue="20776" us="20775"/><bf gi="1277" ue="20778" us="20778"/><bf gi="1278" ue="20781" us="20780"/><bf gi="1280" ue="20783" us="20783"/><bf gi="1281" ue="20789" us="20785"/><bf gi="1286" ue="20796" us="20791"/><bf gi="1292" ue="20816" us="20799"/><bf gi="1310" ue="20821" us="20818"/><bf gi="1314" ue="20824" us="20823"/><bf gi="1316" ue="20826" us="20826"/><bf gi="1317" ue="20828" us="20828"/><bf gi="1318" ue="20831" us="20831"/><bf gi="1319" ue="20834" us="20834"/><bf gi="1320" ue="20838" us="20836"/><bf gi="1323" ue="20846" us="20840"/><bf gi="1330" ue="20849" us="20849"/><bf gi="1331" ue="20856" us="20853"/><bf gi="1335" ue="20860" us="20860"/><bf gi="1336" ue="20862" us="20862"/><bf gi="1337" ue="20864" us="20864"/><bf gi="1338" ue="20870" us="20866"/><bf gi="1343" ue="20883" us="20873"/><bf gi="1354" ue="20889" us="20885"/><bf gi="1359" !
 ue="20893" us="20893"/><bf gi="1360" ue="20902" us="20896"/><bf gi="1367" ue="20909" us="20904"/><bf gi="1373" ue="20920" us="20912"/><bf gi="1382" ue="20922" us="20922"/><bf gi="1383" ue="20927" us="20924"/><bf gi="1387" ue="20930" us="20930"/><bf gi="1388" ue="20934" us="20932"/><bf gi="1391" ue="20937" us="20936"/><bf gi="1393" ue="20941" us="20939"/><bf gi="1396" ue="20943" us="20943"/><bf gi="1397" ue="20947" us="20945"/><bf gi="1400" ue="20950" us="20949"/><bf gi="1402" ue="20952" us="20952"/><bf gi="1403" ue="20958" us="20955"/><bf gi="1407" ue="20962" us="20960"/><bf gi="1410" ue="20967" us="20965"/><bf gi="1413" ue="20970" us="20969"/><bf gi="1415" ue="20974" us="20972"/><bf gi="1418" ue="20986" us="20976"/><bf gi="1429" ue="20990" us="20989"/><bf gi="1431" ue="21000" us="20992"/><bf gi="1440" ue="21003" us="21002"/><bf gi="1442" ue="21006" us="21006"/><bf gi="1443" ue="21016" us="21009"/><bf gi="1451" ue="21021" us="21021"/><bf gi="1452" ue="21026" us="21026"/><bf!
  gi="1453" ue="21029" us="21028"/><bf gi="1455" ue="21034" us="21031"/
><bf gi="1459" ue="21038" us="21038"/><bf gi="1460" ue="21043" us="21040"/><bf gi="1464" ue="21052" us="21045"/><bf gi="1472" ue="21061" us="21059"/><bf gi="1475" ue="21063" us="21063"/><bf gi="1476" ue="21069" us="21065"/><bf gi="1481" ue="21071" us="21071"/><bf gi="1482" ue="21080" us="21076"/><bf gi="1487" ue="21084" us="21082"/><bf gi="1490" ue="21089" us="21086"/><bf gi="1494" ue="21094" us="21091"/><bf gi="1498" ue="21098" us="21097"/><bf gi="1500" ue="21109" us="21102"/><bf gi="1508" ue="21113" us="21111"/><bf gi="1511" ue="21117" us="21117"/><bf gi="1512" ue="21120" us="21119"/><bf gi="1514" ue="21123" us="21122"/><bf gi="1516" ue="21125" us="21125"/><bf gi="1517" ue="21130" us="21127"/><bf gi="1521" ue="21133" us="21132"/><bf gi="1523" ue="21144" us="21137"/><bf gi="1531" ue="21148" us="21146"/><bf gi="1534" ue="21152" us="21151"/><bf gi="1536" ue="21159" us="21155"/><bf gi="1541" ue="21165" us="21161"/><bf gi="1546" ue="21169" us="21167"/><bf gi="1549" ue="21182" u!
 s="21172"/><bf gi="1560" ue="21185" us="21184"/><bf gi="1562" ue="21193" us="21187"/><bf gi="1569" ue="21197" us="21196"/><bf gi="1571" ue="21199" us="21199"/><bf gi="1572" ue="21202" us="21201"/><bf gi="1574" ue="21209" us="21204"/><bf gi="1580" ue="21226" us="21211"/><bf gi="1596" ue="21228" us="21228"/><bf gi="1597" ue="21242" us="21232"/><bf gi="1608" ue="21251" us="21246"/><bf gi="1614" ue="21256" us="21253"/><bf gi="1618" ue="21261" us="21258"/><bf gi="1622" ue="21265" us="21263"/><bf gi="1625" ue="21267" us="21267"/><bf gi="1626" ue="21281" us="21269"/><bf gi="1639" ue="21285" us="21283"/><bf gi="1642" ue="21293" us="21287"/><bf gi="1649" ue="21299" us="21295"/><bf gi="1654" ue="21301" us="21301"/><bf gi="1655" ue="21315" us="21304"/><bf gi="1667" ue="21325" us="21317"/><bf gi="1676" ue="21332" us="21329"/><bf gi="1680" ue="21340" us="21335"/><bf gi="1686" ue="21342" us="21342"/><bf gi="1687" ue="21345" us="21344"/><bf gi="1689" ue="21347" us="21347"/><bf gi="1690" u!
 e="21350" us="21349"/><bf gi="1692" ue="21353" us="21353"/><bf gi="169
3" ue="21365" us="21356"/><bf gi="1703" ue="21369" us="21367"/><bf gi="1706" ue="21371" us="21371"/><bf gi="1707" ue="21375" us="21374"/><bf gi="1709" ue="21380" us="21378"/><bf gi="1712" ue="21384" us="21383"/><bf gi="1714" ue="21390" us="21390"/><bf gi="1715" ue="21396" us="21395"/><bf gi="1717" ue="21398" us="21398"/><bf gi="1718" ue="21402" us="21400"/><bf gi="1721" ue="21405" us="21405"/><bf gi="1722" ue="21409" us="21407"/><bf gi="1725" ue="21414" us="21412"/><bf gi="1728" ue="21419" us="21416"/><bf gi="1732" ue="21424" us="21421"/><bf gi="1736" ue="21432" us="21426"/><bf gi="1743" ue="21435" us="21434"/><bf gi="1745" ue="21437" us="21437"/><bf gi="1746" ue="21440" us="21440"/><bf gi="1747" ue="21443" us="21442"/><bf gi="1749" ue="21445" us="21445"/><bf gi="1750" ue="21455" us="21448"/><bf gi="1758" ue="21463" us="21458"/><bf gi="1764" ue="21467" us="21465"/><bf gi="1767" ue="21491" us="21469"/><bf gi="1790" ue="21496" us="21493"/><bf gi="1794" ue="21498" us="21498"/><!
 bf gi="1795" ue="21508" us="21505"/><bf gi="1799" ue="21521" us="21512"/><bf gi="1809" ue="21523" us="21523"/><bf gi="1810" ue="21531" us="21530"/><bf gi="1812" ue="21533" us="21533"/><bf gi="1813" ue="21537" us="21535"/><bf gi="1816" ue="21551" us="21542"/><bf gi="1826" ue="21553" us="21553"/><bf gi="1827" ue="21558" us="21556"/><bf gi="1830" ue="21561" us="21560"/><bf gi="1832" ue="21566" us="21563"/><bf gi="1836" ue="21568" us="21568"/><bf gi="1837" ue="21572" us="21570"/><bf gi="1840" ue="21578" us="21574"/><bf gi="1845" ue="21583" us="21581"/><bf gi="1848" ue="21585" us="21585"/><bf gi="1849" ue="21599" us="21598"/><bf gi="1851" ue="21602" us="21602"/><bf gi="1852" ue="21604" us="21604"/><bf gi="1853" ue="21611" us="21606"/><bf gi="1859" ue="21614" us="21613"/><bf gi="1861" ue="21617" us="21616"/><bf gi="1863" ue="21623" us="21619"/><bf gi="1868" ue="21629" us="21627"/><bf gi="1871" ue="21633" us="21631"/><bf gi="1874" ue="21638" us="21635"/><bf gi="1878" ue="21650" us!
 ="21640"/><bf gi="1889" ue="21654" us="21653"/><bf gi="1891" ue="21660
" us="21660"/><bf gi="1892" ue="21663" us="21663"/><bf gi="1893" ue="21666" us="21665"/><bf gi="1895" ue="21679" us="21668"/><bf gi="1907" ue="21683" us="21681"/><bf gi="1910" ue="21698" us="21687"/><bf gi="1922" ue="21700" us="21700"/><bf gi="1923" ue="21706" us="21702"/><bf gi="1928" ue="21710" us="21709"/><bf gi="1930" ue="21720" us="21720"/><bf gi="1931" ue="21730" us="21728"/><bf gi="1934" ue="21734" us="21733"/><bf gi="1936" ue="21738" us="21736"/><bf gi="1939" ue="21743" us="21740"/><bf gi="1943" ue="21746" us="21746"/><bf gi="1944" ue="21750" us="21750"/><bf gi="1945" ue="21754" us="21754"/><bf gi="1946" ue="21761" us="21756"/><bf gi="1952" ue="21769" us="21764"/><bf gi="1958" ue="21776" us="21772"/><bf gi="1963" ue="21782" us="21780"/><bf gi="1966" ue="21803" us="21802"/><bf gi="1968" ue="21807" us="21806"/><bf gi="1970" ue="21811" us="21809"/><bf gi="1973" ue="21814" us="21813"/><bf gi="1975" ue="21817" us="21816"/><bf gi="1977" ue="21822" us="21819"/><bf gi="1981"!
  ue="21825" us="21824"/><bf gi="1983" ue="21831" us="21828"/><bf gi="1987" ue="21834" us="21833"/><bf gi="1989" ue="21837" us="21836"/><bf gi="1991" ue="21841" us="21839"/><bf gi="1994" ue="21843" us="21843"/><bf gi="1995" ue="21848" us="21846"/><bf gi="1998" ue="21854" us="21850"/><bf gi="2003" ue="21857" us="21856"/><bf gi="2005" ue="21860" us="21859"/><bf gi="2007" ue="21862" us="21862"/><bf gi="2008" ue="21884" us="21883"/><bf gi="2010" ue="21892" us="21886"/><bf gi="2017" ue="21899" us="21894"/><bf gi="2023" ue="21903" us="21902"/><bf gi="2025" ue="21908" us="21905"/><bf gi="2029" ue="21914" us="21911"/><bf gi="2033" ue="21919" us="21916"/><bf gi="2037" ue="21924" us="21923"/><bf gi="2039" ue="21934" us="21927"/><bf gi="2047" ue="21936" us="21936"/><bf gi="2048" ue="21938" us="21938"/><bf gi="2049" ue="21942" us="21942"/><bf gi="2050" ue="21951" us="21951"/><bf gi="2051" ue="21953" us="21953"/><bf gi="2052" ue="21959" us="21955"/><bf gi="2057" ue="21961" us="21961"/><b!
 f gi="2058" ue="21964" us="21963"/><bf gi="2060" ue="21966" us="21966"
/><bf gi="2061" ue="21972" us="21969"/><bf gi="2065" ue="21976" us="21975"/><bf gi="2067" ue="21980" us="21978"/><bf gi="2070" ue="21983" us="21982"/><bf gi="2072" ue="21988" us="21986"/><bf gi="2075" ue="21993" us="21993"/><bf gi="2076" ue="22007" us="22006"/><bf gi="2078" ue="22009" us="22009"/><bf gi="2079" ue="22015" us="22013"/><bf gi="2082" ue="22022" us="22021"/><bf gi="2084" ue="22026" us="22024"/><bf gi="2087" ue="22034" us="22029"/><bf gi="2093" ue="22036" us="22036"/><bf gi="2094" ue="22041" us="22038"/><bf gi="2098" ue="22043" us="22043"/><bf gi="2099" ue="22057" us="22057"/><bf gi="2100" ue="22060" us="22060"/><bf gi="2101" ue="22073" us="22063"/><bf gi="2112" ue="22077" us="22075"/><bf gi="2115" ue="22084" us="22079"/><bf gi="2121" ue="22086" us="22086"/><bf gi="2122" ue="22089" us="22089"/><bf gi="2123" ue="22096" us="22091"/><bf gi="2129" ue="22100" us="22100"/><bf gi="2130" ue="22107" us="22107"/><bf gi="2131" ue="22110" us="22110"/><bf gi="2132" ue="22116" !
 us="22112"/><bf gi="2137" ue="22118" us="22118"/><bf gi="2138" ue="22125" us="22120"/><bf gi="2144" ue="22127" us="22127"/><bf gi="2145" ue="22130" us="22129"/><bf gi="2147" ue="22133" us="22132"/><bf gi="2149" ue="22136" us="22136"/><bf gi="2150" ue="22138" us="22138"/><bf gi="2151" ue="22144" us="22144"/><bf gi="2152" ue="22152" us="22148"/><bf gi="2157" ue="22156" us="22154"/><bf gi="2160" ue="22159" us="22159"/><bf gi="2161" ue="22165" us="22164"/><bf gi="2163" ue="22170" us="22169"/><bf gi="2165" ue="22176" us="22173"/><bf gi="2169" ue="22178" us="22178"/><bf gi="2170" ue="22185" us="22181"/><bf gi="2175" ue="22190" us="22187"/><bf gi="2179" ue="22193" us="22193"/><bf gi="2180" ue="22196" us="22195"/><bf gi="2182" ue="22199" us="22198"/><bf gi="2184" ue="22204" us="22204"/><bf gi="2185" ue="22206" us="22206"/><bf gi="2186" ue="22211" us="22208"/><bf gi="2190" ue="22213" us="22213"/><bf gi="2191" ue="22225" us="22216"/><bf gi="2201" ue="22227" us="22227"/><bf gi="2202" !
 ue="22241" us="22231"/><bf gi="2213" ue="22248" us="22243"/><bf gi="22
19" ue="22251" us="22251"/><bf gi="2220" ue="22254" us="22253"/><bf gi="2222" ue="22259" us="22256"/><bf gi="2226" ue="22263" us="22262"/><bf gi="2228" ue="22266" us="22265"/><bf gi="2230" ue="22269" us="22269"/><bf gi="2231" ue="22276" us="22271"/><bf gi="2237" ue="22285" us="22279"/><bf gi="2244" ue="22287" us="22287"/><bf gi="2245" ue="22291" us="22289"/><bf gi="2248" ue="22294" us="22293"/><bf gi="2250" ue="22296" us="22296"/><bf gi="2251" ue="22301" us="22298"/><bf gi="2255" ue="22304" us="22303"/><bf gi="2257" ue="22314" us="22306"/><bf gi="2266" ue="22320" us="22316"/><bf gi="2271" ue="22324" us="22323"/><bf gi="2273" ue="22328" us="22327"/><bf gi="2275" ue="22331" us="22331"/><bf gi="2276" ue="22336" us="22333"/><bf gi="2280" ue="22338" us="22338"/><bf gi="2281" ue="22343" us="22341"/><bf gi="2284" ue="22346" us="22346"/><bf gi="2285" ue="22354" us="22348"/><bf gi="2292" ue="22361" us="22361"/><bf gi="2293" ue="22370" us="22369"/><bf gi="2295" ue="22379" us="22372"/>!
 <bf gi="2303" ue="22385" us="22381"/><bf gi="2308" ue="22389" us="22387"/><bf gi="2311" ue="22391" us="22391"/><bf gi="2312" ue="22396" us="22393"/><bf gi="2316" ue="22399" us="22398"/><bf gi="2318" ue="22403" us="22401"/><bf gi="2321" ue="22409" us="22408"/><bf gi="2323" ue="22412" us="22411"/><bf gi="2325" ue="22421" us="22419"/><bf gi="2328" ue="22423" us="22423"/><bf gi="2329" ue="22426" us="22425"/><bf gi="2331" ue="22436" us="22428"/><bf gi="2340" ue="22442" us="22439"/><bf gi="2344" ue="22444" us="22444"/><bf gi="2345" ue="22448" us="22448"/><bf gi="2346" ue="22451" us="22451"/><bf gi="2347" ue="22456" us="22456"/><bf gi="2348" ue="22461" us="22461"/><bf gi="2349" ue="22464" us="22464"/><bf gi="2350" ue="22467" us="22467"/><bf gi="2351" ue="22472" us="22470"/><bf gi="2354" ue="22476" us="22475"/><bf gi="2356" ue="22479" us="22478"/><bf gi="2358" ue="22486" us="22482"/><bf gi="2363" ue="22497" us="22492"/><bf gi="2369" ue="22500" us="22499"/><bf gi="2371" ue="22503" u!
 s="22502"/><bf gi="2373" ue="22505" us="22505"/><bf gi="2374" ue="2250
9" us="22509"/><bf gi="2375" ue="22512" us="22512"/><bf gi="2376" ue="22522" us="22516"/><bf gi="2383" ue="22528" us="22524"/><bf gi="2388" ue="22534" us="22530"/><bf gi="2393" ue="22541" us="22536"/><bf gi="2399" ue="22549" us="22549"/><bf gi="2400" ue="22553" us="22553"/><bf gi="2401" ue="22555" us="22555"/><bf gi="2402" ue="22561" us="22557"/><bf gi="2407" ue="22564" us="22564"/><bf gi="2408" ue="22567" us="22566"/><bf gi="2410" ue="22570" us="22570"/><bf gi="2411" ue="22573" us="22573"/><bf gi="2412" ue="22578" us="22575"/><bf gi="2416" ue="22581" us="22580"/><bf gi="2418" ue="22586" us="22585"/><bf gi="2420" ue="22589" us="22589"/><bf gi="2421" ue="22593" us="22591"/><bf gi="2424" ue="22605" us="22601"/><bf gi="2429" ue="22610" us="22607"/><bf gi="2433" ue="22613" us="22612"/><bf gi="2435" ue="22618" us="22615"/><bf gi="2439" ue="22623" us="22622"/><bf gi="2441" ue="22626" us="22625"/><bf gi="2443" ue="22628" us="22628"/><bf gi="2444" ue="22633" us="22631"/><bf gi="2447!
 " ue="22635" us="22635"/><bf gi="2448" ue="22640" us="22640"/><bf gi="2449" ue="22642" us="22642"/><bf gi="2450" ue="22645" us="22645"/><bf gi="2451" ue="22649" us="22648"/><bf gi="2453" ue="22652" us="22652"/><bf gi="2454" ue="22657" us="22654"/><bf gi="2458" ue="22659" us="22659"/><bf gi="2459" ue="22661" us="22661"/><bf gi="2460" ue="22666" us="22663"/><bf gi="2464" ue="22669" us="22668"/><bf gi="2466" ue="22672" us="22671"/><bf gi="2468" ue="22676" us="22675"/><bf gi="2470" ue="22679" us="22678"/><bf gi="2472" ue="22690" us="22684"/><bf gi="2479" ue="22694" us="22694"/><bf gi="2480" ue="22697" us="22696"/><bf gi="2482" ue="22699" us="22699"/><bf gi="2483" ue="22702" us="22702"/><bf gi="2484" ue="22707" us="22705"/><bf gi="2487" ue="22716" us="22712"/><bf gi="2492" ue="22718" us="22718"/><bf gi="2493" ue="22722" us="22721"/><bf gi="2495" ue="22725" us="22724"/><bf gi="2497" ue="22728" us="22727"/><bf gi="2499" ue="22730" us="22730"/><bf gi="2500" ue="22734" us="22732"/><!
 bf gi="2503" ue="22746" us="22736"/><bf gi="2514" ue="22751" us="22748
"/><bf gi="2518" ue="22754" us="22753"/><bf gi="2520" ue="22757" us="22756"/><bf gi="2522" ue="22761" us="22761"/><bf gi="2523" ue="22764" us="22763"/><bf gi="2525" ue="22771" us="22766"/><bf gi="2531" ue="22775" us="22775"/><bf gi="2532" ue="22781" us="22777"/><bf gi="2537" ue="22786" us="22786"/><bf gi="2538" ue="22790" us="22789"/><bf gi="2540" ue="22796" us="22793"/><bf gi="2544" ue="22800" us="22799"/><bf gi="2546" ue="22806" us="22802"/><bf gi="2551" ue="22813" us="22808"/><bf gi="2557" ue="22821" us="22817"/><bf gi="2562" ue="22835" us="22823"/><bf gi="2575" ue="22840" us="22837"/><bf gi="2579" ue="22847" us="22846"/><bf gi="2581" ue="22852" us="22851"/><bf gi="2583" ue="22857" us="22854"/><bf gi="2587" ue="22869" us="22862"/><bf gi="2595" ue="22875" us="22871"/><bf gi="2600" ue="22883" us="22877"/><bf gi="2607" ue="22885" us="22885"/><bf gi="2608" ue="22895" us="22887"/><bf gi="2617" ue="22902" us="22898"/><bf gi="2622" ue="22905" us="22904"/><bf gi="2624" ue="22909"!
  us="22907"/><bf gi="2627" ue="22916" us="22913"/><bf gi="2631" ue="22926" us="22922"/><bf gi="2636" ue="22931" us="22930"/><bf gi="2638" ue="22935" us="22933"/><bf gi="2641" ue="22937" us="22937"/><bf gi="2642" ue="22939" us="22939"/><bf gi="2643" ue="22941" us="22941"/><bf gi="2644" ue="22943" us="22943"/><bf gi="2645" ue="22949" us="22947"/><bf gi="2648" ue="22952" us="22951"/><bf gi="2650" ue="22960" us="22956"/><bf gi="2655" ue="22963" us="22962"/><bf gi="2657" ue="22967" us="22967"/><bf gi="2658" ue="22972" us="22969"/><bf gi="2662" ue="22974" us="22974"/><bf gi="2663" ue="22977" us="22977"/><bf gi="2664" ue="22980" us="22979"/><bf gi="2666" ue="22982" us="22982"/><bf gi="2667" ue="22987" us="22984"/><bf gi="2671" ue="22989" us="22989"/><bf gi="2672" ue="22996" us="22992"/><bf gi="2677" ue="23002" us="23001"/><bf gi="2679" ue="23007" us="23004"/><bf gi="2683" ue="23016" us="23011"/><bf gi="2689" ue="23019" us="23018"/><bf gi="2691" ue="23023" us="23022"/><bf gi="2693"!
  ue="23026" us="23025"/><bf gi="2695" ue="23028" us="23028"/><bf gi="2
696" ue="23031" us="23030"/><bf gi="2698" ue="23035" us="23035"/><bf gi="2699" ue="23041" us="23039"/><bf gi="2702" ue="23044" us="23043"/><bf gi="2704" ue="23049" us="23049"/><bf gi="2705" ue="23054" us="23052"/><bf gi="2708" ue="23059" us="23057"/><bf gi="2711" ue="23064" us="23064"/><bf gi="2712" ue="23066" us="23066"/><bf gi="2713" ue="23068" us="23068"/><bf gi="2714" ue="23072" us="23070"/><bf gi="2717" ue="23077" us="23075"/><bf gi="2720" ue="23082" us="23079"/><bf gi="2724" ue="23085" us="23085"/><bf gi="2725" ue="23088" us="23087"/><bf gi="2727" ue="23094" us="23093"/><bf gi="2729" ue="23100" us="23100"/><bf gi="2730" ue="23105" us="23104"/><bf gi="2732" ue="23113" us="23108"/><bf gi="2738" ue="23116" us="23116"/><bf gi="2739" ue="23120" us="23120"/><bf gi="2740" ue="23125" us="23125"/><bf gi="2741" ue="23130" us="23130"/><bf gi="2742" ue="23134" us="23134"/><bf gi="2743" ue="23139" us="23138"/><bf gi="2745" ue="23143" us="23141"/><bf gi="2748" ue="23146" us="23146"/!
 ><bf gi="2749" ue="23149" us="23148"/><bf gi="2751" ue="23159" us="23159"/><bf gi="2752" ue="23163" us="23162"/><bf gi="2754" ue="23167" us="23166"/><bf gi="2756" ue="23179" us="23179"/><bf gi="2757" ue="23184" us="23184"/><bf gi="2758" ue="23187" us="23186"/><bf gi="2760" ue="23190" us="23190"/><bf gi="2761" ue="23196" us="23193"/><bf gi="2765" ue="23200" us="23198"/><bf gi="2768" ue="23202" us="23202"/><bf gi="2769" ue="23207" us="23207"/><bf gi="2770" ue="23212" us="23212"/><bf gi="2771" ue="23219" us="23217"/><bf gi="2774" ue="23221" us="23221"/><bf gi="2775" ue="23224" us="23224"/><bf gi="2776" ue="23231" us="23226"/><bf gi="2782" ue="23234" us="23233"/><bf gi="2784" ue="23236" us="23236"/><bf gi="2785" ue="23238" us="23238"/><bf gi="2786" ue="23241" us="23240"/><bf gi="2788" ue="23244" us="23243"/><bf gi="2790" ue="23248" us="23247"/><bf gi="2792" ue="23255" us="23254"/><bf gi="2794" ue="23258" us="23258"/><bf gi="2795" ue="23260" us="23260"/><bf gi="2796" ue="23265" !
 us="23264"/><bf gi="2798" ue="23267" us="23267"/><bf gi="2799" ue="232
70" us="23269"/><bf gi="2801" ue="23274" us="23273"/><bf gi="2803" ue="23278" us="23278"/><bf gi="2804" ue="23286" us="23285"/><bf gi="2806" ue="23291" us="23290"/><bf gi="2808" ue="23293" us="23293"/><bf gi="2809" ue="23297" us="23296"/><bf gi="2811" ue="23305" us="23304"/><bf gi="2813" ue="23308" us="23307"/><bf gi="2815" ue="23319" us="23318"/><bf gi="2817" ue="23321" us="23321"/><bf gi="2818" ue="23323" us="23323"/><bf gi="2819" ue="23325" us="23325"/><bf gi="2820" ue="23330" us="23329"/><bf gi="2822" ue="23333" us="23333"/><bf gi="2823" ue="23338" us="23338"/><bf gi="2824" ue="23341" us="23340"/><bf gi="2826" ue="23344" us="23344"/><bf gi="2827" ue="23346" us="23346"/><bf gi="2828" ue="23348" us="23348"/><bf gi="2829" ue="23350" us="23350"/><bf gi="2830" ue="23352" us="23352"/><bf gi="2831" ue="23358" us="23358"/><bf gi="2832" ue="23361" us="23360"/><bf gi="2834" ue="23363" us="23363"/><bf gi="2835" ue="23365" us="23365"/><bf gi="2836" ue="23372" us="23371"/><bf gi="283!
 8" ue="23378" us="23376"/><bf gi="2841" ue="23384" us="23380"/><bf gi="2846" ue="23391" us="23386"/><bf gi="2852" ue="23398" us="23395"/><bf gi="2856" ue="23401" us="23400"/><bf gi="2858" ue="23403" us="23403"/><bf gi="2859" ue="23409" us="23406"/><bf gi="2863" ue="23411" us="23411"/><bf gi="2864" ue="23413" us="23413"/><bf gi="2865" ue="23416" us="23416"/><bf gi="2866" ue="23418" us="23418"/><bf gi="2867" ue="23425" us="23420"/><bf gi="2873" ue="23441" us="23427"/><bf gi="2888" ue="23453" us="23443"/><bf gi="2899" ue="23455" us="23455"/><bf gi="2900" ue="23462" us="23458"/><bf gi="2905" ue="23465" us="23464"/><bf gi="2907" ue="23482" us="23468"/><bf gi="2922" ue="23484" us="23484"/><bf gi="2923" ue="23495" us="23487"/><bf gi="2932" ue="23497" us="23497"/><bf gi="2933" ue="23501" us="23500"/><bf gi="2935" ue="23504" us="23503"/><bf gi="2937" ue="23508" us="23506"/><bf gi="2940" ue="23515" us="23510"/><bf gi="2946" ue="23522" us="23517"/><bf gi="2952" ue="23529" us="23524"/>!
 <bf gi="2958" ue="23532" us="23531"/><bf gi="2960" ue="23537" us="2353
4"/><bf gi="2964" ue="23542" us="23539"/><bf gi="2968" ue="23544" us="23544"/><bf gi="2969" ue="23546" us="23546"/><bf gi="2970" ue="23551" us="23549"/><bf gi="2973" ue="23554" us="23553"/><bf gi="2975" ue="23567" us="23556"/><bf gi="2987" ue="23569" us="23569"/><bf gi="2988" ue="23571" us="23571"/><bf gi="2989" ue="23575" us="23574"/><bf gi="2991" ue="23578" us="23578"/><bf gi="2992" ue="23584" us="23582"/><bf gi="2995" ue="23588" us="23586"/><bf gi="2998" ue="23590" us="23590"/><bf gi="2999" ue="23593" us="23592"/><bf gi="3001" ue="23598" us="23595"/><bf gi="3005" ue="23602" us="23600"/><bf gi="3008" ue="23606" us="23605"/><bf gi="3010" ue="23617" us="23608"/><bf gi="3020" ue="23622" us="23621"/><bf gi="3022" ue="23624" us="23624"/><bf gi="3023" ue="23627" us="23626"/><bf gi="3025" ue="23633" us="23629"/><bf gi="3030" ue="23635" us="23635"/><bf gi="3031" ue="23637" us="23637"/><bf gi="3032" ue="23642" us="23641"/><bf gi="3034" ue="23644" us="23644"/><bf gi="3035" ue="23646!
 " us="23646"/><bf gi="3036" ue="23653" us="23648"/><bf gi="3042" ue="23657" us="23655"/><bf gi="3045" ue="23665" us="23660"/><bf gi="3051" ue="23670" us="23668"/><bf gi="3054" ue="23677" us="23673"/><bf gi="3059" ue="23688" us="23687"/><bf gi="3061" ue="23690" us="23690"/><bf gi="3062" ue="23692" us="23692"/><bf gi="3063" ue="23698" us="23695"/><bf gi="3067" ue="23700" us="23700"/><bf gi="3068" ue="23709" us="23709"/><bf gi="3069" ue="23715" us="23711"/><bf gi="3074" ue="23718" us="23718"/><bf gi="3075" ue="23724" us="23720"/><bf gi="3080" ue="23736" us="23729"/><bf gi="3088" ue="23740" us="23738"/><bf gi="3091" ue="23742" us="23742"/><bf gi="3092" ue="23749" us="23749"/><bf gi="3093" ue="23751" us="23751"/><bf gi="3094" ue="23753" us="23753"/><bf gi="3095" ue="23755" us="23755"/><bf gi="3096" ue="23762" us="23762"/><bf gi="3097" ue="23767" us="23767"/><bf gi="3098" ue="23769" us="23769"/><bf gi="3099" ue="23773" us="23773"/><bf gi="3100" ue="23777" us="23776"/><bf gi="3102!
 " ue="23786" us="23784"/><bf gi="3105" ue="23794" us="23789"/><bf gi="
3111" ue="23798" us="23796"/><bf gi="3114" ue="23803" us="23802"/><bf gi="3116" ue="23805" us="23805"/><bf gi="3117" ue="23809" us="23809"/><bf gi="3118" ue="23815" us="23814"/><bf gi="3120" ue="23819" us="23819"/><bf gi="3121" ue="23822" us="23821"/><bf gi="3123" ue="23826" us="23825"/><bf gi="3125" ue="23835" us="23828"/><bf gi="3133" ue="23839" us="23839"/><bf gi="3134" ue="23844" us="23842"/><bf gi="3137" ue="23847" us="23846"/><bf gi="3139" ue="23849" us="23849"/><bf gi="3140" ue="23851" us="23851"/><bf gi="3141" ue="23857" us="23857"/><bf gi="3142" ue="23860" us="23860"/><bf gi="3143" ue="23865" us="23865"/><bf gi="3144" ue="23869" us="23869"/><bf gi="3145" ue="23871" us="23871"/><bf gi="3146" ue="23875" us="23874"/><bf gi="3148" ue="23878" us="23878"/><bf gi="3149" ue="23880" us="23880"/><bf gi="3150" ue="23884" us="23882"/><bf gi="3153" ue="23886" us="23886"/><bf gi="3154" ue="23890" us="23888"/><bf gi="3157" ue="23893" us="23893"/><bf gi="3158" ue="23897" us="23897"!
 /><bf gi="3159" ue="23900" us="23900"/><bf gi="3160" ue="23906" us="23903"/><bf gi="3164" ue="23908" us="23908"/><bf gi="3165" ue="23914" us="23913"/><bf gi="3167" ue="23917" us="23916"/><bf gi="3169" ue="23920" us="23919"/><bf gi="3171" ue="23923" us="23923"/><bf gi="3172" ue="23926" us="23926"/><bf gi="3173" ue="23930" us="23929"/><bf gi="3175" ue="23935" us="23934"/><bf gi="3177" ue="23940" us="23937"/><bf gi="3181" ue="23944" us="23943"/><bf gi="3183" ue="23948" us="23946"/><bf gi="3186" ue="23952" us="23952"/><bf gi="3187" ue="23957" us="23954"/><bf gi="3191" ue="23961" us="23961"/><bf gi="3192" ue="23963" us="23963"/><bf gi="3193" ue="23965" us="23965"/><bf gi="3194" ue="23968" us="23967"/><bf gi="3196" ue="23970" us="23970"/><bf gi="3197" ue="23975" us="23975"/><bf gi="3198" ue="23980" us="23979"/><bf gi="3200" ue="23982" us="23982"/><bf gi="3201" ue="23984" us="23984"/><bf gi="3202" ue="23986" us="23986"/><bf gi="3203" ue="23988" us="23988"/><bf gi="3204" ue="23994"!
  us="23991"/><bf gi="3208" ue="23997" us="23996"/><bf gi="3210" ue="24
003" us="24003"/><bf gi="3211" ue="24007" us="24007"/><bf gi="3212" ue="24009" us="24009"/><bf gi="3213" ue="24014" us="24011"/><bf gi="3217" ue="24016" us="24016"/><bf gi="3218" ue="24019" us="24018"/><bf gi="3220" ue="24022" us="24022"/><bf gi="3221" ue="24025" us="24024"/><bf gi="3223" ue="24027" us="24027"/><bf gi="3224" ue="24030" us="24029"/><bf gi="3226" ue="24033" us="24032"/><bf gi="3228" ue="24041" us="24035"/><bf gi="3235" ue="24043" us="24043"/><bf gi="3236" ue="24046" us="24046"/><bf gi="3237" ue="24053" us="24049"/><bf gi="3242" ue="24057" us="24055"/><bf gi="3245" ue="24059" us="24059"/><bf gi="3246" ue="24062" us="24061"/><bf gi="3248" ue="24064" us="24064"/><bf gi="3249" ue="24067" us="24066"/><bf gi="3251" ue="24071" us="24070"/><bf gi="3253" ue="24077" us="24075"/><bf gi="3256" ue="24082" us="24081"/><bf gi="3258" ue="24086" us="24084"/><bf gi="3261" ue="24091" us="24088"/><bf gi="3265" ue="24093" us="24093"/><bf gi="3266" ue="24096" us="24095"/><bf gi="32!
 68" ue="24101" us="24101"/><bf gi="3269" ue="24104" us="24104"/><bf gi="3270" ue="24107" us="24107"/><bf gi="3271" ue="24112" us="24109"/><bf gi="3275" ue="24115" us="24114"/><bf gi="3277" ue="24120" us="24117"/><bf gi="3281" ue="24126" us="24125"/><bf gi="3283" ue="24128" us="24128"/><bf gi="3284" ue="24133" us="24131"/><bf gi="3287" ue="24135" us="24135"/><bf gi="3288" ue="24137" us="24137"/><bf gi="3289" ue="24140" us="24139"/><bf gi="3291" ue="24142" us="24142"/><bf gi="3292" ue="24145" us="24144"/><bf gi="3294" ue="24152" us="24148"/><bf gi="3299" ue="24156" us="24155"/><bf gi="3301" ue="24159" us="24158"/><bf gi="3303" ue="24164" us="24161"/><bf gi="3307" ue="24168" us="24168"/><bf gi="3308" ue="24174" us="24170"/><bf gi="3313" ue="24176" us="24176"/><bf gi="3314" ue="24182" us="24178"/><bf gi="3319" ue="24193" us="24184"/><bf gi="3329" ue="24196" us="24195"/><bf gi="3331" ue="24199" us="24199"/><bf gi="3332" ue="24203" us="24202"/><bf gi="3334" ue="24207" us="24206"/!
 ><bf gi="3336" ue="24215" us="24213"/><bf gi="3339" ue="24218" us="242
18"/><bf gi="3340" ue="24220" us="24220"/><bf gi="3341" ue="24224" us="24224"/><bf gi="3342" ue="24226" us="24226"/><bf gi="3343" ue="24232" us="24228"/><bf gi="3348" ue="24237" us="24234"/><bf gi="3352" ue="24241" us="24241"/><bf gi="3353" ue="24243" us="24243"/><bf gi="3354" ue="24248" us="24245"/><bf gi="3358" ue="24255" us="24253"/><bf gi="3361" ue="24259" us="24257"/><bf gi="3364" ue="24262" us="24262"/><bf gi="3365" ue="24268" us="24264"/><bf gi="3370" ue="24278" us="24270"/><bf gi="3379" ue="24291" us="24282"/><bf gi="3389" ue="24293" us="24293"/><bf gi="3390" ue="24297" us="24296"/><bf gi="3392" ue="24300" us="24299"/><bf gi="3394" ue="24305" us="24304"/><bf gi="3396" ue="24308" us="24307"/><bf gi="3398" ue="24312" us="24310"/><bf gi="3401" ue="24316" us="24314"/><bf gi="3404" ue="24319" us="24318"/><bf gi="3406" ue="24324" us="24321"/><bf gi="3410" ue="24337" us="24326"/><bf gi="3422" ue="24345" us="24339"/><bf gi="3429" ue="24349" us="24347"/><bf gi="3432" ue="2435!
 1" us="24351"/><bf gi="3433" ue="24361" us="24353"/><bf gi="3442" ue="24369" us="24363"/><bf gi="3449" ue="24376" us="24372"/><bf gi="3454" ue="24385" us="24379"/><bf gi="3461" ue="24389" us="24388"/><bf gi="3463" ue="24392" us="24391"/><bf gi="3465" ue="24394" us="24394"/><bf gi="3466" ue="24398" us="24396"/><bf gi="3469" ue="24401" us="24400"/><bf gi="3471" ue="24404" us="24403"/><bf gi="3473" ue="24409" us="24406"/><bf gi="3477" ue="24413" us="24411"/><bf gi="3480" ue="24420" us="24416"/><bf gi="3485" ue="24423" us="24422"/><bf gi="3487" ue="24429" us="24425"/><bf gi="3492" ue="24437" us="24431"/><bf gi="3499" ue="24442" us="24439"/><bf gi="3503" ue="24453" us="24444"/><bf gi="3513" ue="24461" us="24455"/><bf gi="3520" ue="24467" us="24463"/><bf gi="3525" ue="24473" us="24470"/><bf gi="3529" ue="24478" us="24476"/><bf gi="3532" ue="24482" us="24480"/><bf gi="3535" ue="24484" us="24484"/><bf gi="3536" ue="24497" us="24487"/><bf gi="3547" ue="24500" us="24499"/><bf gi="354!
 9" ue="24505" us="24503"/><bf gi="3552" ue="24509" us="24508"/><bf gi=
"3554" ue="24517" us="24515"/><bf gi="3557" ue="24521" us="24519"/><bf gi="3560" ue="24525" us="24523"/><bf gi="3563" ue="24532" us="24528"/><bf gi="3568" ue="24537" us="24534"/><bf gi="3572" ue="24542" us="24540"/><bf gi="3575" ue="24546" us="24544"/><bf gi="3578" ue="24548" us="24548"/><bf gi="3579" ue="24563" us="24552"/><bf gi="3591" ue="24566" us="24565"/><bf gi="3593" ue="24568" us="24568"/><bf gi="3594" ue="24573" us="24570"/><bf gi="3598" ue="24575" us="24575"/><bf gi="3599" ue="24583" us="24583"/><bf gi="3600" ue="24586" us="24586"/><bf gi="3601" ue="24592" us="24589"/><bf gi="3605" ue="24605" us="24594"/><bf gi="3617" ue="24609" us="24607"/><bf gi="3620" ue="24619" us="24612"/><bf gi="3628" ue="24621" us="24621"/><bf gi="3629" ue="24623" us="24623"/><bf gi="3630" ue="24625" us="24625"/><bf gi="3631" ue="24627" us="24627"/><bf gi="3632" ue="24629" us="24629"/><bf gi="3633" ue="24634" us="24634"/><bf gi="3634" ue="24643" us="24640"/><bf gi="3638" ue="24653" us="24646!
 "/><bf gi="3646" ue="24658" us="24656"/><bf gi="3649" ue="24663" us="24660"/><bf gi="3653" ue="24666" us="24665"/><bf gi="3655" ue="24669" us="24669"/><bf gi="3656" ue="24677" us="24671"/><bf gi="3663" ue="24685" us="24679"/><bf gi="3670" ue="24689" us="24687"/><bf gi="3673" ue="24693" us="24693"/><bf gi="3674" ue="24695" us="24695"/><bf gi="3675" ue="24703" us="24702"/><bf gi="3677" ue="24710" us="24705"/><bf gi="3683" ue="24718" us="24712"/><bf gi="3690" ue="24728" us="24721"/><bf gi="3698" ue="24731" us="24730"/><bf gi="3700" ue="24736" us="24733"/><bf gi="3704" ue="24746" us="24738"/><bf gi="3713" ue="24760" us="24752"/><bf gi="3722" ue="24766" us="24763"/><bf gi="3726" ue="24770" us="24770"/><bf gi="3727" ue="24779" us="24772"/><bf gi="3735" ue="24783" us="24782"/><bf gi="3737" ue="24785" us="24785"/><bf gi="3738" ue="24789" us="24787"/><bf gi="3741" ue="24803" us="24792"/><bf gi="3753" ue="24805" us="24805"/><bf gi="3754" ue="24808" us="24807"/><bf gi="3756" ue="24829!
 " us="24816"/><bf gi="3770" ue="24835" us="24832"/><bf gi="3774" ue="2
4842" us="24838"/><bf gi="3779" ue="24855" us="24844"/><bf gi="3791" ue="24860" us="24857"/><bf gi="3795" ue="24866" us="24862"/><bf gi="3800" ue="24872" us="24871"/><bf gi="3802" ue="24876" us="24874"/><bf gi="3805" ue="24881" us="24880"/><bf gi="3807" ue="24887" us="24884"/><bf gi="3811" ue="24889" us="24889"/><bf gi="3812" ue="24895" us="24892"/><bf gi="3816" ue="24898" us="24897"/><bf gi="3818" ue="24910" us="24900"/><bf gi="3829" ue="24915" us="24915"/><bf gi="3830" ue="24917" us="24917"/><bf gi="3831" ue="24922" us="24920"/><bf gi="3834" ue="24928" us="24925"/><bf gi="3838" ue="24931" us="24930"/><bf gi="3840" ue="24933" us="24933"/><bf gi="3841" ue="24936" us="24935"/><bf gi="3843" ue="24940" us="24939"/><bf gi="3845" ue="24952" us="24942"/><bf gi="3856" ue="24956" us="24955"/><bf gi="3858" ue="24964" us="24958"/><bf gi="3865" ue="24967" us="24967"/><bf gi="3866" ue="24971" us="24970"/><bf gi="3868" ue="24974" us="24973"/><bf gi="3870" ue="24980" us="24976"/><bf gi="3!
 875" ue="24986" us="24982"/><bf gi="3880" ue="24989" us="24988"/><bf gi="3882" ue="24992" us="24991"/><bf gi="3884" ue="24997" us="24996"/><bf gi="3886" ue="25006" us="24999"/><bf gi="3894" ue="25010" us="25010"/><bf gi="3895" ue="25014" us="25014"/><bf gi="3896" ue="25018" us="25016"/><bf gi="3899" ue="25020" us="25020"/><bf gi="3900" ue="25022" us="25022"/><bf gi="3901" ue="25027" us="25024"/><bf gi="3905" ue="25040" us="25030"/><bf gi="3916" ue="25045" us="25045"/><bf gi="3917" ue="25055" us="25052"/><bf gi="3921" ue="25059" us="25057"/><bf gi="3924" ue="25063" us="25061"/><bf gi="3927" ue="25065" us="25065"/><bf gi="3928" ue="25069" us="25068"/><bf gi="3930" ue="25071" us="25071"/><bf gi="3931" ue="25074" us="25074"/><bf gi="3932" ue="25076" us="25076"/><bf gi="3933" ue="25080" us="25078"/><bf gi="3936" ue="25082" us="25082"/><bf gi="3937" ue="25089" us="25084"/><bf gi="3943" ue="25092" us="25091"/><bf gi="3945" ue="25098" us="25095"/><bf gi="3949" ue="25102" us="25100"!
 /><bf gi="3952" ue="25110" us="25104"/><bf gi="3959" ue="25123" us="25
114"/><bf gi="3969" ue="25127" us="25126"/><bf gi="3971" ue="25131" us="25129"/><bf gi="3974" ue="25136" us="25134"/><bf gi="3977" ue="25140" us="25138"/><bf gi="3980" ue="25145" us="25144"/><bf gi="3982" ue="25147" us="25147"/><bf gi="3983" ue="25149" us="25149"/><bf gi="3984" ue="25156" us="25151"/><bf gi="3990" ue="25161" us="25158"/><bf gi="3994" ue="25166" us="25163"/><bf gi="3998" ue="25174" us="25168"/><bf gi="4005" ue="25176" us="25176"/><bf gi="4006" ue="25180" us="25178"/><bf gi="4009" ue="25182" us="25182"/><bf gi="4010" ue="25184" us="25184"/><bf gi="4011" ue="25188" us="25187"/><bf gi="4013" ue="25192" us="25192"/><bf gi="4014" ue="25199" us="25197"/><bf gi="4017" ue="25201" us="25201"/><bf gi="4018" ue="25203" us="25203"/><bf gi="4019" ue="25206" us="25206"/><bf gi="4020" ue="25210" us="25209"/><bf gi="4022" ue="25216" us="25212"/><bf gi="4027" ue="25220" us="25218"/><bf gi="4030" ue="25226" us="25225"/><bf gi="4032" ue="25240" us="25229"/><bf gi="4044" ue="252!
 44" us="25243"/><bf gi="4046" ue="25246" us="25246"/><bf gi="4047" ue="25254" us="25254"/><bf gi="4048" ue="25256" us="25256"/><bf gi="4049" ue="25260" us="25259"/><bf gi="4051" ue="25265" us="25265"/><bf gi="4052" ue="25267" us="25267"/><bf gi="4053" ue="25271" us="25269"/><bf gi="4056" ue="25279" us="25273"/><bf gi="4063" ue="25282" us="25282"/><bf gi="4064" ue="25290" us="25284"/><bf gi="4071" ue="25309" us="25292"/><bf gi="4089" ue="25313" us="25312"/><bf gi="4091" ue="25322" us="25322"/><bf gi="4092" ue="25327" us="25324"/><bf gi="4096" ue="25335" us="25329"/><bf gi="4103" ue="25343" us="25340"/><bf gi="4107" ue="25348" us="25345"/><bf gi="4111" ue="25357" us="25351"/><bf gi="4118" ue="25361" us="25360"/><bf gi="4120" ue="25363" us="25363"/><bf gi="4121" ue="25366" us="25366"/><bf gi="4122" ue="25369" us="25368"/><bf gi="4124" ue="25375" us="25375"/><bf gi="4125" ue="25387" us="25383"/><bf gi="4130" ue="25389" us="25389"/><bf gi="4131" ue="25391" us="25391"/><bf gi="41!
 32" ue="25398" us="25397"/><bf gi="4134" ue="25402" us="25401"/><bf gi
="4136" ue="25407" us="25404"/><bf gi="4140" ue="25412" us="25409"/><bf gi="4144" ue="25414" us="25414"/><bf gi="4145" ue="25424" us="25417"/><bf gi="4153" ue="25429" us="25426"/><bf gi="4157" ue="25432" us="25431"/><bf gi="4159" ue="25436" us="25435"/><bf gi="4161" ue="25449" us="25445"/><bf gi="4166" ue="25454" us="25451"/><bf gi="4170" ue="25458" us="25457"/><bf gi="4172" ue="25464" us="25460"/><bf gi="4177" ue="25469" us="25466"/><bf gi="4181" ue="25472" us="25471"/><bf gi="4183" ue="25476" us="25474"/><bf gi="4186" ue="25482" us="25479"/><bf gi="4190" ue="25484" us="25484"/><bf gi="4191" ue="25488" us="25486"/><bf gi="4194" ue="25490" us="25490"/><bf gi="4195" ue="25494" us="25492"/><bf gi="4198" ue="25499" us="25496"/><bf gi="4202" ue="25519" us="25502"/><bf gi="4220" ue="25522" us="25522"/><bf gi="4221" ue="25525" us="25524"/><bf gi="4223" ue="25531" us="25531"/><bf gi="4224" ue="25534" us="25533"/><bf gi="4226" ue="25537" us="25536"/><bf gi="4228" ue="25542" us="2553!
 9"/><bf gi="4232" ue="25545" us="25544"/><bf gi="4234" ue="25558" us="25550"/><bf gi="4243" ue="25564" us="25562"/><bf gi="4246" ue="25569" us="25568"/><bf gi="4248" ue="25571" us="25571"/><bf gi="4249" ue="25573" us="25573"/><bf gi="4250" ue="25578" us="25577"/><bf gi="4252" ue="25580" us="25580"/><bf gi="4253" ue="25582" us="25582"/><bf gi="4254" ue="25590" us="25586"/><bf gi="4259" ue="25594" us="25592"/><bf gi="4262" ue="25606" us="25606"/><bf gi="4263" ue="25610" us="25609"/><bf gi="4265" ue="25613" us="25613"/><bf gi="4266" ue="25616" us="25615"/><bf gi="4268" ue="25620" us="25618"/><bf gi="4271" ue="25624" us="25622"/><bf gi="4274" ue="25628" us="25628"/><bf gi="4275" ue="25630" us="25630"/><bf gi="4276" ue="25632" us="25632"/><bf gi="4277" ue="25634" us="25634"/><bf gi="4278" ue="25638" us="25636"/><bf gi="4281" ue="25642" us="25640"/><bf gi="4284" ue="25645" us="25644"/><bf gi="4286" ue="25648" us="25647"/><bf gi="4288" ue="25654" us="25652"/><bf gi="4291" ue="2565!
 8" us="25658"/><bf gi="4292" ue="25663" us="25661"/><bf gi="4295" ue="
25666" us="25666"/><bf gi="4296" ue="25675" us="25675"/><bf gi="4297" ue="25679" us="25678"/><bf gi="4299" ue="25684" us="25681"/><bf gi="4303" ue="25688" us="25688"/><bf gi="4304" ue="25693" us="25690"/><bf gi="4308" ue="25697" us="25695"/><bf gi="4311" ue="25699" us="25699"/><bf gi="4312" ue="25703" us="25703"/><bf gi="4313" ue="25705" us="25705"/><bf gi="4314" ue="25709" us="25709"/><bf gi="4315" ue="25711" us="25711"/><bf gi="4316" ue="25716" us="25715"/><bf gi="4318" ue="25718" us="25718"/><bf gi="4319" ue="25720" us="25720"/><bf gi="4320" ue="25723" us="25722"/><bf gi="4322" ue="25725" us="25725"/><bf gi="4323" ue="25731" us="25731"/><bf gi="4324" ue="25733" us="25733"/><bf gi="4325" ue="25736" us="25735"/><bf gi="4327" ue="25747" us="25743"/><bf gi="4332" ue="25749" us="25749"/><bf gi="4333" ue="25755" us="25752"/><bf gi="4337" ue="25759" us="25757"/><bf gi="4340" ue="25761" us="25761"/><bf gi="4341" ue="25766" us="25763"/><bf gi="4345" ue="25769" us="25768"/><bf gi="!
 4347" ue="25774" us="25771"/><bf gi="4351" ue="25776" us="25776"/><bf gi="4352" ue="25779" us="25778"/><bf gi="4354" ue="25785" us="25785"/><bf gi="4355" ue="25791" us="25787"/><bf gi="4360" ue="25794" us="25793"/><bf gi="4362" ue="25797" us="25796"/><bf gi="4364" ue="25799" us="25799"/><bf gi="4365" ue="25806" us="25801"/><bf gi="4371" ue="25810" us="25808"/><bf gi="4374" ue="25813" us="25812"/><bf gi="4376" ue="25816" us="25815"/><bf gi="4378" ue="25818" us="25818"/><bf gi="4379" ue="25831" us="25824"/><bf gi="4387" ue="25834" us="25833"/><bf gi="4389" ue="25837" us="25836"/><bf gi="4391" ue="25842" us="25839"/><bf gi="4395" ue="25847" us="25844"/><bf gi="4399" ue="25851" us="25850"/><bf gi="4401" ue="25857" us="25853"/><bf gi="4406" ue="25861" us="25860"/><bf gi="4408" ue="25866" us="25864"/><bf gi="4411" ue="25871" us="25871"/><bf gi="4412" ue="25876" us="25875"/><bf gi="4414" ue="25878" us="25878"/><bf gi="4415" ue="25881" us="25880"/><bf gi="4417" ue="25887" us="25883!
 "/><bf gi="4422" ue="25892" us="25890"/><bf gi="4425" ue="25894" us="2
5894"/><bf gi="4426" ue="25900" us="25897"/><bf gi="4430" ue="25903" us="25902"/><bf gi="4432" ue="25905" us="25905"/><bf gi="4433" ue="25919" us="25908"/><bf gi="4445" ue="25923" us="25923"/><bf gi="4446" ue="25925" us="25925"/><bf gi="4447" ue="25929" us="25927"/><bf gi="4450" ue="25938" us="25933"/><bf gi="4456" ue="25945" us="25940"/><bf gi="4462" ue="25952" us="25949"/><bf gi="4466" ue="25955" us="25954"/><bf gi="4468" ue="25959" us="25958"/><bf gi="4470" ue="25964" us="25963"/><bf gi="4472" ue="25968" us="25968"/><bf gi="4473" ue="25970" us="25970"/><bf gi="4474" ue="25973" us="25972"/><bf gi="4476" ue="25976" us="25975"/><bf gi="4478" ue="25978" us="25978"/><bf gi="4479" ue="25981" us="25981"/><bf gi="4480" ue="25987" us="25985"/><bf gi="4483" ue="25989" us="25989"/><bf gi="4484" ue="25994" us="25991"/><bf gi="4488" ue="25996" us="25996"/><bf gi="4489" ue="25998" us="25998"/><bf gi="4490" ue="26002" us="26000"/><bf gi="4493" ue="26005" us="26005"/><bf gi="4494" ue="26!
 009" us="26007"/><bf gi="4497" ue="26013" us="26011"/><bf gi="4500" ue="26017" us="26015"/><bf gi="4503" ue="26023" us="26019"/><bf gi="4508" ue="26032" us="26027"/><bf gi="4514" ue="26036" us="26034"/><bf gi="4517" ue="26039" us="26039"/><bf gi="4518" ue="26041" us="26041"/><bf gi="4519" ue="26045" us="26044"/><bf gi="4521" ue="26047" us="26047"/><bf gi="4522" ue="26054" us="26049"/><bf gi="4528" ue="26057" us="26056"/><bf gi="4530" ue="26060" us="26059"/><bf gi="4532" ue="26064" us="26062"/><bf gi="4535" ue="26066" us="26066"/><bf gi="4536" ue="26068" us="26068"/><bf gi="4537" ue="26073" us="26070"/><bf gi="4541" ue="26075" us="26075"/><bf gi="4542" ue="26082" us="26079"/><bf gi="4546" ue="26089" us="26085"/><bf gi="4551" ue="26093" us="26092"/><bf gi="4553" ue="26098" us="26096"/><bf gi="4556" ue="26101" us="26100"/><bf gi="4558" ue="26107" us="26105"/><bf gi="4561" ue="26112" us="26110"/><bf gi="4564" ue="26116" us="26114"/><bf gi="4567" ue="26122" us="26118"/><bf gi="4!
 572" ue="26127" us="26124"/><bf gi="4576" ue="26134" us="26129"/><bf g
i="4582" ue="26161" us="26140"/><bf gi="4604" ue="26167" us="26163"/><bf gi="4609" ue="26169" us="26169"/><bf gi="4610" ue="26172" us="26172"/><bf gi="4611" ue="26182" us="26175"/><bf gi="4619" ue="26188" us="26185"/><bf gi="4623" ue="26191" us="26190"/><bf gi="4625" ue="26194" us="26193"/><bf gi="4627" ue="26201" us="26199"/><bf gi="4630" ue="26210" us="26203"/><bf gi="4638" ue="26220" us="26212"/><bf gi="4647" ue="26224" us="26222"/><bf gi="4650" ue="26236" us="26227"/><bf gi="4660" ue="26241" us="26238"/><bf gi="4664" ue="26244" us="26243"/><bf gi="4666" ue="26249" us="26247"/><bf gi="4669" ue="26254" us="26251"/><bf gi="4673" ue="26258" us="26256"/><bf gi="4676" ue="26269" us="26262"/><bf gi="4684" ue="26272" us="26271"/><bf gi="4686" ue="26274" us="26274"/><bf gi="4687" ue="26276" us="26276"/><bf gi="4688" ue="26278" us="26278"/><bf gi="4689" ue="26283" us="26283"/><bf gi="4690" ue="26286" us="26285"/><bf gi="4692" ue="26290" us="26289"/><bf gi="4694" ue="26293" us="262!
 92"/><bf gi="4696" ue="26297" us="26296"/><bf gi="4698" ue="26300" us="26299"/><bf gi="4700" ue="26308" us="26302"/><bf gi="4707" ue="26313" us="26311"/><bf gi="4710" ue="26316" us="26316"/><bf gi="4711" ue="26319" us="26318"/><bf gi="4713" ue="26324" us="26324"/><bf gi="4714" ue="26326" us="26326"/><bf gi="4715" ue="26333" us="26329"/><bf gi="4720" ue="26336" us="26335"/><bf gi="4722" ue="26342" us="26342"/><bf gi="4723" ue="26345" us="26344"/><bf gi="4725" ue="26348" us="26347"/><bf gi="4727" ue="26350" us="26350"/><bf gi="4728" ue="26352" us="26352"/><bf gi="4729" ue="26357" us="26354"/><bf gi="4733" ue="26368" us="26359"/><bf gi="4743" ue="26371" us="26371"/><bf gi="4744" ue="26373" us="26373"/><bf gi="4745" ue="26377" us="26375"/><bf gi="4748" ue="26379" us="26379"/><bf gi="4749" ue="26383" us="26381"/><bf gi="4752" ue="26391" us="26387"/><bf gi="4757" ue="26393" us="26393"/><bf gi="4758" ue="26400" us="26395"/><bf gi="4764" ue="26402" us="26402"/><bf gi="4765" ue="264!
 08" us="26406"/><bf gi="4768" ue="26414" us="26410"/><bf gi="4773" ue=
"26417" us="26417"/><bf gi="4774" ue="26420" us="26419"/><bf gi="4776" ue="26424" us="26422"/><bf gi="4779" ue="26426" us="26426"/><bf gi="4780" ue="26431" us="26429"/><bf gi="4783" ue="26433" us="26433"/><bf gi="4784" ue="26441" us="26437"/><bf gi="4789" ue="26444" us="26444"/><bf gi="4790" ue="26449" us="26446"/><bf gi="4794" ue="26454" us="26451"/><bf gi="4798" ue="26457" us="26457"/><bf gi="4799" ue="26470" us="26460"/><bf gi="4810" ue="26474" us="26474"/><bf gi="4811" ue="26487" us="26476"/><bf gi="4823" ue="26492" us="26491"/><bf gi="4825" ue="26495" us="26494"/><bf gi="4827" ue="26497" us="26497"/><bf gi="4828" ue="26501" us="26500"/><bf gi="4830" ue="26503" us="26503"/><bf gi="4831" ue="26505" us="26505"/><bf gi="4832" ue="26508" us="26507"/><bf gi="4834" ue="26513" us="26510"/><bf gi="4838" ue="26515" us="26515"/><bf gi="4839" ue="26525" us="26517"/><bf gi="4848" ue="26530" us="26528"/><bf gi="4851" ue="26534" us="26534"/><bf gi="4852" ue="26537" us="26537"/><bf gi=!
 "4853" ue="26553" us="26543"/><bf gi="4864" ue="26557" us="26555"/><bf gi="4867" ue="26566" us="26560"/><bf gi="4874" ue="26570" us="26568"/><bf gi="4877" ue="26580" us="26574"/><bf gi="4884" ue="26586" us="26583"/><bf gi="4888" ue="26590" us="26588"/><bf gi="4891" ue="26594" us="26593"/><bf gi="4893" ue="26596" us="26596"/><bf gi="4894" ue="26599" us="26598"/><bf gi="4896" ue="26601" us="26601"/><bf gi="4897" ue="26604" us="26604"/><bf gi="4898" ue="26615" us="26606"/><bf gi="4908" ue="26617" us="26617"/><bf gi="4909" ue="26619" us="26619"/><bf gi="4910" ue="26623" us="26622"/><bf gi="4912" ue="26628" us="26625"/><bf gi="4916" ue="26644" us="26643"/><bf gi="4918" ue="26647" us="26646"/><bf gi="4920" ue="26649" us="26649"/><bf gi="4921" ue="26655" us="26653"/><bf gi="4924" ue="26658" us="26657"/><bf gi="4926" ue="26669" us="26663"/><bf gi="4933" ue="26676" us="26671"/><bf gi="4939" ue="26681" us="26680"/><bf gi="4941" ue="26685" us="26683"/><bf gi="4944" ue="26694" us="2668!
 7"/><bf gi="4952" ue="26696" us="26696"/><bf gi="4953" ue="26698" us="
26698"/><bf gi="4954" ue="26702" us="26700"/><bf gi="4957" ue="26709" us="26704"/><bf gi="4963" ue="26713" us="26711"/><bf gi="4966" ue="26717" us="26715"/><bf gi="4969" ue="26719" us="26719"/><bf gi="4970" ue="26723" us="26723"/><bf gi="4971" ue="26727" us="26727"/><bf gi="4972" ue="26731" us="26731"/><bf gi="4973" ue="26738" us="26734"/><bf gi="4978" ue="26743" us="26740"/><bf gi="4982" ue="26748" us="26745"/><bf gi="4986" ue="26751" us="26750"/><bf gi="4988" ue="26758" us="26753"/><bf gi="4994" ue="26760" us="26760"/><bf gi="4995" ue="26765" us="26765"/><bf gi="4996" ue="26767" us="26767"/><bf gi="4997" ue="26772" us="26771"/><bf gi="4999" ue="26776" us="26774"/><bf gi="5002" ue="26781" us="26778"/><bf gi="5006" ue="26787" us="26783"/><bf gi="5011" ue="26794" us="26789"/><bf gi="5017" ue="26803" us="26797"/><bf gi="5024" ue="26806" us="26805"/><bf gi="5026" ue="26812" us="26809"/><bf gi="5030" ue="26822" us="26820"/><bf gi="5033" ue="26829" us="26824"/><bf gi="5039" ue="2!
 6842" us="26831"/><bf gi="5051" ue="26845" us="26844"/><bf gi="5053" ue="26849" us="26847"/><bf gi="5056" ue="26851" us="26851"/><bf gi="5057" ue="26853" us="26853"/><bf gi="5058" ue="26856" us="26855"/><bf gi="5060" ue="26866" us="26858"/><bf gi="5069" ue="26870" us="26869"/><bf gi="5071" ue="26877" us="26873"/><bf gi="5076" ue="26881" us="26880"/><bf gi="5078" ue="26886" us="26884"/><bf gi="5081" ue="26899" us="26888"/><bf gi="5093" ue="26903" us="26902"/><bf gi="5095" ue="26908" us="26905"/><bf gi="5099" ue="26915" us="26913"/><bf gi="5102" ue="26918" us="26917"/><bf gi="5104" ue="26920" us="26920"/><bf gi="5105" ue="26922" us="26922"/><bf gi="5106" ue="26929" us="26928"/><bf gi="5108" ue="26934" us="26931"/><bf gi="5112" ue="26937" us="26936"/><bf gi="5114" ue="26939" us="26939"/><bf gi="5115" ue="26941" us="26941"/><bf gi="5116" ue="26943" us="26943"/><bf gi="5117" ue="26946" us="26946"/><bf gi="5118" ue="26949" us="26949"/><bf gi="5119" ue="26954" us="26953"/><bf gi="!
 5121" ue="26958" us="26958"/><bf gi="5122" ue="26965" us="26963"/><bf 
gi="5125" ue="26967" us="26967"/><bf gi="5126" ue="26974" us="26969"/><bf gi="5132" ue="26982" us="26976"/><bf gi="5139" ue="26997" us="26984"/><bf gi="5153" ue="27010" us="26999"/><bf gi="5165" ue="27018" us="27018"/><bf gi="5166" ue="27022" us="27021"/><bf gi="5168" ue="27026" us="27025"/><bf gi="5170" ue="27030" us="27028"/><bf gi="5173" ue="27032" us="27032"/><bf gi="5174" ue="27036" us="27035"/><bf gi="5176" ue="27041" us="27040"/><bf gi="5178" ue="27048" us="27045"/><bf gi="5182" ue="27051" us="27051"/><bf gi="5183" ue="27055" us="27053"/><bf gi="5186" ue="27058" us="27057"/><bf gi="5188" ue="27060" us="27060"/><bf gi="5189" ue="27064" us="27063"/><bf gi="5191" ue="27068" us="27066"/><bf gi="5194" ue="27071" us="27070"/><bf gi="5196" ue="27073" us="27073"/><bf gi="5197" ue="27075" us="27075"/><bf gi="5198" ue="27077" us="27077"/><bf gi="5199" ue="27080" us="27079"/><bf gi="5201" ue="27086" us="27082"/><bf gi="5206" ue="27089" us="27088"/><bf gi="5208" ue="27091" us="27!
 091"/><bf gi="5209" ue="27097" us="27094"/><bf gi="5213" ue="27102" us="27101"/><bf gi="5215" ue="27106" us="27106"/><bf gi="5216" ue="27109" us="27109"/><bf gi="5217" ue="27112" us="27111"/><bf gi="5219" ue="27115" us="27115"/><bf gi="5220" ue="27119" us="27117"/><bf gi="5223" ue="27123" us="27121"/><bf gi="5226" ue="27125" us="27125"/><bf gi="5227" ue="27129" us="27129"/><bf gi="5228" ue="27131" us="27131"/><bf gi="5229" ue="27139" us="27133"/><bf gi="5236" ue="27141" us="27141"/><bf gi="5237" ue="27148" us="27146"/><bf gi="5240" ue="27151" us="27151"/><bf gi="5241" ue="27157" us="27153"/><bf gi="5246" ue="27159" us="27159"/><bf gi="5247" ue="27163" us="27161"/><bf gi="5250" ue="27172" us="27165"/><bf gi="5258" ue="27179" us="27176"/><bf gi="5262" ue="27182" us="27182"/><bf gi="5263" ue="27184" us="27184"/><bf gi="5264" ue="27186" us="27186"/><bf gi="5265" ue="27195" us="27188"/><bf gi="5273" ue="27199" us="27197"/><bf gi="5276" ue="27211" us="27204"/><bf gi="5284" ue="27!
 214" us="27214"/><bf gi="5285" ue="27218" us="27216"/><bf gi="5288" ue
="27222" us="27221"/><bf gi="5290" ue="27225" us="27224"/><bf gi="5292" ue="27227" us="27227"/><bf gi="5293" ue="27231" us="27231"/><bf gi="5294" ue="27234" us="27233"/><bf gi="5296" ue="27236" us="27236"/><bf gi="5297" ue="27239" us="27238"/><bf gi="5299" ue="27243" us="27242"/><bf gi="5301" ue="27251" us="27249"/><bf gi="5304" ue="27256" us="27256"/><bf gi="5305" ue="27265" us="27262"/><bf gi="5309" ue="27268" us="27267"/><bf gi="5311" ue="27271" us="27270"/><bf gi="5313" ue="27273" us="27273"/><bf gi="5314" ue="27275" us="27275"/><bf gi="5315" ue="27278" us="27277"/><bf gi="5317" ue="27281" us="27280"/><bf gi="5319" ue="27287" us="27287"/><bf gi="5320" ue="27296" us="27291"/><bf gi="5326" ue="27299" us="27298"/><bf gi="5328" ue="27301" us="27301"/><bf gi="5329" ue="27308" us="27306"/><bf gi="5332" ue="27313" us="27310"/><bf gi="5336" ue="27316" us="27315"/><bf gi="5338" ue="27320" us="27320"/><bf gi="5339" ue="27323" us="27323"/><bf gi="5340" ue="27327" us="27325"/><bf gi!
 ="5343" ue="27331" us="27329"/><bf gi="5346" ue="27334" us="27334"/><bf gi="5347" ue="27337" us="27336"/><bf gi="5349" ue="27340" us="27340"/><bf gi="5350" ue="27345" us="27344"/><bf gi="5352" ue="27350" us="27347"/><bf gi="5356" ue="27359" us="27354"/><bf gi="5362" ue="27362" us="27362"/><bf gi="5363" ue="27364" us="27364"/><bf gi="5364" ue="27368" us="27367"/><bf gi="5366" ue="27370" us="27370"/><bf gi="5367" ue="27372" us="27372"/><bf gi="5368" ue="27378" us="27376"/><bf gi="5371" ue="27389" us="27386"/><bf gi="5375" ue="27399" us="27394"/><bf gi="5381" ue="27402" us="27401"/><bf gi="5383" ue="27410" us="27407"/><bf gi="5387" ue="27415" us="27414"/><bf gi="5389" ue="27419" us="27419"/><bf gi="5390" ue="27425" us="27421"/><bf gi="5395" ue="27428" us="27427"/><bf gi="5397" ue="27432" us="27431"/><bf gi="5399" ue="27436" us="27435"/><bf gi="5401" ue="27439" us="27439"/><bf gi="5402" ue="27442" us="27442"/><bf gi="5403" ue="27451" us="27445"/><bf gi="5410" ue="27455" us="274!
 53"/><bf gi="5413" ue="27459" us="27459"/><bf gi="5414" ue="27463" us=
"27462"/><bf gi="5416" ue="27466" us="27465"/><bf gi="5418" ue="27470" us="27468"/><bf gi="5421" ue="27472" us="27472"/><bf gi="5422" ue="27476" us="27474"/><bf gi="5425" ue="27478" us="27478"/><bf gi="5426" ue="27481" us="27480"/><bf gi="5428" ue="27483" us="27483"/><bf gi="5429" ue="27485" us="27485"/><bf gi="5430" ue="27492" us="27487"/><bf gi="5436" ue="27495" us="27494"/><bf gi="5438" ue="27499" us="27497"/><bf gi="5441" ue="27504" us="27502"/><bf gi="5444" ue="27509" us="27507"/><bf gi="5447" ue="27513" us="27512"/><bf gi="5449" ue="27515" us="27515"/><bf gi="5450" ue="27520" us="27517"/><bf gi="5454" ue="27526" us="27522"/><bf gi="5459" ue="27531" us="27529"/><bf gi="5462" ue="27533" us="27533"/><bf gi="5463" ue="27544" us="27541"/><bf gi="5467" ue="27547" us="27547"/><bf gi="5468" ue="27552" us="27550"/><bf gi="5471" ue="27556" us="27554"/><bf gi="5474" ue="27573" us="27560"/><bf gi="5488" ue="27584" us="27575"/><bf gi="5498" ue="27590" us="27587"/><bf gi="5502" ue="!
 27593" us="27593"/><bf gi="5503" ue="27598" us="27595"/><bf gi="5507" ue="27604" us="27602"/><bf gi="5510" ue="27606" us="27606"/><bf gi="5511" ue="27608" us="27608"/><bf gi="5512" ue="27611" us="27610"/><bf gi="5514" ue="27615" us="27615"/><bf gi="5515" ue="27617" us="27617"/><bf gi="5516" ue="27619" us="27619"/><bf gi="5517" ue="27623" us="27622"/><bf gi="5519" ue="27628" us="27627"/><bf gi="5521" ue="27631" us="27630"/><bf gi="5523" ue="27633" us="27633"/><bf gi="5524" ue="27635" us="27635"/><bf gi="5525" ue="27639" us="27639"/><bf gi="5526" ue="27641" us="27641"/><bf gi="5527" ue="27647" us="27647"/><bf gi="5528" ue="27650" us="27650"/><bf gi="5529" ue="27653" us="27652"/><bf gi="5531" ue="27657" us="27656"/><bf gi="5533" ue="27668" us="27661"/><bf gi="5541" ue="27671" us="27671"/><bf gi="5542" ue="27673" us="27673"/><bf gi="5543" ue="27675" us="27675"/><bf gi="5544" ue="27679" us="27679"/><bf gi="5545" ue="27684" us="27683"/><bf gi="5547" ue="27688" us="27686"/><bf gi=!
 "5550" ue="27692" us="27692"/><bf gi="5551" ue="27694" us="27694"/><bf
 gi="5552" ue="27704" us="27699"/><bf gi="5558" ue="27707" us="27706"/><bf gi="5560" ue="27714" us="27710"/><bf gi="5565" ue="27723" us="27722"/><bf gi="5567" ue="27728" us="27725"/><bf gi="5571" ue="27730" us="27730"/><bf gi="5572" ue="27733" us="27732"/><bf gi="5574" ue="27735" us="27735"/><bf gi="5575" ue="27744" us="27737"/><bf gi="5583" ue="27746" us="27746"/><bf gi="5584" ue="27752" us="27751"/><bf gi="5586" ue="27755" us="27754"/><bf gi="5588" ue="27757" us="27757"/><bf gi="5589" ue="27760" us="27759"/><bf gi="5591" ue="27764" us="27762"/><bf gi="5594" ue="27766" us="27766"/><bf gi="5595" ue="27771" us="27768"/><bf gi="5599" ue="27774" us="27773"/><bf gi="5601" ue="27779" us="27777"/><bf gi="5604" ue="27785" us="27781"/><bf gi="5609" ue="27789" us="27788"/><bf gi="5611" ue="27792" us="27792"/><bf gi="5612" ue="27804" us="27794"/><bf gi="5623" ue="27807" us="27807"/><bf gi="5624" ue="27810" us="27809"/><bf gi="5626" ue="27819" us="27819"/><bf gi="5627" ue="27822" us="2!
 7822"/><bf gi="5628" ue="27828" us="27824"/><bf gi="5633" ue="27839" us="27832"/><bf gi="5641" ue="27842" us="27841"/><bf gi="5643" ue="27846" us="27844"/><bf gi="5646" ue="27850" us="27849"/><bf gi="5648" ue="27853" us="27852"/><bf gi="5650" ue="27863" us="27855"/><bf gi="5659" ue="27869" us="27865"/><bf gi="5664" ue="27875" us="27872"/><bf gi="5668" ue="27877" us="27877"/><bf gi="5669" ue="27884" us="27879"/><bf gi="5675" ue="27892" us="27886"/><bf gi="5682" ue="27908" us="27908"/><bf gi="5683" ue="27911" us="27911"/><bf gi="5684" ue="27916" us="27914"/><bf gi="5687" ue="27919" us="27918"/><bf gi="5689" ue="27923" us="27921"/><bf gi="5692" ue="27927" us="27927"/><bf gi="5693" ue="27931" us="27929"/><bf gi="5696" ue="27935" us="27934"/><bf gi="5698" ue="27947" us="27941"/><bf gi="5705" ue="27951" us="27950"/><bf gi="5707" ue="27955" us="27953"/><bf gi="5710" ue="27958" us="27957"/><bf gi="5712" ue="27961" us="27960"/><bf gi="5714" ue="27967" us="27963"/><bf gi="5719" ue="2!
 7969" us="27969"/><bf gi="5720" ue="27973" us="27972"/><bf gi="5722" u
e="27991" us="27991"/><bf gi="5723" ue="27994" us="27993"/><bf gi="5725" ue="27996" us="27996"/><bf gi="5726" ue="27999" us="27998"/><bf gi="5728" ue="28001" us="28001"/><bf gi="5729" ue="28007" us="28003"/><bf gi="5734" ue="28010" us="28009"/><bf gi="5736" ue="28012" us="28012"/><bf gi="5737" ue="28016" us="28014"/><bf gi="5740" ue="28020" us="28020"/><bf gi="5741" ue="28025" us="28023"/><bf gi="5744" ue="28028" us="28028"/><bf gi="5745" ue="28034" us="28034"/><bf gi="5746" ue="28037" us="28037"/><bf gi="5747" ue="28040" us="28039"/><bf gi="5749" ue="28044" us="28044"/><bf gi="5750" ue="28046" us="28046"/><bf gi="5751" ue="28057" us="28049"/><bf gi="5760" ue="28060" us="28059"/><bf gi="5762" ue="28074" us="28074"/><bf gi="5763" ue="28076" us="28076"/><bf gi="5764" ue="28079" us="28079"/><bf gi="5765" ue="28082" us="28082"/><bf gi="5766" ue="28085" us="28084"/><bf gi="5768" ue="28089" us="28087"/><bf gi="5771" ue="28093" us="28092"/><bf gi="5773" ue="28096" us="28095"/><bf g!
 i="5775" ue="28104" us="28100"/><bf gi="5780" ue="28108" us="28106"/><bf gi="5783" ue="28111" us="28110"/><bf gi="5785" ue="28114" us="28113"/><bf gi="5787" ue="28118" us="28117"/><bf gi="5789" ue="28121" us="28120"/><bf gi="5791" ue="28123" us="28123"/><bf gi="5792" ue="28130" us="28125"/><bf gi="5798" ue="28134" us="28132"/><bf gi="5801" ue="28140" us="28136"/><bf gi="5806" ue="28156" us="28142"/><bf gi="5821" ue="28160" us="28160"/><bf gi="5822" ue="28165" us="28164"/><bf gi="5824" ue="28171" us="28167"/><bf gi="5829" ue="28179" us="28179"/><bf gi="5830" ue="28181" us="28181"/><bf gi="5831" ue="28187" us="28185"/><bf gi="5834" ue="28199" us="28189"/><bf gi="5845" ue="28201" us="28201"/><bf gi="5846" ue="28207" us="28203"/><bf gi="5851" ue="28210" us="28210"/><bf gi="5852" ue="28214" us="28214"/><bf gi="5853" ue="28220" us="28216"/><bf gi="5858" ue="28222" us="28222"/><bf gi="5859" ue="28229" us="28227"/><bf gi="5862" ue="28235" us="28232"/><bf gi="5866" ue="28239" us="28!
 237"/><bf gi="5869" ue="28244" us="28241"/><bf gi="5873" ue="28248" us
="28246"/><bf gi="5876" ue="28255" us="28251"/><bf gi="5881" ue="28259" us="28258"/><bf gi="5883" ue="28264" us="28263"/><bf gi="5885" ue="28267" us="28267"/><bf gi="5886" ue="28271" us="28270"/><bf gi="5888" ue="28275" us="28274"/><bf gi="5890" ue="28278" us="28278"/><bf gi="5891" ue="28283" us="28283"/><bf gi="5892" ue="28288" us="28285"/><bf gi="5896" ue="28290" us="28290"/><bf gi="5897" ue="28301" us="28300"/><bf gi="5899" ue="28304" us="28303"/><bf gi="5901" ue="28307" us="28307"/><bf gi="5902" ue="28310" us="28310"/><bf gi="5903" ue="28313" us="28312"/><bf gi="5905" ue="28317" us="28316"/><bf gi="5907" ue="28320" us="28319"/><bf gi="5909" ue="28322" us="28322"/><bf gi="5910" ue="28325" us="28325"/><bf gi="5911" ue="28327" us="28327"/><bf gi="5912" ue="28330" us="28330"/><bf gi="5913" ue="28335" us="28333"/><bf gi="5916" ue="28339" us="28337"/><bf gi="5919" ue="28343" us="28342"/><bf gi="5921" ue="28347" us="28346"/><bf gi="5923" ue="28349" us="28349"/><bf gi="5924" ue=!
 "28357" us="28351"/><bf gi="5931" ue="28367" us="28359"/><bf gi="5940" ue="28369" us="28369"/><bf gi="5941" ue="28373" us="28371"/><bf gi="5944" ue="28382" us="28381"/><bf gi="5946" ue="28399" us="28395"/><bf gi="5951" ue="28402" us="28402"/><bf gi="5952" ue="28404" us="28404"/><bf gi="5953" ue="28409" us="28407"/><bf gi="5956" ue="28411" us="28411"/><bf gi="5957" ue="28415" us="28413"/><bf gi="5960" ue="28418" us="28417"/><bf gi="5962" ue="28420" us="28420"/><bf gi="5963" ue="28422" us="28422"/><bf gi="5964" ue="28426" us="28424"/><bf gi="5967" ue="28429" us="28428"/><bf gi="5969" ue="28431" us="28431"/><bf gi="5970" ue="28433" us="28433"/><bf gi="5971" ue="28438" us="28435"/><bf gi="5975" ue="28440" us="28440"/><bf gi="5976" ue="28443" us="28442"/><bf gi="5978" ue="28448" us="28448"/><bf gi="5979" ue="28451" us="28450"/><bf gi="5981" ue="28454" us="28454"/><bf gi="5982" ue="28461" us="28457"/><bf gi="5987" ue="28467" us="28463"/><bf gi="5992" ue="28470" us="28470"/><bf gi!
 ="5993" ue="28472" us="28472"/><bf gi="5994" ue="28476" us="28475"/><b
f gi="5996" ue="28479" us="28478"/><bf gi="5998" ue="28481" us="28481"/><bf gi="5999" ue="28485" us="28485"/><bf gi="6000" ue="28495" us="28495"/><bf gi="6001" ue="28500" us="28497"/><bf gi="6005" ue="28511" us="28503"/><bf gi="6014" ue="28514" us="28513"/><bf gi="6016" ue="28516" us="28516"/><bf gi="6017" ue="28518" us="28518"/><bf gi="6018" ue="28520" us="28520"/><bf gi="6019" ue="28528" us="28524"/><bf gi="6024" ue="28532" us="28532"/><bf gi="6025" ue="28536" us="28536"/><bf gi="6026" ue="28538" us="28538"/><bf gi="6027" ue="28542" us="28540"/><bf gi="6030" ue="28548" us="28544"/><bf gi="6035" ue="28552" us="28550"/><bf gi="6038" ue="28558" us="28555"/><bf gi="6042" ue="28564" us="28560"/><bf gi="6047" ue="28567" us="28566"/><bf gi="6049" ue="28570" us="28570"/><bf gi="6050" ue="28577" us="28575"/><bf gi="6053" ue="28584" us="28579"/><bf gi="6059" ue="28586" us="28586"/><bf gi="6060" ue="28593" us="28590"/><bf gi="6064" ue="28595" us="28595"/><bf gi="6065" ue="28598" us="!
 28597"/><bf gi="6067" ue="28601" us="28601"/><bf gi="6068" ue="28604" us="28604"/><bf gi="6069" ue="28611" us="28608"/><bf gi="6073" ue="28616" us="28613"/><bf gi="6077" ue="28618" us="28618"/><bf gi="6078" ue="28629" us="28628"/><bf gi="6080" ue="28632" us="28632"/><bf gi="6081" ue="28635" us="28634"/><bf gi="6083" ue="28641" us="28638"/><bf gi="6087" ue="28644" us="28644"/><bf gi="6088" ue="28649" us="28648"/><bf gi="6090" ue="28652" us="28651"/><bf gi="6092" ue="28657" us="28654"/><bf gi="6096" ue="28659" us="28659"/><bf gi="6097" ue="28662" us="28661"/><bf gi="6099" ue="28666" us="28665"/><bf gi="6101" ue="28670" us="28668"/><bf gi="6104" ue="28673" us="28672"/><bf gi="6106" ue="28679" us="28677"/><bf gi="6109" ue="28681" us="28681"/><bf gi="6110" ue="28683" us="28683"/><bf gi="6111" ue="28685" us="28685"/><bf gi="6112" ue="28687" us="28687"/><bf gi="6113" ue="28689" us="28689"/><bf gi="6114" ue="28693" us="28693"/><bf gi="6115" ue="28696" us="28695"/><bf gi="6117" ue="!
 28699" us="28698"/><bf gi="6119" ue="28704" us="28701"/><bf gi="6123" 
ue="28707" us="28707"/><bf gi="6124" ue="28712" us="28710"/><bf gi="6127" ue="28716" us="28716"/><bf gi="6128" ue="28720" us="28719"/><bf gi="6130" ue="28722" us="28722"/><bf gi="6131" ue="28724" us="28724"/><bf gi="6132" ue="28727" us="28727"/><bf gi="6133" ue="28729" us="28729"/><bf gi="6134" ue="28732" us="28732"/><bf gi="6135" ue="28734" us="28734"/><bf gi="6136" ue="28740" us="28739"/><bf gi="6138" ue="28748" us="28744"/><bf gi="6143" ue="28750" us="28750"/><bf gi="6144" ue="28753" us="28753"/><bf gi="6145" ue="28757" us="28756"/><bf gi="6147" ue="28760" us="28760"/><bf gi="6148" ue="28766" us="28765"/><bf gi="6150" ue="28773" us="28771"/><bf gi="6153" ue="28780" us="28779"/><bf gi="6155" ue="28784" us="28782"/><bf gi="6158" ue="28790" us="28789"/><bf gi="6160" ue="28792" us="28792"/><bf gi="6161" ue="28798" us="28796"/><bf gi="6164" ue="28801" us="28801"/><bf gi="6165" ue="28806" us="28805"/><bf gi="6167" ue="28810" us="28809"/><bf gi="6169" ue="28814" us="28814"/><bf !
 gi="6170" ue="28818" us="28818"/><bf gi="6171" ue="28825" us="28820"/><bf gi="6177" ue="28827" us="28827"/><bf gi="6178" ue="28836" us="28836"/><bf gi="6179" ue="28849" us="28843"/><bf gi="6186" ue="28852" us="28851"/><bf gi="6188" ue="28859" us="28855"/><bf gi="6193" ue="28872" us="28872"/><bf gi="6194" ue="28875" us="28874"/><bf gi="6196" ue="28879" us="28879"/><bf gi="6197" ue="28881" us="28881"/><bf gi="6198" ue="28886" us="28883"/><bf gi="6202" ue="28889" us="28888"/><bf gi="6204" ue="28893" us="28892"/><bf gi="6206" ue="28895" us="28895"/><bf gi="6207" ue="28900" us="28900"/><bf gi="6208" ue="28913" us="28913"/><bf gi="6209" ue="28922" us="28921"/><bf gi="6211" ue="28925" us="28925"/><bf gi="6212" ue="28935" us="28931"/><bf gi="6217" ue="28937" us="28937"/><bf gi="6218" ue="28940" us="28939"/><bf gi="6220" ue="28943" us="28943"/><bf gi="6221" ue="28948" us="28948"/><bf gi="6222" ue="28954" us="28953"/><bf gi="6224" ue="28956" us="28956"/><bf gi="6225" ue="28958" us="2!
 8958"/><bf gi="6226" ue="28961" us="28960"/><bf gi="6228" ue="28966" u
s="28966"/><bf gi="6229" ue="28971" us="28971"/><bf gi="6230" ue="28973" us="28973"/><bf gi="6231" ue="28977" us="28975"/><bf gi="6234" ue="28982" us="28982"/><bf gi="6235" ue="28984" us="28984"/><bf gi="6236" ue="28988" us="28988"/><bf gi="6237" ue="28993" us="28993"/><bf gi="6238" ue="28999" us="28997"/><bf gi="6241" ue="29004" us="29001"/><bf gi="6245" ue="29006" us="29006"/><bf gi="6246" ue="29008" us="29008"/><bf gi="6247" ue="29010" us="29010"/><bf gi="6248" ue="29015" us="29013"/><bf gi="6251" ue="29018" us="29017"/><bf gi="6253" ue="29020" us="29020"/><bf gi="6254" ue="29022" us="29022"/><bf gi="6255" ue="29024" us="29024"/><bf gi="6256" ue="29026" us="29026"/><bf gi="6257" ue="29033" us="29028"/><bf gi="6263" ue="29036" us="29036"/><bf gi="6264" ue="29038" us="29038"/><bf gi="6265" ue="29049" us="29049"/><bf gi="6266" ue="29053" us="29053"/><bf gi="6267" ue="29056" us="29056"/><bf gi="6268" ue="29061" us="29060"/><bf gi="6270" ue="29064" us="29063"/><bf gi="6272" ue!
 ="29066" us="29066"/><bf gi="6273" ue="29068" us="29068"/><bf gi="6274" ue="29071" us="29071"/><bf gi="6275" ue="29074" us="29074"/><bf gi="6276" ue="29077" us="29076"/><bf gi="6278" ue="29083" us="29081"/><bf gi="6281" ue="29088" us="29087"/><bf gi="6283" ue="29090" us="29090"/><bf gi="6284" ue="29096" us="29096"/><bf gi="6285" ue="29100" us="29100"/><bf gi="6286" ue="29107" us="29103"/><bf gi="6291" ue="29114" us="29113"/><bf gi="6293" ue="29121" us="29118"/><bf gi="6297" ue="29124" us="29123"/><bf gi="6299" ue="29129" us="29128"/><bf gi="6301" ue="29132" us="29131"/><bf gi="6303" ue="29134" us="29134"/><bf gi="6304" ue="29136" us="29136"/><bf gi="6305" ue="29143" us="29138"/><bf gi="6311" ue="29146" us="29145"/><bf gi="6313" ue="29148" us="29148"/><bf gi="6314" ue="29152" us="29151"/><bf gi="6316" ue="29159" us="29157"/><bf gi="6319" ue="29166" us="29164"/><bf gi="6322" ue="29173" us="29173"/><bf gi="6323" ue="29177" us="29176"/><bf gi="6325" ue="29180" us="29179"/><bf g!
 i="6327" ue="29184" us="29182"/><bf gi="6330" ue="29193" us="29190"/><
bf gi="6334" ue="29197" us="29197"/><bf gi="6335" ue="29200" us="29200"/><bf gi="6336" ue="29203" us="29203"/><bf gi="6337" ue="29207" us="29207"/><bf gi="6338" ue="29211" us="29210"/><bf gi="6340" ue="29213" us="29213"/><bf gi="6341" ue="29215" us="29215"/><bf gi="6342" ue="29220" us="29220"/><bf gi="6343" ue="29224" us="29224"/><bf gi="6344" ue="29229" us="29226"/><bf gi="6348" ue="29232" us="29231"/><bf gi="6350" ue="29234" us="29234"/><bf gi="6351" ue="29238" us="29236"/><bf gi="6354" ue="29251" us="29240"/><bf gi="6366" ue="29256" us="29253"/><bf gi="6370" ue="29260" us="29259"/><bf gi="6372" ue="29264" us="29262"/><bf gi="6375" ue="29267" us="29266"/><bf gi="6377" ue="29270" us="29269"/><bf gi="6379" ue="29283" us="29272"/><bf gi="6391" ue="29289" us="29287"/><bf gi="6394" ue="29291" us="29291"/><bf gi="6395" ue="29295" us="29294"/><bf gi="6397" ue="29298" us="29297"/><bf gi="6399" ue="29300" us="29300"/><bf gi="6400" ue="29305" us="29303"/><bf gi="6403" ue="29314" us=!
 "29307"/><bf gi="6411" ue="29316" us="29316"/><bf gi="6412" ue="29319" us="29319"/><bf gi="6413" ue="29321" us="29321"/><bf gi="6414" ue="29326" us="29325"/><bf gi="6416" ue="29331" us="29330"/><bf gi="6418" ue="29334" us="29334"/><bf gi="6419" ue="29339" us="29339"/><bf gi="6420" ue="29344" us="29344"/><bf gi="6421" ue="29346" us="29346"/><bf gi="6422" ue="29352" us="29351"/><bf gi="6424" ue="29359" us="29356"/><bf gi="6428" ue="29362" us="29361"/><bf gi="6430" ue="29364" us="29364"/><bf gi="6431" ue="29366" us="29366"/><bf gi="6432" ue="29369" us="29369"/><bf gi="6433" ue="29374" us="29374"/><bf gi="6434" ue="29380" us="29377"/><bf gi="6438" ue="29383" us="29382"/><bf gi="6440" ue="29385" us="29385"/><bf gi="6441" ue="29388" us="29388"/><bf gi="6442" ue="29390" us="29390"/><bf gi="6443" ue="29392" us="29392"/><bf gi="6444" ue="29394" us="29394"/><bf gi="6445" ue="29401" us="29397"/><bf gi="6450" ue="29403" us="29403"/><bf gi="6451" ue="29410" us="29407"/><bf gi="6455" ue=!
 "29413" us="29413"/><bf gi="6456" ue="29417" us="29417"/><bf gi="6457"
 ue="29421" us="29420"/><bf gi="6459" ue="29428" us="29427"/><bf gi="6461" ue="29438" us="29431"/><bf gi="6469" ue="29442" us="29442"/><bf gi="6470" ue="29445" us="29444"/><bf gi="6472" ue="29447" us="29447"/><bf gi="6473" ue="29451" us="29450"/><bf gi="6475" ue="29453" us="29453"/><bf gi="6476" ue="29459" us="29458"/><bf gi="6478" ue="29465" us="29462"/><bf gi="6482" ue="29471" us="29467"/><bf gi="6487" ue="29474" us="29474"/><bf gi="6488" ue="29477" us="29476"/><bf gi="6490" ue="29484" us="29479"/><bf gi="6496" ue="29487" us="29486"/><bf gi="6498" ue="29490" us="29489"/><bf gi="6500" ue="29495" us="29492"/><bf gi="6504" ue="29499" us="29498"/><bf gi="6506" ue="29503" us="29501"/><bf gi="6509" ue="29509" us="29507"/><bf gi="6512" ue="29520" us="29517"/><bf gi="6516" ue="29522" us="29522"/><bf gi="6517" ue="29528" us="29526"/><bf gi="6520" ue="29536" us="29533"/><bf gi="6524" ue="29539" us="29539"/><bf gi="6525" ue="29548" us="29542"/><bf gi="6532" ue="29554" us="29550"/><bf!
  gi="6537" ue="29557" us="29557"/><bf gi="6538" ue="29564" us="29559"/><bf gi="6544" ue="29569" us="29568"/><bf gi="6546" ue="29575" us="29571"/><bf gi="6551" ue="29577" us="29577"/><bf gi="6552" ue="29579" us="29579"/><bf gi="6553" ue="29582" us="29582"/><bf gi="6554" ue="29584" us="29584"/><bf gi="6555" ue="29587" us="29587"/><bf gi="6556" ue="29592" us="29589"/><bf gi="6560" ue="29596" us="29596"/><bf gi="6561" ue="29600" us="29598"/><bf gi="6564" ue="29602" us="29602"/><bf gi="6565" ue="29606" us="29605"/><bf gi="6567" ue="29611" us="29609"/><bf gi="6570" ue="29613" us="29613"/><bf gi="6571" ue="29619" us="29618"/><bf gi="6573" ue="29621" us="29621"/><bf gi="6574" ue="29623" us="29623"/><bf gi="6575" ue="29625" us="29625"/><bf gi="6576" ue="29629" us="29627"/><bf gi="6579" ue="29632" us="29631"/><bf gi="6581" ue="29634" us="29634"/><bf gi="6582" ue="29638" us="29637"/><bf gi="6584" ue="29647" us="29640"/><bf gi="6592" ue="29651" us="29650"/><bf gi="6594" ue="29654" us="!
 29654"/><bf gi="6595" ue="29657" us="29657"/><bf gi="6596" ue="29662" 
us="29661"/><bf gi="6598" ue="29665" us="29664"/><bf gi="6600" ue="29667" us="29667"/><bf gi="6601" ue="29671" us="29669"/><bf gi="6604" ue="29674" us="29673"/><bf gi="6606" ue="29678" us="29677"/><bf gi="6608" ue="29681" us="29681"/><bf gi="6609" ue="29685" us="29684"/><bf gi="6611" ue="29691" us="29687"/><bf gi="6616" ue="29697" us="29693"/><bf gi="6621" ue="29703" us="29699"/><bf gi="6626" ue="29706" us="29705"/><bf gi="6628" ue="29713" us="29713"/><bf gi="6629" ue="29723" us="29722"/><bf gi="6631" ue="29730" us="29730"/><bf gi="6632" ue="29734" us="29732"/><bf gi="6635" ue="29750" us="29736"/><bf gi="6650" ue="29754" us="29753"/><bf gi="6652" ue="29761" us="29759"/><bf gi="6655" ue="29764" us="29763"/><bf gi="6657" ue="29767" us="29766"/><bf gi="6659" ue="29771" us="29771"/><bf gi="6660" ue="29773" us="29773"/><bf gi="6661" ue="29778" us="29777"/><bf gi="6663" ue="29781" us="29781"/><bf gi="6664" ue="29783" us="29783"/><bf gi="6665" ue="29792" us="29785"/><bf gi="6673" u!
 e="29796" us="29794"/><bf gi="6676" ue="29803" us="29798"/><bf gi="6682" ue="29811" us="29805"/><bf gi="6689" ue="29814" us="29814"/><bf gi="6690" ue="29822" us="29822"/><bf gi="6691" ue="29825" us="29824"/><bf gi="6693" ue="29827" us="29827"/><bf gi="6694" ue="29831" us="29829"/><bf gi="6697" ue="29833" us="29833"/><bf gi="6698" ue="29835" us="29835"/><bf gi="6699" ue="29842" us="29839"/><bf gi="6703" ue="29850" us="29848"/><bf gi="6706" ue="29852" us="29852"/><bf gi="6707" ue="29859" us="29854"/><bf gi="6713" ue="29867" us="29862"/><bf gi="6719" ue="29874" us="29870"/><bf gi="6724" ue="29877" us="29877"/><bf gi="6725" ue="29881" us="29881"/><bf gi="6726" ue="29883" us="29883"/><bf gi="6727" ue="29885" us="29885"/><bf gi="6728" ue="29887" us="29887"/><bf gi="6729" ue="29898" us="29896"/><bf gi="6732" ue="29900" us="29900"/><bf gi="6733" ue="29904" us="29903"/><bf gi="6735" ue="29908" us="29907"/><bf gi="6737" ue="29912" us="29912"/><bf gi="6738" ue="29916" us="29914"/><bf !
 gi="6741" ue="29920" us="29918"/><bf gi="6744" ue="29924" us="29922"/>
<bf gi="6747" ue="29931" us="29926"/><bf gi="6753" ue="29938" us="29934"/><bf gi="6758" ue="29940" us="29940"/><bf gi="6759" ue="29944" us="29942"/><bf gi="6762" ue="29948" us="29946"/><bf gi="6765" ue="29951" us="29951"/><bf gi="6766" ue="29953" us="29953"/><bf gi="6767" ue="29958" us="29955"/><bf gi="6771" ue="29966" us="29964"/><bf gi="6774" ue="29971" us="29969"/><bf gi="6777" ue="29976" us="29973"/><bf gi="6781" ue="29978" us="29978"/><bf gi="6782" ue="29980" us="29980"/><bf gi="6783" ue="29985" us="29982"/><bf gi="6787" ue="29996" us="29987"/><bf gi="6797" ue="30003" us="29999"/><bf gi="6802" ue="30016" us="30006"/><bf gi="6813" ue="30020" us="30019"/><bf gi="6815" ue="30034" us="30022"/><bf gi="6828" ue="30036" us="30036"/><bf gi="6829" ue="30039" us="30039"/><bf gi="6830" ue="30050" us="30041"/><bf gi="6840" ue="30055" us="30052"/><bf gi="6844" ue="30059" us="30057"/><bf gi="6847" ue="30061" us="30061"/><bf gi="6848" ue="30065" us="30063"/><bf gi="6851" ue="30068" us!
 ="30067"/><bf gi="6853" ue="30079" us="30070"/><bf gi="6863" ue="30082" us="30081"/><bf gi="6865" ue="30087" us="30085"/><bf gi="6868" ue="30091" us="30089"/><bf gi="6871" ue="30101" us="30094"/><bf gi="6879" ue="30106" us="30105"/><bf gi="6881" ue="30109" us="30108"/><bf gi="6883" ue="30117" us="30114"/><bf gi="6887" ue="30123" us="30123"/><bf gi="6888" ue="30133" us="30129"/><bf gi="6893" ue="30138" us="30136"/><bf gi="6896" ue="30151" us="30140"/><bf gi="6908" ue="30154" us="30154"/><bf gi="6909" ue="30159" us="30156"/><bf gi="6913" ue="30162" us="30162"/><bf gi="6914" ue="30165" us="30164"/><bf gi="6916" ue="30169" us="30167"/><bf gi="6919" ue="30172" us="30171"/><bf gi="6921" ue="30180" us="30174"/><bf gi="6928" ue="30183" us="30183"/><bf gi="6929" ue="30185" us="30185"/><bf gi="6930" ue="30188" us="30188"/><bf gi="6931" ue="30196" us="30190"/><bf gi="6938" ue="30202" us="30201"/><bf gi="6940" ue="30204" us="30204"/><bf gi="6941" ue="30212" us="30206"/><bf gi="6948" ue!
 ="30221" us="30215"/><bf gi="6955" ue="30223" us="30223"/><bf gi="6956
" ue="30227" us="30226"/><bf gi="6958" ue="30230" us="30229"/><bf gi="6960" ue="30233" us="30233"/><bf gi="6961" ue="30247" us="30235"/><bf gi="6974" ue="30249" us="30249"/><bf gi="6975" ue="30253" us="30253"/><bf gi="6976" ue="30256" us="30256"/><bf gi="6977" ue="30261" us="30258"/><bf gi="6981" ue="30268" us="30264"/><bf gi="6986" ue="30284" us="30272"/><bf gi="6999" ue="30290" us="30290"/><bf gi="7000" ue="30294" us="30293"/><bf gi="7002" ue="30297" us="30296"/><bf gi="7004" ue="30300" us="30300"/><bf gi="7005" ue="30303" us="30303"/><bf gi="7006" ue="30306" us="30305"/><bf gi="7008" ue="30309" us="30308"/><bf gi="7010" ue="30314" us="30311"/><bf gi="7014" ue="30322" us="30316"/><bf gi="7021" ue="30324" us="30324"/><bf gi="7022" ue="30326" us="30326"/><bf gi="7023" ue="30328" us="30328"/><bf gi="7024" ue="30334" us="30330"/><bf gi="7029" ue="30344" us="30336"/><bf gi="7038" ue="30350" us="30347"/><bf gi="7042" ue="30352" us="30352"/><bf gi="7043" ue="30355" us="30355"/><b!
 f gi="7044" ue="30358" us="30357"/><bf gi="7046" ue="30368" us="30361"/><bf gi="7054" ue="30376" us="30370"/><bf gi="7061" ue="30378" us="30378"/><bf gi="7062" ue="30382" us="30381"/><bf gi="7064" ue="30384" us="30384"/><bf gi="7065" ue="30388" us="30388"/><bf gi="7066" ue="30394" us="30391"/><bf gi="7070" ue="30397" us="30397"/><bf gi="7071" ue="30399" us="30399"/><bf gi="7072" ue="30403" us="30401"/><bf gi="7075" ue="30406" us="30405"/><bf gi="7077" ue="30414" us="30408"/><bf gi="7084" ue="30418" us="30418"/><bf gi="7085" ue="30420" us="30420"/><bf gi="7086" ue="30423" us="30422"/><bf gi="7088" ue="30425" us="30425"/><bf gi="7089" ue="30428" us="30427"/><bf gi="7091" ue="30433" us="30430"/><bf gi="7095" ue="30440" us="30435"/><bf gi="7101" ue="30442" us="30442"/><bf gi="7102" ue="30444" us="30444"/><bf gi="7103" ue="30446" us="30446"/><bf gi="7104" ue="30450" us="30448"/><bf gi="7107" ue="30452" us="30452"/><bf gi="7108" ue="30454" us="30454"/><bf gi="7109" ue="30457" us=!
 "30456"/><bf gi="7111" ue="30460" us="30459"/><bf gi="7113" ue="30462"
 us="30462"/><bf gi="7114" ue="30465" us="30464"/><bf gi="7116" ue="30468" us="30468"/><bf gi="7117" ue="30476" us="30470"/><bf gi="7124" ue="30478" us="30478"/><bf gi="7125" ue="30482" us="30482"/><bf gi="7126" ue="30485" us="30484"/><bf gi="7128" ue="30487" us="30487"/><bf gi="7129" ue="30492" us="30489"/><bf gi="7133" ue="30496" us="30494"/><bf gi="7136" ue="30498" us="30498"/><bf gi="7137" ue="30502" us="30500"/><bf gi="7140" ue="30505" us="30504"/><bf gi="7142" ue="30511" us="30509"/><bf gi="7145" ue="30522" us="30516"/><bf gi="7152" ue="30526" us="30524"/><bf gi="7155" ue="30528" us="30528"/><bf gi="7156" ue="30530" us="30530"/><bf gi="7157" ue="30535" us="30533"/><bf gi="7160" ue="30538" us="30538"/><bf gi="7161" ue="30543" us="30541"/><bf gi="7164" ue="30546" us="30546"/><bf gi="7165" ue="30551" us="30550"/><bf gi="7167" ue="30556" us="30554"/><bf gi="7170" ue="30568" us="30558"/><bf gi="7181" ue="30572" us="30570"/><bf gi="7184" ue="30576" us="30576"/><bf gi="7185" !
 ue="30580" us="30578"/><bf gi="7188" ue="30586" us="30585"/><bf gi="7190" ue="30592" us="30589"/><bf gi="7194" ue="30596" us="30596"/><bf gi="7195" ue="30606" us="30603"/><bf gi="7199" ue="30609" us="30609"/><bf gi="7200" ue="30614" us="30612"/><bf gi="7203" ue="30618" us="30618"/><bf gi="7204" ue="30624" us="30622"/><bf gi="7207" ue="30626" us="30626"/><bf gi="7208" ue="30629" us="30629"/><bf gi="7209" ue="30631" us="30631"/><bf gi="7210" ue="30634" us="30634"/><bf gi="7211" ue="30641" us="30636"/><bf gi="7217" ue="30643" us="30643"/><bf gi="7218" ue="30646" us="30645"/><bf gi="7220" ue="30649" us="30649"/><bf gi="7221" ue="30655" us="30651"/><bf gi="7226" ue="30659" us="30659"/><bf gi="7227" ue="30663" us="30663"/><bf gi="7228" ue="30665" us="30665"/><bf gi="7229" ue="30669" us="30669"/><bf gi="7230" ue="30674" us="30673"/><bf gi="7232" ue="30677" us="30677"/><bf gi="7233" ue="30679" us="30679"/><bf gi="7234" ue="30684" us="30681"/><bf gi="7238" ue="30688" us="30686"/><bf!
  gi="7241" ue="30695" us="30690"/><bf gi="7247" ue="30698" us="30697"/
><bf gi="7249" ue="30705" us="30700"/><bf gi="7255" ue="30708" us="30707"/><bf gi="7257" ue="30712" us="30712"/><bf gi="7258" ue="30716" us="30715"/><bf gi="7260" ue="30722" us="30722"/><bf gi="7261" ue="30726" us="30725"/><bf gi="7263" ue="30729" us="30729"/><bf gi="7264" ue="30734" us="30732"/><bf gi="7267" ue="30738" us="30737"/><bf gi="7269" ue="30741" us="30740"/><bf gi="7271" ue="30749" us="30749"/><bf gi="7272" ue="30755" us="30752"/><bf gi="7276" ue="30759" us="30757"/><bf gi="7279" ue="30766" us="30765"/><bf gi="7281" ue="30768" us="30768"/><bf gi="7282" ue="30770" us="30770"/><bf gi="7283" ue="30773" us="30772"/><bf gi="7285" ue="30775" us="30775"/><bf gi="7286" ue="30778" us="30778"/><bf gi="7287" ue="30783" us="30783"/><bf gi="7288" ue="30789" us="30787"/><bf gi="7291" ue="30792" us="30791"/><bf gi="7293" ue="30796" us="30796"/><bf gi="7294" ue="30798" us="30798"/><bf gi="7295" ue="30802" us="30802"/><bf gi="7296" ue="30814" us="30812"/><bf gi="7299" ue="30817" u!
 s="30816"/><bf gi="7301" ue="30820" us="30819"/><bf gi="7303" ue="30824" us="30824"/><bf gi="7304" ue="30828" us="30826"/><bf gi="7307" ue="30831" us="30830"/><bf gi="7309" ue="30834" us="30834"/><bf gi="7310" ue="30836" us="30836"/><bf gi="7311" ue="30842" us="30842"/><bf gi="7312" ue="30844" us="30844"/><bf gi="7313" ue="30846" us="30846"/><bf gi="7314" ue="30849" us="30849"/><bf gi="7315" ue="30855" us="30854"/><bf gi="7317" ue="30858" us="30858"/><bf gi="7318" ue="30863" us="30860"/><bf gi="7322" ue="30865" us="30865"/><bf gi="7323" ue="30869" us="30867"/><bf gi="7326" ue="30872" us="30871"/><bf gi="7328" ue="30874" us="30874"/><bf gi="7329" ue="30879" us="30877"/><bf gi="7332" ue="30881" us="30881"/><bf gi="7333" ue="30884" us="30883"/><bf gi="7335" ue="30890" us="30887"/><bf gi="7339" ue="30893" us="30892"/><bf gi="7341" ue="30899" us="30895"/><bf gi="7346" ue="30901" us="30901"/><bf gi="7347" ue="30911" us="30906"/><bf gi="7353" ue="30913" us="30913"/><bf gi="7354" u!
 e="30924" us="30917"/><bf gi="7362" ue="30926" us="30926"/><bf gi="736
3" ue="30934" us="30928"/><bf gi="7370" ue="30939" us="30938"/><bf gi="7372" ue="30945" us="30943"/><bf gi="7375" ue="30948" us="30948"/><bf gi="7376" ue="30952" us="30950"/><bf gi="7379" ue="30954" us="30954"/><bf gi="7380" ue="30956" us="30956"/><bf gi="7381" ue="30959" us="30959"/><bf gi="7382" ue="30964" us="30962"/><bf gi="7385" ue="30967" us="30966"/><bf gi="7387" ue="30971" us="30970"/><bf gi="7389" ue="30973" us="30973"/><bf gi="7390" ue="30977" us="30975"/><bf gi="7393" ue="30983" us="30982"/><bf gi="7395" ue="30988" us="30988"/><bf gi="7396" ue="30990" us="30990"/><bf gi="7397" ue="30994" us="30992"/><bf gi="7400" ue="31002" us="31001"/><bf gi="7402" ue="31004" us="31004"/><bf gi="7403" ue="31008" us="31006"/><bf gi="7406" ue="31015" us="31013"/><bf gi="7409" ue="31021" us="31017"/><bf gi="7414" ue="31025" us="31024"/><bf gi="7416" ue="31029" us="31028"/><bf gi="7418" ue="31041" us="31034"/><bf gi="7426" ue="31051" us="31044"/><bf gi="7434" ue="31057" us="31055"/><!
 bf gi="7437" ue="31064" us="31059"/><bf gi="7443" ue="31072" us="31066"/><bf gi="7450" ue="31074" us="31074"/><bf gi="7451" ue="31077" us="31077"/><bf gi="7452" ue="31081" us="31079"/><bf gi="7455" ue="31083" us="31083"/><bf gi="7456" ue="31085" us="31085"/><bf gi="7457" ue="31090" us="31090"/><bf gi="7458" ue="31095" us="31095"/><bf gi="7459" ue="31100" us="31097"/><bf gi="7463" ue="31105" us="31102"/><bf gi="7467" ue="31109" us="31108"/><bf gi="7469" ue="31119" us="31114"/><bf gi="7475" ue="31121" us="31121"/><bf gi="7476" ue="31126" us="31123"/><bf gi="7480" ue="31128" us="31128"/><bf gi="7481" ue="31133" us="31131"/><bf gi="7484" ue="31137" us="31137"/><bf gi="7485" ue="31147" us="31142"/><bf gi="7491" ue="31153" us="31150"/><bf gi="7495" ue="31156" us="31155"/><bf gi="7497" ue="31163" us="31160"/><bf gi="7501" ue="31170" us="31165"/><bf gi="7507" ue="31172" us="31172"/><bf gi="7508" ue="31179" us="31175"/><bf gi="7513" ue="31183" us="31183"/><bf gi="7514" ue="31186" us!
 ="31185"/><bf gi="7516" ue="31190" us="31188"/><bf gi="7519" ue="31192
" us="31192"/><bf gi="7520" ue="31194" us="31194"/><bf gi="7521" ue="31207" us="31197"/><bf gi="7532" ue="31213" us="31209"/><bf gi="7537" ue="31217" us="31216"/><bf gi="7539" ue="31224" us="31224"/><bf gi="7540" ue="31228" us="31227"/><bf gi="7542" ue="31232" us="31232"/><bf gi="7543" ue="31235" us="31234"/><bf gi="7545" ue="31246" us="31239"/><bf gi="7553" ue="31249" us="31249"/><bf gi="7554" ue="31253" us="31252"/><bf gi="7556" ue="31260" us="31255"/><bf gi="7562" ue="31265" us="31262"/><bf gi="7566" ue="31271" us="31271"/><bf gi="7567" ue="31275" us="31275"/><bf gi="7568" ue="31282" us="31277"/><bf gi="7574" ue="31285" us="31284"/><bf gi="7576" ue="31296" us="31287"/><bf gi="7586" ue="31305" us="31298"/><bf gi="7594" ue="31312" us="31308"/><bf gi="7599" ue="31319" us="31317"/><bf gi="7602" ue="31321" us="31321"/><bf gi="7603" ue="31325" us="31324"/><bf gi="7605" ue="31331" us="31327"/><bf gi="7610" ue="31333" us="31333"/><bf gi="7611" ue="31335" us="31335"/><bf gi="7612"!
  ue="31339" us="31337"/><bf gi="7615" ue="31341" us="31341"/><bf gi="7616" ue="31344" us="31344"/><bf gi="7617" ue="31350" us="31348"/><bf gi="7620" ue="31354" us="31352"/><bf gi="7623" ue="31366" us="31357"/><bf gi="7633" ue="31368" us="31368"/><bf gi="7634" ue="31371" us="31370"/><bf gi="7636" ue="31384" us="31376"/><bf gi="7645" ue="31392" us="31390"/><bf gi="7648" ue="31395" us="31395"/><bf gi="7649" ue="31402" us="31401"/><bf gi="7651" ue="31404" us="31404"/><bf gi="7652" ue="31408" us="31406"/><bf gi="7655" ue="31411" us="31411"/><bf gi="7656" ue="31414" us="31413"/><bf gi="7658" ue="31420" us="31417"/><bf gi="7662" ue="31423" us="31423"/><bf gi="7663" ue="31439" us="31427"/><bf gi="7676" ue="31443" us="31441"/><bf gi="7679" ue="31445" us="31445"/><bf gi="7680" ue="31453" us="31449"/><bf gi="7685" ue="31459" us="31455"/><bf gi="7690" ue="31469" us="31461"/><bf gi="7699" ue="31473" us="31471"/><bf gi="7702" ue="31476" us="31476"/><bf gi="7703" ue="31478" us="31478"/><b!
 f gi="7704" ue="31483" us="31480"/><bf gi="7708" ue="31487" us="31485"
/><bf gi="7711" ue="31490" us="31490"/><bf gi="7712" ue="31492" us="31492"/><bf gi="7713" ue="31496" us="31494"/><bf gi="7716" ue="31499" us="31498"/><bf gi="7718" ue="31503" us="31503"/><bf gi="7719" ue="31505" us="31505"/><bf gi="7720" ue="31508" us="31508"/><bf gi="7721" ue="31513" us="31512"/><bf gi="7723" ue="31515" us="31515"/><bf gi="7724" ue="31520" us="31518"/><bf gi="7727" ue="31523" us="31523"/><bf gi="7728" ue="31537" us="31525"/><bf gi="7741" ue="31542" us="31539"/><bf gi="7745" ue="31545" us="31545"/><bf gi="7746" ue="31549" us="31549"/><bf gi="7747" ue="31553" us="31551"/><bf gi="7750" ue="31561" us="31557"/><bf gi="7755" ue="31570" us="31563"/><bf gi="7763" ue="31574" us="31572"/><bf gi="7766" ue="31581" us="31581"/><bf gi="7767" ue="31584" us="31584"/><bf gi="7768" ue="31591" us="31588"/><bf gi="7772" ue="31594" us="31593"/><bf gi="7774" ue="31605" us="31596"/><bf gi="7784" ue="31607" us="31607"/><bf gi="7785" ue="31610" us="31610"/><bf gi="7786" ue="31620" !
 us="31620"/><bf gi="7787" ue="31623" us="31622"/><bf gi="7789" ue="31625" us="31625"/><bf gi="7790" ue="31627" us="31627"/><bf gi="7791" ue="31634" us="31629"/><bf gi="7797" ue="31649" us="31636"/><bf gi="7811" ue="31653" us="31653"/><bf gi="7812" ue="31658" us="31658"/><bf gi="7813" ue="31661" us="31660"/><bf gi="7815" ue="31666" us="31663"/><bf gi="7819" ue="31670" us="31668"/><bf gi="7822" ue="31672" us="31672"/><bf gi="7823" ue="31677" us="31674"/><bf gi="7827" ue="31682" us="31680"/><bf gi="7830" ue="31692" us="31684"/><bf gi="7839" ue="31695" us="31695"/><bf gi="7840" ue="31700" us="31700"/><bf gi="7841" ue="31703" us="31702"/><bf gi="7843" ue="31707" us="31705"/><bf gi="7846" ue="31709" us="31709"/><bf gi="7847" ue="31712" us="31712"/><bf gi="7848" ue="31718" us="31716"/><bf gi="7851" ue="31722" us="31720"/><bf gi="7854" ue="31725" us="31725"/><bf gi="7855" ue="31738" us="31730"/><bf gi="7864" ue="31740" us="31740"/><bf gi="7865" ue="31742" us="31742"/><bf gi="7866" !
 ue="31748" us="31744"/><bf gi="7871" ue="31751" us="31750"/><bf gi="78
73" ue="31753" us="31753"/><bf gi="7874" ue="31759" us="31755"/><bf gi="7879" ue="31764" us="31761"/><bf gi="7883" ue="31767" us="31767"/><bf gi="7884" ue="31769" us="31769"/><bf gi="7885" ue="31771" us="31771"/><bf gi="7886" ue="31777" us="31775"/><bf gi="7889" ue="31779" us="31779"/><bf gi="7890" ue="31784" us="31781"/><bf gi="7894" ue="31788" us="31786"/><bf gi="7897" ue="31793" us="31793"/><bf gi="7898" ue="31796" us="31795"/><bf gi="7900" ue="31802" us="31798"/><bf gi="7905" ue="31808" us="31805"/><bf gi="7909" ue="31811" us="31811"/><bf gi="7910" ue="31814" us="31814"/><bf gi="7911" ue="31818" us="31818"/><bf gi="7912" ue="31821" us="31820"/><bf gi="7914" ue="31830" us="31823"/><bf gi="7922" ue="31841" us="31832"/><bf gi="7932" ue="31845" us="31843"/><bf gi="7935" ue="31847" us="31847"/><bf gi="7936" ue="31849" us="31849"/><bf gi="7937" ue="31854" us="31852"/><bf gi="7940" ue="31856" us="31856"/><bf gi="7941" ue="31859" us="31858"/><bf gi="7943" ue="31861" us="31861"/>!
 <bf gi="7944" ue="31865" us="31865"/><bf gi="7945" ue="31870" us="31868"/><bf gi="7948" ue="31875" us="31873"/><bf gi="7951" ue="31879" us="31878"/><bf gi="7953" ue="31881" us="31881"/><bf gi="7954" ue="31883" us="31883"/><bf gi="7955" ue="31885" us="31885"/><bf gi="7956" ue="31888" us="31887"/><bf gi="7958" ue="31890" us="31890"/><bf gi="7959" ue="31893" us="31892"/><bf gi="7961" ue="31896" us="31895"/><bf gi="7963" ue="31899" us="31899"/><bf gi="7964" ue="31906" us="31902"/><bf gi="7969" ue="31912" us="31908"/><bf gi="7974" ue="31915" us="31915"/><bf gi="7975" ue="31918" us="31917"/><bf gi="7977" ue="31923" us="31920"/><bf gi="7981" ue="31927" us="31926"/><bf gi="7983" ue="31936" us="31929"/><bf gi="7991" ue="31938" us="31938"/><bf gi="7992" ue="31941" us="31940"/><bf gi="7994" ue="31946" us="31943"/><bf gi="7998" ue="31951" us="31949"/><bf gi="8001" ue="31962" us="31954"/><bf gi="8010" ue="31968" us="31964"/><bf gi="8015" ue="31970" us="31970"/><bf gi="8016" ue="31975" u!
 s="31974"/><bf gi="8018" ue="31977" us="31977"/><bf gi="8019" ue="3197
9" us="31979"/><bf gi="8020" ue="31983" us="31983"/><bf gi="8021" ue="31986" us="31986"/><bf gi="8022" ue="31990" us="31988"/><bf gi="8025" ue="31992" us="31992"/><bf gi="8026" ue="31995" us="31994"/><bf gi="8028" ue="31998" us="31998"/><bf gi="8029" ue="32000" us="32000"/><bf gi="8030" ue="32011" us="32002"/><bf gi="8040" ue="32013" us="32013"/><bf gi="8041" ue="32030" us="32015"/><bf gi="8057" ue="32035" us="32032"/><bf gi="8061" ue="32038" us="32038"/><bf gi="8062" ue="32051" us="32042"/><bf gi="8072" ue="32053" us="32053"/><bf gi="8073" ue="32058" us="32057"/><bf gi="8075" ue="32072" us="32060"/><bf gi="8088" ue="32081" us="32075"/><bf gi="8095" ue="32083" us="32083"/><bf gi="8096" ue="32087" us="32086"/><bf gi="8098" ue="32094" us="32089"/><bf gi="8104" ue="32099" us="32097"/><bf gi="8107" ue="32104" us="32101"/><bf gi="8111" ue="32106" us="32106"/><bf gi="8112" ue="32110" us="32110"/><bf gi="8113" ue="32115" us="32112"/><bf gi="8117" ue="32118" us="32117"/><bf gi="8119!
 " ue="32123" us="32120"/><bf gi="8123" ue="32125" us="32125"/><bf gi="8124" ue="32127" us="32127"/><bf gi="8125" ue="32131" us="32129"/><bf gi="8128" ue="32134" us="32133"/><bf gi="8130" ue="32137" us="32136"/><bf gi="8132" ue="32141" us="32139"/><bf gi="8135" ue="32143" us="32143"/><bf gi="8136" ue="32145" us="32145"/><bf gi="8137" ue="32147" us="32147"/><bf gi="8138" ue="32151" us="32150"/><bf gi="8140" ue="32160" us="32153"/><bf gi="8148" ue="32163" us="32162"/><bf gi="8150" ue="32167" us="32166"/><bf gi="8152" ue="32187" us="32170"/><bf gi="8170" ue="32191" us="32189"/><bf gi="8173" ue="32199" us="32194"/><bf gi="8179" ue="32207" us="32202"/><bf gi="8185" ue="32210" us="32209"/><bf gi="8187" ue="32218" us="32213"/><bf gi="8193" ue="32222" us="32220"/><bf gi="8196" ue="32226" us="32224"/><bf gi="8199" ue="32230" us="32228"/><bf gi="8202" ue="32237" us="32232"/><bf gi="8208" ue="32239" us="32239"/><bf gi="8209" ue="32242" us="32241"/><bf gi="8211" ue="32246" us="32244"/><!
 bf gi="8214" ue="32251" us="32249"/><bf gi="8217" ue="32257" us="32256
"/><bf gi="8219" ue="32261" us="32260"/><bf gi="8221" ue="32267" us="32264"/><bf gi="8225" ue="32274" us="32272"/><bf gi="8228" ue="32277" us="32277"/><bf gi="8229" ue="32279" us="32279"/><bf gi="8230" ue="32291" us="32283"/><bf gi="8239" ue="32296" us="32294"/><bf gi="8242" ue="32303" us="32299"/><bf gi="8247" ue="32307" us="32305"/><bf gi="8250" ue="32311" us="32309"/><bf gi="8253" ue="32315" us="32313"/><bf gi="8256" ue="32319" us="32317"/><bf gi="8259" ue="32321" us="32321"/><bf gi="8260" ue="32327" us="32323"/><bf gi="8265" ue="32331" us="32330"/><bf gi="8267" ue="32334" us="32333"/><bf gi="8269" ue="32336" us="32336"/><bf gi="8270" ue="32338" us="32338"/><bf gi="8271" ue="32342" us="32340"/><bf gi="8274" ue="32346" us="32344"/><bf gi="8277" ue="32351" us="32349"/><bf gi="8280" ue="32354" us="32353"/><bf gi="8282" ue="32359" us="32357"/><bf gi="8285" ue="32363" us="32361"/><bf gi="8288" ue="32368" us="32365"/><bf gi="8292" ue="32371" us="32371"/><bf gi="8293" ue="32377"!
  us="32376"/><bf gi="8295" ue="32383" us="32379"/><bf gi="8300" ue="32387" us="32385"/><bf gi="8303" ue="32394" us="32390"/><bf gi="8308" ue="32406" us="32396"/><bf gi="8319" ue="32408" us="32408"/><bf gi="8320" ue="32414" us="32410"/><bf gi="8325" ue="32566" us="32566"/><bf gi="8326" ue="32568" us="32568"/><bf gi="8327" ue="32575" us="32570"/><bf gi="8333" ue="32581" us="32579"/><bf gi="8336" ue="32583" us="32583"/><bf gi="8337" ue="32597" us="32588"/><bf gi="8347" ue="32600" us="32600"/><bf gi="8348" ue="32605" us="32603"/><bf gi="8351" ue="32609" us="32607"/><bf gi="8354" ue="32619" us="32611"/><bf gi="8363" ue="32622" us="32621"/><bf gi="8365" ue="32626" us="32624"/><bf gi="8368" ue="32629" us="32629"/><bf gi="8369" ue="32633" us="32631"/><bf gi="8372" ue="32640" us="32637"/><bf gi="8376" ue="32643" us="32642"/><bf gi="8378" ue="32648" us="32645"/><bf gi="8382" ue="32657" us="32650"/><bf gi="8390" ue="32660" us="32660"/><bf gi="8391" ue="32663" us="32662"/><bf gi="8393"!
  ue="32666" us="32666"/><bf gi="8394" ue="32670" us="32668"/><bf gi="8
397" ue="32676" us="32673"/><bf gi="8401" ue="32678" us="32678"/><bf gi="8402" ue="32682" us="32680"/><bf gi="8405" ue="32687" us="32685"/><bf gi="8408" ue="32690" us="32690"/><bf gi="8409" ue="32692" us="32692"/><bf gi="8410" ue="32694" us="32694"/><bf gi="8411" ue="32697" us="32696"/><bf gi="8413" ue="32701" us="32700"/><bf gi="8415" ue="32705" us="32703"/><bf gi="8418" ue="32707" us="32707"/><bf gi="8419" ue="32710" us="32709"/><bf gi="8421" ue="32712" us="32712"/><bf gi="8422" ue="32714" us="32714"/><bf gi="8423" ue="32716" us="32716"/><bf gi="8424" ue="32719" us="32718"/><bf gi="8426" ue="32722" us="32722"/><bf gi="8427" ue="32725" us="32724"/><bf gi="8429" ue="32731" us="32731"/><bf gi="8430" ue="32737" us="32735"/><bf gi="8433" ue="32739" us="32739"/><bf gi="8434" ue="32742" us="32741"/><bf gi="8436" ue="32745" us="32744"/><bf gi="8438" ue="32748" us="32747"/><bf gi="8440" ue="32752" us="32750"/><bf gi="8443" ue="32755" us="32754"/><bf gi="8445" ue="32769" us="32761"/!
 ><bf gi="8454" ue="32776" us="32771"/><bf gi="8460" ue="32793" us="32778"/><bf gi="8476" ue="32801" us="32796"/><bf gi="8482" ue="32804" us="32804"/><bf gi="8483" ue="32806" us="32806"/><bf gi="8484" ue="32808" us="32808"/><bf gi="8485" ue="32812" us="32812"/><bf gi="8486" ue="32814" us="32814"/><bf gi="8487" ue="32816" us="32816"/><bf gi="8488" ue="32823" us="32819"/><bf gi="8493" ue="32832" us="32825"/><bf gi="8501" ue="32836" us="32836"/><bf gi="8502" ue="32838" us="32838"/><bf gi="8503" ue="32842" us="32842"/><bf gi="8504" ue="32850" us="32850"/><bf gi="8505" ue="32854" us="32854"/><bf gi="8506" ue="32856" us="32856"/><bf gi="8507" ue="32858" us="32858"/><bf gi="8508" ue="32866" us="32862"/><bf gi="8513" ue="32868" us="32868"/><bf gi="8514" ue="32870" us="32870"/><bf gi="8515" ue="32872" us="32872"/><bf gi="8516" ue="32877" us="32877"/><bf gi="8517" ue="32887" us="32879"/><bf gi="8526" ue="32889" us="32889"/><bf gi="8527" ue="32895" us="32893"/><bf gi="8530" ue="32897" !
 us="32897"/><bf gi="8531" ue="32905" us="32900"/><bf gi="8537" ue="329
08" us="32907"/><bf gi="8539" ue="32910" us="32910"/><bf gi="8540" ue="32915" us="32915"/><bf gi="8541" ue="32918" us="32918"/><bf gi="8542" ue="32920" us="32920"/><bf gi="8543" ue="32926" us="32922"/><bf gi="8548" ue="32930" us="32929"/><bf gi="8550" ue="32935" us="32933"/><bf gi="8553" ue="32941" us="32937"/><bf gi="8558" ue="32943" us="32943"/><bf gi="8559" ue="32946" us="32945"/><bf gi="8561" ue="32948" us="32948"/><bf gi="8562" ue="32954" us="32952"/><bf gi="8565" ue="32964" us="32963"/><bf gi="8567" ue="32966" us="32966"/><bf gi="8568" ue="32968" us="32968"/><bf gi="8569" ue="32975" us="32972"/><bf gi="8573" ue="32978" us="32978"/><bf gi="8574" ue="32987" us="32980"/><bf gi="8582" ue="32990" us="32989"/><bf gi="8584" ue="32993" us="32992"/><bf gi="8586" ue="32997" us="32996"/><bf gi="8588" ue="33012" us="33005"/><bf gi="8596" ue="33014" us="33014"/><bf gi="8597" ue="33018" us="33016"/><bf gi="8600" ue="33022" us="33020"/><bf gi="8603" ue="33027" us="33026"/><bf gi="860!
 5" ue="33035" us="33029"/><bf gi="8612" ue="33048" us="33046"/><bf gi="8615" ue="33052" us="33050"/><bf gi="8618" ue="33054" us="33054"/><bf gi="8619" ue="33056" us="33056"/><bf gi="8620" ue="33060" us="33059"/><bf gi="8622" ue="33063" us="33063"/><bf gi="8623" ue="33065" us="33065"/><bf gi="8624" ue="33068" us="33068"/><bf gi="8625" ue="33073" us="33071"/><bf gi="8628" ue="33075" us="33075"/><bf gi="8629" ue="33077" us="33077"/><bf gi="8630" ue="33082" us="33081"/><bf gi="8632" ue="33084" us="33084"/><bf gi="8633" ue="33086" us="33086"/><bf gi="8634" ue="33095" us="33093"/><bf gi="8637" ue="33100" us="33098"/><bf gi="8640" ue="33102" us="33102"/><bf gi="8641" ue="33109" us="33104"/><bf gi="8647" ue="33111" us="33111"/><bf gi="8648" ue="33121" us="33119"/><bf gi="8651" ue="33129" us="33125"/><bf gi="8656" ue="33131" us="33131"/><bf gi="8657" ue="33137" us="33133"/><bf gi="8662" ue="33140" us="33140"/><bf gi="8663" ue="33146" us="33143"/><bf gi="8667" ue="33158" us="33151"/>!
 <bf gi="8675" ue="33160" us="33160"/><bf gi="8676" ue="33163" us="3316
2"/><bf gi="8678" ue="33168" us="33166"/><bf gi="8681" ue="33171" us="33171"/><bf gi="8682" ue="33174" us="33173"/><bf gi="8684" ue="33176" us="33176"/><bf gi="8685" ue="33182" us="33178"/><bf gi="8690" ue="33184" us="33184"/><bf gi="8691" ue="33188" us="33186"/><bf gi="8694" ue="33193" us="33192"/><bf gi="8696" ue="33198" us="33198"/><bf gi="8697" ue="33200" us="33200"/><bf gi="8698" ue="33205" us="33202"/><bf gi="8702" ue="33208" us="33208"/><bf gi="8703" ue="33211" us="33210"/><bf gi="8705" ue="33216" us="33213"/><bf gi="8709" ue="33219" us="33218"/><bf gi="8711" ue="33222" us="33221"/><bf gi="8713" ue="33227" us="33224"/><bf gi="8717" ue="33231" us="33229"/><bf gi="8720" ue="33233" us="33233"/><bf gi="8721" ue="33235" us="33235"/><bf gi="8722" ue="33237" us="33237"/><bf gi="8723" ue="33243" us="33239"/><bf gi="8728" ue="33249" us="33245"/><bf gi="8733" ue="33253" us="33251"/><bf gi="8736" ue="33256" us="33255"/><bf gi="8738" ue="33261" us="33258"/><bf gi="8742" ue="33270!
 " us="33264"/><bf gi="8749" ue="33283" us="33272"/><bf gi="8761" ue="33285" us="33285"/><bf gi="8762" ue="33290" us="33287"/><bf gi="8766" ue="33296" us="33292"/><bf gi="8771" ue="33300" us="33298"/><bf gi="8774" ue="33311" us="33302"/><bf gi="8784" ue="33314" us="33313"/><bf gi="8786" ue="33324" us="33320"/><bf gi="8791" ue="33326" us="33326"/><bf gi="8792" ue="33338" us="33330"/><bf gi="8801" ue="33344" us="33344"/><bf gi="8802" ue="33351" us="33347"/><bf gi="8807" ue="33355" us="33355"/><bf gi="8808" ue="33359" us="33358"/><bf gi="8810" ue="33361" us="33361"/><bf gi="8811" ue="33366" us="33366"/><bf gi="8812" ue="33370" us="33368"/><bf gi="8815" ue="33373" us="33372"/><bf gi="8817" ue="33376" us="33375"/><bf gi="8819" ue="33380" us="33378"/><bf gi="8822" ue="33384" us="33382"/><bf gi="8825" ue="33387" us="33386"/><bf gi="8827" ue="33391" us="33389"/><bf gi="8830" ue="33394" us="33393"/><bf gi="8832" ue="33396" us="33396"/><bf gi="8833" ue="33400" us="33398"/><bf gi="8836!
 " ue="33403" us="33403"/><bf gi="8837" ue="33409" us="33405"/><bf gi="
8842" ue="33412" us="33411"/><bf gi="8844" ue="33415" us="33415"/><bf gi="8845" ue="33419" us="33417"/><bf gi="8848" ue="33422" us="33421"/><bf gi="8850" ue="33426" us="33425"/><bf gi="8852" ue="33428" us="33428"/><bf gi="8853" ue="33430" us="33430"/><bf gi="8854" ue="33435" us="33432"/><bf gi="8858" ue="33437" us="33437"/><bf gi="8859" ue="33441" us="33439"/><bf gi="8862" ue="33460" us="33443"/><bf gi="8880" ue="33471" us="33463"/><bf gi="8889" ue="33478" us="33477"/><bf gi="8891" ue="33493" us="33488"/><bf gi="8897" ue="33495" us="33495"/><bf gi="8898" ue="33500" us="33497"/><bf gi="8902" ue="33512" us="33502"/><bf gi="8913" ue="33515" us="33514"/><bf gi="8915" ue="33517" us="33517"/><bf gi="8916" ue="33519" us="33519"/><bf gi="8917" ue="33521" us="33521"/><bf gi="8918" ue="33524" us="33523"/><bf gi="8920" ue="33527" us="33526"/><bf gi="8922" ue="33531" us="33529"/><bf gi="8925" ue="33534" us="33533"/><bf gi="8927" ue="33547" us="33536"/><bf gi="8939" ue="33550" us="33550"!
 /><bf gi="8940" ue="33560" us="33558"/><bf gi="8943" ue="33567" us="33563"/><bf gi="8948" ue="33571" us="33569"/><bf gi="8951" ue="33576" us="33576"/><bf gi="8952" ue="33594" us="33579"/><bf gi="8968" ue="33597" us="33596"/><bf gi="8970" ue="33600" us="33600"/><bf gi="8971" ue="33605" us="33602"/><bf gi="8975" ue="33607" us="33607"/><bf gi="8976" ue="33610" us="33609"/><bf gi="8978" ue="33624" us="33613"/><bf gi="8990" ue="33634" us="33634"/><bf gi="8991" ue="33648" us="33648"/><bf gi="8992" ue="33651" us="33651"/><bf gi="8993" ue="33653" us="33653"/><bf gi="8994" ue="33656" us="33655"/><bf gi="8996" ue="33661" us="33659"/><bf gi="8999" ue="33664" us="33663"/><bf gi="9001" ue="33666" us="33666"/><bf gi="9002" ue="33671" us="33668"/><bf gi="9006" ue="33674" us="33673"/><bf gi="9008" ue="33678" us="33677"/><bf gi="9010" ue="33686" us="33682"/><bf gi="9015" ue="33696" us="33688"/><bf gi="9024" ue="33698" us="33698"/><bf gi="9025" ue="33709" us="33702"/><bf gi="9033" ue="33713"!
  us="33713"/><bf gi="9034" ue="33717" us="33717"/><bf gi="9035" ue="33
729" us="33725"/><bf gi="9040" ue="33733" us="33733"/><bf gi="9041" ue="33735" us="33735"/><bf gi="9042" ue="33738" us="33737"/><bf gi="9044" ue="33740" us="33740"/><bf gi="9045" ue="33745" us="33742"/><bf gi="9049" ue="33748" us="33747"/><bf gi="9051" ue="33750" us="33750"/><bf gi="9052" ue="33752" us="33752"/><bf gi="9053" ue="33757" us="33756"/><bf gi="9055" ue="33760" us="33759"/><bf gi="9057" ue="33771" us="33768"/><bf gi="9061" ue="33778" us="33775"/><bf gi="9065" ue="33780" us="33780"/><bf gi="9066" ue="33785" us="33782"/><bf gi="9070" ue="33789" us="33787"/><bf gi="9073" ue="33793" us="33793"/><bf gi="9074" ue="33796" us="33795"/><bf gi="9076" ue="33799" us="33798"/><bf gi="9078" ue="33807" us="33802"/><bf gi="9084" ue="33809" us="33809"/><bf gi="9085" ue="33811" us="33811"/><bf gi="9086" ue="33813" us="33813"/><bf gi="9087" ue="33817" us="33817"/><bf gi="9088" ue="33824" us="33824"/><bf gi="9089" ue="33826" us="33826"/><bf gi="9090" ue="33834" us="33833"/><bf gi="90!
 92" ue="33836" us="33836"/><bf gi="9093" ue="33839" us="33839"/><bf gi="9094" ue="33841" us="33841"/><bf gi="9095" ue="33845" us="33845"/><bf gi="9096" ue="33849" us="33848"/><bf gi="9098" ue="33853" us="33852"/><bf gi="9100" ue="33866" us="33861"/><bf gi="9106" ue="33871" us="33869"/><bf gi="9109" ue="33874" us="33873"/><bf gi="9111" ue="33884" us="33878"/><bf gi="9118" ue="33895" us="33888"/><bf gi="9126" ue="33905" us="33897"/><bf gi="9135" ue="33914" us="33907"/><bf gi="9143" ue="33917" us="33916"/><bf gi="9145" ue="33922" us="33921"/><bf gi="9147" ue="33925" us="33924"/><bf gi="9149" ue="33931" us="33931"/><bf gi="9150" ue="33936" us="33936"/><bf gi="9151" ue="33941" us="33938"/><bf gi="9155" ue="33945" us="33945"/><bf gi="9156" ue="33948" us="33948"/><bf gi="9157" ue="33951" us="33950"/><bf gi="9159" ue="33953" us="33953"/><bf gi="9160" ue="33958" us="33958"/><bf gi="9161" ue="33962" us="33960"/><bf gi="9164" ue="33965" us="33965"/><bf gi="9165" ue="33967" us="33967"/!
 ><bf gi="9166" ue="33970" us="33969"/><bf gi="9168" ue="33972" us="339
72"/><bf gi="9169" ue="33986" us="33976"/><bf gi="9180" ue="33988" us="33988"/><bf gi="9181" ue="33997" us="33990"/><bf gi="9189" ue="34001" us="33999"/><bf gi="9192" ue="34003" us="34003"/><bf gi="9193" ue="34006" us="34006"/><bf gi="9194" ue="34010" us="34009"/><bf gi="9196" ue="34012" us="34012"/><bf gi="9197" ue="34023" us="34023"/><bf gi="9198" ue="34026" us="34026"/><bf gi="9199" ue="34028" us="34028"/><bf gi="9200" ue="34034" us="34030"/><bf gi="9205" ue="34036" us="34036"/><bf gi="9206" ue="34039" us="34039"/><bf gi="9207" ue="34045" us="34042"/><bf gi="9211" ue="34048" us="34047"/><bf gi="9213" ue="34051" us="34050"/><bf gi="9215" ue="34055" us="34054"/><bf gi="9217" ue="34060" us="34060"/><bf gi="9218" ue="34062" us="34062"/><bf gi="9219" ue="34065" us="34064"/><bf gi="9221" ue="34069" us="34067"/><bf gi="9224" ue="34072" us="34071"/><bf gi="9226" ue="34074" us="34074"/><bf gi="9227" ue="34076" us="34076"/><bf gi="9228" ue="34079" us="34078"/><bf gi="9230" ue="3408!
 7" us="34081"/><bf gi="9237" ue="34093" us="34090"/><bf gi="9241" ue="34095" us="34095"/><bf gi="9242" ue="34102" us="34098"/><bf gi="9247" ue="34109" us="34109"/><bf gi="9248" ue="34113" us="34111"/><bf gi="9251" ue="34115" us="34115"/><bf gi="9252" ue="34118" us="34118"/><bf gi="9253" ue="34123" us="34120"/><bf gi="9257" ue="34131" us="34126"/><bf gi="9263" ue="34138" us="34133"/><bf gi="9269" ue="34148" us="34140"/><bf gi="9278" ue="34155" us="34152"/><bf gi="9282" ue="34157" us="34157"/><bf gi="9283" ue="34159" us="34159"/><bf gi="9284" ue="34167" us="34167"/><bf gi="9285" ue="34171" us="34169"/><bf gi="9288" ue="34177" us="34173"/><bf gi="9293" ue="34188" us="34180"/><bf gi="9302" ue="34193" us="34191"/><bf gi="9305" ue="34196" us="34195"/><bf gi="9307" ue="34201" us="34199"/><bf gi="9310" ue="34205" us="34203"/><bf gi="9313" ue="34208" us="34207"/><bf gi="9315" ue="34210" us="34210"/><bf gi="9316" ue="34224" us="34212"/><bf gi="9329" ue="34228" us="34228"/><bf gi="933!
 0" ue="34234" us="34230"/><bf gi="9335" ue="34239" us="34236"/><bf gi=
"9339" ue="34242" us="34241"/><bf gi="9341" ue="34247" us="34247"/><bf gi="9342" ue="34251" us="34249"/><bf gi="9345" ue="34256" us="34253"/><bf gi="9349" ue="34261" us="34261"/><bf gi="9350" ue="34264" us="34264"/><bf gi="9351" ue="34266" us="34266"/><bf gi="9352" ue="34269" us="34268"/><bf gi="9354" ue="34272" us="34271"/><bf gi="9356" ue="34278" us="34276"/><bf gi="9359" ue="34282" us="34280"/><bf gi="9362" ue="34285" us="34285"/><bf gi="9363" ue="34291" us="34291"/><bf gi="9364" ue="34295" us="34294"/><bf gi="9366" ue="34300" us="34297"/><bf gi="9370" ue="34304" us="34302"/><bf gi="9373" ue="34306" us="34306"/><bf gi="9374" ue="34311" us="34308"/><bf gi="9378" ue="34315" us="34314"/><bf gi="9380" ue="34318" us="34317"/><bf gi="9382" ue="34323" us="34320"/><bf gi="9386" ue="34331" us="34326"/><bf gi="9392" ue="34334" us="34334"/><bf gi="9393" ue="34338" us="34337"/><bf gi="9395" ue="34343" us="34343"/><bf gi="9396" ue="34345" us="34345"/><bf gi="9397" ue="34349" us="34349!
 "/><bf gi="9398" ue="34352" us="34351"/><bf gi="9400" ue="34358" us="34358"/><bf gi="9401" ue="34360" us="34360"/><bf gi="9402" ue="34362" us="34362"/><bf gi="9403" ue="34365" us="34364"/><bf gi="9405" ue="34370" us="34367"/><bf gi="9409" ue="34374" us="34374"/><bf gi="9410" ue="34382" us="34381"/><bf gi="9412" ue="34384" us="34384"/><bf gi="9413" ue="34394" us="34386"/><bf gi="9422" ue="34404" us="34396"/><bf gi="9431" ue="34407" us="34407"/><bf gi="9432" ue="34409" us="34409"/><bf gi="9433" ue="34412" us="34411"/><bf gi="9435" ue="34415" us="34415"/><bf gi="9436" ue="34417" us="34417"/><bf gi="9437" ue="34423" us="34421"/><bf gi="9440" ue="34427" us="34425"/><bf gi="9443" ue="34440" us="34440"/><bf gi="9444" ue="34445" us="34442"/><bf gi="9448" ue="34449" us="34449"/><bf gi="9449" ue="34451" us="34451"/><bf gi="9450" ue="34454" us="34453"/><bf gi="9452" ue="34456" us="34456"/><bf gi="9453" ue="34458" us="34458"/><bf gi="9454" ue="34460" us="34460"/><bf gi="9455" ue="34465!
 " us="34465"/><bf gi="9456" ue="34468" us="34467"/><bf gi="9458" ue="3
4475" us="34470"/><bf gi="9464" ue="34477" us="34477"/><bf gi="9465" ue="34481" us="34479"/><bf gi="9468" ue="34489" us="34483"/><bf gi="9475" ue="34497" us="34495"/><bf gi="9478" ue="34503" us="34499"/><bf gi="9483" ue="34505" us="34505"/><bf gi="9484" ue="34507" us="34507"/><bf gi="9485" ue="34510" us="34509"/><bf gi="9487" ue="34514" us="34513"/><bf gi="9489" ue="34517" us="34516"/><bf gi="9491" ue="34519" us="34519"/><bf gi="9492" ue="34524" us="34521"/><bf gi="9496" ue="34528" us="34526"/><bf gi="9499" ue="34533" us="34531"/><bf gi="9502" ue="34535" us="34535"/><bf gi="9503" ue="34537" us="34537"/><bf gi="9504" ue="34543" us="34540"/><bf gi="9508" ue="34558" us="34552"/><bf gi="9515" ue="34560" us="34560"/><bf gi="9516" ue="34571" us="34562"/><bf gi="9526" ue="34580" us="34573"/><bf gi="9534" ue="34586" us="34584"/><bf gi="9537" ue="34588" us="34588"/><bf gi="9538" ue="34591" us="34590"/><bf gi="9540" ue="34593" us="34593"/><bf gi="9541" ue="34595" us="34595"/><bf gi="9!
 542" ue="34597" us="34597"/><bf gi="9543" ue="34601" us="34600"/><bf gi="9545" ue="34607" us="34606"/><bf gi="9547" ue="34610" us="34609"/><bf gi="9549" ue="34612" us="34612"/><bf gi="9550" ue="34615" us="34615"/><bf gi="9551" ue="34624" us="34617"/><bf gi="9559" ue="34627" us="34627"/><bf gi="9560" ue="34629" us="34629"/><bf gi="9561" ue="34633" us="34633"/><bf gi="9562" ue="34638" us="34635"/><bf gi="9566" ue="34643" us="34643"/><bf gi="9567" ue="34645" us="34645"/><bf gi="9568" ue="34649" us="34647"/><bf gi="9571" ue="34653" us="34653"/><bf gi="9572" ue="34657" us="34655"/><bf gi="9575" ue="34662" us="34659"/><bf gi="9579" ue="34664" us="34664"/><bf gi="9580" ue="34666" us="34666"/><bf gi="9581" ue="34671" us="34670"/><bf gi="9583" ue="34674" us="34673"/><bf gi="9585" ue="34676" us="34676"/><bf gi="9586" ue="34678" us="34678"/><bf gi="9587" ue="34680" us="34680"/><bf gi="9588" ue="34683" us="34683"/><bf gi="9589" ue="34687" us="34687"/><bf gi="9590" ue="34697" us="34690"!
 /><bf gi="9598" ue="34701" us="34699"/><bf gi="9601" ue="34704" us="34
704"/><bf gi="9602" ue="34707" us="34707"/><bf gi="9603" ue="34709" us="34709"/><bf gi="9604" ue="34713" us="34711"/><bf gi="9607" ue="34720" us="34718"/><bf gi="9610" ue="34723" us="34722"/><bf gi="9612" ue="34727" us="34727"/><bf gi="9613" ue="34735" us="34731"/><bf gi="9618" ue="34737" us="34737"/><bf gi="9619" ue="34739" us="34739"/><bf gi="9620" ue="34741" us="34741"/><bf gi="9621" ue="34747" us="34746"/><bf gi="9623" ue="34753" us="34749"/><bf gi="9628" ue="34756" us="34756"/><bf gi="9629" ue="34763" us="34758"/><bf gi="9635" ue="34766" us="34766"/><bf gi="9636" ue="34768" us="34768"/><bf gi="9637" ue="34770" us="34770"/><bf gi="9638" ue="34774" us="34773"/><bf gi="9640" ue="34778" us="34777"/><bf gi="9642" ue="34780" us="34780"/><bf gi="9643" ue="34784" us="34783"/><bf gi="9645" ue="34788" us="34786"/><bf gi="9648" ue="34795" us="34794"/><bf gi="9650" ue="34797" us="34797"/><bf gi="9651" ue="34799" us="34799"/><bf gi="9652" ue="34803" us="34801"/><bf gi="9655" ue="348!
 11" us="34806"/><bf gi="9661" ue="34815" us="34814"/><bf gi="9663" ue="34817" us="34817"/><bf gi="9664" ue="34819" us="34819"/><bf gi="9665" ue="34823" us="34821"/><bf gi="9668" ue="34827" us="34825"/><bf gi="9671" ue="34838" us="34829"/><bf gi="9681" ue="34844" us="34840"/><bf gi="9686" ue="34847" us="34846"/><bf gi="9688" ue="34851" us="34849"/><bf gi="9691" ue="34856" us="34855"/><bf gi="9693" ue="34862" us="34861"/><bf gi="9695" ue="34866" us="34864"/><bf gi="9698" ue="34870" us="34869"/><bf gi="9700" ue="34876" us="34873"/><bf gi="9704" ue="34886" us="34880"/><bf gi="9711" ue="34894" us="34888"/><bf gi="9718" ue="34899" us="34897"/><bf gi="9721" ue="34916" us="34901"/><bf gi="9737" ue="34921" us="34920"/><bf gi="9739" ue="34923" us="34923"/><bf gi="9740" ue="34930" us="34928"/><bf gi="9743" ue="34933" us="34933"/><bf gi="9744" ue="34935" us="34935"/><bf gi="9745" ue="34937" us="34937"/><bf gi="9746" ue="34939" us="34939"/><bf gi="9747" ue="34946" us="34941"/><bf gi="97!
 53" ue="34952" us="34952"/><bf gi="9754" ue="34955" us="34955"/><bf gi
="9755" ue="34957" us="34957"/><bf gi="9756" ue="34962" us="34962"/><bf gi="9757" ue="34972" us="34966"/><bf gi="9764" ue="34976" us="34974"/><bf gi="9767" ue="34978" us="34978"/><bf gi="9768" ue="34980" us="34980"/><bf gi="9769" ue="34984" us="34984"/><bf gi="9770" ue="34987" us="34986"/><bf gi="9772" ue="34990" us="34990"/><bf gi="9773" ue="34993" us="34992"/><bf gi="9775" ue="34997" us="34996"/><bf gi="9777" ue="34999" us="34999"/><bf gi="9778" ue="35002" us="35002"/><bf gi="9779" ue="35013" us="35005"/><bf gi="9788" ue="35023" us="35018"/><bf gi="9794" ue="35029" us="35025"/><bf gi="9799" ue="35033" us="35032"/><bf gi="9801" ue="35039" us="35035"/><bf gi="9806" ue="35041" us="35041"/><bf gi="9807" ue="35048" us="35047"/><bf gi="9809" ue="35061" us="35055"/><bf gi="9816" ue="35065" us="35063"/><bf gi="9819" ue="35070" us="35068"/><bf gi="9822" ue="35074" us="35073"/><bf gi="9824" ue="35076" us="35076"/><bf gi="9825" ue="35079" us="35078"/><bf gi="9827" ue="35082" us="3508!
 2"/><bf gi="9828" ue="35088" us="35084"/><bf gi="9833" ue="35091" us="35090"/><bf gi="9835" ue="35094" us="35093"/><bf gi="9837" ue="35098" us="35096"/><bf gi="9840" ue="35102" us="35100"/><bf gi="9843" ue="35104" us="35104"/><bf gi="9844" ue="35112" us="35109"/><bf gi="9848" ue="35115" us="35114"/><bf gi="9850" ue="35122" us="35120"/><bf gi="9853" ue="35126" us="35125"/><bf gi="9855" ue="35131" us="35128"/><bf gi="9859" ue="35134" us="35134"/><bf gi="9860" ue="35142" us="35136"/><bf gi="9867" ue="35145" us="35145"/><bf gi="9868" ue="35149" us="35148"/><bf gi="9870" ue="35151" us="35151"/><bf gi="9871" ue="35154" us="35154"/><bf gi="9872" ue="35159" us="35158"/><bf gi="9874" ue="35164" us="35162"/><bf gi="9877" ue="35172" us="35166"/><bf gi="9884" ue="35174" us="35174"/><bf gi="9885" ue="35179" us="35178"/><bf gi="9887" ue="35184" us="35181"/><bf gi="9891" ue="35189" us="35186"/><bf gi="9895" ue="35191" us="35191"/><bf gi="9896" ue="35199" us="35194"/><bf gi="9902" ue="3520!
 1" us="35201"/><bf gi="9903" ue="35203" us="35203"/><bf gi="9904" ue="
35211" us="35206"/><bf gi="9910" ue="35213" us="35213"/><bf gi="9911" ue="35216" us="35215"/><bf gi="9913" ue="35224" us="35219"/><bf gi="9919" ue="35228" us="35226"/><bf gi="9922" ue="35233" us="35231"/><bf gi="9925" ue="35239" us="35237"/><bf gi="9928" ue="35242" us="35241"/><bf gi="9930" ue="35244" us="35244"/><bf gi="9931" ue="35248" us="35247"/><bf gi="9933" ue="35255" us="35250"/><bf gi="9939" ue="35258" us="35258"/><bf gi="9940" ue="35261" us="35260"/><bf gi="9942" ue="35264" us="35263"/><bf gi="9944" ue="35282" us="35282"/><bf gi="9945" ue="35288" us="35284"/><bf gi="9950" ue="35290" us="35290"/><bf gi="9951" ue="35293" us="35292"/><bf gi="9953" ue="35299" us="35299"/><bf gi="9954" ue="35303" us="35301"/><bf gi="9957" ue="35305" us="35305"/><bf gi="9958" ue="35307" us="35307"/><bf gi="9959" ue="35309" us="35309"/><bf gi="9960" ue="35313" us="35313"/><bf gi="9961" ue="35316" us="35315"/><bf gi="9963" ue="35318" us="35318"/><bf gi="9964" ue="35321" us="35320"/><bf gi="!
 9966" ue="35325" us="35325"/><bf gi="9967" ue="35328" us="35327"/><bf gi="9969" ue="35333" us="35330"/><bf gi="9973" ue="35336" us="35335"/><bf gi="9975" ue="35338" us="35338"/><bf gi="9976" ue="35340" us="35340"/><bf gi="9977" ue="35352" us="35342"/><bf gi="9988" ue="35355" us="35355"/><bf gi="9989" ue="35360" us="35357"/><bf gi="9993" ue="35366" us="35362"/><bf gi="9998" ue="35373" us="35370"/><bf gi="10002" ue="35375" us="35375"/><bf gi="10003" ue="35377" us="35377"/><bf gi="10004" ue="35383" us="35379"/><bf gi="10009" ue="35390" us="35386"/><bf gi="10014" ue="35393" us="35392"/><bf gi="10016" ue="35395" us="35395"/><bf gi="10017" ue="35401" us="35397"/><bf gi="10022" ue="35406" us="35405"/><bf gi="10024" ue="35416" us="35408"/><bf gi="10033" ue="35422" us="35419"/><bf gi="10037" ue="35427" us="35424"/><bf gi="10041" ue="35431" us="35429"/><bf gi="10044" ue="35433" us="35433"/><bf gi="10045" ue="35438" us="35435"/><bf gi="10049" ue="35443" us="35440"/><bf gi="10053" ue="!
 35447" us="35445"/><bf gi="10056" ue="35452" us="35449"/><bf gi="10060
" ue="35456" us="35454"/><bf gi="10063" ue="35463" us="35458"/><bf gi="10069" ue="35465" us="35465"/><bf gi="10070" ue="35469" us="35467"/><bf gi="10073" ue="35475" us="35471"/><bf gi="10078" ue="35482" us="35477"/><bf gi="10084" ue="35489" us="35486"/><bf gi="10088" ue="35497" us="35491"/><bf gi="10095" ue="35504" us="35500"/><bf gi="10100" ue="35507" us="35506"/><bf gi="10102" ue="35511" us="35510"/><bf gi="10104" ue="35513" us="35513"/><bf gi="10105" ue="35516" us="35515"/><bf gi="10107" ue="35519" us="35518"/><bf gi="10109" ue="35524" us="35522"/><bf gi="10112" ue="35533" us="35526"/><bf gi="10120" ue="35535" us="35535"/><bf gi="10121" ue="35543" us="35537"/><bf gi="10128" ue="35554" us="35546"/><bf gi="10137" ue="35556" us="35556"/><bf gi="10138" ue="35559" us="35558"/><bf gi="10140" ue="35566" us="35563"/><bf gi="10144" ue="35569" us="35568"/><bf gi="10146" ue="35576" us="35571"/><bf gi="10152" ue="35578" us="35578"/><bf gi="10153" ue="35580" us="35580"/><bf gi="10154"!
  ue="35586" us="35582"/><bf gi="10159" ue="35591" us="35588"/><bf gi="10163" ue="35596" us="35594"/><bf gi="10166" ue="35598" us="35598"/><bf gi="10167" ue="35601" us="35600"/><bf gi="10169" ue="35604" us="35604"/><bf gi="10170" ue="35607" us="35606"/><bf gi="10172" ue="35617" us="35609"/><bf gi="10181" ue="35622" us="35622"/><bf gi="10182" ue="35624" us="35624"/><bf gi="10183" ue="35629" us="35627"/><bf gi="10186" ue="35632" us="35632"/><bf gi="10187" ue="35635" us="35635"/><bf gi="10188" ue="35639" us="35639"/><bf gi="10189" ue="35641" us="35641"/><bf gi="10190" ue="35644" us="35644"/><bf gi="10191" ue="35646" us="35646"/><bf gi="10192" ue="35654" us="35649"/><bf gi="10198" ue="35657" us="35656"/><bf gi="10200" ue="35663" us="35660"/><bf gi="10204" ue="35668" us="35666"/><bf gi="10207" ue="35670" us="35670"/><bf gi="10208" ue="35676" us="35672"/><bf gi="10213" ue="35679" us="35678"/><bf gi="10215" ue="35683" us="35683"/><bf gi="10216" ue="35686" us="35686"/><bf gi="10217"!
  ue="35693" us="35691"/><bf gi="10220" ue="35698" us="35695"/><bf gi="
10224" ue="35700" us="35700"/><bf gi="10225" ue="35705" us="35702"/><bf gi="10229" ue="35713" us="35708"/><bf gi="10235" ue="35717" us="35715"/><bf gi="10238" ue="35728" us="35722"/><bf gi="10245" ue="35734" us="35730"/><bf gi="10250" ue="35738" us="35737"/><bf gi="10252" ue="35740" us="35740"/><bf gi="10253" ue="35743" us="35742"/><bf gi="10255" ue="35898" us="35895"/><bf gi="10259" ue="35903" us="35901"/><bf gi="10262" ue="35905" us="35905"/><bf gi="10263" ue="35916" us="35909"/><bf gi="10271" ue="35921" us="35918"/><bf gi="10275" ue="35925" us="35923"/><bf gi="10278" ue="35931" us="35927"/><bf gi="10283" ue="35933" us="35933"/><bf gi="10284" ue="35940" us="35937"/><bf gi="10288" ue="35942" us="35942"/><bf gi="10289" ue="35949" us="35944"/><bf gi="10295" ue="35955" us="35955"/><bf gi="10296" ue="35958" us="35957"/><bf gi="10298" ue="35964" us="35960"/><bf gi="10303" ue="35966" us="35966"/><bf gi="10304" ue="35970" us="35970"/><bf gi="10305" ue="35975" us="35973"/><bf gi="1!
 0308" ue="35982" us="35977"/><bf gi="10314" ue="35984" us="35984"/><bf gi="10315" ue="35988" us="35986"/><bf gi="10318" ue="35993" us="35992"/><bf gi="10320" ue="35998" us="35995"/><bf gi="10324" ue="36002" us="36000"/><bf gi="10327" ue="36004" us="36004"/><bf gi="10328" ue="36016" us="36007"/><bf gi="10338" ue="36020" us="36018"/><bf gi="10341" ue="36029" us="36022"/><bf gi="10349" ue="36043" us="36031"/><bf gi="10362" ue="36047" us="36045"/><bf gi="10365" ue="36049" us="36049"/><bf gi="10366" ue="36051" us="36051"/><bf gi="10367" ue="36054" us="36053"/><bf gi="10369" ue="36062" us="36057"/><bf gi="10375" ue="36068" us="36064"/><bf gi="10380" ue="36070" us="36070"/><bf gi="10381" ue="36072" us="36072"/><bf gi="10382" ue="36074" us="36074"/><bf gi="10383" ue="36077" us="36076"/><bf gi="10385" ue="36080" us="36079"/><bf gi="10387" ue="36082" us="36082"/><bf gi="10388" ue="36085" us="36084"/><bf gi="10390" ue="36088" us="36087"/><bf gi="10392" ue="36095" us="36090"/><bf gi="1!
 0398" ue="36097" us="36097"/><bf gi="10399" ue="36101" us="36099"/><bf
 gi="10402" ue="36107" us="36103"/><bf gi="10407" ue="36109" us="36109"/><bf gi="10408" ue="36112" us="36111"/><bf gi="10410" ue="36116" us="36114"/><bf gi="10413" ue="36119" us="36118"/><bf gi="10415" ue="36123" us="36123"/><bf gi="10416" ue="36199" us="36196"/><bf gi="10420" ue="36201" us="36201"/><bf gi="10421" ue="36206" us="36203"/><bf gi="10425" ue="36209" us="36208"/><bf gi="10427" ue="36212" us="36211"/><bf gi="10429" ue="36215" us="36214"/><bf gi="10431" ue="36223" us="36223"/><bf gi="10432" ue="36226" us="36225"/><bf gi="10434" ue="36229" us="36228"/><bf gi="10436" ue="36232" us="36232"/><bf gi="10437" ue="36234" us="36234"/><bf gi="10438" ue="36237" us="36237"/><bf gi="10439" ue="36241" us="36240"/><bf gi="10441" ue="36245" us="36245"/><bf gi="10442" ue="36249" us="36249"/><bf gi="10443" ue="36256" us="36254"/><bf gi="10446" ue="36259" us="36259"/><bf gi="10447" ue="36262" us="36262"/><bf gi="10448" ue="36264" us="36264"/><bf gi="10449" ue="36268" us="36267"/><bf !
 gi="10451" ue="36271" us="36271"/><bf gi="10452" ue="36275" us="36274"/><bf gi="10454" ue="36277" us="36277"/><bf gi="10455" ue="36279" us="36279"/><bf gi="10456" ue="36284" us="36281"/><bf gi="10460" ue="36286" us="36286"/><bf gi="10461" ue="36288" us="36288"/><bf gi="10462" ue="36290" us="36290"/><bf gi="10463" ue="36296" us="36293"/><bf gi="10467" ue="36300" us="36298"/><bf gi="10470" ue="36303" us="36302"/><bf gi="10472" ue="36305" us="36305"/><bf gi="10473" ue="36311" us="36308"/><bf gi="10477" ue="36315" us="36313"/><bf gi="10480" ue="36317" us="36317"/><bf gi="10481" ue="36319" us="36319"/><bf gi="10482" ue="36321" us="36321"/><bf gi="10483" ue="36325" us="36323"/><bf gi="10486" ue="36328" us="36327"/><bf gi="10488" ue="36332" us="36330"/><bf gi="10491" ue="36341" us="36335"/><bf gi="10498" ue="36349" us="36348"/><bf gi="10500" ue="36351" us="36351"/><bf gi="10501" ue="36353" us="36353"/><bf gi="10502" ue="36358" us="36356"/><bf gi="10505" ue="36363" us="36360"/><bf !
 gi="10509" ue="36369" us="36367"/><bf gi="10512" ue="36372" us="36372"
/><bf gi="10513" ue="36374" us="36374"/><bf gi="10514" ue="36387" us="36381"/><bf gi="10521" ue="36391" us="36390"/><bf gi="10523" ue="36394" us="36394"/><bf gi="10524" ue="36401" us="36400"/><bf gi="10526" ue="36409" us="36403"/><bf gi="10533" ue="36413" us="36413"/><bf gi="10534" ue="36418" us="36416"/><bf gi="10537" ue="36420" us="36420"/><bf gi="10538" ue="36432" us="36423"/><bf gi="10548" ue="36437" us="36436"/><bf gi="10550" ue="36441" us="36441"/><bf gi="10551" ue="36452" us="36443"/><bf gi="10561" ue="36457" us="36457"/><bf gi="10562" ue="36461" us="36460"/><bf gi="10564" ue="36466" us="36463"/><bf gi="10568" ue="36468" us="36468"/><bf gi="10569" ue="36470" us="36470"/><bf gi="10570" ue="36476" us="36473"/><bf gi="10574" ue="36485" us="36481"/><bf gi="10579" ue="36487" us="36487"/><bf gi="10580" ue="36491" us="36489"/><bf gi="10583" ue="36493" us="36493"/><bf gi="10584" ue="36501" us="36496"/><bf gi="10590" ue="36507" us="36505"/><bf gi="10593" ue="36510" us="36509"/!
 ><bf gi="10595" ue="36514" us="36513"/><bf gi="10597" ue="36519" us="36519"/><bf gi="10598" ue="36529" us="36521"/><bf gi="10607" ue="36531" us="36531"/><bf gi="10608" ue="36533" us="36533"/><bf gi="10609" ue="36539" us="36538"/><bf gi="10611" ue="36542" us="36542"/><bf gi="10612" ue="36545" us="36544"/><bf gi="10614" ue="36552" us="36547"/><bf gi="10620" ue="36557" us="36554"/><bf gi="10624" ue="36559" us="36559"/><bf gi="10625" ue="36562" us="36561"/><bf gi="10627" ue="36564" us="36564"/><bf gi="10628" ue="36572" us="36571"/><bf gi="10630" ue="36575" us="36575"/><bf gi="10631" ue="36579" us="36578"/><bf gi="10633" ue="36584" us="36584"/><bf gi="10634" ue="36587" us="36587"/><bf gi="10635" ue="36590" us="36589"/><bf gi="10637" ue="36593" us="36592"/><bf gi="10639" ue="36606" us="36599"/><bf gi="10647" ue="36608" us="36608"/><bf gi="10648" ue="36611" us="36610"/><bf gi="10650" ue="36613" us="36613"/><bf gi="10651" ue="36618" us="36615"/><bf gi="10655" ue="36620" us="36620"/!
 ><bf gi="10656" ue="36624" us="36623"/><bf gi="10658" ue="36633" us="3
6626"/><bf gi="10666" ue="36641" us="36635"/><bf gi="10673" ue="36643" us="36643"/><bf gi="10674" ue="36650" us="36645"/><bf gi="10680" ue="36655" us="36652"/><bf gi="10684" ue="36667" us="36659"/><bf gi="10693" ue="36679" us="36670"/><bf gi="10703" ue="36681" us="36681"/><bf gi="10704" ue="36687" us="36684"/><bf gi="10708" ue="36693" us="36689"/><bf gi="10713" ue="36696" us="36695"/><bf gi="10715" ue="36703" us="36700"/><bf gi="10719" ue="36709" us="36705"/><bf gi="10724" ue="36769" us="36763"/><bf gi="10731" ue="36776" us="36771"/><bf gi="10737" ue="36786" us="36781"/><bf gi="10743" ue="36792" us="36789"/><bf gi="10747" ue="36796" us="36794"/><bf gi="10750" ue="36802" us="36798"/><bf gi="10755" ue="36806" us="36804"/><bf gi="10758" ue="36811" us="36810"/><bf gi="10760" ue="36814" us="36813"/><bf gi="10762" ue="36821" us="36816"/><bf gi="10768" ue="36826" us="36826"/><bf gi="10769" ue="36832" us="36832"/><bf gi="10770" ue="36838" us="36834"/><bf gi="10775" ue="36843" us="36!
 840"/><bf gi="10779" ue="36849" us="36845"/><bf gi="10784" ue="36859" us="36852"/><bf gi="10792" ue="36862" us="36861"/><bf gi="10794" ue="36870" us="36864"/><bf gi="10801" ue="36872" us="36872"/><bf gi="10802" ue="36881" us="36875"/><bf gi="10809" ue="36891" us="36883"/><bf gi="10818" ue="36899" us="36893"/><bf gi="10825" ue="36906" us="36903"/><bf gi="10829" ue="36911" us="36908"/><bf gi="10833" ue="36921" us="36913"/><bf gi="10842" ue="36924" us="36924"/><bf gi="10843" ue="36927" us="36926"/><bf gi="10845" ue="36933" us="36929"/><bf gi="10850" ue="36935" us="36935"/><bf gi="10851" ue="36950" us="36937"/><bf gi="10865" ue="36953" us="36952"/><bf gi="10867" ue="36958" us="36955"/><bf gi="10871" ue="36963" us="36960"/><bf gi="10875" ue="36969" us="36965"/><bf gi="10880" ue="36976" us="36972"/><bf gi="10885" ue="36978" us="36978"/><bf gi="10886" ue="36986" us="36980"/><bf gi="10893" ue="36989" us="36988"/><bf gi="10895" ue="36997" us="36991"/><bf gi="10902" ue="37004" us="36!
 999"/><bf gi="10908" ue="37009" us="37006"/><bf gi="10912" ue="37013" 
us="37013"/><bf gi="10913" ue="37017" us="37015"/><bf gi="10916" ue="37019" us="37019"/><bf gi="10917" ue="37027" us="37024"/><bf gi="10921" ue="37030" us="37029"/><bf gi="10923" ue="37032" us="37032"/><bf gi="10924" ue="37034" us="37034"/><bf gi="10925" ue="37046" us="37039"/><bf gi="10933" ue="37048" us="37048"/><bf gi="10934" ue="37054" us="37053"/><bf gi="10936" ue="37057" us="37057"/><bf gi="10937" ue="37061" us="37059"/><bf gi="10940" ue="37064" us="37063"/><bf gi="10942" ue="37066" us="37066"/><bf gi="10943" ue="37068" us="37068"/><bf gi="10944" ue="37070" us="37070"/><bf gi="10945" ue="37074" us="37074"/><bf gi="10946" ue="37077" us="37077"/><bf gi="10947" ue="37081" us="37079"/><bf gi="10950" ue="37087" us="37083"/><bf gi="10955" ue="37090" us="37089"/><bf gi="10957" ue="37093" us="37092"/><bf gi="10959" ue="37096" us="37096"/><bf gi="10960" ue="37099" us="37099"/><bf gi="10961" ue="37101" us="37101"/><bf gi="10962" ue="37104" us="37103"/><bf gi="10964" ue="37111" u!
 s="37108"/><bf gi="10968" ue="37120" us="37117"/><bf gi="10972" ue="37122" us="37122"/><bf gi="10973" ue="37126" us="37124"/><bf gi="10976" ue="37128" us="37128"/><bf gi="10977" ue="37133" us="37133"/><bf gi="10978" ue="37136" us="37136"/><bf gi="10979" ue="37138" us="37138"/><bf gi="10980" ue="37146" us="37140"/><bf gi="10987" ue="37148" us="37148"/><bf gi="10988" ue="37150" us="37150"/><bf gi="10989" ue="37152" us="37152"/><bf gi="10990" ue="37155" us="37154"/><bf gi="10992" ue="37157" us="37157"/><bf gi="10993" ue="37159" us="37159"/><bf gi="10994" ue="37161" us="37161"/><bf gi="10995" ue="37170" us="37165"/><bf gi="11001" ue="37172" us="37172"/><bf gi="11002" ue="37175" us="37174"/><bf gi="11004" ue="37178" us="37177"/><bf gi="11006" ue="37181" us="37180"/><bf gi="11008" ue="37187" us="37187"/><bf gi="11009" ue="37199" us="37191"/><bf gi="11018" ue="37204" us="37202"/><bf gi="11021" ue="37211" us="37206"/><bf gi="11027" ue="37221" us="37217"/><bf gi="11032" ue="37223" u!
 s="37223"/><bf gi="11033" ue="37226" us="37225"/><bf gi="11035" ue="37
229" us="37228"/><bf gi="11037" ue="37237" us="37234"/><bf gi="11041" ue="37243" us="37239"/><bf gi="11046" ue="37251" us="37249"/><bf gi="11049" ue="37255" us="37253"/><bf gi="11052" ue="37259" us="37257"/><bf gi="11055" ue="37262" us="37261"/><bf gi="11057" ue="37269" us="37264"/><bf gi="11063" ue="37272" us="37271"/><bf gi="11065" ue="37276" us="37276"/><bf gi="11066" ue="37278" us="37278"/><bf gi="11067" ue="37282" us="37281"/><bf gi="11069" ue="37284" us="37284"/><bf gi="11070" ue="37286" us="37286"/><bf gi="11071" ue="37288" us="37288"/><bf gi="11072" ue="37302" us="37290"/><bf gi="11085" ue="37304" us="37304"/><bf gi="11086" ue="37309" us="37306"/><bf gi="11090" ue="37315" us="37311"/><bf gi="11095" ue="37321" us="37317"/><bf gi="11100" ue="37329" us="37323"/><bf gi="11107" ue="37332" us="37331"/><bf gi="11109" ue="37343" us="37334"/><bf gi="11119" ue="37345" us="37345"/><bf gi="11120" ue="37351" us="37347"/><bf gi="11125" ue="37354" us="37353"/><bf gi="11127" ue="373!
 61" us="37356"/><bf gi="11133" ue="37367" us="37365"/><bf gi="11136" ue="37369" us="37369"/><bf gi="11137" ue="37373" us="37371"/><bf gi="11140" ue="37377" us="37375"/><bf gi="11143" ue="37383" us="37380"/><bf gi="11147" ue="37386" us="37385"/><bf gi="11149" ue="37390" us="37388"/><bf gi="11152" ue="37398" us="37392"/><bf gi="11159" ue="37400" us="37400"/><bf gi="11160" ue="37406" us="37404"/><bf gi="11163" ue="37414" us="37411"/><bf gi="11167" ue="37417" us="37416"/><bf gi="11169" ue="37420" us="37420"/><bf gi="11170" ue="37424" us="37422"/><bf gi="11173" ue="37434" us="37427"/><bf gi="11181" ue="37436" us="37436"/><bf gi="11182" ue="37440" us="37438"/><bf gi="11185" ue="37451" us="37442"/><bf gi="11195" ue="37457" us="37453"/><bf gi="11200" ue="37470" us="37463"/><bf gi="11208" ue="37474" us="37472"/><bf gi="11211" ue="37481" us="37476"/><bf gi="11217" ue="37489" us="37486"/><bf gi="11221" ue="37497" us="37493"/><bf gi="11226" ue="37504" us="37499"/><bf gi="11232" ue="375!
 07" us="37507"/><bf gi="11233" ue="37509" us="37509"/><bf gi="11234" u
e="37514" us="37512"/><bf gi="11237" ue="37518" us="37517"/><bf gi="11239" ue="37523" us="37521"/><bf gi="11242" ue="37532" us="37525"/><bf gi="11250" ue="37536" us="37535"/><bf gi="11252" ue="37541" us="37540"/><bf gi="11254" ue="37544" us="37543"/><bf gi="11256" ue="37547" us="37547"/><bf gi="11257" ue="37549" us="37549"/><bf gi="11258" ue="37551" us="37551"/><bf gi="11259" ue="37554" us="37554"/><bf gi="11260" ue="37565" us="37558"/><bf gi="11268" ue="37571" us="37567"/><bf gi="11273" ue="37576" us="37573"/><bf gi="11277" ue="37584" us="37579"/><bf gi="11283" ue="37587" us="37586"/><bf gi="11285" ue="37589" us="37589"/><bf gi="11286" ue="37593" us="37591"/><bf gi="11289" ue="37597" us="37596"/><bf gi="11291" ue="37601" us="37599"/><bf gi="11294" ue="37605" us="37603"/><bf gi="11297" ue="37610" us="37607"/><bf gi="11301" ue="37614" us="37612"/><bf gi="11304" ue="37616" us="37616"/><bf gi="11305" ue="37619" us="37618"/><bf gi="11307" ue="37628" us="37624"/><bf gi="11312" ue!
 ="37632" us="37631"/><bf gi="11314" ue="37634" us="37634"/><bf gi="11315" ue="37638" us="37638"/><bf gi="11316" ue="37640" us="37640"/><bf gi="11317" ue="37645" us="37645"/><bf gi="11318" ue="37649" us="37647"/><bf gi="11321" ue="37653" us="37652"/><bf gi="11323" ue="37658" us="37656"/><bf gi="11326" ue="37676" us="37660"/><bf gi="11343" ue="37679" us="37678"/><bf gi="11345" ue="37687" us="37682"/><bf gi="11351" ue="37691" us="37690"/><bf gi="11353" ue="37700" us="37700"/><bf gi="11354" ue="37705" us="37703"/><bf gi="11357" ue="37707" us="37707"/><bf gi="11358" ue="37709" us="37709"/><bf gi="11359" ue="37714" us="37712"/><bf gi="11362" ue="37720" us="37716"/><bf gi="11367" ue="37724" us="37722"/><bf gi="11370" ue="37726" us="37726"/><bf gi="11371" ue="37728" us="37728"/><bf gi="11372" ue="37733" us="37732"/><bf gi="11374" ue="37735" us="37735"/><bf gi="11375" ue="37738" us="37737"/><bf gi="11377" ue="37745" us="37740"/><bf gi="11383" ue="37750" us="37747"/><bf gi="11387" ue!
 ="37754" us="37754"/><bf gi="11388" ue="37762" us="37756"/><bf gi="113
95" ue="37768" us="37768"/><bf gi="11396" ue="37773" us="37770"/><bf gi="11400" ue="37775" us="37775"/><bf gi="11401" ue="37778" us="37778"/><bf gi="11402" ue="37784" us="37780"/><bf gi="11407" ue="37787" us="37786"/><bf gi="11409" ue="37790" us="37790"/><bf gi="11410" ue="37793" us="37793"/><bf gi="11411" ue="37796" us="37795"/><bf gi="11413" ue="37801" us="37798"/><bf gi="11417" ue="37806" us="37803"/><bf gi="11421" ue="37808" us="37808"/><bf gi="11422" ue="37814" us="37812"/><bf gi="11425" ue="37818" us="37817"/><bf gi="11427" ue="37825" us="37825"/><bf gi="11428" ue="37837" us="37827"/><bf gi="11439" ue="37841" us="37840"/><bf gi="11441" ue="37843" us="37843"/><bf gi="11442" ue="37849" us="37846"/><bf gi="11446" ue="37855" us="37852"/><bf gi="11450" ue="37858" us="37857"/><bf gi="11452" ue="37864" us="37860"/><bf gi="11457" ue="37883" us="37879"/><bf gi="11462" ue="37885" us="37885"/><bf gi="11463" ue="37892" us="37889"/><bf gi="11467" ue="37897" us="37895"/><bf gi="1147!
 0" ue="37904" us="37901"/><bf gi="11474" ue="37914" us="37907"/><bf gi="11482" ue="37919" us="37919"/><bf gi="11483" ue="37921" us="37921"/><bf gi="11484" ue="37931" us="37931"/><bf gi="11485" ue="37935" us="37934"/><bf gi="11487" ue="37942" us="37937"/><bf gi="11493" ue="37944" us="37944"/><bf gi="11494" ue="37947" us="37946"/><bf gi="11496" ue="37949" us="37949"/><bf gi="11497" ue="37951" us="37951"/><bf gi="11498" ue="37953" us="37953"/><bf gi="11499" ue="37957" us="37955"/><bf gi="11502" ue="37960" us="37960"/><bf gi="11503" ue="37962" us="37962"/><bf gi="11504" ue="37964" us="37964"/><bf gi="11505" ue="37971" us="37969"/><bf gi="11508" ue="37973" us="37973"/><bf gi="11509" ue="37980" us="37977"/><bf gi="11513" ue="37987" us="37982"/><bf gi="11519" ue="37992" us="37992"/><bf gi="11520" ue="37995" us="37994"/><bf gi="11522" ue="38002" us="37997"/><bf gi="11528" ue="38005" us="38005"/><bf gi="11529" ue="38007" us="38007"/><bf gi="11530" ue="38015" us="38012"/><bf gi="1153!
 4" ue="38017" us="38017"/><bf gi="11535" ue="38020" us="38019"/><bf gi
="11537" ue="38265" us="38263"/><bf gi="11540" ue="38270" us="38270"/><bf gi="11541" ue="38272" us="38272"/><bf gi="11542" ue="38276" us="38274"/><bf gi="11545" ue="38287" us="38279"/><bf gi="11554" ue="38292" us="38289"/><bf gi="11558" ue="38294" us="38294"/><bf gi="11559" ue="38297" us="38296"/><bf gi="11561" ue="38313" us="38301"/><bf gi="11574" ue="38317" us="38315"/><bf gi="11577" ue="38322" us="38322"/><bf gi="11578" ue="38324" us="38324"/><bf gi="11579" ue="38326" us="38326"/><bf gi="11580" ue="38335" us="38329"/><bf gi="11587" ue="38339" us="38339"/><bf gi="11588" ue="38349" us="38342"/><bf gi="11596" ue="38358" us="38352"/><bf gi="11603" ue="38362" us="38360"/><bf gi="11606" ue="38370" us="38364"/><bf gi="11613" ue="38374" us="38372"/><bf gi="11616" ue="38430" us="38428"/><bf gi="11619" ue="38434" us="38433"/><bf gi="11621" ue="38438" us="38436"/><bf gi="11624" ue="38440" us="38440"/><bf gi="11625" ue="38442" us="38442"/><bf gi="11626" ue="38444" us="38444"/><bf gi=!
 "11627" ue="38447" us="38446"/><bf gi="11629" ue="38451" us="38449"/><bf gi="11632" ue="38461" us="38455"/><bf gi="11639" ue="38466" us="38463"/><bf gi="11643" ue="38468" us="38468"/><bf gi="11644" ue="38477" us="38475"/><bf gi="11647" ue="38480" us="38479"/><bf gi="11649" ue="38482" us="38482"/><bf gi="11650" ue="38484" us="38484"/><bf gi="11651" ue="38488" us="38486"/><bf gi="11654" ue="38495" us="38491"/><bf gi="11659" ue="38502" us="38497"/><bf gi="11665" ue="38506" us="38506"/><bf gi="11666" ue="38508" us="38508"/><bf gi="11667" ue="38510" us="38510"/><bf gi="11668" ue="38512" us="38512"/><bf gi="11669" ue="38520" us="38514"/><bf gi="11676" ue="38527" us="38522"/><bf gi="11682" ue="38534" us="38529"/><bf gi="11688" ue="38539" us="38536"/><bf gi="11692" ue="38543" us="38541"/><bf gi="11695" ue="38545" us="38545"/><bf gi="11696" ue="38557" us="38548"/><bf gi="11706" ue="38560" us="38559"/><bf gi="11708" ue="38570" us="38563"/><bf gi="11716" ue="38580" us="38574"/><bf gi=!
 "11723" ue="38588" us="38582"/><bf gi="11730" ue="38593" us="38592"/><
bf gi="11732" ue="38599" us="38596"/><bf gi="11736" ue="38606" us="38601"/><bf gi="11742" ue="38610" us="38609"/><bf gi="11744" ue="38614" us="38613"/><bf gi="11746" ue="38623" us="38616"/><bf gi="11754" ue="38627" us="38626"/><bf gi="11756" ue="38635" us="38632"/><bf gi="11760" ue="38642" us="38639"/><bf gi="11764" ue="38647" us="38646"/><bf gi="11766" ue="38651" us="38649"/><bf gi="11769" ue="38656" us="38656"/><bf gi="11770" ue="38666" us="38658"/><bf gi="11779" ue="38671" us="38669"/><bf gi="11782" ue="38673" us="38673"/><bf gi="11783" ue="38675" us="38675"/><bf gi="11784" ue="38678" us="38678"/><bf gi="11785" ue="38686" us="38681"/><bf gi="11791" ue="38692" us="38689"/><bf gi="11795" ue="38696" us="38695"/><bf gi="11797" ue="38698" us="38698"/><bf gi="11798" ue="38707" us="38704"/><bf gi="11802" ue="38713" us="38712"/><bf gi="11804" ue="38715" us="38715"/><bf gi="11805" ue="38718" us="38717"/><bf gi="11807" ue="38724" us="38721"/><bf gi="11811" ue="38726" us="38726"/><b!
 f gi="11812" ue="38730" us="38728"/><bf gi="11815" ue="38735" us="38733"/><bf gi="11818" ue="38738" us="38737"/><bf gi="11820" ue="38748" us="38741"/><bf gi="11828" ue="38750" us="38750"/><bf gi="11829" ue="38756" us="38752"/><bf gi="11834" ue="38763" us="38758"/><bf gi="11840" ue="38766" us="38765"/><bf gi="11842" ue="38769" us="38769"/><bf gi="11843" ue="38772" us="38771"/><bf gi="11845" ue="38781" us="38774"/><bf gi="11853" ue="38785" us="38783"/><bf gi="11856" ue="38790" us="38788"/><bf gi="11859" ue="38793" us="38793"/><bf gi="11860" ue="38795" us="38795"/><bf gi="11861" ue="38797" us="38797"/><bf gi="11862" ue="38800" us="38799"/><bf gi="11864" ue="38810" us="38805"/><bf gi="11870" ue="38812" us="38812"/><bf gi="11871" ue="38816" us="38814"/><bf gi="11874" ue="38819" us="38818"/><bf gi="11876" ue="38822" us="38822"/><bf gi="11877" ue="38824" us="38824"/><bf gi="11878" ue="38830" us="38827"/><bf gi="11882" ue="38838" us="38833"/><bf gi="11888" ue="38842" us="38840"/><b!
 f gi="11891" ue="38844" us="38844"/><bf gi="11892" ue="38847" us="3884
6"/><bf gi="11894" ue="38849" us="38849"/><bf gi="11895" ue="38862" us="38851"/><bf gi="11907" ue="38865" us="38864"/><bf gi="11909" ue="38868" us="38867"/><bf gi="11911" ue="38873" us="38871"/><bf gi="11914" ue="38878" us="38875"/><bf gi="11918" ue="38881" us="38880"/><bf gi="11920" ue="38884" us="38884"/><bf gi="11921" ue="38895" us="38893"/><bf gi="11924" ue="38904" us="38897"/><bf gi="11932" ue="38907" us="38906"/><bf gi="11934" ue="38911" us="38911"/><bf gi="11935" ue="38915" us="38913"/><bf gi="11938" ue="38920" us="38917"/><bf gi="11942" ue="38922" us="38922"/><bf gi="11943" ue="38932" us="38924"/><bf gi="11952" ue="38938" us="38934"/><bf gi="11957" ue="38940" us="38940"/><bf gi="11958" ue="38942" us="38942"/><bf gi="11959" ue="38945" us="38944"/><bf gi="11961" ue="38950" us="38947"/><bf gi="11965" ue="38960" us="38955"/><bf gi="11971" ue="38965" us="38962"/><bf gi="11975" ue="38968" us="38967"/><bf gi="11977" ue="38974" us="38971"/><bf gi="11981" ue="38980" us="38980!
 "/><bf gi="11982" ue="38983" us="38982"/><bf gi="11984" ue="38991" us="38986"/><bf gi="11990" ue="39003" us="38993"/><bf gi="12001" ue="39006" us="39006"/><bf gi="12002" ue="39011" us="39010"/><bf gi="12004" ue="39015" us="39013"/><bf gi="12007" ue="39020" us="39018"/><bf gi="12010" ue="39025" us="39023"/><bf gi="12013" ue="39028" us="39027"/><bf gi="12015" ue="39080" us="39080"/><bf gi="12016" ue="39083" us="39082"/><bf gi="12018" ue="39089" us="39085"/><bf gi="12023" ue="39092" us="39092"/><bf gi="12024" ue="39096" us="39094"/><bf gi="12027" ue="39099" us="39098"/><bf gi="12029" ue="39103" us="39103"/><bf gi="12030" ue="39110" us="39106"/><bf gi="12035" ue="39112" us="39112"/><bf gi="12036" ue="39116" us="39116"/><bf gi="12037" ue="39132" us="39131"/><bf gi="12039" ue="39135" us="39135"/><bf gi="12040" ue="39139" us="39137"/><bf gi="12043" ue="39143" us="39141"/><bf gi="12046" ue="39147" us="39145"/><bf gi="12049" ue="39151" us="39149"/><bf gi="12052" ue="39156" us="39154!
 "/><bf gi="12055" ue="39158" us="39158"/><bf gi="12056" ue="39166" us=
"39164"/><bf gi="12059" ue="39171" us="39170"/><bf gi="12061" ue="39173" us="39173"/><bf gi="12062" ue="39178" us="39175"/><bf gi="12066" ue="39180" us="39180"/><bf gi="12067" ue="39192" us="39184"/><bf gi="12076" ue="39202" us="39194"/><bf gi="12085" ue="39204" us="39204"/><bf gi="12086" ue="39208" us="39206"/><bf gi="12089" ue="39212" us="39211"/><bf gi="12091" ue="39214" us="39214"/><bf gi="12092" ue="39221" us="39217"/><bf gi="12097" ue="39230" us="39225"/><bf gi="12103" ue="39234" us="39232"/><bf gi="12106" ue="39241" us="39237"/><bf gi="12111" ue="39246" us="39243"/><bf gi="12115" ue="39250" us="39248"/><bf gi="12118" ue="39253" us="39252"/><bf gi="12120" ue="39257" us="39255"/><bf gi="12123" ue="39260" us="39259"/><bf gi="12125" ue="39264" us="39262"/><bf gi="12128" ue="39321" us="39318"/><bf gi="12132" ue="39323" us="39323"/><bf gi="12133" ue="39327" us="39325"/><bf gi="12136" ue="39334" us="39333"/><bf gi="12138" ue="39336" us="39336"/><bf gi="12139" ue="39342" us="!
 39340"/><bf gi="12142" ue="39349" us="39344"/><bf gi="12148" ue="39354" us="39353"/><bf gi="12150" ue="39357" us="39356"/><bf gi="12152" ue="39359" us="39359"/><bf gi="12153" ue="39361" us="39361"/><bf gi="12154" ue="39366" us="39363"/><bf gi="12158" ue="39369" us="39368"/><bf gi="12160" ue="39381" us="39376"/><bf gi="12166" ue="39391" us="39384"/><bf gi="12174" ue="39394" us="39394"/><bf gi="12175" ue="39399" us="39399"/><bf gi="12176" ue="39406" us="39402"/><bf gi="12181" ue="39410" us="39408"/><bf gi="12184" ue="39413" us="39412"/><bf gi="12186" ue="39417" us="39416"/><bf gi="12188" ue="39419" us="39419"/><bf gi="12189" ue="39423" us="39421"/><bf gi="12192" ue="39429" us="39425"/><bf gi="12197" ue="39436" us="39435"/><bf gi="12199" ue="39443" us="39438"/><bf gi="12205" ue="39446" us="39446"/><bf gi="12206" ue="39449" us="39449"/><bf gi="12207" ue="39454" us="39454"/><bf gi="12208" ue="39456" us="39456"/><bf gi="12209" ue="39460" us="39458"/><bf gi="12212" ue="39464" us="!
 39463"/><bf gi="12214" ue="39467" us="39467"/><bf gi="12215" ue="39470
" us="39469"/><bf gi="12217" ue="39472" us="39472"/><bf gi="12218" ue="39475" us="39475"/><bf gi="12219" ue="39480" us="39477"/><bf gi="12223" ue="39486" us="39486"/><bf gi="12224" ue="39493" us="39488"/><bf gi="12230" ue="39495" us="39495"/><bf gi="12231" ue="39502" us="39498"/><bf gi="12236" ue="39505" us="39505"/><bf gi="12237" ue="39511" us="39508"/><bf gi="12241" ue="39515" us="39514"/><bf gi="12243" ue="39517" us="39517"/><bf gi="12244" ue="39519" us="39519"/><bf gi="12245" ue="39522" us="39522"/><bf gi="12246" ue="39525" us="39524"/><bf gi="12248" ue="39531" us="39529"/><bf gi="12251" ue="39592" us="39592"/><bf gi="12252" ue="39594" us="39594"/><bf gi="12253" ue="39600" us="39596"/><bf gi="12258" ue="39602" us="39602"/><bf gi="12259" ue="39606" us="39604"/><bf gi="12262" ue="39609" us="39608"/><bf gi="12264" ue="39612" us="39611"/><bf gi="12266" ue="39617" us="39614"/><bf gi="12270" ue="39620" us="39619"/><bf gi="12272" ue="39622" us="39622"/><bf gi="12273" ue="39624"!
  us="39624"/><bf gi="12274" ue="39641" us="39630"/><bf gi="12286" ue="39644" us="39643"/><bf gi="12288" ue="39648" us="39646"/><bf gi="12291" ue="39655" us="39650"/><bf gi="12297" ue="39663" us="39657"/><bf gi="12304" ue="39669" us="39665"/><bf gi="12309" ue="39671" us="39671"/><bf gi="12310" ue="39675" us="39673"/><bf gi="12313" ue="39677" us="39677"/><bf gi="12314" ue="39686" us="39679"/><bf gi="12322" ue="39689" us="39688"/><bf gi="12324" ue="39694" us="39691"/><bf gi="12328" ue="39696" us="39696"/><bf gi="12329" ue="39698" us="39698"/><bf gi="12330" ue="39702" us="39702"/><bf gi="12331" ue="39708" us="39704"/><bf gi="12336" ue="39712" us="39711"/><bf gi="12338" ue="39715" us="39714"/><bf gi="12340" ue="39723" us="39717"/><bf gi="12347" ue="39727" us="39725"/><bf gi="12350" ue="39733" us="39729"/><bf gi="12355" ue="39735" us="39735"/><bf gi="12356" ue="39741" us="39737"/><bf gi="12361" ue="39749" us="39745"/><bf gi="12366" ue="39752" us="39752"/><bf gi="12367" ue="39759"!
  us="39755"/><bf gi="12372" ue="39761" us="39761"/><bf gi="12373" ue="
39768" us="39764"/><bf gi="12378" ue="39771" us="39770"/><bf gi="12380" ue="39774" us="39774"/><bf gi="12381" ue="39777" us="39777"/><bf gi="12382" ue="39779" us="39779"/><bf gi="12383" ue="39782" us="39781"/><bf gi="12385" ue="39784" us="39784"/><bf gi="12386" ue="39791" us="39786"/><bf gi="12392" ue="39797" us="39794"/><bf gi="12396" ue="39801" us="39799"/><bf gi="12399" ue="39808" us="39807"/><bf gi="12401" ue="39815" us="39811"/><bf gi="12406" ue="39819" us="39817"/><bf gi="12409" ue="39828" us="39821"/><bf gi="12417" ue="39831" us="39830"/><bf gi="12419" ue="39834" us="39834"/><bf gi="12420" ue="39840" us="39837"/><bf gi="12424" ue="39854" us="39846"/><bf gi="12433" ue="39858" us="39856"/><bf gi="12436" ue="39860" us="39860"/><bf gi="12437" ue="39865" us="39863"/><bf gi="12440" ue="39868" us="39867"/><bf gi="12442" ue="39873" us="39870"/><bf gi="12446" ue="39882" us="39878"/><bf gi="12451" ue="39890" us="39886"/><bf gi="12456" ue="39892" us="39892"/><bf gi="12457" ue="3!
 9896" us="39894"/><bf gi="12460" ue="39899" us="39899"/><bf gi="12461" ue="39901" us="39901"/><bf gi="12462" ue="39903" us="39903"/><bf gi="12463" ue="39909" us="39905"/><bf gi="12468" ue="39912" us="39911"/><bf gi="12470" ue="39915" us="39914"/><bf gi="12472" ue="39923" us="39919"/><bf gi="12477" ue="39925" us="39925"/><bf gi="12478" ue="39930" us="39927"/><bf gi="12482" ue="39933" us="39933"/><bf gi="12483" ue="39936" us="39935"/><bf gi="12485" ue="39938" us="39938"/><bf gi="12486" ue="39940" us="39940"/><bf gi="12487" ue="39942" us="39942"/><bf gi="12488" ue="39949" us="39944"/><bf gi="12494" ue="39958" us="39951"/><bf gi="12502" ue="39964" us="39960"/><bf gi="12507" ue="39966" us="39966"/><bf gi="12508" ue="39978" us="39969"/><bf gi="12518" ue="39986" us="39981"/><bf gi="12524" ue="39991" us="39989"/><bf gi="12527" ue="39995" us="39993"/><bf gi="12530" ue="39998" us="39997"/><bf gi="12532" ue="40001" us="40001"/><bf gi="12533" ue="40010" us="40003"/><bf gi="12541" ue="4!
 0016" us="40014"/><bf gi="12544" ue="40020" us="40018"/><bf gi="12547"
 ue="40024" us="40022"/><bf gi="12550" ue="40032" us="40026"/><bf gi="12557" ue="40035" us="40035"/><bf gi="12558" ue="40043" us="40039"/><bf gi="12563" ue="40046" us="40046"/><bf gi="12564" ue="40048" us="40048"/><bf gi="12565" ue="40050" us="40050"/><bf gi="12566" ue="40056" us="40053"/><bf gi="12570" ue="40059" us="40059"/><bf gi="12571" ue="40167" us="40165"/><bf gi="12574" ue="40169" us="40169"/><bf gi="12575" ue="40172" us="40171"/><bf gi="12577" ue="40176" us="40176"/><bf gi="12578" ue="40180" us="40178"/><bf gi="12581" ue="40183" us="40182"/><bf gi="12583" ue="40185" us="40185"/><bf gi="12584" ue="40195" us="40194"/><bf gi="12586" ue="40201" us="40198"/><bf gi="12590" ue="40203" us="40203"/><bf gi="12591" ue="40206" us="40206"/><bf gi="12592" ue="40210" us="40209"/><bf gi="12594" ue="40213" us="40213"/><bf gi="12595" ue="40216" us="40215"/><bf gi="12597" ue="40223" us="40219"/><bf gi="12602" ue="40227" us="40227"/><bf gi="12603" ue="40230" us="40230"/><bf gi="12604" !
 ue="40232" us="40232"/><bf gi="12605" ue="40236" us="40234"/><bf gi="12608" ue="40240" us="40239"/><bf gi="12610" ue="40244" us="40242"/><bf gi="12613" ue="40255" us="40250"/><bf gi="12619" ue="40264" us="40257"/><bf gi="12627" ue="40266" us="40266"/><bf gi="12628" ue="40273" us="40272"/><bf gi="12630" ue="40276" us="40275"/><bf gi="12632" ue="40281" us="40281"/><bf gi="12633" ue="40293" us="40284"/><bf gi="12643" ue="40300" us="40297"/><bf gi="12647" ue="40304" us="40303"/><bf gi="12649" ue="40306" us="40306"/><bf gi="12650" ue="40311" us="40310"/><bf gi="12652" ue="40316" us="40314"/><bf gi="12655" ue="40318" us="40318"/><bf gi="12656" ue="40324" us="40323"/><bf gi="12658" ue="40327" us="40326"/><bf gi="12660" ue="40330" us="40329"/><bf gi="12662" ue="40335" us="40333"/><bf gi="12665" ue="40339" us="40338"/><bf gi="12667" ue="40344" us="40341"/><bf gi="12671" ue="40346" us="40346"/><bf gi="12672" ue="40353" us="40353"/><bf gi="12673" ue="40356" us="40356"/><bf gi="12674" !
 ue="40364" us="40361"/><bf gi="12678" ue="40367" us="40366"/><bf gi="1
2680" ue="40370" us="40369"/><bf gi="12682" ue="40373" us="40372"/><bf gi="12684" ue="40380" us="40376"/><bf gi="12689" ue="40383" us="40383"/><bf gi="12690" ue="40388" us="40385"/><bf gi="12694" ue="40391" us="40390"/><bf gi="12696" ue="40394" us="40393"/><bf gi="12698" ue="40399" us="40399"/><bf gi="12699" ue="40407" us="40403"/><bf gi="12704" ue="40410" us="40409"/><bf gi="12706" ue="40416" us="40414"/><bf gi="12709" ue="40423" us="40421"/><bf gi="12712" ue="40425" us="40425"/><bf gi="12713" ue="40427" us="40427"/><bf gi="12714" ue="40432" us="40429"/><bf gi="12718" ue="40436" us="40434"/><bf gi="12721" ue="40442" us="40440"/><bf gi="12724" ue="40446" us="40445"/><bf gi="12726" ue="40450" us="40450"/><bf gi="12727" ue="40455" us="40455"/><bf gi="12728" ue="40458" us="40458"/><bf gi="12729" ue="40462" us="40462"/><bf gi="12730" ue="40466" us="40464"/><bf gi="12733" ue="40470" us="40469"/><bf gi="12735" ue="40478" us="40473"/><bf gi="12741" ue="40565" us="40565"/><bf gi="12!
 742" ue="40573" us="40568"/><bf gi="12748" ue="40581" us="40575"/><bf gi="12755" ue="40584" us="40583"/><bf gi="12757" ue="40588" us="40587"/><bf gi="12759" ue="40591" us="40590"/><bf gi="12761" ue="40595" us="40593"/><bf gi="12764" ue="40600" us="40597"/><bf gi="12768" ue="40603" us="40603"/><bf gi="12769" ue="40607" us="40605"/><bf gi="12772" ue="40614" us="40612"/><bf gi="12775" ue="40618" us="40616"/><bf gi="12778" ue="40624" us="40620"/><bf gi="12783" ue="40629" us="40627"/><bf gi="12786" ue="40636" us="40632"/><bf gi="12791" ue="40639" us="40638"/><bf gi="12793" ue="40644" us="40644"/><bf gi="12794" ue="40646" us="40646"/><bf gi="12795" ue="40648" us="40648"/><bf gi="12796" ue="40658" us="40651"/><bf gi="12804" ue="40661" us="40660"/><bf gi="12806" ue="40665" us="40664"/><bf gi="12808" ue="40672" us="40667"/><bf gi="12814" ue="40677" us="40676"/><bf gi="12816" ue="40680" us="40679"/><bf gi="12818" ue="40690" us="40684"/><bf gi="12825" ue="40697" us="40692"/><bf gi="12!
 831" ue="40701" us="40699"/><bf gi="12834" ue="40703" us="40703"/><bf 
gi="12835" ue="40707" us="40706"/><bf gi="12837" ue="40713" us="40711"/><bf gi="12840" ue="40727" us="40718"/><bf gi="12850" ue="40731" us="40729"/><bf gi="12853" ue="40738" us="40735"/><bf gi="12857" ue="40742" us="40742"/><bf gi="12858" ue="40748" us="40746"/><bf gi="12861" ue="40751" us="40751"/><bf gi="12862" ue="40754" us="40753"/><bf gi="12864" ue="40756" us="40756"/><bf gi="12865" ue="40759" us="40759"/><bf gi="12866" ue="40767" us="40761"/><bf gi="12873" ue="40769" us="40769"/><bf gi="12874" ue="40775" us="40771"/><bf gi="12879" ue="40779" us="40778"/><bf gi="12881" ue="40783" us="40782"/><bf gi="12883" ue="40792" us="40786"/><bf gi="12890" ue="40794" us="40794"/><bf gi="12891" ue="40803" us="40797"/><bf gi="12898" ue="40810" us="40806"/><bf gi="12903" ue="40819" us="40812"/><bf gi="12911" ue="40823" us="40821"/><bf gi="12914" ue="40826" us="40826"/><bf gi="12915" ue="40829" us="40829"/><bf gi="12916" ue="40845" us="40845"/><bf gi="12917" ue="40850" us="40847"/><bf g!
 i="12921" ue="40855" us="40852"/><bf gi="12925" ue="40862" us="40860"/><bf gi="12928" ue="40867" us="40864"/><bf gi="12932" ue="40869" us="40869"/><bf gi="12933" ue="63785" us="63785"/><bf gi="12934" ue="63964" us="63964"/><bf gi="12935" ue="64045" us="64014"/><bf gi="12967" ue="65374" us="65281"/><bf gi="13061" ue="65439" us="65377"/><bf gi="13124" ue="65507" us="65504"/><bf gi="13128" ue="65509" us="65509"/><bf gi="0" ue="65535" us="65535"/></bfranges><cid-widths start-index="0"><wx w="1000"/><wx w="0"/><wx w="333"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="50!
 0"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><
wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="446"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="490"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="50!
 0"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="875"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="812"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w=!
 "500"/><wx w="500"/><wx w="500"/><wx w="875"/><wx w="875"/><wx w="500"
/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="915"/><wx w="1000"/><wx w="1000"/><wx w="915"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="765"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="915"/><wx w="1000"/><wx w="1000"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="915"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="915"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="915"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="976"/><wx w="976"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="915"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="976"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="976"/><wx w="976"/><wx w="976"/><wx w="976"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><!
 wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="1000"/><wx w="915"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx !
 w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="50
0"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/></cid-widths></multibyte-extras></fo!
 nt-metrics>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/sazanami-mincho.ttf
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/sazanami-mincho.ttf
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/sazanami-mincho.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/sazanami-mincho.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/sazanami-mincho.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="utf-8"?><font-metrics type="TYPE0"><font-name>SazanamiMincho,Mincho-Regular</font-name><embed/><cap-height>0</cap-height><x-height>0</x-height><ascender>973</ascender><descender>-156</descender><bbox><left>-50</left><bottom>-156</bottom><right>1250</right><top>973</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><ttc-name>Sazanami Mincho</ttc-name><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="0" ue="0" us="0"/><bf gi="3" ue="126" us="32"/><bf gi="98" ue="383" us="160"/><bf gi="322" ue="402" us="402"/><bf gi="323" ue="476" us="461"/><bf gi="339" ue="501" us="501"/><bf gi="340" ue="511" us="506"/><bf gi="346" ue="680" us="592"/><bf gi="435" ue="711" us="710"/><bf gi="437" ue="715" us="713"/><bf gi="440" ue="733" us="728"/><bf gi="446" ue="885" us="884"/><bf gi="448" ue="890" us="890"/><bf gi="449" ue="894" us="894"/><bf gi="450" ue="906" us="900!
 "/><bf gi="457" ue="908" us="908"/><bf gi="458" ue="929" us="910"/><bf gi="478" ue="974" us="931"/><bf gi="522" ue="977" us="976"/><bf gi="524" ue="981" us="981"/><bf gi="525" ue="1013" us="1013"/><bf gi="526" ue="1036" us="1025"/><bf gi="538" ue="1103" us="1038"/><bf gi="604" ue="1116" us="1105"/><bf gi="616" ue="1158" us="1118"/><bf gi="657" ue="1220" us="1168"/><bf gi="710" ue="1224" us="1223"/><bf gi="712" ue="1228" us="1227"/><bf gi="714" ue="1259" us="1232"/><bf gi="742" ue="1269" us="1262"/><bf gi="750" ue="1273" us="1272"/><bf gi="752" ue="7813" us="7808"/><bf gi="758" ue="7923" us="7922"/><bf gi="760" ue="8238" us="8192"/><bf gi="807" ue="8262" us="8240"/><bf gi="830" ue="8304" us="8304"/><bf gi="831" ue="8334" us="8308"/><bf gi="858" ue="8362" us="8352"/><bf gi="869" ue="8364" us="8364"/><bf gi="870" ue="8504" us="8448"/><bf gi="927" ue="8578" us="8531"/><bf gi="975" ue="8682" us="8592"/><bf gi="1066" ue="8945" us="8704"/><bf gi="1308" ue="8962" us="8962"/><bf gi=!
 "1309" ue="8967" us="8967"/><bf gi="1310" ue="8976" us="8976"/><bf gi=
"1311" ue="8978" us="8978"/><bf gi="1312" ue="8993" us="8992"/><bf gi="1314" ue="9450" us="9312"/><bf gi="1453" ue="9621" us="9472"/><bf gi="1603" ue="9711" us="9632"/><bf gi="1683" ue="9747" us="9728"/><bf gi="1703" ue="9839" us="9754"/><bf gi="1789" ue="9988" us="9985"/><bf gi="1793" ue="9993" us="9990"/><bf gi="1797" ue="10023" us="9996"/><bf gi="1825" ue="10059" us="10025"/><bf gi="1860" ue="10061" us="10061"/><bf gi="1861" ue="10066" us="10063"/><bf gi="1865" ue="10070" us="10070"/><bf gi="1866" ue="10078" us="10072"/><bf gi="1873" ue="10087" us="10081"/><bf gi="1880" ue="10132" us="10102"/><bf gi="1911" ue="10159" us="10136"/><bf gi="1935" ue="10174" us="10161"/><bf gi="1949" ue="12319" us="12288"/><bf gi="1981" ue="12336" us="12336"/><bf gi="1982" ue="12341" us="12339"/><bf gi="1985" ue="12438" us="12353"/><bf gi="2071" ue="12447" us="12443"/><bf gi="2076" ue="12542" us="12449"/><bf gi="2170" ue="12850" us="12849"/><bf gi="2172" ue="12857" us="12857"/><bf gi="2173" ue!
 ="12968" us="12964"/><bf gi="2178" ue="13059" us="13059"/><bf gi="2179" ue="13069" us="13069"/><bf gi="2180" ue="13076" us="13076"/><bf gi="2181" ue="13080" us="13080"/><bf gi="2182" ue="13091" us="13090"/><bf gi="2184" ue="13095" us="13094"/><bf gi="2186" ue="13099" us="13099"/><bf gi="2187" ue="13110" us="13110"/><bf gi="2188" ue="13115" us="13115"/><bf gi="2189" ue="13130" us="13129"/><bf gi="2191" ue="13133" us="13133"/><bf gi="2192" ue="13137" us="13137"/><bf gi="2193" ue="13143" us="13143"/><bf gi="2194" ue="13182" us="13179"/><bf gi="2198" ue="13199" us="13198"/><bf gi="2200" ue="13214" us="13212"/><bf gi="2203" ue="13217" us="13217"/><bf gi="2204" ue="13252" us="13252"/><bf gi="2205" ue="13259" us="13259"/><bf gi="2206" ue="13261" us="13261"/><bf gi="2207" ue="19973" us="19968"/><bf gi="2213" ue="19982" us="19975"/><bf gi="2221" ue="19986" us="19984"/><bf gi="2224" ue="19993" us="19988"/><bf gi="2230" ue="19999" us="19998"/><bf gi="2232" ue="20001" us="20001"/><bf g!
 i="2233" ue="20004" us="20003"/><bf gi="2235" ue="20006" us="20006"/><
bf gi="2236" ue="20008" us="20008"/><bf gi="2237" ue="20011" us="20010"/><bf gi="2239" ue="20018" us="20013"/><bf gi="2245" ue="20022" us="20021"/><bf gi="2247" ue="20025" us="20024"/><bf gi="2249" ue="20028" us="20027"/><bf gi="2251" ue="20037" us="20031"/><bf gi="2258" ue="20039" us="20039"/><bf gi="2259" ue="20043" us="20043"/><bf gi="2260" ue="20047" us="20045"/><bf gi="2263" ue="20049" us="20049"/><bf gi="2264" ue="20058" us="20053"/><bf gi="2270" ue="20063" us="20060"/><bf gi="2274" ue="20067" us="20066"/><bf gi="2276" ue="20073" us="20072"/><bf gi="2278" ue="20081" us="20081"/><bf gi="2279" ue="20085" us="20083"/><bf gi="2282" ue="20089" us="20089"/><bf gi="2283" ue="20096" us="20094"/><bf gi="2286" ue="20098" us="20098"/><bf gi="2287" ue="20102" us="20101"/><bf gi="2289" ue="20110" us="20104"/><bf gi="2296" ue="20114" us="20113"/><bf gi="2298" ue="20121" us="20116"/><bf gi="2304" ue="20130" us="20123"/><bf gi="2312" ue="20134" us="20132"/><bf gi="2315" ue="20136" us=!
 "20136"/><bf gi="2316" ue="20144" us="20139"/><bf gi="2322" ue="20147" us="20147"/><bf gi="2323" ue="20150" us="20150"/><bf gi="2324" ue="20154" us="20153"/><bf gi="2326" ue="20164" us="20160"/><bf gi="2331" ue="20167" us="20166"/><bf gi="2333" ue="20171" us="20170"/><bf gi="2335" ue="20176" us="20173"/><bf gi="2339" ue="20187" us="20180"/><bf gi="2347" ue="20197" us="20189"/><bf gi="2356" ue="20200" us="20200"/><bf gi="2357" ue="20211" us="20205"/><bf gi="2364" ue="20215" us="20213"/><bf gi="2367" ue="20227" us="20219"/><bf gi="2376" ue="20242" us="20232"/><bf gi="2387" ue="20247" us="20245"/><bf gi="2390" ue="20250" us="20249"/><bf gi="2392" ue="20253" us="20252"/><bf gi="2394" ue="20273" us="20270"/><bf gi="2398" ue="20286" us="20275"/><bf gi="2410" ue="20288" us="20288"/><bf gi="2411" ue="20291" us="20290"/><bf gi="2413" ue="20297" us="20294"/><bf gi="2417" ue="20320" us="20299"/><bf gi="2439" ue="20323" us="20323"/><bf gi="2440" ue="20330" us="20329"/><bf gi="2442" ue=!
 "20332" us="20332"/><bf gi="2443" ue="20337" us="20334"/><bf gi="2447"
 ue="20339" us="20339"/><bf gi="2448" ue="20351" us="20341"/><bf gi="2459" ue="20358" us="20353"/><bf gi="2465" ue="20372" us="20360"/><bf gi="2478" ue="20379" us="20374"/><bf gi="2484" ue="20385" us="20381"/><bf gi="2489" ue="20395" us="20395"/><bf gi="2490" ue="20399" us="20397"/><bf gi="2493" ue="20402" us="20402"/><bf gi="2494" ue="20407" us="20405"/><bf gi="2497" ue="20409" us="20409"/><bf gi="2498" ue="20422" us="20411"/><bf gi="2510" ue="20434" us="20424"/><bf gi="2521" ue="20436" us="20436"/><bf gi="2522" ue="20440" us="20439"/><bf gi="2524" ue="20445" us="20442"/><bf gi="2528" ue="20453" us="20447"/><bf gi="2535" ue="20464" us="20462"/><bf gi="2538" ue="20467" us="20466"/><bf gi="2540" ue="20470" us="20469"/><bf gi="2542" ue="20472" us="20472"/><bf gi="2543" ue="20474" us="20474"/><bf gi="2544" ue="20481" us="20476"/><bf gi="2550" ue="20487" us="20484"/><bf gi="2554" ue="20500" us="20489"/><bf gi="2566" ue="20511" us="20502"/><bf gi="2576" ue="20526" us="20513"/><bf!
  gi="2590" ue="20528" us="20528"/><bf gi="2591" ue="20531" us="20530"/><bf gi="2593" ue="20534" us="20533"/><bf gi="2595" ue="20537" us="20537"/><bf gi="2596" ue="20539" us="20539"/><bf gi="2597" ue="20547" us="20544"/><bf gi="2601" ue="20554" us="20549"/><bf gi="2607" ue="20556" us="20556"/><bf gi="2608" ue="20563" us="20558"/><bf gi="2614" ue="20567" us="20565"/><bf gi="2617" ue="20570" us="20569"/><bf gi="2619" ue="20572" us="20572"/><bf gi="2620" ue="20576" us="20575"/><bf gi="2622" ue="20579" us="20578"/><bf gi="2624" ue="20583" us="20581"/><bf gi="2627" ue="20586" us="20586"/><bf gi="2628" ue="20589" us="20588"/><bf gi="2630" ue="20594" us="20592"/><bf gi="2633" ue="20598" us="20596"/><bf gi="2636" ue="20600" us="20600"/><bf gi="2637" ue="20605" us="20605"/><bf gi="2638" ue="20609" us="20608"/><bf gi="2640" ue="20614" us="20611"/><bf gi="2644" ue="20618" us="20618"/><bf gi="2645" ue="20628" us="20621"/><bf gi="2653" ue="20630" us="20630"/><bf gi="2654" ue="20636" us="!
 20632"/><bf gi="2659" ue="20642" us="20638"/><bf gi="2664" ue="20650" 
us="20650"/><bf gi="2665" ue="20653" us="20652"/><bf gi="2667" ue="20656" us="20655"/><bf gi="2669" ue="20661" us="20658"/><bf gi="2673" ue="20663" us="20663"/><bf gi="2674" ue="20666" us="20665"/><bf gi="2676" ue="20670" us="20669"/><bf gi="2678" ue="20672" us="20672"/><bf gi="2679" ue="20677" us="20674"/><bf gi="2683" ue="20679" us="20679"/><bf gi="2684" ue="20682" us="20681"/><bf gi="2686" ue="20689" us="20684"/><bf gi="2692" ue="20694" us="20691"/><bf gi="2696" ue="20696" us="20696"/><bf gi="2697" ue="20698" us="20698"/><bf gi="2698" ue="20703" us="20700"/><bf gi="2702" ue="20713" us="20706"/><bf gi="2710" ue="20719" us="20717"/><bf gi="2713" ue="20722" us="20721"/><bf gi="2715" ue="20726" us="20724"/><bf gi="2718" ue="20731" us="20729"/><bf gi="2721" ue="20734" us="20734"/><bf gi="2722" ue="20740" us="20736"/><bf gi="2727" ue="20745" us="20742"/><bf gi="2731" ue="20750" us="20747"/><bf gi="2735" ue="20752" us="20752"/><bf gi="2736" ue="20754" us="20754"/><bf gi="2737" u!
 e="20767" us="20756"/><bf gi="2749" ue="20769" us="20769"/><bf gi="2750" ue="20771" us="20771"/><bf gi="2751" ue="20776" us="20775"/><bf gi="2753" ue="20778" us="20778"/><bf gi="2754" ue="20781" us="20780"/><bf gi="2756" ue="20783" us="20783"/><bf gi="2757" ue="20789" us="20785"/><bf gi="2762" ue="20796" us="20791"/><bf gi="2768" ue="20816" us="20799"/><bf gi="2786" ue="20821" us="20818"/><bf gi="2790" ue="20824" us="20823"/><bf gi="2792" ue="20826" us="20826"/><bf gi="2793" ue="20828" us="20828"/><bf gi="2794" ue="20831" us="20831"/><bf gi="2795" ue="20834" us="20834"/><bf gi="2796" ue="20838" us="20836"/><bf gi="2799" ue="20846" us="20840"/><bf gi="2806" ue="20849" us="20849"/><bf gi="2807" ue="20856" us="20853"/><bf gi="2811" ue="20860" us="20860"/><bf gi="2812" ue="20862" us="20862"/><bf gi="2813" ue="20864" us="20864"/><bf gi="2814" ue="20870" us="20866"/><bf gi="2819" ue="20883" us="20873"/><bf gi="2830" ue="20889" us="20885"/><bf gi="2835" ue="20893" us="20893"/><bf !
 gi="2836" ue="20902" us="20896"/><bf gi="2843" ue="20909" us="20904"/>
<bf gi="2849" ue="20920" us="20912"/><bf gi="2858" ue="20922" us="20922"/><bf gi="2859" ue="20927" us="20924"/><bf gi="2863" ue="20930" us="20930"/><bf gi="2864" ue="20934" us="20932"/><bf gi="2867" ue="20937" us="20936"/><bf gi="2869" ue="20941" us="20939"/><bf gi="2872" ue="20943" us="20943"/><bf gi="2873" ue="20947" us="20945"/><bf gi="2876" ue="20950" us="20949"/><bf gi="2878" ue="20952" us="20952"/><bf gi="2879" ue="20958" us="20955"/><bf gi="2883" ue="20962" us="20960"/><bf gi="2886" ue="20967" us="20965"/><bf gi="2889" ue="20970" us="20969"/><bf gi="2891" ue="20974" us="20972"/><bf gi="2894" ue="20986" us="20976"/><bf gi="2905" ue="20990" us="20989"/><bf gi="2907" ue="21000" us="20992"/><bf gi="2916" ue="21003" us="21002"/><bf gi="2918" ue="21006" us="21006"/><bf gi="2919" ue="21016" us="21009"/><bf gi="2927" ue="21021" us="21021"/><bf gi="2928" ue="21026" us="21026"/><bf gi="2929" ue="21029" us="21028"/><bf gi="2931" ue="21034" us="21031"/><bf gi="2935" ue="21038" us!
 ="21038"/><bf gi="2936" ue="21043" us="21040"/><bf gi="2940" ue="21052" us="21045"/><bf gi="2948" ue="21061" us="21059"/><bf gi="2951" ue="21063" us="21063"/><bf gi="2952" ue="21069" us="21065"/><bf gi="2957" ue="21071" us="21071"/><bf gi="2958" ue="21080" us="21076"/><bf gi="2963" ue="21084" us="21082"/><bf gi="2966" ue="21089" us="21086"/><bf gi="2970" ue="21094" us="21091"/><bf gi="2974" ue="21098" us="21097"/><bf gi="2976" ue="21109" us="21102"/><bf gi="2984" ue="21113" us="21111"/><bf gi="2987" ue="21117" us="21117"/><bf gi="2988" ue="21120" us="21119"/><bf gi="2990" ue="21123" us="21122"/><bf gi="2992" ue="21125" us="21125"/><bf gi="2993" ue="21130" us="21127"/><bf gi="2997" ue="21133" us="21132"/><bf gi="2999" ue="21144" us="21137"/><bf gi="3007" ue="21148" us="21146"/><bf gi="3010" ue="21152" us="21151"/><bf gi="3012" ue="21159" us="21155"/><bf gi="3017" ue="21165" us="21161"/><bf gi="3022" ue="21169" us="21167"/><bf gi="3025" ue="21182" us="21172"/><bf gi="3036" ue!
 ="21185" us="21184"/><bf gi="3038" ue="21193" us="21187"/><bf gi="3045
" ue="21197" us="21196"/><bf gi="3047" ue="21199" us="21199"/><bf gi="3048" ue="21202" us="21201"/><bf gi="3050" ue="21209" us="21204"/><bf gi="3056" ue="21226" us="21211"/><bf gi="3072" ue="21228" us="21228"/><bf gi="3073" ue="21242" us="21232"/><bf gi="3084" ue="21251" us="21246"/><bf gi="3090" ue="21256" us="21253"/><bf gi="3094" ue="21261" us="21258"/><bf gi="3098" ue="21265" us="21263"/><bf gi="3101" ue="21267" us="21267"/><bf gi="3102" ue="21281" us="21269"/><bf gi="3115" ue="21285" us="21283"/><bf gi="3118" ue="21293" us="21287"/><bf gi="3125" ue="21299" us="21295"/><bf gi="3130" ue="21301" us="21301"/><bf gi="3131" ue="21315" us="21304"/><bf gi="3143" ue="21325" us="21317"/><bf gi="3152" ue="21332" us="21329"/><bf gi="3156" ue="21340" us="21335"/><bf gi="3162" ue="21342" us="21342"/><bf gi="3163" ue="21345" us="21344"/><bf gi="3165" ue="21347" us="21347"/><bf gi="3166" ue="21350" us="21349"/><bf gi="3168" ue="21353" us="21353"/><bf gi="3169" ue="21365" us="21356"/><b!
 f gi="3179" ue="21369" us="21367"/><bf gi="3182" ue="21371" us="21371"/><bf gi="3183" ue="21375" us="21374"/><bf gi="3185" ue="21380" us="21378"/><bf gi="3188" ue="21384" us="21383"/><bf gi="3190" ue="21390" us="21390"/><bf gi="3191" ue="21396" us="21395"/><bf gi="3193" ue="21398" us="21398"/><bf gi="3194" ue="21402" us="21400"/><bf gi="3197" ue="21405" us="21405"/><bf gi="3198" ue="21409" us="21407"/><bf gi="3201" ue="21414" us="21412"/><bf gi="3204" ue="21419" us="21416"/><bf gi="3208" ue="21424" us="21421"/><bf gi="3212" ue="21432" us="21426"/><bf gi="3219" ue="21435" us="21434"/><bf gi="3221" ue="21437" us="21437"/><bf gi="3222" ue="21440" us="21440"/><bf gi="3223" ue="21443" us="21442"/><bf gi="3225" ue="21445" us="21445"/><bf gi="3226" ue="21455" us="21448"/><bf gi="3234" ue="21463" us="21458"/><bf gi="3240" ue="21467" us="21465"/><bf gi="3243" ue="21491" us="21469"/><bf gi="3266" ue="21496" us="21493"/><bf gi="3270" ue="21498" us="21498"/><bf gi="3271" ue="21508" us=!
 "21505"/><bf gi="3275" ue="21521" us="21512"/><bf gi="3285" ue="21523"
 us="21523"/><bf gi="3286" ue="21531" us="21530"/><bf gi="3288" ue="21533" us="21533"/><bf gi="3289" ue="21537" us="21535"/><bf gi="3292" ue="21551" us="21542"/><bf gi="3302" ue="21553" us="21553"/><bf gi="3303" ue="21558" us="21556"/><bf gi="3306" ue="21561" us="21560"/><bf gi="3308" ue="21566" us="21563"/><bf gi="3312" ue="21568" us="21568"/><bf gi="3313" ue="21572" us="21570"/><bf gi="3316" ue="21578" us="21574"/><bf gi="3321" ue="21583" us="21581"/><bf gi="3324" ue="21585" us="21585"/><bf gi="3325" ue="21599" us="21598"/><bf gi="3327" ue="21602" us="21602"/><bf gi="3328" ue="21604" us="21604"/><bf gi="3329" ue="21611" us="21606"/><bf gi="3335" ue="21614" us="21613"/><bf gi="3337" ue="21617" us="21616"/><bf gi="3339" ue="21623" us="21619"/><bf gi="3344" ue="21629" us="21627"/><bf gi="3347" ue="21633" us="21631"/><bf gi="3350" ue="21638" us="21635"/><bf gi="3354" ue="21650" us="21640"/><bf gi="3365" ue="21654" us="21653"/><bf gi="3367" ue="21660" us="21660"/><bf gi="3368" !
 ue="21663" us="21663"/><bf gi="3369" ue="21666" us="21665"/><bf gi="3371" ue="21679" us="21668"/><bf gi="3383" ue="21683" us="21681"/><bf gi="3386" ue="21698" us="21687"/><bf gi="3398" ue="21700" us="21700"/><bf gi="3399" ue="21706" us="21702"/><bf gi="3404" ue="21710" us="21709"/><bf gi="3406" ue="21720" us="21720"/><bf gi="3407" ue="21730" us="21728"/><bf gi="3410" ue="21734" us="21733"/><bf gi="3412" ue="21738" us="21736"/><bf gi="3415" ue="21743" us="21740"/><bf gi="3419" ue="21746" us="21746"/><bf gi="3420" ue="21750" us="21750"/><bf gi="3421" ue="21754" us="21754"/><bf gi="3422" ue="21761" us="21756"/><bf gi="3428" ue="21769" us="21764"/><bf gi="3434" ue="21776" us="21772"/><bf gi="3439" ue="21782" us="21780"/><bf gi="3442" ue="21803" us="21802"/><bf gi="3444" ue="21807" us="21806"/><bf gi="3446" ue="21811" us="21809"/><bf gi="3449" ue="21814" us="21813"/><bf gi="3451" ue="21817" us="21816"/><bf gi="3453" ue="21822" us="21819"/><bf gi="3457" ue="21825" us="21824"/><bf!
  gi="3459" ue="21831" us="21828"/><bf gi="3463" ue="21834" us="21833"/
><bf gi="3465" ue="21837" us="21836"/><bf gi="3467" ue="21841" us="21839"/><bf gi="3470" ue="21843" us="21843"/><bf gi="3471" ue="21848" us="21846"/><bf gi="3474" ue="21854" us="21850"/><bf gi="3479" ue="21857" us="21856"/><bf gi="3481" ue="21860" us="21859"/><bf gi="3483" ue="21862" us="21862"/><bf gi="3484" ue="21884" us="21883"/><bf gi="3486" ue="21892" us="21886"/><bf gi="3493" ue="21899" us="21894"/><bf gi="3499" ue="21903" us="21902"/><bf gi="3501" ue="21908" us="21905"/><bf gi="3505" ue="21914" us="21911"/><bf gi="3509" ue="21919" us="21916"/><bf gi="3513" ue="21924" us="21923"/><bf gi="3515" ue="21934" us="21927"/><bf gi="3523" ue="21936" us="21936"/><bf gi="3524" ue="21938" us="21938"/><bf gi="3525" ue="21942" us="21942"/><bf gi="3526" ue="21951" us="21951"/><bf gi="3527" ue="21953" us="21953"/><bf gi="3528" ue="21959" us="21955"/><bf gi="3533" ue="21961" us="21961"/><bf gi="3534" ue="21964" us="21963"/><bf gi="3536" ue="21966" us="21966"/><bf gi="3537" ue="21972" u!
 s="21969"/><bf gi="3541" ue="21976" us="21975"/><bf gi="3543" ue="21980" us="21978"/><bf gi="3546" ue="21983" us="21982"/><bf gi="3548" ue="21988" us="21986"/><bf gi="3551" ue="21993" us="21993"/><bf gi="3552" ue="22007" us="22006"/><bf gi="3554" ue="22009" us="22009"/><bf gi="3555" ue="22015" us="22013"/><bf gi="3558" ue="22022" us="22021"/><bf gi="3560" ue="22026" us="22024"/><bf gi="3563" ue="22034" us="22029"/><bf gi="3569" ue="22036" us="22036"/><bf gi="3570" ue="22041" us="22038"/><bf gi="3574" ue="22043" us="22043"/><bf gi="3575" ue="22057" us="22057"/><bf gi="3576" ue="22060" us="22060"/><bf gi="3577" ue="22073" us="22063"/><bf gi="3588" ue="22077" us="22075"/><bf gi="3591" ue="22084" us="22079"/><bf gi="3597" ue="22086" us="22086"/><bf gi="3598" ue="22089" us="22089"/><bf gi="3599" ue="22096" us="22091"/><bf gi="3605" ue="22100" us="22100"/><bf gi="3606" ue="22107" us="22107"/><bf gi="3607" ue="22110" us="22110"/><bf gi="3608" ue="22116" us="22112"/><bf gi="3613" u!
 e="22118" us="22118"/><bf gi="3614" ue="22125" us="22120"/><bf gi="362
0" ue="22127" us="22127"/><bf gi="3621" ue="22130" us="22129"/><bf gi="3623" ue="22133" us="22132"/><bf gi="3625" ue="22136" us="22136"/><bf gi="3626" ue="22138" us="22138"/><bf gi="3627" ue="22144" us="22144"/><bf gi="3628" ue="22152" us="22148"/><bf gi="3633" ue="22156" us="22154"/><bf gi="3636" ue="22159" us="22159"/><bf gi="3637" ue="22165" us="22164"/><bf gi="3639" ue="22170" us="22169"/><bf gi="3641" ue="22176" us="22173"/><bf gi="3645" ue="22178" us="22178"/><bf gi="3646" ue="22185" us="22181"/><bf gi="3651" ue="22190" us="22187"/><bf gi="3655" ue="22193" us="22193"/><bf gi="3656" ue="22196" us="22195"/><bf gi="3658" ue="22199" us="22198"/><bf gi="3660" ue="22204" us="22204"/><bf gi="3661" ue="22206" us="22206"/><bf gi="3662" ue="22211" us="22208"/><bf gi="3666" ue="22213" us="22213"/><bf gi="3667" ue="22225" us="22216"/><bf gi="3677" ue="22227" us="22227"/><bf gi="3678" ue="22241" us="22231"/><bf gi="3689" ue="22248" us="22243"/><bf gi="3695" ue="22251" us="22251"/><!
 bf gi="3696" ue="22254" us="22253"/><bf gi="3698" ue="22259" us="22256"/><bf gi="3702" ue="22263" us="22262"/><bf gi="3704" ue="22266" us="22265"/><bf gi="3706" ue="22269" us="22269"/><bf gi="3707" ue="22276" us="22271"/><bf gi="3713" ue="22285" us="22279"/><bf gi="3720" ue="22287" us="22287"/><bf gi="3721" ue="22291" us="22289"/><bf gi="3724" ue="22294" us="22293"/><bf gi="3726" ue="22296" us="22296"/><bf gi="3727" ue="22301" us="22298"/><bf gi="3731" ue="22304" us="22303"/><bf gi="3733" ue="22314" us="22306"/><bf gi="3742" ue="22320" us="22316"/><bf gi="3747" ue="22324" us="22323"/><bf gi="3749" ue="22328" us="22327"/><bf gi="3751" ue="22331" us="22331"/><bf gi="3752" ue="22336" us="22333"/><bf gi="3756" ue="22338" us="22338"/><bf gi="3757" ue="22343" us="22341"/><bf gi="3760" ue="22346" us="22346"/><bf gi="3761" ue="22354" us="22348"/><bf gi="3768" ue="22361" us="22361"/><bf gi="3769" ue="22370" us="22369"/><bf gi="3771" ue="22379" us="22372"/><bf gi="3779" ue="22385" us!
 ="22381"/><bf gi="3784" ue="22389" us="22387"/><bf gi="3787" ue="22391
" us="22391"/><bf gi="3788" ue="22396" us="22393"/><bf gi="3792" ue="22399" us="22398"/><bf gi="3794" ue="22403" us="22401"/><bf gi="3797" ue="22409" us="22408"/><bf gi="3799" ue="22412" us="22411"/><bf gi="3801" ue="22421" us="22419"/><bf gi="3804" ue="22423" us="22423"/><bf gi="3805" ue="22426" us="22425"/><bf gi="3807" ue="22436" us="22428"/><bf gi="3816" ue="22442" us="22439"/><bf gi="3820" ue="22444" us="22444"/><bf gi="3821" ue="22448" us="22448"/><bf gi="3822" ue="22451" us="22451"/><bf gi="3823" ue="22456" us="22456"/><bf gi="3824" ue="22461" us="22461"/><bf gi="3825" ue="22464" us="22464"/><bf gi="3826" ue="22467" us="22467"/><bf gi="3827" ue="22472" us="22470"/><bf gi="3830" ue="22476" us="22475"/><bf gi="3832" ue="22479" us="22478"/><bf gi="3834" ue="22486" us="22482"/><bf gi="3839" ue="22497" us="22492"/><bf gi="3845" ue="22500" us="22499"/><bf gi="3847" ue="22503" us="22502"/><bf gi="3849" ue="22505" us="22505"/><bf gi="3850" ue="22509" us="22509"/><bf gi="3851"!
  ue="22512" us="22512"/><bf gi="3852" ue="22522" us="22516"/><bf gi="3859" ue="22528" us="22524"/><bf gi="3864" ue="22534" us="22530"/><bf gi="3869" ue="22541" us="22536"/><bf gi="3875" ue="22549" us="22549"/><bf gi="3876" ue="22553" us="22553"/><bf gi="3877" ue="22555" us="22555"/><bf gi="3878" ue="22561" us="22557"/><bf gi="3883" ue="22564" us="22564"/><bf gi="3884" ue="22567" us="22566"/><bf gi="3886" ue="22570" us="22570"/><bf gi="3887" ue="22573" us="22573"/><bf gi="3888" ue="22578" us="22575"/><bf gi="3892" ue="22581" us="22580"/><bf gi="3894" ue="22586" us="22585"/><bf gi="3896" ue="22589" us="22589"/><bf gi="3897" ue="22593" us="22591"/><bf gi="3900" ue="22605" us="22601"/><bf gi="3905" ue="22610" us="22607"/><bf gi="3909" ue="22613" us="22612"/><bf gi="3911" ue="22618" us="22615"/><bf gi="3915" ue="22623" us="22622"/><bf gi="3917" ue="22626" us="22625"/><bf gi="3919" ue="22628" us="22628"/><bf gi="3920" ue="22633" us="22631"/><bf gi="3923" ue="22635" us="22635"/><b!
 f gi="3924" ue="22640" us="22640"/><bf gi="3925" ue="22642" us="22642"
/><bf gi="3926" ue="22645" us="22645"/><bf gi="3927" ue="22649" us="22648"/><bf gi="3929" ue="22652" us="22652"/><bf gi="3930" ue="22657" us="22654"/><bf gi="3934" ue="22659" us="22659"/><bf gi="3935" ue="22661" us="22661"/><bf gi="3936" ue="22666" us="22663"/><bf gi="3940" ue="22669" us="22668"/><bf gi="3942" ue="22672" us="22671"/><bf gi="3944" ue="22676" us="22675"/><bf gi="3946" ue="22679" us="22678"/><bf gi="3948" ue="22690" us="22684"/><bf gi="3955" ue="22694" us="22694"/><bf gi="3956" ue="22697" us="22696"/><bf gi="3958" ue="22699" us="22699"/><bf gi="3959" ue="22702" us="22702"/><bf gi="3960" ue="22707" us="22705"/><bf gi="3963" ue="22716" us="22712"/><bf gi="3968" ue="22718" us="22718"/><bf gi="3969" ue="22722" us="22721"/><bf gi="3971" ue="22725" us="22724"/><bf gi="3973" ue="22728" us="22727"/><bf gi="3975" ue="22730" us="22730"/><bf gi="3976" ue="22734" us="22732"/><bf gi="3979" ue="22746" us="22736"/><bf gi="3990" ue="22751" us="22748"/><bf gi="3994" ue="22754" !
 us="22753"/><bf gi="3996" ue="22757" us="22756"/><bf gi="3998" ue="22761" us="22761"/><bf gi="3999" ue="22764" us="22763"/><bf gi="4001" ue="22771" us="22766"/><bf gi="4007" ue="22775" us="22775"/><bf gi="4008" ue="22781" us="22777"/><bf gi="4013" ue="22786" us="22786"/><bf gi="4014" ue="22790" us="22789"/><bf gi="4016" ue="22796" us="22793"/><bf gi="4020" ue="22800" us="22799"/><bf gi="4022" ue="22806" us="22802"/><bf gi="4027" ue="22813" us="22808"/><bf gi="4033" ue="22821" us="22817"/><bf gi="4038" ue="22835" us="22823"/><bf gi="4051" ue="22840" us="22837"/><bf gi="4055" ue="22847" us="22846"/><bf gi="4057" ue="22852" us="22851"/><bf gi="4059" ue="22857" us="22854"/><bf gi="4063" ue="22869" us="22862"/><bf gi="4071" ue="22875" us="22871"/><bf gi="4076" ue="22883" us="22877"/><bf gi="4083" ue="22885" us="22885"/><bf gi="4084" ue="22895" us="22887"/><bf gi="4093" ue="22902" us="22898"/><bf gi="4098" ue="22905" us="22904"/><bf gi="4100" ue="22909" us="22907"/><bf gi="4103" !
 ue="22916" us="22913"/><bf gi="4107" ue="22926" us="22922"/><bf gi="41
12" ue="22931" us="22930"/><bf gi="4114" ue="22935" us="22933"/><bf gi="4117" ue="22937" us="22937"/><bf gi="4118" ue="22939" us="22939"/><bf gi="4119" ue="22941" us="22941"/><bf gi="4120" ue="22943" us="22943"/><bf gi="4121" ue="22949" us="22947"/><bf gi="4124" ue="22952" us="22951"/><bf gi="4126" ue="22960" us="22956"/><bf gi="4131" ue="22963" us="22962"/><bf gi="4133" ue="22967" us="22967"/><bf gi="4134" ue="22972" us="22969"/><bf gi="4138" ue="22974" us="22974"/><bf gi="4139" ue="22977" us="22977"/><bf gi="4140" ue="22980" us="22979"/><bf gi="4142" ue="22982" us="22982"/><bf gi="4143" ue="22987" us="22984"/><bf gi="4147" ue="22989" us="22989"/><bf gi="4148" ue="22996" us="22992"/><bf gi="4153" ue="23002" us="23001"/><bf gi="4155" ue="23007" us="23004"/><bf gi="4159" ue="23016" us="23011"/><bf gi="4165" ue="23019" us="23018"/><bf gi="4167" ue="23023" us="23022"/><bf gi="4169" ue="23026" us="23025"/><bf gi="4171" ue="23028" us="23028"/><bf gi="4172" ue="23031" us="23030"/>!
 <bf gi="4174" ue="23035" us="23035"/><bf gi="4175" ue="23041" us="23039"/><bf gi="4178" ue="23044" us="23043"/><bf gi="4180" ue="23049" us="23049"/><bf gi="4181" ue="23054" us="23052"/><bf gi="4184" ue="23059" us="23057"/><bf gi="4187" ue="23064" us="23064"/><bf gi="4188" ue="23066" us="23066"/><bf gi="4189" ue="23068" us="23068"/><bf gi="4190" ue="23072" us="23070"/><bf gi="4193" ue="23077" us="23075"/><bf gi="4196" ue="23082" us="23079"/><bf gi="4200" ue="23085" us="23085"/><bf gi="4201" ue="23088" us="23087"/><bf gi="4203" ue="23094" us="23093"/><bf gi="4205" ue="23100" us="23100"/><bf gi="4206" ue="23105" us="23104"/><bf gi="4208" ue="23113" us="23108"/><bf gi="4214" ue="23116" us="23116"/><bf gi="4215" ue="23120" us="23120"/><bf gi="4216" ue="23125" us="23125"/><bf gi="4217" ue="23130" us="23130"/><bf gi="4218" ue="23134" us="23134"/><bf gi="4219" ue="23139" us="23138"/><bf gi="4221" ue="23143" us="23141"/><bf gi="4224" ue="23146" us="23146"/><bf gi="4225" ue="23149" u!
 s="23148"/><bf gi="4227" ue="23159" us="23159"/><bf gi="4228" ue="2316
3" us="23162"/><bf gi="4230" ue="23167" us="23166"/><bf gi="4232" ue="23179" us="23179"/><bf gi="4233" ue="23184" us="23184"/><bf gi="4234" ue="23187" us="23186"/><bf gi="4236" ue="23190" us="23190"/><bf gi="4237" ue="23196" us="23193"/><bf gi="4241" ue="23200" us="23198"/><bf gi="4244" ue="23202" us="23202"/><bf gi="4245" ue="23207" us="23207"/><bf gi="4246" ue="23212" us="23212"/><bf gi="4247" ue="23219" us="23217"/><bf gi="4250" ue="23221" us="23221"/><bf gi="4251" ue="23224" us="23224"/><bf gi="4252" ue="23231" us="23226"/><bf gi="4258" ue="23234" us="23233"/><bf gi="4260" ue="23236" us="23236"/><bf gi="4261" ue="23238" us="23238"/><bf gi="4262" ue="23241" us="23240"/><bf gi="4264" ue="23244" us="23243"/><bf gi="4266" ue="23248" us="23247"/><bf gi="4268" ue="23255" us="23254"/><bf gi="4270" ue="23258" us="23258"/><bf gi="4271" ue="23260" us="23260"/><bf gi="4272" ue="23265" us="23264"/><bf gi="4274" ue="23267" us="23267"/><bf gi="4275" ue="23270" us="23269"/><bf gi="4277!
 " ue="23274" us="23273"/><bf gi="4279" ue="23278" us="23278"/><bf gi="4280" ue="23286" us="23285"/><bf gi="4282" ue="23291" us="23290"/><bf gi="4284" ue="23293" us="23293"/><bf gi="4285" ue="23297" us="23296"/><bf gi="4287" ue="23305" us="23304"/><bf gi="4289" ue="23308" us="23307"/><bf gi="4291" ue="23319" us="23318"/><bf gi="4293" ue="23321" us="23321"/><bf gi="4294" ue="23323" us="23323"/><bf gi="4295" ue="23325" us="23325"/><bf gi="4296" ue="23330" us="23329"/><bf gi="4298" ue="23333" us="23333"/><bf gi="4299" ue="23338" us="23338"/><bf gi="4300" ue="23341" us="23340"/><bf gi="4302" ue="23344" us="23344"/><bf gi="4303" ue="23346" us="23346"/><bf gi="4304" ue="23348" us="23348"/><bf gi="4305" ue="23350" us="23350"/><bf gi="4306" ue="23352" us="23352"/><bf gi="4307" ue="23358" us="23358"/><bf gi="4308" ue="23361" us="23360"/><bf gi="4310" ue="23363" us="23363"/><bf gi="4311" ue="23365" us="23365"/><bf gi="4312" ue="23372" us="23371"/><bf gi="4314" ue="23378" us="23376"/><!
 bf gi="4317" ue="23384" us="23380"/><bf gi="4322" ue="23391" us="23386
"/><bf gi="4328" ue="23398" us="23395"/><bf gi="4332" ue="23401" us="23400"/><bf gi="4334" ue="23403" us="23403"/><bf gi="4335" ue="23409" us="23406"/><bf gi="4339" ue="23411" us="23411"/><bf gi="4340" ue="23413" us="23413"/><bf gi="4341" ue="23416" us="23416"/><bf gi="4342" ue="23418" us="23418"/><bf gi="4343" ue="23425" us="23420"/><bf gi="4349" ue="23441" us="23427"/><bf gi="4364" ue="23453" us="23443"/><bf gi="4375" ue="23455" us="23455"/><bf gi="4376" ue="23462" us="23458"/><bf gi="4381" ue="23465" us="23464"/><bf gi="4383" ue="23482" us="23468"/><bf gi="4398" ue="23484" us="23484"/><bf gi="4399" ue="23495" us="23487"/><bf gi="4408" ue="23497" us="23497"/><bf gi="4409" ue="23501" us="23500"/><bf gi="4411" ue="23504" us="23503"/><bf gi="4413" ue="23508" us="23506"/><bf gi="4416" ue="23515" us="23510"/><bf gi="4422" ue="23522" us="23517"/><bf gi="4428" ue="23529" us="23524"/><bf gi="4434" ue="23532" us="23531"/><bf gi="4436" ue="23537" us="23534"/><bf gi="4440" ue="23542"!
  us="23539"/><bf gi="4444" ue="23544" us="23544"/><bf gi="4445" ue="23546" us="23546"/><bf gi="4446" ue="23551" us="23549"/><bf gi="4449" ue="23554" us="23553"/><bf gi="4451" ue="23567" us="23556"/><bf gi="4463" ue="23569" us="23569"/><bf gi="4464" ue="23571" us="23571"/><bf gi="4465" ue="23575" us="23574"/><bf gi="4467" ue="23578" us="23578"/><bf gi="4468" ue="23584" us="23582"/><bf gi="4471" ue="23588" us="23586"/><bf gi="4474" ue="23590" us="23590"/><bf gi="4475" ue="23593" us="23592"/><bf gi="4477" ue="23598" us="23595"/><bf gi="4481" ue="23602" us="23600"/><bf gi="4484" ue="23606" us="23605"/><bf gi="4486" ue="23617" us="23608"/><bf gi="4496" ue="23622" us="23621"/><bf gi="4498" ue="23624" us="23624"/><bf gi="4499" ue="23627" us="23626"/><bf gi="4501" ue="23633" us="23629"/><bf gi="4506" ue="23635" us="23635"/><bf gi="4507" ue="23637" us="23637"/><bf gi="4508" ue="23642" us="23641"/><bf gi="4510" ue="23644" us="23644"/><bf gi="4511" ue="23646" us="23646"/><bf gi="4512"!
  ue="23653" us="23648"/><bf gi="4518" ue="23657" us="23655"/><bf gi="4
521" ue="23665" us="23660"/><bf gi="4527" ue="23670" us="23668"/><bf gi="4530" ue="23677" us="23673"/><bf gi="4535" ue="23688" us="23687"/><bf gi="4537" ue="23690" us="23690"/><bf gi="4538" ue="23692" us="23692"/><bf gi="4539" ue="23698" us="23695"/><bf gi="4543" ue="23700" us="23700"/><bf gi="4544" ue="23709" us="23709"/><bf gi="4545" ue="23715" us="23711"/><bf gi="4550" ue="23718" us="23718"/><bf gi="4551" ue="23724" us="23720"/><bf gi="4556" ue="23736" us="23729"/><bf gi="4564" ue="23740" us="23738"/><bf gi="4567" ue="23742" us="23742"/><bf gi="4568" ue="23749" us="23749"/><bf gi="4569" ue="23751" us="23751"/><bf gi="4570" ue="23753" us="23753"/><bf gi="4571" ue="23755" us="23755"/><bf gi="4572" ue="23762" us="23762"/><bf gi="4573" ue="23767" us="23767"/><bf gi="4574" ue="23769" us="23769"/><bf gi="4575" ue="23773" us="23773"/><bf gi="4576" ue="23777" us="23776"/><bf gi="4578" ue="23786" us="23784"/><bf gi="4581" ue="23794" us="23789"/><bf gi="4587" ue="23798" us="23796"/!
 ><bf gi="4590" ue="23803" us="23802"/><bf gi="4592" ue="23805" us="23805"/><bf gi="4593" ue="23809" us="23809"/><bf gi="4594" ue="23815" us="23814"/><bf gi="4596" ue="23819" us="23819"/><bf gi="4597" ue="23822" us="23821"/><bf gi="4599" ue="23826" us="23825"/><bf gi="4601" ue="23835" us="23828"/><bf gi="4609" ue="23839" us="23839"/><bf gi="4610" ue="23844" us="23842"/><bf gi="4613" ue="23847" us="23846"/><bf gi="4615" ue="23849" us="23849"/><bf gi="4616" ue="23851" us="23851"/><bf gi="4617" ue="23857" us="23857"/><bf gi="4618" ue="23860" us="23860"/><bf gi="4619" ue="23865" us="23865"/><bf gi="4620" ue="23869" us="23869"/><bf gi="4621" ue="23871" us="23871"/><bf gi="4622" ue="23875" us="23874"/><bf gi="4624" ue="23878" us="23878"/><bf gi="4625" ue="23880" us="23880"/><bf gi="4626" ue="23884" us="23882"/><bf gi="4629" ue="23886" us="23886"/><bf gi="4630" ue="23890" us="23888"/><bf gi="4633" ue="23893" us="23893"/><bf gi="4634" ue="23897" us="23897"/><bf gi="4635" ue="23900" !
 us="23900"/><bf gi="4636" ue="23906" us="23903"/><bf gi="4640" ue="239
08" us="23908"/><bf gi="4641" ue="23914" us="23913"/><bf gi="4643" ue="23917" us="23916"/><bf gi="4645" ue="23920" us="23919"/><bf gi="4647" ue="23923" us="23923"/><bf gi="4648" ue="23926" us="23926"/><bf gi="4649" ue="23930" us="23929"/><bf gi="4651" ue="23935" us="23934"/><bf gi="4653" ue="23940" us="23937"/><bf gi="4657" ue="23944" us="23943"/><bf gi="4659" ue="23948" us="23946"/><bf gi="4662" ue="23952" us="23952"/><bf gi="4663" ue="23957" us="23954"/><bf gi="4667" ue="23961" us="23961"/><bf gi="4668" ue="23963" us="23963"/><bf gi="4669" ue="23965" us="23965"/><bf gi="4670" ue="23968" us="23967"/><bf gi="4672" ue="23970" us="23970"/><bf gi="4673" ue="23975" us="23975"/><bf gi="4674" ue="23980" us="23979"/><bf gi="4676" ue="23982" us="23982"/><bf gi="4677" ue="23984" us="23984"/><bf gi="4678" ue="23986" us="23986"/><bf gi="4679" ue="23988" us="23988"/><bf gi="4680" ue="23994" us="23991"/><bf gi="4684" ue="23997" us="23996"/><bf gi="4686" ue="24003" us="24003"/><bf gi="468!
 7" ue="24007" us="24007"/><bf gi="4688" ue="24009" us="24009"/><bf gi="4689" ue="24014" us="24011"/><bf gi="4693" ue="24016" us="24016"/><bf gi="4694" ue="24019" us="24018"/><bf gi="4696" ue="24022" us="24022"/><bf gi="4697" ue="24025" us="24024"/><bf gi="4699" ue="24027" us="24027"/><bf gi="4700" ue="24030" us="24029"/><bf gi="4702" ue="24033" us="24032"/><bf gi="4704" ue="24041" us="24035"/><bf gi="4711" ue="24043" us="24043"/><bf gi="4712" ue="24046" us="24046"/><bf gi="4713" ue="24053" us="24049"/><bf gi="4718" ue="24057" us="24055"/><bf gi="4721" ue="24059" us="24059"/><bf gi="4722" ue="24062" us="24061"/><bf gi="4724" ue="24064" us="24064"/><bf gi="4725" ue="24067" us="24066"/><bf gi="4727" ue="24071" us="24070"/><bf gi="4729" ue="24077" us="24075"/><bf gi="4732" ue="24082" us="24081"/><bf gi="4734" ue="24086" us="24084"/><bf gi="4737" ue="24091" us="24088"/><bf gi="4741" ue="24093" us="24093"/><bf gi="4742" ue="24096" us="24095"/><bf gi="4744" ue="24101" us="24101"/>!
 <bf gi="4745" ue="24104" us="24104"/><bf gi="4746" ue="24107" us="2410
7"/><bf gi="4747" ue="24112" us="24109"/><bf gi="4751" ue="24115" us="24114"/><bf gi="4753" ue="24120" us="24117"/><bf gi="4757" ue="24126" us="24125"/><bf gi="4759" ue="24128" us="24128"/><bf gi="4760" ue="24133" us="24131"/><bf gi="4763" ue="24135" us="24135"/><bf gi="4764" ue="24137" us="24137"/><bf gi="4765" ue="24140" us="24139"/><bf gi="4767" ue="24142" us="24142"/><bf gi="4768" ue="24145" us="24144"/><bf gi="4770" ue="24152" us="24148"/><bf gi="4775" ue="24156" us="24155"/><bf gi="4777" ue="24159" us="24158"/><bf gi="4779" ue="24164" us="24161"/><bf gi="4783" ue="24168" us="24168"/><bf gi="4784" ue="24174" us="24170"/><bf gi="4789" ue="24176" us="24176"/><bf gi="4790" ue="24182" us="24178"/><bf gi="4795" ue="24193" us="24184"/><bf gi="4805" ue="24196" us="24195"/><bf gi="4807" ue="24199" us="24199"/><bf gi="4808" ue="24203" us="24202"/><bf gi="4810" ue="24207" us="24206"/><bf gi="4812" ue="24215" us="24213"/><bf gi="4815" ue="24218" us="24218"/><bf gi="4816" ue="24220!
 " us="24220"/><bf gi="4817" ue="24224" us="24224"/><bf gi="4818" ue="24226" us="24226"/><bf gi="4819" ue="24232" us="24228"/><bf gi="4824" ue="24237" us="24234"/><bf gi="4828" ue="24241" us="24241"/><bf gi="4829" ue="24243" us="24243"/><bf gi="4830" ue="24248" us="24245"/><bf gi="4834" ue="24255" us="24253"/><bf gi="4837" ue="24259" us="24257"/><bf gi="4840" ue="24262" us="24262"/><bf gi="4841" ue="24268" us="24264"/><bf gi="4846" ue="24278" us="24270"/><bf gi="4855" ue="24291" us="24282"/><bf gi="4865" ue="24293" us="24293"/><bf gi="4866" ue="24297" us="24296"/><bf gi="4868" ue="24300" us="24299"/><bf gi="4870" ue="24305" us="24304"/><bf gi="4872" ue="24308" us="24307"/><bf gi="4874" ue="24312" us="24310"/><bf gi="4877" ue="24316" us="24314"/><bf gi="4880" ue="24319" us="24318"/><bf gi="4882" ue="24324" us="24321"/><bf gi="4886" ue="24337" us="24326"/><bf gi="4898" ue="24345" us="24339"/><bf gi="4905" ue="24349" us="24347"/><bf gi="4908" ue="24351" us="24351"/><bf gi="4909!
 " ue="24361" us="24353"/><bf gi="4918" ue="24369" us="24363"/><bf gi="
4925" ue="24376" us="24372"/><bf gi="4930" ue="24385" us="24379"/><bf gi="4937" ue="24389" us="24388"/><bf gi="4939" ue="24392" us="24391"/><bf gi="4941" ue="24394" us="24394"/><bf gi="4942" ue="24398" us="24396"/><bf gi="4945" ue="24401" us="24400"/><bf gi="4947" ue="24404" us="24403"/><bf gi="4949" ue="24409" us="24406"/><bf gi="4953" ue="24413" us="24411"/><bf gi="4956" ue="24420" us="24416"/><bf gi="4961" ue="24423" us="24422"/><bf gi="4963" ue="24429" us="24425"/><bf gi="4968" ue="24437" us="24431"/><bf gi="4975" ue="24442" us="24439"/><bf gi="4979" ue="24453" us="24444"/><bf gi="4989" ue="24461" us="24455"/><bf gi="4996" ue="24467" us="24463"/><bf gi="5001" ue="24473" us="24470"/><bf gi="5005" ue="24478" us="24476"/><bf gi="5008" ue="24482" us="24480"/><bf gi="5011" ue="24484" us="24484"/><bf gi="5012" ue="24497" us="24487"/><bf gi="5023" ue="24500" us="24499"/><bf gi="5025" ue="24505" us="24503"/><bf gi="5028" ue="24509" us="24508"/><bf gi="5030" ue="24517" us="24515"!
 /><bf gi="5033" ue="24521" us="24519"/><bf gi="5036" ue="24525" us="24523"/><bf gi="5039" ue="24532" us="24528"/><bf gi="5044" ue="24537" us="24534"/><bf gi="5048" ue="24542" us="24540"/><bf gi="5051" ue="24546" us="24544"/><bf gi="5054" ue="24548" us="24548"/><bf gi="5055" ue="24563" us="24552"/><bf gi="5067" ue="24566" us="24565"/><bf gi="5069" ue="24568" us="24568"/><bf gi="5070" ue="24573" us="24570"/><bf gi="5074" ue="24575" us="24575"/><bf gi="5075" ue="24583" us="24583"/><bf gi="5076" ue="24586" us="24586"/><bf gi="5077" ue="24592" us="24589"/><bf gi="5081" ue="24605" us="24594"/><bf gi="5093" ue="24609" us="24607"/><bf gi="5096" ue="24619" us="24612"/><bf gi="5104" ue="24621" us="24621"/><bf gi="5105" ue="24623" us="24623"/><bf gi="5106" ue="24625" us="24625"/><bf gi="5107" ue="24627" us="24627"/><bf gi="5108" ue="24629" us="24629"/><bf gi="5109" ue="24634" us="24634"/><bf gi="5110" ue="24643" us="24640"/><bf gi="5114" ue="24653" us="24646"/><bf gi="5122" ue="24658"!
  us="24656"/><bf gi="5125" ue="24663" us="24660"/><bf gi="5129" ue="24
666" us="24665"/><bf gi="5131" ue="24669" us="24669"/><bf gi="5132" ue="24677" us="24671"/><bf gi="5139" ue="24685" us="24679"/><bf gi="5146" ue="24689" us="24687"/><bf gi="5149" ue="24693" us="24693"/><bf gi="5150" ue="24695" us="24695"/><bf gi="5151" ue="24703" us="24702"/><bf gi="5153" ue="24710" us="24705"/><bf gi="5159" ue="24718" us="24712"/><bf gi="5166" ue="24728" us="24721"/><bf gi="5174" ue="24731" us="24730"/><bf gi="5176" ue="24736" us="24733"/><bf gi="5180" ue="24746" us="24738"/><bf gi="5189" ue="24760" us="24752"/><bf gi="5198" ue="24766" us="24763"/><bf gi="5202" ue="24770" us="24770"/><bf gi="5203" ue="24779" us="24772"/><bf gi="5211" ue="24783" us="24782"/><bf gi="5213" ue="24785" us="24785"/><bf gi="5214" ue="24789" us="24787"/><bf gi="5217" ue="24803" us="24792"/><bf gi="5229" ue="24805" us="24805"/><bf gi="5230" ue="24808" us="24807"/><bf gi="5232" ue="24829" us="24816"/><bf gi="5246" ue="24835" us="24832"/><bf gi="5250" ue="24842" us="24838"/><bf gi="52!
 55" ue="24855" us="24844"/><bf gi="5267" ue="24860" us="24857"/><bf gi="5271" ue="24866" us="24862"/><bf gi="5276" ue="24872" us="24871"/><bf gi="5278" ue="24876" us="24874"/><bf gi="5281" ue="24881" us="24880"/><bf gi="5283" ue="24887" us="24884"/><bf gi="5287" ue="24889" us="24889"/><bf gi="5288" ue="24895" us="24892"/><bf gi="5292" ue="24898" us="24897"/><bf gi="5294" ue="24910" us="24900"/><bf gi="5305" ue="24915" us="24915"/><bf gi="5306" ue="24917" us="24917"/><bf gi="5307" ue="24922" us="24920"/><bf gi="5310" ue="24928" us="24925"/><bf gi="5314" ue="24931" us="24930"/><bf gi="5316" ue="24933" us="24933"/><bf gi="5317" ue="24936" us="24935"/><bf gi="5319" ue="24940" us="24939"/><bf gi="5321" ue="24952" us="24942"/><bf gi="5332" ue="24956" us="24955"/><bf gi="5334" ue="24964" us="24958"/><bf gi="5341" ue="24967" us="24967"/><bf gi="5342" ue="24971" us="24970"/><bf gi="5344" ue="24974" us="24973"/><bf gi="5346" ue="24980" us="24976"/><bf gi="5351" ue="24986" us="24982"/!
 ><bf gi="5356" ue="24989" us="24988"/><bf gi="5358" ue="24992" us="249
91"/><bf gi="5360" ue="24997" us="24996"/><bf gi="5362" ue="25006" us="24999"/><bf gi="5370" ue="25010" us="25010"/><bf gi="5371" ue="25014" us="25014"/><bf gi="5372" ue="25018" us="25016"/><bf gi="5375" ue="25020" us="25020"/><bf gi="5376" ue="25022" us="25022"/><bf gi="5377" ue="25027" us="25024"/><bf gi="5381" ue="25040" us="25030"/><bf gi="5392" ue="25045" us="25045"/><bf gi="5393" ue="25055" us="25052"/><bf gi="5397" ue="25059" us="25057"/><bf gi="5400" ue="25063" us="25061"/><bf gi="5403" ue="25065" us="25065"/><bf gi="5404" ue="25069" us="25068"/><bf gi="5406" ue="25071" us="25071"/><bf gi="5407" ue="25074" us="25074"/><bf gi="5408" ue="25076" us="25076"/><bf gi="5409" ue="25080" us="25078"/><bf gi="5412" ue="25082" us="25082"/><bf gi="5413" ue="25089" us="25084"/><bf gi="5419" ue="25092" us="25091"/><bf gi="5421" ue="25098" us="25095"/><bf gi="5425" ue="25102" us="25100"/><bf gi="5428" ue="25110" us="25104"/><bf gi="5435" ue="25123" us="25114"/><bf gi="5445" ue="2512!
 7" us="25126"/><bf gi="5447" ue="25131" us="25129"/><bf gi="5450" ue="25136" us="25134"/><bf gi="5453" ue="25140" us="25138"/><bf gi="5456" ue="25145" us="25144"/><bf gi="5458" ue="25147" us="25147"/><bf gi="5459" ue="25149" us="25149"/><bf gi="5460" ue="25156" us="25151"/><bf gi="5466" ue="25161" us="25158"/><bf gi="5470" ue="25166" us="25163"/><bf gi="5474" ue="25174" us="25168"/><bf gi="5481" ue="25176" us="25176"/><bf gi="5482" ue="25180" us="25178"/><bf gi="5485" ue="25182" us="25182"/><bf gi="5486" ue="25184" us="25184"/><bf gi="5487" ue="25188" us="25187"/><bf gi="5489" ue="25192" us="25192"/><bf gi="5490" ue="25199" us="25197"/><bf gi="5493" ue="25201" us="25201"/><bf gi="5494" ue="25203" us="25203"/><bf gi="5495" ue="25206" us="25206"/><bf gi="5496" ue="25210" us="25209"/><bf gi="5498" ue="25216" us="25212"/><bf gi="5503" ue="25220" us="25218"/><bf gi="5506" ue="25226" us="25225"/><bf gi="5508" ue="25240" us="25229"/><bf gi="5520" ue="25244" us="25243"/><bf gi="552!
 2" ue="25246" us="25246"/><bf gi="5523" ue="25254" us="25254"/><bf gi=
"5524" ue="25256" us="25256"/><bf gi="5525" ue="25260" us="25259"/><bf gi="5527" ue="25265" us="25265"/><bf gi="5528" ue="25267" us="25267"/><bf gi="5529" ue="25271" us="25269"/><bf gi="5532" ue="25279" us="25273"/><bf gi="5539" ue="25282" us="25282"/><bf gi="5540" ue="25290" us="25284"/><bf gi="5547" ue="25309" us="25292"/><bf gi="5565" ue="25313" us="25312"/><bf gi="5567" ue="25322" us="25322"/><bf gi="5568" ue="25327" us="25324"/><bf gi="5572" ue="25335" us="25329"/><bf gi="5579" ue="25343" us="25340"/><bf gi="5583" ue="25348" us="25345"/><bf gi="5587" ue="25357" us="25351"/><bf gi="5594" ue="25361" us="25360"/><bf gi="5596" ue="25363" us="25363"/><bf gi="5597" ue="25366" us="25366"/><bf gi="5598" ue="25369" us="25368"/><bf gi="5600" ue="25375" us="25375"/><bf gi="5601" ue="25387" us="25383"/><bf gi="5606" ue="25389" us="25389"/><bf gi="5607" ue="25391" us="25391"/><bf gi="5608" ue="25398" us="25397"/><bf gi="5610" ue="25402" us="25401"/><bf gi="5612" ue="25407" us="25404!
 "/><bf gi="5616" ue="25412" us="25409"/><bf gi="5620" ue="25414" us="25414"/><bf gi="5621" ue="25424" us="25417"/><bf gi="5629" ue="25429" us="25426"/><bf gi="5633" ue="25432" us="25431"/><bf gi="5635" ue="25436" us="25435"/><bf gi="5637" ue="25449" us="25445"/><bf gi="5642" ue="25454" us="25451"/><bf gi="5646" ue="25458" us="25457"/><bf gi="5648" ue="25464" us="25460"/><bf gi="5653" ue="25469" us="25466"/><bf gi="5657" ue="25472" us="25471"/><bf gi="5659" ue="25476" us="25474"/><bf gi="5662" ue="25482" us="25479"/><bf gi="5666" ue="25484" us="25484"/><bf gi="5667" ue="25488" us="25486"/><bf gi="5670" ue="25490" us="25490"/><bf gi="5671" ue="25494" us="25492"/><bf gi="5674" ue="25499" us="25496"/><bf gi="5678" ue="25519" us="25502"/><bf gi="5696" ue="25522" us="25522"/><bf gi="5697" ue="25525" us="25524"/><bf gi="5699" ue="25531" us="25531"/><bf gi="5700" ue="25534" us="25533"/><bf gi="5702" ue="25537" us="25536"/><bf gi="5704" ue="25542" us="25539"/><bf gi="5708" ue="25545!
 " us="25544"/><bf gi="5710" ue="25558" us="25550"/><bf gi="5719" ue="2
5564" us="25562"/><bf gi="5722" ue="25569" us="25568"/><bf gi="5724" ue="25571" us="25571"/><bf gi="5725" ue="25573" us="25573"/><bf gi="5726" ue="25578" us="25577"/><bf gi="5728" ue="25580" us="25580"/><bf gi="5729" ue="25582" us="25582"/><bf gi="5730" ue="25590" us="25586"/><bf gi="5735" ue="25594" us="25592"/><bf gi="5738" ue="25606" us="25606"/><bf gi="5739" ue="25610" us="25609"/><bf gi="5741" ue="25613" us="25613"/><bf gi="5742" ue="25616" us="25615"/><bf gi="5744" ue="25620" us="25618"/><bf gi="5747" ue="25624" us="25622"/><bf gi="5750" ue="25628" us="25628"/><bf gi="5751" ue="25630" us="25630"/><bf gi="5752" ue="25632" us="25632"/><bf gi="5753" ue="25634" us="25634"/><bf gi="5754" ue="25638" us="25636"/><bf gi="5757" ue="25642" us="25640"/><bf gi="5760" ue="25645" us="25644"/><bf gi="5762" ue="25648" us="25647"/><bf gi="5764" ue="25654" us="25652"/><bf gi="5767" ue="25658" us="25658"/><bf gi="5768" ue="25663" us="25661"/><bf gi="5771" ue="25666" us="25666"/><bf gi="5!
 772" ue="25675" us="25675"/><bf gi="5773" ue="25679" us="25678"/><bf gi="5775" ue="25684" us="25681"/><bf gi="5779" ue="25688" us="25688"/><bf gi="5780" ue="25693" us="25690"/><bf gi="5784" ue="25697" us="25695"/><bf gi="5787" ue="25699" us="25699"/><bf gi="5788" ue="25703" us="25703"/><bf gi="5789" ue="25705" us="25705"/><bf gi="5790" ue="25709" us="25709"/><bf gi="5791" ue="25711" us="25711"/><bf gi="5792" ue="25716" us="25715"/><bf gi="5794" ue="25718" us="25718"/><bf gi="5795" ue="25720" us="25720"/><bf gi="5796" ue="25723" us="25722"/><bf gi="5798" ue="25725" us="25725"/><bf gi="5799" ue="25731" us="25731"/><bf gi="5800" ue="25733" us="25733"/><bf gi="5801" ue="25736" us="25735"/><bf gi="5803" ue="25747" us="25743"/><bf gi="5808" ue="25749" us="25749"/><bf gi="5809" ue="25755" us="25752"/><bf gi="5813" ue="25759" us="25757"/><bf gi="5816" ue="25761" us="25761"/><bf gi="5817" ue="25766" us="25763"/><bf gi="5821" ue="25769" us="25768"/><bf gi="5823" ue="25774" us="25771"!
 /><bf gi="5827" ue="25776" us="25776"/><bf gi="5828" ue="25779" us="25
778"/><bf gi="5830" ue="25785" us="25785"/><bf gi="5831" ue="25791" us="25787"/><bf gi="5836" ue="25794" us="25793"/><bf gi="5838" ue="25797" us="25796"/><bf gi="5840" ue="25799" us="25799"/><bf gi="5841" ue="25806" us="25801"/><bf gi="5847" ue="25810" us="25808"/><bf gi="5850" ue="25813" us="25812"/><bf gi="5852" ue="25816" us="25815"/><bf gi="5854" ue="25818" us="25818"/><bf gi="5855" ue="25831" us="25824"/><bf gi="5863" ue="25834" us="25833"/><bf gi="5865" ue="25837" us="25836"/><bf gi="5867" ue="25842" us="25839"/><bf gi="5871" ue="25847" us="25844"/><bf gi="5875" ue="25851" us="25850"/><bf gi="5877" ue="25857" us="25853"/><bf gi="5882" ue="25861" us="25860"/><bf gi="5884" ue="25866" us="25864"/><bf gi="5887" ue="25871" us="25871"/><bf gi="5888" ue="25876" us="25875"/><bf gi="5890" ue="25878" us="25878"/><bf gi="5891" ue="25881" us="25880"/><bf gi="5893" ue="25887" us="25883"/><bf gi="5898" ue="25892" us="25890"/><bf gi="5901" ue="25894" us="25894"/><bf gi="5902" ue="259!
 00" us="25897"/><bf gi="5906" ue="25903" us="25902"/><bf gi="5908" ue="25905" us="25905"/><bf gi="5909" ue="25919" us="25908"/><bf gi="5921" ue="25923" us="25923"/><bf gi="5922" ue="25925" us="25925"/><bf gi="5923" ue="25929" us="25927"/><bf gi="5926" ue="25938" us="25933"/><bf gi="5932" ue="25945" us="25940"/><bf gi="5938" ue="25952" us="25949"/><bf gi="5942" ue="25955" us="25954"/><bf gi="5944" ue="25959" us="25958"/><bf gi="5946" ue="25964" us="25963"/><bf gi="5948" ue="25968" us="25968"/><bf gi="5949" ue="25970" us="25970"/><bf gi="5950" ue="25973" us="25972"/><bf gi="5952" ue="25976" us="25975"/><bf gi="5954" ue="25978" us="25978"/><bf gi="5955" ue="25981" us="25981"/><bf gi="5956" ue="25987" us="25985"/><bf gi="5959" ue="25989" us="25989"/><bf gi="5960" ue="25994" us="25991"/><bf gi="5964" ue="25996" us="25996"/><bf gi="5965" ue="25998" us="25998"/><bf gi="5966" ue="26002" us="26000"/><bf gi="5969" ue="26005" us="26005"/><bf gi="5970" ue="26009" us="26007"/><bf gi="59!
 73" ue="26013" us="26011"/><bf gi="5976" ue="26017" us="26015"/><bf gi
="5979" ue="26023" us="26019"/><bf gi="5984" ue="26032" us="26027"/><bf gi="5990" ue="26036" us="26034"/><bf gi="5993" ue="26039" us="26039"/><bf gi="5994" ue="26041" us="26041"/><bf gi="5995" ue="26045" us="26044"/><bf gi="5997" ue="26047" us="26047"/><bf gi="5998" ue="26054" us="26049"/><bf gi="6004" ue="26057" us="26056"/><bf gi="6006" ue="26060" us="26059"/><bf gi="6008" ue="26064" us="26062"/><bf gi="6011" ue="26066" us="26066"/><bf gi="6012" ue="26068" us="26068"/><bf gi="6013" ue="26073" us="26070"/><bf gi="6017" ue="26075" us="26075"/><bf gi="6018" ue="26082" us="26079"/><bf gi="6022" ue="26089" us="26085"/><bf gi="6027" ue="26093" us="26092"/><bf gi="6029" ue="26098" us="26096"/><bf gi="6032" ue="26101" us="26100"/><bf gi="6034" ue="26107" us="26105"/><bf gi="6037" ue="26112" us="26110"/><bf gi="6040" ue="26116" us="26114"/><bf gi="6043" ue="26122" us="26118"/><bf gi="6048" ue="26127" us="26124"/><bf gi="6052" ue="26134" us="26129"/><bf gi="6058" ue="26161" us="2614!
 0"/><bf gi="6080" ue="26167" us="26163"/><bf gi="6085" ue="26169" us="26169"/><bf gi="6086" ue="26172" us="26172"/><bf gi="6087" ue="26182" us="26175"/><bf gi="6095" ue="26188" us="26185"/><bf gi="6099" ue="26191" us="26190"/><bf gi="6101" ue="26194" us="26193"/><bf gi="6103" ue="26201" us="26199"/><bf gi="6106" ue="26210" us="26203"/><bf gi="6114" ue="26220" us="26212"/><bf gi="6123" ue="26224" us="26222"/><bf gi="6126" ue="26236" us="26227"/><bf gi="6136" ue="26241" us="26238"/><bf gi="6140" ue="26244" us="26243"/><bf gi="6142" ue="26249" us="26247"/><bf gi="6145" ue="26254" us="26251"/><bf gi="6149" ue="26258" us="26256"/><bf gi="6152" ue="26269" us="26262"/><bf gi="6160" ue="26272" us="26271"/><bf gi="6162" ue="26274" us="26274"/><bf gi="6163" ue="26276" us="26276"/><bf gi="6164" ue="26278" us="26278"/><bf gi="6165" ue="26283" us="26283"/><bf gi="6166" ue="26286" us="26285"/><bf gi="6168" ue="26290" us="26289"/><bf gi="6170" ue="26293" us="26292"/><bf gi="6172" ue="2629!
 7" us="26296"/><bf gi="6174" ue="26300" us="26299"/><bf gi="6176" ue="
26308" us="26302"/><bf gi="6183" ue="26313" us="26311"/><bf gi="6186" ue="26316" us="26316"/><bf gi="6187" ue="26319" us="26318"/><bf gi="6189" ue="26324" us="26324"/><bf gi="6190" ue="26326" us="26326"/><bf gi="6191" ue="26333" us="26329"/><bf gi="6196" ue="26336" us="26335"/><bf gi="6198" ue="26342" us="26342"/><bf gi="6199" ue="26345" us="26344"/><bf gi="6201" ue="26348" us="26347"/><bf gi="6203" ue="26350" us="26350"/><bf gi="6204" ue="26352" us="26352"/><bf gi="6205" ue="26357" us="26354"/><bf gi="6209" ue="26368" us="26359"/><bf gi="6219" ue="26371" us="26371"/><bf gi="6220" ue="26373" us="26373"/><bf gi="6221" ue="26377" us="26375"/><bf gi="6224" ue="26379" us="26379"/><bf gi="6225" ue="26383" us="26381"/><bf gi="6228" ue="26391" us="26387"/><bf gi="6233" ue="26393" us="26393"/><bf gi="6234" ue="26400" us="26395"/><bf gi="6240" ue="26402" us="26402"/><bf gi="6241" ue="26408" us="26406"/><bf gi="6244" ue="26414" us="26410"/><bf gi="6249" ue="26417" us="26417"/><bf gi="!
 6250" ue="26420" us="26419"/><bf gi="6252" ue="26424" us="26422"/><bf gi="6255" ue="26426" us="26426"/><bf gi="6256" ue="26431" us="26429"/><bf gi="6259" ue="26433" us="26433"/><bf gi="6260" ue="26441" us="26437"/><bf gi="6265" ue="26444" us="26444"/><bf gi="6266" ue="26449" us="26446"/><bf gi="6270" ue="26454" us="26451"/><bf gi="6274" ue="26457" us="26457"/><bf gi="6275" ue="26470" us="26460"/><bf gi="6286" ue="26474" us="26474"/><bf gi="6287" ue="26487" us="26476"/><bf gi="6299" ue="26492" us="26491"/><bf gi="6301" ue="26495" us="26494"/><bf gi="6303" ue="26497" us="26497"/><bf gi="6304" ue="26501" us="26500"/><bf gi="6306" ue="26503" us="26503"/><bf gi="6307" ue="26505" us="26505"/><bf gi="6308" ue="26508" us="26507"/><bf gi="6310" ue="26513" us="26510"/><bf gi="6314" ue="26515" us="26515"/><bf gi="6315" ue="26525" us="26517"/><bf gi="6324" ue="26530" us="26528"/><bf gi="6327" ue="26534" us="26534"/><bf gi="6328" ue="26537" us="26537"/><bf gi="6329" ue="26553" us="26543!
 "/><bf gi="6340" ue="26557" us="26555"/><bf gi="6343" ue="26566" us="2
6560"/><bf gi="6350" ue="26570" us="26568"/><bf gi="6353" ue="26580" us="26574"/><bf gi="6360" ue="26586" us="26583"/><bf gi="6364" ue="26590" us="26588"/><bf gi="6367" ue="26594" us="26593"/><bf gi="6369" ue="26596" us="26596"/><bf gi="6370" ue="26599" us="26598"/><bf gi="6372" ue="26601" us="26601"/><bf gi="6373" ue="26604" us="26604"/><bf gi="6374" ue="26615" us="26606"/><bf gi="6384" ue="26617" us="26617"/><bf gi="6385" ue="26619" us="26619"/><bf gi="6386" ue="26623" us="26622"/><bf gi="6388" ue="26628" us="26625"/><bf gi="6392" ue="26644" us="26643"/><bf gi="6394" ue="26647" us="26646"/><bf gi="6396" ue="26649" us="26649"/><bf gi="6397" ue="26655" us="26653"/><bf gi="6400" ue="26658" us="26657"/><bf gi="6402" ue="26669" us="26663"/><bf gi="6409" ue="26676" us="26671"/><bf gi="6415" ue="26681" us="26680"/><bf gi="6417" ue="26685" us="26683"/><bf gi="6420" ue="26694" us="26687"/><bf gi="6428" ue="26696" us="26696"/><bf gi="6429" ue="26698" us="26698"/><bf gi="6430" ue="26!
 702" us="26700"/><bf gi="6433" ue="26709" us="26704"/><bf gi="6439" ue="26713" us="26711"/><bf gi="6442" ue="26717" us="26715"/><bf gi="6445" ue="26719" us="26719"/><bf gi="6446" ue="26723" us="26723"/><bf gi="6447" ue="26727" us="26727"/><bf gi="6448" ue="26731" us="26731"/><bf gi="6449" ue="26738" us="26734"/><bf gi="6454" ue="26743" us="26740"/><bf gi="6458" ue="26748" us="26745"/><bf gi="6462" ue="26751" us="26750"/><bf gi="6464" ue="26758" us="26753"/><bf gi="6470" ue="26760" us="26760"/><bf gi="6471" ue="26765" us="26765"/><bf gi="6472" ue="26767" us="26767"/><bf gi="6473" ue="26772" us="26771"/><bf gi="6475" ue="26776" us="26774"/><bf gi="6478" ue="26781" us="26778"/><bf gi="6482" ue="26787" us="26783"/><bf gi="6487" ue="26794" us="26789"/><bf gi="6493" ue="26803" us="26797"/><bf gi="6500" ue="26806" us="26805"/><bf gi="6502" ue="26812" us="26809"/><bf gi="6506" ue="26822" us="26820"/><bf gi="6509" ue="26829" us="26824"/><bf gi="6515" ue="26842" us="26831"/><bf gi="6!
 527" ue="26845" us="26844"/><bf gi="6529" ue="26849" us="26847"/><bf g
i="6532" ue="26851" us="26851"/><bf gi="6533" ue="26853" us="26853"/><bf gi="6534" ue="26856" us="26855"/><bf gi="6536" ue="26866" us="26858"/><bf gi="6545" ue="26870" us="26869"/><bf gi="6547" ue="26877" us="26873"/><bf gi="6552" ue="26881" us="26880"/><bf gi="6554" ue="26886" us="26884"/><bf gi="6557" ue="26899" us="26888"/><bf gi="6569" ue="26903" us="26902"/><bf gi="6571" ue="26908" us="26905"/><bf gi="6575" ue="26915" us="26913"/><bf gi="6578" ue="26918" us="26917"/><bf gi="6580" ue="26920" us="26920"/><bf gi="6581" ue="26922" us="26922"/><bf gi="6582" ue="26929" us="26928"/><bf gi="6584" ue="26934" us="26931"/><bf gi="6588" ue="26937" us="26936"/><bf gi="6590" ue="26939" us="26939"/><bf gi="6591" ue="26941" us="26941"/><bf gi="6592" ue="26943" us="26943"/><bf gi="6593" ue="26946" us="26946"/><bf gi="6594" ue="26949" us="26949"/><bf gi="6595" ue="26954" us="26953"/><bf gi="6597" ue="26958" us="26958"/><bf gi="6598" ue="26965" us="26963"/><bf gi="6601" ue="26967" us="269!
 67"/><bf gi="6602" ue="26974" us="26969"/><bf gi="6608" ue="26982" us="26976"/><bf gi="6615" ue="26997" us="26984"/><bf gi="6629" ue="27010" us="26999"/><bf gi="6641" ue="27018" us="27018"/><bf gi="6642" ue="27022" us="27021"/><bf gi="6644" ue="27026" us="27025"/><bf gi="6646" ue="27030" us="27028"/><bf gi="6649" ue="27032" us="27032"/><bf gi="6650" ue="27036" us="27035"/><bf gi="6652" ue="27041" us="27040"/><bf gi="6654" ue="27048" us="27045"/><bf gi="6658" ue="27051" us="27051"/><bf gi="6659" ue="27055" us="27053"/><bf gi="6662" ue="27058" us="27057"/><bf gi="6664" ue="27060" us="27060"/><bf gi="6665" ue="27064" us="27063"/><bf gi="6667" ue="27068" us="27066"/><bf gi="6670" ue="27071" us="27070"/><bf gi="6672" ue="27073" us="27073"/><bf gi="6673" ue="27075" us="27075"/><bf gi="6674" ue="27077" us="27077"/><bf gi="6675" ue="27080" us="27079"/><bf gi="6677" ue="27086" us="27082"/><bf gi="6682" ue="27089" us="27088"/><bf gi="6684" ue="27091" us="27091"/><bf gi="6685" ue="270!
 97" us="27094"/><bf gi="6689" ue="27102" us="27101"/><bf gi="6691" ue=
"27106" us="27106"/><bf gi="6692" ue="27109" us="27109"/><bf gi="6693" ue="27112" us="27111"/><bf gi="6695" ue="27115" us="27115"/><bf gi="6696" ue="27119" us="27117"/><bf gi="6699" ue="27123" us="27121"/><bf gi="6702" ue="27125" us="27125"/><bf gi="6703" ue="27129" us="27129"/><bf gi="6704" ue="27131" us="27131"/><bf gi="6705" ue="27139" us="27133"/><bf gi="6712" ue="27141" us="27141"/><bf gi="6713" ue="27148" us="27146"/><bf gi="6716" ue="27151" us="27151"/><bf gi="6717" ue="27157" us="27153"/><bf gi="6722" ue="27159" us="27159"/><bf gi="6723" ue="27163" us="27161"/><bf gi="6726" ue="27172" us="27165"/><bf gi="6734" ue="27179" us="27176"/><bf gi="6738" ue="27182" us="27182"/><bf gi="6739" ue="27184" us="27184"/><bf gi="6740" ue="27186" us="27186"/><bf gi="6741" ue="27195" us="27188"/><bf gi="6749" ue="27199" us="27197"/><bf gi="6752" ue="27211" us="27204"/><bf gi="6760" ue="27214" us="27214"/><bf gi="6761" ue="27218" us="27216"/><bf gi="6764" ue="27222" us="27221"/><bf gi=!
 "6766" ue="27225" us="27224"/><bf gi="6768" ue="27227" us="27227"/><bf gi="6769" ue="27231" us="27231"/><bf gi="6770" ue="27234" us="27233"/><bf gi="6772" ue="27236" us="27236"/><bf gi="6773" ue="27239" us="27238"/><bf gi="6775" ue="27243" us="27242"/><bf gi="6777" ue="27251" us="27249"/><bf gi="6780" ue="27256" us="27256"/><bf gi="6781" ue="27265" us="27262"/><bf gi="6785" ue="27268" us="27267"/><bf gi="6787" ue="27271" us="27270"/><bf gi="6789" ue="27273" us="27273"/><bf gi="6790" ue="27275" us="27275"/><bf gi="6791" ue="27278" us="27277"/><bf gi="6793" ue="27281" us="27280"/><bf gi="6795" ue="27287" us="27287"/><bf gi="6796" ue="27296" us="27291"/><bf gi="6802" ue="27299" us="27298"/><bf gi="6804" ue="27301" us="27301"/><bf gi="6805" ue="27308" us="27306"/><bf gi="6808" ue="27313" us="27310"/><bf gi="6812" ue="27316" us="27315"/><bf gi="6814" ue="27320" us="27320"/><bf gi="6815" ue="27323" us="27323"/><bf gi="6816" ue="27327" us="27325"/><bf gi="6819" ue="27331" us="2732!
 9"/><bf gi="6822" ue="27334" us="27334"/><bf gi="6823" ue="27337" us="
27336"/><bf gi="6825" ue="27340" us="27340"/><bf gi="6826" ue="27345" us="27344"/><bf gi="6828" ue="27350" us="27347"/><bf gi="6832" ue="27359" us="27354"/><bf gi="6838" ue="27362" us="27362"/><bf gi="6839" ue="27364" us="27364"/><bf gi="6840" ue="27368" us="27367"/><bf gi="6842" ue="27370" us="27370"/><bf gi="6843" ue="27372" us="27372"/><bf gi="6844" ue="27378" us="27376"/><bf gi="6847" ue="27389" us="27386"/><bf gi="6851" ue="27399" us="27394"/><bf gi="6857" ue="27402" us="27401"/><bf gi="6859" ue="27410" us="27407"/><bf gi="6863" ue="27415" us="27414"/><bf gi="6865" ue="27419" us="27419"/><bf gi="6866" ue="27425" us="27421"/><bf gi="6871" ue="27428" us="27427"/><bf gi="6873" ue="27432" us="27431"/><bf gi="6875" ue="27436" us="27435"/><bf gi="6877" ue="27439" us="27439"/><bf gi="6878" ue="27442" us="27442"/><bf gi="6879" ue="27451" us="27445"/><bf gi="6886" ue="27455" us="27453"/><bf gi="6889" ue="27459" us="27459"/><bf gi="6890" ue="27463" us="27462"/><bf gi="6892" ue="2!
 7466" us="27465"/><bf gi="6894" ue="27470" us="27468"/><bf gi="6897" ue="27472" us="27472"/><bf gi="6898" ue="27476" us="27474"/><bf gi="6901" ue="27478" us="27478"/><bf gi="6902" ue="27481" us="27480"/><bf gi="6904" ue="27483" us="27483"/><bf gi="6905" ue="27485" us="27485"/><bf gi="6906" ue="27492" us="27487"/><bf gi="6912" ue="27495" us="27494"/><bf gi="6914" ue="27499" us="27497"/><bf gi="6917" ue="27504" us="27502"/><bf gi="6920" ue="27509" us="27507"/><bf gi="6923" ue="27513" us="27512"/><bf gi="6925" ue="27515" us="27515"/><bf gi="6926" ue="27520" us="27517"/><bf gi="6930" ue="27526" us="27522"/><bf gi="6935" ue="27531" us="27529"/><bf gi="6938" ue="27533" us="27533"/><bf gi="6939" ue="27544" us="27541"/><bf gi="6943" ue="27547" us="27547"/><bf gi="6944" ue="27552" us="27550"/><bf gi="6947" ue="27556" us="27554"/><bf gi="6950" ue="27573" us="27560"/><bf gi="6964" ue="27584" us="27575"/><bf gi="6974" ue="27590" us="27587"/><bf gi="6978" ue="27593" us="27593"/><bf gi="!
 6979" ue="27598" us="27595"/><bf gi="6983" ue="27604" us="27602"/><bf 
gi="6986" ue="27606" us="27606"/><bf gi="6987" ue="27608" us="27608"/><bf gi="6988" ue="27611" us="27610"/><bf gi="6990" ue="27615" us="27615"/><bf gi="6991" ue="27617" us="27617"/><bf gi="6992" ue="27619" us="27619"/><bf gi="6993" ue="27623" us="27622"/><bf gi="6995" ue="27628" us="27627"/><bf gi="6997" ue="27631" us="27630"/><bf gi="6999" ue="27633" us="27633"/><bf gi="7000" ue="27635" us="27635"/><bf gi="7001" ue="27639" us="27639"/><bf gi="7002" ue="27641" us="27641"/><bf gi="7003" ue="27647" us="27647"/><bf gi="7004" ue="27650" us="27650"/><bf gi="7005" ue="27653" us="27652"/><bf gi="7007" ue="27657" us="27656"/><bf gi="7009" ue="27668" us="27661"/><bf gi="7017" ue="27671" us="27671"/><bf gi="7018" ue="27673" us="27673"/><bf gi="7019" ue="27675" us="27675"/><bf gi="7020" ue="27679" us="27679"/><bf gi="7021" ue="27684" us="27683"/><bf gi="7023" ue="27688" us="27686"/><bf gi="7026" ue="27692" us="27692"/><bf gi="7027" ue="27694" us="27694"/><bf gi="7028" ue="27704" us="27!
 699"/><bf gi="7034" ue="27707" us="27706"/><bf gi="7036" ue="27714" us="27710"/><bf gi="7041" ue="27723" us="27722"/><bf gi="7043" ue="27728" us="27725"/><bf gi="7047" ue="27730" us="27730"/><bf gi="7048" ue="27733" us="27732"/><bf gi="7050" ue="27735" us="27735"/><bf gi="7051" ue="27744" us="27737"/><bf gi="7059" ue="27746" us="27746"/><bf gi="7060" ue="27752" us="27751"/><bf gi="7062" ue="27755" us="27754"/><bf gi="7064" ue="27757" us="27757"/><bf gi="7065" ue="27760" us="27759"/><bf gi="7067" ue="27764" us="27762"/><bf gi="7070" ue="27766" us="27766"/><bf gi="7071" ue="27771" us="27768"/><bf gi="7075" ue="27774" us="27773"/><bf gi="7077" ue="27779" us="27777"/><bf gi="7080" ue="27785" us="27781"/><bf gi="7085" ue="27789" us="27788"/><bf gi="7087" ue="27792" us="27792"/><bf gi="7088" ue="27804" us="27794"/><bf gi="7099" ue="27807" us="27807"/><bf gi="7100" ue="27810" us="27809"/><bf gi="7102" ue="27819" us="27819"/><bf gi="7103" ue="27822" us="27822"/><bf gi="7104" ue="27!
 828" us="27824"/><bf gi="7109" ue="27839" us="27832"/><bf gi="7117" ue
="27842" us="27841"/><bf gi="7119" ue="27846" us="27844"/><bf gi="7122" ue="27850" us="27849"/><bf gi="7124" ue="27853" us="27852"/><bf gi="7126" ue="27863" us="27855"/><bf gi="7135" ue="27869" us="27865"/><bf gi="7140" ue="27875" us="27872"/><bf gi="7144" ue="27877" us="27877"/><bf gi="7145" ue="27884" us="27879"/><bf gi="7151" ue="27892" us="27886"/><bf gi="7158" ue="27908" us="27908"/><bf gi="7159" ue="27911" us="27911"/><bf gi="7160" ue="27916" us="27914"/><bf gi="7163" ue="27919" us="27918"/><bf gi="7165" ue="27923" us="27921"/><bf gi="7168" ue="27927" us="27927"/><bf gi="7169" ue="27931" us="27929"/><bf gi="7172" ue="27935" us="27934"/><bf gi="7174" ue="27947" us="27941"/><bf gi="7181" ue="27951" us="27950"/><bf gi="7183" ue="27955" us="27953"/><bf gi="7186" ue="27958" us="27957"/><bf gi="7188" ue="27961" us="27960"/><bf gi="7190" ue="27967" us="27963"/><bf gi="7195" ue="27969" us="27969"/><bf gi="7196" ue="27973" us="27972"/><bf gi="7198" ue="27991" us="27991"/><bf gi!
 ="7199" ue="27994" us="27993"/><bf gi="7201" ue="27996" us="27996"/><bf gi="7202" ue="27999" us="27998"/><bf gi="7204" ue="28001" us="28001"/><bf gi="7205" ue="28007" us="28003"/><bf gi="7210" ue="28010" us="28009"/><bf gi="7212" ue="28012" us="28012"/><bf gi="7213" ue="28016" us="28014"/><bf gi="7216" ue="28020" us="28020"/><bf gi="7217" ue="28025" us="28023"/><bf gi="7220" ue="28028" us="28028"/><bf gi="7221" ue="28034" us="28034"/><bf gi="7222" ue="28037" us="28037"/><bf gi="7223" ue="28040" us="28039"/><bf gi="7225" ue="28044" us="28044"/><bf gi="7226" ue="28046" us="28046"/><bf gi="7227" ue="28057" us="28049"/><bf gi="7236" ue="28060" us="28059"/><bf gi="7238" ue="28074" us="28074"/><bf gi="7239" ue="28076" us="28076"/><bf gi="7240" ue="28079" us="28079"/><bf gi="7241" ue="28082" us="28082"/><bf gi="7242" ue="28085" us="28084"/><bf gi="7244" ue="28089" us="28087"/><bf gi="7247" ue="28093" us="28092"/><bf gi="7249" ue="28096" us="28095"/><bf gi="7251" ue="28104" us="281!
 00"/><bf gi="7256" ue="28108" us="28106"/><bf gi="7259" ue="28111" us=
"28110"/><bf gi="7261" ue="28114" us="28113"/><bf gi="7263" ue="28118" us="28117"/><bf gi="7265" ue="28121" us="28120"/><bf gi="7267" ue="28123" us="28123"/><bf gi="7268" ue="28130" us="28125"/><bf gi="7274" ue="28134" us="28132"/><bf gi="7277" ue="28140" us="28136"/><bf gi="7282" ue="28156" us="28142"/><bf gi="7297" ue="28160" us="28160"/><bf gi="7298" ue="28165" us="28164"/><bf gi="7300" ue="28171" us="28167"/><bf gi="7305" ue="28179" us="28179"/><bf gi="7306" ue="28181" us="28181"/><bf gi="7307" ue="28187" us="28185"/><bf gi="7310" ue="28199" us="28189"/><bf gi="7321" ue="28201" us="28201"/><bf gi="7322" ue="28207" us="28203"/><bf gi="7327" ue="28210" us="28210"/><bf gi="7328" ue="28214" us="28214"/><bf gi="7329" ue="28220" us="28216"/><bf gi="7334" ue="28222" us="28222"/><bf gi="7335" ue="28229" us="28227"/><bf gi="7338" ue="28235" us="28232"/><bf gi="7342" ue="28239" us="28237"/><bf gi="7345" ue="28244" us="28241"/><bf gi="7349" ue="28248" us="28246"/><bf gi="7352" ue="!
 28255" us="28251"/><bf gi="7357" ue="28259" us="28258"/><bf gi="7359" ue="28264" us="28263"/><bf gi="7361" ue="28267" us="28267"/><bf gi="7362" ue="28271" us="28270"/><bf gi="7364" ue="28275" us="28274"/><bf gi="7366" ue="28278" us="28278"/><bf gi="7367" ue="28283" us="28283"/><bf gi="7368" ue="28288" us="28285"/><bf gi="7372" ue="28290" us="28290"/><bf gi="7373" ue="28301" us="28300"/><bf gi="7375" ue="28304" us="28303"/><bf gi="7377" ue="28307" us="28307"/><bf gi="7378" ue="28310" us="28310"/><bf gi="7379" ue="28313" us="28312"/><bf gi="7381" ue="28317" us="28316"/><bf gi="7383" ue="28320" us="28319"/><bf gi="7385" ue="28322" us="28322"/><bf gi="7386" ue="28325" us="28325"/><bf gi="7387" ue="28327" us="28327"/><bf gi="7388" ue="28330" us="28330"/><bf gi="7389" ue="28335" us="28333"/><bf gi="7392" ue="28339" us="28337"/><bf gi="7395" ue="28343" us="28342"/><bf gi="7397" ue="28347" us="28346"/><bf gi="7399" ue="28349" us="28349"/><bf gi="7400" ue="28357" us="28351"/><bf gi=!
 "7407" ue="28367" us="28359"/><bf gi="7416" ue="28369" us="28369"/><bf
 gi="7417" ue="28373" us="28371"/><bf gi="7420" ue="28382" us="28381"/><bf gi="7422" ue="28399" us="28395"/><bf gi="7427" ue="28402" us="28402"/><bf gi="7428" ue="28404" us="28404"/><bf gi="7429" ue="28409" us="28407"/><bf gi="7432" ue="28411" us="28411"/><bf gi="7433" ue="28415" us="28413"/><bf gi="7436" ue="28418" us="28417"/><bf gi="7438" ue="28420" us="28420"/><bf gi="7439" ue="28422" us="28422"/><bf gi="7440" ue="28426" us="28424"/><bf gi="7443" ue="28429" us="28428"/><bf gi="7445" ue="28431" us="28431"/><bf gi="7446" ue="28433" us="28433"/><bf gi="7447" ue="28438" us="28435"/><bf gi="7451" ue="28440" us="28440"/><bf gi="7452" ue="28443" us="28442"/><bf gi="7454" ue="28448" us="28448"/><bf gi="7455" ue="28451" us="28450"/><bf gi="7457" ue="28454" us="28454"/><bf gi="7458" ue="28461" us="28457"/><bf gi="7463" ue="28467" us="28463"/><bf gi="7468" ue="28470" us="28470"/><bf gi="7469" ue="28472" us="28472"/><bf gi="7470" ue="28476" us="28475"/><bf gi="7472" ue="28479" us="2!
 8478"/><bf gi="7474" ue="28481" us="28481"/><bf gi="7475" ue="28485" us="28485"/><bf gi="7476" ue="28495" us="28495"/><bf gi="7477" ue="28500" us="28497"/><bf gi="7481" ue="28511" us="28503"/><bf gi="7490" ue="28514" us="28513"/><bf gi="7492" ue="28516" us="28516"/><bf gi="7493" ue="28518" us="28518"/><bf gi="7494" ue="28520" us="28520"/><bf gi="7495" ue="28528" us="28524"/><bf gi="7500" ue="28532" us="28532"/><bf gi="7501" ue="28536" us="28536"/><bf gi="7502" ue="28538" us="28538"/><bf gi="7503" ue="28542" us="28540"/><bf gi="7506" ue="28548" us="28544"/><bf gi="7511" ue="28552" us="28550"/><bf gi="7514" ue="28558" us="28555"/><bf gi="7518" ue="28564" us="28560"/><bf gi="7523" ue="28567" us="28566"/><bf gi="7525" ue="28570" us="28570"/><bf gi="7526" ue="28577" us="28575"/><bf gi="7529" ue="28584" us="28579"/><bf gi="7535" ue="28586" us="28586"/><bf gi="7536" ue="28593" us="28590"/><bf gi="7540" ue="28595" us="28595"/><bf gi="7541" ue="28598" us="28597"/><bf gi="7543" ue="2!
 8601" us="28601"/><bf gi="7544" ue="28604" us="28604"/><bf gi="7545" u
e="28611" us="28608"/><bf gi="7549" ue="28616" us="28613"/><bf gi="7553" ue="28618" us="28618"/><bf gi="7554" ue="28629" us="28628"/><bf gi="7556" ue="28632" us="28632"/><bf gi="7557" ue="28635" us="28634"/><bf gi="7559" ue="28641" us="28638"/><bf gi="7563" ue="28644" us="28644"/><bf gi="7564" ue="28649" us="28648"/><bf gi="7566" ue="28652" us="28651"/><bf gi="7568" ue="28657" us="28654"/><bf gi="7572" ue="28659" us="28659"/><bf gi="7573" ue="28662" us="28661"/><bf gi="7575" ue="28666" us="28665"/><bf gi="7577" ue="28670" us="28668"/><bf gi="7580" ue="28673" us="28672"/><bf gi="7582" ue="28679" us="28677"/><bf gi="7585" ue="28681" us="28681"/><bf gi="7586" ue="28683" us="28683"/><bf gi="7587" ue="28685" us="28685"/><bf gi="7588" ue="28687" us="28687"/><bf gi="7589" ue="28689" us="28689"/><bf gi="7590" ue="28693" us="28693"/><bf gi="7591" ue="28696" us="28695"/><bf gi="7593" ue="28699" us="28698"/><bf gi="7595" ue="28704" us="28701"/><bf gi="7599" ue="28707" us="28707"/><bf g!
 i="7600" ue="28712" us="28710"/><bf gi="7603" ue="28716" us="28716"/><bf gi="7604" ue="28720" us="28719"/><bf gi="7606" ue="28722" us="28722"/><bf gi="7607" ue="28724" us="28724"/><bf gi="7608" ue="28727" us="28727"/><bf gi="7609" ue="28729" us="28729"/><bf gi="7610" ue="28732" us="28732"/><bf gi="7611" ue="28734" us="28734"/><bf gi="7612" ue="28740" us="28739"/><bf gi="7614" ue="28748" us="28744"/><bf gi="7619" ue="28750" us="28750"/><bf gi="7620" ue="28753" us="28753"/><bf gi="7621" ue="28757" us="28756"/><bf gi="7623" ue="28760" us="28760"/><bf gi="7624" ue="28766" us="28765"/><bf gi="7626" ue="28773" us="28771"/><bf gi="7629" ue="28780" us="28779"/><bf gi="7631" ue="28784" us="28782"/><bf gi="7634" ue="28790" us="28789"/><bf gi="7636" ue="28792" us="28792"/><bf gi="7637" ue="28798" us="28796"/><bf gi="7640" ue="28801" us="28801"/><bf gi="7641" ue="28806" us="28805"/><bf gi="7643" ue="28810" us="28809"/><bf gi="7645" ue="28814" us="28814"/><bf gi="7646" ue="28818" us="28!
 818"/><bf gi="7647" ue="28825" us="28820"/><bf gi="7653" ue="28827" us
="28827"/><bf gi="7654" ue="28836" us="28836"/><bf gi="7655" ue="28849" us="28843"/><bf gi="7662" ue="28852" us="28851"/><bf gi="7664" ue="28859" us="28855"/><bf gi="7669" ue="28872" us="28872"/><bf gi="7670" ue="28875" us="28874"/><bf gi="7672" ue="28879" us="28879"/><bf gi="7673" ue="28881" us="28881"/><bf gi="7674" ue="28886" us="28883"/><bf gi="7678" ue="28889" us="28888"/><bf gi="7680" ue="28893" us="28892"/><bf gi="7682" ue="28895" us="28895"/><bf gi="7683" ue="28900" us="28900"/><bf gi="7684" ue="28913" us="28913"/><bf gi="7685" ue="28922" us="28921"/><bf gi="7687" ue="28925" us="28925"/><bf gi="7688" ue="28935" us="28931"/><bf gi="7693" ue="28937" us="28937"/><bf gi="7694" ue="28940" us="28939"/><bf gi="7696" ue="28943" us="28943"/><bf gi="7697" ue="28948" us="28948"/><bf gi="7698" ue="28954" us="28953"/><bf gi="7700" ue="28956" us="28956"/><bf gi="7701" ue="28958" us="28958"/><bf gi="7702" ue="28961" us="28960"/><bf gi="7704" ue="28966" us="28966"/><bf gi="7705" ue=!
 "28971" us="28971"/><bf gi="7706" ue="28973" us="28973"/><bf gi="7707" ue="28977" us="28975"/><bf gi="7710" ue="28982" us="28982"/><bf gi="7711" ue="28984" us="28984"/><bf gi="7712" ue="28988" us="28988"/><bf gi="7713" ue="28993" us="28993"/><bf gi="7714" ue="28999" us="28997"/><bf gi="7717" ue="29004" us="29001"/><bf gi="7721" ue="29006" us="29006"/><bf gi="7722" ue="29008" us="29008"/><bf gi="7723" ue="29010" us="29010"/><bf gi="7724" ue="29015" us="29013"/><bf gi="7727" ue="29018" us="29017"/><bf gi="7729" ue="29020" us="29020"/><bf gi="7730" ue="29022" us="29022"/><bf gi="7731" ue="29024" us="29024"/><bf gi="7732" ue="29026" us="29026"/><bf gi="7733" ue="29033" us="29028"/><bf gi="7739" ue="29036" us="29036"/><bf gi="7740" ue="29038" us="29038"/><bf gi="7741" ue="29049" us="29049"/><bf gi="7742" ue="29053" us="29053"/><bf gi="7743" ue="29056" us="29056"/><bf gi="7744" ue="29061" us="29060"/><bf gi="7746" ue="29064" us="29063"/><bf gi="7748" ue="29066" us="29066"/><bf gi!
 ="7749" ue="29068" us="29068"/><bf gi="7750" ue="29071" us="29071"/><b
f gi="7751" ue="29074" us="29074"/><bf gi="7752" ue="29077" us="29076"/><bf gi="7754" ue="29083" us="29081"/><bf gi="7757" ue="29088" us="29087"/><bf gi="7759" ue="29090" us="29090"/><bf gi="7760" ue="29096" us="29096"/><bf gi="7761" ue="29100" us="29100"/><bf gi="7762" ue="29107" us="29103"/><bf gi="7767" ue="29114" us="29113"/><bf gi="7769" ue="29121" us="29118"/><bf gi="7773" ue="29124" us="29123"/><bf gi="7775" ue="29129" us="29128"/><bf gi="7777" ue="29132" us="29131"/><bf gi="7779" ue="29134" us="29134"/><bf gi="7780" ue="29136" us="29136"/><bf gi="7781" ue="29143" us="29138"/><bf gi="7787" ue="29146" us="29145"/><bf gi="7789" ue="29148" us="29148"/><bf gi="7790" ue="29152" us="29151"/><bf gi="7792" ue="29159" us="29157"/><bf gi="7795" ue="29166" us="29164"/><bf gi="7798" ue="29173" us="29173"/><bf gi="7799" ue="29177" us="29176"/><bf gi="7801" ue="29180" us="29179"/><bf gi="7803" ue="29184" us="29182"/><bf gi="7806" ue="29193" us="29190"/><bf gi="7810" ue="29197" us="!
 29197"/><bf gi="7811" ue="29200" us="29200"/><bf gi="7812" ue="29203" us="29203"/><bf gi="7813" ue="29207" us="29207"/><bf gi="7814" ue="29211" us="29210"/><bf gi="7816" ue="29213" us="29213"/><bf gi="7817" ue="29215" us="29215"/><bf gi="7818" ue="29220" us="29220"/><bf gi="7819" ue="29224" us="29224"/><bf gi="7820" ue="29229" us="29226"/><bf gi="7824" ue="29232" us="29231"/><bf gi="7826" ue="29234" us="29234"/><bf gi="7827" ue="29238" us="29236"/><bf gi="7830" ue="29251" us="29240"/><bf gi="7842" ue="29256" us="29253"/><bf gi="7846" ue="29260" us="29259"/><bf gi="7848" ue="29264" us="29262"/><bf gi="7851" ue="29267" us="29266"/><bf gi="7853" ue="29270" us="29269"/><bf gi="7855" ue="29283" us="29272"/><bf gi="7867" ue="29289" us="29287"/><bf gi="7870" ue="29291" us="29291"/><bf gi="7871" ue="29295" us="29294"/><bf gi="7873" ue="29298" us="29297"/><bf gi="7875" ue="29300" us="29300"/><bf gi="7876" ue="29305" us="29303"/><bf gi="7879" ue="29314" us="29307"/><bf gi="7887" ue="!
 29316" us="29316"/><bf gi="7888" ue="29319" us="29319"/><bf gi="7889" 
ue="29321" us="29321"/><bf gi="7890" ue="29326" us="29325"/><bf gi="7892" ue="29331" us="29330"/><bf gi="7894" ue="29334" us="29334"/><bf gi="7895" ue="29339" us="29339"/><bf gi="7896" ue="29344" us="29344"/><bf gi="7897" ue="29346" us="29346"/><bf gi="7898" ue="29352" us="29351"/><bf gi="7900" ue="29359" us="29356"/><bf gi="7904" ue="29362" us="29361"/><bf gi="7906" ue="29364" us="29364"/><bf gi="7907" ue="29366" us="29366"/><bf gi="7908" ue="29369" us="29369"/><bf gi="7909" ue="29374" us="29374"/><bf gi="7910" ue="29380" us="29377"/><bf gi="7914" ue="29383" us="29382"/><bf gi="7916" ue="29385" us="29385"/><bf gi="7917" ue="29388" us="29388"/><bf gi="7918" ue="29390" us="29390"/><bf gi="7919" ue="29392" us="29392"/><bf gi="7920" ue="29394" us="29394"/><bf gi="7921" ue="29401" us="29397"/><bf gi="7926" ue="29403" us="29403"/><bf gi="7927" ue="29410" us="29407"/><bf gi="7931" ue="29413" us="29413"/><bf gi="7932" ue="29417" us="29417"/><bf gi="7933" ue="29421" us="29420"/><bf !
 gi="7935" ue="29428" us="29427"/><bf gi="7937" ue="29438" us="29431"/><bf gi="7945" ue="29442" us="29442"/><bf gi="7946" ue="29445" us="29444"/><bf gi="7948" ue="29447" us="29447"/><bf gi="7949" ue="29451" us="29450"/><bf gi="7951" ue="29453" us="29453"/><bf gi="7952" ue="29459" us="29458"/><bf gi="7954" ue="29465" us="29462"/><bf gi="7958" ue="29471" us="29467"/><bf gi="7963" ue="29474" us="29474"/><bf gi="7964" ue="29477" us="29476"/><bf gi="7966" ue="29484" us="29479"/><bf gi="7972" ue="29487" us="29486"/><bf gi="7974" ue="29490" us="29489"/><bf gi="7976" ue="29495" us="29492"/><bf gi="7980" ue="29499" us="29498"/><bf gi="7982" ue="29503" us="29501"/><bf gi="7985" ue="29509" us="29507"/><bf gi="7988" ue="29520" us="29517"/><bf gi="7992" ue="29522" us="29522"/><bf gi="7993" ue="29528" us="29526"/><bf gi="7996" ue="29536" us="29533"/><bf gi="8000" ue="29539" us="29539"/><bf gi="8001" ue="29548" us="29542"/><bf gi="8008" ue="29554" us="29550"/><bf gi="8013" ue="29557" us="2!
 9557"/><bf gi="8014" ue="29564" us="29559"/><bf gi="8020" ue="29569" u
s="29568"/><bf gi="8022" ue="29575" us="29571"/><bf gi="8027" ue="29577" us="29577"/><bf gi="8028" ue="29579" us="29579"/><bf gi="8029" ue="29582" us="29582"/><bf gi="8030" ue="29584" us="29584"/><bf gi="8031" ue="29587" us="29587"/><bf gi="8032" ue="29592" us="29589"/><bf gi="8036" ue="29596" us="29596"/><bf gi="8037" ue="29600" us="29598"/><bf gi="8040" ue="29602" us="29602"/><bf gi="8041" ue="29606" us="29605"/><bf gi="8043" ue="29611" us="29609"/><bf gi="8046" ue="29613" us="29613"/><bf gi="8047" ue="29619" us="29618"/><bf gi="8049" ue="29621" us="29621"/><bf gi="8050" ue="29623" us="29623"/><bf gi="8051" ue="29625" us="29625"/><bf gi="8052" ue="29629" us="29627"/><bf gi="8055" ue="29632" us="29631"/><bf gi="8057" ue="29634" us="29634"/><bf gi="8058" ue="29638" us="29637"/><bf gi="8060" ue="29647" us="29640"/><bf gi="8068" ue="29651" us="29650"/><bf gi="8070" ue="29654" us="29654"/><bf gi="8071" ue="29657" us="29657"/><bf gi="8072" ue="29662" us="29661"/><bf gi="8074" ue!
 ="29665" us="29664"/><bf gi="8076" ue="29667" us="29667"/><bf gi="8077" ue="29671" us="29669"/><bf gi="8080" ue="29674" us="29673"/><bf gi="8082" ue="29678" us="29677"/><bf gi="8084" ue="29681" us="29681"/><bf gi="8085" ue="29685" us="29684"/><bf gi="8087" ue="29691" us="29687"/><bf gi="8092" ue="29697" us="29693"/><bf gi="8097" ue="29703" us="29699"/><bf gi="8102" ue="29706" us="29705"/><bf gi="8104" ue="29713" us="29713"/><bf gi="8105" ue="29723" us="29722"/><bf gi="8107" ue="29730" us="29730"/><bf gi="8108" ue="29734" us="29732"/><bf gi="8111" ue="29750" us="29736"/><bf gi="8126" ue="29754" us="29753"/><bf gi="8128" ue="29761" us="29759"/><bf gi="8131" ue="29764" us="29763"/><bf gi="8133" ue="29767" us="29766"/><bf gi="8135" ue="29771" us="29771"/><bf gi="8136" ue="29773" us="29773"/><bf gi="8137" ue="29778" us="29777"/><bf gi="8139" ue="29781" us="29781"/><bf gi="8140" ue="29783" us="29783"/><bf gi="8141" ue="29792" us="29785"/><bf gi="8149" ue="29796" us="29794"/><bf g!
 i="8152" ue="29803" us="29798"/><bf gi="8158" ue="29811" us="29805"/><
bf gi="8165" ue="29814" us="29814"/><bf gi="8166" ue="29822" us="29822"/><bf gi="8167" ue="29825" us="29824"/><bf gi="8169" ue="29827" us="29827"/><bf gi="8170" ue="29831" us="29829"/><bf gi="8173" ue="29833" us="29833"/><bf gi="8174" ue="29835" us="29835"/><bf gi="8175" ue="29842" us="29839"/><bf gi="8179" ue="29850" us="29848"/><bf gi="8182" ue="29852" us="29852"/><bf gi="8183" ue="29859" us="29854"/><bf gi="8189" ue="29867" us="29862"/><bf gi="8195" ue="29874" us="29870"/><bf gi="8200" ue="29877" us="29877"/><bf gi="8201" ue="29881" us="29881"/><bf gi="8202" ue="29883" us="29883"/><bf gi="8203" ue="29885" us="29885"/><bf gi="8204" ue="29887" us="29887"/><bf gi="8205" ue="29898" us="29896"/><bf gi="8208" ue="29900" us="29900"/><bf gi="8209" ue="29904" us="29903"/><bf gi="8211" ue="29908" us="29907"/><bf gi="8213" ue="29912" us="29912"/><bf gi="8214" ue="29916" us="29914"/><bf gi="8217" ue="29920" us="29918"/><bf gi="8220" ue="29924" us="29922"/><bf gi="8223" ue="29931" us=!
 "29926"/><bf gi="8229" ue="29938" us="29934"/><bf gi="8234" ue="29940" us="29940"/><bf gi="8235" ue="29944" us="29942"/><bf gi="8238" ue="29948" us="29946"/><bf gi="8241" ue="29951" us="29951"/><bf gi="8242" ue="29953" us="29953"/><bf gi="8243" ue="29958" us="29955"/><bf gi="8247" ue="29966" us="29964"/><bf gi="8250" ue="29971" us="29969"/><bf gi="8253" ue="29976" us="29973"/><bf gi="8257" ue="29978" us="29978"/><bf gi="8258" ue="29980" us="29980"/><bf gi="8259" ue="29985" us="29982"/><bf gi="8263" ue="29996" us="29987"/><bf gi="8273" ue="30003" us="29999"/><bf gi="8278" ue="30016" us="30006"/><bf gi="8289" ue="30020" us="30019"/><bf gi="8291" ue="30034" us="30022"/><bf gi="8304" ue="30036" us="30036"/><bf gi="8305" ue="30039" us="30039"/><bf gi="8306" ue="30050" us="30041"/><bf gi="8316" ue="30055" us="30052"/><bf gi="8320" ue="30059" us="30057"/><bf gi="8323" ue="30061" us="30061"/><bf gi="8324" ue="30065" us="30063"/><bf gi="8327" ue="30068" us="30067"/><bf gi="8329" ue=!
 "30079" us="30070"/><bf gi="8339" ue="30082" us="30081"/><bf gi="8341"
 ue="30087" us="30085"/><bf gi="8344" ue="30091" us="30089"/><bf gi="8347" ue="30101" us="30094"/><bf gi="8355" ue="30106" us="30105"/><bf gi="8357" ue="30109" us="30108"/><bf gi="8359" ue="30117" us="30114"/><bf gi="8363" ue="30123" us="30123"/><bf gi="8364" ue="30133" us="30129"/><bf gi="8369" ue="30138" us="30136"/><bf gi="8372" ue="30151" us="30140"/><bf gi="8384" ue="30154" us="30154"/><bf gi="8385" ue="30159" us="30156"/><bf gi="8389" ue="30162" us="30162"/><bf gi="8390" ue="30165" us="30164"/><bf gi="8392" ue="30169" us="30167"/><bf gi="8395" ue="30172" us="30171"/><bf gi="8397" ue="30180" us="30174"/><bf gi="8404" ue="30183" us="30183"/><bf gi="8405" ue="30185" us="30185"/><bf gi="8406" ue="30188" us="30188"/><bf gi="8407" ue="30196" us="30190"/><bf gi="8414" ue="30202" us="30201"/><bf gi="8416" ue="30204" us="30204"/><bf gi="8417" ue="30212" us="30206"/><bf gi="8424" ue="30221" us="30215"/><bf gi="8431" ue="30223" us="30223"/><bf gi="8432" ue="30227" us="30226"/><bf!
  gi="8434" ue="30230" us="30229"/><bf gi="8436" ue="30233" us="30233"/><bf gi="8437" ue="30247" us="30235"/><bf gi="8450" ue="30249" us="30249"/><bf gi="8451" ue="30253" us="30253"/><bf gi="8452" ue="30256" us="30256"/><bf gi="8453" ue="30261" us="30258"/><bf gi="8457" ue="30268" us="30264"/><bf gi="8462" ue="30284" us="30272"/><bf gi="8475" ue="30290" us="30290"/><bf gi="8476" ue="30294" us="30293"/><bf gi="8478" ue="30297" us="30296"/><bf gi="8480" ue="30300" us="30300"/><bf gi="8481" ue="30303" us="30303"/><bf gi="8482" ue="30306" us="30305"/><bf gi="8484" ue="30309" us="30308"/><bf gi="8486" ue="30314" us="30311"/><bf gi="8490" ue="30322" us="30316"/><bf gi="8497" ue="30324" us="30324"/><bf gi="8498" ue="30326" us="30326"/><bf gi="8499" ue="30328" us="30328"/><bf gi="8500" ue="30334" us="30330"/><bf gi="8505" ue="30344" us="30336"/><bf gi="8514" ue="30350" us="30347"/><bf gi="8518" ue="30352" us="30352"/><bf gi="8519" ue="30355" us="30355"/><bf gi="8520" ue="30358" us="!
 30357"/><bf gi="8522" ue="30368" us="30361"/><bf gi="8530" ue="30376" 
us="30370"/><bf gi="8537" ue="30378" us="30378"/><bf gi="8538" ue="30382" us="30381"/><bf gi="8540" ue="30384" us="30384"/><bf gi="8541" ue="30388" us="30388"/><bf gi="8542" ue="30394" us="30391"/><bf gi="8546" ue="30397" us="30397"/><bf gi="8547" ue="30399" us="30399"/><bf gi="8548" ue="30403" us="30401"/><bf gi="8551" ue="30406" us="30405"/><bf gi="8553" ue="30414" us="30408"/><bf gi="8560" ue="30418" us="30418"/><bf gi="8561" ue="30420" us="30420"/><bf gi="8562" ue="30423" us="30422"/><bf gi="8564" ue="30425" us="30425"/><bf gi="8565" ue="30428" us="30427"/><bf gi="8567" ue="30433" us="30430"/><bf gi="8571" ue="30440" us="30435"/><bf gi="8577" ue="30442" us="30442"/><bf gi="8578" ue="30444" us="30444"/><bf gi="8579" ue="30446" us="30446"/><bf gi="8580" ue="30450" us="30448"/><bf gi="8583" ue="30452" us="30452"/><bf gi="8584" ue="30454" us="30454"/><bf gi="8585" ue="30457" us="30456"/><bf gi="8587" ue="30460" us="30459"/><bf gi="8589" ue="30462" us="30462"/><bf gi="8590" u!
 e="30465" us="30464"/><bf gi="8592" ue="30468" us="30468"/><bf gi="8593" ue="30476" us="30470"/><bf gi="8600" ue="30478" us="30478"/><bf gi="8601" ue="30482" us="30482"/><bf gi="8602" ue="30485" us="30484"/><bf gi="8604" ue="30487" us="30487"/><bf gi="8605" ue="30492" us="30489"/><bf gi="8609" ue="30496" us="30494"/><bf gi="8612" ue="30498" us="30498"/><bf gi="8613" ue="30502" us="30500"/><bf gi="8616" ue="30505" us="30504"/><bf gi="8618" ue="30511" us="30509"/><bf gi="8621" ue="30522" us="30516"/><bf gi="8628" ue="30526" us="30524"/><bf gi="8631" ue="30528" us="30528"/><bf gi="8632" ue="30530" us="30530"/><bf gi="8633" ue="30535" us="30533"/><bf gi="8636" ue="30538" us="30538"/><bf gi="8637" ue="30543" us="30541"/><bf gi="8640" ue="30546" us="30546"/><bf gi="8641" ue="30551" us="30550"/><bf gi="8643" ue="30556" us="30554"/><bf gi="8646" ue="30568" us="30558"/><bf gi="8657" ue="30572" us="30570"/><bf gi="8660" ue="30576" us="30576"/><bf gi="8661" ue="30580" us="30578"/><bf !
 gi="8664" ue="30586" us="30585"/><bf gi="8666" ue="30592" us="30589"/>
<bf gi="8670" ue="30596" us="30596"/><bf gi="8671" ue="30606" us="30603"/><bf gi="8675" ue="30609" us="30609"/><bf gi="8676" ue="30614" us="30612"/><bf gi="8679" ue="30618" us="30618"/><bf gi="8680" ue="30624" us="30622"/><bf gi="8683" ue="30626" us="30626"/><bf gi="8684" ue="30629" us="30629"/><bf gi="8685" ue="30631" us="30631"/><bf gi="8686" ue="30634" us="30634"/><bf gi="8687" ue="30641" us="30636"/><bf gi="8693" ue="30643" us="30643"/><bf gi="8694" ue="30646" us="30645"/><bf gi="8696" ue="30649" us="30649"/><bf gi="8697" ue="30655" us="30651"/><bf gi="8702" ue="30659" us="30659"/><bf gi="8703" ue="30663" us="30663"/><bf gi="8704" ue="30665" us="30665"/><bf gi="8705" ue="30669" us="30669"/><bf gi="8706" ue="30674" us="30673"/><bf gi="8708" ue="30677" us="30677"/><bf gi="8709" ue="30679" us="30679"/><bf gi="8710" ue="30684" us="30681"/><bf gi="8714" ue="30688" us="30686"/><bf gi="8717" ue="30695" us="30690"/><bf gi="8723" ue="30698" us="30697"/><bf gi="8725" ue="30705" us!
 ="30700"/><bf gi="8731" ue="30708" us="30707"/><bf gi="8733" ue="30712" us="30712"/><bf gi="8734" ue="30716" us="30715"/><bf gi="8736" ue="30722" us="30722"/><bf gi="8737" ue="30726" us="30725"/><bf gi="8739" ue="30729" us="30729"/><bf gi="8740" ue="30734" us="30732"/><bf gi="8743" ue="30738" us="30737"/><bf gi="8745" ue="30741" us="30740"/><bf gi="8747" ue="30749" us="30749"/><bf gi="8748" ue="30755" us="30752"/><bf gi="8752" ue="30759" us="30757"/><bf gi="8755" ue="30766" us="30765"/><bf gi="8757" ue="30768" us="30768"/><bf gi="8758" ue="30770" us="30770"/><bf gi="8759" ue="30773" us="30772"/><bf gi="8761" ue="30775" us="30775"/><bf gi="8762" ue="30778" us="30778"/><bf gi="8763" ue="30783" us="30783"/><bf gi="8764" ue="30789" us="30787"/><bf gi="8767" ue="30792" us="30791"/><bf gi="8769" ue="30796" us="30796"/><bf gi="8770" ue="30798" us="30798"/><bf gi="8771" ue="30802" us="30802"/><bf gi="8772" ue="30814" us="30812"/><bf gi="8775" ue="30817" us="30816"/><bf gi="8777" ue!
 ="30820" us="30819"/><bf gi="8779" ue="30824" us="30824"/><bf gi="8780
" ue="30828" us="30826"/><bf gi="8783" ue="30831" us="30830"/><bf gi="8785" ue="30834" us="30834"/><bf gi="8786" ue="30836" us="30836"/><bf gi="8787" ue="30842" us="30842"/><bf gi="8788" ue="30844" us="30844"/><bf gi="8789" ue="30846" us="30846"/><bf gi="8790" ue="30849" us="30849"/><bf gi="8791" ue="30855" us="30854"/><bf gi="8793" ue="30858" us="30858"/><bf gi="8794" ue="30863" us="30860"/><bf gi="8798" ue="30865" us="30865"/><bf gi="8799" ue="30869" us="30867"/><bf gi="8802" ue="30872" us="30871"/><bf gi="8804" ue="30874" us="30874"/><bf gi="8805" ue="30879" us="30877"/><bf gi="8808" ue="30881" us="30881"/><bf gi="8809" ue="30884" us="30883"/><bf gi="8811" ue="30890" us="30887"/><bf gi="8815" ue="30893" us="30892"/><bf gi="8817" ue="30899" us="30895"/><bf gi="8822" ue="30901" us="30901"/><bf gi="8823" ue="30911" us="30906"/><bf gi="8829" ue="30913" us="30913"/><bf gi="8830" ue="30924" us="30917"/><bf gi="8838" ue="30926" us="30926"/><bf gi="8839" ue="30934" us="30928"/><b!
 f gi="8846" ue="30939" us="30938"/><bf gi="8848" ue="30945" us="30943"/><bf gi="8851" ue="30948" us="30948"/><bf gi="8852" ue="30952" us="30950"/><bf gi="8855" ue="30954" us="30954"/><bf gi="8856" ue="30956" us="30956"/><bf gi="8857" ue="30959" us="30959"/><bf gi="8858" ue="30964" us="30962"/><bf gi="8861" ue="30967" us="30966"/><bf gi="8863" ue="30971" us="30970"/><bf gi="8865" ue="30973" us="30973"/><bf gi="8866" ue="30977" us="30975"/><bf gi="8869" ue="30983" us="30982"/><bf gi="8871" ue="30988" us="30988"/><bf gi="8872" ue="30990" us="30990"/><bf gi="8873" ue="30994" us="30992"/><bf gi="8876" ue="31002" us="31001"/><bf gi="8878" ue="31004" us="31004"/><bf gi="8879" ue="31008" us="31006"/><bf gi="8882" ue="31015" us="31013"/><bf gi="8885" ue="31021" us="31017"/><bf gi="8890" ue="31025" us="31024"/><bf gi="8892" ue="31029" us="31028"/><bf gi="8894" ue="31041" us="31034"/><bf gi="8902" ue="31051" us="31044"/><bf gi="8910" ue="31057" us="31055"/><bf gi="8913" ue="31064" us=!
 "31059"/><bf gi="8919" ue="31072" us="31066"/><bf gi="8926" ue="31074"
 us="31074"/><bf gi="8927" ue="31077" us="31077"/><bf gi="8928" ue="31081" us="31079"/><bf gi="8931" ue="31083" us="31083"/><bf gi="8932" ue="31085" us="31085"/><bf gi="8933" ue="31090" us="31090"/><bf gi="8934" ue="31095" us="31095"/><bf gi="8935" ue="31100" us="31097"/><bf gi="8939" ue="31105" us="31102"/><bf gi="8943" ue="31109" us="31108"/><bf gi="8945" ue="31119" us="31114"/><bf gi="8951" ue="31121" us="31121"/><bf gi="8952" ue="31126" us="31123"/><bf gi="8956" ue="31128" us="31128"/><bf gi="8957" ue="31133" us="31131"/><bf gi="8960" ue="31137" us="31137"/><bf gi="8961" ue="31147" us="31142"/><bf gi="8967" ue="31153" us="31150"/><bf gi="8971" ue="31156" us="31155"/><bf gi="8973" ue="31163" us="31160"/><bf gi="8977" ue="31170" us="31165"/><bf gi="8983" ue="31172" us="31172"/><bf gi="8984" ue="31179" us="31175"/><bf gi="8989" ue="31183" us="31183"/><bf gi="8990" ue="31186" us="31185"/><bf gi="8992" ue="31190" us="31188"/><bf gi="8995" ue="31192" us="31192"/><bf gi="8996" !
 ue="31194" us="31194"/><bf gi="8997" ue="31207" us="31197"/><bf gi="9008" ue="31213" us="31209"/><bf gi="9013" ue="31217" us="31216"/><bf gi="9015" ue="31224" us="31224"/><bf gi="9016" ue="31228" us="31227"/><bf gi="9018" ue="31232" us="31232"/><bf gi="9019" ue="31235" us="31234"/><bf gi="9021" ue="31246" us="31239"/><bf gi="9029" ue="31249" us="31249"/><bf gi="9030" ue="31253" us="31252"/><bf gi="9032" ue="31260" us="31255"/><bf gi="9038" ue="31265" us="31262"/><bf gi="9042" ue="31271" us="31271"/><bf gi="9043" ue="31275" us="31275"/><bf gi="9044" ue="31282" us="31277"/><bf gi="9050" ue="31285" us="31284"/><bf gi="9052" ue="31296" us="31287"/><bf gi="9062" ue="31305" us="31298"/><bf gi="9070" ue="31312" us="31308"/><bf gi="9075" ue="31319" us="31317"/><bf gi="9078" ue="31321" us="31321"/><bf gi="9079" ue="31325" us="31324"/><bf gi="9081" ue="31331" us="31327"/><bf gi="9086" ue="31333" us="31333"/><bf gi="9087" ue="31335" us="31335"/><bf gi="9088" ue="31339" us="31337"/><bf!
  gi="9091" ue="31341" us="31341"/><bf gi="9092" ue="31344" us="31344"/
><bf gi="9093" ue="31350" us="31348"/><bf gi="9096" ue="31354" us="31352"/><bf gi="9099" ue="31366" us="31357"/><bf gi="9109" ue="31368" us="31368"/><bf gi="9110" ue="31371" us="31370"/><bf gi="9112" ue="31384" us="31376"/><bf gi="9121" ue="31392" us="31390"/><bf gi="9124" ue="31395" us="31395"/><bf gi="9125" ue="31402" us="31401"/><bf gi="9127" ue="31404" us="31404"/><bf gi="9128" ue="31408" us="31406"/><bf gi="9131" ue="31411" us="31411"/><bf gi="9132" ue="31414" us="31413"/><bf gi="9134" ue="31420" us="31417"/><bf gi="9138" ue="31423" us="31423"/><bf gi="9139" ue="31439" us="31427"/><bf gi="9152" ue="31443" us="31441"/><bf gi="9155" ue="31445" us="31445"/><bf gi="9156" ue="31453" us="31449"/><bf gi="9161" ue="31459" us="31455"/><bf gi="9166" ue="31469" us="31461"/><bf gi="9175" ue="31473" us="31471"/><bf gi="9178" ue="31476" us="31476"/><bf gi="9179" ue="31478" us="31478"/><bf gi="9180" ue="31483" us="31480"/><bf gi="9184" ue="31487" us="31485"/><bf gi="9187" ue="31490" u!
 s="31490"/><bf gi="9188" ue="31492" us="31492"/><bf gi="9189" ue="31496" us="31494"/><bf gi="9192" ue="31499" us="31498"/><bf gi="9194" ue="31503" us="31503"/><bf gi="9195" ue="31505" us="31505"/><bf gi="9196" ue="31508" us="31508"/><bf gi="9197" ue="31513" us="31512"/><bf gi="9199" ue="31515" us="31515"/><bf gi="9200" ue="31520" us="31518"/><bf gi="9203" ue="31523" us="31523"/><bf gi="9204" ue="31537" us="31525"/><bf gi="9217" ue="31542" us="31539"/><bf gi="9221" ue="31545" us="31545"/><bf gi="9222" ue="31549" us="31549"/><bf gi="9223" ue="31553" us="31551"/><bf gi="9226" ue="31561" us="31557"/><bf gi="9231" ue="31570" us="31563"/><bf gi="9239" ue="31574" us="31572"/><bf gi="9242" ue="31581" us="31581"/><bf gi="9243" ue="31584" us="31584"/><bf gi="9244" ue="31591" us="31588"/><bf gi="9248" ue="31594" us="31593"/><bf gi="9250" ue="31605" us="31596"/><bf gi="9260" ue="31607" us="31607"/><bf gi="9261" ue="31610" us="31610"/><bf gi="9262" ue="31620" us="31620"/><bf gi="9263" u!
 e="31623" us="31622"/><bf gi="9265" ue="31625" us="31625"/><bf gi="926
6" ue="31627" us="31627"/><bf gi="9267" ue="31634" us="31629"/><bf gi="9273" ue="31649" us="31636"/><bf gi="9287" ue="31653" us="31653"/><bf gi="9288" ue="31658" us="31658"/><bf gi="9289" ue="31661" us="31660"/><bf gi="9291" ue="31666" us="31663"/><bf gi="9295" ue="31670" us="31668"/><bf gi="9298" ue="31672" us="31672"/><bf gi="9299" ue="31677" us="31674"/><bf gi="9303" ue="31682" us="31680"/><bf gi="9306" ue="31692" us="31684"/><bf gi="9315" ue="31695" us="31695"/><bf gi="9316" ue="31700" us="31700"/><bf gi="9317" ue="31703" us="31702"/><bf gi="9319" ue="31707" us="31705"/><bf gi="9322" ue="31709" us="31709"/><bf gi="9323" ue="31712" us="31712"/><bf gi="9324" ue="31718" us="31716"/><bf gi="9327" ue="31722" us="31720"/><bf gi="9330" ue="31725" us="31725"/><bf gi="9331" ue="31738" us="31730"/><bf gi="9340" ue="31740" us="31740"/><bf gi="9341" ue="31742" us="31742"/><bf gi="9342" ue="31748" us="31744"/><bf gi="9347" ue="31751" us="31750"/><bf gi="9349" ue="31753" us="31753"/><!
 bf gi="9350" ue="31759" us="31755"/><bf gi="9355" ue="31764" us="31761"/><bf gi="9359" ue="31767" us="31767"/><bf gi="9360" ue="31769" us="31769"/><bf gi="9361" ue="31771" us="31771"/><bf gi="9362" ue="31777" us="31775"/><bf gi="9365" ue="31779" us="31779"/><bf gi="9366" ue="31784" us="31781"/><bf gi="9370" ue="31788" us="31786"/><bf gi="9373" ue="31793" us="31793"/><bf gi="9374" ue="31796" us="31795"/><bf gi="9376" ue="31802" us="31798"/><bf gi="9381" ue="31808" us="31805"/><bf gi="9385" ue="31811" us="31811"/><bf gi="9386" ue="31814" us="31814"/><bf gi="9387" ue="31818" us="31818"/><bf gi="9388" ue="31821" us="31820"/><bf gi="9390" ue="31830" us="31823"/><bf gi="9398" ue="31841" us="31832"/><bf gi="9408" ue="31845" us="31843"/><bf gi="9411" ue="31847" us="31847"/><bf gi="9412" ue="31849" us="31849"/><bf gi="9413" ue="31854" us="31852"/><bf gi="9416" ue="31856" us="31856"/><bf gi="9417" ue="31859" us="31858"/><bf gi="9419" ue="31861" us="31861"/><bf gi="9420" ue="31865" us!
 ="31865"/><bf gi="9421" ue="31870" us="31868"/><bf gi="9424" ue="31875
" us="31873"/><bf gi="9427" ue="31879" us="31878"/><bf gi="9429" ue="31881" us="31881"/><bf gi="9430" ue="31883" us="31883"/><bf gi="9431" ue="31885" us="31885"/><bf gi="9432" ue="31888" us="31887"/><bf gi="9434" ue="31890" us="31890"/><bf gi="9435" ue="31893" us="31892"/><bf gi="9437" ue="31896" us="31895"/><bf gi="9439" ue="31899" us="31899"/><bf gi="9440" ue="31906" us="31902"/><bf gi="9445" ue="31912" us="31908"/><bf gi="9450" ue="31915" us="31915"/><bf gi="9451" ue="31918" us="31917"/><bf gi="9453" ue="31923" us="31920"/><bf gi="9457" ue="31927" us="31926"/><bf gi="9459" ue="31936" us="31929"/><bf gi="9467" ue="31938" us="31938"/><bf gi="9468" ue="31941" us="31940"/><bf gi="9470" ue="31946" us="31943"/><bf gi="9474" ue="31951" us="31949"/><bf gi="9477" ue="31962" us="31954"/><bf gi="9486" ue="31968" us="31964"/><bf gi="9491" ue="31970" us="31970"/><bf gi="9492" ue="31975" us="31974"/><bf gi="9494" ue="31977" us="31977"/><bf gi="9495" ue="31979" us="31979"/><bf gi="9496"!
  ue="31983" us="31983"/><bf gi="9497" ue="31986" us="31986"/><bf gi="9498" ue="31990" us="31988"/><bf gi="9501" ue="31992" us="31992"/><bf gi="9502" ue="31995" us="31994"/><bf gi="9504" ue="31998" us="31998"/><bf gi="9505" ue="32000" us="32000"/><bf gi="9506" ue="32011" us="32002"/><bf gi="9516" ue="32013" us="32013"/><bf gi="9517" ue="32030" us="32015"/><bf gi="9533" ue="32035" us="32032"/><bf gi="9537" ue="32038" us="32038"/><bf gi="9538" ue="32051" us="32042"/><bf gi="9548" ue="32053" us="32053"/><bf gi="9549" ue="32058" us="32057"/><bf gi="9551" ue="32072" us="32060"/><bf gi="9564" ue="32081" us="32075"/><bf gi="9571" ue="32083" us="32083"/><bf gi="9572" ue="32087" us="32086"/><bf gi="9574" ue="32094" us="32089"/><bf gi="9580" ue="32099" us="32097"/><bf gi="9583" ue="32104" us="32101"/><bf gi="9587" ue="32106" us="32106"/><bf gi="9588" ue="32110" us="32110"/><bf gi="9589" ue="32115" us="32112"/><bf gi="9593" ue="32118" us="32117"/><bf gi="9595" ue="32123" us="32120"/><b!
 f gi="9599" ue="32125" us="32125"/><bf gi="9600" ue="32127" us="32127"
/><bf gi="9601" ue="32131" us="32129"/><bf gi="9604" ue="32134" us="32133"/><bf gi="9606" ue="32137" us="32136"/><bf gi="9608" ue="32141" us="32139"/><bf gi="9611" ue="32143" us="32143"/><bf gi="9612" ue="32145" us="32145"/><bf gi="9613" ue="32147" us="32147"/><bf gi="9614" ue="32151" us="32150"/><bf gi="9616" ue="32160" us="32153"/><bf gi="9624" ue="32163" us="32162"/><bf gi="9626" ue="32167" us="32166"/><bf gi="9628" ue="32187" us="32170"/><bf gi="9646" ue="32191" us="32189"/><bf gi="9649" ue="32199" us="32194"/><bf gi="9655" ue="32207" us="32202"/><bf gi="9661" ue="32210" us="32209"/><bf gi="9663" ue="32218" us="32213"/><bf gi="9669" ue="32222" us="32220"/><bf gi="9672" ue="32226" us="32224"/><bf gi="9675" ue="32230" us="32228"/><bf gi="9678" ue="32237" us="32232"/><bf gi="9684" ue="32239" us="32239"/><bf gi="9685" ue="32242" us="32241"/><bf gi="9687" ue="32246" us="32244"/><bf gi="9690" ue="32251" us="32249"/><bf gi="9693" ue="32257" us="32256"/><bf gi="9695" ue="32261" !
 us="32260"/><bf gi="9697" ue="32267" us="32264"/><bf gi="9701" ue="32274" us="32272"/><bf gi="9704" ue="32277" us="32277"/><bf gi="9705" ue="32279" us="32279"/><bf gi="9706" ue="32291" us="32283"/><bf gi="9715" ue="32296" us="32294"/><bf gi="9718" ue="32303" us="32299"/><bf gi="9723" ue="32307" us="32305"/><bf gi="9726" ue="32311" us="32309"/><bf gi="9729" ue="32315" us="32313"/><bf gi="9732" ue="32319" us="32317"/><bf gi="9735" ue="32321" us="32321"/><bf gi="9736" ue="32327" us="32323"/><bf gi="9741" ue="32331" us="32330"/><bf gi="9743" ue="32334" us="32333"/><bf gi="9745" ue="32336" us="32336"/><bf gi="9746" ue="32338" us="32338"/><bf gi="9747" ue="32342" us="32340"/><bf gi="9750" ue="32346" us="32344"/><bf gi="9753" ue="32351" us="32349"/><bf gi="9756" ue="32354" us="32353"/><bf gi="9758" ue="32359" us="32357"/><bf gi="9761" ue="32363" us="32361"/><bf gi="9764" ue="32368" us="32365"/><bf gi="9768" ue="32371" us="32371"/><bf gi="9769" ue="32377" us="32376"/><bf gi="9771" !
 ue="32383" us="32379"/><bf gi="9776" ue="32387" us="32385"/><bf gi="97
79" ue="32394" us="32390"/><bf gi="9784" ue="32406" us="32396"/><bf gi="9795" ue="32408" us="32408"/><bf gi="9796" ue="32414" us="32410"/><bf gi="9801" ue="32566" us="32566"/><bf gi="9802" ue="32568" us="32568"/><bf gi="9803" ue="32575" us="32570"/><bf gi="9809" ue="32581" us="32579"/><bf gi="9812" ue="32583" us="32583"/><bf gi="9813" ue="32597" us="32588"/><bf gi="9823" ue="32600" us="32600"/><bf gi="9824" ue="32605" us="32603"/><bf gi="9827" ue="32609" us="32607"/><bf gi="9830" ue="32619" us="32611"/><bf gi="9839" ue="32622" us="32621"/><bf gi="9841" ue="32626" us="32624"/><bf gi="9844" ue="32629" us="32629"/><bf gi="9845" ue="32633" us="32631"/><bf gi="9848" ue="32640" us="32637"/><bf gi="9852" ue="32643" us="32642"/><bf gi="9854" ue="32648" us="32645"/><bf gi="9858" ue="32657" us="32650"/><bf gi="9866" ue="32660" us="32660"/><bf gi="9867" ue="32663" us="32662"/><bf gi="9869" ue="32666" us="32666"/><bf gi="9870" ue="32670" us="32668"/><bf gi="9873" ue="32676" us="32673"/>!
 <bf gi="9877" ue="32678" us="32678"/><bf gi="9878" ue="32682" us="32680"/><bf gi="9881" ue="32687" us="32685"/><bf gi="9884" ue="32690" us="32690"/><bf gi="9885" ue="32692" us="32692"/><bf gi="9886" ue="32694" us="32694"/><bf gi="9887" ue="32697" us="32696"/><bf gi="9889" ue="32701" us="32700"/><bf gi="9891" ue="32705" us="32703"/><bf gi="9894" ue="32707" us="32707"/><bf gi="9895" ue="32710" us="32709"/><bf gi="9897" ue="32712" us="32712"/><bf gi="9898" ue="32714" us="32714"/><bf gi="9899" ue="32716" us="32716"/><bf gi="9900" ue="32719" us="32718"/><bf gi="9902" ue="32722" us="32722"/><bf gi="9903" ue="32725" us="32724"/><bf gi="9905" ue="32731" us="32731"/><bf gi="9906" ue="32737" us="32735"/><bf gi="9909" ue="32739" us="32739"/><bf gi="9910" ue="32742" us="32741"/><bf gi="9912" ue="32745" us="32744"/><bf gi="9914" ue="32748" us="32747"/><bf gi="9916" ue="32752" us="32750"/><bf gi="9919" ue="32755" us="32754"/><bf gi="9921" ue="32769" us="32761"/><bf gi="9930" ue="32776" u!
 s="32771"/><bf gi="9936" ue="32793" us="32778"/><bf gi="9952" ue="3280
1" us="32796"/><bf gi="9958" ue="32804" us="32804"/><bf gi="9959" ue="32806" us="32806"/><bf gi="9960" ue="32808" us="32808"/><bf gi="9961" ue="32812" us="32812"/><bf gi="9962" ue="32814" us="32814"/><bf gi="9963" ue="32816" us="32816"/><bf gi="9964" ue="32823" us="32819"/><bf gi="9969" ue="32832" us="32825"/><bf gi="9977" ue="32836" us="32836"/><bf gi="9978" ue="32838" us="32838"/><bf gi="9979" ue="32842" us="32842"/><bf gi="9980" ue="32850" us="32850"/><bf gi="9981" ue="32854" us="32854"/><bf gi="9982" ue="32856" us="32856"/><bf gi="9983" ue="32858" us="32858"/><bf gi="9984" ue="32866" us="32862"/><bf gi="9989" ue="32868" us="32868"/><bf gi="9990" ue="32870" us="32870"/><bf gi="9991" ue="32872" us="32872"/><bf gi="9992" ue="32877" us="32877"/><bf gi="9993" ue="32887" us="32879"/><bf gi="10002" ue="32889" us="32889"/><bf gi="10003" ue="32895" us="32893"/><bf gi="10006" ue="32897" us="32897"/><bf gi="10007" ue="32905" us="32900"/><bf gi="10013" ue="32908" us="32907"/><bf gi=!
 "10015" ue="32910" us="32910"/><bf gi="10016" ue="32915" us="32915"/><bf gi="10017" ue="32918" us="32918"/><bf gi="10018" ue="32920" us="32920"/><bf gi="10019" ue="32926" us="32922"/><bf gi="10024" ue="32930" us="32929"/><bf gi="10026" ue="32935" us="32933"/><bf gi="10029" ue="32941" us="32937"/><bf gi="10034" ue="32943" us="32943"/><bf gi="10035" ue="32946" us="32945"/><bf gi="10037" ue="32948" us="32948"/><bf gi="10038" ue="32954" us="32952"/><bf gi="10041" ue="32964" us="32963"/><bf gi="10043" ue="32966" us="32966"/><bf gi="10044" ue="32968" us="32968"/><bf gi="10045" ue="32975" us="32972"/><bf gi="10049" ue="32978" us="32978"/><bf gi="10050" ue="32987" us="32980"/><bf gi="10058" ue="32990" us="32989"/><bf gi="10060" ue="32993" us="32992"/><bf gi="10062" ue="32997" us="32996"/><bf gi="10064" ue="33012" us="33005"/><bf gi="10072" ue="33014" us="33014"/><bf gi="10073" ue="33018" us="33016"/><bf gi="10076" ue="33022" us="33020"/><bf gi="10079" ue="33027" us="33026"/><bf gi=!
 "10081" ue="33035" us="33029"/><bf gi="10088" ue="33048" us="33046"/><
bf gi="10091" ue="33052" us="33050"/><bf gi="10094" ue="33054" us="33054"/><bf gi="10095" ue="33056" us="33056"/><bf gi="10096" ue="33060" us="33059"/><bf gi="10098" ue="33063" us="33063"/><bf gi="10099" ue="33065" us="33065"/><bf gi="10100" ue="33068" us="33068"/><bf gi="10101" ue="33073" us="33071"/><bf gi="10104" ue="33075" us="33075"/><bf gi="10105" ue="33077" us="33077"/><bf gi="10106" ue="33082" us="33081"/><bf gi="10108" ue="33084" us="33084"/><bf gi="10109" ue="33086" us="33086"/><bf gi="10110" ue="33095" us="33093"/><bf gi="10113" ue="33100" us="33098"/><bf gi="10116" ue="33102" us="33102"/><bf gi="10117" ue="33109" us="33104"/><bf gi="10123" ue="33111" us="33111"/><bf gi="10124" ue="33121" us="33119"/><bf gi="10127" ue="33129" us="33125"/><bf gi="10132" ue="33131" us="33131"/><bf gi="10133" ue="33137" us="33133"/><bf gi="10138" ue="33140" us="33140"/><bf gi="10139" ue="33146" us="33143"/><bf gi="10143" ue="33158" us="33151"/><bf gi="10151" ue="33160" us="33160"/><b!
 f gi="10152" ue="33163" us="33162"/><bf gi="10154" ue="33168" us="33166"/><bf gi="10157" ue="33171" us="33171"/><bf gi="10158" ue="33174" us="33173"/><bf gi="10160" ue="33176" us="33176"/><bf gi="10161" ue="33182" us="33178"/><bf gi="10166" ue="33184" us="33184"/><bf gi="10167" ue="33188" us="33186"/><bf gi="10170" ue="33193" us="33192"/><bf gi="10172" ue="33198" us="33198"/><bf gi="10173" ue="33200" us="33200"/><bf gi="10174" ue="33205" us="33202"/><bf gi="10178" ue="33208" us="33208"/><bf gi="10179" ue="33211" us="33210"/><bf gi="10181" ue="33216" us="33213"/><bf gi="10185" ue="33219" us="33218"/><bf gi="10187" ue="33222" us="33221"/><bf gi="10189" ue="33227" us="33224"/><bf gi="10193" ue="33231" us="33229"/><bf gi="10196" ue="33233" us="33233"/><bf gi="10197" ue="33235" us="33235"/><bf gi="10198" ue="33237" us="33237"/><bf gi="10199" ue="33243" us="33239"/><bf gi="10204" ue="33249" us="33245"/><bf gi="10209" ue="33253" us="33251"/><bf gi="10212" ue="33256" us="33255"/><b!
 f gi="10214" ue="33261" us="33258"/><bf gi="10218" ue="33270" us="3326
4"/><bf gi="10225" ue="33283" us="33272"/><bf gi="10237" ue="33285" us="33285"/><bf gi="10238" ue="33290" us="33287"/><bf gi="10242" ue="33296" us="33292"/><bf gi="10247" ue="33300" us="33298"/><bf gi="10250" ue="33311" us="33302"/><bf gi="10260" ue="33314" us="33313"/><bf gi="10262" ue="33324" us="33320"/><bf gi="10267" ue="33326" us="33326"/><bf gi="10268" ue="33338" us="33330"/><bf gi="10277" ue="33344" us="33344"/><bf gi="10278" ue="33351" us="33347"/><bf gi="10283" ue="33355" us="33355"/><bf gi="10284" ue="33359" us="33358"/><bf gi="10286" ue="33361" us="33361"/><bf gi="10287" ue="33366" us="33366"/><bf gi="10288" ue="33370" us="33368"/><bf gi="10291" ue="33373" us="33372"/><bf gi="10293" ue="33376" us="33375"/><bf gi="10295" ue="33380" us="33378"/><bf gi="10298" ue="33384" us="33382"/><bf gi="10301" ue="33387" us="33386"/><bf gi="10303" ue="33391" us="33389"/><bf gi="10306" ue="33394" us="33393"/><bf gi="10308" ue="33396" us="33396"/><bf gi="10309" ue="33400" us="33398!
 "/><bf gi="10312" ue="33403" us="33403"/><bf gi="10313" ue="33409" us="33405"/><bf gi="10318" ue="33412" us="33411"/><bf gi="10320" ue="33415" us="33415"/><bf gi="10321" ue="33419" us="33417"/><bf gi="10324" ue="33422" us="33421"/><bf gi="10326" ue="33426" us="33425"/><bf gi="10328" ue="33428" us="33428"/><bf gi="10329" ue="33430" us="33430"/><bf gi="10330" ue="33435" us="33432"/><bf gi="10334" ue="33437" us="33437"/><bf gi="10335" ue="33441" us="33439"/><bf gi="10338" ue="33460" us="33443"/><bf gi="10356" ue="33471" us="33463"/><bf gi="10365" ue="33478" us="33477"/><bf gi="10367" ue="33493" us="33488"/><bf gi="10373" ue="33495" us="33495"/><bf gi="10374" ue="33500" us="33497"/><bf gi="10378" ue="33512" us="33502"/><bf gi="10389" ue="33515" us="33514"/><bf gi="10391" ue="33517" us="33517"/><bf gi="10392" ue="33519" us="33519"/><bf gi="10393" ue="33521" us="33521"/><bf gi="10394" ue="33524" us="33523"/><bf gi="10396" ue="33527" us="33526"/><bf gi="10398" ue="33531" us="33529!
 "/><bf gi="10401" ue="33534" us="33533"/><bf gi="10403" ue="33547" us=
"33536"/><bf gi="10415" ue="33550" us="33550"/><bf gi="10416" ue="33560" us="33558"/><bf gi="10419" ue="33567" us="33563"/><bf gi="10424" ue="33571" us="33569"/><bf gi="10427" ue="33576" us="33576"/><bf gi="10428" ue="33594" us="33579"/><bf gi="10444" ue="33597" us="33596"/><bf gi="10446" ue="33600" us="33600"/><bf gi="10447" ue="33605" us="33602"/><bf gi="10451" ue="33607" us="33607"/><bf gi="10452" ue="33610" us="33609"/><bf gi="10454" ue="33624" us="33613"/><bf gi="10466" ue="33634" us="33634"/><bf gi="10467" ue="33648" us="33648"/><bf gi="10468" ue="33651" us="33651"/><bf gi="10469" ue="33653" us="33653"/><bf gi="10470" ue="33656" us="33655"/><bf gi="10472" ue="33661" us="33659"/><bf gi="10475" ue="33664" us="33663"/><bf gi="10477" ue="33666" us="33666"/><bf gi="10478" ue="33671" us="33668"/><bf gi="10482" ue="33674" us="33673"/><bf gi="10484" ue="33678" us="33677"/><bf gi="10486" ue="33686" us="33682"/><bf gi="10491" ue="33696" us="33688"/><bf gi="10500" ue="33698" us="!
 33698"/><bf gi="10501" ue="33709" us="33702"/><bf gi="10509" ue="33713" us="33713"/><bf gi="10510" ue="33717" us="33717"/><bf gi="10511" ue="33729" us="33725"/><bf gi="10516" ue="33733" us="33733"/><bf gi="10517" ue="33735" us="33735"/><bf gi="10518" ue="33738" us="33737"/><bf gi="10520" ue="33740" us="33740"/><bf gi="10521" ue="33745" us="33742"/><bf gi="10525" ue="33748" us="33747"/><bf gi="10527" ue="33750" us="33750"/><bf gi="10528" ue="33752" us="33752"/><bf gi="10529" ue="33757" us="33756"/><bf gi="10531" ue="33760" us="33759"/><bf gi="10533" ue="33771" us="33768"/><bf gi="10537" ue="33778" us="33775"/><bf gi="10541" ue="33780" us="33780"/><bf gi="10542" ue="33785" us="33782"/><bf gi="10546" ue="33789" us="33787"/><bf gi="10549" ue="33793" us="33793"/><bf gi="10550" ue="33796" us="33795"/><bf gi="10552" ue="33799" us="33798"/><bf gi="10554" ue="33807" us="33802"/><bf gi="10560" ue="33809" us="33809"/><bf gi="10561" ue="33811" us="33811"/><bf gi="10562" ue="33813" us="!
 33813"/><bf gi="10563" ue="33817" us="33817"/><bf gi="10564" ue="33824
" us="33824"/><bf gi="10565" ue="33826" us="33826"/><bf gi="10566" ue="33834" us="33833"/><bf gi="10568" ue="33836" us="33836"/><bf gi="10569" ue="33839" us="33839"/><bf gi="10570" ue="33841" us="33841"/><bf gi="10571" ue="33845" us="33845"/><bf gi="10572" ue="33849" us="33848"/><bf gi="10574" ue="33853" us="33852"/><bf gi="10576" ue="33866" us="33861"/><bf gi="10582" ue="33871" us="33869"/><bf gi="10585" ue="33874" us="33873"/><bf gi="10587" ue="33884" us="33878"/><bf gi="10594" ue="33895" us="33888"/><bf gi="10602" ue="33905" us="33897"/><bf gi="10611" ue="33914" us="33907"/><bf gi="10619" ue="33917" us="33916"/><bf gi="10621" ue="33922" us="33921"/><bf gi="10623" ue="33925" us="33924"/><bf gi="10625" ue="33931" us="33931"/><bf gi="10626" ue="33936" us="33936"/><bf gi="10627" ue="33941" us="33938"/><bf gi="10631" ue="33945" us="33945"/><bf gi="10632" ue="33948" us="33948"/><bf gi="10633" ue="33951" us="33950"/><bf gi="10635" ue="33953" us="33953"/><bf gi="10636" ue="33958"!
  us="33958"/><bf gi="10637" ue="33962" us="33960"/><bf gi="10640" ue="33965" us="33965"/><bf gi="10641" ue="33967" us="33967"/><bf gi="10642" ue="33970" us="33969"/><bf gi="10644" ue="33972" us="33972"/><bf gi="10645" ue="33986" us="33976"/><bf gi="10656" ue="33988" us="33988"/><bf gi="10657" ue="33997" us="33990"/><bf gi="10665" ue="34001" us="33999"/><bf gi="10668" ue="34003" us="34003"/><bf gi="10669" ue="34006" us="34006"/><bf gi="10670" ue="34010" us="34009"/><bf gi="10672" ue="34012" us="34012"/><bf gi="10673" ue="34023" us="34023"/><bf gi="10674" ue="34026" us="34026"/><bf gi="10675" ue="34028" us="34028"/><bf gi="10676" ue="34034" us="34030"/><bf gi="10681" ue="34036" us="34036"/><bf gi="10682" ue="34039" us="34039"/><bf gi="10683" ue="34045" us="34042"/><bf gi="10687" ue="34048" us="34047"/><bf gi="10689" ue="34051" us="34050"/><bf gi="10691" ue="34055" us="34054"/><bf gi="10693" ue="34060" us="34060"/><bf gi="10694" ue="34062" us="34062"/><bf gi="10695" ue="34065"!
  us="34064"/><bf gi="10697" ue="34069" us="34067"/><bf gi="10700" ue="
34072" us="34071"/><bf gi="10702" ue="34074" us="34074"/><bf gi="10703" ue="34076" us="34076"/><bf gi="10704" ue="34079" us="34078"/><bf gi="10706" ue="34087" us="34081"/><bf gi="10713" ue="34093" us="34090"/><bf gi="10717" ue="34095" us="34095"/><bf gi="10718" ue="34102" us="34098"/><bf gi="10723" ue="34109" us="34109"/><bf gi="10724" ue="34113" us="34111"/><bf gi="10727" ue="34115" us="34115"/><bf gi="10728" ue="34118" us="34118"/><bf gi="10729" ue="34123" us="34120"/><bf gi="10733" ue="34131" us="34126"/><bf gi="10739" ue="34138" us="34133"/><bf gi="10745" ue="34148" us="34140"/><bf gi="10754" ue="34155" us="34152"/><bf gi="10758" ue="34157" us="34157"/><bf gi="10759" ue="34159" us="34159"/><bf gi="10760" ue="34167" us="34167"/><bf gi="10761" ue="34171" us="34169"/><bf gi="10764" ue="34177" us="34173"/><bf gi="10769" ue="34188" us="34180"/><bf gi="10778" ue="34193" us="34191"/><bf gi="10781" ue="34196" us="34195"/><bf gi="10783" ue="34201" us="34199"/><bf gi="10786" ue="3!
 4205" us="34203"/><bf gi="10789" ue="34208" us="34207"/><bf gi="10791" ue="34210" us="34210"/><bf gi="10792" ue="34224" us="34212"/><bf gi="10805" ue="34228" us="34228"/><bf gi="10806" ue="34234" us="34230"/><bf gi="10811" ue="34239" us="34236"/><bf gi="10815" ue="34242" us="34241"/><bf gi="10817" ue="34247" us="34247"/><bf gi="10818" ue="34251" us="34249"/><bf gi="10821" ue="34256" us="34253"/><bf gi="10825" ue="34261" us="34261"/><bf gi="10826" ue="34264" us="34264"/><bf gi="10827" ue="34266" us="34266"/><bf gi="10828" ue="34269" us="34268"/><bf gi="10830" ue="34272" us="34271"/><bf gi="10832" ue="34278" us="34276"/><bf gi="10835" ue="34282" us="34280"/><bf gi="10838" ue="34285" us="34285"/><bf gi="10839" ue="34291" us="34291"/><bf gi="10840" ue="34295" us="34294"/><bf gi="10842" ue="34300" us="34297"/><bf gi="10846" ue="34304" us="34302"/><bf gi="10849" ue="34306" us="34306"/><bf gi="10850" ue="34311" us="34308"/><bf gi="10854" ue="34315" us="34314"/><bf gi="10856" ue="3!
 4318" us="34317"/><bf gi="10858" ue="34323" us="34320"/><bf gi="10862"
 ue="34331" us="34326"/><bf gi="10868" ue="34334" us="34334"/><bf gi="10869" ue="34338" us="34337"/><bf gi="10871" ue="34343" us="34343"/><bf gi="10872" ue="34345" us="34345"/><bf gi="10873" ue="34349" us="34349"/><bf gi="10874" ue="34352" us="34351"/><bf gi="10876" ue="34358" us="34358"/><bf gi="10877" ue="34360" us="34360"/><bf gi="10878" ue="34362" us="34362"/><bf gi="10879" ue="34365" us="34364"/><bf gi="10881" ue="34370" us="34367"/><bf gi="10885" ue="34374" us="34374"/><bf gi="10886" ue="34382" us="34381"/><bf gi="10888" ue="34384" us="34384"/><bf gi="10889" ue="34394" us="34386"/><bf gi="10898" ue="34404" us="34396"/><bf gi="10907" ue="34407" us="34407"/><bf gi="10908" ue="34409" us="34409"/><bf gi="10909" ue="34412" us="34411"/><bf gi="10911" ue="34415" us="34415"/><bf gi="10912" ue="34417" us="34417"/><bf gi="10913" ue="34423" us="34421"/><bf gi="10916" ue="34427" us="34425"/><bf gi="10919" ue="34440" us="34440"/><bf gi="10920" ue="34445" us="34442"/><bf gi="10924" !
 ue="34449" us="34449"/><bf gi="10925" ue="34451" us="34451"/><bf gi="10926" ue="34454" us="34453"/><bf gi="10928" ue="34456" us="34456"/><bf gi="10929" ue="34458" us="34458"/><bf gi="10930" ue="34460" us="34460"/><bf gi="10931" ue="34465" us="34465"/><bf gi="10932" ue="34468" us="34467"/><bf gi="10934" ue="34475" us="34470"/><bf gi="10940" ue="34477" us="34477"/><bf gi="10941" ue="34481" us="34479"/><bf gi="10944" ue="34489" us="34483"/><bf gi="10951" ue="34497" us="34495"/><bf gi="10954" ue="34503" us="34499"/><bf gi="10959" ue="34505" us="34505"/><bf gi="10960" ue="34507" us="34507"/><bf gi="10961" ue="34510" us="34509"/><bf gi="10963" ue="34514" us="34513"/><bf gi="10965" ue="34517" us="34516"/><bf gi="10967" ue="34519" us="34519"/><bf gi="10968" ue="34524" us="34521"/><bf gi="10972" ue="34528" us="34526"/><bf gi="10975" ue="34533" us="34531"/><bf gi="10978" ue="34535" us="34535"/><bf gi="10979" ue="34537" us="34537"/><bf gi="10980" ue="34543" us="34540"/><bf gi="10984" !
 ue="34558" us="34552"/><bf gi="10991" ue="34560" us="34560"/><bf gi="1
0992" ue="34571" us="34562"/><bf gi="11002" ue="34580" us="34573"/><bf gi="11010" ue="34586" us="34584"/><bf gi="11013" ue="34588" us="34588"/><bf gi="11014" ue="34591" us="34590"/><bf gi="11016" ue="34593" us="34593"/><bf gi="11017" ue="34595" us="34595"/><bf gi="11018" ue="34597" us="34597"/><bf gi="11019" ue="34601" us="34600"/><bf gi="11021" ue="34607" us="34606"/><bf gi="11023" ue="34610" us="34609"/><bf gi="11025" ue="34612" us="34612"/><bf gi="11026" ue="34615" us="34615"/><bf gi="11027" ue="34624" us="34617"/><bf gi="11035" ue="34627" us="34627"/><bf gi="11036" ue="34629" us="34629"/><bf gi="11037" ue="34633" us="34633"/><bf gi="11038" ue="34638" us="34635"/><bf gi="11042" ue="34643" us="34643"/><bf gi="11043" ue="34645" us="34645"/><bf gi="11044" ue="34649" us="34647"/><bf gi="11047" ue="34653" us="34653"/><bf gi="11048" ue="34657" us="34655"/><bf gi="11051" ue="34662" us="34659"/><bf gi="11055" ue="34664" us="34664"/><bf gi="11056" ue="34666" us="34666"/><bf gi="11!
 057" ue="34671" us="34670"/><bf gi="11059" ue="34674" us="34673"/><bf gi="11061" ue="34676" us="34676"/><bf gi="11062" ue="34678" us="34678"/><bf gi="11063" ue="34680" us="34680"/><bf gi="11064" ue="34683" us="34683"/><bf gi="11065" ue="34687" us="34687"/><bf gi="11066" ue="34697" us="34690"/><bf gi="11074" ue="34701" us="34699"/><bf gi="11077" ue="34704" us="34704"/><bf gi="11078" ue="34707" us="34707"/><bf gi="11079" ue="34709" us="34709"/><bf gi="11080" ue="34713" us="34711"/><bf gi="11083" ue="34720" us="34718"/><bf gi="11086" ue="34723" us="34722"/><bf gi="11088" ue="34727" us="34727"/><bf gi="11089" ue="34735" us="34731"/><bf gi="11094" ue="34737" us="34737"/><bf gi="11095" ue="34739" us="34739"/><bf gi="11096" ue="34741" us="34741"/><bf gi="11097" ue="34747" us="34746"/><bf gi="11099" ue="34753" us="34749"/><bf gi="11104" ue="34756" us="34756"/><bf gi="11105" ue="34763" us="34758"/><bf gi="11111" ue="34766" us="34766"/><bf gi="11112" ue="34768" us="34768"/><bf gi="11!
 113" ue="34770" us="34770"/><bf gi="11114" ue="34774" us="34773"/><bf 
gi="11116" ue="34778" us="34777"/><bf gi="11118" ue="34780" us="34780"/><bf gi="11119" ue="34784" us="34783"/><bf gi="11121" ue="34788" us="34786"/><bf gi="11124" ue="34795" us="34794"/><bf gi="11126" ue="34797" us="34797"/><bf gi="11127" ue="34799" us="34799"/><bf gi="11128" ue="34803" us="34801"/><bf gi="11131" ue="34811" us="34806"/><bf gi="11137" ue="34815" us="34814"/><bf gi="11139" ue="34817" us="34817"/><bf gi="11140" ue="34819" us="34819"/><bf gi="11141" ue="34823" us="34821"/><bf gi="11144" ue="34827" us="34825"/><bf gi="11147" ue="34838" us="34829"/><bf gi="11157" ue="34844" us="34840"/><bf gi="11162" ue="34847" us="34846"/><bf gi="11164" ue="34851" us="34849"/><bf gi="11167" ue="34856" us="34855"/><bf gi="11169" ue="34862" us="34861"/><bf gi="11171" ue="34866" us="34864"/><bf gi="11174" ue="34870" us="34869"/><bf gi="11176" ue="34876" us="34873"/><bf gi="11180" ue="34886" us="34880"/><bf gi="11187" ue="34894" us="34888"/><bf gi="11194" ue="34899" us="34897"/><bf g!
 i="11197" ue="34916" us="34901"/><bf gi="11213" ue="34921" us="34920"/><bf gi="11215" ue="34923" us="34923"/><bf gi="11216" ue="34930" us="34928"/><bf gi="11219" ue="34933" us="34933"/><bf gi="11220" ue="34935" us="34935"/><bf gi="11221" ue="34937" us="34937"/><bf gi="11222" ue="34939" us="34939"/><bf gi="11223" ue="34946" us="34941"/><bf gi="11229" ue="34952" us="34952"/><bf gi="11230" ue="34955" us="34955"/><bf gi="11231" ue="34957" us="34957"/><bf gi="11232" ue="34962" us="34962"/><bf gi="11233" ue="34972" us="34966"/><bf gi="11240" ue="34976" us="34974"/><bf gi="11243" ue="34978" us="34978"/><bf gi="11244" ue="34980" us="34980"/><bf gi="11245" ue="34984" us="34984"/><bf gi="11246" ue="34987" us="34986"/><bf gi="11248" ue="34990" us="34990"/><bf gi="11249" ue="34993" us="34992"/><bf gi="11251" ue="34997" us="34996"/><bf gi="11253" ue="34999" us="34999"/><bf gi="11254" ue="35002" us="35002"/><bf gi="11255" ue="35013" us="35005"/><bf gi="11264" ue="35023" us="35018"/><bf g!
 i="11270" ue="35029" us="35025"/><bf gi="11275" ue="35033" us="35032"/
><bf gi="11277" ue="35039" us="35035"/><bf gi="11282" ue="35041" us="35041"/><bf gi="11283" ue="35048" us="35047"/><bf gi="11285" ue="35061" us="35055"/><bf gi="11292" ue="35065" us="35063"/><bf gi="11295" ue="35070" us="35068"/><bf gi="11298" ue="35074" us="35073"/><bf gi="11300" ue="35076" us="35076"/><bf gi="11301" ue="35079" us="35078"/><bf gi="11303" ue="35082" us="35082"/><bf gi="11304" ue="35088" us="35084"/><bf gi="11309" ue="35091" us="35090"/><bf gi="11311" ue="35094" us="35093"/><bf gi="11313" ue="35098" us="35096"/><bf gi="11316" ue="35102" us="35100"/><bf gi="11319" ue="35104" us="35104"/><bf gi="11320" ue="35112" us="35109"/><bf gi="11324" ue="35115" us="35114"/><bf gi="11326" ue="35122" us="35120"/><bf gi="11329" ue="35126" us="35125"/><bf gi="11331" ue="35131" us="35128"/><bf gi="11335" ue="35134" us="35134"/><bf gi="11336" ue="35142" us="35136"/><bf gi="11343" ue="35145" us="35145"/><bf gi="11344" ue="35149" us="35148"/><bf gi="11346" ue="35151" us="35151"/>!
 <bf gi="11347" ue="35154" us="35154"/><bf gi="11348" ue="35159" us="35158"/><bf gi="11350" ue="35164" us="35162"/><bf gi="11353" ue="35172" us="35166"/><bf gi="11360" ue="35174" us="35174"/><bf gi="11361" ue="35179" us="35178"/><bf gi="11363" ue="35184" us="35181"/><bf gi="11367" ue="35189" us="35186"/><bf gi="11371" ue="35191" us="35191"/><bf gi="11372" ue="35199" us="35194"/><bf gi="11378" ue="35201" us="35201"/><bf gi="11379" ue="35203" us="35203"/><bf gi="11380" ue="35211" us="35206"/><bf gi="11386" ue="35213" us="35213"/><bf gi="11387" ue="35216" us="35215"/><bf gi="11389" ue="35224" us="35219"/><bf gi="11395" ue="35228" us="35226"/><bf gi="11398" ue="35233" us="35231"/><bf gi="11401" ue="35239" us="35237"/><bf gi="11404" ue="35242" us="35241"/><bf gi="11406" ue="35244" us="35244"/><bf gi="11407" ue="35248" us="35247"/><bf gi="11409" ue="35255" us="35250"/><bf gi="11415" ue="35258" us="35258"/><bf gi="11416" ue="35261" us="35260"/><bf gi="11418" ue="35264" us="35263"/>!
 <bf gi="11420" ue="35282" us="35282"/><bf gi="11421" ue="35288" us="35
284"/><bf gi="11426" ue="35290" us="35290"/><bf gi="11427" ue="35293" us="35292"/><bf gi="11429" ue="35299" us="35299"/><bf gi="11430" ue="35303" us="35301"/><bf gi="11433" ue="35305" us="35305"/><bf gi="11434" ue="35307" us="35307"/><bf gi="11435" ue="35309" us="35309"/><bf gi="11436" ue="35313" us="35313"/><bf gi="11437" ue="35316" us="35315"/><bf gi="11439" ue="35318" us="35318"/><bf gi="11440" ue="35321" us="35320"/><bf gi="11442" ue="35325" us="35325"/><bf gi="11443" ue="35328" us="35327"/><bf gi="11445" ue="35333" us="35330"/><bf gi="11449" ue="35336" us="35335"/><bf gi="11451" ue="35338" us="35338"/><bf gi="11452" ue="35340" us="35340"/><bf gi="11453" ue="35352" us="35342"/><bf gi="11464" ue="35355" us="35355"/><bf gi="11465" ue="35360" us="35357"/><bf gi="11469" ue="35366" us="35362"/><bf gi="11474" ue="35373" us="35370"/><bf gi="11478" ue="35375" us="35375"/><bf gi="11479" ue="35377" us="35377"/><bf gi="11480" ue="35383" us="35379"/><bf gi="11485" ue="35390" us="353!
 86"/><bf gi="11490" ue="35393" us="35392"/><bf gi="11492" ue="35395" us="35395"/><bf gi="11493" ue="35401" us="35397"/><bf gi="11498" ue="35406" us="35405"/><bf gi="11500" ue="35416" us="35408"/><bf gi="11509" ue="35422" us="35419"/><bf gi="11513" ue="35427" us="35424"/><bf gi="11517" ue="35431" us="35429"/><bf gi="11520" ue="35433" us="35433"/><bf gi="11521" ue="35438" us="35435"/><bf gi="11525" ue="35443" us="35440"/><bf gi="11529" ue="35447" us="35445"/><bf gi="11532" ue="35452" us="35449"/><bf gi="11536" ue="35456" us="35454"/><bf gi="11539" ue="35463" us="35458"/><bf gi="11545" ue="35465" us="35465"/><bf gi="11546" ue="35469" us="35467"/><bf gi="11549" ue="35475" us="35471"/><bf gi="11554" ue="35482" us="35477"/><bf gi="11560" ue="35489" us="35486"/><bf gi="11564" ue="35497" us="35491"/><bf gi="11571" ue="35504" us="35500"/><bf gi="11576" ue="35507" us="35506"/><bf gi="11578" ue="35511" us="35510"/><bf gi="11580" ue="35513" us="35513"/><bf gi="11581" ue="35516" us="355!
 15"/><bf gi="11583" ue="35519" us="35518"/><bf gi="11585" ue="35524" u
s="35522"/><bf gi="11588" ue="35533" us="35526"/><bf gi="11596" ue="35535" us="35535"/><bf gi="11597" ue="35543" us="35537"/><bf gi="11604" ue="35554" us="35546"/><bf gi="11613" ue="35556" us="35556"/><bf gi="11614" ue="35559" us="35558"/><bf gi="11616" ue="35566" us="35563"/><bf gi="11620" ue="35569" us="35568"/><bf gi="11622" ue="35576" us="35571"/><bf gi="11628" ue="35578" us="35578"/><bf gi="11629" ue="35580" us="35580"/><bf gi="11630" ue="35586" us="35582"/><bf gi="11635" ue="35591" us="35588"/><bf gi="11639" ue="35596" us="35594"/><bf gi="11642" ue="35598" us="35598"/><bf gi="11643" ue="35601" us="35600"/><bf gi="11645" ue="35604" us="35604"/><bf gi="11646" ue="35607" us="35606"/><bf gi="11648" ue="35617" us="35609"/><bf gi="11657" ue="35622" us="35622"/><bf gi="11658" ue="35624" us="35624"/><bf gi="11659" ue="35629" us="35627"/><bf gi="11662" ue="35632" us="35632"/><bf gi="11663" ue="35635" us="35635"/><bf gi="11664" ue="35639" us="35639"/><bf gi="11665" ue="35641" us!
 ="35641"/><bf gi="11666" ue="35644" us="35644"/><bf gi="11667" ue="35646" us="35646"/><bf gi="11668" ue="35654" us="35649"/><bf gi="11674" ue="35657" us="35656"/><bf gi="11676" ue="35663" us="35660"/><bf gi="11680" ue="35668" us="35666"/><bf gi="11683" ue="35670" us="35670"/><bf gi="11684" ue="35676" us="35672"/><bf gi="11689" ue="35679" us="35678"/><bf gi="11691" ue="35683" us="35683"/><bf gi="11692" ue="35686" us="35686"/><bf gi="11693" ue="35693" us="35691"/><bf gi="11696" ue="35698" us="35695"/><bf gi="11700" ue="35700" us="35700"/><bf gi="11701" ue="35705" us="35702"/><bf gi="11705" ue="35713" us="35708"/><bf gi="11711" ue="35717" us="35715"/><bf gi="11714" ue="35728" us="35722"/><bf gi="11721" ue="35734" us="35730"/><bf gi="11726" ue="35738" us="35737"/><bf gi="11728" ue="35740" us="35740"/><bf gi="11729" ue="35743" us="35742"/><bf gi="11731" ue="35898" us="35895"/><bf gi="11735" ue="35903" us="35901"/><bf gi="11738" ue="35905" us="35905"/><bf gi="11739" ue="35916" us!
 ="35909"/><bf gi="11747" ue="35921" us="35918"/><bf gi="11751" ue="359
25" us="35923"/><bf gi="11754" ue="35931" us="35927"/><bf gi="11759" ue="35933" us="35933"/><bf gi="11760" ue="35940" us="35937"/><bf gi="11764" ue="35942" us="35942"/><bf gi="11765" ue="35949" us="35944"/><bf gi="11771" ue="35955" us="35955"/><bf gi="11772" ue="35958" us="35957"/><bf gi="11774" ue="35964" us="35960"/><bf gi="11779" ue="35966" us="35966"/><bf gi="11780" ue="35970" us="35970"/><bf gi="11781" ue="35975" us="35973"/><bf gi="11784" ue="35982" us="35977"/><bf gi="11790" ue="35984" us="35984"/><bf gi="11791" ue="35988" us="35986"/><bf gi="11794" ue="35993" us="35992"/><bf gi="11796" ue="35998" us="35995"/><bf gi="11800" ue="36002" us="36000"/><bf gi="11803" ue="36004" us="36004"/><bf gi="11804" ue="36016" us="36007"/><bf gi="11814" ue="36020" us="36018"/><bf gi="11817" ue="36029" us="36022"/><bf gi="11825" ue="36043" us="36031"/><bf gi="11838" ue="36047" us="36045"/><bf gi="11841" ue="36049" us="36049"/><bf gi="11842" ue="36051" us="36051"/><bf gi="11843" ue="3605!
 4" us="36053"/><bf gi="11845" ue="36062" us="36057"/><bf gi="11851" ue="36068" us="36064"/><bf gi="11856" ue="36070" us="36070"/><bf gi="11857" ue="36072" us="36072"/><bf gi="11858" ue="36074" us="36074"/><bf gi="11859" ue="36077" us="36076"/><bf gi="11861" ue="36080" us="36079"/><bf gi="11863" ue="36082" us="36082"/><bf gi="11864" ue="36085" us="36084"/><bf gi="11866" ue="36088" us="36087"/><bf gi="11868" ue="36095" us="36090"/><bf gi="11874" ue="36097" us="36097"/><bf gi="11875" ue="36101" us="36099"/><bf gi="11878" ue="36107" us="36103"/><bf gi="11883" ue="36109" us="36109"/><bf gi="11884" ue="36112" us="36111"/><bf gi="11886" ue="36116" us="36114"/><bf gi="11889" ue="36119" us="36118"/><bf gi="11891" ue="36123" us="36123"/><bf gi="11892" ue="36199" us="36196"/><bf gi="11896" ue="36201" us="36201"/><bf gi="11897" ue="36206" us="36203"/><bf gi="11901" ue="36209" us="36208"/><bf gi="11903" ue="36212" us="36211"/><bf gi="11905" ue="36215" us="36214"/><bf gi="11907" ue="3622!
 3" us="36223"/><bf gi="11908" ue="36226" us="36225"/><bf gi="11910" ue
="36229" us="36228"/><bf gi="11912" ue="36232" us="36232"/><bf gi="11913" ue="36234" us="36234"/><bf gi="11914" ue="36237" us="36237"/><bf gi="11915" ue="36241" us="36240"/><bf gi="11917" ue="36245" us="36245"/><bf gi="11918" ue="36249" us="36249"/><bf gi="11919" ue="36256" us="36254"/><bf gi="11922" ue="36259" us="36259"/><bf gi="11923" ue="36262" us="36262"/><bf gi="11924" ue="36264" us="36264"/><bf gi="11925" ue="36268" us="36267"/><bf gi="11927" ue="36271" us="36271"/><bf gi="11928" ue="36275" us="36274"/><bf gi="11930" ue="36277" us="36277"/><bf gi="11931" ue="36279" us="36279"/><bf gi="11932" ue="36284" us="36281"/><bf gi="11936" ue="36286" us="36286"/><bf gi="11937" ue="36288" us="36288"/><bf gi="11938" ue="36290" us="36290"/><bf gi="11939" ue="36296" us="36293"/><bf gi="11943" ue="36300" us="36298"/><bf gi="11946" ue="36303" us="36302"/><bf gi="11948" ue="36305" us="36305"/><bf gi="11949" ue="36311" us="36308"/><bf gi="11953" ue="36315" us="36313"/><bf gi="11956" ue=!
 "36317" us="36317"/><bf gi="11957" ue="36319" us="36319"/><bf gi="11958" ue="36321" us="36321"/><bf gi="11959" ue="36325" us="36323"/><bf gi="11962" ue="36328" us="36327"/><bf gi="11964" ue="36332" us="36330"/><bf gi="11967" ue="36341" us="36335"/><bf gi="11974" ue="36349" us="36348"/><bf gi="11976" ue="36351" us="36351"/><bf gi="11977" ue="36353" us="36353"/><bf gi="11978" ue="36358" us="36356"/><bf gi="11981" ue="36363" us="36360"/><bf gi="11985" ue="36369" us="36367"/><bf gi="11988" ue="36372" us="36372"/><bf gi="11989" ue="36374" us="36374"/><bf gi="11990" ue="36387" us="36381"/><bf gi="11997" ue="36391" us="36390"/><bf gi="11999" ue="36394" us="36394"/><bf gi="12000" ue="36401" us="36400"/><bf gi="12002" ue="36409" us="36403"/><bf gi="12009" ue="36413" us="36413"/><bf gi="12010" ue="36418" us="36416"/><bf gi="12013" ue="36420" us="36420"/><bf gi="12014" ue="36432" us="36423"/><bf gi="12024" ue="36437" us="36436"/><bf gi="12026" ue="36441" us="36441"/><bf gi="12027" ue=!
 "36452" us="36443"/><bf gi="12037" ue="36457" us="36457"/><bf gi="1203
8" ue="36461" us="36460"/><bf gi="12040" ue="36466" us="36463"/><bf gi="12044" ue="36468" us="36468"/><bf gi="12045" ue="36470" us="36470"/><bf gi="12046" ue="36476" us="36473"/><bf gi="12050" ue="36485" us="36481"/><bf gi="12055" ue="36487" us="36487"/><bf gi="12056" ue="36491" us="36489"/><bf gi="12059" ue="36493" us="36493"/><bf gi="12060" ue="36501" us="36496"/><bf gi="12066" ue="36507" us="36505"/><bf gi="12069" ue="36510" us="36509"/><bf gi="12071" ue="36514" us="36513"/><bf gi="12073" ue="36519" us="36519"/><bf gi="12074" ue="36529" us="36521"/><bf gi="12083" ue="36531" us="36531"/><bf gi="12084" ue="36533" us="36533"/><bf gi="12085" ue="36539" us="36538"/><bf gi="12087" ue="36542" us="36542"/><bf gi="12088" ue="36545" us="36544"/><bf gi="12090" ue="36552" us="36547"/><bf gi="12096" ue="36557" us="36554"/><bf gi="12100" ue="36559" us="36559"/><bf gi="12101" ue="36562" us="36561"/><bf gi="12103" ue="36564" us="36564"/><bf gi="12104" ue="36572" us="36571"/><bf gi="12106!
 " ue="36575" us="36575"/><bf gi="12107" ue="36579" us="36578"/><bf gi="12109" ue="36584" us="36584"/><bf gi="12110" ue="36587" us="36587"/><bf gi="12111" ue="36590" us="36589"/><bf gi="12113" ue="36593" us="36592"/><bf gi="12115" ue="36606" us="36599"/><bf gi="12123" ue="36608" us="36608"/><bf gi="12124" ue="36611" us="36610"/><bf gi="12126" ue="36613" us="36613"/><bf gi="12127" ue="36618" us="36615"/><bf gi="12131" ue="36620" us="36620"/><bf gi="12132" ue="36624" us="36623"/><bf gi="12134" ue="36633" us="36626"/><bf gi="12142" ue="36641" us="36635"/><bf gi="12149" ue="36643" us="36643"/><bf gi="12150" ue="36650" us="36645"/><bf gi="12156" ue="36655" us="36652"/><bf gi="12160" ue="36667" us="36659"/><bf gi="12169" ue="36679" us="36670"/><bf gi="12179" ue="36681" us="36681"/><bf gi="12180" ue="36687" us="36684"/><bf gi="12184" ue="36693" us="36689"/><bf gi="12189" ue="36696" us="36695"/><bf gi="12191" ue="36703" us="36700"/><bf gi="12195" ue="36709" us="36705"/><bf gi="12200!
 " ue="36769" us="36763"/><bf gi="12207" ue="36776" us="36771"/><bf gi=
"12213" ue="36786" us="36781"/><bf gi="12219" ue="36792" us="36789"/><bf gi="12223" ue="36796" us="36794"/><bf gi="12226" ue="36802" us="36798"/><bf gi="12231" ue="36806" us="36804"/><bf gi="12234" ue="36811" us="36810"/><bf gi="12236" ue="36814" us="36813"/><bf gi="12238" ue="36821" us="36816"/><bf gi="12244" ue="36826" us="36826"/><bf gi="12245" ue="36832" us="36832"/><bf gi="12246" ue="36838" us="36834"/><bf gi="12251" ue="36843" us="36840"/><bf gi="12255" ue="36849" us="36845"/><bf gi="12260" ue="36859" us="36852"/><bf gi="12268" ue="36862" us="36861"/><bf gi="12270" ue="36870" us="36864"/><bf gi="12277" ue="36872" us="36872"/><bf gi="12278" ue="36881" us="36875"/><bf gi="12285" ue="36891" us="36883"/><bf gi="12294" ue="36899" us="36893"/><bf gi="12301" ue="36906" us="36903"/><bf gi="12305" ue="36911" us="36908"/><bf gi="12309" ue="36921" us="36913"/><bf gi="12318" ue="36924" us="36924"/><bf gi="12319" ue="36927" us="36926"/><bf gi="12321" ue="36933" us="36929"/><bf gi="!
 12326" ue="36935" us="36935"/><bf gi="12327" ue="36950" us="36937"/><bf gi="12341" ue="36953" us="36952"/><bf gi="12343" ue="36958" us="36955"/><bf gi="12347" ue="36963" us="36960"/><bf gi="12351" ue="36969" us="36965"/><bf gi="12356" ue="36976" us="36972"/><bf gi="12361" ue="36978" us="36978"/><bf gi="12362" ue="36986" us="36980"/><bf gi="12369" ue="36989" us="36988"/><bf gi="12371" ue="36997" us="36991"/><bf gi="12378" ue="37004" us="36999"/><bf gi="12384" ue="37009" us="37006"/><bf gi="12388" ue="37013" us="37013"/><bf gi="12389" ue="37017" us="37015"/><bf gi="12392" ue="37019" us="37019"/><bf gi="12393" ue="37027" us="37024"/><bf gi="12397" ue="37030" us="37029"/><bf gi="12399" ue="37032" us="37032"/><bf gi="12400" ue="37034" us="37034"/><bf gi="12401" ue="37046" us="37039"/><bf gi="12409" ue="37048" us="37048"/><bf gi="12410" ue="37054" us="37053"/><bf gi="12412" ue="37057" us="37057"/><bf gi="12413" ue="37061" us="37059"/><bf gi="12416" ue="37064" us="37063"/><bf gi="!
 12418" ue="37066" us="37066"/><bf gi="12419" ue="37068" us="37068"/><b
f gi="12420" ue="37070" us="37070"/><bf gi="12421" ue="37074" us="37074"/><bf gi="12422" ue="37077" us="37077"/><bf gi="12423" ue="37081" us="37079"/><bf gi="12426" ue="37087" us="37083"/><bf gi="12431" ue="37090" us="37089"/><bf gi="12433" ue="37093" us="37092"/><bf gi="12435" ue="37096" us="37096"/><bf gi="12436" ue="37099" us="37099"/><bf gi="12437" ue="37101" us="37101"/><bf gi="12438" ue="37104" us="37103"/><bf gi="12440" ue="37111" us="37108"/><bf gi="12444" ue="37120" us="37117"/><bf gi="12448" ue="37122" us="37122"/><bf gi="12449" ue="37126" us="37124"/><bf gi="12452" ue="37128" us="37128"/><bf gi="12453" ue="37133" us="37133"/><bf gi="12454" ue="37136" us="37136"/><bf gi="12455" ue="37138" us="37138"/><bf gi="12456" ue="37146" us="37140"/><bf gi="12463" ue="37148" us="37148"/><bf gi="12464" ue="37150" us="37150"/><bf gi="12465" ue="37152" us="37152"/><bf gi="12466" ue="37155" us="37154"/><bf gi="12468" ue="37157" us="37157"/><bf gi="12469" ue="37159" us="37159"/><bf!
  gi="12470" ue="37161" us="37161"/><bf gi="12471" ue="37170" us="37165"/><bf gi="12477" ue="37172" us="37172"/><bf gi="12478" ue="37175" us="37174"/><bf gi="12480" ue="37178" us="37177"/><bf gi="12482" ue="37181" us="37180"/><bf gi="12484" ue="37187" us="37187"/><bf gi="12485" ue="37199" us="37191"/><bf gi="12494" ue="37204" us="37202"/><bf gi="12497" ue="37211" us="37206"/><bf gi="12503" ue="37221" us="37217"/><bf gi="12508" ue="37223" us="37223"/><bf gi="12509" ue="37226" us="37225"/><bf gi="12511" ue="37229" us="37228"/><bf gi="12513" ue="37237" us="37234"/><bf gi="12517" ue="37243" us="37239"/><bf gi="12522" ue="37251" us="37249"/><bf gi="12525" ue="37255" us="37253"/><bf gi="12528" ue="37259" us="37257"/><bf gi="12531" ue="37262" us="37261"/><bf gi="12533" ue="37269" us="37264"/><bf gi="12539" ue="37272" us="37271"/><bf gi="12541" ue="37276" us="37276"/><bf gi="12542" ue="37278" us="37278"/><bf gi="12543" ue="37282" us="37281"/><bf gi="12545" ue="37284" us="37284"/><bf!
  gi="12546" ue="37286" us="37286"/><bf gi="12547" ue="37288" us="37288
"/><bf gi="12548" ue="37302" us="37290"/><bf gi="12561" ue="37304" us="37304"/><bf gi="12562" ue="37309" us="37306"/><bf gi="12566" ue="37315" us="37311"/><bf gi="12571" ue="37321" us="37317"/><bf gi="12576" ue="37329" us="37323"/><bf gi="12583" ue="37332" us="37331"/><bf gi="12585" ue="37343" us="37334"/><bf gi="12595" ue="37345" us="37345"/><bf gi="12596" ue="37351" us="37347"/><bf gi="12601" ue="37354" us="37353"/><bf gi="12603" ue="37361" us="37356"/><bf gi="12609" ue="37367" us="37365"/><bf gi="12612" ue="37369" us="37369"/><bf gi="12613" ue="37373" us="37371"/><bf gi="12616" ue="37377" us="37375"/><bf gi="12619" ue="37383" us="37380"/><bf gi="12623" ue="37386" us="37385"/><bf gi="12625" ue="37390" us="37388"/><bf gi="12628" ue="37398" us="37392"/><bf gi="12635" ue="37400" us="37400"/><bf gi="12636" ue="37406" us="37404"/><bf gi="12639" ue="37414" us="37411"/><bf gi="12643" ue="37417" us="37416"/><bf gi="12645" ue="37420" us="37420"/><bf gi="12646" ue="37424" us="37422"!
 /><bf gi="12649" ue="37434" us="37427"/><bf gi="12657" ue="37436" us="37436"/><bf gi="12658" ue="37440" us="37438"/><bf gi="12661" ue="37451" us="37442"/><bf gi="12671" ue="37457" us="37453"/><bf gi="12676" ue="37470" us="37463"/><bf gi="12684" ue="37474" us="37472"/><bf gi="12687" ue="37481" us="37476"/><bf gi="12693" ue="37489" us="37486"/><bf gi="12697" ue="37497" us="37493"/><bf gi="12702" ue="37504" us="37499"/><bf gi="12708" ue="37507" us="37507"/><bf gi="12709" ue="37509" us="37509"/><bf gi="12710" ue="37514" us="37512"/><bf gi="12713" ue="37518" us="37517"/><bf gi="12715" ue="37523" us="37521"/><bf gi="12718" ue="37532" us="37525"/><bf gi="12726" ue="37536" us="37535"/><bf gi="12728" ue="37541" us="37540"/><bf gi="12730" ue="37544" us="37543"/><bf gi="12732" ue="37547" us="37547"/><bf gi="12733" ue="37549" us="37549"/><bf gi="12734" ue="37551" us="37551"/><bf gi="12735" ue="37554" us="37554"/><bf gi="12736" ue="37565" us="37558"/><bf gi="12744" ue="37571" us="37567"!
 /><bf gi="12749" ue="37576" us="37573"/><bf gi="12753" ue="37584" us="
37579"/><bf gi="12759" ue="37587" us="37586"/><bf gi="12761" ue="37589" us="37589"/><bf gi="12762" ue="37593" us="37591"/><bf gi="12765" ue="37597" us="37596"/><bf gi="12767" ue="37601" us="37599"/><bf gi="12770" ue="37605" us="37603"/><bf gi="12773" ue="37610" us="37607"/><bf gi="12777" ue="37614" us="37612"/><bf gi="12780" ue="37616" us="37616"/><bf gi="12781" ue="37619" us="37618"/><bf gi="12783" ue="37628" us="37624"/><bf gi="12788" ue="37632" us="37631"/><bf gi="12790" ue="37634" us="37634"/><bf gi="12791" ue="37638" us="37638"/><bf gi="12792" ue="37640" us="37640"/><bf gi="12793" ue="37645" us="37645"/><bf gi="12794" ue="37649" us="37647"/><bf gi="12797" ue="37653" us="37652"/><bf gi="12799" ue="37658" us="37656"/><bf gi="12802" ue="37676" us="37660"/><bf gi="12819" ue="37679" us="37678"/><bf gi="12821" ue="37687" us="37682"/><bf gi="12827" ue="37691" us="37690"/><bf gi="12829" ue="37700" us="37700"/><bf gi="12830" ue="37705" us="37703"/><bf gi="12833" ue="37707" us="3!
 7707"/><bf gi="12834" ue="37709" us="37709"/><bf gi="12835" ue="37714" us="37712"/><bf gi="12838" ue="37720" us="37716"/><bf gi="12843" ue="37724" us="37722"/><bf gi="12846" ue="37726" us="37726"/><bf gi="12847" ue="37728" us="37728"/><bf gi="12848" ue="37733" us="37732"/><bf gi="12850" ue="37735" us="37735"/><bf gi="12851" ue="37738" us="37737"/><bf gi="12853" ue="37745" us="37740"/><bf gi="12859" ue="37750" us="37747"/><bf gi="12863" ue="37754" us="37754"/><bf gi="12864" ue="37762" us="37756"/><bf gi="12871" ue="37768" us="37768"/><bf gi="12872" ue="37773" us="37770"/><bf gi="12876" ue="37775" us="37775"/><bf gi="12877" ue="37778" us="37778"/><bf gi="12878" ue="37784" us="37780"/><bf gi="12883" ue="37787" us="37786"/><bf gi="12885" ue="37790" us="37790"/><bf gi="12886" ue="37793" us="37793"/><bf gi="12887" ue="37796" us="37795"/><bf gi="12889" ue="37801" us="37798"/><bf gi="12893" ue="37806" us="37803"/><bf gi="12897" ue="37808" us="37808"/><bf gi="12898" ue="37814" us="3!
 7812"/><bf gi="12901" ue="37818" us="37817"/><bf gi="12903" ue="37825"
 us="37825"/><bf gi="12904" ue="37837" us="37827"/><bf gi="12915" ue="37841" us="37840"/><bf gi="12917" ue="37843" us="37843"/><bf gi="12918" ue="37849" us="37846"/><bf gi="12922" ue="37855" us="37852"/><bf gi="12926" ue="37858" us="37857"/><bf gi="12928" ue="37864" us="37860"/><bf gi="12933" ue="37883" us="37879"/><bf gi="12938" ue="37885" us="37885"/><bf gi="12939" ue="37892" us="37889"/><bf gi="12943" ue="37897" us="37895"/><bf gi="12946" ue="37904" us="37901"/><bf gi="12950" ue="37914" us="37907"/><bf gi="12958" ue="37919" us="37919"/><bf gi="12959" ue="37921" us="37921"/><bf gi="12960" ue="37931" us="37931"/><bf gi="12961" ue="37935" us="37934"/><bf gi="12963" ue="37942" us="37937"/><bf gi="12969" ue="37944" us="37944"/><bf gi="12970" ue="37947" us="37946"/><bf gi="12972" ue="37949" us="37949"/><bf gi="12973" ue="37951" us="37951"/><bf gi="12974" ue="37953" us="37953"/><bf gi="12975" ue="37957" us="37955"/><bf gi="12978" ue="37960" us="37960"/><bf gi="12979" ue="37962" !
 us="37962"/><bf gi="12980" ue="37964" us="37964"/><bf gi="12981" ue="37971" us="37969"/><bf gi="12984" ue="37973" us="37973"/><bf gi="12985" ue="37980" us="37977"/><bf gi="12989" ue="37987" us="37982"/><bf gi="12995" ue="37992" us="37992"/><bf gi="12996" ue="37995" us="37994"/><bf gi="12998" ue="38002" us="37997"/><bf gi="13004" ue="38005" us="38005"/><bf gi="13005" ue="38007" us="38007"/><bf gi="13006" ue="38015" us="38012"/><bf gi="13010" ue="38017" us="38017"/><bf gi="13011" ue="38020" us="38019"/><bf gi="13013" ue="38265" us="38263"/><bf gi="13016" ue="38270" us="38270"/><bf gi="13017" ue="38272" us="38272"/><bf gi="13018" ue="38276" us="38274"/><bf gi="13021" ue="38287" us="38279"/><bf gi="13030" ue="38292" us="38289"/><bf gi="13034" ue="38294" us="38294"/><bf gi="13035" ue="38297" us="38296"/><bf gi="13037" ue="38313" us="38301"/><bf gi="13050" ue="38317" us="38315"/><bf gi="13053" ue="38322" us="38322"/><bf gi="13054" ue="38324" us="38324"/><bf gi="13055" ue="38326" !
 us="38326"/><bf gi="13056" ue="38335" us="38329"/><bf gi="13063" ue="3
8339" us="38339"/><bf gi="13064" ue="38349" us="38342"/><bf gi="13072" ue="38358" us="38352"/><bf gi="13079" ue="38362" us="38360"/><bf gi="13082" ue="38370" us="38364"/><bf gi="13089" ue="38374" us="38372"/><bf gi="13092" ue="38430" us="38428"/><bf gi="13095" ue="38434" us="38433"/><bf gi="13097" ue="38438" us="38436"/><bf gi="13100" ue="38440" us="38440"/><bf gi="13101" ue="38442" us="38442"/><bf gi="13102" ue="38444" us="38444"/><bf gi="13103" ue="38447" us="38446"/><bf gi="13105" ue="38451" us="38449"/><bf gi="13108" ue="38461" us="38455"/><bf gi="13115" ue="38466" us="38463"/><bf gi="13119" ue="38468" us="38468"/><bf gi="13120" ue="38477" us="38475"/><bf gi="13123" ue="38480" us="38479"/><bf gi="13125" ue="38482" us="38482"/><bf gi="13126" ue="38484" us="38484"/><bf gi="13127" ue="38488" us="38486"/><bf gi="13130" ue="38495" us="38491"/><bf gi="13135" ue="38502" us="38497"/><bf gi="13141" ue="38506" us="38506"/><bf gi="13142" ue="38508" us="38508"/><bf gi="13143" ue="38!
 510" us="38510"/><bf gi="13144" ue="38512" us="38512"/><bf gi="13145" ue="38520" us="38514"/><bf gi="13152" ue="38527" us="38522"/><bf gi="13158" ue="38534" us="38529"/><bf gi="13164" ue="38539" us="38536"/><bf gi="13168" ue="38543" us="38541"/><bf gi="13171" ue="38545" us="38545"/><bf gi="13172" ue="38557" us="38548"/><bf gi="13182" ue="38560" us="38559"/><bf gi="13184" ue="38570" us="38563"/><bf gi="13192" ue="38580" us="38574"/><bf gi="13199" ue="38588" us="38582"/><bf gi="13206" ue="38593" us="38592"/><bf gi="13208" ue="38599" us="38596"/><bf gi="13212" ue="38606" us="38601"/><bf gi="13218" ue="38610" us="38609"/><bf gi="13220" ue="38614" us="38613"/><bf gi="13222" ue="38623" us="38616"/><bf gi="13230" ue="38627" us="38626"/><bf gi="13232" ue="38635" us="38632"/><bf gi="13236" ue="38642" us="38639"/><bf gi="13240" ue="38647" us="38646"/><bf gi="13242" ue="38651" us="38649"/><bf gi="13245" ue="38656" us="38656"/><bf gi="13246" ue="38666" us="38658"/><bf gi="13255" ue="38!
 671" us="38669"/><bf gi="13258" ue="38673" us="38673"/><bf gi="13259" 
ue="38675" us="38675"/><bf gi="13260" ue="38678" us="38678"/><bf gi="13261" ue="38686" us="38681"/><bf gi="13267" ue="38692" us="38689"/><bf gi="13271" ue="38696" us="38695"/><bf gi="13273" ue="38698" us="38698"/><bf gi="13274" ue="38707" us="38704"/><bf gi="13278" ue="38713" us="38712"/><bf gi="13280" ue="38715" us="38715"/><bf gi="13281" ue="38718" us="38717"/><bf gi="13283" ue="38724" us="38721"/><bf gi="13287" ue="38726" us="38726"/><bf gi="13288" ue="38730" us="38728"/><bf gi="13291" ue="38735" us="38733"/><bf gi="13294" ue="38738" us="38737"/><bf gi="13296" ue="38748" us="38741"/><bf gi="13304" ue="38750" us="38750"/><bf gi="13305" ue="38756" us="38752"/><bf gi="13310" ue="38763" us="38758"/><bf gi="13316" ue="38766" us="38765"/><bf gi="13318" ue="38769" us="38769"/><bf gi="13319" ue="38772" us="38771"/><bf gi="13321" ue="38781" us="38774"/><bf gi="13329" ue="38785" us="38783"/><bf gi="13332" ue="38790" us="38788"/><bf gi="13335" ue="38793" us="38793"/><bf gi="13336" u!
 e="38795" us="38795"/><bf gi="13337" ue="38797" us="38797"/><bf gi="13338" ue="38800" us="38799"/><bf gi="13340" ue="38810" us="38805"/><bf gi="13346" ue="38812" us="38812"/><bf gi="13347" ue="38816" us="38814"/><bf gi="13350" ue="38819" us="38818"/><bf gi="13352" ue="38822" us="38822"/><bf gi="13353" ue="38824" us="38824"/><bf gi="13354" ue="38830" us="38827"/><bf gi="13358" ue="38838" us="38833"/><bf gi="13364" ue="38842" us="38840"/><bf gi="13367" ue="38844" us="38844"/><bf gi="13368" ue="38847" us="38846"/><bf gi="13370" ue="38849" us="38849"/><bf gi="13371" ue="38862" us="38851"/><bf gi="13383" ue="38865" us="38864"/><bf gi="13385" ue="38868" us="38867"/><bf gi="13387" ue="38873" us="38871"/><bf gi="13390" ue="38878" us="38875"/><bf gi="13394" ue="38881" us="38880"/><bf gi="13396" ue="38884" us="38884"/><bf gi="13397" ue="38895" us="38893"/><bf gi="13400" ue="38904" us="38897"/><bf gi="13408" ue="38907" us="38906"/><bf gi="13410" ue="38911" us="38911"/><bf gi="13411" u!
 e="38915" us="38913"/><bf gi="13414" ue="38920" us="38917"/><bf gi="13
418" ue="38922" us="38922"/><bf gi="13419" ue="38932" us="38924"/><bf gi="13428" ue="38938" us="38934"/><bf gi="13433" ue="38940" us="38940"/><bf gi="13434" ue="38942" us="38942"/><bf gi="13435" ue="38945" us="38944"/><bf gi="13437" ue="38950" us="38947"/><bf gi="13441" ue="38960" us="38955"/><bf gi="13447" ue="38965" us="38962"/><bf gi="13451" ue="38968" us="38967"/><bf gi="13453" ue="38974" us="38971"/><bf gi="13457" ue="38980" us="38980"/><bf gi="13458" ue="38983" us="38982"/><bf gi="13460" ue="38991" us="38986"/><bf gi="13466" ue="39003" us="38993"/><bf gi="13477" ue="39006" us="39006"/><bf gi="13478" ue="39011" us="39010"/><bf gi="13480" ue="39015" us="39013"/><bf gi="13483" ue="39020" us="39018"/><bf gi="13486" ue="39025" us="39023"/><bf gi="13489" ue="39028" us="39027"/><bf gi="13491" ue="39080" us="39080"/><bf gi="13492" ue="39083" us="39082"/><bf gi="13494" ue="39089" us="39085"/><bf gi="13499" ue="39092" us="39092"/><bf gi="13500" ue="39096" us="39094"/><bf gi="135!
 03" ue="39099" us="39098"/><bf gi="13505" ue="39103" us="39103"/><bf gi="13506" ue="39110" us="39106"/><bf gi="13511" ue="39112" us="39112"/><bf gi="13512" ue="39116" us="39116"/><bf gi="13513" ue="39132" us="39131"/><bf gi="13515" ue="39135" us="39135"/><bf gi="13516" ue="39139" us="39137"/><bf gi="13519" ue="39143" us="39141"/><bf gi="13522" ue="39147" us="39145"/><bf gi="13525" ue="39151" us="39149"/><bf gi="13528" ue="39156" us="39154"/><bf gi="13531" ue="39158" us="39158"/><bf gi="13532" ue="39166" us="39164"/><bf gi="13535" ue="39171" us="39170"/><bf gi="13537" ue="39173" us="39173"/><bf gi="13538" ue="39178" us="39175"/><bf gi="13542" ue="39180" us="39180"/><bf gi="13543" ue="39192" us="39184"/><bf gi="13552" ue="39202" us="39194"/><bf gi="13561" ue="39204" us="39204"/><bf gi="13562" ue="39208" us="39206"/><bf gi="13565" ue="39212" us="39211"/><bf gi="13567" ue="39214" us="39214"/><bf gi="13568" ue="39221" us="39217"/><bf gi="13573" ue="39230" us="39225"/><bf gi="135!
 79" ue="39234" us="39232"/><bf gi="13582" ue="39241" us="39237"/><bf g
i="13587" ue="39246" us="39243"/><bf gi="13591" ue="39250" us="39248"/><bf gi="13594" ue="39253" us="39252"/><bf gi="13596" ue="39257" us="39255"/><bf gi="13599" ue="39260" us="39259"/><bf gi="13601" ue="39264" us="39262"/><bf gi="13604" ue="39321" us="39318"/><bf gi="13608" ue="39323" us="39323"/><bf gi="13609" ue="39327" us="39325"/><bf gi="13612" ue="39334" us="39333"/><bf gi="13614" ue="39336" us="39336"/><bf gi="13615" ue="39342" us="39340"/><bf gi="13618" ue="39349" us="39344"/><bf gi="13624" ue="39354" us="39353"/><bf gi="13626" ue="39357" us="39356"/><bf gi="13628" ue="39359" us="39359"/><bf gi="13629" ue="39361" us="39361"/><bf gi="13630" ue="39366" us="39363"/><bf gi="13634" ue="39369" us="39368"/><bf gi="13636" ue="39381" us="39376"/><bf gi="13642" ue="39391" us="39384"/><bf gi="13650" ue="39394" us="39394"/><bf gi="13651" ue="39399" us="39399"/><bf gi="13652" ue="39406" us="39402"/><bf gi="13657" ue="39410" us="39408"/><bf gi="13660" ue="39413" us="39412"/><bf gi!
 ="13662" ue="39417" us="39416"/><bf gi="13664" ue="39419" us="39419"/><bf gi="13665" ue="39423" us="39421"/><bf gi="13668" ue="39429" us="39425"/><bf gi="13673" ue="39436" us="39435"/><bf gi="13675" ue="39443" us="39438"/><bf gi="13681" ue="39446" us="39446"/><bf gi="13682" ue="39449" us="39449"/><bf gi="13683" ue="39454" us="39454"/><bf gi="13684" ue="39456" us="39456"/><bf gi="13685" ue="39460" us="39458"/><bf gi="13688" ue="39464" us="39463"/><bf gi="13690" ue="39467" us="39467"/><bf gi="13691" ue="39470" us="39469"/><bf gi="13693" ue="39472" us="39472"/><bf gi="13694" ue="39475" us="39475"/><bf gi="13695" ue="39480" us="39477"/><bf gi="13699" ue="39486" us="39486"/><bf gi="13700" ue="39493" us="39488"/><bf gi="13706" ue="39495" us="39495"/><bf gi="13707" ue="39502" us="39498"/><bf gi="13712" ue="39505" us="39505"/><bf gi="13713" ue="39511" us="39508"/><bf gi="13717" ue="39515" us="39514"/><bf gi="13719" ue="39517" us="39517"/><bf gi="13720" ue="39519" us="39519"/><bf gi!
 ="13721" ue="39522" us="39522"/><bf gi="13722" ue="39525" us="39524"/>
<bf gi="13724" ue="39531" us="39529"/><bf gi="13727" ue="39592" us="39592"/><bf gi="13728" ue="39594" us="39594"/><bf gi="13729" ue="39600" us="39596"/><bf gi="13734" ue="39602" us="39602"/><bf gi="13735" ue="39606" us="39604"/><bf gi="13738" ue="39609" us="39608"/><bf gi="13740" ue="39612" us="39611"/><bf gi="13742" ue="39617" us="39614"/><bf gi="13746" ue="39620" us="39619"/><bf gi="13748" ue="39622" us="39622"/><bf gi="13749" ue="39624" us="39624"/><bf gi="13750" ue="39641" us="39630"/><bf gi="13762" ue="39644" us="39643"/><bf gi="13764" ue="39648" us="39646"/><bf gi="13767" ue="39655" us="39650"/><bf gi="13773" ue="39663" us="39657"/><bf gi="13780" ue="39669" us="39665"/><bf gi="13785" ue="39671" us="39671"/><bf gi="13786" ue="39675" us="39673"/><bf gi="13789" ue="39677" us="39677"/><bf gi="13790" ue="39686" us="39679"/><bf gi="13798" ue="39689" us="39688"/><bf gi="13800" ue="39694" us="39691"/><bf gi="13804" ue="39696" us="39696"/><bf gi="13805" ue="39698" us="39698"/><!
 bf gi="13806" ue="39702" us="39702"/><bf gi="13807" ue="39708" us="39704"/><bf gi="13812" ue="39712" us="39711"/><bf gi="13814" ue="39715" us="39714"/><bf gi="13816" ue="39723" us="39717"/><bf gi="13823" ue="39727" us="39725"/><bf gi="13826" ue="39733" us="39729"/><bf gi="13831" ue="39735" us="39735"/><bf gi="13832" ue="39741" us="39737"/><bf gi="13837" ue="39749" us="39745"/><bf gi="13842" ue="39752" us="39752"/><bf gi="13843" ue="39759" us="39755"/><bf gi="13848" ue="39761" us="39761"/><bf gi="13849" ue="39768" us="39764"/><bf gi="13854" ue="39771" us="39770"/><bf gi="13856" ue="39774" us="39774"/><bf gi="13857" ue="39777" us="39777"/><bf gi="13858" ue="39779" us="39779"/><bf gi="13859" ue="39782" us="39781"/><bf gi="13861" ue="39784" us="39784"/><bf gi="13862" ue="39791" us="39786"/><bf gi="13868" ue="39797" us="39794"/><bf gi="13872" ue="39801" us="39799"/><bf gi="13875" ue="39808" us="39807"/><bf gi="13877" ue="39815" us="39811"/><bf gi="13882" ue="39819" us="39817"/><!
 bf gi="13885" ue="39828" us="39821"/><bf gi="13893" ue="39831" us="398
30"/><bf gi="13895" ue="39834" us="39834"/><bf gi="13896" ue="39840" us="39837"/><bf gi="13900" ue="39854" us="39846"/><bf gi="13909" ue="39858" us="39856"/><bf gi="13912" ue="39860" us="39860"/><bf gi="13913" ue="39865" us="39863"/><bf gi="13916" ue="39868" us="39867"/><bf gi="13918" ue="39873" us="39870"/><bf gi="13922" ue="39882" us="39878"/><bf gi="13927" ue="39890" us="39886"/><bf gi="13932" ue="39892" us="39892"/><bf gi="13933" ue="39896" us="39894"/><bf gi="13936" ue="39899" us="39899"/><bf gi="13937" ue="39901" us="39901"/><bf gi="13938" ue="39903" us="39903"/><bf gi="13939" ue="39909" us="39905"/><bf gi="13944" ue="39912" us="39911"/><bf gi="13946" ue="39915" us="39914"/><bf gi="13948" ue="39923" us="39919"/><bf gi="13953" ue="39925" us="39925"/><bf gi="13954" ue="39930" us="39927"/><bf gi="13958" ue="39933" us="39933"/><bf gi="13959" ue="39936" us="39935"/><bf gi="13961" ue="39938" us="39938"/><bf gi="13962" ue="39940" us="39940"/><bf gi="13963" ue="39942" us="3994!
 2"/><bf gi="13964" ue="39949" us="39944"/><bf gi="13970" ue="39958" us="39951"/><bf gi="13978" ue="39964" us="39960"/><bf gi="13983" ue="39966" us="39966"/><bf gi="13984" ue="39978" us="39969"/><bf gi="13994" ue="39986" us="39981"/><bf gi="14000" ue="39991" us="39989"/><bf gi="14003" ue="39995" us="39993"/><bf gi="14006" ue="39998" us="39997"/><bf gi="14008" ue="40001" us="40001"/><bf gi="14009" ue="40010" us="40003"/><bf gi="14017" ue="40016" us="40014"/><bf gi="14020" ue="40020" us="40018"/><bf gi="14023" ue="40024" us="40022"/><bf gi="14026" ue="40032" us="40026"/><bf gi="14033" ue="40035" us="40035"/><bf gi="14034" ue="40043" us="40039"/><bf gi="14039" ue="40046" us="40046"/><bf gi="14040" ue="40048" us="40048"/><bf gi="14041" ue="40050" us="40050"/><bf gi="14042" ue="40056" us="40053"/><bf gi="14046" ue="40059" us="40059"/><bf gi="14047" ue="40167" us="40165"/><bf gi="14050" ue="40169" us="40169"/><bf gi="14051" ue="40172" us="40171"/><bf gi="14053" ue="40176" us="4017!
 6"/><bf gi="14054" ue="40180" us="40178"/><bf gi="14057" ue="40183" us
="40182"/><bf gi="14059" ue="40185" us="40185"/><bf gi="14060" ue="40195" us="40194"/><bf gi="14062" ue="40201" us="40198"/><bf gi="14066" ue="40203" us="40203"/><bf gi="14067" ue="40206" us="40206"/><bf gi="14068" ue="40210" us="40209"/><bf gi="14070" ue="40213" us="40213"/><bf gi="14071" ue="40216" us="40215"/><bf gi="14073" ue="40223" us="40219"/><bf gi="14078" ue="40227" us="40227"/><bf gi="14079" ue="40230" us="40230"/><bf gi="14080" ue="40232" us="40232"/><bf gi="14081" ue="40236" us="40234"/><bf gi="14084" ue="40240" us="40239"/><bf gi="14086" ue="40244" us="40242"/><bf gi="14089" ue="40255" us="40250"/><bf gi="14095" ue="40264" us="40257"/><bf gi="14103" ue="40266" us="40266"/><bf gi="14104" ue="40273" us="40272"/><bf gi="14106" ue="40276" us="40275"/><bf gi="14108" ue="40281" us="40281"/><bf gi="14109" ue="40293" us="40284"/><bf gi="14119" ue="40300" us="40297"/><bf gi="14123" ue="40304" us="40303"/><bf gi="14125" ue="40306" us="40306"/><bf gi="14126" ue="40311" us=!
 "40310"/><bf gi="14128" ue="40316" us="40314"/><bf gi="14131" ue="40318" us="40318"/><bf gi="14132" ue="40324" us="40323"/><bf gi="14134" ue="40327" us="40326"/><bf gi="14136" ue="40330" us="40329"/><bf gi="14138" ue="40335" us="40333"/><bf gi="14141" ue="40339" us="40338"/><bf gi="14143" ue="40344" us="40341"/><bf gi="14147" ue="40346" us="40346"/><bf gi="14148" ue="40353" us="40353"/><bf gi="14149" ue="40356" us="40356"/><bf gi="14150" ue="40364" us="40361"/><bf gi="14154" ue="40367" us="40366"/><bf gi="14156" ue="40370" us="40369"/><bf gi="14158" ue="40373" us="40372"/><bf gi="14160" ue="40380" us="40376"/><bf gi="14165" ue="40383" us="40383"/><bf gi="14166" ue="40388" us="40385"/><bf gi="14170" ue="40391" us="40390"/><bf gi="14172" ue="40394" us="40393"/><bf gi="14174" ue="40399" us="40399"/><bf gi="14175" ue="40407" us="40403"/><bf gi="14180" ue="40410" us="40409"/><bf gi="14182" ue="40416" us="40414"/><bf gi="14185" ue="40423" us="40421"/><bf gi="14188" ue="40425" us=!
 "40425"/><bf gi="14189" ue="40427" us="40427"/><bf gi="14190" ue="4043
2" us="40429"/><bf gi="14194" ue="40436" us="40434"/><bf gi="14197" ue="40442" us="40440"/><bf gi="14200" ue="40446" us="40445"/><bf gi="14202" ue="40450" us="40450"/><bf gi="14203" ue="40455" us="40455"/><bf gi="14204" ue="40458" us="40458"/><bf gi="14205" ue="40462" us="40462"/><bf gi="14206" ue="40466" us="40464"/><bf gi="14209" ue="40470" us="40469"/><bf gi="14211" ue="40478" us="40473"/><bf gi="14217" ue="40565" us="40565"/><bf gi="14218" ue="40573" us="40568"/><bf gi="14224" ue="40581" us="40575"/><bf gi="14231" ue="40584" us="40583"/><bf gi="14233" ue="40588" us="40587"/><bf gi="14235" ue="40591" us="40590"/><bf gi="14237" ue="40595" us="40593"/><bf gi="14240" ue="40600" us="40597"/><bf gi="14244" ue="40603" us="40603"/><bf gi="14245" ue="40607" us="40605"/><bf gi="14248" ue="40614" us="40612"/><bf gi="14251" ue="40618" us="40616"/><bf gi="14254" ue="40624" us="40620"/><bf gi="14259" ue="40629" us="40627"/><bf gi="14262" ue="40636" us="40632"/><bf gi="14267" ue="40639!
 " us="40638"/><bf gi="14269" ue="40644" us="40644"/><bf gi="14270" ue="40646" us="40646"/><bf gi="14271" ue="40648" us="40648"/><bf gi="14272" ue="40658" us="40651"/><bf gi="14280" ue="40661" us="40660"/><bf gi="14282" ue="40665" us="40664"/><bf gi="14284" ue="40672" us="40667"/><bf gi="14290" ue="40677" us="40676"/><bf gi="14292" ue="40680" us="40679"/><bf gi="14294" ue="40690" us="40684"/><bf gi="14301" ue="40697" us="40692"/><bf gi="14307" ue="40701" us="40699"/><bf gi="14310" ue="40703" us="40703"/><bf gi="14311" ue="40707" us="40706"/><bf gi="14313" ue="40713" us="40711"/><bf gi="14316" ue="40727" us="40718"/><bf gi="14326" ue="40731" us="40729"/><bf gi="14329" ue="40738" us="40735"/><bf gi="14333" ue="40742" us="40742"/><bf gi="14334" ue="40748" us="40746"/><bf gi="14337" ue="40751" us="40751"/><bf gi="14338" ue="40754" us="40753"/><bf gi="14340" ue="40756" us="40756"/><bf gi="14341" ue="40759" us="40759"/><bf gi="14342" ue="40767" us="40761"/><bf gi="14349" ue="40769!
 " us="40769"/><bf gi="14350" ue="40775" us="40771"/><bf gi="14355" ue=
"40779" us="40778"/><bf gi="14357" ue="40783" us="40782"/><bf gi="14359" ue="40792" us="40786"/><bf gi="14366" ue="40794" us="40794"/><bf gi="14367" ue="40803" us="40797"/><bf gi="14374" ue="40810" us="40806"/><bf gi="14379" ue="40819" us="40812"/><bf gi="14387" ue="40823" us="40821"/><bf gi="14390" ue="40826" us="40826"/><bf gi="14391" ue="40829" us="40829"/><bf gi="14392" ue="40845" us="40845"/><bf gi="14393" ue="40850" us="40847"/><bf gi="14397" ue="40855" us="40852"/><bf gi="14401" ue="40862" us="40860"/><bf gi="14404" ue="40867" us="40864"/><bf gi="14408" ue="40869" us="40869"/><bf gi="14409" ue="63785" us="63785"/><bf gi="14410" ue="63964" us="63964"/><bf gi="14411" ue="64045" us="64014"/><bf gi="14443" ue="64260" us="64259"/><bf gi="14445" ue="65374" us="65281"/><bf gi="14539" ue="65439" us="65377"/><bf gi="14602" ue="65509" us="65504"/><bf gi="0" ue="65535" us="65535"/></bfranges><cid-widths start-index="0"><wx w="1000"/><wx w="0"/><wx w="333"/><wx w="500"/><wx w="50!
 0"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="50!
 0"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><
wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="490"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="875"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="!
 500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="812"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="718"/><wx w="515"/><wx w="718"/><wx w="515"/><wx w="718"/><wx w="515"/><wx w="640"/><wx w="515"/><wx w="640"/><wx w="515"/><wx w="500"/><wx w="500"/><wx w="640"/><wx w="515"/><wx w="687"/><wx w="531"/><wx w="500"/><wx w="531"/><wx w="609"/><wx w="515"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="609"/><wx w="515"/><wx w="609"/><wx w="515"/><wx w="703"/><wx w="531"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="671"/><wx w="625"/><wx w="500"/><wx w="625"/><wx w="500"/><wx w="500"/><wx w="296"/><wx w=!
 "328"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"
/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="390"/><wx w="390"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="578"/><wx w="296"/><wx w="500"/><wx w="500"/><wx w="578"/><wx w="296"/><wx w="500"/><wx w="500"/><wx w="578"/><wx w="296"/><wx w="687"/><wx w="609"/><wx w="500"/><wx w="500"/><wx w="687"/><wx w="609"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="718"/><wx w="546"/><wx w="500"/><wx w="500"/><wx w="718"/><wx w="546"/><wx w="1000"/><wx w="937"/><wx w="625"/><wx w="468"/><wx w="500"/><wx w="500"/><wx w="625"/><wx w="468"/><wx w="531"/><wx w="406"/><wx w="531"/><wx w="406"/><wx w="531"/><wx w="406"/><wx w="531"/><wx w="406"/><wx w="703"/><wx w="390"/><wx w="703"/><wx w="390"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="703"/><wx w="593"/><wx w="703"/><wx w="593"/><wx w="703"/><wx w="593"/><wx w="703"/><wx w="593"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="593"/><wx w="468"/><wx w="593"/><wx w="468"!
 /><wx w="593"/><wx w="468"/><wx w="500"/><wx w="500"/><wx w="718"/><wx w="515"/><wx w="1000"/><wx w="328"/><wx w="718"/><wx w="546"/><wx w="1000"/><wx w="593"/><wx w="1000"/><wx w="593"/><wx w="1000"/><wx w="593"/><wx w="1000"/><wx w="593"/><wx w="1000"/><wx w="593"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="828"/><wx w="500"/><wx w="500"/><wx w="515"/><wx w="500"/><wx w="531"/><wx w="531"/><wx w="515"/><wx w="500"/><wx w="640"/><wx w="640"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="468"/><wx w="500"/><wx w="500"/><wx w="375"/><wx w="671"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="625"/><wx w="625"/><wx w="625"/><wx w="578"/><wx w="328"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="296"/><wx w="375"/><wx w="578"/><wx w="890"/><wx w="859"/><wx w="828"/><wx w="718"/><wx w="1000"/><wx w="500"/><wx w="546"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="468"/><wx w="453"/><wx w="546"/><wx w="500"/><wx w="468"/><wx w="437"/><wx w="500"/><wx!
  w="500"/><wx w="593"/><wx w="406"/><wx w="500"/><wx w="515"/><wx w="5
00"/><wx w="500"/><wx w="500"/><wx w="375"/><wx w="1000"/><wx w="500"/><wx w="531"/><wx w="625"/><wx w="890"/><wx w="609"/><wx w="500"/><wx w="593"/><wx w="484"/><wx w="500"/><wx w="500"/><wx w="515"/><wx w="515"/><wx w="500"/><wx w="500"/><wx w="718"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="359"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="515"/><wx w="515"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/!
 ><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/!
 ><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx 
w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><w!
 x w="500"/><wx w="500"/><wx w="1000"/><wx w="915"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="531"/><wx w="500"/><wx w="500"/><wx w="750"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/>!
 <wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w
="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="781"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="976"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="812"/><wx w="906"/><wx w="812"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/!
 ><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1171"/><wx w="1265"/><wx w="1062"/><wx w="1000"/><wx w="1062"/><wx w="1171"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="843"/><wx w="656"/><wx w="937"/><wx w="1078"/><wx w="1125"/><wx w="968"/><wx w="703"/><wx w="968"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="976"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><!
 wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w=
"500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="976"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="976"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="656"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="562"/><wx w="500"/><wx w="500"/><wx w=!
 "500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="750"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="976"/><wx w="500"/><wx w="562"/><wx w="500"/><wx w="500"/><wx w="562"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/>!
 <wx w="1000"/><wx w="562"/><wx w="500"/><wx w="500"/><wx w="500"/><wx 
w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="976"/><wx w="976"/><wx w="500"/><wx w="500"/><wx w="562"/><wx w="562"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="656"/><wx w="656"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="656"/><wx w="656"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="976"/><wx w="976"/><wx w="976"/><wx w="976"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="976"/><wx w="500"/><wx w="976"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="50!
 0"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="562"/><wx w="562"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="976"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/!
 ><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><w
x w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx !
 w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="976"/><wx 
w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="976"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="976"/><wx w="976"/><wx w="1000"/><wx w="937"/><wx w="976"/><wx w="1000"/><wx w="406"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="976"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="976"/><wx w="976"/><wx w="976"/><wx w="976"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="976"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="915"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="915"/><wx w="1000"/><wx w="1000"/><wx w="915"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="781"/><wx w="781"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="50!
 0"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/></cid-widths></multibyte-extras></font-metrics>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/userconfig.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/userconfig.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/fop/userconfig.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+<!--<!DOCTYPE configuration SYSTEM "config.dtd">-->
+<!-- 
+     this file contains templates which allow an user easy 
+     configuration of Fop. Actually normally you don't need this configuration 
+     file, but if you need to change configuration, you should
+     always use this file and *not* config.xml. 
+     Usage: java org.apache.fop.apps.Fop -c userconfig.xml -fo fo-file -pdf pdf-file
+-->
+
+
+<configuration>
+
+<!--  
+baseDir: normally the base directory is the directory where the fo file is 
+         located. if you want to specify your own, uncomment this entry.
+         This value can also be a URL. Actually, the value is converted to 
+         a URL.
+-->
+<!-- 
+  <entry>
+    <key>baseDir</key>
+    <value></value>
+  </entry>
+-->
+
+<!--  
+fontBaseDir: Similar to baseDir, except that this value is used for fonts. If
+         it isn't specified, the value from baseDir is used.
+-->
+<!-- 
+  <entry>
+    <key>fontBaseDir</key>
+    <value></value>
+  </entry>
+-->
+
+<!--
+************************************************************************
+                        HYPHENATION 
+************************************************************************
+-->
+  
+<!--
+   hyphenation directory 
+   if you want to specify your own directory with hyphenation pattern
+   then uncomment the next entry and add the directory name
+-->
+
+<!--
+  <entry>
+    <key>hyphenation-dir</key>
+    <value>/java/xml-fop/hyph</value>
+  </entry>
+-->
+
+<!--
+************************************************************************
+  Add fonts here
+************************************************************************
+-->
+
+<fonts>
+ <!-- Example Japanese fonts
+ <font metrics-file="msgothic.xml" embed-file="D:\winnt\font\msgothic.ttc" kerning="yes">
+    <font-triplet name="Gothic" style="normal" weight="normal"/>
+    <font-triplet name="Gothic" style="normal" weight="bold"/>
+    <font-triplet name="Gothic" style="italic" weight="normal"/>
+    <font-triplet name="Gothic" style="italic" weight="bold"/>
+ </font>
+ <font metrics-file="msmincho.xml" embed-file="Cyberbit.ttf" kerning="yes">
+    <font-triplet name="Mincho" style="normal" weight="normal"/>
+    <font-triplet name="Mincho" style="normal" weight="bold"/>
+    <font-triplet name="Mincho" style="italic" weight="normal"/>
+    <font-triplet name="Mincho" style="italic" weight="bold"/>
+   </font>
+  -->
+
+<font metrics-file="sazanami-mincho.xml" kerning="yes" embed-file="sazanami-mincho.ttf">
+    <font-triplet name="MS-Mincho" style="normal" weight="normal"/>
+    <font-triplet name="MS-Mincho" style="normal" weight="bold"/>
+    <font-triplet name="MS-Mincho" style="italic" weight="normal"/>
+    <font-triplet name="MS-Mincho" style="italic" weight="bold"/>
+    <font-triplet name="MSMincho" style="normal" weight="normal"/>
+    <font-triplet name="MSMincho" style="normal" weight="bold"/>
+    <font-triplet name="MSMincho" style="italic" weight="normal"/>
+    <font-triplet name="MSMincho" style="italic" weight="bold"/>
+    <font-triplet name="Mincho" style="normal" weight="normal"/>
+    <font-triplet name="Mincho" style="normal" weight="bold"/>
+    <font-triplet name="Mincho" style="italic" weight="normal"/>
+    <font-triplet name="Mincho" style="italic" weight="bold"/>
+    <font-triplet name="‚l‚r–¾’©" style="normal" weight="normal"/>
+    <font-triplet name="‚l‚r–¾’©" style="normal" weight="bold"/>
+    <font-triplet name="‚l‚r–¾’©" style="italic" weight="normal"/>
+    <font-triplet name="‚l‚r–¾’©" style="italic" weight="bold"/>
+    <font-triplet name="serif" style="normal" weight="normal"/>
+    <font-triplet name="serif" style="normal" weight="bold"/>
+    <font-triplet name="serif" style="italic" weight="normal"/>
+    <font-triplet name="serif" style="italic" weight="bold"/>
+    <font-triplet name="Mincho" style="normal" weight="normal"/>
+    <font-triplet name="Mincho" style="normal" weight="bold"/>
+    <font-triplet name="Mincho" style="italic" weight="normal"/>
+    <font-triplet name="Mincho" style="italic" weight="bold"/>
+    <font-triplet name="SazanamiMincho" style="normal" weight="normal"/>
+    <font-triplet name="SazanamiMincho" style="normal" weight="bold"/>
+    <font-triplet name="SazanamiMincho" style="italic" weight="normal"/>
+    <font-triplet name="SazanamiMincho" style="italic" weight="bold"/> 
+    <font-triplet name="Mincho-Regular" style="normal" weight="normal"/>
+    <font-triplet name="Mincho-Regular" style="normal" weight="bold"/>
+    <font-triplet name="Mincho-Regular" style="italic" weight="normal"/>
+    <font-triplet name="Mincho-Regular" style="italic" weight="bold"/>
+    <font-triplet name="‚³‚´‚È‚Ý–¾’©" style="normal" weight="normal"/>
+    <font-triplet name="‚³‚´‚È‚Ý–¾’©" style="normal" weight="bold"/>
+    <font-triplet name="‚³‚´‚È‚Ý–¾’©" style="italic" weight="normal"/>
+    <font-triplet name="‚³‚´‚È‚Ý–¾’©" style="italic" weight="bold"/>    
+ </font>    
+ 
+  <font metrics-file="sazanami-gothic.xml" kerning="yes" embed-file="sazanami-gothic.ttf">
+    <font-triplet name="MS-Gothic" style="normal" weight="normal"/>
+    <font-triplet name="MS-Gothic" style="normal" weight="bold"/>
+    <font-triplet name="MS-Gothic" style="italic" weight="normal"/>
+    <font-triplet name="MS-Gothic" style="italic" weight="bold"/>
+    <font-triplet name="MSGothic" style="normal" weight="normal"/>
+    <font-triplet name="MSGothic" style="normal" weight="bold"/>
+    <font-triplet name="MSGothic" style="italic" weight="normal"/>
+    <font-triplet name="MSGothic" style="italic" weight="bold"/>
+    <font-triplet name="Gothic" style="normal" weight="normal"/>
+    <font-triplet name="Gothic" style="normal" weight="bold"/>
+    <font-triplet name="Gothic" style="italic" weight="normal"/>
+    <font-triplet name="Gothic" style="italic" weight="bold"/>
+    <font-triplet name="‚l‚r–¾’©" style="normal" weight="normal"/>
+    <font-triplet name="‚l‚r–¾’©" style="normal" weight="bold"/>
+    <font-triplet name="‚l‚r–¾’©" style="italic" weight="normal"/>
+    <font-triplet name="‚l‚r–¾’©" style="italic" weight="bold"/>
+    <font-triplet name="sans-serif" style="normal" weight="normal"/>
+    <font-triplet name="sans-serif" style="normal" weight="bold"/>
+    <font-triplet name="sans-serif" style="italic" weight="normal"/>
+    <font-triplet name="sans-serif" style="italic" weight="bold"/>
+    <font-triplet name="Gothic" style="normal" weight="normal"/>
+    <font-triplet name="Gothic" style="normal" weight="bold"/>
+    <font-triplet name="Gothic" style="italic" weight="normal"/>
+    <font-triplet name="Gothic" style="italic" weight="bold"/>
+    <font-triplet name="SazanamiGothic" style="normal" weight="normal"/>
+    <font-triplet name="SazanamiGothic" style="normal" weight="bold"/>
+    <font-triplet name="SazanamiGothic" style="italic" weight="normal"/>
+    <font-triplet name="SazanamiGothic" style="italic" weight="bold"/> 
+    <font-triplet name="Gothic-Regular" style="normal" weight="normal"/>
+    <font-triplet name="Gothic-Regular" style="normal" weight="bold"/>
+    <font-triplet name="Gothic-Regular" style="italic" weight="normal"/>
+    <font-triplet name="Gothic-Regular" style="italic" weight="bold"/>
+    <font-triplet name="‚³‚´‚Ȃ݃SƒVƒbƒN" style="normal" weight="normal"/>
+    <font-triplet name="‚³‚´‚Ȃ݃SƒVƒbƒN" style="normal" weight="bold"/>
+    <font-triplet name="‚³‚´‚Ȃ݃SƒVƒbƒN" style="italic" weight="normal"/>
+    <font-triplet name="‚³‚´‚Ȃ݃SƒVƒbƒN" style="italic" weight="bold"/>     
+ </font>
+ 
+ 
+ 
+</fonts>
+
+</configuration>
+
+
+

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/styles/fopdf.xsl
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/styles/fopdf.xsl	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/styles/fopdf.xsl	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,516 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+
+<!--
+
+    This is the XSL FO configuration file for the Hibernate
+    Reference Documentation. It defines a custom titlepage and
+    the parameters for the A4 sized PDF printable output.
+
+    It took me days to figure out this stuff and fix most of
+    the obvious bugs in the DocBook XSL distribution. Some of
+    the workarounds might not be appropriate with a newer version
+    of DocBook XSL. This file is released as part of Hibernate,
+    hence LGPL licensed.
+
+    christian at hibernate.org
+
+-->
+
+<!DOCTYPE xsl:stylesheet [
+    <!ENTITY db_xsl_path        "../../support/docbook-xsl/">
+]>
+
+<xsl:stylesheet
+    version="1.0"
+    xmlns="http://www.w3.org/TR/xhtml1/transitional"
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:fo="http://www.w3.org/1999/XSL/Format"
+    exclude-result-prefixes="#default">
+
+    <xsl:import href="&db_xsl_path;/fo/docbook.xsl"/>
+
+    <!--###################################################
+                       Custom Title Page
+        ################################################### -->
+
+    <xsl:template name="book.titlepage.recto">
+        <fo:block>
+            <fo:table table-layout="fixed" width="175mm">
+                <fo:table-column column-width="175mm"/>
+                <fo:table-body>
+                    <fo:table-row>
+                        <fo:table-cell text-align="center">
+                            <fo:block>
+                                <fo:external-graphic src="file:images/hibernate_logo_a.png"/>
+                            </fo:block>
+                            <fo:block font-family="Helvetica" font-size="22pt" padding-before="10mm">
+                                <xsl:value-of select="bookinfo/subtitle"/>
+                            </fo:block>
+                            <fo:block font-family="Helvetica" font-size="12pt" padding="10mm">
+                                Version:
+                                <xsl:value-of select="bookinfo/releaseinfo"/>
+                            </fo:block>
+                        </fo:table-cell>
+                    </fo:table-row>
+                </fo:table-body>
+            </fo:table>
+        </fo:block>
+    </xsl:template>
+
+    <!-- Prevent blank pages in output -->
+    <xsl:template name="book.titlepage.before.verso">
+    </xsl:template>
+    <xsl:template name="book.titlepage.verso">
+    </xsl:template>
+    <xsl:template name="book.titlepage.separator">
+    </xsl:template>
+
+    <!--###################################################
+                          Header
+        ################################################### -->
+
+    <!-- More space in the center header for long text -->
+    <xsl:attribute-set name="header.content.properties">
+        <xsl:attribute name="font-family">
+            <xsl:value-of select="$body.font.family"/>
+        </xsl:attribute>
+        <xsl:attribute name="margin-left">-5em</xsl:attribute>
+        <xsl:attribute name="margin-right">-5em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!--###################################################
+                          Custom Footer
+        ################################################### -->
+
+    <!-- This footer prints the Hibernate version number on the left side -->
+    <xsl:template name="footer.content">
+        <xsl:param name="pageclass" select="''"/>
+        <xsl:param name="sequence" select="''"/>
+        <xsl:param name="position" select="''"/>
+        <xsl:param name="gentext-key" select="''"/>
+
+        <xsl:variable name="Version">
+            <xsl:choose>
+                <xsl:when test="//releaseinfo">
+                    <xsl:text>Hibernate </xsl:text>
+                    <xsl:value-of select="//releaseinfo"/>
+                </xsl:when>
+                <xsl:otherwise>
+                    <!-- nop -->
+                </xsl:otherwise>
+            </xsl:choose>
+        </xsl:variable>
+
+        <xsl:choose>
+            <xsl:when test="$sequence='blank'">
+                <xsl:choose>
+                    <xsl:when test="$double.sided != 0 and $position = 'left'">
+                        <xsl:value-of select="$Version"/>
+                    </xsl:when>
+
+                    <xsl:when test="$double.sided = 0 and $position = 'center'">
+                        <!-- nop -->
+                    </xsl:when>
+
+                    <xsl:otherwise>
+                        <fo:page-number/>
+                    </xsl:otherwise>
+                </xsl:choose>
+            </xsl:when>
+
+            <xsl:when test="$pageclass='titlepage'">
+                <!-- nop: other titlepage sequences have no footer -->
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='left'">
+                <fo:page-number/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='right'">
+                <fo:page-number/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided = 0 and $position='right'">
+                <fo:page-number/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='left'">
+                <xsl:value-of select="$Version"/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='right'">
+                <xsl:value-of select="$Version"/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided = 0 and $position='left'">
+                <xsl:value-of select="$Version"/>
+            </xsl:when>
+
+            <xsl:otherwise>
+                <!-- nop -->
+            </xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+    <!--###################################################
+                       Custom Toc Line
+        ################################################### -->
+    
+    <!-- Improve the TOC. -->
+    <xsl:template name="toc.line">
+        <xsl:variable name="id">
+            <xsl:call-template name="object.id"/>
+        </xsl:variable>
+
+        <xsl:variable name="label">
+            <xsl:apply-templates select="." mode="label.markup"/>
+        </xsl:variable>
+
+        <fo:block text-align-last="justify"
+            end-indent="{$toc.indent.width}pt"
+            last-line-end-indent="-{$toc.indent.width}pt">
+            <fo:inline keep-with-next.within-line="always">
+                <fo:basic-link internal-destination="{$id}">
+
+                    <!-- Chapter titles should be bold. -->
+                    <xsl:choose>
+                        <xsl:when test="local-name(.) = 'chapter'">
+                            <xsl:attribute name="font-weight">bold</xsl:attribute>
+                        </xsl:when>
+                    </xsl:choose>
+
+                    <xsl:if test="$label != ''">
+                        <xsl:copy-of select="$label"/>
+                        <xsl:value-of select="$autotoc.label.separator"/>
+                    </xsl:if>
+                    <xsl:apply-templates select="." mode="titleabbrev.markup"/>
+                </fo:basic-link>
+            </fo:inline>
+            <fo:inline keep-together.within-line="always">
+                <xsl:text> </xsl:text>
+                <fo:leader leader-pattern="dots"
+                    leader-pattern-width="3pt"
+                    leader-alignment="reference-area"
+                    keep-with-next.within-line="always"/>
+                <xsl:text> </xsl:text>
+                <fo:basic-link internal-destination="{$id}">
+                    <fo:page-number-citation ref-id="{$id}"/>
+                </fo:basic-link>
+            </fo:inline>
+        </fo:block>
+    </xsl:template>
+
+    <!--###################################################
+                          Extensions
+        ################################################### -->
+
+    <!-- These extensions are required for table printing and other stuff -->
+    <xsl:param name="use.extensions">1</xsl:param>
+    <xsl:param name="tablecolumns.extension">0</xsl:param>
+    <!-- FOP provide only PDF Bookmarks at the moment -->
+    <xsl:param name="fop.extensions">1</xsl:param>
+
+    <!--###################################################
+                          Table Of Contents
+        ################################################### -->
+
+    <!-- Generate the TOCs for named components only -->
+    <xsl:param name="generate.toc">
+        book   toc
+    </xsl:param>
+    
+    <!-- Show only Sections up to level 3 in the TOCs -->
+    <xsl:param name="toc.section.depth">3</xsl:param>
+    
+    <!-- Dot and Whitespace as separator in TOC between Label and Title-->
+    <xsl:param name="autotoc.label.separator" select="'.  '"/>
+
+
+    <!--###################################################
+                       Paper & Page Size
+        ################################################### -->
+    
+    <!-- Paper type, no headers on blank pages, no double sided printing -->
+    <xsl:param name="paper.type" select="'A4'"/>
+    <xsl:param name="double.sided">0</xsl:param>
+    <xsl:param name="headers.on.blank.pages">0</xsl:param>
+    <xsl:param name="footers.on.blank.pages">0</xsl:param>
+
+    <!-- Space between paper border and content (chaotic stuff, don't touch) -->
+    <xsl:param name="page.margin.top">5mm</xsl:param>
+    <xsl:param name="region.before.extent">10mm</xsl:param>
+    <xsl:param name="body.margin.top">10mm</xsl:param>
+
+    <xsl:param name="body.margin.bottom">15mm</xsl:param>
+    <xsl:param name="region.after.extent">10mm</xsl:param>
+    <xsl:param name="page.margin.bottom">0mm</xsl:param>
+
+    <xsl:param name="page.margin.outer">18mm</xsl:param>
+    <xsl:param name="page.margin.inner">18mm</xsl:param>
+
+    <!-- No intendation of Titles -->
+    <xsl:param name="title.margin.left">0pc</xsl:param>
+
+    <!--###################################################
+                       Fonts & Styles
+        ################################################### -->
+
+    <!-- Default Font size -->
+    <xsl:param name="body.font.master">11</xsl:param>
+
+    <!-- Line height in body text -->
+    <xsl:param name="line-height">1.4</xsl:param>
+
+    <!-- Monospaced fonts are smaller than regular text -->
+    <xsl:attribute-set name="monospace.properties">
+        <xsl:attribute name="font-family">
+            <xsl:value-of select="$monospace.font.family"/>
+        </xsl:attribute>
+        <xsl:attribute name="font-size">0.8em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!--###################################################
+                       Tables
+        ################################################### -->
+
+    <!-- The table width should be adapted to the paper size -->
+    <xsl:param name="default.table.width">17.4cm</xsl:param>
+
+    <!-- Some padding inside tables -->
+    <xsl:attribute-set name="table.cell.padding">
+        <xsl:attribute name="padding-left">4pt</xsl:attribute>
+        <xsl:attribute name="padding-right">4pt</xsl:attribute>
+        <xsl:attribute name="padding-top">4pt</xsl:attribute>
+        <xsl:attribute name="padding-bottom">4pt</xsl:attribute>
+    </xsl:attribute-set>
+    
+    <!-- Only hairlines as frame and cell borders in tables -->
+    <xsl:param name="table.frame.border.thickness">0.1pt</xsl:param>
+    <xsl:param name="table.cell.border.thickness">0.1pt</xsl:param>
+
+    <!--###################################################
+                             Labels
+        ################################################### -->
+
+    <!-- Label Chapters and Sections (numbering) -->
+    <xsl:param name="chapter.autolabel">1</xsl:param>
+    <xsl:param name="section.autolabel" select="1"/>
+    <xsl:param name="section.label.includes.component.label" select="1"/>
+
+    <!-- Label only Sections up to level 2 -->
+    <xsl:param name="local.l10n.xml" select="document('')"/>
+    <l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0">
+        <l:l10n language="en">
+            <l:context name="title-numbered">
+                <l:template name="sect3" text="%t"/>
+                <l:template name="sect4" text="%t"/>
+                <l:template name="sect5" text="%t"/>
+            </l:context>
+            <l:context name="section-xref-numbered">
+                <l:template name="sect3" text="the section called %t"/>
+                <l:template name="sect4" text="the section called %t"/>
+                <l:template name="sect5" text="the section called %t"/>
+            </l:context>
+        </l:l10n>
+    </l:i18n>
+    
+    <!--###################################################
+                             Titles
+        ################################################### -->
+    
+    <!-- Chapter title size -->
+    <xsl:attribute-set name="chapter.titlepage.recto.style">
+        <xsl:attribute name="text-align">left</xsl:attribute>
+        <xsl:attribute name="font-weight">bold</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.8"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+    </xsl:attribute-set>
+
+    <!-- Why is the font-size for chapters hardcoded in the XSL FO templates? 
+        Let's remove it, so this sucker can use our attribute-set only... -->
+    <xsl:template match="title" mode="chapter.titlepage.recto.auto.mode">
+        <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
+            xsl:use-attribute-sets="chapter.titlepage.recto.style">
+            <xsl:call-template name="component.title">
+                <xsl:with-param name="node" select="ancestor-or-self::chapter[1]"/>
+            </xsl:call-template>
+        </fo:block>
+    </xsl:template>
+    
+    <!-- Sections 1, 2 and 3 titles have a small bump factor and padding -->
+    <xsl:attribute-set name="section.title.level1.properties">
+        <xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.5"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+    <xsl:attribute-set name="section.title.level2.properties">
+        <xsl:attribute name="space-before.optimum">0.6em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.6em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.6em</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.25"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+    <xsl:attribute-set name="section.title.level3.properties">
+        <xsl:attribute name="space-before.optimum">0.4em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.4em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.4em</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.0"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!-- Titles of formal objects (tables, examples, ...) -->
+    <xsl:attribute-set name="formal.title.properties" use-attribute-sets="normal.para.spacing">
+        <xsl:attribute name="font-weight">bold</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="hyphenate">false</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.4em</xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.6em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.8em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!--###################################################
+                          Programlistings
+        ################################################### -->
+    
+    <!-- Verbatim text formatting (programlistings) -->
+    <xsl:attribute-set name="verbatim.properties">
+        <xsl:attribute name="space-before.minimum">1em</xsl:attribute>
+        <xsl:attribute name="space-before.optimum">1em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+        <xsl:attribute name="border-color">#444444</xsl:attribute>
+        <xsl:attribute name="border-style">solid</xsl:attribute>
+        <xsl:attribute name="border-width">0.1pt</xsl:attribute>
+        <xsl:attribute name="padding-top">0.5em</xsl:attribute>
+        <xsl:attribute name="padding-left">0.5em</xsl:attribute>
+        <xsl:attribute name="padding-right">0.5em</xsl:attribute>
+        <xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
+        <xsl:attribute name="margin-left">0.5em</xsl:attribute>
+        <xsl:attribute name="margin-right">0.5em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!-- Shade (background) programlistings -->
+    <xsl:param name="shade.verbatim">1</xsl:param>
+    <xsl:attribute-set name="shade.verbatim.style">
+        <xsl:attribute name="background-color">#F0F0F0</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!--###################################################
+                             Callouts
+        ################################################### -->
+
+    <!-- We want to use callouts... -->
+    <xsl:param name="callout.extensions">1</xsl:param>
+
+    <!-- Place callout bullets at this column in programmlisting.-->
+    <xsl:param name="callout.defaultcolumn">90</xsl:param>
+
+    <!--
+        No, don't use crappy graphics for the callout bullets. This setting
+        enables some weird Unicode rendering for some fancy bullet points
+        in callouts. By default, this can only count to 10 and produces
+        strange results if you ever have more than 10 callouts for one
+        programlisting. We will fix that next.
+    -->
+    <xsl:param name="callout.graphics">0</xsl:param>
+
+    <!--
+        Again, fun with DocBook XSL: The callout bullets are rendered in
+        two places: In the programlisting itself and in the list below
+        the listing, with the actual callout text. The rendering in the
+        programlisting is some XSL transformer extension (e.g. a Saxon
+        extension), so we can't change that without messing with the
+        extensions. We only can turn it off by setting this limit to
+        zero, then, a simple bracket style like "(3)" and "(4)" will
+        be used in the programlisting.
+    -->
+    <xsl:param name="callout.unicode.number.limit" select="'0'"></xsl:param>
+
+    <!--
+        The callout bullets in the actual callout list will be rendered
+        with an XSL FO template. The default template is broken: limited to 10
+        nice looking Unicode bullet points and then it doesn't print anything,
+        the fallback doesn't work. We implement our own template, which is not
+        as complicated, more ugly, but works. As always, function is more
+        important than form.
+    -->
+    <xsl:template name="callout-bug">
+        <xsl:param name="conum" select='1'/>
+        <fo:inline
+            color="black"
+            padding-top="0.1em"
+            padding-bottom="0.1em"
+            padding-start="0.2em"
+            padding-end="0.2em"
+            baseline-shift="0.1em"
+            font-family="{$monospace.font.family}"
+            font-weight="bold"
+            font-size="75%">
+            <xsl:text>(</xsl:text>
+            <xsl:value-of select="$conum"/>
+            <xsl:text>)</xsl:text>
+        </fo:inline>
+
+    </xsl:template>
+
+    <!--###################################################
+                              Misc
+        ################################################### -->
+
+    <!-- Correct placement of titles for figures and examples. -->
+    <xsl:param name="formal.title.placement">
+        figure after
+        example before
+        equation before
+        table before
+        procedure before
+    </xsl:param>
+    
+    <!-- Format Variable Lists as Blocks (prevents horizontal overflow). -->
+    <xsl:param name="variablelist.as.blocks">1</xsl:param>
+
+    <!-- The horrible list spacing problems, this is much better. -->
+    <xsl:attribute-set name="list.block.spacing">
+        <xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!-- Newer DocBook XSL apparently thinks that some sections are by
+         default "draft" status, and this idiotic thing is by default
+         also set to "maybe", so it spits out a lot of errors with the
+         latest FOP as the XSL/FO styles have references to some draft
+         watermarks, which you actually don't want in the first place.
+         Turn this crap off. If you have to work with the "status"
+         attribute, don't.
+    -->
+    <xsl:param name="draft.mode" select="'no'"/>
+
+</xsl:stylesheet>

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/styles/html.xsl
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/styles/html.xsl	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/styles/html.xsl	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+
+<!--
+
+    This is the XSL HTML configuration file for the Hibernate
+    Reference Documentation.
+
+    It took me days to figure out this stuff and fix most of
+    the obvious bugs in the DocBook XSL distribution. Some of
+    the workarounds might not be appropriate with a newer version
+    of DocBook XSL. This file is released as part of Hibernate,
+    hence LGPL licensed.
+
+    christian at hibernate.org
+-->
+
+<!DOCTYPE xsl:stylesheet [
+    <!ENTITY db_xsl_path        "../../support/docbook-xsl/">
+]>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0"
+                xmlns="http://www.w3.org/TR/xhtml1/transitional"
+                exclude-result-prefixes="#default">
+                
+<xsl:import href="&db_xsl_path;/html/docbook.xsl"/>
+
+<!--###################################################
+                     HTML Settings
+    ################################################### -->   
+
+    <xsl:param name="html.stylesheet">../shared/css/html.css</xsl:param>
+
+    <!-- These extensions are required for table printing and other stuff -->
+    <xsl:param name="use.extensions">1</xsl:param>
+    <xsl:param name="tablecolumns.extension">0</xsl:param>
+    <xsl:param name="callout.extensions">1</xsl:param>
+    <xsl:param name="graphicsize.extension">0</xsl:param>
+
+<!--###################################################
+                      Table Of Contents
+    ################################################### -->   
+
+    <!-- Generate the TOCs for named components only -->
+    <xsl:param name="generate.toc">
+        book   toc
+    </xsl:param>
+    
+    <!-- Show only Sections up to level 3 in the TOCs -->
+    <xsl:param name="toc.section.depth">3</xsl:param>
+    
+<!--###################################################
+                         Labels
+    ################################################### -->   
+
+    <!-- Label Chapters and Sections (numbering) -->
+    <xsl:param name="chapter.autolabel">1</xsl:param>
+    <xsl:param name="section.autolabel" select="1"/>
+    <xsl:param name="section.label.includes.component.label" select="1"/>
+
+<!--###################################################
+                         Callouts
+    ################################################### -->
+
+    <!-- Don't use graphics, use a simple number style -->
+    <xsl:param name="callout.graphics">0</xsl:param>
+
+    <!-- Place callout marks at this column in annotated areas -->
+    <xsl:param name="callout.defaultcolumn">90</xsl:param>
+
+<!--###################################################
+                          Misc
+    ################################################### -->   
+
+    <!-- Placement of titles -->
+    <xsl:param name="formal.title.placement">
+        figure after
+        example before
+        equation before
+        table before
+        procedure before
+    </xsl:param>    
+    
+</xsl:stylesheet>

Added: trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/styles/html_chunk.xsl
===================================================================
--- trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/styles/html_chunk.xsl	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ja-JP/src/no-idea-what-to-do-with-these-yet/styles/html_chunk.xsl	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="Shift_JIS"?>
+
+<!--
+
+    This is the XSL HTML configuration file for the Hibernate
+    Reference Documentation.
+
+    It took me days to figure out this stuff and fix most of
+    the obvious bugs in the DocBook XSL distribution. Some of
+    the workarounds might not be appropriate with a newer version
+    of DocBook XSL. This file is released as part of Hibernate,
+    hence LGPL licensed.
+
+    christian at hibernate.org
+-->
+
+<!DOCTYPE xsl:stylesheet [
+    <!ENTITY db_xsl_path        "../../support/docbook-xsl/">
+]>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0"
+                xmlns="http://www.w3.org/TR/xhtml1/transitional"
+                exclude-result-prefixes="#default">
+                
+<xsl:import href="&db_xsl_path;/html/chunk.xsl"/>
+
+<!--###################################################
+                     HTML Settings
+    ################################################### -->   
+
+    <xsl:param name="chunk.section.depth">'5'</xsl:param>
+    <xsl:param name="use.id.as.filename">'1'</xsl:param>
+    <xsl:param name="html.stylesheet">../shared/css/html.css</xsl:param>
+
+    <!-- These extensions are required for table printing and other stuff -->
+    <xsl:param name="use.extensions">1</xsl:param>
+    <xsl:param name="tablecolumns.extension">0</xsl:param>
+    <xsl:param name="callout.extensions">1</xsl:param>
+    <xsl:param name="graphicsize.extension">0</xsl:param>
+    
+<!--###################################################
+                      Table Of Contents
+    ################################################### -->   
+
+    <!-- Generate the TOCs for named components only -->
+    <xsl:param name="generate.toc">
+        book   toc
+    </xsl:param>
+    
+    <!-- Show only Sections up to level 3 in the TOCs -->
+    <xsl:param name="toc.section.depth">3</xsl:param>
+
+<!--###################################################
+                         Labels
+    ################################################### -->   
+
+    <!-- Label Chapters and Sections (numbering) -->
+    <xsl:param name="chapter.autolabel">1</xsl:param>
+    <xsl:param name="section.autolabel" select="1"/>
+    <xsl:param name="section.label.includes.component.label" select="1"/>
+                
+<!--###################################################
+                         Callouts
+    ################################################### -->   
+
+    <!-- Don't use graphics, use a simple number style -->
+    <xsl:param name="callout.graphics">0</xsl:param>
+
+    <!-- Place callout marks at this column in annotated areas -->
+    <xsl:param name="callout.defaultcolumn">90</xsl:param>
+
+<!--###################################################
+                          Misc
+    ################################################### -->   
+
+    <!-- Placement of titles -->
+    <xsl:param name="formal.title.placement">
+        figure after
+        example before
+        equation before
+        table before
+        procedure before
+    </xsl:param>    
+    
+</xsl:stylesheet>

Added: trunk/Hibernate3/documentation/manual/ko-KR/README-KO.txt
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/README-KO.txt	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/README-KO.txt	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,85 @@
+[NOTICE]FOR Korean,
+	ÀÌ ¹ø¿ª¹°¿¡¼­ ¿¹Á¦ ³»ÀÇ ÁÖ¼®¿¡ ´ëÇÑ ¿µ¹®À» ¿ø¹® ±×´ë·Î µÎ¾ú½À´Ï´Ù. 
+	ÀÌÀ¯´Â ¿¹Á¦ ºÎºÐ¿¡ ÇÑ±Û ÆùÆ®¸¦ Àû¿ëÇÒ °æ¿ì¿¡, ÅؽºÆ®µéÀÌ Àϱ׷¯Áö´Â ¹®Á¦°¡ 
+	Á¸ÀçÇϱ⿡ ±âÁ¸ÀÇ ¹ø¿ªµÈ ¿¹Á¦ ÁÖ¼®À» ¸ðµÎ ·Ñ¹é½ÃÄ×½À´Ï´Ù. 
+	Â÷ÈÄ¿¡ ÇÑ±Û ÆùÆ®¿¡ ¸Âµµ·Ï Çü½ÄÀ» ÀçÆíÁýÇؾßÇÒ ºÎºÐÀÌ´Ï ¾çÇعٶø´Ï´Ù.
+	±×·³ ÇÏÀ̹ö³×ÀÌÆ®¿Í Áñ°Å¿î ½Ã°£À» º¸³»½Ã±æ ¹Ù¶ø´Ï´Ù. 
+	
+	¹ø¿ªÀÚ ±èÁ¾´ë(jdkim528 at korea.com)
+	Blog : http://blog.naver.com/jdkim528/
+
+[Down/Config/Build]
+ * ±âÁ¸ÀÇ CVS¿¡¼­ SVNÀ¸·Î ¹Ù²î¸é¼­ ½Å±Ô »ç¿ëÀÚµéÀ» À§ÇÑ ±æÀâÀ̸¦ ÀÛ¼ºÇÒ ÇÊ¿ä°¡ 
+     »ý°å³×¿ä... 
+  
+    ÇÊÀÚ´Â °³ÀÎÀûÀ¸·Î TortoiseSVN°ú Subclipse¸¦ »ç¿ëÇÏ°í ÀÖÀ¸³ª Subclpse¸¦ Áß½ÉÀ¸·Î 
+    ¼³¸íÇÒ±î ÇÕ´Ï´Ù.(¼±È£ÇÏ´Â svn Ŭ¶óÀ̾ðÆ®°¡ ÀÖ´Ù¸é ÇØ´ç Ŭ¶óÀ̾ðÆ®ÀÇ ¼³Á¤¿¡ 
+    µû¶ó ¼³Á¤ÇÑ ÈÄ¿¡ »ç¿ëÇϼŵµ µÉ °ÍÀÔ´Ï´Ù.)
+        
+        [Subclipse ¼³Ä¡]
+        
+        Subclipse¸¦ ¼³Ä¡ÇÏ´Â ¹æ¹ýÀº http://subclipse.tigris.org/install.html À» ÂüÁ¶ÇÏ¿© 
+        eclipseÀÇ µµ¿ò¸»>¼ÒÇÁÆ®¿þ¾î°»½Å>ã±â ¹× ¼³Ä¡ ¸Þ´º¸¦ ÅëÇØ ½±°Ô ¼³Ä¡ÇÒ ¼ö ÀÖ½À´Ï´Ù.
+        
+        [Subclipse Checkout]
+        0) Subclipse ¼³Ä¡°¡ ³¡³µÀ¸¸é ÀÌŬ¸³½º¸¦ Àç½ÃÀÛÇϽʽÿÀ.
+        1) ÀÌŬ¸³½ºÀÇ Perspective ¿­±â¿¡¼­ SVN Repository exploringÀ» ¿­¾î ÀúÀå¼Ò¸¦ µî·ÏÇÏ¿© »ç¿ëÇϰųª
+           ÀÌŬ¸³½ºÀÇ ÆÐÅ°Áö Ž»ö±â¿¡¼­ ¸¶¿ì½º ¿À¸¥ÂÊ Æ˾÷ ¸Þ´º¿¡¼­ "ÇÁ·ÎÁ§Æ®"¸¦ »ý¼º½Ãŵ´Ï´Ù.
+           ¿©±â¼­´Â "ÇÁ·ÎÁ§Æ®" »ý¼º ¹æ¹ýÀ» ¼³¸íÇÕ´Ï´Ù.
+        2) ÀÌŬ¸³½ºÀÇ ÆÐÅ°Áö Ž»ö±â¿¡¼­ ¸¶¿ì½º ¿À¸¥ÂÊ Æ˾÷ ¸Þ´º¿¡¼­ "ÇÁ·ÎÁ§Æ®"¸¦ Ŭ¸¯ÇÑ´Ù
+        3) Æ˾÷ âÀÇ "SVN" ³ëµå¿¡¼­ "Checkout Projects from SVN"À» ¼±ÅÃÇÑ´Ù
+        4) "´ÙÀ½" ¹öÆ°À» Ŭ¸¯ÇÑ´Ù
+        5) "Create a new respository location"À» ¼±ÅÃÇÑ´Ù
+        6) ´ÙÀ½" ¹öÆ°À» Ŭ¸¯ÇÑ´Ù
+        7) Location url¿¡ "http://anonhibernate.labs.jboss.com/trunk/Hibernate3" ¶Ç´Â 
+           "https://hibernate.labs.jboss.com/repos/hibernate/trunk" À» ÀÔ·ÂÇÕ´Ï´Ù.
+        8) "Hibernate3" ³ëµå´Â ¼±ÅÃÇϰųª ÇÏÀ§ÀÇ Æ¯Á¤ ³ëµå¸¦ ¼±ÅÃÇÏ°í "¿Ï·á" ¹öÆ°À» Ŭ¸¯ÇÑ´Ù.
+        9) ÇÁ·ÎÁ§Æ® ¸íÀ» hibernate3 µîÀÇ ¿øÇÏ´Â À̸§À¸·Î ¸í¸íÇÑ´Ù.
+        10) checkoutÀÌ ½ÇÇàµË´Ï´Ù.
+         
+        [TortoiseSVN ¼³Ä¡]
+	TortoiseSVN Ŭ¶óÀ̾ðÆ®¸¦ ¼³Ä¡Çϼ̴ٸé, ½Ã½ºÅÛÀ» Àç½ÃÀÛ ÇϽʽÿÀ.
+	1)·¹ÆÄÁöÅ丮¸¦ À§ÇÑ Æú´õ¸¦ Çϳª »ý¼º½Ãŵ´Ï´Ù.(D:\repo)
+	2)À©µµ¿ìŽ»ö±â¿¡¼­ D:\repo¸¦ ¸¶¿ì½º ¿À¸¥ÂÊ Å¬¸¯ÇÑ ÈÄ  TortoiseSVN ¸Þ´º¿¡¼­ 
+	  "Create repository Here..."¸¦ Ŭ¸¯Çϸé Æ˾÷ÀÌ ¶ß´Âµ¥, 
+	   ÆÄÀϽýºÅÛ/¹öŬ¸®DB Çü½Ä Áß Çϳª¸¦  ¼±ÅÃÇÏ°í OK ¹öÆ°À» ´©¸£¼¼¿ä.
+	3)hibernate¸¦ ³»·Á ¹Þ±â À§ÇÑ Æú´õ¸¦ Çϳª »ý¼º½ÃÅ°¼¼¿ä(D:\repo\Hibernate3)
+	4)D:\repo\hibernate Æú´õ¸¦ ¸¶¿ì½º ¿À¸¥ÂÊ Å¬¸¯ÇÑ ÈÄ, 
+	  TortoiseSVN Æ˾÷ ¸Þ´º¿¡¼­ CheckOutÀ» Ŭ¸¯ÇϽʽÿÀ.
+	5)URL repository¿¡ "http://anonhibernate.labs.jboss.com/trunk/Hibernate3" ¶Ç´Â 
+           "https://hibernate.labs.jboss.com/repos/hibernate/trunk" ¸¦ ÀÔ·ÂÇÏ°í, 
+	  OK ¹öÆ°À» Ŭ¸¯ÇϽʽÿÀ
+	6)¸ðµÎ ³»·Á¹ÞÀ¸½Å ´ÙÀ½¿¡ D:\repo\Hibernate3\doc\reference·Î À̵¿ÇÕ´Ï´Ù.
+	7)ÀÌÁ¦ ºôµåÇÏ½Ã¸é µË´Ï´Ù.
+	
+	*) ÇÑ±Û ¹ø¿ªº»¸¸ ÇÊ¿äÇÏ½Ã´Ù¸é ´ÙÀ½°ú °°ÀÌ Çϼŵµ µË´Ï´Ù.
+	/doc/reference/build.xml ÆÄÀÏÀ» 
+	¾Æ·¡ ¿¹¿Í °°ÀÌ ÇÑ±Û ¹ø¿ªº» ¿ÜÀÇ ºÎºÐµéÀ» ÁÖ¼®Ã³¸®ÇÕ´Ï´Ù. 
+	[°¡]. ºôµåÇϱâ
+	±×·± ´ÙÀ½  [·ÎÄà °æ·Î]/reference/ ¿¡¼­ ant all.doc·Î ºôµåÇÏ½Ã¸é µË´Ï´Ù.
+	ºôµå ½Ã°£Àº 2ºÐ °¡·® ¼Ò¿äµË´Ï´Ù.
+	[³ª]. ¹®¼­ º¸±â
+	µð·ºÅ丮 [·ÎÄà °æ·Î]/reference/build/ko/ µð·ºÅ丮¿¡ ºôµåµÈ ¹®¼­¸¦ º¸½Ã±â ¹Ù¶ø´Ï´Ù.
+	±×·³ ÇÏÀ̹ö³×ÀÌÆ®¿Í ÇÔ²² Áñ°Å¿î ½Ã°£À» º¸³»¼¼¿ä.
+	
+	[¿¹]
+	    <target name="all.doc"
+            depends="clean"
+            description="Compile documentation for all languages and all formats.">
+
+        <!-- TRANSLATOR: Duplicate this line for your language -->
+        <!--antcall target="lang.all"><param name="lang" value="en"/></antcall-->
+        <!--antcall target="lang.all"><param name="lang" value="zh-cn"/></antcall-->
+        <!--antcall target="lang.all"><param name="lang" value="es"/></antcall-->
+    	<antcall target="lang.all"><param name="lang" value="ko"/></antcall>
+
+    </target>
+    <target name="all.revdiff"
+            description="Generates a diff report for all translated versions.">
+
+        <!-- TRANSLATOR: Duplicate this line for your language -->
+        <!--antcall target="lang.revdiff"><param name="lang" value="zh-cn"/></antcall-->
+        <!--antcall target="lang.revdiff"><param name="lang" value="es"/></antcall-->
+    	<antcall target="lang.revdiff"><param name="lang" value="ko"/></antcall>
+
+    </target>

Added: trunk/Hibernate3/documentation/manual/ko-KR/pom.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-manual</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>hibernate-manual-${translation}</artifactId>
+    <packaging>pom</packaging>
+    <name>Hibernate Manual (${translation})</name>
+
+    <properties>
+        <translation>ko-KR</translation>
+    </properties>
+
+</project>

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/master.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/master.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/master.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,184 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
+                      "../support/docbook-dtd/docbookx.dtd"
+[
+<!ENTITY tutorial               SYSTEM "modules/tutorial.xml">
+<!ENTITY architecture           SYSTEM "modules/architecture.xml">
+<!ENTITY configuration          SYSTEM "modules/configuration.xml">
+<!ENTITY persistent-classes     SYSTEM "modules/persistent_classes.xml">
+<!ENTITY basic-mapping          SYSTEM "modules/basic_mapping.xml">
+<!ENTITY collection-mapping     SYSTEM "modules/collection_mapping.xml">
+<!ENTITY association-mapping    SYSTEM "modules/association_mapping.xml">
+<!ENTITY component-mapping      SYSTEM "modules/component_mapping.xml">
+<!ENTITY inheritance-mapping    SYSTEM "modules/inheritance_mapping.xml">
+<!ENTITY session-api            SYSTEM "modules/session_api.xml">
+<!ENTITY transactions           SYSTEM "modules/transactions.xml">
+<!ENTITY events                 SYSTEM "modules/events.xml">
+<!ENTITY batch                  SYSTEM "modules/batch.xml">
+<!ENTITY query-hql              SYSTEM "modules/query_hql.xml">
+<!ENTITY query-criteria         SYSTEM "modules/query_criteria.xml">
+<!ENTITY query-sql              SYSTEM "modules/query_sql.xml">
+<!ENTITY filters                SYSTEM "modules/filters.xml">
+<!ENTITY xml                    SYSTEM "modules/xml.xml">
+<!ENTITY performance            SYSTEM "modules/performance.xml">
+<!ENTITY toolset-guide          SYSTEM "modules/toolset_guide.xml">
+<!ENTITY example-parentchild    SYSTEM "modules/example_parentchild.xml">
+<!ENTITY example-weblog         SYSTEM "modules/example_weblog.xml">
+<!ENTITY example-mappings       SYSTEM "modules/example_mappings.xml">
+<!ENTITY best-practices         SYSTEM "modules/best_practices.xml">
+]>
+
+<book lang="ko">
+
+    <bookinfo lang="ko">
+        <title>HIBERNATE - 개성있는 자바를 위한 관계 영속</title>
+        <subtitle>하이버네이트 참조 문서</subtitle>
+        <releaseinfo lang="ko">3.2 cr3</releaseinfo>
+    </bookinfo>
+
+    <toc lang="ko" />
+
+    <preface id="preface" revision="2">
+        <title>머리말</title>
+
+        <para>
+            객체 지향 소프트웨어와 관계형 데이터베이스로 작업하는 것은 오늘날의 엔터프라이즈 환경들에서 성가시고 시간이
+            소비될 수 있다. Hibernate는 자바 환경들을 위한 객체/관계형 매핑 도구이다.
+            object/relational mapping(ORM) 용어는 객체 모형으로부터 SQL-기반의 스키마를 가진
+            관계형 데이터 모형으로의 데이터 표상을 매핑하는 기술을 언급한다.
+        </para>
+
+        <para>
+            Hibernate는 자바 클래스들로부터 데이터베이스로의 매핑(그리고 자바 데이터 타입들로부터 SQL 데이터
+            타입들로의 매핑)을 처리할 뿐만 아니라, 또한 데이터 질의와 검색 편의들을 제공하며, SQL과 JDBC로
+            수작업 데이터 핸들링에 소요되는 개발 시간을 현저하게 단축시켜줄 수 있다.
+        </para>
+
+        <para>
+            Hibernate의 목적은 공통된 데이터 영속화 관련 프로그래밍 작업들의 95%를 덜어주는 것이다.
+            Hibernate는 데이터베이스에서 비지니스 로직을 구현하는데 내장 프로시저들을 전용으로 사용하는 데이터
+            중심적 어플리케이션에 대한 최상의 솔루션이 아닐 수도 있지만, 그것은 자바 기반 미들-티어에서 객체 지향
+            도메인 모형들과 비지니스 로직에 가장 유용하다. 하지만 Hibernate는 벤더 지정적인 SQL 코드를
+            제거하거나 캡슐화 시키는 당신을 확실히 도와줄 수 있고 테이블 형식의 표현으로부터 객체들의 그래프로 결과
+            셋을 변환하는 공통된 태스크를 도와줄 것이다.
+        </para>
+
+        <para>
+            만일 당신이 Hibernate와 Object/Relational 매핑 또는 심지어 자바에 초심자라면, 다음
+            단계들을 따르기 바란다:
+        </para>
+
+        <orderedlist>
+            <listitem>
+                <para>
+                                        더 많은 단계적인 사용 설명서들을 가진 더 긴 튜토리얼은
+                    <xref linkend="tutorial"/>
+                                        을 읽어라. 튜토리얼을 위한 소스 코드는 <literal>doc/reference/tutorial/</literal> 
+                                        디렉토리에 포함되어 있다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Hibernate가 사용될 수 있는 환경을 이해려면
+                    <xref linkend="architecture" />
+                    를 읽어라.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Hibernate 배포본 내의
+                    <literal>eg/</literal>
+                    디렉토리를 살펴 보라. 이 디렉토리는 간단한 스탠드얼론 어플리케이션을 포함하고 있다. 당신의
+                    JDBC 드라이버를
+                    <literal>lib/</literal>
+                    디렉토리에 복사하고 당신의 데이터베이스에 맞는 정확한 값을 지정하여
+                    <literal>etc/hibernate.properties</literal>
+                    를 편집하라. 배보본 디렉토리에서 명령 라인 프롬프트에서 (Ant를 사용하여)
+                    <literal>ant eg</literal>
+                    를 타이핑 하거나 , Windows 하에서
+                    <literal>build eg</literal>
+                    를 타이프 하라.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    당신의 주된 정보의 소스로서 이 참조 문서를 사용하라. 만일 어플리케이션 설계에 대해 더 많은
+                    도움을 필요로 하거나 당신이 단계적인 튜토리얼을 선호한다면
+                    <emphasis>Hibernate in Action</emphasis>
+                    (http://www.manning.com/bauer)을 읽는 것을 고려하라.또한
+                    http://caveatemptor.hibernate.org에 방문하여 Hibernate in
+                    Action용 예제 어플리케이션을 다운로드 하라.
+                </para>
+            </listitem>
+            <listitem>
+				<para>
+					FAQ들은 Hibernate 웹 사이트 상에 답변되어 있다.
+                </para>
+            </listitem>
+            <listitem>
+				<para>
+					제 3의 데모들, 예제들, 그리고 튜토리얼들은 Hibernate 웹 사이트 상에 링크되어
+                    있다.
+				</para>
+			</listitem>
+            <listitem>
+                <para>
+                    Hibernate 웹사이트 상의 공동체 영역은 설계 패턴과 다양한 통합 솔루션들(Tomcat,
+                    JBoss AS, Struts, EJB 등.)에 관한 좋은 리소스이다.
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <para>
+            질문이 있다면, Hibernate 상에 링크되어 있는 사용자 포럼을 사용하라. 우리는 또한 버그 보고와 특징
+            요청들을 위한 JIRA 쟁점 추적 시스템을 제공한다. 당신이 Hibernate의 개발에 관심이 있다면,
+            개발자 메일링 리스트에 참여하라. 만일 당신이 이 문서를 당신의 언어로 번역하는 것에 관심이 있다면, 개발자
+            메일링 리스트에 접촉하라.
+        </para>
+
+        <para>
+            Hibernate를 위한 상용 개발 지원, 제품 지원, 그리고 교육은 JBoss Inc를 통해 이용 가능하다
+            (http://www.hibernate.org/SupportTraining/를 보라). Hibernate는
+            JBoss Professional Open Source product 프로젝트이고 제품들에 대한 JBoss
+            Enterprise Middleware System (JEMS) suite의 중대한 컴포넌트이다.
+        </para>
+
+    </preface>
+
+    &tutorial;
+
+    &architecture;
+
+    &configuration;
+
+    &persistent-classes;
+
+    &basic-mapping;
+    &collection-mapping;
+    &association-mapping;
+    &component-mapping;
+    &inheritance-mapping;
+
+    &session-api;
+    &transactions;
+    &events;
+    &batch;
+
+    &query-hql;
+    &query-criteria;
+    &query-sql;
+    &filters;
+    &xml;
+
+    &performance;
+
+    &toolset-guide;
+
+    &example-parentchild;
+    &example-weblog;
+    &example-mappings;
+
+    &best-practices;
+
+</book>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/architecture.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/architecture.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/architecture.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,308 @@
+<chapter id="architecture">
+
+    <title>아키텍처</title>
+
+    <sect1 id="architecture-overview" revision="1">
+        <title>개요</title>
+        
+        <para>
+            Hibernate 아키텍처에 대한 (매우) 높은 수준의 개요::
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/overview.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/overview.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+                        이 다이어그램은 어플리케이션에 영속화 서비스들(과 영속 객체들)을 제공하기 위해 데이터베이스와 
+                        컨피그레이션을 사용하는 Hibernate를 보여준다.
+        </para>
+
+        <para>
+                        우리는 런타임 아키텍처에 대한 보다 상세한 뷰를 보여주고 싶다. 불행하게도, Hibernate는 유연하며 
+                        몇 가지 접근법들을 제공한다. 우리는 두 가지 극단을 보여줄 것이다. "경량급" 아키텍처는 그것 자신의 
+            JDBC 커넥션들을 제공하고 그것 자신의 트랜잭션들을 관리하는 어플리케이션을 갖는다. 이 접근법은 
+            Hibernate의 API의 최소 부분집합을 사용한다:
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/lite.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/lite.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            "전체 정수" 아키텍처는 기본 JDBC/JTA로부터 어플리케이션을 추상화 시키고 Hibernate로 하여금 
+                        상세한 것을 처리하게 한다.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/full_cream.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/full_cream.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+                        다음은 다이어그램들 내에 있는 객체들에 대한 몇가지 정의들이다:
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
+                    <listitem>
+                        <para>
+                                                        단일 데이터베이스에 대한 컴파일된 매핑들의 threadsafe (불변의) 캐시. Session과 ConnectionProvider의 
+                                                        클라이언트를 위한 팩토리. 프로세스 레벨 또는 클러스터 레벨에서 트랜잭션들 사이에 재사용 가능한 데이터의 선택적인
+                            (second-level) 캐시를 보관할 수도 있다.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Session (<literal>org.hibernate.Session</literal>)</term>
+                    <listitem>
+                        <para>
+                                                        어플리케이션과 영속 저장소 사이의 대화를 표현하는 단일 쓰레드이고, 수명이 짧은 객체.  JDBC 커넥션을 포장한다. 
+                            <literal>Transaction</literal> 용 팩토리. 객체 그래프를 네비게이트 하거나 식별자로 객체들을 룩업할 때 
+                                                        사용되는 영속 객체들에 대한 필수적인(첫 번째 레벨의) 캐시를 보관한다.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>영속 객체들과 콜렉션들</term>
+                    <listitem>
+                        <para>
+                            persistent 상태와 비지니스 기능을 포함하는 수명이 짧고, 단일 쓰레드인 객체들. 이것들은 통상의 JavaBeans/POJO들일 
+                                                        수 있고, 오직 그것들에 대한 오직 특별한 것은 그것들이 현재 (정확하게 한 개의) <literal>Session</literal>과  연관되어 
+                                                        있다는 점이다. <literal>Session</literal>이 닫히자마자, 그것들은 분리될(detached 상태가 될) 것이고 어플리케이션 
+                                                        레이어에서 사용하는 것이 자유로와진다(예를 들면. 직접적으로 프리젠테이션 계층으로 
+                                                        데이터 전송 객체들로서 그리고 직접적으로 프리젠테이션 계층으로부터 데이터 전송 객체들로서).
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>전이(Transient, 필자 주-과도) 객체들과 콜렉션들</term>
+                    <listitem>
+                        <para>
+                            <literal>Session</literal>과 현재 연관되어 있지 않은 영속 클래스들의 인스턴스들. 그것들은 어플리케이션에 의해 초기화
+                                                        되었고 (아직) 영속화 되지 않았거나 그것들은 닫혀진<literal>Session</literal>에 의해 초기화 되었을 수도 있다.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
+                    <listitem>
+                        <para>
+                            (옵션) 작업의 원자 단위를 지정하기 위해 어플리케이션에 의해 사용되는 단일 쓰레드이고, 수명이 짧은 객체. 기본 JDBC, JTA 
+                                                        또는 CORBA 트랜잭션으로부터 어플리케이션을 추상화 시킨다. 몇몇 경우들에서 하나의 <literal>Session</literal>은 
+                                                        여러 개의 <literal>Transaction</literal>들에 걸칠 수 있다. 하지만 기본 API 또는 <literal>Transaction</literal>을 
+                                                        사용하는 트랜잭션 경계 설정은 결코 옵션이 아니다!
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
+                    <listitem>
+                        <para>
+                            (옵션) JDBC 커넥션들에 대한 팩토리(그리고 그것들의 pool). 기본 <literal>Datasource</literal> 또는 
+                            <literal>DriverManager</literal>로부터 어플리케이션을 추상화 시킨다. 어플리케이션에 노출되지는 않지만 
+                                                        개발자에 의해 확장/구현 된다.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
+                    <listitem>
+                        <para>
+                            (옵션) <literal>Transaction</literal> 인스턴스들에 대한 팩토리. 어플리케이션에 노출되지는 않지만 개발자에 의해 
+                                                        확장/구현 된다. 
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><emphasis>Extension Interfaces</emphasis></term>
+                    <listitem>
+                        <para>
+                            Hibernate는 당신의 영속 계층의 특성을 맞춤화 시키기 위해 당신이 구현할 수 있는 선택적인 확장 인터페이스들을 제공한다. 
+                                                        상세한 것은 API 문서를 보라.
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+        </para>
+
+        <para>
+                        주어진 "경량급" 아키텍처의 경우, 어플리케이션은 JTA 또는 JDBC와 직접 대화하기 위해서 <literal>Transaction</literal>/<literal>TransactionFactory</literal> 
+                        그리고/또는 <literal>ConnectionProvider</literal> API들을 무시한다.
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-states" revision="1">
+        <title>인스턴스 상태들</title>
+        <para>
+                        영속 클래스들의 인스턴스는 세개의 상태들 중 하나 일 수 있다. 그것들(상태들)은  영속  컨텍스트(<emphasis>persistence context</emphasis>)에 
+                        대해 정의된다. Hibernate <literal>Session</literal> 객체는 영속 컨텍스트이다:
+        </para>
+        
+       <variablelist spacing="compact">
+            <varlistentry>
+                <term>transient</term>
+                <listitem>
+                    <para>
+                                                인스턴스는 임의의 컨텍스트와 연관되어 있지 않고, 결코 연관된 적이 없었다. 그것은 영속 식별자(프라이머리 키 값)을 갖지 않는다.
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>persistent</term>
+                <listitem>
+                    <para>
+                                                인스턴스는 현재 영속 컨텍스트와 연관되어 있다. 그것은 영속 식별자(프라이머리 키 값) 그리고 아마 데이터베이스 내에 있는 대응하는 
+                                                행을 갖는다. 특별한 영속 컨텍스트의 경우, Hibernate는 영속 identity가 Java identity(객체의 메모리 내 위치)와 같다는 점을 
+                        <emphasis>보증한다</emphasis>.
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>detached</term>
+                <listitem>
+                    <para>
+                                                인스턴스는 영속 컨텍스트와 한번 연관되었지만, 그 컨텍스트가 닫혔거나, 그 인스턴스가 또 다른 프로세스로 직렬화 되었다. 그것은 영속 
+                        identity 그리고, 아마 데이터베이스 내에 대응하는 행을 갖는다. detached 인스턴스들의 경우, Hibernate는 영속 identity과 
+                        Java identity 사이의 관계를 보증하지 않는다.
+                    </para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </sect1>    
+
+    <sect1 id="architecture-jmx" revision="1">
+        <title>JMX 통합</title>
+
+        <para>
+            JMX는 자바 컴포넌트 관리를 위한 J2EE 표준이다. Hibernate는 JMX 표준 서비스를 통해 관리될 수도 있다. 우리는 배포본 내에 MBean 구현, 
+            <literal>org.hibernate.jmx.HibernateService</literal>를 제공한다.
+        </para>
+
+        <para>
+            JBoss 어플리케이션 서버 상에 Hibernae를 JMX 서비스로서 배치하는 방법에 대한 예제는 JBoss 사용자 가이드를 보길 바란다. JBoss 
+                        어플리케이션 서버 상에서, 만일 당신이 JMX를 사용하여 배치할 경우 당신은 또한 다음 이점들을 얻는다:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>Session 관리:</emphasis> Hibernate <literal>Session</literal>의 생명주기가 JTA 트랜잭션의 
+                                        영역 내에 자동적으로 바인드 될 수 있다. 이것은 당신이 더이상 <literal>Session</literal>을 수작업으로 열고 닫지 않아도 
+                                        됨을 의미하고, 이것은 JBoss EJB 인터셉터의 업무가 된다.  당신은 또한 더 이상 당신의 코드 어느 곳에서든 트랜잭션 경계설정에 
+                                        대해 걱정하지 않아도 된다(당신이 물론 이식성 있는 영속 계층을 작성하고자 원하지 않는한, 이를 위해 옵션 Hibernate <literal>Transaction</literal> 
+                    API를 사용하라). 당신은 <literal>Session</literal>에 접근하기 위해 <literal>HibernateContext</literal>를 호출한다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>HAR 배치:</emphasis> 대개 당신은 JBoss 서비스 배치 디스크립터를 사용하여 Hibernate JMX 서비스를 
+                    (EAR 과/또는 SAR 파일로) 배치하고, 그것은 Hibernate <literal>SessionFactory</literal>의 통상적인 구성 
+                                       옵션들 모두를 지원한다. 하지만 당신은 여전히 모든 당신의 매핑 파일들을 배치 디스크립터 속에 명명해야 한다. 만일 당신이 
+                                       옵션 HAR 배치를 사용하고자 결정하는 경우, JBoss는 당신의 HAR 파일 내에 있는 모든 매핑 파일들을 자동적으로 검출해낼 것이다.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+                        이들 옵션들에 대한 추가 정보는 JBoss 어플리케이션 서버 사용자 가이드를 참조하라.
+        </para>
+
+        <para>
+            JMX 서비스로서 이용 가능한 또다른 특징은 런타임 Hibernate 통계이다. 
+            <xref linkend="configuration-optional-statistics"/>를 보라.
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-jca" revision="1">
+        <title>JCA 지원</title>
+        <para>
+            Hibernate는 JCA 커넥터로서 구성될 수도 있다. 상세한 것은 웹 사이트를 보길 바란다. Hibernate JCA 지원은 여전히 실험적으로 
+                        검토 중에 있음을 노트하길 바란다.
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-current-session" revision="2">
+        <title>컨텍스트 상의 세션들</title>
+        <para>
+	        Hibernate를 사용하는 대부분의 어플리케이션들은 어떤 양식의 "컨텍스트상의(contextual)" 세션들을 필요로 한다. 여기서 
+	                주어진 세션은 주어진 컨텍스트의 영역에 걸쳐 활동을 한다. 하지만 어플리케이션들을 가로질러 컨텍스트를 구성하는 것에 대한 정의는 
+	                일반적으로 다르다; 그리고 다른 컨텍스트들은 현재라고 하는 개념에 대해 다른 영역들을 정의한다. 버전 3.0 전의 Hibernate를 
+	                사용하는 어플리케이션들은 자가생산된 <literal>ThreadLocal</literal>-기반의 컨텍스상의 세션들, 
+	        <literal>HibernateUtil</literal>과 같은 helper 클래스들을 활용했거나  
+	                프락시/인터셉션 기반의 컨텍스트상의 세션들을 제공해주었던 (Spring 또는 Pico와 같은 )제 3의 프레임웍들을 활용하는 경향이 있었다.
+        </para>
+	    <para>
+		        버전 3.0.1에서부터 시작하여, Hibernate는 <literal>SessionFactory.getCurrentSession()</literal> 메소드를 
+		        추가했다. 초기에 이것은 <literal>JTA</literal> 트랜잭션들을 사용하는 것을 전제했다. 여기서 <literal>JTA</literal>
+		        트랜잭션은 현재 세션의 영역과 컨텍스트를 정의했다. Hibernate 팀은 성숙된 다수의 스탠드얼론 <literal>JTA TransactionManager</literal>
+		        구현들이 발표되면, (전부는 아니겠지만) 대부분의 어플리케이션들이 그것들이 <literal>J2EE</literal> 컨테이너 내로 배치되든 
+		        그렇지 않든 간에 <literal>JTA</literal> 트랜잭션 관리를 사용하게 될 것이라고 주장한다. 그것에 기초하여, <literal>JTA</literal>에 기반한 
+		        컨텍스트상의 세션들은 언젠가 당신이 사용을 필요로 하게 될 전부다.
+	    </para>
+	    <para>
+		        하지만 버전 3.1 이후로 <literal>SessionFactory.getCurrentSession()</literal> 이면의 처리과정은
+		        이제 플러그 가능하다. 그것을 끝내기 위해, 하나의 새로운 확장 인터페이스
+		    (<literal>org.hibernate.context.CurrentSessionContext</literal>)와 
+		        하나의 새로운 구성 파라미터(<literal>hibernate.current_session_context_class</literal>)가 현재 세션들을 
+		        정의하는 영역과 컨텍스트의 플러그 가능성을 허용하기 위해 추가되었다.
+	    </para>
+	    <para>
+		        그것의 계약에 대한 상세한 논의는 <literal>org.hibernate.context.CurrentSessionContext</literal> 인터페이스에 
+		        관한 javadocs를 보라. 그것은 하나의 메소드, <literal>currentSession()</literal>를 정의하며, 그 구현은 
+		        현재의 컨텍스트 상의 세션을 추적할 책임이 있다. 비공식적으로, Hibernate는 이 인터페이스에 대한 세 개의 구현들을 부수적으로 
+		        포함하고 있다.
+	    </para>
+	    
+		<itemizedlist>
+			<listitem>
+				<para>
+					<literal>org.hibernate.context.JTASessionContext</literal> - 현재의 세션들은 하나의 
+					<literal>JTA</literal>에 의해 추적되고 영역화 된다. 여기서 처리과정은 이전의 JTA-전용 접근과 정확하게 
+					동일하다. 상세한 것은 javadocs를 보라.
+				</para>
+			</listitem>
+			<listitem>
+				<para>
+					<literal>org.hibernate.context.ThreadLocalSessionContext</literal> - 현재의 세션들은 
+					실행 쓰레드에 의해 추적된다. 상세한 것은 다시 javadocs를 보라.
+				</para>
+			</listitem>
+		</itemizedlist>
+	    <para>
+                        처음의 두 구현들은 <emphasis>session-per-request</emphasis>로 알려지고 사용되고 있는 
+            "하나의 세션 - 하나의 데이터베이스 트랜잭션" 프로그래밍 모형을 제공한다. 하나의 Hibernate 세션의 시작과 끝은 
+                        데이터베이스 트랜잭션의 존속 기간에 의해 정의된다. 만일 (예를 들면 순수 J2SE에서 또는 JTA/UserTransaction/BMT의 경우에)
+                        당신이 프로그램 상의 트랜잭션 경계구분을 사용할 경우, 당신은 당신의 코드로부터 기본 트랜잭션 시스템을 은폐시키는데 
+            Hibernate <literal>Transaction</literal> API를 사용하는 것이 권장된다. 만일 당신이 CMT를 지원하는 
+                        하나의 EJB 컨테이너에서 실행할 경우, 트랜잭션 경계들이 선언적으로 정의되고 당신은 당신의 코드 내에 어떤 트랜잭션도 
+                        세션 경계구분 오퍼레이션들을 필요로 하지 않는다. 추가 정보와 코드 예제들은 <xref linkend="transactions"/>를 참조하라.
+	    </para>
+	    
+	    <para>
+		    <literal>hibernate.current_session_context_class</literal> 구성 파라미터는 
+		    <literal>org.hibernate.context.CurrentSessionContext</literal> 구현이 사용될 것임을 정의한다. 역호환을 위해. 
+		        만일 이 구성 파라미터가 설정되지 않았지만 하나의 <literal>org.hibernate.transaction.TransactionManagerLookup</literal>이 
+		        구성되어 있을 경우, Hibernate는 <literal>org.hibernate.context.JTASessionContext</literal>를 사용할 것임을 
+		        노트하라. 일반적으로, 이 파라미터의 값은 단지 사용할 구현 클래스를 명명할 것이다; 하지만 두 가지 비공식적인 구현들로서 두 개의 
+		        대응하는 짧은 이름들 "jta"와 "thread"이 존재한다.
+		</para>
+		
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/association_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/association_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/association_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,603 @@
+<chapter id="associations">
+
+    <title>연관 매핑들</title>
+
+    <sect1 id="assoc-intro" revision="1">
+        <title>개요</title>
+        
+        <para>
+                        연관 매핑들은 올바른 것을 얻기가 종종 가장 어려운 것이다. 이 절에서 우리는 단방향 매핑들에서 시작하고, 그런 다음 양방향 경우들을 
+                        검토함으로써, 하나씩 표준적인 경우들을 상세히 논의할 것이다. 우리는 모든 예제들에서 <literal>Person</literal>과 
+            <literal>Address</literal>를 사용할 것이다.
+        </para>
+        
+        <para>
+        	우리는 연관들을 중재하는 join 테이블로 매핑시킬 것인지 여부에 따라, 그리고 multiplicity(다중성)에 따라 연관들을 분류할 것이다.
+        </para>
+        
+        <para>
+        	null 허용 가능한 foreign 키들은 전통적인 데이터 모델링에서 좋은 실례로 간주되지 않아서, 모든 우리의 예제들은 not null 
+            foreign 키들을 사용한다. 이것은 Hibernate에서 필수가 아니고, 당신이 null 허용 가능 컨스트레인트들을 드롭시킬 경우 매핑들은  
+                        모두 동작할 것이다.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="assoc-unidirectional" revision="1">
+        <title>단방향 연관들</title>
+        
+        <sect2 id="assoc-unidirectional-m21">
+        <title>many to one</title>
+        
+        <para>
+            <emphasis>단방향 many-to-one 연관</emphasis>은 가장 공통적인 종류의 단방향 연관이다.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-121">
+        <title>one to one</title>
+        
+        <para>
+            <emphasis>foreign 키에 대한 단방향 one-to-one 연관은 대개 아주 동일하다.</emphasis> 유일한 차이점은 
+                        컬럼 유일(unique) 컨스트레인트이다.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId" 
+        unique="true"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        <para>
+            <emphasis>하나의 프라이머리 키에 대한 단방향 one-to-one 연관</emphasis>은 대개 특별한 id 생성기를 사용한다. 
+            (이 예제에서 연관의 방향이 역전되었음을 주목하라.)
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+</class>
+
+<class name="Address">
+    <id name="id" column="personId">
+        <generator class="foreign">
+            <param name="property">person</param>
+        </generator>
+    </id>
+    <one-to-one name="person" constrained="true"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+        <sect2 id="assoc-unidirectional-12m">
+        <title>one to many</title>
+        
+        <para>
+            <emphasis>하나의 foreign 키에 대한 단방향 one-to-many 연관</emphasis>은 매우 색다른 경우이고, 실제로 권장되지 않는다.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses">
+        <key column="personId" 
+            not-null="true"/>
+        <one-to-many class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( addressId bigint not null primary key, personId bigint not null )
+        ]]></programlisting>
+        
+        <para>
+                        우리는 이런 종류의 연관에 대해 하나의 join 테이블을 사용하는 것이 더 좋다고 생각한다.
+        </para>
+        
+        </sect2>
+    
+    </sect1>
+
+    <sect1 id="assoc-unidirectional-join" revision="1">
+        <title>join 테이블들에 대한 단방향 연관들</title>
+        
+        <sect2 id="assoc-unidirectional-join-12m">
+        <title>one to many</title>
+        
+        <para>
+            <emphasis>하나의 join 테이블에 대한 단방향 one-to-many 연관</emphasis>이 보다 더 선호된다. <literal>unique="true"</literal>를 
+                        지정함으로써 우리는 many-to-many에서 one-to-many로 아중성(multiplicity)를 변경시켰음을 주목하라.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            unique="true"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-m21">
+        <title>many to one</title>
+        
+        <para>
+            <emphasis>하나의 join 테이블에 대한 단방향 many-to-one 연관</emphasis>은 그 연관이 선택적일 때 매우 공통적이다.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-121">
+        <title>one to one</title>
+        
+        <para>
+            <emphasis>하나의 join 테이블에 대한 단방향 one-to-one 연관</emphasis>은 극히 통상적이지 않지만 가능하다.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-m2m">
+        <title>many to many</title>
+        
+        <para>
+                        마지막으로, 우리는 <emphasis>단방향 many-to-many 연관</emphasis>을  갖는다. 
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="assoc-bidirectional" revision="1">
+        <title>양방향 연관들</title>
+        
+        <sect2 id="assoc-bidirectional-m21" revision="2">
+        <title>one to many / many to one</title>
+        
+        <para>
+            <emphasis>양방향 many-to-one 연관</emphasis>은 가장 공통된 종류의 연관이다.(이것은 표준 부모/자식 관계이다. )
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <set name="people" inverse="true">
+        <key column="addressId"/>
+        <one-to-many class="Person"/>
+    </set>
+</class>]]></programlisting>
+
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+
+        <para>
+                        만일 당신이 <literal>List</literal>(또는 다른 인덱싱 된 콜렉션)을 사용할 경우 당신은 foreign key의 
+            <literal>key</literal> 컬럼을 <literal>not null</literal>로 설정하고, Hibernate로 하여금 
+                        각각의 요소의 인덱스를 유지관리하기 위해 (<literal>update="false"</literal>와 
+            <literal>insert="false"</literal>를 설정함으로써 다른 측을 가상적으로 inverse로 만들어) 
+                        그 콜렉션들 측으로부터  연관을 관리하도록 할 필요가 있다:
+        </para>
+
+        <programlisting><![CDATA[<class name="Person">
+   <id name="id"/>
+   ...
+   <many-to-one name="address"
+      column="addressId"
+      not-null="true"
+      insert="false"
+      update="false"/>
+</class>
+
+<class name="Address">
+   <id name="id"/>
+   ...
+   <list name="people">
+      <key column="addressId" not-null="true"/>
+      <list-index column="peopleIdx"/>
+      <one-to-many class="Person"/>
+   </list>
+</class>]]></programlisting>
+
+            <para>
+                                만일 기본 외래 키 컬럼이 <literal>NOT NULL</literal>일 경우 콜렉션 매핑의 <literal>&lt;key&gt;</literal>
+                                요소 상에 <literal>not-null="true"</literal>를 정의하는 것이 중요하다. 내포된 
+                <literal>&lt;column&gt;</literal> 요소 상에 <literal>not-null="true"</literal>를 
+                                선언하지 말고, <literal>&lt;key&gt;</literal> 요소 상에 선언하라.
+            </para>
+
+        </sect2>
+        
+        <sect2 id="assoc-bidirectional-121">
+        <title>one to one</title>
+        
+        <para>
+            <emphasis>foreign에 대한 양방향 one-to-one 연관</emphasis>은 꽤 공통적이다.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId" 
+        unique="true"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+   <one-to-one name="person" 
+        property-ref="address"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        <para>
+            <emphasis>하나의 프라이머리 키에 대한 양방향 one-to-one 연관</emphasis>은 특별한 id 생성기를 사용한다.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <one-to-one name="address"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="personId">
+        <generator class="foreign">
+            <param name="property">person</param>
+        </generator>
+    </id>
+    <one-to-one name="person" 
+        constrained="true"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="assoc-bidirectional-join" revision="1">
+        <title>join 테이블들에 대한 양방향 연관들</title>
+        
+        <sect2 id="assoc-bidirectional-join-12m">
+        <title>one to many / many to one</title>
+        
+        <para>
+            <emphasis>하나의 join 테이블에 대한 양방향 one-to-many 연관</emphasis>. <literal>inverse="true"</literal>는 
+                        연관의 어느 쪽 끝이든 콜렉션 측으로 또는 join 측으로 갈 수 있다.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" 
+        table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            unique="true"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        inverse="true" 
+        optional="true">
+        <key column="addressId"/>
+        <many-to-one name="person"
+            column="personId"
+            not-null="true"/>
+    </join>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+         <sect2 id="assoc-bidirectional-join-121">
+        <title>one to one</title>
+        
+        <para>
+            <emphasis>하나의 join 테이블에 대한 양방향 one-to-one 연관</emphasis>은 극히 통상적이지 않지만, 가능하다.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true"
+        inverse="true">
+        <key column="addressId" 
+            unique="true"/>
+        <many-to-one name="person"
+            column="personId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+
+        </sect2>
+        
+        <sect2 id="assoc-bidirectional-join-m2m" revision="1">
+        <title>many to many</title>
+        
+        <para>
+                        마지막으로, 우리는 하나의 <emphasis>양방향 many-to-many 연관</emphasis>을 갖는다.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <set name="people" inverse="true" table="PersonAddress">
+        <key column="addressId"/>
+        <many-to-many column="personId"
+            class="Person"/>
+    </set>
+</class>]]></programlisting>
+
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+    </sect1>
+    
+    <sect1 id="assoc-complex">
+        <title>보다 복잡한  연관 매핑들</title>
+        
+        <para>
+                        보다 복잡한 연관 조인들은 <emphasis>극기</emphasis> 드물다. 
+            Hibernate는 매핑 문서들 내에 삽입된 SQL 조각들을 사용하여 보다 복잡한 상황을 처리하는 것을 
+                        가능하도록 해준다. 예를 들어, 만일  계좌 내역 정보 데이터를 가진 하나이 테이블이   
+            <literal>accountNumber</literal>, <literal>effectiveEndDate</literal> 
+                        그리고 <literal>effectiveStartDate</literal> 컬럼들을 정의할 경우, 다음과 같이 매핑된다:
+        </para>
+        
+        <programlisting><![CDATA[<properties name="currentAccountKey">
+    <property name="accountNumber" type="string" not-null="true"/>
+    <property name="currentAccount" type="boolean">
+        <formula>case when effectiveEndDate is null then 1 else 0 end</formula>
+    </property>
+</properties>
+<property name="effectiveEndDate" type="date"/>
+<property name="effectiveStateDate" type="date" not-null="true"/>]]></programlisting>
+
+        <para>
+                        그때 우리는 다음을 사용하여 하나의 연관을 <emphasis>현재</emphasis> 인스턴스
+            (null <literal>effectiveEndDate</literal>을 가진 인스턴스)로 매핑시킬 수 있다:
+        </para>
+        
+        <programlisting><![CDATA[<many-to-one name="currentAccountInfo" 
+        property-ref="currentAccountKey"
+        class="AccountInfo">
+    <column name="accountNumber"/>
+    <formula>'1'</formula>
+</many-to-one>]]></programlisting>
+
+        <para>
+                        보다 복잡한 예제에서, <literal>Employee</literal>와 <literal>Organization</literal> 사이의 
+                        연관이 전체 고용 내역 데이터를 가진 <literal>Employment</literal> 테이블 내에 유지된다고 가정하자. 
+                        그때 종업원의 <emphasis>가장 최근의</emphasis> 고용주에 대한 하나의 연관(가장 최근의 
+            <literal>startDate</literal>를 갖고 있는 것)이 다음 방법으로 매핑될 수 있다:
+        </para>
+        
+        <programlisting><![CDATA[<join>
+    <key column="employeeId"/>
+    <subselect>
+        select employeeId, orgId 
+        from Employments 
+        group by orgId 
+        having startDate = max(startDate)
+    </subselect>
+    <many-to-one name="mostRecentEmployer" 
+            class="Organization" 
+            column="orgId"/>
+</join>]]></programlisting>
+
+        <para>
+                        당신은 이 기능으로 아주 생산성을 얻을 수 있지만, 그것은 대개 HQL 또는 criteria 질의를 사용하여 이들 종류의 경우들을 
+                        처리하는 것이 보다 실용적이다.
+        </para>
+
+    </sect1>
+
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/basic_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/basic_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/basic_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,3202 @@
+<chapter id="mapping">
+    <title>기본 O/R 매핑</title>
+
+    <sect1 id="mapping-declaration" revision="1">
+        <title>매핑 선언</title>
+
+        <para>
+                        객체/관계형 매핑들은 대개 XML 문서 내에 정의된다. 매핑 문서는 가독성이 있고 수작업 편집이 가능하도록 
+                        설계되어 있다. 매핑 언어는 매핑들이 테이블 선언들이 아닌, 영속 클래스 선언들로 생성된다는 의미에서 
+                        자바 중심적이다. 
+        </para>
+        
+        <para>
+                        심지어 많은 Hibernate 사용자들이 수작업으로 XML을 작성하고자 선택할지라도, XDoclet, Middlegen, 
+                        그리고 AndroMDA를 포함하는, 매핑 문서를 생성시키는 많은 도구들이 존재한다는 점을 노트하라. 
+        </para>
+
+        <para>
+                        예제 매핑으로 시작하자:
+        </para>
+
+        <programlisting id="mapping-declaration-ex1" revision="1"><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+        <class name="Cat" 
+            table="cats"
+            discriminator-value="C">
+                
+                <id name="id">
+                        <generator class="native"/>
+                </id>
+
+                <discriminator column="subclass" 
+                     type="character"/>
+
+                <property name="weight"/>
+
+                <property name="birthdate"
+                    type="date" 
+                    not-null="true" 
+                    update="false"/>
+
+                <property name="color"
+                    type="eg.types.ColorUserType"
+                    not-null="true"
+                    update="false"/>
+
+                <property name="sex"
+                    not-null="true" 
+                    update="false"/>
+
+                <property name="litterId"
+                    column="litterId"
+                    update="false"/>
+
+                <many-to-one name="mother"
+                    column="mother_id"
+                    update="false"/>
+
+                <set name="kittens"
+                    inverse="true"
+                    order-by="litter_id">
+                        <key column="mother_id"/>
+                        <one-to-many class="Cat"/>
+                </set>
+
+                <subclass name="DomesticCat"
+                    discriminator-value="D">
+
+                        <property name="name" 
+                            type="string"/>
+
+                </subclass>
+
+        </class>
+
+        <class name="Dog">
+                <!-- mapping for Dog could go here -->
+        </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+                          우리는 이제 매핑 문서의 내용을 논의할 것이다. 우리는 Hibernate에 의해 실행 시에 사용되는 문서 요소들과 
+                          속성들 만을 설명할 것이다. 매핑 문서는 또한 스키마 내보내기 도구에 의해 내보내진 데이터베이스 스키마에 
+                          영향을 주는 어떤 특별한 옵션 속성들과 요소들을 포함한다. (예를 들어 <literal>not-null</literal> 속성.)
+        </para>
+
+
+
+        <sect2 id="mapping-declaration-doctype" revision="3">
+            <title>Doctype</title>
+
+            <para>
+                모든 XML 매핑들은 doctype이 보이게 선언해야 한다. 실제 DTD는 위의 URL에서, 
+        <literal>hibernate-x.x.x/src/org/hibernate</literal> 디렉토리 내에서 또는 <literal>hibernate3.jar</literal> 
+                내에서 찾을 수 있다. Hibernate는 항상 첫 번째로 그것의 classpath 속에서 DTD를 찾게 될 것이다. 만일 
+                당신이 인터넷 연결을 사용하는 DTD에 대한 룩업들을 겪게 될 경우, 당신의 classpath의 컨텐츠에 대해 당신의 DTD 선언을 
+                체크하라.
+            </para>
+            
+            <sect3 id="mapping-declaration-entity-resolution">
+                <title>EntityResolver</title>
+                <para>
+                                        앞서 언급했듯이, Hibernate는 먼저 그것의 classpath에서 DTD들을 해석하려고 시도할 것이다. 
+                    Hibernate가 이것을 행하는 방법은 그것이 xml 파일들을 읽어들이는데 사용하는 SAXReader에 맞춤형  
+                    <literal>org.xml.sax.EntityResolver</literal> 구현을 등록하는 것이다. 이 맞춤형 
+                    <literal>EntityResolver</literal>는 두 개의 다른 systemId namespace들을 인지해낸다.
+                </para>
+                <itemizedlist>
+                    <listitem>
+                        <para>
+                            <literal>hibernate namespace</literal>는  resolver가 
+                            <literal>http://hibernate.sourceforge.net/</literal>로 시작하는 하나의 
+                            systemId와 만날때마다 인지된다; resolver는 Hibernate 클래스들을 로드시켰던 클래스로더를 통해 
+                                                        이들 엔티티들을 해석하려고 시도한다.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            <literal>user namespace</literal>는 resolver가  <literal>classpath://</literal> 
+                            URL 프로토콜을 사용하는 systemId를 만날때마다 인지된다; resolver는 (1)현재 쓰레드 컨텍스트 
+                                                        클래스로더와 (2)Hibernate 클래스들을 로드시켰던 클래스로더를 통해 이들 엔티티들을 해석하려고 
+                                                        시도할 것이다.
+                        </para>
+                    </listitem>
+                </itemizedlist>
+                <para>
+                    user namespacing을 활용하는 예제:
+                </para>
+                <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [
+    <!ENTITY types SYSTEM "classpath://your/domain/types.xml">
+]>
+
+<hibernate-mapping package="your.domain">
+    <class name="MyEntity">
+        <id name="id" type="my-custom-id-type">
+            ...
+        </id>
+    <class>
+    &types;
+</hibernate-mapping>]]></programlisting>
+                <para>
+                                        여기서 <literal>types.xml</literal>은 <literal>your.domain</literal> 패키지 내에 있는 리소스이고 
+                                        맞춤형 <xref linkend="mapping-types-custom">typedef</xref>를 포함한다.
+                </para>
+            </sect3>
+        </sect2>
+
+        <sect2 id="mapping-declaration-mapping" revision="3">
+            <title>hibernate-mapping</title>
+
+            <para>
+                                이 요소는 몇 개의 선택적인 속성들을 갖는다. <literal>schema</literal> 속성과 <literal>catalog</literal> 
+                                속성은 이 매핑 내에서 참조된 테이블들이 명명된 schema 와/또는 catalog에 속한다는 점을 지정한다. 만일 지정될 경우, 
+                                테이블 이름들은 주어진 schema 이름과 catalog 이름에 의해 한정(수식)될 것이다. 누락될 경우, 테이블 이름들은  
+                                한정되지((수식어가 붙지) 않을 것이다. <literal>default-cascade</literal> 속성은 <literal>cascade</literal> 
+                                속성을 지정하지 않은 프로퍼티들과 콜렉션들에 대해 전제될 <literal>cascade</literal> 스타일이 무엇인지를 지정한다. 
+                <literal>auto-import</literal> 속성은 디폴트로 우리가 질의 언어 속에서 수식어가 붙지 않은(unqualified) 
+                                클래스 이름들을 사용하게 할 것이다.
+            </para>
+ 
+             <programlistingco>
+                 <areaspec>
+                     <area id="hm1" coords="2 55"/>
+                     <area id="hm2" coords="3 55"/>
+                     <area id="hm3" coords="4 55"/>
+                     <area id="hm4" coords="5 55"/>
+                     <area id="hm5" coords="6 55"/>
+                     <area id="hm6" coords="7 55"/>
+                     <area id="hm7" coords="8 55"/>
+                 </areaspec>
+                 <programlisting><![CDATA[<hibernate-mapping
+         schema="schemaName"
+         catalog="catalogName"
+         default-cascade="cascade_style"
+         default-access="field|property|ClassName"
+         default-lazy="true|false"
+         auto-import="true|false"
+         package="package.name"
+ />]]></programlisting>
+                 <calloutlist>
+                     <callout arearefs="hm1">
+                         <para>
+                             <literal>schema</literal> (옵션): 데이터베이스 스키마의 이름.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm2">
+                         <para>
+                             <literal>catalog</literal> (옵션): 데이터베이스 카다록의 이름.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm3">
+                         <para>
+                             <literal>default-cascade</literal> (옵션 - 디폴트는 <literal>none</literal>): 
+                                                          디폴트 cascade 스타일.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm4">
+                         <para>
+                             <literal>default-access</literal> (옵션 - 디폴트는 <literal>property</literal>):
+                             Hibernate가 모든 프로퍼티들에 액세스하는데 사용하게 될 방도. <literal>PropertyAccessor</literal>에 
+                                                          대한  맞춤형 구현일 수 있다.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm5">
+                         <para>
+                             <literal>default-lazy</literal> (옵션 - 디폴트는 <literal>true</literal>):
+                             class 및 collection 매핑들의 지정되지 않은 <literal>lazy</literal> 속성들에 대한 디폴트 값.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm6">
+                         <para>
+                             <literal>auto-import</literal> (옵션 - 디폴트는 <literal>true</literal>):
+                                                          우리가 질의 언어 내에 (이 매핑에서 클래스들에 대해) 수식어가 붙지 않은 클래스 이름들을 사용할 수 있는지를 
+                                                          지정한다.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm7">
+                         <para>
+                             <literal>package</literal> (옵션): 매핑 문서 내에서 수식어가 붙지 않은 클래스 이름들에 대해 
+                                                          가정할 패키지 접두어를 지정한다.
+                         </para>
+                     </callout>
+                 </calloutlist>
+             </programlistingco>
+             
+             <para>
+                                  만일 당신이 동일한 (수식어가 붙지 않은) 이름을 가진 두 개의 영속 클래스들을 갖고 있다면, 당신은 <literal>auto-import="false"</literal>를 
+                                  설정해야 한다. 만일 당신이 두 개의 클래스들에 동일한 "imported" 이름을  할당하려고 시도할 경우에 Hibernate는 예외상황을 던질 것이다.
+             </para>
+
+             <para>
+                                  위에 보여진 것처럼 <literal>hibernate-mapping</literal> 요소는 몇몇 영속 <literal>&lt;class&gt;</literal> 매핑들을 내부에 포함하는 
+                                  것을 허용해준다는 점을 노트하라. 하지만 한 개의 매핑 파일 속에 한 개의 영속 클래스(또는 한 개의 클래스 계층구조) 만을 매핑하고 영속 서브 클래스 뒤에 
+                                  그것을 명명하는 것이 좋은 연습이다 (그리고 몇몇 도구들에 의해 기대된다). 예를 들면 <literal>Cat.hbm.xml</literal>, 
+                 <literal>Dog.hbm.xml</literal> 또는 상속을 사용할 경우에는 <literal>Animal.hbm.xml</literal>.
+             </para>
+ 
+        </sect2>
+
+        <sect2 id="mapping-declaration-class" revision="3">
+            <title>class</title>
+
+            <para>
+                                당신은 <literal>class</literal> 요소를 사용하여 영속 클래스를 선언할 수도 있다:
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="class1" coords="2 55"/>
+                    <area id="class2" coords="3 55" />
+                    <area id="class3" coords="4 55"/>
+                    <area id="class4" coords="5 55" />
+                    <area id="class5" coords="6 55"/>
+                    <area id="class6" coords="7 55" />
+                    <area id="class7" coords="8 55"/>
+                    <area id="class8" coords="9 55" />
+                    <area id="class9" coords="10 55" />
+                    <area id="class10" coords="11 55"/>
+                    <area id="class11" coords="12 55"/>
+                    <area id="class12" coords="13 55"/>
+                    <area id="class13" coords="14 55"/>
+                    <area id="class14" coords="15 55"/>
+                    <area id="class15" coords="16 55"/>
+                    <area id="class16" coords="17 55"/>
+                    <area id="class17" coords="18 55"/>
+                    <area id="class18" coords="19 55"/>
+                    <area id="class19" coords="20 55"/>
+                    <area id="class20" coords="21 55"/>
+                    <area id="class21" coords="22 55"/>
+                </areaspec>
+                <programlisting><![CDATA[<class
+        name="ClassName"
+        table="tableName"
+        discriminator-value="discriminator_value"
+        mutable="true|false"
+        schema="owner"
+        catalog="catalog"
+        proxy="ProxyInterface"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        select-before-update="true|false"
+        polymorphism="implicit|explicit"
+        where="arbitrary sql where condition"
+        persister="PersisterClass"
+        batch-size="N"
+        optimistic-lock="none|version|dirty|all"
+        lazy="true|false"
+        entity-name="EntityName"
+        check="arbitrary sql check condition"
+        rowid="rowid"
+        subselect="SQL expression"
+        abstract="true|false"
+        node="element-name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="class1">
+                        <para>
+                            <literal>name</literal> (옵션): 영속 클래스(또는 인터페이스)의 전체 수식어가 붙은 Java 클래스 이름. 
+                                                        만일 이 속성이 누락될 경우, 매핑이 non-POJO 엔티티라고 가정된다.
+                        </para>
+                    </callout>
+                    <callout arearefs="class2">
+                        <para>
+                            <literal>table</literal> (옵션 - 디폴트는 수식어가 붙지 않은 클래스명): 그것의 데이터베이스 테이블의 이름.
+                        </para>
+                    </callout>
+                    <callout arearefs="class3">
+                        <para>
+                            <literal>discriminator-value</literal> (옵션 - 디폴트는 클래스 이름): 다형성(polymorphic) 특징에 사용되는, 
+                                                        개별 서브 클래스들를 구별짓는 값. 허용가능한 값들은<literal>null</literal>과  <literal>not null</literal>을 포함한다.
+                        </para>
+                    </callout>
+                    <callout arearefs="class4">
+                        <para>
+                            <literal>mutable</literal> (옵션 - 디폴트는 <literal>true</literal>): 클래스들의 인스턴스들이 가변적인지를
+                            (가변적이지 않은지를) 지정한다.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class5">
+                        <para>
+                            <literal>schema</literal> (옵션): 루트 <literal>&lt;hibernate-mapping&gt;</literal> 요소에 의해 지정된 
+                                                        스키마 이름을 오버라이드 시킨다.
+                        </para>
+                    </callout>                
+                    <callout arearefs="class6">
+                        <para>
+                            <literal>catalog</literal> (옵션): 루트 <literal>&lt;hibernate-mapping&gt;</literal> 요소에 의해 지정된 
+                                                        카다록 이름을 오버라이드 시킨다.
+                        </para>
+                    </callout>                
+                    <callout arearefs="class7">
+                        <para>
+                            <literal>proxy</literal> (옵션): lazy initializing proxy들에 사용할 인터페이스를 지정한다. 당신은 클래스 
+                                                        그 자체의 이름을 지정할 수 도 있다.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class8">
+                        <para>
+                            <literal>dynamic-update</literal> (옵션 - 디폴트는 <literal>false</literal>): 
+                            <literal>UPDATE</literal> SQL이 실행 시에 생성되고 그들 컬럼들의 값들이 변경된 그들 컬럼들 만을 
+                                                        포함할 것인지를 지정한다.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class9">
+                        <para>
+                            <literal>dynamic-insert</literal> (옵션 - 디폴트는 <literal>false</literal>): 
+                                                        생성될 <literal>INSERT</literal>이 실행 시에 생성되고 그들 컬럼들의 값이 null이 아닌 컬럼들 만을 
+                                                        포함할 것인지를 지정한다.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class10">
+                        <para>
+                            <literal>select-before-update</literal> (옵션 - 디폴트는 <literal>false</literal>): 
+                                                        객체가 실제로 변경되는 것이 확실하지 않는 한, Hibernate가 SQL <literal>UPDATE</literal>를 
+                            <emphasis>결코</emphasis> 실행하지 않을 것임을 지정한다. 어떤 경우들에서(실제로 transient 
+                                                        객체가 <literal>update()</literal>를 사용하여 새로운 session에 연관되었을 때에만), 이것은 
+                                                        하나의 <literal>UPDATE</literal>가 실제로 필요한 경우인지 여부를 결정하기 위해 Hibernate는 
+                                                        특별한 SQL <literal>SELECT</literal>를 실행할 것임을 의미한다.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class11">
+                        <para>
+                            <literal>polymorphism</literal> (옵션 - 디폴트는 <literal>implicit</literal>): 
+                            implicit 질의 다형성이나 explicit 질의 다형성 중 어느 것이 사용될 것인지를 결정한다.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class12">
+                        <para>
+                            <literal>where</literal> (옵션) 이 클래스의 객체들을 검색할 때 사용될 임의적인 SQL 
+                            <literal>WHERE</literal> 조건을 지정한다
+                        </para>
+                    </callout>                 
+                    <callout arearefs="class13">
+                        <para>
+                            <literal>persister</literal> (옵션): 맞춤형 <literal>ClassPersister</literal>를 지정한다.
+                        </para>
+                    </callout>                 
+                    <callout arearefs="class14">
+                        <para>
+                            <literal>batch-size</literal> (옵션 - 디폴트는 <literal>1</literal>) 식별자에 의해 이 클래스의 
+                                                        인스턴스들을 페치시키는 "배치 사이즈"를 지정한다.
+                        </para>
+                    </callout>                 
+                   <callout arearefs="class15">
+                        <para>
+                            <literal>optimistic-lock</literal> (옵션 - 디폴트는 <literal>version</literal>): 
+                            optimistic 잠금 방도를 결정한다.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class16">
+                        <para>
+                            <literal>lazy</literal> (옵션): <literal>lazy="false"</literal>를 설정함으로써 
+                            Lazy fetching이 전체적으로 사용불가능하게 될 수 있다.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class17">
+                        <para>
+                            <literal>entity-name</literal>(옵션, 디폴트는 클래스 이름): Hibernate3는 하나의 클래스가 
+                            (잠정적으로 다른 테이블들로) 여러번 매핑되는 것을 허용해주고, Java 레벨에서 Map 또는 XML에 의해 표현
+                                                        되는 엔티티 매핑들을 허용한다. 이들 경우들에서, 당신은 그 엔티티에 대한 명시적인 임의의 이름을 제공해야 한다.
+                            <literal>entity-name</literal> (옵션): Hibernate3는  하나의 클래스가 (잠정적으로 다른 테이블들로) 
+                                                        여러 번 매핑되는 것을 허용하며, 자바 레벨에서 Map들 또는 XML에 의해 표현되는 엔티티 매핑들을 허용한다. 
+                                                        이들 경우들에서, 당신은 그 엔티티들에 대한 명시적인 임의의 이름을 제공해야 한다. 추가 정보는 
+                            <xref linkend="persistent-classes-dynamicmodels"/>과 <xref linkend="xml"/>을 보라.
+                        </para>
+                    </callout>
+                    <callout arearefs="class18">
+                        <para>
+                            <literal>check</literal> (옵션): 자동적인 스키마 생성을 위한 다중-행 <emphasis>check</emphasis> 
+                            constraint를 생성시키는데 사용되는 SQL 표현식.
+                        </para>
+                    </callout>
+                    <callout arearefs="class19">
+                        <para>
+                            <literal>rowid</literal> (옵션): Hibernate는 지원되는 데이터베이스들, 예를 들어 Oracle 상에서 이른바 
+                            ROWID들을 사용할 수 있고, Hibernate는 당신이 이 옵션을 <literal>rowid</literal>로 설정하는 경우에 빠른 
+                                                        업데이트를 위한 특별한 <literal>rowid</literal> 컬럼을 사용할 수 있다. ROWID는 구현 상세이고 저장된 
+                                                        튜플(tuple)의 물리적이니 위치를 표현한다.
+                        </para>
+                    </callout>
+                    <callout arearefs="class20">
+                        <para>
+                            <literal>subselect</literal> (옵션): 불변의 읽기 전용 엔티티를 데이터베이스 subselect로 매핑시킨다. 
+                                                        당신이 기본 테이블 대신에 뷰를 갖고자 원할 경우에 유용하지만, 사용을 자제하라. 추가 정보는 아래를 보라.
+                        </para>
+                    </callout>
+                    <callout arearefs="class21">
+                        <para>
+                            <literal>abstract</literal> (옵션): <literal>&lt;union-subclass&gt;</literal> 계층 구조들 내에서 
+                            abstract 슈퍼클래스들을 마크하는데 사용된다.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+           
+            <para>
+                                명명된 영속 클래스가 인터페이스가 되는 것은 완전히 수용가능하다. 그런 다음 당신은 <literal>&lt;subclass&gt;</literal> 
+                                요소를 사용하여 그 인터페이스에 대한 구현 클래스들을 선언할 것이다. 당신은 임의의 <emphasis>static</emphasis> inner 
+                                클래스를 영속화 시킬 수 있다. 당신은 표준 형식, 예를 들어 <literal>eg.Foo$Bar</literal>를 사용하여 클래스 이름을 
+                                지정해야 한다.
+            </para>
+
+            <para>
+                                불변의 클래스, <literal>mutable="false"</literal>는 어플리케이션에 의해 업데이트되지 않을 것이거나 삭제되지 않을 것이다. 
+                                이것은  Hibernate로 하여금 어떤 마이너 퍼포먼스 최적화를 행하게끔 허용해준다.
+            </para>
+            
+            <para>
+                                선택적인 <literal>proxy</literal> 속성은 그 클래스의 영속 인스턴스들에 대한 lazy 초기화를 가능하게 해준다. Hibernate는 
+                                명명된 인터페이스를 구현하는 CGLIB 프락시들을 초기에 반환할 것이다. 실제 영속 객체는 프락시의 메소드가 호출될 때 로드될 것이다. 
+                                아래 "Lazy 초기화를 위한 프락시들"을 보라.
+            </para>
+            
+            <para><emphasis>Implicit</emphasis> 다형성은 클래스의 인스턴스들이 어떤 서브클래스나 구현된 인터페이스 또는 클래스를 명명하는 
+                                질의에 의해 반환될 것임을 의미하고 그 클래스의 어떤 서브클래스에 대한 인스턴스들이 그 클래스 자체를 명명하는 질의에 의해 반환될 것임을 
+                                의미한다. <emphasis>Explicit</emphasis> 다형성은 클래스 인스턴스들이 그 클래스를 명시적으로 명명하는 질의들에 의해서만 
+                                반환될 것임을 의미고 그 클래스를 명명하는 질의들이 이 <literal>&lt;class&gt;</literal> 선언 내부에서 <literal>&lt;subclass&gt;</literal> 
+                                또는 <literal>&lt;joined-subclass&gt;</literal>로 매핑된 서브 클래스들의 인스턴스들 만을 반환하게 될 것임을 의미한다. 
+                                대부분의 용도로, 디폴트인 <literal>polymorphism="implicit"</literal>가 적절하다.두 개의 다른 클래스들이 동일한 테이블로 
+                                매핑될 때 Explicit 다형성이 유용하다(이것은 테이블 컬럼들의 서브셋을 포함하는 "경량급" 클래스를 허용한다).
+            </para>
+            
+            <para>
+                <literal>persister</literal> 속성은 클래스에 사용되는 영속화 방도를 당신이 커스트마이징 할 수 있도록 해준다. 예를 들어 
+                                당신은 <literal>org.hibernate.persister.EntityPersister</literal>에 대한 당신 자신의 서브클래스를 지정할 수도 
+                                있거나 당신은 심지어 예를 들어  플랫 파일들이나 LDAP로의 직렬화,내장 프로시저 호출들을 통해 영속화를 구현하는 인터페이스 
+                <literal>org.hibernate.persister.ClassPersister</literal>에 대한 완전히 새로운 구현을 제공할 수도 있다. 
+                (<literal>Hashtable</literal>로의 "영속성"에 관한) 간단한 예제는 
+                <literal>org.hibernate.test.CustomPersister</literal>를 보라. 
+            </para>
+            
+            <para>
+                <literal>dynamic-update</literal> 설정과 <literal>dynamic-insert</literal> 설정은 서브클래스들에 의해 
+                                상속되지 않고 따라서 또한 <literal>&lt;subclass&gt;</literal> 또는 <literal>&lt;joined-subclass&gt;</literal> 
+                                요소들 상에 지정될 수도 있음을 노트하라. 이들 설정들은 몇몇 경우들에서 퍼포먼스를 증가시키지만 다른 경우들에서는 퍼포먼스를 
+                                실제로 감소시킬 수도 있다. 적절하게 사용하라.
+            </para>
+            
+            <para>
+                <literal>select-before-update</literal> 사용은 대개 퍼포먼스를 감소시킬 것이다. 당신이 detached 인스턴스들의 
+                                그래프를 <literal>Session</literal>에 다시 첨부할 경우에 그것은  데이터베이스 업데이트 트리거가 불필요하게 호출되는 
+                                것을 방지하는데 매우 유용하다.
+            </para>
+            
+            <para>
+                <literal>dynamic-update</literal>를 사용가능하게 할 경우, 당신은 다음 optimistic 잠금 전략들을 선택하게 될 것이다:
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <literal>version</literal>은 version/timestamp 컬럼들을 체크한다
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>all</literal>은 모든 컬럼들을 체크한다
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>dirty</literal>는 몇몇 동시성 업데이트들을 허용하여, 변경된 컬럼들을 체크한다
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>none</literal>은 optimistic 잠금을 사용하지 않는다
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <para>
+                                우리는 당신이 Hibernate에서 optimistic 잠금을 위해 version/timestamp 컬럼들을 사용할 것을 <emphasis>매우</emphasis> 강력하게 
+                                권장한다. 이것은 퍼포먼스에 대해 최적의 방도이고 detached 인스턴스들에 대해 행해진 변경들을 정확하게 핸들링하는 유일한 방도이다(예를 들어 
+                <literal>Session.merge()</literal>가 사용될 때).
+            </para>
+
+            <para>
+                Hibernate 매핑의 경우에 베이스 테이블과 뷰 사이에 차이점이 존재하지 않는다. 왜냐하면 이것이 데이터베이스 레벨에서는 투명하다고 기대되기 
+                                때문이다(몇몇 DBMS는 뷰를 고유하게 지원하지 않고 특히 뷰 업데이트를 지원하지 않음을 노트하라). 때때로 당신이 뷰를 사용하고자 원하지만, 
+                (예를 들어 리거시 스키마로) 데이터베이스 속에 뷰를 생성시킬 수 없다. 이 경우에, 당신은 불변의 읽기 전용 엔티티를 주어진 SQL subselect 
+                                표현식으로 매핑시킬 수  있다:
+            </para>
+
+            <programlisting><![CDATA[<class name="Summary">
+    <subselect>
+        select item.name, max(bid.amount), count(*)
+        from item
+        join bid on bid.item_id = item.id
+        group by item.name
+    </subselect>
+    <synchronize table="item"/>
+    <synchronize table="bid"/>
+    <id name="name"/>
+    ...
+</class>]]></programlisting>
+
+            <para>
+                auto-flush가 정확하게 발생하도록 하고, 그리고 파생된 엔티티에 대한 질의들이 쓸효성 없는 데이터를 반환하지 않도록 함으로써, 이 엔티티와 동기화 될 
+                                테이블을 선언하라. <literal>&lt;subselect&gt;</literal>는 속성과 내포된 매핑 요소 양자로서 이용 가능하다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-id" revision="4">
+            <title>id</title>
+
+            <para>
+                                매핑된 클래스들은 데이터베이스 테이블의 프라이머리 키 컬럼을 선언<emphasis>해야 한다</emphasis>. 대부분의 클래스들은 또한 인스턴스의 유일 식별자를 소유하는 
+                                자바빈즈-스타일 프로퍼티를 가질 것이다. <literal>&lt;id&gt;</literal> 요소는 그 프로퍼티로부터 프라이머리 키 컬럼으로의 매핑을 정의한다.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="id1" coords="2 70"/>
+                    <area id="id2" coords="3 70" />
+                    <area id="id3" coords="4 70"/>
+                    <area id="id4" coords="5 70" />
+                    <area id="id5" coords="6 70" />
+                </areaspec>
+                <programlisting><![CDATA[<id
+        name="propertyName"
+        type="typename"
+        column="column_name"
+        unsaved-value="null|any|none|undefined|id_value"
+        access="field|property|ClassName">
+        node="element-name|@attribute-name|element/@attribute|."
+
+        <generator class="generatorClass"/>
+</id>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="id1">
+                        <para>
+                            <literal>name</literal> (옵션): 식별자 프로퍼티의 이름.
+                        </para>
+                    </callout>
+                    <callout arearefs="id2">
+                        <para>
+                            <literal>type</literal> (옵션): Hibernate 타입을 나타내는 이름.
+                        </para>
+                    </callout>
+                    <callout arearefs="id3">
+                        <para>
+                            <literal>column</literal> (옵션 - 디폴트는 프로퍼티 이름): 프라이머리 키 컬럼의 이름.
+                        </para>
+                    </callout>
+                    <callout arearefs="id4">
+                        <para>
+                            <literal>unsaved-value</literal> (옵션 - 디폴트는 "sensible" 값): 
+                                                        이전 세션에서 저장되었거나 로드되었던 detached(분리된) 인스턴스들로부터 그것을 구분지우도록, 인스턴스가 새로이 초기화되어 있음(저장되어 
+                                                        있지 않음)을 나타내는 식별자 프로퍼티 값.
+                        </para>
+                    </callout>            
+                   <callout arearefs="id5">
+                        <para>
+                            <literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>): 
+                            Hibernate가 프로퍼티 값에 액세스하는데 사용할 방도.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                <literal>name</literal> 속성이 누락되면, 클래스는 식별자 프로퍼티를 갖지 않는다고 가정된다.
+            </para>
+            
+            <para>
+                <literal>unsaved-value</literal> 속성은 Hibernate3에서는 거의 필요하지 않다.
+            </para>
+
+             <para>
+                composite 키들로서 리거시 데이터에 액세스하는 것을 허용해주는 대체적인 <literal>&lt;composite-id&gt;</literal> 
+                                선언이 존재한다. 우리는 그 밖의 어떤것에 대한 그것의 사용에 대해 강력하게 반대한다.
+            </para>
+            
+            <sect3 id="mapping-declaration-id-generator" revision="2">
+                <title>Generator</title>
+
+                <para>
+                                        선택적인 <literal>&lt;generator&gt;</literal> 자식 요소는 영속 클래스의 인스턴스들에 대한 유일 식별자들을 생성시키는데 사용되는 
+                                        자바 클래스를 명명한다. 만일 임의의 파라미터들이 생성기 인스턴스를 구성하거나 초기화 시키는데 필요할 경우, 그것들은 <literal>&lt;param&gt;</literal> 
+                                        요소 를 사용하여 전달된다. 
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="org.hibernate.id.TableHiLoGenerator">
+                <param name="table">uid_table</param>
+                <param name="column">next_hi_value_column</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                                        모든 생성기들은 <literal>org.hibernate.id.IdentifierGenerator</literal> 인터페이스를 구현한다. 이것은 매우 간단한 인터페이스이다; 
+                                        몇몇 어플리케이션들은 그것들 자신의 특화된 구현들을 제공하도록 선택할 수 있다. 하지만 Hibernate는 미리 빈드된 구현들의 영역들을 제공한다. 
+                                        빌드-인 생성기(generator)들에 대한 단축 이름들이 존재한다:
+
+                    <variablelist>
+                        <varlistentry>
+                        <term><literal>increment</literal></term>
+                        <listitem>
+                            <para>
+                                                                동일한 테이블 속으로 데이터를 입력하는 다른 프로세스가 없을 때에만 유일한 <literal>long</literal>, <literal>short</literal> 또는 <literal>int</literal> 
+                                                                타입의 식별자들을 생성시킨다. <emphasis>클러스터 내에서는 사용하지 말라.</emphasis> 
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>identity</literal></term>
+                        <listitem>
+                            <para>
+                                DB2, MySQL, MS SQL Server, Sybase, HypersonicSQL에서 식별 컬럼들을 지원한다. 반환되는 식별자는 <literal>long</literal>, 
+                                <literal>short</literal> 또는 <literal>int</literal> 타입이다.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>sequence</literal></term>
+                        <listitem>
+                            <para>
+                                DB2, PostgreSQL, Oracle, SAP DB, McKoi에서 시퀀스를 사용하거나 Interbase에서 생성기(generator)를 사용한다. 반환되는 식별자는 
+                                <literal>long</literal>, <literal>short</literal> 또는 <literal>int</literal> 타입이다.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>hilo</literal></term>
+                        <listitem>
+                            <para id="mapping-declaration-id-hilodescription" revision="1">
+                                                                테이블과 컬럼(디폴트로 각각 <literal>hibernate_unique_key</literal>와 <literal>next_hi</literal>)이 hi 값들의 
+                                                                소스로서 주어지면, <literal>long</literal>, <literal>short</literal> 또는 <literal>int</literal> 타입의 
+                                                                식별자들을 효과적으로 생성시키는데 hi/lo 알고리즘을 사용한다. hi/lo 알고리즘은 특정 데이터베이스에 대해서만 유일한 식별자들을 
+                                                                생성시킨다.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>seqhilo</literal></term>
+                        <listitem>
+                            <para>
+                                                                명명된 데이터베이스 시퀀스가 주어지면, <literal>long</literal>, <literal>short</literal> 또는 <literal>int</literal> 
+                                                                타입의 식별자들을 효과적으로 생성시키는데 hi/lo 알고리즘을 사용한다.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>uuid</literal></term>
+                        <listitem>
+                            <para>
+                                                                네트웍 내에서 유일한(IP 주소가 사용된다) string 타입의 식별자들을 생성시키기 위해 128 비트 UUID 알고리즘을 사용한다. 
+                                UUID는 길이가 32인 16진수들의 문자열로서 인코딩 된다.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>guid</literal></term>
+                        <listitem>
+                            <para>
+                                MS SQL Server와 MySQL 상에서 데이터베이스 생성 GUID 문자열을 사용한다.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>native</literal></term>
+                        <listitem>
+                            <para>
+                                                                기본 데이터베이스의 가용성들에 의존하여 <literal>identity</literal>, <literal>sequence</literal> 
+                                                                또는 <literal>hilo</literal>를 찾아낸다.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>assigned</literal></term>
+                        <listitem>
+                            <para>
+                                                                어플리케이션으로 하여금 <literal>save()</literal>가 호출되기 전에 식별자를 객체에 할당하도록 한다. 
+                                <literal>&lt;generator&gt;</literal> 요소가 지정되지 않을 경우 이것이 디폴트 방도이다.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>select</literal></term>
+                        <listitem>
+                            <para>
+                                                                어떤 유일 키에 의해 행을 select하고 프라이머리 키 값을 검색함으로써 데이터베이스 트리거에 의해 할당된 
+                                                                프라이머리 키를 검색한다.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>foreign</literal></term>
+                        <listitem>
+                            <para>
+                                                                또 다른 연관된 객체의 식별자를 사용한다. 대개 <literal>&lt;one-to-one&gt;</literal> 프라이머리 키 
+                                                                연관관계와 함께 사용된다.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>sequence-identity</literal></term>
+                        <listitem>
+                            <para>
+                                                                실제 값 생성을 위해 데이터베이스 시퀀스를 활용하지만, 생성된 식별자 값을 insert 문장 실행의 부분으로서 
+                                                                실제로 반환시키기 위해 이것을 JDBC3 getGeneratedKeys와 결합시킨 특화된 시퀀스 생성 방도. 이 방도는 
+                                JDK 1.4에 대상화된 Oracle 10g 드라이버들 상에서만 지원되는 거승로 알려져 있다. 이들 insert 문장들에 
+                                                                대한 주석들은 Oracle 드라이버들 내에 있는 버그 때문에 사용불가능하게 되어 있음을 노트하라.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                    </variablelist>
+
+                </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-hilo" revision="1">
+                <title>Hi/lo algorithm</title>
+                <para>
+                    <literal>hilo</literal>와 <literal>seqhilo</literal> 생성기들은 식별자 생성에 대한 마음에 드는 접근법인, 
+                    hi/lo 알고리즘에 대한 두 개의 대체 구현들은 제공한다. 첫 번째 구현은 다음에 이용 가능한 "hi" 값을 수용하기 위한 "특별한" 
+                                        데이터베이스 테이블을 필요로 한다. 두 번째는 (지원되는) Oracle 스타일의 시퀀스를 사용한다.
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="hilo">
+                <param name="table">hi_value</param>
+                <param name="column">next_value</param>
+                <param name="max_lo">100</param>
+        </generator>
+</id>]]></programlisting>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="seqhilo">
+                <param name="sequence">hi_value</param>
+                <param name="max_lo">100</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                                        불행히도 당신은 Hibernate에 당신 자신의 <literal>Connection</literal>을 제공할 때  <literal>hilo</literal>를 
+                                        사용할 수 없다. Hibernate가 JTA의 도움을 받는 커넥션들을 얻기 위해 어플리케이션 서버 데이터소스를 사용할 때 당신은 
+                    <literal>hibernate.transaction.manager_lookup_class</literal>를 적절하게 구성해야 한다.
+                </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-uuid">
+                <title>UUID 알고리즘</title>
+                <para>
+                    UUID 는 다음을 포함한다: IP 주소, JVM의 시작 시간(정확히 1/4 초), 시스템 시간과 (JVM 내에서 유일한) counter 값. 
+                    Java 코드로부터 MAC 주소 또는 메모리 주소를 얻는 것은 불가능하여서, 이것은 우리가 JNI를 사용하지 않고서 행할 수 있는 
+                                        최상의 것이다.
+                </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-sequences">
+            <title>식별 컬럼들과 시퀀스들</title>
+                <para>
+                                        식별 컬럼들을 지원하는 데이터베이스들(DB2, MySQL, Sybase, MS SQL)의 경우, 당신은 <literal>identity</literal> 키 
+                                        생성을 사용할 수 있다. 시퀀스들을 지원하는 데이터베이스들(DB2, Oracle, PostgreSQL, Interbase, McKoi, SAP DB)의 
+                                        경우, 당신은 <literal>sequence</literal> 스타일 키 생성을 사용할 수도 있다.  이들 방도들 모두 새로운 객체를 insert하기 
+                                        위해 두 개의 SQL 질의들을 필요로 한다.
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+        <generator class="sequence">
+                <param name="sequence">person_id_sequence</param>
+        </generator>
+</id>]]></programlisting>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id" unsaved-value="0">
+        <generator class="identity"/>
+</id>]]></programlisting>
+            
+                <para>
+                                        크로스 플랫폼 개발을 위해서, <literal>native</literal> 방도가 기준 데이터베이스들의 가용성들에 따라  <literal>identity</literal>, 
+                    <literal>sequence</literal>, <literal>hilo</literal> 방도 중에서 선택될 것이다.
+                </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-assigned">
+                <title>할당된 식별자들</title>
+                <para>
+                    (Hibernate로 하여금 식별자들을 생성시키도록 하는 것과는 반대로) 당신이 어플리케이션으로 하여금 식별자들을 할당하도록 원할 경우, 
+                                        당신은 <literal>assigned</literal> 생성기를 사용할 수 있다. 이 특별한 생성기는 객체의 identifier 프로퍼티에 이미 할당된 
+                                        식별자 값을 사용할 것이다. 이 생성기(generator)는 프라이머리 키가 대용(surrogate ) 키 대신에 natural 키일 때 사용된다. 
+                                        당신이 <literal>&lt;generator&gt;</literal> 요소를 지정하지 않을 경우에 이것이 디폴트 특징이다
+                </para>
+                
+                <para>
+                    <literal>assigned</literal> 생성기(generator)를 선택하는 것은 , version 또는 timestamp 프로퍼티가 존재하지 않는 한 
+                                        또는 당신이 <literal>Interceptor.isUnsaved()</literal>를 정의하지 않는 한, 하나의 인스턴스가 transient 또는 detached인지를 
+                                        결정하기 위해 Hibernae로 하여금 데이터베이스에 접촉하도록 강제하는, <literal>unsaved-value="undefined"</literal>를 
+                    Hibernate에게 사용하도록 한다.
+                </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-select">
+                <title>트리거들에 의해 할당된 프라이머리 키들</title>
+                <para>
+                                        리거시 스키마에 대해서만(Hibernate는 트리거들을 가진 DDL을 생성시키지 않는다).
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+        <generator class="select">
+                <param name="key">socialSecurityNumber</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                                        위의 예제에서, natural 키로서 클래스에 의해 <literal>socialSecurityNumber</literal>로 명명된 유일 값을 가진 프로퍼티가 존재하고, 
+                                        트리거에 의해 그 값이 생성되는 <literal>person_id</literal>로 명명된 대용키가 존재한다.
+                </para>
+                
+            </sect3>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-compositeid" revision="3">
+            <title>composite-id</title>
+
+            <programlisting><![CDATA[<composite-id
+        name="propertyName"
+        class="ClassName"
+        mapped="true|false"
+        access="field|property|ClassName">
+        node="element-name|."
+
+        <key-property name="propertyName" type="typename" column="column_name"/>
+        <key-many-to-one name="propertyName class="ClassName" column="column_name"/>
+        ......
+</composite-id>]]></programlisting>
+
+            <para>
+                composite 키를 가진 테이블의 경우, 당신은 클래스의 여러 프로퍼티들을 식별자 프로퍼티들로서 매핑할 수 있다. 
+                <literal>&lt;composite-id&gt;</literal> 요소는 자식 요소들로서 <literal>&lt;key-property&gt;</literal> 
+                                프로퍼티 매핑과 <literal>&lt;key-many-to-one&gt;</literal> 매핑들을 허용한다. 
+            </para>
+            
+            <programlisting><![CDATA[<composite-id>
+        <key-property name="medicareNumber"/>
+        <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+            <para>
+                                당신의 영속 클래스는 composite 식별자 동등성을 구현하기 위해서 <literal>equals()</literal>와 
+                <literal>hashCode()</literal>를 오버라이드 <emphasis>시켜야 한다</emphasis>. 그것은 또한 
+                <literal>Serializable</literal>을 구현해야 한다.
+            </para>
+
+            <para>
+                                불행히도, composite 식별자들에 대한 이 접근법은 영속 객체가 그것 자신의 식별자라는 점을 의미한다. 객체 
+                                자신 외의 다른 "핸들"이 존재하지 않는다. 당신은 당신이 composite key로 연관된 영속 상태를 <literal>load()</literal> 
+                                할 수 있기 이전에 영속 클래스 그 자체의 인스턴스를 초기화 하고 그것의 식별자 프로퍼티들을 군집화 시켜야 한다. 우리는 
+                                이 접근법을 <emphasis>embedded</emphasis> composite 식별자로 부르고, 중대한 어플리케이션들에 대해 그것을 억제시킨다.
+            </para>
+            
+            <para>
+                                두 번째 접근법은 우리가 <emphasis>mapped</emphasis> composite 식별자라고 부르는 것인데, 여기서 
+                <literal>&lt;composite-id&gt;</literal> 요소 내에 명명된 여기서 식별자 프로퍼티들은 영속 클래스와 별도의 식별자 클래스 
+                                양자 상에 중복된다.
+            </para>
+                
+            <programlisting><![CDATA[<composite-id class="MedicareId" mapped="true">
+        <key-property name="medicareNumber"/>
+        <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+            <para>
+                                이 예제에서, composite 식별자 클래스인 <literal>MedicareId</literal>와 엔티티 크래스 그 자체 양자는 
+                <literal>medicareNumber</literal>와  <literal>dependent</literal>로 명명된 프로퍼티들을 갖는다. 식별자 클래스는 
+                <literal>equals()</literal>와 <literal>hashCode()</literal>를 오버라이드 시켜고 <literal>Serializable</literal>을 
+                                구현해야 한다. 이 접근법의 단점은 아주 명백한&mdash;코드 중복이다.
+            </para>
+            
+            <para>
+                                다음 속성들은 매핑된 composite 식별자를 지정하는데 사용된다:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para> 
+                        <literal>mapped</literal> (옵션, 디폴트는 <literal>false</literal>):
+                                                하나의 매핑된 composite 식별자가 사용됨을, 그리고 포함된 프로퍼티 매핑들이 엔티티 클래스와 
+                        composite 식별자 클래스 양자를 참조함을 나타낸다.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>class</literal> (옵션, 하지만 하나의 매핑된 commposite 식별자에 대해서는 필수적임): 
+                                                하나의 composite 식별자로서 사용되는 클래스.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                                우리는 <xref linkend="components-compositeid"/>에서 composite 식별자가 하나의 component 클래스로서 구현되는 
+                                보다 편리한 접근법인 세번째 방도를 설명할 것이다. 아래에 설명되어 있는 속성들은 이 대체적인 접근법에만 적용된다:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>name</literal> (옵션, 이 접근법의 경우에는 필수임): 하나의 component 
+                                                식별자를 소유하는 컴포넌트 타입의 프로퍼티(9장을 보라).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>): 
+                        Hibernate가 프로퍼티 값에 접근하는데 사용할 방도.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>class</literal> (옵션 - 디폴트는 reflection에 의해 결정된 프로퍼티 타입): 
+                                                하나의 composite 식별자로서 사용되는 컴포넌트 클래스(다음 절을 보라).
+                    </para>
+                </listitem>
+            </itemizedlist>
+            
+            <para>
+                                이 세번째 접근법, <emphasis>identifier component</emphasis>은 거의 모든 어플리케이션들에 대해 우리가 권장하는 것이다.
+            </para>
+        </sect2>
+        
+        <sect2 id="mapping-declaration-discriminator" revision="3">
+            <title>discriminator</title>
+
+            <para>
+                <literal>&lt;discriminator&gt;</literal> 요소는 table-per-class-hierarchy(테이블 당 클래스 계층구조) 
+                                매핑 방도를 사용하는 다형성 영속화에 필요하고 테이블의 discriminator(판별자) 컬럼을 선언한다. discriminator 컬럼은 
+                                특정 행에 대해 초기화 시킬 서브 클래스가 무엇인지를 영속 계층에 알려주는 표시자 값들을 포함한다. 타입들의 제한적인 집합이 
+                                사용될 수 있다:  <literal>string</literal>, <literal>character</literal>, <literal>integer</literal>, 
+                <literal>byte</literal>, <literal>short</literal>, <literal>boolean</literal>,
+                <literal>yes_no</literal>, <literal>true_false</literal>.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="discriminator1" coords="2 60"/>
+                    <area id="discriminator2" coords="3 60" />
+                    <area id="discriminator3" coords="4 60" />
+                    <area id="discriminator4" coords="5 60" />
+                    <area id="discriminator5" coords="6 60" />
+                </areaspec>
+                <programlisting><![CDATA[<discriminator
+        column="discriminator_column"
+        type="discriminator_type"
+        force="true|false"
+        insert="true|false"
+        formula="arbitrary sql expression"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="discriminator1">
+                        <para>
+                            <literal>column</literal> (옵션 - 디폴트는 <literal>class</literal>) 
+                            discriminator 컬럼명.
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator2">
+                        <para>
+                            <literal>type</literal> (옵션 - 디폴트는 <literal>string</literal>) 
+                            Hibernate 타입을 나타내는 이름
+                        </para>
+                    </callout>          
+                    <callout arearefs="discriminator3">
+                        <para>
+                            <literal>force</literal> (옵션 - 디폴트는 <literal>false</literal>) 
+                                                        이것은 Hibernate로 하여금 루트 클래스의 모든 인스턴스들을 검색할 때조차도 허용된 discriminator 
+                                                        값들을 지정하도록 "강제한다".
+                        </para>
+                    </callout>          
+                    <callout arearefs="discriminator4">
+                        <para>
+                            <literal>insert</literal> (옵션 - 디폴트는 <literal>true</literal>)
+                                                        당신의 discriminator 컬럼이 또한 매핑된 composite 식별자의 부분일 경우에 이것을 <literal>false</literal>로 설정하라.
+                            (Hibernate에게  SQL <literal>INSERT</literal>들 속에 그 컬럼을 포함하지 않도록 통보한다.) 
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator5">
+                        <para>
+                            <literal>formula</literal> (옵션) 
+                                                        타입이 평가 되어야 할 때 실행되는 임의의 SQL 표현식. 컨텐츠 기반의 판별을 허용해준다.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                discriminator 컬럼의 실제 값들은 <literal>&lt;class&gt;</literal> 요소와 
+                <literal>&lt;subclass&gt;</literal> 요소의 <literal>discriminator-value</literal> 속성에 의해 지정된다.
+            </para>
+            
+            <para>
+                <literal>force</literal> 속성은 테이블이 영속 클래스로 매핑되지 않는 "특별한" discriminator 값들을 가진 행들을 
+                                포함할 경우에(만) 유용하다. 이것은 대개 그 경우가 아닐 것이다.
+            </para>
+
+            <para>
+                <literal>formula</literal> 속성을 사용하여 당신은 행의 타입을 판단하는데 사용될 임의의 SQL 표현식을 선언할 수 있다:
+            </para>
+
+            <programlisting><![CDATA[<discriminator
+    formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
+    type="integer"/>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-version" revision="4">
+            <title>version (옵션)</title>
+            
+            <para>
+                <literal>&lt;version&gt;</literal> 요소는 옵션이고 테이블이 버전화된 데이터를 포함한다는 것을 나타낸다. 
+                                이것은 당신이 <emphasis>긴 트랜잭션(long transaction)들</emphasis>을 사용할 계획이라면 특히 유용하다
+                (아래를 보라). 
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="version1" coords="2 70"/>
+                    <area id="version2" coords="3 70"/>
+                    <area id="version3" coords="4 70"/>
+                    <area id="version4" coords="5 70"/>
+                    <area id="version5" coords="6 70"/>
+                    <area id="version6" coords="7 70"/>
+                    <area id="version7" coords="8 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<version
+        column="version_column"
+        name="propertyName"
+        type="typename"
+        access="field|property|ClassName"
+        unsaved-value="null|negative|undefined"
+        generated="never|always"
+        insert="true|false"
+        node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="version1">
+                        <para>
+                            <literal>column</literal> (옵션 - 디폴트는 프로퍼티 명):
+                                                        버전 번호를 가진 컬럼의 이름.
+                        </para>
+                    </callout>          
+                    <callout arearefs="version2">
+                        <para>
+                            <literal>name</literal>: 영속 클래스의 프로퍼티 명.
+                        </para>
+                    </callout>
+                    <callout arearefs="version3">
+                        <para>
+                            <literal>type</literal> (옵션 - 디폴트는 <literal>integer</literal>): 
+                                                        버전 번호의 타입.
+                        </para>
+                    </callout>          
+                   <callout arearefs="version4">
+                        <para>
+                            <literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>): 
+                            Hibernate가 프로퍼티 값에 액세스하는데 사용할 방도.
+                        </para>
+                    </callout>
+                   <callout arearefs="version5">
+                        <para>
+                            <literal>unsaved-value</literal> (옵션 - 디폴트는 <literal>undefined</literal>): 
+                                                        이전 세션에서 저장되었거나 로드되었던 detached 인스턴스로부터 구별지어서, 인스턴스가 새로이 초기화됨(unsaved)을 
+                                                        나타내는 version 프로퍼티 값.(<literal>undefined</literal>는 식별자 프로퍼티 값이 사용될 것임을 지정한다.)
+                        </para>
+                    </callout>
+                    <callout arearefs="version6">
+                        <para>
+                            <literal>generated</literal> (옵션 - 디폴트는 <literal>never</literal>):
+                                                        이 version 프로퍼티 값이 데이터베이스에 의해 실제로 산출되는지를 지정한다. 
+                            <xref linkend="mapping-generated">산출되는 프로퍼티들</xref>에 관한 논의를 보라.
+                        </para>
+                    </callout>
+                    <callout arearefs="version7">
+                        <para>
+                            <literal>insert</literal> (옵션 - 디폴트는 <literal>true</literal>):
+                            version 컬럼이 SQL insert 문장들 속에 포함될 것인지 여부를 지정한다.
+                                                       데이터베이스 컬럼이 디폴트 값 <literal>0</literal>으로 정의되는 경우에만 <literal>false</literal>로 
+                                                        설정될 수 있다.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                                버전 번호들은 <literal>long</literal>, <literal>integer</literal>, <literal>short</literal>, 
+                <literal>timestamp</literal> 또는 <literal>calendar</literal> 타입일 수 있다.
+            </para>
+            
+            <para>
+                version 또는 timestamp 프로퍼티는 detached 인스턴스에 대해 결코 null일 수가 없어서, Hibernate는 
+                                다른 <literal>unsaved-value</literal> 방도들이 지정되는 것에 상관없이, null version이나 timestamp를 
+                                가진 임의의 인스턴스를 transient로서 검출할 것이다. <emphasis>null 허용되는 version 이나 property를 
+                                선언하는 것은 Hibernate에서 transitive reattachment에 대한 임의의 문제들을 피하는 쉬운 방법이고, 
+                assigned 식별자들이나 composite key들을 사용하는 사람들에게 특히 유용하다!</emphasis>
+            </para>
+        </sect2>
+        
+        <sect2 id="mapping-declaration-timestamp" revision="4" >
+            <title>timestamp (옵션)</title>
+
+            <para>
+                                옵션 <literal>&lt;timestamp&gt;</literal> 요소는 테이블이 타임스탬프화 된 데이터를 포함함을 나타낸다. 이것은 
+                                버전화에 대한 대체물로서 고안되었다. Timestamp은 고유하게 optimistic 잠금에 대한 다소 안전한 구현이다. 하지만 때때로 
+                                어플리케이션은 다른 방법들로 timestamp들을 사용할 수도 있다.
+            </para>
+                        
+            <programlistingco>
+                <areaspec>
+                    <area id="timestamp1" coords="2 70"/>
+                    <area id="timestamp2" coords="3 70" />
+                    <area id="timestamp3" coords="4 70" />
+                    <area id="timestamp4" coords="5 70" />
+                    <area id="timestamp5" coords="6 70" />
+                    <area id="timestamp6" coords="7 70" />
+                </areaspec>            
+                <programlisting><![CDATA[<timestamp
+        column="timestamp_column"
+        name="propertyName"
+        access="field|property|ClassName"
+        unsaved-value="null|undefined"
+        source="vm|db"
+        generated="never|always"
+        node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="timestamp1">
+                        <para>
+                            <literal>column</literal> (옵션 - 디폴트는 프로퍼티 명): 
+                                                        타임스탬프를 포함하는 컬럼 명.
+                        </para>
+                    </callout>                   
+                    <callout arearefs="timestamp2">
+                        <para>
+                            <literal>name</literal>: 
+                                                        영속 클래스에 대해 자바 <literal>Date</literal> 또는 <literal>Timestamp</literal> 타입을 
+                                                        가진 자바빈즈 스타일의 프로퍼티 이름.
+                        </para>
+                    </callout>
+                    <callout arearefs="timestamp3">
+                        <para>
+                            <literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>): 
+                            Hibernate가 프로퍼티 값에 접근하는데 사용할 방도.
+                        </para>
+                    </callout>
+                   <callout arearefs="timestamp4">
+                        <para>
+                            <literal>unsaved-value</literal> (옵션 - 디폴트는 <literal>null</literal>): 
+                                                        이전 세션에서 저장되었거나 로드되었던 detached 인스턴스로부터 인스턴스를 구별지우는, 인스턴스가 새로이 
+                                                        초기화됨(unsaved)을 나타내는 version 프로퍼티 값.(<literal>undefined</literal>는 식별자 
+                                                        프로퍼티 값이 사용될 것임을 지정한다.)
+                        </para>
+                    </callout>
+                    <callout arearefs="timestamp5">
+                        <para>
+                            <literal>source</literal> (옵션 - 디폴트는 <literal>vm</literal>):
+                            Hibernate는 어디서 timestamp 값을 검색할 것인가? 데이터베이스로부터인가 현재의 JVM으로부터인가?
+                                                        데이터베이스 기반의 timestamp들은 Hibernate가 "다음 값"을 결정하기 위해 데이터베이스에 접속해야 
+                                                        하기 때문에 오버헤드를 초래하지만, 클러스터링된 환경들에서의 용도로 보다 더 안전할 것이다. 또한 모든 
+                            <literal>Dialect</literal>들이 데이터베이스의 현재의 timestamp에 대한 검색을 지원하는 것으로 알려져 
+                                                        있지 않지만, 다른 <literal>Dialect</literal>들은 정밀도 결핍 때문에 잠금에 있어 사용이 안전하지 않을 
+                                                        수 있음을 노트하라(예를 들면 오라클 8).
+                        </para>
+                    </callout>
+                    <callout arearefs="timestamp6">
+                        <para>
+                            <literal>generated</literal> (옵션 - 디폴트는 <literal>never</literal>):
+                                                        이 timestamp 프로퍼티 값이 데이터베이스에 의해 실제로 생성됨을 지정한다.
+                            <xref linkend="mapping-generated">산출되는 프로퍼티들</xref>에 대한 논의들 보라.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                <literal>&lt;timestamp&gt;</literal>는 <literal>&lt;version type="timestamp"&gt;</literal>과 
+                                같음을 노트하라. 그리고 <literal>&lt;timestamp use-db="true"&gt;</literal>는 
+                <literal>&lt;version type="dbtimestamp"&gt;</literal>과  같다
+            </para>
+        </sect2>
+
+
+        <sect2 id="mapping-declaration-property" revision="4">
+            <title>프로퍼티</title>
+
+            <para>
+                <literal>&lt;property&gt;</literal> 요소는 클래스의 자바빈즈 스타일의 영속 프로퍼티를 선언한다.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="property1" coords="2 70"/>
+                    <area id="property2" coords="3 70"/>
+                    <area id="property3" coords="4 70"/>
+                    <areaset id="property4-5" coords="">
+                        <area id="property4" coords='5 70'/>
+                        <area id="property5" coords='6 70'/>
+                    </areaset>
+                    <area id="property6" coords="7 70"/>
+                    <area id="property7" coords="8 70"/>
+                    <area id="property8" coords="9 70"/>
+                    <area id="property9" coords="10 70"/>
+                    <area id="property10" coords="11 70"/>
+                    <area id="property11" coords="12 70"/>
+                    <area id="property12" coords="13 70"/>
+                </areaspec>            
+                <programlisting><![CDATA[<property
+        name="propertyName"
+        column="column_name"
+        type="typename"
+        update="true|false"
+        insert="true|false"
+        formula="arbitrary SQL expression"
+        access="field|property|ClassName"
+        lazy="true|false"
+        unique="true|false"
+        not-null="true|false"
+        optimistic-lock="true|false"
+        generated="never|insert|always"
+        node="element-name|@attribute-name|element/@attribute|."
+        index="index_name"
+        unique_key="unique_key_id"
+        length="L"
+        precision="P"
+        scale="S"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="property1">
+                        <para>
+                            <literal>name</literal>: 첫 소문자로 시작하는 프로퍼티 이름.
+                        </para>
+                    </callout>                   
+                    <callout arearefs="property2">
+                        <para>
+                            <literal>column</literal> (옵션 - 디폴트는 프로퍼티 이름): 
+                                                        매핑된 데이터베이스 테이블 컬럼의 이름. 이것은 또한 내부에 포함되는 <literal>&lt;column&gt;</literal> 요소(들)에 
+                                                        의해 지정될 수도 있다.
+                        </para>
+                    </callout>
+                    <callout arearefs="property3">
+                        <para>
+                            <literal>type</literal> (옵션): Hibernate 타입을 나타내는 이름.
+                        </para>
+                    </callout>
+                    <callout arearefs="property4-5">
+                        <para>
+                            <literal>update, insert</literal> (옵션 - 디폴트는 <literal>true</literal>) :
+                                                        매핑된 컬럼들이 <literal>UPDATE</literal>와/또는 <literal>INSERT</literal> 문장들속에 포함될 것임을 지정한다. 
+                                                        둘다 <literal>false</literal>로 설정하는 것은  그 값이 동일한 컬럼(들)로 매핑되는 어떤 다른 프로퍼티로부터 또는 트리거에 
+                                                        의해 또는 다른 어플리케이션으로부터 초기화 되는 순수하게 "파생된(derived)" 프로퍼티를 허용해준다.
+                        </para>
+                    </callout>
+                    <callout arearefs="property6">
+                        <para>
+                            <literal>formula</literal> (옵션): 
+                            <emphasis>계산되는</emphasis> 프로퍼티에 대해 값을 정의하는 SQL 표현식. 계산되는 프로퍼티들은 
+                                                        그것들 자신에 대한 컬럼 매핑을 갖지 않는다.
+                        </para>
+                    </callout>
+                   <callout arearefs="property7">
+                        <para>
+                            <literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>): 
+                            Hibernate가 프로퍼티 값에 접근하는데 사용할 방도.
+                        </para>
+                    </callout>
+                   <callout arearefs="property8">
+                        <para>
+                            <literal>lazy</literal> (옵션 - 디폴트는 <literal>false</literal>): 
+                                                        인스턴스 변수가 처음으로 액세스 될 때 이 프로퍼티가 lazily하게 페치될 것임을 지정한다(빌드-시 바이트코드 
+                                                        수단을 필요로 한다).
+                        </para>
+                    </callout>
+                    <callout arearefs="property9">
+                        <para>
+                            <literal>unique</literal> (옵션): 
+                                                        컬럼들에 대한 유일 컨스트레인트의 DDL 생성을 가능하게 만든다. 또한 이것이 <literal>property-ref</literal>의 
+                                                        타켓이 되는 것을 허용해준다.
+                        </para>
+                    </callout>
+                    <callout arearefs="property10">
+                        <para>
+                            <literal>not-null</literal> (옵션): 
+                                                        컬럼들에 대해 null 가능 컨스트레인트의 DDL 생성을 가능하게 만든다.
+                        </para>
+                    </callout>
+                    <callout arearefs="property11">
+                        <para>
+                            <literal>optimistic-lock</literal> (옵션 - 디폴트는 <literal>true</literal>): 
+                                                        이 프로퍼티에 대한 업데이트들이 optimistic 잠금을 획득하는 것을 필요로 하거나 필요로 하지 않음을 지정한다. 
+                                                        달리말해, 이 프로퍼티가 dirty일 때 버전 증가가 발생할 경우인지를 결정한다.
+                        </para>
+                    </callout>
+                    <callout arearefs="property12">
+                        <para>
+                            <literal>generated</literal> (옵션 - 디폴트는 <literal>never</literal>):
+                                                        이 프로퍼티 값이 데이터베이스에 의해 실제로 산출되는지를 지정한다. 
+                            <xref linkend="mapping-generated">산출되는 프로퍼티들</xref>에 대한 논의를 보라.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                <emphasis>typename</emphasis>은 다음일 수 있다:
+            </para>
+
+            <orderedlist spacing="compact">
+                <listitem>
+                    <para>
+                        Hibernate 기본 타입의 이름 (예를 들어. <literal>integer, string, character, date, timestamp, 
+                        float, binary, serializable, object, blob</literal>).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                                                디폴트 기본 타입을 가진 Java 클래스의 이름(예를 들어. <literal>int, float,
+                        char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob</literal>).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        serializable Java 클래스의 이름.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                                                맞춤 타입의 클래스 이름(예를 들어. <literal>com.illflow.type.MyCustomType</literal>).
+                    </para>
+                </listitem>
+            </orderedlist>
+
+            <para>
+                                만일 당신이 타입을 지정하지 않을 경우, Hibernate는 정확한 Hibernate 타입을 추정하기 위해 명명된 프로퍼티에 대해 
+                reflection을 사용할 것이다. Hibernate는 그 순서에서 2,3,4 규칙들을 사용하여  프로퍼티 getter의 반환 클래스의 
+                                이름을 해석하려고 시도할 것이다. 하지만 이것은 항상 충분하지는 않다. 어떤 경우들에서, 당신은 여전히 <literal>type</literal> 
+                                속성을 필요로 할 것이다.(예를 들어, <literal>Hibernate.DATE</literal>와 <literal>Hibernate.TIMESTAMP</literal> 
+                                사이를 구별하기 위해, 또는 맞춤 타입을 지정하기 위해.)
+            </para>
+            
+            <para>
+                <literal>access</literal> 속성은 당신으로 하여금 Hibernate가 런타임 시에 프로퍼티에 액세스하는 방법을 제어하도록 해준다. 
+                                디폴트로 Hibernate는 프로퍼티 get/set 쌍을 호출할 것이다. 만일 당신이 <literal>access="field"</literal>를 지정할 
+                                경우, Hibernate는 get/set 쌍을 피하고 reflection을 사용하여 직접 필드에 액세스 할 것이다. 당신은 
+                <literal>org.hibernate.property.PropertyAccessor</literal> 인터페이스를 구현하는 클래스를 명명함으로써 
+                                프로퍼티 접근을 위한 당신 자신의 방도를 지정할 수도 있다.
+            </para>
+
+            <para>
+                                특별히 강력한 특징은 파생된 플로퍼티들이다. 이들 프로퍼티들은 정의상 읽기 전용이고, 그 프로퍼티 값은 로드 시에 계산된다. 당신은 
+                                그 계산을 SQL 표현식으로 선언하고, 이것은 인스턴스를 로드시키는 SQL 질의 내의 <literal>SELECT</literal> 절 서브질의로 
+                                번역된다:
+            </para>
+
+        <programlisting><![CDATA[
+<property name="totalPrice"
+    formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p
+                WHERE li.productId = p.productId
+                AND li.customerId = customerId
+                AND li.orderNumber = orderNumber )"/>]]></programlisting>
+
+            <para>
+                                당신은 특정 컬럼(주어진 예제에서는 <literal>customerId</literal>)에 대해 alias를 선언하지 않음으로써 엔티티들 자신의 
+                                테이블을 참조할 수 있음을 노트하라. 또한 당신은 만일 당신이 그 속성을 사용하고 싶지 않을 경우에 내포된 <literal>&lt;formula&gt;</literal> 
+                                매핑 요소를 사용할 수 있음을 노트하라.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-manytoone" revision="5">
+            <title>many-to-one</title>
+
+            <para>
+                                또 다른 영속 클래스에 대한 정규 연관관계는 <literal>many-to-one</literal> 요소를 사용하여 선언된다. 관계형 모형은 
+                many-to-one 연관관계이다.: 하나의 테이블 내에 있는 foreign 키는 대상 테이블의 프라이머리 키 컬럼(들)을 참조하고 있다.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="manytoone1" coords="2 70"/>
+                    <area id="manytoone2" coords="3 70"/>
+                    <area id="manytoone3" coords="4 70"/>
+                    <area id="manytoone4" coords="5 70"/>
+                    <area id="manytoone5" coords="6 70"/>
+                    <areaset id="manytoone6-7" coords="">
+                        <area id="manytoone6" coords='7 70'/>
+                        <area id="manytoone7" coords='8 70'/>
+                    </areaset>
+                    <area id="manytoone8" coords="9 70"/>
+                    <area id="manytoone9" coords="10 70"/>
+                    <area id="manytoone10" coords="11 70"/>
+                    <area id="manytoone11" coords="12 70"/>
+                    <area id="manytoone12" coords="13 70"/>
+                    <area id="manytoone13" coords="14 70"/>
+                    <area id="manytoone14" coords="15 70"/>
+                    <area id="manytoone15" coords="16 70"/>
+                    <area id="manytoone16" coords="17 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<many-to-one
+        name="propertyName"
+        column="column_name"
+        class="ClassName"
+        cascade="cascade_style"
+        fetch="join|select"
+        update="true|false"
+        insert="true|false"
+        property-ref="propertyNameFromAssociatedClass"
+        access="field|property|ClassName"
+        unique="true|false"
+        not-null="true|false"
+        optimistic-lock="true|false"
+        lazy="proxy|no-proxy|false"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        formula="arbitrary SQL expression"
+        node="element-name|@attribute-name|element/@attribute|."
+        embed-xml="true|false"
+        index="index_name"
+        unique_key="unique_key_id"
+        foreign-key="foreign_key_name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="manytoone1">
+                        <para>
+                            <literal>name</literal>: 프로퍼티의 이름.
+                        </para>                    
+                    </callout>                   
+                    <callout arearefs="manytoone2">
+                        <para>
+                            <literal>column</literal> (옵션): 
+                            foreign key 컬럼의 이름. 이것은 또한 내포된 <literal>&lt;column&gt;</literal> 요소(들)에 의해  
+                                                        지정된다.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone3">
+                        <para>
+                            <literal>class</literal> (옵션 - 디폴트는 reflection에 의해 결정된 프로퍼티 타입): 
+                                                        연관된 클래스의 이름. 
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone4">
+                        <para>
+                            <literal>cascade</literal> (옵션): 
+                                                        어느 오퍼레이션들이 부모 객체로부터 연관된 객체로 케스케이드 될 것인지를 지정한다.
+                        </para>                    
+                    </callout>
+                    <callout arearefs="manytoone5">
+                        <para>
+                            <literal>fetch</literal> (옵션 - 디폴트는 <literal>select</literal>): 
+                            outer-join 페칭 또는 sequential select 페칭 사이에서 선택하라.
+                        </para>                    
+                    </callout>
+                    <callout arearefs="manytoone6-7">
+                        <para>
+                            <literal>update, insert</literal> (옵션 - 디폴트는 <literal>true</literal>) 
+                                                        매핑된 컬럼들이 SQL <literal>UPDATE</literal>와/또는 <literal>INSERT</literal> 문장들 속에 포함될 것인지를 지정한다. 
+                                                        둘다 <literal>false</literal>로 설정하는 것은  그 값이 동일한 컬럼(들)로 매핑시키는 어떤 다른 컬럼들로부터 초기화 되거나 트리거나 
+                                                        다른 어플리케이션에 의해 초기화되는 단순한 "파생된" 연관관계 값을 허용한다.
+                        </para>                    
+                    </callout>
+                    <callout arearefs="manytoone8">
+                        <para>
+                            <literal>property-ref</literal>: (옵션) 이 foreign key에 조인되는 연관된 클래스의 프로퍼티 이름. 지정되지 않을 경우, 
+                                                        연관 클래스의 프라이머리 키가 사용된다.
+                        </para>                
+                    </callout>                   
+                   <callout arearefs="manytoone9">
+                        <para>
+                            <literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>): 
+                            Hibernate가 프로퍼티 값에 접근하는데 사용할 방도.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone10">
+                        <para>
+                            <literal>unique</literal> (옵션): 
+                            foreign-key 컬럼을 위한 유일 컨스트레인트의 DDL 생성을 가능하도록 해준다. 또한 이것이 property-ref의 대상이 되는 것을 허용해준다. 
+                                                        이것은 연관 다중성(association multiplicity)을 효율적으로 일 대 일로 만든다.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone11">
+                        <para>
+                            <literal>not-null</literal> (옵션): 
+                            foreign key 컬럼들을 위한 null 가능한 컨스트레인트의 DDL 생성을 가능하도록 해준다. 
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone12">
+                        <para>
+                            <literal>optimistic-lock</literal> (옵션 - 디폴트는 <literal>true</literal>): 
+                                                        이 프로퍼티에 대한 업데이트들이 optimistic lock의 획득을 필요로 하는지 아닌지 여부를 지정한다. 
+                                                        달리 말해 이 프로퍼티가 dirty일 때 version 증가가 발생해야 할 경우인지를 결정한다.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone13">
+                        <para>
+                            <literal>lazy</literal> (옵션 - 디폴트는 <literal>proxy</literal>): 
+                                                        디폴트로, 단일 포인트 연관들이 프락시된다. <literal>lazy="no-proxy"</literal>는 인스턴스 변수가 처음으로 접근될 때 
+                                                        그 프로퍼티가 lazily 페치될 것임을 지정한다(빌드-시 바이트코드 수단을 필요로 한다). <literal>lazy="false"</literal>는 
+                                                        그 연관이 항상 eagerly 페치될 것임을 지정한다.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone14">
+                        <para>
+                            <literal>not-found</literal> (옵션 - 디폴트는 <literal>exception</literal>): 
+                                                        누락된 행들을 참조하는 foreign key들이 어떻게 처리될 것인지를 지정한다: <literal>ignore</literal>는 한 개의 누락된 행을 
+                                                        한 개의 null 연관으로 취급할 것이다.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone15">
+                        <para>
+                            <literal>entity-name</literal> (옵션): 연관된 클래스의 엔티티 이름.
+                        </para>                   
+                    </callout>
+                </calloutlist>
+                    <callout arearefs="manytoone16">
+                        <para>
+                            <literal>formula</literal> (옵션): <emphasis>계산된</emphasis> foreign key에 대한 값을 정의하는 SQL 표현식.
+                        </para>
+                    </callout>
+            </programlistingco>
+
+            <para>
+                <literal>cascade</literal> 속성 값을 <literal>none</literal> 아닌 어떤 의미있는 다른 값으로 설정하는 것은 
+                                어떤 오퍼레이션들을 연관된 객체에게 보급할 것이다. 유의미한 값들은 Hibernate의 기본 오퍼레이션들의 이름들,
+                                즉 <literal>persist, merge, delete, save-update, evict, replicate, lock, refresh</literal> 
+                                뿐만 아니라 특별한 값들, 즉 <literal>delete-orphan</literal>과 <literal>all</literal> 그리고 오퍼레이션 이름들의 
+                                쉼표 분리된 조합들, 예를 들면 <literal>cascade="persist,merge,evict"</literal> 또는 
+                <literal>cascade="all,delete-orphan"</literal>이다. 전체 설명은 
+                <xref linkend="objectstate-transitive"/>를 보라. 단일값 연관들(many-to-one 연관과 
+                one-to-one 연관)은 orphan delete를 지원하지 않음을 노트하라.
+            </para>
+            
+            <para>
+                                일반적인 <literal>many-to-one</literal> 선언은 다음과 같이 간단하게 보여진다:
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="product" class="Product" column="PRODUCT_ID"/>]]></programlisting>
+            
+            <para>
+                <literal>property-ref</literal> 속성은 오직 foreign key가 프라이머리 키가 아닌 연관된 테이블의 유일 키를 참조하는 
+                                리거시 데이터를 매핑하는데만 사용된다. 이것은 꼴사나운 관계형 모형이다. 예를 들어, <literal>Product</literal> 
+                                클래스가 프라이머리 키를 아닌, 유일한 시리얼 번호를 갖는다고 가정하자.(<literal>unique</literal> 속성은 
+                SchemaExport 도구로 Hibernate의 DDL 생성을 제어한다.)
+            </para>
+            
+            <programlisting><![CDATA[<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>]]></programlisting>
+            
+            <para>
+                                그런 다음 <literal>OrderItem</literal>에 대한 매핑은 다음을 사용할 것이다:
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>]]></programlisting>
+            
+            <para>
+                                하지만 이것은 확실히 권장되지 않는다.
+            </para>
+            
+            <para>
+                                만일 참조된 유일 키가 연관된 엔티티의 여러 프로퍼티들을 포함할 경우, 당신은 명명된 <literal>&lt;properties&gt;</literal> 
+                                요소 내부에 참조된 프로퍼티들을 매핑할 것이다.
+            </para>
+            
+            <para>
+                                만일 참조된 유일키가 컴포넌트의 프로퍼티일 경우, 당신은 하나의 프로퍼티 경로를 지정할 수 있다:
+            </para>
+            
+           <programlisting><![CDATA[<many-to-one name="owner" property-ref="identity.ssn" column="OWNER_SSN"/>]]></programlisting>           
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-onetoone" revision="3">
+            <title>one-to-one</title>
+
+            <para>
+                                또 다른 영속 클래스에 대한 one-to-one 연관관계는 <literal>one-to-one</literal> 요소를 사용하여 선언된다.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="onetoone1" coords="2 70"/>
+                    <area id="onetoone2" coords="3 70"/>
+                    <area id="onetoone3" coords="4 70"/>
+                    <area id="onetoone4" coords="5 70"/>
+                    <area id="onetoone5" coords="6 70"/>
+                    <area id="onetoone6" coords="7 70"/>
+                    <area id="onetoone7" coords="8 70"/>
+                    <area id="onetoone8" coords="9 70"/>
+                    <area id="onetoone9" coords="10 70"/>
+                    <area id="onetoone10" coords="11 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<one-to-one
+        name="propertyName"
+        class="ClassName"
+        cascade="cascade_style"
+        constrained="true|false"
+        fetch="join|select"
+        property-ref="propertyNameFromAssociatedClass"
+        access="field|property|ClassName"
+        formula="any SQL expression"
+        lazy="proxy|no-proxy|false"
+        entity-name="EntityName"
+        node="element-name|@attribute-name|element/@attribute|."
+        embed-xml="true|false"
+        foreign-key="foreign_key_name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="onetoone1">
+                        <para>
+                            <literal>name</literal>: 프로퍼티의 이름.
+                        </para>                
+                    </callout>                   
+                    <callout arearefs="onetoone2">
+                        <para>
+                            <literal>class</literal> (옵션 - 디폴트는 reflection에 의해 결정된 프로퍼티 타입): 
+                                                        연관된 클래스의 이름.
+                        </para>                   
+                    </callout>
+                    <callout arearefs="onetoone3">
+                        <para>
+                            <literal>cascade</literal> (옵션) 어느 오퍼레이션들이 부모 객체로부터 연관된 객체로 
+                                                        케스케이드 될 것인지를 지정한다.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone4">
+                        <para>
+                            <literal>constrained</literal> (옵션) 매핑된 테이블의 프라이머리 키에 대한 foreign 키 
+                                                        컨스트레인트가 연관된 클래스의 테이블을 참조하는지 여부를 지정한다. 이 옵션은  <literal>save()</literal>와 
+                            <literal>delete()</literal>가 케스케이드 되는 순서에 영향을 주고, 그 연관이 프락시 될 것인지 여부를 결정한다
+                            (또한 스키마 내보내기 도구에 의해 사용된다).
+                        </para>                  
+                    </callout>
+                    <callout arearefs="onetoone5">
+                        <para>
+                            <literal>fetch</literal> (옵션 - 디폴트는 <literal>select</literal>): 
+                            outer-join 페칭 또는 순차적인 select 페칭 중에서 선택하라.
+                        </para>              
+                    </callout>
+                    <callout arearefs="onetoone6">
+                        <para>
+                            <literal>property-ref</literal>: (옵션) 이 클래스의 프라이머리 키에 연결된 연관 클래스의 프로퍼티의 이름. 
+                                                        만일 지정되지 않을 경우, 연관 클래스의 프라이머리 키가 사용된다.
+                        </para>                
+                    </callout>                   
+                    <callout arearefs="onetoone7">
+                        <para>
+                            <literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>): 
+                            Hibernate가 프로퍼티 값에 접근 하는데 사용할 방도.
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone8">
+                        <para>
+                            <literal>formula</literal> (옵션): 
+                                                        거의 모든 one to one 연관관계들은 소유하는 엔티티의 프라이머리 키로 매핑된다. 이것이 그 경우가 아닌 드문 경우들에서, 
+                                                        당신은 SQL formula 사용에 결합시킬 몇몇 다른 컬럼, 컬럼들, 또는 표현식을 지정할 수 있다.(예제는 
+                            <literal>org.hibernate.test.onetooneformula</literal>를 보라.)
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone9">
+                        <para>
+                            <literal>lazy</literal> (옵션 - 디폴트는 <literal>proxy</literal>): 
+                                                        디폴트로 한쪽 끝 연관들이 프락시 된다. <literal>lazy="no-proxy"</literal>는 인스턴스 변수가 처음 접근될 때 
+                                                        그 프로퍼티가 lazily 페치될 것임을 지정한다(빌드-시 바이트코드 수단을 필요로 한다).
+                            <literal>lazy="false"</literal>는 그 연관들이 항상 eagerly 페치될 것임을 지정한다. <emphasis>만일 
+                            <literal>constrained="false"</literal>인 경우에, 프락싱은 불가능하고 Hibernate는 그 연관을 eager 페치시킬 것이다!</emphasis>
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone10">
+                        <para>
+                            <literal>entity-name</literal> (옵션): 연관된 클래스의 엔티티 이름.
+                        </para>                   
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+        
+            <para>
+                one-to-one 연관관계에는 두 가지 변종이 존재한다:
+            </para>
+            <itemizedlist>
+            <listitem><para>
+                                프라이머리 키 연관관계들
+            </para></listitem>
+            <listitem><para>
+                                유일 foreign 키 연관관계들
+            </para></listitem>
+            </itemizedlist>
+            
+            <para>
+                                프라이머리 키 연관들은 특별한 테이블 컬럼을 필요로 하지 않는다; 만일 두 개의 행들이 그 연관에 의해  관계지워지면, 
+                                두 개의 테이블 행들은 동일한 프라이머리 키 값을 공유한다. 따라서 만일 두 개의 객체들이 프라이머리 키 연관에 의해 
+                                관계지워지도록 당신이 원할 경우, 당신은 그것들에 동일한 식별자 값이 할당되도록 해야 한다!
+            </para>
+            
+            <para>
+                                프라이머리 키 연관에 대해, 다음 매핑들을 <literal>Employee</literal>와 <literal>Person</literal> 각각에 추가하라.
+            </para>
+
+            <programlisting><![CDATA[<one-to-one name="person" class="Person"/>]]></programlisting>
+            <programlisting><![CDATA[<one-to-one name="employee" class="Employee" constrained="true"/>]]></programlisting>
+
+            <para>
+                                이제 우리는 PERSON 과 EMPLOYEE 테이블들에서 관계지워진 행들의 프라이머리 키들이 동일함을 확실히 해야 한다! 우리는 
+                <literal>foreign</literal>로 명명되는 특별한 Hibernate 식별자 생성 방도를 사용한다:
+            </para>
+
+            <programlisting><![CDATA[<class name="person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="foreign">
+            <param name="property">employee</param>
+        </generator>
+    </id>
+    ...
+    <one-to-one name="employee"
+        class="Employee"
+        constrained="true"/>
+</class>]]></programlisting>
+
+            <para>
+                                그때 <literal>Person</literal>의 새로이 저장된 인스턴스는 그 <literal>Person</literal>의 
+                <literal>employee</literal> 프로퍼티에 대해 참조된 <literal>Employee</literal> 인스턴스와 동일한 
+                                프라이머리 키를 할당받는다.
+            </para>
+
+            <para>
+                                달리, <literal>Employee</literal>로부터 <literal>Person</literal>으로의 유일 컨스트레인트를 가진 
+                                하나의 foreign key는 다음과 같이 표현될 수 있다:
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/>]]></programlisting>
+            
+            <para>
+                                그리고 이 연관은 다음을 <literal>Person</literal> 매핑에 추가함으로써 양방향이 될 수 있다:
+            </para>
+            
+           <programlisting><![CDATA[<one-to-one name"employee" class="Employee" property-ref="person"/>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-naturalid">
+            <title>natural-id</title>
+
+            <programlisting><![CDATA[<natural-id mutable="true|false"/>
+        <property ... />
+        <many-to-one ... />
+        ......
+</natural-id>]]></programlisting>
+
+            <para>
+                                비록 우리가 프라이머리 키들로서 대용키들을 사용하는 것을 권장했을지라도, 당신은 여전히 모든 엔티티들에 대한 natural 
+                                키들을 식별하고자 원할 것이다. narutal 키는 유일(unique)하고 null이 아닌 프로퍼티 또는 프로퍼티들의 조합이다. 
+                                그것이 또한 불변하는 것일 경우가 더 좋다. <literal>&lt;natural-id&gt;</literal> 요소 내부에 있는 natural 키의 
+                                프로퍼티들을 매핑하라. Hibernate는 필수적인 유일 키와 null 허용가능한 컨스트레인트들을 생성시킬 것이고, 당신의 
+                                매핑은 보다 자가 설명적이게 될 것이다.
+            </para>
+            
+            <para>
+                                 우리는 당신이 엔티티에 대한 narutal 키 프로퍼티들을 비교하는데 <literal>equals()</literal>와 
+                 <literal>hashCode()</literal>를 구현할 것을 강력하게 권장한다. 
+            </para>
+
+            <para>
+                                이 매핑은 natural 프라이머리 키들을 가진 엔티티들을 위한 용도로 고안된 것은 아니다.
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>mutable</literal> (옵션, 디폴트는 <literal>false</literal>): 
+                                                디폴트로, narutal 식별자 프로퍼티들은 변경될 수 없는 것(상수)으로 가정된다.
+                    </para>
+                </listitem>
+            </itemizedlist>
+            
+        </sect2>
+        
+        <sect2 id="mapping-declaration-component" revision="2">
+            <title>component, dynamic-component</title>
+
+            <para>
+                <literal>&lt;component&gt;</literal> 요소는 자식 객체의 프로퍼티들을 부모 클래스에 대한 테이블의 컬럼들로 매핑시킨다. 
+                                컴포넌트들은 그것들 자신의 프로퍼티들, 컴포넌트들, 또는 콜렉션들을 선언한다. 이래 "컴포넌트들"을 보라.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="component1" coords="2 45"/>
+                    <area id="component2" coords="3 45"/>
+                    <area id="component3" coords="4 45"/>
+                    <area id="component4" coords="5 45"/>
+                    <area id="component5" coords="6 45"/>
+                    <area id="component6" coords="7 45"/>
+                    <area id="component7" coords="8 45"/>
+                    <area id="component8" coords="9 45"/>
+                </areaspec>            
+                <programlisting><![CDATA[<component 
+        name="propertyName" 
+        class="className"
+        insert="true|false"
+        update="true|false"
+        access="field|property|ClassName"
+        lazy="true|false"
+        optimistic-lock="true|false"
+        unique="true|false"
+        node="element-name|."
+>
+        
+        <property ...../>
+        <many-to-one .... />
+        ........
+</component>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="component1">
+                        <para>
+                            <literal>name</literal>: 프로퍼티의 이름.
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="component2">
+                        <para>
+                            <literal>class</literal> (옵션 - 디폴트는 reflection에 의해 결정된 프로퍼티 타입): 
+                                                        컴포넌트(자식) 클래스의 이름.
+                        </para>                 
+                    </callout>
+                    <callout arearefs="component3">
+                        <para>
+                            <literal>insert</literal>: 매핑된 컬럼들이 SQL <literal>INSERT</literal>들 속에 
+                                                        나타나야 하는가?
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="component4">
+                        <para>
+                            <literal>update</literal>: 매핑된 컬럼들이 SQL <literal>UPDATE</literal>들 속에 
+                                                        나타나야 하는가?
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="component5">
+                        <para>
+                            <literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>): 
+                            Hibernate가 프로퍼티 값에 액세스하는데 사용할 방도.
+                        </para>
+                    </callout>
+                   <callout arearefs="component6">
+                        <para>
+                            <literal>lazy</literal> (옵션 - 디폴트는 <literal>false</literal>): 
+                                                        인스턴스 변수가 처음으로 액세스될 때 이 컴포넌트가 lazily(느리게) 페치되어야 하는지 여부를 지정한다
+                            (빌드 시 바이트코드 수단을 필요로 한다).
+                        </para>
+                    </callout>
+                    <callout arearefs="component7">
+                            <para>
+                                <literal>optimistic-lock</literal> (옵션 - 디폴트는 <literal>true</literal>):
+                                                                이 컴포넌트에 대한 업데이트들이 optimistic 잠금을 획득하는 것을 필요로 하는지 여부를 지정한다. 
+                                                                달리 말해 이 프로퍼티가 dirty 일 때 버전 증가가 발생할 것인지 여부를 결정한다.
+                            </para>
+                    </callout>
+                    <callout arearefs="component8">
+                            <para>
+                                <literal>unique</literal> (옵션 - 디폴트는 <literal>false</literal>):
+                                                                유일 컨스트레인트가 컴포넌트의 모든 매핑된 컬럼들에 대해 존재하는지 여부를 지정한다.
+                            </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                                자식 <literal>&lt;property&gt;</literal> 태그들은 자식 클래스의 프로퍼티들을 테이블 컬럼들로 매핑시킨다.
+            </para>
+
+            <para>
+                <literal>&lt;component&gt;</literal> 요소는 컴포넌트 클래스의 프로퍼티를 포함하는 엔티티에 대한 참조로서 매핑시키는 
+                <literal>&lt;parent&gt;</literal> 서브요소를 허용한다.
+            </para>
+
+            <para>
+                <literal>&lt;dynamic-component&gt;</literal> 요소는 컴포넌트로서 매핑될<literal>Map</literal>을 허용한다. 
+                                여기서 프로퍼티 이름들은 map의 키들을 참조한다. <xref linkend="components-dynamic"/>을 보라.
+            </para>
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-properties" revision="2">
+            <title>properties</title>
+
+            <para>
+                <literal>&lt;properties&gt;</literal> 요소는 클래스의 프로퍼티들의 명명된, 논리적 그룹핑에 대한 정의를 허용한다. 
+                                그 구조에 대한 가장 중요한 사용은 그것이 프로퍼티들의 조합이 <literal>property-ref</literal>의 대상이 되는 것을 
+                                허용해준다는 점이다. 또한 그것은 다중 컬럼 유일 컨스트레인느를 정의하는 편리한 방법이다.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="properties1" coords="2 45"/>
+                    <area id="properties2" coords="3 45"/>
+                    <area id="properties3" coords="4 45"/>
+                    <area id="properties4" coords="5 45"/>
+                    <area id="properties5" coords="6 45"/>
+                </areaspec>            
+                <programlisting><![CDATA[<properties 
+        name="logicalName" 
+        insert="true|false"
+        update="true|false"
+        optimistic-lock="true|false"
+        unique="true|false"
+>
+        
+        <property ...../>
+        <many-to-one .... />
+        ........
+</properties>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="properties1">
+                        <para>
+                            <literal>name</literal>: 그룹핑의 논리적 이름 - 실제 프로퍼티 이름이 <emphasis>아니다</emphasis>.
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="properties2">
+                        <para>
+                            <literal>insert</literal>: 매핑된 컬럼들이 SQL <literal>INSERT</literal>들 내에 나타날 것인가?
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="properties3">
+                        <para>
+                            <literal>update</literal>: 매핑된 컬럼들이 SQL <literal>UPDATE</literal>들 내에 나타날 것인가?
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="properties4">
+                            <para>
+                                <literal>optimistic-lock</literal> (옵션 - 디폴트는 <literal>true</literal>):
+                                                                이들 프로퍼티들에 대한 업데이트들이 optimistic 잠금의 획득을 필요로 하는지 여부를 지정한다. 달리 말해 
+                                                                이 프로퍼티가 dirty 일 때 버전 증가가 발생할 것인지 여부를 결정한다.
+                            </para>
+                    </callout>
+                    <callout arearefs="properties5">
+                            <para>
+                                <literal>unique</literal> (옵션 - 디폴트는 <literal>false</literal>):
+                                                                유일 컨스트레인트가 컴포넌트의 모든 매핑된 컬럼들에 대해 존재하는지 여부를 지정한다.
+                            </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                                예를 들어, 만일 우리가 다음 <literal>&lt;properties&gt;</literal> 매핑을 가질 경우:
+            </para>
+            
+            <programlisting><![CDATA[<class name="Person">
+    <id name="personNumber"/>
+    ...
+    <properties name="name" 
+            unique="true" update="false">
+        <property name="firstName"/>
+        <property name="initial"/>
+        <property name="lastName"/>
+    </properties>
+</class>]]></programlisting>
+
+            <para>
+                                그 때 우리는 프라이머리 키가 아닌, <literal>Person</literal> 테이블의 이 유일 키를 참조하는 어떤 리거시 데이터 연관을 
+                                가질 수 있다:
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="person" 
+         class="Person" property-ref="name">
+    <column name="firstName"/>
+    <column name="initial"/>
+    <column name="lastName"/>
+</many-to-one>]]></programlisting>
+            
+            <para>
+                                우리는 리거시 데이터를 매핑시키는 컨텍스트 바깥에서 이런 종류의 것을 사용하는 것을 권장하지 않는다.
+            </para>
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-subclass" revision="4">
+            <title>subclass</title>
+
+            <para>
+                                마지막으로, 다형성 영속성은 루트 영속 클래스에 대한 각각의 서브클래스 선언을 필요로 한다.(권장되는) 
+                table-per-class-hierarchy(테이블 당 클래스  계층구조) 매핑 방도의 경우, <literal>&lt;subclass&gt;</literal> 
+                                선언이 사용된다.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="subclass1" coords="2 55"/>
+                    <area id="subclass2" coords="3 55"/>
+                    <area id="subclass3" coords="4 55"/>
+                    <area id="subclass4" coords="5 55"/>
+                </areaspec>
+                <programlisting><![CDATA[<subclass
+        name="ClassName"
+        discriminator-value="discriminator_value"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        entity-name="EntityName"
+        node="element-name"
+        extends="SuperclassName">
+
+        <property .... />
+        .....
+</subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="subclass1">
+                        <para>
+                            <literal>name</literal>: 서브클래스의 전체 수식어가 붙은 클래스 이름.
+                        </para>              
+                    </callout>                   
+                    <callout arearefs="subclass2">
+                        <para>
+                            <literal>discriminator-value</literal> (옵션 - 디폴트는 클래스 이름): 
+                                                        개개의 서브클래스들을 구분짓는 값.
+                        </para>               
+                    </callout>
+                    <callout arearefs="subclass3">
+                        <para>
+                            <literal>proxy</literal> (옵션): lazy 초기화 프락시들을 사용하는데 클래스 또는 인터페이스를 지정한다.
+                        </para>               
+                    </callout>
+                    <callout arearefs="subclass4">
+                        <para>
+                            <literal>lazy</literal> (옵션 - 디폴트는 <literal>true</literal>): 
+                            <literal>lazy="false"</literal> 설정은 lazy 페칭의 사용을 불가능하게 만든다.
+                        </para>
+                    </callout>    
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                                각각의 서브클래스는 그것 자신의 영속 프로퍼티들과 서브클래스들을 선언할 것이다. <literal>&lt;version&gt;</literal> 
+                                프로퍼티와 <literal>&lt;id&gt;</literal> 프로퍼티는 루트 클래스로부터 상속된다고 가정된다. 계층구조 내에서 각각의 
+                                서브클래스는 유일한 <literal>discriminator-value</literal>를 정의해야 한다. none이 지정될 경우, 전체 수식어가 
+                                붙은 자바 클래스 이름이 사용된다.
+            </para>
+            
+            <para>
+                                상속 매핑들에 대한 정보는 <xref linkend="inheritance"/>을 보라.
+            </para>
+
+        </sect2>
+
+         <sect2 id="mapping-declaration-joinedsubclass" revision="3">
+            <title>joined-subclass</title>
+
+            <para>
+                                다른 방법으로 각각의 서브클래스는 그것 자신이 테이블로 매핑될 수 있다(table-per-subclass 매핑 방도). 상속된 상태는 
+                                슈퍼클래스의 테이블과 조인함으로써 검색된다. 우리는 <literal>&lt;joined-subclass&gt;</literal> 요소를 사용한다.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="joinedsubclass1" coords="2 45"/>
+                    <area id="joinedsubclass2" coords="3 45"/>
+                    <area id="joinedsubclass3" coords="4 45"/>
+                    <area id="joinedsubclass4" coords="5 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<joined-subclass
+        name="ClassName"
+        table="tablename"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        schema="schema"
+        catalog="catalog"
+        extends="SuperclassName"
+        persister="ClassName"
+        subselect="SQL expression"
+        entity-name="EntityName"
+        node="element-name">
+
+        <key .... >
+
+        <property .... />
+        .....
+</joined-subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="joinedsubclass1">
+                        <para>
+                            <literal>name</literal>: 서브클래스의 전체 수식어가 붙은 클래스 명.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="joinedsubclass2">
+                        <para>
+                            <literal>table</literal>: 서브클래스 테이블의 이름.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="joinedsubclass3">
+                        <para>
+                            <literal>proxy</literal> (옵션): 프락시들을 lazy 초기화 시키는데 사용할 클래스 또는 인터페이스를 지정한다.
+                        </para>              
+                    </callout>
+                    <callout arearefs="joinedsubclass4">
+                        <para>
+                             <literal>lazy</literal> (옵션 - 디폴트는 <literal>true</literal>): 
+                             <literal>lazy="false"</literal> 설정은 lazy 페칭을 사용불가능하게 만든다
+                         </para>
+                    </callout>    
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                                판별자(discriminator) 컬럼은 이 매핑 방도에 필요하지 않다. 하지만 각각의 서브클래스는 <literal>&lt;key&gt;</literal> 요소를 
+                                사용하여 객체 식별자를 보관하는 테이블 컬럼을 선언해야 한다. 이 장의 시작 부분에 있는 매핑은 다음과 같이 다시 작성될 것이다:
+            </para>
+            
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+        <class name="Cat" table="CATS">
+                <id name="id" column="uid" type="long">
+                        <generator class="hilo"/>
+                </id>
+                <property name="birthdate" type="date"/>
+                <property name="color" not-null="true"/>
+                <property name="sex" not-null="true"/>
+                <property name="weight"/>
+                <many-to-one name="mate"/>
+                <set name="kittens">
+                        <key column="MOTHER"/>
+                        <one-to-many class="Cat"/>
+                </set>
+                <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
+                    <key column="CAT"/>
+                    <property name="name" type="string"/>
+                </joined-subclass>
+        </class>
+
+        <class name="eg.Dog">
+                <!-- mapping for Dog could go here -->
+        </class>
+
+</hibernate-mapping>]]></programlisting>
+
+             <para>
+                                  상속 매핑들에 대한 정보는 <xref linkend="inheritance"/>을 보라.
+             </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-unionsubclass" revision="2">
+           <title>union-subclass</title>
+
+           <para>
+                              제3의 옵션은 상속 계층구조의 concrete 클래스들 만을 테이블들로 매핑하는 것이다 (table-per-concrete-class 방도). 여기서 
+                              각각의 테이블은 상속된 상태를 포함하여 클래스의 모든 영속 상태를 정의한다. Hibernate에서, 그것은 그런 상속 계층구조들을 
+                              명시적으로 매핑하는데 필수적이지 않다. 당신은 별도의 <literal>&lt;class&gt;</literal> 선언을 가진 각각의 클래스를 
+                              간단히 매핑시킬 수 있다. 하지만 당신이 다형성 연관관계들(예를 들면 당신의 계층구조의 슈퍼클래스에 대한 연관)을 사용하고자 원할 
+                              경우, 당신은 <literal>&lt;union-subclass&gt;</literal> 매핑을 사용할 필요가 있다.
+           </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="unionsubclass1" coords="2 45"/>
+                    <area id="unionsubclass2" coords="3 45"/>
+                    <area id="unionsubclass3" coords="4 45"/>
+                    <area id="unionsubclass4" coords="5 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<union-subclass
+        name="ClassName"
+        table="tablename"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        schema="schema"
+        catalog="catalog"
+        extends="SuperclassName"
+        abstract="true|false"
+        persister="ClassName"
+        subselect="SQL expression"
+        entity-name="EntityName"
+        node="element-name">
+
+        <property .... />
+        .....
+</union-subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="unionsubclass1">
+                        <para>
+                            <literal>name</literal>: 서브클래스의 전체 수식어가 붙은 클래스 명.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="unionsubclass2">
+                        <para>
+                            <literal>table</literal>: 서브클래스 테이블의 이름.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="unionsubclass3">
+                        <para>
+                            <literal>proxy</literal> (옵션): 프락시들을 lazy 초기화 시키는데 사용할 클래스 또는 인터페이스를 지정한다.
+                        </para>              
+                    </callout>
+                    <callout arearefs="unionsubclass4">
+                        <para>
+                            <literal>lazy</literal> (옵션 - 디폴트는 <literal>true</literal>): 
+                            <literal>lazy="false"</literal> 설정은 lazy 페칭을 사용불가능하게 만든다.
+                         </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                                이 매핑 방도에는 판별자 컬럼이나 키 컬럼이 필요하지 않다.
+            </para>
+
+            <para>
+                                상속 매핑들에 대한 정보는 <xref linkend="inheritance"/>을 보라.
+            </para>
+
+        </sect2>
+
+    <sect2 id="mapping-declaration-join" revision="3">
+            <title>join</title>
+
+            <para>
+                <literal>&lt;join&gt;</literal>요소를 사용하면,  테이블들 사이에 1대일 관계가 존재할 때, 
+                                하나의 클래스에 속한 프로퍼티들을 여러 테이블들로 매핑시키는 것이 
+                                가능하다.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="join1" coords="2 50"/>
+                    <area id="join2" coords="3 50"/>
+                    <area id="join3" coords="4 50"/>
+                    <area id="join4" coords="5 50"/>
+                    <area id="join5" coords="6 50"/>
+                    <area id="join6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<join
+        table="tablename"
+        schema="owner"
+        catalog="catalog"
+        fetch="join|select"
+        inverse="true|false"
+        optional="true|false">
+        
+        <key ... />
+        
+        <property ... />
+        ...
+</join>]]></programlisting>
+
+                <calloutlist>
+                    <callout arearefs="join1">
+                        <para>
+                            <literal>table</literal>: 조인된 테이블의 이름.
+                        </para>
+                    </callout>
+                    <callout arearefs="join2">
+                        <para>
+                            <literal>schema</literal> (옵션): 루트 <literal>&lt;hibernate-mapping&gt;</literal> 요소에 
+                                                        의해 지정된 스키마 이름을 오버라이드 시킨다
+                        </para>
+                    </callout>
+                    <callout arearefs="join3">
+                        <para>
+                            <literal>catalog</literal> (옵션): 루트 <literal>&lt;hibernate-mapping&gt;</literal> 요소에 
+                                                        의해 지정된 카타록 이름을 오버라이드 시킨다.
+                        </para>
+                    </callout>
+                    <callout arearefs="join4">
+                        <para>
+                            <literal>fetch</literal> (옵션 - 디폴트는 <literal>join</literal>):
+                            <literal>join</literal>으로 설정될 경우, 디폴트로 Hibernate는 하나의 클래스 또는 그것의 슈퍼 클래스들에 의해 
+                                                        정의된 <literal>&lt;join&gt;</literal>을 검색하는데 inner join을 사용하고 서브클래스에 의해 정의된 
+                            <literal>&lt;join&gt;</literal>을 검색하는데 outer join을 사용할 것이다. 만일 <literal>select</literal>로 
+                                                        설정할 경우, Hibernate는 서브클래스 상에 정의된 <literal>&lt;join&gt;</literal>에 대해 sequential 
+                            select를 사용할 것이고, 그것은 한 행이 서브클래스의 인스턴스를 표현하는 것으로 판명되는 경우에만 명령이 내려질 것이다. 
+                            inner join들은 여전히 클래스와 그것의 슈퍼클래스들에 의해 정의된 <literal>&lt;join&gt;</literal>을 검색하는데 
+                                                        사용될 것이다.
+                        </para>
+                    </callout>
+                    <callout arearefs="join5">
+                        <para>
+                            <literal>inverse</literal> (옵션 - 디폴트는 <literal>false</literal>):
+                                                        이용 가능할 경우, Hibernate는 이 조인에 의해 정의된 프로퍼티들을 삽입시키거나 업데이트하려고 시도하지 
+                                                        않을 것이다.
+                        </para>
+                    </callout>
+                    <callout arearefs="join6">
+                        <para>
+                            <literal>optional</literal> (옵션 - 디폴트는 <literal>false</literal>):
+                                                        이용 가능할 경우, Hibernate는 이 조인에 의해 정의된 프로퍼티들이 null이 아닐 경우에만 한 행을 삽입시킬 것이고 
+                                                        그 프로퍼티들을 검색하는데 outer join을 항상 사용할 것이다.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                                예를 들어, (모든 프로퍼티들에 대해 value 타입 의미를 유지하면서) 개인의 주소 정보는 별도의 테이블에 매핑될 수 있다: 
+            </para>
+
+            <programlisting><![CDATA[<class name="Person"
+    table="PERSON">
+
+    <id name="id" column="PERSON_ID">...</id>
+
+    <join table="ADDRESS">
+        <key column="ADDRESS_ID"/>
+        <property name="address"/>
+        <property name="zip"/>
+        <property name="country"/>
+    </join>
+    ...]]></programlisting>
+
+            <para>
+                                이 특징은 자주 리거시 데이터 모형들에 대해서만 유용하고, 우리는 클래스들과 잘 정제된 도메인 모형 보다 더 적은 테이블들을 
+                                권장한다. 하지만 뒷 부분에 설명되어 있듯이, 그것은 하나의 계층구조 내에 있는 상속 매핑 방도들 사이를 전환하는 것에 유용하다. 
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-key">
+            <title>key</title>
+
+            <para>
+                                우리는 지금까지 몇 번 나타났던 <literal>&lt;key&gt;</literal> 요소를 보았다. 그것은 부모 매핑 요소가 새로운 테이블에 
+                                대한 조인을 정의하는 어느 곳에서나 나타나고, 그것은 조인된 테이블의 foreign 키를 정의하고, 그것은 원래의 테이블의 
+                                프라이머리 키를 참조한다.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="key1" coords="2 50"/>
+                    <area id="key2" coords="3 50"/>
+                    <area id="key3" coords="4 50"/>
+                    <area id="key4" coords="5 50"/>
+                    <area id="key5" coords="6 50"/>
+                    <area id="key6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<key
+        column="columnname"
+        on-delete="noaction|cascade"
+        property-ref="propertyName"
+        not-null="true|false"
+        update="true|false"
+        unique="true|false"
+/>]]></programlisting>
+
+                <calloutlist>
+                    <callout arearefs="key1">
+                        <para>
+                            <literal>column</literal> (옵션): 
+                            foreign key 컬럼의 이름. 이것은 또한 내포된 <literal>&lt;column&gt;</literal> 요소(들)에 의해 지정될 수 있다.
+                        </para>
+                    </callout>
+                    <callout arearefs="key2">
+                        <para>
+                            <literal>on-delete</literal> (옵션 - 디폴트는 <literal>noaction</literal>): 
+                            foreign key 컨스트레인트가 데이터베이스 레벨의 cascade delete를 사용가능하도록 할 것인지 여부를 지정한다.
+                        </para>
+                    </callout>
+                    <callout arearefs="key3">
+                        <para>
+                            <literal>property-ref</literal> (옵션): 
+                            foreign key가 원래의 테이블의 프라이머리 키가 아닌 컬럼들을 참조함을 지정한다. (리거시 데이터에 제공됨.)
+                        </para>
+                    </callout>
+                    <callout arearefs="key4">
+                        <para>
+                            <literal>not-null</literal> (옵션): 
+                            foreign 키 컬럼들이 not null 임를 지정한다(이것은 foreign 키가 또한 프라이머리 키의 부분일 때마다 함축된다). 
+                        </para>
+                    </callout>
+                    <callout arearefs="key5">
+                        <para>
+                            <literal>update</literal> (옵션): 
+                            foreign 키가 결코 업데이트되지 않아야 함을 지정한다(이것은 foreign 키가 또한 프라이머리 키의 부분일 때마다 
+                                                        함축된다).
+                        </para>
+                    </callout>
+                    <callout arearefs="key6">
+                        <para>
+                            <literal>unique</literal> (옵션): 
+                            foreign 키가 유일 컨스트레인트를 가져야 함을 지정한다 (이것은 foreign 키가 또한 프라이머리 키의 부분일 
+                                                        때마다 함축된다).
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                                우리는 delete 퍼포먼스가 중요한 시스템들에 대해 권장하고, 모든 키들은 <literal>on-delete="cascade"</literal>로 
+                                정의되고, Hibernate는 많은 <literal>DELETE</literal> 문장들 대신에, 데이터베이스 레벨의 
+                <literal>ON CASCADE DELETE</literal> 컨스트레인트를 사용할 것이다. 이 특징은 Hibernate의 통상적인 버전화된 
+                                데이터에 대한 optimistic 잠금 방도를 무시한다는 점을 알고 있어라.
+            </para>
+            
+            <para>
+                <literal>not-null</literal> 속성과 <literal>update</literal> 속성들은 단방향 one to many 연관관계를 매핑할 때 
+                                유용하다. 만일 당신이 단방향 one to many를 null이 허용되지 않는 foreign 키로 매핑할 경우, 당신은 
+                <literal>&lt;key not-null="true"&gt;</literal>를 사용하여 그 키 컬럼을 선언<emphasis>해야 한다</emphasis>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-column" revision="4">
+           <title>column 요소와 formula 요소</title>
+           <para>
+               column 속성을 허용하는 임의의 매핑 요소는 대안적으로 하나의 <literal>&lt;column&gt;</literal> 서브요소를 수용할 것이다. 
+                              비슷하게 <literal>&lt;formula&gt;</literal>는 <literal>formula</literal> 속성에 대한  대안이다.
+           </para>
+
+           <programlisting><![CDATA[<column
+        name="column_name"
+        length="N"
+        precision="N"
+        scale="N"
+        not-null="true|false"
+        unique="true|false"
+        unique-key="multicolumn_unique_key_name"
+        index="index_name"
+        sql-type="sql_type_name"
+        check="SQL expression"
+        default="SQL expression"/>]]></programlisting>
+
+            <programlisting><![CDATA[<formula>SQL expression</formula>]]></programlisting>
+        
+            <para>
+                <literal>column</literal> 속성과 <literal>formula</literal> 속성은 예를 들어 신종 조인 조건들을 표현하기 위해 
+                                동일한 property 또는 연관관계 매핑 내에 결합될 수 있다.
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="homeAddress" class="Address"
+        insert="false" update="false">
+    <column name="person_id" not-null="true" length="10"/>
+    <formula>'MAILING'</formula>
+</many-to-one>]]></programlisting>
+
+    </sect2>  
+    
+        <sect2 id="mapping-declaration-import">
+            <title>import</title>
+
+            <para>
+                                당신의 어플리케이션이 동일한 이름을 가진 두 개의 영속 클래스들을 갖고, 당신이 Hibernate 질의들 내에서 전체 수식어가 붙은 
+                (패키지)이름을 지정하는 것을 원하지 않는다고 가정하자. 클래스들은 <literal>auto-import="true"</literal>에 의존하기 
+                                보다 명시적으로 "임포트 될 " 것이다. 당신은 심지어 명시적으로 매핑되지 않는 클래스들과 인터페이스들을 임포트 시킬 수(가져오기 할 수) 
+                                있다.
+            </para>
+            
+            <programlisting><![CDATA[<import class="java.lang.Object" rename="Universe"/>]]></programlisting>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="import1" coords="2 40"/>
+                    <area id="import2" coords="3 40"/>
+                </areaspec>
+                <programlisting><![CDATA[<import
+        class="ClassName"
+        rename="ShortName"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="import1">
+                        <para>
+                            <literal>class</literal>: 임의의 Java 클래스의 전체 수식어가 붙은 클래스 이름.
+                        </para>              
+                    </callout>                   
+                    <callout arearefs="import2">
+                        <para>
+                            <literal>rename</literal> (옵션 - 디폴트는 수식어가 붙지 않은 클래스 이름):
+                                                        질의 언어 내에서 사용될 이름.
+                        </para>               
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+        </sect2>
+
+        <sect2 id="mapping-types-anymapping" revision="2">
+            <title>any</title>
+            
+            <para>
+                                하나 이상의 프로퍼티 매핑 타입이 존재한다. <literal>&lt;any&gt;</literal> 매핑 요소는 여러 테이블들로부터 클래스들에 
+                                대한 하나의 다형성 연관관계를 정의한다. 이 매핑 타입은 언제나 하나 이상의 컬럼을 필요로 한다. 첫 번째 컬럼은 연관된 엔티티의 
+                                타입을 보관한다. 나머지 컬럼들은 식별자를 보관한다. 이런 종류의 연관관계들에 대해 foreign key 컨스트레인트를 지정하는 것이 
+                                불가능해서, 이것은 (다형성) 연관관계들을 매핑하는 통상적인 방법으로서 가장 확실한 수단이 아니다. 당신은 매우 특별한 경우들
+                (예를 들어 감사 로그들, 사용자 세션 데이터 등)에서만 이것을 사용해야 한다. 
+            </para>
+
+            <para>
+                 <literal>meta-type</literal> 속성은 어플리케이션으로 하여금 데이터베이스 컬럼 값들을 <literal>id-type</literal>에 
+                                  의해 지정된 타입의 식별자 프로퍼티들을 가진 영속 클래스들로 매핑시키는 맞춤형 타입을 지정하도록 한다. 당신은 meta-type의 
+                                  값들로부터 클래스 이름들로의 매핑을 지정해야 한다.
+            </para>
+
+            <programlisting><![CDATA[<any name="being" id-type="long" meta-type="string">
+    <meta-value value="TBL_ANIMAL" class="Animal"/>
+    <meta-value value="TBL_HUMAN" class="Human"/>
+    <meta-value value="TBL_ALIEN" class="Alien"/>
+    <column name="table_name"/>
+    <column name="id"/>
+</any>]]></programlisting>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="any1" coords="2 50"/>
+                    <area id="any2" coords="3 50"/>
+                    <area id="any3" coords="4 50"/>
+                    <area id="any4" coords="5 50"/>
+                    <area id="any5" coords="6 50"/>
+                    <area id="any6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<any
+        name="propertyName"
+        id-type="idtypename"
+        meta-type="metatypename"
+        cascade="cascade_style"
+        access="field|property|ClassName"
+        optimistic-lock="true|false"
+>
+        <meta-value ... />
+        <meta-value ... />
+        .....
+        <column .... />
+        <column .... />
+        .....
+</any>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="any1">
+                        <para>
+                            <literal>name</literal>: 프로퍼티 이름.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any2">
+                        <para>
+                            <literal>id-type</literal>: 식별자 타입.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any3">
+                        <para>
+                            <literal>meta-type</literal> (옵션 - 디폴트는 <literal>string</literal>): 
+                            discriminator 매핑에 허용되는 임의의 타입.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any4">
+                        <para>
+                            <literal>cascade</literal> (optional- defaults to <literal>none</literal>): 
+                            cascade 스타일.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any5">
+                        <para>
+                            <literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>): 
+                            Hibernate가 프로퍼티 값에 접근하는데 사용할 방도.
+                        </para>
+                    </callout>
+                    <callout arearefs="any6">
+                        <para>
+                            <literal>optimistic-lock</literal> (옵션 - 디폴트는 <literal>true</literal>): 
+                                                        이 프로퍼티에 대한 업데이트들이 optimistic 잠금 획득을 필요로 하는지 여부를 지정한다. 달리 말해, 
+                                                        이 프로퍼티가 dirty일 경우에 버전증가가 발생할 것인지 여부를 정의한다.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+      </sect2>
+
+    </sect1>
+
+    <sect1 id="mapping-types">
+        <title>Hibernate 타입들</title>
+
+        <sect2 id="mapping-types-entitiesvalues" revision="1">
+            <title>엔티티들과 값들</title>
+
+            <para>
+                                영속 서비스에 관한 여러 Java 언어-레벨의 객체들을 이해하기 위해, 우리는 그것들을 다음 두 개의 그룹들로 분류할 필요가 있다:
+            </para>
+
+            <para>
+                <emphasis>entity</emphasis>는 엔티티에 대한 참조들을 보관하는 임의의 다른 객체들과는 독립적으로 존재한다. 참조되지 않은 
+                                객체가 쓰레기 수집되는 통상의 자바 모형과 이것은 대조적이다. (저장들과 삭제들이 부모 엔티티로부터 그것의 자식으로의 케스케이드 
+                                되는 경우를 제외하면) 엔티티들은 명시적으로 저장되고 삭제되어야 한다. 이것은 도달 가능성(reachablity)에 의한 객체 영속성의 
+                ODMG 모형과는 다르다 - 그리고 어플리케이션 객체들이 대형 시스템들에서 대개 어떻게 사용되는가에 훨씬 더 가깝게 대응한다. 
+                                엔티티들은 순환 참조와 공유 참조들을 지원한다. 그것들 또한 버전화 될 수 있다.
+            </para>
+
+            <para>
+                                엔티티의 영속 상태는 다른 엔티티들에 대한 참조들과 <emphasis>value</emphasis> 타입들로 구성된다. 값들은 원시 타입들, 
+                                콜렉션들(하나의 콜렉션 내부에 있지 않는 것들), 컴포넌트들, 그리고 어떤 불변의 객체들이다. entities와는 달리, (특별한 
+                                콜렉션들과 컴포넌트들에서) 값들은 도달가능성(reachability)에 의해 영속화 <emphasis>되고</emphasis> 삭제 된다. 
+                value 객체들(과 원시 타입들)이 그것들의 포함하는 엔티티에 따라 영속화 되고 삭제 되므로, 그것들은 독립적으로 버전화 되지 
+                                않는다. 값들은 독립적인 엔티티를 갖지 않아서, 그것들은 두 개의 엔티티들이나 콜렉션들에 의해 공유될 수 없다. 
+            </para>
+
+            <para>
+                                지금까지 우리는 엔티티들을 참조하기 위해 "영속 클래스"를 사용해 왔다. 우리는 그것을 계속 사용할 것이다. 하지만 엄격히 말해, 
+                                영속 상태를 가진 모든 사용자 정의 클래스들은 엔티티들이 아니다. <emphasis>컴포넌트</emphasis>는 value 의미를 가진 
+                                사용자 정의 클래스이다. <literal>java.lang.String</literal> 타입의 자바 프로퍼티는 또한 value 의미를 갖는다. 
+                                이 정의가 주어지면, 우리는 JDK에 의해 제공된 모든 타입들(클래스들)이 자바에서 value 타입 의미를 갖고, 반면에 사용자 정의 
+                                타입들은 엔티티 또는 type 의미로서 매핑된다고 말할 수 있다. 이 판단은 어플리케이션 개발자에게 달려 있다. 도메인 모형에서 
+                                엔티티 클래스에 대한 좋은 힌트는 그 클래스의 하나의 인스턴스에 대한 공유된 참조들인 반면에, composition이나 aggregation은 
+                                대개 value 타입으로 변환된다.
+            </para>
+
+            <para>
+                                우리는 문서를 통해 두 개념들을 다시 고찰할 것이다.
+            </para>
+
+            <para>
+                                도점점은 Java type 시스템(과 엔티티들 및 value 타입들에 대한 개발자의 정의)를 SQL/데이터베이스 type 타입으로 매핑하는 
+                                것이다. 두 시스템들 사이의 다리는 Hibernate에 의해 제공된다: 엔티티들의 경우 우리는 <literal>&lt;class&gt;</literal>, 
+                <literal>&lt;subclass&gt;</literal> 등을 사용한다.value 타입들의 경우 우리는 대개<literal>type</literal> 속성을 가진 
+                <literal>&lt;property&gt;</literal>, <literal>&lt;component&gt;</literal> 등을 사용한다. 이 속성의 값은 
+                Hibernate <emphasis>매핑 타입</emphasis>의 이름이다. Hibernate는 (표준 JDK value 타입들에 대해) 많은 매핑들을 
+                                제공한다. 나중에 보게 되듯이, 당신은 당신 자신의 매핑 타입들을 작성할 수 있고 마찬가지로 당신의 맞춤형 변환 방도들을 구현할 수 
+                                있다.
+            </para>
+
+            <para>
+                                콜렉션들을 제외한 모든 미리 빌드된 Hibernate 타입들은 null 의미를 지원한다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-types-basictypes" revision="3">
+            <title>기본 value 타입들</title>
+
+            <para>
+                                미리-만들어진 <emphasis>기본 매핑 타입들</emphasis>은 대략 다음과 같이 카테고리로 분류된다
+
+                <variablelist>
+                    <varlistentry>
+                        <term><literal>integer, long, short, float, double, character, byte,
+                            boolean, yes_no, true_false</literal></term>
+                        <listitem>
+                            <para>
+                                                                자바 원시타입들이나 wrapper 클래스들로부터 적절한(벤더-지정적인) SQL 컬럼 타입들로의 타입 매핑. 
+                                <literal>boolean, yes_no</literal>와 <literal>true_false</literal>는 
+                                Java <literal>boolean</literal>이나  <literal>java.lang.Boolean</literal>에 대한 
+                                                                모든 대체적인 인코딩들이다.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>string</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>java.lang.String</literal>으로부터 <literal>VARCHAR</literal>
+                                (또는 Oracle <literal>VARCHAR2</literal>)로의 타입 매핑.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>date, time, timestamp</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>java.util.Date</literal>와 그것의 서브클래스로부터 SQL 타입들인 
+                                <literal>DATE</literal>, <literal>TIME</literal>, <literal>TIMESTAMP</literal>
+                                (또는 등가물)로의 타입 매핑들.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>calendar, calendar_date</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>java.util.Calendar</literal>로부터 SQL 타입들인 
+                                <literal>TIMESTAMP</literal>, <literal>DATE</literal> (또는 등가물)로의 타입 매핑들.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>big_decimal, big_integer</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>java.math.BigDecimal</literal>과 <literal>java.math.BigInteger</literal>로부터 
+                                <literal>NUMERIC</literal> (또는 Oracle <literal>NUMBER</literal>)로의 타입 매핑들.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>locale, timezone, currency</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>java.util.Locale</literal>, <literal>java.util.TimeZone</literal>, 그리고 
+                                <literal>java.util.Currency</literal>로부터 <literal>VARCHAR</literal>(또는 Oracle 
+                                <literal>VARCHAR2</literal>)로의 타입 매핑. <literal>Locale</literal>과 <literal>Currency</literal>의 
+                                                                인스턴스들은 그것들의 ISO 코드들로 매핑된다. <literal>TimeZone</literal>의 인스턴스들은 그것들의 
+                                <literal>ID</literal>로 매핑된다. 
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>class</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>java.lang.Class</literal>로부터 <literal>VARCHAR</literal> (또는 Oracle 
+                                <literal>VARCHAR2</literal>)로의 타입 매핑. <literal>Class</literal>는 그것의 전체 
+                                                                수식어가 붙은 이름으로 매핑된다.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>binary</literal></term>
+                        <listitem>
+                            <para>
+                                byte 배열들을 적절한 SQL binary 타입으로 매핑시킨다.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>text</literal></term>
+                        <listitem>
+                            <para>
+                                long Java 문자열을 SQL <literal>CLOB</literal> 또는 <literal>TEXT</literal> 타입으로 
+                                                                매핑시킨다
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>serializable</literal></term>
+                        <listitem>
+                            <para>
+                                serializable Java 타입들을 적절한  SQL binary 타입으로 매핑시킨다. 당신은 또한 디폴트로 기본 타입이 
+                                                                아닌 serializable 자바 클래스 또는 인터페이스의 이름을 가진 Hibernate 타입 <literal>serializable</literal>을 
+                                                                나타낼 수도 있다.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>clob, blob</literal></term>
+                        <listitem>
+                            <para>
+                                <literal>java.sql.Clob</literal>와 <literal>java.sql.Blob</literal> JDBC 클래스들에 대한 타입 매핑들. 
+                                                                이들 타입들은 몇몇 어플리케이션들에서는 불편하다. 왜냐하면 blob 또는 clob 객체는 트랜잭션 외부에서 재사용될 수 없기
+                                                                 때문이다.(게다가 드라이버 지원이 비일관적이고 페치되어야 한다)
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date,
+                            imm_serializable, imm_binary</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                                                대개 가변적인 Java 타입들로 간주되는 것에 대한 타입 매핑들. 여기서 Hibernate는 불변적인 Java 타입들에 대해서만 적절한 
+                                                                어떤 최적화를 행하고, 어플리케이션 그 객체를 변할 수 없는 것으로 취급한다. 예를 들어, 당신은 <literal>imm_timestamp</literal>로서 
+                                                                매핑된 인스턴스에 대해 <literal>Date.setTime()</literal>을 호출하지 않을 것이다. 프로퍼티의 값을 변경시키고, 
+                                                                그 변경을 영속화 시키기 위해서, 어플리케이션은 하나의 새로운 (동일하지 않은) 객체를 그 프로퍼티에 할당해야 한다.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                </variablelist>
+            
+            </para>
+
+            <para>
+                                엔트리들과 콜렉션들의 유일 식별자들은 <literal>binary</literal>, <literal>blob</literal> 그리고 <literal>clob</literal>를 
+                                제외한 기본 타입 중 어느 것일 수 있다. (Composite 식별자들이 또한 허용된다. 아래를 보라.)
+            </para>
+            
+            <para>
+                                기본 value 타입들은 <literal>org.hibernate.Hibernate</literal>에 정의되어 있는 대응하는 
+                <literal>Type</literal> 상수들을 갖는다. 예를 들어, <literal>Hibernate.STRING</literal>은 
+                <literal>string</literal> 타입을 표현한다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-types-custom" revision="2">
+            <title>맞춤형 value 타입들</title>
+
+            <para>
+                                개발자들이 그들 자신들의 value 타입들을 생성시키는 것이 상대적으로 쉽다. 예를 들어, 당신은 
+                <literal>java.lang.BigInteger</literal> 타입의 프로퍼티들을 <literal>VARCHAR</literal> 컬럼들로 
+                                영속화 시키고자 원할 수 있다. Hibernate는 이것을 위한 미리 만들어진 타입을 제공하지 않는다. 그러나 맞춤형 타입들은 
+                                프로퍼티(또는 콜렉션 요소)를 하나의 테이블 컬럼으로의 매핑하는 것에 제약되지 않는다. 따라서 예를 들어, 당신은 
+                <literal>FIRST_NAME</literal>, <literal>INITIAL</literal>, <literal>SURNAME</literal> 컬럼들로 
+                                영속화 되는 <literal>java.lang.String</literal> 타입의 자바 프로퍼티<literal>getName()</literal>/
+                <literal>setName()</literal>를 가질 수 있다. 
+            </para>
+            
+            <para>
+                                맞춤형 타입을 구현하려면, <literal>org.hibernate.UserType</literal> 또는 <literal>org.hibernate.CompositeUserType</literal>을 
+                                구현하고 그 타입의 전체 수식어가 붙은 클래스명을 사용하여 프로퍼티들을 선언하라. 가능한 종류의 것들을 보려면 
+                <literal>org.hibernate.test.DoubleStringType</literal>을 체크하라.
+            </para>
+
+            <programlisting><![CDATA[<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
+    <column name="first_string"/>
+    <column name="second_string"/>
+</property>]]></programlisting>
+
+            <para>
+                                하나의 프로퍼티를 여러 개의 컬럼들로 매핑시키는 <literal>&lt;column&gt;</literal> 태그의 사용을 주목하라.
+            </para>
+            
+            <para>
+                <literal>CompositeUserType</literal>, <literal>EnhancedUserType</literal>, 
+                <literal>UserCollectionType</literal>, 그리고 <literal>UserVersionType</literal> 인터페이스들은 
+                                더 많은 특화된 사용들을 위한 지원을 제공한다.
+            </para>
+            
+            <para>
+                                당신은 매핑 파일 속에 <literal>UserType</literal>에 대한 파라미터들을 제공할 수도 있다. 이것을 행하기 위해, 
+                                당신의 <literal>UserType</literal>은 <literal>org.hibernate.usertype.ParameterizedType</literal> 
+                                인터페이스를 구현해야 한다. 당신의 맞춤형 타입에 파라미터들을 제공하기 위해, 당신은 당신의 매핑 파일들 속에 
+                <literal>&lt;type&gt;</literal> 요소를 사용할 수 있다.
+            </para>
+            
+            <programlisting><![CDATA[<property name="priority">
+    <type name="com.mycompany.usertypes.DefaultValueIntegerType">
+        <param name="default">0</param>
+    </type>
+</property>]]></programlisting>
+
+            <para>
+                <literal>UserType</literal>은 이제 그것에 전달된 <literal>Properties</literal> 객체로부터 
+                <literal>default</literal>로 명명된 파라미터에 대한 값을 검색할 수 있다.
+            </para>
+            
+            <para>
+                                만일 당신이 매우 자주 어떤 UserType을 사용할 경우, 그것은 그것에 대한 더 짧은 이름을 정의하는 것이 유용할 수 있다. 
+                <literal>&lt;typedef&gt;</literal> 요소를 사용하여 이것을 행할 수 있다. Typedef들은 이름을 맞춤형 타입에 
+                                할당하고, 또한 만일 그 타입이 파라미터화 된 경우에 디폴트 파라미터 값들의 리스트를 포함할 수도 있다.
+            </para>
+            
+            <programlisting><![CDATA[<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
+    <param name="default">0</param>
+</typedef>]]></programlisting>
+
+            <programlisting><![CDATA[<property name="priority" type="default_zero"/>]]></programlisting>
+
+            <para>
+                property 매핑 상에 type 파라미터들을 사용함으로써 경우에 맞게 typedef 내에 제공된 파라미터들을 오버라이드 시키는 것이 
+                                가능하다.
+            </para>
+            
+            <para>
+                                비록 Hibernate의 풍부한 범위의 미리 만들어진 타입들과 컴포넌트들에 대한 지원이 당신이 가끔 맞춤형 타입을 사용할 <emphasis>필요가</emphasis> 
+                                거의 없을 것임을 의미할 지라도, 그럼에도 불구하고 그것은 당신의 어플리케이션에서 자주 발생하는 (엔티티가 아닌) 클래스들에 대해 
+                                맞춤형 타입들을 사용하는 좋은 형식으로 간주된다. 예를 들어 <literal>MonetaryAmount</literal> 클래스는 비록 그것이 
+                                컴포넌트로서 쉽게 매핑될 수  있을지라도, <literal>CompositeUserType</literal>에 대한 좋은 후보이다. 이것에 대한 
+                                하나의 동기는 추상화이다. 맞춤형 타입으로, 당신의 매핑 문서들은 화폐 값들을 표현하는 당신의 방법에서 가능한 변경들에 대해 장차 
+                                검증될 것이다.
+            </para>
+
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="mapping-entityname">
+        <title>하나의 클래스를 한 번 이상 매핑하기</title>
+        <para>
+                        하나의 특정한 영속 클래스에 대해 하나 이상의 매핑을 제공하는 것이 가능하다. 이 경우에 당신은 두 개의 매핑된 엔티티들의  
+                        인스턴스들 사이를 명확하게 하기 위해 <emphasis>하나의 엔티티 이름</emphasis>을 지정해야 한다. (디폴트로, 엔티티 
+                        이름은 클래스 이름과 동일한 것이다.) Hibernate는 영속 객체들에 대해 작업할 때, 질의들을 작성할 때, 또는 명명된 엔티티에 
+                        대한 연관들을 매핑할 때 당신으로 하여금 엔티티 이름을 지정하도록 한다.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Contract" table="Contracts" 
+        entity-name="CurrentContract">
+    ...
+    <set name="history" inverse="true" 
+            order-by="effectiveEndDate desc">
+        <key column="currentContractId"/>
+        <one-to-many entity-name="HistoricalContract"/>
+    </set>
+</class>
+
+<class name="Contract" table="ContractHistory" 
+        entity-name="HistoricalContract">
+    ...
+    <many-to-one name="currentContract" 
+            column="currentContractId" 
+            entity-name="CurrentContract"/>
+</class>]]></programlisting>
+
+        <para>
+                        연관들은 이제 <literal>class</literal> 대신에 <literal>entity-name</literal>을 사용하여 어떻게 지정되는지를 
+                        주목하라. 
+        </para>
+
+    </sect1>
+
+    <sect1 id="mapping-quotedidentifiers">
+            <title>SQL 인용부호 표시된 식별자들</title>
+            <para>
+                                당신은 매핑 문서 내에서 테이블 또는 컬럼 이름을 역인용기호(`)들 속에 넣어서 생성된 SQL에서 식별자를 인용부호 처리하도록 
+                Hibernate에게 강제할 수도 있다. Hibernate는 SQL <literal>Dialect</literal>에 대해 정확한 인용 스타일을 사용할 
+                                것이다(대개 이중 인용부호 이지만, SQL Server의 경우에는 모난 괄호들이고 MySQL의 경우에는 역인용부호(`)).
+            </para>
+
+            <programlisting><![CDATA[<class name="LineItem" table="`Line Item`">
+    <id name="id" column="`Item Id`"/><generator class="assigned"/></id>
+    <property name="itemNumber" column="`Item #`"/>
+    ...
+</class>]]></programlisting>
+
+    </sect1>
+
+    
+    <sect1 id="mapping-alternatives">
+    <title>Metadata 대안들</title>
+    
+    <para>
+        XML은 모든 사람들을 위한 것이 아니지만, Hibernate에서 O/R 매핑 메타데이터를 정의하는 몇몇 대안적인 방법들이 존재한다.
+    </para>
+
+    <sect2 id="mapping-xdoclet">
+        <title>XDoclet 마크업 사용하기</title>
+
+        <para>
+                        많은 Hibernate 사용자들은 XDoclet <literal>@hibernate.tags</literal>를 사용하여 소스 코드 속에 
+                        직접 매핑 정보를 삽입시키는 것을 선호한다. 우리는 이 문서에서 이 접근법을 다루지 않을 것이다. 왜냐하면 그것은 
+                        엄격하게는 XDoclet의 부분으로 간주되기 때문이다. 하지만 우리는 XDoclet 매핑들을 가진 <literal>Cat</literal> 
+                        클래스에 관한 다음 예제를 포함한다.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+/**
+ * @hibernate.class
+ *  table="CATS"
+ */
+public class Cat {
+    private Long id; // identifier
+    private Date birthdate;
+    private Cat mother;
+    private Set kittens
+    private Color color;
+    private char sex;
+    private float weight;
+
+    /*
+     * @hibernate.id
+     *  generator-class="native"
+     *  column="CAT_ID"
+     */
+    public Long getId() {
+        return id;
+    }
+    private void setId(Long id) {
+        this.id=id;
+    }
+
+    /**
+     * @hibernate.many-to-one
+     *  column="PARENT_ID"
+     */
+    public Cat getMother() {
+        return mother;
+    }
+    void setMother(Cat mother) {
+        this.mother = mother;
+    }
+
+    /**
+     * @hibernate.property
+     *  column="BIRTH_DATE"
+     */
+    public Date getBirthdate() {
+        return birthdate;
+    }
+    void setBirthdate(Date date) {
+        birthdate = date;
+    }
+    /**
+     * @hibernate.property
+     *  column="WEIGHT"
+     */
+    public float getWeight() {
+        return weight;
+    }
+    void setWeight(float weight) {
+        this.weight = weight;
+    }
+
+    /**
+     * @hibernate.property
+     *  column="COLOR"
+     *  not-null="true"
+     */
+    public Color getColor() {
+        return color;
+    }
+    void setColor(Color color) {
+        this.color = color;
+    }
+    /**
+     * @hibernate.set
+     *  inverse="true"
+     *  order-by="BIRTH_DATE"
+     * @hibernate.collection-key
+     *  column="PARENT_ID"
+     * @hibernate.collection-one-to-many
+     */
+    public Set getKittens() {
+        return kittens;
+    }
+    void setKittens(Set kittens) {
+        this.kittens = kittens;
+    }
+    // addKitten not needed by Hibernate
+    public void addKitten(Cat kitten) {
+        kittens.add(kitten);
+    }
+
+    /**
+     * @hibernate.property
+     *  column="SEX"
+     *  not-null="true"
+     *  update="false"
+     */
+    public char getSex() {
+        return sex;
+    }
+    void setSex(char sex) {
+        this.sex=sex;
+    }
+}]]></programlisting>
+
+        <para>
+            XDoclet과 ibernate에 관한 추가 예제들은 Hibernate 웹 사이트를 보라.
+        </para>
+
+    </sect2>
+
+    <sect2 id="mapping-annotations" revision="2">
+        <title>JDK 5.0 Annotations 사용하기</title>
+
+        <para>
+            JDK 5.0은 언어 레벨에서 XDoclet-스타일의 주석들, type-safe와 컴파일 시 체킹을 도입했다. 이 메커니즘은 XDoclet 
+                        주석들 보다 더 강력하며 도구들과 IDE들에 의해 더 좋게 지원된다. 예를 들어 IntelliJ IDEA는 JDK 5.0 주석들에 대한 
+                        자동-완성 기능과 구문 강조를 지원한다. EJB 명세서의 새로운 개정판(JSR-220)은 엔티티 빈즈에 대한 프라이머리 메타데이터 
+                        메커니즘으로서 JDK 5.0 Annotations을 사용한다. Hibernate3는 JSR-220(영속 API)의 <literal>EntityManager</literal>를 
+                        구현하고, 매핑 메타데이터에 대한 지원은 별도의 내려받기로서 <emphasis>Hibernate Annotations</emphasis> 패키지를 
+                        통해 이용 가능하다. EJB3 (JSR-220)과 Hibernate3 metadata 양자가 지원된다.
+        </para>
+
+        <para>
+                        다음은 EJB 엔티티 빈으로서 주석이 붙은 POJO 클래스에 관한 예제이다: 
+        </para>
+
+        <programlisting><![CDATA[@Entity(access = AccessType.FIELD)
+public class Customer implements Serializable {
+
+    @Id;
+    Long id;
+
+    String firstName;
+    String lastName;
+    Date birthday;
+
+    @Transient
+    Integer age;
+
+    @Embedded
+    private Address homeAddress;
+
+    @OneToMany(cascade=CascadeType.ALL)
+    @JoinColumn(name="CUSTOMER_ID")
+    Set<Order> orders;
+
+    // Getter/setter and business methods
+}]]></programlisting>
+
+        <para>
+            JDK 5.0 Annotations(그리고 JSR-220)에 대한 지원은 여전히 작업이 진행 중이고 완성되지 않았음을 노트하라. 상세한 것은 
+            Hibernate Anotations를 참조하라.
+        </para>
+    
+    </sect2>
+    </sect1>
+    
+        <sect1 id="mapping-generated" revision="1">
+        <title>산출되는 프로퍼티들</title>
+        <para>
+                        산출되는 프로퍼티들은 데이터베이스에 의해 산출되는 그것들의 값들을 갖는 프로퍼티들이다. 전형적으로, 
+            Hibernate 어플리케이션들은 데이터베이스가 값들을 생성시켰던 임의의 프로퍼티들을 포함하는 객체들을 
+            <literal>갱신</literal>시킬 필요가 있었다.하지만 generated로 마크된 프로퍼티들은 어플리케이션으로 
+                        하여금 이 책임을 Hibernate에게 위임시키도록 한다. 본질적으로 Hibernate가 산출되는 프로퍼티들을 정의했던 엔티티에 
+                        대해 SQL INSERT 또는 UPDATE 명령을 내릴 때마다 바로 직후에 산출되는 값들을 검색하기 위해 하나의 select 명령을 
+                        내린다.
+        </para>
+        <para>
+            generated로 마크된 프로퍼티들은 부가적으로 inser 가능하지 않아야 하고 update 불가능해야 한다. 오직 
+            Properties marked as generated must additionally be non-insertable and non-updateable.
+            <xref linkend="mapping-declaration-version">versions</xref>,
+            <xref linkend="mapping-declaration-timestamp">timestamps</xref>, 그리고
+            <xref linkend="mapping-declaration-property">단순 프로퍼티들</xref> 만이 generated로 
+                        마크될 수 있다.
+        </para>
+        <para>
+		    <literal>never</literal> (디폴트) - 는 주어진 프로퍼티 값이 데이터베이스 내에 생성되지 않을 것임을 의미한다.
+	    </para>
+	    <para>
+		    <literal>insert</literal> - 는 주어진 프로퍼티 값이 insert 시에 생성되지만, 차후의 업데이트들에서 다시 
+		        생성되지 않을 것임을 기술한다. 생성-날짜와 같은 것들이 이 카테고리 내로 포함될 것이다. 비록 
+		    <xref linkend="mapping-declaration-version">version</xref>ê³¼ 
+		    <xref linkend="mapping-declaration-timestamp">timestamp</xref> 프로퍼티들이 생성되는 것으로서 
+		        마크될 수 있을 지라도, 이 옵션은 거기서 이용 불가능함을 노트하라...
+	    </para>
+	    <para>
+		    <literal>always</literal> - 는 프로퍼티 값이 insert 시와 update 시 모두에 생성됨을 기술한다.
+	    </para>
+    </sect1>
+
+    <sect1 id="mapping-database-object">
+        <title>보조 데이터베이스 객체들</title>
+        <para>
+            Hibernate 매핑 파일들 내에 사용자 스키마를 완전하게 정의하기 위한 능력을 제공하기 위해서, 
+            Hibernate의 스키마 방출 도구들과 함께 임의적인 데이터베이스 객체들에 대한 CREATE와 DROP을 허용해준다.
+                        비록 트리거들 또는 내장 프로시저들과 같은 것들을 생성시키고 드롭시키기 이해 특별히 고안되었을지라도
+                        하나의 <literal>java.sql.Statement.execute()</literal> 메소드를 통해 실행될 수 있는 SQL 명령이 
+                        여기서 유효하다(ALTERs, INSERTS, 기타). 보조 데0이터베이스 객체들을 정의하는 두 가지 모드들이 본질적으로 
+                        존재한다...
+        </para>
+        <para>
+                        첫 번째 모드는 매핑 파일 바깥에서 CREATE 및 DROP 명령들을 명시적으로 나열하는 것이다:
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <create>CREATE TRIGGER my_trigger ...</create>
+        <drop>DROP TRIGGER my_trigger</drop>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+        <para>
+                        두번째 모드는 CREATE 및 DROP 명령들을 생성시키는 방법을 알고 있는 하나의 맞춤 클래스를 제공하는 것이다.
+                        이 맞춤 클래스는 <literal>org.hibernate.mapping.AuxiliaryDatabaseObject</literal> 
+                        인터페이스를 구현해야 한다.
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <definition class="MyTriggerDefinition"/>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+        <para>
+                        덧붙여 이들 데이터베이스 객체들은 어떤 dialect들이 사용될 때 그것들이 단지 적용될 수 있도록 선택적으로 
+                        변동될 수 있다.
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <definition class="MyTriggerDefinition"/>
+        <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/>
+        <dialect-scope name="org.hibernate.dialect.OracleDialect"/>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+    </sect1>
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/batch.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/batch.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/batch.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,320 @@
+<chapter id="batch">
+    <title>Batch 처리</title>
+    
+    <para>
+        Hibernate를 사용하여 데이터베이스 내에서 100 000 개의 행들을 삽입시키는 본래의 접근법은 다음과 같다:
+    </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+for ( int i=0; i<100000; i++ ) {
+    Customer customer = new Customer(.....);
+    session.save(customer);
+}
+tx.commit();
+session.close();]]></programlisting>
+
+    <para>
+                이것은 50 000번째 행 가까운 곳에서 <literal>OutOfMemoryException</literal>으로 떨어질 것이다. 그것은 Hibernate가 
+        session-level 캐시 속에 모든 새로이 삽입된 <literal>Customer</literal> 인스턴스들을 캐시시키기 때문이다. 
+    </para>
+
+    <para>
+                이 장에서 우리는 이 문제를 피하는 방법을 당신에게 보여줄 것이다. 하지만 먼저 당신이 배치 처리를 행하는 중이라면, 당신이 적당한 퍼포먼스를 
+                성취하려고 할 경우에 당신이 JDBC 배치 사용을 가능하게 하는 것은 절대적으로 필요하다. JDBC 배치 사이즈를 적당한 숫자(10-50)로 설정하라:
+    </para>
+    
+<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
+
+    <para id="disablebatching" revision="1">
+        만일 당신이 <literal>identiy</literal> 식별자 생성자를 사용할 경우 
+        Hibernate가 JDBC 레벨에서 투명하게 insert 배치작업을 사용불가능하게 한다는 점을 노트하라.
+    </para>
+
+    <para>
+                당신은 또한 second-level 캐시를 가진 상호작용이 완전하게 불가능한 프로세스 내에서 이런 종류의 작업을 행하고 싶어할 수도 있다:
+    </para>
+
+<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
+
+    <para>
+                하지만 이것은 절대적으로 필요하지 않다. 왜냐하면 우리는 second-level 캐시와의 상호작용을 불가능하도록 하기 위해
+                명시적으로 <literal>CacheMode</literal>를 설정할 수 있기 때문이다.
+    </para>
+
+    <sect1 id="batch-inserts">
+        <title>Batch inserts</title>
+
+        <para>
+                        새로운 객체들을 영속화  시킬 때, 당신은 first-level 캐시의 사이즈를 제어하기 위해 세션을 정기적으로 <literal>flush()</literal>
+                        시키고 나서 <literal>clear()</literal> 시켜야 한다.
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+   
+for ( int i=0; i<100000; i++ ) {
+    Customer customer = new Customer(.....);
+    session.save(customer);
+    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
+        //flush a batch of inserts and release memory:
+        session.flush();
+        session.clear();
+    }
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="batch-update" >
+        <title>Batch updates</title>
+
+        <para>
+                        데이터 검색과 업데이트의 경우 동일한 개념들이 적용된다. 게다가 당신은 많은 데이터 행들을 반환하는 질의들에 대해 서버-측 커서들의 장점을 
+                        취하는데 <literal>scroll()</literal>을 사용할 필요가 있다.
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+   
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+    .setCacheMode(CacheMode.IGNORE)
+    .scroll(ScrollMode.FORWARD_ONLY);
+int count=0;
+while ( customers.next() ) {
+    Customer customer = (Customer) customers.get(0);
+    customer.updateStuff(...);
+    if ( ++count % 20 == 0 ) {
+        //flush a batch of updates and release memory:
+        session.flush();
+        session.clear();
+    }
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="batch-statelesssession">
+        <title>StatelessSession 인터페이스</title>
+        <para>
+                        다른 방법으로 Hibernate는 분리된(detached) 객체들의 형식으로 데이터베이스로 그리고 데이터베이스로부터 
+                        데이터를 스트리밍하는데 사용될 수 있는 하나의 명령 지향 API를 제공한다. <literal>StatelessSession</literal>은 
+                        그것과 연관된 영속 컨텍스트를 갖지 않고 많은 보다 높은 레벨의 생명 주기 의미를 제공하지 않는다. 
+                        특히 하나의 상태 없는 세션은 첫 번째 레벨 캐시를 구현하지 않거나 임의의 두 번째 레벨 캐시 또는 질의 캐시와 
+                        상호작용하지 않는다. 그것은 전통적인 쓰기-이면(write-behind)의 체킹이나 자동적인 dirty 체킹을 구현하지 않는다.
+                        하나의 상태 없는 세션을 사용하여 수행된 연산들은 연관된 인스턴스들에 대해 케스케이드 되지 않는다. 콜렉션들은
+                        상태 없는 세션에 의해 무시된다. 상태없는 세션을 통해 수행된 연산들은 Hibernate의 이벤트 모형과 인터셉터들을 
+                        우회한다. 상태없는 세션들은 첫번째-레벨의 캐시의 부족으로 인해 데이터 alias 효과들에 취약하다. 상태없는 세션은 
+                        기본 JDBC에 훨씬 더 가까운 하나의 보다 낮은 레벨의 추상화(abstraction)이다.
+        </para>
+        
+<programlisting><![CDATA[StatelessSession session = sessionFactory.openStatelessSession();
+Transaction tx = session.beginTransaction();
+   
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+    .scroll(ScrollMode.FORWARD_ONLY);
+while ( customers.next() ) {
+    Customer customer = (Customer) customers.get(0);
+    customer.updateStuff(...);
+    session.update(customer);
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+                        이 코드 예제에서, 질의에 의해 반환된 <literal>Customer</literal> 인스턴스들은 곧바고 분리된다(detached). 
+                        그것들은 임의의 영속 컨텍스트와 결코 연관되지 않는다.
+        </para>
+        
+        <para>
+            <literal>StatelessSession</literal> 인터페이스에 의해 정의된 
+            <literal>insert(), update()</literal> 그리고 <literal>delete()</literal> 연산들은 직접적인 
+                        데이터베이스 저급 연산들로 갖주되고, 그것은 각각 하나의 SQL <literal>INSERT, UPDATE</literal> 또는 
+            <literal>DELETE</literal>의 즉각적인 실행으로 귀결된다. 따라서 그것들은 <literal>Session</literal>
+                        인터페이스에 의해 정의된 <literal>save(), saveOrUpdate()</literal>와 <literal>delete()</literal>
+                        연산들과는 매우 다른 의미들을 갖는다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="batch-direct" revision="3">
+        <title>DML-스타일 연산들</title>
+
+        <para>
+                        이미 논의했듯이, 자동적이고 투명한 객체/관계형 매핑은 객체 상태에 대한 관리에 관계된다. 이것은 객체 상태가 메모리 내에서 이용 가능함을 
+                        의미하므로, (SQL <literal>Data Manipulation Language</literal>(DML) 문장들 : <literal>INSERT</literal>, 
+            <literal>UPDATE</literal>, <literal>DELETE</literal>를 사용하여) 데이터베이스에서 직접 데이터를 
+                        업데이트하거나 삭제하는 것은 메모리 내 상태에 영향을 주지 않을 것이다. 하지만 Hibernate는  Hibernate Query Language
+            (<xref linkend="queryhql">HQL</xref>)를 통해 실행되는 대량 SQL-스타일의 DML 문장 실행을 위한 메소드들을 제공한다.
+        </para>
+
+	    <para>
+            <literal>UPDATE</literal>와 <literal>DELETE</literal> 문장들에 대한 유사 구문은 다음과 같다: 
+            <literal>( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?</literal>. 노트할 몇 가지:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    from-절에서, FROM 키워드는 옵션이다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    from-절 내에 한 개의 명명된 엔티티가 오직 존재할 수 있다; 그것은 선택적으로 alias될 수 있다. 만일 엔티티 
+                                        이름이 alias되면, 그때 임의의 프로퍼티 참조들은 그 alias를 사용하여 수식되어야 한다; 만일 엔티티 이름이 
+                    alias되지 않을 경우, 임의의 프로퍼티 참조들에 대해 수식되는 것은 규칙에 어긋난다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <xref linkend="queryhql-joins-forms">join들</xref>은 (함축적이든 명시적이든) 
+                                        대량 HQL 질의 속에 지정될 수 없다. 서브-질의들이 where-절에 사용될 수 있다;
+                                        서브질의들 그 자신들은 조인들을 포함할 수 있다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    where-절 또한 옵션이다.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+                        하나의 예제로서, 한 개의 HQL <literal>UPDATE</literal>를 실행하기 위해, <literal>Query.executeUpdate()</literal> 
+                        메소드(이 메소드는 JDBC의 <literal>PreparedStatement.executeUpdate()</literal>와 유사하게 명명된다)를 사용하라:
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
+// or String hqlUpdate = "update Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+        .setString( "newName", newName )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            HQL <literal>UPDATE</literal> 문장들은 디폴트로 영향받는 엔티티들에 대한 
+            <xref linkend="mapping-declaration-version">version</xref> 또는 
+            <xref linkend="mapping-declaration-timestamp">timestamp</xref> 프로퍼티 값들에 영향을 주지 않는다;
+                        이것은 EJB3 명세서에서 유지되고 있다. 하지만 당신은 하이버네이트로 하여금 <literal>versioned update</literal>의 
+                        사용을 통해 <literal>version</literal> 또는 <literal>timestamp</literal> 프로퍼티 값들을 적절하게 
+                        재설정하도록 강제할 수 있다. 이것은 <literal>UPDATE</literal> 키워드 뒤에 <literal>VERSIONED</literal> 키워드를 
+                        추가시켜서 성취된다.
+        </para>
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+        .setString( "newName", newName )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+                        맞춤형 version 타입들(<literal>org.hibernate.usertype.UserVersionType</literal>)은 
+            <literal>update versioned</literal> 문장과 함께 사용하는 것이 허용되지 않음을 노트하라.
+        </para>
+
+        <para>
+            HQL <literal>DELETE</literal>를 실행하려면, 같은 메소드 <literal>Query.executeUpdate()</literal>를 
+                        사용하라:
+        </para>
+        
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlDelete = "delete Customer c where c.name = :oldName";
+// or String hqlDelete = "delete Customer where name = :oldName";
+int deletedEntities = s.createQuery( hqlDelete )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            <literal>Query.executeUpdate()</literal> 메소드에 의해 반환되는 <literal>int</literal> 값은 그 오퍼레이션에 의해 
+                        영향받은 엔티티들의 개수를 나타낸다. 이것이 데이터베이스 내에서 영향받은 행들의 개수와 상관이 있는지 없는지 여부를 살펴보자. HQL 
+                        대량 오퍼레이션은 예를 들어 joined-subclass의 경우에 실행 중인 여러 개의 실제 SQL 문장들로 귀결될 수 있다. 반환되는 숫자는 
+                        그 문장에 의해 영향받은 실제 엔티티들의 개수를 나타낸다. joined-subclass 예제로 되돌아가면, 서브 클래스들 중 하나에 대한 삭제는 
+                        단지 그 서브클래스가 매핑되어 있는 테이블에 대한 삭제 뿐만 아니라 또한 "루트" 테이블과 상속 계층에서 더 내려온 잠정적으로 
+                        조인된-서브클래스 테이블들에 대한 삭제들로 귀결될 수 있다.
+        </para>
+
+        <para>
+                        장래의 배포본들에서 전달될 대량 HQL 오퍼레이션들에 대한 몇 가지 제한들이 현재 존재함을 노트하라; 상세한 것은 JIRA 로드맵을 참조하라.
+            <literal>INSERT</literal> 문장들을 위한 유사-구문은 다음과 같다: 
+            <literal>INSERT INTO EntityName properties_list select_statement</literal>.  노트할 몇 가지:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                                        오직 INSERT INTO ... SELECT ... 형식 만일 지원된다; INSERT INTO ... VALUES ... 형식은 지원되지 않는다.
+                </para>
+                <para>
+                    properties_list는 SQL <literal>INSERT</literal> 내에서 <literal>column speficiation</literal>과 유사하다.
+                                        매핑된 상속에 참여하는 엔티티들의 경우, 그 주어진 클래스-레벨 상에 직접 정의된 프로퍼티들 만이 properties_list에 사용될 수 있다. 
+                                        슈퍼클래스 프로퍼티들은 허용되지 않는다; 그리고 서브클래스 프로퍼티들은 의미가 없다. 달리 말해 <literal>INSERT</literal> 문장들은  
+                                        본래적으로 다형적이지 않다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    select_statement는 반환 타입들이 insert에 의해 기대되는 타입들과 일치해야 한다는 단서 하에 임의의 유효한 HQL select 질의일 수 
+                                        있다. 현재 이것은 체크를  데이터베이스로 이관시키는 것을 허용하기 보다는 질의 컴파일 동안에 체크된다. 하지만 이것은 
+                    <emphasis>equal</emphasis>과는 대조적으로 <emphasis>등가인(equivalent)</emphasis> Hibernate <literal>Type</literal>들 
+                                        사이에서 문제점들을 일으킬 수도 있음을 노트하라. 비록 데이터베이스가 구별짓지 않을 수 있거나 변환을 처리할 수 있을 지라도, 이것은 
+                    <literal>org.hibernate.type.DateType</literal>로서 정의된 프로퍼티와 <literal>org.hibernate.type.TimestampType</literal>으로 
+                                        정의된 프로퍼티 사이에 불일치 쟁점들을 일으킨다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    id 프로퍼티의 경우, insert 문장은 당신에게 두 개의 옵션을 준다. 당신은 properties_list 내에 id 프로퍼티를 명시적으로 
+                                        지정할 수 있거나(그것의 값이 대응하는 select 표현식으로부터 얻어진 경우) 또는 properties_list에서 그것을 생략할 수도 있다
+                    (산출된 값이 사용되는 경우). 이 후자의 옵션은 데이터베이스 내에서 연산되는 id 연산자들을 사용할 때에만 이용 가능하다; 
+                                        임의의 "메모리 내" 타입 연산자들과 함께 이 옵션을 사용하려고 시도하는 것은 파싱 동안에 예외상황을 일으킬 것이다. 이 논의의 
+                                        목적 상, 데이터베이스 내 산출자(generator)들은 <literal>org.hibernate.id.SequenceGenerator</literal> 
+                    (그리고 그것의 서브클래스들) 그리고 임의의 <literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>의 
+                                        구현자들이라고 간주됨을 노트하라. 여기서 가장 주목할 만한 예외상황은 그것이 그것의 값들을 얻기 위한 select 가능한 방법을 
+                                        노출시키지 않기 때문ㅇ에 사용될 수 없는 <literal>org.hibernate.id.TableHiLoGenerator</literal>이다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>version</literal> 또는 <literal>timestamp</literal>로서 매핑된 프로퍼티들의 경우에, 
+                    insert 문장은 당신에게 두 개의 옵션들을 준다. 당신은 properties_list 내에 그 프로퍼티를 지정할 수 있거나
+                    (그 것의 값이 대응하는 select 표현식으로부터 얻어진 경우) 또는 properties_list에서 그것을 생략할 수 있다
+                    (<literal>org.hibernate.type.VersionType</literal>에 의해 정의된 <literal>seed value</literal> 
+                                        값이 사용되는 경우).
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+                         예제 HQL <literal>INSERT</literal> 문장 실행:
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
+int createdEntities = s.createQuery( hqlInsert )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/best_practices.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/best_practices.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/best_practices.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,204 @@
+<chapter id="best-practices" revision="3">
+    <title>최상의 실전 경험들</title>
+
+    <variablelist spacing="compact">
+        <varlistentry>
+            <term>fine-grained 클래스들을 작성하고 <literal>&lt;component&gt;</literal>를 사용하여 그것들을 매핑하라. </term>
+            <listitem>
+                <para>
+                    <literal>street</literal>, <literal>suburb</literal>, <literal>state</literal>, <literal>postcode</literal>를 
+                                        캡슐화 시키는데 <literal>Address</literal> 클래스를 사용하라. 이것은 코드 재사용성을 촉진시키고 리팩토링을 단순화 시킨다. 
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>영속 클래스들에 대해 식별자 프로퍼티들을 선언하라.</term>
+            <listitem>
+                <para>
+                    Hibernate는 식별자 프로퍼티들을 옵션으로 만든다. 왜 우리가 그것들을 사용해야 하는가에 대한 모든 종류의 이유들이 존재한다. 
+                                        우리는 식별자들이 '합성(synthetic)'이 되는(비지니스 의미 없이 생성되는) 것을 권장한다.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>고유 키들을 식별하라.</term>
+            <listitem>
+                <para>
+                                        모든 엔티티들에 대해 고유 키들을 식별하고, <literal>&lt;natural-id&gt;</literal>를 사용하여 그것들을 매핑하라.
+                                        고유 키를 구성하는 프로퍼티들을 비교하기 위해 <literal>equals()</literal>와 <literal>hashCode()</literal>를 
+                                        구현하라.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry><term>각각의 클래스 매핑을 그것 자신의 파일 내에 위치지워라.</term>
+            <listitem>
+                <para>
+                                          하나의 한덩어리 매핑 문서를 사용하지 말라. <literal>com/eg/Foo.hbm.xml</literal> 파일 속에 
+                     <literal>com.eg.Foo</literal>를 매핑하라. 이것은 팀 환경에서 특히 좋은 의미를 준다. 
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>매핑들을 리소스들로서 로드시켜라.</term>
+            <listitem>
+                <para>
+                                        그것들이 매핑하는 클래스들에 따라서 매핑들을 배치하라
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>질의 문자열들을 객관화 시키는 것을 고려하라.</term>
+            <listitem>
+                <para>
+                                        당신의 질의들이 ANSI 표준이 아닌 SQL 함수들을 호출하는 경우는 좋은 실전연습이다. 질의 문자열들을 매핑 파일들에다가 
+                                        외부화 시키는 것은 어플리케이션을 보다 이식성 있도록 만들어줄 것이다.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>바인드 변수들을 사용하라.</term>
+            <listitem>
+                <para>
+                     JDBC에서처럼, 상수 아닌 값들을 "?"로 대체시켜라. 질의 속에 상수 아닌 값을 바인드 시키는데 문자열 처리를 결코 
+                                          사용하지 말라! 더 좋게는 질의들 속에 명명된 파라미터들을 사용하는 것을 고려하라.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>당신 자신의 JDBC 커넥션들을 관리하지 말라.</term>
+            <listitem>
+                <para>
+                    Hibernate는 어플리케이션으로 하여금 JDBC 커넥션들을 관리하도록 한다. 이 접근법은 마지막 수단으로서 고려되어야 한다. 
+                                        만일 당신이 미리 만들어진 커넥션 프로바이더들을 사용할 수 없을 경우, <literal>org.hibernate.connection.ConnectionProvider</literal>에 
+                                        대한 당신 자신의 구현을 제공하는 것을 고려하라.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>맞춤형 타입 사용을 고려하라.</term>
+            <listitem>
+                <para>
+                                        당신이 자바 타입을 갖고 있고, 어떤 라이브러리로부터 말하고, 그것이 영속화 될 필요가 있지만 그것을 컴포넌트로서 매핑시키는데 
+                                        필요한 accessor들을 제공할 필요가 없다고 가정하자. 당신은 <literal>org.hibernate.UserType</literal>을 구현하는 
+                                        것을 고려해야 할 것이다. 이 접근법은 Hibernate 타입으로/으로부터 변환들을 구현하는 것으로부터 어플리케이션 코드를 자유롭게 
+                                        해준다.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>병목 지점들에서 수작업으로 코딩된 JDBC를 사용하라.</term>
+            <listitem>
+                <para>
+                                        시스템의 퍼포먼스가 중대한 영역들에서, 몇몇 종류의 오퍼레이션들은 직접적인 JDBC에서 이득을 본다. 그러나 당신이 어떤 것이 병목인지를 
+                    <emphasis>알기</emphasis> 전까지 기다리길 바란다. 그리고 직접적인 JDBC가 반드시 더 빠르다고 가정하지 말라. 만일 당신이 직접적인 
+                    JDBC를 사용할 필요가 있을 경우, Hibernate <literal>Session</literal>을 열고 그 SQL 커넥션을 사용할 가치가 있다. 그 방법으로 
+                                        당신은 동일한 트랜잭션 방도와 기본 커넥션 프로바이더를 여전히 사용할 수 있다
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term><literal>Session</literal> flushing을 이해하라.</term>
+            <listitem>
+                <para>
+                                        시간이 지남에 따라 Session은 그것의 영속 상태를 데이터베이스와 동기화 시킨다. 만일 이 과정이 너무 자주 발생할 경우 퍼포먼스가 
+                                        영향을 받을 것이다. 당신은 때때로 자동적인 flushing을 사용 불가능하게 만들거나 특정 트랜잭션 내에서 질의들의 순서와 다른 
+                                        오퍼레이션들의 순서를 변경시켜서 불필요한 flushing을 최소화 시킬 수 있다.      
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>3-tier 아키텍처에서, <literal>saveOrUpdate()</literal> 사용을 고려하라.</term>
+            <listitem>
+                <para>
+                    servlet / session 빈 아키텍처를 사용할 때, 당신은 sesson bean 내에 로드된 영속 객체들을 서블릿/JSP 계층으로/으로부터 
+                                        전달할/받을 수 있다. 각각의 요청을 서비스하는데 새로운 세션을 사용하라. 객체들을 데이터베이스와 동기화 시키기 위해서 
+                    <literal>Session.merge()</literal> 또는 <literal>Session.saveOrUpdate()</literal>를 사용하라.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>2-tier 아키텍처에서, 수명이 긴 영속 컨텍스트들을 사용하는 것을 고려하라.</term>
+            <listitem>
+                <para>
+                                        데이터베이스 트랜잭션들은 최상의 가용성을 위해 가능한 한 짧아야 한다. 하지만 장기간 실행되는 <emphasis>어플리케이션 트랜잭션들</emphasis>, 
+                                        사용자의 뷰 관점에서 한 개의 단위 작업을 구현하는 것이 가끔 필수적이다. 하나의 어플리케이션 트랜잭션은 몇 개의 클라이언트 요청들과 
+                                        응답 주기들에 걸칠 수도 있다. 어플리케이션 트랜잭션들을 구현하는데 detached 객체들을 사용하는 것이 공통적이다. 2-티어 아키텍처에서 
+                                        매우 적절한 대안은 어플리케이션 트랜잭션의 전체 생명주기 동안에 한 개의 열려진 영속 접속 (세션)을 유지하는 것이고 각각의 요청의 끝에서 
+                    JDBC 커넥션을 간단하게 연결해제하고 차후의 요청의 시작 시에 다시 연결하는 것이다. 한 개 이상의 어플리케이션 트랜잭션을 가로질러서 
+                                        하나의 단일 세션을 결코 공유하지 말라. 공유할 경우에 당신은 실효성이 없는 데이터로 작업하게 될 것이다.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>예외상황들을 복구가능한 것으로서 다루지 말라.</term>
+            <listitem>
+                <para>
+                                        이것은 "최상의" 실전이 아닌 보다 필수적인 실전이다. 예외상황이 발생할 때, <literal>Transaction</literal>을 롤백시키고 
+                    <literal>Session</literal>을 닫아라. 만일 당신이 그렇게 하지 않을 경우, Hibernate는 메모리 내 상태가 영속 상태를 정확하게 
+                                        표현하는 것을 보증할 수 없다. 이 특별한 경우처럼, 만일 주어진 식별자를 가진 인스턴스가 데이터베이스 상에 존재하는지 여부를 결정하는데 
+                    <literal>Session.load()</literal>를 사용하지 말라; 대신에 <literal>Session.get()</literal> 또는 하나의 질의를 
+                                        사용하라.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>연관들에 대한 lazy 페칭을 선호하라.</term>
+            <listitem>
+                <para>
+                    eager 페칭을 관대하게 사용하라. second-level 캐시 내에 완전하게 보관되지 않을 것 같은 클래스들에 대한 대붑분의 연관들에 
+                                        대해 프락시들과 lazy 콜렉션들을 사용하라. 캐시된 클래스들에 대한 연관들의 경우, 이곳은 캐시 성공의 매우 높은 확률이 존재하는
+                                        곳이며, <literal>lazy="false"</literal>를 사용하여 eager 페칭을 명시적으로 사용 불가능하게 하라. 한의 join 페칭이 
+                                        특정 쓰임새에 대해 적절할 때, 하나의 <literal>left join fetch</literal>를 가진 질의를 사용하라.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>
+                                페치되지 않은 데이터 문제점들을 피하기 위해 <emphasis>뷰 내에 열려진 세션(open session in view)</emphasis> 패턴 또는 
+                                하나의 정리된 <emphasis>어셈블리 단계(assembly phase)</emphasis>를 사용하라.
+            </term>
+            <listitem>
+                <para>
+                    Hibernate는 개발자들이 <emphasis>Data Transfer Objects</emphasis> (DTO)를 지루하게 작성하는 것으로부터 
+                                         자유롭게 해준다. 전통적인 EJB 아키텍처에서, DTO는 이중 용도로 기능한다: 첫 번째로 그것들은 엔티티 빈즈가 직렬화 가능하지 않는 
+                                         문제점에 대해 착수한다; 두 번째로 그것들은 뷰에 의해 사용되는 모든 데이터가 프리젠테이션 티어로 컨트롤을 반환하기 전에 DTO들 속으로 
+                                         페치되고 마샬링되는 어셈블리 단계를 암묵적으로 정의한다. Hibernate는 첫 번째 용도를 제거시킨다. 하지만 당신이 뷰 렌더링 프로세스를 
+                                         가로질러 열려져 있는 영속 컨텍스트(세션)을 보관할 준비가 되어 있지 않는 한, 당신은 여전히 어셈블리 단계를 필요로 할 것이다(detached 
+                                         객체들에서 이용가능한 데이터가 무엇인지에 대해 프리젠테이션 티어와 엄격하게 계약을 갖도록 당신의 비지니스 메소드들을 고려하라)
+                                         이것은 Hibernate의 한계점이 아니다! 그것은 안전한 트랜잭션 데이터 접근의 필수 조건이다.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Hibernate에서 당신의 비지니스 로직을 추상화 시키는 것을 고려하라.</term>
+            <listitem>
+                <para>
+                    (Hibernate) 데이터 액세스 코드를 인터페이스 이면에 은폐시켜라. <emphasis>DAO</emphasis>와 
+                    <emphasis>Thread Local Session</emphasis> 패턴들을 결합시켜라. 당신은 심지어 <literal>UserType</literal>을 
+                                        통해 Hibernate에 연관된, 수작업으로 코딩된 JDBC로서 몇몇 클래스들을 영속화 시킬 수도 있다. (이 충고는 "충분히 큰" 
+                                        어플리케이션들에 대한 것이다; 그것은 5개의 테이블들을 가진 어플리케이션에 대해서는 적절하지 않다!) 
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>신종의 연관 매핑을 사용하지 말라.</term>
+            <listitem>
+                <para>
+                                        실제의 many-to-many 연관들에 대한 좋은 쓰임새들은 드물다. 대부분의 시간 동안 당신은 "연결 테이블" 내에 저장된 추가적인 정보를 필요로 한다. 
+                                        이 경우에, 매개하는 연결 클래스에 대해 두 개의 one-to-many 연관들을 사용하는 것이 훨씬 더 좋다. 사실 우리는 대부분의 연관들이 one-to-many와  
+                    many-to-one이라고 생각하며, 당신은 다른 연관 스타일을 사용할 때 주의해야 하고 그것이 진정 필수적인지를 당신 스스로 질문하라. 
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>양방향 연관들을 선호하라.</term>
+            <listitem>
+                <para>
+                                        단방향 연관들은 질의하기가 더 어렵다. 많은 어플리케이션에서, 거의 모든 연관들은 질의들 내에서 양 방향으로 네비게이트 가능해야 한다.
+                </para>
+            </listitem>
+        </varlistentry>
+    </variablelist>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/collection_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/collection_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/collection_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1158 @@
+<chapter id="collections">
+    <title>콜렉션 매핑</title>
+
+    <sect1 id="collections-persistent" revision="3">
+        <title>영속 콜렉션들</title>
+        
+        <para>
+                        예를 들어 Hibernate는 영속 콜렉션-값을 가진 필드들이 인터페이스 타입으로서 선언될 것을 필요로 한다: 
+        </para>
+        
+        <programlisting><![CDATA[public class Product {
+    private String serialNumber;
+    private Set parts = new HashSet();
+    
+    public Set getParts() { return parts; }
+    void setParts(Set parts) { this.parts = parts; }
+    public String getSerialNumber() { return serialNumber; }
+    void setSerialNumber(String sn) { serialNumber = sn; }
+}]]></programlisting>
+        
+        <para>
+                        실제 인터페이스는 <literal>java.util.Set</literal>, <literal>java.util.Collection</literal>, 
+            <literal>java.util.List</literal>, <literal>java.util.Map</literal>, <literal>java.util.SortedSet</literal>, 
+            <literal>java.util.SortedMap</literal> 또는 당신이 좋아하는 어떤 것일 수 있다!(여기서 "당신이 좋아하는 어떤 것"이란 
+                        당신이 <literal>org.hibernate.usertype.UserCollectionType</literal>에 대한 구현을 작성해야 함을 의미한다.) 
+        </para>
+        
+        <para>
+                        우리가 <literal>HashSet</literal>의 인스턴스를 가진 인스턴스 변수를 초기화 시켰던 방법을 주목하라. 이것은 새로이 
+                        초기화 된(비-영속) 인스턴스들을 가진 콜렉션 값 프로퍼티들을 초기화 시키는 최선의 방법이다. 당신이 -예를 들어 
+            <literal>persist()</literal>를 호출하여- 인스턴스를 영속화 시킬 때 Hibernate는 실제로 <literal>HashSet</literal>을 
+            <literal>Set</literal>에 대한 Hibernate 자신의 구현의 인스턴스로 대체시킬 것이다. 다음과 같은 오류들을 관찰하라:
+        </para>
+        
+        <programlisting><![CDATA[Cat cat = new DomesticCat();
+Cat kitten = new DomesticCat();
+....
+Set kittens = new HashSet();
+kittens.add(kitten);
+cat.setKittens(kittens);
+session.persist(cat);
+kittens = cat.getKittens(); // Okay, kittens collection is a Set
+(HashSet) cat.getKittens(); // Error!]]></programlisting>
+
+        <para>
+            Hibernate에 의해 도입된 영속 콜렉션들은 인터페이스 타입에 따라 <literal>HashMap</literal>, <literal>HashSet</literal>, 
+            <literal>TreeMap</literal>, <literal>TreeSet</literal> 또는 <literal>ArrayList</literal>와 같이 행위한다.
+        </para>
+
+        <para>
+                        콜렉션 인스턴스들은 value 타입들을 가진 통상의 특징을 갖는다. 그것들은 영속 객체에 의해 참조될 때 자동적으로 영속화 되고 
+                        참조 해제될 때 자동적으로 삭제된다. 만일 하나의 콜렉션이 하나의 영속 객체로부터 또 다른 영속 객체로 전달될 때, 그것의 요소들은 
+                        하나의 테이블로부터  다른 테이블로 이동될 수 있다. 두 개의 엔티티들은 동일한 콜렉션 인스턴스에 대한 참조를 공유하지 않는다. 
+                        기본 관계형 모형 때문에 콜렉션 값 프로퍼티들은 null 값 의미들을 지원하지 않는다; Hibernate는 null 콜렉션 참조와 공백의 
+                        콜렉션 사이를 구별 짓지 않는다.
+        </para>
+
+        <para>
+                        당신은 이것의 어떤 것에 대해 너무 많이 걱정하지 않아도 될 것이다. 당신이 통상의 자바 콜렉션들을 사용하는 것과 동일한 방법으로 
+                        영속 콜렉션들을 사용하라. 단지 당신이 양방향 연관관계들에 대한 의미를 확실히 이해하도록 하라(나중에 논의됨).
+        </para>
+
+    </sect1>
+
+    <sect1 id="collections-mapping" revision="4">
+        <title>콜렉션 매핑들</title>
+
+        <para>
+                        콜렉션을 매핑하는데 사용되는 Hiberante 매핑 요소는 인터페이스의 타입에 의존한다. 예를 들어<literal>&lt;set&gt;</literal> 
+                        요소는 <literal>Set</literal> 타입의 매핑 프로퍼티들에 사용된다
+        </para>
+        
+        <programlisting><![CDATA[<class name="Product">
+    <id name="serialNumber" column="productSerialNumber"/>
+    <set name="parts">
+        <key column="productSerialNumber" not-null="true"/>
+        <one-to-many class="Part"/>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            <literal>&lt;set&gt;</literal>과는 별도로, 또한 <literal>&lt;list&gt;</literal>, <literal>&lt;map&gt;</literal>, 
+            <literal>&lt;bag&gt;</literal>, <literal>&lt;array&gt;</literal>, 그리고 <literal>&lt;map&gt;</literal> 
+                        매핑 요소들이 존재한다. <literal>&lt;map&gt;</literal> 요소가 대표적이다:
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="mappingcollection1" coords="2 65"/>
+                <area id="mappingcollection2" coords="3 65"/>
+                <area id="mappingcollection3" coords="4 65"/>
+                <area id="mappingcollection4" coords="5 65"/>
+                <area id="mappingcollection5" coords="6 65"/>
+                <area id="mappingcollection6" coords="7 65"/>
+                <area id="mappingcollection7" coords="8 65"/>
+                <area id="mappingcollection8" coords="9 65"/>
+                <area id="mappingcollection9" coords="10 65"/>
+                <area id="mappingcollection10" coords="11 65"/>
+                <area id="mappingcollection11" coords="12 65"/>
+                <area id="mappingcollection12" coords="13 65"/>
+                <area id="mappingcollection13" coords="14 65"/>
+                <area id="mappingcollection14" coords="15 65"/>
+            </areaspec>
+            <programlisting><![CDATA[<map
+    name="propertyName"
+    table="table_name"
+    schema="schema_name"
+    lazy="true|extra|false"
+    inverse="true|false"
+    cascade="all|none|save-update|delete|all-delete-orphan|delete-orphan"
+    sort="unsorted|natural|comparatorClass"
+    order-by="column_name asc|desc"
+    where="arbitrary sql where condition"
+    fetch="join|select|subselect"
+    batch-size="N"
+    access="field|property|ClassName"
+    optimistic-lock="true|false"
+    mutable="true|false"
+    node="element-name|."
+    embed-xml="true|false"
+>
+
+    <key .... />
+    <map-key .... />
+    <element .... />
+</map>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="mappingcollection1">
+                    <para>
+                        <literal>name</literal> 콜렉션 프로퍼티 이름
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection2">
+                    <para>
+                        <literal>table</literal> (옵션 - 디폴트는 프로퍼티 이름) 
+                                                콜렉션 테이블의 이름(one-to-many 연관관계들에 대해서는 사용되지 않음)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection3">
+                    <para>
+                        <literal>schema</literal> (옵션) 
+                                                루트 요소 상에 선언된 스키마를 오버라이드 시키는 테이블 스키마의 이름
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection4">
+                    <para>
+                        <literal>lazy</literal> (옵션 - 디폴트는 <literal>true</literal>)는
+                        lazy 페칭을 사용 불가능하도록 하고 그 연관이 항상 eagerly 페치됨을 지정하는데 , 또는 대부분의 
+                                                연산들이 콜렉션을 초기화시키지 않는 곳에서 "extra-lazy" 페칭을 이용 가능하도록 하는데(매우 큰 콜렉션들에 
+                                                적당함) 사용될 수 있다
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection5">
+                    <para>
+                        <literal>inverse</literal> (옵션 - 디폴트는 <literal>false</literal>)
+                                                이 콜렉션을 양방향 연관관계의 "inverse" 끝(end)으로 표시한다
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection6">
+                    <para>
+                        <literal>cascade</literal> (옵션 - 디폴트는 <literal>none</literal>)
+                                                오퍼레이션들이 자식 엔티티들에 대해 케스케이드하는 것을  이용 가능하게 한다
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection7">
+                    <para>
+                        <literal>sort</literal> (옵션) 
+                        <literal>natural</literal> 정렬 순서로 정렬된(sorted) 콜렉션 또는 주어진 comparator 클래스를 지정한다
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection8">
+                    <para>
+                        <literal>order-by</literal> (옵션, JDK1.4에서만) 
+                        <literal>asc</literal> 또는 <literal>desc</literal> 옵션과 함께 <literal>Map</literal>, 
+                        <literal>Set</literal> 또는 bag의 반복 순서를 정의하는 테이블 컬럼(또는 컬럼들)을 지정한다
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection9">
+                    <para>
+                        <literal>where</literal> (옵션) 
+                                                콜렉션을 검색하거나 제거할 때 사용될 임의적인 SQL <literal>WHERE</literal> 조건을 지정한다
+                        (콜렉션이 오직 이용 가능한 데이터의 부분집합 만을 포함할 경우에 유용하다)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection10">
+                    <para>
+                        <literal>fetch</literal> (옵션, 디폴트는 <literal>select</literal>) 
+                        outer-join 페칭, sequential select 페칭, 그리고 sequential subselect 페칭 사이에서 선택하라. 
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection11">
+                    <para>
+                        <literal>batch-size</literal> (옵션, 디폴트는 <literal>1</literal>) 
+                                               이 콜렉션의 lazily fetching 인스턴스에 대해 "배치 사이즈"를 지정하라.
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection12">
+                    <para>
+                        <literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>): 
+                        Hibernate가 콜렉션 프로퍼티 값에 접근하는데 사용할 방도.
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection13">
+                    <para>
+                        <literal>optimistic-lock</literal> (옵션 - 디폴트는 <literal>true</literal>): 
+                                                콜렉션의 상태에 대한 변경들이 소유하는 엔티티의 버전의 증가로 귀결될 것인지를 지정한다. 
+                        (one to many 연관들에 대해, 이 설정을 사용 불가능하게 하는 것이 종종 합당하다.) 
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection14">
+                    <para>
+                        <literal>mutable</literal> (옵션 - 디폴트는 <literal>true</literal>): 
+                        <literal>false</literal> 값은 콜렉션의 요소들이 결코 변경되지 않음을 지정한다.
+                        (몇몇 경우들에서 마이너 퍼포먼스 최적화).
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <sect2 id="collections-foreignkeys" >
+           <title>콜렉션 foreign 키들</title>
+    
+            <para>
+                                콜렉션 인스턴스들은 그 콜렉션을 소유하는 엔티티의 foreign 키에 의해 데이터베이스 내에서 구별지워진다. 이 foreign 키는 
+                                그 콜렉션 테이블의 <emphasis>콜렉션 키 컬럼</emphasis> (또는 컬럼들)로서 참조된다. 그 콜렉션 키 컬럼은 
+                <literal>&lt;key&gt;</literal> 요소에 의해 매핑된다. 
+            </para>
+    
+            <para>
+                foreign 키 컬럼에 대한 null 허용 가능 컨스트레인트가 존재할 수 있다. 대부분의 콜렉션들에 대해, 이것이 당연히 수반된다. 
+                                단방향 one to many 연관들의 경우, foreign 키는 디폴트로 null 허용 가능하여서, 당신은  <literal>not-null="true"</literal>를 
+                                지정할 필요가 있을 수 있다.
+            </para>
+    
+            <programlisting><![CDATA[<key column="productSerialNumber" not-null="true"/>]]></programlisting>
+    
+            <para>
+                foreign 키 컨스트레인트는 <literal>ON DELETE CASCADE</literal>를 사용할 수도 있다.
+            </para>
+    
+            <programlisting><![CDATA[<key column="productSerialNumber" on-delete="cascade"/>]]></programlisting>
+            
+            <para>
+                <literal>&lt;key&gt;</literal> 요소에 대한 전체 정의는 앞 장을 보라.
+            </para>
+            
+        </sect2>
+        
+        <sect2 id="collections-elements" >
+            <title>콜렉션 요소들</title>
+    
+            <para>
+                                콜렉션들은 모든 기본 타입들, 컴포넌트들, 그리고 물론 다른 엔티티들에 대한 참조들을 포함하여 거의 대부분의 
+                                어떤 다른 Hibernate 타입을 포함할 수도 있다. 이것은 중요한 구분이다: 콜렉션 내에 있는 객체는 "값(value)" 
+                                의미로 처리될 수도 있거나(그것의 생명주기는 콜렉션 소유자에 의존한다) 그것은 그것 자신의 생명주기를 가진 
+                                또 다른 엔티티에 대한 참조일 수 있다. 후자의 경우, 두 개의 객체들 사이의 "링크" 만이 그 콜렉션에 의해 소유된 
+                                상태로 간주된다. 
+            </para>
+                
+            <para>
+                                포함된 타입은 콜렉션 요소 타입으로서 불려진다. 콜렉션 요소들은 <literal>&lt;element&gt;</literal> 
+                                또는 <literal>&lt;composite-element&gt;</literal>에 의해 매핑되거나, 엔티티 참조들의 경우에 
+                <literal>&lt;one-to-many&gt;</literal> 또는 <literal>&lt;many-to-many&gt;</literal>로서 
+                                매핑된다. 앞의 두 개는 value 의미를 가진 요소들을 매핑시키고, 뒤의 두개는 엔티티 연관들을 매핑하는데 사용된다. 
+            </para>
+            
+        </sect2>
+        
+        <sect2 id="collections-indexed">
+            <title>인덱싱 된 콜렉션들</title>
+    
+            <para>
+                set 과 bag 의미들을 가진 것들을 제외하면, 모든 콜렉션 매핑들은 콜렉션 테이블 내에 <emphasis>인덱스 컬럼</emphasis>-
+                                배열 인덱스, 또는 <literal>List</literal> 인덱스 또는 <literal>Map</literal> 키로 매핑되는  컬럼-을 필요로 한다. 
+                <literal>Map</literal>의 인덱스는 <literal>&lt;map-key&gt;</literal>로 매핑된, 어떤 기본 타입일 수 있고, 
+                                그것은 <literal>&lt;map-key-many-to-many&gt;</literal>로 매핑된 엔티티 참조일 수 있거나, 그것은 
+                <literal>&lt;composite-map-key&gt;</literal>로 매핑된 composite 타입일 수 있다. 배열 또는 리스트의 인덱스는 
+                                항상 <literal>integer</literal> 타입이고 <literal>&lt;list-index&gt;</literal> 요소를 사용하여 매핑된다. 
+                                매핑된 컬럼은 순차적인 정수들을 포함한다(디폴트로 0에서 시작하는 번호가 붙여짐).
+            </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="index1" coords="2 45"/>
+                <area id="index2" coords="3 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<list-index 
+        column="column_name"
+        base="0|1|..."/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="index1">
+                    <para>
+                        <literal>column_name</literal> (필수): 
+                                                콜렉션 인덱스 값들을 보관하는 컬럼의 이름.
+                    </para>
+                </callout>
+                <callout arearefs="index1">
+                    <para>
+                        <literal>base</literal> (옵션, 디폴트는 <literal>0</literal>): 
+                                                리스트 또는 배열의 첫 번째 요소에 대응하는 인덱스 컬럼의 값.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <programlistingco>
+            <areaspec>
+                <area id="mapkey1" coords="2 45"/>
+                <area id="mapkey2" coords="3 45"/>
+                <area id="mapkey3" coords="4 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<map-key 
+        column="column_name"
+        formula="any SQL expression"
+        type="type_name"
+        node="@attribute-name"
+        length="N"/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="mapkey1">
+                    <para>
+                        <literal>column</literal> (옵션): 
+                                                콜렉션 인덱스 값들을 보관하는 컬럼의 이름.
+                    </para>
+                </callout>
+                <callout arearefs="mapkey2">
+                    <para>
+                        <literal>formula</literal> (옵션): 
+                        map의 키를 평가하는데 사용되는 SQL formula.
+                    </para>
+                </callout>
+                <callout arearefs="mapkey3">
+                    <para>
+                        <literal>type</literal> (필수): The type of the map 키들의 타입
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <programlistingco>
+            <areaspec>
+                <area id="indexmanytomany1" coords="2 45"/>
+                <area id="indexmanytomany2" coords="3 45"/>
+                <area id="indexmanytomany3" coords="3 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<map-key-many-to-many
+        column="column_name"
+        formula="any SQL expression"
+        class="ClassName"
+/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="indexmanytomany1">
+                    <para>
+                        <literal>column</literal> (옵션): 
+                                                콜렉션 인덱스 값들에 대한 foreign 키 컬럼의 이름.
+                    </para>
+                </callout>
+                <callout arearefs="indexmanytomany2">
+                    <para>
+                        <literal>formula</literal> (옵션): 
+                        map의 foreign 키를 평가하는데 사용되는 SQL formula.
+                    </para>
+                </callout>
+                <callout arearefs="indexmanytomany3">
+                    <para>
+                        <literal>class</literal> (필수): map 키로서 사용되는 엔티티 클래스.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+
+            <para>
+                                만일 당신의 테이블이 인덱스 컬럼을 가지 않고, 당신이 여전히 프로퍼티 타입으로서 <literal>List</literal>를 사용하고자 
+                                원할 경우, 당신은 그 프로퍼티를 Hibernate <emphasis>&lt;bag&gt;</emphasis>으로서 매핑해야 한다. bag이 
+                                데이터베이스로부터 검색될 때 그것은 그것의 순서를 보유하지 않지만, 그것은 선택적으로 정렬(sorting)되거나 ordering될 
+                                수도 있다.
+            </para>
+            
+        </sect2>
+
+        <para>
+                        많은 공통된 관계형 모형들을 다루는, 콜렉션들에 대해 생성될 수 있는 매핑들의 영역이 꽤 존재한다. 여러가지 매핑 선언들이 데이터베이스 
+                        테이블들로 변환되는 방법을 당신이 느끼려면 스키마 생성 도구로 실험할 것을 우리는 제안한다.
+        </para>
+
+    <sect2 id="collections-ofvalues" revision="2">
+        <title>값들을 가진 콜렉션들과 many-to-many 연관들</title>
+
+        <para>
+                        어떤 값들을 가진 콜렉션 또는 many-to-many 연관은 foreign 키 컬럼이나 컬럼들, <emphasis>콜렉션 요소 컬럼</emphasis>이나 
+                        컬럼들 그리고 가능하면 인덱스 컬럼들이나 컬럼들을 가진 전용 <emphasis>콜렉션 테이블</emphasis>을 필요로 한다.
+        </para>
+
+        <para>
+                        값들을 가진 콜렉션의 경우, 우리는 <literal>&lt;element&gt;</literal> 태그를 사용한다.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="element1b" coords="2 50"/>
+                <area id="element2b" coords="3 50"/>
+                <area id="element3b" coords="4 50"/>
+             </areaspec>
+            <programlisting><![CDATA[<element
+        column="column_name"
+        formula="any SQL expression"
+        type="typename"
+        length="L"
+        precision="P"
+        scale="S"
+        not-null="true|false"
+        unique="true|false"
+        node="element-name"
+/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="element1b">
+                    <para>
+                        <literal>column</literal> (옵션): 콜렉션 요소 값들을 소유하는 컬럼의 이름.
+                    </para>
+                </callout>
+                <callout arearefs="element2b">
+                    <para>
+                        <literal>formula</literal> (옵션): 요소를 평가하는데 사용되는 SQL formula.
+                    </para>
+                </callout>
+                <callout arearefs="element3b">
+                    <para>
+                        <literal>type</literal> (필수): 콜렉션 요소의 타입.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <para>
+            <emphasis>many-to-many association</emphasis> 연관은  <literal>&lt;many-to-many&gt;</literal> 요소를 
+                        사용하여 지정된다.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="manytomany1" coords="2 60"/>
+                <area id="manytomany2" coords="3 60"/>
+                <area id="manytomany3" coords="4 60"/>
+                <area id="manytomany4" coords="5 60"/>
+                <area id="manytomany5" coords="6 60"/>
+                <area id="manytomany6" coords="7 60"/>
+                <area id="manytomany7" coords="8 60"/>
+                <area id="manytomany8" coords="9 60"/>
+            </areaspec>
+            <programlisting><![CDATA[<many-to-many
+        column="column_name"
+        formula="any SQL expression"
+        class="ClassName"
+        fetch="select|join"
+        unique="true|false"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        property-ref="propertyNameFromAssociatedClass"
+        node="element-name"
+        embed-xml="true|false"
+    />]]></programlisting>
+            <calloutlist>
+                <callout arearefs="manytomany1">
+                    <para>
+                        <literal>column</literal> (옵션): 요소 foreign 키 컬럼의 이름.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany2">
+                    <para>
+                        <literal>formula</literal> (옵션): 요소 foreign 키 값을 평가하는데 사용되는 SQL formula.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany3">
+                    <para>
+                        <literal>class</literal> (필수): 연관된 클래스의 이름.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany4">
+                    <para>
+                        <literal>fetch</literal> (옵션 - 디폴트는 <literal>join</literal>):
+                                                이 연관에 대해 outer-join 페칭 또는 sequential select 페칭을 이용 가능하게 만든다. 이것은 특별한 경우이다; 
+                                                엔티티 그리고 다른 엔티티들과 그것의 many-to-many 관계들에 대한 (하나의 <literal>SELECT</literal> 
+                                                내에서) 전체 eager 페칭의 경우, 당신은 콜렉션 그 자체에 대해서 뿐만 아니라 내포된 요소 <literal>&lt;many-to-many&gt;</literal> 
+                                                상의 이 속성에 대해 <literal>join</literal> 페칭을 이용 가능하게 할 것이다.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany5">
+                    <para>
+                        <literal>unique</literal> (옵션): 
+                        foreign-key 컬럼에 대한 유일 컨스트레인트의 DDL 생성을 가능하도록 한다. 이것은 연관 다중성
+                        (association multiplicity)을 효율적으로 one to many로 만든다.
+                    </para>
+                </callout>
+	            <callout arearefs="manytomany6">
+	                <para>
+	                    <literal>not-found</literal> (옵션 - 디폴트는 <literal>exception</literal>): 
+	                                        누락된 행들을 참조하는 foreign 키들이 어떻게 처리될 것인지를 지정한다: 
+                        <literal>ignore</literal>는 누락된 한 행을 한 개의 연관으로 다룰 것이다.
+	                </para>
+	            </callout>
+                <callout arearefs="manytomany7">
+                    <para>
+                        <literal>entity-name</literal> (옵션): <literal>class</literal>에 대한 하나의 대안으로서, 
+                                                연관된 클래스의 엔티티 이름.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany8">
+                    <para>
+                        <literal>property-ref</literal>: (옵션) 이 foreign 키에 조인된 연관 클래스의 프로퍼티의 이름. 
+                                                지정되지 않을 경우, 연관 클래스의 프라이머리 키가 사용된다.
+                    </para>                
+                </callout>    
+            </calloutlist>
+        </programlistingco>
+
+        <para>
+                        몇몇 예제들, 먼저 문자열들을 가진 set:
+        </para>
+
+        <programlisting><![CDATA[<set name="names" table="person_names">
+    <key column="person_id"/>
+    <element column="person_name" type="string"/>
+</set>]]></programlisting>
+
+        <para>
+            (<literal>order-by</literal> 속성에 의해 결정되는 반복 순서를 가진) 정수들을 포함하는 bag :
+        </para>
+
+        <programlisting><![CDATA[<bag name="sizes" 
+        table="item_sizes" 
+        order-by="size asc">
+    <key column="item_id"/>
+    <element column="size" type="integer"/>
+</bag>]]></programlisting>
+
+        <para>
+                        엔티티들을 가진 배열 - 이 경우에, many to many 연관 :
+        </para>
+
+        <programlisting><![CDATA[<array name="addresses" 
+        table="PersonAddress" 
+        cascade="persist">
+    <key column="personId"/>
+    <list-index column="sortOrder"/>
+    <many-to-many column="addressId" class="Address"/>
+</array>]]></programlisting>
+
+        <para>
+                        날짜들에 대한 문자열 인덱스들을 가진 map :
+        </para>
+
+        <programlisting><![CDATA[<map name="holidays" 
+        table="holidays" 
+        schema="dbo" 
+        order-by="hol_name asc">
+    <key column="id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+        <para>
+                        컴포넌트들의 리스트(다음 장에서 논의됨):
+        </para>
+
+        <programlisting><![CDATA[<list name="carComponents" 
+        table="CarComponents">
+    <key column="carId"/>
+    <list-index column="sortOrder"/>
+    <composite-element class="CarComponent">
+        <property name="price"/>
+        <property name="type"/>
+        <property name="serialNumber" column="serialNum"/>
+    </composite-element>
+</list>]]></programlisting>
+
+    </sect2>
+
+    <sect2 id="collections-onetomany">
+        <title>One-to-many 연관들</title>
+
+        <para>
+            <emphasis>one to many 연관</emphasis>은 중재하는 콜렉션 테이블 없이 foreign 키를 통해 두 개의 클래스들의 테이블들을 
+                        연결시킨다. 이 매핑은 통상의 자바 콜렉션들의 어떤 의미를 상실한다:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                                        포함된 엔티티 클래스의 인스턴스는 그 콜렉션의 하나 이상의 인스턴스에 속하지 않을 수 있다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        포함된 엔티티 클래스의 인스턴스는 콜렉션 인덱스의 하나 이상의 값에서 나타나지 않을 수 있다
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>Product</literal>로부터 <literal>Part</literal>로의 연관은 foreign 키 컬럼과 <literal>Part</literal> 
+                        테이블에 대한 인덱스 컬럼의 존재를 필요로 한다. <literal>&lt;one-to-many&gt;</literal> 태그는 이것이 one to many 
+                        연관임을 나타낸다.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="onetomany1" coords="2 60"/>
+                <area id="onetomany2" coords="3 60"/>
+                <area id="onetomany3" coords="4 60"/>
+            </areaspec>
+            <programlisting><![CDATA[<one-to-many 
+        class="ClassName"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        node="element-name"
+        embed-xml="true|false"
+    />]]></programlisting>
+            <calloutlist>
+                <callout arearefs="onetomany1">
+                    <para>
+                        <literal>class</literal> (필수): 연관된 클래스의 이름.
+                    </para>
+                </callout>
+		        <callout arearefs="onetomany2">
+		            <para>
+		                <literal>not-found</literal> (옵션 - 디폴트는 <literal>exception</literal>): 
+		                                누락된 행들을 참조하는 캐시된 식별자들이 어떻게 처리될 것인지를 지정한다:
+                        <literal>ignore</literal>는 누락된 한 행을 한 개의 연관으로 다룰 것이다. 
+		            </para>
+		        </callout>
+                <callout arearefs="onetomany3">
+                    <para>
+                        <literal>entity-name</literal> (옵션): <literal>class</literal>에 대한 대안으로서, 
+                                                연관된 클래스의 엔티티 이름. 
+                    </para>
+                </callout>
+            </calloutlist>
+       </programlistingco>
+  
+        <para>
+            <literal>&lt;one-to-many&gt;</literal> 요소는 어떤 컬럼들을 선언하는데 필요하지 않음을 주목하라. 어딘가에 
+            <literal>table</literal> 이름을 지정하는 것도 필수적이지 않다. 
+        </para>
+
+        <para>
+            <emphasis>매우 중요한 노트</emphasis>:  만일 <literal>&lt;one-to-many&gt;</literal> 연관의 foreign 키 컬럼이 
+            <literal>NOT NULL</literal>로 선언될 경우,  당신은 <literal>&lt;key&gt;</literal> 매핑을 <literal>not-null="true"</literal>로 
+                        선언해야 하거나 <literal>inverse="true"</literal>로 마크된 콜렉션 매핑을 가진 <emphasis>양방향 연관을 사용해야 한다</emphasis>. 
+                        양방향 연관들에 대한 논의는 이 장의 뒷부분을 보라.
+        </para>
+        
+        <para>
+                        이 예제는 name으로 <literal>Part</literal> 엔티티들을 가진 map을 보여준다(여기서 <literal>partName</literal>은 
+            <literal>Part</literal>의 영속 프로퍼티이다). formula-기반 index의 사용을 주목하라. 
+        </para>
+
+        <programlisting><![CDATA[<map name="parts"
+        cascade="all">
+    <key column="productId" not-null="true"/>
+    <map-key formula="partName"/>
+    <one-to-many class="Part"/>
+</map>]]></programlisting>
+    </sect2>
+    
+    </sect1>
+
+    <sect1 id="collections-advancedmappings">
+        <title>개선된 콜렉션 매핑들</title>
+
+    <sect2 id="collections-sorted" revision="2">
+        <title>Sorted 콜렉션들</title>
+
+        <para>
+            Hibernate는 <literal>java.util.SortedMap</literal>과 <literal>java.util.SortedSet</literal>를 구현하는 
+                        콜렉션들을 지원한다. 당신은 매핑 파일 속에 하나의 comparator를 지정해야 한다:
+        </para>
+
+        <programlisting><![CDATA[<set name="aliases" 
+            table="person_aliases" 
+            sort="natural">
+    <key column="person"/>
+    <element column="name" type="string"/>
+</set>
+
+<map name="holidays" sort="my.custom.HolidayComparator">
+    <key column="year_id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            <literal>sort</literal> 속성에 허용되는 값들은 <literal>unsorted</literal>, <literal>natural</literal>, 
+                        그리고 <literal>java.util.Comparator</literal>를 구현하는 클래스의 이름이다.
+        </para>
+
+        <para>
+            Sorted 콜렉션들은 <literal>java.util.TreeSet</literal> 또는 <literal>java.util.TreeMap</literal>처럼 행동한다.
+        </para>
+
+        <para>
+                        만일 당신이 데이터베이스 그 자체가 콜렉션 요소들을 순서지우도록(order)원할 경우 <literal>set</literal>, 
+            <literal>bag</literal> 또는<literal>map</literal> 매핑들에 대해 <literal>order-by</literal> 속성을 사용하라. 
+                        이 해결책은 JDK 1.4 이상의 버전에서만 이용 가능하다(그것은 <literal>LinkedHashSet</literal> 또는 <literal>LinkedHashMap</literal>을 
+                        사용하여 구현된다). 이것은 메모리 내가 아닌, SQL 질의 내에서 순서지움(ordering)을 수행한다. 
+        </para>
+
+        <programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="lower(name) asc">
+    <key column="person"/>
+    <element column="name" type="string"/>
+</set>
+
+<map name="holidays" order-by="hol_date, hol_name">
+    <key column="year_id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            <literal>order-by</literal> 속성의 값은 HQL 순서지움(ordering)이 아니라 SQL 순서지움(ordering)임을 노트하라!
+        </para>
+
+        <para>
+                        연관들은 콜렉션 <literal>filter()</literal>를 사용하여 실행 시에 어떤 임의의 criteria(기준)을 사용하여 정렬(sort)될 
+                        수도 있다.
+        </para>
+
+        <programlisting><![CDATA[sortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list();]]></programlisting>
+
+    </sect2>
+
+     <sect2 id="collections-bidirectional" revision="1">
+        <title>양방향 연관들</title>
+
+        <para>
+            <emphasis>양방향 연관</emphasis>은 연관의 양 "끝(end)들"로부터 네비게이션을 허용한다. 
+                        두 가지 종류의 양방향 연관들이 지원된다: 
+
+            <variablelist>
+                <varlistentry>
+                    <term>one-to-many</term>
+                    <listitem>
+                        <para>
+                                                        한쪽 끝에 set 또는 bag 값을 갖고, 다른 쪽 긑에 단일 값을 가진 연관
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>many-to-many</term>
+                    <listitem>
+                        <para>
+                                                        양 끝에서 set 또는 bag 값을 가진 연관 
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+        </para>
+
+        <para>
+                        당신은 동일한 두 개의 many-to-many 연관들을 동일한 데이터베이스 테이블로 간단하게 매핑하고 한 쪽 끝을 
+            <emphasis>inverse</emphasis>(당신의 선택은 하나이지만, 그것은 인덱싱된 콜렉션일 수 없다)로 선언함으로써 하나의 양방향 
+            many-to-many 연관을 지정할 수도 있다.
+        </para>
+
+        <para>
+                        다음은 양방향 many-to-many 연관에 관한 예제이다; 각각의 카테고리는 많은 아이템들을 가질 수 있고 각각의 아이템은 많은 
+                        카테고리들 속에 있을 수 있다:
+        </para>
+
+        <programlisting><![CDATA[<class name="Category">
+    <id name="id" column="CATEGORY_ID"/>
+    ...
+    <bag name="items" table="CATEGORY_ITEM">
+        <key column="CATEGORY_ID"/>
+        <many-to-many class="Item" column="ITEM_ID"/>
+    </bag>
+</class>
+
+<class name="Item">
+    <id name="id" column="CATEGORY_ID"/>
+    ...
+
+    <!-- inverse end -->
+    <bag name="categories" table="CATEGORY_ITEM" inverse="true">
+        <key column="ITEM_ID"/>
+        <many-to-many class="Category" column="CATEGORY_ID"/>
+    </bag>
+</class>]]></programlisting>
+
+        <para>
+                        연관의 inverse 끝(end)에 대해서만 행해진 변경들은  영속화 되지 <emphasis>않는다</emphasis>. 이것은 Hibernate가 
+                        모든 양방향 연관에 대해 메모리 내에 두 개의 표상들을 갖는다는 점을 의미한다: A로부터 B로의 하나의 링크와 B로부터 A로의 또 다른 링크. 
+                        만일 당신이 자바 객체 모형에 대해 그리고 자바에서 many-to-many 관계를 생성시키는 방법에 대해 생각하면 이것은 이해하기가 더 쉽다:
+        </para>
+
+        <programlisting><![CDATA[
+category.getItems().add(item);          // The category now "knows" about the relationship
+item.getCategories().add(category);     // The item now "knows" about the relationship
+
+session.persist(item);                   // The relationship won't be saved!
+session.persist(category);               // The relationship will be saved]]></programlisting>
+
+        <para>
+            non-inverse 측은 메모리 내 표상을 데이터베이스로 저장하는데 사용된다.
+        </para>
+
+        <para>
+                        당신은 하나의 one-to-many 연관을 하나의 many-to-one 연관으로서 동일한 테이블 컬럼(들)로 매핑하고 many-값을 가진 끝(end)을 
+            <literal>inverse="true"</literal>로 선언함으로써 하나의 양방향 연관을 정의할 수도 있다. 
+        </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <set name="children" inverse="true">
+        <key column="parent_id"/>
+        <one-to-many class="Child"/>
+    </set>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        not-null="true"/>
+</class>]]></programlisting>
+
+        <para>
+                        연관의 한쪽 끝을 <literal>inverse="true"</literal>로 매핑하는 것은 cascade들을 가진 오퍼레이션에 영향을 주지 않으며, 
+                        이것들은 orthogonal(직교) 개념들이다!
+        </para>
+
+    </sect2>
+    
+    <sect2 id="collections-indexedbidirectional">
+        <title>인덱싱된 콜렉션들을 가진 양방향 연관들</title>
+        <para>
+                        한쪽 끝이 하나의 <literal>&lt;list&gt;</literal> 또는 <literal>&lt;map&gt;</literal>으로서 표현되는 양방향  
+                        연관은 특별한 검토를 필요로 한다. 만일 인덱스 컬럼으로 매핑되는 child 클래스의 프로퍼티가 하나 존재한다면 문제가 없고, 
+                        우리는 콜렉션 매핑 상에 <literal>inverse="true"</literal>를 사용하여 계속할 수 있다:
+        </para>
+        
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <map name="children" inverse="true">
+        <key column="parent_id"/>
+        <map-key column="name" 
+            type="string"/>
+        <one-to-many class="Child"/>
+    </map>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <property name="name" 
+        not-null="true"/>
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        not-null="true"/>
+</class>]]></programlisting>
+
+        <para>
+                        그러나 만일 child 클래스 상에 그런 프로퍼티가 존재하지 않을 경우, 우리는 그 연관을 진정하게 양방향으로 간주할 수 없다
+            (다른 쪽 끝에서 이용가능하지 않은 그 연관의 끝에서 이용 가능한 정보가 존재한다). 이 경우에 우리는 그 콜렉션을 
+            <literal>inverse="true"</literal>로 매핑시킬 수 없다. 대신에 우리는 다음 매핑을 사용할 수 있다:
+        </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <map name="children">
+        <key column="parent_id"
+            not-null="true"/>
+        <map-key column="name" 
+            type="string"/>
+        <one-to-many class="Child"/>
+    </map>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        insert="false"
+        update="false"
+        not-null="true"/>
+</class>]]></programlisting>
+
+       <para>
+                      이 매핑에서 그 연관의 콜렉션 값을 가진 끝이 foreign 키에 대한 업데이트 책임이 있음을 노트하라.
+       </para>
+
+    </sect2>
+    
+    <sect2 id="collections-ternary">
+        <title>Ternary associations(세겹 연관들)</title>
+
+        <para>
+                        세 겹의 연관을 매핑하는 세 가지 가능한 접근법들이 존재한다. 하나의 접근법은 그것의 인덱스로서 연관관계를 가진 
+            <literal>Map</literal>을 사용하는 것이다:
+        </para>
+
+        <programlisting><![CDATA[<map name="contracts">
+    <key column="employer_id" not-null="true"/>
+    <map-key-many-to-many column="employee_id" class="Employee"/>
+    <one-to-many class="Contract"/>
+</map>]]></programlisting>
+            
+            <programlisting><![CDATA[<map name="connections">
+    <key column="incoming_node_id"/>
+    <map-key-many-to-many column="outgoing_node_id" class="Node"/>
+    <many-to-many column="connection_id" class="Connection"/>
+</map>]]></programlisting>
+            
+        <para>
+                        두 번째 접근법은 그 연관을 엔티티 클래스로서 단순하게 리모델링 하는 것이다. 이것은 우리가 가장 공통적으로 사용하는 접근법이다.
+        </para>
+        
+        <para>
+                        마지막 대안은 우리가 나중에 논의하게 될 composite 요소들을 사용하는 것이다. 
+        </para>
+        
+    </sect2>
+    
+    <sect2 id="collections-idbag" revision="1">
+        <title><literal>&lt;idbag&gt;</literal> 사용하기</title>
+
+        <para>
+                       만일 당신이 composite 키들이 나쁜 것이고 엔티티들이 합성 식별자들(대용 키들, surrogate keys)을 가져야 한다는 
+                       우리의 견해를 전적으로 수용할 경우, 당신은 우리가 지금까지 보여주었던 값들을 가진 콜렉션들과 many to many 연관들이 모두 
+            composite 키들을 가진 테이블들로 매핑된다는 약간 이상한 점을 발견할 수도 있다! 이제 이 점은 꽤 논의의 여지가 있다; 순수한 
+                        연관 테이블은 (비록 composite 값들을 가진 콜렉션<emphasis>일 수도</emphasis> 있을지라도) 대용 키로부터 많은 이점을 
+                        취하지 않는 것처럼 보인다. 그럼에도 불구하고 Hibernate는 당신이 값들을 가진 콜렉션들과 many to many 연관들을 대용 키를 가진 
+                        테이블로 매핑시키는 것을 당신에게 허용해주는 특징을 제공한다.
+        </para>
+
+        <para>
+            <literal>&lt;idbag&gt;</literal> 요소는 bag 의미를 가진 <literal>List</literal>(또는 <literal>Collection</literal>)을 
+                        매핑하도록 당신에게 허용해준다.
+        </para>
+
+<programlisting><![CDATA[<idbag name="lovers" table="LOVERS">
+    <collection-id column="ID" type="long">
+        <generator class="sequence"/>
+    </collection-id>
+    <key column="PERSON1"/>
+    <many-to-many column="PERSON2" class="Person" fetch="join"/>
+</idbag>]]></programlisting>
+
+        <para>
+                        당신이 볼 수 있듯이, <literal>&lt;idbag&gt;</literal>은 마치 엔티티 클래스인양 synthetic id generator(합성 id 생성기)를 
+                        갖는다! 다른 대용 키는 각각의 콜렉션 행에 할당된다. 하지만 Hibernate는 특정 행의 대용 키 값을 발견하는 메커니즘을 제공하지 않는다.
+        </para>
+
+        <para>
+            <literal>&lt;idbag&gt;</literal>의 업데이트 퍼포먼스는 정규 <literal>&lt;bag&gt;</literal> 보다 훨씬 좋다는 점을 
+                        노트하라! Hibernate는 마치 list, map, 또는 set인양, 개별 행들을 효율적으로 위치지울 수 있고 그것들을 개별적으로 업데이트 
+                        하거나 삭제시킬 수 있다.
+        </para>
+
+        <para>
+                        현재 구현에서, <literal>native</literal> 식별자 생성 방도는 <literal>&lt;idbag&gt;</literal> 콜렉션 식별자들에 대해 
+                        지원되지 않는다.
+        </para>
+
+    </sect2>
+
+    </sect1>
+    
+    <!--다음 요소를 문서화하지 않음 -->
+    
+    <!--sect1 id="collections-heterogeneous">
+        <title>Heterogeneous Associations</title>
+
+        <para>
+            <literal>&lt;many-to-any&gt;</literal>와 <literal>&lt;index-many-to-any&gt;</literal> 요소들은 
+                        진정한 이종의(heterogeneous) 연관들을 제공한다. 이들 매핑 요소들은 <literal>&lt;any&gt;</literal> 요소와 
+                        동일한 방법으로 동작한다 - 그리고 또한 아마 드물게 사용될 수 있을 것이다. 
+        </para>
+
+    </sect1-->
+
+    <sect1 id="collections-example" revision="1">
+        <title>콜렉션 예제들</title>
+
+        <para>
+                        앞의 절들은 꽤 혼동스럽다. 따라서 예제를 살펴보자. 다음 클래스:
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+
+public class Parent {
+    private long id;
+    private Set children;
+
+    public long getId() { return id; }
+    private void setId(long id) { this.id=id; }
+
+    private Set getChildren() { return children; }
+    private void setChildren(Set children) { this.children=children; }
+
+    ....
+    ....
+}]]></programlisting>
+
+        <para>
+                        는 <literal>Child</literal> 인스턴스들을 가진 하나의 콜렉션을 갖고 있다. 만일 각각의 자식이 최소한 한 개의 부모를 가질 경우, 
+                        대부분의 고유한 매핑은 one-to-many 연관이다:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children">
+            <key column="parent_id"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+                       이것은 다음 테이블 정의들로 매핑된다:
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255), parent_id bigint )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+        <para>
+                        만일 부모가 <emphasis>필수적</emphasis>이라면, 양방향 one-to-many 연관관계를 사용하라:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children" inverse="true">
+            <key column="parent_id"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+        <many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            <literal>NOT NULL</literal> 컨스트레인트를 주목하라:
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null
+                     primary key,
+                     name varchar(255),
+                     parent_id bigint not null )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+        <para>
+                        대안적으로, 만일 당신이 이 연관관계가 단방향이어야 함을 절대적으로 역설할 경우, 당신은 <literal>&lt;key&gt;</literal> 
+                        매핑 상에 <literal>NOT NULL</literal> 컨스트레인트를 선언할 수 있다:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children">
+            <key column="parent_id" not-null="true"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+                        반면에, 만일 자식이 여러 부모들을 가질 수 있을 경우, many-to-many 연관이 적절하다:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children" table="childset">
+            <key column="parent_id"/>
+            <many-to-many class="Child" column="child_id"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+                        테이블 정의들:
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255) )
+create table childset ( parent_id bigint not null,
+                        child_id bigint not null,
+                        primary key ( parent_id, child_id ) )
+alter table childset add constraint childsetfk0 (parent_id) references parent
+alter table childset add constraint childsetfk1 (child_id) references child]]></programlisting>
+
+        <para>
+                        부모/자식 관계 매핑을 연습하는 더 많은 예제들과 전체 리허설은 <xref linkend="example-parentchild"/>를 보라.
+        </para>
+        
+        <para>
+                        비록 더 많은 신종 연관 매핑들이 가능할지라도, 우리는 다음 장에서 모든 가능성들을 분류할 것이다.
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/component_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/component_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/component_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,373 @@
+<chapter id="components">
+    <title>Component 매핑</title>
+
+    <para>
+        <emphasis>component</emphasis>의 개념은 Hibernate에서 다른 용도로 몇몇 다른 컨텍스트들 내에서 재사용된다.
+    </para>
+
+    <sect1 id="components-dependentobjects" revision="2" >
+        <title>종속 객체들</title>
+
+        <para>
+                        하나의 컴포넌트는 엔티티 참조가 아닌, value 타입으로서 영속화 되는 하나의 포함된 객체이다. "컴포넌트" 용어는 
+            (아키텍처 수준의 컴포넌트들이 아닌) composition(구성,합성)에 대한 객체-지향적인 개념을 언급한다. 
+                        예를 들어 당신은 다음과 같이 개인을 모형화 시킬 수도 있다:
+        </para>
+
+        <programlisting><![CDATA[public class Person {
+    private java.util.Date birthday;
+    private Name name;
+    private String key;
+    public String getKey() {
+        return key;
+    }
+    private void setKey(String key) {
+        this.key=key;
+    }
+    public java.util.Date getBirthday() {
+        return birthday;
+    }
+    public void setBirthday(java.util.Date birthday) {
+        this.birthday = birthday;
+    }
+    public Name getName() {
+        return name;
+    }
+    public void setName(Name name) {
+        this.name = name;
+    }
+    ......
+    ......
+}]]></programlisting>
+
+<programlisting><![CDATA[public class Name {
+    char initial;
+    String first;
+    String last;
+    public String getFirst() {
+        return first;
+    }
+    void setFirst(String first) {
+        this.first = first;
+    }
+    public String getLast() {
+        return last;
+    }
+    void setLast(String last) {
+        this.last = last;
+    }
+    public char getInitial() {
+        return initial;
+    }
+    void setInitial(char initial) {
+        this.initial = initial;
+    }
+}]]></programlisting>
+
+        <para>
+                        이제 <literal>Name</literal>은 <literal>Person</literal>의 컴포넌트로서 영속화 될 수도 있다. <literal>Name</literal>이 
+                        그것의 영속 프로퍼티들에 대한 getter 메소드와 setter 메소드를 정의하지만, 어떤 인터페이스들이나 식별자 프로퍼티들을 선언하는 것을 
+                        필요로 하지 않음을 주목하라.
+        </para>
+
+        <para>
+                        우리의 Hibernate 매핑은 다음과 같을 것이다:
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Person" table="person">
+    <id name="Key" column="pid" type="string">
+        <generator class="uuid"/>
+    </id>
+    <property name="birthday" type="date"/>
+    <component name="Name" class="eg.Name"> <!-- class attribute optional -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </component>
+</class>]]></programlisting>
+
+        <para>
+            person 테이블은 
+            <literal>pid</literal>, 
+            <literal>birthday</literal>, 
+            <literal>initial</literal>, 
+            <literal>first</literal>, 
+            <literal>last</literal> 컬럼들을 가질 것이다.
+        </para>
+
+        <para>
+                        모든 값(value) 타입들처럼, 컴포넌트들은 공유된 참조들을 지원하지 않는다. 달리 말해, 두 명의 개인들은 동일한 이름을 가질 수 
+                        있지만, 두 개의 person 객체들은 오직 값 만이 "동일한" 두 개의 독립적인 name 객체들을 포함할 것이다. 컴포넌트의 null 값 의미는 
+            <emphasis>특별한 용도를 위한 것이다</emphasis>. 포함된 객체를 다시 로드시킬 때, Hibernate는 모든 컴포넌트 컬럼들이 
+            null일 경우에 전체 컴포넌트가 null이라고 가정할 것이다. 이것은 대부분의 용도에 맞을 것이다. 
+        </para>
+
+        <para>
+                        컴포넌트의 프로퍼티들은 임의의 Hibernate 타입일 수 있다(콜렉션들, many-to-one 연관들, 다른 컴포넌트들, 기타). 
+                        내포된 컴포넌트들은 신종의 사용례로 간주되지 <emphasis>않을</emphasis> 것이다. Hibernate는 매우 잘 정제된 객체 모형을 
+                        지원하도록 고안되어있다.
+        </para>
+
+        <para>
+            <literal>&lt;component&gt;</literal> 요소는 컴포넌트 클래스의 프로퍼티를 포함되는 엔티티에 대한 역 참조로서 매핑시키는 
+            <literal>&lt;parent&gt;</literal> 서브요소를 허용한다.
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Person" table="person">
+    <id name="Key" column="pid" type="string">
+        <generator class="uuid"/>
+    </id>
+    <property name="birthday" type="date"/>
+    <component name="Name" class="eg.Name" unique="true">
+        <parent name="namedPerson"/> <!-- reference back to the Person -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </component>
+</class>]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="components-incollections" revision="1">
+        <title>종속 객체들을 가진 콜렉션들</title>
+
+        <para>
+                        컴포넌트들을 가진 콜렉션들이 지원된다(예를 들면 <literal>Name</literal> 타입을 가진 배열). 
+            <literal>&lt;element&gt;</literal> 태그를 <literal>&lt;composite-element&gt;</literal> 태그로 
+                        대체시켜서 당신의 컴포넌트 콜렉션을 선언하라.
+        </para>
+
+        <programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
+    <key column="id"/>
+    <composite-element class="eg.Name"> <!-- class attribute required -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </composite-element>
+</set>]]></programlisting>
+
+        <para>
+                        노트: 만일 당신이 composite 요소를 가진 하나의 <literal>Set</literal>를 정의할 경우, <literal>equals()</literal>와 
+            <literal>hashCode()</literal>를 정확하게 구현하는 것이 매우 중요하다.
+        </para>
+
+        <para>
+            Composite 요소들은 컴포넌트들을 포함하지만 콜렉션들을 포함하지 않는다. 만일 당신의 composite 요소 자체가 컴포넌트들을 포함할 
+                        경우, <literal>&lt;nested-composite-element&gt;</literal> 태그를 사용하라. 이것은 꽤 신종의 경우-그것들 자체가 
+                        컴포넌트들을 갖고 있는 컴포넌트들의 콜렉션-이다. 이 단계에서 당신은 one-to-many 연관이 더 적절한지를 당신 스스로에게 질문하게 
+                        될 것이다. 하나의 엔티티로서 composite 요소를 다시 모델링하려고 시도하라 - 그러나 자바 모형들이 동일할지라도, 
+                        관계형 모형과 영속화 의미들은 여전히 약간 다르다.
+        </para>
+
+        <para>
+                        당신이 하나의 <literal>&lt;set&gt;</literal>을 사용 중이라면, 하나의 composite 요소 매핑은 null 가능한 프로퍼티들을 
+                        지원하지 않음을 노트하길 바란다. Hibernate는 객체들을 삭제할 때 하나의 레코드를 식별하는데 각각의 컬럼들 값을 사용해야 하며
+            (composite 요소 테이블 내에 별도의 프라이머리 키 컬럼이 존재하지 않는다), 그것은 null 값들에 대해서는 불가능하다. 당신은 
+                        하나의 composite-요소 내에 not-null 프로퍼티들 만을 사용해야 하거나  하나의 <literal>&lt;list&gt;</literal>, 
+            <literal>&lt;map&gt;</literal>, <literal>&lt;bag&gt;</literal> 또는 <literal>&lt;idbag&gt;</literal>을 
+                        선택해야 한다.
+        </para>
+
+        <para>
+            composite 요소에 대한 하나의 특별한 경우는 내포된 <literal>&lt;many-to-one&gt;</literal> 요소를 가진 composite 요소이다. 
+                        이같은 매핑은 many-to-many 연관 테이블의 특별한 컬럼들을 composite 요소 클래스로 매핑시키는 것을 당신에게 허용해준다. 다음은 
+            <literal>Order</literal>로부터 <literal>Item</literal>으로의 many-to-many 연관이다. 여기서 
+            <literal>purchaseDate</literal>, <literal>price</literal>, 그리고 <literal>quantity</literal>는 연관의 
+                        프로퍼티들이다:
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Order" .... >
+    ....
+    <set name="purchasedItems" table="purchase_items" lazy="true">
+        <key column="order_id">
+        <composite-element class="eg.Purchase">
+            <property name="purchaseDate"/>
+            <property name="price"/>
+            <property name="quantity"/>
+            <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+                        물론, 양방향 연관 네비게이션의 경우, 다른 측 상에 있는 purchase에 대한 참조가 존재할 수 없다. 컴포넌트들이 값(value) 타입들이고 
+                        공유된 참조들을 허용하지 않음을 기억하라. 하나의 <literal>Purchase</literal>는<literal>Order</literal>를 가진 set 
+                        내에 있을 수 있지만, 그것은 동시에 <literal>Item</literal>에 의해 참조될 수 없다.
+        </para>
+
+        <para>심지어 세겹의(또는 네 겹의, 기타) 연관들이 가능하다:</para>
+
+        <programlisting><![CDATA[<class name="eg.Order" .... >
+    ....
+    <set name="purchasedItems" table="purchase_items" lazy="true">
+        <key column="order_id">
+        <composite-element class="eg.OrderLine">
+            <many-to-one name="purchaseDetails class="eg.Purchase"/>
+            <many-to-one name="item" class="eg.Item"/>
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            composite 요소들은 다른 엔티티들에 대한 연관들과 동일한 구문을 사용하여 질의들 내에 나타날 수도 있다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="components-asmapindex">
+        <title>Map 인덱스들로서 컴포넌트들</title>
+
+        <para>
+            <literal>&lt;composite-map-key&gt;</literal> 요소는 당신에게 하나의 컴포넌트 클래스를 하나의 <literal>Map</literal>의 
+                        키로서 매핑시키도록 한다. 당신은 컴포넌트 클래스 상에서 <literal>hashCode()</literal>와 <literal>equals()</literal>를 
+                        정확하게 오버라이드 시키도록 하라.
+        </para>
+    </sect1>
+
+    <sect1 id="components-compositeid" revision="1">
+        <title>composite 식별자들로서 컴포넌트들</title>
+
+        <para>
+                        당신은 하나의 컴포넌트를 하나의 엔티티 클래스에 대한 하나의 식별자로서 사용할 수도 있다. 당신의 컴포넌트 클래스는 어떤 사양들을 
+                        충족시켜야 한다: 
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                                        그것은 <literal>java.io.Serializable</literal>을 구현해야 한다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        그것은 composite 키 등가(equality)에 대한 데이터베이스 개념과 일치되게, <literal>equals()</literal>와 
+                    <literal>hashCode()</literal>를 다시 구현해야 한다.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            <emphasis>노트: Hibernate3에서, 두 번째 사양은 Hibernate의 절대적으로 엄격한 사양이 아니다. 
+                        그러나 아무튼 그것을 행하라.</emphasis>
+        </para>
+
+        <para>
+                        당신은 compsite 키들을 생성시키는데 <literal>IdentifierGenerator</literal>를 사용할 수 없다. 대신에 어플리케이션은 
+                        그것 자신의 식별자들을 할당해야 한다.
+        </para>
+
+        <para>
+                        통상의 <literal>&lt;id&gt;</literal> 선언 위치에 (내포된 <literal>&lt;key-property&gt;</literal> 요소들을 가진) 
+            <literal>&lt;composite-id&gt;</literal> 태그를 사용하라. 예를 들어, <literal>OrderLine</literal> 클래스는 
+            <literal>Order</literal>의 (composite) 프라이머리 키에 의존하는 프라이머리 키를 갖는다. 
+        </para>
+
+        <programlisting><![CDATA[<class name="OrderLine">
+    
+    <composite-id name="id" class="OrderLineId">
+        <key-property name="lineId"/>
+        <key-property name="orderId"/>
+        <key-property name="customerId"/>
+    </composite-id>
+    
+    <property name="name"/>
+    
+    <many-to-one name="order" class="Order"
+            insert="false" update="false">
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </many-to-one>
+    ....
+    
+</class>]]></programlisting>
+
+        <para>
+                        이제 <literal>OrderLine</literal> 테이블을 참조하는 임의의 foreign 키들이 또한 compsite이다. 당신은 다른 클래스들에 대한 
+                        당신의 매핑들 속에 이것을 선언해야 한다. <literal>OrderLine</literal>에 대한 하나의 연관은 다음과 같이 매핑될 것이다:
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
+<!-- the "class" attribute is optional, as usual -->
+    <column name="lineId"/>
+    <column name="orderId"/>
+    <column name="customerId"/>
+</many-to-one>]]></programlisting>
+
+        <para>
+            (<literal>&lt;column&gt;</literal> 태그가 모든 곳에서 <literal>column</literal> 속성에 대한 대안임을 노트하라.) 
+        </para>
+        
+        <para>
+            <literal>OrderLine</literal>에 대한 <literal>many-to-many</literal> 연관은 또한 composite foreign 키를 사용한다:
+        </para>
+    
+    <programlisting><![CDATA[<set name="undeliveredOrderLines">
+    <key column name="warehouseId"/>
+    <many-to-many class="OrderLine">
+        <column name="lineId"/>
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </many-to-many>
+</set>]]></programlisting>
+
+        <para>
+            <literal>Order</literal>에서 <literal>OrderLine</literal>들의 콜렉션이 사용될 것이다: 
+        </para>
+
+    <programlisting><![CDATA[<set name="orderLines" inverse="true">
+    <key>
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </key>
+    <one-to-many class="OrderLine"/>
+</set>]]></programlisting>
+
+        <para>
+            (통상적으로 <literal>&lt;one-to-many&gt;</literal> 요소는 컬럼들을 선언하지 않는다.)
+        </para>
+        
+        <para>
+                        만일 <literal>OrderLine</literal> 자체가 하나의 콜렉션을 소유할 경우, 그것은 또한 하나의 composite foreign 키를 갖는다.
+        </para>
+
+        <programlisting><![CDATA[<class name="OrderLine">
+    ....
+    ....
+    <list name="deliveryAttempts">
+        <key>   <!-- a collection inherits the composite key type -->
+            <column name="lineId"/>
+            <column name="orderId"/>
+            <column name="customerId"/>
+        </key>
+        <list-index column="attemptId" base="1"/>
+        <composite-element class="DeliveryAttempt">
+            ...
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="components-dynamic" revision="1">
+        <title>동적인 컴포넌트들</title>
+
+        <para>
+                        당신은 <literal>Map</literal> 타입의 프로퍼티를 매핑시킬 수도 있다:
+        </para>
+
+    <programlisting><![CDATA[<dynamic-component name="userAttributes">
+    <property name="foo" column="FOO" type="string"/>
+    <property name="bar" column="BAR" type="integer"/>
+    <many-to-one name="baz" class="Baz" column="BAZ_ID"/>
+</dynamic-component>]]></programlisting>
+
+        <para>
+            <literal>&lt;dynamic-component&gt;</literal> 매핑의 의미는 <literal>&lt;component&gt;</literal>와 동일하다. 
+                        이런 종류의 매핑의 장점은 배치 시에 단지 매핑 문서를 편집함으로써 그 bean의 실제 프로퍼티들을 결정하는 가용성이다. 매핑 문서에 
+                        대한 런타임 처리는 또한 DOM 파서를 사용하여 가능하다. 더 좋게는 당신이 <literal>Configuration</literal> 객체를 통해 
+            Hibernate의 구성-시 메타모형에 접근할 수 있다(그리고 변경시킬 수 있다)
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/configuration.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/configuration.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/configuration.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1648 @@
+<chapter id="session-configuration" revision="1">
+
+    <title>구성</title>
+    
+    <para>
+        Hibernate가 많은 다른 환경들에서 동작하도록 설계되어 있으므로, 많은 개수의 구성 파라미터들이 존재한다. 다행히 대부분은 유의미한 
+                디폴트 값들이고 Hibernate는 다양한 옵션들을 보여주는 <literal>etc/</literal> 내의 예제 파일 <literal>hibernate.properties</literal>로 
+                배포된다. 당신은 단지 당신의 classpath 경로 속에 그 파일을 집어넣고 그것을 커스트마이징하기만 해야 한다.
+    </para>
+
+    <sect1 id="configuration-programmatic" revision="1">
+        <title>프로그램 상의 구성</title>
+
+        <para>
+            <literal>org.hibernate.cfg.Configuration</literal>의 인스턴스는 어플리케이션의 Java 타입들을 SQL 데이터베이스 
+                        타입으로의 전체 매핑 집합을 표현한다. <literal>Configuration</literal>은 (불변의) <literal>SessionFactory</literal>를 
+                        빌드하는데 사용된다. 매핑들은 여러 XML 매핑 파일들로부터 컴파일 된다.
+        </para>
+
+        <para>
+                        당신은 <literal>Configuration</literal> 인스턴스를 초기화 시키고 XML 매핑 문서들을 지정함으로써 <literal>Configuration</literal> 
+                        인스턴스를 얻을 수 있다. 만일 매핑 파일들이 classpath 내에 있다면, <literal>addResource()</literal>를 사용하라: 
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addResource("Item.hbm.xml")
+    .addResource("Bid.hbm.xml");]]></programlisting>
+
+        <para>
+            (때때로 더 나은) 다른 방법은 매핑된 클래스를 지정하는 것이고, Hibernate로 하여금 당신을 위해 매핑 문서를 찾도록 하라:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addClass(org.hibernate.auction.Item.class)
+    .addClass(org.hibernate.auction.Bid.class);]]></programlisting>
+
+        <para>
+                        그때 Hibernate는 classpath 내에서 <literal>/org/hibernate/auction/Item.hbm.xml</literal>과 
+            <literal>/org/hibernate/auction/Bid.hbm.xml</literal>로 명명된 매핑 파일들을 룩업할 것이다. 이 접근법은 
+                        임의의 하드코딩된 파일 이름들을 제거한다.
+        </para>
+        
+        <para>
+            <literal>Configuration</literal>은 또한 구성 프로퍼티들을 지정하는 것을 허용해준다:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addClass(org.hibernate.auction.Item.class)
+    .addClass(org.hibernate.auction.Bid.class)
+    .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
+    .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
+    .setProperty("hibernate.order_updates", "true");]]></programlisting>
+    
+        <para>
+                        이것은 컨피그레이션 프로퍼티들을 Hibernate에 전달하는 유일한 방법이 아니다. 여러 가지 옵션들은 다음을 포함한다:
+        </para>
+
+        <orderedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>java.util.Properties</literal>의 인스턴스를 <literal>Configuration.setProperties()</literal>에 
+                                        전달한다 .
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    classpath의 루트 디렉토리에 <literal>hibernate.properties</literal>를 위치지운다. 
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>java -Dproperty=value</literal>를 사용하여 <literal>System</literal> 프로퍼티들을 설정한다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>hibernate.cfg.xml</literal>에 <literal>&lt;property&gt;</literal> 요소들을 포함한다
+                    (나중에 논의됨). 
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <para>
+                        당신이 빠르게 시작하고 원할 경우 <literal>hibernate.properties</literal>는 가장 쉬운 접근법이다.
+        </para>
+
+        <para>
+            <literal>Configuration</literal>은 시작 시(startup-time) 객체로서 일단 <literal>SessionFactory</literal>가 
+                        생성되면 폐기되게끔 예정되어 있다.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="configuration-sessionfactory">
+        <title>SessionFactory 얻기</title>
+
+        <para>
+                        모든 매핑들이 <literal>Configuration</literal>에 의해 파싱되었을 때, 어플리케이션은 <literal>Session</literal> 
+                        인스턴스들에 대한 팩토리를 얻어야 한다. 이 팩토리는 모든 어플리케이션 쓰레드들에 의해 공유되도록 고안되었다:
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sessions = cfg.buildSessionFactory();]]></programlisting>
+
+        <para>
+                        하지만 Hibernate는 당신의 어플리케이션이 하나 이상의 <literal>SessionFactory</literal>를 초기화 시키는 것을 허용한다. 
+                        이것은 당신이 하나 이상의 데이터베이스를 사용하는 경우에 유용하다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-hibernatejdbc" revision="1">
+        <title>JDBC 커넥션들</title>
+
+        <para>
+                        대개 당신은 <literal>SessionFactory</literal>로 하여금 당신을 위한 JDBC 커넥션들을 생성시키고 풀링시키는 것을 원한다. 
+                        만일 당신이 이 접근법을 취할 경우, 한 개의 <literal>Session</literal>을 여는 것은 다음과 같이 간단하다:
+        </para>
+
+        <programlisting><![CDATA[Session session = sessions.openSession(); // open a new Session]]></programlisting>
+        
+        <para>
+                        당신이 데이터베이스에 대한 접근을 요청하는 어떤 것을 행하자 마자, 한 개의 JDBC 커넥션이 그 풀로부터 얻어질 것이다.
+        </para>
+
+        <para> 
+                        이것이 동작하도록 하기 위해서, 우리는 몇몇 JDBC 커넥션 프로퍼티들을 Hibernate에 전달할 필요가 있다. 모든 Hibernate 프로퍼티 
+                        이름들과 의미론들은 <literal>org.hibernate.cfg.Environment</literal> 클래스 상에 정의되어 있다. 우리는 이제 JDBC
+                        커넥션 구성을 위한 가장 중요한 설정들을 설명할 것이다.
+        </para>
+
+        <para>
+                        만일 당신이 다음 프로퍼티들을 설정할 경우 Hibernate는 <literal>java.sql.DriverManager</literal>를 사용하여 커넥션들을 
+                        얻을 것이다(그리고 풀링시킬 것이다): 
+        </para>
+
+        <table frame="topbot">
+            <title>Hibernate JDBC 프로퍼티들</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>프로퍼티 이름</entry>
+                        <entry>용도</entry>
+                    </row>
+                </thead>
+            <tbody>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.driver_class</literal>
+                </entry>
+                <entry>
+                    <emphasis>jdbc 드라이버 클래스</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.url</literal>
+                </entry>
+                <entry>
+                    <emphasis>jdbc URL</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.username</literal>
+                </entry>
+                <entry>
+                    <emphasis>데이터베이스 사용자</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.password</literal>
+                </entry>
+                <entry>
+                    <emphasis>데이터베이스 사용자 패스워드</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.pool_size</literal>
+                </entry>
+                <entry>
+                    <emphasis>풀링된 커넥션들의 최대 개수</emphasis>
+                </entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+                        하지만 Hibernate 자신의 커넥션 풀링 알고리즘은 아주 기본적이다. 그것은 당신이 시작하는 것을 도와주려고 의도되었고 <emphasis>제품 
+                        시스템 용도 또는 퍼포먼스 테스트용으로는 고안되지 않았다</emphasis>. 최상의 퍼포먼스와 안정성을 위해서는 제 3의 풀을 사용하라. 즉 
+            <literal>hibernate.connection.pool_size</literal> 프로퍼티를 커넥션 풀 지정 설정들로 대체하라. 이것은 Hibernate의 내부 
+            pool을 오프시킬 것이다. 예를 들어 당신은 C3P0를 사용할 수도 있다.
+        </para>
+
+        <para>
+            C3P0는 <literal>lib</literal> 디펙토리 속에 Hibernate에 배포된 오픈 소스 JDBC 커넥션 풀이다. 당신이 <literal>hibernate.c3p0.*</literal> 
+                        프로퍼티들을 설정할 경우  Hibernate는  커넥션 풀링을 위해 그것의 <literal>C3P0ConnectionProvider</literal>를 사용할 것이다. 
+                        만일 당신이 Proxool을 사용하고자 원할 경우 패키지화 된 <literal>hibernate.properties</literal>를 참조하고 추가 정보는 
+            Hibernate 웹 사이트를 참조하라.
+        </para>
+
+        <para>
+                        다음은 C3P0에 대한 사용하는 예제 <literal>hibernate.properties</literal> 파일이다:
+        </para>
+
+        <programlisting id="c3p0-configuration" revision="1"><![CDATA[hibernate.connection.driver_class = org.postgresql.Driver
+hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
+hibernate.connection.username = myuser
+hibernate.connection.password = secret
+hibernate.c3p0.min_size=5
+hibernate.c3p0.max_size=20
+hibernate.c3p0.timeout=1800
+hibernate.c3p0.max_statements=50
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+        <para>
+                        어플리케이션 서버 내부의 용도로, 당신은 JNDI로 등록된 어플리케이션 서버 <literal>Datasource</literal>로부터 커넥션을 얻기 
+                        위해 항상 Hibernate를 구성해야 한다. 당신은 적어도 다음 프로퍼티들 중 하나를 최소한으로 설정할 필요가 있을 것이다.
+        </para>
+
+        <table frame="topbot">
+            <title>Hibernate Datasource Properties</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>프로퍼티 이름</entry>
+                        <entry>용도</entry>
+                    </row>
+                </thead>
+            <tbody>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.datasource</literal>
+                </entry>
+                <entry>
+                    <emphasis>데이터소스 JNDI 이름</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.jndi.url</literal>
+                </entry>
+                <entry>
+                    <emphasis>JNDI 프로바이더의 URL</emphasis> (옵션)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.jndi.class</literal>
+                </entry>
+                <entry>
+                    <emphasis>JNDI <literal>InitialContextFactory</literal>의 클래스 </emphasis> (옵션)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.username</literal>
+                </entry>
+                <entry>
+                    <emphasis>데이터베이스 사용자</emphasis> (옵션)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.password</literal>
+                </entry>
+                <entry>
+                    <emphasis>데이터베이스 사용자 패스워드</emphasis> (옵션)
+                </entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+                        다음은 어플리케이션 서버 제공 JNDI 데이터소스용 예제 <literal>hibernate.properties</literal> 파일이다:
+        </para>
+
+        <programlisting><![CDATA[hibernate.connection.datasource = java:/comp/env/jdbc/test
+hibernate.transaction.factory_class = \
+    org.hibernate.transaction.JTATransactionFactory
+hibernate.transaction.manager_lookup_class = \
+    org.hibernate.transaction.JBossTransactionManagerLookup
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+        <para>
+            JNDI datasource로부터 얻어진 JDBC 커넥션들은 어플리케이션 서버의 컨테이너에 의해 관리되는 트랜잭션들에 자동적으로 참여할 것이다.
+        </para>
+
+        <para>
+                        임의의 커넥션 프로퍼티들은 프로퍼티 이름 앞에 "<literal>hibernate.connnection</literal>"을 첨가하여 부여될 수 있다. 예를 들어 
+                        당신은 <literal>hibernate.connection.charSet</literal>을 사용하여 <literal>charSet</literal>을 지정할 수도 있다.
+        </para>
+
+        <para>
+                        당신은 <literal>org.hibernate.connection.ConnectionProvider</literal> 인터페이스를 구현함으로써 JDBC 커넥션들을 
+                        얻는 당신 자신의 플러그인 방도를 정의할수도 있다. 당신은 <literal>hibernate.connection.provider_class</literal>를 
+                        설정하여 맞춤형 구현을 선택할 수도 있다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-optional" revision="1">
+        <title>선택적인 구성 프로퍼티들</title>
+        
+        <para>
+                        실행 시에 Hibernate의 행위를 제어하는 많은 다른 프로퍼티들이 존재한다. 모든 것이 옵션이지만 합당한 디폴트 값들을 갖는다.
+        </para>
+
+        <para>
+        	<emphasis>경고: 이들 프로퍼티들 중 몇몇은 "system-level" 전용이다.</emphasis> 시스템 레벨 프로퍼티들은 오직 
+            <literal>java -Dproperty=value</literal> 또는 <literal>hibernate.properties</literal>를 통해서만 설정될 수 
+                        있다. 그것들은 위에 설명된 다른 기법들에 의해 설정될 수 <emphasis>없다</emphasis>.
+        </para>
+
+        <table frame="topbot" id="configuration-optional-properties" revision="8">
+            <title>Hibernate 구성 프로퍼티들</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>프로퍼티 이름</entry>
+                        <entry>용도</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.dialect</literal>
+                        </entry>
+                        <entry>
+                                                        특정 관계형 데이터베이스에 최적화 된 SQL을 생성시키는 것을 Hibernate에게 허용해주는 
+                            Hibernate <literal>Dialect</literal>의 클래스명. 
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>full.classname.of.Dialect</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.show_sql</literal>
+                        </entry>
+                        <entry>
+                                                        모든 SQL 문장들을 콘솔에 기록한다. 이것은 로그 카테고리 <literal>org.hibernate.SQL</literal>를 
+                            <literal>debug</literal>로 설정하는 것에 대한 하나의 다른 방법이다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.format_sql</literal>
+                        </entry>
+                        <entry>
+                                                        로그와 콘솔 속에 SQL을 깔끔하게 프린트한다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_schema</literal>
+                        </entry>
+                        <entry>
+                                                        생성된 SQL 내에 주어진 schema/tablespace로서 수식이 없는 테이블이름들을 수식한다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>SCHEMA_NAME</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_catalog</literal>
+                        </entry>
+                        <entry>
+                                                        주어진 SQL 내에 주어진 카타록으로서 수식이 없는 테이블이름들을 수식한다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>CATALOG_NAME</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.session_factory_name</literal>
+                        </entry>
+                        <entry>
+                            <literal>SessionFactory</literal>는 그것이 생성된 후에 JNDI 내에서  이 이름에 자동적으로 바인드 
+                                                        될 것이다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>jndi/composite/name</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.max_fetch_depth</literal>
+                        </entry>
+                        <entry>
+                            single-ended 연관관계들(one-to-one, many-to-one)의 경우에 outer join fetch 트리의 최대 "깊이"를 
+                                                        설정한다. <literal>0</literal>은 디폴트 outer join fetching을 사용불가능하게 만든다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>0</literal>ê³¼ 
+                                <literal>3</literal> 사이의 값들이권장된다 
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_batch_fetch_size</literal>
+                        </entry>
+                        <entry>
+                                                       연관들의 Hibernate 배치 페칭에 대한 디폴트 크기를 설정한다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                                            권장되는 값들은 <literal>4</literal>, <literal>8</literal>, 
+                                <literal>16</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_entity_mode</literal>
+                        </entry>
+                        <entry>
+                                                        이 <literal>SessionFactory</literal>로부터 열려진 모든 세션들에 대해 엔티티 표현을 디폴트 모드로 
+                                                        설정한다
+                            <para>
+                                <literal>dynamic-map</literal>, <literal>dom4j</literal>,
+                                <literal>pojo</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.order_updates</literal>
+                        </entry>
+                        <entry>
+                                                        업데이트 중인 항목들의 프라이머리 키 값에 의해 SQL 업데이트들이 순서(ordering)지워지도록 Hibernate에게 
+                                                        강제시킨다. 이것은 고도의 동시성 시스템들에서 더 적은 트랜잭션 데드락(deadlock)들로 귀결될 것이다
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.generate_statistics</literal>
+                        </entry>
+                        <entry>
+                                                        이용 가능하게 되면, Hibernate는 퍼포먼스 튜닝에 유용한 통계들을 수집할 것이다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.use_identifer_rollback</literal>
+                        </entry>
+                        <entry>
+                                                        이용 가능하게 되면, 객체가 삭제될 때 생성된 식별자 프로퍼티들은 디폴트 값들로 재설정될 것이다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.use_sql_comments</literal>
+                        </entry>
+                        <entry>
+                                                        이용 가능하게 되면, Hibernate는 보다 쉬운 디버깅을 위해 SQL 내에 주석들을 생성시킬 것이다. 
+                                                        디폴트는 <literal>false</literal>.
+                            <para>
+                                <emphasis role="strong">예.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-jdbc-properties" revision="8">
+            <title>Hibernate JDBC 및 커넥션 프로퍼티들</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>프로퍼티 이름</entry>
+                        <entry>용도</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.fetch_size</literal>
+                        </entry>
+                        <entry>
+                            0 아닌 값은 JDBC fetch 사이즈를 결정한다(<literal>Statement.setFetchSize()</literal>을 호출한다 ).
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.batch_size</literal>
+                        </entry>
+                        <entry>
+                            0 아닌 값은 Hibernate에 의한 JDBC2 배치 업데이트의 사용을 이용 가능하게 한다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis>
+                                <literal>5</literal>와 <literal>30</literal> 사이의 값들이 권장된다
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.batch_versioned_data</literal>
+                        </entry>
+                        <entry>
+                                                        당신의 JDBC 드라이버가 <literal>executeBatch()</literal>로부터 정확한 행 카운트들을 반환할 경우에 
+                                                        이 프로퍼티를 <literal>true</literal>로 설정하라(대개 이 옵션을 사용 가능하게 하는 것이 안전하다). 
+                                                        그러면 Hibernate는 자동적으로 버전화 된 데이터에 대해 배치화된(batched) DML을 사용할 것이다. 
+                                                        디폴트는  <literal>false</literal>.
+                            <para>
+                                <emphasis role="strong">예.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.factory_class</literal>
+                        </entry>
+                        <entry>
+                                                        맞춤형 <literal>Batcher</literal>를 선택한다. 대부분의 어플리케이션들은 이 구성 프로퍼티를 필요로 하지 
+                                                        않을 것이다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis>
+                                <literal>classname.of.Batcher</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_scrollable_resultset</literal>
+                        </entry>
+                        <entry>
+                            Hibernate에 의한 JDBC2 스크롤 가능한 결과셋들의 사용을 가능하게 해준다. 이 프로퍼티는 사용자가 제공한 
+                            JDBC커넥션들을 사용할 때에만 필수적이고, 그 밖의 경우 Hibernate는 커넥션 메타데이터를 사용한다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_streams_for_binary</literal>
+                        </entry>
+                        <entry>
+                            <literal>binary</literal> 또는 <literal>serializable</literal> 타입들을 JDBC로 기록하고
+                            /JDBC로부터 <literal>binary</literal> 또는 <literal>serializable</literal> 타입들을 읽어들일 때 
+                                                        스트림들을 사용한다(시스템-레벨 프로퍼티).
+                            <para>
+                                <emphasis role="strong">예.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_get_generated_keys</literal>
+                        </entry>
+                        <entry>
+                            insert 후에 고유하게 생성된 키들을 검색하는데 JDBC3 <literal>PreparedStatement.getGeneratedKeys()</literal>의 
+                                                        사용을 이용 가능하도록 만든다. JDBC3+ 드라이버와 JRE1.4+를 필요로 하고, 당신의 드라이버가 Hibernate 
+                                                        식별자 생성자들에 문제가 있을 경우에 false로 설정하라. 디폴트로 커넥션 메타 데이터를 사용하여 드라이버 
+                                                        가용성들을 결정하려고 시도하라.
+                            <para>
+                                <emphasis role="strong">예.</emphasis>
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.provider_class</literal>
+                        </entry>
+                        <entry>
+                            Hibernate에 JDBC 커넥션들을 제공하는 맞춤형 <literal>ConnectionProvider</literal>의 클래스명.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>classname.of.ConnectionProvider</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                    <entry>
+                        <literal>hibernate.connection.isolation</literal>
+                    </entry>
+                    <entry>
+                        JDBC transaction isolation 레벨을 설정한다. 의미있는 값들로 <literal>java.sql.Connection</literal>을 
+                                                체크하지만 대부분의 데이터베이스들이 모든 격리(isolate) 레벨들을 지원하지 않음을 노트하라.
+                        <para>
+                            <emphasis role="strong">예.</emphasis> 
+                            <literal>1, 2, 4, 8</literal>
+                        </para>
+                    </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.autocommit</literal>
+                        </entry>
+                        <entry>
+                            JDBC 풀링된 커넥션들에 대해 자동커밋을 이용 가능하도록 한다(권장되지 않음).
+                            <para>
+                                <emphasis role="strong">예.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.release_mode</literal>
+                        </entry>
+                        <entry>
+                            Hibernate가 JDBC 커넥션들을 해제하게 될 시점을 지정한다. 디폴트로 한 개의 JDBC 커넥션은 그 세션이 명시적으로 
+                                                        닫히거나 연결해제되기 전까지 보관된다. 어플리케이션 트랜잭션 서버 JTA 데이터소스의 경우, 당신은 모든 JDBC 
+                                                        호출 후에 커넥션들을 과감하게 해제시키기 위해 <literal>after_statement</literal>를 사용해야 한다. 비-JTA 
+                                                        연결의 경우, <literal>after_transaction</literal>을 사용하여 각각의 트랜잭션의 끝에서 커넥션들을 
+                                                        해제시키는 것이 종종 의미가 있다. <literal>auto</literal>는 JTA 및 CMT 트랜잭션 방도들의 경우에 
+                            <literal>after_statement</literal>를 선택하고 JDBC 트랜잭션 방도에 대해 <literal>after_transaction</literal>를 
+                                                        선택할 것이다.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>auto</literal> (디폴트) | <literal>on_close</literal> |
+                                <literal>after_transaction</literal> | <literal>after_statement</literal>
+                            </para>
+                            <para>
+                                                                이 설정이 <literal>SessionFactory.openSession</literal>로부터 반환된 <literal>Session</literal>들에만 
+                                                                영향을 준다는 점을 노트하라. <literal>SessionFactory.getCurrentSession</literal>을 통해 얻어진 
+                                <literal>Session</literal>들의 경우, 사용하기 위해 구성된 <literal>CurrentSessionContext</literal> 구현이
+                                                                그들 <literal>Session</literal>들에 대한 연결 해제를 제어한다. <xref linkend="architecture-current-session"/>를 
+                                                                보라.
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                    <entry>
+                        <literal>hibernate.connection.<emphasis>&lt;propertyName&gt;</emphasis></literal>
+                    </entry>
+                    <entry>
+                        JDBC 프로퍼티 <literal>propertyName</literal>을 <literal>DriverManager.getConnection()</literal>에 
+                                                전달한다.
+                    </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jndi.<emphasis>&lt;propertyName&gt;</emphasis></literal>
+                        </entry>
+                        <entry>
+                            <literal>propertyName</literal> 프로퍼티를 JNDI <literal>InitialContextFactory</literal>에 전달한다.
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-cache-properties" revision="7">
+            <title>Hibernate Cache 프로퍼티들</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>프로퍼티 이름</entry>
+                        <entry>용도</entry>
+                    </row>
+                </thead>
+                <tbody>
+                     <row>
+                        <entry>
+                            <literal>hibernate.cache.provider_class</literal>
+                        </entry>
+                        <entry>
+                                                        맞춤형 <literal>CacheProvider</literal>의 클래스명.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>classname.of.CacheProvider</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_minimal_puts</literal>
+                        </entry>
+                        <entry>
+                                                        읽기가 매우 빈번한 경우에, 쓰기를 최소화 시키기 위해 second-level 캐시 연산을 최적화 시킨다. 이 설정은 Hibernate3에서 클러스터링 된 
+                                                        캐시들에 가장 유용하고, Hibernate3에서는 클러스터링된 캐시 구현들에 대해 디폴트로 이용 가능하다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_query_cache</literal>
+                        </entry>
+                        <entry>
+                                                        질의 캐시를 가능하게 만든다. 개별 질의들은 여전히 캐시 가능한 것으로 설정되어야 한다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_second_level_cache</literal>
+                        </entry>
+                        <entry>
+                            second-level 캐시를 완전히 사용 불가능하게 하는데 사용될 수 있고, 그것은 <literal>&lt;cache&gt;</literal> 매핑을 
+                                                        지정하는 클래스들에 대해 디폴트로 이용 가능이다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.query_cache_factory</literal>
+                        </entry>
+                        <entry>
+                                                        맞춤형 <literal>QueryCache</literal> 인터페이스의 클래스명. 디폴트는 미리 빌드된  
+                            <literal>StandardQueryCache</literal>.
+                            <para>
+                                <emphasis role="strong">예.</emphasis>
+                                <literal>classname.of.QueryCache</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.region_prefix</literal>
+                        </entry>
+                        <entry>
+                            second-level 캐시 영역 이름들에 사용할 접두어.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>prefix</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_structured_entries</literal>
+                        </entry>
+                        <entry>
+                                                        인간에게 보다 더 친숙한 형식으로 second-level 캐시 속에 데이터를 저장하도록 Hibernate에게 강제시킨다..
+                            <para>
+                                <emphasis role="strong">예.</emphasis>
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-transaction-properties" revision="9">
+            <title>Hibernate 트랜잭션 프로퍼티들</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>프로퍼티 이름</entry>
+                        <entry>용도</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.factory_class</literal>
+                        </entry>
+                        <entry>
+                            Hibernate <literal>Transaction</literal> API 에 사용할 <literal>TransactionFactory</literal>의 
+                                                       클래스 이름.(디폴트는 <literal>JDBCTransactionFactory</literal>). 
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>classname.of.TransactionFactory</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>jta.UserTransaction</literal>
+                        </entry>
+                        <entry>
+                                                        어플리케이션 서버로부터 JTA <literal>UserTransaction</literal>을  얻기 위해 <literal>JTATransactionFactory</literal>에 
+                                                        의해 사용되는 JNDI 이름.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>jndi/composite/name</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.manager_lookup_class</literal>
+                        </entry>
+                        <entry>
+                            <literal>TransactionManagerLookup</literal>의 클래스명- JVM 레벨의 캐싱이 이용 가능할 때 또는 JTA 환경에서 
+                            hilo generator를 사용할 때 필요하다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>classname.of.TransactionManagerLookup</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.flush_before_completion</literal>
+                        </entry>
+                        <entry>
+                                                        만일 사용가능하도록 되면, 세션은 트랜잭션의 before completion 단계 동안에 자동적으로 flush 될 것이다.
+                                                       빌드되어 있는 자동적인 세션 컨텍스트 관리가 선호되는데, 
+                            <xref linkend="architecture-current-session"/>를 보라.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.auto_close_session</literal>
+                        </entry>
+                        <entry>
+                                                        만일 사용가능토록 하면, after completion 단계 동안에 세션이 자동적으로 닫혀질 것이다.
+                            (CMT에 대해 Hibernate를 사용할 때 매우 유용하다.)
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-misc-properties" revision="10">
+            <title>여러가지 프로퍼티들</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>프로퍼티 이름</entry>
+                        <entry>용도</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.current_session_context_class</literal>
+                        </entry>
+                        <entry>
+                            "현재" <literal>Session</literal>의 영역화를 위한 하나의 (맞춤) 방도를 
+                                                        제공한다. 빌드되어 있는 방도들에 대한 추가 정보는 
+                            <xref linkend="architecture-current-session"/>를 보라.
+                            <para>
+                                <emphasis role="strong">예.</emphasis>
+                            <literal>jta</literal> | <literal>thread</literal> |
+                                <literal>managed</literal> | <literal>custom.Class</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.query.factory_class</literal>
+                        </entry>
+                        <entry>
+                            Chooses the HQL 파서 구현을 선택한다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> or
+                                <literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.query.substitutions</literal>
+                        </entry>
+                        <entry>
+                            Hibernate 질의들 내의 토큰들로부터 SQL 토큰들로의 매핑
+                            (예를 들어 토큰들은 함수 이름 또는 리터럴 이름일 수 있다).
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.hbm2ddl.auto</literal>
+                        </entry>
+                        <entry>
+                            <literal>SessionFactory</literal>가 생성될 때, 자동적으로 유효성을 검사하거나 
+                            schema DDL을 데이터베이스로 내보내기 한다. <literal>create-drop</literal>의 경우, 
+                            <literal>SessionFactory</literal>가 명시적으로 닫혀질 때 데이터베이스 스키마가 
+                                                        드롭될 것이다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>validate</literal> | <literal>update</literal> | 
+                                <literal>create</literal> | <literal>create-drop</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cglib.use_reflection_optimizer</literal>
+                        </entry>
+                        <entry>
+                                                        런타임 reflection 대신에 CGLIB의 사용을 가능하도록 만든다(시스템 레벨 프로퍼티). 
+                             Reflection은 문제가 발생할 시에 때때로 유용할 수 있고, 
+                                                        당신이 optimizer를 사용하지 않을 경우조차도 Hibernate는 항상 필요로 함을 유의하라. 
+                                                        당신은 <literal>hibernate.cfg.xml</literal> 
+                                                        속에 이 프로퍼티를 설정할수 없다.
+                            <para>
+                                <emphasis role="strong">예.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <sect2 id="configuration-optional-dialects" revision="1">
+            <title>SQL Dialects</title>
+
+            <para>
+                                당신은 항상 당신의 데이터베이스를 위해 <literal>hibernate.dialect</literal> 프로퍼티를 정확한 <literal>org.hibernate.dialect.Dialect</literal> 
+                                서브클래스로 설정해야 한다. 만일 당신이 dialect를 지정할 경우, 당신이 프로퍼티들을 수작업으로 지정하는 노력을 절약하도록 Hibernate는 위에 열거된 다른 프로퍼티들 
+                                중 몇몇에 대해  의미있는 디폴트들을 사용할 것이다.
+            </para>
+
+            <table frame="topbot" id="sql-dialects" revision="2">
+                <title>Hibernate SQL Dialects (<literal>hibernate.dialect</literal>)</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>RDBMS</entry>
+                            <entry>Dialect</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry>DB2</entry> <entry><literal>org.hibernate.dialect.DB2Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>DB2 AS/400</entry> <entry><literal>org.hibernate.dialect.DB2400Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>DB2 OS390</entry> <entry><literal>org.hibernate.dialect.DB2390Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>PostgreSQL</entry> <entry><literal>org.hibernate.dialect.PostgreSQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL</entry> <entry><literal>org.hibernate.dialect.MySQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL with InnoDB</entry> <entry><literal>org.hibernate.dialect.MySQLInnoDBDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL with MyISAM</entry> <entry><literal>org.hibernate.dialect.MySQLMyISAMDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Oracle (any version)</entry> <entry><literal>org.hibernate.dialect.OracleDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Oracle 9i/10g</entry> <entry><literal>org.hibernate.dialect.Oracle9Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Sybase</entry> <entry><literal>org.hibernate.dialect.SybaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Sybase Anywhere</entry> <entry><literal>org.hibernate.dialect.SybaseAnywhereDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Microsoft SQL Server</entry> <entry><literal>org.hibernate.dialect.SQLServerDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>SAP DB</entry> <entry><literal>org.hibernate.dialect.SAPDBDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Informix</entry> <entry><literal>org.hibernate.dialect.InformixDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>HypersonicSQL</entry> <entry><literal>org.hibernate.dialect.HSQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Ingres</entry> <entry><literal>org.hibernate.dialect.IngresDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Progress</entry> <entry><literal>org.hibernate.dialect.ProgressDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Mckoi SQL</entry> <entry><literal>org.hibernate.dialect.MckoiDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Interbase</entry> <entry><literal>org.hibernate.dialect.InterbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Pointbase</entry> <entry><literal>org.hibernate.dialect.PointbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>FrontBase</entry> <entry><literal>org.hibernate.dialect.FrontbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Firebird</entry> <entry><literal>org.hibernate.dialect.FirebirdDialect</literal></entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-outerjoin" revision="4">
+            <title>Outer Join Fetching</title>
+
+            <para>
+                                만일 당신의 데이터베이스가 ANSI, Oracle, 또는 Sybase 스타일의 outer join들을 지원할 경우, <emphasis>outer join
+                fetching</emphasis>은 (데이터베이스 그 자체에 의해 보다 더 많은 작업이 수행되는 비용으로) 데이터베이스로의 그리고 
+                                데이터베이스로부터의 라운드 트립들의 개수를 제한함으로써 종종 퍼포먼스를 증가시킬 것이다. Outer join fetching은 
+                many-to-one, one-to-many, many-to-many,one-to-one 연관관계들이 에 의해 연결된 객체들의 전체 그래프가  
+                                하나의 SQL <literal>SELECT</literal> 속에서 검색되게끔 허용해준다.
+            </para>
+
+            <para>
+                Outer join fetching은 hibernate.max_fetch_depth 프로퍼티를 <literal>0</literal>으로 설정함으로써 
+                <emphasis>전역적으로</emphasis> 사용 불가능하게 할 수 있다. <literal>1</literal> 이상의 값을 설정하는 
+                                것은 <literal>fetch="join"</literal>으로 매핑되었던 모든 one-to-one 및 many-to-one 연관관계들에 대해 
+                outer join fetching을 사용 가능하도록 만든다.
+            </para>
+
+            <para>
+                                추가 정보는 <xref linkend="performance-fetching"/>를 보라.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-binarystreams" revision="1">
+            <title>Binary Streams</title>
+
+            <para>
+                Oracle은 JDBC 드라이버 로/부터 전달되는 <literal>byte</literal> 배열들의 크기를 제한시킨다. 만일 당신이 
+                <literal>binary</literal> 또는 <literal>serializable</literal> 타입의 대형 인스턴스를 사용하고자 
+                                원할 경우에, 당신은 <literal>hibernate.jdbc.use_streams_for_binary</literal>를 사용 가능하게 해야 
+                                할 것이다. <emphasis>이것은 오직 시스템 레벨 설정이다.</emphasis>
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-cacheprovider" revision="2">
+            <title>Second-level 캐시와 query 캐시</title>
+
+            <para>
+                <literal>hibernate.cache</literal> 접두어가 붙은 프로퍼티들은 Hibernate에 대해 프로세스 또는 
+                                클러스터 범위의 두 번째 레벨 캐시 시스템을 사용하는 것을 허용해준다. 상세한 것은 
+                <xref linkend="performance-cache"/>를 보라. 
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-querysubstitution">
+            <title>Query Language 치환</title>
+
+            <para>
+                                당신은 <literal>hibernate.query.substitutions</literal>을 사용하여 새로운 Hibernate 질의 토큰들을 
+                                정의할 수 있다. 예를 들어:
+            </para>
+
+            <programlisting>hibernate.query.substitutions true=1, false=0</programlisting>
+
+            <para>
+                                은<literal>true</literal>와 <literal>false</literal> 토큰들이 생성된 SQL 내에서 
+                                정수 리터럴들로 번역되도록 강제할 것이다.
+            </para>
+
+            <programlisting>hibernate.query.substitutions toLowercase=LOWER</programlisting>
+
+            <para>
+                               은 SQL <literal>LOWER</literal> function  함수 이름을 변경하는 것을 당신에게 허용해 줄 것이다
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-statistics" revision="2">
+            <title>Hibernate 통계</title>
+
+            <para>
+                                만일 당신이 <literal>hibernate.generate_statistics</literal>를 사용 가능하도록 할 경우, Hibernate는 
+                <literal>SessionFactory.getStatistics()</literal>를 통해 가동 중인 시스템을 튜닝할 때 유용한 많은 통계들을 
+                                노출시킬 것이다. Hibernate는 심지어 JMX를 통해 이들 통계들을 노출시키도록 구성될 수 있다. 추가 정보는 
+                <literal>org.hibernate.stats</literal>에 있는 인터페이스들에 관한 Javadoc를 읽어라.
+            </para>
+
+        </sect2>
+    </sect1>
+
+    <sect1 id="configuration-logging">
+        <title>로깅</title>
+
+        <para>
+            Hibernate는 Apache commons-logging를 사용하여 다양한 이벤트들을 로그시킨다. 
+        </para>
+
+        <para>
+            commons-logging 서비스는 (만일 당신이 classpath 내에 <literal>log4j.jar</literal>를 포함할 경우) Apache Log4j로 
+                        또는 (JDK1.4 이상의 버전에서 실행될 경우) JDK 1.4 로깅으로 직접 출력할 것이다. 당신은 <literal>http://jakarta.apache.org</literal>에서 
+            Log4j를 다운로드 할 수 있다. Log4j를 사용하기 위해, 당신은 <literal>log4j.properties</literal> 파일을 당신의 classpath 
+                        내에 위치지울 필요가 있을 것이고, 예제 properties 파일은 Hibernate의  <literal>src/</literal> 디렉토리 내에 배포되어 있다. 
+        </para>
+        
+        <para>
+                        우리는 당신이 Hibernate의 로그 메시지들에 익숙해지기를 강력히 권장한다. 읽기 불가능하지 않게끔 가능한 한 상세하게 Hibernate 로그를 
+                        만들도록 많은 작업이 행해졌다. 그것은 본질적인 문제던지기 장치이다. 가장 흥미로운 로그 카테고리들이 다음에 있다:
+        </para>
+        
+            <table frame="topbot" id="log-categories" revision="2">
+                <title>Hibernate 로그 카테고리들</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>카테고리</entry>
+                            <entry>기능</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>org.hibernate.SQL</literal></entry>
+                            <entry>SQL DML 문장들이 실행될 때 그것들 모두를 로그 시킨다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.type</literal></entry>
+                            <entry>모든 JDBC 파라미터들을 로그시킨다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.tool.hbm2ddl</literal></entry>
+                            <entry>SQL DDL 문장들이 실행될 때 그것들 모두를 로그 시킨다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.pretty</literal></entry>
+                            <entry>
+                                flush 시점에서 세션과 연관된 모든 엔티티들(최대 20개의 엔티티들)의 상태를 로그 시킨다
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.cache</literal></entry>
+                            <entry>모든 second-level 캐시 액티비티를 로그시킨다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction</literal></entry>
+                            <entry>트랜잭션 관련 액티비티를 로그 시킨다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.jdbc</literal></entry>
+                            <entry>모든 JDBC 리소스 취득을 로그 시킨다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.hql.ast.AST</literal></entry>
+                            <entry>
+                                                                질의 파싱 동안에 HQL AST와 SQL AST를 로그시킨다
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.secure</literal></entry>
+                            <entry>모든 JAAS 허가 요청들을 로그시킨다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate</literal></entry>
+                            <entry>
+                                                                모든 것을 로그시킨다(많은 정보이지만, 문제해결에 매우 유용하다)
+                            </entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+            
+        <para>
+            Hibernate로 어플리케이션들을 개발할 때, 당신은 거의 항상 <literal>org.hibernate.SQL</literal> 카테고리에 대해 
+                        이용 가능한 <literal>debug</literal> 모드로 작업하거나, 다른 방법으로 <literal>hibernate.show_sql</literal> 
+                        프로퍼티를 이용가능하게 하여 작업해야 할 것이다.
+        </para>
+                       
+        
+    </sect1>
+
+    <sect1 id="configuration-namingstrategy">
+        <title><literal>NamingStrategy</literal> 구현하기</title>
+
+        <para>
+            <literal>org.hibernate.cfg.NamingStrategy</literal> 인터페이스는 데이터베이스 객체들과 스키마 요소들에 대한 
+            "네이밍 표준"을 지정하는 것을 당신에게 허용해준다.
+        </para>
+
+        <para>
+                        당신은 Java 식별자들로부터 데이터베이스 식별자들을 자동적으로 생성시키거나 매핑 파일에 주어진 "논리적" 컬럼과 테이블 
+                        이름들을 "물리적" 테이블과 컬럼 이름들로 자동적으로 처리하는 규칙들을 제공할 수 있다. 이 특징은 반복되는 잡음(예를 들어 
+            <literal>TBL_</literal>접두어들)을 제거함으로써, 매핑 문서의 말많은 장황함을 감소시키도록 도와준다. Hibernate에 
+                        의해 사용되는 디폴트 방도는 아주 작은 작품이다.
+        </para>
+
+        <para>
+                        당신은 매핑들을 추가하기 이전에 <literal>Configuration.setNamingStrategy()</literal>를 호출함으로써 다른 방도를 
+                        지정할 수 있다:
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sf = new Configuration()
+    .setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
+    .addFile("Item.hbm.xml")
+    .addFile("Bid.hbm.xml")
+    .buildSessionFactory();]]></programlisting>
+    
+        <para>
+            <literal>org.hibernate.cfg.ImprovedNamingStrategy</literal>는 어떤 어플리케이션들에 대한 유용한 시작점일 수 있는 
+                        미리 빌드된 방도이다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-xmlconfig" revision="2">
+        <title>XML 구성 파일</title>
+
+        <para>
+                        구성에 대한 다른 접근법은 <literal>hibernate.cfg.xml</literal>로 명명된 파일 속에 전체 구성을 지정하는 것이다. 이 파일은 
+            <literal>hibernate.properties</literal> 파일에 대한 대용물로서 사용될 수 있거나, 만일 둘 다 존재할 경우에 프로퍼티들을 
+                        중복정의하는데 사용될 수 있다.
+        </para>
+
+        <para>
+            XML 구성 파일은 디폴트로 당신의 <literal>CLASSPATH</literal>의 루트에 존재하는 것이 기대된다. 다음은 예제이다:
+        </para>
+
+        <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+    "-//Hibernate/Hibernate Configuration DTD//EN"
+    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <!-- a SessionFactory instance listed as /jndi/name -->
+    <session-factory
+        name="java:hibernate/SessionFactory">
+
+        <!-- properties -->
+        <property name="connection.datasource">java:/comp/env/jdbc/MyDB</property>
+        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
+        <property name="show_sql">false</property>
+        <property name="transaction.factory_class">
+            org.hibernate.transaction.JTATransactionFactory
+        </property>
+        <property name="jta.UserTransaction">java:comp/UserTransaction</property>
+
+        <!-- mapping files -->
+        <mapping resource="org/hibernate/auction/Item.hbm.xml"/>
+        <mapping resource="org/hibernate/auction/Bid.hbm.xml"/>
+
+        <!-- cache settings -->
+        <class-cache class="org.hibernate.auction.Item" usage="read-write"/>
+        <class-cache class="org.hibernate.auction.Bid" usage="read-only"/>
+        <collection-cache collection="org.hibernate.auction.Item.bids" usage="read-write"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+                        당신이 볼 수 있듯이, 이 접근법의 장점은 구성에 대한 매핑 파일 이름들을 구체화 시키는 것이다. <literal>hibernate.cfg.xml</literal>은 
+                        또한 당신이 Hibernate 캐시를 튜닝해야할 때 보다 편리하다. <literal>hibernate.properties</literal> 또는 
+            <literal>hibernate.cfg.xml</literal> 중 어느 것을 사용하는가는 당신의 선택이다. XML 구문을 사용하는 위에 언급된 
+                        이점들을 제외하면 둘다 같은 것임을 노트하라.
+        </para>
+
+       <para>
+           Hibernate 구성으로, Hibernate를 시작하는 것은 다음과 같이 간단하다
+       </para>
+
+       <programlisting><![CDATA[SessionFactory sf = new Configuration().configure().buildSessionFactory();]]></programlisting>
+
+       <para>
+                      당신은 다음을 사용하여 다른 XML 구성 파일을 찾아낼 수 있다
+       </para>
+
+       <programlisting><![CDATA[SessionFactory sf = new Configuration()
+    .configure("catdb.cfg.xml")
+    .buildSessionFactory();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="configuration-j2ee" revision="1">
+        <title>J2EE 어플리케이션 서버 통합</title>
+
+        <para>
+            Hibernate는 J2EE 인프라스트럭처에 대한 다음 통합 점들을 갖고 있다: 
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>Container-managed datasources</emphasis>: Hibernate는 컨테이너에 의해 관리되는 JDBC 커넥션들을 
+                                사용할 수 있고 JNDI를 통해 제공된다. 대개 JTA 호환 <literal>TransactionManager</literal>와 <literal>ResourceManager</literal>는 
+                                트랜잭션 관리(CMT), 특히 몇몇 데이터소스들을 가로질러 분산된 트랜잭션 핸들링을 처리한다. 물론 당신은 또한 프로그램 상으로 
+                                트랜잭션 경계들을 한정할 수도 있거나(BMT) 당신은 당신의 코드가 이식성을 유지하도록 이것에 대한 선택적인 Hibernate 
+                <literal>Transaction</literal> API를 사용하고자 원할 수도 있다.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>자동적인 JNDI 바인딩</emphasis>: Hibernate는 시작 후에 그것의 <literal>SessionFactory</literal>를 
+                JNDI에 바인드 시킬 수 있다.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>JTA Session 바인딩</emphasis>: Hibernate <literal>Session</literal>은 
+                JTA 트랜잭션들의 영역(scope)에 자동적으로 바인드 시킬 수도 있다. 간단하게 JNDI로부터 <literal>SessionFactory</literal>를 
+                                룩업하고 현재 <literal>Session</literal>을 얻어라. Hibernate로 하여금 당신의 JTA 트랜잭션이 완료될 때 <literal>Session</literal>을 
+                flush시키고 닫는 것을 처리하도록 하라. 트랜잭션 경계 구분은 선언적(CMT)이거나 프로그래밍적((BMT/UserTransaction))이다.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>JMX 배치</emphasis>: 만일 당신이 JMX 가용성이 있는 어플리케이션 서버(예를 들면 JBoss AS)를 갖고 있다면, 
+                                당신은 Hibernate를 하나의 managed MBean으로서 배치하는 것을 선택할 수 있다. 이것은 <literal>Configuration</literal>으로부터 
+                                당신의 <literal>SessionFactory</literal>를 빌드 시키는 한 줄의 시작 코드를 절약해준다. 컨테이너는 당신의 <literal>HibernateService</literal>를 
+                                시작할 것이고, 또한 이상적으로 서비스 의존성들을 처리할 것이다(데이터소스는 Hibernate가 시작되기 전에 이용 가능해야 한다). 
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+                        당신의 환경에 따라, 당신은 당신의 어플리케이션 서버가 "connection containment(연결 봉쇄)" 예외상황들을 보일 경우에 구성 옵션 
+            <literal>hibernate.connection.aggressive_release</literal>를 true로 설정해야 될 수도 있다.
+        </para>
+
+        <sect2 id="configuration-optional-transactionstrategy" revision="3">
+            <title>트랜잭션 방도 구성</title>
+
+            <para>
+                Hibernate <literal>Session</literal> API는 당신의 아카텍처 내에서 임의의 트랜잭션 관할 시스템에 독립적이다. 만일 
+                                당신이 Hibernate로 하여금 커넥션 풀을 통해 직접 JDBC를 사용하도록 강제할 경우, 당신은 JDBC API를 호출하여 당신의 트랜잭션을 
+                                시작하고 끝낼 수 있다. 만일 당신이 J2EE 어플리케이션 서버를 실행 중이라면, 당신은 필요할 때 bean-managed 트랜잭션들을 사용하고 
+                JTA API와 <literal>UserTransaction</literal>을 호출하고자 원할 수 있다.
+            </para>
+
+            <para>
+                                이들 두 개의 (그리고 다른) 환경들에서 당신의 코드에 이식성을 유지하기 위해 우리는 기본 시스템을 포장하고 은폐시키는 선택적인 
+                Hibernate <literal>Transaction</literal> API를 권장한다. 당신은 Hibernate 구성 프로퍼티 <literal>hibernate.transaction.factory_class</literal>를 
+                                사용하여 <literal>Transaction</literal> 인스턴스들에 대한 팩토리 클래스를 지정해야 한다.
+            </para>
+
+            <para>
+                                세 개의 표준(미리 만들어진) 선택들이 존재한다:
+            </para>
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.JDBCTransactionFactory</literal></term>
+                    <listitem>
+                        <para>데이터베이스 (JDBC) 트랜잭션들에게 위임시킨다(디폴트)</para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.JTATransactionFactory</literal></term>
+                    <listitem>
+                        <para>
+                                                        기존의 트랜잭션이 이 컨텍스트(예를 들면 EJB session bean 메소드) 내에서 진행 중일 경우에 
+                            container-managed transaction에게 위임시키고, 그 밖의 경우 새로운 트랜잭션이 시작되고 
+                            bean-managed transaction이 사용된다.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.CMTTransactionFactory</literal></term>
+                    <listitem>
+                        <para>container-managed JTA 트랜잭션들에게 위임시킨다</para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+            <para>
+                                당신은 또한 당신 자신의 트랜잭션 방도들(예를 들면 CORBA 트랜잭션 서비스)을 정의할 수도 있다.
+            </para>
+
+            <para>
+                Hibernate에 있는 몇몇 특징들(예를 들면. second level 캐시, JTA를 가진 컨텍스트 상의 세션들, 기타.)은 관리되는 환경에서 
+                JTA <literal>TransactionManager</literal>에 대한 접근을 필요로 한다. 어플리케이션 서버에서 당신은 Hibernate가 
+                <literal>TransactionManager</literal>에 대한 참조를 획득하는 방법을 지정해야 한다. 왜냐하면 J2EE가 한 개의 메커니즘을 
+                                표준화 시키고 있지 않기 때문이다:
+            </para>
+
+            <table frame="topbot" id="jtamanagerlookup" revision="1">
+                <title>JTA TransactionManagers</title>
+                <tgroup cols="2">
+                    <colspec colwidth="2.5*"/>
+                    <colspec colwidth="1*"/>
+                    <thead>
+                        <row>
+                            <entry>트랜잭션 팩토리</entry>
+                            <entry align="center">어플리케이션 서버</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JBossTransactionManagerLookup</literal></entry>
+                            <entry align="center">JBoss</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WeblogicTransactionManagerLookup</literal></entry>
+                            <entry align="center">Weblogic</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WebSphereTransactionManagerLookup</literal></entry>
+                            <entry align="center">WebSphere</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</literal></entry>
+                            <entry align="center">WebSphere 6</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.OrionTransactionManagerLookup</literal></entry>
+                            <entry align="center">Orion</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.ResinTransactionManagerLookup</literal></entry>
+                            <entry align="center">Resin</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JOTMTransactionManagerLookup</literal></entry>
+                            <entry align="center">JOTM</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JOnASTransactionManagerLookup</literal></entry>
+                            <entry align="center">JOnAS</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JRun4TransactionManagerLookup</literal></entry>
+                            <entry align="center">JRun4</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.BESTransactionManagerLookup</literal></entry>
+                            <entry align="center">Borland ES</entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-jndi" revision="3">
+            <title>JNDI-bound <literal>SessionFactory</literal></title>
+
+            <para>
+                                하나의 JNDI 바인드된 Hibernate <literal>SessionFactory</literal>는 그 팩토리에 대한 룩업과 새로운 
+                <literal>Session</literal>들의 생성을 단순화 시킬 수 있다. 이것은 JNDI 바인드된 <literal>Datasource</literal>에 
+                                관련되어 있지 않고, 단순하게 둘 다 동일한 레지스트리를 사용한다는 점을 노트하라!
+            </para>
+
+            <para>
+                                만일 당신이 <literal>SessionFactory</literal>를 하나의 JNDI namespace에 바인드 시키고자 원할 경우, 
+                <literal>hibernate.session_factory_name</literal> 프로퍼티를 사용하여 한 개의 이름(예를 들면. 
+                <literal>java:hibernate/SessionFactory</literal>)을 지정하라. 만일 이 프로퍼티가 생략될 경우, 
+                <literal>SessionFactory</literal>는 JNDI에 바인드 되지 않을 것이다. (이것은 읽기-전용 JNDI 디폴트 
+                                구현을 가진 환경들, 예를 들면 Tomcat에서 특히 유용하다.)
+            </para>
+
+            <para>
+                <literal>SessionFactory</literal>를 JNDI에 바인드 시킬 때, Hibernate는 초기 컨텍스트를 초기화 시키기 위해 
+                <literal>hibernate.jndi.url</literal>, <literal>hibernate.jndi.class</literal>의 값들을 사용할 것이다. 
+                                만일 그것들이 지정되어 있지 않을 경우, 디폴트 <literal>InitialContext</literal>가 사용될 것이다.
+            </para>
+
+            <para>
+                Hibernate는 당신이 <literal>cfg.buildSessionFactory()</literal>를 호출한 후에 <literal>SessionFactory</literal>를 JNDI 내에 
+                                자동적으로 위치지울 것이다. 이것은 당신이 (나중에 논의되는) <literal>HibernateService</literal>를 가진 JMX 배치를 
+                                사용하지 않는 한, 당신이 적어도 당신의 어플리케이션 내에 있는 어떤 시작 코드 (또는 유틸리티 클래스) 내에서 이것을 호출할 것임을 
+                                의미한다.
+            </para>
+
+            <para>
+                                만일 당신이 하나의 JNDI <literal>SessionFactory</literal>를 사용할 경우, 하나의 EJB 또는 어떤 다른 클래스는 JNDI 
+                                룩업을 사용하여 <literal>SessionFactory</literal>를 얻을 수 있다.
+            </para>
+
+            <para>
+                                 우리는 관리되는 환경들에서 <literal>SessionFactory</literal>를 JNDI에 바인드 시키고 그 밖의 경우에는 
+                                 하나의 <literal>static</literal> 싱글톤을 사용하는 것을 권장한다. 이들 상세로부터 당신의 어플리케이션 코드를 
+                                 은폐시키기 위해, 우리는 또한 <literal>HibernateUtil.getSessionFactory()</literal>과 같은 하나의 
+                 helper 클래스 내에서 <literal>SessionFactory</literal>에 대한 실제 룩업 코드를 은폐시키기를 권장한다.
+                                 그런 클래스는 또한 Hibernate를 시작하는 편리한 방법임을 노트하라&mdash; 1장을 보라.
+            </para>
+            
+        </sect2>
+
+        <sect2 id="configuration-j2ee-currentsession" revision="4">
+            <title>Current Session context management with JTA</title>
+
+            <para>
+	           	당신 자신의 <literal>ThreadLocal</literal> 유틸리티를 작동시키는 대신에, 우리는 또한 Hibernate <literal>Session</literal>를 
+	           	얻기 위해 <literal>SessionFactory</literal> 상의 <literal>getCurrentSession()</literal> 메소드 사용을 
+	           	권장한다. <xref linkend="architecture-current-session">현재 세션들</xref>에 관한 논의를 보라. <literal>"jta"</literal>
+	           	세션 컨텍스트를 사용하고 있는 경우에, 현재의 JTA 트랜잭션으로 시작되고 연관된 Hibernate <literal>Session</literal>이 
+	           	존재하지 않을 경우, 우리는 JTA 트랜잭션으로 시작되고 연관될 것이다. <literal>"jta"</literal> 컨텍스트에서 
+	           	<literal>getCurrentSession()</literal>를 통해 검색된 <literal>Session</literal>들은 그 트랜잭션이 완료되기 전에
+	           	자동적으로 flush될 것이고 트랜잭션 완료 후에 닫혀질 것이고, 그리고 각각의 문장 뒤에 JDBC 커넥션들을 적극적으로 해제할 것이다.
+	           	이것은 그런 관리 사항들에 대해 사용자 코드를 명료하게 유지시켜서, 연관되어 있는 JTA 트랜잭션의 생명주기에 의해 <literal>Session</literal>들이 
+	           	관리되도록 허용해준다. 이것은 그런 관리 사항들에 대해 사용자 코드를 명료하게 유지시켜서, 세션이 연관되어 있는 JTA 트랜잭션의 
+	           	생명주기에 의해 관리되는 것을 <literal>Session</literal>들에게 허용해준다. 당신의 코드는 
+	           	
+	           	<literal>Session</literal>들과 트랜잭션들을 처리하는 가장 손쉬운 방법은 Hibernate의 자동적인 "현재"
+	           	<literal>Session</literal>이다. 
+	           	<xref linkend="architecture-current-session">current sessions</xref>에 관한 논의를 보라.
+	           	<literal>"jta"</literal> 세션 컨텍스트를 사용하는 경우, 현재의 JTA 트랜잭션으로 시작되고 연관된 
+	           	Hibernate <literal>Session</literal>들이 존재하지 않을 경우, 당신이 
+	           	<literal>sessionFactory.getCurrentSession()</literal>을 처음 호출할 때 하나의 세션이 현재의 JTA 트랜잭션에 대해 
+	           	시작되고 연관될 것이다. <literal>"jta"</literal> 컨텍스트에서 <literal>getCurrentSession()</literal>을 
+	           	통해 검색된 <literal>Session</literal>들은 그 트랜잭션이 완료되기 전에 자동적으로 flush될 것이고
+	           	그 트랜잭션 완료들 후에 닫혀질 것이고 각각의 문장 후에 JDBC 커넥션들을 적극적으로 해제할 것이다.
+	           	이것은 그런 관리 사항들에 대해 사용자 코드를 명료하게 유지시켜서, 연관되어 있는 JTA 트랜잭션의 생명주기에 의해 <literal>Session</literal>들이 
+	           	관리되도록 허용해준다. 이것은 그런 관리 사항들에 대해 사용자 코드를 명료하게 유지시켜서, 세션이 연관되어 있는 JTA 트랜잭션의 
+	           	생명주기에 의해 관리되는 것을 <literal>Session</literal>들에게 허용해준다. 당신의 코드는 트랜잭션 경계들을 설정하는데 
+	           	<literal>UserTransaction</literal>을 통해 프로그램 상으로 JTA를 사용하거나, Hibernate <literal>Transaction</literal> API를 (이식성을 위한 코드로 권장됨)
+	           	사용할 수 있다. 만일 당신이 하나의 EJB 컨테이너에서 실행하고 있을 경우, CMT의 경우에 선언적인 트랜잭션 경계설정이 선호된다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-j2ee-jmx" revision="1">
+            <title>JMX 배치</title>
+
+            <para>
+                <literal>cfg.buildSessionFactory()</literal> 줄은 여전히 JNDI에 붙은 하나의 <literal>SessionFactory</literal>를 얻기 위해 
+                                어딘가에서 실행되어야 한다. 당신은 (<literal>HibernateUtil</literal> 내에 있는 것처럼) <literal>static</literal> initializer 
+                                블록 속에서 이것을 행할 수 있거나 당신은 Hibernate를 <emphasis>managed service</emphasis>로서 배치할 수 있다.
+            </para>
+
+            <para>
+                Hibernate는 JBoss AS와 같은 JMX 가용성들을 가진 어플리케이션 서버 상의 배치를 위해 <literal>org.hibernate.jmx.HibernateService</literal>를 
+                                배포하고 있다. 실제 배치와 구성은 벤더 지정적이다. 다음은 JBoss 4.0.x를 위한 <literal>jboss-service.xml</literal> 예제이다:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<server>
+
+<mbean code="org.hibernate.jmx.HibernateService"
+    name="jboss.jca:service=HibernateFactory,name=HibernateFactory">
+
+    <!-- Required services -->
+    <depends>jboss.jca:service=RARDeployer</depends>
+    <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends>
+
+    <!-- Bind the Hibernate service to JNDI -->
+    <attribute name="JndiName">java:/hibernate/SessionFactory</attribute>
+
+    <!-- Datasource settings -->
+    <attribute name="Datasource">java:HsqlDS</attribute>
+    <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>
+
+    <!-- Transaction integration -->
+    <attribute name="TransactionStrategy">
+        org.hibernate.transaction.JTATransactionFactory</attribute>
+    <attribute name="TransactionManagerLookupStrategy">
+        org.hibernate.transaction.JBossTransactionManagerLookup</attribute>
+    <attribute name="FlushBeforeCompletionEnabled">true</attribute>
+    <attribute name="AutoCloseSessionEnabled">true</attribute>
+
+    <!-- Fetching options -->
+    <attribute name="MaximumFetchDepth">5</attribute>
+
+    <!-- Second-level caching -->
+    <attribute name="SecondLevelCacheEnabled">true</attribute>
+    <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute>
+    <attribute name="QueryCacheEnabled">true</attribute>
+
+    <!-- Logging -->
+    <attribute name="ShowSqlEnabled">true</attribute>
+
+    <!-- Mapping files -->
+    <attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute>
+
+</mbean>
+
+</server>]]></programlisting>
+
+            <para>
+                                이 파일은 <literal>META-INF</literal>로 명명된 디렉토리 속에 배치되고 확장자 <literal>.sar</literal>
+                (service archive)를 가진 한 개의 JAR 파일 속에 패키징된다. 당신은 또한 Hibernate, 그것의 필요한 제 3의 라이브러리들, 당신의 컴파일된 
+                                영속 클래스들 뿐만 아니라 당신의 매핑 파일들을 동일한 아카이브 속에 패키징할 필요가 있다. 당신의 엔터프라이즈 빈즈(대개 session beans)는 
+                                그것들 자신의 JAR 파일 속에 유지될 수 있지만, 당신은 한 개의 (hot-)배치 가능한 단위를 얻기 위해 메인 서비스 아카이브 속에 이 EJB JAR 파일을 
+                                포함시킬 수도 있다. JMX 서비스와 EJB 배치에 관한 추가 정보는 JBoss AS 문서를 참조하라.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/events.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/events.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/events.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,255 @@
+<chapter id="events">
+    <title>인터셉터들과 이벤트들</title>
+
+    <para>
+                어플리케이션이 Hibernate 내부에서 발생하는 어떤 이벤트들에 대해 반응하는 것에 흔히 유용하다. 이것은 어떤 종류의 일반적인 기능, 
+                그리고 Hibernate의 확장 기능의 구현을 허용해준다.
+    </para>
+
+    <sect1 id="objectstate-interceptors" revision="3">
+        <title>인터셉터들</title>
+
+        <para>
+            <literal>Interceptor</literal> 인터페이스는 영속 객체가 저장되고, 업데이트되고, 삭제되거나 로드되기 전에 영속 객체의 
+                        프로퍼티들을 조사하고/하거나 처리하는 것을 어플리케이션에 허용해줌으로써 세션으로부터 어플리케이션으로의 콜백들을 제공한다. 
+                        이것에 대한 한 가지 가능한 사용은 감사 정보를 추적하는 것이다. 예를 들어, 다음 <literal>Interceptor</literal>는 
+            <literal>Auditable</literal>이 생성될 때 <literal>createTimestamp</literal>를 자동적으로 설정하고 
+            <literal>Auditable</literal>이 업데이트될 때 <literal>lastUpdateTimestamp</literal> 프로퍼티를 업데이트 한다.
+        </para>
+        
+        <para>
+                        당신은 <literal>Interceptor</literal>를 직접 구현해야 하거나 (더 좋게는) 
+            <literal>EmptyInterceptor</literal>를 확장(extend)해야 한다.
+        </para>
+
+        <programlisting><![CDATA[package org.hibernate.test;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.Transaction;
+import org.hibernate.type.Type;
+
+public class AuditInterceptor extends EmptyInterceptor {
+
+    private int updates;
+    private int creates;
+    private int loads;
+
+    public void onDelete(Object entity,
+                         Serializable id,
+                         Object[] state,
+                         String[] propertyNames,
+                         Type[] types) {
+        // do nothing
+    }
+
+    public boolean onFlushDirty(Object entity,
+                                Serializable id,
+                                Object[] currentState,
+                                Object[] previousState,
+                                String[] propertyNames,
+                                Type[] types) {
+
+        if ( entity instanceof Auditable ) {
+            updates++;
+            for ( int i=0; i < propertyNames.length; i++ ) {
+                if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
+                    currentState[i] = new Date();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean onLoad(Object entity,
+                          Serializable id,
+                          Object[] state,
+                          String[] propertyNames,
+                          Type[] types) {
+        if ( entity instanceof Auditable ) {
+            loads++;
+        }
+        return false;
+    }
+
+    public boolean onSave(Object entity,
+                          Serializable id,
+                          Object[] state,
+                          String[] propertyNames,
+                          Type[] types) {
+
+        if ( entity instanceof Auditable ) {
+            creates++;
+            for ( int i=0; i<propertyNames.length; i++ ) {
+                if ( "createTimestamp".equals( propertyNames[i] ) ) {
+                    state[i] = new Date();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void afterTransactionCompletion(Transaction tx) {
+        if ( tx.wasCommitted() ) {
+            System.out.println("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads);
+        }
+        updates=0;
+        creates=0;
+        loads=0;
+    }
+
+}]]></programlisting>
+
+        <para>
+                        인터셉터들은 다음 두 개의  특징들로 나타난다: <literal>Session</literal>-영역화 그리고 
+            <literal>SessionFactory</literal>-영역화.
+        </para>
+
+        <para>
+            <literal>Session</literal>-영역의 인터셉터는 세션이 하나의 <literal>Interceptor</literal>를 수용하는 
+                        오버로드된  SessionFactory.openSession() 메소드들 중 하나를 사용하여 열릴 때 
+                        지정된다.
+        </para>
+
+        <programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
+
+        <para>
+                        당신은 또한 <literal>Configuration</literal>을 사용하여 인터셉터를 전역 레벨 상에 설정할 수도 있다. 
+                        이 경우에, 인터셉터는 threadsafe이어야 한다.
+        </para>
+    
+        <programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
+        
+        <para>
+            <literal>SessionFactory</literal>-영역의 인터셉터는 <literal>SessionFactory</literal>을 빌드하기에 앞서 
+            <literal>Configuration</literal> 객체에 등록된다. 이 경우에, 공급되는 인터셉터는 그 <literal>SessionFactory</literal>로부터
+                        열려진 모든 세션들에 적용될 것이다; 하나의 세션이 사용할 인터셉터를 명시적으로 지정하여 열리지 않는 한 이것은 참이다. 
+            <literal>SessionFactory</literal>-영역의 인터셉터들은 세션-지정적인 상태를 저장하지 않도록 주의하여 쓰레드-안전해야 한다. 
+                        왜냐하면 다중 세션들은 (잠정적으로) 이 인터셉터를 동시적으로 사용할 것이기 때문이다.
+        </para>
+    
+        <programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
+
+    </sect1>
+
+     <sect1 id="objectstate-events" revision="4">
+        <title>이벤트 시스템</title>
+
+        <para>
+                        만일 당신이 당신의 영속 계층에서 특정 이벤트들에 대해 반응해야 한다면, 당신은 또한 Hibernate3 <emphasis>event</emphasis>
+                        아키텍처를 사용할 수도 있다. 이벤트 시스템은 부가물로 사용될 수 있거나 인터셉터들에 대한 대체물로 사용될 수 있다.
+        </para>
+
+        <para>
+                        본질적으로 <literal>Session</literal> 인터페이스의 모든 메소드들은 이벤트와 서로 관련되어 있다. 
+                        당신은 <literal>LoadEvent</literal>, 
+            <literal>FlushEvent</literal>, 등을 갖는다 (정의된 이벤트 타입들의 전체 리스트에 대해서는 XML 구성 파일 DTD 또는 
+            <literal>org.hibernate.event</literal> 패키지를 참조하라). 하나의 요청이 이들 메소드들 중 하나에 의해 만들어질 때, 
+            Hibernate <literal>Session</literal>은  적절한 이벤트를 생성시키고 그것을 그 타입의 구성된 이벤트 리스너에게 전달한다. 
+                        박싱없이, 이들 리스너들은 그들 메소드들이 항상 귀결되었던 동일한 프로세싱을 구현한다. 하지만 당신이 리스너 인터페이스들 중 하나의 맞춤을 
+                        구현하는 것이 자유롭고(예를 들어 <literal>LoadEvent</literal>는 <literal>LoadEventListener</literal> 인터페이스의 
+                        등록된 구현에 의해 처리된다), 그 경우에 그들 구현은 <literal>Session</literal>에 대해 행해진 임의의 <literal>load()</literal> 
+                        요청들을 처리할 책임이 있을 것이다.
+        </para>
+
+        <para>
+                        리스너들은 효율적이게끔 싱글톤(singleton)들로 간주되어야 할 것이다; 이것은 그것들이 요청들 사이에서 공유되고, 따라서 임의의 상태를 
+                        인스턴스 변수들로서 저장하지 말아야 함을 의미한다.
+        </para>
+
+        <para>
+                        맞춤형 리스너는 그것이 편의적인 기저 클래스들(또는 리스너들이 이 용도로 final이 아닌 것으로 선언되므로 Hibernate 
+            out-of-the-box에 의해 사용된 디폴트 이벤트 리스너들) 중 하나를 처리하고/하거나 확장하고자 원하는 이벤트들에 대해 
+                        적절한 인터페이스를 구현해야 한다. 맞춤형 리스너들은 <literal>Configuration</literal> 객체를 통해 프로그램 상으로 
+                        등록될 수 있거나, Hibernate 구성 XML 속에 지정될 수 있다 (properties 파일을 통한 선언적인 구성은 지원되지 않는다). 
+                        다음은 맞춤형 load 이벤트 리스너에 대한 예제이다:
+        </para>
+
+        <programlisting><![CDATA[public class MyLoadListener implements LoadEventListener {
+    // this is the single method defined by the LoadEventListener interface
+    public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
+            throws HibernateException {
+        if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
+            throw MySecurityException("Unauthorized access");
+        }
+    }
+}]]></programlisting>
+
+        <para>
+                        당신은 또한 디폴트 리스너에 덧붙여 그 리스너를 사용하도록 Hibernate에게 알려주는 구성 엔트리를 필요로 한다:
+        </para>
+
+<programlisting><![CDATA[<hibernate-configuration>
+    <session-factory>
+        ...
+        <event type="load">
+            <listener class="com.eg.MyLoadListener"/>
+            <listener class="org.hibernate.event.def.DefaultLoadEventListener"/>
+        </event>
+    </session-factory>
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+                        대신에 당신은 그것을 프로그래밍 방식으로 등록할 수도 있다:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration();
+LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() };
+cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
+
+        <para>
+                        선언적으로 등록된 리스너들은 인스턴스들을 공유할 수 없다. 만일 동일한 클래스 이름이 여러 개의 <literal>&lt;listener/&gt;</literal> 
+                        요소들에서 사용될 경우, 각각의 참조는 그 클래스에 대한 별도의 인스턴스로 귀결될 것이다. 만일 당신이 리스너 타입들 사이에서 리스너 인스턴스들을 
+                        공유할 가용성을 필요로 할 경우 당신은 프로그래밍 방식의 등록 접근법을 사용해야 한다.
+        </para>
+
+        <para>
+                        구성 동안에 왜 인터페이스를 구현하고 특정 타입을 지정하는가? 물론 리스너 구현은 여러 개의 이벤트 리스너 인터페이스들을 
+                        구현할 수 있다. 등록 동안에 추가적으로 타입을 정의하는 것은 컨피그레이션 동안에 맞춤형 리스너들의 사용 여부를 전환시키는 것을 
+                        더 쉽게 해준다.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="objectstate-decl-security" revision="2">
+        <title>Hibernate 선언적인 보안</title>
+        <para>
+                       대개 Hibernate 어플리케이션들에서 선언적인 보안은 session facade 계층 내에서 관리된다. 이제, Hibernate3는 어떤 액션들이 
+           JACC를 통해 퍼미션을 주어지고, JAAS를 통해 인가되는 것을 허용해준다. 이것은 모든 아키텍처의 상단에 빌드된 옵션 기능이다.
+        </para>
+        
+        <para>
+                        먼저, 당신은 JAAS authorization 사용을 이용 가능하도록 하기 위해 적절한 이벤트 리스터들을 구성해야 한다.
+        </para>
+        
+        <programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
+<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
+<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
+<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
+
+        <para>
+            <literal>&lt;listener type="..." class="..."/&gt;</literal>는 특정 이벤트 타입에 대해 정확히 한 개의 
+                        리스너가 존재할 때  단지 <literal>&lt;event type="..."&gt;&lt;listener class="..."/&gt;&lt;/event&gt;</literal>의 
+                        단축형임을 노트하라.
+        </para>
+
+        <para>
+                        다음으로, 여전히 <literal>hibernate.cfg.xml</literal> 내에서 퍼미션들을 role들에 바인드 시킨다 :
+        </para>
+        
+        <programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
+<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
+        
+        <para>
+                        역할(role) 이름들은 당신의 JACC 프로바이더에 의해 인지된 역할(role)들이다.
+        </para>
+       
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/example_mappings.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/example_mappings.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/example_mappings.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,652 @@
+<chapter id="example-mappings">
+    <title>예제: 여러 가지 매핑들</title>
+    
+    <para>
+                이 장은 몇몇 보다 복잡한 연관 매핑들을 보여준다.
+    </para>
+    
+    <sect1 id="example-mappings-emp">
+        <title>Employer/Employee</title>
+
+        <para>
+            <literal>Employer</literal>와 <literal>Employee</literal> 사이의 관계에 대한 다음 모형은 그 연관를 표현하는 데 
+                        실제 엔티티 클래스(<literal>Employment</literal>)를 사용한다. 동일한 두 부분들에 대해 하나 이상의 채용 주기가 존재할 수 있기 
+                        때문에 이것이 행해진다. 컴포넌트들이 화폐 값들과 종업원 이름들을 모형화 시키는데 사용된다.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/EmployerEmployee.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/EmployerEmployee.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+                        다음은 가능한 매핑 문서이다:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+        
+    <class name="Employer" table="employers">
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employer_id_seq</param>
+            </generator>
+        </id>
+        <property name="name"/>
+    </class>
+
+    <class name="Employment" table="employment_periods">
+
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employment_id_seq</param>
+            </generator>
+        </id>
+        <property name="startDate" column="start_date"/>
+        <property name="endDate" column="end_date"/>
+
+        <component name="hourlyRate" class="MonetaryAmount">
+            <property name="amount">
+                <column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>
+            </property>
+            <property name="currency" length="12"/>
+        </component>
+
+        <many-to-one name="employer" column="employer_id" not-null="true"/>
+        <many-to-one name="employee" column="employee_id" not-null="true"/>
+
+    </class>
+
+    <class name="Employee" table="employees">
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employee_id_seq</param>
+            </generator>
+        </id>
+        <property name="taxfileNumber"/>
+        <component name="name" class="Name">
+            <property name="firstName"/>
+            <property name="initial"/>
+            <property name="lastName"/>
+        </component>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+                그리고 다음은 <literal>SchemaExport</literal>에 의해 생성된 테이블 스키마이다.
+    </para>
+
+    <programlisting><![CDATA[create table employers (
+    id BIGINT not null, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+create table employment_periods (
+    id BIGINT not null,
+    hourly_rate NUMERIC(12, 2),
+    currency VARCHAR(12), 
+    employee_id BIGINT not null, 
+    employer_id BIGINT not null, 
+    end_date TIMESTAMP, 
+    start_date TIMESTAMP, 
+    primary key (id)
+)
+
+create table employees (
+    id BIGINT not null, 
+    firstName VARCHAR(255), 
+    initial CHAR(1), 
+    lastName VARCHAR(255), 
+    taxfileNumber VARCHAR(255), 
+    primary key (id)
+)
+
+alter table employment_periods 
+    add constraint employment_periodsFK0 foreign key (employer_id) references employers
+alter table employment_periods 
+    add constraint employment_periodsFK1 foreign key (employee_id) references employees
+create sequence employee_id_seq
+create sequence employment_id_seq
+create sequence employer_id_seq]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="example-mappings-authorwork">
+        <title>Author/Work</title>
+
+        <para>
+            <literal>Work</literal>, <literal>Author</literal> 그리고 <literal>Person</literal> 사이의 관계들에 대한 
+                        다음 모형을 검토하자. 우리는 <literal>Work</literal>과 <literal>Author</literal> 사이의 관계를 many-to-many 
+                        연관으로 표현한다. 우리는 <literal>Author</literal>와 <literal>Person</literal> 사이의 관계를 one-to-one 
+                        연관으로 표현하고자 선택한다. 또 다른 가능성은 <literal>Author</literal>가 <literal>Person</literal>을 확장하도록 
+                        하는 것일 것이다. 
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/AuthorWork.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/AuthorWork.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+                        다음 매핑 문서는 이들 관계들을 정확하게 표현한다:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Work" table="works" discriminator-value="W">
+
+        <id name="id" column="id">
+            <generator class="native"/>
+        </id>
+        <discriminator column="type" type="character"/>
+
+        <property name="title"/>
+        <set name="authors" table="author_work">
+            <key column name="work_id"/>
+            <many-to-many class="Author" column name="author_id"/>
+        </set>
+
+        <subclass name="Book" discriminator-value="B">
+            <property name="text"/>
+        </subclass>
+
+        <subclass name="Song" discriminator-value="S">
+            <property name="tempo"/>
+            <property name="genre"/>
+        </subclass>
+
+    </class>
+
+    <class name="Author" table="authors">
+
+        <id name="id" column="id">
+            <!-- The Author must have the same identifier as the Person -->
+            <generator class="assigned"/> 
+        </id>
+
+        <property name="alias"/>
+        <one-to-one name="person" constrained="true"/>
+
+        <set name="works" table="author_work" inverse="true">
+            <key column="author_id"/>
+            <many-to-many class="Work" column="work_id"/>
+        </set>
+
+    </class>
+
+    <class name="Person" table="persons">
+        <id name="id" column="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+                이 매핑에는 네 개의 테이블들이 존재한다. <literal>works</literal>, <literal>authors</literal>와 
+        <literal>persons</literal>은 각각 작업 데이터, 저자 데이터, 개인 데이터를 보관한다. <literal>author_work</literal>는 
+                저자들을 작업들에 연결시키는 연관 테이블이다. 다음은 <literal>SchemaExport</literal>에 의해 생성된 테이블 
+                스키마이다.
+    </para>
+
+    <programlisting><![CDATA[create table works (
+    id BIGINT not null generated by default as identity, 
+    tempo FLOAT, 
+    genre VARCHAR(255), 
+    text INTEGER, 
+    title VARCHAR(255), 
+    type CHAR(1) not null, 
+    primary key (id)
+)
+
+create table author_work (
+    author_id BIGINT not null, 
+    work_id BIGINT not null, 
+    primary key (work_id, author_id)
+)
+
+create table authors (
+    id BIGINT not null generated by default as identity, 
+    alias VARCHAR(255), 
+    primary key (id)
+)
+
+create table persons (
+    id BIGINT not null generated by default as identity, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+alter table authors 
+    add constraint authorsFK0 foreign key (id) references persons
+alter table author_work 
+    add constraint author_workFK0 foreign key (author_id) references authors
+alter table author_work
+    add constraint author_workFK1 foreign key (work_id) references works]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-mappings-customerorderproduct">
+        <title>Customer/Order/Product</title>
+
+        <para>
+                        이제 <literal>Customer</literal>, <literal>Order</literal>와 <literal>LineItem</literal> 
+                        그리고 <literal>Product</literal> 사이의 관계들에 관한 모형을 검토하자. <literal>Customer</literal>와 
+            <literal>Order</literal> 사이의 one-to-many 연관이 존재하지만, 우리는 어떻게 
+            <literal>Order</literal> / <literal>LineItem</literal> / <literal>Product</literal>를 
+                        표현할 것인가? 나는 <literal>Order</literal>와 <literal>Product</literal> 사이의 many-to-many 
+                        연관를 나타내는 하나의 연관 클래스로서 <literal>LineItem</literal>을 매핑하기로 선택했다. Hibernate에서 
+                        이것은 composite 요소로 명명된다.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+                        매핑 문서:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Customer" table="customers">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+        <set name="orders" inverse="true">
+            <key column="customer_id"/>
+            <one-to-many class="Order"/>
+        </set>
+    </class>
+
+    <class name="Order" table="orders">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="date"/>
+        <many-to-one name="customer" column="customer_id"/>
+        <list name="lineItems" table="line_items">
+            <key column="order_id"/>
+            <list-index column="line_number"/>
+            <composite-element class="LineItem">
+                <property name="quantity"/>
+                <many-to-one name="product" column="product_id"/>
+            </composite-element>
+        </list>
+    </class>
+
+    <class name="Product" table="products">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="serialNumber"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        <literal>customers</literal>, <literal>orders</literal>, <literal>line_items</literal> 그리고 
+        <literal>products</literal>는 각각 고객 데이터, 주문 데이터, 주문 라인 아이템 데이터, 그리고 제품 데이터를 
+                보관한다. <literal>line_items</literal>는 또한 주문들을 제품들과 연결시키는 연관 테이블로서 동작한다.
+    </para>
+
+    <programlisting><![CDATA[create table customers (
+    id BIGINT not null generated by default as identity, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+create table orders (
+    id BIGINT not null generated by default as identity, 
+    customer_id BIGINT, 
+    date TIMESTAMP, 
+    primary key (id)
+)
+
+create table line_items (
+    line_number INTEGER not null, 
+    order_id BIGINT not null, 
+    product_id BIGINT, 
+    quantity INTEGER, 
+    primary key (order_id, line_number)
+)
+
+create table products (
+    id BIGINT not null generated by default as identity, 
+    serialNumber VARCHAR(255), 
+    primary key (id)
+)
+
+alter table orders 
+    add constraint ordersFK0 foreign key (customer_id) references customers
+alter table line_items
+    add constraint line_itemsFK0 foreign key (product_id) references products
+alter table line_items
+    add constraint line_itemsFK1 foreign key (order_id) references orders]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="misc">
+        <title>기타 예제 매핑들</title>
+        
+        <para>
+                        이들 예제들은 모두 Hiberante test suite로부터 취했다. 당신은 거기서 많은 
+                        다른 유용한 예제 매핑들을 발견할 것이다. Hibernate 배포본의 <literal>test</literal> 
+                        폴더를 살펴보라.
+        </para>
+        
+        <para>TODO: 이 내용을 둘러싼 말들을 집어넣을 것.</para>
+        
+        <sect2 id="example-mappings-typed-onetone">
+            <title>"형식화된(Typed)" one-to-one 연관</title>
+<programlisting><![CDATA[<class name="Person">
+    <id name="name"/>
+    <one-to-one name="address" 
+            cascade="all">
+        <formula>name</formula>
+        <formula>'HOME'</formula>
+    </one-to-one>
+    <one-to-one name="mailingAddress" 
+            cascade="all">
+        <formula>name</formula>
+        <formula>'MAILING'</formula>
+    </one-to-one>
+</class>
+
+<class name="Address" batch-size="2" 
+        check="addressType in ('MAILING', 'HOME', 'BUSINESS')">
+    <composite-id>
+        <key-many-to-one name="person" 
+                column="personName"/>
+        <key-property name="type" 
+                column="addressType"/>
+    </composite-id>
+    <property name="street" type="text"/>
+    <property name="state"/>
+    <property name="zip"/>
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="example-mappings-composite-key">
+            <title>Composite 키 예제</title>
+<programlisting><![CDATA[<class name="Customer">
+
+    <id name="customerId"
+        length="10">
+        <generator class="assigned"/>
+    </id>
+
+    <property name="name" not-null="true" length="100"/>
+    <property name="address" not-null="true" length="200"/>
+
+    <list name="orders"
+            inverse="true"
+            cascade="save-update">
+        <key column="customerId"/>
+        <index column="orderNumber"/>
+        <one-to-many class="Order"/>
+    </list>
+
+</class>
+
+<class name="Order" table="CustomerOrder" lazy="true">
+    <synchronize table="LineItem"/>
+    <synchronize table="Product"/>
+    
+    <composite-id name="id" 
+            class="Order$Id">
+        <key-property name="customerId" length="10"/>
+        <key-property name="orderNumber"/>
+    </composite-id>
+    
+    <property name="orderDate" 
+            type="calendar_date"
+            not-null="true"/>
+    
+    <property name="total">
+        <formula>
+            ( select sum(li.quantity*p.price) 
+            from LineItem li, Product p 
+            where li.productId = p.productId 
+                and li.customerId = customerId 
+                and li.orderNumber = orderNumber )
+        </formula>
+    </property>
+    
+    <many-to-one name="customer"
+            column="customerId"
+            insert="false"
+            update="false" 
+            not-null="true"/>
+        
+    <bag name="lineItems"
+            fetch="join" 
+            inverse="true"
+            cascade="save-update">
+        <key>
+            <column name="customerId"/>
+            <column name="orderNumber"/>
+        </key>
+        <one-to-many class="LineItem"/>
+    </bag>
+    
+</class>
+    
+<class name="LineItem">
+    
+    <composite-id name="id" 
+            class="LineItem$Id">
+        <key-property name="customerId" length="10"/>
+        <key-property name="orderNumber"/>
+        <key-property name="productId" length="10"/>
+    </composite-id>
+    
+    <property name="quantity"/>
+    
+    <many-to-one name="order"
+            insert="false"
+            update="false" 
+            not-null="true">
+        <column name="customerId"/>
+        <column name="orderNumber"/>
+    </many-to-one>
+    
+    <many-to-one name="product"
+            insert="false"
+            update="false" 
+            not-null="true"
+            column="productId"/>
+        
+</class>
+
+<class name="Product">
+    <synchronize table="LineItem"/>
+
+    <id name="productId"
+        length="10">
+        <generator class="assigned"/>
+    </id>
+    
+    <property name="description" 
+        not-null="true" 
+        length="200"/>
+    <property name="price" length="3"/>
+    <property name="numberAvailable"/>
+    
+    <property name="numberOrdered">
+        <formula>
+            ( select sum(li.quantity) 
+            from LineItem li 
+            where li.productId = productId )
+        </formula>
+    </property>
+    
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="example-mappings-composite-key-manytomany">
+            <title>공유된 합성 키 속성을 가진 Many-to-many</title>
+<programlisting><![CDATA[<class name="User" table="`User`">
+    <composite-id>
+        <key-property name="name"/>
+        <key-property name="org"/>
+    </composite-id>
+    <set name="groups" table="UserGroup">
+        <key>
+            <column name="userName"/>
+            <column name="org"/>
+        </key>
+        <many-to-many class="Group">
+            <column name="groupName"/>
+            <formula>org</formula>
+        </many-to-many>
+    </set>
+</class>
+    
+<class name="Group" table="`Group`">
+    <composite-id>
+        <key-property name="name"/>
+        <key-property name="org"/>
+    </composite-id>
+    <property name="description"/>
+    <set name="users" table="UserGroup" inverse="true">
+        <key>
+            <column name="groupName"/>
+            <column name="org"/>
+        </key>
+        <many-to-many class="User">
+            <column name="userName"/>
+            <formula>org</formula>
+        </many-to-many>
+    </set>
+</class>
+]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-content-discrimination">
+            <title>내용 기반 판별</title>
+<programlisting><![CDATA[<class name="Person"
+    discriminator-value="P">
+    
+    <id name="id" 
+        column="person_id" 
+        unsaved-value="0">
+        <generator class="native"/>
+    </id>
+    
+            
+    <discriminator 
+        type="character">
+        <formula>
+            case 
+                when title is not null then 'E' 
+                when salesperson is not null then 'C' 
+                else 'P' 
+            end
+        </formula>
+    </discriminator>
+
+    <property name="name" 
+        not-null="true"
+        length="80"/>
+        
+    <property name="sex" 
+        not-null="true"
+        update="false"/>
+    
+    <component name="address">
+        <property name="address"/>
+        <property name="zip"/>
+        <property name="country"/>
+    </component>
+    
+    <subclass name="Employee" 
+        discriminator-value="E">
+            <property name="title"
+                length="20"/>
+            <property name="salary"/>
+            <many-to-one name="manager"/>
+    </subclass>
+    
+    <subclass name="Customer" 
+        discriminator-value="C">
+            <property name="comments"/>
+            <many-to-one name="salesperson"/>
+    </subclass>
+    
+</class>]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-association-alternatekeys" revision="2">
+            <title>대체 키들에 대한 연관들</title>
+<programlisting><![CDATA[<class name="Person">
+    
+    <id name="id">
+        <generator class="hilo"/>
+    </id>
+    
+    <property name="name" length="100"/>
+    
+    <one-to-one name="address" 
+        property-ref="person"
+        cascade="all"
+        fetch="join"/>
+    
+    <set name="accounts" 
+        inverse="true">
+        <key column="userId"
+            property-ref="userId"/>
+        <one-to-many class="Account"/>
+    </set>
+    
+    <property name="userId" length="8"/>
+
+</class>
+
+<class name="Address">
+
+    <id name="id">
+        <generator class="hilo"/>
+    </id>
+
+    <property name="address" length="300"/>
+    <property name="zip" length="5"/>
+    <property name="country" length="25"/>
+    <many-to-one name="person" unique="true" not-null="true"/>
+
+</class>
+
+<class name="Account">
+    <id name="accountId" length="32">
+        <generator class="uuid"/>
+    </id>
+    
+    <many-to-one name="user"
+        column="userId"
+        property-ref="userId"/>
+    
+    <property name="type" not-null="true"/>
+    
+</class>]]></programlisting>
+        </sect2>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/example_parentchild.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/example_parentchild.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/example_parentchild.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,343 @@
+<chapter id="example-parentchild">
+    <title>예제: 부모/자식</title>
+
+    <para>
+                새로운 사용자들이 Hibernate로 행하고자 시도하는 바로 첫 번째 것들 중 하나는 부모/자식 타입의 관계를 모형화 시키는 것이다. 이것에 대한 
+                두 가지 다른 접근법들이 존재한다. 여러가지 이유들로 인해 특히 새로운 사용자들에게 가장 편한 접근법은 <literal>Parent</literal>로부터 
+        <literal>Child</literal>로의 <literal>&lt;one-to-many&gt;</literal> 연관을 가진 엔티티 클래스들로서  <literal>Parent</literal>와 
+        <literal>Child</literal> 양자를 모형화 시키는 것이다. (다른 접근법은 <literal>Child</literal>를 
+        <literal>&lt;composite-element&gt;</literal>로 선언하는 것이다.) 이제, (Hibernate에서) one to many 연관에 대한 디폴트 
+                의미는 composite 요소 매핑의 의미보다 부모/자식 관계의 통상적인 의미에 훨씬 덜 가깝다는 것이 판명된다. 우리는 부모/자식 관계를 효율적이고 
+                강력하게 모형화 시키기 위해 <emphasis>케스케이드들을 가진 양방향 one to many 연관</emphasis>을 사용하는 방법을 설명할 것이다. 
+                그것은 전혀 어렵지 않다!
+    </para>
+    
+    <sect1 id="example-parentchild-collections">
+        <title>콜렉션들에 관한 노트</title>
+
+        <para>
+            Hibernate 콜렉션들은 그것들의 소유하고 있는 엔티티의 논리적 부분으로 간주된다; 결코 포함된 엔티티들의 부분이 아니다. 이것은 
+                        중대한 구분점이다! 그것은 다음은 다음 결과들을 갖는다:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+            <para>
+                                콜렉션으로부터 객체를 제거하고/콜렉션에 객체를 추가 시킬 때, 콜렉션 소유자의 버전 번호가 증가된다.
+            </para>
+            </listitem>
+            <listitem>
+            <para>
+                                만일 콜렉션으로부터 제거되었던 객체가 하나의 값 타입의 인스턴스(예를 들어 composite 요소)이면, 그 객체는 영속상태를 끝내고 
+                                그것의 상태가 데이터베이스로부터 완전히 제거될 것이다. 마찬가지로 하나의 값 타입의 인스턴스를 콜렉션에 추가시키는 것은 그것의 
+                                상태가 즉시 영속화 되도록 강제시킬 것이다.
+            </para>
+            </listitem>
+            <listitem>
+            <para>
+                                반면에, 만일 엔티티가 콜렉션으로부터 제거될 경우(one-to-many 또는 many-to-many 연관), 그것은 디폴트로 삭제되지 않을 
+                                것이다. 이 특징은 완전하게 일관적이다 - 다른 엔티티의 내부 상태에 대한 변경은 연관된 엔티티를 사라지도록 강제하지 않을 것이다! 
+                                마찬가지로 콜렉션에 엔티티를 추가시키는 것은 디폴트로 그 엔티티가 영속화 되도록 강제시키지 않는다.
+            </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+                        대신에 콜렉션으로의 엔티티 추가가 두 엔티티들 사이에 단지 하나의 링크를 생성시키는 반면에, 그것을 제거하는 것은 링크를 제거한다는 점이 
+                        디폴트 특징이다. 이것은 모든 종류의 경우들에 대해 매우 적절하다. 그것이 전혀 적절하지 않은 곳은 부모/자식 관계인 경우이고, 여기서 
+                        자식의 생애는 부모의 생명주기에 묶여져 있다.
+        </para>
+    
+    </sect1>
+
+    <sect1 id="example-parentchild-bidir">
+        <title>ì–‘ë°©í–¥ one-to-many</title>
+
+        <para>
+            <literal>Parent</literal>로부터 <literal>Child</literal>로의 간단한 <literal>&lt;one-to-many&gt;</literal> 
+                        연관관계로 시작한다고 가정하자.
+        </para>
+
+        <programlisting><![CDATA[<set name="children">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+    
+        <para>
+                        우리가 다음 코드를 실행시켰다면
+        </para>
+
+        <programlisting><![CDATA[Parent p = .....;
+Child c = new Child();
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+    
+        <para>
+            Hibernate는 두 개의 SQL 문장들을 실행할 것이다:
+        </para>
+
+        <itemizedlist>
+        <listitem>
+            <para><literal>c</literal>에 대한 레코드를 생성시키는 <literal>INSERT</literal></para>
+        </listitem>
+        <listitem>
+            <para><literal>p</literal>로부터 <literal>c</literal>로의 링크를 생성시키는  <literal>UPDATE</literal></para>
+        </listitem>
+        </itemizedlist>
+    
+        <para>
+                        이것은 비효율적일 뿐만 아니라, 또한 <literal>parent_id</literal> 컬럼 상의 임의의 <literal>NOT NULL</literal> 
+                        컨스트레인트에 위배된다. 우리는 콜렉션 매핑에서 <literal>not-null="true"</literal>를 지정함으로써 null 허용 가능 
+                        컨스트레인트 위반을 정정할 수 있다:
+        </para>
+
+        <programlisting><![CDATA[<set name="children">
+    <key column="parent_id" not-null="true"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+    
+        <para>
+        	하지만 이것은 권장되는 해결책이 아니다.
+       	</para>
+       	<para>
+                        이 행위의 기본 원인은 <literal>p</literal>로부터 <literal>c</literal>로의 링크(foreign key <literal>parent_id</literal>)가 
+            <literal>Child</literal> 객체의 상태의 부분으로 간주되지 않고 그러므로 <literal>INSERT</literal>로 생성되지 않는다는 
+                        점이다. 따라서 해결책은 <literal>Child</literal> 매핑의 링크 부분을 만드는 것이다. 
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
+
+        <para>
+            (우리는 또한 <literal>parent</literal> 프로퍼티를 <literal>Child</literal> 클래스에 추가시킬 필요가 있다.)
+        </para>
+
+        <para>
+                        이제 <literal>Child</literal> 엔티티가 링크의 상태를 관리한다는 점을 노트하고, 우리는 링크를 업데이트 시키지 말도록 콜렉션에게 
+                        통보한다. 우리는 <literal>inverse</literal> 속성을 사용한다.
+        </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+        <para>
+                        다음 코드는 새로운 <literal>Child</literal>를 추가시키는데 사용될 것이다
+        </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+        <para>
+                        그리고 이제, 유일하게 한 개의 SQL <literal>INSERT</literal>가 실행될 것이다!
+        </para>
+
+        <para>
+                        약간 거칠게, 우리는 <literal>Parent</literal>의 <literal>addChild()</literal> 메소드를 생성시킬 수 있다.
+        </para>
+
+        <programlisting><![CDATA[public void addChild(Child c) {
+    c.setParent(this);
+    children.add(c);
+}]]></programlisting>
+
+        <para>
+                        이제, <literal>Child</literal>를 추가하는 코드는 다음과 같다
+        </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+     </sect1>
+     
+     <sect1 id="example-parentchild-cascades">
+         <title>케스케이딩 생명주기</title>
+     
+         <para>
+             <literal>save()</literal>에 대한 명시적인 호출은 여전히 성가시다. 우리는 케스케이딩을 사용하여 이것을 얘기할 것이다.
+         </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true" cascade="all">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+     
+         <para>
+                          다음은 위의 코드를 단순화 시킨다
+         </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.flush();]]></programlisting>
+     
+         <para>
+                          유사하게, 우리는 <literal>Parent</literal>를 저장하거나 삭제할 때 자식들에 대해 반복하는 것을 필요로 하지 않는다. 다음은 
+                          데이터베이스로부터 <literal>p</literal>와 모든 그것의 자식들을 제거시킨다.
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+session.delete(p);
+session.flush();]]></programlisting>
+     
+         <para>
+                          하지만, 다음 코드
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+c.setParent(null);
+session.flush();]]></programlisting>
+     
+         <para>
+                          는 데이터베이스로부터 <literal>c</literal>를 제거하지 않을 것이다; 그것은 오직 <literal>p</literal>에 대한 링크만을 제거할 
+                          것이다(그리고 이 경우에 <literal>NOT NULL</literal> 컨스트레인트 위반을 일으킬 것이다 ). 당신은 명시적으로 
+             <literal>Child</literal>를 <literal>delete()</literal> 시킬 필요가 있다.
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+session.delete(c);
+session.flush();]]></programlisting>
+
+         <para>
+                          이제 우리의 경우에 <literal>Child</literal>는 그것의 부모 없이는 진정으로 존재할 수 없다. 따라서 만일 우리가 콜렉션으로부터 
+                          하나의 <literal>Child</literal>를 제거할 경우, 우리는 그것이 정말로 삭제되기를 원한다. 이를 위해 우리는 
+             <literal>cascade="all-delete-orphan"</literal>을 사용해야 한다.
+         </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true" cascade="all-delete-orphan">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+         <para>
+                          노트: 비록 콜렉션 매핑이 <literal>inverse="true"</literal>를 지정할 지라도, 케스케이드들은 여전히 콜렉션 요소들을 
+                          반복함으로써 처리된다. 따라서 객체가 케스케이드에 의해 저장되고, 삭제되거나 업데이트 되는 것을 당신이 필요로 할 경우, 당신은 
+                          그것을 그 콜렉션에 추가해야 한다. 단순히 <literal>setParent()</literal>를 호출하는 것으로는 충분하지 않다.
+         </para>
+               
+     </sect1>
+     
+     <sect1 id="example-parentchild-update">
+         <title>케스케이드들과 <literal>unsaved-value</literal></title>
+     
+         <para>
+                          우리가 하나의 <literal>Session</literal> 속에 <literal>Parent</literal>를 로드시켰고 UI 액션에서 어떤 변경들을 행했고, 
+             <literal>update()</literal>를 호출하여 새로운 세션에서 이들 변경들을 영속화 시키는 것을 원한다고 가정하자. <literal>Parent</literal>는 
+                          자식들을 가진 콜렉션을 포함할 것이고, 케스케이딩 업데이트가 사용 가능하기 때문에, Hibernate는 어느 자식들이 새로이 초기화 되는지 
+                          그리고 어느 것이 데이터베이스에서 현재 행들을 표현하는지를 알 필요가 있다. <literal>Parent</literal>와 <literal>Child</literal> 
+                          모두 <literal>Long</literal> 타입의 식별자 프로퍼티들을 생성시켰다고 가정하자. Hibernate는 어느 자식들이 새로운 것인지를 
+                          결정하는데 식별자와 version/timestamp 프로퍼티 값을 사용할 것이다.(<xref linkend="objectstate-saveorupdate"/>을 보라.) 
+             <emphasis>Hibernate3에서는<literal>unsaved-value</literal>를 더이상 명시적으로 지정할 필요가 없다.</emphasis>
+         </para>
+
+         <para>
+                          다음 코드는 <literal>parent</literal>와 <literal>child</literal>를 업데이트하고 <literal>newChild</literal>를 
+                          삽입시킬 것이다.
+         </para>
+
+         <programlisting><![CDATA[//parent and child were both loaded in a previous session
+parent.addChild(child);
+Child newChild = new Child();
+parent.addChild(newChild);
+session.update(parent);
+session.flush();]]></programlisting>
+     
+         <para>
+                          물론 그것은 생성되는 식별자의 경우에는 모두 매우 좋지만, 할당되는 식별자들과 composite 식별자들에 대해서는 어떠한가? 이것은 보다 
+                          어렵다. 왜냐하면 Hibernate는 (사용자에 의해 할당된 식별자를 가진) 새로이 초기화 된 객체와 이전 세션에서 로드되었던 객체 사이를 
+                          구별짓는데 식별자 프로퍼티를 사용할 수 없기 때문이다. 이 경우에, Hibernate는 timestamp 프로퍼티 또는 version 프로퍼티를 
+                          사용하거나 실제로 second-level 캐시를 질의하거나 가장 나쁜 경우에는 행이 존재하는지를 알기 위해 데이터베이스를 질의할 것이다.
+         </para>
+         
+         <!-- undocumenting
+         <para>
+             There is one further possibility. The <literal>Interceptor</literal> method named 
+             <literal>isUnsaved()</literal> lets the application implement its own strategy for distinguishing
+             newly instantiated objects. For example, you could define a base class for your persistent classes.
+         </para>
+
+         <programlisting><![CDATA[public class Persistent {
+    private boolean _saved = false;
+    public void onSave() {
+        _saved=true;
+    }
+    public void onLoad() {
+        _saved=true;
+    }
+    ......
+    public boolean isSaved() {
+        return _saved;
+    }
+}]]></programlisting>
+     
+         <para>
+             (The <literal>saved</literal> property is non-persistent.)
+             Now implement <literal>isUnsaved()</literal>, along with <literal>onLoad()</literal>
+             and <literal>onSave()</literal> as follows.
+         </para>
+
+         <programlisting><![CDATA[public Boolean isUnsaved(Object entity) {
+    if (entity instanceof Persistent) {
+        return new Boolean( !( (Persistent) entity ).isSaved() );
+    }
+    else {
+        return null;
+    }
+}
+
+public boolean onLoad(Object entity, 
+    Serializable id,
+    Object[] state,
+    String[] propertyNames,
+    Type[] types) {
+
+    if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
+    return false;
+}
+
+public boolean onSave(Object entity,
+    Serializable id,
+    Object[] state,
+    String[] propertyNames,
+    Type[] types) {
+        
+    if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
+    return false;
+}]]></programlisting>
+
+		<para>
+			Don't worry; in Hibernate3 you don't need to write any of this kind of code if you don't want to.
+		</para>
+     -->
+     </sect1>
+
+     <sect1 id="example-parentchild-conclusion">
+         <title>ê²°ë¡ </title>
+
+         <para>
+                          여기에 숙지할 것이 약간 있고 그것은 처음에는 혼동스러운 것처럼 보일 수 있다. 하지만 실제로 그것은 모두 매우 좋게 동작한다. 대부분의 
+             Hibernate 어플리케이션들은 많은 장소들에서 부모/자식 패턴을 사용한다.
+         </para>
+
+         <para>
+                          우리는 첫 번째 단락에서 대안을 언급했다. 위의 쟁점들 중 어느 것도  정확하게 부모/자식 관계의 의미를 가진, 
+             <literal>&lt;composite-element&gt;</literal> 매핑들의 경우에는 존재하지 않는다. 불행히도, composite 요소 클래스들에 
+                          대한 두 개의 커다란 제약들이 존재한다:  composite 요소들은 콜렉션들을 소유하지 않고, 그것들은 유일한 부모가 아닌 다른 어떤 
+                          엔티티의 자식일 수는 없다.
+         </para>
+     
+     </sect1>
+     
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/example_weblog.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/example_weblog.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/example_weblog.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,428 @@
+<chapter id="example-weblog">
+    <title>예제: Weblog 어플리케이션</title>
+
+    <sect1 id="example-weblog-classes">
+        <title>영속 클래스들</title>
+
+        <para>
+                        영속 클래스들은 웹로그, 그리고 웹 로그 내에 게시된 항목을 표현한다.그것들은 
+                        표준 부모/자식 관계로 모형화 될 것이지만, 우리는 set 대신에 순서지워진 bag를 사용할 것이다.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+import java.util.List;
+
+public class Blog {
+    private Long _id;
+    private String _name;
+    private List _items;
+
+    public Long getId() {
+        return _id;
+    }
+    public List getItems() {
+        return _items;
+    }
+    public String getName() {
+        return _name;
+    }
+    public void setId(Long long1) {
+        _id = long1;
+    }
+    public void setItems(List list) {
+        _items = list;
+    }
+    public void setName(String string) {
+        _name = string;
+    }
+}]]></programlisting>
+
+        <programlisting><![CDATA[package eg;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+
+public class BlogItem {
+    private Long _id;
+    private Calendar _datetime;
+    private String _text;
+    private String _title;
+    private Blog _blog;
+
+    public Blog getBlog() {
+        return _blog;
+    }
+    public Calendar getDatetime() {
+        return _datetime;
+    }
+    public Long getId() {
+        return _id;
+    }
+    public String getText() {
+        return _text;
+    }
+    public String getTitle() {
+        return _title;
+    }
+    public void setBlog(Blog blog) {
+        _blog = blog;
+    }
+    public void setDatetime(Calendar calendar) {
+        _datetime = calendar;
+    }
+    public void setId(Long long1) {
+        _id = long1;
+    }
+    public void setText(String string) {
+        _text = string;
+    }
+    public void setTitle(String string) {
+        _title = string;
+    }
+}]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-weblog-mappings">
+        <title>Hibernate 매핑들</title>
+
+        <para>
+            XML 매핑들은 이제  매우 간단해질 것이다.
+        </para>
+        
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+    <class
+        name="Blog"
+        table="BLOGS">
+
+        <id
+            name="id"
+            column="BLOG_ID">
+
+            <generator class="native"/>
+
+        </id>
+
+        <property
+            name="name"
+            column="NAME"
+            not-null="true"
+            unique="true"/>
+
+        <bag
+            name="items"
+            inverse="true"
+            order-by="DATE_TIME"
+            cascade="all">
+
+            <key column="BLOG_ID"/>
+            <one-to-many class="BlogItem"/>
+
+        </bag>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+    <class
+        name="BlogItem"
+        table="BLOG_ITEMS"
+        dynamic-update="true">
+
+        <id
+            name="id"
+            column="BLOG_ITEM_ID">
+
+            <generator class="native"/>
+
+        </id>
+
+        <property
+            name="title"
+            column="TITLE"
+            not-null="true"/>
+
+        <property
+            name="text"
+            column="TEXT"
+            not-null="true"/>
+
+        <property
+            name="datetime"
+            column="DATE_TIME"
+            not-null="true"/>
+
+        <many-to-one
+            name="blog"
+            column="BLOG_ID"
+            not-null="true"/>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="example-weblog-code">
+        <title>Hibernate 코드</title>
+
+        <para>
+                        다음 클래스는 우리가 Hibernate를 사용하여 이들 클래스들로 행할 수 있는 몇몇 종류의 것들을 설명한다.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+
+public class BlogMain {
+    
+    private SessionFactory _sessions;
+    
+    public void configure() throws HibernateException {
+        _sessions = new Configuration()
+            .addClass(Blog.class)
+            .addClass(BlogItem.class)
+            .buildSessionFactory();
+    }
+    
+    public void exportTables() throws HibernateException {
+        Configuration cfg = new Configuration()
+            .addClass(Blog.class)
+            .addClass(BlogItem.class);
+        new SchemaExport(cfg).create(true, true);
+    }
+    
+    public Blog createBlog(String name) throws HibernateException {
+        
+        Blog blog = new Blog();
+        blog.setName(name);
+        blog.setItems( new ArrayList() );
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.persist(blog);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return blog;
+    }
+    
+    public BlogItem createBlogItem(Blog blog, String title, String text)
+                        throws HibernateException {
+        
+        BlogItem item = new BlogItem();
+        item.setTitle(title);
+        item.setText(text);
+        item.setBlog(blog);
+        item.setDatetime( Calendar.getInstance() );
+        blog.getItems().add(item);
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.update(blog);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return item;
+    }
+    
+    public BlogItem createBlogItem(Long blogid, String title, String text)
+                        throws HibernateException {
+        
+        BlogItem item = new BlogItem();
+        item.setTitle(title);
+        item.setText(text);
+        item.setDatetime( Calendar.getInstance() );
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            Blog blog = (Blog) session.load(Blog.class, blogid);
+            item.setBlog(blog);
+            blog.getItems().add(item);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return item;
+    }
+    
+    public void updateBlogItem(BlogItem item, String text)
+                    throws HibernateException {
+        
+        item.setText(text);
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.update(item);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+    }
+    
+    public void updateBlogItem(Long itemid, String text)
+                    throws HibernateException {
+    
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            BlogItem item = (BlogItem) session.load(BlogItem.class, itemid);
+            item.setText(text);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+    }
+    
+    public List listAllBlogNamesAndItemCounts(int max)
+                    throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        List result = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "select blog.id, blog.name, count(blogItem) " +
+                "from Blog as blog " +
+                "left outer join blog.items as blogItem " +
+                "group by blog.name, blog.id " +
+                "order by max(blogItem.datetime)"
+            );
+            q.setMaxResults(max);
+            result = q.list();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return result;
+    }
+    
+    public Blog getBlogAndAllItems(Long blogid)
+                    throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        Blog blog = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "from Blog as blog " +
+                "left outer join fetch blog.items " +
+                "where blog.id = :blogid"
+            );
+            q.setParameter("blogid", blogid);
+            blog  = (Blog) q.uniqueResult();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return blog;
+    }
+    
+    public List listBlogsAndRecentItems() throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        List result = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "from Blog as blog " +
+                "inner join blog.items as blogItem " +
+                "where blogItem.datetime > :minDate"
+            );
+
+            Calendar cal = Calendar.getInstance();
+            cal.roll(Calendar.MONTH, false);
+            q.setCalendar("minDate", cal);
+            
+            result = q.list();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return result;
+    }
+}]]></programlisting>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/filters.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/filters.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/filters.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,138 @@
+<chapter id="filters">
+    <title>데이터 필터링하기</title>
+    
+    <para>
+        Hibernate3은 혁신적인 "가시성(visibility)" 규칙들로서 데이터를 처리하는 새로운 접근법을 제공한다. <emphasis>Hibernate 
+                필터</emphasis>는 특정 Hibernate 세션에 대해 이용 가능하게 되거나 이용 불가능하게 될 수도 있는 전역, 명명된 파라미터화 된 필터이다.
+    </para>
+
+    <sect1 id="objectstate-filters" revision="1">
+        <title>Hibernate 필터들</title>
+
+        <para>
+            Hibernate3은 필터 기준(criteria)을 미리 정의하고 클래스 레벨과 콜렉션 레벨 양자에서 그들 필터들을 첨부할 능력을 추가시킨다. 
+                        필터 기준(criteria)은 클래스 요소와 다양한 콜렉션 요소들에 대해 이용 가능한 기존의 "where" 속성과 매우 유사한 하나의 제한 절을 
+                        정의하는 능력이다. 이것들을 제외하면 필터 조건들은 파라미터화 될 수 있다. 그때 어플리케이션은 주어진 필터들이 이용 가능한지 여부 
+                        그리고 그들 파라미터 값들이 무엇이어야 하는지를 실행 시에 결정할 수 있다. 필터들은 데이터베이스 뷰들 처럼 사용될 수 있지만, 
+                        어플리케이션 내부에 파라미터화 된다.
+        </para>
+
+        <para>
+                        필터들을 사용하기 위해서, 그것들은 먼저 정의되고 나서 적절한 매핑 요소들에 첨가되어야 한다. 필터를 정의하기 위해, 
+            <literal>&lt;hibernate-mapping/&gt;</literal> 요소 내부에 <literal>&lt;filter-def/&gt;</literal> 요소를 
+                        사용하라:
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="myFilter">
+    <filter-param name="myFilterParam" type="string"/>
+</filter-def>]]></programlisting>
+
+        <para>
+                       그때 이 필터는 클래스에 첨가될 수 있다:
+        </para>
+
+        <programlisting><![CDATA[<class name="myClass" ...>
+    ...
+    <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</class>]]></programlisting>
+
+        <para>
+                        또는 콜렉션에 첨가될 수 있다:
+        </para>
+
+        <programlisting><![CDATA[<set ...>
+    <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</set>]]></programlisting>
+
+        <para>
+                        또는 동시에 양자에(또는 각각의 여러번) 첨가될 수 있다.
+        </para>
+
+        <para>
+            <literal>Session</literal> 상의 메소드들은 다음과 같다: <literal>enableFilter(String filterName)</literal>, 
+            <literal>getEnabledFilter(String filterName)</literal>, <literal>disableFilter(String filterName)</literal>. 
+                        디폴트로, 필터들은 주어진 세션에 대해 이용 가능하지 <emphasis>않다</emphasis>; 그것들은 <literal>Session.enabledFilter()</literal> 
+                        메소드의 사용을 통해 명시적으로 이용 가능하게 되어야 한다. <literal>Session.enabledFilter()</literal>는 
+            <literal>Filter</literal> 인터페이스의 인스턴스를 반환한다. 위에 정의된 간단한 필터를 사용하면, 이것은 다음과 같을 것이다:
+        </para>
+
+        <programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
+
+        <para>
+            org.hibernate.Filter 인터페이스 상의 메소드들은 Hibernate에 매우 공통된 method-chaining을 허용한다는 점을 노트하라.
+        </para>
+
+        <para>
+                        유효한 기록 날짜 패턴을 가진 시간 데이터를 사용하는 전체 예제 :
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="effectiveDate">
+    <filter-param name="asOfDate" type="date"/>
+</filter-def>
+
+<class name="Employee" ...>
+...
+    <many-to-one name="department" column="dept_id" class="Department"/>
+    <property name="effectiveStartDate" type="date" column="eff_start_dt"/>
+    <property name="effectiveEndDate" type="date" column="eff_end_dt"/>
+...
+    <!--
+        Note that this assumes non-terminal records have an eff_end_dt set to
+        a max db date for simplicity-sake
+    -->
+    <filter name="effectiveDate"
+            condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+</class>
+
+<class name="Department" ...>
+...
+    <set name="employees" lazy="true">
+        <key column="dept_id"/>
+        <one-to-many class="Employee"/>
+        <filter name="effectiveDate"
+                condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+                        그때 당신이 현재 유효한 레코드들을 항상 얻는 것을 확실히 하기 위해, employee 데이터를 검색하기 전에 세션 상에 필터를 
+                        간단하게 이용 가능하게 하라:
+        </para>
+
+<programlisting><![CDATA[Session session = ...;
+session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
+List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
+         .setLong("targetSalary", new Long(1000000))
+         .list();
+]]></programlisting>
+
+        <para>
+                        위의 HQL 에서, 심지어 비록 우리가 결과들에 대한 봉급 컨스트레인트를 명시적으로 언급만 했을지라도, 이용 가능한 필터 때문에 
+                        그 질의는 봉급이 백만달러 이상인 현재 채용중인 직원들만을 반환할 것이다.
+        </para>
+
+        <para>
+                        노트: 만일 당신이 outer 조인에 대해 필터들을 사용할 계획이라면 (HQL이든 로드 페칭이든) 조건 표현식의 방향을 주의하라. 
+                        이것을 left outer join으로 설정하는 것이 가장 안전하다; 일반적으로 오퍼레이터 뒤에 있는 컬럼 이름(들)이 뒤따르는 첫번째에 
+                        파라미터를 위치지워라.
+        </para>
+
+    </sect1>
+
+        <para>
+            필터가 정의된 후에는 그것 자신의 조건에 대해 각각 여러 개의 엔티티들 그리고/또는 콜렉션들에 첨가될 수 있다. 
+            조건들이 매번 동일할 때 그것은 지루할 수 있다. 따라서 <literal>&lt;filter-def/&gt;</literal>은 
+            attribute 든 CDATA 든 어느것이든 디폴트 조건을 정의하는 것을 허용해준다:
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="myFilter" condition="abc > xyz">...</filter-def>
+<filter-def name="myOtherFilter">abc=xyz</filter-def>]]></programlisting>
+
+        <para>
+            그때 이 디폴트 조건은 그 필터가 어떤 조건을 지정함이 없이 어떤 것에 첨가될때마다 사용될 수 있다.
+            이것은 당신이 특정한 경우에 디폴트 조건을 오버라이드 시키는 필터의 첨가 부분으로서 특정 조건을 
+            부여할 수 있음을 의미함을 노트하라.
+        </para>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/inheritance_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/inheritance_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/inheritance_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,459 @@
+<chapter id="inheritance">
+    <title>상속 매핑</title>
+
+    <sect1 id="inheritance-strategies" revision="3">
+        <title>세 가지 방도들</title>
+
+        <para>
+            Hibernate는 세 가지 기본적인 상속 매핑 방도들을 지원한다:
+        </para>
+
+        <itemizedlist>
+        <listitem>
+        <para>
+            table per class hierarchy
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            table per subclass
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            table per concrete class
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+                        게다가 Hibernate는 네 번째의 약간 다른 종류의 다형성을 지원한다:
+        </para>
+
+        <itemizedlist>
+        <listitem>
+        <para>
+            implicit polymorphism(함축적인 다형성)
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+                        동일한 상속 계층구조의 다른 가지들에 대해 다른 매핑 방도들을 사용하는 것이 가능하고, 그런 다음 전체 계층 구조를 가로질러 
+                        다형성을 성취하는데 함축적인 다형성을 사용하라. 하지만 Hibernate는 동일한 루트 <literal>&lt;class&gt;</literal> 요소 
+                        하에서 <literal>&lt;subclass&gt;</literal> 그리고 <literal>&lt;joined-subclass&gt;</literal> 그리고 
+            <literal>&lt;union-subclass&gt;</literal> 매핑들을 혼합하는 것을 지원하지 않는다. 동일한 <literal>&lt;class&gt;</literal> 
+                        요소 하에서 <literal>&lt;subclass&gt;</literal> 요소와 <literal>&lt;join&gt;</literal> 요소를 결합시킴으로써 
+            table per hierarchy 방도와 table per subclass 방도를 함께 혼합시키는 것이 가능하다(아래를 보라). 
+        </para>
+
+        <para>
+                          별도의 매핑 문서 내에, <literal>hibernate-mapping</literal> 바로 밑에 <literal>subclass</literal>, 
+             <literal>union-subclass</literal>, 그리고 <literal>joined-subclass</literal> 매핑들을 정의하는 것이 
+                         가능하다. 이것은 단지 하나의 새로운 매핑 파일을 추가시켜서 하나의 class 계층구조를 확장하는 것을 당신에게 허용해준다. 
+                         당신은 subclass 매핑 내에 앞서 매핑된 슈퍼클래스를 명명하여 <literal>extends</literal> 속성을 지정해야 한다. 
+                         노트 : 명백하게 이 특징은 매핑 문서들의 순서를 중요하게끔 만들었다. Hibernate3 이후로, 매핑 파일들의 순서는 extends 키워드를 
+                         사용할 때 상관없다. 하나의 매핑 파일 내의 순서는 여전히 서브클래스들에 앞서 슈퍼클래스들을 정의하는데 여전히 필요하다.
+         </para>
+
+         <programlisting><![CDATA[
+ <hibernate-mapping>
+     <subclass name="DomesticCat" extends="Cat" discriminator-value="D">
+          <property name="name" type="string"/>
+     </subclass>
+ </hibernate-mapping>]]></programlisting>
+
+
+        <sect2 id="inheritance-tableperclass" >
+        <title>Table per class hierarchy</title>
+
+        <para>
+                        우리가 <literal>CreditCardPayment</literal>, <literal>CashPayment</literal>, <literal>ChequePayment</literal> 
+                        구현자들을 가진 하나의 인터페이스 <literal>Payment</literal>를 갖고 있다고 가정하자. table per hierarchy 매핑은 
+                        다음과 같을 것이다:
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        ...
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        ...
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+                        정확히 하나의 테이블이 필요하다. 이 매핑 방도에는 다음의 하나의 큰 제약이 존재한다: <literal>CCTYPE</literal>과 같이, 
+                        서브 클래스들에 의해 선언된 컬럼들은 <literal>NOT NULL</literal> 컨스트레인트들을 가질 수 없다.
+        </para>
+        
+        </sect2>
+
+        <sect2 id="inheritance-tablepersubclass">
+        <title>Table per subclass</title>
+
+        <para>
+            table per subclass 매핑은 다음과 같을 것이다:
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        ...
+    </joined-subclass>
+</class>]]></programlisting>
+
+        <para>
+                        네 개의 테이블들이 필요하다. 세 개의 서브클래스 테이블들은 슈퍼클래스 테이블에 대한 프라이머리 키 연관들을 갖는다
+            (따라서 그 관계형 모형은 실제로 one-to-one 연관이다). 
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-tablepersubclass-discriminator" revision="2">
+        <title>discriminator를 사용하는, table per subclass</title>
+
+        <para>
+            table-per-subclass에 대한 Hibernate의 구현은 discriminator(판별자) 컬럼을 필요로 하지 않음을 노트하라. 
+                        다른 객체/관계형 매핑기들은 슈퍼클래스 테이블 속에 하나의 타입 판별자 컬럼을 필요로 하는 table-per-subclass에 대한 다른 구현을 
+                        사용한다. Hibernate에 의해 채택된 접근법은 구현하기가 훨씬 더 어렵지만 관계형 관점에서는 아마 틀림없이 보다 더 정확하다. 
+                        만일 당신이 table per subclass 방도에 대해 하나의 판별자 컬럼을 사용하고 싶다면, 당신은 다음과 같이 
+            <literal>&lt;subclass&gt;</literal>와 <literal>&lt;join&gt;</literal>의 사용을 결합시킬 수도 있다:
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <join table="CREDIT_PAYMENT">
+            <key column="PAYMENT_ID"/>
+            <property name="creditCardType" column="CCTYPE"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        <join table="CASH_PAYMENT">
+            <key column="PAYMENT_ID"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        <join table="CHEQUE_PAYMENT" fetch="select">
+            <key column="PAYMENT_ID"/>
+            ...
+        </join>
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+                        선택적인 <literal>fetch="select"</literal> 선언은 슈퍼클래스를 질의할 때 outer join을 사용하여 
+            <literal>ChequePayment</literal> 서브클래스 데이터를 페치시키지 않도록 Hibernate에게 알려준다.
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
+        <title>table per class hierarchy와 table per subclass를 혼합하기</title>
+
+        <para>
+                        당신은 이 접근법을 사용하여 table per hierarchy 방도와 table per subclass 방도를 혼합시킬 수 있다: 
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <join table="CREDIT_PAYMENT">
+            <property name="creditCardType" column="CCTYPE"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        ...
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        ...
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+                        이들 매핑 방도들 중 어떤 것에 대해, 루트 <literal>Payment</literal> 클래스에 대한 하나의 다형성 연관은 
+            <literal>&lt;many-to-one&gt;</literal>을 사용하여 매핑된다.
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
+    
+        </sect2>
+
+        <sect2 id="inheritance-tableperconcrete" revision="2">
+        <title>Table per concrete class</title>
+
+        <para>
+                        우리가 table per concrete class 방도 매핑에 대해 취할 수 있는 두 가지 방법들이 존재한다. 첫 번째는 
+            <literal>&lt;union-subclass&gt;</literal>를 사용하는 것이다.
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="sequence"/>
+    </id>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </union-subclass>
+    <union-subclass name="CashPayment" table="CASH_PAYMENT">
+        ...
+    </union-subclass>
+    <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        ...
+    </union-subclass>
+</class>]]></programlisting>
+
+        <para>
+                        세 개의 테이블들이 슈퍼클래스들에 대해 수반된다. 각각의 테이블은 상속된 프로퍼티들을 포함하여, 그 클래스의 모든 프로퍼티들에 대한 컬럼들을 정의한다. 
+        </para>
+        
+        <para>
+                        이 접근법의 제약은 만일 하나의 프로퍼티가 슈퍼클래스 상으로 매핑될 경우, 그 컬럼 이름이 모든 서브클래스 테이블들 상에서 같아야 한다는 
+                        점이다.(장래의 Hibernate 배포본에서 우리는 이 제약을 풀 수도 있다.) identity 생성기 방도는 union 서브클래스 상속에서 허용되지 
+                        않으며, 진정 프라이머리 키 시드는 하나의 계층구조의 모든 unioned 서브클래스들을 가로질러 공유되어야 한다. 
+        </para>
+        
+        <para>
+                        만일 당신의 슈퍼클래스가 abstract일 경우에, 그것을 <literal>abstract="true"</literal>로 매핑하라. 
+                        물론 만일 그것이 abstract가 아닐 경우, 추가적인 테이블(위의 예제에서는 디폴트로 <literal>PAYMENT</literal>)이 
+                        슈퍼클래스의 인스턴스들을 소유하는데 필요하다.
+        </para>
+        
+        </sect2>
+
+        <sect2 id="inheritance-tableperconcreate-polymorphism">
+        <title>함축적인 다형성을 사용하는, table per concrete class</title>
+
+        <para>
+                        대안적인 접근법은 함축적인 다형성을 사용하는 것이다:
+        </para>
+
+        <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+    <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CREDIT_AMOUNT"/>
+    ...
+</class>
+
+<class name="CashPayment" table="CASH_PAYMENT">
+    <id name="id" type="long" column="CASH_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CASH_AMOUNT"/>
+    ...
+</class>
+
+<class name="ChequePayment" table="CHEQUE_PAYMENT">
+    <id name="id" type="long" column="CHEQUE_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CHEQUE_AMOUNT"/>
+    ...
+</class>]]></programlisting>
+           
+        <para>
+                        어느 곳에서도 우리가 명시적으로 <literal>Payment</literal> 인터페이스를 언급하지 않음을 주목하라. 
+                        또한 <literal>Payment</literal>의 프로퍼티들이 서브클래스들 각각에서 매핑된다는 점을 주목하라. 
+                        만일 당신이 중복을 피하고자 원한다면, XML 엔티티들을 사용하는 것을 고려하라(예를 들어 매핑에서 
+            <literal>DOCTYPE</literal> 선언과 <literal>&amp;allproperties;</literal>에서 
+            <literal>[ &lt;!ENTITY allproperties SYSTEM "allproperties.xml"&gt; ]</literal>).
+        </para>
+        
+        <para>
+                        이 접근법의 단점은 다형성 질의들을 수행할 때 Hibernate가 생성된 SQl <literal>UNION</literal>들을 생성시키는 
+                        않는다는 점이다. 
+        </para>
+
+        <para>
+                        이 매핑 방도의 경우, <literal>Payment</literal>에 대한 하나의 다형성 연관은 대개 <literal>&lt;any&gt;</literal>를 
+                        사용하여 매핑된다.
+        </para>
+
+        <programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
+    <meta-value value="CREDIT" class="CreditCardPayment"/>
+    <meta-value value="CASH" class="CashPayment"/>
+    <meta-value value="CHEQUE" class="ChequePayment"/>
+    <column name="PAYMENT_CLASS"/>
+    <column name="PAYMENT_ID"/>
+</any>]]></programlisting>
+           
+        </sect2>
+
+        <sect2 id="inheritace-mixingpolymorphism">
+        <title>함축적인 다형성을 다른 상속 매핑들과 혼합하기</title>
+
+        <para>
+                        이 매핑에 대해 주목할 하나 이상의 것이 존재한다. 서브클래스들이 그것들 자신의<literal>&lt;class&gt;</literal> 요소 내에 
+                        각각 매핑되므로(그리고 <literal>Payment</literal>가 단지 인터페이스이므로), 서브클래스들 각각은 쉽게 또 다른 상속 계층구조의 
+                        부분일 수 있다! (그리고 당신은 <literal>Payment</literal> 인터페이스에 대해 여전히 다형성 질의들을 사용할 수 있다.)
+       </para>
+
+        <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+    <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="CREDIT_CARD" type="string"/>
+    <property name="amount" column="CREDIT_AMOUNT"/>
+    ...
+    <subclass name="MasterCardPayment" discriminator-value="MDC"/>
+    <subclass name="VisaPayment" discriminator-value="VISA"/>
+</class>
+
+<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
+    <id name="id" type="long" column="TXN_ID">
+        <generator class="native"/>
+    </id>
+    ...
+    <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="amount" column="CASH_AMOUNT"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="amount" column="CHEQUE_AMOUNT"/>
+        ...
+    </joined-subclass>
+</class>]]></programlisting>
+
+        <para>
+                        다시 한번, 우리는 <literal>Payment</literal>를 명시적으로 언급하지 않는다. 만일 우리가 <literal>Payment</literal> 
+                        인터페이스에 대해 하나의 질의를 실행할 경우-예를 들어, from Payment-, Hibernate는 <literal>CreditCardPayment</literal>
+            (와 그것의 서브클래스들, 왜냐하면 그것들 또한 <literal>Payment</literal>를 구현하므로), <literal>CashPayment</literal> 
+                        그리고 <literal>ChequePayment</literal> 인스턴스들을 자동적으로 반환할 것이지만 
+            <literal>NonelectronicTransaction</literal>의 인스턴스들을 반환하지 않는다. 
+        </para>
+        
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="inheritance-limitations">
+        <title>제약들</title>
+
+        <para>
+            table per concrete-class 매핑 방도에 대한 "함축적인 다형성" 접근법에는 어떤 제약들이 존재한다. 
+            <literal>&lt;union-subclass&gt;</literal> 매핑들에 대해서는 다소 덜 제한적인 제약들이 존재한다:
+        </para>
+
+        <para>
+                        다음 표는 Hibernate에서 table per concrete-class 매핑들에 대한 제약들, 그리고 함축적인 다형성에 대한 제약들을 보여준다.
+        </para>
+            
+        <table frame="topbot">
+            <title>상속 매핑들의 특징들</title>
+            <tgroup cols='8' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="1*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <colspec colname='c6' colwidth="1*"/>
+            <colspec colname='c7' colwidth="1*"/>
+            <colspec colname='c8' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>상속 방도</entry>
+              <entry>다형성 다대일</entry>
+              <entry>다형성 일대일</entry>
+              <entry>다형성 일대다</entry>
+              <entry>다형성 다대다</entry>
+              <entry>다형성 <literal>load()/get()</literal></entry>
+              <entry>다형성 질의들</entry>
+              <entry>다형성 조인들</entry>
+              <entry>Outer 조인 페칭</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>table per class-hierarchy</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal></entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>지원됨</emphasis></entry>
+            </row>
+            <row>
+                <entry>table per subclass</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal></entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>지원됨</emphasis></entry>
+            </row>
+            <row>
+                <entry>table per concrete-class (union-subclass)</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal> (for <literal>inverse="true"</literal> only)</entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>지원됨</emphasis></entry>
+            </row>
+            <row>
+                <entry>table per concrete class (implicit polymorphism)</entry>
+                <entry><literal>&lt;any&gt;</literal></entry>
+                <entry><emphasis>지원되지 않음</emphasis></entry>
+                <entry><emphasis>지원되지 않음</emphasis></entry>
+                <entry><literal>&lt;many-to-any&gt;</literal></entry>
+                <entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><emphasis>지원되지 않음</emphasis></entry>
+                <entry><emphasis>지원되지 않음</emphasis></entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/performance.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/performance.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/performance.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1293 @@
+<chapter id="performance">
+    <title>퍼포먼스 개선하기</title>
+
+    <sect1 id="performance-fetching" revision="2">
+        <title>페칭 방도들</title>
+
+        <para>
+            <emphasis>페칭 방도</emphasis>는 어플리케이션이 연관을 네비게이트할 필요가 있을 때 Hibernate가 연관된 객체들을 검색하는데 
+                        사용하게 될 방도이다.페치 방도들은 O/R 매핑 메타데이터 내에서 선언될 수 있거나 하나의 특정 HQL 또는 <literal>Criteria</literal> 
+                        질의에 의해 오버라이드 될 수도 있다.
+        </para>
+
+        <para>
+            Hibernate3는 다음 페칭 방도들을 정의한다:
+        </para>
+
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <emphasis>Join 페칭</emphasis> - Hibernate는 <literal>OUTER JOIN</literal>을 사용하여 연관된 인스턴스 
+                                        또는 동일한 <literal>SELECT</literal> 내에서 콜렉션을 검색한다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Select 페칭</emphasis> - 두 번째 <literal>SELECT</literal>는 연과된 엔티티 또는 콜렉션을 검색하는데 
+                                        사용된다. 당신이 <literal>lazy="false"</literal>를 지정함으로써 명시적으로 lazy 페칭을 사용 불가능하게 하지 않는 
+                                        한, 이 두 번째 select는 당신이 그 연관에 실제로 액세스할 때 오직 실행될 것이다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Subselect 페칭</emphasis> - 두 번째 <literal>SELECT</literal>는 이전 질의 또는 페치에서 검색된 
+                                        모든 엔티티들에 대해 연관된 콜렉션들을 검색하는데 사용된다. 당신이 <literal>lazy="false"</literal>를 지정하여 
+                                        명시적으로 lazy 페칭을 사용 불가능하게 하지 않는 한, 이 두 번째 select는 당신이 실제로 그 연관에 접근할 때 오직 실행될 
+                                        것이다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Batch 페칭</emphasis> - select 페칭을 위한 최적화 방도 - Hibernate는 프라이머리 키들이나 foreign 
+                                        키들의 리스트를 지정함으로써 하나의<literal>SELECT</literal> 내에서 엔티티 인스턴스들이나 콜렉션들에 대한 batch를 
+                                        검색한다.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            Hibernate는 또한 다음 사이를 구별 짓는다:
+        </para>
+
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <emphasis>즉각적인 페칭</emphasis> - 소유자가 로드될 때, 연관, 콜렉션 또는 속성이 즉시 페치된다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Lazy 콜렉션 페칭</emphasis> - 어플리케이션이 그 콜렉션에 대해 하나의 오퍼레이션을 호출할 때 
+                                        콜렉션이 페치된다.(이것은 콜렉션들에 대해 디폴트이다.)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>"Extra-lazy" 콜렉션 페칭</emphasis> - 콜렉션의 개별 요소들은 필요할 때 
+                                        데이터베이스로부터 접근된다. Hibernate는 절대적으로 필요하지 않은 한 전체 콜렉션을 메모리 내로 
+                                        페치하려고 시도하지 않는다(매우 큰 콜렉션에 적합함)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>프락시 페칭</emphasis> - 식별자 getter가 아닌 다른 메소드가 연관된 객체에 대해 호출될 때 
+                                        단일 값 연관이 페치된다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>"No-proxy" 페칭</emphasis> - 인스턴스 변수가 접근될 때 단일 값 연관이 페치된다.
+                                        프락시 페칭과 비교할 때, 이 접근법은 다소 덜 lazy하지만(그 연관은 심지어 유일하게 식별자가 접근될 때에도 
+                                        페치된다)보다 투명하다. 왜냐하면 프락시는 어플리케이션에 가시적이지 않기 때문이다. 이 접근법은 빌드 시 
+                                        바이트코드 수단을 필요로 하며 드물게 필요하다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Lazy 속성 페칭</emphasis> - 인스턴스 변수가 접근될 때 속성 또는 단일 값 연관이 페치된다
+                    이 접근법은 빌드시 바이트코드 수단을 필요로 하며 드물게 필요하다.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+                        우리는 여기서 두 개의 직교하는 개념들을 갖는다: 연관이 페치될 <emphasis>때</emphasis>, 그리고 그것이 페치되는 
+            <emphasis>방법</emphasis>(사용되는 SQL). 그것들을 혼동하지 말라! 우리는 퍼포먼스를 튜팅하는데 
+            <literal>페치</literal>를 사용한다. 우리는 특정 클래스의 어떤 detached 인스턴스 내에서 항상 이용 가능한 
+                        데이터가 무엇인지에 대한 계약을 정의하는데 <literal>lazy</literal>를 사용할 수 있다.
+        </para>
+ 
+        <sect2 id="performance-fetching-lazy">
+            <title>lazy 연관들로 작업하기</title>
+            
+            <para>
+                                디폴트로 Hibernate3는 콜렉션들에 대해 lazy select 페칭을 사용하고, 단일 값 연관들에 대해 lazy 
+                                프락시 페칭을 사용한다. 이들 디폴트들은 거의 모든 어플리케이션들에서 거의 모든 연관들에 대해 유의미하다. 
+            </para>
+            
+            <para>
+                <emphasis>노트:</emphasis> 만일 당신이 <literal>hibernate.default_batch_fetch_size</literal>를 설정하는 
+                                경우, Hibernate는 lazy 페칭을 위한 batch 페치 최적화를 사용할 것이다(이 최적화는 또한 더 많은 과립상의 레벨에서 이용 가능할 
+                                수 있다).
+            </para>
+            
+            <para>
+                                하지만, lazy 페칭은 당신이 알고 있어야 하는 한 가지 문제를 제기한다. 열려진 Hibernate 세션 컨텍스트 외부에서 lazy 연관에 
+                                대한 접근은 예외상황으로 귀결될 것이다. 예를 들면 :
+            </para>
+        
+            <programlisting><![CDATA[s = sessions.openSession();
+Transaction tx = s.beginTransaction();
+            
+User u = (User) s.createQuery("from User u where u.name=:userName")
+    .setString("userName", userName).uniqueResult();
+Map permissions = u.getPermissions();
+
+tx.commit();
+s.close();
+
+Integer accessLevel = (Integer) permissions.get("accounts");  // Error!]]></programlisting>
+
+            <para>
+                <literal>Session</literal>이 닫혔을 때 permissions 콜렉션이 초기화 되지 않았으므로, 그 콜렉션은 그것의 상태를 로드시킬 
+                                수가 없을 것이다. <emphasis>Hibernate 는 detached 객체들에 대한 lazy 초기화를 지원하지 않는다.</emphasis> 정정은 
+                                콜렉션으로부터 읽어들이는 코드를 커밋 바로 직전으로 이동시키는 것이다.
+            </para>
+    
+            <para>
+                                다른 방법으로 연관 매핑에 대해 <literal>lazy="false"</literal>를 지정함으로써, non-lazy  콜렉션 또는 
+                non-lazy 연관을 사용할 수 있다. 하지만 lazy 초기화는 거의 모든 콜렉션들과 연관들에 대해 사용되도록 고안되어 있다. 
+                                만일 당신이 당신의 객체 모형 내에 너무 많은 non-lazy 연관들을 정의할 경우, Hibernate는 모든 트랜잭션에서 전체 
+                                데이터베이스를 메모리 속으로 페치하는 필요성을 끝내게 될 것이다!
+            </para>
+    
+            <para>
+                                다른 한편으로, 우리는 특정 트랜잭션 내에서 select 페칭 대신에 (고유하게 non-lazy인) join 페칭을 선택하기를 자주 원한다. 
+                                우리는 이제 페칭 방도를 맞춤화 시키는 방법을 알게 될 것이다. Hibernate3에서, 페치 방도를 선택하는 메커니즘은 단일 값 연관들과 
+                                콜렉션들에 대해 동일하다.
+            </para>
+        
+        </sect2>
+        
+        <sect2 id="performance-fetching-custom" revision="4">
+            <title>페치 방도들을 튜닝하기</title>
+            
+            <para>
+                select 페칭(디폴트)은 N+1 selects 문제점들에 매우 취약해서, 우리는 매핑 문서에서 join 페칭을 사용 가능하게 하기를 원할 
+                                수도 있다:
+            </para>
+            
+            <programlisting><![CDATA[<set name="permissions" 
+            fetch="join">
+    <key column="userId"/>
+    <one-to-many class="Permission"/>
+</set]]></programlisting>
+
+           <programlisting><![CDATA[<many-to-one name="mother" class="Cat" fetch="join"/>]]></programlisting>
+
+            <para>
+                                매핑 문서 내에 정의된 <literal>fetch</literal> 방도는 다음에 영향을 준다:
+            </para>
+            
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <literal>get()</literal> 또는 <literal>load()</literal>를 통한 검색
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        연관이 네비게이트될 때 함축적으로 발생하는 검색
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>Criteria</literal> 질의들
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>subselect</literal> 페칭이 사용될 경우에 HQL 질의들
+                </para>
+            </listitem>
+        </itemizedlist>
+
+            <para>
+                                당신이 사용하는 페칭 방도가 무엇인가에 상관없이, 정의된 비-lazy 그래프가 메모리 내로 로드되는 것이 보장된다. 
+                                이것은 하나의 특별한 HQL 질의를 실행시키는데 사용되는 몇몇 즉시적인 select들로 귀결될 수 있음을 노트하라.
+            </para>
+
+            <para>            
+                                대개, 우리는 페칭을 맞춤화 시키는데 매핑 문서를 사용하지 않는다. 대신에, 우리는 디폴트 특징을 유지하고, HQL에서 
+                <literal>left join fetch</literal>를 사용하여, 특정 트랜잭션에 대해 그것을 오버라이드 시킨다. 이것은 
+                outer join을 사용하여 첫 번째 select에서 초기에 그 연관을 eagerly 페치시킬 것을 Hibernate에게 알려준다. 
+                <literal>Criteria</literal> query API에서, 우리는 <literal>setFetchMode(FetchMode.JOIN)</literal>을 
+                                사용한다.
+            </para>
+            
+            <para>
+                                만일 당신이 <literal>get()</literal> 또는 <literal>load()</literal>에 의해 사용된 페칭 방도를 변경시킬 수 있기를 
+                                당신이 원한다고 느낄 경우, 단순하게 <literal>Criteria</literal> 질의를 사용하라. 예를 들면:
+            </para>
+            
+            <programlisting><![CDATA[User user = (User) session.createCriteria(User.class)
+                .setFetchMode("permissions", FetchMode.JOIN)
+                .add( Restrictions.idEq(userId) )
+                .uniqueResult();]]></programlisting>
+                
+            <para>
+                (이것은 몇몇 ORM 솔루션들이 "페치 계획"이라고 부르는 것에 대한 Hibernate의 등가물이다.)
+            </para>
+
+            <para>
+                N+1 개의 select들을 가진 문제점들을 피하는 완전히 다른 방법은 second-level 캐시를 사용하는 것이다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-proxies" revision="2">
+            <title>Single-ended 연관 프락시</title>
+
+            <para>
+                                콜렉션들에 대한 Lazy 페칭은 영속 콜렉션들에 대한 Hibernate 자신의 구현을 사용하여 구현된다. 하지만 다른 메커니즘은 
+                single-ended 연관들에서 lazy 특징에 필요하다. 연관의  대상 엔티티는 프락시 되어야 한다. Hibernate는 
+                (훌륭한 CGLIB 라이브러리를 통해) 런타임 바이트코드 증진을 사용하여 영속 객체들에 대한 lazy 초기화 프락시들을 구현한다.
+            </para>
+
+            <para>
+                                디폴트로, Hibernate3는 모든 영속 클래스들에 대해 (시작 시에) 프락시들을 생성시키고 <literal>many-to-one</literal> 
+                                연관과 <literal>one-to-one</literal> 연관에 대해 lazy 페칭을 이용 가능하게 하는데 그것들을 사용한다.
+            </para>
+
+            <para>
+                                매핑 파일은 그 클래스에 대한 프락시 인터페이스로서 사용할, <literal>proxy</literal> 속성을 가진, 인터페이스를 선언할 
+                                수도 있다. 디폴트로 Hibernate는 그 클래스의 서브클래스를 사용한다. <emphasis>프락시된 클래스는 최소한의 패키지 가시성
+                (visibility)을 가진 디폴트 생성자를 구현해야 함을 노트하라. 우리는 모든 영속 클래스들에 대해 이 생성자를 권장한다!</emphasis>
+            </para>
+
+            <para>
+                                다형성 클래스들에 대해 이 접근법을 확장할 때 의식해야 하는 몇몇 난처함들이 존재한다. 예를 들면.
+            </para>
+
+            <programlisting><![CDATA[<class name="Cat" proxy="Cat">
+    ......
+    <subclass name="DomesticCat">
+        .....
+    </subclass>
+</class>]]></programlisting>
+
+            <para>
+                                첫 번째로, 심지어 기본 인스턴스가 <literal>DomesticCat</literal>의 인스턴스인 경우조차도, 
+                <literal>Cat</literal>의 인스턴스들은 결코 <literal>DomesticCat</literal>으로 타입캐스트가 가능하지 않을 것이다:
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id);  // instantiate a proxy (does not hit the db)
+if ( cat.isDomesticCat() ) {                  // hit the db to initialize the proxy
+    DomesticCat dc = (DomesticCat) cat;       // Error!
+    ....
+}]]></programlisting>
+
+            <para>
+                                두번째로, 프락시 <literal>==</literal>를 파기할 가능성이 있다.
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id);            // instantiate a Cat proxy
+DomesticCat dc = 
+        (DomesticCat) session.load(DomesticCat.class, id);  // acquire new DomesticCat proxy!
+System.out.println(cat==dc);                            // false]]></programlisting>
+
+            <para>
+                                하지만, 그 경우는 보이는 만큼 그렇게 나쁘지는 않다. 심지어 우리가 이제 다른 프락시 객체들에 대한 두 개의 참조를 가질지라도, 
+                                기본 인스턴스는 여전히 동일한 객체들일 것이다:
+            </para>
+
+            <programlisting><![CDATA[cat.setWeight(11.0);  // hit the db to initialize the proxy
+System.out.println( dc.getWeight() );  // 11.0]]></programlisting>
+
+            <para>
+                                세번째로, 당신은 <literal>final</literal> 클래스 또는  임의의 <literal>final</literal> 메소드들을 가진 클래스에 
+                                대해 CGLIB 프락시를 사용하지 않을 수 있다.
+            </para>
+
+            <para>
+                                마지막으로, 만일 당신의 영속 객체가 초기화 시에 어떤 리소스들을 필요로 할 경우(예를 들어, initializer들 또는 디폴트 생성자 
+                                내에서), 그때 그들 리소스들이 또한 프락시에 의해 획득될 것이다. 프락시 클래스는 영속 클래스에 대한 실제 서브클래스이다.
+            </para>
+
+            <para>
+                                이들 문제점들은 모두 자바의 단일 상속 모형의 기본적인 제약 때문이다. 만일 당신이 이들 문제점들을 피하고자 원할 경우 당신의 영속 
+                                클래스들은 각각 그것의 비지니스 메소드들을 선언하는 인터페이스를 구현해야 한다. 당신은 매핑 파일 속에 이들 인터페이스들을 
+                                지정해야 한다. 예를 들면.
+            </para>
+
+            <programlisting><![CDATA[<class name="CatImpl" proxy="Cat">
+    ......
+    <subclass name="DomesticCatImpl" proxy="DomesticCat">
+        .....
+    </subclass>
+</class>]]></programlisting>
+
+            <para>
+                                여기서 <literal>CatImpl</literal>은 <literal>Cat</literal> 인터페이스를 구현하고 <literal>DomesticCatImpl</literal>은 
+                <literal>DomesticCat</literal> 인터페이스를 구현한다. 그때 <literal>Cat</literal>과 <literal>DomesticCat</literal>의 
+                                인스턴스들에 대한 프락시들은 <literal>load()</literal> 또는 <literal>iterate()</literal>에 의해 반환될 수 있다.
+                (<literal>list()</literal>가 대개 프락시들을 반환하지 않음을 노트하라.)
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(CatImpl.class, catid);
+Iterator iter = session.iterate("from CatImpl as cat where cat.name='fritz'");
+Cat fritz = (Cat) iter.next();]]></programlisting>
+
+            <para>
+                                관계들은 또한 lazy 초기화 된다. 이것은 당신이 임의의 프로퍼티들을  <literal>CatImpl</literal> 타입이 아닌 
+                <literal>Cat</literal> 타입으로 선언해야 함을 의미한다.
+            </para>
+
+            <para>
+                                어떤 오퍼레이션들은 프락시 초기화를 필요로 하지 <emphasis>않는다</emphasis>
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>equals()</literal>, 만일 영속 클래스가 <literal>equals()</literal>를 오버라이드 시키지 않는 경우
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>hashCode()</literal>, 만일 영속 클래스가<literal>hashCode()</literal>를 오버라이드 시키지 
+                                                않는 경우
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                                                식별자 getter 메소드
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Hibernate는 <literal>equals()</literal> 또는 <literal>hashCode()</literal>를 오버라이드 시키는 영속 클래스들을 
+                                검출할 것이다.
+            </para>
+            
+            <para>
+                                디폴트 <literal>lazy="proxy"</literal> 대신에 <literal>lazy="no-proxy"</literal>를 선택하여,
+                                우리는 타입캐스팅과 연관된 문제점들을 피할 수 있다. 하지만 우리는 빌드 시 바이트코드 수단을 필요로 할 것이고, 
+                                모든 연산들은 즉각적인 프락시 초기화로 귀결될 것이다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-initialization" revision="1">
+            <title>콜렉션들과 프락시들을 초기화 시키기</title>
+
+            <para>
+                                만일 초기화 되지 않은 콜렉션이나 프락시가 <literal>Session</literal> 영역의 외부에서 접근될 경우에, 예를 들어 콜렉션을 
+                                소유하거나 프락시에 대한 참조를 가진 엔티티가 detached 상태에 있을 때, <literal>LazyInitializationException</literal>이 
+                Hibernate에 의해 던져질 것이다.
+            </para>
+
+            <para>
+                                때때로 우리는<literal>Session</literal>을 닫기 전에 프락시 또는 콜렉션이 초기화 됨을 확실히 할 필요가 있다. 물론 우리는 
+                                예를 들어 <literal>cat.getSex()</literal> 또는 <literal>cat.getKittens().size()</literal>를 호출하여 항상 
+                                초기화를 강제시킬 수 있다. 그러나 그것은 코드의 독자들에게는 혼동스럽고 일반적인 코드로 편의적이지 않다.
+            </para>
+
+            <para>
+                static 메소드들 <literal>Hibernate.initialize()</literal>와 <literal>Hibernate.isInitialized()</literal>는 
+                lazy 초기화 된 콜렉션들이나 프락시들에 대해 작업하는 편리한 방법을 어플리케이션에 제공한다. <literal>Hibernate.initialize(cat)</literal>은 
+                                그것의 <literal>Session</literal>이 여전히 열려져 있는 한 프락시 <literal>cat</literal>의 초기화를 강제할 것이다. 
+                <literal>Hibernate.initialize( cat.getKittens())</literal>는 kittens의 콜렉션에 대해 유사한 효과를 갖는다.
+            </para>
+
+            <para>
+                                또 다른 옵션은 모든 필요한 콜렉션들과 프락시들이 로드되기 전까지 <literal>Session</literal>을 열린 채로 유지하는 것이다. 
+                                몇몇 어플리케이션 아키텍처들, 특히 Hibernate를 사용하여 데이터에 접근하는 코드, 그리고 다른 어플리케이션 계층들이나 다른 
+                                물리적 프로세스들 내에서 그것을 사용하는 코드에서, 그것은 콜렉션이 초기화 될 때 <literal>Session</literal>이 열려져 
+                                있음을 확실히 하는 문제일 수 있다. 이 쟁점을 다루는 두 가지 기본 방법들이 존재한다:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                                                웹 기반 어플리케이션에서, 서블릿 필터는 뷰 렌더링이 완료되는, 사용자 요청의 바로 끝에서만 <literal>Session</literal>을 
+                                                닫는데 사용될 수 있다(<emphasis>Open Session in View</emphasis> 패턴). 물론 이것은 당신의 어플리케이션 
+                                                인프라스트럭처의 예외상황 처리의 정정에 관한 무거운 요구를 부과한다. 
+                                                뷰 렌더링 동안에 하나의 예외상황이 발생할때에도 사용자에게 반환되기 전에 <literal>Session</literal>이 닫혀지고 
+                                                트랜잭션이 종료되는 것은 지극히 중요하다. 이 "Open Session in View" 패턴에 관한 예제들은 Hibernate 위키를 보라.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                                                별도의 비지니스 티어를 가진 어플리케이션에서, 비지니스 로직은 반환 전에 웹 티어에 필요한 모든 콜렉션들을 
+                        "준비"해야 한다. 이것은 비지니스 티어가 모든 데이터를 로드시키고 이미 초기화된 모든 데이터를 특정 쓰임새에 
+                                                필요한 프리젠테이션/웹 티어로 반환해야 함을 의미한다. 대개 어플리케이션은 웹 티어에 필요하게 될 각각의 콜렉션에 
+                                                대해 <literal>Hibernate.initialize()</literal>를 호출하거나(이 호출은 세션이 닫히기 전에 발생해야 한다) 
+                                                또는 <literal>FETCH</literal> 절을 갖거나 또는 <literal>Criteria</literal> 내에 
+                        <literal>FetchMode.JOIN</literal>을 가진 Hibernate 질의를 사용하여 콜렉션을 열심히 검색한다. 이것은 
+                                                대개 당신이 <emphasis>Session Facade</emphasis> 대신 <emphasis>Command</emphasis> 패턴을 채택할 
+                                                경우에 더 쉽다.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                                                당신은 또한 초기화 되지 않은 콜렉션들(또는 다른 프락시들)에 접근하기 전에 <literal>merge()</literal> 또는 
+                        <literal>lock()</literal>으로 앞서 로드된 객체를 새로운 <literal>Session</literal>n에 첨부할 수도 있다. 
+                                                아니다. Hibernate는 이것을 자동적으로 행하지 않고, 확실히 자동적으로 행하지 <emphasis>않을 것이다</emphasis>. 
+                                                왜냐하면 그것은 특별한 목적을 위한 트랜잭션 의미를 도입할 것이기 때문이다!
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                                때때로 당신은 거대한 콜렉션을 초기화 시키는 것을 원하지 않지만, 여전히 (그것의 사이즈와 같은) 그것에 대한 어떤 정보 또는 
+                                데이터의 부분집합을 필요로 한다.
+            </para>
+
+            <para>
+                                당신은 그것을 초기화 시키지 않고서 콜렉션의 사이즈를 얻는데 콜렉션 필터를 사용할 수 있다:
+            </para>
+
+            <programlisting><![CDATA[( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()]]></programlisting>
+
+            <para>
+                <literal>createFilter()</literal> 메소드는 또한 전체 콜렉션을 초기화 시킬 필요 없이 콜렉션의 부분집합들을 효율적으로 
+                                검색하는데 사용된다:
+            </para>
+
+            <programlisting><![CDATA[s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-batch">
+            <title>batch 페칭 사용하기</title>
+
+            <para>
+                Hibernate는 배치 페칭을 효율적으로 사용할 수 있다. 즉 하나의 프락시가 액세스 될 경우에 Hibernate는 몇몇 초기화 되지 않은 
+                                프락시들을 로드시킬 수 있다(또는 콜렉션들). batch 페칭은 lazy select 페칭 방도에 대한 최적화이다. 당신이 batch 
+                                페칭을 튜닝시킬 수 있는 두 가지 방법들이 존재한다: 클래스 레벨에서 그리고 콜렉션 레벨에서.
+            </para>
+
+            <para>
+                                클래스들/엔티티들에 대한 batch 페칭은 이해하기가 더 쉽다. 당신이 실행 시에 다음 상황에 처한다고 상상하라: 당신은 하나의
+                <literal>Session</literal> 속에 로드된 25개의 <literal>Cat</literal> 인스턴스들을 갖고 있고, 각각의 
+                <literal>Cat</literal>은 그것의 <literal>소유자</literal> 즉, <literal>Person</literal>에 대한 참조를 
+                                갖고 있다. <literal>Person</literal> 클래스는 프락시 <literal>lazy="true"</literal>로서 매핑된다. 만일 
+                                당신이 이제  모든 cat들을 통해 반복하고 각각의 cat에 대해 <literal>getOwner()</literal>를 호출할 경우, Hibernate는 
+                                프락시된 소유자들을 검색하기 위해 25개의 <literal>SELECT</literal> 문장들을 디폴트로 실행시킬 것이다. 당신은 
+                <literal>Person</literal> 매핑에서 <literal>batch-size</literal>를 지정함으로써 이 동작을 튜닝시킬 수 있다:
+            </para>
+
+            <programlisting><![CDATA[<class name="Person" batch-size="10">...</class>]]></programlisting>
+
+            <para>
+                Hibernate는 이제 세 개의 질의들 만을 실행시킬 것이고, 그 패턴은 10,10, 5 이다.
+            </para>
+
+            <para>
+                                당신은 또한 콜렉션들에 대해 batch 페칭을 이용 가능하게 할 수도 있다. 예를 들어, 만일 각각의 <literal>Person</literal>이 
+                <literal>Cat</literal>들을 가진 lazy 콜렉션을 갖고, 10개의 person들이 <literal>Sesssion</literal> 내에 현재 
+                                로드되어 있을 경우, 모든 person들에 대한 반복은 10개의 <literal>SELECT</literal>들을 생성시킬 것이고, <literal>getCats()</literal>에 
+                                대한 매번의 호출에 대해 하나의 <literal>SELECT</literal>를 생성시킬 것이다. 만일 당신이 <literal>Person</literal> 
+                                매핑에서 <literal>cats</literal> 콜렉션에 대해 batch 페칭을 사용가능하게 할 경우, Hibernate는 콜렉션들을 미리-페치
+                                시킬 수 있다:
+            </para>
+
+            <programlisting><![CDATA[<class name="Person">
+    <set name="cats" batch-size="3">
+        ...
+    </set>
+</class>]]></programlisting>
+
+            <para>
+                <literal>batch-size</literal> 8로서, Hibernate는 4개의 SELECT들에서 3, 3, 3, 1 개의 콜렉션들을 로드시킬 것이다. 
+                                다시 그 속성의 값은 특정 <literal>Session</literal> 내에서 초기화 되지 않은 콜렉션들의 예상되는 개수에 의존한다.
+            </para>
+
+            <para>
+                                만일 당신이 항목들의 포개진 트리를 가질 경우, 예를 들어 전형적인 bill-of-materials 패턴인 경우, (비록 
+                <emphasis>내포된 set</emphasis> 또는 <emphasis>실체화된 경로(materialized path)</emphasis>가 
+                                주로-읽기-트리들에 대해 더 좋은 옵션일 수 있을지라도) 콜렉션들에 대한 batch 페칭이 특히 유용하다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-subselect">
+            <title>subselect 페칭 사용하기</title>
+
+            <para>
+                                만일 한 개의 lazy 콜렉션이나 단일 값 프락시가  페치되어야 한다면, Hibernate는 하나의 subselect 내에서 원래의 
+                                질의를 다시 실행하여 그것들 모두를 로드시킨다. 이것은 조각난 로딩 없이 batch 페칭과 동일한 방식으로 동작한다.
+            </para>
+            
+            <!-- TODO: 이것에 대해 더 많이 작성할 것 -->
+
+        </sect2>
+        
+        <sect2 id="performance-fetching-lazyproperties">
+            <title>lazy 프로퍼티 페칭 사용하기</title>
+
+            <para>
+                Hibernate3은 개별적인 프로퍼티들에 대한 lazy 페칭을 지원한다. 이 최적화 기술은 또한 <emphasis>fetch groups</emphasis>
+                                으로 알려져 있다. 이것이 대개 마케팅 특징임을 노트하길 바란다. 왜냐하면 실제로 행 읽기를 최적화 시키는 것이 컬럼 읽기에 대한 
+                                최적화 보다 훨씬 더 중요하기 때문이다. 하지만  리거시 테이블들이 수백 개의 컬럼들을 갖고 데이터 모형이 개선될 수 없을 때, 
+                                오직 클래스의 몇몇 프로퍼티들을 로드시키는 것 만이 유용할 수도 있다.
+            </para>
+
+            <para>
+                lazy 프로퍼티 로딩을 이용가능하게 하려면, 당신의 특정 property 매핑들에 대해 <literal>lazy</literal> 속성을 설정하라:
+            </para>
+
+            <programlisting><![CDATA[<class name="Document">
+       <id name="id">
+        <generator class="native"/>
+    </id>
+    <property name="name" not-null="true" length="50"/>
+    <property name="summary" not-null="true" length="200" lazy="true"/>
+    <property name="text" not-null="true" length="2000" lazy="true"/>
+</class>]]></programlisting>
+
+            <para>
+                Lazy property 로딩은 빌드 시 바이트코드 수단을 필요로 한다! 만일 당신의 영속 클래스들이 개선되지 않을 경우, 
+                Hibernate는 조용하게 lazy 프로퍼티 설정들을 무시하고 즉각적인 페칭으로 후퇴할 것이다.
+            </para>
+
+            <para>
+                bytecode 수단으로, 다음 Ant 태스크를 사용하라:
+            </para>
+
+            <programlisting><![CDATA[<target name="instrument" depends="compile">
+    <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
+        <classpath path="${jar.path}"/>
+        <classpath path="${classes.dir}"/>
+        <classpath refid="lib.class.path"/>
+    </taskdef>
+
+    <instrument verbose="true">
+        <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
+            <include name="*.class"/>
+        </fileset>
+    </instrument>
+</target>]]></programlisting>
+
+            <para>
+                                불필요한 컬럼 읽기를 피하는 다른 (더 좋은?) 방법은 적어도 읽기 전용 트랜잭션의 경우에 HQL 질의 또는 Criteria 질의의 
+                                투사(projection) 특징들을 사용하는 것이다. 이것은 빌드 시 바이트코드 처리에 대한 필요성을 피하게 해주고 확실히 선호되는 
+                                해결책이다.
+            </para>
+            
+            <para>
+                                당신은 HQL에서 <literal>fetch all properties</literal>를 사용하여 프로퍼티들에 대한 통상의 eager 페칭을 
+                                강제시킬 수 있다.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="performance-cache" revision="1">
+        <title>두번째 레벨 캐시</title>
+
+        <para>
+            Hibernate <literal>Session</literal>은 영속 데이터에 대한 트랜잭션 레벨 캐시이다. class-by-class와 
+            collection-by-collection 기반 위에 클러스터 또는 JVM-레벨(<literal>SessionFactory</literal>-레벨) 캐시를 구성하는 
+                        것이 가능하다. 당신은 클러스터링 된 캐시 속에 플러그인 할 수도 있다. 주의하라. 캐시들은 (비록 그것들이 캐시된 데이터를 정기적으로 
+                        만료되도록 구성되어 있을지라도) 또 다른 어플리케이션에 의해 영속 저장소에 대해 행해진 변경들을 결코 알지 못한다.
+        </para>
+        
+        <para revision="1">
+                        디폴트로, Hibernate는 JVM-레벨의 캐싱에 EHCache를 사용한다. (JCS 지원은 이제 진부하게 되었고 Hibernate의 장래 버전에서 
+                        제거될 것이다.) 당신은 <literal>hibernate.cache.provider_class</literal> 프로퍼티를 사용하여 
+            <literal>org.hibernate.cache.CacheProvider</literal>를 구현하는 클래스의 이름을 지정함으로써 다른 구현을 선택할 수도 
+                        있다.
+            You have the option to tell Hibernate which caching implementation to use by
+            specifying the name of a class that implements <literal>org.hibernate.cache.CacheProvider</literal>
+            using the property <literal>hibernate.cache.provider_class</literal>.  Hibernate
+            comes bundled with a number of built-in integrations with open-source cache providers
+            (listed below); additionally, you could implement your own and plug it in as
+            outlined above.  Note that versions prior to 3.2 defaulted to use EhCache as the
+            default cache provider; that is no longer the case as of 3.2.
+                        당신은 <literal>hibernate.cache.provider_class</literal> 프로퍼티를 사용하여 
+            <literal>org.hibernate.cache.CacheProvider</literal>를 구현하는 클래스의 이름을 지정함으로써 어느 캐싱 구현을 
+                        사용할 것인지를 Hibernate에게 알려주는 옵션을 갖는다. Hibernate는 (아래에 열거된) 오픈-소스 프로바이더들을 가진 
+                        많은 빌드되어 있는 통합들을 번들로 갖고 있다; 추가적으로 당신은 위에서 언급했듯이 그것에 당신 자신의 것을 구현할 수 있고 그것에 
+                        플러그 시킬 수 있다. 3.2 이번 버전들은 디플트 캐시 프로바이더로서 EhCache를 사용하도록 디포릍로 내장되어 있음을 노트하라; 
+                        버전 3.2의 경우에 그것은 더이상 디폴트 내장이 아니다.
+        </para>
+
+        <table frame="topbot" id="cacheproviders" revision="1">
+            <title>캐시 프로바이더들</title>
+            <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="3*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>캐시</entry>
+              <entry>프로바이더 클래스</entry>
+              <entry>타입</entry>
+              <entry>클러스터 안전</entry>
+              <entry>질의 캐시 지원</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>Hashtable (제품 용도로 고안되어 있지 않음)</entry>
+                <entry><literal>org.hibernate.cache.HashtableCacheProvider</literal></entry>
+                <entry>memory</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>EHCache</entry>
+                <entry><literal>org.hibernate.cache.EhCacheProvider</literal></entry>
+                <entry>memory, disk</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>OSCache</entry>
+                <entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
+                <entry>memory, disk</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>SwarmCache</entry>
+                <entry><literal>org.hibernate.cache.SwarmCacheProvider</literal></entry>
+                <entry>clustered (ip multicast)</entry>
+                <entry>yes (clustered invalidation)</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>JBoss TreeCache</entry>
+                <entry><literal>org.hibernate.cache.TreeCacheProvider</literal></entry>
+                <entry>clustered (ip multicast), transactional</entry>
+                <entry>yes (replication)</entry>
+                <entry>yes (clock sync req.)</entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <sect2 id="performance-cache-mapping" revision="2">
+            <title>Cache 매핑들</title>
+
+            <para>
+                                클래스 또는 콜렉션 매핑의 <literal>&lt;cache&gt;</literal> 요소는 다음 형식을 갖는다:
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="cache1" coords="2 70"/>
+                    <area id="cache2" coords="3 70"/>
+                    <area id="cache3" coords="4 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<cache 
+    usage="transactional|read-write|nonstrict-read-write|read-only"
+    region="RegionName"
+    include="all|non-lazy"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="cache1">
+                        <para>
+                            <literal>usage</literal>(필수) 캐싱 방도를 지정한다:
+                            <literal>transactional</literal>,
+                            <literal>read-write</literal>,
+                            <literal>nonstrict-read-write</literal> 또는
+                            <literal>read-only</literal>
+                        </para>
+                    </callout>
+                    <callout arearefs="cache2">
+                        <para>
+                            <literal>region</literal> (옵션, 디폴트는 class 또는 콜렉션 role 이름) 
+                            second level 캐시 영역의 이름을 지정한다
+                        </para>
+                    </callout>                   
+                    <callout arearefs="cache3">
+                        <para>
+                            <literal>include</literal> (옵션, 디폴트는 <literal>all</literal>) 
+                            <literal>non-lazy</literal>는 <literal>lazy="true"</literal>로 매핑된 엔티티의 
+                                                        프로퍼티들을 지정하며 속성-레벨 lazy 페칭이 이용 가능할 때 키시될 수 없다
+                        </para>
+                    </callout>                       
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                                다른 방법으로 (선호적으로?), 당신은 <literal>hibernate.cfg.xml</literal> 내에 <literal>&lt;class-cache&gt;</literal>와 
+                <literal>&lt;collection-cache&gt;</literal> 요소들을 지정할 수도 있다.
+            </para>
+            
+            <para>
+                <literal>usage</literal> 속성은 <emphasis> 캐시 동시성 방도</emphasis>를 지정한다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-cache-readonly">
+            <title>방도: 읽기 전용</title>
+
+            <para>
+                                당신의 어플리케이션이 영속 클래스의 인스턴스들을 읽어들일 필요가 있지만 결코 변경할 필요가 없을 경우에 <literal>read-only</literal> 
+                                캐시가 사용될 수 있다. 이것은 가장 간단한 최상의 퍼포먼스를 위한 방도이다. 그것은 클러스터 내 사용에는 완벽하게 안전하다.
+            </para>
+
+            <programlisting><![CDATA[<class name="eg.Immutable" mutable="false">
+    <cache usage="read-only"/>
+    ....
+</class>]]></programlisting>
+
+        </sect2>
+
+
+        <sect2 id="performance-cache-readwrite">
+            <title>방도: 읽기/쓰기</title>
+
+            <para>
+                                어플리케이션이 데이터를 업데이트 할 필요가 있을 경우, <literal>read-write</literal> 캐시가 적절하다. 만일 
+                                직렬화 가능한(serializable) 트랜잭션 격리 레벨이 필요한 경우에는 이 캐시 방도가 결코 사용되지 말아야 한다. 만일 캐시가 JTA 
+                                환경에서 사용될 경우, 당신은 JTA <literal>TransactionManager</literal>를 얻는 방도를 명명하는 
+                <literal>hibernate.transaction.manager_lookup_class</literal> 프로퍼티를 지정해야 한다. 다른 환경들에서, 
+                                당신은<literal>Session.close()</literal> 또는 <literal>Session.disconnect()</literal>가 호출될 때 
+                                트랜잭션이 완료되는 것을 확실히 해야 한다. 만일 당신이 클러스터 내에 이 방도를 사용하고자 원할 경우, 당신은 기본 캐시 구현이 
+                                잠금을 지원하도록 하는 것을 확실히 해야 한다. 미리 만들어진 캐시 프로바이더들은 그렇게 행하지 <emphasis>않는다</emphasis>.
+            </para>
+
+            <programlisting><![CDATA[<class name="eg.Cat" .... >
+    <cache usage="read-write"/>
+    ....
+    <set name="kittens" ... >
+        <cache usage="read-write"/>
+        ....
+    </set>
+</class>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-cache-nonstrict">
+            <title>방도: 엄격하지 않은 읽기/쓰기</title>
+
+            <para>
+                                만일 어플리케이션이 오직 데이터를 자주 업데이트할 필요가 있고(예를 들어, 만일 두 개의 트랜잭션들이 동시에 동일한 항목을 업데이트
+                                하려고 시도하는 정말 있음직하지 않은 경우) 그리고 엄격한 트랜잭션 격리가 필요하지 않은 경우, <literal>nonstrict-read-write</literal> 
+                                캐시가 적절할 수 있다. 만일 그 캐시가 JTA 환경에서 사용될 경우, 당신은 <literal>hibernate.transaction.manager_lookup_class</literal>를 
+                                지정해야 한다. 다른 환경들에서, 당신은 <literal>Session.close()</literal> 또는 <literal>Session.disconnect()</literal>가 호출될 때 
+                                트랜잭션이 완료되도록 확실히 해야 한다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-cache-transactional">
+            <title>방도: transactional</title>
+
+            <para>
+                <literal>transactional</literal> 캐시 방도는 JBoss TreeCache와 같은 전체 트랜잭션적인 캐시 프로바이더들에 대한 
+                                지원을 제공한다. 그런 캐시는 오직 JTA 환경 내에서 사용될 수 있고 당신은 
+                <literal>hibernate.transaction.manager_lookup_class</literal>를 지정해야 한다.
+            </para>
+
+        </sect2>
+        
+        <para>
+                        캐시 프로바이더들 중 어느 것도 모든 캐시 동시성 방도들을 지원하지 않는다. 다음 테이블은 어느 프로바이더들이 어느 동시성 방도들과 
+                        호환되는지를 보여준다.
+        </para>
+
+        <table frame="topbot">
+            <title>캐시 동시성 방도 지원</title>
+            <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="1*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>캐시</entry>
+              <entry>읽기 전용</entry>
+              <entry>엄격하지 않은 읽기-쓰기</entry>
+              <entry>읽기-쓰기</entry>
+              <entry>transactional</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>Hashtable (제품용으로 고안되지 않음)</entry>
+                <entry>예</entry>
+                <entry>예</entry>
+                <entry>예</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>EHCache</entry>
+                <entry>예</entry>
+                <entry>예</entry>
+                <entry>예</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>OSCache</entry>
+                <entry>예</entry>
+                <entry>예</entry>
+                <entry>예</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>SwarmCache</entry>
+                <entry>예</entry>
+                <entry>예</entry>
+                <entry></entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>JBoss TreeCache</entry>
+                <entry>예</entry>
+                <entry></entry>
+                <entry></entry>
+                <entry>예</entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+    </sect1>
+
+    <sect1 id="performance-sessioncache" revision="2">
+        <title>캐시들을 관리하기</title>
+
+        <para>
+                         당신이 객체를 <literal>save()</literal>, <literal>update()</literal> 또는 <literal>saveOrUpdate()</literal>에 
+                         전달할 때마다 그리고 당신이 <literal>load()</literal>, <literal>get()</literal>, <literal>list()</literal>, 
+            <literal>iterate()</literal> 또는 <literal>scroll()</literal>을 사용하여 객체를 검색할 때마다, 그 객체는 
+            <literal>Session</literal>의 내부 캐시에 추가된다. 
+        </para>
+        <para>
+            <literal>flush()</literal>가 차후적으로 호출될 때, 그 객체의 상태는 데이터베이스와 동기화 될 것이다. 만일 당신이 이 동기화가 
+                        발생되는 것을 원하지 않거나 만일 당신이 대량의 객체들을 처리 중이고 메모리를 효율적으로 관리할 필요가 있을 경우, <literal>evict()</literal> 
+                        메소드는 first-level 캐시로부터 그 객체와 그것의 콜렉션들을 제거하는데 사용될 수 있다.
+        </para>
+        
+        <programlisting><![CDATA[ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
+while ( cats.next() ) {
+    Cat cat = (Cat) cats.get(0);
+    doSomethingWithACat(cat);
+    sess.evict(cat);
+}]]></programlisting>
+        
+        <para>
+            <literal>Session</literal>은 또한 인스턴스가 세션 캐시에 속하는지 여부를 결정하는데 <literal>contains()</literal> 
+                        메소드를 제공한다.
+        </para>
+        
+        <para>
+                        세션 캐시로부터 모든 객체들을 완전하게 퇴거시키기 위해, <literal>Session.clear()</literal>를 호출하라.
+        </para>
+        
+        <para>
+            second-level 캐시의 경우, 하나의 인스턴스, 전체 클래스, 콜렉션 인스턴스 또는 전체 콜렉션 role의 캐시된 상태를 퇴거시키는 
+            <literal>SessionFactory</literal> 상에 정의된 메소드들이 존재한다.
+        </para>
+        
+        <programlisting><![CDATA[sessionFactory.evict(Cat.class, catId); //evict a particular Cat
+sessionFactory.evict(Cat.class);  //evict all Cats
+sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
+sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections]]></programlisting>
+
+        <para>
+            <literal>CacheMode</literal>는 특정 세션이 second-level 캐시와 어떻게 상호작용하는지를 제어한다
+        </para>
+        
+        <itemizedlist>
+        <listitem>
+        <para>
+            <literal>CacheMode.NORMAL</literal> - second-level 캐시로부터 아이템들을 읽어들이고 second-level 캐시로 
+                        아이템들을 기록한다
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.GET</literal> - second-level 캐시로부터 아이템들을 읽어들이지만, 데이터를 업데이트할 때를 제외하면 
+            second-level 캐시로 기록하지 않는다
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.PUT</literal> - 아이템들을 second-level 캐시에 기록하지만, second-level 캐시로부터 읽어들이지 
+                        않는다
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.REFRESH</literal> -  아이템들을 second-level 캐시로기록하지만, second-level 캐시로부터 
+                       읽어들이지 않고, 데이터베이스로부터 읽어들인 모든 아이템들에 대한 second-level 캐시의 갱신을 강제시켜, 
+            <literal>hibernate.cache.use_minimal_puts</literal>의 효과를 무시한다
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            second-level 캐시 또는 질의 캐시 영역의 내용물을 브라우징하려면 <literal>Statistics</literal> API를 사용하라:
+        </para>
+        
+        <programlisting><![CDATA[Map cacheEntries = sessionFactory.getStatistics()
+        .getSecondLevelCacheStatistics(regionName)
+        .getEntries();]]></programlisting>
+        
+        <para>
+                        당신은 통계를 이용 가능하게 하고, 선택적으로 Hibernate로 하여금 캐시 엔트리들을 보다 인간에게 이해가능한 형식으로 유지시키도록 
+                        강제시키는 것이 필요할 것이다:
+        </para>
+        
+        <programlisting><![CDATA[hibernate.generate_statistics true
+hibernate.cache.use_structured_entries true]]></programlisting>       
+                
+    </sect1>
+    
+    <sect1 id="performance-querycache" revision="1">
+        <title>질의 캐시</title>
+
+        <para>
+                        질의 결과 셋들이 또한 캐시될 수도 있다. 이것은 동일한 파라미터들을 가지고 자주 실행되는 질의들에만 유용하다. 
+                        질의 캐시를 사용하기 위해 당신은 먼저 그것을 이용 가능하도록 해야 한다:
+        </para>
+
+        <programlisting><![CDATA[hibernate.cache.use_query_cache true]]></programlisting>       
+        
+        <para>
+                        이 설정은 두 개의 새로운 캐시 영역들 - 캐시된 질의 결과 셋들을 보관하는 것
+            (<literal>org.hibernate.cache.StandardQueryCache</literal>), 질의 가능한 테이블들에 대한 가장 
+                        최신 업데이트들에 대한 timestamp들을 보관하는 다른 것
+            (<literal>org.hibernate.cache.UpdateTimestampsCache</literal>)-의 생성을 강제한다 . 질의 캐시는 
+                       결과 셋 내에 실제 엔티티들의 상태를 캐시시키지 않음을 노트하라; 그것은 오직 식별자 값들과 값 타입의 결과들 
+                       만을 캐시시킨다. 따라서 질의 캐시는 항상 second-level 캐시와 함께 사용되어야 한다.
+        </para>
+        
+        <para>
+                        대부분의 질의들은 캐싱으로부터 이점이 없기에, 디폴트로 질의들은 캐시되지 않는다. 캐싱을 이용 가능하도록 하려면, 
+            <literal>Query.setCacheable(true)</literal>를 호출하라. 이 호출은 기존 캐시 결과들을 찾는 것을 질의에게 
+                        허용해주거나 질의가 실행될 때 그것의 결과들을 캐시에 추가하는 것을 허용해준다.
+        </para>
+        
+        <para>
+                        만일 당신이 질의 캐시 만료 정책들에 대한 세밀한 제어를 필요로 할 경우, 당신은 
+            <literal>Query.setCacheRegion()</literal>을 호출함으로써 특별한 질의에 대해 명명되니 캐시 영역을 
+                        지정할 수도 있다.
+        </para>
+        
+        <programlisting><![CDATA[List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
+    .setEntity("blogger", blogger)
+    .setMaxResults(15)
+    .setCacheable(true)
+    .setCacheRegion("frontpages")
+    .list();]]></programlisting>
+
+        <para>
+                        만일 질의가 그것의 질의 캐시 영역의 갱신을 강제시켜야 하는 경우에, 당신은 <literal>Query.setCacheMode(CacheMode.REFRESH)</literal>를 
+                        호출해야 한다. 이것은 기본 데이터가 별도의 프로세스를 통해 업데이트되었고(예를 들면, Hibernate를 통해 변경되지 않았고) 
+                        특정 질의 결과 셋들을 선택적으로 갱신하는 것을 어플리케이션에게 허용해주는 경우들에서 특별히 유용하다. 이것은  
+            <literal>SessionFactory.evictQueries()</literal>를 통해 질의 캐시 영역을 퇴거시키는 보다 효과적인 대안이다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="performance-collections">
+        <title>콜렉션 퍼포먼스 이해하기</title>
+
+        <para>
+                        우리는이미  콜렉션들에 관해 얘기하는데 꽤 많은 시간을 소요했다. 이 절에서 우리는 콜렉션들이 실행 시에 어떻게 행위하는지에 관한 
+                        한 쌍의 쟁점들을 조명할 것이다.
+        </para>
+
+        <sect2 id="performance-collections-taxonomy">
+            <title>분류</title>
+
+            <para>Hibernate는 세 가지 기본적인 종류의 콜렉션들을 정의한다:</para>
+
+            <itemizedlist>
+            <listitem>
+                <para>값들을 가진 콜렉션들</para>
+            </listitem>
+            <listitem>
+                <para>one to many 연관들</para>
+            </listitem>
+            <listitem>
+                <para>many to many 연관들</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                                이 분류는 여러 가지 테이블과 foreign key 관계들을 구별짓지만 우리가 관계형 모형에 대해 알 필요가 있는 모든 것을 우리에게 
+                                말해주지 않는다. 관계형 구조와 퍼포먼스 특징들을 완전하게 이해하기 위해, 우리는 또한 콜렉션 행들을 업데이트하거나 삭제하기 
+                                위해 Hibernate에 의해 사용되는 프라이머리 키의 구조를 검토해야 한다. 이것은 다음 분류를 제안한다:
+            </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>인덱싱 된 콜렉션들 </para>
+            </listitem>
+            <listitem>
+                <para>set들</para>
+            </listitem>
+            <listitem>
+                <para>bag들</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                                모든 인덱싱된 콜렉션들(map들, list들, array들)은 <literal>&lt;key&gt;</literal>와 
+                <literal>&lt;index&gt;</literal> 컬럼들로 이루어진 프라이머리 키를 갖는다. 이 경우에 콜렉션 업데이트들은 대개 
+                                극히 효율적이다 - Hibernate가 그것을 업데이트나 삭제를 시도할 때 프라이머리 키는 효율적으로 인덱싱될 수 있고 특정 행은 
+                                효율적으로 위치지워질 수 있다.
+            </para>
+                        
+            <para>
+                Set들은 <literal>&lt;key&gt;</literal>와 요소 컬럼들로 구성된 프라이머리 키를 갖는다. 이것은 몇몇 유형의 콜렉션 요소, 
+                                특히 composite 요소들 또는 대형 텍스트 또는 바이너리 필드들에 대해 덜 효율적일 수 있다; 데이터베이스는 복잡한 프라이머리 
+                                키를 효율적으로 인덱싱하는 것이 불가능할 수도 있다. 반면에 one to many 또는 many to many 연관들의 경우, 특히 합성 
+                                식별자들의 경우에는 효율적일 수 있을 것 같다.(부수-노트: 만일 당신이 당신을 위한 <literal>&lt;set&gt;</literal>의 
+                                프라이머리 키를 실제로 생성시키기 위해 <literal>SchemaExport</literal>를 원한다면 당신은 모든 컬럼들을 
+                <literal>not-null="true"</literal>로 선언해야 한다.)
+            </para>
+
+            <para>
+                <literal>&lt;idbag&gt;</literal> 매핑들은 대용 키를 정의하여서, 그것들은 항상 업데이트에 매우 효율적이다. 사실, 
+                                그것들은 최상의 경우이다.
+            </para>
+            
+            <para>
+                Bag들은 가장 나쁜 경우이다. 왜냐하면 하나의 bag은 중복 요소 값들을 허용하고 인덱스 컬럼을 갖지 않기 때문에, 프라이머리 키가 
+                                정의될 수 없다. Hibernate는 중복 행들 사이를 구분 짓는 방법을 갖고 있지 않다. Hibernate는 그것이 변경될 때마다  
+                (한 개의 DELETE로) 콜렉션을 완전하게 제거하고 다시 생성시킴으로써 이 문제를 해결한다. 이것은 매우 비효율적이다.
+            </para>
+
+            <para>
+                one-to-many 연관의 경우,  "프라이머리 키"는 데이터베이스 테이블의 물리적인 프라이머리 키가 아닐 수도 있지만- 이 경우에서도 
+                                위의 분류는 여전히 유용하다. (그것은 여전히 Hibernate가 콜렉션의 개별 행들을 어떻게 "위치지우는"지를 반영한다.)
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-collections-mostefficientupdate">
+            <title>List, map, idbag, set들은 update에 가장 효율적인 콜렉션들이다</title>
+
+            <para>
+                                위의 논의에서, 인덱싱된 콜렉션들과 (대개) set들이 요소들을 추가하고, 제거하고 업데이트함에 있어 가장 효율적인 오퍼레이션을 
+                                허용해준다.
+            </para>
+
+            <para>
+                                아마 인덱싱 된 콜렉션들이 many to many 연관들을 위한 또는 값들을 가진 콜렉션들을 위한 set들에 대해 갖고 있는 하나 이상의 
+                                장점들이 존재한다. <literal>Set</literal>의 구조 때문에, Hibernate는 요소가 "변경"될 때 행을 <literal>UPDATE</literal> 
+                                하지 않는다. <literal>Set</literal>에 대한 변경들은 항상 (개별 행들에 대한) <literal>INSERT</literal>와 
+                <literal>DELETE</literal>를 통해 동작한다. 다시 이 검토는 one to many 연관들에 적용되지 않는다.
+            </para>
+
+            <para>
+                                배열들이 lazy 될 수 없음을 관찰 한 후에, 우리는 list들, map들, 그리고 idbag들이 단독이 아닌 set들을 가진 가장 퍼포먼스가 
+                                좋은(non-inverse) 콜렉션 타입들임을 결론 지을 것이다. Set들은 Hibernate 어플리케이션들에서 가장 공통된 종류의 콜렉션이 
+                                될 것이라 예상된다. 이것은 "set" 의미가 관계형 모형에서 가장 고유한 것이기 때문이다.
+            </para>
+
+            <para>
+                                하지만, 잘 설계된 Hibernate 도메인 모형들에서, 우리는 대개 대부분의 콜렉션들이 사실 <literal>inverse="true"</literal>를 
+                                가진 one-to-many 연관들임을 보게 된다. 이들 연관들의 경우, 업데이트는 연관의 many-to-one 엔드에 의해 처리되고, 따라서 
+                                콜렉션 업데이트 퍼포먼스에 대한 검토들은 단순히 적용되지 않는다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-collections-mostefficentinverse">
+            <title>Bag들과 list들은 가장 효율적인 inverse 콜렉션들이다</title>
+
+            <para>
+                                단지 당신이 영원히 bag들을 버리기 전에, bag들(과 또한 list들)이 set들보다 훨씬 더 성능이 좋은 특별한 경우들이 존재한다. 
+                <literal>inverse="true"</literal>를 가진 콜렉션들(예를 들어, 표준 양방향 one-to-many 관계 특질)의 경우, 우리는 
+                bag 요소들을 초기화(페치) 시킬 필요 없이 bag 또는 list에 요소들을 추가시킬 수 있다! 이것은 <literal>Collection.add()</literal> 
+                                또는 <literal>Collection.addAll()</literal>이 (<literal>Set</literal>과는 달리) 항상 bag 또는 
+               <literal>List</literal>에 대해 true를 반환해야하기 때문이다. 이것은 훨씬 다음 공통적인 코드를 더 빠르게 만들 수 있다.
+            </para>
+
+            <programlisting><![CDATA[Parent p = (Parent) sess.load(Parent.class, id);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c);  //no need to fetch the collection!
+sess.flush();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-collections-oneshotdelete">
+            <title>원 샷 delete</title>
+
+            <para>
+                                종종 콜렉션 요소들을 하나씩 삭제하는 것은 극히 비효율적일 수 있다! Hibernate는 완전하게 바보가 아니어서, 그것은 새로운 공백의 
+                                콜렉션의 경우(예를 들어 당신이 <literal>list.clear()</literal>를 호출했을 경우)에 그것을 행하지 않을 것임을 알고 있다. 
+                                이 경우에, Hibernate는 하나의 <literal>DELETE</literal> 명령을 내릴 것이고 우리는 모두 행했다!
+            </para>
+
+            <para>
+                                우리가 길이 20인 하나의 콜렉션에 한 개의 요소를 추가하고 그런 다음 두 개의 요소들을 제거한다고 가정하자. Hibernate는 
+                (콜렉션이 bag가 아닌 한) 한 개의 <literal>INSERT</literal> 문장과 두 개의 <literal>DELETE</literal> 문장을 명령 
+                                내릴 것이다. 이것은 확실히 마음에 든다.
+            </para>
+
+            <para>
+                                하지만, 우리가 두 개의 요소들을 남겨둔채 18 개의 요소들을 제거하고 나서 세 개의 새로운 요소들을 추가한다고 가정하자. 
+                                두 가지 가능한 처리 방법들이 존재한다.
+            </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>하나씩 열 여덟 개의 행들을 삭제한 다음에 세 개의 행들을 삽입시킨다</para>
+            </listitem>
+            <listitem>
+                <para>
+                (한 개의 SQL <literal>DELETE</literal>로)전체 콜렉션을 삭제하고 모든 다섯개의 현재 요소들을 (하나씩) insert 시킨다 
+                </para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                Hibernate는 두 번째 옵션이 아마 이 경우에 더 빠르다는 점을 알 만큼 충분히 영리하지 않다.(그리고 Hibernate가 그렇게 영리해지는 것을 희망
+                                하는 것은 가능하지 않을 것이다; 그런 특징은 데이터베이스 트리거들 등을 혼동스럽게 할 수도 있다.)
+            </para>
+
+            <para>
+                                다행히, 당신은 원래의 콜렉션을 폐기시키고(예를 들어 참조 해제하고) 모든 현재 요소들을 가진 새로이 초기화된 콜렉션을 
+                                반환함으로써 아무때든지 이 특징을 강제시킬 수 있다. 이것은 시간이 흐름에 따라 매우 유용하고 강력해질 수 있다. 
+            </para>
+            
+            <para>
+                                물론 단 한번의 삭제(one-shot-delete)는 <literal>inverse="true"</literal>로 매핑된 콜렉션들에 적용되지 않는다.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="performance-monitoring" revision="1">
+        <title>퍼포먼스 모니터링하기</title>
+
+        <para>
+                        최적화는 퍼포먼스 관련 숫자들에 대한 모니터링과 접근 없이는 많이 사용되지 않는다. Hibernate는 그것의 내부적인 오퍼레이션들에 대한 
+                        전체 영역의 특징들을 제공한다. Hibernate에서 Statistics는 <literal>SessionFactory</literal>에 대해 이용 가능하다.
+        </para>
+
+        <sect2 id="performance-monitoring-sf" revision="2">
+            <title>SessionFactory 모니터링 하기</title>
+
+            <para>
+                                당신은 두 가지 방법들로 <literal>SessionFactory</literal> metrics에 접근할 수 있다. 당신의 첫 번째 옵션은 
+                <literal>sessionFactory.getStatistics()</literal>를 호출하고 당신 스스로 <literal>Statistics</literal>를 
+                                읽거나 디스플레이 하는 것이다.
+            </para>
+
+            <para>
+                                만일 당신이 <literal>StatisticsService</literal> MBean을 이용 가능하도록 할 경우 Hibernate는 또한 metrics를 
+                                발표하는데 JMX를 사용할 수 있다. 당신은 모든 당신의<literal>SessionFactory</literal>에 대해 한 개의 MBean 또는
+                                 팩토리 당 한 개를 이용 가능하게 할 수 있다.  최소한의 구성 예제들은 다음 코드를 보라:
+            </para>
+
+            <programlisting><![CDATA[// MBean service registration for a specific SessionFactory
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "myFinancialApp");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
+server.registerMBean(stats, on); // Register the Mbean on the server]]></programlisting>
+
+
+<programlisting><![CDATA[// MBean service registration for all SessionFactory's
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "all");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+server.registerMBean(stats, on); // Register the MBean on the server]]></programlisting>
+
+            <para>
+                TODO: 이것은 의미가 없다: 첫번째 경우에, 우리는 직접 MBean을 검색하고 사용한다. 
+                                두 번째 경우에 우리는 JNDI 이름을 사용하기 전에 세션 팩토리가 보관하고 있는 JNDI 이름을 부여해야 한다.
+                <literal>hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")</literal>을 사용하라.
+            </para>
+            <para>
+                                당신은 <literal>SessionFactory</literal>에 대한 모니터링을 (비)활성화 시킬 수 있다
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                                                구성 시 : <literal>hibernate.generate_statistics</literal>, 디폴트는 <literal>false</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                                                실행 시 : <literal>sf.getStatistics().setStatisticsEnabled(true)</literal> 또는 
+                                                <literal>hibernateStatsBean.setStatisticsEnabled(true)</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Statistics(통계량들)은 <literal>clear()</literal> 메소드를 사용하여 프로그래밍 방식으로 재설정 될  수 있다. 요약은 
+                <literal>logSummary()</literal> 메소드를 사용하여 logger(info 레벨)에게 전송될 수 있다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-monitoring-metrics" revision="1">
+            <title>Metrics</title>
+
+            <para>
+                Hibernate는 매우 기본적인 것에서부터 어떤 시나리오들에만 관련된 전문 정보에 이르는 많은 metrics를 제공한다. 
+                                모든 이용 가능한 카운터들은 <literal>Statistics</literal> interface API에서 3개의 카테고리로 설명되어 있다:
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                                                열려진 세션들의 개수, 검색된 JDBC 커넥션들의 개수 등과 같은 일반적인 <literal>Session</literal> 사용에 
+                                                관련된 metrics. 
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                                                전체적으로 엔티티들, 콜렉션들, 질의들, 그리고 캐시들에 관련된 metrics(전역 metrics로 알려져 있음),
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                                                특정한 엔티티, 콜렉션, 질의 또는 캐시 영역에 관련된 상세 metrics.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                                예를 들어 당신은 엔티티, 콜렉션, 질의들의 캐시 성공율 및 실패율, put(역자 주, 캐시 시도, putt) 비율, 콜렉션들과 질의들, 
+                                그리고 평균 질의 요구 시간 등을 찾을 수 있다. 수 밀리초들가 자바에서 근사치에 종속됨을 의식하라. Hibernate는 JVM 정밀도에 
+                                묶여 있고, 몇몇 플랫폼들에서 이것은 심지어 약 10초가 될 수도 있다.
+            </para>
+
+            <para>
+                                간단한 getter들은 (예를 들어 특정 엔티티, 콜렉션, 캐시 영역에 묶이지 않은) 전역 metrics에 접근하는데 사용된다. 당신은 
+                                그것(특정 엔티티, 콜렉션, 또는 캐시 영역)의 이름을 통해, 그리고 질의들에 대한 그것의 HQL 또는 SQL 표현을 통해 특정 엔티티, 
+                                콜렉션, 또는 캐시 영역의 metrics에 접근할수 있다. 추가 정보는 <literal>Statistics</literal>, <literal>EntityStatistics</literal>, 
+                <literal>CollectionStatistics</literal>, <literal>SecondLevelCacheStatistics</literal>, 그리고 
+                <literal>QueryStatistics</literal>를 참조하라. 다음 코드는 간단한 예제를 보여준다:
+            </para>
+
+            <programlisting><![CDATA[Statistics stats = HibernateUtil.sessionFactory.getStatistics();
+
+double queryCacheHitCount  = stats.getQueryCacheHitCount();
+double queryCacheMissCount = stats.getQueryCacheMissCount();
+double queryCacheHitRatio =
+  queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
+
+log.info("Query Hit ratio:" + queryCacheHitRatio);
+
+EntityStatistics entityStats =
+  stats.getEntityStatistics( Cat.class.getName() );
+long changes =
+        entityStats.getInsertCount()
+        + entityStats.getUpdateCount()
+        + entityStats.getDeleteCount();
+log.info(Cat.class.getName() + " changed " + changes + "times"  );]]></programlisting>
+
+            <para>
+                                모든 엔티티들, 콜렉션들, 콜렉션들,질의들 그리고 영역 캐시들에 대해 작업하기 위해, 당신은 다음 메소드들로서 엔티티들, 
+                                콜렉션들, 질의들, 그리고 영역 캐시들에 대한 이름들의 목록을 검색할 수 있다: <literal>getQueries()</literal>, 
+                <literal>getEntityNames()</literal>, <literal>getCollectionRoleNames()</literal>, 그리고 
+                <literal>getSecondLevelCacheRegionNames()</literal>.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/persistent_classes.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/persistent_classes.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/persistent_classes.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,502 @@
+<chapter id="persistent-classes" revision="2">
+    <title>영속 클래스들</title>
+
+    <para>
+                영속 클래스들은 비지니스 문제의 엔티티들(예를 들어 E-Commerce 어플리케이션에서 고객이나 주문)을 구현하는 
+                어플리케이션 내의 클래스들이다. 영속 클래스들의 인스턴스들은 영속 상태에 있는 것으로 전혀 간주되지 않는다 - 
+                대신에 하나의 인스턴스는 transient 또는 detached 상태일 수 있다.
+    </para>
+
+    <para>
+        Hibernate는 이들 클래스들이 Plain Old Java Object (POJO) 프로그래밍 모형으로서 알려진, 몇몇 간단한 
+                규칙들을 따를 경우에 가장 잘 동작한다. 하지만 이들 규칙들 중 어떤 것도 어려운 사양들이 아니다. 진정 Hibernate3는 
+                당신의 영속 객체들의 특징에 대해 매우 적은 것을 가정한다. 당신은 다른 방법들로 도메인 모형을 표현할 수 있다 : 
+                예를 들어 <literal>Map</literal> 인스턴스의 트리들을 사용하기.
+    </para>
+
+    <sect1 id="persistent-classes-pojo">
+        <title>간단한 POJO 예제</title>
+
+        <para>
+                        대부분의 자바 어플리케이션들은 고양이과들을 표현하는 영속 클래스를 필요로 한다.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+public class Cat {
+    private Long id; // identifier
+
+    private Date birthdate;
+    private Color color;
+    private char sex;
+    private float weight;
+    private int litterId;
+
+    private Cat mother;
+    private Set kittens = new HashSet();
+
+    private void setId(Long id) {
+        this.id=id;
+    }
+    public Long getId() {
+        return id;
+    }
+
+    void setBirthdate(Date date) {
+        birthdate = date;
+    }
+    public Date getBirthdate() {
+        return birthdate;
+    }
+
+    void setWeight(float weight) {
+        this.weight = weight;
+    }
+    public float getWeight() {
+        return weight;
+    }
+
+    public Color getColor() {
+        return color;
+    }
+    void setColor(Color color) {
+        this.color = color;
+    }
+
+    void setSex(char sex) {
+        this.sex=sex;
+    }
+    public char getSex() {
+        return sex;
+    }
+
+    void setLitterId(int id) {
+        this.litterId = id;
+    }
+    public int getLitterId() {
+        return litterId;
+    }
+
+    void setMother(Cat mother) {
+        this.mother = mother;
+    }
+    public Cat getMother() {
+        return mother;
+    }
+    void setKittens(Set kittens) {
+        this.kittens = kittens;
+    }
+    public Set getKittens() {
+        return kittens;
+    }
+    
+    // addKitten not needed by Hibernate
+    public void addKitten(Cat kitten) {
+    	kitten.setMother(this);
+	kitten.setLitterId( kittens.size() ); 
+        kittens.add(kitten);
+    }
+}]]></programlisting>
+
+        <para>
+                        준수할 네 개의 주요 규칙들이 다음에 있다:
+        </para>
+
+
+        <sect2 id="persistent-classes-pojo-constructor" revision="1">
+            <title>아규먼트 없는 생성자를 구현하라 </title>
+
+            <para>
+                <literal>Cat</literal>은 아규먼트 없는 생성자를 갖는다. 모든 영속 클래스들은 Hibernate는 
+                <literal>Constructor.newInstance()</literal>를 사용하여 그것들을 초기화 시킬 수 있도록 디폴트 생성자
+                (public이 아닐 수 있다)를 가져야 한다. 우리는 Hibernate 내에서 런타임 프락시 생성을 위한 최소한의 
+                <emphasis>패키지</emphasis> 가시성(visibility)를 가진 디폴트 생성자를 가질 것을 강력하게 권장한다.
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-identifier" revision="2">
+            <title>identifier 프로퍼티를 제공하라(옵션)</title>
+
+            <para>
+                <literal>Cat</literal>은 <literal>id</literal>로 명명된 하나의 프로퍼티를 갖는다. 이 프로퍼티는 
+                                데이터베이스 테이블의 프라이머리 키 컬럼으로 매핑된다. 이 프로퍼티는  어떤 것으로 명명될 수도 있고, 그것의 타입은 
+                                임의의 원시 타입, 원시 "wrapper" 타입, <literal>java.lang.String</literal> 또는 <literal>java.util.Date</literal>일 
+                                수 있다. (만일 당신의 리거시 데이터베이스 테이블이 composite 키들을 갖고 있다면, 당신은 이들 타입들을 가진 
+                                사용자 정의 클래스를 사용할 수도 있다 - 나중에 composite 식별자들에 대한 절을 보라)
+            </para>
+
+            <para>
+                identifier 프로퍼티는 엄격하게 옵션이다. 당신은 그것을 생략할 수도 있고, Hibernate로 하여금 내부적으로 
+                                객체 식별자들을 추적하도록 할 수 있다. 하지만 우리는 이것을 권장하지 않는다.
+            </para>
+
+            <para>
+                                사실, 어떤 기능은 identifier 프로퍼티를 선언하는 클래스들에 대해서만 이용 가능하다:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        detached 객체들에 대한 Transitive reattachment(cascade update 또는 cascade merge) 
+                        - <xref linkend="objectstate-transitive"/>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session.saveOrUpdate()</literal>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session.merge()</literal>
+                    </para>
+                    <para>
+                                                를 보라 
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                                우리는 당신이 영속 클래스들에 대해 일관되게 명명된 identifier 프로퍼티들을 선언할 것을 권장한다. 게다가 우리는 
+                                당신이 nullable 타입(예를 들어 non-primitive)을 사용할 것을 권장한다.
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-final">
+            <title>final이 아닌 클래스들을 선호하라(옵션)</title>
+            <para>
+                Hibernate의 중심 특징인, 프락시(<emphasis>proxies</emphasis>)들은 final이 아닌 영속 클래스들 또는 모두 
+                public 메소드들로 선언된 인터페이스의 구현인 영속 클래스들에 의존한다.
+            </para>
+            <para>
+                                당신은 Hibernate로 인터페이스를 구현하지 않은 <literal>final</literal> 클래스들을 영속화 시킬 수 있지만 
+                                당신은 lazy 연관 페칭(lazy association fetching)에 대해 프락시들을 사용할 수 없을 것이다 -그것은 퍼포먼스 
+                                튜닝을 위한 당신의 옵션들을 제한시킬 것이다. 
+            </para>
+            <para>
+                                당신은 또한 non-final 클래스들 상에 <literal>public final</literal> 메소드들을 선언하는 것을 피해야 한다. 
+                                만일 당신이 <literal>public final</literal> 메소드를 가진 클래스를 사용하고자 원할 경우, 당신은 
+                <literal>lazy="false"</literal>를 설정함으로써 명시적으로 프락싱을 사용 불가능하도록 해야 한다.
+            </para>
+        </sect2>
+        
+        <sect2 id="persistent-classes-pojo-accessors" revision="2">
+            <title>영속 필드들을 위한 accessor들과 mutator들을 선언하라(옵션)</title>
+
+            <para>
+                <literal>Cat</literal>은 그것의 모든 영속 필드들에 대해 accessor 메소드들을 선언한다. 많은 다른 ORM 도구들은 
+                                인스턴스 변수들을 직접 영속화 시킨다. 우리는 관계형 스키마와 클래스의 내부적인 데이터 구조들 사이에 간접적인 수단을 
+                                제공하는 것이 더 좋다고 믿고 있다. 디폴트로 Hibernate는 자바빈즈 스타일 프로퍼티들을 영속화 시키고, <literal>getFoo</literal>,
+                <literal>isFoo</literal>와 <literal>setFoo</literal> 형식의 메소드 이름들을 인지한다. 당신은 진정으로 
+                                특정 프로퍼티에 대한 직접적인 필드 접근으로 전환할 수도 있다.
+            </para>
+
+            <para>
+                                프로퍼티들은 public으로 선언될 필요가 <emphasis>없다</emphasis> - Hibernate는 디폴트로 
+                <literal>protected</literal> get/set 쌍 또는 <literal>private</literal> get/set 
+                                쌍을 가진 프로퍼티를 영속화 시킬 수 있다. 
+            </para>
+
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="persistent-classes-inheritance">
+        <title>상속 구현하기</title>
+
+        <para>
+                        서브클래스는 또한 첫 번째 규칙들과 두 번째 규칙들을 주시해야 한다. 그것은 슈퍼클래스 <literal>Cat</literal>으로부터 
+                        그것의 identifier 프로퍼티를 상속받는다.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+public class DomesticCat extends Cat {
+        private String name;
+
+        public String getName() {
+                return name;
+        }
+        protected void setName(String name) {
+                this.name=name;
+        }
+}]]></programlisting>
+    </sect1>
+
+    <sect1 id="persistent-classes-equalshashcode" revision="1">
+        <title><literal>equals()</literal>와 <literal>hashCode()</literal> 구현하기</title>
+
+        <para>
+                        만일 당신이 다음의 경우라면, 당신은 <literal>equals()</literal>와 <literal>hashCode()</literal> 
+                        메소드들을 오버라이드 시켜야 한다. 
+        </para>
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                                        하나의 <literal>Set</literal> 속에 영속 클래스들의 인스턴스들을 집어넣고자 의도하고
+                    (many-valued 연관들에 대해 권장되는 방법)  
+                    <emphasis>그리고</emphasis> 
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    detached 인스턴스들의 reattachment(재첨부)를 사용하고자 의도하는 
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Hibernate는 특정 session 범위 내에서만 persistent identity(데이터베이스 행)과 Java identity의 같음을 보장한다. 
+                        따라서 우리가 다른 세션들에서 검색된 인스턴스들을 혼합시키자마자, 우리가 <literal>Set</literal>들에 대해 유의미하게 
+                        만들고자 원할 경우, 우리는 <literal>equals()</literal>와 <literal>hashCode()</literal>를 구현해야 한다.
+        </para>
+
+        <para>
+                        가장 명백한 방법은 두 객체들의 identifier 값을 비교함으로써  <literal>equals()</literal>/<literal>hashCode()</literal>를 
+                        구현하는 것이다. 만일 그 값이 동일하다면, 둘다 동일한 데이터베이스 행이어야 하고, 그러므로 그것들은 같다(둘다 하나의 
+            <literal>Set</literal>에 추가되는 경우에, 우리는 <literal>Set</literal> 속에서 하나의 요소만을 갖게 될 것이다). 
+                        불행하게도, 우리는 생성되는 식별자들을 갖는 그 접근법을 사용할 수 없다! Hibernate는 오직 식별자 값들을 영속화 되는 객체들에 
+                        할당할 것이고, 새로이 생성된 인스턴스는 임의의 identifier 값을 갖지 않을 것이다! 만일 인스턴스가 저장되지 않고 현재 하나의 
+            <literal>Set</literal> 속에 있을 경우에, 그것을 저장하는것은 하나의 식별자 값을 그 객체에게 할당할 것이다. 만일 
+            <literal>equals()</literal>와  <literal>hashCode()</literal>가 그 식별자 값에 기초할 경우, hash 코드는 
+            <literal>Set</literal>의 계약을 파기하여 변경될 것이다. 이 문제에 대한 전체 논의에 대해서는 Hibernate 웹 사이트를 보라. 
+                        이것은 Hibernate 쟁점이 아닌, 객체 identity와 equality에 관한 통상의 자바 의미론임을 노트하라.
+        </para>
+
+        <para>
+                        우리는 <emphasis>Business key equality</emphasis>를 사용하여 <literal>equals()</literal>와  <literal>hashCode()</literal>를 
+                        구현할 것 권장한다. Business key equality는 <literal>equals()</literal> 메소드가 비지니스 키, 즉 실세계에서 우리의 인스턴스를 
+                        식별하게 될 키(<emphasis>natural</emphasis> 후보 키)를 형성하는 프로퍼티들만을 비교한다는 점을 의미한다 :
+        </para>
+
+        <programlisting><![CDATA[public class Cat {
+
+    ...
+    public boolean equals(Object other) {
+        if (this == other) return true;
+        if ( !(other instanceof Cat) ) return false;
+
+        final Cat cat = (Cat) other;
+
+        if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
+        if ( !cat.getMother().equals( getMother() ) ) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result;
+        result = getMother().hashCode();
+        result = 29 * result + getLitterId();
+        return result;
+    }
+
+}]]></programlisting>
+
+        <para>
+                        하나의 비지니스 키는 데이터베이스 프라이머리 키 후보 만큼 견고하지 않아야 한다(<xref linkend="transactions-basics-identity"/>를 보라). 
+                        대개 변경할 수 없는 프로퍼티 또는 유일한(unique) 프로퍼티는 대개 비지니스 키에 대한 좋은 후보들이다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-dynamicmodels">
+        <title>동적인 모형들</title>
+
+        <para>
+            <emphasis>다음 특징들은 현재 실험적으로 고려되고 있으며 장래에는 변경될 수 있음을 노트하라.</emphasis>
+        </para>
+
+        <para>
+                        영속 엔티티들은 반드시 실행시에 POJO 클래스들로 또는 자바빈즈 객체들로 표현되어야할 필요는 없다. Hibernate는 
+                        또한 (실행 시에 <literal>Map</literal>들을 가진 <literal>Map</literal>들을 사용하여) 동적인 모형들을 지원하고 
+            DOM4J 트리들로서 엔티티들에 대한 표현을 지원한다. 이 접근법으로, 당신은 영속 클래스들을 작성하지 않고, 오직 매핑 파일들 
+                        만을 작성한다.
+        </para>
+
+        <para>
+                        디폴트로, Hibernate는 통산의 POJO 모드로 동작한다. 당신은 <literal>default_entity_mode</literal> 구성 옵션을 
+                        사용하여 특별한 <literal>SessionFactory</literal>에 대해 디폴트 엔티티 표현 모드를 설정할 수 있다
+            (<xref linkend="configuration-optional-properties"/>을 보라).
+        </para>
+
+        <para>
+                        다음 예제들은<literal>Map</literal>들을 사용하는 표현을 설명한다. 먼저 매핑 파일에서, <literal>entity-name</literal>은 
+                        클래스 이름 대신에(또는 클래스 이름에 덧붙여) 선언되어야 한다:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class entity-name="Customer">
+
+        <id name="id"
+            type="long"
+            column="ID">
+            <generator class="sequence"/>
+        </id>
+
+        <property name="name"
+            column="NAME"
+            type="string"/>
+
+        <property name="address"
+            column="ADDRESS"
+            type="string"/>
+
+        <many-to-one name="organization"
+            column="ORGANIZATION_ID"
+            class="Organization"/>
+
+        <bag name="orders"
+            inverse="true"
+            lazy="false"
+            cascade="all">
+            <key column="CUSTOMER_ID"/>
+            <one-to-many class="Order"/>
+        </bag>
+
+    </class>
+    
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+                        심지어 비록 연관들이 대상(target) 클래스 이름들을 사용하여 선언될지라도, 연관들의 대상(target) 타입은 또한 POJO가 아닌 
+                        동적인 엔티티일 수 있음을 노트하라.
+        </para>
+
+        <para>
+            <literal>SessionFactory</literal>에 대한 디폴트 엔티티 모드를 <literal>dynamic-map</literal>으로 설정한 후에, 
+                        우리는 <literal>Map</literal>들을 가진 <literal>Map</literal>들에 대해 실행 시에 작업할 수 있다:
+        </para>
+
+        <programlisting><![CDATA[Session s = openSession();
+Transaction tx = s.beginTransaction();
+Session s = openSession();
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+
+// Create an organization
+Map foobar = new HashMap();
+foobar.put("name", "Foobar Inc.");
+
+// Link both
+david.put("organization", foobar);
+
+// Save both
+s.save("Customer", david);
+s.save("Organization", foobar);
+
+tx.commit();
+s.close();]]></programlisting>
+
+        <para>
+            dynamic 매핑의 장점들은 엔티티 클래스 구현에 대한 필요 없이도 프로토타이핑을 위한 빠른 전환 시간이다. 하지만 당신은 
+                        컴파일 시 타입 체킹을 잃고 실행 시에 많은 예외상황들을 다루게 될 것이다. Hibernate 매핑 덕분에,  
+                        나중에 고유한 도메인 모형 구현을 상단에 추가하는 것이 허용되어서, 데이터베이스 스키마가 쉽게 정규화 되고 소리가 울려 퍼질 수 있다.
+        </para>
+
+        <para>
+                        엔티티 표현 모드들은 또한 하나의 단위 <literal>Session</literal> 기준에 대해 설정될 수 있다:
+        </para>
+
+        <programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+dynamicSession.save("Customer", david);
+...
+dynamicSession.flush();
+dynamicSession.close()
+...
+// Continue on pojoSession
+]]></programlisting>
+
+
+        <para>
+            <literal>EntityMode</literal>를 사용하는 <literal>getSession()</literal>에 대한 호출은 
+            <literal>SessionFactory</literal>가 아닌, <literal>Session</literal> API에 대한 것임을 노트하길 바란다. 
+                        그 방법으로, 새로운 <literal>Session</literal>은 기본 JDBC 커넥션, 트랜잭션, 그리고 다른 컨텍스트 정보를 공유한다. 
+                        이것은 당신이 두 번째 <literal>Session</literal> 상에서 <literal>flush()</literal>와 <literal>close()</literal>를 
+                        호출하지 말아야 하고, 또한 트랜잭션 및 커넥션 핸들링을 주된 작업 단위에게 맡긴다는 점을 의미한다.
+        </para>
+
+        <para>
+            XML 표현 가용성들에 대한 추가 정보는 <xref linkend="xml"/>에서 찾을 수 있다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-tuplizers" revision="1">
+        <title>Tuplizer들</title>
+
+        <para>
+            <literal>org.hibernate.tuple.Tuplizer</literal>, 그리고 그것의 서브-인터페이스들은 데이터의 조각에 대한 
+                        특별한 표현의 <literal>org.hibernate.EntityMode</literal>가 주어지면 그 표현을 관리하는 책임이 있다. 만일 
+                        주어진 데이터 조각이 하나의 데이터 구조로 간주될 경우, 그때 하나의 tuplizer는 그런 데이터 구조를 생성시키는 방법과 
+                        그런 데이터 구조로부터 값들을 추출시키는 방법 그리고 그런 데이터구조 속으로 값들을 삽입시키는 방법을 알고 있는 것이다. 
+                        예를 들어, POJO 엔티티 모드의 경우, 대응하는 tuplizer는 그것의 생성자를 통해 POJO를 생성시키는 방법, 그리고 정의된
+                        프로퍼티 접근자들을 사용하여 POJO 프로퍼티들에 접근하는 방법을 안다. 
+            <literal>org.hibernate.tuple.entity.EntityTuplizer</literal> 인터페이스와 
+            <literal>org.hibernate.tuple.component.ComponentTuplizer</literal> 인터페이스에 의해 표현되는 두 가지 고급 유형의 
+            Tuplizer들이 존재한다. <literal>EntityTuplizer</literal>들은 엔티티들에 관해서는 위에 언급된 계약들을 매핑할 
+                        책임이 있는 반면에, <literal>ComponentTuplizer</literal>들은 컴포넌트들에 대해서도 동일한 것을 행한다.
+        </para>
+
+        <para>
+                        사용자들은 또한 그들 자신의 tuplizer들을 플러그 시킬 수 있다. 아마 당신은 dynamic-map entity-mode 동안에 사용되는 
+            <literal>java.util.HashMap</literal> 대신에 하나의 <literal>java.util.Map</literal> 구현을 필요로 한다;
+                        또는 아마 당신은 디폴트로 사용되는 방도 보다는 하나의 다른 다른 프릭시 산출 방도를 필요로 한다. 둘다 하나의 맞춤형 tuplizer를 
+                        정의함으로써 성취될 것이다. Tuplizer들 정의들은 그것들이 관리할 수단인 엔티티 매핑 또는 컴포넌트 매핑에 첨부된다. 우리의 
+                        고객 엔티티에 대한 예제로 되돌아가면:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+    <class entity-name="Customer">
+        <!--
+            Override the dynamic-map entity-mode
+            tuplizer for the customer entity
+        -->
+        <tuplizer entity-mode="dynamic-map"
+                class="CustomMapTuplizerImpl"/>
+
+        <id name="id" type="long" column="ID">
+            <generator class="sequence"/>
+        </id>
+
+        <!-- other properties -->
+        ...
+    </class>
+</hibernate-mapping>
+
+
+public class CustomMapTuplizerImpl
+        extends org.hibernate.tuple.entity.DynamicMapEntityTuplizer {
+    // override the buildInstantiator() method to plug in our custom map...
+    protected final Instantiator buildInstantiator(
+            org.hibernate.mapping.PersistentClass mappingInfo) {
+        return new CustomMapInstantiator( mappingInfo );
+    }
+
+    private static final class CustomMapInstantiator
+            extends org.hibernate.tuple.DynamicMapInstantitor {
+        // override the generateMap() method to return our custom map...
+        protected final Map generateMap() {
+            return new CustomMap();
+        }
+    }
+}]]></programlisting>
+
+
+    </sect1>
+
+    <para>
+        TODO: property 패키지와 proxy 패키지 내에 user-extension 프레임웍을 문서화 할 것.
+    </para>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/query_criteria.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/query_criteria.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/query_criteria.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,418 @@
+<chapter id="querycriteria">
+    <title>Criteria 질의들</title>
+
+    <para>
+        Hibernate는 직관적인, 확장 가능한 criteria query API를 특징 짓는다.
+    </para>
+    
+    <sect1 id="querycriteria-creating">
+        <title><literal>Criteria</literal> 인스턴스 생성하기</title>
+
+        <para>
+            <literal>org.hibernate.Criteria</literal>인터페이스는 특정 영속 클래스에 대한 질의를 표현한다. 
+            <literal>Session</literal>은 <literal>Criteria</literal> 인스턴스들에 대한 팩토리이다.
+        </para>
+
+        <programlisting><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
+crit.setMaxResults(50);
+List cats = crit.list();]]></programlisting>
+
+    </sect1>
+     
+    <sect1 id="querycriteria-narrowing">
+        <title>결과 셋 제한하기</title>
+
+        <para>
+                        개별적인 질의 기준은  <literal>org.hibernate.criterion.Criterion</literal> 인터페이스의 인스턴스이다. 
+            <literal>org.hibernate.criterion.Restrictions</literal> 클래스는 어떤 미리 만들어진 <literal>Criterion</literal> 
+                        타입들을 얻는 팩토리 메소드들을 정의한다.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .add( Restrictions.between("weight", minWeight, maxWeight) )
+    .list();]]></programlisting>
+    
+        <para>
+                        제한들은 논리적으로 그룹지워질 수도 있다.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .add( Restrictions.or(
+        Restrictions.eq( "age", new Integer(0) ),
+        Restrictions.isNull("age")
+    ) )
+    .list();]]></programlisting>
+    
+       <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
+    .add( Restrictions.disjunction()
+        .add( Restrictions.isNull("age") )
+        .add( Restrictions.eq("age", new Integer(0) ) )
+        .add( Restrictions.eq("age", new Integer(1) ) )
+        .add( Restrictions.eq("age", new Integer(2) ) )
+    ) )
+    .list();]]></programlisting>
+    
+        <para>
+                        미리 만들어진 criterion 타입들(<literal>Restrictions</literal> 서브클래스들)의 영역이 꽤 존재하지만, 특히 유용한 것은 
+                        당신으로 하여금 SQL을 직접 지정하도록 해준다.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.sqlRestriction("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
+    .list();]]></programlisting>
+    
+        <para>
+                        질의된 엔티티의 행 alias에 의해 대체된 <literal>{alias}</literal> placeholder.
+        </para>
+        
+        <para>
+            criterion을 얻는 대안적인 접근법은 <literal>Property</literal> 인스턴스로부터 그것을 얻는 것이다. 당신은 
+            <literal>Property.forName()</literal>을 호출하여 <literal>Property</literal>를 생성시킬 수 있다.
+        </para>
+    
+        <programlisting><![CDATA[
+Property age = Property.forName("age");
+List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.disjunction()
+        .add( age.isNull() )
+        .add( age.eq( new Integer(0) ) )
+        .add( age.eq( new Integer(1) ) )
+        .add( age.eq( new Integer(2) ) )
+    ) )
+    .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
+    .list();]]></programlisting>
+    
+   </sect1>
+     
+    <sect1 id="querycriteria-ordering">
+        <title>결과들을 순서지우기(ordering)</title>
+
+        <para>
+                        당신은 <literal>org.hibernate.criterion.Order</literal>를 사용하여 결과들을 순서(ordering)지울 수 있다.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "F%")
+    .addOrder( Order.asc("name") )
+    .addOrder( Order.desc("age") )
+    .setMaxResults(50)
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Property.forName("name").like("F%") )
+    .addOrder( Property.forName("name").asc() )
+    .addOrder( Property.forName("age").desc() )
+    .setMaxResults(50)
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-associations" revision="2">
+        <title>연관들</title>
+
+        <para>
+                        당신은 <literal>createCriteria()</literal>를 사용하여 연관들을 네비게이트함으로써 관계된 엔티티들에 대한 컨스트레인트들을 
+                        쉽게 지정할 수 있다.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "F%") )
+    .createCriteria("kittens")
+        .add( Restrictions.like("name", "F%") )
+    .list();]]></programlisting>
+
+        <para>
+                        두 번째 <literal>createCriteria()</literal>는 <literal>Criteria</literal>의 새로운 인스턴스를 반환하며, 그것은 
+            <literal>kittens</literal> 콜렉션의 요소들을 참조한다는 점을 노트하라.
+        </para>
+
+        <para>
+                        다음 대체 형식은 어떤 환경들에서 유용하다.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .createAlias("kittens", "kt")
+    .createAlias("mate", "mt")
+    .add( Restrictions.eqProperty("kt.name", "mt.name") )
+    .list();]]></programlisting>
+
+        <para>
+            (<literal>createAlias()</literal>는 <literal>Criteria</literal>의 새로운 인스턴스를 생성시키지 않는다.)
+        </para>
+
+        <para>
+                        앞의 두 개의 질의들에 의해 반환된 <literal>Cat</literal> 인스턴스들에 의해 보관된  kittens 콜렉션들은 criteria에 의해 
+                        사전-필터링되지 <emphasis>않는다</emphasis>는 점을 노트하라! 만일 당신이 criteria(기준)과 일치하는 고양이 새끼들을 
+                        단지 검색하고자 원할 경우, 당신은 하나의 <literal>ResultTransformer</literal>를 사용해야 한다.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .createCriteria("kittens", "kt")
+        .add( Restrictions.eq("name", "F%") )
+    .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+    .list();
+Iterator iter = cats.iterator();
+while ( iter.hasNext() ) {
+    Map map = (Map) iter.next();
+    Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
+    Cat kitten = (Cat) map.get("kt");
+}]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="querycriteria-dynamicfetching" revision="1">
+        <title>동적인 연관 페칭</title>
+
+        <para>
+                        당신은 <literal>setFetchMode()</literal>를 사용하여 실행 시에 연관 페칭 의미를 지정할 수 있다.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .setFetchMode("mate", FetchMode.EAGER)
+    .setFetchMode("kittens", FetchMode.EAGER)
+    .list();]]></programlisting>
+    
+        <para>
+                        이 질의는 outer 조인으로  <literal>mate</literal>와  <literal>kittens</literal> 모두를 페치할 것이다. 추가 정보는 
+            <xref linkend="performance-fetching"/>을 보라.
+        </para>
+    
+    </sect1>
+     
+    <sect1 id="querycriteria-examples">
+        <title>예제 질의들</title>
+
+        <para>
+            <literal>org.hibernate.criterion.Example</literal> 클래스는 주어진 인스턴스로부터 질의 기준(criterion)을 구조화 
+                        시키는 것을 당신에게 허용해준다.
+        </para>
+
+        <programlisting><![CDATA[Cat cat = new Cat();
+cat.setSex('F');
+cat.setColor(Color.BLACK);
+List results = session.createCriteria(Cat.class)
+    .add( Example.create(cat) )
+    .list();]]></programlisting>
+    
+        <para>
+                      버전 프로퍼티들, 식별자들, 연관관계들이 무시된다. 디폴트로 null 값 프로퍼티들이 제외된다.
+        </para>
+
+        <para>
+                       당신은 <literal>Example</literal>이 적용되는 방법을 조정할 수 있다.
+        </para>
+
+        <programlisting><![CDATA[Example example = Example.create(cat)
+    .excludeZeroes()           //exclude zero valued properties
+    .excludeProperty("color")  //exclude the property named "color"
+    .ignoreCase()              //perform case insensitive string comparisons
+    .enableLike();             //use like for string comparisons
+List results = session.createCriteria(Cat.class)
+    .add(example)
+    .list();]]></programlisting>
+    
+        <para>
+                        당신은 연관된 객체들에 대한 criteria(기준)을 위치지우는데 examples를 사용할 수 있다.
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .add( Example.create(cat) )
+    .createCriteria("mate")
+        .add( Example.create( cat.getMate() ) )
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-projection">
+        <title>Projections, aggregation 그리고 grouping</title>
+        <para>
+            <literal>org.hibernate.criterion.Projections</literal> 클래스는 <literal>Projection</literal> 인스턴스들에 
+                        대한 팩토리이다. 우리는 <literal>setProjection()</literal>을 호출하여 하나의 질의에 projection(투사,투영)을 적용시킨다.
+        </para>
+        
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.rowCount() )
+    .add( Restrictions.eq("color", Color.BLACK) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount() )
+        .add( Projections.avg("weight") )
+        .add( Projections.max("weight") )
+        .add( Projections.groupProperty("color") )
+    )
+    .list();]]></programlisting>
+    
+        <para>
+            criteria 질의 내에서는 명시적인 "group by"가 필수적이지 않다. 어떤 projection 타입들은 
+            <emphasis>grouping projections</emphasis>들이게끔 정의되고, 그것은 또한 SQL <literal>group by</literal> 절 속에 
+                        나타난다.
+        </para>
+    
+        <para>
+            alias는 선택적으로 projection에 할당될 수 있어서, 투사된(projected) 값은 제한(restriction)들 또는 ordering들 내에서 
+                        참조될 수 있다. 다음은 이것을 행하는 두 개의 다른 방법들이다:
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
+    .addOrder( Order.asc("colr") )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.groupProperty("color").as("colr") )
+    .addOrder( Order.asc("colr") )
+    .list();]]></programlisting>
+    
+        <para>
+            <literal>alias()</literal> 메소드와 <literal>as()</literal> 메소드는 또 다른 alias 된 
+            <literal>Projection</literal>의 인스턴스 내에 하나의 projection 인스턴스를 간단하게 포장한다. 지름길로서, 
+                        당신이 projection을 projection 리스트에 추가할 때 당신은 alias를 할당할 수 있다:
+        </para>
+
+       <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount(), "catCountByColor" )
+        .add( Projections.avg("weight"), "avgWeight" )
+        .add( Projections.max("weight"), "maxWeight" )
+        .add( Projections.groupProperty("color"), "color" )
+    )
+    .addOrder( Order.desc("catCountByColor") )
+    .addOrder( Order.desc("avgWeight") )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Domestic.class, "cat")
+    .createAlias("kittens", "kit")
+    .setProjection( Projections.projectionList()
+        .add( Projections.property("cat.name"), "catName" )
+        .add( Projections.property("kit.name"), "kitName" )
+    )
+    .addOrder( Order.asc("catName") )
+    .addOrder( Order.asc("kitName") )
+    .list();]]></programlisting>
+    
+        <para>
+                        당신은 또한 projection들을 표현하는데 <literal>Property.forName()</literal>을 사용할 수 있다:
+        </para>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Property.forName("name") )
+    .add( Property.forName("color").eq(Color.BLACK) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount().as("catCountByColor") )
+        .add( Property.forName("weight").avg().as("avgWeight") )
+        .add( Property.forName("weight").max().as("maxWeight") )
+        .add( Property.forName("color").group().as("color" )
+    )
+    .addOrder( Order.desc("catCountByColor") )
+    .addOrder( Order.desc("avgWeight") )
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-detachedqueries">
+        <title>Detached 질의들과 서브질의들</title>
+        <para>
+            <literal>DetachedCriteria</literal> 클래스는 당신에게 세션 영역의 외부에서 질의를 생성시키도록 하고, 그런 다음 나중에 
+                        어떤 임의의 <literal>Session</literal>을 사용하여 그것을 실행하도록 한다.
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
+    .add( Property.forName("sex").eq('F') );
+    
+Session session = ....;
+Transaction txn = session.beginTransaction();
+List results = query.getExecutableCriteria(session).setMaxResults(100).list();
+txn.commit();
+session.close();]]></programlisting>
+
+        <para>
+            <literal>DetachedCriteria</literal>는 또한 서브질의를 표현하는데 사용된다. 서브질의들을 포함하는 Criterion 인스턴스들은 
+            <literal>Subqueries</literal> 또는 <literal>Property</literal>를 통해 얻어질 수 있다.            
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
+    .setProjection( Property.forName("weight").avg() );
+session.createCriteria(Cat.class)
+    .add( Property.forName("weight).gt(avgWeight) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
+    .setProjection( Property.forName("weight") );
+session.createCriteria(Cat.class)
+    .add( Subqueries.geAll("weight", weights) )
+    .list();]]></programlisting>
+    
+        <para>
+                        심지어 상관관계 지워진 서브질의들이 가능하다:
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
+    .setProjection( Property.forName("weight").avg() )
+    .add( Property.forName("cat2.sex").eqProperty("cat.sex") );
+session.createCriteria(Cat.class, "cat")
+    .add( Property.forName("weight).gt(avgWeightForSex) )
+    .list();]]></programlisting>
+
+    </sect1>
+
+        <!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer는 -JDO2에서 setResultClass와 유사한- 임의적인 
+                                    사용자 객체들을 반환하는 것을 허용한다. ResultTransformer에 대한 일반적인 사용이 또한 설명될 수 있다. -->
+               
+    <sect1 id="query-criteria-naturalid">
+        <title>natural 식별자에 의한 질의들</title>
+        
+        <para>
+                        대부분의 질의들에서, criteria 질의들을 포함하여, 질의 캐시는 매우 효율적이지 않다. 왜냐하면 질의 캐시 비유효성이 
+                        너무 자주 발생하기 때문이다. 하지만, 우리가 캐시 비유효성 알고리즘을 최적화 시킬 수 있는 한 가지 특별한 종류의 질의가 
+                        존재한다: 상수 natural 키에 의한 룩업. 몇몇 어플리케이션들에서, 이런 종류의 질의가 자주 발생한다. criteria API는 
+                        이 쓰임새를 위한 특별한 설비를 제공한다.
+        </para>
+        
+        <para>
+                        첫번째로 당신은 <literal>&lt;natural-id&gt;</literal>를 사용하여 당신의 엔티티에 대한 natural 키를 매핑
+                        시켜야 하고, second-level 캐시 사용을 가능하게 해야 한다.
+        </para>
+
+        <programlisting><![CDATA[<class name="User">
+    <cache usage="read-write"/>
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <natural-id>
+        <property name="name"/>
+        <property name="org"/>
+    </natural-id>
+    <property name="password"/>
+</class>]]></programlisting>
+    
+        <para>
+                        이 기능은 <emphasis>가변성 있는</emphasis> natural 키들을 가진 엔티티들의 용도로 고안되어 있지 않음을 노트하라.
+        </para>
+        
+        <para>
+                        다음으로 , Hibernate 질의 캐시를 사용 가능하도록 하라.
+        </para>
+        
+        <para>
+                        이제 <literal>Restrictions.naturalId()</literal>는 캐시 알고리즘을 보다 효율적으로 사용할 수 있도록 우리에게 허용해준다.
+        </para>
+       
+        <programlisting><![CDATA[session.createCriteria(User.class)
+    .add( Restrictions.naturalId()
+        .set("name", "gavin")
+        .set("org", "hb") 
+    ).setCacheable(true)
+    .uniqueResult();]]></programlisting>
+            
+    </sect1>
+    
+</chapter>

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/query_hql.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/query_hql.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/query_hql.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1178 @@
+<chapter id="queryhql" revision="1">
+    <title>HQL: 하이버네이트 질의 언어(Hibernate Query Language)</title>
+
+    <para>
+        Hibernate는 (아주 의도적으로) SQL과 매우 흡사하게 보이는 극히 강력한 질의 언어를 구비하고 있다. 그러나 그 구문에 의해 우롱당하지 말라; 
+        HQL은 상속, 다형성 그리고 연관과 같은 개념들을 이해하여서, 전체적으로 객체 지향적이다.
+    </para>
+
+    <sect1 id="queryhql-casesensitivity">
+        <title>대소문자 구분</title>
+
+        <para>
+                        질의들은 Java 클래스들과 프로퍼티들의 이름들을 제외하면 대소문자를 구분하지 않는다. 따라서 <literal>SeLeCT</literal>는 
+            <literal>SELECT</literal>와 같고 <literal>SELECT</literal>와도 같지만 <literal>org.hibernate.eg.FOO</literal>는 
+            <literal>org.hibernate.eg.Foo</literal>과 같지 않고 <literal>foo.barSet</literal>은 
+            <literal>foo.BARSET</literal>과 같지 않다.
+        </para>
+
+        <para>
+                        이 매뉴얼은 소문자 HQL 키워드를 사용한다. 몇몇 사용자들은 보다 나은 가독성을 위해 대문자 키워드들을 가진 질의들을 찾지만, 우리는 
+                        자바 코드 속에 삽입될 때  이 컨벤션이 추하다는 점을 발견한다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-from">
+        <title>from ì ˆ</title>
+
+        <para>
+                        가장 간단한 가능한 Hibernate 질의는 다음 형식이다:
+        </para>
+
+        <programlisting><![CDATA[from eg.Cat]]></programlisting>
+
+        <para>
+                        이것은 <literal>eg.Cat</literal> 클래스의 모든 인스턴스들을 간단하게 반환한다. 우리는 대개 클래스 이름을 수식할 필요가 없다. 
+                        왜냐하면, <literal>auto-import</literal>가 디폴트이기 때문이다. 따라서 우리는 대개 항상 단지 다음과 같이 작성한다:
+        </para>
+
+        <programlisting><![CDATA[from Cat]]></programlisting>
+
+        <para>
+                        대개 당신은 한 개의 <emphasis>alias</emphasis>를 할당할 필요가 있을 것이다. 왜냐하면 당신은 질의의 다른 부분들에서 
+            <literal>Cat</literal>을 참조하고자 원할 것이기 때문이다.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+        <para>
+                        이 질의는 alias <literal>cat</literal>을 <literal>Cat</literal> 인스턴스들에 할당하여서, 우리는 나중에 질의 속에서 
+                        그 alias를 사용할 수 있을 것이다. <literal>as</literal> 키워드는 옵션이다; 우리는 또한 다음과 같이 작성할 수 있다:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat]]></programlisting>
+
+        <para>
+                        여러 개의 클래스들은 cartesian product(카티젼 곱) 또는 "크로스" 조인으로 귀결되어 나타날 수도 있다.
+        </para>
+
+        <programlisting><![CDATA[from Formula, Parameter]]></programlisting>
+        <programlisting><![CDATA[from Formula as form, Parameter as param]]></programlisting>
+
+        <para>
+                       로컬 변수들에 대한 Java 네이밍 표준들과 일치되게, 첫 소문자를 사용하여 질의 alias들을 명명하는 것은 좋은 습관으로 간주된다
+           (예를 들면 <literal>domesticCat</literal>).
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-joins" revision="2">
+        <title>연관들과 조인들</title>
+
+        <para>
+                        우리는 또한 <literal>join</literal>을 사용하여 , 연관된 엔티티들에 또는 값들을 가진 콜렉션의 요소들에도  alias들을 할당할 수도 
+                        있다. 
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    inner join cat.mate as mate
+    left outer join cat.kittens as kitten]]></programlisting>
+
+        <programlisting><![CDATA[from Cat as cat left join cat.mate.kittens as kittens]]></programlisting>
+
+        <programlisting><![CDATA[from Formula form full join form.parameter param]]></programlisting>
+
+        <para>
+                        지원되는 join 타입들은 ANSI SQL로부터 빌려왔다
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>inner join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>left outer join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>right outer join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>full join</literal> (대개 유용하지 않음)
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>inner join</literal>, <literal>left outer join</literal>, 그리고  <literal>right outer join</literal> 
+                        구조체들이  약칭될 수 있다.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    join cat.mate as mate
+    left join cat.kittens as kitten]]></programlisting>
+
+        <para>
+                        당신은 HQL <literal>with</literal> 키워드를 사용하여 특별한 조인 조건들을 제공할 수 있다.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    left join cat.kittens as kitten 
+        with kitten.bodyWeight > 10.0]]></programlisting>
+
+        <para>
+                        게다가, "fetch" join은 값들을 가진 콜렉션들이나 연관관계들이 한 개의 select를 사용하여, 그것들의 부모 객체들에 따라 초기화 되는 
+                        것을 허용해준다. 이것은 콜렉션의 경우에 특히 유용하다. 그것은 연관관계들과 콜렉션들에 대한 매핑 파일의 outer join과 lazy 선언들을 
+                        효율적으로 오버라이드 시킨다. 추가 정보는 <xref linkend="performance-fetching"/>을 보라.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    inner join fetch cat.mate
+    left join fetch cat.kittens]]></programlisting>
+
+        <para>
+            fetch join은 대개 alias를 할당할 필요가 없다. 왜냐하면, 연관된 객체들이  <literal>where</literal> 절(또는 어떤 다른 절) 
+                        속에 사용되지 않을 것이기 때문이다. 또한 연관된 객체들은  질의 결과들 속에 직접 반환되지 않는다. 대신 그것들은 부모 객체를 통해 
+                        접근될 수  있다. 우리가 alias를 필요로 할 수 있는 유일한 이유는 더 많은 콜렉션들을 재귀적으로 조인 페칭시키는 경우이다: 
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    inner join fetch cat.mate
+    left join fetch cat.kittens child
+    left join fetch child.kittens]]></programlisting>
+
+        <para>
+            (비록 <literal>scroll()</literal>이 사용될 수 있을지라도) <literal>fetch</literal> 구조체는 
+            <literal>iterate()</literal>를 사용하여 호출되는 질의들 내에 사용될 수 없음을 노트하라. 이들 오퍼레이션들이 결과 행들에 
+                        기초하고 있기 때문에 <literal>fetch</literal>는 <literal>setMaxResults()</literal> 또는 
+            <literal>setFirstResult()</literal>과 함께 사용되지 말아야 하며, 그것들(결과 행들)은 대개 각각의 eager 콜렉션 페칭에 대해 
+                        중복들을 포함하므로 많은 행들이 당신이 기대하는 것이 아니다.
+            <literal>fetch</literal>는 특별한 용도의 <literal>with</literal> 조건과도 함께 사용될 수 없다.한 개의 질의 내에 하나 
+                        이상의 콜렉션을 조인 페칭시켜 카티젼 곱을 생성시키는 것이 가능한데, 이 경우에 주의하라. 다중 콜렉션 role들을 조인 페칭시키는 것은 
+                        또한 때때로 bag 매핑들에 대해 예기치 않은 결과들을 가져다주기 때문에, 당신이 이 경우에 당신의 질의들을 처방하는 방법에 대해 주의하라. 
+                        마지막으로 <literal>full join fetch</literal>와 <literal>right join fetch</literal>는 의미가 없다.
+        </para>
+
+        <para>
+                        만일 당신이 (바이트코드 방편으로) property-레벨 lazy 페칭을 사용할 경우, Hibernate로 하여금 <literal>fetch all properties</literal>를 
+                        사용하여 (첫 번째 질의에서) lazy 프로퍼티들을 즉시 페치하도록 강제시키는 것이 가능하다.
+        </para>
+
+        <programlisting><![CDATA[from Document fetch all properties order by name]]></programlisting>
+        <programlisting><![CDATA[from Document doc fetch all properties where lower(doc.name) like '%cats%']]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-joins-forms">
+        <title>join 구문의 형식들</title>
+
+	    <para>
+		    HQL은 두 가지 형식의 연관 조인을 지원한다: <literal>암묵적</literal> 그리고 <literal>명시적</literal>.
+		</para>
+
+	    <para>
+		        앞의 절에서 보여진 질의들은 모두 join 키워드가 from 절 내에 명시적으로 사용되는 <literal>명시적인</literal> 형식을 
+		        사용한다. 이것은 권장되는 형식이다.
+	    </para>
+
+	    <para>
+		    <literal>함축적인</literal> 형식은 join 키워드를 사용하지 않는다. 대신에, 연관들은  dot(.) 표기를 
+		        사용하여 "dot-참조된다(dereferenced)".  <literal>함축적인</literal> 조인들은 임의의 HQL 절들내에 
+		        나타날 수 있다. <literal>함축적인</literal> join은 결과되는 SQL 문장에서 inner join으로 귀결된다.
+	    </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.mate.name like '%s%']]></programlisting>
+	</sect1>
+
+    <sect1 id="queryhql-identifier-property">
+        <title>식별자 속성 참조하기</title>
+
+        <para>
+            개략적으로 말하자면, 엔티티의 식별자 속성을 참조하는 2가지 방법들이 존재한다:
+        </para>
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <emphasis>엔티티가 id로 명명된 비식별자 속성을 정의하지 않는다고 가정하면</emphasis> 
+                    특별한 속성(소문자) <literal>id</literal>가 엔티티의 식별자 속성을 참조하는데 사용될 수 있다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    만일 그 엔티티가 명명된 식별자 속성을 정의하는 경우, 당신은 그 속성 이름을 사용할 수도 있다.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            composite 식별자 속성들에 대한 참조들은 동일한 네이밍 규칙들을 따른다. 만일 그 엔티티가 id로 명명된 비식별자를 
+            갖고 있을 경우, composite 속성은 오직 그것의 정의된 명명에 의해 참조될 수 있다; 그밖의 경우 특별한 <literal>id</literal> 
+            속성이 식별자 속성을 참조하는데 사용될 수 있다.
+        </para>
+
+        <para>
+            노트: 이것은 버전 3.2.2에서 시작될 때 현격하게 변경되었다. 이전 버전들에서, <literal>id</literal>는 <emphasis>항상</emphasis> 
+            그것의 실제 이름에 관계없이 식별자 속성을 참조했다. 그 결정의 분기점은 <literal>id</literal>로 명명된 비식별자 속성들이 
+            Hibernate 질의들 내에서 결코 참조될 수 없었다는 점이었다.
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-select">
+        <title>select ì ˆ</title>
+
+        <para>
+            <literal>select</literal> 절은 질의 결과 셋 속에 반환할 객체들과 프로퍼티들이 어느 것인지를 골라 내도록 강제한다. 다음을 
+                        검토하자:
+        </para>
+
+        <programlisting><![CDATA[select mate 
+from Cat as cat 
+    inner join cat.mate as mate]]></programlisting>
+
+        <para>
+                        질의는 다른 <literal>Cat</literal>들의 <literal>mate</literal>들을 select 할 것이다. 실제로 당신은 이 질의들을 다음과 
+                        같이 보다 축약형으로 표현할수도 있다:
+        </para>
+
+        <programlisting><![CDATA[select cat.mate from Cat cat]]></programlisting>
+
+        <para>
+                        질의들은 컴포넌트 타입의 프로퍼티들을 포함하는 임의의 값 타입의 프로퍼티들을 반환할 수도 있다:
+        </para>
+
+        <programlisting><![CDATA[select cat.name from DomesticCat cat
+where cat.name like 'fri%']]></programlisting>
+
+        <programlisting><![CDATA[select cust.name.firstName from Customer as cust]]></programlisting>
+
+        <para>
+            <literal>Family</literal> 클래스가 적당한 생성자를 갖고 있음을 가정하면, 
+                        질의들은 여러 객체들 그리고/또는 프로퍼티들을 <literal>Object[]</literal> 타입의 배열로서,
+        </para>
+
+        <programlisting><![CDATA[select mother, offspr, mate.name 
+from DomesticCat as mother
+    inner join mother.mate as mate
+    left outer join mother.kittens as offspr]]></programlisting>
+
+        <para>
+                        또는 <literal>List</literal>로서,
+        </para>
+
+        <programlisting><![CDATA[select new list(mother, offspr, mate.name)
+from DomesticCat as mother
+    inner join mother.mate as mate
+    left outer join mother.kittens as offspr]]></programlisting>
+
+        <para>
+                        또는 실제 typesafe 자바 객체로서,
+        </para>
+
+        <programlisting><![CDATA[select new Family(mother, mate, offspr)
+from DomesticCat as mother
+    join mother.mate as mate
+    left join mother.kittens as offspr]]></programlisting>
+
+        <para>
+            반환할 수도 있다.
+        </para>
+
+        <para>
+                        당신은 <literal>as</literal>를 사용하여 select되는 표현식들에 alias들을 할당할 수 있다:
+        </para>
+
+        <programlisting><![CDATA[select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
+from Cat cat]]></programlisting>
+
+        <para>
+                        다음은 <literal>select new map</literal>과 함께 사용될 때 가장 유용하다:
+        </para>
+
+        <programlisting><![CDATA[select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
+from Cat cat]]></programlisting>
+
+        <para>
+                        이 질의는 select된 값들에 대한 alias로부터 한 개의 <literal>Map</literal>을 반환한다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-aggregation">
+        <title>집계 함수들</title>
+
+        <para>
+            HQL 질의들은 프로퍼티들에 대한 집계(aggregate) 함수들의 결과들을 반환할수도 있다:
+        </para>
+
+        <programlisting><![CDATA[select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
+from Cat cat]]></programlisting>
+
+<!-- NO LONGER SUPPORTED
+        <para>
+            Collections may also appear inside aggregate functions in the <literal>select</literal> 
+            clause.
+        </para>
+
+        <programlisting><![CDATA[select cat, count( elements(cat.kittens) ) 
+from Cat cat group by cat]]></programlisting>
+-->
+
+        <para>
+                        지원되는 집계 함수들은 다음과 같다
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>avg(...), sum(...), min(...), max(...)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>count(*)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>count(...), count(distinct ...), count(all...)</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+                        당신은 select 절 속에 산술 연산자들, 연결 연산자, 그리고 인지된 SQL 함수들을 사용할 수 있다:
+        </para>
+
+        <programlisting><![CDATA[select cat.weight + sum(kitten.weight) 
+from Cat cat 
+    join cat.kittens kitten
+group by cat.id, cat.weight]]></programlisting>
+    
+        <programlisting><![CDATA[select firstName||' '||initial||' '||upper(lastName) from Person]]></programlisting>
+
+        <para>
+            <literal>distinct</literal> 키워드와 all <literal>all</literal>가 사용될 수 있고 SQL의 경우와 동일한 의미를 갖는다.
+        </para>
+
+        <programlisting><![CDATA[select distinct cat.name from Cat cat
+
+select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-polymorphism">
+        <title>Polymorphic(다형성) 질의들</title>
+
+        <para>
+                        다음과 같은 질의:
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+        <para>
+                        은 <literal>Cat</literal>의 인스턴스들 뿐만 아니라, 또한 <literal>DomesticCat</literal>과 같은 서브클래스들 또한 
+                        반환한다. Hibernate 질의들은 <literal>from</literal> 절 내에 <emphasis>임의의</emphasis> 자바 클래스나 인터페이스를 
+                        명명할 수 있다. 질의는 그 클래스를 확장하거나 그 인터페이스를 구현하는 모든 영속 클래스들의 인스턴스들을 반환할 것이다. 다음 질의는 
+                        모든 영속 객체들을 반환할 것이다:
+        </para>
+
+        <programlisting><![CDATA[from java.lang.Object o]]></programlisting>
+
+        <para>
+                        인터페이스 <literal>Named</literal>는 여러 가지 영속 클래스들에 의해 구현될 수도 있다:
+        </para>
+
+        <programlisting><![CDATA[from Named n, Named m where n.name = m.name]]></programlisting>
+
+        <para>
+                        이들 마지막 두 개의 질의들은 하나 이상의 SQL <literal>SELECT</literal>를 필요로 할 것임을 노트하라. 이것은 <literal>order by</literal> 
+                        절이 정확하게 전체 결과 셋을 순서지우지 않음을 의미한다.(그것은 또한 당신이 <literal>Query.scroll()</literal>을 사용하여 
+                        이들 질의들을 호출할 수 없음을 의미한다).
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-where" revision="1">
+        <title>where ì ˆ</title>
+
+        <para>
+            <literal>where</literal> 절은 반환된 인스턴스들의 목록을 제한시키는 것을 당신에게 허용해준다. 만일 alias가 존재하지 않을 경우, 
+                        당신은 이름에 의해 프로퍼티들을 참조할 수도 있다:
+        </para>
+
+        <programlisting><![CDATA[from Cat where name='Fritz']]></programlisting>
+
+        <para>
+                        만일 한 개의 alias가 존재할 경우, 하나의 수식어가 붙은 프로퍼티 이름을 사용하라:
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.name='Fritz']]></programlisting>
+
+        <para>
+                       는 'Fritz'로 명명된 <literal>Cat</literal>의 인스턴스들을 반환한다.
+        </para>
+
+        <programlisting><![CDATA[select foo 
+from Foo foo, Bar bar
+where foo.startDate = bar.date]]></programlisting>
+
+        <para>
+                        는 <literal>Foo</literal>의 <literal>startDate</literal> 프로퍼티와 동일한 <literal>date</literal> 프로퍼티를 
+                        가진 <literal>bar</literal>의 인스턴스가 존재하는 <literal>Foo</literal>의 모든 인스턴스를 반환할 것이다. 합성 경로 
+                        표현식들은  <literal>where</literal> 절을 매우 강력하게 만들어준다. 다음을 검토하자:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.mate.name is not null]]></programlisting>
+
+        <para>
+                        이 질의는 테이블 (inner) join을 가진 SQL 질의로 번역된다. 만일 당신이 다음과 같은 어떤 것을 작성했다면
+        </para>
+
+        <programlisting><![CDATA[from Foo foo  
+where foo.bar.baz.customer.address.city is not null]]></programlisting>
+
+        <para>
+                        당신은 SQL에서 네 개의 테이블 join들을 필요로 하는 하나의 질의로 끝낼 것이다.
+        </para>
+
+        <para>
+            <literal>=</literal> 연산자는 프로퍼티들 뿐만 아니라 또한 인스턴스들을 비교하는데 사용될 수 있다:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat, Cat rival where cat.mate = rival.mate]]></programlisting>
+
+        <programlisting><![CDATA[select cat, mate 
+from Cat cat, Cat mate
+where cat.mate = mate]]></programlisting>
+
+        <para>
+                        특별한 프로퍼티(소문자) <literal>id</literal>는  객체의 유일 식별자를 참조하는데 사용될 수 있다.
+                        추가 정보는 <xref linkend="queryhql-identifier-property"/>를 보라.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.id = 123
+
+from Cat as cat where cat.mate.id = 69]]></programlisting>
+
+        <para>
+                        두 번째 질의가 효율적이다. 테이블 join이 필요 없다!
+        </para>
+
+        <para>
+            composite(합성) 식별자들의 프로퍼티들이 또한 사용될 수 있다. <literal>Person</literal>이 
+            <literal>country</literal>와 <literal>medicareNumber</literal>로 구성된 composite 식별자를 갖는다고 
+            가정하자. 식별자 속성들을 참조하는 것과 관련된 추가 정보는 다시 <xref linkend="queryhql-identifier-property"/>를 보라.
+        </para>
+
+        <programlisting><![CDATA[from bank.Person person
+where person.id.country = 'AU'
+    and person.id.medicareNumber = 123456]]></programlisting>
+
+        <programlisting><![CDATA[from bank.Account account
+where account.owner.id.country = 'AU'
+    and account.owner.id.medicareNumber = 123456]]></programlisting>
+
+        <para>
+                        다시 한번, 두 번째 질의는 테이블 join을 필요로 하지 않는다.
+        </para>
+
+        <para>
+                        마찬가지로, 특별한 프로퍼티 <literal>class</literal>는 다형적인 영속성(polymorphic persistence)의 경우에 인스턴스의 
+                        판별자(discriminator) 값에 액세스한다. where 절 속에 삽입된 Java 클래스 이름은 그것의 판별자(discriminator) 값으로 
+                        변환될 것이다.
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
+
+        <para>
+            당신은 또한 컴포넌트들 또는 composite 사용자 타입들, 또는 명명된 컴포넌트 타입들의 속성들을 사용할 수도 있다. 상세한 것은 
+             <xref linkend="queryhql-components"/>를 보라.
+        </para>
+
+        <para>
+            "임의의" 타입은 다음 방법으로 join을 표현하는 것을 우리에게 허용해주는, 특별한 프로퍼티들 <literal>id</literal>와 
+            <literal>class</literal>를 갖는다(여기서 <literal>AuditLog.item</literal>은 <literal>&lt;any&gt;</literal>로 
+                        매핑된 프로퍼티이다).
+        </para>
+
+        <programlisting><![CDATA[from AuditLog log, Payment payment 
+where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting>
+
+        <para>
+            <literal>log.item.class</literal>와 <literal>payment.class</literal>는 위의 질의 내에서 완전히 다른 데이터베이스 
+                        컬럼들의 값들을 참조할 것임을 노트하라.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-expressions">
+        <title>표현식들</title>
+
+        <para>
+            <literal>where</literal> 절 속에 허용되는 표현식들은 당신이 SQL로 작성할 수 있는 대부분의 종류의 것들을 포함한다:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                                        산술 연산자들 <literal>+, -, *, /</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        바이너리 비교 연산자들 <literal>=, &gt;=, &lt;=, &lt;&gt;, !=, like</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        논리 연산들 <literal>and, or, not</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        그룹핑을 나타내는 괄호들 <literal>( )</literal>, indicating grouping
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>in</literal>,
+                    <literal>not in</literal>,
+                    <literal>between</literal>,
+                    <literal>is null</literal>,
+                    <literal>is not null</literal>,
+                    <literal>is empty</literal>,
+                    <literal>is not empty</literal>,
+                    <literal>member of</literal> and 
+                    <literal>not member of</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    "간단한" 경우, <literal>case ... when ... then ... else ... end</literal>, 그리고
+                    "검색인" 경우, <literal>case when ... then ... else ... end</literal> 
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        문자열 연결 <literal>...||...</literal> or <literal>concat(...,...)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>current_date()</literal>, <literal>current_time()</literal>,
+                    <literal>current_timestamp()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>second(...)</literal>, <literal>minute(...)</literal>, 
+                    <literal>hour(...)</literal>, <literal>day(...)</literal>, 
+                    <literal>month(...)</literal>, <literal>year(...)</literal>,
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    EJB-QL 3.0에 의해 정의된 임의의 함수 또는 오퍼레이터: <literal>substring(), trim(),
+                    lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>coalesce()</literal> 그리고 <literal>nullif()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    numeric 값들이나 temporal 값들을 가독성 있는 문자열로 변환시키는 <literal>str()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>cast(... as ...)</literal>, 여기서 두번 째 아규먼트는 Hibernate 타입의 이름이고, 
+                    ANSI <literal>cast()</literal>와 <literal>extract()</literal>가 기반 데이터베이스에 의해 
+                                        지원될 경우에는 <literal>extract(... from ...)</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        조인된 인덱싱된 콜렉션의 alias들에 적용되는, HQL <literal>index()</literal> 함수 
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        콜렉션 값을 가진 경로 표현식들을 취하는 HQL 함수들 : <literal>some, all, exists, any, in</literal>을
+                                         사용하여 정량화 될 수 있는 특별한 <literal>elements()</literal>와 <literal>indices</literal> 
+                                        함수들과 함께 <literal>size(), minelement(), maxelement(), minindex(), maxindex()</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>sign()</literal>, <literal>trunc()</literal>, <literal>rtrim()</literal>, 
+                    <literal>sin()</literal>과 같이 임의의 데이터베이스 지원 SQL 스칼라 함수
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    JDBC-스타일 위치 파라미터들 <literal>?</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        명명된 파라미터들 <literal>:name</literal>, <literal>:start_date</literal>, <literal>:x1</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    SQL 리터럴들 <literal>'foo'</literal>, <literal>69</literal>, <literal>6.66E+2</literal>,
+                    <literal>'1970-01-01 10:00:01.0'</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Java <literal>public static final</literal> 상수들. <literal>eg.Color.TABBY</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>in</literal> 과 <literal>between</literal>은 다음과 같이 사용될 수 있다:
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name between 'A' and 'B']]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+        <para>
+                    그리고 부정형들은 다음과 같이 작성될 수 있다
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name not between 'A' and 'B']]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+        <para>
+                        마찬가지로, <literal>is null</literal>과  <literal>is not null</literal>은 null 값들을 테스트하는데 사용될 수 있다.
+        </para>
+
+        <para>
+            Boolean들은 Hibernate 구성 내에 HQL 질의 치환들을 선언함으로써 표현식들 내에 쉽게 사용될 수 있다:
+        </para>
+
+        <programlisting><![CDATA[<property name="hibernate.query.substitutions">true 1, false 0</property>]]></programlisting>
+
+        <para>
+                        이것은 키워드 <literal>true</literal>와 <literal>false</literal> 키워드들을 이 HQL로부터 번역된 SQL에서 
+                        리터럴 <literal>1</literal>과 <literal>0</literal>으로 대체될 것이다:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.alive = true]]></programlisting>
+
+        <para>
+                        당신은 특별한 프로퍼티 <literal>size</literal>로서 또는 특별한 <literal>size()</literal> 함수로서 콜렉션의 사이즈를 
+                        테스트할 수 있다.
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.kittens.size > 0]]></programlisting>
+
+        <programlisting><![CDATA[from Cat cat where size(cat.kittens) > 0]]></programlisting>
+
+        <para>
+                        인덱싱된 콜렉션들에 대해, 당신은<literal>minindex</literal>와 <literal>maxindex</literal> 함수들을 사용하여 
+                        최소 인덱스과 최대 인덱스를 참조할 수 있다. 유사하게 당신은 <literal>minelement</literal>와 
+            <literal>maxelement</literal> 함수를 사용하여 기본 타입을 가진 콜렉션의 최소 요소 및 최대 요소를 참조할 수 있다.
+        </para>
+
+        <programlisting><![CDATA[from Calendar cal where maxelement(cal.holidays) > current_date]]></programlisting>
+
+        <programlisting><![CDATA[from Order order where maxindex(order.items) > 100]]></programlisting>
+
+        <programlisting><![CDATA[from Order order where minelement(order.items) > 10000]]></programlisting>
+
+        <para>
+            SQL 함수들 <literal>any, some, all, exists, in</literal>은 콜렉션의 요소 또는 인덱스 세트(<literal>elements</literal> 
+                        함수와 <literal>indices</literal> 함수), 또는 서브질의의 결과를 전달했을 때 지원된다(아래를 보라).
+        </para>
+
+        <programlisting><![CDATA[select mother from Cat as mother, Cat as kit
+where kit in elements(foo.kittens)]]></programlisting>
+
+        <programlisting><![CDATA[select p from NameList list, Person p
+where p.name = some elements(list.names)]]></programlisting>
+
+        <programlisting><![CDATA[from Cat cat where exists elements(cat.kittens)]]></programlisting>
+
+        <programlisting><![CDATA[from Player p where 3 > all elements(p.scores)]]></programlisting>
+
+        <programlisting><![CDATA[from Show show where 'fizard' in indices(show.acts)]]></programlisting>
+
+        <para>
+                        이들 구조체들-<literal>size</literal>, <literal>elements</literal>, <literal>indices</literal>, 
+            <literal>minindex</literal>, <literal>maxindex</literal>, <literal>minelement</literal>, 
+            <literal>maxelement</literal>-는 Hibernate3에서 where 절 내에서만 사용될 것임을 노트하라.
+        </para>
+
+        <para>
+                        인덱싱 된 콜렉션들의 요소들(배열들, 리스트들, map들)은 인덱스에 의해 참조될 수 있다(where 절 안에서만):
+        </para>
+
+        <programlisting><![CDATA[from Order order where order.items[0].id = 1234]]></programlisting>
+
+        <programlisting><![CDATA[select person from Person person, Calendar calendar
+where calendar.holidays['national day'] = person.birthDay
+    and person.nationality.calendar = calendar]]></programlisting>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11]]></programlisting>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ maxindex(order.items) ] = item and order.id = 11]]></programlisting>
+
+        <para>
+            <literal>[]</literal> 내부의 표현식은 산술 표현실일 수 있다.
+        </para>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ size(order.items) - 1 ] = item]]></programlisting>
+
+        <para>
+            HQL은 또한  one-to-many 연관 또는 값들을 가진 콜렉션의 요소들에 대해 미리 만들어진 <literal>index()</literal> 함수를 
+                        제공한다.
+        </para>
+
+        <programlisting><![CDATA[select item, index(item) from Order order 
+    join order.items item
+where index(item) < 5]]></programlisting>
+
+        <para>
+                        기본 데이터베이스에 의해 제공되는 Scalar SQL 함수들이 사용될 수도 있다
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like 'FRI%']]></programlisting>
+
+        <para>
+                        당신이 아직 이 모든 것을 납득하지 못한다면, SQL 내에서 다음 질의가 가독성이 얼마나 많고 적은지를 생각해보라:
+        </para>
+
+        <programlisting><![CDATA[select cust
+from Product prod,
+    Store store
+    inner join store.customers cust
+where prod.name = 'widget'
+    and store.location.name in ( 'Melbourne', 'Sydney' )
+    and prod = all elements(cust.currentOrder.lineItems)]]></programlisting>
+
+        <para>
+            <emphasis>힌트</emphasis> : 다음과 같은 어떤 것
+        </para>
+
+        <programlisting><![CDATA[SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
+FROM customers cust,
+    stores store,
+    locations loc,
+    store_customers sc,
+    product prod
+WHERE prod.name = 'widget'
+    AND store.loc_id = loc.id
+    AND loc.name IN ( 'Melbourne', 'Sydney' )
+    AND sc.store_id = store.id
+    AND sc.cust_id = cust.id
+    AND prod.id = ALL(
+        SELECT item.prod_id
+        FROM line_items item, orders o
+        WHERE item.order_id = o.id
+            AND cust.current_order = o.id
+    )]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-ordering">
+        <title>order by ì ˆ</title>
+
+        <para>
+                        질의에 의해 반환된 리스트는 반환된 클래스 또는 컴포넌트들의 프로퍼티에 의해 순서(ordering)지워질 수 있다:
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat
+order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
+
+        <para>
+            <literal>asc</literal> 옵션 또는 <literal>desc</literal> 옵션은 각각 오름차순 또는 내림차순 정렬을 나타낸다.
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-grouping" revision="1">
+        <title>group by ì ˆ</title>
+
+        <para>
+            aggregate 값들을 반환하는 질의는 반환된 클래스나 컴포넌트들의 프로퍼티에 의해 그룹지워질 수 있다:
+        </para>
+
+        <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat) 
+from Cat cat
+group by cat.color]]></programlisting>
+
+        <programlisting><![CDATA[select foo.id, avg(name), max(name) 
+from Foo foo join foo.names name
+group by foo.id]]></programlisting>
+
+        <para>
+                        또한 <literal>having</literal> 절이 허용된다.
+        </para>
+
+        <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat) 
+from Cat cat
+group by cat.color 
+having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
+
+        <para>
+            SQL 함수들과 집계 함수들이 기본 데이터베이스에 의해 지원될 경우(예를 들어 MySQL은 지원되지 않는다) 
+            <literal>having</literal> 절과 <literal>order by</literal> 절 속에 허용된다.
+        </para>
+
+        <programlisting><![CDATA[select cat
+from Cat cat
+    join cat.kittens kitten
+group by cat.id, cat.name, cat.other, cat.properties
+having avg(kitten.weight) > 100
+order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
+
+        <para>
+            <literal>group by</literal> 절도 <literal>order by</literal> 절 어느 것도 산술 표현식들을 포함할 수 없다는 점을 
+                        노트하라. 또한 Hibernate는 현재 그룹지워진 엔티티를 확장하지 않아서 만일 <literal>cat</literal>의 
+                        모든 속성들이 집계되지 않을 경우에 당신이 <literal>group by cat</literal>을 쓸수 없음을 노트하라.
+                        당신은 명시적으로 모든 집계되지 않는 속성들을 리스트해야 한다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-subqueries" revision="3">
+        <title>서브질의들</title>
+        
+        <para>
+            subselect들을 지원하는 데이터베이스들의 경우, Hibernate는 질의들 내에 서브질의들을 지원한다. 서브질의는 괄호로 묶여져야 
+            한다(자주 SQL 집계함수 호출에 의해). 심지어 서로 상관된 서브질의들(외부 질의 내에서 alias를 참조하는 서브질의들)이 허용된다.
+        </para>
+
+        <programlisting><![CDATA[from Cat as fatcat
+where fatcat.weight > (
+    select avg(cat.weight) from DomesticCat cat
+)]]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat as cat
+where cat.name = some (
+    select name.nickName from Name as name
+)]]></programlisting>
+
+        <programlisting><![CDATA[from Cat as cat
+where not exists (
+    from Cat as mate where mate.mate = cat
+)]]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat as cat
+where cat.name not in (
+    select name.nickName from Name as name
+)]]></programlisting>
+
+        <programlisting><![CDATA[select cat.id, (select max(kit.weight) from cat.kitten kit)
+from Cat as cat]]></programlisting>
+
+        <para>
+            HQL 서브질의들이 select 절 또는 where 절 내에서만 일어날 수 있음을 노트하라.
+        </para>
+
+
+        <para>
+            서브질의들은 또한 <literal>row value constructor</literal> 구문을 활용할 수 있다. 상세한 것은 
+            <xref linkend="queryhql-tuple"/>를 보라.
+        </para>
+
+    </sect1>
+
+    <sect1 id="queryhql-examples">
+        <title>HQL 예제들</title>
+
+        <para>
+
+            Hibernate 질의들은 매우 강력하고 복잡할 수 있다. 사실, 질의 언어의 힘은 Hibernate의 주요 판매 포인트들 중 하나이다. 다음은 
+                        내가 최근의 프로젝트에서 사용했던 질의들과 매우 유사한 몇몇 예제 질의들이다. 당신이 작성하게 될 대부분의 질의들은 이것들보다 훨씬 
+                        간단하다는 점을 노트하라!
+        </para>
+
+        <para>
+                        다음 질의는 특정 고객에 대한 모든 지불되지 않은 주문들의 주문 id, 항목들의 개수, 그리고 주문의 전체 합계값 그리고 주어진 
+                        최소 전체 합계를 전체 합계값에 따라 결과들을 순서지워서 반환한다. 가격 결정에 있어, 그것은 현재의 카타록을 사용한다.
+                        귀결되는 SQL 질의는 <literal>ORDER</literal>, <literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>, 
+            <literal>CATALOG</literal>, <literal>PRICE</literal> 테이블들에 대한 네 개의 inner 조인들과 한 개의(상관지워지지 
+                        않은) subselect를 갖고 있다.
+        </para>
+
+        <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+    join order.lineItems as item
+    join item.product as product,
+    Catalog as catalog
+    join catalog.prices as price
+where order.paid = false
+    and order.customer = :customer
+    and price.product = product
+    and catalog.effectiveDate < sysdate
+    and catalog.effectiveDate >= all (
+        select cat.effectiveDate 
+        from Catalog as cat
+        where cat.effectiveDate < sysdate
+    )
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+
+        <para>
+                        괴물 같은 것! 실제로 실 생활에서, 나는 서브질의들을 매우 좋아하지 않아서, 나의 질의는 실제로 다음과 같았다:
+        </para>
+
+        <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+    join order.lineItems as item
+    join item.product as product,
+    Catalog as catalog
+    join catalog.prices as price
+where order.paid = false
+    and order.customer = :customer
+    and price.product = product
+    and catalog = :currentCatalog
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+
+        <para>
+                        다음 질의는 현재 사용자에 의해 가장 최근의 상태 변경이 행해졌던 <literal>AWAITING_APPROVAL</literal> 상태에 있는 모든 
+                        지불들을 제외한, 각각의 상태에 있는 지불들의 개수를 카운트 한다. 그것은 <literal>PAYMENT</literal>, 
+            <literal>PAYMENT_STATUS</literal>, <literal>PAYMENT_STATUS_CHANGE</literal> 테이블들에 대한 두 개의 inner 
+                        조인들과 하나의 상관관계 지워진 subselect를 가진 SQL 질의로 변환된다.
+        </para>
+
+        <programlisting><![CDATA[select count(payment), status.name 
+from Payment as payment 
+    join payment.currentStatus as status
+    join payment.statusChanges as statusChange
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+    or (
+        statusChange.timeStamp = ( 
+            select max(change.timeStamp) 
+            from PaymentStatusChange change 
+            where change.payment = payment
+        )
+        and statusChange.user <> :currentUser
+    )
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+        <para>
+                        만일 내가 <literal>statusChanges</literal> 콜렉션을 set가 아닌 list로 매핑했다면, 그 질의는 작성하기가 훨씬 더 
+                        간단했을 것이다.
+        </para>
+
+        <programlisting><![CDATA[select count(payment), status.name 
+from Payment as payment
+    join payment.currentStatus as status
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+    or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+        <para>
+                        다음 질의는 현재의 사용자가 속해 있는 조직의 모든 계정들과 지불되지 않은 지불들을 반환하는데 MS SQL Server 
+            <literal>isNull()</literal> 함수를 사용한다. 그것은 <literal>ACCOUNT</literal>, <literal>PAYMENT</literal>, 
+            <literal>PAYMENT_STATUS</literal>, <literal>ACCOUNT_TYPE</literal>, <literal>ORGANIZATION</literal>, 
+            <literal>ORG_USER</literal> 테이블들에 대한 세 개의 inner 조인들, 하나의 outer 조인, 그리고 하나의 subselect를 가진 
+                        한 개의 SQL 질의로 번역된다.
+        </para>
+
+        <programlisting><![CDATA[select account, payment
+from Account as account
+    left outer join account.payments as payment
+where :currentUser in elements(account.holder.users)
+    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+        <para>
+                        몇몇 데이터베이스들의 경우, 우리는 (상관관계 지워진) subselect를 없앨 필요가 있을 것이다.
+        </para>
+
+        <programlisting><![CDATA[select account, payment
+from Account as account
+    join account.holder.users as user
+    left outer join account.payments as payment
+where :currentUser = user
+    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+   </sect1>
+
+    <sect1 id="queryhql-bulk" revision="2">
+        <title>대량 update와 delete</title>
+
+        <para>
+            HQL은 이제 <literal>update</literal>, <literal>delete</literal> 그리고 
+            <literal>insert ... select ...</literal> 문장들을 지원한다.
+                        상세한 것은 <xref linkend="batch-direct"/>를 보라.
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-tipstricks">
+        <title>팁들 &amp; 트릭들</title>
+
+        <para>
+                        당신은 실제로 질의 결과들을 반환하지 않고서 그것들(질의 결과들)의 개수를 카운트할 수  있다:
+        </para>
+
+        <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue()]]></programlisting>
+
+        <para>
+                        콜렉션의 크기에 따라 결과를 순서(ordering)지우려면, 다음 질의를 사용하라:
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User as usr 
+    left join usr.messages as msg
+group by usr.id, usr.name
+order by count(msg)]]></programlisting>
+
+        <para>
+                        만일 당신의 데이터베이스가 subselect들을 지원할 경우, 당신은 당신의 질의의 where 절 내에 selection 사이즈에 대한 조건을 
+                        위치지울 수 있다:
+        </para>
+
+        <programlisting><![CDATA[from User usr where size(usr.messages) >= 1]]></programlisting>
+
+        <para>
+                        만일 당신의 데이터베이스가 subselect를 지원하지 않을 경우, 다음 질의를 사용하라:
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User usr.name
+    join usr.messages msg
+group by usr.id, usr.name
+having count(msg) >= 1]]></programlisting>
+
+        <para>
+                        이 해결책이 inner 조인 때문에 0개의 메시지를 가진 <literal>User</literal>를 반환할 수 없으므로, 다음 형식이 또한 유용하다:
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+    left join usr.messages as msg
+group by usr.id, usr.name
+having count(msg) = 0]]></programlisting>
+
+        <para>
+                        하나의 JavaBean의 프로퍼티들은 명명된 질의 파라미터들에 바인드될 수 있다:
+        </para>
+
+        <programlisting><![CDATA[Query q = s.createQuery("from foo Foo as foo where foo.name=:name and foo.size=:size");
+q.setProperties(fooBean); // fooBean has getName() and getSize()
+List foos = q.list();]]></programlisting>
+
+        <para>
+                        콜렉션들은 필터를 가진 <literal>Query</literal> 인터페이스를 사용하여 쪼매김하는 것이 가능하다:
+        </para>
+
+        <programlisting><![CDATA[Query q = s.createFilter( collection, "" ); // the trivial filter
+q.setMaxResults(PAGE_SIZE);
+q.setFirstResult(PAGE_SIZE * pageNumber);
+List page = q.list();]]></programlisting>
+
+        <para>
+                        콜렉션 요소들은 질의 필터를 사용하여 순서(ordering)지워지거나 그룹지워질 수 도 있다:
+        </para>
+
+        <programlisting><![CDATA[Collection orderedCollection = s.filter( collection, "order by this.amount" );
+Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );]]></programlisting>
+
+        <para>
+                        당신은 콜렉션을 초기화 하지 않고서 그것(콜렉션)의 크기를 찾을 수 있다:
+        </para>
+
+        <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-components">
+        <title>컴포넌트들</title>
+
+        <para>
+            컴포넌트들은 단지 간단한 값 유형들이 HQL 질의들 내에 사용될 수 있는 모든 방법으로 사용될 수 있다. 그것들은 
+            <literal>select</literal> 절 내에 나타날 수 있다. 
+        </para>
+
+        <programlisting><![CDATA[select p.name from from Person p]]></programlisting>
+        <programlisting><![CDATA[select p.name.first from from Person p]]></programlisting>
+
+        <para>
+            여기서 Person의 name 속성은 컴포넌트이다. 컴포넌트들은 또한 <literal>where</literal> 절 내에 사용될 수 있다: 
+        </para>
+
+        <programlisting><![CDATA[from from Person p where p.name = :name]]></programlisting>
+        <programlisting><![CDATA[from from Person p where p.name.first = :firstName]]></programlisting>
+
+        <para>
+            컴포넌트들은 또한 <literal>order by</literal> 절 내에 사용될 수 있다:
+        </para>
+
+        <programlisting><![CDATA[from from Person p order by p.name]]></programlisting>
+        <programlisting><![CDATA[from from Person p order by p.name.first]]></programlisting>
+
+        <para>
+            컴포넌트들에 대한 또 다른 공통적인 사용은 <xref linkend="queryhql-tuple">row value constructors</xref>에 있다.
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-tuple">
+        <title>Row value constructor 구문</title>
+
+        <para>
+            HQL은 ANSI SQL <literal>row value constructor</literal> 구문(종종 <literal>tuple</literal> 구문이라 명명된다)의 사용을 지원한다. 
+            비록 데이터베이스가 그 개념을 지원하지 않을지라도 그러하다. 여기서 우리는 전형적으로 컴포넌트들과 연관되어 있는 다중-값 비교들을 
+            일반적으로 언급하고 있다. name 컴포넌트를 정의하는 Person 엔티티를 검토하자:
+        </para>
+
+        <programlisting><![CDATA[from Person p where p.name.first='John' and p.name.last='Jingleheimer-Schmidt']]></programlisting>
+
+        <para>
+            비록 약간 장황스럽지만 그것은 유효한 구문이다. 이것을 약간 더 간결하게 만들고 
+            <literal>row value constructor</literal> 구문을 사용하는 것이 좋다:
+        </para>
+
+        <programlisting><![CDATA[from Person p where p.name=('John', 'Jingleheimer-Schmidt')]]></programlisting>
+
+        <para>
+            <literal>select</literal>절 내에 이것을 지정하는 것이 또한 유용할 수 있다:
+        </para>
+
+        <programlisting><![CDATA[select p.name from from Person p]]></programlisting>
+
+        <para>
+            <literal>row value constructor</literal> 구문을 사용하는 또 다른 경우는 다중 값들에 대해 비교할 필요가 있는 
+            서브 질의들을 사용할 때이다:
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat
+where not ( cat.name, cat.color ) in (
+    select cat.name, cat.color from DomesticCat cat
+)]]></programlisting>
+
+        <para>
+            만일 당신이 이 구문을 사용하고자 원할 경우에 고려해야 할 한 가지는 질의가 메타데이터 내에 있는 
+            컴포넌트 서브-속성들의 순서에 종속될 것이라는 점이다.
+        </para>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/query_sql.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/query_sql.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/query_sql.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,694 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="querysql" revision="2">
+  <title>Native SQL</title>
+
+    <para>당신은 또한 당신의 데이터베이스의 native SQL dialect로 질의들을 표현할 수도 있다. 
+                당신이 오라클의 질의 힌트들 또는  <literal>CONNECT</literal> 키워드와 같은 
+                데이터베이스 지정적인 특징들을 활용하고자 원할 경우에 이것이 유용하다. 
+                그것은 또한 직접적인 SQL/JDBC 기반의 어플리케이션으로부터 Hibernate로의 보다 명료한 
+                이전 경로를 제공한다.</para>
+
+    <para>Hibernate3은 또한 모든 create, update, delete, load 오퍼레이션들에 대해 
+        (내장 프로시저들을 포함하여) 손으로 작성된 SQL을 지정하는 것을 당신에게 허용해준다.</para>
+
+  <sect1 id="querysql-creating" revision="4">
+    <title><literal>SQLQuery</literal> 사용하기</title>
+
+    <para>native SQL 질의들의 실행은 <literal>SQLQuery</literal> 인터페이스를 통해 
+        제어되며, 그것은 <literal>Session.createSQLQuery()</literal>을 호출하여 
+        획득된다. 다음은 이 API를 질의에 사용하는 방법을 설명한다.</para>
+
+    <sect2>
+      <title>스칼라 질의들</title>
+
+      <para>가장 기본적인 SQL 질의는 스칼라들(값들)의 목록을 얻는 
+            것이다.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").list();
+sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
+]]></programlisting>
+
+      <para>이것들은 둘다 CATS 테이블 내에 있는 각각의 컬럼에 대한 스칼라 값들을 가진 Object 
+             배열들의 List를 반환할 것이다. Hibernate는 반환되는 스칼라 값들의 실제 순서와 타입들을 
+            도출하는데 ResultSetMetadata를 사용할 것이다.</para>
+
+      <para><literal>ResultSetMetadata</literal> 사용의 오버헤드를 피하거나 
+            간단하게는 반환되는 것을 보다 명시적이게끔 하기 위해 우리는 
+      <literal>addScalar()</literal>를 사용할 수 있다.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME", Hibernate.STRING)
+ .addScalar("BIRTHDATE", Hibernate.DATE)
+]]></programlisting>
+
+      <para>이 질의는 다음을 지정했다:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>SQL 질의 문자열</para>
+        </listitem>
+
+        <listitem>
+          <para>반환할 컬럼들과 타입들</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>이것은 여전히 Object 배열들을 반환할 것이지만, 이제 그것은 
+      <literal>ResultSetMetdata</literal>를 사용하지 않을 것이고 대신에 
+            기반 결과셋으로부터 ID, NAME 그리고 BIRTHDATE 컬럼을 각각 Long, String 
+            그리고 Short 타입으로 반환할 것이다. 심지어 그 질의가 <literal>*</literal>를 
+            사용하고 세 개의 열거된 컬럼들 보다 더 많은 것을 반환할 수 있을지라도, 이것은 
+            또한 오직 이들 세 개의 컬럼들 만이 반환될 것임을 의미한다.</para>
+
+      <para>스칼라들 중 몇몇 또는 전부에 대한 타입 정보를 남겨두는 것이 가능하다.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME")
+ .addScalar("BIRTHDATE")
+]]></programlisting>
+
+        <para>이것은 본질적으로 앞의 것과 동일한 질의이지만, 이제 
+        <literal>ResultSetMetaData</literal>는 ID의 타입이 명시적으로 지정되어 있으므로 
+        NAME과 BIRTHDATE의 타입을 결정하는데 사용된다.</para>
+
+        <para>java.sql.Types returned from ResultSetMetaData이 Hibernate 
+                타입들로 매핑되는 방법은 Dialect에 의해 제어된다. 만일 특정 타입이 매핑되지 않거나 
+                예상되는 타입으로 귀결되지 않을 경우에 Dialect 내에 있는 
+        <literal>registerHibernateType</literal>에 대한 호출들을 통해 그것을 
+                맞춤화 시키는 것이 가능하다.</para>
+    </sect2>
+        
+    <sect2>
+      <title>Entity 질의들</title>
+
+      <para>위의 질의들은 스칼라 값들을 반환하는 것, 결과셋들로부터 "원래의" 값들을 
+            기본적으로 반환하는 것에 대한 전부였다. 다음은 <literal>addEntity()</literal>를 
+            통해 native sql 질의로부터 엔티티 객체들을 얻는 방법을 보여준다.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class);
+sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);
+]]></programlisting>
+
+        <para>이 질의는 다음을 지정했다:</para>
+        
+        <itemizedlist>
+        <listitem>
+          <para>SQL 질의 문자열</para>
+        </listitem>
+
+        <listitem>
+          <para>그 질의에 의해 반환되는 엔티티</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>Cat이 컬럼 ID, NAME 그리고 BIRTHDATE로서 매핑된다고 가정하면, 
+            위의 질의들은 둘다 각각의 요소가 하나의 Cat 엔티티인 하나의 List를 반환할 것이다.</para>
+
+      <para>만일 그 엔티티가 또 다른 엔티티에 대해 <literal>many-to-one</literal>로 
+            매핑되어 있다면 또한 native 질의를 실행할 때 이것을 반환하는 것이 필수적고, 그 밖의 경우 
+            데이터베이스 지정적인 "컬럼이 발견되지 않았습니다" 오류가 일어날 것이다. 추가적인 
+            컬럼은 * 표기를 사용할 자동적으로 반환될 것이지만, 우리는 다음 <literal>Dog</literal>에 
+            대한 <literal>many-to-one</literal> 예제에서처럼 명시적인 것을 더 선호한다:</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);
+]]></programlisting>
+
+      <para>이것은 cat.getDog()이 고유하게 기능하는 것을 허용한다.</para>
+    </sect2>
+
+    <sect2>
+      <title>연관들과 콜렉션들을 처리하기</title>
+
+      <para>프락시를 초기화 시킴에 있어 가능한 특별한 라운드트립을 피하기 위해서 
+      <literal>Dog</literal>에서 eagerly join시키는 것이 간으하다. 이것은 
+      <literal>addJoin()</literal> 메소드를 통해 행해지는데, 그것은 
+            연관이나 콜렉션 내에서 조인시키는 것을 당신에게 허용해준다.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dog");
+]]></programlisting>
+
+      <para>이 예제에서 반환되는 <literal>Cat</literal>들은 데이터베이스에 
+            대한 임의의 특별한 라운드크립 없이 전체적으로 초기화된 그것들의 <literal>dog</literal> 
+            프로퍼티를 갖는다. 우리가 join의 대상 프로퍼티 경로를 지정하는 것을 가능하도록 하기 위해 
+            하나의 alias 이름("cat")을 추가했음을 주지하라. 대신에 예를 들어 <literal>Cat</literal>이 
+      <literal>Dog</literal>에 대해 one-to-many를 가질 경우, 콜렉션들에 대해 동일한 eager joining을 
+            행하는 것이 가능하다.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dogs");
+]]></programlisting>
+
+      <p>이 단계에서 우리는 Hibernate에서 native 질의들을 사용가능하도록 만들기 위해 
+      sql 질의들을 강화시키지는 것을 시작하지 않고서도 native 질의들로서 가능한 것의 한계에 
+            도달하고 있다; 문제점들은 동일한 타입의 여러 엔티티들을 반환할 때 또는 디폴트 alias/column 
+            이름들이 충분하지 않을 때 발생하기 시작한다.</p>
+    </sect2>
+
+    <sect2>
+      <title>여러 개의 엔티티들을 반환하기</title>
+
+      <para>지금까지 결과 셋 컬럼 이름들은 매핑 문서 내에 지정된 컬럼 이름들과 동일하다고 가정되어 있다.
+            동일한 컬럼이 하나 이상의 테이블 내에서 나타날 수 있기 때문에, 이것은 여러 개의 테이블들을 조인시키는 
+      SQL 질의들에 대해 문제가 될 수 있다.</para>
+
+      <para>컬럼 alias 주입은 다음 질의(아마 실패할 것이다)에서 필요하다:</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT c.*, m.*  FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+]]></programlisting>
+
+      <para>이 질의의 목적은 단위 행 당 두 개의 Cat 인스턴스들, 하나의 cat 그리고 그것의 mother를 
+           반환하는 것이다. 왜냐하면 그것들이 동일한 컬럼 이름들로 매핑되어 있기 때문에 이것은 실패할 것이고 
+           데이베이스 상에서 반환된 컬럼 alias들은 아마 매핑들 내에 지정된 컬럼들("ID" 와 "NAME")과 같지 않은 
+      "c.ID", "c.NAME" 등의 형식일 것이다.</para>
+
+      <para>다음 형식은 컬럼 이름 중복 취약점을 갖지 않는다:</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT {cat.*}, {mother.*}  FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+]]></programlisting>
+
+      <para>이 질의는 다음을 지정했다:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>컬럼 alias들을 주입하기 위한 Hibernate용 placeholder들을 가진 SQL 질의 문자열</para>
+        </listitem>
+
+        <listitem>
+          <para>그 질의에 의해 반환되는 엔티티들</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>위에 사용된 {cat.*} 과 {mother.*} 표기는 "모든 프로퍼티들"에 대한 생략이다. 
+            다른 방법으로 당신은 컬럼들을 명시적으로 열거할 수도 있지만, 이 경우에 우리는 Hibernate로 하여금 
+      SQL 컬럼 alias들을 각각의 컬럼에 주입시키도록 강제한다. 컬럼 alias를 위한 placeholder는 단지
+            그 테이블 alias에 의해 수식된 프로퍼티 이름이다. 다음 예제에서, 우리는 다른 테이블(cat_log)로부터 
+           매핑 메타데이터 내에 선언된 것으로의 Cat들과 그것들의 mother들을 검색한다. 우리는 우리가 좋다면 
+           심지어 where 절 내에 프로퍼티 alias를 사용할 수도 있음을 주지하라.</para>
+
+      <programlisting><![CDATA[String sql = "SELECT ID as {c.id}, NAME as {c.name}, " + 
+         "BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
+         "FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
+
+List loggedCats = sess.createSQLQuery(sql)
+        .addEntity("cat", Cat.class)
+        .addEntity("mother", Cat.class).list()
+]]></programlisting>
+
+      <sect3 id="querysql-aliasreferences" revision="2">
+        <title>alias 참조와 프로퍼티 참조</title>
+
+        <para>대부분의 경우에 위의 alias 주입이 필요하지만, composite 프로퍼티들, 상속 판별자들
+        (inheritance discriminators), 콜렉션 등과 같은 보다 복잡한 매핑들과 관련된 질의들의 경우에는 
+                고유한 alias들을 주입시키는 것을 Hibernate에게 허용하는데 사용될 몇몇 특별한 alias들이 존재한다.</para>
+
+        <para>다음 테이블은 alias 주입을 사용하는 다른 가능성들을 보여준다. 노트: 결과 내에 있는 alias 이름들이 
+                예제이며, 각각의 alias는 사용될 때 하나의 유일한 이름과 아마 다른 이름을 가질 것이다.</para>
+                
+        <table frame="topbot" id="aliasinjection-summary">
+          <title>alias 주입 이름들</title>
+
+          <tgroup cols="3">
+            <colspec colwidth="1*" />
+
+            <colspec colwidth="1*" />
+
+            <colspec colwidth="2.5*" />
+
+            <thead>
+              <row>
+                <entry>설명</entry>
+
+                <entry>구문</entry>
+
+                <entry>예제</entry>
+              </row>
+            </thead>
+
+            <tbody>
+              <row>
+                <entry>간단한 프로퍼티</entry>
+                <entry><literal>{[aliasname].[propertyname]</literal></entry>
+                            
+                <entry><literal>A_NAME as {item.name}</literal></entry>                            
+              </row>
+
+              <row>
+                <entry>composite 프로퍼티</entry>
+                            
+                <entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
+                            
+                <entry><literal>CURRENCY as {item.amount.currency}, VALUE as {item.amount.value}</literal></entry>
+              </row>
+
+              <row>
+                <entry>엔티티의 판별자(Discriminator)</entry>
+                <entry><literal>{[aliasname].class}</literal></entry>
+                            
+                <entry><literal>DISC as {item.class}</literal></entry>
+              </row>
+
+              <row>
+                <entry>엔티티의 모든 프로퍼티들</entry>
+                <entry><literal>{[aliasname].*}</literal></entry>
+                            
+                <entry><literal>{item.*}</literal></entry>
+              </row>
+
+              <row>
+                <entry>콜렉션 키</entry>
+                <entry><literal>{[aliasname].key}</literal></entry>
+                            
+                <entry><literal>ORGID as {coll.key}</literal></entry>
+              </row>
+
+              <row>
+                <entry>콜렉션의 id</entry>
+                <entry><literal>{[aliasname].id}</literal></entry>
+                            
+                <entry><literal>EMPID as {coll.id}</literal></entry>
+              </row>
+
+              <row>
+                <entry>콜렉션의 요소</entry>
+                <entry><literal>{[aliasname].element}</literal></entry>
+                            
+                <entry><literal>XID as {coll.element}</literal></entry>
+                <entry></entry>
+              </row>
+
+              <row>
+                <entry>콜렉션 내에 있는 요소의 프로퍼티</entry>
+                <entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
+                            
+                <entry><literal>NAME as {coll.element.name}</literal></entry>
+              </row>
+
+              <row>
+                <entry>콜렉션 내에 있는 요소의 모든 프로퍼티들</entry>
+                <entry><literal>{[aliasname].element.*}</literal></entry>
+                            
+                <entry><literal>{coll.element.*}</literal></entry>
+              </row>
+
+              <row>
+                <entry>콜렉션의 모든 프로퍼티들</entry>
+                <entry><literal>{[aliasname].*}</literal></entry>
+                            
+                <entry><literal>{coll.*}</literal></entry>
+              </row>
+            </tbody>
+          </tgroup>
+        </table>
+      </sect3>
+    </sect2>
+
+    <sect2>
+      <title>non-managed 엔티티들을 반환하기</title>
+
+      <para>native sql 질의에 ResultTransformer를 적용하는 것이 가능하다. 예를 들어
+      non-managed 엔티티들을 반환하기 위해 ResultTransformer를 허용하는 것.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS")
+        .setResultTransformer(Transformers.aliasToBean(CatDTO.class))]]></programlisting>
+        
+              <para>이 질의는 다음을 지정했다:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>SQL 질의 문자열</para>
+        </listitem>
+
+        <listitem>
+          <para>결과 변환자(transformer)</para>
+        </listitem>
+      </itemizedlist>
+        
+        <para>
+                위의 질의는 초기화되어 있고 NAME과 BIRTHNAME의 값들을 <literal>CatDTO</literal>의 
+                대응하는 프로퍼티들과 필드들 속으로 주입시킨 <literal>CatDTO</literal>의 리스트를 반환할 것이다.
+        </para>
+    </sect2>
+
+    <sect2>
+      <title>상속 처리하기</title>
+
+      <para>상속의 부분으로서 매핑되는 엔티티들을 질의하는 native sql 질의들은 baseclass의 
+            모든 프로퍼티들을 포함해야 하고 그 모든 것이 서브클래스화 되어야 한다.</para>
+    </sect2>
+
+    <sect2>
+      <title>파라미터들</title>
+
+      <para>Native sql 질의들은 위치 파라미터들 뿐만 아니라 명명된 파라미터들을 지원한다:</para>
+
+      <programlisting><![CDATA[Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class);
+List pusList = query.setString(0, "Pus%").list();
+     
+query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like :name").addEntity(Cat.class);
+List pusList = query.setString("name", "Pus%").list();          ]]></programlisting>
+    </sect2>
+    
+    
+        
+    </sect1>
+
+    <sect1 id="querysql-namedqueries" revision="3">
+        <title>명명된 SQL 질의들</title>
+
+        <para>
+                        명명된 SQL 질의들은 HQL 질의와 동일한 방법으로 매핑 문서 속에 정의될 수 있고 정확하게 호출될 수도 있다. 이 경우에, 우리는 
+            <literal>addEntity()</literal> 호출을 필요로 하지 <emphasis>않는다</emphasis>.
+        </para>
+
+    <programlisting><![CDATA[<sql-query name="persons">
+    <return alias="person" class="eg.Person"/>
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex}
+    FROM PERSON person
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+    <programlisting><![CDATA[List people = sess.getNamedQuery("persons")
+    .setString("namePattern", namePattern)
+    .setMaxResults(50)
+    .list();]]></programlisting>
+
+    <para><literal>&lt;return-join&gt;</literal> 요소와 
+    <literal>&lt;load-collection&gt;</literal>
+        요소는 연관들을 조인시키고 콜렉션들을 각각 초기화 시키는 질의들을 
+        정의하는데 사용된다.</para>
+         
+    <programlisting><![CDATA[<sql-query name="personsWith">
+    <return alias="person" class="eg.Person"/>
+    <return-join alias="address" property="person.mailingAddress"/>
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex},
+           adddress.STREET AS {address.street},
+           adddress.CITY AS {address.city},
+           adddress.STATE AS {address.state},
+           adddress.ZIP AS {address.zip}
+    FROM PERSON person
+    JOIN ADDRESS adddress
+        ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+    <para>명명된 SQL 질의는 스칼라 값을 반환할수도 있다. 당신은 
+    <literal>&lt;return-scalar&gt;</literal> 요소를 사용하여 
+        컬럼 alias와 Hibernate 타입을 선언해야 한다:</para>
+        
+    <programlisting><![CDATA[<sql-query name="mySqlQuery">
+    <return-scalar column="name" type="string"/>
+    <return-scalar column="age" type="long"/>
+    SELECT p.NAME AS name,
+           p.AGE AS age,
+    FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
+</sql-query>]]></programlisting>
+
+        <para>당신은 여러 개의 명명된 질의들을 가로질러 재사용하거나 <literal>setResultSetMapping()</literal> API를 통해 결과셋 
+                매핑정보들을 재사용하기 위해 <literal>&lt;resultset&gt;</literal> 요소 속에 결과셋 매핑 정보들을 구체화 시킬 수 있다.</para>
+
+    <programlisting><![CDATA[<resultset name="personAddress">
+    <return alias="person" class="eg.Person"/>
+    <return-join alias="address" property="person.mailingAddress"/>
+</resultset>
+
+<sql-query name="personsWith" resultset-ref="personAddress">
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex},
+           adddress.STREET AS {address.street},
+           adddress.CITY AS {address.city},
+           adddress.STATE AS {address.state},
+           adddress.ZIP AS {address.zip}
+    FROM PERSON person
+    JOIN ADDRESS adddress
+        ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+    <para>다른방법으로 당신은 당신의 hbm 파일들 내에 직접 자바 코드로 된 결과셋 매핑 정보를 사용할 수 있다.</para>
+
+    <programlisting><![CDATA[List cats = sess.createSQLQuery(
+        "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
+    )
+    .setResultSetMapping("catAndKitten")
+    .list();]]></programlisting>
+
+    <sect2 id="propertyresults">
+      <title>명시적으로 column/alias 이름들을 지정하는데 return-property 사용하기</title>
+
+      <para>Hibernate로 하여금 그것 자신의 alias들을 끼워넣도록 하기 위해 
+      <literal>{}</literal>-구문을 사용하는 것 대신에, 
+      <literal>&lt;return-property&gt;</literal>로서 당신은 사용할 
+            컬럼 alias들이 무엇인지를 Hibernate에게 명시적으로 알려줄 수 있다.</para>
+             
+      <programlisting><![CDATA[<sql-query name="mySqlQuery">
+    <return alias="person" class="eg.Person">
+        <return-property name="name" column="myName"/>
+        <return-property name="age" column="myAge"/>
+        <return-property name="sex" column="mySex"/>
+    </return>
+    SELECT person.NAME AS myName,
+           person.AGE AS myAge,
+           person.SEX AS mySex,
+    FROM PERSON person WHERE person.NAME LIKE :name
+</sql-query>
+]]></programlisting>
+
+      <para><literal>&lt;return-property&gt;</literal>는 또한 다중 컬럼들에 대해 동작한다. 
+            이것은 다중-컬럼 프로퍼티들에 대한 fine grained 제어를 허용할 수 없는 
+      <literal>{}</literal>-구문을 가진 제약을 해결해준다.</para>
+
+      <programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
+    <return alias="emp" class="Employment">
+        <return-property name="salary">
+            <return-column name="VALUE"/>
+            <return-column name="CURRENCY"/>
+        </return-property>
+        <return-property name="endDate" column="myEndDate"/>
+    </return>
+        SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
+        STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+        REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
+        FROM EMPLOYMENT
+        WHERE EMPLOYER = :id AND ENDDATE IS NULL
+        ORDER BY STARTDATE ASC
+</sql-query>]]></programlisting>
+
+      <para>이 예제에서 우리는 끼워넣기(injection)를 위해 <literal>{}</literal>-구문과 함께 <literal>&lt;return-property&gt;</literal>를 
+            사용했음을 주목하라. 사용자들이 컬럼과 프로퍼티들을 참조하고자 원하는 방법을 선택하는 것을 사용자들에게 허용해줌으로써.</para>
+
+      <para>만일 당신의 매핑이 한 개의 판별자(discriminator )를 가질 경우 당신은 판별자 컬럼을 지정하는데 
+      <literal>&lt;return-discriminator&gt;</literal>를 사용해야 한다.</para>
+    </sect2>
+         
+    <sect2 id="sp_query" revision="1">
+      <title>질의를 위한 내장 프로시저 사용하기</title>
+
+      <para>Hibernate 3은 내장 프로시저들과 함수들을 통한 질의 지원을 도입한다. 대부분의 다음 문서는 양자 모두에 동일하게 적용된다.
+            내장 프로시저/함수는 Hibernate와 동작하는 것이 가능하도록 첫 번째 out-파라미터로서 한 개의 결과셋을 반환해야 한다.
+      Oracle9 이상의 버전에서 그런 내장 프로시저에 대한 예제는 다음과 같다:</para>
+
+      <programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
+    RETURN SYS_REFCURSOR
+AS
+    st_cursor SYS_REFCURSOR;
+BEGIN
+    OPEN st_cursor FOR
+ SELECT EMPLOYEE, EMPLOYER,
+ STARTDATE, ENDDATE,
+ REGIONCODE, EID, VALUE, CURRENCY
+ FROM EMPLOYMENT;
+      RETURN  st_cursor;
+ END;]]></programlisting>
+
+      <para>Hibernate에서 이 질의를 사용하기 위해 당신은 하나의 명명된 질의(a named query)를 통해 
+             그것을 매핑할 필요가 있다.</para>
+
+      <programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
+    <return alias="emp" class="Employment">
+        <return-property name="employee" column="EMPLOYEE"/>
+        <return-property name="employer" column="EMPLOYER"/>
+        <return-property name="startDate" column="STARTDATE"/>
+        <return-property name="endDate" column="ENDDATE"/>
+        <return-property name="regionCode" column="REGIONCODE"/>
+        <return-property name="id" column="EID"/>
+        <return-property name="salary">
+            <return-column name="VALUE"/>
+            <return-column name="CURRENCY"/>
+        </return-property>
+    </return>
+    { ? = call selectAllEmployments() }
+</sql-query>]]></programlisting>
+
+      <para>내장 프로시저들은 현재 스칼라들과 엔티티들 만을 반환함을 주목하라. <literal>&lt;return-join&gt;</literal>과 
+      <literal>&lt;load-collection&gt;</literal>은 지원되지 않는다.</para>
+
+      <sect3 id="querysql-limits-storedprocedures" revision="1">
+        <title>내장 프로시저들을 사용하는 규칙들/제약들</title>
+
+        <para>Hibernate에서 내장 프로시저들을 사용하기 위해서 프로시저들/함수들은 다음 몇몇 규칙들을 따라야 한다. 만일 그것들이 그들 규칙들을 
+                따르지 않을 경우 그것들은 Hibernate와 함께 사용 불가능하다. 만일 당신이 여전히 이들 프로시저들을 사용하고자 원할 경우, 
+                당신은 <literal>session.connection()</literal>을 통해 그것들을 실행시켜야 한다. 데이터베이스 벤더들이 다른 내장 
+                프로시저 의미론/구문을 갖고 있기 때문에, 규칙들은 각각의 데이터베이스에 따라 차이가 난다.</para>
+
+        <para>내장 프로시저 질의들은 <literal>setFirstResult()/setMaxResults()</literal>로서 쪽매김 될 수 없다.</para>
+
+        <para>권장되는 호출 형식은 표준 SQL92이다: <literal>{ ? = call
+        functionName(&lt;parameters&gt;) }</literal> 또는 <literal>{ ? = call
+        procedureName(&lt;parameters&gt;}</literal>. Native 호출 구문은 지원되지 않는다.</para>
+
+        <para>Oracle의 경우 다음 규칙들이 적용된다:</para>
+
+        <itemizedlist spacing="compact">
+          <listitem>
+            <para>하나의 함수는 하나의 결과 셋을 반환해야 한다. 프로시저의 첫 번째 파라미터는 하나의 결과 셋을 반환하는 
+                        하나의 <literal>OUT</literal>이어야 한다. 이것은 Oracle 9 또는 10에서 하나의 
+            <literal>SYS_REFCURSOR</literal>를 사용하여 행해진다. Oracle에서 당신은 
+            <literal>REF CURSOR</literal> 타입을 정의할 필요가 있는데, Oracle 보고서를 보라.</para>
+          </listitem>
+        </itemizedlist>
+
+        <para>Sybase 또는 MS SQL server의 경우 다음 규칙들이 적용된다:</para>
+
+        <itemizedlist spacing="compact">
+          <listitem>
+            <para>프로시저는 한 개의 결과 셋을 반환해야 한다. 이들 서버들이 여러 개의 결과셋들과 업데이트 카운트들을 반환 할수 있다/할 것이이므로, 
+            Hibernate는 결과들을 반복 순환할 것이고 그것의 반환 값으로서 하나의 결과 셋인 첫 번째 결과를 취할 것이다. 그 밖의 모든 것은 
+                        폐기될 것이다.</para>
+          </listitem>    
+          <listitem>
+            <para>만일 당신이 당신의 프로시저 내에 <literal>SET NOCOUNT ON</literal>을 이용 가능하게 할 수 있다면 그것은 아마 
+                        보다 효율적이게 될 것이지만 이것은 필요 조건이 아니다.</para>
+          </listitem>
+        </itemizedlist>
+      </sect3>
+    </sect2>
+  </sect1>
+
+  <sect1 id="querysql-cud">
+    <title>create, update 그리고 delete를 위한 맞춤형 SQL</title>
+
+    <para>Hibernate3는 create, update, delete 오퍼레이션들을 위한 맞춤형 문장들을 사용할 수 있다. Hibernate에서 클래스와 콜렉션 
+        영속자들은 구성 시에 생성된 문자열들의 집합(insertsql, deletesql, updatesql 등)을 이미 포함하고 있다. 
+    <literal>&lt;sql-insert&gt;</literal>, <literal>&lt;sql-delete&gt;</literal>, 
+    <literal>&lt;sql-update&gt;</literal> 매핑 태그들은 이들 문자열들을 오버라이드 시킨다:</para>
+
+    <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
+    <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
+    <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
+</class>]]></programlisting>
+
+    <para>SQL이 당신의 데이터베이스 내에서 직접 실행되어서, 당신이 좋아하는 임의의 dialect를 사용하는 것이 자유롭다. 만일 당신이 데이터베이스 
+        지정적인 SQL을 사용할 경우 이것은 물론 당신의 매핑의 이식성을 감소시킬 것이다.</para>
+
+    <para>만일 <literal>callable</literal> 속성이 설정되면 내장 프로시저들이 지원된다:</para>
+
+    <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
+    <sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
+    <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
+</class>]]></programlisting>
+
+    <para>위치 파라미터들은 Hibernate가 그것들을 기대하는 것과 같은 순서가 되어야 하므로, 
+        위치 파라미터들의 순서는 현재 절대적으로 중요하다.</para>
+
+    <para>당신은 <literal>org.hiberate.persister.entity</literal> 레벨로 디버그 로깅을 사용 가능하게 함으로써 예상된 순서를 볼 수 
+        있다. 이 레벨을 이용 가능하게 하면 Hibernate는 엔티티들을 생성시키고, 업데이트하고, 삭제하는데 사용되는 정적인 SQL을 출력할 것이다. 
+    (예상되는 결과를 보려면, Hibernate 생성된 정적인 sql을 오버라이드 시키게 매핑 파일들 속에 당신의 맞춤형 SQL을 포함시키지 않도록 염두에 
+        두라.)</para>
+
+    <para>Hibernate가 문장의 성공을 위해 몇몇 실행 시 체크들을 행하므로, 내장 프로시저들은 대부분의 경우들(읽기:다른 경우들 보다 그것을 더 잘 
+        행한다)에서 insert되고/업데이트되고/삭제된 행들의 개수를 반환하는데 필요하다. Hibernate는 항상 CUD 오퍼레이션들에 대한 숫자 
+        출력 파라미터로서 첫 번째 문장 파라미터를 등록시킨다:</para>
+
+    <programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
+    RETURN NUMBER IS
+BEGIN
+
+    update PERSON
+    set
+        NAME = uname,
+    where
+        ID = uid;
+
+    return SQL%ROWCOUNT;
+
+END updatePerson;]]></programlisting>
+  </sect1>
+
+  <sect1 id="querysql-load">
+    <title>로딩을 위한 맞춤형 SQL</title>
+
+    <para>당신은 또한 엔티티 로딩을 위한 당신 자신의 SQL (또는 HQL)을 선언할 수도 있다:</para>
+
+    <programlisting><![CDATA[<sql-query name="person">
+    <return alias="pers" class="Person" lock-mode="upgrade"/>
+    SELECT NAME AS {pers.name}, ID AS {pers.id}
+    FROM PERSON
+    WHERE ID=?
+    FOR UPDATE
+</sql-query>]]></programlisting>
+
+    <para>이것은 앞서 논의했듯이 단지 명명된 질의 선언이다. 당신은 class 매핑 속에 이 명명된 질의를 참조할 수 있다:</para>
+
+    <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <loader query-ref="person"/>
+</class>]]></programlisting>
+    
+    <para>이것은 심지어 내장 프로시저들에 동작한다.</para>
+
+    <para>당신은 콜렉션 로딩을 위한 한 개의 질의를 정의할 수도 있다:</para>
+
+    <programlisting><![CDATA[<set name="employments" inverse="true">
+    <key/>
+    <one-to-many class="Employment"/>
+    <loader query-ref="employments"/>
+</set>]]></programlisting>
+
+    <programlisting><![CDATA[<sql-query name="employments">
+    <load-collection alias="emp" role="Person.employments"/>
+    SELECT {emp.*}
+    FROM EMPLOYMENT emp
+    WHERE EMPLOYER = :id
+    ORDER BY STARTDATE ASC, EMPLOYEE ASC
+</sql-query>]]></programlisting>
+
+    <para>당신은 심지어 조인 페칭에 의해 하나의 콜렉션을 로드시키는 하나의 엔티티를 정의할 수 있다:</para>
+
+    <programlisting><![CDATA[<sql-query name="person">
+    <return alias="pers" class="Person"/>
+    <return-join alias="emp" property="pers.employments"/>
+    SELECT NAME AS {pers.*}, {emp.*}
+    FROM PERSON pers
+    LEFT OUTER JOIN EMPLOYMENT emp
+        ON pers.ID = emp.PERSON_ID
+    WHERE ID=?
+</sql-query>]]></programlisting>
+  </sect1>
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/quickstart.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/quickstart.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/quickstart.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,572 @@
+<chapter id="quickstart">
+    <title>Tomcat으로 빠른 시작</title>
+
+    <sect1 id="quickstart-intro" revision="2">
+        <title>Hibernate 시작하기</title>
+
+        <para>
+                        이 튜토리얼은 웹 기반의 어플리케이션 용 Apache Tomcat 서블릿 컨테이너에 대한 Hibernate 3.0 셋업을 
+                        설명한다(우리는 버전 4.1을 사용했다. 5.0에 대한 차이점들은 적을 것이다). Hibernate는 모든 주요 J2EE 
+                        어플리케이션 서버들의 관리되는 환경에서 잘 동작하고, 또는 심지어 스탠드얼론 어플리케이션들에서도 잘 동작
+                        한다. 이 튜토리얼에 사용되는 데이터베이스 시스템은  PostgreSQL 7.4이고, 다른 데이터베이스에 대한 지원은  
+                        단지 Hibernate SQL dialect 구성과 커넥션 프로퍼티들을 변경시키는 것에만 관계된다.
+        </para>
+
+        <para>
+                        먼저 우리는 모든 필수적인 라이브러리들을 Tomcat 설치 장소에 복사해야 한다. 우리는 이 튜토리얼을 위해 별도의 
+                        웹 컨텍스트(<literal>webapps/quickstart</literal>)를 사용하며, 따라서 우리는 전역 라이브러리 검색 경로
+            (<literal>TOMCAT/common/lib</literal>)와  <literal>webapps/quickstart/WEB-INF/lib</literal>
+            (JAR 파일들의 경우)와 <literal>webapps/quickstart/WEB-INF/classes</literal> 내 에 있는 컨텍스트 
+                        레벨에서 클래스로더 양자를 고려해야 한다. 우리는 두 개의 클래스로더 레벨들을 전역 classpath와  컨텍스트 
+            classpath로서 언급한다. 
+        </para>
+
+        <para>
+                        이제 라이브러리들을 두 개의 classpath들에 복사하라:
+        </para>
+
+        <orderedlist>
+            <listitem>
+                <para>
+                                        데이터베이스 용 JDBC 드라이버를 전역 classpath로 복사하라. 이것은 Tomcat에 번들로구성된 DBCP 커넥션 
+                                        풀 소프트웨어에 필요하다. Hibernate는 데이터베이스 상에서 SQL을 실행시키는데 JDBC 커넥션들을 사용하므로, 
+                                        당신은 풀링된 JDBC 커넥션들을 제공해야 하거나, 직접 지원되는 풀들(C3P0, Proxool) 중 하나를 사용하기 
+                                        위해 Hibernate를 구성해야 한다. 이 튜토리얼을 위해, (PostgreSQL 7.4와 JDK 1.4용) <literal>pg74jdbc3.jar</literal> 
+                                        라이브러리를 전역 classloaders 경로로 복사하라. 만일 당신이 다른 데이터베이스를 사용하고자 원할 경우, 
+                                        간단하게 그것의 적절한 JDBC 드라이버를 복사하라.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        그 밖의 어떤 것을 Tomcat 내의 전역 클래스로더 경로에 복사하지 말라. 또는 당신은 Log4j, commons-logging 
+                                        그리고 다른 것들을 포함하는 여러 가지 도구들에 관련된 문제점들을 얻게 될 것이다. 각각의 웹 어플리케이션에 대해 
+                                        컨텍스트 classpath를 사용하라. 즉 라이브러리들을  <literal>WEB-INF/lib</literal>에 복사하고, 당신 자신의 클래스들과 
+                                        구성 파일들/프로퍼티 파일들을 <literal>WEB-INF/classes</literal>에 복사하라. 두 디렉토리들 양자는 디폴트로 컨텍스트 
+                    classpath 내에 있다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Hibernate는 JAR 라이브러리로서 패키지화 되어 있다. <literal>hibernate3.jar</literal> 파일은 어플리케이션의 다른 클래스들과 
+                                        함께 컨텍스트 classpath 속에 복사되어야 한다. Hibernate는 실행 시에 어떤 제 3의 라이브러리들을 필요로하고, 
+                                        이것들은 <literal>lib/</literal> 디렉토리 내의 Hibernate 배포본에 번들화되어 있다; <xref linkend="3rdpartylibs"/>를 
+                                        보라. 필요한 제3의 라이브러리들을 컨텍스트 classpath로 복사하라.
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <table frame="topbot" id="3rdpartylibs">
+            <title>
+                Hibernate 제3의 라이브러리
+            </title>
+            <tgroup cols="2" rowsep="1" colsep="1">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="2*"/>
+                <thead>
+                    <row>
+                        <entry align="center">
+                                                        라이브러리
+                        </entry>
+                        <entry align="center">
+                                                        설명
+                        </entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            antlr (필수)
+                        </entry>
+                        <entry>
+                            Hibernate는 질의 파서들을 산출하는데 ANTLR을 사용하고, 이 라이브러리는 또한 
+                                                        실행 시에 필요하다.
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            dom4j (필수)
+                        </entry>
+                        <entry>
+                            Hibernate는 XML 구성과 XML 매핑 메타데이터 파일들을 파싱하는데 dom4j를 사용
+                                                        한다.
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            CGLIB, asm (필수)
+                        </entry>
+                        <entry>
+                            Hibernate는 (Java reflection과 결합하여) 런타임 시에 클래스들을  고양시키는데 
+                                                        코드 생성 라이브러리를 사용한다.
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            Commons Collections, Commons Logging (필수)
+                        </entry>
+                        <entry>
+                            Hibernate는 Apache Jakarta Commons 프로젝트로부터 다양한 유틸리티 라이브러리
+                                                        들을 사용한다.
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            EHCache (필수)
+                        </entry>
+                        <entry>
+                            Hibernate는 second-level 캐시를 위한 다양한 캐시 프로바이더들을 사용할 수 있다. 
+                                                        만일 구성에서 변하지 않을 경우 EHCache가 디폴트 캐시 프로바이더이다.
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            Log4j (옵션)
+                        </entry>
+                        <entry>
+                            Hibernate는 기본 로깅 메커니즘으로서 Log4j를 사용할 수 있는, Commons Logging 
+                            API를 사용한다. 만일 Log4j 라이브러리가 컨텍스트 라이브러리 디렉토리 속에서 이용
+                                                        가능하다면, Commons Logging은 Log4j와 컨텍스트 classpath 내에 있는 <literal>log4j.properties</literal> 
+                                                        구성을 사용할 것이다.  Log4j에 대한 예제 properties 파일은 Hibernate 배포본에 
+                                                        번들화 되어 있다. 따라서 당신이 이면에서 무엇이 진행되는 지을 보고자 원할 경우에 log4j.jar와 
+                            (<literal>src/</literal>에 있는) 구성 파일을 당신의 컨텍스트 classpath 속으로 복사하라.
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                                                        필수 여부?
+                        </entry>
+                        <entry>
+                            Hibernate 배포본 내에 있는 <literal>lib/README.txt</literal> 파일을 살펴보라. 
+                                                        이것은 Hibernate에 배포된 제 3의 라이브러리들의 최신 목록이다. 당신은 그곳에 열거된 
+                                                        모든 필수 라이브러리들과 옵션 라이브러리들을 찾게 될 것이다(여기서 "빌드 시 필요함"은 
+                                                        당신의 어플리케이션이 아니라 Hibernate에 대한 의미임을 노트하라). 
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+                        우리는 이제 Tomcat과 Hibernate 양자에서 데이터베이스 커넥션 풀링과 공유를 설정한다. 이것은 Tomcat이 
+            (그것의 미리 빌드되어 있는 DBCP 풀링 특징을 사용하여) 풀링된 JDBC 커넥션들을 제공할 것이고, Hibernate가 
+            JNDI를 통해 이들 커넥션들을 요청한다는 것을 의미한다. 달리 당신은 Hibernate로 하여금 커넥션 풀을 관리하도록 
+                        할 수 있다. Tomcat은 그것의 커넥션 풀을 JNDI에 바인드 시킨다; 우리는 리소스 선언을 Tomcat 메인 구성 파일인 
+            <literal>TOMCAT/conf/server.xml</literal>에 추가한다:
+        </para>
+
+        <programlisting><![CDATA[<Context path="/quickstart" docBase="quickstart">
+    <Resource name="jdbc/quickstart" scope="Shareable" type="javax.sql.DataSource"/>
+    <ResourceParams name="jdbc/quickstart">
+        <parameter>
+            <name>factory</name>
+            <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
+        </parameter>
+
+        <!-- DBCP database connection settings -->
+        <parameter>
+            <name>url</name>
+            <value>jdbc:postgresql://localhost/quickstart</value>
+        </parameter>
+        <parameter>
+            <name>driverClassName</name><value>org.postgresql.Driver</value>
+        </parameter>
+        <parameter>
+            <name>username</name>
+            <value>quickstart</value>
+        </parameter>
+        <parameter>
+            <name>password</name>
+            <value>secret</value>
+        </parameter>
+
+        <!-- DBCP connection pooling options -->
+        <parameter>
+            <name>maxWait</name>
+            <value>3000</value>
+        </parameter>
+        <parameter>
+            <name>maxIdle</name>
+            <value>100</value>
+        </parameter>
+        <parameter>
+            <name>maxActive</name>
+            <value>10</value>
+        </parameter>
+    </ResourceParams>
+</Context>]]></programlisting>
+
+        <para>
+                        우리가 이 예제에서 구성하는 컨텍스트는 <literal>quickstart</literal>로 명명되고, 그것의 베이스는 
+            <literal>TOMCAT/webapp/quickstart</literal> 디렉토리이다. 임의의 서블릿들에 접근하기 위해, 
+            (물론 당신의 <literal>web.xml</literal> 속에 매핑된 서블릿의 이름을 추가하여) 당신의 브라우저에서 
+            <literal>http://localhost:8080/quickstart</literal> 경로를 호출하라. 당신은 또한 계속 진행하고 
+                        이제 공백의 <literal>process()</literal> 메소드를 가진 간단한 서블릿을 생성시킬 수 있다.
+        </para>
+
+        <para>
+            Tomcat은 이제 <literal>java:comp/env/jdbc/quickstart</literal>로 JNDI을 통해 커넥션들을 제공한다. 
+                        만일 당신이 실행 중인 커넥션 풀을 얻는 것에 문제가 있다면 Tomcat 문서를 참조하라. 당신이 JDBC 드라이버 예외상황 
+                        메시지를 얻을 경우, 먼저 Hibernate 없이 JDBC 커넥션 풀을 셋업하라. Tomcat &amp; JDBC 튜토리얼들은 
+                        그 웹 서이트에서 이용 가능하다.
+        </para>
+
+        <para>
+                        당신의 다음 단계는 Hibernate를 구성하는 것이다. Hibernate는 그것이 JDBC 커넥션들을 얻는 방법을 알고 있어야 한다. 
+                        우리는 Hibernate의 XML 기반 구성을 사용한다.  properties 파일을 사용하는 다른 접근법은 거의 동일하지만 XML 
+                        구문이 허용하는 몇몇 특징들을 누락하고 있다.  XML 구성 파일은 <literal>hibernate.cfg.xml</literal>로서 
+                        컨텍스트 classpath (<literal>WEB-INF/classes</literal>) 내에  위치해 있다:
+        </para>
+
+        <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+    "-//Hibernate/Hibernate Configuration DTD//EN"
+    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <session-factory>
+
+        <property name="connection.datasource">java:comp/env/jdbc/quickstart</property>
+        <property name="show_sql">false</property>
+        <property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
+
+        <!-- Mapping files -->
+        <mapping resource="Cat.hbm.xml"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+                        우리는 SQL 명령들에 대한 로깅을 사용하지 않고 Hibernate에게 사용되는 데이터베이스 SQL direct가 무엇인지 
+                        그리고 (Tomcat 바인드된 풀의 JNDI 주소를 선언하여) JDBC 커넥션들을 얻는 곳을 알려준다. dialect는 
+                        필수적인 설정이고, 데이터베이스들은 SQL "표준"에 대한 그것들의 해석을 달리한다. Hibernate는 차이점들을 
+                        처리하고 모든 주요 상용 데이터베이스들 및 오픈 소스 데이터베이스들 용도의 direct들을 번들로 포함하고 있다.
+        </para>
+
+        <para>
+            <literal>SessionFactory</literal>는 단일 데이터저장소에 관한 개념이고, 여러 데이터베이스들은 여러 
+                        개의 XML 구성 파일들을  생성시키고 당신의 어플리케이션 속에서 여러 개의 <literal>Configuration</literal> 
+                        및 <literal>SessionFactory</literal> 객체들을 생성시켜서 사용될 수 있다. 
+        </para>
+
+        <para>
+            <literal>hibernate.cfg.xml</literal>의 마지막 요소는 영속 클래스 <literal>Cat</literal>에 대한 
+            Hibernate XML 매핑 파일의 이름으로써 <literal>Cat.hbm.xml</literal>을 선언한다. 이 파일은 데이터베이스 
+                        테이블(또는 테이블들)로 POJO 클래스 <literal>Cat</literal> 을 매핑시키는 메타데이터를 포함한다. 우리는 
+                        곧 그 파일로 되돌아 갈 것이다. 먼저 POJO 클래스를 작성하고 그런 다음 그것을 위한 매핑 메타데이터를 선언하자.
+        </para>
+
+    </sect1>
+
+    <sect1 id="quickstart-persistentclass" revision="1">
+        <title>첫 번째 영속 클래스</title>
+
+        <para>
+            Hibernate는 영속 클래스들에 대한 Plain Old Java Objects (POJOs, 종종 Plain Ordinary Java Objects로 
+                        명명된다) 프로그래밍 모형으로 가장 잘 동작한다.  POJO는 공용으로 가시적인 인터페이스로부터 내부적인 표상을 은폐시켜, 
+            getter와 setter 메소드들을 통해 접근가능한 클래스들의 프로퍼티들을 가진 자바빈과 꽤 유사하다(필요하다면 Hibernate는 
+                        또한 필드들에 직접 접근할 수 있다):
+        </para>
+
+        <programlisting><![CDATA[package org.hibernate.examples.quickstart;
+
+public class Cat {
+
+    private String id;
+    private String name;
+    private char sex;
+    private float weight;
+
+    public Cat() {
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    private void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public char getSex() {
+        return sex;
+    }
+
+    public void setSex(char sex) {
+        this.sex = sex;
+    }
+
+    public float getWeight() {
+        return weight;
+    }
+
+    public void setWeight(float weight) {
+        this.weight = weight;
+    }
+
+}]]></programlisting>
+
+        <para>
+            Hibernate는 그것의 프로퍼티 타입들의 사용에 제약되지 않고, 자바 콜렉션 프레임웍에서의 클래스들을 포함하여, 모든 
+                        자바 JDK 타입들과 (<literal>String</literal>, <literal>char</literal>와 <literal>Date</literal> 
+                        같은) 원시타입들이 매핑될 수 있다. 당신은 그것을 값들로서, 값들을 가진 콜렉션들로서, 또는 다른 엔티티들에 대한 
+                        연관들로서 매핑시킬 수 있다.  <literal>id</literal>는 그 클래스의 데이터베이스 식별자(프라이머리 키)를 표현하는 
+                        특별한 프로퍼티이고, 그것은 <literal>Cat</literal>과 같은 엔티티들에 대해 매우 권장된다. Hibernate는 내부적으로만 
+                        식별자들을 사용할 수 있지만, 우리는 우리의 어플리케이션 아키텍처에서 어떤 유연성을 상실하게 될 것이다.
+        </para>
+
+        <para>
+                        특정 인터페이스는 영속 클래스들에 대해 구현되지 말아야 하거나 특정 루트 영속 클래스로부터 서브 클래스로 만들지 말아야 한다. 
+            Hibernate는 또한 바이트 코드 처리와 같은, 어떤 빌드 시 처리를 필요로 하지 않고, 그것은 오직 자바 reflection과 
+            (CGLIB를 통한) 런타임 클래스 고양에만 의존한다. 따라서 Hibernate에 대한 POJO 클래스의 어떤 의존성 없이도, 우리는 
+                        그것을 데이터베이스 테이블로 매핑할 수 있다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="quickstart-mapping" revision="2">
+        <title>cat 매핑하기</title>
+
+        <para>
+            <literal>Cat.hbm.xml</literal> 매핑파일은 객체/관계형 매핑에 필요한 메타데이터를 포함한다. 메타데이터는 영속 
+                        클래스들의 선언과 데이터베이스 테이블들에 대한 (컬럼들과 다른 엔티티들에 대한 foreign 키 관계들에 대한) 프로퍼티들의 
+                        매핑을 포함한다.
+        </para>
+
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+
+    <class name="org.hibernate.examples.quickstart.Cat" table="CAT">
+
+        <!-- A 32 hex character is our surrogate key. It's automatically
+            generated by Hibernate with the UUID pattern. -->
+        <id name="id" type="string" unsaved-value="null" >
+            <column name="CAT_ID" sql-type="char(32)" not-null="true"/>
+            <generator class="uuid"/>
+        </id>
+
+        <!-- A cat has to have a name, but it shouldn' be too long. -->
+        <property name="name">
+            <column name="NAME" length="16" not-null="true"/>
+        </property>
+
+        <property name="sex"/>
+
+        <property name="weight"/>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+                        모든 영속 클래스는 식별자 속성을 가져야 한다(실제로 value-타입의 클래스들에 의존하지 않는, 엔티티들을 표현하는 유일한 
+                        클래스들은 엔티티을 가진 컴포넌트들로 매핑된다). 이 프로퍼티는 영속 객체들을 구별짓는데 사용된다: 만일 
+            <literal>catA.getId().equals(catB.getId())</literal>가 true일 경우, 두 개의 cat들은 같고, 이 개념은 
+            <emphasis>database identity</emphasis>로 명명된다.  Hibernate는 (데이터베이스 시퀀스, hi/lo 식별자 테이블들, 
+                        그리고 어플리케이션 할당 식별자들에 대한 native 생성기들을 포함하는) 다른 시나리오들에 대해 여러 가지 식별자 생성기들을 
+                        번들로 갖고 있다. 우리는 UUID 생성기(데이터이스에 의해 생성된 정수 대용 키들이 선호될 것이므로, 테스트용으로만 권장됨)를 
+                        사용하고 또한  Hibernate 생성된 식별자 값을 위한 <literal>CAT</literal> 테이블의 <literal>CAT_ID</literal> 
+                        컬럼을 (테이블의 프라이머리 키로서) 지정한다.
+        </para>
+
+        <para>
+            <literal>Cat</literal>의 모든 다른 프로퍼티들은 동일한 테이블로 매핑된다. <literal>name</literal> 프로퍼티의 경우에, 
+                        우리는 그것을 명시적인 데이터베이스 컬럼 선언으로 매핑시켰다. 데이터베이스 스키마가 Hibernate의 <emphasis>SchemaExport</emphasis> 
+                        도구에 의해 매핑 선언으로부터 (SQL DDL 문장들로) 자동적으로 생성될 때 이것이 특별히 유용하다. 모든 다른 프로퍼티들은 
+            Hibernate의 디폴트 설정들을 사용하여 매핑되고, 디폴트 설정들은 당신이 가장 많은 시간을 필요로 하는 것이다. 데이터베이스 
+                        내의 테이블 <literal>CAT</literal>은 다음과 같다:
+        </para>
+
+        <programlisting><![CDATA[ Column |         Type          | Modifiers
+--------+-----------------------+-----------
+ cat_id | character(32)         | not null
+ name   | character varying(16) | not null
+ sex    | character(1)          |
+ weight | real                  |
+Indexes: cat_pkey primary key btree (cat_id)]]></programlisting>
+
+        <para>
+                        당신은 이제 수작업으로 당신의 데이터베이스 내에 이 테이블을 생성시킬 것이고, 만일 당신이 <literal>hbm2ddl</literal> 
+                        도구로 이 단계를 자동화 시키고자 원할 경우 <xref linkend="toolsetguide"/>를 읽어라. 이 도구는 테이블 정의, 맞춤형 
+                        컬럼 타입 컨스트레인트들, 유일 컨스트레인트들과 인덱스들을 포함하는, 전체 SQL DDL을 생성시킬 수 있다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="quickstart-playingwithcats" revision="3">
+        <title>cat들에 작업하기</title>
+
+        <para>
+                        우리는 이제 Hibernate의 <literal>Session</literal>을 시작할 준비가 되어 있다. 그것은  <emphasis>persistence manager</emphasis>
+            (영속 관리자)이고, 우리는 데이터베이스로 <literal>Cat</literal>들을 저장하고 데이터베이스로부터 
+            <literal>Cat</literal>들을 검색하는데 그것을 사용한다. 그러나 먼저 우리는 <literal>SessionFactory</literal>로부터 
+            <literal>Session</literal>(Hibernate의 작업 단위)를 얻어야 한다: 
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sessionFactory =
+            new Configuration().configure().buildSessionFactory();]]></programlisting>
+
+        <para>
+            <literal>configure()</literal> 호출은 <literal>hibernate.cfg.xml</literal> 구성 파일을 로드시키고  
+            <literal>Configuration</literal> 인스턴스를 초기화 시킨다. 당신이 SessionFactory(불변적임)를 빌드하기 
+            <emphasis>이전에</emphasis> 당신은 <literal>Configuration</literal>에 접근함으로써 다른 프로퍼티들을 
+                        설정할 수 있다(그리고 심지어 매핑 메타데이터를 변경시킬 수 있다). 우리는 어디서 <literal>SessionFactory</literal>를 
+                        생성시키고 우리의 어플리케이션 속에서 어떻게 그것에 접근할 수 있나?
+        </para>
+
+        <para>
+			<literal>SessionFactory</literal>는 대개 오직 한번만, 예를 들어 대개 <emphasis>load-on-startup</emphasis> 
+                        서블릿으로 시작 시에 빌드된다. 이것은 또한 당신이 당신의 서블릿들 내에 있는 인스턴스 변수 속에 그것을 유지하지 않을 것이지만 
+                        어떤 다른 위치에 유지시킬 것임을 의미한다. 더구나 우리는 어떤 종류의 <emphasis>Singleton</emphasis>을 필요로 하며, 
+                        따라서 우리는 어플리케이션 코드로 쉽게 <literal>SessionFactory</literal>에 액세스 할 수 있다. 다음에 보여진 접근법은 
+                        두 문제 모두를 해결한다: 시작 구성과 <literal>SessionFactory</literal>에 대한 쉬운 접근.
+		</para>
+
+		<para>
+                        우리는 <literal>HibernateUtil</literal> helper 클래스를 구현한다: 
+		</para>
+
+		<programlisting><![CDATA[import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+    private static Log log = LogFactory.getLog(HibernateUtil.class);
+
+    private static final SessionFactory sessionFactory;
+
+    static {
+        try {
+            // Create the SessionFactory
+            sessionFactory = new Configuration().configure().buildSessionFactory();
+        } catch (Throwable ex) {
+            // Make sure you log the exception, as it might be swallowed
+            log.error("Initial SessionFactory creation failed.", ex);
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    public static final ThreadLocal session = new ThreadLocal();
+
+    public static Session getCurrentSession() {
+        Session s = (Session) session.get();
+        // Open a new Session, if this Thread has none yet
+        if (s == null) {
+            s = sessionFactory.openSession();
+            session.set(s);
+        }
+        return s;
+    }
+
+    public static void closeSession() {
+        Session s = (Session) session.get();
+        if (s != null)
+            s.close();
+        session.set(null);
+    }
+}]]></programlisting>
+
+        <para>
+                        이 클래스는 static 초기자를 가진 <literal>SessionFactory</literal>를 처리할 뿐만 아니라 또한 현재의 쓰레드를 
+                        위한 <literal>Session</literal>을 소유하는 <literal>ThreadLocal</literal> 변수를 갖는다. 이 helper를 
+                        사용하려고 시도하기 전에 thread-local 변수에 대한 자바 개념을 이해해야 한다. 보다 복잡하고 강력한 <literal>HibernateUtil</literal> 
+                        클래스는  http://caveatemptor.hibernate.org/의 <literal>CaveatEmptor</literal>에서 찾을 수 있다.
+        </para>
+
+        <para>
+            <literal>SessionFactory</literal>는 threadsafe이고, 많은 쓰레드들이 동시에 그것에 접근할 수 있고 
+            <literal>Session</literal>들을 요청할 수 있다. 하나의 <literal>Session</literal>은 데이터베이스에 대해 
+                        한 개의 단위 작업을 나타내는 non-threadsafe 객체이다. <literal>Session</literal>들은 <literal>SessionFactory</literal>
+                        로부터 열려지고 모든 작업이 완료될 때 닫혀진다. 당신의 서블릿의 <literal>process()</literal> 메소드 내에 있는 
+                        예제는 다음과 같을 수 있다(예외상황 처리 없이): 
+        </para>
+
+        <programlisting><![CDATA[Session session = HibernateUtil.getCurrentSession();
+Transaction tx = session.beginTransaction();
+
+Cat princess = new Cat();
+princess.setName("Princess");
+princess.setSex('F');
+princess.setWeight(7.4f);
+
+session.save(princess);
+
+tx.commit();
+HibernateUtil.closeSession();]]></programlisting>
+
+        <para>
+                        하나의 <literal>Session</literal> 내에서 모든 데이터베이스 오퍼레이션은 데이터베이스 오퍼레이션들(심지어 읽기 전용 
+                        오퍼레이션들 조차도)을 격리시키는 하나의 트랜잭션 내부에서 발생한다. 우리는 기본 트랜잭션 방도(우리의 경우, JDBC 
+                        트랜잭션들)로부터 추상화시키는데 Hibernates <literal>Transaction</literal> API 를 사용한다. 이것은 우리의 
+                        코드가 임의의 변경들 없이도 (JTA를 사용하는) 컨테이너-관리되는 트랜잭션들에 배치되는 것을 허용해준다.
+        </para>
+
+        <para>
+                        당신이 원하는 만큼 당신이 <literal>HibernateUtil.getCurrentSession();</literal>을 호출할 수 있고, 당신은 
+                        이 쓰레드의 현재 <literal>Session</literal>을 항상 얻을 것임을 노트하라. 당신은 서블릿 코드 내에서든 또는 서블릿 필터 
+                        내에서든 HTTP response가 전송되기 전에, 당신의 단위 작업이 완료된 후에 <literal>Session</literal>이 확실히 
+                        닫혀지도록 해야 한다. 두 번째 옵션의 좋은 측면은 쉬운 lazy 초기화이다: 뷰가 렌더링 될 때 <literal>Session</literal>이 
+                        여전히 열려져 있어서, Hibernate는 당신이 현재 객체 그래프를 네비게이트 하는 동안 초기화 되지 않은 객체들을 로드시킬 수 있다.
+        </para>
+
+        <para>
+            Hibernate는 데이터베이스로부터 객체들을 검색하는데 사용될 수 있는 다양한 메소드들을 갖고 있다. 가장 유연한 방법은 Hibernate 
+            Query Language (HQL)을 사용하는 것이다. Hibernate Query Language (HQL)은 배우기가 쉽고 SQL에 대한 강력한 객체 지향 
+                        확장이다:
+        </para>
+
+        <programlisting><![CDATA[Transaction tx = session.beginTransaction();
+
+Query query = session.createQuery("select c from Cat as c where c.sex = :sex");
+query.setCharacter("sex", 'F');
+for (Iterator it = query.iterate(); it.hasNext();) {
+    Cat cat = (Cat) it.next();
+    out.println("Female Cat: " + cat.getName() );
+}
+
+tx.commit();]]></programlisting>
+
+        <para>
+            Hibernate는 또한 type-safe 질의들을 공식화 시키는데 사용될 수 있는 객체-지향 <emphasis>query by criteria</emphasis> 
+            API을 제공한다. 물론 Hibernate는 데이터베이스와의 모든 SQL 통신을 위해 <literal>PreparedStatement</literal>들과 
+                        파라미터 바인딩을 사용한다. 당신은 또한 Hibernate 직접적인 SQL 질의 특징을 사용할 수도 있거나 드문 경우에 
+            <literal>Session</literal>으로부터 plain JDBC 커넥션을 얻을 수도 있다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="quickstart-summary" revision="1">
+        <title>마지막으로</title>
+
+        <para>
+                        우리는 이 작은 튜토리얼 내에서 단지 Hibernate의 표면을 훑기만 했다. 우리는 우리의 예제들 속에 어떤 서블릿 지정적 코드를 
+                        포함하지 않음을 노트하라. 당신이 적합한지를 알려고 할 때 당신은 당신 자신의 서블릿을 생성시켜야 하고 Hibernate 코드를 
+                        삽입해야 한다.
+        </para>
+
+        <para>
+                        데이터 접근 계층으로서 Hibernate는 당신의 어플리케이션에 강하게 통합됨을 염두에 두라. 대개 모든 다른 레이어들은 영속 
+                        메커니즘에 의존했다. 당신은 이 설계의 함축을 확실히 이해하도록 하라.
+        </para>
+
+        <para>
+                        보다 복잡한 어플리케이션 예제는 http://caveatemptor.hibernate.org/ 를 보고 http://caveatemptor.hibernate.org/에 
+                        있는 다른 튜토리얼들을 살펴보라.
+        </para>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/session_api.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/session_api.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/session_api.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1136 @@
+<chapter id="objectstate">
+    <title>객체들로 작업하기</title>
+
+    <para>
+        Hibernate는 기본 데이터베이스 관리 시스템의 상세로부터 개발자들을 은폐시켜줄 뿐만 아니라, 또한 객체들에 대한 
+        <emphasis>상태 관리</emphasis>를 제공하는 하나의 완전한 객체/관계형 매핑 솔루션이다. 이것은 공통적인 
+        JDBC/SQL 영속 계층들 내에서의 SQL <literal>문장들</literal>에 대한 관리와는 반대로, 자바 어플리케이션들에서 
+                영속에 관한 매우 고유한 객체-지향적 관점이다.
+    </para>
+
+    <para>
+                달리 말해, Hibernate 어플리케이션 개발자들은 그들의 객체들의 <emphasis>상태</emphasis>에 대해 항상 생각해야 하고, 
+        SQL 문장들의 실행에 대해서는 필수적이지 않다. 이 부분은 Hibernate에 의해 처리되고 시스템의 퍼포먼스를 튜닝할 때 
+                어플리케이션 개발자와 유일하게 관련된다.
+    </para>
+
+    <sect1 id="objectstate-overview">
+        <title>Hibernate 객체 상태들</title>
+
+        <para>
+            Hibernate 다음 객체 상태들을 정의하고 지원한다:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>Transient</emphasis> - 만일 객체가 <literal>new</literal> 연산자를 사용하여 방금 초기화 되었다면 
+                                        객체는 transient이고, 그것은 Hibernate <literal>Session</literal>과 연관되어 있지 않다. 그것은 데이터베이스 
+                                        내에서 영속 표상을 갖지 않고 식별자 값이 할당되지 않았다. 만일 어플리케이션이 더 이상 참조를 소유하지 않을 경우 
+                    transient 인스턴스들은 쓰레기 수집기에 의해 파괴될 것이다. 객체를 영속화 시키는데
+                    (그리고 이 전이(transition)에 대해 실행될 필요가 있는 SQL 문장들을 Hibernate로 하여금 처리하도록 하는데) 
+                    Hibernate <literal>Session</literal>을 사용하라.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Persistent</emphasis> - 하나의 영속 인스턴스는 데이터베이스 내에서 하나의 표상을 갖고 하나의 식별자 값을 
+                                        갖는다. 그것은 방금 저장되었거나 로드되었을 수 있지만, 정의상 그것은 <literal>Session</literal>의 범위 내에 있다. 
+                    Hibernate는 영속 상태에서 객체에 대해 행해진 임의의 변경들을 검출해낼 것이고 단위 작업이 완료될 때 그 상태를 데이터베이스와 
+                                        동기화 시킬 것이다. 개발자들은 하나의 객체가 transient로 되어야 할 때 <literal>UPDATE</literal> 문장들이나 
+                    <literal>DELETE</literal> 문장들을 수작업으로 실행하지 않는다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Detached</emphasis> - 하나의 detached 인스턴스는 영속화 되었지만, 그것의 
+                    <literal>Session</literal>이 닫혀진 객체이다. 물론 그 객체에 대한 참조는 여전히 유효하고, 
+                                        그 detached 인스턴스는 이 상태에서도 변경될 수도 있다. 하나의 detached 인스턴스는 나중에 
+                                        그것(과 모두 변경들)을 다시 영속화 시켜서 새로운 <literal>Session</literal>에 다시 첨부될 수 있다. 
+                                        이 특징은 사용자가 생각할 시간을 필요로 하는 장 기간 실행되는 작업 단위를 위한 프로그래밍 모형을 가능하게
+                                        해준다. 우리는 그것들을 <emphasis>어플리케이션 트랜잭션들</emphasis>, 즉 사용자의 관점의 작업 단위라고 
+                                        부른다.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+                        이제 우리는 상태들과 상태 전이(transition)들(그리고 전이를 트리거 시키는 Hibernate 메소드들)을 상세하게 논의할 것이다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-makingpersistent" revision="1">
+        <title>객체들을 영속화 시키기</title>
+
+        <para>
+                        하나의 영속 클래스의 새로이 초기화 된 인스턴스들은 Hibernate에 의해 <emphasis>transient</emphasis>로 간주된다. 
+                        우리는 그것을 세션과 연관지어서 transient 인스턴스를 <emphasis>영속화</emphasis> 시킬 수 있다:
+        </para>
+
+        <programlisting><![CDATA[DomesticCat fritz = new DomesticCat();
+fritz.setColor(Color.GINGER);
+fritz.setSex('M');
+fritz.setName("Fritz");
+Long generatedId = (Long) sess.save(fritz);]]></programlisting>
+
+        <para>
+                        만일 <literal>Cat</literal>이 생성된 식별자를 가질 경우, <literal>save()</literal>가 호출될 때 
+                        그 식별자가 생성되고 <literal>cat</literal>에 할당된다. 만일 <literal>Cat</literal>이 하나의 
+            <literal>assigned</literal> 식별자나 하나의 composite key를 가질 경우, <literal>save()</literal>를 
+                        호출하기 전에 그 식별자가<literal>cat</literal> 인스턴스에 할당될 것이다. 당신은 또한  EJB3 초기 드래프트에서 
+                        정의된 의미로 <literal>save()</literal> 대신 <literal>persist()</literal>를 사용할 수도 있다.
+        </para>
+        
+        <para>
+                        다른 방법으로, 당신은 <literal>save()</literal>의 오버로드된 버전을 사용하여 식별자를 할당할 수 있다.
+        </para>
+
+<programlisting><![CDATA[DomesticCat pk = new DomesticCat();
+pk.setColor(Color.TABBY);
+pk.setSex('F');
+pk.setName("PK");
+pk.setKittens( new HashSet() );
+pk.addKitten(fritz);
+sess.save( pk, new Long(1234) );]]></programlisting>
+        
+        <para>
+                        만일 당신이 영속화 시키는 객체가 연관된 객체들(예를 들면. 앞의 예제에 있는 <literal>kittens</literal> 콜렉션)을 갖고 있다면, 
+                       당신이 하나의 foreign 키 컬럼에 대해 하나의 <literal>NOT NULL</literal> 컨스트레인트를 갖지 않는 한, 
+                       이들 객체들은 당신이 좋아하는 임의의 순서로 영속화 되었을 수도 있다. foreign 키 컨스트레인트들을 위배하는 위험성이 
+                       결코 존재하지 않는다. 하지만 당신이 잘못된 순서로 그 객체들을 <literal>save()</literal> 시킬 경우 당신은 
+            <literal>NOT NULL</literal> 컨스트레인트를 위배할 수도 있다.
+        </para>
+        
+        <para>
+                        당신이 연관된 객체들을 자동적으로 저장시키는데 Hibernate의 <emphasis>transitive persistence(전이 영속)</emphasis> 
+                        특징을 사용하는 것을 매우 좋아할 것이므로 대개 당신은 이 상세를 내버려둔다. 그때 <literal>NOT NULL</literal> 컨스트레인트 
+                        위배들이 발생되지 않을지라도 - Hibernate는 모든 것을 처리할 것이다. Transitive persistence(전이 영속)은 이 장에서 
+                        후반부에서 논의된다.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="objectstate-loading">
+        <title>객체를 로드시키기</title>
+
+        <para>
+            <literal>Session</literal>의 <literal>load()</literal> 메소드들은 만일 당신이 그것(영속 인스턴스)의 식별자들을 
+                        이미 알고 있을 경우에 영속 인스턴스를 검색하는 방법을 당신에게 제공한다. <literal>load()</literal>는 하나의 클래스 객체를 
+                        취하고  그 상태를 영속(persistent) 상태로 그 클래스의 새로이 초기화 된 인스턴스 속으로 로드시킬 것이다.
+        </para>
+
+        <programlisting><![CDATA[Cat fritz = (Cat) sess.load(Cat.class, generatedId);]]></programlisting>
+
+<programlisting><![CDATA[// you need to wrap primitive identifiers
+long id = 1234;
+DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id) );]]></programlisting>
+
+        <para>
+                        다른 방법으로 당신은 주어진 인스턴스 속으로 상태를 로드시킬 수 있다:
+        </para>
+
+<programlisting><![CDATA[Cat cat = new DomesticCat();
+// load pk's state into cat
+sess.load( cat, new Long(pkId) );
+Set kittens = cat.getKittens();]]></programlisting>
+
+        <para>
+                        만일 일치하는 데이터베이스 행이 존재하지 않을 경우에 <literal>load()</literal>가 unrecoverable(복구 불가능한) 예외상황을 
+                        던질 것임을 노트하라. 만일 클래스가 프락시를 갖도록 매핑된 경우, <literal>load()</literal>는 초기화 되지 않은 프락시를 단지 
+                        반환하고 당신이 그 프락시의 메소드를 호출하기 전까지는 실제로 데이터베이스에 접속하지 않는다. 당신이 데이터베이스로부터 
+                        객체에 대한 연관을 실제로 로드시키지 않고서 객체에 대한 연관을 생성시키고자 원할 경우에 이 특징이 매우 유용하다. 만일 
+            <literal>batch-size</literal>가 class 매핑에 정의되는 경우 그것은 또한 다중 인스턴스들이 하나의 배치로서 로드되는 것을 
+                        허용해준다.
+        </para>
+        
+        <para>
+                        만일 당신이 하나의 일치하는 행이 존재하는지를 확신할 수 없을 경우, 당신은  <literal>get()</literal> 메소드를 사용해야 한다. 
+                        그것(<literal>get()</literal> 메소드)는 데이터베이스에 즉시 접속하고 만일 일치하는 행이 없을 경우 null을 반환한다.
+        </para>
+        
+        <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id);
+if (cat==null) {
+    cat = new Cat();
+    sess.save(cat, id);
+}
+return cat;]]></programlisting>
+
+        <para>
+                        당신은 하나의 <literal>LockMode</literal>를 사용하는, <literal>SELECT ... FOR UPDATE</literal>를 사용하여 
+                        하나의 객체를 로드시킬 수도 있다. 추가 정보는 API 문서를 보라.
+        </para>
+
+        <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);]]></programlisting>
+        
+        <para>
+                        어떤 연관된 인스턴스들이나 포함된 콜렉션들은 당신이 그 연관에 대한 케스케이드 스타일로서 <literal>lock</literal> 또는 
+            <literal>all</literal>을 지정하도록 결정하지 않는 한, <literal>FOR UPDATE</literal>로 선택되지 않음을 노트하라.
+        </para>
+        
+        <para>
+            <literal>refresh()</literal> 메소드를 사용하여, 아무때나 하나의 객체와 모든 그것의 콜렉션들을 다시 로드시키는 것이 
+                        가능하다. 데이터베이스 트리거들이 그 객체의 프로퍼티들 중 어떤 것을 초기화 시키는데 사용될 때 이것이 유용하다.
+        </para>
+        
+        <programlisting><![CDATA[sess.save(cat);
+sess.flush(); //force the SQL INSERT
+sess.refresh(cat); //re-read the state (after the trigger executes)]]></programlisting>
+
+        <para>
+                        중요한 질문이 대개 이 지점에서 나타난다: Hibernate는 데이터베이로부터 그것을 얼마나 많이 로드시키고 그리고 얼마나 많은 
+            SQL <literal>SELECT</literal>들이 그것을 사용할 것인가? 이것은 <emphasis>페칭 방도</emphasis>에 의존하고 
+            <xref linkend="performance-fetching"/>에 설명되어 있다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-querying" revision="1">
+        <title>질의하기</title>
+
+        <para>
+                        만일 당신이 당신이 찾고 있는 객체들에 대한 식별자들을 모를 경우, 당신은 하나의 질의를 필요로 한다. Hibernate는 사용이 쉽지만 
+                        강력한 객체 지향 질의 언어(HQL)를 지원한다. 프로그램 상의 질의 생성을 위해, Hibernate는 정교한 Criteria 및 Example 질의 
+                        특징(QBC와 QBE)를 지원한다. 당신은 또한 객체들로의 결과 셋 변환을 위한 선택적인  Hibernate의 지원으로, 당신의 데이터베이스의 
+            native SQL 속에 당신의 질의를 표현할 수도 있다.
+        </para>
+
+        <sect2 id="objectstate-querying-executing" revision="1">
+            <title>질의들을 실행하기</title>
+
+            <para>
+                HQL 질의와 native SQL 질의는 <literal>org.hibernate.Query</literal>의 인스턴스로 표현된다. 이 인터페이스는 
+                                파라미터 바인딩, 결과셋 핸들링을 위한, 그리고 실제 질의의 실행을 위한 메소드들을 제공한다. 당신은 항상 현재 
+                <literal>Session</literal>을 사용하여 하나의 <literal>Query</literal>를 얻는다:
+            </para>
+
+        <programlisting><![CDATA[List cats = session.createQuery(
+    "from Cat as cat where cat.birthdate < ?")
+    .setDate(0, date)
+    .list();
+
+List mothers = session.createQuery(
+    "select mother from Cat as cat join cat.mother as mother where cat.name = ?")
+    .setString(0, name)
+    .list();
+
+List kittens = session.createQuery(
+    "from Cat as cat where cat.mother = ?")
+    .setEntity(0, pk)
+    .list();
+
+Cat mother = (Cat) session.createQuery(
+    "select cat.mother from Cat as cat where cat = ?")
+    .setEntity(0, izi)
+    .uniqueResult();]]
+
+Query mothersWithKittens = (Cat) session.createQuery(
+    "select mother from Cat as mother left join fetch mother.kittens");
+Set uniqueMothers = new HashSet(mothersWithKittens.list());]]></programlisting>
+
+            <para>
+                                하나의 질의는 대개 <literal>list()</literal>를 호출하여 실행되고, 질의의 결과는 메모리 내에서 하나의 콜렉션 속으로 
+                                전체적으로 로드될 것이다. 하나의 질의에 의해 검색된 엔티티 인스턴스들은 영속(persistent) 상태에 있다. 당신의 질의가 
+                                하나의 객체를 오직 반환할 것임을 당신이 알고 있을 경우에 <literal>uniqueResult()</literal> 메소드는 단축을 제공한다.
+                                콜렉션들에 대해  eager 페칭을 사용하는 질의들은 대개 (그것들의 초기화된 콜렉션들을 가진) 루트 객체들에 대한 중복들을 대개 
+                                반환한다. 당신은 <literal>Set</literal>을 통해 이들 중복들을 간단하게 필터링할 수 있다.
+            </para>
+
+            <sect3 id="objectstate-querying-executing-iterate">
+                <title>결과들을 반복하기</title>
+
+                <para>
+                                        종종, 당신은 <literal>iterate()</literal> 메소드를 사용하여 질의를 실행함으로써 더 나은 퍼포먼스를 성취하는 
+                                        것이 가능할 수 있다. 이것은 오직 대개 질의에 의해 반환되는 실제 엔티티 인스턴스들이 이미 세션 내에 있거나 
+                    second-level 캐시 내에 있을 것임을 당신이 예상하는 경우일 것이다. 만일 그것들이 이미 캐시되지 않았다면, 
+                    <literal>iterate()</literal>는 <literal>list()</literal> 보다 더 느릴 것이고 간단한 질의에 대해 
+                                        많은 데이터베이스 접속들을, 대개 오직 식별자들을 반환하는 초기 select에 대해 <emphasis>1</emphasis>번의 접속과 
+                                        실제 인스턴스들을 초기화 시키는 추가적인 select들에 대해 <emphasis>n</emphasis> 번의 접속을 필요로 할 수 있다.
+                </para>
+
+                <programlisting><![CDATA[// fetch ids
+Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate();
+while ( iter.hasNext() ) {
+    Qux qux = (Qux) iter.next();  // fetch the object
+    // something we couldnt express in the query
+    if ( qux.calculateComplicatedAlgorithm() ) {
+        // delete the current instance
+        iter.remove();
+        // dont need to process the rest
+        break;
+    }
+}]]></programlisting>
+            </sect3>
+            
+            <sect3 id="objectstate-querying-executing-tuples">
+                <title>튜플들을 반환하는 질의들</title>
+
+                <para>
+                    Hibernate 질의들은 때때로 객체들의 튜플들을 반환하고, 그 경우에 각각의 튜플은 배열로서 반환된다:
+                </para>
+
+                <programlisting><![CDATA[Iterator kittensAndMothers = sess.createQuery(
+            "select kitten, mother from Cat kitten join kitten.mother mother")
+            .list()
+            .iterator();
+
+while ( kittensAndMothers.hasNext() ) {
+    Object[] tuple = (Object[]) kittensAndMothers.next();
+    Cat kitten  = tuple[0];
+    Cat mother  = tuple[1];
+    ....
+}]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-scalar" revision="1">
+                <title>스칼라 결과들</title>
+
+                <para>
+                                        질의들은 <literal>select</literal> 절 내에 하나의 클래스에 대한 하나의 프로퍼티를 지정할 수 있다. 
+                                        그것들은 심지어 SQL 집계 함수들을 호출할 수도 있다. 프로퍼티들이나 aggregate들은 
+                    "스칼라" 결과들(그리고 영속 상태에 있는 엔티티들이 아닌 것으)로 간주된다.
+                </para>
+
+                <programlisting><![CDATA[Iterator results = sess.createQuery(
+        "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
+        "group by cat.color")
+        .list()
+        .iterator();
+
+while ( results.hasNext() ) {
+    Object[] row = (Object[]) results.next();
+    Color type = (Color) row[0];
+    Date oldest = (Date) row[1];
+    Integer count = (Integer) row[2];
+    .....
+}]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-parameters">
+                <title>바인드 프라미터들</title>
+
+                <para>
+                    <literal>Query</literal> 상의 메소드들은 명명된 파라미터들 또는 JDBC-스타일의 <literal>?</literal> 
+                                        파라미터들에 바인딩 값들을 제공한다. <emphasis>JDBC와는 대조적으로, Hibernate 숫자 파라미터들은 0에서 
+                                        시작된다.</emphasis> 명명된 파라미터들은 질의 문자열 속에서 <literal>:name</literal> 형식의 식별자들이다. 
+                                        명명된 파라미터들의 장점들은 다음과 같다:
+                </para>
+
+                <itemizedlist spacing="compact">
+                    <listitem>
+                        <para>
+                                                        명명된 파라미터들은 그것들이 질의 문자열 내에 발생하는 순서에 관계없다
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                                                        그것들은 동일한 질의 내에서 여러 번 발생할 수 있다
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                                                        그것은 자기-설명적이다 
+                        </para>
+                    </listitem>
+                </itemizedlist>
+
+                <programlisting><![CDATA[//named parameter (preferred)
+Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
+q.setString("name", "Fritz");
+Iterator cats = q.iterate();]]></programlisting>
+
+                <programlisting><![CDATA[//positional parameter
+Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
+q.setString(0, "Izi");
+Iterator cats = q.iterate();]]></programlisting>
+
+                <programlisting><![CDATA[//named parameter list
+List names = new ArrayList();
+names.add("Izi");
+names.add("Fritz");
+Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)");
+q.setParameterList("namesList", names);
+List cats = q.list();]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-pagination">
+                <title>쪽매김</title>
+
+                <para>
+                                        만일 당신이 당신의 결과 셋에 경계(당신이 검색하고자 원하는 최대 개수 그리고/또는 당신이 검색하고자 원하는 첫 번째 행)을 
+                                        지정할 필요가 있다면 당신은 <literal>Query</literal> 인터페이스의 메소드들을 사용해야 한다:
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.createQuery("from DomesticCat cat");
+q.setFirstResult(20);
+q.setMaxResults(10);
+List cats = q.list();]]></programlisting>
+
+                <para>
+                    Hibernate는 이 limit 질의를 당신의 DBMS의 native SQL로 번역하는 방법을 알고 있다.
+                </para>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-scrolling">
+                <title>스크롤 가능한 iteration</title>
+
+                <para>
+                                        당신의 JDBC 드라이버가  스크롤 가능한 <literal>ResultSet</literal>들을 지원할 경우, 
+                    <literal>Query</literal> 인터페이스는 <literal>ScrollableResults</literal> 객체를 얻는데 
+                                        사용될 수 있고, 그것은 질의 결과들에 대한 유연한 네비게이션을 허용해준다.
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
+                            "order by cat.name");
+ScrollableResults cats = q.scroll();
+if ( cats.first() ) {
+
+    // find the first name on each page of an alphabetical list of cats by name
+    firstNamesOfPages = new ArrayList();
+    do {
+        String name = cats.getString(0);
+        firstNamesOfPages.add(name);
+    }
+    while ( cats.scroll(PAGE_SIZE) );
+
+    // Now get the first page of cats
+    pageOfCats = new ArrayList();
+    cats.beforeFirst();
+    int i=0;
+    while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) );
+
+}
+cats.close()]]></programlisting>
+
+                <para>
+                                        열려진 데이터베이스 커넥션(과 커서)가 이 기능에 필요함을 노트하고, 만일 당신이 쪽매김 기능을 작동시킬 필요가 있다면 
+                    <literal>setMaxResult()</literal>/<literal>setFirstResult()</literal>를 사용하라.
+                </para>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-named" revision="1">
+                <title>명명된 질의들을 구체화 시키기</title>
+
+                <para>
+                                        당신은 또한 매핑 문서 속에 명명된 질의들을 정의할 수 있다.(만일 당신의 질의가 마크업으로서 해석될 수 있는 문자들을 
+                                        포함할 경우에 <literal>CDATA</literal> 섹션을 사용하는 것을 기억하라))
+                </para>
+
+                <programlisting><![CDATA[<query name="ByNameAndMaximumWeight"><![CDATA[
+    from eg.DomesticCat as cat
+        where cat.name = ?
+        and cat.weight > ?
+] ]></query>]]></programlisting>
+
+                <para>
+                                        파라미터 바인딩과 실행은 프로그램 상으로 행해진다:
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.getNamedQuery("ByNameAndMaximumWeight");
+q.setString(0, name);
+q.setInt(1, minWeight);
+List cats = q.list();]]></programlisting>
+
+                <para>
+                                        실제 프로그램 코드는 사용되는 질의 언어에 독립적이고, 당신은 또한 메타데이터로 native SQL 질의들을 정의할 수도 있거나 
+                                        그것들을 매핑 파일들 속에 기존 질의들을 위치지움으로써 기존 질의들을 Hibernate로 이전시킬 수도 있음을 노트하라.
+                </para>
+                
+                <para>
+                                        또한 <literal>&lt;hibernate-mapping&gt;</literal> 요소 내에서 하나의 질의 선언은 그 질의에 대한 
+                                        전역 유일 이름을 필요로 하고, 반면에 <literal>&lt;class&gt;</literal> 요소 내에서의 질의 선언은 
+                                        클래스 이름으로 수직된이름을 첨가하여 자동적으로 유일하게 만들어진다. 
+                                        예를 들어  <literal>eg.Cat.ByNameAndMaximumWeight</literal>.
+                </para>
+
+            </sect3>
+
+        </sect2>
+
+        <sect2 id="objectstate-filtering" revision="1">
+            <title>콜렉션들을 필터링 하기</title>
+            <para>
+                                콜렉션 <emphasis>필터</emphasis>는 영속 콜렉션 또는 배열에 적용될 수 있는 질의의 특별한 타입이다. 질의 문자열은 
+                                현재의 콜렉션 요소를 의미하는 <literal>this</literal>를 참조할 수 있다.
+            </para>
+
+            <programlisting><![CDATA[Collection blackKittens = session.createFilter(
+    pk.getKittens(), 
+    "where this.color = ?")
+    .setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) )
+    .list()
+);]]></programlisting>
+        
+            <para>
+                                반환되는 콜렉션은 하나의 bag으로 간주되고, 그것은 주어진 콜렉션에 대한 사본이다. 원래의 콜렉션은 변경되지 않는다
+                (이것은 이름 "filter"의 의미와는 정반대이지만, 예상되는 행위와 일치된다).
+            </para>
+
+            <para>
+                                필터들은 <literal>from</literal> 절을 필요로 하지 않음을 관찰하라(필요할 경우에 필터들이 한 개의 from 절을 가질 수 
+                                있을지라도). 필터들은 콜렉션 요소들 자체들을 반환하는 것으로 한정되지 않는다.
+            </para>
+
+            <programlisting><![CDATA[Collection blackKittenMates = session.createFilter(
+    pk.getKittens(), 
+    "select this.mate where this.color = eg.Color.BLACK.intValue")
+    .list();]]></programlisting>
+
+            <para>
+                                심지어 하나의 공백의 필터 질의도 예를 들어 거대한 콜렉션 내에 있는 요소들의 부분집합들을 로드시키는데 유용하다:
+            </para>
+
+            <programlisting><![CDATA[Collection tenKittens = session.createFilter(
+    mother.getKittens(), "")
+    .setFirstResult(0).setMaxResults(10)
+    .list();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="objecstate-querying-criteria" revision="1">
+           <title>Criteria 질의들</title>
+
+            <para>
+                HQL은 극히 강력하지만 몇몇 개발자들은 질의 문자열들을 빌드하기 보다, 객체 지향 API를 사용하여 동적으로 질의들을 빌드시키는 
+                                것을 선호한다. Hibernate는 이들 경우들을 위한 직관적인 <literal>Criteria</literal> query API를 제공한다:
+            </para>
+
+            <programlisting><![CDATA[Criteria crit = session.createCriteria(Cat.class);
+crit.add( Expression.eq( "color", eg.Color.BLACK ) );
+crit.setMaxResults(10);
+List cats = crit.list();]]></programlisting>
+    
+            <para>
+                <literal>Criteria</literal>와 연관된 <literal>Example</literal> API 는 
+                <xref linkend="querycriteria"/>에서 상세하게 논의된다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="objectstate-querying-nativesql" revision="2">
+            <title>native SQL에서 질의들</title>
+
+            <para>
+                                당신은 <literal>createSQLQuery()</literal>를 사용하여 SQL 속에 하나의 질의를 표현할 수 있고, 
+                Hibernate로 하여금 결과 셋들로부터 객체들로의 매핑을 처리하도록 할수도 있다. 당신은 아무때나
+                <literal>session.connection()</literal>을 호출할 수 있고 직접 JDBC <literal>Connection</literal>을 
+                                사용할 수 있음을 노트하라. 만일 당신이 Hibernate API를 사용하고자 선택한 경우에 , 당신은 SQL alias들을 
+                                중괄호들 속에 포함시켜야 한다:
+            </para>
+
+            <programlisting><![CDATA[List cats = session.createSQLQuery(
+    "SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10",
+    "cat",
+    Cat.class
+).list();]]></programlisting>
+                
+            <programlisting><![CDATA[List cats = session.createSQLQuery(
+    "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
+           "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
+    "FROM CAT {cat} WHERE ROWNUM<10",
+    "cat",
+    Cat.class
+).list()]]></programlisting>
+
+            <para>
+                SQL 질의들은 Hibernate 질의들처럼 명명된 파라미터들과 위치 파라미터들을 포함할 수도 있다. SQL 질의들에 대한 
+                               추가 정보는 <xref linkend="querysql"/>에서 찾을 수 있다.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="objectstate-modifying" revision="1">
+        <title>영속 객체들을 변경하기</title>
+
+        <para>
+            <emphasis>트랜잭션 상의 영속 인스턴스들</emphasis> (예를들면. <literal>Session</literal>에 의해 로드되고, 
+                        저장되고, 생성되거나 질의된 객체들)은 어플리케이션에 의해 처리될 수 있고 영속 상태에 대한 임의의 변경들은 
+            <literal>Session</literal>이 <emphasis>flush될</emphasis> 때 영속화 될 것이다(이 장의 뒷 부분에서 논의됨). 
+                        당신의 변경들을 영속화 시키기 위해 (다른 용도를 가진 <literal>update()</literal>와 같은) 특별한 메소드를 호출할 
+                        필요가 없다. 따라서 객체의 상태를 업데이트 시키는 가장 간단한 방법은 <literal>Session</literal>이 열려 있는 동안, 
+                        그것을 <literal>load()</literal>시키고 나서, 그것을 직접 처리하는 것이다:
+        </para>
+
+        <programlisting><![CDATA[DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
+cat.setName("PK");
+sess.flush();  // changes to cat are automatically detected and persisted]]></programlisting>
+
+        <para>
+                        때때로 이 프로그래밍 모형은 불충분하다. 왜냐하면 그것은 동일한 세션 내에서 (객체를 로드시키는) SQL 
+            <literal>SELECT</literal>와 (그것의 업데이트된 상태를 영속화 시키는) SQL <literal>UPDATE</literal> 
+                        양자를 필요로 할 것이기 때문이다. 그러므로 Hibernate는 detached 인스턴스들을 사용하는 대안적인 접근법을 제공한다.
+        </para>
+
+        <para>
+            <emphasis>Hibernate는 <literal>UPDATE</literal> 문장 또는 <literal>DELETE</literal> 문장의 직접적인 실행을 위한 
+                        그것 자신의 API를 제공하지 않음을 노트하라. Hibernate는 하나의 <emphasis>상태 관리</emphasis> 서비스이고, 당신은 그것을 
+                        사용할 <emphasis>문장들</emphasis>을 생각하지 말아야 한다. JDBC는 SQL 문장들을 실행시키는 완전한 API이고, 당신은
+            <literal>session.connection()</literal>을 호출하여 아무때나 한 개의 JDBC <literal>Connection</literal>을 
+                        얻을 수 있다. 게다가 대량 오퍼레이션의 개념은 온라인 트랜잭션 처리-지향적인 어플리케이션들을 위한 객체/관계형 매핑과 충돌한다. 
+                        하지만 Hibernate의 장래 버전들은 특별한 대용량의 오퍼레이션 기능들을 제공할 수도 있다. 몇몇 가능한 배치 오퍼레이션 트릭들에 
+                        대해서는 <xref linkend="batch"/>을 보라.</emphasis>
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-detached" revision="2">
+        <title>detached 객체들을 변경시키기</title>
+
+        <para>
+                        많은 어플리케이션들은 하나의 트랜잭션 내에서 하나의 객체를 검색하고, 처리를 위한 UI 계층으로 그것을 전송하고, 
+                        그런 다음 새로운 트랜잭션 내에서 변경들을 저장할 필요가 있다. 고도의-동시성 환경에서 이런 종류의 접근법을 사용하는 
+                        어플리케이션들은 대개 작업의 "긴" 단위를 확실히 격리시키기 위해 버전화 된 데이터를 사용한다.
+        </para>
+
+        <para>
+            Hibernate는 <literal>Session.update()</literal> 메소드 또는 <literal>Session.merge()</literal> 메소드를 
+                        사용하여 detached 인스턴스들의 재첨부를 제공함으로써 이 모형을 지원한다:
+        </para>
+
+        <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catId);
+Cat potentialMate = new Cat();
+firstSession.save(potentialMate);
+
+// in a higher layer of the application
+cat.setMate(potentialMate);
+
+// later, in a new session
+secondSession.update(cat);  // update cat
+secondSession.update(mate); // update mate]]></programlisting>
+
+        <para>
+                        만일 <literal>catId</literal> 식별자를 가진 <literal>Cat</literal>이 <literal>secondSession</literal>에 의해 
+                        이미 로드되었을 경우에 어플리케이션이 그것을 다시 재첨부하려고 시도할 때, 예외상황이 던져졌을 것이다.
+        </para>
+
+        <para>
+                        만일 그 세션이 동일한 식별자를 가진 영속 인스턴스를 이미 포함하지 않음을 당신이 확신하는 경우에는 
+            <literal>update()</literal>를 사용하고, 만일 당신이 세션의 상태를 고려하지 않은채로 아무때나 당신의 변경을 병합시키고자 
+                        원할 경우에는 <literal>merge()</literal>를 사용하라. 달리 말해, 당신의 detached 인스턴스들에 대한 재첨부가 실행되는 
+                        첫 번째 오퍼레이션임을 확실히 함으로써, <literal>update()</literal>는 대개 갓 만들어진 세션에서 당신이 호출하게 될 
+                        첫 번째 메소드이다.
+        </para>
+
+        <para>
+                        어플리케이션은 만일 그것이 detached 인스턴스들의 상태가 또한 업데이트 되는 것을 원할 경우에<emphasis>만</emphasis> 
+                        주어진 detached 인스턴스로부터 도달 가능한 detached 인스턴스들을 개별적으로<literal>update()</literal> 시킬 것이다. 
+                        이것은 물론 <emphasis>transitive persistence(전이 영속)</emphasis>을 사용하여 자동화 될 수 있고, 
+            <xref linkend="objectstate-transitive"/>를 보라.
+        </para>
+
+        <para>
+            <literal>lock()</literal> 메소드는 또한 하나의 객체를 새로운 세션에 대해 다시 연관시키는것을 어플리케이션에게 허용해준다. 
+                        하지만 detached 인스턴스는 변경되지 않아야 한다!
+        </para>
+
+        <programlisting><![CDATA[//just reassociate:
+sess.lock(fritz, LockMode.NONE);
+//do a version check, then reassociate:
+sess.lock(izi, LockMode.READ);
+//do a version check, using SELECT ... FOR UPDATE, then reassociate:
+sess.lock(pk, LockMode.UPGRADE);]]></programlisting>
+
+        <para>
+            <literal>lock()</literal>이 여러가지 <literal>LockMode</literal>들에 사용될 수 있음을 노트하고, 
+                        상세한 것은 API 문서와 트랜잭션 처리에 관한 장을 보라. 재첨부는 <literal>lock()</literal>에 대한 
+                        유일한 쓰임새는 아니다.
+        </para>
+
+        <para>
+                        긴 작업 단위에 대한 다른 모형들은 <xref linkend="transactions-optimistic"/>에서 논의된다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-saveorupdate">
+        <title>자동적인 상태 검출</title>
+
+        <para>
+            Hibernate 사용자들은 새로운 식별자를 생성시켜서 transient 인스턴스를 저장하거나 
+                        그것의 현재 식별자와 연관된 detached 인스턴스들을 업데이트/재첨부 시키는 일반적인 용도의 메소드를 요청했다. 
+            <literal>saveOrUpdate()</literal> 메소드는 이 기능을 구현한다.
+        </para>
+
+        <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catID);
+
+// in a higher tier of the application
+Cat mate = new Cat();
+cat.setMate(mate);
+
+// later, in a new session
+secondSession.saveOrUpdate(cat);   // update existing state (cat has a non-null id)
+secondSession.saveOrUpdate(mate);  // save the new instance (mate has a null id)]]></programlisting>
+
+        <para>
+            <literal>saveOrUpdate()</literal>의 사용 예제와 의미는 초심자들에게는 혼동스러워 보인다. 먼저, 하나의 세션에서 온 
+                        인스턴스를 또 다른 새로운 세션 내에서 사용하려고 시도하지 않는 한, 당신은 <literal>update()</literal>, 
+            <literal>saveOrUpdate()</literal>, 또는 <literal>merge()</literal>를 사용할 필요는 없을 것이다. 
+                        몇몇 전체 어플리케이션들은 이들 메소드들 중 어느 것도 결코 사용하지 않을 것이다.
+        </para>
+
+        <para>
+                        대개 <literal>update()</literal> 또는 <literal>saveOrUpdate()</literal>는 다음 시나리오에서 사용된다:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                                        어플리케이션이 첫 번째 세션 내에 객체를 로드시킨다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        객체가 UI 티어로 전달된다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        몇몇 변경들이 그 객체에 행해진다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        객체가 비지니스 로직 티어로 전달된다 
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        어플리케이션은 두 번째 세션에서 <literal>update()</literal>를 호출함으로써 이들 변경들을 영속화 시킨다
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>saveOrUpdate()</literal>는 다음을 행한다:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                                        만일 객체가 이 세션 내에서 이미 영속화 되어 있을 경우, 아무것도 행하지 않는다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        만일 그 세션과 연관된 또 다른 객체가 동일한 식별자를 가질 경우, 예외상황을 던진다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        만일 그 객체가 식별자 프로퍼티를 갖지 않을 경우, 그것을 <literal>save()</literal> 시킨다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        만일 객체의 식별자가 새로이 초기화 된 객체에 할당된 값을 가질 경우, 그것을 <literal>save()</literal> 시킨다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        만일 객체가 (<literal>&lt;version&gt;</literal> 또는 <literal>&lt;timestamp&gt;</literal>에 의해) 
+                                        버전화 되고, version 프로퍼티 값이 새로이 초기화 된 객체에 할당된 것과 동일한 값일 경우, 그것을 <literal>save()</literal> 
+                                        시킨다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        그 밖의 경우 그 객체를 <literal>update()</literal> 시킨다
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+                        그리고 <literal>merge()</literal>는 매우 다르다:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                                        만일 세션과 현재 연관된 동일한 식별자를 가진 영속 인스턴스가 존재할 경우, 
+                                        주어진 객체의 상태를 영속 인스턴스 상으로 복사한다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        만일 세션과 현재 연관된 영속 인스턴스가 존재하지 않을 경우, 데이터베이스로부터 그것을 로드시키려고 시도하거나 
+                                        새로운 영속 인스턴스를 생성시키려고 시도한다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        영속 인스턴스가 반환된다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                       주어진 인스턴스는 세션과 연관되지 않고, 그것은 detached 상태에 머무른다
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect1>
+
+    <sect1 id="objectstate-deleting" revision="1">
+        <title>영속 객체들을 삭제하기</title>
+
+        <para>
+            <literal>Session.delete()</literal>는 데이터베이스로부터 객체의 상태를 제거할 것이다. 
+                        물론 당신의 어플리케이션은 여전히 detached 객체에 대한 참조를 소유할 것이다. 영속 인스턴스를 transient로 만들 때 
+            <literal>delete()</literal>를 생각하는 것이 최상이다.
+        </para>
+
+        <programlisting><![CDATA[sess.delete(cat);]]></programlisting>
+
+        <para>
+                        당신은 foreign 키 컨스트레인트 위배들에 대한 위험성 없이 당신이 좋아하는 어떤 순서로 객체들을 삭제할 수도 있다. 
+                        잘못된 순서로 객체들을 삭제함으로써 foreign 키 컬럼에 대한 <literal>NOT NULL</literal> 컨스트레인트를 위배할 가능성이 
+                        여전히 존재한다. 예를 들어, 당신이 부모를 삭제하지만, 그 자식들을 삭제하는 것을 잊은 경우.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="objectstate-replicating" revision="1">
+    	<title>두 개의 다른 데이터저장소들 사이에 객체들을 복제하기</title>
+    	
+    	<para>
+    	         영속 인스턴스들의 그래프를 취하고 식별자 값들을 다시 생성시키지 않고서 그것들을 다른 저장소 속에 영속화 시키는 것을 가능하도록 
+                         만드는 것이  종종 유용하다.
+    	</para>
+    	
+        <programlisting><![CDATA[//retrieve a cat from one database
+Session session1 = factory1.openSession();
+Transaction tx1 = session1.beginTransaction();
+Cat cat = session1.get(Cat.class, catId);
+tx1.commit();
+session1.close();
+
+//reconcile with a second database
+Session session2 = factory2.openSession();
+Transaction tx2 = session2.beginTransaction();
+session2.replicate(cat, ReplicationMode.LATEST_VERSION);
+tx2.commit();
+session2.close();]]></programlisting>
+
+        <para>
+            <literal>ReplicationMode</literal>는  <literal>replicate()</literal>가 데이터베이스 내에 있는 기존의
+                        행들과의 충돌을 처리하게될 방법을 결정한다.
+        </para>
+        
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.IGNORE</literal> - 동일한 식별자를 가진 기존 데이터베이스 행이 존재할 
+                                        경우에 그 객체를 무시한다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.OVERWRITE</literal> - 동일한 식별자를 가진 어떤 기존의 데이터베이스 행을 덮어 쓴다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.EXCEPTION</literal> - 만일 동일한 식별자를 가진 기존 데이터베이스 행이 존재할 경우에 
+                                        예외상황을 던진다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.LATEST_VERSION</literal> - 행의 버전 번호가 객체의 버전 번호 보다 이전의 것이면 덮어쓰고, 
+                                        그 밖의 경우에 그 객체를 무시한다
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+                        이 특징의 쓰임새들은 다른 데이터베이스 인스턴스들 속으로 입력된 데이터 일치시키기, 제품 업그레이드 동안에 시스템 구성 정보 
+                        업데이트 하기, non-ACID 트랜잭션들 동안에 행해진 변경들을 롤백시키기 등을 포함한다.
+        </para>
+    	
+    </sect1>
+
+    <sect1 id="objectstate-flushing">
+        <title>Session을 flush 시키기</title>
+
+        <para>
+                        시간이 지남에 따라 <literal>Session</literal>은 JDBC 커넥션의 상태와 메모리 내에 보관된 객체들의 상태를 동기화 시키는데 
+                        필요한 SQL 문장들을 실행시킬 것이다. 이 프로세스 <emphasis>flush</emphasis>는 다음 시점들에서 디폴트로 발생한다
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                                        몇몇 질의들이 실행되기 전에
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.Transaction.commit()</literal> 시점에서
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>Session.flush()</literal> 시점에서
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            SQL 문장들이 다음 순서로 실행 명령이 내려진다
+        </para>
+
+        <orderedlist spacing="compact">
+            <listitem>
+                <para>
+                    
+                                        대응하는 객체들이 <literal>Session.save()</literal>를 사용하여 저장되었던 것과 같은 순서로, 모든 엔티티 삽입들
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        모든 엔티티 업데이트들
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        모든 콜렉션 삭제들
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        모든 콜렉션 요소 삭제들, 업데이트들 그리고 삽입들
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        모든 콜렉션 삽입들
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        대응하는 객체들이 <literal>Session.delete()</literal>를 사용하여 삭제되었던 것과 같은 순서로 모든 엔티티 삭제들. 
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <para>
+            (한가지 예외는 객체들이 저장될 때 <literal>native</literal> ID 생성을 사용하는 객체들이 insert 되는 점이다.) 
+        </para>
+
+        <para>
+                        당신이 명시적으로 <literal>flush()</literal> 시킬 때를 제외하면, <literal>Session</literal>이 JDBC 호출들을 
+                        실행시키는 <emphasis>시점</emphasis>, 그것들이 실행되는 <emphasis>순서</emphasis>만을 절대적으로 보장하지는 않는다. 
+                        하지만 Hibernate는 <literal>Query.list(..)</literal>가 실효성이 없는 데이터를 결코 반환하지 않을 것임을 보장하거나; 
+                        그것들이 잘못된 데이터도 반환하지 않을 것임을 보장한다.
+        </para>
+
+        <para>
+            flush가 너무 자주 발생하지 않도록 디폴트 행위를 변경하는 것이 가능하다. <literal>FlushMode</literal> 클래스는 세 개의 
+                        다른 모드들을 정의한다: 오직 커밋 시(그리고 Hibernate <literal>Transaction</literal> API가 사용될 때에만) flush 모드, 
+                        설명된 루틴을 사용하는 자동적인 flush 모드, 또는 <literal>flush()</literal>가 명시적으로 호출되지 않는 한  flush 시키지 
+                        않는 모드. 마지막 모드는 오래 동안 실행되는 작업 단위에 대해 유용하고, 여기서 <literal>Session</literal>은 열려진채로 
+                        유지되고 오랜 시간 동안 연결이 해제된 채로 유지된다. (<xref linkend="transactions-optimistic-longsession"/>를 보라).
+        </para>
+
+        <programlisting><![CDATA[sess = sf.openSession();
+Transaction tx = sess.beginTransaction();
+sess.setFlushMode(FlushMode.COMMIT); // allow queries to return stale state
+
+Cat izi = (Cat) sess.load(Cat.class, id);
+izi.setName(iznizi);
+
+// might return stale data
+sess.find("from Cat as cat left outer join cat.kittens kitten");
+
+// change to izi is not flushed!
+...
+tx.commit(); // flush occurs
+sess.close();]]></programlisting>
+
+        <para>
+            flush 동안에, 하나의 예외상황이 발생할 수도 있다(예를 들면. 만일 DML 오퍼레이션이 컨스트레인트를 위반할 경우). 예외상황들을 
+                        처리하는 것은  Hibernatem의 트랜잭션 특징에 관한 어떤 이해를 수반하며, 우리는 <xref linkend="transactions"/>에서 그것을 
+                        논의한다.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-transitive" revision="1">
+        <title>Transitive persistence(전이 영속)</title>
+
+        <para>
+                        특히 당신이 연관된 객체들의 그래프를 다룰 경우에, 특히 개별 객체들을 저장하고, 삭제하거나, 재첨부시키는 것이 꽤 번거롭다. 
+                        공통된 경우는 하나의 부모/자식 관계이다. 다음 예제를 검토하자:
+        </para>
+
+        <para>
+                        만일 부모/자식 관계에서 자식들이 값(value) 타입(예를 들면. 주소들 또는 문자열들을 가진 하나의 콜렉션)일 경우, 그것들의 생명주기는 
+                        부모에 의존할 것이고 상태 변경들에 대해 편리한 "케스케이딩"에 더 이상의 액션이 필요하지 않을 것이다. 만일 부모가 저장될 때, 
+                        값(value)-타입의 자식 객체들도 마찬가지로 저장되고, 부모가 삭제될 때, 자식들이 삭제될 것이다. 이것은 심지어 콜렉션으로부터 하나의 
+                        자식을 제거하는 그런 오퍼레이션들에 대해서도 동작한다; Hibernate는 이것을 검출하고, 값(value)-타입의 객체들은 참조를 공유할 수 
+                        없으므로, 데이터베이스로부터 그 자식을 삭제시킨다.
+        </para>
+
+        <para>
+                        이제 값(value) 타입이 아닌, 엔티티들인 부모와 자식 객체들을 가진 동일한 시나리오를 검토하자(예를 들면. 카테고리들과 아이템들, 
+                        또는 부모 고양이나 자식 고양이). 엔티티들은 그것들 자신의 생명주기를 갖고, 공유된 참조들을 지원하고 (따라서 콜렉션으로부터 하나의 
+                        엔티티를 제거하는 것은 그것이 삭제될 수 있음을 의미하지 않는다), 그리고 디폴트로 하나의 엔티티로부터 어떤 다른 연관된 엔티티들로의 
+                        상태의 케스케이딩은 존재하지 않는다. Hibernate는 디폴트로 <emphasis>도달가능성에 의한 영속성(persistence by reachability)</emphasis>을 
+                        구현하지 않는다.
+        </para>
+
+        <para>
+            - <literal>persist(), merge(), saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate()</literal>를 
+                        포함하는- Hibernate 세션에 대한 각각의 기본 오퍼레이션에 대해서 하나의 대응하는 케스케이딩 스타일이 존재한다. 케스케이드 스타일들 
+                        각각은 <literal>create, merge, save-update, delete, lock, refresh, evict, replicate</literal>로 명명된다. 
+                        만일 당신이 하나의 오퍼레이션이 하나의 연관에 따라 케스케이딩되는 것을 원할 경우, 당신은 매핑 문서 내에 그것을 지시해야 한다. 
+                        예를 들면:
+        </para>
+        
+        <programlisting><![CDATA[<one-to-one name="person" cascade="persist"/>]]></programlisting>
+        
+        <para>
+                        케스케이딩 스타일들이 결합될 수도 있다:
+        </para>
+        
+        <programlisting><![CDATA[<one-to-one name="person" cascade="persist,delete,lock"/>]]></programlisting>
+        
+        <para>
+                        당신은 <emphasis>모든</emphasis> 오퍼레이션들이 그 연관에 따라 케스케이드 되어야 함을 지정하는데 
+            <literal>cascade="all"</literal>을 사용할 수도 있다. 디폴트<literal>cascade="none"</literal>은 오퍼레이션들이 
+                        케스케이드 되지 않을 것임을 지정한다.
+        </para>
+        
+        <para>
+                        특정한 케스케이드 스타일인, <literal>delete-orphan</literal>은 오직 one-to-many 연관들에만 적용되고, 
+            <literal>delete()</literal> 오퍼레이션이 그 연관으로부터 제거되는 임의의 자식 객체에 적용되어야 함을 나타낸다.
+        </para>
+
+
+        <para>
+                        권장사항들 : 
+        </para>
+
+       <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                                        하나의 <literal>&lt;many-to-one&gt;</literal> 또는 <literal>&lt;many-to-many&gt;</literal> 연관에 
+                                        대해 케스케이드를 가능하게 하는 것은 대개 의미가 없다. 케스케이드는 <literal>&lt;one-to-one&gt;</literal> 연관과 
+                    <literal>&lt;one-to-many&gt;</literal> 연관에 대해 종종 유용하다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        만일 자식 객체의 수명이 그 부모 객체의 수명에 묶여져 있을 경우, <literal>cascade="all,delete-orphan"</literal>을 
+                                        지정함으로써 그것을 <emphasis>생명 주기 객체</emphasis>로 만들어라.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        그 밖의 경우, 당신은 케스케이드를 전혀 필요로 하지 않을 수 있다. 그러나 만일 당신이 동일한 트랜잭션 내에서 부모와 자식에 
+                                        대해 자주 함께 작업하게 될 것이라 생각되고, 당신 스스로  타이핑 하는 것을 절약하고자 원할 경우, 
+                    <literal>cascade="persist,merge,save-update"</literal>를 사용하는 것을 고려하라.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>cascade="all"</literal>을 가진 (단일 값 연관이든 하나의 콜렉션이든) 하나의 연관을 매핑시키는 것은 
+                        그 연관을 부모의 저장/업데이트/삭제가 자식 또는 자식들의 저장/업데이트/삭제로 귀결되는 <emphasis>부모/자식</emphasis> 
+                        스타일의 관계로 마크한다.
+        </para>
+        <para>
+                        게다가, 하나의 영속 부모로부터 하나의 자식에 대한 단순한 참조는 자식의 저장/업데이트로 귀결될 것이다. 하지만 이 메타포는 불완전하다. 
+                        그것의 부모에 의해 참조 해제되는 자식은 <literal>cascade="delete-orphan"</literal>으로 매핑된 하나의 
+            <literal>&lt;one-to-many&gt;</literal> 연관의 경우를 제외하면, 자동적으로 삭제되지 <emphasis>않는다</emphasis>. 
+                        하나의 부모/자식 관계에 대한 케스케이딩 오퍼레이션의 정확한 의미는 다음과 같다:
+        </para>
+
+       <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                                        만일 부모가 <literal>persist()</literal>에 전달될 경우, 모든 자식들이 <literal>persist()</literal>에 전달된다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        만일 부모가 <literal>merge()</literal>에 전달될 경우, 모든 자식들이 <literal>merge()</literal>에 전달된다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        만일 부모가 <literal>save()</literal>, <literal>update()</literal> 또는 <literal>saveOrUpdate()</literal>에 
+                                        전달될 경우, 모든 자식들이 <literal>saveOrUpdate()</literal>에 전달된다 
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        만일 transient 또는 detached 자식이 영속 부모에 의해 참조될 경우, 그것은 <literal>saveOrUpdate()</literal>에 전달된다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        만일 부모가 삭제될 경우, 모든 자식들이 <literal>delete()</literal>에 전달된다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        만일 자식이 영속 부모에 의해 참조 해제 될 경우, <literal>cascade="delete-orphan"</literal>이 아닌 한, 
+                    <emphasis>특별한 어떤 것도 발생하지 않는다</emphasis> - 어플리케이션은 필요한 경우에 자식을 명시적으로 삭제해야 한다 -, 
+                    <literal>cascade="delete-orphan"</literal>인 경우에 "orphaned(고아)"인 경우 자식이 삭제된다.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect1>
+
+        <para>
+                        마지막으로 오퍼레이션들의 케스케이딩이 <emphasis>호출 시점</emphasis>에서 또는 <emphasis>flush 시점</emphasis>에서 
+                        객체 그래프에 적용될 수 있음을 노트하라. 이용 가능할 경우에 모든 오퍼레이션들은 그 오퍼레이션이 실행될 때 도달 가능한 연관된 
+                        엔티티들에 대해 케스케이드 된다. 하지만 <literal>save-upate</literal>와 <literal>delete-orphan</literal>은 
+            <literal>Session</literal>의 flush 동안에 도달 가능한 모든 연관된 엔티티들에 대해 이행적(transitive)이다.
+        </para>
+
+    <sect1 id="objectstate-metadata">
+        <title>메타데이터 사용하기</title>
+
+        <para>
+            Hibernate는 모든 엔티티와 값(value) 타입들을 가진 매우 풍부한 메타-레벨 모형을 필요로 한다. 시간이 지남에 따라, 이 모형은 
+                        어플리케이션 그 자체에 매우 유용하다. 예를 들어, 어플리케이션은 어느 객체들이 복사되어야 하는지(예를 들면 가변적인 값(value) 타입들) 
+                        그리고 어느 것이 복사되지 말아야 하는지(예를 들면, 불변의 value 타입들과 가능한 연관된 엔티티들)를 인지하는 "스마트" deep-copy 
+                        알고리즘을 구현하는데 Hibernate의 메타데이터를 사용할 수도 있다.
+        </para>
+        <para>
+            Hibernate는 <literal>ClassMetadata</literal> 인터페이스와 <literal>CollectionMetadata</literal> 인터페이스 
+                        그리고  <literal>Type</literal> 계층구조를 통해 메타데이터를 노출시킨다. 메타데이터 인터페이스들의 인스턴스들은 
+            <literal>SessionFactory</literal>로부터 얻어질 수도 있다.
+        </para>
+
+        <programlisting><![CDATA[Cat fritz = ......;
+ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class);
+
+Object[] propertyValues = catMeta.getPropertyValues(fritz);
+String[] propertyNames = catMeta.getPropertyNames();
+Type[] propertyTypes = catMeta.getPropertyTypes();
+
+// get a Map of all properties which are not collections or associations
+Map namedValues = new HashMap();
+for ( int i=0; i<propertyNames.length; i++ ) {
+    if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType() ) {
+        namedValues.put( propertyNames[i], propertyValues[i] );
+    }
+}]]></programlisting>
+        
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/toolset_guide.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/toolset_guide.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/toolset_guide.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,588 @@
+<chapter id="toolsetguide" revision="2">
+    <title>도구셋 안내</title>
+
+    <para>
+        Hibernate에 대한 라운드트립 엔지니어링은 Eclipse 플러그인 세트, 명령라인 도구들, 뿐만 아니라 Ant 태스크들을 사용하여 가능하다.
+    </para>
+
+    <para>
+        <emphasis>Hibernate 도구들</emphasis>은 현재 기존 데이터베이스들에 대한 리버스 엔지니어링을 위해 Ant 태스크들 뿐만 아니라 
+        Eclipse IDE용 플러그인들을 포함하고 있다:
+    </para>
+
+    <itemizedlist>
+        <listitem><para>
+            <emphasis>매핑 편집기:</emphasis> 자동 완성 기능과 구문 강조를 지원하는 Hibernate XML 매핑 파일들에 대한 편집기. 그것은 또한 
+                        통상의 XML 편집기 보다 훨씬 더 융통성 있게 만들어서 클래스 이름들과 프로퍼티/필드 이름들에 대한 의미론적 자동 완성 기능을 지원한다.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>콘솔:</emphasis> 콘솔은 Eclipse에서 새로운 뷰이다. 당신의 콘솔 구성들에 대한 tree overview에 덧붙여, 당신은 또한 
+                        당신의 영속 클래스들과 그것들의 관계들에 대한 상호작용 뷰를 얻는다. 콘솔은 당신의 데이터베이스에 대해 HQL 질의들을 실행하고 그 결과를 
+            Eclipse 내에서 직접 브라우징 하도록 당신에게 허용해준다.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>개발 마법사들:</emphasis> 몇몇 마법사들이 Hibernate Eclipse 도구들에 제공된다; 당신은 Hibernate 구성
+            (cfg.xml) 파일들을 빠르게 생성시키는데 마법사를 사용하거나, 심지어 당신은 기존 데이터베이스 스키마를 POJO 소스 파일들과 
+            Hibernate 매핑 파일들로 완전하게 리버스 엔지니어링할 수도 있다. 리버스 엔지니어링 마법사는 맞춤 가능한 템플릿들을 제공한다.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Ant 태스크들:</emphasis>
+        </para></listitem>
+
+    </itemizedlist>
+
+    <para>
+                추가 정보는 <emphasis>Hibernate Tools</emphasis> 패키지와 그것의 문서를 참조하길 바란다.
+    </para>
+
+    <para>
+                하지만 Hibernate 메인 패키지는 통합 도구에 번들화 되어 있다(그것은 심지어 플라이 상에서 Hibernate "내에서" 사용될 수 있다): 
+        <emphasis>SchemaExport</emphasis> 별칭은 <literal>hbm2ddl</literal>.
+    </para>
+
+    <sect1 id="toolsetguide-s1" revision="2">
+        <title>자동적인 스키마 생성</title>
+
+        <para>
+            DDL은 Hibernate 유틸리티에 의해 당신의 매핑 파일들로부터 생성될 수 있다. 생성된 스키마는 엔티티 테이블과 콜렉션 테이블에 대한 
+                        참조 무결성 컨스트레인트들(프라이머리 키와 foreign 키들)을 포함한다. 테이블들과 시퀀스들은 또한 페칭된 식별자 생성기들에 대해 
+                        생성된다.
+        </para>
+        
+        <para>
+            DDL이 매우 벤더에 특정하므로, 이 도구를 사용할 때 당신은 <literal>hibernate.dialect</literal> 프로퍼티를 통해 한 개의 SQL 
+            <literal>Dialect</literal>를 지정<emphasis>해야 한다</emphasis>.
+        </para>
+
+        <para>
+                        먼저 생성된 스키마를 개선시키기 위해 당신의 매핑 파일들을 맞춤화 시켜라.
+        </para>
+
+        <sect2 id="toolsetguide-s1-2" revision="3">
+            <title>스키마 맞춤화 시키기</title>
+
+            <para>
+                                많은 Hibernate 매핑 요소들은 <literal>length</literal>로 명명된 옵션 속성을 정의한다. 당신은 이 속성으로 컬럼의 길이를 
+                                설정할 수 있다.(또는 numeric/decimal 데이터 타입들, 배정도에 대해 ).
+                                많은 Hibernate 매칭 요소들은 <literal>length</literal>, <literal>precision</literal> 그리고 
+                <literal>scale</literal>로 명명된 옵션 속성들을 정의하고 있다. 당신은 이 속성으로서 컬럼이 길이, 정밀도, 크기를 설정할 수 있다.
+ 
+            </para>
+            
+            <programlisting><![CDATA[<property name="zip" length="5"/>]]></programlisting>
+            <programlisting><![CDATA[<property name="balance" precision="12" scale="2"/>]]></programlisting>
+
+            <para>
+                                몇몇 태그들은 또한 (테이블 컬럼들에 대한 <literal>NOT NULL</literal> 컨스트레인트를 생성시키는) <literal>not-null</literal> 
+                                속성과 (테이블 컬럼들에 대한 <literal>UNIQUE</literal> 컨스트레인트를 생성시키는) <literal>unique</literal> 속성을 수용한다.
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="bar" column="barId" not-null="true"/>]]></programlisting>
+
+            <programlisting><![CDATA[<element column="serialNumber" type="long" not-null="true" unique="true"/>]]></programlisting>
+
+            <para>
+                <literal>unique-key</literal> 속성은 하나의 유일 키 컨스트레인트로 컬럼들을 그룹지우는데 사용될 수도 있다. 현재 
+                <literal>unique-key</literal> 속성의 지정된 값은 산출된 DDL내에서 컨스트레인트를 명명하는데 사용되지 <emphasis>않고</emphasis>, 
+                                오직 매핑 파일 내에서 컬럼들을 그룹 지우는데 사용된다.
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="org" column="orgId" unique-key="OrgEmployeeId"/>
+<property name="employeeId" unique-key="OrgEmployee"/>]]></programlisting>
+            
+            
+            <para>
+                <literal>index</literal> 속성은 매핑된 컬럼 또는 컬럼들을 사용하여 생성될 인덱스의 이름을 지정한다. 간단하게 
+                                동일한 인덱스 이름을 지정함으로써 여러 컬럼들이 동일한 인덱스 내로 그룹지워질 수도 있다.
+            </para>
+
+            <programlisting><![CDATA[<property name="lastName" index="CustName"/>
+<property name="firstName" index="CustName"/>]]></programlisting>
+
+            <para>
+                <literal>foreign-key</literal> 속성은 임의의 산출된 foreign 키 컨스트레인트의 이름을 
+                                오버라이드 시키는데 사용될 수 도 있다.
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="bar" column="barId" foreign-key="FKFooBar"/>]]></programlisting>
+
+            <para>
+                                많은 매핑 요소들은 또한 하나의 자식 <literal>&lt;column&gt;</literal> 요소를 허용한다.
+                                이것은 특히 다중 컬럼 타입들을 매핑하는데 유용하다:
+            </para>
+
+            <programlisting><![CDATA[<property name="name" type="my.customtypes.Name"/>
+    <column name="last" not-null="true" index="bar_idx" length="30"/>
+    <column name="first" not-null="true" index="bar_idx" length="20"/>
+    <column name="initial"/>
+</property>]]></programlisting>
+
+            <para>
+                                다른 방법으로, 이들 요소들은 또한 자식 <literal>&lt;column&gt;</literal> 요소를 수용한다. 이것은 다중 컬럼 타입들에 
+                                특히 유용하다:
+                <literal>default</literal> 속성은 당신으로 하여금 하나의 컬럼에 대한 디폴트 값을 설정하도록 한다(당신은 매핑된 
+                                클래스의 새로운 인스턴스를 저장하기 전에 매핑된 프로퍼티에 동일한 값을 할당하게 될 것이다).
+            </para>
+
+            <programlisting><![CDATA[<property name="credits" type="integer" insert="false">
+    <column name="credits" default="10"/>
+</property>]]></programlisting>
+
+            <programlisting><![CDATA[<version name="version" type="integer" insert="false">
+    <column name="version" default="0"/>
+</property>]]></programlisting>
+
+            <para>
+                <literal>sql-type</literal> 속성은 SQL 데이터타입에 대한 Hibernate 타입의 디폴트 매핑을 오버라이드 시키는 것을 
+                                사용자에게 허용해준다.
+            </para>
+            
+            <programlisting><![CDATA[<property name="balance" type="float">
+    <column name="balance" sql-type="decimal(13,3)"/>
+</property>]]></programlisting>
+            
+            <para>
+                <literal>check</literal> 속성은 check 컨스트레인트를 지정하는 것을 당신에게 허용해준다.
+            </para>
+            
+            <programlisting><![CDATA[<property name="foo" type="integer">
+    <column name="foo" check="foo > 10"/>
+</property>]]></programlisting>
+
+            <programlisting><![CDATA[<class name="Foo" table="foos" check="bar < 100.0">
+    ...
+    <property name="bar" type="float"/>
+</class>]]></programlisting>
+            
+
+            <table frame="topbot" id="schemattributes-summary" revision="2">
+                <title>요약</title>
+                <tgroup cols="3">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>속성</entry>
+                            <entry>값들</entry>
+                            <entry>해석</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>length</literal></entry>
+                            <entry>number</entry>
+                            <entry>컬럼 길이</entry>
+                        </row>
+                        <row>
+                            <entry><literal>precision</literal></entry>
+                            <entry>number</entry>
+                            <entry>컬럼 decimal 정밀도</entry>
+                        </row>
+                        <row>
+                            <entry><literal>scale</literal></entry>
+                            <entry>number</entry>
+                            <entry>컬럼 decimal 크기</entry>
+                        </row>
+                        <row>
+                            <entry><literal>not-null</literal></entry>
+                            <entry><literal>true|false</literal></entry>
+                            <entry>컬럼이 null이 아니어야 함을 지정한다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>unique</literal></entry>
+                            <entry><literal>true|false</literal></entry>
+                            <entry>컬럼이 하나의 유일 컨스트레인트를 가져야함을 지정한다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>index</literal></entry>
+                            <entry><literal>index_name</literal></entry>
+                            <entry>(다중-컬럼) 인덱스의 이름을 지정한다 </entry>
+                        </row>
+                        <row>
+                            <entry><literal>unique-key</literal></entry>
+                            <entry><literal>unique_key_name</literal></entry>
+                            <entry>다중-컬럼 유일 컨스트레인트의 이름을 지정한다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>foreign-key</literal></entry>
+                            <entry><literal>foreign_key_name</literal></entry>
+                            <entry>
+                                                                하나의 연관에 대해, <literal>&lt;one-to-one&gt;</literal>, 
+                                <literal>&lt;many-to-one&gt;</literal>,
+                                <literal>&lt;key&gt;</literal>, 또는 <literal>&lt;many-to-many&gt;</literal> 
+                                                                매핑 요소에 대해 foreign key 컨스트레인트의 이름을 지정한다.<literal>inverse="true"</literal> 
+                                                                측들은 <literal>SchemaExport</literal>에 의해 고려되지 않을 것임을 노트하라.
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>sql-type</literal></entry>
+                            <entry><literal>SQL column type</literal></entry>
+                            <entry>
+                                                                디폴트 컬럼 타입을 오버라이드 시킨다
+                                (<literal>&lt;column&gt;</literal> 요소의 속성에만)
+                            </entry>
+                       </row>
+                       <row>
+                            <entry><literal>default</literal></entry>
+                            <entry>SQL expression</entry>
+                            <entry>
+                                                                컬럼에 대한 디폴트 값을 지정한다
+                            </entry>
+                       </row>
+                       <row>
+                            <entry><literal>check</literal></entry>
+                            <entry>SQL expression</entry>
+                            <entry>
+                                                                컬럼 또는 테이블에 대한 SQL check 컨스트레인트를 생성시킨다
+                            </entry>
+                       </row>
+                   </tbody>
+                </tgroup>
+            </table>
+            
+            <para>
+                <literal>&lt;comment&gt;</literal> 요소는 생성된 스키마에 대한 주석들을 지정하는 것을 당신에게 허용해준다. 
+            </para>
+            
+            <programlisting><![CDATA[<class name="Customer" table="CurCust">
+    <comment>Current customers only</comment>
+    ...
+</class>]]></programlisting>
+
+            <programlisting><![CDATA[<property name="balance">
+    <column name="bal">
+        <comment>Balance in USD</comment>
+    </column>
+</property>]]></programlisting>
+            
+            <para>
+                                이것은 (지원되는 경우) 생성된 DDL에서 <literal>comment on table</literal> 또는 
+                <literal>comment on column</literal> 문장으로 귀결된다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-3" revision="2">
+            <title>도구 실행하기</title>
+
+            <para>
+                <literal>SchemaExport</literal> 도구는 DDL 스크립트를 표준 출력으로 기록 하고/하거나 DDL 문장들을 실행시킨다.
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaExport</literal> <emphasis>options mapping_files</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaExport</literal> 명령 라인 옵션들</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>옵션</entry>
+                            <entry>설명</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--quiet</literal></entry>
+                            <entry>스크립트를 표준출력으로 출력하지 않는다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--drop</literal></entry>
+                            <entry>오직 테이블들을 드롭시킨다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--create</literal></entry>
+                            <entry>오직 테이블들을 생성시킨다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--text</literal></entry>
+                            <entry>데이터베이스로 내보내기 하지 않는다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--output=my_schema.ddl</literal></entry>
+                            <entry>ddl 스크립트를 파일로 출력한다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>하나의 <literal>NamingStrategy</literal>를 선택한다</entry>
+                        </row>
+                         <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry>XML 파일로부터 Hibernate 구성을 읽어들인다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>파일로부터 데이터베이스 프로퍼티들을 읽어들인다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--format</literal></entry>
+                            <entry>생성된 SQL을 스크립트 내에 좋게 형식지운다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--delimiter=;</literal></entry>
+                            <entry>스크립트를 위한 라인 경계의 끝을 설정한다 </entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                                당신은 당신의 어플리케이션 내에 <literal>SchemaExport</literal>를 삽입시킬 수도 있다:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaExport(cfg).create(false, true);]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-4">
+            <title>프로퍼티들</title>
+
+            <para>
+                                데이터베이스 프로퍼티들은 다음과 같이 지정될 수 있다
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para><literal>-D</literal><emphasis>&lt;property&gt;</emphasis>를 가진 시스템 프로퍼티로서</para>
+                </listitem>
+                <listitem>
+                    <para><literal>hibernate.properties</literal> 내에서</para>
+                </listitem>
+                <listitem>
+                    <para><literal>--properties</literal>를 가진 명명된  프로퍼티들 내에서</para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                                필요한 프로퍼티들은 다음과 같다:
+            </para>
+
+            <table frame="topbot">
+                <title>SchemaExport 커넥션 프로퍼티들</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>프로퍼티 이름</entry>
+                            <entry>설명</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                    <row>
+                        <entry><literal>hibernate.connection.driver_class</literal></entry>
+                        <entry>jdbc 드라이버 클래스</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.url</literal></entry>
+                        <entry>jdbc url</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.username</literal></entry>
+                        <entry>데이터베이스 사용자</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.password</literal></entry>
+                        <entry>사용자 패스워드</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.dialect</literal></entry>
+                        <entry>dialect</entry>
+                    </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-5">
+            <title>Ant 사용하기</title>
+
+            <para>
+                                당신은 당신의 Ant 빌드 스크립트에서 <literal>SchemaExport</literal>를 호출할 수 있다:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemaexport">
+    <taskdef name="schemaexport"
+        classname="org.hibernate.tool.hbm2ddl.SchemaExportTask"
+        classpathref="class.path"/>
+    
+    <schemaexport
+        properties="hibernate.properties"
+        quiet="no"
+        text="no"
+        drop="no"
+        delimiter=";"
+        output="schema-export.sql">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaexport>
+</target>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-6" revision="2">
+            <title>점증하는 스키마 업데이트들</title>
+
+            <para>
+                <literal>SchemaUpdate</literal> 도구는 "점증하는" 변경들을 가진 기존 스키마를 변경시킬 것이다. <literal>SchemaUpdate</literal>는 
+                JDBC 메타데이터 API에 무겁게 의존하여서, 그것은 모든 JDBC 드라이버들에 동작하지 않을 것임을 주목하라.
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>options mapping_files</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaUpdate</literal> 명령 라인 옵션들</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>옵션</entry>
+                            <entry>설명</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--quiet</literal></entry>
+                            <entry>스크립트를 표준출력으로 출력하지 않는다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--text</literal></entry>
+                            <entry>스크립트를 데이터베이스로 내보내기 하지 않는다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>하나의 <literal>NamingStrategy</literal>를 선택한다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>파일로부터 데이터베이스 프로퍼티들을 읽어 들인다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry><literal>.cfg.xml</literal> 파일을 지정한다</entry>
+                        </row>
+                     </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                                당신은 당신의 어플리케이션 내에 <literal>SchemaUpdate</literal>를 삽입시킬 수 있다:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaUpdate(cfg).execute(false);]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-7">
+            <title>점증하는 스키마 업데이트들에 Ant 사용하기</title>
+
+            <para>
+                                당신은 Ant 스크립트에서<literal>SchemaUpdate</literal>를 호출할 수 있다:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemaupdate">
+    <taskdef name="schemaupdate"
+        classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask"
+        classpathref="class.path"/>
+    
+    <schemaupdate
+        properties="hibernate.properties"
+        quiet="no">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaupdate>
+</target>]]></programlisting>
+
+        </sect2>
+        
+                <sect2 id="toolsetguide-s1-8" revision="1">
+            <title>스키마 유효성 검사</title>
+
+            <para>
+                <literal>SchemaValidator</literal> 도구는 기존의 데이터베이스 스키마가 당신의 매핑 문서들과 "일치하는지"를 유효성 
+                                검사할 것이다. <literal>SchemaValidator</literal>가 JDBC 메타데이터 API에 무겁게 의존하므로 그것은 모든 
+                JDBC 드라이버들에 대해 동작하지 않을 것이다. 이 도구는 테스팅에 극히 유용하다.
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaValidator</literal> <emphasis>options mapping_files</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaValidator</literal> 명령 라인 옵션들</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>옵션</entry>
+                            <entry>설명</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>하나의 <literal>NamingStrategy</literal>를 선택한다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>파일로부터 데이터베이스 프로퍼티들을 읽어들인다</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry><literal>.cfg.xml</literal> 파일을 지정한다</entry>
+                        </row>
+                     </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                                당신은 당신의 어플리케이션 내에 <literal>SchemaValidator</literal>을 삽입시킬 수 도 있다:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaValidator(cfg).validate();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-9">
+            <title>스키마 유효성 검사를 위해 Ant 사용하기</title>
+
+            <para>
+                                당신은 Ant 스크립트에서 <literal>SchemaValidator</literal>를 호출할 수 있다:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemavalidate">
+    <taskdef name="schemavalidator"
+        classname="org.hibernate.tool.hbm2ddl.SchemaValidatorTask"
+        classpathref="class.path"/>
+    
+    <schemavalidator
+        properties="hibernate.properties">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaupdate>
+</target>]]></programlisting>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/transactions.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/transactions.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/transactions.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1004 @@
+<chapter id="transactions" revision="2">
+    <title>트랜잭션들과 동시성</title>
+
+    <para>
+        Hibernate와 동시성 제어에 대한 가장 중요한 점은 이해하기가 매우 쉽다는 점이다. Hibernate는 어떤 추가적인 잠금 행위 없이 
+        JDBC 커넥션들과 JTA 리소스들을 직접 사용한다. 우리는 당신의 데이터베이스 관리 시스템의 JDBC, ANSI, 그리고 트랜잭션 격리 명세에 
+                약간의 시간을 할애할 것을 매우 권장한다.
+    </para>
+
+    <para>
+        Hibernate는 메모리 내에서 객체들을 잠그지 않는다. 당신의 어플리케이션은 격리 레벨에 의해 정의된 대로 행위를 기대할 수 있다.
+                또한 transaction-영역의 캐시인 <literal>Session</literal> 덕분에, Hibernate는 (스칼라 값들을 반환하는 질의들을 보고하지 않는) 
+                식별자와 엔티티 질의들에 의한 룩업을 위해 반복 가능한 읽기를 제공한다.
+    </para>
+
+    <para>
+                자동적인 optimistic 동시성 제어를 위한 버전화에 덧붙여, Hibernate는 또한 <literal>SELECT FOR UPDATE</literal>
+                구문을 사용하여 행들에 대한 pessimistic 잠금을 위한 하나의 (마이너)API를 제공한다. optimistic 동시성 제어와 이 API는 
+                이 장의 뒷부분에서 논의된다.
+    </para>
+
+    <para>
+                우리는 <literal>Configuration</literal>, <literal>SessionFactory</literal>, <literal>Session</literal>, 
+                알갱이를 가진 Hibernate에서의 동시성 제어 뿐만 아니라 데이터베이스 트랜잭션과 장기간에 걸친 (컴퓨터와의)대화들에 대한 논의를 시작한다.
+    </para>
+
+    <sect1 id="transactions-basics" revision="1">
+        <title>세션 영역과 트랜잭션 영역</title>
+
+        <para>
+            <literal>SessionFactory</literal>는 모든 어플리케이션 쓰레드들에 의해 공유되도록 고안된 생성에 비용이 드는, 
+                        쓰레드안전(threadsafe) 객체이다. 그것은 대개 어플리케이션 시작 시에 <literal>Configuration</literal> 인스턴스로부터 
+                        한번 생성된다.
+        </para>
+
+        <para>
+            <literal>Session</literal>은 하나의 요청, 하나의 대화 , 하나의 작업 단위를 위해 한번만 사용되고 나서 폐기될 예정인, 
+                         비용이 들지 않는, 쓰레드 안전하지 않은 객체이다. <literal>Session</literal>은 커넥션이 필요하지 않으면 하나의 JDBC 
+            <literal>Connection</literal>(또는 <literal>Datasource</literal>)를 얻지 않을 것이므로, 사용될 때까지
+                        리소스들을 소비하지 않는다.
+        </para>
+
+        <para>
+                        이 그림을 완성하기 위해 당신은 또한 데이터베이스 트랜재션들에 대해 생각해야 한다. 데이터베이스 트랜잭션은 데이터베이스에서 
+                        잠금 다툼을 줄이기 위해 가능한 짧아야 한다. 긴 데이터베이스 트랜잭션들은 당신의 어플리케이션이 고도의 동시성 로드로의 가용성을 
+                        높이는 것을 방해할 것이다. 그러므로 사용자가 생각하는 시간 동안 단위 작업이 완료될 때까지 데이터베이스 트랜잭션을 열려진채로 
+                        소유하는 것은 대개 결코 좋은 설계는 아니다.
+        </para>
+
+        <para>
+                        하나의 작업 단위의 영역은 무엇인가? 하나의 Hibernate <literal>Session</literal>은 몇몇 데이터베이스 트랜잭션들에 
+                        걸칠 수 있는가 또는 이것은 영역들의 one-to-one 관계인가?  당신은 언제 <literal>Session</literal>을 열고 닫는가 
+                        그리고 당신은 데이터베이스 트랜잭션 경계들을 어떻게 한정하는가?
+        </para>
+
+        <sect2 id="transactions-basics-uow" revision="1">
+            <title>작업 단위</title>
+
+            <para>
+                                첫번째로, <emphasis>session-per-operation</emphasis> anti-패턴을 사용하지 말라. 즉, 단일 쓰레드 내에서 
+                                모든 간단한 데이터베이스 호출에 대해 <literal>Session</literal>을 열고 닫지 말라! 물론 같은 것이 데이터베이스 
+                                트랜잭션들에 대해서도 참이다. 어플리케이션 내의 데이터베이스 호출들은 계획된 순서를사용하여 행해지며, 그것들은 원자
+                                작업 단위 속으로 그룹지워진다. (이것은 또한 모든 하나의 SQL 문장 뒤의 auto-commit(자동-커밋)이 어플리케이션 내에서 
+                                무용지물임을 의미하고, 이 모드가  SQL 콘솔 작업을 돕도록 고안되었음을 노트하라. Hibernate는 
+                                  의미하고, 이 모드는 Hibernate는 즉시 자동-커밋 모드를 사용 불가능하게 하거나, 어플리케이션 서버가 그렇게 행하고, 
+                                  즉시 자동-커밋시키는 것을 사용불가능하게 하거나 ,그렇게 행하는 것을 기대한다.) 데이터베이스 트랜잭션들은 결코 옵션이 아니며, 
+                                  하나의 데이터베이스와의 모든 통신은 당신이 데이터를 읽든 쓰단간에 상관없이 하나의 트랜잭션 내에서 발생해야 한다.
+                                  설명하였듯이, 데이터 읽기를 위한 auto-commit 특징을 피해야 할 것이며, 많은 작은 트랜잭션들은 하나의 명료하게 정의된 
+                                  작업 단위보다 더 좋게 수행될 것 같지 않다. 후자가 또한 훨씬 더 유지가능하고 확장적이다.
+            </para>
+
+            <para>
+                                다중 사용자 클라이언트/서버 어플리케이션에서 가장 공통된 패턴은 <emphasis>session-per-request</emphasis>이다. 
+                                이 모형에서, 클라이언트로부터의 요청은 (Hibernate 영속 계층이 실행되는) 서버로 전송되고, 새로운 Hibernate 
+                <literal>Session</literal>이 열려지고, 모든 데이터베이스 오퍼레이션들이 이 작업 단위 내에서 실행된다. 일단 그 작업이 
+                                 완료되었다면(그리고 클라이언트에 대한 응답이 준비되었다면), 그 세션은 flush 되고 닫혀진다. 당신은 또한 당신이 
+                <literal>Session</literal>을 열고 닫을 때 그것을 시작하고 커밋시켜서 클라이언트 요청에 서비스하는데 한 개의 데이터베이스 
+                                 트랜잭션을 사용하게 될 것이다. 둘 사이의 관계는 일대일 대응이고 이 모형은 많은 어플리케이션들에서 완전하게 적합하다.
+            </para>
+             
+             <para>
+                                난제는 구현에 놓여있다: Hibernate는 이 패턴을 단순화 시키기 위해 "현재 세션"에 관한 미리 빌드된 관리를 제공한다. 당신이 
+                                행해야할 모든 것은 서버 요청이 처리되어야 할 때 트랜잭션을 시작하고, 그 응답이 클라이언트로 전송되기 전에 트랜잭션을 끝내는 
+                                것이다. 당신은 당신이 좋아하는 임의의 방법으로 이것을 행할 수 있으며, 공통된 해결책들은 서비스 메소드들 상의 첨단, 또는 
+                                하나의 프락시/인터셉션 컨테이너를 가진 APO 인터셉터인, <literal>ServletFilter</literal>이다. 하나의 EJB 
+                                컨테이너는 CMT의 경우에 선언적으로 EJB session beans 상에 트랜잭션 경계구분과 같은 동시 대조 측면들을 구현하는 
+                                표준 방법이다. 만일 당신이 프로그램 상의 트랜잭션 경계구분을 사용하고자 결정한다면, 사용의 용이성과 코드 이식성을 위해 
+                                이 장의 뒷 부분에서 보여진 Hibernate <literal>Transaction</literal>을 선호하라.
+            </para>
+
+            <para>
+                                당신의 어플리케이션 코드는 어디서든 필요할 때 종종 <literal>sessionFactory.getCurrentSession()</literal>을 
+                                간단히 호출함으로써 요청을 처리할 "현재 세션"에 접근할 수 있다. 당신은 현재 데이터베이스 트랜잭션으로 영역화된 하나의 
+                <literal>Session</literal>을 항상 얻게 될 것이다. 이것은 resource-local 환경 또는 JTA 환경에 대해 구성되어야 
+                                하며, <xref linkend="architecture-current-session"/>을 보라.
+            </para>
+
+            <para>
+                                때때로 "뷰가 렌더링될 때까지" 하나의 <literal>Session</literal> 과 데이터베이스 트랜잭션의 영역을 확장시키는 것이 
+                                편리하다. 이것은 요청이 처리된 후에 하나의 별도의 렌더링 단계를 활용하는 서블릿 어플리케이션들에서 특히 유용하다. 
+                                뷰 렌더링이 완료될 때까지 데이터베이스 트랜잭션을 확장하는 것은 당신이 당신 자신의 인터셉터를 구현하는 경우에 행하기가 쉽다.
+                                하지만 만일 당신이 컨테이너에 의해 관리되는 트랜잭션들을 가진 EJB들에 의존할 경우에, 하나의 EJB 메소드가 반환될 때 
+                                임의의 뷰 렌더링이 시작될 수 있기 전에 하나의 트랜잭션이 완료되기 때문에, 행하는 것이 쉽지 않다. 이 
+                <emphasis>Open Session in View</emphasis> 패턴을 둘러싼 팁들과 예제들은 Hibernate 웹 사이트와 포럼을 보라.
+             </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-apptx" revision="1">
+            <title>장기간의 대화</title>
+
+            <para>
+                session-per-request 패턴은 당신이 작업 단위들을 설계하는데 사용할 수 있는 유일한 유용한 개념이 아니다. 많은 비지니스 
+                                프로세스들은 데이터베이스 접근들을 중재하는 사용자 사이의 전체 일련의 상호작용들을 필요로 한다. 웹과 엔터프라이즈 
+                                어플리케이션에서 사용자 상호작용에 걸치는 것은  데이터베이스 트랜잭션에 허용되지 않는다. 다음 예제를 검토하자:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                                                대화상자의 첫 번째 화면이 열리고, 사용자에게 보여진 데이터는 특정 <literal>Session</literal>과 데이터베이스 
+                                                트랜잭션 속에 로드되었다. 사용자가 객체들을 변경시키는 것이 자유롭다.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                                                
+                                                사용자는 5분 후에 "저장"을 클릭하고 그의 변경들이 영속화 되기를 기대한다; 그는 또한 그가 이 정보를 편집하는 유일한 
+                                                개인이고 변경 충돌이 발생하지 않기를 기대한다. 
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                                우리는 사용자의 관점에서, 이것을 작업 단위, 장기간 실행되는 <emphasis>대화</emphasis>
+                (또는 <emphasis>어플리케이션 트랜잭션</emphasis>)이라고 명명한다. 
+                                당신이 당신의 어플리케이션에서 이것을 어떻게 구현할 수 있는 많은 방법들이 존재한다.
+            </para>
+
+            <para>
+                                첫 번째 naive 구현은 동시성 변경을 방지하고, 격리와 atomicity(원자 단위성)을 보장하기 위해 데이터베이스에 의해 
+                                소유된 잠금으로 사용자가 생각하는동안 <literal>Session</literal>과 데이터베이스 트랜잭션을 유지할 수도 있다. 
+                                이것은 물론 anti-패턴이다. 왜냐하면 잠금 다툼은 어플리케이션이 동시 사용자들의 가용 숫자를 높이는 것을 허용하지 
+                                않을 것이기 때문이다.
+            </para>
+
+            <para>
+                                명료하게, 우리는 대화(<emphasis>어플리케이션 트랜잭션</emphasis>)를 구현하는데 몇몇 데이터베이스 트랜잭션들을 
+                                사용해야 한다. 이 경우에, 비지니스 프로세스들의 격리를 유지하는 것은 어플리케이션 티어의 부분적인 책임이 된다. 
+                                단일 대화는 대개 여러 개의 데이터베이스 트랜잭션들에 걸친다. 그것은 이들 데이터베이스 트랜잭션들 중 
+                                오직 한 개(마지막 트랜잭션)가 업데이트된 데이터를 저장하고, 모든 다른 트랜잭션들이 단순히 데이터를 읽는 (예를 들면, 
+                                몇몇 요청/응답 주기에 걸치는 마법사 스타일의 대화 상자에서) 경우에만 원자단위가 될 것이다. 특히 당신이 Hibernate의 
+                                특징들을 사용할 경우에 , 이것은 들리는 것보다 구현하기가 더 쉽다:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <emphasis>자동적인 버전화</emphasis> - Hibernate는 당신을 위해 자동적인 optimistic 
+                                                동시성 제어를 행할 수 있고, 그것은 사용자가 생각하는 시간 동안 동시적인 변경이 발생했는지를 자동적으로 검출할 수 있다.
+                                                대개 우리는 오직 대화의 끝에서 체크한다.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <emphasis>Detached 객체들</emphasis> - 만일 당신이 이미 논의된 <emphasis>session-per-request</emphasis> 
+                                                패턴을 사용하고자 결정하는 경우, 모든 로드된 인스턴스들은 사용자가 생각하는 시간 동안 detached 상태에 있을 것이다. 
+                        Hibernate는 그 객체들을 재첨부시키고 변경들을 영속화 시키는 것을 허용해주며, 그 패턴은 
+                        <emphasis>session-per-request-with-detached-objects(detached-객체들을 가진 요청 당 세션)</emphasis>으로 명명된다. 
+                                                자동적인 버전화는 동시성 변경들을 격리시키는데 사용된다.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <emphasis>확장된 (또는 Long) Session</emphasis> - Hibernate <emphasis>Session</emphasis>은 데이터베이스 
+                                                트랜잭션이 커밋된 후에 기본 JDBC 커넥션이 연결 해제될 수도 있고, 새로운 클라이언트 요청이 발생할 때 다시 연결될 수 
+                                                있다. 이 패턴은 <emphasis>session-per-conversation(대화 당 세션)</emphasis>으로 
+                                                알려져 있고 재첨부를 불필요하게 만든다. 자동적인 버전화는 동시성 변경들을 격리시키는데 사용되고 <literal>Session</literal>은 
+                                                자동적으로 flush되는 것이 허용되지 않지만 명시적으로 flush되는 것은 허용된다.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                <emphasis>session-per-request-with-detached-objects</emphasis>ê³¼ 
+                <emphasis>session-per-conversation</emphasis> 양자는 장점들과 단점들을 갖는데, 우리는 이 장의 
+                                뒷 부분에서 optimistic 동시성 제어 단락에서 그것들을 논의한다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-identity">
+            <title>객체 identity 고려하기</title>
+
+            <para>
+                                어플리케이션은 두 개의 다른 <literal>Session</literal>들 내에 있는 동일한 영속 상태에 동시에 접근할 수도 있다. 
+                                하지만 영속 클래스의 인스턴스는 두 개의 <literal>Session</literal> 인스턴스들 사이에 결코 공유되지 않는다. 
+                                그러므로 identity에 대한 두 개의 다른 개념들이 존재한다:
+            </para>
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term>데이터베이스 Identity</term>
+                    <listitem>
+                        <para>
+                            <literal>foo.getId().equals( bar.getId() )</literal>
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>JVM Identity</term>
+                    <listitem>
+                        <para>
+                            <literal>foo==bar</literal>
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+            <para>
+                                그때 (예를 들어 <literal>Session</literal> 영역에서) <emphasis>특정</emphasis> <literal>Session</literal>에 
+                                첨부된 객체들의 경우 두 개의 개념들은 동등한 것이고, 데이터베이스 identity에 대한 JVM identity가 Hibernate에 의해 보장된다. 
+                                하지만, 어플리케이션이 두 개의 다른 세션들에서 "동일한" (영속 identity) 비지니스 객체에 동시에 접근하는 동안, 두 개의 인스턴스들은 
+                                실제로 "다르다"(JVM identity). 충돌들은 flush/커밋 시에 (자동적인 버전화)를 사용하여, optimistic 접근법을 사용하여 해결된다. 
+            </para>
+
+            <para>
+                                이 접근법은 Hibernate와 데이터베이스가 동시성에 대해 걱정하지 않도록 해준다; 그것은 또한 최상의 scalability를 제공한다. 
+                                왜냐하면 단일 쓰레드-작업 단위 내에서 identity 보장은 단지 비용이 드는 잠금이나 다른 동기화 수단들을 필요로 하지 않기 때문이다. 
+                                어플리케이션은 그것이 <literal>Session</literal> 당 단일 쓰레드를 강제하는 한, 어떤 비지니스 객체에 대해 결코 동기화 시킬 
+                                필요가 없다. 하나의 <literal>Session</literal> 내에서 어플리케이션은 객체들을 비교하는데 <literal>==</literal>를 
+                                안전하게 사용할 수가 있다.
+            </para>
+
+            <para>
+                                하지만, 하나의 <literal>Session</literal> 외부에서 <literal>==</literal>를 사용하는 어플리케이션은 예기치 않은 
+                                결과들을 보게 될 수도 있다. 이것은 어떤 예기치 않은 장소들에서, 예를 들어 당신이 두 개의 detached 인스턴스들을 동일한 
+                <literal>Set</literal> 내에 집어넣을 경우에 발생할 수도 있다. 둘 다 동일한 데이터베이스 identity를 가질 수 있지만
+                (예를 들어 그것들은 동일한 행을 표현한다), JVM identity는 정의 상 detached 상태에 있는 인스턴스들을 보장하지 않는다. 
+                                개발자는 영속 클래스들내에  <literal>equals()</literal> 메소드와 <literal>hashCode()</literal> 메소드를 오버라이드 시켜야 하고 
+                                객체 equality에 대한 그 자신의 개념을 구현해야 한다. 하나의 경고가 존재한다: equality를 구현하는데 데이터베이스 identifier를 결코 
+                                사용하지 말고, 하나의 비지니스 키, 유일한, 대개 불변인 속성들의 조합을 사용하라. 데이터베이스 식별자는 만일 transient 객체가 영속화되는 
+                                경우에 변경될 것이다. 만일 transient 인스턴스가(대개 detached 인스턴스들과 함께) <literal>Set</literal> 내에 보관되는 경우에, 
+                hashcode 변경은 <literal>Set</literal>의 계약을 파기시킨다. 비지니스 키들에 대한 속성들은 데이터베이스 프라이머리 키들 만큼 
+                                안정적이어서는 안되며, 당신은 오직 객체들이 동일한 <literal>Set</literal> 내에 있는 한에서 안정성을 보장해야만 한다. 
+                                이 쟁점에 관한 논의에 대한 더 많은 것을 Hibernate 웹 사이트를 보라. 또한 이것이 Hibernate 쟁점이 아니며, 단지 자바 객체 
+                identity와 equality가 구현되어야 하는 방법임을 노트하라.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-issues">
+            <title>공통된 쟁점들</title>
+
+             <para>
+                                  안티-패턴들 <emphasis>session-per-user-session</emphasis> 또는 
+                 <emphasis>session-per-application</emphasis>을 결코 사용하지 말라(물론 이 규칙에 대한 드문 예외상황들이 존재한다). 
+                                  다음 쟁점들 중 몇몇이 또한 권장되는 패턴들로 나타날 수 있음을 노트하고, 당신이 설계 결정을 내리기 전에 내포된 의미들을 
+                                  확실히 이해하라:
+             </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <literal>Session</literal>은 쓰레드-안전하지 않다. HTTP 요청들, 세션 빈즈, 또는 Swing worker들처럼 
+                                                동시에 작업하는 것으로 가정되는 것들은 하나의 <literal>Session</literal> 인스턴스가 공유될 경우에 경쟁 조건들을 
+                                                발생시킬 것이다. 만일 당신이 당신의 <literal>HttpSession</literal> 내에 Hibernate 
+                        <literal>Session</literal>을 유지시키는 경우(나중에 논의됨), 당신은 당신의 Http 세션에 대한 접근을 동기화 
+                                                시키는 것을 고려해야 한다. 그 밖의 경우, 충분히 빠르게 reload를 클릭하는 사용자는 두 개의 동시적으로 실행되는 
+                                                쓰레드들 내에서 동일한 <literal>Session</literal>을 사용할 수도 있다.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Hibernate에 의해 던져진 예외상황은 당신이 당신의 데이터베이스 트랜잭션을 롤백 시키고 즉시 <literal>Session</literal>을 
+                                                닫아야 함을 의미한다(나중에 상세히 논의됨). 만일 당신의 <literal>Session</literal>이 어플리케이션에 바인드 되어 있는 경우, 
+                                                당신은 어플리케이션을 중지시켜야 한다. 데이터베이스 트랜잭션 롤백은 당신의 비지니스 객체들을 그것들이 트랜잭션의 시작 시에 
+                                                머물렀던 상태로 되돌리지는 않는다. 이것은 데이터베이스 상태와 비지니스 객체들이 동기화를 벗어남을 의미한다. 대개 이것은 문제가 아니다. 
+                                                왜냐하면 예외상황들은 회복가능한 것이 아니고 당신이 어떻게든 롤백 후에 시작해야 하기 때문이다.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session</literal>은 (Hibernate에 의해 dirty 상태로 관찰되었거나 체크된) 영속 상태에 있는 
+                                                모든 객체를 캐시 시킨다. 이것은 당신이 오랜 시간 동안  <literal>Session</literal>을 열어둔 채로 유지하거나 
+                                                단순하게 너무 많은 데이터를 로드시킬 경우에, 당신이 OutOfMemoryException을 얻기 전까지, 그것이 끝없이 
+                                                성장한다는 점을 의미한다. 이것에 대한 하나의 해결책은 <literal>Session</literal> 캐시를 관리하기 위해 
+                        <literal>clear()</literal>와 <literal>evict()</literal>를 호출하는 것이지만, 당신이 대용량 데이터 
+                                                오퍼레이션들을 필요로 하는 경우에 당신은 대개 내장 프로시저를 고려해야 할 것이다. 몇몇 해결책들이 
+                        <xref linkend="batch"/>에 보여져 있다. 사용자 세션 동안에 <literal>Session</literal>을 열려진 채로 
+                                                 유지하는 것은 또한 실효성이 떨어진 데이터에 대한 높은 확률을 의미한다.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="transactions-demarcation">
+        <title>데이터베이스 트랜잭션 경계 설정</title>
+
+        <para>
+                        데이터베이스 (또는 시스템) 트랜잭션 경계들은 항상 필수적이다. 데이터베이스와의 통신은 데이터베이스 트랜잭션의 외부에서 발생할 수 
+                        없다(이것은 자동-커밋 모드로 사용되는 많은 개발자들에게는 혼동스러워 보인다). 항상 심지어 읽기 전용 오퍼레이션들에 대해서도 명료한 
+                        트랜잭션 경계들을 사용하라. 당신의 격리 레벨과 데이터베이스 가용성들에 따라, 이것은 필요하지 않을 수 있지만, 만일 당신이 항상 
+                        트랜잭션들을 명시적으로 경계 설정할 경우에는 하강하는 결점들이 존재하지 않는다. 확실히, 하나의 데이터베이스 트랜잭션은 심지어 
+                        데이터 읽기조차도 많은 작은 트랜잭션들의 경우보다는 더 좋게 수행될 것이다.
+        </para>
+
+        <para>
+            Hibernate 어플리케이션은 관리되지 않는  환경(예를 들면. 스탠드얼론, 간단히 웹 어플리케이션들 또는 Swing 어플리케이션들)과 
+                        관리되는 J2EE 환경에서 실행될 수 있다. 관리되지 않는 환경에서, Hibernate는 대개 그것 자신의 데이터베이스 커넥션 풀에 대한 
+                        책임이 있다. 어플리케이션 개발자는 트랜잭션 경계들을 손수 설정해야 한다. 달리 말해, 개발자 스스로 데이터베이스 트랜잭션들을 
+                        시작하고, 커밋시키거나 롤백시켜야 한다. 관리되는 환경은  대개 예를 들어 EJB 세션 빈즈의 배치 디스크립터 속에 선언적으로 정의된 
+                        트랜잭션 어셈블리를 가진, 컨테이너에 의해-관리되는 트랜잭션들(CMT)을 제공한다. 그때 프로그램 상의 트랜잭션 경계 설정은 더 이상 필요하지 
+                        않다.
+        </para>
+
+        <para>           
+                        하지만, CMT 대신 BMT를 사용하는 JTA에 의존할 수 있는 시스템들, 그리고  관리되지 않는 resource-local 환경들 사이에서 
+                        당신의 영속 계층에 이식성을 유지시키는 것이 자주 희망된다. 두 경우들에서 당신은 프로그램 상의 트랜잭션 경계설정을 사용할 것이다.
+            Hibernate는 당신의 배치 환경의 고유한 트랜잭션 시스템 속으로 변환되는 <literal>Transaction</literal>이라 명명되는 
+            wrapper API 를 제공한다. 이 API는 실제로 옵션이지만 우리는 당신이 CMT session bean 속에 있지 않는 한 그것의 사용을 
+                        강력하게 권장한다.
+        </para>
+
+        <para>
+                        대개 <literal>Session</literal> 종료는 네 개의 구분되는 단계들을 수반한다:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                                        세션을 flush 시킨다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        트랜잭션을 커밋 시킨다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        세션을 닫는다
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                                        예외상황들을 처리한다
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+                        세션을 flush 시키는 것은 앞서 논의되었고, 우리는 이제 관리되는 환경과 관리되지 않는 환경 양자에서 트랜잭션 경계 설정과 예외상황을 
+                        더 자세히 살펴볼 것이다.
+        </para>
+
+
+        <sect2 id="transactions-demarcation-nonmanaged" revision="2">
+            <title>관리되지 않는 환경</title>
+
+            <para>
+                                만일 Hibernate 영속 계층이 관리되지 않는(non-managed) 환경에서 실행될 경우, 데이터베이스 커넥션들은 대개 Hibernate가
+                                필요로할 때 커넥션들을 획득하는 간단한 (예를 들면 DataSource가 아닌) 커넥션 풀(pool)들로부터 처리된다. 
+                session/transaction 처리 관용구는 다음과 같다:
+            </para>
+
+            <programlisting><![CDATA[// Non-managed environment idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+    tx = sess.beginTransaction();
+
+    // do some work
+    ...
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    if (tx != null) tx.rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+           <para>
+                                당신은 <literal>Session</literal>을 명시적으로 <literal>flush()</literal> 하지 말아야 한다 - 
+                <literal>commit()</literal>에 대한 호출은 (그 세션에 대한  
+                <xref linkend="objectstate-flushing">FlushMode</xref>에 따라)자동적으로 동기화를 트리거시킨다. 
+                <literal>close()</literal>에 대한 호출은 세션의 끝을 마크한다. <literal>close()</literal>의 
+                                주된 구현은 JDBC 커넥션이 그 세션에 의해 포기될 것이라는 점이다. 이 Java 코드는 관리되지 않는 환경과 
+                JTA 환경 양자에서 이식성이 있고 실행된다.
+            </para>
+
+           <para>
+                                보다 더 유연한 해결책은 앞서 설명했듯이 Hibernate의 미리 빌드되어 있는 "현재 세션" 컨텍스트 관리이다:
+           </para>
+
+            <programlisting><![CDATA[// Non-managed environment idiom with getCurrentSession()
+try {
+    factory.getCurrentSession().beginTransaction();
+
+    // do some work
+    ...
+
+    factory.getCurrentSession().getTransaction().commit();
+}
+catch (RuntimeException e) {
+    factory.getCurrentSession().getTransaction().rollback();
+    throw e; // or display error message
+}]]></programlisting>
+
+            <para>
+                                당신은 통상의 어플리케이션에서 비지니스 코드 속에 이 관용구를 결코 보지 않을 것이다; 치명적인(시스템) 예외상황들은 항상 
+                "상단"에서 잡혀야 한다. 달리 말해, (영속 계층에서) Hibernate 호출들을 실행시키는 코드와 <literal>RuntimeException</literal>을 
+                                처리하(고 대개 오직 제거하고 빠져나갈 수 있는) 코드는 다른 계층들 속에 있다. Hibernate에 의한 현재 컨텍스트 관리는 이 설계를 
+                                현격하게 단순화시켜서, 당신이 필요로 하는 모든 것은 <literal>SessionFactory</literal>에 대한 접근이다.예외상황 
+                                처리는 이 장의 뒷부분에서 논의된다.
+            </para>
+
+           <para>
+                                당신은 (디폴트인) <literal>org.hibernate.transaction.JDBCTransactionFactory</literal>를 선택해야 하고, 
+                                두번째 예제의 경우 당신의 <literal>hibernate.current_session_context_class</literal>를 선택해야 함을 노트하라.
+            </para>
+            
+        </sect2>
+
+        <sect2 id="transactions-demarcation-jta" revision="3">
+            <title>JTA 사용하기</title>
+
+            <para>
+                               만일 당신의 영속 계층이 어플리케이션 서버에서(예를 들어, EJB 세션 빈즈 이면에서) 실행될 경우, Hibernate에 의해 
+                               획득된 모든 데이터소스 커넥션은 자동적으로 전역 JTA 트랜잭션의 부분일 것이다. 당신은 또한 스탠드얼론 JTA 구현을 
+                               설치할 수 있고 EJB 없이 그것을 사용할 수 있다. Hibernate는 JTA 통합을 위한 두 개의 방도들을 제공한다.
+            </para>
+
+            <para>
+                                만일 당신이 bean-managed transactions(BMT)를 사용할 경우 Hibernate는 당신이 <literal>Transaction</literal> 
+                API를 사용할 경우에 BMT 트랜잭션을 시작하고 종료하도록 어플리케이션 서버에게 알려줄 것이다. 따라서 트랜잭션 관리 코드는 
+                non-managed 환경과 동일하다.
+            </para>
+            
+           <programlisting><![CDATA[// BMT idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+    tx = sess.beginTransaction();
+
+    // do some work
+    ...
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    if (tx != null) tx.rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+            <para>
+                               만일 당신이 트랜잭션에 묶인 <literal>Session</literal>, 즉 쉬운 컨텍스트 보급을 위한 
+               <literal>getCurrentSession()</literal> 기능을 사용하고자 원할 경우, 당신은 
+               JTA <literal>UserTransaction</literal> API를 직접 사용해야 할 것이다:
+            </para>
+
+            <programlisting><![CDATA[// BMT idiom with getCurrentSession()
+try {
+    UserTransaction tx = (UserTransaction)new InitialContext()
+                            .lookup("java:comp/UserTransaction");
+
+    tx.begin();
+
+    // Do some work on Session bound to transaction
+    factory.getCurrentSession().load(...);
+    factory.getCurrentSession().persist(...);
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    tx.rollback();
+    throw e; // or display error message
+}]]></programlisting>
+
+            <para>
+                CMT의 경우, 트랜잭션 관할[경계 설정]은 프로그램 상이 아닌, session bean 배치 디스크립터들 속에서 행해진다. 
+                                그러므로 코드는 다음으로 감소된다:
+            </para>
+
+            <programlisting><![CDATA[// CMT idiom
+ Session sess = factory.getCurrentSession();
+
+ // do some work
+ ...
+]]></programlisting>
+
+            <para>
+                                왜냐하면 하나의 세션 빈 메소드에 의해 던져진 처리되지 않은 <literal>RuntimeException</literal>이 
+                                글로벌 트랜잭션을 rollback으로 설정하도록 컨테이너에게 알려주기 때문에, CMT/EJB에서조차 롤백은 자동적으로 발생된다. 
+                <emphasis>이것은 당신이 BMT 이든 CMT이든 모두에서 Hibernate <literal>Transaction</literal> API를 사용할 필요가 
+                                없으며, 당신은 그 트랜잭션에 묶인 "현재" Session의 자동적인 보급(propagation)을 얻게 됨을 의미한다.</emphasis>
+            </para>
+
+            <para>
+                                당신이 Hibernate의 트랜잭션 팩토리를 구성할 때, 당신이 JTA를 직접 사용할 경우(BMT) 당신은 
+                <literal>org.hibernate.transaction.JTATransactionFactory</literal>를 선택해야하고, CMT session bean에서는 
+                <literal>org.hibernate.transaction.CMTTransactionFactory</literal>를 선택해야 함을 노트하라. 또한 
+                <literal>org.hibernate.transaction.manager_lookup_class</literal>를 설정하는 것을 염두에 두라. 게다가 
+                                반드시 당신의 <literal>hibernate.current_session_context_class</literal>이 설정되지 않도록 하거나(역호환성), 
+                                또는 <literal>"jta"</literal>로 설정되도록 하라.
+            </para>
+
+            <para>
+                <literal>getCurrentSession()</literal> 오퍼레이션들은 JTA 환경에서 한 가지 단점을 갖고 있다.
+                                디폴트로 사용되는, <literal>after_statement</literal> 커넥션 해제 모드 사용에 대한 하나의 보류 통보가 존재한다.
+                JTA 명세서의 어리석은 제한으로 인해, Hibernate가 <literal>scroll()</literal> 또는 <literal>iterate()</literal>에 
+                                의해 반환되는 임의의 닫혀지지 않은 <literal>ScrollableResults</literal> 또는 <literal>Iterator</literal> 
+                                인스턴스들을 자동적으로 제거하는 것이 불가능하다. 당신은 <literal>finally</literal> 블록 내에서 명시적으로 
+                <literal>ScrollableResults.close()</literal> 또는 <literal>Hibernate.close(Iterator)</literal>를 
+                                호출하여 기본 데이터베이스 커서를 해제<emphasis>시켜야 한다</emphasis>.(물론 대부분의 어플리케이션들은 JTA 또는 CMT  코드에서 
+                <literal>scroll()</literal>이나 <literal>iterate()</literal>를 사용하는 것을 쉽게 피할 수 있다.)
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-demarcation-exceptions">
+            <title>예외상황 처리</title>
+
+            <para>
+                                만일<literal>Session</literal>이 (어떤 <literal>SQLException</literal>을 포함하는) 예외상황을 던질 경우, 
+                                당신은 데이터베이스 트랜잭션을 즉시 롤백시키고, <literal>Session.close()</literal>를 호출하고 
+                <literal>Session</literal> 인스턴스를 폐기시켜야한다. <literal>Session</literal>의 어떤 메소드들은 
+                                그 세션을 일관된 상태로 남겨두지 <emphasis>않을</emphasis> 것이다. Hibernate에 의해 던져진 예외상황은 복구가능한 
+                                것으로 취급될 수 없다. 그 <literal>Session</literal>이  <literal>finally</literal> 블록 내에서 
+                <literal>close()</literal>를 호출하여 닫혀지도록 확실히 하라.
+            </para>
+
+            <para>
+                Hibernate 영속 계층에서 발생할 수 있는 대부분의 오류들을 포장하는, <literal>HibernateException</literal>은 
+                                체크되지 않은 예외상황이다(그것은 Hibernate의 이전 버전에는 없었다). 우리의 의견으로, 우리는 낮은 계층에서 복구불가능한 
+                                예외상황을 붙잡도록 어플리케이션 개발자에게 강제하지 않을 것이다. 대부분의 시스템들에서, 체크되지 않은 치명적인 예외상황들은 
+                (예를 들어, 더 높은 계층에서) 메소드 호출 스택의 첫 번째 프레임들 중 하나 속에서 처리되고, 한 개의 오류 메시지가 어플리케이션 
+                                사용자에게 표시된다(또는 어떤 다른 적절한 액션이 취해진다). Hibernate는 또한 <literal>HibernateException</literal>이 
+                                아닌, 다른 체크되지 않은 예외상황들을 던질 수도 있음을 노트하라. 다시 이것들은 복구가능하지 않고 적절한 액션이 취해져야 한다.
+            </para>
+
+            <para>
+                Hibernate는 데이터베이스와 상호작용하는 동안에 던져진 <literal>SQLException</literal>들을 하나의 
+                <literal>JDBCException</literal> 속에 포장한다. 사실, Hibernate는 그 예외상황을 
+                <literal>JDBCException</literal>의 보다 의미있는 서브클래스로 변환하려고 시도할 것이다. 기본 
+                <literal>SQLException</literal>은 <literal>JDBCException.getCause()</literal>를 통해 항상 이용 가능하다. 
+                Hibernate는<literal>SessionFactory</literal>에 첨부된 <literal>SQLExceptionConverter</literal>를 
+                                사용하여 <literal>SQLException</literal>을 적당한 하나의 <literal>JDBCException</literal> 서브클래스로 
+                                변환시킨다. 디폴트로 <literal>SQLExceptionConverter</literal>는 구성된 dialect에 의해 정의된다; 하지만 
+                                맞춤 구현 속에 플러그인 시키는 것이 또한 가능하다(상세한 것은 <literal>SQLExceptionConverterFactory</literal> 
+                                클래스에 관한 javadocs를 보라). 표준 <literal>JDBCException</literal> 서브타입은 다음과 같다:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>JDBCConnectionException</literal> - 기본 JDBC 통신에 대한 오류를 나타낸다.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>SQLGrammarException</literal> - 생겨난 SQL에 대한 문법 또는 구문 문제점을 나타낸다.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>ConstraintViolationException</literal> - 무결성 제약 위반에 관한 어떤 형식을 나타낸다.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>LockAcquisitionException</literal> - 요청된 오퍼레이션을 실행하는데 필수적인 잠금 레벨을 
+                                                획득하는 오류를 나타낸다.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>GenericJDBCException</literal> - 다른 카테고리들 중 어떤 것으로 분류되지 않았던 일반적인 예외상황.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+        </sect2>
+
+        <sect2 id="transactions-demarcation-timeout">
+            <title>트랜잭션 타임아웃</title>
+
+            <para>
+                                관리되지 않는 코드에 대해서는 결코 제공되지 않는 EJB와 같이 관리되는 환경에 의해 제공되는 한 가지 극히 
+                                중요한 특징은 트랜잭션 타임아웃이다. 트랜잭션 타임아웃은 사용자에게 응답을 반환하지 않는 동안에 
+                                무례한 행동을 행하는 트랜잭션이 자원들을 무한정 묶어둘 수 없음을 보증해준다. 관리되는 (JTA) 환경 
+                                외부에서, Hibernate는 이 기능을 온전하게 제공할 수 없다. 하지만 Hibernate는 데이터베이스 
+                                레벨 데드락들과 거대한 결과 셋들을 가진 질의들이 정의된 타임아웃에 의해 제약되는 것을 보장함으로써 
+                                최소한 데이터 접근 오퍼레이션들을 제어할 수 있다. 관리되는 환경에서, Hibernate는 트랜잭션 타임아웃을 
+                JTA에게 위임시킬 수 있다. 이 기능은 Hibernate <literal>Transaction</literal> 객체에 의해 
+                                추상화 된다.
+            </para>
+            
+            <programlisting><![CDATA[
+Session sess = factory.openSession();
+try {
+    //set transaction timeout to 3 seconds
+    sess.getTransaction().setTimeout(3);
+    sess.getTransaction().begin();
+
+    // do some work
+    ...
+
+    sess.getTransaction().commit()
+}
+catch (RuntimeException e) {
+    sess.getTransaction().rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+            <para>
+                <literal>setTimeout()</literal>은  CMT bean 내에서 호출도리 수 없음을 노트하라. 
+                                여기서 트랜잭션 타임아웃들은 선언적으로 정의되어야 한다.
+            </para>
+            
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="transactions-optimistic">
+        <title>Optimistic 동시성 제어</title>
+
+        <para>
+                        고도의 동시성과 고도의 가용성을 일치시키는 유일한 접근법은 버전화를 가진 optimistic동시성 제어이다. 버전 체킹은 업데이트 충돌을 
+                        검출하기 위해(그리고 업데이트 손실을 방지하기 위해) 버전 번호들 또는 timestamp들을 사용한다. Hibernate는 optimistic 동시성을 
+                        사용하는 어플리케이션 코드 작성에 세 가지 가능한 접근법들을 제공한다. 우리가 보여주는 쓰임새들은 장시간의 대화의 상황 
+                        속에 있지만, 버전 체킹 또한 단일 데이터베이스 트랜잭션들에서 업데이트 손실을 방지하는 이점을 갖고 있다.
+        </para>
+
+        <sect2 id="transactions-optimistic-manual">
+            <title>어플리케이션 버전 체킹</title>
+
+            <para>
+                                하나의 구현에서 Hibernate로부터 많은 도움이 없이, 데이터베이스에 대한 각각의 상호작용은 새로운 <literal>Session</literal> 
+                                내에서 일어나고, 개발자는 영속 인스턴스들을 처리하기 전에 데이터베이스로부터 모든 영속 인스턴스들을 다시 로드시킬 책임이 있다. 
+                                이 접근법은 대화 트랜잭션을 확실히 격리시키기 위해 그것 자신의 버전 체킹을 수행하도록 어플리케이션에게 강제시킨다. 
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+
+int oldVersion = foo.getVersion();
+session.load( foo, foo.getKey() ); // load the current state
+if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();
+foo.setProperty("bar");
+
+t.commit();
+session.close();]]></programlisting>
+
+            <para>
+                version 프로퍼티는 <literal>&lt;version&gt;</literal>을 사용하여 매핑되고, Hibernate는 만일 엔티티가 dirty일 경우 
+                flush 동안에 그것을 자동적으로 증가시킬 것이다.
+            </para>
+
+            <para>
+                                물론, 당신이 낮은 데이터 동시성 환경에서 작업하고 있고 버전 체킹을 필요로 하지 않을 경우에, 당신은 이 접근법을 사용할 수 도 있고 
+                                단지 버전 체크를 생략할 수도 있다. 그 경우에, <emphasis>마지막의 커밋 성공</emphasis>은 당신의 장시간의 대화에 
+                                대한 디폴트 방도가 될 것이다. 이것이 어플리케이션의 사용자들을 혼동시킬 수 있음을 염두에 두라. 왜냐하면 사용자들은 오류 메시지들 
+                                또는 충돌 변경들을 병합시킬 기회 없이 업데이트들 손실을 겪을 수도 있기 때문이다.
+            </para>
+
+            <para>
+                                명료하게 수작업 버전 체킹은 매우 사소한 환경들에서도 공포적이고 대부분의 어플리케이션들에 대해 실제적이지 않다. 흔히 단일 
+                                인스턴스 뿐만 아니라 변경된 객체들의 전체 그래프들이 체크되어야 한다. Hibernate는 설계 패러다임으로서 하나의 확장된 <literal>Session</literal> 
+                                또는 detached 인스턴스들에 대해 자동적인 버전 체킹을 제공한다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-longsession">
+            <title>확장된 세션과 자동적인 버전화</title>
+
+            <para>
+                                하나의 <literal>Session</literal> 인스턴스와 그것의 영속 인스턴스들은 전체 어플리케이션 트랜잭션에 사용된다. Hibernate는 
+                flush 할 때 인스턴스 버전들을 체크하고 만일 동시성 변경이 검출될 경우에 예외상황을 던진다. 이 예외상황을 잡아내고 처리하는 것을 
+                                개발자의 몫이다(공통된 옵션들은 변경들을 병합시키거나 또는 쓸모가 없지 않은 데이터로 비지니스 프로세스를 다시 시작하는 기회를 
+                                사용자에게 주는 것이다). 
+                                하나의 <literal>Session</literal> 인스턴스와 그것의 영속 인스턴스들은 <emphasis>session-per-conversation</emphasis>로 
+                                알려진 전체 대화에 사용된다. Hibernate는 flush 시점에서 인스턴스 버전들을 체크하며, 만일 동시적인 변경이 검출될 경우에 
+                                하나의 예외상황을 던진다. 이 예외상황을 포착하고 처리하는 것은 개발자의 몫이다(공통된 옵션들은 사용자가 변경들을 병합하거나 
+                                손실되지 않은 데이터를 가지고 비지니스 대화를 재시작하는 기회이다).
+            </para>
+
+            <para>
+                <literal>Session</literal>은 사용자 상호작용을 기다릴 때 어떤 기본 JDBC 커넥션으로부터 연결해제된다. 이 접근법은 
+                                데이터베이스 접근의 관점에서 보면 가장 효율적이다. 어플리케이션은 버전 체킹 또는 detached 인스턴스들을 재첨부하는 것에 
+                                그 자체 관계할 필요가 없거나 그것은 모든 데이터베이스 트랜잭션에서 인스턴스들을 다시 로드시킬 필요가 없다.
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded earlier by the old session
+Transaction t = session.beginTransaction(); // Obtain a new JDBC connection, start transaction
+
+foo.setProperty("bar");
+
+session.flush();    // Only for last transaction in conversation
+t.commit();         // Also return JDBC connection
+session.close();    // Only for last transaction in conversation]]></programlisting>
+            <para>
+                <literal>foo</literal> 객체는 그것이 로드되었던 <literal>Session</literal>이 어느 것인지를 여전히 알고 있다.
+                                이전 세션 상에서 하나의 새로운 데이터베이스 트랜잭션을 시작하는 것은 하나의 새로운 커넥션을 획득하고 그 세션을 소비한다.
+                                데이터베이스 트랜잭션을 커밋(확약)시키는 것은 그 JDBC 커넥션으로부터 하나의 세션을 연결해제시키고 그 커넥션을 풀(pool)로 
+                                반환시킬 것이다. 재연결 후에, 당신이 업데이트하고 있지 않은 데이터에 대한 버전 체크를 강제시키기 위해서, 당신은 
+                                또 다른 트랜잭션에 의해 업데이트되었을 수도 있는 임의의 객체들에 대해 <literal>LockMode.READ</literal>로서 
+                <literal>Session.lock()</literal>을 호출할 수도 있다. 당신은 당신이 업데이트 중인 임의의 데이터를 잠금할 필요가 없다.
+                                대개 당신은 마지막 데이터베이스 트랜잭션 주기만이 이 대화 내에서 행해진 모든 변경들을 실제로 영속화시키는 것이 허용되도록 하기 위해, 
+                                하나의 확장된 <literal>Session</literal>에 대해 <literal>FlushMode.NEVER</literal>를 설정할 것이다.
+                                그러므로 오직 이 마지막 데이터베이스 트랜잭션 만이 <literal>flush()</literal> 오퍼레이션을 포함할 것이고, 또한 
+                                대화를 종료시키기 위해 세션을 <literal>close()</literal>할 것이다.
+            </para>
+            
+            <para>
+                                 만일 사용자가 생각하는시간 동안 <literal>Session</literal>이 저장되기에 너무 큰 경우 이 패턴은 문제성이 있다. 예를 들어 
+                <literal>HttpSession</literal>은 가능한 작은 것으로 유지되어야 한다. 또한  <literal>Session</literal>은 (필수의) 
+                                첫 번째 레벨 캐시이고 모든 로드된 객체들을 포함하기 때문에, 우리는 아마 적은 요청/응답 주기들에 대해서만 이 방도를 사용할 수 있다.
+                                당신은 하나의 대화에 대해서만 하나의  <literal>Session</literal>을 사용해야 한다. 왜냐하면 그것은 또한 곧 실없는 데이터가 
+                                될 것이기 때문이다.
+            </para>
+
+            <para>
+                (초기의 Hibernate 버전들은 <literal>Session</literal>에 대한 명시적인 연결해제와 재연결을 필요로 했음을 
+                                노트하라. 트랜잭션을 시작하고 끝내는 것이 동일한 효과를 가지므로, 이들 방법들은 진부하게 되었다.) 
+            </para>
+
+            <para>        
+                                또한 당신은 영속 계층에 대해 연결해제된 <literal>Session</literal>을 닫혀진채로 유지해야함을 노트하라. 달
+                                리말해, 하나의 3-tier 환경에서 <literal>Session</literal>을 소유하는데 EJB stateful session bean을 
+                                사용하고, <literal>HttpSession</literal> 내에 그것을 저장하기 위해 그것을 웹 계층에 전송하지 말라
+                (또는 그것을 별도의 티어에 직렬화 시키지도 말라).
+            </para>
+            
+            <para>
+                                확장된 세션 패턴, 또는 <emphasis>session-per-conversation</emphasis>은 자동적인 현재 세션 컨텍스트 관리에 대해
+                                구현하기가 더 어렵다. 당신은 이를 위해 당신 자신의 <literal>CurrentSessionContext</literal> 구현을 공급할 필요가 
+                                있으며, 예제들은 Hibernate Wiki를 보라.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-detached">
+            <title>Detached 객체들과 자동적인 버전화</title>
+
+            <para>
+                                영속 저장소에 대한 각각의 상호작용은 새로운 <literal>Session</literal>에서 일어난다. 하지만 동일한 영속 인스턴스들은 
+                                데이터베이스와의 각각의 상호작용에 재사용된다. 어플리케이션은 원래 로드되었던 detached 인스턴스들의 상태를 또 다른 
+                <literal>Session</literal> 내에서 처리하고 나서 <literal>Session.update()</literal>, 
+                <literal>Session.saveOrUpdate()</literal>, <literal>Session.merge()</literal>를 사용하여 그것들을 
+                               다시 첨부시킨다.
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+foo.setProperty("bar");
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded already
+t.commit();
+session.close();]]></programlisting>
+
+            <para>
+                                다시, Hibernate는 flush 동안에 인스턴스 버전들을 체크할 것이고 업데이트 충돌이 발생할 경우에 예외상황을 던질 것이다.
+            </para>
+
+            <para>
+                                당신은 또한 <literal>update()</literal>대신에 <literal>lock()</literal>을 호출할 수도 있고 만일 그 객체가 
+                                변경되지 않았음을 당신이 확신하는 경우에 (버전 체킹을 수행하고 모든 캐시들을 무시하는) <literal>LockMode.READ</literal>를 
+                                사용할 수 있다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-customizing">
+            <title>자동적인 버전화를 맞춤화 시키기</title>
+
+            <para>
+                                당신은 <literal>optimistic-lock</literal> 매핑 속성을 <literal>false</literal>로 설정함으로써 특정 프로퍼티들과 
+                                콜렉션들에 대한 Hibernate의 자동적인 버전 증가를 불가능하도록 할 수도 있다. 그때 Hibernate는 그 프로퍼티가 dirty 일 경우에 
+                                더 이상 버전을 증가시키지 않을 것이다.
+            </para>
+
+            <para>
+                                리거시 데이터베이스 스키마들은 자주 static이고 변경될 수 없다. 또는 다른 어플리케이션들은 또한 동일한 데이터베이스에 접근하고 
+                                버전 번호들 또는 심지어 timestamp들을 처리하는 방법을 모를 수도 있다. 두 경우들에서, 버전화는 테이블 내의 특정 컬럼에 의지할 수 
+                                없다. version 또는 timestamp 프로퍼티 매핑 없이 행 내의 모든 필드들에 대한 상태를 비교하여 버전 체크를 강제시키기 위해서, 
+                <literal>&lt;class&gt;</literal> 매핑 속에 <literal>optimistic-lock="all"</literal>을 표시하라. 만일 
+                Hibernate가 이전 상태와 새로운 상태를 비교할 수 있을 경우에, 예를 들면 당신이 하나의 긴 <literal>Session</literal>을 
+                                사용하고 session-per-request-with-detached-objects을 사용하지 않을 경우 이것은 개념적으로만 동작함을 노트하라.
+            </para>
+
+            <para>
+                                때때로 행해졌던 변경들이 중첩되지 않는 한 동시적인 변경이 허용될 수 있다. 만일 <literal>&lt;class&gt;</literal>를 
+                                매핑할 때 당신이 <literal>optimistic-lock="dirty"</literal>를 설정하면, Hibernate는 flush 동안에 dirty 필드들을 
+                                비교만 할 것이다.
+            </para>
+
+            <para>
+                                두 경우들에서, 전용 version/timestamp 컬럼의 경우 또는 full/dirty 필드 비교의 경우, Hibernate는 법전 체크를 실행하고 
+                                정보를 업데이트하는데 엔티티 당 (적절한 <literal>WHERE</literal> 절을 가진) 한 개의<literal>UPDATE</literal> 
+                                문장을 사용한다. 만일 당신이 연관된 엔티티들에 대한 재첨부를 케스케이드 하는데 transitive 영속을 사용할 경우, 
+                Hibernate는 불필요하게 업데이트들을 실행할 수도 있다. 이것은 대개 문제가 아니지만, 심지어 변경들이 detached 인스턴스들에 
+                                대해 행해지지 않았을 때에도 데이터베이스 내에서 <emphasis>on update</emphasis> 트리거들이 실행될 수도 있다. 그 행을 
+                                업데이트하기 전에 변경들이 실제로 일어났음을 확인하기 위해 인스턴스를 <literal>SELECT</literal>하는 것을 Hibernate에게 
+                                강제시키는, <literal>&lt;class&gt;</literal> 매핑 속에 <literal>select-before-update="true"</literal>를 
+                                설정함으로써 당신은 이 특징을 맞춤화 시킬 수 있다.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="transactions-locking">
+        <title>Pessimistic 잠금</title>
+
+        <para>
+                        사용자들은 잠금 방도에 대해 걱정하는데 많은 시간을 할애하하려고 생각하지 않는다. 대개 JDBC 커넥션들에 대한 격리 레벨을 지정하는 
+                        것으로 충분하고 그런 다음 단순히 데이터베이스로 하여금 모든 작업을 행하도록 한다. 하지만 진일보한 사용자들은 때때로 배타적인 
+            pessimistic 잠금들을 얻거나 또는 새로운 트랜잭션의 시작 시에 잠금들을 다시 얻고자 원할 수도 있다.
+        </para>
+
+        <para>
+            Hibernate는 결코 메모리 내에 있는 객체들이 아닌, 데이터베이스의 잠금 메커니즘을 항상 사용할 것이다!
+        </para>
+
+        <para>
+            <literal>LockMode</literal> 클래스는 Hibernate에 의해 획득될 수 있는 다른 잠금 레벨들을 정의한다. 잠금은 다음 메커니즘들에 
+                        의해 얻어진다:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>LockMode.WRITE</literal>는 Hibernate가 한 행을 업데이트 하거나 insert 할 때 자동적으로 획득된다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.UPGRADE</literal>는 <literal>SELECT ... FOR UPDATE</literal> 구문을 지원하는 
+                                        데이터베이스 상에서 <literal>SELECT ... FOR UPDATE</literal>를 사용하여 명시적인 사용자 요청 상에서 
+                                        얻어질 수 있다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.UPGRADE_NOWAIT</literal>는 오라클에서 <literal>SELECT ... FOR UPDATE NOWAIT</literal>를 
+                                        사용하여 명시적인 사용자 요청 상에서 얻어질 수도 있다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.READ</literal>는 Hibernate가 반복 가능한 읽기(Repeatable Read) 또는 Serialization 
+                                        격리 레벨에서 데이터를 읽어들일 때 자동적으로 얻어질 수도 있다. 명시적인 사용자 요청에 의해 다시 얻어질 수도 있다.
+                </para>
+            </listitem>
+        <listitem>
+        <para>
+            <literal>LockMode.NONE</literal>은 잠금이 없음을 나타낸다. 모든 객체들은 <literal>Transaction</literal>의 끝에서 
+                        이 잠금 모드로 전환된다. <literal>update()</literal> 또는 <literal>saveOrUpdate()</literal>에 대한 호출을 통해 
+                        세션과 연관된 객체들이 또한 이 잠금 모드로 시작된다.
+        </para>
+        </listitem>
+        </itemizedlist>
+
+        <para>
+            "명시적인 사용자 요청"은 다음 방법들 중 하나로 표현된다:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>LockMode</literal>를 지정한 <literal>Session.load()</literal>에 대한 호출.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>Session.lock()</literal>에 대한 호출.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>Query.setLockMode()</literal>에 대한 호출.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+                        만일 <literal>Session.load()</literal>가 <literal>UPGRADE</literal> 또는 <literal>UPGRADE_NOWAIT</literal> 
+                        모드로 호출되고 ,요청된 객체가 아직 이 세션에 의해 로드되지 않았다면, 그 객체는 <literal>SELECT ... FOR UPDATE</literal>를 
+                        사용하여 로드된다. 만일 요청된 것이 아닌 다소 제한적인 잠금으로 이미 로드되어 있는 객체에 대해 <literal>load()</literal>가 
+                        호출될 경우, Hibernate는 그 객체에 대해 <literal>lock()</literal>을 호출한다.
+        </para>
+
+        <para>
+                        만일 지정된 잠금 모드가 <literal>READ</literal>, <literal>UPGRADE</literal> 또는 
+            <literal>UPGRADE_NOWAIT</literal> 일 경우에 <literal>Session.lock()</literal>은 버전 번호 체크를 수행한다.
+            (<literal>UPGRADE</literal> 또는 <literal>UPGRADE_NOWAIT</literal> 인 경우에, 
+            <literal>SELECT ... FOR UPDATE</literal>가 사용된다.)
+        </para>
+
+        <para>
+                        만일 데이터베이스가 요청된 잠금 모드를 지원하지 않을 경우, (예외상황을 던지는 대신에) Hibernate는 적절한 대체 모드를 사용할 것이다. 
+                        이것은 어플리케이션이 이식 가능할 것임을 확실히 해준다.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="transactions-connection-release">
+        <title>연결 해제 모드들</title>
+
+        <para>
+            JDBC 커넥션 관리에 관한 Hibernate의 리거시(2.x) 특징은 그것이 처음으로 필요로 했을 때
+                        하나의 <literal>Session</literal>이 하나의 커넥션을 획득할 것이고, 그런 다음 그 커넥션은 그 세션이 
+                        닫혀질때까지 보관된다는 것이었다. 
+            Hibernate 3.x는 세션에게 그것의 JDBC 커넥션들을 처리하는 방법을 알려주기 위해 연결 해제 모드들에 관한 
+                        개념을 도입했다. 다음 논의는 구성된 <literal>ConnectionProvider</literal>를 통해 제공되는 커넥션들에 
+                        대해서만 적절하다는 점을 노트하라; 사용자가 제공하는 커넥션들은 
+            <literal>org.hibernate.ConnectionReleaseMode</literal>의 열거된 값들에 의해 식별된다:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>ON_CLOSE</literal> - 는 본질적으로 위에 설명된 리거시 특징이다. Hibernate 세션은 그것이 
+                                        어떤 JDBC 접근을 수행하고 세션이 닫혀질 때까지 그 커넥션을 보관할 필요가 있을 때 하나의 커넥션을 획득한다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>AFTER_TRANSACTION</literal> - 은 하나의 
+                    <literal>org.hibernate.Transaction</literal>이 완료된 후에 연결들을 해제하라고 말한다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>AFTER_STATEMENT</literal> (또한 적극적인 해제라고 언급됨) - 는 각각의 모든 문장 실행 후에 
+                                        커넥션들을 해제하라고 말한다. 이 적극적인 해제는 그 문장이 주어진 세션과 연관된 리소스들을 열려진채로 남겨둘 
+                                        경우에는 건너뛰게(skip) 된다; 현재 이것이 일어나는 유일한 상황은 
+                    <literal>org.hibernate.ScrollableResults</literal>의 사용을 통해서이다.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+                        사용할 해제 모드를 지정하기 위해 구성 파라미터 <literal>hibernate.connection.release_mode</literal>가 사용된다.
+                        가능한 값들은 다음과 같다:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>auto</literal> (디폴트) - 이 선택은 
+                    <literal>org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode()</literal> 
+                                        메소드에 의해 반환된 해제 모드로 위임시킨다. JTATransactionFactory인 경우, 이것은 
+                    ConnectionReleaseMode.AFTER_STATEMENT를 반환한다;  JDBCTransactionFactory인 경우, 이것은 
+                    ConnectionReleaseMode.AFTER_TRANSACTION을 반환한다. 이 설정의 값이 사용자 코드 내의 버그들 그리고/또는 
+                                        유효하지 않은 가정들을 가리키는 경향이 있음으로 인해 이 디폴트 특징을 실패로 변경하는 것은 거의 좋은 생각이 아니다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>on_close</literal> - 는 ConnectionReleaseMode.ON_CLOSE를 사용하라고 말한다. 이 설정은 
+                                        역호환성을 위해 남겨졌지만, 그것의 사용은 매우 권장되지 않는다.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>after_transaction</literal> - 은 ConnectionReleaseMode.AFTER_TRANSACTION을 사용하라고 말한다.
+                                        이 설정은 JTA 환경들에서 사용되지 않을 것이다. 또한 
+                    ConnectionReleaseMode.AFTER_TRANSACTION인 경우에 만일 세션이 auto-commit 모드에 있도록 고려될 경우, 
+                                        커넥션들은 마치 해제 모드가 AFTER_STATEMENT인 것처럼 해제될 것임을 또한 노트하라.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>after_statement</literal> - 는 ConnectionReleaseMode.AFTER_STATEMENT를 사용하라고 말한다.
+                                        추가적으로 구성된 <literal>ConnectionProvider</literal>는 그것이 이 설정
+                    (<literal>supportsAggressiveRelease()</literal>)을 지원하는지 여부를 알기 위해 참고된다. 
+                                        만일 지원하지 않을 경우, 해제 모드는 ConnectionReleaseMode.AFTER_TRANSACTION으로 재설정된다. 이 설정은 
+                                        우리가 <literal>ConnectionProvider.getConnection()</literal>을 호출할 때마다 우리가 동일한 기본 JDBC 
+                                        커넥션을 다시 필요로 할 수 있는 환경들에서 또는 우리가 동일한 커넥션을 얻는 것에 상관없는 auto-commit 환경에서 오직 
+                                        안전하다.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/tutorial.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/tutorial.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/tutorial.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1486 @@
+<chapter id="tutorial">
+    <title>Hibernate 개요</title>
+    
+    <sect1 id="tutorial-intro" revision="1">
+        <title>머리말</title>
+        
+        <para>
+                        이 장은 Hibernate 초심자를 위한 개론적인 튜토리얼이다.  우리는 메모리-내 데이터베이스를  
+                        사용하는 간단한 명령 라인 어플리케이션으로 시작하고 단계들을 이해하도록 쉽게 그것을 개발한다.
+        </para>
+
+        <para>
+                        이 튜토리얼은 Hibernate 신규 사용자들을 의도하고 있지만 Java와 SQL 지식을 필요로 한다. 
+                        그것은 Michael Gloegl이 작성한 튜토리얼에 기초하며, 우리가 명명하는 제 3의 라이브러리들은
+            JDK 1.4와 5.0 버전용이다. 당신은 JDK1.3에 대해 다른 라이브러리들을 필요로 할 수도 있다.
+        </para>
+
+        <para>
+                        튜토리얼용 소스는 <literal>doc/reference/tutorial/</literal> 디렉토리 내에 있는
+                        배포본 내에 포함되어 있다.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="tutorial-firstapp" revision="2">
+        <title>파트 1 - 첫 번째  Hibernate 어플리케이션</title>
+
+        <para>
+                        먼저, 우리는 한 개의 간단한 콘솔-기반 Hibernate 어플리케이션을 생성시킬 것이다. 우리는 메모리-내 
+                        데이터베이스(HSQL DB)를 사용하므로, 우리는 어떤 데이터베이스 서버를 설치하지 않아도 된다.
+        </para>
+
+        <para>
+                        우리가 우리가 수반하고자 원하는 이벤트들을 저장할 수 있는 작은 데이터베이스 어플리케이션과 이들 
+                        이벤트들의 호스트들에 대한 정보를 필요로 한다고 가정하자.
+        </para>
+            
+        <para>
+                        우리가 행할 첫 번째 것은 우리의 개발 디렉토리를 설정하고, 우리가 필요로 하는 모든 Java 라이브러리들을 
+                        그것 속에 집어 넣는 것이다. Hibernate 웹 사이트로부터 Hibernate 배포본을 내려 받아라. 패키지를 
+                        추출해내고 <literal>/lib</literal> 속에서 발견되는 모든 필요한 라이브러리들을 당신의 새로운 개발 작업 
+                        디렉토리의 <literal>/lib</literal> 디렉토리 속에 위치지워라. 그것은 다음과 같을 것이다:
+        </para>
+            
+        <programlisting><![CDATA[.
++lib
+  antlr.jar
+  cglib.jar
+  asm.jar
+  asm-attrs.jars
+  commons-collections.jar
+  commons-logging.jar
+  hibernate3.jar
+  jta.jar
+  dom4j.jar
+  log4j.jar ]]></programlisting>
+
+        <para>
+                        이것은 <emphasis>글의 작성 시점에서</emphasis> Hibernate에 필수적인 최소한의 세트이다(우리는 
+                        또한 메인 아카이브인 hibernate3.jar를 복사했음을 노트하라). 당신이 사용 중인 Hibernate 배포본이 
+                        더 많거나 보다 적은 라이브러리들을 필요로 할 수도 있다. 필수 라이브러리들과  선택적인 제3의 라이브러리들에 대한  
+                        추가 정보는 Hibernate 배포본의 <literal>lib/</literal> 디렉토리 내에 있는 <literal>README.txt</literal>
+                        파일을 보라. (실제로, Log4j는 필수는 아니지만 많은 개발자들에 의해 선호된다.)
+        </para>
+
+        <para>
+                        다음으로 우리는 우리가 데이터베이스 속에 저장시키고자 원하는 이벤트를 표현하는 한 개의 클래스를 생성시킨다.
+        </para>
+      
+        <sect2 id="tutorial-firstapp-firstclass" revision="1">
+            <title>첫 번째 클래스</title>
+            
+            <para>
+                                우리의 첫 번째 영속 클래스는 몇몇 프로퍼티들을 가진 간단한 자바빈즈 클래스이다:
+            </para>
+
+             <programlisting><![CDATA[package events;
+
+import java.util.Date;
+
+public class Event {
+    private Long id;
+
+    private String title;
+    private Date date;
+
+    public Event() {}
+
+    public Long getId() {
+        return id;
+    }
+
+    private void setId(Long id) {
+        this.id = id;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+}]]></programlisting>
+
+            <para>
+                                당신은 이 클래스가 프로퍼티 getter와 setter 메소드들에 대한 표준 자바빈즈 명명법들 뿐만 아니라 필드들에 대한 
+                private 가시성을 사용하고 있음을 알 수 있다. 이것은 권장되는 설계이지만, 필수적이지는 않다. Hibernate는 
+                                또한 필드들에 직접 접근할 수 있으며, accessor 메소드들의 이점은 강건한 리팩토링이다. 아규먼트 없는 생성자는 
+                reflection을 통해 이 클래스의 객체를 초기화 시킬 필요가 있다.
+            </para>
+
+            <para>
+                <literal>id</literal> 프로퍼티는 특별한 이벤트를 위한 유일 식별자를 소유한다. 모든 영속 엔티티 클래스들
+                (보다 덜 중요한 종속 클래스들도 존재한다)은  우리가 Hibernate의 전체 특징 집합을 사용하고자 원할 경우에 
+                                그런 식별자 프로퍼티를 필요로 할 것이다. 사실 대부분의 어플리케이션들(특히 웹 어플리케이션들)은 식별자에 의해 
+                                객체들을 구분지을 필요가 있어서, 당신은  이것을 어떤 제약점이라기 보다는 하나의 특징으로 간주할 것이다. 하지만 
+                                우리는 대개 객체의 항등(identity)를 처리하지 않으므로, setter 메소드는 private이어야 한다. 객체가 저장될 때, 
+                Hibernate는 단지 식별자들을 할당할 것이다. 당신은 Hibernate가 public, private, protected 접근자 메소드들 
+                                뿐만 아니라 (public, private, protected) 필드들에도 직접 접근할 수 있음을 알 수 있다. 선택은 당신에게 달려
+                                있으며, 당신은 당신의 어플리케이션 설계에 적합하도록 그것을 부합시킬 수 있다.
+            </para>
+
+            <para>
+                                아규먼트 없는 생성자는 모든 영속 클래스들에 대한 필요조건이다; Hibernate는 당신을 위해 Java Reflection을 
+                                사용하여 객체들을 생성시켜야 한다. 하지만 생성자는 private 일 수 있고, 패키지 가시성은 런타임 프락시 생성과 
+                                바이트코드 방편 없는 효율적인 데이터 검색에 필요하다.
+            </para>
+
+            <para>
+                                이 Java 소스 파일을 개발 폴더 내의 <literal>src</literal>로 명명된 디렉토리 속에 있는 위치지워라. 이제
+                                그 디렉토리는 다음과 같을 것이다:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java]]></programlisting>
+
+            <para>
+                                다음 단계에서, 우리는 Hiberante에게 이 영속 클래스에 대해 알려 준다.
+            </para>
+                
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-mapping" revision="1">
+            <title>The mapping file</title>
+
+            <para>
+                Hibernate는 영속 크래스들에 대한 객체들을 로드시키고 저장시키는 방법을 알 필요가 있다. 
+                                이곳은 Hibernate 매핑 파일이 역할을 행하는 곳이다. 매핑 파일은 Hibernate가 접근해야 하는 
+                                데이터베이스 내의 테이블이 무엇인지, 그리고 그것이 사용해야 하는 그 테이블 내의 컬럼들이 
+                                무엇인지를 Hibernate에게 알려준다.
+            </para>
+
+            <para>
+                                매핑 파일의 기본 구조는 다음과 같다:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+[...]
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Hibernate DTD는 매우 정교하다. 당신은 당신의 편집기 또는 IDE 내에서 XML 매핑 요소들과 속성들에
+                                대한 자동 완성 기능을 위해 그것을 사용할 수 있다. 당신은 또한 당신의 텍스트 편집기 내에 DTD 파일을
+                                열 수 있을 것이다 - 그것은 모든 요소들과 속성들에 대한 전체상을 얻고 디폴트들 뿐만 아니라 몇몇 주석들을
+                                보는 가장 손쉬운 방법이다. Hibernate는 웹으로부터 DTD 파일을 로드시키지 않지만, 먼저 어플리케이션의
+                classpath 경로로부터 그것을 먼저 룩업할 것임을 노트하라. DTD 파일은 <literal>hibernate3.jar</literal> 
+                                속에 포함되어 있을 뿐만 아니라 Hibernate 배포본의 <literal>src/</literal> 디렉토리 속에 포함되어 
+                                있다.
+            </para>
+
+            <para>
+                                우리는 코드를 간략화 시키기 위해 장래의 예제에서 DTD 선언을 생략할 것이다. 그것은 물론 옵션이 아니다.
+            </para>
+
+            <para>
+                                두 개의 <literal>hibernate-mapping</literal> 태그들 사이에  <literal>class</literal> 요소를 
+                                포함시켜라. 모든 영속 엔티티 클래스들(다시금 종속 클래스들일 수 있고, 그것은 첫번째-급의 엔티티들이 아니다)은 
+                SQL 데이터베이스 내의 테이블에 대한 그런 매핑을 필요로 한다:
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                                지금까지 우리는 그 테이블 내에 있는 한 행에 의해 표현된 각각의 인스턴스인, 클래스의 객체를 영속화 시키고 
+                                로드시키는 방법을 Hibernate에게 알려주었다. 이제 우린느 테이블 프라이머리 키에 대한 유일 식별자 프로퍼티 매핑을 
+                                계속 행한다. 게다가 우리는 이 식별자를 처리하는 것에 주의를 기울이고자 원하지 않으므로, 우리는 대용 키 프라이머리 키 
+                                컬럼에 대한 Hibernate의 식별자 생성 방도를 구성한다:
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="native"/>
+        </id>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                <literal>id</literal> 요소는 식별자 프로퍼티의 선언이고, <literal>name="id"</literal>는  
+                Java 프로퍼티의 이름을 선언한다 - Hibernate는 그 프로퍼티에 접근하는데 getter 및 setter 메소드들을 
+                                사용할 것이다. column 속성은 우리가 <literal>EVENTS</literal> 테이블의 어느 컬럼을 이 프라이머리 키로 
+                                사용하는지를 Hibernate에게 알려준다. 내포된 <literal>generator</literal> 요소는 식별자 생성 방도를 
+                                지정하며, 이 경우에 우리는 <literal>increment</literal>를 사용했고, 그것은 대개 테스팅(과 튜토리얼들)에 
+                                유용한 매우 간단한 메모리-내 숫자 증가 방법이다. Hibernate는 또한 전역적으로 유일한 데이터베이스에 의해 생성된
+                                식별자 뿐만 아니라 어플리케이션에 의해 할당된 식별자(또는 당신이 확장으로 작성한 어떤 방도)를 지원한다.  
+            </para>
+
+            <para>
+                                마지막으로 우리는 매핑 파일 속에서 클래스의 영속 프로퍼티들에 대한 선언들을 포함한다. 디폴트로, 클래스의
+                                프로퍼티들은 영속적인 것으로 간주되지 않는다:
+            </para>
+            
+            <programlisting><![CDATA[
+<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="native"/>
+        </id>
+        <property name="date" type="timestamp" column="EVENT_DATE"/>
+        <property name="title"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+            
+            <para>
+                <literal>id</literal> 요소의 경우처럼, <literal>property</literal> 요소의 <literal>name</literal> 
+                                속성은 사용할 getter 및 setter 메소드들이 어느 것인지를 Hibernate에게 알려준다. 따라서 이 경우에 Hibernate는 
+                <literal>getDate()/setDate()</literal> 뿐만 아니라 <literal>getTitle()/setTitle()</literal>을 
+                                찾게 될 것이다.
+            </para>
+
+            <para>
+                <literal>date</literal> 프로퍼티 매핑은 <literal>column</literal> 속성을 포함하는데, 
+                                왜 <literal>title</literal>은 <literal>column</literal> 속성을 포함하지 않는가? 
+                <literal>column</literal> 속성이 없을 경우 Hibernate는 디폴트로 컬럼 이름으로서 프로퍼티 이름을
+                                사용한다. 이것은 에 대해 잘 동작한다. 하지만 <literal>date</literal>는 대부분의 데이터베이스에서 
+                                예약된 키워드이어서, 우리는 그것을 다른 이름으로 더 좋게 매핑 시킨다.
+            </para>
+
+            <para>
+                                다음 흥미로운 점은 <literal>title</literal> 매핑 또한 <literal>type</literal> 속성을 갖지 않는다. 
+                                우리가 매핑파일들 속에서 선언하고 사용하는 타입들은 당신이 예상하는 Java 데이터 타입들이 아니다. 그것들은 
+                                또한 SQL 데이터베이스 타입들도 아니다. 이들 타입들은 이른바 <emphasis>Hibernate 매핑 타입들</emphasis>, 
+                                즉 Java 타입들로부터 SQL 타입들로 변환될 수 있고 반대로 SQL 타입들로부터 Java 타입들로 매핑될 수 있는 컨버터들이다.
+                                다시말해, <literal>type</literal> 속성이 매핑 속에 존재하지 않을 경우 Hibernate는 정확환 변환 및 매핑 타입 
+                                그 자체를 결정하려고 시도할 것이다. 몇몇 경우들에서 (Java 클래스에 대한 Reflection을 사용하는) 이 자동적인 검출은 
+                                당신이 예상하거나 필요로 하는 디폴트를 갖지 않을 수도 있다. 이것은 <literal>date</literal> 프로퍼티를 가진 
+                                경우이다. Hibernate는  그 프로퍼티가 SQL <literal>date</literal> 컬럼, <literal>timestamp</literal> 
+                                컬럼 또는 <literal>time</literal> 컬럼 중 어느 것으로 매핑되어야 하는지를 알 수가 없다. 우리는  
+                <literal>timestamp</literal> 컨버터를 가진 프로퍼티를 매핑함으로써 전체 날짜와 시간 정보를 보존하고 싶다고 
+                                선언한다.
+            </para>
+
+            <para>
+                                다음 매핑 파일은 <literal>Event</literal> Java 클래스 소스 파일과 같은 디렉토리 속에 
+                <literal>Event.hbm.xml</literal>로서 저장될 것이다. 매핑 파일들에 대한 네이밍은 임의적일 수 
+                                있지만, 접미사 <literal>hbm.xml</literal>은 Hibernate 개발자 공동체 내에서 컨벤션이 되었다. 
+                                디렉토리 구조는 이제 다음과 같을 것이다: 
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java
+    Event.hbm.xml]]></programlisting>
+
+             <para>
+                                우리는 Hibernate의 메인 구성을 계속 행한다.
+             </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-configuration" revision="2">
+            <title>Hibernate 구성</title>
+
+            <para>
+                                우리는 이제 적절한 곳에 한 개의 영속 클래스와 그것의 매핑 파일을 갖고 있다. Hibernate를 구성할 차례이다. 
+                                우리가 이것을 행하기 전에, 우리는 데이터베이스를 필요로 할 것이다. 자바 기반의 메모리-내 SQL DBMS인 
+                HSQL DB는 HSQL DB 웹 사이트에서 내려받을 수 있다. 실제로, 당신은 이 다운로드에서 오직 <literal>hsqldb.jar</literal> 
+                                만을 필요로 한다. 개발 폴더의 <literal>lib/</literal> 디렉토리 속에 이 파일을 위치지워라. 
+            </para>
+
+            <para>
+                                개발 디렉토리의 루트에 <literal>data</literal>로 명명된 디렉토리를 생성시켜라 - 이  디렉토리는 
+                HSQL DB가 그것의 데이터 파일들을 저장하게 될 장소이다. 이제 이 데이터 디렉토리에서 
+                <literal>java -classpath ../lib/hsqldb.jar org.hsqldb.Server</literal>를 실행시켜서 
+                                데이터베이스를 시작시켜라. 당신은 그것이 시작되고 이것은 우리의 어플리케이션이 나중에 연결하게 될 장소인, 
+                                하나의 TCP/IP 소켓에 바인드 되는 것을 볼 수 있다. 만일 이 튜토리얼 동안에 당신이 새 데이터베이스로 
+                                시작하고자 원할 경우, HSQL DB를 셧다운시키고(왼도우에서 <literal>CTRL + C</literal>를 눌러라), 
+                <literal>data/</literal> 디렉토리 내에 있는 모든 파일들을 삭제하고 다시 HSQL DB를 시작하라.
+            </para>
+
+            <para>
+                Hibernate는 당신의 어플리케이션  내에서 이 데이터베이스에 연결하는 계층이고, 따라서 그것은 커넥션 정보를 
+                                필요로 한다. 커넥션들은 마찬가지로 구성되어야 하는 하나의 JDBC 커넥션 풀을 통해 행해진다. Hibernate 
+                                배포본은 몇몇 오픈 소스 JDBC 커넥션 풀링 도구들을 포함하고 있지만, 이 튜토리얼에서는 Hibernate에 의해 
+                                미리 빌드된 커넥션 풀링을 사용할 것이다. 당신이 필수 라이브러리를 당신의 classpath 속에 복사해야 하고
+                                만일 당신이 제품-특징의 제3의 JDBC 풀링 소프트웨어를 사용하고자 원할 경우에는 다른 커넥션 풀링 설정들을 
+                                사용해야 함을 노트하라. 
+            </para>
+
+            <para>
+                Hibernate의 구성을 위해, 우리는 한 개의 간단한 <literal>hibernate.properties</literal> 파일,
+                                한 개의 약간 더 세련된 <literal>hibernate.cfg.xml</literal> 파일, 또는  심지어 완전한 프로그램 
+                                상의 설정을 사용할 수 있다. 대부분의 사용자들은 XMl 구성 파일을 선호한다: 
+            </para>
+
+            <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <session-factory>
+
+        <!-- Database connection settings -->
+        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
+        <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
+        <property name="connection.username">sa</property>
+        <property name="connection.password"></property>
+
+        <!-- JDBC connection pool (use the built-in) -->
+        <property name="connection.pool_size">1</property>
+
+        <!-- SQL dialect -->
+        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
+
+        <!-- Enable Hibernate's automatic session context management -->
+        <property name="current_session_context_class">thread</property>
+
+        <!-- Disable the second-level cache  -->
+        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
+
+        <!-- Echo all executed SQL to stdout -->
+        <property name="show_sql">true</property>
+
+        <!-- Drop and re-create the database schema on startup -->
+        <property name="hbm2ddl.auto">create</property>
+
+        <mapping resource="events/Event.hbm.xml"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+            <para>
+                                이 XML 구성이 다른 DTD를 사용함을 노트하라. 우리는 Hibernate의 <literal>SessionFactory</literal> 
+                -특정 데이터베이스에 대해 책임이 있는 전역 팩토리-를 구성한다. 만일 당신이 여러 데이터베이스들을
+                                갖고 있다면, (보다 쉬운 시작을 위해) 몇 개의 구성 파일들 속에 여러 개의 <literal>&lt;session-factory&gt;</literal> 
+                                구성들을 사용하라.  
+            </para>
+
+            <para>
+                                처음 네 개의 <literal>property</literal> 요소들은 JDBC 커넥션을 위한 필수 구성을 포함한다. 
+                dialect <literal>property</literal> 요소는 Hibernate가 발생시키는 특별한 SQL 이형(異形)을 
+                                지정한다. 
+                <literal>hbm2ddl.auto</literal> 옵션은 -직접 데이터베이스 속으로- 데이터베이스 스키마의 자동적인
+                                생성을 활성화 시킨다. 물론 이것은 (config 옵션을 제거함으로써) 비활성화 시킬 수 있거나 
+                <literal>SchemaExport</literal> Ant 태스크의 도움으로 파일로 리다이렉트 될 수 있다. 마지막으로 
+                                우리는 영속 클래스들을 위한 매핑 파일(들)을 추가시킨다.
+            </para>
+
+            <para>
+                                이 파일을 소스 디렉토리 속으로 복사하고, 따라서 그것은 classpath의 루트에서 끝날 것이다. Hibernate는 
+                                시작 시에 classpath의 루트에서 <literal>hibernate.cfg.xml</literal>로 명명된 파일을 자동적으로 
+                                찾는다. 
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-ant" revision="1">
+            <title>Ant로 빌드하기</title>
+
+            <para>
+                                우리는 이제 Ant로 튜토리얼을 빌드할 것이다. 당신은 Ant를 설치할 필요가 있을 것이다 - 
+                <ulink url="http://ant.apache.org/bindownload.cgi">Ant 내려받기 페이지</ulink>에서 
+                Ant를 얻어라. Ant를 설치하는 방법은 여기서 다루지 않을 것이다. <ulink url="http://ant.apache.org/manual/index.html">Ant 매뉴얼</ulink>을 
+                                참조하길 바란다. 당신이 Ant를 설치한 후에, 우리는 빌드파일 생성을 시작할 수 있다. 그것은 <literal>build.xml</literal>로 
+                                명명되고 개발 디렉토리 속에 직접 위치될 것이다.
+            </para>
+
+            <para>
+                                기본 빌드 파일은 다음과 같다: 
+            </para>
+
+            <programlisting><![CDATA[<project name="hibernate-tutorial" default="compile">
+
+    <property name="sourcedir" value="${basedir}/src"/>
+    <property name="targetdir" value="${basedir}/bin"/>
+    <property name="librarydir" value="${basedir}/lib"/>
+
+    <path id="libraries">
+        <fileset dir="${librarydir}">
+            <include name="*.jar"/>
+        </fileset>
+    </path>
+
+    <target name="clean">
+        <delete dir="${targetdir}"/>
+        <mkdir dir="${targetdir}"/>
+    </target>
+
+    <target name="compile" depends="clean, copy-resources">
+      <javac srcdir="${sourcedir}"
+             destdir="${targetdir}"
+             classpathref="libraries"/>
+    </target>
+
+    <target name="copy-resources">
+        <copy todir="${targetdir}">
+            <fileset dir="${sourcedir}">
+                <exclude name="**/*.java"/>
+            </fileset>
+        </copy>
+    </target>
+
+</project>]]></programlisting>
+
+            <para>
+                                이것은 <literal>.jar</literal>로 끝나는 lib 디렉토리 내에 있는 모든 파일들을 컴파일에 사용되는 classpath에 
+                                추가하도록 Ant에게 알려줄 것이다. 그것은 또한 모든 비-Java 소스 파일들을 대상 디렉토리로 복사할 것이다. 예를 들면,
+                                구성 및 Hibernate 매핑 파일들. 만일 당신이 Ant를 이제 실행할 경우, 당신은 다음 출력을 얻게 될 것이다: 
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant
+Buildfile: build.xml
+
+copy-resources:
+     [copy] Copying 2 files to C:\hibernateTutorial\bin
+
+compile:
+    [javac] Compiling 1 source file to C:\hibernateTutorial\bin
+
+BUILD SUCCESSFUL
+Total time: 1 second ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-helpers" revision="3">
+            <title>시작과 helper들</title>
+
+            <para>
+                                몇몇 <literal>Event</literal> 객체들을 로드시키고 저장할 차례이지만, 먼저 우리는 어떤 인프라스트럭처 
+                                코드로 설정을 완료해야 한다. 우리는 Hibernate를 시작해야 한다. 이 시작은 전역 <literal>SessionFactory</literal>
+                                객체를 빌드하고 어플리케이션 내에서 용이한 접근을 위해 그것을 어떤 곳에 저장하는 것을 포함한다. 
+                <literal>SessionFactory</literal>는 새로운 <literal>Session</literal>들을 열 수 있다. 
+                <literal>Session</literal>은 작업의 단일-쓰레드 단위를 표현하며, <literal>SessionFactory</literal>는 
+                                한번 초기화 되는 하나의 thread-safe 전역 객체이다. 
+            </para>
+
+            <para>
+                                우리는 시작을 처리하고 <literal>Session</literal> 처리를 편리하게 해주는 <literal>HibernateUtil</literal> 
+                helper 클래스를 생성시킬 것이다. 이른바 <emphasis>ThreadLocal Session</emphasis> 패턴이 여기서 
+                                유용하며, 우리는 현재의 작업 단위를 현재의 쓰레드와 연관지워 유지한다. 구현을 살펴보자: 
+            </para>
+
+            <programlisting><![CDATA[package util;
+
+import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+    private static final SessionFactory sessionFactory;
+
+    static {
+        try {
+            // Create the SessionFactory from hibernate.cfg.xml
+            sessionFactory = new Configuration().configure().buildSessionFactory();
+        } catch (Throwable ex) {
+            // Make sure you log the exception, as it might be swallowed
+            System.err.println("Initial SessionFactory creation failed." + ex);
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    public static SessionFactory getSessionFactory() {
+        return sessionFactory;
+    }
+
+}]]></programlisting>
+
+            <para>
+                                이 클래스는 (클래스가 로드될 때 JVM에 의해 한번 호출되는) 그것의 static 초기자 내에 전역 <literal>SessionFactory</literal>를 
+                                산출할 뿐만 아니라 또한 현재 쓰레드에 대한 <literal>Session</literal>을 소유하는 <literal>ThreadLocal</literal> 변수를 
+                                갖는다. 당신이 <literal>HibernateUtil.getCurrentSession()</literal>을 호출하는 시점에는 문제가 없으며, 
+                                그것은 항상 동일 쓰레드 내에 동일한 Hibernate 작업 단위를 반환할 것이다. <literal>HibernateUtil.closeSession()</literal>에
+                                대한 호출은 쓰레드와 현재 연관되어 있는 작업 단위를 종료시킨다.
+            </para>
+
+            <para>
+                                당신이 이 helper를 사용하기 전에 thread-local 변수들에 대한 Java 개념을 확실히 이해하도록 하라. 
+                                보다 강력한 <literal>HibernateUtil</literal> helper는 http://caveatemptor.hibernate.org/에 
+                                있는 <literal>CaveatEmptor</literal> 뿐만 아니라 "Hibernate in Action" 책에서 찾을 수 있다. 
+                                당신이 J2EE 어플리케이션 서버 내에 Hibernate를 배치할 경우에 이 클래스는 필수적이지 않다: 하나의 
+                <literal>Session</literal>은 현재의 JTA 트랜잭션에 자동적으로 바인드 될 것이고 당신은 JNDI를 통해 
+                <literal>SessionFactory</literal>를 룩업할 수 있다. 만일 당신이 JBoss AS를 사용할 경우, 
+                Hibernate는 관리되는 시스템 서비스로서 배치될 수 있고 <literal>SessionFactory</literal>를 
+                JNDI 이름에 자동적으로 바인드시킬 수 있을 것이다.
+            </para>
+
+            <para>
+                                개발 소스 디렉토리 속에 <literal>HibernateUtil.java</literal> 를 위치지우고, 다음으로 <literal>Event.java</literal>를 
+                                위치지워라:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java
+    Event.hbm.xml
+  +util
+    HibernateUtil.java
+  hibernate.cfg.xml
++data
+build.xml]]></programlisting>
+
+            <para>
+                                이것은 문제 없이 다시 컴파일 될 것이다. 우리는 마지막으로 로깅 시스템을 구성할 필요가 있다 - Hibernate는 
+                commons logging를 사용하고 Log4j와 JDK 1.4 사이의 선택은 당신의 몫으로 남겨둔다. 대부분의 개발자들은 
+                Log4j를 선호한다: Hibernate 배포본에 있는 <literal>log4j.properties</literal>(이것은 디렉토리 
+                <literal>etc/</literal> 내에 있다)를 <literal>src</literal> 디렉토리로 복사하고, 다음으로 
+                <literal>hibernate.cfg.xml</literal>을 복사하라. 예제 구성을 살펴보고 당신이 더 많은 verbose 출력을
+                                원할 경우에 설정들을 변경하라. 디폴트로 Hibernate 시작 메시지는 stdout 상에 보여진다. 
+            </para>
+
+            <para>
+                                튜토리얼 인프라스트럭처는 완전하다 - 그리고 우리는 Hibernate로 어떤 실제 작업을 행할 준비가 되어 있다. 
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-workingpersistence" revision="5">
+            <title>객체 로딩과 객체 저장</title>
+
+            <para>
+                                마지막으로 우리는 객체들을 로드시키고 저장하는데 Hibernate를 사용할 수 있다. 우리는 한 개의 <literal>main()</literal> 
+                                메소드를 가진 한 개의 <literal>EventManager</literal> 클래스를 작성한다: 
+            </para>
+
+            <programlisting><![CDATA[package events;
+import org.hibernate.Session;
+
+import java.util.Date;
+
+import util.HibernateUtil;
+
+public class EventManager {
+
+    public static void main(String[] args) {
+        EventManager mgr = new EventManager();
+
+        if (args[0].equals("store")) {
+            mgr.createAndStoreEvent("My Event", new Date());
+        }
+
+        HibernateUtil.getSessionFactory().close();
+    }
+
+    private void createAndStoreEvent(String title, Date theDate) {
+
+        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+        session.beginTransaction();
+
+        Event theEvent = new Event();
+        theEvent.setTitle(title);
+        theEvent.setDate(theDate);
+
+        session.save(theEvent);
+
+        session.getTransaction().commit();
+    }
+
+}]]></programlisting>
+
+            <para>
+                                우리는 한 개의 새로운 <literal>Event</literal> 객체를 생성시키고, 그것을 Hibernate에게 건네준다.
+                Hibernate는 이제 SQL을 처리하고 데이터베이스 상에서 <literal>INSERT</literal>들을 실행시킨다. 
+                -우리가 이것을 실행하기 전에 코드를 처리하는- <literal>Session</literal>과 <literal>Transaction</literal>을 
+                                살펴보자. 
+            </para>
+
+            <para>
+                <literal>Session</literal>은 한 개의 작업 단위이다. 지금부터 우리는 단숨함을 유지할 것이고 
+                Hibernate <literal>Session</literal>과 데이터베이스 트랜잭션 사이의 일-대-일 과립형(granularity)을 가정할 것이다.
+                                실제 기반 트랜잭션 시스템으로부터 우리의 소스를 은폐시키기 위해(이 경우 통상의 JDBC이지만, 그것은 또한 JTA에도 실행된다) 
+                                우리는  Hibernate <literal>Session</literal> 상에서 이용 가능한 <literal>Transaction</literal> API를 
+                                사용한다.
+            </para>
+
+            <para>
+                
+                <literal>sessionFactory.getCurrentSession()</literal>은 무엇을 행하는가? 먼저 
+                                당신은 당신이 (<literal>HibernateUtil</literal> 덕분에 쉽게) <literal>SessionFactory</literal>을 
+                                당신이 소유하고 있다면, 원하는 만큼 어디서든 여러번 그것을 호출할 수 있다. 
+                <literal>getCurrentSession()</literal> 메소드는 항상 "현재의" 작업 단위를 반환한다. 우리가 
+                <literal>hibernate.cfg.xml</literal> 내에서 이 매커니즘에 대한 구성 옵션을 "thread"로 전환시켰음을 기억하는가?
+                 그러므로 작업의 현재 단위는 우리의 어플리케이션을 실행시키는 현재 자바 쓰레드에 묶여 있다. 하지만 
+                 이것은 전체 그림이 아니며, 당신은 또한 scope(영역), 작업 단위가 시작될 때와 작업 단위가 종료될 때를 
+                 고려해야 한다.
+            </para>
+
+            <para>
+                <literal>Session</literal>은 그것이 처음으로 필요로 되고 <literal>getCurrentSession()</literal>에 대한 
+                첫 번째 호출이 이루어질 때 시작된다. 그때 그것은 Hibernate에 의해 현재의 쓰레드에 바인드 된다. 
+                커밋되든 롤백되든 간에 트랜잭션이 종료되고, Hibernate가 자동적으로 그 쓰레드로부터 <literal>Session</literal>을 
+                 바인드 해제시키고 당신을 위해 세션을 닫는다. 만일 당신이 <literal>getCurrentSession()</literal>을 다시 
+                 호출한다면, 당신은  새로운 <literal>Session</literal>을 얻고 새로운 작업단위를 시작할 수 있다. 
+                 이 <emphasis>thread-bound</emphasis> 프로그래밍 모형은 Hibernate를 사용하는 가장 대중적인 방법이다. 
+                 왜냐하면 그것은 당신의 코드를 유연하게 계층화시키는 것을 허용해주기 때문이다(트랜잭션 경계 분할 코드는 
+                 데이트 접근 코드와 구별지워질 수 있는데, 우리는 이 튜토리얼의 뒷부분에서 이것을 다룰 것이다.).
+            </para>
+
+            <para>
+                작업 영역의 단위와 관련하여, Hibernate <literal>Session</literal>은 하나 또는 여러 개의 데이터베이스 
+                오퍼레이션들을 실행시키는데 사용될 수 있는가? 위의 예제는 하나의 오퍼레이션에 한 개의 <literal>Session</literal>을 
+                사용하고 있다. 이것은 순진한 일치이며, 예제는 어떤 다른 접근법을 보여주기에는 충분히 복잡하지 않다. 
+                Hibernate <literal>Session</literal>의 scope(영역)은 유연하지만 당신은 결코 <emphasis>모든</emphasis> 
+                데이터베이스 오퍼레이션 각각에 대해 새로운 Hibernate <literal>Session</literal>을 사용하도록 
+                당신의 어플리케이션을 설계할 수 없다. 따라서 심지어 당신이 다음의 (매우 사소한) 예제들에서 여러 번 
+                그것을 볼 수 있을지라도 <emphasis>session-per-operation</emphasis>을 하나의 안티-패턴으로 간주하라. 
+                실제 (웹) 어플리케이션은 이 튜토리얼의 뒷부분에 보여진다.
+            </para>
+
+            <para>
+                                트랜잭션 핸들링과 경계구분에 대한 추가 정보는 <xref linkend="transactions"/>을 살펴보라. 
+                                우리는 또한 앞의 예제에서 임의의 오류 처리와 롤백을 생략했다.
+            </para>
+
+            <para>
+                                이 첫 번째 루틴을 실행하기 위해서 우리는 호출 가능한 대상을 Ant 빌드 파일에 추가해야 한다: 
+            </para>
+
+            <programlisting><![CDATA[<target name="run" depends="compile">
+    <java fork="true" classname="events.EventManager" classpathref="libraries">
+        <classpath path="${targetdir}"/>
+        <arg value="${action}"/>
+    </java>
+</target>]]></programlisting>
+
+            <para>
+                <literal>action</literal> 아규먼트의 값은 대상을 호출할 때 명령 라인 상에서 설정된다: 
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant run -Daction=store]]></programlisting>
+
+            <para>
+                                컴파일, 구성에 따른 Hibernate 시작 후에,  당신은  많은 로그 출력을 보게 될 것이다. 끝에서 당신은 
+                                다음 라인을 발견할 것이다: 
+            </para>
+
+            <programlisting><![CDATA[[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)]]></programlisting>
+
+            <para>
+                                이것은 Hibernate에 의해 실행된 <literal>INSERT</literal>이고, 물음표 기호는 JDBC 바인드 
+                                파라미터들을 나타낸다. 아규먼트로서 바인드 된 값들을 보거나 장황한 로그를 줄이려면 당신의 
+                <literal>log4j.properties</literal>를 체크하라. 
+            </para>
+
+            <para>
+                                 이제 우리는 마찬가지로 저장된 이벤트들을 열거하고자 원하며, 우리는 main 메소드에 한 개의 옵션을 
+                                 추가한다: 
+            </para>
+
+            <programlisting><![CDATA[if (args[0].equals("store")) {
+    mgr.createAndStoreEvent("My Event", new Date());
+}
+else if (args[0].equals("list")) {
+    List events = mgr.listEvents();
+    for (int i = 0; i < events.size(); i++) {
+        Event theEvent = (Event) events.get(i);
+        System.out.println("Event: " + theEvent.getTitle() +
+                           " Time: " + theEvent.getDate());
+    }
+}]]></programlisting>
+
+            <para>
+                                우리는 또한 새로운 <literal>listEvents() method</literal> 메소드를 추가 시킨다: 
+            </para>
+
+            <programlisting><![CDATA[private List listEvents() {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+    session.beginTransaction();
+
+    List result = session.createQuery("from Event").list();
+
+    session.getTransaction().commit();
+
+    return result;
+}]]></programlisting>
+
+            <para>
+                                여기서 우리가 행할 것은 데이터베이스로부터 모든 존재하는 <literal>Event</literal> 객체들을 로드시키기 
+                                위해 HQL (Hibernate Query Language) 질의를 사용하는 것이다. Hibernate는 적절한 SQL을 생성시킬 
+                                것이고, 그것을 데이터베이스로 전송하고 데이터를 <literal>Event</literal> 객체들에 거주시킬 것이다. 
+                                당신은 물론 HQL로서 보다 복잡한 질의들을 생성시킬 수 있다.
+            </para>
+
+            <para>
+                                이제 이 모든 것을 실행하고 테스트하기 위해, 다음 단계들을 따르라:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                                                데이터베이스 속으로 어떤 것을 저장하고 물론 앞서 hbm2ddl을 통해 데이터베이스 스키마를 산출시키기 위해 
+                        <literal>ant run -Daction=store</literal>를 실행하라.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                                                이제 당신의 <literal>hibernate.cfg.xml</literal> 파일 속에서 그 프로퍼티를 주석처리함으로써 hbm2ddl을 
+                                                사용불가능하게 하라. 대개 당신은 지속되는 단위 테스팅에서는 그것을 사용 가능하게 내버려두어도 되지만, 또 다른 
+                        hbm2ddl의 실행은 당신이 저장했던 모든 것을 <emphasis>drop</emphasis>시킬 것이다 - <literal>create</literal>
+                                                구성 설정은 실제로 "스키마로부터 모든 테이블들을 드롭시키고 나서, SessionFactory가 빌드될 때 모든 테이블들을 
+                                                다시 생성시키는 것"으로 변환된다.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                                만일 당신이 지금 <literal>-Daction=list</literal>로 Ant를 호출할 경우, 당신은 당신이 지금까지 저장했던 이벤트들을 
+                                보게 될 것이다. 물론 당신은 또한 여러 번 <literal>store</literal> 액션을 호출할 수 있다.
+            </para>
+            
+            <para>
+                                노트 : 대부분의 Hibernate 사용자들은 이 지점에서 실패하고 우리는 정기적으로 <emphasis>Table not found</emphasis>
+                                오류 메시지들에 관한 질문을 받는다. 하지만 만일 당신이 위에 조명된 단게들을 따를 경우 당신은 이 문제를 겪지 않을 것이고, 
+                hbm2ddl이 처음 실행 시에 데이터베이스 스키마를 생성시키므로, 차후의 어플리케이션 재시작은 이 스키마를 사용할 것이다.
+                                만일 당신이 매핑 그리고/또는 데이터베이스 스키마를 변경할 경우에, 당신은 다시 한번 더 hbm2ddl을 이용 가능하도록 해야 한다.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="tutorial-associations">
+        <title>파트 2 - 연관들을 매핑하기</title>
+
+        <para>
+                        우리는 한 개의 영속 엔티티 클래스를 한 개의 테이블로 매핑했다. 이것 위에서 빌드하고 몇몇 클래스 연관들을 추가시키자. 먼저 
+                        우리는 우리의 어플리케이션에 사람들을 추가하고 그들이 참여하는 이벤트들의 목록을 저장할 것이다.
+        </para>
+
+        <sect2 id="tutorial-associations-mappinguser" revision="1">
+            <title>Person 클래스 매핑하기</title>
+
+            <para>
+                                클래스의 첫 번째 장면은 간단하다: 
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+public class Person {
+
+    private Long id;
+    private int age;
+    private String firstname;
+    private String lastname;
+
+    public Person() {}
+
+    // Accessor methods for all properties, private setter for 'id'
+
+}]]></programlisting>
+
+            <para>
+                <literal>Person.hbm.xml</literal>로 명명되는 새로운 매핑 파일을 생성시켜라
+                (맨위에 DTD 참조를 잊지말라):
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Person" table="PERSON">
+        <id name="id" column="PERSON_ID">
+            <generator class="native"/>
+        </id>
+        <property name="age"/>
+        <property name="firstname"/>
+        <property name="lastname"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                                마지막으로 새로운 매핑을 Hibernate의 구성에 추가하라: 
+            </para>
+
+            <programlisting><![CDATA[<mapping resource="events/Event.hbm.xml"/>
+<mapping resource="events/Person.hbm.xml"/>]]></programlisting>
+
+            <para>
+                                이제 우리는 이들 두 개의 엔티티들 사이에 한 개의 연관을 생성시킬 것이다. 명백하게, 개인들은 이벤트들에 
+                                참여할 수 있고, 이벤트들은 참여자들을 갖는다. 우리가 다루어야 하는 설계 질문들은 다음과 같다 : 
+                                방향성(directionality), 다중성(multiplicity), 그리고 콜렉션 특징.  
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-unidirset" revision="3">
+            <title>단방향 Set-기반의 연관</title>
+
+            <para>
+                                우리는 <literal>Person</literal> 클래스에 이벤트들을 가진 한 개의 콜렉션을 추가할 것이다. 그 방법으로 우리는 
+                                명시적인 질의-<literal>aPerson.getEvents()</literal>를 호출함으로써-를 실행시키지 않고서  특정 개인에 대한 
+                                이벤트들을 쉽게 네비게이트할 수 있다. 우리는 하나의 Java 콜렉션, 하나의 <literal>Set</literal>를 사용한다. 왜냐하면 
+                                그 콜렉션은 중복 요소들을 포함하기 않을 것이고 그 순서가 우리와 관련되어 있지 않기 때문이다.
+            </para>
+
+            <para>
+                                우리는 하나의 <literal>Set</literal>으로 구현된, 하나의 단방향, 다중값 연관들을 필요로 한다. Java 클래스들 내에 
+                                이를 위한 코드를 작성하고 그런 다음 그것을  매핑시키자:
+            </para>
+
+            <programlisting><![CDATA[public class Person {
+
+    private Set events = new HashSet();
+
+    public Set getEvents() {
+        return events;
+    }
+
+    public void setEvents(Set events) {
+        this.events = events;
+    }
+}]]></programlisting>
+
+            <para>
+                                우리가 이 연관을 매핑하기 전에, 다른 측에 대해 생각하라. 명백하게 우리는 이것을 단지 단방향으로 유지시킬 수 있다. 
+                                또는 우리가 그것을 양방향으로 네비게이트하는 것-예를 들어 <literal>anEvent.getParticipants()</literal>-이 
+                                가능하도록 원할 경우에, <literal>Event</literal>측 상에 또 다른 콜렉션을 생성시킬 수 있다. 이것은 당신에게 
+                                남겨진 설계 선택이지만, 이 논의에서 명료한 점은 연관의 다중성이다: 양 측 상에서  "다중" 값을 갖는 경우, 우리는 이것을 
+                <emphasis>many-to-many</emphasis> 연관이라고 명명한다. 그러므로 우리는 Hibernate의 many-to-many 매핑을 
+                                사용한다: 
+            </para>
+
+            <programlisting><![CDATA[<class name="events.Person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="native"/>
+    </id>
+    <property name="age"/>
+    <property name="firstname"/>
+    <property name="lastname"/>
+
+    <set name="events" table="PERSON_EVENT">
+        <key column="PERSON_ID"/>
+        <many-to-many column="EVENT_ID" class="events.Event"/>
+    </set>
+
+</class>]]></programlisting>
+
+            <para>
+                Hibernate는 모든 종류의 콜렉션 매핑들, 가장 공통적인 <literal>&lt;set&gt;</literal>을 지원한다. many-to-many 
+                                연관 (또는 <emphasis>n:m</emphasis> 엔티티 관계)의 경우, 한 개의 연관 테이블이 필요하다. 이 테이블 내에 있는 각각의 
+                                행은 한 명의 개인과 한 개의 이벤트 사이의 링크를 표현한다. 테이블 이름은 <literal>set</literal> 요소의 <literal>table</literal> 
+                                속성으로 구성된다. 연관 내의 식별자 컬럼 이름은 개인 측에 대해 <literal>&lt;key&gt;</literal> 요소로 정의되고 
+                                이벤트 측에 대한 컬럼 이름은 <literal>&lt;many-to-many&gt;</literal>의 <literal>column</literal> 속성으로 
+                                정의된다. 당신은 또한 당신의 콜렉션 내에 있는 객체들의 클래스(정확하게 : 참조들을 가진 콜렉션의 다른 측 상에 있는 클래스)를 
+                Hibernate에게 알려주어야 한다.
+            </para>
+
+            <para>
+                                따라서 이 매핑을 위한 데이터베이스 스키마는 다음과 같다:
+            </para>
+
+            <programlisting><![CDATA[
+    _____________        __________________
+   |             |      |                  |       _____________
+   |   EVENTS    |      |   PERSON_EVENT   |      |             |
+   |_____________|      |__________________|      |    PERSON   |
+   |             |      |                  |      |_____________|
+   | *EVENT_ID   | <--> | *EVENT_ID        |      |             |
+   |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  |
+   |  TITLE      |      |__________________|      |  AGE        |
+   |_____________|                                |  FIRSTNAME  |
+                                                  |  LASTNAME   |
+                                                  |_____________|
+ ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-working" revision="2">
+            <title>연관들에 작업하기</title>
+
+            <para>
+                <literal>EventManager</literal> 속에 있는 한 개의 새로운 메소드 내에 몇몇 사람들과 이벤트들을 함께 가져오자: 
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    aPerson.getEvents().add(anEvent);
+
+    session.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                <literal>Person</literal>과 <literal>Event</literal>를 로드시킨 후에, 정규 콜렉션 메소드들을 사용하여 
+                                콜렉션을 간단하게 변경하라. 당신이 알 수 있듯이, <literal>update()</literal> 또는 <literal>save()</literal>에 
+                                대한 명시적인 호출이 존재하지 않고, 변경되었고 저장할 필요가 있는 콜렉션을 Hibernate가 자동적으로 검출해낸다. 이것은 
+                <emphasis>자동적인 dirty 체킹</emphasis>이라 불려지며, 당신은 또한 당신의 임의의 객체들에 대한 name 또는 date 
+                                프로퍼티를 변경함으로써 그것을 시도할 수 있다. 그것들이 <emphasis>영속(persistent)</emphasis> 상태에 있는 동안, 즉 특정 Hibernate 
+                <literal>Session</literal>에 바인드되어 있는 동안(예를 들면. 그것들은 작업 단위 속에 방금 로드되었거나 저장되었다), 
+                Hibernate는 임의의 변경들을 모니터링하고 쓰기 이면의 형태로 SQL을 실행시킨다. 메모리 상태를 데이터베이스와 동기화 시키는 
+                                과정은 대개 오직 작업 단위의 끝에서이고, <emphasis>flushing</emphasis>이라 명명된다. 우리의 코드에서, 작업 단위는 
+                <literal>CurrentSessionContext</literal> 클래스에 대한 <literal>thread</literal> 구성 옵션에 의해 정의된 
+                                대로 - 데이터베이스 트랜잭션의 커밋(또는 롤백)으로 끝이난다.
+            </para>
+
+            <para>
+                                물론 당신은 다른 작업 단위 속에 개인과 이벤트를 로드시킬 수 도 있다. 또는 당신은 하나의 객체그 영속 상태에 있지 않을 때 
+                <literal>Session</literal>의 외부에서 객체를 변경시킬 수도 있다(만일 객체가 이전에 영속화 되었다면, 우리는 이 상태를 
+                <emphasis>detached</emphasis>라고 부른다). (매우 사실적이지 않은) 코드 내에서 이것은 다음과 같을 수 있다: 
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session
+            .createQuery("select p from Person p left join fetch p.events where p.id = :pid")
+            .setParameter("pid", personId)
+            .uniqueResult(); // Eager fetch the collection so we can use it detached
+
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    session.getTransaction().commit();
+
+    // End of first unit of work
+
+    aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached
+
+    // Begin second unit of work
+
+    Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
+    session2.beginTransaction();
+
+    session2.update(aPerson); // Reattachment of aPerson
+
+    session2.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                <literal>update</literal>에 대한 호출은 한 개의 detached 객체를  다시 영속화 시키고, 당신은 그것이 새로운 작업 단위에 
+                                바인드된다고 말할 수 있고, 따라서 detached 동안에 당신이 그것에 대해 행한 임의의 변경들이 데이터베이스에 저장될 수 있다. 
+                                이것은 당신이 그 엔티티 객체의 콜렉션에 대해 행했던 임의의 변경들(추가/삭제)를 포함한다. 
+            </para>
+
+            <para>
+                                물론, 우리의 현재 상황에서 이것은 많이 사용되지 않지만, 그것은 당신이 당신 자신의 어플리케이션 내로 설계할 수 있는 중요한 
+                                개념이다. 지금 <literal>EventManager</literal>의 main 메소드에 한 개의 새로운 액션을 추가하고 명령 라인에서 그것을 
+                                호출하여 이 연습을 완료하라. 만일 당신이 한명의 개인과 한 개의 이벤트에 대한 식별자들을 필요로 할 경우 - <literal>save()</literal> 
+                                메소드가 그것을 반환시킨다(당신은 그 식별자를 반환시키는 앞의 메소드들 중 몇몇을 변경시켜야 할 것이다):
+            </para>
+
+            <programlisting><![CDATA[else if (args[0].equals("addpersontoevent")) {
+    Long eventId = mgr.createAndStoreEvent("My Event", new Date());
+    Long personId = mgr.createAndStorePerson("Foo", "Bar");
+    mgr.addPersonToEvent(personId, eventId);
+    System.out.println("Added person " + personId + " to event " + eventId);
+}]]></programlisting>
+
+            <para>
+                                이것은 두 개의 동등하게 중요한 클래스들, 두 개의 엔티티들 사이에서 한 개의 연관에 관한 예제였다. 앞서 언급했듯이, 전형적인 모형 내에는 
+                                다른 클래스들과 타이들이 존재하는데, 대개 "덜 중요하다". 당신은 이미 <literal>int</literal> 또는 <literal>String</literal>과 
+                                같은 어떤 것을 이미 보았다. 우리는 이들 클래스들을 <emphasis>값 타입들(value types)</emphasis>이라 명명하고, 그들 인스턴스들은 
+                                특정 엔티티에 <emphasis>의존한다(depend)</emphasis>. 이들 타입들을 가진 인스턴스들은 그것들 자신의 식별성(identity)를 갖지 않거나, 
+                                그것들은 엔티티들 사이에서 공유되지도 않는다(두개의 person들은 심지어 그것들이 같은 첫 번째 이름을 갖는 경우에도 동일한 <literal>firstname</literal>을 
+                                참조하지 않는다 ). 물론 값 타입들은 JDK 내에서 발견될 뿐만 아니라(사실, Hibernate 어플리케이션에서 모든 JDK 클래스들은 값 타입들로 간주된다), 
+                                당신은 또한 당신 스스로 종속 클래스들, 예를 들면  <literal>Address</literal> 또는 <literal>MonetaryAmount</literal>을 작성할 수 있다. 
+            </para>
+
+            <para>
+                                당신은 또한 값 타입들을 설계할 수 있다. 이것은 다른 엔티티들에 대한 참조들을 가진 콜렉션과는 개념적으로 매우 다르지만, 
+                Java에서는 대개 동일한 것으로 보여진다. 
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-valuecollections">
+            <title>값들을 가진 콜렉션</title>
+
+            <para>
+                                우리는 값 타입의 객체들을 가진 한 개의 콜렉션을 <literal>Person</literal> 엔티티에 추가시킨다. 우리는 email 주소를 
+                                저장하고자 원하므로, 우리가 사용하는 타입은 <literal>String</literal>이고, 그 콜렉션은 다시 한 개의 <literal>Set</literal>이다:
+            </para>
+            <programlisting><![CDATA[private Set emailAddresses = new HashSet();
+
+public Set getEmailAddresses() {
+    return emailAddresses;
+}
+
+public void setEmailAddresses(Set emailAddresses) {
+    this.emailAddresses = emailAddresses;
+}]]></programlisting>
+
+            <para>
+                                이 <literal>Set</literal>에 대한 매핑은 다음과 같다: 
+            </para>
+
+            <programlisting><![CDATA[<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
+    <key column="PERSON_ID"/>
+    <element type="string" column="EMAIL_ADDR"/>
+</set>]]></programlisting>
+
+            <para>
+                                앞의 매핑과 비교한 차이점은 <literal>element</literal> 부분인데, 그것은 그 콜렉션이 또 다른 엔티티에 대한 
+                                참조들을 포함하지 않을 것이지만 <literal>String</literal>(소문자 이름은 그것이 Hibernate 매핑 타입/변환자임을 
+                                당신에게 말해준다) 타입의 요소들을 가진 한 개의 콜렉션을 포함할 것임을 Hibernate에게 알려준다. 일단 다시 <literal>set</literal> 
+                                요소의  <literal>table</literal> 속성은 그 콜렉션에 대한 테이블 이름을 결정한다. <literal>key</literal> 요소는 
+                                콜렉션 테이블 내에서 foreign-key 컬럼 이름을 정의한다. <literal>element</literal> 요소 내에 있는 <literal>column</literal> 
+                                속성은 <literal>String</literal> 값들이 실제로 저장될 컬럼 이름을 정의한다.
+            </para>
+
+            <para>
+                                업데이트된 스키마를 살펴보라: 
+            </para>
+
+            <programlisting><![CDATA[
+  _____________        __________________
+ |             |      |                  |       _____________
+ |   EVENTS    |      |   PERSON_EVENT   |      |             |       ___________________
+ |_____________|      |__________________|      |    PERSON   |      |                   |
+ |             |      |                  |      |_____________|      | PERSON_EMAIL_ADDR |
+ | *EVENT_ID   | <--> | *EVENT_ID        |      |             |      |___________________|
+ |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  | <--> |  *PERSON_ID       |
+ |  TITLE      |      |__________________|      |  AGE        |      |  *EMAIL_ADDR      |
+ |_____________|                                |  FIRSTNAME  |      |___________________|
+                                                |  LASTNAME   |
+                                                |_____________|
+ ]]></programlisting>
+
+            <para>
+                                당신은 콜렉션 테이블의 프라이머리 키가 사실은 두 컬럼들을 사용하는 한  개의 합성 키(composite key)임을 알 수 있다. 
+                                이것은 또한 개인에 대해 email 주소가 중복될 수 없음을 의미하며, 그것은 정확하게 우리가 Java에서 set을 필요로 하는 
+                                의미론이다.  
+            </para>
+
+            <para>
+                                마치 개인들과 이벤트들을 링크시켜서 이전에 우리가 행했던 것처럼  이제 당신은 요소들을 시도하고 이 콜렉션에 추가할 수 있다. 
+                                그것은 Java에서 동일한 코드이다.
+            </para>
+
+            <programlisting><![CDATA[private void addEmailToPerson(Long personId, String emailAddress) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+
+    // The getEmailAddresses() might trigger a lazy load of the collection
+    aPerson.getEmailAddresses().add(emailAddress);
+
+    session.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                                지금 우리는 콜렉션을 초기화 시키는데 <emphasis>fetch</emphasis> 질의를 사용하지 않았다. 
+                                그러므로 콜렉션의 getter 메소드에 대한 호출은 콜렉션을 초기화 시키기 위해 추가적인 select를 트리거 시킬 
+                                것이어서, 우리는 그것에 요소를 추가시킬 수 있다. SQL 로그를 관찰하고 이것을 eager fetch로 최적화 시키려고 
+                                시도하라.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-bidirectional" revision="1">
+            <title>Bi-directional associations</title>
+
+            <para>
+                                다음으로 우리는 양방향 연관을 매핑시킬 예정이다-개인과 이벤트 사이에 연관을 만드는 것은 Java에서 양 측들에서 동작한다. 
+                                물론  데이터베이스 스키마는 변경되지 않고, 우리는 여전히 many-to-many 다중성을 갖는다. 관계형 데이터베이스는 
+                                네트웍 프로그래밍 언어 보다 훨씬 더 유연하여서, 그것은 네비게이션 방향과 같은 어떤 것을 필요로 하지 않는다 - 데이터는 
+                                어떤 가능한 바업ㅂ으로 보여질 수 있고 검색될 수 있다. 
+            </para>
+
+            <para>
+                                먼저, 참여자들을 가진 한 개의 콜렉션을 <literal>Event</literal> Event 클래스에 추가시켜라:
+            </para>
+
+            <programlisting><![CDATA[private Set participants = new HashSet();
+
+public Set getParticipants() {
+    return participants;
+}
+
+public void setParticipants(Set participants) {
+    this.participants = participants;
+}]]></programlisting>
+
+            <para>
+                                이제 <literal>Event.hbm.xml</literal> 내에 연관의 이 쪽도 매핑하라. 
+            </para>
+
+            <programlisting><![CDATA[<set name="participants" table="PERSON_EVENT" inverse="true">
+    <key column="EVENT_ID"/>
+    <many-to-many column="PERSON_ID" class="events.Person"/>
+</set>]]></programlisting>
+
+            <para>
+                                당신이 볼 수 있듯이, 이것들은 두 매핑 문서들 내에서 정규 <literal>set</literal> 매핑들이다. <literal>key</literal>와 
+                <literal>many-to-many</literal>에서 컬럼 이름들은 두 매핑 문서들에서 바뀌어진다. 여기서 가장 중요한 부가물은 
+                <literal>Event</literal>의 콜렉션 매핑에 관한 <literal>set</literal> 요소 내에 있는 <literal>inverse="true"</literal> 
+                                속성이다. 
+            </para>
+
+            <para>
+                                이것이 의미하는 바는 Hibernate가 둘 사이의 링크에 대한 정보를 알 필요가 있을 때 다른 측-<literal>Person</literal> 클래스-를 취할 
+                                것이라는 점이다. 일단 당신이 우리의 두 엔티티들 사이에 양방향 링크가 생성되는 방법을 안다면 이것은 이해하기가 훨씬 더 쉬울 것이다. 
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-usingbidir">
+            <title>양방향 링크들에 작업하기</title>
+
+            <para>
+                                첫 번째로 Hibernate가 정규 Java 의미론에 영향을 주지 않음을 염두에 두라. 우리는 단방향 예제에서 <literal>Person</literal>과 
+                <literal>Event</literal> 사이에 어떻게 한 개의 링크를 생성시켰는가? 우리는 <literal>Event</literal> 타입의 인스턴스를 
+                <literal>Person</literal> 타입의 이벤트 참조들을 가진 콜렉션에 추가시켰다. 따라서 명백하게 우리가 이 링크를 양방향으로 
+                                동작하도록 만들고자 원한다면, 우리는 다른 측 상에서 -하나의 <literal>Person</literal> 참조를 하나의 <literal>Event</literal> 
+                                내에 있는 콜렉션에 추가시킴으로써- 동일한 것을 행해야 한다. 이 "양 측 상에 링크 설정하기"는 절대적으로 필수적이고 당신은 그것을 행하는 
+                                것을 결코 잊지 말아야 한다.   
+            </para>
+
+            <para>
+                                많은 개발자들은 방비책을 프로그램하고 양 측들을 정확하게 설정하기 위한 하나의 링크 관리 메소드들을 생성시킨다. 예를 들면 <literal>Person</literal>에서 :
+            </para>
+
+            <programlisting><![CDATA[protected Set getEvents() {
+    return events;
+}
+
+protected void setEvents(Set events) {
+    this.events = events;
+}
+
+public void addToEvent(Event event) {
+    this.getEvents().add(event);
+    event.getParticipants().add(this);
+}
+
+public void removeFromEvent(Event event) {
+    this.getEvents().remove(event);
+    event.getParticipants().remove(this);
+}]]></programlisting>
+
+            <para>
+                                콜렉션에 대한 get 및 set 메소드드은 이제 protected임을 인지하라 - 이것은 동일한 패키지 내에 있는 클래스들과 서브클래스들이 
+                                그 메소드들에 접근하는 것을 허용해주지만, 그 밖의 모든 것들이 그 콜렉션들을 (물론, 대개) 직접 만지는 것을 금지시킨다. 당신은 
+                                다른 측 상에 있는 콜렉션에 대해 동일한 것을 행할 것이다. 
+            </para>
+
+            <para>
+                <literal>inverse</literal> 매핑 속성은 무엇인가? 당신의 경우, 그리고 Java의 경우, 한 개의 양방향 링크는 단순히 양 측들에 대한 
+                               참조들을 정확하게 설정하는 문제이다. 하지만 Hibernate는 (컨스트레인트 위배를 피하기 위해서) SQL <literal>INSERT</literal> 문장과 
+                <literal>UPDATE</literal> 문장을 정확하게 마련하기에 충분한 정보를 갖고 있지 않으며, 양방향 연관들을 올바르게 처리하기 위해 
+                                어떤 도움을 필요로 한다. 연관의 한 측을 <literal>inverse</literal>로 만드는 것은 기본적으로 그것을 무시하고 그것을 다른 측의 
+                <emphasis>거울(mirror)</emphasis>로 간주하도록 Hibernate에게 알려준다. 그것은 Hibernate가 하나의 방향성 네비게이션 모형을 
+                                한 개의 SQL 스키마로 변환시킬 때 모든 쟁점들을 잘 해결하는데 필수적인 모든 것이다. 당신이 염두에 두어야 하는 규칙들은  간단하다 : 
+                                모든 양방향 연관들은 한 쪽이  <literal>inverse</literal>일 필요가 있다. one-to-many 연관에서 그것은 many-측이어야 하고, 
+                many-to-many 연관에서 당신은 어느 측이든 선택할 수 있으며 차이점은 없다.
+            </para>
+
+        </sect2>
+
+        <para>
+            Let's turn this into a small web application.
+        </para>
+
+    </sect1>
+
+    <sect1 id="tutorial-webapp">
+        <title>파트 3 - EventManager 웹 어플리케이션</title>
+
+        <para>
+            Hibernate 웹 어플리케이션은 대부분의 스탠드얼론 어플리케이션과 같이 <literal>Session</literal>과 
+            <literal>Transaction</literal>을 사용한다. 하지만 몇몇 공통 패턴들이 유용하다. 우리는 이제 
+            <literal>EventManagerServlet</literal>를 작성한다. 이 서블릿은 데이터베이스 내에 저장된 모든 이벤트들을 나열할 수 있고, 
+                        그것은 새로운 이벤트들을 입력하기 위한 HTML form을 제공한다.
+        </para>
+
+        <sect2 id="tutorial-webapp-servlet" revision="2">
+            <title>기본 서블릿 작성하기</title>
+
+            <para>
+                                다음 장에서 우리는 Hibernate를 Tomcat 및 WebWork와 통합시킨다. <literal>EventManager</literal>는 우리의 성장하는 
+                                어플리케이션을 더이상 감당하지 못한다. 
+                                당신의 소스 디렉토리에서 <literal>events</literal> 패키지 내에 새로운 클래스를 생성시켜라: 
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+// Imports
+
+public class EventManagerServlet extends HttpServlet {
+
+    // Servlet code
+}]]></programlisting>
+
+            <para>
+                                서블릿은 HTTP <literal>GET</literal> 요청들 만을 처리하므로, 우리가 구현하는 메소드는 <literal>doGet()</literal>이다:
+            </para>
+
+            <programlisting><![CDATA[protected void doGet(HttpServletRequest request,
+                     HttpServletResponse response)
+        throws ServletException, IOException {
+
+    SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
+
+    try {
+        // Begin unit of work
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().beginTransaction();
+
+        // Process request and render page...
+
+        // End unit of work
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().getTransaction().commit();
+
+    } catch (Exception ex) {
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().getTransaction().rollback();
+        throw new ServletException(ex);
+    }
+
+}]]></programlisting>
+
+            <para>
+                                우리가 여기서 적용하는 패턴은 <emphasis>session-per-request</emphasis>이다. 하나의 요청이 
+                                서블릿에 도달할 때, 하나의 새로운 Hibernate <literal>Session</literal>이 
+                <literal>SessionFactory</literal> 상의 <literal>getCurrentSession()</literal>에 대한 
+                                첫번째 호출을 통해 열린다. 그때 하나의 데이터베이스 트랜잭션이 시작되고, 모든 데이터 접근이 하나의 트랜잭션 
+                                내에서 발생하는 한, 데이터가 읽혀지거나 기록되는데 문제가 없다(우리는 어플리케이션들 내에서 auto-commit 모드를 
+                                사용하지 않는다).
+            </para>
+
+           <para>
+                모든 데이터베이스 오퍼레이션 각각에 대해 새로운 Hibernate <literal>Session</literal>을 사용하지 <emphasis>말라</emphasis>.
+                전체 요청에 대해 영역지워진 한 개의 Hibernate <literal>Session</literal>을 사용하라. 그것이 자동적으로 현재의 자바 쓰레드에 바인드되도록 
+                <literal>getCurrentSession()</literal>을 사용하라.
+            </para>
+
+            <para>
+                                다음으로, 요청의 가능한 액션들이 처리되고 응답 HTML이 렌더링된다. 우리는 곧장 그부분으로 갈 것이다.
+            </para>
+
+            <para>
+                                마지막으로, 프로세싱과 렌더링이 완료될 때 작업 단위가 종료된다. 만일 어떤 문제가 프로세싱과 렌더링 동안에 발생될 경우, 
+                                하나의 예외상황이 던져질 것이고 데이터베이스 트랜잭션은 롤백될 것이다. 이것은 <literal>session-per-request</literal>을 
+                                완료시킨다. 모든 서블릿 내에 있는 트랜잭션 구획 코드 대신에 당신은 또한 서블릿 필터를 사용할 수 있다. 
+                <emphasis>Open Session in View</emphasis>로 명명되는 이 패턴에 대한 추가 정보는 Hibernate 웹 사이트와 위키를 보라.
+                                당신은 서블릿 내에서가 아닌 JSP 내에 당신의 뷰를 렌더링하는 것을 고려할 때 그것을 필요로 할 것이다.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-webapp-processing" revision="1">
+            <title>프로세싱과 렌더링</title>
+
+            <para>
+                                요청의 처리와 페이지의 렌더링을 구현하자.
+            </para>
+
+<programlisting><![CDATA[// Write HTML header
+PrintWriter out = response.getWriter();
+out.println("<html><head><title>Event Manager</title></head><body>");
+
+// Handle actions
+if ( "store".equals(request.getParameter("action")) ) {
+
+    String eventTitle = request.getParameter("eventTitle");
+    String eventDate = request.getParameter("eventDate");
+
+    if ( "".equals(eventTitle) || "".equals(eventDate) ) {
+        out.println("<b><i>Please enter event title and date.</i></b>");
+    } else {
+        createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
+        out.println("<b><i>Added event.</i></b>");
+    }
+}
+
+// Print page
+printEventForm(out);
+listEvents(out, dateFormatter);
+
+// Write HTML footer
+out.println("</body></html>");
+out.flush();
+out.close();]]></programlisting>
+
+            <para>
+                Java와 HTML이 혼합된 이 코딩이 보다 복잡한 어플리케이션에서 기준이 될 수 없다 할지라도, 우리는 
+                                단지 이 튜토리얼 내에서 기본 Hibernate 개념들을 설명하고 있음을 염두에 두라. 코드는 
+                                하나의 HTML 헤더와 하나의 footer를 프린트한다. 이 페이지 내에 이벤트 엔트리를 위한 
+                                하나의 HTML form과 데이터베이스 내에 있는 모든 이벤트들의 목록이 프린트된다. 첫 번째 메소드는 
+                                시행적이고 오직 HTML을 출력한다:
+            </para>
+
+            <programlisting><![CDATA[private void printEventForm(PrintWriter out) {
+    out.println("<h2>Add new event:</h2>");
+    out.println("<form>");
+    out.println("Title: <input name='eventTitle' length='50'/><br/>");
+    out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");
+    out.println("<input type='submit' name='action' value='store'/>");
+    out.println("</form>");
+}]]></programlisting>
+
+            <para>
+                <literal>listEvents()</literal> 메소드는 하나의 질의를 실행하기 위해서 현재의 
+                                쓰레드에 결합된 Hibernate <literal>Session</literal>을 사용한다:
+            </para>
+
+            <programlisting><![CDATA[private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) {
+
+    List result = HibernateUtil.getSessionFactory()
+                    .getCurrentSession().createCriteria(Event.class).list();
+    if (result.size() > 0) {
+        out.println("<h2>Events in database:</h2>");
+        out.println("<table border='1'>");
+        out.println("<tr>");
+        out.println("<th>Event title</th>");
+        out.println("<th>Event date</th>");
+        out.println("</tr>");
+        for (Iterator it = result.iterator(); it.hasNext();) {
+            Event event = (Event) it.next();
+            out.println("<tr>");
+            out.println("<td>" + event.getTitle() + "</td>");
+            out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
+            out.println("</tr>");
+        }
+        out.println("</table>");
+    }
+}]]></programlisting>
+
+            <para>
+                                마지막으로, <literal>store</literal> 액션은 <literal>createAndStoreEvent()</literal>
+                                메소드로 디스패치된다. 그것은 현재 쓰레드의 <literal>Session</literal>을 사용한다:
+            </para>
+
+            <programlisting><![CDATA[protected void createAndStoreEvent(String title, Date theDate) {
+    Event theEvent = new Event();
+    theEvent.setTitle(title);
+    theEvent.setDate(theDate);
+
+    HibernateUtil.getSessionFactory()
+                    .getCurrentSession().save(theEvent);
+}]]></programlisting>
+
+            <para>
+                                즉 서블릿이 완성된다. 서블릿에 대한 요청은 하나의 단일 <literal>Session</literal>과 
+                <literal>Transaction</literal> 내에서 처리될 것이다. 이전처럼 스탠드얼론 어플리케이션에서, 
+                Hibernate는 이들 객체들을 실행 중인 현재 쓰레드에 자동적으로 바인드시킬 수 있다. 이것은 당신의 코드를 
+                                계층화 시키고 당신이 좋아하는 임의의 방법으로 <literal>SessionFactory</literal>에 접근하는 자유를 
+                                당신에게 부여한다. 대개 당신은 보다 세련된 설계를 사용할 것이고 데이터 접근 코드를 데이터 접근 객체들 내로 
+                                이동시킬 것이다(DAO 패턴). 추가 예제들은 Hibernate 위키를 보라.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-webapp-deploy">
+            <title>배치하기 그리고 테스트하기</title>
+
+            <para>
+                                이 어플리케이션을 배치하기 위해서 당신은 하나의 웹 아카이브, WAR를 생성시켜야 한다. 다음 Ant target을 
+                                당신의 <literal>build.xml</literal> 내에 추가하라:
+            </para>
+
+<programlisting><![CDATA[<target name="war" depends="compile">
+    <war destfile="hibernate-tutorial.war" webxml="web.xml">
+        <lib dir="${librarydir}">
+          <exclude name="jsdk*.jar"/>
+        </lib>
+
+        <classes dir="${targetdir}"/>
+    </war>
+</target>]]></programlisting>
+
+            <para>
+                                이 target은 당신의 프로젝트 디렉토리 내에 <literal>hibernate-tutorial.war</literal>로 명명된 
+                                하나의 파일을 생성시킨다. 그것은 당신의 프로젝트의 기본 디렉토리 내에 기대되는 모든 라이브러리들과 
+                <literal>web.xml</literal> 디스크립터를 패키징한다: 
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+    xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+    <servlet>
+        <servlet-name>Event Manager</servlet-name>
+        <servlet-class>events.EventManagerServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Event Manager</servlet-name>
+        <url-pattern>/eventmanager</url-pattern>
+    </servlet-mapping>
+</web-app>]]></programlisting>
+
+            <para>
+                                당신이 웹 어플리케이션을 컴파일하고 배치하기 전에, 하나의 부가적인 라이브러리가 필요함을 노트하라: 
+                <literal>jsdk.jar</literal>. 당신이 이미 이 라이브러리를 갖고 있지 않을 경우, 이것은 Java servlet 
+                development kit이며, Sun 웹 사이트로부터 그것을 얻어서 그것을 당신의 라이브러리 디렉토리에 복사하라.
+                                하지만 그것은 오직 컴파일 시에만 사용될 것이고 WAR 패키지에서는 제외된다.
+            </para>
+
+            <para>
+                                빌드하고 배치하기 위해 당신의 프로젝트 디렉토리 내에서 <literal>ant war</literal>를 호출하고 
+                <literal>hibernate-tutorial.war</literal> 파일을 당신의 Tomcat <literal>webapp</literal> 
+                                디렉토리로 복사하라. 만일 당신이 Tomcat을 설치하지 않았다면, 그것을 내려받아 설치 지침들을 따르라. 당신은 
+                                이 어플리케이션을 배치하기 위해 임의의 Tomcat 구성을 변경하지 않아야 한다.
+            </para>
+
+            <para>
+                                일단 배치했고 Tomcat이 실행중이면, <literal>http://localhost:8080/hibernate-tutorial/eventmanager</literal>로 
+                                어플리케이션에 접근하라. 첫 번째 요청이 당신의 서블릿에 도달할 때 Hibernate가 초기화(<literal>HibernateUtil</literal>
+                                내에 있는 static initializer가 호출된다) 되는 것을 보기 위해 그리고 만일 어떤 예외상황들이 발생할 경우 
+                                상세한 출력을 얻기 위해서  Tomcat 로그를 지켜보도록 하라.
+            </para>
+
+        </sect2>
+    </sect1>
+
+    <sect1 id="tutorial-summary" revision="1">
+        <title>요약</title>
+
+        <para>
+                        이 튜토리얼은 간단한 스탠드얼론 Hibernate 어플리케이션과 하나의 작은 웹 어플리케이션을 작성하는 기초를 다루었다.
+        </para>
+
+        <para>
+                        만일 당신이 이미 Hibernate에 자신이 있다고 느낀다면, 당신이 흥미를 찾는 주제들에 대한 참조 문서 목차를 계속 브라우징하라 
+            - 가장 많이 요청되는 것은 트랜잭션 처리(<xref linkend="transactions"/>), 페치 퍼포먼스(<xref linkend="performance"/>), 
+            또는 API 사용법(<xref linkend="objectstate"/>), 그리고 질의 특징들(<xref linkend="objectstate-querying"/>)이다.
+        </para>
+
+        <para>
+                        더 많은(특화된) 튜토리얼들에 대해서는 Hibernate 웹 사이트를 체크하는 것을 잊지 말라. 
+        </para>
+
+    </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/xml.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/xml.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/docbook/modules/xml.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,273 @@
+<chapter id="xml">
+    <title>XML 매핑</title>
+
+    <para><emphasis>
+                이것은 Hibernate3.0에서 실험적인 특징이고 매우 활동적으로 개발 중에 있음을 노트하라.
+    </emphasis></para>
+
+    <sect1 id="xml-intro" revision="1">
+        <title>XML 데이터로 작업하기</title>
+
+        <para>
+            Hibernate는 당신이 영속 POJO들로 작업하는 것과 아주 동일한 방법으로 영속 XML 데이터에 작업하도록 해준다. 파싱된 XML 트리는 
+                        단지 객체 레벨에서 관계형 데이터를 나타내는 또 다른 방법으로 간주될 수 있다. 하나의 파싱된 XML 트리는 POJO들 대신, 객체 레벨에서 
+                        관계형 데이터를 표현하는 단지 또 다른 방법으로 간주될 수 있다.
+        </para>
+
+        <para>
+            Hibernate는 XML 트리들을 처리하는 API로서 dom4j를 지원한다. 당신은 데이터베이스로부터 dom4j 트리들을 검색하고 당신이 그 트리를 
+                        데이터베이스와 자동적으로 동기화시키기 위해 어떤 변경을 행하도록 하는 질의들을 작성할 수 있다. 당신은 심지어 XML 문서를 취하고, 
+            dom4j를 사용하여 그것을 파싱하고, Hibernate의 다음 기본적인 오퍼레이션들 중 어떤 것으로서 그것을 데이터베이스에 저장시킬 수 있다: 
+            <literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal>(merging(병합)은 아직 지원되지 
+                        않는다).
+        </para>
+
+        <para>
+                        이 특징은 데이터 가져오기/내보내기,JMS 또는 SOAP 그리고 XSLT-기반의 레포팅을 통한 엔티티 데이터의 구체화를 포함하는 많은 
+                        어플리케이션들을 갖는다.
+        </para>
+        
+        <para>
+                         하나의 매핑은 클래스들의 프로퍼티들과 XML 문서의 노드들을 데이터베이스로 동시에 매핑시키는데 사용될 수 있거나, 만일 매핑할 클래스가 
+                         존재하지 않을 경우, 그것은 단지 XML을 매핑시키는데 사용될 수도 있다.
+        </para>
+        
+        <sect2 id="xml-intro-mapping">
+            <title>XML과 클래스 매핑을 함께 지정하기</title>
+
+            <para>
+                                다음은 POJO와 XML을 동시에 매핑시키는 예제이다 :
+            </para>
+            
+            <programlisting><![CDATA[<class name="Account" 
+        table="ACCOUNTS" 
+        node="account">
+        
+    <id name="accountId" 
+            column="ACCOUNT_ID" 
+            node="@id"/>
+            
+    <many-to-one name="customer" 
+            column="CUSTOMER_ID" 
+            node="customer/@id" 
+            embed-xml="false"/>
+            
+    <property name="balance" 
+            column="BALANCE" 
+            node="balance"/>
+            
+    ...
+    
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="xml-onlyxml">
+            <title>XML 매핑만을 지정하기</title>
+
+            <para>
+                                다음은 POJO 클래스가 존재하지 않는 예제이다:
+            </para>
+            
+            <programlisting><![CDATA[<class entity-name="Account" 
+        table="ACCOUNTS" 
+        node="account">
+        
+    <id name="id" 
+            column="ACCOUNT_ID" 
+            node="@id" 
+            type="string"/>
+            
+    <many-to-one name="customerId" 
+            column="CUSTOMER_ID" 
+            node="customer/@id" 
+            embed-xml="false" 
+            entity-name="Customer"/>
+            
+    <property name="balance" 
+            column="BALANCE" 
+            node="balance" 
+            type="big_decimal"/>
+            
+    ...
+    
+</class>]]></programlisting>
+        
+            <para>
+                                이 매핑은 dom4j 트리로서 또는 프로퍼티 name/value 쌍들(java <literal>Map</literal>들)의 그래프로서 데이터에 
+                                접근하는 것을 당신에게 허용해준다. 프로퍼티 이름들은 HQL 질의들 내에서 참조될 수도 있는 순수하게 논리적인 구조체들이다.
+            </para>
+
+        </sect2>
+        
+     </sect1>
+     
+    <sect1 id="xml-mapping" revision="1">
+        <title>XML 매핑 메타데이터</title>
+
+        <para>
+                        많은 Hibernate 매핑 요소들은  <literal>node</literal> 속성을 수용한다. 이것은 당신이 프로퍼티 또는 엔티티 데이터를 소유하는 
+            XML 속성이나 요소의 이름을 지정하도록 한다. <literal>node</literal> 속성의 포맷은 다음 중 하나이어야 한다:
+        </para>
+        
+        <itemizedlist spacing="compact">
+        <listitem>
+            <para><literal>"element-name"</literal> - 명명된 XML 요소로 매핑시킨다</para>
+        </listitem>
+        <listitem>
+            <para><literal>"@attribute-name"</literal> - 명명된 XML 속성으로 매핑시킨다 </para>
+        </listitem>
+        <listitem>
+            <para><literal>"."</literal> - 부모 요소로 매핑 시킨다</para>
+        </listitem>
+        <listitem>
+            <para>
+                <literal>"element-name/@attribute-name"</literal> - 
+                                명명된 요소의 명명된 속성으로 매핑시킨다
+            </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+                        콜렉션들과 단일 값 콜렉션들의 경우, 추가적인 <literal>embed-xml</literal> 속성이 존재한다. 만일 <literal>embed-xml="true"</literal> 
+                        일 경우, 연관된 엔티티(또는 value 타입을 가진 콜렉션)에 대한 디폴트 XML 트리는 그 연관을 소유하는 엔티티에 대한 XML 트리 속에 
+                        직접 삽입될 것이다. 그 밖의 경우 <literal>embed-xml="false"</literal> 일 경우, 참조된 식별자 값 만이 단일 포인트 연관들에 
+                        대해 나타날 것이고 콜렉션들은 단순히 전혀 나타나지 않을 것이다.
+        </para>
+        
+        <para>
+                        당신은 너무 많은 연관들에 대해 <literal>embed-xml="true"</literal>로 남겨두지 말도록 주의해야 한다. 왜냐하면 XML이 
+                        순환적으로 잘 처리하지 못하기 때문이다!
+        </para>
+        
+        <programlisting><![CDATA[<class name="Customer" 
+        table="CUSTOMER" 
+        node="customer">
+        
+    <id name="id" 
+            column="CUST_ID" 
+            node="@id"/>
+            
+    <map name="accounts" 
+            node="." 
+            embed-xml="true">
+        <key column="CUSTOMER_ID" 
+                not-null="true"/>
+        <map-key column="SHORT_DESC" 
+                node="@short-desc" 
+                type="string"/>
+        <one-to-many entity-name="Account"
+                embed-xml="false" 
+                node="account"/>
+    </map>
+    
+    <component name="name" 
+            node="name">
+        <property name="firstName" 
+                node="first-name"/>
+        <property name="initial" 
+                node="initial"/>
+        <property name="lastName" 
+                node="last-name"/>
+    </component>
+    
+    ...
+    
+</class>]]></programlisting>
+
+        <para>
+                        이 경우에, 우리는 실제 account 데이터가 아닌, account id들을 가진 콜렉션을 삽입시키기로 결정했다. 다음 HQL 질의:
+        </para>
+        
+        <programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
+        
+        <para>
+                        는 다음과 같은 데이터셋들을 반환할 것이다:
+        </para>
+        
+        <programlisting><![CDATA[<customer id="123456789">
+    <account short-desc="Savings">987632567</account>
+    <account short-desc="Credit Card">985612323</account>
+    <name>
+        <first-name>Gavin</first-name>
+        <initial>A</initial>
+        <last-name>King</last-name>
+    </name>
+    ...
+</customer>]]></programlisting>
+
+        <para>
+                        만일 당신이 <literal>&lt;one-to-many&gt;</literal> 매핑에 대해 <literal>embed-xml="true"</literal>를 설정할 경우, 
+                        데이터는 다음과 같이 보일 수도 있다:
+        </para>
+        
+        <programlisting><![CDATA[<customer id="123456789">
+    <account id="987632567" short-desc="Savings">
+        <customer id="123456789"/>
+        <balance>100.29</balance>
+    </account>
+    <account id="985612323" short-desc="Credit Card">
+        <customer id="123456789"/>
+        <balance>-2370.34</balance>
+    </account>
+    <name>
+        <first-name>Gavin</first-name>
+        <initial>A</initial>
+        <last-name>King</last-name>
+    </name>
+    ...
+</customer>]]></programlisting>
+       
+    </sect1>
+    
+    
+    <sect1 id="xml-manipulation" revision="1">
+        <title>XML 데이터 처리하기</title>
+        
+        <para>
+                        우리의 어플리케이션 내에서 XML 문서들을 다시 읽어들이고 업데이트 시키자. 우리는 dom4j 세션을 얻어서 이것을 행한다:
+        </para>
+        
+       <programlisting><![CDATA[Document doc = ....;
+       
+Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+List results = dom4jSession
+    .createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")
+    .list();
+for ( int i=0; i<results.size(); i++ ) {
+    //add the customer data to the XML document
+    Element customer = (Element) results.get(i);
+    doc.add(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+       
+       <programlisting><![CDATA[Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+Element cust = (Element) dom4jSession.get("Customer", customerId);
+for ( int i=0; i<results.size(); i++ ) {
+    Element customer = (Element) results.get(i);
+    //change the customer name in the XML and database
+    Element name = customer.element("name");
+    name.element("first-name").setText(firstName);
+    name.element("initial").setText(initial);
+    name.element("last-name").setText(lastName);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            XML 기반의 데이터 가져오기/내보내기를 구현하는데 이 특징과 Hibernate의 <literal>replicate()</literal> 오퍼레이션을 
+                        결합시키는 것이 매우 유용하다.
+        </para>
+       
+    </sect1>
+     
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/css/html.css
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/css/html.css	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/css/html.css	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,97 @@
+A {
+    color: #003399;
+}
+
+A:active {
+    color: #003399;
+}
+
+A:visited {
+    color: #888888;
+}
+
+P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
+    color: #000000;
+}
+
+TD, TH, SPAN {
+    color: #000000;
+}
+
+BLOCKQUOTE {
+    margin-right: 0px;
+}
+
+
+H1, H2, H3, H4, H5, H6    {
+    color: #000000;
+    font-weight:500;
+    margin-top:10px;
+    padding-top:15px;
+}
+
+TABLE  {
+    border-collapse: collapse;
+    border-spacing:0;
+    border: 1px thin black;
+    empty-cells: hide;
+}
+
+TD  {
+    padding: 4pt;
+}
+
+H1 { font-size: 150%; }
+H2 { font-size: 140%; }
+H3 { font-size: 110%; font-weight: bold; }
+H4 { font-size: 110%; font-weight: bold;}
+H5 { font-size: 100%; font-style: italic; }
+H6 { font-size: 100%; font-style: italic; }
+
+TT {
+font-size: 90%;
+    font-family: "Courier New", Courier, monospace;
+    color: #000000;
+}
+
+PRE {
+font-size: 100%;
+    padding: 5px;
+    border-style: solid;
+    border-width: 1px;
+    border-color: #CCCCCC;
+    background-color: #F4F4F4;
+}
+
+UL, OL, LI {
+    list-style: disc;
+}
+
+HR  {
+    width: 100%;
+    height: 1px;
+    background-color: #CCCCCC;
+    border-width: 0px;
+    padding: 0px;
+    color: #CCCCCC;
+}
+
+.variablelist { 
+    padding-top: 10; 
+    padding-bottom:10; 
+    margin:0;
+}
+
+.itemizedlist, UL { 
+    padding-top: 0; 
+    padding-bottom:0; 
+    margin:0; 
+}
+
+.term { 
+    font-weight:bold;
+}
+
+
+
+    

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/AuthorWork.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/AuthorWork.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/AuthorWork.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/AuthorWork.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/CustomerOrderProduct.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/CustomerOrderProduct.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/CustomerOrderProduct.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/CustomerOrderProduct.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/EmployerEmployee.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/EmployerEmployee.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/EmployerEmployee.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/EmployerEmployee.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/full_cream.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/full_cream.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/full_cream.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/full_cream.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/full_cream.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,429 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="354.331"
+   height="336.614"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+     style="font-size:12;"
+     id="g659">
+    <rect
+       width="212.257"
+       height="57.2441"
+       x="17.9576"
+       y="100.132"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       transform="matrix(0.743454,0,0,0.482981,6.46949,52.2178)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <rect
+     width="325.86"
+     height="63.6537"
+     x="17.4083"
+     y="15.194"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect136" />
+  <rect
+     width="325.86"
+     height="63.6537"
+     x="13.6713"
+     y="12.4966"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect126" />
+  <g
+     transform="matrix(1.14345,0,0,0.729078,-1.67818,105.325)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <text
+     x="170.824753"
+     y="58.402939"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="170.824997"
+       y="58.402901"
+       id="tspan360">
+Application</tspan>
+  </text>
+  <text
+     x="178.076340"
+     y="364.281433"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="178.076004"
+       y="364.281006"
+       id="tspan421">
+Database</tspan>
+  </text>
+  <text
+     x="68.605331"
+     y="138.524582"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="68.605301"
+       y="138.524994"
+       id="tspan384">
+SessionFactory</tspan>
+  </text>
+  <rect
+     width="67.0014"
+     height="101.35"
+     x="196.927"
+     y="89.2389"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect387" />
+  <rect
+     width="67.0014"
+     height="101.35"
+     x="194.633"
+     y="86.4389"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect388" />
+  <text
+     x="249.108841"
+     y="173.885559"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text389">
+    <tspan
+       x="249.108994"
+       y="173.886002"
+       id="tspan392">
+Session</tspan>
+  </text>
+  <rect
+     width="73.0355"
+     height="101.35"
+     x="270.995"
+     y="90.0018"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect395" />
+  <rect
+     width="73.0355"
+     height="101.35"
+     x="267.869"
+     y="87.2018"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect396" />
+  <text
+     x="328.593658"
+     y="174.715622"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text397">
+    <tspan
+       x="328.593994"
+       y="174.716003"
+       id="tspan563">
+Transaction</tspan>
+  </text>
+  <g
+     transform="matrix(0.29544,0,0,0.397877,9.70533,103.96)"
+     style="font-size:12;"
+     id="g565">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect566" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect567" />
+  </g>
+  <text
+     x="25.592752"
+     y="204.497803"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text568">
+    <tspan
+       x="25.592800"
+       y="204.498001"
+       id="tspan662">
+TransactionFactory</tspan>
+  </text>
+  <g
+     transform="matrix(0.298082,0,0,0.397877,99.6898,103.96)"
+     style="font-size:12;"
+     id="g573">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect574" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect575" />
+  </g>
+  <text
+     x="134.030670"
+     y="205.532791"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text576">
+    <tspan
+       x="134.031006"
+       y="205.533005"
+       id="tspan664">
+ConnectionProvider</tspan>
+  </text>
+  <g
+     transform="matrix(1.14345,0,0,0.729078,-1.67818,38.9539)"
+     style="font-size:12;"
+     id="g587">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect588" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect589" />
+  </g>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="25.6196"
+     y="206.028"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect594" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="24.4229"
+     y="204.135"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect595" />
+  <text
+     x="85.575645"
+     y="282.300354"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text596">
+    <tspan
+       x="85.575600"
+       y="282.299988"
+       id="tspan607">
+JNDI</tspan>
+  </text>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="236.937"
+     y="206.791"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect610" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="235.741"
+     y="204.898"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect611" />
+  <text
+     x="342.093201"
+     y="283.226410"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text612">
+    <tspan
+       x="342.092987"
+       y="283.226013"
+       id="tspan621">
+JTA</tspan>
+  </text>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="130.134"
+     y="206.791"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect616" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="128.937"
+     y="204.898"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect617" />
+  <text
+     x="212.445343"
+     y="283.226410"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text618">
+    <tspan
+       x="212.445007"
+       y="283.226013"
+       id="tspan623">
+JDBC</tspan>
+  </text>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,6.19341)"
+     style="font-size:12;"
+     id="g637">
+    <g
+       transform="matrix(0.499515,0,0,0.415467,-0.237339,5.61339)"
+       id="g167">
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="61.8805"
+         y="68.4288"
+         style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect134" />
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="59.2613"
+         y="65.8095"
+         style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect135" />
+    </g>
+    <text
+       x="33.749969"
+       y="50.589706"
+       style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+       id="text188">
+      <tspan
+         x="33.750000"
+         y="50.589699"
+         id="tspan635">
+Transient Objects</tspan>
+    </text>
+  </g>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+     style="font-size:12;"
+     id="g644">
+    <g
+       transform="matrix(0.297486,0,0,0.516482,230.251,36.9178)"
+       id="g364">
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="61.8805"
+         y="68.4288"
+         style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect365" />
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="59.2613"
+         y="65.8095"
+         style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect366" />
+    </g>
+    <text
+       x="277.123230"
+       y="85.155571"
+       style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+       id="text367">
+      <tspan
+         x="277.122986"
+         y="85.155602"
+         id="tspan631">
+Persistent</tspan>
+      <tspan
+         x="277.122986"
+         y="96.155602"
+         id="tspan633">
+Objects</tspan>
+    </text>
+  </g>
+</svg>

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/hibernate_logo_a.png
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/hibernate_logo_a.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/lite.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/lite.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/lite.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/lite.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/lite.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,334 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="318.898"
+   height="248.031"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <rect
+     width="291.837"
+     height="57.0074"
+     x="17.3169"
+     y="18.646"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect136" />
+  <rect
+     width="291.837"
+     height="57.0074"
+     x="13.9703"
+     y="16.2302"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect126" />
+  <g
+     transform="matrix(0.326107,0,0,0.765831,9.59261,8.98517)"
+     style="font-size:12;"
+     id="g161">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <g
+     transform="matrix(1.02406,0,0,0.652953,0.223384,39.9254)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <g
+     transform="matrix(0.449834,0,0,0.338463,-3.15909,9.73319)"
+     style="font-size:12;"
+     id="g167">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect134" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect135" />
+  </g>
+  <text
+     x="302.277679"
+     y="65.943230"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="302.277954"
+       y="65.943184"
+       id="tspan360">
+Application</tspan>
+  </text>
+  <text
+     x="36.235924"
+     y="63.796055"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text188">
+    <tspan
+       x="36.235950"
+       y="63.796051"
+       id="tspan427">
+Transient Objects</tspan>
+  </text>
+  <text
+     x="180.416245"
+     y="290.543701"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="180.415939"
+       y="290.543549"
+       id="tspan421">
+Database</tspan>
+  </text>
+  <text
+     x="25.037701"
+     y="179.154755"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="25.037655"
+       y="179.154648"
+       id="tspan384">
+SessionFactory</tspan>
+  </text>
+  <g
+     transform="matrix(0.252763,0,0,0.765831,109.104,8.98517)"
+     style="font-size:12;"
+     id="g386">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect387" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect388" />
+  </g>
+  <g
+     transform="matrix(0.297394,0,0,0.572692,101.502,21.6359)"
+     style="font-size:12;"
+     id="g364">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect365" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect366" />
+  </g>
+  <text
+     x="202.746506"
+     y="102.992203"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text367">
+    <tspan
+       x="202.746948"
+       y="102.992249"
+       id="tspan423">
+Persistent</tspan>
+    <tspan
+       x="202.746948"
+       y="116.992355"
+       id="tspan425">
+Objects</tspan>
+  </text>
+  <text
+     x="174.458496"
+     y="180.080795"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text389">
+    <tspan
+       x="174.458618"
+       y="180.080338"
+       id="tspan392">
+Session</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,188.675,8.98517)"
+     style="font-size:12;"
+     id="g394">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect395" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect396" />
+  </g>
+  <text
+     x="260.413269"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text397">
+    <tspan
+       x="260.412964"
+       y="179.154343"
+       id="tspan400">
+JDBC</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,229.156,8.98517)"
+     style="font-size:12;"
+     id="g405">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect406" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect407" />
+  </g>
+  <text
+     x="320.606903"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text408">
+    <tspan
+       x="320.606964"
+       y="179.154343"
+       id="tspan417">
+JNDI</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,269.281,8.98517)"
+     style="font-size:12;"
+     id="g411">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect412" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect413" />
+  </g>
+  <text
+     x="377.096313"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text414">
+    <tspan
+       x="377.096008"
+       y="179.154999"
+       id="tspan145">
+JTA</tspan>
+  </text>
+</svg>

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/overview.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/overview.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/overview.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/overview.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/main/resources/shared/images/overview.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,250 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="248.031"
+   height="248.031"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,-3.02123)"
+     style="font-size:12;"
+     id="g158">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="17.3527"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect136" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="15.3883"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect126" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,3.04452)"
+     style="font-size:12;"
+     id="g161">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,8.0993)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.543505,2.59104,21.1103)"
+     style="font-size:12;"
+     id="g167">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect134" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect135" />
+  </g>
+  <text
+     x="105.392174"
+     y="56.568123"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="105.392273"
+       y="56.568146"
+       id="tspan186">
+Application</tspan>
+  </text>
+  <text
+     x="81.820183"
+     y="103.149330"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:20;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text188">
+    <tspan
+       x="81.820213"
+       y="103.149727"
+       id="tspan206">
+Persistent Objects</tspan>
+  </text>
+  <text
+     x="111.548180"
+     y="278.927887"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="111.547874"
+       y="278.927551"
+       id="tspan200">
+Database</tspan>
+  </text>
+  <text
+     x="94.436180"
+     y="153.805740"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="94.436180"
+       y="153.805740"
+       id="tspan221">
+HIBERNATE</tspan>
+  </text>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,2.59083,1.02261)"
+     style="font-size:12;"
+     id="g254">
+    <g
+       transform="translate(4.58374,2.61928)"
+       id="g176">
+      <g
+         transform="matrix(0.571429,0,0,0.67347,-10.6174,117.093)"
+         id="g170">
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="61.8805"
+           y="68.4288"
+           style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect171" />
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="59.2613"
+           y="65.8095"
+           style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect172" />
+      </g>
+      <g
+         transform="matrix(0.571429,0,0,0.67347,138.682,117.093)"
+         id="g173">
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="61.8805"
+           y="68.4288"
+           style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect174" />
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="59.2613"
+           y="65.8095"
+           style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect175" />
+      </g>
+    </g>
+    <text
+       x="47.259438"
+       y="182.367538"
+       style="font-weight:bold;stroke-width:1pt;font-family:Courier;"
+       id="text191">
+      <tspan
+         x="47.259399"
+         y="182.367996"
+         id="tspan212">
+hibernate.</tspan>
+      <tspan
+         x="47.259399"
+         y="194.367996"
+         id="tspan214">
+properties</tspan>
+    </text>
+    <text
+       x="198.523010"
+       y="188.260941"
+       style="font-weight:normal;stroke-width:1pt;font-family:helvetica;"
+       id="text194">
+      <tspan
+         id="tspan195">
+XML Mapping</tspan>
+    </text>
+  </g>
+</svg>

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/Bangwool.ttf
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/Bangwool.ttf
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/Bangwool.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/Bangwool.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/Bangwool.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><font-metrics type="TYPE0"><font-name>Bangwool</font-name><embed/><cap-height>750</cap-height><x-height>500</x-height><ascender>901</ascender><descender>-325</descender><bbox><left>-638</left><bottom>-341</bottom><right>2735</right><top>1068</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><ttc-name>Bangwool</ttc-name><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="2" ue="13" us="13"/><bf gi="3" ue="126" us="32"/><bf gi="98" ue="255" us="160"/><bf gi="194" ue="263" us="262"/><bf gi="196" ue="269" us="268"/><bf gi="198" ue="273" us="273"/><bf gi="199" ue="287" us="286"/><bf gi="201" ue="305" us="304"/><bf gi="203" ue="322" us="321"/><bf gi="205" ue="339" us="338"/><bf gi="207" ue="353" us="350"/><bf gi="211" ue="376" us="376"/><bf gi="212" ue="382" us="381"/><bf gi="214" ue="402" us="402"/><bf gi="215" ue="711" us="710"/><bf gi="217" ue="!
 720" us="720"/><bf gi="218" ue="733" us="728"/><bf gi="224" ue="937" us="937"/><bf gi="225" ue="960" us="960"/><bf gi="226" ue="4370" us="4352"/><bf gi="245" ue="4469" us="4449"/><bf gi="266" ue="4516" us="4515"/><bf gi="268" ue="4546" us="4520"/><bf gi="295" ue="8212" us="8211"/><bf gi="297" ue="8218" us="8216"/><bf gi="300" ue="8222" us="8220"/><bf gi="303" ue="8226" us="8224"/><bf gi="306" ue="8230" us="8230"/><bf gi="307" ue="8240" us="8240"/><bf gi="308" ue="8251" us="8249"/><bf gi="311" ue="8361" us="8361"/><bf gi="312" ue="8364" us="8364"/><bf gi="313" ue="8451" us="8451"/><bf gi="314" ue="8457" us="8457"/><bf gi="315" ue="8467" us="8467"/><bf gi="316" ue="8482" us="8481"/><bf gi="318" ue="8706" us="8706"/><bf gi="319" ue="8710" us="8710"/><bf gi="320" ue="8719" us="8719"/><bf gi="321" ue="8722" us="8721"/><bf gi="323" ue="8725" us="8725"/><bf gi="324" ue="8730" us="8729"/><bf gi="326" ue="8734" us="8734"/><bf gi="327" ue="8747" us="8747"/><bf gi="328" ue="8757" us="!
 8756"/><bf gi="330" ue="8776" us="8776"/><bf gi="331" ue="8786" us="87
86"/><bf gi="332" ue="8801" us="8800"/><bf gi="334" ue="8805" us="8804"/><bf gi="336" ue="9674" us="9674"/><bf gi="337" ue="9679" us="9679"/><bf gi="338" ue="12305" us="12296"/><bf gi="348" ue="12311" us="12308"/><bf gi="352" ue="12643" us="12593"/><bf gi="403" ue="13249" us="13184"/><bf gi="469" ue="55203" us="44032"/><bf gi="11641" ue="65374" us="65281"/><bf gi="0" ue="65535" us="65535"/></bfranges><cid-widths start-index="0"><wx w="583"/><wx w="0"/><wx w="333"/><wx w="583"/><wx w="333"/><wx w="333"/><wx w="583"/><wx w="500"/><wx w="666"/><wx w="666"/><wx w="250"/><wx w="333"/><wx w="333"/><wx w="500"/><wx w="500"/><wx w="250"/><wx w="500"/><wx w="250"/><wx w="500"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="333"/><wx w="333"/><wx w="416"/><wx w="500"/><wx w="416"/><wx w="500"/><wx w="666"/><wx w="666"/><wx w="583"/><wx w="666"/><wx w="666"/><wx w="583"/><wx w="583"/><wx w="666"/>!
 <wx w="666"/><wx w="500"/><wx w="550"/><wx w="583"/><wx w="583"/><wx w="833"/><wx w="666"/><wx w="666"/><wx w="583"/><wx w="666"/><wx w="583"/><wx w="583"/><wx w="633"/><wx w="666"/><wx w="666"/><wx w="833"/><wx w="666"/><wx w="650"/><wx w="583"/><wx w="333"/><wx w="500"/><wx w="333"/><wx w="500"/><wx w="583"/><wx w="333"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="333"/><wx w="333"/><wx w="500"/><wx w="333"/><wx w="666"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="666"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="466"/><wx w="333"/><wx w="466"/><wx w="583"/><wx w="583"/><wx w="333"/><wx w="500"/><wx w="583"/><wx w="583"/><wx w="650"/><wx w="333"/><wx w="500"/><wx w="500"/><wx w="833"/><wx w="500"/><wx w="666"/><wx w="750"/><wx w="416"/><wx w="833"/><wx w="416"/><wx w="333"/><wx w="500"/><wx w="416"/><wx w="416"/><wx w="333"/>!
 <wx w="500"/><wx w="583"/><wx w="250"/><wx w="500"/><wx w="416"/><wx w
="500"/><wx w="666"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="666"/><wx w="666"/><wx w="666"/><wx w="666"/><wx w="666"/><wx w="666"/><wx w="1000"/><wx w="666"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="750"/><wx w="666"/><wx w="666"/><wx w="666"/><wx w="666"/><wx w="666"/><wx w="666"/><wx w="500"/><wx w="666"/><wx w="666"/><wx w="666"/><wx w="666"/><wx w="666"/><wx w="650"/><wx w="583"/><wx w="583"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="833"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="333"/><wx w="333"/><wx w="333"/><wx w="333"/><wx w="583"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="666"/><wx w="500"/><wx w="666"/><wx w="500"/><wx w="583"/><wx w="666"/><w!
 x w="500"/><wx w="500"/><wx w="333"/><wx w="750"/><wx w="500"/><wx w="1083"/><wx w="833"/><wx w="583"/><wx w="500"/><wx w="583"/><wx w="500"/><wx w="650"/><wx w="583"/><wx w="500"/><wx w="583"/><wx w="500"/><wx w="500"/><wx w="416"/><wx w="500"/><wx w="500"/><wx w="333"/><wx w="500"/><wx w="500"/><wx w="416"/><wx w="750"/><wx w="666"/><wx w="383"/><wx w="800"/><wx w="383"/><wx w="383"/><wx w="800"/><wx w="383"/><wx w="383"/><wx w="383"/><wx w="800"/><wx w="383"/><wx w="800"/><wx w="383"/><wx w="383"/><wx w="800"/><wx w="383"/><wx w="383"/><wx w="383"/><wx w="383"/><wx w="383"/><wx w="376"/><wx w="540"/><wx w="376"/><wx w="533"/><wx w="373"/><wx w="540"/><wx w="373"/><wx w="533"/><wx w="200"/><wx w="460"/><wx w="620"/><wx w="456"/><wx w="200"/><wx w="200"/><wx w="456"/><wx w="623"/><wx w="456"/><wx w="200"/><wx w="200"/><wx w="456"/><wx w="373"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/!
 ><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50
"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="50"/><wx w="500"/><wx w="1000"/><wx w="250"/><wx w="250"/><wx w="250"/><wx w="416"/><wx w="416"/><wx w="416"/><wx w="500"/><wx w="500"/><wx w="583"/><wx w="583"/><wx w="916"/><wx w="416"/><wx w="416"/><wx w="666"/><wx w="1000"/><wx w="750"/><wx w="916"/><wx w="916"/><wx w="500"/><wx w="1000"/><wx w="750"/><wx w="500"/><wx w="750"/><wx w="666"/><wx w="666"/><wx w="500"/><wx w="500"/><wx w="333"/><wx w="666"/><wx w="833"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="416"/><wx w="416"/><wx w="500"/><wx w="750"/><wx w="416"/><wx w="416"/><wx w="666"/><wx w="666"/><wx w="500"/><wx w="500"/><wx w="583"/><wx w="583"/><wx w="416"/><wx w="416"/><wx w="333"/><wx w="333"/><wx w="500"/><wx w="500"/><wx w="583"/><wx w="966"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="!
 966"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="966"/><wx w="583"/><wx w="583"/><wx w="966"/><wx w="583"/><wx w="583"/><wx w="966"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="916"/><wx w="1000"/><wx w="833"/><wx w="583"/><wx w="583"/><wx w="833"/><wx w="1000"/><wx w="833"/><wx w="583"/><wx w="583"/><wx w="833"/><wx w="583"/><wx w="1166"/><wx w="1166"/><wx w="1166"/><wx w="1333"/><wx w="1166"/><wx w="1083"/><wx w="1416"/><wx w="1250"/><wx w="1250"/><wx w="1750"/><wx w="1083"/><wx w="1083"/><wx w="1083"/><wx w="1000"/><wx w="1166"/><wx w="1000"/><wx w="1166"/><wx w="1666"/><wx w="2000"/><wx w="1833"/><wx w="1833"/><wx w="1000"/><wx w="1166"/><wx w="1000"/><wx w="1000"/><wx w="1166"/><wx w="1166"/><wx w="1166"/><wx w="1333"/><wx w="1166"/><!
 wx w="1166"/><wx w="1750"/><wx w="1583"/><wx w="1083"/><wx w="1583"/><
wx w="1750"/><wx w="1583"/><wx w="1083"/><wx w="1583"/><wx w="1583"/><wx w="2000"/><wx w="1083"/><wx w="1583"/><wx w="1916"/><wx w="1750"/><wx w="1500"/><wx w="2416"/><wx w="2833"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1166"/><wx w="1166"/><wx w="1166"/><wx w="1166"/><wx w="1333"/><wx w="1166"/><wx w="1500"/><wx w="1333"/><wx w="1333"/><wx w="1333"/><wx w="1500"/><wx w="1333"/><wx w="1666"/><wx w="1250"/><wx w="1583"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960!
 "/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793!
 "/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><w
x w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx!
  w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx!
  w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="1040"/><wx w="
1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="!
 626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="104!
 3"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="104
3"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"!
 /><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"!
 /><wx w="793"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/
><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1!
 293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1206"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><w!
 x w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><w
x w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1206"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376!
 "/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1456"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w!
 ="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w
="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1040"/><wx w="1043"/><wx w="1043"/>!
 <wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1456"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1!
 460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1
460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx!
  w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1206"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210!
 "/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="873"
/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/!
 ><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/!
 ><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx 
w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w!
 ="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx!
  w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="8
76"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="62!
 6"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="!
 876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/
><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/>!
 <wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/>!
 <wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w
="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w=!
 "793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w=!
 "793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"
/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/!
 ><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626!
 "/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><w
x w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="104!
 3"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><!
 wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w=
"626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="!
 793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="!
 1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="
1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1206"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1373"/><w!
 x w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1206"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="137!
 6"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="137
6"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1456"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w!
 ="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/!
 ><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/
><wx w="1043"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1456"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1!
 460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><w!
 x w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><w
x w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1206"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210!
 "/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><w!
 x w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="
876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="9!
 60"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="6!
 23"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/>
<wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx!
  w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/!
 ><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx 
w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx!
  w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx!
  w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="8
76"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="95!
 6"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="96!
 0"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><
wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><w!
 x w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><w!
 x w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="
960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w=!
 "626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w=!
 "876"/><wx w="876"/><wx w="876"/><wx w="1040"/><wx w="1043"/><wx w="10
43"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626!
 "/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793!
 "/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><w
x w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx!
  w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx!
  w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="9
60"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="96!
 0"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx !
 w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx 
w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/>!
 <wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"!
 /><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx
 w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx !
 w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="129!
 3"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="129
3"/><wx w="1293"/><wx w="1293"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w!
 ="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1206"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/!
 ><wx w="1376"/><wx w="1206"/><wx w="1210"/><wx w="1210"/><wx w="1210"/
><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1!
 043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1456"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><w!
 x w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><w
x w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043!
 "/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1456"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w!
 ="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w
="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1290"/><wx w="1293"/><wx w="1293"/>!
 <wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1206"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/!
 ><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx 
w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w!
 ="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w!
 ="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793
"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"!
 /><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="87!
 6"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><
wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><w!
 x w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/>!
 <wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w
="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w=!
 "793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w=!
 "1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1290"/><wx w=
"1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1206"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><!
 wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1206"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1373"/><wx w="1376"/><wx w="13!
 76"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="13
76"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx !
 w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1456"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"!
 /><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"
/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="!
 1456"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><!
 wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><
wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1206"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="121!
 0"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><!
 wx w="960"/><wx w="960"/><wx w="960"/><wx w="873"/><wx w="876"/><wx w=
"876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="!
 793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="!
 960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/
><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><w!
 x w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"!
 /><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx
 w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w!
 ="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><w!
 x w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="
626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="8!
 76"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="9!
 60"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/>
<wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><!
 wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><!
 wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="956"/><wx w=
"960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w!
 ="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w!
 ="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876
"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="62!
 6"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="87!
 6"/><wx w="876"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><
wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w=!
 "1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1206"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/>!
 <wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/>
<wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1206"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="12!
 10"/><wx w="1210"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1373"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx!
  w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx
 w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1376"/><wx w="1456"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"!
 /><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w=!
 "1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w=
"1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1456"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1460"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><!
 wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1290"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="1293"/><wx w="12!
 93"/><wx w="1293"/><wx w="1293"/><wx w="1206"/><wx w="1210"/><wx w="12
10"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="1210"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960!
 "/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793!
 "/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><w
x w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx!
  w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="1040"/><wx w="1043"/><!
 wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><
wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="!
 626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx !
 w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx 
w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"!
 /><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"!
 /><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx
 w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx !
 w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx !
 w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="96
0"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626!
 "/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="8!
 76"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/>
<wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><!
 wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/!
 ><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx 
w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w!
 ="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w!
 ="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960
"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"!
 /><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"!
 /><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx
 w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="1040"/><wx!
  w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><w!
 x w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="
626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w=!
 "1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w=!
 "626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"
/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/!
 ><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/!
 ><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx 
w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w!
 ="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w!
 ="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626
"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="87!
 6"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="87!
 3"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><
wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/>!
 <wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/>!
 <wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w
="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w=!
 "960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w=!
 "793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"
/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="956"/><wx w="960"/><wx w="960"/!
 ><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="956"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/!
 ><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx w="960"/><wx 
w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx!
  w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="1040"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="!
 1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="
1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="1043"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="!
 626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="873"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="876"/><wx w="790"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="793"/><wx w="!
 793"/><wx w="793"/><wx w="793"/><wx w="333"/><wx w="333"/><wx w="583"/
><wx w="500"/><wx w="666"/><wx w="666"/><wx w="250"/><wx w="333"/><wx w="333"/><wx w="500"/><wx w="500"/><wx w="250"/><wx w="500"/><wx w="250"/><wx w="500"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="583"/><wx w="333"/><wx w="333"/><wx w="416"/><wx w="500"/><wx w="416"/><wx w="500"/><wx w="666"/><wx w="666"/><wx w="583"/><wx w="666"/><wx w="666"/><wx w="583"/><wx w="583"/><wx w="666"/><wx w="666"/><wx w="500"/><wx w="550"/><wx w="583"/><wx w="583"/><wx w="833"/><wx w="666"/><wx w="666"/><wx w="583"/><wx w="666"/><wx w="583"/><wx w="583"/><wx w="633"/><wx w="666"/><wx w="666"/><wx w="833"/><wx w="666"/><wx w="650"/><wx w="583"/><wx w="333"/><wx w="500"/><wx w="333"/><wx w="500"/><wx w="583"/><wx w="333"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="333"/><wx w="333"/><wx w="500"/><wx w="333"/><wx w="666"/><wx w="500"/><wx w="500"/>!
 <wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="666"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="466"/><wx w="333"/><wx w="466"/><wx w="583"/></cid-widths></multibyte-extras></font-metrics>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/Hankc.ttf
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/Hankc.ttf
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/Hankc.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/Hankc.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/Hankc.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><font-metrics type="TYPE0"><font-name>Hankc</font-name><embed/><cap-height>740</cap-height><x-height>473</x-height><ascender>829</ascender><descender>263</descender><bbox><left>-45</left><bottom>-240</bottom><right>1192</right><top>904</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><ttc-name>Hankc</ttc-name><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="13009" ue="13" us="13"/><bf gi="3" ue="32" us="32"/><bf gi="9603" ue="33" us="33"/><bf gi="9602" ue="34" us="34"/><bf gi="4" ue="38" us="36"/><bf gi="13001" ue="39" us="39"/><bf gi="7" ue="41" us="40"/><bf gi="13002" ue="42" us="42"/><bf gi="9" ue="59" us="43"/><bf gi="12434" ue="60" us="60"/><bf gi="26" ue="61" us="61"/><bf gi="12435" ue="62" us="62"/><bf gi="27" ue="95" us="63"/><bf gi="13000" ue="96" us="96"/><bf gi="60" ue="127" us="97"/><bf gi="3" ue="160" us="160"/><bf gi="10472"!
  ue="161" us="161"/><bf gi="12430" ue="162" us="162"/><bf gi="12429" ue="163" us="163"/><bf gi="10473" ue="164" us="164"/><bf gi="12428" ue="165" us="165"/><bf gi="10474" ue="168" us="167"/><bf gi="10476" ue="170" us="170"/><bf gi="10477" ue="180" us="176"/><bf gi="12424" ue="181" us="181"/><bf gi="10482" ue="186" us="182"/><bf gi="10461" ue="191" us="188"/><bf gi="12380" ue="197" us="192"/><bf gi="10487" ue="198" us="198"/><bf gi="12386" ue="199" us="199"/><bf gi="12373" ue="201" us="200"/><bf gi="12372" ue="202" us="202"/><bf gi="12375" ue="207" us="203"/><bf gi="10488" ue="208" us="208"/><bf gi="12387" ue="214" us="209"/><bf gi="10489" ue="216" us="215"/><bf gi="12393" ue="220" us="217"/><bf gi="12426" ue="221" us="221"/><bf gi="10491" ue="223" us="222"/><bf gi="12397" ue="229" us="224"/><bf gi="10493" ue="230" us="230"/><bf gi="12403" ue="239" us="231"/><bf gi="10494" ue="240" us="240"/><bf gi="12421" ue="241" us="241"/><bf gi="12412" ue="242" us="242"/><bf gi="12414" u!
 e="243" us="243"/><bf gi="12413" ue="244" us="244"/><bf gi="12415" ue=
"246" us="245"/><bf gi="10495" ue="248" us="247"/><bf gi="12417" ue="252" us="249"/><bf gi="12422" ue="253" us="253"/><bf gi="10497" ue="254" us="254"/><bf gi="12423" ue="255" us="255"/><bf gi="10498" ue="273" us="273"/><bf gi="10499" ue="295" us="294"/><bf gi="10501" ue="307" us="305"/><bf gi="10504" ue="312" us="312"/><bf gi="10505" ue="323" us="319"/><bf gi="10510" ue="331" us="330"/><bf gi="10469" ue="338" us="338"/><bf gi="10471" ue="339" us="339"/><bf gi="12433" ue="352" us="352"/><bf gi="12431" ue="353" us="353"/><bf gi="10512" ue="359" us="358"/><bf gi="12425" ue="376" us="376"/><bf gi="12427" ue="382" us="382"/><bf gi="10514" ue="711" us="711"/><bf gi="10515" ue="720" us="720"/><bf gi="10516" ue="731" us="728"/><bf gi="12432" ue="732" us="732"/><bf gi="10520" ue="733" us="733"/><bf gi="10250" ue="929" us="913"/><bf gi="10267" ue="937" us="931"/><bf gi="10274" ue="961" us="945"/><bf gi="10291" ue="969" us="963"/><bf gi="10298" ue="1025" us="1025"/><bf gi="10299" ue="!
 1103" us="1040"/><bf gi="10363" ue="1105" us="1105"/><bf gi="10364" ue="8213" us="8213"/><bf gi="13005" ue="8217" us="8216"/><bf gi="13007" ue="8221" us="8220"/><bf gi="10466" ue="8225" us="8224"/><bf gi="10365" ue="8229" us="8229"/><bf gi="10465" ue="8230" us="8230"/><bf gi="10468" ue="8240" us="8240"/><bf gi="10366" ue="8243" us="8242"/><bf gi="10368" ue="8251" us="8251"/><bf gi="10369" ue="8308" us="8308"/><bf gi="10370" ue="8319" us="8319"/><bf gi="10371" ue="8324" us="8321"/><bf gi="10375" ue="8361" us="8361"/><bf gi="10376" ue="8451" us="8451"/><bf gi="10377" ue="8457" us="8457"/><bf gi="10378" ue="8467" us="8467"/><bf gi="10379" ue="8470" us="8470"/><bf gi="10380" ue="8481" us="8481"/><bf gi="10470" ue="8482" us="8482"/><bf gi="10381" ue="8486" us="8486"/><bf gi="10382" ue="8491" us="8491"/><bf gi="10383" ue="8532" us="8531"/><bf gi="10385" ue="8542" us="8539"/><bf gi="10389" ue="8553" us="8544"/><bf gi="10399" ue="8569" us="8560"/><bf gi="10409" ue="8601" us="8592"/!
 ><bf gi="10419" ue="8658" us="8658"/><bf gi="10420" ue="8660" us="8660
"/><bf gi="10421" ue="8704" us="8704"/><bf gi="10422" ue="8707" us="8706"/><bf gi="10424" ue="8712" us="8711"/><bf gi="10426" ue="8715" us="8715"/><bf gi="10427" ue="8719" us="8719"/><bf gi="10428" ue="8721" us="8721"/><bf gi="10458" ue="8722" us="8722"/><bf gi="10429" ue="8730" us="8730"/><bf gi="10430" ue="8734" us="8733"/><bf gi="10432" ue="8736" us="8736"/><bf gi="10433" ue="8741" us="8741"/><bf gi="10434" ue="8748" us="8743"/><bf gi="10440" ue="8750" us="8750"/><bf gi="10441" ue="8757" us="8756"/><bf gi="10443" ue="8765" us="8764"/><bf gi="10445" ue="8786" us="8786"/><bf gi="10446" ue="8801" us="8800"/><bf gi="10448" ue="8805" us="8804"/><bf gi="10450" ue="8811" us="8810"/><bf gi="10452" ue="8835" us="8834"/><bf gi="10454" ue="8839" us="8838"/><bf gi="10456" ue="8857" us="8857"/><bf gi="10457" ue="8869" us="8869"/><bf gi="10615" ue="8978" us="8978"/><bf gi="10459" ue="8993" us="8992"/><bf gi="9689" ue="9326" us="9312"/><bf gi="9704" ue="9346" us="9332"/><bf gi="9719" ue!
 ="9397" us="9372"/><bf gi="9745" ue="9449" us="9424"/><bf gi="9771" ue="9475" us="9472"/><bf gi="9775" ue="9547" us="9484"/><bf gi="9605" ue="9618" us="9618"/><bf gi="9839" ue="9633" us="9632"/><bf gi="9841" ue="9641" us="9635"/><bf gi="9848" ue="9651" us="9650"/><bf gi="9850" ue="9655" us="9654"/><bf gi="9852" ue="9661" us="9660"/><bf gi="9854" ue="9665" us="9664"/><bf gi="9856" ue="9672" us="9670"/><bf gi="9859" ue="9675" us="9675"/><bf gi="9860" ue="9681" us="9678"/><bf gi="9864" ue="9734" us="9733"/><bf gi="9866" ue="9743" us="9742"/><bf gi="9868" ue="9756" us="9756"/><bf gi="9869" ue="9758" us="9758"/><bf gi="9870" ue="9792" us="9792"/><bf gi="9871" ue="9794" us="9794"/><bf gi="9872" ue="9825" us="9824"/><bf gi="9874" ue="9829" us="9827"/><bf gi="9877" ue="9834" us="9831"/><bf gi="9881" ue="9837" us="9836"/><bf gi="9883" ue="12291" us="12288"/><bf gi="9887" ue="12305" us="12296"/><bf gi="9897" ue="12309" us="12307"/><bf gi="9900" ue="12435" us="12353"/><bf gi="9983" ue!
 ="12534" us="12449"/><bf gi="9636" ue="12643" us="12593"/><bf gi="1006
9" ue="12686" us="12644"/><bf gi="10112" ue="12828" us="12800"/><bf gi="10141" ue="12923" us="12896"/><bf gi="10169" ue="12927" us="12927"/><bf gi="10170" ue="13188" us="13184"/><bf gi="10175" ue="13258" us="13192"/><bf gi="10242" ue="13264" us="13263"/><bf gi="10244" ue="13267" us="13267"/><bf gi="10245" ue="13270" us="13270"/><bf gi="10246" ue="13272" us="13272"/><bf gi="10247" ue="13277" us="13275"/><bf gi="10616" ue="44618" us="44032"/><bf gi="91" ue="44619" us="44619"/><bf gi="11203" ue="45201" us="44620"/><bf gi="92" ue="45207" us="45202"/><bf gi="11785" ue="45794" us="45208"/><bf gi="98" ue="55203" us="45795"/><bf gi="9507" ue="57344" us="57344"/><bf gi="9606" ue="57370" us="57345"/><bf gi="9509" ue="57402" us="57371"/><bf gi="9541" ue="57446" us="57441"/><bf gi="9687" ue="57448" us="57447"/><bf gi="9547" ue="57503" us="57449"/><bf gi="9604" ue="57622" us="57622"/><bf gi="12981" ue="60266" us="60266"/><bf gi="10535" ue="65281" us="65281"/><bf gi="10526" ue="65284" us=!
 "65282"/><bf gi="10536" ue="65289" us="65285"/><bf gi="10529" ue="65291" us="65290"/><bf gi="10541" ue="65292" us="65292"/><bf gi="9508" ue="65293" us="65293"/><bf gi="10542" ue="65338" us="65294"/><bf gi="10531" ue="65339" us="65339"/><bf gi="10587" ue="65340" us="65340"/><bf gi="10532" ue="65343" us="65341"/><bf gi="10588" ue="65370" us="65344"/><bf gi="9632" ue="65374" us="65371"/><bf gi="10521" ue="65505" us="65504"/><bf gi="10524" ue="65506" us="65506"/><bf gi="10523" ue="65509" us="65509"/><bf gi="10525" ue="65510" us="65510"/><bf gi="0" ue="65535" us="65535"/></bfranges><cid-widths start-index="0"><wx w="250"/><wx w="0"/><wx w="731"/><wx w="250"/><wx w="500"/><wx w="823"/><wx w="676"/><wx w="296"/><wx w="296"/><wx w="665"/><wx w="238"/><wx w="497"/><wx w="238"/><wx w="300"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="281"/><wx w="281"/><wx w="791"/><wx w="502"/><wx w="696"/><!
 wx w="623"/><wx w="605"/><wx w="601"/><wx w="658"/><wx w="603"/><wx w=
"547"/><wx w="658"/><wx w="713"/><wx w="329"/><wx w="385"/><wx w="604"/><wx w="548"/><wx w="767"/><wx w="659"/><wx w="659"/><wx w="546"/><wx w="659"/><wx w="658"/><wx w="491"/><wx w="548"/><wx w="656"/><wx w="618"/><wx w="878"/><wx w="659"/><wx w="611"/><wx w="547"/><wx w="296"/><wx w="258"/><wx w="296"/><wx w="950"/><wx w="475"/><wx w="439"/><wx w="494"/><wx w="438"/><wx w="496"/><wx w="438"/><wx w="274"/><wx w="439"/><wx w="494"/><wx w="275"/><wx w="264"/><wx w="493"/><wx w="274"/><wx w="713"/><wx w="493"/><wx w="438"/><wx w="493"/><wx w="496"/><wx w="329"/><wx w="384"/><wx w="273"/><wx w="493"/><wx w="437"/><wx w="603"/><wx w="441"/><wx w="439"/><wx w="382"/><wx w="475"/><wx w="475"/><wx w="475"/><wx w="618"/><wx w="950"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="400"/><wx w="400"/><wx w="400"/><wx w="400"/><wx w="400"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="250"/><wx w="250"/>
<wx w="400"/><wx w="400"/><wx w="400"/><wx w="400"/><wx w="250"/><wx w="250"/><wx w="400"/><wx w="1000"/><wx w="250"/><wx w="500"/><wx w="500"/><wx w="400"/><wx w="751"/><wx w="1000"/><wx w="400"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="800"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="400"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="401"/><wx w="485"/><wx w="901"/><wx w="631"/><wx w="1000"/><wx w="800"/><wx w="768"/><wx w="900"/><wx w="900"/><wx w="770"/><wx w="900"/><wx w="900"/><wx w="900"/><wx w="900"/><wx w="450"/><wx w="450"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="646"/><wx w="571"/><wx w="675"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="314"/><wx w="281"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="332"/><wx w="332"/><wx w="500"/!
 ><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="384"/><wx w="384"/><wx w="384"/><wx w="226"/><wx w="384"/><wx w="651"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="398"/><wx w="499"/><wx w="699"/><wx w="400"/><wx w="1000"/><wx w="300"/><wx w="350"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="400"/><wx w="400"/><wx w="400"/><wx w="400"/><wx w="450"/><wx w="450"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="912"/><wx w="898"/><wx w="1000"/><wx w="1002"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1152"/><wx w="1202"/><wx w="1010"/><wx w="1191"/><wx w="1152"/><wx w="1201"/><wx w="101!
 0"/><wx w="1193"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="881"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="649"/><wx w="753"/><wx w="902"/><wx w="613"/><wx w="747"/><wx w="764"/><wx w="949"/><wx w="650"/><wx w="599"/><wx w="888"/><wx w="650"/><wx w="946"/><wx w="854"/><wx w="899"/><wx w="624"/><wx w="963"/><wx w="753"/><wx w="750"/><wx w="703"/><wx w="703"/><wx w="599"/><wx w="798"/><wx w="750"/><wx w="750"/><wx w="501"/><wx w="504"/><wx w="500"/><wx !
 w="501"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="50
0"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="501"/><wx w="500"/><wx w="669"/><wx w="749"/><wx w="619"/><wx w="624"/><wx w="651"/><wx w="658"/><wx w="659"/><wx w="870"/><wx w="548"/><wx w="668"/><wx w="668"/><wx w="691"/><wx w="628"/><wx w="779"/><wx w="669"/><wx w="605"/><wx w="664"/><wx w="600"/><wx w="588"/><wx w="641"/><wx w="560"/><wx w="629"/><wx w="676"/><wx w="683"/><wx w="591"/><wx w="860"/><wx w="882"/><wx w="809"/><wx w="857"/><wx w="601"/><wx w="581"/><wx w="754"/><wx w="704"/><wx w="450"/><wx w="450"/><wx w="450"/><wx w="450"/><wx w="500"/><wx w="450"/><wx w="586"/><wx w="450"/><wx w="500"/><wx w="500"/><wx w="467"/><wx w="450"/><wx w="581"/><wx w="500"/><wx w="450"/><wx w="500"/><wx w="452"/><wx w="450"/><wx w="477"/><wx w="450"/><wx w="550"/><wx w="502"/><wx w="500"/><wx w="450"/><wx w="623"/><wx w="631"/><wx w="593"/><wx w="611!
 "/><wx w="430"/><wx w="450"/><wx w="548"/><wx w="512"/><wx w="450"/><wx w="1000"/><wx w="1000"/><wx w="251"/><wx w="399"/><wx w="1000"/><wx w="350"/><wx w="399"/><wx w="350"/><wx w="350"/><wx w="350"/><wx w="350"/><wx w="1000"/><wx w="751"/><wx w="852"/><wx w="301"/><wx w="1000"/><wx w="1000"/><wx w="649"/><wx w="658"/><wx w="699"/><wx w="699"/><wx w="699"/><wx w="699"/><wx w="699"/><wx w="699"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="746"/><wx w="400"/><wx w="668"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="452"/><wx w="719"/><wx w="551"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="600"/><wx w="600"/><wx w="699"/><wx w="701"/><wx w="699"/><wx w="450"/><wx w="950"/><wx w="950"/><wx w="950"/><wx w="903"/><wx w="651"/><wx w="950"/><wx w="601"/><wx w="300"/><wx w="950"/><wx w="400"/><wx w="950"/><wx w="490"/><wx w="352"/><wx w="950"/><wx w="400"/><wx w="400"/><wx w="301"/><wx w="950"/><wx w="950"/><wx w="950"/><wx w="400"/><wx w="500"/><wx w="950"/><wx w="621"/><wx w="950"/><wx w="552"/><wx w="411"/><wx w="499"/><wx w="950"/><wx w="400"/><wx w="950"/><wx w="415"/><wx w="400"/><wx w="528"/><wx w="700"/><wx w="559"/><wx w="328"/><wx w="682"/><wx w="463"/><wx w="526"/><wx w="536"/><wx w="448"/><wx w="528"/><wx w="484"/><wx w="440"/><wx w="448"!
 /><wx w="422"/><wx w="591"/><wx w="359"/><wx w="1000"/><wx w="482"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="484"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="573"/><wx w="573"/><wx w="573"/><wx w="573"/><wx w="313"/><wx w="313"/><wx w="313"/><wx w="313"/><wx w="592"/><wx w="592"/><wx w="592"/><wx w="592"/><wx w="592"/><wx w="592"/><wx w="571"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="626"/><wx w="623"/><wx w="623"/><wx w="623"/><wx w="623"/><wx w="417"/><wx w="417"/><wx w="417"/><wx w="417"/><wx w="417"/><wx w="417"/><wx w="416"/><wx w="416"/><wx w="416"/><wx w="416"/><wx w="416"/><wx w="261"/><wx w="261"/><wx w="261"/><wx w="261"/><wx w="416"/><wx w="416"/><wx w="416"/><wx!
  w="416"/><wx w="416"/><wx w="468"/><wx w="468"/><wx w="468"/><wx w="468"/><wx w="468"/><wx w="417"/><wx w="417"/><wx w="588"/><wx w="580"/><wx w="580"/><wx w="363"/><wx w="503"/><wx w="475"/><wx w="475"/><wx w="365"/><wx w="475"/><wx w="466"/><wx w="475"/><wx w="475"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="995"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="998"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="250"/><wx w="250"!
 /><wx w="631"/><wx w="401"/><wx w="401"/><wx w="250"/><wx w="250"/><wx w="400"/><wx w="400"/><wx w="250"/></cid-widths></multibyte-extras></font-metrics>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/userconfig.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/userconfig.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/fop/userconfig.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,113 @@
+<!--<!DOCTYPE configuration SYSTEM "config.dtd">-->
+<!-- 
+     this file contains templates which allow an user easy 
+     configuration of Fop. Actually normally you don't need this configuration 
+     file, but if you need to change configuration, you should
+     always use this file and *not* config.xml. 
+     Usage: java org.apache.fop.apps.Fop -c userconfig.xml -fo fo-file -pdf pdf-file
+-->
+
+
+<configuration>
+
+<!--  
+baseDir: normally the base directory is the directory where the fo file is 
+         located. if you want to specify your own, uncomment this entry.
+         This value can also be a URL. Actually, the value is converted to 
+         a URL.
+-->
+<!--
+<entry>
+    <key>baseDir</key>
+    <value></value>
+  </entry>
+  -->
+<!--  
+fontBaseDir: Similar to baseDir, except that this value is used for fonts. If
+         it isn't specified, the value from baseDir is used.
+-->
+<!-- 
+  <entry>
+    <key>fontBaseDir</key>
+    <value></value>
+  </entry>
+-->
+
+<!--
+************************************************************************
+                        HYPHENATION 
+************************************************************************
+-->
+  
+<!--
+   hyphenation directory 
+   if you want to specify your own directory with hyphenation pattern
+   then uncomment the next entry and add the directory name
+-->
+
+<!--
+  <entry>
+    <key>hyphenation-dir</key>
+    <value>/java/xml-fop/hyph</value>
+  </entry>
+-->
+
+<!--
+************************************************************************
+  Add fonts here
+************************************************************************
+-->
+
+<fonts>
+  <!-- example -->
+ <!--
+ <font metrics-file="arial.xml" kerning="yes" embed-file="arial.ttf">
+    <font-triplet name="Arial" style="normal" weight="normal"/>
+    <font-triplet name="ArialMT" style="normal" weight="normal"/>
+ </font>
+ <font metrics-file="arialb.xml" kerning="yes" embed-file="arialb.ttf">
+    <font-triplet name="Arial" style="normal" weight="bold"/>
+    <font-triplet name="ArialMT" style="normal" weight="bold"/>
+ </font>
+ <font metrics-file="ariali.xml" kerning="yes" embed-file="ariali.ttf">
+    <font-triplet name="Arial" style="italic" weight="normal"/>
+    <font-triplet name="ArialMT" style="italic" weight="normal"/>
+ </font>
+ <font metrics-file="arialbi.xml" kerning="yes" embed-file="arialbi.ttf">
+    <font-triplet name="Arial" style="italic" weight="bold"/>
+    <font-triplet name="ArialMT" style="italic" weight="bold"/>
+ </font>
+ -->
+ <!-- Example Japanese fonts
+ <font metrics-file="msgothic.xml" embed-file="D:\winnt\font\msgothic.ttc" kerning="yes">
+    <font-triplet name="Gothic" style="normal" weight="normal"/>
+    <font-triplet name="Gothic" style="normal" weight="bold"/>
+    <font-triplet name="Gothic" style="italic" weight="normal"/>
+    <font-triplet name="Gothic" style="italic" weight="bold"/>
+ </font>
+ <font metrics-file="msmincho.xml" embed-file="Cyberbit.ttf" kerning="yes">
+    <font-triplet name="Mincho" style="normal" weight="normal"/>
+    <font-triplet name="Mincho" style="normal" weight="bold"/>
+    <font-triplet name="Mincho" style="italic" weight="normal"/>
+    <font-triplet name="Mincho" style="italic" weight="bold"/>
+   </font>
+  -->
+ <font metrics-file="Hankc.xml" kerning="yes" embed-file="Hankc.ttf">
+    <font-triplet name="Hankc" style="normal" weight="normal"/>
+    <font-triplet name="Hankc" style="normal" weight="bold"/>
+    <font-triplet name="Hankc" style="italic" weight="normal"/>
+    <font-triplet name="Hankc" style="italic" weight="bold"/>
+</font>
+<font metrics-file="Bangwool.xml" kerning="yes" embed-file="Bangwool.ttf">
+<font-triplet name="Bangwool" style="normal" weight="normal"/>
+<font-triplet name="Bangwool" style="normal" weight="bold"/>
+<font-triplet name="Bangwool" style="italic" weight="normal"/>
+<font-triplet name="Bangwool" style="italic" weight="bold"/>
+</font>
+</fonts>
+
+
+</configuration>
+
+
+

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/styles/fopdf.xsl
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/styles/fopdf.xsl	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/styles/fopdf.xsl	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,525 @@
+<?xml version="1.0"?>
+
+<!--
+
+    This is the XSL FO configuration file for the Hibernate
+    Reference Documentation. It defines a custom titlepage and
+    the parameters for the A4 sized PDF printable output.
+
+    It took me days to figure out this stuff and fix most of
+    the obvious bugs in the DocBook XSL distribution. Some of
+    the workarounds might not be appropriate with a newer version
+    of DocBook XSL. This file is released as part of Hibernate,
+    hence LGPL licensed.
+
+    christian at hibernate.org
+
+-->
+
+<!DOCTYPE xsl:stylesheet [
+    <!ENTITY db_xsl_path        "../../support/docbook-xsl/">
+]>
+
+<xsl:stylesheet
+    version="1.0"
+    xmlns="http://www.w3.org/TR/xhtml1/transitional"
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:fo="http://www.w3.org/1999/XSL/Format"
+    exclude-result-prefixes="#default">
+
+    <xsl:import href="&db_xsl_path;/fo/docbook.xsl"/>
+
+    <!--###################################################
+                       Custom Title Page
+        ################################################### -->
+
+    <xsl:template name="book.titlepage.recto">
+        <fo:block>
+            <fo:table table-layout="fixed" width="175mm">
+                <fo:table-column column-width="175mm"/>
+                <fo:table-body>
+                    <fo:table-row>
+                        <fo:table-cell text-align="center">
+                            <fo:block>
+                                <fo:external-graphic src="file:images/hibernate_logo_a.png"/>
+                            </fo:block>
+                            <fo:block font-family="Bangwool" font-size="18pt" padding-before="10mm">
+                                <xsl:value-of select="bookinfo/subtitle"/>
+                            </fo:block>
+                            <fo:block font-family="Bangwool" font-size="12pt" padding="10mm">
+                                                                버전:
+                                <xsl:value-of select="bookinfo/releaseinfo"/>
+                            </fo:block>
+                        </fo:table-cell>
+                    </fo:table-row>
+                </fo:table-body>
+            </fo:table>
+        </fo:block>
+    </xsl:template>
+
+    <!-- Prevent blank pages in output -->
+    <xsl:template name="book.titlepage.before.verso">
+    </xsl:template>
+    <xsl:template name="book.titlepage.verso">
+    </xsl:template>
+    <xsl:template name="book.titlepage.separator">
+    </xsl:template>
+
+    <!--###################################################
+                          Header
+        ################################################### -->
+
+    <!-- More space in the center header for long text -->
+    <xsl:attribute-set name="header.content.properties">
+        <xsl:attribute name="font-family">
+            <xsl:value-of select="$body.font.family"/>
+        </xsl:attribute>
+        <xsl:attribute name="margin-left">-5em</xsl:attribute>
+        <xsl:attribute name="margin-right">-5em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!--###################################################
+                          Custom Footer
+        ################################################### -->
+
+    <!-- This footer prints the Hibernate version number on the left side -->
+    <xsl:template name="footer.content">
+        <xsl:param name="pageclass" select="''"/>
+        <xsl:param name="sequence" select="''"/>
+        <xsl:param name="position" select="''"/>
+        <xsl:param name="gentext-key" select="''"/>
+
+        <xsl:variable name="Version">
+            <xsl:choose>
+                <xsl:when test="//releaseinfo">
+                    <xsl:text>하이버네이트</xsl:text>
+                    <xsl:value-of select="//releaseinfo"/>
+                </xsl:when>
+                <xsl:otherwise>
+                    <!-- nop -->
+                </xsl:otherwise>
+            </xsl:choose>
+        </xsl:variable>
+
+        <xsl:choose>
+            <xsl:when test="$sequence='blank'">
+                <xsl:choose>
+                    <xsl:when test="$double.sided != 0 and $position = 'left'">
+                        <xsl:value-of select="$Version"/>
+                    </xsl:when>
+
+                    <xsl:when test="$double.sided = 0 and $position = 'center'">
+                        <!-- nop -->
+                    </xsl:when>
+
+                    <xsl:otherwise>
+                        <fo:page-number/>
+                    </xsl:otherwise>
+                </xsl:choose>
+            </xsl:when>
+
+            <xsl:when test="$pageclass='titlepage'">
+                <!-- nop: other titlepage sequences have no footer -->
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='left'">
+                <fo:page-number/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='right'">
+                <fo:page-number/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided = 0 and $position='right'">
+                <fo:page-number/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='left'">
+                <xsl:value-of select="$Version"/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='right'">
+                <xsl:value-of select="$Version"/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided = 0 and $position='left'">
+                <xsl:value-of select="$Version"/>
+            </xsl:when>
+
+            <xsl:otherwise>
+                <!-- nop -->
+            </xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+    <!--###################################################
+                       Custom Toc Line
+        ################################################### -->
+    
+    <!-- Improve the TOC. -->
+    <xsl:template name="toc.line">
+        <xsl:variable name="id">
+            <xsl:call-template name="object.id"/>
+        </xsl:variable>
+
+        <xsl:variable name="label">
+            <xsl:apply-templates select="." mode="label.markup"/>
+        </xsl:variable>
+
+        <fo:block text-align-last="justify"
+            end-indent="{$toc.indent.width}pt"
+            last-line-end-indent="-{$toc.indent.width}pt">
+            <fo:inline keep-with-next.within-line="always">
+                <fo:basic-link internal-destination="{$id}">
+
+                    <!-- Chapter titles should be bold. -->
+                    <xsl:choose>
+                        <xsl:when test="local-name(.) = 'chapter'">
+                            <xsl:attribute name="font-weight">bold</xsl:attribute>
+                        </xsl:when>
+                    </xsl:choose>
+
+                    <xsl:if test="$label != ''">
+                        <xsl:copy-of select="$label"/>
+                        <xsl:value-of select="$autotoc.label.separator"/>
+                    </xsl:if>
+                    <xsl:apply-templates select="." mode="titleabbrev.markup"/>
+                </fo:basic-link>
+            </fo:inline>
+            <fo:inline keep-together.within-line="always">
+                <xsl:text> </xsl:text>
+                <fo:leader leader-pattern="dots"
+                    leader-pattern-width="3pt"
+                    leader-alignment="reference-area"
+                    keep-with-next.within-line="always"/>
+                <xsl:text> </xsl:text>
+                <fo:basic-link internal-destination="{$id}">
+                    <fo:page-number-citation ref-id="{$id}"/>
+                </fo:basic-link>
+            </fo:inline>
+        </fo:block>
+    </xsl:template>
+
+    <!--###################################################
+                          Extensions
+        ################################################### -->
+
+    <!-- These extensions are required for table printing and other stuff -->
+    <xsl:param name="use.extensions">1</xsl:param>
+    <xsl:param name="tablecolumns.extension">0</xsl:param>
+    <!-- FOP provide only PDF Bookmarks at the moment -->
+    <xsl:param name="fop.extensions">1</xsl:param>
+
+    <!--###################################################
+                          Table Of Contents
+        ################################################### -->
+
+    <!-- Generate the TOCs for named components only -->
+    <xsl:param name="generate.toc">
+        book   toc
+    </xsl:param>
+    
+    <!-- Show only Sections up to level 3 in the TOCs -->
+    <xsl:param name="toc.section.depth">3</xsl:param>
+    
+    <!-- Dot and Whitespace as separator in TOC between Label and Title-->
+    <xsl:param name="autotoc.label.separator" select="'.  '"/>
+
+
+    <!--###################################################
+                       Paper & Page Size
+        ################################################### -->
+    
+    <!-- Paper type, no headers on blank pages, no double sided printing -->
+    <xsl:param name="paper.type" select="'A4'"/>
+    <xsl:param name="double.sided">0</xsl:param>
+    <xsl:param name="headers.on.blank.pages">0</xsl:param>
+    <xsl:param name="footers.on.blank.pages">0</xsl:param>
+
+    <!-- Space between paper border and content (chaotic stuff, don't touch) -->
+    <xsl:param name="page.margin.top">5mm</xsl:param>
+    <xsl:param name="region.before.extent">10mm</xsl:param>
+    <xsl:param name="body.margin.top">10mm</xsl:param>
+
+    <xsl:param name="body.margin.bottom">15mm</xsl:param>
+    <xsl:param name="region.after.extent">10mm</xsl:param>
+    <xsl:param name="page.margin.bottom">0mm</xsl:param>
+
+    <xsl:param name="page.margin.outer">18mm</xsl:param>
+    <xsl:param name="page.margin.inner">18mm</xsl:param>
+
+    <!-- No intendation of Titles -->
+    <xsl:param name="title.margin.left">0pc</xsl:param>
+
+    <!--###################################################
+                       Fonts & Styles
+        ################################################### -->
+
+    <!-- Default Font size -->
+    <xsl:param name="body.font.master">10</xsl:param>
+
+    <!-- Line height in body text -->
+    <xsl:param name="line-height">1.6</xsl:param>
+
+    <!-- Monospaced fonts are smaller than regular text -->
+    <xsl:attribute-set name="monospace.properties">
+        <xsl:attribute name="font-family">
+            <xsl:value-of select="$monospace.font.family"/>
+        </xsl:attribute>
+        <xsl:attribute name="font-size">0.8em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!--###################################################
+                       Tables
+        ################################################### -->
+
+    <!-- The table width should be adapted to the paper size -->
+    <xsl:param name="default.table.width">17.4cm</xsl:param>
+
+    <!-- Some padding inside tables -->
+    <xsl:attribute-set name="table.cell.padding">
+        <xsl:attribute name="padding-left">4pt</xsl:attribute>
+        <xsl:attribute name="padding-right">4pt</xsl:attribute>
+        <xsl:attribute name="padding-top">4pt</xsl:attribute>
+        <xsl:attribute name="padding-bottom">4pt</xsl:attribute>
+    </xsl:attribute-set>
+    
+    <!-- Only hairlines as frame and cell borders in tables -->
+    <xsl:param name="table.frame.border.thickness">0.1pt</xsl:param>
+    <xsl:param name="table.cell.border.thickness">0.1pt</xsl:param>
+
+    <!--###################################################
+                             Labels
+        ################################################### -->
+
+    <!-- Label Chapters and Sections (numbering) -->
+    <xsl:param name="chapter.autolabel">1</xsl:param>
+    <xsl:param name="section.autolabel" select="1"/>
+    <xsl:param name="section.label.includes.component.label" select="1"/>
+
+    <!-- Label only Sections up to level 2 -->
+    <xsl:param name="local.l10n.xml" select="document('')"/>
+    <l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0">
+        <l:l10n language="ko">
+            <l:context name="title-numbered">
+                <l:template name="sect3" text="%t"/>
+                <l:template name="sect4" text="%t"/>
+                <l:template name="sect5" text="%t"/>
+            </l:context>
+            <l:context name="section-xref-numbered">
+                <l:template name="sect3" text="the section called %t"/>
+                <l:template name="sect4" text="the section called %t"/>
+                <l:template name="sect5" text="the section called %t"/>
+            </l:context>
+        </l:l10n>
+    </l:i18n>
+    
+    <!--###################################################
+                             Titles
+        ################################################### -->
+    
+    <!-- Chapter title size -->
+    <xsl:attribute-set name="chapter.titlepage.recto.style">
+        <xsl:attribute name="text-align">left</xsl:attribute>
+        <xsl:attribute name="font-weight">bold</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.8"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+    </xsl:attribute-set>
+
+    <!-- Why is the font-size for chapters hardcoded in the XSL FO templates? 
+        Let's remove it, so this sucker can use our attribute-set only... -->
+    <xsl:template match="title" mode="chapter.titlepage.recto.auto.mode">
+        <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
+            xsl:use-attribute-sets="chapter.titlepage.recto.style">
+            <xsl:call-template name="component.title">
+                <xsl:with-param name="node" select="ancestor-or-self::chapter[1]"/>
+            </xsl:call-template>
+        </fo:block>
+    </xsl:template>
+    
+    <!-- Sections 1, 2 and 3 titles have a small bump factor and padding -->
+    <xsl:attribute-set name="section.title.level1.properties">
+        <xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.5"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+    <xsl:attribute-set name="section.title.level2.properties">
+        <xsl:attribute name="space-before.optimum">0.6em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.6em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.6em</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.25"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+    <xsl:attribute-set name="section.title.level3.properties">
+        <xsl:attribute name="space-before.optimum">0.4em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.4em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.4em</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.0"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!-- Titles of formal objects (tables, examples, ...) -->
+    <xsl:attribute-set name="formal.title.properties" use-attribute-sets="normal.para.spacing">
+        <xsl:attribute name="font-weight">bold</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="hyphenate">false</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.4em</xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.6em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.8em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!--###################################################
+                          Programlistings
+        ################################################### -->
+    
+    <!-- Verbatim text formatting (programlistings) -->
+    <xsl:attribute-set name="verbatim.properties">
+        <xsl:attribute name="space-before.minimum">1em</xsl:attribute>
+        <xsl:attribute name="space-before.optimum">1em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+        <xsl:attribute name="border-color">#444444</xsl:attribute>
+        <xsl:attribute name="border-style">solid</xsl:attribute>
+        <xsl:attribute name="border-width">0.1pt</xsl:attribute>
+        <xsl:attribute name="padding-top">0.5em</xsl:attribute>
+        <xsl:attribute name="padding-left">0.5em</xsl:attribute>
+        <xsl:attribute name="padding-right">0.5em</xsl:attribute>
+        <xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
+        <xsl:attribute name="margin-left">0.5em</xsl:attribute>
+        <xsl:attribute name="margin-right">0.5em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!-- Shade (background) programlistings -->
+    <xsl:param name="shade.verbatim">1</xsl:param>
+    <xsl:attribute-set name="shade.verbatim.style">
+        <xsl:attribute name="background-color">#F0F0F0</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!--###################################################
+                             Callouts
+        ################################################### -->
+
+    <!-- We want to use callouts... -->
+    <xsl:param name="callout.extensions">1</xsl:param>
+
+    <!-- Place callout bullets at this column in programmlisting.-->
+    <xsl:param name="callout.defaultcolumn">90</xsl:param>
+
+    <!--
+        No, don't use crappy graphics for the callout bullets. This setting
+        enables some weird Unicode rendering for some fancy bullet points
+        in callouts. By default, this can only count to 10 and produces
+        strange results if you ever have more than 10 callouts for one
+        programlisting. We will fix that next.
+    -->
+    <xsl:param name="callout.graphics">0</xsl:param>
+
+    <!--
+        Again, fun with DocBook XSL: The callout bullets are rendered in
+        two places: In the programlisting itself and in the list below
+        the listing, with the actual callout text. The rendering in the
+        programlisting is some XSL transformer extension (e.g. a Saxon
+        extension), so we can't change that without messing with the
+        extensions. We only can turn it off by setting this limit to
+        zero, then, a simple bracket style like "(3)" and "(4)" will
+        be used in the programlisting.
+    -->
+    <xsl:param name="callout.unicode.number.limit" select="'0'"></xsl:param>
+
+    <!--
+        The callout bullets in the actual callout list will be rendered
+        with an XSL FO template. The default template is broken: limited to 10
+        nice looking Unicode bullet points and then it doesn't print anything,
+        the fallback doesn't work. We implement our own template, which is not
+        as complicated, more ugly, but works. As always, function is more
+        important than form.
+    -->
+    <xsl:template name="callout-bug">
+        <xsl:param name="conum" select='1'/>
+        <fo:inline
+            color="black"
+            padding-top="0.1em"
+            padding-bottom="0.1em"
+            padding-start="0.2em"
+            padding-end="0.2em"
+            baseline-shift="0.1em"
+            font-family="{$monospace.font.family}"
+            font-weight="bold"
+            font-size="75%">
+            <xsl:text>(</xsl:text>
+            <xsl:value-of select="$conum"/>
+            <xsl:text>)</xsl:text>
+        </fo:inline>
+
+    </xsl:template>
+
+    <!--###################################################
+                              Misc
+        ################################################### -->
+
+    <!-- Correct placement of titles for figures and examples. -->
+    <xsl:param name="formal.title.placement">
+        figure after
+        example before
+        equation before
+        table before
+        procedure before
+    </xsl:param>
+    
+    <!-- Format Variable Lists as Blocks (prevents horizontal overflow). -->
+    <xsl:param name="variablelist.as.blocks">1</xsl:param>
+
+    <!-- The horrible list spacing problems, this is much better. -->
+    <xsl:attribute-set name="list.block.spacing">
+        <xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!-- Newer DocBook XSL apparently thinks that some sections are by
+         default "draft" status, and this idiotic thing is by default
+         also set to "maybe", so it spits out a lot of errors with the
+         latest FOP as the XSL/FO styles have references to some draft
+         watermarks, which you actually don't want in the first place.
+         Turn this crap off. If you have to work with the "status"
+         attribute, don't.
+    -->
+    <xsl:param name="draft.mode" select="'no'"/>
+    
+    <!-- Korean related Settings -->
+    <xsl:param name="hyphenate">false</xsl:param>
+    <xsl:param name="body.font.family">Hankc</xsl:param>
+    <!-- xsl:param name="monospace.font.family">Bangwool</xsl:param-->
+    <xsl:param name="title.font.family">Bangwool</xsl:param>
+    <xsl:param name="saxon.character.representation" select="native"/>
+    <xsl:param name="callout.unicode" select="1"/>
+    <xsl:param name="callout.unicode.start.character" select="10102"/>
+    <xsl:param name="l10n.gentext.default.language" select="ko"/>
+</xsl:stylesheet>

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/styles/html.xsl
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/styles/html.xsl	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/styles/html.xsl	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+
+<!--
+
+    This is the XSL HTML configuration file for the Hibernate
+    Reference Documentation.
+
+    It took me days to figure out this stuff and fix most of
+    the obvious bugs in the DocBook XSL distribution. Some of
+    the workarounds might not be appropriate with a newer version
+    of DocBook XSL. This file is released as part of Hibernate,
+    hence LGPL licensed.
+
+    christian at hibernate.org
+-->
+
+<!DOCTYPE xsl:stylesheet [
+    <!ENTITY db_xsl_path        "../../support/docbook-xsl/">
+]>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0"
+                xmlns="http://www.w3.org/TR/xhtml1/transitional"
+                exclude-result-prefixes="#default">
+                
+<xsl:import href="&db_xsl_path;/html/docbook.xsl"/>
+
+<!--###################################################
+                     HTML Settings
+    ################################################### -->   
+
+    <xsl:param name="html.stylesheet">../shared/css/html.css</xsl:param>
+
+    <!-- These extensions are required for table printing and other stuff -->
+    <xsl:param name="use.extensions">1</xsl:param>
+    <xsl:param name="tablecolumns.extension">0</xsl:param>
+    <xsl:param name="callout.extensions">1</xsl:param>
+    <xsl:param name="graphicsize.extension">0</xsl:param>
+
+<!--###################################################
+                      Table Of Contents
+    ################################################### -->   
+
+    <!-- Generate the TOCs for named components only -->
+    <xsl:param name="generate.toc">
+        book   toc
+    </xsl:param>
+    
+    <!-- Show only Sections up to level 3 in the TOCs -->
+    <xsl:param name="toc.section.depth">3</xsl:param>
+    
+<!--###################################################
+                         Labels
+    ################################################### -->   
+
+    <!-- Label Chapters and Sections (numbering) -->
+    <xsl:param name="chapter.autolabel">1</xsl:param>
+    <xsl:param name="section.autolabel" select="1"/>
+    <xsl:param name="section.label.includes.component.label" select="1"/>
+
+<!--###################################################
+                         Callouts
+    ################################################### -->
+
+    <!-- Don't use graphics, use a simple number style -->
+    <xsl:param name="callout.graphics">0</xsl:param>
+
+    <!-- Place callout marks at this column in annotated areas -->
+    <xsl:param name="callout.defaultcolumn">90</xsl:param>
+
+<!--###################################################
+                          Misc
+    ################################################### -->   
+
+    <!-- Placement of titles -->
+    <xsl:param name="formal.title.placement">
+        figure after
+        example before
+        equation before
+        table before
+        procedure before
+    </xsl:param>    
+    
+</xsl:stylesheet>

Added: trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/styles/html_chunk.xsl
===================================================================
--- trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/styles/html_chunk.xsl	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/ko-KR/src/no-idea-what-to-do-with-these-yet/styles/html_chunk.xsl	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+
+<!--
+
+    This is the XSL HTML configuration file for the Hibernate
+    Reference Documentation.
+
+    It took me days to figure out this stuff and fix most of
+    the obvious bugs in the DocBook XSL distribution. Some of
+    the workarounds might not be appropriate with a newer version
+    of DocBook XSL. This file is released as part of Hibernate,
+    hence LGPL licensed.
+
+    christian at hibernate.org
+-->
+
+<!DOCTYPE xsl:stylesheet [
+    <!ENTITY db_xsl_path        "../../support/docbook-xsl/">
+]>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0"
+                xmlns="http://www.w3.org/TR/xhtml1/transitional"
+                exclude-result-prefixes="#default">
+                
+<xsl:import href="&db_xsl_path;/html/chunk.xsl"/>
+
+<!--###################################################
+                     HTML Settings
+    ################################################### -->   
+
+    <xsl:param name="chunk.section.depth">'5'</xsl:param>
+    <xsl:param name="use.id.as.filename">'1'</xsl:param>
+    <xsl:param name="html.stylesheet">../shared/css/html.css</xsl:param>
+
+    <!-- These extensions are required for table printing and other stuff -->
+    <xsl:param name="use.extensions">1</xsl:param>
+    <xsl:param name="tablecolumns.extension">0</xsl:param>
+    <xsl:param name="callout.extensions">1</xsl:param>
+    <xsl:param name="graphicsize.extension">0</xsl:param>
+    
+<!--###################################################
+                      Table Of Contents
+    ################################################### -->   
+
+    <!-- Generate the TOCs for named components only -->
+    <xsl:param name="generate.toc">
+        book   toc
+    </xsl:param>
+    
+    <!-- Show only Sections up to level 3 in the TOCs -->
+    <xsl:param name="toc.section.depth">3</xsl:param>
+
+<!--###################################################
+                         Labels
+    ################################################### -->   
+
+    <!-- Label Chapters and Sections (numbering) -->
+    <xsl:param name="chapter.autolabel">1</xsl:param>
+    <xsl:param name="section.autolabel" select="1"/>
+    <xsl:param name="section.label.includes.component.label" select="1"/>
+                
+<!--###################################################
+                         Callouts
+    ################################################### -->   
+
+    <!-- Don't use graphics, use a simple number style -->
+    <xsl:param name="callout.graphics">0</xsl:param>
+
+    <!-- Place callout marks at this column in annotated areas -->
+    <xsl:param name="callout.defaultcolumn">90</xsl:param>
+
+<!--###################################################
+                          Misc
+    ################################################### -->   
+
+    <!-- Placement of titles -->
+    <xsl:param name="formal.title.placement">
+        figure after
+        example before
+        equation before
+        table before
+        procedure before
+    </xsl:param>    
+    
+</xsl:stylesheet>

Added: trunk/Hibernate3/documentation/manual/pom.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,100 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>hibernate-manual</artifactId>
+    <packaging>pom</packaging>
+    <name>Hibernate Manual</name>
+    <description>The Hibernate reference manual</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jboss.maven.plugins</groupId>
+            <artifactId>maven-jboss-docbook-plugin</artifactId>
+            <version>1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-docbook-xslt</artifactId>
+            <version>0.1</version>
+        </dependency>
+    </dependencies>
+
+    <modules>
+        <module>en-US</module>
+        <module>fr-FR</module>
+    </modules>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.jboss.maven.plugins</groupId>
+                <artifactId>maven-jboss-docbook-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.hibernate</groupId>
+                        <artifactId>hibernate-docbook-xslt</artifactId>
+                        <version>0.1</version>
+                    </dependency>
+                </dependencies>
+                <configuration>
+                    <sourceDocumentName>master.xml</sourceDocumentName>
+                    <formats>
+                        <format>
+                            <formatName>pdf</formatName>
+                            <stylesheetResource>/standard/fopdf.xsl</stylesheetResource>
+                            <finalName>hibernate_reference.pdf</finalName>
+                        </format>
+                        <format>
+                            <formatName>html</formatName>
+                            <stylesheetResource>/standard/html.xsl</stylesheetResource>
+                            <finalName>index.html</finalName>
+                        </format>
+                    </formats>
+                    <xincludeSupported>true</xincludeSupported>
+                    <options>
+                        <xincludeSupported>true</xincludeSupported>
+                        <xmlTransformerType>saxon</xmlTransformerType>
+                        <transformerParameters>
+                            <property>
+                                <name>custom.titlepage.img</name>
+                                <value>${basedir}/src/main/docbook/standard/resources/shared/images/hibernate_logo_a.png</value>
+                            </property>
+                        </transformerParameters>
+                    </options>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+<!-- report plugin is currently hosed
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.jboss.maven.plugin</groupId>
+                <artifactId>jboss-docbook-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </reporting>
+-->
+    <properties>
+        <masterTranslation>en-US</masterTranslation>
+    </properties>
+
+</project>

Added: trunk/Hibernate3/documentation/manual/pt-BR/pom.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-manual</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>hibernate-manual-${translation}</artifactId>
+    <packaging>pom</packaging>
+    <name>Hibernate Manual (${translation})</name>
+
+    <properties>
+        <translation>pt-BR</translation>
+    </properties>
+
+</project>

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/master.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/master.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/master.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,261 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
+                      "../support/docbook-dtd/docbookx.dtd"
+[
+<!ENTITY tutorial               SYSTEM "modules/tutorial.xml">
+<!ENTITY architecture           SYSTEM "modules/architecture.xml">
+<!ENTITY configuration          SYSTEM "modules/configuration.xml">
+<!ENTITY persistent-classes     SYSTEM "modules/persistent_classes.xml">
+<!ENTITY basic-mapping          SYSTEM "modules/basic_mapping.xml">
+<!ENTITY collection-mapping     SYSTEM "modules/collection_mapping.xml">
+<!ENTITY association-mapping    SYSTEM "modules/association_mapping.xml">
+<!ENTITY component-mapping      SYSTEM "modules/component_mapping.xml">
+<!ENTITY inheritance-mapping    SYSTEM "modules/inheritance_mapping.xml">
+<!ENTITY session-api            SYSTEM "modules/session_api.xml">
+<!ENTITY transactions           SYSTEM "modules/transactions.xml">
+<!ENTITY events                 SYSTEM "modules/events.xml">
+<!ENTITY batch                  SYSTEM "modules/batch.xml">
+<!ENTITY query-hql              SYSTEM "modules/query_hql.xml">
+<!ENTITY query-criteria         SYSTEM "modules/query_criteria.xml">
+<!ENTITY query-sql              SYSTEM "modules/query_sql.xml">
+<!ENTITY filters                SYSTEM "modules/filters.xml">
+<!ENTITY xml                    SYSTEM "modules/xml.xml">
+<!ENTITY performance            SYSTEM "modules/performance.xml">
+<!ENTITY toolset-guide          SYSTEM "modules/toolset_guide.xml">
+<!ENTITY example-parentchild    SYSTEM "modules/example_parentchild.xml">
+<!ENTITY example-weblog         SYSTEM "modules/example_weblog.xml">
+<!ENTITY example-mappings       SYSTEM "modules/example_mappings.xml">
+<!ENTITY best-practices         SYSTEM "modules/best_practices.xml">
+]>
+
+<book lang="en">
+
+    <bookinfo>
+        <title>HIBERNATE - Relational Persistence for Idiomatic Java</title>
+        <subtitle>Documentação da Referência do Hibernate</subtitle>
+        <releaseinfo>3.2 cr2</releaseinfo>
+    </bookinfo>
+
+    <toc/>
+
+    <preface id="preface" revision="2">
+        <title>Prefácio</title>
+        
+        <para>
+		        <emphasis>Advertencia! Esta é uma versão traduzida do inglês da 
+		        documentação de referencia do Hibernate. A versão traduziada pode estar
+		        desatualizada. Sem dúvida, as diferenças devem ser pequenas e serão corrigidas o 
+		        mais breve possivel. Consulte a documentação de referencia em inglês, se estiver
+		        faltando alguma informação ou você encotrar erros de tradução. Se quiser 
+		        colaborar com ama tradução em particular, entre em contato com um dos tradutores
+		        abaixo:</emphasis>. Gamarra
+		        
+        </para>
+
+        <para>
+            Tradutor(es) em ordem alfabética: 
+        </para>
+
+       <itemizedlist>
+        <listitem>
+        <para>
+            <emphasis>Alvaro Netto</emphasis> alvaronetto at cetip.com.br
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <emphasis>Anderson Braulio</emphasis> andersonbraulio at gmail.com
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <emphasis>Daniel Vieira Costa</emphasis> danielvc at gmail.com
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <emphasis>Francisco gamarra</emphasis> francisco.gamarra at gmail.com
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <emphasis>Gamarra</emphasis> mauricio.gamarra at gmail.com
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <emphasis>Luiz Carlos Rodrigues</emphasis> luizcarlos_rodrigues at yahoo.com.br
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <emphasis>Marcel Castelo</emphasis> marcel.castelo at gmail.com
+        </para>
+        </listitem>
+
+        <listitem>
+        <para>
+            <emphasis>Paulo César</emphasis> paulocol at gmail.com
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <emphasis>Pablo L. de Miranda</emphasis> pablolmiranda at gmail.com
+        </para>
+        </listitem>
+        <listitem>
+         <para>
+            <emphasis>Renato Deggau</emphasis> rdeggau at gmail.com
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <emphasis>Rogério Araújo</emphasis> rgildoaraujo at yahoo.com.br
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <emphasis>Wanderson	Siqueira</emphasis> wandersonxs at gmail.com
+        </para>
+        </listitem>
+       
+
+        </itemizedlist>
+ 
+        <para>
+            Trabalhando com software orientado a objetos e banco de dados relacional, podemos 
+            ter alguns incômodos hoje em dia em ambientes empresariais. Hibernate é uma ferramenta 
+            que mapeia o objeto/relacional para o ambiente Java. O termo de mapeamento de 
+            objeto/relacional (ou ORM – Object/Relational Mapping) se refere a técnica de mapear 
+            uma representação de dados de um modelo de objeto para dados de modelo 
+            relacional com o esquema baseado em SQL
+        </para>
+
+        <para>
+            O Hibernate não somente cuida do mapeamento de classes em Java 
+            para tabelas de banco de dados (e de tipos de dados em Java para tipos de dados em SQL), como também 
+            fornece facilidade de consultas e recuperação de dados, podendo também reduzir significantemente o 
+            tempo de desenvolvimento gasto com a manipulação manual de dados no SQL e JDBC.
+        </para>
+
+        <para>
+            O objetivo do Hibernate é de aliviar o desenvolvedor de 95 por cento das tarefas de programação 
+            relacionadas aos dados comuns de persistência. O Hibernate talvez não seja a melhor solução para 
+            aplicações de dados-data-centric que somente usa stored-procedures para implementar a lógica 
+            de negócio no banco de dados, isto é muito utilizado com o domínio de modelos orientado a objetos e 
+            lógicas de negócio em camadas do meio (middle-tier) baseadas em Java. Porém, o Hibernate
+            poderá certamente ajuda-lo a remover ou encapsular o código SQL de um vendedor específico,
+            ajudando também com a tarefa comum da tradução do resultado ajustado de uma representação 
+            para um gráfico de objetos.
+        </para>
+
+        <para>
+            Se você for novo no Hibernate e no mapeamento Objeto/Relacional, ou até mesmo em Java, 
+            por favor, siga os seguintes passos.
+        </para>
+
+        <orderedlist>
+            <listitem>
+                <para>
+                    Leia <xref linkend="tutorial"/> para um tutorial com instruções passo-a-passo. 
+                    O código fonte para do tutorial está incluído na distribuição no diretório 
+                    <literal>doc/reference/tutorial/</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Leia o <xref linkend="architecture"/> para entender o ambiente onde o Hibernate pode ser utilizado. 
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Dê uma olhada no diretório de exemplo <literal>eg/</literal> da distribuição 
+                    do Hibernate, ele contém uma simples aplicação standalone. 
+                    Copie seu driver JDBC para o diretório <literal>lib/</literal> e edite o arquivo 
+                    <literal>etc/hibernate.properties</literal>, especificando corretamente os valores 
+                    para seu banco de dados. Usando o prompt de commando no diretorio de distribuicao,
+                    digite <literal>ant eg</literal> (usando Ant), ou no Windows, digite
+                    <literal>build eg</literal>.                     
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Use esta documentação de referencia como sua fonte primaria de informação. 
+                    Considere ler também o livro <emphasis>Hibernate in Action</emphasis>  
+                    (http://www.manning.com/bauer) caso você precise de mais ajuda com o 
+                    desenvolvimento de aplicações ou caso prefira um tutorial passo-a-passo. 
+                    Também visite o site http://caveatemptor.hibernate.org e faça o download 
+                    da aplicação de exemplo do Hibernate em Ação.
+                </para>
+            </listitem>
+            <listitem>
+				<para>
+					FAQs (perguntas feitas com mais freqüência) estão respondidas no site do Hibernate
+				</para>
+            </listitem>
+			<listitem>
+				<para>
+					Demonstrações, exemplos e tutorials estão disponíveis no site do Hibernate.
+				</para>
+			</listitem>
+            <listitem>
+                <para>
+                    A Área da comunidade no site do Hibernate é uma boa fonte de recursos 
+                    para padrões de projeto e várias soluções de integração (Tomcat, JBoss AS, Struts, EJB, etc.).
+                </para>
+            </listitem>
+         </orderedlist>
+
+         <para>
+             Caso você tenha dúvidas, use o fórum dos usuários encontrado no site do Hibernate. 
+             Nós também fornecemos um sistema para controle de bug’s (JIRA) para relatórios de erros 
+             e requisições de features. Se você está interessado no desenvolvimento do Hibernate, 
+             junte-se a lista de e-mail dos desenvolvedores. 
+         </para>
+
+         <para>
+             Suporte comercial de desenvolvimento, suporte de produção e treinamento para o Hibernate 
+             está disponível através do JBoss Inc. (veja http://www.hibernate.org/SupportTraining). 
+             O Hibernate é um Projeto Profissional de Código Aberto e um componente crítico da suíte 
+             de produtos JBoss Enterprise Middleware System (JEMS).              
+         </para>
+
+    </preface>
+
+    &tutorial;
+
+    &architecture;
+
+    &configuration;
+
+    &persistent-classes;
+
+    &basic-mapping;
+    &collection-mapping;
+    &association-mapping;
+    &component-mapping;
+    &inheritance-mapping;
+
+    &session-api;
+    &transactions;
+    &events;
+    &batch;
+
+    &query-hql;
+    &query-criteria;
+    &query-sql;
+    &filters;
+    &xml;
+
+    &performance;
+
+    &toolset-guide;
+
+    &example-parentchild;
+    &example-weblog;
+    &example-mappings;
+
+    &best-practices;
+
+</book>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/master.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/architecture.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/architecture.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/architecture.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,359 @@
+<chapter id="architecture">
+
+    <title>Arquitetura</title>
+
+    <sect1 id="architecture-overview" revision="1">
+        <title>Vis&#x00E3;o Geral</title>
+        
+        <para>
+            Uma vis&#x00E3;o bem ampla da arquitetura do Hibernate:
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/overview.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/overview.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            Esse diagrama mostra o Hibernate usando o banco de dados e a configuração 
+            de dados para prover persistência de serviços (e persistência de objetos) 
+            para o aplicativo.
+        </para>
+
+        <para>
+            Nós gostaríamos de mostrar uma visão mais detalhada da arquitetura em execução. 
+            Infelizmente, o Hibernate é muito flexível e suporta v&#x00E1;rias aproximações. 
+            Nós iremos mostrar os dois extremos. Na arquitetura mais simples o aplicativo 
+            fornece suas próprias conexões JDBC e gerencia suas transações. Esta abordagem 
+            usa o mínimo de subconjuntos das APIs do Hibernate:
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/lite.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/lite.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            A arquitetura "completa" abstrai a aplicação de ter de lidar diretamente 
+            com JDBC/JTA e APIs e deixa o Hibernate tomar conta dos detalhes.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/full_cream.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/full_cream.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            Algumas definições dos objetos do diagrama:
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
+                    <listitem>
+                        <para>
+                            Um cache threadsafe  (imutáveis) composto de identidades compiladas para um 
+                            único banco de dados. Uma fabrica para <literal>Session</literal> e um cliente 
+                            de <literal>ConnectionProvider</literal>. Pode conter um cachê opcional de 
+                            dados (segundo nível) reutilizáveis entre transações, no nível de processo- ou cluster.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Session (<literal>org.hibernate.Session</literal>)</term>
+                    <listitem>
+                        <para>
+                            Objeto single-threaded, de vida curta, representando uma conversação entre 
+                            o aplicativo e o armazenamento persistente. Cria uma camada sobre uma conexão JDBC. 
+                            É uma fabrica de <literal>Transaction</literal>. Possui um cachê obrigatório 
+                            (primeiro nível) de objetos persistentes, usado para navegação no gráficos 
+                            de objetos e pesquisa de objetos pelo identificador.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Objetos persistentes e coleções</term>
+                    <listitem>
+                        <para>
+                            Objetos, de vida curta, single threaded contendo estado persistente e função 
+                            de negócios. Esses podem ser JavaBeans/POJOs, onde única coisa especial sobre 
+                            eles é que são associados a (exatamente uma) <literal>Session</literal>. 
+                            Quando a <literal>Session</literal>  é fechada, eles são separados e liberados 
+                            para serem usados dentro de qualquer camada da aplicacao (Ex. diretamente como 
+                            data transfer objects de e para a camada de apresentação)
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Objetos e coleções desatachados e transientes</term>
+                    <listitem>
+                        <para>
+                            Instâncias de classes persistentes que ainda não estão associadas a uma 
+                            <literal>Session</literal>. Eles podem ter sido instanciados pela aplicação
+                            e não persistido (ainda) ou eles foram instanciados por uma <literal>Session</literal>
+                            que foi encerrada.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
+                    <listitem>
+                        <para>
+                            (Opcional) Objeto de vida curta, single threaded, usado pela aplicação para 
+                            especificar unidades atômicas de trabalho. Abstrai o aplicativo de lidar 
+                            diretamente com transações JDBC, JTA ou CORBA.  Uma <literal>Session</literal> pode, 
+                            em alguns casos, iniciar várias <literal>Transaction</literal>s. Entretanto, 
+                            a demarcação da transação, mesmo utilizando API ou Transaction subjacentes, 
+                            nunca é opcional!
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
+                    <listitem>
+                        <para>
+                            (Opcional) Uma fábrica de (e combinações de) conexões JDBC. Abstrai a aplicação
+                            de lidar diretamente com <literal>Datasource</literal> ou <literal>DriverManager</literal>.
+                            Não exposto para a aplicação, mas pode ser implementado ou estendido pelo programador.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
+                    <listitem>
+                        <para>
+                            (Opcional) Uma fábrica para instâncias de <literal>Transaction</literal>. Não exposta 
+                            a aplicação, mas pode ser extendida/implementada pelo programador.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><emphasis>Extension Interfaces</emphasis></term>
+                    <listitem>
+                        <para>
+                            O Hibernate oferece várias opções de interfaces estendidas que você pode implementar 
+                            para customizar sua camada persistente. Veja a documentação da API para maiores detalhes. 
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+        </para>
+
+        <para>
+            Dada uma arquitetura simples, o aplicativo passa pelas APIs 
+            <literal>Transaction</literal>/<literal>TransactionFactory</literal> e/ou 
+            <literal>ConnectionProvider</literal> para se comunicar diretamente com a transação JTA ou JDBC.
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-states" revision="1">
+        <title>Estados de instância</title>
+        <para>
+            Uma instância de classes persistentes pode estar em um dos três diferentes estados, 
+            que são definidos respeitando um <emphasis>contexto persistente</emphasis>. 
+            O objeto <literal>Session</literal> do Hibernate é o contexto persistente:
+        </para>
+        
+       <variablelist spacing="compact">
+            <varlistentry>
+                <term>transiente</term>
+                <listitem>
+                    <para>
+                        A instância não é, e nunca foi associada com nenhum 
+                        contexto persistente. Não possui uma identidade persistente 
+                        (valor de chave primária).
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>persistente</term>
+                <listitem>
+                    <para>
+                       	A instância está atualmente associada a um contexto persistente. 
+                       	Possui uma identidade persistente (valor de chave primária) e, 
+                       	talvez, correspondente a um registro no banco de dados. Para um 
+                       	contexto persistente em particular, o Hibernate 
+                       	<emphasis>guarantees</emphasis> que a identidade persistente 
+                       	é equivalente a identidade Java (na localização em memória do 
+                       	objeto).
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>desatachado</term>
+                <listitem>
+                    <para>
+                        A instância foi associada com um contexto persistente, 
+                        porém este contexto foi fechado, ou a instância 
+                        foi serializada por outro processo. Possui uma identidade 
+                        persistente, e, talvez, correspondenta a um registro no 
+                        banco de dados. Para instâncias desatachadas, o Hibernate 
+                        não garante o relacionamento entre identidade persistente 
+                        e identidade Java.
+                    </para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </sect1>    
+
+    <sect1 id="architecture-jmx" revision="1">
+        <title>Integração JMX</title>
+
+        <para>
+            JMX é padrão J2EE para manipulação de componentes Java. O Hibernate pode ser manipulado 
+            por um serviço JMX padrão. Nós fornecemos uma implementação do MBean na distribuição, 
+            <literal>org.hibernate.jmx.HibernateService</literal>.
+        </para>
+
+        <para>
+            Para um exemplo de como instalar o Hibernate como um serviço JMX em um servidor de 
+            aplicativo JBoss, por favor, consulte o manual do usuário do JBoss. No JBoss As, você 
+            poderá ver os benefícios de de se fazer o deploy usando JMX:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>Session Management:</emphasis> O ciclo de vida de uma <literal>Session</literal> do 
+                    Hibernate pode ser automaticamente conectada a um escopo de transação JTA. Isso significa 
+                    que você não precisará mais abrir e fechar manualmente uma <literal>Session</literal>, isso 
+                    se torna trabalho para um interceptor EJB do JBoss . Você também não precisa se preocupar, 
+                    nunca mais, com demarcação de transação em seu código (a não ser que você prefira escrever 
+                    uma camada persistente portável, para isso, use a API opcional do Hibernate  
+                    <literal>Transaction</literal>). Você deve chamar <literal>HibernateContext</literal> 
+                    para acessar uma <literal>Session</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>HAR deployment:</emphasis>: Normalmente você faz o deploy de um serviço JMX do
+                    Hibernate usando um serviço descritor de deploy do JBoss (em um EAR e/ou arquivo SAR), 
+                    que suporta todas as configurações usuais de uma <literal>SessionFactory</literal> do 
+                    Hibernate. Entretanto, você ainda precisa nomear todos os seus arquivos de mapeamento 
+                    no descritor de deploração. Se você decidir usar o deploy opcional HAR, o JBoss irá 
+                    automaticamente detectar todos os seus arquivos de mapeamento no seu arquivo HAR.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Consulte o manual do usuário do JBoss AS, para obter maiores informações sobre essas opções.
+        </para>
+
+        <para>
+            Another feature available as a JMX service are runtime Hibernate statistics. See
+            <xref linkend="configuration-optional-statistics"/>.
+            Outra opção disponível como um serviço JMX são as estatísticas de execução do Hibernate. 
+            Veja a <xref linkend="configuration-optional-statistics"/>.
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-jca" revision="1">
+        <title>Suporte JCA</title>
+        <para>
+            Hibernate may also be configured as a JCA connector. Please see the website for more
+            details. Please note that Hibernate JCA support is still considered experimental.
+            O Hibernate pode também ser configurado como um conector JCA. Por favor, visite o 
+            website para maiores detalhes. Entretanto, note que o suporte JCA do Hibernate 
+            ainda é considerado experimental.
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-current-session" revision="2">
+        <title>Sessões contextuais</title>
+        <para>
+            Muitas aplicações que usam o Hibernate necessita de algum tipo de sessão "contextual", 
+            onde uma sessão dada é na verdade um escopo de um contexto. Entretanto, através de aplicações 
+            a definição sobre um contexto é geralmente diferente; e contextos diferentes definem escopos 
+            diferentes. Aplicações usando versões anteriores ao Hibernate 3.0 tendem a utilizar tanto 
+            sessões contextuais baseadas em <literal>ThreadLocal</literal>, classes utilitárias como 
+            <literal>HibernateUtil</literal>, ou utilizar frameworks de terceiros(como Spring ou Pico) 
+            que provê sessões contextuais baseadas em proxy.
+
+        </para>
+        <para>
+            A partir da versão 3.0.1, o Hibernate adicionou o método <literal>SessionFactory.getCurrentSession()</literal>.
+            Inicialmente, este assume o uso de transações <literal>JTA</literal>, onde a transação 
+            <literal>JTA</literal> define tanto o escopo quanto o contexto de uma sessão atual. 
+            O time do Hibernate mantém este recurso, desenvolvendo as diversas implementações do 
+            <literal>JTA TransactionManager</literal>, a maioria (se não todos) aplicativos deveria 
+            utilizar o gerenciador de transações <literal>JTA</literal> sendo ou não instalados dentro 
+            de um container <literal>J2EE</literal>. Baseado neste recurso, você deveria sempre utilizar sessões 
+            contextuais baseadas em <literal>JTA</literal>.
+        </para>
+        <para>
+            Entretanto, na versão 3.1, o processo por trás do método <literal>SessionFactory.getCurrentSession()</literal> 
+            é agora plugavel. Com isso, uma nova interface (<literal>org.hibernate.context.CurrentSessionContext</literal>)
+            e um novo parâmetro de configuração (<literal>hibernate.current_session_context_class</literal>)
+            foram adicionados para possibilitar a compatibilidade do contexto e do escopo na definição de sessões correntes.
+        </para>
+        <para>
+            De uma olhada em Javadocs sobre a interface <literal>org.hibernate.context.CurrentSessionContext</literal>
+            para uma discussão detalhada. Ela define um método único, <literal>currentSession()</literal>, 
+            com o qual a implementação é responsável por rastrear a sessão contextual corrente. 
+            Por fora do "encapsulamento", o Hibernate possui duas implementações dessa interface.
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.context.JTASessionContext</literal> - As sessões correntes 
+                    são rastreadas e recebem um escopo por uma transação <literal>JTA</literal>. 
+                    O processamento aqui é exatamente igual ao antigo processo JTA. Consulte em 
+                    Javadocs para maiores detalhes.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.context.ThreadLocalSessionContext</literal> - As sessões 
+                    correntes são rastreadas por uma thread de execução. Novamente, consulte em 
+                    Javadocs para maiores detalhes.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.context.ManagedSessionContext</literal> - current
+                    sessions are tracked by thread of execution. However, you are responsible to
+                    bind and unbind a <literal>Session</literal> instance with static methods
+                    on this class, it does never open, flush, or close a <literal>Session</literal>.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            As duas primeiras implementações usam o modelo de programação "uma sessão – uma transação 
+            do banco de dados", também conhecida e usado como <emphasis>sessão por requisição</emphasis>. 
+            O começo e o fim de uma sessão Hibernate é definida pela duração da transação do banco de dados. 
+            Se você usa demarcação programática de transação (por exemplo. em J2SE puro ou com JTA
+            /UserTransaction/BMT), você é recomendado a usar a API Hibernate <literal>Transaction</literal> 
+            para esconder a base do sistema de transação do seu código. Se você executa em um container EJB 
+            que suporta CMT, os limites das transações são definidas declarativamente e você não necessita 
+            de qualquer transação ou operação de demarcação de sessão no seu código. Consulte o <xref linkend="transactions"/>
+            para mais informações exemplos de código.
+        </para>
+
+        <para>
+            O parâmetro de configuração <literal>hibernate.current_session_context_class</literal> 
+            define que a implementação <literal>org.hibernate.context.CurrentSessionContext</literal> 
+            deve ser usada. Note que para compatibilidade anterior, se este parâmetro de configuração 
+            não é determinado mas um <literal>org.hibernate.transaction.TransactionManagerLookup</literal> 
+            é configurado, Hibernate usará o <literal>org.hibernate.context.JTASessionContext</literal>.
+            Tipicamente, o valor deste parâmetro nomearia apenas a classe de implementação para usar; 
+            para as duas implementações out-of-the-box, entretanto, há dois pequenos nomes correspondentes, 
+            "jta", "thread", and "managed".
+        </para>
+        
+    </sect1>
+
+</chapter>


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/architecture.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/association_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/association_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/association_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,635 @@
+<chapter id="associations">
+
+    <title>Mapeamento de Associações</title>
+
+    <sect1 id="assoc-intro" revision="1">
+        <title>Introdução</title>
+        
+        <para>
+            Mapeamentos de associações são freqüentemente a  coisa mais difícil de se 
+            acertar. Nesta seção nós passaremos pêlos casos canônicos um pôr um, 
+            começando com mapeamentos unidirecionais e considerando os casos 
+            bidirecionais. Nos vamos usar <literal>Person</literal> e 
+            <literal>Address</literal> em todos os exemplos.
+        </para>
+        
+        <para>
+        	Nós classificaremos as associações pelo seu mapeamento ou a falta do 
+        	mesmo, sua intervenção na tabela associativa, e pela sua multiplicidade.
+        </para>
+        
+        <para>
+        	O uso de chaves estrangeiras não obrigatórias não é considerada uma boa 
+        	prática na modelagem de dados tradicional, assim todos nossos exemplos 
+        	usam chaves estrangeiras obrigatórias. Esta não é uma exigência do 
+        	Hibernate, e todas as mapeamentos funcionarão se você remover as 
+        	constraints de obrigatoriedade.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="assoc-unidirectional" revision="1">
+        <title>Associações Unidirecionais</title>
+        
+        <sect2 id="assoc-unidirectional-m21">
+        <title>muitos para um</title>
+        
+        <para>
+            Uma <emphasis>associação unidirecional  muitos-para-um</emphasis> é o 
+            tipo mais comum de associação unidirecional.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-121">
+        <title>um para um</title>
+        
+        <para>
+            Uma <emphasis>associação unidirecional um-para-um em uma chave estrangeira
+            </emphasis> é quase idêntica. A única diferença é a constraint unique 
+            na coluna.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId" 
+        unique="true"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        <para>
+            Uma <emphasis>associação unidirecional um-para-um  na chave primaria</emphasis>  
+            geralmente usa um gerador de id special. ( Note que nós invertemos a 
+            direção da associação nesse exemplo).
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+</class>
+
+<class name="Address">
+    <id name="id" column="personId">
+        <generator class="foreign">
+            <param name="property">person</param>
+        </generator>
+    </id>
+    <one-to-one name="person" constrained="true"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+        <sect2 id="assoc-unidirectional-12m">
+        <title>um para muitos</title>
+        
+        <para>
+            Uma <emphasis>associação unidirecional um-para-muitos em uma chave 
+            estrangeira</emphasis> é um caso muito incomum, e realmente não é recomendada.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses">
+        <key column="personId" 
+            not-null="true"/>
+        <one-to-many class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( addressId bigint not null primary key, personId bigint not null )
+        ]]></programlisting>
+        
+        <para>
+            Nós achamos que é melhor usar uma tabela associativa para este tipo de 
+            associação.
+        </para>
+        
+        </sect2>
+    
+    </sect1>
+
+    <sect1 id="assoc-unidirectional-join" revision="1">
+        <title>Associações Unidirecionais com tabelas associativas</title>
+        
+        <sect2 id="assoc-unidirectional-join-12m">
+        <title>um para muitos</title>
+        
+        <para>
+            Uma <emphasis>associação um-para-muitos unidirecional usando uma tabela 
+            associativa</emphasis> e o mais comum. Note que se especificarmos 
+            <literal>unique="true"</literal>, estaremos modificando a cardinalidade 
+            de muitos-para-muitos para um-para-muitos.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            unique="true"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-m21">
+        <title>muitos para um</title>
+        
+        <para>
+            Uma <emphasis>associação unidirecional muitos-para-um em uma tabela 
+            associativa</emphasis> é bastante comum quando a associação for opcional.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-121">
+        <title>um para um</title>
+        
+        <para>
+            Uma <emphasis>associação unidirecional um-para-um em uma tabela 
+            associativa</emphasis> é extremamente incomum, mas possível.
+            
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-m2m">
+        <title>muitos para muitos</title>
+        
+        <para>
+            Finalmente, nós temos a <emphasis>associação unidirecional muitos-para-
+            muitos</emphasis>.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="assoc-bidirectional" revision="1">
+        <title>Associações Bidirecionais</title>
+        
+        <sect2 id="assoc-bidirectional-m21" revision="2">
+        <title>um para muitos / muitos para um</title>
+        
+        <para>
+            Uma <emphasis>associação bidirecional muitos-para-um</emphasis> é o 
+            tipo mais comum de associação. (Esse é o relacionamento padrão 
+            pai / filho. )
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <set name="people" inverse="true">
+        <key column="addressId"/>
+        <one-to-many class="Person"/>
+    </set>
+</class>]]></programlisting>
+
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+
+        <para>
+            Se você usar uma <literal>List</literal> ( ou outra coleção indexada ), você 
+            precisa especificar a coluna <literal>chave</literal> estrangeira como not null, 
+            e deixar o Hibernate administrar a associação do lado da coleção para que 
+            seja mantido o índice de cada elemento da coleção (fazendo com que o outro 
+            lado seja virtualmente inverso setando <literal>update="false"</literal> 
+            e <literal>insert="false"</literal>):             
+        </para>
+
+        <programlisting><![CDATA[<class name="Person">
+   <id name="id"/>
+   ...
+   <many-to-one name="address"
+      column="addressId"
+      not-null="true"
+      insert="false"
+      update="false"/>
+</class>
+
+<class name="Address">
+   <id name="id"/>
+   ...
+   <list name="people">
+      <key column="addressId" not-null="true"/>
+      <list-index column="peopleIdx"/>
+      <one-to-many class="Person"/>
+   </list>
+</class>]]></programlisting>
+
+            <para>
+                É importante que você defina <literal>not-null="true"</literal> no elemento 
+                <literal>&lt;key&gt;</literal> no mapeamento na coleção se a coluna de chave 
+                estrangeira for <literal>NOT NULL</literal>. Não declare como 
+                <literal>not-null="true"</literal> apenas um elemento aninhado 
+                <literal>&lt;column&gt;</literal>, mas sim o elemento 
+                <literal>&lt;key&gt;</literal>.
+            </para>
+
+        </sect2>
+        
+        <sect2 id="assoc-bidirectional-121">
+        <title>um para um</title>
+        
+        <para>
+            Uma <emphasis>associação bidirecional um para um em uma chave estrangeira</emphasis>
+             é bastante comum.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId" 
+        unique="true"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+   <one-to-one name="person" 
+        property-ref="address"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        <para>
+            Uma <emphasis>associação bidirecional um para um em uma chave primária</emphasis>
+            usa um gerador de id especial.
+        </para>
+        
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <one-to-one name="address"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="personId">
+        <generator class="foreign">
+            <param name="property">person</param>
+        </generator>
+    </id>
+    <one-to-one name="person" 
+        constrained="true"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="assoc-bidirectional-join" revision="1">
+        <title>Associações Bidirecionais com tabelas associativas</title>
+        
+        <sect2 id="assoc-bidirectional-join-12m">
+        <title>um para muitos / muitos para um</title>
+        
+        <para>
+            Uma <emphasis>associação bidirecional um para muitos em uma tabela 
+            associativa</emphasis>. Veja que <literal>inverse="true"</literal>  pode ser 
+            colocado em qualquer ponta associação, na coleção, ou no join.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" 
+        table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            unique="true"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        inverse="true" 
+        optional="true">
+        <key column="addressId"/>
+        <many-to-one name="person"
+            column="personId"
+            not-null="true"/>
+    </join>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+         <sect2 id="assoc-bidirectional-join-121">
+        <title>one to one</title>
+        
+        <para>
+            Uma <emphasis>associação bidirecional um-para-um em uma tabela de 
+            associação</emphasis>  é algo bastante incomum, mas possivel.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true"
+        inverse="true">
+        <key column="addressId" 
+            unique="true"/>
+        <many-to-one name="person"
+            column="personId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+
+        </sect2>
+        
+        <sect2 id="assoc-bidirectional-join-m2m" revision="1">
+        <title>muitos para muitos</title>
+        
+        <para>
+            Finally, we have a <emphasis>bidirectional many-to-many association</emphasis>.
+            Finalmente, nós temos uma associação bidirecional de muitos para muitos.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <set name="people" inverse="true" table="PersonAddress">
+        <key column="addressId"/>
+        <many-to-many column="personId"
+            class="Person"/>
+    </set>
+</class>]]></programlisting>
+
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+    </sect1>
+    
+    <sect1 id="assoc-complex">
+        <title>Mapeamento de associações mais complexas</title>
+        
+        <para>
+            More complex association joins are <emphasis>extremely</emphasis> rare. 
+            Hibernate makes it possible to handle more complex situations using
+            SQL fragments embedded in the mapping document. For example, if a table
+            with historical account information data defines 
+            <literal>accountNumber</literal>, <literal>effectiveEndDate</literal> 
+            and <literal>effectiveStartDate</literal>columns, mapped as follows:
+Joins de associações mais complexas são extremamente raros. O Hibernate torna possível tratar mapeamentos mais complexos usando fragmentos de SQL embutidos no documento de mapeamento. Por exemplo, se uma tabela com informações de dados históricos de uma conta define a coluna accountNumber, effectiveEndDate e effectiveStartDate, mapeadas assim como segue:
+        </para>
+        
+        <programlisting><![CDATA[<properties name="currentAccountKey">
+    <property name="accountNumber" type="string" not-null="true"/>
+    <property name="currentAccount" type="boolean">
+        <formula>case when effectiveEndDate is null then 1 else 0 end</formula>
+    </property>
+</properties>
+<property name="effectiveEndDate" type="date"/>
+<property name="effectiveStateDate" type="date" not-null="true"/>]]></programlisting>
+
+        <para>
+            Then we can map an association to the <emphasis>current</emphasis> instance 
+            (the one with null <literal>effectiveEndDate</literal>) using:
+Então nós podemos mapear uma associação para a instância corrente (aquela com a effectiveEndDate igual a null) usando:            
+        </para>
+        
+        <programlisting><![CDATA[<many-to-one name="currentAccountInfo" 
+        property-ref="currentAccountKey"
+        class="AccountInfo">
+    <column name="accountNumber"/>
+    <formula>'1'</formula>
+</many-to-one>]]></programlisting>
+
+        <para>
+            In a more complex example, imagine that the association between 
+            <literal>Employee</literal> and <literal>Organization</literal> is maintained
+            in an <literal>Employment</literal> table full of historical employment data.
+            Then an association to the employee's <emphasis>most recent</emphasis> employer
+            (the one with the most recent <literal>startDate</literal>) might be mapped this way:
+Em um exemplo mais complexo, imagine que a associação entre Employee e Organization é mantida em uma tabela Employment cheia de dados históricos do trabalho. Então a associação do funcionário mais recentemente empregado (aquele com a mais recente startDate) deve ser mapeado desta maneira:            
+        </para>
+        
+        <programlisting><![CDATA[<join>
+    <key column="employeeId"/>
+    <subselect>
+        select employeeId, orgId 
+        from Employments 
+        group by orgId 
+        having startDate = max(startDate)
+    </subselect>
+    <many-to-one name="mostRecentEmployer" 
+            class="Organization" 
+            column="orgId"/>
+</join>]]></programlisting>
+
+        <para>
+            You can get quite creative with this functionality, but it is usually more practical 
+            to handle these kinds of cases using HQL or a criteria query.
+Você pode ser criativo com esta funcionalidade, mas geralmente é mais prático tratar estes tipos de casos, usando uma pesquisa HQL ou uma pesquisa por criteria.
+        </para>
+
+    </sect1>
+
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/association_mapping.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/basic_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/basic_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/basic_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,3491 @@
+<chapter id="mapping">
+    <title>Mapeamento O/R Bassico</title>
+
+    <sect1 id="mapping-declaration" revision="1">
+        <title>Declaração de mapeamento</title>
+
+        <para>
+            Object/relational mappings are usually defined in an XML document. The mapping
+            document is designed to be readable and hand-editable. The mapping language is
+            Java-centric, meaning that mappings are constructed around persistent class
+            declarations, not table declarations.
+        </para>
+        
+        <para>
+            Note that, even though many Hibernate users choose to write the XML by hand,
+            a number of tools exist to generate the mapping document, including XDoclet,
+            Middlegen and AndroMDA.
+        </para>
+
+        <para>
+            Lets kick off with an example mapping:
+        </para>
+
+        <programlisting id="mapping-declaration-ex1" revision="1"><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+        <class name="Cat" 
+            table="cats"
+            discriminator-value="C">
+                
+                <id name="id">
+                        <generator class="native"/>
+                </id>
+
+                <discriminator column="subclass" 
+                     type="character"/>
+
+                <property name="weight"/>
+
+                <property name="birthdate"
+                    type="date" 
+                    not-null="true" 
+                    update="false"/>
+
+                <property name="color"
+                    type="eg.types.ColorUserType"
+                    not-null="true"
+                    update="false"/>
+
+                <property name="sex"
+                    not-null="true" 
+                    update="false"/>
+
+                <property name="litterId"
+                    column="litterId"
+                    update="false"/>
+
+                <many-to-one name="mother"
+                    column="mother_id"
+                    update="false"/>
+
+                <set name="kittens"
+                    inverse="true"
+                    order-by="litter_id">
+                        <key column="mother_id"/>
+                        <one-to-many class="Cat"/>
+                </set>
+
+                <subclass name="DomesticCat"
+                    discriminator-value="D">
+
+                        <property name="name" 
+                            type="string"/>
+
+                </subclass>
+
+        </class>
+
+        <class name="Dog">
+                <!-- mapping for Dog could go here -->
+        </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+             Discutir agora o conteúdo deste documento de mapeamento. Iremos apenas descrever 
+             os elementos do documento e atributos que são utilizados pelo Hibernate em tempo 
+             de execução. O documento de mapeamento também contém alguns atributos adicionais 
+             e opcionais além de elementos que afetam os esquemas de banco de dados exportados 
+             pela ferramenta de exportação de esquemas. (Por exemplo, o atributo 
+             <literal>not-null</literal>).
+        </para>
+
+
+
+        <sect2 id="mapping-declaration-doctype" revision="3">
+            <title>Doctype</title>
+
+            <para>
+                Todos os mapeamentos de XML devem declarar o doctype exibido. O DTD atual pode 
+                ser encontrado na URL abaixo, no diretório <literal>hibernate-x.x.x/src/org/
+                hibernate </literal> ou no <literal>hibernate3.jar</literal>. O Hibernate sempre 
+                irá procurar pelo DTD inicialmente no seu classpath. Se você tentar localizar
+                o DTD usando uma conexão de internet, compare a declaração do seu DTD com o 
+                conteúdo do seu classpath
+            </para>
+
+            <sect3 id="mapping-declaration-entity-resolution">
+                <title>EntityResolver</title>
+                <para>
+                    As mentioned previously, Hibernate will first attempt to resolve DTDs in its classpath.  The
+                    manner in which it does this is by registering a custom <literal>org.xml.sax.EntityResolver</literal>
+                    implementation with the SAXReader it uses to read in the xml files.  This custom
+                    <literal>EntityResolver</literal> recognizes two different systemId namespaces.
+                </para>
+                <itemizedlist>
+                    <listitem>
+                        <para>
+                            a <literal>hibernate namespace</literal> is recognized whenever the
+                            resolver encounteres a systemId starting with
+                            <literal>http://hibernate.sourceforge.net/</literal>; the resolver
+                            attempts to resolve these entities via the classlaoder which loaded
+                            the Hibernate classes.
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            a <literal>user namespace</literal> is recognized whenever the
+                            resolver encounteres a systemId using a <literal>classpath://</literal>
+                            URL protocol; the resolver will attempt to resolve these entities
+                            via (1) the current thread context classloader and (2) the
+                            classloader which loaded the Hibernate classes.
+                        </para>
+                    </listitem>
+                </itemizedlist>
+                <para>
+                    An example of utilizing user namespacing:
+                </para>
+                <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [
+    <!ENTITY types SYSTEM "classpath://your/domain/types.xml">
+]>
+
+<hibernate-mapping package="your.domain">
+    <class name="MyEntity">
+        <id name="id" type="my-custom-id-type">
+            ...
+        </id>
+    <class>
+    &types;
+</hibernate-mapping>]]></programlisting>
+                <para>
+                    Where <literal>types.xml</literal> is a resource in the <literal>your.domain</literal>
+                    package and contains a custom <xref linkend="mapping-types-custom">typedef</xref>.
+                </para>
+            </sect3>
+        </sect2>
+
+        <sect2 id="mapping-declaration-mapping" revision="3">
+            <title>hibernate-mapping</title>
+
+            <para>
+                Este elemento tem diversos atributos opcionais. Os atributos  
+                <literal>schema</literal> e <literal>catalog</literal> especificam que tabelas 
+                referenciadas neste mapeamento pertencem ao esquema e/ou ao catalogo nomeado. 
+                Se especificados, os nomes das tabelas irão ser qualificados no schema ou catalog dado. 
+                Se não, os nomes das tabelas não serão qualificados. O atributo <literal>default-cascade
+                </literal> especifica qual estilo de cascata será assumido pelas propriedades e 
+                coleções que não especificarm um atributo <literal>cascade</literal>. O atributo 
+                <literal>auto-import</literal> nos deixa utilizar nomes de classes não qualificados 
+                na linguagem de consulta, por default.
+            </para>
+ 
+             <programlistingco>
+                 <areaspec>
+                     <area id="hm1" coords="2 55"/>
+                     <area id="hm2" coords="3 55"/>
+                     <area id="hm3" coords="4 55"/>
+                     <area id="hm4" coords="5 55"/>
+                     <area id="hm5" coords="6 55"/>
+                     <area id="hm6" coords="7 55"/>
+                     <area id="hm7" coords="8 55"/>
+                 </areaspec>
+                 <programlisting><![CDATA[<hibernate-mapping
+         schema="schemaName"
+         catalog="catalogName"
+         default-cascade="cascade_style"
+         default-access="field|property|ClassName"
+         default-lazy="true|false"
+         auto-import="true|false"
+         package="package.name"
+ />]]></programlisting>
+                 <calloutlist>
+                     <callout arearefs="hm1">
+                         <para>
+                             <literal>schema</literal> (opcional): O nome do esquema do banco de dados.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm2">
+                         <para>
+                             <literal>catalog</literal> (opcional):  O nome do catálogo do banco de dados.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm3">
+                         <para>
+                             <literal>default-cascade</literal> (opcional – default é <literal>nenhum
+                             </literal>): Um estilo cascata default.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm4">
+                         <para>
+                             <literal>default-access</literal> (opcional – default é <literal>property</literal>): 
+                             A estratégia que o Hibernate deve utilizar para acessar todas as propridades. Pode 
+                             ser uma implementação própria de <literal>PropertyAccessor</literal>.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm5">
+                         <para>
+                             <literal>default-lazy</literal> (opcional - default é <literal>true</literal>): 
+                             O valor default para atributos <literal>lazy</literal> da classe e dos 
+                             mapeamentos de coleções.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm6">
+                         <para>
+                             <literal>auto-import</literal> ((opcional - default é <literal>true</literal>):
+                             Especifica se nós podemos usar nomes de classess não qualificados 
+                             (das classes deste mapeamento) na linguagem de consulta.
+                         </para>
+                     </callout>
+                     <callout arearefs="hm7">
+                         <para>
+                             <literal>package</literal> (opcional): Especifica um prefixo da package para 
+                             assumir para nomes de classes não qualificadas no documento de mapeamento.
+                         </para>
+                     </callout>
+                 </calloutlist>
+             </programlistingco>
+             
+             <para>
+                 Se voce tem duas classes persistentes com o mesmo nome (não qualificadas), você deve 
+                 setar <literal>auto-import="false"</literal>. O Hibernate irá gerar uma exceção se 
+                 você tentar setar duas classes para o mesmo nome "importado".
+             </para>
+
+             <para>
+                  Observe que o elemento <literal>hibernate-mapping</literal> permite a você 
+                 aninhar diversos mapeamentos de <literal>&lt;class&gt;</literal> persistentes, 
+                 como mostrado abaixo. Entretanto, é uma boa prática (e esperado por algumas 
+                 ferramentas)o mapeamento de apenas uma classe persistente simples (ou uma 
+                 hierarquia de classes simples) em um arquivo de mapeamento e nomea-la após 
+                 a superclasse persistente, por exemplo: <literal>Cat.hbm.xml</literal>, 
+                 <literal>Dog.hbm.xml</literal>,  ou se estiver usando herança,
+                 <literal>Animal.hbm.xml</literal>.
+             </para>
+ 
+        </sect2>
+
+        <sect2 id="mapping-declaration-class" revision="3">
+            <title>class</title>
+
+            <para>
+                Você pode declarar uma classe persistente utilizando o elemento
+                <literal>class</literal>:
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="class1" coords="2 55"/>
+                    <area id="class2" coords="3 55" />
+                    <area id="class3" coords="4 55"/>
+                    <area id="class4" coords="5 55" />
+                    <area id="class5" coords="6 55"/>
+                    <area id="class6" coords="7 55" />
+                    <area id="class7" coords="8 55"/>
+                    <area id="class8" coords="9 55" />
+                    <area id="class9" coords="10 55" />
+                    <area id="class10" coords="11 55"/>
+                    <area id="class11" coords="12 55"/>
+                    <area id="class12" coords="13 55"/>
+                    <area id="class13" coords="14 55"/>
+                    <area id="class14" coords="15 55"/>
+                    <area id="class15" coords="16 55"/>
+                    <area id="class16" coords="17 55"/>
+                    <area id="class17" coords="18 55"/>
+                    <area id="class18" coords="19 55"/>
+                    <area id="class19" coords="20 55"/>
+                    <area id="class20" coords="21 55"/>
+                    <area id="class21" coords="22 55"/>
+                </areaspec>
+                <programlisting><![CDATA[<class
+        name="ClassName"
+        table="tableName"
+        discriminator-value="discriminator_value"
+        mutable="true|false"
+        schema="owner"
+        catalog="catalog"
+        proxy="ProxyInterface"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        select-before-update="true|false"
+        polymorphism="implicit|explicit"
+        where="arbitrary sql where condition"
+        persister="PersisterClass"
+        batch-size="N"
+        optimistic-lock="none|version|dirty|all"
+        lazy="true|false"
+        entity-name="EntityName"
+        check="arbitrary sql check condition"
+        rowid="rowid"
+        subselect="SQL expression"
+        abstract="true|false"
+        node="element-name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="class1">
+                        <para>
+                            <literal>name</literal> (opcional): O nome da classe Java inteiramente qualificado
+                            da classe persistente (ou interface); Se o atributo é ausente, assume-se que o 
+                            mapeamento é para intidades não-POJO.
+                        </para>
+                    </callout>
+                    <callout arearefs="class2">
+                        <para>
+                            <literal>table</literal> (opcional – default para nomes de classes não 
+                            qualificadas) O nome da sua tabela do banco de dados.
+                        </para>
+                    </callout>
+                    <callout arearefs="class3">
+                        <para>
+                            <literal>discriminator-value</literal> (opcional – default para o nome da classe):  
+                            Um valor que distingue subclasses individuais, usadas para o comportamento polimorfico. 
+                            Valores aceitos incluem <literal>null</literal> e <literal>not null</literal>
+                        </para>
+                    </callout>
+                    <callout arearefs="class4">
+                        <para>
+                            <literal>mutable</literal> (opcional - valor default <literal>true</literal>): 
+                            Especifica que instancias da classe são (ou não) mutáveis
+                        </para>
+                    </callout>    
+                    <callout arearefs="class5">
+                        <para>
+                            <literal>schema</literal> (opcional): Sobrepõe o nome do esquema especificado 
+                            pelo elemento root <literal>&lt;hibernate-mapping&gt;</literal>.
+                        </para>
+                    </callout>                
+                    <callout arearefs="class6">
+                        <para>
+                            <literal>catalog</literal> (opcional): Sobrepõe o nome do catálogo especificado 
+                            pelo elemento root  <literal>&lt;hibernate-mapping&gt;</literal>. 
+                        </para>
+                    </callout>                
+                    <callout arearefs="class7">
+                        <para>
+                            <literal>proxy</literal> (opcional): Especifica um interface para ser 
+                            utilizada pelos proxies de inicialização tardia. Você pode especificar o 
+                            nome da própria classe.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class8">
+                        <para>
+                            <literal>dynamic-update</literal> (opcional, valor default <literal>false</literal>): 
+                            Especifica que o SQL de <literal>UPDATE</literal> deve ser gerado em tempo de 
+                            execução e conter apenas aquelas colunas cujos valores foram alterados.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class9">
+                        <para>
+                            <literal>dynamic-insert</literal> (opcional, valor default <literal>false</literal>): 
+                            Especifica que o SQL de  <literal>INSERT</literal> deve ser gerado em tempo de 
+                            execução e conter apenas aquelas colunas cujos valores não estão nulos.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class10">
+                        <para>
+                            <literal>select-before-update</literal>  (opcional, valor default <literal>false</literal>): 
+                            Especifica que o Hibernate <emphasis>never</emphasis> deve executar um SQL de 
+                            <literal>UPDATE</literal> a não ser que com certeza um objeto está atualmente modificado. 
+                            Em certos casos (atualmente, apenas quando um objeto transiente foi associado com uma nova
+                            sessão utilizando  <literal>update()</literal>), isto significa que o Hibernate ira executar 
+                            uma instrução SQL de <literal>SELECT</literal> adicional para determinar se um 
+                            <literal>UPDATE</literal> é necessário nesse momento.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class11">
+                        <para>
+                            <literal>polymorphism</literal> (opcional, default para <literal>implicit</literal>): 
+                            Determina se deve ser utilizado a query polimorfica implicita ou explicitamente.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class12">
+                        <para>
+                            <literal>where</literal> (opicional) especifica um comando SQL <literal>WHERE</literal>
+                            arbitrário para ser usado quando da recuperação de objetos desta classe.
+                        </para>
+                    </callout>                 
+                    <callout arearefs="class13">
+                        <para>
+                            <literal>persister</literal> (opcional): Espeicifca uma <literal>ClassPersister</literal> 
+                            customizada.
+                        </para>
+                    </callout>                 
+                    <callout arearefs="class14">
+                        <para>
+                            <literal>batch-size</literal> (opcional, valor default <literal>1</literal>) especifica um  
+                            "tamanho de lote" para a recuperação de instancias desta classe pelo identificador.
+                        </para>
+                    </callout>                 
+                   <callout arearefs="class15">
+                        <para>
+                            <literal>optimistic-lock</literal> (octional, valor default <literal>version</literal>): 
+                            Determina a estratégia de bloqueio.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class16">
+                        <para>
+                            <literal>lazy</literal> (opcional): A recuperação tardia pode ser completamente 
+                            desabilitada, setando <literal>lazy="false"</literal>.
+                        </para>
+                    </callout>    
+                    <callout arearefs="class17">
+                        <para>
+                            <literal>entity-name</literal> (opcional, default para o nome da classe): O 
+                            Hibernate3 permite uma classe ser mapeada multiplas vezes, (potencialmente,para 
+                            diferentes tabelas), e permite mapeamentos de entidades que são representadas 
+                            por Maps ou XML no nível Java. Nestes casos, você deve especificar um nome 
+                            arbitrário explicitamente para a entidade. Veja <xref linkend="persistent-classes-dynamicmodels"/> 
+                            e <xref linkend="xml"/> para maiores informações.
+                        </para>
+                    </callout>
+                    <callout arearefs="class18">
+                        <para>
+                            <literal>check</literal> (opcional): Uma expressão SQL utilizada para gerar uma 
+                            constraint de <emphasis>verificação</emphasis> de múltiplas linhas para a geração 
+                            automática do esquema.
+                        </para>
+                    </callout>
+                    <callout arearefs="class19">
+                        <para>
+                            <literal>rowid</literal> (opcional): O Hibernate poder usar as assim chamadas 
+                            ROWIDs em bancos de dados que a suportam. Por exemplo, no Oracle, o Hibernate 
+                            pode utilizar a coluna extra rowid para atualizações mais rápidas se você 
+                            configurar esta opção para <literal>rowid</literal>. Um ROWID é uma implementação 
+                            que representa de maneira detalhada a localização física de uma determinada 
+                            tupla armazenado.
+                        </para>
+                    </callout>
+                    <callout arearefs="class20">
+                        <para>
+                            <literal>subselect</literal> (optional): Maps an immutable and read-only entity
+                            to a database subselect. Useful if you want to have a view instead of a base table,
+                            but don't. See below for more information.
+                            <literal>subselect</literal> (opcional): Mapeia uma entidade imutavel e somente
+                            de leitura para um  subconjunto do banco de dados. Útil se você quiser ter uma 
+                            view em vez de uma tabela. Veja abaixo para mais informações.
+                        </para>
+                    </callout>
+                    <callout arearefs="class21">
+                        <para>
+                            <literal>abstract</literal> (opcional): Utilizada para marcar superclasses 
+                            abstratas em hierarquias <literal>&lt;union-subclass&gt;</literal>.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+           
+            <para>
+                É perfeitamente aceitável para uma classe persitente nomeada ser uma interface. Você deverá 
+                então declarar as classes implementadas desta interface utilizando o elemento  
+                <literal>&lt;subclass&gt;</literal>. Você pode persistir qualquer classe de aninhada
+                <emphasis>estatica</emphasis>. Você deverá especificar o nome da classe usando a forma 
+                padrão, por exemplo:  <literal>eg.Foo$Bar</literal>.
+            </para>
+
+            <para>
+                Classes imutáveis,  <literal>mutable="false"</literal>, não podem ser modificadas ou excluídas 
+                pela aplicação. Isso permite ao Hibernate fazer alguns aperfeiçoamentos de performance.
+            </para>
+            
+            <para>
+                O atributo opcional <literal>proxy</literal> habilita a inicialização tardia das 
+                instâncias persistentes da classe. O Hibernate irá retornar CGLIB proxies como implementado 
+                na interface nomeada. O objeto persistente atual  será carregado quando um método do proxy 
+                for invocado. Veja "Proxies para Inicialização Lazy" abaixo.
+            </para>
+            
+            <para>Polimorfismo <emphasis>implícito</emphasis> significa que instâncias de uma classe 
+                serão retornada por uma query que dá nome a qualquer superclasse ou interface implementada, 
+                ou a classe e as instancias de qualquer subclasse da classe será retornada por umq query 
+                que nomeia a classe por si. Polimorfismo <emphasis>explícito</emphasis> significa que 
+                instancias da classe serão retornadas apenas por queries que explicitamente nomeiam a 
+                classe e que queries que nomeiam as classes irão retornar apenas instancias de subclasses 
+                mapeadas dentro da declaração <literal>&lt;class&gt;</literal> como uma 
+                <literal>&lt;subclass&gt;</literal> ou <literal>&lt;joined-subclass&gt;</literal>.
+                Para a maioria dos casos, o valor default <literal>polymorphism="implicit"</literal>, 
+                é apropriado. Polimorfismo explicito é útil quando duas classes distintas estão mapeadas 
+                para a mesma tabela (isso permite um classe "peso leve" que contem um subconjunto 
+                de colunas da tabela).
+            </para>
+            
+            <para>
+                O atributo <literal>persister</literal> deixa você customizar a estratégia de persistência 
+                utilizada para a classe. Você pode, por exemplo, especificar sua prórpia subclasse do 
+                <literal>org.hibernate.persister.EntityPersister</literal> ou você pode criar 
+                uma implementação completamente nova  da interface 
+                <literal>org.hibernate.persister.ClassPersister</literal> que implementa a persistência 
+                através de, por exemplo, chamadas a stored procedeures, serialização de arquivos flat ou 
+                LDAP. Veja <literal>org.hibernate.test.CustomPersister</literal> para um exemplo 
+                simples (de "persistencia" para uma <literal>Hashtable</literal>).
+            </para>
+            
+            <para>
+                Observe que as configurações <literal>dynamic-update</literal> e 
+                <literal>dynamic-insert</literal> não sao herdadas pelas subclasses e assim podem tambem 
+                ser especificadas em elementos <literal>&lt;subclass&gt;</literal> or 
+                <literal>&lt;joined-subclass&gt;</literal>. Estas configurações podem incrementar a 
+                performance em alguns casos, mas pode realmente diminuir a performance em outras. 
+                Use-as de forma bastante criteriosa.
+            </para>
+            
+            <para>
+                O uso de <literal>select-before-update</literal> geralmente irá diminuir a performance. Ela é 
+                muito útil para prevenir que uma trigger de atualização no banco de dados seja ativada 
+                desnecessariamente, se você reconectar um nó de uma instancia desconectada em uma 
+                <literal>Session</literal>.
+            </para>
+            
+            <para>
+                Se você ativar  <literal>dynamic-update</literal>, você terá de escolher 
+                a estratégia de bloqueio otimista:
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <literal>version</literal> verifica a versão e a hora das colunas
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>all</literal> cverifica todas as colunas
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>dirty</literal> verifica as colunas modificadas, permitindo 
+                        alguns updates concorrentes
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>none</literal> não utiliza o bloqueio otimista
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <para>
+                Nós <emphasis>recomendamos</emphasis> com muita enfase que você utilize a 
+                versão e a hora das colunas para o bloqueio otimista com o Hibernate. 
+                Esta é a melhor estratégia com respeito a performance e é a única estratégia 
+                que trata corretamente as modificações efetuadas em instancias desconectadas 
+                (por exemplo, quando <literal>Session.merge()</literal> é utilizado).
+
+            </para>
+
+            <para>
+                Não ha diferença entre uma view e uma tabela para o mapeamento do Hibernate, e como 
+                esperado isto é transparente no nível do banco de dados (observe que alguns bancos de 
+                dados não suportam views apropriadamente, especialmente com updates). Algumas vezes, 
+                você quer utilizar uma view, ma snão pode cria-la no banco de dados (por exemplo, 
+                com um esquema legado). Neste caso, você pode mapear uma entidade imutável e de 
+                somente leitura, para uma dada expressão SQL, que representa um subselect:
+            </para>
+
+            <programlisting><![CDATA[<class name="Summary">
+    <subselect>
+        select item.name, max(bid.amount), count(*)
+        from item
+        join bid on bid.item_id = item.id
+        group by item.name
+    </subselect>
+    <synchronize table="item"/>
+    <synchronize table="bid"/>
+    <id name="name"/>
+    ...
+</class>]]></programlisting>
+
+            <para>
+                Declare as tabelas para sincronizar com esta entidade, garantindo que o auto-flush 
+                ocorra corretamente, e que as queries para esta entidade derivada não retornem dados 
+                desatualizados. O <literal>&lt;subselect&gt;</literal> está disponível tanto como um 
+                atributo como um elemento mapeado nested.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-id" revision="4">
+            <title>id</title>
+
+            <para>
+                Classes mapeadas <emphasis>precisam</emphasis> declarar a coluna de chave primaria da 
+                tabela do banco de dados. Muitas classes irão tambem ter uma propriedade ao estilo 
+                Java-Beans declarando o identificador unico de uma instancia. O elemento 
+                <literal>&lt;id&gt;</literal> define o mapeamento desta propriedade para a chave primária.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="id1" coords="2 70"/>
+                    <area id="id2" coords="3 70" />
+                    <area id="id3" coords="4 70"/>
+                    <area id="id4" coords="5 70" />
+                    <area id="id5" coords="6 70" />
+                </areaspec>
+                <programlisting><![CDATA[<id
+        name="propertyName"
+        type="typename"
+        column="column_name"
+        unsaved-value="null|any|none|undefined|id_value"
+        access="field|property|ClassName">
+        node="element-name|@attribute-name|element/@attribute|."
+
+        <generator class="generatorClass"/>
+</id>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="id1">
+                        <para>
+                            <literal>name</literal> (opcional): O nome do identificador.
+                        </para>
+                    </callout>
+                    <callout arearefs="id2">
+                        <para>
+                            <literal>type</literal> (opcional): Um nome que indica o tipo no Hibernate.
+                        </para>
+                    </callout>
+                    <callout arearefs="id3">
+                        <para>
+                            <literal>column</literal> (opcional – default para o a propridade name): O 
+                            nome coluna chave primaria.
+                        </para>
+                    </callout>
+                    <callout arearefs="id4">
+                        <para>
+                            <literal>unsaved-value</literal> (opcional - default para um valor "sensível"): 
+                            Uma propriedade de identificação que indica que a instancia foi novamente 
+                            instanciada (unsaved), diferenciando de instancias desconectadas que foram 
+                            salvas ou carregadas em uma sessão anterior.
+                        </para>
+                    </callout>            
+                   <callout arearefs="id5">
+                        <para>
+                            <literal>access</literal> (opcional - valor default <literal>property</literal>): A 
+                            estratégia que o Hiberante deve utilizar para acessar o valor da propriedade
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                Se o atributo <literal>name</literal> não for declarado, assume-se que a classe não tem 
+                a propriedade de identificação.
+            </para>
+            
+            <para>
+                O atributo <literal>unsaved-value</literal> não é mais necessário no Hibernate 3.
+            </para>
+
+             <para>
+                Há declaração alternativa  <literal>&lt;composite-id&gt;</literal> permite o acesso a 
+                dados legados com chaves compostas. Nós desencorajamos fortemente o seu uso por 
+                qualquer pessoa.
+            </para>
+            
+            <sect3 id="mapping-declaration-id-generator" revision="2">
+                <title>Generator</title>
+
+                <para>
+                    O elemento filho opcional <literal>&lt;generator&gt;</literal> nomeia uma classe Java 
+                    usada para gerar identificadores unicos para instancias de uma classe persistente. 
+                    Se algum parâmetro é requerido para configurar ou inicializar a instancia geradora, 
+                    eles são passados utilizando o elemento <literal>&lt;param&gt;</literal>.
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="org.hibernate.id.TableHiLoGenerator">
+                <param name="table">uid_table</param>
+                <param name="column">next_hi_value_column</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                    Todos os generators implementam a interface  <literal>org.hibernate.id.IdentifierGenerator</literal>. 
+                    Esta é uma interface bem simples; algumas aplicações podem prover sua própria implementação 
+                    esepecializada. Entretanto, o Hibernate disponibiliza um conjunto de implementações internamente. 
+                    Há nomes de atalhos para estes generators próprios:
+                    <variablelist>
+                        <varlistentry>
+                        <term><literal>increment</literal></term>
+                        <listitem>
+                            <para>
+                                gera identificadores dos tipos <literal>long</literal>, <literal>short</literal> ou
+                                <literal>int</literal> que são unicos apenas quando nenhum outro processo está 
+                                inserindo dados na mesma tabela. <emphasis>Não utilize em ambientes 
+                                de cluster.</emphasis>
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>identity</literal></term>
+                        <listitem>
+                            <para>
+                                suporta colunas de identidade em  DB2, MySQL, MS SQL Server, Sybase e 
+                                HypersonicSQL. O identificador retornado é do tipo <literal>long</literal>, 
+                                <literal>short</literal> ou <literal>int</literal>.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>sequence</literal></term>
+                        <listitem>
+                            <para>
+                                utiliza uma sequence em DB2, PostgreSQL, Oracle, SAP DB, McKoi ou um 
+                                generator no Interbase. O identificador de retorno é do tipo <literal>
+                                long</literal>, <literal>short</literal> ou <literal>int</literal>.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>hilo</literal></term>
+                        <listitem>
+                            <para id="mapping-declaration-id-hilodescription" revision="1">
+                                utiliza um algoritmo hi/lo para gerar de forma eficiente identificadores do tipo 
+                                <literal>long</literal>, <literal>short</literal> ou <literal>int</literal>,
+                                a partir de uma tabela e coluna fornecida (por default 
+                                <literal>hibernate_unique_key</literal> e <literal>next_hi</literal>) 
+                                como fonte para os valores hi. O algoritmo hi/lo gera identificadores que são 
+                                únicos apenas para um banco de dados particular. 
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>seqhilo</literal></term>
+                        <listitem>
+                            <para>
+                                utiliza um algoritmo hi/lo para gerar de forma eficinete identificadores do tipo 
+                                <literal>long</literal>, <literal>short</literal> ou <literal>int</literal>,
+                                a partir de uma sequence de banco de dados fornecida.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>uuid</literal></term>
+                        <listitem>
+                            <para>
+                                utiliza um algortimo UUID de 128-bits para gerar identificadores do 
+                                tipo string, unicos em uma rede(o endereço IP é utilizado). O UUID é 
+                                codificado como um string de digitos hexadecimais de tamanho 32.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>guid</literal></term>
+                        <listitem>
+                            <para>
+                                utiliza um string GUID gerado pelo banco de dados no MS SQL Server 
+                                e MySQL.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>native</literal></term>
+                        <listitem>
+                            <para>
+                                seleciona entre <literal>identity</literal>, <literal>sequence</literal> 
+                                ou <literal>hilo</literal> dependendo das capacidades do banco de dados 
+                                utilizado.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>assigned</literal></term>
+                        <listitem>
+                            <para>
+                                deixa a aplicação definir um identificador para o objeto antes que o 
+                                <literal>save()</literal> seja chamado. Esta é a estratégia default 
+                                se nenhum elemento <literal>&lt;generator&gt;</literal> é especificado.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>select</literal></term>
+                        <listitem>
+                            <para>
+                                retorna a chave primaria recuperada por uma trigger do banco de 
+                                dados, selecionado uma linha pela chave única e recuperando o valor 
+                                da chave primária.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>foreign</literal></term>
+                        <listitem>
+                            <para>
+                                utiliza o identificador de um outro objeto associado. Normalmente utilizado 
+                                em conjunto com uma associaçõa de chave primária do tipo
+                                <literal>&lt;one-to-one&gt;</literal>.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>sequence-identity</literal></term>
+                        <listitem>
+                            <para>
+                                a specialized sequence generation strategy which utilizes a
+                                database sequence for the actual value generation, but combines
+                                this with JDBC3 getGeneratedKeys to actually return the generated
+                                identifier value as part of the insert statement execution.  This
+                                strategy is only known to be supported on Oracle 10g drivers
+                                targetted for JDK 1.4.  Note comments on these insert statements
+                                are disabled due to a bug in the Oracle drivers.
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                    </variablelist>
+
+                </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-hilo" revision="1">
+                <title>Algoritmo Hi/lo</title>
+                <para>
+                    Os geradores <literal>hilo</literal> e <literal>seqhilo</literal> fornecem duas 
+                    implementações alternativas do algoritmo hi/lo, uma solução preferencial para a geração 
+                    de identificadores. A primeira implementação requer uma tabela especial do banco de 
+                    dados para manter o proximo valor "hi" disponível. A segunda utiliza uma seqüência 
+                    do estilo Oracle (quando suportado). 
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="hilo">
+                <param name="table">hi_value</param>
+                <param name="column">next_value</param>
+                <param name="max_lo">100</param>
+        </generator>
+</id>]]></programlisting>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="seqhilo">
+                <param name="sequence">hi_value</param>
+                <param name="max_lo">100</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                    Infelizemente, voce não pode utilizar <literal>hilo</literal> quando estiver 
+                    fornecendo sia propria  <literal>Connection</literal> para o Hibernate. Quando o 
+                    Hibernate está usando um datasource do servidor de aplicações para obter conexões 
+                    suportadas com JTA, você precisa configurar adequadamente o 
+                    <literal>hibernate.transaction.manager_lookup_class</literal>.
+                </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-uuid">
+                <title>UUID algorithm</title>
+                <para>
+                    O UUID contem: o endereço IP, hora de inicio da JVM (com precisão de um quarto 
+                    de segundo), a hora do sistema e um valor contador (unico dentro da JVM). 
+                    Não é possivel obter o endereço MAC ou um endereço de memória do código Java, 
+                    assim este é o melhor que pode ser feito sem utilizar JNI.
+                </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-sequences">
+            <title>Colunas de identidade e sequencias</title>
+                <para>
+                    Para bancos de dados que suportam colunas de identidade (DB2, MySQL, Sybase, 
+                    MS SQL), você pode utilizar uma geração de chave <literal>identity</literal>. 
+                    Para bancos de dados que suportam sequencias (DB2, Oracle, PostgreSQL, Interbase, 
+                    McKoi, SAP DB) voce pode utilizar a geração de chaves no estilo 
+                    <literal>sequence</literal>. As duas estratégias requerem duas consultas SQL 
+                    para inserir um novo objeto. 
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+        <generator class="sequence">
+                <param name="sequence">person_id_sequence</param>
+        </generator>
+</id>]]></programlisting>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id" unsaved-value="0">
+        <generator class="identity"/>
+</id>]]></programlisting>
+            
+                <para>
+                    Para desenvolvimento multi-plataforma, a estratégia <literal>native</literal> 
+                    irá escolher entre as estratégias i <literal>identity</literal>, 
+                    <literal>sequence</literal> e <literal>hilo</literal>, dependendo das 
+                    capacidades do banco de dados utilizado.
+                </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-assigned">
+                <title>Identificadores especificados</title>
+                <para>
+                    Se você quer que a aplicação especifique os identificadores 
+                    (em vez do Hibernate gerá-los) você deve utilizar o gerador 
+                    <literal>assigned</literal>. Este gerador especial irá utilizar o valor 
+                    do identificador especificado para a propriedade de identificação do objeto. 
+                    Este gerador é usado quando a chave primaria é a chave natural em vez de uma 
+                    surrogate key. Este é o comportamento padrão se você não especificar 
+                    um elemento  <literal>&lt;generator&gt;</literal>. 
+                </para>
+                
+                <para>
+                    Escolher o gerador <literal>assigned</literal> faz com que o Hibernate 
+                    utilize <literal>unsaved-value="undefined"</literal>, forçando o Hibernate 
+                    ir até o banco de dados para determinar se uma instância está transiente ou 
+                    desasociada, a menos que haja uma versão ou uma propriedade timestamp, 
+                    ou você pode definir <literal>Interceptor.isUnsaved()</literal>.
+                </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-select">
+                <title>Chaves primárias geradas por triggers</title>
+                <para>
+                    Apenas para sistemas legados (o Hibernate nao gera DDL com triggers).
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+        <generator class="select">
+                <param name="key">socialSecurityNumber</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                    No exemplo acima, há uma única propriedade com valor nomeada 
+                    <literal>socialSecurityNumber</literal>  definida pela classe, 
+                    uma chave natural, e uma surrogate key nomeada 
+                    <literal>person_id</literal> cujo valor é gerado pro uma trigger.
+                </para>
+                
+            </sect3>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-compositeid" revision="3">
+            <title>composite-id</title>
+
+            <programlisting><![CDATA[<composite-id
+        name="propertyName"
+        class="ClassName"
+        mapped="true|false"
+        access="field|property|ClassName">
+        node="element-name|."
+
+        <key-property name="propertyName" type="typename" column="column_name"/>
+        <key-many-to-one name="propertyName class="ClassName" column="column_name"/>
+        ......
+</composite-id>]]></programlisting>
+
+            <para>
+                Para tabelas com uma chave composta, você pode mapear múltiplas propriedades 
+                da classe como propriedades de identificação. O elemento 
+                <literal>&lt;composite-id&gt;</literal> aceita o mapeamento da propriedade  
+                <literal>&lt;key-property&gt;</literal> e mapeamentos 
+                <literal>&lt;key-many-to-one&gt;</literal>como elements filhos.
+            </para>
+            
+            <programlisting><![CDATA[<composite-id>
+        <key-property name="medicareNumber"/>
+        <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+            <para>
+                Sua classe persistente <emphasis>precisa</emphasis> sobre escrever 
+                <literal>equals()</literal> e <literal>hashCode()</literal> para implementar 
+                identificadores compostos igualmente. E precisa também implementar 
+                <literal>Serializable</literal>.
+            </para>
+
+            <para>
+                Infelizmente, esta solução para um identificador composto significa que um objeto 
+                persistente é seu próprio identificador. Não há outro "handle" que o próprio objeto. 
+                Você mesmo precisa instanciar uma instância de outra classe persistente e preencher 
+                suas propriedades de identificação antes que você possa dar um  <literal>load()</literal>
+                para o estado persistente associado com uma chave composta. Nos chamamos esta 
+                solução de identificador composto <emphasis>embedded</emphasis> e não aconselhamos 
+                para aplicações sérias. 
+            </para>
+            
+            <para>
+                Uma segunda solução é o que podemos chamar de identificador composto 
+                <emphasis>mapped</emphasis> quando a propriedades de identificação nomeadas dentro do 
+                elemento <literal>&lt;composite-id&gt;</literal> estão duplicadas tando na classe 
+                persistente como em uma classe de identificação separada. 
+            </para>
+                
+            <programlisting><![CDATA[<composite-id class="MedicareId" mapped="true">
+        <key-property name="medicareNumber"/>
+        <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+            <para>
+                No exemplo, ambas as classes de identificação compostas, <literal>MedicareId</literal>, 
+                e a própria classe entidade tem propriedades nomeadas <literal>medicareNumber</literal> 
+                e <literal>dependent</literal>. A classe identificadora precisa sobrepor 
+                <literal>equals()</literal> e <literal>hashCode()</literal> e implementar 
+                <literal>Serializable</literal>. A desvantagem desta solução é obvia – 
+                duplicação de código.
+            </para>
+            
+            <para>
+                Os seguintes atributos ão utilizados para especificar o mapeamento de 
+                um identificador composto:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>mapped</literal> mapped (opcional, valor default <literal>false
+                        </literal>): indica que um identificar composto mapeado é usado, e que as 
+                        propriedades de mapeamento contidas refere-se tanto a classe entidade e 
+                        a classe de identificação composta.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>class</literal> (opcional, mas requerida para um identificar composto 
+                        mapeado): A classe usada como um identificador composto. 
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Nós iremos descrever uma terceira e as vezes mais conveniente solução, onde o 
+                identificador composto é implementado como uma classe componente na 
+                <xref linkend="components-compositeid"/>. Os atributos descritos abaixo aplicam-se 
+                apenas para esta solução:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>name</literal> (opcional, requerida para esta solução): Uma 
+                        propriedade do tipo componente que armazena o identificador composto 
+                        (veja capítulo 9) 
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>access</literal> (opcional - valor default <literal>property</literal>): 
+                        A estartégia Hibernate que deve ser utilizada para acessar o valor da propriedade.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>class</literal> (opcional - valor default para o tipo de propriedade 
+                        determiando por reflexão) : A classe componente utilizada como um identificador 
+                        composto (veja a próxima sessão).
+                    </para>
+                </listitem>
+            </itemizedlist>
+            
+            <para>
+                Esta terceira solução, um <emphasis>componente de identificação</emphasis>, é o que nós 
+                recomendamos para a maioria das aplicações.
+            </para>
+            
+        </sect2>
+        
+        <sect2 id="mapping-declaration-discriminator" revision="3">
+            <title>discriminator</title>
+
+            <para>
+                O  elemento <literal>&lt;discriminator&gt;</literal> é necessário para persistência 
+                polimórfica utilizando a estratégia de mapeamento table-per-class-hierarchy e declara 
+                uma coluna discriminadora da tabela. A coluna discriminadora contem valores de marcação 
+                que dizem a camada de persistência qual subclasse instanciar para uma linha particular. 
+                Um restrito conjunto de tipos que podem ser utilizados: <literal>string</literal>, 
+                <literal>character</literal>, <literal>integer</literal>, <literal>byte</literal>, 
+                <literal>short</literal>, <literal>boolean</literal>, 
+                <literal>yes_no</literal>, <literal>true_false</literal>.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="discriminator1" coords="2 60"/>
+                    <area id="discriminator2" coords="3 60" />
+                    <area id="discriminator3" coords="4 60" />
+                    <area id="discriminator4" coords="5 60" />
+                    <area id="discriminator5" coords="6 60" />
+                </areaspec>
+                <programlisting><![CDATA[<discriminator
+        column="discriminator_column"
+        type="discriminator_type"
+        force="true|false"
+        insert="true|false"
+        formula="arbitrary sql expression"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="discriminator1">
+                        <para>
+                            <literal>column</literal> (opcional - valor default <literal>class</literal>) 
+                            o nome da coluna discriminadora
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator2">
+                        <para>
+                            <literal>type</literal> (opcional - valor default  <literal>string</literal>) 
+                            o nome que indica o tipo Hibernate
+                        </para>
+                    </callout>          
+                    <callout arearefs="discriminator3">
+                        <para>
+                            <literal>force</literal> (opcional - valor default <literal>false</literal>) 
+                            "força" o Hibernate a especificar valores discriminadores permitidos mesmo 
+                            quando recuperando todas as instancias da classe root.
+                        </para>
+                    </callout>          
+                    <callout arearefs="discriminator4">
+                        <para>
+                            <literal>insert</literal> (opcional - valor default para  <literal>true</literal>) 
+                            sete isto para <literal>false</literal> se sua coluna discriminadora é também 
+                            parte do identificador composto mapeado. (Diz ao Hibernate para não incluir a 
+                            coluna em comandos SQL <literal>INSERT</literal>s). 
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator5">
+                        <para>
+                            <literal>formula</literal> (opcional) uma expressão SQL arbitraria que é e
+                            xecutada quando um tipo tem que ser avaliado. Permite discriminação baseada 
+                            em conteúdo.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Valores atuais de uma coluna discriminada são especificados pelo atributo 
+                <literal>discriminator-value</literal> da <literal>&lt;class&gt;</literal> 
+                e elementos da <literal>&lt;subclass&gt;</literal>.
+            </para>
+            
+            <para>
+                O atributo  <literal>force</literal> é util (apenas) em tabelas contendo linhas com 
+                valores discriminadores "extras" que não estão mapeados para uma classe persistente. 
+                Este não é geralmente o caso.
+            </para>
+
+            <para>
+                Usando o atributo <literal>formula</literal> voce pode declarar uma expressão SQL 
+                arbitrária que sera utilizada para avaliar o tipo de uma linha :
+            </para>
+
+            <programlisting><![CDATA[<discriminator
+    formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
+    type="integer"/>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-version" revision="4">
+            <title>version (optional)</title>
+            
+            <para>
+                O elemento <literal>&lt;version&gt;</literal> é opcional e indica que a tabela 
+                possui dados versionados. Isto é particularmente útil se você planeja utilizar 
+                <emphasis>transações longas</emphasis> (veja abaixo):
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="version1" coords="2 70"/>
+                    <area id="version2" coords="3 70"/>
+                    <area id="version3" coords="4 70"/>
+                    <area id="version4" coords="5 70"/>
+                    <area id="version5" coords="6 70"/>
+                    <area id="version6" coords="7 70"/>
+                    <area id="version7" coords="8 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<version
+        column="version_column"
+        name="propertyName"
+        type="typename"
+        access="field|property|ClassName"
+        unsaved-value="null|negative|undefined"
+        generated="never|always"
+        insert="true|false"
+        node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="version1">
+                        <para>
+                            <literal>column</literal> (opcional - default a a propriedade name): O nome da 
+                            coluna mantendo o numero da versão 
+                        </para>
+                    </callout>          
+                    <callout arearefs="version2">
+                        <para>
+                            <literal>name</literal>: O nome da propriedade da classe persistente.
+                        </para>
+                    </callout>
+                    <callout arearefs="version3">
+                        <para>
+                            <literal>type</literal> (opcional - valor default para <literal>integer</literal>): 
+                            O tipo do numero da versão
+                        </para>
+                    </callout>          
+                   <callout arearefs="version4">
+                        <para>
+                            <literal>access</literal> (opcional - valor default <literal>property</literal>): 
+                            A estratégia Hibernate que deve ser usada para acessar o valor da propriedade.
+                        </para>
+                    </callout>
+                   <callout arearefs="version5">
+                        <para>
+                            <literal>unsaved-value</literal>  (opcional – valor default para <literal>undefined
+                            </literal>): Um valor para a propriedade versão que indica que uma instancia é 
+                            uma nova instanciada (unsaved), distinguindo de instancias desconectadas que foram 
+                            salvas ou carregadas em sessões anteriores. ((<literal>undefined</literal> especifica 
+                            que o valor da propriedade de identificação deve ser utilizado).
+                        </para>
+                    </callout>
+                    <callout arearefs="version6">
+                        <para>
+                            <literal>generated</literal> (optional - defaults to <literal>never</literal>):
+                            Specifies that this version property value is actually generated by the database.
+                            See the discussion of <xref linkend="mapping-generated">generated properties</xref>.
+                            <literal>generated</literal> (opcional - valor default <literal>never</literal>): 
+                            Especifica que valor para a propriedade versão é na verdade gerado pelo banco de 
+                            dados. Veja a discussão da Seção 
+                            <xref linkend="mapping-generated">generated properties</xref>. 
+                        </para>
+                    </callout>
+                    <callout arearefs="version7">
+                        <para>
+                            <literal>insert</literal> (opcional - valor default para <literal>true</literal>): 
+                            Especifica se a coluna de versão deve ser incluída no comando SQL de insert. 
+                            Pode ser configurado como <literal>false</literal> se a coluna do banco de dados 
+                            está definida com um valor default de <literal>0</literal>.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                Números de versão podem ser dos tipos Hibernate <literal>long</literal>, 
+                <literal>integer</literal>, <literal>short</literal>, <literal>timestamp</literal> ou
+                <literal>calendar</literal>.
+            </para>
+            
+            <para>
+                A versão de uma propriedade timestamp nunca deve ser nula para uma instancia 
+                desconectada, assim o Hibernate irá identificar qualquer instância com uma versão 
+                nula ou timestamp como transiente, não importando qual estratégia para foi 
+                especificada para <literal>unsaved-value</literal>. <emphasis>Declarando uma versão 
+                nula ou a propriedade timestamp é um caminho fácil para tratar problemas com 
+                reconexões transitivas no Hibernate, especialmente úteis para pessoas utilizando 
+                identificadores assinaldados ou chaves compostas!</emphasis>
+            </para>
+        </sect2>
+        
+        <sect2 id="mapping-declaration-timestamp" revision="4" >
+            <title>timestamp (optional)</title>
+
+            <para>
+                O elemento opcional <literal>&lt;timestamp&gt;</literal> indica que uma tabela contém 
+                dados timestamped. Isso tem por objetivo dar uma alternativa para versionamento. Timestamps 
+                são por natureza uma implementação menos segura do locking otimista. Entretanto, algumas 
+                vezes a aplicação pode usar timestamps em outros caminhos.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="timestamp1" coords="2 70"/>
+                    <area id="timestamp2" coords="3 70" />
+                    <area id="timestamp3" coords="4 70" />
+                    <area id="timestamp4" coords="5 70" />
+                    <area id="timestamp5" coords="6 70" />
+                    <area id="timestamp6" coords="7 70" />
+                </areaspec>            
+                <programlisting><![CDATA[<timestamp
+        column="timestamp_column"
+        name="propertyName"
+        access="field|property|ClassName"
+        unsaved-value="null|undefined"
+        source="vm|db"
+        generated="never|always"
+        node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="timestamp1">
+                        <para>
+                            <literal>column</literal> (opcional - valor default para a propriedade name): 
+                            O nome da coluna que mantem o timestamp.
+                        </para>
+                    </callout>                   
+                    <callout arearefs="timestamp2">
+                        <para>
+                            <literal>name</literal>: O nome da propriedade no estilo JavaBeans do 
+                            tipo <literal>Date</literal> ou <literal>Timestamp</literal> da classe 
+                            persistente Java.
+                        </para>
+                    </callout>
+                   <callout arearefs="timestamp3">
+                        <para>
+                            <literal>access</literal> (opcional - valor default para <literal>property</literal>): 
+                            A estretagia Hibernate que deve ser utilizada para acessar o valor da propriedade.
+                        </para>
+                    </callout>
+                   <callout arearefs="timestamp4">
+                        <para>
+                            <literal>unsaved-value</literal> (opcional - valor default <literal>null</literal>): 
+                            Uma propriedade para a versão de que indica que uma instância é uma nova instanciada 
+                            (unsaved), distinguindo-a de instancias desconectadas que foram salvas ou carregadas 
+                            em sessões previas. (<literal>undefined</literal> especifica que um valor de 
+                            propriedade de identificação deve ser utilizado)
+                        </para>
+                    </callout>
+                   <callout arearefs="timestamp5">
+                        <para>
+                            <literal>source</literal>  (opcional - valor default para <literal>vm</literal>): 
+                            De onde o Hibernate deve recuperar o valor timestamp? Do banco de dados ou da JVM 
+                            corrente? Timestamps baseados em banco de dados levam a um overhead porque o 
+                            Hibernate precisa acessar o banco de dados para determinar o "próximo valor", mas é 
+                            mais seguro para uso em ambientes de "cluster". Observe também, que nem todos 
+                            <literal>Dialect</literal>s suportam a recuperação do timestamp corrente do banco 
+                            de dados, enquando outros podem não ser seguros para utilização em bloqueios 
+                            pela falta de precisão (Oracle 8 por exemplo)
+                        </para>
+                    </callout>
+                    <callout arearefs="timestamp6">
+                        <para>
+                            <literal>generated</literal> (opcional - valor default <literal>never</literal>): 
+                            Especifica que o valor da propriedade timestamp é gerado pelo banco de dados. 
+                            Veja a discussão <xref linkend="mapping-generated">generated properties</xref>. 
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                Observe que <literal>&lt;timestamp&gt;</literal> é equivalente a  
+                <literal>&lt;version type="timestamp"&gt;</literal>. E 
+                <literal>&lt;timestamp source="db"&gt;</literal> é equivalente a 
+                <literal>&lt;version type="dbtimestamp"&gt;</literal>.
+            </para>
+        </sect2>
+
+
+        <sect2 id="mapping-declaration-property" revision="4">
+            <title>property</title>
+
+            <para>
+                O elemento <literal>&lt;property&gt;</literal> declara uma propriedade 
+                persistente de uma classe, no estilo JavaBean. 
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="property1" coords="2 70"/>
+                    <area id="property2" coords="3 70"/>
+                    <area id="property3" coords="4 70"/>
+                    <areaset id="property4-5" coords="">
+                        <area id="property4" coords='5 70'/>
+                        <area id="property5" coords='6 70'/>
+                    </areaset>
+                    <area id="property6" coords="7 70"/>
+                    <area id="property7" coords="8 70"/>
+                    <area id="property8" coords="9 70"/>
+                    <area id="property9" coords="10 70"/>
+                    <area id="property10" coords="11 70"/>
+                    <area id="property11" coords="12 70"/>
+                    <area id="property12" coords="13 70"/>
+                </areaspec>            
+                <programlisting><![CDATA[<property
+        name="propertyName"
+        column="column_name"
+        type="typename"
+        update="true|false"
+        insert="true|false"
+        formula="arbitrary SQL expression"
+        access="field|property|ClassName"
+        lazy="true|false"
+        unique="true|false"
+        not-null="true|false"
+        optimistic-lock="true|false"
+        generated="never|insert|always"
+        node="element-name|@attribute-name|element/@attribute|."
+        index="index_name"
+        unique_key="unique_key_id"
+        length="L"
+        precision="P"
+        scale="S"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="property1">
+                        <para>
+                            <literal>name</literal>: o nome da propriedade, iniciando com letra minúscula.
+                        </para>
+                    </callout>                   
+                    <callout arearefs="property2">
+                        <para>
+                            <literal>column</literal> (opcional - default para a propriedade name): o nome 
+                            da coluna mapeada do banco de dados, Isto pode também ser especificado pelo(s) 
+                            elemento(s) <literal>&lt;column&gt;</literal> aninhados.
+
+                        </para>
+                    </callout>
+                    <callout arearefs="property3">
+                        <para>
+                            <literal>type</literal> (opcional): um nome que indica o tipo Hibernate.
+                        </para>
+                    </callout>
+                    <callout arearefs="property4-5">
+                        <para>
+                            <literal>update, insert</literal> (opcional - valor default <literal>true</literal>):
+                            especifica que as colunas mapeadas devem ser incluidas nas instruções SQL de 
+                            <literal>UPDATE</literal> e/ou <literal>INSERT</literal> . Setar ambas para to 
+                            <literal>false</literal> permite uma propridade "derivada" pura cujo valor é 
+                            inicializado de outra propriedade que mapeie a mesma coluna(s) ou por uma trigger 
+                            ou outra aplicação.
+                        </para>
+                    </callout>
+                    <callout arearefs="property6">
+                        <para>
+                            <literal>formula</literal>  (opcional): uma expressão SQL que definie o valor para 
+                            uma propriedade <emphasis>calculada</emphasis>. Propriedades calculadas nao tem 
+                            uma coluna de mapeamento para elas.
+                        </para>
+                    </callout>
+                    <callout arearefs="property7">
+                        <para>
+                            <literal>access</literal> (opcional – valor default <literal>property</literal>): 
+                            A estratégia que o Hibernate deve utilizar para acessar o valor da propriedade
+                        </para>
+                    </callout>
+                    <callout arearefs="property8">
+                        <para>
+                            <literal>lazy</literal> (opcional - valor default para <literal>false</literal>): 
+                            Especifica que esta propriedade deve ser trazida de forma "lazy" quando a 
+                            instancia da variável é acessada pela primeira vez (requer instrumentação 
+                            bytecode em tempo de criação).
+                        </para>
+                    </callout>
+                    <callout arearefs="property9">
+                        <para>
+                            <literal>unique</literal> (opcional): Habilita a geração de DDL de uma 
+                            unica constraint para as colunas. Assim, permite que isto seja o 
+                            alvo de uma <literal>property-ref</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="property10">
+                        <para>
+                            <literal>not-null</literal> (opcional): Habilita a geração de DDL de uma 
+                            constraint de nulidade para as colunas.
+                        </para>
+                    </callout>
+                    <callout arearefs="property11">
+                        <para>
+                            <literal>optimistic-lock</literal> (opcional - valor default <literal>true</literal>):
+                            Especifica se mudanças para esta propriedade requerem ou não bloqueio otimista. 
+                            Em outras palavras, determina se um incremento de versão deve ocorrer quando 
+                            esta propriedade está suja.
+                        </para>
+                    </callout>
+                    <callout arearefs="property12">
+                        <para>
+                            <literal>generated</literal> (opcional - valor default <literal>never</literal>): 
+                            Especifica que o valor da propriedade é na verdade gerado pelo banco de dados.
+                            Veja a discussão da seção 
+                            <xref linkend="mapping-generated">generated properties</xref>.
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                <emphasis>typename</emphasis> pode ser:
+            </para>
+
+            <orderedlist spacing="compact">
+                <listitem>
+                    <para>
+                        The name of a Hibernate basic type (eg. <literal>integer, string, character,
+                        date, timestamp, float, binary, serializable, object, blob</literal>).
+                        O nome do tipo basico do Hibernate (ex., <literal>integer, string, character,
+                        date, timestamp, float, binary, serializable, object, blob</literal>).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        O nome da classe Java com um tipo básico default (ex.  <literal>int, float,
+                        char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob</literal>).
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        O nome da classe Java serializable
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        O nome da classe de um tipo customizado (ex. <literal>com.illflow.type.MyCustomType</literal>).
+                    </para>
+                </listitem>
+            </orderedlist>
+
+            <para>
+                Se você não especificar um tipo, o Hibernate ira utilizar reflexão sobre  a 
+                propriedade nomeada para ter uma idéia do tipo Hibernate correto. O Hibernate ira 
+                tentar interpretar o nome da classe retornada, usando as regras 2, 3 e 4 nesta ordem. 
+                Entretanto, isto não é sempre suficiente Em certos casos, você ainda irá necessitar
+                do atributo <literal>type</literal>. (Por exemplo, para distinguir entre 
+                <literal>Hibernate.DATE</literal> ou <literal>Hibernate.TIMESTAMP</literal>, 
+                ou para espcificar uma tipo ciustomizado.)
+            </para>
+            
+            <para>
+                O atributo <literal>access</literal> permite voce controlar como o Hibernate irá 
+                acessar a propriedade em tempo de execução. Por default, o Hibernate irá chamar os 
+                métodos get/set da propriedades. Se voce especificar <literal>access="field"</literal>, 
+                o Hibernate ira bipassar os metodos get/set, acessnado o campo diretamente, 
+                usando reflexão. Voc epode especificar sua própria estratégia para acesso da 
+                propriedade criando uma classe que implemente a interface 
+                <literal>org.hibernate.property.PropertyAccessor</literal>.
+            </para>
+
+            <para>
+                Um recurso especialmente poderoso é o de propriedades derivadas. Estas propriedades 
+                são por definição read-only, e o valor da propriedade é calculado em tempo de execução. 
+                Você declara este calculo como uma expressão SQL, que traduz para clausula 
+                <literal>SELECT</literal> de uma subquery daquery SQL que carrega a instancia: 
+            </para>
+
+        <programlisting><![CDATA[
+<property name="totalPrice"
+    formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p
+                WHERE li.productId = p.productId
+                AND li.customerId = customerId
+                AND li.orderNumber = orderNumber )"/>]]></programlisting>
+
+            <para>
+                Observe que você pode referenciar as entidades da própria tabela, 
+                através da não declaração de um alias para uma coluna particular (
+                <literal>customerId</literal> no exemplo dado). Observe tambem que voce pode usar o 
+                mapeamento de elemento aninhado <literal>&lt;formula&gt;</literal>, se você não 
+                gostar de usar o atributo.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-manytoone" revision="5">
+            <title>many-to-one</title>
+
+            <para>
+                Uma associação ordinária para outra classe persistente é declarada usando o 
+                elemento <literal>many-to-one</literal>. O modelo relacional é uma 
+                associação many-to-one: a uma chave estrangeira de uma tabela referenciando
+                a chave primaria da tabela destino.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="manytoone1" coords="2 70"/>
+                    <area id="manytoone2" coords="3 70"/>
+                    <area id="manytoone3" coords="4 70"/>
+                    <area id="manytoone4" coords="5 70"/>
+                    <area id="manytoone5" coords="6 70"/>
+                    <areaset id="manytoone6-7" coords="">
+                        <area id="manytoone6" coords='7 70'/>
+                        <area id="manytoone7" coords='8 70'/>
+                    </areaset>
+                    <area id="manytoone8" coords="9 70"/>
+                    <area id="manytoone9" coords="10 70"/>
+                    <area id="manytoone10" coords="11 70"/>
+                    <area id="manytoone11" coords="12 70"/>
+                    <area id="manytoone12" coords="13 70"/>
+                    <area id="manytoone13" coords="14 70"/>
+                    <area id="manytoone14" coords="15 70"/>
+                    <area id="manytoone15" coords="16 70"/>
+                    <area id="manytoone16" coords="17 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<many-to-one
+        name="propertyName"
+        column="column_name"
+        class="ClassName"
+        cascade="cascade_style"
+        fetch="join|select"
+        update="true|false"
+        insert="true|false"
+        property-ref="propertyNameFromAssociatedClass"
+        access="field|property|ClassName"
+        unique="true|false"
+        not-null="true|false"
+        optimistic-lock="true|false"
+        lazy="proxy|no-proxy|false"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        formula="arbitrary SQL expression"
+        node="element-name|@attribute-name|element/@attribute|."
+        embed-xml="true|false"
+        index="index_name"
+        unique_key="unique_key_id"
+        foreign-key="foreign_key_name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="manytoone1">
+                        <para>
+                            <literal>name</literal>: O nome da propriedade.
+                        </para>                    
+                    </callout>                   
+                    <callout arearefs="manytoone2">
+                        <para>
+                            <literal>column</literal> (opcional): O nome da coluna foreign key. Isto 
+                            pode também ser especificado através de elementos aninhados 
+                            <literal>&lt;column&gt;</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone3">
+                        <para>
+                            <literal>class</literal> (opcional – default para o tipo de propriedade 
+                            determinado pela reflexão). O nome da classe associada. 
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone4">
+                        <para>
+                            <literal>cascade</literal> (opcional): Especifica quais operações dever 
+                            ser em cascata do objeto pai para o objeto associado. 
+                        </para>                    
+                    </callout>
+                    <callout arearefs="manytoone5">
+                        <para>
+                            <literal>fetch</literal> (opcional - default para <literal>select</literal>): 
+                            Escolhe entre recuperação outer-join ou recuperação seqüencial.
+                         </para>                    
+                    </callout>
+                    <callout arearefs="manytoone6-7">
+                        <para>
+                            <literal>update, insert</literal> (opcional - valor default <literal>true</literal>):
+                            especifica que as colunas mapeadas dever ser incluidas em instruções SQL de 
+                            <literal>UPDATE</literal> e/ou <literal>INSERT</literal>. Setando ambas para 
+                            <literal>false</literal> você permite uma associação "derivada" pura cujos valores 
+                            são inicializados de algumas outras propriedades que mapeiam a mesma coluna ou 
+                            por uma trigger ou outra aplicação. 
+                         </para>                    
+                    </callout>
+                    <callout arearefs="manytoone8">
+                        <para>
+                            <literal>property-ref</literal>: (opcional) O nome da propriedade da classe associada 
+                            que faz a junção desta foreign key. Se não especificada, a chave primaria da 
+                            classe associada será utilizada. 
+                         </para>                
+                    </callout>                   
+                    <callout arearefs="manytoone9">
+                        <para>
+                            <literal>access</literal> (opcional - valor default <literal>property</literal>): A 
+                            estrategia que o Hibernate deve utilizar para acessar o valor da propriedade.
+                         </para>
+                    </callout>
+                    <callout arearefs="manytoone10">
+                        <para>
+                            <literal>unique</literal> (opcional): Habilita a geração DDL de uma constraint 
+                            unique para a coluna foreign-key. Alem disso, permite ser o alvo de uma 
+                            <literal>property-ref</literal>. Isso torna a associação multipla 
+                            efetivamente um para um. 
+                         </para>
+                    </callout>
+                    <callout arearefs="manytoone11">
+                        <para>
+                            <literal>not-null</literal> (opcional): Habilita a geração DDL de uma constraint de 
+                            nulidade para as foreign keys.
+                         </para>
+                    </callout>
+                    <callout arearefs="manytoone12">
+                        <para>
+                            <literal>optimistic-lock</literal> (opcional - valor default <literal>true</literal>): 
+                            Especifica se mudanças desta propriedade requerem ou não travamento otimista. 
+                            Em outras palavras, determina se um incremento de versão deve ocorrer quando 
+                            esta propriedade está suja.
+                         </para>
+                    </callout>
+                    <callout arearefs="manytoone13">
+                        <para>
+                            <literal>lazy</literal>(opcional – valor default  <literal>proxy</literal>): 
+                            Por default, associações de ponto unico são envoltas em um proxie. 
+                            <literal>lazy="no-proxy"</literal> especifica que a propriedade deve ser 
+                            trazida de forma tardia quando a instancia da variável é acessada pela 
+                            primeira vez (requer instrumentação bytecode em tempo de criação) 
+                            <literal>lazy="false"</literal> especifica que a associação será 
+                            sempre recuperada fortemente. 
+                         </para>
+                    </callout>
+                    <callout arearefs="manytoone14">
+                        <para>
+                            <literal>not-found</literal> (opcional - valor default <literal>exception</literal>): 
+                            Especifica como as foreign keys que referenciam linhas ausentes serão tratadas:
+                            <literal>ignore</literal> irá tratar a linha ausente como ama associaççao de null
+                         </para>
+                    </callout>
+                    <callout arearefs="manytoone15">
+                        <para>
+                            <literal>entity-name</literal> (opcional): O nome da entidade da classe associada. 
+                         </para>                   
+                    </callout>
+                </calloutlist>
+                    <callout arearefs="manytoone16">
+                        <para>
+                            <literal>formula</literal> (optional): Uma expressão SQL que define um valor
+                            para um foreign key <emphasis>computed</emphasis>.
+                        </para>
+                    </callout>
+            </programlistingco>
+
+            <para>
+                Setar o valor do atributo  <literal>cascade</literal> para qualquer valor 
+                significativo diferente de  <literal>none</literal> irá propagar certas operações 
+                ao objeto associado. Os valores significativos são os nomes das operações básicas 
+                do Hibernate, <literal>persist, merge, delete, save-update, evict, replicate, lock,
+                refresh</literal>, assim como os valores especiais  <literal>delete-orphan</literal> 
+                e <literal>all</literal> e combinações de nomes de operações separadas por vírgula, 
+                como por exemplo, <literal>cascade="persist,merge,evict"</literal> ou
+                <literal>cascade="all,delete-orphan"</literal>. Veja a seção 
+                <xref linkend="objectstate-transitive"/> para uma explicação completa. Note que 
+                associações valoradas simples (associações muitos-pra-um, e um-pra-um) não suportam 
+                orphan delete.
+            </para>
+            
+            <para>
+                Uma típica declaração <literal>muitos-pra-um</literal> se parece com esta:
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="product" class="Product" column="PRODUCT_ID"/>]]></programlisting>
+            
+            <para>
+                O atributo <literal>property-ref</literal> deve apenas ser usado para mapear dados 
+                legados onde uma chave estrangeira se referencia a uma chave exclusiva da tabela 
+                associada que não seja à chave primária. Este é um modelo relacional desagradável. 
+                Por exemplo, suponha que a classe  <literal>Product</literal> tenha um número 
+                seqüencial exclusivo, que não é a chave primária. (O atributo <literal>unique</literal> 
+                controla a geração de DDL do Hibernate com a ferramenta SchemaExport.)
+            </para>
+            
+            <programlisting><![CDATA[<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>]]></programlisting>
+            
+            <para>
+                Então o mapeamento para <literal>OrderItem</literal> poderia usar:
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>]]></programlisting>
+            
+            <para>
+                Porém, isto obviamente não é indicado, nunca.
+            </para>
+            
+            <para>
+                Se a chave exclusiva referenciada engloba múltiplas propriedades da entidade associada, 
+                você deve mapear as propriedades referenciadas dentro de um elemento chamado 
+                <literal>&lt;properties&gt;</literal>
+
+            </para>
+            
+            <para>
+            	Se a chave exclusiva referenciada é a propriedade de um componente, você pode especificar 
+            	um caminho para a propriedade. 
+            </para>
+            
+           <programlisting><![CDATA[<many-to-one name="owner" property-ref="identity.ssn" column="OWNER_SSN"/>]]></programlisting>           
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-onetoone" revision="3">
+            <title>one-to-one (um-pra-um)</title>
+
+            <para>
+                Uma associação um-pra-um para outra classe persistente é declarada usando 
+                um elemento <literal>one-to-one </literal>.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="onetoone1" coords="2 70"/>
+                    <area id="onetoone2" coords="3 70"/>
+                    <area id="onetoone3" coords="4 70"/>
+                    <area id="onetoone4" coords="5 70"/>
+                    <area id="onetoone5" coords="6 70"/>
+                    <area id="onetoone6" coords="7 70"/>
+                    <area id="onetoone7" coords="8 70"/>
+                    <area id="onetoone8" coords="9 70"/>
+                    <area id="onetoone9" coords="10 70"/>
+                    <area id="onetoone10" coords="11 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<one-to-one
+        name="propertyName"
+        class="ClassName"
+        cascade="cascade_style"
+        constrained="true|false"
+        fetch="join|select"
+        property-ref="propertyNameFromAssociatedClass"
+        access="field|property|ClassName"
+        formula="any SQL expression"
+        lazy="proxy|no-proxy|false"
+        entity-name="EntityName"
+        node="element-name|@attribute-name|element/@attribute|."
+        embed-xml="true|false"
+        foreign-key="foreign_key_name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="onetoone1">
+                        <para>
+                            <literal>name</literal>: O nome da propriedade.
+                        </para>                
+                    </callout>                   
+                    <callout arearefs="onetoone2">
+                        <para>
+                            <literal>class</literal> (opcional – default para o tipo da propriedade 
+                            definido via reflection): O nome da classe associada.
+                         </para>                   
+                    </callout>
+                    <callout arearefs="onetoone3">
+                        <para>
+                            <literal>cascade</literal> (opcional): Especifica qual operação deve 
+                            ser cascateada do objeto pai para o objeto associado.
+                         </para>
+                    </callout>
+                    <callout arearefs="onetoone4">
+                        <para>
+                            <literal>constrained</literal> (opcional): Especifica que uma chave estrangeira 
+                            constraint na chave primária da tabela mapeada referencia a tabela da classe 
+                            associada, Esta opção afeta a ordem em queh <literal>save()</literal> e
+                            <literal>delete()</literal> são cascateadas, e determina se a associação 
+                            pode ser substituída (isto também é usado pela ferramenta schema export).
+                         </para>                  
+                    </callout>
+                    <callout arearefs="onetoone5">
+                        <para>
+                            <literal>fetch</literal> ((opcional – valor default <literal>select</literal>): 
+                            Escolhe entre outer-join fetching ou sequential select fetching.
+                         </para>              
+                    </callout>
+                    <callout arearefs="onetoone6">
+                        <para>
+                            <literal>property-ref</literal>(opcional): O nome da propriedade da classe associada 
+                            que é ligada a chave primária desta classe. Se não for especificada, a chave primária 
+                            da classe associada é utilizada.
+                         </para>                
+                    </callout>                   
+                    <callout arearefs="onetoone7">
+                        <para>
+                            <literal>access</literal> (opcional - valor default padrão <literal>property</literal>): 
+                            A estratégia que o Hibernate pode usar para acessar o valor da propriedade.
+                         </para>
+                    </callout>
+                    <callout arearefs="onetoone8">
+                        <para>
+                            <literal>formula</literal> (opcional): Quase todas associações um-pra-um mapeiam 
+                            para a chave primária da entidade dona. No caso raro, que não é o caso, você 
+                            pode especificar uma outra coluna, colunas ou expressões para juntar utilizando 
+                            uma formula SQL. (Veja <literal>org.hibernate.test.onetooneformula</literal> 
+                            para exemplo).
+                         </para>
+                    </callout>
+                    <callout arearefs="onetoone9">
+                        <para>
+                            <literal>lazy</literal> (opcional – valor default <literal>proxy</literal>): 
+                            Por default, associações single point são proxied. <literal>lazy="no-proxy"</literal> 
+                            especifica que a propriedade deve ser fetched lazily quando o atributo é acessado 
+                            pela primeira vez (requer build-time bytecode instrumentation). 
+                            <literal>lazy="false"</literal> especifica que a associação vai sempre ser 
+                            avidamente fetched. <emphasis>Note que se <literal>constrained="false"</literal>, 
+                            proxing é impossível e o Hibernate vai ávido fetch a associação!</emphasis>
+                         </para>
+                    </callout>
+                    <callout arearefs="onetoone10">
+                        <para>
+                            <literal>entity-name</literal> (opcional): O nome da entidade da classe associada.
+                         </para>                   
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+        
+            <para>
+                Existem duas variedades de associações um-pra-um:
+            </para>
+            <itemizedlist>
+            <listitem><para>
+                associações de chave primária
+            </para></listitem>
+            <listitem><para>
+                associações de chave estrangeira exclusiva
+            </para></listitem>
+            </itemizedlist>
+            
+            <para>
+                Associações de chave primária não necessitam de uma coluna extra de tabela; se duas 
+                linhas são relacionadas pela associação então as duas linhas da tabela dividem a mesmo 
+                valor da chave primária. Assim, se você quer que dois objetos sejam relacionados por 
+                uma associação de chave primária, você deve ter certeza que eles são assinados com o 
+                mesmo valor identificador!
+            </para>
+            
+            <para>
+                Para uma associação de chave primária, adicione os seguintes mapeamentos em 
+                <literal>Employee</literal> e <literal>Person</literal>, respectivamente.
+            </para>
+
+            <programlisting><![CDATA[<one-to-one name="person" class="Person"/>]]></programlisting>
+            <programlisting><![CDATA[<one-to-one name="employee" class="Employee" constrained="true"/>]]></programlisting>
+
+            <para>
+                Agora nós devemos assegurar que as chaves primárias de linhas relacionadas nas 
+                tabelas PERSON e EMPLOYEE são iguais. Nós usamos uma estratégia especial de geração 
+                de identificador do Hibernate chamada <literal>foreign</literal>:
+            </para>
+
+            <programlisting><![CDATA[<class name="person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="foreign">
+            <param name="property">employee</param>
+        </generator>
+    </id>
+    ...
+    <one-to-one name="employee"
+        class="Employee"
+        constrained="true"/>
+</class>]]></programlisting>
+
+            <para>
+                Uma nova instância de <literal>Person</literal> salva recentemente é então assinada 
+                com o mesmo valor da chave primária da instância de <literal>employee</literal> referenciada 
+                com a propriedade <literal>employee</literal> daquela <literal>Person</literal>.
+            </para>
+
+            <para>
+                Alternativamente, uma chave estrangeira com uma unique constraint, de 
+                <literal>Employee</literal> para <literal>Person</literal>, pode ser expressa como:
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/>]]></programlisting>
+            
+            <para>
+                E esta associação pode ser feita de forma bi-direcional adicionando o seguinte 
+                no mapeamento de <literal>Person</literal>:
+            </para>
+            
+           <programlisting><![CDATA[<one-to-one name"employee" class="Employee" property-ref="person"/>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-naturalid">
+            <title>natural-id</title>
+
+            <programlisting><![CDATA[<natural-id mutable="true|false"/>
+        <property ... />
+        <many-to-one ... />
+        ......
+</natural-id>]]></programlisting>
+
+            <para>
+                Embora nós recomendemos o uso de surrogate keys como chaves primárias, você deve 
+                ainda identificar chaves naturais para todas as entidades. Uma chave natural é 
+                uma propriedade ou combinação de propriedades que é exclusiva e não nula. Se não 
+                pude ser modificada, melhor ainda. Mapeie as propriedades da chave natural dentro do 
+                elemento <literal>&lt;natural-id&gt;</literal>. O Hibernate irá gerar a chave 
+                exclusiva necessária e as constraints de nullability , e seu mapeamento será 
+                apropriadamente auto documentado.
+            </para>
+            
+            <para>
+                Nós recomendamos com enfase que você implemente <literal>equals()</literal> e 
+                <literal>hashCode()</literal> para comparar as propriedades da chave natural da 
+                entidade.
+            </para>
+
+            <para>
+                Este mapeamento não tem o objetivo de uso com entidades com natural chaves primárias.
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>mutable</literal>  mutable (opcional, valor default<literal>false</literal>): 
+                        Por default, propriedades naturais identificadoras são consideradas imutáveis (constante).
+                    </para>
+                </listitem>
+            </itemizedlist>
+            
+        </sect2>
+        
+        <sect2 id="mapping-declaration-component" revision="2">
+            <title>componente, componente dinâmico</title>
+
+            <para>
+                O elemento<literal>&lt;component&gt;</literal> mapeia propriedades de um 
+                objeto filho para colunas da tabela de uma classe pai. Componentes podem, 
+                um após o outro, declarar suas próprias propriedades, componentes ou coleções. 
+                Veja "Components" abaixo.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="component1" coords="2 45"/>
+                    <area id="component2" coords="3 45"/>
+                    <area id="component3" coords="4 45"/>
+                    <area id="component4" coords="5 45"/>
+                    <area id="component5" coords="6 45"/>
+                    <area id="component6" coords="7 45"/>
+                    <area id="component7" coords="8 45"/>
+                    <area id="component8" coords="9 45"/>
+                </areaspec>            
+                <programlisting><![CDATA[<component 
+        name="propertyName" 
+        class="className"
+        insert="true|false"
+        update="true|false"
+        access="field|property|ClassName"
+        lazy="true|false"
+        optimistic-lock="true|false"
+        unique="true|false"
+        node="element-name|."
+>
+        
+        <property ...../>
+        <many-to-one .... />
+        ........
+</component>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="component1">
+                        <para>
+                            <literal>name</literal>: O nome da propriedade.
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="component2">
+                        <para>
+                            <literal>class</literal> (opcional – valor default para o tipo de 
+                            propriedade determinada por reflection): O nome da classe (filha) do 
+                            componente.
+                         </para>                 
+                    </callout>
+                    <callout arearefs="component3">
+                        <para>
+                            <literal>insert</literal>: As colunas mapeadas aparecem nos 
+                            SQL de <literal>INSERT</literal>s?
+                         </para>               
+                    </callout>                   
+                    <callout arearefs="component4">
+                        <para>
+                            <literal>update</literal>: As colunas mapeadas aparecem nos 
+                            SQL de <literal>UPDATE</literal>s?
+                         </para>               
+                    </callout>                   
+                    <callout arearefs="component5">
+                        <para>
+                            <literal>access</literal> (opcional – valor default <literal>property</literal>): 
+                            A estratégia que o Hibernate pode usar para acessar o valor da propriedade.
+                         </para>
+                    </callout>
+                   <callout arearefs="component6">
+                        <para>
+                            <literal>lazy</literal> (opcional - valor default <literal>false</literal>): 
+                            Especifica que este componente deve ser fetched lazily quando o atributo for 
+                            acessado pela primeira vez (requer build-time bytecode instrumentation).
+                         </para>
+                    </callout>
+                    <callout arearefs="component7">
+                            <para>
+                                <literal>optimistic-lock</literal> (opcional – valor default <literal>true</literal>): 
+                                Especifica que atualizações para este componente requerem ou não aquisição 
+                                de um lock otimista. Em outras palavras, determina se uma versão de incremento deve 
+                                ocorrer quando esta propriedade estiver modificada.
+                             </para>
+                    </callout>
+                    <callout arearefs="component8">
+                            <para>
+                                <literal>unique</literal> (opcional – valor default <literal>false</literal>): 
+                                Especifica que existe uma unique constraint em todas as colunas mapeadas do 
+                                componente.
+                             </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                A tag filha <literal>&lt;property&gt;</literal> acrescenta a propriedade
+                de mapeamento da classe filha para colunas de uma tabela.
+            </para>
+
+            <para>
+                O elemento <literal>&lt;component&gt;</literal> permite um sub-elemento 
+                <literal>&lt;parent&gt;</literal> mapeie uma propriedade da classe do componente 
+                como uma referencia de volta para a entidade que o contém.
+            </para>
+
+            <para>
+                O elemento  <literal>&lt;dynamic-component&gt;</literal> permite que um 
+                <literal>Map</literal> possa ser mapeado como um componente onde os nomes das 
+                propriedades referem-se para as chaves no mapa, veja 
+                <xref linkend="components-dynamic"/>.
+            </para>
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-properties" revision="2">
+            <title>propriedades</title>
+
+            <para>
+                O elemento <literal>&lt;properties&gt;</literal> permite a definição de um grupo 
+                com nome, lógico de propriedades de uma classe. O uso mais importante do construtor 
+                é que este permite uma combinação de propriedades para ser o objetivo de uma 
+                <literal>property-ref</literal>. É também um modo conveninente para definir uma 
+                unique constraint de múltiplas colunas.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="properties1" coords="2 45"/>
+                    <area id="properties2" coords="3 45"/>
+                    <area id="properties3" coords="4 45"/>
+                    <area id="properties4" coords="5 45"/>
+                    <area id="properties5" coords="6 45"/>
+                </areaspec>            
+                <programlisting><![CDATA[<properties 
+        name="logicalName" 
+        insert="true|false"
+        update="true|false"
+        optimistic-lock="true|false"
+        unique="true|false"
+>
+        
+        <property ...../>
+        <many-to-one .... />
+        ........
+</properties>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="properties1">
+                        <para>
+                            <literal>name</literal>:: O nome lógico do agrupamento – 
+                            <emphasis>não </emphasis> é o nome atual de propriedade.
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="properties2">
+                        <para>
+                            <literal>insert</literal>: As colunas mapeadas aparecem nos 
+                            SQL de <literal>INSERT</literal>s?
+                         </para>               
+                    </callout>                   
+                    <callout arearefs="properties3">
+                        <para>
+                            <literal>update</literal>: As colunas mapeadas aparecem nos 
+                            SQL de <literal>UPDATE</literal>s?
+                         </para>               
+                    </callout>                   
+                    <callout arearefs="properties4">
+                            <para>
+                                <literal>optimistic-lock</literal> (opcional – valor default <literal>true</literal>): 
+                                Especifica que atualizações para estes componentes requerem ou não aquisição de um
+                                lock otimista. Em outras palavras, determina se uma versão de incremento deve ocorrer 
+                                quando estas propriedades estiverem modificadas.
+                             </para>
+                    </callout>
+                    <callout arearefs="properties5">
+                            <para>
+                                <literal>unique</literal> (opcional – valor defautl <literal>false</literal>): 
+                                Especifica que uma unique constraint existe em todas as colunas mapeadas do componente.
+                            </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                Por exemplo, se nós temos o seguinte mapeamento de <literal>&lt;properties&gt;</literal>:
+            </para>
+            
+            <programlisting><![CDATA[<class name="Person">
+    <id name="personNumber"/>
+    ...
+    <properties name="name" 
+            unique="true" update="false">
+        <property name="firstName"/>
+        <property name="initial"/>
+        <property name="lastName"/>
+    </properties>
+</class>]]></programlisting>
+
+            <para>
+                Então nós podemos ter uma  associação de dados herdados que referem a esta chave 
+                exclusiva da tabela <literal>Person</literal>, ao invés de se referirem a chave 
+                primária:
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="person" 
+         class="Person" property-ref="name">
+    <column name="firstName"/>
+    <column name="initial"/>
+    <column name="lastName"/>
+</many-to-one>]]></programlisting>
+            
+            <para>
+                Nós não recomendamos o uso deste tipo de coisa fora do contexto de mapeamento de 
+                dados herdados.
+            </para>
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-subclass" revision="4">
+            <title>subclass (subclasse)</title>
+
+            <para>
+                Finalmente, a persistência polimórfica requer a declaração de cada subclasse 
+                da classe de persistência raiz. Para a estratégia de mapeamento 
+                table-per-class-hierarchy, a declaração <literal>&lt;subclass&gt;</literal>
+                deve ser usada.                
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="subclass1" coords="2 55"/>
+                    <area id="subclass2" coords="3 55"/>
+                    <area id="subclass3" coords="4 55"/>
+                    <area id="subclass4" coords="5 55"/>
+                </areaspec>
+                <programlisting><![CDATA[<subclass
+        name="ClassName"
+        discriminator-value="discriminator_value"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        entity-name="EntityName"
+        node="element-name"
+        extends="SuperclassName">
+
+        <property .... />
+        .....
+</subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="subclass1">
+                        <para>
+                            <literal>name</literal>:  O nome de classe completamente qualificada da subclasse.                            
+                        </para>              
+                    </callout>                   
+                    <callout arearefs="subclass2">
+                        <para>
+                            <literal>discriminator-value</literal> (opcional – valor default o nome da classe): 
+                            Um valor que distingue subclasses individuais.
+                        </para>               
+                    </callout>
+                    <callout arearefs="subclass3">
+                        <para>
+                            <literal>proxy</literal> (opcional): Especifica a classe ou interface que 
+                            usará os proxies de inicialização atrasada.
+                        </para>               
+                    </callout>
+                    <callout arearefs="subclass4">
+                        <para>
+                            <literal>lazy</literal> (opcional, valor default <literal>true</literal>): 
+                            Configurar <literal>lazy="false"</literal> desabilitará o uso de 
+                            inicialização atrasada.
+                        </para>
+                    </callout>    
+                </calloutlist>
+            </programlistingco>
+            <para>
+                Cada subclasse deve declarar suas próprias propriedades persistentes e subclasses. 
+                As propriedades <literal>&lt;version&gt;</literal> e <literal>&lt;id&gt;</literal>  
+                são configuradas para serem herdades da classe raiz. Cada subclasse numa hierarquia 
+                deve definir um único <literal>discriminator-value</literal>. Se nenhum for 
+                especificado, o nome da classe Java completamente qualificada será usada.
+            </para>
+            
+            <para>
+                Para informações sobre mapeamento de heranças, veja o <xref linkend="inheritance"/>.
+            </para>
+
+        </sect2>
+
+         <sect2 id="mapping-declaration-joinedsubclass" revision="3">
+            <title>joined-subclass</title>
+
+            <para>
+                Alternativamente, cada subclasse pode ser mapeada para sua própria tabela 
+                (Estratégia de mapeamento table-per-subclass). O estado herdado é devolvido 
+                por associação com a tabela da superclasse. Nós usamos o elemento 
+                <literal>&lt;joined-subclass&gt;</literal>.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="joinedsubclass1" coords="2 45"/>
+                    <area id="joinedsubclass2" coords="3 45"/>
+                    <area id="joinedsubclass3" coords="4 45"/>
+                    <area id="joinedsubclass4" coords="5 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<joined-subclass
+        name="ClassName"
+        table="tablename"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        schema="schema"
+        catalog="catalog"
+        extends="SuperclassName"
+        persister="ClassName"
+        subselect="SQL expression"
+        entity-name="EntityName"
+        node="element-name">
+
+        <key .... >
+
+        <property .... />
+        .....
+</joined-subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="joinedsubclass1">
+                        <para>
+                            <literal>name</literal>: O nome da classe completamente qualificada da 
+                            subclasse.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="joinedsubclass2">
+                        <para>
+                            <literal>table</literal>: O nome da tabela da subclasse.
+                         </para>            
+                    </callout>                   
+                    <callout arearefs="joinedsubclass3">
+                        <para>
+                            <literal>proxy</literal> (opcional): Especifica a classe ou interface 
+                            para usar os proxies de recuperação atrasada.
+                         </para>              
+                    </callout>
+                    <callout arearefs="joinedsubclass4">
+                        <para>
+                            <literal>lazy</literal> (opcional, valor default <literal>true</literal>): 
+                            Fixanr <literal>lazy="false"</literal> desabilita o uso recuperação 
+                            atrasada.
+                          </para>
+                    </callout>    
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                A coluna discriminator requerida para esta estratégia de mapeamento. Porém, 
+                cada subclasse deve declarar uma coluna de tabela com o identificador do objeto 
+                usando o elemento <literal>&lt;key&gt;</literal>. O mapeamento no início do 
+                capítulo poderia ser re-escrito assim:
+            </para>
+            
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+        <class name="Cat" table="CATS">
+                <id name="id" column="uid" type="long">
+                        <generator class="hilo"/>
+                </id>
+                <property name="birthdate" type="date"/>
+                <property name="color" not-null="true"/>
+                <property name="sex" not-null="true"/>
+                <property name="weight"/>
+                <many-to-one name="mate"/>
+                <set name="kittens">
+                        <key column="MOTHER"/>
+                        <one-to-many class="Cat"/>
+                </set>
+                <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
+                    <key column="CAT"/>
+                    <property name="name" type="string"/>
+                </joined-subclass>
+        </class>
+
+        <class name="eg.Dog">
+                <!-- mapping for Dog could go here -->
+        </class>
+
+</hibernate-mapping>]]></programlisting>
+
+             <para>
+                 Para informações de mapeamentos de herança, veja <xref linkend="inheritance"/>.
+             </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-unionsubclass" revision="2">
+           <title>union-subclass</title>
+
+           <para>
+               Uma terceira opção é mapear para tabelas apenas as classes concretas de uma 
+               hierarquia de heranças, (a estratégia table-per-concrete-class) onde cada tabela 
+               define todos os estados persistentes da classe, incluindo estados herdados. 
+               No Hibernate, não é absolutamente necessário mapear explicitamente como hierarquia 
+               de heranças. Você pode simplesmente mapear cada classe com uma declaração 
+               <literal>&lt;class&gt;</literal> separada. Porém, se você deseja usar associações 
+               polimórficas (por exemplo: uma associação para a superclasse de sua hierarquia), 
+               você precisa usar o mapeamento <literal>&lt;union-subclass&gt;</literal>.
+
+           </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="unionsubclass1" coords="2 45"/>
+                    <area id="unionsubclass2" coords="3 45"/>
+                    <area id="unionsubclass3" coords="4 45"/>
+                    <area id="unionsubclass4" coords="5 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<union-subclass
+        name="ClassName"
+        table="tablename"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        schema="schema"
+        catalog="catalog"
+        extends="SuperclassName"
+        abstract="true|false"
+        persister="ClassName"
+        subselect="SQL expression"
+        entity-name="EntityName"
+        node="element-name">
+
+        <property .... />
+        .....
+</union-subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="unionsubclass1">
+                        <para>
+                            <literal>name</literal>: O nome da subclasse completamente qualificada.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="unionsubclass2">
+                        <para>
+                            <literal>table</literal>: O nome da tabela da subclasse.
+                         </para>            
+                    </callout>                   
+                    <callout arearefs="unionsubclass3">
+                        <para>
+                            <literal>proxy</literal> (optional): Specifies a class or interface to use 
+                            for lazy initializing proxies.
+                            
+                            <literal>proxy</literal> (opcional): Especifica a classe ou interface para usar 
+                            os proxies de recuperação atrasada.
+                         </para>              
+                    </callout>
+                    <callout arearefs="unionsubclass4">
+                        <para>
+                            <literal>lazy</literal> (optional, defaults to <literal>true</literal>): Setting 
+                            <literal>lazy="false"</literal> disables the use of lazy fetching.
+                            <literal>lazy</literal> (opcional, valor default p<literal>true</literal>): 
+                            Fixando <literal>lazy="false"</literal> desabilita o uso da recuperação atrasada.
+                          </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                A coluna discriminatõria não é requerida para esta estratégia de mapeamento.
+
+         </para>
+
+            <para>
+                Para informações sobre mapeamentos de herança, veja <xref linkend="inheritance"/>.
+            </para>
+
+        </sect2>
+
+   	<sect2 id="mapping-declaration-join" revision="3">
+            <title>join</title>
+
+            <para>
+                Usando o elemento  <literal>&lt;join&gt;</literal>>, é possível mapear 
+                propriedades de uma classe para várias tabelas.
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="join1" coords="2 50"/>
+                    <area id="join2" coords="3 50"/>
+                    <area id="join3" coords="4 50"/>
+                    <area id="join4" coords="5 50"/>
+                    <area id="join5" coords="6 50"/>
+                    <area id="join6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<join
+        table="tablename"
+        schema="owner"
+        catalog="catalog"
+        fetch="join|select"
+        inverse="true|false"
+        optional="true|false">
+        
+        <key ... />
+        
+        <property ... />
+        ...
+</join>]]></programlisting>
+
+                <calloutlist>
+                    <callout arearefs="join1">
+                        <para>
+                            <literal>table</literal>: O nome da tabela associada.
+                        </para>
+                    </callout>
+                    <callout arearefs="join2">
+                        <para>
+                            <literal>schema</literal> (opcional): Sobrepõe o nome do esquema 
+                            especificado pelo elemento raiz <literal>&lt;hibernate-mapping&gt;</literal>.
+                         </para>
+                    </callout>
+                    <callout arearefs="join3">
+                        <para>
+                            <literal>catalog</literal> (opcional): Sobrepõe o nome do catálogo
+                            especificado pelo elemento raiz<literal>&lt;hibernate-mapping&gt;</literal>.
+                         </para>
+                    </callout>
+                    <callout arearefs="join4">
+                        <para>
+                            <literal>fetch</literal>(opcional – valor default <literal>join</literal>): Se setado 
+                            para <literal>join</literal>, o padrão, o Hibernate irá usar um inner join para 
+                            restaurar um <literal>join</literal> definido por uma classe ou suas subclasses e 
+                            uma outer join para um <literal>join</literal> definido por uma subclasse. 
+                            Se setado para <literal>select</literal>, então o Hibernate irá usar uma seleção 
+                            seqüencial para um <literal>&lt;join&gt;</literal> definida numa subclasse, que irá 
+                            ser emitido apenas se uma linha se concentrar para representar uma instância 
+                            da subclasse. Inner joins irá ainda ser usado para restaurar um 
+                            <literal>&lt;join&gt;</literal> definido pela classe e suas superclasses.
+                         </para>
+                    </callout>
+                    <callout arearefs="join5">
+                        <para>
+                            <literal>inverse</literal> (opcional – valor default <literal>false</literal>): 
+                            Se habilitado, o Hibernate não irá tentar inserir ou atualizar as propriedades 
+                            definidas por este join.
+                         </para>
+                    </callout>
+                    <callout arearefs="join6">
+                        <para>
+                            <literal>optional</literal> (opcional – valor default <literal>false</literal>):
+                            Se habilitado, o Hibernate irá inserir uma linha apenas se as propriedades definidas 
+                            por esta junção não forem nulas e irá sempre usar uma outer join para 
+                            recuperar as propriedades.
+                         </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Por exemplo, a informação de endereço para uma pessoa pode ser mapeada para uma 
+                tabela separada (enquanto preservando o valor da semântica de tipos para 
+                todas as propriedades):       
+            </para>
+
+            <programlisting><![CDATA[<class name="Person"
+    table="PERSON">
+
+    <id name="id" column="PERSON_ID">...</id>
+
+    <join table="ADDRESS">
+        <key column="ADDRESS_ID"/>
+        <property name="address"/>
+        <property name="zip"/>
+        <property name="country"/>
+    </join>
+    ...]]></programlisting>
+
+            <para>
+                Esta característica é útil apenas para modelos de dados legados, nós recomendamos 
+                menos tabelas do que classes e um modelo de domínio bem granulado. Porém, é 
+                útil para ficar trocando entre estratégias de mapeamento de herança 
+                numa hierarquia simples, como explicado mais a frente.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-key">
+            <title>key</title>
+
+            <para>
+                Nós vimos que o elemento <literal>&lt;key&gt;</literal> surgiu algumas vezes
+                até agora. Ele aparece em qualquer lugar que o elemento pai define uma junção 
+                para a nova tabela, e define a chave estrangeira para a tabela associada, que 
+                referencia a chave primária da tabela original.                
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="key1" coords="2 50"/>
+                    <area id="key2" coords="3 50"/>
+                    <area id="key3" coords="4 50"/>
+                    <area id="key4" coords="5 50"/>
+                    <area id="key5" coords="6 50"/>
+                    <area id="key6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<key
+        column="columnname"
+        on-delete="noaction|cascade"
+        property-ref="propertyName"
+        not-null="true|false"
+        update="true|false"
+        unique="true|false"
+/>]]></programlisting>
+
+                <calloutlist>
+                    <callout arearefs="key1">
+                        <para>.
+                            <literal>column</literal> (opcional): O nome da coluna da chave estrangeira. 
+                            Isto também pode ser especificado por aninhamento de elemento(s) 
+                            <literal>&lt;column&gt;</literal>.
+                        </para>
+                    </callout>
+                    <callout arearefs="key2">
+                        <para>
+                            <literal>on-delete</literal> (opcional, valor default <literal>noaction</literal>): 
+                            Especifica se a constraint da chave estrangeira no banco de dados esta
+                            habilitada para cascade delete .
+                         </para>
+                    </callout>
+                    <callout arearefs="key3">
+                        <para>
+                            <literal>property-ref</literal> (opcional): Especifica que a chave estrangeira 
+                            se refere a colunas que não são chave primária da tabela original. 
+                            (Util para base de dados legadas.)
+                         </para>
+                    </callout>
+                    <callout arearefs="key4">
+                        <para>
+                            <literal>not-null</literal> (opcional): Especifica que a coluna da chave 
+                            estrangeira não aceita valores nulos (isto é implícito em qualquer momento 
+                            que a chave estrangeira também fizer parte da chave primária).
+                        </para>
+                    </callout>
+                    <callout arearefs="key5">
+                        <para>
+                            <literal>update</literal> (optional): Specifies that the foreign key should never
+                            be updated (this is implied whenever the foreign key is also part of the primary 
+                            key).
+                            <literal>update</literal> (opcional): Especifica que a chave estrangeira nunca 
+                            deve ser atualizada (isto é implícito em qualquer momento que a chave estrangeira 
+                            também fizer parte da chave primária).
+                        </para>
+                    </callout>
+                    <callout arearefs="key6">
+                        <para>
+                             <literal>unique</literal> (opcional): Especifica que a chave estrangeira deve ter 
+                            uma constraint unique (sto é implícito em qualquer momento que a chave estrangeira 
+                            também fizer parte da chave primária).
+                         </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                Nós recomendamos que para sistemas que a performance de delete seja importante, todas as 
+                chaves deve ser definida <literal>on-delete="cascade"</literal>, e o Hibernate irá usar 
+                uma constraint a nível de banco de dados <literal>ON CASCADE DELETE</literal>, ao invés 
+                de muitas instruções <literal>DELETE</literal>. Esteja ciente que esta característica é 
+                um atalho da estratégia usual de optimistic locking do Hibernate para dados versionados.
+            </para>
+            
+            <para>
+                Os atributos <literal>not-null</literal> e <literal>update</literal> são úteis quando 
+                estamos mapeamos uma associação unidirecional um para muitos. Se você mapear uma 
+                asociação unidirecional um para muitos para uma chave estrangeira non-nullable, você 
+                <emphasis>deve</emphasis> declarar a coluna chave usando 
+                <literal>&lt;key not-null="true"&gt;</literal>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-column" revision="4">
+           <title>elementos column e formula</title>
+           <para>
+               Qualquer elemento de mapeamente que aceita um atributo <literal>column</literal> irá 
+               aceitar alternativamente um subelemento <literal>&lt;column&gt;</literal>. Da mesma forma, 
+               <literal>formula</literal> é uma alternativa para o atributo <literal>formula</literal>.               
+           </para>
+
+           <programlisting><![CDATA[<column
+        name="column_name"
+        length="N"
+        precision="N"
+        scale="N"
+        not-null="true|false"
+        unique="true|false"
+        unique-key="multicolumn_unique_key_name"
+        index="index_name"
+        sql-type="sql_type_name"
+        check="SQL expression"
+        default="SQL expression"/>]]></programlisting>
+
+            <programlisting><![CDATA[<formula>SQL expression</formula>]]></programlisting>
+        
+            <para>
+                O atributo <literal>column</literal> e <literal>formula</literal> podem até ser combinados
+                dentro da mesma propriedade ou associação mapeando para expressar, 
+                por exemplo, associações exóticas.
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="homeAddress" class="Address"
+        insert="false" update="false">
+    <column name="person_id" not-null="true" length="10"/>
+    <formula>'MAILING'</formula>
+</many-to-one>]]></programlisting>
+
+    </sect2>  
+   	
+        <sect2 id="mapping-declaration-import">
+            <title>import</title>
+
+            <para>
+                Suponha que a sua aplicação tem duas classes persistentes com o mesmo nome, e você não quer 
+                especificar o nome qualificado (do pacote) nas queries do Hibernate. As Classes devem 
+                ser "importadas" explicitamente, de preferência contando com  <literal>auto-import="true"</literal>. 
+                Você pode até importar classes e interfaces que não estão explicitamente mapeadas.
+            </para>
+            
+            <programlisting><![CDATA[<import class="java.lang.Object" rename="Universe"/>]]></programlisting>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="import1" coords="2 40"/>
+                    <area id="import2" coords="3 40"/>
+                </areaspec>
+                <programlisting><![CDATA[<import
+        class="ClassName"
+        rename="ShortName"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="import1">
+                        <para>
+                            <literal>class</literal>: O nome qualificado (do pacote) de qualquer classe Java.
+                        </para>              
+                    </callout>                   
+                    <callout arearefs="import2">
+                        <para>
+                            <literal>rename</literal> (opcional – valor default, o nome da classe não 
+                            qualificada): Um nome que pode ser usado numa linguagem de consulta.
+                         </para>               
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+        </sect2>
+        
+        <sect2 id="mapping-types-anymapping" revision="2">
+            <title>any</title>
+            
+            <para>
+                Existe mais um tipo de propriedade de mapeamento. O elemento de mapeamento 
+                <literal>&lt;any&gt;</literal> define uma associação polimórfica para classes de múltiplas tabelas. 
+                Este tipo de mapeamento sempre requer mais de uma coluna. A primeira coluna possui o tipo da entidade 
+                associada. A outra coluna que ficou possui o identificador. É impossível especificar uma restrição 
+                de chave estrangeira para este tipo de associação, assim isto claramente não é visto 
+                como um caminho usual para associações (polimórficas) de mapeamento. Você deve usar este mapeamento
+                apenas em casos muito especiais (exemplo: audit logs, dados de sessão do usuário, etc).
+
+           </para>
+
+            <para>
+                 O atributo <literal>meta-type</literal> permite a aplicação especificar um tipo adaptado 
+                 que mapeia valores de colunas de banco de dados para classes persistentes que tem propriedades 
+                 identificadoras do tipo especificado através do <literal>id-type</literal>. Você deve especificar 
+                 o mapeamento de valores do meta-type para nome de classes.
+            </para>
+
+            <programlisting><![CDATA[<any name="being" id-type="long" meta-type="string">
+    <meta-value value="TBL_ANIMAL" class="Animal"/>
+    <meta-value value="TBL_HUMAN" class="Human"/>
+    <meta-value value="TBL_ALIEN" class="Alien"/>
+    <column name="table_name"/>
+    <column name="id"/>
+</any>]]></programlisting>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="any1" coords="2 50"/>
+                    <area id="any2" coords="3 50"/>
+                    <area id="any3" coords="4 50"/>
+                    <area id="any4" coords="5 50"/>
+                    <area id="any5" coords="6 50"/>
+                    <area id="any6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<any
+        name="propertyName"
+        id-type="idtypename"
+        meta-type="metatypename"
+        cascade="cascade_style"
+        access="field|property|ClassName"
+        optimistic-lock="true|false"
+>
+        <meta-value ... />
+        <meta-value ... />
+        .....
+        <column .... />
+        <column .... />
+        .....
+</any>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="any1">
+                        <para>
+                            <literal>name</literal>: o nome da propriedade.
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any2">
+                        <para>
+                            <literal>id-type</literal>: o tipo identificador.
+                         </para>            
+                    </callout>                   
+                    <callout arearefs="any3">
+                        <para>
+                            <literal>meta-type</literal> (opcional – valor default <literal>string</literal>): 
+                            Qualquer tipo que é permitido para um mapeamento discriminador.
+                         </para>            
+                    </callout>                   
+                    <callout arearefs="any4">
+                        <para>
+                            <literal>cascade</literal> (opcional – valor default <literal>none</literal>): 
+                            o estilo do cascade.
+                         </para>            
+                    </callout>                   
+                    <callout arearefs="any5">
+                        <para>
+                            <literal>access</literal> (opcional – valor default <literal>property</literal>): 
+                            A estratégia que o hibernate deve usar para acessar o valor da propriedade.
+                         </para>
+                    </callout>
+                    <callout arearefs="any6">
+                        <para>
+                            <literal>optimistic-lock</literal> (opcional - valor default<literal>true</literal>): 
+                            Especifica que as atualizações para esta propriedade requerem ou não aquisição da 
+                            trava otimista. Em outras palavras, define se uma versão de incremento deve ocorrer 
+                            se esta propriedade está modificada.
+                    </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+      </sect2>
+
+    </sect1>
+
+    <sect1 id="mapping-types">
+        <title>Tipos do Hibernate</title>
+
+        <sect2 id="mapping-types-entitiesvalues" revision="1">
+            <title>Entidades e valores</title>
+
+            <para>
+                Para entender o comportamento de vários objetos em nível de linguagem de Java a 
+                respeito do serviço de persistência, nós precisamos classificá-los em dois grupos.
+            </para>
+
+            <para>
+                Uma <emphasis>entidade </emphasis> existe independentemente de qualquer outro 
+                objeto guardando referências para a entidade. Em contraste com o modelo usual de 
+                Java que um objeto não referenciado é coletado pelo garbage collector. Entidades 
+                devem ser explicitamente salvas ou deletada (exceto em operações de salvamento 
+                ou deleção que possam ser executada em <emphasis>cascata</emphasis> de uma entidade 
+                pai para seus filhos). Isto é diferente do modelo ODMG de persistência do objeto 
+                por acessibilidade – e corresponde quase a como objetos de aplicações são 
+                geralmente usados em grandes sistemas. Entidades suportam referências circulares 
+                e comuns. Eles podem ser versionadas.
+            </para>
+
+            <para>
+                Uma entidade em estado persistente consiste de referências para outras entidades 
+                e instâncias de tipos de  <emphasis>valor</emphasis>. Valores são primitivos, 
+                coleções (não o que tem dentro de uma coleção), componentes e certos objetos 
+                imutáveis. Entidades distintas, valores (em coleções e componentes particulares)
+                <emphasis>são </emphasis> persistidos e apagados por acessibilidade. Visto que 
+                objetos value (e primitivos) são persistidos e apagados junto com as entidades 
+                que os contém e não podem ser versionados independentemente. Valores têm 
+                identidade não independente, assim eles não podem ser comuns para duas 
+                entidades ou coleções.
+
+            </para>
+
+            <para>
+                Até agora, nós estivemos usando o termo "classe persistente" para referir 
+                a entidades. Nós iremos continuar a fazer isto. Falando a rigor, porém, nem todas 
+                as classes definidas pelo usuário com estados persistentes são entidades. Um 
+                <emphasis>componente</emphasis> é uma classe de usuário definida com valores 
+                semânticos. Uma propriedade de Java de tipo <literal>java.lang.String</literal> 
+                também tem um valor semêntico. Dada esta definição, nós podemos dizer que 
+                todos os tipos (classes) fornecida pelo JDK tem tipo de valor semântico em Java, 
+                enquanto que tipos definidos pelo usuário pode ser mapeados com entidade ou valor 
+                de tipo semântico. Esta decisão pertence ao desenvolvedor da aplicação. Uma boa 
+                dica para uma classe entidade em um modelo de domínio são referências comuns 
+                para uma instância simples daquela classe, enquanto a composição ou agregação 
+                geralmente se traduz para um valor de tipo.
+            </para>
+
+            <para>
+                Nós iremos rever ambos os conceitos durante toda a documentação.
+
+            </para>
+
+            <para>
+                O desafio pe mapear o sistema de tipo de Java (e a definição do desenvolvedor de 
+                entidades e tipos de valor) para o sistema de tipo SQL/banco de dados. A ponte entre ambos 
+                os sistemas é fornecido pelo Hibernate: para entidades que usam 
+                <literal>&lt;class&gt;</literal>, <literal>&lt;subclass&gt;</literal> e assim por diante. 
+                Para tipos de valores nós usamos <literal>&lt;property&gt;</literal>, 
+                <literal>&lt;component&gt;</literal>, etc, geralmente com um atributo 
+                <literal>type</literal>. O valor deste atributo é o nome de um  <emphasis>tipo de 
+                mapeamento</emphasis> do Hibernate. O Hibernate fornece muitos mapeamentos 
+                (para tipos de valores do JDK padrão) ut of the box. Você pode escrever os seus 
+                próprios tipos de mapeamentos e implementar sua estratégia de conversão adaptada, 
+                como você verá adiante.
+            </para>
+
+            <para>
+                Todos os tipos internos do hibernate exceto coleções suportam semânticas nulas.
+
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-types-basictypes" revision="3">
+            <title>Valores de tipos básicos</title>
+
+            <para>
+                O tipos internos de mapeamentos básicos podem ser a grosso modo categorizado como:
+                <variablelist>
+                    <varlistentry>
+                        <term><literal>integer, long, short, float, double, character, byte,
+                            boolean, yes_no, true_false</literal></term>
+                        <listitem>
+                            <para>
+                                Tipos de mapeamentos de classes primitivas ou wrapper Java especificos
+                               	(vendor-specific) para tipos de coluna SQL. Boolean, 
+                               	<literal>boolean, yes_no</literal> são todas codificações alternativas 
+                               	para um <literal>boolean</literal> ou <literal>java.lang.Boolean</literal>
+                               	do Java.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>string</literal></term>
+                        <listitem>
+                            <para>
+                                Um tipo de mapeamento de <literal>java.lang.String</literal> para
+                                <literal>VARCHAR</literal> (ou <literal>VARCHAR2</literal> no Oracle).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>date, time, timestamp</literal></term>
+                        <listitem>
+                            <para>
+                                Tipos de mapeamento de <literal>java.util.Date</literal> e suas 
+                                subclasses para os tipos SQL <literal>DATE</literal>,
+                                <literal>TIME</literal> e <literal>TIMESTAMP</literal> 
+                                (ou equivalente).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>calendar, calendar_date</literal></term>
+                        <listitem>
+                            <para>
+                                Tipo de mapeamento de <literal>java.util.Calendar</literal> para 
+                                os tipos SQL <literal>TIMESTAMP</literal> e 
+                                <literal>DATE</literal> (ou equivalente).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>big_decimal, big_integer</literal></term>
+                        <listitem>
+                            <para>
+                                Tipo de mapeamento de <literal>java.math.BigDecimal</literal> and
+                                <literal>java.math.BigInteger</literal> para  <literal>NUMERIC</literal>
+                                (ou <literal>NUMBER</literal> no Oracle).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>locale, timezone, currency</literal></term>
+                        <listitem>
+                            <para>
+                                Tipos de mapeamentos de <literal>java.util.Locale</literal>,
+                                <literal>java.util.TimeZone</literal> e <literal>java.util.Currency</literal>
+                                para <literal>VARCHAR</literal> (ou <literal>VARCHAR2</literal> no Oracle). 
+                                Instâncias de f <literal>Locale</literal> e <literal>Currency</literal> 
+                                são mapeados para seus códigos ISO. Instâncias de <literal>TimeZone</literal> 
+                                são mapeados para seu <literal>ID</literal>.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>class</literal></term>
+                        <listitem>
+                            <para>
+                                um tipo de mapeamento de <literal>java.lang.Class</literal> para 
+                                <literal>VARCHAR</literal>  (ou <literal>VARCHAR2</literal>  no 
+                                Oracle). Uma <literal>Class</literal> é mapeada pelo 
+                                seu nome qualificado (completo).
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>binary</literal></term>
+                        <listitem>
+                            <para>
+                                Mapeia arrays de bytes para um tipo binário de SQL apropriado.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>text</literal></term>
+                        <listitem>
+                            <para>
+                                Maps long Java strings to a SQL <literal>CLOB</literal> or 
+                                <literal>TEXT</literal> type.
+                                Mapeia strings longas de Java para um tipo SQL
+                                <literal>CLOB</literal> ou <literal>TEXT</literal>.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>serializable</literal></term>
+                        <listitem>
+                            <para>
+                                Mapeia tipos Java serializáveis para um tipo binário SQL apropriado. 
+                                Você pode também indicar o tipo <literal>serializable</literal> do 
+                                Hibernate com o nome da classe ou interface Java serializável que 
+                                não é padrão para um tipo básico.
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>clob, blob</literal></term>
+                        <listitem>
+                            <para>
+                                Tipos de mapeamentos para as classes JDBC <literal>java.sql.Clob</literal> and
+                                <literal>java.sql.Blob</literal>. Estes tipos podem ser inconveniente para 
+                                algumas aplicações, visto que o objeto blob ou clob pode não ser reusado 
+                                fora de uma transação. (Além disso, o suporte de driver é imcompleto e 
+                                inconsistente.)
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date,
+                            imm_serializable, imm_binary</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                Mapeando tipos para o que geralmente são consideradas tipos mutáveis de 
+                                Java, onde o Hibernate faz determinadas otimizações apropriadas somente 
+                                para tipos imutáveis de Java, e a aplicação trata o objeto como imutável. 
+                                Por exemplo, você não deve chamar <literal>Date.setTime()</literal> para 
+                                uma instância mapeada como  <literal>imm_timestamp</literal>. Para mudar 
+                                o valor da propriedade, e ter a mudança feita persistente, a aplicação 
+                                deve atribuir um novo objeto (nonidentical) à propriedade. 
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                </variablelist>
+            
+            </para>
+
+            <para>
+                Identificadores únicos das entidades e coleções podem ser de qualquer tipo 
+                básico exceto <literal>binary</literal>, <literal>blob</literal> ou 
+                <literal>clob</literal>. (Identificadores compostos também são permitidos, 
+                veja abaixo.)
+            </para>
+            
+            <para>
+                Os tipos de valores básicos têm  suas constantes <literal>Type</literal> 
+                correspondentes definidas em <literal>org.hibernate.Hibernate</literal>. Por exemplo,
+                <literal>Hibernate.STRING</literal> representa o tipo  <literal>string</literal>.  
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-types-custom" revision="2">
+            <title>Tipos de valores personalizados</title>
+
+            <para>
+                É relativamente fácil para desenvolvedores criar seus próprios tipos de valor. 
+                Por exemplo, você pode querer persistir propriedades do tipo 
+                <literal>java.lang.BigInteger</literal> para colunas <literal>VARCHAR</literal>. O 
+                Hibernate não fornece um tipo correspondente para isso. Mas os tipos adaptados 
+                não são limitados a mapeamento de uma propriedade (ou elemento de coleção) a uma 
+                única coluna da tabela. Assim, por exemplo, você pôde ter uma propriedade Java 
+                <literal>getName()</literal>/<literal>setName()</literal> do tipo 
+                <literal>java.lang.String</literal> que é persistido para colunas 
+                <literal>FIRST_NAME</literal>, <literal>INITIAL</literal>, <literal>SURNAME</literal>.  
+
+            </para>
+            
+            <para>
+                Para implementar um tipo personalizado, implemente <literal>org.hibernate.UserType</literal>
+                or <literal>org.hibernate.CompositeUserType</literal> e declare propriedades usando o nome 
+                qualificado da classe do tipo. Veja <literal>org.hibernate.test.DoubleStringType</literal> 
+                para ver o tipo das coisas que são possíveis. 
+            </para>
+
+            <programlisting><![CDATA[<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
+    <column name="first_string"/>
+    <column name="second_string"/>
+</property>]]></programlisting>
+
+            <para>
+                Observe o uso da tag <literal>&lt;column&gt;</literal> para mapear uma propriedade 
+                para colunas múltiplas.  
+            </para>
+            
+            <para>
+                As interfaces <literal>CompositeUserType</literal>, <literal>EnhancedUserType</literal>,
+                <literal>UserCollectionType</literal>, e <literal>UserVersionType</literal>  
+                fornecem suporte para usos mais especializados.
+            </para>
+            
+            <para>
+                Você pode mesmo fornecer parâmetros a um <literal>UserType</literal> no arquivo de mapeamento. 
+                Para isto, seu <literal>UserType</literal> deve implementar a interface 
+                <literal>org.hibernate.usertype.ParameterizedType</literal>. Para fornecer parâmetros a seu 
+                tipo personalizado, você  pode usar o elemento <literal>&lt;type&gt;</literal> em seus 
+                arquivos de mapeamento.  
+            </para>
+            
+            <programlisting><![CDATA[<property name="priority">
+    <type name="com.mycompany.usertypes.DefaultValueIntegerType">
+        <param name="default">0</param>
+    </type>
+</property>]]></programlisting>
+
+            <para>
+                O <literal>UserType</literal> pode agora recuperar o valor para o parâmetro chamado 
+                <literal>default</literal> da <literal>Propriedade</literal> do passado a ele.  
+            </para>
+            
+            <para>
+                Se você usar freqüentemente um determinado <literal>UserType</literal>, pode ser útil definir 
+                um nome mais curto para ele. Você pode fazer isto usando o elemento 
+                <literal>&lt;typedef&gt;</literal>. Typedefs atribui um nome a um tipo personalizado, e pode também 
+                conter uma lista de valores default de parâmetro se o tipo for parametrizado.
+            </para>
+            
+            <programlisting><![CDATA[<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
+    <param name="default">0</param>
+</typedef>]]></programlisting>
+
+            <programlisting><![CDATA[<property name="priority" type="default_zero"/>]]></programlisting>
+
+            <para>
+                It is also possible to override the parameters supplied in a typedef on a case-by-case basis
+                by using type parameters on the property mapping.
+            </para>
+            
+            <para>
+                Even though Hibernate's rich range of built-in types and support for components means you
+                will very rarely <emphasis>need</emphasis> to use a custom type, it is nevertheless
+                considered good form to use custom types for (non-entity) classes that occur frequently
+                in your application. For example, a <literal>MonetaryAmount</literal> class is a good
+                candidate for a <literal>CompositeUserType</literal>, even though it could easily be mapped 
+                as a component. One motivation for this is abstraction. With a custom type, your mapping 
+                documents would be future-proofed against possible changes in your way of representing 
+                monetary values.
+            </para>
+
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="mapping-entityname">
+        <title>Mapping a class more than once</title>
+        <para>
+            It is possible to provide more than one mapping for a particular persistent class. In this
+            case you must specify an <emphasis>entity name</emphasis> do disambiguate between instances
+            of the two mapped entities. (By default, the entity name is the same as the class name.)
+            Hibernate lets you specify the entity name when working with persistent objects, when writing
+            queries, or when mapping associations to the named entity.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Contract" table="Contracts" 
+        entity-name="CurrentContract">
+    ...
+    <set name="history" inverse="true" 
+            order-by="effectiveEndDate desc">
+        <key column="currentContractId"/>
+        <one-to-many entity-name="HistoricalContract"/>
+    </set>
+</class>
+
+<class name="Contract" table="ContractHistory" 
+        entity-name="HistoricalContract">
+    ...
+    <many-to-one name="currentContract" 
+            column="currentContractId" 
+            entity-name="CurrentContract"/>
+</class>]]></programlisting>
+
+        <para>
+            Notice how associations are now specified using <literal>entity-name</literal> instead of
+            <literal>class</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="mapping-quotedidentifiers">
+            <title>SQL quoted identifiers</title>
+            <para>
+                You may force Hibernate to quote an identifier in the generated SQL by enclosing the table or
+                column name in backticks in the mapping document. Hibernate will use the correct quotation
+                style for the SQL <literal>Dialect</literal> (usually double quotes, but brackets for SQL
+                Server and backticks for MySQL).
+            </para>
+
+            <programlisting><![CDATA[<class name="LineItem" table="`Line Item`">
+    <id name="id" column="`Item Id`"/><generator class="assigned"/></id>
+    <property name="itemNumber" column="`Item #`"/>
+    ...
+</class>]]></programlisting>
+
+    </sect1>
+
+  	
+   	<sect1 id="mapping-alternatives">
+   	<title>Metadata alternatives</title>
+   	
+   	<para>
+   	    XML isn't for everyone, and so there are some alternative ways to define O/R mapping metadata in Hibernate.
+   	</para>
+
+    <sect2 id="mapping-xdoclet">
+        <title>Using XDoclet markup</title>
+
+        <para>
+            Many Hibernate users prefer to embed mapping information directly in sourcecode using
+            XDoclet <literal>@hibernate.tags</literal>. We will not cover this approach in this
+            document, since strictly it is considered part of XDoclet. However, we include the
+            following example of the <literal>Cat</literal> class with XDoclet mappings.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+/**
+ * @hibernate.class
+ *  table="CATS"
+ */
+public class Cat {
+    private Long id; // identifier
+    private Date birthdate;
+    private Cat mother;
+    private Set kittens
+    private Color color;
+    private char sex;
+    private float weight;
+
+    /*
+     * @hibernate.id
+     *  generator-class="native"
+     *  column="CAT_ID"
+     */
+    public Long getId() {
+        return id;
+    }
+    private void setId(Long id) {
+        this.id=id;
+    }
+
+    /**
+     * @hibernate.many-to-one
+     *  column="PARENT_ID"
+     */
+    public Cat getMother() {
+        return mother;
+    }
+    void setMother(Cat mother) {
+        this.mother = mother;
+    }
+
+    /**
+     * @hibernate.property
+     *  column="BIRTH_DATE"
+     */
+    public Date getBirthdate() {
+        return birthdate;
+    }
+    void setBirthdate(Date date) {
+        birthdate = date;
+    }
+    /**
+     * @hibernate.property
+     *  column="WEIGHT"
+     */
+    public float getWeight() {
+        return weight;
+    }
+    void setWeight(float weight) {
+        this.weight = weight;
+    }
+
+    /**
+     * @hibernate.property
+     *  column="COLOR"
+     *  not-null="true"
+     */
+    public Color getColor() {
+        return color;
+    }
+    void setColor(Color color) {
+        this.color = color;
+    }
+    /**
+     * @hibernate.set
+     *  inverse="true"
+     *  order-by="BIRTH_DATE"
+     * @hibernate.collection-key
+     *  column="PARENT_ID"
+     * @hibernate.collection-one-to-many
+     */
+    public Set getKittens() {
+        return kittens;
+    }
+    void setKittens(Set kittens) {
+        this.kittens = kittens;
+    }
+    // addKitten not needed by Hibernate
+    public void addKitten(Cat kitten) {
+        kittens.add(kitten);
+    }
+
+    /**
+     * @hibernate.property
+     *  column="SEX"
+     *  not-null="true"
+     *  update="false"
+     */
+    public char getSex() {
+        return sex;
+    }
+    void setSex(char sex) {
+        this.sex=sex;
+    }
+}]]></programlisting>
+
+        <para>
+            See the Hibernate web site for more examples of XDoclet and Hibernate.
+        </para>
+
+    </sect2>
+
+    <sect2 id="mapping-annotations" revision="2">
+        <title>Using JDK 5.0 Annotations</title>
+
+        <para>
+            JDK 5.0 introduced XDoclet-style annotations at the language level, type-safe and
+            checked at compile time. This mechnism is more powerful than XDoclet annotations and
+            better supported by tools and IDEs. IntelliJ IDEA, for example, supports auto-completion
+            and syntax highlighting of JDK 5.0 annotations. The new revision of the EJB specification
+            (JSR-220) uses JDK 5.0 annotations as the primary metadata mechanism for entity beans.
+            Hibernate3 implements the <literal>EntityManager</literal> of JSR-220 (the persistence API),
+            support for mapping metadata is available via the <emphasis>Hibernate Annotations</emphasis>
+            package, as a separate download. Both EJB3 (JSR-220) and Hibernate3 metadata is supported.
+        </para>
+
+        <para>
+            This is an example of a POJO class annotated as an EJB entity bean:
+        </para>
+
+        <programlisting><![CDATA[@Entity(access = AccessType.FIELD)
+public class Customer implements Serializable {
+
+    @Id;
+    Long id;
+
+    String firstName;
+    String lastName;
+    Date birthday;
+
+    @Transient
+    Integer age;
+
+    @Embedded
+    private Address homeAddress;
+
+    @OneToMany(cascade=CascadeType.ALL)
+    @JoinColumn(name="CUSTOMER_ID")
+    Set<Order> orders;
+
+    // Getter/setter and business methods
+}]]></programlisting>
+
+        <para>
+            Note that support for JDK 5.0 Annotations (and JSR-220) is still work in progress and
+            not completed. Please refer to the Hibernate Annotations module for more details.
+        </para>
+    
+    </sect2>
+    </sect1>
+
+    <sect1 id="mapping-generated" revision="1">
+        <title>Generated Properties</title>
+        <para>
+            Generated properties are properties which have their values generated by the
+            database.  Typically, Hibernate applications needed to <literal>refresh</literal>
+            objects which contain any properties for which the database was generating values.
+            Marking properties as generated, however, lets the application delegate this
+            responsibility to Hibernate.  Essentially, whenever Hibernate issues an SQL INSERT
+            or UPDATE for an entity which has defined generated properties, it immediately
+            issues a select afterwards to retrieve the generated values.
+        </para>
+        <para>
+            Properties marked as generated must additionally be non-insertable and non-updateable.
+            Only <xref linkend="mapping-declaration-version">versions</xref>,
+            <xref linkend="mapping-declaration-timestamp">timestamps</xref>, and
+            <xref linkend="mapping-declaration-property">simple properties</xref> can be marked as
+            generated.
+        </para>
+	    <para>
+		    <literal>never</literal> (the default) - means that the given property value
+		    is not generated within the database.
+	    </para>
+	    <para>
+		    <literal>insert</literal> - states that the given property value is generated on
+		    insert, but is not regenerated on subsequent updates.  Things like created-date would
+		    fall into this category.  Note that even thought
+		    <xref linkend="mapping-declaration-version">version</xref> and
+		    <xref linkend="mapping-declaration-timestamp">timestamp</xref> properties can
+		    be marked as generated, this option is not available there...
+	    </para>
+	    <para>
+		    <literal>always</literal> - states that the property value is generated both
+		    on insert and on update.
+	    </para>
+    </sect1>
+
+    <sect1 id="mapping-database-object">
+        <title>Auxiliary Database Objects</title>
+        <para>
+            Allows CREATE and DROP of arbitrary database objects, in conjunction with
+            Hibernate's schema evolution tools, to provide the ability to fully define
+            a user schema within the Hibernate mapping files.  Although designed specifically
+            for creating and dropping things like triggers or stored procedures, really any
+            SQL command that can be run via a <literal>java.sql.Statement.execute()</literal>
+            method is valid here (ALTERs, INSERTS, etc).  There are essentially two modes for
+            defining auxiliary database objects...
+        </para>
+        <para>
+            The first mode is to explicitly list the CREATE and DROP commands out in the mapping
+            file:
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <create>CREATE TRIGGER my_trigger ...</create>
+        <drop>DROP TRIGGER my_trigger</drop>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+        <para>
+            The second mode is to supply a custom class which knows how to construct the
+            CREATE and DROP commands.  This custom class must implement the
+            <literal>org.hibernate.mapping.AuxiliaryDatabaseObject</literal> interface.
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <definition class="MyTriggerDefinition"/>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+        <para>
+            Additionally, these database objects can be optionally scoped such that they only
+            apply when certain dialects are used.
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <definition class="MyTriggerDefinition"/>
+        <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/>
+        <dialect-scope name="org.hibernate.dialect.OracleDialect"/>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+    </sect1>
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/basic_mapping.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/batch.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/batch.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/batch.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,357 @@
+<chapter id="batch">
+    <title>Processamento de lotes</title>
+    
+    <para>
+        Uma alternativa para inserir 100.000 linhas no banco de dados usando o Hibernate 
+        pode ser a seguinte:        
+    </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+for ( int i=0; i<100000; i++ ) {
+    Customer customer = new Customer(.....);
+    session.save(customer);
+}
+tx.commit();
+session.close();]]></programlisting>
+
+    <para>
+        Isto irá falhar em algum lugar próximo a linha 50.000, lançando uma 
+        <literal>OutOfMemoryException</literal>. Isso ocorre devido ao fato do Hibernate 
+        fazer cache de todas as instâncias de <literal>Customer</literal> inseridas num 
+        cachê em nível de sessão.
+    </para>
+
+    <para>
+        Neste capítulo veremos como contornar esse problema.  Entretanto, se você vai realizar 
+        processamento de lotes, é muito importante que você habilite o uso de lotes JDBC, se 
+        você pretende obter um desempenho razoável. Defina o tamanho do lote JDBC em um 
+        valor razoável (algo entre 10-50):
+    </para>
+    
+<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
+
+    <para>
+        Você também pode querer rodar esse tipo de processamento de lotes com o cache 
+        secundário completamente desabilitado:
+    </para>
+
+<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
+
+    <para>
+        Mas isto não é absolutamente necessário, desde que nós possamos ajustar o 
+         <literal>CacheMode</literal> para desabilitar  a interação com o cache secundário.
+    </para>
+
+    <sect1 id="batch-inserts">
+        <title>Inserção de lotes</title>
+
+        <para>
+            Quando você estiver inserindo novos objetos persistentes, vocês deve executar 
+            os métodos <literal>flush()</literal> e  <literal>clear()</literal> regularmente
+            na sessão, para controlar o tamanho do cache primário.            
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+   
+for ( int i=0; i<100000; i++ ) {
+    Customer customer = new Customer(.....);
+    session.save(customer);
+    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
+        //flush a batch of inserts and release memory:
+        session.flush();
+        session.clear();
+    }
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="batch-update" >
+        <title>Batch updates</title>
+
+        <para>
+            Para recuperar e atualizar informações a mesma idéia é válida. Adicionalmente, 
+            pode precisar usar o  <literal>scroll()</literal> para usar recursos no lado 
+            do servidor em queries que retornam muita informação.            
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+   
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+    .setCacheMode(CacheMode.IGNORE)
+    .scroll(ScrollMode.FORWARD_ONLY);
+int count=0;
+while ( customers.next() ) {
+    Customer customer = (Customer) customers.get(0);
+    customer.updateStuff(...);
+    if ( ++count % 20 == 0 ) {
+        //flush a batch of updates and release memory:
+        session.flush();
+        session.clear();
+    }
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="batch-statelesssession">
+        <title>A interface StatelessSession</title>
+        <para>
+            Alternativamente, o Hibernate provê uma API orientada à comandos, usada para 
+            transmitir um fluxo de dados de e para o banco de dados na forma de objetos soltos. 
+            Uma  <literal>StatelessSession</literal> não tem um contexto persistente associado e 
+            não fornece muito das semânticas de alto nível para controle do ciclo de vida. 
+            Em especial, uma StatelessSession não implemente o cache primário e nem interage 
+            com o cache secundário ou query cache. Ele não implementa  salvamento transacional 
+            automatico ou checagem automática de mudanças. Operação realizadas usando uma 
+            StatelessSession não fazem nenhum tipo de cascade com as instancias associadas.  
+            As coleções são ignoradas por uma StatelessSession. Operações realizadas com um 
+            StatelessSession ignoram a arquitetura de eventos e os interceptadores. 
+            StatelessSession são vulneráveis aos efeitos do aliasing dos dados, devido a 
+            falta do cache primário. Uma StatelessSession é uma abstração de baixo nível, 
+            muito mais próxima do JDBC.           
+        </para>
+        
+<programlisting><![CDATA[StatelessSession session = sessionFactory.openStatelessSession();
+Transaction tx = session.beginTransaction();
+   
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+    .scroll(ScrollMode.FORWARD_ONLY);
+while ( customers.next() ) {
+    Customer customer = (Customer) customers.get(0);
+    customer.updateStuff(...);
+    session.update(customer);
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            Veja neste exempo, as instancias de <literal>Customer</literal> retornadas pela query 
+            são imediatamente desvinculadas. Elas nunca serão assossiadas à um contexto persistente.
+        </para>
+        
+        <para>
+            As operações <literal>insert(), update()</literal> e <literal>delete()</literal>
+            definidos pela interface <literal>StatelessSession</literal> são considerados 
+            operações diretas no banco de dados (row-level operations), isso resulta em uma 
+            execução imediata de comandos SQL  <literal>INSERT, UPDATE</literal> ou
+            <literal>DELETE</literal> respectivamente. Devido a isso, eles possuem uma 
+            semântica bem diferente das operações <literal>save(), saveOrUpdate()</literal> 
+            ou  <literal>delete()</literal> definidas na interface  <literal>Session</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="batch-direct" revision="3">
+        <title>Operações no estilo DML</title>
+
+        <para>
+            Como já discutido, mapeamento objeto/relacional automático e transparente é conseguido 
+            com a gerência do estado do objeto. Com isto o estado daquele objeto fica disponível na 
+            memória, manipulando(usando as expressões SQL <literal>Data Manipulation Language</literal> 
+            (SQL-style DML): <literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal>) 
+            os dados diretamente no banco de dados não irá afetar o estado registrado em memória. 
+            Entretanto, o Hibernate provê métodos para executar queries SQL-style DML, que são 
+            totalmente executas com HQL (Hibernate Query Language) 
+            (<xref linkend="queryhql">HQL</xref>).
+        </para>
+
+	    <para>
+            A pseudo-sintaxe para expressões <literal>UPDATE</literal> e <literal>DELETE</literal> é: 
+            <literal>( UPDATE | DELETE ) FROM? NomeEntidade (WHERE condições_where)?</literal>. 
+            Algumas observações:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Na clausula from, a palavra chave FROM é opcional;
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Somente uma entidade pode ser chamada na clausula from; opcionalmente pode ter
+                    um alias. Se o nome da entidade for possuir um alias, então qualquer propriedade 
+                    referenciada deve usar esse alias qualificado; se o nome da entidade não possuir
+                    um alias, então nenhuma das propriedade precisa usar o acesso qualificado.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+	            Na <xref linkend="queryhql-joins-forms">joins</xref>  (ambas implícita ou explicita) 
+	            pode ser especificada em um bulk HQL query. Sub-queries podem ser usadas na clausula 
+	            where; as subqueries podem conter joins.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    A clausula where também é opcional.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Como exemplo para executar um HQL <literal>UPDATE</literal>, use o 
+            método <literal>Query.executeUpdate()</literal>(o método ganhou o nome 
+            devido a sua familiaridade com o do JDBC 
+            <literal>PreparedStatement.executeUpdate()</literal>):
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
+// or String hqlUpdate = "update Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+        .setString( "newName", newName )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            HQL <literal>UPDATE</literal> statements, by default do not effect the
+            <xref linkend="mapping-declaration-version">version</xref>
+            or the <xref linkend="mapping-declaration-timestamp">timestamp</xref> property values
+            for the affected entities; this is in keeping with the EJB3 specification.  However,
+            you can force Hibernate to properly reset the <literal>version</literal> or
+            <literal>timestamp</literal> property values through the use of a <literal>versioned update</literal>.
+            This is achieved by adding the <literal>VERSIONED</literal> keyword after the <literal>UPDATE</literal>
+            keyword.
+          
+        </para>
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+        .setString( "newName", newName )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            Note that custom version types (<literal>org.hibernate.usertype.UserVersionType</literal>)
+            are not allowed in conjunction with a <literal>update versioned</literal> statement.
+        </para>
+
+        <para>
+
+            Para executar um HQL <literal>DELETE</literal>, use o mesmo método 
+            <literal>Query.executeUpdate()</literal>:
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlDelete = "delete Customer c where c.name = :oldName";
+// or String hqlDelete = "delete Customer where name = :oldName";
+int deletedEntities = s.createQuery( hqlDelete )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            O valor <literal>int</literal> retornado pelo método <literal>Query.executeUpdate()</literal>
+            indica o numero de entidade afetadas pela operação. Lembre-se que isso pode estar ou não 
+            relacionado ao número de linhas alteradas no banco de dados. Uma operação bulk HQL pode resultar 
+            em várias expressões SQL reais a serem executadas, por exemplo, no caso de joined-subclass. 
+            O número retornado indica a quantidade real de entidades afetadas pela expressão. Voltando 
+            ao exemplo da joined-subclass, a exclusão de uma das subclasses pode resultar numa 
+            exclusão em outra tabelas, não apenas na tabela para qual a subclasses está mapeada, mas 
+            também tabela "root" e possivelmente nas tabelas joined-subclass num nível hierárquico 
+            imediatamente abaixo.
+        </para>
+
+        <para>
+            
+            A pseudo-sintaxe para o comando <literal>INSERT</literal> é: 
+            <literal>INSERT INTO EntityName properties_list select_statement</literal>. Alguns 
+            pontos a observar:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Apenas a forma INSERT INTO ... SELECT ... é suportada; INSERT INTO ... VALUES ... 
+                    não é suportada.
+                </para>
+                <para>
+                    A lista de propriedade é análoga à <literal>especificação da coluna</literal> 
+                    do comando SQL <literal>INSERT</literal>. Para entidades envolvidas em mapeamentos, 
+                    apenas a propriedades definidas diretamente a nível da classe podem ser usandas na 
+                    properties_list. Propriedades da superclass não são permitidas; e as propriedades 
+                    da subclasse não faz sentido. Em outras palavras, os comandos 
+                    <literal>INSERT</literal> não são polimorficos.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    O camando select pode ser qualquer query HQL válida, que tenha um retorno compatível 
+                    com o tipo com o esperado pela inclusão. Atualmente, isto é verificado durante a compilação 
+                    da query, isto é melhor do que permitir que a verificação chegue ao banco de dados. 
+                    Entretanto perceba que isso pode causar problemas entre os <literal>Tipo</literal> do Hibernate 
+                    que são <emphasis>equivalentes</emphasis> em oposição a  <emphasis>equal</emphasis>. 
+                    Isso pode causar problemas nas combinações entre a propriedade definida como 
+                    <literal>org.hibernate.type.DateType</literal>e um propriedade definida como 
+                    <literal>org.hibernate.type.TimestampType</literal>, embora o banco de dados não possa 
+                    fazer uma distinção ou possa ser capaz de manusear a conversão.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Para a propriedade id, a expressão insert oferece duas opções. Você pode especificar 
+                    qualquer propriedade id explicitamente no properties_list (em alguns casos esse valor 
+                    é obtido diretamente da expressão select) ou pode omitir do properties_list (nesse caso, 
+                    um valor gerado é usado). Essa ultima opção só é válida quando são usados geradores de ids 
+                    que operam no banco de dados; a tentativa de usar essa opção com geradores do tipo 
+                    "em memória" vai causar um exceção durante a etapa de parser. Veja a finalidades desta 
+                    discussão, os seguintes geradores operam com o banco de dados  
+                    <literal>org.hibernate.id.SequenceGenerator</literal> (e suas subclasses) 
+                    e qualquer implementação de <literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>. 
+                    Aqui, a exceção mais notável é o <literal>org.hibernate.id.TableHiLoGenerator</literal>, que 
+                    não pode ser usado porque ele não dispõe de mecanismos para recuperar o seu valor.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    For properties mapped as either <literal>version</literal> or <literal>timestamp</literal>,
+                    the insert statement gives you two options.  You can either specify the property in the
+                    properties_list (in which case its value is taken from the corresponding select expressions)
+                    or omit it from the properties_list (in which case the <literal>seed value</literal> defined
+                    by the <literal>org.hibernate.type.VersionType</literal> is used).
+                    
+                    Para propriedades mapeadas como <literal>version</literal> ou  <literal>timestamp</literal>, 
+                    a expressão insert oferece a você duas opções. Você pode especificar a propriedade na 
+                    properties_list (nesse caso o seu valor é obtido a partir da expressão select correspondente) 
+                    ou ele pode ser omitido da properties_list (neste caso o usa o <literal>valor semente</literal>
+                    definido pela classe <literal>org.hibernate.type.VersionType</literal>).
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Exemplo da execução de um HQL <literal>INSERT</literal>:
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
+int createdEntities = s.createQuery( hqlInsert )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+</chapter>


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/batch.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/best_practices.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/best_practices.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/best_practices.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,225 @@
+<chapter id="best-practices" revision="3">
+    <title>Boas práticas</title>
+
+    <variablelist spacing="compact">
+        <varlistentry>
+            <term>Escreva classes compactas e mapeie-as usando <literal>&lt;component&gt;</literal>.</term>
+            <listitem>
+                <para>
+                    Use uma classe <literal>Endereco</literal> para encapsular <literal>rua</literal>, 
+                    <literal>bairro</literal>, <literal>estado</literal>, <literal>CEP</literal>. Isto promove 
+                    a reutilização de código e simplifica o refactoring.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Declare propriedades identificadoras em classes persistentes.</term>
+            <listitem>
+                <para>
+                    O Hibernate constrói propriedades identificadoras opcionais. Existem todos os tipos 
+                    de razões que explicam porquê você deveria utilizá-las. Nós recomendamos que os 
+                    identificadores sejam 'sintéticos' (gerados, sem significado para o negocio).
+                    
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Identifique chaves naturais.</term>
+            <listitem>
+                <para>
+                    Identifique chaves naturais para todas as entidades, e mapeie-as usando 
+                    <literal>&lt;natural-id&gt;</literal>. Implemente <literal>equals()</literal> e
+                    <literal>hashCode()</literal> para comparar as propriedades que compõem a chave natural.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Coloque cada classe de mapeamento em seu próprio arquivo.</term>
+            <listitem>
+                <para>
+                     Não use um único código de mapeamento monolítico. Mapeie <literal>com.eg.Foo</literal> 
+                     no arquivo <literal>com/eg/Foo.hbm.xml</literal>. Isto promove particularmente o bom 
+                     senso no time de desenvolvimento.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Carregue os mapeamentos como recursos.</term>
+            <listitem>
+                <para>
+                    Faça o deploy dos mapeamentos junto com as classes que eles mapeiam.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Considere externalizar as strings de consultas.</term>
+            <listitem>
+                <para>
+                    Esta é uma boa prática se suas consultas chamam funções SQL que não sejam ANSI. 
+                    Externalizar as strings de consultas para mapear arquivos irão tornar a aplicação 
+                    mais portável.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Use bind variables.</term>
+            <listitem>
+                <para>
+                     Assim como em JDBC, sempre substitua valores não constantes por "?". Nunca use a manipulação 
+                     de strings para concatenar valores não constantes em uma consulta! Até melhor, considere 
+                     usar parâmetros nomeados nas consultas.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Não gerencie suas conexões JDBC.</term>
+            <listitem>
+                <para>
+                    O Hibernate permite que a aplicação gerencie conexões JDBC. Esta abordagem deve ser considerada 
+                    um último recurso. Se você não pode usar os provedores de conexão embutidos, considere fazer 
+                    sua implementação a partir de <literal>org.hibernate.connection.ConnectionProvider</literal>.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Considere usar tipos customizados.</term>
+            <listitem>
+                <para>
+                    Suponha que você tenha um tipo Java, de alguma biblioteca, que precisa ser persistido mas não 
+                    provê os acessórios necessários para mapeá-lo como um componente. Você deve implementar 
+                    <literal>org.hibernate.UserType</literal>. Esta abordagem livra o código da aplicação de 
+                    implementar transformações de/para o tipo Hibernate.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term> Use código manual JDBC nos gargalos.</term>
+            <listitem>
+                <para>
+                    Nas áreas de desempenho crítico do sistema, alguns tipos de operações podem se beneficiar do 
+                    uso direto do JDBC. Mas por favor, espere até você <emphasis>saber </emphasis> se é um gargalo. 
+                    E não suponha que o uso direto do JDBC é necessariamente mais rápido. Se você precisar usar 
+                    diretamente o JDBC, vale a pena abrir uma <literal>Session</literal> do Hibernate e usar uma 
+                    conexão JDBC. De modo que você possa ainda usar a mesma estratégia de transação e ocultar 
+                    o provedor a conexão                    
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Entenda o <literal>Session</literal> flushing.</term>
+            <listitem>
+                <para>
+                    De tempos em tempos a sessão sincroniza seu estado persistente com o banco de dados. O desempenho 
+                    será afetado se este processo ocorrer frequentemente. Você pode algumas vezes minimizar o fluxo 
+                    desnecessário desabilitando o fluxo automático ou até mesmo mudando a ordem das consultas e outras 
+                    operações em uma transação particular.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Em uma arquitetura de três camadas, considere o uso de objetos separados.</term>
+            <listitem>
+                <para>
+                    When using a servlet / session bean architecture, you could pass persistent objects loaded in
+                    the session bean to and from the servlet / JSP layer. Use a new session to service each request. 
+                    Use <literal>Session.merge()</literal> or <literal>Session.saveOrUpdate()</literal> to 
+                    synchronize objects with the database.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>In a two tiered architecture, consider using long persistence contexts.</term>
+            <listitem>
+                <para>
+                    Database Transactions have to be as short as possible for best scalability. However, it is often
+                    neccessary to implement long running <emphasis>application transactions</emphasis>, a single 
+                    unit-of-work from the point of view of a user. An application transaction might span several 
+                    client request/response cycles. It is common to use detached objects to implement application
+                    transactions. An alternative, extremely appropriate in two tiered architecture, is to maintain
+                    a single open persistence contact (session) for the whole lifecycle of the application transaction 
+                    and simply disconnect from the JDBC connection at the end of each request and reconnect at the 
+                    beginning of the subsequent request. Never share a single session across more than one application 
+                    transaction, or you will be working with stale data.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Don't treat exceptions as recoverable.</term>
+            <listitem>
+                <para>
+                    This is more of a necessary practice than a "best" practice. When an exception occurs, roll back
+                    the <literal>Transaction</literal> and close the <literal>Session</literal>. If you don't, Hibernate
+                    can't guarantee that in-memory state accurately represents persistent state. As a special case of this,
+                    do not use <literal>Session.load()</literal> to determine if an instance with the given identifier 
+                    exists on the database; use <literal>Session.get()</literal> or a query instead.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Prefer lazy fetching for associations.</term>
+            <listitem>
+                <para>
+                    Use eager fetching sparingly. Use proxies and lazy collections for most associations to classes that 
+                    are not likely to be completely held in the second-level cache. For associations to cached classes, 
+                    where there is an a extremely high probability of a cache hit, explicitly disable eager fetching using 
+                    <literal>lazy="false"</literal>. When an join fetching is appropriate to a particular use
+                    case, use a query with a <literal>left join fetch</literal>.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>
+                Use the <emphasis>open session in view</emphasis> pattern, or a disciplined 
+                <emphasis>assembly phase</emphasis> to avoid problems with unfetched data.
+            </term>
+            <listitem>
+                <para>
+                    Hibernate frees the developer from writing tedious <emphasis>Data Transfer Objects</emphasis> (DTO). 
+                    In a traditional EJB architecture, DTOs serve dual purposes: first, they work around the problem
+                    that entity beans are not serializable; second, they implicitly define an assembly phase where
+                    all data to be used by the view is fetched and marshalled into the DTOs before returning control 
+                    to the presentation tier. Hibernate eliminates the first purpose. However, you will still need
+                    an assembly phase (think of your business methods as having a strict contract with the presentation
+                    tier about what data is available in the detached objects) unless you are prepared to hold the
+                    persistence context (the session) open across the view rendering process. This is not a limitation
+                    of Hibernate! It is a fundamental requirement of safe transactional data access.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Consider abstracting your business logic from Hibernate.</term>
+            <listitem>
+                <para>
+                    Hide (Hibernate) data-access code behind an interface. Combine the <emphasis>DAO</emphasis> and 
+                    <emphasis>Thread Local Session</emphasis> patterns. You can even have some classes persisted by
+                    handcoded JDBC, associated to Hibernate via a <literal>UserType</literal>. (This advice is 
+                    intended for "sufficiently large" applications; it is not appropriate for an application with
+                    five tables!)
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Don't use exotic association mappings.</term>
+            <listitem>
+                <para>
+                    Good usecases for a real many-to-many associations are rare. Most of the time you need
+                    additional information stored in the "link table". In this case, it is much better to
+                    use two one-to-many associations to an intermediate link class. In fact, we think that
+                    most associations are one-to-many and many-to-one, you should be careful when using any
+                    other association style and ask yourself if it is really neccessary.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>Prefer bidirectional associations.</term>
+            <listitem>
+                <para>
+                    Unidirectional associations are more difficult to query. In a large application, almost
+                    all associations must be navigable in both directions in queries.
+                </para>
+            </listitem>
+        </varlistentry>
+    </variablelist>
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/best_practices.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/collection_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/collection_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/collection_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1238 @@
+<chapter id="collections">
+    <title>Mapeamento de Coleções</title>
+
+    <sect1 id="collections-persistent" revision="3">
+        <title>Persistent collections</title>
+        
+        <para>
+            Hibernate requires that persistent collection-valued fields be declared
+            as an interface type, for example:
+        </para>
+        
+        <programlisting><![CDATA[public class Product {
+    private String serialNumber;
+    private Set parts = new HashSet();
+    
+    public Set getParts() { return parts; }
+    void setParts(Set parts) { this.parts = parts; }
+    public String getSerialNumber() { return serialNumber; }
+    void setSerialNumber(String sn) { serialNumber = sn; }
+}]]></programlisting>
+        
+        <para>
+            The actual interface might be <literal>java.util.Set</literal>,
+            <literal>java.util.Collection</literal>, <literal>java.util.List</literal>,
+            <literal>java.util.Map</literal>, <literal>java.util.SortedSet</literal>,
+            <literal>java.util.SortedMap</literal> or ... anything you like! (Where 
+            "anything you like" means you will have to write an implementation of 
+            <literal>org.hibernate.usertype.UserCollectionType</literal>.)
+        </para>
+        
+        <para>
+            Notice how we initialized the instance variable with an instance of
+            <literal>HashSet</literal>. This is the best way to initialize collection
+            valued properties of newly instantiated (non-persistent) instances. When
+            you make the instance persistent - by calling <literal>persist()</literal>,
+            for example - Hibernate will actually replace the <literal>HashSet</literal>
+            with an instance of Hibernate's own implementation of <literal>Set</literal>.
+            Watch out for errors like this:
+        </para>
+        
+        <programlisting><![CDATA[Cat cat = new DomesticCat();
+Cat kitten = new DomesticCat();
+....
+Set kittens = new HashSet();
+kittens.add(kitten);
+cat.setKittens(kittens);
+session.persist(cat);
+kittens = cat.getKittens(); // Okay, kittens collection is a Set
+(HashSet) cat.getKittens(); // Error!]]></programlisting>
+
+        <para>
+            The persistent collections injected by Hibernate behave like
+            <literal>HashMap</literal>, <literal>HashSet</literal>,
+            <literal>TreeMap</literal>, <literal>TreeSet</literal> or
+            <literal>ArrayList</literal>, depending upon the interface type.
+        </para>
+
+        <para>
+            Collections instances have the usual behavior of value types. They are 
+            automatically persisted when referenced by a persistent object and 
+            automatically deleted when unreferenced. If a collection is passed from one
+            persistent object to another, its elements might be moved from one table to
+            another. Two entities may not share a reference to the same collection 
+            instance. Due to the underlying relational model, collection-valued properties
+            do not support null value semantics; Hibernate does not distinguish between 
+            a null collection reference and an empty collection.
+        </para>
+
+        <para>
+            You shouldn't have to worry much about any of this. Use persistent collections 
+            the same way you use ordinary Java collections. Just make sure you understand 
+            the semantics of bidirectional associations (discussed later).
+        </para>
+
+    </sect1>
+
+    <sect1 id="collections-mapping" revision="4">
+        <title>Collection mappings</title>
+
+        <para>
+            The Hibernate mapping element used for mapping a collection depends upon
+            the type of the interface. For example, a <literal>&lt;set&gt;</literal> 
+            element is used for mapping properties of type <literal>Set</literal>.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Product">
+    <id name="serialNumber" column="productSerialNumber"/>
+    <set name="parts">
+        <key column="productSerialNumber" not-null="true"/>
+        <one-to-many class="Part"/>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Apart from <literal>&lt;set&gt;</literal>, there is also 
+            <literal>&lt;list&gt;</literal>, <literal>&lt;map&gt;</literal>,
+            <literal>&lt;bag&gt;</literal>, <literal>&lt;array&gt;</literal> and
+            <literal>&lt;primitive-array&gt;</literal> mapping elements. The
+            <literal>&lt;map&gt;</literal> element is representative:
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="mappingcollection1" coords="2 65"/>
+                <area id="mappingcollection2" coords="3 65"/>
+                <area id="mappingcollection3" coords="4 65"/>
+                <area id="mappingcollection4" coords="5 65"/>
+                <area id="mappingcollection5" coords="6 65"/>
+                <area id="mappingcollection6" coords="7 65"/>
+                <area id="mappingcollection7" coords="8 65"/>
+                <area id="mappingcollection8" coords="9 65"/>
+                <area id="mappingcollection9" coords="10 65"/>
+                <area id="mappingcollection10" coords="11 65"/>
+                <area id="mappingcollection11" coords="12 65"/>
+                <area id="mappingcollection12" coords="13 65"/>
+                <area id="mappingcollection13" coords="14 65"/>
+                <area id="mappingcollection14" coords="15 65"/>
+            </areaspec>
+            <programlisting><![CDATA[<map
+    name="propertyName"
+    table="table_name"
+    schema="schema_name"
+    lazy="true|extra|false"
+    inverse="true|false"
+    cascade="all|none|save-update|delete|all-delete-orphan|delete-orphan"
+    sort="unsorted|natural|comparatorClass"
+    order-by="column_name asc|desc"
+    where="arbitrary sql where condition"
+    fetch="join|select|subselect"
+    batch-size="N"
+    access="field|property|ClassName"
+    optimistic-lock="true|false"
+    mutable="true|false"
+    node="element-name|."
+    embed-xml="true|false"
+>
+
+    <key .... />
+    <map-key .... />
+    <element .... />
+</map>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="mappingcollection1">
+                    <para>
+                        <literal>name</literal> the collection property name
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection2">
+                    <para>
+                        <literal>table</literal> (optional - defaults to property name) the
+                        name of the collection table (not used for one-to-many associations)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection3">
+                    <para>
+                        <literal>schema</literal> (optional) the name of a table schema to
+                        override the schema declared on the root element
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection4">
+                    <para>
+                        <literal>lazy</literal> (optional - defaults to <literal>true</literal>)
+                        may be used to disable lazy fetching and specify that the association is 
+                        always eagerly fetched, or to enable "extra-lazy" fetching where most 
+                        operations do not initialize the collection (suitable for very large 
+                        collections)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection5">
+                    <para>
+                        <literal>inverse</literal> (optional - defaults to <literal>false</literal>)
+                        mark this collection as the "inverse" end of a bidirectional association
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection6">
+                    <para>
+                        <literal>cascade</literal> (optional - defaults to <literal>none</literal>)
+                        enable operations to cascade to child entities
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection7">
+                    <para>
+                        <literal>sort</literal> (optional) specify a sorted collection with
+                        <literal>natural</literal> sort order, or a given comparator class
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection8">
+                    <para>
+                        <literal>order-by</literal> (optional, JDK1.4 only) specify a table column (or columns)
+                        that define the iteration order of the <literal>Map</literal>, <literal>Set</literal>
+                        or bag, together with an optional <literal>asc</literal> or <literal>desc</literal>
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection9">
+                    <para>
+                        <literal>where</literal> (optional) specify an arbitrary SQL <literal>WHERE</literal>
+                        condition to be used when retrieving or removing the collection (useful if the
+                        collection should contain only a subset of the available data)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection10">
+                    <para>
+                        <literal>fetch</literal> (optional, defaults to <literal>select</literal>) Choose
+                        between outer-join fetching, fetching by sequential select, and fetching by sequential
+                        subselect.
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection11">
+                    <para>
+                        <literal>batch-size</literal> (optional, defaults to <literal>1</literal>) specify a
+                        "batch size" for lazily fetching instances of this collection.
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection12">
+                    <para>
+                        <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+                        strategy Hibernate should use for accessing the collection property value.
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection13">
+                    <para>
+                        <literal>optimistic-lock</literal> (optional - defaults to <literal>true</literal>): 
+                        Species that changes to the state of the collection results in increment of the
+                        owning entity's version. (For one to many associations, it is often reasonable to
+                        disable this setting.)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection14">
+                    <para>
+                        <literal>mutable</literal> (optional - defaults to <literal>true</literal>): 
+                        A value of <literal>false</literal> specifies that the elements of the 
+                        collection never change (a minor performance optimization in some cases).
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <sect2 id="collections-foreignkeys" >
+           <title>Collection foreign keys</title>
+    
+            <para>
+                Collection instances are distinguished in the database by the foreign key of
+                the entity that owns the collection. This foreign key is referred to as the
+                <emphasis>collection key column</emphasis> (or columns) of the collection 
+                table. The collection key column is mapped by the <literal>&lt;key&gt;</literal> 
+                element. 
+            </para>
+    
+            <para>
+                There may be a nullability constraint on the foreign key column. For most
+                collections, this is implied. For unidirectional one to many associations,
+                the foreign key column is nullable by default, so you might need to specify
+                <literal>not-null="true"</literal>.
+            </para>
+    
+            <programlisting><![CDATA[<key column="productSerialNumber" not-null="true"/>]]></programlisting>
+    
+            <para>
+                The foreign key constraint may use <literal>ON DELETE CASCADE</literal>.
+            </para>
+    
+            <programlisting><![CDATA[<key column="productSerialNumber" on-delete="cascade"/>]]></programlisting>
+            
+            <para>
+                See the previous chapter for a full definition of the <literal>&lt;key&gt;</literal> 
+                element.
+            </para>
+            
+        </sect2>
+        
+        <sect2 id="collections-elements" >
+            <title>Collection elements</title>
+    
+            <para>
+                Collections may contain almost any other Hibernate type, including all basic types,
+                custom types, components, and of course, references to other entities. This is an
+                important distinction: an object in a collection might be handled with "value" 
+                semantics (its lifecycle fully depends on the collection owner) or it might be a
+                reference to another entity, with its own lifecycle. In the latter case, only the 
+                "link" between the two objects is considered to be state held by the collection. 
+            </para>
+                
+            <para>
+                The contained type is referred to as the <emphasis>collection element type</emphasis>. 
+                Collection elements are mapped by <literal>&lt;element&gt;</literal> or
+                <literal>&lt;composite-element&gt;</literal>, or in the case of entity references, 
+                with <literal>&lt;one-to-many&gt;</literal> or <literal>&lt;many-to-many&gt;</literal>. 
+                The first two map elements with value semantics, the next two are used to map entity 
+                associations.
+            </para>
+            
+        </sect2>
+        
+        <sect2 id="collections-indexed">
+            <title>Indexed collections</title>
+    
+            <para>
+                All collection mappings, except those with set and bag semantics, need an
+                <emphasis>index column</emphasis> in the collection table - a column that maps to an
+                array index, or <literal>List</literal> index, or <literal>Map</literal> key. The
+                index of a <literal>Map</literal> may be of any basic type, mapped with 
+                <literal>&lt;map-key&gt;</literal>, it may be an entity reference mapped with 
+                <literal>&lt;map-key-many-to-many&gt;</literal>, or it may be a composite type,
+                mapped with <literal>&lt;composite-map-key&gt;</literal>. The index of an array or 
+                list is always of type <literal>integer</literal> and is mapped using the 
+                <literal>&lt;list-index&gt;</literal> element. The mapped column contains 
+                sequential integers (numbered from zero, by default).
+            </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="index1" coords="2 45"/>
+                <area id="index2" coords="3 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<list-index 
+        column="column_name"
+        base="0|1|..."/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="index1">
+                    <para>
+                        <literal>column_name</literal> (required): The name of the column holding the
+                        collection index values.
+                    </para>
+                </callout>
+                <callout arearefs="index1">
+                    <para>
+                        <literal>base</literal> (optional, defaults to <literal>0</literal>): The value
+                        of the index column that corresponds to the first element of the list or array.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <programlistingco>
+            <areaspec>
+                <area id="mapkey1" coords="2 45"/>
+                <area id="mapkey2" coords="3 45"/>
+                <area id="mapkey3" coords="4 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<map-key 
+        column="column_name"
+        formula="any SQL expression"
+        type="type_name"
+        node="@attribute-name"
+        length="N"/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="mapkey1">
+                    <para>
+                        <literal>column</literal> (optional): The name of the column holding the
+                        collection index values.
+                    </para>
+                </callout>
+                <callout arearefs="mapkey2">
+                    <para>
+                        <literal>formula</literal> (optional): A SQL formula used to evaluate the
+                        key of the map.
+                    </para>
+                </callout>
+                <callout arearefs="mapkey3">
+                    <para>
+                        <literal>type</literal> (reguired): The type of the map keys.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <programlistingco>
+            <areaspec>
+                <area id="indexmanytomany1" coords="2 45"/>
+                <area id="indexmanytomany2" coords="3 45"/>
+                <area id="indexmanytomany3" coords="3 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<map-key-many-to-many
+        column="column_name"
+        formula="any SQL expression"
+        class="ClassName"
+/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="indexmanytomany1">
+                    <para>
+                        <literal>column</literal> (optional): The name of the foreign key
+                        column for the collection index values.
+                    </para>
+                </callout>
+                <callout arearefs="indexmanytomany2">
+                    <para>
+                        <literal>formula</literal> (optional): A SQL formula used to evaluate the
+                        foreign key of the map key.
+                    </para>
+                </callout>
+                <callout arearefs="indexmanytomany3">
+                    <para>
+                        <literal>class</literal> (required): The entity class used as the map key.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+
+            <para>
+                If your table doesn't have an index column, and you still wish to use <literal>List</literal> 
+                as the property type, you should map the property as a Hibernate <emphasis>&lt;bag&gt;</emphasis>.
+                A bag does not retain its order when it is retrieved from the database, but it may be 
+                optionally sorted or ordered.
+            </para>
+            
+        </sect2>
+
+        <para>
+            There are quite a range of mappings that can be generated for collections, covering 
+            many common relational models. We suggest you experiment with the schema generation tool 
+            to get a feeling for how various mapping declarations translate to database tables.
+        </para>
+
+    <sect2 id="collections-ofvalues" revision="2">
+        <title>Collections of values and many-to-many associations</title>
+
+        <para>
+            Any collection of values or many-to-many association requires a dedicated 
+            <emphasis>collection table</emphasis> with a foreign key column or columns, 
+            <emphasis>collection element column</emphasis> or columns and possibly 
+            an index column or columns.
+        </para>
+
+        <para>
+            For a collection of values, we use the <literal>&lt;element&gt;</literal> tag.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="element1b" coords="2 50"/>
+                <area id="element2b" coords="3 50"/>
+                <area id="element3b" coords="4 50"/>
+             </areaspec>
+            <programlisting><![CDATA[<element
+        column="column_name"
+        formula="any SQL expression"
+        type="typename"
+        length="L"
+        precision="P"
+        scale="S"
+        not-null="true|false"
+        unique="true|false"
+        node="element-name"
+/>]]></programlisting>
+            <calloutlist>
+                <callout arearefs="element1b">
+                    <para>
+                        <literal>column</literal> (optional): The name of the column holding the
+                        collection element values.
+                    </para>
+                </callout>
+                <callout arearefs="element2b">
+                    <para>
+                        <literal>formula</literal> (optional): An SQL formula used to evaluate the
+                        element.
+                    </para>
+                </callout>
+                <callout arearefs="element3b">
+                    <para>
+                        <literal>type</literal> (required): The type of the collection element.
+                    </para>
+                </callout>
+            </calloutlist>
+        </programlistingco>
+
+        <para>
+            A <emphasis>many-to-many association</emphasis> is specified using the 
+            <literal>&lt;many-to-many&gt;</literal> element.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="manytomany1" coords="2 60"/>
+                <area id="manytomany2" coords="3 60"/>
+                <area id="manytomany3" coords="4 60"/>
+                <area id="manytomany4" coords="5 60"/>
+                <area id="manytomany5" coords="6 60"/>
+                <area id="manytomany6" coords="7 60"/>
+                <area id="manytomany7" coords="8 60"/>
+                <area id="manytomany8" coords="9 60"/>
+            </areaspec>
+            <programlisting><![CDATA[<many-to-many
+        column="column_name"
+        formula="any SQL expression"
+        class="ClassName"
+        fetch="select|join"
+        unique="true|false"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        property-ref="propertyNameFromAssociatedClass"
+        node="element-name"
+        embed-xml="true|false"
+    />]]></programlisting>
+            <calloutlist>
+                <callout arearefs="manytomany1">
+                    <para>
+                        <literal>column</literal> (optional): The name of the element foreign key column.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany2">
+                    <para>
+                        <literal>formula</literal> (optional): An SQL formula used to evaluate the element
+                        foreign key value.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany3">
+                    <para>
+                        <literal>class</literal> (required): The name of the associated class.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany4">
+                    <para>
+                        <literal>fetch</literal> (optional - defaults to <literal>join</literal>):
+                        enables outer-join or sequential select fetching for this association. This
+                        is a special case; for full eager fetching (in a single <literal>SELECT</literal>)
+                        of an entity and its many-to-many relationships to other entities, you would
+                        enable <literal>join</literal> fetching not only of the collection itself,
+                        but also with this attribute on the <literal>&lt;many-to-many&gt;</literal>
+                        nested element.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany5">
+                    <para>
+                        <literal>unique</literal> (optional): Enable the DDL generation of a unique
+                        constraint for the foreign-key column. This makes the association multiplicity
+                        effectively one to many.
+                    </para>
+                </callout>
+	            <callout arearefs="manytomany6">
+	                <para>
+	                    <literal>not-found</literal> (optional - defaults to <literal>exception</literal>): 
+	                    Specifies how foreign keys that reference missing rows will be handled: 
+	                    <literal>ignore</literal> will treat a missing row as a null association.
+	                </para>
+	            </callout>
+                <callout arearefs="manytomany7">
+                    <para>
+                        <literal>entity-name</literal> (optional): The entity name of the associated class,
+                        as an alternative to <literal>class</literal>.
+                    </para>
+                </callout>
+                <callout arearefs="manytomany8">
+                    <para>
+                        <literal>property-ref</literal>: (optional) The name of a property of the associated 
+                        class that is joined to this foreign key. If not specified, the primary key of
+                        the associated class is used.
+                    </para>                
+                </callout>                   
+            </calloutlist>
+        </programlistingco>
+
+        <para>
+            Some examples, first, a set of strings:
+        </para>
+
+        <programlisting><![CDATA[<set name="names" table="person_names">
+    <key column="person_id"/>
+    <element column="person_name" type="string"/>
+</set>]]></programlisting>
+
+        <para>
+            A bag containing integers (with an iteration order determined by the
+            <literal>order-by</literal> attribute):
+        </para>
+
+        <programlisting><![CDATA[<bag name="sizes" 
+        table="item_sizes" 
+        order-by="size asc">
+    <key column="item_id"/>
+    <element column="size" type="integer"/>
+</bag>]]></programlisting>
+
+        <para>
+            An array of entities - in this case, a many to many association:
+        </para>
+
+        <programlisting><![CDATA[<array name="addresses" 
+        table="PersonAddress" 
+        cascade="persist">
+    <key column="personId"/>
+    <list-index column="sortOrder"/>
+    <many-to-many column="addressId" class="Address"/>
+</array>]]></programlisting>
+
+        <para>
+            A map from string indices to dates:
+        </para>
+
+        <programlisting><![CDATA[<map name="holidays" 
+        table="holidays" 
+        schema="dbo" 
+        order-by="hol_name asc">
+    <key column="id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            A list of components (discussed in the next chapter):
+        </para>
+
+        <programlisting><![CDATA[<list name="carComponents" 
+        table="CarComponents">
+    <key column="carId"/>
+    <list-index column="sortOrder"/>
+    <composite-element class="CarComponent">
+        <property name="price"/>
+        <property name="type"/>
+        <property name="serialNumber" column="serialNum"/>
+    </composite-element>
+</list>]]></programlisting>
+
+    </sect2>
+
+    <sect2 id="collections-onetomany">
+        <title>One-to-many associations</title>
+
+        <para>
+            A <emphasis>one to many association</emphasis> links the tables of two classes
+            via a foreign key, with no intervening collection table. This mapping loses 
+            certain semantics of normal Java collections:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    An instance of the contained entity class may not belong to more than
+                    one instance of the collection
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    An instance of the contained entity class may not appear at more than
+                    one value of the collection index
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            An association from <literal>Product</literal> to <literal>Part</literal> requires 
+            existence of a foreign key column and possibly an index column to the <literal>Part</literal> 
+            table. A <literal>&lt;one-to-many&gt;</literal> tag indicates that this is a one to many 
+            association.
+        </para>
+
+        <programlistingco>
+            <areaspec>
+                <area id="onetomany1" coords="2 60"/>
+                <area id="onetomany2" coords="3 60"/>
+                <area id="onetomany3" coords="4 60"/>
+            </areaspec>
+            <programlisting><![CDATA[<one-to-many 
+        class="ClassName"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        node="element-name"
+        embed-xml="true|false"
+    />]]></programlisting>
+            <calloutlist>
+                <callout arearefs="onetomany1">
+                    <para>
+                        <literal>class</literal> (required): The name of the associated class.
+                    </para>
+                </callout>
+		        <callout arearefs="onetomany2">
+		            <para>
+		                <literal>not-found</literal> (optional - defaults to <literal>exception</literal>): 
+		                Specifies how cached identifiers that reference missing rows will be handled: 
+		                <literal>ignore</literal> will treat a missing row as a null association.
+		            </para>
+		        </callout>
+                <callout arearefs="onetomany3">
+                    <para>
+                        <literal>entity-name</literal> (optional): The entity name of the associated class,
+                        as an alternative to <literal>class</literal>.
+                    </para>
+                </callout>
+            </calloutlist>
+       </programlistingco>
+  
+        <para>
+            Notice that the <literal>&lt;one-to-many&gt;</literal> element does not need to
+            declare any columns. Nor is it necessary to specify the <literal>table</literal>
+            name anywhere.
+        </para>
+
+        <para>
+            <emphasis>Very important note:</emphasis> If the foreign key column of a 
+            <literal>&lt;one-to-many&gt;</literal> association is declared <literal>NOT NULL</literal>, 
+            you must declare the <literal>&lt;key&gt;</literal> mapping 
+            <literal>not-null="true"</literal> or <emphasis>use a bidirectional association</emphasis> 
+            with the collection mapping marked <literal>inverse="true"</literal>. See the discussion 
+            of bidirectional associations later in this chapter.
+        </para>
+        
+        <para>
+            This example shows a map of <literal>Part</literal> entities by name (where
+            <literal>partName</literal> is a persistent property of <literal>Part</literal>).
+            Notice the use of a formula-based index.
+        </para>
+
+        <programlisting><![CDATA[<map name="parts"
+        cascade="all">
+    <key column="productId" not-null="true"/>
+    <map-key formula="partName"/>
+    <one-to-many class="Part"/>
+</map>]]></programlisting>
+    </sect2>
+    
+    </sect1>
+
+    <sect1 id="collections-advancedmappings">
+        <title>Advanced collection mappings</title>
+
+    <sect2 id="collections-sorted" revision="2">
+        <title>Sorted collections</title>
+
+        <para>
+            Hibernate supports collections implementing <literal>java.util.SortedMap</literal> and
+            <literal>java.util.SortedSet</literal>. You must specify a comparator in the mapping file:
+        </para>
+
+        <programlisting><![CDATA[<set name="aliases" 
+            table="person_aliases" 
+            sort="natural">
+    <key column="person"/>
+    <element column="name" type="string"/>
+</set>
+
+<map name="holidays" sort="my.custom.HolidayComparator">
+    <key column="year_id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            Allowed values of the <literal>sort</literal> attribute are <literal>unsorted</literal>,
+            <literal>natural</literal> and the name of a class implementing
+            <literal>java.util.Comparator</literal>.
+        </para>
+
+        <para>
+            Sorted collections actually behave like <literal>java.util.TreeSet</literal> or
+            <literal>java.util.TreeMap</literal>.
+        </para>
+
+        <para>
+            If you want the database itself to order the collection elements use the
+            <literal>order-by</literal> attribute of <literal>set</literal>, <literal>bag</literal>
+            or <literal>map</literal> mappings. This solution is only available under
+            JDK 1.4 or higher (it is implemented using <literal>LinkedHashSet</literal> or
+            <literal>LinkedHashMap</literal>). This performs the ordering in the SQL query, 
+            not in memory.
+        </para>
+
+        <programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="lower(name) asc">
+    <key column="person"/>
+    <element column="name" type="string"/>
+</set>
+
+<map name="holidays" order-by="hol_date, hol_name">
+    <key column="year_id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date type="date"/>
+</map>]]></programlisting>
+
+        <para>
+            Note that the value of the <literal>order-by</literal> attribute is an SQL ordering, not
+            a HQL ordering!
+        </para>
+
+        <para>
+            Associations may even be sorted by some arbitrary criteria at runtime using a collection
+            <literal>filter()</literal>.
+        </para>
+
+        <programlisting><![CDATA[sortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list();]]></programlisting>
+
+    </sect2>
+
+     <sect2 id="collections-bidirectional" revision="1">
+        <title>Bidirectional associations</title>
+
+        <para>
+            A <emphasis>bidirectional association</emphasis> allows navigation from both
+            "ends" of the association. Two kinds of bidirectional association are
+            supported:
+
+            <variablelist>
+                <varlistentry>
+                    <term>one-to-many</term>
+                    <listitem>
+                        <para>
+                            set or bag valued at one end, single-valued at the other
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>many-to-many</term>
+                    <listitem>
+                        <para>
+                            set or bag valued at both ends
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+        </para>
+
+        <para>
+            You may specify a bidirectional many-to-many association simply by mapping two
+            many-to-many associations to the same database table and declaring one end as
+            <emphasis>inverse</emphasis> (which one is your choice, but it can not be an
+            indexed collection).
+        </para>
+
+        <para>
+            Here's an example of a bidirectional many-to-many association; each category can
+            have many items and each item can be in many categories:
+        </para>
+
+        <programlisting><![CDATA[<class name="Category">
+    <id name="id" column="CATEGORY_ID"/>
+    ...
+    <bag name="items" table="CATEGORY_ITEM">
+        <key column="CATEGORY_ID"/>
+        <many-to-many class="Item" column="ITEM_ID"/>
+    </bag>
+</class>
+
+<class name="Item">
+    <id name="id" column="CATEGORY_ID"/>
+    ...
+
+    <!-- inverse end -->
+    <bag name="categories" table="CATEGORY_ITEM" inverse="true">
+        <key column="ITEM_ID"/>
+        <many-to-many class="Category" column="CATEGORY_ID"/>
+    </bag>
+</class>]]></programlisting>
+
+        <para>
+            As mudanças feitas somente de um lado da associação <emphasis>não</emphasis> são 
+            persistidas. Isto significa que o Hibernate tem duas representações na memória 
+            para cada associação bidirecional, uma associação de A para B e uma outra 
+            associação de B para A. Isto é mais fácil de compreender se você pensa 
+            sobre o modelo do objetos do Java e como nós criamos um relacionamento muitos 
+            para muitos em Java:
+        </para>
+
+        <programlisting><![CDATA[
+category.getItems().add(item);          // The category now "knows" about the relationship
+item.getCategories().add(category);     // The item now "knows" about the relationship
+
+session.persist(item);                   // The relationship won't be saved!
+session.persist(category);               // The relationship will be saved]]></programlisting>
+
+        <para>
+            A outra ponta é usada salvar a representação em memória à base de dados.
+        </para>
+
+        <para>
+            Você pode definir uma associação bidirecional um para muitos através de uma associação 
+            um-para-muitos indicando as mesmas colunas da tabela que à associação muitos-para-um  e 
+            declarando a propriedade <literal>inverse="true"</literal> 
+
+        </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <set name="children" inverse="true">
+        <key column="parent_id"/>
+        <one-to-many class="Child"/>
+    </set>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        not-null="true"/>
+</class>]]></programlisting>
+
+        <para>
+            Mapear apenas uma das pontas da associação com <literal>inverse="true"</literal> 
+            não afeta as operações em cascata, isso é um conceito ortogonal.
+        </para>
+
+    </sect2>
+
+    <sect2 id="collections-indexedbidirectional">
+        <title>Associações bidirecionais com coleções indexadas</title>
+        <para>
+            Uma associação bidirecional onde uma dos lados e representa pôr uma 
+            <literal>&lt;list&gt;</literal> ou <literal>&lt;map&gt;</literal> requer uma consideração 
+            especial. Se houver uma propriedade da classe filha que faça o mapeamento da coluna do 
+            índice, sem  problema, pode-se continuar usando <literal>inverse="true"</literal>  no 
+            mapeamento da coleção.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <map name="children" inverse="true">
+        <key column="parent_id"/>
+        <map-key column="name" 
+            type="string"/>
+        <one-to-many class="Child"/>
+    </map>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <property name="name" 
+        not-null="true"/>
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        not-null="true"/>
+</class>]]></programlisting>
+
+        <para>
+            Mas, se não houver nenhuma propriedade na classe filha, não podemos ver essa associação 
+            como verdadeiramente bidirecional (há uma informação disponível em um lado da associação 
+            que não está disponível no extremo oposto). Nesse caso, nos não podemos mapear a coleção 
+            usando <literal>inverse="true"</literal>. Nos devemos usar o seguinte mapeamento:
+        </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <map name="children">
+        <key column="parent_id"
+            not-null="true"/>
+        <map-key column="name" 
+            type="string"/>
+        <one-to-many class="Child"/>
+    </map>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        insert="false"
+        update="false"
+        not-null="true"/>
+</class>]]></programlisting>
+
+       <para>
+           Veja que neste mapeamento, que um dos lado da associação, a coleção, é responsável pela 
+           atualização da chave estrangeira. TODO: Isso realmente resulta em updates desnecessários ?.       
+       </para>
+
+    </sect2>
+    
+    <sect2 id="collections-ternary">
+        <title>Associações Ternárias</title>
+
+        <para>
+            Há três meios possíveis de se mapear uma associação ternária. Uma é usar um 
+            <literal>Map</literal> com uma associação como seu índice:            
+        </para>
+
+        <programlisting><![CDATA[<map name="contracts">
+    <key column="employer_id" not-null="true"/>
+    <map-key-many-to-many column="employee_id" class="Employee"/>
+    <one-to-many class="Contract"/>
+</map>]]></programlisting>
+            
+            <programlisting><![CDATA[<map name="connections">
+    <key column="incoming_node_id"/>
+    <map-key-many-to-many column="outgoing_node_id" class="Node"/>
+    <many-to-many column="connection_id" class="Connection"/>
+</map>]]></programlisting>
+            
+        <para>
+            A segunda maneira é simplesmente remodelar a associação das classes da entidade.
+             Esta é a maneira que nós usamos de uma maneira geral.
+        </para>
+        
+        <para>
+            Uma alternativa final é usar os elementos compostos, que nós 
+            discutiremos mais tarde.
+        </para>
+        
+    </sect2>
+    
+    <sect2 id="collections-idbag" revision="1">
+        <title><literal>Usando o &lt;idbag&gt;</literal></title>
+
+        <para>
+            Se você concorda com nossa visão que chaves compostas são uma coisa ruim e que 
+            as entidades devem ter identificadores sintéticos (surrogate keys), então você 
+            deve estar achando um pouco estranho que as associações muitos para muitos 
+            usando coleções de valores que nós mostramos estejam mapeadas com chaves 
+            compostas! Bem, este ponto é bastante discutível; um simples tabela de associação 
+            não parece se beneficiar muito de uma surrogate key (entretanto uma coleção de 
+            valores compostos <emphasis>sim</emphasis>). Opcionalmente, o Hibernate prove 
+            uma maneira de mapear uma associação muitos para muitos com uma coleção 
+            de valores para uma tabela com uma surrogate key. 
+        </para>
+
+        <para>
+            O elemento <literal>&lt;idbag&gt;</literal> permite mapear um <literal>List</literal>
+            (ou uma  <literal>Collection</literal> com uma semântica de bag.
+        </para>
+
+<programlisting><![CDATA[<idbag name="lovers" table="LOVERS">
+    <collection-id column="ID" type="long">
+        <generator class="sequence"/>
+    </collection-id>
+    <key column="PERSON1"/>
+    <many-to-many column="PERSON2" class="Person" fetch="join"/>
+</idbag>]]></programlisting>
+
+        <para>
+            Como você pode ver, um <literal>&lt;idbag&gt;</literal> possui um gerador de id 
+            sintético, igual uma classe de entidade! Uma surrogate key diferente é associada 
+            para cada elemento de coleção. Porém, o Hibernate não prove nenhum mecanismo 
+            para descobrir qual a surrogate key de uma linha em particular.
+        </para>
+
+        <para>
+            Note que o desempenho de atualização de um <literal>&lt;idbag&gt;</literal> é 
+            <emphasis>much</emphasis> melhor que um <literal>&lt;bag&gt;</literal> normal! 
+            O Hibernate pode localizar uma linha individual eficazmente e atualizar ou 
+            deletar individualmente, como um list, map ou set.
+        </para>
+
+        <para>
+            Na implementação atual, a estratégia de geração de identificador  <literal>native</literal> 
+            não é suportada para identificadores de coleção usando o <literal>&lt;idbag&gt;</literal>.
+        </para>
+
+    </sect2>
+
+    </sect1>
+    
+    <!--undocumenting this stuff -->
+    
+    <!--sect1 id="collections-heterogeneous">
+        <title>Heterogeneous Associations</title>
+
+        <para>
+            The <literal>&lt;many-to-any&gt;</literal> and <literal>&lt;index-many-to-any&gt;</literal>
+            elements provide for true heterogeneous associations. These mapping elements work in the
+            same way as the <literal>&lt;any&gt;</literal> element - and should also be used
+            rarely, if ever.
+        </para>
+
+    </sect1-->
+
+    <sect1 id="collections-example" revision="1">
+        <title>Exemplos de coleções</title>
+
+        <para>
+            As seções anteriores são uma grande confusão. Assim sendo vejamos uma exemplo. 
+            Essa classe:            
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+
+public class Parent {
+    private long id;
+    private Set children;
+
+    public long getId() { return id; }
+    private void setId(long id) { this.id=id; }
+
+    private Set getChildren() { return children; }
+    private void setChildren(Set children) { this.children=children; }
+
+    ....
+    ....
+}]]></programlisting>
+
+        <para>
+            tem uma coleção de instancias de <literal>Child</literal>. Se 
+            cada Child  tiver no máximo um parent, o mapeamento natural é 
+            uma associação um para muitos:             
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children">
+            <key column="parent_id"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Esse mapeamento gera a seguinte definição de tabelas
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255), parent_id bigint )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+        <para>
+            Se o parent for <emphasis>obrigatório</emphasis>, use uma associação bidirecional 
+            um para muitos:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children" inverse="true">
+            <key column="parent_id"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+        <many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Repare na constraint <literal>NOT NULL</literal>: 
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null
+                     primary key,
+                     name varchar(255),
+                     parent_id bigint not null )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+        <para>
+            Uma outra alternativa, no caso de você insistir que esta associação devea ser 
+            unidirecional, você pode declarar a constraint como <literal>NOT NULL</literal> 
+            na tag <literal>&lt;key&gt;</literal> do mapeamento:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children">
+            <key column="parent_id" not-null="true"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Por outro lado, se uma child puder ter os múltiplos parents, a associação 
+            apropriada é muitos-para-muitos:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children" table="childset">
+            <key column="parent_id"/>
+            <many-to-many class="Child" column="child_id"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            Definições das tabelas:
+        </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255) )
+create table childset ( parent_id bigint not null,
+                        child_id bigint not null,
+                        primary key ( parent_id, child_id ) )
+alter table childset add constraint childsetfk0 (parent_id) references parent
+alter table childset add constraint childsetfk1 (child_id) references child]]></programlisting>
+
+        <para>
+            For more examples and a complete walk-through a parent/child relationship mapping,
+            see <xref linkend="example-parentchild"/>.
+            Para mais exemplos e um exemplo completo de mapeamento de relacionamento 
+            de mestre/detalhe, veja <xref linkend="example-parentchild"/>. 
+        </para>
+        
+        <para>
+            Até mesmo o mapeamento de associações mais exóticas são possíveis, nós catalogaremos 
+            todas as possibilidades no próximo capítulo.
+        </para>
+
+    </sect1>
+
+</chapter>


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/collection_mapping.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/component_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/component_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/component_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,413 @@
+<chapter id="components">
+    <title>Mapeamento de Componentes</title>
+
+    <para>
+        A noção de <emphasis>componente</emphasis>  é reusada em vários contextos diferentes, 
+        para propósitos diferentes, pelo Hibernate.
+
+
+    </para>
+
+    <sect1 id="components-dependentobjects" revision="2" >
+        <title>Objetos dependentes</title>
+
+        <para>
+            Um componente é um objeto contido que é persistido como um tipo de valor, não uma 
+            referência de entidade. O termo "componente" refere-se à noção de composição da 
+            orientação a objetos (não a componentes no nível de arquitetura). Por exemplo, você 
+            pode modelar uma pessoa desta maneira:
+        </para>
+
+        <programlisting><![CDATA[public class Person {
+    private java.util.Date birthday;
+    private Name name;
+    private String key;
+    public String getKey() {
+        return key;
+    }
+    private void setKey(String key) {
+        this.key=key;
+    }
+    public java.util.Date getBirthday() {
+        return birthday;
+    }
+    public void setBirthday(java.util.Date birthday) {
+        this.birthday = birthday;
+    }
+    public Name getName() {
+        return name;
+    }
+    public void setName(Name name) {
+        this.name = name;
+    }
+    ......
+    ......
+}]]></programlisting>
+
+<programlisting><![CDATA[public class Name {
+    char initial;
+    String first;
+    String last;
+    public String getFirst() {
+        return first;
+    }
+    void setFirst(String first) {
+        this.first = first;
+    }
+    public String getLast() {
+        return last;
+    }
+    void setLast(String last) {
+        this.last = last;
+    }
+    public char getInitial() {
+        return initial;
+    }
+    void setInitial(char initial) {
+        this.initial = initial;
+    }
+}]]></programlisting>
+
+        <para>
+            Agora <literal>Name</literal> pode ser persistido como um componente 
+            de <literal>Person</literal>. Note que <literal>Name</literal> define métodos 
+            getter e setter para suas propriedades persistentes, mas não necessita declarar 
+            nenhuma interface ou propriedades identificadoras.
+        </para>
+
+        <para>
+            Nosso mapeamento do Hibernate seria semelhante a isso
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Person" table="person">
+    <id name="Key" column="pid" type="string">
+        <generator class="uuid"/>
+    </id>
+    <property name="birthday" type="date"/>
+    <component name="Name" class="eg.Name"> <!-- class attribute optional -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </component>
+</class>]]></programlisting>
+
+        <para>
+            A tabela pessoa teria as seguintes colunas  <literal>pid</literal>,
+            <literal>birthday</literal>,
+            <literal>initial</literal>,
+            <literal>first</literal> and
+            <literal>last</literal>.
+        </para>
+
+        <para>
+            Assim como todos tipos por valor, componentes não suportam referencias cruzadas. Em 
+            outras palavras, duas pessoas poderiam possuir o mesmo nome, mas os dois objetos 
+            pessoa poderiam conter dois objetos nome independentes, apenas com "o mesmo" por valor. 
+            A semântica dos valores null de um componente são <emphasis>ad hoc</emphasis>. No 
+            recarregameno do conteúdo do objeto, O Hibernate assumira que se todas as colunas 
+            do componente são null, então todo o componente é null. Isto seria o certo para 
+            a maioria dos propósitos.
+        </para>
+
+        <para>
+            As propriedades de um componente podem ser de qualquer tipo do Hibernate(collections, 
+            associações muitos-para-um, outros componentes, etc). Componentes agrupados 
+            <emphasis>não </emphasis> devem ser consideros um uso exótico. O Hibernate tem 
+            a intenção de suportar um modelo de objetos muito bem granulado.
+        </para>
+
+        <para>
+            O elemento <literal>&lt;component&gt;</literal> permite um subelemento 
+            <literal>&lt;parent&gt;</literal> que mapeia uma propriedade da classe componente 
+            como uma referência de volta para a entidade que a contém.
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Person" table="person">
+    <id name="Key" column="pid" type="string">
+        <generator class="uuid"/>
+    </id>
+    <property name="birthday" type="date"/>
+    <component name="Name" class="eg.Name" unique="true">
+        <parent name="namedPerson"/> <!-- reference back to the Person -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </component>
+</class>]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="components-incollections" revision="1">
+        <title>Collections de objetos dependentes</title>
+
+        <para>
+            Collections de componentes são suportadadas(ex. uma array de 
+            tipo <literal>Name</literal>). Declare a sua collection de 
+            componentes substituindo a tag<literal>&lt;element&gt;</literal>
+            pela tag <literal>&lt;composite-element&gt;</literal>.
+        </para>
+
+        <programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
+    <key column="id"/>
+    <composite-element class="eg.Name"> <!-- class attribute required -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </composite-element>
+</set>]]></programlisting>
+
+        <para>
+            Nota: se você definir um  <literal>Set</literal> de elementos compostos, 
+            é muito importante implementar  <literal>equals()</literal> e 
+            <literal>hashCode()</literal> corretamente.
+        </para>
+
+        <para>
+            Elementos compostos podem conter componentes mas não collections. Se o 
+            seu elemento composto contiver componentes , use a tag 
+            <literal>&lt;nested-composite-element&gt;</literal> . Este é um caso 
+            bastante exótico – uma collections de componentes que por si própria 
+            possui componentes. Neste momento você deve estar se perguntando se 
+            uma associação de um-para-muitos seria mais apropriada. Tente remodelar 
+            o elemento composto como uma entidade – mas note que mesmo pensando 
+            que o modelo Java é o mesmo, o modelo relacional e a semântica de 
+            persistência  ainda são diferentes.
+        </para>
+
+        <para>
+            Por favor, note que um mapeamento de elemento composto não suporta propriedades 
+            capazes de serem null se você estiver usando um <literal>&lt;set&gt;</literal>. 
+            O Hibernate tem que usar cada valor das colunas para identificar um registro 
+            quando estiver deletando objetos (não existe coluna chave primária separada na 
+            tabela de elemento composto), que não é possível com valores null. 
+            Você tem que usar um dos dois, ou apenas propriedades não null em um elemento 
+            composto ou escolher uma <literal>&lt;list&gt;</literal>, 
+            <literal>&lt;map&gt;</literal>, <literal>&lt;bag&gt;</literal> ou
+            <literal>&lt;idbag&gt;</literal>.
+        </para>
+
+        <para>
+            Um caso especial de elemento composto é um elemento composto com um elemento 
+            <literal>&lt;many-to-one&gt;</literal>  aninhado. Um mapeamento como este 
+            permite você a mapear colunas extras de uma tabela de associação de 
+            muitos-para-muitos para a classe de elemento composto. A seguinte 
+            associação de muitos-para-muitos de <literal>Order</literal> para um
+            <literal>Item</literal> onde <literal>purchaseDate</literal>, 
+            <literal>price</literal> e <literal>quantity</literal> são propriedades 
+            da associação:
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Order" .... >
+    ....
+    <set name="purchasedItems" table="purchase_items" lazy="true">
+        <key column="order_id">
+        <composite-element class="eg.Purchase">
+            <property name="purchaseDate"/>
+            <property name="price"/>
+            <property name="quantity"/>
+            <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Claro, que não pode ter uma referência para purchase no outro lado, para a 
+            navegação da associação bidirecional. Lembre-se que componentes são tipos por 
+            valor e não permitem referências compartilhadas. Uma classe <literal>Purchase</literal>
+            simples pode estar no set de uma classe <literal>Order</literal>, mas ela não 
+            pode ser referenciada por <literal>Item</literal> no mesmo momento.
+        </para>
+
+        <para>Até mesmo associações ternárias (ou quaternária, etc) são possíveis:</para>
+
+
+        <programlisting><![CDATA[<class name="eg.Order" .... >
+    ....
+    <set name="purchasedItems" table="purchase_items" lazy="true">
+        <key column="order_id">
+        <composite-element class="eg.OrderLine">
+            <many-to-one name="purchaseDetails class="eg.Purchase"/>
+            <many-to-one name="item" class="eg.Item"/>
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Elementos compostos podem aparecer em pesquisas usando a mesma 
+            sintaxe assim como associações para outras entidades.
+        </para>
+
+    </sect1>
+
+    <sect1 id="components-asmapindex">
+        <title>Componentes como índices de Map</title>
+
+        <para>
+            O elemento <literal>&lt;composite-map-key&gt;</literal> permite você mapear 
+            uma classe componente como uma chave de um <literal>Map</literal>. Tenha 
+            certeza que você sobrescreveu <literal>hashCode()</literal> e
+            <literal>equals()</literal>  corretamente na classe componente.
+        </para>
+    </sect1>
+
+    <sect1 id="components-compositeid" revision="1">
+        <title>. Componentes como identificadores compostos</title>
+
+        <para>
+            Você pode usar um componente como um identificador de uma classe entidade. 
+            Sua classe componente deve satisfazer certos requisitos:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                   Ele deve implementar <literal>java.io.Serializable</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Ele deve re-implementar <literal>equals()</literal> e
+                    <literal>hashCode()</literal>, consistentemente com a noção 
+                    de igualdade de chave composta do banco de dados.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            <emphasis>Nota: no Hibernate 3, o segundo requisito não é um requisito absolutamente 
+            necessário.  Mas atenda ele de qualquer forma.</emphasis>
+        </para>
+
+        <para>
+            Você não pode usar um <literal>IdentifierGenerator</literal> para gerar chaves compostas. 
+            Ao invés disso o aplicativo deve gerenciar seus próprios identificadores.
+        </para>
+
+        <para>
+            Use a tag  <literal>&lt;composite-id&gt;</literal> (com elementos 
+            <literal>&lt;key-property&gt;</literal> aninhados) no lugar da declaração 
+            <literal>&lt;id&gt;</literal> de costume. Por exemplo, a classe 
+            <literal>OrderLine</literal> possui uma chave primária que depende da 
+            chave primária (composta) de <literal>Order</literal>.
+        </para>
+
+        <programlisting><![CDATA[<class name="OrderLine">
+    
+    <composite-id name="id" class="OrderLineId">
+        <key-property name="lineId"/>
+        <key-property name="orderId"/>
+        <key-property name="customerId"/>
+    </composite-id>
+    
+    <property name="name"/>
+    
+    <many-to-one name="order" class="Order"
+            insert="false" update="false">
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </many-to-one>
+    ....
+    
+</class>]]></programlisting>
+
+        <para>
+            Agora, qualquer chave estrangeira referenciando a tabela <literal>OrderLine</literal>
+            também serão compostas. Você deve declarar isto em seus mapeamentos para outras 
+            classes. Uma associação para <literal>OrderLine</literal> seria mapeada dessa forma:
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
+<!-- the "class" attribute is optional, as usual -->
+    <column name="lineId"/>
+    <column name="orderId"/>
+    <column name="customerId"/>
+</many-to-one>]]></programlisting>
+
+        <para>
+            (Note que a tag  <literal>&lt;column&gt;</literal> é uma alternativa para o 
+            atributo  <literal>column</literal> por toda a parte.)
+
+
+        </para>
+        
+        <para>
+            Uma associação <literal>many-to-many</literal> para <literal>many-to-many</literal>
+            também usa a chave estrangeira composta:
+        </para>
+    
+    <programlisting><![CDATA[<set name="undeliveredOrderLines">
+    <key column name="warehouseId"/>
+    <many-to-many class="OrderLine">
+        <column name="lineId"/>
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </many-to-many>
+</set>]]></programlisting>
+
+        <para>
+            A collection de <literal>OrderLine</literal>s em <literal>Order</literal> usaria:
+        </para>
+
+    <programlisting><![CDATA[<set name="orderLines" inverse="true">
+    <key>
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </key>
+    <one-to-many class="OrderLine"/>
+</set>]]></programlisting>
+
+        <para>
+            (O elemento <literal>&lt;one-to-many&gt;</literal>, como de costume, não declara colunas.)
+
+
+        </para>
+        
+        <para>
+            Se <literal>OrderLine</literal> possui uma collection, ela também tem uma 
+            chave estrangeira composta.
+        </para>
+
+        <programlisting><![CDATA[<class name="OrderLine">
+    ....
+    ....
+    <list name="deliveryAttempts">
+        <key>   <!-- a collection inherits the composite key type -->
+            <column name="lineId"/>
+            <column name="orderId"/>
+            <column name="customerId"/>
+        </key>
+        <list-index column="attemptId" base="1"/>
+        <composite-element class="DeliveryAttempt">
+            ...
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="components-dynamic" revision="1">
+        <title>Componentes Dinâmicos</title>
+
+        <para>
+            Você pode até mesmo mapear uma propriedade do tipo <literal>Map</literal>:
+        </para>
+
+    <programlisting><![CDATA[<dynamic-component name="userAttributes">
+    <property name="foo" column="FOO" type="string"/>
+    <property name="bar" column="BAR" type="integer"/>
+    <many-to-one name="baz" class="Baz" column="BAZ_ID"/>
+</dynamic-component>]]></programlisting>
+
+        <para>
+            A semântica de um mapeamento <literal>&lt;dynamic-component&gt;</literal> é idêntica 
+            à <literal>&lt;component&gt;</literal>. A vantagem deste tipo de mapeamento é a 
+            habilidade de determinar as propriedades atuais do bean no momento de deploy, 
+            apenas editando o documento de mapeamento. A Manipulação em tempo de execução do 
+            documento de mapeamento também é possível, usando o parser DOM. Até melhor, 
+            você pode acessar (e mudar) o metamodelo configuration-time do Hibernate 
+            através do objeto <literal>Configuration</literal>.
+        </para>
+
+    </sect1>
+
+</chapter>


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/component_mapping.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/configuration.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/configuration.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/configuration.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1789 @@
+<chapter id="session-configuration" revision="1">
+
+    <title>Configuração</title>
+    
+    <para>
+        Devido ao fato de o Hibernate ser projetado para operar em vários ambientes diferentes, 
+        há um grande número de parâmetros de configuração. Felizmente, a maioria tem valores default 
+        lógicos e o Hibernate é distribuído com um arquivo <literal>hibernate.properties</literal> 
+        de exemplo no <literal>etc/</literal> que mostra várias opções. Apenas coloque o arquivo 
+        de exemplo no seu classpath e personalize-o.
+    </para>
+
+    <sect1 id="configuration-programmatic" revision="1">
+        <title>1.11 Configuração programática</title>
+
+        <para>
+            Uma instância de <literal>org.hibernate.cfg.Configuration</literal>
+            representa um conjunto inteiro de mapeamentos de tipos Java da aplicação para 
+            um banco de dados SQL. O <literal>Configuration</literal> é usado para construir 
+            uma <literal>SessionFactory</literal> (imutável). Os mapeamentos são compilados 
+            a partir de arquivos de mapeamento XML.
+
+        </para>
+
+        <para>
+            Você pode obter uma instância <literal>Configuration</literal> intanciando-
+            o diretamente e especificando documentos de mapeamento XML. Se o arquivo 
+            de mapeamento estão no classpath, use use <literal>addResource()</literal>:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addResource("Item.hbm.xml")
+    .addResource("Bid.hbm.xml");]]></programlisting>
+
+        <para>
+            Uma alternativa (às vezes melhor) é especificar a classe mapeada, 
+            e permitir que o Hibernate encontre o documento de mapeamento para você: 
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addClass(org.hibernate.auction.Item.class)
+    .addClass(org.hibernate.auction.Bid.class);]]></programlisting>
+
+        <para>
+            Então o Hibernate procurará pelos arquivos de mapeamento chamados 
+            <literal>/org/hibernate/auction/Item.hbm.xml</literal> e
+            <literal>/org/hibernate/auction/Bid.hbm.xml</literal> no classpath.
+            Esta abordagem elimina qualquer nome de arquivo de difícil compreensão.
+        </para>
+        
+        <para>
+            Uma <literal>Configuration</literal> também permite você especificar 
+            propriedades de configuração:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addClass(org.hibernate.auction.Item.class)
+    .addClass(org.hibernate.auction.Bid.class)
+    .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
+    .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
+    .setProperty("hibernate.order_updates", "true");]]></programlisting>
+    
+        <para>
+            Este não é o único caminho para passar as propriedades de configuração 
+            para o Hibernate. As várias opções incluem:
+        </para>
+
+        <orderedlist spacing="compact">
+            <listitem>
+                <para>
+                    Passar uma instância de <literal>java.util.Properties</literal> 
+                    para <literal>Configuration.setProperties()</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Colocar <literal>hibernate.properties</literal> no diretório 
+                    raiz do classpath.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Determinar as propriedades do <literal>System</literal> 
+                    usando <literal>java -Dproperty=value</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Include <literal>&lt;property&gt;</literal> elements in
+                    <literal>hibernate.cfg.xml</literal> (discussed later).
+                    Incluir elementos <literal>&lt;property&gt;</literal> no 
+                    <literal>hibernate.cfg.xml</literal> (discutido mais tarde).
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <para>
+            <literal>hibernate.properties</literal>  é o caminho mais facil 
+            se você quer começar mais rápido.
+        </para>
+
+        <para>
+            O <literal>Configuration</literal> é entendido como um objeto startup-time, 
+            é descartado uma vez que a <literal>SessionFactory</literal> é criada.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="configuration-sessionfactory">
+        <title>Obtendo uma SessionFactory</title>
+
+        <para>
+            Quando todos os mapeamentos têm sido analisados pelo <literal>Configuration</literal>, 
+            a aplicação deve obter uma factory para as instâncias da <literal>Session</literal>. 
+            O objetivo desta factory é ser compartilhado por todas as threads da aplicação:
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sessions = cfg.buildSessionFactory();]]></programlisting>
+
+        <para>
+            Hibernate permite sua aplicação instanciar mais do que uma 
+            <literal>SessionFactory</literal>. Isto é útil se você está usando mais 
+            do que um banco de dados.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-hibernatejdbc" revision="1">
+        <title>Conexões JDBC</title>
+
+        <para>
+            Normalmente, você quer mandar criar a  <literal>SessionFactory</literal>  criar um
+            pool de conexões JDBC para você. Se você seguir essa abordagem, a abertura de uma 
+            <literal>Session</literal> é tão simples quanto:
+
+        </para>
+
+        <programlisting><![CDATA[Session session = sessions.openSession(); // open a new Session]]></programlisting>
+        
+        <para>
+            Assim que você fizer algo que requer o acesso ao banco de dados, uma 
+            conexão JDBC será obtida do pool.
+        </para>
+
+        <para>
+            Para esse trabalho, nós necessitamos passar algumas propriedades da conexão JDBC 
+            para o Hibernate. Todos os nomes de propriedades Hibernate e semânticas são definidas 
+            <literal>org.hibernate.cfg.Environment</literal>. Nós iremos descrever agora 
+            o mais importantes configurações de conexão JDBC.
+        </para>
+
+        <para>
+            O Hibernate obterá conexões( e pool) usando <literal>java.sql.DriverManager</literal>
+            se você determinar as seguintes propriedades:
+        </para>
+
+        <table frame="topbot">
+            <title>Propriedades JDBC Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nome da Propriedade</entry>
+                        <entry>Propósito</entry>
+                    </row>
+                </thead>
+            <tbody>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.driver_class</literal>
+                </entry>
+                <entry>
+                    <emphasis>Classe driver jdbc</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.url</literal>
+                </entry>
+                <entry>
+                    <emphasis>URL jdbc</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.username</literal>
+                </entry>
+                <entry>
+                    <emphasis>Usuário do banco de dados</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.password</literal>
+                </entry>
+                <entry>
+                    <emphasis>Senha do usuário do banco de dados</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.pool_size</literal>
+                </entry>
+                <entry>
+                    <emphasis>Número máximo de connecxões no pool</emphasis>
+                </entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+            O algoritmo de pool de conexões do próprio Hibernate entretanto é completamente 
+            rudimentar. A intenção dele e ajudar a iniciar e <emphasis>não para usar em um 
+            sistema de produção</emphasis> ou até para testar desempenho. Você deveria usar 
+            uma ferramente de pool de terceiros para conseguir melhor desempenho e estabilidade. 
+            Apenas especifique a propriedade <literal>hibernate.connection.pool_size</literal> 
+            com a definição do pool de conexões. Isto irá desligar o pool interno do Hibernate. 
+            Por exemplo, você pode gostar de usar C3P0.
+        </para>
+
+        <para>
+            O C3P0 é um pool conexão JDBC de código aberto distribuído junto com 
+            Hibernate       no diretório <literal>lib</literal>. O Hibernate usará o 
+            <literal>C3P0ConnectionProvider</literal> para o pool de conexão se 
+            você configurar a propriedade <literal>hibernate.c3p0.*</literal>. Se você 
+            gostar de usar Proxool consulte ao pacote <literal>hibernate.properties</literal> 
+            e o web site do Hibernate para mais informações.
+        </para>
+
+        <para>
+            Aqui é um exemplo de arquivo <literal>hibernate.properties</literal> para C3P0:
+        </para>
+
+        <programlisting id="c3p0-configuration" revision="1"><![CDATA[hibernate.connection.driver_class = org.postgresql.Driver
+hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
+hibernate.connection.username = myuser
+hibernate.connection.password = secret
+hibernate.c3p0.min_size=5
+hibernate.c3p0.max_size=20
+hibernate.c3p0.timeout=1800
+hibernate.c3p0.max_statements=50
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+        <para>
+            Para usar dentro de um servidor de aplicação, você deve configurar 
+            o Hibernate para obter conexões de um application server  
+            <literal>Datasource</literal> registrado no JNDI. Você necessitará 
+            determinar pelo menos uma das seguintes propriedades:
+        </para>
+
+        <table frame="topbot">
+            <title>Propriedades do Datasource do Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nome da Propriedade</entry>
+                        <entry>Propósito</entry>
+                    </row>
+                </thead>
+            <tbody>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.datasource</literal>
+                </entry>
+                <entry>
+                    <emphasis>Nome datasource JNDI</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.jndi.url</literal>
+                </entry>
+                <entry>
+                    <emphasis>URL do fornecedor JNDI</emphasis> (opcional)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.jndi.class</literal>
+                </entry>
+                <entry>
+                    <emphasis>Classe do JNDI <literal>InitialContextFactory</literal></emphasis> (opcional)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.username</literal>
+                </entry>
+                <entry>
+                    <emphasis>Usuário do banco de dados</emphasis> (opcional)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.password</literal>
+                </entry>
+                <entry>
+                    <emphasis>Senha do usuário do banco de dados</emphasis> (opcional)
+                </entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+            Eis um exemplo de arquivo <literal>hibernate.properties</literal> para 
+            um servidor de aplicação fornecedor de datasources JNDI:
+        </para>
+
+        <programlisting><![CDATA[hibernate.connection.datasource = java:/comp/env/jdbc/test
+hibernate.transaction.factory_class = \
+    org.hibernate.transaction.JTATransactionFactory
+hibernate.transaction.manager_lookup_class = \
+    org.hibernate.transaction.JBossTransactionManagerLookup
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+        <para>
+            Conexões JDBC obtidas de um datasource JNDI irão automaticamente irão participar 
+            das transações gerenciadas pelo container no servidor de aplicação.
+        </para>
+
+        <para>
+            Arbitrariamente as propriedades de conexão podem ser acrescentandas ao 
+            "<literal>hibernate.connnection</literal>" ao nome da propriedade. Por exemplo, 
+            você deve especificar o <literal>charSet</literal> usando <literal>hibernate.connection.charSet</literal>.t.
+        </para>
+
+        <para>
+            Você pode definir sua própria estratégia de plugin para obter conexões JDBC implementando 
+            a interface <literal>org.hibernate.connection.ConnectionProvider</literal>. Você pode 
+            escolher uma implementação customizada setando <literal>hibernate.connection.provider_class</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-optional" revision="1">
+        <title>Propriedades opcionais de configuração</title>
+        
+        <para>
+            Há um grande número de outras propriedades que controlam o comportamento do Hibernate 
+            em tempo de execução. Todos são opcionais e tem valores default lógicos.
+        </para>
+
+        <para>
+            <emphasis>Aviso: algumas destas propriedades são somente a "nível de sistema".</emphasis>
+            Propriedades nível de sistema podem ser determinados somente via <literal>java -Dproperty=value</literal>
+            ou <literal>hibernate.properties</literal>. Elas <emphasis>não</emphasis>podem ser 
+            configuradas por outras técnicas descritas abaixo.
+        </para>
+
+        <table frame="topbot" id="configuration-optional-properties" revision="8">
+            <title>Hibernate Configuration Properties</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nome da Propriedade</entry>
+                        <entry>Propósito</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.dialect</literal>
+                        </entry>
+                        <entry>
+                            O nome da classe de um <literal>Dialeto</literal> 
+                            que permite o Hibernate gerar SQL otimizado para um banco de 
+                            dados relacional em particular.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>full.classname.of.Dialect</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.show_sql</literal>
+                        </entry>
+                        <entry>
+                            Escreve todas as instruções SQL no console. Esta é uma alternativa 
+                            a configurar a categoria de log <literal>org.hibernate.SQL</literal>
+                            para <literal>debug</literal>.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.format_sql</literal>
+                        </entry>
+                        <entry>
+                            Imprime o SQL formatado no log e console.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_schema</literal>
+                        </entry>
+                        <entry>
+                            Qualifica no sql gerado, os nome das tabelas sem qualificar 
+                            com schena/tablespace dado
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>SCHEMA_NAME</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_catalog</literal>
+                        </entry>
+                        <entry>
+                            Qualifica no sql gerado, os nome das tabelas sem qualificar 
+                            com catálogo dado
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>CATALOG_NAME</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.session_factory_name</literal>
+                        </entry>
+                        <entry>
+                            O <literal>SessionFactory</literal> irá automaticamente 
+                            se ligar a este nome no JNDI depois de ter sido criado.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>jndi/composite/name</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.max_fetch_depth</literal>
+                        </entry>
+                        <entry>
+                            Estabelece a "profundidade" máxima para árvore outer join fetch 
+                            para associações finais únicas(one-to-one,many-to-one). 
+                            Um <literal>0</literal> desativa por default a busca outer join.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                Valores recomendados entre<literal>0</literal> e <literal>3</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_batch_fetch_size</literal>
+                        </entry>
+                        <entry>
+                            Determina um tamanho default para busca de associações em lotes do Hibernate 
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                Valores recomendados <literal>4</literal>, <literal>8</literal>, 
+                                <literal>16</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_entity_mode</literal>
+                        </entry>
+                        <entry>
+                            Determina um modo default para representação de entidades 
+                            para todas as sessões abertas desta <literal>SessionFactory</literal>
+                            <para>
+                                <literal>dynamic-map</literal>, <literal>dom4j</literal>,
+                                <literal>pojo</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.order_updates</literal>
+                        </entry>
+                        <entry>
+                            Força o Hibernate a ordenar os updates SQL pelo valor da chave 
+                            primária dos itens a serem atualizados. Isto resultará em menos 
+                            deadlocks nas transações em sistemas altamente concorrente.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.generate_statistics</literal>
+                        </entry>
+                        <entry>
+                            If enabled, Hibernate will collect statistics useful for
+                            performance tuning.
+                            Se habilitado, o Hibernate coletará estatísticas úties 
+                            para performance tuning dos bancos.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.use_identifer_rollback</literal>
+                        </entry>
+                        <entry>
+                            Se habilitado, propriedades identificadoras geradas 
+                            serão zeradas para os valores default quando os 
+                            objetos forem apagados.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.use_sql_comments</literal>
+                        </entry>
+                        <entry>
+                            Se ligado, o Hibernate irá gerar comentários dentro do SQL, 
+                            para facilitar o debugging, o valor default é <literal>false</literal>.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-jdbc-properties" revision="8">
+            <title>JDBC Hibernate e Propriedades de Conexão</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nome da Propriedade</entry>
+                        <entry>Propósito</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.fetch_size</literal>
+                        </entry>
+                        <entry>
+                            Um valor maior que zero determina o tamanho do fetch 
+                            do JDBC( chamadas <literal>Statement.setFetchSize()</literal>).
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.batch_size</literal>
+                        </entry>
+                        <entry>
+                            Um valor maior que zero habilita uso de batch updates JDBC2 pelo Hibernate.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis>
+                                valores recomentados entre <literal>5</literal> e <literal>30</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.batch_versioned_data</literal>
+                        </entry>
+                        <entry>
+                            Sete esta propriedade como <literal>true</literal> se seu driver JDBC retorna 
+                            o número correto de linhas no <literal>executeBatch()</literal> ( É usualmente 
+                            seguro tornar esta opção ligada). O Hibernate então irá usar betched DML 
+                            para automaticamente versionar dados.  <literal>false</literal> por default.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.factory_class</literal>
+                        </entry>
+                        <entry>
+                            Escolher um <literal>Batcher</literal> customizado. Muitas 
+                            aplicações não irão necessitar desta propriedade de configuração
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis>
+                                <literal>classname.of.Batcher</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_scrollable_resultset</literal>
+                        </entry>
+                        <entry>
+                            Habilita o uso de JDBC2 scrollable resultsets pelo Hibernate.
+                            Essa propriedade somente é necessaria quando se usa Conexeções
+                            JDBC providas pelo usuário, caso contrário o Hibernate os os 
+                            metadados da conexão.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_streams_for_binary</literal>
+                        </entry>
+                        <entry>
+                            Use streams para escrever/ler tipos <literal>binary</literal>
+                            ou <literal>serializable</literal> para/a o JDBC( propriedade a nível de sistema).
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_get_generated_keys</literal>
+                        </entry>
+                        <entry>
+                            Possibilita o uso <literal>PreparedStatement.getGeneratedKeys()</literal> 
+                            do JDBC3 para recuperar chaves geradas nativamente depois da inserçãp. 
+                            Requer driver JDBC3+ e JRE1.4+, determine para false se seu driver tem 
+                            problemas com gerador de indentificadores Hibernate. Por default, tente 
+                            determinar o driver capaz de usar metadados da conexão.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis>
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.provider_class</literal>
+                        </entry>
+                        <entry>
+                            O nome da classe de um <literal>ConnectionProvider</literal> personalizado
+                            o qual proverá conexões JDBC para o Hibernate.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>classname.of.ConnectionProvider</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                    <entry>
+                        <literal>hibernate.connection.isolation</literal>
+                    </entry>
+                    <entry>
+                        Determina o nível de isolamento de uma transação JDBC. 
+                        Verifique <literal>java.sql.Connection</literal> para valores 
+                        siginificativos mas note que a maior parte dos bancos de dados 
+                        não suportam todos os níveis de isolamento.
+                        <para>
+                            <emphasis role="strong">Ex.</emphasis> 
+                            <literal>1, 2, 4, 8</literal>
+                        </para>
+                    </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.autocommit</literal>
+                        </entry>
+                        <entry>
+                            Habilita autocommit para conexões no pool JDBC( não recomendado).
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.release_mode</literal>
+                        </entry>
+                        <entry>
+                            Especifica quando o Hibernate deve liberar conexões JDBC. Por default, 
+                            uma conexão JDBC é retida até a sessão está explicitamente fechada 
+                            ou desconectada. Para um datasource JTA do servidor de aplicação, você deve 
+                            usar <literal>after_statement</literal> para forçar s liberação da conexões 
+                            depois de todas as chamadas JDBC. Para uma conexão não-JTA, freqüentemente 
+                            faz sentido liberar a conexão ao fim de cada transação, usando
+                            <literal>after_transaction</literal>. <literal>auto</literal> escolheremos
+                            <literal>after_statement</literal>  para as estratégias de transaçãoes JTA e CMT 
+                            e <literal>after_transaction</literal> para as estratégias de transação JDBC
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>auto</literal> (default) | <literal>on_close</literal> |
+                                <literal>after_transaction</literal> | <literal>after_statement</literal>
+                            </para>
+                            <para>
+                                Note that this setting only affects <literal>Session</literal>s returned from
+                                <literal>SessionFactory.openSession</literal>.  For <literal>Session</literal>s
+                                obtained through <literal>SessionFactory.getCurrentSession</literal>, the
+                                <literal>CurrentSessionContext</literal> implementation configured for use
+                                controls the connection release mode for those <literal>Session</literal>s.
+                                See <xref linkend="architecture-current-session"/>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                    <entry>
+                        <literal>hibernate.connection.<emphasis>&lt;propertyName&gt;</emphasis></literal>
+                    </entry>
+                    <entry>
+                        Passa a propriedade JDBC <literal>propertyName</literal> 
+                        para <literal>DriverManager.getConnection()</literal>.
+                    </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jndi.<emphasis>&lt;propertyName&gt;</emphasis></literal>
+                        </entry>
+                        <entry>
+                            Passar a propriedade <literal>propertyName</literal> para 
+                            o <literal>InitialContextFactory</literal> JNDI.
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-cache-properties" revision="7">
+            <title>Propriedades de Cachê do Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nome da Propriedade</entry>
+                        <entry>Propósito</entry>
+                    </row>
+                </thead>
+                <tbody>
+                     <row>
+                        <entry>
+                            <literal>hibernate.cache.provider_class</literal>
+                        </entry>
+                        <entry>
+                            O nome da classe de um <literal>CacheProvider</literal> customizado.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>classname.of.CacheProvider</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_minimal_puts</literal>
+                        </entry>
+                        <entry>
+                            Otimizar operação de cachê de segundo nível para minimizar escritas, 
+                            ao custo de leituras mais frequantes. Esta configuração é mais útil 
+                            para cachês clusterizados e, no Hibernate3, é habilitado por default 
+                            para implementações de cachê clusterizar.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_query_cache</literal>
+                        </entry>
+                        <entry>
+                            Habilita a cache de consultas, Mesmo assim, consultas individuais ainda tem que ser 
+                            habilitadas para o cache.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_second_level_cache</literal>
+                        </entry>
+                        <entry>
+                            May be used to completely disable the second level cache, which is enabled
+                            by default for classes which specify a <literal>&lt;cache&gt;</literal>
+                            mapping.
+                            Pode ser usada para desabilitar completamente ocache de segundo nível, 
+                            o qual está habilitado por default para classes que especificam 
+                            um mapeamento <literal>&lt;cache&gt;</literal>.
+
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.query_cache_factory</literal>
+                        </entry>
+                        <entry>
+                            O nome de uma classe que implementa a interface 
+                            <literal>QueryCache</literal> personalizada, por 
+                            default, um <literal>StandardQueryCache</literal>
+                            criado automaticamente.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis>
+                                <literal>classname.of.QueryCache</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.region_prefix</literal>
+                        </entry>
+                        <entry>
+                            Um prefixo para usar nos nomes da área especial 
+                            do cachê de segundo nível.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>prefix</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_structured_entries</literal>
+                        </entry>
+                        <entry>
+                            Forces Hibernate to store data in the second-level cache
+                            in a more human-friendly format.
+                            Força o Hibernate armazenar dados no cachê se segundo 
+                            nível em um formato mais legivel.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis>
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-transaction-properties" revision="9">
+            <title>Propriedades de Transação do Hibernate</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nome da Propriedade</entry>
+                        <entry>Propósito</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.factory_class</literal>
+                        </entry>
+                        <entry>
+                            O nome da clase de um a <literal>TransactionFactory</literal>
+                            para usar com API <literal>Transaction</literal>
+                            ( por default JDBCTransactionFactory).
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>classname.of.TransactionFactory</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>jta.UserTransaction</literal>
+                        </entry>
+                        <entry>
+                            Um nome JNDI usado pelo <literal>JTATransactionFactory</literal> 
+                            para obter uma <literal>UserTransaction</literal> JTA a partir 
+                            do servidor de aplicação.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>jndi/composite/name</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.manager_lookup_class</literal>
+                        </entry>
+                        <entry>
+                            O nome da classe de um <literal>TransactionManagerLookup</literal>
+                            – requerido quando caching a nível JVM esta habilitado ou quando 
+                            estivermos usando um generator hilo em um ambiente JTA.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>classname.of.TransactionManagerLookup</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.flush_before_completion</literal>
+                        </entry>
+                        <entry>
+                            Se habilitado, a sessão será automaticamente limpa antes da fase de 
+                            conclusão da transação. É preferivel a gerência interna e 
+                            automática do contexto da sessão, veja
+                            <xref linkend="architecture-current-session"/>
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.auto_close_session</literal>
+                        </entry>
+                        <entry>
+                            Se habilitado, a sessão será automaticamente fechada após a fase de
+                             conclusão da transação. É preferivel a gerência interna e 
+                            automática do contexto da sessão, veja
+                            <xref linkend="architecture-current-session"/>
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-misc-properties" revision="10">
+            <title>Propriedades Variadas</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>Nome da Propriedade</entry>
+                        <entry>Propósito</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.current_session_context_class</literal>
+                        </entry>
+                        <entry>
+                            Forneçe uma estratégia (personalizada) para extensão 
+                            da <literal>Session</literal> "corrente". Veja 
+                             <xref linkend="architecture-current-session"/> para 
+                             mais informação sobre estratégias internas.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis>
+                                <literal>jta</literal> | <literal>thread</literal> |
+                                <literal>managed</literal> | <literal>custom.Class</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.query.factory_class</literal>
+                        </entry>
+                        <entry>
+                            Escolha a implementação de análise HQL.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> or
+                                <literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.query.substitutions</literal>
+                        </entry>
+                        <entry>
+                            Mapeamento a partir de símbolos em consultas HQL para 
+                            símbolos SQL( símbolos devem ser funções ou nome literais
+                            , por exemplo).
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.hbm2ddl.auto</literal>
+                        </entry>
+                        <entry>
+                            Automaticamente valida ou exporta schema DDL para o banco de 
+                            dados quando o <literal>SessionFactory</literal>  é criads.
+                            Com <literal>create-drop</literal>, o schema do banco de dados 
+                            será excluido quando a <literal>create-drop</literal> for
+                            fechada esplicitamente.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>validate</literal> | <literal>update</literal> | 
+                                <literal>create</literal> | <literal>create-drop</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cglib.use_reflection_optimizer</literal>
+                        </entry>
+                        <entry>
+                            Habilita o uso de CGLIB em vez de reflexão em tempo de execução
+                            ( propriedade a nível de sistema). Reflexão pode algumas vezes ser ú
+                            til quando controlar erros, note que o Hibernate sempre irá requerer a CGLIB 
+                            mesmo se você desligar o otimizador. Você não pode determinar esta 
+                            propriedade no hibernate.cfg.xml.
+                            <para>
+                                <emphasis role="strong">Ex.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <sect2 id="configuration-optional-dialects" revision="1">
+            <title>Dialetos SQL</title>
+
+            <para>
+                Você deve sempre determinar a propriedade <literal>hibernate.dialect</literal> 
+                para a subclasse de <literal>org.hibernate.dialect.Dialect</literal>  correta de seu 
+                banco de dados. Se você especificar um dialeto, Hibernate usará defaults lógicos 
+                para qualquer um das outras propriedades listadas abaixo, reduzindo o esforço de 
+                especificá-los manualmente. 
+            </para>
+
+            <table frame="topbot" id="sql-dialects" revision="2">
+                <title>Hibernate SQL Dialects (<literal>hibernate.dialect</literal>)</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>RDBMS</entry>
+                            <entry>Dialect</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry>DB2</entry> <entry><literal>org.hibernate.dialect.DB2Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>DB2 AS/400</entry> <entry><literal>org.hibernate.dialect.DB2400Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>DB2 OS390</entry> <entry><literal>org.hibernate.dialect.DB2390Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>PostgreSQL</entry> <entry><literal>org.hibernate.dialect.PostgreSQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL</entry> <entry><literal>org.hibernate.dialect.MySQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL with InnoDB</entry> <entry><literal>org.hibernate.dialect.MySQLInnoDBDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL with MyISAM</entry> <entry><literal>org.hibernate.dialect.MySQLMyISAMDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Oracle (any version)</entry> <entry><literal>org.hibernate.dialect.OracleDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Oracle 9i/10g</entry> <entry><literal>org.hibernate.dialect.Oracle9Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Sybase</entry> <entry><literal>org.hibernate.dialect.SybaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Sybase Anywhere</entry> <entry><literal>org.hibernate.dialect.SybaseAnywhereDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Microsoft SQL Server</entry> <entry><literal>org.hibernate.dialect.SQLServerDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>SAP DB</entry> <entry><literal>org.hibernate.dialect.SAPDBDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Informix</entry> <entry><literal>org.hibernate.dialect.InformixDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>HypersonicSQL</entry> <entry><literal>org.hibernate.dialect.HSQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Ingres</entry> <entry><literal>org.hibernate.dialect.IngresDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Progress</entry> <entry><literal>org.hibernate.dialect.ProgressDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Mckoi SQL</entry> <entry><literal>org.hibernate.dialect.MckoiDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Interbase</entry> <entry><literal>org.hibernate.dialect.InterbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Pointbase</entry> <entry><literal>org.hibernate.dialect.PointbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>FrontBase</entry> <entry><literal>org.hibernate.dialect.FrontbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Firebird</entry> <entry><literal>org.hibernate.dialect.FirebirdDialect</literal></entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-outerjoin" revision="4">
+            <title>Recuperação por união externa (Outer Join Fetching)</title>
+
+            <para>
+                Se seu banco de dados suporta Recuperação por união externa (Outer Join Fetching) no estilo ANSI, 
+                Oracle ou Sybase, A recuperação por união externa (Outer Join Fetching) frequentemente aumentará
+                o desempenho limitando o número de chamadas (round trips) ao banco de dados( ao custo de 
+                possivelmente mais trabalho desempenhado pelo próprio banco de dados). A recuperação por 
+                união externa (Outer Join Fetching)permite um gráfico completo de objetos conectados 
+                por muitos-para-um, um-para-muitos, muitos-para-muitos e associações um-para-um para ser 
+                recuperadas em um simples instrução SQL SELECT .
+
+            </para>
+
+            <para>
+                A recuperação por união externa (Outer Join Fetching) pode ser desabilitado 
+                <emphasis>globalmente</emphasis> setando a propriedade 
+                <literal>hibernate.max_fetch_depth</literal> para <literal>0</literal>. 
+                Uma valor 1 ou maior habilita o outer join fetching para associações um-para-um 
+                e muitos-para-umos cujos quais tem sido mapeado com <literal>fetch="join"</literal>.
+            </para>
+
+            <para>
+                Veja <xref linkend="performance-fetching"/> para mais informações.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-binarystreams" revision="1">
+            <title>Fluxos Binários (Binary Streams)</title>
+
+            <para>
+                O Oracle limita o tamanho de arrays de <literal>byte</literal> que pode ser 
+                passado para/de o driver JDBC. Se você desejar usar grandes instâncias de 
+                tipos  <literal>binary</literal> ou <literal>serializable</literal>, você 
+                deve habilitar <literal>hibernate.jdbc.use_streams_for_binary</literal>.
+                <emphasis>Essa é uma configuração que só pode ser feita a nível de sistema.</emphasis>
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-cacheprovider" revision="2">
+            <title>Cachê de segundo nível e query</title>
+
+            <para>
+                As propriedades prefixadas pelo <literal>hibernate.cache</literal> 
+                permite você usar um sistema de cachê de segundo nível 
+                em um processo executado em clustercom Hibernate. 
+                Veja <xref linkend="performance-cache"/> para mais detalhes.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-querysubstitution">
+            <title>Substituições na Linguagem de Consulta</title>
+
+            <para>
+                Você pode definir novos símbolos de consulta Hibernate usando 
+                <literal>hibernate.query.substitutions</literal>. 
+                Por exemplo:
+            </para>
+
+            <programlisting>hibernate.query.substitutions true=1, false=0</programlisting>
+
+            <para>
+                Faria com que os símbolos <literal>true</literal> e <literal>false</literal> 
+                passasem a ser traduzidos para literais inteiro no SQL gerado.
+            </para>
+
+            <programlisting>hibernate.query.substitutions toLowercase=LOWER</programlisting>
+
+            <para>
+                permitirá você renomear a função <literal>LOWER</literal> no SQL.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-statistics" revision="2">
+            <title>Estatísticas do Hibernate</title>
+
+            <para>
+                If you enable <literal>hibernate.generate_statistics</literal>, Hibernate will 
+                expose a number of metrics that are useful when tuning a running system via
+                <literal>SessionFactory.getStatistics()</literal>. Hibernate can even be configured
+                to expose these statistics via JMX. Read the Javadoc of the interfaces in
+                <literal>org.hibernate.stats</literal> for more information.
+                
+                Se você habilitar <literal>hibernate.generate_statistics</literal>, o Hibernate 
+                exibirá um número de métricas bastante útil ao ajustar um sistema via
+                <literal>SessionFactory.getStatistics()</literal>. O Hibernate pode até ser 
+                configurado para exibir essas estatísticas via JMX. Leia o Javadoc da interface
+                <literal>org.hibernate.stats</literal> para mais informações.
+            </para>
+
+        </sect2>
+    </sect1>
+
+    <sect1 id="configuration-logging">
+        <title>Logging</title>
+
+        <para>
+            Hibernate registra vários eventos usando Apache commons-logging.
+        </para>
+
+        <para>
+            O serviço commons-logging direcionará a saída para o Apache Log4j
+            ( se você incluir <literal>log4j.jar</literal>r no seu classpath) ou 
+            JDK1.4 logging( se estiver em uso JDK1.4 ou maior). Você pode fazer o 
+            download do Log4j a partir de  <literal>http://jakarta.apache.org</literal>.
+            Para usar Log4j você necessitará colocar um arquivo 
+            <literal>log4j.properties</literal> no seu classpath, um exemplo de arquivo
+            de propriedades é distribuído com o Hibernate no diretório 
+            <literal>src/</literal>.
+
+        </para>
+        
+        <para>
+            We strongly recommend that you familiarize yourself with Hibernate's log
+            messages. A lot of work has been put into making the Hibernate log as
+            detailed as possible, without making it unreadable. It is an essential
+            troubleshooting device. The most interesting log categories are the
+            following:
+            
+            Nós recomendamos enfaticamente que você se familiarize-se com mensagens de 
+            log do Hibernate. Uma parte do trabalho tem sido posto em fazer o log 
+            Hibernate tão detalhado quanto possível, sem fazê-lo ilegível. 
+            É um essencial dispositivos de controle de erros. As categorias de log 
+            mais interessantes são as seguintes:
+        </para>
+        
+            <table frame="topbot" id="log-categories" revision="2">
+                <title>Categorias de Log do Hibernate</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>Categoria</entry>
+                            <entry>Função</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>org.hibernate.SQL</literal></entry>
+                            <entry>Registra todas as instruções SQL DML a medida que elas são executadas</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.type</literal></entry>
+                            <entry>Registra todos os parâmetros JDBC</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.tool.hbm2ddl</literal></entry>
+                            <entry>Registra todas as instruções SQL DDL a medida que elas são executadas</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.pretty</literal></entry>
+                            <entry>
+                                Log the state of all entities (max 20 entities) associated
+                                with the session at flush time
+                                Registra o estado de todas as entidades (máximo 20 entidades) 
+                                associadas a session no momento da limpeza (flush).
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.cache</literal></entry>
+                            <entry>Registra todas as atividades de cachê de segundo nível</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction</literal></entry>
+                            <entry>Registra atividades relacionada a transação</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.jdbc</literal></entry>
+                            <entry>Registra todas as requisições de recursos JDBC</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.hql.ast.AST</literal></entry>
+                            <entry>
+                                Registra instruções SQL e HQL durante a análise da consultas
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.secure</literal></entry>
+                            <entry>Registra todas as requisições de autorização JAAS</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate</literal></entry>
+                            <entry>
+                                Registra tudo ( uma parte das informações, mas muito 
+                                útil para controle de erros )
+                            </entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+            
+        <para>
+            Quando desenvolver aplicações com Hibernate, você deve quase sempre trabalhar com 
+            debug <literal>debug</literal>  para a categoria <literal>org.hibernate.SQL</literal>, 
+            ou, alternativamente, a com a propriedade <literal>hibernate.show_sql</literal> habilitada.
+        </para>
+                       
+        
+    </sect1>
+
+    <sect1 id="configuration-namingstrategy">
+        <title>Implementado uma <literal>NamingStrategy</literal></title>
+
+        <para>
+            A interface <literal>org.hibernate.cfg.NamingStrategy</literal> permite você 
+            especificar um "padrão de nomeação" para objetos do banco de dados e elementos schema.
+        </para>
+
+        <para>
+            Você deve criar regras para a geração automaticamente de identificadores 
+            do banco de dados a partir de identificadores Java ou para processar  
+            colunas "computadas" e nomes de tabelas dado o arquivo de mapeamento 
+            para nomes "físicos" de tabelas e colunas. Esta característica ajuda a 
+            reduzir a verbosidade do documento de mapeamento, eliminando interferências 
+            repetitivas( <literal>TBL_</literal>prefixos, por exemplo). A estratégia 
+            default usada pelo Hibernate é completamente mínima.
+        </para>
+
+        <para>
+            Você pode especificar uma estratégia diferente ao chamar 
+            <literal>Configuration.setNamingStrategy()</literal> antes de adicionar 
+            os mapeamentos:
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sf = new Configuration()
+    .setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
+    .addFile("Item.hbm.xml")
+    .addFile("Bid.hbm.xml")
+    .buildSessionFactory();]]></programlisting>
+    
+        <para>
+            <literal>org.hibernate.cfg.ImprovedNamingStrategy</literal> é uma estratégia 
+            interna que pode ser um ponto de começo útil para algumas aplicações.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-xmlconfig" revision="2">
+        <title>Arquivo de configuração XML</title>
+
+        <para>
+            Uma maneira alternativa de configuração é especificar uma configuração completa 
+            em um arquivo chamado <literal>hibernate.cfg.xml</literal>. Este arquivo pode 
+            ser usado como um substituto para o arquivo <literal>hibernate.properties</literal> 
+            ou, se ambos estão presentes, sobrescrever propriedades.
+        </para>
+
+        <para>
+            The XML configuration file is by default expected to be in the root o
+            your <literal>CLASSPATH</literal>. Here is an example:
+            O arquivo XML de configuração é por default esperado para estar na 
+            raiz do seu <literal>CLASSPATH</literal>. Veja um exemplo:
+        </para>
+
+        <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+    "-//Hibernate/Hibernate Configuration DTD//EN"
+    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <!-- a SessionFactory instance listed as /jndi/name -->
+    <session-factory
+        name="java:hibernate/SessionFactory">
+
+        <!-- properties -->
+        <property name="connection.datasource">java:/comp/env/jdbc/MyDB</property>
+        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
+        <property name="show_sql">false</property>
+        <property name="transaction.factory_class">
+            org.hibernate.transaction.JTATransactionFactory
+        </property>
+        <property name="jta.UserTransaction">java:comp/UserTransaction</property>
+
+        <!-- mapping files -->
+        <mapping resource="org/hibernate/auction/Item.hbm.xml"/>
+        <mapping resource="org/hibernate/auction/Bid.hbm.xml"/>
+
+        <!-- cache settings -->
+        <class-cache class="org.hibernate.auction.Item" usage="read-write"/>
+        <class-cache class="org.hibernate.auction.Bid" usage="read-only"/>
+        <collection-cache collection="org.hibernate.auction.Item.bids" usage="read-write"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+            Como você pode ver, a vantagem deste enfoque é a externalização dos nomes dos 
+            arquivos de mapeamento para configuração. O  <literal>hibernate.cfg.xml</literal> 
+            também é mais conveniente caso você tenha que ajustar o cache do Hibernate. 
+            Note que a escolha é sua  em usar  <literal>hibernate.properties</literal> ou
+            <literal>hibernate.cfg.xml</literal>, ambos são equivalente, à exceção dos benefícios 
+            acima mencionados de usar a sintaxe de XML.
+        </para>
+
+       <para>
+           Com a configuração do XML, iniciar o Hibernate é então tão simples como
+       </para>
+
+       <programlisting><![CDATA[SessionFactory sf = new Configuration().configure().buildSessionFactory();]]></programlisting>
+
+       <para>
+           You can pick a different XML configuration file using
+       </para>
+
+       <programlisting><![CDATA[SessionFactory sf = new Configuration()
+    .configure("catdb.cfg.xml")
+    .buildSessionFactory();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="configuration-j2ee" revision="1">
+        <title>Integração com servidores de aplicação J2EE</title>
+
+        <para>
+            O Hibernate tem os seguintes pontos da integração para o infraestrutura de J2EE:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>DataSources gerenciados pelo container</emphasis>: O Hibernate pode 
+                usar conexões JDBC gerenciadas pelo Container e fornecidas pela JNDI. Geralmente, 
+                um <literal>TransactionManager</literal> compatível com JTA e um 
+                <literal>ResourceManager</literal> cuidam do gerenciamento da transação ( CMT ), 
+                especialmente em transações distribuídas manipuladas através de vários DataSources. 
+                Naturalmente, você também pode demarcar os limites das transações programaticamente (BMT) 
+                ou você poderia querer usar a API opcional do Hibernate  <literal>Transaction</literal>
+                para esta manter seu código portável.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>Ligação (binding) automática a JNDI</emphasis>: O Hibernate pode 
+                associar sua <literal>SessionFactory</literal> a JNDI depois de iniciado.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>Ligação (binding) Session na JTA:</emphasis> 
+                A <literal>Session</literal> do Hibernate pode automaticamente ser ligada 
+                ao escopo da transações JTA. Simplesmente localizando a <literal>SessionFactory</literal> 
+                da JNDI e obtendo a<literal>Session</literal> corrente. Deixe o Hibernate cuidar 
+                da limpeza e encerramento da <literal>Session</literal> quando as transações JTA 
+                terminarem. A Demarcação de transação pode ser declarativa (CMT) ou 
+                programática(BMT/Transação do usuário).
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>JMX deployment:</emphasis> Se você usa um JMX servidor de 
+                aplicações capaz (ex. Jboss AS), você pode fazer a instação do Hibernate 
+                como um Mbean controlado. Isto evita ter que iniciar uma linha de 
+                código para construir sua <literal>SessionFactory</literal> de uma 
+                <literal>Configuration</literal>. O container iniciará seu 
+                <literal>HibernateService</literal>, e idealmente também cuidará 
+                das dependências de serviços (DataSources, têm que estar disponíveis 
+                antes do Hibernate iniciar, etc.).
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+             Dependendo em seu ambiente, você poderia ter que ajustar a opção de configuração 
+            <literal>hibernate.connection.aggressive_release</literal> para verdadeiro ( true ), 
+            se seu servidor de aplicações lançar exeções "retenção de conecção".
+        </para>
+
+        <sect2 id="configuration-optional-transactionstrategy" revision="3">
+            <title>Configuração de estratégia de transação</title>
+
+            <para>
+                A API Hibernate <literal>Session</literal> é independente de qualquer sistema de 
+                demarcação de transação em sua arquitetura. Se você deixar o Hibernate usar 
+                a JDBC diretamente, através de um pool de conexões, você pode inicializar e 
+                encerrar  suas transações chamando a API JDBC. Se você rodar em um servidor de 
+                aplicações J2EE, você poderá usar transações controladas por beans e chamar 
+                a API JTA e <literal>UserTransaction</literal> quando necessário.
+
+            </para>
+
+            <para>
+                Para manter seu código portável entre estes dois ( e outros ) ambientes, recomendamos 
+                a API Hibernate <literal>Transaction</literal>, que envolve e esconde o sistema subjacente. 
+                Você tem que especificar um classe construtora para <literal>Transaction</literal> instanciar 
+                ajustando a propriedade de configuração do <literal>hibernate.transaction.factory_class</literal>.
+
+            </para>
+
+            <para>
+                Existem três escolhas (internas) padrões:
+            </para>
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.JDBCTransactionFactory</literal></term>
+                    <listitem>
+                        <para>delegada as transações (JDBC)a bases de dados  (Padrão)</para>
+                              
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.JTATransactionFactory</literal></term>
+                    <listitem>
+                        <para>
+                            delegada a transação a um container gerenciador se a transação 
+                            existente estiver de acordo neste contexto (ex: método bean sessão EJB), 
+                            se não uma nova transação é iniciada e uma transação controlado por 
+                            um bean é usada.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.CMTTransactionFactory</literal></term>
+                    <listitem>
+                        <para>delega para um container gerenciador de transações JTA</para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+            <para>
+                Você também pode definir suas próprias estratégias de transação ( para um serviço de 
+                transação CORBA por exemplo).
+            </para>
+
+            <para>
+                Algumas características no Hibernate (ex., o cache de segundo nível, sessões contextuais 
+                com JTA, etc.) requerem acesso a JTA <literal>TransactionManager</literal> em um ambiente 
+                controlado. Em um servidor de aplicação você tem que especificar como o Hibernate pode 
+                obter uma referência para a <literal>TransactionManager</literal>, pois o J2EE não 
+                padronize um mecanismo simples :
+            </para>
+
+            <table frame="topbot" id="jtamanagerlookup" revision="1">
+                <title>Gerenciadores de transações JTA</title>
+                <tgroup cols="2">
+                    <colspec colwidth="2.5*"/>
+                    <colspec colwidth="1*"/>
+                    <thead>
+                        <row>
+                            <entry>Transaction Factory</entry>
+                            <entry align="center">Application Server</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JBossTransactionManagerLookup</literal></entry>
+                            <entry align="center">JBoss</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WeblogicTransactionManagerLookup</literal></entry>
+                            <entry align="center">Weblogic</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WebSphereTransactionManagerLookup</literal></entry>
+                            <entry align="center">WebSphere</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</literal></entry>
+                            <entry align="center">WebSphere 6</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.OrionTransactionManagerLookup</literal></entry>
+                            <entry align="center">Orion</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.ResinTransactionManagerLookup</literal></entry>
+                            <entry align="center">Resin</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JOTMTransactionManagerLookup</literal></entry>
+                            <entry align="center">JOTM</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JOnASTransactionManagerLookup</literal></entry>
+                            <entry align="center">JOnAS</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JRun4TransactionManagerLookup</literal></entry>
+                            <entry align="center">JRun4</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.BESTransactionManagerLookup</literal></entry>
+                            <entry align="center">Borland ES</entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-jndi" revision="3">
+            <title><literal>SessionFactory</literal> ligada a JNDI</title>
+
+            <para>
+                Uma <literal>SessionFactory</literal> de Hibernate ligada a JNDI pode simplificar
+                a localização da fabrica e a criação de novas <literal>Session</literal>s.
+                Observe que isto não relacionado a um <literal>Datasource</literal> ligado 
+                a JNDI, simplemente ambos usam o mesmo registro!
+            </para>
+
+            <para>
+                If you wish to have the <literal>SessionFactory</literal> bound to a JNDI namespace, specify
+                a name (eg. <literal>java:hibernate/SessionFactory</literal>) using the property
+                <literal>hibernate.session_factory_name</literal>. If this property is omitted, the
+                <literal>SessionFactory</literal> will not be bound to JNDI. (This is especially useful in
+                environments with a read-only JNDI default implementation, e.g. Tomcat.)
+            </para>
+
+            <para>
+                When binding the <literal>SessionFactory</literal> to JNDI, Hibernate will use the values of
+                <literal>hibernate.jndi.url</literal>, <literal>hibernate.jndi.class</literal> to instantiate
+                an initial context. If they are not specified, the default <literal>InitialContext</literal>
+                will be used.
+            </para>
+
+            <para>
+                Hibernate will automatically place the <literal>SessionFactory</literal> in JNDI after
+                you call <literal>cfg.buildSessionFactory()</literal>. This means you will at least have
+                this call in some startup code (or utility class) in your application, unless you use
+                JMX deployment with the <literal>HibernateService</literal> (discussed later).
+            </para>
+
+            <para>
+                If you use a JNDI <literal>SessionFactory</literal>, an EJB or any other class may
+                obtain the  <literal>SessionFactory</literal> using a JNDI lookup.
+            </para>
+
+            <para>
+                We recommend that you bind the <literal>SessionFactory</literal> to JNDI in
+                a managend environment and use a <literal>static</literal> singleton otherwise.
+                To shield your application code from these details, we also recommend to hide the
+                actual lookup code for a <literal>SessionFactory</literal> in a helper class,
+                such as <literal>HibernateUtil.getSessionFactory()</literal>. Note that such a
+                class is also a convenient way to startup Hibernate&mdash;see chapter 1.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-j2ee-currentsession" revision="4">
+            <title>Current Session context management with JTA</title>
+
+            <para>
+                The easiest way to handle <literal>Session</literal>s and transactions is
+                Hibernates automatic "current" <literal>Session</literal> management.
+                See the discussion of <xref linkend="architecture-current-session">current sessions</xref>.
+                Using the <literal>"jta"</literal> session context, if there is no Hibernate
+                <literal>Session</literal> associated with the current JTA transaction, one will
+	            be started and associated with that JTA transaction the first time you call
+	            <literal>sessionFactory.getCurrentSession()</literal>. The <literal>Session</literal>s
+	            retrieved via <literal>getCurrentSession()</literal> in <literal>"jta"</literal> context
+	            will be set to automatically flush before the transaction completes, close
+	            after the transaction completes, and aggressively release JDBC connections
+	            after each statement.  This allows the <literal>Session</literal>s to
+	            be managed by the lifecycle of the JTA transaction to which it is associated,
+	            keeping user code clean of such management concerns. Your code can either use
+	            JTA programmatically through <literal>UserTransaction</literal>, or (recommended
+	            for portable code) use the Hibernate <literal>Transaction</literal> API to set
+	            transaction boundaries. If you run in an EJB container, declarative transaction
+	            demarcation with CMT is preferred.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-j2ee-jmx" revision="1">
+            <title>JMX deployment</title>
+
+            <para>
+                The line <literal>cfg.buildSessionFactory()</literal> still has to be executed
+                somewhere to get a <literal>SessionFactory</literal> into JNDI. You can do this
+                either in a <literal>static</literal> initializer block (like the one in
+                <literal>HibernateUtil</literal>) or you deploy Hibernate as a <emphasis>managed
+                service</emphasis>.
+            </para>
+
+            <para>
+                Hibernate is distributed with <literal>org.hibernate.jmx.HibernateService</literal>
+                for deployment on an application server with JMX capabilities, such as JBoss AS.
+                The actual deployment and configuration is vendor specific. Here is an example
+                <literal>jboss-service.xml</literal> for JBoss 4.0.x:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<server>
+
+<mbean code="org.hibernate.jmx.HibernateService"
+    name="jboss.jca:service=HibernateFactory,name=HibernateFactory">
+
+    <!-- Required services -->
+    <depends>jboss.jca:service=RARDeployer</depends>
+    <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends>
+
+    <!-- Bind the Hibernate service to JNDI -->
+    <attribute name="JndiName">java:/hibernate/SessionFactory</attribute>
+
+    <!-- Datasource settings -->
+    <attribute name="Datasource">java:HsqlDS</attribute>
+    <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>
+
+    <!-- Transaction integration -->
+    <attribute name="TransactionStrategy">
+        org.hibernate.transaction.JTATransactionFactory</attribute>
+    <attribute name="TransactionManagerLookupStrategy">
+        org.hibernate.transaction.JBossTransactionManagerLookup</attribute>
+    <attribute name="FlushBeforeCompletionEnabled">true</attribute>
+    <attribute name="AutoCloseSessionEnabled">true</attribute>
+
+    <!-- Fetching options -->
+    <attribute name="MaximumFetchDepth">5</attribute>
+
+    <!-- Second-level caching -->
+    <attribute name="SecondLevelCacheEnabled">true</attribute>
+    <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute>
+    <attribute name="QueryCacheEnabled">true</attribute>
+
+    <!-- Logging -->
+    <attribute name="ShowSqlEnabled">true</attribute>
+
+    <!-- Mapping files -->
+    <attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute>
+
+</mbean>
+
+</server>]]></programlisting>
+
+            <para>
+                This file is deployed in a directory called <literal>META-INF</literal> and packaged
+                in a JAR file with the extension <literal>.sar</literal> (service archive). You also need
+                to package Hibernate, its required third-party libraries, your compiled persistent classes,
+                as well as your mapping files in the same archive. Your enterprise beans (usually session
+                beans) may be kept in their own JAR file, but you may include this EJB JAR file in the
+                main service archive to get a single (hot-)deployable unit. Consult the JBoss AS
+                documentation for more information about JMX service and EJB deployment.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/configuration.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/events.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/events.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/events.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,271 @@
+<chapter id="events">
+    <title>Interceptadores e Eventos</title>
+
+    <para>
+        É muito útil quando a aplicação precisa executar alguma "coisa" no momento em 
+        que o Hibernate executa uma de suas ações. Isso permite a implementação de 
+        certas funções genéricas, assim como permite estender as funcionalidades do 
+        Hibernate
+    </para>
+
+    <sect1 id="objectstate-interceptors" revision="3">
+        <title>Interceptadores</title>
+
+        <para>
+            A interface <literal>Interceptor</literal> permite fornecer informações da session para o 
+            aplicativo, permitindo ao aplicativo inspecionar e/ou manipular as propriedades de um 
+            objeto persistente antes de ser salvo, atualizado, excluído ou salvo. Um dos possíveis usos é 
+            gerar informações de auditoria. Por exemplo, o seguinte <literal>Interceptor</literal> seta 
+            automaticamente o atributo <literal>createTimestamp</literal> quando um 
+            <literal>Auditable</literal> é criada e atualiza o atributo <literal>lastUpdateTimestamp</literal> 
+            quando um <literal>Auditable</literal> é atualizado.
+        </para>
+
+        <para>
+            Você pode implementar <literal>Auditable</literal> diretamente ou pode estender 
+            <literal>EmptyInterceptor</literal>, sendo que a segunda é considerada a melhor opção.
+        </para>
+
+        <programlisting><![CDATA[package org.hibernate.test;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.Transaction;
+import org.hibernate.type.Type;
+
+public class AuditInterceptor extends EmptyInterceptor {
+
+    private int updates;
+    private int creates;
+    private int loads;
+
+    public void onDelete(Object entity,
+                         Serializable id,
+                         Object[] state,
+                         String[] propertyNames,
+                         Type[] types) {
+        // do nothing
+    }
+
+    public boolean onFlushDirty(Object entity,
+                                Serializable id,
+                                Object[] currentState,
+                                Object[] previousState,
+                                String[] propertyNames,
+                                Type[] types) {
+
+        if ( entity instanceof Auditable ) {
+            updates++;
+            for ( int i=0; i < propertyNames.length; i++ ) {
+                if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
+                    currentState[i] = new Date();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean onLoad(Object entity,
+                          Serializable id,
+                          Object[] state,
+                          String[] propertyNames,
+                          Type[] types) {
+        if ( entity instanceof Auditable ) {
+            loads++;
+        }
+        return false;
+    }
+
+    public boolean onSave(Object entity,
+                          Serializable id,
+                          Object[] state,
+                          String[] propertyNames,
+                          Type[] types) {
+
+        if ( entity instanceof Auditable ) {
+            creates++;
+            for ( int i=0; i<propertyNames.length; i++ ) {
+                if ( "createTimestamp".equals( propertyNames[i] ) ) {
+                    state[i] = new Date();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void afterTransactionCompletion(Transaction tx) {
+        if ( tx.wasCommitted() ) {
+            System.out.println("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads);
+        }
+        updates=0;
+        creates=0;
+        loads=0;
+    }
+
+}]]></programlisting>
+
+        <para>
+            Os interceptadores podem ser aplicados em dois diferentes escopos:  
+            No escopo da <literal>Session</literal> e no escopo 
+            <literal>SessionFactory</literal>.
+        </para>
+
+        <para>
+            Um interceptador no escopo da <literal>Session</literal> é definido quando 
+            uma sessão é aberta usando o método sobrecarregado da SessionFactory.openSession() 
+            que aceita um <literal>Interceptor</literal> como parâmetro.
+        </para>
+
+        <programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
+
+        <para>
+            Um interceptador no escopo da <literal>SessionFactory</literal> é definido no objeto 
+            <literal>Configuration</literal> antes da <literal>SessionFactory</literal> ser instanciada. 
+            Nesse caso, o interceptador fornecido será aplicado para todas as sessões abertas por aquela 
+            <literal>SessionFactory</literal>; Isso apenas não ocorrerá caso seja especificado um 
+            interceptador no momento em que a sessão for aberta.  Um interceptador no escopo de
+            <literal>SessionFactory</literal> deve ser thread safe, tomando-se o cuidado de não 
+            armazenar atributos de estado específicos da sessão, pois, provavelmente, múltiplas 
+            sessões irão utilizar esse interceptador simultaneamente.            
+        </para>
+    
+        <programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
+
+    </sect1>
+
+     <sect1 id="objectstate-events" revision="4">
+        <title>Sistema de Eventos</title>
+
+        <para>
+            Se você precisa executar uma ação em determinados eventos da camada de persistência, 
+            você também pode usar a arquitetura de <emphasis>event</emphasis> do Hibernate3. 
+            Um evento do sistema pode ser utilizado como complemento ou em 
+            substituição a um interceptador.
+        </para>
+
+        <para>
+            Essencialmente todos os métodos da interface <literal>Session</literal> possuem um evento 
+            correlacionado. Se você tiver um <literal>LoadEvent</literal>, um <literal>LoadEvent</literal>, 
+            etc (consulte o DTD do XML de configuração ou o pacote <literal>org.hibernate.event</literal>
+            para a lista completa dos tipos de eventos). Quando uma requisição é feita em um desses métodos, 
+            a <literal>Session</literal> do hibernate gera um evento apropriado e o envia para o listener 
+            de evento correspondente àquele tipo de evento. Esses listeners implementam a mesma lógica 
+            que aqueles métodos, trazendo os mesmos resultados. Entretanto, você é livre para implementar 
+            uma customização de um desses listeners (isto é, o  <literal>LoadEvent</literal> é processado 
+            pela implementação registrada da interface <literal>LoadEventListener</literal>), então sua  
+            implementação vai ficar responsável por processar qualquer requisição <literal>load()</literal>
+            feita pela <literal>Session</literal>.
+        </para>
+
+        <para>
+            Para todos os efeitos esses listeners deve ser considerados singletons; ou seja, eles são 
+            compartilhados entre as requisições, e  assim sendo, não devem salvar nenhum estado das 
+            variáveis instanciadas.
+        </para>
+
+        <para>
+            Um listener personalizado deve implementar a interface referente ao evento a ser 
+            processado e/ou deve estender a classes base equivalente (ou mesmo os listeners padrões 
+            usados pelo Hibernate, eles não são declarados como finais com esse objetivo). O listener 
+            personalizado pode ser registrado programaticamente no objeto <literal>Configuration</literal>, 
+            ou declarativamente no XML de configuração do Hibernate (o registro do listener no propertie 
+            de configuração não é suportado). Aqui temos um exemplo de como carregar um listener 
+            personalizado:
+        </para>
+
+        <programlisting><![CDATA[public class MyLoadListener implements LoadEventListener {
+    // this is the single method defined by the LoadEventListener interface
+    public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
+            throws HibernateException {
+        if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
+            throw MySecurityException("Unauthorized access");
+        }
+    }
+}]]></programlisting>
+
+        <para>
+            Você também precisa adicionar uma entrada no XML de configuração do Hibernate para 
+            registrar declarativamente qual listener deve se utilizado em conjunto com o listener 
+            padrão:
+        </para>
+
+<programlisting><![CDATA[<hibernate-configuration>
+    <session-factory>
+        ...
+        <event type="load">
+            <listener class="com.eg.MyLoadListener"/>
+            <listener class="org.hibernate.event.def.DefaultLoadEventListener"/>
+        </event>
+    </session-factory>
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+            Ou, você pode registrar o listener programaticamente:            
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration();
+LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() };
+cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
+
+        <para>
+            Listeners registrados declarativamente não compartilham da mesma instancia. Se o mesmo 
+            nome da classe é utilizado em vários elementos e <literal>&lt;listener/&gt;</literal>,  
+            cada um vai resultar em uma instancia separada dessa classe. Se você tem a necessidade 
+            de compartilhar uma instancia de um listener entre diversos tipos de listeners você 
+            deve registrar o listener programaticamente.
+           
+        </para>
+
+        <para>
+            Mas porque implementar uma interface e definir o tipo específico durante a configuração? 
+            Bem, um listener pode implementar vários listeners de evento. Com o tipo sendo definido 
+            durante o registro, fica fácil ligar ou desligar listeners personalizados durante 
+            a configuração. 
+        </para>
+
+    </sect1>
+    
+    <sect1 id="objectstate-decl-security" revision="2">
+        <title>Hibernate declarative security</title>
+        <para>
+            Usually, declarative security in Hibernate applications is managed in a session facade
+            layer. Now, Hibernate3 allows certain actions to be permissioned via JACC, and authorized 
+            via JAAS. This is optional functionality built on top of the event architecture.
+        </para>
+        
+        <para>
+            First, you must configure the appropriate event listeners, to enable the use of JAAS
+            authorization.
+        </para>
+        
+        <programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
+<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
+<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
+<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
+
+        <para>
+            Note that <literal>&lt;listener type="..." class="..."/&gt;</literal> is just a shorthand
+            for <literal>&lt;event type="..."&gt;&lt;listener class="..."/&gt;&lt;/event&gt;</literal>
+            when there is exactly one listener for a particular event type.
+        </para>
+
+        <para>
+            Next, still in <literal>hibernate.cfg.xml</literal>, bind the permissions to roles:
+        </para>
+        
+        <programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
+<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
+        
+        <para>
+            The role names are the roles understood by your JACC provider.
+        </para>
+       
+    </sect1>
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/events.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_mappings.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_mappings.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_mappings.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,663 @@
+<chapter id="example-mappings">
+    <title>Exemplo: Vários Mapeamentos</title>
+    
+    <para>
+        Este capitulo mostra algums mapeamentos de associações mais complexos.
+    </para>
+    
+    <sect1 id="example-mappings-emp">
+        <title>Employer/Employee</title>
+
+        <para>
+            O modelo de seguinte relacionamento entre <literal>Employer</literal> e
+            <literal>Employee</literal> utiliza uma entidade de classe atual (<literal>Employment</literal>) 
+            para representar a associação. Isto é feito porque pode-ser ter mais do que um período de 
+            trabalho para as duas partes envolvidas. Outros Componentes são usados para modelar 
+            valores monetários e os nomes do empregado.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/EmployerEmployee.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/EmployerEmployee.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            Abaixo o código de um possível mapeamento:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+        
+    <class name="Employer" table="employers">
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employer_id_seq</param>
+            </generator>
+        </id>
+        <property name="name"/>
+    </class>
+
+    <class name="Employment" table="employment_periods">
+
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employment_id_seq</param>
+            </generator>
+        </id>
+        <property name="startDate" column="start_date"/>
+        <property name="endDate" column="end_date"/>
+
+        <component name="hourlyRate" class="MonetaryAmount">
+            <property name="amount">
+                <column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>
+            </property>
+            <property name="currency" length="12"/>
+        </component>
+
+        <many-to-one name="employer" column="employer_id" not-null="true"/>
+        <many-to-one name="employee" column="employee_id" not-null="true"/>
+
+    </class>
+
+    <class name="Employee" table="employees">
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employee_id_seq</param>
+            </generator>
+        </id>
+        <property name="taxfileNumber"/>
+        <component name="name" class="Name">
+            <property name="firstName"/>
+            <property name="initial"/>
+            <property name="lastName"/>
+        </component>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        E abaixo o esquema da tabela gerado pelo <literal>SchemaExport</literal>.
+    </para>
+
+    <programlisting><![CDATA[create table employers (
+    id BIGINT not null, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+create table employment_periods (
+    id BIGINT not null,
+    hourly_rate NUMERIC(12, 2),
+    currency VARCHAR(12), 
+    employee_id BIGINT not null, 
+    employer_id BIGINT not null, 
+    end_date TIMESTAMP, 
+    start_date TIMESTAMP, 
+    primary key (id)
+)
+
+create table employees (
+    id BIGINT not null, 
+    firstName VARCHAR(255), 
+    initial CHAR(1), 
+    lastName VARCHAR(255), 
+    taxfileNumber VARCHAR(255), 
+    primary key (id)
+)
+
+alter table employment_periods 
+    add constraint employment_periodsFK0 foreign key (employer_id) references employers
+alter table employment_periods 
+    add constraint employment_periodsFK1 foreign key (employee_id) references employees
+create sequence employee_id_seq
+create sequence employment_id_seq
+create sequence employer_id_seq]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="example-mappings-authorwork">
+        <title>Author/Work</title>
+
+        <para>
+            Considere o seguinte modelo de relacionamento entre <literal>Work</literal>,
+            <literal>Author</literal> e <literal>Person</literal>. Nós representamos o relacionamento
+            entre <literal>Work</literal> e <literal>Author</literal> como uma associação 
+            muitos-para-muitos. Nós escolhemos representar o relacionamento entre <literal>Author</literal> 
+            e <literal>Person</literal> como uma associação um-para-um. Outra possibilidade seria ter 
+            <literal>Author</literal> extendendo  <literal>Person</literal>.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/AuthorWork.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/AuthorWork.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            O mapeamento do código seguinte representa corretamente estes relacionamentos:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Work" table="works" discriminator-value="W">
+
+        <id name="id" column="id">
+            <generator class="native"/>
+        </id>
+        <discriminator column="type" type="character"/>
+
+        <property name="title"/>
+        <set name="authors" table="author_work">
+            <key column name="work_id"/>
+            <many-to-many class="Author" column name="author_id"/>
+        </set>
+
+        <subclass name="Book" discriminator-value="B">
+            <property name="text"/>
+        </subclass>
+
+        <subclass name="Song" discriminator-value="S">
+            <property name="tempo"/>
+            <property name="genre"/>
+        </subclass>
+
+    </class>
+
+    <class name="Author" table="authors">
+
+        <id name="id" column="id">
+            <!-- The Author must have the same identifier as the Person -->
+            <generator class="assigned"/> 
+        </id>
+
+        <property name="alias"/>
+        <one-to-one name="person" constrained="true"/>
+
+        <set name="works" table="author_work" inverse="true">
+            <key column="author_id"/>
+            <many-to-many class="Work" column="work_id"/>
+        </set>
+
+    </class>
+
+    <class name="Person" table="persons">
+        <id name="id" column="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        There are four tables in this mapping. <literal>works</literal>, 
+        <literal>authors</literal> and <literal>persons</literal> hold work, author
+        and person data respectively. <literal>author_work</literal> is an association
+        table linking authors to works. Heres the table schema, as generated by
+        <literal>SchemaExport</literal>.
+        Existem quatro tabelas neste mapeamento. <literal>works</literal>, 
+        <literal>authors</literal> e <literal>persons</literal> recebem os dados de work, 
+        author e person, respectivamente. <literal>author_work</literal> é uma tabela de 
+        associação que liga authors à works. Abaixo o esquema das tabelas, gerados pelo 
+        <literal>SchemaExport</literal>.
+    </para>
+
+    <programlisting><![CDATA[create table works (
+    id BIGINT not null generated by default as identity, 
+    tempo FLOAT, 
+    genre VARCHAR(255), 
+    text INTEGER, 
+    title VARCHAR(255), 
+    type CHAR(1) not null, 
+    primary key (id)
+)
+
+create table author_work (
+    author_id BIGINT not null, 
+    work_id BIGINT not null, 
+    primary key (work_id, author_id)
+)
+
+create table authors (
+    id BIGINT not null generated by default as identity, 
+    alias VARCHAR(255), 
+    primary key (id)
+)
+
+create table persons (
+    id BIGINT not null generated by default as identity, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+alter table authors 
+    add constraint authorsFK0 foreign key (id) references persons
+alter table author_work 
+    add constraint author_workFK0 foreign key (author_id) references authors
+alter table author_work
+    add constraint author_workFK1 foreign key (work_id) references works]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-mappings-customerorderproduct">
+        <title>Customer/Order/Product</title>
+
+        <para>
+            Agora considere um modelo de relacionamento entre <literal>Customer</literal>,
+            <literal>Order</literal> e <literal>LineItem</literal> e <literal>Product</literal>.
+            Existe uma associação um-para-muitos entre <literal>Customer</literal> e
+            <literal>Order</literal>, mas como devemos representar <literal>Order</literal> / 
+            <literal>LineItem</literal> / <literal>Product</literal>? Eu escolhi mapear LineItem 
+            como uma classe de associação representando a associação muitos-para-muitos entre 
+            <literal>Order</literal> and <literal>Product</literal>. No Hibernate, isto é conhecido 
+            como um elemento composto.
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            O código do mapeamento:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Customer" table="customers">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+        <set name="orders" inverse="true">
+            <key column="customer_id"/>
+            <one-to-many class="Order"/>
+        </set>
+    </class>
+
+    <class name="Order" table="orders">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="date"/>
+        <many-to-one name="customer" column="customer_id"/>
+        <list name="lineItems" table="line_items">
+            <key column="order_id"/>
+            <list-index column="line_number"/>
+            <composite-element class="LineItem">
+                <property name="quantity"/>
+                <many-to-one name="product" column="product_id"/>
+            </composite-element>
+        </list>
+    </class>
+
+    <class name="Product" table="products">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="serialNumber"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        <literal>customers</literal>, <literal>orders</literal>, <literal>line_items</literal> e
+        <literal>products</literal> recebem os dados de customer, order, line_item e product, 
+        respectivamente. <literal>line_items</literal> também atua como uma tabela de associação 
+        ligando orders com products.
+    </para>
+
+    <programlisting><![CDATA[create table customers (
+    id BIGINT not null generated by default as identity, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+create table orders (
+    id BIGINT not null generated by default as identity, 
+    customer_id BIGINT, 
+    date TIMESTAMP, 
+    primary key (id)
+)
+
+create table line_items (
+    line_number INTEGER not null, 
+    order_id BIGINT not null, 
+    product_id BIGINT, 
+    quantity INTEGER, 
+    primary key (order_id, line_number)
+)
+
+create table products (
+    id BIGINT not null generated by default as identity, 
+    serialNumber VARCHAR(255), 
+    primary key (id)
+)
+
+alter table orders 
+    add constraint ordersFK0 foreign key (customer_id) references customers
+alter table line_items
+    add constraint line_itemsFK0 foreign key (product_id) references products
+alter table line_items
+    add constraint line_itemsFK1 foreign key (order_id) references orders]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="misc">
+        <title>Exemplos variados de mapeamento</title>
+        
+        <para>
+            Todos estes exemplos são retirados do conjunto de testes do Hibernate. 
+            Lá, você encontrará vários outros exemplos úteis de mapeamentos. 
+            Verifique o diretorio <literal>test</literal> da distribuição do Hibernate.
+        </para>
+        
+        <para>TODO: put words around this stuff</para>
+        
+        <sect2 id="example-mappings-typed-onetone">
+            <title>Associação um-para-um "Tipadas"</title>
+<programlisting><![CDATA[<class name="Person">
+    <id name="name"/>
+    <one-to-one name="address" 
+            cascade="all">
+        <formula>name</formula>
+        <formula>'HOME'</formula>
+    </one-to-one>
+    <one-to-one name="mailingAddress" 
+            cascade="all">
+        <formula>name</formula>
+        <formula>'MAILING'</formula>
+    </one-to-one>
+</class>
+
+<class name="Address" batch-size="2" 
+        check="addressType in ('MAILING', 'HOME', 'BUSINESS')">
+    <composite-id>
+        <key-many-to-one name="person" 
+                column="personName"/>
+        <key-property name="type" 
+                column="addressType"/>
+    </composite-id>
+    <property name="street" type="text"/>
+    <property name="state"/>
+    <property name="zip"/>
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="example-mappings-composite-key">
+            <title>Exemplo de chave composta</title>
+<programlisting><![CDATA[<class name="Customer">
+
+    <id name="customerId"
+        length="10">
+        <generator class="assigned"/>
+    </id>
+
+    <property name="name" not-null="true" length="100"/>
+    <property name="address" not-null="true" length="200"/>
+
+    <list name="orders"
+            inverse="true"
+            cascade="save-update">
+        <key column="customerId"/>
+        <index column="orderNumber"/>
+        <one-to-many class="Order"/>
+    </list>
+
+</class>
+
+<class name="Order" table="CustomerOrder" lazy="true">
+    <synchronize table="LineItem"/>
+    <synchronize table="Product"/>
+    
+    <composite-id name="id" 
+            class="Order$Id">
+        <key-property name="customerId" length="10"/>
+        <key-property name="orderNumber"/>
+    </composite-id>
+    
+    <property name="orderDate" 
+            type="calendar_date"
+            not-null="true"/>
+    
+    <property name="total">
+        <formula>
+            ( select sum(li.quantity*p.price) 
+            from LineItem li, Product p 
+            where li.productId = p.productId 
+                and li.customerId = customerId 
+                and li.orderNumber = orderNumber )
+        </formula>
+    </property>
+    
+    <many-to-one name="customer"
+            column="customerId"
+            insert="false"
+            update="false" 
+            not-null="true"/>
+        
+    <bag name="lineItems"
+            fetch="join" 
+            inverse="true"
+            cascade="save-update">
+        <key>
+            <column name="customerId"/>
+            <column name="orderNumber"/>
+        </key>
+        <one-to-many class="LineItem"/>
+    </bag>
+    
+</class>
+    
+<class name="LineItem">
+    
+    <composite-id name="id" 
+            class="LineItem$Id">
+        <key-property name="customerId" length="10"/>
+        <key-property name="orderNumber"/>
+        <key-property name="productId" length="10"/>
+    </composite-id>
+    
+    <property name="quantity"/>
+    
+    <many-to-one name="order"
+            insert="false"
+            update="false" 
+            not-null="true">
+        <column name="customerId"/>
+        <column name="orderNumber"/>
+    </many-to-one>
+    
+    <many-to-one name="product"
+            insert="false"
+            update="false" 
+            not-null="true"
+            column="productId"/>
+        
+</class>
+
+<class name="Product">
+    <synchronize table="LineItem"/>
+
+    <id name="productId"
+        length="10">
+        <generator class="assigned"/>
+    </id>
+    
+    <property name="description" 
+        not-null="true" 
+        length="200"/>
+    <property name="price" length="3"/>
+    <property name="numberAvailable"/>
+    
+    <property name="numberOrdered">
+        <formula>
+            ( select sum(li.quantity) 
+            from LineItem li 
+            where li.productId = productId )
+        </formula>
+    </property>
+    
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="example-mappings-composite-key-manytomany">
+            <title>Mmuitos-para-muitos com atributo de chave composta compartilhada</title>
+<programlisting><![CDATA[<class name="User" table="`User`">
+    <composite-id>
+        <key-property name="name"/>
+        <key-property name="org"/>
+    </composite-id>
+    <set name="groups" table="UserGroup">
+        <key>
+            <column name="userName"/>
+            <column name="org"/>
+        </key>
+        <many-to-many class="Group">
+            <column name="groupName"/>
+            <formula>org</formula>
+        </many-to-many>
+    </set>
+</class>
+    
+<class name="Group" table="`Group`">
+    <composite-id>
+        <key-property name="name"/>
+        <key-property name="org"/>
+    </composite-id>
+    <property name="description"/>
+    <set name="users" table="UserGroup" inverse="true">
+        <key>
+            <column name="groupName"/>
+            <column name="org"/>
+        </key>
+        <many-to-many class="User">
+            <column name="userName"/>
+            <formula>org</formula>
+        </many-to-many>
+    </set>
+</class>
+]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-content-discrimination">
+            <title>Conteúdo baseado em descriminação</title>
+<programlisting><![CDATA[<class name="Person"
+    discriminator-value="P">
+    
+    <id name="id" 
+        column="person_id" 
+        unsaved-value="0">
+        <generator class="native"/>
+    </id>
+    
+            
+    <discriminator 
+        type="character">
+        <formula>
+            case 
+                when title is not null then 'E' 
+                when salesperson is not null then 'C' 
+                else 'P' 
+            end
+        </formula>
+    </discriminator>
+
+    <property name="name" 
+        not-null="true"
+        length="80"/>
+        
+    <property name="sex" 
+        not-null="true"
+        update="false"/>
+    
+    <component name="address">
+        <property name="address"/>
+        <property name="zip"/>
+        <property name="country"/>
+    </component>
+    
+    <subclass name="Employee" 
+        discriminator-value="E">
+            <property name="title"
+                length="20"/>
+            <property name="salary"/>
+            <many-to-one name="manager"/>
+    </subclass>
+    
+    <subclass name="Customer" 
+        discriminator-value="C">
+            <property name="comments"/>
+            <many-to-one name="salesperson"/>
+    </subclass>
+    
+</class>]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-association-alternatekeys" revision="2">
+            <title>Associações em chaves alternativas</title>
+<programlisting><![CDATA[<class name="Person">
+    
+    <id name="id">
+        <generator class="hilo"/>
+    </id>
+    
+    <property name="name" length="100"/>
+    
+    <one-to-one name="address" 
+        property-ref="person"
+        cascade="all"
+        fetch="join"/>
+    
+    <set name="accounts" 
+        inverse="true">
+        <key column="userId"
+            property-ref="userId"/>
+        <one-to-many class="Account"/>
+    </set>
+    
+    <property name="userId" length="8"/>
+
+</class>
+
+<class name="Address">
+
+    <id name="id">
+        <generator class="hilo"/>
+    </id>
+
+    <property name="address" length="300"/>
+    <property name="zip" length="5"/>
+    <property name="country" length="25"/>
+    <many-to-one name="person" unique="true" not-null="true"/>
+
+</class>
+
+<class name="Account">
+    <id name="accountId" length="32">
+        <generator class="uuid"/>
+    </id>
+    
+    <many-to-one name="user"
+        column="userId"
+        property-ref="userId"/>
+    
+    <property name="type" not-null="true"/>
+    
+</class>]]></programlisting>
+        </sect2>
+
+    </sect1>
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_mappings.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_parentchild.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_parentchild.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_parentchild.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,361 @@
+<chapter id="example-parentchild">
+    <title>Example: Parent/Child</title>
+
+    <para>
+        One of the very first things that new users try to do with Hibernate is to model a parent / child type 
+        relationship. There are two different approaches to this. For various reasons the most convenient 
+        approach, especially for new users, is to model both <literal>Parent</literal> and <literal>Child</literal> 
+        as entity classes with a <literal>&lt;one-to-many&gt;</literal> association from <literal>Parent</literal> 
+        to <literal>Child</literal>. (The alternative approach is to declare the <literal>Child</literal> as a 
+        <literal>&lt;composite-element&gt;</literal>.) Now, it turns out that default semantics of a one to many 
+        association (in Hibernate) are much less close to the usual semantics of a parent / child relationship than 
+        those of a composite element mapping. We will explain how to use a <emphasis>bidirectional one to many 
+        association with cascades</emphasis> to model a parent / child relationship efficiently and elegantly. 
+        It's not at all difficult!
+    </para>
+    
+    <sect1 id="example-parentchild-collections">
+        <title>A note about collections</title>
+
+        <para>
+            Hibernate collections are considered to be a logical part of their owning entity; never of the
+            contained entities. This is a crucial distinction! It has the following consequences:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+            <para>
+                When we remove / add an object from / to a collection, the version number of the collection owner
+                is incremented.
+            </para>
+            </listitem>
+            <listitem>
+            <para>
+                If an object that was removed from a collection is an instance of a value type (eg, a composite
+                element), that object will cease to be persistent and its state will be completely removed from
+                the database. Likewise, adding a value type instance to the collection will cause its state to be
+                immediately persistent.
+            </para>
+            </listitem>
+            <listitem>
+            <para>
+                On the other hand, if an entity is removed from a collection (a one-to-many or many-to-many
+                association), it will not be deleted, by default. This behaviour is completely consistent - a
+                change to the internal state of another entity should not cause the associated entity to vanish!
+                Likewise, adding an entity to a collection does not cause that entity to become persistent, by
+                default.
+            </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Instead, the default behaviour is that adding an entity to a collection merely creates a link between
+            the two entities, while removing it removes the link. This is very appropriate for all sorts of cases.
+            Where it is not appropriate at all is the case of a parent / child relationship, where the life of the
+            child is bound to the lifecycle of the parent.
+        </para>
+    
+    </sect1>
+
+    <sect1 id="example-parentchild-bidir">
+        <title>Bidirectional one-to-many</title>
+
+        <para>
+            Suppose we start with a simple <literal>&lt;one-to-many&gt;</literal> association from
+            <literal>Parent</literal> to <literal>Child</literal>.
+        </para>
+
+        <programlisting><![CDATA[<set name="children">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+    
+        <para>
+            If we were to execute the following code
+        </para>
+
+        <programlisting><![CDATA[Parent p = .....;
+Child c = new Child();
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+    
+        <para>
+            Hibernate would issue two SQL statements:
+        </para>
+
+        <itemizedlist>
+        <listitem>
+            <para>an <literal>INSERT</literal> to create the record for <literal>c</literal></para>
+        </listitem>
+        <listitem>
+            <para>
+                an <literal>UPDATE</literal> to create the link from <literal>p</literal> to
+                <literal>c</literal>
+            </para>
+        </listitem>
+        </itemizedlist>
+    
+        <para>
+            This is not only inefficient, but also violates any <literal>NOT NULL</literal> constraint on the
+            <literal>parent_id</literal> column. We can fix the nullability constraint violation by specifying
+            <literal>not-null="true"</literal> in the collection mapping:
+        </para>
+
+        <programlisting><![CDATA[<set name="children">
+    <key column="parent_id" not-null="true"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+    
+        <para>
+        	However, this is not the recommended solution.
+       	</para>
+       	<para>
+            The underlying cause of this behaviour is that the link (the foreign key <literal>parent_id</literal>) 
+            from <literal>p</literal> to <literal>c</literal> is not considered part of the state of the 
+            <literal>Child</literal> object and is therefore not created in the <literal>INSERT</literal>. So the 
+            solution is to make the link part of the <literal>Child</literal> mapping.
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
+
+        <para>
+            (We also need to add the <literal>parent</literal> property to the <literal>Child</literal> class.)
+        </para>
+
+        <para>
+            Now that the <literal>Child</literal> entity is managing the state of the link, we tell the collection 
+            not to update the link. We use the <literal>inverse</literal> attribute.
+        </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+        <para>
+            The following code would be used to add a new <literal>Child</literal>
+        </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+        <para>
+            And now, only one SQL <literal>INSERT</literal> would be issued!
+        </para>
+
+        <para>
+            To tighten things up a bit, we could create an <literal>addChild()</literal> method of
+            <literal>Parent</literal>.
+        </para>
+
+        <programlisting><![CDATA[public void addChild(Child c) {
+    c.setParent(this);
+    children.add(c);
+}]]></programlisting>
+
+        <para>
+            Now, the code to add a <literal>Child</literal> looks like
+        </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+     </sect1>
+     
+     <sect1 id="example-parentchild-cascades">
+         <title>Cascading lifecycle</title>
+     
+         <para>
+             The explicit call to <literal>save()</literal> is still annoying. We will address this by
+             using cascades.
+         </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true" cascade="all">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+     
+         <para>
+             This simplifies the code above to
+         </para>
+
+        <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.flush();]]></programlisting>
+     
+         <para>
+             Similarly, we don't need to iterate over the children when saving or deleting a <literal>Parent</literal>.
+             The following removes <literal>p</literal> and all its children from the database.
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+session.delete(p);
+session.flush();]]></programlisting>
+     
+         <para>
+             However, this code
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+c.setParent(null);
+session.flush();]]></programlisting>
+     
+         <para>
+             will not remove <literal>c</literal> from the database; it will ony remove the link to <literal>p</literal>
+             (and cause a <literal>NOT NULL</literal> constraint violation, in this case). You need to explicitly
+             <literal>delete()</literal> the <literal>Child</literal>.
+         </para>
+
+         <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+session.delete(c);
+session.flush();]]></programlisting>
+
+         <para>
+             Now, in our case, a <literal>Child</literal> can't really exist without its parent. So if we remove
+             a <literal>Child</literal> from the collection, we really do want it to be deleted. For this, we must
+             use <literal>cascade="all-delete-orphan"</literal>.
+         </para>
+
+        <programlisting><![CDATA[<set name="children" inverse="true" cascade="all-delete-orphan">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+         <para>
+             Note: even though the collection mapping specifies <literal>inverse="true"</literal>, cascades are 
+             still processed by iterating the collection elements. So if you require that an object be saved, 
+             deleted or updated by cascade, you must add it to the collection. It is not enough to simply call
+             <literal>setParent()</literal>.
+         </para>
+               
+     </sect1>
+     
+     <sect1 id="example-parentchild-update">
+         <title>Cascades and <literal>unsaved-value</literal></title>
+     
+         <para>
+             Suppose we loaded up a <literal>Parent</literal> in one <literal>Session</literal>, made some changes 
+             in a UI action and wish to persist these changes in a new session by calling <literal>update()</literal>. 
+             The <literal>Parent</literal> will contain a collection of childen and, since cascading update is enabled, 
+             Hibernate needs to know which children are newly instantiated and which represent existing rows in the 
+             database. Lets assume that both <literal>Parent</literal> and <literal>Child</literal> have genenerated
+             identifier properties of type <literal>Long</literal>. Hibernate will use the identifier and 
+             version/timestamp property value to determine which of the children are new. (See
+             <xref linkend="objectstate-saveorupdate"/>.) <emphasis>In Hibernate3, it is no longer necessary to specify
+             an <literal>unsaved-value</literal> explicitly.</emphasis>
+         </para>
+
+         <para>
+             The following code will update <literal>parent</literal> and <literal>child</literal> and insert 
+             <literal>newChild</literal>.
+         </para>
+
+         <programlisting><![CDATA[//parent and child were both loaded in a previous session
+parent.addChild(child);
+Child newChild = new Child();
+parent.addChild(newChild);
+session.update(parent);
+session.flush();]]></programlisting>
+     
+         <para>
+             Well, that's all very well for the case of a generated identifier, but what about assigned identifiers
+             and composite identifiers? This is more difficult, since Hibernate can't use the identifier property to
+             distinguish between a newly instantiated object (with an identifier assigned by the user) and an 
+             object loaded in a previous session. In this case, Hibernate will either use the timestamp or version 
+             property, or will actually query the second-level cache or, worst case, the database, to see if the 
+             row exists.
+         </para>
+         
+         <!-- undocumenting
+         <para>
+             There is one further possibility. The <literal>Interceptor</literal> method named 
+             <literal>isUnsaved()</literal> lets the application implement its own strategy for distinguishing
+             newly instantiated objects. For example, you could define a base class for your persistent classes.
+         </para>
+
+         <programlisting><![CDATA[public class Persistent {
+    private boolean _saved = false;
+    public void onSave() {
+        _saved=true;
+    }
+    public void onLoad() {
+        _saved=true;
+    }
+    ......
+    public boolean isSaved() {
+        return _saved;
+    }
+}]]></programlisting>
+     
+         <para>
+             (The <literal>saved</literal> property is non-persistent.)
+             Now implement <literal>isUnsaved()</literal>, along with <literal>onLoad()</literal>
+             and <literal>onSave()</literal> as follows.
+         </para>
+
+         <programlisting><![CDATA[public Boolean isUnsaved(Object entity) {
+    if (entity instanceof Persistent) {
+        return new Boolean( !( (Persistent) entity ).isSaved() );
+    }
+    else {
+        return null;
+    }
+}
+
+public boolean onLoad(Object entity, 
+    Serializable id,
+    Object[] state,
+    String[] propertyNames,
+    Type[] types) {
+
+    if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
+    return false;
+}
+
+public boolean onSave(Object entity,
+    Serializable id,
+    Object[] state,
+    String[] propertyNames,
+    Type[] types) {
+        
+    if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
+    return false;
+}]]></programlisting>
+
+		<para>
+			Don't worry; in Hibernate3 you don't need to write any of this kind of code if you don't want to.
+		</para>
+     -->
+     </sect1>
+
+     <sect1 id="example-parentchild-conclusion">
+         <title>Conclusion</title>
+
+         <para>
+             There is quite a bit to digest here and it might look confusing first time around. However, in practice, 
+             it all works out very nicely. Most Hibernate applications use the parent / child pattern in many places.
+         </para>
+
+         <para>
+             We mentioned an alternative in the first paragraph. None of the above issues exist in the case of
+             <literal>&lt;composite-element&gt;</literal> mappings, which have exactly the semantics of a parent / child
+             relationship. Unfortunately, there are two big limitations to composite element classes: composite elements 
+             may not own collections, and they should not be the child of any entity other than the unique parent.
+         </para>
+     
+     </sect1>
+     
+</chapter>
\ No newline at end of file


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_parentchild.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_weblog.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_weblog.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_weblog.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,430 @@
+<chapter id="example-weblog">
+    <title>Example: Weblog Application</title>
+
+    <sect1 id="example-weblog-classes">
+        <title>Persistent Classes</title>
+
+        <para>
+            The persistent classes represent a weblog, and an item posted
+            in a weblog. They are to be modelled as a standard parent/child
+            relationship, but we will use an ordered bag, instead of a set.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+import java.util.List;
+
+public class Blog {
+    private Long _id;
+    private String _name;
+    private List _items;
+
+    public Long getId() {
+        return _id;
+    }
+    public List getItems() {
+        return _items;
+    }
+    public String getName() {
+        return _name;
+    }
+    public void setId(Long long1) {
+        _id = long1;
+    }
+    public void setItems(List list) {
+        _items = list;
+    }
+    public void setName(String string) {
+        _name = string;
+    }
+}]]></programlisting>
+
+        <programlisting><![CDATA[package eg;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+
+public class BlogItem {
+    private Long _id;
+    private Calendar _datetime;
+    private String _text;
+    private String _title;
+    private Blog _blog;
+
+    public Blog getBlog() {
+        return _blog;
+    }
+    public Calendar getDatetime() {
+        return _datetime;
+    }
+    public Long getId() {
+        return _id;
+    }
+    public String getText() {
+        return _text;
+    }
+    public String getTitle() {
+        return _title;
+    }
+    public void setBlog(Blog blog) {
+        _blog = blog;
+    }
+    public void setDatetime(Calendar calendar) {
+        _datetime = calendar;
+    }
+    public void setId(Long long1) {
+        _id = long1;
+    }
+    public void setText(String string) {
+        _text = string;
+    }
+    public void setTitle(String string) {
+        _title = string;
+    }
+}]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-weblog-mappings">
+        <title>Hibernate Mappings</title>
+
+        <para>
+            The XML mappings should now be quite straightforward.
+        </para>
+        
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+    <class
+        name="Blog"
+        table="BLOGS">
+
+        <id
+            name="id"
+            column="BLOG_ID">
+
+            <generator class="native"/>
+
+        </id>
+
+        <property
+            name="name"
+            column="NAME"
+            not-null="true"
+            unique="true"/>
+
+        <bag
+            name="items"
+            inverse="true"
+            order-by="DATE_TIME"
+            cascade="all">
+
+            <key column="BLOG_ID"/>
+            <one-to-many class="BlogItem"/>
+
+        </bag>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+    <class
+        name="BlogItem"
+        table="BLOG_ITEMS"
+        dynamic-update="true">
+
+        <id
+            name="id"
+            column="BLOG_ITEM_ID">
+
+            <generator class="native"/>
+
+        </id>
+
+        <property
+            name="title"
+            column="TITLE"
+            not-null="true"/>
+
+        <property
+            name="text"
+            column="TEXT"
+            not-null="true"/>
+
+        <property
+            name="datetime"
+            column="DATE_TIME"
+            not-null="true"/>
+
+        <many-to-one
+            name="blog"
+            column="BLOG_ID"
+            not-null="true"/>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="example-weblog-code">
+        <title>Hibernate Code</title>
+
+        <para>
+            The following class demonstrates some of the kinds of things
+            we can do with these classes, using Hibernate.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+
+public class BlogMain {
+    
+    private SessionFactory _sessions;
+    
+    public void configure() throws HibernateException {
+        _sessions = new Configuration()
+            .addClass(Blog.class)
+            .addClass(BlogItem.class)
+            .buildSessionFactory();
+    }
+    
+    public void exportTables() throws HibernateException {
+        Configuration cfg = new Configuration()
+            .addClass(Blog.class)
+            .addClass(BlogItem.class);
+        new SchemaExport(cfg).create(true, true);
+    }
+    
+    public Blog createBlog(String name) throws HibernateException {
+        
+        Blog blog = new Blog();
+        blog.setName(name);
+        blog.setItems( new ArrayList() );
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.persist(blog);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return blog;
+    }
+    
+    public BlogItem createBlogItem(Blog blog, String title, String text)
+                        throws HibernateException {
+        
+        BlogItem item = new BlogItem();
+        item.setTitle(title);
+        item.setText(text);
+        item.setBlog(blog);
+        item.setDatetime( Calendar.getInstance() );
+        blog.getItems().add(item);
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.update(blog);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return item;
+    }
+    
+    public BlogItem createBlogItem(Long blogid, String title, String text)
+                        throws HibernateException {
+        
+        BlogItem item = new BlogItem();
+        item.setTitle(title);
+        item.setText(text);
+        item.setDatetime( Calendar.getInstance() );
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            Blog blog = (Blog) session.load(Blog.class, blogid);
+            item.setBlog(blog);
+            blog.getItems().add(item);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return item;
+    }
+    
+    public void updateBlogItem(BlogItem item, String text)
+                    throws HibernateException {
+        
+        item.setText(text);
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.update(item);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+    }
+    
+    public void updateBlogItem(Long itemid, String text)
+                    throws HibernateException {
+    
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            BlogItem item = (BlogItem) session.load(BlogItem.class, itemid);
+            item.setText(text);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+    }
+    
+    public List listAllBlogNamesAndItemCounts(int max)
+                    throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        List result = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "select blog.id, blog.name, count(blogItem) " +
+                "from Blog as blog " +
+                "left outer join blog.items as blogItem " +
+                "group by blog.name, blog.id " +
+                "order by max(blogItem.datetime)"
+            );
+            q.setMaxResults(max);
+            result = q.list();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return result;
+    }
+    
+    public Blog getBlogAndAllItems(Long blogid)
+                    throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        Blog blog = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "from Blog as blog " +
+                "left outer join fetch blog.items " +
+                "where blog.id = :blogid"
+            );
+            q.setParameter("blogid", blogid);
+            blog  = (Blog) q.uniqueResult();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return blog;
+    }
+    
+    public List listBlogsAndRecentItems() throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        List result = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "from Blog as blog " +
+                "inner join blog.items as blogItem " +
+                "where blogItem.datetime > :minDate"
+            );
+
+            Calendar cal = Calendar.getInstance();
+            cal.roll(Calendar.MONTH, false);
+            q.setCalendar("minDate", cal);
+            
+            result = q.list();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return result;
+    }
+}]]></programlisting>
+
+    </sect1>
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/example_weblog.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/filters.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/filters.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/filters.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,128 @@
+<chapter id="filters">
+    <title>Filtrando dados</title>
+    
+    <para>
+        O Hibernate3 provê um novo método inovador para manusear dados com regras de "visibilidade". 
+        Um <emphasis>Filtro do Hibernate</emphasis> é um filtro global, nomeado e parametrizado que pode 
+        se habilitado ou não dentro de um Session do Hibernate.        
+    </para>
+
+    <sect1 id="objectstate-filters">
+        <title>Filtros do Hibernate</title>
+
+        <para>
+            O Hibernate tem a habilidade de pré definir os critérios do filtro e anexar esses filtros no 
+            nível da classe e no nível da coleção. Um critério do filtro é a habilidade de definir uma 
+            cláusula restritiva muito semelhante ao atributo "where" disponível para a classe e várias 
+            coleções. A não ser que essas condições de filtros podem ser parametrizadas. A aplicação 
+            pode, então, fazer uma decisão em tempo de execução se os filtros definidos devem estar 
+            habilitados e quais valores seus parâmetros devem ter. Os filtros podem ser usados como 
+            Views de bancos de dados, mas com parametros internos à aplicação.
+        </para>
+
+        <para>
+            Para usar esses filtros, eles primeiramente devem ser definidos e anexados aos elementos do 
+            mapeamento apropriados. Para definir um filtro, use o elemento <literal>&lt;filter-def/&gt;</literal>
+            dentro do elemento <literal>&lt;hibernate-mapping/&gt;</literal>:
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="myFilter">
+    <filter-param name="myFilterParam" type="string"/>
+</filter-def>]]></programlisting>
+
+        <para>
+            Então esse filtro pode ser anexo à uma classe:
+        </para>
+
+        <programlisting><![CDATA[<class name="myClass" ...>
+    ...
+    <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</class>]]></programlisting>
+
+        <para>
+            ou em uma coleção:
+        </para>
+
+        <programlisting><![CDATA[<set ...>
+    <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</set>]]></programlisting>
+
+        <para>
+            ou mesmo para ambos (ou muitos de cada) ao mesmo tempo.
+        </para>
+
+        <para>
+            Os métodos na <literal>Session</literal> são: <literal>enableFilter(String filterName)</literal>,
+            <literal>getEnabledFilter(String filterName)</literal>, e <literal>disableFilter(String filterName)</literal>.
+            Por padrão, os filtros não são habilitados dentro de qualquer session; Eles devem ser explicitamente 
+            habilitados usando o método  <literal>Session.enabledFilter()</literal>, que retorna uma instância da 
+            interface <literal>Filter</literal>. Usando o filtro simples definido acima, o código se pareceria 
+            com o seguinte:
+        </para>
+
+        <programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
+
+        <para>
+            Veja que os métodos da interface org.hibernate.Filter permite o encadeamento de funções, comum à maioria das funções do Hibernate.
+        </para>
+
+        <para>
+            Um exemplo completo, usando dados temporais com um padrão efetivo de registro de datas:
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="effectiveDate">
+    <filter-param name="asOfDate" type="date"/>
+</filter-def>
+
+<class name="Employee" ...>
+...
+    <many-to-one name="department" column="dept_id" class="Department"/>
+    <property name="effectiveStartDate" type="date" column="eff_start_dt"/>
+    <property name="effectiveEndDate" type="date" column="eff_end_dt"/>
+...
+    <!--
+        Note that this assumes non-terminal records have an eff_end_dt set to
+        a max db date for simplicity-sake
+    -->
+    <filter name="effectiveDate"
+            condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+</class>
+
+<class name="Department" ...>
+...
+    <set name="employees" lazy="true">
+        <key column="dept_id"/>
+        <one-to-many class="Employee"/>
+        <filter name="effectiveDate"
+                condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+            Para garantir que você sempre tenha registro efetivos, simplesmente habilite o filtro 
+            na session antes de recuperar os dados dos empregados:
+        </para>
+
+<programlisting><![CDATA[Session session = ...;
+session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
+List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
+         .setLong("targetSalary", new Long(1000000))
+         .list();
+]]></programlisting>
+
+        <para>
+            No HQL acima, mesmo que mencionamos apenas uma restrição de salário nos resultados, por causa  
+            do filtro habilitado, a consulta retornará apenas os funcionários ativos cujo salário é maior 
+            que um milhão de dólares.
+        </para>
+
+        <para>
+            Nota: se você planeja usar filtros com outer join (por HQL ou por load fetching) seja cuidadoso 
+            na direção da expressão de condição. É mais seguro configura-lo com para um left outer join; 
+            geralmente, coloque o parâmetro primeiro seguido pelo nome da coluna após o operador.
+        </para>
+
+    </sect1>
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/filters.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/inheritance_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/inheritance_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/inheritance_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,501 @@
+<chapter id="inheritance">
+    <title>Mapeamento de Herança</title>
+
+    <sect1 id="inheritance-strategies" revision="3">
+        <title> As três estratégias</title>
+
+        <para>
+            O Hibernate suporta as três estratégias básicas de mapeamento de herança:
+        </para>
+
+        <itemizedlist>
+        <listitem>
+        <para>
+            tabela por hierarquia de classes
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            tabela por subclasse
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            tabela por classe concreta
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            Adicionalmente, o Hibernate suporta uma quarta, um tipo levemente 
+            diferente de polimorfismo:
+        </para>
+
+        <itemizedlist>
+        <listitem>
+        <para>
+            polimorfismo implícito
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            É possível usar diferentes estratégias de mapeamento para diferentes 
+            ramificações da mesma hierarquia de herança, e então fazer uso do 
+            polimorfismo implícito para alcançar polimorfismo através da 
+            hierarquia completa. De qualquer forma, O Hibernate não suporta a 
+            mistura de mapeamentos <literal>&lt;subclass&gt;</literal>,
+            and <literal>&lt;joined-subclass&gt;</literal> e
+            <literal>&lt;union-subclass&gt;</literal> dentro do mesmo elemento 
+            raiz <literal>&lt;class&gt;</literal>. É possível usar junto às estratégias 
+            tabela por hierarquia e a tabela por subclasse, abaixo do mesmo elemento 
+            <literal>&lt;class&gt;</literal>, combinando os elementos  
+            <literal>&lt;subclass&gt;</literal> e <literal>&lt;join&gt;</literal> 
+            (veja abaixo).
+
+        </para>
+
+        <para>
+             É possível definir mapeamentos <literal>subclass</literal>, <literal>union-subclass</literal>,
+             e <literal>joined-subclass</literal> em documentos de mapeamento separados, diretamente abaixo de 
+             <literal>hibernate-mapping</literal>. Isso permite a você estender uma hierarquia de classes 
+             apenas adicionando um novo arquivo de mapeamento. Você deve especificar um atributo  
+             <literal>extends</literal> no mapeamento da subclasse, nomeando uma superclasse previamente 
+             mapeada. Nota: Anteriormente esta característica fazia o ordenamento dos documentos de 
+             mapeamento importantes. Desde o Hibernate3, o ordenamento dos arquivos de mapeamento não 
+             importa quando usamos a palavra chave extends. O ordenamento dentro de um arquivo de mapeamento 
+             simples ainda necessita ser definido como superclasse antes de subclasse.
+         </para>
+
+         <programlisting><![CDATA[
+ <hibernate-mapping>
+     <subclass name="DomesticCat" extends="Cat" discriminator-value="D">
+          <property name="name" type="string"/>
+     </subclass>
+ </hibernate-mapping>]]></programlisting>
+
+
+        <sect2 id="inheritance-tableperclass" >
+        <title>Tabela por hierarquia de classes</title>
+
+        <para>
+            Suponha que tenhamos uma interface <literal>Payment</literal>, com sua 
+            implementação <literal>CreditCardPayment</literal>, <literal>CashPayment</literal>,
+            <literal>ChequePayment</literal>. O mapeamento da tabela por hierarquia 
+            seria parecido com:            
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        ...
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        ...
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            Exactly one table is required. There is one big limitation of this mapping 
+            strategy: columns declared by the subclasses, such as <literal>CCTYPE</literal>, 
+            may not have <literal>NOT NULL</literal> constraints.
+        </para>
+        
+        </sect2>
+
+        <sect2 id="inheritance-tablepersubclass">
+        <title>Tabela por subclasse</title>
+
+        <para>
+            Um mapeamento de tabela por subclasse seria parecido com:
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        ...
+    </joined-subclass>
+</class>]]></programlisting>
+
+        <para>
+            Quatro tabelas são necessárias. As três tabelas subclasses possuem 
+            associação de chave primária para a tabela de superclasse 
+            (então o modelo relacional é atualmente uma associação de 
+            um-para-um).
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-tablepersubclass-discriminator" revision="2">
+        <title>Tabela por subclasse, usando um discriminador</title>
+
+        <para>
+        		Note que a implementação de tabela por subclasse do Hibernate não 
+            necessita de coluna de discriminador. Outro mapeador objeto/relacional 
+            usa uma implementação diferente de tabela por subclasse, que necessita 
+            uma coluna com o tipo discriminador na tabela da superclasse. A 
+            abordagem escolhida pelo Hibernate é muito mais difícil de implementar, 
+            porém de forma argumentável mais correto de um ponto de vista relacional. 
+            Se você deseja utilizar uma coluna discriminadora com a estratégia 
+            tabela por subclasse, você pode combinar o uso de 
+            <literal>&lt;subclass&gt;</literal> e <literal>&lt;join&gt;</literal>, 
+            dessa maneira:            
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <join table="CREDIT_PAYMENT">
+            <key column="PAYMENT_ID"/>
+            <property name="creditCardType" column="CCTYPE"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        <join table="CASH_PAYMENT">
+            <key column="PAYMENT_ID"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        <join table="CHEQUE_PAYMENT" fetch="select">
+            <key column="PAYMENT_ID"/>
+            ...
+        </join>
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            The optional <literal>fetch="select"</literal> declaration tells Hibernate 
+            not to fetch the <literal>ChequePayment</literal> subclass data using an
+            outer join when querying the superclass.
+A declaração opcional fetch=”select” diz ao Hibernate  para não buscar os dados da subclasse ChequePayment, quando usar um outer join pesquisando pela superclasse.
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
+        <title>. Misturando tabela por hierarquia de classes com tabela por subclasse</title>
+
+        <para>
+            Você pode até mesmo misturar a estratégia de tabela por hierarquia e 
+            tabela por subclasse usando esta abordagem:
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <join table="CREDIT_PAYMENT">
+            <property name="creditCardType" column="CCTYPE"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        ...
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        ...
+    </subclass>
+</class>]]></programlisting>
+
+        <para>
+            Para qualquer uma dessas estratégias de mapeamento, uma associação 
+            polimórfica para a classe raiz <literal>Payment</literal> deve ser 
+            mapeada usando <literal>&lt;many-to-one&gt;</literal>.            
+        </para>
+
+        <programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
+    
+        </sect2>
+
+        <sect2 id="inheritance-tableperconcrete" revision="2">
+        <title>Tabela por classe concreta</title>
+
+        <para>
+            Existem duas formas que poderíamos usar a respeito da estratégia de 
+            mapeamento de tabela por classe concreta. A primeira é usar 
+            <literal>&lt;union-subclass&gt;</literal>..
+        </para>
+
+        <programlisting><![CDATA[<class name="Payment">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="sequence"/>
+    </id>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </union-subclass>
+    <union-subclass name="CashPayment" table="CASH_PAYMENT">
+        ...
+    </union-subclass>
+    <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        ...
+    </union-subclass>
+</class>]]></programlisting>
+
+        <para>
+            Três tabelas estão envolvidas para as subclasses. Cada tabela define 
+            colunas para todas as propriedades da classe, incluindo propriedades herdadas.
+        </para>
+        
+        <para>
+						A limitação dessa abordagem é que se uma propriedade é mapeada na 
+						superclasse, o nome da coluna deve ser o mesmo em todas as tabelas das 
+						subclasses. (Nós devemos melhorar isto em um futuro release do Hibernate). 
+						A estratégia do gerador de identidade não é permitida em união de 
+						subclasses(union-subclass) herdadas, na verdade a fonte de chave 
+						primária deve ser compartilhada através de todas subclasses unidas da 
+						hierarquia.
+
+        </para>
+
+        <para>
+            Se sua superclasse é abstrata, mapeie ela com  <literal>abstract="true"</literal>. 
+            Claro, que se ela não for abstrata, uma tabela (padrão para <literal>PAYMENT</literal>  
+            no exemplo acima) adicional é necessária para segurar as instâncias da superclasse.
+        </para>
+
+        </sect2>
+
+        <sect2 id="inheritance-tableperconcreate-polymorphism">
+        <title>Tabela por classe concreta, usando polimorfismo implícito</title>
+
+        <para>
+            Uma abordagem alternativa é fazer uso de polimorfismo implícito:
+        </para>
+
+        <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+    <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CREDIT_AMOUNT"/>
+    ...
+</class>
+
+<class name="CashPayment" table="CASH_PAYMENT">
+    <id name="id" type="long" column="CASH_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CASH_AMOUNT"/>
+    ...
+</class>
+
+<class name="ChequePayment" table="CHEQUE_PAYMENT">
+    <id name="id" type="long" column="CHEQUE_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CHEQUE_AMOUNT"/>
+    ...
+</class>]]></programlisting>
+           
+        <para>
+            Veja que em nenhum lugar mencionamos a interface <literal>Payment</literal> 
+            explicitamente. Também preste atenção que propriedades de <literal>Payment</literal> 
+            são mapeadas em cada uma das subclasses. Se você quer evitar duplicação, 
+            considere usar entidades de XML (ex. (e.g. <literal>[ &lt;!ENTITY allproperties 
+            SYSTEM "allproperties.xml"&gt; ]</literal> na declaração do <literal>DOCTYPE</literal> 
+            e <literal>&amp;allproperties;</literal> no mapeamento).
+        </para>
+        
+        <para>
+            A desvantagem dessa abordagem é que o Hibernate não gera <literal>UNION</literal>s 
+            SQL quando executa pesquisas polimórficas.
+        </para>
+
+        <para>
+            Para essa estratégia, uma associação polimórfica para <literal>Payment</literal>
+            geralmente é mapeada usando <literal>&lt;any&gt;</literal>.
+        </para>
+
+        <programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
+    <meta-value value="CREDIT" class="CreditCardPayment"/>
+    <meta-value value="CASH" class="CashPayment"/>
+    <meta-value value="CHEQUE" class="ChequePayment"/>
+    <column name="PAYMENT_CLASS"/>
+    <column name="PAYMENT_ID"/>
+</any>]]></programlisting>
+           
+        </sect2>
+
+        <sect2 id="inheritace-mixingpolymorphism">
+        <title>Misturando polimorfismo implícito com outros mapeamentos de herança</title>
+
+        <para>
+            Ainda existe uma coisa para ser observada com respeito a este mapeamento. 
+            Desde que as subclasses sejam mapeadas em seu próprio elemento 
+            <literal>&lt;class&gt;</literal> (e desde que <literal>Payment</literal> seja 
+            apenas uma interface), cada uma das subclasses pode ser facilmente parte de uma 
+            outra hierarquia de herança! (E você ainda pode usar pesquisas polimórficas 
+            em cima da interface <literal>Payment</literal>.)
+           
+       </para>
+
+        <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+    <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="CREDIT_CARD" type="string"/>
+    <property name="amount" column="CREDIT_AMOUNT"/>
+    ...
+    <subclass name="MasterCardPayment" discriminator-value="MDC"/>
+    <subclass name="VisaPayment" discriminator-value="VISA"/>
+</class>
+
+<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
+    <id name="id" type="long" column="TXN_ID">
+        <generator class="native"/>
+    </id>
+    ...
+    <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="amount" column="CASH_AMOUNT"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="amount" column="CHEQUE_AMOUNT"/>
+        ...
+    </joined-subclass>
+</class>]]></programlisting>
+
+        <para>
+            Mais uma vez, nós não mencionamos <literal>Payment</literal> explicitamente. 
+            Se nós executarmos uma pesquisa em cima da interface <literal>Payment</literal> – 
+            por exemplo, <literal>from Payment</literal> – o Hibernate retorna 
+            automaticamente instâncias de <literal>CreditCardPayment</literal> (e suas 
+            subclasses, desde que elas também implementem <literal>Payment</literal>), 
+            <literal>CashPayment</literal> e <literal>ChequePayment</literal> mas 
+            não as instâncias de <literal>NonelectronicTransaction</literal>.
+        </para>
+        
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="inheritance-limitations">
+        <title>Limitações</title>
+
+        <para>
+            Existem certas limitações para a abordagem do "polimorfismo implícito" 
+            comparada com a estratégia de mapeamento da tabela por classe concreta. 
+            Existe uma limitação um tanto menos restritiva para mapeamentos 
+            <literal>&lt;union-subclass&gt;</literal>.
+           
+        </para>
+
+        <para>
+            A tabela seguinte demonstra as limitações do mapeamento de tabela 
+            por classe concreta e do polimorfismo implícito no Hibernate.
+        </para>
+            
+        <table frame="topbot">
+            <title>Features of inheritance mappings</title>
+            <tgroup cols='8' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="1*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <colspec colname='c6' colwidth="1*"/>
+            <colspec colname='c7' colwidth="1*"/>
+            <colspec colname='c8' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Estratégia de Herança</entry>
+              <entry>muitos-para-um Polimórfico</entry>
+              <entry>um-para-um Polimórfico</entry>
+              <entry>um-para-muitos Polimórfico</entry>
+              <entry>muitos-para-muitos Polimórfico</entry>
+              <entry><literal>load()/get()</literal> Polimórfico </entry>
+              <entry>Pesquisas Polimórficas</entry>
+              <entry>Joins polimórficos</entry>
+              <entry>Outer join fetching</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>table per class-hierarchy</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal></entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>supported</emphasis></entry>
+            </row>
+            <row>
+                <entry>table per subclass</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal></entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>supported</emphasis></entry>
+            </row>
+            <row>
+                <entry>table per concrete-class (union-subclass)</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal> (for <literal>inverse="true"</literal> only)</entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>supported</emphasis></entry>
+            </row>
+            <row>
+                <entry>table per concrete class (implicit polymorphism)</entry>
+                <entry><literal>&lt;any&gt;</literal></entry>
+                <entry><emphasis>not supported</emphasis></entry>
+                <entry><emphasis>not supported</emphasis></entry>
+                <entry><literal>&lt;many-to-any&gt;</literal></entry>
+                <entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><emphasis>not supported</emphasis></entry>
+                <entry><emphasis>not supported</emphasis></entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+    </sect1>
+
+</chapter>


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/inheritance_mapping.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/performance.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/performance.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/performance.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1384 @@
+<chapter id="performance">
+    <title>Aumentando a performance</title>
+
+    <sect1 id="performance-fetching" revision="2">
+        <title>Estratégias de Fetching</title>
+
+        <para>
+            Uma <emphasis>estratégia de fetching</emphasis> é a estratégia que o Hibernate 
+            irá usar para buscar objetos associados se a aplicação precisar navegar pela associação. 
+            Estratégias de Fetch podem ser declaradas nos metadados de mapeamento O/R, ou sobrescritos 
+            por uma query HQL ou query com <literal>Criteria</literal>.
+        </para>
+
+        <para>
+            Hibernate3 define as seguintes estratégias de fetching:
+        </para>
+
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <emphasis>Join fetching</emphasis> - o Hibernate busca o objeto 
+                    ou coleção associada no mesmo <literal>SELECT</literal>, usando um 
+                    <literal>OUTER JOIN</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Select fetching</emphasis> - um segundo <literal>SELECT</literal> é 
+                    usado para buscar a entidade ou coleção associada. A menos que você desabilite 
+                    lazy fetching especificando <literal>lazy="false"</literal>, esse segundo SELECT 
+                    será executado apenas quando você acessar a associação.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Subselect fetching</emphasis> - um segundo <literal>SELECT</literal> será 
+                    usado para buscar as coleções associadas de todas as entidades buscadas na query ou 
+                    fetch anterior. A menos que você desabilite lazy fetching especificando 
+                    <literal>lazy="false"</literal>, esse segundo SELECT será executado apenas quando 
+                    você acessar a associação.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Batch fetching</emphasis> - uma opção de otimização para o Select 
+                    Fetching – O Hibernate busca um lote de instâncias ou entidades usando um único 
+                    <literal>SELECT</literal>, especificando uma lista de chaves primárias ou chaves 
+                    estrangeiras.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            O Hibernate distingue também entre:
+        </para>
+
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <emphasis>Immediate fetching</emphasis> - uma associação, coleção ou atributo é buscado 
+		                como ela é carregada (Qual SQL é usado). Não se confuda com eles! Nós usamos fetch para melhorar a performance. Nós podemos usar lazy para definir um contrato para qual dado é sempre disponível em qualquer instância desanexada de uma classe qualquer.
+		                imediatamente, quando o pai é carregado.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Lazy collection fetching</emphasis> - a coleção é buscada quando a 
+                    aplicação invoca uma operação sobre aquela coleção (Esse é o padrão para coleções)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>"Extra-lazy" collection fetching</emphasis> - elementos individuais de uma 
+                    coleção são acessados do banco de dados quando preciso. O Hibernate tenta não buscar 
+                    a coleção inteira dentro da memória ao menos que seja absolutamente preciso. 
+                    (indicado para coleções muito grandes)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Proxy fetching</emphasis> - uma associação de um valor é carregada quando um método 
+                    diferente do getter do identificador é invocado sobre o objeto associado.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>"No-proxy" fetching</emphasis> -  uma associação de um valor é carregada quando 
+                    a variável da instância é carregada. Comparada com a proxy fetching, esse método é menos 
+                    preguiçoso (lazy)(a associação é carregada somente quando o identificador é acessada) 
+                    mas é mais transparente, já que não há proxies visíveis para a aplicação. 
+                    Esse método requer instrumentação de bytecodes em build-time e é raramente necessário.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Lazy attribute fetching</emphasis> - um atributo ou associação de um valor é 
+                    carregada quanto a varíavel da instância é acessada. Esse método requer instrumentação 
+                    de bytecodes em build-time e é raramente necessário.
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            Nós temos aqui duas noções ortogonais: <emphasis>quando</emphasis> a associação é carregada e 
+            <emphasis>como </emphasis> ela é carregada (Qual SQL é usado). Não se confuda com eles! Nós 
+            usamos <literal>fetch</literal> para melhorar a performance. Nós podemos usar lazy para 
+            definir um contrato para qual dado é sempre disponível em qualquer instância desconectada
+            de uma classe qualquer.
+        </para>
+ 
+        <sect2 id="performance-fetching-lazy">
+            <title>Trabalhando com associações preguiçosas (lazy)</title>
+            
+            <para>
+                Por padrão, o Hibernate3 usa busca preguiçosa para coleções e busca preguiçosa 
+                com proxy para associações de um valor. Esses padrões fazem sentido para quase 
+                todas as associações em quase todas a aplicações.
+            </para>
+            
+            <para>
+                <emphasis>Veja:</emphasis> se voce setar 
+                <literal>hibernate.default_batch_fetch_size</literal>, O Hibernate irá usar otimização
+                de carregamento em lote para o carregamento preguiçoso(Essa otimização pode ser também 
+                habilitada em um nível mais fino).
+            </para>
+            
+            <para>
+                Porém, a busca preguiçosa tem um problema que você precisar saber. Acesso a associações 
+                preguiçosas fora do contexto de uma sessão aberta do Hibernate irá resultar numa exceção. 
+                Por exemplo:
+            </para>
+        
+            <programlisting><![CDATA[s = sessions.openSession();
+Transaction tx = s.beginTransaction();
+            
+User u = (User) s.createQuery("from User u where u.name=:userName")
+    .setString("userName", userName).uniqueResult();
+Map permissions = u.getPermissions();
+
+tx.commit();
+s.close();
+
+Integer accessLevel = (Integer) permissions.get("accounts");  // Error!]]></programlisting>
+
+            <para>
+                Como a coleção de permissões não foi inicializada quando a <literal>Session</literal> 
+                foi fechada, a coleção não poderá carregar o seu estado. O Hibernate não suporta 
+                inicialização preguiçosa para objetos desconectados. Para consertar isso, é necessário 
+                mover o código que carrega a coleção para antes da transação ser comitada.
+            </para>
+    
+            <para>
+                Alternativamente, nós podemos usar uma coleção ou associação não preguiçosa, 
+                especificando <literal>lazy="false"</literal> para o mapeamento da associação. 
+                Porém, é pretendido que a inicialização preguiçosa seja usada por quase todas as 
+                coleções e associações. Se você definir muitas associações não preguiçosas em seu 
+                modelo de objetos, o Hibernate irá precisar carregar o banco de dados inteiro na memória 
+                em cada transação!
+            </para>
+    
+            <para>
+                Por outro lado, nós geralmente escolhemos join fetching (que é não preguiçosa por natureza) 
+                ao invés de select fetching em uma transação particular. Nós iremos ver como customizar 
+                a estratégoa de busca. No Hibernate3, os mecanismos para escolher a estratégia de fetching 
+                são identicos para as associações simples e para coleções.
+            </para>
+        
+        </sect2>
+        
+        <sect2 id="performance-fetching-custom" revision="4">
+            <title>Personalizando as estratégias de busca</title>
+            
+            <para>
+                O select fetching (o padrão) é extremamente vunerável para N+1 problemas em select, 
+                então nós iremos querer habilitar o join fetching no documento de mapeamento:
+            </para>
+            
+            <programlisting><![CDATA[<set name="permissions" 
+            fetch="join">
+    <key column="userId"/>
+    <one-to-many class="Permission"/>
+</set]]></programlisting>
+
+           <programlisting><![CDATA[<many-to-one name="mother" class="Cat" fetch="join"/>]]></programlisting>
+
+            <para>
+                A estratégia de <literal>fetch</literal> definida no documento de mapeamento afeta:
+            </para>
+            
+        <itemizedlist>
+             <listitem>
+                <para>
+                    recupera via <literal>get()</literal> ou <literal>load()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Recuperações  que acontecem implicitamente quando navegamos por uma associação
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>Criteria</literal> queries
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    buscas por HQL se buscar por <literal>subselect</literal> for usado
+                </para>
+            </listitem>
+        </itemizedlist>
+
+            <para>
+                Independentemente da estratégia de busca que você usar, o grafo não preguiçoso definido 
+                será garantidamente carregado na memória. Note que isso irá resultar em diversos selects 
+                imediatos sendo usados em um HQL em particular.
+            </para>
+
+            <para>
+                Usualmente não usamos documentos de mapeamento para customizar as buscas. Ao invés disso, 
+                nós deixamos o comportamento padrão e sobrescrevemos isso em uma transação em particular, 
+                usando <literal>left join fetch</literal> no HQL. Isso diz ao Hibernate para buscar a associação 
+                inteira no primeiro select, usando um outer join. Na API de busca <literal>Criteria</literal>, 
+                você irá usar <literal>setFetchMode(FetchMode.JOIN)</literal>.
+            </para>
+            
+            <para>
+                Se você quiser mudar a estratégia de busca usada pelo <literal>get()</literal> 
+                ou <literal>load()</literal>, simplesmente use uma query <literal>Criteria</literal>, 
+                por exemplo:
+            </para>
+            
+            <programlisting><![CDATA[User user = (User) session.createCriteria(User.class)
+                .setFetchMode("permissions", FetchMode.JOIN)
+                .add( Restrictions.idEq(userId) )
+                .uniqueResult();]]></programlisting>
+                
+            <para>
+                (Isto é o  equivalente do Hibernate para o que algumas soluções ORM chamam de "plano de busca")
+            </para>
+
+            <para>
+                Um meio totalmente diferente de evitar problemas com selects N+1 é usar um cache de segundo nível.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-proxies" revision="2">
+            <title>Proxies de associação single-ended</title>
+
+            <para>
+                A recuperação preguiçosa para coleções é implementada usando uma implementação 
+                própria do Hibernate para coleções persistentes. Porém, um mecanismo diferente é 
+                necessário para comportamento preguiçoso para associações de um lado só. A entidade 
+                alvo da associação precisa usar um proxy. O Hibernate implementa proxies para inicialização 
+                preguiçosa em objetos persistentes usando manipulação de bytecode 
+                (via a excelente biblioteca CGLIB).
+            </para>
+
+            <para>
+                Por padrão, o Hibernate3 gera proxies (na inicialização) para todas as classes 
+                persistentes que usem eles para habilitar recuperaçãopreguiçosa de associações 
+                <literal>many-to-one</literal> e <literal>one-to-one</literal>.
+            </para>
+
+            <para>
+                O arquivo de mapeamento deve declaram uma interface para usar como interface de proxy 
+                para aquela classe, com o atributo <literal>proxy</literal>. Por padrão, o Hibernate usa 
+                uma subclasse dessa classe. <emphasis>Note que a classe a ser usada via proxy precisa 
+                implementar o construtor padrão com pelo menos visibilidade de package. Nós recomendamos 
+                esse construtor para todas as classes persistentes!</emphasis>
+            </para>
+
+            <para>
+                Existe alguns truques que você deve saber quando extender esse comportamento para classes 
+                polimórficas, dessa maneira:
+            </para>
+
+            <programlisting><![CDATA[<class name="Cat" proxy="Cat">
+    ......
+    <subclass name="DomesticCat">
+        .....
+    </subclass>
+</class>]]></programlisting>
+
+            <para>
+                Primeiramente, instâncias de  <literal>Cat</literal> nunca seráo convertidas 
+                para <literal>DomesticCat</literal>, mesmo que a instância em questão seja uma 
+                estância de <literal>DomesticCat</literal>:
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id);  // instantiate a proxy (does not hit the db)
+if ( cat.isDomesticCat() ) {                  // hit the db to initialize the proxy
+    DomesticCat dc = (DomesticCat) cat;       // Error!
+    ....
+}]]></programlisting>
+
+            <para>
+                É possível quebrar o proxy <literal>==</literal>.
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id);            // instantiate a Cat proxy
+DomesticCat dc = 
+        (DomesticCat) session.load(DomesticCat.class, id);  // acquire new DomesticCat proxy!
+System.out.println(cat==dc);                            // false]]></programlisting>
+
+            <para>
+                Porém a situação não é tão ruim como parece. Mesmo quando temos duas referências para 
+                objetos proxies diferentes, a instância deles será o mesmo objeto
+            </para>
+
+            <programlisting><![CDATA[cat.setWeight(11.0);  // hit the db to initialize the proxy
+System.out.println( dc.getWeight() );  // 11.0]]></programlisting>
+
+            <para>
+                Terceiro, Você não pode usar um proxy CGLIB em uma classe <literal>final</literal>
+                ou com qualquer método <literal>final</literal>.
+            </para>
+
+            <para>
+                Finalmente, se o seu objeto persistente adquirir qualquer recursto durante a instanciação 
+                (em inicializadores ou construtor padrão), então esses recursos serão adquiridos pelo proxy 
+                também. A classe de proxy é uma subclasse da classe persistente.
+            </para>
+
+            <para>
+                Esses problemas são todos devido a limitação fundamental do modelo de herança simples do Java. 
+                Se você quiser evitar esse problemas em suas classes persistentes você deve imeplementar uma 
+                interface que declare seus métodos de negócio. Você deve especificar essas interfaces no arquivo 
+                de mapeamento. Ex:
+            </para>
+
+            <programlisting><![CDATA[<class name="CatImpl" proxy="Cat">
+    ......
+    <subclass name="DomesticCatImpl" proxy="DomesticCat">
+        .....
+    </subclass>
+</class>]]></programlisting>
+
+            <para>
+                onde <literal>CatImpl</literal> implementa a interface <literal>Cat</literal> e 
+                <literal>DomesticCatImpl</literal> implementa a interface <literal>DomesticCat</literal>. 
+                Então proxies para instâncias de <literal>Cat</literal> e <literal>DomesticCat</literal> 
+                serão retornadas por <literal>load()</literal> ou <literal>iterate()</literal>. 
+                (Note que <literal>list()</literal> geralmente não retorna proxies).
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(CatImpl.class, catid);
+Iterator iter = session.iterate("from CatImpl as cat where cat.name='fritz'");
+Cat fritz = (Cat) iter.next();]]></programlisting>
+
+            <para>
+                Relacionamentos são também carregados preguiçosamente. Isso significa que você precisa declarar 
+                qualquer propriedade como sendo do tipo <literal>Cat</literal>, e não <literal>CatImpl</literal>.
+            </para>
+
+            <para>
+                Algumas operações <emphasis>não</emphasis> requerem inicialização por proxy:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>equals()</literal>, se a classe persistente não sobrescrever 
+                        <literal>equals()</literal>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>hashCode()</literal>, se a classe persistente não sobrescrever 
+                        <literal>hashCode()</literal>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        O método getter do identificador
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                O Hibernate irá detectar classes persistentes que sobrescrevem 
+                <literal>equals()</literal> ou <literal>hashCode()</literal>.
+            </para>
+            
+            <para>
+                Escolhendo <literal>lazy="no-proxy"</literal> ao invés do padrão 
+                <literal>lazy="proxy"</literal>, podemos evitar problemas associados com typecasting.
+                Porém, iremos precisar de instrumentação de bytecode em tempo de compilação e todas 
+                as operações irão resultar em iniciazações de proxy imediatas.
+	            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-initialization" revision="1">
+            <title>Inicializando coleções e proxies</title>
+
+            <para>
+                Será lançada uma <literal>LazyInitializationException</literal>  se uma coleção não inicializada 
+                ou proxy é acessado fora do escopo da <literal>Session</literal>, isto é, quando a entidade que 
+                contém a coleção ou tem a referência ao proxy estiver no estado destachado.
+            </para>
+
+            <para>
+                Algumas vezes precisamos garantir qie o proxy ou coleção é inicializado antes de se fechar a 
+                <literal>Session</literal>. Claro que sempre podemos forçar a inicialização chamando 
+                <literal>cat.getSex()</literal> ou <literal>cat.getKittens().size()</literal>, por exemplo. 
+                Mas isto parece confuso para quem lê o código e não é conveniente para códigos genéricos.
+            </para>
+
+            <para>
+                Os métodos estáticos <literal>Hibernate.initialize()</literal> e <literal>Hibernate.isInitialized()</literal> 
+                possibilitam a aplicação uma maneira conveniente de trabalhar com coleções inicializadas preguiçosamente e 
+                proxies. <literal>Hibernate.initialize(cat)</literal> irá forçar a inicialização de um proxy, 
+                <literal>cat</literal>, contanto que a <literal>Session</literal> esteja ainda aberta. 
+                <literal>Hibernate.initialize( cat.getKittens() )</literal> tem um efeito similar para a coleção de 
+                kittens.
+            </para>
+
+            <para>
+                Outra opção é manter a <literal>Session</literal> aberta até que todas as coleções e 
+                proxies necessários sejam  carregados. Em algumas arquiteturas de aplicações, particularmente 
+                onde o código que acessa os dados usando Hibernate e o código que usa os dados estão em diferentes 
+                camadas da aplicação ou diferentes processos físicos, será um problema garantir que a 
+                <literal>Session</literal> esteja aberta quando uma coleção for inicializada. Existem dois 
+                caminhos básicos para lidar com esse problema:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        Em aplicações web, um filtro servlet pode ser usado para fechar a 
+                        <literal>Session</literal> somente no final da requisição do usuário, já que a 
+                        renderização da visão estará completa (o pattern <emphasis>Open Session In View</emphasis>). 
+                        Claro, que isto cria a necessidade de um correto manuseio de exceções na infraestrutura 
+                        de sua aplicação. É vitalmente importante que a <literal>Session</literal> esteja fechada 
+                        e a transação terminada antes de retornar para o usuário, mesmo que uma exceção ocorra 
+                        durante a renderização da view. Veja o Wiki do Hibernate para exemplos do pattern 
+                        "Open Session In View"
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Em uma aplicação com uma camada de negócios separada, a lógica de negócios deve 
+                        "preparar" todas as coleções que serão usadas pela camada web antes de retornar. 
+                        Isto sgnifica que a camada de negócios deve carregar todos os dados e retorná-los 
+                        já inicializados para a camada de apresentação. Usualmente a aplicação chama 
+                        <literal>Hibernate.initialize()</literal> para cada coleção que será usada pela 
+                        camada web (essa chamada de método deve ocorrer antes da sessão ser fechada ou 
+                        retornar a coleção usando uma consulta Hibernate com uma cláusula <literal>FETCH</literal>
+                        ou um <literal>FetchMode.JOIN</literal> na <literal>Criteria</literal>. Fica muito 
+                        mais fácil se você adotar o pattern <emphasis>Command</emphasis> ao invés do 
+                        <emphasis>Session Facade</emphasis>.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Você também pode anexar um objeto prevaimente carregado em uma nova 
+                        <literal>Session</literal> <literal>merge()</literal> or <literal>lock()</literal> 
+                        antes de acessar coleções não inicializadas (ou outros proxies). O Hibernate não faz 
+                        e certamente <literal>não deve</literal> isso automaticamente pois isso introduziria
+                        semantica em transações ad hoc.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                As vezes você não quer inicializar uma coleção muito grande, mas precisa de algumas 
+                informações (como o tamanho) ou alguns de seus dados.
+            </para>
+
+            <para>
+                Você pode usar um filtro de coleção para saber seu tamanho sem a inicializar:
+            </para>
+
+            <programlisting><![CDATA[( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()]]></programlisting>
+
+            <para>
+                O método <literal>createFilter()</literal> é usado também para retornar algus dados de uma
+                coleção eficientemente sem precisar inicializar a coleção inteira:
+            </para>
+
+            <programlisting><![CDATA[s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-batch">
+            <title>Usando busca em lote</title>
+
+            <para>
+                O Hibernate pode fazer uso eficiente de busca em lote, isto é, o Hibernate pode carregar diversos 
+                proxies não inicializados se um proxy é acessado (ou coleções. A busca em lote é uma otimização da 
+                estratégia de select fetching). Existe duas maneiras em que você pode usar busca em lote: no nível 
+                da classe ou no nível da coleção.
+            </para>
+
+            <para>
+                A recuperação em lote para classes/entidades é mais fácil de entender. Imagine que você tem a seguinte 
+                situação em tempo de execução: Você tem 25 instâncias de <literal>Cat</literal> carregadas em uma 
+                <literal>Session</literal>, cada <literal>Cat</literal> tem uma referência ao seu <literal>owner</literal>,
+                que é da classe <literal>Person</literal>. A classe <literal>Person</literal> é mapeada com um proxy, 
+                <literal>lazy="true"</literal>. Se você iterar sobre todos os Cat's e chamar <literal>getOwner()</literal>
+                em cada, o Hibernate irá por padrão executar 25 comandos <literal>SELECT()</literal>, para buscar os 
+                proxies de owners. Você pode melhorar esse comportamento especificando um <literal>batch-size</literal>
+                no mapeamento da classe <literal>Person</literal>:
+            </para>
+
+            <programlisting><![CDATA[<class name="Person" batch-size="10">...</class>]]></programlisting>
+
+            <para>
+                O Hibernate irá executar agora apenas três consultas, buscando por vez, 10, 10 e 5 Person.
+            </para>
+
+            <para>
+                Você também pode habilitar busca em lote de uma coleção. Por exemplo, se cada <literal>Person</literal> 
+                tem uma coleção preguiçosa de <literal>Cat</literal>s, e 10 pessoas estão já carregados em uma 
+                <literal>Sesssion</literal>, serão gerados 10 <literal>SELECT</literal>s ao se iterar todas as 
+                pessoas, um para cada chamada de <literal>getCats()</literal>.. Se você habilitar busca em lote 
+                para a coleção de <literal>cats</literal> no mapeamento da classe <literal>Person</literal>, 
+                o Hibernate pode fazer uma pré carga das coleções:
+            </para>
+
+            <programlisting><![CDATA[<class name="Person">
+    <set name="cats" batch-size="3">
+        ...
+    </set>
+</class>]]></programlisting>
+
+            <para>
+                Com um <literal>batch-size</literal>de 8, o Hibernate irá carregar 3, 3, 3, 1 coleções em 4 
+                <literal>SELECT</literal>s. Novamente, o valor do atributo depende do número esperado de coleções 
+                não inicialiadas em determinada <literal>Session</literal>.
+            </para>
+
+            <para>
+                A busca em lote de coleções é particularmente útil quando você tem uma árvore encadeada de 
+                items, ex. o típico padrão bill-of-materials (Se bem que um <emphasis>conjunto encadeado</emphasis> 
+                ou <emphasis>caminho materializado </emphasis> pode ser uma opção melhor para árvores com mais
+                leitura)
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-subselect">
+            <title>Usando subselect fetching</title>
+
+            <para>
+                Se uma coleção ou proxy simples precisa ser recuperado, o Hibernate carrega todos eles 
+                rodando novamente a query original em um subselect. Isso funciona da mesma maneira que busca 
+                em lote, sem carregar tanto.
+            </para>
+            
+            <!-- TODO: Write more about this -->
+
+        </sect2>
+        
+        <sect2 id="performance-fetching-lazyproperties">
+            <title>Usando busca preguiçosa de propriedade</title>
+
+            <para>
+                O Hibernate3 suporta a carga posterior de propriedades individuais. Essa técnica de otimização 
+                também conhecida como  <emphasis>fetch groups</emphasis>. Veja que isso é mais uma funcionalidade 
+                de marketing já que na prática, é mais importante otimização nas leituras dos registros do 
+                que na leitura das colunas. Porém, carregar apenas algumas propriedades de uma classe pode 
+                ser útil em casos extremos, onde tabelas legadas podem ter centenas de colunas e o modelo 
+                de dados não pode ser melhorado.
+            </para>
+
+            <para>
+                Para habilitar a carga posterior de propriedade, é preciso setar o atributo 
+                <literal>lazy</literal> no seu mapeamento de propriedade:
+            </para>
+
+            <programlisting><![CDATA[<class name="Document">
+       <id name="id">
+        <generator class="native"/>
+    </id>
+    <property name="name" not-null="true" length="50"/>
+    <property name="summary" not-null="true" length="200" lazy="true"/>
+    <property name="text" not-null="true" length="2000" lazy="true"/>
+</class>]]></programlisting>
+
+            <para>
+                A carga posterior de propriedades requer instrumentação de bytecode! Se suas classes 
+                persistentes não forem melhoradas, o Hibernate irá ignorar silenciosamente essa 
+                configuração e usará busca imediatamente.
+            </para>
+
+            <para>
+                Para instrumentação de bytecode, use a seguinte tarefa do Ant:
+            </para>
+
+            <programlisting><![CDATA[<target name="instrument" depends="compile">
+    <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
+        <classpath path="${jar.path}"/>
+        <classpath path="${classes.dir}"/>
+        <classpath refid="lib.class.path"/>
+    </taskdef>
+
+    <instrument verbose="true">
+        <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
+            <include name="*.class"/>
+        </fileset>
+    </instrument>
+</target>]]></programlisting>
+
+            <para>
+                A different (better?) way to avoid unnecessary column reads, at least for
+                read-only transactions is to use the projection features of HQL or Criteria
+                queries. This avoids the need for buildtime bytecode processing and is
+                certainly a prefered solution.
+            </para>
+            
+            <para>
+                You may force the usual eager fetching of properties using <literal>fetch all
+                properties</literal> in HQL.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="performance-cache" revision="1">
+        <title>The Second Level Cache</title>
+
+        <para>
+            A Hibernate <literal>Session</literal> is a transaction-level cache of persistent data. It is
+            possible to configure a cluster or JVM-level (<literal>SessionFactory</literal>-level) cache on 
+            a class-by-class and collection-by-collection basis. You may even plug in a clustered cache. Be 
+            careful. Caches are never aware of changes made to the persistent store by another application 
+            (though they may be configured to regularly expire cached data).
+        </para>
+        
+        <para revision="1">
+            You have the option to tell Hibernate which caching implementation to use by
+            specifying the name of a class that implements <literal>org.hibernate.cache.CacheProvider</literal>
+            using the property <literal>hibernate.cache.provider_class</literal>.  Hibernate
+            comes bundled with a number of built-in integrations with open-source cache providers
+            (listed below); additionally, you could implement your own and plug it in as
+            outlined above.  Note that versions prior to 3.2 defaulted to use EhCache as the
+            default cache provider; that is no longer the case as of 3.2.
+        </para>
+
+        <table frame="topbot" id="cacheproviders" revision="1">
+            <title>Cache Providers</title>
+            <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="3*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Cache</entry>
+              <entry>Provider class</entry>
+              <entry>Type</entry>
+              <entry>Cluster Safe</entry>
+              <entry>Query Cache Supported</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>Hashtable (not intended for production use)</entry>
+                <entry><literal>org.hibernate.cache.HashtableCacheProvider</literal></entry>
+                <entry>memory</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>EHCache</entry>
+                <entry><literal>org.hibernate.cache.EhCacheProvider</literal></entry>
+                <entry>memory, disk</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>OSCache</entry>
+                <entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
+                <entry>memory, disk</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>SwarmCache</entry>
+                <entry><literal>org.hibernate.cache.SwarmCacheProvider</literal></entry>
+                <entry>clustered (ip multicast)</entry>
+                <entry>yes (clustered invalidation)</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>JBoss TreeCache</entry>
+                <entry><literal>org.hibernate.cache.TreeCacheProvider</literal></entry>
+                <entry>clustered (ip multicast), transactional</entry>
+                <entry>yes (replication)</entry>
+                <entry>yes (clock sync req.)</entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <sect2 id="performance-cache-mapping" revision="2">
+            <title>Cache mappings</title>
+
+            <para>
+                The <literal>&lt;cache&gt;</literal> element of a class or collection mapping has the
+                following form:
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="cache1" coords="2 70"/>
+                    <area id="cache2" coords="3 70"/>
+                    <area id="cache3" coords="4 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<cache 
+    usage="transactional|read-write|nonstrict-read-write|read-only"
+    region="RegionName"
+    include="all|non-lazy"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="cache1">
+                        <para>
+                            <literal>usage</literal> (required) specifies the caching strategy:
+                            <literal>transactional</literal>,
+                            <literal>read-write</literal>,
+                            <literal>nonstrict-read-write</literal> or
+                            <literal>read-only</literal>
+                        </para>
+                    </callout>                   
+                    <callout arearefs="cache2">
+                        <para>
+                            <literal>region</literal> (optional, defaults to the class or
+                            collection role name) specifies the name of the second level cache 
+                            region
+                        </para>
+                    </callout>                   
+                    <callout arearefs="cache3">
+                        <para>
+                            <literal>include</literal> (optional, defaults to <literal>all</literal>) 
+                            <literal>non-lazy</literal> specifies that properties of the entity mapped
+                            with <literal>lazy="true"</literal> may not be cached when attribute-level
+                            lazy fetching is enabled
+                        </para>
+                    </callout>                   
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                Alternatively (preferrably?), you may specify <literal>&lt;class-cache&gt;</literal> and 
+                <literal>&lt;collection-cache&gt;</literal> elements in <literal>hibernate.cfg.xml</literal>.
+            </para>
+            
+            <para>
+                The <literal>usage</literal> attribute specifies a <emphasis>cache concurrency strategy</emphasis>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-cache-readonly">
+            <title>Strategy: read only</title>
+
+            <para>
+                If your application needs to read but never modify instances of a persistent class, a 
+                <literal>read-only</literal> cache may be used. This is the simplest and best performing
+                strategy. It's even perfectly safe for use in a cluster.
+            </para>
+
+            <programlisting><![CDATA[<class name="eg.Immutable" mutable="false">
+    <cache usage="read-only"/>
+    ....
+</class>]]></programlisting>
+
+        </sect2>
+
+
+        <sect2 id="performance-cache-readwrite">
+            <title>Strategy: read/write</title>
+
+            <para>
+                If the application needs to update data, a <literal>read-write</literal> cache might be appropriate. 
+                This cache strategy should never be used if serializable transaction isolation level is required. 
+                If the cache is used in a JTA environment, you must specify the property 
+                <literal>hibernate.transaction.manager_lookup_class</literal>, naming a strategy for obtaining the 
+                JTA <literal>TransactionManager</literal>. In other environments, you should ensure that the transaction 
+                is completed when <literal>Session.close()</literal> or <literal>Session.disconnect()</literal> is called. 
+                If you wish to use this strategy in a cluster, you should ensure that the underlying cache implementation 
+                supports locking. The built-in cache providers do <emphasis>not</emphasis>.
+            </para>
+
+            <programlisting><![CDATA[<class name="eg.Cat" .... >
+    <cache usage="read-write"/>
+    ....
+    <set name="kittens" ... >
+        <cache usage="read-write"/>
+        ....
+    </set>
+</class>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-cache-nonstrict">
+            <title>Strategy: nonstrict read/write</title>
+
+            <para>
+                If the application only occasionally needs to update data (ie. if it is extremely unlikely that two 
+                transactions would try to update the same item simultaneously) and strict transaction isolation is
+                not required, a <literal>nonstrict-read-write</literal> cache might be appropriate. If the cache is 
+                used in a JTA environment, you must specify <literal>hibernate.transaction.manager_lookup_class</literal>. 
+                In other environments, you should ensure that the transaction is completed when 
+                <literal>Session.close()</literal> or <literal>Session.disconnect()</literal> is called.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-cache-transactional">
+            <title>Strategy: transactional</title>
+
+            <para>
+                The <literal>transactional</literal> cache strategy provides support for fully transactional cache
+                providers such as JBoss TreeCache. Such a cache may only be used in a JTA environment and you must 
+                specify <literal>hibernate.transaction.manager_lookup_class</literal>. 
+            </para>
+
+        </sect2>
+        
+        <para>
+            None of the cache providers support all of the cache concurrency strategies. The following table shows
+            which providers are compatible with which concurrency strategies.
+        </para>
+
+        <table frame="topbot">
+            <title>Cache Concurrency Strategy Support</title>
+            <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="1*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Cache</entry>
+              <entry>read-only</entry>
+              <entry>nonstrict-read-write</entry>
+              <entry>read-write</entry>
+              <entry>transactional</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>Hashtable (not intended for production use)</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>EHCache</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>OSCache</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>SwarmCache</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>JBoss TreeCache</entry>
+                <entry>yes</entry>
+                <entry></entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+    </sect1>
+
+    <sect1 id="performance-sessioncache" revision="2">
+        <title>Managing the caches</title>
+
+        <para>
+            Whenever you pass an object to <literal>save()</literal>, <literal>update()</literal>
+            or <literal>saveOrUpdate()</literal> and whenever you retrieve an object using 
+            <literal>load()</literal>, <literal>get()</literal>, <literal>list()</literal>, 
+            <literal>iterate()</literal> or <literal>scroll()</literal>, that object is added 
+            to the internal cache of the <literal>Session</literal>. 
+        </para>
+        <para>
+            When <literal>flush()</literal> is subsequently called, the state of that object will 
+            be synchronized with the database. If you do not want this synchronization to occur or 
+            if you are processing a huge number of objects and need to manage memory efficiently, 
+            the <literal>evict()</literal> method may be used to remove the object and its collections 
+            from the first-level cache.
+        </para>
+        
+        <programlisting><![CDATA[ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
+while ( cats.next() ) {
+    Cat cat = (Cat) cats.get(0);
+    doSomethingWithACat(cat);
+    sess.evict(cat);
+}]]></programlisting>
+        
+        <para>
+            The <literal>Session</literal> also provides a <literal>contains()</literal> method to determine 
+            if an instance belongs to the session cache.
+        </para>
+        
+        <para>
+            To completely evict all objects from the session cache, call <literal>Session.clear()</literal>
+        </para>
+        
+        <para>
+            For the second-level cache, there are methods defined on <literal>SessionFactory</literal> for 
+            evicting the cached state of an instance, entire class, collection instance or entire collection 
+            role.
+        </para>
+        
+        <programlisting><![CDATA[sessionFactory.evict(Cat.class, catId); //evict a particular Cat
+sessionFactory.evict(Cat.class);  //evict all Cats
+sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
+sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections]]></programlisting>
+
+        <para>
+            The <literal>CacheMode</literal> controls how a particular session interacts with the second-level
+            cache.
+        </para>
+        
+        <itemizedlist>
+        <listitem>
+        <para>
+            <literal>CacheMode.NORMAL</literal> - read items from and write items to the second-level cache
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.GET</literal> - read items from the second-level cache, but don't write to
+            the second-level cache except when updating data
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.PUT</literal> - write items to the second-level cache, but don't read from
+            the second-level cache
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            <literal>CacheMode.REFRESH</literal> - write items to the second-level cache, but don't read from
+            the second-level cache, bypass the effect of <literal>hibernate.cache.use_minimal_puts</literal>, forcing
+            a refresh of the second-level cache for all items read from the database
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            To browse the contents of a second-level or query cache region, use the <literal>Statistics</literal>
+            API:
+        </para>
+        
+        <programlisting><![CDATA[Map cacheEntries = sessionFactory.getStatistics()
+        .getSecondLevelCacheStatistics(regionName)
+        .getEntries();]]></programlisting>
+        
+        <para>
+            You'll need to enable statistics, and, optionally, force Hibernate to keep the cache entries in a
+            more human-understandable format:
+        </para>
+        
+        <programlisting><![CDATA[hibernate.generate_statistics true
+hibernate.cache.use_structured_entries true]]></programlisting>       
+                
+    </sect1>
+    
+    <sect1 id="performance-querycache" revision="1">
+        <title>The Query Cache</title>
+
+        <para>
+            Query result sets may also be cached. This is only useful for queries that are run
+            frequently with the same parameters. To use the query cache you must first enable it:
+        </para>
+
+        <programlisting><![CDATA[hibernate.cache.use_query_cache true]]></programlisting>       
+        
+        <para>
+            This setting causes the creation of two new cache regions - one holding cached query 
+            result sets (<literal>org.hibernate.cache.StandardQueryCache</literal>), the other 
+            holding timestamps of the most recent updates to queryable tables 
+            (<literal>org.hibernate.cache.UpdateTimestampsCache</literal>). Note that the query
+            cache does not cache the state of the actual entities in the result set; it caches 
+            only identifier values and results of value type. So the query cache should always be
+            used in conjunction with the second-level cache.
+        </para>
+        
+        <para>
+            Most queries do not benefit from caching, so by default queries are not cached. To
+            enable caching, call <literal>Query.setCacheable(true)</literal>. This call allows
+            the query to look for existing cache results or add its results to the cache when
+            it is executed.
+        </para>
+        
+        <para>
+            If you require fine-grained control over query cache expiration policies, you may
+            specify a named cache region for a particular query by calling 
+            <literal>Query.setCacheRegion()</literal>.
+        </para>
+        
+        <programlisting><![CDATA[List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
+    .setEntity("blogger", blogger)
+    .setMaxResults(15)
+    .setCacheable(true)
+    .setCacheRegion("frontpages")
+    .list();]]></programlisting>
+
+        <para>
+            If the query should force a refresh of its query cache region, you should call
+            <literal>Query.setCacheMode(CacheMode.REFRESH)</literal>. This is particularly useful 
+            in cases where underlying data may have been updated via a separate process (i.e., 
+            not modified through Hibernate) and allows the application to selectively refresh 
+            particular query result sets. This is a more efficient alternative to eviction of 
+            a query cache region via <literal>SessionFactory.evictQueries()</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="performance-collections">
+        <title>Understanding Collection performance</title>
+
+        <para>
+            We've already spent quite some time talking about collections.
+            In this section we will highlight a couple more issues about
+            how collections behave at runtime.
+        </para>
+
+        <sect2 id="performance-collections-taxonomy">
+            <title>Taxonomy</title>
+
+            <para>Hibernate defines three basic kinds of collections:</para>
+
+            <itemizedlist>
+            <listitem>
+                <para>collections of values</para>
+            </listitem>
+            <listitem>
+                <para>one to many associations</para>
+            </listitem>
+            <listitem>
+                <para>many to many associations</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                This classification distinguishes the various table and foreign key
+                relationships but does not tell us quite everything we need to know
+                about the relational model. To fully understand the relational structure
+                and performance characteristics, we must also consider the structure of
+                the primary key that is used by Hibernate to update or delete collection
+                rows. This suggests the following classification:
+            </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>indexed collections</para>
+            </listitem>
+            <listitem>
+                <para>sets</para>
+            </listitem>
+            <listitem>
+                <para>bags</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                All indexed collections (maps, lists, arrays) have a primary key consisting
+                of the <literal>&lt;key&gt;</literal> and <literal>&lt;index&gt;</literal>
+                columns. In this case collection updates are usually extremely efficient -
+                the primary key may be efficiently indexed and a particular row may be efficiently
+                located when Hibernate tries to update or delete it.
+            </para>
+                        
+            <para>
+                Sets have a primary key consisting of <literal>&lt;key&gt;</literal> and element
+                columns. This may be less efficient for some types of collection element, particularly
+                composite elements or large text or binary fields; the database may not be able to index
+                a complex primary key as efficently.  On the other hand, for one to many or many to many
+                associations, particularly in the case of synthetic identifiers, it is likely to be just
+                as efficient. (Side-note: if you want <literal>SchemaExport</literal> to actually create
+                the primary key of a <literal>&lt;set&gt;</literal> for you, you must declare all columns
+                as <literal>not-null="true"</literal>.)
+            </para>
+
+            <para>
+                <literal>&lt;idbag&gt;</literal> mappings define a surrogate key, so they are
+                always very efficient to update. In fact, they are the best case.
+            </para>
+            
+            <para>
+                Bags are the worst case. Since a bag permits duplicate element values and has no
+                index column, no primary key may be defined. Hibernate has no way of distinguishing
+                between duplicate rows. Hibernate resolves this problem by completely removing
+                (in a single <literal>DELETE</literal>) and recreating the collection whenever it
+                changes. This might be very inefficient.
+            </para>
+
+            <para>
+                Note that for a one-to-many association, the "primary key" may not be the physical
+                primary key of the database table - but even in this case, the above classification
+                is still useful. (It still reflects how Hibernate "locates" individual rows of the
+                collection.)
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-collections-mostefficientupdate">
+            <title>Lists, maps, idbags and sets are the most efficient collections to update</title>
+
+            <para>
+                From the discussion above, it should be clear that indexed collections
+                and (usually) sets allow the most efficient operation in terms of adding,
+                removing and updating elements.
+            </para>
+
+            <para>
+                There is, arguably, one more advantage that indexed collections have over sets for
+                many to many associations or collections of values. Because of the structure of a
+                <literal>Set</literal>, Hibernate doesn't ever <literal>UPDATE</literal> a row when
+                an element is "changed". Changes to a <literal>Set</literal> always work via
+                <literal>INSERT</literal> and <literal>DELETE</literal> (of individual rows). Once
+                again, this consideration does not apply to one to many associations.
+            </para>
+
+            <para>
+                After observing that arrays cannot be lazy, we would conclude that lists, maps and 
+                idbags are the most performant (non-inverse) collection types, with sets not far 
+                behind. Sets are expected to be the most common kind of collection in Hibernate 
+                applications. This is because the "set" semantics are most natural in the relational
+                model.
+            </para>
+
+            <para>
+                However, in well-designed Hibernate domain models, we usually see that most collections
+                are in fact one-to-many associations with <literal>inverse="true"</literal>. For these
+                associations, the update is handled by the many-to-one end of the association, and so
+                considerations of collection update performance simply do not apply.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-collections-mostefficentinverse">
+            <title>Bags and lists are the most efficient inverse collections</title>
+
+            <para>
+                Just before you ditch bags forever, there is a particular case in which bags (and also lists)
+                are much more performant than sets. For a collection with <literal>inverse="true"</literal>
+                (the standard bidirectional one-to-many relationship idiom, for example) we can add elements
+                to a bag or list without needing to initialize (fetch) the bag elements! This is because
+                <literal>Collection.add()</literal> or <literal>Collection.addAll()</literal> must always
+                return true for a bag or <literal>List</literal> (unlike a <literal>Set</literal>). This can
+                make the following common code much faster.
+            </para>
+
+            <programlisting><![CDATA[Parent p = (Parent) sess.load(Parent.class, id);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c);  //no need to fetch the collection!
+sess.flush();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-collections-oneshotdelete">
+            <title>One shot delete</title>
+
+            <para>
+                Occasionally, deleting collection elements one by one can be extremely inefficient. Hibernate
+                isn't completely stupid, so it knows not to do that in the case of an newly-empty collection
+                (if you called <literal>list.clear()</literal>, for example). In this case, Hibernate will
+                issue a single <literal>DELETE</literal> and we are done!
+            </para>
+
+            <para>
+                Suppose we add a single element to a collection of size twenty and then remove two elements.
+                Hibernate will issue one <literal>INSERT</literal> statement and two <literal>DELETE</literal>
+                statements (unless the collection is a bag). This is certainly desirable.
+            </para>
+
+            <para>
+                However, suppose that we remove eighteen elements, leaving two and then add thee new elements.
+                There are two possible ways to proceed
+            </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>delete eighteen rows one by one and then insert three rows</para>
+            </listitem>
+            <listitem>
+                <para>remove the whole collection (in one SQL <literal>DELETE</literal>) and insert
+                all five current elements (one by one)</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+                Hibernate isn't smart enough to know that the second option is probably quicker in this case.
+                (And it would probably be undesirable for Hibernate to be that smart; such behaviour might
+                confuse database triggers, etc.)
+            </para>
+
+            <para>
+                Fortunately, you can force this behaviour (ie. the second strategy) at any time by discarding
+                (ie. dereferencing) the original collection and returning a newly instantiated collection with
+                all the current elements. This can be very useful and powerful from time to time.
+            </para>
+            
+            <para>
+                Of course, one-shot-delete does not apply to collections mapped <literal>inverse="true"</literal>.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="performance-monitoring" revision="1">
+        <title>Monitoring performance</title>
+
+        <para>
+            Optimization is not much use without monitoring and access to performance numbers.
+            Hibernate provides a full range of figures about its internal operations.
+            Statistics in Hibernate are available per <literal>SessionFactory</literal>.
+        </para>
+
+        <sect2 id="performance-monitoring-sf" revision="2">
+            <title>Monitoring a SessionFactory</title>
+
+            <para>
+                You can access <literal>SessionFactory</literal> metrics in two ways.
+                Your first option is to call <literal>sessionFactory.getStatistics()</literal> and
+                read or display the <literal>Statistics</literal> yourself.
+            </para>
+
+            <para>
+                Hibernate can also use JMX to publish metrics if you enable the
+                <literal>StatisticsService</literal> MBean. You may enable a single MBean for all your
+                <literal>SessionFactory</literal> or one per factory. See the following code for
+                minimalistic configuration examples:
+            </para>
+
+            <programlisting><![CDATA[// MBean service registration for a specific SessionFactory
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "myFinancialApp");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
+server.registerMBean(stats, on); // Register the Mbean on the server]]></programlisting>
+
+
+<programlisting><![CDATA[// MBean service registration for all SessionFactory's
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "all");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+server.registerMBean(stats, on); // Register the MBean on the server]]></programlisting>
+
+            <para>
+                TODO: This doesn't make sense: In the first case, we retrieve and use the MBean directly. In the second one, we must give
+                the JNDI name in which the session factory is held before using it. Use
+                <literal>hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")</literal>
+            </para>
+            <para>
+                You can (de)activate the monitoring for a <literal>SessionFactory</literal>
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        at configuration time, set <literal>hibernate.generate_statistics</literal> to <literal>false</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        at runtime: <literal>sf.getStatistics().setStatisticsEnabled(true)</literal>
+                        or <literal>hibernateStatsBean.setStatisticsEnabled(true)</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Statistics can be reset programatically using the <literal>clear()</literal> method.
+                A summary can be sent to a logger (info level) using the <literal>logSummary()</literal>
+                method.
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-monitoring-metrics" revision="1">
+            <title>Metrics</title>
+
+            <para>
+                Hibernate provides a number of metrics, from very basic to the specialized information
+                only relevant in certain scenarios. All available counters are described in the
+                <literal>Statistics</literal> interface API, in three categories:
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        Metrics related to the general <literal>Session</literal> usage, such as
+                        number of open sessions, retrieved JDBC connections, etc.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Metrics related to he entities, collections, queries, and caches as a
+                        whole (aka global metrics),
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Detailed metrics related to a particular entity, collection, query or
+                        cache region.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                For exampl,e you can check the cache hit, miss, and put ratio of entities, collections
+                and queries, and the average time a query needs. Beware that the number of milliseconds
+                is subject to approximation in Java. Hibernate is tied to the JVM precision, on some
+                platforms this might even only be accurate to 10 seconds.
+            </para>
+
+            <para>
+                Simple getters are used to access the global metrics (i.e. not tied to a particular entity,
+                collection, cache region, etc.). You can access the metrics of a particular entity, collection
+                or cache region through its name, and through its HQL or SQL representation for queries. Please
+                refer to the <literal>Statistics</literal>, <literal>EntityStatistics</literal>,
+                <literal>CollectionStatistics</literal>, <literal>SecondLevelCacheStatistics</literal>,
+                and <literal>QueryStatistics</literal> API Javadoc for more information. The following
+                code shows a simple example:
+            </para>
+
+            <programlisting><![CDATA[Statistics stats = HibernateUtil.sessionFactory.getStatistics();
+
+double queryCacheHitCount  = stats.getQueryCacheHitCount();
+double queryCacheMissCount = stats.getQueryCacheMissCount();
+double queryCacheHitRatio =
+  queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
+
+log.info("Query Hit ratio:" + queryCacheHitRatio);
+
+EntityStatistics entityStats =
+  stats.getEntityStatistics( Cat.class.getName() );
+long changes =
+        entityStats.getInsertCount()
+        + entityStats.getUpdateCount()
+        + entityStats.getDeleteCount();
+log.info(Cat.class.getName() + " changed " + changes + "times"  );]]></programlisting>
+
+            <para>
+                To work on all entities, collections, queries and region caches, you can retrieve
+                the list of names of entities, collections, queries and region caches with the
+                following methods: <literal>getQueries()</literal>, <literal>getEntityNames()</literal>,
+                <literal>getCollectionRoleNames()</literal>, and
+                <literal>getSecondLevelCacheRegionNames()</literal>.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
\ No newline at end of file


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/performance.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/persistent_classes.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/persistent_classes.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/persistent_classes.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,531 @@
+<chapter id="persistent-classes" revision="2">
+    <title>Persistent Classes</title>
+
+    <para>
+        Persistent classes are classes in an application that implement the entities
+        of the business problem (e.g. Customer and Order in an E-commerce application).
+        Not all instances of a persistent class are considered to be in the persistent 
+        state - an instance may instead be transient or detached.
+    </para>
+
+    <para>
+        Hibernate works best if these classes follow some simple rules, also known
+        as the Plain Old Java Object (POJO) programming model. However, none of these
+        rules are hard requirements. Indeed, Hibernate3 assumes very little about
+        the nature of your persistent objects. You may express a domain model in other 
+        ways: using trees of <literal>Map</literal> instances, for example.
+    </para>
+
+    <sect1 id="persistent-classes-pojo">
+        <title>A simple POJO example</title>
+
+        <para>
+            Most Java applications require a persistent class representing felines.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+public class Cat {
+    private Long id; // identifier
+
+    private Date birthdate;
+    private Color color;
+    private char sex;
+    private float weight;
+    private int litterId;
+
+    private Cat mother;
+    private Set kittens = new HashSet();
+
+    private void setId(Long id) {
+        this.id=id;
+    }
+    public Long getId() {
+        return id;
+    }
+
+    void setBirthdate(Date date) {
+        birthdate = date;
+    }
+    public Date getBirthdate() {
+        return birthdate;
+    }
+
+    void setWeight(float weight) {
+        this.weight = weight;
+    }
+    public float getWeight() {
+        return weight;
+    }
+
+    public Color getColor() {
+        return color;
+    }
+    void setColor(Color color) {
+        this.color = color;
+    }
+
+    void setSex(char sex) {
+        this.sex=sex;
+    }
+    public char getSex() {
+        return sex;
+    }
+
+    void setLitterId(int id) {
+        this.litterId = id;
+    }
+    public int getLitterId() {
+        return litterId;
+    }
+
+    void setMother(Cat mother) {
+        this.mother = mother;
+    }
+    public Cat getMother() {
+        return mother;
+    }
+    void setKittens(Set kittens) {
+        this.kittens = kittens;
+    }
+    public Set getKittens() {
+        return kittens;
+    }
+    
+    // addKitten not needed by Hibernate
+    public void addKitten(Cat kitten) {
+    	kitten.setMother(this);
+	kitten.setLitterId( kittens.size() ); 
+        kittens.add(kitten);
+    }
+}]]></programlisting>
+
+        <para>
+            There are four main rules to follow here:
+        </para>
+
+
+        <sect2 id="persistent-classes-pojo-constructor" revision="1">
+            <title>Implement a no-argument constructor</title>
+
+            <para>
+                <literal>Cat</literal> has a no-argument constructor. All persistent classes must 
+                have a default constructor (which may be non-public) so that Hibernate can instantiate 
+                them using <literal>Constructor.newInstance()</literal>. We strongly recommend having a 
+                default constructor with at least <emphasis>package</emphasis> visibility for runtime proxy 
+                generation in Hibernate.
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-identifier" revision="2">
+            <title>Provide an identifier property (optional)</title>
+
+            <para>
+                <literal>Cat</literal> has a property called <literal>id</literal>. This property 
+                maps to the primary key column of a database table. The property might have been called
+                anything, and its type might have been any primitive type, any primitive "wrapper" 
+                type, <literal>java.lang.String</literal> or <literal>java.util.Date</literal>. (If 
+                your legacy database table has composite keys, you can even use a user-defined class 
+                with properties of these types - see the section on composite identifiers later.)
+            </para>
+
+            <para>
+                The identifier property is strictly optional. You can leave them off and let Hibernate 
+                keep track of object identifiers internally. We do not recommend this, however.
+            </para>
+
+            <para>
+                In fact, some functionality is available only to classes which declare an
+                identifier property:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        Transitive reattachment for detached objects (cascade update or cascade
+                        merge) - see <xref linkend="objectstate-transitive"/>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session.saveOrUpdate()</literal>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session.merge()</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                We recommend you declare consistently-named identifier properties on persistent
+                classes. We further recommend that you use a nullable (ie. non-primitive) type.
+            </para>
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-final">
+            <title>Prefer non-final classes (optional)</title>
+            <para>
+                A central feature of Hibernate, <emphasis>proxies</emphasis>, depends upon the
+                persistent class being either non-final, or the implementation of an interface
+                that declares all public methods.
+            </para>
+            <para>
+                You can persist <literal>final</literal> classes that do not implement an interface
+                with Hibernate, but you won't be able to use proxies for lazy association fetching -
+                which will limit your options for performance tuning.
+            </para>
+            <para>
+                You should also avoid declaring <literal>public final</literal> methods on the 
+                non-final classes. If you want to use a class with a <literal>public final</literal> 
+                method, you must explicitly disable proying by setting <literal>lazy="false"</literal>.
+            </para>
+        </sect2>
+        
+        <sect2 id="persistent-classes-pojo-accessors" revision="2">
+            <title>Declare accessors and mutators for persistent fields (optional)</title>
+
+            <para>
+                <literal>Cat</literal> declares accessor methods for all its persistent fields.
+                Many other ORM tools directly persist instance variables. We believe it is 
+                better to provide an indirection between the relational schema and internal
+                data structures of the class. By default, Hibernate persists JavaBeans style 
+                properties, and recognizes method names of the form <literal>getFoo</literal>, 
+                <literal>isFoo</literal> and <literal>setFoo</literal>. You may switch to direct 
+                field access for particular properties, if needed.
+            </para>
+
+            <para>
+                Properties need <emphasis>not</emphasis> be declared public - Hibernate can
+                persist a property with a default, <literal>protected</literal> or 
+                <literal>private</literal> get / set pair.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-inheritance">
+        <title>Implementing inheritance</title>
+
+        <para>
+            A subclass must also observe the first and second rules. It inherits its
+            identifier property from the superclass, <literal>Cat</literal>.
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+public class DomesticCat extends Cat {
+        private String name;
+
+        public String getName() {
+                return name;
+        }
+        protected void setName(String name) {
+                this.name=name;
+        }
+}]]></programlisting>
+    </sect1>
+
+    <sect1 id="persistent-classes-equalshashcode" revision="1">
+        <title>Implementing <literal>equals()</literal> and <literal>hashCode()</literal></title>
+
+        <para>
+            You have to override the <literal>equals()</literal> and <literal>hashCode()</literal>
+            methods if you 
+        </para>
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    intend to put instances of persistent classes in a <literal>Set</literal>
+                    (the recommended way to represent many-valued associations) 
+                    <emphasis>and</emphasis>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    intend to use reattachment of detached instances
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Hibernate guarantees equivalence of persistent identity (database row) and Java identity
+            only inside a particular session scope. So as soon as we mix instances retrieved in
+            different sessions, we must implement <literal>equals()</literal> and
+            <literal>hashCode()</literal> if we wish to have meaningful semantics for
+            <literal>Set</literal>s.
+        </para>
+
+        <para>
+            The most obvious way is to implement <literal>equals()</literal>/<literal>hashCode()</literal>
+            by comparing the identifier value of both objects. If the value is the same, both must
+            be the same database row, they are therefore equal (if both are added to a <literal>Set</literal>,
+            we will only have one element in the <literal>Set</literal>). Unfortunately, we can't use that
+            approach with generated identifiers! Hibernate will only assign identifier values to objects 
+            that are persistent, a newly created instance will not have any identifier value! Furthermore,
+            if an instance is unsaved and currently in a <literal>Set</literal>, saving it will assign
+            an identifier value to the object. If <literal>equals()</literal> and <literal>hashCode()</literal>
+            are based on the identifier value, the hash code would change, breaking the contract of the
+            <literal>Set</literal>. See the Hibernate website for a full discussion of this problem. Note
+            that this is not a Hibernate issue, but normal Java semantics of object identity and equality.
+        </para>
+
+        <para>
+            We recommend  implementing <literal>equals()</literal> and <literal>hashCode()</literal>
+            using <emphasis>Business key equality</emphasis>. Business key equality means that the
+            <literal>equals()</literal> method compares only the properties that form the business
+            key, a key that would identify our instance in the real world (a
+            <emphasis>natural</emphasis> candidate key):
+        </para>
+
+        <programlisting><![CDATA[public class Cat {
+
+    ...
+    public boolean equals(Object other) {
+        if (this == other) return true;
+        if ( !(other instanceof Cat) ) return false;
+
+        final Cat cat = (Cat) other;
+
+        if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
+        if ( !cat.getMother().equals( getMother() ) ) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result;
+        result = getMother().hashCode();
+        result = 29 * result + getLitterId();
+        return result;
+    }
+
+}]]></programlisting>
+
+        <para>
+            Note that a business key does not have to be as solid as a database
+            primary key candidate (see <xref linkend="transactions-basics-identity"/>).
+            Immutable or unique properties are usually good
+            candidates for a business key.
+        </para>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-dynamicmodels">
+        <title>Dynamic models</title>
+
+        <para>
+            <emphasis>Note that the following features are currently considered
+            experimental and may change in the near future.</emphasis>
+        </para>
+
+        <para>
+            Persistent entities don't necessarily have to be represented as POJO classes
+            or as JavaBean objects at runtime. Hibernate also supports dynamic models
+            (using <literal>Map</literal>s of <literal>Map</literal>s at runtime) and the
+            representation of entities as DOM4J trees. With this approach, you don't
+            write persistent classes, only mapping files.
+        </para>
+
+        <para>
+            By default, Hibernate works in normal POJO mode. You may set a default entity
+            representation mode for a particular <literal>SessionFactory</literal> using the
+            <literal>default_entity_mode</literal> configuration option (see
+            <xref linkend="configuration-optional-properties"/>.
+        </para>
+
+        <para>
+            The following examples demonstrates the representation using <literal>Map</literal>s.
+            First, in the mapping file, an <literal>entity-name</literal> has to be declared
+            instead of (or in addition to) a class name:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class entity-name="Customer">
+
+        <id name="id"
+            type="long"
+            column="ID">
+            <generator class="sequence"/>
+        </id>
+
+        <property name="name"
+            column="NAME"
+            type="string"/>
+
+        <property name="address"
+            column="ADDRESS"
+            type="string"/>
+
+        <many-to-one name="organization"
+            column="ORGANIZATION_ID"
+            class="Organization"/>
+
+        <bag name="orders"
+            inverse="true"
+            lazy="false"
+            cascade="all">
+            <key column="CUSTOMER_ID"/>
+            <one-to-many class="Order"/>
+        </bag>
+
+    </class>
+    
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+
+            Note that even though associations are declared using target class names,
+            the target type of an associations may also be a dynamic entity instead
+            of a POJO.
+        </para>
+
+        <para>
+            After setting the default entity mode to <literal>dynamic-map</literal>
+            for the <literal>SessionFactory</literal>, we can at runtime work with
+            <literal>Map</literal>s of <literal>Map</literal>s:
+        </para>
+
+        <programlisting><![CDATA[Session s = openSession();
+Transaction tx = s.beginTransaction();
+Session s = openSession();
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+
+// Create an organization
+Map foobar = new HashMap();
+foobar.put("name", "Foobar Inc.");
+
+// Link both
+david.put("organization", foobar);
+
+// Save both
+s.save("Customer", david);
+s.save("Organization", foobar);
+
+tx.commit();
+s.close();]]></programlisting>
+
+        <para>
+            The advantages of a dynamic mapping are quick turnaround time for prototyping
+            without the need for entity class implementation. However, you lose compile-time
+            type checking and will very likely deal with many exceptions at runtime. Thanks
+            to the Hibernate mapping, the database schema can easily be normalized and sound,
+            allowing to add a proper domain model implementation on top later on.
+        </para>
+
+        <para>
+            Entity representation modes can also be set on a per <literal>Session</literal>
+            basis:
+        </para>
+
+        <programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+dynamicSession.save("Customer", david);
+...
+dynamicSession.flush();
+dynamicSession.close()
+...
+// Continue on pojoSession
+]]></programlisting>
+
+
+        <para>
+            Please note that the call to <literal>getSession()</literal> using an
+            <literal>EntityMode</literal> is on the <literal>Session</literal> API, not the
+            <literal>SessionFactory</literal>. That way, the new <literal>Session</literal>
+            shares the underlying JDBC connection, transaction, and other context
+            information. This means you don't have tocall <literal>flush()</literal>
+            and <literal>close()</literal> on the secondary <literal>Session</literal>, and
+            also leave the transaction and connection handling to the primary unit of work.
+        </para>
+
+        <para>
+            More information about the XML representation capabilities can be found
+            in <xref linkend="xml"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-tuplizers" revision="0">
+        <title>Tuplizers</title>
+
+        <para>
+            <literal>org.hibernate.tuple.Tuplizer</literal>, and its sub-interfaces, are responsible
+            for managing a particular representation of a piece of data, given that representation's
+            <literal>org.hibernate.EntityMode</literal>.  If a given piece of data is thought of as
+            a data structure, then a tuplizer is the thing which knows how to create such a data structure
+            and how to extract values from and inject values into such a data structure.  For example,
+            for the POJO entity mode, the correpsonding tuplizer knows how create the POJO through its
+            constructor and how to access the POJO properties using the defined property accessors.
+            There are two high-level types of Tuplizers, represented by the
+            <literal>org.hibernate.tuple.EntityTuplizer</literal> and <literal>org.hibernate.tuple.ComponentTuplizer</literal>
+            interfaces.  <literal>EntityTuplizer</literal>s are responsible for managing the above mentioned
+            contracts in regards to entities, while <literal>ComponentTuplizer</literal>s do the same for
+            components.
+        </para>
+
+        <para>
+            Users may also plug in their own tuplizers.  Perhaps you require that a <literal>java.util.Map</literal>
+            implementation other than <literal>java.util.HashMap</literal> be used while in the
+            dynamic-map entity-mode; or perhaps you need to define a different proxy generation strategy
+            than the one used by default.  Both would be achieved by defining a custom tuplizer
+            implementation.  Tuplizers definitions are attached to the entity or component mapping they
+            are meant to manage.  Going back to the example of our customer entity:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+    <class entity-name="Customer">
+        <!--
+            Override the dynamic-map entity-mode
+            tuplizer for the customer entity
+        -->
+        <tuplizer entity-mode="dynamic-map"
+                class="CustomMapTuplizerImpl"/>
+
+        <id name="id" type="long" column="ID">
+            <generator class="sequence"/>
+        </id>
+
+        <!-- other properties -->
+        ...
+    </class>
+</hibernate-mapping>
+
+
+public class CustomMapTuplizerImpl
+        extends org.hibernate.tuple.DynamicMapEntityTuplizer {
+    // override the buildInstantiator() method to plug in our custom map...
+    protected final Instantiator buildInstantiator(
+            org.hibernate.mapping.PersistentClass mappingInfo) {
+        return new CustomMapInstantiator( mappingInfo );
+    }
+
+    private static final class CustomMapInstantiator
+            extends org.hibernate.tuple.DynamicMapInstantitor {
+        // override the generateMap() method to return our custom map...
+	    protected final Map generateMap() {
+		    return new CustomMap();
+	    }
+    }
+}]]></programlisting>
+
+
+    </sect1>
+
+    <para>
+        TODO: Document user-extension framework in the property and proxy packages
+    </para>
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/persistent_classes.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_criteria.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_criteria.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_criteria.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,436 @@
+<chapter id="querycriteria">
+    <title>Consultas por critérios</title>
+
+    <para>
+        O Hibernate provê uma intuitiva e extensível API de critério de query.
+    </para>
+    
+    <sect1 id="querycriteria-creating">
+        <title>Criando uma instancia <literal>Criteria</literal></title>
+
+        <para>
+            A interface <literal>org.hibernate.Criteria</literal>  representa a query 
+            ao invés de uma classe persistente particular. A sessão é uma fábrica para 
+            intancias de <literal>Criteria</literal> .
+        </para>
+
+        <programlisting><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
+crit.setMaxResults(50);
+List cats = crit.list();]]></programlisting>
+
+    </sect1>
+     
+    <sect1 id="querycriteria-narrowing">
+        <title>Limitando o result set</title>
+
+        <para>
+            Um critério individual de query é uma instancia da interface 
+            <literal>org.hibernate.criterion.Criterion</literal>. A classe 
+            <literal>org.hibernate.criterion.Restrictions</literal> define 
+            os métodos da fábrica para obter certos tipos pré fabricados
+            de <literal>Criterion</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .add( Restrictions.between("weight", minWeight, maxWeight) )
+    .list();]]></programlisting>
+    
+        <para>
+            Restrições podem ser logicamente agrupadas.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .add( Restrictions.or(
+        Restrictions.eq( "age", new Integer(0) ),
+        Restrictions.isNull("age")
+    ) )
+    .list();]]></programlisting>
+    
+       <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
+    .add( Restrictions.disjunction()
+        .add( Restrictions.isNull("age") )
+        .add( Restrictions.eq("age", new Integer(0) ) )
+        .add( Restrictions.eq("age", new Integer(1) ) )
+        .add( Restrictions.eq("age", new Integer(2) ) )
+    ) )
+    .list();]]></programlisting>
+    
+        <para>
+            Existe um grande número de critérios pré fabricados (subclasses de
+            <literal>Restrictions</literal>), mas um é especialmente útil pois
+             permite especificar o SQL diretamente. 
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.sqlRestriction("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
+    .list();]]></programlisting>
+    
+        <para>
+            O parametro <literal>{alias}</literal>  será substituido pelo alias da entidade procurada.
+        </para>
+        
+        <para>
+            Uma maneira alternativa de obter um critério é pegá-lo de uma instancia de
+            <literal>Property</literal>. Você pode criar uma <literal>Property</literal>
+            chamando <literal>Property.forName()</literal>.
+        </para>
+    
+        <programlisting><![CDATA[
+Property age = Property.forName("age");
+List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.disjunction()
+        .add( age.isNull() )
+        .add( age.eq( new Integer(0) ) )
+        .add( age.eq( new Integer(1) ) )
+        .add( age.eq( new Integer(2) ) )
+    ) )
+    .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
+    .list();]]></programlisting>
+    
+   </sect1>
+     
+    <sect1 id="querycriteria-ordering">
+        <title>Ordering the results</title>
+
+        <para>
+            You may order the results using <literal>org.hibernate.criterion.Order</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "F%")
+    .addOrder( Order.asc("name") )
+    .addOrder( Order.desc("age") )
+    .setMaxResults(50)
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Property.forName("name").like("F%") )
+    .addOrder( Property.forName("name").asc() )
+    .addOrder( Property.forName("age").desc() )
+    .setMaxResults(50)
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-associations" revision="2">
+        <title>Associations</title>
+
+        <para>
+            You may easily specify constraints upon related entities by navigating
+            associations using <literal>createCriteria()</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "F%") )
+    .createCriteria("kittens")
+        .add( Restrictions.like("name", "F%") )
+    .list();]]></programlisting>
+
+        <para>
+            note that the second <literal>createCriteria()</literal> returns a new
+            instance of <literal>Criteria</literal>, which refers to the elements of
+            the <literal>kittens</literal> collection.
+        </para>
+
+        <para>
+            The following, alternate form is useful in certain circumstances.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .createAlias("kittens", "kt")
+    .createAlias("mate", "mt")
+    .add( Restrictions.eqProperty("kt.name", "mt.name") )
+    .list();]]></programlisting>
+
+        <para>
+            (<literal>createAlias()</literal> does not create a new instance of
+            <literal>Criteria</literal>.)
+        </para>
+
+        <para>
+            Note that the kittens collections held by the <literal>Cat</literal> instances
+            returned by the previous two queries are <emphasis>not</emphasis> pre-filtered
+            by the criteria! If you wish to retrieve just the kittens that match the
+            criteria, you must use a <literal>ResultTransformer</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .createCriteria("kittens", "kt")
+        .add( Restrictions.eq("name", "F%") )
+    .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+    .list();
+Iterator iter = cats.iterator();
+while ( iter.hasNext() ) {
+    Map map = (Map) iter.next();
+    Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
+    Cat kitten = (Cat) map.get("kt");
+}]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="querycriteria-dynamicfetching" revision="1">
+        <title>Dynamic association fetching</title>
+
+        <para>
+            You may specify association fetching semantics at runtime using
+            <literal>setFetchMode()</literal>.
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .setFetchMode("mate", FetchMode.EAGER)
+    .setFetchMode("kittens", FetchMode.EAGER)
+    .list();]]></programlisting>
+    
+        <para>
+            This query will fetch both <literal>mate</literal> and <literal>kittens</literal>
+            by outer join. See <xref linkend="performance-fetching"/> for more information.
+        </para>
+    
+    </sect1>
+     
+    <sect1 id="querycriteria-examples">
+        <title>Example queries</title>
+
+        <para>
+            The class <literal>org.hibernate.criterion.Example</literal> allows
+            you to construct a query criterion from a given instance.
+        </para>
+
+        <programlisting><![CDATA[Cat cat = new Cat();
+cat.setSex('F');
+cat.setColor(Color.BLACK);
+List results = session.createCriteria(Cat.class)
+    .add( Example.create(cat) )
+    .list();]]></programlisting>
+    
+        <para>
+           Version properties, identifiers and associations are ignored. By default,
+           null valued properties are excluded.
+        </para>
+
+        <para>
+           You can adjust how the <literal>Example</literal> is applied.
+        </para>
+
+        <programlisting><![CDATA[Example example = Example.create(cat)
+    .excludeZeroes()           //exclude zero valued properties
+    .excludeProperty("color")  //exclude the property named "color"
+    .ignoreCase()              //perform case insensitive string comparisons
+    .enableLike();             //use like for string comparisons
+List results = session.createCriteria(Cat.class)
+    .add(example)
+    .list();]]></programlisting>
+    
+        <para>
+            You can even use examples to place criteria upon associated objects.
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .add( Example.create(cat) )
+    .createCriteria("mate")
+        .add( Example.create( cat.getMate() ) )
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-projection">
+        <title>Projections, aggregation and grouping</title>
+        <para>
+            The class <literal>org.hibernate.criterion.Projections</literal> is a
+            factory for <literal>Projection</literal> instances. We apply a
+            projection to a query by calling <literal>setProjection()</literal>.
+        </para>
+        
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.rowCount() )
+    .add( Restrictions.eq("color", Color.BLACK) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount() )
+        .add( Projections.avg("weight") )
+        .add( Projections.max("weight") )
+        .add( Projections.groupProperty("color") )
+    )
+    .list();]]></programlisting>
+    
+        <para>
+            There is no explicit "group by" necessary in a criteria query. Certain
+            projection types are defined to be <emphasis>grouping projections</emphasis>,
+            which also appear in the SQL <literal>group by</literal> clause.
+        </para>
+    
+        <para>
+            An alias may optionally be assigned to a projection, so that the projected value
+            may be referred to in restrictions or orderings. Here are two different ways to
+            do this:
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
+    .addOrder( Order.asc("colr") )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.groupProperty("color").as("colr") )
+    .addOrder( Order.asc("colr") )
+    .list();]]></programlisting>
+    
+        <para>
+            The <literal>alias()</literal> and <literal>as()</literal> methods simply wrap a
+            projection instance in another, aliased, instance of <literal>Projection</literal>.
+            As a shortcut, you can assign an alias when you add the projection to a 
+            projection list:
+        </para>
+
+       <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount(), "catCountByColor" )
+        .add( Projections.avg("weight"), "avgWeight" )
+        .add( Projections.max("weight"), "maxWeight" )
+        .add( Projections.groupProperty("color"), "color" )
+    )
+    .addOrder( Order.desc("catCountByColor") )
+    .addOrder( Order.desc("avgWeight") )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Domestic.class, "cat")
+    .createAlias("kittens", "kit")
+    .setProjection( Projections.projectionList()
+        .add( Projections.property("cat.name"), "catName" )
+        .add( Projections.property("kit.name"), "kitName" )
+    )
+    .addOrder( Order.asc("catName") )
+    .addOrder( Order.asc("kitName") )
+    .list();]]></programlisting>
+    
+        <para>
+            You can also use <literal>Property.forName()</literal> to express projections:
+        </para>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Property.forName("name") )
+    .add( Property.forName("color").eq(Color.BLACK) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount().as("catCountByColor") )
+        .add( Property.forName("weight").avg().as("avgWeight") )
+        .add( Property.forName("weight").max().as("maxWeight") )
+        .add( Property.forName("color").group().as("color" )
+    )
+    .addOrder( Order.desc("catCountByColor") )
+    .addOrder( Order.desc("avgWeight") )
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-detachedqueries">
+        <title>Detached queries and subqueries</title>
+        <para>
+            The <literal>DetachedCriteria</literal> class lets you create a query outside the scope 
+            of a session, and then later execute it using some arbitrary <literal>Session</literal>.
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
+    .add( Property.forName("sex").eq('F') );
+    
+Session session = ....;
+Transaction txn = session.beginTransaction();
+List results = query.getExecutableCriteria(session).setMaxResults(100).list();
+txn.commit();
+session.close();]]></programlisting>
+
+        <para>
+            A <literal>DetachedCriteria</literal> may also be used to express a subquery. Criterion
+            instances involving subqueries may be obtained via <literal>Subqueries</literal> or
+            <literal>Property</literal>.            
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
+    .setProjection( Property.forName("weight").avg() );
+session.createCriteria(Cat.class)
+    .add( Property.forName("weight).gt(avgWeight) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
+    .setProjection( Property.forName("weight") );
+session.createCriteria(Cat.class)
+    .add( Subqueries.geAll("weight", weights) )
+    .list();]]></programlisting>
+    
+        <para>
+            Even correlated subqueries are possible:
+        </para>
+        
+        <programlisting><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
+    .setProjection( Property.forName("weight").avg() )
+    .add( Property.forName("cat2.sex").eqProperty("cat.sex") );
+session.createCriteria(Cat.class, "cat")
+    .add( Property.forName("weight).gt(avgWeightForSex) )
+    .list();]]></programlisting>
+
+    </sect1>
+
+        <!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer allow returning arbitrary 
+                  user objects - similar to setResultClass in JDO2. General use of ResultTransformer 
+                  could also be explained. -->
+               
+    <sect1 id="query-criteria-naturalid">
+        <title>Queries by natural identifier</title>
+        
+        <para>
+            For most queries, including criteria queries, the query cache is not very efficient,
+            because query cache invalidation occurs too frequently. However, there is one special
+            kind of query where we can optimize the cache invalidation algorithm: lookups by a 
+            constant natural key. In some applications, this kind of query occurs frequently.
+            The criteria API provides special provision for this use case.
+        </para>
+        
+        <para>
+            First, you should map the natural key of your entity using 
+            <literal>&lt;natural-id&gt;</literal>, and enable use of the second-level cache.
+        </para>
+
+        <programlisting><![CDATA[<class name="User">
+    <cache usage="read-write"/>
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <natural-id>
+        <property name="name"/>
+        <property name="org"/>
+    </natural-id>
+    <property name="password"/>
+</class>]]></programlisting>
+    
+        <para>
+            Note that this functionality is not intended for use with entities with 
+            <emphasis>mutable</emphasis> natural keys.
+        </para>
+        
+        <para>
+            Next, enable the Hibernate query cache.
+        </para>
+        
+        <para>
+            Now, <literal>Restrictions.naturalId()</literal> allows us to make use of
+            the more efficient cache algorithm.
+        </para>
+       
+        <programlisting><![CDATA[session.createCriteria(User.class)
+    .add( Restrictions.naturalId()
+        .set("name", "gavin")
+        .set("org", "hb") 
+    ).setCacheable(true)
+    .uniqueResult();]]></programlisting>
+            
+    </sect1>
+    
+</chapter>


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_criteria.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_hql.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_hql.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_hql.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1162 @@
+858
+
+<chapter id="queryhql">
+    <title>HQL: A linguagem de Queries do Hibernate</title>
+    
+    <para>
+        O Hibernate vem com uma poderosa linguagem que é (intencionalmente) muito parecida 
+        com o SQL. Mas não seja enganado pela sintaxe; a HQL é totalmente orientada à objetos, 
+        requer conhecimentos de herança, polimorfismo e associações.        
+    </para>
+
+    <sect1 id="queryhql-casesensitivity">
+        <title>Case Sensitíve</title>
+
+        <para>
+            As Queries não são case-sensitive, exceto pelo nomes das classes e propriedades Java. 
+            <literal>sELEct</literal> e o mesmo que 
+            <literal>SELECT</literal> mas
+            <literal>org.hibernate.eg.FOO</literal> não é
+            <literal>org.hibernate.eg.Foo</literal> e
+            <literal>foo.barSet</literal> não é
+            <literal>foo.BARSET</literal>.
+           
+        </para>
+        
+        <para>
+            Esse manual usa as palavras chave HQL em letras minúsculas. Alguns usuários acham que 
+            com letras maiúsculas as queries ficam mais legíveis, mas nós achamos essa convenção feia 
+            dentro do código Java.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-from">
+        <title>A clausula from</title>
+
+        <para>
+            A mais simples query possível do Hibernate é a assim:
+        </para>
+        
+        <programlisting><![CDATA[from eg.Cat]]></programlisting>
+        
+        <para>
+            Ela irá retornar todas as instancias da classe <literal>eg.Cat</literal>.
+            Necessariamente não precisamos qualificar o nome da classe, pois é realizado 
+            <literal>auto-import</literal> por padrão. Por isso na maior parte do tempos 
+            nós simplesmente escrevemos:
+        </para>
+        
+        <programlisting><![CDATA[from Cat]]></programlisting>
+        
+        <para>
+            Na maior parte do tempo, você precisará atribuir um <emphasis>alias</emphasis>, 
+            desde que você queira se referia ao <literal>Cat</literal> em outras partes da 
+            query.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+        <para>
+            Essa query atribui um alias a <literal>cat</literal> para as instancias de 
+            <literal>Cat</literal>, então nós podemos usar esse alias depois na query. 
+            A palavra chave as é opcional; poderíamos escrever assim:
+        </para>
+        
+        <programlisting><![CDATA[from Cat cat]]></programlisting>
+        
+        <para>
+            Múltiplas classes pode ser envolvidas, resultando em um produto cartesiano ou "cross" join.
+        </para>
+        
+        <programlisting><![CDATA[from Formula, Parameter]]></programlisting>
+        <programlisting><![CDATA[from Formula as form, Parameter as param]]></programlisting>
+        
+        <para>
+            É considerada uma boa prática os nomes dos aliases começarem com letra minúscula, 
+            aderente com os padrões Java para variáveis locais (ex: <literal>domesticCat</literal>).
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-joins" revision="2">
+        <title>Associações e joins</title>
+
+        <para>
+            Nós também podemos querer atribuir aliases em uma entidade associada, ou mesmo 
+            em elementos de uma coleção de valores, usando um <literal>join</literal>.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    inner join cat.mate as mate
+    left outer join cat.kittens as kitten]]></programlisting>
+
+        <programlisting><![CDATA[from Cat as cat left join cat.mate.kittens as kittens]]></programlisting>
+
+        <programlisting><![CDATA[from Formula form full join form.parameter param]]></programlisting>
+
+        <para>
+            Os tipos de joins suportados foram inspirados no SQL ANSI:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>inner join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>left outer join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>right outer join</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>full join</literal> (geralmente não é útil)
+                </para>
+            </listitem>
+        </itemizedlist>
+    
+        <para>
+            The <literal>inner join</literal>, <literal>left outer join</literal> and 
+            <literal>right outer join</literal> constructs may be abbreviated.
+            As construções <literal>inner join</literal>, <literal>left outer join</literal> e
+            <literal>right outer join</literal> podem ser abreviadas.            
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    join cat.mate as mate
+    left join cat.kittens as kitten]]></programlisting>
+    
+        <para>
+            Você pode fornecer condições extras de join usando a palavra 
+            chave do HQL <literal>with</literal>.
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    left join cat.kittens as kitten 
+        <literal>with</literal> kitten.bodyWeight > 10.0]]></programlisting>
+
+        <para>
+            Adicionalmente, um "fetch" join permite que associações ou coleções de valores 
+            sejam inicializadas junto com o objeto pai, usando apenas um select. Isso é 
+            muito útil no caso das coleções. Isso efetivamente sobre escreve as declarações
+            outer join e lazy do arquivo mapeamento para associações e coleções.
+             Veja a seção <xref linkend="performance-fetching"/> para mais informações.
+        </para>
+    
+        <programlisting><![CDATA[from Cat as cat 
+    inner join <literal>fetch</literal>cat.mate
+    left join <literal>fetch</literal>cat.kittens]]></programlisting>
+    
+        <para>
+            Usualmente, um <literal>fetch</literal>join não precisa atribuir um alias, pois o objeto associado não 
+            deve ser usado na clausula <literal>where</literal> (ou em qualquer outra clausula). 
+            Também, os objetos associados não são retornados diretamente nos resultados da query. 
+            Ao invés disso, eles devem ser acessados usando o objeto pai. A única razão que nós 
+            podemos necessitar de um alias é quando fazemos um fech join recursivamente em uma 
+            coleção adicional:
+        </para>
+        
+        <programlisting><![CDATA[from Cat as cat 
+    inner join <literal>fetch</literal>cat.mate
+    left join <literal>fetch</literal>cat.kittens child
+    left join <literal>fetch</literal>child.kittens]]></programlisting>
+    
+        <para>
+            Observe que a construção <literal>fetch</literal>  não deve ser usada em queries invocadas usando 
+            <literal>iterate()</literal> (embora possa ser usado com <literal>scroll()</literal>). O 
+            <literal>fetch</literal> também não deve ser usado junto com o  <literal>setMaxResults()</literal> ou 
+            <literal>setFirstResult()</literal> pois essas operações são baseadas nas linhas retornadas, que 
+            normalmente contem duplicidade devido ao fetching das coleções, então o número de linhas pode não 
+            ser o que você espera. 
+            
+            O <literal>fetch</literal> não deve ser usado junto com uma condição <literal>with</literal> em 
+            uma condição <literal>with</literal> ad hoc. É possível que seja criado um produto cartesiano pelo 
+            join fetching em mais do que uma coleção em uma query, então tome cuidado nesses casos. Um join 
+            fetching em varias coleções pode trazer resultados inesperados para mapeamentos do tipo bag, tome 
+            cuidado na hora de formular queries como essas. Finalmente, observe o seguinte, o 
+            <literal>full join fetch</literal> e <literal>right join fetch</literal>  não são significativos.
+        </para>
+        
+        <para>
+            
+            Se está usando o nível de propriedade lazy (<literal>com</literal> instrumentação de bytecode), é possível 
+            forçar o Hibernate a  <literal>buscar</literal> as propriedades lazy imediatamente (na primeira query), 
+            usando <literal>fetch all properties </literal>.            
+        </para>
+        
+        <programlisting><![CDATA[from Document <literal>fetch</literal>all properties order by name]]></programlisting>
+        <programlisting><![CDATA[from Document doc <literal>fetch</literal>all properties where lower(doc.name) like '%cats%']]></programlisting>
+
+	    </sect1>
+
+    <sect1 id="queryhql-joins-forms">
+        <title>Formas e sintaxe de joins</title>
+
+	    <para>
+		    O HQL suporta duas formas de associação para união: <literal>implícita</literal> e <literal>explicita</literal>.
+		</para>
+
+	    <para>
+		    As queries apresentadas na seção anterior usam a forma <literal>explicita</literal>, onde a 
+		    palavra chave "join" é explicitamente usada na clausula "from". Essa é a forma recomendada.
+	    </para>
+
+	    <para>
+		    A forma <literal>implícita</literal> não usa a palavra chave "join". Entretanto, as associações 
+		    são diferenciadas usando pontuação ("." - dotnation). Uniões implícitas podem aparecer em
+		    qualquer das clausulas HQL. A união <literal>implícita</literal> resulta em declarações
+		    SQL que contem inner joins. 
+	    </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.mate.name like '%s%']]></programlisting>
+	</sect1>
+
+    <sect1 id="queryhql-select">
+        <title>Clausula select</title>
+
+        <para>
+            A clausula <literal>select</literal> seleciona quais obetos e propriedades retornam
+             no resultado da query. Considere:            
+        </para>
+
+        <programlisting><![CDATA[select mate 
+from Cat as cat 
+    inner join cat.mate as mate]]></programlisting>
+
+        <para>
+            A query selecionará <literal>mate</literal>s (companheiros), de outros <literal>Cat</literal>s. 
+            Atualmente, podemos expressar a query de forma mais compacta como:
+        </para>
+
+        <programlisting><![CDATA[select cat.mate from Cat cat]]></programlisting>
+
+        <para>
+            Queries podem retornar propriedades de qualquer tipo de valor, incluindo propriedades de tipo de componente:
+
+        </para>
+
+        <programlisting><![CDATA[select cat.name from DomesticCat cat
+where cat.name like 'fri%']]></programlisting>
+
+        <programlisting><![CDATA[select cust.name.firstName from Customer as cust]]></programlisting>
+
+        <para>
+            Queries podem retornar múltiplos objetos e/ou propriedades como um array do 
+            tipo Object[],
+        </para>
+
+        <programlisting><![CDATA[select mother, offspr, mate.name 
+from DomesticCat as mother
+    inner join mother.mate as mate
+    left outer join mother.kittens as offspr]]></programlisting>
+    
+        <para>
+            ou como um <literal>List</literal>,
+        </para>
+        
+        <programlisting><![CDATA[select new list(mother, offspr, mate.name)
+from DomesticCat as mother
+    inner join mother.mate as mate
+    left outer join mother.kittens as offspr]]></programlisting>
+    
+        <para>
+            ou como um objeto Java typesafe,
+        </para>
+        
+        <programlisting><![CDATA[select new Family(mother, mate, offspr)
+from DomesticCat as mother
+    join mother.mate as mate
+    left join mother.kittens as offspr]]></programlisting>
+        
+        <para>
+            assumindo que a classe <literal>Family</literal> tenha um construtor apropriado.
+        </para>
+        
+        <para>
+            Pode-se designar referencias a expressões selecionadas, <literal>as</literal>:
+        </para>
+
+        <programlisting><![CDATA[select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
+from Cat cat]]></programlisting>
+
+        <para>
+            Isto é bem mais útil quando usado junto <literal>com</literal> <literal>select new map</literal>:
+        </para>
+            
+        <programlisting><![CDATA[select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
+from Cat cat]]></programlisting>
+
+        <para>
+            Esta query retorna um <literal>Map</literal> de referencias para valores selecionados.
+        </para>
+         
+    </sect1>
+
+    <sect1 id="queryhql-aggregation">
+        <title>Funções de agregação</title>
+
+        <para>
+            As queries HQL podem retornar o resultado de funções agregadas nas propriedades.
+        </para>
+
+        <programlisting><![CDATA[select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
+from Cat cat]]></programlisting>
+
+<!-- NO LONGER SUPPORTED
+        <para>
+            Collections may also appear inside aggregate functions in the <literal>select</literal> 
+            clause.
+        </para>
+
+        <programlisting><![CDATA[select cat, count( elements(cat.kittens) ) 
+from Cat cat group by cat]]></programlisting>
+-->
+
+        <para>
+            As funções agregadas suportadas são:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>avg(...), sum(...), min(...), max(...)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>count(*)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>count(...), count(distinct ...), count(all...)</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+    
+        <para>
+            Pode-se usar operadores aritiméticos, concatenação e funções SQL 
+            reconhecidas na clausula select:
+        </para>
+        
+        <programlisting><![CDATA[select cat.weight + sum(kitten.weight) 
+from Cat cat 
+    join cat.kittens kitten
+group by cat.id, cat.weight]]></programlisting>
+    
+        <programlisting><![CDATA[select firstName||' '||initial||' '||upper(lastName) from Person]]></programlisting>
+    
+        <para>
+            As palavras <literal>distinct</literal> e <literal>all</literal> podem ser usadas e têm 
+            a mesma semântica como no SQL.
+        </para>
+
+        <programlisting><![CDATA[select distinct cat.name from Cat cat
+
+select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="queryhql-polymorphism">
+        <title>Queries polimórficas</title>
+
+        <para>
+            A query:
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+        <para>
+            retorna instancias não só de <literal>Cat</literal>, mas também de subclasses como 
+            <literal>DomesticCat</literal>. As queries do Hibernate podem nomear qualquer classe Java 
+            ou interface na clausula <literal>from</literal>. A query retornará instancias de toda classe 
+            persistente que extenda  a determinada classe ou implemente a determinada interface. A query
+            , a seguir, pode retornar todo objeto persistente:            
+        </para>
+        
+        <programlisting><![CDATA[from java.lang.Object o]]></programlisting>
+        
+        <para>
+            A interface <literal>Named</literal> pode ser implementada por várias classes persistentes:
+        </para>
+        
+        <programlisting><![CDATA[from Named n, Named m where n.name = m.name]]></programlisting>
+        
+        <para>
+            Note que as duas últimas queries requerem mais de um SQL SELECT . Isto significa que a clausula 
+            <literal>order by</literal> não ordena corretamente todo o resultado. (Isso também significa que 
+            você não pode chamar essas queries usando <literal>Query.scroll()</literal>.)            
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-where">
+        <title>A clausula where</title>
+
+        <para>
+            A clausula <literal>where</literal> permite estreitar a lista de instancias retornada. 
+            Se não houver referencia alguma, pode-se referir a propriedades pelo nome:
+        </para>
+
+        <programlisting><![CDATA[from Cat where name='Fritz']]></programlisting>
+        
+        <para>
+        	Se houver uma referência, use o nome da propriedade qualificada:        	
+        </para>
+        
+        <programlisting><![CDATA[from Cat as cat where cat.name='Fritz']]></programlisting>
+
+        <para>
+            retorna instancias de <literal>Cat</literal> com nome ‘Fritz’.
+        </para>
+
+        <programlisting><![CDATA[select foo 
+from Foo foo, Bar bar
+where foo.startDate = bar.date]]></programlisting>
+
+        <para>
+            retornará todas as instancias de <literal>Foo</literal>, para cada 
+            um que tiver uma instancia de <literal>bar</literal> com a propriedade 
+            <literal>date</literal> igual a propriedade 
+            <literal>startDate</literal> de 
+            <literal>Foo</literal>. Expressões de filtro compostas fazem da 
+            clausula <literal>where</literal>, extremamente poderosa. Consideremos:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.mate.name is not null]]></programlisting>
+
+        <para>
+            Esta query traduzida para uma query SQL <literal>com</literal> uma tabela (inner) join. Se fosse 
+            escrever algo como:
+        </para>
+
+        <programlisting><![CDATA[from Foo foo  
+where foo.bar.baz.customer.address.city is not null]]></programlisting>
+
+        <para>
+            Poderia-se terminar <literal>com</literal> uma query que necessitasse de join de quatro tabelas, 
+            no SQL.
+        </para>
+
+        <para>
+            O operador <literal>=</literal> pode ser uasdo para comparar não apenas propriedades, 
+            mas também instancias: 
+        </para>
+
+        <programlisting><![CDATA[from Cat cat, Cat rival where cat.mate = rival.mate]]></programlisting>
+
+        <programlisting><![CDATA[select cat, mate 
+from Cat cat, Cat mate
+where cat.mate = mate]]></programlisting>
+
+        <para>
+            A propriedade especial (lowercase)  <literal>id</literal> pode ser usada para referenciar 
+            o identificador único de um objeto. (Pode-se usar também o nome de sua propriedade)
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.id = 123
+
+from Cat as cat where cat.mate.id = 69]]></programlisting>
+
+        <para>
+            A Segunda query é eficiente. Nenhuma união de tabelas é necessária!
+        </para>
+
+        <para>
+            As propriedades de identificadores compostas também podem ser usadas. Suponha que 
+            <literal>Person</literal>  tenha um identificador composto que consiste de 
+            <literal>country</literal> e <literal>medicareNumber</literal>.
+        </para>
+
+        <programlisting><![CDATA[from bank.Person person
+where person.id.country = 'AU' 
+    and person.id.medicareNumber = 123456]]></programlisting>
+
+        <programlisting><![CDATA[from bank.Account account
+where account.owner.id.country = 'AU' 
+    and account.owner.id.medicareNumber = 123456]]></programlisting>
+
+        <para>
+            Mais uma vez, a Segunda query não precisa de nenhum join de tabela.
+        </para>
+            
+        <para>
+            Assim mesmo, a propriedade especial <literal>class</literal> acessa o valor discriminador da 
+            instancia, no caso de persistência polimórfica. O nome de uma classe Java inclusa em uma 
+            clausula "where", será traduzida para seu valor descriminante. 
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
+        
+        <para>
+            Pode-se também especificar as propriedades dos components ou tipos de usuário composto 
+            (e de componentes de componentes). Nunca tente usar uma expressão de filtro que termine na propriedade 
+            de um tipo de componente (ao contrário de uma propriedade de um componente). Por exemplo, 
+            se store.owner é uma entidade  <literal>com</literal> um componente  <literal>address</literal>.
+        </para>
+
+        <programlisting><![CDATA[store.owner.address.city    // okay
+store.owner.address         // error!]]></programlisting>
+
+        <para>
+            Um tipo "any" tem as propriedades <literal>id</literal> e <literal>class</literal> especiais, 
+            nôs permitindo expressar um join da seguinte forma (onde <literal>AuditLog.item</literal> é 
+            uma propriedade mapeada <literal>com</literal> <literal>&lt;any&gt;</literal>)
+        </para>
+       
+        <programlisting><![CDATA[from AuditLog log, Payment payment 
+where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting>
+    
+        <para>
+            Veja que <literal>log.item.class</literal> e <literal>payment.class</literal> podem 
+            referir-se a valores de colunas de banco de dados completamente diferentes, na query acima.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-expressions">
+        <title>Expressões</title>
+
+        <para>
+            As expressões permitidas na cláusula <literal>where</literal> inclui a maioria 
+            das coisas que você poderia escrever no SQL:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    operadores matemáticos <literal>+, -, *, /</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    operadores de comparação binários <literal>=, &gt;=, &lt;=, &lt;&gt;, !=, like</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    operadores lógicos  <literal>and, or, not</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    parenteses <literal>( )</literal>, indicating grouping
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>in</literal>,
+                    <literal>not in</literal>,
+                    <literal>between</literal>,
+                    <literal>is null</literal>,
+                    <literal>is not null</literal>,
+                    <literal>is empty</literal>,
+                    <literal>is not empty</literal>,
+                    <literal>member of</literal> and 
+                    <literal>not member of</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                	case "simples" , <literal>case ... when ... then ... else ... end</literal>, and
+                    "searched" case, <literal>case when ... then ... else ... end</literal> 
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    concatenação de string <literal>...||...</literal> ou <literal>concat(...,...)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>current_date()</literal>, <literal>current_time()</literal>,
+                    <literal>current_timestamp()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+					<literal>second(...)</literal>, <literal>minute(...)</literal>, 
+					<literal>hour(...)</literal>, <literal>day(...)</literal>, 
+					<literal>month(...)</literal>, <literal>year(...)</literal>,
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    qualquer funcao ou operador definida pela EJB-QL 3.0: <literal>substring(), trim(),
+                    lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>coalesce()</literal> and <literal>nullif()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>str()</literal> para converter valores numericos ou temporais para string
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>cast(... as ...)</literal>, onde o segundo argumento é o nome do tipo 
+                    hibernate, e<literal>extract(... from ...)</literal> se ANSI 
+                    <literal>cast()</literal> e <literal>extract()</literal> é suportado pele
+                    banco de dados usado
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    A função HQL <literal>index()</literal> , que se aplicam a referencias de 
+                    coleçôes associadas e indexadas
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    As funções hql que retornam expressões de coleções de valores:
+                    <literal>size(), minelement(), maxelement(), minindex(), maxindex()</literal>, 
+                    <literal>junto</literal> com o elemento especial, <literal>elements()</literal>,
+                    e funções de <literal>índice</literal> que podem ser quantificadas usando 
+                    <literal>some, all, exists, any, in</literal>.                    
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Qualquer funçâo escalar pelo bando de dados como <literal>sign()</literal>, 
+                    <literal>trunc()</literal>, <literal>rtrim()</literal>, <literal>sin()</literal> 
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Parametros posicionais ao estilo JDBC <literal>?</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Parametros nomeados <literal>:name</literal>, <literal>:start_date</literal>, <literal>:x1</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Literais SQL <literal>'foo'</literal>, <literal>69</literal>, <literal>6.66E+2</literal>,
+                    <literal>'1970-01-01 10:00:01.0'</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Constantes Java <literal>public static final</literal> <literal>ex: Color.TABBY</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>in</literal> e <literal>between</literal> podem ser usadas da seguinte maneira:
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name between 'A' and 'B']]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+        <para>
+            e as formas negativas podem ser escritas
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name not between 'A' and 'B']]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+        <para>
+            Likewise, <literal>is null</literal> and <literal>is not null</literal> may be used to test 
+            for null values.
+            Assim mesmo, , <literal>is null</literal> e <literal>is not null</literal> podem ser usados 
+            para testar valores nulos.
+        </para>
+
+        <para>
+            Booleanos podem ser facilmente usados em expressões, declarando as substituições da HQL query, 
+            na configuração do Hibernate
+        </para>
+
+        <programlisting><![CDATA[<property name="hibernate.query.substitutions">true 1, false 0</property>]]></programlisting>
+
+        <para>
+            Isso irá substituir as palavras chave <literal>true</literal> e <literal>false</literal>
+            <literal>pelos</literal> literais <literal>1</literal> e <literal>0</literal> na tradução do HQL para SQL.
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.alive = true]]></programlisting>
+
+        <para>
+            Pode-se testar o tamanho de uma coleção <literal>com</literal> a propriedade especial  <literal>size</literal>, 
+            ou a função especial <literal>size()</literal>.
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.kittens.size > 0]]></programlisting>
+
+        <programlisting><![CDATA[from Cat cat where size(cat.kittens) > 0]]></programlisting>
+
+        <para>
+            Para coleções indexadas, você pode se referir aos índices máximo e mínimo, usando 
+            as funções <literal>minindex</literal> e <literal>maxindex</literal>. Similarmente, 
+            pode-se referir aos elementos máximo e mínimo de uma coleção de tipos básicos usando
+            as funções <literal>minelement</literal> e <literal>maxelement</literal>.
+        </para>
+        
+        <programlisting><![CDATA[from Calendar cal where maxelement(cal.holidays) > current_date]]></programlisting>
+        
+        <programlisting><![CDATA[from Order order where maxindex(order.items) > 100]]></programlisting>
+
+        <programlisting><![CDATA[from Order order where minelement(order.items) > 10000]]></programlisting>
+        
+        <para>
+            As funções SQL  <literal>any, some, all, exists, in</literal> são suportadas quando passado o 
+            elemento ou o conjunto de índices de uma coleção (<literal>elements</literal> e 
+            <literal>indices</literal> de funções), ou o resultado de uma subquery (veja abaixo).
+        </para>
+
+        <programlisting><![CDATA[select mother from Cat as mother, Cat as kit
+where kit in elements(foo.kittens)]]></programlisting>
+
+        <programlisting><![CDATA[select p from NameList list, Person p
+where p.name = some elements(list.names)]]></programlisting>
+
+        <programlisting><![CDATA[from Cat cat where exists elements(cat.kittens)]]></programlisting>
+
+        <programlisting><![CDATA[from Player p where 3 > all elements(p.scores)]]></programlisting>
+
+        <programlisting><![CDATA[from Show show where 'fizard' in indices(show.acts)]]></programlisting>
+
+        <para>
+            Note que essas construções - <literal>size</literal>, <literal>elements</literal>,
+            <literal>indices</literal>, <literal>minindex</literal>, <literal>maxindex</literal>,
+            <literal>minelement</literal>, <literal>maxelement</literal>– 
+            só podem ser usados na clausula where do Hibernate3.
+        </para>
+        
+        <para>
+            Elementos de coleções com índice (arrays, lists, maps), podem ser referenciadas 
+            pelo índice (apenas na clausula where):
+        </para>
+        
+        <programlisting><![CDATA[from Order order where order.items[0].id = 1234]]></programlisting>
+
+        <programlisting><![CDATA[select person from Person person, Calendar calendar
+where calendar.holidays['national day'] = person.birthDay
+    and person.nationality.calendar = calendar]]></programlisting>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11]]></programlisting>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ maxindex(order.items) ] = item and order.id = 11]]></programlisting>
+
+        <para>
+            A expressão entre colchetes <literal>[]</literal>, pode ser até uma expressão aritimética.
+        </para>
+        
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ size(order.items) - 1 ] = item]]></programlisting>
+        
+        <para>
+            O HQL também provê a função interna <literal>index()</literal>, para elementos de 
+            associação um-pra-muitos ou coleção de valores.
+        </para>
+
+        <programlisting><![CDATA[select item, index(item) from Order order 
+    join order.items item
+where index(item) < 5]]></programlisting>
+
+        <para>
+            Funções escalares SQL, suportadas pelo banco de dados subjacente.
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like 'FRI%']]></programlisting>
+
+        <para>
+            Se ainda ainda não está totalmente convencido, pense o quão maior e menos legível poderia 
+            ser a query a seguir, em SQL:
+        </para>
+
+        <programlisting><![CDATA[select cust
+from Product prod,
+    Store store
+    inner join store.customers cust
+where prod.name = 'widget'
+    and store.location.name in ( 'Melbourne', 'Sydney' )
+    and prod = all elements(cust.currentOrder.lineItems)]]></programlisting>
+
+        <para>
+            <emphasis>Hint:</emphasis> something like
+        </para>
+
+        <programlisting><![CDATA[SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
+FROM customers cust,
+    stores store,
+    locations loc,
+    store_customers sc,
+    product prod
+WHERE prod.name = 'widget'
+    AND store.loc_id = loc.id
+    AND loc.name IN ( 'Melbourne', 'Sydney' )
+    AND sc.store_id = store.id
+    AND sc.cust_id = cust.id
+    AND prod.id = ALL(
+        SELECT item.prod_id
+        FROM line_items item, orders o
+        WHERE item.order_id = o.id
+            AND cust.current_order = o.id
+    )]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-ordering">
+        <title>A clausula order by</title>
+
+        <para>
+            A lista retornada pela query pode ser ordenada por qualquer propriedade da classe ou componente retornado:
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat
+order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
+
+        <para>
+            As opções <literal>asc</literal> ou <literal>desc</literal> indicam ordem crescente ou decrescente, 
+            respectivamente.  
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-grouping">
+        <title>A clausula group by</title>
+
+        <para>
+            Uma query que retorne valores agregados, podem ser agrupados por qualquer propriedade de uma classe 
+            ou componente retornado:
+        </para>
+
+        <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat) 
+from Cat cat
+group by cat.color]]></programlisting>
+
+        <programlisting><![CDATA[select foo.id, avg(name), max(name) 
+from Foo foo join foo.names name
+group by foo.id]]></programlisting>
+
+        <para>
+            Uma clausula <literal>having</literal> também é permitida.
+        </para>
+
+        <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat) 
+from Cat cat
+group by cat.color 
+having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
+
+        <para>
+            Funções SQL e funções agregadas são permitidas nas clausulas 
+            <literal>having</literal> e <literal>order by</literal>, se suportadas pelo banco 
+            de dados subjacente (ex: não no MySQL).            
+        </para>
+
+        <programlisting><![CDATA[select cat
+from Cat cat
+    join cat.kittens kitten
+group by cat
+having avg(kitten.weight) > 100
+order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
+
+        <para>
+            Note que, nem a clausula <literal>group by</literal> ou 
+            <literal>order by</literal>, podem conter expressões aritiméticas.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="queryhql-subqueries" revision="2">
+        <title>Subqueries</title>
+        
+        <para>
+            Para bancos de dados que suportem subselects, o Hibernate suporta subqueries dentro de queries. 
+            Uma subquery precisa estar entre parênteses (normalmente uma chamada de função agregada SQL). 
+            Mesmo subqueries co-relacionadas (subqueries que fazem referência à alias de outras queries), 
+            são aceitas.
+        </para>
+
+        <programlisting><![CDATA[from Cat as fatcat 
+where fatcat.weight > ( 
+    select avg(cat.weight) from DomesticCat cat 
+)]]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat as cat 
+where cat.name = some ( 
+    select name.nickName from Name as name 
+)]]></programlisting>
+    
+        <programlisting><![CDATA[from Cat as cat 
+where not exists ( 
+    from Cat as mate where mate.mate = cat 
+)]]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat as cat 
+where cat.name not in ( 
+    select name.nickName from Name as name 
+)]]></programlisting>
+
+        <programlisting><![CDATA[select cat.id, (select max(kit.weight) from cat.kitten kit) 
+from Cat as cat]]></programlisting>
+
+        <para>
+            Note que HQL subqueries podem aparecer apenas dentro de clausulas select ou where.
+        </para>
+
+        <para>
+            Para subqueries <literal>com</literal> mais de uma expressão na lista do select, pode-se usar um construtor 
+            de tuplas:
+        </para>
+        
+        <programlisting><![CDATA[from Cat as cat 
+where not ( cat.name, cat.color ) in ( 
+    select cat.name, cat.color from DomesticCat cat 
+)]]></programlisting>
+
+        <para>
+            Veja que em alguns bancos de dados (mas não o Oracle ou HSQL), pode-se  usar construtores 
+            de tuplas em outros contextos. Por exemplo quando buscando componentes ou tipos de usuário composto.
+        </para>
+
+        <programlisting><![CDATA[from Person where name = ('Gavin', 'A', 'King')]]></programlisting>
+        
+        <para>
+            Qual é equivalente ao mais verbalizado:
+        </para>
+        
+        <programlisting><![CDATA[from Person where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')]]></programlisting>
+
+        <para>
+            Há duas razões boas que você pode não querer fazer este tipo de coisa: primeira, não 
+            é completamente portável entre plataformas de banco de dados; segunda, a query agora é 
+            dependente da ordem de propriedades no documento de mapeamento.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-examples">
+        <title>Exemplos de HQL</title>
+        
+        <para>
+            As queries do Hibernate, podem ser muito poderosas e complexas. De fato, o poder da linguagem de 
+            querie é um dos pontos principais na distribuição do Hibernate. Aqui temos algumas queries de exemplo, 
+            muito similares a queries que usei em um projeto recente. Note que a maioria das queries que você 
+            irá escrever, são mais simples que estas.
+        </para>
+        
+        <para>
+            A query a seguir retorna o id de order, numero de itens e o valor total do order para todos os 
+            orders não pagos para um freguês particular e valor total mínimo dado, ordenando os resultados por 
+            valor total. Ao determinar os preços, é usado o catalogo corrente. A query SQL resultante, 
+            usando tabelas  <literal>ORDER</literal>, <literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>,
+            <literal>CATALOG</literal> e <literal>PRICE</literal>, tem quatro inner joins e um 
+            (não correlacionado) subselect.
+        </para>
+        
+        <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+    join order.lineItems as item
+    join item.product as product,
+    Catalog as catalog
+    join catalog.prices as price
+where order.paid = false
+    and order.customer = :customer
+    and price.product = product
+    and catalog.effectiveDate < sysdate
+    and catalog.effectiveDate >= all (
+        select cat.effectiveDate 
+        from Catalog as cat
+        where cat.effectiveDate < sysdate
+    )
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+        
+        <para>
+            Que monstro! Atualmente, na vida real, eu não sou muito afeiçoado a subqueries, então 
+            minha query seria mais parecida com isto:
+        </para>
+        
+        <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+    join order.lineItems as item
+    join item.product as product,
+    Catalog as catalog
+    join catalog.prices as price
+where order.paid = false
+    and order.customer = :customer
+    and price.product = product
+    and catalog = :currentCatalog
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+        
+        <para>
+            A próxima query conta o número de pagamentos em cada status, tirando todos os pagamentos com 
+            status <literal>AWAITING_APPROVAL</literal>, onde a mais recente mudança de status foi feita 
+            pelo usuário corrente. Traduz-se para uma query SQL <literal>com</literal> dois inner joins e 
+            um subselect correlacionado, nas tabelas <literal>PAYMENT</literal>, 
+            <literal>PAYMENT_STATUS</literal> e <literal>PAYMENT_STATUS_CHANGE</literal> .
+        </para>
+
+        <programlisting><![CDATA[select count(payment), status.name 
+from Payment as payment 
+    join payment.currentStatus as status
+    join payment.statusChanges as statusChange
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+    or (
+        statusChange.timeStamp = ( 
+            select max(change.timeStamp) 
+            from PaymentStatusChange change 
+            where change.payment = payment
+        )
+        and statusChange.user <> :currentUser
+    )
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+        <para>
+            Se eu tivesse mapeado a Collection <literal>statusChanges</literal> como um List, ao invés de um 
+            Set, a query teria sido muito mais simples de escrever.
+        </para>
+    
+        <programlisting><![CDATA[select count(payment), status.name 
+from Payment as payment
+    join payment.currentStatus as status
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+    or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+        <para>
+            A próxima query usa a função <literal>isNull()</literal> do MS SQL Server, para retornar 
+            todas as contas e pagamentos não pagos para a organização, para cada usuário corrente 
+            pertencente. Traduz-se para uma query SQL <literal>com</literal> três inner joins, 
+            um outer join e um subselect nas tabelas <literal>ACCOUNT</literal>, <literal>PAYMENT</literal>, 
+            <literal>PAYMENT_STATUS</literal>,<literal>ACCOUNT_TYPE</literal>, 
+            <literal>ORGANIZATION</literal> e <literal>ORG_USER</literal> .
+        </para>
+
+        <programlisting><![CDATA[select account, payment
+from Account as account
+    left outer join account.payments as payment
+where :currentUser in elements(account.holder.users)
+    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+        <para>
+            Para alguns bancos de dados, precisaremos eleminar o subselect (correlacionado).
+        </para>
+
+        <programlisting><![CDATA[select account, payment
+from Account as account
+    join account.holder.users as user
+    left outer join account.payments as payment
+where :currentUser = user
+    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+   </sect1>
+
+    <sect1 id="queryhql-bulk" revision="2">
+        <title>update e delete em lote</title>
+
+        <para>
+            Agora o HQL suporta declarações, <literal>update</literal>, 
+            <literal>delete</literal> e <literal>insert ... select ...</literal> 
+            Veja <xref linkend="batch-direct"/>, para mais detalhes.
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-tipstricks">
+        <title>Dicas e Truques</title>
+
+        <para>
+            Pode-se contar o número de resultados da query, sem realmente retorna-los.
+        </para>
+
+        <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue()]]></programlisting>
+
+        <para>
+            Para ordenar um resultado pelo tamanho de uma Collection, use a query a seguir.
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User as usr 
+    left join usr.messages as msg
+group by usr.id, usr.name
+order by count(msg)]]></programlisting>
+
+        <para>
+            Se seu banco de dados suporta subselects, pode-se colocar uma condição sobre 
+            tamanho de seleção na cláusula where da sua query:
+        </para>
+
+        <programlisting><![CDATA[from User usr where size(usr.messages) >= 1]]></programlisting>
+
+        <para>
+            Se seu banco de dados não suporta subselects, use a query a seguir:
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User usr.name
+    join usr.messages msg
+group by usr.id, usr.name
+having count(msg) >= 1]]></programlisting>
+
+        <para>
+            Com essa solução não se pode retornar um <literal>User</literal> <literal>com</literal> sem
+            nenhuma menssagem, por causa do "inner join", a forma a seguir também é útil. 
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+    left join usr.messages as msg
+group by usr.id, usr.name
+having count(msg) = 0]]></programlisting>
+
+        <para>
+            As propriedades de um JavaBean podem ser limitadas à parâmetros nomeados da query:
+        </para>
+
+        <programlisting><![CDATA[Query q = s.createQuery("from foo Foo as foo where foo.name=:name and foo.size=:size");
+q.setProperties(fooBean); // fooBean has getName() and getSize()
+List foos = q.list();]]></programlisting>
+
+        <para>
+            As Collections são paginaveis, usando a interface <literal>Query</literal> <literal>com</literal> um filtro:
+        </para>
+
+        <programlisting><![CDATA[Query q = s.createFilter( collection, "" ); // the trivial filter
+q.setMaxResults(PAGE_SIZE);
+q.setFirstResult(PAGE_SIZE * pageNumber);
+List page = q.list();]]></programlisting>
+
+        <para>
+            Os elementos da Collection podem ser ordenados ou agrupados 
+            usando um filtro de query:
+        </para>
+        
+        <programlisting><![CDATA[Collection orderedCollection = s.filter( collection, "order by this.amount" );
+Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );]]></programlisting>
+
+        <para>
+            Pode-se achar o tamanho de uma Collection sem inicializa-la:
+        </para>
+
+        <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue();]]></programlisting>
+
+    </sect1>
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_hql.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_sql.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_sql.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_sql.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,783 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<chapter id="querysql" revision="2">
+  <title>Native SQL</title>
+
+  <para>You may also express queries in the native SQL dialect of your
+  database. This is useful if you want to utilize database specific features
+  such as query hints or the <literal>CONNECT</literal> keyword in Oracle. It
+  also provides a clean migration path from a direct SQL/JDBC based
+  application to Hibernate.</para>
+
+  <para>Hibernate3 allows you to specify handwritten SQL (including stored
+  procedures) for all create, update, delete, and load operations.</para>
+
+  <sect1 id="querysql-creating" revision="4">
+    <title>Using a <literal>SQLQuery</literal></title>
+
+    <para>Execution of native SQL queries is controlled via the
+    <literal>SQLQuery</literal> interface, which is obtained by calling
+    <literal>Session.createSQLQuery()</literal>. The following describes how
+    to use this API for querying.</para>
+
+    <sect2>
+      <title>Scalar queries</title>
+
+      <para>The most basic SQL query is to get a list of scalars
+      (values).</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").list();
+sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
+]]></programlisting>
+
+      <para>These will both return a List of Object arrays (Object[]) with
+      scalar values for each column in the CATS table. Hibernate will use
+      ResultSetMetadata to deduce the actual order and types of the returned
+      scalar values.</para>
+
+      <para>To avoid the overhead of using
+      <literal>ResultSetMetadata</literal> or simply to be more explicit in
+      what is returned one can use <literal>addScalar()</literal>.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME", Hibernate.STRING)
+ .addScalar("BIRTHDATE", Hibernate.DATE)
+]]></programlisting>
+
+      <para>This query specified:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>the SQL query string</para>
+        </listitem>
+
+        <listitem>
+          <para>the columns and types to return</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>This will still return Object arrays, but now it will not use
+      <literal>ResultSetMetdata</literal> but will instead explicitly get the
+      ID, NAME and BIRTHDATE column as respectively a Long, String and a Short
+      from the underlying resultset. This also means that only these three
+      columns will be returned, even though the query is using
+      <literal>*</literal> and could return more than the three listed
+      columns.</para>
+
+      <para>It is possible to leave out the type information for all or some
+      of the scalars.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME")
+ .addScalar("BIRTHDATE")
+]]></programlisting>
+
+      <para>This is essentially the same query as before, but now
+      <literal>ResultSetMetaData</literal> is used to decide the type of NAME
+      and BIRTHDATE where as the type of ID is explicitly specified.</para>
+
+      <para>How the java.sql.Types returned from ResultSetMetaData is mapped
+      to Hibernate types is controlled by the Dialect. If a specific type is
+      not mapped or does not result in the expected type it is possible to
+      customize it via calls to <literal>registerHibernateType</literal> in
+      the Dialect.</para>
+    </sect2>
+
+    <sect2>
+      <title>Entity queries</title>
+
+      <para>The above queries were all about returning scalar values,
+      basically returning the "raw" values from the resultset. The following
+      shows how to get entity objects from a native sql query via
+      <literal>addEntity()</literal>.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class);
+sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);
+]]></programlisting>
+
+      <para>This query specified:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>the SQL query string</para>
+        </listitem>
+
+        <listitem>
+          <para>the entity returned by the query</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>Assuming that Cat is mapped as a class with the columns ID, NAME
+      and BIRTHDATE the above queries will both return a List where each
+      element is a Cat entity.</para>
+
+      <para>If the entity is mapped with a <literal>many-to-one</literal> to
+      another entity it is required to also return this when performing the
+      native query, otherwise a database specific "column not found" error
+      will occur. The additional columns will automatically be returned when
+      using the * notation, but we prefer to be explicit as in the following
+      example for a <literal>many-to-one</literal> to a
+      <literal>Dog</literal>:</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);
+]]></programlisting>
+
+      <para>This will allow cat.getDog() to function properly.</para>
+    </sect2>
+
+    <sect2>
+      <title>Handling associations and collections</title>
+
+      <para>It is possible to eagerly join in the <literal>Dog</literal> to
+      avoid the possible extra roundtrip for initializing the proxy. This is
+      done via the <literal>addJoin()</literal> method, which allows you to
+      join in an association or collection.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dog");
+]]></programlisting>
+
+      <para>In this example the returned <literal>Cat</literal>'s will have
+      their <literal>dog</literal> property fully initialized without any
+      extra roundtrip to the database. Notice that we added a alias name
+      ("cat") to be able to specify the target property path of the join. It
+      is possible to do the same eager joining for collections, e.g. if the
+      <literal>Cat</literal> had a one-to-many to <literal>Dog</literal>
+      instead.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dogs");
+]]></programlisting>
+
+      <p>At this stage we are reaching the limits of what is possible with
+      native queries without starting to enhance the sql queries to make them
+      usable in Hibernate; the problems starts to arise when returning
+      multiple entities of the same type or when the default alias/column
+      names are not enough.</p>
+    </sect2>
+
+    <sect2>
+      <title>Returning multiple entities</title>
+
+      <para>Until now the result set column names are assumed to be the same
+      as the column names specified in the mapping document. This can be
+      problematic for SQL queries which join multiple tables, since the same
+      column names may appear in more than one table.</para>
+
+      <para>Column alias injection is needed in the following query (which
+      most likely will fail):</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT c.*, m.*  FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+]]></programlisting>
+
+      <para>The intention for this query is to return two Cat instances per
+      row, a cat and its mother. This will fail since there is a conflict of
+      names since they are mapped to the same column names and on some
+      databases the returned column aliases will most likely be on the form
+      "c.ID", "c.NAME", etc. which are not equal to the columns specificed in
+      the mappings ("ID" and "NAME").</para>
+
+      <para>The following form is not vulnerable to column name
+      duplication:</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT {cat.*}, {mother.*}  FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+]]></programlisting>
+
+      <para>This query specified:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>the SQL query string, with placeholders for Hibernate to
+          inject column aliases</para>
+        </listitem>
+
+        <listitem>
+          <para>the entities returned by the query</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>The {cat.*} and {mother.*} notation used above is a shorthand for
+      "all properties". Alternatively, you may list the columns explicity, but
+      even in this case we let Hibernate inject the SQL column aliases for
+      each property. The placeholder for a column alias is just the property
+      name qualified by the table alias. In the following example, we retrieve
+      Cats and their mothers from a different table (cat_log) to the one
+      declared in the mapping metadata. Notice that we may even use the
+      property aliases in the where clause if we like.</para>
+
+      <programlisting><![CDATA[String sql = "SELECT ID as {c.id}, NAME as {c.name}, " + 
+         "BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
+         "FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
+
+List loggedCats = sess.createSQLQuery(sql)
+        .addEntity("cat", Cat.class)
+        .addEntity("mother", Cat.class).list()
+]]></programlisting>
+
+      <sect3 id="querysql-aliasreferences" revision="2">
+        <title>Alias and property references</title>
+
+        <para>For most cases the above alias injection is needed, but for
+        queries relating to more complex mappings like composite properties,
+        inheritance discriminators, collections etc. there are some specific
+        aliases to use to allow Hibernate to inject the proper aliases.</para>
+
+        <para>The following table shows the different possibilities of using
+        the alias injection. Note: the alias names in the result are examples,
+        each alias will have a unique and probably different name when
+        used.</para>
+
+        <table frame="topbot" id="aliasinjection-summary">
+          <title>Alias injection names</title>
+
+          <tgroup cols="3">
+            <colspec colwidth="1*" />
+
+            <colspec colwidth="1*" />
+
+            <colspec colwidth="2.5*" />
+
+            <thead>
+              <row>
+                <entry>Description</entry>
+
+                <entry>Syntax</entry>
+
+                <entry>Example</entry>
+              </row>
+            </thead>
+
+            <tbody>
+              <row>
+                <entry>A simple property</entry>
+
+                <entry><literal>{[aliasname].[propertyname]</literal></entry>
+
+                <entry><literal>A_NAME as {item.name}</literal></entry>
+              </row>
+
+              <row>
+                <entry>A composite property</entry>
+
+                <entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
+
+                <entry><literal>CURRENCY as {item.amount.currency}, VALUE as
+                {item.amount.value}</literal></entry>
+              </row>
+
+              <row>
+                <entry>Discriminator of an entity</entry>
+
+                <entry><literal>{[aliasname].class}</literal></entry>
+
+                <entry><literal>DISC as {item.class}</literal></entry>
+              </row>
+
+              <row>
+                <entry>All properties of an entity</entry>
+
+                <entry><literal>{[aliasname].*}</literal></entry>
+
+                <entry><literal>{item.*}</literal></entry>
+              </row>
+
+              <row>
+                <entry>A collection key</entry>
+
+                <entry><literal>{[aliasname].key}</literal></entry>
+
+                <entry><literal>ORGID as {coll.key}</literal></entry>
+              </row>
+
+              <row>
+                <entry>The id of an collection</entry>
+
+                <entry><literal>{[aliasname].id}</literal></entry>
+
+                <entry><literal>EMPID as {coll.id}</literal></entry>
+              </row>
+
+              <row>
+                <entry>The element of an collection</entry>
+
+                <entry><literal>{[aliasname].element}</literal></entry>
+
+                <entry><literal>XID as {coll.element}</literal></entry>
+              </row>
+
+              <row>
+                <entry>roperty of the element in the collection</entry>
+
+                <entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
+
+                <entry><literal>NAME as {coll.element.name}</literal></entry>
+              </row>
+
+              <row>
+                <entry>All properties of the element in the collection</entry>
+
+                <entry><literal>{[aliasname].element.*}</literal></entry>
+
+                <entry><literal>{coll.element.*}</literal></entry>
+              </row>
+
+              <row>
+                <entry>All properties of the the collection</entry>
+
+                <entry><literal>{[aliasname].*}</literal></entry>
+
+                <entry><literal>{coll.*}</literal></entry>
+              </row>
+            </tbody>
+          </tgroup>
+        </table>
+      </sect3>
+    </sect2>
+
+    <sect2>
+      <title>Returning non-managed entities</title>
+
+      <para>It is possible to apply a ResultTransformer to native sql queries. Allowing it to e.g. return non-managed entities.</para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS")
+        .setResultTransformer(Transformers.aliasToBean(CatDTO.class))]]></programlisting>
+        
+              <para>This query specified:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>the SQL query string</para>
+        </listitem>
+
+        <listitem>
+          <para>a result transformer</para>
+        </listitem>
+      </itemizedlist>
+        
+        <para>
+        The above query will return a list of <literal>CatDTO</literal> which has been instantiated and injected the values of NAME and BIRTHNAME into its corresponding
+        properties or fields.
+        </para>
+    </sect2>
+
+    <sect2>
+      <title>Handling inheritance</title>
+
+      <para>Native sql queries which query for entities that is mapped as part
+      of an inheritance must include all properties for the baseclass and all
+      it subclasses.</para>
+    </sect2>
+
+    <sect2>
+      <title>Parameters</title>
+
+      <para>Native sql queries support positional as well as named
+      parameters:</para>
+
+      <programlisting><![CDATA[Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class);
+List pusList = query.setString(0, "Pus%").list();
+     
+query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like :name").addEntity(Cat.class);
+List pusList = query.setString("name", "Pus%").list();          ]]></programlisting>
+    </sect2>
+    
+    
+        
+  </sect1>
+
+  <sect1 id="querysql-namedqueries" revision="3">
+    <title>Named SQL queries</title>
+
+    <para>Named SQL queries may be defined in the mapping document and called
+    in exactly the same way as a named HQL query. In this case, we do
+    <emphasis>not</emphasis> need to call
+    <literal>addEntity()</literal>.</para>
+
+    <programlisting><![CDATA[<sql-query name="persons">
+    <return alias="person" class="eg.Person"/>
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex}
+    FROM PERSON person
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+    <programlisting><![CDATA[List people = sess.getNamedQuery("persons")
+    .setString("namePattern", namePattern)
+    .setMaxResults(50)
+    .list();]]></programlisting>
+
+    <para>The <literal>&lt;return-join&gt;</literal> and
+    <literal>&lt;load-collection&gt;</literal> elements are used to join
+    associations and define queries which initialize collections,
+    respectively.</para>
+
+    <programlisting><![CDATA[<sql-query name="personsWith">
+    <return alias="person" class="eg.Person"/>
+    <return-join alias="address" property="person.mailingAddress"/>
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex},
+           adddress.STREET AS {address.street},
+           adddress.CITY AS {address.city},
+           adddress.STATE AS {address.state},
+           adddress.ZIP AS {address.zip}
+    FROM PERSON person
+    JOIN ADDRESS adddress
+        ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+    <para>A named SQL query may return a scalar value. You must declare the
+    column alias and Hibernate type using the
+    <literal>&lt;return-scalar&gt;</literal> element:</para>
+
+    <programlisting><![CDATA[<sql-query name="mySqlQuery">
+    <return-scalar column="name" type="string"/>
+    <return-scalar column="age" type="long"/>
+    SELECT p.NAME AS name,
+           p.AGE AS age,
+    FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
+</sql-query>]]></programlisting>
+
+    <para>You can externalize the resultset mapping informations in a
+    <literal>&lt;resultset&gt;</literal> element to either reuse them accross
+    several named queries or through the
+    <literal>setResultSetMapping()</literal> API.</para>
+
+    <programlisting><![CDATA[<resultset name="personAddress">
+    <return alias="person" class="eg.Person"/>
+    <return-join alias="address" property="person.mailingAddress"/>
+</resultset>
+
+<sql-query name="personsWith" resultset-ref="personAddress">
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex},
+           adddress.STREET AS {address.street},
+           adddress.CITY AS {address.city},
+           adddress.STATE AS {address.state},
+           adddress.ZIP AS {address.zip}
+    FROM PERSON person
+    JOIN ADDRESS adddress
+        ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+    <para>You can alternatively use the resultset mapping information in your
+    hbm files directly in java code.</para>
+
+    <programlisting><![CDATA[List cats = sess.createSQLQuery(
+        "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
+    )
+    .setResultSetMapping("catAndKitten")
+    .list();]]></programlisting>
+
+    <sect2 id="propertyresults">
+      <title>Using return-property to explicitly specify column/alias
+      names</title>
+
+      <para>With <literal>&lt;return-property&gt;</literal> you can explicitly
+      tell Hibernate what column aliases to use, instead of using the
+      <literal>{}</literal>-syntax to let Hibernate inject its own
+      aliases.</para>
+
+      <programlisting><![CDATA[<sql-query name="mySqlQuery">
+    <return alias="person" class="eg.Person">
+        <return-property name="name" column="myName"/>
+        <return-property name="age" column="myAge"/>
+        <return-property name="sex" column="mySex"/>
+    </return>
+    SELECT person.NAME AS myName,
+           person.AGE AS myAge,
+           person.SEX AS mySex,
+    FROM PERSON person WHERE person.NAME LIKE :name
+</sql-query>
+]]></programlisting>
+
+      <para><literal>&lt;return-property&gt;</literal> also works with
+      multiple columns. This solves a limitation with the
+      <literal>{}</literal>-syntax which can not allow fine grained control of
+      multi-column properties.</para>
+
+      <programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
+    <return alias="emp" class="Employment">
+        <return-property name="salary">
+            <return-column name="VALUE"/>
+            <return-column name="CURRENCY"/>
+        </return-property>
+        <return-property name="endDate" column="myEndDate"/>
+    </return>
+        SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
+        STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+        REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
+        FROM EMPLOYMENT
+        WHERE EMPLOYER = :id AND ENDDATE IS NULL
+        ORDER BY STARTDATE ASC
+</sql-query>]]></programlisting>
+
+      <para>Notice that in this example we used
+      <literal>&lt;return-property&gt;</literal> in combination with the
+      <literal>{}</literal>-syntax for injection. Allowing users to choose how
+      they want to refer column and properties.</para>
+
+      <para>If your mapping has a discriminator you must use
+      <literal>&lt;return-discriminator&gt;</literal> to specify the
+      discriminator column.</para>
+    </sect2>
+
+    <sect2 id="sp_query" revision="1">
+      <title>Using stored procedures for querying</title>
+
+      <para>Hibernate 3 introduces support for queries via stored procedures
+      and functions. Most of the following documentation is equivalent for
+      both. The stored procedure/function must return a resultset as the first
+      out-parameter to be able to work with Hibernate. An example of such a
+      stored function in Oracle 9 and higher is as follows:</para>
+
+      <programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
+    RETURN SYS_REFCURSOR
+AS
+    st_cursor SYS_REFCURSOR;
+BEGIN
+    OPEN st_cursor FOR
+ SELECT EMPLOYEE, EMPLOYER,
+ STARTDATE, ENDDATE,
+ REGIONCODE, EID, VALUE, CURRENCY
+ FROM EMPLOYMENT;
+      RETURN  st_cursor;
+ END;]]></programlisting>
+
+      <para>To use this query in Hibernate you need to map it via a named
+      query.</para>
+
+      <programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
+    <return alias="emp" class="Employment">
+        <return-property name="employee" column="EMPLOYEE"/>
+        <return-property name="employer" column="EMPLOYER"/>
+        <return-property name="startDate" column="STARTDATE"/>
+        <return-property name="endDate" column="ENDDATE"/>
+        <return-property name="regionCode" column="REGIONCODE"/>
+        <return-property name="id" column="EID"/>
+        <return-property name="salary">
+            <return-column name="VALUE"/>
+            <return-column name="CURRENCY"/>
+        </return-property>
+    </return>
+    { ? = call selectAllEmployments() }
+</sql-query>]]></programlisting>
+
+      <para>Notice stored procedures currently only return scalars and
+      entities. <literal>&lt;return-join&gt;</literal> and
+      <literal>&lt;load-collection&gt;</literal> are not supported.</para>
+
+      <sect3 id="querysql-limits-storedprocedures" revision="1">
+        <title>Rules/limitations for using stored procedures</title>
+
+        <para>To use stored procedures with Hibernate the procedures/functions
+        have to follow some rules. If they do not follow those rules they are
+        not usable with Hibernate. If you still want to use these procedures
+        you have to execute them via <literal>session.connection()</literal>.
+        The rules are different for each database, since database vendors have
+        different stored procedure semantics/syntax.</para>
+
+        <para>Stored procedure queries can't be paged with
+        <literal>setFirstResult()/setMaxResults()</literal>.</para>
+
+        <para>Recommended call form is standard SQL92: <literal>{ ? = call
+        functionName(&lt;parameters&gt;) }</literal> or <literal>{ ? = call
+        procedureName(&lt;parameters&gt;}</literal>. Native call syntax is not
+        supported.</para>
+
+        <para>For Oracle the following rules apply:</para>
+
+        <itemizedlist spacing="compact">
+          <listitem>
+            <para>            
+            A funçãp deve retornar um result set. O primeiro parâmetro da procedure 
+            dever ser uma <literal>SAÍDA</literal> que retorne um result set. Isto é feito 
+            usando o tipo a <literal>SYS_REFCURSOR</literal> no Oracle 9 ou 10.  No Oracle é 
+            necessário  definir o tipo <literal>REF CURSOR</literal>, veja a documentação do Oracle.
+            </para>
+          </listitem>
+        </itemizedlist>
+
+        <para>For Sybase or MS SQL server the following rules apply:</para>
+
+        <itemizedlist spacing="compact">
+          <listitem>
+            <para>
+            	A procedure deve retornar um result set. Veja que este servidor pode retornar 
+            	múltiplos result sets e update counts. O Hibernate ira iterar os resultados e 
+            	pegar o primeiro resultado que é o valor de retorno do result set. 
+            	O resto será descartado.
+            </para>
+          </listitem>
+
+          <listitem>
+            <para>
+            Se você habilitar <literal>SET NOCOUNT ON</literal>  na sua procedure, ela 
+            provavelmente será mais eficiente. Mas, isto não é obrigatório</para>
+          </listitem>
+        </itemizedlist>
+      </sect3>
+    </sect2>
+  </sect1>
+
+  <sect1 id="querysql-cud">
+    <title>SQL customizado para create, update e delete</title>
+
+    <para>Hibernate3 can use custom SQL statements for create, update, and
+    delete operations. The class and collection persisters in Hibernate
+    already contain a set of configuration time generated strings (insertsql,
+    deletesql, updatesql etc.). The mapping tags
+    <literal>&lt;sql-insert&gt;</literal>,
+    <literal>&lt;sql-delete&gt;</literal>, and
+    <literal>&lt;sql-update&gt;</literal> override these strings:
+  
+    	Hibernate3 pode usar SQL customizado para operações de create, update e delete. 
+    	A persistência de classe e collection no hibernate já contem alguma strings 
+    	de configurações (insertsql, deletesql, updatesql etc.). 
+    	O mapaemento das tags  
+    	<literal>&lt;sql-insert&gt;</literal>,
+	<literal>&lt;sql-delete&gt;</literal>, e
+	<literal>&lt;sql-update&gt;</literal>     	
+	sobreecreve essas strings:
+    </para>
+
+    <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
+    <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
+    <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
+</class>]]></programlisting>
+
+    <para>
+    O SQL é executado diretamente no seu banco de dados, então você pode usar qualquer 
+    linguagem que quiser. Isto com certeza reduzira a portabilidade do seu mapeamento se 
+    você utilizar um SQL para um banco de dados especifico. 
+    </para>
+
+    <para>
+    	Stored Procedures são suportadas se o atributo the 
+    	<literal>callable</literal> estiver ativado:
+    </para>
+
+    <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
+    <sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
+    <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
+</class>]]></programlisting>
+
+    <para>
+    A ordem de posições dos parâmetros são vitais, pois eles devem estar na mesma seqüência 
+    esperada pelo Hibernate.
+    </para>
+
+    <para>Você pode ver a ordem esperada ativando o debug logging no nível 
+    <literal>org.hibernate.persister.entity</literal>. Com este nível ativado, o Hibernate 
+    irá imprimir o SQL estático que foi usado para create, update, delete, etc. 
+    Entidades. (Para ver a seqüência esperada, lembre-se de não incluir seu SQL 
+    customizado no arquivo de mapeamento, pois ele irá sobreecreve o SQL 
+    estático gerado pelo Hibernate).
+    </para>
+
+    <para>As stored procedures são na maioria dos casos (leia: melhor não fazer) requeridas para 
+    retornar o numero de linhas inseridas/atualizadas/deletadas. O hibernate tem algumas 
+    verificações em tempo de execução para o sucesso da declaração. Hibernate sempre registra 
+    o primeiro parâmetro da declaração como uma saída numérica para operações CRUD.
+    </para>
+
+    <programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
+    RETURN NUMBER IS
+BEGIN
+
+    update PERSON
+    set
+        NAME = uname,
+    where
+        ID = uid;
+
+    return SQL%ROWCOUNT;
+
+END updatePerson;]]>
+</programlisting>
+
+  </sect1>
+
+  <sect1 id="querysql-load">
+    <title>SQL customizado para carga</title>
+
+    <para>
+    Você pode declarar sua própria query SQL (ou HQL) para iniciar entidades:
+    </para>
+
+    <programlisting><![CDATA[<sql-query name="person">
+    <return alias="pers" class="Person" lock-mode="upgrade"/>
+    SELECT NAME AS {pers.name}, ID AS {pers.id}
+    FROM PERSON
+    WHERE ID=?
+    FOR UPDATE
+</sql-query>]]></programlisting>
+
+    <para>
+    Este é apenas uma declaração de query com nome, como discutido anteriormente. 
+    Você pode referenciar esta query com nome em um mapeamento de classe:
+    </para>
+
+    <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <loader query-ref="person"/>
+</class>]]></programlisting>
+
+    <para>Isto também funciona com stored procedures.
+    </para>
+
+    <para>Você pode tembém definir uma query para iniciar collection:
+    </para>
+
+    <programlisting><![CDATA[<set name="employments" inverse="true">
+    <key/>
+    <one-to-many class="Employment"/>
+    <loader query-ref="employments"/>
+</set>]]></programlisting>
+
+    <programlisting><![CDATA[<sql-query name="employments">
+    <load-collection alias="emp" role="Person.employments"/>
+    SELECT {emp.*}
+    FROM EMPLOYMENT emp
+    WHERE EMPLOYER = :id
+    ORDER BY STARTDATE ASC, EMPLOYEE ASC
+</sql-query>]]></programlisting>
+
+    <para>You could even define an entity loader that loads a collection by
+    join fetching:</para>
+
+    <programlisting><![CDATA[<sql-query name="person">
+    <return alias="pers" class="Person"/>
+    <return-join alias="emp" property="pers.employments"/>
+    SELECT NAME AS {pers.*}, {emp.*}
+    FROM PERSON pers
+    LEFT OUTER JOIN EMPLOYMENT emp
+        ON pers.ID = emp.PERSON_ID
+    WHERE ID=?
+</sql-query>]]></programlisting>
+  </sect1>
+</chapter>
\ No newline at end of file


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/query_sql.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/session_api.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/session_api.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/session_api.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1248 @@
+<chapter id="objectstate">
+    <title>Trabalhando com objetos</title>
+
+    <para>
+        O Hibernate é uma solução completa de mapeamento objeto/relacional que não apenas 
+        poupa o desenvolvedor dos detalhes de baixo nível do sistema de gerenciamento do 
+        banco de dados, mas também oferece um <emphasis>gerenciamento de estado </emphasis>
+        para objetos. Isto é, ao contrário do gerenciamento de  <literal>instruções </literal>
+        SQL em camadas de persistência JDBC/SQL comuns, uma visão natural da persistência 
+        orientada a objetos em aplicações Java.
+    </para>
+
+    <para>
+        Em outras palavras, desenvolvedores de aplicações Hibernate podem sempre pensar em 
+        relação ao <emphasis>estado</emphasis> de seus objetos, e não necessariamente em 
+        relação a execução de instruções SQL. Este parte é responsabilidade do Hibernate e 
+        é relevante aos desenvolvedores de aplicações apenas quando estão ajustando 
+        a performance do sistema.
+    </para>
+
+    <sect1 id="objectstate-overview">
+        <title>Estado dos objetos no Hibernate</title>
+
+        <para>
+            O Hibernate define e suporta os seguintes estados de um objetos:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>Transient</emphasis> - um objeto é transiente se ele foi instanciando 
+                    usando apenas o operador <literal>new</literal>, e não foi associado com uma 
+                    <literal>Session</literal> do Hibernate. Ele não terá uma representação 
+                    persistente no banco de dados e nenhum identificador será atribuído para ele. 
+                    Instâncias transientes serão destruídas pelo coletor de lixo se a aplicação 
+                    não manter sua referência. Use uma <literal>Session</literal> do Hibernate 
+                    para tornar o objeto persistente ( e deixe o Hibernate gerenciar as 
+                    instruções SQL que serão necessárias para executar esta transição).
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Persistent</emphasis> -– uma instância persistente possui uma 
+                    representação no banco de dados e um identificador. Ele pode ter sido salvo 
+                    ou carregado, assim, ele está por definição no escopo de uma 
+                    <literal>Session</literal>. O Hibernate irá detectar qualquer mudança feita a 
+                    um objeto persistente e sincronizar o seu estado com o banco de dados quando 
+                    completar a unidade de trabalho. Desenvolvedores não executam instruções manuais 
+                    de <literal>UPDATE</literal>, ou instruções de  <literal>DELETE</literal> 
+                    quando o objeto deve ser passado para transiente.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Detached</emphasis> – uma instância desaclopada é um objeto que 
+                    foi persistido, mas sua <literal>Session</literal> foi fechada. A referência 
+                    ao objeto continua válida, é claro, e  a instância destacada desaclopada pode 
+                    ser acoplada a uma nova <literal>Session</literal> no futuro, fazendo-o 
+                    ( e todas as modificações sofridas) persistente novamente. Essa característica 
+                    possibilita um modelo de programação para unidades de trabalho que rodam 
+                    durante muito tempo que requer um pensamento por tempo do usuário. Podemos 
+                    chamar-las de <emphasis>transações da aplicação</emphasis>, i.e. uma unidade 
+                    de trabalho do ponto de vista do usuário.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Agora iremos discutir os estados e suas transições ( e os métodos do Hibernate que 
+            disparam uma transição) em mais detalhes.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-makingpersistent" revision="1">
+        <title>Tornando os objetos persistentes</title>
+
+        <para>
+            Instâncias recentemente instanciadas de uma classe persistente são 
+            consideradas <emphasis>transientes </emphasis> pelo Hibernate.
+            Podemos tornar uma instância transiente em  <emphasis>persistente</emphasis>
+            associando-a a uma sessão:            
+        </para>
+
+        <programlisting><![CDATA[DomesticCat fritz = new DomesticCat();
+fritz.setColor(Color.GINGER);
+fritz.setSex('M');
+fritz.setName("Fritz");
+Long generatedId = (Long) sess.save(fritz);]]></programlisting>
+
+        <para>
+            Se <literal>Cat</literal> possui um identificador gerado, o identificador 
+            é gerado e atribuído a <literal>cat</literal> quando <literal>save()</literal> 
+            for chamada. Se <literal>Cat</literal> possuir um identificador 
+            <literal>Associado</literal>, ou uma chave composta, o identificador deve ser 
+            atribuído à instância de <literal>cat</literal> antes que <literal>save()</literal> 
+            seja chamado. Pode-se usar também  <literal>persist()</literal> ao invés de 
+             <literal>save()</literal>, com a semântica definada no novo esboço do EJB3.
+        </para>
+        
+        <para>
+            Alternativamente, pode-se atribuir o identificador usando uma versão 
+            sobrecarregada de <literal>save()</literal>.
+        </para>
+
+<programlisting><![CDATA[DomesticCat pk = new DomesticCat();
+pk.setColor(Color.TABBY);
+pk.setSex('F');
+pk.setName("PK");
+pk.setKittens( new HashSet() );
+pk.addKitten(fritz);
+sess.save( pk, new Long(1234) );]]></programlisting>
+        
+        <para>
+            Se o objeto persistido possuir objetos associados (e.g. a coleção 
+            <literal>kittens</literal> no exemplo anterior), esses objetos podem ser 
+            tornar persistente em qualquer ordem que se queira ao menos que se tenha uma 
+            restrição <literal>NOT NULL</literal> em uma coluna de chave estrangeira. 
+            Nunca há risco de violação de restrições de chave estrangeira. Assim, 
+            pode-se violar uma restrição <literal>NOT NULL</literal> se 
+            <literal>save()</literal> for usada nos objetos em uma ordem errada.
+        </para>
+        
+        <para>
+            Geralmente você não deve se importar com esses detalhes, muito provavelmente se 
+            usará a característica de <emphasis>persistência transitiva </emphasis> do Hibernate 
+            para salvar os objetos associados automaticamente. Então, enquanto uma restrição 
+            <literal>NOT NULL</literal> não ocorrer – Hibernate tomará conta de tudo. 
+            Persistência transitiva será discutida futuramente nesse capítulo.
+        </para>
+        
+    </sect1>
+
+    <sect1 id="objectstate-loading">
+        <title>Carregando o objetos</title>
+
+        <para>
+            O método <literal>load()</literal> de uma <literal> Session</literal> nos 
+            fornece um meio para recuperar uma instância persistente se o identificador 
+            for conhecido. <literal>load()</literal> recebe uma classe do objeto e carregará
+            o estado em uma instância mais recente dessa classe, no estado persistente.             
+        </para>
+
+        <programlisting><![CDATA[Cat fritz = (Cat) sess.load(Cat.class, generatedId);]]></programlisting>
+
+<programlisting><![CDATA[// you need to wrap primitive identifiers
+long id = 1234;
+DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id) );]]></programlisting>
+
+        <para>
+            Alternatively, you can load state into a given instance:
+Alternativamente, pode-se carregar um estado em uma instância dada:
+        </para>
+
+<programlisting><![CDATA[Cat cat = new DomesticCat();
+// load pk's state into cat
+sess.load( cat, new Long(pkId) );
+Set kittens = cat.getKittens();]]></programlisting>
+
+        <para>
+            Repare que <literal>load()</literal> irá lançar uma exceção irrecuperável 
+            se não houver na tabela no banco de dados um registro que combine. 
+            Se a classe for mapeada com um proxy, <literal>load()</literal> 
+            simplesmente retorna um proxy não inicializado e realmente não chamará 
+            o banco de dados até que um método do proxy seja invocado. 
+            Esse comportamento é muito útil se deseja-se criar uma associação 
+            com um objeto sem que realmente o carregue do bando de dados. 
+            Isto também permite que sejam carregadas múltiplas instâncias como um 
+            grupo se <literal>batch-size</literal> estiver para o mapeamento da 
+            classe.
+        </para>
+        
+        <para>
+            Se você não tiver certeza da existencia do registro no banco, você deve
+            usar o metodo <literal>get()</literal>, que consulta o banco 
+            imediantamente e retorna um null se não existir o registro.
+        </para>
+        
+        <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id);
+if (cat==null) {
+    cat = new Cat();
+    sess.save(cat, id);
+}
+return cat;]]></programlisting>
+
+        <para>
+            Também pode-se carregar um objeto usando <literal>SELECT ... FOR UPDATE</literal>, 
+            usando um <literal>LockMode</literal>. Veja a documentação da API para maiores 
+            informações.
+        </para>
+
+        <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);]]></programlisting>
+        
+        <para>
+            Note that any associated instances or contained collections are 
+            <emphasis>not</emphasis> selected <literal>FOR UPDATE</literal>, unless you decide
+            to specify <literal>lock</literal> or <literal>all</literal> as a
+            cascade style for the association.
+       </para>
+        
+        <para>
+            O recarregamento de um objeto e todas as suas coleções é possível a qualquer momento, 
+            usando o método <literal>refresh()</literal>. Util quando as triggers do banco de 
+            dados  são usados para inicializar algumas propriedades do objeto.
+        </para>
+        
+        <programlisting><![CDATA[sess.save(cat);
+sess.flush(); //force the SQL INSERT
+sess.refresh(cat); //re-read the state (after the trigger executes)]]></programlisting>
+
+        <para>
+            Uma importante questão geralmente aparece neste ponto: O quanto Hibernate carrega 
+            do banco de dados e quantos SQL  <literal>SELECT</literal> ele irá usar? Isto 
+            depende da estratégia de <emphasis>recuperação</emphasis>usada e explicada na 
+            <xref linkend="performance-fetching"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-querying" revision="1">
+        <title>Consultando</title>
+
+        <para>
+            Se o identificador do objeto que se está buscando não for conhecido, 
+            uma consulta será necessária. O Hibernate suporta uma linguagem de consulta 
+            (HQL) orientada a objetos fácil mas poderosa. Para criação via programação 
+            de consultas, o Hibernate suporta características sofisticadas de consulta 
+            por Critério e Exemplo (QBCe QBE). Pode-se também expressar a consulta 
+            por meio de SQL nativa do banco de dados, com suporte opcional do Hibernate 
+            para conversão do conjunto de reultados em objetos.
+        </para>
+
+        <sect2 id="objectstate-querying-executing" revision="1">
+            <title>Executando consultas</title>
+
+            <para>
+                Consultas HQL e SQL nativa são representadas por uma instância de <literal>org.hibernate.Query</literal>.
+                Esta interface oferece métodos para associação de parâmetros, tratamento de conjunto de resultados, 
+                e para a execução de consultas reais. Você pode obter uma <literal>Query</literal> usando a 
+                <literal>Session</literal> atual:
+            </para>
+
+        <programlisting><![CDATA[List cats = session.createQuery(
+    "from Cat as cat where cat.birthdate < ?")
+    .setDate(0, date)
+    .list();
+
+List mothers = session.createQuery(
+    "select mother from Cat as cat join cat.mother as mother where cat.name = ?")
+    .setString(0, name)
+    .list();
+
+List kittens = session.createQuery(
+    "from Cat as cat where cat.mother = ?")
+    .setEntity(0, pk)
+    .list();
+
+Cat mother = (Cat) session.createQuery(
+    "select cat.mother from Cat as cat where cat = ?")
+    .setEntity(0, izi)
+    .uniqueResult();]]
+
+Query mothersWithKittens = (Cat) session.createQuery(
+    "select mother from Cat as mother left join fetch mother.kittens");
+Set uniqueMothers = new HashSet(mothersWithKittens.list());]]></programlisting>
+
+            <para>
+                Geralmente uma consulta é executada ao invocar <literal>list()</literal>, 
+                o resultado da consulta será carregado completamente em uma coleção na memória. 
+                Instâncias de entidades recuperadas por uma consulta estão no estado persistente. 
+                O <literal>uniqueResult()</literal> oferece um atalho se você souber de 
+                previamente que a consulta retornará apenas um único objeto. Repare que consultas 
+                que fazem uso de buscas de coleções de forma ansiosa (eager) geralmente retornam 
+                duplicatas dos objetos raiz ( mas com suas coleções inicializadas ). Pode-se 
+                filtrar estas duplicatas através de um simples <literal>Set</literal>.
+            </para>
+
+            <sect3 id="objectstate-querying-executing-iterate">
+                <title>Interagindo com resultados</title>
+
+                <para>
+                    Ocasionalmente, deves-se ser capaz de atingir performances melhores com 
+                    a execução de consultas usando o método <literal>iterate()</literal>. 
+                    Geralmente isso será o caso esperado apenas se as instâncias dos entidades 
+                    reais retornadas pela consulta já estiverem na sessão ou no caché de segundo 
+                    nível. Caso elas ainda não tenham sido armazenadas,  <literal>iterate()</literal> 
+                    será mais devagar do que <literal>list()</literal> e pode ser necessário vários 
+                    acessos ao banco de dados para um simples consulta, geralmente  <emphasis>1</emphasis>
+                    para a seleção inicial que retorna apenas identificadores, e <emphasis>n</emphasis>
+                    consultas adicionais para inicializar as instâncias reais.
+                </para>
+
+                <programlisting><![CDATA[// fetch ids
+Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate();
+while ( iter.hasNext() ) {
+    Qux qux = (Qux) iter.next();  // fetch the object
+    // something we couldnt express in the query
+    if ( qux.calculateComplicatedAlgorithm() ) {
+        // delete the current instance
+        iter.remove();
+        // dont need to process the rest
+        break;
+    }
+}]]></programlisting>
+            </sect3>
+            
+            <sect3 id="objectstate-querying-executing-tuples">
+                <title>Consultas que retornam tuplas</title>
+
+                <para>
+                    Algumas vezes as consultas do Hibernate retornam tuplas de objetos, nesse caso 
+                    cada tupla é retornada como um array:                    
+                </para>
+
+                <programlisting><![CDATA[Iterator kittensAndMothers = sess.createQuery(
+            "select kitten, mother from Cat kitten join kitten.mother mother")
+            .list()
+            .iterator();
+
+while ( kittensAndMothers.hasNext() ) {
+    Object[] tuple = (Object[]) kittensAndMothers.next();
+    Cat kitten  = tuple[0];
+    Cat mother  = tuple[1];
+    ....
+}]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-scalar" revision="1">
+                <title>Resultados escalares</title>
+
+                <para>
+                    Consultas devem especificar uma propriedade da classe na clausula 
+                    <literal>select</literal>. Elas também podem chamar funções SQL  de agregaçãos. 
+                    Propriedades ou agregações são considerados resultados agregados 
+                    ( e não entidades no estado persistente).
+                </para>
+
+                <programlisting><![CDATA[Iterator results = sess.createQuery(
+        "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
+        "group by cat.color")
+        .list()
+        .iterator();
+
+while ( results.hasNext() ) {
+    Object[] row = (Object[]) results.next();
+    Color type = (Color) row[0];
+    Date oldest = (Date) row[1];
+    Integer count = (Integer) row[2];
+    .....
+}]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-parameters">
+                <title>Bind parameters</title>
+
+                <para>
+                    Methods on <literal>Query</literal> are provided for binding values to
+                    named parameters or JDBC-style <literal>?</literal> parameters. 
+                    <emphasis>Contrary to JDBC, Hibernate numbers parameters from zero.</emphasis>
+                    Named parameters are identifiers of the form <literal>:name</literal> in 
+                    the query string. The advantages of named parameters are:
+                </para>
+
+                <itemizedlist spacing="compact">
+                    <listitem>
+                        <para>
+                            named parameters are insensitive to the order they occur in the
+                            query string
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            they may occur multiple times in the same query
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                            they are self-documenting
+                        </para>
+                    </listitem>
+                </itemizedlist>
+
+                <programlisting><![CDATA[//named parameter (preferred)
+Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
+q.setString("name", "Fritz");
+Iterator cats = q.iterate();]]></programlisting>
+
+                <programlisting><![CDATA[//positional parameter
+Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
+q.setString(0, "Izi");
+Iterator cats = q.iterate();]]></programlisting>
+
+                <programlisting><![CDATA[//named parameter list
+List names = new ArrayList();
+names.add("Izi");
+names.add("Fritz");
+Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)");
+q.setParameterList("namesList", names);
+List cats = q.list();]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-pagination">
+                <title>Pagination</title>
+
+                <para>
+                    If you need to specify bounds upon your result set (the maximum number of rows
+                    you want to retrieve and / or the first row you want to retrieve) you should
+                    use methods of the <literal>Query</literal> interface:
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.createQuery("from DomesticCat cat");
+q.setFirstResult(20);
+q.setMaxResults(10);
+List cats = q.list();]]></programlisting>
+
+                <para>
+                    Hibernate knows how to translate this limit query into the native
+                    SQL of your DBMS.
+                </para>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-scrolling">
+                <title>Scrollable iteration</title>
+
+                <para>
+                    If your JDBC driver supports scrollable <literal>ResultSet</literal>s, the
+                    <literal>Query</literal> interface may be used to obtain a
+                    <literal>ScrollableResults</literal> object, which allows flexible
+                    navigation of the query results.
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
+                            "order by cat.name");
+ScrollableResults cats = q.scroll();
+if ( cats.first() ) {
+
+    // find the first name on each page of an alphabetical list of cats by name
+    firstNamesOfPages = new ArrayList();
+    do {
+        String name = cats.getString(0);
+        firstNamesOfPages.add(name);
+    }
+    while ( cats.scroll(PAGE_SIZE) );
+
+    // Now get the first page of cats
+    pageOfCats = new ArrayList();
+    cats.beforeFirst();
+    int i=0;
+    while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) );
+
+}
+cats.close()]]></programlisting>
+
+                <para>
+                    Note that an open database connection (and cursor) is required for this
+                    functionality, use <literal>setMaxResult()</literal>/<literal>setFirstResult()</literal>
+                    if you need offline pagination functionality.
+                </para>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-named" revision="1">
+                <title>Externalizing named queries</title>
+
+                <para>
+                    You may also define named queries in the mapping document. (Remember to use a
+                    <literal>CDATA</literal> section if your query contains characters that could
+                    be interpreted as markup.)
+                </para>
+
+                <programlisting><![CDATA[<query name="ByNameAndMaximumWeight"><![CDATA[
+    from eg.DomesticCat as cat
+        where cat.name = ?
+        and cat.weight > ?
+] ]></query>]]></programlisting>
+
+                <para>
+                    Parameter binding and executing is done programatically:
+                </para>
+
+                <programlisting><![CDATA[Query q = sess.getNamedQuery("ByNameAndMaximumWeight");
+q.setString(0, name);
+q.setInt(1, minWeight);
+List cats = q.list();]]></programlisting>
+
+                <para>
+                    Note that the actual program code is independent of the query language that
+                    is used, you may also define native SQL queries in metadata, or migrate
+                    existing queries to Hibernate by placing them in mapping files.
+                </para>
+
+                <para>
+                    Also note that a query declaration inside a <literal>&lt;hibernate-mapping&gt;</literal>
+                    element requires a global unique name for the query, while a query declaration inside a
+                    <literal>&lt;class&gt;</literal> element is made unique automatically by prepending the
+                    fully qualified name of the class, for example
+                    <literal>eg.Cat.ByNameAndMaximumWeight</literal>.
+                </para>
+
+            </sect3>
+
+        </sect2>
+
+        <sect2 id="objectstate-filtering" revision="1">
+            <title>Filtering collections</title>
+            <para>
+                A collection <emphasis>filter</emphasis> is a special type of query that may be applied to
+                a persistent collection or array. The query string may refer to <literal>this</literal>,
+                meaning the current collection element.
+            </para>
+
+            <programlisting><![CDATA[Collection blackKittens = session.createFilter(
+    pk.getKittens(), 
+    "where this.color = ?")
+    .setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) )
+    .list()
+);]]></programlisting>
+        
+            <para>
+                The returned collection is considered a bag, and it's a copy of the given
+                collection. The original collection is not modified (this is contrary to
+                the implication of the name "filter", but consistent with expected behavior).
+            </para>
+
+            <para>
+                Observe that filters do not require a <literal>from</literal> clause (though they may have
+                one if required). Filters are not limited to returning the collection elements themselves.
+            </para>
+
+            <programlisting><![CDATA[Collection blackKittenMates = session.createFilter(
+    pk.getKittens(), 
+    "select this.mate where this.color = eg.Color.BLACK.intValue")
+    .list();]]></programlisting>
+
+            <para>
+                Even an empty filter query is useful, e.g. to load a subset of elements in a
+                huge collection:
+            </para>
+
+            <programlisting><![CDATA[Collection tenKittens = session.createFilter(
+    mother.getKittens(), "")
+    .setFirstResult(0).setMaxResults(10)
+    .list();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="objecstate-querying-criteria" revision="1">
+           <title>Criteria queries</title>
+
+            <para>
+                HQL is extremely powerful but some developers prefer to build queries dynamically,
+                using an object-oriented API, rather than building query strings. Hibernate provides
+                an intuitive <literal>Criteria</literal> query API for these cases:
+            </para>
+
+            <programlisting><![CDATA[Criteria crit = session.createCriteria(Cat.class);
+crit.add( Expression.eq( "color", eg.Color.BLACK ) );
+crit.setMaxResults(10);
+List cats = crit.list();]]></programlisting>
+    
+            <para>
+                The <literal>Criteria</literal> and the associated <literal>Example</literal>
+                API are discussed in more detail in <xref linkend="querycriteria"/>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="objectstate-querying-nativesql" revision="2">
+            <title>Queries in native SQL</title>
+
+            <para>
+                You may express a query in SQL, using <literal>createSQLQuery()</literal> and
+                let Hibernate take care of the mapping from result sets to objects. Note
+                that you may at any time call <literal>session.connection()</literal> and
+                use the JDBC <literal>Connection</literal> directly. If you chose to use the
+                Hibernate API, you must enclose SQL aliases in braces:
+            </para>
+
+            <programlisting><![CDATA[List cats = session.createSQLQuery(
+    "SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10",
+    "cat",
+    Cat.class
+).list();]]></programlisting>
+                
+            <programlisting><![CDATA[List cats = session.createSQLQuery(
+    "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
+           "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
+    "FROM CAT {cat} WHERE ROWNUM<10",
+    "cat",
+    Cat.class
+).list()]]></programlisting>
+
+            <para>
+                SQL queries may contain named and positional parameters, just like Hibernate queries.
+                More information about native SQL queries in Hibernate can be found in
+                <xref linkend="querysql"/>.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="objectstate-modifying" revision="1">
+        <title>Modifying persistent objects</title>
+
+        <para>
+            <emphasis>Transactional persistent instances</emphasis> (ie. objects loaded, saved, created or
+            queried by the <literal>Session</literal>) may be manipulated by the application
+            and any changes to persistent state will be persisted when the <literal>Session</literal>
+            is <emphasis>flushed</emphasis> (discussed later in this chapter). There is no need
+            to call a particular method (like <literal>update()</literal>, which has a different
+            purpose) to make your modifications persistent. So the most straightforward way to update
+            the state of an object is to <literal>load()</literal> it,
+            and then manipulate it directly, while the <literal>Session</literal> is open:
+        </para>
+
+        <programlisting><![CDATA[DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
+cat.setName("PK");
+sess.flush();  // changes to cat are automatically detected and persisted]]></programlisting>
+
+        <para>
+            Sometimes this programming model is inefficient since it would require both an SQL
+            <literal>SELECT</literal> (to load an object) and an SQL <literal>UPDATE</literal>
+            (to persist its updated state) in the same session. Therefore Hibernate offers an
+            alternate approach, using detached instances.
+        </para>
+
+        <para>
+            <emphasis>Note that Hibernate does not offer its own API for direct execution of
+            <literal>UPDATE</literal> or <literal>DELETE</literal> statements. Hibernate is a
+            <emphasis>state management</emphasis> service, you don't have to think in
+            <emphasis>statements</emphasis> to use it. JDBC is a perfect API for executing
+            SQL statements, you can get a JDBC <literal>Connection</literal> at any time
+            by calling <literal>session.connection()</literal>. Furthermore, the notion
+            of mass operations conflicts with object/relational mapping for online
+            transaction processing-oriented applications. Future versions of Hibernate
+            may however provide special mass operation functions. See <xref linkend="batch"/>
+            for some possible batch operation tricks.</emphasis>
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-detached" revision="2">
+        <title>Modifying detached objects</title>
+
+        <para>
+            Many applications need to retrieve an object in one transaction, send it to the
+            UI layer for manipulation, then save the changes in a new transaction.
+            Applications that use this kind of approach in a high-concurrency environment
+            usually use versioned  data to ensure isolation for the "long" unit of work.
+        </para>
+
+        <para>
+            Hibernate supports this model by providing for reattachment of detached instances
+            using the <literal>Session.update()</literal> or <literal>Session.merge()</literal>
+            methods:
+        </para>
+
+        <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catId);
+Cat potentialMate = new Cat();
+firstSession.save(potentialMate);
+
+// in a higher layer of the application
+cat.setMate(potentialMate);
+
+// later, in a new session
+secondSession.update(cat);  // update cat
+secondSession.update(mate); // update mate]]></programlisting>
+
+        <para>
+            If the <literal>Cat</literal> with identifier <literal>catId</literal> had already
+            been loaded  by <literal>secondSession</literal> when the application tried to
+            reattach it, an exception would have been thrown.
+        </para>
+
+        <para>
+            Use <literal>update()</literal> if you are sure that the session does
+            not contain an already persistent instance with the same identifier, and
+            <literal>merge()</literal> if you want to merge your modifications at any time
+            without consideration of the state of the session. In other words, <literal>update()</literal>
+            is usually the first method you would call in a fresh session, ensuring that
+            reattachment of your detached instances is the first operation that is executed.
+        </para>
+
+        <para>
+            The application should individually <literal>update()</literal> detached instances
+            reachable from the given detached instance if and <emphasis>only</emphasis> if it wants
+            their state also updated. This can be automated of course, using <emphasis>transitive
+            persistence</emphasis>, see <xref linkend="objectstate-transitive"/>.
+        </para>
+
+        <para>
+            The <literal>lock()</literal> method also allows an application to reassociate
+            an object with a new session. However, the detached instance has to be unmodified!
+        </para>
+
+        <programlisting><![CDATA[//just reassociate:
+sess.lock(fritz, LockMode.NONE);
+//do a version check, then reassociate:
+sess.lock(izi, LockMode.READ);
+//do a version check, using SELECT ... FOR UPDATE, then reassociate:
+sess.lock(pk, LockMode.UPGRADE);]]></programlisting>
+
+        <para>
+            Note that <literal>lock()</literal> can be used with various
+            <literal>LockMode</literal>s, see the API documentation and the
+            chapter on transaction handling for more information. Reattachment is not
+            the only usecase for <literal>lock()</literal>.
+        </para>
+
+        <para>
+            Other models for long units of work are discussed in <xref linkend="transactions-optimistic"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-saveorupdate">
+        <title>Automatic state detection</title>
+
+        <para>
+            Hibernate users have requested a general purpose method that either saves a
+            transient instance by generating a new identifier or updates/reattaches
+            the detached instances associated with its current identifier.
+            The <literal>saveOrUpdate()</literal> method implements this functionality.
+        </para>
+
+        <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catID);
+
+// in a higher tier of the application
+Cat mate = new Cat();
+cat.setMate(mate);
+
+// later, in a new session
+secondSession.saveOrUpdate(cat);   // update existing state (cat has a non-null id)
+secondSession.saveOrUpdate(mate);  // save the new instance (mate has a null id)]]></programlisting>
+
+        <para>
+            The usage and semantics of <literal>saveOrUpdate()</literal> seems to be confusing
+            for new users. Firstly, so long as you are not trying to use instances from one session
+            in another new session, you should not need to use <literal>update()</literal>,
+            <literal>saveOrUpdate()</literal>, or <literal>merge()</literal>. Some whole
+            applications will never use either of these methods.
+        </para>
+
+        <para>
+            Usually <literal>update()</literal> or <literal>saveOrUpdate()</literal> are used in
+            the following scenario:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    the application loads an object in the first session
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    the object is passed up to the UI tier
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    some modifications are made to the object
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    the object is passed back down to the business logic tier
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    the application persists these modifications by calling
+                    <literal>update()</literal> in a second session
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>saveOrUpdate()</literal> does the following:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    if the object is already persistent in this session, do nothing
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    if another object associated with the session has the same identifier, 
+                    throw an exception
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    if the object has no identifier property, <literal>save()</literal> it
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    if the object's identifier has the value assigned to a newly instantiated
+                    object, <literal>save()</literal> it
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    if the object is versioned (by a <literal>&lt;version&gt;</literal> or
+                    <literal>&lt;timestamp&gt;</literal>), and the version property value
+                    is the same value assigned to a newly instantiated object, 
+                    <literal>save()</literal> it
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    otherwise <literal>update()</literal> the object
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            and <literal>merge()</literal> is very different:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    if there is a persistent instance with the same identifier currently 
+                    associated with the session, copy the state of the given object onto 
+                    the persistent instance
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    if there is no persistent instance currently associated with the session, 
+                    try to load it from the database, or create a new persistent instance
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    the persistent instance is returned
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    the given instance does not become associated with the session, it
+                    remains detached
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect1>
+
+    <sect1 id="objectstate-deleting" revision="1">
+        <title>Deleting persistent objects</title>
+
+        <para>
+            <literal>Session.delete()</literal> will remove an object's state from the database.
+            Of course, your application might still hold a reference to a deleted object.
+            It's best to think of <literal>delete()</literal> as making a persistent instance
+            transient.
+        </para>
+
+        <programlisting><![CDATA[sess.delete(cat);]]></programlisting>
+
+        <para>
+            You may delete objects in any order you like, without risk of foreign key
+            constraint violations. It is still possible to violate a <literal>NOT
+            NULL</literal> constraint on a foreign key column by deleting objects in
+            the wrong order, e.g. if you delete the parent, but forget to delete the
+            children.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="objectstate-replicating" revision="1">
+    	<title>Replicating object between two different datastores</title>
+    	
+    	<para>
+    	    It is occasionally useful to be able to take a graph of persistent instances
+    	    and make them persistent in a different datastore, without regenerating identifier
+    	    values.
+    	</para>
+    	
+        <programlisting><![CDATA[//retrieve a cat from one database
+Session session1 = factory1.openSession();
+Transaction tx1 = session1.beginTransaction();
+Cat cat = session1.get(Cat.class, catId);
+tx1.commit();
+session1.close();
+
+//reconcile with a second database
+Session session2 = factory2.openSession();
+Transaction tx2 = session2.beginTransaction();
+session2.replicate(cat, ReplicationMode.LATEST_VERSION);
+tx2.commit();
+session2.close();]]></programlisting>
+
+        <para>
+            The <literal>ReplicationMode</literal> determines how <literal>replicate()</literal>
+            will deal with conflicts with existing rows in the database.
+        </para>
+        
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.IGNORE</literal> - ignore the object when there is
+                    an existing database row with the same identifier
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.OVERWRITE</literal> - overwrite any existing database 
+                    row with the same identifier
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.EXCEPTION</literal> - throw an exception if there is
+                    an existing database row with the same identifier
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.LATEST_VERSION</literal> - overwrite the row if its
+                    version number is earlier than the version number of the object, or ignore
+                    the object otherwise
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Usecases for this feature include reconciling data entered into different database
+            instances, upgrading system configuration information during product upgrades,
+            rolling back changes made during non-ACID transactions and more.
+        </para>
+    	
+    </sect1>
+
+    <sect1 id="objectstate-flushing">
+        <title>Flushing the Session</title>
+
+        <para>
+            From time to time the <literal>Session</literal> will execute the SQL statements 
+            needed to synchronize the JDBC connection's state with the state of objects held in 
+            memory. This process, <emphasis>flush</emphasis>, occurs by default at the following 
+            points
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    before some query executions
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    from <literal>org.hibernate.Transaction.commit()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    from <literal>Session.flush()</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            The SQL statements are issued in the following order
+        </para>
+
+        <orderedlist spacing="compact">
+            <listitem>
+                <para>
+                    all entity insertions, in the same order the corresponding objects
+                    were saved using <literal>Session.save()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    all entity updates
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    all collection deletions
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    all collection element deletions, updates and insertions
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    all collection insertions
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    all entity deletions, in the same order the corresponding objects
+                    were deleted using <literal>Session.delete()</literal>
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <para>
+            (An exception is that objects using <literal>native</literal> ID generation are 
+            inserted when they are saved.)
+        </para>
+
+        <para>
+            Except when you explicity <literal>flush()</literal>, there are absolutely no 
+            guarantees about <emphasis>when</emphasis> the <literal>Session</literal> executes 
+            the JDBC calls, only the <emphasis>order</emphasis> in which they are executed.
+            However, Hibernate does guarantee that the <literal>Query.list(..)</literal> 
+            will never return stale data; nor will they return the wrong data.
+        </para>
+
+        <para>
+            It is possible to change the default behavior so that flush occurs less frequently.
+            The <literal>FlushMode</literal> class defines three different modes: only flush
+            at commit time (and only when the Hibernate <literal>Transaction</literal> API
+            is used), flush automatically using the explained routine, or never flush unless
+            <literal>flush()</literal> is called explicitly. The last mode is useful for long running
+            units of work, where a <literal>Session</literal> is kept open and disconnected for
+            a long time (see <xref linkend="transactions-optimistic-longsession"/>).
+        </para>
+
+        <programlisting><![CDATA[sess = sf.openSession();
+Transaction tx = sess.beginTransaction();
+sess.setFlushMode(FlushMode.COMMIT); // allow queries to return stale state
+
+Cat izi = (Cat) sess.load(Cat.class, id);
+izi.setName(iznizi);
+
+// might return stale data
+sess.find("from Cat as cat left outer join cat.kittens kitten");
+
+// change to izi is not flushed!
+...
+tx.commit(); // flush occurs
+sess.close();]]></programlisting>
+
+        <para>
+            During flush, an exception might occur (e.g. if a DML operation violates a constraint).
+            Since handling exceptions involves some understanding of Hibernate's transactional 
+            behavior, we discuss it in <xref linkend="transactions"/>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-transitive" revision="1">
+        <title>Transitive persistence</title>
+
+        <para>
+            It is quite cumbersome to save, delete, or reattach individual objects,
+            especially if you deal with a graph of associated objects. A common case is
+            a parent/child relationship. Consider the following example:
+        </para>
+
+        <para>
+            If the children in a parent/child relationship would be value typed (e.g. a collection
+            of addresses or strings), their lifecycle would depend on the parent and no
+            further action would be required for convenient "cascading" of state changes.
+            When the parent is saved, the value-typed child objects are saved as
+            well, when the parent is deleted, the children will be deleted, etc. This
+            even works for operations such as the removal of a child from the collection;
+            Hibernate will detect this and, since value-typed objects can't have shared
+            references, delete the child from the database.
+        </para>
+
+        <para>
+            Now consider the same scenario with parent and child objects being entities,
+            not value-types (e.g. categories and items, or parent and child cats). Entities
+            have their own lifecycle, support shared references (so removing an entity from
+            the collection does not mean it can be deleted), and there is by default no
+            cascading of state from one entity to any other associated entities. Hibernate
+            does not implement <emphasis>persistence by reachability</emphasis> by default.
+        </para>
+
+        <para>
+            For each basic operation of the Hibernate session - including <literal>persist(), merge(),
+            saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate()</literal> - there is a 
+            corresponding cascade style. Respectively, the cascade styles are named <literal>create, 
+            merge, save-update, delete, lock, refresh, evict, replicate</literal>. If you want an 
+            operation to be cascaded along an association, you must indicate that in the mapping
+            document. For example:
+        </para>
+        
+        <programlisting><![CDATA[<one-to-one name="person" cascade="persist"/>]]></programlisting>
+        
+        <para>
+            Cascade styles my be combined:
+        </para>
+        
+        <programlisting><![CDATA[<one-to-one name="person" cascade="persist,delete,lock"/>]]></programlisting>
+        
+        <para>
+            You may even use <literal>cascade="all"</literal> to specify that <emphasis>all</emphasis>
+            operations should be cascaded along the association. The default <literal>cascade="none"</literal>
+            specifies that no operations are to be cascaded.
+        </para>
+        
+        <para>
+            A special cascade style, <literal>delete-orphan</literal>, applies only to one-to-many
+            associations, and indicates that the <literal>delete()</literal> operation should
+            be applied to any child object that is removed from the association.
+        </para>
+
+
+        <para>
+            Recommendations:
+        </para>
+
+       <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    It doesn't usually make sense to enable cascade on a <literal>&lt;many-to-one&gt;</literal>
+                    or <literal>&lt;many-to-many&gt;</literal> association. Cascade is often useful for 
+                    <literal>&lt;one-to-one&gt;</literal> and <literal>&lt;one-to-many&gt;</literal>
+                    associations.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    If the child object's lifespan is bounded by the lifespan of the of the parent
+                    object make it a <emphasis>lifecycle object</emphasis> by specifying
+                    <literal>cascade="all,delete-orphan"</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Otherwise, you might not need cascade at all. But if you think that you will often be
+                    working with the parent and children together in the same transaction, and you want to save 
+                    yourself some typing, consider using <literal>cascade="persist,merge,save-update"</literal>.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Mapping an association (either a single valued association, or a collection) with 
+            <literal>cascade="all"</literal> marks the association as a 
+            <emphasis>parent/child</emphasis> style relationship where save/update/delete of the 
+            parent results in save/update/delete of the child or children.
+        </para>
+        <para>
+            Futhermore, a mere reference to a child from a persistent parent will result in 
+            save/update of the child. This metaphor is incomplete, however. A child which becomes 
+            unreferenced by its parent is <emphasis>not</emphasis> automatically deleted, except 
+            in the case of a <literal>&lt;one-to-many&gt;</literal> association mapped with
+            <literal>cascade="delete-orphan"</literal>. The precise semantics of cascading 
+            operations for a parent/child relationship are as follows:
+        </para>
+
+       <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    If a parent is passed to <literal>persist()</literal>, all children are passed to 
+                    <literal>persist()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    If a parent is passed to <literal>merge()</literal>, all children are passed to 
+                    <literal>merge()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    If a parent is passed to <literal>save()</literal>, <literal>update()</literal> or 
+                    <literal>saveOrUpdate()</literal>, all children are passed to <literal>saveOrUpdate()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    If a transient or detached child becomes referenced by a persistent parent, 
+                    it is passed to <literal>saveOrUpdate()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    If a parent is deleted, all children are passed to <literal>delete()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    If a child is dereferenced by a persistent parent, <emphasis>nothing
+                    special happens</emphasis> - the application should explicitly delete 
+                    the child if necessary - unless <literal>cascade="delete-orphan"</literal>, 
+                    in which case the "orphaned" child is deleted.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Finally, note that cascading of operations can be applied to an object graph at
+            <emphasis>call time</emphasis> or at <emphasis>flush time</emphasis>. All operations,
+            if enabled, are cascaded to associated entities reachable when the operation is
+            executed. However, <literal>save-upate</literal> and <literal>delete-orphan</literal>
+            are transitive for all associated entities reachable during flush of the
+            <literal>Session</literal>.
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-metadata">
+        <title>Usando metadados</title>
+
+        <para>
+            O Hibernate requer um modelo muito rico a nível de metadados de todas as entidades e tipos de 
+            valores. De tempos em tempos, este modelo é muito útil à própria aplicação. Por exemplo, a 
+            aplicação pode usar o metadados do Hibernate que executa um algoritmo "inteligente" que 
+            compreende quais objetos podem ser copiados (por exemplo, tipos de valores mutáveis) ou 
+            não (por exemplo, tipos de valores imutáveis e, possivelmente, entidades associadas).            
+        </para>
+        <para>
+            O Hibernate expõe o metadados via interfaces <literal>ClassMetadata</literal>
+            e <literal>CollectionMetadata</literal> e pela hierarquia <literal>Type</literal>. 
+            Instâncias das interfaces de metadados podem ser obtidas a partir do 
+            <literal>SessionFactory</literal>.
+        </para>
+
+        <programlisting><![CDATA[Cat fritz = ......;
+ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class);
+
+Object[] propertyValues = catMeta.getPropertyValues(fritz);
+String[] propertyNames = catMeta.getPropertyNames();
+Type[] propertyTypes = catMeta.getPropertyTypes();
+
+// get a Map of all properties which are not collections or associations
+Map namedValues = new HashMap();
+for ( int i=0; i<propertyNames.length; i++ ) {
+    if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType() ) {
+        namedValues.put( propertyNames[i], propertyValues[i] );
+    }
+}]]></programlisting>
+        
+    </sect1>
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/session_api.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/toolset_guide.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/toolset_guide.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/toolset_guide.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,604 @@
+<chapter id="toolsetguide" revision="2">
+    <title>Toolset Guide</title>
+
+    <para>
+        Roundtrip engineering with Hibernate is possible using a set of Eclipse plugins,
+        commandline tools, as well as Ant tasks.
+    </para>
+
+    <para>
+        The <emphasis>Hibernate Tools</emphasis> currently include plugins for the Eclipse
+        IDE as well as Ant tasks for reverse engineering of existing databases:
+    </para>
+
+    <itemizedlist>
+        <listitem><para>
+            <emphasis>Mapping Editor:</emphasis> An editor for Hibernate XML mapping files,
+            supporting auto-completion and syntax highlighting. It also supports semantic
+            auto-completion for class names and property/field names, making it much more versatile than a normal XML editor.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Console:</emphasis> The console is a new view in Eclipse. In addition to
+            a tree overview of your console configurations, you also get an interactive view
+            of your persistent classes and their relationships. The console allows you to
+            execute HQL queries against your database and browse the result directly in
+            Eclipse.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Development Wizards:</emphasis> Several wizards are provided with the
+            Hibernate Eclipse tools; you can use a wizard to quickly generate Hibernate configuration
+            (cfg.xml) files, or you may even completely reverse engineer an existing database schema
+            into POJO source files and Hibernate mapping files. The reverse engineering wizard
+            supports customizable templates.
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Ant Tasks:</emphasis>
+        </para></listitem>
+
+    </itemizedlist>
+
+    <para>
+        Please refer to the <emphasis>Hibernate Tools</emphasis> package and it's documentation
+        for more information.
+    </para>
+
+    <para>
+        However, the Hibernate main package comes bundled with an integrated tool (it can even
+        be used from "inside" Hibernate on-the-fly): <emphasis>SchemaExport</emphasis> aka
+        <literal>hbm2ddl</literal>.
+    </para>
+
+    <sect1 id="toolsetguide-s1" revision="2">
+        <title>Automatic schema generation</title>
+
+        <para>
+            DDL may be generated from your mapping files by a Hibernate utility. The generated
+            schema includes referential integrity constraints (primary and foreign keys) for
+            entity and collection tables. Tables and sequences are also created for mapped
+            identifier generators.
+        </para>
+        
+        <para>
+            You <emphasis>must</emphasis> specify a SQL <literal>Dialect</literal> via the 
+            <literal>hibernate.dialect</literal> property when using this tool, as DDL
+            is highly vendor specific.
+        </para>
+
+        <para>
+            First, customize your mapping files to improve the generated schema.
+        </para>
+
+        <sect2 id="toolsetguide-s1-2" revision="3">
+            <title>Customizing the schema</title>
+
+            <para>
+                Many Hibernate mapping elements define optional attributes named <literal>length</literal>,
+                <literal>precision</literal> and <literal>scale</literal>. You may set the length, precision 
+                and scale of a column with this attribute. 
+                
+            </para>
+
+            <programlisting><![CDATA[<property name="zip" length="5"/>]]></programlisting>
+            <programlisting><![CDATA[<property name="balance" precision="12" scale="2"/>]]></programlisting>
+
+            <para>
+                Some tags also accept a <literal>not-null</literal> attribute (for generating a 
+                <literal>NOT NULL</literal> constraint on table columns) and a <literal>unique</literal> 
+                attribute (for generating <literal>UNIQUE</literal> constraint on table columns).
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="bar" column="barId" not-null="true"/>]]></programlisting>
+
+            <programlisting><![CDATA[<element column="serialNumber" type="long" not-null="true" unique="true"/>]]></programlisting>
+
+            <para>
+                A <literal>unique-key</literal> attribute may be used to group columns in
+                a single unique key constraint. Currently, the specified value of the 
+                <literal>unique-key</literal> attribute is <emphasis>not</emphasis> used 
+                to name the constraint in the generated DDL, only to group the columns in 
+                the mapping file.
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="org" column="orgId" unique-key="OrgEmployeeId"/>
+<property name="employeeId" unique-key="OrgEmployee"/>]]></programlisting>
+
+            <para>
+                An <literal>index</literal> attribute specifies the name of an index that
+                will be created using the mapped column or columns. Multiple columns may be 
+                grouped into the same index, simply by specifying the same index name. 
+            </para>
+
+            <programlisting><![CDATA[<property name="lastName" index="CustName"/>
+<property name="firstName" index="CustName"/>]]></programlisting>
+
+            <para>
+                A <literal>foreign-key</literal> attribute may be used to override the name 
+                of any generated foreign key constraint.
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="bar" column="barId" foreign-key="FKFooBar"/>]]></programlisting>
+
+            <para>
+                Many mapping elements also accept a child <literal>&lt;column&gt;</literal> element. 
+                This is particularly useful for mapping multi-column types:
+            </para>
+
+            <programlisting><![CDATA[<property name="name" type="my.customtypes.Name"/>
+    <column name="last" not-null="true" index="bar_idx" length="30"/>
+    <column name="first" not-null="true" index="bar_idx" length="20"/>
+    <column name="initial"/>
+</property>]]></programlisting>
+
+            <para>
+                The <literal>default</literal> attribute lets you specify a default value for
+                a column (you should assign the same value to the mapped property before
+                saving a new instance of the mapped class).
+            </para>
+
+            <programlisting><![CDATA[<property name="credits" type="integer" insert="false">
+    <column name="credits" default="10"/>
+</property>]]></programlisting>
+
+            <programlisting><![CDATA[<version name="version" type="integer" insert="false">
+    <column name="version" default="0"/>
+</property>]]></programlisting>
+
+            <para>
+                The <literal>sql-type</literal> attribute allows the user to override the default 
+                mapping of a Hibernate type to SQL datatype.
+            </para>
+            
+            <programlisting><![CDATA[<property name="balance" type="float">
+    <column name="balance" sql-type="decimal(13,3)"/>
+</property>]]></programlisting>
+            
+            <para>
+                The <literal>check</literal> attribute allows you to specify a check constraint.
+            </para>
+            
+            <programlisting><![CDATA[<property name="foo" type="integer">
+    <column name="foo" check="foo > 10"/>
+</property>]]></programlisting>
+
+            <programlisting><![CDATA[<class name="Foo" table="foos" check="bar < 100.0">
+    ...
+    <property name="bar" type="float"/>
+</class>]]></programlisting>
+            
+
+            <table frame="topbot" id="schemattributes-summary" revision="2">
+                <title>Summary</title>
+                <tgroup cols="3">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>Attribute</entry>
+                            <entry>Values</entry>
+                            <entry>Interpretation</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>length</literal></entry>
+                            <entry>number</entry>
+                            <entry>column length</entry>
+                        </row>
+                        <row>
+                            <entry><literal>precision</literal></entry>
+                            <entry>number</entry>
+                            <entry>column decimal precision</entry>
+                        </row>
+                        <row>
+                            <entry><literal>scale</literal></entry>
+                            <entry>number</entry>
+                            <entry>column decimal scale</entry>
+                        </row>
+                        <row>
+                            <entry><literal>not-null</literal></entry>
+                            <entry><literal>true|false</literal></entry>
+                            <entry>specfies that the column should be non-nullable</entry>
+                        </row>
+                        <row>
+                            <entry><literal>unique</literal></entry>
+                            <entry><literal>true|false</literal></entry>
+                            <entry>specifies that the column should have a unique constraint</entry>
+                        </row>
+                        <row>
+                            <entry><literal>index</literal></entry>
+                            <entry><literal>index_name</literal></entry>
+                            <entry>specifies the name of a (multi-column) index</entry>
+                        </row>
+                        <row>
+                            <entry><literal>unique-key</literal></entry>
+                            <entry><literal>unique_key_name</literal></entry>
+                            <entry>specifies the name of a multi-column unique constraint</entry>
+                        </row>
+                        <row>
+                            <entry><literal>foreign-key</literal></entry>
+                            <entry><literal>foreign_key_name</literal></entry>
+                            <entry>
+                                specifies the name of the foreign key constraint generated
+                                for an association, for a <literal>&lt;one-to-one&gt;</literal>, 
+                                <literal>&lt;many-to-one&gt;</literal>, <literal>&lt;key&gt;</literal>, 
+                                or <literal>&lt;many-to-many&gt;</literal> mapping element. Note that
+                                <literal>inverse="true"</literal> sides will not be considered
+                                by <literal>SchemaExport</literal>.
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>sql-type</literal></entry>
+                            <entry><literal>SQL column type</literal></entry>
+                            <entry>
+                                overrides the default column type (attribute of 
+                                <literal>&lt;column&gt;</literal> element only)
+                            </entry>
+                       </row>
+                       <row>
+                            <entry><literal>default</literal></entry>
+                            <entry>SQL expression</entry>
+                            <entry>
+                                specify a default value for the column
+                            </entry>
+                       </row>
+                       <row>
+                            <entry><literal>check</literal></entry>
+                            <entry>SQL expression</entry>
+                            <entry>
+                                create an SQL check constraint on either column or table
+                            </entry>
+                       </row>
+                   </tbody>
+                </tgroup>
+            </table>
+            
+            <para>
+                The <literal>&lt;comment&gt;</literal> element allows you to specify comments
+                for the generated schema.
+            </para>
+            
+            <programlisting><![CDATA[<class name="Customer" table="CurCust">
+    <comment>Current customers only</comment>
+    ...
+</class>]]></programlisting>
+
+            <programlisting><![CDATA[<property name="balance">
+    <column name="bal">
+        <comment>Balance in USD</comment>
+    </column>
+</property>]]></programlisting>
+            
+            <para>
+                This results in a <literal>comment on table</literal> or 
+                <literal>comment on column</literal> statement in the generated
+                DDL (where supported).
+            </para>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-3" revision="2">
+            <title>Running the tool</title>
+
+            <para>
+                The <literal>SchemaExport</literal> tool writes a DDL script to standard out and/or
+                executes the DDL statements.
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaExport</literal> <emphasis>options mapping_files</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaExport</literal> Command Line Options</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Option</entry>
+                            <entry>Description</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--quiet</literal></entry>
+                            <entry>don't output the script to stdout</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--drop</literal></entry>
+                            <entry>only drop the tables</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--create</literal></entry>
+                            <entry>only create the tables</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--text</literal></entry>
+                            <entry>don't export to the database</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--output=my_schema.ddl</literal></entry>
+                            <entry>output the ddl script to a file</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>select a <literal>NamingStrategy</literal></entry>
+                        </row>
+                         <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry>read Hibernate configuration from an XML file</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>read database properties from a file</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--format</literal></entry>
+                            <entry>format the generated SQL nicely in the script</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--delimiter=;</literal></entry>
+                            <entry>set an end of line delimiter for the script</entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                You may even embed <literal>SchemaExport</literal> in your application:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaExport(cfg).create(false, true);]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-4">
+            <title>Properties</title>
+
+            <para>
+                Database properties may be specified
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>as system properties with <literal>-D</literal><emphasis>&lt;property&gt;</emphasis></para>
+                </listitem>
+                <listitem>
+                    <para>in <literal>hibernate.properties</literal></para>
+                </listitem>
+                <listitem>
+                    <para>in a named properties file with <literal>--properties</literal></para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                The needed properties are:
+            </para>
+
+            <table frame="topbot">
+                <title>SchemaExport Connection Properties</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Property Name</entry>
+                            <entry>Description</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                    <row>
+                        <entry><literal>hibernate.connection.driver_class</literal></entry>
+                        <entry>jdbc driver class</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.url</literal></entry>
+                        <entry>jdbc url</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.username</literal></entry>
+                        <entry>database user</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.password</literal></entry>
+                        <entry>user password</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.dialect</literal></entry>
+                        <entry>dialect</entry>
+                    </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-5">
+            <title>Using Ant</title>
+
+            <para>
+                You can call <literal>SchemaExport</literal> from your Ant build script:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemaexport">
+    <taskdef name="schemaexport"
+        classname="org.hibernate.tool.hbm2ddl.SchemaExportTask"
+        classpathref="class.path"/>
+    
+    <schemaexport
+        properties="hibernate.properties"
+        quiet="no"
+        text="no"
+        drop="no"
+        delimiter=";"
+        output="schema-export.sql">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaexport>
+</target>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-6" revision="2">
+            <title>Incremental schema updates</title>
+
+            <para>
+                The <literal>SchemaUpdate</literal> tool will update an existing schema with "incremental" changes.
+                Note that <literal>SchemaUpdate</literal> depends heavily upon the JDBC metadata API, so it will
+                not work with all JDBC drivers.
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>options mapping_files</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaUpdate</literal> Command Line Options</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Option</entry>
+                            <entry>Description</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--quiet</literal></entry>
+                            <entry>don't output the script to stdout</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--text</literal></entry>
+                            <entry>don't export the script to the database</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>select a <literal>NamingStrategy</literal></entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>read database properties from a file</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry>specify a <literal>.cfg.xml</literal> file</entry>
+                        </row>
+                     </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                You may embed <literal>SchemaUpdate</literal> in your application:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaUpdate(cfg).execute(false);]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-7">
+            <title>Using Ant for incremental schema updates</title>
+
+            <para>
+                You can call <literal>SchemaUpdate</literal> from the Ant script:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemaupdate">
+    <taskdef name="schemaupdate"
+        classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask"
+        classpathref="class.path"/>
+    
+    <schemaupdate
+        properties="hibernate.properties"
+        quiet="no">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaupdate>
+</target>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-8" revision="1">
+            <title>Schema validation</title>
+
+            <para>
+                The <literal>SchemaValidator</literal> tool will validate that the existing database schema "matches"
+                your mapping documents. Note that <literal>SchemaValidator</literal> depends heavily upon the JDBC 
+                metadata API, so it will not work with all JDBC drivers. This tool is extremely useful for testing.
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaValidator</literal> <emphasis>options mapping_files</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaValidator</literal> Command Line Options</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>Option</entry>
+                            <entry>Description</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>select a <literal>NamingStrategy</literal></entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>read database properties from a file</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry>specify a <literal>.cfg.xml</literal> file</entry>
+                        </row>
+                     </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                You may embed <literal>SchemaValidator</literal> in your application:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaValidator(cfg).validate();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-9">
+            <title>Using Ant for schema validation</title>
+
+            <para>
+                You can call <literal>SchemaValidator</literal> from the Ant script:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemavalidate">
+    <taskdef name="schemavalidator"
+        classname="org.hibernate.tool.hbm2ddl.SchemaValidatorTask"
+        classpathref="class.path"/>
+    
+    <schemavalidator
+        properties="hibernate.properties">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaupdate>
+</target>]]></programlisting>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/toolset_guide.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/transactions.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/transactions.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/transactions.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1147 @@
+<chapter id="transactions" revision="2">
+    <title>Transações e Concorrência</title>
+
+    <para>
+        O ponto o mais importante sobre o Hibernate e o controle de concorrência é que é muito 
+        fácil de ser compreendido. O Hibernate usa diretamente conexões de JDBC e recursos de 
+        JTA sem adicionar nenhum comportamento de bloqueio a mais. Nós altamente recomendamos 
+        que você gaste algum tempo com o JDBC, o ANSI e a especificação de isolamento de transação 
+        de seu sistema de gerência da base de dados.
+    </para>
+
+    <para>
+        O Hibernate não bloqueia objetos na memória. Sua aplicação pode esperar o comportamento 
+        tal qual definido pelo nível de isolamento de suas transações de banco de dados. 
+        Note que graças ao <literal>Session</literal>, que também é um cache de escopo de 
+        transação, o Hibernate fornece leituras repetíveis para procurar por identificadores 
+        e consultas de entidade (não pesquisas de relatórios que retornam valores escalares).
+    </para>
+
+    <para>        
+    		Além do versionamento para o controle automático de concorrência otimista, o Hibernate 
+        oferece também uma API (menor) para bloqueio pessimista de linhas usando a sintaxe 
+        <literal>SELECT FOR UPDATE</literal>. O controle de concorrência otimista e esta 
+        API são discutidos mais tarde neste capítulo. 
+    </para>
+
+    <para>
+        Nós começamos a discussão do controle de concorrência no Hibernate com a granularidade 
+        do <literal>Configuration</literal>, <literal>SessionFactory</literal>, e
+        <literal>Session</literal>, além de transações de base de dados e conversações longas.
+    </para>
+
+    <sect1 id="transactions-basics" revision="1">
+        <title>Session e escopos de transações</title>
+
+        <para>
+            Um <literal>SessionFactory</literal> é objeto threadsafe compartilhado por 
+            todas as threads da aplicação que consome muitos recursos na sua criação. 
+            É criado uma unica vez no inicio da execução da aplicação a partir da
+            instância de uma <literal>Configuration</literal>.
+        </para>
+
+        <para>
+            Uma <literal>Session</literal> é um objeto de baixo custo de criação, não é threadsafe, 
+            deve ser usado uma vez, para uma única requisição, uma conversação, uma única unidade 
+            do trabalho e então deve ser descartado. Um <literal>Session</literal> não obterá um 
+            JDBC <literal>Connection</literal> (ou um <literal>Datasource</literal>) a menos que 
+            necessite, conseqüentemente não consome nenhum recurso até ser usado. 
+        </para>
+
+        <para>
+            Para completar, você também tem que pensar sobre as transações de base de dados. 
+            Uma transação tem que ser tão curta quanto possível, para reduzir a disputa pelo 
+            bloqueio na base de dados. Transações longas impedirão que sua aplicação escale a 
+            carga altamente concorrente. Por isso, em um projeto raramente é para manter 
+            uma transação de base de dados aberta durante o tempo que o usuário pensa, 
+            até que a unidade do trabalho esteja completa.
+        </para>
+
+        <para>
+            Qual é o escopo de uma unidade de trabalho? Pode uma únicoa <literal>Session</literal> 
+            do Hibernate gerenciar diversas transações ou é esta um o relacionamento um-para-um dos 
+            escopos? Quando deve você abrir e fechar uma <literal>Session</literal> e como você 
+            demarca os limites da transação?
+        </para>
+
+        <sect2 id="transactions-basics-uow" revision="1">
+            <title>Unidade de trabalho</title>
+
+            <para>
+                Primeiro, não use o antipattern <emphasis>sessão-por-operação</emphasis>, 
+                isto é, não abra e não feche uma <literal>Session</literal> para cada simples chamada 
+                ao banco de de dados em uma única thread! Naturalmente, o mesmo é verdadeiro para 
+                transações. As chamadas a banco de dados em uma aplicação são feitas usando uma 
+                seqüência planejada, elas são agrupadas em unidades de trabalho atômicas. 
+                (Veja que isso também significa que um auto-commit depois de cada sentença SQL é 
+                inútil em uma aplicação, esta modalidade é ideal para o trabalho ad hoc do console 
+                do SQL. O Hibernate impede, ou espera que o servidor de aplicação impessa isso, 
+                o uso da modalidade de auto-commit.) As transações nunca são opcionais, toda a 
+                comunicação com um banco de dados tem que ocorrer dentro de uma transação, não 
+                importa se você vai ler ou escrever dados. Como explicado, o comportamento auto-commit 
+                para leitura de dados deve ser evitado, como muitas transações pequenas são 
+                improváveis de executar melhor do que uma unidade claramente definida do trabalho. A
+                última opção também muito mais manutenível e extensível.
+            </para>
+
+            <para>
+                O pattern mais comum em uma aplicação multi-usuário cliente/servidor é 
+                <emphasis>sessão-por-requisição</emphasis>. Neste modelo, uma requisição do cliente é 
+                enviada ao servidor (onde a camada de persistência do Hibernate roda), uma 
+                <literal>Session</literal> nova do Hibernate é aberta, e todas as operações da base de 
+                dados são executadas nesta unidade do trabalho. Logo que o trabalho for completado 
+                (e a resposta para o cliente for preparada), a sessão é descarregad e fechada. 
+                Você usaria também uma única transação de base de dados para servir às requisições 
+                dos clientes, começando e commitando-o quando você abre e fecha a  <literal>Session</literal>. 
+                O relacionamento entre os dois é um-para-um e este modelo é um ajuste perfeito para muitas 
+                aplicações.
+          </para>
+
+            <para>
+                O desafio encontra-se na implementação. O Hibernate fornece gerência integrada da "sessão atual" 
+                para simplificar este pattern. Tudo que você tem que fazer é iniciar uma transação quando uma 
+                requisição tem que ser processada e termina a transação antes que a resposta seja enviada ao 
+                cliente. Você pode fazer onde quiser, soluções comuns são <literal>ServletFilter</literal>, 
+                interceptador AOP com um pointcut (ponto de corte) nos métodos de serviço ou em um 
+                container de proxy/interceptação. Um container de EJB é uma maneira padronizada para 
+                implementar aspectos cross-cutting tais como a demarcação da transação em EJB session beans, 
+                declarativamente com CMT. Se você se decidir usar demarcação programática de transação, 
+                de preferencia a API <literal>Transaction</literal> do Hibernate mostrada mais adiante neste 
+                capítulo, para fácilidade no uso e portabilidade de código. 
+            </para>
+
+            <para>
+                Seu código de aplicação pode acessar a "sessão atual" para processar a requisição 
+                fazendo uma chamada simples a  <literal>sessionFactory.getCurrentSession()</literal> em 
+                qualquer lugar e com a frequencia necessária. Você sempre conseguirá uma
+                <literal>Session</literal> limitada a transação atual. Isto tem que ser configurado 
+                para recurso local ou os ambientes JTA. Veja <xref linkend="architecture-current-session"/>. 
+            </para>
+
+            <para>
+                Às vezes é conveniente estender o escopo de uma  <literal>Session</literal> e de 
+                uma transação do banco de dados até que a "visão esteja renderizada". É especialmente 
+                útil em aplicações servlet que utilizam uma fase de rendenderização separada depois 
+                que a requisição ter sido processada. Estendendo a transação até que renderização da 
+                visão esteja completa é fácil de fazer se você implementar seu próprio interceptador. 
+                Entretanto, não se pode fazer facilmente se você confiar em EJBs com transações 
+                gerenciadas por contêiner, porque uma transação será terminada quando um método de 
+                EJB retornar, antes da renderização de toda visão puder começar. 
+                Veja o website e o fórum do Hibernate para dicas e exemplos em torno deste 
+                pattern <emphasis>Open Session in View</emphasis>. 
+
+             </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-apptx" revision="1">
+            <title>Longas conversações</title>
+
+            <para>
+                O pattern sessão-por-requisição não é o único conceito útil que você pode usar ao projetar 
+                unidades de trabalho. Muitos processos de negócio requerem uma totalidade de séries de 
+                interações com o usuário intercaladas com acessos a uma base de dados. Em aplicações web 
+                e corporativas não é aceitável para uma transação atrapalhe uma interação do usuário.
+                Considere o seguinte exemplo:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        A primeira tela de um diálogo abre os dados carregado pelo usuário em através de 
+                        <literal>Session</literal> e transação particulares. O usuário está livre 
+                        modificar os objetos. 
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        O usuário clica em "Salvar" após 5 minutos e espera suas modificações serem persistidas; 
+                        espera também que ele era a única pessoa que edita esta informação e que nenhuma 
+                        modificação conflitante possa ocorrer. 
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Nós chamamos esta unidade de trabalho, do ponto da visão do usuário, executando uma 
+                longa <emphasis>conversação</emphasis> (ou <emphasis>transação da aplicação</emphasis>). 
+                Há muitas maneiras de você pode implementar em sua aplicação. 
+
+            </para>
+
+            <para>
+                Uma primeira implementação simples pode manter a<literal>Session</literal> e a transação 
+                aberta durante o tempo de interação do usuário, com bloqueios na base de dados para impedir 
+                a modificação concorrente e para garantir o isolamento e a atomicidade. Esse é naturalmente 
+                um anti-pattern, desde que a disputa do bloqueio não permitiria o escalonameneto da 
+                aplicação com o número de usuários concorrentes. 
+            </para>
+
+            <para>
+                Claramente, nós temos que usar diversas transações para implementar a conversação. 
+                Neste caso, Manter o isolamento dos processos de negócio torna-se responsabilidade 
+                parcial da camada da aplicação. Uma única conversação geralmente usa diversas transações. 
+                Ela será atômica se somente uma destas transações (a última) armazenar os
+                dados atualizados, todas as outras simplesmente leram os dados (por exemplo em um 
+                diálogo do estilo wizard que mede diversos ciclos de requisição/resposta). Isto é mais 
+                fácil de implementar do que pode parecer, especialmente se você usar as
+                características do Hibernate: 
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <emphasis>Versionamento automático</emphasis> - O Hibernate pode fazer o 
+                        controle automático de concorrência otimista para você, ele pode 
+                        automaticamente detectar se uma modificação concorrente 
+                        ocorreu durante o tempo de interação do usuário. Geralmente nós verificamos 
+                        somente no fim da conversação.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <emphasis>Detached Objects</emphasis>- se você se decidir usar o já discutido 
+                        pattern <emphasis>session-per-request</emphasis>, todas as instâncias carregadas 
+                        estarão no estado destacado durante o tempo em que o usuário estiver pensando.
+                        O Hibernate permite que você reatache os objetos e persita as modificações,
+                        esse pattern é chamado 
+                        <emphasis>session-per-request-with-detached-objects</emphasis>.
+                        É usado versionamento automatico para isolar as modificações concorrentes.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <emphasis>Extended (or Long) Session</emphasis> A <literal>Session</literal> 
+                        do Hibernate pode ser desligada da conexão básica do JDBC depois que a 
+                        transação foi commitada e ser reconectado quando uma nova requisição do 
+                        cliente ocorrer. Este pattern é conhecido como 
+                        <emphasis>session-per-conversation</emphasis> e faz o reatamento uniforme 
+                        desnecessário. Versionamento automático é usado para isolar modificações 
+                        concorrentes e a <emphasis>session-per-conversation</emphasis> usualmente 
+                        não é permitido para ser nivelado automaticamente, e sim explicitamente. 
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Ambos <emphasis>session-per-request-with-detached-objects</emphasis> e
+                <emphasis>session-per-conversation</emphasis> possuem vantagens e desvantagens, 
+                nos discutiremos mais tarde neste capítulo no contexto do controle de 
+                concorrência otimista. 
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-identity">
+            <title>Considerando a identidade do objeto</title>
+
+            <para>
+                Uma aplicação pode acessar concorrentemente o mesmo estado persistente em duas 
+                <literal>Session</literal>s diferentes. Entretanto, uma instância de uma classe 
+                persistente nunca é compartilhada entre duas instâncias <literal>Session</literal>. 
+                Por tanto, há duas noções diferentes da identidade: 
+            </para>
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term>Identidade da base de dados</term>
+                    <listitem>
+                        <para>
+                            <literal>foo.getId().equals( bar.getId() )</literal>
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Identidade da JVM</term>
+                    <listitem>
+                        <para>
+                            <literal>foo==bar</literal>
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+            <para>
+                Então para os objetos acoplados a um <literal>Session</literal> em <literal>particular </literal>
+                (isto é no escopo de um <literal>Session</literal>), as duas noções são equivalentes e a 
+                identidade da JVM para a identidade da base de dados é garantida pelo Hibernate. Entretanto, 
+                quando a aplicação pode acessar concorrentemente o "mesmo" objeto do negócio (identidade 
+                persistente) em duas sessões diferentes, as duas instâncias serão realmente "diferentes"
+                (identidade de JVM). Os conflitos são resolvidos usando (versionamento automático) no 
+                flush/commit, usando abordagem otimista. 
+
+            </para>
+
+            <para>
+                Este caminho deixa o Hibernate e o banco dedados se preocuparem com a concorrência; também 
+                fornece uma escalabilidade melhor, garantindo que a identidade em unidades de trabalho 
+                único-encadeadas não necessite de bloqueio dispendioso ou de outros meios de sincronização. 
+                A aplicação nunca necessita sincronizar qualquer objeto de negócio tão longo que transpasse 
+                uma única thread por <literal>Session</literal>. Dentro de uma <literal>Session</literal> a 
+                aplicação pode usar com segurança o <literal>==</literal> para comparar objetos. 
+            </para>
+
+            <para>
+                Com tudo, uma aplicação que usa <literal>==</literal> fora de uma <literal>Session</literal>, 
+                pode ver resultados inesperados. Isto pode ocorrer mesmo em alguns lugares inesperados, por 
+                exemplo, se você colocar duas instâncias desacopladas em um mesmo <literal>Set</literal>. 
+                Ambos podem ter a mesma identidade na base de dados (isto é eles representam a mesma linha 
+                em uma tabela), mas a identidade da JVM pela definição não garantida para instâncias em estado 
+                desacoplado. O desenvolvedor tem que sobrescrever os métodos <literal>equals()</literal> e 
+                <literal>hashCode()</literal> em classes persistentes e implementar sua própria noção da 
+                igualdade do objeto. Advertência: nunca use o identificador da base de dados para implementar 
+                a igualdade, use atributos de negócio, uma combinação única, geralmente imutável. O 
+                identificador da base de dados mudará se um objeto transiente passar para o estado persistente. 
+                Se a instância transiente (geralmente junto com instâncias desacopladas) for inserida em um 
+                <literal>Set</literal>, mudar o hashcode quebra o contrato do <literal>Set</literal>. 
+                Atributos para chaves de negócio não têm que ser tão estável quanto às chaves primárias 
+                da base de dados, você somente tem que garantir a estabilidade durante o tempo que 
+                os objetos estiverem no mesmo Set. Veja o website do Hibernate para uma discussão mais 
+                completa sobre o assunto. Note também que esta não é uma caracteristica do Hibernate, 
+                mas simplesmente como a identidade e a igualdade do objeto de Java têm que ser implementadas. 
+	            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-issues">
+            <title>Edições comuns</title>
+
+             <para>
+                 Nunca use o anti-patterns <emphasis>session-per-user-session</emphasis> ou 
+                 <emphasis>session-per-application</emphasis> (naturalmente, há umas exceções raras a 
+                 essa regra). Note que algumas das seguintes edições podem também aparecer com patterns 
+                 recomendados, certifique-se que tenha compreendido as implicações antes de fazer 
+                 uma decisão de projeto: 
+             </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        Uma <literal>Session</literal> não é threadsafe. As coisas que são supostas para trabalhar 
+                        concorrentemente, como requisições HTTP, session beans, ou Swing, causarão condições de 
+                        disputa se uma instância <literal>Session</literal> for compartilhada. Se você mantiver 
+                        sua <literal>Session</literal> do Hibernate em seu <literal>HttpSession</literal> 
+                        (discutido mais tarde), você deve considerar sincronizar o acesso a sua sessão do HTTP. 
+                        Caso contrário, um usuário que clica em reload várias muito rapidamente pode usar o 
+                        mesmo <literal>Session</literal> em duas threads executando concorrentemente.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Uma exceção lançada pelo Hibernate significa que você tem que dar rollback na sua 
+                        transação no banco de dados e fechar a <literal>Session</literal> imediatamente 
+                        (discutido mais tarde em maiores detalhes). Se sua <literal>Session</literal> é 
+                        limitado pela aplicação, você tem que parar a aplicação. Dando rollback na 
+                        transação no banco de dados não põe seus objetos do negócio em um estado anterior 
+                        que estavam no início da transação. Isto significa que o estado da base de dados 
+                        e os objetos de negócio perdem a sincronização. Geralmente não é um problema 
+                        porque as exceções não são recuperáveis e você tem que iniciar após o 
+                        rollback de qualquer maneira.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        O <literal>Session</literal> guarda em cache cada objeto que está no estado persistente 
+                        (guardado e checado para estado "sujo" pelo Hibernate). Isto significa que ele cresce 
+                        infinitamente até que você obtenha uma OutOfMemoryException, se você o mantiver aberto 
+                        por muito tempo ou simplesmente carregar dados demais. Uma solução é chamar  
+                        <literal>clear()</literal> e <literal>evict()</literal> para controlar o cache 
+                        da <literal>Session</literal>, mas você deve considerar uma Store Procedure 
+                        se precisar de operações que envolvam grande volume de dados. Algumas soluções são
+                        mostradas no  <xref linkend="batch"/>. Manter uma <literal>Session</literal> aberta 
+                        durante uma sessão do usuário significa também uma probabilidade elevada de se acabar 
+                        com dados velhos.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="transactions-demarcation">
+        <title>Demarcação de transações de bancos de dados</title>
+
+        <para>
+            Os limites de uma transação de banco de dados (ou sistema) são sempre necessários. Nenhuma 
+            comunicação com o banco de dados pode ocorrer fora de uma transação de banco de dados (isto 
+            parece confundir muitos desenvolvedores que estão usados modo auto-commit). Sempre use os 
+            limites desobstruídos da transação, até mesmo para operações somente leitura. Dependendo 
+            de seu nível de isolamento e capacidade da base de dados isto pode não ser requerido, 
+            mas não há nenhum aspecto negativo se você demarca sempre transações explicitamente. 
+            Certamente, uma única transação será melhor executada do que muitas transações pequenas, 
+            até mesmo para dados de leitura. 
+        </para>
+
+        <para>
+            Uma aplicação do Hibernate pode funcionar em ambientes não gerenciados (isto é aplicações standalone, Web 
+            simples ou Swing) e ambientes gerenciados J2EE. Em um ambiente não gerenciado, o Hibernate é geralmente 
+            responsável pelo seu próprio pool de conexões. O desenvolvedor tem que manualmente ajustar limites das 
+            transaçãos, ou seja, começar, commitar, ou dar rollback nas transações ele mesmo. Um ambiente gerenciado 
+            fornece transações gerenciadas por contêiner (CMT - container-managed transactions), com um conjunto 
+            da transações definido declarativamente em descritores de deployment de EJB session beans, por exemplo. 
+            A demarcação programática é então já não é necessário. 
+        </para>
+
+        <para>
+            Entretanto, é freqüentemente desejável manter sua camada de persistência portável entre ambientes 
+            de recurso locais não gerenciados e sistemas que podem confiar em JTA, mas usar BMT em vez de CMT. 
+            Em ambos os casos você usaria demarcação de transação programática. O Hibernate oferece uma API 
+            chamada Transaction que traduz dentro do sistema de transação nativa de seu ambiente de deployment. 
+            Esta API é realmente opcional, mas nós encorajamos fortemente seu uso a menos que você estiver 
+            em um CMT session bean. 
+        </para>
+
+        <para>
+            Geralmente, finalizar um <literal>Session</literal>envolve quatro fases distintas:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    flush da sessão
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    commitar a transação
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    fechar a sessão
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                		tratar as exceções 
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            A limpeza da sessão já foi bem discutida, agora nós daremos uma olhada na demarcação da 
+            transação e na manipulação de exceção em ambientes controlados e não controlados. 
+        </para>
+
+
+        <sect2 id="transactions-demarcation-nonmanaged" revision="2">
+            <title>Ambiente não gerenciado</title>
+
+            <para>
+	               Se uma camada de persistência do Hibernate roda em um ambiente não gerenciado, as conexões 
+	               do banco de dados são geralmente tratadas pelos pools de conexões simples 
+	               (isto é, não baseados em DataSource) dos quais o Hibernate obtém as conexões assim 
+	               que necessita. A maneira de se manipular uma sessão/transação é mais ou menos assim:             
+	         </para>
+
+            <programlisting><![CDATA[// Non-managed environment idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+    tx = sess.beginTransaction();
+
+    // do some work
+    ...
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    if (tx != null) tx.rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+            <para>
+                Você não pode chamar <literal>flush()</literal> do  <literal>Session()</literal> 
+                explicitamente - a chamada ao <literal>commit()</literal> dispara automaticamente 
+                a sincronização para a sessão (dependendo do <xref linkend="objectstate-flushing">
+                FlushMode</xref>). Uma chamada ao <literal>close()</literal> marca o fim de uma sessão. 
+                A principal implicação do <literal>close()</literal> é que a conexão JDBC será abandonada 
+                pela sessão. Este código Java é portável e funciona em ambientes não gerenciado e de JTA. 
+            </para>
+
+           <para>
+                Uma solução muito mais flexível é gerência integrada de contexto da "sessão atual" 
+                do Hibernate, como descrito anteriormente: 
+            </para>
+
+            <programlisting><![CDATA[// Non-managed environment idiom with getCurrentSession()
+try {
+    factory.getCurrentSession().beginTransaction();
+
+    // do some work
+    ...
+
+    factory.getCurrentSession().getTransaction().commit();
+}
+catch (RuntimeException e) {
+    factory.getCurrentSession().getTransaction().rollback();
+    throw e; // or display error message
+}]]></programlisting>
+
+            <para>
+                Você muito provavelmente nunca verá estes fragmentos de código em uma aplicação 
+                regular; as exceções fatais (do sistema) devem sempre ser pegas no "alto". 
+                Ou seja, o código que executa chamadas do Hibernate (na camada de persistência) 
+                e o código que trata <literal>RuntimeException</literal>  (e geralmente pode 
+                somente limpar acima e na saída) estão em camadas diferentes. O gerenciamento do 
+                contexto atual feito pelo Hibernate pode significativamente simplificar este 
+                projeto, como tudo que você necessita é do acesso a um <literal>SessionFactory</literal>.
+                A manipulação de exceção é discutida mais tarde neste capítulo. 
+            </para>
+
+           <para>
+                Note que você deve selecionar <literal>org.hibernate.transaction.JDBCTransactionFactory</literal>
+                (que é o padrão) e para o segundo exemplo <literal>"thread"</literal> como seu 
+                <literal>hibernate.current_session_context_class</literal>.
+            </para>
+            
+        </sect2>
+
+        <sect2 id="transactions-demarcation-jta" revision="3">
+            <title>Usando JTA</title>
+
+            <para>
+                Se sua camada de persistência funcionar em um servidor de aplicação (por exemplo, 
+                dentro dos EJB session beans), cada conexão do datasource obtida pelo Hibernate 
+                automaticamente fará parte da transação global de JTA. Você pode também instalar uma 
+                implementação standalone de JTA e usá-la sem EJB. O Hibernate oferece duas estratégias 
+                para a integração de JTA. 
+            </para>
+
+            <para>
+                Se você usar bean-managed transactions (BMT - transações gerenciadas por bean) o Hibernate dirá 
+                ao servidor de aplicação para começar e para terminar uma transação de BMT se você usar a API 
+                Transaction. Assim, o código de gerência de transação é idêntico ao ambiente não gerenciado. 
+            </para>
+            
+           <programlisting><![CDATA[// BMT idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+    tx = sess.beginTransaction();
+
+    // do some work
+    ...
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    if (tx != null) tx.rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+           <para>
+               Se você quiser usar um  <literal>Session</literal> limitada por transação, isto é, 
+               a funcionalidade do <literal>getCurrentSession()</literal> para a propagação fácil 
+               do contexto, você terá que usar diretamente a API JTA <literal>UserTransaction</literal>: 
+            </para>
+
+            <programlisting><![CDATA[// BMT idiom with getCurrentSession()
+try {
+    UserTransaction tx = (UserTransaction)new InitialContext()
+                            .lookup("java:comp/UserTransaction");
+
+    tx.begin();
+
+    // Do some work on Session bound to transaction
+    factory.getCurrentSession().load(...);
+    factory.getCurrentSession().persist(...);
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    tx.rollback();
+    throw e; // or display error message
+}]]></programlisting>
+
+            <para>
+                Com CMT, a demarcação da transação é feita em descritores de deployment do session beans, 
+                não programaticamente, conseqüentemente, o código é reduzido a: 
+            </para>
+
+            <programlisting><![CDATA[// CMT idiom
+ Session sess = factory.getCurrentSession();
+
+ // do some work
+ ...
+]]></programlisting>
+
+            <para>
+                Em um CMT/EJB mesmo um rollback acontece automaticamente, desde que uma exeção <literal>RuntimeException</literal>
+                não tratável seja lançada por um método de um session bean que informa ao contêiner ajustar a 
+                transação global ao rollback. <emphasis>Isto significa que você não necessita usar a API 
+                <literal>Transaction</literal> do Hibernate em tudo com BMT ou CMT e você obtém a propagação 
+                automática do Session "atual" limitada à transação.</emphasis>
+            </para>
+
+            <para>
+                Veja que você deverá escolher <literal>org.hibernate.transaction.JTATransactionFactory</literal> 
+                se você usar o JTA diretamente (BMT) e <literal>org.hibernate.transaction.CMTTransactionFactory</literal> 
+                em um CMT session bean, quando você configura a fábrica de transação do Hibernate. Lembre-se também de 
+                configurar o <literal>hibernate.transaction.manager_lookup_class</literal>. Além disso, certifique-se 
+                que seu <literal>hibernate.current_session_context_class</literal> ou não é configurado (compatibilidade 
+                com o legado) ou é definido para <literal>"jta"</literal>.
+
+            </para>
+
+            <para>
+                A operação <literal>getCurrentSession()</literal> tem um aspecto negativo em um ambiente JTA. 
+                Há uma advertência para o uso do método liberado de conexão <literal>after_statement</literal>, 
+                o qual é usado então por padrão. Devido a uma limitação simples da especificação JTA, não é 
+                possível para o Hibernate automaticamente limpar quaisquer instâncias <literal>ScrollableResults</literal>
+                ou <literal>Iterator</literal> abertas retornadas pelo <literal>scroll()</literal> ou
+                <literal>iterate()</literal>. Você <emphasis>deve</emphasis> liberar o cursor subjacente da 
+                base de dados chamando <literal>ScrollableResults.close()</literal> ou
+                <literal>Hibernate.close(Iterator)</literal> explicitamente de um bloco <literal>finally</literal>. 
+                (Claro que a maioria de aplicações podem facilmente evitar o uso do <literal>scroll()</literal> ou 
+                do <literal>iterate()</literal> em todo código provindo do JTA ou do CMT.) 
+
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-demarcation-exceptions">
+            <title>Tratamento de Exceção</title>
+
+            <para>
+                Se a <literal>Session</literal> levantar uma exceção (incluindo qualquer 
+                <literal>SQLException</literal>), você deve imediatamente dar um rollback 
+                na transação do banco, chamando <literal>Session.close()</literal> e descartando 
+                a instância da <literal>Session</literal>. Certos métodos da <literal>Session</literal> 
+                <literal>não</literal> deixarão a sessão em um estado inconsistente. Nenhuma exceção 
+                lançada pelo Hibernate pode ser recuperada. Certifique-se que a <literal>Session</literal>
+                será fechada chamando <literal>close()</literal> no bloco <literal>finally</literal>.
+            </para>
+
+            <para>
+                A exceção <literal>HibernateException</literal>, a qual envolve a maioria dos erros 
+                que podem ocorrer em uma camada de persistência do Hibernate, é uma exceção unchecked (
+                não estava em umas versões mais antigas de Hibernate). Em nossa opinião, nós não devemos
+                forçar o desenvolvedor a tratar uma exceção irrecuperável em uma camada mais baixa. 
+                Na maioria dos sistemas, as exceções unchecked e fatais são tratadas em um dos primeiros 
+                frames da pilha da chamada do método (isto é, em umas camadas mais elevadas) e uma mensagem 
+                de erro é apresentada ao usuário da aplicação (ou a alguma outra ação apropriada é feita). 
+                Note que Hibernate pode também lançar outras exceções unchecked que não são um 
+                <literal>HibernateException</literal>. Estas, também são, irrecuperáveis e uma ação 
+                apropriada deve ser tomada.
+            </para>
+
+            <para>
+                O Hibernate envolve <literal>SQLException</literal>s lançadas ao interagir com a base de dados 
+                em um <literal>JDBCException</literal>. Na realidade, o Hibernate tentará converter a exceção em
+                em uma sub classe mais significativa da <literal>JDBCException</literal>. A 
+                <literal>SQLException</literal> subjacente está sempre disponível através de 
+                <literal>JDBCException.getCause()</literal>. 
+            </para>
+
+            <para>
+                O Hibernate converte a <literal>SQLException</literal> em uma sub classe 
+                <literal>JDBCException</literal> apropriada usando <literal>SQLExceptionConverter</literal> 
+                associado ao SessionFactory. Por padrão, o <literal>SQLExceptionConverter</literal>  é definido 
+                pelo dialeto configurado; entretanto, é também possível conectar em uma implementação customizada
+                (veja o javadoc para mais detalhes da classe  <literal>SQLExceptionConverterFactory</literal>). 
+                Os subtipos padrão de <literal>JDBCException</literal> são:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>JDBCConnectionException</literal> - indica um erro com a comunicação subjacente de JDBC.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>SQLGrammarException</literal> - indica um problema da gramática ou da sintaxe com o SQL emitido.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>ConstraintViolationException</literal> - indica algum forma de violação de confinamento de integridade.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>LockAcquisitionException</literal> - indica um erro ao adquirir um nível de bloqueio necessário para realizar a operação de requisição.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>GenericJDBCException</literal> - uma exceção genérica que não cai em algumas das outras categorias. 
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+        </sect2>
+
+        <sect2 id="transactions-demarcation-timeout">
+            <title>Timeout de Transação</title>
+
+            <para>
+                Uma característica extremamente importante fornecida por um ambiente 
+                gerenciado como EJB e que nunca é fornecido pelo código não gerenciado é o timeout 
+                de transação. Timeouts de transação asseguram que nenhuma transação possa 
+                reter  indefinidamente recursos enquanto não retorna nenhuma resposta ao usuário.
+                Fora de um ambiente controlado (JTA), o Hibernate não pode fornecer inteiramente 
+                esta funcionalidade. Entretanto, o Hibernate pode afinal controlar as operações 
+                do acesso a dados, assegurando que o nível de deadlocks e queries do banco de 
+                dados com imensos resultados definidos sejam limitados pelo timeout. Em um ambiente 
+                gerenciado, o Hibernate pode delegar o timeout da transação ao JTA. Esta funcionalidade 
+                é abstraída pelo objeto  <literal>Transaction</literal> do Hibernate. 
+            </para>
+            
+            <programlisting><![CDATA[
+Session sess = factory.openSession();
+try {
+    //set transaction timeout to 3 seconds
+    sess.getTransaction().setTimeout(3);
+    sess.getTransaction().begin();
+
+    // do some work
+    ...
+
+    sess.getTransaction().commit()
+}
+catch (RuntimeException e) {
+    sess.getTransaction().rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+            <para>
+                Veja que <literal>setTimeout()</literal> não pode ser chamado em um CMT bean, 
+                onde os timeouts das transações devem ser definidos declarativamente.
+            </para>
+            
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="transactions-optimistic">
+        <title>Controle de concorrência otimista</title>
+
+        <para>
+            O único caminho que é consistente com a elevada concorrência e escalabilidade 
+            é controle de concorrência otimista com versionamento. Checagem de versão usa 
+            número de versão, ou timestamps, para detectar conflitos de atualizações (e para 
+            impedir atualizações perdidas). O Hibernate fornece três caminhos possíveis para 
+            escrever aplicações que usam concorrência otimista. Os casos de uso que nós mostramos 
+            estão no contexto de conversações longas, mas a checagem de versão também tem o 
+            benefício de impedir atualizações perdidas em únicas transações.            
+        </para>
+
+        <sect2 id="transactions-optimistic-manual">
+            <title>Checagem de versão da aplicação</title>
+
+            <para>
+                Em uma implementação sem muita ajuda do Hibernate, cada interação com o banco de dados 
+                ocorre em uma nova <literal>Session</literal> e o desenvolvedor é responsável para 
+                recarregar todas as instâncias persistentes da base de dados antes de manipulá-las. 
+                Este caminho força a aplicação a realizar sua própria checagem de versão para assegurar 
+                a conversação do isolamento da transação. Este caminho é menos eficiente em termos de 
+                acesso ao banco de dados. É a caminho mais similar a EJBs entity.                
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+
+int oldVersion = foo.getVersion();
+session.load( foo, foo.getKey() ); // load the current state
+if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();
+foo.setProperty("bar");
+
+t.commit();
+session.close();]]></programlisting>
+
+            <para>
+                A propriedade <literal>version</literal> é mapeada usando <literal>&lt;version&gt;</literal>, 
+                e o Hibernate vai incrementá-lo-á automaticamente durante o flush se a entidade 
+                estiver alterada.
+            </para>
+
+            <para>
+                Claro, se você se estiver operando em um ambiente de baixa concorrência de dados 
+                e não requerer a checagem de versão, você pode usar este caminho e apenas saltar a 
+                checagem de versão. Nesse caso, o  <emphasis>ultimo commit realizdo </emphasis> é 
+                a estratégia padrão para suas conversações longas. Mantenha em mente que isto pode 
+                confundir os usuários da aplicação, assim como eles podem experimentar atualizações
+                perdidas sem mensagens de erro ou uma possibilidade ajustar mudanças de conflito.
+
+            </para>
+
+            <para>
+                Claro que, checagem manual da versão é somente praticável em circunstâncias triviais 
+                e não para a maioria de aplicações. Freqüentemente, os grafos completos de objetos 
+                modificados têm que ser verificados, não somente únicas instâncias. O Hibernate oferece 
+                checagem de versão automática com uma <literal>Session</literal> estendida ou instâncias 
+                desatachadas como o paradigma do projeto.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-longsession">
+            <title>Sessão estendida e versionamento automático</title>
+
+            <para>
+                Uma única instância de <literal>Session</literal> e suas instâncias persistentes 
+                são usadas para a conversação inteira, isto é conhecido como 
+                <emphasis>session-per-conversation</emphasis>. O Hibernate verifica versões da instância 
+                no momento dio flush, lançando uma exceção se a modificação concorrente for detectada. 
+                Até o desenvolvedor pegar e tratar essa exceção (as opções comuns são a oportunidade 
+                para que o usuário intercale as mudanças ou reinicie a conversação do negócio com 
+                dados não antigos).                
+            </para>
+
+            <para>
+                The <literal>Session</literal> is disconnected from any underlying JDBC connection
+                when waiting for user interaction. This approach is the most efficient in terms
+                of database access. The application need not concern itself with version checking or
+                with reattaching detached instances, nor does it have to reload instances in every
+                database transaction.
+                A <literal>Session</literal> é desconectada de toda a conexão JDBC subjacente 
+                enquanto espera a interação do usuário. Este caminho é a mais eficiente em termos 
+                de acesso a bancos de dados. A aplicação não necessita concernir-se com a checagem 
+                de versão ou com as instâncias destacadas reatadas, nem tem que recarregar instâncias 
+                em cada transação.
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded earlier by the old session
+Transaction t = session.beginTransaction(); // Obtain a new JDBC connection, start transaction
+
+foo.setProperty("bar");
+
+session.flush();    // Only for last transaction in conversation
+t.commit();         // Also return JDBC connection
+session.close();    // Only for last transaction in conversation]]></programlisting>
+            <para>
+                O objeto <literal>foo</literal> sabe que <literal>Session</literal> já foi carregada. Começando 
+                uma nova transação em uma sessão velha obtém uma conexão nova e recomeça a sessão. Commitando 
+                uma transação desconecta uma sessão da conexão JDBC e retorna a conexão ao pool. Após a reconexão, 
+                forçar uma checagem de versão em dados que você não está atualizando, você pode chamar 
+                <literal>Session.lock()</literal> com o <literal>LockMode.READ</literal> em todos os objetos 
+                que possam ter sido atualizados por uma outra transação. Você não necessita bloquear nenhum 
+                dado para atualizar. Geralmente você configuraria <literal>FlushMode.NEVER</literal> em uma
+                <literal>Session</literal> estendida, de modo que somente o último ciclo da transação tenha
+                permissão de persistir todas as modificações feitas nesta conversação. Disso, somente esta última 
+                transação incluiria a operação <literal>flush()</literal> e então chamar também <literal>close()</literal>
+                da sessão para terminar a conversação.
+            </para>
+            
+            <para>
+                Este pattern é problemático se a <literal>Session</literal> for demasiadamente grande para
+                ser armazenado durante o tempo que usuário pensar, por exemplo um <literal>HttpSession</literal> 
+                estiver mantido tão pequeno quanto possível. Como o <literal>Session</literal> é também cache 
+                de primeiro nível (imperativo) e contém todos os objetos carregados, nós podemos provavelmente 
+                usar esta estratégia somente para alguns ciclos de requisição/resposta. Você deve usar a
+                <literal>Session</literal> somente para uma única conversação, porque ela logo também 
+                estará com dados velhos.
+            </para>
+
+            <para>
+                (Note que versões mais atuais de Hibernate requerem a desconexão e o reconexão explícitas de 
+                uma <literal>Session</literal>. Estes métodos são desatualizados, como o início e término de 
+                uma transação tem o mesmo efeito.)
+            </para>
+
+            <para>
+                Note também que você deve manter a <literal>Session</literal> desconectada fechada 
+                para a camada de persistência. Ou seja, use um EJB stateful session bean para 
+                prender a <literal>Session</literal> em um ambiente do três camadas e não o 
+                transferir à camada web (ou até serializá-lo para uma camada separada)
+                para armazená-lo no <literal>HttpSession</literal>.
+
+            </para>
+
+            <para>
+                O pattern sessão estendida, ou <emphasis>session-per-conversation</emphasis>, é mais 
+                difícil de implementar com gerenciamento automático de sessão atual. Você precisa fornecer 
+                sua própria implementação do <literal>CurrentSessionContext</literal> para isto
+                (veja o Hibernate Wiki para exemplos).
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-detached">
+            <title>Objetos destacados e versionamento automático</title>
+
+            <para>
+                Cada interação com o armazenamento persistente ocorre em uma <literal>Session</literal> nova. 
+                Entretanto, as mesmas instâncias persistentes são reusadas para cada interação com o banco de dados. 
+                A aplicação manipula o estado das instâncias desatachadas originalmente carregadas em um outro 
+                <literal>Session</literal> e reata-os então usando <literal>Session.update()</literal>, 
+                <literal>Session.saveOrUpdate()</literal> ou <literal>Session.merge()</literal>.
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+foo.setProperty("bar");
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded already
+t.commit();
+session.close();]]></programlisting>
+
+            <para>
+                Outra vez, o Hibernate verificará versões da instância durante o flush, 
+                lançando uma exceção se ocorrer conflitos de atualizações.
+            </para>
+
+            <para>
+                Você pode também chamar o <literal>lock()</literal> em vez de <literal>update()</literal> 
+                e usar <literal>LockMode.READ</literal> (executando uma checagem de versão, ignorando 
+                todos os caches) se você estiver certo de que o objeto não foi modificado.
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-customizing">
+            <title>Versionamento automático customizado</title>
+
+            <para>
+                Você pode desabilitar o incremento da versão automática de Hibernate para propriedades 
+                e coleções particulares configurando o mapeamento do atributo <literal>optimistic-lock</literal>
+                para false. O Hibernate então não irá incrementa versões se a propriedade estiver
+                modificada.
+            </para>
+
+            <para>
+                Os esquemas da base de dados legada são freqüentemente estáticos e não podem ser modificados. 
+                Ou outras aplicações puderam também acessar a mesma base de dados e não sabem tratar a 
+                versão dos números ou timestamps. Em ambos os casos, o versionamento não pode confiar em uma 
+                coluna particular em uma tabela. Para forçar uma checagem de versão sem uma versão ou mapeamento
+                da propriedade do timestamp com uma comparação do estado de todos os campos em uma linha, 
+                configure <literal>optimistic-lock="all"</literal> no mapeamento <literal>&lt;class&gt;</literal>. 
+                Note que isto conceitualmente é somente feito em trabalhos se Hibernate puder comparar o estado 
+                velho e novo, isto é, se você usa um único  <literal>Session</literal> longo e não 
+                session-per-request-with-detached-objects.
+            </para>
+
+            <para>
+                Às vezes a modificação concorrente pode ser permitida tão longa quanto às mudanças que 
+                tiveram sido feitas que não sobrepuseram. Se você configurar <literal>optimistic-lock="dirty"</literal>
+                ao mapear o <literal>&lt;class&gt;</literal>, o Hibernate comparará somente campos 
+                modificados durante o flush.
+            </para>
+
+            <para>
+                Em ambos os casos, com as colunas dedicadas da versão/timestamp ou com comparação do 
+                campo cheio/modificados, o Hibernate usa uma única declaração UPDATE (com uma cláusula 
+                WHERE apropriada ) por entidade para executar a checagem da versão e atualizar a informação. 
+                Se você usa a persistência transitiva para cascatear o reatamento das entidades associadas, 
+                o Hibernate pode executar atualizações desnecessárias. Isso não é geralmente um problema, 
+                mas triggers <emphasis>on update</emphasis> em um banco de dados podem ser executados 
+                mesmo quando nenhuma mudança foi feita nas instâncias destacadas. Você pode customizar 
+                este comportamento configurando <literal>select-before-update="true"</literal> no 
+                mapeamento  <literal>&lt;class&gt;</literal>, forçando o Hibernate a dá um SELECT nas 
+                instâncias para assegurar-se esse as mudanças ocorreram realmente, antes de atualizar 
+                a linha.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="transactions-locking">
+        <title>Locking pessimista</title>
+
+        <para>
+            Não se pretende que os usuários gastam muitas horas se preocupando com suas estratégias de 
+            locking. Geralmente é o bastante para especificar um nível de isolamento para as conexões 
+            JDBC e então deixar simplesmente o banco de dados fazer todo o trabalho. Entretanto, os 
+            usuários avançados podem às vezes desejar obter locks pessimistas exclusivos, ou re-obter 
+            locks no início de uma nova transação. 
+        </para>
+
+        <para>
+            O Hibernate usará sempre o mecanismo de lock da base de dados, nunca trava objetos 
+            na memória!
+        </para>
+
+        <para>
+            A classe <literal>LockMode</literal> define os diferentes níveis de lock que o Hibernate 
+            pode adquirir. Um lock é obtido pelos seguintes mecanismos:
+
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>LockMode.WRITE</literal> é adquirido automaticamente quando o Hibernate atualiza 
+                    ou insere uma linha.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.UPGRADE</literal> pode ser adquirido explicitamente pelo usuário 
+                    usando <literal>SELECT ... FOR UPDATE</literal> em um banco de dados que suporte 
+                    esse sintaxe.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.UPGRADE_NOWAIT</literal> pode ser adquirido explicitamente pelo usuário 
+                    usando <literal>SELECT ... FOR UPDATE NOWAIT</literal> no Oracle.
+
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>LockMode.READ</literal> é adquirido automaticamente quando o Hibernate lê 
+                    dados em um nível Repeatable Read ou Serializable isolation. Pode ser readquirido 
+                    explicitamente pelo usuário.
+                </para>
+            </listitem>
+        <listitem>
+        <para>
+            <literal>LockMode.NONE</literal> representa a ausência do lock. Todos os objetos mudam para 
+            esse estado de lock no final da  <literal>Transaction</literal>. Objetos associados com a sessão 
+            através do método <literal>update()</literal> ou <literal>saveOrUpdate()</literal> também são
+             inicializados com esse lock mode.
+        </para>
+        </listitem>
+        </itemizedlist>
+
+        <para>
+            O lock obtido "explicitamente pelo usuário" se dá em uma das seguintes maneiras:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    Uma chamada a <literal>Session.load()</literal>, especificando 
+                    o <literal>LockMode</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Uma chamada a <literal>Session.lock()</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                   Uma chamada a  <literal>Query.setLockMode()</literal>.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Se uma <literal>Session.load()</literal> é invocada com <literal>UPGRADE</literal> ou
+            <literal>UPGRADE_NOWAIT</literal>, e o objeto requisitado ainda não foi carregado 
+            pela sessão, o objeto é carregado usando <literal>SELECT ... FOR UPDATE</literal>. 
+            Se <literal>load()</literal> for chamado para um objeto que já foi carregado 
+            com um lock menos restritivo que o novo lock solicitado, o Hibernate invoca o 
+            método <literal>lock()</literal> para aquele objeto.
+        </para>
+
+        <para>
+            O método  <literal>Session.lock()</literal> executa uma verificação no número da versão 
+            se o modo de lock especificado for <literal>READ</literal>, <literal>UPGRADE</literal> ou
+            <literal>UPGRADE_NOWAIT</literal>.. (No caso do <literal>UPGRADE</literal> ou
+            <literal>UPGRADE_NOWAIT</literal>, é usado <literal>SELECT ... FOR UPDATE</literal>.)
+        </para>
+
+        <para>
+            Se o banco de dados não suportar o lock mode solicitado, o Hibernate vai usar um modo 
+            alternativo apropriado (ao invés de lançar uma exceção). Isso garante que a aplicação 
+            vai ser portável.
+        </para>
+
+    </sect1>
+
+    <sect1 id="transactions-connection-release">
+        <title>Modos de liberar a Connection</title>
+
+        <para>
+            O comportamento legado do Hibernate (2.x) em consideração ao gerenciamento da conexão 
+            via JDBC fez com que a <literal>Session</literal> precisasse obter uma conexão 
+            quando ela precisasse pela primeira vez e depois manter a conexão enquanto 
+            a sessão não fosse fechada. O Hibernate 3.x introduz a idéia de modos de liberar a 
+            sessão, para informar a sessão a forma como deve manusear a sua conexão JDBC. 
+            Veja que essa discussão só é pertinente para conexões fornecidas com um 
+            <literal>ConnectionProvider</literal> configurado; conexões fornecidas pelo usuário 
+            estão fora do escopo dessa discussão. Os diferentes modos de liberação estão definidos 
+            pelos valores da enumeração 
+            <literal>org.hibernate.ConnectionReleaseMode</literal>:
+           
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>ON_CLOSE</literal> - essencialmente é o modo legado descrito acima. A sessão 
+                    do Hibernate obtêm a conexão quando precisar executar alguma operação JDBC pela 
+                    primeira vez e mantem enquanto a conexão não for fechada.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>AFTER_TRANSACTION</literal> – informa que a conexão deve ser 
+                    liberada após a conclusão de uma <literal>org.hibernate.Transaction</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>AFTER_STATEMENT</literal> (também conhecida com liberação agressiva) – informa 
+                    que a conexão deve ser liberada após a execução de cada statement. A liberação agressiva 
+                    não ocorre se o statement deixa pra trás algum recurso aberto associado com a sessão 
+                    obtida; atualmente, a única situação em que isso é possível é com o uso de 
+                    <literal>org.hibernate.ScrollableResults</literal>.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            O parâmetro de configuração <literal>hibernate.connection.release_mode</literal> é usado 
+            para especificar qual modo de liberação deve ser usado. Opções disponíveis:            
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>auto</literal>  (padrão) – essa opção delega ao modo de liberação retornado pelo 
+                    método <literal>org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode()</literal>. 
+                    Para JTATransactionFactory, ele retorna ConnectionReleaseMode.AFTER_STATEMENT; para 
+                    JDBCTransactionFactory, ele retorna ConnectionReleaseMode.AFTER_TRANSACTION. 
+                    Raramente é uma boa idéia alterar padrão, como frequencia ao se fazer isso temos falhas 
+                    que parecem bugs e/ou suposições inválidas no código do usuário.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>on_close</literal> - indica o uso da ConnectionReleaseMode.ON_CLOSE. Essa opção 
+                    foi deixada para manter a compatibilidade, mas seu uso é fortemente desencorajado.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>after_transaction</literal> – indica o uso da ConnectionReleaseMode.AFTER_TRANSACTION. 
+                    Essa opção nada deve ser usada com ambientes JTA. Também note que no caso da 
+                    ConnectionReleaseMode.AFTER_TRANSACTION, se a sessão foi colocada no modo auto-commit a 
+                    conexão vai ser liberada de forma similar ao modo AFTER_STATEMENT.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>after_statement</literal> – indica o uso ConnectionReleaseMode.AFTER_STATEMENT. 
+                    Adicionalmente, o  <literal>ConnectionProvider</literal> configurado é consultado para 
+                    verificar se suporta essa configuração ((<literal>supportsAggressiveRelease()</literal>). 
+                    Se não suportar, o modo de liberação é redefinido como ConnectionRelease-Mode.AFTER_TRANSACTION. 
+                    Essa configuração só é segura em ambientes onde podemos readquirir a mesma conexão JDBC 
+                    toda vez que o método <literal>ConnectionProvider.getConnection()</literal>  for chamado ou 
+                    em um ambiente auto-commit onde não importa se nós recuperamos a mesma conexão. 
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect1>
+
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/transactions.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/tutorial.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/tutorial.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/tutorial.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1530 @@
+<chapter id="tutorial">
+    <title>Introdu&#x00E7;&#x00E3;o ao Hibernate</title>
+    
+    <sect1 id="tutorial-intro" revision="1">
+        <title>Prefácio</title>
+        
+        <para>
+            Este cap&#x00ED;tulo &#x00E9; um tutorial introdut&#x00F3;rio para novos usuários do Hibernate. N&#x00F3;s iniciaremos com uma simples linha de comando em uma aplica&#x00E7;&#x00E3;o usando uma base de dados em mem&#x00F3;ria tornando isto um passo de fácil de compreender.
+        </para>
+
+        <para>
+            Este tutorial &#x00E9; voltado para novos usuários do Hibernate, mas requer um conhecimento de Java e SQL. Este tutorial &#x00E9; baseado no tutorial de Michael Gloegl, as bibliotecas Third Party foram nomeadas para JDK 1.4 e 5.0. Você pode precisar de outras bibliotecas para JDK 1.3.
+        </para>
+
+        <para>
+            O código fonte para o tutorial está incluído no diretório da distribuição 
+            <literal>doc/reference/tutorial/</literal>. 
+        </para>
+
+    </sect1>
+    
+    <sect1 id="tutorial-firstapp" revision="2">
+        <title>Parte 1 – A primeira aplicação Hibernate</title>
+
+        <para>
+            Primeiro, iremos criar uma simples aplica&#x00E7;&#x00E3;o Hibernate baseada em console. Usaremos uma base de dados Java (HSQL DB), ent&#x00E3;o n&#x00E3;o teremos que instalar nenhum servidor de base de dados.
+        </para>
+
+        <para>
+            Vamos supor que precisemos de uma aplica&#x00E7;&#x00E3;o com um banco de dados pequeno que possa armazenar e atender os eventos que queremos, e as informa&#x00E7;&#x00E7;es sobre os hosts destes eventos. 
+        </para>
+            
+        <para>
+            A primeira coisa que devemos fazer &#x00E9; configurar nosso diret&#x00F3;rio de desenvolvimento, 
+            e colocar todas as bibliotecas Java que precisamos dentro dele. Fa&#x00E7;a o download da 
+            distribui&#x00E7;&#x00E3;o do Hibernate no site do Hibernate. Descompacte o pacote e coloque todas 
+            as bibliotecas necessárias encontradas no diret&#x00F3;rio <literal>/lib</literal>, dentro do 
+            diret&#x00F3;rio <literal>/lib</literal> do seu novo projeto. Você deverá ter algo parecido
+            com isso:
+        </para>
+            
+        <programlisting><![CDATA[.
++lib
+  antlr.jar
+  cglib.jar
+  asm.jar
+  asm-attrs.jars
+  commons-collections.jar
+  commons-logging.jar
+  hibernate3.jar
+  jta.jar
+  dom4j.jar
+  log4j.jar ]]></programlisting>
+
+        <para>
+            Esta &#x00E9; a configura&#x00E7;&#x00E3;o m&#x00ED;nima requerida das bibliotecas (observe que tamb&#x00E9;m foi copiado 
+            o hibernate3.jar da pasta principal do Hibernate) para o Hibernate <emphasis>na hora do desenvolvimento</emphasis>. O Hibernate permite que você utilize mais ou menos bibliotecas. 
+            Veja o arquivo <literal>README.txt</literal>  no diret&#x00F3;rio <literal>lib/</literal> da distribui&#x00E7;&#x00E3;o 
+            do Hibernate para maiores informa&#x00E7;&#x00E7;es sobre bibliotecas requeridas e opcionais. 
+            (Atualmente, a biblioteca Log4j n&#x00E3;o &#x00E9; requerida, mas &#x00E9; preferida por muitos desenvolvedores.)
+        </para>
+
+        <para>
+            Agora, iremos criar uma classe que representa o evento que queremos armazenar na base de dados..
+        </para>
+      
+        <sect2 id="tutorial-firstapp-firstclass" revision="1">
+            <title>A primeira Classe</title>
+            
+            <para>
+                Nossa primeira classe de persistência é uma simples classe JavaBean com algumas propriedades:
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+import java.util.Date;
+
+public class Event {
+    private Long id;
+
+    private String title;
+    private Date date;
+
+    public Event() {}
+
+    public Long getId() {
+        return id;
+    }
+
+    private void setId(Long id) {
+        this.id = id;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+}]]></programlisting>
+
+            <para>
+                Você pode ver que esta classe usa o padrão JavaBean para o nomeamento convencional da propriedade getter e dos métodos setter, como também a visibilidade private dos campos. Este é um padrão de projeto recomendado, mas não requerido. O Hibernate pode também acessar campos diretamente, o benefício para os métodos de acesso é a robustez para o Refactoring. O construtor sem argumento é requerido para instanciar um objeto desta classe com a reflexão.
+            </para>
+
+            <para>
+                A propriedade  <literal>id</literal> mantém um único valor de identificação para um evento 
+                particular. Todas as classes persistentes da entidade (bem como aquelas classes dependentes 
+                de menos importância) precisam de uma propriedade de identificação, caso nós queiramos usar o 
+                conjunto completo de características do Hibernate. De fato, a maioria das aplicações 
+                (esp. aplicações web)  precisam destinguir os objetos pelo identificador, então você deverá 
+                considerar esta, uma característica em lugar de uma limitação. Porém, nós normalmente não 
+                manipulamos a identidade de um objeto, consequentemente o método setter deverá ser privado. 
+                O Hibernate somente nomeará os identificadores quando um objeto for salvo. Você pode ver como 
+                o Hibernate pode acessar métodos públicos, privados, e protegidos, como também campos 
+                (públicos, privados, protegidos) diretamente. A escolha está até você, e você pode combinar 
+                isso para adaptar seu projeto de aplicação
+            </para>
+
+            <para>
+                O construtor sem argumentos é um requerimento para todas as classes persistentes; 
+                O Hibernate tem que criar para você os objetos usando Java Reflection.  O construtor 
+                pode ser privado, porém, a visibilidade do pacote é requerida para a procuração da 
+                geração em tempo de execução e recuperação eficiente dos dados sem a instrumentação 
+                de bytecode 
+            </para>
+
+            <para>
+                Coloque este fonte Java no diretório chamado <literal>src</literal> na pasta de desenvolvimento, 
+                e em seu pacote correto. O diretório deverá ser parecido como este:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java]]></programlisting>
+
+            <para>
+                No próximo passo, iremos falar sobre as classes de persistência do Hibernate..
+            </para>
+                
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-mapping" revision="1">
+            <title>O mapeamento do arquivo</title>
+
+            <para>
+                O Hibernate precisa saber como carregar e armazenar objetos da classe de 
+                persistência. Isto será onde o mapeamento do arquivo do Hibernate entrará em 
+                jogo. O arquivo mapeado informa ao Hibernate, qual tabela no banco de dados 
+                ele deverá acessar, e quais as colunas na tabela ele deverá usar.
+            </para>
+
+            <para>
+                A estrutura básica de um arquivo de mapeamento é parecida com:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+[...]
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Note que o Hibernate DTD é muito sofisticado. Você pode usar isso para auto-conclusão 
+                no mapeamento XML dos elementos e atributos no seu editor ou IDE. Você também pode 
+                abrir o arquivo DTD no seu editor – é a maneira mais fácil de ter uma visão geral 
+                de todos os elementos e atributos e dos padrões, como também alguns comentários. 
+                Note que o Hibernate não irá carregar o arquivo DTD da web, e sim do diretório 
+                da aplicação (classpath). O arquivo DTD está incluído no  <literal>hibernate3.jar</literal> como 
+                também no diretório <literal>src/</literal> da distribuição do Hibernate. 
+            </para>
+
+            <para>
+                Nós omitiremos a declaração do DTD nos exemplos futuros para encurtar o código. Isto, é claro, não é opcional.
+            </para>
+
+            <para>
+                Entre os dois tags <literal>hibernate-mapping</literal>, inclua um elemento <literal>class</literal>. 
+                Todas as classes persistentes da entidade (novamente, poderá haver 
+                mais tarde, dependências sobre as classes que não são classes-primárias 
+                de entidades) necessitam do tal mapeamento, para uma tabela na base 
+                de dados SQL
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Mais adiante iremos dizer ao Hibernate como fazer para persistir e carregar objetos da classe 
+                <literal>Event</literal> da tabela <literal>EVENTS</literal>, cada instancia representada por 
+                uma coluna na tabela. Agora, continuaremos com o mapeamento de uma única propriedade identificadora 
+                para as chaves primárias da tabela. Além disso, nós não iremos se importar com esta propriedade 
+                identificadora, nós iremos configurar uma estratégia de geração de id’s para uma chave primária 
+                de uma surrogate key: 
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="native"/>
+        </id>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                O elemento <literal>id</literal> é a declaração da propriedade identificadora, 
+                o <literal>name="id"</literal> declara o nome da propriedade Java – 
+                o Hibernate irá usar os métodos getter e setter para acessar a propriedade.
+                O atributo da coluna informa ao Hibernate qual coluna da tabela  <literal>EVENTS</literal> nós 
+                iremos usar como chave primária. O elemento <literal>generator</literal> especifica 
+                a estratégia de geração do identificador, neste caso usaremos <literal>native</literal>, que 
+                escolhe a melhor estratégia dependendo da base de dados (dialeto) configurada. 
+                O Hibernate suporta a base de dados gerada, globalmente única, bem como a atribuição 
+                aos identificadores da aplicação (ou toda estratégia escrita para uma extensão).
+            </para>
+
+            <para>
+                Finalmente incluiremos as declarações para as propriedades persistentes da classe 
+                no arquivo mapeado. Por default, nenhuma das propriedades da classe é considerada persistente:
+            </para>
+            
+            <programlisting><![CDATA[
+<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="native"/>
+        </id>
+        <property name="date" type="timestamp" column="EVENT_DATE"/>
+        <property name="title"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+            
+            <para>
+                Da mesma maneira que com o elemento  <literal>id</literal>, o atributo <literal>name</literal> do elemento 
+                <literal>property</literal> informa ao Hibernate qual método getter e setter deverá usar. 
+                Assim, neste caso, o Hibernate irá procurar pelo <literal>getDate()/setDate()</literal>, 
+                como também pelo <literal>getTitle()/setTitle()</literal>.
+            </para>
+
+            <para>
+                Porque fazer o mapeamento da propriedade  <literal>date</literal> incluído no 
+                atributo <literal>column</literal>, e no title não fazer? 
+                Sem o atributo <literal>column</literal> o Hibernate por padrão usa o nome 
+                da propriedade como o nome da coluna. Isto trabalha muito 
+                bem para o  <literal>title</literal>. Entretanto o <literal>date</literal> é uma palavra-chave reservada 
+                na maioria dos bancos de dados, assim nós melhoramos o mapeamentos 
+                disto com um nome diferente.
+            </para>
+
+            <para>
+                A próxima coisa interessante é que mapemanto do <literal>title</literal> 
+                também falta o atributo <literal>type</literal>. O tipo que declaramos e o uso nos 
+                arquivos mapeados, não são como você pôde esperar, atributos de dados Java. 
+                Eles não são como os tipos de base de dados SQL. 
+                Esses tipos podem ser chamados de <emphasis>Tipos de mapeamento Hibernate</emphasis>, que são conversores 
+                que podem traduzir tipos de dados do Java para os tipos de dados SQL e vice-versa. 
+                Novamente, o Hibernate irá tentar determinar a conversão correta e mapeará o <literal>type</literal> 
+                próprio, caso o tipo do atributo não estiver presente no mapeamento. 
+                Em alguns casos, esta detecção automática (que usa Reflection sobre as classes Java) 
+                poderá não ter padrão que você espera ou necessita. 
+                Este é o caso com a propriedade <literal>date</literal>. O Hibernate não pode saber se a propriedade 
+                (que é do <literal>java.util.Date</literal>) pode mapear para uma coluna do tipo <literal>date</literal> 
+                do SQL, <literal>timestamp</literal>, ou <literal>time</literal> . 
+                Nós preservamos a informação cheia de datas e horas pelo mapeamento da propriedade com um conversor 
+                 <literal>timestamp</literal>.
+            </para>
+
+            <para>
+                Este arquivo de mapeamento deve ser salvo como <literal>Event.hbm.xml</literal>, 
+                corretamente no diretório próximo ao arquivo fonte da Classe Java <literal>Event</literal>. 
+                O nomeamento dos arquivos de mapeamento podem ser arbitrários, porém o sufixo 
+                <literal>hbm.xml</literal> é uma convenção da comunidade dos desenvolvedores do Hibernate. 
+                Esta estrutura do diretório deve agora se parecer com isso:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java
+    Event.hbm.xml]]></programlisting>
+
+             <para>
+                 Nós iremos continuar com a configuração principal do Hibernate.
+             </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-configuration" revision="2">
+            <title>Configuração do Hibernate</title>
+
+            <para>
+                Agora nós temos uma classe persistente e este arquivo de mapeamento no lugar. 
+                Está na hora de configurar o Hibernate. Antes de fazermos isso, iremos precisar de uma base de dados. 
+                O HSQL DB, um SQL DBMS feito em java, pode ser baixado através do site do HSQL DB. 
+                Atualmente, você só precisa baixar o <literal>hsqldb.jar</literal>. 
+                Coloque este arquivo no diretório da pasta de desenvolvimento <literal>lib/</literal>.
+            </para>
+
+            <para>
+                Crie um diretório chamado  <literal>data</literal> no diretório root de desenvolvimento – 
+                Isto será onde o HSQL DB irá armazenar arquivos de dados. Agora iremos iniciar o banco de dados 
+                executando  <literal>java -classpath ../lib/hsqldb.jar org.hsqldb.Server</literal> neste diretório de dados. 
+                Você pode ver ele iniciando e conectando ao socket TCP/IP, isto será onde nossa aplicação irá se 
+                conectar depois. Se você deseja iniciar uma nova base de dados durante este tutorial, 
+                finalize o HSQL DB(pressionando o <literal>CTRL + C</literal> na janela), delete todos os 
+                arquivos no diretório <literal>data/</literal>, e inicie o HSQL BD novamente.
+            </para>
+
+            <para>
+                O Hibernate é uma camada na sua aplicação na qual se conecta com a base de dados, para isso
+                necessita de informação da conexão. As conexões são feitas através de um pool de conexão JDBC, 
+                na qual teremos que configurar. A distribuição do Hibernate contém diversas ferramentas de pooling 
+                da conexão JDBC de fonte aberta, mas iremos usar o pool de conexão interna para este tutorial. 
+                Note que você tem que copiar a biblioteca necessária em seu classpath e use configurações 
+                diferentes para pooling de conexão caso você deseje utilizar um software de pooling JDBC terceirizado 
+                para qualidade de produção.
+            </para>
+
+            <para>
+                Para as configurações do Hibernate, nós podemos usar um arquivo simples <literal>hibernate.properties</literal>, 
+                um arquivo mais ligeiramente sofisticado <literal>hibernate.cfg.xml</literal> ou até mesmo uma 
+                instalação programática completa. A maioria dos usuários preferem utilizar o arquivo de configuração XML
+            </para>
+
+            <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <session-factory>
+
+        <!-- Database connection settings -->
+        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
+        <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
+        <property name="connection.username">sa</property>
+        <property name="connection.password"></property>
+
+        <!-- JDBC connection pool (use the built-in) -->
+        <property name="connection.pool_size">1</property>
+
+        <!-- SQL dialect -->
+        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
+
+        <!-- Enable Hibernate's automatic session context management -->
+        <property name="current_session_context_class">thread</property>
+
+        <!-- Disable the second-level cache  -->
+        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
+
+        <!-- Echo all executed SQL to stdout -->
+        <property name="show_sql">true</property>
+
+        <!-- Drop and re-create the database schema on startup -->
+        <property name="hbm2ddl.auto">create</property>
+
+        <mapping resource="events/Event.hbm.xml"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+            <para>
+                Note que esta configuração XML usa um diferente DTD. Nós configuraremos 
+                as <literal>SessionFactory</literal> do Hibernate – uma factory global responsável 
+                por uma base de dedados particular. Se você tiver diversas bases de dados, 
+                use diversas configurações <literal>&lt;session-factory&gt;</literal>, geralmente 
+                em diversos arquivos de configuração (para uma partida mais fácil). 
+            </para>
+
+            <para>
+                As primeiras quatro <literal>propriedades</literal> do elemento contém a configuração 
+                necessária para a conexão ao JDBC. A propriedade <literal>propriedade</literal> dialect 
+                do elemento especifica a variante particular do SQL que o Hibernate gera. 
+                O gerenciamento automático de sessão do Hibernate para contextos de persistência 
+                estará disponível em breve. A opção <literal>hbm2ddl.auto</literal> habilita a geração 
+                automática de schemas da base de dados – diretamente na base de dados. 
+                Isto também pode ser naturalmente desligado (removendo a opção de configuração) ou redirecionando
+                para um arquivo com ajuda do <literal>SchemaExport</literal> nas tarefas do Ant. 
+                Finalmente, iremos adicionar os arquivos das classes de persistência mapeadas na configuração.
+            </para>
+
+            <para>
+                Copie este arquivo no diretório fonte, assim isto irá terminar na raiz (root) do 
+                classpath. O Hibernate automaticamente procura por um arquivo chamado 
+                <literal>hibernate.cfg.xml</literal> na raiz do classpath, no startup.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-ant" revision="1">
+            <title>Construindo com o Ant</title>
+
+            <para>
+                Nos iremos, agora, construir o tutorial com Ant. Você ira precisar o Ant instalado – 
+                se encontra disponível  <ulink url="http://ant.apache.org/bindownload.cgi">na página de download do Ant</ulink>. 
+                Como instalar o Ant, não será abordado aqui. Caso tenha alguma dúvida, por favor, 
+                vá ao <ulink url="http://ant.apache.org/manual/index.html">Ant manual</ulink>.
+                Depois que tiver instalado o Ant, podemos começar a criar o arquivo de construção <literal>build.xml</literal>. 
+                Este arquivo será chamado de <literal>build.xml</literal> e posto diretamente no diretório de desenvolvimento.
+            </para>
+
+            <para>
+                Um arquivo básico de build, se parece com isto:
+            </para>
+
+            <programlisting><![CDATA[<project name="hibernate-tutorial" default="compile">
+
+    <property name="sourcedir" value="${basedir}/src"/>
+    <property name="targetdir" value="${basedir}/bin"/>
+    <property name="librarydir" value="${basedir}/lib"/>
+
+    <path id="libraries">
+        <fileset dir="${librarydir}">
+            <include name="*.jar"/>
+        </fileset>
+    </path>
+
+    <target name="clean">
+        <delete dir="${targetdir}"/>
+        <mkdir dir="${targetdir}"/>
+    </target>
+
+    <target name="compile" depends="clean, copy-resources">
+      <javac srcdir="${sourcedir}"
+             destdir="${targetdir}"
+             classpathref="libraries"/>
+    </target>
+
+    <target name="copy-resources">
+        <copy todir="${targetdir}">
+            <fileset dir="${sourcedir}">
+                <exclude name="**/*.java"/>
+            </fileset>
+        </copy>
+    </target>
+
+</project>]]></programlisting>
+
+            <para>
+                Isto irá avisar ao Ant para adicionar todos os arquivos no diretório lib terminando com 
+                <literal>.jar</literal>, para o classpath usado para compilação. Irá também copiar todos os 
+                arquivos não-java para o diretório alvo (arquivos de configuração, mapeamento). Se você rodar 
+                o ant agora, deverá ter esta saída.              
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant
+Buildfile: build.xml
+
+copy-resources:
+     [copy] Copying 2 files to C:\hibernateTutorial\bin
+
+compile:
+    [javac] Compiling 1 source file to C:\hibernateTutorial\bin
+
+BUILD SUCCESSFUL
+Total time: 1 second ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-helpers" revision="3">
+            <title>Startup and helpers</title>
+
+            <para>
+                É hora de carregar e arquivar alguns objetos <literal>Event</literal>, mas primeiro 
+                nós temos de completar o setup com algum código de infraestrutura. Este startup 
+                inclui a construção de um objeto  <literal>SessionFactory</literal>  global e  armazenar
+                isto em algum lugar de fácil acesso para o código da aplicação.
+                Uma <literal>SessionFactory</literal> pode abrir novas <literal>Session</literal>'s. 
+                Uma <literal>Session</literal> representa uma unidade single-theaded do trabalho, a 
+                <literal>SessionFactory</literal> é um objeto global thread-safe, instanciado uma vez.
+            </para>
+
+            <para>
+                Nos iremos criar uma classe de ajuda <literal>HibernateUtil</literal>, que toma 
+                conta do startup e faz acesso a uma <literal>SessionFactory</literal> conveniente. 
+                Vamos dar uma olhada na implementação:
+            </para>
+
+            <programlisting><![CDATA[package util;
+
+import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+    private static final SessionFactory sessionFactory;
+
+    static {
+        try {
+            // Create the SessionFactory from hibernate.cfg.xml
+            sessionFactory = new Configuration().configure().buildSessionFactory();
+        } catch (Throwable ex) {
+            // Make sure you log the exception, as it might be swallowed
+            System.err.println("Initial SessionFactory creation failed." + ex);
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    public static SessionFactory getSessionFactory() {
+        return sessionFactory;
+    }
+
+}]]></programlisting>
+
+            <para>
+                Esta classe não só produz a global <literal>SessionFactory</literal> no seu static initializer
+                (chamado uma vez pela JVM quando a classe é carregada), mas também esconde o fato 
+                de que isto usa um static singleton. Ela pode muito bem, enxergar a 
+                <literal>SessionFactory</literal> do JNDI em um application server.
+            </para>
+
+            <para>
+                Se você der à <literal>SessionFactory</literal> um nome, no seu arquivo de configuração. 
+                O Hibernate irá, de fato, tentar uni-lo ao JNDI depois que estiver construído. 
+                Para evitar este completamente este código, você também poderia usar JMX deployment 
+                e deixar o contêiner JMX capaz, instanciar e unir um <literal>HibernateService</literal> 
+                no JNDI. Essas opções avançadas são discutidas no documento de referência do Hibernate.
+            </para>
+
+            <para>
+                Coloque o <literal>HibernateUtil.java</literal> no diretório de arquivos 
+                de desenvolvimento(source), em um pacote após o <literal>events</literal>:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java
+    Event.hbm.xml
+  +util
+    HibernateUtil.java
+  hibernate.cfg.xml
++data
+build.xml]]></programlisting>
+
+            <para>
+                Novamente, isto deve compilar sem problemas. Finalmente, nós precisamos configurar 
+                um sistema de logging – o Hibernate usa commons logging e deixa você escolher entre o 
+                Log4j e o logging do JDK 1.4 . A maioria dos desenvolvedores preferem o Log4j: copie 
+                <literal>log4j.properties</literal> da distribuição do Hibernate (está no diretório 
+                <literal>etc/</literal>), para seu diretório  <literal>src</literal>, 
+                depois vá em hibernate.cfg.xml. Dê uma olhada no exemplo de configuração e mude as
+                configurações se você quizer ter uma saída mais detalhada. Por default, apenas as
+                mensagems de startup  e shwwn do Hibernate é mostrada no stdout.
+            </para>
+
+            <para>
+                O tutorial de infra-estrutura está completo - e nós já estamos preparados para algum 
+                trabalho de verdade com o Hibernate.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-workingpersistence" revision="4">
+            <title>Carregando e salvando objetos</title>
+
+            <para>
+                Finalmente, nós podemos usar o Hibernate para carregar e armazenar objetos. 
+                Nós escrevemos uma classe <literal>EventManager</literal> com um método main():
+            </para>
+
+            <programlisting><![CDATA[package events;
+import org.hibernate.Session;
+
+import java.util.Date;
+
+import util.HibernateUtil;
+
+public class EventManager {
+
+    public static void main(String[] args) {
+        EventManager mgr = new EventManager();
+
+        if (args[0].equals("store")) {
+            mgr.createAndStoreEvent("My Event", new Date());
+        }
+
+        HibernateUtil.getSessionFactory().close();
+    }
+
+    private void createAndStoreEvent(String title, Date theDate) {
+
+        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+        session.beginTransaction();
+
+        Event theEvent = new Event();
+        theEvent.setTitle(title);
+        theEvent.setDate(theDate);
+
+        session.save(theEvent);
+
+        session.getTransaction().commit();
+    }
+
+}]]></programlisting>
+
+            <para>
+                Nós criamos um novo objeto <literal>Event</literal>, e passamos para o Hibernate. 
+                O Hibernate sabe como tomar conta do SQL e executa <literal>INSERT</literal>s 
+                no banco de dados. Vamos dar uma olhada na <literal>Session</literal> e no 
+                código <literal>Transaction</literal>-handling antes de executarmos.
+            </para>
+
+            <para>
+                Um <literal>Session</literal> é uma unidade simples de trabalho. Por agora nós 
+                iremos pegar coisas simples e assumir uma granularidade de um-pra-um entre uma 
+                <literal>Session</literal> do Hibernate e uma transação de banco de dados. 
+                Para proteger nosso código de um atual sistema subjacente de transação (nesse 
+                caso puro JDBC, mas também poderia rodar com JTA), nos usamos a API 
+                <literal>Transaction</literal>, que está disponível na <literal>Session</literal> do Hibernate.
+            </para>
+
+            <para>
+                O que a <literal>sessionFactory.getCurrentSession()</literal> faz? Primeiro, você pode 
+                chamar quantas vezes e de onde quiser, uma vez você recebe sua <literal>SessionFactory</literal>
+                (fácil graças ao <literal>HibernateUtil</literal>). O método <literal>getCurrentSession()</literal>
+                sempre retorna a unidade de trabalho "corrente". Lembra de que nós mudamos a opção 
+                de configuração desse mecanismo para thread no <literal>hibernate.cfg.xml</literal>? Daqui em
+                diante, o escopo da unidade de trabalho corrente é a thread Java 
+                corrente que executa nossa aplicação. Entretanto, esta não é toda a verdade. Uma 
+                <literal>Session</literal> começa quando é primeiramente necessária, quando é feita a 
+                primeira chamada à <literal>getCurrentSession()</literal>. É então limitado pelo Hibernate 
+                para thread corrente. Quando a transação termina, tanto com commit quanto rollback, 
+                o Hibernate também desune a <literal>Session</literal> da thread e fecha isso pra você. 
+                Se você chamar <literal>getCurrentSession()</literal> novamente, você receberá uma nova 
+                <literal>Session</literal> e pode começar uma nova unidade de trabalho. Esse modelo de 
+                programação de limite de thread  <emphasis>thread-bound</emphasis>, é o modo mais popular 
+                de se usar o Hibernate.
+           </para>
+
+            <para>
+               Dê uma olhada no <xref linkend="transactions"/>  para mais informações a 
+               respeito de manipulação de transação e demarcação. Nós também pulamos qualquer 
+               manipulação de erro e rollback no exemplo anterior.
+            </para>
+
+            <para>
+               Para executar esta primeira rotina, nos teremos que adicionar um ponto de chamada 
+               para o arquivo de build do Ant:
+            </para>
+
+            <programlisting><![CDATA[<target name="run" depends="compile">
+    <java fork="true" classname="events.EventManager" classpathref="libraries">
+        <classpath path="${targetdir}"/>
+        <arg value="${action}"/>
+    </java>
+</target>]]></programlisting>
+
+            <para>
+                O valor do argumento <literal>action</literal>, é setado na linha de comando quando chamando esse ponto:
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant run -Daction=store]]></programlisting>
+
+            <para>
+                Você deverá ver, após a compilação, o startup do Hibernate e, dependendo da sua 
+                configuração, muito log de saída. No final você verá a seguinte linha:
+            </para>
+
+            <programlisting><![CDATA[[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)]]></programlisting>
+
+            <para>
+                Este é o <literal>INSERT</literal> executado pelo Hibernate, os pontos de interrogação 
+                representam parêmetros de união do JDBC. Para ver os valores substituídos, ou para diminuir a 
+                verbalidade do log, check seu l<literal>log4j.properties</literal>.
+            </para>
+
+            <para>
+              Agora nós gostaríamos de listar os eventos arquivados, então nós adicionamos uma 
+              opção para o método main:
+            </para>
+
+            <programlisting><![CDATA[if (args[0].equals("store")) {
+    mgr.createAndStoreEvent("My Event", new Date());
+}
+else if (args[0].equals("list")) {
+    List events = mgr.listEvents();
+    for (int i = 0; i < events.size(); i++) {
+        Event theEvent = (Event) events.get(i);
+        System.out.println("Event: " + theEvent.getTitle() +
+                           " Time: " + theEvent.getDate());
+    }
+}]]></programlisting>
+
+            <para>
+                Nos também adicionamos um novo <literal>método listEvents()</literal>:
+            </para>
+
+            <programlisting><![CDATA[private List listEvents() {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+    session.beginTransaction();
+
+    List result = session.createQuery("from Event").list();
+
+    session.getTransaction().commit();
+
+    return result;
+}]]></programlisting>
+
+            <para>
+                O que nós fazemos aqui, é usar uma query HQL (Hibernate Query Language), 
+                para carregar todos os objetos <literal>Event</literal>  exitentes no banco de dados. 
+                O Hibernate irá gerar o SQL apropriado, enviar para o banco de dados e popular objetos 
+                <literal>Event</literal> com os dados. Você pode criar queries mais complexas com 
+                HQL, claro.
+            </para>
+
+            <para>
+                Agora, para executar e testar tudo isso, siga os passos a seguir:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        Execute <literal>ant run -Daction=store</literal>  para armazenar algo no banco de dados 
+                        e, claro, gerar o esquema do banco de dados antes pelo hbm2ddl.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Agora desabilite hbm2ddl comentando a propriedade no seu arquivo <literal>hibernate.cfg.xml</literal>. 
+                        Normalmente só se deixa habilitado em teste unitários contínuos, mas outra carga de  hbm2ddl 
+                        pode <emphasis>remover</emphasis> tudo que você já tenha arquivado. Sa configuração  
+                        <literal>create</literal>, atualmente são traduzidas para "apague todas as tabelas do esquema, 
+                        então recrie todas quando a SessionFactory estiver pronta".
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Se você agora chamar o Ant com <literal>-Daction=list</literal>, você deverá ver os 
+                eventos que você acabou de criar. Você pode também chamar a ação <literal>store</literal> 
+                mais algumas vezes. 
+            </para>
+
+            <para>
+                Nota: A maioria dos novos usuários do Hibernate falha nesse ponto e nós regularmente, vemos 
+                questões sobre mensagens de erro de <emphasis>tabela não encontrada </emphasis> . 
+                Entretanto, se você seguir os passos marcados acima, você não terá esse problema, 
+                com o hbm2ddl criando o esquema do banco de dados na primeira execução, e restarts
+                subsequentes da aplicação irão usar este esquema. Se você mudar o mapeamento e/ou
+                o esquema do banco de dados, terá de re-habilitar o hbm2ddl mais uma vez.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="tutorial-associations">
+        <title>Part 2 - Mapeando associações</title>
+
+        <para>
+           Nós mapeamos uma classe de entidade de persistência para uma tabela. Agora vamos continuar
+           e adicionar algumas associações de classe. Primeiro nos iremos adicionar pessoas a nossa aplicação, 
+           e armazenar os eventos de que elas participam.
+        </para>
+
+        <sect2 id="tutorial-associations-mappinguser" revision="1">
+            <title>Mapeando a classe Person</title>
+
+            <para>
+                O primeiro código da classe <literal>Person</literal> é simples:
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+public class Person {
+
+    private Long id;
+    private int age;
+    private String firstname;
+    private String lastname;
+
+    public Person() {}
+
+    // Accessor methods for all properties, private setter for 'id'
+
+}]]></programlisting>
+
+            <para>
+                Crie um novo arquivo de mapeamento, chamado <literal>Person.hbm.xml</literal> (não 
+                esqueça a referencia ao DTD no topo)
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Person" table="PERSON">
+        <id name="id" column="PERSON_ID">
+            <generator class="native"/>
+        </id>
+        <property name="age"/>
+        <property name="firstname"/>
+        <property name="lastname"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Finalmente, adicione o novo mapeamento a configuração do Hibernate:
+            </para>
+
+            <programlisting><![CDATA[<mapping resource="events/Event.hbm.xml"/>
+<mapping resource="events/Person.hbm.xml"/>]]></programlisting>
+
+            <para>
+                Nos iremos agora criar uma associação entre estas duas entidades. Obviamente, 
+                pessoas (Person) podem participar de eventos, e eventos possuem participantes. 
+                As questões de design com que teremos de lidar são: direcionalidade, multiplicidade e 
+                comportamento de coleção.
+              </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-unidirset" revision="3">
+            <title>Uma associação Set-based unidirectional</title>
+
+            <para>
+                Nos iremos adicionar uma coleção de eventos na classe <literal>Person</literal>. Desse jeito 
+                poderemos navegar pelos eventos de uma pessoa em particular, sem executar uma query explicitamente – 
+                apenas chamando  <literal>aPerson.getEvents()</literal>. Nos usaremos uma coleção Java, um  
+                <literal>Set</literal>, porquê a coleção não conterá elementos duplicados e a ordem não é 
+                relevante para nós.
+            </para>
+
+            <para>
+                Vamos escrever o código para isto nas classes Java e então mapear:
+            </para>
+
+            <programlisting><![CDATA[public class Person {
+
+    private Set events = new HashSet();
+
+    public Set getEvents() {
+        return events;
+    }
+
+    public void setEvents(Set events) {
+        this.events = events;
+    }
+}]]></programlisting>
+
+            <para>
+                Antes de mapearmos esta associação, pense no outro lado. Claramente, poderíamos apenas fazer isto de 
+                forma unidirecional. Ou poderíamos criar outra coleção no  <literal>Event</literal>, se quisermos 
+                ser capaz de navegar bidirecionalmente, i.e. um - <literal>anEvent.getParticipants()</literal>. 
+                Isto não é necessário, de perspectiva funcional. Você poderia sempre executar uma query explicita 
+                que retornasse os participantes de um evento em particular. Esta é uma escolha de design que cabe 
+                a você, mas o que é claro nessa discussão é a multiplicidade da associação: "muitos" valores em ambos 
+                os lados, nós chamamos isto uma associação <emphasis>muitos-para-muitos</emphasis>. Daqui pra frente, 
+                nos usaremos o mapeamento muitos-para-muitos do Hibernate:
+            </para>
+
+            <programlisting><![CDATA[<class name="events.Person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="native"/>
+    </id>
+    <property name="age"/>
+    <property name="firstname"/>
+    <property name="lastname"/>
+
+    <set name="events" table="PERSON_EVENT">
+        <key column="PERSON_ID"/>
+        <many-to-many column="EVENT_ID" class="events.Event"/>
+    </set>
+
+</class>]]></programlisting>
+
+            <para>
+                O Hibernate suporta todo tipo de mapeamento de coleção , sendo um <literal>&lt;set&gt;</literal> mais comum. 
+                Para uma associação muitos-para-muitos (ou relacionamento de entidade <emphasis>n:m</emphasis> ), 
+                uma tabela de associação é necessária. Cada linha nessa tabela representa um link entre uma pessoa e um 
+                evento. O nome da tabela é configurado com o atributo <literal>table</literal> do elemento 
+                <literal>set</literal>. O nome da coluna identificadora na associção, peloo lado da pessoa, 
+                é definido com o elemento <literal>&lt;key&gt;</literal> , o nome da coluna pelo lado dos eventos, 
+                e definido com o atributo <literal>column</literal>  do  <literal>&lt;many-to-many&gt;</literal>. 
+                Você também precisa dizer para o Hibernate a classe dos objetos na sua coleção (a classe do outro 
+                lado das coleções de referência).
+            </para>
+
+            <para>
+                O esquema de mapeamento para o banco de dados está a seguir:
+            </para>
+
+            <programlisting><![CDATA[
+    _____________        __________________
+   |             |      |                  |       _____________
+   |   EVENTS    |      |   PERSON_EVENT   |      |             |
+   |_____________|      |__________________|      |    PERSON   |
+   |             |      |                  |      |_____________|
+   | *EVENT_ID   | <--> | *EVENT_ID        |      |             |
+   |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  |
+   |  TITLE      |      |__________________|      |  AGE        |
+   |_____________|                                |  FIRSTNAME  |
+                                                  |  LASTNAME   |
+                                                  |_____________|
+ ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-working" revision="1">
+            <title>Trabalhando a associação</title>
+
+            <para>
+                Vamos trazer juntos algumas pessoas e eventos em um novo método na classe <literal>EventManager</literal>::
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    aPerson.getEvents().add(anEvent);
+
+    session.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                Após carregar um <literal>Person</literal> e um <literal>Event</literal>, simplesmente 
+                modifique a coleção usando os métodos normais de uma coleção. Como você pode ver, não há chamada explícita 
+                para <literal>update()</literal> ou <literal>save()</literal>,  o Hibernate detecta automaticamente 
+                que a coleção foi modificada e necessita ser atualizada. Isso é chamado de <emphasis>checagem 
+                suja automática</emphasis>, e você também pode usá-la modificando o nome ou a data de qualquer um dos 
+                seus objetos. Assim que eles estiverem no estado <emphasis>persistent</emphasis>, ou seja, 
+                limitado por uma <literal>Session</literal> do Hibernate em particular (i.e. eles foram carregados ou 
+                salvos dentro de uma unidade de trabalho), o Hibernate monitora qualquer alteração e executa o SQL 
+                em modo de escrita em segundo plano. O processo de sincronização do estado da memória com o banco de 
+                dados, geralmente apenas no final de uma unidade de trabalho, é chamado de  <emphasis>flushing</emphasis>. 
+                No nosso código, a unidade de trabalho termina com o commit da transação do banco de dados – 
+                como definido pela opção de configuração da  <literal>thread</literal> da classe <literal>CurrentSessionContext</literal>.
+            </para>
+
+            <para>
+                Você pode também querer carregar pessoas e eventos em diferentes unidades de trabalho. 
+                Ou você modifica um objeto fora de uma <literal>Session</literal>, quando não se encontra no 
+                estado persistent (se já esteve neste estado anteriormente, chamamos esse estado de 
+                <emphasis>detached</emphasis>). Você pode até mesmo modificar uma coleção quando esta 
+                se encontrar no estado detached.
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session
+            .createQuery("select p from Person p left join fetch p.events where p.id = :pid")
+            .setParameter("pid", personId)
+            .uniqueResult(); // Eager fetch the collection so we can use it detached
+
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    session.getTransaction().commit();
+
+    // End of first unit of work
+
+    aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached
+
+    // Begin second unit of work
+
+    Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
+    session2.beginTransaction();
+
+    session2.update(aPerson); // Reattachment of aPerson
+
+    session2.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                A chamada <literal>update</literal> cria um objeto persistent novamente, você poderia 
+                dizer que ele liga o objeto a uma nova unidade de trabalho, assim qualquer modificação 
+                que você faça neste objeto enquanto estiver no estado detached pode ser salvo no banco de dados. 
+                Isso inclui qualquer modificação (adição/exclusão) que você faça em uma coleção da entidade deste objeto.
+            </para>
+
+            <para>
+                Bom, isso não foi muito usado na nossa situação, porém, é um importante conceito que você 
+                pode aplicar em seus aplicativos. Agora, complete este exercício adicionando uma nova ação 
+                ao método main( ) da classe  <literal>EventManager</literal> e chame-o pela linha de comando. 
+                Se você precisar dos identificadores de uma pessoa ou evento – o método  <literal>save()</literal> 
+                retorna estes identificadores (você poderá modificar alguns dos métodos anteriores para retornar aquele 
+                identificador):
+            </para>
+
+            <programlisting><![CDATA[else if (args[0].equals("addpersontoevent")) {
+    Long eventId = mgr.createAndStoreEvent("My Event", new Date());
+    Long personId = mgr.createAndStorePerson("Foo", "Bar");
+    mgr.addPersonToEvent(personId, eventId);
+    System.out.println("Added person " + personId + " to event " + eventId);]]></programlisting>
+
+            <para>
+                Este foi um exemplo de uma associação entre duas classes igualmente importantes, duas entidades. 
+                Como mencionado anteriormente, há outras classes e tipos dentro de um modelo típico, 
+                geralmente "menos importante". Alguns você já viu, como um  <literal>int</literal> ou uma <literal>String</literal>.
+                Nós chamamos essas classes de <emphasis>value types</emphasis>, e suas instâncias <emphasis>depend</emphasis>
+                de uma entidade particular. As instâncias desses tipos não possuem sua própria identidade, nem são 
+                compartilhados entre entidades (duas pessoas não referenciam o mesmo objeto  <literal>firstname</literal>
+                mesmo se elas tiverem o mesmo objeto firstname). Naturalmente, os value types não são apenas encontrados 
+                dentro da JDK (de fato, em um aplicativo Hibernate todas as classes JDK são consideradas como value types), 
+                mas você pode também criar suas classes como, por exemplo,  <literal>Address</literal> ou  <literal>MonetaryAmount</literal>.
+
+            </para>
+
+            <para>
+                Você também pode criar uma coleção de value types. Isso é conceitualmente muito diferente 
+                de uma coleção de referências para outras entidades, mas em Java parece ser quase a mesma coisa.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-valuecollections">
+            <title>Coleção de valores</title>
+
+            <para>
+                Nós adicionamos uma coleção de objetos de tipo de valores à entidade <literal>Person</literal>. 
+                Nós querermos armazenar endereços de e-mail, para isso utilizamos o tipo <literal>String</literal>, 
+                e a coleção novamente será um <literal>Set</literal>:
+            </para>
+            <programlisting><![CDATA[private Set emailAddresses = new HashSet();
+
+public Set getEmailAddresses() {
+    return emailAddresses;
+}
+
+public void setEmailAddresses(Set emailAddresses) {
+    this.emailAddresses = emailAddresses;
+}]]></programlisting>
+
+            <para>
+                O mapeamento deste <literal>Set</literal>:
+            </para>
+
+            <programlisting><![CDATA[<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
+    <key column="PERSON_ID"/>
+    <element type="string" column="EMAIL_ADDR"/>
+</set>]]></programlisting>
+
+            <para>
+                A diferença comparada com o mapeamento anterior se encontra na parte <literal>element</literal>, 
+                que indica ao Hibernate que a coleção não contém referências à outra entidade, mas uma coleção de 
+                elementos do tipo <literal>String</literal> (a tag name em miniscula indica que se trata de um 
+                mapeamento do Hibernate para conversão de tipos). Mais uma vez, o atributo  <literal>table</literal> 
+                do elemento <literal>set</literal> determina o nome da tabela para a coleção. O elemento 
+                <literal>key</literal> define o nome da coluna  de chave estrangeira na tabela de coleção. 
+                O atributo <literal>column</literal> dentro do elemento <literal>element</literal> define o 
+                nome da coluna onde os valores da <literal>String</literal> serão armazenados.
+            </para>
+
+            <para>
+                Dê uma olhada no esquema atualizado:
+            </para>
+
+            <programlisting><![CDATA[
+  _____________        __________________
+ |             |      |                  |       _____________
+ |   EVENTS    |      |   PERSON_EVENT   |      |             |       ___________________
+ |_____________|      |__________________|      |    PERSON   |      |                   |
+ |             |      |                  |      |_____________|      | PERSON_EMAIL_ADDR |
+ | *EVENT_ID   | <--> | *EVENT_ID        |      |             |      |___________________|
+ |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  | <--> |  *PERSON_ID       |
+ |  TITLE      |      |__________________|      |  AGE        |      |  *EMAIL_ADDR      |
+ |_____________|                                |  FIRSTNAME  |      |___________________|
+                                                |  LASTNAME   |
+                                                |_____________|
+ ]]></programlisting>
+
+            <para>
+                Você pode observar que a chave primária da tabela da coleção é de na verdade uma chave composta, 
+                usando ambas colunas. Isso também implica que cada pessoa não pode ter endereços de e-mail 
+                duplicados, o que é exatamente a semântica que precisamos para um set em Java.
+            </para>
+
+            <para>
+                Você pode agora tentar adicionar elementos a essa coleção, do mesmo modo que fizemos 
+                anteriormente ligando pessoas e eventos. È o mesmo código em Java:
+            </para>
+
+            <programlisting><![CDATA[private void addEmailToPerson(Long personId, String emailAddress) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+
+    // The getEmailAddresses() might trigger a lazy load of the collection
+    aPerson.getEmailAddresses().add(emailAddress);
+
+    session.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                This time we didnt' use a <emphasis>fetch</emphasis> query to initialize the collection.
+                Hence, the call to its getter method will trigger an additional select to initialize
+                it, so we can add an element to it. Monitor the SQL log and try to optimize this with
+                an eager fetch.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-bidirectional" revision="1">
+            <title>Associações bidirecionais</title>
+
+            <para>
+                Agora iremos mapear uma associação bidirecional – fazendo a associação entre pessoas e 
+                eventos, de ambos os lados, em Java. Logicamente, o esquema do banco de dados não muda, 
+                nós continuamos tendo multiplicidades muitos-para-muitos. Um banco de dados é mais flexível do que 
+                uma linguagem de programação para redes, ele não precisa de nenhuma direção de navegação – os 
+                dados podem ser acessados em qualquer caminho possível.
+            </para>
+
+            <para>
+                Primeiramente, adicione uma coleção de participantes à classe <literal>Event</literal>:
+            </para>
+
+            <programlisting><![CDATA[private Set participants = new HashSet();
+
+public Set getParticipants() {
+    return participants;
+}
+
+public void setParticipants(Set participants) {
+    this.participants = participants;
+}]]></programlisting>
+
+            <para>
+                Agora mapeie este lado da associação em <literal>Event.hbm.xml</literal>.
+            </para>
+
+            <programlisting><![CDATA[<set name="participants" table="PERSON_EVENT" inverse="true">
+    <key column="EVENT_ID"/>
+    <many-to-many column="PERSON_ID" class="events.Person"/>
+</set>]]></programlisting>
+
+            <para>
+                Como você pode ver, esses é uma mapeamento normal usando <literal>set</literal> em ambos documenentos
+                de mapeamento. Observe que o nome das colunas em  <literal>key</literal> e <literal>many-to-many</literal>
+                estão trocados em ambos os documentos de mapeamento. A adição mais importante feita está no atributo 
+                <literal>inverse="true"</literal> no elemento set do mapeamento da coleção da classe  <literal>Event</literal>.
+            </para>
+
+            <para>
+                Isso significa que o Hibernate deve pegar o outro lado – a classe <literal>Person</literal> – 
+                quando necessitar encontrar informação sobre a relação entre as duas entidades. Isso será muito 
+                mais facilmente compreendido quando você analisar como a relação bidirecional entre as entidades é criada. 
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-usingbidir">
+            <title>Trabalhando com links bidirecionais</title>
+
+            <para>
+                Primeiro tenha em mente que o Hibernate não afeta a semântica normal do Java. Como nós criamos 
+                um link entre uma <literal>Person</literal> e um <literal>Event</literal> no exemplo unidirecional? 
+                Nós adicionamos uma instância de <literal>Event</literal>, da coleção de referências de eventos, 
+                a uma instância de <literal>Person</literal>. Então, obviamente, se nós queremos que este link funcione 
+                bidirecionalmente, nós devemos fazer a mesma coisa para o outro lado – adicionando uma referência de 
+                <literal>Person</literal> na coleção de um <literal>Event</literal>. Esse acerto de link de ambos 
+                os lados é absolutamente necessário e você nunca deve esquecer de faze-lo.
+            </para>
+
+            <para>
+                Muitos desenvolvedores programam de maneira defensiva e criam métodos
+                gerenciador de associações que ajusta corretamente ambos os lados:
+            </para>
+
+            <programlisting><![CDATA[protected Set getEvents() {
+    return events;
+}
+
+protected void setEvents(Set events) {
+    this.events = events;
+}
+
+public void addToEvent(Event event) {
+    this.getEvents().add(event);
+    event.getParticipants().add(this);
+}
+
+public void removeFromEvent(Event event) {
+    this.getEvents().remove(event);
+    event.getParticipants().remove(this);
+}]]></programlisting>
+
+            <para>
+                Observe que os métodos set e get da a coleção estão protegidos – isso permite que classes e 
+                subclasses do mesmo pacote continuem acessando os métodos, mas previne que qualquer outra classe, 
+                que não esteja no mesmo pacote, acesse a coleção diretamente. Você provavelmente deve fazer a mesma 
+                coisa para a coleção do outro lado.
+            </para>
+
+            <para>
+                E sobre o mapeamento do atributo <literal>inverse</literal>? Pra você, e para o Java, um link bidirecional 
+                é simplesmente o fato de ajustar corretamente as referências de ambos os lados. O Hibernate, entretanto 
+                não possui informação necessária para corretamente adaptar os estados <literal>INSERT</literal> e
+                <literal>UPDATE</literal> do SQL, e precisa de ajuda para manipular as propriedades das associações 
+                bidirecionais. Fazer um lado da associação com o atributo <literal>inverse</literal> instrui o Hibernate 
+                para basicamente ignora-lo, considerando-o uma <emphasis>cópia</emphasis> do outro lado. Isso é todo o 
+                necessário para o Hibernate trabalhar com todas as possibilidades quando transformando um modelo de 
+                navegação bidirecional em esquema de banco de dados do SQL. As regras que você possui para lembrar são 
+                diretas: Todas associações bidirecionais necessitam que um lado possua o atributo inverse. Em uma 
+                associação de um-para-muitos, o lado de "muitos" deve conter o atributo <literal>inverse</literal>, 
+                já em uma associação de muitos-para-muitos você pode pegar qualquer lado, não há diferença. 
+            </para>
+
+        </sect2>
+
+        <para>
+            Agora, vamos portar este exemplo para um pequeno aplicativo para internet.
+
+        </para>
+
+    </sect1>
+
+    <sect1 id="tutorial-webapp">
+        <title>EventManager um aplicativo para internet</title>
+
+        <para>
+            Um aplicativo para internet do Hibernate usa uma <literal>Session</literal> e uma <literal>Transaction</literal> 
+            quase do mesmo modo que um aplicativo standalone. Entretanto, alguns patterns comuns são úteis. 
+            Nós agora criaremos um <literal>EventManagerServlet</literal>. Esse servlet lista todos os eventos 
+            salvos no banco de dados, e cria um formulário HTML para entrada de novos eventos.
+        </para>
+
+        <sect2 id="tutorial-webapp-servlet" revision="1">
+            <title>Criando um servlet básico</title>
+
+            <para>
+                Crie uma nova classe no seu diretório fonte, no pacote <literal>events</literal>:
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+// Imports
+
+public class EventManagerServlet extends HttpServlet {
+
+    // Servlet code
+}]]></programlisting>
+
+            <para>
+                O servlet manuseia somente requisições <literal>GET</literal> do HTTP, 
+                portanto o método que iremos implementar é <literal>doGet()</literal>:
+            </para>
+
+            <programlisting><![CDATA[protected void doGet(HttpServletRequest request,
+                     HttpServletResponse response)
+        throws ServletException, IOException {
+
+    SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
+
+    try {
+        // Begin unit of work
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().beginTransaction();
+
+        // Process request and render page...
+
+        // End unit of work
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().getTransaction().commit();
+
+    } catch (Exception ex) {
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().getTransaction().rollback();
+        throw new ServletException(ex);
+    }
+
+}]]></programlisting>
+
+            <para>
+                O pattern que estamos aplicando neste código é chamado <emphasis>session-per-request</emphasis>.
+                Quando uma requisição chega ao servlet, uma nova <literal>Session</literal> do Hibernate é 
+                aberta através da primeira chamada para <literal>getCurrentSession()</literal> em 
+                <literal>SessionFactory</literal>. Então uma transação do banco de dados é inicializada - 
+                todo acesso a dados deve ocorrer dentro de uma transação, não importando se o dado é de leitura ou escrita.
+                (nós não devemos usar o modo auto-commit em aplicações).
+
+            </para>
+
+            <para>
+                Agora, as possibilidades de ações de uma requisição serão processadas e uma resposta HTML será renderizada. 
+                Nós já iremos chegar nesta parte.
+            </para>
+
+            <para>
+                Finalmente, a unidade de trabalho termina quando o processamento e a restituição são completados. 
+                Se ocorrer algum erro durante o processamento ou a restituição, uma exceção será lançada e a 
+                transação do banco de dados encerrada. Isso completa o pattern <literal>session-per-request</literal>. 
+                Em vez de usar código de demarcação de transação em todo servlet você pode também criar um filtro servlet. 
+                Dê uma olhada no site do Hibernate e do Wiki para maiores informações sobre esse pattern, 
+                chamado <emphasis>Open Session in View</emphasis>.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-webapp-processing" revision="1">
+            <title>Processando e renderizando</title>
+
+            <para>
+                Vamos implementar o processamento da requisição e a restituição da página HTML.
+            </para>
+
+<programlisting><![CDATA[// Write HTML header
+PrintWriter out = response.getWriter();
+out.println("<html><head><title>Event Manager</title></head><body>");
+
+// Handle actions
+if ( "store".equals(request.getParameter("action")) ) {
+
+    String eventTitle = request.getParameter("eventTitle");
+    String eventDate = request.getParameter("eventDate");
+
+    if ( "".equals(eventTitle) || "".equals(eventDate) ) {
+        out.println("<b><i>Please enter event title and date.</i></b>");
+    } else {
+        createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
+        out.println("<b><i>Added event.</i></b>");
+    }
+}
+
+// Print page
+printEventForm(out);
+listEvents(out, dateFormatter);
+
+// Write HTML footer
+out.println("</body></html>");
+out.flush();
+out.close();]]></programlisting>
+
+            <para>
+                O estilo de código acima, misturando linguagem HTML e Java não será funcional em um aplicativo 
+                mais complexo&mdash;tenha em mente que neste manual nós estamos apenas ilustrando conceitos 
+                básicos do Hibernate. O código imprime um cabeçalho HTML e um rodapé. Dentro desta página, 
+                é mostrado um formulário em HTML, para entrada de novos eventos, e uma lista de todos 
+                os eventos contidos no banco de dados. O primeiro método é trivial e apenas imprime 
+                uma página HTML:
+            </para>
+
+            <programlisting><![CDATA[private void printEventForm(PrintWriter out) {
+    out.println("<h2>Add new event:</h2>");
+    out.println("<form>");
+    out.println("Title: <input name='eventTitle' length='50'/><br/>");
+    out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");
+    out.println("<input type='submit' name='action' value='store'/>");
+    out.println("</form>");
+}]]></programlisting>
+
+            <para>
+                O método <literal>listEvents()</literal>  usa a <literal>Session</literal> do Hibernate  
+                associada a thread atual para executar um query:
+            </para>
+
+            <programlisting><![CDATA[private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) {
+
+    List result = HibernateUtil.getSessionFactory()
+                    .getCurrentSession().createCriteria(Event.class).list();
+    if (result.size() > 0) {
+        out.println("<h2>Events in database:</h2>");
+        out.println("<table border='1'>");
+        out.println("<tr>");
+        out.println("<th>Event title</th>");
+        out.println("<th>Event date</th>");
+        out.println("</tr>");
+        for (Iterator it = result.iterator(); it.hasNext();) {
+            Event event = (Event) it.next();
+            out.println("<tr>");
+            out.println("<td>" + event.getTitle() + "</td>");
+            out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
+            out.println("</tr>");
+        }
+        out.println("</table>");
+    }
+}]]></programlisting>
+
+            <para>
+                Finalmente, a action <literal>store</literal> é passada pra o método 
+                <literal>createAndStoreEvent()</literal>, que também usa a 
+                <literal>Session</literal> da thread atual:
+            </para>
+
+            <programlisting><![CDATA[protected void createAndStoreEvent(String title, Date theDate) {
+    Event theEvent = new Event();
+    theEvent.setTitle(title);
+    theEvent.setDate(theDate);
+
+    HibernateUtil.getSessionFactory()
+                    .getCurrentSession().save(theEvent);
+}]]></programlisting>
+
+            <para>
+                Pronto, o servlet está completo. Uma requisição para o servlet será processada 
+                em uma  <literal>Session</literal> e uma  <literal>Transaction</literal> simples. 
+                Como anteriormente, no aplicativo standalone, o Hibernate pode automaticamente 
+                associar esses objetos a thread atual em execução. Isso possibilita a liberdade 
+                de você modelar seu código e acessar o método  <literal>SessionFactory</literal> 
+                do jeito que achar melhor. Geralmente você irá usar um design mais sofisticado 
+                e mover o código de acesso a dados para dentro de objetos de acesso a dados 
+                (o patter DAO). Leia o Hibernate Wiki para maiores exemplos.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-webapp-deploy">
+            <title>Instalando e testando</title>
+
+            <para>
+                Para fazer o deploy desta aplicação você tem que criar um arquivo para web, um WAR. 
+                Adicione o alvo Ant abaixo em seu <literal>build.xml</literal>:
+            </para>
+
+<programlisting><![CDATA[<target name="war" depends="compile">
+    <war destfile="hibernate-tutorial.war" webxml="web.xml">
+        <lib dir="${librarydir}">
+          <exclude name="jsdk*.jar"/>
+        </lib>
+
+        <classes dir="${targetdir}"/>
+    </war>
+</target>]]></programlisting>
+
+            <para>
+                Esta target cria um arquivo chamado <literal>hibernate-tutorial.war</literal> 
+                no diretório do seu projeto. Ele empacota todas as bibliotecas e o arquivo de 
+                descrição <literal>web.xml</literal>, o qual é esperado no diretório base do seu projeto:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+    xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+    <servlet>
+        <servlet-name>Event Manager</servlet-name>
+        <servlet-class>events.EventManagerServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Event Manager</servlet-name>
+        <url-pattern>/eventmanager</url-pattern>
+    </servlet-mapping>
+</web-app>]]></programlisting>
+
+            <para>
+                Antes de você compilar e fazer o deploy desta aplicação web, note que uma biblioteca 
+                adicional é requerida: <literal>jsdk.jar</literal>. Esse é o Java servlet development kit, 
+                se você não possui esta biblioteca, faça seu download na página da Sun e copie-a
+                para seu diretório de bibliotecas. Entretanto, será usado somente para a compilação e 
+                excluído do pacote WAR.
+            </para>
+
+            <para>
+                Para compilar e instalar execute <literal>ant war</literal> no seu diretório do projeto 
+                e copie o arquivo <literal>hibernate-tutorial.war</literal> para o diretório 
+                <literal>webapp</literal> do Tomcat. Se você não possui o Tomcat instalado faça 
+                o download e siga as instruções de instalação. Você não precisa modificar 
+                nenhuma configuração do Tomcat para rodar este aplicativo.
+            </para>
+
+            <para>
+                Uma vez feito o deploy e com Tomcat rodando, acesse o aplicativo em 
+                <literal>http://localhost:8080/hibernate-tutorial/eventmanager</literal>. 
+                Veja o log do Tomcat para observar a inicialização do Hibernate quando a 
+                primeira requisição chega ao servlet (o inicializador estático dentro de 
+                <literal>HibernateUtil</literal> é chamado) e para ter uma depuração 
+                detalhada se ocorrer alguma exceção. 
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="tutorial-summary" revision="1">
+        <title>Sumário</title>
+
+        <para>
+            Este manual cobriu os princípios básicos para criação de uma aplicação simples do Hibernate 
+            e uma pequena aplicação web. 
+        </para>
+
+        <para>
+            Se você já se sente seguro com o Hibernate, continue navegando na documentação de referência 
+            por tópicos que você acha interessante – os tópicos mais questionados são: 
+            processo de transação (<xref linkend="transactions"/>), uso da API (<xref linkend="objectstate"/>) 
+            e características de consulta (<xref linkend="objectstate-querying"/>).
+        </para>
+
+        <para>
+            Não esqueça de visitar o site do Hibernate para obter mais tutoriais especializados.
+        </para>
+
+    </sect1>
+
+</chapter>


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/tutorial.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/tutorial1.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/tutorial1.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/tutorial1.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1544 @@
+<chapter id="tutorial">
+    <title>Introdu&#x00E7;&#x00E3;o ao Hibernate</title>
+    
+    <sect1 id="tutorial-intro" revision="1">
+        <title>Pref&#x00E1;cio</title>
+        
+        <para>
+            Este cap&#x00ED;tulo &#x00E9; um tutorial introdut&#x00F3;rio para novos usu&#x00E1;rios do Hibernate. N&#x00F3;s iniciaremos com uma simples linha de comando em uma aplica&#x00E7;&#x00E3;o usando uma base de dados em mem&#x00F3;ria tornando isto um passo de f&#x00E1;cil de compreender.
+        </para>
+
+        <para>
+            Este tutorial &#x00E9; voltado para novos usu&#x00E1;rios do Hibernate, mas requer um conhecimento de Java e SQL. Este tutorial &#x00E9; baseado no tutorial de Michael Gloegl, as bibliotecas Third Party foram nomeadas para JDK 1.4 e 5.0. Você pode precisar de outras bibliotecas para JDK 1.3.
+        </para>
+
+        <para>
+            O código fonte para o tutorial está incluído no diretório da distribuição 
+            <literal>doc/reference/tutorial/</literal>. 
+        </para>
+
+    </sect1>
+    
+    <sect1 id="tutorial-firstapp" revision="2">
+        <title>Parte 1 – A primeira aplicação Hibernate</title>
+
+        <para>
+            Primeiro, iremos criar uma simples aplica&#x00E7;&#x00E3;o Hibernate baseada em console. Usaremos uma base de dados Java (HSQL DB), ent&#x00E3;o n&#x00E3;o teremos que instalar nenhum servidor de base de dados.
+        </para>
+
+        <para>
+            Vamos supor que precisemos de uma aplica&#x00E7;&#x00E3;o com um banco de dados pequeno que possa armazenar e atender os eventos que queremos, e as informa&#x00E7;&#x00E7;es sobre os hosts destes eventos. 
+        </para>
+            
+        <para>
+            A primeira coisa que devemos fazer &#x00E9; configurar nosso diret&#x00F3;rio de desenvolvimento, 
+            e colocar todas as bibliotecas Java que precisamos dentro dele. Fa&#x00E7;a o download da 
+            distribui&#x00E7;&#x00E3;o do Hibernate no site do Hibernate. Descompacte o pacote e coloque todas 
+            as bibliotecas necess&#x00E1;rias encontradas no diret&#x00F3;rio <literal>/lib</literal>, dentro do 
+            diret&#x00F3;rio <literal>/lib</literal> do seu novo projeto. Você dever&#x00E1; ter algo parecido
+            com isso:
+        </para>
+            
+        <programlisting><![CDATA[.
++lib
+  antlr.jar
+  cglib.jar
+  asm.jar
+  asm-attrs.jars
+  commons-collections.jar
+  commons-logging.jar
+  hibernate3.jar
+  jta.jar
+  dom4j.jar
+  log4j.jar ]]></programlisting>
+
+        <para>
+         		Esta &#x00E9; a configura&#x00E7;&#x00E3;o m&#x00ED;nima requerida das bibliotecas (observe que tamb&#x00E9;m foi copiado 
+            o hibernate3.jar da pasta principal do Hibernate) para o Hibernate <emphasis>na hora do desenvolvimento</emphasis>. O Hibernate permite que você utilize mais ou menos bibliotecas. 
+            Veja o arquivo <literal>README.txt</literal>  no diret&#x00F3;rio <literal>lib/</literal> da distribui&#x00E7;&#x00E3;o 
+            do Hibernate para maiores informa&#x00E7;&#x00E7;es sobre bibliotecas requeridas e opcionais. 
+            (Atualmente, a biblioteca Log4j n&#x00E3;o &#x00E9; requerida, mas &#x00E9; preferida por muitos desenvolvedores.)
+        </para>
+
+        <para>
+            Agora, iremos criar uma classe que representa o evento que queremos armazenar na base de dados..
+        </para>
+      
+        <sect2 id="tutorial-firstapp-firstclass" revision="1">
+            <title>A primeira Classe</title>
+            
+            <para>
+                Nossa primeira classe de persistência é uma simples classe JavaBean com algumas propriedades:
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+import java.util.Date;
+
+public class Event {
+    private Long id;
+
+    private String title;
+    private Date date;
+
+    public Event() {}
+
+    public Long getId() {
+        return id;
+    }
+
+    private void setId(Long id) {
+        this.id = id;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+}]]></programlisting>
+
+            <para>
+                Você pode ver que esta classe usa o padrão JavaBean para o nomeamento convencional da propriedade getter e dos métodos setter, como também a visibilidade private dos campos. Este é um padrão de projeto recomendado, mas não requerido. O Hibernate pode também acessar campos diretamente, o benefício para os métodos de acesso é a robustez para o Refactoring. O construtor sem argumento é requerido para instanciar um objeto desta classe com a reflexão.
+            </para>
+
+            <para>
+                A propriedade  <literal>id</literal> mantém um único valor de identificação para um evento 
+                particular. Todas as classes persistentes da entidade (bem como aquelas classes dependentes 
+                de menos importância) precisam de uma propriedade de identificação, caso nós queiramos usar o 
+                conjunto completo de características do Hibernate. De fato, a maioria das aplicações 
+                (esp. aplicações web)  precisam destinguir os objetos pelo identificador, então você deverá 
+                considerar esta, uma característica em lugar de uma limitação. Porém, nós normalmente não 
+                manipulamos a identidade de um objeto, consequentemente o método setter deverá ser privado. 
+                O Hibernate somente nomeará os identificadores quando um objeto for salvo. Você pode ver como 
+                o Hibernate pode acessar métodos públicos, privados, e protegidos, como também campos 
+                (públicos, privados, protegidos) diretamente. A escolha está até você, e você pode combinar 
+                isso para adaptar seu projeto de aplicação
+            </para>
+
+            <para>
+                 O construtor sem argumentos é um requerimento para todas as classes persistentes; 
+                O Hibernate tem que criar para você os objetos usando Java Reflection.  O construtor 
+                pode ser privado, porém, a visibilidade do pacote é requerida para a procuração da 
+                geração em tempo de execução e recuperação eficiente dos dados sem a instrumentação 
+                de bytecode 
+            </para>
+
+            <para>
+                Coloque este fonte Java no diretório chamado <literal>src</literal> na pasta de desenvolvimento, 
+                e em seu pacote correto. O diretório deverá ser parecido como este:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java]]></programlisting>
+
+            <para>
+                No próximo passo, iremos falar sobre as classes de persistência do Hibernate..
+            </para>
+                
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-mapping" revision="1">
+            <title>O mapeamento do arquivo</title>
+
+            <para>
+                O Hibernate precisa saber como carregar e armazenar objetos da classe de 
+                persistência. Isto será onde o mapeamento do arquivo do Hibernate entrará em 
+                jogo. O arquivo mapeado informa ao Hibernate, qual tabela no banco de dados 
+                ele deverá acessar, e quais as colunas na tabela ele deverá usar.
+            </para>
+
+            <para>
+                A estrutura básica de um arquivo de mapeamento é parecida com:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+[...]
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Note que o Hibernate DTD é muito sofisticado. Você pode usar isso para auto-conclusão 
+                no mapeamento XML dos elementos e atributos no seu editor ou IDE. Você também pode 
+                abrir o arquivo DTD no seu editor – é a maneira mais fácil de ter uma visão geral 
+                de todos os elementos e atributos e dos padrões, como também alguns comentários. 
+                Note que o Hibernate não irá carregar o arquivo DTD da web, e sim do diretório 
+                da aplicação (classpath). O arquivo DTD está incluído no  <literal>hibernate3.jar</literal> como 
+                também no diretório <literal>src/</literal> da distribuição do Hibernate. 
+            </para>
+
+            <para>
+                Nós omitiremos a declaração do DTD nos exemplos futuros para encurtar o código. Isto, é claro, não é opcional.
+            </para>
+
+            <para>
+                Entre os dois tags <literal>hibernate-mapping</literal>, inclua um elemento <literal>class</literal>. 
+                Todas as classes persistentes da entidade (novamente, poderá haver 
+                mais tarde, dependências sobre as classes que não são classes-primárias 
+                de entidades) necessitam do tal mapeamento, para uma tabela na base 
+                de dados SQL
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Mais adiante iremos dizer ao Hibernate como fazer para persistir e carregar objetos da classe 
+                <literal>Event</literal> da tabela <literal>EVENTS</literal>, cada instancia representada por 
+                uma coluna na tabela. Agora, continuaremos com o mapeamento de uma única propriedade identificadora 
+                para as chaves primárias da tabela. Além disso, nós não iremos se importar com esta propriedade 
+                identificadora, nós iremos configurar uma estratégia de geração de id’s para uma chave primária 
+                de coluna surrogate: 
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="native"/>
+        </id>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                O elemento <literal>id</literal> é a declaração da propriedade identificadora, 
+                o <literal>name="id"</literal> declara o nome da propriedade Java – 
+                o Hibernate irá usar os métodos getter e setter para acessar a propriedade.
+                O atributo da coluna informa ao Hibernate qual coluna da tabela  <literal>EVENTS</literal> nós 
+                iremos usar como chave primária. O elemento <literal>generator</literal> especifica 
+                a estratégia de geração do identificador, neste caso usaremos <literal>native</literal>, que 
+                escolhe a melhor estratégia dependendo da base de dados (dialeto) configurada. 
+                O Hibernate suporta a base de dados gerada, globalmente única, bem como a atribuição 
+                aos identificadores da aplicação (ou toda estratégia escrita para uma extensão).
+            </para>
+
+            <para>
+                Finalmente incluiremos as declarações para as propriedades persistentes da classe 
+                no arquivo mapeado. Por default, nenhuma das propriedades da classe é considerada persistente:
+            </para>
+            
+            <programlisting><![CDATA[
+<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="native"/>
+        </id>
+        <property name="date" type="timestamp" column="EVENT_DATE"/>
+        <property name="title"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+            
+            <para>
+                Da mesma maneira que com o elemento  <literal>id</literal>, o atributo <literal>name</literal> do elemento 
+                <literal>property</literal> informa ao Hibernate qual método getter e setter deverá usar. 
+                Assim, neste caso, o Hibernate irá procurar pelo <literal>getDate()/setDate()</literal>, 
+                como também pelo <literal>getTitle()/setTitle()</literal>.
+            </para>
+
+            <para>
+                Porque fazer o mapeamento da propriedade  <literal>date</literal> incluído no 
+                atributo <literal>column</literal>, e no title não fazer? 
+                Sem o atributo <literal>column</literal> o Hibernate por padrão usa o nome 
+                da propriedade como o nome da coluna. Isto trabalha muito 
+                bem para o  <literal>title</literal>. Entretanto o <literal>date</literal> é uma palavra-chave reservada 
+                na maioria dos bancos de dados, assim nós melhoramos o mapeamentos 
+                disto com um nome diferente.
+            </para>
+
+            <para>
+                A próxima coisa interessante é que mapemanto do <literal>title</literal> 
+                também falta o atributo <literal>type</literal>. O tipo que declaramos e o uso nos 
+                arquivos mapeados, não são como você pôde esperar, atributos de dados Java. 
+                Eles não são como os tipos de base de dados SQL. 
+                Esses tipos podem ser chamados de <emphasis>Tipos de mapeamento Hibernate</emphasis>, que são conversores 
+                que podem traduzir tipos de dados do Java para os tipos de dados SQL e vice-versa. 
+                Novamente, o Hibernate irá tentar determinar a conversão correta e mapeará o <literal>type</literal> 
+                próprio, caso o tipo do atributo não estiver presente no mapeamento. 
+                Em alguns casos, esta detecção automática (que usa Reflection sobre as classes Java) 
+                poderá não ter padrão que você espera ou necessita. 
+                Este é o caso com a propriedade <literal>date</literal>. O Hibernate não pode saber se a propriedade 
+                (que é do <literal>java.util.Date</literal>) pode mapear para uma coluna do tipo <literal>date</literal> 
+                do SQL, <literal>timestamp</literal>, ou <literal>time</literal> . 
+                Nós preservamos a informação cheia de datas e horas pelo mapeamento da propriedade com um conversor 
+                 <literal>timestamp</literal>.
+            </para>
+
+            <para>
+                Este arquivo de mapeamento deve ser salvo como <literal>Event.hbm.xml</literal>, 
+                corretamente no diretório próximo ao arquivo fonte da Classe Java <literal>Event</literal>. 
+                O nomeamento dos arquivos de mapeamento podem ser arbitrários, porém o sufixo 
+                <literal>hbm.xml</literal> é uma convenção da comunidade dos desenvolvedores do Hibernate. 
+                Esta estrutura do diretório deve agora se parecer com isso:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java
+    Event.hbm.xml]]></programlisting>
+
+             <para>
+                 Nós iremos continuar com a configuração principal do Hibernate.
+             </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-configuration" revision="2">
+            <title>Configuração do Hibernate</title>
+
+            <para>
+                Agora nós temos uma classe persistente e este arquivo de mapeamento no lugar. 
+                Está na hora de configurar o Hibernate. Antes de fazermos isso, iremos precisar de uma base de dados. 
+                O HSQL DB, um SQL DBMS feito em java, pode ser baixado através do site do HSQL DB. 
+                Atualmente, você só precisa baixar o <literal>hsqldb.jar</literal>. 
+                Coloque este arquivo no diretório da pasta de desenvolvimento <literal>lib/</literal>.
+            </para>
+
+            <para>
+                Crie um diretório chamado  <literal>data</literal> no diretório root de desenvolvimento – 
+                Isto será onde o HSQL DB irá armazenar arquivos de dados. Agora iremos iniciar o banco de dados 
+                executando  <literal>java -classpath ../lib/hsqldb.jar org.hsqldb.Server</literal> neste diretório de dados. 
+                Você pode ver ele iniciando e conectando ao socket TCP/IP, isto será onde nossa aplicação irá se 
+                conectar depois. Se você deseja iniciar uma nova base de dados durante este tutorial, 
+                finalize o HSQL DB(pressionando o <literal>CTRL + C</literal> na janela), delete todos os 
+                arquivos no diretório <literal>data/</literal>, e inicie o HSQL BD novamente.
+            </para>
+
+            <para>
+                O Hibernate é uma camada na sua aplicação na qual se conecta com a base de dados, para isso
+                necessita de informação da conexão. As conexões são feitas através de um pool de conexão JDBC, 
+                na qual teremos que configurar. A distribuição do Hibernate contém diversas ferramentas de pooling 
+                da conexão JDBC de fonte aberta, mas iremos usar o pool de conexão interna para este tutorial. 
+                Note que você tem que copiar a biblioteca necessária em seu classpath e use configurações 
+                diferentes para pooling de conexão caso você deseje utilizar um software de pooling JDBC terceirizado 
+                para qualidade de produção.
+            </para>
+
+            <para>
+                Para as configurações do Hibernate, nós podemos usar um arquivo simples <literal>hibernate.properties</literal>, 
+                um arquivo mais ligeiramente sofisticado <literal>hibernate.cfg.xml</literal> ou até mesmo uma 
+                instalação programática completa. A maioria dos usuários preferem utilizar o arquivo de configuração XML
+            </para>
+
+            <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <session-factory>
+
+        <!-- Database connection settings -->
+        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
+        <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
+        <property name="connection.username">sa</property>
+        <property name="connection.password"></property>
+
+        <!-- JDBC connection pool (use the built-in) -->
+        <property name="connection.pool_size">1</property>
+
+        <!-- SQL dialect -->
+        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
+
+        <!-- Enable Hibernate's automatic session context management -->
+        <property name="current_session_context_class">thread</property>
+
+        <!-- Disable the second-level cache  -->
+        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
+
+        <!-- Echo all executed SQL to stdout -->
+        <property name="show_sql">true</property>
+
+        <!-- Drop and re-create the database schema on startup -->
+        <property name="hbm2ddl.auto">create</property>
+
+        <mapping resource="events/Event.hbm.xml"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+            <para>
+                Note que esta configuração XML usa um diferente DTD. Nós configuraremos 
+                as <literal>SessionFactory</literal> do Hibernate – uma factory global responsável 
+                por uma base de dedados particular. Se você tiver diversas bases de dados, 
+                use diversas configurações <literal>&lt;session-factory&gt;</literal>, geralmente 
+                em diversos arquivos de configuração (para uma partida mais fácil). 
+            </para>
+
+            <para>
+                As primeiras quatro <literal>propriedades</literal> do elemento contém a configuração 
+                necessária para a conexão ao JDBC. A propriedade <literal>propriedade</literal> dialect 
+                do elemento especifica a variante particular do SQL que o Hibernate gera. 
+                O gerenciamento automático de sessão do Hibernate para contextos de persistência 
+                estará disponível em breve. A opção <literal>hbm2ddl.auto</literal> habilita a geração 
+                automática de schemas da base de dados – diretamente na base de dados. 
+                Isto também pode ser naturalmente desligado (removendo a opção de configuração) ou redirecionando
+                para um arquivo com ajuda do <literal>SchemaExport</literal> nas tarefas do Ant. 
+                Finalmente, iremos adicionar os arquivos das classes de persistência mapeadas na configuração.
+            </para>
+
+            <para>
+                Copie este arquivo no diretório fonte, assim isto irá terminar na raiz (root) do 
+                classpath. O Hibernate automaticamente procura por um arquivo chamado 
+                <literal>hibernate.cfg.xml</literal> na raiz do classpath, no startup.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-ant" revision="1">
+            <title>Construindo com o Ant</title>
+
+            <para>
+                Nos iremos, agora, construir o tutorial com Ant. Você ira precisar o Ant instalado – 
+                se encontra disponível  <ulink url="http://ant.apache.org/bindownload.cgi">na página de download do Ant</ulink>. 
+                Como instalar o Ant, não será abordado aqui. Caso tenha alguma dúvida, por favor, 
+                vá ao <ulink url="http://ant.apache.org/manual/index.html">Ant manual</ulink>.
+                Depois que tiver instalado o Ant, podemos começar a criar o arquivo de construção <literal>build.xml</literal>. 
+                Este arquivo será chamado de <literal>build.xml</literal> e posto diretamente no diretório de desenvolvimento.
+            </para>
+
+            <para>
+                Um arquivo básico de build, se parece com isto:
+            </para>
+
+            <programlisting><![CDATA[<project name="hibernate-tutorial" default="compile">
+
+    <property name="sourcedir" value="${basedir}/src"/>
+    <property name="targetdir" value="${basedir}/bin"/>
+    <property name="librarydir" value="${basedir}/lib"/>
+
+    <path id="libraries">
+        <fileset dir="${librarydir}">
+            <include name="*.jar"/>
+        </fileset>
+    </path>
+
+    <target name="clean">
+        <delete dir="${targetdir}"/>
+        <mkdir dir="${targetdir}"/>
+    </target>
+
+    <target name="compile" depends="clean, copy-resources">
+      <javac srcdir="${sourcedir}"
+             destdir="${targetdir}"
+             classpathref="libraries"/>
+    </target>
+
+    <target name="copy-resources">
+        <copy todir="${targetdir}">
+            <fileset dir="${sourcedir}">
+                <exclude name="**/*.java"/>
+            </fileset>
+        </copy>
+    </target>
+
+</project>]]></programlisting>
+
+            <para>
+                Isto irá avisar ao Ant para adicionar todos os arquivos no diretório lib terminando com 
+                <literal>.jar</literal>, para o classpath usado para compilação. Irá também copiar todos os 
+                arquivos não-java para o diretório alvo (arquivos de configuração, mapeamento). Se você rodar 
+                o ant agora, deverá ter esta saída.              
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant
+Buildfile: build.xml
+
+copy-resources:
+     [copy] Copying 2 files to C:\hibernateTutorial\bin
+
+compile:
+    [javac] Compiling 1 source file to C:\hibernateTutorial\bin
+
+BUILD SUCCESSFUL
+Total time: 1 second ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-helpers" revision="3">
+            <title>Startup and helpers</title>
+
+            <para>
+                É hora de carregar e arquivar alguns objetos <literal>Event</literal>, mas primeiro 
+                nós temos de completar o setup com algum código de infraestrutura. Este startup 
+                inclui a construção de um objeto  <literal>SessionFactory</literal>  global e  armazenar
+                isto em algum lugar de fácil acesso para o código da aplicação.
+                Uma <literal>SessionFactory</literal> pode abrir novas <literal>Session</literal>'s. 
+                Uma <literal>Session</literal> representa uma unidade single-theaded do trabalho, a 
+                <literal>SessionFactory</literal> é um objeto global thread-safe, instanciado uma vez.
+            </para>
+
+            <para>
+                Nos iremos criar uma classe de ajuda <literal>HibernateUtil</literal>, que toma 
+                conta do startup e faz acesso a uma <literal>SessionFactory</literal> conveniente. 
+                Vamos dar uma olhada na implementação:
+            </para>
+
+            <programlisting><![CDATA[package util;
+
+import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+    private static final SessionFactory sessionFactory;
+
+    static {
+        try {
+            // Create the SessionFactory from hibernate.cfg.xml
+            sessionFactory = new Configuration().configure().buildSessionFactory();
+        } catch (Throwable ex) {
+            // Make sure you log the exception, as it might be swallowed
+            System.err.println("Initial SessionFactory creation failed." + ex);
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    public static SessionFactory getSessionFactory() {
+        return sessionFactory;
+    }
+
+}]]></programlisting>
+
+            <para>
+                 Esta classe não só produz a global <literal>SessionFactory</literal> no seu static initializer
+                (chamado uma vez pela JVM quando a classe é carregada), mas também esconde o fato 
+                de que isto usa um static singleton. Ela pode muito bem, enxergar a 
+                <literal>SessionFactory</literal> do JNDI em um application server.
+            </para>
+
+            <para>
+                Se você der à <literal>SessionFactory</literal> um nome, no seu arquivo de configuração. 
+                O Hibernate irá, de fato, tentar uni-lo ao JNDI depois que estiver construído. 
+                Para evitar este completamente este código, você também poderia usar JMX deployment 
+                e deixar o contêiner JMX capaz, instanciar e unir um <literal>HibernateService</literal> 
+                no JNDI. Essas opções avançadas são discutidas no documento de referência do Hibernate.
+            </para>
+
+            <para>
+                Coloque o Place <literal>HibernateUtil.java</literal> no diretório de arquivos 
+                de desenvolvimento(source), em um pacote após o <literal>events</literal>:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java
+    Event.hbm.xml
+  +util
+    HibernateUtil.java
+  hibernate.cfg.xml
++data
+build.xml]]></programlisting>
+
+            <para>
+                 Novamente, isto deve compilar sem problemas. Finalmente, nós precisamos configurar 
+                um sistema de logging – o Hibernate usa commons logging e deixa você escolher entre o 
+                Log4j e o logging do JDK 1.4 . A maioria dos desenvolvedores preferem o Log4j: copie 
+                <literal>log4j.properties</literal> da distribuição do Hibernate (está no diretório 
+                <literal>etc/</literal>), para seu diretório  <literal>src</literal>, 
+                depois vá em hibernate.cfg.xml. Dê uma olhada no exemplo de configuração e mude as
+                configurações se você quizer ter uma saída mais detalhada. Por default, apenas as
+                mensagems de startup  e shwwn do Hibernate é mostrada no stdout.
+            </para>
+
+            <para>
+                O tutorial de infra-estrutura está completo - e nós já estamos preparados para algum 
+                trabalho de verdade com o Hibernate.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-workingpersistence" revision="4">
+            <title>Carregando e salvando objetos</title>
+
+            <para>
+                Finalmente, nós podemos usar o Hibernate para carregar e armazenar objetos. 
+                Nós escrevemos uma classe <literal>EventManager</literal> com um método main():
+            </para>
+
+            <programlisting><![CDATA[package events;
+import org.hibernate.Session;
+
+import java.util.Date;
+
+import util.HibernateUtil;
+
+public class EventManager {
+
+    public static void main(String[] args) {
+        EventManager mgr = new EventManager();
+
+        if (args[0].equals("store")) {
+            mgr.createAndStoreEvent("My Event", new Date());
+        }
+
+        HibernateUtil.getSessionFactory().close();
+    }
+
+    private void createAndStoreEvent(String title, Date theDate) {
+
+        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+        session.beginTransaction();
+
+        Event theEvent = new Event();
+        theEvent.setTitle(title);
+        theEvent.setDate(theDate);
+
+        session.save(theEvent);
+
+        session.getTransaction().commit();
+    }
+
+}]]></programlisting>
+
+            <para>
+                We create a new <literal>Event</literal> object, and hand it over to Hibernate.
+                Hibernate now takes care of the SQL and executes <literal>INSERT</literal>s
+                on the database. Let's have a look at the <literal>Session</literal> and
+                <literal>Transaction</literal>-handling code before we run this.
+                
+                Nós criamos um novo objeto <literal>Event</literal>, e passamos para o Hibernate. 
+                O Hibernate sabe como tomar conta do SQL e executa <literal>INSERT</literal>s 
+                no banco de dados. Vamos dar uma olhada na <literal>Session</literal> e no 
+                código <literal>Transaction</literal>-handling antes de executarmos.
+            </para>
+
+            <para>
+  		Um <literal>Session</literal> é uma unidade simples de trabalho. Por agora nós 
+		iremos pegar coisas simples e assumir uma granularidade de um-pra-um entre uma 
+		<literal>Session</literal> do Hibernate e uma transação de banco de dados. 
+		Para proteger nosso código de um atual sistema subjacente de transação (nesse 
+		caso puro JDBC, mas também poderia rodar com JTA), nos usamos a API 
+		<literal>Transaction</literal>, que está disponível na <literal>Session</literal> do Hibernate.
+            </para>
+
+            <para>
+                O que a <literal>sessionFactory.getCurrentSession()</literal> faz? Primeiro, você pode 
+                chamar quantas vezes e de onde quiser, uma vez você recebe sua <literal>SessionFactory</literal>
+                (fácil graças ao <literal>HibernateUtil</literal>). O método <literal>getCurrentSession()</literal>
+                sempre retorna a unidade de trabalho "corrente". Lembra de que nós mudamos a opção 
+                de configuração desse mecanismo para thread no <literal>hibernate.cfg.xml</literal>? Daqui em
+                diante, o escopo da unidade de trabalho corrente é a thread Java 
+                corrente que executa nossa aplicação. Entretanto, esta não é toda a verdade. Uma 
+                <literal>Session</literal> começa quando é primeiramente necessária, quando é feita a 
+                primeira chamada à <literal>getCurrentSession()</literal>. É então limitado pelo Hibernate 
+                para thread corrente. Quando a transação termina, tanto com commit quanto rollback, 
+                o Hibernate também desune a <literal>Session</literal> da thread e fecha isso pra você. 
+                Se você chamar <literal>getCurrentSession()</literal> novamente, você receberá uma nova 
+                <literal>Session</literal> e pode começar uma nova unidade de trabalho. Esse modelo de 
+                programação de limite de thread  <emphasis>thread-bound</emphasis>, é o modo mais popular 
+                de se usar o Hibernate.
+           </para>
+
+            <para>
+		Dê uma olhada no <xref linkend="transactions"/>  para mais informações a 
+		respeito de manipulação de transação e demarcação. Nós também pulamos qualquer 
+		manipulação de erro e rollback no exemplo anterior.
+            </para>
+
+            <para>
+		Para executar esta primeira rotina, nos teremos que adicionar um ponto de chamada 
+		para o arquivo de build do Ant:
+            </para>
+
+            <programlisting><![CDATA[<target name="run" depends="compile">
+    <java fork="true" classname="events.EventManager" classpathref="libraries">
+        <classpath path="${targetdir}"/>
+        <arg value="${action}"/>
+    </java>
+</target>]]></programlisting>
+
+            <para>
+                O valor do argumento <literal>action</literal>, é setado na linha de comando quando chamando esse ponto:
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant run -Daction=store]]></programlisting>
+
+            <para>
+                Você deverá ver, após a compilação, o startup do Hibernate e, dependendo da sua 
+                configuração, muito log de saída. No final você verá a seguinte linha:
+            </para>
+
+            <programlisting><![CDATA[[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)]]></programlisting>
+
+            <para>
+                Este é o <literal>INSERT</literal> executado pelo Hibernate, os pontos de interrogação 
+                representam parêmetros de união do JDBC. Para ver os valores substituídos, ou para diminuir a 
+                verbalidade do log, check seu l<literal>log4j.properties</literal>.
+            </para>
+
+            <para>
+             	Agora nós gostaríamos de listar os eventos arquivados, então nós adicionamos uma 
+             	opção para o método main:
+            </para>
+
+            <programlisting><![CDATA[if (args[0].equals("store")) {
+    mgr.createAndStoreEvent("My Event", new Date());
+}
+else if (args[0].equals("list")) {
+    List events = mgr.listEvents();
+    for (int i = 0; i < events.size(); i++) {
+        Event theEvent = (Event) events.get(i);
+        System.out.println("Event: " + theEvent.getTitle() +
+                           " Time: " + theEvent.getDate());
+    }
+}]]></programlisting>
+
+            <para>
+                Nos também adicionamos um novo <literal>método listEvents()</literal>:
+            </para>
+
+            <programlisting><![CDATA[private List listEvents() {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+    session.beginTransaction();
+
+    List result = session.createQuery("from Event").list();
+
+    session.getTransaction().commit();
+
+    return result;
+}]]></programlisting>
+
+            <para>
+                O que nós fazemos aqui, é usar uma query HQL (Hibernate Query Language), 
+                para carregar todos os objetos <literal>Event</literal>  exitentes no banco de dados. 
+                O Hibernate irá gerar o SQL apropriado, enviar para o banco de dados e popular objetos 
+                <literal>Event</literal> com os dados. Você pode criar queries mais complexas com 
+                HQL, claro.
+            </para>
+
+            <para>
+                Agora, para executar e testar tudo isso, siga os passos a seguir:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        Execute <literal>ant run -Daction=store</literal>  para armazenar algo no banco de dados 
+                        e, claro, gerar o esquema do banco de dados antes pelo hbm2ddl.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Agora desabilite hbm2ddl comentando a propriedade no seu arquivo <literal>hibernate.cfg.xml</literal>. 
+                        Normalmente só se deixa habilitado em teste unitários contínuos, mas outra carga de  hbm2ddl 
+                        pode <emphasis>remover</emphasis> tudo que você já tenha arquivado. Sa configuração  
+                        <literal>create</literal>, atualmente são traduzidas para "apague todas as tabelas do esquema, 
+                        então recrie todas quando a SessionFactory estiver pronta".
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Se você agora chamar o Ant com <literal>-Daction=list</literal>, você deverá ver os 
+                eventos que você acabou de criar. Você pode também chamar a ação <literal>store</literal> 
+                mais algumas vezes. 
+            </para>
+
+            <para>
+                Nota: A maioria dos novos usuários do Hibernate falha nesse ponto e nós regularmente, vemos 
+                questões sobre mensagens de erro de <emphasis>tabela não encontrada </emphasis> . 
+                Entretanto, se você seguir os passos marcados acima, você não terá esse problema, 
+                com o hbm2ddl criando o esquema do banco de dados na primeira execução, e restarts
+                subsequentes da aplicação irão usar este esquema. Se você mudar o mapeamento e/ou
+                o esquema do banco de dados, terá de re-habilitar o hbm2ddl mais uma vez.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="tutorial-associations">
+        <title>Part 2 - Mapeando associações</title>
+
+        <para>
+	    Nós mapeamos uma classe de entidade de persistência para uma tabela. Agora vamos continuar
+	    e adicionar algumas associações de classe. Primeiro nos iremos adicionar pessoas a nossa aplicação, 
+	    e armazenar os eventos de que elas participam.
+        </para>
+
+        <sect2 id="tutorial-associations-mappinguser" revision="1">
+            <title>Mapeando a classe Person</title>
+
+            <para>
+                O primeiro código da classe <literal>Person</literal> é simples:
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+public class Person {
+
+    private Long id;
+    private int age;
+    private String firstname;
+    private String lastname;
+
+    public Person() {}
+
+    // Accessor methods for all properties, private setter for 'id'
+
+}]]></programlisting>
+
+            <para>
+                Crie um novo arquivo de mapeamento, chamado <literal>Person.hbm.xml</literal> (não 
+                esqueça a referencia ao DTD no topo)
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Person" table="PERSON">
+        <id name="id" column="PERSON_ID">
+            <generator class="native"/>
+        </id>
+        <property name="age"/>
+        <property name="firstname"/>
+        <property name="lastname"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                Finalmente, adicione o novo mapeamento a configuração do Hibernate:
+            </para>
+
+            <programlisting><![CDATA[<mapping resource="events/Event.hbm.xml"/>
+<mapping resource="events/Person.hbm.xml"/>]]></programlisting>
+
+            <para>
+                Nos iremos agora criar uma associação entre estas duas entidades. Obviamente, 
+                pessoas (Person) podem participar de eventos, e eventos possuem participantes. 
+                As questões de design com que teremos de lidar são: direcionalidade, multiplicidade e 
+                comportamento de coleção.
+              </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-unidirset" revision="3">
+            <title>Uma associação Set-based unidirectional</title>
+
+            <para>
+                Nos iremos adicionar uma coleção de eventos na classe <literal>Person</literal>. Desse jeito 
+                poderemos navegar pelos eventos de uma pessoa em particular, sem executar uma query explicitamente – 
+                apenas chamando  <literal>aPerson.getEvents()</literal>. Nos usaremos uma coleção Java, um  
+                <literal>Set</literal>, porquê a coleção não conterá elementos duplicados e a ordem não é 
+                relevante para nós.
+            </para>
+
+            <para>
+                Vamos escrever o código para isto nas classes Java e então mapear:
+            </para>
+
+            <programlisting><![CDATA[public class Person {
+
+    private Set events = new HashSet();
+
+    public Set getEvents() {
+        return events;
+    }
+
+    public void setEvents(Set events) {
+        this.events = events;
+    }
+}]]></programlisting>
+
+            <para>
+                Antes de mapearmos esta associação, pense no outro lado. Claramente, poderíamos apenas fazer isto de 
+                forma unidirecional. Ou poderíamos criar outra coleção no  <literal>Event</literal>, se quisermos 
+                ser capaz de navegar bidirecionalmente, i.e. um - <literal>anEvent.getParticipants()</literal>. 
+                Isto não é necessário, de perspectiva funcional. Você poderia sempre executar uma query explicita 
+                que retornasse os participantes de um evento em particular. Esta é uma escolha de design que cabe 
+                a você, mas o que é claro nessa discussão é a multiplicidade da associação: "muitos" valores em ambos 
+                os lados, nós chamamos isto uma associação <emphasis>muitos-para-muitos</emphasis>. Daqui pra frente, 
+                nos usaremos o mapeamento muitos-para-muitos do Hibernate:
+            </para>
+
+            <programlisting><![CDATA[<class name="events.Person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="native"/>
+    </id>
+    <property name="age"/>
+    <property name="firstname"/>
+    <property name="lastname"/>
+
+    <set name="events" table="PERSON_EVENT">
+        <key column="PERSON_ID"/>
+        <many-to-many column="EVENT_ID" class="events.Event"/>
+    </set>
+
+</class>]]></programlisting>
+
+            <para>
+                O Hibernate suporta todo tipo de mapeamento de coleção , sendo um <literal>&lt;set&gt;</literal> mais comum. 
+                Para uma associação muitos-para-muitos (ou relacionamento de entidade <emphasis>n:m</emphasis> ), 
+                uma tabela de associação é necessária. Cada linha nessa tabela representa um link entre uma pessoa e um 
+                evento. O nome da tabela é configurado com o atributo <literal>table</literal> do elemento 
+                <literal>set</literal>. O nome da coluna identificadora na associção, peloo lado da pessoa, 
+                é definido com o elemento <literal>&lt;key&gt;</literal> , o nome da coluna pelo lado dos eventos, 
+                e definido com o atributo <literal>column</literal>  do  <literal>&lt;many-to-many&gt;</literal>. 
+                Você também precisa dizer para o Hibernate a classe dos objetos na sua coleção (a classe do outro 
+                lado das coleções de referência).
+            </para>
+
+            <para>
+                O esquema de mapeamento para o banco de dados está a seguir:
+            </para>
+
+            <programlisting><![CDATA[
+    _____________        __________________
+   |             |      |                  |       _____________
+   |   EVENTS    |      |   PERSON_EVENT   |      |             |
+   |_____________|      |__________________|      |    PERSON   |
+   |             |      |                  |      |_____________|
+   | *EVENT_ID   | <--> | *EVENT_ID        |      |             |
+   |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  |
+   |  TITLE      |      |__________________|      |  AGE        |
+   |_____________|                                |  FIRSTNAME  |
+                                                  |  LASTNAME   |
+                                                  |_____________|
+ ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-working" revision="1">
+            <title>Trabalhando a associação</title>
+
+            <para>
+                Vamos trazer juntos algumas pessoas e eventos em um novo método na classe <literal>EventManager</literal>::
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    aPerson.getEvents().add(anEvent);
+
+    session.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                Após carregar um <literal>Person</literal> e um <literal>Event</literal>, simplesmente 
+                modifique a coleção usando os métodos normais de uma coleção. Como você pode ver, não há chamada explícita 
+                para <literal>update()</literal> ou <literal>save()</literal>,  o Hibernate detecta automaticamente 
+                que a coleção foi modificada e necessita ser atualizada. Isso é chamado de <emphasis>checagem 
+                suja automática</emphasis>, e você também pode usá-la modificando o nome ou a data de qualquer um dos 
+                seus objetos. Assim que eles estiverem no estado <emphasis>persistent</emphasis>, ou seja, 
+                limitado por uma <literal>Session</literal> do Hibernate em particular (i.e. eles foram carregados ou 
+                salvos dentro de uma unidade de trabalho), o Hibernate monitora qualquer alteração e executa o SQL 
+                em modo de escrita em segundo plano. O processo de sincronização do estado da memória com o banco de 
+                dados, geralmente apenas no final de uma unidade de trabalho, é chamado de  <emphasis>flushing</emphasis>. 
+                No nosso código, a unidade de trabalho termina com o commit da transação do banco de dados – 
+                como definido pela opção de configuração da  <literal>thread</literal> da classe <literal>CurrentSessionContext</literal>.
+            </para>
+
+            <para>
+                Você pode também querer carregar pessoas e eventos em diferentes unidades de trabalho. 
+                Ou você modifica um objeto fora de uma <literal>Session</literal>, quando não se encontra no 
+                estado persistent (se já esteve neste estado anteriormente, chamamos esse estado de 
+                <emphasis>detached</emphasis>). Você pode até mesmo modificar uma coleção quando esta 
+                se encontrar no estado detached.
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session
+            .createQuery("select p from Person p left join fetch p.events where p.id = :pid")
+            .setParameter("pid", personId)
+            .uniqueResult(); // Eager fetch the collection so we can use it detached
+
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    session.getTransaction().commit();
+
+    // End of first unit of work
+
+    aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached
+
+    // Begin second unit of work
+
+    Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
+    session2.beginTransaction();
+
+    session2.update(aPerson); // Reattachment of aPerson
+
+    session2.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                A chamada <literal>update</literal> cria um objeto persistent novamente, você poderia 
+                dizer que ele liga o objeto a uma nova unidade de trabalho, assim qualquer modificação 
+                que você faça neste objeto enquanto estiver no estado detached pode ser salvo no banco de dados. 
+                Isso inclui qualquer modificação (adição/exclusão) que você faça em uma coleção da entidade deste objeto.
+            </para>
+
+            <para>
+		Bom, isso não foi muito usado na nossa situação, porém, é um importante conceito que você 
+		pode aplicar em seus aplicativos. Agora, complete este exercício adicionando uma nova ação 
+		ao método main( ) da classe  <literal>EventManager</literal> e chame-o pela linha de comando. 
+		Se você precisar dos identificadores de uma pessoa ou evento – o método  <literal>save()</literal> 
+		retorna estes identificadores (você poderá modificar alguns dos métodos anteriores para retornar aquele 
+		identificador):
+            </para>
+
+            <programlisting><![CDATA[else if (args[0].equals("addpersontoevent")) {
+    Long eventId = mgr.createAndStoreEvent("My Event", new Date());
+    Long personId = mgr.createAndStorePerson("Foo", "Bar");
+    mgr.addPersonToEvent(personId, eventId);
+    System.out.println("Added person " + personId + " to event " + eventId);]]></programlisting>
+
+            <para>
+                 Este foi um exemplo de uma associação entre duas classes igualmente importantes, duas entidades. 
+                Como mencionado anteriormente, há outras classes e tipos dentro de um modelo típico, 
+                geralmente "menos importante". Alguns você já viu, como um  <literal>int</literal> ou uma <literal>String</literal>.
+                Nós chamamos essas classes de <emphasis>value types</emphasis>, e suas instâncias <emphasis>depend</emphasis>
+                de uma entidade particular. As instâncias desses tipos não possuem sua própria identidade, nem são 
+                compartilhados entre entidades (duas pessoas não referenciam o mesmo objeto  <literal>firstname</literal>
+                mesmo se elas tiverem o mesmo objeto firstname). Naturalmente, os value types não são apenas encontrados 
+                dentro da JDK (de fato, em um aplicativo Hibernate todas as classes JDK são consideradas como value types), 
+                mas você pode também criar suas classes como, por exemplo,  <literal>Address</literal> ou  <literal>MonetaryAmount</literal>.
+
+            </para>
+
+            <para>
+                Você também pode criar uma coleção de value types. Isso é conceitualmente muito diferente 
+                de uma coleção de referências para outras entidades, mas em Java parece ser quase a mesma coisa.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-valuecollections">
+            <title>Coleção de valores</title>
+
+            <para>
+                Nós adicionamos uma coleção de objetos de tipo de valores à entidade <literal>Person</literal. 
+                Nós querermos armazenar endereços de e-mail, para isso utilizamos o tipo <literal>String</literal>, 
+                e a coleção novamente será um <literal>Set</literal>:
+            </para>
+            <programlisting><![CDATA[private Set emailAddresses = new HashSet();
+
+public Set getEmailAddresses() {
+    return emailAddresses;
+}
+
+public void setEmailAddresses(Set emailAddresses) {
+    this.emailAddresses = emailAddresses;
+}]]></programlisting>
+
+            <para>
+                O mapeamento deste <literal>Set</literal>:
+            </para>
+
+            <programlisting><![CDATA[<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
+    <key column="PERSON_ID"/>
+    <element type="string" column="EMAIL_ADDR"/>
+</set>]]></programlisting>
+
+            <para>
+                The difference compared with the earlier mapping is the <literal>element</literal> part, which tells Hibernate that the collection
+                does not contain references to another entity, but a collection of elements of type
+                <literal>String</literal> (the lowercase name tells you it's a Hibernate mapping type/converter).
+                Once again, the <literal>table</literal> attribute of the <literal>set</literal> element determines
+                the table name for the collection. The <literal>key</literal> element defines the foreign-key column
+                name in the collection table. The <literal>column</literal> attribute in the <literal>element</literal>
+                element defines the column name where the <literal>String</literal> values will actually be stored.
+                
+                A diferença comparada com o mapeamento anterior se encontra na parte <literal>element</literal>, 
+                que indica ao Hibernate que a coleção não contém referências à outra entidade, mas uma coleção de 
+                elementos do tipo <literal>String</literal> (a tag name em miniscula indica que se trata de um 
+                mapeamento do Hibernate para conversão de tipos). Mais uma vez, o atributo  <literal>table</literal> 
+                do elemento <literal>set</literal> determina o nome da tabela para a coleção. O elemento 
+                <literal>key</literal> define o nome da coluna  de chave estrangeira na tabela de coleção. 
+                O atributo <literal>column</literal> dentro do elemento <literal>element</literal> define o 
+                nome da coluna onde os valores da <literal>String</literal> serão armazenados.
+            </para>
+
+            <para>
+                Dê uma olhada no esquema atualizado:
+            </para>
+
+            <programlisting><![CDATA[
+  _____________        __________________
+ |             |      |                  |       _____________
+ |   EVENTS    |      |   PERSON_EVENT   |      |             |       ___________________
+ |_____________|      |__________________|      |    PERSON   |      |                   |
+ |             |      |                  |      |_____________|      | PERSON_EMAIL_ADDR |
+ | *EVENT_ID   | <--> | *EVENT_ID        |      |             |      |___________________|
+ |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  | <--> |  *PERSON_ID       |
+ |  TITLE      |      |__________________|      |  AGE        |      |  *EMAIL_ADDR      |
+ |_____________|                                |  FIRSTNAME  |      |___________________|
+                                                |  LASTNAME   |
+                                                |_____________|
+ ]]></programlisting>
+
+            <para>
+                Você pode observar que a chave primária da tabela da coleção é de na verdade uma chave composta, 
+                usando ambas colunas. Isso também implica que cada pessoa não pode ter endereços de e-mail 
+                duplicados, o que é exatamente a semântica que precisamos para um set em Java.
+            </para>
+
+            <para>
+                Você pode agora tentar adicionar elementos a essa coleção, do mesmo modo que fizemos 
+                anteriormente ligando pessoas e eventos. È o mesmo código em Java:
+            </para>
+
+            <programlisting><![CDATA[private void addEmailToPerson(Long personId, String emailAddress) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+
+    // The getEmailAddresses() might trigger a lazy load of the collection
+    aPerson.getEmailAddresses().add(emailAddress);
+
+    session.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                This time we didnt' use a <emphasis>fetch</emphasis> query to initialize the collection.
+                Hence, the call to its getter method will trigger an additional select to initialize
+                it, so we can add an element to it. Monitor the SQL log and try to optimize this with
+                an eager fetch.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-bidirectional" revision="1">
+            <title>Associações bidirecionais</title>
+
+            <para>
+                Agora iremos mapear uma associação bidirecional – fazendo a associação entre pessoas e 
+                eventos, de ambos os lados, em Java. Logicamente, o esquema do banco de dados não muda, 
+                nós continuamos tendo multiplicidades muitos-para-muitos. Um banco de dados é mais flexível do que 
+                uma linguagem de programação para redes, ele não precisa de nenhuma direção de navegação – os 
+                dados podem ser acessados em qualquer caminho possível.
+            </para>
+
+            <para>
+                Primeiramente, adicione uma coleção de participantes à classe <literal>Event</literal>:
+            </para>
+
+            <programlisting><![CDATA[private Set participants = new HashSet();
+
+public Set getParticipants() {
+    return participants;
+}
+
+public void setParticipants(Set participants) {
+    this.participants = participants;
+}]]></programlisting>
+
+            <para>
+                Agora mapeie este lado da associação em <literal>Event.hbm.xml</literal>.
+            </para>
+
+            <programlisting><![CDATA[<set name="participants" table="PERSON_EVENT" inverse="true">
+    <key column="EVENT_ID"/>
+    <many-to-many column="PERSON_ID" class="events.Person"/>
+</set>]]></programlisting>
+
+            <para>
+                Como você pode ver, esses é uma mapeamento normal usando <literal>set</literal> em ambos documenentos
+                de mapeamento. Observe que o nome das colunas em  <literal>key</literal> e <literal>many-to-many</literal>
+                estão trocados em ambos os documentos de mapeamento. A adição mais importante feita está no atributo 
+                <literal>inverse="true"</literal> no elemento set do mapeamento da coleção da classe  <literal>Event</literal>.
+            </para>
+
+            <para>
+                Isso significa que o Hibernate deve pegar o outro lado – a classe <literal>Person</literal> – 
+                quando necessitar encontrar informação sobre a relação entre as duas entidades. Isso será muito 
+                mais facilmente compreendido quando você analisar como a relação bidirecional entre as entidades é criada. 
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-usingbidir">
+            <title>Trabalhando com links bidirecionais</title>
+
+            <para>
+                Primeiro tenha em mente que o Hibernate não afeta a semântica normal do Java. Como nós criamos 
+                um link entre uma <literal>Person</literal> e um <literal>Event</literal> no exemplo unidirecional? 
+                Nós adicionamos uma instância de <literal>Event</literal>, da coleção de referências de eventos, 
+                a uma instância de <literal>Person</literal>. Então, obviamente, se nós queremos que este link funcione 
+                bidirecionalmente, nós devemos fazer a mesma coisa para o outro lado – adicionando uma referência de 
+                <literal>Person</literal> na coleção de um <literal>Event</literal>. Esse acerto de link de ambos 
+                os lados é absolutamente necessário e você nunca deve esquecer de faze-lo.
+            </para>
+
+            <para>
+                Muitos desenvolvedores programam de maneira defensiva e criam métodos
+                gerenciador de links que ajusta corretamente ambos os lados:
+            </para>
+
+            <programlisting><![CDATA[protected Set getEvents() {
+    return events;
+}
+
+protected void setEvents(Set events) {
+    this.events = events;
+}
+
+public void addToEvent(Event event) {
+    this.getEvents().add(event);
+    event.getParticipants().add(this);
+}
+
+public void removeFromEvent(Event event) {
+    this.getEvents().remove(event);
+    event.getParticipants().remove(this);
+}]]></programlisting>
+
+            <para>
+                Notice that the get and set methods for the collection are now protected - this allows classes in the
+                same package and subclasses to still access the methods, but prevents everybody else from messing
+                with the collections directly (well, almost). You should probably do the same with the collection
+                on the other side.
+            </para>
+
+            <para>
+                What about the <literal>inverse</literal> mapping attribute? For you, and for Java, a bi-directional
+                link is simply a matter of setting the references on both sides correctly. Hibernate however doesn't
+                have enough information to correctly arrange SQL <literal>INSERT</literal> and <literal>UPDATE</literal>
+                statements (to avoid constraint violations), and needs some help to handle bi-directional associations
+                properly. Making one side of the association <literal>inverse</literal> tells Hibernate to basically
+                ignore it, to consider it a <emphasis>mirror</emphasis> of the other side. That's all that is necessary
+                for Hibernate to work out all of the issues when transformation a directional navigation model to
+                a SQL database schema. The rules you have to remember are straightforward: All bi-directional associations
+                need one side as <literal>inverse</literal>. In a one-to-many association it has to be the many-side,
+                in many-to-many association you can pick either side, there is no difference.
+            </para>
+
+        </sect2>
+
+        <para>
+            Let's turn this into a small web application.
+        </para>
+
+    </sect1>
+
+    <sect1 id="tutorial-webapp">
+        <title>Part 3 - The EventManager web application</title>
+
+        <para>
+            A Hibernate web application uses <literal>Session</literal> and <literal>Transaction</literal>
+            almost like a standalone application. However, some common patterns are useful. We now write
+            an <literal>EventManagerServlet</literal>. This servlet can list all events stored in the
+            database, and it provides an HTML form to enter new events.
+        </para>
+
+        <sect2 id="tutorial-webapp-servlet" revision="1">
+            <title>Writing the basic servlet</title>
+
+            <para>
+                Create a new class in your source directory, in the <literal>events</literal>
+                package:
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+// Imports
+
+public class EventManagerServlet extends HttpServlet {
+
+    // Servlet code
+}]]></programlisting>
+
+            <para>
+                The servlet handles HTTP <literal>GET</literal> requests only, hence, the method
+                we implement is <literal>doGet()</literal>:
+            </para>
+
+            <programlisting><![CDATA[protected void doGet(HttpServletRequest request,
+                     HttpServletResponse response)
+        throws ServletException, IOException {
+
+    SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
+
+    try {
+        // Begin unit of work
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().beginTransaction();
+
+        // Process request and render page...
+
+        // End unit of work
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().getTransaction().commit();
+
+    } catch (Exception ex) {
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().getTransaction().rollback();
+        throw new ServletException(ex);
+    }
+
+}]]></programlisting>
+
+            <para>
+                The pattern we are applying here is called <emphasis>session-per-request</emphasis>.
+                When a request hits the servlet, a new Hibernate <literal>Session</literal> is
+                opened through the first call to <literal>getCurrentSession()</literal> on the
+                <literal>SessionFactory</literal>. Then a database transaction is started&mdash;all
+                data access as to occur inside a transaction, no matter if data is read or written
+                (we don't use the auto-commit mode in applications).
+            </para>
+
+            <para>
+                Next, the possible actions of the request are processed and the response HTML
+                is rendered. We'll get to that part soon.
+            </para>
+
+            <para>
+                Finally, the unit of work ends when processing and rendering is complete. If any
+                problem occured during processing or rendering, an exception will be thrown
+                and the database transaction rolled back. This completes the
+                <literal>session-per-request</literal> pattern. Instead of the transaction
+                demarcation code in every servlet you could also write a servlet filter.
+                See the Hibernate website and Wiki for more information about this pattern,
+                called <emphasis>Open Session in View</emphasis>&mdash;you'll need it as soon
+                as you consider rendering your view in JSP, not in a servlet.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-webapp-processing" revision="1">
+            <title>Processing and rendering</title>
+
+            <para>
+                Let's implement the processing of the request and rendering of the page.
+            </para>
+
+<programlisting><![CDATA[// Write HTML header
+PrintWriter out = response.getWriter();
+out.println("<html><head><title>Event Manager</title></head><body>");
+
+// Handle actions
+if ( "store".equals(request.getParameter("action")) ) {
+
+    String eventTitle = request.getParameter("eventTitle");
+    String eventDate = request.getParameter("eventDate");
+
+    if ( "".equals(eventTitle) || "".equals(eventDate) ) {
+        out.println("<b><i>Please enter event title and date.</i></b>");
+    } else {
+        createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
+        out.println("<b><i>Added event.</i></b>");
+    }
+}
+
+// Print page
+printEventForm(out);
+listEvents(out, dateFormatter);
+
+// Write HTML footer
+out.println("</body></html>");
+out.flush();
+out.close();]]></programlisting>
+
+            <para>
+                Granted, this coding style with a mix of Java and HTML would not scale
+                in a more complex application&mdash;keep in mind that we are only illustrating
+                basic Hibernate concepts in this tutorial. The code prints an HTML
+                header and a footer. Inside this page, an HTML form for event entry and
+                a list of all events in the database are printed. The first method is
+                trivial and only outputs HTML:
+            </para>
+
+            <programlisting><![CDATA[private void printEventForm(PrintWriter out) {
+    out.println("<h2>Add new event:</h2>");
+    out.println("<form>");
+    out.println("Title: <input name='eventTitle' length='50'/><br/>");
+    out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");
+    out.println("<input type='submit' name='action' value='store'/>");
+    out.println("</form>");
+}]]></programlisting>
+
+            <para>
+                The <literal>listEvents()</literal> method uses the Hibernate
+                <literal>Session</literal> bound to the current thread to execute
+                a query:
+            </para>
+
+            <programlisting><![CDATA[private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) {
+
+    List result = HibernateUtil.getSessionFactory()
+                    .getCurrentSession().createCriteria(Event.class).list();
+    if (result.size() > 0) {
+        out.println("<h2>Events in database:</h2>");
+        out.println("<table border='1'>");
+        out.println("<tr>");
+        out.println("<th>Event title</th>");
+        out.println("<th>Event date</th>");
+        out.println("</tr>");
+        for (Iterator it = result.iterator(); it.hasNext();) {
+            Event event = (Event) it.next();
+            out.println("<tr>");
+            out.println("<td>" + event.getTitle() + "</td>");
+            out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
+            out.println("</tr>");
+        }
+        out.println("</table>");
+    }
+}]]></programlisting>
+
+            <para>
+                Finally, the <literal>store</literal> action is dispatched to the
+                <literal>createAndStoreEvent()</literal> method, which also uses
+                the <literal>Session</literal> of the current thread:
+            </para>
+
+            <programlisting><![CDATA[protected void createAndStoreEvent(String title, Date theDate) {
+    Event theEvent = new Event();
+    theEvent.setTitle(title);
+    theEvent.setDate(theDate);
+
+    HibernateUtil.getSessionFactory()
+                    .getCurrentSession().save(theEvent);
+}]]></programlisting>
+
+            <para>
+                That's it, the servlet is complete. A request to the servlet will be processed
+                in a single <literal>Session</literal> and <literal>Transaction</literal>. As
+                earlier in the standalone application, Hibernate can automatically bind these
+                ojects to the current thread of execution. This gives you the freedom to layer
+                your code and access the <literal>SessionFactory</literal> in any way you like.
+                Usually you'd use a more sophisticated design and move the data access code
+                into data access objects (the DAO pattern). See the Hibernate Wiki for more
+                examples.
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-webapp-deploy">
+            <title>Deploying and testing</title>
+
+            <para>
+                To deploy this application you have to create a web archive, a WAR. Add the
+                following Ant target to your <literal>build.xml</literal>:
+            </para>
+
+<programlisting><![CDATA[<target name="war" depends="compile">
+    <war destfile="hibernate-tutorial.war" webxml="web.xml">
+        <lib dir="${librarydir}">
+          <exclude name="jsdk*.jar"/>
+        </lib>
+
+        <classes dir="${targetdir}"/>
+    </war>
+</target>]]></programlisting>
+
+            <para>
+                This target creates a file called <literal>hibernate-tutorial.war</literal>
+                in your project directory. It packages all libraries and the <literal>web.xml</literal>
+                descriptor, which is expected in the base directory of your project:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+    xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+    <servlet>
+        <servlet-name>Event Manager</servlet-name>
+        <servlet-class>events.EventManagerServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Event Manager</servlet-name>
+        <url-pattern>/eventmanager</url-pattern>
+    </servlet-mapping>
+</web-app>]]></programlisting>
+
+            <para>
+                Before you compile and deploy the web application, note that an additional library
+                is required: <literal>jsdk.jar</literal>. This is the Java servlet development kit,
+                if you don't have this library already, get it from the Sun website and copy it to
+                your library directory. However, it will be only used for compliation and excluded
+                from the WAR package.
+            </para>
+
+            <para>
+                To build and deploy call <literal>ant war</literal> in your project directory
+                and copy the <literal>hibernate-tutorial.war</literal> file into your Tomcat
+                <literal>webapp</literal> directory. If you don't have Tomcat installed, download
+                it and follow the installation instructions. You don't have to change any Tomcat
+                configuration to deploy this application though.
+            </para>
+
+            <para>
+                Once deployed and Tomcat is running, access the application at
+                <literal>http://localhost:8080/hibernate-tutorial/eventmanager</literal>. Make
+                sure you watch the Tomcat log to see Hibernate initialize when the first
+                request hits your servlet (the static initializer in <literal>HibernateUtil</literal>
+                is called) and to get the detailed output if any exceptions occurs.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="tutorial-summary" revision="1">
+        <title>Summary</title>
+
+        <para>
+            This tutorial covered the basics of writing a simple standalone Hibernate application
+            and a small web application.
+        </para>
+
+        <para>
+            If you already feel confident with Hibernate, continue browsing through the reference
+            documentation table of contents for topics you find interesting - most asked are
+            transactional processing (<xref linkend="transactions"/>), fetch
+            performance (<xref linkend="performance"/>), or the usage of the API (<xref linkend="objectstate"/>)
+            and the query features (<xref linkend="objectstate-querying"/>).
+        </para>
+
+        <para>
+            Don't forget to check the Hibernate website for more (specialized) tutorials.
+        </para>
+
+    </sect1>
+
+</chapter>


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/tutorial1.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/xml.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/xml.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/xml.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,289 @@
+<chapter id="xml">
+    <title>Mapeamento XML</title>
+
+    <para><emphasis>
+        Note that this is an experimental feature in Hibernate 3.0 and is under
+        extremely active development.
+        Veja que essa é uma feature experimental no Hibernate 3.0 e o 
+        desenvolvimento esta bastante ativo.
+        
+    </emphasis></para>
+
+    <sect1 id="xml-intro" revision="1">
+        <title>Trabalhando com dados em XML</title>
+
+        <para>
+            O Hibernate permite que se trabalhe com dados persistentes em XML quase 
+            da mesma maneira como você trabalhar com POJOs persistentes. Uma árvore XML 
+            parseada, pode ser imaginada como apenas uma maneira de representar os 
+            dados relacionais como objetos, ao invés dos POJOs.
+        </para>
+
+        <para>
+            O Hibernate suporta a API dom4j para manipular árvores XML. Você pode escrever 
+            queries que retornem árvores dom4j do banco de dados e automaticamente 
+            sincronizar com o banco de dados qualquer modificação feita nessas árvores. 
+            Você pode até mesmo pegar um documento XML, parsear usando o  dom4j, e escrever 
+            as alterações no banco de dados usando quaisquer operações básicas do Hibernate: 
+            <literal>persist(), saveOrUpdate(),merge(), delete(), replicate()</literal> 
+            (merging ainda não é suportado)
+        </para>
+
+        <para>
+            Essa funcionalidade tem várias aplicações incluindo importação/exportação de dados, 
+            externalização de dados de entidade via JMS or SOAP e relatórios usando XSLT.
+        </para>
+        
+        <para>
+            Um mapeamento simples pode ser usado para simultaneamente mapear propriedades 
+            da classe e nós de um documento XML para um banco de dados ou, se não houver 
+            classe para mapear, pode ser usado simplesmente para mapear o XML.
+        </para>
+        
+        <sect2 id="xml-intro-mapping">
+            <title>Especificando o mapeamento de uma classe e de um arquivo XML simultaneamente</title>
+
+            <para>
+                Segue um exemplo de como mapear um POJO e um XML ao mesmo tempo:
+            </para>
+            
+            <programlisting><![CDATA[<class name="Account" 
+        table="ACCOUNTS" 
+        node="account">
+        
+    <id name="accountId" 
+            column="ACCOUNT_ID" 
+            node="@id"/>
+            
+    <many-to-one name="customer" 
+            column="CUSTOMER_ID" 
+            node="customer/@id" 
+            embed-xml="false"/>
+            
+    <property name="balance" 
+            column="BALANCE" 
+            node="balance"/>
+            
+    ...
+    
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="xml-onlyxml">
+            <title>Especificando somente um mapeamento XML</title>
+
+            <para>
+                Segue um exemplo que não contém uma classe POJO:
+            </para>
+            
+            <programlisting><![CDATA[<class entity-name="Account" 
+        table="ACCOUNTS" 
+        node="account">
+        
+    <id name="id" 
+            column="ACCOUNT_ID" 
+            node="@id" 
+            type="string"/>
+            
+    <many-to-one name="customerId" 
+            column="CUSTOMER_ID" 
+            node="customer/@id" 
+            embed-xml="false" 
+            entity-name="Customer"/>
+            
+    <property name="balance" 
+            column="BALANCE" 
+            node="balance" 
+            type="big_decimal"/>
+            
+    ...
+    
+</class>]]></programlisting>
+        
+            <para>
+                Esse mapeamento permite que você acesse os dados como uma árvore dom4j ou um 
+                grafo de de pares nome de propriedade/valor (<literal>Map</literal>s do Java). 
+                Os nomes de propriedades são somente construções lógicas que podem ser 
+                referenciadas em consultas HQL.
+            </para>
+
+        </sect2>
+        
+     </sect1>
+     
+    <sect1 id="xml-mapping" revision="1">
+        <title>Mapeando metadados com XML</title>
+
+        <para>
+            Muitos elementos do mapeamento do Hibernate aceitam o atributo  <literal>node</literal>. 
+            Por meio dele, você pode especificar o nome de um atributo ou elemento XML que contém 
+            a propriedade ou os dados da entidade. O formato do atributo  <literal>node</literal>
+            deve ser o seguinte:            
+        </para>
+        
+        <itemizedlist spacing="compact">
+        <listitem>
+            <para><literal>"element-name"</literal> - mapeia para o elemento XML com determinado nome</para>
+        </listitem>
+        <listitem>
+            <para><literal>"@attribute-name"</literal> - mapeia para o atributo XML com determinado nome</para>
+        </listitem>
+        <listitem>
+            <para><literal>"."</literal> - mapeia para o elemento pai</para>
+        </listitem>
+        <listitem>
+            <para>
+                <literal>"element-name/@attribute-name"</literal> - 
+                mapeia para para o atributo com determinado nome do elemento com determinado nome
+            </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            Para coleções e associações simples, existe o atributo adicional <literal>embed-xml</literal>. 
+            Se o atributo <literal>embed-xml="true"</literal>, que é o valor padrão, a árvore XML para a 
+            entidade associada (ou coleção de determinado tipo de valor) será embutida diretamente na 
+            árvore XML que contém a associação. Por outro lado, se <literal>embed-xml="false"</literal>, 
+            então apenas o valor do identificador referenciado irá aparecer no XML para associações 
+            simples e coleções simplesmentenão irão aparecer.
+        </para>
+        
+        <para>
+            Você precisa tomar cuidado em não deixar o<literal>embed-xml="true"</literal> 
+            para muitas associações, pois o XML não suporta bem referências circulares.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Customer" 
+        table="CUSTOMER" 
+        node="customer">
+        
+    <id name="id" 
+            column="CUST_ID" 
+            node="@id"/>
+            
+    <map name="accounts" 
+            node="." 
+            embed-xml="true">
+        <key column="CUSTOMER_ID" 
+                not-null="true"/>
+        <map-key column="SHORT_DESC" 
+                node="@short-desc" 
+                type="string"/>
+        <one-to-many entity-name="Account"
+                embed-xml="false" 
+                node="account"/>
+    </map>
+    
+    <component name="name" 
+            node="name">
+        <property name="firstName" 
+                node="first-name"/>
+        <property name="initial" 
+                node="initial"/>
+        <property name="lastName" 
+                node="last-name"/>
+    </component>
+    
+    ...
+    
+</class>]]></programlisting>
+
+        <para>
+            Nesse caso, decidimos embutir a colenção de account ids, e não os dados de accounts. 
+            A query HQL a seguir:
+        </para>
+        
+        <programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
+        
+        <para>
+            Retornaria  um conjunto de dados como esse:
+        </para>
+        
+        <programlisting><![CDATA[<customer id="123456789">
+    <account short-desc="Savings">987632567</account>
+    <account short-desc="Credit Card">985612323</account>
+    <name>
+        <first-name>Gavin</first-name>
+        <initial>A</initial>
+        <last-name>King</last-name>
+    </name>
+    ...
+</customer>]]></programlisting>
+
+        <para>
+            Se você setar <literal>embed-xml="true"</literal> em um mapeamento 
+            <literal>&lt;one-to-many&gt;</literal>, os dados se pareceriam com o seguinte:
+        </para>
+        
+        <programlisting><![CDATA[<customer id="123456789">
+    <account id="987632567" short-desc="Savings">
+        <customer id="123456789"/>
+        <balance>100.29</balance>
+    </account>
+    <account id="985612323" short-desc="Credit Card">
+        <customer id="123456789"/>
+        <balance>-2370.34</balance>
+    </account>
+    <name>
+        <first-name>Gavin</first-name>
+        <initial>A</initial>
+        <last-name>King</last-name>
+    </name>
+    ...
+</customer>]]></programlisting>
+       
+    </sect1>
+    
+    
+    <sect1 id="xml-manipulation" revision="1">
+        <title>Manipulando dados em XML</title>
+        
+        <para>
+            Vamos reler e atualizar documentos em XML em nossa aplicação. Nós fazemos isso 
+            obtendo uma session do dom4j:            
+        </para>
+        
+       <programlisting><![CDATA[Document doc = ....;
+       
+Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+List results = dom4jSession
+    .createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")
+    .list();
+for ( int i=0; i<results.size(); i++ ) {
+    //add the customer data to the XML document
+    Element customer = (Element) results.get(i);
+    doc.add(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+       
+       <programlisting><![CDATA[Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+Element cust = (Element) dom4jSession.get("Customer", customerId);
+for ( int i=0; i<results.size(); i++ ) {
+    Element customer = (Element) results.get(i);
+    //change the customer name in the XML and database
+    Element name = customer.element("name");
+    name.element("first-name").setText(firstName);
+    name.element("initial").setText(initial);
+    name.element("last-name").setText(lastName);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            É extremamente útil combinar essa funcionalidade com a operação <literal>replicate()</literal>
+            do Hibernate para implementar importação/exportação baseadas em XML.
+        </para>
+       
+    </sect1>
+     
+</chapter>
+


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/docbook/modules/xml.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/css/html.css
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/css/html.css	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/css/html.css	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,97 @@
+A {
+    color: #003399;
+}
+
+A:active {
+    color: #003399;
+}
+
+A:visited {
+    color: #888888;
+}
+
+P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
+    color: #000000;
+}
+
+TD, TH, SPAN {
+    color: #000000;
+}
+
+BLOCKQUOTE {
+    margin-right: 0px;
+}
+
+
+H1, H2, H3, H4, H5, H6    {
+    color: #000000;
+    font-weight:500;
+    margin-top:10px;
+    padding-top:15px;
+}
+
+TABLE  {
+    border-collapse: collapse;
+    border-spacing:0;
+    border: 1px thin black;
+    empty-cells: hide;
+}
+
+TD  {
+    padding: 4pt;
+}
+
+H1 { font-size: 150%; }
+H2 { font-size: 140%; }
+H3 { font-size: 110%; font-weight: bold; }
+H4 { font-size: 110%; font-weight: bold;}
+H5 { font-size: 100%; font-style: italic; }
+H6 { font-size: 100%; font-style: italic; }
+
+TT {
+font-size: 90%;
+    font-family: "Courier New", Courier, monospace;
+    color: #000000;
+}
+
+PRE {
+font-size: 100%;
+    padding: 5px;
+    border-style: solid;
+    border-width: 1px;
+    border-color: #CCCCCC;
+    background-color: #F4F4F4;
+}
+
+UL, OL, LI {
+    list-style: disc;
+}
+
+HR  {
+    width: 100%;
+    height: 1px;
+    background-color: #CCCCCC;
+    border-width: 0px;
+    padding: 0px;
+    color: #CCCCCC;
+}
+
+.variablelist { 
+    padding-top: 10; 
+    padding-bottom:10; 
+    margin:0;
+}
+
+.itemizedlist, UL { 
+    padding-top: 0; 
+    padding-bottom:0; 
+    margin:0; 
+}
+
+.term { 
+    font-weight:bold;
+}
+
+
+
+    

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/AuthorWork.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/AuthorWork.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/AuthorWork.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/AuthorWork.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/CustomerOrderProduct.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/CustomerOrderProduct.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/CustomerOrderProduct.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/CustomerOrderProduct.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/EmployerEmployee.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/EmployerEmployee.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/EmployerEmployee.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/EmployerEmployee.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/full_cream.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/full_cream.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/full_cream.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/full_cream.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/full_cream.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,429 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="354.331"
+   height="336.614"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+     style="font-size:12;"
+     id="g659">
+    <rect
+       width="212.257"
+       height="57.2441"
+       x="17.9576"
+       y="100.132"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       transform="matrix(0.743454,0,0,0.482981,6.46949,52.2178)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <rect
+     width="325.86"
+     height="63.6537"
+     x="17.4083"
+     y="15.194"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect136" />
+  <rect
+     width="325.86"
+     height="63.6537"
+     x="13.6713"
+     y="12.4966"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect126" />
+  <g
+     transform="matrix(1.14345,0,0,0.729078,-1.67818,105.325)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <text
+     x="170.824753"
+     y="58.402939"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="170.824997"
+       y="58.402901"
+       id="tspan360">
+Application</tspan>
+  </text>
+  <text
+     x="178.076340"
+     y="364.281433"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="178.076004"
+       y="364.281006"
+       id="tspan421">
+Database</tspan>
+  </text>
+  <text
+     x="68.605331"
+     y="138.524582"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="68.605301"
+       y="138.524994"
+       id="tspan384">
+SessionFactory</tspan>
+  </text>
+  <rect
+     width="67.0014"
+     height="101.35"
+     x="196.927"
+     y="89.2389"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect387" />
+  <rect
+     width="67.0014"
+     height="101.35"
+     x="194.633"
+     y="86.4389"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect388" />
+  <text
+     x="249.108841"
+     y="173.885559"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text389">
+    <tspan
+       x="249.108994"
+       y="173.886002"
+       id="tspan392">
+Session</tspan>
+  </text>
+  <rect
+     width="73.0355"
+     height="101.35"
+     x="270.995"
+     y="90.0018"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect395" />
+  <rect
+     width="73.0355"
+     height="101.35"
+     x="267.869"
+     y="87.2018"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect396" />
+  <text
+     x="328.593658"
+     y="174.715622"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text397">
+    <tspan
+       x="328.593994"
+       y="174.716003"
+       id="tspan563">
+Transaction</tspan>
+  </text>
+  <g
+     transform="matrix(0.29544,0,0,0.397877,9.70533,103.96)"
+     style="font-size:12;"
+     id="g565">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect566" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect567" />
+  </g>
+  <text
+     x="25.592752"
+     y="204.497803"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text568">
+    <tspan
+       x="25.592800"
+       y="204.498001"
+       id="tspan662">
+TransactionFactory</tspan>
+  </text>
+  <g
+     transform="matrix(0.298082,0,0,0.397877,99.6898,103.96)"
+     style="font-size:12;"
+     id="g573">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect574" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect575" />
+  </g>
+  <text
+     x="134.030670"
+     y="205.532791"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text576">
+    <tspan
+       x="134.031006"
+       y="205.533005"
+       id="tspan664">
+ConnectionProvider</tspan>
+  </text>
+  <g
+     transform="matrix(1.14345,0,0,0.729078,-1.67818,38.9539)"
+     style="font-size:12;"
+     id="g587">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect588" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect589" />
+  </g>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="25.6196"
+     y="206.028"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect594" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="24.4229"
+     y="204.135"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect595" />
+  <text
+     x="85.575645"
+     y="282.300354"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text596">
+    <tspan
+       x="85.575600"
+       y="282.299988"
+       id="tspan607">
+JNDI</tspan>
+  </text>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="236.937"
+     y="206.791"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect610" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="235.741"
+     y="204.898"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect611" />
+  <text
+     x="342.093201"
+     y="283.226410"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text612">
+    <tspan
+       x="342.092987"
+       y="283.226013"
+       id="tspan621">
+JTA</tspan>
+  </text>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="130.134"
+     y="206.791"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect616" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="128.937"
+     y="204.898"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect617" />
+  <text
+     x="212.445343"
+     y="283.226410"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text618">
+    <tspan
+       x="212.445007"
+       y="283.226013"
+       id="tspan623">
+JDBC</tspan>
+  </text>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,6.19341)"
+     style="font-size:12;"
+     id="g637">
+    <g
+       transform="matrix(0.499515,0,0,0.415467,-0.237339,5.61339)"
+       id="g167">
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="61.8805"
+         y="68.4288"
+         style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect134" />
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="59.2613"
+         y="65.8095"
+         style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect135" />
+    </g>
+    <text
+       x="33.749969"
+       y="50.589706"
+       style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+       id="text188">
+      <tspan
+         x="33.750000"
+         y="50.589699"
+         id="tspan635">
+Transient Objects</tspan>
+    </text>
+  </g>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+     style="font-size:12;"
+     id="g644">
+    <g
+       transform="matrix(0.297486,0,0,0.516482,230.251,36.9178)"
+       id="g364">
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="61.8805"
+         y="68.4288"
+         style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect365" />
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="59.2613"
+         y="65.8095"
+         style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect366" />
+    </g>
+    <text
+       x="277.123230"
+       y="85.155571"
+       style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+       id="text367">
+      <tspan
+         x="277.122986"
+         y="85.155602"
+         id="tspan631">
+Persistent</tspan>
+      <tspan
+         x="277.122986"
+         y="96.155602"
+         id="tspan633">
+Objects</tspan>
+    </text>
+  </g>
+</svg>

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/hibernate_logo_a.png
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/hibernate_logo_a.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/lite.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/lite.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/lite.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/lite.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/lite.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,334 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="318.898"
+   height="248.031"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <rect
+     width="291.837"
+     height="57.0074"
+     x="17.3169"
+     y="18.646"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect136" />
+  <rect
+     width="291.837"
+     height="57.0074"
+     x="13.9703"
+     y="16.2302"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect126" />
+  <g
+     transform="matrix(0.326107,0,0,0.765831,9.59261,8.98517)"
+     style="font-size:12;"
+     id="g161">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <g
+     transform="matrix(1.02406,0,0,0.652953,0.223384,39.9254)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <g
+     transform="matrix(0.449834,0,0,0.338463,-3.15909,9.73319)"
+     style="font-size:12;"
+     id="g167">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect134" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect135" />
+  </g>
+  <text
+     x="302.277679"
+     y="65.943230"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="302.277954"
+       y="65.943184"
+       id="tspan360">
+Application</tspan>
+  </text>
+  <text
+     x="36.235924"
+     y="63.796055"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text188">
+    <tspan
+       x="36.235950"
+       y="63.796051"
+       id="tspan427">
+Transient Objects</tspan>
+  </text>
+  <text
+     x="180.416245"
+     y="290.543701"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="180.415939"
+       y="290.543549"
+       id="tspan421">
+Database</tspan>
+  </text>
+  <text
+     x="25.037701"
+     y="179.154755"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="25.037655"
+       y="179.154648"
+       id="tspan384">
+SessionFactory</tspan>
+  </text>
+  <g
+     transform="matrix(0.252763,0,0,0.765831,109.104,8.98517)"
+     style="font-size:12;"
+     id="g386">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect387" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect388" />
+  </g>
+  <g
+     transform="matrix(0.297394,0,0,0.572692,101.502,21.6359)"
+     style="font-size:12;"
+     id="g364">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect365" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect366" />
+  </g>
+  <text
+     x="202.746506"
+     y="102.992203"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text367">
+    <tspan
+       x="202.746948"
+       y="102.992249"
+       id="tspan423">
+Persistent</tspan>
+    <tspan
+       x="202.746948"
+       y="116.992355"
+       id="tspan425">
+Objects</tspan>
+  </text>
+  <text
+     x="174.458496"
+     y="180.080795"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text389">
+    <tspan
+       x="174.458618"
+       y="180.080338"
+       id="tspan392">
+Session</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,188.675,8.98517)"
+     style="font-size:12;"
+     id="g394">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect395" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect396" />
+  </g>
+  <text
+     x="260.413269"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text397">
+    <tspan
+       x="260.412964"
+       y="179.154343"
+       id="tspan400">
+JDBC</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,229.156,8.98517)"
+     style="font-size:12;"
+     id="g405">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect406" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect407" />
+  </g>
+  <text
+     x="320.606903"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text408">
+    <tspan
+       x="320.606964"
+       y="179.154343"
+       id="tspan417">
+JNDI</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,269.281,8.98517)"
+     style="font-size:12;"
+     id="g411">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect412" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect413" />
+  </g>
+  <text
+     x="377.096313"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text414">
+    <tspan
+       x="377.096008"
+       y="179.154999"
+       id="tspan145">
+JTA</tspan>
+  </text>
+</svg>

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/overview.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/overview.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/overview.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/overview.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/pt-BR/src/main/resources/shared/images/overview.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,250 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="248.031"
+   height="248.031"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,-3.02123)"
+     style="font-size:12;"
+     id="g158">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="17.3527"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect136" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="15.3883"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect126" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,3.04452)"
+     style="font-size:12;"
+     id="g161">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,8.0993)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.543505,2.59104,21.1103)"
+     style="font-size:12;"
+     id="g167">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect134" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect135" />
+  </g>
+  <text
+     x="105.392174"
+     y="56.568123"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="105.392273"
+       y="56.568146"
+       id="tspan186">
+Application</tspan>
+  </text>
+  <text
+     x="81.820183"
+     y="103.149330"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:20;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text188">
+    <tspan
+       x="81.820213"
+       y="103.149727"
+       id="tspan206">
+Persistent Objects</tspan>
+  </text>
+  <text
+     x="111.548180"
+     y="278.927887"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="111.547874"
+       y="278.927551"
+       id="tspan200">
+Database</tspan>
+  </text>
+  <text
+     x="94.436180"
+     y="153.805740"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="94.436180"
+       y="153.805740"
+       id="tspan221">
+HIBERNATE</tspan>
+  </text>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,2.59083,1.02261)"
+     style="font-size:12;"
+     id="g254">
+    <g
+       transform="translate(4.58374,2.61928)"
+       id="g176">
+      <g
+         transform="matrix(0.571429,0,0,0.67347,-10.6174,117.093)"
+         id="g170">
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="61.8805"
+           y="68.4288"
+           style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect171" />
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="59.2613"
+           y="65.8095"
+           style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect172" />
+      </g>
+      <g
+         transform="matrix(0.571429,0,0,0.67347,138.682,117.093)"
+         id="g173">
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="61.8805"
+           y="68.4288"
+           style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect174" />
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="59.2613"
+           y="65.8095"
+           style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect175" />
+      </g>
+    </g>
+    <text
+       x="47.259438"
+       y="182.367538"
+       style="font-weight:bold;stroke-width:1pt;font-family:Courier;"
+       id="text191">
+      <tspan
+         x="47.259399"
+         y="182.367996"
+         id="tspan212">
+hibernate.</tspan>
+      <tspan
+         x="47.259399"
+         y="194.367996"
+         id="tspan214">
+properties</tspan>
+    </text>
+    <text
+       x="198.523010"
+       y="188.260941"
+       style="font-weight:normal;stroke-width:1pt;font-family:helvetica;"
+       id="text194">
+      <tspan
+         id="tspan195">
+XML Mapping</tspan>
+    </text>
+  </g>
+</svg>

Added: trunk/Hibernate3/documentation/manual/zh-CN/README_CHINESE_FONT.txt
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/README_CHINESE_FONT.txt	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/README_CHINESE_FONT.txt	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,6 @@
+Please be noticed that to build the pdf in Simplified Chinese, you need SimHei.ttf and SimSun.ttf from windows system, which can be found at \Windows\Fonts. 
+Please copy  these 2 files into fop folder  before build.
+
+Thanks!
+
+Xiaogang Cao.
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/zh-CN/pom.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-manual</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>hibernate-manual-${translation}</artifactId>
+    <packaging>pom</packaging>
+    <name>Hibernate Manual (${translation})</name>
+
+    <properties>
+        <translation>zh-CN</translation>
+    </properties>
+
+</project>

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/glossary.txt
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/glossary.txt	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/glossary.txt	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+O/R Mapping 对象/关系数据库映射
+identifier property: 标识属性
+discriminator: 辨别标志(不使用"鉴别器")
+
+join-subclass,union-subclass,join: 不翻译
+
+fine-grained 细粒度
+domain model 领域模型
+business object 业务对象(v2的时候翻译为"商业对象",被无数人痛骂....)
+annotations 注解(这个词还比较新,也见到有翻译为"特殊注释"/"标注"的)
+
+Aggregate functions 统计函数 (聚集函数?聚合函数? 还是翻译为统计函数才能让人看懂)
+Criteria Queries 条件查询(标准查询?这里Criteria是"判据"的含义,而非"标准",意译为条件查询更加明白)
+
+session flush session清洗
+lazy fetching 延迟加载(懒加载,翻译很直白,但是却不易理解)
+
+对象状态:
+ persistent class 持久化类
+ persistent object 持久对象 (体现这是与某个持久化设备联系的,掉电之后不消失)
+ transient object 瞬时对象  (其含义是仅在内存中存在的,掉电之后消失,翻译为瞬时对象比较好)
+ detached object 脱管对象(与session脱离的对象)
+
+outer-join fetching 外连接抓取 (fetch一般翻译为"获取",v2翻译的时候,为了突出其主动获取的特点,翻译为"抓取")
+
+class hierarchy 类分层结构 http://www.umlchina.com/xprogrammer/glossary1.htm
+inheritance hierarchy 继承层次 http://www-128.ibm.com/developerworks/cn/java/j-aopwork4/?ca=dwcn-newsletter-java

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/master.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/master.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/master.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,474 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
+                      "../support/docbook-dtd/docbookx.dtd"
+[
+<!ENTITY tutorial               SYSTEM "modules/tutorial.xml">
+<!ENTITY architecture           SYSTEM "modules/architecture.xml">
+<!ENTITY configuration          SYSTEM "modules/configuration.xml">
+<!ENTITY persistent-classes     SYSTEM "modules/persistent_classes.xml">
+<!ENTITY basic-mapping          SYSTEM "modules/basic_mapping.xml">
+<!ENTITY collection-mapping     SYSTEM "modules/collection_mapping.xml">
+<!ENTITY association-mapping    SYSTEM "modules/association_mapping.xml">
+<!ENTITY component-mapping      SYSTEM "modules/component_mapping.xml">
+<!ENTITY inheritance-mapping    SYSTEM "modules/inheritance_mapping.xml">
+<!ENTITY session-api            SYSTEM "modules/session_api.xml">
+<!ENTITY transactions           SYSTEM "modules/transactions.xml">
+<!ENTITY events                 SYSTEM "modules/events.xml">
+<!ENTITY batch                  SYSTEM "modules/batch.xml">
+<!ENTITY query-hql              SYSTEM "modules/query_hql.xml">
+<!ENTITY query-criteria         SYSTEM "modules/query_criteria.xml">
+<!ENTITY query-sql              SYSTEM "modules/query_sql.xml">
+<!ENTITY filters                SYSTEM "modules/filters.xml">
+<!ENTITY xml                    SYSTEM "modules/xml.xml">
+<!ENTITY performance            SYSTEM "modules/performance.xml">
+<!ENTITY toolset-guide          SYSTEM "modules/toolset_guide.xml">
+<!ENTITY example-parentchild    SYSTEM "modules/example_parentchild.xml">
+<!ENTITY example-weblog         SYSTEM "modules/example_weblog.xml">
+<!ENTITY example-mappings       SYSTEM "modules/example_mappings.xml">
+<!ENTITY best-practices         SYSTEM "modules/best_practices.xml">
+]>
+
+
+<book lang="zh-cn">
+
+    <bookinfo>
+        <title>HIBERNATE - 符合Java习惯的关系数据库持久化</title>
+        
+        <subtitle>Hibernate参考文档</subtitle>
+        <releaseinfo>3.2</releaseinfo>
+    </bookinfo>
+
+    <toc/>
+
+    <preface id="preface" revision="2">
+        <title>前言</title>
+
+        <para>
+            WARNING! This is a translated version of the English Hibernate reference
+            documentation. The translated version might not be up to date! However, the
+            differences should only be very minor. Consult the English reference
+            documentation if you are missing information or encounter a translation
+            error. If you like to contribute to a particular translation, contact us
+            on the Hibernate developer mailing list.
+        </para>
+
+        <para>
+            Translator(s): RedSaga Translate Team 满江红翻译团队  &lt;caoxg at yahoo.com&gt; 
+        </para>
+
+        <para>
+            在今日的企业环境中,把面向对象的软件和关系数据库一起使用可能是相当麻烦、浪费时间的。Hibernate是一个面向Java环境的对象/关系数据库映射工具。对象/关系数据库映射(object/relational mapping (ORM))这个术语表示一种技术,用来把对象模型表示的对象映射到基于SQL的关系模型数据结构中去。
+		</para>
+
+        <para>
+            Hibernate不仅仅管理Java类到数据库表的映射(包括Java数据类型到SQL数据类型的映射),还提供数据查询和获取数据的方法,可以大幅度减少开发时人工使用SQL和JDBC处理数据的时间。
+        </para>
+        
+        <para>
+        Hibernate的目标是对于开发者通常的数据持久化相关的编程任务,解放其中的95%。对于以数据为中心的程序来说,它们往往只在数据库中使用存储过程来实现商业逻辑,Hibernate可能不是最好的解决方案;对于那些在基于Java的中间层应用中,它们实现面向对象的业务模型和商业逻辑的应用,Hibernate是最有用的。不管怎样,Hibernate一定可以帮助你消除或者包装那些针对特定厂商的SQL代码,并且帮你把结果集从表格式的表示形式转换到一系列的对象去。
+        </para>
+
+        <para>
+            如果你对Hibernate和对象/关系数据库映射还是个新手,或者甚至对Java也不熟悉,请按照下面的步骤来学习。
+        </para>
+
+        <orderedlist>
+            <listitem>
+                <para>
+                    阅读<xref linkend="tutorial"/>,这是一篇包含详细的逐步指导的指南。本指南的源代码包含在发行包中,你可以在<literal>doc/reference/tutorial/</literal>目录下找到。                 </para>
+            </listitem>     
+            <listitem>
+                <para>
+                    阅读<xref linkend="architecture"/>来理解Hibernate可以使用的环境。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    查看Hibernate发行包中的<literal>eg/</literal>目录,里面有一个简单的独立运行的程序。把你的JDBC驱动拷贝到<literal>lib/</literal>目录下,修改一下<literal>src/hibernate.properties</literal>,指定其中你的数据库的信息。进入命令行,切换到你的发行包的目录,输入<literal>ant eg</literal>(使用了Ant),或者在Windows操作系统中使用<literal>build eg</literal>。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    把这份参考文档作为你学习的主要信息来源。
+                </para>
+            </listitem>
+            <listitem>
+				<para>
+					在Hibernate 的网站上可以找到经常提问的问题与解答(FAQ)。
+				</para>
+            </listitem>
+			<listitem>
+				<para>
+					在Hibernate网站上还有第三方的演示、示例和教程的链接。
+				</para>
+			</listitem>
+            <listitem>
+                <para>
+                    Hibernate网站的“社区(Community Area)”是讨论关于设计模式以及很多整合方案(Tomcat, JBoss AS, Struts, EJB,等等)的好地方。
+                </para>
+            </listitem>
+         </orderedlist>
+
+         <para>
+             如果你有问题,请使用Hibernate网站上链接的用户论坛。我们也提供一个JIRA问题追踪系统,来搜集bug报告和新功能请求。如果你对开发Hibernate有兴趣,请加入开发者的邮件列表。(Hibernate网站上的用户论坛有一个中文版面,JavaEye也有Hibernate中文版面,您可以在那里交流问题与经验。)
+         </para>
+
+         <para>
+             商业开发、产品支持和Hibernate培训可以通过JBoss Inc.获得。(请查阅:http://www.hibernate.org/SupportTraining/)。
+			 Hibernate是一个专业的开放源代码项目(Professional Open Source project),也是JBoss Enterprise Middleware System(JEMS),JBoss企业级中间件系统的一个核心组件。
+         </para>
+         
+         <sect1 id="preface-translate-comments-zh-cn">
+         <title>翻译说明</title>
+	         
+	         <para>
+	         	本文档的翻译是在网络上协作进行的,也会不断根据Hibernate的升级进行更新。提供此文档的目的是为了减缓学习Hibernate的坡度,而非代替原文档。我们建议所有有能力的读者都直接阅读英文原文。若您对翻译有异议,或发现翻译错误,敬请不吝赐教,报告到如下email地址:cao at redsaga.com
+	         </para>
+	 		 
+	         <para>
+	         Hibernate版本3的翻译由满江红翻译团队(RedSaga Translate Team)集体进行,这也是一次大规模网络翻译的试验。在不到20天的时间内,我们完成了两百多页文档的翻译,这一成果是通过十几位网友集体努力完成的。通过这次翻译,我们也有了一套完整的流程,从初译、技术审核一直到文字审核、发布。我们的翻译团队还会继续完善我们的翻译流程,并翻译其他优秀的Java开源资料,敬请期待。
+	         </para>
+
+        <table frame="topbot" id="redsaga-translate-team">
+            <title>
+                Hibernate v3翻译团队
+            </title>
+            <tgroup cols="5" rowsep="1" colsep="1">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="2*"/>
+                <colspec colname="c3" colwidth="2*"/>
+                <colspec colname="c4" colwidth="2*"/>
+                <colspec colname="c5" colwidth="2*"/>
+                <thead>
+                    <row>
+                        <entry align="center">
+                            序号
+                        </entry>
+                        <entry align="center">
+                            标题
+                        </entry>
+                        <entry align="center">
+                            中文标题
+                        </entry>
+                        <entry align="center">
+                            v3翻译
+                        </entry>
+                        <entry align="center">
+                            v3审校
+                        </entry>
+                        <entry align="center">
+                            v3.1审校
+                        </entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>--</entry>
+                        <entry>Quickstart with Tomcat</entry>
+                        <entry>在Tomcat中快速上手(3.1版本中取消)</entry>
+                        <entry>曹晓钢</entry>
+                        <entry>zoujm</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#1</entry>
+                        <entry>Turtotial</entry>
+                        <entry>Hibernate入门</entry>
+                        <entry>Zheng Shuai</entry>
+                        <entry>-</entry>
+                        <entry>Sean Chan</entry>
+                    </row>
+                    <row>
+                        <entry>#2</entry>
+                        <entry>Architecture</entry>
+                        <entry>体系结构</entry>
+                        <entry>Hilton(BJUG)</entry>
+                        <entry>厌倦发呆</entry>
+                        <entry>Sean Chan</entry>
+                    </row>
+                    <row>
+                        <entry>#3</entry>
+                        <entry>Configuration</entry>
+                        <entry>配置</entry>
+                        <entry>Goncha</entry>
+                        <entry>mochow</entry>
+                        <entry>zcgly</entry>
+                    </row>
+                    <row>
+                        <entry>#4</entry>
+                        <entry>Persistent Classes</entry>
+                        <entry>持久化类</entry>
+                        <entry>曹晓钢</entry>
+                        <entry>mochow</entry>
+                        <entry>DigitalSonic</entry>
+                    </row>
+                    <row>
+                        <entry>#5</entry>
+                        <entry>Basic O/R Mapping</entry>
+                        <entry>对象/关系数据库映射基础(上)</entry>
+                        <entry>moxie</entry>
+                        <entry>Kingfish</entry>
+                        <entry>张成钢</entry>
+                    </row>
+                    <row>
+                        <entry></entry>
+                        <entry></entry>
+                        <entry>对象/关系数据库映射基础(下)</entry>
+                        <entry>inter_dudu</entry>
+                        <entry>刘国雄(vincent)</entry>
+                        <entry>张成钢</entry>
+                    </row>
+                    <row>
+                        <entry>#6</entry>
+                        <entry>Collection Mapping</entry>
+                        <entry>集合类映射</entry>
+                        <entry>曹晓钢</entry>
+                        <entry>robbin</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#7</entry>
+                        <entry>Association Mappings</entry>
+                        <entry>关联关系映射</entry>
+                        <entry>Robbin</entry>
+                        <entry>devils.advocate</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#8</entry>
+                        <entry>Component Mapping</entry>
+                        <entry>组件映射</entry>
+                        <entry>曹晓钢</entry>
+                        <entry>Robbin</entry>
+                        <entry>Song guo qiang</entry>
+                    </row>
+                    <row>
+                        <entry>#9</entry>
+                        <entry>Inheritance Mappings</entry>
+                        <entry>继承映射</entry>
+                        <entry>morning(BJUG)</entry>
+                        <entry>mochow</entry>
+                        <entry>Liang cheng</entry>
+                    </row>
+                    <row>
+                        <entry>#10</entry>
+                        <entry>Working with objects</entry>
+                        <entry>与对象共事</entry>
+                        <entry>程广楠</entry>
+                        <entry>厌倦发呆</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#11</entry>
+                        <entry>Transactions And Concurrency</entry>
+                        <entry>事务和并发</entry>
+                        <entry>Robbin</entry>
+                        <entry>mochow</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#12</entry>
+                        <entry>Interceptors and events</entry>
+                        <entry>继承映射</entry>
+                        <entry>七彩狼(BJUG)</entry>
+                        <entry>厌倦发呆</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#13</entry>
+                        <entry>Batch processing</entry>
+                        <entry>批量处理</entry>
+                        <entry>Kingfish(BJUG)</entry>
+                        <entry>厌倦发呆</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#14</entry>
+                        <entry>HQL: The Hibernate Query Language</entry>
+                        <entry>HQL: Hibernate查询语言</entry>
+                        <entry>郑浩(BJUG)</entry>
+                        <entry>Zheng Shuai</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#15</entry>
+                        <entry>Criteria Queries</entry>
+                        <entry>条件查询</entry>
+                        <entry>nemo(BJUG)</entry>
+                        <entry>Zheng Shuai</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#16</entry>
+                        <entry>Native SQL</entry>
+                        <entry>Native SQL查询</entry>
+                        <entry>似水流年</entry>
+                        <entry>zoujm</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#17</entry>
+                        <entry>Filters</entry>
+                        <entry>过滤数据</entry>
+                        <entry>冰云(BJUG)</entry>
+                        <entry>Goncha</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#18</entry>
+                        <entry>XML Mapping</entry>
+                        <entry>XML映射</entry>
+                        <entry>edward(BJUG)</entry>
+                        <entry>Goncha</entry>
+                        <entry>huxb</entry>
+                    </row>
+                    <row>
+                        <entry>#19</entry>
+                        <entry>Improving performance</entry>
+                        <entry>性能提升</entry>
+                        <entry>Wangjinfeng</entry>
+                        <entry>Robbin</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#20</entry>
+                        <entry>Toolset Guide</entry>
+                        <entry>工具箱指南</entry>
+                        <entry>曹晓钢</entry>
+                        <entry>Robbin</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#21</entry>
+                        <entry>Example: Parent/Child</entry>
+                        <entry>示例:父子关系</entry>
+                        <entry>曹晓钢</entry>
+                        <entry>devils.advocate</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#22</entry>
+                        <entry>Example: Weblog Application</entry>
+                        <entry>示例:Weblog 应用程序</entry>
+                        <entry>曹晓钢</entry>
+                        <entry>devils.advocate</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#23</entry>
+                        <entry>Example: Various Mappings</entry>
+                        <entry>示例:多种映射</entry>
+                        <entry>shidu(BJUG)</entry>
+                        <entry>冰云</entry>
+                        <entry>--</entry>
+                    </row>
+                    <row>
+                        <entry>#24</entry>
+                        <entry>Best Practices</entry>
+                        <entry>最佳实践</entry>
+                        <entry>曹晓钢</entry>
+                        <entry>冰云</entry>
+                        <entry>--</entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+	         
+	         <para>
+	         v3.2版本在2006年11月份由曹晓钢更新。
+	         </para>
+	         
+	         <para>
+	         关于我们
+	         </para>
+	         
+	         
+             <variablelist spacing="compact">
+                <varlistentry>
+                    <term>满江红.开源, http://www.redsaga.com</term>
+                    <listitem>
+                        <para>
+                        从成立之初就致力于Java开放源代码在中国的传播与发展,与国内多个Java团体及出版社有深入交流。坚持少说多做的原则,目前有两个团队,“OpenDoc团队”与“翻译团队”,本翻译文档即为翻译团队作品。OpenDoc团队已经推出包括Hibernate、iBatis、Spring、WebWork的多份开放文档,并于2005年5月在Hibernate开放文档基础上扩充成书,出版了原创书籍:《深入浅出Hibernate》,本书400余页,适合各个层次的Hibernate用户。(http://www.redsaga.com/hibernate_book.html)敬请支持。
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>北京Java用户组, http://www.bjug.org</term>
+                    <listitem>
+                        <para>
+                        Beiing Java User Group,民间技术交流组织,成立于2004年6月。以交流与共享为宗旨,每两周举行一次技术聚会活动。BJUG的目标是,通过小部分人的努力,形成一个技术社群,创建良好的交流氛围,并将新的技术和思想推广到整个IT界,让我们共同进步。
+
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Java视线, http://www.javaeye.com</term>
+                    <listitem>
+                        <para>
+                        Java视线在是Hibernate中文论坛(http://www.hibernate.org.cn,Hibernate中文论坛是中国最早的Hibernate专业用户论坛,为Hibernate在中国的推广做出了巨大的贡献)基础上发展起来的Java深度技术网站,目标是成为一个高品质的,有思想深度的、原创精神的Java技术交流网站,为软件从业人员提供一个自由的交流技术,交流思想和交流信息的平台。
+
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>致谢</term>
+                    <listitem>
+                        <para>还有一些朋友给我们发来了勘误,在此致谢:Kurapica,李毅,李海林。
+                        </para>
+                    </listitem>
+                </varlistentry>
+             </variablelist>
+
+		</sect1>
+
+         <sect1 id="preface-translate-licence-zh-cn">
+	 		 <title>版权声明</title>
+
+	         <para>
+	         	Hibernate英文文档属于Hibernate发行包的一部分,遵循LGPL协议。本翻译版本同样遵循LGPL协议。参与翻译的译者一致同意放弃除署名权外对本翻译版本的其它权利要求。
+	 		 </para>
+
+	         <para>
+	         	您可以自由链接、下载、传播此文档,或者放置在您的网站上,甚至作为产品的一部分发行。但前提是必须保证全文完整转载,包括完整的版权信息和作译者声明,并不能违反LGPL协议。这里“完整”的含义是,不能进行任何删除/增添/注解。若有删除/增添/注解,必须逐段明确声明那些部分并非本文档的一部分。
+	         </para>
+         </sect1>
+
+    </preface>
+
+    &tutorial;
+
+    &architecture;
+
+    &configuration;
+
+    &persistent-classes;
+
+    &basic-mapping;
+    &collection-mapping;
+    &association-mapping;
+    &component-mapping;
+    &inheritance-mapping;
+
+    &session-api;
+    &transactions;
+    &events;
+    &batch;
+
+    &query-hql;
+    &query-criteria;
+    &query-sql;
+    &filters;
+    &xml;
+
+    &performance;
+
+    &toolset-guide;
+
+    &example-parentchild;
+    &example-weblog;
+    &example-mappings;
+
+    &best-practices;
+
+</book>
+

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/architecture.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/architecture.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/architecture.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,284 @@
+<chapter id="architecture">
+
+    <title>体系结构(Architecture)</title>
+    <sect1 id="architecture-overview" revision="1">
+        <title>概况(Overview)</title>
+        
+        <para>
+            一个非常简要的Hibernate体系结构的概要图:
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/overview.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/overview.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            从这个图可以看出,Hibernate使用数据库和配置信息来为应用程序提供持久化服务(以及持久的对象)。
+        </para>
+
+        <para>
+            我们来更详细地看一下Hibernate运行时体系结构。由于Hibernate非常灵活,且支持多种应用方案,
+            所以我们这只描述一下两种极端的情况。“轻型”的体系结构方案,要求应用程序提供自己的JDBC
+            连接并管理自己的事务。这种方案使用了Hibernate API的最小子集:
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/lite.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/lite.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            “全面解决”的体系结构方案,将应用层从底层的JDBC/JTA API中抽象出来,而让Hibernate来处理这些细节。
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/full_cream.svg" format="SVG" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/full_cream.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+
+        <para>
+            图中各个对象的定义如下:
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
+                    <listitem>
+                        <para>
+                            针对单个数据库映射关系经过编译后的内存镜像,是线程安全的(不可变)。
+                            它是生成<literal>Session</literal>的工厂,本身要用到<literal>ConnectionProvider</literal>。
+                            该对象可以在进程或集群的级别上,为那些事务之间可以重用的数据提供可选的二级缓存。
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Session (<literal>org.hibernate.Session</literal>)</term>
+                    <listitem>
+                        <para>
+                            表示应用程序与持久储存层之间交互操作的一个单线程对象,此对象生存期很短。
+                            其隐藏了JDBC连接,也是<literal>Transaction</literal>的工厂。
+                            其会持有一个针对持久化对象的必选(第一级)缓存,在遍历对象图或者根据持久化标识查找对象时会用到。
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>持久的对象及其集合</term>
+                    <listitem>
+                        <para>
+                            带有持久化状态的、具有业务功能的单线程对象,此对象生存期很短。
+                            这些对象可能是普通的JavaBeans/POJO,唯一特殊的是他们正与(仅仅一个)<literal>Session</literal>相关联。
+                            一旦这个<literal>Session</literal>被关闭,这些对象就会脱离持久化状态,这样就可被应用程序的任何层自由使用。
+                           (例如,用作跟表示层打交道的数据传输对象。)
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>瞬态(transient)和脱管(detached)的对象及其集合</term>
+                    <listitem>
+                        <para>
+                            那些目前没有与session关联的持久化类实例。
+                            他们可能是在被应用程序实例化后,尚未进行持久化的对象。
+                            也可能是因为实例化他们的<literal>Session</literal>已经被关闭而脱离持久化的对象。
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>事务Transaction (<literal>org.hibernate.Transaction</literal>)</term>
+                    <listitem>
+                        <para>
+                            (可选的)应用程序用来指定原子操作单元范围的对象,它是单线程的,生命周期很短。
+                            它通过抽象将应用从底层具体的JDBC、JTA以及CORBA事务隔离开。
+                            某些情况下,一个<literal>Session</literal>之内可能包含多个<literal>Transaction</literal>对象。
+                            尽管是否使用该对象是可选的,但无论是使用底层的API还是使用<literal>Transaction</literal>对象,事务边界的开启与关闭是必不可少的。
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
+                    <listitem>
+                        <para>
+                            (可选的)生成JDBC连接的工厂(同时也起到连接池的作用)。
+                            它通过抽象将应用从底层的<literal>Datasource</literal>或<literal>DriverManager</literal>隔离开。
+                            仅供开发者扩展/实现用,并不暴露给应用程序使用。
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
+                    <listitem>
+                        <para>
+                           (可选的)生成<literal>Transaction</literal>对象实例的工厂。
+                           仅供开发者扩展/实现用,并不暴露给应用程序使用。
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><emphasis>扩展接口</emphasis></term>
+                    <listitem>
+                        <para>
+                             Hibernate提供了很多可选的扩展接口,你可以通过实现它们来定制你的持久层的行为。
+                             具体请参考API文档。
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+        </para>
+
+        <para>
+            在特定“轻型”的体系结构中,应用程序可能绕过
+            <literal>Transaction</literal>/<literal>TransactionFactory</literal> 以及
+            <literal>ConnectionProvider</literal> 等API直接跟JTA或JDBC打交道。
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-states" revision="1">
+        <title>实例状态</title>
+        <para>
+            一个持久化类的实例可能处于三种不同状态中的某一种。
+            这三种状态的定义则与所谓的<emphasis>持久化上下文(persistence context)</emphasis>有关。
+            Hibernate的<literal>Session</literal>对象就是这个所谓的持久化上下文:
+        </para>
+        
+       <variablelist spacing="compact">
+            <varlistentry>
+                <term>瞬态(transient)</term>
+                <listitem>
+                    <para>
+                        该实例从未与任何持久化上下文关联过。它没有持久化标识(相当于主键值)。
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>持久化(persistent)</term>
+                <listitem>
+                    <para>
+                        实例目前与某个持久化上下文有关联。
+                        它拥有持久化标识(相当于主键值),并且可能在数据库中有一个对应的行。
+                        对于某一个特定的持久化上下文,Hibernate<emphasis>保证</emphasis>持久化标识与Java标识(其值代表对象在内存中的位置)等价。
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>脱管(detached)</term>
+                <listitem>
+                    <para>
+                        实例曾经与某个持久化上下文发生过关联,不过那个上下文被关闭了,
+                        或者这个实例是被序列化(serialize)到另外的进程。
+                        它拥有持久化标识,并且在数据库中可能存在一个对应的行。
+                        对于脱管状态的实例,Hibernate不保证任何持久化标识和Java标识的关系。
+                    </para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </sect1>    
+
+    <sect1 id="architecture-jmx" revision="1">
+        <title>JMX整合</title>
+
+        <para>
+            JMX是管理Java组件(Java components)的J2EE标准。 Hibernate 可以通过一个JMX标准服务来管理。
+            在这个发行版本中,我们提供了一个MBean接口的实现,即
+            <literal>org.hibernate.jmx.HibernateService</literal>。
+        </para>
+
+        <para>
+            想要看如何在JBoss应用服务器上将Hibernate部署为一个JMX服务的例子,您可以参考JBoss用户指南。
+            我们现在说一下在Jboss应用服务器上,使用JMX来部署Hibernate的好处:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <emphasis>Session管理:</emphasis> Hibernate的<literal>Session</literal>对象的生命周期可以
+                    自动跟一个JTA事务边界绑定。这意味着你无需手工开关<literal>Session</literal>了, 这项
+                    工作会由JBoss EJB 拦截器来完成。你再也不用担心你的代码中的事务边界了(除非你想利用Hibernate提供可选
+                    的<literal>Transaction</literal> API来自己写一个便于移植的的持久层)。 
+                    你通过调用<literal>HibernateContext</literal>来访问<literal>Session</literal>。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>HAR 部署:</emphasis> 通常情况下,你会使用JBoss的服务部署描述符(在EAR或/和SAR文件中)来部署Hibernate JMX服务。
+                    这种部署方式支持所有常见的Hibernate <literal>SessionFactory</literal>的配置选项。
+                    不过,你仍需在部署描述符中,列出你所有的映射文件的名字。如果你使用HAR部署方式, JBoss 
+                    会自动探测出你的HAR文件中所有的映射文件。
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            这些选项更多的描述,请参考JBoss 应用程序用户指南。
+        </para>
+
+        <para>
+            将Hibernate以部署为JMX服务的另一个好处,是可以查看Hibernate的运行时统计信息。参看
+            <xref linkend="configuration-optional-statistics"/>.
+        </para>
+    </sect1>
+
+    <sect1 id="architecture-jca" revision="1">
+        <title>对JCA的支持</title>
+        <para>
+            Hibernate也可以被配置为一个JCA连接器(JCA connector)。更多信息请参看网站。
+            请注意,Hibernate对JCA的支持,仍处于实验性阶段。
+        </para>
+    </sect1>
+    <sect1 id="architecture-current-session" revision="2">
+        <title>上下文相关的(Contextual)Session</title>
+        <para>
+           	使用Hibernate的大多数应用程序需要某种形式的“上下文相关的” session,特定的session在整个特定的上下文范围内始终有效。然而,对不同类型的应用程序而言,要为什么是组成这种“上下文”下一个定义通常是困难的;不同的上下文对“当前”这个概念定义了不同的范围。在3.0版本之前,使用Hibernate的程序要么采用自行编写的基于<literal>ThreadLocal</literal>的上下文session,要么采用<literal>HibernateUtil</literal>这样的辅助类,要么采用第三方框架(比如Spring或Pico),它们提供了基于代理(proxy)或者基于拦截器(interception)的上下文相关session。
+        </para>
+        <para>
+            从3.0.1版本开始,Hibernate增加了<literal>SessionFactory.getCurrentSession()</literal>方法。一开始,它假定了采用<literal>JTA</literal>事务,<literal>JTA</literal>事务定义了当前session的范围和上下文(scope and context)。Hibernate开发团队坚信,因为有好几个独立的<literal>JTA TransactionManager</literal>实现稳定可用,不论是否被部署到一个<literal>J2EE</literal>容器中,大多数(假若不是所有的)应用程序都应该采用<literal>JTA</literal>事务管理。基于这一点,采用<literal>JTA</literal>的上下文相关session可以满足你一切需要。
+        </para>
+        <para>
+            更好的是,从3.1开始,<literal>SessionFactory.getCurrentSession()</literal>的后台实现是可拔插的。因此,我们引入了新的扩展接口(<literal>org.hibernate.context.CurrentSessionContext</literal>)和新的配置参数(<literal>hibernate.current_session_context_class</literal>),以便对什么是“当前session”的范围和上下文(scope and context)的定义进行拔插。
+        </para>
+        <para>
+            请参阅<literal>org.hibernate.context.CurrentSessionContext</literal>接口的Javadoc,那里有关于它的契约的详细讨论。它定义了单一的方法,<literal>currentSession()</literal>,特定的实现用它来负责跟踪当前的上下文session。Hibernate内置了此接口的三种实现。
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.context.JTASessionContext</literal> - 当前session根据<literal>JTA</literal>来跟踪和界定。这和以前的仅支持JTA的方法是完全一样的。详情请参阅Javadoc。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.context.ThreadLocalSessionContext</literal> - 当前session通过当前执行的线程来跟踪和界定。详情也请参阅Javadoc。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>org.hibernate.context.ManagedSessionContext</literal> - 当前session通过当前执行的线程来跟踪和界定。但是,你需要负责使用这个类的静态方法将<literal>Session</literal>实例绑定、或者取消绑定,它并不会打开(open)、flush或者关闭(close)任何<literal>Session</literal>。
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            前两种实现都提供了“每数据库事务对应一个session”的编程模型,也称作<emphasis>每次请求一个session</emphasis>。Hibernate session的起始和终结由数据库事务的生存来控制。假若你在纯粹的 Java SE之上采用自行编写代码来管理事务,而不使用JTA,建议你使用Hibernate <literal>Transaction</literal> API来把底层事务实现从你的代码中隐藏掉。如果你使用JTA,请使用JTA借口来管理Transaction。如果你在支持CMT的EJB容器中执行代码,事务边界是声明式定义的,你不需要在代码中进行任何事务或session管理操作。请参阅<xref linkend="transactions"/>一节来阅读更多的内容和示例代码。
+        </para>
+
+        <para>
+            <literal>hibernate.current_session_context_class</literal>配置参数定义了应该采用哪个<literal>org.hibernate.context.CurrentSessionContext</literal>实现。注意,为了向下兼容,如果未配置此参数,但是存在<literal>org.hibernate.transaction.TransactionManagerLookup</literal>的配置,Hibernate会采用<literal>org.hibernate.context.JTASessionContext</literal>。一般而言,此参数的值指明了要使用的实现类的全名,但那三种内置的实现可以使用简写,即"jta"、"thread"和"managed"。
+            
+        </para>
+        
+    </sect1>
+
+</chapter>
+
+

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/association_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/association_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/association_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,579 @@
+<chapter id="associations">
+
+    <title>关联关系映射</title>
+	
+    <sect1 id="assoc-intro" revision="1">
+         <title>介绍</title>   
+		 
+        <para>
+            关联关系映射通常情况是最难配置正确的。在这个部分中,我们从单向关系映射开始,然后考虑双向关系映射,由浅至深讲述一遍典型的案例。在所有的例子中,我们都使用 <literal>Person</literal>和<literal>Address</literal>。
+        </para>
+        
+         <para>
+        	我们根据映射关系是否涉及连接表以及多样性来划分关联类型。
+        </para>
+		
+         <para>
+        	在传统的数据建模中,允许为Null值的外键被认为是一种不好的实践,因此我们所有的例子中都使用不允许为Null的外键。这并不是Hibernate的要求,即使你删除掉不允许为Null的约束,Hibernate映射一样可以工作的很好。
+        </para>
+		
+    </sect1>
+
+    <sect1 id="assoc-unidirectional" revision="1">
+         <title>单向关联(Unidirectional associations)</title>
+		 
+        <sect2 id="assoc-unidirectional-m21">
+        <title>多对一(many to one)</title>
+        
+        <para>
+             <emphasis>单向many-to-one关联</emphasis>是最常见的单向关联关系。
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-121">
+        <title>一对一(one to one)</title>
+        
+         <para>
+             <emphasis>基于外键关联的单向一对一关联</emphasis>和<emphasis>单向多对一关联</emphasis>几乎是一样的。唯一的不同就是单向一对一关联中的外键字段具有唯一性约束。
+        </para>
+		
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId" 
+        unique="true"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+         <para>
+            <emphasis>基于主键关联的单向一对一关联</emphasis>通常使用一个特定的id生成器。(请注意,在这个例子中我们掉换了关联的方向。)
+        </para>
+		
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+</class>
+
+<class name="Address">
+    <id name="id" column="personId">
+        <generator class="foreign">
+            <param name="property">person</param>
+        </generator>
+    </id>
+    <one-to-one name="person" constrained="true"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+        <sect2 id="assoc-unidirectional-12m">
+        <title>一对多(one to many)</title>
+        
+        <para>
+            <emphasis>基于外键关联的单向一对多关联</emphasis>是一种很少见的情况,并不推荐使用。
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses">
+        <key column="personId" 
+            not-null="true"/>
+        <one-to-many class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( addressId bigint not null primary key, personId bigint not null )
+        ]]></programlisting>
+        
+         <para>
+            我们认为对于这种关联关系最好使用连接表。
+        </para>
+		
+        </sect2>
+    
+    </sect1>
+
+    <sect1 id="assoc-unidirectional-join" revision="1">
+        <title>使用连接表的单向关联(Unidirectional associations with join tables)</title>
+		 
+        <sect2 id="assoc-unidirectional-join-12m">
+        <title>一对多(one to many)</title>
+        
+         <para>
+            <emphasis>基于连接表的单向一对多关联</emphasis> 应该优先被采用。请注意,通过指定<literal>unique="true"</literal>,我们可以把多样性从多对多改变为一对多。
+        </para>
+		
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            unique="true"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-m21">
+        <title>多对一(many to one)</title>
+        
+        <para>
+            <emphasis>基于连接表的单向多对一关联</emphasis>在关联关系可选的情况下应用也很普遍。
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-121">
+        <title>一对一(one to one)</title>
+        
+         <para>
+            <emphasis>基于连接表的单向一对一关联</emphasis>非常少见,但也是可行的。
+        </para>
+		
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+        <sect2 id="assoc-unidirectional-join-m2m">
+        <title>多对多(many to many)</title>
+        
+         <para>
+            最后,还有 <emphasis>单向多对多关联</emphasis>.
+        </para>
+		
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="assoc-bidirectional" revision="1">
+        <title>双向关联(Bidirectional associations)</title>
+        
+        <sect2 id="assoc-bidirectional-m21" revision="2">
+        <title>一对多(one to many) / 多对一(many to one)</title>
+        
+         <para>
+            <emphasis>双向多对一关联</emphasis> 是最常见的关联关系。(这也是标准的父/子关联关系。)
+        </para>
+		
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <set name="people" inverse="true">
+        <key column="addressId"/>
+        <one-to-many class="Person"/>
+    </set>
+</class>]]></programlisting>
+
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+                <para>
+            如果你使用<literal>List</literal>(或者其他有序集合类),你需要设置外键对应的<literal>key</literal>列为 <literal>not null</literal>,让Hibernate来从集合端管理关联,维护每个元素的索引(通过设置<literal>update="false"</literal> and <literal>insert="false"</literal>来对另一端反向操作)。
+        </para>
+
+        <programlisting><![CDATA[<class name="Person">
+   <id name="id"/>
+   ...
+   <many-to-one name="address"
+      column="addressId"
+      not-null="true"
+      insert="false"
+      update="false"/>
+</class>
+
+<class name="Address">
+   <id name="id"/>
+   ...
+   <list name="people">
+      <key column="addressId" not-null="true"/>
+      <list-index column="peopleIdx"/>
+      <one-to-many class="Person"/>
+   </list>
+</class>]]></programlisting>
+
+            <para>
+                假若集合映射的<literal>&lt;key&gt;</literal>元素对应的底层外键字段是<literal>NOT NULL</literal>的,那么为这一key元素定义<literal>not-null="true"</literal>是很重要的。不要仅仅为可能的嵌套<literal>&lt;column&gt;</literal>元素定义<literal>not-null="true"</literal>,<literal>&lt;key&gt;</literal>元素也是需要的。
+            </para>
+
+        </sect2>
+        
+        <sect2 id="assoc-bidirectional-121">
+        <title>一对一(one to one)</title>
+        
+         <para>
+           <emphasis>基于外键关联的双向一对一关联</emphasis>也很常见。
+        </para>
+		
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <many-to-one name="address" 
+        column="addressId" 
+        unique="true"
+        not-null="true"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+   <one-to-one name="person" 
+        property-ref="address"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+         <para>
+            <emphasis>基于主键关联的一对一关联</emphasis>需要使用特定的id生成器。
+        </para>
+		
+       <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <one-to-one name="address"/>
+</class>
+
+<class name="Address">
+    <id name="id" column="personId">
+        <generator class="foreign">
+            <param name="property">person</param>
+        </generator>
+    </id>
+    <one-to-one name="person" 
+        constrained="true"/>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="assoc-bidirectional-join" revision="1">
+        <title>使用连接表的双向关联(Bidirectional associations with join tables)</title>
+        
+        <sect2 id="assoc-bidirectional-join-12m">
+        <title>一对多(one to many) /多对一( many to one)</title>
+        
+         <para>
+             <emphasis>基于连接表的双向一对多关联</emphasis>。注意<literal>inverse="true"</literal>可以出现在关联的任意一端,即collection端或者join端。
+        </para>
+		
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses" 
+        table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            unique="true"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        inverse="true" 
+        optional="true">
+        <key column="addressId"/>
+        <many-to-one name="person"
+            column="personId"
+            not-null="true"/>
+    </join>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+
+         <sect2 id="assoc-bidirectional-join-121">
+        <title>一对一(one to one)</title>
+        
+         <para>
+            <emphasis>基于连接表的双向一对一关联</emphasis>极为罕见,但也是可行的。
+        </para>
+		
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true">
+        <key column="personId" 
+            unique="true"/>
+        <many-to-one name="address"
+            column="addressId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <join table="PersonAddress" 
+        optional="true"
+        inverse="true">
+        <key column="addressId" 
+            unique="true"/>
+        <many-to-one name="person"
+            column="personId" 
+            not-null="true"
+            unique="true"/>
+    </join>
+</class>]]></programlisting>
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+
+        </sect2>
+        
+        <sect2 id="assoc-bidirectional-join-m2m" revision="1">
+        <title>多对多(many to many)</title>
+        
+        <para>
+            最后,还有 <emphasis>双向多对多关联</emphasis>.
+        </para>
+        
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id" column="personId">
+        <generator class="native"/>
+    </id>
+    <set name="addresses"  table="PersonAddress">
+        <key column="personId"/>
+        <many-to-many column="addressId"
+            class="Address"/>
+    </set>
+</class>
+
+<class name="Address">
+    <id name="id" column="addressId">
+        <generator class="native"/>
+    </id>
+    <set name="people" inverse="true"  table="PersonAddress">
+        <key column="addressId"/>
+        <many-to-many column="personId"
+            class="Person"/>
+    </set>
+</class>]]></programlisting>
+
+        <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+        ]]></programlisting>
+        
+        </sect2>
+        
+    </sect1>
+    <sect1 id="assoc-complex">
+        <title>更复杂的关联映射</title>
+        
+        <para>
+            更复杂的关联连接<emphasis>极为</emphasis>罕见。 
+            通过在映射文档中嵌入SQL片断,Hibernate也可以处理更为复杂的情况。比如,假若包含历史帐户数据的表定义了<literal>accountNumber</literal>, <literal>effectiveEndDate</literal> 和<literal>effectiveStartDate</literal>字段,按照下面映射:
+        </para>
+        
+        <programlisting><![CDATA[<properties name="currentAccountKey">
+    <property name="accountNumber" type="string" not-null="true"/>
+    <property name="currentAccount" type="boolean">
+        <formula>case when effectiveEndDate is null then 1 else 0 end</formula>
+    </property>
+</properties>
+<property name="effectiveEndDate" type="date"/>
+<property name="effectiveStateDate" type="date" not-null="true"/>]]></programlisting>
+
+        <para>
+        那么我们可以对<emphasis>目前(current)</emphasis>实例(其<literal>effectiveEndDate</literal>为null)使用这样的关联映射:
+        </para>
+        
+        <programlisting><![CDATA[<many-to-one name="currentAccountInfo" 
+        property-ref="currentAccountKey"
+        class="AccountInfo">
+    <column name="accountNumber"/>
+    <formula>'1'</formula>
+</many-to-one>]]></programlisting>
+
+        <para>
+            更复杂的例子,假想<literal>Employee</literal>和<literal>Organization</literal>之间的关联是通过一个<literal>Employment</literal>中间表维护的,而中间表中填充了很多历史雇员数据。那“雇员的<emphasis>最新</emphasis>雇主”这个关联(最新雇主就是<literal>startDate</literal>最后的那个)可以这样映射:
+        </para>
+        
+        <programlisting><![CDATA[<join>
+    <key column="employeeId"/>
+    <subselect>
+        select employeeId, orgId 
+        from Employments 
+        group by orgId 
+        having startDate = max(startDate)
+    </subselect>
+    <many-to-one name="mostRecentEmployer" 
+            class="Organization" 
+            column="orgId"/>
+</join>]]></programlisting>
+
+        <para>
+        使用这一功能时可以充满创意,但通常更加实用的是用HQL或条件查询来处理这些情形。
+        </para>
+
+    </sect1>
+
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/basic_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/basic_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/basic_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,2982 @@
+<chapter id="mapping">
+    <title>对象/关系数据库映射基础(Basic O/R Mapping)</title>
+
+    <sect1 id="mapping-declaration" revision="1">
+        <title>映射定义(Mapping declaration)</title>
+
+        <para>
+            对象和关系数据库之间的映射通常是用一个XML文档(XML document)来定义的。这个映射文档被设计为易读的,
+            并且可以手工修改。映射语言是以Java为中心,这意味着映射文档是按照持久化类的定义来创建的,
+            而非表的定义。
+        </para>
+        
+        
+        <para>
+            请注意,虽然很多Hibernate用户选择手写XML映射文档,但也有一些工具可以用来生成映射文档,
+            包括XDoclet,Middlegen和AndroMDA。
+        </para>
+
+        <para>
+            让我们从一个映射的例子开始:
+        </para>
+
+        <programlisting id="mapping-declaration-ex1" revision="1"><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+        <class name="Cat" 
+            table="cats"
+            discriminator-value="C">
+                
+                <id name="id">
+                        <generator class="native"/>
+                </id>
+
+                <discriminator column="subclass" 
+                     type="character"/>
+
+                <property name="weight"/>
+
+                <property name="birthdate"
+                    type="date" 
+                    not-null="true" 
+                    update="false"/>
+
+                <property name="color"
+                    type="eg.types.ColorUserType"
+                    not-null="true"
+                    update="false"/>
+
+                <property name="sex"
+                    not-null="true" 
+                    update="false"/>
+
+                <property name="litterId"
+                    column="litterId"
+                    update="false"/>
+
+                <many-to-one name="mother"
+                    column="mother_id"
+                    update="false"/>
+
+                <set name="kittens"
+                    inverse="true"
+                    order-by="litter_id">
+                        <key column="mother_id"/>
+                        <one-to-many class="Cat"/>
+                </set>
+
+                <subclass name="DomesticCat"
+                    discriminator-value="D">
+
+                        <property name="name" 
+                            type="string"/>
+
+                </subclass>
+
+        </class>
+
+        <class name="Dog">
+                <!-- mapping for Dog could go here -->
+        </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+             我们现在开始讨论映射文档的内容。我们只描述Hibernate在运行时用到的文档元素和属性。
+             映射文档还包括一些额外的可选属性和元素,它们在使用schema导出工具的时候会影响导出的数据库schema结果。
+             (比如,<literal> not-null</literal> 属性。)
+        </para>
+
+
+
+        <sect2 id="mapping-declaration-doctype" revision="3">
+            <title>Doctype</title>
+
+            <para>
+                所有的XML映射都需要定义如上所示的doctype。DTD可以从上述URL中获取,
+                也可以从<literal>hibernate-x.x.x/src/net/sf/hibernate</literal>目录中、
+                或<literal>hibernate.jar</literal>文件中找到。Hibernate总是会首先在它的classptah中搜索DTD文件。
+                如果你发现它是通过连接Internet查找DTD文件,就对照你的classpath目录检查XML文件里的DTD声明。
+            </para>
+            
+            <sect3 id="mapping-declaration-entity-resolution">
+                <title>EntityResolver</title>
+                <para>
+                    As mentioned previously, Hibernate will first attempt to resolve DTDs in its classpath.  The
+                    manner in which it does this is by registering a custom <literal>org.xml.sax.EntityResolver</literal>
+                    implementation with the SAXReader it uses to read in the xml files.  This custom
+                    <literal>EntityResolver</literal> recognizes two different systemId namespaces.
+                    如前所述,Hibernate首先在其classpath中查找DTD。其行为是依靠在系统中注册的<literal>org.xml.sax.EntityResolver</literal>的一个具体实现,SAXReader依靠它来读取xml文件。这一 <literal>EntityResolver</literal> 实现能辨认两种不同的 systenId命名空间。
+                </para>
+                <itemizedlist>
+                    <listitem>
+                        <para>
+                            若resolver遇到了一个以<literal>http://hibernate.sourceforge.net/</literal>为开头的systemId,它会辨认出是<literal>hibernate namespace</literal>,resolver就试图通过加载Hibernate类的classloader来查找这些实体。
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+
+                            若resolver遇到了一个使用<literal>classpath://</literal>URL协议的systemId,它会辨认出这是<literal>user namespace</literal>,resolver试图通过(1)当前线程上下文的classloader和(2)加载Hibernate class的classloader来查找这些实体。
+                        </para>
+                    </listitem>
+                </itemizedlist>
+                <para>
+                    使用user namespace(用户命名空间)的例子:
+                </para>
+                <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [
+    <!ENTITY types SYSTEM "classpath://your/domain/types.xml">
+]>
+
+<hibernate-mapping package="your.domain">
+    <class name="MyEntity">
+        <id name="id" type="my-custom-id-type">
+            ...
+        </id>
+    <class>
+    &types;
+</hibernate-mapping>]]></programlisting>
+                <para>
+                    <literal>types.xml</literal>是<literal>your.domain</literal>包中的一个资源,它包含了一个定制的<xref linkend="mapping-types-custom">typedef</xref>。
+                </para>
+                
+            </sect3>
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-mapping" revision="3">
+            <title>hibernate-mapping</title>
+
+            <para>
+                这个元素包括一些可选的属性。<literal>schema</literal>和<literal>catalog</literal>属性,
+                指明了这个映射所连接(refer)的表所在的schema和/或catalog名称。
+                假若指定了这个属性,表名会加上所指定的schema和catalog的名字扩展为全限定名。假若没有指定,表名就不会使用全限定名。
+                <literal>default-cascade</literal>指定了未明确注明<literal>cascade</literal>属性的Java属性和
+                集合类Hibernate会采取什么样的默认级联风格。<literal>auto-import</literal>属性默认让我们在查询语言中可以使用
+                非全限定名的类名。
+            </para>
+            
+ 
+             <programlistingco>
+                 <areaspec>
+                     <area id="hm1" coords="2 55"/>
+                     <area id="hm2" coords="3 55"/>
+                     <area id="hm3" coords="4 55"/>
+                     <area id="hm4" coords="5 55"/>
+                     <area id="hm5" coords="6 55"/>
+                     <area id="hm6" coords="7 55"/>
+                     <area id="hm7" coords="8 55"/>
+                 </areaspec>
+                 <programlisting><![CDATA[<hibernate-mapping
+         schema="schemaName"
+         catalog="catalogName"
+         default-cascade="cascade_style"
+         default-access="field|property|ClassName"
+         default-lazy="true|false"
+         auto-import="true|false"
+         package="package.name"
+ />]]></programlisting>
+                 <calloutlist>
+                     <callout arearefs="hm1">
+                         <para>
+                             <literal>schema</literal> (可选): 数据库schema的名称。
+                         </para>
+                     </callout>
+                     <callout arearefs="hm2">
+                         <para>
+                             <literal>catalog</literal> (可选): 数据库catalog的名称。
+                         </para>
+                     </callout>
+                     <callout arearefs="hm3">
+                         <para>
+                             <literal>default-cascade</literal> (可选 - 默认为 <literal>none</literal>): 
+                             默认的级联风格。
+                         </para>
+                     </callout>
+                     <callout arearefs="hm4">
+                         <para>
+                             <literal>default-access</literal> (可选 - 默认为 <literal>property</literal>):
+                             Hibernate用来访问所有属性的策略。可以通过实现<literal>PropertyAccessor</literal>接口
+                             自定义。
+                         </para>
+                     </callout>
+                     <callout arearefs="hm5">
+                         <para>
+                         		 <literal>default-lazy</literal> (可选 - 默认为 <literal>true</literal>):
+                             指定了未明确注明<literal>lazy</literal>属性的Java属性和集合类,
+                             Hibernate会采取什么样的默认加载风格。
+                         </para>
+                     </callout>
+                     <callout arearefs="hm6">
+                         <para>
+                         		 <literal>auto-import</literal> (可选 - 默认为 <literal>true</literal>):
+                             指定我们是否可以在查询语言中使用非全限定的类名(仅限于本映射文件中的类)。
+                         </para>
+                     </callout>
+                     <callout arearefs="hm7">
+                         <para>
+                             <literal>package</literal> (可选): 指定一个包前缀,如果在映射文档中没有指定全限定的类名,
+                             就使用这个作为包名。
+                         </para>
+                     </callout>
+                 </calloutlist>
+             </programlistingco>
+             
+             <para>
+                 假若你有两个持久化类,它们的非全限定名是一样的(就是两个类的名字一样,所在的包不一样--译者注),
+                 你应该设置<literal>auto-import="false"</literal>。如果你把一个“import过”的名字同时对应两个类,
+                  Hibernate会抛出一个异常。
+             </para>
+
+             <para>
+                 注意<literal>hibernate-mapping</literal> 元素允许你嵌套多个如上所示的
+                 <literal>&lt;class&gt;</literal>映射。但是最好的做法(也许一些工具需要的)是一个
+                 持久化类(或一个类的继承层次)对应一个映射文件,并以持久化的超类名称命名,例如:
+                 <literal>Cat.hbm.xml</literal>,
+                 <literal>Dog.hbm.xml</literal>,或者如果使用继承,<literal>Animal.hbm.xml</literal>。
+             </para>
+ 
+        </sect2>
+
+        <sect2 id="mapping-declaration-class" revision="3">
+            <title>class</title>
+
+            <para>
+                你可以使用<literal>class</literal>元素来定义一个持久化类:
+            </para>
+            
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="class1" coords="2 55"/>
+                    <area id="class2" coords="3 55" />
+                    <area id="class3" coords="4 55"/>
+                    <area id="class4" coords="5 55" />
+                    <area id="class5" coords="6 55"/>
+                    <area id="class6" coords="7 55" />
+                    <area id="class7" coords="8 55"/>
+                    <area id="class8" coords="9 55" />
+                    <area id="class9" coords="10 55" />
+                    <area id="class10" coords="11 55"/>
+                    <area id="class11" coords="12 55"/>
+                    <area id="class12" coords="13 55"/>
+                    <area id="class13" coords="14 55"/>
+                    <area id="class14" coords="15 55"/>
+                    <area id="class15" coords="16 55"/>
+                    <area id="class16" coords="17 55"/>
+                    <area id="class17" coords="18 55"/>
+                    <area id="class18" coords="19 55"/>
+                    <area id="class19" coords="20 55"/>
+                    <area id="class20" coords="21 55"/>
+                    <area id="class21" coords="22 55"/>
+                </areaspec>
+                <programlisting><![CDATA[<class
+        name="ClassName"
+        table="tableName"
+        discriminator-value="discriminator_value"
+        mutable="true|false"
+        schema="owner"
+        catalog="catalog"
+        proxy="ProxyInterface"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        select-before-update="true|false"
+        polymorphism="implicit|explicit"
+        where="arbitrary sql where condition"
+        persister="PersisterClass"
+        batch-size="N"
+        optimistic-lock="none|version|dirty|all"
+        lazy="true|false"
+        entity-name="EntityName"
+        check="arbitrary sql check condition"
+        rowid="rowid"
+        subselect="SQL expression"
+        abstract="true|false"
+        node="element-name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="class1">
+                        <para>
+                            <literal>name</literal> (可选): 持久化类(或者接口)的Java全限定名。
+                            如果这个属性不存在,Hibernate将假定这是一个非POJO的实体映射。
+                        </para>
+                    </callout>
+                    <callout arearefs="class2">
+                        <para>
+                            <literal>table</literal> (可选 - 默认是类的非全限定名):  对应的数据库表名。
+                        </para>
+                    </callout>
+                    <callout arearefs="class3">
+                        <para>
+                            <literal>discriminator-value</literal> (可选 - 默认和类名一样): 
+                            一个用于区分不同的子类的值,在多态行为时使用。它可以接受的值包括
+                            <literal>null</literal> 和 <literal>not null</literal>。
+                        </para>
+                    </callout>
+                    <callout arearefs="class4">
+                        <para>
+                            <literal>mutable</literal> (可选,默认值为<literal>true</literal>):
+                            表明该类的实例是可变的或者不可变的。
+                        </para>
+                    </callout>    
+                    <callout arearefs="class5">
+                        <para>
+                            <literal>schema</literal> (可选):
+                            覆盖在根<literal>&lt;hibernate-mapping&gt;</literal>元素中指定的schema名字。
+                        </para>
+                    </callout>                
+                    <callout arearefs="class6">
+                        <para>
+                            <literal>catalog</literal> (可选):
+                            覆盖在根<literal>&lt;hibernate-mapping&gt;</literal>元素中指定的catalog名字。
+                        </para>
+                    </callout>                
+                    <callout arearefs="class7">
+                        <para>
+                            <literal>proxy</literal> (可选): 指定一个接口,在延迟装载时作为代理使用。
+                            你可以在这里使用该类自己的名字。
+                        </para>
+                    </callout>    
+                    <callout arearefs="class8">
+                        <para>
+                            <literal>dynamic-update</literal> (可选, 默认为 <literal>false</literal>): 
+                            指定用于<literal>UPDATE</literal> 的SQL将会在运行时动态生成,并且只更新那些改变过的字段。
+                        </para>
+                    </callout>    
+                    <callout arearefs="class9">
+                        <para>
+                            <literal>dynamic-insert</literal> (可选, 默认为 <literal>false</literal>): 
+                            指定用于<literal>INSERT</literal>的 SQL 将会在运行时动态生成,并且只包含那些非空值字段。
+                        </para>
+                    </callout>    
+                    <callout arearefs="class10">
+                        <para>
+                            <literal>select-before-update</literal> (可选, 默认为 <literal>false</literal>): 
+                            指定Hibernate除非确定对象真正被修改了(如果该值为true-译注),否则<emphasis>不会</emphasis>执行SQL
+                             <literal>UPDATE</literal>操作。在特定场合(实际上,它只在一个瞬时对象(transient object)关联到一个
+                             新的session中时执行的update()中生效),这说明Hibernate会在<literal>UPDATE</literal>
+                             之前执行一次额外的SQL <literal>SELECT</literal>操作,来决定是否应该执行
+                             <literal>UPDATE</literal>。
+                        </para>
+                    </callout>    
+                    <callout arearefs="class11">
+                        <para>
+                            <literal>polymorphism(多态)</literal> (可选, 默认值为 <literal>implicit (隐式)
+                            </literal>): 界定是隐式还是显式的使用多态查询(这只在Hibernate的具体表继承策略中用到-译注)。
+                        </para>
+                    </callout>    
+                    <callout arearefs="class12">
+                        <para>
+                            <literal>where</literal> (可选) 指定一个附加的SQL<literal>WHERE</literal> 条件,
+                            在抓取这个类的对象时会一直增加这个条件。
+                        </para>
+                    </callout>                 
+                    <callout arearefs="class13">
+                        <para>
+                            <literal>persister</literal> (可选): 指定一个定制的<literal>ClassPersister</literal>。
+                        </para>
+                    </callout>                 
+                    <callout arearefs="class14">
+                        <para>
+                            <literal>batch-size</literal> (可选,默认是<literal>1</literal>) 指定一个用于
+                            根据标识符(identifier)抓取实例时使用的"batch size"(批次抓取数量)。
+                        </para>
+                    </callout>                 
+                   <callout arearefs="class15">
+                        <para>
+                            <literal>optimistic-lock(乐观锁定)</literal> 
+                            (可选,默认是<literal>version</literal>): 决定乐观锁定的策略。
+                        </para>
+                    </callout>    
+                    <callout arearefs="class16">
+                        <para>
+                            <literal>lazy</literal> (可选): 通过设置<literal>lazy="false"</literal>,
+                            所有的延迟加载(Lazy fetching)功能将被全部禁用(disabled)。
+                        </para>
+                    </callout>    
+                    <callout arearefs="class17">
+                        <para>
+                            <literal>entity-name</literal> (可选,默认为类名): Hibernate3允许一个类进行多次映射(
+                            前提是映射到不同的表),并且允许使用Maps或XML代替Java层次的实体映射
+                            (也就是实现动态领域模型,不用写持久化类-译注)。
+                            更多信息请看<xref linkend="persistent-classes-dynamicmodels"/> and <xref linkend="xml"/>。
+                        </para>
+                    </callout>
+                    <callout arearefs="class18">
+                        <para>
+                            <literal>check</literal> (可选): 这是一个SQL表达式,
+                            用于为自动生成的schema添加多行(multi-row)约束<emphasis>检查</emphasis>。
+                        </para>
+                    </callout>
+                    <callout arearefs="class19">
+                        <para>
+                            <literal>rowid</literal> (可选): Hibernate可以使用数据库支持的所谓的ROWIDs,例如:
+                            Oracle数据库,如果你设置这个可选的<literal>rowid</literal>,
+                            Hibernate可以使用额外的字段<literal>rowid</literal>实现快速更新。ROWID是这个功能实现的重点,
+                            它代表了一个存储元组(tuple)的物理位置。
+                        </para>
+                    </callout>
+                    <callout arearefs="class20">
+                        <para>
+                            <literal>subselect</literal> (可选): 它将一个不可变(immutable)并且只读的实体映射到一个数据库的
+                            子查询中。当你想用视图代替一张基本表的时候,这是有用的,但最好不要这样做。更多的介绍请看下面内容。
+                        </para>
+                    </callout>
+                    <callout arearefs="class21">
+                        <para>
+                            <literal>abstract</literal> (可选): 用于在<literal>&lt;union-subclass&gt;</literal>的继承结构
+                            (hierarchies)中标识抽象超类。
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+           
+			<para>
+                若指明的持久化类实际上是一个接口,这也是完全可以接受的。
+                之后你可以用元素<literal>&lt;subclass&gt;</literal>来指定该接口的实际实现类。
+                你可以持久化任何<emphasis>static</emphasis>(静态的)内部类。
+                你应该使用标准的类名格式来指定类名,<literal>比如:Foo$Bar</literal>。
+            </para>
+            <para>
+                不可变类,<literal>mutable="false"</literal>不可以被应用程序更新或者删除。
+                这可以让Hibernate做一些小小的性能优化。
+            </para>
+            
+            <para>
+                可选的<literal>proxy</literal>属性允许延迟加载类的持久化实例。
+                Hibernate开始会返回实现了这个命名接口的CGLIB代理。当代理的某个方法被实际调用的时候,
+                真实的持久化对象才会被装载。参见下面的“用于延迟装载的代理”。
+            </para>
+            
+            <para><emphasis>Implicit</emphasis> (隐式)的多态是指,如果查询时给出的是任何超类、该类实现的接口或者该类的
+            名字,都会返回这个类的实例;如果查询中给出的是子类的名字,则会返回子类的实例。
+                <emphasis>Explicit</emphasis> (显式)的多态是指,只有在查询时给出明确的该类名字时才会返回这个类的实例;
+                同时只有在这个<literal>&lt;class&gt;</literal>的定义中作为<literal>&lt;subclass&gt;</literal>
+                或者<literal>&lt;joined-subclass&gt;</literal>出现的子类,才会可能返回。
+                在大多数情况下,默认的<literal>polymorphism="implicit"</literal>都是合适的。
+                显式的多态在有两个不同的类映射到同一个表的时候很有用。(允许一个“轻型”的类,只包含部分表字段)。
+            </para>
+            
+            <para>
+                <literal>persister</literal>属性可以让你定制这个类使用的持久化策略。
+                你可以指定你自己实现
+                <literal>org.hibernate.persister.EntityPersister</literal>的子类,你甚至可以完全从头开始编写一个
+                <literal>org.hibernate.persister.ClassPersister</literal>接口的实现,
+                比如是用储存过程调用、序列化到文件或者LDAP数据库来实现。
+                参阅<literal>org.hibernate.test.CustomPersister</literal>,这是一个简单的例子
+                (“持久化”到一个<literal>Hashtable</literal>)。
+            </para>
+            
+            <para>
+                请注意<literal>dynamic-update</literal>和<literal>dynamic-insert</literal>的设置并不会继承到子类,
+                所以在<literal>&lt;subclass&gt;</literal>或者<literal>&lt;joined-subclass&gt;</literal>元素中可能
+                需要再次设置。这些设置是否能够提高效率要视情形而定。请用你的智慧决定是否使用。
+            </para>
+            
+            <para>
+                使用<literal>select-before-update</literal>通常会降低性能。如果你重新连接一个脱管(detache)对象实例
+                到一个<literal>Session</literal>中时,它可以防止数据库不必要的触发update。
+                这就很有用了。
+            </para>
+            
+            <para>
+            	如果你打开了<literal>dynamic-update</literal>,你可以选择几种乐观锁定的策略:
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+            					<literal>version(版本检查)</literal> 检查version/timestamp字段
+            				</para>
+                </listitem>
+                <listitem>
+                    <para>
+            					<literal>all(全部)</literal> 检查全部字段
+            				</para>
+                </listitem>
+                <listitem>
+                    <para>
+            					<literal>dirty(脏检查)</literal>只检察修改过的字段
+            				</para>
+                </listitem>
+                <listitem>
+                    <para>
+            					<literal>none(不检查)</literal>不使用乐观锁定
+            				</para>
+                </listitem>
+            </itemizedlist>
+            <para>
+            	我们<emphasis>非常</emphasis>强烈建议你在Hibernate中使用version/timestamp字段来进行乐观锁定。
+            	对性能来说,这是最好的选择,并且这也是唯一能够处理在session外进行操作的策略(例如:
+            	在使用<literal>Session.merge()</literal>的时候)。
+            </para>
+
+            <para>
+                对Hibernate映射来说视图和表是没有区别的,这是因为它们在数据层都是透明的(
+                注意:一些数据库不支持视图属性,特别是更新的时候)。有时你想使用视图,但却不能在数据库
+                中创建它(例如:在遗留的schema中)。这样的话,你可以映射一个不可变的(immutable)并且是
+                只读的实体到一个给定的SQL子查询表达式:
+            </para>
+
+            <programlisting><![CDATA[<class name="Summary">
+    <subselect>
+        select item.name, max(bid.amount), count(*)
+        from item
+        join bid on bid.item_id = item.id
+        group by item.name
+    </subselect>
+    <synchronize table="item"/>
+    <synchronize table="bid"/>
+    <id name="name"/>
+    ...
+</class>]]></programlisting>
+
+            <para>
+                定义这个实体用到的表为同步(synchronize),确保自动刷新(auto-flush)正确执行,
+                并且依赖原实体的查询不会返回过期数据。<literal>&lt;subselect&gt;</literal>在属性元素
+                和一个嵌套映射元素中都可见。
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-id" revision="4">
+            <title>id</title>
+
+            <para>
+                被映射的类<emphasis>必须</emphasis>定义对应数据库表主键字段。大多数类有一个JavaBeans风格的属性,
+                为每一个实例包含唯一的标识。<literal>&lt;id&gt;</literal> 元素定义了该属性到数据库表主键字段的映射。
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="id1" coords="2 70"/>
+                    <area id="id2" coords="3 70" />
+                    <area id="id3" coords="4 70"/>
+                    <area id="id4" coords="5 70" />
+                    <area id="id5" coords="6 70" />
+                </areaspec>
+                <programlisting><![CDATA[<id
+        name="propertyName"
+        type="typename"
+        column="column_name"
+        unsaved-value="null|any|none|undefined|id_value"
+        access="field|property|ClassName"
+        node="element-name|@attribute-name|element/@attribute|.">
+
+        <generator class="generatorClass"/>
+</id>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="id1">
+                        <para>
+                            <literal>name</literal> (可选): 标识属性的名字。
+                        </para>
+                    </callout>
+                    <callout arearefs="id2">
+                        <para>
+                            <literal>type</literal> (可选): 标识Hibernate类型的名字。
+                        </para>
+                    </callout>
+                    <callout arearefs="id3">
+                        <para>
+                            <literal>column</literal> (可选 - 默认为属性名): 主键字段的名字。
+                        </para>
+                    </callout>
+                    <callout arearefs="id4">
+                        <para>
+                            <literal>unsaved-value</literal> (可选 - 默认为一个切合实际(sensible)的值): 
+                            一个特定的标识属性值,用来标志该实例是刚刚创建的,尚未保存。
+                            这可以把这种实例和从以前的session中装载过(可能又做过修改--译者注)
+                            但未再次持久化的实例区分开来。
+                        </para>
+                    </callout>            
+                   <callout arearefs="id5">
+                        <para>
+                            <literal>access</literal> (可选 - 默认为<literal>property</literal>):
+                             Hibernate用来访问属性值的策略。
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                如果 <literal>name</literal>属性不存在,会认为这个类没有标识属性。
+            </para>
+            
+            <para>
+                <literal>unsaved-value</literal> 属性在Hibernate3中几乎不再需要。
+            </para>
+
+            <para>
+                还有一个另外的<literal>&lt;composite-id&gt;</literal>定义可以访问旧式的多主键数据。
+                我们强烈不建议使用这种方式。
+            </para>
+            
+            <sect3 id="mapping-declaration-id-generator" revision="2">
+                <title>Generator</title>
+
+                <para>
+                可选的<literal>&lt;generator&gt;</literal>子元素是一个Java类的名字,
+                用来为该持久化类的实例生成唯一的标识。如果这个生成器实例需要某些配置值或者初始化参数,
+                用<literal>&lt;param&gt;</literal>元素来传递。
+            		</para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="org.hibernate.id.TableHiLoGenerator">
+                <param name="table">uid_table</param>
+                <param name="column">next_hi_value_column</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                    
+                    所有的生成器都实现<literal>org.hibernate.id.IdentifierGenerator</literal>接口。
+                    这是一个非常简单的接口;某些应用程序可以选择提供他们自己特定的实现。当然,
+                    Hibernate提供了很多内置的实现。下面是一些内置生成器的快捷名字:
+
+                    <variablelist>
+                        <varlistentry>
+                        <term><literal>increment</literal></term>
+                        <listitem>
+                            <para>
+                                用于为<literal>long</literal>, <literal>short</literal>或者<literal>int</literal>类型生成
+                                唯一标识。只有在没有其他进程往同一张表中插入数据时才能使用。
+                                <emphasis>在集群下不要使用。</emphasis>
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>identity</literal></term>
+                        <listitem>
+                            <para>
+                                对DB2,MySQL, MS SQL Server, Sybase和HypersonicSQL的内置标识字段提供支持。
+                                返回的标识符是<literal>long</literal>, <literal>short</literal> 或者<literal>int</literal>类型的。
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>sequence</literal></term>
+                        <listitem>
+                            <para>
+                                在DB2,PostgreSQL, Oracle, SAP DB, McKoi中使用序列(sequence),
+                                而在Interbase中使用生成器(generator)。返回的标识符是<literal>long</literal>, 
+                                <literal>short</literal>或者 <literal>int</literal>类型的。
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>hilo</literal></term>
+                        <listitem>
+                            <para id="mapping-declaration-id-hilodescription" revision="1">
+                                使用一个高/低位算法高效的生成<literal>long</literal>, <literal>short</literal>
+                                或者 <literal>int</literal>类型的标识符。给定一个表和字段(默认分别是
+                                <literal>hibernate_unique_key</literal> 和<literal>next_hi</literal>)作为高位值的来源。
+                                高/低位算法生成的标识符只在一个特定的数据库中是唯一的。
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>seqhilo</literal></term>
+                        <listitem>
+                            <para>
+                                使用一个高/低位算法来高效的生成<literal>long</literal>, <literal>short</literal>
+                                或者 <literal>int</literal>类型的标识符,给定一个数据库序列(sequence)的名字。
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>uuid</literal></term>
+                        <listitem>
+                            <para>
+                                用一个128-bit的UUID算法生成字符串类型的标识符,
+                                这在一个网络中是唯一的(使用了IP地址)。UUID被编码为一个32位16进制数字的字符串。
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>guid</literal></term>
+                        <listitem>
+                            <para>
+                                在MS SQL Server 和 MySQL 中使用数据库生成的GUID字符串。
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>native</literal></term>
+                        <listitem>
+                            <para>
+                                根据底层数据库的能力选择<literal>identity</literal>, <literal>sequence</literal> 
+                                或者<literal>hilo</literal>中的一个。
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>assigned</literal></term>
+                        <listitem>
+                            <para>
+                                让应用程序在<literal>save()</literal>之前为对象分配一个标示符。这是
+                                <literal>&lt;generator&gt;</literal>元素没有指定时的默认生成策略。
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>select</literal></term>
+                        <listitem>
+                            <para>
+                                通过数据库触发器选择一些唯一主键的行并返回主键值来分配一个主键。
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>foreign</literal></term>
+                        <listitem>
+                            <para>
+                                使用另外一个相关联的对象的标识符。通常和<literal>&lt;one-to-one&gt;</literal>联合起来使用。
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        <varlistentry>
+                        <term><literal>sequence-identity</literal></term>
+                        <listitem>
+                            <para>
+                                一种特别的序列生成策略,使用数据库序列来生成实际值,但将它和JDBC3的getGeneratedKeys结合在一起,使得在插入语句执行的时候就返回生成的值。目前为止只有面向JDK 1.4的Oracle 10g驱动支持这一策略。注意,因为Oracle驱动程序的一个bug,这些插入语句的注释被关闭了。(原文:Note comments on these insert statements are disabled due to a bug in the Oracle drivers.)
+                            </para>
+                        </listitem>
+                        </varlistentry>
+                        
+                    </variablelist>
+
+                </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-hilo" revision="1">
+                <title>高/低位算法(Hi/Lo Algorithm)</title>
+                <para>
+                <literal>hilo</literal> 和 <literal>seqhilo</literal>生成器给出了两种hi/lo算法的实现,
+                这是一种很令人满意的标识符生成算法。第一种实现需要一个“特殊”的数据库表来保存下一个可用的“hi”值。
+                第二种实现使用一个Oracle风格的序列(在被支持的情况下)。
+            </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="hilo">
+                <param name="table">hi_value</param>
+                <param name="column">next_value</param>
+                <param name="max_lo">100</param>
+        </generator>
+</id>]]></programlisting>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+        <generator class="seqhilo">
+                <param name="sequence">hi_value</param>
+                <param name="max_lo">100</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                很不幸,你在为Hibernate自行提供<literal>Connection</literal>时无法使用<literal>hilo</literal>。
+                当Hibernate使用JTA获取应用服务器的数据源连接时,你必须正确地配置
+                <literal>hibernate.transaction.manager_lookup_class</literal>。
+            </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-uuid">
+                <title>UUID算法(UUID Algorithm )</title>
+                <para>
+                UUID包含:IP地址,JVM的启动时间(精确到1/4秒),系统时间和一个计数器值(在JVM中唯一)。
+                在Java代码中不可能获得MAC地址或者内存地址,所以这已经是我们在不使用JNI的前提下的能做的最好实现了。
+            </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-sequences">
+            <title>标识字段和序列(Identity columns and Sequences)</title>
+                <para>
+                	对于内部支持标识字段的数据库(DB2,MySQL,Sybase,MS SQL),你可以使用<literal>identity</literal>关键字生成。
+                	对于内部支持序列的数据库(DB2,Oracle, PostgreSQL, Interbase, McKoi,SAP DB),
+                	你可以使用<literal>sequence</literal>风格的关键字生成。
+                	这两种方式对于插入一个新的对象都需要两次SQL查询。
+            		</para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+        <generator class="sequence">
+                <param name="sequence">person_id_sequence</param>
+        </generator>
+</id>]]></programlisting>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id" unsaved-value="0">
+        <generator class="identity"/>
+</id>]]></programlisting>
+                <para>
+                对于跨平台开发,<literal>native</literal>策略会从<literal>identity</literal>,
+                 <literal>sequence</literal> 和<literal>hilo</literal>中进行选择,选择哪一个,这取决于底层数据库的支持能力。
+            </para>
+            </sect3>
+            
+            <sect3 id="mapping-declaration-id-assigned">
+                <title>程序分配的标识符(Assigned Identifiers)</title>
+                <para>
+                如果你需要应用程序分配一个标示符(而非Hibernate来生成),你可以使用<literal>assigned</literal>
+                生成器。这种特殊的生成器会使用已经分配给对象的标识符属性的标识符值。
+                这个生成器使用一个自然键(natural key,有商业意义的列-译注)作为主键,而不是使用一个代理键(
+                surrogate key,没有商业意义的列-译注)。这是没有指定<literal>&lt;generator&gt;</literal>元素时的默认行为
+            </para>
+                
+                <para>
+                    当选择<literal>assigned</literal>生成器时,除非有一个version或timestamp属性,或者你定义了
+                    <literal>Interceptor.isUnsaved()</literal>,否则需要让Hiberante使用
+                    <literal>unsaved-value="undefined"</literal>,强制Hibernatet查询数据库来确定一个实例是瞬时的(transient)
+                    还是脱管的(detached)。
+                </para>
+            </sect3>
+
+            <sect3 id="mapping-declaration-id-select">
+                <title>触发器实现的主键生成器(Primary keys assigned by triggers)</title>
+                <para>
+                    仅仅用于遗留的schema中 (Hibernate不能使用触发器生成DDL)。
+                </para>
+
+                <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+        <generator class="select">
+                <param name="key">socialSecurityNumber</param>
+        </generator>
+</id>]]></programlisting>
+
+                <para>
+                    在上面的例子中,类定义了一个命名为<literal>socialSecurityNumber</literal>的唯一值属性,
+                    它是一个自然键(natural key),命名为<literal>person_id</literal>的代理键(surrogate key)
+                    的值由触发器生成。
+                </para>
+                
+            </sect3>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-compositeid" revision="3">
+            <title>composite-id</title>
+
+            <programlisting><![CDATA[<composite-id
+        name="propertyName"
+        class="ClassName"
+        mapped="true|false"
+        access="field|property|ClassName"
+        node="element-name|."
+        >
+
+        <key-property name="propertyName" type="typename" column="column_name"/>
+        <key-many-to-one name="propertyName class="ClassName" column="column_name"/>
+        ......
+</composite-id>]]></programlisting>
+
+            <para>
+                如果表使用联合主键,你可以映射类的多个属性为标识符属性。
+                <literal>&lt;composite-id&gt;</literal>元素接受<literal>&lt;key-property&gt;</literal>
+                属性映射和<literal>&lt;key-many-to-one&gt;</literal>属性映射作为子元素。
+            </para>
+            
+            <programlisting><![CDATA[<composite-id>
+        <key-property name="medicareNumber"/>
+        <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+            <para>
+                你的持久化类<emphasis>必须</emphasis>重载<literal>equals()</literal>和
+                <literal>hashCode()</literal>方法,来实现组合的标识符的相等判断。
+                实现<literal>Serializable</literal>接口也是必须的。
+            </para>
+
+            <para>
+                不幸的是,这种组合关键字的方法意味着一个持久化类是它自己的标识。除了对象自己之外,
+                没有什么方便的“把手”可用。你必须初始化持久化类的实例,填充它的标识符属性,再<literal>load()</literal>
+                组合关键字关联的持久状态。我们把这种方法称为<emphasis>embedded(嵌入式)</emphasis>的组合标识符,在重要的应用中不鼓励使用这种用法。
+            </para>
+
+            <para>
+                第二种方法我们称为<emphasis>mapped(映射式)</emphasis>组合标识符 (mapped composite identifier),<literal>&lt;composite-id&gt;</literal>元素中列出的标识属性不但在持久化类出现,还形成一个独立的标识符类。
+            </para>
+             
+            <programlisting><![CDATA[<composite-id class="MedicareId" mapped="true">
+        <key-property name="medicareNumber"/>
+        <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+            <para>
+                在这个例子中,组合标识符类<literal>MedicareId</literal>和实体类都含有<literal>medicareNumber</literal>和<literal>dependent</literal>属性。标识符类必须重载<literal>equals()</literal>和<literal>hashCode()</literal>并且实现<literal>Serializable</literal>接口。这种方法的缺点是出现了明显的代码重复。
+            </para>
+            
+            <para>
+                下面列出的属性是用来指定一个映射式组合标识符的:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>mapped</literal> (可选, 默认为<literal>false</literal>):
+                        指明使用一个映射式组合标识符,其包含的属性映射同时在实体类和组合标识符类中出现。
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>class</literal> (可选,但对映射式组合标识符必须指定): 
+                        作为组合标识符类使用的类名.
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                在<xref linkend="components-compositeid"/>一节中,我们会描述第三种方式,那就是把组合标识符实现为一个组件(component)类,这是更方便的方法。下面的属性仅对第三种方法有效:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>name</literal> (可选,但对这种方法而言必须): 包含此组件标识符的组件类型的名字 (参阅第9章).
+                        
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>access</literal> (可选 - 默认为<literal>property</literal>): 
+                        Hibernate应该使用的访问此属性值的策略
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>class</literal> (可选 - 默认会用反射来自动判定属性类型
+                        ): 用来作为组合标识符的组件类的类名(参阅下一节)
+                        
+                    </para>
+                </listitem>
+            </itemizedlist>
+            
+            <para>
+                第三种方式,被称为<emphasis>identifier component(标识符组件)</emphasis>是我们对几乎所有应用都推荐使用的方式。
+            </para>
+            
+        </sect2>
+        
+        <sect2 id="mapping-declaration-discriminator" revision="3">
+            <title>鉴别器(discriminator)</title>
+
+            <para>
+                在"一棵对象继承树对应一个表"的策略中,<literal>&lt;discriminator&gt;</literal>元素是必需的,
+                它定义了表的鉴别器字段。鉴别器字段包含标志值,用于告知持久化层应该为某个特定的行创建哪一个子类的实例。
+                如下这些受到限制的类型可以使用: 
+                <literal>string</literal>, <literal>character</literal>, <literal>integer</literal>, 
+                <literal>byte</literal>, <literal>short</literal>, <literal>boolean</literal>, 
+                <literal>yes_no</literal>, <literal>true_false</literal>.
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="discriminator1" coords="2 60"/>
+                    <area id="discriminator2" coords="3 60" />
+                    <area id="discriminator3" coords="4 60" />
+                    <area id="discriminator4" coords="5 60" />
+                    <area id="discriminator5" coords="6 60" />
+                </areaspec>
+                <programlisting><![CDATA[<discriminator
+        column="discriminator_column"
+        type="discriminator_type"
+        force="true|false"
+        insert="true|false"
+        formula="arbitrary sql expression"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="discriminator1">
+                        <para>
+                            <literal>column</literal> (可选 - 默认为 <literal>class</literal>) 鉴别器字段的名字
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator2">
+                        <para>
+                            <literal>type</literal> (可选 - 默认为 <literal>string</literal>) 一个Hibernate字段类型的名字
+                        </para>
+                    </callout>          
+                    <callout arearefs="discriminator3">
+                        <para>
+                            <literal>force(强制)</literal> (可选 - 默认为 <literal>false</literal>) 
+                            "强制"Hibernate指定允许的鉴别器值,即使当取得的所有实例都是根类的。
+                        </para>
+                    </callout>          
+                    <callout arearefs="discriminator4">
+                        <para>
+                            <literal>insert</literal> (可选 - 默认为<literal>true</literal>)
+                            如果你的鉴别器字段也是映射为复合标识(composite identifier)的一部分,则需将
+                            这个值设为<literal>false</literal>。(告诉Hibernate在做SQL <literal>INSERT</literal>
+                            时不包含该列)
+                        </para>
+                    </callout>
+                    <callout arearefs="discriminator5">
+                        <para>
+                            <literal>formula</literal> (可选) 
+                            一个SQL表达式,在类型判断(判断是父类还是具体子类-译注)时执行。可用于基于内容的鉴别器。
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                鉴别器字段的实际值是根据<literal>&lt;class&gt;</literal>和<literal>&lt;subclass&gt;</literal>元素中
+                的<literal>discriminator-value</literal>属性得来的。
+            </para>
+            
+            <para>
+                <literal>force</literal>属性仅仅在这种情况下有用的:表中包含没有被映射到持久化类的附加辨别器值。
+                这种情况不会经常遇到。          
+            </para>
+
+            <para>
+                使用<literal>formula</literal>属性你可以定义一个SQL表达式,用来判断一个行数据的类型。
+            </para>
+
+            <programlisting><![CDATA[<discriminator
+    formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
+    type="integer"/>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-version" revision="4">
+            <title>版本(version)(可选)</title>
+            
+            <para>
+                <literal>&lt;version&gt;</literal>元素是可选的,表明表中包含附带版本信息的数据。
+                这在你准备使用<emphasis> 长事务(long transactions)</emphasis>的时候特别有用。(见后)
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="version1" coords="2 70"/>
+                    <area id="version2" coords="3 70"/>
+                    <area id="version3" coords="4 70"/>
+                    <area id="version4" coords="5 70"/>
+                    <area id="version5" coords="6 70"/>
+                    <area id="version6" coords="7 70"/>
+                    <area id="version7" coords="8 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<version
+        column="version_column"
+        name="propertyName"
+        type="typename"
+        access="field|property|ClassName"
+        unsaved-value="null|negative|undefined"
+        generated="never|always"
+        insert="true|false"
+        node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="version1">
+                        <para>
+                            <literal>column</literal> (可选 - 默认为属性名): 指定持有版本号的字段名。
+                        </para>
+                    </callout>          
+                    <callout arearefs="version2">
+                        <para>
+                            <literal>name</literal>: 持久化类的属性名。
+                        </para>
+                    </callout>
+                    <callout arearefs="version3">
+                        <para>
+                            <literal>type</literal> (可选 - 默认是 <literal>integer</literal>): 版本号的类型。
+                        </para>
+                    </callout>          
+                   <callout arearefs="version4">
+                        <para>
+                            <literal>access</literal> (可选 - 默认是 <literal>property</literal>):  
+                            Hibernate用于访问属性值的策略。
+                        </para>
+                    </callout>
+                   <callout arearefs="version5">
+                        <para>
+                            <literal>unsaved-value</literal> (可选 - 默认是<literal>undefined</literal>): 
+                            用于标明某个实例时刚刚被实例化的(尚未保存)版本属性值,依靠这个值就可以把这种情况
+                            和已经在先前的session中保存或装载的脱管(detached)实例区分开来。
+                            (<literal>undefined</literal>指明应被使用的标识属性值。)
+                        </para>
+                    </callout>
+                    <callout arearefs="version6">
+                        <para>
+                            <literal>generated</literal> (可选 - 默认是 <literal>never</literal>):
+                            表明此版本属性值是否实际上是由数据库生成的。请参阅<xref linkend="mapping-generated">generated properties</xref>部分的讨论。
+                        </para>
+                    </callout>
+                    <callout arearefs="version7">
+                        <para>
+                            <literal>insert</literal> (可选 - 默认是 <literal>true</literal>):
+                            表明此版本列应该包含在SQL插入语句中。只有当数据库字段有默认值<literal>0</literal>的时候,才可以设置为<literal>false</literal>。
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                版本号必须是以下类型:<literal>long</literal>, <literal>integer</literal>,
+                <literal>short</literal>, <literal>timestamp</literal>或者<literal>calendar</literal>。
+            </para>
+            
+            <para>
+                一个脱管(detached)实例的version或timestamp属性不能为空(null),因为Hibernate不管
+                <literal>unsaved-value</literal>被指定为何种策略,它将任何属性为空的version或timestamp
+                实例看作为瞬时(transient)实例。
+                <emphasis>避免Hibernate中的传递重附(transitive reattachment)问题的一个简单方法是
+              	定义一个不能为空的version或timestamp属性,特别是在人们使用程序分配的标识符(assigned identifiers)
+              	或复合主键时非常有用!</emphasis>
+            </para>
+        </sect2>
+        
+        <sect2 id="mapping-declaration-timestamp" revision="4">
+            <title>timestamp (可选)</title>
+
+            <para>
+                可选的<literal>&lt;timestamp&gt;</literal>元素指明了表中包含时间戳数据。
+                这用来作为版本的替代。时间戳本质上是一种对乐观锁定的一种不是特别安全的实现。当然,
+                有时候应用程序可能在其他方面使用时间戳。
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="timestamp1" coords="2 70"/>
+                    <area id="timestamp2" coords="3 70" />
+                    <area id="timestamp3" coords="4 70" />
+                    <area id="timestamp4" coords="5 70" />
+                    <area id="timestamp5" coords="6 70" />
+                    <area id="timestamp6" coords="7 70" />
+                </areaspec>            
+                <programlisting><![CDATA[<timestamp
+        column="timestamp_column"
+        name="propertyName"
+        access="field|property|ClassName"
+        unsaved-value="null|undefined"
+        source="vm|db"
+        generated="never|always"
+        node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="timestamp1">
+                        <para>
+                            <literal>column</literal> (可选 - 默认为属性名): 持有时间戳的字段名。
+                        </para>
+                    </callout>                   
+                    <callout arearefs="timestamp2">
+                        <para>
+                            <literal>name</literal>: 在持久化类中的JavaBeans风格的属性名,
+                            其Java类型是 <literal>Date</literal> 或者 <literal>Timestamp</literal>的。
+                        </para>
+                    </callout>
+                   <callout arearefs="timestamp3">
+                        <para>
+                            <literal>access</literal> (可选 - 默认是 <literal>property</literal>): 
+                             Hibernate用于访问属性值的策略。
+                        </para>
+                    </callout>
+                   <callout arearefs="timestamp4">
+                        <para>
+                            <literal>unsaved-value</literal> (可选 - 默认是<literal>null</literal>): 
+                            用于标明某个实例时刚刚被实例化的(尚未保存)版本属性值,依靠这个值就可以把这种情况和
+                            已经在先前的session中保存或装载的脱管(detached)实例区分开来。(<literal>undefined</literal>
+                            指明使用标识属性值进行这种判断。)
+                        </para>
+                    </callout>
+                   <callout arearefs="timestamp5">
+                        <para>
+                            <literal>source</literal> (可选 - 默认是 <literal>vm</literal>):
+                            Hibernate如何才能获取到时间戳的值呢?从数据库,还是当前JVM?从数据库获取会带来一些负担,因为Hibernate必须访问数据库来获得“下一个值”,但是在集群环境中会更安全些。还要注意,并不是所有的<literal>Dialect(方言)</literal>都支持获得数据库的当前时间戳的,而支持的数据库中又有一部分因为精度不足,用于锁定是不安全的(例如Oracle 8)。
+                        </para>
+                    </callout>
+                    <callout arearefs="timestamp6">
+                        <para>
+                            <literal>generated</literal> (可选 - 默认是 <literal>never</literal>):
+                            指出时间戳值是否实际上是由数据库生成的.请参阅<xref linkend="mapping-generated">generated properties</xref>的讨论。
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                注意,<literal>&lt;timestamp&gt;</literal> 和<literal>&lt;version type="timestamp"&gt;</literal>是等价的。并且<literal>&lt;timestamp source="db"&gt;</literal>和<literal>&lt;version type="dbtimestamp"&gt;</literal>是等价的。
+            </para>
+        </sect2>
+
+
+        <sect2 id="mapping-declaration-property" revision="4">
+            <title>property</title>
+
+            <para>
+                <literal>&lt;property&gt;</literal>元素为类定义了一个持久化的,JavaBean风格的属性。
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="property1" coords="2 70"/>
+                    <area id="property2" coords="3 70"/>
+                    <area id="property3" coords="4 70"/>
+                    <areaset id="property4-5" coords="">
+	                    <area id="property4" coords='5 70'/>
+    	                <area id="property5" coords='6 70'/>
+                    </areaset>
+                    <area id="property6" coords="7 70"/>
+                    <area id="property7" coords="8 70"/>
+                    <area id="property8" coords="9 70"/>
+                    <area id="property9" coords="10 70"/>
+                    <area id="property10" coords="11 70"/>
+                    <area id="property11" coords="12 70"/>
+                    <area id="property12" coords="13 70"/>
+                </areaspec>            
+                <programlisting><![CDATA[<property
+        name="propertyName"
+        column="column_name"
+        type="typename"
+        update="true|false"
+        insert="true|false"
+        formula="arbitrary SQL expression"
+        access="field|property|ClassName"
+        lazy="true|false"
+        unique="true|false"
+        not-null="true|false"
+        optimistic-lock="true|false"
+        generated="never|insert|always"
+        node="element-name|@attribute-name|element/@attribute|."
+
+        index="index_name"
+        unique_key="unique_key_id"
+        length="L"
+        precision="P"
+        scale="S"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="property1">
+                        <para>
+                            <literal>name</literal>: 属性的名字,以小写字母开头。
+                        </para>
+                    </callout>                   
+                    <callout arearefs="property2">
+                        <para>
+                            <literal>column</literal> (可选 - 默认为属性名字): 对应的数据库字段名。
+                            也可以通过嵌套的<literal>&lt;column&gt;</literal>元素指定。
+                        </para>
+                    </callout>
+                    <callout arearefs="property3">
+                        <para>
+                            <literal>type</literal> (可选): 一个Hibernate类型的名字。
+                        </para>
+                    </callout>
+                    <callout arearefs="property4-5">
+                        <para>
+                            <literal>update, insert</literal> (可选 - 默认为 <literal>true</literal>) :
+                            表明用于<literal>UPDATE</literal> 和/或 <literal>INSERT</literal>
+                            的SQL语句中是否包含这个被映射了的字段。这二者如果都设置为<literal>false</literal>
+                            则表明这是一个“外源性(derived)”的属性,它的值来源于映射到同一个(或多个)
+                            字段的某些其他属性,或者通过一个trigger(触发器)或其他程序生成。
+                        </para>
+                    </callout>
+                    <callout arearefs="property6">
+                        <para>
+                            <literal>formula</literal> (可选): 一个SQL表达式,定义了这个<emphasis>计算
+                            (computed)</emphasis> 属性的值。计算属性没有和它对应的数据库字段。
+                        </para>
+                    </callout>
+                   <callout arearefs="property7">
+                        <para>
+                            <literal>access</literal> (可选 - 默认值为 <literal>property</literal>): 
+                            Hibernate用来访问属性值的策略。
+                        </para>
+                    </callout>
+                   <callout arearefs="property8">
+                        <para>
+                            <literal>lazy</literal> (可选 - 默认为 <literal>false</literal>): 指定
+                            指定实例变量第一次被访问时,这个属性是否延迟抓取(fetched lazily)(
+                            需要运行时字节码增强)。
+                        </para>
+                    </callout>
+                    <callout arearefs="property9">
+                        <para>
+                            <literal>unique</literal> (可选): 使用DDL为该字段添加唯一的约束。
+                            同样,允许它作为<literal>property-ref</literal>引用的目标。
+                        </para>
+                    </callout>
+                    <callout arearefs="property10">
+                        <para>
+                            <literal>not-null</literal> (可选): 使用DDL为该字段添加可否为空(nullability)的约束。
+                        </para>
+                    </callout>
+                    <callout arearefs="property11">
+                        <para>
+                            <literal>optimistic-lock</literal> (可选 - 默认为 <literal>true</literal>): 
+                            指定这个属性在做更新时是否需要获得乐观锁定(optimistic lock)。
+                            换句话说,它决定这个属性发生脏数据时版本(version)的值是否增长。
+                        </para>
+                    </callout>
+                    <callout arearefs="property12">
+                        <para>
+                            <literal>generated</literal> (可选 - 默认为 <literal>never</literal>):
+                            表明此属性值是否实际上是由数据库生成的。请参阅<xref linkend="mapping-generated">generated properties</xref>的讨论。
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                <emphasis>typename</emphasis>可以是如下几种:
+            </para>
+
+            <orderedlist spacing="compact">
+                <listitem>
+                    <para>
+                        Hibernate基本类型名(比如:<literal>integer, string, character,date, timestamp,
+                         float, binary, serializable, object, blob</literal>)。
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        一个Java类的名字,这个类属于一种默认基础类型 
+                        (比如: <literal>int, float,char, java.lang.String, java.util.Date, java.lang.Integer, 
+                        java.sql.Clob</literal>)。
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        一个可以序列化的Java类的名字。
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        一个自定义类型的类的名字。(比如: <literal>com.illflow.type.MyCustomType</literal>)。
+                    </para>
+                </listitem>
+            </orderedlist>
+
+            <para>
+                如果你没有指定类型,Hibernarte会使用反射来得到这个名字的属性,以此来猜测正确的Hibernate类型。
+                Hibernate会按照规则2,3,4的顺序对属性读取器(getter方法)的返回类进行解释。然而,这还不够。
+                在某些情况下你仍然需要<literal>type</literal>属性。(比如,为了区别<literal>Hibernate.DATE</literal>
+                和<literal>Hibernate.TIMESTAMP</literal>,或者为了指定一个自定义类型。)
+            </para>
+            
+            <para>
+            	<literal>access</literal>属性用来让你控制Hibernate如何在运行时访问属性。在默认情况下,
+            	Hibernate会使用属性的get/set方法对(pair)。如果你指明<literal>access="field"</literal>,
+            	Hibernate会忽略get/set方法对,直接使用反射来访问成员变量。你也可以指定你自己的策略,
+            	这就需要你自己实现<literal>org.hibernate.property.PropertyAccessor</literal>接口,
+            	再在access中设置你自定义策略类的名字。
+            </para>
+
+            <para>
+                衍生属性(derive propertie)是一个特别强大的特征。这些属性应该定义为只读,属性值在装载时计算生成。
+                你用一个SQL表达式生成计算的结果,它会在这个实例转载时翻译成一个SQL查询的<literal>SELECT</literal>
+                子查询语句。
+            </para>
+
+        <programlisting><![CDATA[
+<property name="totalPrice"
+    formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p
+                WHERE li.productId = p.productId
+                AND li.customerId = customerId
+                AND li.orderNumber = orderNumber )"/>]]></programlisting>
+
+            <para>
+                注意,你可以使用实体自己的表,而不用为这个特别的列定义别名(
+                上面例子中的<literal>customerId</literal>)。同时注意,如果你不喜欢使用属性,
+                你可以使用嵌套的<literal>&lt;formula&gt;</literal>映射元素。
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-manytoone" revision="5">
+            <title>多对一(many-to-one)</title>
+
+            <para>
+                通过<literal>many-to-one</literal>元素,可以定义一种常见的与另一个持久化类的关联。
+                这种关系模型是多对一关联(实际上是一个对象引用-译注):这个表的一个外键引用目标表的
+                主键字段。
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="manytoone1" coords="2 70"/>
+                    <area id="manytoone2" coords="3 70"/>
+                    <area id="manytoone3" coords="4 70"/>
+                    <area id="manytoone4" coords="5 70"/>
+                    <area id="manytoone5" coords="6 70"/>
+                    <areaset id="manytoone6-7" coords="">
+                        <area id="manytoone6" coords='7 70'/>
+                        <area id="manytoone7" coords='8 70'/>
+                    </areaset>
+                    <area id="manytoone8" coords="9 70"/>
+                    <area id="manytoone9" coords="10 70"/>
+                    <area id="manytoone10" coords="11 70"/>
+                    <area id="manytoone11" coords="12 70"/>
+                    <area id="manytoone12" coords="13 70"/>
+                    <area id="manytoone13" coords="14 70"/>
+                    <area id="manytoone14" coords="15 70"/>
+                    <area id="manytoone15" coords="16 70"/>
+                    <area id="manytoone16" coords="17 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<many-to-one
+        name="propertyName"
+        column="column_name"
+        class="ClassName"
+        cascade="cascade_style"
+        fetch="join|select"
+        update="true|false"
+        insert="true|false"
+        property-ref="propertyNameFromAssociatedClass"
+        access="field|property|ClassName"
+        unique="true|false"
+        not-null="true|false"
+        optimistic-lock="true|false"
+        lazy="proxy|no-proxy|false"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        formula="arbitrary SQL expression"
+        node="element-name|@attribute-name|element/@attribute|."
+
+        embed-xml="true|false"
+        index="index_name"
+        unique_key="unique_key_id"
+        foreign-key="foreign_key_name"
+        
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="manytoone1">
+                        <para>
+                            <literal>name</literal>: 属性名。
+                        </para>                   
+                    </callout>                   
+                    <callout arearefs="manytoone2">
+                        <para>
+                            <literal>column</literal> (可选): 外间字段名。它也可以通过嵌套的
+                            <literal>&lt;column&gt;</literal>元素指定。
+                        </para>    
+                    </callout>
+                    <callout arearefs="manytoone3">
+                        <para>
+                            <literal>class</literal> (可选 - 默认是通过反射得到属性类型): 关联的类的名字。
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone4">
+                        <para>
+                            <literal>cascade(级联)</literal> (可选): 指明哪些操作会从父对象级联到关联的对象。
+                        </para>                 
+                    </callout>
+                    <callout arearefs="manytoone5">
+                        <para>
+                            <literal>fetch</literal> (可选 - 默认为 <literal>select</literal>):
+			    在外连接抓取(outer-join fetching)和序列选择抓取(sequential select fetching)两者中选择其一。 
+                        </para>                
+                    </callout>
+                    <callout arearefs="manytoone6">
+                        <para>
+                            <literal>update, insert</literal> (可选 - 默认为 <literal>true</literal>) 
+                            指定对应的字段是否包含在用于<literal>UPDATE</literal> 和/或 <literal>INSERT</literal>
+                            的SQL语句中。如果二者都是<literal>false</literal>,则这是一个纯粹的
+                            “外源性(derived)”关联,它的值是通过映射到同一个(或多个)字段的某些其他属性得到
+                            或者通过trigger(触发器)、或其他程序生成。
+                        </para>                    
+                    </callout>
+                    <callout arearefs="manytoone7">
+                        <para>
+                            <literal>property-ref</literal>: (可选) 指定关联类的一个属性,这个属性将会和本外键相对应。
+                            如果没有指定,会使用对方关联类的主键。
+                        </para>              
+                    </callout>                   
+                   <callout arearefs="manytoone8">
+                        <para>
+                            <literal>access</literal> (可选 - 默认是 <literal>property</literal>): 
+                            Hibernate用来访问属性的策略。
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone9">
+                        <para>
+                            <literal>unique</literal> (可选): 使用DDL为外键字段生成一个唯一约束。此外,
+                            这也可以用作<literal>property-ref</literal>的目标属性。这使关联同时具有
+                            一对一的效果。
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone10">
+                        <para>
+                            <literal>not-null</literal> (可选): 使用DDL为外键字段生成一个非空约束。
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone11">
+                        <para>
+                            <literal>optimistic-lock</literal> (可选 - 默认为 <literal>true</literal>): 
+                            指定这个属性在做更新时是否需要获得乐观锁定(optimistic lock)。
+                            换句话说,它决定这个属性发生脏数据时版本(version)的值是否增长。
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone12">
+                        <para>
+                            <literal>lazy</literal> (可选 - 默认为 <literal>proxy</literal>): 
+                            默认情况下,单点关联是经过代理的。<literal>lazy="no-proxy"</literal>指定此属性应该在实例变量第一次被访问时应该延迟抓取(fetche lazily)(需要运行时字节码的增强)。
+                            <literal>lazy="false"</literal>指定此关联总是被预先抓取。
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone13">
+                        <para>
+                            <literal>not-found</literal> (可选 - 默认为 <literal>exception</literal>): 
+                            指定外键引用的数据不存在时如何处理:
+                            <literal>ignore</literal>会将行数据不存在视为一个空(null)关联。
+                        </para>
+                    </callout>
+                    <callout arearefs="manytoone14">
+                        <para>
+                            <literal>entity-name</literal> (可选): 被关联的类的实体名。
+                        </para>                   
+                    </callout>
+                    <callout arearefs="manytoone15">
+                        <para>
+                            <literal>formula</literal> (可选): 
+                            SQL表达式,用于定义<emphasis>computed(计算出的)</emphasis>外键值。
+                        </para>
+                    </callout>
+                    
+                </calloutlist>
+            </programlistingco>
+
+            
+            <para>
+                <literal>cascade</literal>属性设置为除了<literal>none</literal>以外任何有意义的值,
+                它将把特定的操作传递到关联对象中。这个值就代表着Hibernate基本操作的名称,
+                <literal>persist, merge, delete, save-update, evict, replicate, lock, refresh</literal>,
+                以及特别的值<literal>delete-orphan</literal>和<literal>all</literal>,并且可以用逗号分隔符
+                来组合这些操作,例如,<literal>cascade="persist,merge,evict"</literal>或
+                <literal>cascade="all,delete-orphan"</literal>。更全面的解释请参考<xref linkend="objectstate-transitive"/>. 注意,单值关联 (many-to-one 和 
+                one-to-one 关联) 不支持删除孤儿(orphan delete,删除不再被引用的值).
+                
+                
+            </para>
+            
+            <para>
+                一个典型的简单<literal>many-to-one</literal>定义例子:
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="product" class="Product" column="PRODUCT_ID"/>]]></programlisting>
+            
+            <para>
+                <literal>property-ref</literal>属性只应该用来对付遗留下来的数据库系统,
+                可能有外键指向对方关联表的是个非主键字段(但是应该是一个惟一关键字)的情况下。
+                这是一种十分丑陋的关系模型。比如说,假设<literal>Product</literal>类有一个惟一的序列号,
+                它并不是主键。(<literal>unique</literal>属性控制Hibernate通过SchemaExport工具进行的DDL生成。)
+            </para>
+            
+            
+            <programlisting><![CDATA[<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>]]></programlisting>
+            
+            <para>
+                那么关于<literal>OrderItem</literal> 的映射可能是:
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>]]></programlisting>
+            
+            <para>
+                当然,我们决不鼓励这种用法。
+            </para>
+            
+           
+            <para>
+                如果被引用的唯一主键由关联实体的多个属性组成,你应该在名称为<literal>&lt;properties&gt;</literal>的元素
+                里面映射所有关联的属性。
+            </para>
+            
+            <para>
+            	假若被引用的唯一主键是组件的属性,你可以指定属性路径:
+            </para>
+            
+           <programlisting><![CDATA[<many-to-one name="owner" property-ref="identity.ssn" column="OWNER_SSN"/>]]></programlisting>           
+
+        </sect2>
+
+<sect2 id="mapping-declaration-onetoone" revision="3">
+            <title>一对一</title>
+
+            <para>
+		持久化对象之间一对一的关联关系是通过<literal>one-to-one</literal>元素定义的。
+	     </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="onetoone1" coords="2 70"/>
+                    <area id="onetoone2" coords="3 70"/>
+                    <area id="onetoone3" coords="4 70"/>
+                    <area id="onetoone4" coords="5 70"/>
+                    <area id="onetoone5" coords="6 70"/>
+                    <area id="onetoone6" coords="7 70"/>
+                    <area id="onetoone7" coords="8 70"/>
+                    <area id="onetoone8" coords="9 70"/>
+                    <area id="onetoone9" coords="10 70"/>
+                    <area id="onetoone10" coords="11 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<one-to-one
+        name="propertyName"
+        class="ClassName"
+        cascade="cascade_style"
+        constrained="true|false"
+        fetch="join|select"
+        property-ref="propertyNameFromAssociatedClass"
+        access="field|property|ClassName"
+        formula="any SQL expression"
+        lazy="proxy|no-proxy|false"
+        entity-name="EntityName"
+        node="element-name|@attribute-name|element/@attribute|."
+
+        embed-xml="true|false"
+        foreign-key="foreign_key_name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="onetoone1">
+                        <para>
+                            <literal>name</literal>: 属性的名字。
+                        </para>                
+                    </callout>                   
+                    <callout arearefs="onetoone2">
+                        <para>
+                            <literal>class</literal>  (可选 - 默认是通过反射得到的属性类型):被关联的类的名字。
+                        </para>                   
+                    </callout>
+                    <callout arearefs="onetoone3">
+                        <para>
+                            <literal>cascade(级联)</literal> (可选) 表明操作是否从父对象级联到被关联的对象。
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone4">                        
+                        <para>
+                            <literal>constrained(约束)</literal> (可选) 表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。
+                           这个选项影响<literal>save()</literal>和<literal>delete()</literal>在级联执行时的先后顺序以及
+                            决定该关联能否被委托(也在schema export tool中被使用).
+                        </para>                  
+                    </callout>
+                    <callout arearefs="onetoone5">
+                        <para>
+                            <literal>fetch</literal> (可选 - 默认设置为<literal>选择</literal>): 
+                            在外连接抓取或者序列选择抓取选择其一.                            
+                        </para>              
+                    </callout>
+                    <callout arearefs="onetoone6">
+                        <para>
+                            <literal>property-ref</literal>: (可选) 指定关联类的属性名,这个属性将会和本类的主键相对应。如果没有指定,会使用对方关联类的主键。
+                        </para>                
+                    </callout>                   
+                    <callout arearefs="onetoone7">
+                        <para>
+                            <literal>access</literal>  (可选 - 默认是 <literal>property</literal>): Hibernate用来访问属性的策略。
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone8">
+                        <para>
+                            <literal>formula </literal> (可选):绝大多数一对一的关联都指向其实体的主键。在一些少见的情况中, 你可能会指向其他的一个或多个字段,或者是一个表达式,这些情况下,你可以用一个SQL公式来表示。 (可以在org.hibernate.test.onetooneformula找到例子)
+
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone9">
+                        <para>
+                            <literal>lazy</literal> (可选 - 默认为 <literal>proxy</literal>): 
+                            默认情况下,单点关联是经过代理的。<literal>lazy="no-proxy"</literal>指定此属性应该在实例变量第一次被访问时应该延迟抓取(fetche lazily)(需要运行时字节码的增强)。
+                            <literal>lazy="false"</literal>指定此关联总是被预先抓取。<emphasis>注意,如果<literal>constrained="false"</literal>,
+                            不可能使用代理,Hibernate会采取预先抓取!</emphasis>
+                        </para>
+                    </callout>
+                    <callout arearefs="onetoone10">
+                        <para>
+                            <literal>entity-name</literal> (可选): 被关联的类的实体名。
+                        </para>                   
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+        
+            <para>
+                有两种不同的一对一关联:
+            </para>
+            <itemizedlist>
+            <listitem>
+             <para>
+                主键关联
+            </para></listitem>
+            <listitem>
+            <para>
+                惟一外键关联
+            </para></listitem>
+            </itemizedlist>
+            
+             <para>
+                主键关联不需要额外的表字段;如果两行是通过这种一对一关系相关联的,那么这两行就共享同样的主关键字值。所以如果你希望两个对象通过主键一对一关联,你必须确认它们被赋予同样的标识值!
+            </para>
+            
+            <para>
+                比如说,对下面的<literal>Employee</literal>和<literal>Person</literal>进行主键一对一关联:
+            </para>
+            
+
+            <programlisting><![CDATA[<one-to-one name="person" class="Person"/>]]></programlisting>
+            <programlisting><![CDATA[<one-to-one name="employee" class="Employee" constrained="true"/>]]></programlisting>
+
+            <para>
+                现在我们必须确保PERSON和EMPLOYEE中相关的字段是相等的。我们使用一个被成为<literal>foreign</literal>的特殊的hibernate标识符生成策略:
+            </para>
+
+            <programlisting><![CDATA[<class name="person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="foreign">
+            <param name="property">employee</param>
+        </generator>
+    </id>
+    ...
+    <one-to-one name="employee"
+        class="Employee"
+        constrained="true"/>
+</class>]]></programlisting>
+
+            <para>
+                一个刚刚保存的<literal>Person</literal>实例被赋予和该<literal>Person</literal>的<literal>employee</literal>属性所指向的<literal>Employee</literal>实例同样的关键字值。
+            </para>
+
+             <para>
+                另一种方式是一个外键和一个惟一关键字对应,上面的<literal>Employee</literal>和<literal>Person</literal>的例子,如果使用这种关联方式,可以表达成:
+            </para>
+            
+            <programlisting><![CDATA[<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/>]]></programlisting>
+            
+             <para>
+                如果在<literal>Person</literal>的映射加入下面几句,这种关联就是双向的:
+            </para>
+            
+           <programlisting><![CDATA[<one-to-one name"employee" class="Employee" property-ref="person"/>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="mapping-declaration-naturalid">
+            <title>自然ID(natural-id)</title>
+
+            <programlisting><![CDATA[<natural-id mutable="true|false"/>
+        <property ... />
+        <many-to-one ... />
+        ......
+</natural-id>]]></programlisting>
+
+            <para>
+                我们建议使用代用键(键值不具备实际意义)作为主键,我们仍然应该尝试为所有的实体采用自然的键值作为(附加——译者注)标示。自然键(natural key)是单个或组合属性,他们必须唯一且非空。如果它还是不可变的那就更理想了。在<literal>&lt;natural-id&gt;</literal>元素中列出自然键的属性。Hibernate会帮你生成必须的唯一键值和非空约束,你的映射会更加的明显易懂(原文是self-documenting,自我注解)。
+            </para>
+            
+            <para>
+                我们强烈建议你实现<literal>equals()</literal> 和<literal>hashCode()</literal>方法,来比较实体的自然键属性。
+            </para>
+
+            <para>
+                这一映射不是为了把自然键作为主键而准备的。
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>mutable</literal> (可选, 默认为<literal>false</literal>): 
+                        默认情况下,自然标识属性被假定为不可变的(常量)。
+                    </para>
+                </listitem>
+            </itemizedlist>
+            
+        </sect2>
+        
+
+        <sect2 id="mapping-declaration-component" revision="2">
+            <title>组件(component), 动态组件(dynamic-component)</title>
+
+            <para>
+                <literal>&lt;component&gt;</literal>元素把子对象的一些元素与父类对应的表的一些字段映射起来。 然后组件可以定义它们自己的属性、组件或者集合。参见后面的“Components”一章。
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="component1" coords="2 45"/>
+                    <area id="component2" coords="3 45"/>
+                    <area id="component3" coords="4 45"/>
+                    <area id="component4" coords="5 45"/>
+                    <area id="component5" coords="6 45"/>
+                    <area id="component6" coords="7 45"/>
+                    <area id="component7" coords="8 45"/>
+                    <area id="component8" coords="9 45"/>
+                </areaspec>            
+                <programlisting><![CDATA[<component 
+        name="propertyName" 
+        class="className"
+        insert="true|false"
+        update="true|false"
+        access="field|property|ClassName"
+        lazy="true|false"
+        optimistic-lock="true|false"
+        unique="true|false"
+        node="element-name|."
+>
+        
+        <property ...../>
+        <many-to-one .... />
+        ........
+</component>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="component1">
+                        <para>
+                            <literal>name</literal>: 属性名
+                        </para>
+
+                    </callout>                   
+                    <callout arearefs="component2">
+                        <para>
+                            <literal>class</literal> (可选 - 默认为通过反射得到的属性类型):组件(子)类的名字。
+                        </para>
+                    </callout>
+                    <callout arearefs="component3">
+                         <para>
+                            <literal>insert</literal>: 被映射的字段是否出现在SQL的<literal>INSERT</literal>语句中?
+                        </para> 
+                    </callout>                   
+                    <callout arearefs="component4">
+                        <para>
+                            <literal>update</literal>: 被映射的字段是否出现在SQL的<literal>UPDATE</literal>语句中?
+                        </para>
+                    </callout>                   
+                    <callout arearefs="component5">
+                        <para>
+                            <literal>access</literal> (可选 - 默认是 <literal>property</literal>): Hibernate用来访问属性的策略。
+                        </para>
+                    </callout>
+                   <callout arearefs="component6">
+                        <para>
+                            <literal>lazy</literal> (可选 - 默认是 <literal>false</literal>): 表明此组件应在实例变量第一次被访问的时候延迟加载(需要编译时字节码装置器)
+                        </para>
+                    </callout>
+                    <callout arearefs="component7">
+                            <para>
+                                <literal>optimistic-lock</literal> (可选 - 默认是 <literal>true</literal>):表明更新此组件是否需要获取乐观锁。换句话说,当这个属性变脏时,是否增加版本号(Version)
+                            </para>
+                    </callout>
+                    <callout arearefs="component8">
+                            <para>
+                                <literal>unique</literal> (可选 - 默认是 <literal>false</literal>):表明组件映射的所有字段上都有唯一性约束
+                            </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+             <para>
+                其<literal>&lt;property&gt;</literal>子标签为子类的一些属性与表字段之间建立映射。 
+            </para>
+
+            <para>
+                <literal>&lt;component&gt;</literal>元素允许加入一个<literal>&lt;parent&gt;</literal>子元素,在组件类内部就可以有一个指向其容器的实体的反向引用。
+            </para>
+
+             <para>
+                <literal>&lt;dynamic-component&gt;</literal>元素允许把一个<literal>Map</literal>映射为组件,其属性名对应map的键值。
+                参见<xref linkend="components-dynamic"/>.
+            </para>
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-properties" revision="2">
+            <title>properties</title>
+
+            <para>
+                <literal>&lt;properties&gt;</literal> 元素允许定义一个命名的逻辑分组(grouping)包含一个类中的多个属性。
+                这个元素最重要的用处是允许多个属性的组合作为<literal>property-ref</literal>的目标(target)。
+                这也是定义多字段唯一约束的一种方便途径。
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="properties1" coords="2 45"/>
+                    <area id="properties2" coords="3 45"/>
+                    <area id="properties3" coords="4 45"/>
+                    <area id="properties4" coords="5 45"/>
+                    <area id="properties5" coords="6 45"/>
+                </areaspec>            
+                <programlisting><![CDATA[<properties 
+        name="logicalName" 
+        insert="true|false"
+        update="true|false"
+        optimistic-lock="true|false"
+        unique="true|false"
+>
+        
+        <property ...../>
+        <many-to-one .... />
+        ........
+</properties>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="properties1">
+                        <para>
+                            <literal>name</literal>: 分组的逻辑名称 - 
+                            <emphasis>不是</emphasis> 实际属性的名称.
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="properties2">
+                        <para>
+                            <literal>insert</literal>: 被映射的字段是否出现在SQL的
+                            <literal>INSERT</literal>语句中?
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="properties3">
+                        <para>
+                            <literal>update</literal>:  被映射的字段是否出现在SQL的
+                            <literal>UPDATE</literal>语句中?
+                        </para>               
+                    </callout>                   
+                    <callout arearefs="properties4">
+                            <para>
+                                <literal>optimistic-lock</literal> (可选 - 默认是 <literal>true</literal>):表明更新此组件是否需要获取乐观锁。换句话说,当这个属性变脏时,是否增加版本号(Version)
+                            </para>
+                    </callout>
+                    <callout arearefs="properties5">
+                            <para>
+                                <literal>unique</literal> (可选 - 默认是 <literal>false</literal>):表明组件映射的所有字段上都有唯一性约束
+                            </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+                例如,如果我们有如下的<literal>&lt;properties&gt;</literal>映射:
+            </para>
+            
+            <programlisting><![CDATA[<class name="Person">
+    <id name="personNumber"/>
+    ...
+    <properties name="name" 
+            unique="true" update="false">
+        <property name="firstName"/>
+        <property name="initial"/>
+        <property name="lastName"/>
+    </properties>
+</class>]]></programlisting>
+
+            <para>
+                然后,我们可能有一些遗留的数据关联,引用 <literal>Person</literal>表的这个唯一键,而不是主键。
+            </para>
+            <programlisting><![CDATA[<many-to-one name="person" 
+         class="Person" property-ref="name">
+    <column name="firstName"/>
+    <column name="initial"/>
+    <column name="lastName"/>
+</many-to-one>]]></programlisting>
+            
+            <para>
+                我们并不推荐这样使用,除非在映射遗留数据的情况下。
+            </para>
+            
+        </sect2>
+
+        <sect2 id="mapping-declaration-subclass" revision="4">
+            <title>子类(subclass)</title>
+
+             <para>
+                最后,多态持久化需要为父类的每个子类都进行定义。对于“每一棵类继承树对应一个表”的策略来说,就需要使用<literal>&lt;subclass&gt;</literal>定义。
+            </para>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="subclass1" coords="2 55"/>
+                    <area id="subclass2" coords="3 55"/>
+                    <area id="subclass3" coords="4 55"/>
+                    <area id="subclass4" coords="5 55"/>
+                </areaspec>
+                <programlisting><![CDATA[<subclass
+        name="ClassName"
+        discriminator-value="discriminator_value"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        entity-name="EntityName"
+        node="element-name"
+        extends="SuperclassName">
+
+        <property .... />
+        .....
+</subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="subclass1">
+                        <para>
+                            <literal>name</literal>: 子类的全限定名。
+                        </para>
+                    </callout>                   
+                    <callout arearefs="subclass2">
+                        <para>
+                            <literal>discriminator-value(辨别标志)</literal> (可选 - 默认为类名):一个用于区分每个独立的子类的值。
+                        </para>
+                    </callout>
+                    <callout arearefs="subclass3">
+                         <para>
+                            <literal>proxy(代理)</literal> (可选): 指定一个类或者接口,在延迟装载时作为代理使用。
+                        </para>
+                    </callout>
+                    <callout arearefs="subclass4">
+                        <para>
+                            <literal>lazy</literal> (可选, 默认是<literal>true</literal>): 设置为
+                            <literal>lazy="false"</literal> 禁止使用延迟抓取
+                        </para>
+                    </callout>    
+                </calloutlist>
+            </programlistingco>
+
+             <para>
+                每个子类都应该定义它自己的持久化属性和子类。
+                <literal>&lt;version&gt;</literal> 和<literal>&lt;id&gt;</literal> 属性可以从根父类继承下来。在一棵继承树上的每个子类都必须定义一个唯一的<literal>discriminator-value</literal>。如果没有指定,就会使用Java类的全限定名。
+            </para>
+            
+
+            <para>
+                更多关于继承映射的信息, 参考 <xref linkend="inheritance"/>章节.
+            </para>
+        </sect2>
+
+         <sect2 id="mapping-declaration-joinedsubclass" revision="3">
+            <title>连接的子类(joined-subclass)</title>
+
+            <para>
+                此外,每个子类可能被映射到他自己的表中(每个子类一个表的策略)。被继承的状态通过和超类的表关联得到。我们使用<literal>&lt;joined-subclass&gt;</literal>元素。
+            </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="joinedsubclass1" coords="2 45"/>
+                    <area id="joinedsubclass2" coords="3 45"/>
+                    <area id="joinedsubclass3" coords="4 45"/>
+                    <area id="joinedsubclass4" coords="5 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<joined-subclass
+        name="ClassName"
+        table="tablename"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        schema="schema"
+        catalog="catalog"
+        extends="SuperclassName"
+        persister="ClassName"
+        subselect="SQL expression"
+        entity-name="EntityName"
+        node="element-name">
+
+        <key .... >
+
+        <property .... />
+        .....
+</joined-subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="joinedsubclass1">
+                        <para>
+                            <literal>name</literal>: 子类的全限定名。
+                        </para>
+                    </callout>                   
+                    <callout arearefs="joinedsubclass2">
+                        <para>
+                            <literal>table</literal>: 子类的表名.
+                        </para>
+                    </callout>                   
+                    <callout arearefs="joinedsubclass3">
+                         <para>
+                            <literal>proxy</literal> (可选): 指定一个类或者接口,在延迟装载时作为代理使用。
+                        </para>
+                    </callout>
+                    <callout arearefs="joinedsubclass4">
+                        <para>
+                             <literal>lazy</literal> (可选, 默认是 <literal>true</literal>): 设置为 
+                            <literal>lazy="false"</literal> 禁止使用延迟装载。
+                         </para>
+                    </callout>    
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                这种映射策略不需要指定辨别标志(discriminator)字段。但是,每一个子类都必须使用<literal>&lt;key&gt;</literal>元素指定一个表字段来持有对象的标识符。本章开始的映射可以被用如下方式重写:
+            </para>
+            
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+        <class name="Cat" table="CATS">
+                <id name="id" column="uid" type="long">
+                        <generator class="hilo"/>
+                </id>
+                <property name="birthdate" type="date"/>
+                <property name="color" not-null="true"/>
+                <property name="sex" not-null="true"/>
+                <property name="weight"/>
+                <many-to-one name="mate"/>
+                <set name="kittens">
+                        <key column="MOTHER"/>
+                        <one-to-many class="Cat"/>
+                </set>
+                <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
+                    <key column="CAT"/>
+                    <property name="name" type="string"/>
+                </joined-subclass>
+        </class>
+
+        <class name="eg.Dog">
+                <!-- mapping for Dog could go here -->
+        </class>
+
+</hibernate-mapping>]]></programlisting>
+
+             <para>
+                 更多关于继承映射的信息,参考<xref linkend="inheritance"/>。
+             </para>
+        </sect2>
+
+        <sect2 id="mapping-declaration-unionsubclass" revision="2">
+           <title>联合子类(union-subclass)</title>
+
+           <para>
+		       第三种选择是仅仅映射类继承树中具体类部分到表中(每个具体类一张表的策略)。其中,每张表定义了类的所有持久化状态,包括继承的状态。在 Hibernate 中,并不需要完全显式地映射这样的继承树。你可以简单地使用单独的<literal>&lt;class&gt;</literal>定义映射每个类。然而,如果你想使用多态关联(例如,一个对类继承树中超类的关联),你需要使用<literal>&lt;union-subclass&gt;</literal>映射。
+           </para>
+            <programlistingco>
+                <areaspec>
+                    <area id="unionsubclass1" coords="2 45"/>
+                    <area id="unionsubclass2" coords="3 45"/>
+                    <area id="unionsubclass3" coords="4 45"/>
+                    <area id="unionsubclass4" coords="5 45"/>
+                </areaspec>
+                <programlisting><![CDATA[<union-subclass
+        name="ClassName"
+        table="tablename"
+        proxy="ProxyInterface"
+        lazy="true|false"
+        dynamic-update="true|false"
+        dynamic-insert="true|false"
+        schema="schema"
+        catalog="catalog"
+        extends="SuperclassName"
+        abstract="true|false"
+        persister="ClassName"
+        subselect="SQL expression"
+        entity-name="EntityName"
+        node="element-name">
+
+        <property .... />
+        .....
+</union-subclass>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="unionsubclass1">
+                        <para>
+                            <literal>name</literal>: 子类的全限定名。
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="unionsubclass2">
+                        <para>
+                            <literal>table</literal>: 子类的表名
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="unionsubclass3">
+                        <para>
+                            <literal>proxy</literal> (可选): 指定一个类或者接口,在延迟装载时作为代理使用。
+                        </para>              
+                    </callout>
+                    <callout arearefs="unionsubclass4">
+                        <para>
+                             <literal>lazy</literal> (可选, 默认是 <literal>true</literal>): 设置为 
+                            <literal>lazy="false"</literal> 禁止使用延迟装载。
+                         </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                这种映射策略不需要指定辨别标志(discriminator)字段。
+            </para>
+            <para>
+                 更多关于继承映射的信息,参考<xref linkend="inheritance"/>。
+            </para>
+        </sect2>
+
+   	<sect2 id="mapping-declaration-join" revision="3">
+            <title>连接(join)</title>
+
+            <para>
+               使用 <literal>&lt;join&gt;</literal> 元素,假若在表之间存在一对一关联,可以将一个类的属性映射到多张表中。
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="join1" coords="2 50"/>
+                    <area id="join2" coords="3 50"/>
+                    <area id="join3" coords="4 50"/>
+                    <area id="join4" coords="5 50"/>
+                    <area id="join5" coords="6 50"/>
+                    <area id="join6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<join
+        table="tablename"
+        schema="owner"
+        catalog="catalog"
+        fetch="join|select"
+        inverse="true|false"
+        optional="true|false">
+        
+        <key ... />
+        
+        <property ... />
+        ...
+</join>]]></programlisting>
+
+                <calloutlist>
+                    <callout arearefs="join1">
+                        <para>
+                            <literal>table</literal>: 被连接表的名称。
+                        </para>
+                    </callout>
+                    <callout arearefs="join2">
+                        <para>
+                            <literal>schema</literal> (可选):覆盖由根<literal>&lt;hibernate-mapping&gt;</literal>元素指定的模式名称。
+                        </para>
+                    </callout>
+                    <callout arearefs="join3">
+                        <para>
+                            <literal>catalog</literal> (可选): 覆盖由根 <literal>&lt;hibernate-mapping&gt;</literal>元素指定的目录名称。
+                        </para>
+                    </callout>
+                    <callout arearefs="join4">
+                        <para>
+                            <literal>fetch</literal> (可选 - 默认是 <literal>join</literal>):
+                            如果设置为默认值<literal>join</literal>, Hibernate 将使用一个内连接来得到这个类或其超类定义的<literal>&lt;join&gt;</literal>,而使用一个外连接来得到其子类定义的<literal>&lt;join&gt;</literal>。如果设置为<literal>select</literal>,则 Hibernate 将为子类定义的 <literal>&lt;join&gt;</literal>使用顺序选择。这仅在一行数据表示一个子类的对象的时候才会发生。对这个类和其超类定义的<literal>&lt;join&gt;</literal>,依然会使用内连接得到。
+                        </para>
+                    </callout>
+                    <callout arearefs="join5">
+                        <para>
+                            <literal>inverse</literal> (可选 - 默认是 <literal>false</literal>):
+                            如果打开,Hibernate 不会插入或者更新此连接定义的属性。
+                        </para>
+                    </callout>
+                    <callout arearefs="join6">
+                        <para>
+                            <literal>optional</literal> (可选 - 默认是 <literal>false</literal>):
+                            如果打开,Hibernate 只会在此连接定义的属性非空时插入一行数据,并且总是使用一个外连接来得到这些属性。
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                例如,一个人(person)的地址(address)信息可以被映射到单独的表中(并保留所有属性的值类型语义):
+            </para>
+
+            <programlisting><![CDATA[<class name="Person"
+    table="PERSON">
+
+    <id name="id" column="PERSON_ID">...</id>
+
+    <join table="ADDRESS">
+        <key column="ADDRESS_ID"/>
+        <property name="address"/>
+        <property name="zip"/>
+        <property name="country"/>
+    </join>
+    ...]]></programlisting>
+
+            <para>
+                此特性常常对遗留数据模型有用,我们推荐表个数比类个数少,以及细粒度的领域模型。然而,在单独的继承树上切换继承映射策略是有用的,后面会解释这点。
+            </para>
+        </sect2>
+
+        <sect2 id="mapping-declaration-key">
+            <title>é”®(key)</title>
+
+            <para>
+               我们目前已经见到过<literal>&lt;key&gt;</literal>元素多次了。 这个元素在父映射元素定义了对新表的连接,并且在被连接表中定义了一个外键引用原表的主键的情况下经常使用。
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="key1" coords="2 50"/>
+                    <area id="key2" coords="3 50"/>
+                    <area id="key3" coords="4 50"/>
+                    <area id="key4" coords="5 50"/>
+                    <area id="key5" coords="6 50"/>
+                    <area id="key6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<key
+        column="columnname"
+        on-delete="noaction|cascade"
+        property-ref="propertyName"
+        not-null="true|false"
+        update="true|false"
+        unique="true|false"
+/>]]></programlisting>
+
+                <calloutlist>
+                    <callout arearefs="key1">
+                        <para>
+                            <literal>column</literal> (可选): 外键字段的名称。也可以通过嵌套的 <literal>&lt;column&gt;</literal>指定。
+                        </para>
+                    </callout>
+                    <callout arearefs="key2">
+                        <para>
+                            <literal>on-delete</literal> (可选, 默认是 <literal>noaction</literal>): 
+                            表明外键关联是否打开数据库级别的级联删除。
+                        </para>
+                    </callout>
+                    <callout arearefs="key3">
+                        <para>
+                            <literal>property-ref</literal> (可选): 表明外键引用的字段不是原表的主键(提供给遗留数据)。
+                        </para>
+                    </callout>
+                    <callout arearefs="key4">
+                        <para>
+                            <literal>not-null</literal> (可选): 表明外键的字段不可为空(这意味着无论何时外键都是主键的一部分)。
+                        </para>
+                    </callout>
+                    <callout arearefs="key5">
+                        <para>
+                            <literal>update</literal> (可选): 表明外键决不应该被更新(这意味着无论何时外键都是主键的一部分)。
+                        </para>
+                    </callout>
+                    <callout arearefs="key6">
+                        <para>
+                            <literal>unique</literal> (可选): 表明外键应有唯一性约束 (这意味着无论何时外键都是主键的一部分)。
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                对那些看重删除性能的系统,我们推荐所有的键都应该定义为<literal>on-delete="cascade"</literal>,这样 Hibernate 将使用数据库级的<literal>ON CASCADE DELETE</literal>约束,而不是多个<literal>DELETE</literal>语句。 注意,这个特性会绕过 Hibernate 通常对版本数据(versioned data)采用的乐观锁策略。
+            </para>
+            <para>
+                <literal>not-null</literal> 和 <literal>update</literal> 属性在映射单向一对多关联的时候有用。如果你映射一个单向一对多关联到非空的(non-nullable)外键,你<emphasis>必须</emphasis> 用<literal>&lt;key not-null="true"&gt;</literal>定义此键字段。
+            </para>
+        </sect2>
+
+        <sect2 id="mapping-column" revision="4">
+           <title>字段和规则元素(column and formula elements)</title>
+           <para>
+               任何接受<literal>column</literal>属性的映射元素都可以选择接受<literal>&lt;column&gt;</literal> 子元素。同样的,<literal>formula</literal>子元素也可以替换<literal>&lt;formula&gt;</literal>属性。
+           </para>
+           <programlisting><![CDATA[<column
+        name="column_name"
+        length="N"
+        precision="N"
+        scale="N"
+        not-null="true|false"
+        unique="true|false"
+        unique-key="multicolumn_unique_key_name"
+        index="index_name"
+        sql-type="sql_type_name"
+        check="SQL expression"
+        default="SQL expression"/>]]></programlisting>
+
+            <programlisting><![CDATA[<formula>SQL expression</formula>]]></programlisting>
+            <para>
+                <literal>column</literal> 和 <literal>formula</literal> 属性甚至可以在同一个属性或关联映射中被合并来表达,例如,一些奇异的连接条件。
+            </para>
+            <programlisting><![CDATA[<many-to-one name="homeAddress" class="Address"
+        insert="false" update="false">
+    <column name="person_id" not-null="true" length="10"/>
+    <formula>'MAILING'</formula>
+</many-to-one>]]></programlisting>
+
+    </sect2>  
+   	
+        <sect2 id="mapping-declaration-import">
+            <title>引用(import)</title>
+
+            <para>
+                假设你的应用程序有两个同样名字的持久化类,但是你不想在Hibernate查询中使用他们的全限定名。除了依赖<literal>auto-import="true"</literal>以外,类也可以被显式地“import(引用)”。你甚至可以引用没有被明确映射的类和接口。
+            </para>
+            
+            <programlisting><![CDATA[<import class="java.lang.Object" rename="Universe"/>]]></programlisting>
+            
+            <programlistingco>
+                <areaspec>
+                    <area id="import1" coords="2 40"/>
+                    <area id="import2" coords="3 40"/>
+                </areaspec>
+                <programlisting><![CDATA[<import
+        class="ClassName"
+        rename="ShortName"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="import1">
+                        <para>
+                            <literal>class</literal>: 任何Java类的全限定名。
+                        </para>
+                    </callout>                   
+                    <callout arearefs="import2">
+                        <para>
+                            <literal>rename</literal> (可选 - 默认为类的全限定名):
+                            在查询语句中可以使用的名字。
+                        </para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+            
+        </sect2>
+
+        <sect2 id="mapping-types-anymapping" revision="2">
+            <title>any</title>
+            <para>
+                这是属性映射的又一种类型。<literal>&lt;any&gt;</literal> 映射元素定义了一种从多个表到类的多态关联。这种类型的映射常常需要多于一个字段。第一个字段持有被关联实体的类型,其他的字段持有标识符。对这种类型的关联来说,不可能指定一个外键约束,所以这当然不是映射(多态)关联的通常的方式。你只应该在非常特殊的情况下使用它(比如,审计log,用户会话数据等等)。
+            </para>
+            <para>
+                 <literal>meta-type</literal> 属性使得应用程序能指定一个将数据库字段的值映射到持久化类的自定义类型。这个持久化类包含有用<literal>id-type</literal>指定的标识符属性。
+				 你必须指定从meta-type的值到类名的映射。
+            </para>
+
+            <programlisting><![CDATA[<any name="being" id-type="long" meta-type="string">
+    <meta-value value="TBL_ANIMAL" class="Animal"/>
+    <meta-value value="TBL_HUMAN" class="Human"/>
+    <meta-value value="TBL_ALIEN" class="Alien"/>
+    <column name="table_name"/>
+    <column name="id"/>
+</any>]]></programlisting>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="any1" coords="2 50"/>
+                    <area id="any2" coords="3 50"/>
+                    <area id="any3" coords="4 50"/>
+                    <area id="any4" coords="5 50"/>
+                    <area id="any5" coords="6 50"/>
+                    <area id="any6" coords="7 50"/>
+                </areaspec>
+                <programlisting><![CDATA[<any
+        name="propertyName"
+        id-type="idtypename"
+        meta-type="metatypename"
+        cascade="cascade_style"
+        access="field|property|ClassName"
+        optimistic-lock="true|false"
+>
+        <meta-value ... />
+        <meta-value ... />
+        .....
+        <column .... />
+        <column .... />
+        .....
+</any>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="any1">
+                        <para>
+                            <literal>name</literal>: 属性名
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any2">
+                        <para>
+                            <literal>id-type</literal>: 标识符类型
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any3">
+                        <para>
+                            <literal>meta-type</literal> (可选 -默认是 <literal>string</literal>): 
+                            允许辨别标志(discriminator)映射的任何类型
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any4">
+                        <para>
+                            <literal>cascade</literal> (可选 -默认是<literal>none</literal>): 
+                            级联的类型
+                        </para>            
+                    </callout>                   
+                    <callout arearefs="any5">
+                        <para>
+                            <literal>access</literal> (可选 -默认是 <literal>property</literal>): Hibernate 用来访问属性值的策略。
+                        </para>
+                    </callout>
+                    <callout arearefs="any6">
+                        <para>
+                            <literal>optimistic-lock</literal> (可选 -默认是 <literal>true</literal>): 表明更新此组件是否需要获取乐观锁。换句话说,当这个属性变脏时,是否增加版本号(Version)
+							</para>
+                    </callout>
+                </calloutlist>
+            </programlistingco>
+
+      </sect2>
+
+    </sect1>
+
+    <sect1 id="mapping-types">
+        <title>Hibernate 的类型</title>
+        <sect2 id="mapping-types-entitiesvalues" revision="1">
+            <title>实体(Entities)和值(values)</title>
+
+            <para>
+                为了理解很多与持久化服务相关的Java语言级对象的行为,我们需要把它们分为两类:
+            </para>
+
+            <para>
+                <emphasis>实体entity</emphasis> 独立于任何持有实体引用的对象。与通常的Java模型相比,不再被引用的对象会被当作垃圾收集掉。实体必须被显式的保存和删除(除非保存和删除是从父实体向子实体引发的<emphasis>级联</emphasis>)。这和ODMG模型中关于对象通过可触及保持持久性有一些不同——比较起来更加接近应用程序对象通常在一个大系统中的使用方法。实体支持循环引用和交叉引用,它们也可以加上版本信息。
+            </para>
+
+            <para>
+               一个实体的持久状态包含指向其他实体和<emphasis>值</emphasis>类型实例的引用。值可以是原始类型,集合(不是集合中的对象),组件或者特定的不可变对象。与实体不同,值(特别是集合和组件)是通过可触及性来进行持久化和删除的。因为值对象(和原始类型数据)是随着包含他们的实体而被持久化和删除的,他们不能被独立的加上版本信息。值没有独立的标识,所以他们不能被两个实体或者集合共享。
+            </para>
+
+            <para>
+			    直到现在,我们都一直使用术语“持久类”(persistent class)来代表实体。我们仍然会这么做。	然而严格说来,不是所有的用户自定义的,带有持久化状态的类都是实体。<emphasis>组件</emphasis>就是用户自定义类,却是值语义的。<literal>java.lang.String</literal>类型的java属性也是值语义的。给了这个定义以后,我们可以说所有JDK提供的类型(类)都是值类型的语义,而用于自定义类型可能被映射为实体类型或值类型语义。采用哪种类型的语义取决于开发人员。在领域模型中,寻找实体类的一个好线索是共享引用指向这个类的单一实例,而组合或聚合通常被转化为值类型。
+            </para>
+
+            <para>
+                我们会在本文档中重复碰到这两个概念。
+            </para>
+
+            <para>
+                挑战在于将java类型系统(和开发者定义的实体和值类型)映射到 SQL/数据库类型系统。Hibernate提供了连接两个系统之间的桥梁:对于实体类型,我们使用<literal>&lt;class&gt;</literal>, <literal>&lt;subclass&gt;</literal>  等等。对于值类型,我们使用 <literal>&lt;property&gt;</literal>, <literal>&lt;component&gt;</literal> 及其他,通常跟随着<literal>type</literal>属性。这个属性的值是Hibernate 的<emphasis>映射类型</emphasis>的名字。Hibernate提供了许多现成的映射(标准的JDK值类型)。你也可以编写自己的映射类型并实现自定义的变换策略,随后我们会看到这点。
+            </para>
+            <para>
+                所有的Hibernate内建类型,除了collections以外,都支持空(null)语义。
+            </para>
+        </sect2>
+
+        <sect2 id="mapping-types-basictypes" revision="3">
+            <title>基本值类型</title>
+
+            <para>
+                内建的 <emphasis>基本映射类型</emphasis>可以大致分为
+                <variablelist>
+                    <varlistentry>
+                        <term><literal>integer, long, short, float, double, character, byte,
+                            boolean, yes_no, true_false</literal></term>
+                        <listitem>
+                            <para>
+                                这些类型都对应Java的原始类型或者其封装类,来符合(特定厂商的)SQL 字段类型。<literal>boolean, yes_no</literal> 和 <literal>true_false</literal>都是Java 中<literal>boolean</literal> 或者<literal>java.lang.Boolean</literal>的另外说法。
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>string</literal></term>
+                        <listitem>
+                            <para>
+                                从<literal>java.lang.String</literal> 到
+                                <literal>VARCHAR</literal> (或者 Oracle的 <literal>VARCHAR2</literal>)的映射。
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>date, time, timestamp</literal></term>
+                        <listitem>
+                            <para>
+                                从<literal>java.util.Date</literal>和其子类到SQL类型<literal>DATE</literal>, <literal>TIME</literal> 和<literal>TIMESTAMP</literal> (或等价类型)的映射。
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>calendar, calendar_date</literal></term>
+                        <listitem>
+                            <para>
+                                从<literal>java.util.Calendar</literal> 到SQL 类型<literal>TIMESTAMP</literal>和 <literal>DATE</literal>(或等价类型)的映射。
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>big_decimal, big_integer</literal></term>
+                        <listitem>
+                             <para>
+                                从<literal>java.math.BigDecimal</literal>和<literal>java.math.BigInteger</literal>到<literal>NUMERIC</literal> (或者 Oracle 的<literal>NUMBER</literal>类型)的映射。
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>locale, timezone, currency</literal></term>
+                        <listitem>
+                            <para>
+                                从<literal>java.util.Locale</literal>,                                <literal>java.util.TimeZone</literal> 和<literal>java.util.Currency</literal> 到<literal>VARCHAR</literal> (或者 Oracle 的<literal>VARCHAR2</literal>类型)的映射.
+                                <literal>Locale</literal>和 <literal>Currency</literal> 的实例被映射为它们的ISO代码。<literal>TimeZone</literal>的实例被影射为它的<literal>ID</literal>。
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>class</literal></term>
+                        <listitem>
+                            <para>
+                                从<literal>java.lang.Class</literal> 到
+                                <literal>VARCHAR</literal> (或者 Oracle 的<literal>VARCHAR2</literal>类型)的映射。<literal>Class</literal>被映射为它的全限定名。
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>binary</literal></term>
+                        <listitem>
+                            <para>
+                                把字节数组(byte arrays)映射为对应的 SQL二进制类型。
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>text</literal></term>
+                        <listitem>
+                            <para>
+                                把长Java字符串映射为SQL的<literal>CLOB</literal>或者<literal>TEXT</literal>类型。
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>serializable</literal></term>
+                        <listitem>
+                            <para>
+                                把可序列化的Java类型映射到对应的SQL二进制类型。你也可以为一个并非默认为基本类型的可序列化Java类或者接口指定Hibernate类型<literal>serializable</literal>。
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term><literal>clob, blob</literal></term>
+                        <listitem>
+                             <para>
+                                JDBC 类 <literal>java.sql.Clob</literal> 和 <literal>java.sql.Blob</literal>的映射。某些程序可能不适合使用这个类型,因为blob和clob对象可能在一个事务之外是无法重用的。(而且, 驱动程序对这种类型的支持充满着补丁和前后矛盾。)
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>
+                            <literal>imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date,
+                            imm_serializable, imm_binary</literal>
+                        </term>
+                        <listitem>
+                            <para>
+                                一般来说,映射类型被假定为是可变的Java类型,只有对不可变Java类型,Hibernate会采取特定的优化措施,应用程序会把这些对象作为不可变对象处理。比如,你不应该对作为<literal>imm_timestamp</literal>映射的Date执行<literal>Date.setTime()</literal>。要改变属性的值,并且保存这一改变,应用程序必须对这一属性重新设置一个新的(不一样的)对象。
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    
+                </variablelist>
+            
+            </para>
+
+            <para>
+                实体及其集合的唯一标识可以是除了<literal>binary</literal>、 <literal>blob</literal> 和 <literal>clob</literal>之外的任何基础类型。(联合标识也是允许的,后面会说到。)
+            </para>
+            
+            <para>
+                在<literal>org.hibernate.Hibernate</literal>中,定义了基础类型对应的<literal>Type</literal>常量。比如,<literal>Hibernate.STRING</literal>代表<literal>string</literal> 类型。
+            </para>
+
+        </sect2>
+
+        <sect2 id="mapping-types-custom" revision="2">
+            <title>自定义值类型</title>
+
+            <para>
+                开发者创建属于他们自己的值类型也是很容易的。比如说,你可能希望持久化<literal>java.lang.BigInteger</literal>类型的属性,持久化成为<literal>VARCHAR</literal>字段。Hibernate没有内置这样一种类型。自定义类型能够映射一个属性(或集合元素)到不止一个数据库表字段。比如说,你可能有这样的Java属性:<literal>getName()</literal>/<literal>setName()</literal>,这是<literal>java.lang.String</literal>类型的,对应的持久化到三个字段:<literal>FIRST_NAME</literal>, <literal>INITIAL</literal>, <literal>SURNAME</literal>。
+            </para>
+
+            <para>
+                要实现一个自定义类型,可以实现<literal>org.hibernate.UserType</literal>或<literal>org.hibernate.CompositeUserType</literal>中的任一个,并且使用类型的Java全限定类名来定义属性。请查看<literal>org.hibernate.test.DoubleStringType</literal>这个例子,看看它是怎么做的。
+            </para>
+
+            <programlisting><![CDATA[<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
+    <column name="first_string"/>
+    <column name="second_string"/>
+</property>]]></programlisting>
+
+            <para>
+                注意使用<literal>&lt;column&gt;</literal>标签来把一个属性映射到多个字段的做法。
+            </para>
+            
+            <para>
+                <literal>CompositeUserType</literal>, <literal>EnhancedUserType</literal>,
+                <literal>UserCollectionType</literal>, 和 <literal>UserVersionType</literal> 接口为更特殊的使用方式提供支持。
+            </para>
+            <para>
+                你甚至可以在一个映射文件中提供参数给一个<literal>UserType</literal>。 为了这样做,你的<literal>UserType</literal>必须实现<literal>org.hibernate.usertype.ParameterizedType</literal>接口。为了给自定义类型提供参数,你可以在映射文件中使用<literal>&lt;type&gt;</literal>元素。
+            </para>
+            <programlisting><![CDATA[<property name="priority">
+    <type name="com.mycompany.usertypes.DefaultValueIntegerType">
+        <param name="default">0</param>
+    </type>
+</property>]]></programlisting>
+
+            <para>
+                现在,<literal>UserType</literal> 可以从传入的<literal>Properties</literal>对象中得到<literal>default</literal> 参数的值。
+            </para>
+            <para>
+                如果你非常频繁地使用某一<literal>UserType</literal>,可以为他定义一个简称。这可以通过使用 <literal>&lt;typedef&gt;</literal>元素来实现。Typedefs为一自定义类型赋予一个名称,并且如果此类型是参数化的,还可以包含一系列默认的参数值。
+            </para>
+            <programlisting><![CDATA[<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
+    <param name="default">0</param>
+</typedef>]]></programlisting>
+
+            <programlisting><![CDATA[<property name="priority" type="default_zero"/>]]></programlisting>
+
+            <para>
+                也可以根据具体案例通过属性映射中的类型参数覆盖在typedef中提供的参数。
+            </para>
+            <para>
+			    尽管 Hibernate 内建的丰富的类型和对组件的支持意味着你可能很少 <emphasis>需要</emphasis>使用自定义类型。不过,为那些在你的应用中经常出现的(非实体)类使用自定义类型也是一个好方法。例如,一个<literal>MonetaryAmount</literal>类使用<literal>CompositeUserType</literal>来映射是不错的选择,虽然他可以很容易地被映射成组件。这样做的动机之一是抽象。使用自定义类型,以后假若你改变表示金额的方法时,它可以保证映射文件不需要修改。
+            </para>
+        </sect2>
+        
+    </sect1>
+
+    <sect1 id="mapping-entityname">
+        <title>多次映射同一个类</title>
+        <para>
+            对特定的持久化类,映射多次是允许的。这种情形下,你必须指定<emphasis>entity name</emphasis>来区别不同映射实体的对象实例。(默认情况下,实体名字和类名是相同的。)
+            Hibernate在操作持久化对象、编写查询条件,或者把关联映射到指定实体时,允许你指定这个entity name(实体名字)。
+        </para>
+        
+        <programlisting><![CDATA[<class name="Contract" table="Contracts" 
+        entity-name="CurrentContract">
+    ...
+    <set name="history" inverse="true" 
+            order-by="effectiveEndDate desc">
+        <key column="currentContractId"/>
+        <one-to-many entity-name="HistoricalContract"/>
+    </set>
+</class>
+
+<class name="Contract" table="ContractHistory" 
+        entity-name="HistoricalContract">
+    ...
+    <many-to-one name="currentContract" 
+            column="currentContractId" 
+            entity-name="CurrentContract"/>
+</class>]]></programlisting>
+
+        <para>
+            注意这里关联是如何用<literal>entity-name</literal>来代替<literal>class</literal>的。
+        </para>
+
+    </sect1>
+
+    <sect1 id="mapping-quotedidentifiers">
+            <title>SQL中引号包围的标识符</title>
+            <para>
+                你可通过在映射文档中使用反向引号(`)把表名或者字段名包围起来,以强制Hibernate在生成的SQL中把标识符用引号包围起来。Hibernate会使用相应的SQL<literal>Dialect</literal>(方言)来使用正确的引号风格(通常是双引号,但是在SQL Server中是括号,MySQL中是反向引号)。
+            </para>
+
+            <programlisting><![CDATA[<class name="LineItem" table="`Line Item`">
+    <id name="id" column="`Item Id`"/><generator class="assigned"/></id>
+    <property name="itemNumber" column="`Item #`"/>
+    ...
+</class>]]></programlisting>
+
+    </sect1>
+
+  	
+   	<sect1 id="mapping-alternatives">
+   	<title>其他元数据(Metadata)</title>
+
+    <para>
+   	    XML 并不适用于所有人,  因此有其他定义Hibernate O/R 映射元数据(metadata)的方法。
+   	</para>
+
+    <sect2 id="mapping-xdoclet">
+        <title>使用 XDoclet 标记</title>
+      
+        <para>
+            很多Hibernate使用者更喜欢使用XDoclet<literal>@hibernate.tags</literal>将映射信息直接嵌入到源代码中。我们不会在本文档中涉及这个方法,因为严格说来,这属于XDoclet的一部分。然而,我们包含了如下使用XDoclet映射的<literal>Cat</literal>类的例子。
+        </para>
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+/**
+ * @hibernate.class
+ *  table="CATS"
+ */
+public class Cat {
+    private Long id; // identifier
+    private Date birthdate;
+    private Cat mother;
+    private Set kittens
+    private Color color;
+    private char sex;
+    private float weight;
+
+    /*
+     * @hibernate.id
+     *  generator-class="native"
+     *  column="CAT_ID"
+     */
+    public Long getId() {
+        return id;
+    }
+    private void setId(Long id) {
+        this.id=id;
+    }
+
+    /**
+     * @hibernate.many-to-one
+     *  column="PARENT_ID"
+     */
+    public Cat getMother() {
+        return mother;
+    }
+    void setMother(Cat mother) {
+        this.mother = mother;
+    }
+
+    /**
+     * @hibernate.property
+     *  column="BIRTH_DATE"
+     */
+    public Date getBirthdate() {
+        return birthdate;
+    }
+    void setBirthdate(Date date) {
+        birthdate = date;
+    }
+    /**
+     * @hibernate.property
+     *  column="WEIGHT"
+     */
+    public float getWeight() {
+        return weight;
+    }
+    void setWeight(float weight) {
+        this.weight = weight;
+    }
+
+    /**
+     * @hibernate.property
+     *  column="COLOR"
+     *  not-null="true"
+     */
+    public Color getColor() {
+        return color;
+    }
+    void setColor(Color color) {
+        this.color = color;
+    }
+    /**
+     * @hibernate.set
+     *  inverse="true"
+     *  order-by="BIRTH_DATE"
+     * @hibernate.collection-key
+     *  column="PARENT_ID"
+     * @hibernate.collection-one-to-many
+     */
+    public Set getKittens() {
+        return kittens;
+    }
+    void setKittens(Set kittens) {
+        this.kittens = kittens;
+    }
+    // addKitten not needed by Hibernate
+    public void addKitten(Cat kitten) {
+        kittens.add(kitten);
+    }
+
+    /**
+     * @hibernate.property
+     *  column="SEX"
+     *  not-null="true"
+     *  update="false"
+     */
+    public char getSex() {
+        return sex;
+    }
+    void setSex(char sex) {
+        this.sex=sex;
+    }
+}]]></programlisting>
+
+        <para>
+            参考Hibernate网站更多的Xdoclet和Hibernate的例子
+        </para>
+    </sect2>
+
+    <sect2 id="mapping-annotations" revision="2">
+        <title>使用 JDK 5.0 的注解(Annotation)</title>
+
+        <para>
+            JDK 5.0 在语言级别引入了 XDoclet 风格的标注,并且是类型安全的,在编译期进行检查。这一机制比XDoclet的注解更为强大,有更好的工具和IDE支持。例如, IntelliJ IDEA,支持JDK 5.0注解的自动完成和语法高亮 。EJB规范的新修订版(JSR-220)使用 JDK 5.0的注解作为entity beans的主要元数据(metadata)机制。Hibernate 3 实现了JSR-220 (the persistence API)的<literal>EntityManager</literal>,支持通过<emphasis>Hibernate Annotations</emphasis>包定义映射元数据。这个包作为单独的部分下载,支持EJB3 (JSR-220)和Hibernate3的元数据。
+        </para>
+        <para>
+            这是一个被注解为EJB entity bean 的POJO类的例子
+        </para>
+        <programlisting><![CDATA[@Entity(access = AccessType.FIELD)
+public class Customer implements Serializable {
+
+    @Id;
+    Long id;
+
+    String firstName;
+    String lastName;
+    Date birthday;
+
+    @Transient
+    Integer age;
+
+    @Embedded
+    private Address homeAddress;
+
+    @OneToMany(cascade=CascadeType.ALL)
+    @JoinColumn(name="CUSTOMER_ID")
+    Set<Order> orders;
+
+    // Getter/setter and business methods
+}]]></programlisting>
+
+        <para>
+            注意:对 JDK 5.0 注解 (和 JSR-220)支持的工作仍然在进行中,并未完成。更多细节请参阅Hibernate Annotations 模块。
+        </para>
+    </sect2>
+    </sect1>
+    <sect1 id="mapping-generated" revision="1">
+        <title>数据库生成属性(Generated Properties)</title>
+        <para>
+            Generated properties指的是其值由数据库生成的属性。一般来说,如果对象有任何属性由数据库生成值,Hibernate应用程序需要进行<literal>刷新(refresh)</literal>。但如果把属性标明为generated,就可以转由Hibernate来负责这个动作。实际上。对定义了generated properties的实体,每当Hibernate执行一条SQL INSERT或者UPDATE语句,会立刻执行一条select来获得生成的值。
+        </para>
+        <para>
+            被标明为generated的属性还必须是 non-insertable和 non-updateable的。只有<xref linkend="mapping-declaration-version">versions</xref>,<xref linkend="mapping-declaration-timestamp">timestamps</xref>和<xref linkend="mapping-declaration-property">简单属性(simple properties)</xref>可以被标明为generated。
+        </para>
+	    <para>
+		    <literal>never</literal> (默认) 标明此属性值不是从数据库中生成。
+	    </para>
+	    <para>
+		    <literal>insert</literal> - 标明此属性值在insert的时候生成,但是不会在随后的update时重新生成。比如说创建日期就归属于这类。注意虽然<xref linkend="mapping-declaration-version">version</xref>和<xref linkend="mapping-declaration-timestamp">timestamp</xref>属性可以被标注为generated,但是不适用这个选项...
+	    </para>
+	    <para>
+		    <literal>always</literal> - 标明此属性值在insert和update时都会被生成。
+	    </para>
+    </sect1>
+
+    <sect1 id="mapping-database-object">
+        <title>辅助数据库对象(Auxiliary Database Objects)</title>
+        <para>
+            Allows CREATE and DROP of arbitrary database objects, in conjunction with
+            Hibernate's schema evolution tools, to provide the ability to fully define
+            a user schema within the Hibernate mapping files.  Although designed specifically
+            for creating and dropping things like triggers or stored procedures, really any
+            SQL command that can be run via a <literal>java.sql.Statement.execute()</literal>
+            method is valid here (ALTERs, INSERTS, etc).  There are essentially two modes for
+            defining auxiliary database objects...
+            帮助CREATE和DROP任意数据库对象,与Hibernate的schema交互工具组合起来,可以提供在Hibernate映射文件中完全定义用户schema的能力。虽然这是为创建和销毁trigger(触发器)或stored procedure(存储过程)等特别设计的,实际上任何可以在<literal>java.sql.Statement.execute()</literal>方法中执行的SQL命令都可以在此使用(比如ALTER, INSERT,等等)。本质上有两种模式来定义辅助数据库对象...
+        </para>
+        <para>
+            第一种模式是在映射文件中显式声明CREATE和DROP命令:
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <create>CREATE TRIGGER my_trigger ...</create>
+        <drop>DROP TRIGGER my_trigger</drop>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+        <para>
+            第二种模式是提供一个类,这个类知道如何组织CREATE和DROP命令。这个特别类必须实现<literal>org.hibernate.mapping.AuxiliaryDatabaseObject</literal>接口。
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <definition class="MyTriggerDefinition"/>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+        <para>
+            还有,这些数据库对象可以特别指定为仅在特定的方言中才使用。
+        </para>
+        <programlisting><![CDATA[<hibernate-mapping>
+    ...
+    <database-object>
+        <definition class="MyTriggerDefinition"/>
+        <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/>
+        <dialect-scope name="org.hibernate.dialect.OracleDialect"/>
+    </database-object>
+</hibernate-mapping>]]></programlisting>
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/batch.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/batch.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/batch.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,282 @@
+<chapter id="batch">
+    <title>批量处理(Batch processing)</title>
+    <para>
+        使用Hibernate将 100 000 条记录插入到数据库的一个很自然的做法可能是这样的
+    </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+for ( int i=0; i<100000; i++ ) {
+    Customer customer = new Customer(.....);
+    session.save(customer);
+}
+tx.commit();
+session.close();]]></programlisting>
+
+    <para>
+        这段程序大概运行到 50 000 条记录左右会失败并抛出 <literal>内存溢出异常(OutOfMemoryException)</literal> 。
+        这是因为 Hibernate 把所有新插入的 <literal>客户(Customer)</literal>实例在 session级别的缓存区进行了缓存的缘故。
+    </para>
+
+    <para>
+        我们会在本章告诉你如何避免此类问题。首先,如果你要执行批量处理并且想要达到一个理想的性能,
+        那么使用JDBC的批量(batching)功能是至关重要。将JDBC的批量抓取数量(batch size)参数设置到一个合适值
+        (比如,10-50之间):
+    </para>
+    
+<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
+
+    <para id="disablebatching" revision="1">
+        注意,假若你使用了<literal>identiy</literal>标识符生成器,Hibernate在JDBC级别透明的关闭插入语句的批量执行。
+    </para>
+
+    <para>
+        你也可能想在执行批量处理时关闭二级缓存:
+    </para>
+
+<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
+    <para>
+        但是,这不是绝对必须的,因为我们可以显式设置<literal>CacheMode</literal>来关闭与二级缓存的交互。
+    </para>
+
+
+    <sect1 id="batch-inserts">
+        <title>批量插入(Batch inserts)</title>
+
+        <para>
+            如果要将很多对象持久化,你必须通过经常的调用 <literal>flush()</literal> 以及稍后调用 
+            <literal>clear()</literal> 来控制第一级缓存的大小。
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+   
+for ( int i=0; i<100000; i++ ) {
+    Customer customer = new Customer(.....);
+    session.save(customer);
+    if ( i % 20 == 0 ) { //20, same as the JDBC batch size //20,与JDBC批量设置相同
+        //flush a batch of inserts and release memory:
+        //将本批插入的对象立即写入数据库并释放内存
+        session.flush();
+        session.clear();
+    }
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="batch-update" >
+        <title>批量更新(Batch updates)</title>
+
+        <para>
+            此方法同样适用于检索和更新数据。此外,在进行会返回很多行数据的查询时,
+            你需要使用 <literal>scroll()</literal> 方法以便充分利用服务器端游标所带来的好处。
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+   
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+    .setCacheMode(CacheMode.IGNORE)
+    .scroll(ScrollMode.FORWARD_ONLY);
+int count=0;
+while ( customers.next() ) {
+    Customer customer = (Customer) customers.get(0);
+    customer.updateStuff(...);
+    if ( ++count % 20 == 0 ) {
+        //flush a batch of updates and release memory:
+        session.flush();
+        session.clear();
+    }
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="batch-statelesssession">
+        <title>StatelessSession (无状态session)接口</title>
+        <para>
+            作为选择,Hibernate提供了基于命令的API,可以用detached object的形式把数据以流的方法加入到数据库,或从数据库输出。<literal>StatelessSession</literal>没有持久化上下文,也不提供多少高层的生命周期语义。特别是,无状态session不实现第一级cache,也不和第二级缓存,或者查询缓存交互。它不实现事务化写,也不实现脏数据检查。用stateless session进行的操作甚至不级联到关联实例。stateless session忽略集合类(Collections)。通过stateless session进行的操作不触发Hibernate的事件模型和拦截器。无状态session对数据的混淆现象免疫,因为它没有第一级缓存。无状态session是低层的抽象,和低层JDBC相当接近。
+        </para>
+        
+<programlisting><![CDATA[StatelessSession session = sessionFactory.openStatelessSession();
+Transaction tx = session.beginTransaction();
+   
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+    .scroll(ScrollMode.FORWARD_ONLY);
+while ( customers.next() ) {
+    Customer customer = (Customer) customers.get(0);
+    customer.updateStuff(...);
+    session.update(customer);
+}
+   
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            注意在上面的例子中,查询返回的<literal>Customer</literal>实例立即被脱管(detach)。它们与任何持久化上下文都没有关系。
+        </para>
+        
+        <para>
+            <literal>StatelessSession</literal> 接口定义的<literal>insert(), update()</literal> 和 <literal>delete()</literal>操作是直接的数据库行级别操作,其结果是立刻执行一条<literal>INSERT, UPDATE</literal> 或 <literal>DELETE</literal> 语句。因此,它们的语义和<literal>Session</literal> 接口定义的<literal>save(), saveOrUpdate()</literal> 和<literal>delete()</literal> 操作有很大的不同。
+        </para>
+
+    </sect1>
+
+    <sect1 id="batch-direct" revision="3">
+        <title>DML(数据操作语言)风格的操作(DML-style operations)</title>
+
+        <para>
+        hence manipulating (using the SQL <literal>Data Manipulation Language</literal>
+            (DML) statements: <literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal>)
+            data directly in the database will not affect in-memory state. However, Hibernate provides methods
+            for bulk SQL-style DML statement execution which are performed through the
+            Hibernate Query Language (<xref linkend="queryhql">HQL</xref>).
+            
+            
+            就像已经讨论的那样,自动和透明的 对象/关系 映射(object/relational mapping)关注于管理对象的状态。
+            这就意味着对象的状态存在于内存,因此直接操作 (使用 SQL <literal>Data Manipulation Language</literal>(DML,数据操作语言)语句 :<literal>INSERT</literal> ,<literal>UPDATE</literal> 和
+            <literal>DELETE</literal>) 数据库中的数据将不会影响内存中的对象状态和对象数据。
+            不过,Hibernate提供通过Hibernate查询语言(<xref linkend="queryhql">HQL</xref>)来执行大批
+            量SQL风格的DML语句的方法。
+        </para>
+
+	    <para>
+            <literal>UPDATE</literal> 和 <literal>DELETE</literal>语句的语法为:
+            <literal>( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?</literal>
+            有几点说明:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    在FROM子句(from-clause)中,FROM关键字是可选的
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    在FROM子句(from-clause)中只能有一个实体名,它可以是别名。如果实体名是别名,那么任何被引用的属性都必须加上此别名的前缀;如果不是别名,那么任何有前缀的属性引用都是非法的。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    不能在大批量HQL语句中使用<xref linkend="queryhql-joins-forms">连接(join)</xref>(显式或者隐式的都不行)。不过在WHERE子句中可以使用子查询。可以在where子句中使用子查询,子查询本身可以包含join。
+
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                       整个WHERE子句是可选的。
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            举个例子,使用<literal>Query.executeUpdate()</literal>方法执行一个HQL
+            <literal>UPDATE</literal>语句(:
+             (方法命名是来源于JDBC's <literal>PreparedStatement.executeUpdate()</literal>):
+        </para>
+
+		<programlisting><![CDATA[Session session = sessionFactory.openSession();
+		Transaction tx = session.beginTransaction();
+
+		String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
+		// or String hqlUpdate = "update Customer set name = :newName where name = :oldName";
+		int updatedEntities = s.createQuery( hqlUpdate )
+		        .setString( "newName", newName )
+		        .setString( "oldName", oldName )
+		        .executeUpdate();
+		tx.commit();
+		session.close();]]></programlisting>
+
+        <para>
+            HQL <literal>UPDATE</literal>语句,默认不会影响更新实体的<xref linkend="mapping-declaration-version">version</xref>或者<xref linkend="mapping-declaration-timestamp">timestamp</xref>属性值。这和EJB3规范是一致的。但是,通过使用<literal>versioned update</literal>,你可以强制Hibernate正确的重置<literal>version</literal>或者<literal>timestamp</literal>属性值。这通过在<literal>UPDATE</literal>关键字后面增加<literal>VERSIONED</literal>关键字来实现的。
+        </para>
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+        .setString( "newName", newName )
+        .setString( "oldName", oldName )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            注意,自定义的版本类型(<literal>org.hibernate.usertype.UserVersionType</literal>)不允许和<literal>update versioned</literal>语句联用。
+        </para>
+
+        <para>
+            执行一个HQL <literal>DELETE</literal>,同样使用 <literal>Query.executeUpdate()</literal> 方法:
+        </para>
+
+		<programlisting><![CDATA[Session session = sessionFactory.openSession();
+		Transaction tx = session.beginTransaction();
+
+		String hqlDelete = "delete Customer c where c.name = :oldName";
+		// or String hqlDelete = "delete Customer where name = :oldName";
+		int deletedEntities = s.createQuery( hqlDelete )
+		        .setString( "oldName", oldName )
+		        .executeUpdate();
+		tx.commit();
+		session.close();]]></programlisting>
+
+        <para>
+            由<literal>Query.executeUpdate()</literal>方法返回的<literal>整型</literal>值表明了受此操作影响的记录数量。
+            注意这个数值可能与数据库中被(最后一条SQL语句)影响了的“行”数有关,也可能没有。一个大批量HQL操作可能导致多条实际的SQL语句被执行,
+            举个例子,对joined-subclass映射方式的类进行的此类操作。这个返回值代表了实际被语句影响了的记录数量。在那个joined-subclass的例子中,
+            对一个子类的删除实际上可能不仅仅会删除子类映射到的表而且会影响“根”表,还有可能影响与之有继承关系的joined-subclass映射方式的子类的表。
+        </para>
+
+        <para>
+            <literal>INSERT</literal>语句的伪码是:
+            <literal>INSERT INTO EntityName properties_list select_statement</literal>.  
+            要注意的是:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    只支持INSERT INTO ... SELECT ...形式,不支持INSERT INTO ... VALUES ...形式.
+                </para>
+                <para>
+                    properties_list和SQL <literal>INSERT</literal>语句中的<literal>字段定义(column speficiation)</literal>类似。对参与继承树映射的实体而言,只有直接定义在给定的类级别的属性才能直接在properties_list中使用。超类的属性不被支持;子类的属性无意义。换句话说,<literal>INSERT</literal>天生不支持多态。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    select_statement可以是任何合法的HQL选择查询,不过要保证返回类型必须和要插入的类型完全匹配。目前,这一检查是在查询编译的时候进行的,而不是把它交给数据库。注意,在Hibernate<literal>Type</literal>间如果只是<emphasis>等价(equivalent)</emphasis>而非<emphasis>相等(equal)</emphasis>,会导致问题。定义为<literal>org.hibernate.type.DateType</literal>和<literal>org.hibernate.type.TimestampType</literal>的两个属性可能会产生类型不匹配错误,虽然数据库级可能不加区分或者可以处理这种转换。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    对id属性来说,insert语句给你两个选择。你可以明确地在properties_list表中指定id属性(这样它的值是从对应的select表达式中获得),或者在properties_list中省略它(此时使用生成指)。后一种选择只有当使用在数据库中生成值的id产生器时才能使用;如果是“内存”中计算的类型生成器,在解析时会抛出一个异常。注意,为了说明这一问题,数据库产生值的生成器是<literal>org.hibernate.id.SequenceGenerator</literal>(和它的子类),以及任何<literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>接口的实现。这儿最值得注意的意外是<literal>org.hibernate.id.TableHiLoGenerator</literal>,它不能在此使用,因为它没有得到其值的途径。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    对映射为<literal>version</literal> 或 <literal>timestamp</literal>的属性来说,insert语句也给你两个选择,你可以在properties_list表中指定(此时其值从对应的select表达式中获得),或者在properties_list中省略它(此时,使用在<literal>org.hibernate.type.VersionType</literal> 中定义的<literal>seed value(种子值)</literal>)。
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            执行HQL <literal>INSERT</literal>语句的例子如下:
+        </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
+int createdEntities = s.createQuery( hqlInsert )
+        .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+    </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/best_practices.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/best_practices.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/best_practices.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,175 @@
+<chapter id="best-practices" revision="2">
+    <title>最佳实践(Best Practices)</title>
+    
+    <variablelist spacing="compact">
+        <varlistentry>
+            <term>设计细颗粒度的持久类并且使用<literal>&lt;component&gt;</literal>来实现映射。</term>
+            <listitem>
+                <para>
+                    使用一个<literal>Address</literal>持久类来封装 <literal>street</literal>,
+                    <literal>suburb</literal>, <literal>state</literal>, <literal>postcode</literal>.
+                    这将有利于代码重用和简化代码重构(refactoring)的工作。
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>对持久类声明标识符属性( identifier properties)。</term>
+            <listitem>
+                <para>
+                    Hibernate中标识符属性是可选的,不过有很多原因来说明你应该使用标识符属性。我们建议标识符应该是“人造”的(自动生成,不涉及业务含义)。
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>使用自然键(natural keys)标识</term>
+            <listitem>
+                <para>
+                    对所有的实体都标识出自然键,用<literal>&lt;natural-id&gt;</literal>进行映射。实现<literal>equals()</literal>和<literal>hashCode()</literal>,在其中用组成自然键的属性进行比较。
+                </para>
+            </listitem>
+            Y00008051221000980   2.7,89,100万
+        </varlistentry>
+        
+        <varlistentry> 
+            <term>为每个持久类写一个映射文件</term>
+            <listitem>
+                <para>
+                     不要把所有的持久类映射都写到一个大文件中。把 <literal>com.eg.Foo</literal> 映射到<literal>com/eg/Foo.hbm.xml</literal>中, 在团队开发环境中,这一点显得特别有意义。
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>把映射文件作为资源加载</term>
+            <listitem>
+                <para>
+                    把映射文件和他们的映射类放在一起进行部署。
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>考虑把查询字符串放在程序外面</term>
+            <listitem>
+                <para>
+                    如果你的查询中调用了非ANSI标准的SQL函数,那么这条实践经验对你适用。把查询字符串放在映射文件中可以让程序具有更好的可移植性。
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>使用绑定变量</term>
+            <listitem>
+                <para>
+                     就像在JDBC编程中一样,应该总是用占位符"?"来替换非常量值,不要在查询中用字符串值来构造非常量值!更好的办法是在查询中使用命名参数。
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>不要自己来管理JDBC connections</term>
+            <listitem>
+                <para>
+                    Hibernate允许应用程序自己来管理JDBC connections,但是应该作为最后没有办法的办法。如果你不能使用Hibernate内建的connections providers,那么考虑实现自己来实现<literal>org.hibernate.connection.ConnectionProvider</literal>
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>考虑使用用户自定义类型(custom type)</term>
+            <listitem>
+                <para>
+                    假设你有一个Java类型,来自某些类库,需要被持久化,但是该类没有提供映射操作需要的存取方法。那么你应该考虑实现<literal>org.hibernate.UserType</literal>接口。这种办法使程序代码写起来更加自如,不再需要考虑类与Hibernate type之间的相互转换。
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>在性能瓶颈的地方使用硬编码的JDBC</term>
+            <listitem>
+                <para>
+                    In performance-critical areas of the system, some kinds of operations might benefit from 
+                    direct JDBC. But please, wait until you <emphasis>know</emphasis> something is a bottleneck. 
+                    And don't assume that direct JDBC is necessarily faster. If you need to use direct JDBC, it might 
+                    be worth opening a Hibernate <literal>Session</literal> and using that JDBC connection. That 
+                    way you can still use the same transaction strategy and underlying connection provider.
+
+                    在系统中对性能要求很严格的一些部分,某些操作也许直接使用JDBC会更好。但是请先<emphasis>确认</emphasis>这的确是一个瓶颈,并且不要想当然认为JDBC一定会更快。如果确实需要直接使用JDBC,那么最好打开一个
+Hibernate <literal>Session</literal> 然后从 <literal>Session</literal>获得connection,按照这种办法你仍然可以使用同样的transaction策略和底层的connection provider。
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+             <term>理解<literal>Session</literal>清洗( flushing)</term>
+            <listitem>
+                <para>
+                    Session会不时的向数据库同步持久化状态,如果这种操作进行的过于频繁,性能会受到一定的影响。有时候你可以通过禁止自动flushing,尽量最小化非必要的flushing操作,或者更进一步,在一个特定的transaction中改变查询和其它操作的顺序。
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>在三层结构中,考虑使用托管对象(detached object)</term>
+            <listitem>
+                <para>
+                    当使用一个servlet / session bean 类型的架构的时候, 你可以把已加载的持久对象在session bean层和servlet / JSP 层之间来回传递。使用新的session来为每个请求服务,使用 <literal>Session.merge()</literal> 或者<literal>Session.saveOrUpdate()</literal>来与数据库同步。
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>在两层结构中,考虑使用长持久上下文(long persistence contexts).</term>
+            <listitem>
+                <para>
+                    为了得到最佳的可伸缩性,数据库事务(Database Transaction)应该尽可能的短。但是,程序常常需要实现长时间运行的<emphasis>“应用程序事务(Application Transaction)”</emphasis>,包含一个从用户的观点来看的原子操作。这个应用程序事务可能跨越多次从用户请求到得到反馈的循环。用脱管对象(与session脱离的对象)来实现应用程序事务是常见的。或者,尤其在两层结构中,把Hibernate Session从JDBC连接中脱离开,下次需要用的时候再连接上。绝不要把一个Session用在多个应用程序事务(Application Transaction)中,否则你的数据可能会过期失效。
+                </para>
+                
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>不要把异常看成可恢复的</term>
+            <listitem>
+                <para>
+                    这一点甚至比“最佳实践”还要重要,这是“必备常识”。当异常发生的时候,必须要回滚 <literal>Transaction</literal> ,关闭<literal>Session</literal>。如果你不这样做的话,Hibernate无法保证内存状态精确的反应持久状态。尤其不要使用<literal>Session.load()</literal>来判断一个给定标识符的对象实例在数据库中是否存在,应该使用<literal>Session.get()</literal>或者进行一次查询.
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>对于关联优先考虑lazy fetching </term>
+            <listitem>
+                <para>
+                    谨慎的使用主动抓取(eager fetching)。对于关联来说,若其目标是无法在第二级缓存中完全缓存所有实例的类,应该使用代理(proxies)与/或具有延迟加载属性的集合(lazy collections)。若目标是可以被缓存的,尤其是缓存的命中率非常高的情况下,应该使用<literal>lazy="false"</literal>,明确的禁止掉eager fetching。如果那些特殊的确实适合使用join fetch 的场合,请在查询中使用<literal>left join fetch</literal>。
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>
+                使用<emphasis>open session in view</emphasis>模式,或者执行严格的<emphasis>装配期(assembly phase)</emphasis>策略来避免再次抓取数据带来的问题
+            </term>
+            <listitem>
+                <para>
+                    
+                    Hibernate让开发者们摆脱了繁琐的<emphasis>Data Transfer Objects</emphasis> (DTO)。在传统的EJB结构中,DTO有双重作用:首先,他们解决了entity bean无法序列化的问题;其次,他们隐含地定义了一个装配期,在此期间,所有在view层需要用到的数据,都被抓取、集中到了DTO中,然后控制才被装到表示层。Hibernate终结了第一个作用。然而,除非你做好了在整个渲染过程中都维护一个打开的持久化上下文(session)的准备,你仍然需要一个装配期(想象一下,你的业务方法与你的表示层有严格的契约,数据总是被放置到托管对象中)。这并非是Hibernate的限制!这是实现安全的事务化数据访问的基本需求。
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>考虑把Hibernate代码从业务逻辑代码中抽象出来</term>
+            <listitem>
+                <para>
+                    把Hibernate的数据存取代码隐藏到接口(interface)的后面,组合使用<emphasis>DAO</emphasis>和<emphasis>Thread Local Session</emphasis>模式。通过Hibernate的<literal>UserType</literal>,你甚至可以用硬编码的JDBC来持久化那些本该被Hibernate持久化的类。 (该建议更适用于规模足够大应用软件中,对于那些只有5张表的应用程序并不适合。)
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>不要用怪异的连接映射</term>
+            <listitem>
+                <para>
+                    多对多连接用得好的例子实际上相当少见。大多数时候你在“连接表”中需要保存额外的信息。这种情况下,用两个指向中介类的一对多的连接比较好。实际上,我们认为绝大多数的连接是一对多和多对一的,你应该谨慎使用其它连接风格,用之前问自己一句,是否真的必须这么做。
+                </para>
+            </listitem>
+        </varlistentry>
+        <varlistentry>
+            <term>偏爱双向关联</term>
+            <listitem>
+                <para>
+                    单向关联更加难于查询。在大型应用中,几乎所有的关联必须在查询中可以双向导航。
+                </para>
+            </listitem>
+        </varlistentry>
+    </variablelist>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/collection_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/collection_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/collection_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1081 @@
+    <chapter id="collections">
+        <title>集合类(Collections)映射</title>
+        
+
+        <sect1 id="collections-persistent" revision="3">
+            <title>持久化集合类(Persistent collections)</title>
+            
+            <para id="collections-persistent-translate-comment">
+            (译者注:在阅读本章的时候,以后整个手册的阅读过程中,我们都会面临一个名词方面的问题,那就是“集合”。"Collections"和"Set"在中文里对应都被翻译为“集合”,但是他们的含义很不一样。Collections是一个超集,Set是其中的一种。大部分情况下,本译稿中泛指的未加英文注明的“集合”,都应当理解为“Collections”。在有些二者同时出现,可能造成混淆的地方,我们用“集合类”来特指“Collecions”,“集合(Set)”来指"Set",一般都会在后面的括号中给出英文。希望大家在阅读时联系上下文理解,不要造成误解。
+            与此同时,“元素”一词对应的英文“element”,也有两个不同的含义。其一为集合的元素,是内存中的一个变量;另一含义则是XML文档中的一个标签所代表的元素。也请注意区别。
+            本章中,特别是后半部分是需要反复阅读才能理解清楚的。如果遇到任何疑问,请记住,英文版本的reference是惟一标准的参考资料。)
+            </para>
+
+        <para>
+            Hibernate要求持久化集合值字段必须声明为接口,比如:
+        </para>
+        
+        <programlisting><![CDATA[public class Product {
+    private String serialNumber;
+    private Set parts = new HashSet();
+    
+    public Set getParts() { return parts; }
+    void setParts(Set parts) { this.parts = parts; }
+    public String getSerialNumber() { return serialNumber; }
+    void setSerialNumber(String sn) { serialNumber = sn; }
+}]]></programlisting>
+        
+        <para>
+            实际的接口可能是<literal>java.util.Set</literal>,
+            <literal>java.util.Collection</literal>, <literal>java.util.List</literal>,
+            <literal>java.util.Map</literal>, <literal>java.util.SortedSet</literal>,
+            <literal>java.util.SortedMap</literal> 或者...任何你喜欢的类型!("任何你喜欢的类型" 代表你需要编写           <literal>org.hibernate.usertype.UserCollectionType</literal>的实现.)
+        </para>
+
+        <para>
+            注意我们是如何用一个<literal>HashSet</literal>实例来初始化实例变量的.这是用于初始化新创建(尚未持久化)的类实例中集合值属性的最佳方法。当你持久化这个实例时——比如通过调用<literal>persist()</literal>——Hibernate 会自动把<literal>HashSet</literal>替换为Hibernate自己的<literal>Set</literal>实现。观察下面的错误:
+        </para>
+
+
+            <programlisting><![CDATA[Cat cat = new DomesticCat();
+Cat kitten = new DomesticCat();
+....
+Set kittens = new HashSet();
+kittens.add(kitten);
+cat.setKittens(kittens);
+session.persist(cat);
+kittens = cat.getKittens(); //Okay, kittens collection is a Set
+(HashSet) cat.getKittens(); //Error!]]></programlisting>
+
+        <para>
+                    根据不同的接口类型,被Hibernate注射的持久化集合类的表现类似<literal>HashMap</literal>, <literal>HashSet</literal>,
+            <literal>TreeMap</literal>, <literal>TreeSet</literal> or
+            <literal>ArrayList</literal>。
+		</para>
+
+        <para>
+        	集合类实例具有值类型的通常行为。当被持久化对象引用后,他们会自动被持久化,当不再被引用后,自动被删除。假若实例被从一个持久化对象传递到另一个,它的元素可能从一个表转移到另一个表。两个实体不能共享同一个集合类实例的引用。因为底层关系数据库模型的原因,集合值属性无法支持空值语义;Hibernate对空的集合引用和空集合不加区别。
+        </para>
+
+        <para>
+        你不需要过多的为此担心。就如同你平时使用普通的Java集合类一样来使用持久化集合类。只是要确认你理解了双向关联的语义(后文讨论)。
+        </para>
+
+    </sect1>
+
+        <sect1 id="collections-mapping" revision="4">
+            <title>集合映射( Collection mappings )</title>
+
+        <para>
+        用于映射集合类的Hibernate映射元素取决于接口的类型。比如, <literal>&lt;set&gt;</literal> 元素用来映射<literal>Set</literal>类型的属性。
+        </para>
+        
+        <programlisting><![CDATA[<class name="Product">
+    <id name="serialNumber" column="productSerialNumber"/>
+    <set name="parts">
+        <key column="productSerialNumber" not-null="true"/>
+        <one-to-many class="Part"/>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+        除了<literal>&lt;set&gt;</literal>,还有<literal>&lt;list&gt;</literal>, <literal>&lt;map&gt;</literal>,            <literal>&lt;bag&gt;</literal>, <literal>&lt;array&gt;</literal> 和
+            <literal>&lt;primitive-array&gt;</literal> 映射元素。<literal>&lt;map&gt;</literal>具有代表性:
+        </para>
+        
+
+            <programlistingco>
+                <areaspec>
+                    <area id="mappingcollection1" coords="2 65"/>
+                    <area id="mappingcollection2" coords="3 65"/>
+                    <area id="mappingcollection3" coords="4 65"/>
+                    <area id="mappingcollection4" coords="5 65"/>
+                    <area id="mappingcollection5" coords="6 65"/>
+                    <area id="mappingcollection6" coords="7 65"/>
+                    <area id="mappingcollection7" coords="8 65"/>
+                    <area id="mappingcollection8" coords="9 65"/>
+                    <area id="mappingcollection9" coords="10 65"/>
+                    <area id="mappingcollection10" coords="11 65"/>
+                    <area id="mappingcollection11" coords="12 65"/>
+                    <area id="mappingcollection12" coords="13 65"/>
+	                <area id="mappingcollection13" coords="14 65"/>
+    	            <area id="mappingcollection14" coords="15 65"/>
+                    
+                </areaspec>
+                <programlisting><![CDATA[<map
+    name="propertyName"
+    table="table_name"
+    schema="schema_name"
+    lazy="true|extra|false"
+    inverse="true|false"
+    cascade="all|none|save-update|delete|all-delete-orphan|delete-orphan"
+    sort="unsorted|natural|comparatorClass"
+    order-by="column_name asc|desc"
+    where="arbitrary sql where condition"
+    fetch="join|select|subselect"
+    batch-size="N"
+    access="field|property|ClassName"
+    optimistic-lock="true|false"
+    mutable="true|false"
+    node="element-name|."
+    embed-xml="true|false"
+>
+
+    <key .... />
+    <map-key .... />
+    <element .... />
+</map>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="mappingcollection1">
+                        <para>
+                            <literal>name</literal> 集合属性的名称
+                        </para>
+                    </callout>                   
+                    <callout arearefs="mappingcollection2">
+                        <para>
+							<literal>table</literal> (可选——默认为属性的名称)这个集合表的名称(不能在一对多的关联关系中使用)
+                        </para>
+                    </callout>                   
+                    <callout arearefs="mappingcollection3">
+                        <para>
+                            <literal>schema</literal> (可选) 表的schema的名称, 他将覆盖在根元素中定义的schema
+                        </para>
+                    </callout>                   
+                    <callout arearefs="mappingcollection4">
+                        <para>
+                            <literal>lazy</literal> (可选--默认为true) 可以用来关闭延迟加载(false),指定一直使用预先抓取,或者打开"extra-lazy" 抓取,此时大多数操作不会初始化集合类(适用于非常大的集合)
+                        </para>
+                    </callout>                   
+                    <callout arearefs="mappingcollection5">
+                        <para>
+                            <literal>inverse</literal> (可选——默认为<literal>false</literal>)
+                            标记这个集合作为双向关联关系中的方向一端。
+
+                        </para>
+                    </callout>                   
+                    <callout arearefs="mappingcollection6">
+                        <para>
+                            <literal>cascade</literal> (可选——默认为<literal>none</literal>)
+                            让操作级联到子实体
+                        </para>
+                    </callout>                   
+                    <callout arearefs="mappingcollection7">
+                        <para>
+                            <literal>sort</literal>(可选)指定集合的排序顺序, 其可以为自然的(<literal>natural</literal>)或者给定一个用来比较的类。
+
+                        </para>
+                    </callout>                   
+                    <callout arearefs="mappingcollection8">
+                        <para>
+                            <literal>order-by</literal> (可选, 仅用于jdk1.4) 指定表的字段(一个或几个)再加上asc或者desc(可选), 定义Map,Set和Bag的迭代顺序
+                        </para>
+                    </callout>                   
+                    <callout arearefs="mappingcollection9">
+                        <para>
+                            <literal>where</literal> (可选) 指定任意的SQL where条件, 该条件将在重新载入或者删除这个集合时使用(当集合中的数据仅仅是所有可用数据的一个子集时这个条件非常有用)
+                        </para>
+                    </callout>                   
+                    <callout arearefs="mappingcollection10">
+                    <para>
+                        <literal>fetch</literal> (可选, 默认为<literal>select</literal>) 用于在外连接抓取、通过后续select抓取和通过后续subselect抓取之间选择。
+                    </para>
+                    </callout>                   
+                    <callout arearefs="mappingcollection11">
+                        <para>
+                            <literal>batch-size</literal> (可选, 默认为<literal>1</literal>) 指定通过延迟加载取得集合实例的批处理块大小("batch size")。
+                        </para>
+                    </callout>                 
+                    <callout arearefs="mappingcollection12">
+                        <para>
+                            <literal>access</literal>(可选-默认为属性property):Hibernate取得集合属性值时使用的策略
+                        </para>
+                    </callout>
+                <callout arearefs="mappingcollection13">
+                    <para>
+                        <literal>乐观锁</literal> (可选 - 默认为 <literal>true</literal>): 
+                        对集合的状态的改变会是否导致其所属的实体的版本增长。 (对一对多关联来说,关闭这个属性常常是有理的)
+                    </para>
+                </callout>
+                <callout arearefs="mappingcollection14">
+                    <para>
+                        <literal>mutable(可变)</literal> (可选 - 默认为<literal>true</literal>): 
+                        若值为<literal>false</literal>,表明集合中的元素不会改变(在某些情况下可以进行一些小的性能优化)。
+                    </para>
+                </callout>
+                    
+                </calloutlist>
+            </programlistingco>
+
+        <sect2 id="collections-foreignkeys" >
+           <title>集合外键(Collection foreign keys)</title>
+    
+            <para>
+            集合实例在数据库中依靠持有集合的实体的外键加以辨别。此外键作为<emphasis>集合关键字段(collection key column)</emphasis>(或多个字段)加以引用。集合关键字段通过<literal>&lt;key&gt;</literal> 元素映射。
+            </para>
+
+            <para>
+                在外键字段上可能具有非空约束。对于大多数集合来说,这是隐含的。对单向一对多关联来说,外键字段默认是可以为空的,因此你可能需要指明 <literal>not-null="true"</literal>。
+            </para>
+    
+            <programlisting><![CDATA[<key column="productSerialNumber" not-null="true"/>]]></programlisting>
+    
+            <para>
+                外键约束可以使用<literal>ON DELETE CASCADE</literal>。
+            </para>
+    
+            <programlisting><![CDATA[<key column="productSerialNumber" on-delete="cascade"/>]]></programlisting>
+            
+            <para>
+                对<literal>&lt;key&gt;</literal> 元素的完整定义,请参阅前面的章节。
+            </para>
+            
+        </sect2>
+        
+        <sect2 id="collections-elements" >
+            <title>集合元素(Collection elements)</title>
+    
+            <para>
+              集合几乎可以包含任何其他的Hibernate类型,包括所有的基本类型、自定义类型、组件,当然还有对其他实体的引用。存在一个重要的区别:位于集合中的对象可能是根据“值”语义来操作(其声明周期完全依赖于集合持有者),或者它可能是指向另一个实体的引用,具有其自己的生命周期。在后者的情况下,被作为集合持有的状态考虑的,只有两个对象之间的“连接”。
+            </para>
+                
+            
+            <para>
+                被包容的类型被称为<emphasis>集合元素类型(collection element type)</emphasis>。集合元素通过<literal>&lt;element&gt;</literal>或<literal>&lt;composite-element&gt;</literal>映射,或在其是实体引用的时候,通过<literal>&lt;one-to-many&gt;</literal> 或<literal>&lt;many-to-many&gt;</literal>映射。前两种用于使用值语义映射元素,后两种用于映射实体关联。
+            </para>
+            
+        </sect2>
+        
+        <sect2 id="collections-indexed">
+            <title>索引集合类(Indexed collections)</title>
+    
+            
+            <para>
+             所有的集合映射,除了set和bag语义的以外,都需要指定一个集合表的<emphasis>索引字段(index column)</emphasis>——用于对应到数组索引,或者<literal>List</literal>的索引,或者<literal>Map</literal>的关键字。通过<literal>&lt;map-key&gt;</literal>,<literal>Map</literal> 的索引可以是任何基础类型;若通过<literal>&lt;map-key-many-to-many&gt;</literal>,它也可以是一个实体引用;若通过<literal>&lt;composite-map-key&gt;</literal>,它还可以是一个组合类型。数组或列表的索引必须是<literal>integer</literal>类型,并且使用 <literal>&lt;list-index&gt;</literal>元素定义映射。被映射的字段包含有顺序排列的整数(默认从0开始)。
+            </para>
+            
+
+        <programlistingco>
+            <areaspec>
+                <area id="mapkey1" coords="2 45"/>
+                <area id="mapkey2" coords="3 45"/>
+                <area id="mapkey3" coords="4 45"/>
+             </areaspec>
+            <programlisting><![CDATA[<map-key 
+        column="column_name"
+        formula="any SQL expression"
+        type="type_name"
+        node="@attribute-name"
+        length="N"/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="mapkey1">
+                        <para>
+                            <literal>column</literal>(可选):保存集合索引值的字段名。
+                        </para>
+                    </callout>          
+                <callout arearefs="mapkey2">
+                    <para>
+                        <literal>formula</literal> (可选): 用于计算map关键字的SQL公式
+                    </para>
+                </callout>
+                    
+                    <callout arearefs="mapkey3">
+                        <para>
+                            <literal>type</literal> (必须):映射键(map key)的类型。
+                        </para>
+                    </callout>          
+                </calloutlist>
+            </programlistingco>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="indexmanytomany1" coords="2 45"/>
+                    <area id="indexmanytomany2" coords="3 45"/>
+              	    <area id="indexmanytomany3" coords="3 45"/>
+                 </areaspec>
+            <programlisting><![CDATA[<map-key-many-to-many
+        column="column_name"
+        formula="any SQL expression"
+        class="ClassName"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="indexmanytomany1">
+                        <para>
+							<literal>column</literal>(可选):集合索引值中外键字段的名称
+                        </para>
+                    </callout>          
+                <callout arearefs="indexmanytomany2">
+                    <para>
+                        <literal>formula</literal> (可选): 用于计算map关键字的外键的SQL公式
+                    </para>
+                </callout>
+                    <callout arearefs="indexmanytomany3">
+                        <para>
+                            <literal>class</literal> (必需):映射的键(map key)使用的实体类。
+                        </para>
+                    </callout>          
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+            假若你的表没有一个索引字段,当你仍然希望使用<literal>List</literal>作为属性类型,你应该把此属性映射为Hibernate <emphasis>&lt;bag&gt;</emphasis>。从数据库中获取的时候,bag不维护其顺序,但也可选择性的进行排序。
+            </para>
+            
+        </sect2>
+        
+        
+        <para>
+        从集合类可以产生很大一部分映射,覆盖了很多常见的关系模型。我们建议你试验schema生成工具,来体会一下不同的映射声明是如何被翻译为数据库表的。
+        </para>
+
+    <sect2 id="collections-ofvalues" revision="2">
+        <title>值集合于多对多关联(Collections of values and many-to-many associations)</title>
+
+        
+        <para>
+        任何值集合或者多对多关联需要专用的具有一个或多个外键字段的<emphasis>collection table</emphasis>、一个或多个<emphasis>collection element column</emphasis>,以及还可能有一个或多个索引字段。
+        </para>
+
+
+            <para>
+                对于一个值集合, 我们使用<literal>&lt;element&gt;</literal>标签。
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                <area id="element1b" coords="2 50"/>
+                <area id="element2b" coords="3 50"/>
+                <area id="element3b" coords="4 50"/>
+                 </areaspec>
+            <programlisting><![CDATA[<element
+        column="column_name"
+        formula="any SQL expression"
+        type="typename"
+        length="L"
+        precision="P"
+        scale="S"
+        not-null="true|false"
+        unique="true|false"
+        node="element-name"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="element1b">
+                        <para>
+                            <literal>column</literal>(可选):保存集合元素值的字段名。
+                        </para>
+                    </callout>          
+                <callout arearefs="element2b">
+                    <para>
+                        <literal>formula</literal> (可选): 用于计算元素的SQL公式                    
+                       </para>
+                </callout>
+                    <callout arearefs="element3b">
+                        <para>
+                            <literal>type</literal> (必需):集合元素的类型
+                        </para>
+                    </callout>          
+                </calloutlist>
+            </programlistingco>
+
+        <para>
+            <emphasis>多对多关联(many-to-many association)</emphasis> 使用
+            <literal>&lt;many-to-many&gt;</literal>元素定义.
+        </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="manytomany1" coords="2 60"/>
+                    <area id="manytomany2" coords="3 60"/>
+                    <area id="manytomany3" coords="4 60"/>
+                <area id="manytomany4" coords="5 60"/>
+                <area id="manytomany5" coords="6 60"/>
+                <area id="manytomany6" coords="7 60"/>
+                <area id="manytomany7" coords="8 60"/>
+                <area id="manytomany8" coords="9 60"/>
+                </areaspec>
+            <programlisting><![CDATA[<many-to-many
+        column="column_name"
+        formula="any SQL expression"
+        class="ClassName"
+        fetch="select|join"
+        unique="true|false"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        property-ref="propertyNameFromAssociatedClass"
+        node="element-name"
+        embed-xml="true|false"
+    />]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="manytomany1">
+                        <para>
+                            <literal>column</literal>(可选): 这个元素的外键关键字段名
+                        </para>                    
+                    </callout>
+                <callout arearefs="manytomany2">
+                    <para>
+                        <literal>formula</literal> (可选): 用于计算元素外键值的SQL公式.
+                    </para>
+                </callout>
+                    
+                    <callout arearefs="manytomany3">
+                        <para>
+                            <literal>class</literal> (必需): 关联类的名称
+                        </para>
+                    </callout>
+                    <callout arearefs="manytomany3">
+                        <para>
+							<literal>outer-join</literal> (可选 - 默认为<literal>auto</literal>):
+							在Hibernate系统参数中<literal>hibernate.use_outer_join</literal>被打开的情况下,该参数用来允许使用outer join来载入此集合的数据。
+                        </para>                    
+                    </callout>
+                <callout arearefs="manytomany4">
+                        <para>
+                        为此关联打开外连接抓取或者后续select抓取。这是特殊情况;对于一个实体及其指向其他实体的多对多关联进全预先抓取(使用一条单独的<literal>SELECT</literal>),你不仅需要对集合自身打开<literal>join</literal>,也需要对<literal>&lt;many-to-many&gt;</literal>这个内嵌元素打开此属性。
+                    </para>
+                </callout>
+                <callout arearefs="manytomany5">
+                        <para>
+                        对外键字段允许DDL生成的时候生成一个惟一约束。这使关联变成了一个高效的一对多关联。(此句存疑:原文为This makes the association multiplicity effectively one to many.)
+                    </para>
+                </callout>
+	            <callout arearefs="manytomany6">
+	                <para>
+	                    <literal>not-found</literal> (可选 - 默认为 <literal>exception</literal>): 指明引用的外键中缺少某些行该如何处理:
+	                    <literal>ignore</literal> 会把缺失的行作为一个空引用处理。
+	                </para>
+	                
+	            </callout>
+                <callout arearefs="manytomany7">
+                    <para>
+                        <literal>entity-name</literal> (可选): 被关联的类的实体名,作为<literal>class</literal>的替代。
+                    </para>
+                </callout>
+                <callout arearefs="manytomany8">
+                    <para>
+                        <literal>property-ref</literal>: (可选) 被关联到此外键(foreign key)的类中的对应属性的名字。若未指定,使用被关联类的主键。
+                    </para>                
+                </callout>                   
+                </calloutlist>
+            </programlistingco>
+
+            <para>
+                例子:首先, 一组字符串:
+            </para>
+
+            <programlisting><![CDATA[<set name="names" table="NAMES">
+    <key column="GROUPID"/>
+    <element column="NAME" type="string"/>
+</set>]]></programlisting>
+
+            <para>
+                包含一组整数的bag(还设置了<literal>order-by</literal>参数指定了迭代的顺序):
+            </para>
+
+        <programlisting><![CDATA[<bag name="sizes" 
+        table="item_sizes" 
+        order-by="size asc">
+    <key column="item_id"/>
+    <element column="size" type="integer"/>
+</bag>]]></programlisting>
+
+            <para>
+                一个实体数组,在这个案例中是一个多对多的关联(注意这里的实体是自动管理生命周期的对象(lifecycle objects),<literal>cascade="all"</literal>):
+            </para>
+
+
+        <programlisting><![CDATA[<array name="addresses" 
+        table="PersonAddress" 
+        cascade="persist">
+    <key column="personId"/>
+    <list-index column="sortOrder"/>
+    <many-to-many column="addressId" class="Address"/>
+</array>]]></programlisting>
+
+            <para>
+                一个map,通过字符串的索引来指明日期:
+            </para>
+
+
+        <programlisting><![CDATA[<map name="holidays" 
+        table="holidays" 
+        schema="dbo" 
+        order-by="hol_name asc">
+    <key column="id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+            <para>
+                一个组件的列表:(下一章讨论)
+            </para>
+
+        <programlisting><![CDATA[<list name="carComponents" 
+        table="CarComponents">
+    <key column="carId"/>
+    <list-index column="sortOrder"/>
+    <composite-element class="CarComponent">
+        <property name="price"/>
+        <property name="type"/>
+        <property name="serialNumber" column="serialNum"/>
+    </composite-element>
+</list>]]></programlisting>
+
+
+        </sect2>
+
+
+        <sect2 id="collections-onetomany">
+            <title>一对多关联(One-to-many Associations)</title>
+            
+
+            <para>
+                <emphasis>一对多关联</emphasis><emphasis>通过外键</emphasis>连接两个类对应的表,而没有中间集合表。 这个关系模型失去了一些Java集合的语义:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        一个被包含的实体的实例只能被包含在一个集合的实例中
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        一个被包含的实体的实例只能对应于集合索引的一个值中
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <para>
+                一个从<literal>Product</literal>到<literal>Part</literal>的关联需要关键字字段,可能还有一个索引字段指向<literal>Part</literal>所对应的表。 <literal>&lt;one-to-many&gt;</literal>标记指明了一个一对多的关联。
+            </para>
+
+            <programlistingco>
+            <areaspec>
+                <area id="onetomany1" coords="2 60"/>
+                <area id="onetomany2" coords="3 60"/>
+                <area id="onetomany3" coords="4 60"/>
+            </areaspec>
+            <programlisting><![CDATA[<one-to-many 
+        class="ClassName"
+        not-found="ignore|exception"
+        entity-name="EntityName"
+        node="element-name"
+        embed-xml="true|false"
+    />]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="onetomany1">
+                        <para>
+                            <literal>class</literal>(必须):被关联类的名称。
+                        </para>
+                    </callout>
+		        <callout arearefs="onetomany2">
+		            <para>
+		                <literal>not-found</literal> (可选 - 默认为<literal>exception</literal>): 
+		               指明若缓存的标示值关联的行缺失,该如何处理:
+		                <literal>ignore</literal> 会把缺失的行作为一个空关联处理。
+		            </para>
+		        </callout>
+                <callout arearefs="onetomany3">
+                    <para>
+                        <literal>entity-name</literal> (可选): 被关联的类的实体名,作为<literal>class</literal>的替代。
+                    </para>
+                </callout>
+            </calloutlist>
+       </programlistingco>
+
+
+            <para>
+                例子
+            </para>
+
+            <programlisting><![CDATA[<set name="bars">
+    <key column="foo_id"/>
+    <one-to-many class="org.hibernate.Bar"/>
+</set>]]></programlisting>
+
+            <para>
+                注意:<literal>&lt;one-to-many&gt;</literal>元素不需要定义任何字段。 也不需要指定表名。
+                
+            </para>
+
+            <para>
+                <emphasis>重要提示</emphasis>:如果<literal>一对多</literal>关联中的外键字段定义成<literal>NOT NULL</literal>,你必须把<literal>&lt;key&gt;</literal>映射声明为<literal>not-null="true"</literal>,或者使用<emphasis>双向关联</emphasis>,并且标明<literal>inverse="true"</literal>。参阅本章后面关于双向关联的讨论。
+            </para>
+            
+        <para>
+            下面的例子展示一个<literal>Part</literal>实体的map,把name作为关键字。(  <literal>partName</literal> 是<literal>Part</literal>的持久化属性)。注意其中的基于公式的索引的用法。
+        </para>
+
+        <programlisting><![CDATA[<map name="parts"
+        cascade="all">
+    <key column="productId" not-null="true"/>
+    <map-key formula="partName"/>
+    <one-to-many class="Part"/>
+</map>]]></programlisting>
+    </sect2>
+    
+    </sect1>
+
+    <sect1 id="collections-advancedmappings">
+        <title>高级集合映射(Advanced collection mappings)</title>
+
+    <sect2 id="collections-sorted" revision="2">
+        <title>有序集合(Sorted collections)</title>
+
+            <para>
+                Hibernate支持实现<literal>java.util.SortedMap</literal>和<literal>java.util.SortedSet</literal>的集合。
+你必须在映射文件中指定一个比较器:
+            </para>
+
+        <programlisting><![CDATA[<set name="aliases" 
+            table="person_aliases" 
+            sort="natural">
+    <key column="person"/>
+    <element column="name" type="string"/>
+</set>
+
+<map name="holidays" sort="my.custom.HolidayComparator">
+    <key column="year_id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+            <para>
+                <literal>sort</literal>属性中允许的值包括<literal>unsorted</literal>,<literal>natural</literal>和某个实现了<literal>java.util.Comparator</literal>的类的名称。
+            </para>
+
+            <para>
+                分类集合的行为事实上象<literal>java.util.TreeSet</literal>或者<literal>java.util.TreeMap</literal>。
+            </para>
+
+            <para>
+                如果你希望数据库自己对集合元素排序,可以利用<literal>set</literal>,<literal>bag</literal>或者<literal>map</literal>映射中的<literal>order-by</literal>属性。这个解决方案只能在jdk1.4或者更高的jdk版本中才可以实现(通过LinkedHashSet或者
+LinkedHashMap实现)。 它是在SQL查询中完成排序,而不是在内存中。
+            </para>
+            
+            <programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="lower(name) asc">
+    <key column="person"/>
+    <element column="name" type="string"/>
+</set>
+
+<map name="holidays" order-by="hol_date, hol_name">
+    <key column="year_id"/>
+    <map-key column="hol_name" type="string"/>
+    <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+            <para>
+                注意: 这个<literal>order-by</literal>属性的值是一个SQL排序子句而不是HQL的!
+            </para>
+
+            <para>
+                关联还可以在运行时使用集合<literal>filter()</literal>根据任意的条件来排序。
+            </para>
+
+        <programlisting><![CDATA[sortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list();]]></programlisting>
+
+        </sect2>
+
+     <sect2 id="collections-bidirectional" revision="1">
+            <title>双向关联(Bidirectional associations)</title>
+
+            <para>
+                <emphasis>双向关联</emphasis>允许通过关联的任一端访问另外一端。在Hibernate中, 支持两种类型的双向关联:
+
+                <variablelist>
+                    <varlistentry>
+                        <term>一对多(one-to-many)</term>
+                        <listitem>
+                            <para>
+						    Set或者bag值在一端, 单独值(非集合)在另外一端
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                    <varlistentry>
+                        <term>多对多(many-to-many)</term>
+                        <listitem>
+                            <para>
+				        两端都是set或bag值
+                            </para>
+                        </listitem>
+                    </varlistentry>
+                </variablelist>
+            
+            </para>
+
+            <para>
+                要建立一个双向的多对多关联,只需要映射两个many-to-many关联到同一个数据库表中,并再定义其中的一端为<emphasis>inverse</emphasis>(使用哪一端要根据你的选择,但它不能是一个索引集合)。
+            </para>
+
+
+
+		<para>
+		这里有一个many-to-many的双向关联的例子;每一个category都可以有很多items,每一个items可以属于很多categories:
+		</para>
+            
+
+        <programlisting><![CDATA[<class name="Category">
+    <id name="id" column="CATEGORY_ID"/>
+    ...
+    <bag name="items" table="CATEGORY_ITEM">
+        <key column="CATEGORY_ID"/>
+        <many-to-many class="Item" column="ITEM_ID"/>
+    </bag>
+</class>
+
+<class name="Item">
+    <id name="id" column="CATEGORY_ID"/>
+    ...
+
+    <!-- inverse end -->
+    <bag name="categories" table="CATEGORY_ITEM" inverse="true">
+        <key column="ITEM_ID"/>
+        <many-to-many class="Category" column="CATEGORY_ID"/>
+    </bag>
+</class>]]></programlisting>
+
+            <para>
+                如果只对关联的反向端进行了改变,这个改变<emphasis>不会</emphasis>被持久化。
+            这表示Hibernate为每个双向关联在内存中存在两次表现,一个从A连接到B,另一个从B连接到A。如果你回想一下Java对象模型,我们是如何在Java中创建多对多关系的,这可以让你更容易理解:
+
+            </para>
+
+        <programlisting><![CDATA[
+category.getItems().add(item);          // The category now "knows" about the relationship
+item.getCategories().add(category);     // The item now "knows" about the relationship
+
+session.persist(item);                   // The relationship won''t be saved!
+session.persist(category);               // The relationship will be saved]]></programlisting>
+
+        <para>
+            非反向端用于把内存中的表示保存到数据库中。
+        </para>
+            
+            <para>
+                要建立一个一对多的双向关联,你可以通过把一个一对多关联,作为一个多对一关联映射到到同一张表的字段上,并且在"多"的那一端定义<literal>inverse="true"</literal>。
+            </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <set name="children" inverse="true">
+        <key column="parent_id"/>
+        <one-to-many class="Child"/>
+    </set>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        not-null="true"/>
+</class>]]></programlisting>
+
+
+        
+            <para>
+                在“一”这一端定义<literal>inverse="true"</literal>不会影响级联操作,二者是正交的概念!
+            </para>
+
+        </sect2>
+
+    <sect2 id="collections-indexedbidirectional">
+        <title>双向关联,涉及有序集合类</title>
+        <para>
+            对于有一端是<literal>&lt;list&gt;</literal>或者<literal>&lt;map&gt;</literal>的双向关联,需要加以特别考虑。假若子类中的一个属性映射到索引字段,没问题,我们仍然可以在集合类映射上使用<literal>inverse="true"</literal>:
+        </para>
+        
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <map name="children" inverse="true">
+        <key column="parent_id"/>
+        <map-key column="name" 
+            type="string"/>
+        <one-to-many class="Child"/>
+    </map>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <property name="name" 
+        not-null="true"/>
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        not-null="true"/>
+</class>]]></programlisting>
+
+        <para>
+            但是,假若子类中没有这样的属性存在,我们不能认为这个关联是真正的双向关联(信息不对称,在关联的一端有一些另外一端没有的信息)。在这种情况下,我们不能使用<literal>inverse="true"</literal>。我们需要这样用:
+        </para>
+
+        <programlisting><![CDATA[<class name="Parent">
+    <id name="id" column="parent_id"/>
+    ....
+    <map name="children">
+        <key column="parent_id"
+            not-null="true"/>
+        <map-key column="name" 
+            type="string"/>
+        <one-to-many class="Child"/>
+    </map>
+</class>
+
+<class name="Child">
+    <id name="id" column="child_id"/>
+    ....
+    <many-to-one name="parent" 
+        class="Parent" 
+        column="parent_id"
+        insert="false"
+        update="false"
+        not-null="true"/>
+</class>]]></programlisting>
+
+       <para>
+           注意在这个映射中,关联中集合类"值"一端负责来更新外键.TODO: Does this really result in some unnecessary update statements?
+       </para>
+
+    </sect2>
+
+
+        <sect2 id="collections-ternary">
+            <title>三重关联(Ternary associations)</title>
+            
+            <para>
+            	有三种可能的途径来映射一个三重关联。第一种是使用一个<literal>Map</literal>,把一个关联作为其索引:
+            </para>
+            	
+        <programlisting><![CDATA[<map name="contracts">
+    <key column="employer_id" not-null="true"/>
+    <map-key-many-to-many column="employee_id" class="Employee"/>
+    <one-to-many class="Contract"/>
+</map>]]></programlisting>
+            
+            <programlisting><![CDATA[<map name="connections">
+    <key column="incoming_node_id"/>
+    <map-key-many-to-many column="outgoing_node_id" class="Node"/>
+    <many-to-many column="connection_id" class="Connection"/>
+</map>]]></programlisting>
+        
+        <para>
+        第二种方法是简单的把关联重新建模为一个实体类。这使我们最经常使用的方法。
+        </para>
+        <para>
+        最后一种选择是使用复合元素,我们会在后面讨论
+        </para>
+        
+    </sect2>
+	
+        <sect2 id="collections-idbag" revision="1">
+            <title><literal>使用&lt;idbag&gt;</literal></title>
+            <para>
+                如果你完全信奉我们对于“联合主键(composite keys)是个坏东西”,和“实体应该使用(无机的)自己生成的代用标识符(surrogate keys)”的观点,也许你会感到有一些奇怪,我们目前为止展示的多对多关联和值集合都是映射成为带有联合主键的表的!现在,这一点非常值得争辩;看上去一个单纯的关联表并不能从代用标识符中获得什么好处(虽然使用组合值的集合<emphasis>可能</emphasis>会获得一点好处)。不过,Hibernate提供了一个(一点点试验性质的)功能,让你把多对多关联和值集合应得到一个使用代用标识符的表去。
+            </para>
+            
+            <para>
+                <literal>&lt;idbag&gt;</literal> 属性让你使用bag语义来映射一个<literal>List</literal> (或<literal>Collection</literal>)。
+            </para>
+            
+<programlisting><![CDATA[<idbag name="lovers" table="LOVERS">
+    <collection-id column="ID" type="long">
+        <generator class="sequence"/>
+    </collection-id>
+    <key column="PERSON1"/>
+    <many-to-many column="PERSON2" class="Person" fetch="join"/>
+</idbag>]]></programlisting>
+
+            <para>
+                你可以理解,<literal>&lt;idbag&gt;</literal>人工的id生成器,就好像是实体类一样!集合的每一行都有一个不同的人造关键字。但是,Hibernate没有提供任何机制来让你取得某个特定行的人造关键字。
+            </para>
+            
+            <para>
+                注意<literal>&lt;idbag&gt;</literal>的更新性能要比普通的<literal>&lt;bag&gt;</literal>高得多!Hibernate可以有效的定位到不同的行,分别进行更新或删除工作,就如同处理一个list, map或者set一样。
+                
+            </para>
+            
+            <para>
+                在目前的实现中,还不支持使用<literal>identity</literal>标识符生成器策略来生成<literal>&lt;idbag&gt;</literal>集合的标识符。
+            </para>
+    
+        </sect2>
+       
+       </sect1>
+    <!--undocumenting this stuff -->
+	<!--sect1 id="collections-heterogeneous">
+	    <title>异类关联(Heterogeneous Associations)</title>
+	    
+	    <para>
+	        <literal>&lt;many-to-any&gt;</literal>和<literal>&lt;index-many-to-any&gt;</literal>元素提供真正的异类关联。这些元素和<literal>&lt;any&gt;</literal>元素工作方式是同样的,他们都应该很少用到。
+	    </para>
+	</sect1-->
+
+        <sect1 id="collections-example" revision="1">
+            <title>集合例子(Collection example)</title>
+
+            <para>
+                在前面的几个章节的确非常令人迷惑。 因此让我们来看一个例子。这个类:
+            </para>
+
+            <programlisting><![CDATA[package eg;
+import java.util.Set;
+
+public class Parent {
+    private long id;
+    private Set children;
+
+    public long getId() { return id; }
+    private void setId(long id) { this.id=id; }
+
+    private Set getChildren() { return children; }
+    private void setChildren(Set children) { this.children=children; }
+
+    ....
+    ....
+}]]></programlisting>
+
+            <para>
+                这个类有一个<literal>Child</literal>的实例集合。如果每一个子实例至多有一个父实例, 那么最自然的映射是一个one-to-many的关联关系:
+            </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children">
+            <key column="parent_id"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                在以下的表定义中反应了这个映射关系:
+            </para>
+
+            <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255), parent_id bigint )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+            <para>
+                如果父亲是<emphasis>必须</emphasis>的, 那么就可以使用双向one-to-many的关联了:
+            </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children" inverse="true">
+            <key column="parent_id"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+        <many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                请注意<literal>NOT NULL</literal>的约束:                
+            </para>
+
+            <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null
+                     primary key,
+                     name varchar(255),
+                     parent_id bigint not null )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+
+            <para>
+            另外,如果你绝对坚持这个关联应该是单向的,你可以对<literal>&lt;key&gt;</literal>映射声明<literal>NOT NULL</literal>约束:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children">
+            <key column="parent_id" not-null="true"/>
+            <one-to-many class="Child"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+                另外一方面,如果一个子实例可能有多个父实例, 那么就应该使用many-to-many关联:
+            </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Parent">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <set name="children" table="childset">
+            <key column="parent_id"/>
+            <many-to-many class="Child" column="child_id"/>
+        </set>
+    </class>
+
+    <class name="Child">
+        <id name="id">
+            <generator class="sequence"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+            <para>
+                表定义:
+            </para>
+
+        <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255) )
+create table childset ( parent_id bigint not null,
+                        child_id bigint not null,
+                        primary key ( parent_id, child_id ) )
+alter table childset add constraint childsetfk0 (parent_id) references parent
+alter table childset add constraint childsetfk1 (child_id) references child]]></programlisting>
+
+		<para>
+		 更多的例子,以及一个完整的父/子关系映射的排练,请参阅<xref linkend="example-parentchild"/>.
+		</para>
+        
+        <para>
+            甚至可能出现更加复杂的关联映射,我们会在下一章中列出所有可能性。
+        </para>
+        
+        </sect1>
+             
+    </chapter>

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/component_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/component_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/component_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,339 @@
+<chapter id="components">
+  <title>组件(Component)映射</title>
+
+  <para>
+      <emphasis>组件</emphasis>(Component)这个概念在Hibernate中几处不同的地方为了不同的目的被重复使用.
+  </para>
+
+  <sect1 id="components-dependentobjects" revision="2">
+    <title>依赖对象(Dependent objects)</title>
+
+    <para>
+        组件(Component)是一个被包含的对象,在持久化的过程中,它被当作值类型,而并非一个实体的引用。在这篇文档中,组件这一术语指的是面向对象的合成概念(而并不是系统构架层次上的组件的概念)。举个例子, 你对人(Person)这个概念可以像下面这样来建模:
+    </para>
+
+    <programlisting><![CDATA[public class Person {
+    private java.util.Date birthday;
+    private Name name;
+    private String key;
+    public String getKey() {
+        return key;
+    }
+    private void setKey(String key) {
+        this.key=key;
+    }
+    public java.util.Date getBirthday() {
+        return birthday;
+    }
+    public void setBirthday(java.util.Date birthday) {
+        this.birthday = birthday;
+    }
+    public Name getName() {
+        return name;
+    }
+    public void setName(Name name) {
+        this.name = name;
+    }
+    ......
+    ......
+}]]></programlisting>
+
+    <programlisting><![CDATA[public class Name {
+    char initial;
+    String first;
+    String last;
+    public String getFirst() {
+        return first;
+    }
+    void setFirst(String first) {
+        this.first = first;
+    }
+    public String getLast() {
+        return last;
+    }
+    void setLast(String last) {
+        this.last = last;
+    }
+    public char getInitial() {
+        return initial;
+    }
+    void setInitial(char initial) {
+        this.initial = initial;
+    }
+}]]></programlisting>
+
+        <para>
+            在持久化的过程中,<literal>姓名(Name)</literal>可以作为<literal>人(Person)</literal>的一个组件。需要注意的是:你应该为<literal>姓名</literal>的持久化属性定义getter和setter方法,但是你不需要实现任何的接口或申明标识符字段。
+        </para>
+
+        <para>
+            以下是这个例子的Hibernate映射文件:
+        </para>
+
+        <programlisting><![CDATA[<class name="eg.Person" table="person">
+    <id name="Key" column="pid" type="string">
+        <generator class="uuid"/>
+    </id>
+    <property name="birthday" type="date"/>
+    <component name="Name" class="eg.Name"> <!-- class attribute optional -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </component>
+</class>]]></programlisting>
+
+    <para>
+        人员(Person)表中将包括<literal>pid</literal>,
+        <literal>birthday</literal>,
+        <literal>initial</literal>,
+        <literal>first</literal>和
+        <literal>last</literal>等字段。</para>
+
+    <para>
+        就像所有的值类型一样, 组件不支持共享引用。
+        换句话说,两个人可能重名,但是两个Person对象应该包含两个独立的Name对象,只不过这两个Name对象具有“同样”的值。
+        组件的值可以为空,其定义如下。
+        每当Hibernate重新加载一个包含组件的对象,如果该组件的所有字段为空,Hibernate将假定整个组件为空。
+        在大多数情况下,这样假定应该是没有问题的。
+    </para>
+
+    <para>
+        组件的属性可以是任意一种Hibernate类型(包括集合, 多对多关联,
+        以及其它组件等等)。嵌套组件不应该被当作一种特殊的应用(Nested components should not be considered an
+        exotic usage)。 Hibernate倾向于支持细致的(fine-grained)对象模型。
+    </para>
+    
+    <para>
+        <literal>&lt;component&gt;</literal> 元素还允许有 <literal>&lt;parent&gt;</literal>子元素,用来表明component类中的一个属性是指向包含它的实体的引用。
+    </para>
+
+    <programlisting><![CDATA[<class name="eg.Person" table="person">
+    <id name="Key" column="pid" type="string">
+        <generator class="uuid"/>
+    </id>
+    <property name="birthday" type="date">
+    <component name="Name" class="eg.Name" unique="true">
+        <parent name="namedPerson"/> <!-- reference back to the Person -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>
+    </component&gt;
+</class>]]></programlisting>
+
+  </sect1>
+
+  <sect1 id="components-incollections" revision="1">
+    <title>在集合中出现的依赖对象 (Collections of dependent objects)</title>
+
+    <para>
+        Hibernate支持组件的集合(例如: 一个元素是姓名(Name)这种类型的数组)。
+        你可以使用<literal>&lt;composite-element&gt;</literal>标签替代<literal>&lt;element&gt;</literal>标签来定义你的组件集合。
+    </para>
+
+    <programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
+    <key column="id"/&gt;
+    <composite-element class="eg.Name"> <!-- class attribute required -->
+        <property name="initial"/>
+        <property name="first"/>
+        <property name="last"/>;
+    </composite-element>
+</set>]]></programlisting>
+
+    <para>
+        注意,如果你定义的Set包含组合元素(composite-element),正确地实现<literal>equals()</literal>和<literal>hashCode()</literal>是非常重要的。
+    </para>
+
+    <para>
+        组合元素可以包含组件,但是不能包含集合。如果你的组合元素自身包含组件, 你必须使用<literal>&lt;nested-composite-element&gt;</literal>标签。这是一个相当特殊的案例 - 在一个组件的集合里,那些组件本身又可以包含其他的组件。这个时候你就应该考虑一下使用one-to-many关联是否会更恰当。
+		尝试对这个组合元素重新建模为一个实体-但是需要注意的是,虽然Java模型和重新建模前是一样的,关系模型和持久性语义会有细微的变化。
+    </para>
+
+    <para>
+        请注意如果你使用<literal>&lt;set&gt;</literal>标签,一个组合元素的映射不支持可能为空的属性. 当删除对象时, Hibernate必须使用每一个字段的值来确定一条记录(在组合元素表中,没有单独的关键字段),
+		如果有为null的字段,这样做就不可能了。你必须作出一个选择,要么在组合元素中使用不能为空的属性,要么选择使用<literal>&lt;list&gt;</literal>,<literal>&lt;map&gt;</literal>,<literal>&lt;bag&gt;</literal> 或者 <literal>&lt;idbag&gt;</literal>而不是 <literal>&lt;set&gt;</literal>。
+    </para>
+
+    <para>
+        组合元素有个特别的用法是它可以包含一个<literal>&lt;many-to-one&gt;</literal>元素。类似这样的映射允许你将一个many-to-many关联表映射为组合元素的集合。(A mapping like this allows you to map extra columns of a many-to-many association table to the composite element class.) 接下来的的例子是从<literal>Order</literal>到<literal>Item</literal>的一个多对多的关联关系, 关联属性是 <literal>purchaseDate</literal>, <literal>price</literal> 和 <literal>quantity</literal> 。
+    </para>
+
+    <programlisting><![CDATA[<class name="eg.Order" .... >
+    ....
+    <set name="purchasedItems" table="purchase_items" lazy="true">
+        <key column="order_id">
+        <composite-element class="eg.Purchase">
+            <property name="purchaseDate"/>
+            <property name="price"/>
+            <property name="quantity"/>
+            <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+    <para>
+        当然,当你定义Item时,你无法引用这些purchase,因此你无法实现双向关联查询。记住组件是值类型,并且不允许共享引用。某一个特定的<literal>Purchase</literal> 可以放在<literal>Order</literal>的集合中,但它不能同时被<literal>Item</literal>所引用。
+    </para>
+
+    <para>其实组合元素的这个用法可以扩展到三重或多重关联:</para>
+
+    <programlisting><![CDATA[<class name="eg.Order" .... >
+    ....
+    <set name="purchasedItems" table="purchase_items" lazy="true">
+        <key column="order_id">
+        <composite-element class="eg.OrderLine">
+            <many-to-one name="purchaseDetails" class="eg.Purchase"/>
+            <many-to-one name="item" class="eg.Item"/>
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+    <para>
+        在查询中,表达组合元素的语法和关联到其他实体的语法是一样的。
+     </para>
+     
+  </sect1>
+
+  <sect1 id="components-asmapindex">
+    <title>组件作为Map的索引(Components as Map indices )</title>
+
+    <para>
+        <literal>&lt;composite-map-key&gt;</literal>元素允许你映射一个组件类作为一个<literal>Map</literal>的key,前提是你必须正确的在这个类中重写了<literal>hashCode()</literal> 和 <literal>equals()</literal>方法。
+    </para>
+  </sect1>
+
+  <sect1 id="components-compositeid" revision="1">
+    <title>组件作为联合标识符(Components as composite identifiers)</title>
+
+    <para>
+       你可以使用一个组件作为一个实体类的标识符。 你的组件类必须满足以下要求:
+    </para>
+
+    <itemizedlist spacing="compact">
+      <listitem>
+        <para>
+            它必须实现<literal>java.io.Serializable</literal>接口
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+            它必须重新实现<literal>equals()</literal>和<literal>hashCode()</literal>方法, 始终和组合关键字在数据库中的概念保持一致
+        </para>
+      </listitem>
+    </itemizedlist>
+
+    <para>
+        <emphasis>注意:在Hibernate3中,第二个要求并非是Hibernate强制必须的。但最好这样做。</emphasis>
+    </para>
+
+    <para>
+        你不能使用一个<literal>IdentifierGenerator</literal>产生组合关键字。一个应用程序必须分配它自己的标识符。
+    </para>
+
+    <para>
+        使用<literal>&lt;composite-id&gt;</literal> 标签(并且内嵌<literal>&lt;key-property&gt;</literal>元素)代替通常的<literal>&lt;id&gt;</literal>标签。比如,<literal>OrderLine</literal>类具有一个主键,这个主键依赖于<literal>Order</literal>的(联合)主键。
+    </para>
+
+        <programlisting><![CDATA[<class name="OrderLine">
+    
+    <composite-id name="id" class="OrderLineId">
+        <key-property name="lineId"/>
+        <key-property name="orderId"/>
+        <key-property name="customerId"/>
+    </composite-id>
+    
+    <property name="name"/>
+    
+    <many-to-one name="order" class="Order"
+            insert="false" update="false">
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </many-to-one>
+    ....
+    
+</class>]]></programlisting>
+
+    <para>
+        现在,任何指向<literal>OrderLine</literal>的外键都是复合的。在你的映射文件中,必须为其他类也这样声明。例如,一个指向<literal>OrderLine</literal>的关联可能被这样映射:
+    </para>
+
+        <programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
+<!-- the "class" attribute is optional, as usual -->
+    <column name="lineId"/>
+    <column name="orderId"/>
+    <column name="customerId"/>
+</many-to-one>]]></programlisting>
+
+    <para>
+        (注意在各个地方<literal>&lt;column&gt;</literal>标签都是<literal>column</literal>属性的替代写法。)
+    </para>
+
+    <para>
+        指向<literal>OrderLine</literal>的<literal>多对多</literal>关联也使用联合外键:
+    </para>
+
+    <programlisting><![CDATA[<set name="undeliveredOrderLines">
+    <key column name="warehouseId"/>
+    <many-to-many class="OrderLine">
+        <column name="lineId"/>
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </many-to-many>
+</set>]]></programlisting>
+
+    <para>
+        在<literal>Order</literal>中,<literal>OrderLine</literal>的集合则是这样:
+    </para>
+
+    <programlisting><![CDATA[<set name="orderLines" inverse="true">
+    <key>
+        <column name="orderId"/>
+        <column name="customerId"/>
+    </key>
+    <one-to-many class="OrderLine"/>
+</set>]]></programlisting>
+
+    <para>
+        (与通常一样,<literal>&lt;one-to-many&gt;</literal>元素不声明任何列.)
+    </para>
+
+    <para>
+        假若<literal>OrderLine</literal>本身拥有一个集合,它也具有组合外键。
+    </para>
+
+        <programlisting><![CDATA[<class name="OrderLine">
+    ....
+    ....
+    <list name="deliveryAttempts">
+        <key>   <!-- a collection inherits the composite key type -->
+            <column name="lineId"/>
+            <column name="orderId"/>
+            <column name="customerId"/>
+        </key>
+        <list-index column="attemptId" base="1"/>
+        <composite-element class="DeliveryAttempt">
+            ...
+        </composite-element>
+    </set>
+</class>]]></programlisting>
+
+  </sect1>
+
+  <sect1 id="components-dynamic" revision="1">
+    <title>动态组件 (Dynamic components)</title>
+
+    <para>
+        你甚至可以映射<literal>Map</literal>类型的属性:
+    </para>
+
+    <programlisting><![CDATA[<dynamic-component name="userAttributes">
+    <property name="foo" column="FOO" type="string"/>
+    <property name="bar" column="BAR" type="integer"/>
+    <many-to-one name="baz" class="Baz" column="BAZ_ID"/>
+</dynamic-component>]]></programlisting>
+
+    <para>
+        从<literal>&lt;dynamic-component&gt;</literal>映射的语义上来讲,它和<literal>&lt;component&gt;</literal>是相同的。
+        这种映射类型的优点在于通过修改映射文件,就可以具有在部署时检测真实属性的能力。利用一个DOM解析器,也可以在程序运行时操作映射文件。
+        更好的是,你可以通过<literal>Configuration</literal>对象来访问(或者修改)Hibernate的运行时元模型。
+     </para>
+  </sect1>
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/configuration.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/configuration.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/configuration.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1694 @@
+<chapter id="session-configuration" revision="1">
+
+    <title>
+        配置
+    </title>
+    
+    <para>
+        由于Hibernate是为了能在各种不同环境下工作而设计的, 因此存在着大量的配置参数. 幸运的是多数配置参数都
+        有比较直观的默认值, 并有随Hibernate一同分发的配置样例<literal>hibernate.properties</literal>
+        (位于<literal>etc/</literal>)来展示各种配置选项. 所需做的仅仅是将这个样例文件复制到类路径
+        (classpath)下并做一些自定义的修改.
+    </para>
+
+    <sect1 id="configuration-programmatic" revision="1">
+        <title>
+            可编程的配置方式
+        </title>
+
+        <para>
+            一个<literal>org.hibernate.cfg.Configuration</literal>实例代表了一个应用程序中Java类型
+            到SQL数据库映射的完整集合. <literal>Configuration</literal>被用来构建一个(不可变的
+            (immutable))<literal>SessionFactory</literal>. 映射定义则由不同的XML映射定义文件编译而来.
+        </para>
+
+        <para>
+            你可以直接实例化<literal>Configuration</literal>来获取一个实例,并为它指定XML映射定义
+            文件. 如果映射定
+            义文件在类路径(classpath)中, 请使用<literal>addResource()</literal>:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addResource("Item.hbm.xml")
+    .addResource("Bid.hbm.xml");]]></programlisting>
+
+        <para>
+            一个替代方法(有时是更好的选择)是,指定被映射的类,让Hibernate帮你寻找映射定义文件:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addClass(org.hibernate.auction.Item.class)
+    .addClass(org.hibernate.auction.Bid.class);]]></programlisting>
+
+        <para>
+            Hibernate将会在类路径(classpath)中寻找名字为
+            <literal>/org/hibernate/auction/Item.hbm.xml</literal>和
+            <literal>/org/hibernate/auction/Bid.hbm.xml</literal>映射定义文件.
+            这种方式消除了任何对文件名的硬编码(hardcoded).
+        </para>
+        
+        <para>
+            <literal>Configuration</literal>也允许你指定配置属性:
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration()
+    .addClass(org.hibernate.auction.Item.class)
+    .addClass(org.hibernate.auction.Bid.class)
+    .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
+    .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
+    .setProperty("hibernate.order_updates", "true");]]></programlisting>
+    
+        <para>
+            当然这不是唯一的传递Hibernate配置属性的方式, 其他可选方式还包括:
+        </para>
+
+        <orderedlist spacing="compact">
+            <listitem>
+                <para>
+                    传一个<literal>java.util.Properties</literal>实例给
+                    <literal>Configuration.setProperties()</literal>.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    将<literal>hibernate.properties</literal>放置在类路径(classpath)的根目录下
+                    (root directory).
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    通过<literal>java -Dproperty=value</literal>来设置系统
+                    (<literal>System</literal>)属性.
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    在<literal>hibernate.cfg.xml</literal>中加入元素
+                    <literal>&lt;property&gt;</literal> (稍后讨论).
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <para>
+            如果想尽快体验Hibernate, <literal>hibernate.properties</literal>是最简单的方式.
+        </para>
+
+        <para>
+            <literal>Configuration</literal>实例被设计成启动期间(startup-time)对象, 
+            一旦<literal>SessionFactory</literal>创建完成它就被丢弃了.
+        </para>
+
+    </sect1>
+    
+    <sect1 id="configuration-sessionfactory">
+        <title>
+            获得SessionFactory
+        </title>
+		
+
+        <para>
+            当所有映射定义被<literal>Configuration</literal>解析后, 
+            应用程序必须获得一个用于构造<literal>Session</literal>实例的工厂. 
+            这个工厂将被应用程序的所有线程共享:
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sessions = cfg.buildSessionFactory();]]></programlisting>
+
+        <para>
+            Hibernate允许你的应用程序创建多个<literal>SessionFactory</literal>实例. 这对
+            使用多个数据库的应用来说很有用.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-hibernatejdbc" revision="1">
+        <title>
+            JDBC连接
+        </title>
+
+        <para>
+            通常你希望<literal>SessionFactory</literal>来为你创建和缓存(pool)JDBC连接. 如果你采用这种方式, 
+            只需要如下例所示那样,打开一个<literal>Session</literal>:
+        </para>
+
+        <programlisting><![CDATA[Session session = sessions.openSession(); // open a new Session]]></programlisting>
+        
+        <para>
+            一旦你需要进行数据访问时, 就会从连接池(connection pool)获得一个JDBC连接.
+        </para>
+
+        <para>
+            为了使这种方式工作起来, 我们需要向Hibernate传递一些JDBC连接的属性.
+            所有Hibernate属性的名字和语义都在<literal>org.hibernate.cfg.Environment</literal>中定义. 
+            我们现在将描述JDBC连接配置中最重要的设置.
+        </para>
+
+        <para>
+            如果你设置如下属性,Hibernate将使用<literal>java.sql.DriverManager</literal>来获得(和缓存)JDBC连接 :
+        </para>
+
+        <table frame="topbot">
+            <title>
+                Hibernate JDBC属性
+            </title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>
+                            属性名
+                        </entry>
+                        <entry>
+                            用途
+                        </entry>
+                    </row>
+                </thead>
+            <tbody>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.driver_class</literal>
+                </entry>
+                <entry>
+                    <emphasis>jdbc驱动类</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.url</literal>
+                </entry>
+                <entry>
+                    <emphasis>jdbc URL</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.username</literal>
+                </entry>
+                <entry>
+                    <emphasis>数据库用户</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.password</literal>
+                </entry>
+                <entry>
+                    <emphasis>数据库用户密码</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.pool_size</literal>
+                </entry>
+                <entry>
+                    <emphasis>连接池容量上限数目</emphasis>
+                </entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+            但Hibernate自带的连接池算法相当不成熟. 
+            它只是为了让你快些上手<emphasis>,并不适合用于产品系统</emphasis>或性能测试中。
+            出于最佳性能和稳定性考虑你应该使用第三方的连接池。只需要用特定连接池的设置替换
+            <literal>hibernate.connection.pool_size</literal>即可。这将关闭Hibernate自带的连接池.
+            例如, 你可能会想用C3P0.
+        </para>
+
+        <para>
+            C3P0是一个随Hibernate一同分发的开源的JDBC连接池, 它位于<literal>lib</literal>目录下。
+            如果你设置了<literal>hibernate.c3p0.*</literal>相关的属性, Hibernate将使用
+            <literal>C3P0ConnectionProvider</literal>来缓存JDBC连接. 如果你更原意使用Proxool, 请参考发
+            行包中的<literal>hibernate.properties</literal>并到Hibernate网站获取更多的信息.
+        </para>
+
+        <para>
+            这是一个使用C3P0的<literal>hibernate.properties</literal>样例文件:
+        </para>
+
+        <programlisting id="c3p0-configuration" revision="1"><![CDATA[hibernate.connection.driver_class = org.postgresql.Driver
+hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
+hibernate.connection.username = myuser
+hibernate.connection.password = secret
+hibernate.c3p0.min_size=5
+hibernate.c3p0.max_size=20
+hibernate.c3p0.timeout=1800
+hibernate.c3p0.max_statements=50
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+        <para>
+            为了能在应用程序服务器(application server)中使用Hibernate, 应当总是将Hibernate
+            配置成从注册在JNDI中的<literal>Datasource</literal>处获得连接,你至少需要设置下列属性中的一个:
+        </para>
+
+        <table frame="topbot">
+            <title>
+                Hibernate数据源属性
+            </title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>
+                            属性名
+                        </entry>
+                        <entry>
+                            用途
+                        </entry>
+                    </row>
+                </thead>
+            <tbody>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.datasource</literal>
+                </entry>
+                <entry>
+                    <emphasis>数据源JNDI名字</emphasis>
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.jndi.url</literal>
+                </entry>
+                <entry>
+                    <emphasis>JNDI提供者的URL</emphasis> (可选)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.jndi.class</literal>
+                </entry>
+                <entry>
+                    <emphasis>JNDI <literal>InitialContextFactory</literal>类</emphasis> (可选)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.username</literal>
+                </entry>
+                <entry>
+                    <emphasis>数据库用户</emphasis> (可选)
+                </entry>
+            </row>
+            <row>
+                <entry>
+                    <literal>hibernate.connection.password</literal>
+                </entry>
+                <entry>
+                    <emphasis>数据库用户密码</emphasis> (可选)
+                </entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+            这是一个使用应用程序服务器提供的JNDI数据源的<literal>hibernate.properties</literal>样例文件:
+        </para>
+
+        <programlisting><![CDATA[hibernate.connection.datasource = java:/comp/env/jdbc/test
+hibernate.transaction.factory_class = \
+    org.hibernate.transaction.JTATransactionFactory
+hibernate.transaction.manager_lookup_class = \
+    org.hibernate.transaction.JBossTransactionManagerLookup
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+        <para>
+            从JNDI数据源获得的JDBC连接将自动参与到应用程序服务器中容器管理的事务(container-managed transactions)中去.
+        </para>
+
+        <para>
+            任何连接(connection)属性的属性名都要以"<literal>hibernate.connnection</literal>"开头. 
+            例如, 你可能会使用<literal>hibernate.connection.charSet</literal>来指定字符集<literal>charSet</literal>.
+        </para>
+
+        <para>
+            通过实现<literal>org.hibernate.connection.ConnectionProvider</literal>接口,你可以定义属于
+            你自己的获得JDBC连接的插件策略。通过设置<literal>hibernate.connection.provider_class</literal>,
+            你可以选择一个自定义的实现.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-optional" revision="1">
+        <title>
+            可选的配置属性
+        </title>
+        
+        <para>
+            有大量属性能用来控制Hibernate在运行期的行为. 它们都是可选的, 并拥有适当的默认值.
+        </para>
+
+        <para>
+            <emphasis>警告: 其中一些属性是"系统级(system-level)的".</emphasis>
+            系统级属性只能通过<literal>java -Dproperty=value</literal>或
+            <literal>hibernate.properties</literal>来设置, 而<emphasis>不能</emphasis>用上面描述的其他方法来设置.
+        </para>
+
+        <table frame="topbot" id="configuration-optional-properties" revision="8">
+            <title>
+                Hibernate配置属性
+            </title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>
+                            属性名
+                        </entry>
+                        <entry>
+                            用途
+                        </entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.dialect</literal>
+                        </entry>
+                        <entry>
+                            一个Hibernate <literal>Dialect</literal>类名允许Hibernate针对特定的关系数据库生成优化的SQL.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>full.classname.of.Dialect</literal>
+               
+             </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.show_sql</literal>
+                        </entry>
+                        <entry>
+                            输出所有SQL语句到控制台.
+							有一个另外的选择是把<literal>org.hibernate.SQL</literal>这个log category设为<literal>debug</literal>。
+                            <para>
+                                <emphasis role="strong">eg.</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.format_sql</literal>
+                        </entry>
+                        <entry>
+                            在log和console中打印出更漂亮的SQL。
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_schema</literal>
+                        </entry>
+                        <entry>
+                            在生成的SQL中, 将给定的schema/tablespace附加于非全限定名的表名上.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>SCHEMA_NAME</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_catalog</literal>
+                        </entry>
+                        <entry>
+                            在生成的SQL中, 将给定的catalog附加于非全限定名的表名上.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>CATALOG_NAME</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.session_factory_name</literal>
+                        </entry>
+                        <entry>
+                            <literal>SessionFactory</literal>创建后,将自动使用这个名字绑定到JNDI中.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>jndi/composite/name</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.max_fetch_depth</literal>
+                        </entry>
+                        <entry>
+                            为单向关联(一对一, 多对一)的外连接抓取(outer join fetch)树设置最大深度.
+                            值为<literal>0</literal>意味着将关闭默认的外连接抓取.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                建议在<literal>0</literal>到<literal>3</literal>之间取值
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_batch_fetch_size</literal>
+                        </entry>
+                        <entry>
+                            为Hibernate关联的批量抓取设置默认数量.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                建议的取值为<literal>4</literal>, <literal>8</literal>, 
+                                和<literal>16</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.default_entity_mode</literal>
+                        </entry>
+                        <entry>
+                            为由这个<literal>SessionFactory</literal>打开的所有Session指定默认的实体表现模式.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>dynamic-map</literal>, <literal>dom4j</literal>,
+                                <literal>pojo</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.order_updates</literal>
+                        </entry>
+                        <entry>
+                            强制Hibernate按照被更新数据的主键,为SQL更新排序。这么做将减少在高并发系统中事务的死锁。
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.generate_statistics</literal>
+                        </entry>
+                        <entry>
+                            如果开启, Hibernate将收集有助于性能调节的统计数据.
+                            <para>
+                                <emphasis role="strong">取值</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.use_identifer_rollback</literal>
+                        </entry>
+                        <entry>
+                            如果开启, 在对象被删除时生成的标识属性将被重设为默认值.
+                            <para>
+                                <emphasis role="strong">取值</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.use_sql_comments</literal>
+                        </entry>
+                        <entry>
+                            如果开启, Hibernate将在SQL中生成有助于调试的注释信息, 默认值为<literal>false</literal>.
+                            <para>
+                                <emphasis role="strong">取值</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-jdbc-properties" revision="8">
+            <title>
+                Hibernate JDBC和连接(connection)属性
+            </title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>
+                            属性名
+                        </entry>
+                        <entry>
+                            用途
+                        </entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.fetch_size</literal>
+                        </entry>
+                        <entry>
+                            非零值,指定JDBC抓取数量的大小 (调用<literal>Statement.setFetchSize()</literal>).
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.batch_size</literal>
+                        </entry>
+                        <entry>
+                            非零值,允许Hibernate使用JDBC2的批量更新.
+                            <para>
+                                <emphasis role="strong">取值</emphasis>
+                                建议取<literal>5</literal>到<literal>30</literal>之间的值
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.batch_versioned_data</literal>
+                        </entry>
+                        <entry>
+                            如果你想让你的JDBC驱动从<literal>executeBatch()</literal>返回正确的行计数 , 
+                            那么将此属性设为<literal>true</literal>(开启这个选项通常是安全的). 
+                            同时,Hibernate将为自动版本化的数据使用批量DML. 默认值为<literal>false</literal>.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.factory_class</literal>
+                        </entry>
+                        <entry>
+                            选择一个自定义的<literal>Batcher</literal>. 多数应用程序不需要这个配置属性.
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>classname.of.Batcher</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_scrollable_resultset</literal>
+                        </entry>
+                        <entry>
+                            允许Hibernate使用JDBC2的可滚动结果集.
+                            只有在使用用户提供的JDBC连接时,这个选项才是必要的, 
+                            否则Hibernate会使用连接的元数据.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_streams_for_binary</literal>
+                        </entry>
+                        <entry>
+                            在JDBC读写<literal>binary (二进制)</literal>或<literal>serializable (可序列化)</literal>
+                            的类型时使用流(stream)(系统级属性).
+                            <para>
+                                <emphasis role="strong">取值</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jdbc.use_get_generated_keys</literal>
+                        </entry>
+                        <entry>
+                            在数据插入数据库之后,允许使用JDBC3 <literal>PreparedStatement.getGeneratedKeys()</literal>
+                            来获取数据库生成的key(键)。需要JDBC3+驱动和JRE1.4+, 如果你的数据库驱动在使用Hibernate的标
+                            识生成器时遇到问题,请将此值设为false. 默认情况下将使用连接的元数据来判定驱动的能力.
+                            <para>
+                                <emphasis role="strong">取值</emphasis>
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.provider_class</literal>
+                        </entry>
+                        <entry>
+                            自定义<literal>ConnectionProvider</literal>的类名, 此类用来向Hibernate提供JDBC连接.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>classname.of.ConnectionProvider</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                    <entry>
+                        <literal>hibernate.connection.isolation</literal>
+                    </entry>
+                    <entry>
+                        设置JDBC事务隔离级别. 查看<literal>java.sql.Connection</literal>来了解各个值的具体意义, 
+                        但请注意多数数据库都不支持所有的隔离级别.
+                        <para>
+                            <emphasis role="strong">取值</emphasis> 
+                            <literal>1, 2, 4, 8</literal>
+                        </para>
+                    </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.autocommit</literal>
+                        </entry>
+                        <entry>
+                            允许被缓存的JDBC连接开启自动提交(autocommit) (不建议).
+                            <para>
+                                <emphasis role="strong">取值</emphasis>
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.connection.release_mode</literal>
+                        </entry>
+                        <entry>
+                            指定Hibernate在何时释放JDBC连接. 默认情况下,直到Session被显式关闭或被断开连接时,才会释放JDBC连接. 
+                            对于应用程序服务器的JTA数据源, 你应当使用<literal>after_statement</literal>, 这样在每次JDBC调用后,都会主动的释放连接. 
+                            对于非JTA的连接, 使用<literal>after_transaction</literal>在每个事务结束时释放连接是合理的. 
+                            <literal>auto</literal>将为JTA和CMT事务策略选择<literal>after_statement</literal>, 
+                            为JDBC事务策略选择<literal>after_transaction</literal>.
+                            <para>
+                                <emphasis role="strong">取值</emphasis>
+                                <literal>auto</literal> (默认) | <literal>on_close</literal> |
+                                <literal>after_transaction</literal> | <literal>after_statement</literal>
+                            </para>
+                            <para>
+
+                                注意,这些设置仅对通过<literal>SessionFactory.openSession</literal>得到的<literal>Session</literal>起作用。对于通过<literal>SessionFactory.getCurrentSession</literal>得到的<literal>Session</literal>,所配置的<literal>CurrentSessionContext</literal>实现控制这些<literal>Session</literal>的连接释放模式。请参阅<xref linkend="architecture-current-session"/>。
+                            </para>
+
+
+  	                    </entry>
+  	                </row>
+  	                <row>
+  	                    <entry>
+                            <literal>hibernate.connection.<emphasis>&lt;propertyName&gt;</emphasis></literal>
+                        </entry>
+                        <entry>
+                            将JDBC属性<literal>propertyName</literal>传递到<literal>DriverManager.getConnection()</literal>中去.
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.jndi.<emphasis>&lt;propertyName&gt;</emphasis></literal>
+                        </entry>
+                        <entry>
+                            将属性<literal>propertyName</literal>传递到JNDI <literal>InitialContextFactory</literal>中去.
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-cache-properties" revision="7">
+            <title>
+                Hibernate缓存属性
+            </title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>
+                            属性名
+                        </entry>
+                        <entry>
+                            用途
+                        </entry>
+                    </row>
+                </thead>
+                <tbody>
+                     <row>
+                        <entry>
+                            <literal>hibernate.cache.provider_class</literal>
+                        </entry>
+                        <entry>
+                            自定义的<literal>CacheProvider</literal>的类名.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>classname.of.CacheProvider</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_minimal_puts</literal>
+                        </entry>
+                        <entry>
+                            以频繁的读操作为代价, 优化二级缓存来最小化写操作. 在Hibernate3中,这个设置对的集群缓存非常有用, 
+                            对集群缓存的实现而言,默认是开启的.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_query_cache</literal>
+                        </entry>
+                        <entry>
+                            允许查询缓存, 个别查询仍然需要被设置为可缓存的.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_second_level_cache</literal>
+                        </entry>
+                        <entry>
+                            能用来完全禁止使用二级缓存. 对那些在类的映射定义中指定<literal>&lt;cache&gt;</literal>的类,会默认开启二级缓存.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.query_cache_factory</literal>
+                        </entry>
+                        <entry>
+                            自定义实现<literal>QueryCache</literal>接口的类名,
+                            默认为内建的<literal>StandardQueryCache</literal>.
+                            <para>
+                                <emphasis role="strong">取值</emphasis>
+                                <literal>classname.of.QueryCache</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.region_prefix</literal>
+                        </entry>
+                        <entry>
+                            二级缓存区域名的前缀.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>prefix</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cache.use_structured_entries</literal>
+                        </entry>
+                        <entry>
+                            强制Hibernate以更人性化的格式将数据存入二级缓存.
+                            <para>
+                                <emphasis role="strong">取值</emphasis>
+                                <literal>true|false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-transaction-properties" revision="9">
+            <title>
+                Hibernate事务属性
+            </title>
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>
+                            属性名
+                        </entry>
+                        <entry>
+                            用途
+                        </entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.factory_class</literal>
+                        </entry>
+                        <entry>
+                            一个<literal>TransactionFactory</literal>的类名, 用于Hibernate <literal>Transaction</literal> API
+                            (默认为<literal>JDBCTransactionFactory</literal>).
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>classname.of.TransactionFactory</literal>
+                            </para>                            
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>jta.UserTransaction</literal>
+                        </entry>
+                        <entry>
+                            一个JNDI名字,被<literal>JTATransactionFactory</literal>用来从应用服务器获取JTA <literal>UserTransaction</literal>.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>jndi/composite/name</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.manager_lookup_class</literal>
+                        </entry>
+                        <entry>
+                            一个<literal>TransactionManagerLookup</literal>的类名
+                            - 当使用JVM级缓存,或在JTA环境中使用hilo生成器的时候需要该类.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>classname.of.TransactionManagerLookup</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.flush_before_completion</literal>
+                        </entry>
+                        <entry>
+                            如果开启, session在事务完成后将被自动清洗(flush)。 现在更好的方法是使用自动session上下文管理。请参见<xref linkend="architecture-current-session"/>。
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.transaction.auto_close_session</literal>
+                        </entry>
+                        <entry>
+                            如果开启, session在事务完成后将被自动关闭。 现在更好的方法是使用自动session上下文管理。请参见<xref linkend="architecture-current-session"/>。
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <table frame="topbot" id="configuration-misc-properties" revision="10">
+            <title>
+                其他属性
+            </title>
+
+            <tgroup cols="2">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="1*"/>
+                <thead>
+                    <row>
+                        <entry>
+                            属性名
+                            </entry>
+                        <entry>
+                            用途
+                        </entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            <literal>hibernate.current_session_context_class</literal>
+                        </entry>
+                        <entry>
+                            为"当前"
+                            <literal>Session</literal>指定一个(自定义的)策略。关于内置策略的详情,请参见<xref linkend="architecture-current-session"/> 。
+                            <para>
+                                <emphasis role="strong">eg.</emphasis>
+                                <literal>jta</literal> | <literal>thread</literal> |
+                                <literal>managed</literal> | <literal>custom.Class</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.query.factory_class</literal>
+                        </entry>
+                        <entry>
+                            选择HQL解析器的实现.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> or
+                                <literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.query.substitutions</literal>
+                        </entry>
+                        <entry>
+                            将Hibernate查询中的符号映射到SQL查询中的符号
+                            (符号可能是函数名或常量名字).
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.hbm2ddl.auto</literal>
+                        </entry>
+                        <entry>
+                            在<literal>SessionFactory</literal>创建时,自动检查数据库结构,或者将数据库schema的DDL导出到数据库. 使用
+                            <literal>create-drop</literal>时,在显式关闭<literal>SessionFactory</literal>时,将drop掉数据库schema.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>validate</literal> | <literal>update</literal> | 
+                                <literal>create</literal> | <literal>create-drop</literal>
+                            </para>
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            <literal>hibernate.cglib.use_reflection_optimizer</literal>
+                        </entry>
+                        <entry>
+                            开启CGLIB来替代运行时反射机制(系统级属性). 反射机制有时在除错时比较有用. 
+                            注意即使关闭这个优化, Hibernate还是需要CGLIB. 你不能在<literal>hibernate.cfg.xml</literal>中设置此属性.
+                            <para>
+                                <emphasis role="strong">取值</emphasis> 
+                                <literal>true</literal> | <literal>false</literal>
+                            </para>
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <sect2 id="configuration-optional-dialects" revision="1">
+            <title>
+                SQL方言
+            </title>
+
+            <para>
+                你应当总是为你的数据库将<literal>hibernate.dialect</literal>属性设置成正确的
+                <literal>org.hibernate.dialect.Dialect</literal>子类. 如果你指定一种方言, 
+                Hibernate将为上面列出的一些属性使用合理的默认值, 为你省去了手工指定它们的功夫.
+            </para>
+
+            <table frame="topbot" id="sql-dialects" revision="2">
+                <title>
+                    Hibernate SQL方言 (<literal>hibernate.dialect</literal>)
+                </title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>RDBMS</entry>
+                            <entry>
+                                方言
+                            </entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry>DB2</entry> <entry><literal>org.hibernate.dialect.DB2Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>DB2 AS/400</entry> <entry><literal>org.hibernate.dialect.DB2400Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>DB2 OS390</entry> <entry><literal>org.hibernate.dialect.DB2390Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>PostgreSQL</entry> <entry><literal>org.hibernate.dialect.PostgreSQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL</entry> <entry><literal>org.hibernate.dialect.MySQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL with InnoDB</entry> <entry><literal>org.hibernate.dialect.MySQLInnoDBDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>MySQL with MyISAM</entry> <entry><literal>org.hibernate.dialect.MySQLMyISAMDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Oracle (any version)</entry> <entry><literal>org.hibernate.dialect.OracleDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Oracle 9i/10g</entry> <entry><literal>org.hibernate.dialect.Oracle9Dialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Sybase</entry> <entry><literal>org.hibernate.dialect.SybaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Sybase Anywhere</entry> <entry><literal>org.hibernate.dialect.SybaseAnywhereDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Microsoft SQL Server</entry> <entry><literal>org.hibernate.dialect.SQLServerDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>SAP DB</entry> <entry><literal>org.hibernate.dialect.SAPDBDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Informix</entry> <entry><literal>org.hibernate.dialect.InformixDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>HypersonicSQL</entry> <entry><literal>org.hibernate.dialect.HSQLDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Ingres</entry> <entry><literal>org.hibernate.dialect.IngresDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Progress</entry> <entry><literal>org.hibernate.dialect.ProgressDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Mckoi SQL</entry> <entry><literal>org.hibernate.dialect.MckoiDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Interbase</entry> <entry><literal>org.hibernate.dialect.InterbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Pointbase</entry> <entry><literal>org.hibernate.dialect.PointbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>FrontBase</entry> <entry><literal>org.hibernate.dialect.FrontbaseDialect</literal></entry>
+                        </row>
+                        <row>
+                            <entry>Firebird</entry> <entry><literal>org.hibernate.dialect.FirebirdDialect</literal></entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-outerjoin" revision="4">
+            <title>
+                外连接抓取(Outer Join Fetching)
+            </title>
+
+            <para>
+                如果你的数据库支持ANSI, Oracle或Sybase风格的外连接, <emphasis>外连接抓取</emphasis>通常能通过限制往返数据库次数
+                (更多的工作交由数据库自己来完成)来提高效率. 外连接抓取允许在单个<literal>SELECT</literal>SQL语句中,
+                通过many-to-one, one-to-many, many-to-many和one-to-one关联获取连接对象的整个对象图.
+            </para>
+
+            <para>
+                将<literal>hibernate.max_fetch_depth</literal>设为<literal>0</literal>能在<emphasis>全局</emphasis>
+                范围内禁止外连接抓取. 设为<literal>1</literal>或更高值能启用one-to-one和many-to-oneouter关联的外连接抓取, 它们通过
+                <literal>fetch="join"</literal>来映射.
+            </para>
+
+            <para>
+                参见<xref linkend="performance-fetching"/>获得更多信息.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-binarystreams" revision="1">
+            <title>
+                二进制流 (Binary Streams)
+            </title>
+
+            <para>
+                Oracle限制那些通过JDBC驱动传输的<literal>字节</literal>数组的数目. 如果你希望使用<literal>二进值 (binary)</literal>或
+                <literal>可序列化的 (serializable)</literal>类型的大对象, 你应该开启
+                <literal>hibernate.jdbc.use_streams_for_binary</literal>属性.
+                <emphasis>这是系统级属性.</emphasis>
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-cacheprovider" revision="2">
+            <title>
+                二级缓存与查询缓存
+            </title>
+
+            <para>
+                以<literal>hibernate.cache</literal>为前缀的属性允许你在Hibernate中,使用进程或群集范围内的二级缓存系统.
+                参见<xref linkend="performance-cache"/>获取更多的详情.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-querysubstitution">
+            <title>
+                查询语言中的替换
+            </title>
+
+            <para>
+                你可以使用<literal>hibernate.query.substitutions</literal>在Hibernate中定义新的查询符号.
+                例如:         
+            </para>
+
+            <programlisting>hibernate.query.substitutions true=1, false=0</programlisting>
+
+            <para>
+                将导致符号<literal>true</literal>和<literal>false</literal>在生成的SQL中被翻译成整数常量.
+            </para>
+
+            <programlisting>hibernate.query.substitutions toLowercase=LOWER</programlisting>
+
+            <para>
+                将允许你重命名SQL中的<literal>LOWER</literal>函数.
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-statistics" revision="2">
+            <title>
+                Hibernate的统计(statistics)机制
+            </title>
+
+            <para>
+                如果你开启<literal>hibernate.generate_statistics</literal>, 那么当你通过
+                <literal>SessionFactory.getStatistics()</literal>调整正在运行的系统时,Hibernate将导出大量有用的数据.
+                Hibernate甚至能被配置成通过JMX导出这些统计信息. 参考<literal>org.hibernate.stats</literal>中接口的Javadoc,以获得更多信息.
+            </para>
+
+        </sect2>
+    </sect1>
+
+    <sect1 id="configuration-logging">
+        <title>
+            日志
+        </title>
+
+        <para>
+            Hibernate使用Apache commons-logging来为各种事件记录日志.
+        </para>
+
+        <para>
+            commons-logging将直接输出到Apache Log4j(如果在类路径中包括<literal>log4j.jar</literal>)或
+            JDK1.4 logging (如果运行在JDK1.4或以上的环境下). 你可以从<literal>http://jakarta.apache.org</literal>
+                下载Log4j. 要使用Log4j,你需要将<literal>log4j.properties</literal>文件放置在类路径下, 随Hibernate
+                一同分发的样例属性文件在<literal>src/</literal>目录下.
+        </para>
+        
+        <para>
+            我们强烈建议你熟悉一下Hibernate的日志消息. 在不失可读性的前提下,
+            我们做了很多工作,使Hibernate的日志可能地详细. 这是必要的查错利器.
+             最令人感兴趣的日志分类有如下这些:
+        </para>
+        
+            <table frame="topbot" id="log-categories" revision="2">
+                <title>
+                    Hibernate日志类别
+                </title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>
+                                类别
+                            </entry>
+                            <entry>
+                                功能
+                            </entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>org.hibernate.SQL</literal></entry>
+                            <entry>
+                                在所有SQL DML语句被执行时为它们记录日志
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.type</literal></entry>
+                            <entry>
+                                为所有JDBC参数记录日志
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.tool.hbm2ddl</literal></entry>
+                            <entry>
+                                在所有SQL DDL语句执行时为它们记录日志
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.pretty</literal></entry>
+                            <entry>
+                                在session清洗(flush)时,为所有与其关联的实体(最多20个)的状态记录日志
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.cache</literal></entry>
+                            <entry>
+                                为所有二级缓存的活动记录日志
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction</literal></entry>
+                            <entry>
+                                为事务相关的活动记录日志
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.jdbc</literal></entry>
+                            <entry>
+                                为所有JDBC资源的获取记录日志
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.hql.AST</literal></entry>
+                            <entry>
+                                在解析查询的时候,记录HQL和SQL的AST分析日志
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.secure</literal></entry>
+                            <entry>
+                                为JAAS认证请求做日志
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate</literal></entry>
+                            <entry>
+                                为任何Hibernate相关信息做日志 (信息量较大, 但对查错非常有帮助)
+                            </entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+            
+        <para>
+            在使用Hibernate开发应用程序时, 你应当总是为<literal>org.hibernate.SQL</literal>
+            开启<literal>debug</literal>级别的日志记录,或者开启<literal>hibernate.show_sql</literal>属性。
+        </para>        
+        
+    </sect1>
+
+    <sect1 id="configuration-namingstrategy">
+        <title>
+            实现<literal>NamingStrategy</literal>
+        </title>
+
+        <para>
+            <literal>org.hibernate.cfg.NamingStrategy</literal>接口允许你为数据库中的对象和schema
+            元素指定一个“命名标准”.
+        </para>
+
+        <para>
+            你可能会提供一些通过Java标识生成数据库标识或将映射定义文件中"逻辑"表/列名处理成"物理"表/列名的规则.
+            这个特性有助于减少冗长的映射定义文件.
+        </para>
+
+        <para>
+            在加入映射定义前,你可以调用
+            <literal>Configuration.setNamingStrategy()</literal>指定一个不同的命名策略:
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sf = new Configuration()
+    .setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
+    .addFile("Item.hbm.xml")
+    .addFile("Bid.hbm.xml")
+    .buildSessionFactory();]]></programlisting>
+    
+        <para>
+            <literal>org.hibernate.cfg.ImprovedNamingStrategy</literal>是一个内建的命名策略, 对
+            一些应用程序而言,可能是非常有用的起点.
+        </para>
+
+    </sect1>
+
+    <sect1 id="configuration-xmlconfig" revision="2">
+        <title>
+            XML配置文件
+        </title>
+
+        <para>
+            另一个配置方法是在<literal>hibernate.cfg.xml</literal>文件中指定一套完整的配置. 
+            这个文件可以当成<literal>hibernate.properties</literal>的替代。 若两个文件同时存在,它将覆盖前者的属性.
+        </para>
+
+        <para>
+            XML配置文件被默认是放在<literal>CLASSPATH</literal>的根目录下. 这是一个例子:
+        </para>
+		<para>
+            
+        </para>
+
+        <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+    "-//Hibernate/Hibernate Configuration DTD//EN"
+    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <!-- 以/jndi/name绑定到JNDI的SessionFactory实例 -->
+    <session-factory
+        name="java:hibernate/SessionFactory">
+
+        <!-- 属性 -->
+        <property name="connection.datasource">java:/comp/env/jdbc/MyDB</property>
+        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
+        <property name="show_sql">false</property>
+        <property name="transaction.factory_class">
+            org.hibernate.transaction.JTATransactionFactory
+        </property>
+        <property name="jta.UserTransaction">java:comp/UserTransaction</property>
+
+        <!-- 映射定义文件 -->
+        <mapping resource="org/hibernate/auction/Item.hbm.xml"/>
+        <mapping resource="org/hibernate/auction/Bid.hbm.xml"/>
+
+        <!-- 缓存设置 -->
+        <class-cache class="org.hibernate.auction.Item" usage="read-write"/>
+        <class-cache class="org.hibernate.auction.Bid" usage="read-only"/>
+        <collection-cache collection="org.hibernate.auction.Item.bids" usage="read-write"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+            如你所见, 这个方法优势在于,在配置文件中指出了映射定义文件的名字. 一旦你需要调整Hibernate的缓存,
+            <literal>hibernate.cfg.xml</literal>也是更方便. 注意,使用<literal>hibernate.properties</literal>还是
+            <literal>hibernate.cfg.xml</literal>完全是由你来决定, 除了上面提到的XML语法的优势之外, 两者是等价的.
+        </para>
+		
+        <para>
+            使用XML配置,使得启动Hibernate变的异常简单, 如下所示,一行代码就可以搞定:
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sf = new Configuration().configure().buildSessionFactory();]]></programlisting>
+
+        <para>
+            你可以使用如下代码来添加一个不同的XML配置文件
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sf = new Configuration()
+    .configure("catdb.cfg.xml")
+    .buildSessionFactory();]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="configuration-j2ee" revision="1">
+        <title>
+            J2EE应用程序服务器的集成
+        </title>
+
+        <para>
+            针对J2EE体系,Hibernate有如下几个集成的方面:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>容器管理的数据源(Container-managed datasources)</emphasis>: 
+                Hibernate能使用通过容器管理,并由JNDI提供的JDBC连接. 通常, 特别是当处理多个数据源的分布式事务的时候, 
+                由一个JTA兼容的<literal>TransactionManager</literal>和一个
+                <literal>ResourceManager</literal>来处理事务管理(CMT, 容器管理的事务). 当然你可以通过
+                编程方式来划分事务边界(BMT, Bean管理的事务). 或者为了代码的可移植性,你也也许会想使用可选的
+                Hibernate <literal>Transaction</literal> API.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>自动JNDI绑定</emphasis>: Hibernate可以在启动后将
+                <literal>SessionFactory</literal>绑定到JNDI.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>JTA Session绑定:</emphasis> Hibernate <literal>Session</literal>
+                可以自动绑定到JTA事务作用的范围. 只需简单地从JNDI查找<literal>SessionFactory</literal>并获得当前的
+                <literal>Session</literal>. 当JTA事务完成时, 让Hibernate来处理
+                <literal>Session</literal>的清洗(flush)与关闭. 事务的划分可以是声明式的(CMT),也可以是编程式的(BMT/UserTransaction).
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                <emphasis>JMX部署:</emphasis> 如果你使用支持JMX应用程序服务器(如, JBoss AS), 那么你可以选择将Hibernate部署成托管MBean. 
+                这将为你省去一行从<literal>Configuration</literal>构建<literal>SessionFactory</literal>的启动代码. 
+                容器将启动你的<literal>HibernateService</literal>, 并完美地处理好服务间的依赖关系 (在Hibernate启动前,数据源必须是可用的,等等).
+                </para>
+            </listitem>
+        </itemizedlist>
+        <para>
+            如果应用程序服务器抛出"connection containment"异常, 根据你的环境,也许该将配置属性
+            <literal>hibernate.connection.release_mode</literal>设为<literal>after_statement</literal>.
+        </para>
+        <sect2 id="configuration-optional-transactionstrategy" revision="3">
+            <title>
+                事务策略配置
+            </title>
+
+            <para>
+                在你的架构中,Hibernate的<literal>Session</literal> API是独立于任何事务分界系统的. 
+                如果你让Hibernate通过连接池直接使用JDBC, 你需要调用JDBC API来打开和关闭你的事务. 
+                如果你运行在J2EE应用程序服务器中, 你也许想用Bean管理的事务并在需要的时候调用JTA API和<literal>UserTransaction</literal>.
+            </para>
+
+            <para>
+                为了让你的代码在两种(或其他)环境中可以移植,我们建议使用可选的Hibernate <literal>Transaction</literal> API, 
+                它包装并隐藏了底层系统. 你必须通过设置Hibernate配置属性<literal>hibernate.transaction.factory_class</literal>来指定
+                一个<literal>Transaction</literal>实例的工厂类.
+            </para>
+
+            <para>
+                有三个标准(内建)的选择:
+            </para>
+
+            <variablelist spacing="compact">
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.JDBCTransactionFactory</literal></term>
+                    <listitem>
+                        <para>
+                            委托给数据库(JDBC)事务(默认)
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.JTATransactionFactory</literal></term>
+                    <listitem>
+                        <para>
+                            如果在上下文环境中存在运行着的事务(如, EJB会话Bean的方法), 则委托给容器管
+                            理的事务, 否则,将启动一个新的事务,并使用Bean管理的事务.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term><literal>org.hibernate.transaction.CMTTransactionFactory</literal></term>
+                    <listitem>
+                        <para>
+                            委托给容器管理的JTA事务
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+            <para>
+                你也可以定义属于你自己的事务策略 (如, 针对CORBA的事务服务)
+            </para>
+
+            <para>
+                Hibernate的一些特性 (比如二级缓存, Contextual Sessions with JTA等等)需要访问在托管环境中的JTA <literal>TransactionManager</literal>. 
+                由于J2EE没有标准化一个单一的机制,Hibernate在应用程序服务器中,你必须指定Hibernate如何获得<literal>TransactionManager</literal>的引用:
+            </para>
+
+            <table frame="topbot" id="jtamanagerlookup" revision="1">
+                <title>JTA TransactionManagers</title>
+                <tgroup cols="2">
+                    <colspec colwidth="2.5*"/>
+                    <colspec colwidth="1*"/>
+                    <thead>
+                        <row>
+                            <entry>
+                                Transaction工厂类
+                            </entry>
+                            <entry align="center">
+                                应用程序服务器
+                            </entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JBossTransactionManagerLookup</literal></entry>
+                            <entry align="center">JBoss</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WeblogicTransactionManagerLookup</literal></entry>
+                            <entry align="center">Weblogic</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WebSphereTransactionManagerLookup</literal></entry>
+                            <entry align="center">WebSphere</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</literal></entry>
+                            <entry align="center">WebSphere 6</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.OrionTransactionManagerLookup</literal></entry>
+                            <entry align="center">Orion</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.ResinTransactionManagerLookup</literal></entry>
+                            <entry align="center">Resin</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JOTMTransactionManagerLookup</literal></entry>
+                            <entry align="center">JOTM</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JOnASTransactionManagerLookup</literal></entry>
+                            <entry align="center">JOnAS</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.JRun4TransactionManagerLookup</literal></entry>
+                            <entry align="center">JRun4</entry>
+                        </row>
+                        <row>
+                            <entry><literal>org.hibernate.transaction.BESTransactionManagerLookup</literal></entry>
+                            <entry align="center">Borland ES</entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="configuration-optional-jndi" revision="3">
+            <title>
+                JNDI绑定的<literal>SessionFactory</literal>
+            </title>
+
+
+            <para>
+                与JNDI绑定的Hibernate的<literal>SessionFactory</literal>能简化工厂的查询,简化创建新的<literal>Session</literal>. 
+                需要注意的是这与JNDI绑定<literal>Datasource</literal>没有关系, 它们只是恰巧用了相同的注册表!
+            </para>
+
+            <para>
+                如果你希望将<literal>SessionFactory</literal>绑定到一个JNDI的名字空间, 
+                用属性<literal>hibernate.session_factory_name</literal>指定一个名字(如, <literal>java:hibernate/SessionFactory</literal>). 
+                如果不设置这个属性, <literal>SessionFactory</literal>将不会被绑定到JNDI中. (在以只读JNDI为默认实现的环境中,这个设置尤其有用, 如Tomcat.)
+            </para>
+
+            <para>
+                在将<literal>SessionFactory</literal>绑定至JNDI时, Hibernate将使用<literal>hibernate.jndi.url</literal>, 
+                和<literal>hibernate.jndi.class</literal>的值来实例化初始环境(initial context). 
+                如果它们没有被指定, 将使用默认的<literal>InitialContext</literal>.
+            </para>
+
+            <para>
+                在你调用<literal>cfg.buildSessionFactory()</literal>后, Hibernate会自动将<literal>SessionFactory</literal>注册到JNDI.
+                这意味这你至少需要在你应用程序的启动代码(或工具类)中完成这个调用, 除非你使用<literal>HibernateService</literal>来做JMX部署 (见后面讨论).
+            </para>
+
+            <para>
+                假若你使用JNDI <literal>SessionFactory</literal>,EJB或者任何其它类都可以从JNDI中找到此<literal>SessionFactory</literal>。
+            </para>
+
+            <para>
+                我们建议,在受管理的环境中,把<literal>SessionFactory</literal>绑定到JNDI,在其它情况下,使用一个<literal>static(静态的)</literal>singleton。为了在你的应用程序代码中隐藏这些细节,我们还建议你用一个helper类把实际查找<literal>SessionFactory</literal>的代码隐藏起来,比如<literal>HibernateUtil.getSessionFactory()</literal>。注意,这个类也就可以方便地启动Hibernate,参见第一章。
+            </para>
+
+        </sect2>
+
+        <sect2 id="configuration-j2ee-currentsession" revision="4">
+            <title>在JTA环境下使用Current Session context (当前session上下文)管理</title>
+
+            <para>
+	            在Hibernate中,管理<literal>Session</literal>å’Œtransaction最好的方法是自动的"当前"<literal>Session</literal>管理。请参见<xref linkend="architecture-current-session">contextual sessions</xref>一节的讨论。使用<literal>"jta"</literal>session上下文,假若在当前JTA事务中还没有Hibernate<literal>Session</literal>关联,第一次<literal>sessionFactory.getCurrentSession()</literal>调用会启动一个Session,并关联到当前的JTA事务。在<literal>"jta"</literal>上下文中调用<literal>getCurrentSession()</literal>获得的<literal>Session</literal>,会被设置为在transaction关闭的时候自动flush(清洗)、在transaction关闭之后自动关闭,每句语句之后主动释放JDBC连接。这就可以根据JTA事务的生命周期来管理与之关联的<literal>Session</literal>,用户代码中就可以不再考虑这些管理。你的代码也可以通过<literal>UserTransaction</literal>用编ç¨!
 ‹æ–¹å¼ä½¿ç”¨JTA,或者(我们建议,为了便于移植代码)使用Hibernateçš„<literal>Transaction</literal> API来设置transaction边界。如果你的代码运行在EJB容器中,建议对CMT使用声明式事务声明。
+	            
+            </para>
+        </sect2>
+        <sect2 id="configuration-j2ee-jmx" revision="1">
+            <title>
+                JMX部署
+            </title>
+
+            <para>
+                为了将<literal>SessionFactory</literal>注册到JNDI中,<literal>cfg.buildSessionFactory()</literal>这行代码仍需在某处被执行.
+                你可在一个<literal>static</literal>初始化块(像<literal>HibernateUtil</literal>中的那样)中执行它或将Hibernate部署为一个<emphasis>托管的服务</emphasis>.
+            </para>
+
+            <para>
+                为了部署在一个支持JMX的应用程序服务器上,Hibernate和
+                <literal>org.hibernate.jmx.HibernateService</literal>一同分发,如Jboss AS。
+                实际的部署和配置是由应用程序服务器提供者指定的. 这里是JBoss 4.0.x的<literal>jboss-service.xml</literal>样例:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<server>
+
+<mbean code="org.hibernate.jmx.HibernateService"
+    name="jboss.jca:service=HibernateFactory,name=HibernateFactory">
+
+    <!-- 必须的服务 -->
+    <depends>jboss.jca:service=RARDeployer</depends>
+    <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends>
+
+    <!-- 将Hibernate服务绑定到JNDI -->
+    <attribute name="JndiName">java:/hibernate/SessionFactory</attribute>
+
+    <!-- 数据源设置 -->
+    <attribute name="Datasource">java:HsqlDS</attribute>
+    <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>
+
+    <!-- 事务集成 -->
+    <attribute name="TransactionStrategy">
+        org.hibernate.transaction.JTATransactionFactory</attribute>
+    <attribute name="TransactionManagerLookupStrategy">
+        org.hibernate.transaction.JBossTransactionManagerLookup</attribute>
+    <attribute name="FlushBeforeCompletionEnabled">true</attribute>
+    <attribute name="AutoCloseSessionEnabled">true</attribute>
+
+    <!-- 抓取选项 -->
+    <attribute name="MaximumFetchDepth">5</attribute>
+
+    <!-- 二级缓存 -->
+    <attribute name="SecondLevelCacheEnabled">true</attribute>
+    <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute>
+    <attribute name="QueryCacheEnabled">true</attribute>
+
+    <!-- 日志 -->
+    <attribute name="ShowSqlEnabled">true</attribute>
+
+    <!-- 映射定义文件 -->
+    <attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute>
+
+</mbean>
+
+</server>]]></programlisting>
+
+            <para>
+                这个文件是部署在<literal>META-INF</literal>目录下的, 并会被打包到以<literal>.sar</literal> (service archive)为扩展名的JAR文件中.
+                同时,你需要将Hibernate、它所需要的第三方库、你编译好的持久化类以及你的映射定义文件打包进同一个文档. 
+                你的企业Bean(一般为会话Bean)可能会被打包成它们自己的JAR文件, 但你也许会将EJB JAR文件一同包含进能独立(热)部署的主服务文档.
+                参考JBoss AS文档以了解更多的JMX服务与EJB部署的信息.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/events.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/events.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/events.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,247 @@
+<chapter id="events">
+    <title>
+	拦截器与事件(Interceptors and events)
+	</title>
+
+    <para>
+	    应用程序能够响应Hibernate内部产生的特定事件是非常有用的。这样就允许实现某些通用的功能
+		以及允许对Hibernate功能进行扩展。
+    </para>
+
+    <sect1 id="objectstate-interceptors" revision="3">
+        <title>
+		拦截器(Interceptors)
+		</title>
+
+        <para>
+            <literal>Interceptor</literal>接口提供了从会话(session)回调(callback)应用程序(application)的机制,
+                        这种回调机制可以允许应用程序在持久化对象被保存、更新、删除或是加载之前,检查并(或)修改其
+			属性。一个可能的用途,就是用来跟踪审核(auditing)信息。例如:下面的这个<literal>拦截器</literal>,会在一个实现了
+			<literal>Auditable</literal>接口的对象被创建时自动地设置<literal>createTimestamp</literal>属性,并在实现了
+			<literal>Auditable</literal>接口的对象被更新时,同步更新<literal>lastUpdateTimestamp</literal>属性。
+        </para>
+
+        <para>
+            你可以直接实现<literal>Interceptor</literal>接口,也可以(最好)继承自<literal>EmptyInterceptor</literal>。
+        </para>
+
+        <programlisting><![CDATA[package org.hibernate.test;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.Transaction;
+import org.hibernate.type.Type;
+
+public class AuditInterceptor extends EmptyInterceptor {
+
+    private int updates;
+    private int creates;
+    private int loads;
+
+    public void onDelete(Object entity,
+                         Serializable id,
+                         Object[] state,
+                         String[] propertyNames,
+                         Type[] types) {
+        // do nothing
+    }
+
+    public boolean onFlushDirty(Object entity,
+                                Serializable id,
+                                Object[] currentState,
+                                Object[] previousState,
+                                String[] propertyNames,
+                                Type[] types) {
+
+        if ( entity instanceof Auditable ) {
+            updates++;
+            for ( int i=0; i < propertyNames.length; i++ ) {
+                if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
+                    currentState[i] = new Date();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean onLoad(Object entity,
+                          Serializable id,
+                          Object[] state,
+                          String[] propertyNames,
+                          Type[] types) {
+        if ( entity instanceof Auditable ) {
+            loads++;
+        }
+        return false;
+    }
+
+    public boolean onSave(Object entity,
+                          Serializable id,
+                          Object[] state,
+                          String[] propertyNames,
+                          Type[] types) {
+
+        if ( entity instanceof Auditable ) {
+            creates++;
+            for ( int i=0; i<propertyNames.length; i++ ) {
+                if ( "createTimestamp".equals( propertyNames[i] ) ) {
+                    state[i] = new Date();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void afterTransactionCompletion(Transaction tx) {
+        if ( tx.wasCommitted() ) {
+            System.out.println("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads);
+        }
+        updates=0;
+        creates=0;
+        loads=0;
+    }
+
+}]]></programlisting>
+
+
+        <para>
+            拦截器可以有两种:<literal>Session</literal>范围内的,和<literal>SessionFactory</literal>范围内的。
+        </para>
+
+        <para>
+		    当使用某个重载的SessionFactory.openSession()使用<literal>Interceptor</literal>作为参数调用打开一个session的时候,就指定了<literal>Session</literal>范围内的拦截器。
+		    
+        </para>
+
+        <programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
+
+        <para>
+		    <literal>SessionFactory</literal>范围内的拦截器要通过<literal>Configuration</literal>中注册,而这必须在创建<literal>SessionFactory</literal>之前。在这种情况下,给出的拦截器会被这个<literal>SessionFactory</literal>所打开的所有session使用了;除非session打开时明确指明了使用的拦截器。<literal>SessionFactory</literal>范围内的拦截器,必须是线程安全的,因为多个session可能并发使用这个拦截器,要因此小心不要保存与session相关的状态。
+        </para>
+    
+        <programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
+
+    </sect1>
+
+     <sect1 id="objectstate-events" revision="4">
+        <title>
+		事件系统(Event system)
+		</title>
+
+        <para>
+		    如果需要响应持久层的某些特殊事件,你也可以使用Hibernate3的事件框架。
+			该事件系统可以用来替代拦截器,也可以作为拦截器的补充来使用。
+		    
+        </para>
+
+        <para>
+                    基本上,<literal>Session</literal>接口的每个方法都有相对应的事件。比如
+			<literal>LoadEvent</literal>,<literal>FlushEvent</literal>,等等(查阅XML配置文件
+			的DTD,以及<literal>org.hibernate.event</literal>包来获得所有已定义的事件的列表)。当某个方
+			法被调用时,Hibernate <literal>Session</literal>会生成一个相对应的事件并激活所
+			有配置好的事件监听器。系统预设的监听器实现的处理过程就是被监听的方法要做的(被监听的方法所做的其实仅仅是激活监听器,
+                        “实际”的工作是由监听器完成的)。不过,你可以自由地选择实现
+			一个自己定制的监听器(比如,实现并注册用来处理处理<literal>LoadEvent</literal>的<literal>LoadEventListener</literal>接口),
+                        来负责处理所有的调用<literal>Session</literal>的<literal>load()</literal>方法的请求。
+        </para>
+
+        <para>
+		    监听器应该被看作是单例(singleton)对象,也就是说,所有同类型的事件的处理共享同一个监听器实例,因此监听器
+			不应该保存任何状态(也就是不应该使用成员变量)。
+        </para>
+
+        <para>
+                    用户定制的监听器应该实现与所要处理的事件相对应的接口,或者从一个合适的基类继承(甚至是从Hibernate自带的默认事件监听器类继承,
+                        为了方便你这样做,这些类都被声明成non-final的了)。用户定制的监听器可以通过编程使用<literal>Configuration</literal>对象
+                        来注册,也可以在Hibernate的XML格式的配置文件中进行声明(不支持在Properties格式的配置文件声明监听器)。
+                        下面是一个用户定制的加载事件(load event)的监听器:
+        </para>
+
+        <programlisting><![CDATA[public class MyLoadListener implements LoadEventListener {
+    // this is the single method defined by the LoadEventListener interface
+    public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
+            throws HibernateException {
+        if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
+            throw MySecurityException("Unauthorized access");
+        }
+    }
+}]]></programlisting>
+
+        <para>
+		    你还需要修改一处配置,来告诉Hibernate,除了默认的监听器,还要附加选定的监听器。
+        </para>
+
+<programlisting><![CDATA[<hibernate-configuration>
+    <session-factory>
+        ...
+        <event type="load">
+            <listener class="com.eg.MyLoadListener"/>
+            <listener class="org.hibernate.event.def.DefaultLoadEventListener"/>
+        </event>
+    </session-factory>
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+		    看看用另一种方式,通过编程的方式来注册它。
+        </para>
+
+        <programlisting><![CDATA[Configuration cfg = new Configuration();
+LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() };
+cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
+
+        <para>
+		    通过在XML配置文件声明而注册的监听器不能共享实例。如果在多个<literal>&lt;listener/&gt;</literal>节点中使用
+			了相同的类的名字,则每一个引用都将会产生一个独立的实例。如果你需要在多个监听器类型之间共享
+			监听器的实例,则你必须使用编程的方式来进行注册。
+        </para>
+
+        <para>
+                    为什么我们实现了特定监听器的接口,在注册的时候还要明确指出我们要注册哪个事件的监听器呢?
+                    这是因为一个类可能实现多个监听器的接口。在注册的时候明确指定要监听的事件,可以让启用或者禁用对某个事件的监听的配置工作简单些。
+        </para>
+
+    </sect1>
+    
+    <sect1 id="objectstate-decl-security"  revision="2">
+        <title>
+		Hibernate的声明式安全机制
+		</title>
+        <para>
+		    通常,Hibernate应用程序的声明式安全机制由会话外观层(session facade)所管理。
+                    现在,Hibernate3允许某些特定的行为由JACC进行许可管理,由JAAS进行授权管理。
+                    本功能是一个建立在事件框架之上的可选的功能。
+        </para>
+        
+        <para>
+		    首先,你必须要配置适当的事件监听器(event listener),来激活使用JAAS管理授权的功能。
+        </para>
+        
+        <programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
+<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
+<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
+<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
+
+        <para>
+            注意,<literal>&lt;listener type="..." class="..."/&gt;</literal>只是<literal>&lt;event type="..."&gt;&lt;listener class="..."/&gt;&lt;/event&gt;</literal>的简写,对每一个事件类型都必须严格的有一个监听器与之对应。
+        </para>
+
+        <para>
+		    接下来,仍然在<literal>hibernate.cfg.xml</literal>文件中,绑定角色的权限:
+        </para>
+        
+        <programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
+<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
+        
+        <para>
+		    这些角色的名字就是你的JACC provider所定义的角色的名字。
+        </para>
+       
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/example_mappings.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/example_mappings.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/example_mappings.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,650 @@
+<chapter id="example-mappings">
+    <title>示例:复杂映射实例</title>
+    <para>
+        本章展示了一些较为复杂的关系映射。
+    </para>
+    
+    <sect1 id="example-mappings-emp">
+        <title>Employer(雇主)/Employee(雇员)</title>
+
+        <para>
+            下面关于<literal>Employer</literal> 和 <literal>Employee</literal>的关系模型使用了一个真实的实体类
+            (<literal>Employment</literal>)来表述,这是因为对于相同的雇员和雇主可能会有多个雇佣时间段。
+            对于金额和雇员姓名,用Components建模。
+            
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/EmployerEmployee.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/EmployerEmployee.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            映射文件可能是这样:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+        
+    <class name="Employer" table="employers">
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employer_id_seq</param>
+            </generator>
+        </id>
+        <property name="name"/>
+    </class>
+
+    <class name="Employment" table="employment_periods">
+
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employment_id_seq</param>
+            </generator>
+        </id>
+        <property name="startDate" column="start_date"/>
+        <property name="endDate" column="end_date"/>
+
+        <component name="hourlyRate" class="MonetaryAmount">
+            <property name="amount">
+                <column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>
+            </property>
+            <property name="currency" length="12"/>
+        </component>
+
+        <many-to-one name="employer" column="employer_id" not-null="true"/>
+        <many-to-one name="employee" column="employee_id" not-null="true"/>
+
+    </class>
+
+    <class name="Employee" table="employees">
+        <id name="id">
+            <generator class="sequence">
+                <param name="sequence">employee_id_seq</param>
+            </generator>
+        </id>
+        <property name="taxfileNumber"/>
+        <component name="name" class="Name">
+            <property name="firstName"/>
+            <property name="initial"/>
+            <property name="lastName"/>
+        </component>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        用<literal>SchemaExport</literal>生成表结构。
+    </para>
+
+    <programlisting><![CDATA[create table employers (
+    id BIGINT not null, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+create table employment_periods (
+    id BIGINT not null,
+    hourly_rate NUMERIC(12, 2),
+    currency VARCHAR(12), 
+    employee_id BIGINT not null, 
+    employer_id BIGINT not null, 
+    end_date TIMESTAMP, 
+    start_date TIMESTAMP, 
+    primary key (id)
+)
+
+create table employees (
+    id BIGINT not null, 
+    firstName VARCHAR(255), 
+    initial CHAR(1), 
+    lastName VARCHAR(255), 
+    taxfileNumber VARCHAR(255), 
+    primary key (id)
+)
+
+alter table employment_periods 
+    add constraint employment_periodsFK0 foreign key (employer_id) references employers
+alter table employment_periods 
+    add constraint employment_periodsFK1 foreign key (employee_id) references employees
+create sequence employee_id_seq
+create sequence employment_id_seq
+create sequence employer_id_seq]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="example-mappings-authorwork">
+        <title>Author(作家)/Work(作品)</title>
+
+        <para>
+            
+            考虑下面的<literal>Work</literal>,<literal>Author</literal> 和 <literal>Person</literal>模型的关系。
+            我们用多对多关系来描述<literal>Work</literal> 和 <literal>Author</literal>,
+            用一对一关系来描述<literal>Author</literal> 和 <literal>Person</literal>,
+            另一种可能性是<literal>Author</literal>继承<literal>Person</literal>。
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/AuthorWork.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/AuthorWork.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            下面的映射文件正确的描述了这些关系:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Work" table="works" discriminator-value="W">
+
+        <id name="id" column="id">
+            <generator class="native"/>
+        </id>
+        <discriminator column="type" type="character"/>
+
+        <property name="title"/>
+        <set name="authors" table="author_work">
+            <key column name="work_id"/>
+            <many-to-many class="Author" column name="author_id"/>
+        </set>
+
+        <subclass name="Book" discriminator-value="B">
+            <property name="text"/>
+        </subclass>
+
+        <subclass name="Song" discriminator-value="S">
+            <property name="tempo"/>
+            <property name="genre"/>
+        </subclass>
+
+    </class>
+
+    <class name="Author" table="authors">
+
+        <id name="id" column="id">
+            <!-- The Author must have the same identifier as the Person -->
+            <generator class="assigned"/> 
+        </id>
+
+        <property name="alias"/>
+        <one-to-one name="person" constrained="true"/>
+
+        <set name="works" table="author_work" inverse="true">
+            <key column="author_id"/>
+            <many-to-many class="Work" column="work_id"/>
+        </set>
+
+    </class>
+
+    <class name="Person" table="persons">
+        <id name="id" column="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        
+        映射中有4个表。<literal>works</literal>, <literal>authors</literal> 和 <literal>persons</literal>
+        分别保存着work,author和person的数据。<literal>author_work</literal>是authors和works的关联表。
+        表结构是由<literal>SchemaExport</literal>生成的。
+    </para>
+
+    <programlisting><![CDATA[create table works (
+    id BIGINT not null generated by default as identity, 
+    tempo FLOAT, 
+    genre VARCHAR(255), 
+    text INTEGER, 
+    title VARCHAR(255), 
+    type CHAR(1) not null, 
+    primary key (id)
+)
+
+create table author_work (
+    author_id BIGINT not null, 
+    work_id BIGINT not null, 
+    primary key (work_id, author_id)
+)
+
+create table authors (
+    id BIGINT not null generated by default as identity, 
+    alias VARCHAR(255), 
+    primary key (id)
+)
+
+create table persons (
+    id BIGINT not null generated by default as identity, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+alter table authors 
+    add constraint authorsFK0 foreign key (id) references persons
+alter table author_work 
+    add constraint author_workFK0 foreign key (author_id) references authors
+alter table author_work
+    add constraint author_workFK1 foreign key (work_id) references works]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="example-mappings-customerorderproduct">
+        <title>Customer(客户)/Order(订单)/Product(产品)</title>
+
+        <para>
+            
+            现在来考虑<literal>Customer</literal>,<literal>Order</literal> , <literal>LineItem</literal>
+            和 <literal>Product</literal>关系的模型。<literal>Customer</literal> 和 <literal>Order</literal>之间
+            是一对多的关系,但是我们怎么来描述<literal>Order</literal> / <literal>LineItem</literal> / <literal>Product</literal>呢?
+            我可以把<literal>LineItem</literal>作为描述<literal>Order</literal> 和 <literal>Product</literal>
+            多对多关系的关联类,在Hibernate,这叫做组合元素。
+        </para>
+
+        <mediaobject>
+            <imageobject role="fo">
+                <imagedata fileref="images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+            </imageobject>
+            <imageobject role="html">
+                <imagedata fileref="../shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+            </imageobject>
+        </mediaobject>
+        
+        <para>
+            映射文件如下:
+        </para>
+        
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="Customer" table="customers">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+        <set name="orders" inverse="true">
+            <key column="customer_id"/>
+            <one-to-many class="Order"/>
+        </set>
+    </class>
+
+    <class name="Order" table="orders">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="date"/>
+        <many-to-one name="customer" column="customer_id"/>
+        <list name="lineItems" table="line_items">
+            <key column="order_id"/>
+            <list-index column="line_number"/>
+            <composite-element class="LineItem">
+                <property name="quantity"/>
+                <many-to-one name="product" column="product_id"/>
+            </composite-element>
+        </list>
+    </class>
+
+    <class name="Product" table="products">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="serialNumber"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+    <para>
+        <literal>customers</literal>, <literal>orders</literal>, <literal>line_items</literal> 和 
+        <literal>products</literal> 分别保存着customer, order, order line item 和 product的数据。
+        <literal>line_items</literal>也作为连接orders 和 products的关联表。
+    </para>
+
+    <programlisting><![CDATA[create table customers (
+    id BIGINT not null generated by default as identity, 
+    name VARCHAR(255), 
+    primary key (id)
+)
+
+create table orders (
+    id BIGINT not null generated by default as identity, 
+    customer_id BIGINT, 
+    date TIMESTAMP, 
+    primary key (id)
+)
+
+create table line_items (
+    line_number INTEGER not null, 
+    order_id BIGINT not null, 
+    product_id BIGINT, 
+    quantity INTEGER, 
+    primary key (order_id, line_number)
+)
+
+create table products (
+    id BIGINT not null generated by default as identity, 
+    serialNumber VARCHAR(255), 
+    primary key (id)
+)
+
+alter table orders 
+    add constraint ordersFK0 foreign key (customer_id) references customers
+alter table line_items
+    add constraint line_itemsFK0 foreign key (product_id) references products
+alter table line_items
+    add constraint line_itemsFK1 foreign key (order_id) references orders]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="misc">
+        <title>杂例</title>
+        
+        <para>
+            这些例子全部来自于Hibernate的test suite,同时你也可以找到其他有用的例子。
+            可以参考Hibernate的<literal>test</literal>目录。
+        </para>
+        
+        <para>TODO: put words around this stuff</para>
+        
+        <sect2 id="example-mappings-typed-onetone">
+            <title>"Typed" one-to-one association</title>
+<programlisting><![CDATA[<class name="Person">
+    <id name="name"/>
+    <one-to-one name="address" 
+            cascade="all">
+        <formula>name</formula>
+        <formula>'HOME'</formula>
+    </one-to-one>
+    <one-to-one name="mailingAddress" 
+            cascade="all">
+        <formula>name</formula>
+        <formula>'MAILING'</formula>
+    </one-to-one>
+</class>
+
+<class name="Address" batch-size="2" 
+        check="addressType in ('MAILING', 'HOME', 'BUSINESS')">
+    <composite-id>
+        <key-many-to-one name="person" 
+                column="personName"/>
+        <key-property name="type" 
+                column="addressType"/>
+    </composite-id>
+    <property name="street" type="text"/>
+    <property name="state"/>
+    <property name="zip"/>
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="example-mappings-composite-key">
+            <title>Composite key example</title>
+<programlisting><![CDATA[<class name="Customer">
+
+    <id name="customerId"
+        length="10">
+        <generator class="assigned"/>
+    </id>
+
+    <property name="name" not-null="true" length="100"/>
+    <property name="address" not-null="true" length="200"/>
+
+    <list name="orders"
+            inverse="true"
+            cascade="save-update">
+        <key column="customerId"/>
+        <index column="orderNumber"/>
+        <one-to-many class="Order"/>
+    </list>
+
+</class>
+
+<class name="Order" table="CustomerOrder" lazy="true">
+    <synchronize table="LineItem"/>
+    <synchronize table="Product"/>
+    
+    <composite-id name="id" 
+            class="Order$Id">
+        <key-property name="customerId" length="10"/>
+        <key-property name="orderNumber"/>
+    </composite-id>
+    
+    <property name="orderDate" 
+            type="calendar_date"
+            not-null="true"/>
+    
+    <property name="total">
+        <formula>
+            ( select sum(li.quantity*p.price) 
+            from LineItem li, Product p 
+            where li.productId = p.productId 
+                and li.customerId = customerId 
+                and li.orderNumber = orderNumber )
+        </formula>
+    </property>
+    
+    <many-to-one name="customer"
+            column="customerId"
+            insert="false"
+            update="false" 
+            not-null="true"/>
+        
+    <bag name="lineItems"
+            fetch="join" 
+            inverse="true"
+            cascade="save-update">
+        <key>
+            <column name="customerId"/>
+            <column name="orderNumber"/>
+        </key>
+        <one-to-many class="LineItem"/>
+    </bag>
+    
+</class>
+    
+<class name="LineItem">
+    
+    <composite-id name="id" 
+            class="LineItem$Id">
+        <key-property name="customerId" length="10"/>
+        <key-property name="orderNumber"/>
+        <key-property name="productId" length="10"/>
+    </composite-id>
+    
+    <property name="quantity"/>
+    
+    <many-to-one name="order"
+            insert="false"
+            update="false" 
+            not-null="true">
+        <column name="customerId"/>
+        <column name="orderNumber"/>
+    </many-to-one>
+    
+    <many-to-one name="product"
+            insert="false"
+            update="false" 
+            not-null="true"
+            column="productId"/>
+        
+</class>
+
+<class name="Product">
+    <synchronize table="LineItem"/>
+
+    <id name="productId"
+        length="10">
+        <generator class="assigned"/>
+    </id>
+    
+    <property name="description" 
+        not-null="true" 
+        length="200"/>
+    <property name="price" length="3"/>
+    <property name="numberAvailable"/>
+    
+    <property name="numberOrdered">
+        <formula>
+            ( select sum(li.quantity) 
+            from LineItem li 
+            where li.productId = productId )
+        </formula>
+    </property>
+    
+</class>]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-composite-key-manytomany">
+            <title>共有组合键属性的多对多(Many-to-many with shared composite key attribute)</title>
+            
+<programlisting><![CDATA[<class name="User" table="`User`">
+    <composite-id>
+        <key-property name="name"/>
+        <key-property name="org"/>
+    </composite-id>
+    <set name="groups" table="UserGroup">
+        <key>
+            <column name="userName"/>
+            <column name="org"/>
+        </key>
+        <many-to-many class="Group">
+            <column name="groupName"/>
+            <formula>org</formula>
+        </many-to-many>
+    </set>
+</class>
+    
+<class name="Group" table="`Group`">
+    <composite-id>
+        <key-property name="name"/>
+        <key-property name="org"/>
+    </composite-id>
+    <property name="description"/>
+    <set name="users" table="UserGroup" inverse="true">
+        <key>
+            <column name="groupName"/>
+            <column name="org"/>
+        </key>
+        <many-to-many class="User">
+            <column name="userName"/>
+            <formula>org</formula>
+        </many-to-many>
+    </set>
+</class>
+]]></programlisting>
+        </sect2>
+        
+        <sect2 id="example-mappings-content-discrimination">
+            <title>Content based discrimination</title>
+<programlisting><![CDATA[<class name="Person"
+    discriminator-value="P">
+    
+    <id name="id" 
+        column="person_id" 
+        unsaved-value="0">
+        <generator class="native"/>
+    </id>
+    
+            
+    <discriminator 
+        type="character">
+        <formula>
+            case 
+                when title is not null then 'E' 
+                when salesperson is not null then 'C' 
+                else 'P' 
+            end
+        </formula>
+    </discriminator>
+
+    <property name="name" 
+        not-null="true"
+        length="80"/>
+        
+    <property name="sex" 
+        not-null="true"
+        update="false"/>
+    
+    <component name="address">
+        <property name="address"/>
+        <property name="zip"/>
+        <property name="country"/>
+    </component>
+    
+    <subclass name="Employee" 
+        discriminator-value="E">
+            <property name="title"
+                length="20"/>
+            <property name="salary"/>
+            <many-to-one name="manager"/>
+    </subclass>
+    
+    <subclass name="Customer" 
+        discriminator-value="C">
+            <property name="comments"/>
+            <many-to-one name="salesperson"/>
+    </subclass>
+    
+</class>]]></programlisting>
+        </sect2>
+
+        <sect2 id="example-mappings-association-alternatekeys"  revision="2">
+            <title>Associations on alternate keys</title>
+<programlisting><![CDATA[<class name="Person">
+    
+    <id name="id">
+        <generator class="hilo"/>
+    </id>
+    
+    <property name="name" length="100"/>
+    
+    <one-to-one name="address" 
+        property-ref="person"
+        cascade="all"
+        fetch="join"/>
+    
+    <set name="accounts" 
+        inverse="true">
+        <key column="userId"
+            property-ref="userId"/>
+        <one-to-many class="Account"/>
+    </set>
+    
+    <property name="userId" length="8"/>
+
+</class>
+
+<class name="Address">
+
+    <id name="id">
+        <generator class="hilo"/>
+    </id>
+
+    <property name="address" length="300"/>
+    <property name="zip" length="5"/>
+    <property name="country" length="25"/>
+    <many-to-one name="person" unique="true" not-null="true"/>
+
+</class>
+
+<class name="Account">
+    <id name="accountId" length="32">
+        <generator class="uuid"/>
+    </id>
+    
+    <many-to-one name="user"
+        column="userId"
+        property-ref="userId"/>
+    
+    <property name="type" not-null="true"/>
+    
+</class>]]></programlisting>
+        </sect2>
+
+    </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/example_parentchild.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/example_parentchild.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/example_parentchild.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,306 @@
+<chapter id="example-parentchild">
+    <title>示例:父子关系(Parent Child Relationships)</title>
+    <para>
+    刚刚接触Hibernate的人大多是从父子关系(parent / child type relationship)的建模入手的。父子关系的建模有两种方法。由于种种原因,最方便的方法是把<literal>Parent</literal>和<literal>Child</literal>都建模成实体类,并创建一个从<literal>Parent</literal>指向<literal>Child</literal>的&lt;one-to-many&gt;关联,对新手来说尤其如此。还有一种方法,就是将<literal>Child</literal>声明为一个<literal>&lt;composite-element&gt;</literal>(组合元素)。 事实上在Hibernate中one to many关联的默认语义远没有composite element贴近parent / child关系的通常语义。下面我们会阐述如何使用<emphasis>带有级联的双向一对多关联(bidirectional one to many association with cascades)</emphasis>去建立有效、优美的parent / child关系。这一点也不难!
+    </para>
+    
+    <sect1 id="example-parentchild-collections">
+    <title>关于collections需要注意的一点</title>
+    <para>    
+        Hibernate collections被当作其所属实体而不是其包含实体的一个逻辑部分。这非常重要!它主要体现为以下几点:
+    </para>
+    <itemizedlist>
+        <listitem>
+        <para>
+            当删除或增加collection中对象的时候,collection所属者的版本值会递增。
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+	    如果一个从collection中移除的对象是一个值类型(value type)的实例,比如composite element,那么这个对象的持久化状态将会终止,其在数据库中对应的记录会被删除。同样的,向collection增加一个value type的实例将会使之立即被持久化。
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+            另一方面,如果从一对多或多对多关联的collection中移除一个实体,在缺省情况下这个对象并不会被删除。这个行为是完全合乎逻辑的--改变一个实体的内部状态不应该使与它关联的实体消失掉!同样的,向collection增加一个实体不会使之被持久化。
+        </para>
+        </listitem>
+    </itemizedlist>
+    
+    <para>
+        实际上,向Collection增加一个实体的缺省动作只是在两个实体之间创建一个连接而已,同样移除的时候也只是删除连接。这种处理对于所有的情况都是合适的。对于父子关系则是完全不适合的,在这种关系下,子对象的生存绑定于父对象的生存周期。
+    </para>
+    
+    </sect1>
+    <sect1 id="example-parentchild-bidir">
+    <title>双向的一对多关系(Bidirectional one-to-many)</title>
+    
+    <para>
+        假设我们要实现一个简单的从Parent到Child的&lt;one-to-many&gt;关联。
+    </para>
+    
+    <programlisting><![CDATA[<set name="children">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+    
+    <para>
+        如果我们运行下面的代码
+    </para>
+    
+    <programlisting><![CDATA[Parent p = .....;
+Child c = new Child();
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+    
+    <para>
+        Hibernate会产生两条SQL语句:
+    </para>
+    
+    <itemizedlist>
+    <listitem>
+        <para>一条<literal>INSERT</literal>语句,为<literal>c</literal>创建一条记录</para>
+    </listitem>
+    <listitem>
+        <para>
+	    一条<literal>UPDATE</literal>语句,创建从<literal>p</literal>到<literal>c</literal>的连接
+        </para>
+    </listitem>
+    </itemizedlist>
+    
+    <para>
+        这样做不仅效率低,而且违反了列<literal>parent_id</literal>非空的限制。我们可以通过在集合类映射上指定<literal>not-null="true"</literal>来解决违反非空约束的问题:
+    </para>
+    
+        <programlisting><![CDATA[<set name="children">
+    <key column="parent_id" not-null="true"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+    
+    <para>
+    	然而,这并非是推荐的解决方法。
+   	</para>
+    
+    <para>        这种现象的根本原因是从<literal>p</literal>到<literal>c</literal>的连接(外键parent_id)没有被当作<literal>Child</literal>对象状态的一部分,因而没有在INSERT语句中被创建。因此解决的办法就是把这个连接添加到Child的映射中。
+    </para>
+    
+    <programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
+    
+    <para>
+        (我们还需要为类<literal>Child</literal>添加<literal>parent</literal>属性)
+    </para>
+    
+    <para>
+        现在实体<literal>Child</literal>在管理连接的状态,为了使collection不更新连接,我们使用<literal>inverse</literal>属性。
+    </para>
+    
+    <programlisting><![CDATA[<set name="children" inverse="true">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+    <para>
+        下面的代码是用来添加一个新的<literal>Child</literal>
+    </para>
+
+    <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+    <para>
+        现在,只会有一条<literal>INSERT</literal>语句被执行!
+    </para>
+
+    <para>
+        为了让事情变得井井有条,可以为<literal>Parent</literal>加一个<literal>addChild()</literal>方法。
+    </para>
+
+    <programlisting><![CDATA[public void addChild(Child c) {
+    c.setParent(this);
+    children.add(c);
+}]]></programlisting>
+
+    <para>
+        现在,添加<literal>Child</literal>的代码就是这样
+    </para>
+
+    <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+     </sect1>
+     
+     <sect1 id="example-parentchild-cascades">
+     <title>级联生命周期(Cascading lifecycle)</title>
+     <para>
+	需要显式调用<literal>save()</literal>仍然很麻烦,我们可以用级联来解决这个问题。
+     </para>
+     
+    <programlisting><![CDATA[<set name="children" inverse="true" cascade="all">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+     
+     <para>
+         这样上面的代码可以简化为:
+     </para>
+     
+    <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.flush();]]></programlisting>
+     
+     <para>
+         同样的,保存或删除<literal>Parent</literal>对象的时候并不需要遍历其子对象。
+         下面的代码会删除对象<literal>p</literal>及其所有子对象对应的数据库记录。
+     </para>
+     
+     <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+session.delete(p);
+session.flush();]]></programlisting>
+     
+     <para>
+         然而,这段代码
+     </para>
+     
+     <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+c.setParent(null);
+session.flush();]]></programlisting>
+     
+     <para>
+         不会从数据库删除<literal>c</literal>;它只会删除与<literal>p</literal>之间的连接(并且会导致违反<literal>NOT NULL</literal>约束,在这个例子中)。你需要显式调用<literal>delete()</literal>来删除<literal>Child</literal>。 <!--,因为Hibernate并没有设计垃圾回收器!代码如下:-->
+     </para>
+
+     <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+session.delete(c);
+session.flush();]]></programlisting>
+     
+
+     <para>
+         在我们的例子中,如果没有父对象,子对象就不应该存在,如果将子对象从collection中移除,实际上我们是想删除它。要实现这种要求,就必须使用<literal>cascade="all-delete-orphan"</literal>。
+     </para>
+     
+     
+    <programlisting><![CDATA[<set name="children" inverse="true" cascade="all-delete-orphan">
+    <key column="parent_id"/>
+    <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+     <para>
+         注意:即使在collection一方的映射中指定<literal>inverse="true"</literal>,级联仍然是通过遍历collection中的元素来处理的。如果你想要通过级联进行子对象的插入、删除、更新操作,就必须把它加到collection中,只调用<literal>setParent()</literal>是不够的。
+     </para>
+     
+     </sect1>
+     
+     <sect1 id="example-parentchild-update">
+     <title>级联与<literal>未保存值</literal>(Cascades and <literal>unsaved-value</literal>)</title>
+     
+     <para>
+         假设我们从<literal>Session</literal>中装入了一个<literal>Parent</literal>对象,用户界面对其进行了修改,然后希望在一个新的Session里面调用<literal>update()</literal>来保存这些修改。对象<literal>Parent</literal>包含了子对象的集合,由于打开了级联更新,Hibernate需要知道哪些Child对象是新实例化的,哪些代表数据库中已经存在的记录。我们假设<literal>Parent</literal>和<literal>Child</literal>对象的标识属性都是自动生成的,类型为<literal>java.lang.Long</literal>。Hibernate会使用标识属性的值,和version 或 timestamp 属性,来判断哪些子对象是新的。(参见<xref linkend="objectstate-saveorupdate"/>.) <emphasis>在 Hibernate3 中,显式指定<literal>unsaved-value</literal>不再是必须的了。</emphasis>
+     </para>
+     
+     <para>
+         下面的代码会更新<literal>parent</literal>和<literal>child</literal>对象,并且插入<literal>newChild</literal>对象。
+     </para>
+     
+     <programlisting><![CDATA[//parent and child were both loaded in a previous session
+parent.addChild(child);
+Child newChild = new Child();
+parent.addChild(newChild);
+session.update(parent);
+session.flush();]]></programlisting>
+     
+         <para>
+             Well, that's all very well for the case of a generated identifier, but what about assigned identifiers
+             and composite identifiers? This is more difficult, since Hibernate can't use the identifier property to
+             distinguish between a newly instantiated object (with an identifier assigned by the user) and an 
+             object loaded in a previous session. In this case, Hibernate will either use the timestamp or version 
+             property, or will actually query the second-level cache or, worst case, the database, to see if the 
+             row exists.
+         </para>
+     <para>
+         这对于自动生成标识的情况是非常好的,但是自分配的标识和复合标识怎么办呢?这是有点麻烦,因为Hibernate没有办法区分新实例化的对象(标识被用户指定了)和前一个Session装入的对象。在这种情况下,Hibernate会使用timestamp或version属性,或者查询第二级缓存,或者最坏的情况,查询数据库,来确认是否此行存在。</para>
+     
+     <!-- undocumenting
+
+     <para>
+         还有一种可能情况,有一个名为<literal>isUnsaved()</literal>的<literal>新的拦截器(Interceptor)</literal>方法,它允许应用程序自己实现新实例的判断。比如,你可以自己定义一个持久类的祖先类:
+     </para>
+     
+         <programlisting><![CDATA[public class Persistent {
+    private boolean _saved = false;
+    public void onSave() {
+        _saved=true;
+    }
+    public void onLoad() {
+        _saved=true;
+    }
+    ......
+    public boolean isSaved() {
+        return _saved;
+    }
+}]]></programlisting>
+     
+     <para>
+     	(<literal>saved</literal>属性是不会被持久化的。)
+     	现在在<literal>onLoad()</literal>和<literal>onSave()</literal>外,还要实现<literal>isUnsaved()</literal>。
+     </para>
+     
+     <programlisting><![CDATA[public Boolean isUnsaved(Object entity) {
+    if (entity instanceof Persistent) {
+        return new Boolean( !( (Persistent) entity ).isSaved() );
+    }
+    else {
+        return null;
+    }
+}
+
+public boolean onLoad(Object entity, 
+    Serializable id,
+    Object[] state,
+    String[] propertyNames,
+    Type[] types) {
+
+    if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
+    return false;
+}
+
+public boolean onSave(Object entity,
+    Serializable id,
+    Object[] state,
+    String[] propertyNames,
+    Type[] types) {
+        
+    if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
+    return false;
+}]]></programlisting>
+
+		<para>
+			Don't worry; in Hibernate3 you don't need to write any of this kind of code if you don't want to.
+			别担心,在Hibernate3中,假若你不愿意,你不需要编写任何这类代码。
+		</para>
+     -->
+     
+     </sect1>
+     
+     
+     <sect1 id="example-parentchild-conclusion">
+     <title>结论</title>
+     <para>         这里有不少东西需要融会贯通,可能会让新手感到迷惑。但是在实践中它们都工作地非常好。大部分Hibernate应用程序都会经常用到父子对象模式。
+     </para>
+     <para>
+         在第一段中我们曾经提到另一个方案。上面的这些问题都不会出现在<literal>&lt;composite-element&gt;</literal>映射中,它准确地表达了父子关系的语义。很不幸复合元素还有两个重大限制:复合元素不能拥有collections,并且,除了用于惟一的父对象外,它们不能再作为其它任何实体的子对象。
+     </para>
+     </sect1>
+     
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/example_weblog.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/example_weblog.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/example_weblog.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,424 @@
+<chapter id="example-weblog">
+    <title>示例:Weblog 应用程序</title>
+    
+    <sect1 id="example-weblog-classes">
+        <title>持久化类</title>
+        
+        <para>        	下面的持久化类表示一个weblog和在其中张贴的一个贴子。他们是标准的父/子关系模型,但是我们会用一个有序包(ordered bag)而非集合(set)。
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+import java.util.List;
+
+public class Blog {
+    private Long _id;
+    private String _name;
+    private List _items;
+
+    public Long getId() {
+        return _id;
+    }
+    public List getItems() {
+        return _items;
+    }
+    public String getName() {
+        return _name;
+    }
+    public void setId(Long long1) {
+        _id = long1;
+    }
+    public void setItems(List list) {
+        _items = list;
+    }
+    public void setName(String string) {
+        _name = string;
+    }
+}]]></programlisting>
+
+        <programlisting><![CDATA[package eg;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+
+public class BlogItem {
+    private Long _id;
+    private Calendar _datetime;
+    private String _text;
+    private String _title;
+    private Blog _blog;
+
+    public Blog getBlog() {
+        return _blog;
+    }
+    public Calendar getDatetime() {
+        return _datetime;
+    }
+    public Long getId() {
+        return _id;
+    }
+    public String getText() {
+        return _text;
+    }
+    public String getTitle() {
+        return _title;
+    }
+    public void setBlog(Blog blog) {
+        _blog = blog;
+    }
+    public void setDatetime(Calendar calendar) {
+        _datetime = calendar;
+    }
+    public void setId(Long long1) {
+        _id = long1;
+    }
+    public void setText(String string) {
+        _text = string;
+    }
+    public void setTitle(String string) {
+        _title = string;
+    }
+}]]></programlisting>
+
+    </sect1>
+    <sect1 id="example-weblog-mappings">
+        <title>Hibernate 映射</title>
+        
+        <para>
+            下列的XML映射应该是很直白的。
+        </para>
+        
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+    <class 
+        name="Blog" 
+        table="BLOGS" >
+        
+        <id 
+            name="id" 
+            column="BLOG_ID">
+            
+            <generator class="native"/>
+            
+        </id>
+        
+        <property 
+            name="name" 
+            column="NAME" 
+            not-null="true" 
+            unique="true"/>
+            
+        <bag 
+            name="items" 
+            inverse="true" 
+            order-by="DATE_TIME" 
+            cascade="all">
+            
+            <key column="BLOG_ID"/>
+            <one-to-many class="BlogItem"/>
+            
+        </bag>
+        
+    </class>
+    
+</hibernate-mapping>]]></programlisting>
+
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+    
+    <class 
+        name="BlogItem" 
+        table="BLOG_ITEMS" 
+        dynamic-update="true">
+        
+        <id 
+            name="id" 
+            column="BLOG_ITEM_ID">
+            
+            <generator class="native"/>
+            
+        </id>
+        
+        <property 
+            name="title" 
+            column="TITLE" 
+            not-null="true"/>
+            
+        <property 
+            name="text" 
+            column="TEXT" 
+            not-null="true"/>
+            
+        <property 
+            name="datetime" 
+            column="DATE_TIME" 
+            not-null="true"/>
+            
+        <many-to-one 
+            name="blog" 
+            column="BLOG_ID" 
+            not-null="true"/>
+            
+    </class>
+    
+</hibernate-mapping>]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="example-weblog-code">
+        <title>Hibernate 代码</title>
+        
+        <para>
+            下面的类演示了我们可以使用Hibernate对这些类进行的一些操作。
+        </para>
+        
+        <programlisting><![CDATA[package eg;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+
+public class BlogMain {
+    
+    private SessionFactory _sessions;
+    
+    public void configure() throws HibernateException {
+        _sessions = new Configuration()
+            .addClass(Blog.class)
+            .addClass(BlogItem.class)
+            .buildSessionFactory();
+    }
+    
+    public void exportTables() throws HibernateException {
+        Configuration cfg = new Configuration()
+            .addClass(Blog.class)
+            .addClass(BlogItem.class);
+        new SchemaExport(cfg).create(true, true);
+    }
+    
+    public Blog createBlog(String name) throws HibernateException {
+        
+        Blog blog = new Blog();
+        blog.setName(name);
+        blog.setItems( new ArrayList() );
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.persist(blog);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return blog;
+    }
+    
+    public BlogItem createBlogItem(Blog blog, String title, String text)
+                        throws HibernateException {
+        
+        BlogItem item = new BlogItem();
+        item.setTitle(title);
+        item.setText(text);
+        item.setBlog(blog);
+        item.setDatetime( Calendar.getInstance() );
+        blog.getItems().add(item);
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.update(blog);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return item;
+    }
+    
+    public BlogItem createBlogItem(Long blogid, String title, String text)
+                        throws HibernateException {
+        
+        BlogItem item = new BlogItem();
+        item.setTitle(title);
+        item.setText(text);
+        item.setDatetime( Calendar.getInstance() );
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            Blog blog = (Blog) session.load(Blog.class, blogid);
+            item.setBlog(blog);
+            blog.getItems().add(item);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return item;
+    }
+    
+    public void updateBlogItem(BlogItem item, String text)
+                    throws HibernateException {
+        
+        item.setText(text);
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            session.update(item);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+    }
+    
+    public void updateBlogItem(Long itemid, String text)
+                    throws HibernateException {
+    
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        try {
+            tx = session.beginTransaction();
+            BlogItem item = (BlogItem) session.load(BlogItem.class, itemid);
+            item.setText(text);
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+    }
+    
+    public List listAllBlogNamesAndItemCounts(int max)
+                    throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        List result = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "select blog.id, blog.name, count(blogItem) " +
+                "from Blog as blog " +
+                "left outer join blog.items as blogItem " +
+                "group by blog.name, blog.id " +
+                "order by max(blogItem.datetime)"
+            );
+            q.setMaxResults(max);
+            result = q.list();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return result;
+    }
+    
+    public Blog getBlogAndAllItems(Long blogid)
+                    throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        Blog blog = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "from Blog as blog " +
+                "left outer join fetch blog.items " +
+                "where blog.id = :blogid"
+            );
+            q.setParameter("blogid", blogid);
+            blog  = (Blog) q.uniqueResult();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return blog;
+    }
+    
+    public List listBlogsAndRecentItems() throws HibernateException {
+        
+        Session session = _sessions.openSession();
+        Transaction tx = null;
+        List result = null;
+        try {
+            tx = session.beginTransaction();
+            Query q = session.createQuery(
+                "from Blog as blog " +
+                "inner join blog.items as blogItem " +
+                "where blogItem.datetime > :minDate"
+            );
+
+            Calendar cal = Calendar.getInstance();
+            cal.roll(Calendar.MONTH, false);
+            q.setCalendar("minDate", cal);
+            
+            result = q.list();
+            tx.commit();
+        }
+        catch (HibernateException he) {
+            if (tx!=null) tx.rollback();
+            throw he;
+        }
+        finally {
+            session.close();
+        }
+        return result;
+    }
+}]]></programlisting>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/filters.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/filters.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/filters.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,140 @@
+<chapter id="filters">
+    <title>过滤数据</title>
+    <para>
+
+                Hibernate3 提供了一种创新的方式来处理具有“显性(visibility)”规则的数据,那就是使用<emphasis>Hibernate filter</emphasis>。
+                <emphasis>Hibernate filter</emphasis>是全局有效的、具有名字、可以带参数的过滤器,
+                对于某个特定的Hibernate session您可以选择是否启用(或禁用)某个过滤器。
+    </para>
+
+    <sect1 id="objectstate-filters" revision="1">
+        <title>Hibernate 过滤器(filters)</title>
+
+        <para>
+                        Hibernate3新增了对某个类或者集合使用预先定义的过滤器条件(filter criteria)的功能。过滤器条件相当于定义一个
+                        非常类似于类和各种集合上的“where”属性的约束子句,但是过滤器条件可以带参数。
+                        应用程序可以在运行时决定是否启用给定的过滤器,以及使用什么样的参数值。
+                        过滤器的用法很像数据库视图,只不过是在应用程序中确定使用什么样的参数的。
+                        
+        </para>
+
+        <para>
+
+            要使用过滤器,必须首先在相应的映射节点中定义。而定义一个过滤器,要用到位于<literal>&lt;hibernate-mapping/&gt;</literal>
+			节点之内的<literal>&lt;filter-def/&gt;</literal>节点:
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="myFilter">
+    <filter-param name="myFilterParam" type="string"/>
+</filter-def>]]></programlisting>
+
+        <para>
+			定义好之后,就可以在某个类中使用这个过滤器:
+        </para>
+
+        <programlisting><![CDATA[<class name="myClass" ...>
+    ...
+    <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</class>]]></programlisting>
+
+        <para>
+			也可以在某个集合使用它:
+        </para>
+
+        <programlisting><![CDATA[<set ...>
+    <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</set>]]></programlisting>
+
+        <para>
+                        可以在多个类或集合中使用某个过滤器;某个类或者集合中也可以使用多个过滤器。
+        </para>
+
+        <para>
+
+			<literal>Session</literal>对象中会用到的方法有:<literal>enableFilter(String filterName)</literal>,
+            <literal>getEnabledFilter(String filterName)</literal>, 和 <literal>disableFilter(String filterName)</literal>.
+			Session中默认是<emphasis>不</emphasis>启用过滤器的,必须通过<literal>Session.enabledFilter()</literal>方法显式的启用。
+			该方法返回被启用的<literal>Filter</literal>的实例。以上文定义的过滤器为例:
+        </para>
+
+        <programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
+
+        <para>
+			注意,org.hibernate.Filter的方法允许链式方法调用。(类似上面例子中启用Filter之后设定Filter参数这个“方法链”)
+                        Hibernate的其他部分也大多有这个特性。
+        </para>
+
+        <para>
+			下面是一个比较完整的例子,使用了记录生效日期模式过滤有时效的数据:
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="effectiveDate">
+    <filter-param name="asOfDate" type="date"/>
+</filter-def>
+
+<class name="Employee" ...>
+...
+    <many-to-one name="department" column="dept_id" class="Department"/>
+    <property name="effectiveStartDate" type="date" column="eff_start_dt"/>
+    <property name="effectiveEndDate" type="date" column="eff_end_dt"/>
+...
+    <!--
+        Note that this assumes non-terminal records have an eff_end_dt set to
+        a max db date for simplicity-sake
+
+		注意,为了简单起见,此处假设雇用关系生效期尚未结束的记录的eff_end_dt字段的值等于数据库最大的日期
+    -->
+    <filter name="effectiveDate"
+            condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+</class>
+
+<class name="Department" ...>
+...
+    <set name="employees" lazy="true">
+        <key column="dept_id"/>
+        <one-to-many class="Employee"/>
+        <filter name="effectiveDate"
+                condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+    </set>
+</class>]]></programlisting>
+
+        <para>
+			定义好后,如果想要保证取回的都是目前处于生效期的记录,只需在获取雇员数据的操作之前先开启过滤器即可:
+        </para>
+
+<programlisting><![CDATA[Session session = ...;
+session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
+List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
+         .setLong("targetSalary", new Long(1000000))
+         .list();
+]]></programlisting>
+
+        <para>
+
+			在上面的HQL中,虽然我们仅仅显式的使用了一个薪水条件,但因为启用了过滤器,查询将仅返回那些目前雇用
+			关系处于生效期的,并且薪水高于一百万美刀的雇员的数据。
+
+        </para>
+
+        <para>
+
+			注意:如果你打算在使用外连接(或者通过HQL或load fetching)的同时使用过滤器,要注意条件表达式的方向(左还是右)。
+			最安全的方式是使用左外连接(left outer joining)。并且通常来说,先写参数,
+			然后是操作符,最后写数据库字段名。
+        </para>
+        
+        <para>
+            在Filter定义之后,它可能被附加到多个实体和/或集合类,每个都有自己的条件。假若这些条件都是一样的,每次都要定义就显得很繁琐。因此,<literal>&lt;filter-def/&gt;</literal>被用来定义一个默认条件,它可能作为属性或者CDATA出现:
+        </para>
+
+        <programlisting><![CDATA[<filter-def name="myFilter" condition="abc > xyz">...</filter-def>
+<filter-def name="myOtherFilter">abc=xyz</filter-def>]]></programlisting>
+
+        <para>
+        	当这个filter被附加到任何目的地,而又没有指明条件时,这个条件就会被使用。注意,换句话说,你可以通过给filter附加特别的条件来重载默认条件。
+        </para>
+
+
+    </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/inheritance_mapping.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/inheritance_mapping.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/inheritance_mapping.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,467 @@
+    <chapter id="inheritance">
+        <title>继承映射(Inheritance Mappings)</title>
+
+	    <sect1 id="inheritance-strategies" revision="3">
+            <title> 三种策略</title>
+
+
+            <para>
+               	Hibernate支持三种基本的继承映射策略:
+            </para>
+            
+            <itemizedlist>
+            <listitem>
+            <para>
+                每个类分层结构一张表(table per class hierarchy)
+            </para>
+            </listitem>
+            <listitem>
+            <para>
+                每个子类一张表(table per subclass)
+            </para>
+            </listitem>
+            <listitem>
+            <para>
+                每个具体类一张表(table per concrete class)
+            </para>
+            </listitem>
+            </itemizedlist>
+	        <para>
+	            此外,Hibernate还支持第四种稍有不同的多态映射策略:
+	        </para>
+
+            <itemizedlist>
+            <listitem>
+            <para>
+                隐式多态(implicit polymorphism)
+            </para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+									对于同一个继承层次内的不同分支,可以采用不同的映射策略,然后用隐式多
+									态来完成跨越整个层次的多态。但是在同一个<literal>&lt;class&gt;</literal>根元素
+									下,Hibernate不支持混合了元素<literal>&lt;subclass&gt;</literal>、
+									<literal>&lt;joined-subclass&gt;</literal>和<literal>&lt;union-subclass&gt;</literal>
+									的映射。在同一个<literal>&lt;class&gt;</literal>元素下,可以混合使用
+									“每个类分层结构一张表”(table per hierarchy) 和“每个子类一张表”(table per subclass)
+									这两种映射策略,这是通过结合元素<literal>&lt;subclass&gt;</literal>和
+									<literal>&lt;join&gt;</literal>来实现的(见后)。
+									
+            </para>
+
+        <para>
+			在多个映射文件中,可以直接在<literal>hibernate-mapping</literal>根下定义<literal>subclass</literal>,<literal>union-subclass</literal>和<literal>joined-subclass</literal>。也就是说,你可以仅加入一个新的映射文件来扩展类层次。你必须在subclass的映射中指明<literal>extends</literal>属性,给出一个之前定义的超类的名字。注意,在以前,这一功能对映射文件的顺序有严格的要求,从Hibernate 3开始,使用extends关键字的时侯,对映射文件的顺序不再有要求;但在每个映射文件里,超类必须在子类之前定义。
+		</para>
+
+         <programlisting><![CDATA[
+ <hibernate-mapping>
+     <subclass name="DomesticCat" extends="Cat" discriminator-value="D">
+          <property name="name" type="string"/>
+     </subclass>
+ </hibernate-mapping>]]></programlisting>
+
+            <sect2 id="inheritance-tableperclass" >
+            <title>每个类分层结构一张表(Table per class hierarchy)</title>
+
+            
+            <para>
+                假设我们有接口<literal>Payment</literal>和它的几个实现类:
+                <literal>CreditCardPayment</literal>, <literal>CashPayment</literal>, 
+                和<literal>ChequePayment</literal>。则“每个类分层结构一张表”(Table per 
+                class hierarchy)的映射代码如下所示:
+            </para>
+            
+            <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        ...
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        ...
+    </subclass>
+</class>]]></programlisting>
+
+            <para>
+                采用这种策略只需要一张表即可。它有一个很大的限制:要求那些由子类定义的字段,
+                如<literal>CCTYPE</literal>,不能有<literal>非空(NOT NULL)</literal>约束。
+            </para>
+
+            </sect2>
+
+            <sect2 id="inheritance-tablepersubclass">
+
+            <title>每个子类一张表(Table per subclass)</title>
+
+
+            <para>
+                对于上例中的几个类而言,采用“每个子类一张表”的映射策略,代码如下所示:
+            </para>
+            
+            <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        ...
+    </joined-subclass>
+</class>]]></programlisting>
+            <para>
+                需要四张表。三个子类表通过主键关联到超类表(因而关系模型实际上是一对一关联)。
+            </para>
+
+            </sect2>
+
+            <sect2 id="inheritance-tablepersubclass-discriminator" revision="2">
+        		
+            <title>每个子类一张表(Table per subclass),使用辨别标志(Discriminator)</title>
+
+            <para>
+                注意,对“每个子类一张表”的映射策略,Hibernate的实现不需要辨别字段,而其他
+                的对象/关系映射工具使用了一种不同于Hibernate的实现方法,该方法要求在超类
+                表中有一个类型辨别字段(type discriminator column)。Hibernate采用的方法更
+                难实现,但从关系(数据库)的角度来看,按理说它更正确。若你愿意使用带有辨别字
+                段的“每个子类一张表”的策略,你可以结合使用<literal>&lt;subclass&gt;</literal>
+                与<literal>&lt;join&gt;</literal>,如下所示:
+            </para>
+            
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <join table="CREDIT_PAYMENT">
+            <key column="PAYMENT_ID"/>
+            <property name="creditCardType" column="CCTYPE"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        <join table="CASH_PAYMENT">
+            <key column="PAYMENT_ID"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        <join table="CHEQUE_PAYMENT" fetch="select">
+            <key column="PAYMENT_ID"/>
+            ...
+        </join>
+    </subclass>
+</class>]]></programlisting>
+
+
+            <para>
+                可选的声明<literal>fetch="select"</literal>,是用来告诉Hibernate,在查询超类时,
+                不要使用外部连接(outer join)来抓取子类<literal>ChequePayment</literal>的数据。
+            </para>
+
+            </sect2>
+
+            <sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
+            <title>混合使用“每个类分层结构一张表”和“每个子类一张表”</title>
+
+            <para>
+                你甚至可以采取如下方法混和使用“每个类分层结构一张表”和“每个子类一张表”这两种策略:
+            </para>
+
+        <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="PAYMENT_TYPE" type="string"/>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+        <join table="CREDIT_PAYMENT">
+            <property name="creditCardType" column="CCTYPE"/>
+            ...
+        </join>
+    </subclass>
+    <subclass name="CashPayment" discriminator-value="CASH">
+        ...
+    </subclass>
+    <subclass name="ChequePayment" discriminator-value="CHEQUE">
+        ...
+    </subclass>
+</class>]]></programlisting>
+
+            <para>
+                对上述任何一种映射策略而言,指向根类<literal>Payment</literal>的
+                关联是使用<literal>&lt;many-to-one&gt;</literal>进行映射的。
+            </para>
+           
+            <programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
+
+            </sect2>
+        
+            <sect2 id="inheritance-tableperconcrete" revision="2">
+            <title>每个具体类一张表(Table per concrete class)</title>
+
+            <para>
+                对于“每个具体类一张表”的映射策略,可以采用两种方法。第一种方法是使用
+                <literal>&lt;union-subclass&gt;</literal>。
+            </para>
+           
+        <programlisting><![CDATA[<class name="Payment">
+    <id name="id" type="long" column="PAYMENT_ID">
+        <generator class="sequence"/>
+    </id>
+    <property name="amount" column="AMOUNT"/>
+    ...
+    <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+        <property name="creditCardType" column="CCTYPE"/>
+        ...
+    </union-subclass>
+    <union-subclass name="CashPayment" table="CASH_PAYMENT">
+        ...
+    </union-subclass>
+    <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        ...
+    </union-subclass>
+</class>]]></programlisting>
+
+            <para>
+                这里涉及三张与子类相关的表。每张表为对应类的所有属性(包括从超类继承的属性)定义相应字段。
+            </para>
+
+            <para>
+                这种方式的局限在于,如果一个属性在超类中做了映射,其字段名必须与所有子类
+                表中定义的相同。(我们可能会在Hibernate的后续发布版本中放宽此限制。) 
+                不允许在联合子类(union subclass)的继承层次中使用标识生成器策略(identity generator strategy), 
+                实际上, 主键的种子(primary key seed)不得不为同一继承层次中的全部被联合子类所共用.
+            </para>
+
+        <para>
+            假若超类是抽象类,请使用<literal>abstract="true"</literal>。当然,假若它不是抽象的,需要一个额外的表(上面的例子中,默认是<literal>PAYMENT</literal>),来保存超类的实例。
+        </para>
+        
+            </sect2>
+
+            <sect2 id="inheritance-tableperconcreate-polymorphism">
+     			  <title>Table per concrete class, using implicit polymorphism</title>
+            <title>每个具体类一张表,使用隐式多态</title>
+
+            <para>
+                另一种可供选择的方法是采用隐式多态:
+            </para>
+
+            <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+    <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CREDIT_AMOUNT"/>
+    ...
+</class>
+
+<class name="CashPayment" table="CASH_PAYMENT">
+    <id name="id" type="long" column="CASH_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CASH_AMOUNT"/>
+    ...
+</class>
+
+<class name="ChequePayment" table="CHEQUE_PAYMENT">
+    <id name="id" type="long" column="CHEQUE_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <property name="amount" column="CHEQUE_AMOUNT"/>
+    ...
+</class>]]></programlisting>
+           
+            <para>
+                注意,我们没有在任何地方明确的提及接口<literal>Payment</literal>。同时注意
+                <literal>Payment</literal>的属性在每个子类中都进行了映射。如果你想避免重复,
+                可以考虑使用XML实体(例如:位于<literal>DOCTYPE</literal>声明内的
+                <literal>[ &lt;!ENTITY allproperties SYSTEM "allproperties.xml"&gt; ]</literal>
+                和映射中的<literal>&amp;allproperties;</literal>)。
+            </para>
+        
+            <para>
+                这种方法的缺陷在于,在Hibernate执行多态查询时(polymorphic queries)无法生成带
+                <literal>UNION</literal>的SQL语句。
+            </para>
+
+            <para>
+                对于这种映射策略而言,通常用<literal>&lt;any&gt;</literal>来实现到
+                <literal>Payment</literal>的多态关联映射。
+            </para>
+
+        <programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
+    <meta-value value="CREDIT" class="CreditCardPayment"/>
+    <meta-value value="CASH" class="CashPayment"/>
+    <meta-value value="CHEQUE" class="ChequePayment"/>
+    <column name="PAYMENT_CLASS"/>
+    <column name="PAYMENT_ID"/>
+</any>]]></programlisting>
+           
+            </sect2>
+
+            <sect2 id="inheritace-mixingpolymorphism">
+            <title>隐式多态和其他继承映射混合使用</title>
+
+            <para>
+                对这一映射还有一点需要注意。因为每个子类都在各自独立的元素<literal>&lt;class&gt;</literal>
+                中映射(并且<literal>Payment</literal>只是一个接口),每个子类可以很容易的成为另一
+                个继承体系中的一部分!(你仍然可以对接口<literal>Payment</literal>使用多态查询。)
+            </para>
+                
+            <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+    <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+        <generator class="native"/>
+    </id>
+    <discriminator column="CREDIT_CARD" type="string"/>
+    <property name="amount" column="CREDIT_AMOUNT"/>
+    ...
+    <subclass name="MasterCardPayment" discriminator-value="MDC"/>
+    <subclass name="VisaPayment" discriminator-value="VISA"/>
+</class>
+
+<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
+    <id name="id" type="long" column="TXN_ID">
+        <generator class="native"/>
+    </id>
+    ...
+    <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="amount" column="CASH_AMOUNT"/>
+        ...
+    </joined-subclass>
+    <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+        <key column="PAYMENT_ID"/>
+        <property name="amount" column="CHEQUE_AMOUNT"/>
+        ...
+    </joined-subclass>
+</class>]]></programlisting>
+
+            <para>
+                我们还是没有明确的提到<literal>Payment</literal>。
+                如果我们针对接口<literal>Payment</literal>执行查询 
+                ——如<literal>from Payment</literal>—— Hibernate
+                自动返回<literal>CreditCardPayment</literal>(和它的子类,因为
+                它们也实现了接口<literal>Payment</literal>)、
+                <literal>CashPayment</literal>和<literal>Chequepayment</literal>的实例,
+                但不返回<literal>NonelectronicTransaction</literal>的实例。
+            </para>
+           
+            </sect2>
+
+        </sect1>
+             
+        <sect1 id="inheritance-limitations">
+            <title>限制</title>
+            
+            <para>
+                对“每个具体类映射一张表”(table per concrete-class)的映射策略而言,隐式多态的
+                方式有一定的限制。而<literal>&lt;union-subclass&gt;</literal>映射的限制则没有那
+                么严格。
+            </para>
+
+            <para>
+                下面表格中列出了在Hibernte中“每个具体类一张表”的策略和隐式多态的限制。            
+            </para>
+            
+        <table frame="topbot">
+				<title>继承映射特性(Features of inheritance mappings)			</title>
+			<tgroup cols='8' align='left' colsep='1' rowsep='1'>
+			<colspec colname='c1' colwidth="1*"/>
+			<colspec colname='c2' colwidth="1*"/>
+			<colspec colname='c3' colwidth="1*"/>
+			<colspec colname='c4' colwidth="1*"/>
+			<colspec colname='c5' colwidth="1*"/>
+			<colspec colname='c6' colwidth="1*"/>
+			<colspec colname='c7' colwidth="1*"/>
+			<colspec colname='c8' colwidth="1*"/>
+			<thead>
+			 <row>
+			  <entry>继承策略(Inheritance strategy)</entry>
+			  <entry>多态多对一</entry>
+			  <entry>多态一对一</entry>
+			  <entry>多态一对多</entry>
+			  <entry>多态多对多</entry>
+			  <entry>多态 <literal>load()/get()</literal></entry>
+			  <entry>多态查询</entry>
+			  <entry>多态连接(join)</entry>
+			  <entry>外连接(Outer join)读取</entry>
+			</row>
+			</thead>
+			<tbody>
+			<row>
+			
+				<entry>每个类分层结构一张表</entry>
+				<entry><literal>&lt;many-to-one&gt;</literal></entry>
+				<entry><literal>&lt;one-to-one&gt;</literal></entry>
+				<entry><literal>&lt;one-to-many&gt;</literal></entry>
+				<entry><literal>&lt;many-to-many&gt;</literal></entry>
+				<entry><literal>s.get(Payment.class, id)</literal></entry>
+				<entry><literal>from Payment p</literal></entry>
+				<entry><literal>from Order o join o.payment p</literal></entry>
+				<entry><emphasis>支持</emphasis></entry>
+			</row>
+			<row>
+				<entry>每个子类一张表</entry>
+				<entry><literal>&lt;many-to-one&gt;</literal></entry>
+				<entry><literal>&lt;one-to-one&gt;</literal></entry>
+				<entry><literal>&lt;one-to-many&gt;</literal></entry>
+				<entry><literal>&lt;many-to-many&gt;</literal></entry>
+				<entry><literal>s.get(Payment.class, id)</literal></entry>
+				<entry><literal>from Payment p</literal></entry>
+				<entry><literal>from Order o join o.payment p</literal></entry>
+				<entry><emphasis>支持</emphasis></entry>
+			</row>
+            <row>
+
+                <entry>每个具体类一张表(union-subclass)</entry>
+                <entry><literal>&lt;many-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-one&gt;</literal></entry>
+                <entry><literal>&lt;one-to-many&gt;</literal> (仅对于<literal>inverse="true"</literal>的情况)</entry>
+                <entry><literal>&lt;many-to-many&gt;</literal></entry>
+                <entry><literal>s.get(Payment.class, id)</literal></entry>
+                <entry><literal>from Payment p</literal></entry>
+                <entry><literal>from Order o join o.payment p</literal></entry>
+                <entry><emphasis>支持</emphasis></entry>
+            </row>
+			<row>
+
+				<entry>每个具体类一张表(隐式多态)</entry>
+				<entry><literal>&lt;any&gt;</literal></entry>
+				<entry><emphasis>不支持</emphasis></entry>
+				<entry><emphasis>不支持</emphasis></entry>
+				<entry><literal>&lt;many-to-any&gt;</literal></entry>
+				<entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
+				<entry><literal>from Payment p</literal></entry>
+				<entry><emphasis>不支持</emphasis></entry>
+				<entry><emphasis>不支持</emphasis></entry>
+			</row>
+			</tbody>
+			</tgroup>
+		</table>		        
+
+        </sect1>
+            
+    </chapter>

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/kicken.pl
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/kicken.pl	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/kicken.pl	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+#!/bin/env perl
+
+use strict;
+use warnings;
+
+
+open(F, $ARGV[0]) or die "Can't open file $ARGV[0]: $!\n";
+  
+my $status = 1;
+
+READLINE:
+while (<F>) {
+  if (/\s+\+{3,}/) { 
+    $status = -1; 
+    next READLINE; 
+  }
+  if (/\s+-{3,}/) { 
+    $status = 1; 
+    next READLINE; 
+  }
+  if (/\s+={3,}/) { 
+    next READLINE; 
+  }
+  
+  if ($status < 0) { 
+    next READLINE; 
+  }
+  
+  print $_;
+}
+

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/performance.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/performance.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/performance.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1315 @@
+<chapter id="performance">
+    <title>提升性能
+	</title>
+    <sect1 id="performance-fetching" revision="2">
+        <title>
+			抓取策略(Fetching strategies)
+		</title>		
+
+        <para>
+	
+			<emphasis>抓取策略(fetching strategy)</emphasis> 是指:当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候,
+			Hibernate如何获取关联对象的策略。抓取策略可以在O/R映射的元数据中声明,也可以在特定的HQL
+			或<literal>条件查询(Criteria Query)</literal>中重载声明。			
+        </para>
+
+        <para>
+			Hibernate3 定义了如下几种抓取策略:
+        </para>
+		
+        <itemizedlist>
+             <listitem>
+				<para>
+	
+					<emphasis>连接抓取(Join fetching)</emphasis> - Hibernate通过
+					在<literal>SELECT</literal>语句使用<literal>OUTER JOIN</literal>(外连接)来
+					获得对象的关联实例或者关联集合。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+	
+				<emphasis>查询抓取(Select fetching)</emphasis> - 另外发送一条 <literal>SELECT</literal>
+                    语句抓取当前对象的关联实体或集合。除非你显式的指定<literal>lazy="false"</literal>禁止
+				延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。           
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+				 <emphasis>子查询抓取(Subselect fetching)</emphasis> - 另外发送一条<literal>SELECT</literal>
+				 语句抓取在前面查询到(或者抓取到)的所有实体对象的关联集合。除非你显式的指定<literal>lazy="false"</literal>
+				 禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+    
+	                <emphasis>批量抓取(Batch fetching)</emphasis> - 对查询抓取的优化方案,
+				通过指定一个主键或外键列表,Hibernate使用单条<literal>SELECT</literal>语句获取一批对象实例或集合。
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            Hibernate会区分下列各种情况:
+        </para>
+
+        <itemizedlist>
+             <listitem>
+                <para>
+                    <emphasis>Immediate fetching,立即抓取</emphasis> - 当宿主被加载时,关联、集合或属性被立即抓取。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Lazy collection fetching,延迟集合抓取</emphasis>- 直到应用程序对集合进行了一次操作时,集合才被抓取。(对集合而言这是默认行为。)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>"Extra-lazy" collection fetching,"Extra-lazy"集合抓取</emphasis> -对集合类中的每个元素而言,都是直到需要时才去访问数据库。除非绝对必要,Hibernate不会试图去把整个集合都抓取到内存里来(适用于非常大的集合)。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Proxy fetching,代理抓取</emphasis>  - 对返回单值的关联而言,当其某个方法被调用,而非对其关键字进行get操作时才抓取。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>"No-proxy" fetching,非代理抓取</emphasis> -  对返回单值的关联而言,当实例变量被访问的时候进行抓取。与上面的代理抓取相比,这种方法没有那么“延迟”得厉害(就算只访问标识符,也会导致关联抓取)但是更加透明,因为对应用程序来说,不再看到proxy。这种方法需要在编译期间进行字节码增强操作,因此很少需要用到。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>Lazy attribute fetching,属性延迟加载</emphasis> - 对属性或返回单值的关联而言,当其实例变量被访问的时候进行抓取。需要编译期字节码强化,因此这一方法很少是必要的。
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+        <para>
+            这里有两个正交的概念:关联<emphasis>何时</emphasis>被抓取,以及被<emphasis>如何</emphasis>抓取(会采用什么样的SQL语句)。不要混淆它们!我们使用<literal>抓取</literal>来改善性能。我们使用<literal>延迟</literal>来定义一些契约,对某特定类的某个脱管的实例,知道有哪些数据是可以使用的。
+        </para>
+ 
+        <sect2 id="performance-fetching-lazy">
+            <title>操作延迟加载的关联</title>
+            
+            <para>
+                默认情况下,Hibernate 3对集合使用延迟select抓取,对返回单值的关联使用延迟代理抓取。对几乎是所有的应用而言,其绝大多数的关联,这种策略都是有效的。
+            </para>
+            
+            <para>
+                <emphasis>注意:</emphasis>假若你设置了<literal>hibernate.default_batch_fetch_size</literal>,Hibernate会对延迟加载采取批量抓取优化措施(这种优化也可能会在更细化的级别打开)。
+            </para>
+            
+            <para>
+                然而,你必须了解延迟抓取带来的一个问题。在一个打开的Hibernate session上下文之外调用延迟集合会导致一次意外。比如:
+            </para>
+		
+            <programlisting><![CDATA[s = sessions.openSession();
+Transaction tx = s.beginTransaction();
+            
+User u = (User) s.createQuery("from User u where u.name=:userName")
+	.setString("userName", userName).uniqueResult();
+Map permissions = u.getPermissions();
+
+tx.commit();
+s.close();
+
+Integer accessLevel = (Integer) permissions.get("accounts");  // Error!]]></programlisting>
+
+        <para>
+		 在<literal>Session</literal>关闭后,permessions集合将是未实例化的、不再可用,因此无法正常载入其状态。
+            <emphasis>Hibernate对脱管对象不支持延迟实例化</emphasis>. 这里的修改方法是:将permissions读取数据的代码
+			移到tx.commit()之前。
+        </para>
+    		
+        <para>
+			除此之外,通过对关联映射指定<literal>lazy="false"</literal>,我们也可以使用非延迟的集合或关联。但是,
+			对绝大部分集合来说,更推荐使用延迟方式抓取数据。如果在你的对象模型中定义了太多的非延迟关联,Hibernate最终几乎需要在每个事务中载入整个数据库到内存中!
+        </para>
+
+        <para>
+         
+		    但是,另一方面,在一些特殊的事务中,我们也经常需要使用到连接抓取(它本身上就是非延迟的),以代替查询抓取。
+			下面我们将会很快明白如何具体的定制Hibernate中的抓取策略。在Hibernate3中,具体选择哪种抓取策略的机制是和选择
+			单值关联或集合关联相一致的。
+	    </para>
+    	        </sect2>
+        
+
+        <sect2 id="performance-fetching-custom" revision="4">
+            <title>
+			
+				调整抓取策略(Tuning fetch strategies)
+    		</title> 
+			
+			<para>
+			
+				查询抓取(默认的)在N+1查询的情况下是极其脆弱的,因此我们可能会要求在映射文档中定义使用连接抓取:
+			</para>		
+            <programlisting><![CDATA[<set name="permissions" 
+            fetch="join">
+    <key column="userId"/>
+    <one-to-many class="Permission"/>
+</set]]></programlisting>
+
+           <programlisting><![CDATA[<many-to-one name="mother" class="Cat" fetch="join"/>]]></programlisting>
+
+            <para>
+			    在映射文档中定义的<literal>抓取</literal>策略将会对以下列表条目产生影响:
+            </para>
+						
+        <itemizedlist>
+             <listitem>
+                <para>
+               
+			        通过<literal>get()</literal>或<literal>load()</literal>方法取得数据。
+			    </para>
+			</listitem>
+            <listitem>
+                <para>
+				    只有在关联之间进行导航时,才会隐式的取得数据。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+					<literal>条件查询</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    使用了<literal>subselect</literal>抓取的HQL查询
+                </para>
+            </listitem>
+        </itemizedlist>
+        
+            <para>
+                不管你使用哪种抓取策略,定义为非延迟的类图会被保证一定装载入内存。注意这可能意味着在一条HQL查询后紧跟着一系列的查询。
+            </para>
+
+            <para>
+			    通常情况下,我们并不使用映射文档进行抓取策略的定制。更多的是,保持其默认值,然后在特定的事务中,
+				使用HQL的<literal>左连接抓取(left join fetch)</literal> 对其进行重载。这将通知
+				Hibernate在第一次查询中使用外部关联(outer join),直接得到其关联数据。
+				在<literal>条件查询</literal> API中,应该调用 <literal>setFetchMode(FetchMode.JOIN)</literal>语句。
+            </para>
+            
+            <para>
+				也许你喜欢仅仅通过条件查询,就可以改变<literal>get()</literal> 
+				或 <literal>load()</literal>语句中的数据抓取策略。例如:
+            </para>
+            
+            <programlisting><![CDATA[User user = (User) session.createCriteria(User.class)
+            	.setFetchMode("permissions", FetchMode.JOIN)
+            	.add( Restrictions.idEq(userId) )
+            	.uniqueResult();]]></programlisting>
+            	
+            <para>
+             
+			    (这就是其他ORM解决方案的“抓取计划(fetch plan)”在Hibernate中的等价物。)
+            </para>
+   
+
+            <para>
+				截然不同的一种避免N+1次查询的方法是,使用二级缓存。
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-proxies" revision="2">
+            <title>单端关联代理(Single-ended association proxies)
+			</title>
+
+            <para>
+				在Hinerbate中,对集合的延迟抓取的采用了自己的实现方法。但是,对于单端关联的延迟抓取,则需要采用
+				其他不同的机制。单端关联的目标实体必须使用代理,Hihernate在运行期二进制级(通过优异的CGLIB库),
+				为持久对象实现了延迟载入代理。				
+            </para>
+
+            <para>
+				默认的,Hibernate3将会为所有的持久对象产生代理(在启动阶段),然后使用他们实现
+				<literal>多对一(many-to-one)</literal>关联和<literal>一对一(one-to-one)</literal>
+				关联的延迟抓取。
+            </para>
+
+            <para>
+				在映射文件中,可以通过设置<literal>proxy</literal>属性为目标class声明一个接口供代理接口使用。
+				默认的,Hibernate将会使用该类的一个子类。
+				<emphasis>注意:被代理的类必须实现一个至少包可见的默认构造函数,我们建议所有的持久类都应拥有这样的构造函数</emphasis>
+            </para>
+
+            <para>
+				在如此方式定义一个多态类的时候,有许多值得注意的常见性的问题,例如:
+            </para>
+
+            <programlisting><![CDATA[<class name="Cat" proxy="Cat">
+    ......
+    <subclass name="DomesticCat">
+        .....
+    </subclass>
+</class>]]></programlisting>
+
+            <para>
+				首先,<literal>Cat</literal>实例永远不可以被强制转换为<literal>DomesticCat</literal>,
+				即使它本身就是<literal>DomesticCat</literal>实例。				
+			 </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id);  // instantiate a proxy (does not hit the db)
+if ( cat.isDomesticCat() ) {                  // hit the db to initialize the proxy
+    DomesticCat dc = (DomesticCat) cat;       // Error!
+    ....
+}]]></programlisting>
+
+            <para>
+				其次,代理的“<literal>==</literal>”可能不再成立。
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id);            // instantiate a Cat proxy
+DomesticCat dc = 
+        (DomesticCat) session.load(DomesticCat.class, id);  // acquire new DomesticCat proxy!
+System.out.println(cat==dc);                            // false]]></programlisting>
+
+            <para>
+				虽然如此,但实际情况并没有看上去那么糟糕。虽然我们现在有两个不同的引用,分别指向这两个不同的代理对象,
+				但实际上,其底层应该是同一个实例对象: 
+            </para>
+
+            <programlisting><![CDATA[cat.setWeight(11.0);  // hit the db to initialize the proxy
+System.out.println( dc.getWeight() );  // 11.0]]></programlisting>
+
+            <para>
+				第三,你不能对“final类”或“具有final方法的类”使用CGLIB代理。 				
+            </para>
+
+            <para>
+				最后,如果你的持久化对象在实例化时需要某些资源(例如,在实例化方法、默认构造方法中),
+				那么代理对象也同样需要使用这些资源。实际上,代理类是持久化类的子类。 				
+            </para>
+
+            <para>
+			
+				这些问题都源于Java的单根继承模型的天生限制。如果你希望避免这些问题,那么你的每个持久化类必须实现一个接口,
+				在此接口中已经声明了其业务方法。然后,你需要在映射文档中再指定这些接口。例如: 
+            </para>
+
+            <programlisting><![CDATA[<class name="CatImpl" proxy="Cat">
+    ......
+    <subclass name="DomesticCatImpl" proxy="DomesticCat">
+        .....
+    </subclass>
+</class>]]></programlisting>
+
+            <para>
+				
+				这里<literal>CatImpl</literal>实现了<literal>Cat</literal>接口,
+				<literal>DomesticCatImpl</literal>实现<literal>DomesticCat</literal>接口。
+				在<literal>load()</literal>、<literal>iterate()</literal>方法中就会返回
+				<literal>Cat</literal>和<literal>DomesticCat</literal>的代理对象。
+				(注意<literal>list()</literal>并不会返回代理对象。)		
+            </para>
+
+            <programlisting><![CDATA[Cat cat = (Cat) session.load(CatImpl.class, catid);
+Iterator iter = session.iterate("from CatImpl as cat where cat.name='fritz'");
+Cat fritz = (Cat) iter.next();]]></programlisting>
+
+            <para>
+			
+				这里,对象之间的关系也将被延迟载入。这就意味着,你应该将属性声明为<literal>Cat</literal>,而不是<literal>CatImpl</literal>。
+            </para>
+
+            <para>
+		
+				但是,在有些方法中是<emphasis>不需要</emphasis>使用代理的。例如:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+						<literal>equals()</literal>方法,如果持久类没有重载<literal>equals()</literal>方法。						
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+						<literal>hashCode()</literal>方法,如果持久类没有重载<literal>hashCode()</literal>方法。
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+						标志符的getter方法。
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+				Hibernate将会识别出那些重载了<literal>equals()</literal>、或<literal>hashCode()</literal>方法的持久化类。
+            </para>
+            <para>
+                若选择<literal>lazy="no-proxy"</literal>而非默认的<literal>lazy="proxy"</literal>,我们可以避免类型转换带来的问题。然而,这样我们就需要编译期字节码增强,并且所有的操作都会导致立刻进行代理初始化。
+                
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-initialization" revision="1">
+            <title>实例化集合和代理(Initializing collections and proxies)
+			</title>
+
+            <para>
+				在<literal>Session</literal>范围之外访问未初始化的集合或代理,Hibernate将会抛出<literal>LazyInitializationException</literal>异常。
+				也就是说,在分离状态下,访问一个实体所拥有的集合,或者访问其指向代理的属性时,会引发此异常。
+            </para>
+
+            <para>
+			
+				有时候我们需要保证某个代理或者集合在Session关闭前就已经被初始化了。				
+				当然,我们可以通过强行调用<literal>cat.getSex()</literal>或者<literal>cat.getKittens().size()</literal>之类的方法来确保这一点。
+				但是这样的程序会造成读者的疑惑,也不符合通常的代码规范。				
+            </para>
+
+            <para>
+			
+				静态方法<literal>Hibernate.initialized()</literal>
+				为你的应用程序提供了一个便捷的途径来延迟加载集合或代理。
+				只要它的Session处于open状态,<literal>Hibernate.initialize(cat)</literal> 将会为cat强制对代理实例化。
+				同样,<literal>Hibernate.initialize( cat.getKittens() )</literal> 对kittens的集合具有同样的功能。 
+	        </para>
+
+            <para>
+			
+				还有另外一种选择,就是保持<literal>Session</literal>一直处于open状态,直到所有需要的集合或代理都被载入。
+				在某些应用架构中,特别是对于那些使用Hibernate进行数据访问的代码,以及那些在不同应用层和不同物理进程中使用Hibernate的代码。
+				在集合实例化时,如何保证<literal>Session</literal>处于open状态经常会是一个问题。有两种方法可以解决此问题:				
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+						在一个基于Web的应用中,可以利用servlet过滤器(filter),在用户请求(request)结束、页面生成
+						结束时关闭<literal>Session</literal>(这里使用了<emphasis>在展示层保持打开Session模式(Open Session in View)</emphasis>),
+						当然,这将依赖于应用框架中异常需要被正确的处理。在返回界面给用户之前,乃至在生成界面过程中发生异常的情况下,
+						正确关闭<literal>Session</literal>和结束事务将是非常重要的,
+                        请参见Hibernate wiki上的"Open Session in View"模式,你可以找到示例。
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+					
+						在一个拥有单独业务层的应用中,业务层必须在返回之前,为web层“准备”好其所需的数据集合。这就意味着
+						业务层应该载入所有表现层/web层所需的数据,并将这些已实例化完毕的数据返回。通常,应用程序应该
+						为web层所需的每个集合调用<literal>Hibernate.initialize()</literal>(这个调用必须发生咱session关闭之前);
+						或者使用带有<literal>FETCH</literal>从句,或<literal>FetchMode.JOIN</literal>的Hibernate查询,
+						事先取得所有的数据集合。如果你在应用中使用了<emphasis>Command</emphasis>模式,代替<emphasis>Session Facade</emphasis>						,
+						那么这项任务将会变得简单的多。
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+						你也可以通过<literal>merge()</literal>或<literal>lock()</literal>方法,在访问未实例化的集合(或代理)之前,
+						为先前载入的对象绑定一个新的<literal>Session</literal>。
+						显然,Hibernate将不会,也不<emphasis>应该</emphasis>自动完成这些任务,因为这将引入一个特殊的事务语义。
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+				有时候,你并不需要完全实例化整个大的集合,仅需要了解它的部分信息(例如其大小)、或者集合的部分内容。
+            </para>
+
+            <para>
+				
+				你可以使用集合过滤器得到其集合的大小,而不必实例化整个集合:
+            </para>
+
+            <programlisting><![CDATA[( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()]]></programlisting>
+
+            <para>
+				这里的<literal>createFilter()</literal>方法也可以被用来有效的抓取集合的部分内容,而无需实例化整个集合:
+            </para>
+
+            <programlisting><![CDATA[s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-batch">
+            <title>使用批量抓取(Using batch fetching)
+			</title>
+
+            <para>
+				Hibernate可以充分有效的使用批量抓取,也就是说,如果仅一个访问代理(或集合),那么Hibernate将不载入其他未实例化的代理。
+				批量抓取是延迟查询抓取的优化方案,你可以在两种批量抓取方案之间进行选择:在类级别和集合级别。				
+            </para>
+
+            <para>
+				
+				类/实体级别的批量抓取很容易理解。假设你在运行时将需要面对下面的问题:你在一个<literal>Session</literal>中载入了25个
+				<literal>Cat</literal>实例,每个<literal>Cat</literal>实例都拥有一个引用成员<literal>owner</literal>,
+				其指向<literal>Person</literal>,而<literal>Person</literal>类是代理,同时<literal>lazy="true"</literal>。
+				如果你必须遍历整个cats集合,对每个元素调用<literal>getOwner()</literal>方法,Hibernate将会默认的执行25次<literal>SELECT</literal>查询,
+				得到其owner的代理对象。这时,你可以通过在映射文件的<literal>Person</literal>属性,显式声明<literal>batch-size</literal>,改变其行为:
+				
+            </para>
+
+            <programlisting><![CDATA[<class name="Person" batch-size="10">...</class>]]></programlisting>
+
+            <para>
+				随之,Hibernate将只需要执行三次查询,分别为10、10、	5。
+            </para>
+
+            <para>
+				你也可以在集合级别定义批量抓取。例如,如果每个<literal>Person</literal>都拥有一个延迟载入的<literal>Cats</literal>集合,
+				现在,<literal>Sesssion</literal>中载入了10个person对象,遍历person集合将会引起10次<literal>SELECT</literal>查询,
+				每次查询都会调用<literal>getCats()</literal>方法。如果你在<literal>Person</literal>的映射定义部分,允许对<literal>cats</literal>批量抓取,
+				那么,Hibernate将可以预先抓取整个集合。请看例子:
+            </para>
+
+            <programlisting><![CDATA[<class name="Person">
+    <set name="cats" batch-size="3">
+        ...
+    </set>
+</class>]]></programlisting>
+
+            <para>
+				如果整个的<literal>batch-size</literal>是3(笔误?),那么Hibernate将会分四次执行<literal>SELECT</literal>查询,
+				按照3、3、3、1的大小分别载入数据。这里的每次载入的数据量还具体依赖于当前<literal>Session</literal>中未实例化集合的个数。
+            </para>
+
+            <para>
+				如果你的模型中有嵌套的树状结构,例如典型的帐单-原料结构(bill-of-materials pattern),集合的批量抓取是非常有用的。
+				(尽管在更多情况下对树进行读取时,<emphasis>嵌套集合(nested set)</emphasis>或<emphasis>原料路径(materialized path)</emphasis>(××)
+				 是更好的解决方法。)
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-fetching-subselect">
+            <title>使用子查询抓取(Using subselect fetching)
+			</title>
+            <para>
+                假若一个延迟集合或单值代理需要抓取,Hibernate会使用一个subselect重新运行原来的查询,一次性读入所有的实例。这和批量抓取的实现方法是一样的,不会有破碎的加载。
+            </para>
+            
+            <!-- TODO: Write more about this -->
+        </sect2>
+        
+        <sect2 id="performance-fetching-lazyproperties">
+            <title>使用延迟属性抓取(Using lazy property fetching)	
+			</title>
+
+            <para>
+				Hibernate3对单独的属性支持延迟抓取,这项优化技术也被称为<emphasis>组抓取(fetch groups)</emphasis>。
+				请注意,该技术更多的属于市场特性。在实际应用中,优化行读取比优化列读取更重要。但是,仅载入类的部分属性在某些特定情况下会有用,例如在原有表中拥有几百列数据、数据模型无法改动的情况下。
+            </para>
+
+            <para>
+				
+				可以在映射文件中对特定的属性设置<literal>lazy</literal>,定义该属性为延迟载入。
+            </para>
+
+            <programlisting><![CDATA[<class name="Document">
+       <id name="id">
+        <generator class="native"/>
+    </id>
+    <property name="name" not-null="true" length="50"/>
+    <property name="summary" not-null="true" length="200" lazy="true"/>
+    <property name="text" not-null="true" length="2000" lazy="true"/>
+</class>]]></programlisting>
+
+            <para>
+				
+				属性的延迟载入要求在其代码构建时加入二进制指示指令(bytecode instrumentation),如果你的持久类代码中未含有这些指令,
+				Hibernate将会忽略这些属性的延迟设置,仍然将其直接载入。
+            </para>
+
+            <para>
+				你可以在Ant的Task中,进行如下定义,对持久类代码加入“二进制指令。”
+            </para>
+
+            <programlisting><![CDATA[<target name="instrument" depends="compile">
+    <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
+        <classpath path="${jar.path}"/>
+        <classpath path="${classes.dir}"/>
+        <classpath refid="lib.class.path"/>
+    </taskdef>
+
+    <instrument verbose="true">
+        <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
+            <include name="*.class"/>
+        </fileset>
+    </instrument>
+</target>]]></programlisting>
+
+            <para>
+				
+				还有一种可以优化的方法,它使用HQL或条件查询的投影(projection)特性,可以避免读取非必要的列,
+				这一点至少对只读事务是非常有用的。它无需在代码构建时“二进制指令”处理,因此是一个更加值得选择的解决方法。				
+            </para>
+            
+            <para>
+				有时你需要在HQL中通过<literal>抓取所有属性</literal>,强行抓取所有内容。
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="performance-cache" revision="1">
+        <title>二级缓存(The Second Level Cache)
+		</title>
+
+        <para>
+			Hibernate的<literal>Session</literal>在事务级别进行持久化数据的缓存操作。
+   		    当然,也有可能分别为每个类(或集合),配置集群、或JVM级别(<literal>SessionFactory级别</literal>)的缓存。
+			你甚至可以为之插入一个集群的缓存。注意,缓存永远不知道其他应用程序对持久化仓库(数据库)可能进行的修改
+			(即使可以将缓存数据设定为定期失效)。 
+        </para>
+        
+        <para revision="1">
+            通过在<literal>hibernate.cache.provider_class</literal>属性中指定<literal>org.hibernate.cache.CacheProvider</literal>的某个实现的类名,你可以选择让Hibernate使用哪个缓存实现。Hibernate打包一些开源缓存实现,提供对它们的内置支持(见下表)。除此之外,你也可以实现你自己的实现,将它们插入到系统中。注意,在3.2版本之前,默认使用EhCache 作为缓存实现,但从3.2起就不再这样了。
+		</para>
+
+        <table frame="topbot" id="cacheproviders" revision="1">
+            <title>
+				缓存策略提供商(Cache Providers)
+			</title>
+            <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="3*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Cache</entry>
+              <entry>Provider class</entry>
+              <entry>Type</entry>
+              <entry>Cluster Safe</entry>
+              <entry>Query Cache Supported</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>Hashtable (not intended for production use)</entry>
+                <entry><literal>org.hibernate.cache.HashtableCacheProvider</literal></entry>
+                <entry>memory</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>EHCache</entry>
+                <entry><literal>org.hibernate.cache.EhCacheProvider</literal></entry>
+                <entry>memory, disk</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>OSCache</entry>
+                <entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
+                <entry>memory, disk</entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            <row>
+                <entry>SwarmCache</entry>
+                <entry><literal>org.hibernate.cache.SwarmCacheProvider</literal></entry>
+                <entry>clustered (ip multicast)</entry>
+                <entry>yes (clustered invalidation)</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>JBoss TreeCache</entry>
+                <entry><literal>org.hibernate.cache.TreeCacheProvider</literal></entry>
+                <entry>clustered (ip multicast), transactional</entry>
+                <entry>yes (replication)</entry>
+                <entry>yes (clock sync req.)</entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+        <sect2 id="performance-cache-mapping" revision="2">
+            <title>缓存映射(Cache mappings)
+			</title>
+
+            <para>
+				类或者集合映射的“<literal>&lt;cache&gt;</literal>元素”可以有下列形式: 
+            </para>
+
+            <programlistingco>
+                <areaspec>
+                    <area id="cache1" coords="2 70"/>
+                    <area id="cache2" coords="3 70"/>
+                    <area id="cache3" coords="4 70"/>
+                </areaspec>
+                <programlisting><![CDATA[<cache 
+    usage="transactional|read-write|nonstrict-read-write|read-only"
+    region="RegionName"
+    include="all|non-lazy"
+/>]]></programlisting>
+                <calloutlist>
+                    <callout arearefs="cache1">
+                        <para>
+						   
+						    <literal>usage</literal>(必须)说明了缓存的策略:
+                            <literal>transactional</literal>、
+                            <literal>read-write</literal>、
+                            <literal>nonstrict-read-write</literal>或 
+                            <literal>read-only</literal>。
+                        </para>
+                    </callout>                   
+                    <callout arearefs="cache2">
+                        <para>
+                            <literal>region</literal> (可选, 默认为类或者集合的名字(class or
+                            collection role name)) 指定第二级缓存的区域名(name of the second level cache 
+                            region)
+                            
+                        </para>
+                    </callout>                   
+                    <callout arearefs="cache3">
+                        <para>
+                            <literal>include</literal> (可选,默认为 <literal>all</literal>) 
+                            <literal>non-lazy</literal> 当属性级延迟抓取打开时, 标记为<literal>lazy="true"</literal>的实体的属性可能无法被缓存
+                        </para>
+                    </callout>                   
+                </calloutlist>
+            </programlistingco>
+            
+            <para>
+				另外(首选?), 你可以在hibernate.cfg.xml中指定<literal>&lt;class-cache&gt;</literal>和
+				<literal>&lt;collection-cache&gt;</literal> 元素。 				
+            </para>
+            
+            <para>
+                
+				这里的<literal>usage</literal> 属性指明了<emphasis>缓存并发策略(cache concurrency strategy)</emphasis>。
+			</para>
+
+        </sect2>
+
+        <sect2 id="performance-cache-readonly">
+            <title>策略:只读缓存(Strategy: read only)
+			</title>
+
+            <para>
+				如果你的应用程序只需读取一个持久化类的实例,而无需对其修改,
+				那么就可以对其进行<literal>只读</literal> 缓存。这是最简单,也是实用性最好的方法。甚至在集群中,它也能完美地运作。 
+            </para>
+
+            <programlisting><![CDATA[<class name="eg.Immutable" mutable="false">
+    <cache usage="read-only"/>
+    ....
+</class>]]></programlisting>
+
+        </sect2>
+
+
+        <sect2 id="performance-cache-readwrite">
+            <title>
+				策略:读/写缓存(Strategy: read/write)
+			</title>
+
+            <para>
+				
+				如果应用程序需要更新数据,那么使用<literal>读/写缓存</literal> 比较合适。
+				如果应用程序要求“序列化事务”的隔离级别(serializable transaction isolation level),那么就决不能使用这种缓存策略。
+				如果在JTA环境中使用缓存,你必须指定<literal>hibernate.transaction.manager_lookup_class</literal>属性的值,
+				通过它,Hibernate才能知道该应用程序中JTA的<literal>TransactionManager</literal>的具体策略。				
+				在其它环境中,你必须保证在<literal>Session.close()</literal>、或<literal>Session.disconnect()</literal>调用前,
+				整个事务已经结束。 如果你想在集群环境中使用此策略,你必须保证底层的缓存实现支持锁定(locking)。Hibernate内置的缓存策略并不支持锁定功能。 
+            </para>
+
+            <programlisting><![CDATA[<class name="eg.Cat" .... >
+    <cache usage="read-write"/>
+    ....
+    <set name="kittens" ... >
+        <cache usage="read-write"/>
+        ....
+    </set>
+</class>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-cache-nonstrict">
+            <title>
+				策略:非严格读/写缓存(Strategy: nonstrict read/write)				
+			</title>
+
+            <para>
+				
+				如果应用程序只偶尔需要更新数据(也就是说,两个事务同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离,
+				那么比较适合使用<literal>非严格读/写缓存</literal>策略。如果在JTA环境中使用该策略,
+				你必须为其指定<literal>hibernate.transaction.manager_lookup_class</literal>属性的值,
+				在其它环境中,你必须保证在<literal>Session.close()</literal>、或<literal>Session.disconnect()</literal>调用前,
+				整个事务已经结束。				
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-cache-transactional">
+            <title>
+				
+				策略:事务缓存(transactional)				
+			</title>
+
+            <para>
+				Hibernate的<literal>事务缓存</literal>策略提供了全事务的缓存支持,
+				例如对JBoss TreeCache的支持。这样的缓存只能用于JTA环境中,你必须指定
+			    为其<literal>hibernate.transaction.manager_lookup_class</literal>属性。 				
+            </para>
+
+        </sect2>
+        
+        <para>
+			没有一种缓存提供商能够支持上列的所有缓存并发策略。下表中列出了各种提供器、及其各自适用的并发策略。 			
+        </para>
+
+        <table frame="topbot">
+            <title>
+			各种缓存提供商对缓存并发策略的支持情况(Cache Concurrency Strategy Support)
+			</title>
+            <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+            <colspec colname='c1' colwidth="1*"/>
+            <colspec colname='c2' colwidth="1*"/>
+            <colspec colname='c3' colwidth="1*"/>
+            <colspec colname='c4' colwidth="1*"/>
+            <colspec colname='c5' colwidth="1*"/>
+            <thead>
+            <row>
+              <entry>Cache</entry>
+              <entry>read-only</entry>
+              <entry>nonstrict-read-write</entry>
+              <entry>read-write</entry>
+              <entry>transactional</entry>
+            </row>
+            </thead>
+            <tbody>
+            <row>
+                <entry>Hashtable (not intended for production use)</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>EHCache</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>OSCache</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>SwarmCache</entry>
+                <entry>yes</entry>
+                <entry>yes</entry>
+                <entry></entry>
+                <entry></entry>
+            </row>
+            <row>
+                <entry>JBoss TreeCache</entry>
+                <entry>yes</entry>
+                <entry></entry>
+                <entry></entry>
+                <entry>yes</entry>
+            </row>
+            </tbody>
+            </tgroup>
+        </table>
+
+    </sect1>
+
+    <sect1 id="performance-sessioncache" revision="2">
+        <title>
+			管理缓存(Managing the caches)
+    	</title>
+
+        <para>
+			无论何时,当你给<literal>save()</literal>、<literal>update()</literal>或
+            <literal>saveOrUpdate()</literal>方法传递一个对象时,或使用<literal>load()</literal>、
+			<literal>get()</literal>、<literal>list()</literal>、<literal>iterate()</literal>
+			或<literal>scroll()</literal>方法获得一个对象时,
+			该对象都将被加入到<literal>Session</literal>的内部缓存中。
+        </para>
+        <para>
+			当随后flush()方法被调用时,对象的状态会和数据库取得同步。
+			如果你不希望此同步操作发生,或者你正处理大量对象、需要对有效管理内存时,你可以调用<literal>evict()</literal>
+			方法,从一级缓存中去掉这些对象及其集合。 
+        </para>
+        
+        <programlisting><![CDATA[ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
+while ( cats.next() ) {
+    Cat cat = (Cat) cats.get(0);
+    doSomethingWithACat(cat);
+    sess.evict(cat);
+}]]></programlisting>
+        
+        <para>
+			Session还提供了一个<literal>contains()</literal>方法,用来判断某个实例是否处于当前session的缓存中。 
+        </para>
+        
+        <para>
+			如若要把所有的对象从session缓存中彻底清除,则需要调用<literal>Session.clear()</literal>。 
+        </para>
+        
+        <para>
+			对于二级缓存来说,在<literal>SessionFactory</literal>中定义了许多方法,
+			清除缓存中实例、整个类、集合实例或者整个集合。 			
+        </para>
+        
+        <programlisting><![CDATA[sessionFactory.evict(Cat.class, catId); //evict a particular Cat
+sessionFactory.evict(Cat.class);  //evict all Cats
+sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
+sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections]]></programlisting>
+
+        <para>
+			<literal>CacheMode</literal>参数用于控制具体的Session如何与二级缓存进行交互。
+        </para>
+        
+        <itemizedlist>
+        <listitem>
+        <para>
+			<literal>CacheMode.NORMAL</literal> - 从二级缓存中读、写数据。
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+			<literal>CacheMode.GET</literal> - 从二级缓存中读取数据,仅在数据更新时对二级缓存写数据。
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+			<literal>CacheMode.PUT</literal> - 仅向二级缓存写数据,但不从二级缓存中读数据。
+        </para>
+        </listitem>
+        <listitem>
+        <para>
+			<literal>CacheMode.REFRESH</literal> - 仅向二级缓存写数据,但不从二级缓存中读数据。通过
+			<literal>hibernate.cache.use_minimal_puts</literal>的设置,强制二级缓存从数据库中读取数据,刷新缓存内容。
+        </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+			如若需要查看二级缓存或查询缓存区域的内容,你可以使用<literal>统计(Statistics)</literal> API。
+        </para>
+        
+        <programlisting><![CDATA[Map cacheEntries = sessionFactory.getStatistics()
+        .getSecondLevelCacheStatistics(regionName)
+        .getEntries();]]></programlisting>
+        
+        <para>
+			此时,你必须手工打开统计选项。可选的,你可以让Hibernate更人工可读的方式维护缓存内容。
+        </para>
+        
+        <programlisting><![CDATA[hibernate.generate_statistics true
+hibernate.cache.use_structured_entries true]]></programlisting>       
+                
+    </sect1>
+    
+    <sect1 id="performance-querycache" revision="1">
+        <title>查询缓存(The Query Cache)
+		</title>
+
+        <para>
+			查询的结果集也可以被缓存。只有当经常使用同样的参数进行查询时,这才会有些用处。
+			要使用查询缓存,首先你必须打开它:			
+        </para>
+
+        <programlisting><![CDATA[hibernate.cache.use_query_cache true]]></programlisting>       
+        
+        <para>
+			
+			该设置将会创建两个缓存区域 - 一个用于保存查询结果集(<literal>org.hibernate.cache.StandardQueryCache</literal>);
+			另一个则用于保存最近查询的一系列表的时间戳(<literal>org.hibernate.cache.UpdateTimestampsCache</literal>)。
+			请注意:在查询缓存中,它并不缓存结果集中所包含的实体的确切状态;它只缓存这些实体的标识符属性的值、以及各值类型的结果。
+			所以查询缓存通常会和二级缓存一起使用。 
+        </para>
+        
+        <para>
+			
+			绝大多数的查询并不能从查询缓存中受益,所以Hibernate默认是不进行查询缓存的。如若需要进行缓存,请调用
+			<literal>Query.setCacheable(true)</literal>方法。这个调用会让查询在执行过程中时先从缓存中查找结果,
+			并将自己的结果集放到缓存中去。 
+        </para>
+        
+        <para>
+
+			如果你要对查询缓存的失效政策进行精确的控制,你必须调用<literal>Query.setCacheRegion()</literal>方法,
+			为每个查询指定其命名的缓存区域。 
+        </para>
+        
+        <programlisting><![CDATA[List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
+    .setEntity("blogger", blogger)
+    .setMaxResults(15)
+    .setCacheable(true)
+    .setCacheRegion("frontpages")
+    .list();]]></programlisting>
+
+        <para>
+			如果查询需要强行刷新其查询缓存区域,那么你应该调用<literal>Query.setCacheMode(CacheMode.REFRESH)</literal>方法。
+			这对在其他进程中修改底层数据(例如,不通过Hibernate修改数据),或对那些需要选择性更新特定查询结果集的情况特别有用。
+			这是对<literal>SessionFactory.evictQueries()</literal>的更为有效的替代方案,同样可以清除查询缓存区域。
+        </para>
+
+    </sect1>
+
+    <sect1 id="performance-collections">
+        <title>
+		理解集合性能(Understanding Collection performance)	
+		</title>
+
+        <para>
+			前面我们已经对集合进行了足够的讨论。本段中,我们将着重讲述集合在运行时的事宜。
+        </para>
+
+        <sect2 id="performance-collections-taxonomy">
+            <title>
+
+            分类(Taxonomy)
+			</title>
+
+            <para>
+			
+			Hibernate定义了三种基本类型的集合:	
+			</para>
+
+            <itemizedlist>
+            <listitem>
+                <para>
+				
+				值数据集合	
+				</para>
+            </listitem>
+            <listitem>
+                <para>
+				
+				一对多关联	
+				</para>
+            </listitem>
+            <listitem>
+                <para>
+				
+				多对多关联	
+				</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+				这个分类是区分了不同的表和外键关系类型,但是它没有告诉我们关系模型的所有内容。
+				要完全理解他们的关系结构和性能特点,我们必须同时考虑“用于Hibernate更新或删除集合行数据的主键的结构”。
+				因此得到了如下的分类: 
+            </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>
+				
+				有序集合类	
+				</para>
+            </listitem>
+            <listitem>
+                <para>
+				
+				集合(sets)	
+				</para>
+            </listitem>
+            <listitem>
+                <para>
+					
+				包(bags)
+				</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+				
+				所有的有序集合类(maps, lists, arrays)都拥有一个由<literal>&lt;key&gt;</literal>和
+				<literal>&lt;index&gt;</literal>组成的主键。
+				这种情况下集合类的更新是非常高效的——主键已经被有效的索引,因此当Hibernate试图更新或删除一行时,可以迅速找到该行数据。 
+	        </para>
+                        
+            <para>
+				
+				集合(sets)的主键由<literal>&lt;key&gt;</literal>和其他元素字段构成。
+				对于有些元素类型来说,这很低效,特别是组合元素或者大文本、大二进制字段;
+				数据库可能无法有效的对复杂的主键进行索引。
+				另一方面,对于一对多、多对多关联,特别是合成的标识符来说,集合也可以达到同样的高效性能。(
+				附注:如果你希望<literal>SchemaExport</literal>为你的<literal>&lt;set&gt;</literal>创建主键,
+				你必须把所有的字段都声明为<literal>not-null="true"</literal>。) 
+            </para>
+
+            <para>
+				
+				<literal>&lt;idbag&gt;</literal>映射定义了代理键,因此它总是可以很高效的被更新。事实上,
+				<literal>&lt;idbag&gt;</literal>拥有着最好的性能表现。
+            </para>
+            
+            <para>
+				Bag是最差的。因为bag允许重复的元素值,也没有索引字段,因此不可能定义主键。
+				Hibernate无法判断出重复的行。当这种集合被更改时,Hibernate将会先完整地移除
+				(通过一个(in a single <literal>DELETE</literal>))整个集合,然后再重新创建整个集合。
+				因此Bag是非常低效的。 
+            </para>
+
+            <para>
+				请注意:对于一对多关联来说,“主键”很可能并不是数据库表的物理主键。
+				但就算在此情况下,上面的分类仍然是有用的。(它仍然反映了Hibernate在集合的各数据行中是如何进行“定位”的。) 
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-collections-mostefficientupdate">
+            <title>				
+			Lists, maps 和sets用于更新效率最高
+			</title>
+
+            <para>
+				
+				根据我们上面的讨论,显然有序集合类型和大多数set都可以在增加、删除、修改元素中拥有最好的性能。 
+            </para>
+
+            <para>
+				可论证的是对于多对多关联、值数据集合而言,有序集合类比集合(set)有一个好处。因为<literal>Set</literal>的内在结构,
+				如果“改变”了一个元素,Hibernate并不会<literal>更新(UPDATE)</literal>这一行。
+				对于<literal>Set</literal>来说,只有在<literal>插入(INSERT)</literal>和<literal>删除(DELETE)</literal>
+				操作时“改变”才有效。再次强调:这段讨论对“一对多关联”并不适用。 				
+            </para>
+
+            <para>
+				注意到数组无法延迟载入,我们可以得出结论,list, map和idbags是最高效的(非反向)集合类型,set则紧随其后。
+				在Hibernate中,set应该时最通用的集合类型,这时因为“set”的语义在关系模型中是最自然的。
+            </para>
+
+            <para>
+				但是,在设计良好的Hibernate领域模型中,我们通常可以看到更多的集合事实上是带有<literal>inverse="true"</literal>
+				的一对多的关联。对于这些关联,更新操作将会在多对一的这一端进行处理。因此对于此类情况,无需考虑其集合的更新性能。
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-collections-mostefficentinverse">
+            <title>
+			Bag和list是反向集合类中效率最高的
+			</title>
+
+            <para>
+				在把bag扔进水沟之前,你必须了解,在一种情况下,bag的性能(包括list)要比set高得多:
+				对于指明了<literal>inverse="true"</literal>的集合类(比如说,标准的双向的一对多关联),
+				我们可以在未初始化(fetch)包元素的情况下直接向bag或list添加新元素!
+				这是因为<literal>Collection.add()</literal>)或者<literal>Collection.addAll()</literal> 方法
+				对bag或者List总是返回true(这点与与Set不同)。因此对于下面的相同代码来说,速度会快得多。 
+			</para>
+
+            <programlisting><![CDATA[Parent p = (Parent) sess.load(Parent.class, id);
+    Child c = new Child();
+    c.setParent(p);
+    p.getChildren().add(c);  //no need to fetch the collection!
+    sess.flush();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="performance-collections-oneshotdelete">
+            <title>
+			一次性删除(One shot delete)
+			</title>
+
+            <para>
+				偶尔的,逐个删除集合类中的元素是相当低效的。Hibernate并没那么笨, 
+				如果你想要把整个集合都删除(比如说调用list.clear()),Hibernate只需要一个DELETE就搞定了。 
+            </para>
+
+            <para>
+				假设我们在一个长度为20的集合类中新增加了一个元素,然后再删除两个。
+				Hibernate会安排一条<literal>INSERT</literal>语句和两条<literal>DELETE</literal>语句(除非集合类是一个bag)。
+				这当然是显而易见的。 
+            </para>
+
+            <para>
+				但是,假设我们删除了18个数据,只剩下2个,然后新增3个。则有两种处理方式: 			
+            </para>
+
+            <itemizedlist>
+            <listitem>
+                <para>
+				逐一的删除这18个数据,再新增三个;
+				</para>
+            </listitem>
+            <listitem>
+                <para>
+				删除整个集合类(只用一句DELETE语句),然后增加5个数据。 
+				</para>
+            </listitem>
+            </itemizedlist>
+
+            <para>
+				Hibernate还没那么聪明,知道第二种选择可能会比较快。
+				(也许让Hibernate不这么聪明也是好事,否则可能会引发意外的“数据库触发器”之类的问题。) 
+            </para>
+
+            <para>
+				幸运的是,你可以强制使用第二种策略。你需要取消原来的整个集合类(解除其引用),
+				然后再返回一个新的实例化的集合类,只包含需要的元素。有些时候这是非常有用的。
+            </para>
+            
+            <para>
+				显然,一次性删除并不适用于被映射为<literal>inverse="true"</literal>的集合。
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="performance-monitoring" revision="1">
+        <title>
+		监测性能(Monitoring performance)
+		</title>
+
+        <para>
+			没有监测和性能参数而进行优化是毫无意义的。Hibernate为其内部操作提供了一系列的示意图,因此可以从
+			每个<literal>SessionFactory</literal>抓取其统计数据。
+        </para>
+
+        <sect2 id="performance-monitoring-sf" revision="2">
+            <title>
+			监测SessionFactory	
+			</title>
+
+            <para>
+				你可以有两种方式访问<literal>SessionFactory</literal>的数据记录,第一种就是自己直接调用
+				<literal>sessionFactory.getStatistics()</literal>方法读取、显示<literal>统计</literal>数据。
+            </para>
+
+            <para>
+				此外,如果你打开<literal>StatisticsService</literal> MBean选项,那么Hibernate则可以使用JMX技术
+				发布其数据记录。你可以让应用中所有的<literal>SessionFactory</literal>同时共享一个MBean,也可以每个
+				SessionFactory分配一个MBean。下面的代码即是其演示代码:
+            </para>
+
+            <programlisting><![CDATA[// MBean service registration for a specific SessionFactory
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "myFinancialApp");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
+server.registerMBean(stats, on); // Register the Mbean on the server]]></programlisting>
+
+
+<programlisting><![CDATA[// MBean service registration for all SessionFactory's
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "all");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+server.registerMBean(stats, on); // Register the MBean on the server]]></programlisting>
+
+            <para>
+				
+				TODO:仍需要说明的是:在第一个例子中,我们直接得到和使用MBean;而在第二个例子中,在使用MBean之前
+				我们则需要给出SessionFactory的JNDI名,使用<literal>hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")</literal>
+				得到SessionFactory,然后将MBean保存于其中。
+            </para>
+            <para>
+				你可以通过以下方法打开或关闭<literal>SessionFactory</literal>的监测功能:
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+						
+						在配置期间,将<literal>hibernate.generate_statistics</literal>设置为<literal>true</literal>或<literal>false</literal>;
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <itemizedlist>
+                <listitem>
+                    <para>
+						
+						在运行期间,则可以可以通过<literal>sf.getStatistics().setStatisticsEnabled(true)</literal>
+                        或<literal>hibernateStatsBean.setStatisticsEnabled(true)</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+				你也可以在程序中调用<literal>clear()</literal>方法重置统计数据,调用<literal>logSummary()</literal>
+				在日志中记录(info级别)其总结。				
+            </para>
+
+        </sect2>
+
+        <sect2 id="performance-monitoring-metrics" revision="1">
+            <title>
+			数据记录(Metrics)
+			</title>
+
+            <para>
+				Hibernate提供了一系列数据记录,其记录的内容包括从最基本的信息到与具体场景的特殊信息。所有的测量值都可以由
+				<literal>Statistics</literal>接口进行访问,主要分为三类:
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+						使用<literal>Session</literal>的普通数据记录,例如打开的Session的个数、取得的JDBC的连接数等;
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+						实体、集合、查询、缓存等内容的统一数据记录
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+						和具体实体、集合、查询、缓存相关的详细数据记录
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+				例如:你可以检查缓存的命中成功次数,缓存的命中失败次数,实体、集合和查询的使用概率,查询的平均时间等。请注意
+				Java中时间的近似精度是毫秒。Hibernate的数据精度和具体的JVM有关,在有些平台上其精度甚至只能精确到10秒。
+            </para>
+
+            <para>
+				你可以直接使用getter方法得到全局数据记录(例如,和具体的实体、集合、缓存区无关的数据),你也可以在具体查询中通过标记实体名、
+				或HQL、SQL语句得到某实体的数据记录。请参考<literal>Statistics</literal>、<literal>EntityStatistics</literal>、
+                <literal>CollectionStatistics</literal>、<literal>SecondLevelCacheStatistics</literal>、
+                和<literal>QueryStatistics</literal>的API文档以抓取更多信息。下面的代码则是个简单的例子:
+            </para>
+
+            <programlisting><![CDATA[Statistics stats = HibernateUtil.sessionFactory.getStatistics();
+
+double queryCacheHitCount  = stats.getQueryCacheHitCount();
+double queryCacheMissCount = stats.getQueryCacheMissCount();
+double queryCacheHitRatio =
+  queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
+
+log.info("Query Hit ratio:" + queryCacheHitRatio);
+
+EntityStatistics entityStats =
+  stats.getEntityStatistics( Cat.class.getName() );
+long changes =
+        entityStats.getInsertCount()
+        + entityStats.getUpdateCount()
+        + entityStats.getDeleteCount();
+log.info(Cat.class.getName() + " changed " + changes + "times"  );]]></programlisting>
+
+            <para>
+				如果你想得到所有实体、集合、查询和缓存区的数据,你可以通过以下方法获得实体、集合、查询和缓存区列表:
+				<literal>getQueries()</literal>、<literal>getEntityNames()</literal>、
+				<literal>getCollectionRoleNames()</literal>和
+                <literal>getSecondLevelCacheRegionNames()</literal>。
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/persistent_classes.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/persistent_classes.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/persistent_classes.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,493 @@
+<chapter id="persistent-classes" revision="2">
+ 		<title>持久化类(Persistent Classes)</title>
+ 		
+    <para>
+        在应用程序中,用来实现业务问题实体的(如,在电子商务应用程序中的Customer和Order)
+        类就是持久化类。不能认为所有的持久化类的实例都是持久的状态——一个实例的状态也可能
+        是瞬时的或脱管的。
+   </para>
+    
+
+
+    <para>
+        如果这些持久化类遵循一些简单的规则,Hibernate能够工作得更好,这些规则也被称作
+        简单传统Java对象(POJO:Plain Old Java Object)编程模型。但是这些规则并不是必需的。
+        实际上,Hibernate3对于你的持久化类几乎不做任何设想。你可以用其他的方法来表达领域模型:
+        比如,使用<literal>Map</literal>实例的树型结构。
+    </para>
+
+
+    <sect1 id="persistent-classes-pojo">
+        <title>一个简单的POJO例子</title>
+        <para>
+            大多数Java程序需要用一个持久化类来表示猫科动物。
+        </para>
+
+
+        <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+public class Cat {
+    private Long id; // identifier
+
+    private Date birthdate;
+    private Color color;
+    private char sex;
+    private float weight;
+    private int litterId;
+
+    private Cat mother;
+    private Set kittens = new HashSet();
+
+    private void setId(Long id) {
+        this.id=id;
+    }
+    public Long getId() {
+        return id;
+    }
+
+    void setBirthdate(Date date) {
+        birthdate = date;
+    }
+    public Date getBirthdate() {
+        return birthdate;
+    }
+
+    void setWeight(float weight) {
+        this.weight = weight;
+    }
+    public float getWeight() {
+        return weight;
+    }
+
+    public Color getColor() {
+        return color;
+    }
+    void setColor(Color color) {
+        this.color = color;
+    }
+
+    void setSex(char sex) {
+        this.sex=sex;
+    }
+    public char getSex() {
+        return sex;
+    }
+
+    void setLitterId(int id) {
+        this.litterId = id;
+    }
+    public int getLitterId() {
+        return litterId;
+    }
+
+    void setMother(Cat mother) {
+        this.mother = mother;
+    }
+    public Cat getMother() {
+        return mother;
+    }
+    void setKittens(Set kittens) {
+        this.kittens = kittens;
+    }
+    public Set getKittens() {
+        return kittens;
+    }
+    
+    // addKitten not needed by Hibernate
+    public void addKitten(Cat kitten) {
+    	kitten.setMother(this);
+	kitten.setLitterId( kittens.size() ); 
+        kittens.add(kitten);
+    }
+}]]></programlisting>
+
+       <para>
+            这里要遵循四条主要的规则:
+        </para>
+
+
+        <sect2 id="persistent-classes-pojo-constructor" revision="1">
+            <title>实现一个默认的(即无参数的)构造方法(constructor)</title>
+            
+            <para>
+                <literal>Cat</literal>有一个无参数的构造方法。所有的持久化类都必须有一个
+                默认的构造方法(可以不是public的),这样的话Hibernate就可以使用
+                <literal>Constructor.newInstance()</literal>来实例化它们。
+                我们强烈建议,在Hibernate中,为了运行期代理的生成,构造方法至少是
+                <emphasis>包(package)</emphasis>内可见的。
+            </para>            
+            
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-identifier" revision="2">
+            <title>提供一个标识属性(identifier property)(可选) </title>
+
+       	  <para>
+                <literal>Cat</literal>有一个属性叫做<literal>id</literal>。这个属性映射数据库表的主
+                键字段。这个属性可以叫任何名字,其类型可以是任何的原始类型、原始类型的包装类型、
+                <literal>java.lang.String</literal> 或者是 <literal>java.util.Date</literal>。
+                (如果你的遗留数据库表有联合主键,你甚至可以用一个用户自定义的类,该类拥有这些类型
+                的属性。参见后面的关于联合标识符的章节。)
+            </para>
+
+
+            <para>
+                标识符属性是可选的。可以不用管它,让Hibernate内部来追踪对象的识别。
+                但是我们并不推荐这样做。
+            </para>
+
+            <para>
+                实际上,一些功能只对那些声明了标识符属性的类起作用:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+
+                   <para>
+                        托管对象的传播性再连接(级联更新或级联合并)
+                        ——参阅 <xref linkend="objectstate-transitive"/>
+                    </para>
+                      
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session.saveOrUpdate()</literal>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session.merge()</literal>
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+
+            <para>
+            	我们建议你对持久化类声明命名一致的标识属性。我们还建议你使用一
+            	个可以为空(也就是说,不是原始类型)的类型。
+            </para>
+            
+        </sect2>
+
+        <sect2 id="persistent-classes-pojo-final">
+            <title>使用非final的类 (可选)</title>
+           <para>
+            	<emphasis>代理(proxies)</emphasis>是Hibernate的一个重要的功能,它依赖的条件是,持久
+            	化类或者是非final的,或者是实现了一个所有方法都声明为public的接口。
+            </para>
+            
+
+            <para>
+            	你可以用Hibernate持久化一个没有实现任何接口的<literal>final</literal>类,但是你
+            	不能使用代理来延迟关联加载,这会限制你进行性能优化的选择。
+            </para>
+
+
+            <para> 
+            	你也应该避免在非final类中声明 <literal>public final</literal>的方法。如果你想使用一
+            	个有<literal>public final</literal>方法的类,你必须通过设置<literal>lazy="false"</literal>
+            	来明确地禁用代理。
+            </para>
+        </sect2>
+        
+        <sect2 id="persistent-classes-pojo-accessors" revision="2">
+		<title>为持久化字段声明访问器(accessors)和是否可变的标志(mutators)(可选)</title>
+
+            <para>
+                <literal>Cat</literal>为它的所有持久化字段声明了访问方法。很多其他ORM工具直接对
+                实例变量进行持久化。我们相信,在关系数据库schema和类的内部数据结构之间引入间接层(原文为"非直接",indirection)会好一些。默认情况下Hibernate持久化JavaBeans风格的属性,认可
+                <literal>getFoo</literal>,<literal>isFoo</literal> 和 <literal>setFoo</literal>这种形式的方法名。
+                如果需要,你可以对某些特定属性实行直接字段访问。
+            </para>
+
+
+            <para>
+                属性<emphasis>不需要</emphasis>要声明为public的。Hibernate可以持久化一个有
+                <literal>default</literal>、<literal>protected</literal>或<literal>private</literal>的get/set方法对
+                的属性进行持久化。
+            </para>
+        </sect2>
+    </sect1>
+
+    <sect1 id="persistent-classes-inheritance">
+        <title>实现继承(Inheritance)</title>
+        
+        <para>
+            子类也必须遵守第一条和第二条规则。它从超类<literal>Cat</literal>继承了标识属性。
+        </para>
+
+        <programlisting><![CDATA[package eg;
+
+public class DomesticCat extends Cat {
+        private String name;
+
+        public String getName() {
+                return name;
+        }
+        protected void setName(String name) {
+                this.name=name;
+        }
+}]]></programlisting>
+    </sect1>
+
+    <sect1 id="persistent-classes-equalshashcode" revision="1">
+        <title>实现<literal>equals()</literal>和<literal>hashCode()</literal></title>
+        
+        <para>
+            如果你有如下需求,你必须重载
+            <literal>equals()</literal> 和 <literal>hashCode()</literal>方法:
+        </para>     
+                
+        <itemizedlist spacing="compact">
+            <listitem>
+								<para> 
+										想把持久类的实例放入<literal>Set</literal>中(当表示多值关联时,推荐这么做)										
+								</para>
+            </listitem>
+            <listitem>
+                <para>
+                		想重用脱管实例
+                </para>
+            </listitem>
+        </itemizedlist>
+  
+				<para>
+						Hibernate保证,仅在特定会话范围内,持久化标识(数据库的行)和Java标识是等价的。因此,一旦
+						我们混合了从不同会话中获取的实例,如果希望<literal>Set</literal>有明确的语义,就必
+						须实现<literal>equals()</literal> 和<literal>hashCode()</literal>。
+				</para>
+
+				<para>
+						实现<literal>equals()</literal>/<literal>hashCode()</literal>最显而易见的方法是比较两个对象
+						标识符的值。如果值相同,则两个对象对应于数据库的同一行,因此它们是相等的(如果都被添加到
+						<literal>Set</literal>,则在<literal>Set</literal>中只有一个元素)。不幸的是,对生成的标识不能
+						使用这种方法。Hibernate仅对那些持久化对象赋标识值,一个新创建的实例将不会有任何标识值。此外,
+						如果一个实例没有被保存(unsaved),并且它当前正在一个<literal>Set</literal>中,保存它将会给这个对象
+						赋一个标识值。如果<literal>equals()</literal> 和 <literal>hashCode()</literal>是基于标识值
+						实现的,则其哈希码将会改变,这违反了<literal>Set</literal>的契约。建议去Hibernate的站点阅读关于这个
+						问题的全部讨论。注意,这不是Hibernate的问题,而是一般的Java对象标识和Java对象等价的语义问题。
+				</para>
+				<para>
+						我们建议使用<emphasis>业务键值相等(Business key equality)</emphasis>来实现<literal>equals()</literal>
+						和 <literal>hashCode()</literal>。业务键值相等的意思是,<literal>equals()</literal>方法
+						仅仅比较形成业务键的属性,它能在现实世界里标识我们的实例(是一个<emphasis>自然的</emphasis>候选码)。
+				</para>
+        <programlisting><![CDATA[public class Cat {
+
+    ...
+    public boolean equals(Object other) {
+        if (this == other) return true;
+        if ( !(other instanceof Cat) ) return false;
+
+        final Cat cat = (Cat) other;
+
+        if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
+        if ( !cat.getMother().equals( getMother() ) ) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result;
+        result = getMother().hashCode();
+        result = 29 * result + getLitterId();
+        return result;
+    }
+
+}]]></programlisting>
+
+				<para>
+						注意,业务键不必像数据库的主键那样固定不变(参见<xref linkend="transactions-basics-identity"/>)。
+						对业务键而言,不可变或唯一的属性是不错的选择。
+				</para>
+
+    </sect1>
+
+    <sect1 id="persistent-classes-dynamicmodels">
+				<title>动态模型(Dynamic models)</title>
+				<para>
+						<emphasis>注意,以下特性在当前处于试验阶段,将来可能会有变化。</emphasis>
+				</para>
+
+				<para>
+						运行期的持久化实体没有必要一定表示为像POJO类或JavaBean对象那样的形式。Hibernate也支持动态模型
+						(在运行期使用<literal>Map</literal>的<literal>Map</literal>)和象DOM4J的树模型那
+						样的实体表示。使用这种方法,你不用写持久化类,只写映射文件就行了。
+				</para>
+
+
+				<para>
+						Hibernate默认工作在普通POJO模式。你可以使用配置选项<literal>default_entity_mode</literal>,
+						对特定的<literal>SessionFactory</literal>,设置一个默认的实体表示模式。
+						(参见<xref linkend="configuration-optional-properties"/>。)
+				</para>
+
+				<para>
+						下面是用<literal>Map</literal>来表示的例子。首先,在映射文件中,要声明
+						<literal>entity-name</literal>来代替一个类名(或作为一种附属)。
+				</para>
+        <programlisting><![CDATA[<hibernate-mapping>
+
+    <class entity-name="Customer">
+
+        <id name="id"
+            type="long"
+            column="ID">
+            <generator class="sequence"/>
+        </id>
+
+        <property name="name"
+            column="NAME"
+            type="string"/>
+
+        <property name="address"
+            column="ADDRESS"
+            type="string"/>
+
+        <many-to-one name="organization"
+            column="ORGANIZATION_ID"
+            class="Organization"/>
+
+        <bag name="orders"
+            inverse="true"
+            lazy="false"
+            cascade="all">
+            <key column="CUSTOMER_ID"/>
+            <one-to-many class="Order"/>
+        </bag>
+
+    </class>
+    
+</hibernate-mapping>]]></programlisting>
+
+				<para>
+						注意,虽然是用目标类名来声明关联的,但是关联的目标类型除了是POJO之外,也可以
+						是一个动态的实体。
+				</para>
+
+				<para>
+						在使用<literal>dynamic-map</literal>为<literal>SessionFactory</literal>
+						设置了默认的实体模式之后,可以在运行期使用<literal>Map</literal>的
+						<literal>Map</literal>。
+				</para>
+
+        <programlisting><![CDATA[Session s = openSession();
+Transaction tx = s.beginTransaction();
+Session s = openSession();
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+
+// Create an organization
+Map foobar = new HashMap();
+foobar.put("name", "Foobar Inc.");
+
+// Link both
+david.put("organization", foobar);
+
+// Save both
+s.save("Customer", david);
+s.save("Organization", foobar);
+
+tx.commit();
+s.close();]]></programlisting>
+
+				<para>
+						动态映射的好处是,变化所需要的时间少了,因为原型不需要实现实体类。然而,你无法进行
+						编译期的类型检查,并可能由此会处理很多的运行期异常。幸亏有了Hibernate映射,它使得数
+						据库的schema能容易的规格化和合理化,并允许稍后在此之上添加合适的领域模型实现。
+				</para>
+
+
+				<para>
+						实体表示模式也能在每个<literal>Session</literal>的基础上设置:
+				</para>
+        <programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+dynamicSession.save("Customer", david);
+...
+dynamicSession.flush();
+dynamicSession.close()
+...
+// Continue on pojoSession
+]]></programlisting>
+
+
+
+				<para>
+						请注意,用<literal>EntityMode</literal>调用<literal>getSession()</literal>是在
+						<literal>Session</literal>的API中,而不是<literal>SessionFactory</literal>。
+						这样,新的<literal>Session</literal>共享底层的JDBC连接,事务,和其他的上下文信
+						息。这意味着,你不需要在第二个<literal>Session</literal>中调用
+						<literal>flush()</literal>和<literal>close()</literal>,同样的,把事务和连接的处理
+						交给原来的工作单元。
+				</para>
+
+
+				<para>
+						关于XML表示能力的更多信息可以在<xref linkend="xml"/>中找到。
+				</para>
+    </sect1>
+
+    <sect1 id="persistent-classes-tuplizers" revision="1">
+        <title>元组片断映射(Tuplizers)</title>
+
+        <para>
+            <literal>org.hibernate.tuple.Tuplizer</literal>,以及其子接口,负责根据给定的<literal>org.hibernate.EntityMode</literal>,来复现片断数据。如果给定的片断数据被认为其是一种数据结构,"tuplizer"就是一个知道如何创建这样的数据结构,以及如何给这个数据结构赋值的东西。比如说,对于POJO这种Entity Mode,对应的tuplizer知道通过其构造方法来创建一个POJO,再通过其属性访问器来访问POJO属性。有两大类高层Tuplizer,分别是<literal>org.hibernate.tuple.entity.EntityTuplizer</literal> 和<literal>org.hibernate.tuple.entity.ComponentTuplizer</literal>接口。<literal>EntityTuplizer</literal>负责管理上面提到的实体的契约,而<literal>ComponentTuplizer</literal>则是针对组件的。
+        </para>
+
+        <para>
+            用户也可以插入其自定义的tuplizer。或许您需要一种不同于dynamic-map entity-mode中使用的<literal>java.util.HashMap</literal>的<literal>java.util.Map</literal>实现;或许您需要与默认策略不同的代理生成策略(proxy generation strategy)。通过自定义tuplizer实现,这两个目标您都可以达到。Tuplizer定义被附加到它们期望管理的entity或者component映射中。回到我们的customer entity例子:
+        </para>
+
+        <programlisting><![CDATA[<hibernate-mapping>
+    <class entity-name="Customer">
+        <!--
+            Override the dynamic-map entity-mode
+            tuplizer for the customer entity
+        -->
+        <tuplizer entity-mode="dynamic-map"
+                class="CustomMapTuplizerImpl"/>
+
+        <id name="id" type="long" column="ID">
+            <generator class="sequence"/>
+        </id>
+
+        <!-- other properties -->
+        ...
+    </class>
+</hibernate-mapping>
+
+
+public class CustomMapTuplizerImpl
+        extends org.hibernate.tuple.entity.DynamicMapEntityTuplizer {
+    // override the buildInstantiator() method to plug in our custom map...
+    protected final Instantiator buildInstantiator(
+            org.hibernate.mapping.PersistentClass mappingInfo) {
+        return new CustomMapInstantiator( mappingInfo );
+    }
+
+    private static final class CustomMapInstantiator
+            extends org.hibernate.tuple.DynamicMapInstantitor {
+        // override the generateMap() method to return our custom map...
+	    protected final Map generateMap() {
+		    return new CustomMap();
+	    }
+    }
+}]]></programlisting>
+
+
+    </sect1>
+    
+    <para>
+    		TODO:property和proxy包里的用户扩展框架文档。
+    </para>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/query_criteria.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/query_criteria.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/query_criteria.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,424 @@
+<chapter id="querycriteria">
+    <title>
+    条件查询(Criteria Queries)
+    </title>
+    <para>
+        具有一个直观的、可扩展的条件查询API是Hibernate的特色。
+    </para>
+    
+    <sect1 id="querycriteria-creating">
+        <title>创建一个<literal>Criteria</literal> 实例</title>
+
+        <para>
+            <literal>org.hibernate.Criteria</literal>接口表示特定持久类的一个查询。<literal>Session</literal>是
+            <literal>Criteria</literal>实例的工厂。
+        </para>
+
+        <programlisting><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
+crit.setMaxResults(50);
+List cats = crit.list();]]></programlisting>
+
+    </sect1>
+     
+    <sect1 id="querycriteria-narrowing">
+        <title>限制结果集内容</title>
+
+        <para>
+            一个单独的查询条件是<literal>org.hibernate.criterion.Criterion</literal>
+            接口的一个实例。<literal>org.hibernate.criterion.Restrictions</literal>类
+            定义了获得某些内置<literal>Criterion</literal>类型的工厂方法。
+        </para>
+	
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .add( Restrictions.between("weight", minWeight, maxWeight) )
+    .list();]]></programlisting>
+    
+        <para>
+            约束可以按逻辑分组。
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .add( Restrictions.or(
+        Restrictions.eq( "age", new Integer(0) ),
+        Restrictions.isNull("age")
+    ) )
+    .list();]]></programlisting>
+    
+       <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
+    .add( Restrictions.disjunction()
+        .add( Restrictions.isNull("age") )
+    	.add( Restrictions.eq("age", new Integer(0) ) )
+    	.add( Restrictions.eq("age", new Integer(1) ) )
+    	.add( Restrictions.eq("age", new Integer(2) ) )
+    ) )
+    .list();]]></programlisting>
+    
+        <para>
+            Hibernate提供了相当多的内置criterion类型(<literal>Restrictions</literal>
+            子类), 但是尤其有用的是可以允许你直接使用SQL。
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.sqlRestriction("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
+    .list();]]></programlisting>
+    
+        <para>
+            <literal>{alias}</literal>占位符应当被替换为被查询实体的列别名。
+        </para>
+        
+        <para>
+             
+            <literal>Property</literal>实例是获得一个条件的另外一种途径。你可以通过调用<literal>Property.forName()</literal>
+            创建一个<literal>Property</literal>。
+           
+        </para>
+    
+        <programlisting><![CDATA[
+Property age = Property.forName("age");
+List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.disjunction()
+        .add( age.isNull() )
+    	.add( age.eq( new Integer(0) ) )
+    	.add( age.eq( new Integer(1) ) )
+    	.add( age.eq( new Integer(2) ) )
+    ) )
+    .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
+    .list();]]></programlisting>
+    
+   </sect1>
+     
+    <sect1 id="querycriteria-ordering">
+        <title>结果集排序</title>
+
+        <para>
+            你可以使用<literal>org.hibernate.criterion.Order</literal>来为查询结果排序。
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "F%")
+    .addOrder( Order.asc("name") )
+    .addOrder( Order.desc("age") )
+    .setMaxResults(50)
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Property.forName("name").like("F%") )
+    .addOrder( Property.forName("name").asc() )
+    .addOrder( Property.forName("age").desc() )
+    .setMaxResults(50)
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-associations"  revision="2">
+        <title>关联</title>
+
+        <para>
+            你可以使用<literal>createCriteria()</literal>非常容易的在互相关联的实体间建立
+            约束。
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "F%") )
+    .createCriteria("kittens")
+        .add( Restrictions.like("name", "F%") )
+    .list();]]></programlisting>
+
+        <para>
+            注意第二个 <literal>createCriteria()</literal>返回一个新的
+            <literal>Criteria</literal>实例,该实例引用<literal>kittens</literal> 集合中的元素。
+        </para>
+
+        <para>
+            接下来,替换形态在某些情况下也是很有用的。
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .createAlias("kittens", "kt")
+    .createAlias("mate", "mt")
+    .add( Restrictions.eqProperty("kt.name", "mt.name") )
+    .list();]]></programlisting>
+
+        <para>
+            
+            (<literal>createAlias()</literal>并不创建一个新的
+            <literal>Criteria</literal>实例。)
+        </para>
+
+        <para>
+            <literal>Cat</literal>实例所保存的之前两次查询所返回的kittens集合是
+            <emphasis>没有</emphasis>被条件预过滤的。如果你希望只获得符合条件的kittens,
+            你必须使用<literal>ResultTransformer</literal>。
+            
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .createCriteria("kittens", "kt")
+        .add( Restrictions.eq("name", "F%") )
+    .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+    .list();
+Iterator iter = cats.iterator();
+while ( iter.hasNext() ) {
+    Map map = (Map) iter.next();
+    Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
+    Cat kitten = (Cat) map.get("kt");
+}]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="querycriteria-dynamicfetching" revision="1">
+        <title>动态关联抓取</title>
+
+        <para>
+            你可以使用<literal>setFetchMode()</literal>在运行时定义动态关联抓取的语义。
+        </para>
+
+        <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+    .add( Restrictions.like("name", "Fritz%") )
+    .setFetchMode("mate", FetchMode.EAGER)
+    .setFetchMode("kittens", FetchMode.EAGER)
+    .list();]]></programlisting>
+    
+        <para>
+            这个查询可以通过外连接抓取<literal>mate</literal>和<literal>kittens</literal>。
+           查看<xref linkend="performance-fetching"/>可以获得更多信息。
+        </para>
+    
+    </sect1>
+     
+    <sect1 id="querycriteria-examples">
+        <title>查询示例</title>
+
+        <para>
+            <literal>org.hibernate.criterion.Example</literal>类允许你通过一个给定实例
+            构建一个条件查询。
+        </para>
+
+        <programlisting><![CDATA[Cat cat = new Cat();
+cat.setSex('F');
+cat.setColor(Color.BLACK);
+List results = session.createCriteria(Cat.class)
+    .add( Example.create(cat) )
+    .list();]]></programlisting>
+    
+        <para>
+           版本属性、标识符和关联被忽略。默认情况下值为null的属性将被排除。
+        </para>
+
+        <para>
+           你可以自行调整<literal>Example</literal>使之更实用。
+        </para>
+
+        <programlisting><![CDATA[Example example = Example.create(cat)
+    .excludeZeroes()           //exclude zero valued properties
+    .excludeProperty("color")  //exclude the property named "color"
+    .ignoreCase()              //perform case insensitive string comparisons
+    .enableLike();             //use like for string comparisons
+List results = session.createCriteria(Cat.class)
+    .add(example)
+    .list();]]></programlisting>
+    
+        <para>
+            你甚至可以使用examples在关联对象上放置条件。
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .add( Example.create(cat) )
+    .createCriteria("mate")
+        .add( Example.create( cat.getMate() ) )
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-projection">
+        <title>投影(Projections)、聚合(aggregation)和分组(grouping)</title>
+        <para>
+            <literal>org.hibernate.criterion.Projections</literal>是
+            <literal>Projection</literal> 的实例工厂。我们通过调用
+            <literal>setProjection()</literal>应用投影到一个查询。
+        </para>
+        
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.rowCount() )
+    .add( Restrictions.eq("color", Color.BLACK) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount() )
+        .add( Projections.avg("weight") )
+        .add( Projections.max("weight") )
+        .add( Projections.groupProperty("color") )
+    )
+    .list();]]></programlisting>
+    
+        <para>
+            在一个条件查询中没有必要显式的使用 "group by" 。某些投影类型就是被定义为<emphasis>
+            分组投影</emphasis>,他们也出现在SQL的<literal>group by</literal>子句中。
+        </para>
+    
+        <para>
+            你可以选择把一个别名指派给一个投影,这样可以使投影值被约束或排序所引用。下面是两种不同的实现方式:
+        </para>
+
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
+    .addOrder( Order.asc("colr") )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.groupProperty("color").as("colr") )
+    .addOrder( Order.asc("colr") )
+    .list();]]></programlisting>
+    
+        <para>
+            <literal>alias()</literal>和<literal>as()</literal>方法简便的将一个投影实例包装到另外一个
+            别名的<literal>Projection</literal>实例中。简而言之,当你添加一个投影到一个投影列表中时
+            你可以为它指定一个别名:
+        </para>
+
+       <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount(), "catCountByColor" )
+        .add( Projections.avg("weight"), "avgWeight" )
+        .add( Projections.max("weight"), "maxWeight" )
+        .add( Projections.groupProperty("color"), "color" )
+    )
+    .addOrder( Order.desc("catCountByColor") )
+    .addOrder( Order.desc("avgWeight") )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Domestic.class, "cat")
+    .createAlias("kittens", "kit")
+    .setProjection( Projections.projectionList()
+        .add( Projections.property("cat.name"), "catName" )
+        .add( Projections.property("kit.name"), "kitName" )
+    )
+    .addOrder( Order.asc("catName") )
+    .addOrder( Order.asc("kitName") )
+    .list();]]></programlisting>
+    
+        <para>
+            你也可以使用<literal>Property.forName()</literal>来表示投影:
+        </para>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Property.forName("name") )
+    .add( Property.forName("color").eq(Color.BLACK) )
+    .list();]]></programlisting>
+    
+        <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+    .setProjection( Projections.projectionList()
+        .add( Projections.rowCount().as("catCountByColor") )
+        .add( Property.forName("weight").avg().as("avgWeight") )
+        .add( Property.forName("weight").max().as("maxWeight") )
+        .add( Property.forName("color").group().as("color" )
+    )
+    .addOrder( Order.desc("catCountByColor") )
+    .addOrder( Order.desc("avgWeight") )
+    .list();]]></programlisting>
+    
+    </sect1>
+    
+    <sect1 id="querycriteria-detachedqueries">
+    	<title>离线(detached)查询和子查询</title>
+    	<para>
+    		<literal>DetachedCriteria</literal>类使你在一个session范围之外创建一个查询,并且可以使用任意的
+    		 <literal>Session</literal>来执行它。
+    	</para>
+    	
+    	<programlisting><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
+    .add( Property.forName("sex").eq('F') );
+    
+Session session = ....;
+Transaction txn = session.beginTransaction();
+List results = query.getExecutableCriteria(session).setMaxResults(100).list();
+txn.commit();
+session.close();]]></programlisting>
+
+		<para>
+			<literal>DetachedCriteria</literal>也可以用以表示子查询。条件实例包含子查询可以通过
+			<literal>Subqueries</literal>或者<literal>Property</literal>获得。
+		</para>
+		
+		<programlisting><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
+	.setProjection( Property.forName("weight").avg() );
+session.createCriteria(Cat.class)
+	.add( Property.forName("weight).gt(avgWeight) )
+	.list();]]></programlisting>
+	
+		<programlisting><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
+	.setProjection( Property.forName("weight") );
+session.createCriteria(Cat.class)
+	.add( Subqueries.geAll("weight", weights) )
+	.list();]]></programlisting>
+	
+		<para>
+			甚至相互关联的子查询也是有可能的:
+		</para>
+        
+		<programlisting><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
+	.setProjection( Property.forName("weight").avg() )
+	.add( Property.forName("cat2.sex").eqProperty("cat.sex") );
+session.createCriteria(Cat.class, "cat")
+	.add( Property.forName("weight).gt(avgWeightForSex) )
+	.list();]]></programlisting>
+	
+	</sect1>
+
+	
+		<!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer allow returning arbitrary 
+		          user objects - similar to setResultClass in JDO2. General use of ResultTransformer 
+		          could also be explained. -->
+		          
+    <sect1 id="query-criteria-naturalid">
+        <title>根据自然标识查询(Queries by natural identifier)</title>
+        
+        
+        <para>
+            对大多数查询,包括条件查询而言,因为查询缓存的失效(invalidation)发生得太频繁,查询缓存不是非常高效。然而,有一种特别的查询,可以通过不变的自然键优化缓存的失效算法。在某些应用中,这种类型的查询比较常见。条件查询API对这种用例提供了特别规约。
+        </para>
+        
+        <para>
+            首先,你应该对你的entity使用<literal>&lt;natural-id&gt;</literal>来映射自然键,然后打开第二级缓存。
+        </para>
+
+        <programlisting><![CDATA[<class name="User">
+    <cache usage="read-write"/>
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <natural-id>
+        <property name="name"/>
+        <property name="org"/>
+    </natural-id>
+    <property name="password"/>
+</class>]]></programlisting>
+    
+        <para>
+            注意,此功能对具有<emphasis>mutable</emphasis>自然键的entity并不适用。
+        </para>
+        
+        <para>
+            然后,打开Hibernate 查询缓存。
+        </para>
+        
+        <para>
+            现在,我们可以用<literal>Restrictions.naturalId()</literal>来使用更加高效的缓存算法。
+        </para>
+       
+        <programlisting><![CDATA[session.createCriteria(User.class)
+    .add( Restrictions.naturalId()
+        .set("name", "gavin")
+        .set("org", "hb") 
+    ).setCacheable(true)
+    .uniqueResult();]]></programlisting>
+            
+    </sect1>
+    
+		          
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/query_hql.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/query_hql.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/query_hql.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1088 @@
+<chapter id="queryhql">
+    <title>HQL: Hibernate查询语言</title>
+    <para>
+        Hibernate配备了一种非常强大的查询语言,这种语言看上去很像SQL。但是不要被语法结构
+        上的相似所迷惑,HQL是非常有意识的被设计为完全面向对象的查询,它可以理解如继承、多态
+        和关联之类的概念。
+    </para>
+
+    <sect1 id="queryhql-casesensitivity">
+        <title>大小写敏感性问题</title>
+
+        <para>
+            除了Java类与属性的名称外,查询语句对大小写并不敏感。
+            所以 <literal>SeLeCT</literal> 与
+            <literal>sELEct</literal> 以及
+            <literal>SELECT</literal> 是相同的,但是
+            <literal>org.hibernate.eg.FOO</literal> 并不等价于
+            <literal>org.hibernate.eg.Foo</literal> 并且
+            <literal>foo.barSet</literal> 也不等价于
+            <literal>foo.BARSET</literal>。
+        </para>
+        
+        <para>
+            本手册中的HQL关键字将使用小写字母. 很多用户发现使用完全大写的关键字会使查询语句
+	     的可读性更强, 但我们发现,当把查询语句嵌入到Java语句中的时候使用大写关键字比较难看。
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-from">
+        <title>from子句</title>
+
+        <para>
+            Hibernate中最简单的查询语句的形式如下:
+        </para>
+        
+        <programlisting><![CDATA[from eg.Cat]]></programlisting>
+        
+        <para>
+            该子句简单的返回<literal>eg.Cat</literal>类的所有实例。
+            通常我们不需要使用类的全限定名, 因为 <literal>auto-import</literal>(自动引入)
+            是缺省的情况。 所以我们几乎只使用如下的简单写法:
+        </para>
+        
+        <programlisting><![CDATA[from Cat]]></programlisting>
+        
+        <para>
+            大多数情况下, 你需要指定一个<emphasis>别名</emphasis>, 原因是你可能需要
+            在查询语句的其它部分引用到<literal>Cat</literal>
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+        <para>
+            这个语句把别名<literal>cat</literal>指定给类<literal>Cat</literal>
+            的实例, 这样我们就可以在随后的查询中使用此别名了。 关键字<literal>as</literal>
+            是可选的,我们也可以这样写:
+        </para>
+        
+        <programlisting><![CDATA[from Cat cat]]></programlisting>
+        
+        <para>
+            子句中可以同时出现多个类, 其查询结果是产生一个笛卡儿积或产生跨表的连接。
+        </para>
+        
+        <programlisting><![CDATA[from Formula, Parameter]]></programlisting>
+        <programlisting><![CDATA[from Formula as form, Parameter as param]]></programlisting>
+        
+        <para>
+            查询语句中别名的开头部分小写被认为是实践中的好习惯,
+            这样做与Java变量的命名标准保持了一致
+            (比如,<literal>domesticCat</literal>)。
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-joins" revision="2">
+        <title>关联(Association)与连接(Join)</title>
+
+        <para>
+            我们也可以为相关联的实体甚至是对一个集合中的全部元素指定一个别名, 这时要使用关键字<literal>join</literal>。
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    inner join cat.mate as mate
+    left outer join cat.kittens as kitten]]></programlisting>
+
+        <programlisting><![CDATA[from Cat as cat left join cat.mate.kittens as kittens]]></programlisting>
+
+        <programlisting><![CDATA[from Formula form full join form.parameter param]]></programlisting>
+
+        <para>
+            受支持的连接类型是从ANSI SQL中借鉴来的。
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>inner join</literal>(内连接)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>left outer join</literal>(左外连接)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>right outer join</literal>(右外连接)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>full join</literal> (全连接,并不常用)
+                </para>
+            </listitem>
+        </itemizedlist>
+    
+        <para>
+            语句<literal>inner join</literal>, <literal>left outer join</literal> 以及
+            <literal>right outer join</literal> 可以简写。
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    join cat.mate as mate
+    left join cat.kittens as kitten]]></programlisting>
+
+        <para>
+            通过HQL的<literal>with</literal>关键字,你可以提供额外的join条件。
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat 
+    left join cat.kittens as kitten 
+        with kitten.bodyWeight > 10.0]]></programlisting>
+
+        <para>
+            还有,一个"fetch"连接允许仅仅使用一个选择语句就将相关联的对象或一组值的集合随着他们的父对象的初始化而被初始化,这种方法在使用到集合的情况下尤其有用,对于关联和集合来说,它有效的代替了映射文件中的外联接
+            与延迟声明(lazy declarations). 查看
+            <xref linkend="performance-fetching"/> 以获得等多的信息。
+        </para>
+    
+        <programlisting><![CDATA[from Cat as cat 
+    inner join fetch cat.mate
+    left join fetch cat.kittens]]></programlisting>
+    
+        <para>
+            一个fetch连接通常不需要被指定别名, 因为相关联的对象不应当被用在
+            <literal>where</literal> 子句 (或其它任何子句)中。同时,相关联的对象
+            并不在查询的结果中直接返回,但可以通过他们的父对象来访问到他们。
+        </para>
+        
+        <programlisting><![CDATA[from Cat as cat 
+    inner join fetch cat.mate
+    left join fetch cat.kittens child
+    left join fetch child.kittens]]></programlisting>
+    
+
+            <para>
+            假若使用<literal>iterate()</literal>来调用查询,请注意<literal>fetch</literal>构造是不能使用的(<literal>scroll()</literal> 可以使用)。<literal>fetch</literal>也不应该与<literal>setMaxResults()</literal> 或<literal>setFirstResult()</literal>共用,这是因为这些操作是基于结果集的,而在预先抓取集合类时可能包含重复的数据,也就是说无法预先知道精确的行数。<literal>fetch</literal>还不能与独立的 <literal>with</literal>条件一起使用。通过在一次查询中fetch多个集合,可以制造出笛卡尔积,因此请多加注意。对bag映射来说,同时join fetch多个集合角色可能在某些情况下给出并非预期的结果,也请小心。最后注意,使用<literal>full join fetch</literal> 与 <literal>right join fetch</literal>是没有意义的。
+        </para>
+
+        <para>
+            如果你使用属性级别的延迟获取(lazy fetching)(这是通过重新编写字节码实现的),可以使用 <literal>fetch  
+all properties</literal> 
+            来强制Hibernate立即取得那些原本需要延迟加载的属性(在第一个查询中)。
+
+        </para>
+        
+        <programlisting><![CDATA[from Document fetch all properties order by name]]></programlisting>
+        <programlisting><![CDATA[from Document doc fetch all properties where lower(doc.name) like '%cats%']]></programlisting>
+            
+    </sect1>
+
+    <sect1 id="queryhql-joins-forms">
+        <title>join 语法的形式</title>
+
+	    <para>
+		    HQL支持两种关联join的形式:<literal>implicit(隐式)</literal> 与<literal>explicit(显式)</literal>。
+		</para>
+
+	    <para>
+		    上一节中给出的查询都是使用<literal>explicit(显式)</literal>形式的,其中form子句中明确给出了join关键字。这是建议使用的方式。
+	    </para>
+
+	    <para>
+		    <literal>implicit(隐式)</literal>形式不使用join关键字。关联使用"点号"来进行“引用”。<literal>implicit</literal> join可以在任何HQL子句中出现.<literal>implicit</literal> join在最终的SQL语句中以inner join的方式出现。
+	    </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.mate.name like '%s%']]></programlisting>
+	</sect1>
+
+    <sect1 id="queryhql-select">
+        <title>select子句</title>
+
+        <para>
+            <literal>select</literal> 子句选择将哪些对象与属性返
+            回到查询结果集中. 考虑如下情况:
+        </para>
+
+        <programlisting><![CDATA[select mate 
+from Cat as cat 
+    inner join cat.mate as mate]]></programlisting>
+
+        <para>
+            该语句将选择<literal>mate</literal>s of other <literal>Cat</literal>s。(其他猫的配偶)
+            实际上, 你可以更简洁的用以下的查询语句表达相同的含义:
+        </para>
+
+        <programlisting><![CDATA[select cat.mate from Cat cat]]></programlisting>
+
+        <para>
+            查询语句可以返回值为任何类型的属性,包括返回类型为某种组件(Component)的属性:
+        </para>
+
+        <programlisting><![CDATA[select cat.name from DomesticCat cat
+where cat.name like 'fri%']]></programlisting>
+
+        <programlisting><![CDATA[select cust.name.firstName from Customer as cust]]></programlisting>
+
+        <para>
+            查询语句可以返回多个对象和(或)属性,存放在
+            <literal>Object[]</literal>队列中,
+        </para>
+
+        <programlisting><![CDATA[select mother, offspr, mate.name 
+from DomesticCat as mother
+    inner join mother.mate as mate
+    left outer join mother.kittens as offspr]]></programlisting>
+    
+        <para>
+            或存放在一个<literal>List</literal>对象中,
+        </para>
+        
+        <programlisting><![CDATA[select new list(mother, offspr, mate.name)
+from DomesticCat as mother
+    inner join mother.mate as mate
+    left outer join mother.kittens as offspr]]></programlisting>
+    
+        <para>
+            也可能直接返回一个实际的类型安全的Java对象,
+        </para>
+        
+        <programlisting><![CDATA[select new Family(mother, mate, offspr)
+from DomesticCat as mother
+    join mother.mate as mate
+    left join mother.kittens as offspr]]></programlisting>
+        
+        <para>
+            假设类<literal>Family</literal>有一个合适的构造函数.
+        </para>
+        
+        <para>
+            你可以使用关键字<literal>as</literal>给“被选择了的表达式”指派别名:
+        </para>
+
+        <programlisting><![CDATA[select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
+from Cat cat]]></programlisting>
+
+        <para>
+            这种做法在与子句<literal>select new map</literal>一起使用时最有用:
+        </para>
+            
+        <programlisting><![CDATA[select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
+from Cat cat]]></programlisting>
+
+        <para>
+            该查询返回了一个<literal>Map</literal>的对象,内容是别名与被选择的值组成的名-值映射。
+        </para>
+         
+    </sect1>
+
+    <sect1 id="queryhql-aggregation">
+        <title>聚集函数</title>
+
+        <para>
+            HQL查询甚至可以返回作用于属性之上的聚集函数的计算结果:
+        </para>
+
+        <programlisting><![CDATA[select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
+from Cat cat]]></programlisting>
+
+<!-- 已经不再被继续支持
+        <para>
+            在<literal>select</literal>子句中,集合(Collections)也可以出现在聚集函数的内部。
+        </para>
+
+        <programlisting><![CDATA[select cat, count( elements(cat.kittens) ) 
+from Cat cat group by cat]]></programlisting>
+-->
+
+        <para>
+            受支持的聚集函数如下:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>avg(...), sum(...), min(...), max(...)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>count(*)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>count(...), count(distinct ...), count(all...)</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+    
+        <para>
+            你可以在选择子句中使用数学操作符、连接以及经过验证的SQL函数:
+        </para>
+        
+        <programlisting><![CDATA[select cat.weight + sum(kitten.weight) 
+from Cat cat 
+    join cat.kittens kitten
+group by cat.id, cat.weight]]></programlisting>
+    
+        <programlisting><![CDATA[select firstName||' '||initial||' '||upper(lastName) from Person]]></programlisting>
+    
+        <para>
+            关键字<literal>distinct</literal>与<literal>all</literal> 也可以使用,它们具有与SQL相同的语义.
+        </para>
+
+        <programlisting><![CDATA[select distinct cat.name from Cat cat
+
+select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
+
+    </sect1>
+    
+    <sect1 id="queryhql-polymorphism">
+        <title>多态查询</title>
+
+        <para>
+            一个如下的查询语句:
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+        <para>
+            不仅返回<literal>Cat</literal>类的实例, 也同时返回子类
+            <literal>DomesticCat</literal>的实例. Hibernate 可以在<literal>from</literal>子句中指定<emphasis>任何</emphasis> 
+            Java 类或接口. 查询会返回继承了该类的所有持久化子类
+            的实例或返回声明了该接口的所有持久化类的实例。下面的查询语句返回所有的被持久化的对象:        
+       </para>
+        
+        <programlisting><![CDATA[from java.lang.Object o]]></programlisting>
+        
+        <para>
+            接口<literal>Named</literal> 可能被各种各样的持久化类声明:
+        </para>
+        
+        <programlisting><![CDATA[from Named n, Named m where n.name = m.name]]></programlisting>
+        
+        <para>
+            注意,最后的两个查询将需要超过一个的SQL <literal>SELECT</literal>.这表明<literal>order by</literal>子句
+            没有对整个结果集进行正确的排序.
+            (这也说明你不能对这样的查询使用<literal>Query.scroll()</literal>方法.)
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-where">
+        <title>where子句</title>
+
+        <para>
+            <literal>where</literal>子句允许你将返回的实例列表的范围缩小.
+            如果没有指定别名,你可以使用属性名来直接引用属性:
+        </para>
+
+        <programlisting><![CDATA[from Cat where name='Fritz']]></programlisting>
+        
+        <para>
+        	如果指派了别名,需要使用完整的属性名:
+        </para>
+        
+        <programlisting><![CDATA[from Cat as cat where cat.name='Fritz']]></programlisting>
+
+        <para>
+            返回名为(属性name等于)'Fritz'的<literal>Cat</literal>类的实例。 
+        </para>
+
+        <programlisting><![CDATA[select foo 
+from Foo foo, Bar bar
+where foo.startDate = bar.date]]></programlisting>
+
+        <para>
+            将返回所有满足下面条件的<literal>Foo</literal>类的实例:
+            存在如下的<literal>bar</literal>的一个实例,其<literal>date</literal>属性等于
+            <literal>Foo</literal>的<literal>startDate</literal>属性。
+            复合路径表达式使得<literal>where</literal>子句非常的强大,考虑如下情况:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.mate.name is not null]]></programlisting>
+
+        <para>
+            该查询将被翻译成为一个含有表连接(内连接)的SQL查询。如果你打算写像这样的查询语句
+        </para>
+
+        <programlisting><![CDATA[from Foo foo  
+where foo.bar.baz.customer.address.city is not null]]></programlisting>
+
+        <para>
+            在SQL中,你为达此目的将需要进行一个四表连接的查询。
+        </para>
+
+        <para>
+            <literal>=</literal>运算符不仅可以被用来比较属性的值,也可以用来比较实例:
+        </para>
+
+        <programlisting><![CDATA[from Cat cat, Cat rival where cat.mate = rival.mate]]></programlisting>
+
+        <programlisting><![CDATA[select cat, mate 
+from Cat cat, Cat mate
+where cat.mate = mate]]></programlisting>
+
+        <para>
+            特殊属性(小写)<literal>id</literal>可以用来表示一个对象的唯一的标识符。(你也可以使用该对象的属性名。)
+        </para>
+
+        <programlisting><![CDATA[from Cat as cat where cat.id = 123
+
+from Cat as cat where cat.mate.id = 69]]></programlisting>
+
+        <para>
+            第二个查询是有效的。此时不需要进行表连接!
+        </para>
+
+        <para>
+            同样也可以使用复合标识符。比如<literal>Person</literal>类有一个复合标识符,它由<literal>country</literal>属性 
+            与<literal>medicareNumber</literal>属性组成。
+        </para>
+
+        <programlisting><![CDATA[from bank.Person person
+where person.id.country = 'AU' 
+    and person.id.medicareNumber = 123456]]></programlisting>
+
+        <programlisting><![CDATA[from bank.Account account
+where account.owner.id.country = 'AU' 
+    and account.owner.id.medicareNumber = 123456]]></programlisting>
+
+        <para>
+            第二个查询也不需要进行表连接。
+        </para>
+            
+        <para>
+            同样的,特殊属性<literal>class</literal>在进行多态持久化的情况下被用来存取一个实例的鉴别值(discriminator value)。
+            一个嵌入到where子句中的Java类的名字将被转换为该类的鉴别值。
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
+        
+        <para>
+            你也可以声明一个属性的类型是组件或者复合用户类型(以及由组件构成的组件等等)。永远不要尝试使用以组件类型来结尾的路径表达式(path-expression)
+            (与此相反,你应当使用组件的一个属性来结尾)。
+            举例来说,如果<literal>store.owner</literal>含有一个包含了组件的实体<literal>address</literal>
+        </para>
+
+        <programlisting><![CDATA[store.owner.address.city    // 正确
+store.owner.address         // 错误!]]></programlisting>
+
+        <para>
+            一个“任意”类型有两个特殊的属性<literal>id</literal>和<literal>class</literal>,
+            来允许我们按照下面的方式表达一个连接(<literal>AuditLog.item</literal>
+            是一个属性,该属性被映射为<literal>&lt;any&gt;</literal>)。
+        </para>
+       
+        <programlisting><![CDATA[from AuditLog log, Payment payment 
+where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting>
+    
+        <para>
+            注意,在上面的查询与句中,<literal>log.item.class</literal> 和 <literal>payment.class</literal>
+            将涉及到完全不同的数据库中的列。
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-expressions">
+        <title>表达式</title>
+
+        <para>
+            在<literal>where</literal>子句中允许使用的表达式包括
+            大多数你可以在SQL使用的表达式种类:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    数学运算符<literal>+, -, *, /</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    二进制比较运算符<literal>=, &gt;=, &lt;=, &lt;&gt;, !=, like</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    逻辑运算符<literal>and, or, not</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>in</literal>,
+                    <literal>not in</literal>,
+                    <literal>between</literal>,
+                    <literal>is null</literal>,
+                    <literal>is not null</literal>,
+                    <literal>is empty</literal>,
+                    <literal>is not empty</literal>,
+                    <literal>member of</literal> and 
+                    <literal>not member of</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                	"简单的" case, <literal>case ... when ... then ... else ... end</literal>,和
+                    "搜索" case, <literal>case when ... then ... else ... end</literal> 
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    字符串连接符<literal>...||...</literal> or <literal>concat(...,...)</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>current_date()</literal>, <literal>current_time()</literal>,
+                    <literal>current_timestamp()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+					<literal>second(...)</literal>, <literal>minute(...)</literal>, 
+					<literal>hour(...)</literal>, <literal>day(...)</literal>, 
+					<literal>month(...)</literal>, <literal>year(...)</literal>,
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    EJB-QL 3.0定义的任何函数或操作:<literal>substring(), trim(),
+                    lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>coalesce()</literal> 和 <literal>nullif()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>str()</literal> 把数字或者时间值转换为可读的字符串
+                </para>
+            </listitem>
+            
+            <listitem>
+                <para>
+                    <literal>cast(... as ...)</literal>, 其第二个参数是某Hibernate类型的名字,以及<literal>extract(... from ...)</literal>,只要ANSI 
+                    <literal>cast()</literal> 和 <literal>extract()</literal> 被底层数据库支持
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    HQL <literal>index()</literal> 函数,作用于join的有序集合的别名。
+                    
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    HQL函数,把集合作为参数:<literal>size(), minelement(), maxelement(), minindex(), maxindex()</literal>,还有特别的<literal>elements()</literal> 和<literal>indices</literal>函数,可以与数量词加以限定:<literal>some, all, exists, any, in</literal>。
+                    
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                任何数据库支持的SQL标量函数,比如<literal>sign()</literal>, 
+                    <literal>trunc()</literal>, <literal>rtrim()</literal>, <literal>sin()</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    JDBC风格的参数传入 <literal>?</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    命名参数<literal>:name</literal>, <literal>:start_date</literal>, <literal>:x1</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    SQL 直接常量 <literal>'foo'</literal>, <literal>69</literal>, <literal>6.66E+2</literal>, <literal>'1970-01-01 10:00:01.0'</literal>
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    Java <literal>public static final</literal> 类型的常量 <literal>eg.Color.TABBY</literal>
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            关键字<literal>in</literal>与<literal>between</literal>可按如下方法使用:
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name between 'A' and 'B']]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+        <para>
+            而且否定的格式也可以如下书写:
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name not between 'A' and 'B']]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+        <para>
+            同样, 子句<literal>is null</literal>与<literal>is not null</literal>可以被用来测试空值(null).
+        </para>
+
+        <para>
+            在Hibernate配置文件中声明HQL“查询替代(query substitutions)”之后,
+            布尔表达式(Booleans)可以在其他表达式中轻松的使用:
+        </para>
+
+        <programlisting><![CDATA[<property name="hibernate.query.substitutions">true 1, false 0</property>]]></programlisting>
+
+        <para>
+            系统将该HQL转换为SQL语句时,该设置表明将用字符 <literal>1</literal> 和  
+<literal>0</literal> 来
+            取代关键字<literal>true</literal> 和 <literal>false</literal>:
+
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.alive = true]]></programlisting>
+
+        <para>
+            你可以用特殊属性<literal>size</literal>, 或是特殊函数<literal>size()</literal>测试一个集合的大小。
+        </para>
+
+        <programlisting><![CDATA[from Cat cat where cat.kittens.size > 0]]></programlisting>
+
+        <programlisting><![CDATA[from Cat cat where size(cat.kittens) > 0]]></programlisting>
+
+        <para>
+            对于索引了(有序)的集合,你可以使用<literal>minindex</literal> 与 <literal>maxindex</literal>函数来引用到最小与最大的索引序数。
+            同理,你可以使用<literal>minelement</literal> 与 <literal>maxelement</literal>函数来 
+引用到一个基本数据类型的集合中最小与最大的元素。
+
+        </para>
+        
+        <programlisting><![CDATA[from Calendar cal where maxelement(cal.holidays) > current_date]]></programlisting>
+        
+        <programlisting><![CDATA[from Order order where maxindex(order.items) > 100]]></programlisting>
+
+        <programlisting><![CDATA[from Order order where minelement(order.items) > 10000]]></programlisting>
+        
+        <para>
+在传递一个集合的索引集或者是元素集(<literal>elements</literal>与<literal>indices</literal> 函数)
+            或者传递一个子查询的结果的时候,可以使用SQL函数<literal>any, some, all, exists, in</literal>
+
+        </para>
+
+        <programlisting><![CDATA[select mother from Cat as mother, Cat as kit
+where kit in elements(foo.kittens)]]></programlisting>
+
+        <programlisting><![CDATA[select p from NameList list, Person p
+where p.name = some elements(list.names)]]></programlisting>
+
+        <programlisting><![CDATA[from Cat cat where exists elements(cat.kittens)]]></programlisting>
+
+        <programlisting><![CDATA[from Player p where 3 > all elements(p.scores)]]></programlisting>
+
+        <programlisting><![CDATA[from Show show where 'fizard' in indices(show.acts)]]></programlisting>
+
+        <para>
+            注意,在Hibernate3种,这些结构变量- <literal>size</literal>, <literal>elements</literal>,
+            <literal>indices</literal>, <literal>minindex</literal>, <literal>maxindex</literal>,
+            <literal>minelement</literal>, <literal>maxelement</literal> - 只能在where子句中使用。
+        </para>
+        
+        <para>
+            一个被索引过的(有序的)集合的元素(arrays, lists, maps)可以在其他索引中被引用(只能在where子句中):
+        </para>
+        
+        <programlisting><![CDATA[from Order order where order.items[0].id = 1234]]></programlisting>
+
+        <programlisting><![CDATA[select person from Person person, Calendar calendar
+where calendar.holidays['national day'] = person.birthDay
+    and person.nationality.calendar = calendar]]></programlisting>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11]]></programlisting>
+
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ maxindex(order.items) ] = item and order.id = 11]]></programlisting>
+
+        <para>
+            在<literal>[]</literal>中的表达式甚至可以是一个算数表达式。
+        </para>
+        
+        <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ size(order.items) - 1 ] = item]]></programlisting>
+        
+        <para>
+            对于一个一对多的关联(one-to-many association)或是值的集合中的元素,
+            HQL也提供内建的<literal>index()</literal>函数,
+        </para>
+
+        <programlisting><![CDATA[select item, index(item) from Order order 
+    join order.items item
+where index(item) < 5]]></programlisting>
+
+        <para>
+            如果底层数据库支持标量的SQL函数,它们也可以被使用
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like 'FRI%']]></programlisting>
+
+        <para>
+            如果你还不能对所有的这些深信不疑,想想下面的查询。如果使用SQL,语句长度会增长多少,可读性会下降多少:
+        </para>
+
+        <programlisting><![CDATA[select cust
+from Product prod,
+    Store store
+    inner join store.customers cust
+where prod.name = 'widget'
+    and store.location.name in ( 'Melbourne', 'Sydney' )
+    and prod = all elements(cust.currentOrder.lineItems)]]></programlisting>
+
+        <para>
+            <emphasis>提示:</emphasis> 会像如下的语句
+        </para>
+
+        <programlisting><![CDATA[SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
+FROM customers cust,
+    stores store,
+    locations loc,
+    store_customers sc,
+    product prod
+WHERE prod.name = 'widget'
+    AND store.loc_id = loc.id
+    AND loc.name IN ( 'Melbourne', 'Sydney' )
+    AND sc.store_id = store.id
+    AND sc.cust_id = cust.id
+    AND prod.id = ALL(
+        SELECT item.prod_id
+        FROM line_items item, orders o
+        WHERE item.order_id = o.id
+            AND cust.current_order = o.id
+    )]]></programlisting>
+
+    </sect1>
+
+    <sect1 id="queryhql-ordering">
+        <title>order by子句</title>
+
+        <para>
+            查询返回的列表(list)可以按照一个返回的类或组件(components)中的任何属性(property)进行排序:
+        </para>
+
+        <programlisting><![CDATA[from DomesticCat cat
+order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
+
+        <para>
+            可选的<literal>asc</literal>或<literal>desc</literal>关键字指明了按照升序或降序进行排序.
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-grouping" revision="1">
+        <title>group by子句</title>
+
+        <para>
+            一个返回聚集值(aggregate values)的查询可以按照一个返回的类或组件(components)中的任何属性(property)进行分组:
+        </para>
+
+        <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat) 
+from Cat cat
+group by cat.color]]></programlisting>
+
+        <programlisting><![CDATA[select foo.id, avg(name), max(name) 
+from Foo foo join foo.names name
+group by foo.id]]></programlisting>
+
+        <para>
+            <literal>having</literal>子句在这里也允许使用.
+        </para>
+
+        <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat) 
+from Cat cat
+group by cat.color 
+having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
+
+        <para>
+            如果底层的数据库支持的话(例如不能在MySQL中使用),SQL的一般函数与聚集函数也可以出现
+            在<literal>having</literal>与<literal>order by</literal> 子句中。    
+        </para>
+
+        <programlisting><![CDATA[select cat
+from Cat cat
+    join cat.kittens kitten
+group by cat.id, cat.name, cat.other, cat.properties
+having avg(kitten.weight) > 100
+order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
+
+        <para>
+            注意<literal>group by</literal>子句与
+            <literal>order by</literal>子句中都不能包含算术表达式(arithmetic expressions).
+            
+			也要注意Hibernate目前不会扩展group的实体,因此你不能写<literal>group by cat</literal>,除非<literal>cat</literal>的所有属性都不是聚集的(non-aggregated)。你必须明确的列出所有的非聚集属性。
+        </para>
+
+    </sect1>
+
+    
+    <sect1 id="queryhql-subqueries"  revision="2">
+        <title>子查询</title>
+        
+        <para>
+            对于支持子查询的数据库,Hibernate支持在查询中使用子查询。一个子查询必须被圆括号包围起来(经常是SQL聚集函数的圆括号)。
+            甚至相互关联的子查询(引用到外部查询中的别名的子查询)也是允许的。
+        </para>
+
+        <programlisting><![CDATA[from Cat as fatcat 
+where fatcat.weight > ( 
+    select avg(cat.weight) from DomesticCat cat 
+)]]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat as cat 
+where cat.name = some ( 
+    select name.nickName from Name as name 
+)]]></programlisting>
+    
+        <programlisting><![CDATA[from Cat as cat 
+where not exists ( 
+    from Cat as mate where mate.mate = cat 
+)]]></programlisting>
+
+        <programlisting><![CDATA[from DomesticCat as cat 
+where cat.name not in ( 
+    select name.nickName from Name as name 
+)]]></programlisting>
+
+        <programlisting><![CDATA[select cat.id, (select max(kit.weight) from cat.kitten kit) 
+from Cat as cat]]></programlisting>
+
+        <para>
+            注意,HQL自查询只可以在select或者where子句中出现。
+        </para>
+
+        <para>
+            在select列表中包含一个表达式以上的子查询,你可以使用一个元组构造符(tuple constructors): 
+        </para>
+        
+        <programlisting><![CDATA[from Cat as cat 
+where not ( cat.name, cat.color ) in ( 
+    select cat.name, cat.color from DomesticCat cat 
+)]]></programlisting>
+
+        <para>
+            注意在某些数据库中(不包括Oracle与HSQL),你也可以在其他语境中使用元组构造符,
+            比如查询用户类型的组件与组合:
+        </para>
+
+        <programlisting><![CDATA[from Person where name = ('Gavin', 'A', 'King')]]></programlisting>
+        
+        <para>
+            该查询等价于更复杂的:
+        </para>
+        
+        <programlisting><![CDATA[from Person where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')]]></programlisting>
+
+        <para>
+            有两个很好的理由使你不应当作这样的事情:首先,它不完全适用于各个数据库平台;其次,查询现在依赖于映射文件中属性的顺序。
+        </para>
+        
+    </sect1>
+
+    <sect1 id="queryhql-examples">
+        <title>HQL示例</title>
+        
+        <para>
+            Hibernate查询可以非常的强大与复杂。实际上,Hibernate的一个主要卖点就是查询语句的威力。这里有一些例子,它们与我在最近的
+            一个项目中使用的查询非常相似。注意你能用到的大多数查询比这些要简单的多!
+        </para>
+        
+        <para>
+            下面的查询对于某个特定的客户的所有未支付的账单,在给定给最小总价值的情况下,返回订单的id,条目的数量和总价值,
+            返回值按照总价值的结果进行排序。为了决定价格,查询使用了当前目录。作为转换结果的SQL查询,使用了<literal>ORDER</literal>, 
+            <literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>, <literal>CATALOG</literal> 和<literal>PRICE</literal>
+            库表。
+        </para>
+        
+        <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+    join order.lineItems as item
+    join item.product as product,
+    Catalog as catalog
+    join catalog.prices as price
+where order.paid = false
+    and order.customer = :customer
+    and price.product = product
+    and catalog.effectiveDate < sysdate
+    and catalog.effectiveDate >= all (
+        select cat.effectiveDate 
+        from Catalog as cat
+        where cat.effectiveDate < sysdate
+    )
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+        
+        <para>
+            这简直是一个怪物!实际上,在现实生活中,我并不热衷于子查询,所以我的查询语句看起来更像这个:
+        </para>
+        
+        <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+    join order.lineItems as item
+    join item.product as product,
+    Catalog as catalog
+    join catalog.prices as price
+where order.paid = false
+    and order.customer = :customer
+    and price.product = product
+    and catalog = :currentCatalog
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+        
+        <para>
+            下面一个查询计算每一种状态下的支付的数目,除去所有处于<literal>AWAITING_APPROVAL</literal>状态的支付,因为在该状态下
+            当前的用户作出了状态的最新改变。该查询被转换成含有两个内连接以及一个相关联的子选择的SQL查询,该查询使用了表
+            <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal> 以及 
+            <literal>PAYMENT_STATUS_CHANGE</literal>。
+        </para>
+
+        <programlisting><![CDATA[select count(payment), status.name 
+from Payment as payment 
+    join payment.currentStatus as status
+    join payment.statusChanges as statusChange
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+    or (
+        statusChange.timeStamp = ( 
+            select max(change.timeStamp) 
+            from PaymentStatusChange change 
+            where change.payment = payment
+        )
+        and statusChange.user <> :currentUser
+    )
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+        <para>
+            如果我把<literal>statusChanges</literal>实例集映射为一个列表(list)而不是一个集合(set), 
+            书写查询语句将更加简单.
+        </para>
+    
+        <programlisting><![CDATA[select count(payment), status.name 
+from Payment as payment
+    join payment.currentStatus as status
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+    or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+        <para>
+            下面一个查询使用了MS SQL Server的 <literal>isNull()</literal>函数用以返回当前用户所属组织的组织帐号及组织未支付的账。
+            它被转换成一个对表<literal>ACCOUNT</literal>, <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal>,
+            <literal>ACCOUNT_TYPE</literal>, <literal>ORGANIZATION</literal> 以及 <literal>ORG_USER</literal>进行的三个内连接,
+            一个外连接和一个子选择的SQL查询。
+        </para>
+
+        <programlisting><![CDATA[select account, payment
+from Account as account
+    left outer join account.payments as payment
+where :currentUser in elements(account.holder.users)
+    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+        <para>
+            对于一些数据库,我们需要弃用(相关的)子选择。
+        </para>
+
+        <programlisting><![CDATA[select account, payment
+from Account as account
+    join account.holder.users as user
+    left outer join account.payments as payment
+where :currentUser = user
+    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+   </sect1>
+
+    <sect1 id="queryhql-bulk"  revision="2">
+        <title>批量的UPDATE和DELETE</title>
+
+        <para>
+            HQL现在支持 <literal>update</literal>, <literal>delete</literal> 和
+            <literal>insert ... select ...</literal>语句.  查阅
+            <xref linkend="batch-direct"/> 以获得更多信息。
+        </para>
+    </sect1>
+
+    <sect1 id="queryhql-tipstricks">
+        <title>小技巧 &amp; 小窍门</title>
+
+        <para>
+            你可以统计查询结果的数目而不必实际的返回他们:
+        </para>
+
+        <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue()]]></programlisting>
+
+        <para>
+            若想根据一个集合的大小来进行排序,可以使用如下的语句:
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User as usr 
+    left join usr.messages as msg
+group by usr.id, usr.name
+order by count(msg)]]></programlisting>
+
+        <para>
+            如果你的数据库支持子选择,你可以在你的查询的where子句中为选择的大小(selection size)指定一个条件:
+        </para>
+
+        <programlisting><![CDATA[from User usr where size(usr.messages) >= 1]]></programlisting>
+
+        <para>
+            如果你的数据库不支持子选择语句,使用下面的查询:
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User usr.name
+    join usr.messages msg
+group by usr.id, usr.name
+having count(msg) >= 1]]></programlisting>
+
+        <para>
+            因为内连接(inner join)的原因,这个解决方案不能返回含有零个信息的<literal>User</literal>
+            类的实例, 所以这种情况下使用下面的格式将是有帮助的:
+        </para>
+
+        <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+    left join usr.messages as msg
+group by usr.id, usr.name
+having count(msg) = 0]]></programlisting>
+
+        <para>
+            JavaBean的属性可以被绑定到一个命名查询(named query)的参数上:
+        </para>
+
+        <programlisting><![CDATA[Query q = s.createQuery("from foo Foo as foo where foo.name=:name and foo.size=:size");
+q.setProperties(fooBean); // fooBean包含方法getName()与getSize()
+List foos = q.list();]]></programlisting>
+
+        <para>
+            通过将接口<literal>Query</literal>与一个过滤器(filter)一起使用,集合(Collections)是可以分页的:
+        </para>
+
+        <programlisting><![CDATA[Query q = s.createFilter( collection, "" ); // 一个简单的过滤器
+q.setMaxResults(PAGE_SIZE);
+q.setFirstResult(PAGE_SIZE * pageNumber);
+List page = q.list();]]></programlisting>
+
+        <para>
+            通过使用查询过滤器(query filter)可以将集合(Collection)的原素分组或排序:
+        </para>
+        
+        <programlisting><![CDATA[Collection orderedCollection = s.filter( collection, "order by this.amount" );
+Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );]]></programlisting>
+
+        <para>
+            不用通过初始化,你就可以知道一个集合(Collection)的大小:
+        </para>
+
+        <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue();]]></programlisting>
+
+    </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/query_sql.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/query_sql.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/query_sql.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,715 @@
+<chapter id="querysql" revision="2">
+    <title>Native SQL查询</title>
+    <para>
+		你也可以使用你的数据库的Native SQL语言来查询数据。这对你在要使用数据库的某些特性的时候(比如说在查询提示或者Oracle中的
+		<literal>CONNECT</literal>关键字),这是非常有用的。这就能够扫清你把原来直接使用SQL/JDBC 的程序迁移到基于
+		Hibernate应用的道路上的障碍。
+    </para>
+
+    <para>
+		Hibernate3允许你使用手写的sql来完成所有的create,update,delete,和load操作(包括存储过程)
+    </para>
+
+    <sect1 id="querysql-creating" revision="4">
+    <title>使用<literal>SQLQuery</literal></title>
+
+    <para>对原生SQL查询执行的控制是通过<literal>SQLQuery</literal>接口进行的,通过执行<literal>Session.createSQLQuery()</literal>获取这个接口。下面来描述如何使用这个API进行查询。</para>
+
+    <sect2>
+      <title>标量查询(Scalar queries)</title>
+
+      <para>
+      最基本的SQL查询就是获得一个标量(数值)的列表。      </para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").list();
+sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
+]]></programlisting>
+
+      <para>
+      它们都将返回一个Object数组(Object[])组成的List,数组每个元素都是CATS表的一个字段值。Hibernate会使用ResultSetMetadata来判定返回的标量值的实际顺序和类型。
+      </para>
+
+      <para>
+      如果要避免过多的使用<literal>ResultSetMetadata</literal>,或者只是为了更加明确的指名返回值,可以使用<literal>addScalar()</literal>。
+      </para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME", Hibernate.STRING)
+ .addScalar("BIRTHDATE", Hibernate.DATE)
+]]></programlisting>
+
+
+    <para>这个查询指定了:</para>
+
+    <itemizedlist>
+      <listitem>
+        <para>SQL查询字符串</para>
+      </listitem>
+
+      <listitem>
+        <para>要返回的字段和类型</para>
+      </listitem>
+    </itemizedlist>
+
+      <para>
+      它仍然会返回Object数组,但是此时不再使用<literal>ResultSetMetdata</literal>,而是明确的将ID,NAME和BIRTHDATE按照Long,String和Short类型从resultset中取出。同时,也指明了就算query是使用<literal>*</literal>来查询的,可能获得超过列出的这三个字段,也仅仅会返回这三个字段。
+      </para>
+
+      <para>
+      对全部或者部分的标量值不设置类型信息也是可以的。
+      </para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME")
+ .addScalar("BIRTHDATE")
+]]></programlisting>
+
+      <para>
+      基本上这和前面一个查询相同,只是此时使用<literal>ResultSetMetaData</literal>来决定NAME和BIRTHDATE的类型,而ID的类型是明确指出的。
+      </para>
+
+      <para>
+      关于从ResultSetMetaData返回的java.sql.Types是如何映射到Hibernate类型,是由方言(Dialect)控制的。假若某个指定的类型没有被映射,或者不是你所预期的类型,你可以通过Dialet的<literal>registerHibernateType</literal>调用自行定义。
+      </para>
+
+    </sect2>
+
+    <sect2>
+      <title>实体查询(Entity queries)</title>
+
+      <para>
+      上面的查询都是返回标量值的,也就是从resultset中返回的“裸”数据。下面展示如何通过<literal>addEntity()</literal>让原生查询返回实体对象。
+      </para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class);
+sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);
+]]></programlisting>
+
+      <para>这个查询指定:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>SQL查询字符串</para>
+        </listitem>
+
+        <listitem>
+          <para>要返回的实体</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+      假设Cat被映射为拥有ID,NAME和BIRTHDATE三个字段的类,以上的两个查询都返回一个List,每个元素都是一个Cat实体。
+      </para>
+
+      <para>      
+      假若实体在映射时有一个<literal>many-to-one</literal>的关联指向另外一个实体,在查询时必须也返回那个实体,否则会导致发生一个"column not found"的数据库错误。这些附加的字段可以使用*标注来自动返回,但我们希望还是明确指明,看下面这个具有指向<literal>Dog</literal>的<literal>many-to-one</literal>的例子:
+      </para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);
+]]></programlisting>
+
+      <para>
+      这样cat.getDog()就能正常运作。
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>处理关联和集合类(Handling associations and collections)</title>
+
+      <para>      
+      通过提前抓取将<literal>Dog</literal>连接获得,而避免初始化proxy带来的额外开销也是可能的。这是通过<literal>addJoin()</literal>方法进行的,这个方法可以让你将关联或集合连接进来。
+      </para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dog");
+]]></programlisting>
+
+      <para>
+            上面这个例子中,返回的<literal>Cat</literal>对象,其<literal>dog</literal>属性被完全初始化了,不再需要数据库的额外操作。注意,我们加了一个别名("cat"),以便指明join的目标属性路径。通过同样的提前连接也可以作用于集合类,例如,假若<literal>Cat</literal>有一个指向<literal>Dog</literal>的一对多关联。
+      </para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dogs");
+]]></programlisting>
+
+      <p>
+      到此为止,我们碰到了天花板:若不对SQL查询进行增强,这些已经是在Hibernate中使用原生SQL查询所能做到的最大可能了。下面的问题即将出现:返回多个同样类型的实体怎么办?或者默认的别名/字段不够又怎么办?
+      
+      </p>
+    </sect2>
+
+    <sect2>
+      <title>返回多个实体(Returning multiple entities)</title>
+
+      <para>
+      到目前为止,结果集字段名被假定为和映射文件中指定的的字段名是一致的。假若SQL查询连接了多个表,同一个字段名可能在多个表中出现多次,这就会造成问题。
+      </para>
+
+      <para>
+      下面的查询中需要使用字段别名注射(这个例子本身会失败):
+      </para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT c.*, m.*  FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+]]></programlisting>
+
+      <para>
+      这个查询的本意是希望每行返回两个Cat实例,一个是cat,另一个是它的妈妈。但是因为它们的字段名被映射为相同的,而且在某些数据库中,返回的字段别名是“c.ID”,"c.NAME"这样的形式,而它们和在映射文件中的名字("ID"和"NAME")不匹配,这就会造成失败。
+      
+      </para>
+
+      <para>
+      下面的形式可以解决字段名重复:
+      </para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT {cat.*}, {mother.*}  FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+]]></programlisting>
+
+      <para>这个查询指明:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+          SQL查询语句,其中包含占位附来让Hibernate注射字段别名</para>
+        </listitem>
+
+        <listitem>
+          <para>
+          查询返回的实体
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+      上面使用的{cat.*}和{mother.*}标记是作为“所有属性”的简写形式出现的。当然你也可以明确地罗列出字段名,但在这个例子里面我们让Hibernate来为每个属性注射SQL字段别名。字段别名的占位符是属性名加上表别名的前缀。在下面的例子中,我们从另外一个表(cat_log)中通过映射元数据中的指定获取Cat和它的妈妈。注意,要是我们愿意,我们甚至可以在where子句中使用属性别名。
+      
+      </para>
+
+      <programlisting><![CDATA[String sql = "SELECT ID as {c.id}, NAME as {c.name}, " + 
+         "BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
+         "FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
+
+List loggedCats = sess.createSQLQuery(sql)
+        .addEntity("cat", Cat.class)
+        .addEntity("mother", Cat.class).list()
+]]></programlisting>
+
+      <sect3 id="querysql-aliasreferences" revision="2">
+        <title>别名和属性引用(Alias and property references)</title>
+
+        <para>
+        大多数情况下,都需要上面的属性注射,但在使用更加复杂的映射,比如复合属性、通过标识符构造继承树,以及集合类等等情况下,也有一些特别的别名,来允许Hibernate注射合适的别名。
+        </para>
+
+    <para>
+    下表列出了使用别名注射参数的不同可能性。注意:下面结果中的别名只是示例,实用时每个别名需要唯一并且不同的名字。
+    </para>
+
+    <table frame="topbot" id="aliasinjection-summary">
+      <title>别名注射(alias injection names)</title>
+
+      <tgroup cols="3">
+        <colspec colwidth="1*" />
+
+        <colspec colwidth="1*" />
+
+        <colspec colwidth="2.5*" />
+
+        <thead>
+          <row>
+            <entry>描述</entry>
+            
+            <entry>语法</entry>
+            
+            <entry>示例</entry>
+            </row>
+        </thead>
+        <tbody>
+          <row>
+            <entry>简单属性</entry>
+            <entry><literal>{[aliasname].[propertyname]</literal></entry>
+            <entry><literal>A_NAME as {item.name}</literal></entry>
+          </row>
+          <row>
+            <entry>复合属性</entry>
+            <entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
+            <entry><literal>CURRENCY as {item.amount.currency}, VALUE as {item.amount.value}</literal></entry>
+          </row>
+          <row>
+            <entry>实体辨别器(Discriminator of an entity)</entry>
+            <entry><literal>{[aliasname].class}</literal></entry>
+            <entry><literal>DISC as {item.class}</literal></entry>
+          </row>
+          <row>
+            <entry>实体的所有属性</entry>
+            <entry><literal>{[aliasname].*}</literal></entry>
+            <entry><literal>{item.*}</literal></entry>
+          </row>
+          <row>
+            <entry>集合键(collection key)</entry>
+            <entry><literal>{[aliasname].key}</literal></entry>
+            <entry><literal>ORGID as {coll.key}</literal></entry>
+          </row>
+          <row>
+            <entry>集合id</entry>
+            <entry><literal>{[aliasname].id}</literal></entry>
+            <entry><literal>EMPID as {coll.id}</literal></entry>
+          </row>
+          <row>
+            <entry>集合元素</entry>
+            <entry><literal>{[aliasname].element}</literal></entry>
+            <entry><literal>XID as {coll.element}</literal></entry>
+            <entry></entry>
+          </row>
+          <row>
+            <entry>集合元素的属性</entry>
+            <entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
+            <entry><literal>NAME as {coll.element.name}</literal></entry>
+          </row>
+          <row>
+            <entry>集合元素的所有属性</entry>
+            <entry><literal>{[aliasname].element.*}</literal></entry>
+            <entry><literal>{coll.element.*}</literal></entry>
+          </row>
+          <row>
+            <entry>集合的所有属性</entry>
+            <entry><literal>{[aliasname].*}</literal></entry>
+            <entry><literal>{coll.*}</literal></entry>
+          </row>
+        </tbody>
+      </tgroup>
+    </table>
+
+
+    </sect3>
+   </sect2>
+   
+       <sect2>
+      <title>返回非受管实体(Returning non-managed entities)</title>
+
+      <para>
+      可以对原生sql 查询使用ResultTransformer。这会返回不受Hibernate管理的实体。
+      
+      </para>
+
+      <programlisting><![CDATA[sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS")
+        .setResultTransformer(Transformers.aliasToBean(CatDTO.class))]]></programlisting>
+        
+              <para>这个查询指定:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>SQL查询字符串</para>
+        </listitem>
+
+        <listitem>
+          <para>结果转换器(result transformer)</para>
+        </listitem>
+      </itemizedlist>
+        
+        <para>
+        上面的查询将会返回<literal>CatDTO</literal>的列表,它将被实例化并且将NAME和BIRTHDAY的值注射入对应的属性或者字段。
+        </para>
+    </sect2>
+
+    <sect2>
+      <title>处理继承(Handling inheritance)</title>
+
+      <para>
+      原生SQL查询假若其查询结果实体是继承树中的一部分,它必须包含基类和所有子类的所有属性。
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>参数(Parameters)</title>
+
+      <para>
+      原生查询支持位置参数和命名参数:
+      </para>
+
+      <programlisting><![CDATA[Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class);
+List pusList = query.setString(0, "Pus%").list();
+     
+query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like :name").addEntity(Cat.class);
+List pusList = query.setString("name", "Pus%").list();          ]]></programlisting>
+    </sect2>
+    
+    
+        
+  </sect1>
+
+    
+    <sect1 id="querysql-namedqueries" revision="3">
+        <title>命名SQL查询</title>
+
+        <para>
+			可以在映射文档中定义查询的名字,然后就可以象调用一个命名的HQL查询一样直接调用命名SQL查询.在这种情况下,我们<emphasis>不</emphasis>
+			需要调用<literal>addEntity()</literal>方法.
+        </para>
+
+         <programlisting><![CDATA[<sql-query name="persons">
+    <return alias="person" class="eg.Person"/>
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex}
+    FROM PERSON person
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+    <programlisting><![CDATA[List people = sess.getNamedQuery("persons")
+    .setString("namePattern", namePattern)
+    .setMaxResults(50)
+    .list();]]></programlisting>
+    
+    <para><literal>&lt;return-join&gt;</literal>和
+    <literal>&lt;load-collection&gt;</literal> 元素是用来连接关联以及将查询定义为预先初始化各个集合的。</para>
+
+    <programlisting><![CDATA[<sql-query name="personsWith">
+    <return alias="person" class="eg.Person"/>
+    <return-join alias="address" property="person.mailingAddress"/>
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex},
+           adddress.STREET AS {address.street},
+           adddress.CITY AS {address.city},
+           adddress.STATE AS {address.state},
+           adddress.ZIP AS {address.zip}
+    FROM PERSON person
+    JOIN ADDRESS adddress
+        ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+    
+
+        <para>
+			一个命名查询可能会返回一个标量值.你必须使用<literal>&lt;return-scalar&gt;</literal>元素来指定字段的别名和
+			Hibernate类型
+        </para>
+        
+        <programlisting><![CDATA[<sql-query name="mySqlQuery">
+    <return-scalar column="name" type="string"/>
+    <return-scalar column="age" type="long"/>
+    SELECT p.NAME AS name,
+           p.AGE AS age,
+    FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
+</sql-query>]]></programlisting>
+
+    <para>
+    你可以把结果集映射的信息放在外部的<literal>&lt;resultset&gt;</literal>元素中,这样就可以在多个命名查询间,或者通过<literal>setResultSetMapping()</literal>API来访问。(此处原文即存疑。原文为:You can externalize the resultset mapping informations in a
+    <literal>&lt;resultset&gt;</literal> element to either reuse them accross
+    several named queries or through the
+    <literal>setResultSetMapping()</literal> API.)
+    </para>
+
+    <programlisting><![CDATA[<resultset name="personAddress">
+    <return alias="person" class="eg.Person"/>
+    <return-join alias="address" property="person.mailingAddress"/>
+</resultset>
+
+<sql-query name="personsWith" resultset-ref="personAddress">
+    SELECT person.NAME AS {person.name},
+           person.AGE AS {person.age},
+           person.SEX AS {person.sex},
+           adddress.STREET AS {address.street},
+           adddress.CITY AS {address.city},
+           adddress.STATE AS {address.state},
+           adddress.ZIP AS {address.zip}
+    FROM PERSON person
+    JOIN ADDRESS adddress
+        ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+    WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+	    <para>
+    	另外,你可以在java代码中直接使用hbm文件中的结果集定义信息。
+    </para>
+
+    <programlisting><![CDATA[List cats = sess.createSQLQuery(
+        "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
+    )
+    .setResultSetMapping("catAndKitten")
+    .list();]]></programlisting>
+         
+         <sect2 id="propertyresults">
+             <title>使用return-property来明确地指定字段/别名</title>
+             
+             <para>
+				使用<literal>&lt;return-property&gt;</literal>你可以明确的告诉Hibernate使用哪些字段别名,这取代了使用<literal>{}</literal>-语法
+				来让Hibernate注入它自己的别名.
+             </para>
+             
+            <programlisting><![CDATA[<sql-query name="mySqlQuery">
+    <return alias="person" class="eg.Person">
+      <return-property name="name" column="myName"/>
+      <return-property name="age" column="myAge"/>
+      <return-property name="sex" column="mySex"/>
+    </return>
+    SELECT person.NAME AS myName,
+           person.AGE AS myAge,
+           person.SEX AS mySex,
+    FROM PERSON person WHERE person.NAME LIKE :name
+</sql-query>
+]]></programlisting>
+             <literal>&lt;return-property&gt;</literal>也可用于多个字段,它解决了使用<literal>{}</literal>-语法不能细粒度控制多个字段的限制
+             <programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
+            <return alias="emp" class="Employment">            
+             <return-property name="salary"> 
+               <return-column name="VALUE"/>
+               <return-column name="CURRENCY"/>            
+             </return-property>
+             <return-property name="endDate" column="myEndDate"/>
+            </return>
+            SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer}, 
+            STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+            REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
+            FROM EMPLOYMENT
+            WHERE EMPLOYER = :id AND ENDDATE IS NULL
+            ORDER BY STARTDATE ASC
+</sql-query>]]></programlisting>
+             
+            <para>
+				注意在这个例子中,我们使用了<literal>&lt;return-property&gt;</literal>结合<literal>{}</literal>的注入语法.
+				允许用户来选择如何引用字段以及属性.
+            </para>
+
+            <para>
+			 如果你映射一个识别器(discriminator),你必须使用<literal>&lt;return-discriminator&gt;</literal> 来指定识别器字段
+            </para>
+         </sect2>
+         
+         <sect2 id="sp_query"  revision="1">
+             <title>使用存储过程来查询</title>
+             
+             <para>
+				 Hibernate 3引入了对存储过程查询(stored procedure)和函数(function)的支持.以下的说明中,这二者一般都适用。
+				 
+				 存储过程/函数必须返回一个结果集,作为Hibernate能够使用的第一个外部参数.
+				 
+				 下面是一个Oracle9和更高版本的存储过程例子.</para>
+                 
+                 <programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments 
+    RETURN SYS_REFCURSOR 
+AS 
+    st_cursor SYS_REFCURSOR; 
+BEGIN 
+    OPEN st_cursor FOR 
+ SELECT EMPLOYEE, EMPLOYER, 
+ STARTDATE, ENDDATE, 
+ REGIONCODE, EID, VALUE, CURRENCY 
+ FROM EMPLOYMENT; 
+      RETURN  st_cursor; 
+ END;]]></programlisting>
+             <para>    
+				 在Hibernate里要要使用这个查询,你需要通过命名查询来映射它.
+			 </para>
+                 
+             <programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
+    <return alias="emp" class="Employment">
+        <return-property name="employee" column="EMPLOYEE"/>
+        <return-property name="employer" column="EMPLOYER"/>            
+        <return-property name="startDate" column="STARTDATE"/>
+        <return-property name="endDate" column="ENDDATE"/>            
+        <return-property name="regionCode" column="REGIONCODE"/>            
+        <return-property name="id" column="EID"/>                        
+        <return-property name="salary"> 
+            <return-column name="VALUE"/>
+            <return-column name="CURRENCY"/>            
+        </return-property>
+    </return>
+    { ? = call selectAllEmployments() }
+</sql-query>]]></programlisting>
+             
+             <para>
+			  注意存储过程当前仅仅返回标量和实体.现在不支持<literal>&lt;return-join&gt;</literal>和<literal>&lt;load-collection&gt;</literal>
+			  
+             </para>
+             
+             <sect3 id="querysql-limits-storedprocedures"  revision="1">
+               <title>使用存储过程的规则和限制</title>
+               
+               <para>
+				   为了在Hibernate中使用存储过程,你必须遵循一些规则.不遵循这些规则的存储过程将不可用.如果你仍然想要使用他们,
+				   你必须通过<literal>session.connection()</literal>来执行他们.这些规则针对于不同的数据库.因为数据库
+				   提供商有各种不同的存储过程语法和语义.
+               </para>
+               
+               <para>
+                   对存储过程进行的查询无法使用<literal>setFirstResult()/setMaxResults()</literal>进行分页。
+               </para>
+               
+               
+        <para>建议采用的调用方式是标准SQL92: <literal>{ ? = call
+        functionName(&lt;parameters&gt;) }</literal> 或者 <literal>{ ? = call
+        procedureName(&lt;parameters&gt;}</literal>.原生调用语法不被支持。</para>
+
+               <para>
+				   对于Oracle有如下规则:
+               </para>
+               
+               <itemizedlist spacing="compact">
+          <listitem>
+            <para>函数必须返回一个结果集。存储过程的第一个参数必须是<literal>OUT</literal>,它返回一个结果集。这是通过Oracle 9或10的<literal>SYS_REFCURSOR</literal>类型来完成的。在Oracle中你需要定义一个<literal>REF CURSOR</literal>类型,参见Oracle的手册。</para>
+          </listitem>
+              </itemizedlist>
+                           
+              <para>                   
+				   对于Sybase或者MS SQL server有如下规则:
+               </para>
+                   
+               <itemizedlist spacing="compact">
+               <listitem>
+               <para>    
+				   存储过程必须返回一个结果集。.注意这些servers可能返回多个结果集以及更新的数目.Hibernate将取出第一条结果集作为它的返回值,
+				   其他将被丢弃。
+               </para>
+               </listitem>    
+               <listitem>
+               <para>    
+				   如果你能够在存储过程里设定<literal>SET NOCOUNT ON</literal>,这可能会效率更高,但这不是必需的。
+               </para>
+               </listitem>    
+              </itemizedlist>
+              </sect3>
+         </sect2>
+
+    </sect1>
+
+    <sect1 id="querysql-cud">
+        <title>定制SQL用来create,update和delete</title>
+
+        <para>
+			Hibernate3能够使用定制的SQL语句来执行create,update和delete操作。在Hibernate中,持久化的类和集合已经
+			包含了一套配置期产生的语句(insertsql, deletesql, updatesql等等),这些映射标记 <literal>&lt;sql-insert&gt;</literal>, 
+			<literal>&lt;sql-delete&gt;</literal>, and <literal>&lt;sql-update&gt;</literal>重载了
+			这些语句。
+        </para>
+
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
+    <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
+    <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
+</class>]]></programlisting>
+
+        <para>
+			这些SQL直接在你的数据库里执行,所以你可以自由的使用你喜欢的任意语法。但如果你使用数据库特定的语法,
+			这当然会降低你映射的可移植性。
+        </para>
+
+        <para>
+			如果设定<literal>callable</literal>,则能够支持存储过程了。
+        </para>
+
+    <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
+    <sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
+    <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
+</class>]]></programlisting>
+
+        <para>
+		  参数的位置顺序是非常重要的,他们必须和Hibernate所期待的顺序相同。
+        </para>
+        
+        <para>
+		  你能够通过设定日志调试级别为<literal>org.hiberante.persister.entity</literal>,来查看Hibernate所期待的顺序。在这个级别下,
+		  Hibernate将会打印出create,update和delete实体的静态SQL。(如果想看到预计的顺序。记得不要将定制SQL包含在映射文件里,
+		  因为他们会重载Hibernate生成的静态SQL。)
+        </para>
+
+        <para>
+			在大多数情况下(最好这么做),存储过程需要返回插入/更新/删除的行数,因为Hibernate对语句的成功执行有些运行时的检查。
+			Hibernate常会把进行CUD操作的语句的第一个参数注册为一个数值型输出参数。
+        </para>
+
+        <programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
+    RETURN NUMBER IS
+BEGIN
+
+    update PERSON
+    set
+        NAME = uname,
+    where
+        ID = uid;
+
+    return SQL%ROWCOUNT;
+
+END updatePerson;]]></programlisting>
+
+        
+    </sect1>
+
+    <sect1 id="querysql-load">
+        <title>定制装载SQL</title>
+
+        <para>
+			你可能需要声明你自己的SQL(或HQL)来装载实体
+        </para>
+
+    <programlisting><![CDATA[<sql-query name="person">
+    <return alias="pers" class="Person" lock-mode="upgrade"/>
+    SELECT NAME AS {pers.name}, ID AS {pers.id}
+    FROM PERSON
+    WHERE ID=?
+    FOR UPDATE
+</sql-query>]]></programlisting>
+
+        <para>
+			这只是一个前面讨论过的命名查询声明,你可以在类映射里引用这个命名查询。
+        </para>
+
+        <programlisting><![CDATA[<class name="Person">
+    <id name="id">
+        <generator class="increment"/>
+    </id>
+    <property name="name" not-null="true"/>
+    <loader query-ref="person"/>
+</class>]]></programlisting>
+    
+        <para>
+		    这也可以用于存储过程
+        </para>
+
+    <para>你甚至可以定一个用于集合装载的查询:</para>
+
+    <programlisting><![CDATA[<set name="employments" inverse="true">
+    <key/>
+    <one-to-many class="Employment"/>
+    <loader query-ref="employments"/>
+</set>]]></programlisting>
+
+    <programlisting><![CDATA[<sql-query name="employments">
+    <load-collection alias="emp" role="Person.employments"/>
+    SELECT {emp.*}
+    FROM EMPLOYMENT emp
+    WHERE EMPLOYER = :id
+    ORDER BY STARTDATE ASC, EMPLOYEE ASC
+</sql-query>]]></programlisting>
+
+    <para>你甚至还可以定义一个实体装载器,它通过连接抓取装载一个集合:</para>
+
+    <programlisting><![CDATA[<sql-query name="person">
+    <return alias="pers" class="Person"/>
+    <return-join alias="emp" property="pers.employments"/>
+    SELECT NAME AS {pers.*}, {emp.*}
+    FROM PERSON pers
+    LEFT OUTER JOIN EMPLOYMENT emp
+        ON pers.ID = emp.PERSON_ID
+    WHERE ID=?
+</sql-query>]]></programlisting>
+  </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/quickstart.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/quickstart.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/quickstart.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,461 @@
+<chapter id="quickstart">
+    <title>在Tomcat中快速上手</title>
+
+    <sect1 id="quickstart-intro" revision="2">
+        <title>开始Hibernate之旅</title>
+
+        <para>
+            这份教程描述如何在Apache Tomcat servlet容器中为web应用程序配置Hibernate 3.0(我们使用Tomcat 4.1版本,与5.0版本差别很小)。Hibernate在大多数主流J2EE应用服务器
+            的运行环境中都可以工作良好,甚至也可以在独立Java应用程序中使用。在本教程中使用的示例数据库系统是PostgreSQL 7.4,只需要修改Hibernate SQL语言配置与连接属性,就可以
+            很容易的支持其他数据库了。
+        </para>
+
+        <para>
+            第一步,我们必须拷贝所有需要的库文件到Tomcat安装目录中。在这篇教程中,我们使用一个独立的web Context配置(<literal>webapps/quickstart</literal>)。我们确认全局库文件(<literal>TOMCAT/common/lib</literal>)和本web应用程序上下文的路径(对于jar来说是<literal>webapps/quickstart/WEB-INF/lib</literal>,对于class文件来说是<literal>webapps/quickstart/WEB-INF/classes</literal>)能够被类装载器检索到。我们把这两个类装载器级别分别称做全局类路径(global classpath)和上下文类路径(context classpath)。
+        </para>
+
+        <para>
+            现在,把这些库文件copy到两个类路径去:
+        </para>
+
+        <orderedlist>
+            <listitem>
+                <para>
+                   	把数据库需要的JDBC驱动文件拷贝到全局类路径,这是tomcat捆绑的DBCP连接池所需要的。Hibernate使用JDBC连接数据库方式执行SQL语句,所以你要么提供外部连接池中的连接给Hibernate,或者配置Hibernate自带的连接池(C3PO,Proxool)。对于本教程来说,把<literal>pg74jdbc3.jar</literal>库文件(支持PostgreSQL 7.4和JDK 1.4)到全局类装载路径下即可。如果你希望使用其他的数据库,拷贝其相应的JDBC 驱动文件)。
+                </para>
+            </listitem>
+            <listitem>
+				<para>
+                    永远不要拷贝任何其他东西到Tomcat的全局类路径下,否则你可能在使用其他一些工具上遇到麻烦,比如log4j, commons-logging等等。
+                    一定要让每个web应用程序使用自己的上下文类路径,就是说把你自己需要的类库拷贝到<literal>WEB-INF/lib</literal>下去,把配置文件configuration/property等配置文件拷贝到<literal>WEB-INF/classes</literal>下面去。这两个目录都是当前程序缺省的上下文类路径。
+				</para>
+            </listitem>
+            <listitem>
+                <para>
+                    Hibernate本身打包成一个JAR类库。将<literal>hibernate3.jar</literal>文件拷贝到程序的上下文类路径下,和你应用程序的其他库文件放一起。在运行时,Hibernate还需要一些第三方类库,它们在Hibernate发行包的<literal>lib/</literal>目录下。参见<xref linkend="3rdpartylibs"/>。把所需要的第三方库文件也拷贝到上下文类路径下。
+                </para>
+            </listitem>
+        </orderedlist>
+
+        <table frame="topbot" id="3rdpartylibs">
+            <title>
+                Hibernate 第三方类库
+            </title>
+            <tgroup cols="2" rowsep="1" colsep="1">
+                <colspec colname="c1" colwidth="1*"/>
+                <colspec colname="c2" colwidth="2*"/>
+                <thead>
+                    <row>
+                        <entry align="center">
+                            类库
+                        </entry>
+                        <entry align="center">
+                            描述
+                        </entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>
+                            antlr (必需)
+                        </entry>
+                        <entry>
+                        	Hibernate使用ANTLR来产生查询分析器,这个类库在运行环境下时也是必需的。
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            dom4j (必需)
+                        </entry>
+                        <entry>
+                            Hibernate使用dom4j解析XML配置文件和XML映射元文件。
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            CGLIB ,asm(必需)
+                        </entry>
+                        <entry>
+                            Hibernate在运行时使用这个代码生成库增强类(与Java反射机制联合使用)。
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            Commons Collections, Commons Logging   (必需)
+                        </entry>
+                        <entry>
+                            Hibernat使用Apache Jakarta Commons项目提供的多个工具类库。
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            EHCache (必需)
+                        </entry>
+                        <entry>
+                        	Hibernate可以使用不同cache缓存工具作为二级缓存。EHCache是缺省的cache缓存工具。
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            Log4j (可选)
+                        </entry>
+                        <entry>
+                            Hibernate使用Commons Logging API,它也可以依次使用Log4j作为底层实施log的机制。如果上下文类目录中存在Log4j库,则Commons Logging使用Log4j和并它在上下文类路径中寻找的<literal>log4j.properties</literal>文件。你可以使用在Hibernate发行包中包含中的那个示例Log4j的配置文件。这样,把log4j.jar和它的配置文件(位于<literal>src/</literal>目录中)拷贝到你的上下文类路径下,就可以在后台看到底程序如何运行的。
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
+                            其他文件是不是必需的?
+                        </entry>
+                        <entry>
+                            请察看Hibernate发行包中的 lib/README.txt文件,这是一个Hibernate发行包中附带的第三方类库的列表,他们总是保持最新的。你可以在那里找到所有必需或者可选的类库(注意:其中的"buildtime required"指的是编译Hibernate时所需要而非编译你自己的程序所必需的类库)。
+                        </entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+
+        <para>
+        接下来我们来配置在Tomcat和Hibernate中共用的数据库连接池。也就是说Tomcat会提供经过池处理的JDBC连接(用它内置的DBCP连接池),Hibernate通过JNDI方式来请求获得JDBC连接。作为替代方案,你也可以让Hibernate自行管理连接池。Tomcat把连接池绑定到JNDI,我们要在Tomcat的主配置文件(<literal>TOMCAT/conf/server.xml</literal>)中加一个资源声明:
+        </para>
+
+        <programlisting><![CDATA[<Context path="/quickstart" docBase="quickstart">
+    <Resource name="jdbc/quickstart" scope="Shareable" type="javax.sql.DataSource"/>
+    <ResourceParams name="jdbc/quickstart">
+        <parameter>
+            <name>factory</name>
+            <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
+        </parameter>
+
+        <!-- DBCP database connection settings -->
+        <parameter>
+            <name>url</name>
+            <value>jdbc:postgresql://localhost/quickstart</value>
+        </parameter>
+        <parameter>
+            <name>driverClassName</name><value>org.postgresql.Driver</value>
+        </parameter>
+        <parameter>
+            <name>username</name>
+            <value>quickstart</value>
+        </parameter>
+        <parameter>
+            <name>password</name>
+            <value>secret</value>
+        </parameter>
+
+        <!-- DBCP connection pooling options -->
+        <parameter>
+            <name>maxWait</name>
+            <value>3000</value>
+        </parameter>
+        <parameter>
+            <name>maxIdle</name>
+            <value>100</value>
+        </parameter>
+        <parameter>
+            <name>maxActive</name>
+            <value>10</value>
+        </parameter>
+    </ResourceParams>
+</Context>]]></programlisting>
+
+		<para>
+			我们在这个例子中要配置的上下文叫做<literal>quickstart</literal>,它位于<literal>TOMCAT/webapp/quickstart</literal>目录下。如果要访问这个应用程序,在你的浏览器中输入<literal>http://localhost:8080/quickstart</literal>就可以了(当然,在后面加上在你的<literal>web.xml</literal>文件中配置好你的servlet)。你现在可以创建一个只含有空<literal>process()</literal>的简单servlet了。
+		</para>
+
+        <para>
+            Tomcat现在通过JNDI的方式:<literal>java:comp/env/jdbc/quickstart</literal>来提供连接。如果你在配置连接池遇到问题,请查阅Tomcat文档。如果你遇到了JDBC驱动所报的exception出错信息,请在没有Hibernate的环境下,先测试JDBC连接池本身是否配置正确。Tomcat和JDBC的配置教程可以在Web上查到。
+        </para>
+
+        <para>
+            下一步就是配置Hibernate。首先Hibernate必须知道它如何获得JDBC连接,在这里我们使用基于XML格式的Hibernate配置文件。当然使用properties文件的进行配置,但缺少一些XML语法的特性。这个XML配置文件必须放在上下文类路径(<literal>WEB-INF/classes</literal>)下面,命名为<literal>hibernate.cfg.xml</literal>:
+        </para>
+
+        <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration
+    PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
+    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <session-factory>
+
+        <property name="connection.datasource">java:comp/env/jdbc/quickstart</property>
+        <property name="show_sql">false</property>
+        <property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
+
+        <!-- Mapping files -->
+        <mapping resource="Cat.hbm.xml"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+        <para>
+            在这里我们关闭了SQL命令的log,同时告诉Hibernate使用哪种SQL数据库用语(Dialet),以及如何得到JDBC连接(通过Tomcat声明绑定的JNDI地址)。Dialet是必需配置的,因为不同的数据库都和"SQL标准"有一些出入。不用担心,Hibernate会替你处理这些差异,Hibernate支持所有主流的商业和开放源代码数据库。
+        </para>
+
+        <para>
+            <literal>SessionFactory</literal>是Hibernate的一个概念,表示对应一个数据存储源。通过创建多个XML配置文件并在你的程序中创建多个<literal>Configuration</literal>和<literal>SessionFactory</literal>对象,就可以支持多个数据库了。
+        </para>
+
+        <para>
+            在<literal>hibernate.cfg.xml</literal>中的最后一个元素声明了<literal>Cat.hbm.xml</literal>,这是一个Hibernate XML映射文件,对应于持久化类<literal>Cat</literal>。这个文件包含了把<literal>Cat</literal> POJO类映射到数据库表(或多个数据库表)的元数据。我们稍后就回来看这个文件。下一步让我们先编写这个POJO类,然后在声明它的映射元数据。
+                    </para>
+
+    </sect1>
+
+    <sect1 id="quickstart-persistentclass"  revision="1">
+        <title>第一个持久化类</title>
+
+        <para>
+            Hibernate使用简单的Java对象(Plain Old Java Objects ,就是POJOs,有时候也称作Plain Ordinary Java Objects)这种编程模型来进行持久化。一个POJO很像JavaBean,通过getter和setter方法访问其属性,对外则隐藏了内部实现的细节(假若需要的话,Hibernate也可以直接访问其属性字段)。
+        </para>
+
+        <programlisting><![CDATA[package org.hibernate.examples.quickstart;
+
+public class Cat {
+
+    private String id;
+    private String name;
+    private char sex;
+    private float weight;
+
+    public Cat() {
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    private void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public char getSex() {
+        return sex;
+    }
+
+    public void setSex(char sex) {
+        this.sex = sex;
+    }
+
+    public float getWeight() {
+        return weight;
+    }
+
+    public void setWeight(float weight) {
+        this.weight = weight;
+    }
+
+}]]></programlisting>
+
+        <para>
+            Hibernate对属性使用的类型不加任何限制。所有的Java JDK类型和原始类型(比如<literal>String</literal>,<literal>char</literal>和<literal>Date</literal>)都可以被映射,也包括Java 集合(Java collections framework)中的类。你可以把它们映射成为值,值集合,或者与其他实体类相关联。<literal>id</literal>是一个特殊的属性,代表了这个类的数据库标识符(主键),对于类似于<literal>Cat</literal>这样的实体类我们强烈建议使用。Hibernate也可以使用内部标识符,但这样我们会失去一些程序架构方面的灵活性。
+        </para>
+
+        <para>
+            持久化类不需要实现什么特别的接口,也不需要从一个特别的持久化根类继承下来。Hibernate也不需要使用任何编译期处理,比如字节码增强操作,它独立的使用Java反射机制和运行时类增强(通过CGLIB)。所以不依赖于Hibernate,我们就可以把POJO的类映射成为数据库表。
+        </para>
+
+    </sect1>
+
+    <sect1 id="quickstart-mapping" revision="1">
+        <title>映射cat</title>
+
+        <para>
+            <literal>Cat.hbm.xml</literal>映射文件包含了对象/关系映射(O/R Mapping)所需的元数据。元数据包含持久化类的声明和属性到数据库的映射(指向字段和其他实体的外键关联)。
+        </para>
+
+        <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping
+    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+
+    <class name="org.hibernate.examples.quickstart.Cat" table="CAT">
+
+        <!-- A 32 hex character is our surrogate key. It's automatically
+            generated by Hibernate with the UUID pattern. -->
+        <id name="id" type="string" unsaved-value="null" >
+            <column name="CAT_ID" sql-type="char(32)" not-null="true"/>
+            <generator class="uuid.hex"/>
+        </id>
+
+        <!-- A cat has to have a name, but it shouldn' be too long. -->
+        <property name="name">
+            <column name="NAME" length="16" not-null="true"/>
+        </property>
+
+        <property name="sex"/>
+
+        <property name="weight"/>
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+        <para>
+            每个持久化类都应该有一个标识属性(实际上,这个类只代表实体,而不是独立的值类型类,后者会被映射称为实体对象中的一个组件)。这个属性用来区分持久化对象:如果<literal>catA.getId().equals(catB.getId())</literal>结果是true的话,这两个Cat就是相同的。这个概念称为<emphasis>数据库标识</emphasis>。Hiernate附带了几种不同的标识符生成器,用于不同的场合(包括数据库本地的顺序(sequence)生成器、hi/lo高低位标识模式、和程序自己定义的标识符)。我们在这里使用UUID生成器(只在测试时建议使用,如果使用数据库自己生成的整数类型的键值更好),并指定<literal>CAT</literal>表中的<literal>CAT_ID</literal>字段(作为表的主键)存放生成的标识值。
+        </para>
+
+        <para>
+            <literal>Cat</literal>的其他属性都映射到同一个表的字段。对<literal>name</literal>属性来说,我们把它显式地声明映射到一个数据库字段。如果数据库schema是通过由映射声明使用Hibernate的<emphasis>SchemaExport</emphasis>工具自动生成的(作为SQL DDL指令)的话,这就特别有用。所有其它的属性都用Hibernate的默认值映射,大多数情况你都会这样做。数据库中的<literal>CAT</literal>表看起来是这样的:
+        </para>
+
+        <programlisting><![CDATA[ Column |         Type          | Modifiers
+--------+-----------------------+-----------
+ cat_id | character(32)         | not null
+ name   | character varying(16) | not null
+ sex    | character(1)          |
+ weight | real                  |
+Indexes: cat_pkey primary key btree (cat_id)]]></programlisting>
+
+    	<para>
+			你现在可以在你的数据库中手工创建这个表了,如果你需要使用<literal>hbm2ddl</literal>工具把这个步骤自动化,请参阅<xref linkend="toolsetguide"/>。这个工具能够创建完整的SQL DDL,包括表定义,自定义的字段类型约束,惟一约束和索引。
+    	</para>
+
+    </sect1>
+
+    <sect1 id="quickstart-playingwithcats" revision="2">
+        <title>与Cat同乐</title>
+
+        <para>
+            我们现在可以开始Hibernate的<literal>Session</literal>了。它是一个<emphasis>持久化管理器</emphasis>,我们通过它来从数据库中存取<literal>Cat</literal>。首先,我们要从<literal>SessionFactory</literal>中获取一个<literal>Session</literal>(Hibernate的工作单元)。
+        </para>
+
+        <programlisting><![CDATA[SessionFactory sessionFactory =
+            new Configuration().configure().buildSessionFactory();]]></programlisting>
+
+		<para>
+		通过对<literal>configure()</literal>的调用来装载<literal>hibernate.cfg.xml</literal>配置文件,并初始化这个<literal>Configuration</literal>实例。			
+			在创建 <literal>SessionFactory</literal><emphasis>之前</emphasis>(它是不可变的),你可以访问<literal>Configuration</literal>来设置其他属性(甚至修改映射的元数据)。我们应该在哪儿创建<literal>SessionFactory</literal>,在我们的程序中又如何访问它呢?
+			<literal>SessionFactory</literal>通常只是被初始化一次,比如说通过一个<emphasis>load-on-startup</emphasis> servlet的来初始化。这意味着你不应该在serlvet中把它作为一个实例变量来持有,而应该放在其他地方。进一步的说,我们需要使用<emphasis>单例(Singleton)</emphasis>模式,我们才能更容易的在程序中访问<literal>SessionFactory</literal>。下面的方法就同时解决了两个问题:对<literal>SessionFactory</literal>的初始配置与便捷使用。
+		</para>
+
+		<para>
+		    我们实现一个<literal>HibernateUtil</literal>辅助类:
+		</para>
+
+
+		<programlisting><![CDATA[import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+    private static Log log = LogFactory.getLog(HibernateUtil.class);
+
+    private static final SessionFactory sessionFactory;
+
+    static {
+        try {
+            // Create the SessionFactory
+            sessionFactory = new Configuration().configure().buildSessionFactory();
+        } catch (Throwable ex) {
+            // Make sure you log the exception, as it might be swallowed
+            log.error("Initial SessionFactory creation failed.", ex);
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    public static final ThreadLocal session = new ThreadLocal();
+
+    public static Session currentSession()  {
+        Session s = (Session) session.get();
+        // Open a new Session, if this Thread has none yet
+        if (s == null) {
+            s = sessionFactory.openSession();
+            session.set(s);
+        }
+        return s;
+    }
+
+    public static void closeSession() {
+        Session s = (Session) session.get();
+        if (s != null)
+            s.close();
+        session.set(null);
+    }
+}]]></programlisting>
+
+		<para>
+			这个类不但在它的静态初始器中使用了<literal>SessionFactory</literal>,还使用了一个<literal>ThreadLocal</literal>变量来保存<literal>Session</literal>做为当前工作线程。在你使用这个辅助类之前,请确保你理解了thread-local变量这个Java概念。你可以在<literal>CaveatEmptor</literal>(http://caveatemptor.hibernate.org/)上找到一个更加复杂和强大的 <literal>HibernateUtil</literal>。
+	    </para>
+
+        <para>
+            <literal>SessionFactory</literal>是安全线程,可以由很多线程并发访问并获取到<literal>Sessions</literal>。单个<literal>Session</literal>不是安全线程对象,它只代表与数据库之间的一次操作。<literal>Session</literal>通过<literal>SessionFactory</literal>获得并在所有的工作完成后关闭。在你servlet的<literal>process()</literal>中可以象是这么写的(省略了异常情况处理):
+        </para>
+
+        <programlisting><![CDATA[Session session = HibernateUtil.currentSession();
+
+Transaction tx= session.beginTransaction();
+
+Cat princess = new Cat();
+princess.setName("Princess");
+princess.setSex('F');
+princess.setWeight(7.4f);
+
+session.save(princess);
+tx.commit();
+
+HibernateUtil.closeSession();]]></programlisting>
+
+        <para>
+            在一个<literal>Session</literal>中,每个数据库操作都是在一个事务(transaction)中进行的,这样就可以隔离开不同的操作(甚至包括只读操作)。我们使用Hibernate的<literal>Transaction</literal> API来从底层的事务策略中(本例中是JDBC事务)脱身出来。这样,我们就不需要更改任何源代码,就可以把我们的程序部署到一个由容器管理事务的环境中去(使用JTA)。
+
+        </para>
+
+        <para>
+			这样你就可以随心所欲的多次调用<literal>HibernateUtil.currentSession();</literal>,你每次都会得到同一个当前线程的<literal>Session</literal>。不管是在你的servlet代码中,或者在servlet filter中还是在HTTP结果返回之前,你都必须确保这个<literal>Session</literal>在你的数据库访问工作完成后关闭。这样做还有一个好处就是可以容易的使用延迟装载(lazy initialization):<literal>Session</literal>在渲染view层的时候仍然打开着的,所以你在遍历当前对象图的时候可以装载所需的对象。
+        </para>
+
+        <para>
+            Hibernate有不同的方法用来从数据库中取回对象。最灵活的方式就是使用Hibernate查询语言(HQL),这是一种容易学习的语言,是对SQL的面向对象的强大扩展。
+        </para>
+
+        <programlisting><![CDATA[Transaction tx= session.beginTransaction();
+
+Query query = session.createQuery("select c from Cat as c where c.sex = :sex");
+query.setCharacter("sex", 'F');
+for (Iterator it = query.iterate(); it.hasNext();) {
+    Cat cat = (Cat) it.next();
+    out.println("Female Cat: " + cat.getName() );
+}
+
+tx.commit();]]></programlisting>
+
+        <para>
+            Hibernate也提供一种面向对象的<emphasis>按条件查询</emphasis>API,可以执行简洁安全类型的查询。当然,Hibernate在所有与数据库的交互中都使用<literal>PrepatedStatement</literal>和参数绑定。你也可以使用Hibernate的直接SQL查询特性,或者在特殊情况下从<literal>Session</literal>获取一个原始的JDBC连接。
+        </para>
+
+    </sect1>
+
+    <sect1 id="quickstart-summary" revision="1">
+        <title>结语</title>
+
+        <para>
+            在这个短小的教程中,我们对Hibernate浅尝即止。请注意我们没有在例子中包含任何servlet相关代码。你必须自行编写servlet,并插入适合你的Hibernate代码。
+        </para>
+
+        <para>
+			请记住Hibernate作为一个数据库访问层,是与你的程序紧密相关的。通常情况下,所有其他层次都依赖持久机制。请确信你理解了这种设计的内涵。
+	    </para>
+
+        <para>
+         若希望学习更复杂的例子,请参阅http://caveatemptor.hibernate.org/ 。在 http://www.hibernate.org/Documentation 也可以得到其他教程的链接。
+            
+        </para>
+
+    </sect1>
+
+</chapter>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/session_api.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/session_api.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/session_api.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1121 @@
+<chapter id="objectstate">
+  
+   	<title>与对象共事</title>
+    
+    <para>
+	    Hibernate是完整的对象/关系映射解决方案,它提供了对象<emphasis>状态管理(state management)</emphasis>的功能,使开发者不再需要理会底层数据库系统的细节。
+		也就是说,相对于常见的JDBC/SQL持久层方案中需要<literal>管理SQL语句</literal>,Hibernate采用了更自然的面向对象的视角来持久化Java应用中的数据。
+    </para>    
+
+
+    <para>
+		换句话说,使用Hibernate的开发者应该总是关注对象的<emphasis>状态(state)</emphasis>,不必考虑SQL语句的执行。
+		这部分细节已经由Hibernate掌管妥当,只有开发者在进行系统性能调优的时候才需要进行了解。
+    </para>
+
+    <sect1 id="objectstate-overview">
+
+        <title>Hibernate对象状态(object states)</title>
+
+
+        <para>
+            Hibernate定义并支持下列对象状态(state):
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                
+				<para>
+                    <emphasis>瞬时(Transient)</emphasis> - 由<literal>new</literal>操作符创建,且尚未与Hibernate <literal>Session</literal>
+					关联的对象被认定为瞬时(Transient)的。瞬时(Transient)对象不会被持久化到数据库中,也不会被赋予持久化标识(identifier)。
+					如果瞬时(Transient)对象在程序中没有被引用,它会被垃圾回收器(garbage collector)销毁。
+					使用Hibernate <literal>Session</literal>可以将其变为持久(Persistent)状态。(Hibernate会自动执行必要的SQL语句)
+                </para>
+                
+            </listitem>
+            <listitem>
+
+                <para>
+                    <emphasis>持久(Persistent)</emphasis> - 持久(Persistent)的实例在数据库中有对应的记录,并拥有一个持久化标识(identifier)。
+					持久(Persistent)的实例可能是刚被保存的,或刚被加载的,无论哪一种,按定义,它存在于相关联的<literal>Session</literal>作用范围内。
+					Hibernate会检测到处于持久(Persistent)状态的对象的任何改动,在当前操作单元(unit of work)执行完毕时将对象数据(state)与数据库同步(synchronize)。
+					开发者不需要手动执行<literal>UPDATE</literal>。将对象从持久(Persistent)状态变成瞬时(Transient)状态同样也不需要手动执行<literal>DELETE</literal>语句。
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    <emphasis>脱管(Detached)</emphasis> - 与持久(Persistent)对象关联的<literal>Session</literal>被关闭后,对象就变为脱管(Detached)的。
+					对脱管(Detached)对象的引用依然有效,对象可继续被修改。脱管(Detached)对象如果重新关联到某个新的<literal>Session</literal>上,
+					会再次转变为持久(Persistent)的(在Detached其间的改动将被持久化到数据库)。
+                	这个功能使得一种编程模型,即中间会给用户思考时间(user think-time)的长时间运行的操作单元(unit of work)的编程模型成为可能。
+                	我们称之为<emphasis>应用程序事务</emphasis>,即从用户观点看是一个操作单元(unit of work)。
+                </para>
+
+            </listitem>
+        </itemizedlist>
+
+		<para>
+			接下来我们来细致的讨论下状态(states)及状态间的转换(state transitions)(以及触发状态转换的Hibernate方法)。
+        </para>
+
+    </sect1>
+
+    <sect1 id="objectstate-makingpersistent" revision="1">
+        <title>使对象持久化</title>
+                        
+        <para>
+			Hibernate认为持久化类(persistent class)新实例化的对象是<emphasis>瞬时(Transient)</emphasis>的。
+			我们可通过将瞬时(Transient)对象与session关联而把它变为<emphasis>持久(Persistent)</emphasis>的。
+        </para>        
+        
+        <programlisting><![CDATA[DomesticCat fritz = new DomesticCat();
+fritz.setColor(Color.GINGER);
+fritz.setSex('M');
+fritz.setName("Fritz");
+Long generatedId = (Long) sess.save(fritz);]]></programlisting>
+
+        <para>
+			如果<literal>Cat</literal>的持久化标识(identifier)是<literal>generated</literal>类型的,
+			那么该标识(identifier)会自动在<literal>save()</literal>被调用时产生并分配给<literal>cat</literal>。
+			如果<literal>Cat</literal>的持久化标识(identifier)是<literal>assigned</literal>类型的,或是一个复合主键(composite key),
+			那么该标识(identifier)应当在调用<literal>save()</literal>之前手动赋予给<literal>cat</literal>。
+			你也可以按照EJB3 early draft中定义的语义,使用<literal>persist()</literal>替代<literal>save()</literal>。
+        </para>        
+        
+        
+        <para>
+            此外,你可以用一个重载版本的<literal>save()</literal>方法。
+        </para>
+        
+<programlisting><![CDATA[DomesticCat pk = new DomesticCat();
+pk.setColor(Color.TABBY);
+pk.setSex('F');
+pk.setName("PK");
+pk.setKittens( new HashSet() );
+pk.addKitten(fritz);
+sess.save( pk, new Long(1234) );]]></programlisting>
+        
+                
+		<para>
+			如果你持久化的对象有关联的对象(associated objects)(例如上例中的<literal>kittens</literal>集合)
+  			那么对这些对象(译注:pk和kittens)进行持久化的顺序是任意的(也就是说可以先对kittens进行持久化也可以先对pk进行持久化),
+  			除非你在外键列上有<literal>NOT NULL</literal>约束。
+            Hibernate不会违反外键约束,但是如果你用错误的顺序持久化对象(译注:在pk持久化之前持久化kitten),那么可能会违反<literal>NOT NULL</literal>约束。
+        </para>
+        
+        <para>
+			通常你不会为这些细节烦心,因为你很可能会使用Hibernate的
+			<emphasis>传播性持久化(transitive persistence)</emphasis>功能自动保存相关联那些对象。
+			这样连违反<literal>NOT NULL</literal>约束的情况都不会出现了 - Hibernate会管好所有的事情。
+			传播性持久化(transitive persistence)将在本章稍后讨论。
+        </para>        
+        
+    </sect1>
+
+    <sect1 id="objectstate-loading">
+		<title>装载对象</title>
+        <para>
+        	如果你知道某个实例的持久化标识(identifier),你就可以使用<literal>Session</literal>的<literal>load()</literal>方法
+        	来获取它。 <literal>load()</literal>的另一个参数是指定类的.class对象。
+        	本方法会创建指定类的持久化实例,并从数据库加载其数据(state)。
+        </para>        
+
+        <programlisting><![CDATA[Cat fritz = (Cat) sess.load(Cat.class, generatedId);]]></programlisting>
+
+<programlisting><![CDATA[// you need to wrap primitive identifiers
+long id = 1234;
+DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id) );]]></programlisting>
+
+        <para>
+            此外, 你可以把数据(state)加载到指定的对象实例上(覆盖掉该实例原来的数据)。
+        </para>
+
+<programlisting><![CDATA[Cat cat = new DomesticCat();
+// load pk's state into cat
+sess.load( cat, new Long(pkId) );
+Set kittens = cat.getKittens();]]></programlisting>
+
+        
+        <para>
+			请注意如果没有匹配的数据库记录,<literal>load()</literal>方法可能抛出无法恢复的异常(unrecoverable exception)。
+			如果类的映射使用了代理(proxy),<literal>load()</literal>方法会返回一个未初始化的代理,直到你调用该代理的某方法时才会去访问数据库。
+			若你希望在某对象中创建一个指向另一个对象的关联,又不想在从数据库中装载该对象时同时装载相关联的那个对象,那么这种操作方式就用得上的了。
+			如果为相应类映射关系设置了<literal>batch-size</literal>,
+			那么使用这种操作方式允许多个对象被一批装载(因为返回的是代理,无需从数据库中抓取所有对象的数据)。
+        </para>        
+        
+
+        <para>
+       		如果你不确定是否有匹配的行存在,应该使用<literal>get()</literal>方法,它会立刻访问数据库,如果没有对应的记录,会返回null。
+        </para>
+        
+        <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id);
+if (cat==null) {
+    cat = new Cat();
+    sess.save(cat, id);
+}
+return cat;]]></programlisting>
+
+        <para>
+			你甚至可以选用某个<literal>LockMode</literal>,用SQL的<literal>SELECT ... FOR UPDATE</literal>装载对象。
+			请查阅API文档以获取更多信息。
+        </para>
+
+        <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);]]></programlisting>
+        
+        
+        <para>
+              注意,任何关联的对象或者包含的集合都<emphasis>不会</emphasis>被以<literal>FOR UPDATE</literal>方式返回,
+ 			除非你指定了<literal>lock</literal>或者<literal>all</literal>作为关联(association)的级联风格(cascade style)。
+        </para>
+
+        
+		<para>
+			任何时候都可以使用<literal>refresh()</literal>方法强迫装载对象和它的集合。如果你使用数据库触发器功能来处理对象的某些属性,这个方法就很有用了。
+        </para>
+        
+        <programlisting><![CDATA[sess.save(cat);
+sess.flush(); //force the SQL INSERT
+sess.refresh(cat); //re-read the state (after the trigger executes)]]></programlisting>
+
+        
+        <para>
+			此处通常会出现一个重要问题: Hibernate会从数据库中装载多少东西?会执行多少条相应的SQL<literal>SELECT</literal>语句?
+           	这取决于<emphasis>抓取策略(fetching strategy)</emphasis>,会在<xref linkend="performance-fetching"/>中解释。
+        </para>        
+
+    </sect1>
+
+    <sect1 id="objectstate-querying" revision="1">
+		<title>查询</title>
+        <para>
+			如果不知道所要寻找的对象的持久化标识,那么你需要使用查询。Hibernate支持强大且易于使用的面向对象查询语言(HQL)。
+			如果希望通过编程的方式创建查询,Hibernate提供了完善的按条件(Query By Criteria, QBC)以及按样例(Query By Example, QBE)进行查询的功能。
+			你也可以用原生SQL(native SQL)描述查询,Hibernate额外提供了将结果集(result set)转化为对象的支持。
+        </para>        
+
+        <sect2 id="objectstate-querying-executing"  revision="1">
+            <title>执行查询</title>
+            
+            <para>
+                HQL和原生SQL(native SQL)查询要通过为<literal>org.hibernate.Query</literal>的实例来表达。
+				这个接口提供了参数绑定、结果集处理以及运行实际查询的方法。
+				你总是可以通过当前<literal>Session</literal>获取一个<literal>Query</literal>对象:
+            </para>            
+
+        <programlisting><![CDATA[List cats = session.createQuery(
+    "from Cat as cat where cat.birthdate < ?")
+    .setDate(0, date)
+    .list();
+
+List mothers = session.createQuery(
+    "select mother from Cat as cat join cat.mother as mother where cat.name = ?")
+    .setString(0, name)
+    .list();
+
+List kittens = session.createQuery(
+    "from Cat as cat where cat.mother = ?")
+    .setEntity(0, pk)
+    .list();
+
+Cat mother = (Cat) session.createQuery(
+    "select cat.mother from Cat as cat where cat = ?")
+    .setEntity(0, izi)
+    .uniqueResult();]]
+
+Query mothersWithKittens = (Cat) session.createQuery(
+    "select mother from Cat as mother left join fetch mother.kittens");
+Set uniqueMothers = new HashSet(mothersWithKittens.list());]]></programlisting>
+
+            
+            <para>
+            	一个查询通常在调用<literal>list()</literal>时被执行,执行结果会完全装载进内存中的一个集合(collection)。
+            	查询返回的对象处于持久(persistent)状态。如果你知道的查询只会返回一个对象,可使用<literal>list()</literal>的快捷方式<literal>uniqueResult()</literal>。
+            	注意,使用集合预先抓取的查询往往会返回多次根对象(他们的集合类都被初始化了)。你可以通过一个集合来过滤这些重复对象。    	
+            </para>            
+
+            <sect3 id="objectstate-querying-executing-iterate">
+
+                <title>迭代式获取结果(Iterating results)</title>
+                
+                <para>
+					某些情况下,你可以使用<literal>iterate()</literal>方法得到更好的性能。
+					这通常是你预期返回的结果在session,或二级缓存(second-level cache)中已经存在时的情况。
+					如若不然,<literal>iterate()</literal>会比<literal>list()</literal>慢,而且可能简单查询也需要进行多次数据库访问:
+					<literal>iterate()</literal>会首先使用<emphasis>1</emphasis>条语句得到所有对象的持久化标识(identifiers),再根据持久化标识执行<emphasis>n</emphasis>条附加的select语句实例化实际的对象。
+                </para>                
+
+                <programlisting><![CDATA[// fetch ids
+Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate();
+while ( iter.hasNext() ) {
+    Qux qux = (Qux) iter.next();  // fetch the object
+    // something we couldnt express in the query
+    if ( qux.calculateComplicatedAlgorithm() ) {
+        // delete the current instance
+        iter.remove();
+        // dont need to process the rest
+        break;
+    }
+}]]></programlisting>
+            </sect3>
+            
+            <sect3 id="objectstate-querying-executing-tuples">
+                <title>返回元组(tuples)的查询</title>
+                
+                <para>
+                (译注:元组(tuples)指一条结果行包含多个对象)
+                    Hibernate查询有时返回元组(tuples),每个元组(tuples)以数组的形式返回:
+                </para>
+
+                <programlisting><![CDATA[Iterator kittensAndMothers = sess.createQuery(
+            "select kitten, mother from Cat kitten join kitten.mother mother")
+            .list()
+            .iterator();
+
+while ( kittensAndMothers.hasNext() ) {
+    Object[] tuple = (Object[]) kittensAndMothers.next();
+    Cat kitten  = tuple[0];
+    Cat mother  = tuple[1];
+    ....
+}]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-scalar" revision="1">
+                <title>标量(Scalar)结果</title>
+
+                <para>
+					查询可在<literal>select</literal>从句中指定类的属性,甚至可以调用SQL统计(aggregate)函数。
+					属性或统计结果被认定为"标量(Scalar)"的结果(而不是持久(persistent state)的实体)。
+                </para>
+
+                <programlisting><![CDATA[Iterator results = sess.createQuery(
+        "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
+        "group by cat.color")
+        .list()
+        .iterator();
+        
+while ( results.hasNext() ) {
+    Object[] row = (Object[]) results.next();
+    Color type = (Color) row[0];
+    Date oldest = (Date) row[1];
+    Integer count = (Integer) row[2];
+    .....
+}]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-parameters">
+                <title>绑定参数</title> 
+                
+                <para>
+                    接口<literal>Query</literal>提供了对命名参数(named parameters)、JDBC风格的<literal>问号(?)</literal>参数进行绑定的方法。
+					<emphasis>不同于JDBC,Hibernate对参数从0开始计数。</emphasis>
+                    命名参数(named parameters)在查询字符串中是形如<literal>:name</literal>的标识符。
+                    命名参数(named parameters)的优点是:
+                </para>                
+
+                <itemizedlist spacing="compact">
+                    <listitem>
+                        <para>
+                            命名参数(named parameters)与其在查询串中出现的顺序无关
+                        </para>                        
+                    </listitem>
+                    <listitem>
+                        <para>
+                                它们可在同一查询串中多次出现
+                        </para>
+                    </listitem>
+                    <listitem>
+                        <para>
+                                它们本身是自我说明的
+                        </para>                        
+                    </listitem>
+                </itemizedlist>
+
+                <programlisting><![CDATA[//named parameter (preferred)
+Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
+q.setString("name", "Fritz");
+Iterator cats = q.iterate();]]></programlisting>
+
+                <programlisting><![CDATA[//positional parameter
+Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
+q.setString(0, "Izi");
+Iterator cats = q.iterate();]]></programlisting>
+
+                <programlisting><![CDATA[//named parameter list
+List names = new ArrayList();
+names.add("Izi");
+names.add("Fritz");
+Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)");
+q.setParameterList("namesList", names);
+List cats = q.list();]]></programlisting>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-pagination">
+                <title>分页</title>
+
+                <para>
+                    如果你需要指定结果集的范围(希望返回的最大行数/或开始的行数),应该使用<literal>Query</literal>接口提供的方法:
+                </para>                
+
+                <programlisting><![CDATA[Query q = sess.createQuery("from DomesticCat cat");
+q.setFirstResult(20);
+q.setMaxResults(10);
+List cats = q.list();]]></programlisting>
+
+                <para>
+                    Hibernate 知道如何将这个有限定条件的查询转换成你的数据库的原生SQL(native SQL)。
+                </para>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-scrolling">
+				<title>可滚动遍历(Scrollable iteration)</title>
+				
+                
+				<para>
+					如果你的JDBC驱动支持可滚动的<literal>ResuleSet</literal>,<literal>Query</literal>接口可以使用<literal>ScrollableResults</literal>,允许你在查询结果中灵活游走。
+				</para>
+
+                <programlisting><![CDATA[Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
+                            "order by cat.name");
+ScrollableResults cats = q.scroll();
+if ( cats.first() ) {
+
+    // find the first name on each page of an alphabetical list of cats by name
+    firstNamesOfPages = new ArrayList();
+    do {
+        String name = cats.getString(0);
+        firstNamesOfPages.add(name);
+    }
+    while ( cats.scroll(PAGE_SIZE) );
+
+    // Now get the first page of cats
+    pageOfCats = new ArrayList();
+    cats.beforeFirst();
+    int i=0;
+    while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) );
+
+}
+cats.close()]]></programlisting>
+
+                <para>
+					请注意,使用此功能需要保持数据库连接(以及游标(cursor))处于一直打开状态。
+					如果你需要断开连接使用分页功能,请使用<literal>setMaxResult()</literal>/<literal>setFirstResult()</literal>
+                </para>
+
+            </sect3>
+
+            <sect3 id="objectstate-querying-executing-named" revision="1">
+                <title>外置命名查询(Externalizing named queries)</title>
+
+                <para>
+					你可以在映射文件中定义命名查询(named queries)。
+					(如果你的查询串中包含可能被解释为XML标记(markup)的字符,别忘了用<literal>CDATA</literal>包裹起来。)
+                </para>                
+
+                <programlisting><![CDATA[<query name="ByNameAndMaximumWeight"><![CDATA[
+    from eg.DomesticCat as cat
+        where cat.name = ?
+        and cat.weight > ?
+] ]></query>]]></programlisting>
+
+
+                <para>
+					参数绑定及执行以编程方式(programatically)完成:
+                </para>                
+
+                <programlisting><![CDATA[Query q = sess.getNamedQuery("ByNameAndMaximumWeight");
+q.setString(0, name);
+q.setInt(1, minWeight);
+List cats = q.list();]]></programlisting>
+
+                
+                <para>
+                	请注意实际的程序代码与所用的查询语言无关,你也可在元数据中定义原生SQL(native SQL)查询,
+                	或将原有的其他的查询语句放在配置文件中,这样就可以让Hibernate统一管理,达到迁移的目的。
+                </para>                
+
+                <para>
+
+                     也请注意在<literal>&lt;hibernate-mapping&gt;</literal>元素中声明的查询必须有一个全局唯一的名字,而在<literal>&lt;class&gt;</literal>元素中声明的查询自动具有全局名,是通过类的全名加以限定的。比如<literal>eg.Cat.ByNameAndMaximumWeight</literal>。
+                </para>
+
+            </sect3>
+
+        </sect2>
+
+        <sect2 id="objectstate-filtering" revision="1">
+            <title>过滤集合</title>
+            
+            
+            <para>
+     		    集合<emphasis>过滤器(filter)</emphasis>是一种用于一个持久化集合或者数组的特殊的查询。查询字符串中可以使用<literal>"this"</literal>来引用集合中的当前元素。
+	        </para>
+
+            <programlisting><![CDATA[Collection blackKittens = session.createFilter(
+    pk.getKittens(), 
+    "where this.color = ?")
+    .setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) )
+    .list()
+);]]></programlisting>
+        
+            
+            <para>
+                 返回的集合可以被认为是一个包(bag, 无顺序可重复的集合(collection)),它是所给集合的副本。
+                原来的集合不会被改动(这与“过滤器(filter)”的隐含的含义不符,不过与我们期待的行为一致)。
+            </para>            
+
+	        <para>
+	         	请注意过滤器(filter)并不需要<literal>from</literal>子句(当然需要的话它们也可以加上)。过滤器(filter)不限定于只能返回集合元素本身。
+	        </para>
+
+            <programlisting><![CDATA[Collection blackKittenMates = session.createFilter(
+    pk.getKittens(), 
+    "select this.mate where this.color = eg.Color.BLACK.intValue")
+    .list();]]></programlisting>
+            
+            <para>
+				即使无条件的过滤器(filter)也是有意义的。例如,用于加载一个大集合的子集:
+            </para>            
+
+            <programlisting><![CDATA[Collection tenKittens = session.createFilter(
+    mother.getKittens(), "")
+    .setFirstResult(0).setMaxResults(10)
+    .list();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="objecstate-querying-criteria" revision="1">
+			<title>条件查询(Criteria queries)</title>
+			
+	        <para>
+	            HQL极为强大,但是有些人希望能够动态的使用一种面向对象API创建查询,而非在他们的Java代码中嵌入字符串。对于那部分人来说,Hibernate提供了直观的<literal>Criteria</literal>查询API。
+	        </para>            
+
+            <programlisting><![CDATA[Criteria crit = session.createCriteria(Cat.class);
+crit.add( Expression.eq( "color", eg.Color.BLACK ) );
+crit.setMaxResults(10);
+List cats = crit.list();]]></programlisting>
+    
+
+            <para>
+                <literal>Criteria</literal>以及相关的<literal>样例(Example)</literal>API将会再<xref linkend="querycriteria"/>中详细讨论。
+            </para>
+            
+        </sect2>
+
+        <sect2 id="objectstate-querying-nativesql" revision="2">
+	        <title>使用原生SQL的查询</title>
+
+            
+            <para>
+				你可以使用<literal>createSQLQuery()</literal>方法,用SQL来描述查询,并由Hibernate将结果集转换成对象。
+				请注意,你可以在任何时候调用<literal>session.connection()</literal>来获得并使用JDBC <literal>Connection</literal>对象。
+				如果你选择使用Hibernate的API, 你必须把SQL别名用大括号包围起来:
+            </para>            
+
+            <programlisting><![CDATA[List cats = session.createSQLQuery(
+    "SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10",
+    "cat",
+    Cat.class
+).list();]]></programlisting>
+                
+            <programlisting><![CDATA[List cats = session.createSQLQuery(
+    "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
+           "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
+    "FROM CAT {cat} WHERE ROWNUM<10",
+    "cat",
+    Cat.class
+).list()]]></programlisting>
+
+
+            <para>
+                和Hibernate查询一样,SQL查询也可以包含命名参数和占位参数。
+			  可以在<xref linkend="querysql"/>找到更多关于Hibernate中原生SQL(native SQL)的信息。
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="objectstate-modifying" revision="1">
+        <title>修改持久对象</title>
+
+        <para>
+            <emphasis>事务中的持久实例</emphasis>(就是通过<literal>session</literal>装载、保存、创建或者查询出的对象)
+            被应用程序操作所造成的任何修改都会在<literal>Session</literal>被<emphasis>刷出(flushed)</emphasis>的时候被持久化(本章后面会详细讨论)。
+			这里不需要调用某个特定的方法(比如<literal>update()</literal>,设计它的目的是不同的)将你的修改持久化。
+            所以最直接的更新一个对象的方法就是在<literal>Session</literal>处于打开状态时<literal>load()</literal>它,然后直接修改即可:
+        </para>
+
+        <programlisting><![CDATA[DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
+cat.setName("PK");
+sess.flush();  // changes to cat are automatically detected and persisted]]></programlisting>
+
+        <para>
+        	有时这种程序模型效率低下,因为它在同一Session里需要一条SQL <literal>SELECT</literal>语句(用于加载对象)
+        	以及一条SQL <literal>UPDATE</literal>语句(持久化更新的状态)。
+        	为此Hibernate提供了另一种途径,使用脱管(detached)实例。
+        </para>
+
+        
+        <para>
+            <emphasis>请注意Hibernate本身不提供直接执行<literal>UPDATE</literal>或<literal>DELETE</literal>语句的API。
+            Hibernate提供的是<emphasis>状态管理(state management)</emphasis>服务,你不必考虑要使用的<emphasis>语句(statements)</emphasis>。
+			JDBC是出色的执行SQL语句的API,任何时候调用<literal>session.connection()</literal>你都可以得到一个JDBC <literal>Connection</literal>对象。
+			此外,在联机事务处理(OLTP)程序中,大量操作(mass operations)与对象/关系映射的观点是相冲突的。
+            Hibernate的将来版本可能会提供专门的进行大量操作(mass operation)的功能。            
+            参考<xref linkend="batch"/>,寻找一些可用的批量(batch)操作技巧。</emphasis>
+        </para>        
+
+    </sect1>
+
+    <sect1 id="objectstate-detached" revision="2">
+		<title>修改脱管(Detached)对象</title>     
+
+        <para>
+            很多程序需要在某个事务中获取对象,然后将对象发送到界面层去操作,最后在一个新的事务保存所做的修改。
+            在高并发访问的环境中使用这种方式,通常使用附带版本信息的数据来保证这些“长“工作单元之间的隔离。
+        </para>
+
+        <para>
+        	Hibernate通过提供<literal>Session.update()</literal>或<literal>Session.merge()</literal>
+        	重新关联脱管实例的办法来支持这种模型。
+        </para>        
+
+
+        <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catId);
+Cat potentialMate = new Cat();
+firstSession.save(potentialMate);
+
+// in a higher layer of the application
+cat.setMate(potentialMate);
+
+// later, in a new session
+secondSession.update(cat);  // update cat
+secondSession.update(mate); // update mate]]></programlisting>
+
+        <para>
+            如果具有<literal>catId</literal>持久化标识的<literal>Cat</literal>之前已经被<literal>另一Session(secondSession)</literal>装载了,
+            应用程序进行重关联操作(reattach)的时候会抛出一个异常。
+        </para>
+
+
+        <para>
+        	如果你确定当前session没有包含与之具有相同持久化标识的持久实例,使用<literal>update()</literal>。
+        	如果想随时合并你的的改动而不考虑session的状态,使用<literal>merge()</literal>。
+	         换句话说,在一个新session中通常第一个调用的是<literal>update()</literal>方法,以便保证重新关联脱管(detached)对象的操作首先被执行。
+        </para>
+
+        
+        <para>
+		    如果希望相关联的脱管对象(通过引用“可到达”的脱管对象)的数据也要更新到数据库时(并且也<emphasis>仅仅</emphasis>在这种情况),
+		    可以对该相关联的脱管对象单独调用<literal>update()</literal>
+			当然这些可以自动完成,即通过使用<emphasis>传播性持久化(transitive persistence)</emphasis>,请看<xref linkend="objectstate-transitive"/>。
+        </para>        
+
+        
+        <para>
+            <literal>lock()</literal>方法也允许程序重新关联某个对象到一个新session上。不过,该脱管(detached)的对象必须是没有修改过的!
+        </para>        
+
+        <programlisting><![CDATA[//just reassociate:
+sess.lock(fritz, LockMode.NONE);
+//do a version check, then reassociate:
+sess.lock(izi, LockMode.READ);
+//do a version check, using SELECT ... FOR UPDATE, then reassociate:
+sess.lock(pk, LockMode.UPGRADE);]]></programlisting>
+
+
+        <para>
+            请注意,<literal>lock()</literal>可以搭配多种<literal>LockMode</literal>,
+            更多信息请阅读API文档以及关于事务处理(transaction handling)的章节。重新关联不是<literal>lock()</literal>的唯一用途。
+        </para>
+
+        
+        <para>
+            其他用于长时间工作单元的模型会在<xref linkend="transactions-optimistic"/>中讨论。
+        </para>        
+
+    </sect1>
+
+    <sect1 id="objectstate-saveorupdate">
+        <title>自动状态检测</title>
+        
+        
+        <para>
+            Hibernate的用户曾要求一个既可自动分配新持久化标识(identifier)保存瞬时(transient)对象,又可更新/重新关联脱管(detached)实例的通用方法。
+            <literal>saveOrUpdate()</literal>方法实现了这个功能。
+        </para>        
+
+        <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catID);
+
+// in a higher tier of the application
+Cat mate = new Cat();
+cat.setMate(mate);
+
+// later, in a new session
+secondSession.saveOrUpdate(cat);   // update existing state (cat has a non-null id)
+secondSession.saveOrUpdate(mate);  // save the new instance (mate has a null id)]]></programlisting>
+
+
+        <para>
+            <literal>saveOrUpdate()</literal>用途和语义可能会使新用户感到迷惑。
+			首先,只要你没有尝试在某个session中使用来自另一session的实例,你就应该不需要使用<literal>update()</literal>,
+            <literal>saveOrUpdate()</literal>,或<literal>merge()</literal>。有些程序从来不用这些方法。
+        </para>
+
+        
+        <para>
+            通常下面的场景会使用<literal>update()</literal>或<literal>saveOrUpdate()</literal>:
+        </para>        
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    程序在第一个session中加载对象
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    该对象被传递到表现层
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+					对象发生了一些改动
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+					该对象被返回到业务逻辑层
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    程序调用第二个session的<literal>update()</literal>方法持久这些改动
+                </para>                
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>saveOrUpdate()</literal>做下面的事:
+        </para>        
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    如果对象已经在本session中持久化了,不做任何事
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                	如果另一个与本session关联的对象拥有相同的持久化标识(identifier),抛出一个异常
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+					如果对象没有持久化标识(identifier)属性,对其调用<literal>save()</literal>
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                	如果对象的持久标识(identifier)表明其是一个新实例化的对象,对其调用<literal>save()</literal>
+                </para>                
+            </listitem>
+            <listitem>
+              	<para>
+              		如果对象是附带版本信息的(通过<literal>&lt;version&gt;</literal>或<literal>&lt;timestamp&gt;</literal>)
+					并且版本属性的值表明其是一个新实例化的对象,<literal>save()</literal>它。
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    否则<literal>update()</literal> 这个对象
+                </para>                
+            </listitem>
+        </itemizedlist>
+
+
+        <para>
+            <literal>merge()</literal>可非常不同:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                	如果session中存在相同持久化标识(identifier)的实例,用用户给出的对象的状态覆盖旧有的持久实例
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                	如果session没有相应的持久实例,则尝试从数据库中加载,或创建新的持久化实例
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+					最后返回该持久实例
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                	用户给出的这个对象没有被关联到session上,它依旧是脱管的
+                </para>                
+            </listitem>
+        </itemizedlist>
+
+    </sect1>
+
+    <sect1 id="objectstate-deleting" revision="1">
+        <title>删除持久对象</title>
+
+        <para>
+            使用<literal>Session.delete()</literal>会把对象的状态从数据库中移除。
+            当然,你的应用程序可能仍然持有一个指向已删除对象的引用。所以,最好这样理解:<literal>delete()</literal>的用途是把一个持久实例变成瞬时(transient)实例。
+        </para>
+        
+        <programlisting><![CDATA[sess.delete(cat);]]></programlisting>
+
+        
+        <para>
+            你可以用你喜欢的任何顺序删除对象,不用担心外键约束冲突。当然,如果你搞错了顺序,还是有可能引发在外键字段定义的<literal>NOT NULL</literal>约束冲突。
+            例如你删除了父对象,但是忘记删除孩子们。
+        </para>        
+
+    </sect1>
+    
+    <sect1 id="objectstate-replicating" revision="1">
+    	<title>在两个不同数据库间复制对象</title>
+    	
+    	
+    	<para>
+    		偶尔会用到不重新生成持久化标识(identifier),将持久实例以及其关联的实例持久到不同的数据库中的操作。
+    	</para>    	
+    	
+        <programlisting><![CDATA[//retrieve a cat from one database
+Session session1 = factory1.openSession();
+Transaction tx1 = session1.beginTransaction();
+Cat cat = session1.get(Cat.class, catId);
+tx1.commit();
+session1.close();
+
+//reconcile with a second database
+Session session2 = factory2.openSession();
+Transaction tx2 = session2.beginTransaction();
+session2.replicate(cat, ReplicationMode.LATEST_VERSION);
+tx2.commit();
+session2.close();]]></programlisting>
+
+        
+        <para>
+            <literal>ReplicationMode</literal>决定在和数据库中已存在记录由冲突时,<literal>replicate()</literal>如何处理。
+        </para>        
+        
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.IGNORE</literal> - 忽略它
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.OVERWRITE</literal> - 覆盖相同的行
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.EXCEPTION</literal> - 抛出异常
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>ReplicationMode.LATEST_VERSION</literal> - 如果当前的版本较新,则覆盖,否则忽略
+                </para>                
+            </listitem>
+        </itemizedlist>
+
+    	
+        <para>
+        	这个功能的用途包括使录入的数据在不同数据库中一致,产品升级时升级系统配置信息,回滚non-ACID事务中的修改等等。
+        	(译注,non-ACID,非ACID;ACID,Atomic,Consistent,Isolated and Durable的缩写)
+        </para>
+    	
+    </sect1>
+
+    <sect1 id="objectstate-flushing">
+        <title>Session刷出(flush)</title>
+
+        
+        <para>
+            每间隔一段时间,<literal>Session</literal>会执行一些必需的SQL语句来把内存中的对象的状态同步到JDBC连接中。这个过程被称为<emphasis>刷出(flush)</emphasis>,默认会在下面的时间点执行:
+        </para>        
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    在某些查询执行之前
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    在调用<literal>org.hibernate.Transaction.commit()</literal>的时候
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    在调用<literal>Session.flush()</literal>的时候
+                </para>                
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            涉及的SQL语句会按照下面的顺序发出执行:
+        </para>        
+
+        <orderedlist spacing="compact">
+            <listitem>
+                <para>
+                    所有对实体进行插入的语句,其顺序按照对象执行<literal>Session.save()</literal>的时间顺序
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    所有对实体进行更新的语句
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    所有进行集合删除的语句
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    所有对集合元素进行删除,更新或者插入的语句
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    所有进行集合插入的语句
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    所有对实体进行删除的语句,其顺序按照对象执行<literal>Session.delete()</literal>的时间顺序
+                </para>                
+            </listitem>
+        </orderedlist>
+
+        <para>
+            (有一个例外是,如果对象使用<literal>native</literal>方式来生成ID(持久化标识)的话,它们一执行save就会被插入。)
+        </para>
+        
+        <para>
+            除非你明确地发出了<literal>flush()</literal>指令,关于Session<emphasis>何时</emphasis>会执行这些JDBC调用是完全无法保证的,只能保证它们执行的前后顺序。
+            当然,Hibernate保证,<literal>Query.list(..)</literal>绝对不会返回已经失效的数据,也不会返回错误数据。
+        </para>        
+
+        
+        <para>
+            也可以改变默认的设置,来让刷出(flush)操作发生的不那么频繁。
+            <literal>FlushMode</literal>类定义了三种不同的方式。
+              仅在提交时刷出(仅当Hibernate的<literal>Transaction</literal> API被使用时有效),
+              按照刚才说的方式刷出,
+              以及除非明确使用<literal>flush()</literal>否则从不刷出。
+              最后一种模式对于那些需要长时间保持<literal>Session</literal>为打开或者断线状态的长时间运行的工作单元很有用。
+            (参见 <xref linkend="transactions-optimistic-longsession"/>).
+        </para>        
+
+        <programlisting><![CDATA[sess = sf.openSession();
+Transaction tx = sess.beginTransaction();
+sess.setFlushMode(FlushMode.COMMIT); // allow queries to return stale state
+
+Cat izi = (Cat) sess.load(Cat.class, id);
+izi.setName(iznizi);
+
+// might return stale data
+sess.find("from Cat as cat left outer join cat.kittens kitten");
+
+// change to izi is not flushed!
+...
+tx.commit(); // flush occurs
+sess.close();]]></programlisting>
+
+
+        <para>
+        	刷出(flush)期间,可能会抛出异常。(例如一个DML操作违反了约束)
+			异常处理涉及到对Hibernate事务性行为的理解,因此我们将在<xref linkend="transactions"/>中讨论。
+        </para>
+        
+    </sect1>
+
+    <sect1 id="objectstate-transitive"  revision="1">
+        <title>传播性持久化(transitive persistence)</title>
+
+        <para>
+           	对每一个对象都要执行保存,删除或重关联操作让人感觉有点麻烦,尤其是在处理许多彼此关联的对象的时候。
+             一个常见的例子是父子关系。考虑下面的例子:
+        </para>
+
+        
+        <para>
+        	如果一个父子关系中的子对象是值类型(value typed)(例如,地址或字符串的集合)的,他们的生命周期会依赖于父对象,可以享受方便的级联操作(Cascading),不需要额外的动作。
+			父对象被保存时,这些值类型(value typed)子对象也将被保存;父对象被删除时,子对象也将被删除。
+			这对将一个子对象从集合中移除是同样有效:Hibernate会检测到,并且因为值类型(value typed)的对象不可能被其他对象引用,所以Hibernate会在数据库中删除这个子对象。
+        </para>        
+
+        
+        <para>
+        	现在考虑同样的场景,不过父子对象都是实体(entities)类型,而非值类型(value typed)(例如,类别与个体,或母猫和小猫)。
+			实体有自己的生命期,允许共享对其的引用(因此从集合中移除一个实体,不意味着它可以被删除),
+			并且实体到其他关联实体之间默认没有级联操作的设置。
+            Hibernate默认不实现所谓的<emphasis>可到达即持久化(persistence by reachability)</emphasis>的策略。
+        </para>        
+
+        <para>
+        	每个Hibernate session的基本操作 - 包括 <literal>persist(), merge(),
+            saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate()</literal> - 都有对应的级联风格(cascade style)。
+    		这些级联风格(cascade style)风格分别命名为 <literal>create, 
+            merge, save-update, delete, lock, refresh, evict, replicate</literal>。
+            如果你希望一个操作被顺着关联关系级联传播,你必须在映射文件中指出这一点。例如:
+        </para>        
+        
+        <programlisting><![CDATA[<one-to-one name="person" cascade="persist"/>]]></programlisting>
+        
+
+        <para>
+            级联风格(cascade style)是可组合的:
+        </para>
+        
+        <programlisting><![CDATA[<one-to-one name="person" cascade="persist,delete,lock"/>]]></programlisting>
+        
+        
+       <para>
+            你可以使用<literal>cascade="all"</literal>来指定<emphasis>全部</emphasis>操作都顺着关联关系级联(cascaded)。
+			默认值是<literal>cascade="none"</literal>,即任何操作都不会被级联(cascaded)。
+        </para>
+        
+        <para>
+        	注意有一个特殊的级联风格(cascade style) <literal>delete-orphan</literal>,只应用于one-to-many关联,表明<literal>delete()</literal>操作
+        	应该被应用于所有从关联中删除的对象。
+        </para>        
+
+
+
+        <para>
+            建议:
+        </para>        
+
+       <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                	通常在<literal>&lt;many-to-one&gt;</literal>或<literal>&lt;many-to-many&gt;</literal>关系中应用级联(cascade)没什么意义。
+					级联(cascade)通常在 <literal>&lt;one-to-one&gt;</literal>和<literal>&lt;one-to-many&gt;</literal>关系中比较有用。
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                	如果子对象的寿命限定在父亲对象的寿命之内,可通过指定<literal>cascade="all,delete-orphan"</literal>将其变为<emphasis>自动生命周期管理的对象(lifecycle object)</emphasis>。
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                	其他情况,你可根本不需要级联(cascade)。但是如果你认为你会经常在某个事务中同时用到父对象与子对象,并且你希望少打点儿字,可以考虑使用<literal>cascade="persist,merge,save-update"</literal>。
+                </para>                
+            </listitem>
+        </itemizedlist>
+
+        <para>
+        	可以使用<literal>cascade="all"</literal>将一个关联关系(无论是对值对象的关联,或者对一个集合的关联)标记为<emphasis>父/子</emphasis>关系的关联。
+        	这样对父对象进行save/update/delete操作就会导致子对象也进行save/update/delete操作。
+        </para>        
+        
+        <para>
+        	此外,一个持久的父对象对子对象的浅引用(mere reference)会导致子对象被同步save/update。
+        	不过,这个隐喻(metaphor)的说法并不完整。除非关联是<literal>&lt;one-to-many&gt;</literal>关联并且被标记为<literal>cascade="delete-orphan"</literal>,
+        	否则父对象失去对某个子对象的引用<emphasis>不会</emphasis>导致该子对象被自动删除。
+        	父子关系的级联(cascading)操作准确语义如下:
+        </para>        
+
+       <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    如果父对象被<literal>persist()</literal>,那么所有子对象也会被<literal>persist()</literal>
+                </para>                
+            </listitem>
+            <listitem>
+              <para>
+                     如果父对象被<literal>merge()</literal>,那么所有子对象也会被<literal>merge()</literal>
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                     如果父对象被<literal>save()</literal>,<literal>update()</literal>或
+                    <literal>saveOrUpdate()</literal>,那么所有子对象则会被<literal>saveOrUpdate()</literal>
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                	如果某个持久的父对象引用了瞬时(transient)或者脱管(detached)的子对象,那么子对象将会被<literal>saveOrUpdate()</literal>
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                    如果父对象被删除,那么所有子对象也会被<literal>delete()</literal>
+                </para>                
+            </listitem>
+            <listitem>
+                <para>
+                	除非被标记为<literal>cascade="delete-orphan"</literal>(删除“孤儿”模式,此时不被任何一个父对象引用的子对象会被删除),
+                	否则子对象失掉父对象对其的引用时,<emphasis>什么事也不会发生</emphasis>。
+                	如果有特殊需要,应用程序可通过显式调用delete()删除子对象。
+                </para>                
+            </listitem>
+        </itemizedlist>
+        <para>
+            最后,注意操作的级联可能是在<emphasis>调用期(call time)</emphasis>或者<emphasis>写入期(flush time)</emphasis>作用到对象图上的。所有的操作,如果允许,都在操作被执行的时候级联到可触及的关联实体上。然而,<literal>save-upate</literal>和<literal>delete-orphan</literal>是在<literal>Session</literal> flush的时候才作用到所有可触及的被关联对象上的。
+        </para>
+
+
+    </sect1>
+
+    <sect1 id="objectstate-metadata">
+        <title>使用元数据</title>
+		
+		<para>
+            Hibernate中有一个非常丰富的元级别(meta-level)的模型,含有所有的实体和值类型数据的元数据。
+              有时这个模型对应用程序本身也会非常有用。
+              比如说,应用程序可能在实现一种“智能”的深度拷贝算法时,
+              通过使用Hibernate的元数据来了解哪些对象应该被拷贝(比如,可变的值类型数据),
+              那些不应该(不可变的值类型数据,也许还有某些被关联的实体)。
+        </para>
+        
+
+        <para>
+            Hibernate提供了<literal>ClassMetadata</literal>接口,<literal>CollectionMetadata</literal>接口和<literal>Type</literal>层次体系来访问元数据。
+              可以通过<literal>SessionFactory</literal>获取元数据接口的实例。
+        </para>        
+
+        <programlisting><![CDATA[Cat fritz = ......;
+ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class);
+
+Object[] propertyValues = catMeta.getPropertyValues(fritz);
+String[] propertyNames = catMeta.getPropertyNames();
+Type[] propertyTypes = catMeta.getPropertyTypes();
+
+// get a Map of all properties which are not collections or associations
+Map namedValues = new HashMap();
+for ( int i=0; i<propertyNames.length; i++ ) {
+    if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType() ) {
+        namedValues.put( propertyNames[i], propertyValues[i] );
+    }
+}]]></programlisting>
+        
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/toolset_guide.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/toolset_guide.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/toolset_guide.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,564 @@
+<chapter id="toolsetguide" revision="2">
+    <title>工具箱指南</title>
+
+    <para>
+		可以通过一系列Eclipse插件、命令行工具和Ant任务来进行与Hibernate关联的转换。
+
+    </para>
+
+    <para>
+        除了Ant任务外,当前的<emphasis>Hibernate Tools</emphasis>也包含了Eclipse IDE的插件,用于与现存数据库的逆向工程。
+    </para>
+
+    <itemizedlist>
+        <listitem><para>
+
+            <emphasis>Mapping Editor:</emphasis> Hibernate XML映射文件的编辑器,支持自动完成和语法高亮。它也支持对类名和属性/字段名的语义自动完成,比通常的XML编辑器方便得多。
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Console:</emphasis> Console是Eclipse的一个新视图。除了对你的console配置的树状概览,你还可以获得对你持久化类及其关联的交互式视图。Console允许你对数据库执行HQL查询,并直接在Eclipse中浏览结果。
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Development Wizards:</emphasis> 在Hibernate Eclipse tools中还提供了几个向导;你可以用向导快速生成Hibernate 配置文件(cfg.xml),你甚至还可以同现存的数据库schema中反向工程出POJO源代码与Hibernate 映射文件。反向工程支持可定制的模版。
+        </para></listitem>
+        <listitem><para>
+            <emphasis>Ant Tasks:</emphasis>
+        </para></listitem>
+
+    </itemizedlist>
+
+    <para>
+        要得到更多信息,请查阅 <emphasis>Hibernate Tools</emphasis> 包及其文档。
+    </para>
+
+    <para>
+        同时,Hibernate主发行包还附带了一个集成的工具(它甚至可以在Hibernate“内部”快速运行)<emphasis>SchemaExport</emphasis> ,也就是        <literal>hbm2ddl</literal>。
+
+    </para>
+
+    <sect1 id="toolsetguide-s1" revision="2">
+        <title>Schema自动生成(Automatic schema generation)</title>
+
+        <para>
+            可以从你的映射文件使用一个Hibernate工具生成DDL。 生成的schema包含有对实体和集合类表的完整性引用约束(主键和外键)。涉及到的标示符生成器所需的表和sequence也会同时生成。
+        </para>
+        
+        <para>
+            在使用这个工具的时候,你<emphasis>必须</emphasis> 通过<literal>hibernate.dialet</literal>属性指定一个SQL<literal>方言(Dialet)</literal>,因为DDL是与供应商高度相关的。
+        </para>
+
+        <para>
+            首先,要定制你的映射文件,来改善生成的schema。
+        </para>
+
+        <sect2 id="toolsetguide-s1-2" revision="3">
+            <title>对schema定制化(Customizing the schema)</title>
+
+            <para>
+                很多Hibernate映射元素定义了可选的<literal>length</literal>、<literal>precision</literal> 或者 <literal>scale</literal>属性。你可以通过这个属性设置字段的长度、精度、小数点位数。 
+            </para>
+
+            <programlisting><![CDATA[<property name="zip" length="5"/>]]></programlisting>
+            <programlisting><![CDATA[<property name="balance" precision="12" scale="2"/>]]></programlisting>
+
+            <para>
+                有些tag还接受<literal>not-null</literal>属性(用来在表字段上生成<literal>NOT NULL</literal>约束)和<literal>unique</literal>属性(用来在表字段上生成<literal>UNIQUE</literal>约束)。
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="bar" column="barId" not-null="true"/>]]></programlisting>
+            <programlisting><![CDATA[<element column="serialNumber" type="long" not-null="true" unique="true"/>]]></programlisting>
+
+            <para>
+                <literal>unique-key</literal>属性可以对成组的字段指定一个唯一键约束(unique key constraint)。目前,<literal>unique-key</literal>属性指定的值在生成DDL时<emphasis>并不会</emphasis>被当作这个约束的名字,它们只是在用来在映射文件内部用作区分的。
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="org" column="orgId" unique-key="OrgEmployeeId"/>
+<property name="employeeId" unique-key="OrgEmployee"/>]]></programlisting>
+            
+            <para>
+                <literal>index</literal>属性会用对应的字段(一个或多个)生成一个index,它指出了这个index的名字。如果多个字段对应的index名字相同,就会生成包含这些字段的index。
+            </para>
+
+            <programlisting><![CDATA[<property name="lastName" index="CustName"/>
+<property name="firstName" index="CustName"/>]]></programlisting>
+
+            <para>
+                <literal>foreign-key</literal>属性可以用来覆盖任何生成的外键约束的名字。
+            </para>
+
+            <programlisting><![CDATA[<many-to-one name="bar" column="barId" foreign-key="FKFooBar"/>]]></programlisting>
+
+            <para>
+                很多映射元素还接受<literal>&lt;column&gt;</literal>子元素。这在定义跨越多字段的类型时特别有用。
+            </para>
+
+            <programlisting><![CDATA[<property name="name" type="my.customtypes.Name"/>
+    <column name="last" not-null="true" index="bar_idx" length="30"/>
+    <column name="first" not-null="true" index="bar_idx" length="20"/>
+    <column name="initial"/>
+</property>]]></programlisting>
+
+            <para>
+                <literal>default</literal>属性为字段指定一个默认值 (在保存被映射的类的新实例之前,你应该将同样的值赋于对应的属性)。
+            </para>
+
+            <programlisting><![CDATA[<property name="credits" type="integer" insert="false">
+    <column name="credits" default="10"/>
+</property>]]></programlisting>
+
+            <programlisting><![CDATA[<version name="version" type="integer" insert="false">
+    <column name="version" default="0"/>
+</property>]]></programlisting>
+
+            <para>
+                <literal>sql-type</literal>属性允许用户覆盖默认的Hibernate类型到SQL数据类型的映射。
+            </para>	
+            
+            <programlisting><![CDATA[<property name="balance" type="float">
+    <column name="balance" sql-type="decimal(13,3)"/>
+</property>]]></programlisting>
+            
+            <para>
+                <literal>check</literal>属性允许用户指定一个约束检查。
+            </para>
+            
+            <programlisting><![CDATA[<property name="foo" type="integer">
+    <column name="foo" check="foo > 10"/>
+</property>]]></programlisting>
+
+		<programlisting><![CDATA[<class name="Foo" table="foos" check="bar < 100.0">
+    ...
+    <property name="bar" type="float"/>
+</class>]]></programlisting>
+            
+
+            <table frame="topbot" id="schemattributes-summary" revision="1">
+                <title>Summary</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1*"/>
+                    <colspec colwidth="2.5*"/>
+                    <thead>
+                        <row>
+                            <entry>属性(Attribute)</entry>
+                            <entry>值(Values)</entry>
+                            <entry>解释(Interpretation)</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>length</literal></entry>
+                            <entry>æ•°å­—</entry>
+                            <entry>字段长度</entry>
+                            
+                        </row>
+                        <row>
+                            <entry><literal>precision</literal></entry>
+                            <entry>æ•°å­—</entry>
+                            <entry>精度(decimal precision)</entry>
+                        </row>
+                        <row>
+                            <entry><literal>scale</literal></entry>
+                            <entry>æ•°å­—</entry>
+                            <entry>小数点位数(decimal scale)</entry>
+                        </row>
+                        <row>
+                            <entry><literal>not-null</literal></entry>
+                            <entry><literal>true|false</literal></entry>
+                            <entry>指明字段是否应该是非空的</entry>
+                        </row>
+                        <row>
+                            <entry><literal>unique</literal></entry>
+                            <entry><literal>true|false</literal></entry>
+                            <entry>指明是否该字段具有惟一约束</entry>
+                        </row>
+                        <row>
+                            <entry><literal>index</literal></entry>
+                            <entry><literal>index_name</literal></entry>
+                            <entry>指明一个(多字段)的索引(index)的名字</entry>
+                        </row>
+                        <row>
+                            <entry><literal>unique-key</literal></entry>
+                            <entry><literal>unique_key_name</literal></entry>
+                            <entry>指明多字段惟一约束的名字(参见上面的说明)</entry>
+                        </row>
+                        <row>
+                            <entry><literal>foreign-key</literal></entry>
+                            <entry><literal>foreign_key_name</literal></entry>
+                            <entry>
+                                                                specifies the name of the foreign key constraint generated
+                                for an association, for a <literal>&lt;one-to-one&gt;</literal>, 
+                                <literal>&lt;many-to-one&gt;</literal>, <literal>&lt;key&gt;</literal>, 
+                                or <literal>&lt;many-to-many&gt;</literal> mapping element. Note that
+                                <literal>inverse="true"</literal> sides will not be considered
+                                by <literal>SchemaExport</literal>.
+                                指明一个外键的名字,它是为关联生成的,或者<literal>&lt;one-to-one&gt;</literal>,<literal>&lt;many-to-one&gt;</literal>, <literal>&lt;key&gt;</literal>, 或者<literal>&lt;many-to-many&gt;</literal>映射元素。注意<literal>inverse="true"</literal>在<literal>SchemaExport</literal>时会被忽略。
+
+                            </entry>
+                        </row>
+                        <row>
+                            <entry><literal>sql-type</literal></entry>
+                            <entry><literal>SQL 字段类型</literal></entry>
+                            <entry>
+                                覆盖默认的字段类型(只能用于<literal>&lt;column&gt;</literal>属性)
+                            </entry>
+                       </row>
+                       <row>
+                            <entry><literal>default</literal></entry>
+                            <entry>SQL表达式</entry>
+                            <entry>
+                                为字段指定默认值
+                            </entry>
+                       </row>
+                       <row>
+                            <entry><literal>check</literal></entry>
+                            <entry>SQL 表达式</entry>
+                            <entry>
+                            	对字段或表加入SQL约束检查
+                            </entry>
+                       </row>
+                       
+                   </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                <literal>&lt;comment&gt;</literal>元素可以让你在生成的schema中加入注释。
+            </para>
+            
+            <programlisting><![CDATA[<class name="Customer" table="CurCust">
+    <comment>Current customers only</comment>
+    ...
+</class>]]></programlisting>
+
+            <programlisting><![CDATA[<property name="balance">
+    <column name="bal">
+        <comment>Balance in USD</comment>
+    </column>
+</property>]]></programlisting>
+            
+            <para>
+                结果是在生成的DDL中包含<literal>comment on table</literal> 或者
+                <literal>comment on column</literal>语句(假若支持的话)。
+            </para>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-3"  revision="2">
+            <title>运行该工具</title>
+
+            <para>
+                <literal>SchemaExport</literal>工具把DDL脚本写到标准输出,同时/或者执行DDL语句。
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaExport</literal> <emphasis>options mapping_files</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaExport</literal>命令行选项</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>选项</entry>
+                            <entry>说明</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--quiet</literal></entry>
+                            <entry>不要把脚本输出到stdout</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--drop</literal></entry>
+                            <entry>只进行drop tables的步骤</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--create</literal></entry>
+                            <entry>只创建表</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--text</literal></entry>
+                            <entry>不执行在数据库中运行的步骤</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--output=my_schema.ddl</literal></entry>
+                            <entry>把输出的ddl脚本输出到一个文件</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>选择一个命名策略(<literal>NamingStrategy</literal>)</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry>从XML文件读入Hibernate配置</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>从文件读入数据库属性</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--format</literal></entry>
+                            <entry>把脚本中的SQL语句对齐和美化</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--delimiter=;</literal></entry>
+                            <entry>为脚本设置行结束符</entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                你甚至可以在你的应用程序中嵌入<literal>SchemaExport</literal>工具:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaExport(cfg).create(false, true);]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-4">
+            <title>属性(Properties)</title>
+
+            <para>
+                可以通过如下方式指定数据库属性:
+            </para>
+
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>通过<literal>-D</literal><emphasis>&lt;property&gt;</emphasis>系统参数</para>
+                </listitem>
+                <listitem>
+                    <para>在<literal>hibernate.properties</literal>文件中</para>
+                </listitem>
+                <listitem>
+                    <para>位于一个其它名字的properties文件中,然后用 <literal>--properties</literal>参数指定</para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                所需的参数包括:
+            </para>
+
+            <table frame="topbot">
+                <title>SchemaExport 连接属性</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>属性名</entry>
+                            <entry>说明</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                    <row>
+                        <entry><literal>hibernate.connection.driver_class</literal></entry>
+                        <entry>jdbc driver class</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.url</literal></entry>
+                        <entry>jdbc url</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.username</literal></entry>
+                        <entry>database user</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.connection.password</literal></entry>
+                        <entry>user password</entry>
+                    </row>
+                    <row>
+                        <entry><literal>hibernate.dialect</literal></entry>
+                        <entry>方言(dialect)</entry>
+                    </row>
+                    </tbody>
+                </tgroup>
+            </table>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-5">
+            <title>使用Ant(Using Ant)</title>
+
+            <para>
+                你可以在你的Ant build脚本中调用<literal>SchemaExport</literal>:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemaexport">
+    <taskdef name="schemaexport"
+        classname="org.hibernate.tool.hbm2ddl.SchemaExportTask"
+        classpathref="class.path"/>
+    
+    <schemaexport
+        properties="hibernate.properties"
+        quiet="no"
+        text="no"
+        drop="no"
+        delimiter=";"
+        output="schema-export.sql">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaexport>
+</target>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-6"  revision="2">
+            <title>对schema的增量更新(Incremental schema updates)</title>
+
+            <para>
+                <literal>SchemaUpdate</literal>工具对已存在的schema采用"增量"方式进行更新。注意<literal>SchemaUpdate</literal>严重依赖于JDBC metadata API,所以它并非对所有JDBC驱动都有效。
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>options mapping_files</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaUpdate</literal>命令行选项</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>选项</entry>
+                            <entry>说明</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--quiet</literal></entry>
+                            <entry>不要把脚本输出到stdout</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--text</literal></entry>
+                            <entry>不把脚本输出到数据库</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>选择一个命名策略 (<literal>NamingStrategy</literal>)</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>从指定文件读入数据库属性</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry>指定一个 <literal>.cfg.xml</literal>文件</entry>
+                        </row>
+                     </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+                你可以在你的应用程序中嵌入<literal>SchemaUpdate</literal>工具:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaUpdate(cfg).execute(false);]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-7">
+            <title>用Ant来增量更新schema(Using Ant for incremental schema updates)</title>
+
+            <para>
+                你可以在Ant脚本中调用<literal>SchemaUpdate</literal>:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemaupdate">
+    <taskdef name="schemaupdate"
+        classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask"
+        classpathref="class.path"/>
+    
+    <schemaupdate
+        properties="hibernate.properties"
+        quiet="no">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaupdate>
+</target>]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-8" revision="1">
+            <title>Schema 校验</title>
+
+            <para>
+                <literal>SchemaValidator</literal>工具会比较数据库现状是否与映射文档“匹配”。注意,<literal>SchemaValidator</literal> 严重依赖于JDBC的metadata API,因此不是对所有的JDBC驱动都适用。这一工具在测试的时候特别有用。
+            </para>
+
+            <para>
+                <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+                <literal>org.hibernate.tool.hbm2ddl.SchemaValidator</literal> <emphasis>options mapping_files</emphasis>
+            </para>
+
+            <table frame="topbot">
+                <title><literal>SchemaValidator</literal>命令行参数</title>
+                <tgroup cols="2">
+                    <colspec colwidth="1.5*"/>
+                    <colspec colwidth="2*"/>
+                    <thead>
+                        <row>
+                            <entry>选项</entry>
+                            <entry>描述</entry>
+                        </row>
+                    </thead>
+                    <tbody>
+                        <row>
+                            <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+                            <entry>选择一个命名策略 (<literal>NamingStrategy</literal>)</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--properties=hibernate.properties</literal></entry>
+                            <entry>从文件中读取数据库属性</entry>
+                        </row>
+                        <row>
+                            <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+                            <entry>指定一个<literal>.cfg.xml</literal>文件</entry>
+                        </row>
+                     </tbody>
+                </tgroup>
+            </table>
+
+            <para>
+               你可以在你的应用程序中嵌入<literal>SchemaValidator</literal>:
+            </para>
+
+            <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaValidator(cfg).validate();]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="toolsetguide-s1-9">
+            <title>使用Ant进行schema校验</title>
+
+            <para>
+                你可以在Ant脚本中调用<literal>SchemaValidator</literal>:
+            </para>
+
+            <programlisting><![CDATA[<target name="schemavalidate">
+    <taskdef name="schemavalidator"
+        classname="org.hibernate.tool.hbm2ddl.SchemaValidatorTask"
+        classpathref="class.path"/>
+    
+    <schemavalidator
+        properties="hibernate.properties">
+        <fileset dir="src">
+            <include name="**/*.hbm.xml"/>
+        </fileset>
+    </schemaupdate>
+</target>]]></programlisting>
+
+        </sect2>
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/transactions.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/transactions.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/transactions.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,870 @@
+<chapter id="transactions" revision="2">
+	<title>事务和并发</title>
+	<para>
+			Hibernate的事务和并发控制很容易掌握。Hibernate直接使用JDBC连接和JTA资源,不添加任何附加锁定
+			行为。我们强烈推荐你花点时间了解JDBC编程,ANSI SQL查询语言和你使用
+			的数据库系统的事务隔离规范。
+	</para>
+
+    <para>
+        Hibernate不锁定内存中的对象。你的应用程序会按照你的数据库事务的隔离级别规定的那样运作。幸亏有了<literal>Session</literal>,使得Hibernate通过标识符查找,和实体查询(不是返回标量值的报表查询)提供了可重复的读取(Repeatable reads)功能,<literal>Session</literal>同时也是事务范围内的缓存(cache)。
+    </para>
+	
+		<para>
+				除了对自动乐观并发控制提供版本管理,针对行级悲观锁定,Hibernate也提供了辅助的(较小的)API,它使用了
+				<literal>SELECT FOR UPDATE</literal>的SQL语法。本章后面会讨论乐观并发控制和这个API。
+		</para>
+		<para>
+					我们从<literal>Configuration</literal>层、<literal>SessionFactory</literal>层, 和
+      		<literal>Session</literal>层开始讨论Hibernate的并行控制、数据库事务和应用
+        	程序的长事务。
+	</para>
+    <sect1 id="transactions-basics" revision="1">
+	   <title>Session和事务范围(transaction scope)</title>
+				<para>
+						<literal>SessionFactory</literal>对象的创建代价很昂贵,它是线程安全的对象,它为所有的应用程序线程所共享。它只创建一次,通常是在应用程序启动的时候,由一个<literal>Configuraion</literal>的实例来创建。				
+				</para>
+				<para>
+						<literal>Session</literal>对象的创建代价比较小,是非线程安全的,对于单个请求,单个会话、单个的
+						工作单元而言,它只被使用一次,然后就丢弃。只有在需要的时候,一个<literal>Session</literal>对象
+						才会获取一个JDBC的<literal>Connection</literal>(或一个<literal>Datasource</literal>)
+						对象,因此假若不使用的时候它不消费任何资源。
+				</para>
+				<para>
+					此外我们还要考虑数据库事务。数据库事务应该尽可能的短,降低数据库中的锁争用。
+					数据库长事务会阻止你的应用程序扩展到高的并发负载。因此,假若在用户思考期间让数据库事务开着,直到整个工作单元完成才关闭这个事务,这绝不是一个好的设计。
+				</para>
+		<para>
+				一个操作单元(Unit of work)的范围是多大?单个的Hibernate <literal>Session</literal>能跨越多个
+				数据库事务吗?还是一个<literal>Session</literal>的作用范围对应一个数据库事务的范围?应该何时打开
+				<literal>Session</literal>,何时关闭<literal>Session</literal>?,你又如何划分数据库事务的边界呢?
+		</para>
+        <sect2 id="transactions-basics-uow"  revision="1">
+						<title>操作单元(Unit of work)</title>
+		<para>
+				首先,别用<emphasis>session-per-operation</emphasis>这种反模式了,也就是说,在单个线程中,
+				不要因为一次简单的数据库调用,就打开和关闭一次<literal>Session</literal>!数据库事务也是如此。
+				应用程序中的数据库调用是按照计划好的次序,分组为原子的操作单元。(注意,这也意味着,应用程
+				序中,在单个的SQL语句发送之后,自动事务提交(auto-commit)模式失效了。这种模式专门为SQL控制台操作设计的。
+				Hibernate禁止立即自动事务提交模式,或者期望应用服务器禁止立即自动事务提交模式。)数据库事务绝不是可有可无的,任何与数据库之间的通讯都必须在某个事务中进行,不管你是在读还是在写数据。对读数据而言,应该避免auto-commit行为,因为很多小的事务比一个清晰定义的工作单元性能差。后者也更容易维护和扩展。
+		</para>
+		<para>
+				在多用户的client/server应用程序中,最常用的模式是 <emphasis>每个请求一个会话(session-per-request)</emphasis>。
+				在这种模式下,来自客户端的请求被发送到服务器端(即Hibernate持久化层运行的地方),一
+				个新的Hibernate <literal>Session</literal>被打开,并且执行这个操作单元中所有的数据库操作。
+				一旦操作完成(同时对客户端的响应也准备就绪),session被同步,然后关闭。你也可以使用单
+				个数据库事务来处理客户端请求,在你打开<literal>Session</literal>之后启动事务,在你关闭
+				<literal>Session</literal>之前提交事务。会话和请求之间的关系是一对一的关系,这种模式对
+				于大多数应用程序来说是很棒的。
+		</para>
+		<para>
+                实现才是真正的挑战。Hibernate内置了对"当前session(current session)" 的管理,用于简化此模式。你要做的一切就是在服务器端要处理请求的时候,开启事务,在响应发送给客户之前结束事务。你可以用任何方式来完成这一操作,通常的方案有<literal>ServletFilter</literal>,在service方法中进行pointcut的AOP拦截器,或者proxy/interception容器。EJB容器是实现横切诸如EJB session bean上的事务分界,用CMT对事务进行声明等方面的标准手段。假若你决定使用编程式的事务分界,请参考本章后面讲到的Hibernate <literal>Transaction</literal> API,这对易用性和代码可移植性都有好处。
+            </para>
+
+            <para>
+                在任何时间,任何地方,你的应用代码可以通过简单的调用<literal>sessionFactory.getCurrentSession()</literal>来访问"当前session",用于处理请求。你总是会得到当前数据库事务范围内的<literal>Session</literal>。在使用本地资源或JTA环境时,必须配置它,请参见<xref linkend="architecture-current-session"/>。
+            </para>
+
+            <para>
+                有时,将<literal>Session</literal>和数据库事务的边界延伸到"展示层被渲染后"会带来便利。有些serlvet应用程序在对请求进行处理后,有个单独的渲染期,这种延伸对这种程序特别有用。假若你实现你自己的拦截器,把事务边界延伸到展示层渲染结束后非常容易。然而,假若你依赖有容器管理事务的EJB,这就不太容易了,因为事务会在EJB方法返回后结束,而那是在任何展示层渲染开始之前。请访问Hibernate网站和论坛,你可以找到<emphasis>Open Session in View</emphasis>这一模式的提示和示例。
+             </para>
+
+        </sect2>
+
+        <sect2 id="transactions-basics-apptx"  revision="1">
+						<title>长对话</title>
+						<para>
+							session-per-request模式不仅仅是一个可以用来设计操作单元的有用概念。很多业务处理都需
+							要一系列完整的与用户之间的交互,而这些用户是指对数据库有交叉访问的用户。在基于web的应用和企业
+							应用中,跨用户交互的数据库事务是无法接受的。考虑下面的例子:
+						</para>
+            <itemizedlist>
+                <listitem>
+										<para>
+												在界面的第一屏,打开对话框,用户所看到的数据是被一个特定的 <literal>Session</literal> 和数据
+												库事务载入(load)的。用户可以随意修改对话框中的数据对象。
+										</para>
+                </listitem>
+                <listitem>
+				<para>
+						5分钟后,用户点击“保存”,期望所做出的修改被持久化;同时他也期望自己是唯一修改这个信息的人,不会出现
+						修改冲突。
+				</para>
+                </listitem>
+            </itemizedlist>
+
+		<para>
+				从用户的角度来看,我们把这个操作单元称为长时间运行的<emphasis>对话</emphasis>(conversation),或者(or <emphasis>应用事务</emphasis>,application transaction)。
+				在你的应用程序中,可以有很多种方法来实现它。
+		</para>
+		<para>
+				头一个幼稚的做法是,在用户思考的过程中,保持<literal>Session</literal>和数据库事务是打开的,
+				保持数据库锁定,以阻止并发修改,从而保证数据库事务隔离级别和原子操作。这种方式当然是一个反模式,
+				因为锁争用会导致应用程序无法扩展并发用户的数目。
+		 </para>
+		<para>
+				很明显,我们必须使用多个数据库事务来实现这个对话。在这个例子中,维护业务处理的
+				事务隔离变成了应用程序层的部分责任。一个对话通常跨越多个数据库事务。如果仅仅只有一
+				个数据库事务(最后的那个事务)保存更新过的数据,而所有其他事务只是单纯的读取数据(例如在一
+				个跨越多个请求/响应周期的向导风格的对话框中),那么应用程序事务将保证其原子性。这种方式比听
+				起来还要容易实现,特别是当你使用了Hibernate的下述特性的时候:
+		</para>
+
+            <itemizedlist>
+                <listitem>
+										<para>
+										<emphasis>自动版本化</emphasis> - Hibernate能够自动进行乐观并发控制 ,如果在用户思考
+										的过程中发生并发修改,Hibernate能够自动检测到。一般我们只在对话结束时才检查。
+				</para>
+                </listitem>
+                <listitem>
+				<para>
+						<emphasis>脱管对象</emphasis>(Detached Objects)- 如果你决定采用前面已经讨论过的 
+						<emphasis>session-per-request</emphasis>模式,所有载入的实例在用户思考的过程
+						中都处于与Session脱离的状态。Hibernate允许你把与Session脱离的对象重新关联到Session
+						上,并且对修改进行持久化,这种模式被称为
+						<emphasis>session-per-request-with-detached-objects</emphasis>。自动版本化被用来隔离并发修改。
+				</para>
+                </listitem>
+                <listitem>
+				<para>
+						<emphasis>Extended (or Long) Session</emphasis> - Hibernate çš„<literal>Session</literal>
+						可以在数据库事务提交之后和底层的JDBC连接断开,当一个新的客户端请求到来的时候,它又重新连接上底层的
+						JDBC连接。这种模式被称之为<emphasis>session-per-conversation</emphasis>,这种情况可
+						能会造成不必要的Session和JDBC连接的重新关联。自动版本化被用来隔离并发修改, <literal>Session</literal>通常不允许自动flush,而是明确flush。
+				</para>
+                </listitem>
+            </itemizedlist>
+
+		<para>
+			 <emphasis>session-per-request-with-detached-objects</emphasis> 和
+			 <emphasis>session-per-conversation</emphasis> 各有优缺点,我们在本章后面乐观并发
+			 控制那部分再进行讨论。
+		</para>
+        </sect2>
+
+        <sect2 id="transactions-basics-identity">
+						<title>关注对象标识(Considering object identity)</title>
+						<para>
+							应用程序可能在两个不同的<literal>Session</literal>中并发访问同一持久化状态,但是,
+							一个持久化类的实例无法在两个 <literal>Session</literal>中共享。因此有两种不同的标识语义:
+						</para>
+		<para>
+            <variablelist spacing="compact">
+                <varlistentry>
+										<term>数据库标识</term>
+                    <listitem>
+                        <para>
+                            <literal>foo.getId().equals( bar.getId() )</literal>
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+										<term>JVM 标识</term>
+                    <listitem>
+                        <para>
+                            <literal>foo==bar</literal>
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+
+						<para>
+							对于那些关联到 <emphasis>特定</emphasis><literal>Session</literal>
+							(也就是在单个<literal>Session</literal>的范围内)上的对象来说,这
+							两种标识的语义是等价的,与数据库标识对应的JVM标识是由Hibernate来保
+							证的。不过,当应用程序在两个不同的session中并发访问具有同一持久化标
+							识的业务对象实例的时候,这个业务对象的两个实例事实上是不相同的(从
+							JVM识别来看)。这种冲突可以通过在同步和提交的时候使用自动版本化和乐
+							观锁定方法来解决。
+						</para>
+						<para>
+								这种方式把关于并发的头疼问题留给了Hibernate和数据库;由于在单个线程内,操作单元中的对象识别不
+								需要代价昂贵的锁定或其他意义上的同步,因此它同时可以提供最好的可伸缩性。只要在单个线程只持有一个
+								<literal>Session</literal>,应用程序就不需要同步任何业务对象。在<literal>Session</literal>
+								的范围内,应用程序可以放心的使用<literal>==</literal>进行对象比较。
+						</para>
+						<para>
+								不过,应用程序在<literal>Session</literal>的外面使用<literal>==</literal>进行对象比较可能会
+								导致无法预期的结果。在一些无法预料的场合,例如,如果你把两个脱管对象实例放进同一个
+								<literal>Set</literal>的时候,就可能发生。这两个对象实例可能有同一个数据库标识(也就是说,
+								他们代表了表的同一行数据),从JVM标识的定义上来说,对脱管的对象而言,Hibernate无法保证他们
+								的的JVM标识一致。开发人员必须覆盖持久化类的<literal>equals()</literal>方法和 
+								<literal>hashCode()</literal> 方法,从而实现自定义的对象相等语义。警告:不要使用数据库标识
+								来实现对象相等,应该使用业务键值,由唯一的,通常不变的属性组成。当一个瞬时对象被持久化的时
+								候,它的数据库标识会发生改变。如果一个瞬时对象(通常也包括脱管对象实例)被放入一
+								个<literal>Set</literal>,改变它的hashcode会导致与这个<literal>Set</literal>的关系中断。虽
+								然业务键值的属性不象数据库主键那样稳定不变,但是你只需要保证在同一个<literal>Set</literal>
+								中的对象属性的稳定性就足够了。请到Hibernate网站去寻求这个问题更多的详细的讨论。请注意,这不是一
+								个有关Hibernate的问题,而仅仅是一个关于Java对象标识和判等行为如何实现的问题。
+		 				</para>
+		 </para>
+        </sect2>
+
+        <sect2 id="transactions-basics-issues">
+						<title>常见问题</title>
+						<para>
+								决不要使用反模式<emphasis>session-per-user-session</emphasis>或者<emphasis>
+								session-per-application</emphasis>(当然,这个规定几乎没有例外)。请注意,
+								下述一些问题可能也会出现在我们推荐的模式中,在你作出某个设计决定之前,请务必理解该模式的应用前提。
+						</para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <literal>Session</literal> 对象是非线程安全的。如果一个<literal>Session</literal>
+                        实例允许共享的话,那些支持并发运行的东东,例如HTTP request,session beans,或者是
+                        Swing workers,将会导致出现资源争用(race condition)。如果在<literal>HttpSession</literal>中有
+                        Hibernate 的<literal>Session</literal>的话(稍后讨论),你应该考虑同步访问你的Http session。
+                        否则,只要用户足够快的点击浏览器的“刷新”,就会导致两个并发运行线程使用同一个
+                         <literal>Session</literal>。
+                    </para>
+                </listitem>
+                <listitem>
+                     <para>
+					 								一个由Hibernate抛出的异常意味着你必须立即回滚数据库事务,并立即关闭<literal>Session</literal>
+					 								(稍后会展开讨论)。如果你的<literal>Session</literal>绑定到一个应用程序上,你必
+					 								须停止该应用程序。回滚数据库事务并不会把你的业务对象退回到事务启动时候的状态。这
+					 								意味着数据库状态和业务对象状态不同步。通常情况下,这不是什么问题,因为异常是不可
+					 								恢复的,你必须在回滚之后重新开始执行。
+                    </para>
+               </listitem>
+                <listitem>
+                    <para>
+                        <literal>Session</literal> 缓存了处于持久化状态的每个对象(Hibernate会监视和检查脏数据)。
+                        这意味着,如果你让<literal>Session</literal>打开很长一段时间,或是仅仅载入了过多的数据,
+                        <literal>Session</literal>占用的内存会一直增长,直到抛出OutOfMemoryException异常。这个
+                        问题的一个解决方法是调用<literal>clear()</literal> 和<literal>evict()</literal>来管理
+                        <literal>Session</literal>的缓存,但是如果你需要大批量数据操作的话,最好考虑
+                        使用存储过程。在<xref linkend="batch"/>中有一些解决方案。在用户会话期间一直保持
+                        <literal>Session</literal>打开也意味着出现脏数据的可能性很高。
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="transactions-demarcation">
+        <title>数据库事务声明</title>
+        <para>
+						数据库(或者系统)事务的声明总是必须的。在数据库事务之外,就无法和数据库通讯(这可能会让那些习惯于
+						自动提交事务模式的开发人员感到迷惑)。永远使用清晰的事务声明,即使只读操作也是如此。进行
+						显式的事务声明并不总是需要的,这取决于你的事务隔离级别和数据库的能力,但不管怎么说,声明事务总归有益无害。当然,一个单独的数据库事务总是比很多琐碎的事务性能更好,即时对读数据而言也是一样。
+        </para>
+        <para>
+						一个Hibernate应用程序可以运行在非托管环境中(也就是独立运行的应用程序,简单Web应用程序,
+						或者Swing图形桌面应用程序),也可以运行在托管的J2EE环境中。在一个非托管环境中,Hibernate
+						通常自己负责管理数据库连接池。应用程序开发人员必须手工设置事务声明,换句话说,就是手工启
+						动,提交,或者回滚数据库事务。一个托管的环境通常提供了容器管理事务(CMT),例如事务装配通过可声
+						明的方式定义在EJB session beans的部署描述符中。可编程式事务声明不再需要,即使是
+						<literal>Session</literal> 的同步也可以自动完成。
+        </para>
+        <para>
+						让持久层具备可移植性是人们的理想,这种移植发生在非托管的本地资源环境,与依赖JTA但是使用BMT而非CMT的系统之间。在两种情况下你都可以使用编程式的事务管理。Hibernate提供了一套称为<literal>Transaction</literal>的封装API,
+						用来把你的部署环境中的本地事务管理系统转换到Hibernate事务上。这个API是可选的,但是我们强烈
+						推荐你使用,除非你用CMT session bean。
+        </para>
+        <para>
+            通常情况下,结束 <literal>Session</literal> 包含了四个不同的阶段:
+        </para>
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    同步session(flush,刷出到磁盘)
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    提交事务
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                   关闭session
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    处理异常
+                </para>
+            </listitem>
+        </itemizedlist>
+
+
+        <para>
+						session的同步(flush,刷出)前面已经讨论过了,我们现在进一步考察在托管和非托管环境下的事务声明和异常处理。
+        </para>
+
+        <sect2 id="transactions-demarcation-nonmanaged"  revision="2">
+            <title>非托管环境</title>
+            <para>
+                如果Hibernat持久层运行在一个非托管环境中,数据库连接通常由Hibernate的简单(即非DataSource)连接池机制
+                来处理。session/transaction处理方式如下所示:
+            </para>
+            <programlisting><![CDATA[//Non-managed environment idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+    tx = sess.beginTransaction();
+
+    // do some work
+    ...
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    if (tx != null) tx.rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+            <para>
+                你不需要显式<literal>flush()</literal>  <literal>Session</literal>  -  
+                对<literal>commit()</literal>的调用会自动触发session的同步(取决于session的<xref linkend="objectstate-flushing">FlushMode</xref>)。调用 <literal>close()</literal> 标志session的结束。<literal>close()</literal>方法重要的暗示是,<literal>session</literal>释放了JDBC连接。这段Java代码在非托管环境下和JTA环境下都可以运行。
+            </para>
+
+            <para>
+                更加灵活的方案是Hibernate内置的"current session"上下文管理,前文已经讲过:
+            </para>
+
+            <programlisting><![CDATA[// Non-managed environment idiom with getCurrentSession()
+try {
+    factory.getCurrentSession().beginTransaction();
+
+    // do some work
+    ...
+
+    factory.getCurrentSession().getTransaction().commit();
+}
+catch (RuntimeException e) {
+    factory.getCurrentSession().getTransaction().rollback();
+    throw e; // or display error message
+}]]></programlisting>
+
+            <para>
+                你很可能从未在一个通常的应用程序的业务代码中见过这样的代码片断:致命的(系统)异常应该总是
+                在应用程序“顶层”被捕获。换句话说,执行Hibernate调用的代码(在持久层)和处理
+                <literal>RuntimeException</literal>异常的代码(通常只能清理和退出应用程序)应该在不同
+                的应用程序逻辑层。Hibernate的当前上下文管理可以极大地简化这一设计,你所有的一切就是<literal>SessionFactory</literal>。              异常处理将在本章稍后进行讨论。
+            </para>
+
+           <para>
+                请注意,你应该选择 <literal>org.hibernate.transaction.JDBCTransactionFactory</literal>
+                (这是默认选项),对第二个例子来说,<literal>hibernate.current_session_context_class</literal>应该是<literal>"thread"</literal>
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-demarcation-jta"  revision="3">
+            <title>使用JTA</title>
+            <para>
+               	如果你的持久层运行在一个应用服务器中(例如,在EJB session beans的后面),Hibernate获取
+               	的每个数据源连接将自动成为全局JTA事务的一部分。
+                你可以安装一个独立的JTA实现,使用它而不使用EJB。Hibernate提供了两种策略进行JTA集成。
+            </para>
+
+             <para>
+                如果你使用bean管理事务(BMT),可以通过使用Hibernate的 <literal>Transaction</literal> API来告诉
+                应用服务器启动和结束BMT事务。因此,事务管理代码和在非托管环境下是一样的。
+            </para>
+
+           <programlisting><![CDATA[// BMT idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+    tx = sess.beginTransaction();
+
+    // do some work
+    ...
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    if (tx != null) tx.rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+           <para>
+               如果你希望使用与事务绑定的<literal>Session</literal>,也就是使用<literal>getCurrentSession()</literal>来简化上下文管理,你将不得不直接使用JTA <literal>UserTransaction</literal>API。
+            </para>
+
+            <programlisting><![CDATA[// BMT idiom with getCurrentSession()
+try {
+    UserTransaction tx = (UserTransaction)new InitialContext()
+                            .lookup("java:comp/UserTransaction");
+
+    tx.begin();
+
+    // Do some work on Session bound to transaction
+    factory.getCurrentSession().load(...);
+    factory.getCurrentSession().persist(...);
+
+    tx.commit();
+}
+catch (RuntimeException e) {
+    tx.rollback();
+    throw e; // or display error message
+}]]></programlisting>
+
+
+            <para>
+               在CMT方式下,事务声明是在session bean的部署描述符中,而不需要编程。
+               因此,代码被简化为:
+			</para>
+			
+           <programlisting><![CDATA[// CMT idiom
+Session sess = factory.getCurrentSession();
+
+// do some work
+...
+
+]]></programlisting>
+
+            <para>
+                在CMT/EJB中甚至会自动rollback,因为假若有未捕获的<literal>RuntimeException</literal>从session bean方法中抛出,这就会通知容器把全局事务回滚。<emphasis>这就意味着,在BMT或者CMT中,你根本就不需要使用Hibernate <literal>Transaction</literal> API ,你自动得到了绑定到事务的“当前”Session。
+                </emphasis>
+            </para>
+
+            <para>
+                注意,当你配置Hibernate的transaction factory的时候,在直接使用JTA的时候(BMT),你应该选择<literal>org.hibernate.transaction.JTATransactionFactory</literal>,在CMT session bean中选择<literal>org.hibernate.transaction.CMTTransactionFactory</literal>。记得也要设置<literal>hibernate.transaction.manager_lookup_class</literal>。还有,确认你的<literal>hibernate.current_session_context_class</literal>未设置(为了向下兼容),或者设置为<literal>"jta"</literal>。
+            </para>
+
+            <para>
+                <literal>getCurrentSession()</literal>在JTA环境中有一个弊端。对<literal>after_statement</literal>连接释放方式有一个警告,这是被默认使用的。因为JTA规范的一个很愚蠢的限制,Hibernate不可能自动清理任何未关闭的<literal>ScrollableResults</literal> 或者<literal>Iterator</literal>,它们是由<literal>scroll()</literal>或<literal>iterate()</literal>产生的。你<emphasis>must</emphasis>通过在<literal>finally</literal>块中,显式调用<literal>ScrollableResults.close()</literal>或者<literal>Hibernate.close(Iterator)</literal>方法来释放底层数据库游标。(当然,大部分程序完全可以很容易的避免在JTA或CMT代码中出现<literal>scroll()</literal>或<literal>iterate()</literal>。)
+            </para>
+
+
+        </sect2>
+
+
+
+        <sect2 id="transactions-demarcation-exceptions">
+            <title>异常处理</title>
+            <para>
+                如果 <literal>Session</literal> 抛出异常 (包括任何<literal>SQLException</literal>), 
+                你应该立即回滚数据库事务,调用 <literal>Session.close()</literal> ,丢弃该
+                <literal>Session</literal>实例。<literal>Session</literal>的某些方法可能会导致session
+                处于不一致的状态。所有由Hibernate抛出的异常都视为不可以恢复的。确保在
+                <literal>finally</literal> 代码块中调用<literal>close()</literal>方法,以关闭掉
+                <literal>Session</literal>。
+            </para>
+            <para>
+								<literal>HibernateException</literal>是一个非检查期异常(这不同于Hibernate老的版本),
+								它封装了Hibernate持久层可能出现的大多数错误。我们的观点是,不应该强迫应用程序开发人员
+								在底层捕获无法恢复的异常。在大多数软件系统中,非检查期异常和致命异常都是在相应方法调用
+								的堆栈的顶层被处理的(也就是说,在软件上面的逻辑层),并且提供一个错误信息给应用软件的用户
+								(或者采取其他某些相应的操作)。请注意,Hibernate也有可能抛出其他并不属于
+								<literal>HibernateException</literal>的非检查期异常。这些异常同样也是无法恢复的,应该
+								采取某些相应的操作去处理。
+            </para>
+            <para>
+								在和数据库进行交互时,Hibernate把捕获的<literal>SQLException</literal>封装为Hibernate的
+								<literal>JDBCException</literal>。事实上,Hibernate尝试把异常转换为更有实际含义
+								的<literal>JDBCException</literal>异常的子类。底层的<literal>SQLException</literal>可以
+								通过<literal>JDBCException.getCause()</literal>来得到。Hibernate通过使用关联到
+								<literal>SessionFactory</literal>上的<literal>SQLExceptionConverter</literal>来
+								把<literal>SQLException</literal>转换为一个对应的<literal>JDBCException</literal>
+								异常的子类。默认情况下,<literal>SQLExceptionConverter</literal>可以通过配置dialect
+								选项指定;此外,也可以使用用户自定义的实现类(参考javadocs
+								 <literal>SQLExceptionConverterFactory</literal>类来了解详情)。标准的
+								 <literal>JDBCException</literal>子类型是:
+            </para>
+            <itemizedlist spacing="compact">
+                <listitem>
+                    <para>
+                        <literal>JDBCConnectionException</literal> - 指明底层的JDBC通讯出现错误
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>SQLGrammarException</literal> - 指明发送的SQL语句的语法或者格式错误
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>ConstraintViolationException</literal> - 指明某种类型的约束违例错误
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>LockAcquisitionException</literal> - 指明了在执行请求操作时,获取
+                        所需的锁级别时出现的错误。
+                        
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <literal>GenericJDBCException</literal> - 不属于任何其他种类的原生异常
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+
+        </sect2>
+
+        <sect2 id="transactions-demarcation-timeout">
+            <title>事务超时</title>
+
+            <para>
+                EJB这样的托管环境有一项极为重要的特性,而它从未在非托管环境中提供过,那就是事务超时。在出现错误的事务行为的时候,超时可以确保不会无限挂起资源、对用户没有交代。在托管(JTA)环境之外,Hibernate无法完全提供这一功能。但是,Hiberante至少可以控制数据访问,确保数据库级别的死锁,和返回巨大结果集的查询被限定在一个规定的时间内。在托管环境中,Hibernate会把事务超时转交给JTA。这一功能通过Hibernate <literal>Transaction</literal>对象进行抽象。
+            </para>
+            
+            <programlisting><![CDATA[
+Session sess = factory.openSession();
+try {
+    //set transaction timeout to 3 seconds
+    sess.getTransaction().setTimeout(3);
+    sess.getTransaction().begin();
+
+    // do some work
+    ...
+
+    sess.getTransaction().commit()
+}
+catch (RuntimeException e) {
+    sess.getTransaction().rollback();
+    throw e; // or display error message
+}
+finally {
+    sess.close();
+}]]></programlisting>
+
+            <para>
+                注意<literal>setTimeout()</literal>不应该在CMT bean中调用,此时事务超时值应该是被声明式定义的。
+            </para>
+
+		</sect2>
+    </sect1>
+
+    <sect1 id="transactions-optimistic">
+        <title>乐观并发控制(Optimistic concurrency control)</title>
+        <para>
+            唯一能够同时保持高并发和高可伸缩性的方法就是使用带版本化的乐观并发控制。版本检查使用版本号、
+            或者时间戳来检测更新冲突(并且防止更新丢失)。Hibernate为使用乐观并发控制的代码提供了三种可
+            能的方法,应用程序在编写这些代码时,可以采用它们。我们已经在前面应用程序对话那部分展示了
+            乐观并发控制的应用场景,此外,在单个数据库事务范围内,版本检查也提供了防止更新丢失的好处。
+        </para>
+
+        <sect2 id="transactions-optimistic-manual">
+            <title>应用程序级别的版本检查(Application version checking)</title>
+            <para>                
+								 未能充分利用Hibernate功能的实现代码中,每次和数据库交互都需要一个新的
+								 <literal>Session</literal>,而且开发人员必须在显示数据之前从数据库中重
+								 新载入所有的持久化对象实例。这种方式迫使应用程序自己实现版本检查来确保
+								 对话事务的隔离,从数据访问的角度来说是最低效的。这种使用方式和
+								 entity EJB最相似。
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+
+int oldVersion = foo.getVersion();
+session.load( foo, foo.getKey() ); // load the current state
+if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();
+foo.setProperty("bar");
+
+t.commit();
+session.close();]]></programlisting>
+
+            <para>
+                <literal>version</literal> 属性使用 <literal>&lt;version&gt;</literal>来映射,如果对象
+                是脏数据,在同步的时候,Hibernate会自动增加版本号。
+            </para>
+
+            <para>
+								当然,如果你的应用是在一个低数据并发环境下,并不需要版本检查的话,你照样可以使用
+								这种方式,只不过跳过版本检查就是了。在这种情况下,<emphasis>最晚提交生效</emphasis>
+								(<emphasis>last commit wins</emphasis>)就是你的长对话的默认处理策略。
+								请记住这种策略可能会让应用软件的用户感到困惑,因为他们有可能会碰上更新丢失掉却没
+								有出错信息,或者需要合并更改冲突的情况。
+            </para>
+
+            <para>
+                很明显,手工进行版本检查只适合于某些软件规模非常小的应用场景,对于大多数软件应用场景
+                来说并不现实。通常情况下,不仅是单个对象实例需要进行版本检查,整个被修改过的关
+                联对象图也都需要进行版本检查。作为标准设计范例,Hibernate使用扩展周期的
+                <literal>Session</literal>的方式,或者脱管对象实例的方式来提供自动版本检查。
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-longsession">
+            <title>扩展周期的session和自动版本化</title>
+            <para>
+               单个 <literal>Session</literal>实例和它所关联的所有持久化对象实例都被用于整个
+               对话,这被称为<emphasis>session-per-conversation</emphasis>。Hibernate在同步的时候进行对象实例的版本检查,如果检测到并发修
+               改则抛出异常。由开发人员来决定是否需要捕获和处理这个异常(通常的抉择是给用户
+               提供一个合并更改,或者在无脏数据情况下重新进行业务对话的机会)。
+            </para>
+            <para>
+               在等待用户交互的时候, <literal>Session</literal> 断开底层的JDBC连接。这种方式
+               以数据库访问的角度来说是最高效的方式。应用程序不需要关心版本检查或脱管对象实例
+               的重新关联,在每个数据库事务中,应用程序也不需要载入读取对象实例。
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded earlier by the old session
+Transaction t = session.beginTransaction(); // Obtain a new JDBC connection, start transaction
+
+foo.setProperty("bar");
+
+session.flush();    // Only for last transaction in conversation
+t.commit();         // Also return JDBC connection
+session.close();    // Only for last transaction in conversation]]></programlisting>
+
+            <para>
+                <literal>foo</literal>对象知道它是在哪个<literal>Session</literal>中被装入的。在一个旧session中开启一个新的数据库事务,会导致session获取一个新的连接,并恢复session的功能。将数据库事务提交,使得session从JDBC连接断开,并将此连接交还给连接池。在重新连接之后,要强制对你没有更新的数据进行一次版本检查,你可以对所有可能被其他事务修改过的对象,使用参数<literal>LockMode.READ</literal>来调用<literal>Session.lock()</literal>。你不用lock任何你<emphasis>正在</emphasis>更新的数据。一般你会在扩展的<literal>Session</literal>上设置<literal>FlushMode.NEVER</literal>,因此只有最后一个数据库事务循环才会真正的吧整个对话中发生的修改发送到数据库。因此,只有这最后一次数据库事务才会包含<literal>flush()</literal>操作,然后在整个对话结束后,还要<literal!
 >close()</literal>这个session。
+            </para>
+
+            <para>
+                如果在用户思考的过程中,<literal>Session</literal>因为太大了而不能保存,那么这种模式是有
+                问题的。举例来说,一个<literal>HttpSession</literal>应该尽可能的小。由于
+                <literal>Session</literal>是一级缓存,并且保持了所有被载入过的对象,因此
+                我们只应该在那些少量的request/response情况下使用这种策略。你应该只把一个<literal>Session</literal>用于单个对话,因为它很快就会出现脏数据。
+            </para>
+
+            <para>
+                (注意,早期的Hibernate版本需要明确的对<literal>Session</literal>进行disconnec和reconnect。这些方法现在已经过时了,打开事务和关闭事务会起到同样的效果。)
+            </para>
+
+
+            <para>
+                此外,也请注意,你应该让与数据库连接断开的<literal>Session</literal>对持久层保持
+                关闭状态。换句话说,在三层环境中,使用有状态的EJB session bean来持有<literal>Session</literal>,
+                而不要把它传递到web层(甚至把它序列化到一个单独的层),保存在<literal>HttpSession</literal>中。
+            </para>
+
+            <para>
+                扩展session模式,或者被称为<emphasis>每次对话一个session(session-per-conversation)</emphasis>, 在与自动管理当前session上下文联用的时候会更困难。你需要提供你自己的<literal>CurrentSessionContext</literal>实现。请参阅Hibernate Wiki以获得示例。
+            </para>
+
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-detached">
+            <title>脱管对象(deatched object)和自动版本化</title>
+
+            <para>
+                这种方式下,与持久化存储的每次交互都发生在一个新的<literal>Session</literal>中。
+                然而,同一持久化对象实例可以在多次与数据库的交互中重用。应用程序操纵脱管对象实例
+                的状态,这个脱管对象实例最初是在另一个<literal>Session</literal> 中载入的,然后
+                调用 <literal>Session.update()</literal>,<literal>Session.saveOrUpdate()</literal>, 或者
+                <literal>Session.merge()</literal> 来重新关联该对象实例。
+            </para>
+
+            <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+foo.setProperty("bar");
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded already
+t.commit();
+session.close();]]></programlisting>
+
+            <para>
+                Hibernate会再一次在同步的时候检查对象实例的版本,如果发生更新冲突,就抛出异常。
+            </para>
+
+            <para>
+                如果你确信对象没有被修改过,你也可以调用<literal>lock()</literal> 来设置
+                <literal>LockMode.READ</literal>(绕过所有的缓存,执行版本检查),从而取
+                代 <literal>update()</literal>操作。
+            </para>
+
+        </sect2>
+
+        <sect2 id="transactions-optimistic-customizing">
+            <title>定制自动版本化行为</title>
+            <para>
+               对于特定的属性和集合,通过为它们设置映射属性<literal>optimistic-lock</literal>的值
+               为<literal>false</literal>,来禁止Hibernate的版本自动增加。这样的话,如果该属性
+               脏数据,Hibernate将不再增加版本号。
+            </para>
+
+            <para>
+								遗留系统的数据库Schema通常是静态的,不可修改的。或者,其他应用程序也可能访问同一数据
+								库,根本无法得知如何处理版本号,甚至时间戳。在以上的所有场景中,实现版本化不能依靠
+								数据库表的某个特定列。在<literal>&lt;class&gt;</literal>的映射中设置
+								<literal>optimistic-lock="all"</literal>可以在没有版本或者时间戳属性映射的情况下实现
+								版本检查,此时Hibernate将比较一行记录的每个字段的状态。请注意,只有当Hibernate能够比
+								较新旧状态的情况下,这种方式才能生效,也就是说,
+								你必须使用单个长生命周期<literal>Session</literal>模式,而不能使用
+								session-per-request-with-detached-objects模式。
+            </para>
+
+            <para>
+               有些情况下,只要更改不发生交错,并发修改也是允许的。当你在<literal>&lt;class&gt;</literal>
+               的映射中设置<literal>optimistic-lock="dirty"</literal>,Hibernate在同步的时候将只比较有脏
+               数据的字段。
+            </para>
+
+            <para>
+                在以上所有场景中,不管是专门设置一个版本/时间戳列,还是进行全部字段/脏数据字段比较,
+                Hibernate都会针对每个实体对象发送一条<literal>UPDATE</literal>(带有相应的
+                <literal>WHERE</literal>语句 )的SQL语句来执行版本检查和数据更新。如果你对关联实体
+                设置级联关系使用传播性持久化(transitive persistence),那么Hibernate可能会执行不必
+                要的update语句。这通常不是个问题,但是数据库里面对<emphasis>on update</emphasis>点火
+                的触发器可能在脱管对象没有任何更改的情况下被触发。因此,你可以在
+                <literal>&lt;class&gt;</literal>的映射中,通过设置<literal>select-before-update="true"</literal>
+                来定制这一行为,强制Hibernate <literal>SELECT</literal>这个对象实例,从而保证,
+                在更新记录之前,对象的确是被修改过。
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+    <sect1 id="transactions-locking">
+        <title>悲观锁定(Pessimistic Locking)</title>
+        <para>
+           用户其实并不需要花很多精力去担心锁定策略的问题。通常情况下,只要为JDBC连接指定一下隔
+           离级别,然后让数据库去搞定一切就够了。然而,高级用户有时候希望进行一个排它的悲观锁定,
+           或者在一个新的事务启动的时候,重新进行锁定。
+        </para>
+
+        <para>
+            Hibernate总是使用数据库的锁定机制,从不在内存中锁定对象!
+        </para>
+
+        <para>
+            类<literal>LockMode</literal> 定义了Hibernate所需的不同的锁定级别。一个锁定
+            可以通过以下的机制来设置:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    当Hibernate更新或者插入一行记录的时候,锁定级别自动设置为<literal>LockMode.WRITE</literal>。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    当用户显式的使用数据库支持的SQL格式<literal>SELECT ... FOR UPDATE</literal> 
+                    发送SQL的时候,锁定级别设置为<literal>LockMode.UPGRADE</literal> 
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    当用户显式的使用Oracle数据库的SQL语句<literal>SELECT ... FOR UPDATE NOWAIT</literal>
+                    的时候,锁定级别设置<literal>LockMode.UPGRADE_NOWAIT</literal> 
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    当Hibernate在“可重复读”或者是“序列化”数据库隔离级别下读取数据的时候,锁定模式
+                    自动设置为<literal>LockMode.READ</literal>。这种模式也可以通过用户显式指定进行设置。
+                </para>
+            </listitem>
+        <listitem>
+        <para>
+						<literal>LockMode.NONE</literal> 代表无需锁定。在<literal>Transaction</literal>结束时,
+						所有的对象都切换到该模式上来。与session相关联的对象通过调用<literal>update()</literal>
+						或者<literal>saveOrUpdate()</literal>脱离该模式。
+        </para>
+        </listitem>
+        </itemizedlist>
+
+        <para>
+            "显式的用户指定"可以通过以下几种方式之一来表示:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    调用 <literal>Session.load()</literal>的时候指定<literal>锁定模式(LockMode)</literal>。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    调用<literal>Session.lock()</literal>。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    调用<literal>Query.setLockMode()</literal>。
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+           如果在<literal>UPGRADE</literal>或者<literal>UPGRADE_NOWAIT</literal>锁定模式下调
+           用<literal>Session.load()</literal>,并且要读取的对象尚未被session载入过,那么对象
+           通过<literal>SELECT ... FOR UPDATE</literal>这样的SQL语句被载入。如果为一个对象调用
+           <literal>load()</literal>方法时,该对象已经在另一个较少限制的锁定模式下被载入了,那
+           么Hibernate就对该对象调用<literal>lock()</literal> 方法。
+        </para>
+
+        <para>
+            如果指定的锁定模式是<literal>READ</literal>, <literal>UPGRADE</literal> 或
+            <literal>UPGRADE_NOWAIT</literal>,那么<literal>Session.lock()</literal>就
+            执行版本号检查。(在<literal>UPGRADE</literal> 或者<literal>UPGRADE_NOWAIT</literal>
+            锁定模式下,执行<literal>SELECT ... FOR UPDATE</literal>这样的SQL语句。)
+        </para>
+
+        <para>
+           如果数据库不支持用户设置的锁定模式,Hibernate将使用适当的替代模式(而不是扔出异常)。
+           这一点可以确保应用程序的可移植性。
+        </para>
+    </sect1>
+    <sect1 id="transactions-connection-release">
+        <title>连接释放模式(Connection Release Modes)</title>
+
+        <para>
+            Hibernate关于JDBC连接管理的旧(2.x)行为是,<literal>Session</literal>在第一次需要的时候获取一个连接,在session关闭之前一直会持有这个连接。Hibernate引入了连接释放的概念,来告诉session如何处理它的JDBC连接。注意,下面的讨论只适用于采用配置<literal>ConnectionProvider</literal>来提供连接的情况,用户自己提供的连接与这里的讨论无关。通过<literal>org.hibernate.ConnectionReleaseMode</literal>的不同枚举值来使用不用的释放模式:
+            
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>ON_CLOSE</literal> - 基本上就是上面提到的老式行为。Hibernate session在第一次需要进行JDBC操作的时候获取连接,然后持有它,直到session关闭。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>AFTER_TRANSACTION</literal> - 在<literal>org.hibernate.Transaction</literal>结束后释放连接。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>AFTER_STATEMENT</literal> (也被称做积极释放) - 在每一条语句被执行后就释放连接。但假若语句留下了与session相关的资源,那就不会被释放。目前唯一的这种情形就是使用<literal>org.hibernate.ScrollableResults</literal>。
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <literal>hibernate.connection.release_mode</literal>配置参数用来指定使用哪一种释放模式。可能的值有:
+        </para>
+
+        <itemizedlist spacing="compact">
+            <listitem>
+                <para>
+                    <literal>auto</literal>(默认) - 这一选择把释放模式委派给<literal>org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode()</literal>方法。对JTATransactionFactory来说,它会返回ConnectionReleaseMode.AFTER_STATEMENT;对JDBCTransactionFactory来说,则是ConnectionReleaseMode.AFTER_TRANSACTION。很少需要修改这一默认行为,因为假若设置不当,就会带来bug,或者给用户代码带来误导。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>on_close</literal> - 使用 ConnectionReleaseMode.ON_CLOSE.  这种方式是为了向下兼容的,但是已经完全不被鼓励使用了。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>after_transaction</literal> - 使用ConnectionReleaseMode.AFTER_TRANSACTION。这一设置不应该在JTA环境下使用。也要注意,使用ConnectionReleaseMode.AFTER_TRANSACTION的时候,假若session 处于auto-commit状态,连接会像AFTER_STATEMENT那样被释放。
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    <literal>after_statement</literal> - 使用ConnectionReleaseMode.AFTER_STATEMENT。除此之外,会查询配置的<literal>ConnectionProvider</literal>,是否它支持这一设置((<literal>supportsAggressiveRelease()</literal>))。假若不支持,释放模式会被设置为ConnectionReleaseMode.AFTER_TRANSACTION。只有在你每次调用<literal>ConnectionProvider.getConnection()</literal>获取底层JDBC连接的时候,都可以确信获得同一个连接的时候,这一设置才是安全的;或者在auto-commit环境中,你可以不管是否每次都获得同一个连接的时候,这才是安全的。
+                    
+                </para>
+            </listitem>
+        </itemizedlist>
+
+    </sect1>
+
+</chapter>
+

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/tutorial.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/tutorial.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/tutorial.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1233 @@
+<chapter id="tutorial">
+    <title>
+		Hibernate入门
+	</title>
+    <sect1 id="tutorial-intro"  revision="1">
+        <title>
+		前言
+	</title>
+        
+        <para>
+	本章是面向Hibernate初学者的一个入门教程。我们从一个使用驻留内存式(in-memory)数据库的简单命令行应用程序开始, 用易于理解的方式逐步开发。
+
+        </para>
+
+        <para>
+	本章面向Hibernate初学者,但需要Java和SQL知识。它是在Michael Goegl所写的指南的基础上完成的。在这里,我们称第三方库文件是指JDK 1.4和5.0。若使用JDK1.3,你可能需要其它的库文件。
+        </para>
+
+        <para>
+	本章的源代码已包含在发布包中,位于<literal>doc/reference/tutorial/</literal>目录下。
+        </para>
+
+    </sect1>
+    
+    <sect1 id="tutorial-firstapp"  revision="2">
+	<title>
+	第一部分 - 第一个Hibernate应用程序
+	</title>
+        <para>
+	首先我们将创建一个简单的基于控制台的(console-based)Hibernate应用程序。由于我们使用Java数据库(HSQL DB),所以不必安装任何数据库服务器。
+        </para>
+
+        <para>
+	假设我们希望有一个小应用程序可以保存我们希望参加的活动(events)和这些活动主办方的相关信息。
+		(译者注:在本教程的后面部分,我们将直接使用event而不是它的中文翻译“活动”,以免混淆。)
+        </para>
+            
+        <para>
+	我们所做的第一件事就是创建我们的开发目录,并且把所有需要用到的Java库文件放进去。解压缩从Hibernate网站下载的Hibernate发布包,并把<literal>/lib</literal>目录下所有需要的库文件拷到我们新建开发目录下的<literal>/lib</literal>目录下。看起来就像这样:
+        </para>
+            
+        <programlisting><![CDATA[.
++lib
+  antlr.jar
+  cglib.jar
+  asm.jar
+  asm-attrs.jars
+  commons-collections.jar
+  commons-logging.jar
+  ehcache.jar
+  hibernate3.jar
+  jta.jar
+  dom4j.jar
+  log4j.jar ]]></programlisting>
+
+        <para>
+	<emphasis>到编写本文时为止</emphasis>,这些是Hibernate运行所需要的最小库文件集合(注意我们也拷贝了	Hibernate3.jar,这个是最主要的文件)。你正使用的Hibernate版本可能需要比这更多或少一些的库文件。请参见发布包中的<literal>lib/</literal>目录下的<literal>README.txt</literal>,以获取更多关于所需和可选的第三方库文件信息(事实上,Log4j并不是必须的库文件,但被许多开发者所喜欢)。
+
+        </para>
+
+        <para>
+	接下来我们创建一个类,用来代表那些我们希望储存在数据库里的event。
+        </para>
+      
+        <sect2 id="tutorial-firstapp-firstclass" revision="1">
+            <title>
+	第一个class
+           </title>
+            
+            <para>
+	我们的第一个持久化类是一个带有一些属性(property)的简单JavaBean类:
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+import java.util.Date;
+
+public class Event {
+    private Long id;
+
+    private String title;
+    private Date date;
+
+    public Event() {}
+
+    public Long getId() {
+        return id;
+    }
+
+    private void setId(Long id) {
+        this.id = id;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+}]]></programlisting>
+
+            <para>
+	你可以看到这个类对属性的存取方法(getter and setter method)使用了标准JavaBean命名约定,同时把类属性(field)的访问级别设成私有的(private)。这是推荐的设计,但并不是必须的。Hibernate也可以直接访问这些field,而使用访问方法(accessor method)的好处是提供了重构时的健壮性(robustness)。为了通过反射机制(Reflection)来实例化这个类的对象,我们需要提供一个无参的构造器(no-argument constructor)。
+            </para>
+
+            <para>
+	对一特定的event, <literal>id</literal> 属性持有唯一的标识符(identifier)的值。如果我们希望使用Hibernate提供的所有特性,那么所有的持久化实体(persistent entity)类(这里也包括一些次要依赖类)都需要一个这样的标识符属性。而事实上,大多数应用程序(特别是web应用程序)都需要通过标识符来区别对象,所以你应该考虑使用标识符属性而不是把它当作一种限制。然而,我们通常不会操作对象的标识(identity),因此它的setter方法的访问级别应该声明private。这样当对象被保存的时候,只有Hibernate可以为它分配标识符值。你可看到Hibernate可以直接访问public,private和protected的访问方法和field。所以选择哪种方式完全取决于你,你可以使你的选择与你的应用程序设计相吻合。
+            </para>
+
+            <para>
+	所有的持久化类(persistent classes)都要求有无参的构造器,因为Hibernate必须使用Java反射机制来为你创建对象。构造器(constructor)的访问级别可以是private,然而当生成运行时代理(runtime proxy)的时候则要求使用至少是package 级别的访问控制,这样在没有字节码指令(bytecode instrumentation)的情况下,从持久化类里获取数据会更有效率。
+            </para>
+
+            <para>
+	把这个Java源代码文件放到开发目录下的<literal>src</literal>目录里,注意包位置要正确。 现在这个目录看起来应该像这样:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java]]></programlisting>
+
+            <para>
+	下一步,我们把这个持久化类的信息告诉Hibernate。
+            </para>
+                
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-mapping" revision="1">
+	<title>
+	映射文件
+	</title>
+
+            <para>
+	Hibernate需要知道怎样去加载(load)和存储(store)持久化类的对象。这正是Hibernate映射文件发挥作用的地方。映射文件告诉Hibernate它,应该访问数据库(database)里面的哪个表(table)及应该使用表里面的哪些字段(column)。
+
+            </para>
+
+            <para>
+	一个映射文件的基本结构看起来像这样:
+            </para>
+
+            <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+[...]
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+	注意Hibernate的DTD是非常复杂的。你的编辑器或者IDE里使用它来自动完成那些用来映射的XML元素(element)和属性(attribute)。你也可以在文本编辑器里打开DTD-这是最简单的方式来概览所有的元素和attribute,并查看它们的缺省值以及注释。注意Hibernate不会从web加载DTD文件,但它会首先在应用程序的classpath中查找。DTD文件已包括在<literal>hibernate3.jar</literal>里,同时也在Hibernate发布包的<literal>src/</literal>目录下。
+            </para>
+
+            <para>
+	为缩短代码长度,在以后的例子里我们会省略DTD的声明。当然,在实际的应用程序中,DTD声明是必须的。
+            </para>
+
+            <para>
+	在<literal>hibernate-mapping</literal>标签(tag)之间, 含有一个<literal>class</literal>元素。所有的持久化实体类(再次声明,或许接下来会有依赖类,就是那些次要的实体)都需要一个这样的映射,来把类对象映射到SQL数据库里的表。
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+	到目前为止,我们告诉了Hibernate怎样把<literal>Events</literal>类的对象持久化到数据库的<literal>EVENTS</literal>表里,以及怎样从<literal>EVENTS</literal>表加载到<literal>Events</literal>类的对象。每个实例对应着数据库表中的一行。现在我们将继续讨论有关唯一标识符属性到数据库表的映射。另外,由于我们不关心怎样处理这个标识符,我们就配置由Hibernate的标识符生成策略来产生代理主键字段。
+
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="native"/>
+        </id>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+	<literal>id</literal>元素是标识符属性的声明,<literal>name="id"</literal> 声明了Java属性的名字 - Hibernate会使用<literal>getId()</literal>和<literal>setId()</literal>来访问它。  <literal>column</literal>属性则告诉Hibernate, 我们使用<literal>EVENTS</literal>表的哪个字段作为主键。嵌套的<literal>generator</literal>元素指定了标识符生成策略,在这里我们指定<literal>native</literal>,它根据已配置的数据库(方言)自动选择最佳的标识符生成策略。Hibernate支持由数据库生成,全局唯一性(globally unique)和应用程序指定(或者你自己为任何已有策略所写的扩展)这些策略来生成标识符。
+            </para>
+
+            <para>
+	最后我们在映射文件里面包含需要持久化属性的声明。默认情况下,类里面的属性都被视为非持久化的:
+            </para>
+            
+            <programlisting><![CDATA[
+<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="native"/>
+        </id>
+        <property name="date" type="timestamp" column="EVENT_DATE"/>
+        <property name="title"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+            
+            <para>
+	和<literal>id</literal>元素一样,<literal>property</literal>元素的<literal>name</literal>属性告诉Hibernate使用哪个getter和setter方法。在此例中,Hibernate会寻找<literal>getDate()/setDate()</literal>, 以及<literal>getTitle()/setTitle()</literal>。
+            </para>
+
+            <para>
+	为什么<literal>date</literal>属性的映射含有<literal>column</literal> attribute,而<literal>title</literal>却没有?当没有设定<literal>column</literal> attribute 的时候,Hibernate缺省地使用JavaBean的属性名作为字段名。对于<literal>title</literal>,这样工作得很好。然而,<literal>date</literal>在多数的数据库里,是一个保留关键字,所以我们最好把它映射成一个不同的名字。
+
+            </para>
+
+            <para>
+	  另一有趣的事情是<literal>title</literal>属性缺少一个<literal>type</literal> attribute。我们在映射文件里声明并使用的类型,却不是我们期望的那样,是Java数据类型,同时也不是SQL数据库的数据类型。这些类型就是所谓的Hibernate 映射类型<emphasis>(mapping types)</emphasis>,它们能把Java数据类型转换到SQL数据类型,反之亦然。再次重申,如果在映射文件中没有设置<literal>type</literal>属性的话,Hibernate会自己试着去确定正确的转换类型和它的映射类型。在某些情况下这个自动检测机制(在Java 类上使用反射机制)不会产生你所期待或需要的缺省值。<literal>date</literal>属性就是个很好的例子,Hibernate无法知道这个属性(<literal>java.util.Date</literal>类型的)应该被映射成:SQL <literal>date</literal>,或<literal>timestamp</literal>,还是<literal>time</literal> 字段。在此例中ï¼!
 ŒæŠŠè¿™ä¸ªå±žæ€§æ˜ å°„成<literal>timestamp</literal> 转换器,这样我们预留了日期和时间的全部信息。
+            </para>
+
+            <para>
+	应该把这个映射文件保存为<literal>Event.hbm.xml</literal>,且就在<literal>Event</literal>Java类的源文件目录下。映射文件可随意地命名,但<literal>hbm.xml</literal>的后缀已成为Hibernate开发者社区的约定。现在目录结构看起来应该像这样:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+ +events
+  Event.java
+  Event.hbm.xml]]></programlisting>
+
+             <para>
+	我们继续进行Hibernate的主要配置。
+             </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-configuration"  revision="2">
+            <title>
+	Hibernate配置
+		</title>
+
+            <para>
+	现在我们已经有了一个持久化类和它的映射文件,该是配置Hibernate的时候了。在此之前,我们需要一个数据库。 HSQL DB是种基于Java 的SQL数据库管理系统(DBMS),可以从HSQL DB的网站上下载。实际上,你只需下载的包中的<literal>hsqldb.jar</literal>文件,并把这个文件放在开发文件夹的<literal>lib/</literal>目录下即可。
+		
+            </para>
+
+            <para>
+	在开发的根目录下创建一个<literal>data</literal>目录 - 这是HSQL DB存储数据文件的地方。此时在data目录中运行<literal>java -classpath ../lib/hsqldb.jar org.hsqldb.Server</literal>就可启动数据库。你可以在log中看到它的启动,及绑定到TCP/IP套结字,这正是我们的应用程序稍后会连接的地方。如果你希望在本例中运行一个全新的数据库,就在窗口中按下<literal>CTRL + C</literal>来关闭HSQL数据库,并删除<literal>data/</literal>目录下的所有文件,再重新启动HSQL数据库。
+            </para>
+
+            <para>
+	Hibernate是你的应用程序里连接数据库的那层,所以它需要连接用的信息。连接(connection)是通过一个也由我们配置的JDBC连接池(connection pool)来完成的。Hibernate的发布包里包含了许多开源的(open source)连接池,但在我们例子中使用Hibernate内置的连接池。注意,如果你希望使用一个产品级(production-quality)的第三方连接池软件,你必须拷贝所需的库文件到你的classpath下,并使用不同的连接池设置。
+            </para>
+
+            <para>
+	为了保存Hibernate的配置,我们可以使用一个简单的<literal>hibernate.properties</literal>文件,或者一个稍微复杂的<literal>hibernate.cfg.xml</literal>,甚至可以完全使用程序来配置Hibernate。多数用户更喜欢使用XML配置文件:
+            </para>
+
+            <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <session-factory>
+
+        <!-- Database connection settings -->
+        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
+        <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
+        <property name="connection.username">sa</property>
+        <property name="connection.password"></property>
+
+        <!-- JDBC connection pool (use the built-in) -->
+        <property name="connection.pool_size">1</property>
+
+        <!-- SQL dialect -->
+        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
+
+        <!-- Enable Hibernate's automatic session context management -->
+        <property name="current_session_context_class">thread</property>
+
+        <!-- Disable the second-level cache  -->
+        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
+
+        <!-- Echo all executed SQL to stdout -->
+        <property name="show_sql">true</property>
+
+        <!-- Drop and re-create the database schema on startup -->
+        <property name="hbm2ddl.auto">create</property>
+
+        <mapping resource="events/Event.hbm.xml"/>
+
+    </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+            <para>
+	注意这个XML配置使用了一个不同的DTD。在这里,我们配置了Hibernate的<literal>SessionFactory</literal>-一个关联于特定数据库全局的工厂(factory)。如果你要使用多个数据库,就要用多个的<literal>&lt;session-factory&gt;</literal>,通常把它们放在多个配置文件中(为了更容易启动)。
+            </para>
+
+            <para>
+	最开始的4个<literal>property</literal>元素包含必要的JDBC连接信息。方言(dialect)的<literal>property</literal>元素指明Hibernate 生成的特定SQL变量。你很快会看到,Hibernate对持久化上下文的自动session管理就会派上用场。 打开<literal>hbm2ddl.auto</literal>选项将自动生成数据库模式(schema)-	直接加入数据库中。当然这个选项也可以被关闭(通过去除这个配置选项)或者通过Ant任务<literal>SchemaExport</literal>的帮助来把数据库schema重定向到文件中。最后,在配置中为持久化类加入映射文件。
+            </para>
+
+            <para>
+	把这个文件拷贝到源代码目录下面,这样它就位于classpath的根目录的最后。Hibernate在启动时会自动在classpath的根目录查找名为<literal>hibernate.cfg.xml</literal>的配置文件。
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-ant"  revision="1">
+            <title>
+	用Ant构建
+            </title>
+
+            <para>
+	现在我们用Ant来构建应用程序。你必须先安装Ant-可以从<ulink url="http://ant.apache.org/bindownload.cgi">Ant 下载页面</ulink>得到它。怎样安装Ant就不在这里介绍了,请参考<ulink url="http://ant.apache.org/manual/index.html">Ant 用户手册</ulink>。当你安装完了Ant,就可以开始创建<literal>build.xml</literal>文件,把它直接放在开发目录下面。
+            </para>
+            <para>
+	一个简单的build文件看起来像这样:
+            </para>
+
+            <programlisting><![CDATA[<project name="hibernate-tutorial" default="compile">
+
+    <property name="sourcedir" value="${basedir}/src"/>
+    <property name="targetdir" value="${basedir}/bin"/>
+    <property name="librarydir" value="${basedir}/lib"/>
+
+    <path id="libraries">
+        <fileset dir="${librarydir}">
+            <include name="*.jar"/>
+        </fileset>
+    </path>
+
+    <target name="clean">
+        <delete dir="${targetdir}"/>
+        <mkdir dir="${targetdir}"/>
+    </target>
+
+    <target name="compile" depends="clean, copy-resources">
+      <javac srcdir="${sourcedir}"
+             destdir="${targetdir}"
+             classpathref="libraries"/>
+    </target>
+
+    <target name="copy-resources">
+        <copy todir="${targetdir}">
+            <fileset dir="${sourcedir}">
+                <exclude name="**/*.java"/>
+            </fileset>
+        </copy>
+    </target>
+
+</project>]]></programlisting>
+
+            <para>
+	这将告诉Ant把所有在lib目录下以<literal>.jar</literal>结尾的文件拷贝到classpath中以供编译之用。它也把所有的非Java源代码文件,例如配置和Hibernate映射文件,拷贝到目标目录。如果你现在运行Ant,会得到以下输出:
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant
+Buildfile: build.xml
+
+copy-resources:
+     [copy] Copying 2 files to C:\hibernateTutorial\bin
+
+compile:
+    [javac] Compiling 1 source file to C:\hibernateTutorial\bin
+
+BUILD SUCCESSFUL
+Total time: 1 second ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-helpers"  revision="3">
+            <title>
+	启动和辅助类
+		</title>
+
+
+            <para>
+	是时候来加载和储存一些<literal>Event</literal>对象了,但首先我们得编写一些基础的代码以完成设置。我们必须启动Hibernate,此过程包括创建一个全局的<literal>SessoinFactory</literal>,并把它储存在应用程序代码容易访问的地方。<literal>SessionFactory</literal>可以创建并打开新的<literal>Session</literal>。一个<literal>Session</literal>代表一个单线程的单元操作,<literal>SessionFactory</literal>则是个线程安全的全局对象,只需要被实例化一次。
+            </para>
+
+            <para>
+	我们将创建一个<literal>HibernateUtil</literal>辅助类(helper class)来负责启动Hibernate和更方便地操作<literal>SessionFactory</literal>。让我们来看一下它的实现:
+            </para>
+
+            <programlisting><![CDATA[package util;
+
+import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+    private static final SessionFactory sessionFactory;
+
+    static {
+        try {
+            // Create the SessionFactory from hibernate.cfg.xml
+            sessionFactory = new Configuration().configure().buildSessionFactory();
+        } catch (Throwable ex) {
+            // Make sure you log the exception, as it might be swallowed
+            System.err.println("Initial SessionFactory creation failed." + ex);
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    public static SessionFactory getSessionFactory() {
+        return sessionFactory;
+    }
+
+}]]></programlisting>
+
+
+            <para>
+	这个类不但在它的静态初始化过程(仅当加载这个类的时候被JVM执行一次)中产生全局的<literal>SessionFactory</literal>,而且隐藏了它使用了静态singleton的事实。它也可能在应用程序服务器中的JNDI查找<literal>SessionFactory</literal>。
+            </para>
+
+            <para>
+                如果你在配置文件中给<literal>SessionFactory</literal>一个名字,在<literal>SessionFactory</literal>创建后,Hibernate会试着把它绑定到JNDI。要完全避免这样的代码,你也可以使用JMX部署,让具有JMX能力的容器来实例化<literal>HibernateService</literal>并把它绑定到JNDI。这些高级可选项在后面的章节中会讨论到。
+            </para>
+
+            <para>
+                把<literal>HibernateUtil.java</literal>放在开发目录的源代码路径下,与放<literal>events</literal>的包并列:
+            </para>
+
+            <programlisting><![CDATA[.
++lib
+  <Hibernate and third-party libraries>
++src
+  +events
+    Event.java
+    Event.hbm.xml
+  +util
+    HibernateUtil.java
+  hibernate.cfg.xml
++data
+build.xml]]></programlisting>
+
+
+            <para>
+	再次编译这个应用程序应该不会有问题。最后我们需要配置一个日志(logging)系统 - Hibernate使用通用日志接口,允许你在Log4j和JDK 1.4 日志之间进行选择。多数开发者更喜欢Log4j:从Hibernate的发布包中(它在<literal>etc/</literal>目录下)拷贝<literal>log4j.properties</literal>到你的<literal>src</literal>目录,与<literal>hibernate.cfg.xml</literal>.放在一起。看一下配置示例,如果你希望看到更加详细的输出信息,你可以修改配置。默认情况下,只有Hibernate的启动信息才会显示在标准输出上。
+            </para>
+
+            <para>
+	示例的基本框架完成了 - 现在我们可以用Hibernate来做些真正的工作。
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-firstapp-workingpersistence"  revision="5">
+            <title>
+	加载并存储对象
+		</title>
+
+            <para>
+	我们终于可以使用Hibernate来加载和存储对象了,编写一个带有<literal>main()</literal>方法的<literal>EventManager</literal>类:
+
+            </para>
+
+            <programlisting><![CDATA[package events;
+import org.hibernate.Session;
+
+import java.util.Date;
+
+import util.HibernateUtil;
+
+public class EventManager {
+
+    public static void main(String[] args) {
+        EventManager mgr = new EventManager();
+
+        if (args[0].equals("store")) {
+            mgr.createAndStoreEvent("My Event", new Date());
+        }
+
+        HibernateUtil.getSessionFactory().close();
+    }
+
+    private void createAndStoreEvent(String title, Date theDate) {
+
+        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+        session.beginTransaction();
+
+        Event theEvent = new Event();
+        theEvent.setTitle(title);
+        theEvent.setDate(theDate);
+
+        session.save(theEvent);
+
+        session.getTransaction().commit();
+    }
+
+}]]></programlisting>
+
+
+            <para>
+	我们创建了个新的<literal>Event</literal>对象并把它传递给Hibernate。现在Hibernate负责与SQL打交道,并把<literal>INSERT</literal>命令传给数据库。在运行之前,让我们看一下处理<literal>Session</literal>和<literal>Transaction</literal>的代码。
+		
+            </para>
+            <para>
+                一个<literal>Session</literal>就是个单一的工作单元。我们暂时让事情简单一些,并假设Hibernate<literal>Session</literal>和数据库事务是一一对应的。为了让我们的代码从底层的事务系统中脱离出来(此例中是JDBC,但也可能是JTA),我们使用Hibernate <literal>Session</literal>中的<literal>Transaction</literal> API。
+            </para>
+
+            <para>
+                <literal>sessionFactory.getCurrentSession()</literal>是干什么的呢?首先,只要你持有<literal>SessionFactory</literal>(幸亏我们有<literal>HibernateUtil</literal>,可以随时获得),大可在任何时候、任何地点调用这个方法。<literal>getCurrentSession()</literal>方法总会返回“当前的”工作单元。记得我们在<literal>hibernate.cfg.xml</literal>中把这一配置选项调整为"thread"了吗?因此,因此,当前工作单元被绑定到当前执行我们应用程序的Java线程。但是,这并非是完全准确的,你还得考虑工作单元的生命周期范围 (scope),它何时开始,又何时结束. 
+             </para>
+
+             <para>
+                <literal>Session</literal>在第一次被使用的时候,即第一次调用<literal>getCurrentSession()</literal>的时候,其生命周期就开始。然后它被Hibernate绑定到当前线程。当事务结束的时候,不管是提交还是回滚,Hibernate会自动把<literal>Session</literal>从当前线程剥离,并且关闭它。假若你再次调用<literal>getCurrentSession()</literal>,你会得到一个新的<literal>Session</literal>,并且开始一个新的工作单元。这种<emphasis>线程绑定(thread-bound)</emphasis>的编程模型(model)是使用Hibernate的最广泛的方式,因为它支持对你的代码灵活分层(事务划分可以和你的数据访问代码分离开来,在本教程的后面部分就会这么做)。
+  
+            </para>
+
+            <para>
+                
+                和工作单元的生命周期这个话题相关,Hibernate <literal>Session</literal>是否被应该用来执行多次数据库操作?上面的例子对每一次操作使用了一个<literal>Session</literal>,这完全是巧合,这个例子不是很复杂,无法展示其他方式。Hibernate <literal>Session</literal>的生命周期可以很灵活,但是你绝不要把你的应用程序设计成为<emphasis>每一次</emphasis>数据库操作都用一个新的Hibernate <literal>Session</literal>。因此就算下面的例子(它们都很简单)中你可以看到这种用法,记住<emphasis>每次操作一个session</emphasis>是一个反模式。在本教程的后面会展示一个真正的(web)程序。
+            </para>
+
+            
+
+            <para>
+                关于事务处理及事务边界界定的详细信息,请参看<xref linkend="transactions"/>。在上面的例子中,我们也忽略了所有的错误与回滚的处理。
+            </para>
+
+            <para>
+	为第一次运行我们的程序,我们得在Ant的build文件中增加一个可以调用得到的target。
+            </para>
+
+            <programlisting><![CDATA[<target name="run" depends="compile">
+    <java fork="true" classname="events.EventManager" classpathref="libraries">
+        <classpath path="${targetdir}"/>
+        <arg value="${action}"/>
+    </java>
+</target>]]></programlisting>
+
+            <para>
+                <literal>action</literal>参数(argument)的值是通过命令行调用这个target的时候设置的:
+            </para>
+
+            <programlisting><![CDATA[C:\hibernateTutorial\>ant run -Daction=store]]></programlisting>
+
+            <para>
+	你应该会看到,编译以后,Hibernate根据你的配置启动,并产生一大堆的输出日志。在日志最后你会看到下面这行:
+            </para>
+
+            <programlisting><![CDATA[[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)]]></programlisting>
+
+            <para>
+	这是Hibernate执行的<literal>INSERT</literal>命令,问号代表JDBC的绑定参数。如果想要看到绑定参数的值或者减少日志的长度,就要调整你在<literal>log4j.properties</literal>文件里的设置。
+            </para>
+
+            <para>
+	我们想要列出所有已经被存储的events,就要增加一个条件分支选项到main方法中去。
+            </para>
+
+            <programlisting><![CDATA[if (args[0].equals("store")) {
+    mgr.createAndStoreEvent("My Event", new Date());
+}
+else if (args[0].equals("list")) {
+    List events = mgr.listEvents();
+    for (int i = 0; i < events.size(); i++) {
+        Event theEvent = (Event) events.get(i);
+        System.out.println("Event: " + theEvent.getTitle() +
+                           " Time: " + theEvent.getDate());
+    }
+}]]></programlisting>
+
+            <para>
+	我们也增加一个新的<literal>listEvents()</literal>方法:
+            </para>
+
+            <programlisting><![CDATA[private List listEvents() {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+    session.beginTransaction();
+
+    List result = session.createQuery("from Event").list();
+
+    session.getTransaction().commit();
+
+    return result;
+}]]></programlisting>
+
+            <para>
+	我们在这里是用一个HQL(Hibernate Query Language-Hibernate查询语言)查询语句来从数据库中加载所有存在的<literal>Event</literal>对象。Hibernate会生成适当的SQL,把它发送到数据库,并操作从查询得到数据的<literal>Event</literal>对象。当然,你可以使用HQL来创建更加复杂的查询。
+            </para>
+            
+            <para>
+	现在,根据以下步骤来执行并测试以上各项:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        运行<literal>ant run -Daction=store</literal>来保存一些内容到数据库。当然,先得用hbm2ddl来生成数据库schema。
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        现在把<literal>hibernate.cfg.xml</literal>文件中hbm2ddl属性注释掉,这样我们就取消了在启动时用hbm2ddl来生成数据库schema。通常只有在不断重复进行单元测试的时候才需要打开它,但再次运行hbm2ddl会把你保存的一切都删掉(<emphasis>drop</emphasis>)——<literal>create</literal>配置的真实含义是:“在创建SessionFactory的时候,从schema 中drop 掉所有的表,再重新创建它们”。
+                    </para>
+                </listitem>
+            </itemizedlist>
+            
+
+            <para>
+	如果你现在使用命令行参数<literal>-Daction=list</literal>运行Ant,你会看到那些至今为止我们所储存的events。当然,你也可以多调用几次<literal>store</literal>以保存更多的envents。
+            </para>
+            
+            <para>
+                注意,很多Hibernate新手在这一步会失败,我们不时看到关于<emphasis>Table not found</emphasis>错误信息的提问。但是,只要你根据上面描述的步骤来执行,就不会有这个问题,因为hbm2ddl会在第一次运行的时候创建数据库schema,后继的应用程序重起后还能继续使用这个schema。假若你修改了映射,或者修改了数据库schema,你必须把hbm2ddl重新打开一次。
+            </para>
+
+        </sect2>
+
+    </sect1>
+    <sect1 id="tutorial-associations">
+        <title>
+	第二部分 - 关联映射
+	</title>
+
+        <para>
+	我们已经映射了一个持久化实体类到表上。让我们在这个基础上增加一些类之间的关联。首先我们往应用程序里增加人(people)的概念,并存储他们所参与的一个Event列表。(译者注:与Event一样,我们在后面将直接使用person来表示“人”而不是它的中文翻译)
+        </para>
+
+        <sect2 id="tutorial-associations-mappinguser" revision="1">
+            <title>
+	映射Person类
+		</title>
+
+            <para>
+	最初简单的<literal>Person</literal>类:
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+public class Person {
+
+    private Long id;
+    private int age;
+    private String firstname;
+    private String lastname;
+
+    public Person() {}
+
+    // Accessor methods for all properties, private setter for 'id'
+
+}]]></programlisting>
+
+            <para>
+                创建一个名为<literal>Person.hbm.xml</literal>的新映射文件(别忘了最上面的DTD引用):
+            </para>
+
+            <programlisting><![CDATA[<hibernate-mapping>
+
+    <class name="events.Person" table="PERSON">
+        <id name="id" column="PERSON_ID">
+            <generator class="native"/>
+        </id>
+        <property name="age"/>
+        <property name="firstname"/>
+        <property name="lastname"/>
+    </class>
+
+</hibernate-mapping>]]></programlisting>
+
+            <para>
+                最后,把新的映射加入到Hibernate的配置中:
+            </para>
+
+            <programlisting><![CDATA[<mapping resource="events/Event.hbm.xml"/>
+<mapping resource="events/Person.hbm.xml"/>]]></programlisting>
+
+            <para>
+	现在我们在这两个实体之间创建一个关联。显然,persons可以参与一系列events,而events也有不同的参加者(persons)。我们需要处理的设计问题是关联方向(directionality),阶数(multiplicity)和集合(collection)的行为。
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-unidirset" revision="3">
+            <title>
+	单向Set-based的关联
+		</title>
+
+            <para>
+	我们将向<literal>Person</literal>类增加一连串的events。那样,通过调用<literal>aPerson.getEvents()</literal>,就可以轻松地导航到特定person所参与的events,而不用去执行一个显式的查询。我们使用Java的集合类(collection):<literal>Set</literal>,因为set 不包含重复的元素及与我们无关的排序。
+            </para>
+
+            <para>
+	我们需要用set 实现一个单向多值关联。让我们在Java类里为这个关联编码,接着映射它:
+            </para>
+
+            <programlisting><![CDATA[public class Person {
+
+    private Set events = new HashSet();
+
+    public Set getEvents() {
+        return events;
+    }
+
+    public void setEvents(Set events) {
+        this.events = events;
+    }
+}]]></programlisting>
+
+            <para>
+	在映射这个关联之前,先考虑一下此关联的另外一端。很显然,我们可以保持这个关联是单向的。或者,我们可以在<literal>Event</literal>里创建另外一个集合,如果希望能够双向地导航,如:<literal>anEvent.getParticipants()</literal>。从功能的角度来说,这并不是必须的。因为你总可以显式地执行一个查询,以获得某个特定event的所有参与者。这是个在设计时需要做出的选择,完全由你来决定,但此讨论中关于关联的阶数是清楚的:即两端都是“多”值的,我们把它叫做<emphasis>多对多(many-to-many)</emphasis>关联。因而,我们使用Hibernate的多对多映射:
+            </para>
+
+            <programlisting><![CDATA[<class name="events.Person" table="PERSON">
+    <id name="id" column="PERSON_ID">
+        <generator class="native"/>
+    </id>
+    <property name="age"/>
+    <property name="firstname"/>
+    <property name="lastname"/>
+
+    <set name="events" table="PERSON_EVENT">
+        <key column="PERSON_ID"/>
+        <many-to-many column="EVENT_ID" class="events.Event"/>
+    </set>
+
+</class>]]></programlisting>
+
+            <para>
+	Hibernate支持各种各样的集合映射,<literal>&lt;set&gt;</literal>使用的最为普遍。对于多对多关联(或叫<emphasis>n:m</emphasis>实体关系), 需要一个关联表(association table)。<literal>表</literal>里面的每一行代表从person到event的一个关联。表名是由<literal>set</literal>元素的<literal>table</literal>属性配置的。关联里面的标识符字段名,对于person的一端,是由<literal>&lt;key&gt;</literal>元素定义,而event一端的字段名是由<literal>&lt;many-to-many&gt;</literal>元素的<literal>column</literal>属性定义。你也必须告诉Hibernate集合中对象的类(也就是位于这个集合所代表的关联另外一端的类)。
+            </para>
+
+            <para>
+	 因而这个映射的数据库schema是:
+            </para>
+
+            <programlisting><![CDATA[
+    _____________        __________________
+   |             |      |                  |       _____________
+   |   EVENTS    |      |   PERSON_EVENT   |      |             |
+   |_____________|      |__________________|      |    PERSON   |
+   |             |      |                  |      |_____________|
+   | *EVENT_ID   | <--> | *EVENT_ID        |      |             |
+   |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  |
+   |  TITLE      |      |__________________|      |  AGE        |
+   |_____________|                                |  FIRSTNAME  |
+                                                  |  LASTNAME   |
+                                                  |_____________|
+ ]]></programlisting>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-working"  revision="2">
+            <title>
+	使关联工作
+	</title>
+
+            <para>
+	我们把一些people和events 一起放到<literal>EventManager</literal>的新方法中:
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    aPerson.getEvents().add(anEvent);
+
+    session.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+	在加载一<literal>Person</literal>和<literal>Event</literal>后,使用普通的集合方法就可容易地修改我们定义的集合。如你所见,没有显式的<literal>update()</literal>或<literal>save()</literal>,Hibernate会自动检测到集合已经被修改并需要更新回数据库。这叫做自动脏检查(<emphasis>automatic dirty checking</emphasis>),你也可以尝试修改任何对象的name或者date属性,只要他们处于<emphasis>持久化</emphasis>状态,也就是被绑定到某个Hibernate 的<literal>Session</literal>上(如:他们刚刚在一个单元操作被加载或者保存),Hibernate监视任何改变并在后台隐式写的方式执行SQL。同步内存状态和数据库的过程,通常只在单元操作结束的时候发生,称此过程为清理缓存<emphasis>(flushing)</emphasis>。在我们的代码中,工作单元由数据库事务的提交(或者回滚)来结束——这是由<literal>Curren!
 tSessionContext</literal>类的<literal>thread</literal>配置选项定义的。
+            </para>
+
+            <para>
+	当然,你也可以在不同的单元操作里面加载person和event。或在<literal>Session</literal>以外修改不是处在持久化(persistent)状态下的对象(如果该对象以前曾经被持久化,那么我们称这个状态为<emphasis>脱管(detached)</emphasis>)。你甚至可以在一个集合被脱管时修改它:
+            </para>
+
+            <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session
+            .createQuery("select p from Person p left join fetch p.events where p.id = :pid")
+            .setParameter("pid", personId)
+            .uniqueResult(); // Eager fetch the collection so we can use it detached
+
+    Event anEvent = (Event) session.load(Event.class, eventId);
+
+    session.getTransaction().commit();
+
+    // End of first unit of work
+
+    aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached
+
+    // Begin second unit of work
+
+    Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
+    session2.beginTransaction();
+
+    session2.update(aPerson); // Reattachment of aPerson
+
+    session2.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+	对<literal>update</literal>的调用使一个脱管对象重新持久化,你可以说它被绑定到一个新的单元操作上,所以在脱管状态下对它所做的任何修改都会被保存到数据库里。这也包括你对这个实体对象的集合所作的任何改动(增加/删除)。
+            </para>
+
+            <para>
+	这对我们当前的情形不是很有用,但它是非常重要的概念,你可以把它融入到你自己的应用程序设计中。在<literal>EventManager</literal>的main方法中添加一个新的动作,并从命令行运行它来完成我们所做的练习。如果你需要person及event的标识符 — 那就用<literal>save()</literal>方法返回它(你可能需要修改前面的一些方法来返回那个标识符):
+            </para>
+
+            <programlisting><![CDATA[else if (args[0].equals("addpersontoevent")) {
+    Long eventId = mgr.createAndStoreEvent("My Event", new Date());
+    Long personId = mgr.createAndStorePerson("Foo", "Bar");
+    mgr.addPersonToEvent(personId, eventId);
+    System.out.println("Added person " + personId + " to event " + eventId);
+}]]></programlisting>
+
+            <para>
+	上面是个关于两个同等重要的实体类间关联的例子。像前面所提到的那样,在特定的模型中也存在其它的类和类型,这些类和类型通常是“次要的”。你已看到过其中的一些,像<literal>int</literal>或<literal>String</literal>。我们称这些类为<emphasis>值类型(value type)</emphasis>,它们的实例<emphasis>依赖(depend)</emphasis>在某个特定的实体上。这些类型的实例没有它们自己的标识(identity),也不能在实体间被共享(比如,两个person不能引用同一个<literal>firstname</literal>对象,即使他们有相同的first name)。当然,值类型并不仅仅在JDK中存在(事实上,在一个Hibernate应用程序中,所有的JDK类都被视为值类型),而且你也可以编写你自己的依赖类,例如<literal>Address</literal>,<literal>MonetaryAmount</literal>。
+            </para>
+
+            <para>
+	你也可以设计一个值类型的集合,这在概念上与引用其它实体的集合有很大的不同,但是在Java里面看起来几乎是一样的。
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-valuecollections">
+            <title>
+	值类型的集合
+	</title>
+
+            <para>
+	我们把一个值类型对象的集合加入<literal>Person</literal>实体中。我们希望保存email地址,所以使用<literal>String</literal>类型,而且这次的集合类型又是<literal>Set</literal>:
+            </para>
+            <programlisting><![CDATA[private Set emailAddresses = new HashSet();
+
+public Set getEmailAddresses() {
+    return emailAddresses;
+}
+
+public void setEmailAddresses(Set emailAddresses) {
+    this.emailAddresses = emailAddresses;
+}]]></programlisting>
+
+            <para>
+	这个<literal>Set</literal>的映射
+            </para>
+
+            <programlisting><![CDATA[<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
+    <key column="PERSON_ID"/>
+    <element type="string" column="EMAIL_ADDR"/>
+</set>]]></programlisting>
+
+            <para>
+	比较这次和此前映射的差别,主要在于<literal>element</literal>部分,这次并没有包含对其它实体引用的集合,而是元素类型为<literal>String</literal>的集合(在映射中使用小写的名字”string“是向你表明它是一个Hibernate的映射类型或者类型转换器)。和之前一样,<literal>set</literal>元素的<literal>table</literal>属性决定了用于集合的表名。<literal>key</literal>元素定义了在集合表中外键的字段名。<literal>element</literal>元素的<literal>column</literal>属性定义用于实际保存<literal>String</literal>值的字段名。
+            </para>
+
+            <para>
+	看一下修改后的数据库schema。
+            </para>
+
+            <programlisting><![CDATA[
+  _____________        __________________
+ |             |      |                  |       _____________
+ |   EVENTS    |      |   PERSON_EVENT   |      |             |       ___________________
+ |_____________|      |__________________|      |    PERSON   |      |                   |
+ |             |      |                  |      |_____________|      | PERSON_EMAIL_ADDR |
+ | *EVENT_ID   | <--> | *EVENT_ID        |      |             |      |___________________|
+ |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  | <--> |  *PERSON_ID       |
+ |  TITLE      |      |__________________|      |  AGE        |      |  *EMAIL_ADDR      |
+ |_____________|                                |  FIRSTNAME  |      |___________________|
+                                                |  LASTNAME   |
+                                                |_____________|
+ ]]></programlisting>
+
+            <para>
+	你可以看到集合表的主键实际上是个复合主键,同时使用了2个字段。这也暗示了对于同一个person不能有重复的email地址,这正是Java里面使用Set时候所需要的语义(Set里元素不能重复)。
+            </para>
+
+            <para>
+	你现在可以试着把元素加入到这个集合,就像我们在之前关联person和event的那样。其实现的Java代码是相同的:
+            </para>
+            <programlisting><![CDATA[private void addEmailToPerson(Long personId, String emailAddress) {
+
+    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+    session.beginTransaction();
+
+    Person aPerson = (Person) session.load(Person.class, personId);
+
+    // The getEmailAddresses() might trigger a lazy load of the collection
+    aPerson.getEmailAddresses().add(emailAddress);
+
+    session.getTransaction().commit();
+}]]></programlisting>
+
+            <para>
+                这次我们没有使用<emphasis>fetch</emphasis>查询来初始化集合。因此,调用其getter方法会触发另一附加的select来初始化集合,这样我们才能把元素添加进去。检查SQL log,试着通过预先抓取来优化它。
+            </para>
+
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-bidirectional"  revision="1">
+            <title>
+	双向关联
+	</title>
+
+            <para>
+	接下来我们将映射双向关联(bi-directional association)- 在Java里让person和event可以从关联的任何一端访问另一端。当然,数据库schema没有改变,我们仍然需要多对多的阶数。一个关系型数据库要比网络编程语言	更加灵活,所以它并不需要任何像导航方向(navigation direction)的东西 - 数据可以用任何可能的方式进行查看和获取。
+            </para>
+
+            <para>
+	首先,把一个参与者(person)的集合加入<literal>Event</literal>类中:
+            </para>
+
+            <programlisting><![CDATA[private Set participants = new HashSet();
+
+public Set getParticipants() {
+    return participants;
+}
+
+public void setParticipants(Set participants) {
+    this.participants = participants;
+}]]></programlisting>
+
+            <para>
+	在<literal>Event.hbm.xml</literal>里面也映射这个关联。
+            </para>
+
+            <programlisting><![CDATA[<set name="participants" table="PERSON_EVENT" inverse="true">
+    <key column="EVENT_ID"/>
+    <many-to-many column="PERSON_ID" class="events.Person"/>
+</set>]]></programlisting>
+            <para>
+	如你所见,两个映射文件里都有普通的<literal>set</literal>映射。注意在两个映射文件中,互换了<literal>key</literal>和<literal>many-to-many</literal>的字段名。这里最重要的是<literal>Event</literal>映射文件里增加了<literal>set</literal>元素的<literal>inverse="true"</literal>属性。
+            </para>
+
+            <para>
+	这意味着在需要的时候,Hibernate能在关联的另一端 - <literal>Person</literal>类得到两个实体间关联的信息。这将会极大地帮助你理解双向关联是如何在两个实体间被创建的。
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-associations-usingbidir">
+	<title>
+	使双向连起来
+	</title>
+
+            <para>
+	首先请记住,Hibernate并不影响通常的Java语义。	在单向关联的例子中,我们是怎样在<literal>Person</literal>和<literal>Event</literal>之间创建联系的?我们把<literal>Event</literal>实例添加到<literal>Person</literal>实例内的event引用集合里。因此很显然,如果我们要让这个关联可以双向地工作,我们需要在另外一端做同样的事情 - 把<literal>Person</literal>实例加入<literal>Event</literal>类内的Person引用集合。这“在关联的两端设置联系”是完全必要的而且你都得这么做。
+            </para>
+
+            <para>
+	许多开发人员防御式地编程,创建管理关联的方法来保证正确的设置了关联的两端,比如在<literal>Person</literal>里:
+            </para>
+
+            <programlisting><![CDATA[protected Set getEvents() {
+    return events;
+}
+
+protected void setEvents(Set events) {
+    this.events = events;
+}
+
+public void addToEvent(Event event) {
+    this.getEvents().add(event);
+    event.getParticipants().add(this);
+}
+
+public void removeFromEvent(Event event) {
+    this.getEvents().remove(event);
+    event.getParticipants().remove(this);
+}]]></programlisting>
+
+            <para>
+	注意现在对于集合的get和set方法的访问级别是protected - 这允许在位于同一个包(package)中的类以及继承自这个类的子类可以访问这些方法,但禁止其他任何人的直接访问,避免了集合内容的混乱。你应尽可能地在另一端也把集合的访问级别设成protected。
+            </para>
+
+            <para>
+	<literal>inverse</literal>映射属性究竟表示什么呢?对于你和Java来说,一个双向关联仅仅是在两端简单地正确设置引用。然而,Hibernate并没有足够的信息去正确地执行<literal>INSERT</literal>和<literal>UPDATE</literal>语句(以避免违反数据库约束),所以它需要一些帮助来正确的处理双向关联。把关联的一端设置为<literal>inverse</literal>将告诉Hibernate忽略关联的这一端,把这端看成是另外一端的一个<emphasis>镜象(mirror)</emphasis>。这就是所需的全部信息,Hibernate利用这些信息来处理把一个有向导航模型转移到数据库schema时的所有问题。你只需要记住这个直观的规则:所有的双向关联需要有一端被设置为<literal>inverse</literal>。在一对多关联中它必须是代表多(many)的那端。而在多对多(many-to-many)关联中,你可以任意选取一端,因为两端之间并没有差别。
+            </para>
+        </sect2>
+        <para>
+	让我们把进入一个小型的web应用程序。
+        </para>
+
+    </sect1>
+
+    <sect1 id="tutorial-webapp">
+        <title>第三部分 - EventManager web应用程序</title>
+
+        <para>
+            Hibernate web应用程序使用<literal>Session</literal> 和<literal>Transaction</literal>的方式几乎和独立应用程序是一样的。但是,有一些常见的模式(pattern)非常有用。现在我们编写一个<literal>EventManagerServlet</literal>。这个servlet可以列出数据库中保存的所有的events,还提供一个HTML表单来增加新的events。
+        </para>
+
+        <sect2 id="tutorial-webapp-servlet" revision="2">
+            <title>编写基本的servlet</title>
+
+            <para>
+                在你的源代码目录的<literal>events</literal>包中创建一个新的类:
+            </para>
+
+            <programlisting><![CDATA[package events;
+
+// Imports
+
+public class EventManagerServlet extends HttpServlet {
+
+    // Servlet code
+}]]></programlisting>
+
+            <para>
+                我们后面会用到<literal>dateFormatter</literal> 的工具, 它把<literal>Date</literal>对象转换为字符串。只要一个formatter作为servlet的成员就可以了。
+            </para>
+
+            <para>
+                这个servlet只处理 HTTP <literal>GET</literal> 请求,因此,我们要实现的是<literal>doGet()</literal>方法:
+            </para>
+
+            <programlisting><![CDATA[protected void doGet(HttpServletRequest request,
+                     HttpServletResponse response)
+        throws ServletException, IOException {
+
+    SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
+
+    try {
+        // Begin unit of work
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().beginTransaction();
+
+        // Process request and render page...
+
+        // End unit of work
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().getTransaction().commit();
+
+    } catch (Exception ex) {
+        HibernateUtil.getSessionFactory()
+                .getCurrentSession().getTransaction().rollback();
+        throw new ServletException(ex);
+    }
+
+}]]></programlisting>
+            <para>
+我们称这里应用的模式为每次请求一个session<emphasis>(session-per-request)</emphasis>。当有请求到达这个servlet的时候,通过对<literal>SessionFactory</literal>的第一次调用,打开一个新的Hibernate <literal>Session</literal>。然后启动一个数据库事务&mdash;所有的数据访问都是在事务中进行,不管是读还是写(我们在应用程序中不使用auto-commit模式)。
+            </para>
+            
+            <para>
+
+                <emphasis>不要</emphasis>为每次数据库操作都使用一个新的Hibernate <literal>Session</literal>。将Hibernate <literal>Session</literal>的范围设置为整个请求。要用<literal>getCurrentSession()</literal>,这样它自动会绑定到当前Java线程。
+            </para>
+
+            <para>
+                下一步,对请求的可能动作进行处理,渲染出反馈的HTML。我们很快就会涉及到那部分。
+            </para>
+
+            <para>
+                最后,当处理与渲染都结束的时候,这个工作单元就结束了。假若在处理或渲染的时候有任何错误发生,会抛出一个异常,回滚数据库事务。这样,<literal>session-per-request</literal>模式就完成了。为了避免在每个servlet中都编写事务边界界定的代码,可以考虑写一个servlet 过滤器(filter)来更好地解决。关于这一模式的更多信息,请参阅Hibernate网站和Wiki,这一模式叫做<emphasis>Open Session in View</emphasis>&mdash;只要你考虑用JSP来渲染你的视图(view),而不是在servlet中,你就会很快用到它。
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-webapp-processing" revision="1">
+            <title>处理与渲染</title>
+
+            <para>
+                我们来实现处理请求以及渲染页面的工作。
+            </para>
+
+<programlisting><![CDATA[// Write HTML header
+PrintWriter out = response.getWriter();
+out.println("<html><head><title>Event Manager</title></head><body>");
+
+// Handle actions
+if ( "store".equals(request.getParameter("action")) ) {
+
+    String eventTitle = request.getParameter("eventTitle");
+    String eventDate = request.getParameter("eventDate");
+
+    if ( "".equals(eventTitle) || "".equals(eventDate) ) {
+        out.println("<b><i>Please enter event title and date.</i></b>");
+    } else {
+        createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
+        out.println("<b><i>Added event.</i></b>");
+    }
+}
+
+// Print page
+printEventForm(out);
+listEvents(out, dateFormatter);
+
+// Write HTML footer
+out.println("</body></html>");
+out.flush();
+out.close();]]></programlisting>
+            <para>
+                <literal>listEvents()</literal>方法使用绑定到当前线程的Hibernate <literal>Session</literal>来执行查询:
+            </para>
+
+            <programlisting><![CDATA[private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) {
+
+    List result = HibernateUtil.getSessionFactory()
+                    .getCurrentSession().createCriteria(Event.class).list();
+    if (result.size() > 0) {
+        out.println("<h2>Events in database:</h2>");
+        out.println("<table border='1'>");
+        out.println("<tr>");
+        out.println("<th>Event title</th>");
+        out.println("<th>Event date</th>");
+        out.println("</tr>");
+        for (Iterator it = result.iterator(); it.hasNext();) {
+            Event event = (Event) it.next();
+            out.println("<tr>");
+            out.println("<td>" + event.getTitle() + "</td>");
+            out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
+            out.println("</tr>");
+        }
+        out.println("</table>");
+    }
+}]]></programlisting>
+
+            <para>
+                最后,<literal>store</literal>动作会被导向到<literal>createAndStoreEvent()</literal>方法,它也使用当前线程的<literal>Session</literal>:
+            </para>
+
+            <programlisting><![CDATA[protected void createAndStoreEvent(String title, Date theDate) {
+    Event theEvent = new Event();
+    theEvent.setTitle(title);
+    theEvent.setDate(theDate);
+
+    HibernateUtil.getSessionFactory()
+                    .getCurrentSession().save(theEvent);
+}]]></programlisting>
+
+            <para>
+	大功告成,这个servlet写完了。Hibernate会在单一的<literal>Session</literal> 和<literal>Transaction</literal>中处理到达的servlet请求。如同在前面的独立应用程序中那样,Hibernate可以自动的把这些对象绑定到当前运行的线程中。这给了你用任何你喜欢的方式来对代码分层及访问<literal>SessionFactory</literal>的自由。通常,你会用更加完备的设计,把数据访问代码转移到数据访问对象中(DAO模式)。请参见Hibernate Wiki,那里有更多的例子。
+            </para>
+
+        </sect2>
+
+        <sect2 id="tutorial-webapp-deploy">
+            <title>部署与测试</title>
+
+            <para>
+	要发布这个程序,你得把它打成web发布包:WAR文件。把下面的脚本加入到你的<literal>build.xml</literal>中:
+            </para>
+
+<programlisting><![CDATA[<target name="war" depends="compile">
+    <war destfile="hibernate-tutorial.war" webxml="web.xml">
+        <lib dir="${librarydir}">
+          <exclude name="jsdk*.jar"/>
+        </lib>
+
+        <classes dir="${targetdir}"/>
+    </war>
+</target>]]></programlisting>
+
+            <para>
+	这段代码在你的开发目录中创建一个<literal>hibernate-tutorial.war</literal>的文件。它把所有的类库和<literal>web.xml</literal>描述文件都打包进去,web.xml 文件应该位于你的开发根目录中:
+            </para>
+
+<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+    xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+    <servlet>
+        <servlet-name>Event Manager</servlet-name>
+        <servlet-class>events.EventManagerServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Event Manager</servlet-name>
+        <url-pattern>/eventmanager</url-pattern>
+    </servlet-mapping>
+</web-app>]]></programlisting>
+
+            <para>
+                请注意在你编译和部署web应用程之前,需要一个附加的类库:<literal>jsdk.jar</literal>。这是Java Servlet开发包,假若你还没有,可以从Sun网站上下载,把它copy到你的lib目录。但是,它仅仅是在编译时需要,不会被打入WAR包。
+            </para>
+
+            <para>
+                在你的开发目录中,调用<literal>ant war</literal>来构建、打包,然后把<literal>hibernate-tutorial.war</literal>文件拷贝到你的tomcat的<literal>webapps</literal>目录下。假若你还没安装Tomcat,就去下载一个,按照指南来安装。对此应用的发布,你不需要修改任何Tomcat的配置。
+            </para>
+
+            <para>
+		在部署完,启动Tomcat之后,通过<literal>http://localhost:8080/hibernate-tutorial/eventmanager</literal>进行访问你的应用,在第一次servlet 请求发生时,请在Tomcat log中确认你看到Hibernate被初始化了(<literal>HibernateUtil</literal>的静态初始化器被调用),假若有任何异常抛出,也可以看到详细的输出。
+            </para>
+
+        </sect2>
+
+    </sect1>
+	     <sect1 id="tutorial-summary">
+  	         <title>
+  	         总结
+  	         </title>
+  	 
+  	         <para>
+	本章覆盖了如何编写一个简单独立的Hibernate命令行应用程序及小型的Hibernate web应用程序的基本要素。
+  	         </para>
+  	 
+  	         <para>
+	如果你已经对Hibernate感到自信,通过开发指南目录,继续浏览你感兴趣的内容-那些会被问到的问题大多是事务处理 (<xref linkend="transactions"/>),抓取(fetch)的效率 (<xref linkend="performance"/>),或者API的使用 (<xref linkend="objectstate"/>)和查询的特性(<xref linkend="objectstate-querying"/>)。
+  	         </para>
+  	 
+  	         <para>
+  	          别忘了去Hibernate的网站查看更多(有针对性的)示例。
+  	         </para>
+  	 
+  	     </sect1>    
+</chapter>

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/xml.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/xml.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/docbook/modules/xml.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,270 @@
+<chapter id="xml">
+    <title>XML映射</title>
+    <para><emphasis>
+        注意这是Hibernate 3.0的一个实验性的特性。这一特性仍在积极开发中。
+    </emphasis></para>
+
+    <sect1 id="xml-intro" revision="1">
+        <title>用XML数据进行工作</title>
+
+        <para>
+            Hibernate使得你可以用XML数据来进行工作,恰如你用持久化的POJO进行工作那样。解析过的XML树
+            可以被认为是代替POJO的另外一种在对象层面上表示关系型数据的途径.
+        </para>
+
+        <para>
+            Hibernate支持采用dom4j作为操作XML树的API。你可以写一些查询从数据库中检索出
+            dom4j树,随后你对这颗树做的任何修改都将自动同步回数据库。你甚至可以用dom4j解析
+            一篇XML文档,然后使用Hibernate的任一基本操作将它写入数据库:
+            <literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal> 
+            (合并操作merge()目前还不支持)。
+        </para>
+
+        <para>
+            这一特性可以应用在很多场合,包括数据导入导出,通过JMS或SOAP具体化实体数据以及
+            基于XSLT的报表。
+        </para>
+        
+        <para>
+            一个单一的映射就可以将类的属性和XML文档的节点同时映射到数据库。如果不需要映射类,
+            它也可以用来只映射XML文档。
+        </para>
+        
+        <sect2 id="xml-intro-mapping">
+            <title>指定同时映射XML和类</title>
+
+            <para>
+                这是一个同时映射POJO和XML的例子:
+            </para>
+            
+            <programlisting><![CDATA[<class name="Account" 
+        table="ACCOUNTS" 
+        node="account">
+        
+    <id name="accountId" 
+            column="ACCOUNT_ID" 
+            node="@id"/>
+            
+    <many-to-one name="customer" 
+            column="CUSTOMER_ID" 
+            node="customer/@id" 
+            embed-xml="false"/>
+            
+    <property name="balance" 
+            column="BALANCE" 
+            node="balance"/>
+            
+    ...
+    
+</class>]]></programlisting>
+        </sect2>
+        
+        <sect2 id="xml-onlyxml">
+            <title>只定义XML映射</title>
+
+            <para>
+                这是一个不映射POJO的例子:
+            </para>
+            
+            <programlisting><![CDATA[<class entity-name="Account" 
+        table="ACCOUNTS" 
+        node="account">
+        
+    <id name="id" 
+            column="ACCOUNT_ID" 
+            node="@id" 
+            type="string"/>
+            
+    <many-to-one name="customerId" 
+            column="CUSTOMER_ID" 
+            node="customer/@id" 
+            embed-xml="false" 
+            entity-name="Customer"/>
+            
+    <property name="balance" 
+            column="BALANCE" 
+            node="balance" 
+            type="big_decimal"/>
+            
+    ...
+    
+</class>]]></programlisting>
+        
+            <para>
+                这个映射使得你既可以把数据作为一棵dom4j树那样访问,又可以作为由属性键值对(java <literal>Map</literal>s)
+                组成的图那样访问。属性名字纯粹是逻辑上的结构,你可以在HQL查询中引用它。
+            </para>
+
+        </sect2>
+        
+     </sect1>
+     
+    <sect1 id="xml-mapping" revision="1">
+        <title>XML映射元数据</title>
+
+        <para>
+            许多Hibernate映射元素具有<literal>node</literal>属性。这使你可以指定用来保存
+            属性或实体数据的XML属性或元素。<literal>node</literal>属性必须是下列格式之一:
+        </para>
+        
+        <itemizedlist spacing="compact">
+        <listitem>
+            <para><literal>"element-name"</literal> - 映射为指定的XML元素</para>
+        </listitem>
+        <listitem>
+            <para><literal>"@attribute-name"</literal> - 映射为指定的XML属性</para>
+        </listitem>
+        <listitem>
+            <para><literal>"."</literal> - 映射为父元素</para>
+        </listitem>
+        <listitem>
+            <para>
+                <literal>"element-name/@attribute-name"</literal> - 
+                映射为指定元素的指定属性
+            </para>
+        </listitem>
+        </itemizedlist>
+        
+        <para>
+            对于集合和单值的关联,有一个额外的<literal>embed-xml</literal>属性可用。
+            这个属性的缺省值是真(<literal>embed-xml="true"</literal>)。如果<literal>embed-xml="true"</literal>,
+            则对应于被关联实体或值类型的集合的XML树将直接嵌入拥有这些关联的实体的XML树中。
+            否则,如果<literal>embed-xml="false"</literal>,那么对于单值的关联,仅被引用的实体的标识符出现在
+            XML树中(被引用实体本身不出现),而集合则根本不出现。
+        </para>
+        
+        <para>
+            你应该小心,不要让太多关联的embed-xml属性为真(<literal>embed-xml="true"</literal>),因为XML不能很好地处理
+            循环引用!
+        </para>
+        
+        <programlisting><![CDATA[<class name="Customer" 
+        table="CUSTOMER" 
+        node="customer">
+        
+    <id name="id" 
+            column="CUST_ID" 
+            node="@id"/>
+            
+    <map name="accounts" 
+            node="." 
+            embed-xml="true">
+        <key column="CUSTOMER_ID" 
+                not-null="true"/>
+        <map-key column="SHORT_DESC" 
+                node="@short-desc" 
+                type="string"/>
+        <one-to-many entity-name="Account"
+                embed-xml="false" 
+                node="account"/>
+    </map>
+    
+    <component name="name" 
+            node="name">
+        <property name="firstName" 
+                node="first-name"/>
+        <property name="initial" 
+                node="initial"/>
+        <property name="lastName" 
+                node="last-name"/>
+    </component>
+    
+    ...
+    
+</class>]]></programlisting>
+
+        <para>
+            在这个例子中,我们决定嵌入帐目号码(account id)的集合,但不嵌入实际的帐目数据。下面的HQL查询:
+        </para>
+        
+        <programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
+        
+        <para>
+            返回的数据集将是这样:
+        </para>
+        
+        <programlisting><![CDATA[<customer id="123456789">
+    <account id="987632567" short-desc="Savings"/>
+    <account id="985612323" short-desc="Credit Card"/>
+    <name>
+        <first-name>Gavin</first-name>
+        <initial>A</initial>
+        <last-name>King</last-name>
+    </name>
+    ...
+</customer>]]></programlisting>
+
+        <para>
+            如果你把一对多映射<literal>&lt;one-to-many&gt;</literal>的embed-xml属性置为真(<literal>embed-xml="true"</literal>),
+            则数据看上去就像这样:
+        </para>
+        
+        <programlisting><![CDATA[<customer id="123456789">
+    <account id="987632567" short-desc="Savings">
+        <customer id="123456789"/>
+        <balance>100.29</balance>
+    </account>
+    <account id="985612323" short-desc="Credit Card">
+        <customer id="123456789"/>
+        <balance>-2370.34</balance>
+    </account>
+    <name>
+        <first-name>Gavin</first-name>
+        <initial>A</initial>
+        <last-name>King</last-name>
+    </name>
+    ...
+</customer>]]></programlisting>
+       
+    </sect1>
+    
+    
+    <sect1 id="xml-manipulation" revision="1">
+        <title>操作XML数据</title>
+        
+        <para>
+            让我们来读入和更新应用程序中的XML文档。通过获取一个dom4j会话可以做到这一点:
+        </para>
+        
+       <programlisting><![CDATA[Document doc = ....;
+       
+Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+List results = dom4jSession
+    .createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")
+    .list();
+for ( int i=0; i<results.size(); i++ ) {
+    //add the customer data to the XML document
+    Element customer = (Element) results.get(i);
+    doc.add(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+       
+       <programlisting><![CDATA[Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+Element cust = (Element) dom4jSession.get("Customer", customerId);
+for ( int i=0; i<results.size(); i++ ) {
+    Element customer = (Element) results.get(i);
+    //change the customer name in the XML and database
+    Element name = customer.element("name");
+    name.element("first-name").setText(firstName);
+    name.element("initial").setText(initial);
+    name.element("last-name").setText(lastName);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+        <para>
+            将这一特色与Hibernate的<literal>replicate()</literal>操作结合起来对于实现的基于XML的数据导入/导出将非常有用.
+        </para>
+       
+    </sect1>
+     
+</chapter>

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/css/html.css
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/css/html.css	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/css/html.css	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,97 @@
+A {
+    color: #003399;
+}
+
+A:active {
+    color: #003399;
+}
+
+A:visited {
+    color: #888888;
+}
+
+P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
+    color: #000000;
+}
+
+TD, TH, SPAN {
+    color: #000000;
+}
+
+BLOCKQUOTE {
+    margin-right: 0px;
+}
+
+
+H1, H2, H3, H4, H5, H6    {
+    color: #000000;
+    font-weight:500;
+    margin-top:10px;
+    padding-top:15px;
+}
+
+TABLE  {
+    border-collapse: collapse;
+    border-spacing:0;
+    border: 1px thin black;
+    empty-cells: hide;
+}
+
+TD  {
+    padding: 4pt;
+}
+
+H1 { font-size: 150%; }
+H2 { font-size: 140%; }
+H3 { font-size: 110%; font-weight: bold; }
+H4 { font-size: 110%; font-weight: bold;}
+H5 { font-size: 100%; font-style: italic; }
+H6 { font-size: 100%; font-style: italic; }
+
+TT {
+font-size: 90%;
+    font-family: "Courier New", Courier, monospace;
+    color: #000000;
+}
+
+PRE {
+font-size: 100%;
+    padding: 5px;
+    border-style: solid;
+    border-width: 1px;
+    border-color: #CCCCCC;
+    background-color: #F4F4F4;
+}
+
+UL, OL, LI {
+    list-style: disc;
+}
+
+HR  {
+    width: 100%;
+    height: 1px;
+    background-color: #CCCCCC;
+    border-width: 0px;
+    padding: 0px;
+    color: #CCCCCC;
+}
+
+.variablelist { 
+    padding-top: 10; 
+    padding-bottom:10; 
+    margin:0;
+}
+
+.itemizedlist, UL { 
+    padding-top: 0; 
+    padding-bottom:0; 
+    margin:0; 
+}
+
+.term { 
+    font-weight:bold;
+}
+
+
+
+    

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/AuthorWork.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/AuthorWork.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/AuthorWork.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/AuthorWork.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/CustomerOrderProduct.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/CustomerOrderProduct.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/CustomerOrderProduct.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/CustomerOrderProduct.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/EmployerEmployee.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/EmployerEmployee.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/EmployerEmployee.zargo
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/EmployerEmployee.zargo
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/full_cream.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/full_cream.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/full_cream.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/full_cream.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/full_cream.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,429 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="354.331"
+   height="336.614"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+     style="font-size:12;"
+     id="g659">
+    <rect
+       width="212.257"
+       height="57.2441"
+       x="17.9576"
+       y="100.132"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       transform="matrix(0.743454,0,0,0.482981,6.46949,52.2178)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <rect
+     width="325.86"
+     height="63.6537"
+     x="17.4083"
+     y="15.194"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect136" />
+  <rect
+     width="325.86"
+     height="63.6537"
+     x="13.6713"
+     y="12.4966"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect126" />
+  <g
+     transform="matrix(1.14345,0,0,0.729078,-1.67818,105.325)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <text
+     x="170.824753"
+     y="58.402939"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="170.824997"
+       y="58.402901"
+       id="tspan360">
+Application</tspan>
+  </text>
+  <text
+     x="178.076340"
+     y="364.281433"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="178.076004"
+       y="364.281006"
+       id="tspan421">
+Database</tspan>
+  </text>
+  <text
+     x="68.605331"
+     y="138.524582"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="68.605301"
+       y="138.524994"
+       id="tspan384">
+SessionFactory</tspan>
+  </text>
+  <rect
+     width="67.0014"
+     height="101.35"
+     x="196.927"
+     y="89.2389"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect387" />
+  <rect
+     width="67.0014"
+     height="101.35"
+     x="194.633"
+     y="86.4389"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect388" />
+  <text
+     x="249.108841"
+     y="173.885559"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text389">
+    <tspan
+       x="249.108994"
+       y="173.886002"
+       id="tspan392">
+Session</tspan>
+  </text>
+  <rect
+     width="73.0355"
+     height="101.35"
+     x="270.995"
+     y="90.0018"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect395" />
+  <rect
+     width="73.0355"
+     height="101.35"
+     x="267.869"
+     y="87.2018"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect396" />
+  <text
+     x="328.593658"
+     y="174.715622"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text397">
+    <tspan
+       x="328.593994"
+       y="174.716003"
+       id="tspan563">
+Transaction</tspan>
+  </text>
+  <g
+     transform="matrix(0.29544,0,0,0.397877,9.70533,103.96)"
+     style="font-size:12;"
+     id="g565">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect566" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect567" />
+  </g>
+  <text
+     x="25.592752"
+     y="204.497803"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text568">
+    <tspan
+       x="25.592800"
+       y="204.498001"
+       id="tspan662">
+TransactionFactory</tspan>
+  </text>
+  <g
+     transform="matrix(0.298082,0,0,0.397877,99.6898,103.96)"
+     style="font-size:12;"
+     id="g573">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect574" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect575" />
+  </g>
+  <text
+     x="134.030670"
+     y="205.532791"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text576">
+    <tspan
+       x="134.031006"
+       y="205.533005"
+       id="tspan664">
+ConnectionProvider</tspan>
+  </text>
+  <g
+     transform="matrix(1.14345,0,0,0.729078,-1.67818,38.9539)"
+     style="font-size:12;"
+     id="g587">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect588" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect589" />
+  </g>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="25.6196"
+     y="206.028"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect594" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="24.4229"
+     y="204.135"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect595" />
+  <text
+     x="85.575645"
+     y="282.300354"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text596">
+    <tspan
+       x="85.575600"
+       y="282.299988"
+       id="tspan607">
+JNDI</tspan>
+  </text>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="236.937"
+     y="206.791"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect610" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="235.741"
+     y="204.898"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect611" />
+  <text
+     x="342.093201"
+     y="283.226410"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text612">
+    <tspan
+       x="342.092987"
+       y="283.226013"
+       id="tspan621">
+JTA</tspan>
+  </text>
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="130.134"
+     y="206.791"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect616" />
+  <rect
+     width="90.951"
+     height="44.4829"
+     x="128.937"
+     y="204.898"
+     style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect617" />
+  <text
+     x="212.445343"
+     y="283.226410"
+     transform="scale(0.823795,0.823795)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text618">
+    <tspan
+       x="212.445007"
+       y="283.226013"
+       id="tspan623">
+JDBC</tspan>
+  </text>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,6.19341)"
+     style="font-size:12;"
+     id="g637">
+    <g
+       transform="matrix(0.499515,0,0,0.415467,-0.237339,5.61339)"
+       id="g167">
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="61.8805"
+         y="68.4288"
+         style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect134" />
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="59.2613"
+         y="65.8095"
+         style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect135" />
+    </g>
+    <text
+       x="33.749969"
+       y="50.589706"
+       style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+       id="text188">
+      <tspan
+         x="33.750000"
+         y="50.589699"
+         id="tspan635">
+Transient Objects</tspan>
+    </text>
+  </g>
+  <g
+     transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+     style="font-size:12;"
+     id="g644">
+    <g
+       transform="matrix(0.297486,0,0,0.516482,230.251,36.9178)"
+       id="g364">
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="61.8805"
+         y="68.4288"
+         style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect365" />
+      <rect
+         width="199.065"
+         height="61.5532"
+         x="59.2613"
+         y="65.8095"
+         style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+         id="rect366" />
+    </g>
+    <text
+       x="277.123230"
+       y="85.155571"
+       style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+       id="text367">
+      <tspan
+         x="277.122986"
+         y="85.155602"
+         id="tspan631">
+Persistent</tspan>
+      <tspan
+         x="277.122986"
+         y="96.155602"
+         id="tspan633">
+Objects</tspan>
+    </text>
+  </g>
+</svg>

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/hibernate_logo_a.png
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/hibernate_logo_a.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/lite.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/lite.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/lite.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/lite.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/lite.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,334 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="318.898"
+   height="248.031"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <rect
+     width="291.837"
+     height="57.0074"
+     x="17.3169"
+     y="18.646"
+     style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect136" />
+  <rect
+     width="291.837"
+     height="57.0074"
+     x="13.9703"
+     y="16.2302"
+     style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+     id="rect126" />
+  <g
+     transform="matrix(0.326107,0,0,0.765831,9.59261,8.98517)"
+     style="font-size:12;"
+     id="g161">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <g
+     transform="matrix(1.02406,0,0,0.652953,0.223384,39.9254)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <g
+     transform="matrix(0.449834,0,0,0.338463,-3.15909,9.73319)"
+     style="font-size:12;"
+     id="g167">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect134" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect135" />
+  </g>
+  <text
+     x="302.277679"
+     y="65.943230"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="302.277954"
+       y="65.943184"
+       id="tspan360">
+Application</tspan>
+  </text>
+  <text
+     x="36.235924"
+     y="63.796055"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text188">
+    <tspan
+       x="36.235950"
+       y="63.796051"
+       id="tspan427">
+Transient Objects</tspan>
+  </text>
+  <text
+     x="180.416245"
+     y="290.543701"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="180.415939"
+       y="290.543549"
+       id="tspan421">
+Database</tspan>
+  </text>
+  <text
+     x="25.037701"
+     y="179.154755"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="25.037655"
+       y="179.154648"
+       id="tspan384">
+SessionFactory</tspan>
+  </text>
+  <g
+     transform="matrix(0.252763,0,0,0.765831,109.104,8.98517)"
+     style="font-size:12;"
+     id="g386">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect387" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect388" />
+  </g>
+  <g
+     transform="matrix(0.297394,0,0,0.572692,101.502,21.6359)"
+     style="font-size:12;"
+     id="g364">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect365" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect366" />
+  </g>
+  <text
+     x="202.746506"
+     y="102.992203"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+     id="text367">
+    <tspan
+       x="202.746948"
+       y="102.992249"
+       id="tspan423">
+Persistent</tspan>
+    <tspan
+       x="202.746948"
+       y="116.992355"
+       id="tspan425">
+Objects</tspan>
+  </text>
+  <text
+     x="174.458496"
+     y="180.080795"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text389">
+    <tspan
+       x="174.458618"
+       y="180.080338"
+       id="tspan392">
+Session</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,188.675,8.98517)"
+     style="font-size:12;"
+     id="g394">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect395" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect396" />
+  </g>
+  <text
+     x="260.413269"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text397">
+    <tspan
+       x="260.412964"
+       y="179.154343"
+       id="tspan400">
+JDBC</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,229.156,8.98517)"
+     style="font-size:12;"
+     id="g405">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect406" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect407" />
+  </g>
+  <text
+     x="320.606903"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text408">
+    <tspan
+       x="320.606964"
+       y="179.154343"
+       id="tspan417">
+JNDI</tspan>
+  </text>
+  <g
+     transform="matrix(0.127369,0,0,0.765831,269.281,8.98517)"
+     style="font-size:12;"
+     id="g411">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect412" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect413" />
+  </g>
+  <text
+     x="377.096313"
+     y="179.154739"
+     transform="scale(0.73778,0.73778)"
+     style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text414">
+    <tspan
+       x="377.096008"
+       y="179.154999"
+       id="tspan145">
+JTA</tspan>
+  </text>
+</svg>

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/overview.gif
===================================================================
(Binary files differ)


Property changes on: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/overview.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/overview.svg
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/overview.svg	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/main/resources/shared/images/overview.svg	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,250 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+  xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   width="248.031"
+   height="248.031"
+   id="svg1">
+  <defs
+     id="defs3">
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop128" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop129" />
+    </linearGradient>
+    <linearGradient
+       x1="0"
+       y1="0"
+       x2="1"
+       y2="0"
+       id="linearGradient130"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+    <radialGradient
+       cx="0.5"
+       cy="0.5"
+       fx="0.5"
+       fy="0.5"
+       r="0.5"
+       id="radialGradient131"
+       xlink:href="#linearGradient127"
+       gradientUnits="objectBoundingBox"
+       spreadMethod="pad" />
+  </defs>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,-3.02123)"
+     style="font-size:12;"
+     id="g158">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="17.3527"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect136" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="15.3883"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect126" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,3.04452)"
+     style="font-size:12;"
+     id="g161">
+    <rect
+       width="285.502"
+       height="118.523"
+       x="16.6979"
+       y="99.2053"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect137" />
+    <rect
+       width="285.502"
+       height="118.523"
+       x="13.4238"
+       y="95.9309"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect132" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,4.36019,8.0993)"
+     style="font-size:12;"
+     id="g164">
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="16.6979"
+       y="222.966"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect138" />
+    <rect
+       width="285.502"
+       height="77.2688"
+       x="14.7335"
+       y="221.002"
+       transform="translate(-1.30962,-1.30992)"
+       style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect133" />
+  </g>
+  <g
+     transform="matrix(0.771934,0,0,0.543505,2.59104,21.1103)"
+     style="font-size:12;"
+     id="g167">
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="61.8805"
+       y="68.4288"
+       style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect134" />
+    <rect
+       width="199.065"
+       height="61.5532"
+       x="59.2613"
+       y="65.8095"
+       style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+       id="rect135" />
+  </g>
+  <text
+     x="105.392174"
+     y="56.568123"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text183">
+    <tspan
+       x="105.392273"
+       y="56.568146"
+       id="tspan186">
+Application</tspan>
+  </text>
+  <text
+     x="81.820183"
+     y="103.149330"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:20;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text188">
+    <tspan
+       x="81.820213"
+       y="103.149727"
+       id="tspan206">
+Persistent Objects</tspan>
+  </text>
+  <text
+     x="111.548180"
+     y="278.927887"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text197">
+    <tspan
+       x="111.547874"
+       y="278.927551"
+       id="tspan200">
+Database</tspan>
+  </text>
+  <text
+     x="94.436180"
+     y="153.805740"
+     transform="scale(0.771934,0.771934)"
+     style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+     id="text216">
+    <tspan
+       x="94.436180"
+       y="153.805740"
+       id="tspan221">
+HIBERNATE</tspan>
+  </text>
+  <g
+     transform="matrix(0.771934,0,0,0.771934,2.59083,1.02261)"
+     style="font-size:12;"
+     id="g254">
+    <g
+       transform="translate(4.58374,2.61928)"
+       id="g176">
+      <g
+         transform="matrix(0.571429,0,0,0.67347,-10.6174,117.093)"
+         id="g170">
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="61.8805"
+           y="68.4288"
+           style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect171" />
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="59.2613"
+           y="65.8095"
+           style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect172" />
+      </g>
+      <g
+         transform="matrix(0.571429,0,0,0.67347,138.682,117.093)"
+         id="g173">
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="61.8805"
+           y="68.4288"
+           style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect174" />
+        <rect
+           width="199.065"
+           height="61.5532"
+           x="59.2613"
+           y="65.8095"
+           style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+           id="rect175" />
+      </g>
+    </g>
+    <text
+       x="47.259438"
+       y="182.367538"
+       style="font-weight:bold;stroke-width:1pt;font-family:Courier;"
+       id="text191">
+      <tspan
+         x="47.259399"
+         y="182.367996"
+         id="tspan212">
+hibernate.</tspan>
+      <tspan
+         x="47.259399"
+         y="194.367996"
+         id="tspan214">
+properties</tspan>
+    </text>
+    <text
+       x="198.523010"
+       y="188.260941"
+       style="font-weight:normal;stroke-width:1pt;font-family:helvetica;"
+       id="text194">
+      <tspan
+         id="tspan195">
+XML Mapping</tspan>
+    </text>
+  </g>
+</svg>

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/fop/simhei.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/fop/simhei.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/fop/simhei.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<font-metrics type="TYPE0"><font-name>SimHei</font-name><embed/><cap-height>0</cap-height><x-height>0</x-height><ascender>859</ascender><descender>-140</descender><bbox><left>0</left><bottom>-140</bottom><right>996</right><top>855</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf us="32" ue="126" gi="3"/><bf us="127" ue="127" gi="2"/><bf us="164" ue="164" gi="98"/><bf us="167" ue="168" gi="99"/><bf us="176" ue="177" gi="101"/><bf us="183" ue="183" gi="103"/><bf us="215" ue="215" gi="104"/><bf us="224" ue="225" gi="105"/><bf us="232" ue="234" gi="107"/><bf us="236" ue="237" gi="110"/><bf us="242" ue="243" gi="112"/><bf us="247" ue="247" gi="114"/><bf us="249" ue="250" gi="115"/><bf us="252" ue="252" gi="117"/><bf us="257" ue="257" gi="118"/><bf us="275" ue="275" gi="119"/><bf us="283" ue="283" gi="120"/><bf us="299" ue="299" gi="121"!
 /><bf us="324" ue="324" gi="122"/><bf us="328" ue="328" gi="123"/><bf us="333" ue="333" gi="124"/><bf us="363" ue="363" gi="125"/><bf us="462" ue="462" gi="126"/><bf us="464" ue="464" gi="127"/><bf us="466" ue="466" gi="128"/><bf us="468" ue="468" gi="129"/><bf us="470" ue="470" gi="130"/><bf us="472" ue="472" gi="131"/><bf us="474" ue="474" gi="132"/><bf us="476" ue="476" gi="133"/><bf us="505" ue="505" gi="687"/><bf us="593" ue="593" gi="134"/><bf us="609" ue="609" gi="135"/><bf us="711" ue="711" gi="136"/><bf us="713" ue="713" gi="137"/><bf us="714" ue="715" gi="799"/><bf us="729" ue="729" gi="801"/><bf us="913" ue="929" gi="138"/><bf us="931" ue="937" gi="155"/><bf us="945" ue="961" gi="162"/><bf us="963" ue="969" gi="179"/><bf us="1025" ue="1025" gi="186"/><bf us="1040" ue="1103" gi="187"/><bf us="1105" ue="1105" gi="251"/><bf us="8208" ue="8208" gi="971"/><bf us="8211" ue="8211" gi="802"/><bf us="8212" ue="8212" gi="252"/><bf us="8213" ue="8213" gi="803"/><bf us="8214!
 " ue="8214" gi="253"/><bf us="8216" ue="8217" gi="254"/><bf us="8220" 
ue="8221" gi="256"/><bf us="8229" ue="8229" gi="804"/><bf us="8230" ue="8230" gi="258"/><bf us="8240" ue="8240" gi="259"/><bf us="8242" ue="8243" gi="260"/><bf us="8245" ue="8245" gi="805"/><bf us="8251" ue="8251" gi="262"/><bf us="8451" ue="8451" gi="263"/><bf us="8453" ue="8453" gi="806"/><bf us="8457" ue="8457" gi="807"/><bf us="8470" ue="8470" gi="264"/><bf us="8481" ue="8481" gi="969"/><bf us="8544" ue="8555" gi="265"/><bf us="8560" ue="8569" gi="957"/><bf us="8592" ue="8595" gi="277"/><bf us="8598" ue="8601" gi="808"/><bf us="8712" ue="8712" gi="281"/><bf us="8719" ue="8719" gi="282"/><bf us="8721" ue="8721" gi="283"/><bf us="8725" ue="8725" gi="812"/><bf us="8730" ue="8730" gi="284"/><bf us="8733" ue="8734" gi="285"/><bf us="8735" ue="8735" gi="813"/><bf us="8736" ue="8736" gi="287"/><bf us="8739" ue="8739" gi="814"/><bf us="8741" ue="8741" gi="288"/><bf us="8743" ue="8747" gi="289"/><bf us="8750" ue="8750" gi="294"/><bf us="8756" ue="8759" gi="295"/><bf us="8765" ue=!
 "8765" gi="299"/><bf us="8776" ue="8776" gi="300"/><bf us="8780" ue="8780" gi="301"/><bf us="8786" ue="8786" gi="815"/><bf us="8800" ue="8801" gi="302"/><bf us="8804" ue="8805" gi="304"/><bf us="8806" ue="8807" gi="816"/><bf us="8814" ue="8815" gi="306"/><bf us="8853" ue="8853" gi="880"/><bf us="8857" ue="8857" gi="308"/><bf us="8869" ue="8869" gi="309"/><bf us="8895" ue="8895" gi="818"/><bf us="8978" ue="8978" gi="310"/><bf us="9312" ue="9321" gi="311"/><bf us="9332" ue="9371" gi="321"/><bf us="9472" ue="9547" gi="361"/><bf us="9552" ue="9587" gi="819"/><bf us="9601" ue="9615" gi="855"/><bf us="9619" ue="9621" gi="870"/><bf us="9632" ue="9633" gi="437"/><bf us="9650" ue="9651" gi="439"/><bf us="9660" ue="9661" gi="873"/><bf us="9670" ue="9671" gi="441"/><bf us="9675" ue="9675" gi="443"/><bf us="9678" ue="9679" gi="444"/><bf us="9698" ue="9701" gi="875"/><bf us="9733" ue="9734" gi="446"/><bf us="9737" ue="9737" gi="879"/><bf us="9792" ue="9792" gi="448"/><bf us="9794" ue="9!
 794" gi="449"/><bf us="11905" ue="11905" gi="21903"/><bf us="11908" ue
="11908" gi="21907"/><bf us="11912" ue="11912" gi="21910"/><bf us="11915" ue="11915" gi="21911"/><bf us="11916" ue="11916" gi="21916"/><bf us="11943" ue="11943" gi="21930"/><bf us="11946" ue="11946" gi="21933"/><bf us="11950" ue="11950" gi="21936"/><bf us="11955" ue="11955" gi="21938"/><bf us="11958" ue="11959" gi="21939"/><bf us="11963" ue="11963" gi="21944"/><bf us="11978" ue="11978" gi="21954"/><bf us="12272" ue="12283" gi="689"/><bf us="12288" ue="12291" gi="450"/><bf us="12293" ue="12293" gi="454"/><bf us="12294" ue="12294" gi="977"/><bf us="12295" ue="12295" gi="21983"/><bf us="12296" ue="12305" gi="455"/><bf us="12306" ue="12306" gi="881"/><bf us="12307" ue="12311" gi="465"/><bf us="12317" ue="12318" gi="882"/><bf us="12321" ue="12329" gi="884"/><bf us="12353" ue="12435" gi="470"/><bf us="12443" ue="12444" gi="973"/><bf us="12445" ue="12446" gi="978"/><bf us="12449" ue="12534" gi="553"/><bf us="12540" ue="12540" gi="972"/><bf us="12541" ue="12542" gi="975"/><bf us="12!
 549" ue="12585" gi="639"/><bf us="12832" ue="12841" gi="676"/><bf us="12849" ue="12849" gi="970"/><bf us="12963" ue="12963" gi="893"/><bf us="13198" ue="13199" gi="894"/><bf us="13212" ue="13214" gi="896"/><bf us="13217" ue="13217" gi="899"/><bf us="13252" ue="13252" gi="900"/><bf us="13262" ue="13262" gi="901"/><bf us="13265" ue="13266" gi="902"/><bf us="13269" ue="13269" gi="904"/><bf us="13383" ue="13383" gi="21909"/><bf us="13427" ue="13427" gi="21908"/><bf us="13726" ue="13726" gi="21913"/><bf us="13838" ue="13838" gi="21915"/><bf us="13850" ue="13850" gi="21914"/><bf us="14616" ue="14616" gi="21919"/><bf us="14702" ue="14702" gi="21918"/><bf us="14799" ue="14799" gi="21921"/><bf us="14800" ue="14800" gi="21924"/><bf us="14815" ue="14815" gi="21922"/><bf us="14963" ue="14963" gi="21923"/><bf us="15182" ue="15182" gi="21927"/><bf us="15470" ue="15470" gi="21928"/><bf us="15584" ue="15584" gi="21929"/><bf us="16470" ue="16470" gi="21934"/><bf us="16735" ue="16735" gi="21!
 935"/><bf us="17207" ue="17207" gi="21937"/><bf us="17324" ue="17324" 
gi="21943"/><bf us="17329" ue="17329" gi="21942"/><bf us="17373" ue="17373" gi="21945"/><bf us="17622" ue="17622" gi="21946"/><bf us="17996" ue="17996" gi="21948"/><bf us="18017" ue="18017" gi="21947"/><bf us="18211" ue="18211" gi="21950"/><bf us="18217" ue="18217" gi="21951"/><bf us="18300" ue="18300" gi="21952"/><bf us="18317" ue="18317" gi="21953"/><bf us="18759" ue="18759" gi="21955"/><bf us="18810" ue="18810" gi="21956"/><bf us="18813" ue="18813" gi="21957"/><bf us="18818" ue="18819" gi="21958"/><bf us="18821" ue="18822" gi="21960"/><bf us="18843" ue="18843" gi="21963"/><bf us="18847" ue="18847" gi="21962"/><bf us="18870" ue="18870" gi="21965"/><bf us="18871" ue="18871" gi="21964"/><bf us="19575" ue="19575" gi="21972"/><bf us="19615" ue="19615" gi="21969"/><bf us="19617" ue="19617" gi="21971"/><bf us="19618" ue="19618" gi="21973"/><bf us="19619" ue="19619" gi="21968"/><bf us="19629" ue="19629" gi="21970"/><bf us="19731" ue="19737" gi="21974"/><bf us="19886" ue="19886" g!
 i="21981"/><bf us="19968" ue="40869" gi="980"/><bf us="59335" ue="59336" gi="686"/><bf us="59367" ue="59379" gi="688"/><bf us="59413" ue="59492" gi="21903"/><bf us="63788" ue="63788" gi="21882"/><bf us="63865" ue="63865" gi="21883"/><bf us="63893" ue="63893" gi="21884"/><bf us="63975" ue="63975" gi="21885"/><bf us="63985" ue="63985" gi="21886"/><bf us="64012" ue="64015" gi="21887"/><bf us="64017" ue="64017" gi="21891"/><bf us="64019" ue="64020" gi="21892"/><bf us="64024" ue="64024" gi="21894"/><bf us="64031" ue="64033" gi="21895"/><bf us="64035" ue="64036" gi="21898"/><bf us="64039" ue="64041" gi="21900"/><bf us="65072" ue="65073" gi="905"/><bf us="65075" ue="65092" gi="907"/><bf us="65097" ue="65106" gi="925"/><bf us="65108" ue="65111" gi="935"/><bf us="65113" ue="65126" gi="939"/><bf us="65128" ue="65131" gi="953"/><bf us="65281" ue="65374" gi="701"/><bf us="65504" ue="65505" gi="795"/><bf us="65506" ue="65506" gi="967"/><bf us="65507" ue="65507" gi="797"/><bf us="65508" !
 ue="65508" gi="968"/><bf us="65509" ue="65509" gi="798"/><bf us="65535
" ue="65535" gi="0"/></bfranges><cid-widths start-index="0"><wx w="1000"/><wx w="0"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="!
 500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/></cid-widths></multibyte-extras></font-metrics>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/fop/simsun.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/fop/simsun.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/fop/simsun.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<font-metrics type="TYPE0"><font-name>SimSun</font-name><embed/><cap-height>0</cap-height><x-height>0</x-height><ascender>859</ascender><descender>-140</descender><bbox><left>0</left><bottom>-140</bottom><right>996</right><top>855</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><ttc-name>SimSun</ttc-name><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf us="32" ue="126" gi="3"/><bf us="127" ue="127" gi="2"/><bf us="160" ue="163" gi="22021"/><bf us="164" ue="164" gi="98"/><bf us="165" ue="166" gi="22025"/><bf us="167" ue="168" gi="99"/><bf us="169" ue="175" gi="22027"/><bf us="176" ue="177" gi="101"/><bf us="178" ue="182" gi="22034"/><bf us="183" ue="183" gi="103"/><bf us="184" ue="214" gi="22039"/><bf us="215" ue="215" gi="104"/><bf us="216" ue="223" gi="22070"/><bf us="224" ue="225" gi="105"/><bf us="226" ue="231" gi="22078"/><bf us="232" ue="234" gi="107"/><bf us="235" ue="235"!
  gi="22084"/><bf us="236" ue="237" gi="110"/><bf us="238" ue="241" gi="22085"/><bf us="242" ue="243" gi="112"/><bf us="244" ue="246" gi="22089"/><bf us="247" ue="247" gi="114"/><bf us="248" ue="248" gi="22092"/><bf us="249" ue="250" gi="115"/><bf us="251" ue="251" gi="22093"/><bf us="252" ue="252" gi="117"/><bf us="253" ue="255" gi="22094"/><bf us="257" ue="257" gi="118"/><bf us="275" ue="275" gi="119"/><bf us="283" ue="283" gi="120"/><bf us="299" ue="299" gi="121"/><bf us="324" ue="324" gi="122"/><bf us="328" ue="328" gi="123"/><bf us="333" ue="333" gi="124"/><bf us="338" ue="339" gi="22097"/><bf us="352" ue="353" gi="22099"/><bf us="363" ue="363" gi="125"/><bf us="376" ue="376" gi="22101"/><bf us="402" ue="402" gi="22102"/><bf us="462" ue="462" gi="126"/><bf us="464" ue="464" gi="127"/><bf us="466" ue="466" gi="128"/><bf us="468" ue="468" gi="129"/><bf us="470" ue="470" gi="130"/><bf us="472" ue="472" gi="131"/><bf us="474" ue="474" gi="132"/><bf us="476" ue="476" gi="133!
 "/><bf us="505" ue="505" gi="687"/><bf us="593" ue="593" gi="134"/><bf
 us="609" ue="609" gi="135"/><bf us="710" ue="710" gi="22103"/><bf us="711" ue="711" gi="136"/><bf us="713" ue="713" gi="137"/><bf us="714" ue="715" gi="799"/><bf us="729" ue="729" gi="801"/><bf us="732" ue="732" gi="22104"/><bf us="913" ue="929" gi="138"/><bf us="931" ue="937" gi="155"/><bf us="945" ue="961" gi="162"/><bf us="963" ue="969" gi="179"/><bf us="1025" ue="1025" gi="186"/><bf us="1040" ue="1103" gi="187"/><bf us="1105" ue="1105" gi="251"/><bf us="8208" ue="8208" gi="971"/><bf us="8211" ue="8211" gi="802"/><bf us="8212" ue="8212" gi="252"/><bf us="8213" ue="8213" gi="803"/><bf us="8214" ue="8214" gi="253"/><bf us="8216" ue="8217" gi="254"/><bf us="8218" ue="8218" gi="22105"/><bf us="8220" ue="8221" gi="256"/><bf us="8222" ue="8222" gi="22106"/><bf us="8224" ue="8226" gi="22107"/><bf us="8229" ue="8229" gi="804"/><bf us="8230" ue="8230" gi="258"/><bf us="8240" ue="8240" gi="259"/><bf us="8242" ue="8243" gi="260"/><bf us="8245" ue="8245" gi="805"/><bf us="8249" ue="!
 8250" gi="22110"/><bf us="8251" ue="8251" gi="262"/><bf us="8364" ue="8364" gi="22112"/><bf us="8451" ue="8451" gi="263"/><bf us="8453" ue="8453" gi="806"/><bf us="8457" ue="8457" gi="807"/><bf us="8470" ue="8470" gi="264"/><bf us="8481" ue="8481" gi="969"/><bf us="8482" ue="8482" gi="22113"/><bf us="8544" ue="8555" gi="265"/><bf us="8560" ue="8569" gi="957"/><bf us="8592" ue="8595" gi="277"/><bf us="8598" ue="8601" gi="808"/><bf us="8712" ue="8712" gi="281"/><bf us="8719" ue="8719" gi="282"/><bf us="8721" ue="8721" gi="283"/><bf us="8725" ue="8725" gi="812"/><bf us="8730" ue="8730" gi="284"/><bf us="8733" ue="8734" gi="285"/><bf us="8735" ue="8735" gi="813"/><bf us="8736" ue="8736" gi="287"/><bf us="8739" ue="8739" gi="814"/><bf us="8741" ue="8741" gi="288"/><bf us="8743" ue="8747" gi="289"/><bf us="8750" ue="8750" gi="294"/><bf us="8756" ue="8759" gi="295"/><bf us="8765" ue="8765" gi="299"/><bf us="8776" ue="8776" gi="300"/><bf us="8780" ue="8780" gi="301"/><bf us="8786" !
 ue="8786" gi="815"/><bf us="8800" ue="8801" gi="302"/><bf us="8804" ue
="8805" gi="304"/><bf us="8806" ue="8807" gi="816"/><bf us="8814" ue="8815" gi="306"/><bf us="8853" ue="8853" gi="880"/><bf us="8857" ue="8857" gi="308"/><bf us="8869" ue="8869" gi="309"/><bf us="8895" ue="8895" gi="818"/><bf us="8978" ue="8978" gi="310"/><bf us="9312" ue="9321" gi="311"/><bf us="9332" ue="9371" gi="321"/><bf us="9472" ue="9547" gi="361"/><bf us="9552" ue="9587" gi="819"/><bf us="9601" ue="9615" gi="855"/><bf us="9619" ue="9621" gi="870"/><bf us="9632" ue="9633" gi="437"/><bf us="9650" ue="9651" gi="439"/><bf us="9660" ue="9661" gi="873"/><bf us="9670" ue="9671" gi="441"/><bf us="9675" ue="9675" gi="443"/><bf us="9678" ue="9679" gi="444"/><bf us="9698" ue="9701" gi="875"/><bf us="9733" ue="9734" gi="446"/><bf us="9737" ue="9737" gi="879"/><bf us="9792" ue="9792" gi="448"/><bf us="9794" ue="9794" gi="449"/><bf us="11905" ue="11905" gi="21903"/><bf us="11908" ue="11908" gi="21907"/><bf us="11912" ue="11912" gi="21910"/><bf us="11915" ue="11915" gi="21911"/><bf!
  us="11916" ue="11916" gi="21916"/><bf us="11943" ue="11943" gi="21930"/><bf us="11946" ue="11946" gi="21933"/><bf us="11950" ue="11950" gi="21936"/><bf us="11955" ue="11955" gi="21938"/><bf us="11958" ue="11959" gi="21939"/><bf us="11963" ue="11963" gi="21944"/><bf us="11978" ue="11978" gi="21954"/><bf us="12272" ue="12283" gi="689"/><bf us="12288" ue="12291" gi="450"/><bf us="12293" ue="12293" gi="454"/><bf us="12294" ue="12294" gi="977"/><bf us="12295" ue="12295" gi="21983"/><bf us="12296" ue="12305" gi="455"/><bf us="12306" ue="12306" gi="881"/><bf us="12307" ue="12311" gi="465"/><bf us="12317" ue="12318" gi="882"/><bf us="12321" ue="12329" gi="884"/><bf us="12353" ue="12435" gi="470"/><bf us="12443" ue="12444" gi="973"/><bf us="12445" ue="12446" gi="978"/><bf us="12449" ue="12534" gi="553"/><bf us="12540" ue="12540" gi="972"/><bf us="12541" ue="12542" gi="975"/><bf us="12549" ue="12585" gi="639"/><bf us="12832" ue="12841" gi="676"/><bf us="12849" ue="12849" gi="970"/><!
 bf us="12963" ue="12963" gi="893"/><bf us="13198" ue="13199" gi="894"/
><bf us="13212" ue="13214" gi="896"/><bf us="13217" ue="13217" gi="899"/><bf us="13252" ue="13252" gi="900"/><bf us="13262" ue="13262" gi="901"/><bf us="13265" ue="13266" gi="902"/><bf us="13269" ue="13269" gi="904"/><bf us="13383" ue="13383" gi="21909"/><bf us="13427" ue="13427" gi="21908"/><bf us="13726" ue="13726" gi="21913"/><bf us="13838" ue="13838" gi="21915"/><bf us="13850" ue="13850" gi="21914"/><bf us="14616" ue="14616" gi="21919"/><bf us="14702" ue="14702" gi="21918"/><bf us="14799" ue="14799" gi="21921"/><bf us="14800" ue="14800" gi="21924"/><bf us="14815" ue="14815" gi="21922"/><bf us="14963" ue="14963" gi="21923"/><bf us="15182" ue="15182" gi="21927"/><bf us="15470" ue="15470" gi="21928"/><bf us="15584" ue="15584" gi="21929"/><bf us="16470" ue="16470" gi="21934"/><bf us="16735" ue="16735" gi="21935"/><bf us="17207" ue="17207" gi="21937"/><bf us="17324" ue="17324" gi="21943"/><bf us="17329" ue="17329" gi="21942"/><bf us="17373" ue="17373" gi="21945"/><bf us="1762!
 2" ue="17622" gi="21946"/><bf us="17996" ue="17996" gi="21948"/><bf us="18017" ue="18017" gi="21947"/><bf us="18211" ue="18211" gi="21950"/><bf us="18217" ue="18217" gi="21951"/><bf us="18300" ue="18300" gi="21952"/><bf us="18317" ue="18317" gi="21953"/><bf us="18759" ue="18759" gi="21955"/><bf us="18810" ue="18810" gi="21956"/><bf us="18813" ue="18813" gi="21957"/><bf us="18818" ue="18819" gi="21958"/><bf us="18821" ue="18822" gi="21960"/><bf us="18843" ue="18843" gi="21963"/><bf us="18847" ue="18847" gi="21962"/><bf us="18870" ue="18870" gi="21965"/><bf us="18871" ue="18871" gi="21964"/><bf us="19575" ue="19575" gi="21972"/><bf us="19615" ue="19615" gi="21969"/><bf us="19617" ue="19617" gi="21971"/><bf us="19618" ue="19618" gi="21973"/><bf us="19619" ue="19619" gi="21968"/><bf us="19629" ue="19629" gi="21970"/><bf us="19731" ue="19737" gi="21974"/><bf us="19886" ue="19886" gi="21981"/><bf us="19968" ue="40869" gi="980"/><bf us="59335" ue="59336" gi="686"/><bf us="59367" u!
 e="59379" gi="688"/><bf us="59413" ue="59492" gi="21903"/><bf us="6378
8" ue="63788" gi="21882"/><bf us="63865" ue="63865" gi="21883"/><bf us="63893" ue="63893" gi="21884"/><bf us="63975" ue="63975" gi="21885"/><bf us="63985" ue="63985" gi="21886"/><bf us="64012" ue="64015" gi="21887"/><bf us="64017" ue="64017" gi="21891"/><bf us="64019" ue="64020" gi="21892"/><bf us="64024" ue="64024" gi="21894"/><bf us="64031" ue="64033" gi="21895"/><bf us="64035" ue="64036" gi="21898"/><bf us="64039" ue="64041" gi="21900"/><bf us="65072" ue="65073" gi="905"/><bf us="65075" ue="65092" gi="907"/><bf us="65097" ue="65106" gi="925"/><bf us="65108" ue="65111" gi="935"/><bf us="65113" ue="65126" gi="939"/><bf us="65128" ue="65131" gi="953"/><bf us="65281" ue="65374" gi="701"/><bf us="65504" ue="65505" gi="795"/><bf us="65506" ue="65506" gi="967"/><bf us="65507" ue="65507" gi="797"/><bf us="65508" ue="65508" gi="968"/><bf us="65509" ue="65509" gi="798"/><bf us="65535" ue="65535" gi="0"/></bfranges><cid-widths start-index="0"><wx w="1000"/><wx w="0"/><wx w="500"/><w!
 x w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><w!
 x w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="
500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w
x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w
="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1!
 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1
000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000!
 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000
"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>!
 <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>
<wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx!
  w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=!
 "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=
"1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10!
 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10
00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"!
 /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"
/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><!
 wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><
wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx !
 w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx 
w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="!
 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="
1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w!
 x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100!
 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100
0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w!
 ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/!
 ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/
><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/!
 ><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/></cid-widths></multibyte-extras></font-metrics>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/fop/userconfig.xml
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/fop/userconfig.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/fop/userconfig.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,114 @@
+<!--<!DOCTYPE configuration SYSTEM "config.dtd">-->
+<!-- 
+     this file contains templates which allow an user easy 
+     configuration of Fop. Actually normally you don't need this configuration 
+     file, but if you need to change configuration, you should
+     always use this file and *not* config.xml. 
+     Usage: java org.apache.fop.apps.Fop -c userconfig.xml -fo fo-file -pdf pdf-file
+-->
+
+
+<configuration>
+
+<!--  
+baseDir: normally the base directory is the directory where the fo file is 
+         located. if you want to specify your own, uncomment this entry.
+         This value can also be a URL. Actually, the value is converted to 
+         a URL.
+-->
+<!-- 
+  <entry>
+    <key>baseDir</key>
+    <value></value>
+  </entry>
+-->
+
+<!--  
+fontBaseDir: Similar to baseDir, except that this value is used for fonts. If
+         it isn't specified, the value from baseDir is used.
+-->
+<!-- 
+  <entry>
+    <key>fontBaseDir</key>
+    <value></value>
+  </entry>
+-->
+
+<!--
+************************************************************************
+                        HYPHENATION 
+************************************************************************
+-->
+  
+<!--
+   hyphenation directory 
+   if you want to specify your own directory with hyphenation pattern
+   then uncomment the next entry and add the directory name
+-->
+
+<!--
+  <entry>
+    <key>hyphenation-dir</key>
+    <value>/java/xml-fop/hyph</value>
+  </entry>
+-->
+
+<!--
+************************************************************************
+  Add fonts here
+************************************************************************
+-->
+
+<fonts>
+ <!-- example -->
+ <!--
+ <font metrics-file="arial.xml" kerning="yes" embed-file="arial.ttf">
+    <font-triplet name="Arial" style="normal" weight="normal"/>
+    <font-triplet name="ArialMT" style="normal" weight="normal"/>
+ </font>
+ <font metrics-file="arialb.xml" kerning="yes" embed-file="arialb.ttf">
+    <font-triplet name="Arial" style="normal" weight="bold"/>
+    <font-triplet name="ArialMT" style="normal" weight="bold"/>
+ </font>
+ <font metrics-file="ariali.xml" kerning="yes" embed-file="ariali.ttf">
+    <font-triplet name="Arial" style="italic" weight="normal"/>
+    <font-triplet name="ArialMT" style="italic" weight="normal"/>
+ </font>
+ <font metrics-file="arialbi.xml" kerning="yes" embed-file="arialbi.ttf">
+    <font-triplet name="Arial" style="italic" weight="bold"/>
+    <font-triplet name="ArialMT" style="italic" weight="bold"/>
+ </font>
+ -->
+ <!-- Example Japanese fonts
+ <font metrics-file="msgothic.xml" embed-file="D:\winnt\font\msgothic.ttc" kerning="yes">
+    <font-triplet name="Gothic" style="normal" weight="normal"/>
+    <font-triplet name="Gothic" style="normal" weight="bold"/>
+    <font-triplet name="Gothic" style="italic" weight="normal"/>
+    <font-triplet name="Gothic" style="italic" weight="bold"/>
+ </font>
+ <font metrics-file="msmincho.xml" embed-file="Cyberbit.ttf" kerning="yes">
+    <font-triplet name="Mincho" style="normal" weight="normal"/>
+    <font-triplet name="Mincho" style="normal" weight="bold"/>
+    <font-triplet name="Mincho" style="italic" weight="normal"/>
+    <font-triplet name="Mincho" style="italic" weight="bold"/>
+   </font>
+  -->
+ <font metrics-file="simhei.xml" embed-file="simhei.ttf" kerning="yes">
+	<font-triplet name="simhei" style="normal" weight="normal"/> 
+	<font-triplet name="simhei" style="normal" weight="bold"/> 
+	<font-triplet name="simhei" style="italic" weight="normal"/> 
+	<font-triplet name="simhei" style="italic" weight="bold"/> 
+ </font>
+ <font metrics-file="simsun.xml" embed-file="simsun.ttc" kerning="yes">
+	<font-triplet name="simsun" style="normal" weight="normal"/> 
+	<font-triplet name="simsun" style="normal" weight="bold"/> 
+	<font-triplet name="simsun" style="italic" weight="normal"/> 
+	<font-triplet name="simsun" style="italic" weight="bold"/> 
+ </font>
+</fonts>
+
+
+</configuration>
+
+
+

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/fopdf.xsl
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/fopdf.xsl	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/fopdf.xsl	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,509 @@
+<?xml version="1.0"?>
+
+<!--
+
+    This is the XSL FO configuration file for the Hibernate
+    Reference Documentation. It defines a custom titlepage and
+    the parameters for the A4 sized PDF printable output.
+
+    It took me days to figure out this stuff and fix most of
+    the obvious bugs in the DocBook XSL distribution. Some of
+    the workarounds might not be appropriate with a newer version
+    of DocBook XSL. This file is released as part of Hibernate,
+    hence LGPL licensed.
+
+    christian at hibernate.org
+
+-->
+
+<!DOCTYPE xsl:stylesheet [
+    <!ENTITY db_xsl_path        "../../support/docbook-xsl/">
+]>
+
+<xsl:stylesheet
+    version="1.0"
+    xmlns="http://www.w3.org/TR/xhtml1/transitional"
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:fo="http://www.w3.org/1999/XSL/Format"
+    exclude-result-prefixes="#default">
+
+    <xsl:import href="&db_xsl_path;/fo/docbook.xsl"/>
+
+    <!--###################################################
+                       Custom Title Page
+        ################################################### -->
+
+    <xsl:template name="book.titlepage.recto">
+        <fo:block>
+            <fo:table table-layout="fixed" width="175mm">
+                <fo:table-column column-width="175mm"/>
+                <fo:table-body>
+                    <fo:table-row>
+                        <fo:table-cell text-align="center">
+                            <fo:block>
+                                <fo:external-graphic src="file:images/hibernate_logo_a.png"/>
+                            </fo:block>
+                            <fo:block font-family="Helvetica" font-size="22pt" padding-before="10mm">
+                                <xsl:value-of select="bookinfo/subtitle"/>
+                            </fo:block>
+                            <fo:block font-family="Helvetica" font-size="12pt" padding="10mm">
+                                Version:
+                                <xsl:value-of select="bookinfo/releaseinfo"/>
+                            </fo:block>
+                        </fo:table-cell>
+                    </fo:table-row>
+                </fo:table-body>
+            </fo:table>
+        </fo:block>
+    </xsl:template>
+
+    <!-- Prevent blank pages in output -->
+    <xsl:template name="book.titlepage.before.verso">
+    </xsl:template>
+    <xsl:template name="book.titlepage.verso">
+    </xsl:template>
+    <xsl:template name="book.titlepage.separator">
+    </xsl:template>
+
+    <!--###################################################
+                          Header
+        ################################################### -->
+
+    <!-- More space in the center header for long text -->
+    <xsl:attribute-set name="header.content.properties">
+        <xsl:attribute name="font-family">
+            <xsl:value-of select="$body.font.family"/>
+        </xsl:attribute>
+        <xsl:attribute name="margin-left">-5em</xsl:attribute>
+        <xsl:attribute name="margin-right">-5em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!--###################################################
+                          Custom Footer
+        ################################################### -->
+
+    <!-- This footer prints the Hibernate version number on the left side -->
+    <xsl:template name="footer.content">
+        <xsl:param name="pageclass" select="''"/>
+        <xsl:param name="sequence" select="''"/>
+        <xsl:param name="position" select="''"/>
+        <xsl:param name="gentext-key" select="''"/>
+
+        <xsl:variable name="Version">
+            <xsl:choose>
+                <xsl:when test="//releaseinfo">
+                    <xsl:text>Hibernate </xsl:text>
+                    <xsl:value-of select="//releaseinfo"/>
+                </xsl:when>
+                <xsl:otherwise>
+                    <!-- nop -->
+                </xsl:otherwise>
+            </xsl:choose>
+        </xsl:variable>
+
+        <xsl:choose>
+            <xsl:when test="$sequence='blank'">
+                <xsl:choose>
+                    <xsl:when test="$double.sided != 0 and $position = 'left'">
+                        <xsl:value-of select="$Version"/>
+                    </xsl:when>
+
+                    <xsl:when test="$double.sided = 0 and $position = 'center'">
+                        <!-- nop -->
+                    </xsl:when>
+
+                    <xsl:otherwise>
+                        <fo:page-number/>
+                    </xsl:otherwise>
+                </xsl:choose>
+            </xsl:when>
+
+            <xsl:when test="$pageclass='titlepage'">
+                <!-- nop: other titlepage sequences have no footer -->
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='left'">
+                <fo:page-number/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='right'">
+                <fo:page-number/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided = 0 and $position='right'">
+                <fo:page-number/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='left'">
+                <xsl:value-of select="$Version"/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='right'">
+                <xsl:value-of select="$Version"/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided = 0 and $position='left'">
+                <xsl:value-of select="$Version"/>
+            </xsl:when>
+
+            <xsl:otherwise>
+                <!-- nop -->
+            </xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+    <!--###################################################
+                       Custom Toc Line
+        ################################################### -->
+    
+    <!-- Improve the TOC. -->
+    <xsl:template name="toc.line">
+        <xsl:variable name="id">
+            <xsl:call-template name="object.id"/>
+        </xsl:variable>
+
+        <xsl:variable name="label">
+            <xsl:apply-templates select="." mode="label.markup"/>
+        </xsl:variable>
+
+        <fo:block text-align-last="justify"
+            end-indent="{$toc.indent.width}pt"
+            last-line-end-indent="-{$toc.indent.width}pt">
+            <fo:inline keep-with-next.within-line="always">
+                <fo:basic-link internal-destination="{$id}">
+
+                    <!-- Chapter titles should be bold. -->
+                    <xsl:choose>
+                        <xsl:when test="local-name(.) = 'chapter'">
+                            <xsl:attribute name="font-weight">bold</xsl:attribute>
+                        </xsl:when>
+                    </xsl:choose>
+
+                    <xsl:if test="$label != ''">
+                        <xsl:copy-of select="$label"/>
+                        <xsl:value-of select="$autotoc.label.separator"/>
+                    </xsl:if>
+                    <xsl:apply-templates select="." mode="titleabbrev.markup"/>
+                </fo:basic-link>
+            </fo:inline>
+            <fo:inline keep-together.within-line="always">
+                <xsl:text> </xsl:text>
+                <fo:leader leader-pattern="dots"
+                    leader-pattern-width="3pt"
+                    leader-alignment="reference-area"
+                    keep-with-next.within-line="always"/>
+                <xsl:text> </xsl:text>
+                <fo:basic-link internal-destination="{$id}">
+                    <fo:page-number-citation ref-id="{$id}"/>
+                </fo:basic-link>
+            </fo:inline>
+        </fo:block>
+    </xsl:template>
+
+    <!--###################################################
+                          Extensions
+        ################################################### -->
+
+    <!-- These extensions are required for table printing and other stuff -->
+    <xsl:param name="use.extensions">1</xsl:param>
+    <xsl:param name="tablecolumns.extension">0</xsl:param>
+    <!-- FOP provide only PDF Bookmarks at the moment -->
+    <xsl:param name="fop.extensions">1</xsl:param>
+
+    <!--###################################################
+                          Table Of Contents
+        ################################################### -->
+
+    <!-- Generate the TOCs for named components only -->
+    <xsl:param name="generate.toc">
+        book   toc
+    </xsl:param>
+    
+    <!-- Show only Sections up to level 3 in the TOCs -->
+    <xsl:param name="toc.section.depth">3</xsl:param>
+    
+    <!-- Dot and Whitespace as separator in TOC between Label and Title-->
+    <xsl:param name="autotoc.label.separator" select="'.  '"/>
+
+
+    <!--###################################################
+                       Paper & Page Size
+        ################################################### -->
+    
+    <!-- Paper type, no headers on blank pages, no double sided printing -->
+    <xsl:param name="paper.type" select="'A4'"/>
+    <xsl:param name="double.sided">0</xsl:param>
+    <xsl:param name="headers.on.blank.pages">0</xsl:param>
+    <xsl:param name="footers.on.blank.pages">0</xsl:param>
+
+    <!-- Space between paper border and content (chaotic stuff, don't touch) -->
+    <xsl:param name="page.margin.top">5mm</xsl:param>
+    <xsl:param name="region.before.extent">10mm</xsl:param>
+    <xsl:param name="body.margin.top">10mm</xsl:param>
+
+    <xsl:param name="body.margin.bottom">15mm</xsl:param>
+    <xsl:param name="region.after.extent">10mm</xsl:param>
+    <xsl:param name="page.margin.bottom">0mm</xsl:param>
+
+    <xsl:param name="page.margin.outer">18mm</xsl:param>
+    <xsl:param name="page.margin.inner">18mm</xsl:param>
+
+    <!-- No intendation of Titles -->
+    <xsl:param name="title.margin.left">0pc</xsl:param>
+
+    <!--###################################################
+                       Fonts & Styles
+        ################################################### -->
+
+    <!-- Default Font size -->
+    <xsl:param name="body.font.master">11</xsl:param>
+
+    <!-- Line height in body text -->
+    <xsl:param name="line-height">1.4</xsl:param>
+
+    <!-- Monospaced fonts are smaller than regular text -->
+    <xsl:attribute-set name="monospace.properties">
+        <xsl:attribute name="font-family">
+            <xsl:value-of select="$monospace.font.family"/>
+        </xsl:attribute>
+        <xsl:attribute name="font-size">0.8em</xsl:attribute>
+    </xsl:attribute-set>
+
+
+    <!--###################################################
+                       Tables
+        ################################################### -->
+
+    <!-- The table width should be adapted to the paper size -->
+    <xsl:param name="default.table.width">17.4cm</xsl:param>
+
+    <!-- Some padding inside tables -->
+    <xsl:attribute-set name="table.cell.padding">
+        <xsl:attribute name="padding-left">4pt</xsl:attribute>
+        <xsl:attribute name="padding-right">4pt</xsl:attribute>
+        <xsl:attribute name="padding-top">4pt</xsl:attribute>
+        <xsl:attribute name="padding-bottom">4pt</xsl:attribute>
+    </xsl:attribute-set>
+    
+    <!-- Only hairlines as frame and cell borders in tables -->
+    <xsl:param name="table.frame.border.thickness">0.1pt</xsl:param>
+    <xsl:param name="table.cell.border.thickness">0.1pt</xsl:param>
+
+    <!--###################################################
+                             Labels
+        ################################################### -->
+
+    <!-- Label Chapters and Sections (numbering) -->
+    <xsl:param name="chapter.autolabel">1</xsl:param>
+    <xsl:param name="section.autolabel" select="1"/>
+    <xsl:param name="section.label.includes.component.label" select="1"/>
+
+    <!--###################################################
+                             Titles
+        ################################################### -->
+    
+    <!-- Chapter title size -->
+    <xsl:attribute-set name="chapter.titlepage.recto.style">
+        <xsl:attribute name="text-align">left</xsl:attribute>
+        <xsl:attribute name="font-weight">bold</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.8"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+    </xsl:attribute-set>
+
+    <!-- Why is the font-size for chapters hardcoded in the XSL FO templates? 
+        Let's remove it, so this sucker can use our attribute-set only... -->
+    <xsl:template match="title" mode="chapter.titlepage.recto.auto.mode">
+        <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
+            xsl:use-attribute-sets="chapter.titlepage.recto.style">
+            <xsl:call-template name="component.title">
+                <xsl:with-param name="node" select="ancestor-or-self::chapter[1]"/>
+            </xsl:call-template>
+        </fo:block>
+    </xsl:template>
+    
+    <!-- Sections 1, 2 and 3 titles have a small bump factor and padding -->
+    <xsl:attribute-set name="section.title.level1.properties">
+        <xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.5"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+    <xsl:attribute-set name="section.title.level2.properties">
+        <xsl:attribute name="space-before.optimum">0.6em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.6em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.6em</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.25"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+    <xsl:attribute-set name="section.title.level3.properties">
+        <xsl:attribute name="space-before.optimum">0.4em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.4em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.4em</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.0"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!-- Titles of formal objects (tables, examples, ...) -->
+    <xsl:attribute-set name="formal.title.properties" use-attribute-sets="normal.para.spacing">
+        <xsl:attribute name="font-weight">bold</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="hyphenate">false</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.4em</xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.6em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.8em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!--###################################################
+                          Programlistings
+        ################################################### -->
+    
+    <!-- Verbatim text formatting (programlistings) -->
+    <xsl:attribute-set name="verbatim.properties">
+        <xsl:attribute name="space-before.minimum">1em</xsl:attribute>
+        <xsl:attribute name="space-before.optimum">1em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+        <xsl:attribute name="border-color">#444444</xsl:attribute>
+        <xsl:attribute name="border-style">solid</xsl:attribute>
+        <xsl:attribute name="border-width">0.1pt</xsl:attribute>
+        <xsl:attribute name="padding-top">0.5em</xsl:attribute>
+        <xsl:attribute name="padding-left">0.5em</xsl:attribute>
+        <xsl:attribute name="padding-right">0.5em</xsl:attribute>
+        <xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
+        <xsl:attribute name="margin-left">0.5em</xsl:attribute>
+        <xsl:attribute name="margin-right">0.5em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!-- Shade (background) programlistings -->
+    <xsl:param name="shade.verbatim">1</xsl:param>
+    <xsl:attribute-set name="shade.verbatim.style">
+        <xsl:attribute name="background-color">#F0F0F0</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!--###################################################
+                             Callouts
+        ################################################### -->
+
+    <!-- We want to use callouts... -->
+    <xsl:param name="callout.extensions">1</xsl:param>
+
+    <!-- Place callout bullets at this column in programmlisting.-->
+    <xsl:param name="callout.defaultcolumn">90</xsl:param>
+
+    <!--
+        No, don't use crappy graphics for the callout bullets. This setting
+        enables some weird Unicode rendering for some fancy bullet points
+        in callouts. By default, this can only count to 10 and produces
+        strange results if you ever have more than 10 callouts for one
+        programlisting. We will fix that next.
+    -->
+    <xsl:param name="callout.graphics">0</xsl:param>
+
+    <!--
+        Again, fun with DocBook XSL: The callout bullets are rendered in
+        two places: In the programlisting itself and in the list below
+        the listing, with the actual callout text. The rendering in the
+        programlisting is some XSL transformer extension (e.g. a Saxon
+        extension), so we can't change that without messing with the
+        extensions. We only can turn it off by setting this limit to
+        zero, then, a simple bracket style like "(3)" and "(4)" will
+        be used in the programlisting.
+    -->
+    <xsl:param name="callout.unicode.number.limit" select="'0'"></xsl:param>
+
+    <!--
+        The callout bullets in the actual callout list will be rendered
+        with an XSL FO template. The default template is broken: limited to 10
+        nice looking Unicode bullet points and then it doesn't print anything,
+        the fallback doesn't work. We implement our own template, which is not
+        as complicated, more ugly, but works. As always, function is more
+        important than form.
+    -->
+    <xsl:template name="callout-bug">
+        <xsl:param name="conum" select='1'/>
+        <fo:inline
+            color="black"
+            padding-top="0.1em"
+            padding-bottom="0.1em"
+            padding-start="0.2em"
+            padding-end="0.2em"
+            baseline-shift="0.1em"
+            font-family="{$monospace.font.family}"
+            font-weight="bold"
+            font-size="75%">
+            <xsl:text>(</xsl:text>
+            <xsl:value-of select="$conum"/>
+            <xsl:text>)</xsl:text>
+        </fo:inline>
+
+    </xsl:template>
+
+    <!--###################################################
+                              Misc
+        ################################################### -->
+
+    <!-- Correct placement of titles for figures and examples. -->
+    <xsl:param name="formal.title.placement">
+        figure after
+        example before
+        equation before
+        table before
+        procedure before
+    </xsl:param>
+    
+    <!-- Format Variable Lists as Blocks (prevents horizontal overflow). -->
+    <xsl:param name="variablelist.as.blocks">1</xsl:param>
+
+    <!-- The horrible list spacing problems, this is much better. -->
+    <xsl:attribute-set name="list.block.spacing">
+        <xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!-- Newer DocBook XSL apparently thinks that some sections are by
+         default "draft" status, and this idiotic thing is by default
+         also set to "maybe", so it spits out a lot of errors with the
+         latest FOP as the XSL/FO styles have references to some draft
+         watermarks, which you actually don't want in the first place.
+         Turn this crap off. If you have to work with the "status"
+         attribute, don't.
+    -->
+    <xsl:param name="draft.mode" select="'no'"/>
+
+	<!-- Simplified Chinese related Settings -->
+    <xsl:param name="hyphenate">false</xsl:param>
+	<xsl:param name="body.font.family">simsun</xsl:param>
+	<xsl:param name="monospace.font.family">simsun</xsl:param>
+	<xsl:param name="title.font.family">simhei</xsl:param>
+	<xsl:param name="saxon.character.representation" select="native"/>
+	<xsl:param name="callout.unicode" select="1"/>
+	<xsl:param name="callout.unicode.start.character" select="10102"/>
+	<xsl:param name="l10n.gentext.default.language" select="zh-cn"/>
+</xsl:stylesheet>

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/html.css
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/html.css	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/html.css	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,97 @@
+A {
+    color: #003399;
+}
+
+A:active {
+    color: #003399;
+}
+
+A:visited {
+    color: #888888;
+}
+
+P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
+    color: #000000;
+}
+
+TD, TH, SPAN {
+    color: #000000;
+}
+
+BLOCKQUOTE {
+    margin-right: 0px;
+}
+
+
+H1, H2, H3, H4, H5, H6    {
+    color: #000000;
+    font-weight:500;
+    margin-top:10px;
+    padding-top:15px;
+}
+
+TABLE  {
+    border-collapse: collapse;
+    border-spacing:0;
+    border: 1px thin black;
+    empty-cells: hide;
+}
+
+TD  {
+    padding: 4pt;
+}
+
+H1 { font-size: 150%; }
+H2 { font-size: 140%; }
+H3 { font-size: 110%; font-weight: bold; }
+H4 { font-size: 110%; font-weight: bold;}
+H5 { font-size: 100%; font-style: italic; }
+H6 { font-size: 100%; font-style: italic; }
+
+TT {
+font-size: 90%;
+    font-family: "Courier New", Courier, monospace;
+    color: #000000;
+}
+
+PRE {
+font-size: 100%;
+    padding: 5px;
+    border-style: solid;
+    border-width: 1px;
+    border-color: #CCCCCC;
+    background-color: #F4F4F4;
+}
+
+UL, OL, LI {
+    list-style: disc;
+}
+
+HR  {
+    width: 100%;
+    height: 1px;
+    background-color: #CCCCCC;
+    border-width: 0px;
+    padding: 0px;
+    color: #CCCCCC;
+}
+
+.variablelist { 
+    padding-top: 10; 
+    padding-bottom:10; 
+    margin:0;
+}
+
+.itemizedlist, UL { 
+    padding-top: 0; 
+    padding-bottom:0; 
+    margin:0; 
+}
+
+.term { 
+    font-weight:bold;
+}
+
+
+
+    

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/html.xsl
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/html.xsl	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/html.xsl	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+
+<!--
+
+    This is the XSL HTML configuration file for the Hibernate
+    Reference Documentation.
+
+    It took me days to figure out this stuff and fix most of
+    the obvious bugs in the DocBook XSL distribution. Some of
+    the workarounds might not be appropriate with a newer version
+    of DocBook XSL. This file is released as part of Hibernate,
+    hence LGPL licensed.
+
+    christian at hibernate.org
+-->
+
+<!DOCTYPE xsl:stylesheet [
+    <!ENTITY db_xsl_path        "../../support/docbook-xsl/">
+]>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0"
+                xmlns="http://www.w3.org/TR/xhtml1/transitional"
+                exclude-result-prefixes="#default">
+                
+<xsl:import href="&db_xsl_path;/html/docbook.xsl"/>
+
+<!--###################################################
+                     HTML Settings
+    ################################################### -->   
+
+    <xsl:param name="html.stylesheet">../shared/css/html.css</xsl:param>
+
+    <!-- These extensions are required for table printing and other stuff -->
+    <xsl:param name="use.extensions">1</xsl:param>
+    <xsl:param name="tablecolumns.extension">0</xsl:param>
+    <xsl:param name="callout.extensions">1</xsl:param>
+    <xsl:param name="graphicsize.extension">0</xsl:param>
+
+<!--###################################################
+                      Table Of Contents
+    ################################################### -->   
+
+    <!-- Generate the TOCs for named components only -->
+    <xsl:param name="generate.toc">
+        book   toc
+    </xsl:param>
+    
+    <!-- Show only Sections up to level 3 in the TOCs -->
+    <xsl:param name="toc.section.depth">3</xsl:param>
+    
+<!--###################################################
+                         Labels
+    ################################################### -->   
+
+    <!-- Label Chapters and Sections (numbering) -->
+    <xsl:param name="chapter.autolabel">1</xsl:param>
+    <xsl:param name="section.autolabel" select="1"/>
+    <xsl:param name="section.label.includes.component.label" select="1"/>
+
+<!--###################################################
+                         Callouts
+    ################################################### -->
+
+    <!-- Don't use graphics, use a simple number style -->
+    <xsl:param name="callout.graphics">0</xsl:param>
+
+    <!-- Place callout marks at this column in annotated areas -->
+    <xsl:param name="callout.defaultcolumn">90</xsl:param>
+
+<!--###################################################
+                          Misc
+    ################################################### -->   
+
+    <!-- Placement of titles -->
+    <xsl:param name="formal.title.placement">
+        figure after
+        example before
+        equation before
+        table before
+        procedure before
+    </xsl:param>    
+    
+</xsl:stylesheet>

Added: trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/html_chunk.xsl
===================================================================
--- trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/html_chunk.xsl	                        (rev 0)
+++ trunk/Hibernate3/documentation/manual/zh-CN/src/no-idea-what-to-do-with-these-yet/styles/html_chunk.xsl	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+
+<!--
+
+    This is the XSL HTML configuration file for the Hibernate
+    Reference Documentation.
+
+    It took me days to figure out this stuff and fix most of
+    the obvious bugs in the DocBook XSL distribution. Some of
+    the workarounds might not be appropriate with a newer version
+    of DocBook XSL. This file is released as part of Hibernate,
+    hence LGPL licensed.
+
+    christian at hibernate.org
+-->
+
+<!DOCTYPE xsl:stylesheet [
+    <!ENTITY db_xsl_path        "../../support/docbook-xsl/">
+]>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0"
+                xmlns="http://www.w3.org/TR/xhtml1/transitional"
+                exclude-result-prefixes="#default">
+                
+<xsl:import href="&db_xsl_path;/html/chunk.xsl"/>
+
+<!--###################################################
+                     HTML Settings
+    ################################################### -->   
+
+    <xsl:param name="chunk.section.depth">'5'</xsl:param>
+    <xsl:param name="use.id.as.filename">'1'</xsl:param>
+    <xsl:param name="html.stylesheet">../shared/css/html.css</xsl:param>
+
+    <!-- These extensions are required for table printing and other stuff -->
+    <xsl:param name="use.extensions">1</xsl:param>
+    <xsl:param name="tablecolumns.extension">0</xsl:param>
+    <xsl:param name="callout.extensions">1</xsl:param>
+    <xsl:param name="graphicsize.extension">0</xsl:param>
+    
+<!--###################################################
+                      Table Of Contents
+    ################################################### -->   
+
+    <!-- Generate the TOCs for named components only -->
+    <xsl:param name="generate.toc">
+        book   toc
+    </xsl:param>
+    
+    <!-- Show only Sections up to level 3 in the TOCs -->
+    <xsl:param name="toc.section.depth">3</xsl:param>
+
+<!--###################################################
+                         Labels
+    ################################################### -->   
+
+    <!-- Label Chapters and Sections (numbering) -->
+    <xsl:param name="chapter.autolabel">1</xsl:param>
+    <xsl:param name="section.autolabel" select="1"/>
+    <xsl:param name="section.label.includes.component.label" select="1"/>
+                
+<!--###################################################
+                         Callouts
+    ################################################### -->   
+
+    <!-- Don't use graphics, use a simple number style -->
+    <xsl:param name="callout.graphics">0</xsl:param>
+
+    <!-- Place callout marks at this column in annotated areas -->
+    <xsl:param name="callout.defaultcolumn">90</xsl:param>
+
+<!--###################################################
+                          Misc
+    ################################################### -->   
+
+    <!-- Placement of titles -->
+    <xsl:param name="formal.title.placement">
+        figure after
+        example before
+        equation before
+        table before
+        procedure before
+    </xsl:param>    
+    
+</xsl:stylesheet>

Added: trunk/Hibernate3/documentation/pom.xml
===================================================================
--- trunk/Hibernate3/documentation/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>hibernate-documentation</artifactId>
+    <packaging>pom</packaging>
+    <name>Hibernate Documentation Project</name>
+    <description>The grouping project for Hibernate documentation</description>
+
+    <modules>
+        <module>manual</module>
+        <module>tutorial</module>
+    </modules>
+
+</project>

Added: trunk/Hibernate3/documentation/tutorial/pom.xml
===================================================================
--- trunk/Hibernate3/documentation/tutorial/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/tutorial/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.hibernate</groupId>
+    <artifactId>hibernate-tutorial</artifactId>
+    <packaging>jar</packaging>
+    <name>Hibernate Tutorial</name>
+    <description>A tutorial project showcasing Hibernate usage</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-core</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

Added: trunk/Hibernate3/documentation/tutorial/src/main/java/events/Event.hbm.xml
===================================================================
--- trunk/Hibernate3/documentation/tutorial/src/main/java/events/Event.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/tutorial/src/main/java/events/Event.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+
+    <class name="events.Event" table="EVENTS">
+        <id name="id" column="EVENT_ID">
+            <generator class="native"/>
+        </id>
+        <property name="date" type="timestamp" column="EVENT_DATE"/>
+        <property name="title"/>
+
+        <set name="participants" table="PERSON_EVENT" inverse="true">
+            <key column="EVENT_ID"/>
+            <many-to-many column="PERSON_ID" class="events.Person"/>
+        </set>
+
+    </class>
+
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/tutorial/src/main/java/events/Event.java
===================================================================
--- trunk/Hibernate3/documentation/tutorial/src/main/java/events/Event.java	                        (rev 0)
+++ trunk/Hibernate3/documentation/tutorial/src/main/java/events/Event.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+package events;
+
+import java.util.*;
+
+public class Event {
+    private Long id;
+
+    private String title;
+    private Date date;
+
+    public Event() {}
+
+    public Long getId() {
+        return id;
+    }
+
+    private void setId(Long id) {
+        this.id = id;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+    
+
+    private Set participants = new HashSet();
+
+    public Set getParticipants() {
+        return participants;
+    }
+
+    public void setParticipants(Set participants) {
+        this.participants = participants;
+    }
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/documentation/tutorial/src/main/java/events/EventManager.java
===================================================================
--- trunk/Hibernate3/documentation/tutorial/src/main/java/events/EventManager.java	                        (rev 0)
+++ trunk/Hibernate3/documentation/tutorial/src/main/java/events/EventManager.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,136 @@
+package events;
+import org.hibernate.*;
+import org.hibernate.criterion.Expression;
+
+import java.util.*;
+
+import util.HibernateUtil;
+
+public class EventManager {
+
+    public static void main(String[] args) {
+        EventManager mgr = new EventManager();
+
+        if (args[0].equals("store")) {
+            mgr.createAndStoreEvent("My Event", new Date());
+        }
+        else if (args[0].equals("list")) {
+            List events = mgr.listEvents();
+            for (int i = 0; i < events.size(); i++) {
+                Event theEvent = (Event) events.get(i);
+                System.out.println("Event: " + theEvent.getTitle() +
+                                   " Time: " + theEvent.getDate());
+            }
+        }
+        else if (args[0].equals("addpersontoevent")) {
+            Long eventId = mgr.createAndStoreEvent("My Event", new Date());
+            Long personId = mgr.createAndStorePerson("Foo", "Bar");
+            mgr.addPersonToEvent(personId, eventId);
+            System.out.println("Added person " + personId + " to event " + eventId);
+        }
+        else if (args[0].equals("addemailtoperson")) {
+            Long personId = mgr.createAndStorePerson("Foozy", "Beary");
+            mgr.addEmailToPerson(personId, "foo at bar");
+            mgr.addEmailToPerson(personId, "bar at foo");
+            System.out.println("Added two email addresses (value typed objects) to person entity : " + personId);
+        }
+
+        HibernateUtil.getSessionFactory().close();
+    }
+
+    private Long createAndStoreEvent(String title, Date theDate) {
+
+        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+        session.beginTransaction();
+
+        Event theEvent = new Event();
+        theEvent.setTitle(title);
+        theEvent.setDate(theDate);
+
+        session.save(theEvent);
+
+        session.getTransaction().commit();
+
+        return theEvent.getId();
+    }
+
+    private Long createAndStorePerson(String firstname, String lastname) {
+
+        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+        session.beginTransaction();
+
+        Person thePerson = new Person();
+        thePerson.setFirstname(firstname);
+        thePerson.setLastname(lastname);
+
+        session.save(thePerson);
+
+        session.getTransaction().commit();
+
+        return thePerson.getId();
+    }
+
+
+    private List listEvents() {
+
+        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+        session.beginTransaction();
+
+        List result = session.createQuery("from Event").list();
+
+        session.getTransaction().commit();
+
+        return result;
+    }
+
+    private void addPersonToEvent(Long personId, Long eventId) {
+
+        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+        session.beginTransaction();
+
+        Person aPerson = (Person) session
+                .createQuery("select p from Person p left join fetch p.events where p.id = :pid")
+                .setParameter("pid", personId)
+                .uniqueResult(); // Eager fetch the collection so we can use it detached
+
+        Event anEvent = (Event) session.load(Event.class, eventId);
+        // If we want to handle it bidirectional and detached, we also need to load this
+        // collection with an eager outer-join fetch, this time with Criteria and not HQL:
+        /*
+        Event anEvent = (Event) session
+                .createCriteria(Event.class).setFetchMode("participants", FetchMode.JOIN)
+                .add( Expression.eq("id", eventId) )
+                .uniqueResult(); // Eager fetch the colleciton so we can use it detached
+        */
+
+        session.getTransaction().commit();
+
+        // End of first unit of work
+
+        aPerson.getEvents().add(anEvent); // aPerson is detached
+        // or bidirectional safety method, setting both sides: aPerson.addToEvent(anEvent);
+
+        // Begin second unit of work
+
+        Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
+        session2.beginTransaction();
+
+        session2.update(aPerson); // Reattachment of aPerson
+
+        session2.getTransaction().commit();
+    }
+
+    private void addEmailToPerson(Long personId, String emailAddress) {
+
+        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+        session.beginTransaction();
+
+        Person aPerson = (Person) session.load(Person.class, personId);
+
+        // The getEmailAddresses() might trigger a lazy load of the collection
+        aPerson.getEmailAddresses().add(emailAddress);
+
+        session.getTransaction().commit();
+    }
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/documentation/tutorial/src/main/java/events/EventManagerServlet.java
===================================================================
--- trunk/Hibernate3/documentation/tutorial/src/main/java/events/EventManagerServlet.java	                        (rev 0)
+++ trunk/Hibernate3/documentation/tutorial/src/main/java/events/EventManagerServlet.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,101 @@
+package events;
+
+import util.HibernateUtil;
+
+import javax.servlet.http.*;
+import javax.servlet.ServletException;
+import java.io.*;
+import java.util.*;
+import java.text.SimpleDateFormat;
+
+public class EventManagerServlet extends HttpServlet {
+
+    protected void doGet(HttpServletRequest request,
+                         HttpServletResponse response)
+            throws ServletException, IOException {
+
+        SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
+
+        try {
+            // Begin unit of work
+            HibernateUtil.getSessionFactory()
+                    .getCurrentSession().beginTransaction();
+
+            // Write HTML header
+            PrintWriter out = response.getWriter();
+            out.println("<html><head><title>Event Manager</title></head><body>");
+
+            // Handle actions
+            if ( "store".equals(request.getParameter("action")) ) {
+
+                String eventTitle = request.getParameter("eventTitle");
+                String eventDate = request.getParameter("eventDate");
+
+                if ( "".equals(eventTitle) || "".equals(eventDate) ) {
+                    out.println("<b><i>Please enter event title and date.</i></b>");
+                } else {
+                    createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
+                    out.println("<b><i>Added event.</i></b>");
+                }
+            }
+
+            // Print page
+            printEventForm(out);
+            listEvents(out, dateFormatter);
+
+            // Write HTML footer
+            out.println("</body></html>");
+            out.flush();
+            out.close();
+
+            // End unit of work
+            HibernateUtil.getSessionFactory()
+                    .getCurrentSession().getTransaction().commit();
+
+        } catch (Exception ex) {
+            HibernateUtil.getSessionFactory()
+                    .getCurrentSession().getTransaction().rollback();
+            throw new ServletException(ex);
+        }
+    }
+
+    private void printEventForm(PrintWriter out) {
+        out.println("<h2>Add new event:</h2>");
+        out.println("<form>");
+        out.println("Title: <input name='eventTitle' length='50'/><br/>");
+        out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");
+        out.println("<input type='submit' name='action' value='store'/>");
+        out.println("</form>");
+    }
+
+    private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) {
+        List result = HibernateUtil.getSessionFactory()
+                        .getCurrentSession().createCriteria(Event.class).list();
+        if (result.size() > 0) {
+            out.println("<h2>Events in database:</h2>");
+            out.println("<table border='1'>");
+            out.println("<tr>");
+            out.println("<th>Event title</th>");
+            out.println("<th>Event date</th>");
+            out.println("</tr>");
+            for (Iterator it = result.iterator(); it.hasNext();) {
+                Event event = (Event) it.next();
+                out.println("<tr>");
+                out.println("<td>" + event.getTitle() + "</td>");
+                out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
+                out.println("</tr>");
+            }
+            out.println("</table>");
+        }
+    }
+
+    protected void createAndStoreEvent(String title, Date theDate) {
+        Event theEvent = new Event();
+        theEvent.setTitle(title);
+        theEvent.setDate(theDate);
+
+        HibernateUtil.getSessionFactory()
+                        .getCurrentSession().save(theEvent);
+    }
+
+}

Added: trunk/Hibernate3/documentation/tutorial/src/main/java/events/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/documentation/tutorial/src/main/java/events/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/tutorial/src/main/java/events/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+
+    <class name="events.Person" table="PERSON">
+        <id name="id" column="PERSON_ID">
+            <generator class="native"/>
+        </id>
+        <property name="age"/>
+        <property name="firstname"/>
+        <property name="lastname"/>
+
+        <set name="events" table="PERSON_EVENT">
+            <key column="PERSON_ID"/>
+            <many-to-many column="EVENT_ID" class="events.Event"/>
+        </set>
+        
+        <set name="emailAddresses" table="PERSON_EMAIL_ADDR">
+            <key column="PERSON_ID"/>
+            <element type="string" column="EMAIL_ADDR"/>
+        </set>
+
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/documentation/tutorial/src/main/java/events/Person.java
===================================================================
--- trunk/Hibernate3/documentation/tutorial/src/main/java/events/Person.java	                        (rev 0)
+++ trunk/Hibernate3/documentation/tutorial/src/main/java/events/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,80 @@
+package events;
+
+import java.util.*;
+
+public class Person {
+
+    private Long id;
+    private int age;
+    private String firstname;
+    private String lastname;
+
+    public Person() {}
+
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public int getAge() {
+        return age;
+    }
+
+    public void setAge(int age) {
+        this.age = age;
+    }
+
+    public String getFirstname() {
+        return firstname;
+    }
+
+    public void setFirstname(String firstname) {
+        this.firstname = firstname;
+    }
+
+    public String getLastname() {
+        return lastname;
+    }
+
+    public void setLastname(String lastname) {
+        this.lastname = lastname;
+    }
+
+
+    private Set emailAddresses = new HashSet();
+
+    public Set getEmailAddresses() {
+        return emailAddresses;
+    }
+
+    public void setEmailAddresses(Set emailAddresses) {
+        this.emailAddresses = emailAddresses;
+    }
+
+
+    private Set events = new HashSet();
+
+    // Defensive, convenience methods
+    protected Set getEvents() {
+        return events;
+    }
+
+    protected void setEvents(Set events) {
+        this.events = events;
+    }
+
+    public void addToEvent(Event event) {
+        this.getEvents().add(event);
+        event.getParticipants().add(this);
+    }
+
+    public void removeFromEvent(Event event) {
+        this.getEvents().remove(event);
+        event.getParticipants().remove(this);
+    }
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/documentation/tutorial/src/main/java/util/HibernateUtil.java
===================================================================
--- trunk/Hibernate3/documentation/tutorial/src/main/java/util/HibernateUtil.java	                        (rev 0)
+++ trunk/Hibernate3/documentation/tutorial/src/main/java/util/HibernateUtil.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+package util;
+
+import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+    private static final SessionFactory sessionFactory;
+
+    static {
+        try {
+            // Create the SessionFactory from hibernate.cfg.xml
+            sessionFactory = new Configuration().configure().buildSessionFactory();
+        } catch (Throwable ex) {
+            // Make sure you log the exception, as it might be swallowed
+            System.err.println("Initial SessionFactory creation failed." + ex);
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    public static SessionFactory getSessionFactory() {
+        return sessionFactory;
+    }
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/documentation/tutorial/src/main/resources/hibernate.cfg.xml
===================================================================
--- trunk/Hibernate3/documentation/tutorial/src/main/resources/hibernate.cfg.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/tutorial/src/main/resources/hibernate.cfg.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+    <session-factory>
+
+        <!-- Database connection settings -->
+        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
+        <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
+        <property name="connection.username">sa</property>
+        <property name="connection.password"></property>
+
+        <!-- JDBC connection pool (use the built-in) -->
+        <property name="connection.pool_size">1</property>
+
+        <!-- SQL dialect -->
+        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
+
+        <!-- Enable Hibernate's automatic session context management -->
+        <property name="current_session_context_class">thread</property>
+
+        <!-- Disable the second-level cache  -->
+        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
+
+        <!-- Echo all executed SQL to stdout -->
+        <property name="show_sql">true</property>
+
+        <!-- Drop and re-create the database schema on startup -->
+        <property name="hbm2ddl.auto">create</property>
+
+        <mapping resource="events/Event.hbm.xml"/>
+        <mapping resource="events/Person.hbm.xml"/>
+
+    </session-factory>
+
+</hibernate-configuration>
+

Added: trunk/Hibernate3/documentation/tutorial/src/main/resources/log4j.properties
===================================================================
--- trunk/Hibernate3/documentation/tutorial/src/main/resources/log4j.properties	                        (rev 0)
+++ trunk/Hibernate3/documentation/tutorial/src/main/resources/log4j.properties	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+### direct log messages to stdout ###
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
+
+### direct messages to file hibernate.log ###
+#log4j.appender.file=org.apache.log4j.FileAppender
+#log4j.appender.file.File=hibernate.log
+#log4j.appender.file.layout=org.apache.log4j.PatternLayout
+#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
+
+### set log levels - for more verbose logging change 'info' to 'debug' ###
+
+log4j.rootLogger=warn, stdout
+
+log4j.logger.org.hibernate=info
+#log4j.logger.org.hibernate=debug
+
+### log HQL query parser activity
+#log4j.logger.org.hibernate.hql.ast.AST=debug
+
+### log just the SQL
+#log4j.logger.org.hibernate.SQL=debug
+
+### log JDBC bind parameters ###
+log4j.logger.org.hibernate.type=info
+#log4j.logger.org.hibernate.type=debug
+
+### log schema export/update ###
+log4j.logger.org.hibernate.tool.hbm2ddl=debug
+
+### log HQL parse trees
+#log4j.logger.org.hibernate.hql=debug
+
+### log cache activity ###
+#log4j.logger.org.hibernate.cache=debug
+
+### log transaction activity
+#log4j.logger.org.hibernate.transaction=debug
+
+### log JDBC resource acquisition
+#log4j.logger.org.hibernate.jdbc=debug
+
+### enable the following line if you want to track down connection ###
+### leakages when using DriverManagerConnectionProvider ###
+#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace

Added: trunk/Hibernate3/documentation/tutorial/src/main/scripts/runCleanDatabase.sh
===================================================================
--- trunk/Hibernate3/documentation/tutorial/src/main/scripts/runCleanDatabase.sh	                        (rev 0)
+++ trunk/Hibernate3/documentation/tutorial/src/main/scripts/runCleanDatabase.sh	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+# Delete database and recreate/start it
+if test ! -d data
+then
+        mkdir data
+fi
+if test -d data
+then
+        echo Removing database files...
+        rm -r data/test.*
+fi
+echo Starting database engine...
+cd data/
+java -classpath ../lib/hsqldb.jar org.hsqldb.Server

Added: trunk/Hibernate3/documentation/tutorial/src/main/webapp/WEB-INF/web.xml
===================================================================
--- trunk/Hibernate3/documentation/tutorial/src/main/webapp/WEB-INF/web.xml	                        (rev 0)
+++ trunk/Hibernate3/documentation/tutorial/src/main/webapp/WEB-INF/web.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+    xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+    <servlet>
+        <servlet-name>Event Manager</servlet-name>
+        <servlet-class>events.EventManagerServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Event Manager</servlet-name>
+        <url-pattern>/eventmanager</url-pattern>
+    </servlet-mapping>
+</web-app>

Added: trunk/Hibernate3/eg/pom.xml
===================================================================
--- trunk/Hibernate3/eg/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/eg/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.hibernate</groupId>
+    <artifactId>hibernate-eg</artifactId>
+    <packaging>jar</packaging>
+    <name>Hibernate Example</name>
+    <description>A simple example of Hibernate functionality</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-core</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

Added: trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/AuctionInfo.java
===================================================================
--- trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/AuctionInfo.java	                        (rev 0)
+++ trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/AuctionInfo.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: AuctionInfo.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.auction;
+
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class AuctionInfo {
+	private long id;
+	private String description;
+	private Date ends;
+	private Float maxAmount;
+	public String getDescription() {
+		return description;
+	}
+
+	public Date getEnds() {
+		return ends;
+	}
+
+	public long getId() {
+		return id;
+	}
+
+	public Float getMaxAmount() {
+		return maxAmount;
+	}
+	
+	public AuctionInfo(long id, String description, Date ends, Float maxAmount) {
+		this.id = id;
+		this.description = description;
+		this.ends = ends;
+		this.maxAmount = maxAmount;
+	}
+
+}

Added: trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/AuctionItem.hbm.xml
===================================================================
--- trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/AuctionItem.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/AuctionItem.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping 
+	package="org.hibernate.auction">
+
+	<import class="AuctionInfo"/>
+
+	<class name="AuctionItem">
+		<comment>An item that is being auctioned.</comment>
+		
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		
+		<natural-id>
+			<many-to-one name="seller"/>
+			<property name="shortDescription"
+					length="200"/>
+		</natural-id>
+				
+		<property name="description"
+				length="1000"/>
+				
+		<property name="ends"/>
+		
+		<property name="condition" column="`CONDITION`"/>
+		
+		<many-to-one name="successfulBid" 
+				outer-join="false"/>
+		
+		<bag name="bids"
+				inverse="true" 
+				cascade="all">
+			<key column="item"/>
+			<one-to-many class="Bid"/>
+		</bag>
+		
+	</class>
+		
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/AuctionItem.java
===================================================================
--- trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/AuctionItem.java	                        (rev 0)
+++ trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/AuctionItem.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+//$Id: AuctionItem.java 7369 2005-07-04 03:18:34Z oneovthafew $
+package org.hibernate.auction;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author Gavin King
+ */
+public class AuctionItem extends Persistent {
+	private String description;
+	private String shortDescription;
+	private List bids;
+	private Bid successfulBid;
+	private User seller;
+	private Date ends;
+	private int condition;
+	public List getBids() {
+		return bids;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public User getSeller() {
+		return seller;
+	}
+
+	public Bid getSuccessfulBid() {
+		return successfulBid;
+	}
+
+	public void setBids(List bids) {
+		this.bids = bids;
+	}
+
+	public void setDescription(String string) {
+		description = string;
+	}
+
+	public void setSeller(User user) {
+		seller = user;
+	}
+
+	public void setSuccessfulBid(Bid bid) {
+		successfulBid = bid;
+	}
+
+	public Date getEnds() {
+		return ends;
+	}
+
+	public void setEnds(Date date) {
+		ends = date;
+	}
+	
+	public int getCondition() {
+		return condition;
+	}
+
+	public void setCondition(int i) {
+		condition = i;
+	}
+
+	public String toString() {
+		return shortDescription + " (" + description + ": " + condition + "/10)";
+	}
+
+	public String getShortDescription() {
+		return shortDescription;
+	}
+
+	public void setShortDescription(String shortDescription) {
+		this.shortDescription = shortDescription;
+	}
+
+}

Added: trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Bid.hbm.xml
===================================================================
--- trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Bid.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Bid.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping 
+	package="org.hibernate.auction">
+
+	<class name="Bid" 
+		discriminator-value="N">
+		<comment>A bid or "buy now" for an item.</comment>
+		
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		
+		<discriminator type="char">
+			<column name="isBuyNow">
+				<comment>Y if a "buy now", N if a regular bid.</comment>
+			</column>
+		</discriminator>
+		
+		<natural-id>
+			<many-to-one name="item"/>
+			<property name="amount"/>
+		</natural-id>
+		
+		<property name="datetime" 
+				not-null="true" 
+				column="`datetime`"/>
+		
+		<many-to-one name="bidder" 
+				not-null="true"/>
+		
+		<subclass name="BuyNow" 
+			discriminator-value="Y"/>
+			
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Bid.java
===================================================================
--- trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Bid.java	                        (rev 0)
+++ trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Bid.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+//$Id: Bid.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.auction;
+
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class Bid extends Persistent {
+	private AuctionItem item;
+	private float amount;
+	private Date datetime;
+	private User bidder;
+	
+	public AuctionItem getItem() {
+		return item;
+	}
+
+	public void setItem(AuctionItem item) {
+		this.item = item;
+	}
+
+	public float getAmount() {
+		return amount;
+	}
+
+	public Date getDatetime() {
+		return datetime;
+	}
+
+	public void setAmount(float f) {
+		amount = f;
+	}
+
+	public void setDatetime(Date date) {
+		datetime = date;
+	}
+
+	public User getBidder() {
+		return bidder;
+	}
+
+	public void setBidder(User user) {
+		bidder = user;
+	}
+
+	public String toString() {
+		return bidder.getUserName() + " $" + amount;
+	}
+	
+	public boolean isBuyNow() {
+		return false;
+	}
+
+}

Added: trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/BuyNow.java
===================================================================
--- trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/BuyNow.java	                        (rev 0)
+++ trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/BuyNow.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,14 @@
+//$Id: BuyNow.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.auction;
+
+/**
+ * @author Gavin King
+ */
+public class BuyNow extends Bid {
+	public boolean isBuyNow() {
+		return true;
+	}
+	public String toString() {
+		return super.toString() + " (buy now)";
+	}
+}

Added: trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Main.java
===================================================================
--- trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Main.java	                        (rev 0)
+++ trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Main.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,390 @@
+//$Id: Main.java 7369 2005-07-04 03:18:34Z oneovthafew $
+package org.hibernate.auction;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.FetchMode;
+import org.hibernate.FlushMode;
+import org.hibernate.LockMode;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.Example;
+import org.hibernate.criterion.Expression;
+import org.hibernate.criterion.MatchMode;
+
+
+/**
+ * Demonstrate some useful features of Hibernate.
+ *
+ * @author Gavin King
+ */
+public class Main {
+
+	private SessionFactory factory;
+
+	/**
+	 * Demonstrates HQL projection/aggregation
+	 */
+	public void viewAllAuctionsFast() throws Exception {
+		System.out.println("Viewing all auction item info");
+
+		Session s = factory.openSession();
+		Transaction tx=null;
+		try {
+			tx = s.beginTransaction();
+
+			List auctions = s.createQuery(
+				"select new AuctionInfo( item.id, item.description, item.ends, max(bid.amount) ) "
+				+ "from AuctionItem item "
+				+ "left join item.bids bid "
+				+ "group by item.id, item.description, item.ends "
+				+ "order by item.ends desc"
+				)
+				.setMaxResults(100)
+				.list();
+
+			Iterator iter = auctions.iterator();
+			while ( iter.hasNext() ) {
+				AuctionInfo ai = (AuctionInfo) iter.next();
+				System.out.println(
+					"Auction: " + ai.getId() + " - " + ai.getDescription() +
+					", ends: " + ai.getEnds() +
+					", highest bid: " + ai.getMaxAmount()
+				);
+			}
+			System.out.println();
+
+			tx.commit();
+		}
+		catch (Exception e) {
+			if (tx!=null) tx.rollback();
+			throw e;
+		}
+		finally {
+			s.close();
+		}
+	}
+
+	/**
+	 * Demonstrates HQL with runtime fetch strategy
+	 */
+	public void viewAllAuctionsSlow() throws Exception {
+		System.out.println("Viewing all auction item objects");
+
+		Session s = factory.openSession();
+		Transaction tx=null;
+		try {
+			s.setFlushMode(FlushMode.NEVER); //entirely optional!!
+			tx = s.beginTransaction();
+
+			List auctions = s.createQuery(
+				"from AuctionItem item "
+				+ "left join fetch item.bids bid left join fetch bid.bidder "
+				+ "order by item.ends desc"
+				)
+				.setMaxResults(100)
+				.list();
+
+			Iterator iter = new HashSet(auctions).iterator();
+			while ( iter.hasNext() ) {
+				AuctionItem auction = (AuctionItem) iter.next();
+				System.out.println(
+					"Auction: " + auction.getId() + " - " + auction.getDescription() +
+					", ends: " + auction.getEnds() +
+					", bids: " + auction.getBids()
+				);
+			}
+			System.out.println();
+
+			tx.commit();
+		}
+		catch (Exception e) {
+			if (tx!=null) tx.rollback();
+			throw e;
+		}
+		finally {
+			s.close();
+		}
+	}
+
+	/**
+	 * Demonstrates transitive persistence with detached object support
+	 */
+	public void bidOnAuction(User bidder, AuctionItem item, float amount) throws Exception {
+		System.out.println("Creating a new bid for auction item: " + item.getId() + " by user: " + bidder.getId() );
+
+		Session s = factory.openSession();
+		Transaction tx=null;
+		try {
+			tx = s.beginTransaction();
+
+			s.lock(item, LockMode.NONE);
+			s.lock(bidder, LockMode.NONE);
+
+			Bid bid = new Bid();
+			bid.setBidder(bidder);
+			bid.setDatetime( new Date() );
+			bid.setAmount(amount);
+			bid.setItem(item);
+			bidder.getBids().add(bid);
+			item.getBids().add(bid);
+
+			tx.commit();
+		}
+		catch (Exception e) {
+			if (tx!=null) tx.rollback();
+			throw e;
+		}
+		finally {
+			s.close();
+		}
+	}
+
+	/**
+	 * Demonstrates detached object support
+	 */
+	public void changeUserDetails(User user) throws Exception {
+		System.out.println("Changing user details for: " + user.getId() );
+
+		Session s = factory.openSession();
+		Transaction tx=null;
+		try {
+			tx = s.beginTransaction();
+
+			s.merge(user);
+
+			tx.commit();
+		}
+		catch (Exception e) {
+			if (tx!=null) tx.rollback();
+			throw e;
+		}
+		finally {
+			s.close();
+		}
+	}
+
+	/**
+	 * Demonstrates automatic dirty checking
+	 */
+	public void changeItemDescription(Long itemId, String description) throws Exception {
+		System.out.println("Changing auction item description for: " + itemId );
+
+		Session s = factory.openSession();
+		Transaction tx=null;
+		try {
+			tx = s.beginTransaction();
+
+			AuctionItem item = (AuctionItem) s.get(AuctionItem.class, itemId);
+			if (item==null) throw new IllegalArgumentException("No item for the given id: " + itemId);
+			item.setDescription(description);
+
+			tx.commit();
+		}
+		catch (Exception e) {
+			if (tx!=null) tx.rollback();
+			throw e;
+		}
+		finally {
+			s.close();
+		}
+	}
+
+	/**
+	 * Demonstrates query by criteria with runtime fetch strategy
+	 */
+	public void viewUserAuctions(Long sellerId) throws Exception {
+		System.out.println("Viewing user and auctions: " + sellerId);
+
+		Session s = factory.openSession();
+		Transaction tx=null;
+		try {
+			tx = s.beginTransaction();
+
+			List list = s.createCriteria(User.class)
+				.add( Expression.eq("id", sellerId) )
+				.setFetchMode("auctions", FetchMode.JOIN)
+				.list();
+
+			if (list.size()==0) throw new IllegalArgumentException("No user for the given id: " + sellerId);
+			User user = (User) list.get(0);
+			System.out.println(
+				"User: " + user.getId() + " - " + user.getName() +
+				", email: " + user.getEmail() +
+				", auctions: " + user.getAuctions()
+			);
+
+			tx.commit();
+		}
+		catch (Exception e) {
+			if (tx!=null) tx.rollback();
+			throw e;
+		}
+		finally {
+			s.close();
+		}
+	}
+
+	/**
+	 * Demonstrates query by example
+	 */
+	public void viewAuctionsByDescription(String description, int condition) throws Exception {
+		String msg = "Viewing auctions containing: " + description;
+		if (condition>0) msg += " with condition: " + condition + "/10";
+
+		AuctionItem item = new AuctionItem();
+		item.setDescription(description);
+		item.setCondition(condition);
+
+		Session s = factory.openSession();
+		Transaction tx=null;
+		try {
+			tx = s.beginTransaction();
+
+			Iterator iter = s.createCriteria(AuctionItem.class)
+				.add( Example.create(item)
+					.enableLike(MatchMode.ANYWHERE)
+					.ignoreCase()
+					.excludeZeroes()
+				)
+				.list()
+				.iterator();
+
+			System.out.println(msg);
+			while ( iter.hasNext() ) {
+				item = (AuctionItem) iter.next();
+				System.out.println("Item: " + item.getId() + " - " + item.getDescription() );
+			}
+			System.out.println();
+
+			tx.commit();
+		}
+		catch (Exception e) {
+			if (tx!=null) tx.rollback();
+			throw e;
+		}
+		finally {
+			s.close();
+		}
+	}
+
+	/**
+	 * Demonstrates transitive persistence
+	 */
+	public void createTestAuctions() throws Exception {
+		System.out.println("Setting up some test data");
+
+		Session s = factory.openSession();
+		Transaction tx = s.beginTransaction();
+
+		User seller = new User();
+		seller.setUserName("xam");
+		seller.setName( new Name("Max", new Character('R'), "Andersen") );
+		seller.setEmail("max at hibernate.org");
+		seller.setPassword("******");
+		seller.setAuctions( new ArrayList() );
+		s.save(seller);
+		User bidder1 = new User();
+		bidder1.setUserName("1E1");
+		bidder1.setName( new Name( "Gavin", new Character('A'), "King") );
+		bidder1.setEmail("gavin at hibernate.org");
+		bidder1.setPassword("******");
+		bidder1.setBids( new ArrayList() );
+		s.save(bidder1);
+		User bidder2 = new User();
+		bidder2.setUserName("steve");
+		bidder2.setName( new Name("Steve", null, "Ebersole") );
+		bidder2.setEmail("steve at hibernate.org");
+		bidder2.setPassword("******");
+		bidder2.setBids( new ArrayList() );
+		s.save(bidder2);
+
+		for ( int i=0; i<3; i++ ) {
+			AuctionItem item = new AuctionItem();
+			item.setShortDescription("Auction " + i);
+			item.setDescription("the auction item number " + i);
+			item.setEnds( new Date() );
+			item.setBids( new ArrayList() );
+			item.setSeller(seller);
+			item.setCondition(i*3 + 2);
+			for ( int j=0; j<i; j++ ) {
+
+				Bid bid = new Bid();
+				bid.setBidder(bidder1);
+				bid.setAmount(j);
+				bid.setDatetime( new Date() );
+				bid.setItem(item);
+				item.getBids().add(bid);
+				bidder1.getBids().add(bid);
+
+				Bid bid2 = new Bid();
+				bid2.setBidder(bidder2);
+				bid2.setAmount( j + 0.5f);
+				bid2.setDatetime( new Date() );
+				bid2.setItem(item);
+				item.getBids().add(bid2);
+				bidder2.getBids().add(bid2);
+			}
+			seller.getAuctions().add(item);
+			mainItem = item;
+		}
+		mainBidder = bidder2;
+		mainSeller = seller;
+
+		BuyNow buyNow = new BuyNow();
+		buyNow.setAmount(1.2f);
+		buyNow.setDatetime( new Date() );
+		buyNow.setBidder(mainBidder);
+		buyNow.setItem(mainItem);
+		mainBidder.getBids().add(buyNow);
+		mainItem.getBids().add(buyNow);
+
+		tx.commit();
+		s.close();
+	}
+
+	static AuctionItem mainItem;
+	static User mainBidder;
+	static User mainSeller;
+
+	public static void main(String[] args) throws Exception {
+
+		final Main test = new Main();
+
+		Configuration cfg = new Configuration()
+			.addClass(AuctionItem.class)
+			.addClass(Bid.class)
+			.addClass(User.class)
+			.setProperty(Environment.HBM2DDL_AUTO, "create");
+		//cfg.setProperty("hibernate.show_sql", "true");
+
+		test.factory = cfg.buildSessionFactory();
+
+		test.createTestAuctions();
+		test.viewAllAuctionsSlow();
+
+		test.viewAllAuctionsFast();
+		test.bidOnAuction(mainBidder, mainItem, 5.5f);
+		test.viewAllAuctionsFast();
+
+		test.viewUserAuctions( mainSeller.getId() );
+		mainSeller.setEmail("max at jboss.org");
+		test.changeUserDetails(mainSeller);
+		test.changeItemDescription(mainItem.getId(), "new description");
+		test.viewUserAuctions( mainSeller.getId() );
+
+		test.viewAuctionsByDescription("It", 0);
+		test.viewAuctionsByDescription("DESC", 3);
+		test.viewAuctionsByDescription("DESC", 8);
+
+		test.factory.close();
+
+	}
+}

Added: trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Name.java
===================================================================
--- trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Name.java	                        (rev 0)
+++ trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Name.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+//$Id: Name.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.auction;
+
+/**
+ * @author Gavin King
+ */
+public class Name {
+	private String firstName;
+	private String lastName;
+	private Character initial;
+	private Name() {}
+	public Name(String first, Character middle, String last) {
+		firstName = first;
+		initial = middle;
+		lastName = last;
+	}
+	public String getFirstName() {
+		return firstName;
+	}
+
+	public void setFirstName(String firstName) {
+		this.firstName = firstName;
+	}
+
+	public Character getInitial() {
+		return initial;
+	}
+
+	public void setInitial(Character initial) {
+		this.initial = initial;
+	}
+
+	public String getLastName() {
+		return lastName;
+	}
+
+	public void setLastName(String lastName) {
+		this.lastName = lastName;
+	}
+	
+	public String toString() {
+		StringBuffer buf = new StringBuffer()
+			.append(firstName)
+			.append(' ');
+		if (initial!=null) buf.append(initial)
+			.append(' ');
+		return buf.append(lastName)
+			.toString();
+	}
+
+}

Added: trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Persistent.java
===================================================================
--- trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Persistent.java	                        (rev 0)
+++ trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/Persistent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+//$Id: Persistent.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.auction;
+
+/**
+ * @author Gavin King
+ */
+public class Persistent {
+	private Long id;
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long long1) {
+		id = long1;
+	}
+
+}

Added: trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/User.hbm.xml
===================================================================
--- trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/User.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/User.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping 
+	package="org.hibernate.auction">
+
+	<class name="User" table="AuctionUser" lazy="true">
+		<comment>Users may bid for or sell auction items.</comment>
+		
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		
+		<natural-id mutable="true">
+			<property name="userName"
+					length="10"/>
+		</natural-id>
+		
+		<property name="password" 
+				not-null="true"
+				length="15"
+				column="`password`"/>
+		
+		<property name="email"/>
+		
+		<component name="name">
+			<property name="firstName"
+					length="50"
+					not-null="true"/>
+			<property name="initial" 
+					column="`initial`"/>
+			<property name="lastName"
+					length="50"
+					not-null="true"/>
+		</component>
+		
+		<bag name="bids"
+				inverse="true" 
+				cascade="save-update,lock">
+			<key column="bidder"/>
+			<one-to-many class="Bid"/>
+		</bag>
+		
+		<bag name="auctions"
+				inverse="true" 
+				cascade="save-update,lock">
+			<key column="seller"/>
+			<one-to-many class="AuctionItem"/>
+		</bag>
+		
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/User.java
===================================================================
--- trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/User.java	                        (rev 0)
+++ trunk/Hibernate3/eg/src/main/java/org/hibernate/auction/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+//$Id: User.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.auction;
+
+import java.util.List;
+
+/**
+ * @author Gavin King
+ */
+public class User extends Persistent {
+	private String userName;
+	private String password;
+	private String email;
+	private Name name;
+	private List bids;
+	private List auctions;
+	
+	public String getEmail() {
+		return email;
+	}
+
+	public String getPassword() {
+		return password;
+	}
+
+	public String getUserName() {
+		return userName;
+	}
+
+	public void setEmail(String string) {
+		email = string;
+	}
+
+	public void setPassword(String string) {
+		password = string;
+	}
+
+	public void setUserName(String string) {
+		userName = string;
+	}
+
+	public List getAuctions() {
+		return auctions;
+	}
+
+	public List getBids() {
+		return bids;
+	}
+
+	public void setAuctions(List list) {
+		auctions = list;
+	}
+
+	public void setBids(List list) {
+		bids = list;
+	}
+	
+	public String toString() {
+		return userName;
+	}
+
+	public Name getName() {
+		return name;
+	}
+
+	public void setName(Name name) {
+		this.name = name;
+	}
+
+}

Added: trunk/Hibernate3/eg/src/main/resources/org/hibernate/auction/AuctionItem.hbm.xml
===================================================================
--- trunk/Hibernate3/eg/src/main/resources/org/hibernate/auction/AuctionItem.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/eg/src/main/resources/org/hibernate/auction/AuctionItem.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping 
+	package="org.hibernate.auction">
+
+	<import class="AuctionInfo"/>
+
+	<class name="AuctionItem">
+		<comment>An item that is being auctioned.</comment>
+		
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		
+		<natural-id>
+			<many-to-one name="seller"/>
+			<property name="shortDescription"
+					length="200"/>
+		</natural-id>
+				
+		<property name="description"
+				length="1000"/>
+				
+		<property name="ends"/>
+		
+		<property name="condition" column="`CONDITION`"/>
+		
+		<many-to-one name="successfulBid" 
+				outer-join="false"/>
+		
+		<bag name="bids"
+				inverse="true" 
+				cascade="all">
+			<key column="item"/>
+			<one-to-many class="Bid"/>
+		</bag>
+		
+	</class>
+		
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/eg/src/main/resources/org/hibernate/auction/Bid.hbm.xml
===================================================================
--- trunk/Hibernate3/eg/src/main/resources/org/hibernate/auction/Bid.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/eg/src/main/resources/org/hibernate/auction/Bid.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping 
+	package="org.hibernate.auction">
+
+	<class name="Bid" 
+		discriminator-value="N">
+		<comment>A bid or "buy now" for an item.</comment>
+		
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		
+		<discriminator type="char">
+			<column name="isBuyNow">
+				<comment>Y if a "buy now", N if a regular bid.</comment>
+			</column>
+		</discriminator>
+		
+		<natural-id>
+			<many-to-one name="item"/>
+			<property name="amount"/>
+		</natural-id>
+		
+		<property name="datetime" 
+				not-null="true" 
+				column="`datetime`"/>
+		
+		<many-to-one name="bidder" 
+				not-null="true"/>
+		
+		<subclass name="BuyNow" 
+			discriminator-value="Y"/>
+			
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/eg/src/main/resources/org/hibernate/auction/User.hbm.xml
===================================================================
--- trunk/Hibernate3/eg/src/main/resources/org/hibernate/auction/User.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/eg/src/main/resources/org/hibernate/auction/User.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping 
+	package="org.hibernate.auction">
+
+	<class name="User" table="AuctionUser" lazy="true">
+		<comment>Users may bid for or sell auction items.</comment>
+		
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		
+		<natural-id mutable="true">
+			<property name="userName"
+					length="10"/>
+		</natural-id>
+		
+		<property name="password" 
+				not-null="true"
+				length="15"
+				column="`password`"/>
+		
+		<property name="email"/>
+		
+		<component name="name">
+			<property name="firstName"
+					length="50"
+					not-null="true"/>
+			<property name="initial" 
+					column="`initial`"/>
+			<property name="lastName"
+					length="50"
+					not-null="true"/>
+		</component>
+		
+		<bag name="bids"
+				inverse="true" 
+				cascade="save-update,lock">
+			<key column="bidder"/>
+			<one-to-many class="Bid"/>
+		</bag>
+		
+		<bag name="auctions"
+				inverse="true" 
+				cascade="save-update,lock">
+			<key column="seller"/>
+			<one-to-many class="AuctionItem"/>
+		</bag>
+		
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Deleted: trunk/Hibernate3/indent.py
===================================================================
--- trunk/Hibernate3/indent.py	2007-05-24 19:06:06 UTC (rev 11562)
+++ trunk/Hibernate3/indent.py	2007-05-25 20:19:29 UTC (rev 11563)
@@ -1,45 +0,0 @@
-import re
-import sys
-sys.argv.pop(0)
-for fname in sys.argv:
-	file = open(fname)
-	inlines = file.read().split('\n')
-	file.close()
-	out= []
-	tabcount = 0
-	extratab=0
-	for ln in inlines:
-		code = ln.lstrip('\t ').rstrip('\t ')
-		clen = len(code)
-		javadoc = clen > 0 and code[0]=='*'
-		if javadoc:
-			code = ' ' + code
-		else:
-			begincb = clen > 0 and ( code[0]=='}' or code[0]==')' )
-			tabcount -= begincb
-		
-		extratab = extratab or ( len(code)>0 and code[0]=='.' )
-		
-		tabs = '\t' * (tabcount + extratab)
-		
-		extratab = clen>0 and ( code[clen-1]==':' or code[clen-1]=='?' )
-		
-		if clen>5 and code[0:6] == '} else':
-			code = '}\n' + tabs + 'else' + code[6:]
-		if clen>6 and code[0:7] == '} catch':
-			code = '}\n' + tabs + 'catch' + code[7:]
-		
-		out.append( tabs + code + '\n' )
-		
-		if not javadoc:
-			uncommented = code.split('//')[0].rstrip()
-			clen = len(uncommented)
-			endob = clen > 0 and ( code[clen-1]=='{' or code[clen-1]=='(' )
-			tabcount += endob
-		
-	file = open( fname, 'w' )
-	for ln in out:
-		file.write(ln)
-	file.close()
-
-

Added: trunk/Hibernate3/jmx/pom.xml
===================================================================
--- trunk/Hibernate3/jmx/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/jmx/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.hibernate</groupId>
+    <artifactId>hibernate-jmx</artifactId>
+    <packaging>jar</packaging>
+    <name>Hibernate JMX Module</name>
+    <url>http://hibernate.org</url>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-core</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

Added: trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/HibernateService.java
===================================================================
--- trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/HibernateService.java	                        (rev 0)
+++ trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/HibernateService.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,168 @@
+//$Id: HibernateService.java 6100 2005-03-17 10:48:03Z turin42 $
+package org.hibernate.jmx;
+
+import java.util.Properties;
+import java.util.Map;
+
+import javax.naming.InitialContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.SessionFactory;
+import org.hibernate.cfg.Environment;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+import org.hibernate.util.NamingHelper;
+import org.hibernate.util.ExternalSessionFactoryConfig;
+
+
+/**
+ * Implementation of <tt>HibernateServiceMBean</tt>. Creates a
+ * <tt>SessionFactory</tt> and binds it to the specified JNDI name.<br>
+ * <br>
+ * All mapping documents are loaded as resources by the MBean.
+ * @see HibernateServiceMBean
+ * @see org.hibernate.SessionFactory
+ * @author John Urberg, Gavin King
+ */
+public class HibernateService extends ExternalSessionFactoryConfig implements HibernateServiceMBean {
+
+	private static final Log log = LogFactory.getLog(HibernateServiceMBean.class);
+
+	private String boundName;
+	private Properties properties = new Properties();
+
+
+	public void start() throws HibernateException {
+		boundName = getJndiName();
+		try {
+			buildSessionFactory();
+		}
+		catch (HibernateException he) {
+			log.info( "Could not build SessionFactory using the MBean classpath - will try again using client classpath: " + he.getMessage() );
+			log.debug("Error was", he);
+			new SessionFactoryStub(this);
+		}
+	}
+
+	public void stop() {
+		log.info("stopping service");
+		try {
+			InitialContext context = NamingHelper.getInitialContext( buildProperties() );
+			( (SessionFactory) context.lookup(boundName) ).close();
+			//context.unbind(boundName);
+		}
+		catch (Exception e) {
+			log.warn("exception while stopping service", e);
+		}
+	}
+	
+	SessionFactory buildSessionFactory() throws HibernateException {
+		log.info( "starting service at JNDI name: " + boundName );
+		log.info( "service properties: " + properties );
+		return buildConfiguration().buildSessionFactory();
+	}
+
+	protected Map getExtraProperties() {
+		return properties;
+	}
+
+	public String getTransactionStrategy() {
+		return getProperty(Environment.TRANSACTION_STRATEGY);
+	}
+
+	public void setTransactionStrategy(String txnStrategy) {
+		setProperty(Environment.TRANSACTION_STRATEGY, txnStrategy);
+	}
+
+	public String getUserTransactionName() {
+		return getProperty(Environment.USER_TRANSACTION);
+	}
+
+	public void setUserTransactionName(String utName) {
+		setProperty(Environment.USER_TRANSACTION, utName);
+	}
+
+	public String getTransactionManagerLookupStrategy() {
+		return getProperty(Environment.TRANSACTION_MANAGER_STRATEGY);
+	}
+
+	public void setTransactionManagerLookupStrategy(String lkpStrategy) {
+		setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, lkpStrategy);
+	}
+
+	public String getPropertyList() {
+		return buildProperties().toString();
+	}
+
+	public String getProperty(String property) {
+		return properties.getProperty(property);
+	}
+
+	public void setProperty(String property, String value) {
+		properties.setProperty(property, value);
+	}
+
+	public void dropSchema() {
+		new SchemaExport( buildConfiguration() ).drop(false, true);
+	}
+
+	public void createSchema() {
+		new SchemaExport( buildConfiguration() ).create(false, true);
+	}	public String getName() {
+		return getProperty(Environment.SESSION_FACTORY_NAME);
+	}
+
+	public String getDatasource() {
+		return getProperty(Environment.DATASOURCE);
+	}
+
+	public void setDatasource(String datasource) {
+		setProperty(Environment.DATASOURCE, datasource);
+	}
+
+	public String getJndiName() {
+		return getProperty(Environment.SESSION_FACTORY_NAME);
+	}
+
+	public void setJndiName(String jndiName) {
+		setProperty(Environment.SESSION_FACTORY_NAME, jndiName);
+	}
+
+	public String getUserName() {
+		return getProperty(Environment.USER);
+	}
+
+	public void setUserName(String userName) {
+		setProperty(Environment.USER, userName);
+	}
+
+	public String getPassword() {
+		return getProperty(Environment.PASS);
+	}
+
+	public void setPassword(String password) {
+		setProperty(Environment.PASS, password);
+	}
+
+	public void setFlushBeforeCompletionEnabled(String enabled) {
+		setProperty(Environment.FLUSH_BEFORE_COMPLETION, enabled);
+	}
+
+	public String getFlushBeforeCompletionEnabled() {
+		return getProperty(Environment.FLUSH_BEFORE_COMPLETION);
+	}
+
+	public void setAutoCloseSessionEnabled(String enabled) {
+		setProperty(Environment.AUTO_CLOSE_SESSION, enabled);
+	}
+
+	public String getAutoCloseSessionEnabled() {
+		return getProperty(Environment.AUTO_CLOSE_SESSION);
+	}
+
+	public Properties getProperties() {
+		return buildProperties();
+	}
+}

Added: trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/HibernateServiceMBean.java
===================================================================
--- trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/HibernateServiceMBean.java	                        (rev 0)
+++ trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/HibernateServiceMBean.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,333 @@
+//$Id: HibernateServiceMBean.java 10860 2006-11-22 00:02:55Z steve.ebersole at jboss.com $
+package org.hibernate.jmx;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Hibernate JMX Management API
+ * @see HibernateService
+ * @author John Urberg, Gavin King
+ */
+public interface HibernateServiceMBean {
+
+	/**
+	 * The Hibernate mapping files (might be overridden by subclasses
+	 * that want to specify the mapping files by some other mechanism)
+	 * @return String
+	 */
+	public String getMapResources();
+	/**
+	 * Specify the Hibernate mapping files
+	 * @param mappingFiles
+	 */
+	public void setMapResources(String mappingFiles);
+	/**
+	 * Add a mapping file
+	 * @param mapResource
+	 */
+	public void addMapResource(String mapResource);
+
+	/**
+	 * Set a property
+	 * @param property the property name
+	 * @param value the property value
+	 */
+	public void setProperty(String property, String value);
+
+	/**
+	 * Get a property
+	 * @param property the property name
+	 * @return the property value
+	 */
+	public String getProperty(String property);
+
+	/**
+	 * Display the properties
+	 * @return a list of property names and values
+	 */
+	public String getPropertyList();
+
+	/**
+	 * The JNDI name of the datasource to use in this <tt>SessionFactory</tt>
+	 * @return String
+	 */
+	public String getDatasource();
+	/**
+	 * Set the JNDI name of the datasource to use in this <tt>SessionFactory</tt>
+	 * @param datasource
+	 */
+	public void setDatasource(String datasource);
+
+	/**
+	 * Log into the database with this name
+	 * @return String
+	 */
+	public String getUserName();
+	/**
+	 * Log into the database with this name
+	 * @param userName
+	 */
+	public void setUserName(String userName);
+
+	/**
+	 * Log into the database with this password
+	 * @return String
+	 */
+	public String getPassword();
+	/**
+	 * Log into the database with this password
+	 * @param password
+	 */
+	public void setPassword(String password);
+
+	/**
+	 * The JNDI name of the dialect class to use in this <tt>SessionFactory</tt>
+	 * @return String
+	 */
+	public String getDialect();
+	/**
+	 * The name of the dialect class to use in this <tt>SessionFactory</tt>
+	 * @param dialect fully qualified class name of <tt>Dialect</tt> subclass
+	 * @see org.hibernate.dialect.Dialect
+	 */
+	public void setDialect(String dialect);
+
+	/**
+	 * The JNDI name to bind to the <tt>SessionFactory</tt>
+	 * @return String
+	 */
+	public String getJndiName();
+	/**
+	 * The JNDI name to bind to the <tt>SessionFactory</tt>
+	 * @param jndiName
+	 */
+	public void setJndiName(String jndiName);
+
+	/**
+	 * The fully qualified class name of the Hibernate <tt>TransactionFactory</tt> implementation
+	 * @return the class name
+	 * @see org.hibernate.transaction.TransactionFactory
+	 */
+	public String getTransactionStrategy();
+
+	/**
+	 * Set the fully qualified class name of the Hibernate <tt>TransactionFactory</tt> implementation
+	 * @param txnStrategy the class name
+	 * @see org.hibernate.transaction.TransactionFactory
+	 */
+	public void setTransactionStrategy(String txnStrategy);
+
+	/**
+	 * The JNDI name of the JTA UserTransaction object (used only be <tt>JTATransaction</tt>).
+	 * @return the JNDI name
+	 * @see org.hibernate.transaction.JTATransaction
+	 */
+	public String getUserTransactionName();
+	/**
+	 * Set the JNDI name of the JTA UserTransaction object (used only by <tt>JTATransaction</tt>).
+	 * @param utName the JNDI name
+	 * @see org.hibernate.transaction.JTATransaction
+	 */
+	public void setUserTransactionName(String utName);
+
+	/**
+	 * Get the strategy for obtaining the JTA <tt>TransactionManager</tt>
+	 * @return the class name
+	 * @see org.hibernate.transaction.TransactionManagerLookup
+	 */
+	public String getTransactionManagerLookupStrategy();
+	/**
+	 * Set the strategy for obtaining the JTA <tt>TransactionManager</tt>
+	 * @param lkpStrategy the class name
+	 * @see org.hibernate.transaction.TransactionManagerLookup
+	 */
+	public void setTransactionManagerLookupStrategy(String lkpStrategy);
+
+	/**
+	 * Is SQL logging enabled?
+	 */
+	public String getShowSqlEnabled();
+	/**
+	 * Enable logging of SQL to console
+	 */
+	public void setShowSqlEnabled(String showSql);
+	/**
+	 * Get the maximum outer join fetch depth
+	 */
+	public String getMaximumFetchDepth();
+	/**
+	 * Set the maximum outer join fetch depth
+	 */
+	public void setMaximumFetchDepth(String fetchDepth);
+	/**
+	 * Get the maximum JDBC batch size
+	 */
+	public String getJdbcBatchSize();
+	/**
+	 * Set the maximum JDBC batch size
+	 */
+	public void setJdbcBatchSize(String batchSize);
+	/**
+	 * Get the JDBC fetch size
+	 */
+	public String getJdbcFetchSize();
+	/**
+	 * Set the JDBC fetch size
+	 */
+	public void setJdbcFetchSize(String fetchSize);
+	/**
+	 * Get the query language substitutions
+	 */
+	public String getQuerySubstitutions();
+	/**
+	 * Set the query language substitutions
+	 */
+	public void setQuerySubstitutions(String querySubstitutions);
+	/**
+	 * Get the default schema
+	 */
+	public String getDefaultSchema();
+	/**
+	 * Set the default schema
+	 */
+	public void setDefaultSchema(String schema);
+	/**
+	 * Get the default catalog
+	 */
+	public String getDefaultCatalog();
+	/**
+	 * Set the default catalog
+	 */
+	public void setDefaultCatalog(String catalog);
+	/**
+	 * Is use of scrollable resultsets enabled?
+	 */
+	public String getJdbcScrollableResultSetEnabled();
+	/**
+	 * Enable or disable the use of scrollable resultsets 
+	 */
+	public void setJdbcScrollableResultSetEnabled(String enabled);
+	/**
+	 * Is use of JDBC3 <tt>getGeneratedKeys()</tt> enabled?
+	 */
+	public String getGetGeneratedKeysEnabled();
+	/**
+	 * Enable or disable the use <tt>getGeneratedKeys()</tt> 
+	 */
+	public void setGetGeneratedKeysEnabled(String enabled);
+	/**
+	 * Get the second-level cache provider class name
+	 */
+	public String getCacheProviderClass();
+	/**
+	 * Set the second-level cache provider class name
+	 */
+	public void setCacheProviderClass(String providerClassName);
+	/**
+	 * For cache providers which support this setting, get the
+	 * provider's specific configuration resource.
+	 */
+	public String getCacheProviderConfig();
+	/**
+	 * For cache providers which support this setting, specify the
+	 * provider's specific configuration resource.
+	 */
+	public void setCacheProviderConfig(String cacheProviderConfig);
+	/**
+	 * Is the query cache enabled?
+	 */
+	public String getQueryCacheEnabled();
+	/**
+	 * Enable or disable the query cache
+	 */
+	public void setQueryCacheEnabled(String enabled);
+	/**
+	 * Is the second-level cache enabled?
+	 */
+	public String getSecondLevelCacheEnabled();
+	/**
+	 * Enable or disable the second-level cache
+	 */
+	public void setSecondLevelCacheEnabled(String enabled);
+	/**
+	 * Get the cache region prefix
+	 */
+	public String getCacheRegionPrefix();
+	/**
+	 * Set the cache region prefix
+	 */
+	public void setCacheRegionPrefix(String prefix);
+	/**
+	 * Is the second-level cache optimized for miminal puts?
+	 */
+	public String getMinimalPutsEnabled();
+	/**
+	 * Enable or disable optimization of second-level cache
+	 * for minimal puts 
+	 */
+	public void setMinimalPutsEnabled(String enabled);
+	/**
+	 * Are SQL comments enabled?
+	 */
+	public String getCommentsEnabled();
+	/**
+	 * Enable or disable the inclusion of comments in
+	 * generated SQL
+	 */
+	public void setCommentsEnabled(String enabled);
+	/**
+	 * Is JDBC batch update for versioned entities enabled?
+	 */
+	public String getBatchVersionedDataEnabled();
+	/**
+	 * Enable or disable the use of batch updates for
+	 * versioned entities
+	 */
+	public void setBatchVersionedDataEnabled(String enabled);
+	
+	/**
+	 * Enable automatic flushing of the Session when JTA transaction ends.
+	 */
+	public void setFlushBeforeCompletionEnabled(String enabled);
+	/**
+	 * Is automatic Session flusing enabled?
+	 */
+	public String getFlushBeforeCompletionEnabled();
+
+	/**
+	 * Enable automatic closing of Session when JTA transaction ends.
+	 */
+	public void setAutoCloseSessionEnabled(String enabled);
+	/**
+	 * Is automatic Session closing enabled?
+	 */
+	public String getAutoCloseSessionEnabled();
+
+	/**
+	 * Export the <tt>CREATE</tt> DDL to the database
+	 * @throws HibernateException
+	 */
+	public void createSchema() throws HibernateException;
+	/**
+	 * Export the <tt>DROP</tt> DDL to the database
+	 * @throws HibernateException
+	 */
+	public void dropSchema() throws HibernateException;
+
+
+	/**
+	 * Create the <tt>SessionFactory</tt> and bind to the jndi name on startup
+	 */
+	public void start() throws HibernateException;
+	/**
+	 * Unbind the <tt>SessionFactory</tt> or stub from JNDI
+	 */
+	public void stop();
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/SessionFactoryStub.java
===================================================================
--- trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/SessionFactoryStub.java	                        (rev 0)
+++ trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/SessionFactoryStub.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,201 @@
+//$Id: SessionFactoryStub.java 8754 2005-12-05 23:36:59Z steveebersole $
+package org.hibernate.jmx;
+
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.sql.Connection;
+import java.util.Map;
+import java.util.Set;
+
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.SessionFactory;
+import org.hibernate.StatelessSession;
+import org.hibernate.engine.FilterDefinition;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.id.UUIDHexGenerator;
+import org.hibernate.impl.SessionFactoryObjectFactory;
+import org.hibernate.metadata.ClassMetadata;
+import org.hibernate.metadata.CollectionMetadata;
+import org.hibernate.stat.Statistics;
+
+/**
+ * A flyweight for <tt>SessionFactory</tt>. If the MBean itself does not
+ * have classpath to the persistent classes, then a stub will be registered
+ * with JNDI and the actual <tt>SessionFactoryImpl</tt> built upon first
+ * access.
+ * @author Gavin King
+ */
+public class SessionFactoryStub implements SessionFactory {
+
+	private static final Log log = LogFactory.getLog(SessionFactoryStub.class);
+
+	private static final IdentifierGenerator UUID_GENERATOR = new UUIDHexGenerator();
+
+	private transient SessionFactory impl;
+	private transient HibernateService service;
+	private String uuid;
+	private String name;
+
+	SessionFactoryStub(HibernateService service) {
+		this.service = service;
+		this.name = service.getJndiName();
+		try {
+			uuid = (String) UUID_GENERATOR.generate(null, null);
+		}
+		catch (Exception e) {
+			throw new AssertionFailure("Could not generate UUID");
+		}
+
+		SessionFactoryObjectFactory.addInstance( uuid, name, this, service.getProperties() );
+	}
+
+	public org.hibernate.classic.Session openSession(Connection connection, Interceptor interceptor) {
+		return getImpl().openSession(connection, interceptor);
+	}
+
+	public org.hibernate.classic.Session openSession(Interceptor interceptor) throws HibernateException {
+		return getImpl().openSession(interceptor);
+	}
+
+	public org.hibernate.classic.Session openSession() throws HibernateException {
+		return getImpl().openSession();
+	}
+	
+	public org.hibernate.classic.Session openSession(Connection conn) {
+		return getImpl().openSession(conn);
+	}
+
+	public org.hibernate.classic.Session getCurrentSession() {
+		return getImpl().getCurrentSession();
+	}
+	
+	private synchronized SessionFactory getImpl() {
+		if (impl==null) impl = service.buildSessionFactory();
+		return impl;
+	}
+
+	//readResolveObject
+	private Object readResolve() throws ObjectStreamException {
+		// look for the instance by uuid
+		Object result = SessionFactoryObjectFactory.getInstance(uuid);
+		if (result==null) {
+			// in case we were deserialized in a different JVM, look for an instance with the same name
+			// (alternatively we could do an actual JNDI lookup here....)
+			result = SessionFactoryObjectFactory.getNamedInstance(name);
+			if (result==null) {
+				throw new InvalidObjectException("Could not find a stub SessionFactory named: " + name);
+			}
+			else {
+				log.debug("resolved stub SessionFactory by name");
+			}
+		}
+		else {
+			log.debug("resolved stub SessionFactory by uid");
+		}
+		return result;
+	}
+
+	/**
+	 * @see javax.naming.Referenceable#getReference()
+	 */
+	public Reference getReference() throws NamingException {
+		return new Reference(
+			SessionFactoryStub.class.getName(),
+			new StringRefAddr("uuid", uuid),
+			SessionFactoryObjectFactory.class.getName(),
+			null
+		);
+	}
+
+	public ClassMetadata getClassMetadata(Class persistentClass) throws HibernateException {
+		return getImpl().getClassMetadata(persistentClass);
+	}
+
+	public ClassMetadata getClassMetadata(String entityName)
+	throws HibernateException {
+		return getImpl().getClassMetadata(entityName);
+	}
+
+	public CollectionMetadata getCollectionMetadata(String roleName) throws HibernateException {
+		return getImpl().getCollectionMetadata(roleName);
+	}
+
+	public Map getAllClassMetadata() throws HibernateException {
+		return getImpl().getAllClassMetadata();
+	}
+
+	public Map getAllCollectionMetadata() throws HibernateException {
+		return getImpl().getAllCollectionMetadata();
+	}
+
+	public void close() throws HibernateException {
+	}
+	
+	public boolean isClosed() {
+		return false;
+	}
+
+	public void evict(Class persistentClass, Serializable id)
+		throws HibernateException {
+		getImpl().evict(persistentClass, id);
+	}
+
+	public void evict(Class persistentClass) throws HibernateException {
+		getImpl().evict(persistentClass);
+	}
+
+	public void evictEntity(String entityName, Serializable id)
+	throws HibernateException {
+		getImpl().evictEntity(entityName, id);
+	}
+	
+	public void evictEntity(String entityName) throws HibernateException {
+		getImpl().evictEntity(entityName);
+	}
+
+	public void evictCollection(String roleName, Serializable id)
+		throws HibernateException {
+		getImpl().evictCollection(roleName, id);
+	}
+
+	public void evictCollection(String roleName) throws HibernateException {
+		getImpl().evictCollection(roleName);
+	}
+
+	public void evictQueries() throws HibernateException {
+		getImpl().evictQueries();
+	}
+
+	public void evictQueries(String cacheRegion) throws HibernateException {
+		getImpl().evictQueries(cacheRegion);
+	}
+
+	public Statistics getStatistics() {
+		return getImpl().getStatistics();
+	}
+
+	public StatelessSession openStatelessSession() {
+		return getImpl().openStatelessSession();
+	}
+
+	public StatelessSession openStatelessSession(Connection conn) {
+		return getImpl().openStatelessSession(conn);
+	}
+
+	public Set getDefinedFilterNames() {
+		return getImpl().getDefinedFilterNames();
+	}
+
+	public FilterDefinition getFilterDefinition(String filterName) throws HibernateException {
+		return getImpl().getFilterDefinition( filterName );
+	}
+}

Added: trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/StatisticsService.java
===================================================================
--- trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/StatisticsService.java	                        (rev 0)
+++ trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/StatisticsService.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,317 @@
+//$Id: StatisticsService.java 8262 2005-09-30 07:48:53Z oneovthafew $
+package org.hibernate.jmx;
+
+import javax.naming.InitialContext;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.SessionFactory;
+import org.hibernate.impl.SessionFactoryObjectFactory;
+import org.hibernate.stat.CollectionStatistics;
+import org.hibernate.stat.EntityStatistics;
+import org.hibernate.stat.QueryStatistics;
+import org.hibernate.stat.SecondLevelCacheStatistics;
+import org.hibernate.stat.Statistics;
+import org.hibernate.stat.StatisticsImpl;
+
+/**
+ * JMX service for Hibernate statistics<br>
+ * <br>
+ * Register this MBean in your JMX server for a specific session factory
+ * <pre>
+ * //build the ObjectName you want
+ * Hashtable tb = new Hashtable();
+ * tb.put("type", "statistics");
+ * tb.put("sessionFactory", "myFinancialApp");
+ * ObjectName on = new ObjectName("hibernate", tb);
+ * StatisticsService stats = new StatisticsService();
+ * stats.setSessionFactory(sessionFactory);
+ * server.registerMBean(stats, on);
+ * </pre>
+ * And call the MBean the way you want<br>
+ * <br>
+ * Register this MBean in your JMX server with no specific session factory
+ * <pre>
+ * //build the ObjectName you want
+ * Hashtable tb = new Hashtable();
+ * tb.put("type", "statistics");
+ * tb.put("sessionFactory", "myFinancialApp");
+ * ObjectName on = new ObjectName("hibernate", tb);
+ * StatisticsService stats = new StatisticsService();
+ * server.registerMBean(stats, on);
+ * </pre>
+ * And call the MBean by providing the <code>SessionFactoryJNDIName</code> first.
+ * Then the session factory will be retrieved from JNDI and the statistics
+ * loaded.
+ * 
+ * @author Emmanuel Bernard
+ */
+public class StatisticsService implements StatisticsServiceMBean {
+	
+	//TODO: We probably should have a StatisticsNotPublishedException, to make it clean
+	
+	SessionFactory sf;
+	String sfJNDIName;
+	Log log = LogFactory.getLog(StatisticsService.class);
+	Statistics stats = new StatisticsImpl();
+
+	/**
+	 * @see StatisticsServiceMBean#setSessionFactoryJNDIName(java.lang.String)
+	 */
+	public void setSessionFactoryJNDIName(String sfJNDIName) {
+		this.sfJNDIName = sfJNDIName;
+		try {
+			Object obj = new InitialContext().lookup(sfJNDIName);
+			if (obj instanceof Reference) {
+				Reference ref = (Reference) obj;
+				setSessionFactory( (SessionFactory) SessionFactoryObjectFactory.getInstance( (String) ref.get(0).getContent() ) );
+			}
+			else {
+				setSessionFactory( (SessionFactory) obj );
+			} 
+		} 
+		catch (NameNotFoundException e) {
+			log.error("No session factory with JNDI name " + sfJNDIName, e);
+			setSessionFactory(null);
+		} 
+		catch (NamingException e) {
+			log.error("Error while accessing session factory with JNDI name " + sfJNDIName, e);
+			setSessionFactory(null);
+		} 
+		catch (ClassCastException e) {
+			log.error("JNDI name " + sfJNDIName + " does not handle a session factory reference", e);
+			setSessionFactory(null);
+		}
+	}
+	
+	/**
+	 * Useful to init this MBean wo a JNDI session factory name
+	 * 
+	 * @param sf session factory to register
+	 */
+	public void setSessionFactory(SessionFactory sf) {
+		this.sf = sf;
+		if (sf == null) {
+			stats = new StatisticsImpl();
+		}
+		else {
+			stats = sf.getStatistics(); 
+		}
+		
+	}
+	/**
+	 * @see StatisticsServiceMBean#clear()
+	 */
+	public void clear() {
+		stats.clear();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getEntityStatistics(java.lang.String)
+	 */
+	public EntityStatistics getEntityStatistics(String entityName) {
+		return stats.getEntityStatistics(entityName);
+	}
+	/**
+	 * @see StatisticsServiceMBean#getCollectionStatistics(java.lang.String)
+	 */
+	public CollectionStatistics getCollectionStatistics(String role) {
+		return stats.getCollectionStatistics(role);
+	}
+	/**
+	 * @see StatisticsServiceMBean#getSecondLevelCacheStatistics(java.lang.String)
+	 */
+	public SecondLevelCacheStatistics getSecondLevelCacheStatistics(String regionName) {
+		return stats.getSecondLevelCacheStatistics(regionName);
+	}
+	/**
+	 * @see StatisticsServiceMBean#getQueryStatistics(java.lang.String)
+	 */
+	public QueryStatistics getQueryStatistics(String hql) {
+		return stats.getQueryStatistics(hql);
+	}
+	/**
+	 * @see StatisticsServiceMBean#getEntityDeleteCount()
+	 */
+	public long getEntityDeleteCount() {
+		return stats.getEntityDeleteCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getEntityInsertCount()
+	 */
+	public long getEntityInsertCount() {
+		return stats.getEntityInsertCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getEntityLoadCount()
+	 */
+	public long getEntityLoadCount() {
+		return stats.getEntityLoadCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getEntityFetchCount()
+	 */
+	public long getEntityFetchCount() {
+		return stats.getEntityFetchCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getEntityUpdateCount()
+	 */
+	public long getEntityUpdateCount() {
+		return stats.getEntityUpdateCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getQueryExecutionCount()
+	 */
+	public long getQueryExecutionCount() {
+		return stats.getQueryExecutionCount();
+	}
+	public long getQueryCacheHitCount() {
+		return stats.getQueryCacheHitCount();
+	}
+	public long getQueryExecutionMaxTime() {
+		return stats.getQueryExecutionMaxTime();
+	}
+	public long getQueryCacheMissCount() {
+		return stats.getQueryCacheMissCount();
+	}
+	public long getQueryCachePutCount() {
+		return stats.getQueryCachePutCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getFlushCount()
+	 */
+	public long getFlushCount() {
+		return stats.getFlushCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getConnectCount()
+	 */
+	public long getConnectCount() {
+		return stats.getConnectCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getSecondLevelCacheHitCount()
+	 */
+	public long getSecondLevelCacheHitCount() {
+		return stats.getSecondLevelCacheHitCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getSecondLevelCacheMissCount()
+	 */
+	public long getSecondLevelCacheMissCount() {
+		return stats.getSecondLevelCacheMissCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getSecondLevelCachePutCount()
+	 */
+	public long getSecondLevelCachePutCount() {
+		return stats.getSecondLevelCachePutCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getSessionCloseCount()
+	 */
+	public long getSessionCloseCount() {
+		return stats.getSessionCloseCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getSessionOpenCount()
+	 */
+	public long getSessionOpenCount() {
+		return stats.getSessionOpenCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getCollectionLoadCount()
+	 */
+	public long getCollectionLoadCount() {
+		return stats.getCollectionLoadCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getCollectionFetchCount()
+	 */
+	public long getCollectionFetchCount() {
+		return stats.getCollectionFetchCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getCollectionUpdateCount()
+	 */
+	public long getCollectionUpdateCount() {
+		return stats.getCollectionUpdateCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getCollectionRemoveCount()
+	 */
+	public long getCollectionRemoveCount() {
+		return stats.getCollectionRemoveCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getCollectionRecreateCount()
+	 */
+	public long getCollectionRecreateCount() {
+		return stats.getCollectionRecreateCount();
+	}
+	/**
+	 * @see StatisticsServiceMBean#getStartTime()
+	 */
+	public long getStartTime() {
+		return stats.getStartTime();
+	}
+
+	/**
+	 * @see StatisticsServiceMBean#isStatisticsEnabled()
+	 */
+	public boolean isStatisticsEnabled() {
+		return stats.isStatisticsEnabled();
+	}
+
+	/**
+	 * @see StatisticsServiceMBean#setStatisticsEnabled(boolean)
+	 */
+	public void setStatisticsEnabled(boolean enable) {
+		stats.setStatisticsEnabled(enable);
+	}
+	
+	public void logSummary() {
+		stats.logSummary();
+	}
+
+	public String[] getCollectionRoleNames() {
+		return stats.getCollectionRoleNames();
+	}
+
+	public String[] getEntityNames() {
+		return stats.getEntityNames();
+	}
+
+	public String[] getQueries() {
+		return stats.getQueries();
+	}
+
+	public String[] getSecondLevelCacheRegionNames() {
+		return stats.getSecondLevelCacheRegionNames();
+	}
+	
+	public long getSuccessfulTransactionCount() {
+		return stats.getSuccessfulTransactionCount();
+	}
+	public long getTransactionCount() {
+		return stats.getTransactionCount();
+	}
+
+	public long getCloseStatementCount() {
+		return stats.getCloseStatementCount();
+	}
+	public long getPrepareStatementCount() {
+		return stats.getPrepareStatementCount();
+	}
+
+	public long getOptimisticFailureCount() {
+		return stats.getOptimisticFailureCount();
+	}
+
+	public String getQueryExecutionMaxTimeQueryString() {
+		return stats.getQueryExecutionMaxTimeQueryString();
+	}
+}

Added: trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/StatisticsServiceMBean.java
===================================================================
--- trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/StatisticsServiceMBean.java	                        (rev 0)
+++ trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/StatisticsServiceMBean.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+//$Id: StatisticsServiceMBean.java 4332 2004-08-15 12:55:28Z oneovthafew $
+package org.hibernate.jmx;
+
+import org.hibernate.stat.Statistics;
+
+/**
+ * MBean exposing Session Factory statistics
+ * 
+ * @see org.hibernate.stat.Statistics
+ * @author Emmanuel Bernard
+ */
+public interface StatisticsServiceMBean extends Statistics {
+	/**
+	 * Publish the statistics of a session factory bound to 
+	 * the default JNDI context
+	 * @param sfJNDIName session factory jndi name
+	 */
+	public abstract void setSessionFactoryJNDIName(String sfJNDIName);
+}
\ No newline at end of file

Added: trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/package.html
===================================================================
--- trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/package.html	                        (rev 0)
+++ trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,14 @@
+<html>
+<head></head>
+<body>
+<p>
+	This package exposes a Hibernate instance via JMX.
+</p>
+<p>
+	<tt>HibernateService</tt> allows configuration and management
+	of the Hibernate runtime. <tt>StatisticsService</tt>
+	reports information that might be useful for performance
+	tuning.
+</p>
+</body>
+</html>


Property changes on: trunk/Hibernate3/jmx/src/main/java/org/hibernate/jmx/package.html
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testing/pom.xml
===================================================================
--- trunk/Hibernate3/testing/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/testing/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.hibernate</groupId>
+    <artifactId>hibernate-testing</artifactId>
+    <packaging>jar</packaging>
+    <name>Hibernate Testing</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>3.8.1</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-core</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

Added: trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/AbstractClassLoaderIsolatedTestCase.java
===================================================================
--- trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/AbstractClassLoaderIsolatedTestCase.java	                        (rev 0)
+++ trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/AbstractClassLoaderIsolatedTestCase.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+package org.hibernate.junit;
+
+/**
+ * A specialized TestCase for running tests in an isolated class-loader
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractClassLoaderIsolatedTestCase extends UnitTestCase {
+	private ClassLoader parentLoader;
+	private ClassLoader isolatedLoader;
+
+	public AbstractClassLoaderIsolatedTestCase(String string) {
+		super( string );
+	}
+
+	protected void setUp() throws Exception {
+		parentLoader = Thread.currentThread().getContextClassLoader();
+		isolatedLoader = buildIsolatedClassLoader( parentLoader );
+		Thread.currentThread().setContextClassLoader( isolatedLoader );
+		super.setUp();
+	}
+
+	protected void tearDown() throws Exception {
+		super.tearDown();
+		Thread.currentThread().setContextClassLoader( parentLoader );
+		releaseIsolatedClassLoader( isolatedLoader );
+		parentLoader = null;
+		isolatedLoader = null;
+	}
+
+	protected abstract ClassLoader buildIsolatedClassLoader(ClassLoader parent);
+
+	protected abstract void releaseIsolatedClassLoader(ClassLoader isolatedLoader);
+}

Added: trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/SkipLog.java
===================================================================
--- trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/SkipLog.java	                        (rev 0)
+++ trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/SkipLog.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+package org.hibernate.junit;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Well-known-location lookup for the test-skip log...
+ *
+ * @author Steve Ebersole
+ */
+public class SkipLog {
+	public static final Log LOG = LogFactory.getLog( "org.hibernate.test.SKIPPED" );
+}

Added: trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/TestSuiteVisitor.java
===================================================================
--- trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/TestSuiteVisitor.java	                        (rev 0)
+++ trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/TestSuiteVisitor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+package org.hibernate.junit;
+
+import java.util.Enumeration;
+
+import junit.framework.TestSuite;
+import junit.framework.Test;
+
+/**
+ * Handles walking a TestSuite hierarchy for recognition of individual tests.
+ *
+ * @author Steve Ebersole
+ */
+public class TestSuiteVisitor {
+
+	private final TestSuiteVisitor.Handler handler;
+
+	public TestSuiteVisitor(TestSuiteVisitor.Handler handler) {
+		this.handler = handler;
+	}
+
+	public void visit(TestSuite testSuite) {
+		handler.startingTestSuite( testSuite );
+		Enumeration tests = testSuite.tests();
+		while ( tests.hasMoreElements() ) {
+			Test test = ( Test ) tests.nextElement();
+			if ( test instanceof TestSuite ) {
+				visit( ( TestSuite ) test );
+			}
+			else {
+				handler.handleTestCase( test );
+			}
+		}
+		handler.completedTestSuite( testSuite );
+	}
+
+	public static interface Handler {
+		public void handleTestCase(Test test);
+		public void startingTestSuite(TestSuite suite);
+		public void completedTestSuite(TestSuite suite);
+	}
+
+}

Added: trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/UnitTestCase.java
===================================================================
--- trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/UnitTestCase.java	                        (rev 0)
+++ trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/UnitTestCase.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,84 @@
+package org.hibernate.junit;
+
+import java.util.Iterator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import junit.framework.AssertionFailedError;
+
+
+/**
+ * A basic JUnit {@link junit.framework.TestCase} subclass for
+ * adding some Hibernate specific behavior and functionality.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class UnitTestCase extends junit.framework.TestCase {
+
+	private static final Log log = LogFactory.getLog( UnitTestCase.class );
+
+	public UnitTestCase(String string) {
+		super( string );
+	}
+
+	/**
+	 * runBare overridden in order to apply FailureExpected validations
+	 * as well as start/complete logging
+	 *
+	 * @throws Throwable
+	 */
+	public void runBare() throws Throwable {
+		final boolean doValidate = getName().endsWith( "FailureExpected" ) && Boolean.getBoolean( "hibernate.test.validatefailureexpected" );
+		try {
+			log.info( "Starting test [" + fullTestName() + "]" );
+			super.runBare();
+			if ( doValidate ) {
+				fail( "Test marked as FailureExpected, but did not fail!" );
+			}
+		}
+		catch( Throwable t ) {
+			if ( doValidate ) {
+				skipExpectedFailure( t );
+			}
+			else {
+				throw t;
+			}
+		}
+		finally {
+			log.info( "Completed test [" + fullTestName() + "]" );
+		}
+	}
+
+	protected void skipExpectedFailure(Throwable error) {
+		reportSkip( "ignoring *FailuredExpected methods", "Failed with: " + error.toString() );
+	}
+
+	// additional assertions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public static void assertElementTypeAssignability(java.util.Collection collection, Class clazz) throws AssertionFailedError {
+		Iterator itr = collection.iterator();
+		while ( itr.hasNext() ) {
+			assertClassAssignability( itr.next().getClass(), clazz );
+		}
+	}
+
+	public static void assertClassAssignability(Class source, Class target) throws AssertionFailedError {
+		if ( !target.isAssignableFrom( source ) ) {
+			throw new AssertionFailedError(
+			        "Classes were not assignment-compatible : source<" + source.getName() +
+			        "> target<" + target.getName() + ">"
+			);
+		}
+	}
+
+
+	// test skipping ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public String fullTestName() {
+		return this.getClass().getName() + "#" + this.getName();
+	}
+
+	protected void reportSkip(String reason, String testDescription) {
+		SkipLog.LOG.warn( "*** skipping [" + fullTestName() + "] - " + testDescription + " : " + reason, new Exception()  );
+	}
+}

Added: trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/DatabaseSpecificFunctionalTestCase.java
===================================================================
--- trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/DatabaseSpecificFunctionalTestCase.java	                        (rev 0)
+++ trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/DatabaseSpecificFunctionalTestCase.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+package org.hibernate.junit.functional;
+
+import org.hibernate.junit.SkipLog;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public abstract class DatabaseSpecificFunctionalTestCase extends FunctionalTestCase {
+	public DatabaseSpecificFunctionalTestCase(String string) {
+		super( string );
+	}
+
+	protected void runTest() throws Throwable {
+		// Note: this protection comes into play when running
+		// tests individually.  The suite as a whole is already
+		// "protected" by the fact that these tests are actually
+		// filtered out of the suite
+		if ( appliesTo( getDialect() ) ) {
+			super.runTest();
+		}
+		else {
+			SkipLog.LOG.warn( "skipping database-specific test [" + fullTestName() + "] for dialect [" + getDialect().getClass().getName() + "]" );
+		}
+	}
+}

Added: trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/ExecutionEnvironment.java
===================================================================
--- trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/ExecutionEnvironment.java	                        (rev 0)
+++ trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/ExecutionEnvironment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,161 @@
+package org.hibernate.junit.functional;
+
+import java.util.Iterator;
+import java.sql.Blob;
+import java.sql.Clob;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.Mappings;
+import org.hibernate.SessionFactory;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.Collection;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class ExecutionEnvironment {
+
+	public static final Dialect DIALECT = Dialect.getDialect();
+
+	private final ExecutionEnvironment.Settings settings;
+
+	private Configuration configuration;
+	private SessionFactory sessionFactory;
+	private boolean allowRebuild;
+
+	public ExecutionEnvironment(ExecutionEnvironment.Settings settings) {
+		this.settings = settings;
+	}
+
+	public boolean isAllowRebuild() {
+		return allowRebuild;
+	}
+
+	public void setAllowRebuild(boolean allowRebuild) {
+		this.allowRebuild = allowRebuild;
+	}
+
+	public Dialect getDialect() {
+		return DIALECT;
+	}
+
+	public Configuration getConfiguration() {
+		return configuration;
+	}
+
+	public SessionFactory getSessionFactory() {
+		return sessionFactory;
+	}
+
+	public void initialize() {
+		if ( sessionFactory != null ) {
+			throw new IllegalStateException( "attempt to initialize already initialized ExecutionEnvironment" );
+		}
+		if ( ! settings.appliesTo( getDialect() ) ) {
+			return;
+		}
+
+		Configuration configuration = new Configuration();
+		configuration.setProperty( Environment.CACHE_PROVIDER, "org.hibernate.cache.HashtableCacheProvider" );
+
+		settings.configure( configuration );
+
+		applyMappings( configuration );
+		applyCacheSettings( configuration );
+
+
+		if ( settings.createSchema() ) {
+			configuration.setProperty( Environment.HBM2DDL_AUTO, "create-drop" );
+		}
+
+		// make sure we use the same dialect...
+		configuration.setProperty( Environment.DIALECT, getDialect().getClass().getName() );
+
+		configuration.buildMappings();
+		settings.afterConfigurationBuilt( configuration.createMappings(), getDialect() );
+
+		SessionFactory sessionFactory = configuration.buildSessionFactory();
+		this.configuration = configuration;
+		this.sessionFactory = sessionFactory;
+
+		settings.afterSessionFactoryBuilt( ( SessionFactoryImplementor ) sessionFactory );
+	}
+
+	private void applyMappings(Configuration configuration) {
+		String[] mappings = settings.getMappings();
+		for ( int i = 0; i < mappings.length; i++ ) {
+			configuration.addResource( settings.getBaseForMappings() + mappings[i], ExecutionEnvironment.class.getClassLoader() );
+		}
+	}
+
+	private void applyCacheSettings(Configuration configuration) {
+		if ( settings.getCacheConcurrencyStrategy() != null ) {
+			Iterator iter = configuration.getClassMappings();
+			while ( iter.hasNext() ) {
+				PersistentClass clazz = (PersistentClass) iter.next();
+				Iterator props = clazz.getPropertyClosureIterator();
+				boolean hasLob = false;
+				while ( props.hasNext() ) {
+					Property prop = (Property) props.next();
+					if ( prop.getValue().isSimpleValue() ) {
+						String type = ( ( SimpleValue ) prop.getValue() ).getTypeName();
+						if ( "blob".equals(type) || "clob".equals(type) ) {
+							hasLob = true;
+						}
+						if ( Blob.class.getName().equals(type) || Clob.class.getName().equals(type) ) {
+							hasLob = true;
+						}
+					}
+				}
+				if ( !hasLob && !clazz.isInherited() && settings.overrideCacheStrategy() ) {
+					configuration.setCacheConcurrencyStrategy( clazz.getEntityName(), settings.getCacheConcurrencyStrategy() );
+				}
+			}
+			iter = configuration.getCollectionMappings();
+			while ( iter.hasNext() ) {
+				Collection coll = (Collection) iter.next();
+				configuration.setCollectionCacheConcurrencyStrategy( coll.getRole(), settings.getCacheConcurrencyStrategy() );
+			}
+		}
+	}
+
+	public void rebuild() {
+		if ( !allowRebuild ) {
+			return;
+		}
+		if ( sessionFactory != null ) {
+			sessionFactory.close();
+			sessionFactory = null;
+		}
+		sessionFactory = configuration.buildSessionFactory();
+		settings.afterSessionFactoryBuilt( ( SessionFactoryImplementor ) sessionFactory );
+	}
+
+	public void complete() {
+		if ( sessionFactory != null ) {
+			sessionFactory.close();
+			sessionFactory = null;
+		}
+		configuration = null;
+	}
+
+	public static interface Settings {
+		public String[] getMappings();
+		public String getBaseForMappings();
+		public boolean createSchema();
+		public boolean recreateSchemaAfterFailure();
+		public void configure(Configuration cfg);
+		public boolean overrideCacheStrategy();
+		public String getCacheConcurrencyStrategy();
+		public void afterSessionFactoryBuilt(SessionFactoryImplementor sfi);
+		public void afterConfigurationBuilt(Mappings mappings, Dialect dialect);
+		public boolean appliesTo(Dialect dialect);
+	}
+}

Added: trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/FunctionalTestCase.java
===================================================================
--- trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/FunctionalTestCase.java	                        (rev 0)
+++ trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/FunctionalTestCase.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,505 @@
+package org.hibernate.junit.functional;
+
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Mappings;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.DB2Dialect;
+import org.hibernate.dialect.DerbyDialect;
+import org.hibernate.SessionFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.Session;
+import org.hibernate.junit.UnitTestCase;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Most of the Hibernate test suite in fact is a series of functional tests, not
+ * unit tests.  Here is a base class for these functional tests.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class FunctionalTestCase extends UnitTestCase implements ExecutionEnvironment.Settings {
+
+	private static final Log log = LogFactory.getLog( FunctionalTestCase.class );
+
+	private ExecutionEnvironment environment;
+	private boolean isEnvironmentLocallyManaged;
+
+	private org.hibernate.classic.Session session;
+
+	public FunctionalTestCase(String string) {
+		super( string );
+	}
+
+	public ExecutionEnvironment getEnvironment() {
+		return environment;
+	}
+
+	public void setEnvironment(ExecutionEnvironment environment) {
+		this.environment = environment;
+	}
+
+	protected void prepareTest() throws Exception {
+	}
+
+	protected void cleanupTest() throws Exception {
+	}
+
+	// JUnit hooks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Override {@link junit.framework.TestCase#setUp()} to check if we need
+	 * to build a locally managed execution environment.
+	 *
+	 * @throws Exception
+	 */
+	protected final void setUp() throws Exception {
+		if ( environment == null ) {
+			log.info( "Building locally managed execution env" );
+			isEnvironmentLocallyManaged = true;
+			environment = new ExecutionEnvironment( this );
+			environment.initialize();
+		}
+		prepareTest();
+	}
+
+	/**
+	 * Override {@link junit.framework.TestCase#tearDown()} to tear down
+	 * the execution environment if it is locally managed.
+	 *
+	 * @throws Exception
+	 */
+	protected final void tearDown() throws Exception {
+		cleanupTest();
+		if ( isEnvironmentLocallyManaged ) {
+			log.info( "Destroying locally managed execution env" );
+			environment.complete();
+			environment = null;
+		}
+	}
+
+	/**
+	 * runTest is overridden in order to apply session closure assertions.
+	 *
+	 * @throws Throwable
+	 */
+	protected void runTest() throws Throwable {
+		final boolean stats = sfi().getStatistics().isStatisticsEnabled();
+		try {
+			if ( stats ) {
+				sfi().getStatistics().clear();
+			}
+
+			super.runTest();
+
+			if ( stats ) {
+				sfi().getStatistics().logSummary();
+			}
+
+			if ( session != null && session.isOpen() ) {
+				if ( session.isConnected() ) {
+					session.connection().rollback();
+				}
+				session.close();
+				session = null;
+				fail( "unclosed session" );
+			}
+			else {
+				session = null;
+			}
+			assertAllDataRemoved();
+		}
+		catch ( Throwable e ) {
+			log.trace( "test run resulted in error; attempting to cleanup", e );
+			try {
+				if ( session != null && session.isOpen() ) {
+					if ( session.isConnected() ) {
+						session.connection().rollback();
+					}
+					session.close();
+				}
+			}
+			catch ( Exception ignore ) {
+			}
+			try {
+				if ( recreateSchemaAfterFailure() && environment != null ) {
+					environment.rebuild();
+				}
+			}
+			catch ( Exception ignore ) {
+			}
+			throw e;
+		}
+	}
+
+	protected void assertAllDataRemoved() {
+		if ( !createSchema() ) {
+			return; // no tables were created...
+		}
+		if ( !Boolean.getBoolean( "hibernate.test.validateDataCleanup" ) ) {
+			return;
+		}
+
+		Session tmpSession = getSessions().openSession();
+		try {
+			List list = tmpSession.createQuery( "select o from java.lang.Object o" ).list();
+
+			Map items = new HashMap();
+			if ( !list.isEmpty() ) {
+				for ( Iterator iter = list.iterator(); iter.hasNext(); ) {
+					Object element = iter.next();
+					Integer l = ( Integer ) items.get( tmpSession.getEntityName( element ) );
+					if ( l == null ) {
+						l = new Integer( 0 );
+					}
+					l = new Integer( l.intValue() + 1 );
+					items.put( tmpSession.getEntityName( element ), l );
+					System.out.println( "Data left: " + element );
+				}
+				fail( "Data is left in the database: " + items.toString() );
+			}
+		}
+		finally {
+			try {
+				tmpSession.close();
+			}
+			catch( Throwable t ) {
+				// intentionally empty
+			}
+		}
+	}
+
+	protected void skipExpectedFailure(Throwable error) {
+		super.skipExpectedFailure( error );
+		try {
+			if ( recreateSchemaAfterFailure() && environment != null ) {
+				environment.rebuild();
+			}
+		}
+		catch ( Exception ignore ) {
+		}
+	}
+
+	// ExecutionEnvironment.Settings implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public String getBaseForMappings() {
+		return "org/hibernate/test/";
+	}
+
+	public boolean createSchema() {
+		return true;
+	}
+
+	public boolean recreateSchemaAfterFailure() {
+		return true;
+	}
+
+	public void configure(Configuration cfg) {
+	}
+
+	public boolean overrideCacheStrategy() {
+		return true;
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return "nonstrict-read-write";
+	}
+
+	public void afterSessionFactoryBuilt(SessionFactoryImplementor sfi) {
+	}
+
+	public void afterConfigurationBuilt(Mappings mappings, Dialect dialect) {
+	}
+
+	/**
+	 * Intended to indicate that this test class as a whole is intended for
+	 * a dialect or series of dialects.  Skips here (appliesTo = false) therefore
+	 * simply indicate that the given tests target a particular feature of the
+	 * checked database and none of the tests on this class should be run for the
+	 * checked dialect.
+	 *
+	 * @param dialect The dialect to be checked.
+	 * @return False if the test class as a whole is specifically targetting
+	 * a dialect (or series of dialects) other than the indicated dialect
+	 * and the test should therefore be skipped in its entirety;
+	 * true otherwise.
+	 */
+	public boolean appliesTo(Dialect dialect) {
+		return true;
+	}
+
+
+	// methods for subclasses to access environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Get the factory for this test environment.
+	 *
+	 * @return The factory.
+	 */
+	protected SessionFactory getSessions() {
+		return environment.getSessionFactory();
+	}
+
+	/**
+	 * Get the factory for this test environment, casted to {@link org.hibernate.engine.SessionFactoryImplementor}.
+	 * <p/>
+	 * Shorthand for ( {@link org.hibernate.engine.SessionFactoryImplementor} ) {@link #getSessions()}...
+	 *
+	 * @return The factory
+	 */
+	protected SessionFactoryImplementor sfi() {
+		return ( SessionFactoryImplementor ) getSessions();
+	}
+
+	protected Dialect getDialect() {
+		return ExecutionEnvironment.DIALECT;
+	}
+
+	protected Configuration getCfg() {
+		return environment.getConfiguration();
+	}
+
+	public org.hibernate.classic.Session openSession() throws HibernateException {
+		session = getSessions().openSession();
+		return session;
+	}
+
+	public org.hibernate.classic.Session openSession(Interceptor interceptor) throws HibernateException {
+		session = getSessions().openSession(interceptor);
+		return session;
+	}
+
+
+
+
+	/**
+	 * Is connection at least read committed?
+	 * <p/>
+	 * Not, that this skip check relies on the JDBC driver reporting
+	 * the true isolation level correctly.  HSQLDB, for example, will
+	 * report whatever you specify as the isolation
+	 * (Connection.setTransationIsolation()), even though it only supports
+	 * read-uncommitted.
+	 *
+	 * @param scenario text description of the scenario being tested.
+	 * @return true if read-committed isolation is maintained.
+	 */
+	protected boolean readCommittedIsolationMaintained(String scenario) {
+		int isolation = java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
+		Session testSession = null;
+		try {
+			testSession = openSession();
+			isolation = testSession.connection().getTransactionIsolation();
+		}
+		catch( Throwable ignore ) {
+		}
+		finally {
+			if ( testSession != null ) {
+				try {
+					testSession.close();
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+		}
+		if ( isolation < java.sql.Connection.TRANSACTION_READ_COMMITTED ) {
+			reportSkip( "environment does not support at least read committed isolation", scenario );
+			return false;
+		}
+		else {
+			return true;
+		}
+	}
+
+	/**
+	 * Does the db/dialect support using a column's physical name in the order-by clause
+	 * even after it has been aliased in the select clause.  This is not actually
+	 * required by the SQL spec, although virtually ever DB in the world supports this
+	 * (the most glaring omission here being IBM-variant DBs ala DB2 and Derby).
+	 *
+	 * @param testDescription description of the scenario being tested.
+	 * @return true if is allowed
+	 */
+	protected boolean allowsPhysicalColumnNameInOrderby(String testDescription) {
+		if ( DB2Dialect.class.isInstance( getDialect() ) ) {
+			// https://issues.apache.org/jira/browse/DERBY-1624
+			reportSkip( "Dialect does not support physical column name in order-by clause after it is aliased", testDescription );
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Does the db/dialect support using a column's physical name in the having clause
+	 * even after it has been aliased in the select/group-by clause.  This is not actually
+	 * required by the SQL spec, although virtually ever DB in the world supports this.
+	 *
+	 * @param testDescription description of the scenario being tested.
+	 * @return true if is allowed
+	 */
+	protected boolean allowsPhysicalColumnNameInHaving(String testDescription) {
+		// I only *know* of this being a limitation on Derby, although I highly suspect
+		// it is a limitation on any IBM/DB2 variant
+		if ( DerbyDialect.class.isInstance( getDialect() ) ) {
+			// https://issues.apache.org/jira/browse/DERBY-1624
+			reportSkip( "Dialect does not support physical column name in having clause after it is aliased", testDescription );
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Does the db/dialect support empty lists in the IN operator?
+	 * <p/>
+	 * For example, is "... a.b IN () ..." supported?
+	 *
+	 * @param testDescription description of the scenario being tested.
+	 * @return true if is allowed
+	 */
+	protected boolean dialectSupportsEmptyInList(String testDescription) {
+		if ( ! getDialect().supportsEmptyInList() ) {
+			reportSkip( "Dialect does not support SQL empty in list : x in ()", testDescription );
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Is the db/dialect sensitive in terms of string comparisons?
+	 * @param testDescription description of the scenario being tested.
+	 * @return true if sensitive
+	 */
+	protected boolean dialectIsCaseSensitive(String testDescription) {
+		if ( ! getDialect().areStringComparisonsCaseInsensitive() ) {
+			reportSkip( "Dialect is case sensitive. ", testDescription );
+			return true;
+		}
+		return false;
+	}
+
+	protected boolean supportsRowValueConstructorSyntaxInInList() {
+		if ( ! getDialect().supportsRowValueConstructorSyntaxInInList() ) {
+			reportSkip( "Dialect does not support 'tuple' syntax as part of an IN value list", "query support" );
+			return false;
+		}
+		return true;
+	}
+
+	protected boolean supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() {
+		if ( ! getDialect().supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() ) {
+			reportSkip( "Driver does not support 'position query' methods on forward-only cursors", "query support" );
+			return false;
+		}
+		return true;
+	}
+
+	protected boolean supportsCircularCascadeDelete() {
+		if ( ! getDialect().supportsCircularCascadeDeleteConstraints() ) {
+			reportSkip( "db/dialect does not support 'circular' cascade delete constraints", "cascade delete constraint support" );
+			return false;
+		}
+		return true;
+	}
+
+	protected boolean supportsSubselectOnLeftSideIn() {
+		if ( ! getDialect().supportsSubselectAsInPredicateLHS() ) {
+			reportSkip( "Database does not support (<subselect>) in ( ... ) ", "query support" );
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Expected LOB usage pattern is such that I can perform an insert
+	 * via prepared statement with a parameter binding for a LOB value
+	 * without crazy casting to JDBC driver implementation-specific classes...
+	 * <p/>
+	 * Part of the trickiness here is the fact that this is largely
+	 * driver dependent.  For Oracle, which is notoriously bad with
+	 * LOB support in their drivers actually does a pretty good job with
+	 * LOB support as of the 10.2.x versions of their drivers...
+	 *
+	 * @return True if expected usage pattern is support; false otherwise.
+	 */
+	protected boolean supportsExpectedLobUsagePattern() {
+		if ( ! getDialect().supportsExpectedLobUsagePattern() ) {
+			reportSkip( "database/driver does not support expected LOB usage pattern", "LOB support" );
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Does the current dialect support propogating changes to LOB
+	 * values back to the database?  Talking about mutating the
+	 * underlying value as opposed to supplying a new
+	 * LOB instance...
+	 *
+	 * @return True if the changes are propogated back to the
+	 * database; false otherwise.
+	 */
+	protected boolean supportsLobValueChangePropogation() {
+		if ( ! getDialect().supportsLobValueChangePropogation() ) {
+			reportSkip( "database/driver does not support propogating LOB value change back to database", "LOB support" );
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Is it supported to materialize a LOB locator outside the transaction in
+	 * which it was created?
+	 * <p/>
+	 * Again, part of the trickiness here is the fact that this is largely
+	 * driver dependent.
+	 * <p/>
+	 * NOTE: all database I have tested which {@link #supportsExpectedLobUsagePattern()}
+	 * also support the ability to materialize a LOB outside the owning transaction...
+	 *
+	 * @return True if unbounded materialization is supported; false otherwise.
+	 */
+	protected boolean supportsUnboundedLobLocatorMaterialization() {
+		if ( !getDialect().supportsUnboundedLobLocatorMaterialization() ) {
+			reportSkip( "database/driver does not support materializing a LOB locator outside the 'owning' transaction", "LOB support" );
+			return false;
+		}
+		return true;
+	}
+
+	protected boolean supportsSubqueryOnMutatingTable() {
+		if ( !getDialect().supportsSubqueryOnMutatingTable() ) {
+			reportSkip( "database/driver does not support referencing mutating table in subquery", "bulk DML support" );
+			return false;
+		}
+		return true;
+	}
+
+	protected boolean dialectIs(Class dialectClass) {
+		return dialectClass.isInstance( getDialect() );
+	}
+
+	protected boolean dialectIsOneOf(Class[] dialectClasses) {
+		for ( int i = 0; i < dialectClasses.length; i++ ) {
+			if ( dialectClasses[i].isInstance( getDialect() ) ) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	protected boolean dialectIsNot(Class dialectClass) {
+		return ! dialectIs( dialectClass );
+	}
+
+	protected boolean dialectIsNot(Class[] dialectClasses) {
+		return ! dialectIsOneOf( dialectClasses );
+	}
+}

Added: trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/FunctionalTestClassTestSuite.java
===================================================================
--- trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/FunctionalTestClassTestSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testing/src/main/java/org/hibernate/junit/functional/FunctionalTestClassTestSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,129 @@
+package org.hibernate.junit.functional;
+
+import junit.framework.TestSuite;
+import junit.framework.Test;
+import junit.framework.TestResult;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * A specialized {@link junit.framework.TestSuite} implementation intended
+ * for use as an aggregate for a single test class specifically for the purpose
+ * of maintaing a single {@link org.hibernate.SessionFactory} for executings all
+ * tests defined as part of the given functional test class.
+ *
+ * @author Steve Ebersole
+ */
+public class FunctionalTestClassTestSuite extends TestSuite {
+
+	private static final Log log = LogFactory.getLog( FunctionalTestClassTestSuite.class );
+
+	private ExecutionEnvironment.Settings settings;
+	private ExecutionEnvironment environment;
+	private Throwable environmentSetupError;
+	private int testCount;
+	private int testPosition;
+
+	public FunctionalTestClassTestSuite(Class testClass, String name) {
+		super( testClass, name );
+	}
+
+	public FunctionalTestClassTestSuite(Class testClass) {
+		this( testClass, testClass.getName() );
+	}
+
+	/**
+	 * Constructor form used during {@link org.hibernate.test.AllTests} filtering...
+	 *
+	 * @param name The name.
+	 */
+	private FunctionalTestClassTestSuite(String name) {
+		super( name );
+	}
+
+	public void addTest(Test test) {
+		log.trace( "adding test [" + test + "]" );
+		if ( settings == null ) {
+			if ( test instanceof ExecutionEnvironment.Settings ) {
+				settings = ( ExecutionEnvironment.Settings ) test;
+				// todo : we could also centralize the skipping of "database specific" tests here
+				// instead of duplicating this notion in AllTests and DatabaseSpecificFunctionalTestCase.
+				// as a test gets added, simply check to see if we should really add it via
+				// DatabaseSpecificFunctionalTestCase.appliesTo( ExecutionEnvironment.DIALECT )...
+			}
+		}
+		testCount++;
+		super.addTest( test );
+	}
+
+	public void run(TestResult testResult) {
+		if ( testCount == 0 ) {
+			// might be zero if database-specific...
+			return;
+		}
+		try {
+			log.info( "Starting test-suite [" + getName() + "]" );
+			setUp();
+			testPosition = 0;
+			super.run( testResult );
+		}
+		finally {
+			try {
+				tearDown();
+			}
+			catch( Throwable ignore ) {
+			}
+			log.info( "Completed test-suite [" + getName() + "]" );
+		}
+	}
+
+	public void runTest(Test test, TestResult testResult) {
+		testPosition++;
+		if ( environmentSetupError != null ) {
+			testResult.startTest( test );
+			testResult.addError( test, environmentSetupError );
+			testResult.endTest( test );
+			return;
+		}
+		if ( ! ( test instanceof FunctionalTestCase ) ) {
+			super.runTest( test, testResult );
+		}
+		else {
+			FunctionalTestCase functionalTest = ( ( FunctionalTestCase ) test );
+			try {
+				// disallow rebuilding the schema because this is the last test
+				// in this suite, thus it is about to get dropped immediately
+				// afterwards anyway...
+				environment.setAllowRebuild( testPosition < testCount );
+				functionalTest.setEnvironment( environment );
+				super.runTest( functionalTest, testResult );
+			}
+			finally {
+				functionalTest.setEnvironment( null );
+			}
+		}
+	}
+
+	protected void setUp() {
+		if ( settings == null ) {
+			return;
+		}
+		log.info( "Building aggregated execution environment" );
+		try {
+			environment = new ExecutionEnvironment( settings );
+			environment.initialize();
+		}
+		catch( Throwable t ) {
+			environmentSetupError = t;
+		}
+	}
+
+	protected void tearDown() {
+		if ( environment != null ) {
+			log.info( "Destroying aggregated execution environment" );
+			environment.complete();
+			this.environment = null;
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/pom.xml
===================================================================
--- trunk/Hibernate3/testsuite/pom.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/pom.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.hibernate</groupId>
+        <artifactId>hibernate-core-project</artifactId>
+        <version>3.3.0.beta1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.hibernate</groupId>
+    <artifactId>hibernate-testsuite</artifactId>
+    <packaging>jar</packaging>
+    <name>Hibernate Testsuite</name>
+    <description>The testsuite of Hibernate functionality</description>
+    <url>http://hibernate.org</url>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-testing</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-ehcache</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-jbosscache</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-oscache</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-swarmcache</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/AllTests.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/AllTests.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/AllTests.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,445 @@
+//$Id: AllTests.java 11496 2007-05-09 03:54:06Z steve.ebersole at jboss.com $
+package org.hibernate.test;
+
+import java.lang.reflect.Constructor;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.junit.TestSuiteVisitor;
+import org.hibernate.test.abstractembeddedcomponents.cid.AbstractCompositeIdTest;
+import org.hibernate.test.abstractembeddedcomponents.propertyref.AbstractComponentPropertyRefTest;
+import org.hibernate.test.any.AnyTypeTest;
+import org.hibernate.test.array.ArrayTest;
+import org.hibernate.test.ast.ASTIteratorTest;
+import org.hibernate.test.ast.ASTUtilTest;
+import org.hibernate.test.batchfetch.BatchFetchTest;
+import org.hibernate.test.bidi.AuctionTest;
+import org.hibernate.test.bidi.AuctionTest2;
+import org.hibernate.test.bytecode.BytecodeSuite;
+import org.hibernate.test.cache.CacheSuite;
+import org.hibernate.test.cascade.RefreshTest;
+import org.hibernate.test.cid.CompositeIdTest;
+import org.hibernate.test.collection.CollectionSuite;
+import org.hibernate.test.component.ComponentSuite;
+import org.hibernate.test.compositeelement.CompositeElementTest;
+import org.hibernate.test.connections.ConnectionsSuite;
+import org.hibernate.test.criteria.CriteriaQueryTest;
+import org.hibernate.test.cuk.CompositePropertyRefTest;
+import org.hibernate.test.cut.CompositeUserTypeTest;
+import org.hibernate.test.deletetransient.DeleteTransientEntityTest;
+import org.hibernate.test.dialect.functional.DialectFunctionalTestsSuite;
+import org.hibernate.test.dialect.unit.DialectUnitTestsSuite;
+import org.hibernate.test.discriminator.DiscriminatorTest;
+import org.hibernate.test.dynamicentity.interceptor.InterceptorDynamicEntityTest;
+import org.hibernate.test.dynamicentity.tuplizer.TuplizerDynamicEntityTest;
+import org.hibernate.test.ecid.EmbeddedCompositeIdTest;
+import org.hibernate.test.entitymode.EntityModeSuite;
+import org.hibernate.test.exception.SQLExceptionConversionTest;
+import org.hibernate.test.extralazy.ExtraLazyTest;
+import org.hibernate.test.filter.DynamicFilterTest;
+import org.hibernate.test.formulajoin.FormulaJoinTest;
+import org.hibernate.test.generated.GeneratedPropertySuite;
+import org.hibernate.test.generatedkeys.GeneratedKeysSuite;
+import org.hibernate.test.hql.HQLSuite;
+import org.hibernate.test.id.MultipleHiLoPerTableGeneratorTest;
+import org.hibernate.test.idbag.IdBagTest;
+import org.hibernate.test.idclass.IdClassTest;
+import org.hibernate.test.idprops.IdentifierPropertyReferencesTest;
+import org.hibernate.test.immutable.ImmutableTest;
+import org.hibernate.test.instrument.buildtime.InstrumentTest;
+import org.hibernate.test.instrument.runtime.CGLIBInstrumentationTest;
+import org.hibernate.test.instrument.runtime.JavassistInstrumentationTest;
+import org.hibernate.test.interceptor.InterceptorTest;
+import org.hibernate.test.interfaceproxy.InterfaceProxyTest;
+import org.hibernate.test.iterate.IterateTest;
+import org.hibernate.test.join.JoinTest;
+import org.hibernate.test.joinedsubclass.JoinedSubclassTest;
+import org.hibernate.test.joinfetch.JoinFetchTest;
+import org.hibernate.test.jpa.JPAComplianceSuite;
+import org.hibernate.test.keymanytoone.KeyManyToOneSuite;
+import org.hibernate.test.lazycache.InstrumentCacheTest;
+import org.hibernate.test.lazycache.InstrumentCacheTest2;
+import org.hibernate.test.lazyonetoone.LazyOneToOneTest;
+import org.hibernate.test.legacy.ABCProxyTest;
+import org.hibernate.test.legacy.ABCTest;
+import org.hibernate.test.legacy.CacheTest;
+import org.hibernate.test.legacy.ComponentNotNullTest;
+import org.hibernate.test.legacy.ConfigurationPerformanceTest;
+import org.hibernate.test.legacy.FooBarTest;
+import org.hibernate.test.legacy.FumTest;
+import org.hibernate.test.legacy.IJ2Test;
+import org.hibernate.test.legacy.IJTest;
+import org.hibernate.test.legacy.MapTest;
+import org.hibernate.test.legacy.MasterDetailTest;
+import org.hibernate.test.legacy.MultiTableTest;
+import org.hibernate.test.legacy.NonReflectiveBinderTest;
+import org.hibernate.test.legacy.OneToOneCacheTest;
+import org.hibernate.test.legacy.ParentChildTest;
+import org.hibernate.test.legacy.QueryByExampleTest;
+import org.hibernate.test.legacy.SQLFunctionsTest;
+import org.hibernate.test.legacy.SQLLoaderTest;
+import org.hibernate.test.legacy.StatisticsTest;
+import org.hibernate.test.lob.LobSuite;
+import org.hibernate.test.manytomany.ManyToManyTest;
+import org.hibernate.test.map.MapIndexFormulaTest;
+import org.hibernate.test.mapcompelem.MapCompositeElementTest;
+import org.hibernate.test.mapelemformula.MapElementFormulaTest;
+import org.hibernate.test.mapping.PersistentClassVisitorTest;
+import org.hibernate.test.mapping.ValueVisitorTest;
+import org.hibernate.test.mappingexception.MappingExceptionTest;
+import org.hibernate.test.mixed.MixedTest;
+import org.hibernate.test.naturalid.NaturalIdTest;
+import org.hibernate.test.ondelete.OnDeleteTest;
+import org.hibernate.test.onetomany.OneToManyTest;
+import org.hibernate.test.onetoone.OneToOneSuite;
+import org.hibernate.test.ops.OpsSuite;
+import org.hibernate.test.optlock.OptimisticLockTest;
+import org.hibernate.test.ordered.OrderByTest;
+import org.hibernate.test.orphan.OrphanSuite;
+import org.hibernate.test.pagination.PaginationTest;
+import org.hibernate.test.propertyref.PropertyRefSuite;
+import org.hibernate.test.proxy.ProxyTest;
+import org.hibernate.test.querycache.QueryCacheTest;
+import org.hibernate.test.readonly.ReadOnlyTest;
+import org.hibernate.test.rowid.RowIdTest;
+import org.hibernate.test.sorted.SortTest;
+import org.hibernate.test.sql.NativeSqlSupportSuite;
+import org.hibernate.test.stats.SessionStatsTest;
+import org.hibernate.test.stats.StatsTest;
+import org.hibernate.test.subclassfilter.DiscrimSubclassFilterTest;
+import org.hibernate.test.subclassfilter.JoinedSubclassFilterTest;
+import org.hibernate.test.subclassfilter.UnionSubclassFilterTest;
+import org.hibernate.test.subselect.SubselectTest;
+import org.hibernate.test.subselectfetch.SubselectFetchTest;
+import org.hibernate.test.ternary.TernaryTest;
+import org.hibernate.test.timestamp.TimestampTest;
+import org.hibernate.test.tm.CMTTest;
+import org.hibernate.test.typedmanytoone.TypedManyToOneTest;
+import org.hibernate.test.typedonetoone.TypedOneToOneTest;
+import org.hibernate.test.typeparameters.TypeParameterTest;
+import org.hibernate.test.unconstrained.UnconstrainedTest;
+import org.hibernate.test.unidir.BackrefTest;
+import org.hibernate.test.unionsubclass.UnionSubclassTest;
+import org.hibernate.test.usercollection.UserCollectionTypeSuite;
+import org.hibernate.test.util.UtilSuite;
+import org.hibernate.test.version.VersionTest;
+import org.hibernate.test.version.db.DbVersionTest;
+import org.hibernate.test.version.sybase.SybaseTimestampVersioningTest;
+import org.hibernate.test.where.WhereTest;
+import org.hibernate.test.insertordering.InsertOrderingTest;
+import org.hibernate.test.reattachment.ReattachmentSuite;
+
+/**
+ * @author Gavin King
+ */
+public class AllTests {
+
+	/**
+	 * Returns the entire test suite (both legacy and new
+	 *
+	 * @return the entire test suite
+	 */
+	public static Test suite() {
+		TestSuite suite = new TestSuite();
+		suite.addTest( NewTests.suite() );
+		suite.addTest( LegacyTests.suite() );
+		return suite;
+	}
+
+	/**
+	 * Returns the entire test suite (both legacy and new) w/o filtering
+	 *
+	 * @return the entire test suite
+	 */
+	public static Test unfilteredSuite() {
+		TestSuite suite = new TestSuite();
+		suite.addTest( NewTests.unfilteredSuite() );
+		suite.addTest( LegacyTests.unfilteredSuite() );
+		return suite;
+	}
+
+	/**
+	 * Runs the entire test suite.
+	 *
+	 * @param args n/a
+	 * @see #suite
+	 */
+	public static void main(String args[]) {
+		TestRunner.run( suite() );
+	}
+
+	/**
+	 * An inner class representing the new test suite.
+	 */
+	public static class NewTests {
+
+		/**
+		 * Returns the new test suite (filtered)
+		 *
+		 * @return the new test suite
+		 */
+		public static Test suite() {
+			return filter( ( TestSuite ) unfilteredSuite() );
+		}
+
+		/**
+		 * Returns the new test suite (unfiltered)
+		 *
+		 * @return the new test suite
+		 */
+		public static Test unfilteredSuite() {
+			TestSuite suite = new TestSuite("New tests suite");
+			suite.addTest( OpsSuite.suite() );
+			suite.addTest( NaturalIdTest.suite() );
+			suite.addTest( ComponentSuite.suite() );
+			suite.addTest( ProxyTest.suite() );
+			suite.addTest( VersionTest.suite() );
+			suite.addTest( TimestampTest.suite() );
+			suite.addTest( InterceptorTest.suite() );
+			suite.addTest( EmbeddedCompositeIdTest.suite() );
+			suite.addTest( ImmutableTest.suite() );
+			suite.addTest( ReadOnlyTest.suite() );
+			suite.addTest( IdClassTest.suite() );
+			suite.addTest( ArrayTest.suite() );
+			suite.addTest( TernaryTest.suite() );
+			suite.addTest( CollectionSuite.suite() );
+			suite.addTest( IdBagTest.suite() );
+			suite.addTest( MapCompositeElementTest.suite() );
+			suite.addTest( MapIndexFormulaTest.suite() );
+			suite.addTest( MapElementFormulaTest.suite() );
+			suite.addTest( BackrefTest.suite() );
+			suite.addTest( BatchFetchTest.suite() );
+			suite.addTest( CompositeIdTest.suite() );
+			suite.addTest( CompositeElementTest.suite() );
+			suite.addTest( CompositePropertyRefTest.suite() );
+			suite.addTest( FormulaJoinTest.suite() );
+			suite.addTest( DiscriminatorTest.suite() );
+			suite.addTest( EntityModeSuite.suite() );
+			suite.addTest( DynamicFilterTest.suite() );
+			suite.addTest( InterfaceProxyTest.suite() );
+			suite.addTest( OrphanSuite.suite() );
+			suite.addTest( JoinTest.suite() );
+			suite.addTest( JoinedSubclassTest.suite() );
+			suite.addTest( org.hibernate.test.unionsubclass2.UnionSubclassTest.suite() );
+			suite.addTest( MixedTest.suite() );
+			suite.addTest( OneToManyTest.suite() );
+			suite.addTest( ManyToManyTest.suite() );
+			suite.addTest( OneToOneSuite.suite() );
+			suite.addTest( OptimisticLockTest.suite() );
+			suite.addTest( PropertyRefSuite.suite() );
+			suite.addTest( NativeSqlSupportSuite.suite() );
+			suite.addTest( CriteriaQueryTest.suite() );
+			suite.addTest( SubselectTest.suite() );
+			suite.addTest( SubselectFetchTest.suite() );
+			suite.addTest( JoinFetchTest.suite() );
+			suite.addTest( UnionSubclassTest.suite() );
+			suite.addTest( ASTIteratorTest.suite() );
+			suite.addTest( HQLSuite.suite() );
+			suite.addTest( ASTUtilTest.suite() );
+			suite.addTest( CacheSuite.suite() );
+			suite.addTest( QueryCacheTest.suite() );
+			suite.addTest( CompositeUserTypeTest.suite() );
+			suite.addTest( TypeParameterTest.suite() );
+			suite.addTest( TypedOneToOneTest.suite() );
+			suite.addTest( TypedManyToOneTest.suite() );
+			suite.addTest( CMTTest.suite() );
+			suite.addTest( MultipleHiLoPerTableGeneratorTest.suite() );
+			suite.addTest( UnionSubclassFilterTest.suite() );
+			suite.addTest( JoinedSubclassFilterTest.suite() );
+			suite.addTest( DiscrimSubclassFilterTest.suite() );
+			suite.addTest( UnconstrainedTest.suite() );
+			suite.addTest( RowIdTest.suite() );
+			suite.addTest( OnDeleteTest.suite() );
+			suite.addTest( OrderByTest.suite() );
+			suite.addTest( SortTest.suite() );
+			suite.addTest( WhereTest.suite() );
+			suite.addTest( IterateTest.suite() );
+			suite.addTest( RefreshTest.suite() );
+			suite.addTest( ExtraLazyTest.suite() );
+			suite.addTest( StatsTest.suite() );
+			suite.addTest( SessionStatsTest.suite() );
+			suite.addTest( ConnectionsSuite.suite() );
+			suite.addTest( SQLExceptionConversionTest.suite() );
+			suite.addTest( ValueVisitorTest.suite() );
+			suite.addTest( PersistentClassVisitorTest.suite() );
+			suite.addTest( AuctionTest.suite() );
+			suite.addTest( AuctionTest2.suite() );
+			suite.addTest( PaginationTest.suite() );
+			suite.addTest( MappingExceptionTest.suite() );
+			if ( InstrumentTest.isRunnable() ) {
+				suite.addTest( InstrumentTest.suite() );
+			}
+			if ( LazyOneToOneTest.isRunnable() ) {
+				suite.addTest( LazyOneToOneTest.suite() );
+			}
+			if ( InstrumentCacheTest.isRunnable() ) {
+				suite.addTest( InstrumentCacheTest.suite() );
+			}
+			if ( InstrumentCacheTest2.isRunnable() ) {
+				suite.addTest( InstrumentCacheTest2.suite() );
+			}
+			suite.addTest( CGLIBInstrumentationTest.suite() );
+			suite.addTest( JavassistInstrumentationTest.suite() );
+			suite.addTest( SybaseTimestampVersioningTest.suite() );
+			suite.addTest( DbVersionTest.suite() );
+			suite.addTest( GeneratedPropertySuite.suite() );
+			suite.addTest( GeneratedKeysSuite.suite() );
+			suite.addTest( InterceptorDynamicEntityTest.suite() );
+			suite.addTest( TuplizerDynamicEntityTest.suite() );
+			suite.addTest( BytecodeSuite.suite() );
+			suite.addTest( JPAComplianceSuite.suite() );
+			suite.addTest( AbstractComponentPropertyRefTest.suite() );
+			suite.addTest( AbstractCompositeIdTest.suite() );
+			suite.addTest( UtilSuite.suite() );
+			suite.addTest( AnyTypeTest.suite() );
+			suite.addTest( LobSuite.suite() );
+			suite.addTest( IdentifierPropertyReferencesTest.suite() );
+			suite.addTest( DeleteTransientEntityTest.suite() );
+			suite.addTest( UserCollectionTypeSuite.suite() );
+			suite.addTest( KeyManyToOneSuite.suite() );
+			suite.addTest( DialectFunctionalTestsSuite.suite() );
+			suite.addTest( DialectUnitTestsSuite.suite() );
+			suite.addTest( InsertOrderingTest.suite() );
+			suite.addTest( ReattachmentSuite.suite() );
+
+			return suite;
+		}
+
+		/**
+		 * Runs the new test suite
+		 *
+		 * @param args n/a
+		 */
+		public static void main(String[] args) {
+			TestRunner.run( suite() );
+		}
+	}
+
+	/**
+	 * An inner class representing the legacy test suite.
+	 */
+	public static class LegacyTests {
+
+		/**
+		 * Returns the legacy test suite
+		 *
+		 * @return the legacy test suite
+		 */
+		public static Test suite() {
+			return filter( ( TestSuite ) unfilteredSuite() );
+		}
+
+		/**
+		 * Returns the legacy test suite
+		 *
+		 * @return the legacy test suite
+		 */
+		public static Test unfilteredSuite() {
+			TestSuite suite = new TestSuite("Legacy tests suite");
+			suite.addTest( FumTest.suite() );
+			suite.addTest( MasterDetailTest.suite() );
+			suite.addTest( ParentChildTest.suite() );
+			suite.addTest( ABCTest.suite() );
+			suite.addTest( ABCProxyTest.suite() );
+			suite.addTest( SQLFunctionsTest.suite() );
+			suite.addTest( SQLLoaderTest.suite() );
+			suite.addTest( MultiTableTest.suite() );
+			suite.addTest( MapTest.suite() );
+			suite.addTest( QueryByExampleTest.suite() );
+			suite.addTest( ComponentNotNullTest.suite() );
+			suite.addTest( IJTest.suite() );
+			suite.addTest( IJ2Test.suite() );
+			suite.addTest( FooBarTest.suite() );
+			suite.addTest( StatisticsTest.suite() );
+			suite.addTest( CacheTest.suite() );
+			suite.addTest( OneToOneCacheTest.suite() );
+			suite.addTest( NonReflectiveBinderTest.suite() );
+			suite.addTest( ConfigurationPerformanceTest.suite() ); // Added to ensure we can utilize the recommended performance tips ;)
+			return suite;
+		}
+
+		/**
+		 * Run the legacy test suite
+		 *
+		 * @param args n/a
+		 */
+		public static void main(String[] args) {
+			TestRunner.run( suite() );
+		}
+	}
+
+	private static TestSuite filter(TestSuite testSuite) {
+		FilterHandler handler = new FilterHandler();
+		TestSuiteVisitor visitor = new TestSuiteVisitor( handler );
+		visitor.visit( testSuite );
+		return handler.getFilteredTestSuite();
+	}
+
+	private static class TestSuiteStackEntry {
+		public final TestSuite testSuite;
+		public final TestSuiteStackEntry parentEntry;
+
+		public TestSuiteStackEntry(TestSuite testSuite, TestSuiteStackEntry parentEntry) {
+			this.testSuite = testSuite;
+			this.parentEntry = parentEntry;
+			if ( parentEntry != null ) {
+				parentEntry.testSuite.addTest( testSuite );
+			}
+		}
+	}
+
+	private static class FilterHandler implements TestSuiteVisitor.Handler {
+		private TestSuiteStackEntry topStackElement;
+		private TestSuiteStackEntry currentStackElement;
+		private Dialect dialect = Dialect.getDialect();
+
+		public void handleTestCase(Test test) {
+			if ( test instanceof TestCase ) {
+				TestCase hibernateTestCase = ( TestCase ) test;
+				if ( ! hibernateTestCase.appliesTo( dialect ) ) {
+					System.out.println( "skipping test [" + hibernateTestCase.fullTestName() + "] for dialect [" + dialect.getClass().getName() + "]" );
+				}
+				else {
+					currentStackElement.testSuite.addTest( test );
+				}
+			}
+			else {
+				currentStackElement.testSuite.addTest( test );
+			}
+		}
+
+		public void startingTestSuite(TestSuite suite) {
+			currentStackElement = new TestSuiteStackEntry( instantiateCopy( suite ), currentStackElement );
+			if ( topStackElement == null ) {
+				topStackElement = currentStackElement;
+			}
+		}
+
+		public void completedTestSuite(TestSuite suite) {
+			if ( currentStackElement != null ) {
+				currentStackElement = currentStackElement.parentEntry;
+			}
+		}
+
+		public TestSuite getFilteredTestSuite() {
+			return topStackElement.testSuite;
+		}
+
+		private static final Class[] EXPECTED_CTOR_SIG = new Class[] { String.class };
+
+		private TestSuite instantiateCopy(TestSuite suite) {
+			try {
+				Class testSuiteClass = suite.getClass();
+				Constructor ctor = testSuiteClass.getDeclaredConstructor( EXPECTED_CTOR_SIG );
+				ctor.setAccessible( true );
+				return ( TestSuite ) ctor.newInstance( new Object[]  { suite.getName() } );
+			}
+			catch ( Throwable t ) {
+				throw new RuntimeException( "Unable to build test suite copy [" + suite + "]", t );
+			}
+		}
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/FailureExpectedCollector.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/FailureExpectedCollector.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/FailureExpectedCollector.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+package org.hibernate.junit;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import junit.framework.TestSuite;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+import org.hibernate.test.AllTests;
+
+/**
+ * A simple class to collect the names of "failure expected" tests...
+ *
+ * @author Steve Ebersole
+ */
+public class FailureExpectedCollector {
+
+	public static void main(String[] args) {
+		Set testNames = collectAllFailureExpectedTestNames();
+		Iterator itr = testNames.iterator();
+		int i = 0;
+		while ( itr.hasNext() ) {
+			i++;
+			System.out.println( i + ") " + itr.next() );
+		}
+	}
+
+	public static Set collectAllFailureExpectedTestNames() {
+		Set names = new HashSet();
+		collectFailureExpectedTestNames( names, ( TestSuite ) AllTests.unfilteredSuite() );
+		return names;
+	}
+
+	public static void collectFailureExpectedTestNames(final Set names, TestSuite suite) {
+		TestSuiteVisitor.Handler handler = new TestSuiteVisitor.Handler() {
+			public void handleTestCase(Test test) {
+				TestCase testCase = ( TestCase ) test;
+				if ( testCase.getName().endsWith( "FailureExpected" ) ) {
+					names.add( testCase.getClass().getName() + "#" + testCase.getName() );
+				}
+			}
+			public void startingTestSuite(TestSuite suite) {}
+			public void completedTestSuite(TestSuite suite) {}
+		};
+		TestSuiteVisitor visitor = new TestSuiteVisitor( handler );
+		visitor.visit( suite );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/TestCase.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/TestCase.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/TestCase.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,616 @@
+//$Id: TestCase.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test;
+
+import java.sql.Blob;
+import java.sql.Clob;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.AssertionFailedError;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.DB2Dialect;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.DerbyDialect;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.SimpleValue;
+
+public abstract class TestCase extends junit.framework.TestCase {
+
+	private static SessionFactory sessions;
+	private static Configuration cfg;
+	private static Dialect dialect;
+	private static Class lastTestClass;
+	private org.hibernate.classic.Session session;
+
+	public TestCase(String name) {
+		super( name );
+	}
+
+
+	// methods for subclasses to change test environment ~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Get the mapping resources to be used to build the configuration.
+	 * <p/>
+	 * Resources should be relative to {@link #getBaseForMappings()}
+	 *
+	 * @return The mapping resources
+	 */
+	protected abstract String[] getMappings();
+
+	/**
+	 * The base name for relative mapping resources.  The default is
+	 * <tt>org/hibernate/test/</tt>
+	 *
+	 * @return the mapping resource base
+	 */
+	protected String getBaseForMappings() {
+		return "org/hibernate/test/";
+	}
+
+	/**
+	 * Should the database schema be (re)created
+	 *
+	 * @return True for auto export (including recreation on test failure).
+	 */
+	protected boolean recreateSchema() {
+		return true;
+	}
+
+	protected boolean dropAfterFailure() {
+		return true;
+	}
+
+	/**
+	 * Apply any test-specific configuration prior to building the factory.
+	 *
+	 * @param cfg The configuration which will be used to construct the factory.
+	 */
+	protected void configure(Configuration cfg) {
+	}
+
+	protected boolean overrideCacheStrategy() {
+		return true;
+	}
+
+	protected String getCacheConcurrencyStrategy() {
+		return "nonstrict-read-write";
+	}
+
+
+	// methods for subclasses to access environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Get the factory for this test environment.
+	 *
+	 * @return The factory.
+	 */
+	protected SessionFactory getSessions() {
+		return sessions;
+	}
+
+	/**
+	 * Get the factory for this test environment, casted to {@link SessionFactoryImplementor}.
+	 * <p/>
+	 * Shorthand for ( {@link SessionFactoryImplementor} ) {@link #getSessions()}...
+	 *
+	 * @return The factory
+	 */
+	protected SessionFactoryImplementor sfi() {
+		return ( SessionFactoryImplementor ) getSessions();
+	}
+
+	protected Dialect getDialect() {
+		if ( dialect == null ) {
+			dialect = Dialect.getDialect();
+		}
+		return dialect;
+	}
+
+	protected Configuration getCfg() {
+		return cfg;
+	}
+
+	public org.hibernate.classic.Session openSession() throws HibernateException {
+		session = getSessions().openSession();
+		return session;
+	}
+
+	public org.hibernate.classic.Session openSession(Interceptor interceptor)
+	throws HibernateException {
+		session = getSessions().openSession(interceptor);
+		return session;
+	}
+
+
+	// JUnit hooks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * The Hibernate test suite tries to only build the db schema once
+	 * per test class (not test case which = instance) hence all the
+	 * static vars.
+	 * <p/>
+	 * Here is the crux of that attempt.  We only build a factory when one was
+	 * not previously built, or when we start a new test class.
+	 *
+	 * @throws Exception
+	 */
+	protected void setUp() throws Exception {
+		if ( getSessions() == null || lastTestClass != getClass() ) {
+			buildSessionFactory();
+			lastTestClass = getClass();
+		}
+	}
+
+
+	private void buildSessionFactory() throws Exception {
+		if ( getSessions()!=null ) {
+			getSessions().close();
+		}
+
+		TestCase.dialect = Dialect.getDialect();
+		if ( ! appliesTo( getDialect() ) ) {
+			return;
+		}
+
+		try {
+
+			TestCase.cfg = new Configuration();
+			cfg.setProperty( Environment.CACHE_PROVIDER, "org.hibernate.cache.HashtableCacheProvider" );
+			if( recreateSchema() ) {
+				cfg.setProperty( Environment.HBM2DDL_AUTO, "create-drop" );
+			}
+			addMappings( getMappings(), cfg );
+			configure( cfg );
+
+			if ( getCacheConcurrencyStrategy() != null ) {
+				Iterator iter = cfg.getClassMappings();
+				while ( iter.hasNext() ) {
+					PersistentClass clazz = (PersistentClass) iter.next();
+					Iterator props = clazz.getPropertyClosureIterator();
+					boolean hasLob = false;
+					while ( props.hasNext() ) {
+						Property prop = (Property) props.next();
+						if ( prop.getValue().isSimpleValue() ) {
+							String type = ( (SimpleValue) prop.getValue() ).getTypeName();
+							if ( "blob".equals(type) || "clob".equals(type) ) hasLob = true;
+							if ( Blob.class.getName().equals(type) || Clob.class.getName().equals(type) ) hasLob = true;
+						}
+					}
+					if ( !hasLob && !clazz.isInherited() && overrideCacheStrategy() ) {
+						cfg.setCacheConcurrencyStrategy(
+								clazz.getEntityName(),
+								getCacheConcurrencyStrategy()
+							);
+					}
+				}
+				iter = cfg.getCollectionMappings();
+				while ( iter.hasNext() ) {
+					Collection coll = (Collection) iter.next();
+					cfg.setCollectionCacheConcurrencyStrategy(
+							coll.getRole(),
+							getCacheConcurrencyStrategy()
+						);
+				}
+			}
+
+			// make sure we use the same dialect...
+			cfg.setProperty( Environment.DIALECT, TestCase.dialect.getClass().getName() );
+			TestCase.sessions = cfg.buildSessionFactory();
+			afterSessionFactoryBuilt();
+		}
+		catch ( Exception e ) {
+			e.printStackTrace();
+			throw e;
+		}
+	}
+
+	protected void addMappings(String[] files, Configuration cfg) {
+		for ( int i = 0; i < files.length; i++ ) {
+			if ( !files[i].startsWith( "net/" ) ) {
+				files[i] = getBaseForMappings() + files[i];
+			}
+			cfg.addResource( files[i], TestCase.class.getClassLoader() );
+		}
+	}
+
+	protected void afterSessionFactoryBuilt() throws Exception {
+		// for subclasses to override in order to perform extra "stuff" only
+		// when SF (re)built...
+	}
+
+	protected void runTest() throws Throwable {
+		final boolean stats = sessions.getStatistics().isStatisticsEnabled();
+		try {
+			if ( stats ) {
+				sessions.getStatistics().clear();
+			}
+
+			super.runTest();
+
+			if ( stats ) {
+				sessions.getStatistics().logSummary();
+			}
+
+			if ( session != null && session.isOpen() ) {
+				if ( session.isConnected() ) {
+					session.connection().rollback();
+				}
+				session.close();
+				session = null;
+				fail( "unclosed session" );
+			}
+			else {
+				session = null;
+			}
+			assertAllDataRemoved();
+		}
+		catch ( Throwable e ) {
+			try {
+				if ( session != null && session.isOpen() ) {
+					if ( session.isConnected() ) {
+						session.connection().rollback();
+					}
+					session.close();
+				}
+			}
+			catch ( Exception ignore ) {
+			}
+			try {
+				if ( dropAfterFailure() && sessions != null ) {
+					sessions.close();
+					sessions = null;
+				}
+			}
+			catch ( Exception ignore ) {
+			}
+			throw e;
+		}
+	}
+
+	public void runBare() throws Throwable {
+		String sysPropName = "hibernate.test.validatefailureexpected";
+		assertNotNull( getName() );
+		if ( Boolean.getBoolean( sysPropName ) ) {
+			if ( getName().endsWith( "FailureExpected" ) ) {
+				Throwable t = null;
+				try {
+					super.runBare();
+				}
+				catch ( Throwable afe ) {
+					t = afe;
+				}
+				if ( t == null ) {
+					fail( "Test where marked as FailureExpected, but did not fail!" );
+				}
+				else {
+					reportSkip( "ignoring *FailuredExpected methods", "Failed with: " + t.toString() );
+				}
+			}
+			else {
+				super.runBare();
+			}
+		}
+		else {
+			super.runBare();
+		}
+	}
+
+	protected void assertAllDataRemoved() {
+		if ( !recreateSchema() ) {
+			return; // no tables were created...
+		}
+		if ( !Boolean.getBoolean( "hibernate.test.validateDataCleanup" ) ) {
+			return;
+		}
+
+		Session tmpSession = sessions.openSession();
+		try {
+			List list = tmpSession.createQuery( "select o from java.lang.Object o" ).list();
+
+			Map items = new HashMap();
+			if ( !list.isEmpty() ) {
+				for ( Iterator iter = list.iterator(); iter.hasNext(); ) {
+					Object element = iter.next();
+					Integer l = ( Integer ) items.get( tmpSession.getEntityName( element ) );
+					if ( l == null ) {
+						l = new Integer( 0 );
+					}
+					l = new Integer( l.intValue() + 1 );
+					items.put( tmpSession.getEntityName( element ), l );
+					System.out.println( "Data left: " + element );
+				}
+				fail( "Data is left in the database: " + items.toString() );
+			}
+		}
+		finally {
+			try {
+				tmpSession.close();
+			}
+			catch( Throwable t ) {
+				// intentionally empty
+			}
+		}
+	}
+
+	public static void assertElementTypeAssignability(java.util.Collection collection, Class clazz) throws AssertionFailedError {
+		Iterator itr = collection.iterator();
+		while ( itr.hasNext() ) {
+			assertClassAssignability( itr.next().getClass(), clazz );
+		}
+	}
+
+	public static void assertClassAssignability(Class source, Class target) throws AssertionFailedError {
+		if ( !target.isAssignableFrom( source ) ) {
+			throw new AssertionFailedError(
+			        "Classes were not assignment-compatible : source<" + source.getName() +
+			        "> target<" + target.getName() + ">"
+			);
+		}
+	}
+
+
+	// test skipping ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	protected static final Log SKIP_LOG = LogFactory.getLog("org.hibernate.test.SKIPPED");
+
+	public String fullTestName() {
+		return this.getName() + " (" + this.getClass().getName() + ")";
+	}
+
+	protected void reportSkip(String reason, String testDescription) {
+		SKIP_LOG.warn( "*** skipping [" + fullTestName() + "] - " + testDescription + " : " + reason, new Exception()  );
+	}
+
+	/**
+	 * Intended to indicate that this test class as a whole is intended for
+	 * a dialect or series of dialects.  Skips here (appliesTo = false) therefore
+	 * simply indicate that the given tests target a particular feature of the
+	 * checked database and none of the tests on this class should be run for the
+	 * checked dialect.
+	 *
+	 * @param dialect The dialect to be checked.
+	 * @return True if all the tests on this class apply to the given dialect (and
+	 * therefore should be run); false otherwise.
+	 */
+	public boolean appliesTo(Dialect dialect) {
+		return true;
+	}
+
+	/**
+	 * Is connection at least read committed?
+	 * <p/>
+	 * Not, that this skip check relies on the JDBC driver reporting
+	 * the true isolation level correctly.  HSQLDB, for example, will
+	 * report whatever you specify as the isolation
+	 * (Connection.setTransationIsolation()), even though it only supports
+	 * read-uncommitted.
+	 *
+	 * @param scenario text description of the scenario being tested.
+	 * @return true if read-committed isolation is maintained.
+	 */
+	protected boolean readCommittedIsolationMaintained(String scenario) {
+		int isolation = java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
+		Session testSession = null;
+		try {
+			testSession = openSession();
+			isolation = testSession.connection().getTransactionIsolation();
+		}
+		catch( Throwable ignore ) {
+		}
+		finally {
+			if ( testSession != null ) {
+				try {
+					testSession.close();
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+		}
+		if ( isolation < java.sql.Connection.TRANSACTION_READ_COMMITTED ) {
+			reportSkip( "environment does not support at least read committed isolation", scenario );
+			return false;
+		}
+		else {
+			return true;
+		}
+	}
+
+	/**
+	 * Does the db/dialect support using a column's physical name in the order-by clause
+	 * even after it has been aliased in the select clause.  This is not actually
+	 * required by the SQL spec, although virtually ever DB in the world supports this
+	 * (the most glaring omission here being IBM-variant DBs ala DB2 and Derby).
+	 *
+	 * @param testDescription description of the scenario being tested.
+	 * @return true if is allowed
+	 */
+	protected boolean allowsPhysicalColumnNameInOrderby(String testDescription) {
+		if ( DB2Dialect.class.isInstance( getDialect() ) ) {
+			// https://issues.apache.org/jira/browse/DERBY-1624
+			reportSkip( "Dialect does not support physical column name in order-by clause after it is aliased", testDescription );
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Does the db/dialect support using a column's physical name in the having clause
+	 * even after it has been aliased in the select/group-by clause.  This is not actually
+	 * required by the SQL spec, although virtually ever DB in the world supports this.
+	 *
+	 * @param testDescription description of the scenario being tested.
+	 * @return true if is allowed
+	 */
+	protected boolean allowsPhysicalColumnNameInHaving(String testDescription) {
+		// I only *know* of this being a limitation on Derby, although I highly suspect
+		// it is a limitation on any IBM/DB2 variant
+		if ( DerbyDialect.class.isInstance( getDialect() ) ) {
+			// https://issues.apache.org/jira/browse/DERBY-1624
+			reportSkip( "Dialect does not support physical column name in having clause after it is aliased", testDescription );
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Does the db/dialect support empty lists in the IN operator?
+	 * <p/>
+	 * For example, is "... a.b IN () ..." supported?
+	 *
+	 * @param testDescription description of the scenario being tested.
+	 * @return true if is allowed
+	 */
+	protected boolean dialectSupportsEmptyInList(String testDescription) {
+		if ( ! getDialect().supportsEmptyInList() ) {
+			reportSkip( "Dialect does not support SQL empty in list : x in ()", testDescription );
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Is the db/dialect sensitive in terms of string comparisons?
+	 * @param testDescription description of the scenario being tested.
+	 * @return true if sensitive
+	 */
+	protected boolean dialectIsCaseSensitive(String testDescription) {
+		if ( getDialect().areStringComparisonsCaseInsensitive() ) {
+			reportSkip( "Dialect is case sensitive. ", testDescription );
+			return true;
+		}
+		return false;
+	}
+
+	protected boolean supportsRowValueConstructorSyntaxInInList() {
+		if ( ! getDialect().supportsRowValueConstructorSyntaxInInList() ) {
+			reportSkip( "Dialect does not support 'tuple' syntax as part of an IN value list", "query support" );
+			return false;
+		}
+		return true;
+	}
+
+	protected boolean supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() {
+		if ( ! getDialect().supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() ) {
+			reportSkip( "Driver does not support 'position query' methods on forward-only cursors", "query support" );
+			return false;
+		}
+		return true;
+	}
+
+	protected boolean supportsCircularCascadeDelete() {
+		if ( ! getDialect().supportsCircularCascadeDeleteConstraints() ) {
+			reportSkip( "db/dialect does not support 'circular' cascade delete constraints", "cascade delete constraint support" );
+			return false;
+		}
+		return true;
+	}
+	
+	protected boolean supportsSubselectOnLeftSideIn() {
+		if ( ! getDialect().supportsSubselectAsInPredicateLHS() ) {
+			reportSkip( "Database does not support (<subselect>) in ( ... ) ", "query support" );
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Expected LOB usage pattern is such that I can perform an insert
+	 * via prepared statement with a parameter binding for a LOB value
+	 * without crazy casting to JDBC driver implementation-specific classes...
+	 * <p/>
+	 * Part of the trickiness here is the fact that this is largely
+	 * driver dependent.  For Oracle, which is notoriously bad with
+	 * LOB support in their drivers actually does a pretty good job with
+	 * LOB support as of the 10.2.x versions of their drivers...
+	 *
+	 * @return True if expected usage pattern is support; false otherwise.
+	 */
+	protected boolean supportsExpectedLobUsagePattern() {
+		if ( ! getDialect().supportsExpectedLobUsagePattern() ) {
+			reportSkip( "database/driver does not support expected LOB usage pattern", "LOB support" );
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Does the current dialect support propogating changes to LOB
+	 * values back to the database?  Talking about mutating the
+	 * underlying value as opposed to supplying a new
+	 * LOB instance...
+	 *
+	 * @return True if the changes are propogated back to the
+	 * database; false otherwise.
+	 */
+	protected boolean supportsLobValueChangePropogation() {
+		if ( ! getDialect().supportsLobValueChangePropogation() ) {
+			reportSkip( "database/driver does not support propogating LOB value change back to database", "LOB support" );
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Is it supported to materialize a LOB locator outside the transaction in
+	 * which it was created?
+	 * <p/>
+	 * Again, part of the trickiness here is the fact that this is largely
+	 * driver dependent.
+	 * <p/>
+	 * NOTE: all database I have tested which {@link #supportsExpectedLobUsagePattern()}
+	 * also support the ability to materialize a LOB outside the owning transaction...
+	 *
+	 * @return True if unbounded materialization is supported; false otherwise.
+	 */
+	protected boolean supportsUnboundedLobLocatorMaterialization() {
+		if ( !getDialect().supportsUnboundedLobLocatorMaterialization() ) {
+			reportSkip( "database/driver does not support materializing a LOB locator outside the 'owning' transaction", "LOB support" );
+			return false;
+		}
+		return true;
+	}
+
+	protected boolean supportsSubqueryOnMutatingTable() {
+		if ( !getDialect().supportsSubqueryOnMutatingTable() ) {
+			reportSkip( "database/driver does not support referencing mutating table in subquery", "bulk DML support" );
+			return false;
+		}
+		return true;
+	}
+
+	protected boolean dialectIs(Class dialectClass) {
+		return dialectClass.isInstance( getDialect() );
+	}
+
+	protected boolean dialectIsOneOf(Class[] dialectClasses) {
+		for ( int i = 0; i < dialectClasses.length; i++ ) {
+			if ( dialectClasses[i].isInstance( getDialect() ) ) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	protected boolean dialectIsNot(Class dialectClass) {
+		return ! dialectIs( dialectClass );
+	}
+
+	protected boolean dialectIsNot(Class[] dialectClasses) {
+		return ! dialectIsOneOf( dialectClasses );
+	}
+
+}
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/TestSelector.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/TestSelector.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/TestSelector.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+package org.hibernate.test;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.io.File;
+
+import org.apache.tools.ant.types.selectors.FileSelector;
+import org.apache.tools.ant.BuildException;
+
+import org.hibernate.junit.TestSuiteVisitor;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * A custom Ant FileSelector used to limit the tests run from the Ant
+ * build script to only those defined in the {@link org.hibernate.test.AllTests} suite.
+ * <p/>
+ * {@link org.hibernate.test.AllTests} is used/maintained by the developers to easily
+ * run the test suite in all IDEs.  It represents all the tests
+ * which should actually be run and included in test results.
+ *
+ * @author Steve Ebersole
+ */
+public class TestSelector implements FileSelector {
+
+	private final Set allTestClassNames = new HashSet();
+
+	public TestSelector() {
+		TestSuiteVisitor.Handler handler = new TestSuiteVisitor.Handler() {
+			public void handleTestCase(Test test) {
+				allTestClassNames.add( test.getClass().getName() );
+			}
+			public void startingTestSuite(TestSuite suite) {}
+			public void completedTestSuite(TestSuite suite) {}
+		};
+		TestSuiteVisitor visitor = new TestSuiteVisitor( handler );
+		visitor.visit( ( TestSuite ) AllTests.suite() );
+	}
+
+
+	// FileSelector impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean isSelected(File dir, String fileFromDir, File fullFile) throws BuildException {
+		String correspondingClassName = determineClassName( fileFromDir );
+		return allTestClassNames.contains( correspondingClassName );
+	}
+
+	private String determineClassName(String file) {
+		if ( file.endsWith( ".class" ) ) {
+			file = file.substring( 0, file.length() - 6 );
+		}
+		else if ( file.endsWith( ".java" ) ) {
+			file = file.substring( 0, file.length() - 5 );
+		}
+		else {
+			return null;
+		}
+		file = file.replace( '\\', '.' );
+		file = file.replace( '/', '.' );
+		return file;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/AbstractCompositeIdTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/AbstractCompositeIdTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/AbstractCompositeIdTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+package org.hibernate.test.abstractembeddedcomponents.cid;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+import junit.framework.Test;
+
+/**
+ * @author Steve Ebersole
+ */
+public class AbstractCompositeIdTest extends FunctionalTestCase {
+	public AbstractCompositeIdTest(String x) {
+		super( x );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( AbstractCompositeIdTest.class );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "abstractembeddedcomponents/cid/Mappings.hbm.xml" };
+	}
+
+	public void testEmbeddedCompositeIdentifierOnAbstractClass() {
+		MyInterfaceImpl myInterface = new MyInterfaceImpl();
+		myInterface.setKey1( "key1" );
+		myInterface.setKey2( "key2" );
+		myInterface.setName( "test" );
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.save( myInterface );
+		s.flush();
+
+		s.createQuery( "from MyInterface" ).list();
+
+		s.delete( myInterface );
+		t.commit();
+		s.close();
+
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.abstractembeddedcomponents.cid">
+
+    <class name="MyInterface" table="MY_INTF" proxy="MyInterface">
+        <composite-id>
+            <key-property name="key1" type="string"/>
+            <key-property name="key2" type="string"/>
+        </composite-id>
+        <discriminator column="TYPE" type="string" length="10"/>
+        <property name="name" type="string"/>
+    </class>
+
+    <subclass name="MyInterfaceImpl" extends="MyInterface" discriminator-value="1" proxy="MyInterface">
+    </subclass>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/MyInterface.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/MyInterface.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/MyInterface.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+package org.hibernate.test.abstractembeddedcomponents.cid;
+
+import java.io.Serializable;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface MyInterface extends Serializable {
+	public String getKey1();
+	public void setKey1(String key1);
+	public String getKey2();
+	public void setKey2(String key2);
+	public String getName();
+	public void setName(String name);
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/MyInterfaceImpl.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/MyInterfaceImpl.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/cid/MyInterfaceImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+package org.hibernate.test.abstractembeddedcomponents.cid;
+
+import org.hibernate.test.abstractembeddedcomponents.cid.MyInterface;
+
+/**
+ * @author Steve Ebersole
+ */
+public class MyInterfaceImpl implements MyInterface {
+	private String key1;
+	private String key2;
+	private String name;
+
+	public String getKey1() {
+		return key1;
+	}
+
+	public void setKey1(String key1) {
+		this.key1 = key1;
+	}
+
+	public String getKey2() {
+		return key2;
+	}
+
+	public void setKey2(String key2) {
+		this.key2 = key2;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/AbstractComponentPropertyRefTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/AbstractComponentPropertyRefTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/AbstractComponentPropertyRefTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+package org.hibernate.test.abstractembeddedcomponents.propertyref;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+import junit.framework.Test;
+
+/**
+ * @author Steve Ebersole
+ */
+public class AbstractComponentPropertyRefTest extends FunctionalTestCase {
+	public AbstractComponentPropertyRefTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( AbstractComponentPropertyRefTest.class );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "abstractembeddedcomponents/propertyref/Mappings.hbm.xml" };
+	}
+
+	public void testPropertiesRefCascades() {
+		Session session = openSession();
+		Transaction trans = session.beginTransaction();
+		ServerImpl server = new ServerImpl();
+		session.save( server );
+		AddressImpl address = new AddressImpl();
+		server.setAddress( address );
+		address.setServer( server );
+		session.flush();
+		session.createQuery( "from Server s join fetch s.address" ).list();
+		trans.commit();
+		session.close();
+
+		assertNotNull( server.getId() );
+		assertNotNull( address.getId() );
+
+		session = openSession();
+		trans = session.beginTransaction();
+		session.delete( address );
+		session.delete( server );
+		trans.commit();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+package org.hibernate.test.abstractembeddedcomponents.propertyref;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface Address {
+	public Long getId();
+	public void setId(Long id);
+	public String getAddressType();
+	public void setAddressType(String addressType);
+	public Server getServer();
+	public void setServer(Server server);
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/AddressImpl.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/AddressImpl.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/AddressImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+package org.hibernate.test.abstractembeddedcomponents.propertyref;
+
+import org.hibernate.test.abstractembeddedcomponents.propertyref.Address;
+
+/**
+ * @author Steve Ebersole
+ */
+public class AddressImpl implements Address {
+	private Long id;
+	private String addressType;
+	private Server server;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getAddressType() {
+		return addressType;
+	}
+
+	public void setAddressType(String addressType) {
+		this.addressType = addressType;
+	}
+
+	public Server getServer() {
+		return server;
+	}
+
+	public void setServer(Server server) {
+		this.server = server;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.abstractembeddedcomponents.propertyref">
+
+    <class name="Address" table="ADDRESS" proxy="Address">
+        <id name="id" type="long" column="ADDRESS_ID">
+            <generator class="native"/>
+        </id>
+        <discriminator column="ADDRESS_TYPE" type="string" length="30"/>
+        <properties name="uniqueAddress">
+            <property name="addressType" column="ADDRESS_TYPE" type="string" insert="false" update="false" length="30"/>
+            <many-to-one name="server" column="SERVER_ID" class="Server" not-null="true"/>
+        </properties>
+    </class>
+
+    <subclass name="AddressImpl" extends="Address" discriminator-value="2" proxy="Address">
+    </subclass>
+
+    <class name="Server" table="SERVER" proxy="Server">
+        <id name="id" type="long" column="SERVER_ID">
+            <generator class="native"/>
+        </id>
+        <discriminator column="SERVER_TYPE" type="string" length="10"/>
+        <property name="serverType" type="string" column="SERVER_TYPE" length="10" update="false" insert="false"/>
+    </class>
+
+    <subclass name="ServerImpl" extends="Server" discriminator-value="1" proxy="Server">
+        <many-to-one name="address"
+                     class="AddressImpl"
+                     property-ref="uniqueAddress"
+                     cascade="all"
+                     unique="true"
+                     update="false"
+                     insert="false">
+            <column name="ADDRESS_TYPE"/>
+            <column name="SERVER_ID"/>
+        </many-to-one>
+    </subclass>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/Server.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/Server.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/Server.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+package org.hibernate.test.abstractembeddedcomponents.propertyref;
+
+import org.hibernate.test.abstractembeddedcomponents.propertyref.Address;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface Server {
+	public Long getId();
+	public void setId(Long id);
+	public String getServerType();
+	public void setServerType(String serverType);
+	public Address getAddress();
+	public void setAddress(Address address);
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/ServerImpl.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/ServerImpl.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/abstractembeddedcomponents/propertyref/ServerImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+package org.hibernate.test.abstractembeddedcomponents.propertyref;
+
+import org.hibernate.test.abstractembeddedcomponents.propertyref.Address;
+import org.hibernate.test.abstractembeddedcomponents.propertyref.Server;
+
+/**
+ * @author Steve Ebersole
+ */
+public class ServerImpl implements Server {
+	private Long id;
+	private String serverType;
+	private Address address;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getServerType() {
+		return serverType;
+	}
+
+	public void setServerType(String serverType) {
+		this.serverType = serverType;
+	}
+
+	public Address getAddress() {
+		return address;
+	}
+
+	public void setAddress(Address address) {
+		this.address = address;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+package org.hibernate.test.any;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * todo: describe Address
+ *
+ * @author Steve Ebersole
+ */
+public class Address {
+	private Long id;
+	private Set lines = new HashSet();
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Set getLines() {
+		return lines;
+	}
+
+	public void setLines(Set lines) {
+		this.lines = lines;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/AnyTypeTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/AnyTypeTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/AnyTypeTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,59 @@
+package org.hibernate.test.any;
+
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.junit.functional.FunctionalTestCase;
+
+import junit.framework.Test;
+
+/**
+ * todo: describe AnyTypeTest
+ *
+ * @author Steve Ebersole
+ */
+public class AnyTypeTest extends FunctionalTestCase {
+	public AnyTypeTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "any/Person.hbm.xml" };
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		// having second level cache causes a condition whereby the original test case would not fail...
+		return null;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( AnyTypeTest.class );
+	}
+
+	/**
+	 * Specific test for HHH-1663...
+	 */
+	public void testFlushProcessing() {
+		Session session = openSession();
+		session.beginTransaction();
+		Person person = new Person();
+		Address address = new Address();
+		person.setData( address );
+		session.saveOrUpdate(person);
+		session.saveOrUpdate(address);
+		session.getTransaction().commit();
+		session.close();
+
+		session = openSession();
+		session.beginTransaction();
+        person = (Person) session.load( Person.class, person.getId() );
+        person.setName("makingpersondirty");
+		session.getTransaction().commit();
+		session.close();
+
+		session = openSession();
+		session.beginTransaction();
+		session.delete( person );
+		session.getTransaction().commit();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/ComplexPropertyValue.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/ComplexPropertyValue.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/ComplexPropertyValue.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+package org.hibernate.test.any;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * todo: describe ${NAME}
+ *
+ * @author Steve Ebersole
+ */
+public class ComplexPropertyValue implements PropertyValue {
+	private Long id;
+	private Map subProperties = new HashMap();
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Map getSubProperties() {
+		return subProperties;
+	}
+
+	public void setSubProperties(Map subProperties) {
+		this.subProperties = subProperties;
+	}
+
+	public String asString() {
+		return "complex[" + keyString() + "]";
+	}
+
+	private String keyString() {
+		StringBuffer buff = new StringBuffer();
+		Iterator itr = subProperties.keySet().iterator();
+		while ( itr.hasNext() ) {
+			buff.append( itr.next() );
+			if ( itr.hasNext() ) {
+				buff.append( ", " );
+			}
+		}
+		return buff.toString();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/IntegerPropertyValue.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/IntegerPropertyValue.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/IntegerPropertyValue.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+package org.hibernate.test.any;
+
+/**
+ * todo: describe IntegerPropertyValue
+ *
+ * @author Steve Ebersole
+ */
+public class IntegerPropertyValue implements PropertyValue {
+	private Long id;
+	private int value;
+
+	public IntegerPropertyValue() {
+	}
+
+	public IntegerPropertyValue(int value) {
+		this.value = value;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public int getValue() {
+		return value;
+	}
+
+	public void setValue(int value) {
+		this.value = value;
+	}
+
+	public String asString() {
+		return Integer.toString( value );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.any">
+
+    <class name="Person" table="T_ANY_PERSON">
+        <id name="id" column="ID_">
+            <generator class="increment" />
+        </id>
+        <property name="name" />
+        <any name="data" id-type="long" cascade="none">
+            <meta-value value="A" class="Address"/>
+            <column name="DATATYPE_"/>
+            <column name="DATAID_"/>
+        </any>
+    </class>
+
+    <class name="Address" table="T_ANY_ADDRESS">
+        <id name="id" column="ID_">
+            <generator class="increment" />
+        </id>
+        <set name="lines" table="LINE">
+            <key column="ADDRESS" />
+            <element type="string" />
+        </set>
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+package org.hibernate.test.any;
+
+/**
+ * todo: describe Person
+ *
+ * @author Steve Ebersole
+ */
+public class Person {
+	private Long id;
+	private String name;
+	private Object data;
+
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Object getData() {
+		return data;
+	}
+
+	public void setData(Object data) {
+		this.data = data;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Properties.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Properties.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/Properties.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.any">
+
+    <class name="PropertySet" table="T_PROP_SET">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="name" column="NAME" type="string"/>
+        <any name="someSpecificProperty" id-type="long" meta-type="string" cascade="all">
+            <meta-value value="I" class="IntegerPropertyValue"/>
+            <meta-value value="S" class="StringPropertyValue"/>
+            <meta-value value="C" class="ComplexPropertyValue" />
+            <column name="S_S_PROP_TYPE"/>
+            <column name="S_S_PROP_ID"/>
+        </any>
+        <map name="generalProperties" table="T_GEN_PROPS" lazy="true" cascade="all">
+            <key column="PROP_SET_ID"/>
+            <map-key type="string" column="GEN_PROP_NAME"/>
+            <many-to-any id-type="long" meta-type="string">
+                <meta-value value="I" class="IntegerPropertyValue"/>
+                <meta-value value="S" class="StringPropertyValue"/>
+                <column name="PROP_TYPE"/>
+                <column name="PROP_ID"/>
+            </many-to-any>
+        </map>
+    </class>
+
+    <class name="StringPropertyValue" table="T_CHAR_PROP">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="value" column="VAL" not-null="true" type="string"/>
+    </class>
+
+    <class name="IntegerPropertyValue" table="T_NUM_PROP">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="value" column="VAL" not-null="true" type="integer"/>
+    </class>
+
+    <class name="ComplexPropertyValue" table="T_COMPLEX_PROP">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <map name="subProperties" table="T_COMPLEX_SUB_PROPS" lazy="true">
+            <key column="PROP_ID" />
+            <map-key type="string" column="SUB_PROP_NAME" />
+            <element type="string" column="SUB_PROP_VAL" />
+        </map>
+    </class>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/PropertySet.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/PropertySet.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/PropertySet.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+package org.hibernate.test.any;
+
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * todo: describe PropertySet
+ *
+ * @author Steve Ebersole
+ */
+public class PropertySet {
+	private Long id;
+	private String name;
+	private PropertyValue someSpecificProperty;
+	private Map generalProperties = new HashMap();
+
+	public PropertySet() {
+	}
+
+	public PropertySet(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public PropertyValue getSomeSpecificProperty() {
+		return someSpecificProperty;
+	}
+
+	public void setSomeSpecificProperty(PropertyValue someSpecificProperty) {
+		this.someSpecificProperty = someSpecificProperty;
+	}
+
+	public Map getGeneralProperties() {
+		return generalProperties;
+	}
+
+	public void setGeneralProperties(Map generalProperties) {
+		this.generalProperties = generalProperties;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/PropertyValue.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/PropertyValue.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/PropertyValue.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+package org.hibernate.test.any;
+
+/**
+ * todo: describe PropertyValue
+ *
+ * @author Steve Ebersole
+ */
+public interface PropertyValue {
+	public String asString();
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/StringPropertyValue.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/StringPropertyValue.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/any/StringPropertyValue.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+package org.hibernate.test.any;
+
+/**
+ * todo: describe StringPropertyValue
+ *
+ * @author Steve Ebersole
+ */
+public class StringPropertyValue implements PropertyValue {
+	private Long id;
+	private String value;
+
+	public StringPropertyValue() {
+	}
+
+	public StringPropertyValue(String value) {
+		this.value = value;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getValue() {
+		return value;
+	}
+
+	public void setValue(String value) {
+		this.value = value;
+	}
+
+	public String asString() {
+		return value;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/A.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/A.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/A.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates content-based discrimination for the
+  table-per-hierarchy mapping strategy, using a formula
+  discriminator.
+
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.array">
+	
+	<class name="A" lazy="true" table="aaa">
+		
+		<id name="id">
+			<generator class="native"/>
+		</id>
+
+		<array name="bs" cascade="all" fetch="join">
+			<key column="a_id"/>
+			<list-index column="idx"/>
+			<one-to-many class="B"/>
+		</array>
+
+	</class>
+
+	<class name="B" lazy="true" table="bbb">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+	</class>
+
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/A.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/A.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/A.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/A.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: A.java 6527 2005-04-26 16:58:52Z oneovthafew $
+package org.hibernate.test.array;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class A {
+	private Integer id;
+	private B[] bs;
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public B[] getBs() {
+		return bs;
+	}
+
+	public void setBs(B[] bs) {
+		this.bs = bs;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/A.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/ArrayTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/ArrayTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/ArrayTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+//$Id: ArrayTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.array;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class ArrayTest extends FunctionalTestCase {
+
+	public ArrayTest(String x) {
+		super( x );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "array/A.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ArrayTest.class );
+	}
+
+	public void testArrayJoinFetch() throws Exception {
+		Session s;
+		Transaction tx;
+		s = openSession();
+		tx = s.beginTransaction();
+		A a = new A();
+		B b = new B();
+		a.setBs( new B[] {b} );
+		s.persist( a );
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		a = (A) s.get( A.class, a.getId() );
+		assertNotNull( a );
+		assertNotNull( a.getBs() );
+		assertEquals( a.getBs().length, 1 );
+		assertNotNull( a.getBs()[0] );
+		
+		s.delete(a);
+		s.delete(a.getBs()[0]);
+		tx.commit();
+		s.close();
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/ArrayTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/B.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/B.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/B.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+//$Id: B.java 6527 2005-04-26 16:58:52Z oneovthafew $
+package org.hibernate.test.array;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class B {
+	private Integer id;
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/array/B.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ast/ASTIteratorTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ast/ASTIteratorTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ast/ASTIteratorTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,120 @@
+// $Id: ASTIteratorTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.ast;
+
+import java.io.PrintWriter;
+
+import antlr.ASTFactory;
+import antlr.collections.AST;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.hql.antlr.HqlTokenTypes;
+import org.hibernate.hql.ast.HqlParser;
+import org.hibernate.hql.ast.util.ASTIterator;
+import org.hibernate.hql.ast.util.ASTParentsFirstIterator;
+import org.hibernate.hql.ast.util.ASTPrinter;
+import org.hibernate.hql.ast.util.ASTUtil;
+import org.hibernate.junit.UnitTestCase;
+
+/**
+ * Test ASTIterator.
+ */
+public class ASTIteratorTest extends UnitTestCase {
+	private ASTFactory factory;
+
+	/**
+	 * Standard JUnit test case constructor.
+	 *
+	 * @param name The name of the test case.
+	 */
+	public ASTIteratorTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new TestSuite( ASTIteratorTest.class );
+	}
+
+	protected void setUp() throws Exception {
+		super.setUp();
+		factory = new ASTFactory();
+	}
+
+	/**
+	 * Test a simple tree, make sure the iterator encounters every node.
+	 */
+	public void testSimpleTree() throws Exception {
+		String input = "select foo from foo in class org.hibernate.test.Foo, fee in class org.hibernate.test.Fee where foo.dependent = fee order by foo.string desc, foo.component.count asc, fee.id";
+		HqlParser parser = HqlParser.getInstance( input );
+		parser.statement();
+		AST ast = parser.getAST();
+		ASTPrinter printer = new ASTPrinter( HqlTokenTypes.class );
+		printer.showAst( ast, new PrintWriter( System.out ) );
+		ASTIterator iterator = new ASTIterator( ast );
+		int count = 0;
+		while ( iterator.hasNext() ) {
+			assertTrue( iterator.next() instanceof AST );
+			count++;
+		}
+		assertEquals( 43, count );
+
+		UnsupportedOperationException uoe = null;
+		try {
+			iterator.remove();
+		}
+		catch ( UnsupportedOperationException e ) {
+			uoe = e;
+		}
+		assertNotNull( uoe );
+	}
+
+	public void testParentsFirstIterator() throws Exception {
+		AST[] tree = new AST[4];
+		AST grandparent = tree[0] = ASTUtil.create( factory, 1, "grandparent" );
+		AST parent = tree[1] = ASTUtil.create( factory, 2, "parent" );
+		AST child = tree[2] = ASTUtil.create( factory, 3, "child" );
+		AST baby = tree[3] = ASTUtil.create( factory, 4, "baby" );
+		AST t = ASTUtil.createTree( factory, tree );
+		AST brother = ASTUtil.create( factory, 10, "brother" );
+		child.setNextSibling( brother );
+		AST sister = ASTUtil.create( factory, 11, "sister" );
+		brother.setNextSibling( sister );
+		AST uncle = factory.make( new AST[]{
+			factory.create( 20, "uncle" ),
+			factory.create( 21, "cousin1" ),
+			factory.create( 22, "cousin2" ),
+			factory.create( 23, "cousin3" )} );
+		parent.setNextSibling( uncle );
+		System.out.println( t.toStringTree() );
+
+		System.out.println( "--- ASTParentsFirstIterator ---" );
+		ASTParentsFirstIterator iter = new ASTParentsFirstIterator( t );
+		int count = 0;
+		while ( iter.hasNext() ) {
+			AST n = iter.nextNode();
+			count++;
+			System.out.println( n );
+		}
+		assertEquals( 10, count );
+
+		System.out.println( "--- ASTIterator ---" );
+		ASTIterator iter2 = new ASTIterator( t );
+		int count2 = 0;
+		while ( iter2.hasNext() ) {
+			AST n = iter2.nextNode();
+			count2++;
+			System.out.println( n );
+		}
+		assertEquals( 10, count2 );
+
+		System.out.println( "--- ASTParentsFirstIterator (parent) ---" );
+		ASTParentsFirstIterator iter3 = new ASTParentsFirstIterator( parent );
+		int count3 = 0;
+		while ( iter3.hasNext() ) {
+			AST n = iter3.nextNode();
+			count3++;
+			System.out.println( n );
+		}
+		assertEquals( 5, count3 );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ast/ASTUtilTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ast/ASTUtilTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ast/ASTUtilTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,77 @@
+// $Id: ASTUtilTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.ast;
+
+import antlr.ASTFactory;
+import antlr.collections.AST;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.hql.ast.util.ASTUtil;
+import org.hibernate.junit.UnitTestCase;
+
+/**
+ * Unit test for ASTUtil.
+ */
+public class ASTUtilTest extends UnitTestCase {
+	private ASTFactory factory;
+
+	/**
+	 * Standard JUnit test case constructor.
+	 *
+	 * @param name The name of the test case.
+	 */
+	public ASTUtilTest(String name) {
+		super( name );
+	}
+
+	protected void setUp() throws Exception {
+		super.setUp();
+		factory = new ASTFactory();
+	}
+
+	public void testCreate() throws Exception {
+		AST n = ASTUtil.create( factory, 1, "one");
+		assertNull( n.getFirstChild() );
+		assertEquals("one",n.getText());
+		assertEquals(1,n.getType());
+	}
+	/**
+	 * Test adding a tree of children.
+	 */
+	public void testCreateTree() throws Exception {
+		AST[] tree = new AST[4];
+		AST grandparent = tree[0] = ASTUtil.create(factory, 1, "grandparent");
+		AST parent = tree[1] = ASTUtil.create(factory,2,"parent");
+		AST child = tree[2] = ASTUtil.create(factory,3,"child");
+		AST baby = tree[3] = ASTUtil.create(factory,4,"baby");
+		AST t = ASTUtil.createTree( factory, tree);
+		assertSame(t,grandparent);
+		assertSame(parent,t.getFirstChild());
+		assertSame(child,t.getFirstChild().getFirstChild());
+		assertSame(baby,t.getFirstChild().getFirstChild().getFirstChild());
+	}
+
+	public void testFindPreviousSibling() throws Exception {
+		AST child1 = ASTUtil.create(factory,2, "child1");
+		AST child2 = ASTUtil.create(factory,3, "child2");
+		AST n = factory.make( new AST[] {
+			ASTUtil.create(factory, 1, "parent"),
+			child1,
+			child2,
+		});
+		assertSame(child1,ASTUtil.findPreviousSibling( n,child2));
+		Exception e = null;
+		try {
+			ASTUtil.findPreviousSibling(child1,null);
+		}
+		catch (Exception x) {
+			e = x;
+		}
+		assertNotNull(e);
+	}
+
+	public static Test suite() {
+		return new TestSuite( ASTUtilTest.class );
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/BatchTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/BatchTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/BatchTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,89 @@
+//$Id: BatchTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.batch;
+
+import java.math.BigDecimal;
+
+import junit.framework.Test;
+
+import org.hibernate.CacheMode;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+
+/**
+ * This is how to do batch processing in Hibernate.
+ * Remember to enable JDBC batch updates, or this
+ * test will take a Very Long Time!
+ *
+ * @author Gavin King
+ */
+public class BatchTest extends FunctionalTestCase {
+
+	public BatchTest(String str) {
+		super( str );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "batch/DataPoint.hbm.xml" };
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "20" );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( BatchTest.class );
+	}
+
+	public void testBatchInsertUpdate() {
+		long start = System.currentTimeMillis();
+		final int N = 5000; //26 secs with batch flush, 26 without
+		//final int N = 100000; //53 secs with batch flush, OOME without
+		//final int N = 250000; //137 secs with batch flush, OOME without
+
+		Session s = openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		Transaction t = s.beginTransaction();
+		for ( int i = 0; i < N; i++ ) {
+			DataPoint dp = new DataPoint();
+			dp.setX( new BigDecimal( i * 0.1d ).setScale( 19, BigDecimal.ROUND_DOWN ) );
+			dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale( 19, BigDecimal.ROUND_DOWN ) );
+			s.save( dp );
+			if ( i % 20 == 0 ) {
+				s.flush();
+				s.clear();
+			}
+		}
+		t.commit();
+		s.close();
+
+		s = openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		int i = 0;
+		ScrollableResults sr = s.createQuery( "from DataPoint dp order by dp.x asc" )
+				.scroll( ScrollMode.FORWARD_ONLY );
+		while ( sr.next() ) {
+			DataPoint dp = ( DataPoint ) sr.get( 0 );
+			dp.setDescription( "done!" );
+			if ( ++i % 20 == 0 ) {
+				s.flush();
+				s.clear();
+			}
+		}
+		t.commit();
+		s.close();
+		System.out.println( System.currentTimeMillis() - start );
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/BatchTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/DataPoint.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/DataPoint.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/DataPoint.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.batch">
+
+	<class name="DataPoint" 
+		dynamic-update="true">
+		<!--rowid="rowid"--> <!-- remove this if not oracle -->
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		<property name="x">
+			<column name="xval" not-null="true" length="4" unique-key="xy"/>
+		</property>
+		<property name="y">
+			<column name="yval" not-null="true" length="4" unique-key="xy"/>
+		</property>
+		<property name="description"/>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/DataPoint.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/DataPoint.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/DataPoint.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/DataPoint.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+//$Id: DataPoint.java 4343 2004-08-16 11:46:19Z oneovthafew $
+package org.hibernate.test.batch;
+
+import java.math.BigDecimal;
+
+/**
+ * @author Gavin King
+ */
+public class DataPoint {
+	private long id;
+	private BigDecimal x;
+	private BigDecimal y;
+	private String description;
+	/**
+	 * @return Returns the description.
+	 */
+	public String getDescription() {
+		return description;
+	}
+	/**
+	 * @param description The description to set.
+	 */
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the x.
+	 */
+	public BigDecimal getX() {
+		return x;
+	}
+	/**
+	 * @param x The x to set.
+	 */
+	public void setX(BigDecimal x) {
+		this.x = x;
+	}
+	/**
+	 * @return Returns the y.
+	 */
+	public BigDecimal getY() {
+		return y;
+	}
+	/**
+	 * @param y The y to set.
+	 */
+	public void setY(BigDecimal y) {
+		this.y = y;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batch/DataPoint.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/BatchFetchTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/BatchFetchTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/BatchFetchTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,122 @@
+//$Id: BatchFetchTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.batchfetch;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class BatchFetchTest extends FunctionalTestCase {
+
+	public BatchFetchTest(String str) {
+		super( str );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "batchfetch/ProductLine.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( BatchFetchTest.class );
+	}
+
+	public void testBatchFetch() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		ProductLine cars = new ProductLine();
+		cars.setDescription( "Cars" );
+		Model monaro = new Model( cars );
+		monaro.setName( "monaro" );
+		monaro.setDescription( "Holden Monaro" );
+		Model hsv = new Model( cars );
+		hsv.setName( "hsv" );
+		hsv.setDescription( "Holden Commodore HSV" );
+		s.save( cars );
+
+		ProductLine oss = new ProductLine();
+		oss.setDescription( "OSS" );
+		Model jboss = new Model( oss );
+		jboss.setName( "JBoss" );
+		jboss.setDescription( "JBoss Application Server" );
+		Model hibernate = new Model( oss );
+		hibernate.setName( "Hibernate" );
+		hibernate.setDescription( "Hibernate" );
+		Model cache = new Model( oss );
+		cache.setName( "JBossCache" );
+		cache.setDescription( "JBoss TreeCache" );
+		s.save( oss );
+
+		t.commit();
+		s.close();
+
+		s.getSessionFactory().evict( Model.class );
+		s.getSessionFactory().evict( ProductLine.class );
+
+		s = openSession();
+		t = s.beginTransaction();
+
+		List list = s.createQuery( "from ProductLine pl order by pl.description" ).list();
+		cars = ( ProductLine ) list.get( 0 );
+		oss = ( ProductLine ) list.get( 1 );
+		assertFalse( Hibernate.isInitialized( cars.getModels() ) );
+		assertFalse( Hibernate.isInitialized( oss.getModels() ) );
+		assertEquals( cars.getModels().size(), 2 ); //fetch both collections
+		assertTrue( Hibernate.isInitialized( cars.getModels() ) );
+		assertTrue( Hibernate.isInitialized( oss.getModels() ) );
+
+		s.clear();
+
+		list = s.createQuery( "from Model m" ).list();
+		hibernate = ( Model ) s.get( Model.class, hibernate.getId() );
+		hibernate.getProductLine().getId();
+		for ( Iterator i = list.iterator(); i.hasNext(); ) {
+			assertFalse( Hibernate.isInitialized( ( ( Model ) i.next() ).getProductLine() ) );
+		}
+		assertEquals( hibernate.getProductLine().getDescription(), "OSS" ); //fetch both productlines
+
+		s.clear();
+
+		Iterator iter = s.createQuery( "from Model" ).iterate();
+		list = new ArrayList();
+		while ( iter.hasNext() ) {
+			list.add( iter.next() );
+		}
+		Model m = ( Model ) list.get( 0 );
+		m.getDescription(); //fetch a batch of 4
+
+		s.clear();
+
+		list = s.createQuery( "from ProductLine" ).list();
+		ProductLine pl = ( ProductLine ) list.get( 0 );
+		ProductLine pl2 = ( ProductLine ) list.get( 1 );
+		s.evict( pl2 );
+		pl.getModels().size(); //fetch just one collection! (how can we write an assertion for that??)
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		list = s.createQuery( "from ProductLine pl order by pl.description" ).list();
+		cars = ( ProductLine ) list.get( 0 );
+		oss = ( ProductLine ) list.get( 1 );
+		assertEquals( cars.getModels().size(), 2 );
+		assertEquals( oss.getModels().size(), 3 );
+		s.delete( cars );
+		s.delete( oss );
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/BatchFetchTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/Model.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/Model.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/Model.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+//$Id: Model.java 4460 2004-08-29 12:04:14Z oneovthafew $
+package org.hibernate.test.batchfetch;
+
+/**
+ * @author Gavin King
+ */
+public class Model {
+	private String id;
+	private String name;
+	private String description;
+	private ProductLine productLine;
+	
+	Model() {}
+	
+	public Model(ProductLine pl) {
+		this.productLine = pl;
+		pl.getModels().add(this);
+	}
+	
+	public String getDescription() {
+		return description;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	public String getId() {
+		return id;
+	}
+	public void setId(String id) {
+		this.id = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public ProductLine getProductLine() {
+		return productLine;
+	}
+	public void setProductLine(ProductLine productLine) {
+		this.productLine = productLine;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/Model.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/ProductLine.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/ProductLine.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/ProductLine.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.batchfetch">
+
+<!-- 
+
+  This mapping demonstrates the use of batch fetching
+  for collections and entities.
+     
+-->
+
+    <class name="ProductLine" 
+    		batch-size="64">
+    
+    	<id name="id" 
+    		column="productId" 
+    		length="32">
+    		<generator class="uuid.hex"/>
+    	</id>
+    	
+    	<property name="description" 
+    		not-null="true" 
+    		length="200"/>
+    	
+    	<set name="models" 
+    			batch-size="64"
+    			cascade="all"
+    			inverse="true">
+    		<key column="productId"/>
+    		<one-to-many class="Model"/>
+    	</set>
+    	
+	</class>
+
+    <class name="Model" 
+    		batch-size="64">
+    
+    	<id name="id" 
+    		column="modelId" 
+    		length="32">
+    		<generator class="uuid.hex"/>
+    	</id>
+    	
+    	<property name="name"
+    		not-null="true"
+    		length="25"/>
+    		
+    	<property name="description" 
+    		not-null="true" 
+    		length="200"/>
+    	
+    	<many-to-one name="productLine" 
+    		column="productId"
+    		not-null="true"/>
+    	
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/ProductLine.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/ProductLine.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/ProductLine.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/ProductLine.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+//$Id: ProductLine.java 4460 2004-08-29 12:04:14Z oneovthafew $
+package org.hibernate.test.batchfetch;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class ProductLine {
+
+	private String id;
+	private String description;
+	private Set models = new HashSet();
+	
+	public String getDescription() {
+		return description;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	public String getId() {
+		return id;
+	}
+	public void setId(String id) {
+		this.id = id;
+	}
+	public Set getModels() {
+		return models;
+	}
+	public void setModels(Set models) {
+		this.models = models;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/batchfetch/ProductLine.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.bidi">
+
+	<class name="Auction" table="TAuction">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="description"/>
+		<property name="end" column="endDatetime"/>
+		<bag name="bids" inverse="true" 
+				cascade="persist">
+			<key column="auctionId"/>
+			<one-to-many class="Bid"/>
+		</bag>
+		<one-to-one name="successfulBid" 
+				property-ref="abc">
+			<formula>id</formula>
+			<formula>1</formula>
+		</one-to-one>
+	</class>
+	
+	<class name="Bid" table="TBid">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="amount" 
+				scale="19" 
+				precision="31" />
+		<property name="datetime" 
+				column="createdDatetime"/>
+		<properties name="abc">
+			<many-to-one name="item" 
+					column="auctionId" 
+					cascade="persist"/>
+			<property name="successful" 
+					column="success"/>
+		</properties>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+//$Id: Auction.java 5733 2005-02-14 15:56:06Z oneovthafew $
+package org.hibernate.test.bidi;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author Gavin King
+ */
+public class Auction {
+	private Long id;
+	private String description;
+	private List bids = new ArrayList();
+	private Bid successfulBid;
+	private Date end;
+	
+	public Date getEnd() {
+		return end;
+	}
+	public void setEnd(Date end) {
+		this.end = end;
+	}
+	public List getBids() {
+		return bids;
+	}
+	public void setBids(List bids) {
+		this.bids = bids;
+	}
+	public String getDescription() {
+		return description;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public Bid getSuccessfulBid() {
+		return successfulBid;
+	}
+	public void setSuccessfulBid(Bid successfulBid) {
+		this.successfulBid = successfulBid;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction2.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction2.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction2.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.bidi">
+
+	<class name="Auction" table="TAuction2">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="description"/>
+		<property name="end" column="endDatetime"/>
+		<bag name="bids" inverse="true" 
+				cascade="persist">
+			<key column="auctionId"/>
+			<one-to-many class="Bid"/>
+		</bag>
+		<many-to-one name="successfulBid"/>
+	</class>
+	
+	<class name="Bid" table="TBid2">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="amount" scale="19" precision="31"/>
+		<property name="datetime" 
+				column="createdDatetime"/>
+		<many-to-one name="item" 
+				column="auctionId" 
+				cascade="persist"/>
+		<property name="successful">
+			<formula>exists(select a.id from TAuction2 a where a.successfulBid=id)</formula>
+		</property>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Auction2.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/AuctionTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/AuctionTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/AuctionTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,119 @@
+//$Id: AuctionTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.bidi;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.dialect.PostgreSQLDialect;
+
+/**
+ * @author Gavin King
+ */
+public class AuctionTest extends FunctionalTestCase {
+
+	public AuctionTest(String str) {
+		super( str );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "bidi/Auction.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( AuctionTest.class );
+	}
+
+	public void testLazy() {
+		if ( getDialect() instanceof PostgreSQLDialect ) {
+			return; //doesn't like boolean=1
+		}
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Auction a = new Auction();
+		a.setDescription( "an auction for something" );
+		a.setEnd( new Date() );
+		Bid b = new Bid();
+		b.setAmount( new BigDecimal( 123.34 ).setScale( 19, BigDecimal.ROUND_DOWN ) );
+		b.setSuccessful( true );
+		b.setDatetime( new Date() );
+		b.setItem( a );
+		a.getBids().add( b );
+		a.setSuccessfulBid( b );
+		s.persist( b );
+		t.commit();
+		s.close();
+
+		Long aid = a.getId();
+		Long bid = b.getId();
+
+		s = openSession();
+		t = s.beginTransaction();
+		b = ( Bid ) s.load( Bid.class, bid );
+		assertFalse( Hibernate.isInitialized( b ) );
+		a = ( Auction ) s.get( Auction.class, aid );
+		assertFalse( Hibernate.isInitialized( a.getBids() ) );
+		assertTrue( Hibernate.isInitialized( a.getSuccessfulBid() ) );
+		assertSame( a.getBids().iterator().next(), b );
+		assertSame( b, a.getSuccessfulBid() );
+		assertTrue( Hibernate.isInitialized( b ) );
+		assertTrue( b.isSuccessful() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		b = ( Bid ) s.load( Bid.class, bid );
+		assertFalse( Hibernate.isInitialized( b ) );
+		a = ( Auction ) s.createQuery( "from Auction a left join fetch a.bids" ).uniqueResult();
+		assertTrue( Hibernate.isInitialized( b ) );
+		assertTrue( Hibernate.isInitialized( a.getBids() ) );
+		assertSame( b, a.getSuccessfulBid() );
+		assertSame( a.getBids().iterator().next(), b );
+		assertTrue( b.isSuccessful() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		b = ( Bid ) s.load( Bid.class, bid );
+		a = ( Auction ) s.load( Auction.class, aid );
+		assertFalse( Hibernate.isInitialized( b ) );
+		assertFalse( Hibernate.isInitialized( a ) );
+		s.createQuery( "from Auction a left join fetch a.successfulBid" ).list();
+		assertTrue( Hibernate.isInitialized( b ) );
+		assertTrue( Hibernate.isInitialized( a ) );
+		assertSame( b, a.getSuccessfulBid() );
+		assertFalse( Hibernate.isInitialized( a.getBids() ) );
+		assertSame( a.getBids().iterator().next(), b );
+		assertTrue( b.isSuccessful() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		b = ( Bid ) s.load( Bid.class, bid );
+		a = ( Auction ) s.load( Auction.class, aid );
+		assertFalse( Hibernate.isInitialized( b ) );
+		assertFalse( Hibernate.isInitialized( a ) );
+		assertSame( s.get( Bid.class, bid ), b );
+		assertTrue( Hibernate.isInitialized( b ) );
+		assertSame( s.get( Auction.class, aid ), a );
+		assertTrue( Hibernate.isInitialized( a ) );
+		assertSame( b, a.getSuccessfulBid() );
+		assertFalse( Hibernate.isInitialized( a.getBids() ) );
+		assertSame( a.getBids().iterator().next(), b );
+		assertTrue( b.isSuccessful() );
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/AuctionTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/AuctionTest2.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/AuctionTest2.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/AuctionTest2.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,122 @@
+//$Id: AuctionTest2.java 10981 2006-12-13 00:14:17Z steve.ebersole at jboss.com $
+package org.hibernate.test.bidi;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+import junit.framework.Test;
+
+/**
+ * @author Gavin King
+ */
+public class AuctionTest2 extends FunctionalTestCase {
+
+	public AuctionTest2(String str) {
+		super( str );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "bidi/Auction2.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( AuctionTest2.class );
+	}
+
+	public boolean createSchema() {
+		return getDialect().supportsExistsInSelect();
+	}
+
+	public void testLazy() {
+		if ( ! getDialect().supportsExistsInSelect() ) {
+			reportSkip( "dialect does not support exist fragments in the select clause", "bidi support" );
+			return;
+		}
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Auction a = new Auction();
+		a.setDescription( "an auction for something" );
+		a.setEnd( new Date() );
+		Bid b = new Bid();
+		b.setAmount( new BigDecimal( 123.34 ).setScale( 19, BigDecimal.ROUND_DOWN ) );
+		b.setSuccessful( true );
+		b.setDatetime( new Date() );
+		b.setItem( a );
+		a.getBids().add( b );
+		a.setSuccessfulBid( b );
+		s.persist( b );
+		t.commit();
+		s.close();
+
+		Long aid = a.getId();
+		Long bid = b.getId();
+
+		s = openSession();
+		t = s.beginTransaction();
+		b = ( Bid ) s.load( Bid.class, bid );
+		assertFalse( Hibernate.isInitialized( b ) );
+		a = ( Auction ) s.get( Auction.class, aid );
+		assertFalse( Hibernate.isInitialized( a.getBids() ) );
+		assertFalse( Hibernate.isInitialized( a.getSuccessfulBid() ) );
+		assertSame( a.getBids().iterator().next(), b );
+		assertSame( b, a.getSuccessfulBid() );
+		assertTrue( Hibernate.isInitialized( b ) );
+		assertTrue( b.isSuccessful() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		b = ( Bid ) s.load( Bid.class, bid );
+		assertFalse( Hibernate.isInitialized( b ) );
+		a = ( Auction ) s.createQuery( "from Auction a left join fetch a.bids" ).uniqueResult();
+		assertTrue( Hibernate.isInitialized( b ) );
+		assertTrue( Hibernate.isInitialized( a.getBids() ) );
+		assertSame( b, a.getSuccessfulBid() );
+		assertSame( a.getBids().iterator().next(), b );
+		assertTrue( b.isSuccessful() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		b = ( Bid ) s.load( Bid.class, bid );
+		a = ( Auction ) s.load( Auction.class, aid );
+		assertFalse( Hibernate.isInitialized( b ) );
+		assertFalse( Hibernate.isInitialized( a ) );
+		s.createQuery( "from Auction a left join fetch a.successfulBid" ).list();
+		assertTrue( Hibernate.isInitialized( b ) );
+		assertTrue( Hibernate.isInitialized( a ) );
+		assertSame( b, a.getSuccessfulBid() );
+		assertFalse( Hibernate.isInitialized( a.getBids() ) );
+		assertSame( a.getBids().iterator().next(), b );
+		assertTrue( b.isSuccessful() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		b = ( Bid ) s.load( Bid.class, bid );
+		a = ( Auction ) s.load( Auction.class, aid );
+		assertFalse( Hibernate.isInitialized( b ) );
+		assertFalse( Hibernate.isInitialized( a ) );
+		assertSame( s.get( Bid.class, bid ), b );
+		assertTrue( Hibernate.isInitialized( b ) );
+		assertSame( s.get( Auction.class, aid ), a );
+		assertTrue( Hibernate.isInitialized( a ) );
+		assertSame( b, a.getSuccessfulBid() );
+		assertFalse( Hibernate.isInitialized( a.getBids() ) );
+		assertSame( a.getBids().iterator().next(), b );
+		assertTrue( b.isSuccessful() );
+		t.commit();
+		s.close();
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/AuctionTest2.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Bid.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Bid.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Bid.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+//$Id: Bid.java 5733 2005-02-14 15:56:06Z oneovthafew $
+package org.hibernate.test.bidi;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class Bid {
+	private Long id;
+	private Auction item;
+	private BigDecimal amount;
+	private boolean successful;
+	private Date datetime; 
+
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public BigDecimal getAmount() {
+		return amount;
+	}
+	public void setAmount(BigDecimal amount) {
+		this.amount = amount;
+	}
+	public Auction getItem() {
+		return item;
+	}
+	public void setItem(Auction item) {
+		this.item = item;
+	}
+	public boolean isSuccessful() {
+		return successful;
+	}
+	public void setSuccessful(boolean successful) {
+		this.successful = successful;
+	}
+	public Date getDatetime() {
+		return datetime;
+	}
+	public void setDatetime(Date datetime) {
+		this.datetime = datetime;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bidi/Bid.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/Bean.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/Bean.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/Bean.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.bytecode">
+
+	<class name="Bean">
+		<id name="someString" type="string">
+			<generator class="assigned"/>
+		</id>
+        <property name="someLong" type="long" column="S_LONG_1" />
+        <property name="someInteger" type="int" column="S_INT_1" />
+        <property name="someDate" type="timestamp" column="S_DATE_1" />
+        <property name="somelong" type="long" column="S_LONG_2" />
+        <property name="someint" type="int" column="S_INT_2" />
+        <property name="someObject" type="serializable" column="S_OBJ_1" />
+	</class>
+
+
+	<class name="ProxyBean" lazy="true">
+		<id name="someString" type="string">
+			<generator class="assigned"/>
+		</id>
+		<property name="someLong" type="long" column="S_LONG_1" />
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/Bean.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/Bean.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/Bean.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+package org.hibernate.test.bytecode;
+
+import java.util.Date;
+import java.text.ParseException;
+
+/**
+ * @author Steve Ebersole
+ */
+public class Bean {
+	private String someString;
+	private Long someLong;
+	private Integer someInteger;
+	private Date someDate;
+	private long somelong;
+	private int someint;
+	private Object someObject;
+
+
+	public String getSomeString() {
+		return someString;
+	}
+
+	public void setSomeString(String someString) {
+		this.someString = someString;
+	}
+
+	public Long getSomeLong() {
+		return someLong;
+	}
+
+	public void setSomeLong(Long someLong) {
+		this.someLong = someLong;
+	}
+
+	public Integer getSomeInteger() {
+		return someInteger;
+	}
+
+	public void setSomeInteger(Integer someInteger) {
+		this.someInteger = someInteger;
+	}
+
+	public Date getSomeDate() {
+		return someDate;
+	}
+
+	public void setSomeDate(Date someDate) {
+		this.someDate = someDate;
+	}
+
+	public long getSomelong() {
+		return somelong;
+	}
+
+	public void setSomelong(long somelong) {
+		this.somelong = somelong;
+	}
+
+	public int getSomeint() {
+		return someint;
+	}
+
+	public void setSomeint(int someint) {
+		this.someint = someint;
+	}
+
+	public Object getSomeObject() {
+		return someObject;
+	}
+
+	public void setSomeObject(Object someObject) {
+		this.someObject = someObject;
+	}
+
+	public void throwException() throws ParseException {
+		throw new ParseException( "you asked for it...", 0 );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/BeanReflectionHelper.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/BeanReflectionHelper.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/BeanReflectionHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+package org.hibernate.test.bytecode;
+
+import org.hibernate.property.BasicPropertyAccessor;
+import org.hibernate.property.Getter;
+import org.hibernate.property.Setter;
+
+import java.util.Date;
+
+/**
+ * @author Steve Ebersole
+ */
+public class BeanReflectionHelper {
+
+	public static final Object[] TEST_VALUES = new Object[] {
+			"hello", new Long(1), new Integer(1), new Date(), new Long(1), new Integer(1), new Object()
+	};
+
+	private static final String[] getterNames = new String[7];
+	private static final String[] setterNames = new String[7];
+	private static final Class[] types = new Class[7];
+
+	static {
+		BasicPropertyAccessor propertyAccessor = new BasicPropertyAccessor();
+		Getter getter = propertyAccessor.getGetter( Bean.class, "someString" );
+		Setter setter = propertyAccessor.getSetter( Bean.class, "someString" );
+		getterNames[0] = getter.getMethodName();
+		types[0] = getter.getReturnType();
+		setterNames[0] = setter.getMethodName();
+
+		getter = propertyAccessor.getGetter( Bean.class, "someLong" );
+		setter = propertyAccessor.getSetter( Bean.class, "someLong" );
+		getterNames[1] = getter.getMethodName();
+		types[1] = getter.getReturnType();
+		setterNames[1] = setter.getMethodName();
+
+		getter = propertyAccessor.getGetter( Bean.class, "someInteger" );
+		setter = propertyAccessor.getSetter( Bean.class, "someInteger" );
+		getterNames[2] = getter.getMethodName();
+		types[2] = getter.getReturnType();
+		setterNames[2] = setter.getMethodName();
+
+		getter = propertyAccessor.getGetter( Bean.class, "someDate" );
+		setter = propertyAccessor.getSetter( Bean.class, "someDate" );
+		getterNames[3] = getter.getMethodName();
+		types[3] = getter.getReturnType();
+		setterNames[3] = setter.getMethodName();
+
+		getter = propertyAccessor.getGetter( Bean.class, "somelong" );
+		setter = propertyAccessor.getSetter( Bean.class, "somelong" );
+		getterNames[4] = getter.getMethodName();
+		types[4] = getter.getReturnType();
+		setterNames[4] = setter.getMethodName();
+
+		getter = propertyAccessor.getGetter( Bean.class, "someint" );
+		setter = propertyAccessor.getSetter( Bean.class, "someint" );
+		getterNames[5] = getter.getMethodName();
+		types[5] = getter.getReturnType();
+		setterNames[5] = setter.getMethodName();
+
+		getter = propertyAccessor.getGetter( Bean.class, "someObject" );
+		setter = propertyAccessor.getSetter( Bean.class, "someObject" );
+		getterNames[6] = getter.getMethodName();
+		types[6] = getter.getReturnType();
+		setterNames[6] = setter.getMethodName();
+	}
+
+	public static String[] getGetterNames() {
+		return getterNames;
+	}
+
+	public static String[] getSetterNames() {
+		return setterNames;
+	}
+
+	public static Class[] getTypes() {
+		return types;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/BytecodeSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/BytecodeSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/BytecodeSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+package org.hibernate.test.bytecode;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * todo: describe BytecodeSuite
+ *
+ * @author Steve Ebersole
+ */
+public class BytecodeSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "BytecodeProvider tests" );
+		suite.addTest( org.hibernate.test.bytecode.cglib.ReflectionOptimizerTest.suite() );
+		suite.addTest( org.hibernate.test.bytecode.cglib.InvocationTargetExceptionTest.suite() );
+		suite.addTest( org.hibernate.test.bytecode.cglib.CGLIBThreadLocalTest.suite() );
+		suite.addTest( org.hibernate.test.bytecode.javassist.ReflectionOptimizerTest.suite() );
+		suite.addTest( org.hibernate.test.bytecode.javassist.InvocationTargetExceptionTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/ProxyBean.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/ProxyBean.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/ProxyBean.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+package org.hibernate.test.bytecode;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: Paul
+ * Date: Mar 9, 2007
+ * Time: 11:31:40 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class ProxyBean {
+	private String someString;
+	private long someLong;
+
+
+	public String getSomeString() {
+		return someString;
+	}
+
+	public void setSomeString(String someString) {
+		this.someString = someString;
+	}
+
+
+	public long getSomeLong() {
+		return someLong;
+	}
+
+	public void setSomeLong(long someLong) {
+		this.someLong = someLong;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/cglib/CGLIBThreadLocalTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/cglib/CGLIBThreadLocalTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/cglib/CGLIBThreadLocalTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,73 @@
+package org.hibernate.test.bytecode.cglib;
+
+import org.hibernate.junit.functional.*;
+import org.hibernate.cfg.*;
+import org.hibernate.*;
+import org.hibernate.proxy.*;
+import org.hibernate.test.bytecode.*;
+import junit.framework.*;
+
+import java.text.*;
+import java.lang.reflect.*;
+
+import net.sf.cglib.proxy.*;
+
+/**
+ * Test that the static thread local callback object is cleared out of the proxy class after instantiated.
+ * This tests that the memory leak reported by HHH-2481 hasn't been re-introduced.
+ *
+ * @author Paul Malolepsy
+ */
+public class CGLIBThreadLocalTest extends FunctionalTestCase {
+	public CGLIBThreadLocalTest(String name) {
+		super(name);
+	}
+
+	public String[] getMappings() {
+		return new String[]{"bytecode/Bean.hbm.xml"};
+	}
+
+	public static TestSuite suite() {
+		return new FunctionalTestClassTestSuite(CGLIBThreadLocalTest.class);
+	}
+
+	public void testCglibClearing() {
+		if (!(Environment.getBytecodeProvider() instanceof org.hibernate.bytecode.cglib.BytecodeProviderImpl)) {
+			// because of the scoping :(
+			reportSkip("env not configured for cglib provider", "cglib thread local callback clearing");
+			return;
+		}
+
+		//create the object for the test
+		Session s = openSession();
+		s.beginTransaction();
+		ProxyBean proxyBean = new ProxyBean();
+		proxyBean.setSomeString("my-bean");
+		proxyBean.setSomeLong(1234);
+		s.save(proxyBean);
+		s.getTransaction().commit();
+		s.close();
+
+		// read the object as a proxy
+		s = openSession();
+		s.beginTransaction();
+		proxyBean = (ProxyBean) s.load(ProxyBean.class, proxyBean.getSomeString());
+		assertTrue(proxyBean instanceof HibernateProxy);
+		try {
+			//check that the static thread callbacks thread local has been cleared out
+			Field field = proxyBean.getClass().getDeclaredField("CGLIB$THREAD_CALLBACKS");
+			field.setAccessible(true);
+			ThreadLocal threadCallbacksThreadLocal = (ThreadLocal) field.get(null);
+			assertTrue(threadCallbacksThreadLocal.get() == null);
+		} catch (NoSuchFieldException e1) {
+			fail("unable to find CGLIB$THREAD_CALLBACKS field in proxy.");
+		} catch (Throwable t) {
+			fail("unexpected exception type : " + t);
+		} finally {
+			//clean up
+			s.delete(proxyBean);
+			s.getTransaction().commit();
+			s.close();
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/cglib/InvocationTargetExceptionTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/cglib/InvocationTargetExceptionTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/cglib/InvocationTargetExceptionTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+package org.hibernate.test.bytecode.cglib;
+
+import org.hibernate.test.TestCase;
+import org.hibernate.test.bytecode.Bean;
+import org.hibernate.Session;
+import org.hibernate.Hibernate;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.cfg.Environment;
+import junit.framework.TestSuite;
+
+import java.text.ParseException;
+
+/**
+ * Test that the Javassist-based lazy initializer properly handles
+ * InvocationTargetExceptions
+ *
+ * @author Steve Ebersole
+ */
+public class InvocationTargetExceptionTest extends FunctionalTestCase {
+	public InvocationTargetExceptionTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "bytecode/Bean.hbm.xml" };
+	}
+
+	public static TestSuite suite() {
+		return new FunctionalTestClassTestSuite( InvocationTargetExceptionTest.class );
+	}
+
+	public void testProxiedInvocationException() {
+		if ( ! ( Environment.getBytecodeProvider() instanceof org.hibernate.bytecode.cglib.BytecodeProviderImpl ) ) {
+			// because of the scoping :(
+			reportSkip( "env not configured for cglib provider", "bytecode-provider InvocationTargetException handling" );
+			return;
+		}
+		Session s = openSession();
+		s.beginTransaction();
+		Bean bean = new Bean();
+		bean.setSomeString( "my-bean" );
+		s.save( bean );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		bean = ( Bean ) s.load( Bean.class, bean.getSomeString() );
+		assertFalse( Hibernate.isInitialized( bean ) );
+		try {
+			bean.throwException();
+			fail( "exception not thrown" );
+		}
+		catch ( ParseException e ) {
+			// expected behavior
+		}
+		catch( Throwable t ) {
+			fail( "unexpected exception type : " + t );
+		}
+
+		s.delete( bean );
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/cglib/ReflectionOptimizerTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/cglib/ReflectionOptimizerTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/cglib/ReflectionOptimizerTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+package org.hibernate.test.bytecode.cglib;
+
+import junit.framework.TestSuite;
+
+import org.hibernate.bytecode.ReflectionOptimizer;
+import org.hibernate.bytecode.cglib.BytecodeProviderImpl;
+import org.hibernate.junit.UnitTestCase;
+import org.hibernate.test.bytecode.Bean;
+import org.hibernate.test.bytecode.BeanReflectionHelper;
+
+/**
+ * @author Steve Ebersole
+ */
+public class ReflectionOptimizerTest extends UnitTestCase {
+
+	public ReflectionOptimizerTest(String string) {
+		super( string );
+	}
+
+	public void testReflectionOptimization() {
+		BytecodeProviderImpl provider = new BytecodeProviderImpl();
+		ReflectionOptimizer optimizer = provider.getReflectionOptimizer(
+				Bean.class,
+		        BeanReflectionHelper.getGetterNames(),
+		        BeanReflectionHelper.getSetterNames(),
+		        BeanReflectionHelper.getTypes()
+		);
+		assertNotNull( optimizer );
+		assertNotNull( optimizer.getInstantiationOptimizer() );
+		assertNotNull( optimizer.getAccessOptimizer() );
+
+		Object instance = optimizer.getInstantiationOptimizer().newInstance();
+		assertEquals( instance.getClass(), Bean.class );
+		Bean bean = ( Bean ) instance;
+
+		optimizer.getAccessOptimizer().setPropertyValues( bean, BeanReflectionHelper.TEST_VALUES );
+		assertEquals( bean.getSomeString(), BeanReflectionHelper.TEST_VALUES[0] );
+		Object[] values = optimizer.getAccessOptimizer().getPropertyValues( bean );
+		assertEquivalent( values, BeanReflectionHelper.TEST_VALUES );
+	}
+
+	private void assertEquivalent(Object[] checkValues, Object[] values) {
+		assertEquals( "Different lengths", checkValues.length, values.length );
+		for ( int i = 0; i < checkValues.length; i++ ) {
+			assertEquals( "different values at index [" + i + "]", checkValues[i], values[i] );
+		}
+	}
+
+	public static TestSuite suite() {
+		return new TestSuite( ReflectionOptimizerTest.class );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/javassist/InvocationTargetExceptionTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/javassist/InvocationTargetExceptionTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/javassist/InvocationTargetExceptionTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,68 @@
+package org.hibernate.test.bytecode.javassist;
+
+import java.text.ParseException;
+
+import junit.framework.TestSuite;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.bytecode.Bean;
+
+/**
+ * Test that the Javassist-based lazy initializer properly handles
+ * InvocationTargetExceptions
+ *
+ * @author Steve Ebersole
+ */
+public class InvocationTargetExceptionTest extends FunctionalTestCase {
+	public InvocationTargetExceptionTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "bytecode/Bean.hbm.xml" };
+	}
+
+	public static TestSuite suite() {
+		return new FunctionalTestClassTestSuite( InvocationTargetExceptionTest.class );
+	}
+
+	public void testProxiedInvocationException() {
+		if ( !( Environment.getBytecodeProvider() instanceof org.hibernate.bytecode.javassist.BytecodeProviderImpl ) ) {
+			// because of the scoping :(
+			reportSkip(
+					"env not configured for javassist provider", "bytecode-provider InvocationTargetException handling"
+			);
+			return;
+		}
+		Session s = openSession();
+		s.beginTransaction();
+		Bean bean = new Bean();
+		bean.setSomeString( "my-bean" );
+		s.save( bean );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		bean = ( Bean ) s.load( Bean.class, bean.getSomeString() );
+		assertFalse( Hibernate.isInitialized( bean ) );
+		try {
+			bean.throwException();
+			fail( "exception not thrown" );
+		}
+		catch ( ParseException e ) {
+			// expected behavior
+		}
+		catch ( Throwable t ) {
+			fail( "unexpected exception type : " + t );
+		}
+
+		s.delete( bean );
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/javassist/ReflectionOptimizerTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/javassist/ReflectionOptimizerTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/bytecode/javassist/ReflectionOptimizerTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+package org.hibernate.test.bytecode.javassist;
+
+import junit.framework.TestSuite;
+
+import org.hibernate.bytecode.ReflectionOptimizer;
+import org.hibernate.bytecode.javassist.BytecodeProviderImpl;
+import org.hibernate.junit.UnitTestCase;
+import org.hibernate.test.bytecode.Bean;
+import org.hibernate.test.bytecode.BeanReflectionHelper;
+
+/**
+ * @author Steve Ebersole
+ */
+public class ReflectionOptimizerTest extends UnitTestCase {
+
+	public ReflectionOptimizerTest(String string) {
+		super( string );
+	}
+
+	public void testReflectionOptimization() {
+		BytecodeProviderImpl provider = new BytecodeProviderImpl();
+		ReflectionOptimizer optimizer = provider.getReflectionOptimizer(
+				Bean.class,
+		        BeanReflectionHelper.getGetterNames(),
+		        BeanReflectionHelper.getSetterNames(),
+		        BeanReflectionHelper.getTypes()
+		);
+		assertNotNull( optimizer );
+		assertNotNull( optimizer.getInstantiationOptimizer() );
+		assertNotNull( optimizer.getAccessOptimizer() );
+
+		Object instance = optimizer.getInstantiationOptimizer().newInstance();
+		assertEquals( instance.getClass(), Bean.class );
+		Bean bean = ( Bean ) instance;
+
+		optimizer.getAccessOptimizer().setPropertyValues( bean, BeanReflectionHelper.TEST_VALUES );
+		assertEquals( bean.getSomeString(), BeanReflectionHelper.TEST_VALUES[0] );
+		Object[] values = optimizer.getAccessOptimizer().getPropertyValues( bean );
+		assertEquivalent( values, BeanReflectionHelper.TEST_VALUES );
+	}
+
+	private void assertEquivalent(Object[] checkValues, Object[] values) {
+		assertEquals( "Different lengths", checkValues.length, values.length );
+		for ( int i = 0; i < checkValues.length; i++ ) {
+			assertEquals( "different values at index [" + i + "]", checkValues[i], values[i] );
+		}
+	}
+
+	public static TestSuite suite() {
+		return new TestSuite( ReflectionOptimizerTest.class );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/BaseCacheProviderTestCase.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/BaseCacheProviderTestCase.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/BaseCacheProviderTestCase.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,216 @@
+package org.hibernate.test.cache;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cache.ReadWriteCache;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.stat.SecondLevelCacheStatistics;
+import org.hibernate.stat.Statistics;
+import org.hibernate.test.tm.DummyConnectionProvider;
+import org.hibernate.test.tm.DummyTransactionManagerLookup;
+import org.hibernate.transaction.JDBCTransactionFactory;
+
+/**
+ * Common requirement testing for each {@link org.hibernate.cache.CacheProvider} impl.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class BaseCacheProviderTestCase extends FunctionalTestCase {
+
+	// note that a lot of the fucntionality here is intended to be used
+	// in creating specific tests for each CacheProvider that would extend
+	// from a base test case (this) for common requirement testing...
+
+	public BaseCacheProviderTestCase(String x) {
+		super( x );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "cache/Item.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.CACHE_REGION_PREFIX, "" );
+		cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+		cfg.setProperty( Environment.USE_STRUCTURED_CACHE, "true" );
+		cfg.setProperty( Environment.CACHE_PROVIDER, getCacheProvider().getName() );
+
+		if ( getConfigResourceKey() != null ) {
+			cfg.setProperty( getConfigResourceKey(), getConfigResourceLocation() );
+		}
+
+		if ( useTransactionManager() ) {
+			cfg.setProperty( Environment.CONNECTION_PROVIDER, DummyConnectionProvider.class.getName() );
+			cfg.setProperty( Environment.TRANSACTION_MANAGER_STRATEGY, DummyTransactionManagerLookup.class.getName() );
+		}
+		else {
+			cfg.setProperty( Environment.TRANSACTION_STRATEGY, JDBCTransactionFactory.class.getName() );
+		}
+	}
+
+	/**
+	 * The cache provider to be tested.
+	 *
+	 * @return The cache provider.
+	 */
+	protected abstract Class getCacheProvider();
+
+	/**
+	 * For provider-specific configuration, the name of the property key the
+	 * provider expects.
+	 *
+	 * @return The provider-specific config key.
+	 */
+	protected abstract String getConfigResourceKey();
+
+	/**
+	 * For provider-specific configuration, the resource location of that
+	 * config resource.
+	 *
+	 * @return The config resource location.
+	 */
+	protected abstract String getConfigResourceLocation();
+
+	/**
+	 * Should we use a transaction manager for transaction management.
+	 *
+	 * @return True if we should use a RM; false otherwise.
+	 */
+	protected abstract boolean useTransactionManager();
+
+
+	public void testQueryCacheInvalidation() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Item i = new Item();
+		i.setName("widget");
+		i.setDescription("A really top-quality, full-featured widget.");
+		s.persist(i);
+		t.commit();
+		s.close();
+
+		SecondLevelCacheStatistics slcs = s.getSessionFactory().getStatistics()
+				.getSecondLevelCacheStatistics( Item.class.getName() );
+
+		assertEquals( slcs.getPutCount(), 1 );
+		assertEquals( slcs.getElementCountInMemory(), 1 );
+		assertEquals( slcs.getEntries().size(), 1 );
+
+		s = openSession();
+		t = s.beginTransaction();
+		i = (Item) s.get( Item.class, i.getId() );
+
+		assertEquals( slcs.getHitCount(), 1 );
+		assertEquals( slcs.getMissCount(), 0 );
+
+		i.setDescription("A bog standard item");
+
+		t.commit();
+		s.close();
+
+		assertEquals( slcs.getPutCount(), 2 );
+
+		Object entry = slcs.getEntries().get( i.getId() );
+		Map map;
+		if ( entry instanceof ReadWriteCache.Item ) {
+			map = (Map) ( (ReadWriteCache.Item) entry ).getValue();
+		}
+		else {
+			map = (Map) entry;
+		}
+		assertTrue( map.get("description").equals("A bog standard item") );
+		assertTrue( map.get("name").equals("widget") );
+
+		// cleanup
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( i );
+		t.commit();
+		s.close();
+	}
+
+	public void testEmptySecondLevelCacheEntry() throws Exception {
+		getSessions().evictEntity( Item.class.getName() );
+		Statistics stats = getSessions().getStatistics();
+		stats.clear();
+		SecondLevelCacheStatistics statistics = stats.getSecondLevelCacheStatistics( Item.class.getName() );
+        Map cacheEntries = statistics.getEntries();
+		assertEquals( 0, cacheEntries.size() );
+	}
+
+	public void testStaleWritesLeaveCacheConsistent() {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		VersionedItem item = new VersionedItem();
+		item.setName( "steve" );
+		item.setDescription( "steve's item" );
+		s.save( item );
+		txn.commit();
+		s.close();
+
+		Long initialVersion = item.getVersion();
+
+		// manually revert the version property
+		item.setVersion( new Long( item.getVersion().longValue() - 1 ) );
+
+		try {
+			s = openSession();
+			txn = s.beginTransaction();
+			s.update( item );
+			txn.commit();
+			s.close();
+			fail( "expected stale write to fail" );
+		}
+		catch( Throwable expected ) {
+			// expected behavior here
+			if ( txn != null ) {
+				try {
+					txn.rollback();
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+		}
+		finally {
+			if ( s != null && s.isOpen() ) {
+				try {
+					s.close();
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+		}
+
+		// check the version value in the cache...
+		SecondLevelCacheStatistics slcs = sfi().getStatistics()
+				.getSecondLevelCacheStatistics( VersionedItem.class.getName() );
+
+		Object entry = slcs.getEntries().get( item.getId() );
+		Long cachedVersionValue;
+		if ( entry instanceof ReadWriteCache.Lock ) {
+			//FIXME don't know what to test here
+			cachedVersionValue = new Long( ( (ReadWriteCache.Lock) entry).getUnlockTimestamp() );
+		}
+		else {
+			cachedVersionValue = ( Long ) ( (Map) entry ).get( "_version" );
+			assertEquals( initialVersion.longValue(), cachedVersionValue.longValue() );
+		}
+
+
+		// cleanup
+		s = openSession();
+		txn = s.beginTransaction();
+		item = ( VersionedItem ) s.load( VersionedItem.class, item.getId() );
+		s.delete( item );
+		txn.commit();
+		s.close();
+
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/CacheSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/CacheSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/CacheSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+package org.hibernate.test.cache;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.hibernate.test.cache.treecache.optimistic.OptimisticTreeCacheTest;
+import org.hibernate.test.cache.treecache.pessimistic.TreeCacheTest;
+import org.hibernate.test.cache.ehcache.EhCacheTest;
+
+/**
+ * @author Steve Ebersole
+ */
+public class CacheSuite {
+
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "CacheProvider tests");
+		suite.addTest( OptimisticTreeCacheTest.suite() );
+		suite.addTest( TreeCacheTest.suite() );
+		suite.addTest( EhCacheTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/Item.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/Item.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/Item.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.cache">
+
+	<class name="Item" table="Items">
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		<property name="name" not-null="true"/>
+		<property name="description" not-null="true"/>
+	</class>
+
+	<class name="VersionedItem" table="VersionedItems">
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+        <version name="version" type="long"/>
+        <property name="name" not-null="true"/>
+		<property name="description" not-null="true"/>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/Item.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/Item.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/Item.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/Item.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+//$Id: Item.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.cache;
+
+
+/**
+ * @author Gavin King
+ */
+public class Item {
+	private Long id;
+	private String name;
+	private String description;
+	
+	public String getDescription() {
+		return description;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/Item.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/VersionedItem.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/VersionedItem.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/VersionedItem.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+package org.hibernate.test.cache;
+
+/**
+ * @author Steve Ebersole
+ */
+public class VersionedItem extends Item {
+	private Long version;
+
+	public Long getVersion() {
+		return version;
+	}
+
+	public void setVersion(Long version) {
+		this.version = version;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/ehcache/EhCacheTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/ehcache/EhCacheTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/ehcache/EhCacheTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+//$Id: $
+package org.hibernate.test.cache.ehcache;
+
+import junit.framework.Test;
+
+import org.hibernate.cache.EhCacheProvider;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.cache.BaseCacheProviderTestCase;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class EhCacheTest extends BaseCacheProviderTestCase {
+
+	// note that a lot of the fucntionality here is intended to be used
+	// in creating specific tests for each CacheProvider that would extend
+	// from a base test case (this) for common requirement testing...
+
+	public EhCacheTest(String x) {
+		super( x );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( EhCacheTest.class );
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return "read-write";
+	}
+
+	protected Class getCacheProvider() {
+		return EhCacheProvider.class;
+	}
+
+	protected String getConfigResourceKey() {
+		return Environment.CACHE_PROVIDER_CONFIG;
+	}
+
+	protected String getConfigResourceLocation() {
+		return "org/hibernate/test/cache/ehcache/ehcache.xml";
+	}
+
+	protected boolean useTransactionManager() {
+		return false;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/ehcache/ehcache.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/ehcache/ehcache.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/ehcache/ehcache.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,88 @@
+<ehcache>
+
+    <!-- Sets the path to the directory where cache .data files are created.
+
+         If the path is a Java System Property it is replaced by
+         its value in the running VM.
+
+         The following properties are translated:
+         user.home - User's home directory
+         user.dir - User's current working directory
+         java.io.tmpdir - Default temp file path -->
+    <diskStore path="java.io.tmpdir"/>
+
+
+    <!--Default Cache configuration. These will applied to caches programmatically created through
+        the CacheManager.
+
+        The following attributes are required for defaultCache:
+
+        maxInMemory       - Sets the maximum number of objects that will be created in memory
+        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
+                            is never expired.
+        timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
+                            if the element is not eternal. Idle time is now - last accessed time
+        timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
+                            if the element is not eternal. TTL is now - creation time
+        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
+                            has reached the maxInMemory limit.
+
+        -->
+    <defaultCache
+        maxElementsInMemory="10000"
+        eternal="false"
+        timeToIdleSeconds="120"
+        timeToLiveSeconds="120"
+        overflowToDisk="true"
+        />
+
+    <!--Predefined caches.  Add your cache configuration settings here.
+        If you do not have a configuration for your cache a WARNING will be issued when the
+        CacheManager starts
+
+        The following attributes are required for defaultCache:
+
+        name              - Sets the name of the cache. This is used to identify the cache. It must be unique.
+        maxInMemory       - Sets the maximum number of objects that will be created in memory
+        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
+                            is never expired.
+        timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
+                            if the element is not eternal. Idle time is now - last accessed time
+        timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
+                            if the element is not eternal. TTL is now - creation time
+        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
+                            has reached the maxInMemory limit.
+
+        -->
+
+    <!-- Sample cache named sampleCache1
+        This cache contains a maximum in memory of 10000 elements, and will expire
+        an element if it is idle for more than 5 minutes and lives for more than
+        10 minutes.
+
+        If there are more than 10000 elements it will overflow to the
+        disk cache, which in this configuration will go to wherever java.io.tmp is
+        defined on your system. On a standard Linux system this will be /tmp"
+        -->
+    <cache name="sampleCache1"
+        maxElementsInMemory="10000"
+        eternal="false"
+        timeToIdleSeconds="300"
+        timeToLiveSeconds="600"
+        overflowToDisk="true"
+        />
+
+    <!-- Sample cache named sampleCache2
+        This cache contains 1000 elements. Elements will always be held in memory.
+        They are not expired. -->
+    <cache name="sampleCache2"
+        maxElementsInMemory="1000"
+        eternal="true"
+        timeToIdleSeconds="0"
+        timeToLiveSeconds="0"
+        overflowToDisk="false"
+        /> -->
+
+    <!-- Place configuration for your caches following -->
+
+</ehcache>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/optimistic/OptimisticTreeCacheTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/optimistic/OptimisticTreeCacheTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/optimistic/OptimisticTreeCacheTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,113 @@
+package org.hibernate.test.cache.treecache.optimistic;
+
+import junit.framework.Test;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.TreeCache;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.optimistic.DataVersion;
+
+import org.hibernate.cache.OptimisticTreeCacheProvider;
+import org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.cache.BaseCacheProviderTestCase;
+import org.hibernate.test.tm.DummyTransactionManager;
+
+/**
+ * @author Steve Ebersole
+ */
+public class OptimisticTreeCacheTest extends BaseCacheProviderTestCase {
+
+	// note that a lot of the fucntionality here is intended to be used
+	// in creating specific tests for each CacheProvider that would extend
+	// from a base test case (this) for common requirement testing...
+
+	public OptimisticTreeCacheTest(String x) {
+		super( x );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( OptimisticTreeCacheTest.class );
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return "transactional";
+	}
+
+	protected Class getCacheProvider() {
+		return OptimisticTreeCacheProvider.class;
+	}
+
+	protected String getConfigResourceKey() {
+		return Environment.CACHE_PROVIDER_CONFIG;
+	}
+
+	protected String getConfigResourceLocation() {
+		return "org/hibernate/test/cache/treecache/optimistic/treecache.xml";
+	}
+
+	protected boolean useTransactionManager() {
+		return true;
+	}
+
+	public void testCacheLevelStaleWritesFail() throws Throwable {
+		Fqn fqn = new Fqn( "whatever" );
+		TreeCache treeCache = ( ( OptimisticTreeCacheProvider ) ( ( RegionFactoryCacheProviderBridge ) sfi().getSettings().getRegionFactory() ).getCacheProvider() ).getUnderlyingCache();
+
+		Long long1 = new Long(1);
+		Long long2 = new Long(2);
+
+		try {
+			System.out.println( "****************************************************************" );
+			DummyTransactionManager.INSTANCE.begin();
+			treeCache.put( fqn, "ITEM", long1, ManualDataVersion.gen( 1 ) );
+			DummyTransactionManager.INSTANCE.commit();
+
+			System.out.println( "****************************************************************" );
+			DummyTransactionManager.INSTANCE.begin();
+			treeCache.put( fqn, "ITEM", long2, ManualDataVersion.gen( 2 ) );
+			DummyTransactionManager.INSTANCE.commit();
+
+			try {
+				System.out.println( "****************************************************************" );
+				DummyTransactionManager.INSTANCE.begin();
+				treeCache.put( fqn, "ITEM", long1, ManualDataVersion.gen( 1 ) );
+				DummyTransactionManager.INSTANCE.commit();
+				fail( "stale write allowed" );
+			}
+			catch( Throwable ignore ) {
+				// expected behavior
+				DummyTransactionManager.INSTANCE.rollback();
+			}
+
+			Long current = ( Long ) treeCache.get( fqn, "ITEM" );
+			assertEquals( "unexpected current value", 2, current.longValue() );
+		}
+		finally {
+			try {
+				treeCache.remove( fqn, "ITEM" );
+			}
+			catch( Throwable ignore ) {
+			}
+		}
+	}
+
+	private static class ManualDataVersion implements DataVersion {
+		private final int version;
+
+		public ManualDataVersion(int version) {
+			this.version = version;
+		}
+
+		public boolean newerThan(DataVersion dataVersion) {
+			return this.version > ( ( ManualDataVersion ) dataVersion ).version;
+		}
+
+		public static Option gen(int version) {
+			ManualDataVersion mdv = new ManualDataVersion( version );
+			Option option = new Option();
+			option.setDataVersion( mdv );
+			return option;
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/optimistic/treecache.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/optimistic/treecache.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/optimistic/treecache.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ===================================================================== -->
+<!--                                                                       -->
+<!--  Sample TreeCache Service Configuration                               -->
+<!--  Recommended for use as Hibernate's 2nd Level Cache                   -->
+<!--  For use with JBossCache >= 1.3.0 ONLY!!!                             -->
+<!--                                                                       -->
+<!-- ===================================================================== -->
+
+<server>
+
+    <classpath codebase="./lib" archives="jboss-cache.jar, jgroups.jar"/>
+
+
+    <!-- ==================================================================== -->
+    <!-- Defines TreeCache configuration                                      -->
+    <!-- ==================================================================== -->
+
+    <mbean code="org.jboss.cache.TreeCache"
+        name="jboss.cache:service=TreeCache">
+
+        <depends>jboss:service=Naming</depends>
+        <depends>jboss:service=TransactionManager</depends>
+
+        <!--
+            Configure the TransactionManager : no matter since Hibernate will plug in
+            an "adapter" to its own TransactionManagerLookup strategy here
+        -->
+        <attribute name="TransactionManagerLookupClass">org.jboss.cache.GenericTransactionManagerLookup</attribute>
+
+
+        <!--
+            Node locking scheme:
+                OPTIMISTIC
+                PESSIMISTIC (default)
+        -->
+        <attribute name="NodeLockingScheme">OPTIMISTIC</attribute>
+
+        <!--
+            Note that this attribute is IGNORED if your NodeLockingScheme above is OPTIMISTIC.
+
+            Isolation level : SERIALIZABLE
+                              REPEATABLE_READ (default)
+                              READ_COMMITTED
+                              READ_UNCOMMITTED
+                              NONE
+        -->
+        <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
+
+        <!--
+             Valid modes are LOCAL
+                             REPL_ASYNC
+                             REPL_SYNC
+                             INVALIDATION_ASYNC
+                             INVALIDATION_SYNC
+
+             INVALIDATION_ASYNC is highly recommended as the mode for use
+             with clustered second-level caches.
+        -->
+        <attribute name="CacheMode">LOCAL</attribute>
+
+        <!--
+        Just used for async repl: use a replication queue
+        -->
+        <attribute name="UseReplQueue">false</attribute>
+
+        <!--
+            Replication interval for replication queue (in ms)
+        -->
+        <attribute name="ReplQueueInterval">0</attribute>
+
+        <!--
+            Max number of elements which trigger replication
+        -->
+        <attribute name="ReplQueueMaxElements">0</attribute>
+
+        <!-- Name of cluster. Needs to be the same for all clusters, in order
+             to find each other
+        -->
+        <attribute name="ClusterName">TreeCache-Cluster</attribute>
+
+        <!-- JGroups protocol stack properties. Can also be a URL,
+             e.g. file:/home/bela/default.xml
+           <attribute name="ClusterProperties"></attribute>
+        -->
+
+        <attribute name="ClusterConfig">
+            <config>
+                <!-- UDP: if you have a multihomed machine,
+                set the bind_addr attribute to the appropriate NIC IP address -->
+                <!-- UDP: On Windows machines, because of the media sense feature
+                 being broken with multicast (even after disabling media sense)
+                 set the loopback attribute to true -->
+                <UDP mcast_addr="228.1.2.3" mcast_port="48866"
+                    ip_ttl="64" ip_mcast="true"
+                    mcast_send_buf_size="150000" mcast_recv_buf_size="80000"
+                    ucast_send_buf_size="150000" ucast_recv_buf_size="80000"
+                    loopback="false"/>
+                <PING timeout="2000" num_initial_members="3"
+                    up_thread="false" down_thread="false"/>
+                <MERGE2 min_interval="10000" max_interval="20000"/>
+                <!--        <FD shun="true" up_thread="true" down_thread="true" />-->
+                <FD_SOCK/>
+                <VERIFY_SUSPECT timeout="1500"
+                    up_thread="false" down_thread="false"/>
+                <pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
+                    max_xmit_size="8192" up_thread="false" down_thread="false"/>
+                <UNICAST timeout="600,1200,2400" window_size="100" min_threshold="10"
+                    down_thread="false"/>
+                <pbcast.STABLE desired_avg_gossip="20000"
+                    up_thread="false" down_thread="false"/>
+                <FRAG frag_size="8192"
+                    down_thread="false" up_thread="false"/>
+                <pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
+                    shun="true" print_local_addr="true"/>
+                <pbcast.STATE_TRANSFER up_thread="true" down_thread="true"/>
+            </config>
+        </attribute>
+
+        <!--
+         Whether or not to fetch state on joining a cluster
+         NOTE this used to be called FetchStateOnStartup and has been renamed to be more descriptive.
+        -->
+        <attribute name="FetchInMemoryState">false</attribute>
+
+        <!--
+            Number of milliseconds to wait until all responses for a
+            synchronous call have been received.
+        -->
+        <attribute name="SyncReplTimeout">20000</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+
+
+        <!-- Name of the eviction policy class. -->
+        <attribute name="EvictionPolicyClass"></attribute>
+
+       <!--
+          Indicate whether to use marshalling or not. Set this to true if you are running under a scoped
+          class loader, e.g., inside an application server. Default is "false".
+       -->
+       <attribute name="UseMarshalling">false</attribute>
+
+    </mbean>
+</server>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/pessimistic/TreeCacheTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/pessimistic/TreeCacheTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/pessimistic/TreeCacheTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+package org.hibernate.test.cache.treecache.pessimistic;
+
+import junit.framework.Test;
+
+import org.hibernate.cache.TreeCacheProvider;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.cache.BaseCacheProviderTestCase;
+
+/**
+ * @author Steve Ebersole
+ */
+public class TreeCacheTest extends BaseCacheProviderTestCase {
+
+	// note that a lot of the fucntionality here is intended to be used
+	// in creating specific tests for each CacheProvider that would extend
+	// from a base test case (this) for common requirement testing...
+
+	public TreeCacheTest(String x) {
+		super( x );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( TreeCacheTest.class );
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return "transactional";
+	}
+
+	protected Class getCacheProvider() {
+		return TreeCacheProvider.class;
+	}
+
+	protected String getConfigResourceKey() {
+		return Environment.CACHE_PROVIDER_CONFIG;
+	}
+
+	protected String getConfigResourceLocation() {
+		return "org/hibernate/test/cache/treecache/pessimistic/treecache.xml";
+	}
+
+	protected boolean useTransactionManager() {
+		return true;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/pessimistic/treecache.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/pessimistic/treecache.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cache/treecache/pessimistic/treecache.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ===================================================================== -->
+<!--                                                                       -->
+<!--  Sample TreeCache Service Configuration                               -->
+<!--                                                                       -->
+<!-- ===================================================================== -->
+
+<server>
+
+    <classpath codebase="./lib" archives="jboss-cache.jar, jgroups.jar"/>
+
+
+    <!-- ==================================================================== -->
+    <!-- Defines TreeCache configuration                                      -->
+    <!-- ==================================================================== -->
+
+    <mbean code="org.jboss.cache.TreeCache"
+        name="jboss.cache:service=TreeCache">
+
+        <depends>jboss:service=Naming</depends>
+        <depends>jboss:service=TransactionManager</depends>
+
+        <!--
+            TransactionManager configuration not required for Hibernate!
+        -->
+
+
+        <!--
+            Node isolation level : SERIALIZABLE
+                                 REPEATABLE_READ (default)
+                                 READ_COMMITTED
+                                 READ_UNCOMMITTED
+                                 NONE
+        -->
+        <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
+
+        <!--
+             Valid modes are LOCAL
+                             REPL_ASYNC
+                             REPL_SYNC
+        -->
+        <attribute name="CacheMode">LOCAL</attribute>
+
+        <!-- Name of cluster. Needs to be the same for all clusters, in order
+             to find each other
+        -->
+        <attribute name="ClusterName">TreeCache-Cluster</attribute>
+
+        <!-- JGroups protocol stack properties. Can also be a URL,
+             e.g. file:/home/bela/default.xml
+           <attribute name="ClusterProperties"></attribute>
+        -->
+
+        <attribute name="ClusterConfig">
+            <config>
+                <!-- UDP: if you have a multihomed machine,
+                set the bind_addr attribute to the appropriate NIC IP address -->
+                <!-- UDP: On Windows machines, because of the media sense feature
+                 being broken with multicast (even after disabling media sense)
+                 set the loopback attribute to true -->
+                <UDP mcast_addr="228.1.2.3" mcast_port="45566"
+                    ip_ttl="64" ip_mcast="true"
+                    mcast_send_buf_size="150000" mcast_recv_buf_size="80000"
+                    ucast_send_buf_size="150000" ucast_recv_buf_size="80000"
+                    loopback="false"/>
+                <PING timeout="2000" num_initial_members="3"
+                    up_thread="false" down_thread="false"/>
+                <MERGE2 min_interval="10000" max_interval="20000"/>
+                <FD shun="true" up_thread="true" down_thread="true"/>
+                <VERIFY_SUSPECT timeout="1500"
+                    up_thread="false" down_thread="false"/>
+                <pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
+                    up_thread="false" down_thread="false"/>
+                <pbcast.STABLE desired_avg_gossip="20000"
+                    up_thread="false" down_thread="false"/>
+                <UNICAST timeout="600,1200,2400" window_size="100" min_threshold="10"
+                    down_thread="false"/>
+                <FRAG frag_size="8192"
+                    down_thread="false" up_thread="false"/>
+                <pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
+                    shun="true" print_local_addr="true"/>
+                <pbcast.STATE_TRANSFER up_thread="false" down_thread="false"/>
+            </config>
+        </attribute>
+
+        <!--
+             Max number of entries in the cache. If this is exceeded, the
+             eviction policy will kick some entries out in order to make
+             more room
+        -->
+        <attribute name="MaxCapacity">20000</attribute>
+
+        <!--
+            The max amount of time (in milliseconds) we wait until the
+            initial state (ie. the contents of the cache) are retrieved from
+            existing members in a clustered environment
+        -->
+        <attribute name="InitialStateRetrievalTimeout">20000</attribute>
+
+        <!--
+            Number of milliseconds to wait until all responses for a
+            synchronous call have been received.
+        -->
+        <attribute name="SyncReplTimeout">10000</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+
+        <!-- Max number of milliseconds we hold a lock (not currently
+        implemented) -->
+        <attribute name="LockLeaseTimeout">60000</attribute>
+
+        <!-- Name of the eviction policy class. Not supported now. -->
+        <attribute name="EvictionPolicyClass"></attribute>
+    </mbean>
+
+
+</server>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/Job.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/Job.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/Job.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.cascade">
+
+	<class name="Job" table="T_JOB">
+		<id name="id" column="JOB_ID">
+			<generator class="native"/>
+		</id>
+
+		<many-to-one name="batch" class="JobBatch" cascade="none" column="BATCH_ID"/>
+
+		<property name="status" type="int" column="JOB_STATUS" not-null="true"/>
+		<property name="processingInstructions" type="string" column="PI" not-null="true"/>
+
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/Job.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/Job.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/Job.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+// $Id: Job.java 6663 2005-05-03 20:55:31Z steveebersole $
+package org.hibernate.test.cascade;
+
+/**
+ * Implementation of Job.
+ *
+ * @author Steve Ebersole
+ */
+public class Job {
+	private Long id;
+	private JobBatch batch;
+	private String processingInstructions;
+	private int status;
+
+	/** GCLIB constructor */
+	Job() {}
+
+	protected Job(JobBatch batch) {
+		this.batch = batch;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	/*package*/ void setId(Long id) {
+		this.id = id;
+	}
+
+	public JobBatch getBatch() {
+		return batch;
+	}
+
+	/*package*/ void setBatch(JobBatch batch) {
+		this.batch = batch;
+	}
+
+	public String getProcessingInstructions() {
+		return processingInstructions;
+	}
+
+	public void setProcessingInstructions(String processingInstructions) {
+		this.processingInstructions = processingInstructions;
+	}
+
+	public int getStatus() {
+		return status;
+	}
+
+	public void setStatus(int status) {
+		this.status = status;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/JobBatch.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/JobBatch.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/JobBatch.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.cascade">
+
+	<class name="JobBatch" table="T_JOB_BATCH">
+		<id name="id" column="BATCH_ID">
+			<generator class="native"/>
+		</id>
+
+		<property name="batchDate" type="timestamp" column="BATCH_DATE" not-null="true"/>
+
+		<set name="jobs" inverse="true" fetch="select" lazy="true" cascade="all, refresh">
+			<key column="BATCH_ID"/>
+			<one-to-many class="Job"/>
+		</set>
+
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/JobBatch.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/JobBatch.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/JobBatch.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+// $Id: JobBatch.java 6663 2005-05-03 20:55:31Z steveebersole $
+package org.hibernate.test.cascade;
+
+import java.util.Date;
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * Implementation of JobBatch.
+ *
+ * @author Steve Ebersole
+ */
+public class JobBatch {
+	private Long id;
+	private Date batchDate;
+	private Set jobs = new HashSet();
+
+	/** CGLIB constructor */
+	JobBatch() {}
+
+	public JobBatch(Date batchDate) {
+		this.batchDate = batchDate;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Date getBatchDate() {
+		return batchDate;
+	}
+
+	public void setBatchDate(Date batchDate) {
+		this.batchDate = batchDate;
+	}
+
+	public Set getJobs() {
+		return jobs;
+	}
+
+	public void setJobs(Set jobs) {
+		this.jobs = jobs;
+	}
+
+	public Job createJob() {
+		Job job = new Job( this );
+		jobs.add( job );
+		return job;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/RefreshTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/RefreshTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cascade/RefreshTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,79 @@
+// $Id: RefreshTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.cascade;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.util.Date;
+import java.util.Iterator;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Implementation of RefreshTest.
+ *
+ * @author Steve Ebersole
+ */
+public class RefreshTest extends FunctionalTestCase {
+
+	public RefreshTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "cascade/Job.hbm.xml", "cascade/JobBatch.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( RefreshTest.class );
+	}
+
+	public void testRefreshCascade() throws Throwable {
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+
+		JobBatch batch = new JobBatch( new Date() );
+		batch.createJob().setProcessingInstructions( "Just do it!" );
+		batch.createJob().setProcessingInstructions( "I know you can do it!" );
+
+		// write the stuff to the database; at this stage all job.status values are zero
+		session.persist( batch );
+		session.flush();
+
+		// behind the session's back, let's modify the statuses
+		updateStatuses( session.connection() );
+
+		// Now lets refresh the persistent batch, and see if the refresh cascaded to the jobs collection elements
+		session.refresh( batch );
+
+		Iterator itr = batch.getJobs().iterator();
+		while( itr.hasNext() ) {
+			Job job = ( Job ) itr.next();
+			assertEquals( "Jobs not refreshed!", 1, job.getStatus() );
+		}
+
+		txn.rollback();
+		session.close();
+	}
+
+	private void updateStatuses(Connection connection) throws Throwable {
+		PreparedStatement stmnt = null;
+		try {
+			stmnt = connection.prepareStatement( "UPDATE T_JOB SET JOB_STATUS = 1" );
+			stmnt.executeUpdate();
+		}
+		finally {
+			if ( stmnt != null ) {
+				try {
+					stmnt.close();
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cfg/Cacheable.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cfg/Cacheable.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cfg/Cacheable.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+
+    <class entity-name="Entity">
+        <id name="id" type="long" column="ID">
+            <generator class="increment"/>
+        </id>
+        <property name="name" type="string" column="NAME"/>
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cfg/CacheableFileTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cfg/CacheableFileTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cfg/CacheableFileTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+package org.hibernate.test.cfg;
+
+import java.io.File;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.junit.UnitTestCase;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class CacheableFileTest extends UnitTestCase {
+
+	public static final String MAPPING = "org/hibernate/test/cfg/Cacheable.hbm.xml";
+
+	private File mappingFile;
+
+	public CacheableFileTest(String string) {
+		super( string );
+	}
+
+	protected void setUp() throws Exception {
+		super.setUp();
+		mappingFile = new File( getClass().getClassLoader().getResource( MAPPING ).getFile() );
+		assertTrue( mappingFile.exists() );
+		File cached = new File( mappingFile.getParentFile(), mappingFile.getName() + ".bin" );
+		if ( cached.exists() ) {
+			cached.delete();
+		}
+	}
+
+	protected void tearDown() throws Exception {
+		mappingFile = null;
+		super.tearDown();
+	}
+
+	public void testCachedFiles() {
+		Configuration cfg = new Configuration();
+		cfg.addCacheableFile( mappingFile );
+		Configuration cfg2 = new Configuration();
+		cfg2.addCacheableFile( mappingFile );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/CompositeIdTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/CompositeIdTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/CompositeIdTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,269 @@
+//$Id: CompositeIdTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.cid;
+
+import java.math.BigDecimal;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class CompositeIdTest extends FunctionalTestCase {
+	
+	public CompositeIdTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "cid/Customer.hbm.xml", "cid/Order.hbm.xml", "cid/LineItem.hbm.xml", "cid/Product.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite(CompositeIdTest.class);
+	}
+	
+	public void testQuery() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createQuery("from LineItem ol where ol.order.id.customerId = 'C111'").list();
+		t.commit();
+		s.close();
+	}
+	
+	public void testCompositeIds() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		
+		Product p = new Product();
+		p.setProductId("A123");
+		p.setDescription("nipple ring");
+		p.setPrice( new BigDecimal(1.0) );
+		p.setNumberAvailable(1004);
+		s.persist(p);
+		
+		Product p2 = new Product();
+		p2.setProductId("X525");
+		p2.setDescription("nose stud");
+		p2.setPrice( new BigDecimal(3.0) );
+		p2.setNumberAvailable(105);
+		s.persist(p2);
+		
+		Customer c = new Customer();
+		c.setAddress("St Kilda Rd, MEL, 3000");
+		c.setName("Virginia");
+		c.setCustomerId("C111");
+		s.persist(c);
+		
+		Order o = new Order(c);
+		o.setOrderDate( Calendar.getInstance() );
+		LineItem li = new LineItem(o, p);
+		li.setQuantity(2);
+
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		o = (Order) s.get( Order.class, new Order.Id("C111", 0) );
+		assertEquals( o.getTotal().intValue(), 2 );
+		o.getCustomer().getName();
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery("from Customer c left join fetch c.orders o left join fetch o.lineItems li left join fetch li.product p").list();
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery("from Order o left join fetch o.lineItems li left join fetch li.product p").list();
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		Iterator iter = s.createQuery("select o.id, li.id from Order o join o.lineItems li").list().iterator();
+		while ( iter.hasNext() ) {
+			Object[] stuff = (Object[]) iter.next();
+			assertTrue(stuff.length==2);
+		}
+		iter = s.createQuery("from Order o join o.lineItems li").iterate();
+		while ( iter.hasNext() ) {
+			Object[] stuff = (Object[]) iter.next();
+			assertTrue(stuff.length==2);
+		}
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Customer) s.get( Customer.class, "C111" );
+		Order o2 = new Order(c);
+		o2.setOrderDate( Calendar.getInstance() );
+		s.flush();
+		LineItem li2 = new LineItem(o2, p2);
+		li2.setQuantity(5);
+		List bigOrders = s.createQuery("from Order o where o.total>10.0").list();
+		assertEquals( bigOrders.size(), 1 );
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery("delete from LineItem").executeUpdate();
+		s.createQuery("delete from Order").executeUpdate();
+		s.createQuery("delete from Customer").executeUpdate();
+		s.createQuery("delete from Product").executeUpdate();
+		t.commit();
+		s.close();
+	}
+
+	
+	public void testNonLazyFetch() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		
+		Product p = new Product();
+		p.setProductId("A123");
+		p.setDescription("nipple ring");
+		p.setPrice( new BigDecimal(1.0) );
+		p.setNumberAvailable(1004);
+		s.persist(p);
+		
+		Product p2 = new Product();
+		p2.setProductId("X525");
+		p2.setDescription("nose stud");
+		p2.setPrice( new BigDecimal(3.0) );
+		p2.setNumberAvailable(105);
+		s.persist(p2);
+		
+		Customer c = new Customer();
+		c.setAddress("St Kilda Rd, MEL, 3000");
+		c.setName("Virginia");
+		c.setCustomerId("C111");
+		s.persist(c);
+		
+		Order o = new Order(c);
+		o.setOrderDate( Calendar.getInstance() );
+		LineItem li = new LineItem(o, p);
+		li.setQuantity(2);
+
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		o = (Order) s.get( Order.class, new Order.Id("C111", 0) );
+		assertEquals( o.getTotal().intValue(), 2 );
+		o.getCustomer().getName();
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		o = (Order) s.createQuery("from Order o left join fetch o.lineItems li left join fetch li.product p").uniqueResult();
+		assertTrue( Hibernate.isInitialized( o.getLineItems() ) );
+		li = (LineItem) o.getLineItems().iterator().next();
+		assertTrue( Hibernate.isInitialized( li ) );
+		assertTrue( Hibernate.isInitialized( li.getProduct() ) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		o = (Order) s.createQuery("from Order o").uniqueResult();
+		assertTrue( Hibernate.isInitialized( o.getLineItems() ) );
+		li = (LineItem) o.getLineItems().iterator().next();
+		assertTrue( Hibernate.isInitialized( li ) );
+		assertFalse( Hibernate.isInitialized( li.getProduct() ) );
+		t.commit();
+		s.close();
+		
+		
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery("delete from LineItem").executeUpdate();
+		s.createQuery("delete from Order").executeUpdate();
+		s.createQuery("delete from Customer").executeUpdate();
+		s.createQuery("delete from Product").executeUpdate();
+		t.commit();
+		s.close();
+		
+	}
+
+	public void testMultipleCollectionFetch() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		
+		Product p = new Product();
+		p.setProductId("A123");
+		p.setDescription("nipple ring");
+		p.setPrice( new BigDecimal(1.0) );
+		p.setNumberAvailable(1004);
+		s.persist(p);
+		
+		Product p2 = new Product();
+		p2.setProductId("X525");
+		p2.setDescription("nose stud");
+		p2.setPrice( new BigDecimal(3.0) );
+		p2.setNumberAvailable(105);
+		s.persist(p2);
+		
+		Customer c = new Customer();
+		c.setAddress("St Kilda Rd, MEL, 3000");
+		c.setName("Virginia");
+		c.setCustomerId("C111");
+		s.persist(c);
+		
+		Order o = new Order(c);
+		o.setOrderDate( Calendar.getInstance() );
+		LineItem li = new LineItem(o, p);
+		li.setQuantity(2);
+		LineItem li2 = new LineItem(o, p2);
+		li2.setQuantity(3);
+
+		Order o2 = new Order(c);
+		o2.setOrderDate( Calendar.getInstance() );
+		LineItem li3 = new LineItem(o2, p);
+		li3.setQuantity(1);
+		LineItem li4 = new LineItem(o2, p2);
+		li4.setQuantity(1);
+
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Customer) s.createQuery("from Customer c left join fetch c.orders o left join fetch o.lineItems li left join fetch li.product p").uniqueResult();
+		assertTrue( Hibernate.isInitialized( c.getOrders() ) );
+		assertEquals( c.getOrders().size(), 2 );
+		assertTrue( Hibernate.isInitialized( ( (Order) c.getOrders().get(0) ).getLineItems() ) );
+		assertTrue( Hibernate.isInitialized( ( (Order) c.getOrders().get(1) ).getLineItems() ) );
+		assertEquals( ( (Order) c.getOrders().get(0) ).getLineItems().size(), 2 );
+		assertEquals( ( (Order) c.getOrders().get(1) ).getLineItems().size(), 2 );
+		t.commit();
+		s.close();
+				
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery("delete from LineItem").executeUpdate();
+		s.createQuery("delete from Order").executeUpdate();
+		s.createQuery("delete from Customer").executeUpdate();
+		s.createQuery("delete from Product").executeUpdate();
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/CompositeIdTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Customer.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Customer.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Customer.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates how to map a collection
+  <key> to one of the primary key columns of an
+  associated child class with a composite key. This
+  is very useful for legacy data!
+     
+-->
+
+<hibernate-mapping package="org.hibernate.test.cid">
+
+    <class name="Customer">
+    
+    	<id name="customerId"
+    		length="10">
+    		<generator class="assigned"/>
+    	</id>
+
+    	<property name="name" not-null="true" length="100"/>
+    	<property name="address" not-null="true" length="200"/>
+
+    	<list name="orders"
+    		inverse="true"
+    		cascade="save-update">
+    		<key column="customerId"/>
+    		<index column="orderNumber"/>
+    		<one-to-many class="Order"/>
+    	</list>
+
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Customer.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,73 @@
+//$Id: Customer.java 4806 2004-11-25 14:37:00Z steveebersole $
+package org.hibernate.test.cid;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.GregorianCalendar;
+import java.math.BigDecimal;
+
+/**
+ * @author Gavin King
+ */
+public class Customer {
+	private String customerId;
+	private String name;
+	private String address;
+	private List orders = new ArrayList();
+	/**
+	 * @return Returns the address.
+	 */
+	public String getAddress() {
+		return address;
+	}
+	/**
+	 * @param address The address to set.
+	 */
+	public void setAddress(String address) {
+		this.address = address;
+	}
+	/**
+	 * @return Returns the customerId.
+	 */
+	public String getCustomerId() {
+		return customerId;
+	}
+	/**
+	 * @param customerId The customerId to set.
+	 */
+	public void setCustomerId(String customerId) {
+		this.customerId = customerId;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	/**
+	 * @return Returns the orders.
+	 */
+	public List getOrders() {
+		return orders;
+	}
+	/**
+	 * @param orders The orders to set.
+	 */
+	public void setOrders(List orders) {
+		this.orders = orders;
+	}
+
+	public Order generateNewOrder(BigDecimal total) {
+		Order order = new Order(this);
+		order.setOrderDate( new GregorianCalendar() );
+		order.setTotal( total );
+
+		return order;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Customer.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/LineItem.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/LineItem.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/LineItem.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates 
+  
+     (1) composite keys and many-to-one associations on 
+         composite keys
+      
+     (2) use of insert="false" update="false" on an
+         association mapping, when the foreign key is
+         also part of the primary key
+     
+-->
+
+<hibernate-mapping package="org.hibernate.test.cid">
+
+    <class name="LineItem">
+    	
+    	<composite-id name="id" 
+    		class="LineItem$Id">
+    		<key-property name="customerId" length="10"/>
+    		<key-property name="orderNumber"/>
+    		<key-property name="productId" length="10"/>
+    	</composite-id>
+    	
+    	<property name="quantity"/>
+    	
+    	<many-to-one name="order"
+    		insert="false"
+			update="false" 
+			not-null="true">
+			<column name="customerId"/>
+			<column name="orderNumber"/>
+		</many-to-one>
+    	
+    	<many-to-one name="product"
+    		insert="false"
+			update="false" 
+			not-null="true"
+			column="productId"/>
+			
+    </class>
+ 	
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/LineItem.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/LineItem.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/LineItem.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/LineItem.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,137 @@
+//$Id: LineItem.java 4806 2004-11-25 14:37:00Z steveebersole $
+package org.hibernate.test.cid;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class LineItem {
+	public static class Id implements Serializable {
+		private String customerId;
+		private int orderNumber;
+		private String productId;
+
+		public Id(String customerId, int orderNumber, String productId) {
+			this.customerId = customerId;
+			this.orderNumber = orderNumber;
+			this.productId = productId;
+		}
+		public Id() {}
+
+		/**
+		 * @return Returns the customerId.
+		 */
+		public String getCustomerId() {
+			return customerId;
+		}
+		/**
+		 * @param customerId The customerId to set.
+		 */
+		public void setCustomerId(String customerId) {
+			this.customerId = customerId;
+		}
+		/**
+		 * @return Returns the productId.
+		 */
+		public String getProductId() {
+			return productId;
+		}
+		/**
+		 * @param productId The productId to set.
+		 */
+		public void setProductId(String productId) {
+			this.productId = productId;
+		}
+		/**
+		 * @return Returns the orderNumber.
+		 */
+		public int getOrderNumber() {
+			return orderNumber;
+		}
+		/**
+		 * @param orderNumber The orderNumber to set.
+		 */
+		public void setOrderNumber(int orderNumber) {
+			this.orderNumber = orderNumber;
+		}
+		public int hashCode() {
+			return customerId.hashCode() + orderNumber + productId.hashCode();
+		}
+		public boolean equals(Object other) {
+			if (other instanceof Id) {
+				Id that = (Id) other;
+				return that.customerId.equals(this.customerId) &&
+					that.productId.equals(this.productId) &&
+					that.orderNumber == this.orderNumber;
+			}
+			else {
+				return false;
+			}
+		}
+	}
+
+	private Id id = new Id();
+	private int quantity;
+	private Order order;
+	private Product product;
+
+	public LineItem(Order o, Product p) {
+		this.order = o;
+		this.id.orderNumber = o.getId().getOrderNumber();
+		this.id.customerId = o.getId().getCustomerId();
+		this.id.productId = p.getProductId();
+		o.getLineItems().add(this);
+	}
+
+	public LineItem() {}
+
+	/**
+	 * @return Returns the order.
+	 */
+	public Order getOrder() {
+		return order;
+	}
+	/**
+	 * @param order The order to set.
+	 */
+	public void setOrder(Order order) {
+		this.order = order;
+	}
+	/**
+	 * @return Returns the product.
+	 */
+	public Product getProduct() {
+		return product;
+	}
+	/**
+	 * @param product The product to set.
+	 */
+	public void setProduct(Product product) {
+		this.product = product;
+	}
+	/**
+	 * @return Returns the quantity.
+	 */
+	public int getQuantity() {
+		return quantity;
+	}
+	/**
+	 * @param quantity The quantity to set.
+	 */
+	public void setQuantity(int quantity) {
+		this.quantity = quantity;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public Id getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Id id) {
+		this.id = id;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/LineItem.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Order.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Order.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Order.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.cid">
+
+<!-- 
+
+  This mapping demonstrates 
+  
+     (1) composite keys and one-to-many associations on 
+         composite keys
+      
+     (2) use of insert="false" update="false" on an
+         association mapping, when the foreign key is
+         also part of the primary key
+         
+     (3) use of a derived property which performs a
+         subselect against associated tables
+         
+     (4) use of <synchronize/> to ensure that auto-flush
+         works correctly for an entity with a property
+         derived from other tables
+         
+     
+-->
+
+    <class name="Order" table="CustomerOrder">
+    	<synchronize table="LineItem"/>
+    	<synchronize table="Product"/>
+    	
+    	<composite-id name="id" 
+    		class="Order$Id">
+    		<key-property name="customerId" length="10"/>
+    		<key-property name="orderNumber"/>
+    	</composite-id>
+    	
+    	<property name="orderDate" 
+    		type="calendar_date"
+    		not-null="true"/>
+    	
+    	<property name="total" 
+    		formula="( select sum(li.quantity*p.cost) from LineItem li, Product p where li.productId = p.productId and li.customerId = customerId and li.orderNumber = orderNumber )"/>
+    	
+    	<many-to-one name="customer"
+    		column="customerId"
+    		insert="false"
+			update="false" 
+			not-null="true"/>
+			
+    	<bag name="lineItems"
+    		fetch="join" 
+    		lazy="false"
+    		inverse="true"
+    		cascade="save-update">
+    		<key>
+    			<column name="customerId"/>
+    			<column name="orderNumber"/>
+    		</key>
+    		<one-to-many class="LineItem"/>
+    	</bag>
+    	
+    </class>
+ 	
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Order.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Order.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Order.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Order.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,145 @@
+//$Id: Order.java 4806 2004-11-25 14:37:00Z steveebersole $
+package org.hibernate.test.cid;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+
+/**
+ * @author Gavin King
+ */
+public class Order {
+	public static class Id implements Serializable {
+		private String customerId;
+		private int orderNumber;
+
+		public Id(String customerId, int orderNumber) {
+			this.customerId = customerId;
+			this.orderNumber = orderNumber;
+		}
+		public Id() {}
+
+		/**
+		 * @return Returns the customerId.
+		 */
+		public String getCustomerId() {
+			return customerId;
+		}
+		/**
+		 * @param customerId The customerId to set.
+		 */
+		public void setCustomerId(String customerId) {
+			this.customerId = customerId;
+		}
+		/**
+		 * @return Returns the orderNumber.
+		 */
+		public int getOrderNumber() {
+			return orderNumber;
+		}
+		/**
+		 * @param orderNumber The orderNumber to set.
+		 */
+		public void setOrderNumber(int orderNumber) {
+			this.orderNumber = orderNumber;
+		}
+		public int hashCode() {
+			return customerId.hashCode() + orderNumber;
+		}
+		public boolean equals(Object other) {
+			if (other instanceof Id) {
+				Id that = (Id) other;
+				return that.customerId.equals(this.customerId) &&
+					that.orderNumber == this.orderNumber;
+			}
+			else {
+				return false;
+			}
+		}
+	}
+
+	private Id id = new Id();
+	private Calendar orderDate;
+	private Customer customer;
+	private Collection lineItems = new ArrayList();
+	private BigDecimal total;
+
+	public Order(Customer customer) {
+		this.customer = customer;
+		this.id.customerId = customer.getCustomerId();
+		this.id.orderNumber = customer.getOrders().size();
+		customer.getOrders().add(this);
+	}
+
+	public Order() {}
+
+	/**
+	 * @return Returns the customer.
+	 */
+	public Customer getCustomer() {
+		return customer;
+	}
+	/**
+	 * @param customer The customer to set.
+	 */
+	public void setCustomer(Customer customer) {
+		this.customer = customer;
+	}
+	/**
+	 * @return Returns the lineItems.
+	 */
+	public Collection getLineItems() {
+		return lineItems;
+	}
+	/**
+	 * @param lineItems The lineItems to set.
+	 */
+	public void setLineItems(Collection lineItems) {
+		this.lineItems = lineItems;
+	}
+	/**
+	 * @return Returns the orderDate.
+	 */
+	public Calendar getOrderDate() {
+		return orderDate;
+	}
+	/**
+	 * @param orderDate The orderDate to set.
+	 */
+	public void setOrderDate(Calendar orderDate) {
+		this.orderDate = orderDate;
+	}
+	/**
+	 * @return Returns the total.
+	 */
+	public BigDecimal getTotal() {
+		return total;
+	}
+	/**
+	 * @param total The total to set.
+	 */
+	public void setTotal(BigDecimal total) {
+		this.total = total;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public Id getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Id id) {
+		this.id = id;
+	}
+
+	public LineItem generateLineItem( Product product, int quantity ) {
+		LineItem li = new LineItem( this, product );
+		li.setQuantity( quantity );
+		lineItems.add( li );
+		return li;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Order.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Product.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Product.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Product.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.cid">
+
+<!-- 
+
+  This mapping demonstrates 
+
+     (1) use of a derived property which performs a
+         subselect against an associated table
+         
+     (2) use of <synchronize/> to ensure that auto-flush
+         works correctly for an entity with a property
+         derived from another table
+         
+     
+-->
+
+    <class name="Product">
+    	<synchronize table="LineItem"/>
+    
+    	<id name="productId"
+    		length="10">
+    		<generator class="assigned"/>
+    	</id>
+    	
+    	<property name="description" 
+    		not-null="true" 
+    		length="200"/>
+    	<property name="price" length="3" column="cost"/>
+    	<property name="numberAvailable"/>
+    	
+    	<property name="numberOrdered"
+    		formula="( select sum(li.quantity) from LineItem li where li.productId = productId )"/>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Product.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Product.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Product.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Product.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,75 @@
+//$Id: Product.java 4806 2004-11-25 14:37:00Z steveebersole $
+package org.hibernate.test.cid;
+
+import java.math.BigDecimal;
+
+/**
+ * @author Gavin King
+ */
+public class Product {
+	private String productId;
+	private String description;
+	private BigDecimal price;
+	private int numberAvailable;
+	private int numberOrdered;
+	/**
+	 * @return Returns the description.
+	 */
+	public String getDescription() {
+		return description;
+	}
+	/**
+	 * @param description The description to set.
+	 */
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	/**
+	 * @return Returns the numberAvailable.
+	 */
+	public int getNumberAvailable() {
+		return numberAvailable;
+	}
+	/**
+	 * @param numberAvailable The numberAvailable to set.
+	 */
+	public void setNumberAvailable(int numberAvailable) {
+		this.numberAvailable = numberAvailable;
+	}
+	/**
+	 * @return Returns the numberOrdered.
+	 */
+	public int getNumberOrdered() {
+		return numberOrdered;
+	}
+	/**
+	 * @param numberOrdered The numberOrdered to set.
+	 */
+	public void setNumberOrdered(int numberOrdered) {
+		this.numberOrdered = numberOrdered;
+	}
+	/**
+	 * @return Returns the productId.
+	 */
+	public String getProductId() {
+		return productId;
+	}
+	/**
+	 * @param productId The productId to set.
+	 */
+	public void setProductId(String productId) {
+		this.productId = productId;
+	}
+	/**
+	 * @return Returns the price.
+	 */
+	public BigDecimal getPrice() {
+		return price;
+	}
+	/**
+	 * @param price The price to set.
+	 */
+	public void setPrice(BigDecimal price) {
+		this.price = price;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cid/Product.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/CollectionSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/CollectionSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/CollectionSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+package org.hibernate.test.collection;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.collection.bag.PersistentBagTest;
+import org.hibernate.test.collection.idbag.PersistentIdBagTest;
+import org.hibernate.test.collection.list.PersistentListTest;
+import org.hibernate.test.collection.map.PersistentMapTest;
+import org.hibernate.test.collection.original.CollectionTest;
+import org.hibernate.test.collection.set.PersistentSetTest;
+
+/**
+ * Suite of collection (i.e. PersistentCollection) related tests
+ *
+ * @author Steve Ebersole
+ */
+public class CollectionSuite {
+
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "Collection-related tests" );
+		suite.addTest( PersistentBagTest.suite() );
+		suite.addTest( PersistentIdBagTest.suite() );
+		suite.addTest( PersistentListTest.suite() );
+		suite.addTest( PersistentMapTest.suite() );
+		suite.addTest( CollectionTest.suite() );
+		suite.addTest( PersistentSetTest.suite() );
+		return suite;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/bag/BagOwner.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/bag/BagOwner.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/bag/BagOwner.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+package org.hibernate.test.collection.bag;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class BagOwner {
+	private String name;
+	private BagOwner parent;
+	private List children = new ArrayList();
+
+	public BagOwner() {
+	}
+
+	public BagOwner(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public BagOwner getParent() {
+		return parent;
+	}
+
+	public void setParent(BagOwner parent) {
+		this.parent = parent;
+	}
+
+	public List getChildren() {
+		return children;
+	}
+
+	public void setChildren(List children) {
+		this.children = children;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/bag/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/bag/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/bag/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+
+<hibernate-mapping package="org.hibernate.test.collection.bag">
+
+    <class name="BagOwner">
+		<id name="name" column="NAME" type="string" />
+
+        <many-to-one name="parent" class="BagOwner" cascade="none" />
+
+        <bag name="children" inverse="true" cascade="all">
+            <key column="PARENT" />
+            <one-to-many class="BagOwner" />
+        </bag>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/bag/PersistentBagTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/bag/PersistentBagTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/bag/PersistentBagTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,70 @@
+package org.hibernate.test.collection.bag;
+
+import java.util.ArrayList;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.collection.PersistentBag;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Tests related to operations on a PersistentBag.
+ *
+ * @author Steve Ebersole
+ */
+public class PersistentBagTest extends FunctionalTestCase {
+	public PersistentBagTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "collection/bag/Mappings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PersistentBagTest.class );
+	}
+
+	public void testWriteMethodDirtying() {
+		BagOwner parent = new BagOwner( "root" );
+		BagOwner child = new BagOwner( "c1" );
+		parent.getChildren().add( child );
+		child.setParent( parent );
+		BagOwner otherChild = new BagOwner( "c2" );
+
+		Session session = openSession();
+		session.beginTransaction();
+		session.save( parent );
+		session.flush();
+		// at this point, the list on parent has now been replaced with a PersistentBag...
+		PersistentBag children = ( PersistentBag ) parent.getChildren();
+
+		assertFalse( children.remove( otherChild ) );
+		assertFalse( children.isDirty() );
+
+		ArrayList otherCollection = new ArrayList();
+		otherCollection.add( child );
+		assertFalse( children.retainAll( otherCollection ) );
+		assertFalse( children.isDirty() );
+
+		otherCollection = new ArrayList();
+		otherCollection.add( otherChild );
+		assertFalse( children.removeAll( otherCollection ) );
+		assertFalse( children.isDirty() );
+
+		children.clear();
+		session.delete( child );
+		assertTrue( children.isDirty() );
+
+		session.flush();
+
+		children.clear();
+		assertFalse( children.isDirty() );
+
+		session.delete( parent );
+		session.getTransaction().commit();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/idbag/IdbagOwner.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/idbag/IdbagOwner.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/idbag/IdbagOwner.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+package org.hibernate.test.collection.idbag;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class IdbagOwner {
+	private String name;
+	private List children = new ArrayList();
+
+	public IdbagOwner() {
+	}
+
+	public IdbagOwner(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public List getChildren() {
+		return children;
+	}
+
+	public void setChildren(List children) {
+		this.children = children;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/idbag/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/idbag/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/idbag/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+
+<hibernate-mapping package="org.hibernate.test.collection.idbag">
+
+    <class name="IdbagOwner">
+		<id name="name" column="NAME" type="string" />
+
+        <idbag name="children" cascade="all" table="idbag_owner_children">
+            <collection-id column="CHILD" type="long">
+                <generator class="increment"/>
+            </collection-id>
+            <key column="PARENT_FK" />
+            <many-to-many column="CHILD_FK" class="IdbagOwner" />
+        </idbag>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/idbag/PersistentIdBagTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/idbag/PersistentIdBagTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/idbag/PersistentIdBagTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+package org.hibernate.test.collection.idbag;
+
+import java.util.ArrayList;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.collection.PersistentIdentifierBag;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Tests related to operations on a PersistentIdentifierBag
+ *
+ * @author Steve Ebersole
+ */
+public class PersistentIdBagTest extends FunctionalTestCase {
+	public PersistentIdBagTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "collection/idbag/Mappings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PersistentIdBagTest.class );
+	}
+
+	public void testWriteMethodDirtying() {
+		IdbagOwner parent = new IdbagOwner( "root" );
+		IdbagOwner child = new IdbagOwner( "c1" );
+		parent.getChildren().add( child );
+		IdbagOwner otherChild = new IdbagOwner( "c2" );
+
+		Session session = openSession();
+		session.beginTransaction();
+		session.save( parent );
+		session.flush();
+		// at this point, the list on parent has now been replaced with a PersistentBag...
+		PersistentIdentifierBag children = ( PersistentIdentifierBag ) parent.getChildren();
+
+		assertFalse( children.remove( otherChild ) );
+		assertFalse( children.isDirty() );
+
+		ArrayList otherCollection = new ArrayList();
+		otherCollection.add( child );
+		assertFalse( children.retainAll( otherCollection ) );
+		assertFalse( children.isDirty() );
+
+		otherCollection = new ArrayList();
+		otherCollection.add( otherChild );
+		assertFalse( children.removeAll( otherCollection ) );
+		assertFalse( children.isDirty() );
+
+		children.clear();
+		session.delete( child );
+		assertTrue( children.isDirty() );
+
+		session.flush();
+
+		children.clear();
+		assertFalse( children.isDirty() );
+
+		session.delete( parent );
+		session.getTransaction().commit();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/list/ListOwner.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/list/ListOwner.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/list/ListOwner.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+package org.hibernate.test.collection.list;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class ListOwner {
+	private String name;
+	private ListOwner parent;
+	private List children = new ArrayList();
+
+	public ListOwner() {
+	}
+
+	public ListOwner(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public ListOwner getParent() {
+		return parent;
+	}
+
+	public void setParent(ListOwner parent) {
+		this.parent = parent;
+	}
+
+	public List getChildren() {
+		return children;
+	}
+
+	public void setChildren(List children) {
+		this.children = children;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/list/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/list/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/list/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+
+<hibernate-mapping package="org.hibernate.test.collection.list">
+
+    <class name="ListOwner">
+		<id name="name" column="NAME" type="string" />
+
+        <many-to-one name="parent" class="ListOwner" cascade="none" />
+
+        <list name="children" inverse="true" cascade="all">
+            <key column="PARENT" />
+            <list-index column="LIST_INDEX"/>
+            <one-to-many class="ListOwner" />
+        </list>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/list/PersistentListTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/list/PersistentListTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/list/PersistentListTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,70 @@
+package org.hibernate.test.collection.list;
+
+import java.util.ArrayList;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.collection.PersistentList;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Tests related to operations on a PersistentList
+ *
+ * @author Steve Ebersole
+ */
+public class PersistentListTest extends FunctionalTestCase {
+	public PersistentListTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "collection/list/Mappings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PersistentListTest.class );
+	}
+
+	public void testWriteMethodDirtying() {
+		ListOwner parent = new ListOwner( "root" );
+		ListOwner child = new ListOwner( "c1" );
+		parent.getChildren().add( child );
+		child.setParent( parent );
+		ListOwner otherChild = new ListOwner( "c2" );
+
+		Session session = openSession();
+		session.beginTransaction();
+		session.save( parent );
+		session.flush();
+		// at this point, the list on parent has now been replaced with a PersistentList...
+		PersistentList children = ( PersistentList ) parent.getChildren();
+
+		assertFalse( children.remove( otherChild ) );
+		assertFalse( children.isDirty() );
+
+		ArrayList otherCollection = new ArrayList();
+		otherCollection.add( child );
+		assertFalse( children.retainAll( otherCollection ) );
+		assertFalse( children.isDirty() );
+
+		otherCollection = new ArrayList();
+		otherCollection.add( otherChild );
+		assertFalse( children.removeAll( otherCollection ) );
+		assertFalse( children.isDirty() );
+
+		children.clear();
+		session.delete( child );
+		assertTrue( children.isDirty() );
+
+		session.flush();
+
+		children.clear();
+		assertFalse( children.isDirty() );
+
+		session.delete( parent );
+		session.getTransaction().commit();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/Child.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/Child.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/Child.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+package org.hibernate.test.collection.map;
+
+/**
+ * todo: describe Child
+ *
+ * @author Steve Ebersole
+ */
+public class Child {
+	private String name;
+	private Parent parent;
+
+	public Child() {
+	}
+
+	public Child(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Parent getParent() {
+		return parent;
+	}
+
+	public void setParent(Parent parent) {
+		this.parent = parent;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+
+<hibernate-mapping package="org.hibernate.test.collection.map">
+
+    <class name="Parent">
+		<id name="name" column="NAME" type="string" />
+
+        <map name="children" inverse="true" cascade="all">
+            <key column="PARENT" />
+            <map-key type="string" />
+            <one-to-many class="Child" />
+        </map>
+	</class>
+
+    <class name="Child">
+        <id name="name" column="NAME" type="string"/>
+        <many-to-one name="parent" class="Parent" cascade="none" />
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/Parent.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/Parent.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/Parent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+package org.hibernate.test.collection.map;
+
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * todo: describe Parent
+ *
+ * @author Steve Ebersole
+ */
+public class Parent {
+	private String name;
+	private Map children = new HashMap();
+
+	public Parent() {
+	}
+
+	public Parent(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Map getChildren() {
+		return children;
+	}
+
+	public void setChildren(Map children) {
+		this.children = children;
+	}
+
+	public Child addChild(String name) {
+		Child child = new Child( name );
+		addChild( child );
+		return child;
+	}
+
+	public void addChild(Child child) {
+		child.setParent( this );
+		getChildren().put( child.getName(), child );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/PersistentMapTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/PersistentMapTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/map/PersistentMapTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,102 @@
+package org.hibernate.test.collection.map;
+
+import java.util.HashMap;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.collection.PersistentMap;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * todo: describe PersistentMapTest
+ *
+ * @author Steve Ebersole
+ */
+public class PersistentMapTest extends FunctionalTestCase {
+	public PersistentMapTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "collection/map/Mappings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PersistentMapTest.class );
+	}
+
+	public void testWriteMethodDirtying() {
+		Parent parent = new Parent( "p1" );
+		Child child = new Child( "c1" );
+		parent.getChildren().put( child.getName(), child );
+		child.setParent( parent );
+		Child otherChild = new Child( "c2" );
+
+		Session session = openSession();
+		session.beginTransaction();
+		session.save( parent );
+		session.flush();
+		// at this point, the set on parent has now been replaced with a PersistentSet...
+		PersistentMap children = ( PersistentMap ) parent.getChildren();
+
+		Object old = children.put( child.getName(), child );
+		assertTrue( old == child );
+		assertFalse( children.isDirty() );
+
+		old = children.remove( otherChild.getName() );
+		assertNull( old );
+		assertFalse( children.isDirty() );
+
+		HashMap otherMap = new HashMap();
+		otherMap.put( child.getName(), child );
+		children.putAll( otherMap );
+		assertFalse( children.isDirty() );
+
+		otherMap = new HashMap();
+		otherMap.put( otherChild.getName(), otherChild );
+		children.putAll( otherMap );
+		assertTrue( children.isDirty() );
+
+		children.clearDirty();
+		session.delete( child );
+		children.clear();
+		assertTrue( children.isDirty() );
+		session.flush();
+
+		children.clear();
+		assertFalse( children.isDirty() );
+
+		session.delete( parent );
+		session.getTransaction().commit();
+		session.close();
+	}
+
+	public void testPutAgainstUninitializedMap() {
+		// prepare map owner...
+		Session session = openSession();
+		session.beginTransaction();
+		Parent parent = new Parent( "p1" );
+		session.save( parent );
+		session.getTransaction().commit();
+		session.close();
+
+		// Now, reload the parent and test adding children
+		session = openSession();
+		session.beginTransaction();
+		parent = ( Parent ) session.get( Parent.class, parent.getName() );
+		parent.addChild( "c1" );
+		parent.addChild( "c2" );
+		session.getTransaction().commit();
+		session.close();
+
+		assertEquals( 2, parent.getChildren().size() );
+
+		session = openSession();
+		session.beginTransaction();
+		session.delete( parent );
+		session.getTransaction().commit();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/CollectionTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/CollectionTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/CollectionTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,228 @@
+//$Id: CollectionTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.collection.original;
+
+import java.sql.SQLException;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class CollectionTest extends FunctionalTestCase {
+
+	public CollectionTest(String str) {
+		super( str );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "collection/original/UserPermissions.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CollectionTest.class );
+	}
+
+	public void testExtraLazy() throws HibernateException, SQLException {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User u = new User( "gavin" );
+		u.getPermissions().add( new Permission( "obnoxiousness" ) );
+		u.getPermissions().add( new Permission( "pigheadedness" ) );
+		u.getSessionData().put( "foo", "foo value" );
+		s.persist( u );
+		t.commit();
+		s.close();
+		s = openSession();
+		t = s.beginTransaction();
+		u = ( User ) s.get( User.class, "gavin" );
+
+		assertFalse( Hibernate.isInitialized( u.getPermissions() ) );
+		assertEquals( u.getPermissions().size(), 2 );
+		assertTrue( u.getPermissions().contains( new Permission( "obnoxiousness" ) ) );
+		assertFalse( u.getPermissions().contains( new Permission( "silliness" ) ) );
+		assertNotNull( u.getPermissions().get( 1 ) );
+		assertNull( u.getPermissions().get( 3 ) );
+		assertFalse( Hibernate.isInitialized( u.getPermissions() ) );
+
+		assertFalse( Hibernate.isInitialized( u.getSessionData() ) );
+		assertEquals( u.getSessionData().size(), 1 );
+		assertTrue( u.getSessionData().containsKey( "foo" ) );
+		assertFalse( u.getSessionData().containsKey( "bar" ) );
+		assertTrue( u.getSessionData().containsValue( "foo value" ) );
+		assertFalse( u.getSessionData().containsValue( "bar" ) );
+		assertEquals( "foo value", u.getSessionData().get( "foo" ) );
+		assertNull( u.getSessionData().get( "bar" ) );
+		assertFalse( Hibernate.isInitialized( u.getSessionData() ) );
+
+		assertFalse( Hibernate.isInitialized( u.getSessionData() ) );
+		u.getSessionData().put( "bar", "bar value" );
+		u.getSessionAttributeNames().add( "bar" );
+		assertFalse( Hibernate.isInitialized( u.getSessionAttributeNames() ) );
+		assertTrue( Hibernate.isInitialized( u.getSessionData() ) );
+
+		s.delete( u );
+		t.commit();
+		s.close();
+	}
+
+	public void testMerge() throws HibernateException, SQLException {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User u = new User( "gavin" );
+		u.getPermissions().add( new Permission( "obnoxiousness" ) );
+		u.getPermissions().add( new Permission( "pigheadedness" ) );
+		s.persist( u );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		User u2 = ( User ) s.createCriteria( User.class ).uniqueResult();
+		u2.setPermissions( null ); //forces one shot delete
+		s.merge( u );
+		t.commit();
+		s.close();
+
+		u.getPermissions().add( new Permission( "silliness" ) );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.merge( u );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		u2 = ( User ) s.createCriteria( User.class ).uniqueResult();
+		assertEquals( u2.getPermissions().size(), 3 );
+		assertEquals( ( ( Permission ) u2.getPermissions().get( 0 ) ).getType(), "obnoxiousness" );
+		assertEquals( ( ( Permission ) u2.getPermissions().get( 2 ) ).getType(), "silliness" );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( u2 );
+		s.flush();
+		t.commit();
+		s.close();
+
+	}
+
+	public void testFetch() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User u = new User( "gavin" );
+		u.getPermissions().add( new Permission( "obnoxiousness" ) );
+		u.getPermissions().add( new Permission( "pigheadedness" ) );
+		u.getEmailAddresses().add( new Email( "gavin at hibernate.org" ) );
+		u.getEmailAddresses().add( new Email( "gavin.king at jboss.com" ) );
+		s.persist( u );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		User u2 = ( User ) s.createCriteria( User.class ).uniqueResult();
+		assertTrue( Hibernate.isInitialized( u2.getEmailAddresses() ) );
+		assertFalse( Hibernate.isInitialized( u2.getPermissions() ) );
+		assertEquals( u2.getEmailAddresses().size(), 2 );
+		s.delete( u2 );
+		t.commit();
+		s.close();
+	}
+
+	public void testUpdateOrder() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User u = new User( "gavin" );
+		u.getSessionData().put( "foo", "foo value" );
+		u.getSessionData().put( "bar", "bar value" );
+		u.getEmailAddresses().add( new Email( "gavin.king at jboss.com" ) );
+		u.getEmailAddresses().add( new Email( "gavin at hibernate.org" ) );
+		u.getEmailAddresses().add( new Email( "gavin at illflow.com" ) );
+		u.getEmailAddresses().add( new Email( "gavin at nospam.com" ) );
+		s.persist( u );
+		t.commit();
+		s.close();
+
+		u.getSessionData().clear();
+		u.getSessionData().put( "baz", "baz value" );
+		u.getSessionData().put( "bar", "bar value" );
+		u.getEmailAddresses().remove( 0 );
+		u.getEmailAddresses().remove( 2 );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update( u );
+		t.commit();
+		s.close();
+
+		u.getSessionData().clear();
+		u.getEmailAddresses().add( 0, new Email( "gavin at nospam.com" ) );
+		u.getEmailAddresses().add( new Email( "gavin.king at jboss.com" ) );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update( u );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( u );
+		t.commit();
+		s.close();
+
+	}
+
+	public void testValueMap() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User u = new User( "gavin" );
+		u.getSessionData().put( "foo", "foo value" );
+		u.getSessionData().put( "bar", null );
+		u.getEmailAddresses().add( null );
+		u.getEmailAddresses().add( new Email( "gavin.king at jboss.com" ) );
+		u.getEmailAddresses().add( null );
+		u.getEmailAddresses().add( null );
+		s.persist( u );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		User u2 = ( User ) s.createCriteria( User.class ).uniqueResult();
+		assertFalse( Hibernate.isInitialized( u2.getSessionData() ) );
+		assertEquals( u2.getSessionData().size(), 1 );
+		assertEquals( u2.getEmailAddresses().size(), 2 );
+		u2.getSessionData().put( "foo", "new foo value" );
+		u2.getEmailAddresses().set( 1, new Email( "gavin at hibernate.org" ) );
+		//u2.getEmailAddresses().remove(3);
+		//u2.getEmailAddresses().remove(2);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		u2 = ( User ) s.createCriteria( User.class ).uniqueResult();
+		assertFalse( Hibernate.isInitialized( u2.getSessionData() ) );
+		assertEquals( u2.getSessionData().size(), 1 );
+		assertEquals( u2.getEmailAddresses().size(), 2 );
+		assertEquals( u2.getSessionData().get( "foo" ), "new foo value" );
+		assertEquals( ( ( Email ) u2.getEmailAddresses().get( 1 ) ).getAddress(), "gavin at hibernate.org" );
+		s.delete( u2 );
+		t.commit();
+		s.close();
+	}
+
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/CollectionTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/Email.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/Email.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/Email.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+//$Id: Email.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.collection.original;
+
+/**
+ * @author Gavin King
+ */
+public class Email {
+	private String address;
+	Email() {}
+	public String getAddress() {
+		return address;
+	}
+	public void setAddress(String type) {
+		this.address = type;
+	}
+	public Email(String type) {
+		this.address = type;
+	}
+	public boolean equals(Object that) {
+		if ( !(that instanceof Email) ) return false;
+		Email p = (Email) that;
+		return this.address.equals(p.address);
+	}
+	public int hashCode() {
+		return address.hashCode();
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/Email.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/Permission.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/Permission.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/Permission.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+//$Id: Permission.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.collection.original;
+
+/**
+ * @author Gavin King
+ */
+public class Permission {
+	private String type;
+	Permission() {}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public Permission(String type) {
+		this.type = type;
+	}
+	public boolean equals(Object that) {
+		if ( !(that instanceof Permission) ) return false;
+		Permission p = (Permission) that;
+		return this.type.equals(p.type);
+	}
+	public int hashCode() {
+		return type.hashCode();
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/Permission.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+//$Id: User.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.collection.original;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class User {
+	private String userName;
+	private List permissions = new ArrayList();
+	private List emailAddresses = new ArrayList();
+	private Map sessionData = new HashMap();
+	private Set sessionAttributeNames = new HashSet();
+
+	User() {}
+	public User(String name) {
+		userName = name;
+	}
+	public List getPermissions() {
+		return permissions;
+	}
+	public void setPermissions(List permissions) {
+		this.permissions = permissions;
+	}
+	public String getUserName() {
+		return userName;
+	}
+	public void setUserName(String userName) {
+		this.userName = userName;
+	}
+	public List getEmailAddresses() {
+		return emailAddresses;
+	}
+	public void setEmailAddresses(List emailAddresses) {
+		this.emailAddresses = emailAddresses;
+	}
+	public Map getSessionData() {
+		return sessionData;
+	}
+	public void setSessionData(Map sessionData) {
+		this.sessionData = sessionData;
+	}
+	public Set getSessionAttributeNames() {
+		return sessionAttributeNames;
+	}
+	public void setSessionAttributeNames(Set sessionAttributeNames) {
+		this.sessionAttributeNames = sessionAttributeNames;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/User.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/UserPermissions.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/UserPermissions.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/UserPermissions.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates how to use a composite
+  element mapping to model a parent/child association.
+     
+-->
+
+<hibernate-mapping  package="org.hibernate.test.collection.original">
+	
+	<import class="Permission"/>
+
+	<class name="User" table="`Users`">
+		<id name="userName"/>
+		<list name="permissions" lazy="extra">
+			<key column="userName"/>
+			<list-index column="displayOrder" base="1"/>
+			<composite-element class="Permission">
+				<property name="type" column="permissionType"/>
+			</composite-element>
+		</list>
+		<list name="emailAddresses" fetch="join">
+			<key column="userName"/>
+			<list-index column="displayOrder" base="1"/>
+			<composite-element class="Email">
+				<property name="address"/>
+			</composite-element>
+		</list>
+		<map name="sessionData" 
+				order-by="lower(`attributeName`) asc" 
+				lazy="extra">
+			<key column="userName"/>
+			<map-key column="`attributeName`" 
+					type="string"/>
+			<element column="`attributeValue`" 
+					type="serializable" 
+					not-null="true"/>
+		</map>
+		<set name="sessionAttributeNames" 
+				lazy="extra" 
+				inverse="true">
+			<key column="userName"/>
+			<element column="`attributeName`" 
+					type="string"/>
+		</set>
+	</class>
+	
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/original/UserPermissions.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/Child.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/Child.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/Child.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+package org.hibernate.test.collection.set;
+
+/**
+ * todo: describe Child
+ *
+ * @author Steve Ebersole
+ */
+public class Child {
+	private String name;
+	private Parent parent;
+
+	public Child() {
+	}
+
+	public Child(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Parent getParent() {
+		return parent;
+	}
+
+	public void setParent(Parent parent) {
+		this.parent = parent;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+
+<hibernate-mapping package="org.hibernate.test.collection.set">
+
+    <class name="Parent">
+		<id name="name" column="NAME" type="string" />
+
+        <set name="children" inverse="true" cascade="all">
+            <key column="PARENT" />
+            <one-to-many class="Child" />
+        </set>
+	</class>
+
+    <class name="Child">
+        <id name="name" column="NAME" type="string"/>
+        <many-to-one name="parent" class="Parent" cascade="none" />
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/Parent.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/Parent.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/Parent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+package org.hibernate.test.collection.set;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * todo: describe Parent
+ *
+ * @author Steve Ebersole
+ */
+public class Parent {
+	private String name;
+	private Set children = new HashSet();
+
+	public Parent() {
+	}
+
+	public Parent(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Set getChildren() {
+		return children;
+	}
+
+	public void setChildren(Set children) {
+		this.children = children;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/PersistentSetTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/PersistentSetTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/collection/set/PersistentSetTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,80 @@
+package org.hibernate.test.collection.set;
+
+import java.util.HashSet;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.collection.PersistentSet;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * todo: describe PersistentSetTest
+ *
+ * @author Steve Ebersole
+ */
+public class PersistentSetTest extends FunctionalTestCase {
+	public PersistentSetTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "collection/set/Mappings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PersistentSetTest.class );
+	}
+
+	public void testWriteMethodDirtying() {
+		Parent parent = new Parent( "p1" );
+		Child child = new Child( "c1" );
+		parent.getChildren().add( child );
+		child.setParent( parent );
+		Child otherChild = new Child( "c2" );
+
+		Session session = openSession();
+		session.beginTransaction();
+		session.save( parent );
+		session.flush();
+		// at this point, the set on parent has now been replaced with a PersistentSet...
+		PersistentSet children = ( PersistentSet ) parent.getChildren();
+
+		assertFalse( children.add( child ) );
+		assertFalse( children.isDirty() );
+
+		assertFalse( children.remove( otherChild ) );
+		assertFalse( children.isDirty() );
+
+		HashSet otherSet = new HashSet();
+		otherSet.add( child );
+		assertFalse( children.addAll( otherSet ) );
+		assertFalse( children.isDirty() );
+
+		assertFalse( children.retainAll( otherSet ) );
+		assertFalse( children.isDirty() );
+
+		otherSet = new HashSet();
+		otherSet.add( otherChild );
+		assertFalse( children.removeAll( otherSet ) );
+		assertFalse( children.isDirty() );
+
+		assertTrue( children.retainAll( otherSet ));
+		assertTrue( children.isDirty() );
+		assertTrue( children.isEmpty() );
+
+		children.clear();
+		session.delete( child );
+		assertTrue( children.isDirty() );
+
+		session.flush();
+
+		children.clear();
+		assertFalse( children.isDirty() );
+
+		session.delete( parent );
+		session.getTransaction().commit();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/ComponentSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/ComponentSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/ComponentSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+package org.hibernate.test.component;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.component.basic.ComponentTest;
+import org.hibernate.test.component.cascading.collection.CascadeToComponentCollectionTest;
+import org.hibernate.test.component.cascading.toone.CascadeToComponentAssociationTest;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class ComponentSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "component test suite" );
+		suite.addTest( ComponentTest.suite() );
+		suite.addTest( CascadeToComponentCollectionTest.suite() );
+		suite.addTest( CascadeToComponentAssociationTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/ComponentTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/ComponentTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/ComponentTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,194 @@
+//$Id: ComponentTest.java 11349 2007-03-28 15:37:21Z steve.ebersole at jboss.com $
+package org.hibernate.test.component.basic;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.Mappings;
+import org.hibernate.criterion.Property;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.function.SQLFunction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.Formula;
+import org.hibernate.mapping.PersistentClass;
+
+/**
+ * @author Gavin King
+ */
+public class ComponentTest extends FunctionalTestCase {
+	
+	public ComponentTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "component/basic/User.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+	}
+
+	public void afterConfigurationBuilt(Mappings mappings, Dialect dialect) {
+		super.afterConfigurationBuilt( mappings, dialect );
+		// Oracle and Postgres do not have year() functions, so we need to
+		// redefine the 'User.person.yob' formula
+		//
+		// consider temporary until we add the capability to define
+		// mapping foprmulas which can use dialect-registered functions...
+		PersistentClass user = mappings.getClass( User.class.getName() );
+		org.hibernate.mapping.Property personProperty = user.getProperty( "person" );
+		Component component = ( Component ) personProperty.getValue();
+		Formula f = ( Formula ) component.getProperty( "yob" ).getValue().getColumnIterator().next();
+
+		SQLFunction yearFunction = ( SQLFunction ) dialect.getFunctions().get( "year" );
+		if ( yearFunction == null ) {
+			// the dialect not know to support a year() function, so rely on the
+			// ANSI SQL extract function
+			f.setFormula( "extract( year from dob )");
+		}
+		else {
+			List args = new ArrayList();
+			args.add( "dob" );
+			f.setFormula( yearFunction.render( args, null ) );
+		}
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite(ComponentTest.class);
+	}
+	
+	public void testUpdateFalse() {
+		getSessions().getStatistics().clear();
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User u = new User( "gavin", "secret", new Person("Gavin King", new Date(), "Karbarook Ave") );
+		s.persist(u);
+		s.flush();
+		u.getPerson().setName("XXXXYYYYY");
+		t.commit();
+		s.close();
+		
+		assertEquals( 1, getSessions().getStatistics().getEntityInsertCount() );
+		assertEquals( 0, getSessions().getStatistics().getEntityUpdateCount() );
+
+		s = openSession();
+		t = s.beginTransaction();
+		u = (User) s.get(User.class, "gavin");
+		assertEquals( u.getPerson().getName(), "Gavin King" );
+		s.delete(u);
+		t.commit();
+		s.close();
+		
+		assertEquals( 1, getSessions().getStatistics().getEntityDeleteCount() );
+	}
+	
+	public void testComponent() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User u = new User( "gavin", "secret", new Person("Gavin King", new Date(), "Karbarook Ave") );
+		s.persist(u);
+		s.flush();
+		u.getPerson().changeAddress("Phipps Place");
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		u = (User) s.get(User.class, "gavin");
+		assertEquals( u.getPerson().getAddress(), "Phipps Place" );
+		assertEquals( u.getPerson().getPreviousAddress(), "Karbarook Ave" );
+		assertEquals( u.getPerson().getYob(), u.getPerson().getDob().getYear()+1900 );
+		u.setPassword("$ecret");
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		u = (User) s.get(User.class, "gavin");
+		assertEquals( u.getPerson().getAddress(), "Phipps Place" );
+		assertEquals( u.getPerson().getPreviousAddress(), "Karbarook Ave" );
+		assertEquals( u.getPassword(), "$ecret" );
+		s.delete(u);
+		t.commit();
+		s.close();
+	}
+
+	public void testComponentStateChangeAndDirtiness() {
+		// test for HHH-2366
+		Session s = openSession();
+		s.beginTransaction();
+		User u = new User( "steve", "hibernater", new Person( "Steve Ebersole", new Date(), "Main St") );
+		s.persist( u );
+		s.flush();
+		long intialUpdateCount = sfi().getStatistics().getEntityUpdateCount();
+		u.getPerson().setAddress( "Austin" );
+		s.flush();
+		assertEquals( intialUpdateCount + 1, sfi().getStatistics().getEntityUpdateCount() );
+		intialUpdateCount = sfi().getStatistics().getEntityUpdateCount();
+		u.getPerson().setAddress( "Cedar Park" );
+		s.flush();
+		assertEquals( intialUpdateCount + 1, sfi().getStatistics().getEntityUpdateCount() );
+		s.delete( u );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testComponentQueries() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Employee emp = new Employee();
+		emp.setHireDate( new Date() );
+		emp.setPerson( new Person() );
+		emp.getPerson().setName( "steve" );
+		emp.getPerson().setDob( new Date() );
+		s.save( emp );
+
+		s.createQuery( "from Employee e where e.person = :p and 1 = 1 and 2=2" ).setParameter( "p", emp.getPerson() ).list();
+		s.createQuery( "from Employee e where :p = e.person" ).setParameter( "p", emp.getPerson() ).list();
+		s.createQuery( "from Employee e where e.person = ('steve', current_timestamp)" ).list();
+
+		s.delete( emp );
+		t.commit();
+		s.close();
+	}
+	
+	public void testComponentFormulaQuery() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createQuery("from User u where u.person.yob = 1999").list();
+		s.createCriteria(User.class)
+			.add( Property.forName("person.yob").between( new Integer(1999), new Integer(2002) ) )
+			.list();
+		if ( getDialect().supportsRowValueConstructorSyntax() ) {
+			s.createQuery("from User u where u.person = ('gavin', :dob, 'Peachtree Rd', 'Karbarook Ave', 1974, 'Peachtree Rd')")
+				.setDate("dob", new Date("March 25, 1974")).list();
+			s.createQuery("from User where person = ('gavin', :dob, 'Peachtree Rd', 'Karbarook Ave', 1974, 'Peachtree Rd')")
+				.setDate("dob", new Date("March 25, 1974")).list();
+		}
+		t.commit();
+		s.close();
+	}
+
+	public void testNamedQuery() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.getNamedQuery("userNameIn")
+			.setParameterList( "nameList", new Object[] {"1ovthafew", "turin", "xam"} )
+			.list();
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/ComponentTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/Employee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/Employee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/Employee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+package org.hibernate.test.component.basic;
+
+import java.util.Date;
+
+/**
+ * todo: describe Employee
+ *
+ * @author Steve Ebersole
+ */
+public class Employee {
+	private Long id;
+	private Person person;
+	private Date hireDate;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Person getPerson() {
+		return person;
+	}
+
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+
+	public Date getHireDate() {
+		return hireDate;
+	}
+
+	public void setHireDate(Date hireDate) {
+		this.hireDate = hireDate;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+//$Id: Person.java 11345 2007-03-26 17:24:20Z steve.ebersole at jboss.com $
+package org.hibernate.test.component.basic;
+
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class Person {
+	private String name;
+	private Date dob;
+	private String address;
+	private String currentAddress;
+	private String previousAddress;
+	private int yob;
+	Person() {}
+	public Person(String name, Date dob, String address) {
+		this.name = name;
+		this.dob = dob;
+		this.address = address;
+		this.currentAddress = address;
+	}
+	public int getYob() {
+		return yob;
+	}
+	public void setYob(int age) {
+		this.yob = age;
+	}
+	public String getAddress() {
+		return address;
+	}
+	public void setAddress(String address) {
+		this.address = address;
+	}
+	public Date getDob() {
+		return dob;
+	}
+	public void setDob(Date dob) {
+		this.dob = dob;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getPreviousAddress() {
+		return previousAddress;
+	}
+	public void setPreviousAddress(String previousAddress) {
+		this.previousAddress = previousAddress;
+	}
+	public void changeAddress(String add) {
+		setPreviousAddress( getAddress() );
+		setAddress(add);
+	}
+	public String getCurrentAddress() {
+		return currentAddress;
+	}
+	public void setCurrentAddress(String currentAddress) {
+		this.currentAddress = currentAddress;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/User.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/User.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/User.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.component.basic">
+	
+	<class name="User" table="T_USER">
+		<id name="userName"/>
+		<timestamp name="lastModified"/>
+		<property name="password" not-null="true" optimistic-lock="false"/>
+		<component name="person">
+			<property name="name" update="false" not-null="true"/>
+			<property name="dob" update="false" not-null="true"/>
+			<property name="address"/>
+			<property name="previousAddress" insert="false"/>
+			<property name="yob" formula="year(dob)"/>
+			<property name="currentAddress" 
+				column="address" 
+				insert="false" 
+				update="false"/>
+		</component>
+	</class>
+
+	<class name="Employee" table="T_EMP">
+        <id name="id" type="long" column="ID">
+            <generator class="increment"/>
+        </id>
+        <property name="hireDate" type="date" column="HIRE_DATE"/>
+        <component name="person">
+			<property name="name" update="false" not-null="true"/>
+			<property name="dob" update="false" not-null="true"/>
+		</component>
+	</class>
+	
+	<query name="userNameIn"><![CDATA[from User where person.name in (:nameList) or userName in (:nameList)]]></query>
+	
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/User.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+//$Id: User.java 11345 2007-03-26 17:24:20Z steve.ebersole at jboss.com $
+package org.hibernate.test.component.basic;
+
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class User {
+	private String userName;
+	private String password;
+	private Person person;
+	private Date lastModified;
+	User() {}
+	public User(String id, String pw, Person person) {
+		this.userName = id;
+		this.password = pw;
+		this.person = person;
+	}
+	public Date getLastModified() {
+		return lastModified;
+	}
+	public void setLastModified(Date lastModified) {
+		this.lastModified = lastModified;
+	}
+	public String getPassword() {
+		return password;
+	}
+	public void setPassword(String password) {
+		this.password = password;
+	}
+	public Person getPerson() {
+		return person;
+	}
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+	public String getUserName() {
+		return userName;
+	}
+	public void setUserName(String userName) {
+		this.userName = userName;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/basic/User.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/CascadeToComponentCollectionTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/CascadeToComponentCollectionTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/CascadeToComponentCollectionTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,116 @@
+package org.hibernate.test.component.cascading.collection;
+
+import java.util.Iterator;
+import java.util.Locale;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class CascadeToComponentCollectionTest extends FunctionalTestCase {
+
+	public CascadeToComponentCollectionTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "component/cascading/collection/Mappings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CascadeToComponentCollectionTest.class );
+	}
+
+	public void testMerging() {
+		// step1, we create a definition with one value
+		Session session = openSession();
+		session.beginTransaction();
+		Definition definition = new Definition();
+		Value value1 = new Value( definition );
+		value1.getLocalizedStrings().addString( new Locale( "en_US" ), "hello" );
+		session.persist( definition );
+		session.getTransaction().commit();
+		session.close();
+
+		// step2, we verify that the definition has one value; then we detach it
+		session = openSession();
+		session.beginTransaction();
+		definition = ( Definition ) session.get( Definition.class, definition.getId() );
+		assertEquals( 1, definition.getValues().size() );
+		session.getTransaction().commit();
+		session.close();
+
+		// step3, we add a new value during detachment
+		Value value2 = new Value( definition );
+		value2.getLocalizedStrings().addString( new Locale( "es" ), "hola" );
+
+		// step4 we merge the definition
+		session = openSession();
+		session.beginTransaction();
+		session.merge( definition );
+		session.getTransaction().commit();
+		session.close();
+
+		// step5, final test
+		session = openSession();
+		session.beginTransaction();
+		definition = ( Definition ) session.get( Definition.class, definition.getId() );
+		assertEquals( 2, definition.getValues().size() );
+		Iterator values = definition.getValues().iterator();
+		while ( values.hasNext() ) {
+			assertEquals( 1, ( ( Value ) values.next() ).getLocalizedStrings().getStringsCopy().size() );
+		}
+		session.getTransaction().commit();
+		session.close();
+	}
+
+	public void testMergingOriginallyNullComponent() {
+		// step1, we create a definition with one value, but with a null component
+		Session session = openSession();
+		session.beginTransaction();
+		Definition definition = new Definition();
+		Value value1 = new Value( definition );
+		session.persist( definition );
+		session.getTransaction().commit();
+		session.close();
+
+		// step2, we verify that the definition has one value; then we detach it
+		session = openSession();
+		session.beginTransaction();
+		definition = ( Definition ) session.get( Definition.class, definition.getId() );
+		assertEquals( 1, definition.getValues().size() );
+		session.getTransaction().commit();
+		session.close();
+
+		// step3, we add a new value during detachment
+		( ( Value ) definition.getValues().iterator().next() ).getLocalizedStrings().addString( new Locale( "en_US" ), "hello" );
+		Value value2 = new Value( definition );
+		value2.getLocalizedStrings().addString( new Locale( "es" ), "hola" );
+
+		// step4 we merge the definition
+		session = openSession();
+		session.beginTransaction();
+		session.merge( definition );
+		session.getTransaction().commit();
+		session.close();
+
+		// step5, final test
+		session = openSession();
+		session.beginTransaction();
+		definition = ( Definition ) session.get( Definition.class, definition.getId() );
+		assertEquals( 2, definition.getValues().size() );
+		Iterator values = definition.getValues().iterator();
+		while ( values.hasNext() ) {
+			assertEquals( 1, ( ( Value ) values.next() ).getLocalizedStrings().getStringsCopy().size() );
+		}
+		session.getTransaction().commit();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/Definition.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/Definition.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/Definition.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+package org.hibernate.test.component.cascading.collection;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Definition {
+    private Long id;
+	private Set values = new HashSet();
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Set getValues() {
+		return values;
+	}
+
+	public void setValues(Set values) {
+		this.values = values;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/LocalizedStrings.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/LocalizedStrings.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/LocalizedStrings.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+package org.hibernate.test.component.cascading.collection;
+
+import java.util.Locale;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class LocalizedStrings {
+	private Map strings = new HashMap();
+
+	public void addString(Locale locale, String value) {
+		strings.put( locale, value );
+	}
+
+	public String getString(Locale locale) {
+		return ( String ) strings.get( locale );
+	}
+
+	public Map getStringsCopy() {
+		return java.util.Collections.unmodifiableMap( strings );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.component.cascading.collection">
+
+	<class name="Definition" >
+		<id name="id" type="long" column="ID">
+			<generator class="increment"/>
+		</id>
+		<set name="values" cascade="all-delete-orphan,merge" lazy="false" inverse="true">
+			<key column="DEF_ID" />
+			<one-to-many class="Value"/>
+		</set>
+	</class>
+
+    <class name="Value" >
+		<id name="id" type="long" column="ID">
+			<generator class="increment"/>
+		</id>
+
+		<many-to-one name="definition" class="Definition" column="DEF_ID"/>
+
+        <component name="localizedStrings" class="LocalizedStrings">
+            <map name="strings" access="field" cascade="persist,merge" lazy="false">
+                <key column="VAL_ID" />
+                <map-key type="locale" column="LOC" />
+                <element type="string" column="STR_VAL" />
+            </map>
+		</component>
+
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/Value.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/Value.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/collection/Value.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+package org.hibernate.test.component.cascading.collection;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Value {
+	private Long id;
+	private Definition definition;
+	private LocalizedStrings localizedStrings = new LocalizedStrings();
+
+	private Value() {
+	}
+
+	public Value(Definition definition) {
+		this();
+		this.definition = definition;
+		definition.getValues().add( this );
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Definition getDefinition() {
+		return definition;
+	}
+
+	public void setDefinition(Definition definition) {
+		this.definition = definition;
+	}
+
+	public LocalizedStrings getLocalizedStrings() {
+		return localizedStrings;
+	}
+
+	public void setLocalizedStrings(LocalizedStrings localizedStrings) {
+		this.localizedStrings = localizedStrings;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+package org.hibernate.test.component.cascading.toone;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Address {
+	private Long id;
+	private String street1;
+	private String street2;
+	private String city;
+	private String state;
+	private String zipCode;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getStreet1() {
+		return street1;
+	}
+
+	public void setStreet1(String street1) {
+		this.street1 = street1;
+	}
+
+	public String getStreet2() {
+		return street2;
+	}
+
+	public void setStreet2(String street2) {
+		this.street2 = street2;
+	}
+
+	public String getCity() {
+		return city;
+	}
+
+	public void setCity(String city) {
+		this.city = city;
+	}
+
+	public String getState() {
+		return state;
+	}
+
+	public void setState(String state) {
+		this.state = state;
+	}
+
+	public String getZipCode() {
+		return zipCode;
+	}
+
+	public void setZipCode(String zipCode) {
+		this.zipCode = zipCode;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/CascadeToComponentAssociationTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/CascadeToComponentAssociationTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/CascadeToComponentAssociationTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,71 @@
+package org.hibernate.test.component.cascading.toone;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.Session;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class CascadeToComponentAssociationTest extends FunctionalTestCase {
+	public CascadeToComponentAssociationTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "component/cascading/toone/Mappings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CascadeToComponentAssociationTest.class );
+	}
+
+	public void testMerging() {
+		// step1, we create a document with owner
+		Session session = openSession();
+		session.beginTransaction();
+		User user = new User();
+		Document document = new Document();
+		document.setOwner( user );
+		session.persist( document );
+		session.getTransaction().commit();
+		session.close();
+
+		// step2, we verify that the document has owner and that owner has no personal-info; then we detach
+		session = openSession();
+		session.beginTransaction();
+		document = ( Document ) session.get( Document.class, document.getId() );
+		assertNotNull( document.getOwner() );
+		assertNull( document.getOwner().getPersonalInfo() );
+		session.getTransaction().commit();
+		session.close();
+
+		// step3, try to specify the personal-info during detachment
+		Address addr = new Address();
+		addr.setStreet1( "123 6th St" );
+		addr.setCity( "Austin" );
+		addr.setState( "TX" );
+		document.getOwner().setPersonalInfo( new PersonalInfo( addr ) );
+
+		// step4 we merge the document
+		session = openSession();
+		session.beginTransaction();
+		session.merge( document );
+		session.getTransaction().commit();
+		session.close();
+
+		// step5, final test
+		session = openSession();
+		session.beginTransaction();
+		document = ( Document ) session.get( Document.class, document.getId() );
+		assertNotNull( document.getOwner() );
+		assertNotNull( document.getOwner().getPersonalInfo() );
+		assertNotNull( document.getOwner().getPersonalInfo().getHomeAddress() );
+		session.getTransaction().commit();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/Document.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/Document.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/Document.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+package org.hibernate.test.component.cascading.toone;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Document {
+	private Long id;
+	private String location;
+	private User owner;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getLocation() {
+		return location;
+	}
+
+	public void setLocation(String location) {
+		this.location = location;
+	}
+
+	public User getOwner() {
+		return owner;
+	}
+
+	public void setOwner(User owner) {
+		this.owner = owner;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.component.cascading.toone">
+
+	<class name="Document" table="COMP_CASC_TO1_DOC">
+		<id name="id" type="long" column="ID">
+			<generator class="increment"/>
+		</id>
+        <many-to-one name="owner" class="User" cascade="persist,merge,delete"/>
+	</class>
+
+    <class name="User" table="COMP_CASC_TO1_USER">
+		<id name="id" type="long" column="ID">
+			<generator class="increment"/>
+		</id>
+        <component name="personalInfo" class="PersonalInfo">
+            <many-to-one name="homeAddress" class="Address" cascade="persist,merge,delete"/>
+		</component>
+	</class>
+
+    <class name="Address" table="COMP_CASC_TO1_ADDR">
+        <id name="id" type="long" column="ID">
+			<generator class="increment"/>
+        </id>
+        <property name="street1" type="string" column="STREET1" />
+        <property name="street2" type="string" column="STREET2" />
+        <property name="city" type="string" column="CITY" />
+        <property name="state" type="string" column="STATE" />
+        <property name="zipCode" type="string" column="ZIP_CODE" />
+    </class>
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/PersonalInfo.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/PersonalInfo.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/PersonalInfo.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+package org.hibernate.test.component.cascading.toone;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class PersonalInfo {
+	private Address homeAddress = new Address();
+
+	public PersonalInfo() {
+	}
+
+	public PersonalInfo(Address homeAddress) {
+		this.homeAddress = homeAddress;
+	}
+
+	public Address getHomeAddress() {
+		return homeAddress;
+	}
+
+	public void setHomeAddress(Address homeAddress) {
+		this.homeAddress = homeAddress;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/component/cascading/toone/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+package org.hibernate.test.component.cascading.toone;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class User {
+	private Long id;
+	private PersonalInfo personalInfo;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public PersonalInfo getPersonalInfo() {
+		return personalInfo;
+	}
+
+	public void setPersonalInfo(PersonalInfo personalInfo) {
+		this.personalInfo = personalInfo;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Child.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Child.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Child.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+//$Id: Child.java 6978 2005-06-01 03:29:27Z oneovthafew $
+package org.hibernate.test.compositeelement;
+
+/**
+ * @author gavin
+ */
+public class Child {
+	private String name;
+	private String bio;
+	private Parent parent;
+	private int bioLength;
+	Child() {}
+	public Child(String name) {
+		this.name = name;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	/**
+	 * @return Returns the parent.
+	 */
+	public Parent getParent() {
+		return parent;
+	}
+	/**
+	 * @param parent The parent to set.
+	 */
+	public void setParent(Parent parent) {
+		this.parent = parent;
+	}
+	public String getBio() {
+		return bio;
+	}
+	public void setBio(String bio) {
+		this.bio = bio;
+	}
+	public int hashCode() {
+		return name.hashCode();
+	}
+	public boolean equals(Object other) {
+		Child c = (Child) other;
+		return c.parent.getId().equals(parent.getId()) 
+			&& c.name.equals(name);
+	}
+	public int getBioLength() {
+		return bioLength;
+	}
+	public void setBioLength(Integer bioLength) {
+		this.bioLength = bioLength==null ? 0 : bioLength.intValue();
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Child.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/CompositeElementTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/CompositeElementTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/CompositeElementTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,90 @@
+//$Id: CompositeElementTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.compositeelement;
+
+import java.util.ArrayList;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Mappings;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.function.SQLFunction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.Formula;
+
+/**
+ * @author Gavin King
+ */
+public class CompositeElementTest extends FunctionalTestCase {
+
+	public CompositeElementTest(String str) {
+		super( str );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "compositeelement/Parent.hbm.xml" };
+	}
+
+	public void afterConfigurationBuilt(Mappings mappings, Dialect dialect) {
+		super.afterConfigurationBuilt( mappings, dialect );
+		Collection children = mappings.getCollection( Parent.class.getName() + ".children" );
+		Component childComponents = ( Component ) children.getElement();
+		Formula f = ( Formula ) childComponents.getProperty( "bioLength" ).getValue().getColumnIterator().next();
+
+		SQLFunction lengthFunction = ( SQLFunction ) dialect.getFunctions().get( "length" );
+		if ( lengthFunction != null ) {
+			ArrayList args = new ArrayList();
+			args.add( "bio" );
+			f.setFormula( lengthFunction.render( args, null ) );
+		}
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CompositeElementTest.class );
+	}
+
+	public void testHandSQL() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Child c = new Child( "Child One" );
+		Parent p = new Parent( "Parent" );
+		p.getChildren().add( c );
+		c.setParent( p );
+		s.save( p );
+		s.flush();
+
+		p.getChildren().remove( c );
+		c.setParent( null );
+		s.flush();
+
+		p.getChildren().add( c );
+		c.setParent( p );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery( "select distinct p from Parent p join p.children c where c.name like 'Child%'" ).uniqueResult();
+		s.clear();
+		s.createQuery( "select new Child(c.name) from Parent p left outer join p.children c where c.name like 'Child%'" )
+				.uniqueResult();
+		s.clear();
+		//s.createQuery("select c from Parent p left outer join p.children c where c.name like 'Child%'").uniqueResult(); //we really need to be able to do this!
+		s.clear();
+		p = ( Parent ) s.createQuery( "from Parent p left join fetch p.children" ).uniqueResult();
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( p );
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/CompositeElementTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Parent.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Parent.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Parent.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates how to use a composite
+  element mapping to model a parent/child association.
+     
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.compositeelement">
+	
+	<import class="Child"/>
+
+	<class name="Parent">
+		<id name="id" 
+			column="parent_id">
+			<generator class="increment"/>
+		</id>
+		<property name="name"/>
+		<set name="children" table="ParentChild">
+			<key column="parent_id"/>
+			<composite-element class="Child">
+				<parent name="parent"/>
+				<property name="name" not-null="true"/>
+				<property name="bio"/>
+				<property name="bioLength" formula="length(bio)"/>
+			</composite-element>
+		</set>
+	</class>
+	
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Parent.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Parent.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Parent.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Parent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+//$Id: Parent.java 4478 2004-09-02 02:30:28Z oneovthafew $
+package org.hibernate.test.compositeelement;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * @author gavin
+ */
+public class Parent {
+	private Long id;
+	private String name;
+	private Collection children = new HashSet();
+	Parent() {}
+	public Parent(String name) {
+		this.name = name;
+	}
+	/**
+	 * @return Returns the children.
+	 */
+	public Collection getChildren() {
+		return children;
+	}
+	/**
+	 * @param children The children to set.
+	 */
+	public void setChildren(Collection children) {
+		this.children = children;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/compositeelement/Parent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/AggressiveReleaseTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/AggressiveReleaseTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/AggressiveReleaseTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,249 @@
+// $Id: AggressiveReleaseTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.connections;
+
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.Hibernate;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.impl.SessionImpl;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.tm.DummyConnectionProvider;
+import org.hibernate.test.tm.DummyTransactionManager;
+import org.hibernate.test.tm.DummyTransactionManagerLookup;
+import org.hibernate.transaction.CMTTransactionFactory;
+import org.hibernate.util.SerializationHelper;
+
+/**
+ * Implementation of AggressiveReleaseTest.
+ *
+ * @author Steve Ebersole
+ */
+public class AggressiveReleaseTest extends ConnectionManagementTestCase {
+
+	public AggressiveReleaseTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( AggressiveReleaseTest.class );
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.AFTER_STATEMENT.toString() );
+		cfg.setProperty( Environment.CONNECTION_PROVIDER, DummyConnectionProvider.class.getName() );
+		cfg.setProperty( Environment.TRANSACTION_STRATEGY, CMTTransactionFactory.class.getName() );
+		cfg.setProperty( Environment.TRANSACTION_MANAGER_STRATEGY, DummyTransactionManagerLookup.class.getName() );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+		cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "0" );
+	}
+
+	protected Session getSessionUnderTest() throws Throwable {
+		return openSession();
+	}
+
+	protected void reconnect(Session session) {
+		session.reconnect();
+	}
+
+	protected void prepare() throws Throwable {
+		DummyTransactionManager.INSTANCE.begin();
+	}
+
+	protected void done() throws Throwable {
+		DummyTransactionManager.INSTANCE.commit();
+	}
+
+	// Some additional tests specifically for the aggressive-release functionality...
+
+	public void testSerializationOnAfterStatementAggressiveRelease() throws Throwable {
+		prepare();
+		Session s = getSessionUnderTest();
+		Silly silly = new Silly( "silly" );
+		s.save( silly );
+
+		// this should cause the CM to obtain a connection, and then release it
+		s.flush();
+
+		// We should be able to serialize the session at this point...
+		SerializationHelper.serialize( s );
+
+		s.delete( silly );
+		s.flush();
+
+		release( s );
+		done();
+	}
+
+	public void testSerializationFailsOnAfterStatementAggressiveReleaseWithOpenResources() throws Throwable {
+		prepare();
+		Session s = getSessionUnderTest();
+
+		Silly silly = new Silly( "silly" );
+		s.save( silly );
+
+		// this should cause the CM to obtain a connection, and then release it
+		s.flush();
+
+		// both scroll() and iterate() cause the batcher to hold on
+		// to resources, which should make aggresive-release not release
+		// the connection (and thus cause serialization to fail)
+		ScrollableResults sr = s.createQuery( "from Silly" ).scroll();
+
+		try {
+			SerializationHelper.serialize( s );
+			fail( "Serialization allowed on connected session; or aggressive release released connection with open resources" );
+		}
+		catch( IllegalStateException e ) {
+			// expected behavior
+		}
+
+		// Closing the ScrollableResults does currently force the batcher to
+		// aggressively release the connection
+		sr.close();
+		SerializationHelper.serialize( s );
+
+		s.delete( silly );
+		s.flush();
+
+		release( s );
+		done();
+	}
+
+	public void testQueryIteration() throws Throwable {
+		prepare();
+		Session s = getSessionUnderTest();
+		Silly silly = new Silly( "silly" );
+		s.save( silly );
+		s.flush();
+
+		Iterator itr = s.createQuery( "from Silly" ).iterate();
+		assertTrue( itr.hasNext() );
+		Silly silly2 = ( Silly ) itr.next();
+		assertEquals( silly, silly2 );
+		Hibernate.close( itr );
+
+		itr = s.createQuery( "from Silly" ).iterate();
+		Iterator itr2 = s.createQuery( "from Silly where name = 'silly'" ).iterate();
+
+		assertTrue( itr.hasNext() );
+		assertEquals( silly, itr.next() );
+		assertTrue( itr2.hasNext() );
+		assertEquals( silly, itr2.next() );
+
+		Hibernate.close( itr );
+		Hibernate.close( itr2 );
+
+		s.delete( silly );
+		s.flush();
+
+		release( s );
+		done();
+	}
+
+	public void testQueryScrolling() throws Throwable {
+		prepare();
+		Session s = getSessionUnderTest();
+		Silly silly = new Silly( "silly" );
+		s.save( silly );
+		s.flush();
+
+		ScrollableResults sr = s.createQuery( "from Silly" ).scroll();
+		assertTrue( sr.next() );
+		Silly silly2 = ( Silly ) sr.get( 0 );
+		assertEquals( silly, silly2 );
+		sr.close();
+
+		sr = s.createQuery( "from Silly" ).scroll();
+		ScrollableResults sr2 = s.createQuery( "from Silly where name = 'silly'" ).scroll();
+
+		assertTrue( sr.next() );
+		assertEquals( silly, sr.get( 0 ) );
+		assertTrue( sr2.next() );
+		assertEquals( silly, sr2.get( 0 ) );
+
+		sr.close();
+		sr2.close();
+
+		s.delete( silly );
+		s.flush();
+
+		release( s );
+		done();
+	}
+
+	public void testSuppliedConnection() throws Throwable {
+		prepare();
+
+		Connection originalConnection = DummyTransactionManager.INSTANCE.getCurrent().getConnection();
+		Session session = getSessions().openSession( originalConnection );
+
+		Silly silly = new Silly( "silly" );
+		session.save( silly );
+
+		// this will cause the connection manager to cycle through the aggressive release logic;
+		// it should not release the connection since we explicitly suplied it ourselves.
+		session.flush();
+
+		assertTrue( "Different connections", originalConnection == session.connection() );
+
+		session.delete( silly );
+		session.flush();
+
+		release( session );
+		done();
+	}
+
+	public void testBorrowedConnections() throws Throwable {
+		prepare();
+		Session s = getSessionUnderTest();
+
+		Connection conn = s.connection();
+		assertTrue( ( ( SessionImpl ) s ).getJDBCContext().getConnectionManager().hasBorrowedConnection() );
+		conn.close();
+		assertFalse( ( ( SessionImpl ) s ).getJDBCContext().getConnectionManager().hasBorrowedConnection() );
+
+		release( s );
+		done();
+	}
+
+	public void testConnectionMaintanenceDuringFlush() throws Throwable {
+		prepare();
+		Session s = getSessionUnderTest();
+		s.beginTransaction();
+
+		List entities = new ArrayList();
+		for ( int i = 0; i < 10; i++ ) {
+			Other other = new Other( "other-" + i );
+			Silly silly = new Silly( "silly-" + i, other );
+			entities.add( silly );
+			s.save( silly );
+		}
+		s.flush();
+
+		Iterator itr = entities.iterator();
+		while ( itr.hasNext() ) {
+			Silly silly = ( Silly ) itr.next();
+			silly.setName( "new-" + silly.getName() );
+			silly.getOther().setName( "new-" + silly.getOther().getName() );
+		}
+		long initialCount = getSessions().getStatistics().getConnectCount();
+		s.flush();
+		assertEquals( "connection not maintained through flush", initialCount + 1, getSessions().getStatistics().getConnectCount() );
+
+		s.createQuery( "delete from Silly" ).executeUpdate();
+		s.createQuery( "delete from Other" ).executeUpdate();
+		s.getTransaction().commit();
+		release( s );
+		done();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/BasicConnectionProviderTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/BasicConnectionProviderTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/BasicConnectionProviderTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+// $Id: BasicConnectionProviderTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.connections;
+
+import junit.framework.Test;
+
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Implementation of BasicConnectionProviderTest.
+ *
+ * @author Steve Ebersole
+ */
+public class BasicConnectionProviderTest extends ConnectionManagementTestCase {
+
+	public BasicConnectionProviderTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( BasicConnectionProviderTest.class );
+	}
+
+	protected Session getSessionUnderTest() {
+		return openSession();
+	}
+
+	protected void reconnect(Session session) {
+		session.reconnect();
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.ON_CLOSE.toString() );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/ConnectionManagementTestCase.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/ConnectionManagementTestCase.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/ConnectionManagementTestCase.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,307 @@
+// $Id: ConnectionManagementTestCase.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.connections;
+
+import org.hibernate.test.TestCase;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.util.SerializationHelper;
+
+/**
+ * Common test cases relating to session management and how the sessions
+ * manages its underlying jdbc connection across different config
+ * scenarios.  The different config scenarios are controlled by the
+ * individual test subclasses.
+ * <p/>
+ * In general, all the tests required are defined here in templated fashion.
+ * Subclassed then override various hook methods specific to their given
+ * scneario being tested.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class ConnectionManagementTestCase extends FunctionalTestCase {
+
+	public ConnectionManagementTestCase(String name) {
+		super( name );
+	}
+
+	public final String[] getMappings() {
+		return new String[] { "connections/Silly.hbm.xml" };
+	}
+
+
+	// hooks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Used to prepare the environment for testing (e.g., starting a
+	 * JTA transaction or obtaining a user-supplied connection).
+	 *
+	 * @throws Throwable indicates problems preparing
+	 */
+	protected void prepare() throws Throwable {
+	}
+
+	/**
+	 * Used to cleanup the environment after testing (e.g., ending a JTA
+	 * transaction or closing a user-supplied connection).
+	 *
+	 * @throws Throwable indicates problems cleaning up
+	 */
+	protected void done() throws Throwable {
+	}
+
+	/**
+	 * Used to get a session configured based on the config scenario being
+	 * tested.
+	 *
+	 * @return The session to be used in testing.
+	 * @throws Throwable Indicates problems building a test session fixture.
+	 */
+	protected abstract Session getSessionUnderTest() throws Throwable;
+
+	/**
+	 * Used to release a {@link #getSessionUnderTest fixture session}.
+	 * Overridden to perform session releasing/testing specific to the given
+	 * config scenario being tested.
+	 *
+	 * @param session The session to be released.
+	 */
+	protected void release(Session session) {
+		if ( session != null && session.isOpen() ) {
+			try {
+				session.close();
+			}
+			catch( Throwable ignore ) {
+			}
+		}
+	}
+
+	/**
+	 * Perform any steps needed to reconnect a fixture session.
+	 *
+	 * @param session The fixture session to be reconnected.
+	 * @throws Throwable Indicates problems reconnecting.
+	 */
+	protected abstract void reconnect(Session session) throws Throwable;
+
+	/**
+	 * Check the state of a fixture session after serialization, as well
+	 * as validate the environmental state after session serialization.
+	 *
+	 * @param session The fixture session that was serialized.
+	 */
+	protected void checkSerializedState(Session session) {
+	}
+
+	/**
+	 * Check the state of a fixture session after deserialization, as well
+	 * as validate the environmental state after session deserialization.
+	 *
+	 * @param session The fixture session that was deserialized.
+	 */
+	protected void checkDeserializedState(Session session) {
+	}
+
+
+	// tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Tests to validate that a session holding JDBC resources will not
+	 * be allowed to serialize.
+	 *
+	 * @throws Throwable
+	 */
+	public final void testConnectedSerialization() throws Throwable {
+		prepare();
+		Session sessionUnderTest = getSessionUnderTest();
+
+		// force the connection to be retained
+		sessionUnderTest.createQuery( "from Silly" ).scroll();
+
+		try {
+			SerializationHelper.serialize( sessionUnderTest );
+
+			fail( "Serialization of connected session allowed!" );
+		}
+		catch( IllegalStateException e ) {
+			// expected behaviour
+		}
+		finally {
+			release( sessionUnderTest );
+			done();
+		}
+	}
+
+	/**
+	 * Test that a session which has been manually disconnected will be allowed
+	 * to serialize.
+	 *
+	 * @throws Throwable
+	 */
+	public final void testManualDisconnectedSerialization() throws Throwable {
+		prepare();
+		Session sessionUnderTest = getSessionUnderTest();
+
+		sessionUnderTest.disconnect();
+
+		SerializationHelper.serialize( sessionUnderTest );
+		checkSerializedState( sessionUnderTest );
+
+		release( sessionUnderTest );
+		done();
+	}
+
+	/**
+	 * Test that the legacy manual disconnect()/reconnect() chain works as
+	 * expected in the given environment.
+	 *
+	 * @throws Throwable
+	 */
+	public final void testManualDisconnectChain() throws Throwable {
+		prepare();
+		Session sessionUnderTest = getSessionUnderTest();
+
+		sessionUnderTest.disconnect();
+
+		byte[] bytes = SerializationHelper.serialize( sessionUnderTest );
+		checkSerializedState( sessionUnderTest );
+		Session s2 = ( Session ) SerializationHelper.deserialize( bytes );
+		checkDeserializedState( s2 );
+
+		reconnect( s2 );
+
+		s2.disconnect();
+		reconnect( s2 );
+
+		release( sessionUnderTest );
+		release( s2 );
+		done();
+	}
+
+	/**
+	 * Test that the legacy manual disconnect()/reconnect() chain works as
+	 * expected in the given environment.  Similiar to {@link #testManualDisconnectChain}
+	 * expect that here we force the session to acquire and hold JDBC resources
+	 * prior to disconnecting.
+	 *
+	 * @throws Throwable
+	 */
+	public final void testManualDisconnectWithOpenResources() throws Throwable {
+		prepare();
+		Session sessionUnderTest = getSessionUnderTest();
+
+		Silly silly = new Silly( "tester" );
+		sessionUnderTest.save( silly );
+		sessionUnderTest.flush();
+
+		sessionUnderTest.createQuery( "from Silly" ).iterate();
+
+		sessionUnderTest.disconnect();
+		SerializationHelper.serialize( sessionUnderTest );
+		checkSerializedState( sessionUnderTest );
+
+		reconnect( sessionUnderTest );
+		sessionUnderTest.createQuery( "from Silly" ).scroll();
+
+		sessionUnderTest.disconnect();
+		SerializationHelper.serialize( sessionUnderTest );
+		checkSerializedState( sessionUnderTest );
+
+		reconnect( sessionUnderTest );
+		sessionUnderTest.delete( silly );
+		sessionUnderTest.flush();
+
+		release( sessionUnderTest );
+		done();
+	}
+
+	/**
+	 * Test that the basic session usage template works in all environment
+	 * scenarios.
+	 *
+	 * @throws Throwable
+	 */
+	public void testBasicSessionUsage() throws Throwable {
+		prepare();
+		Session s = null;
+		Transaction txn = null;
+		try {
+			s = getSessionUnderTest();
+			txn = s.beginTransaction();
+			s.createQuery( "from Silly" ).list();
+			txn.commit();
+		}
+		catch( Throwable t ) {
+			if ( txn != null ) {
+				try {
+					txn.rollback();
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+		}
+		finally {
+			if ( s != null && s.isOpen() ) {
+				try {
+					s.close();
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+		}
+		done();
+	}
+
+	/**
+	 * Test that session-closed protections work properly in all environments.
+	 *
+	 * @throws Throwable
+	 */
+	public void testSessionClosedProtections() throws Throwable {
+		prepare();
+		Session s = getSessionUnderTest();
+		release( s );
+		done();
+		assertFalse( s.isOpen() );
+		assertFalse( s.isConnected() );
+		assertNotNull( s.getStatistics() );
+		assertNotNull( s.toString() );
+
+		try {
+			s.createQuery( "from Silly" ).list();
+			fail( "allowed to create query on closed session" );
+		}
+		catch( Throwable ignore ) {
+		}
+
+		try {
+			s.getTransaction();
+			fail( "allowed to access transaction on closed session" );
+		}
+		catch( Throwable ignore ) {
+		}
+
+		try {
+			s.connection();
+			fail( "allowed to access connection on closed session" );
+		}
+		catch( Throwable ignore ) {
+		}
+
+		try {
+			s.close();
+			fail( "allowed to close already closed session" );
+		}
+		catch( Throwable ignore ) {
+		}
+
+		try {
+			s.isDirty();
+			fail( "allowed to check dirtiness of closed session" );
+		}
+		catch( Throwable ignore ) {
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/ConnectionsSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/ConnectionsSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/ConnectionsSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+// $Id: ConnectionsSuite.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.connections;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Implementation of ConnectionsSuite.
+ *
+ * @author Steve Ebersole
+ */
+public class ConnectionsSuite {
+
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "Connection-management tests");
+		suite.addTest( AggressiveReleaseTest.suite() );
+		suite.addTest( BasicConnectionProviderTest.suite() );
+		suite.addTest( CurrentSessionConnectionTest.suite() );
+		suite.addTest( SuppliedConnectionTest.suite() );
+		suite.addTest( ThreadLocalCurrentSessionTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/CurrentSessionConnectionTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/CurrentSessionConnectionTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/CurrentSessionConnectionTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+// $Id: CurrentSessionConnectionTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.connections;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Implementation of CurrentSessionConnectionTest.
+ *
+ * @author Steve Ebersole
+ */
+public class CurrentSessionConnectionTest extends AggressiveReleaseTest {
+
+	public CurrentSessionConnectionTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CurrentSessionConnectionTest.class );
+	}
+
+	protected Session getSessionUnderTest() throws Throwable {
+		return getSessions().getCurrentSession();
+	}
+
+	protected void release(Session session) {
+		// do nothing, txn synch should release session as part of current-session definition
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/Other.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/Other.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/Other.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+package org.hibernate.test.connections;
+
+/**
+ * @author Steve Ebersole
+ */
+public class Other {
+	private Long id;
+	private String name;
+
+	public Other() {
+	}
+
+	public Other(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/Silly.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/Silly.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/Silly.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.connections">
+
+	<class name="Silly">
+		<id name="id" type="long">
+			<generator class="native"/>
+		</id>
+		<property name="name"/>
+        <many-to-one name="other" class="Other" cascade="all"/>
+    </class>
+
+	<class name="Other">
+		<id name="id" type="long">
+			<generator class="native"/>
+		</id>
+		<property name="name"/>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/Silly.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/Silly.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/Silly.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+// $Id: Silly.java 9595 2006-03-10 18:14:21Z steve.ebersole at jboss.com $
+package org.hibernate.test.connections;
+
+import java.io.Serializable;
+
+/**
+ * Implementation of Silly.
+ *
+ * @author Steve Ebersole
+ */
+public class Silly implements Serializable {
+	private Long id;
+	private String name;
+	private Other other;
+
+	public Silly() {
+	}
+
+	public Silly(String name) {
+		this.name = name;
+	}
+
+	public Silly(String name, Other other) {
+		this.name = name;
+		this.other = other;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Other getOther() {
+		return other;
+	}
+
+	public void setOther(Other other) {
+		this.other = other;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/SuppliedConnectionTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/SuppliedConnectionTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/SuppliedConnectionTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,121 @@
+// $Id: SuppliedConnectionTest.java 11332 2007-03-22 17:34:55Z steve.ebersole at jboss.com $
+package org.hibernate.test.connections;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+
+import junit.framework.Test;
+
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.connection.ConnectionProviderFactory;
+import org.hibernate.connection.UserSuppliedConnectionProvider;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+
+/**
+ * Implementation of SuppliedConnectionTest.
+ *
+ * @author Steve Ebersole
+ */
+public class SuppliedConnectionTest extends ConnectionManagementTestCase {
+
+	private ConnectionProvider cp = ConnectionProviderFactory.newConnectionProvider();
+	private Connection connectionUnderTest;
+
+	public SuppliedConnectionTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SuppliedConnectionTest.class );
+	}
+
+	protected Session getSessionUnderTest() throws Throwable {
+		connectionUnderTest = cp.getConnection();
+		return getSessions().openSession( connectionUnderTest );
+	}
+
+	protected void reconnect(Session session) {
+		session.reconnect( connectionUnderTest );
+	}
+
+	protected void done() throws Throwable {
+		cp.closeConnection( connectionUnderTest );
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.ON_CLOSE.toString() );
+		cfg.setProperty( Environment.CONNECTION_PROVIDER, UserSuppliedConnectionProvider.class.getName() );
+		boolean supportsScroll = true;
+		Connection conn = null;
+		try {
+			conn = cp.getConnection();
+			supportsScroll = conn.getMetaData().supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE);
+		}
+		catch( Throwable ignore ) {
+		}
+		finally {
+			if ( conn != null ) {
+				try {
+					conn.close();
+				}
+				catch( Throwable ignore ) {
+					// ignore it...
+				}
+			}
+		}
+		cfg.setProperty( Environment.USE_SCROLLABLE_RESULTSET, "" + supportsScroll );
+	}
+
+	public boolean createSchema() {
+		return false;
+	}
+
+	public boolean recreateSchemaAfterFailure() {
+		return false;
+	}
+
+	protected void prepareTest() throws Exception {
+		super.prepareTest();
+		Connection conn = cp.getConnection();
+		try {
+			new SchemaExport( getCfg(), conn ).create( false, true );
+		}
+		finally {
+			if ( conn != null ) {
+				try {
+					cp.closeConnection( conn );
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+		}
+	}
+
+	protected void cleanupTest() throws Exception {
+		Connection conn = cp.getConnection();
+		try {
+			new SchemaExport( getCfg(), conn ).drop( false, true );
+		}
+		finally {
+			if ( conn != null ) {
+				try {
+					cp.closeConnection( conn );
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+		}
+		try {
+			cp.close();
+		}
+		catch( Throwable ignore ) {
+		}
+		super.cleanupTest();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/ThreadLocalCurrentSessionTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/ThreadLocalCurrentSessionTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/connections/ThreadLocalCurrentSessionTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,102 @@
+package org.hibernate.test.connections;
+
+import junit.framework.Test;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.context.ThreadLocalSessionContext;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Steve Ebersole
+ */
+public class ThreadLocalCurrentSessionTest extends ConnectionManagementTestCase {
+
+	public ThreadLocalCurrentSessionTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ThreadLocalCurrentSessionTest.class );
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS, TestableThreadLocalContext.class.getName() );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+	}
+
+	protected Session getSessionUnderTest() throws Throwable {
+		Session session = getSessions().getCurrentSession();
+		session.beginTransaction();
+		return session;
+	}
+
+	protected void release(Session session) {
+		long initialCount = getSessions().getStatistics().getSessionCloseCount();
+		session.getTransaction().commit();
+		long subsequentCount = getSessions().getStatistics().getSessionCloseCount();
+		assertEquals( "Session still open after commit", initialCount + 1, subsequentCount );
+		// also make sure it was cleaned up from the internal ThreadLocal...
+		assertFalse( "session still bound to internal ThreadLocal", TestableThreadLocalContext.hasBind() );
+	}
+
+	protected void reconnect(Session session) throws Throwable {
+//		session.reconnect();
+		session.beginTransaction();
+	}
+
+	protected void checkSerializedState(Session session) {
+		assertFalse( "session still bound after serialize", TestableThreadLocalContext.isSessionBound( session ) );
+	}
+
+	protected void checkDeserializedState(Session session) {
+		assertTrue( "session not bound after deserialize", TestableThreadLocalContext.isSessionBound( session ) );
+	}
+
+	public void testTransactionProtection() {
+		Session session = getSessions().getCurrentSession();
+		try {
+			session.createQuery( "from Silly" );
+			fail( "method other than beginTransaction{} allowed" );
+		}
+		catch ( HibernateException e ) {
+			// ok
+		}
+	}
+
+	public void testContextCleanup() {
+		Session session = getSessions().getCurrentSession();
+		session.beginTransaction();
+		session.getTransaction().commit();
+		assertFalse( "session open after txn completion", session.isOpen() );
+		assertFalse( "session still bound after txn completion", TestableThreadLocalContext.isSessionBound( session ) );
+
+		Session session2 = getSessions().getCurrentSession();
+		assertFalse( "same session returned after txn completion", session == session2 );
+		session2.close();
+		assertFalse( "session open after closing", session2.isOpen() );
+		assertFalse( "session still bound after closing", TestableThreadLocalContext.isSessionBound( session2 ) );
+	}
+
+	public static class TestableThreadLocalContext extends ThreadLocalSessionContext {
+		private static TestableThreadLocalContext me;
+
+		public TestableThreadLocalContext(SessionFactoryImplementor factory) {
+			super( factory );
+			me = this;
+		}
+
+		public static boolean isSessionBound(Session session) {
+			return sessionMap() != null && sessionMap().containsKey( me.factory )
+					&& sessionMap().get( me.factory ) == session;
+		}
+
+		public static boolean hasBind() {
+			return sessionMap() != null && sessionMap().containsKey( me.factory );
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Course.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Course.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Course.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: Course.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.criteria;
+
+/**
+ * @author Gavin King
+ */
+public class Course {
+	private String courseCode;
+	private String description;
+	public String getCourseCode() {
+		return courseCode;
+	}
+	public void setCourseCode(String courseCode) {
+		this.courseCode = courseCode;
+	}
+	public String getDescription() {
+		return description;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Course.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,800 @@
+//$Id: CriteriaQueryTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.criteria;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+
+import org.hibernate.Criteria;
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.DetachedCriteria;
+import org.hibernate.criterion.Example;
+import org.hibernate.criterion.Expression;
+import org.hibernate.criterion.MatchMode;
+import org.hibernate.criterion.Order;
+import org.hibernate.criterion.Projection;
+import org.hibernate.criterion.Projections;
+import org.hibernate.criterion.Property;
+import org.hibernate.criterion.Restrictions;
+import org.hibernate.criterion.Subqueries;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.hql.Animal;
+import org.hibernate.test.hql.Reptile;
+import org.hibernate.transform.Transformers;
+import org.hibernate.type.Type;
+import org.hibernate.util.SerializationHelper;
+
+/**
+ * @author Gavin King
+ */
+public class CriteriaQueryTest extends FunctionalTestCase {
+	
+	public CriteriaQueryTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "criteria/Enrolment.hbm.xml", "hql/Animal.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.USE_QUERY_CACHE, "true" );
+		cfg.setProperty( Environment.CACHE_REGION_PREFIX, "criteriaquerytest" );
+		cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CriteriaQueryTest.class );
+	}
+
+	public void testEscapeCharacter() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+		Course c1 = new Course();
+		c1.setCourseCode( "course-1" );
+		c1.setDescription( "%1" );
+		Course c2 = new Course();
+		c2.setCourseCode( "course-2" );
+		c2.setDescription( "%2" );
+		Course c3 = new Course();
+		c3.setCourseCode( "course-3" );
+		c3.setDescription( "control" );
+		session.persist( c1 );
+		session.persist( c2 );
+		session.persist( c3 );
+		session.flush();
+		session.clear();
+
+		// finds all courses which have a description equal to '%1'
+		Course example = new Course();
+		example.setDescription( "&%1" );
+		List result = session.createCriteria( Course.class )
+				.add( Example.create( example ).ignoreCase().enableLike().setEscapeCharacter( new Character( '&' ) ) )
+				.list();
+		assertEquals( 1, result.size() );
+		// finds all courses which contain '%' as the first char in the description 
+		example.setDescription( "&%%" );
+		result = session.createCriteria( Course.class )
+				.add( Example.create( example ).ignoreCase().enableLike().setEscapeCharacter( new Character( '&' ) ) )
+				.list();
+		assertEquals( 2, result.size() );
+
+		session.createQuery( "delete Course" ).executeUpdate();
+		t.commit();
+		session.close();
+	}
+
+	public void testScrollCriteria() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		session.persist(course);
+		session.flush();
+		session.clear();
+		ScrollableResults sr = session.createCriteria(Course.class).scroll();
+		assertTrue( sr.next() );
+		course = (Course) sr.get(0);
+		assertNotNull(course);
+		sr.close();
+		session.delete(course);
+		
+		t.commit();
+		session.close();
+		
+	}
+	
+	public void testSubselect() {
+
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		session.persist(course);
+		
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		session.persist(gavin);
+
+		Enrolment enrolment2 = new Enrolment();
+		enrolment2.setCourse(course);
+		enrolment2.setCourseCode(course.getCourseCode());
+		enrolment2.setSemester((short) 3);
+		enrolment2.setYear((short) 1998);
+		enrolment2.setStudent(gavin);
+		enrolment2.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add(enrolment2);
+		session.persist(enrolment2);
+		
+		DetachedCriteria dc = DetachedCriteria.forClass(Student.class)
+			.add( Property.forName("studentNumber").eq( new Long(232) ) )
+			.setProjection( Property.forName("name") );
+
+		session.createCriteria(Student.class)
+			.add( Subqueries.propertyEqAll("name", dc) )
+			.list();
+		
+		session.createCriteria(Student.class)
+			.add( Subqueries.exists(dc) )
+			.list();
+	
+		session.createCriteria(Student.class)
+		.add( Property.forName("name").eqAll(dc) )
+		.list();
+	
+		session.createCriteria(Student.class)
+			.add( Subqueries.in("Gavin King", dc) )
+			.list();
+		
+		DetachedCriteria dc2 = DetachedCriteria.forClass(Student.class, "st")
+			.add( Property.forName("st.studentNumber").eqProperty("e.studentNumber") )
+			.setProjection( Property.forName("name") );
+		
+		session.createCriteria(Enrolment.class, "e")
+			.add( Subqueries.eq("Gavin King", dc2) )
+			.list();
+
+		//TODO: join in subselect: HHH-952
+		/*DetachedCriteria dc3 = DetachedCriteria.forClass(Student.class, "st")
+			.createCriteria("enrolments")
+				.createCriteria("course")
+					.add( Property.forName("description").eq("Hibernate Training") )
+					.setProjection( Property.forName("st.name") );
+	
+		session.createCriteria(Enrolment.class, "e")
+			.add( Subqueries.eq("Gavin King", dc3) )
+			.list();*/
+
+		session.delete(enrolment2);
+		session.delete(gavin);
+		session.delete(course);
+		t.commit();
+		session.close();
+		
+	}
+	
+	public void testDetachedCriteria() {
+		
+		DetachedCriteria dc = DetachedCriteria.forClass(Student.class)
+			.add( Property.forName("name").eq("Gavin King") )
+			.addOrder( Order.asc("studentNumber") )
+			.setProjection( Property.forName("studentNumber") );
+		
+		byte[] bytes = SerializationHelper.serialize(dc);
+		
+		dc = (DetachedCriteria) SerializationHelper.deserialize(bytes);
+		
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		Student bizarroGavin = new Student();
+		bizarroGavin.setName("Gavin King");
+		bizarroGavin.setStudentNumber(666);
+		session.persist(bizarroGavin);
+		session.persist(gavin);
+		
+		List result = dc.getExecutableCriteria(session)
+			.setMaxResults(3)
+			.list();
+		
+		assertEquals( result.size(), 2 );
+		assertEquals( result.get(0), new Long(232) );
+		assertEquals( result.get(1), new Long(666) );
+		
+		session.delete(gavin);
+		session.delete(bizarroGavin);
+		t.commit();
+		session.close();
+	}
+	
+		public void testProjectionCache() {
+			Session s = openSession();
+			Transaction t = s.beginTransaction();
+			
+			Course course = new Course();
+			course.setCourseCode("HIB");
+			course.setDescription("Hibernate Training");
+			s.save(course);
+			
+			Student gavin = new Student();
+			gavin.setName("Gavin King");
+			gavin.setStudentNumber(666);
+			s.save(gavin);
+			
+			Student xam = new Student();
+			xam.setName("Max Rydahl Andersen");
+			xam.setStudentNumber(101);
+			s.save(xam);
+			
+			Enrolment enrolment1 = new Enrolment();
+			enrolment1.setCourse(course);
+			enrolment1.setCourseCode(course.getCourseCode());
+			enrolment1.setSemester((short) 1);
+			enrolment1.setYear((short) 1999);
+			enrolment1.setStudent(xam);
+			enrolment1.setStudentNumber(xam.getStudentNumber());
+			xam.getEnrolments().add(enrolment1);
+			s.save(enrolment1);
+			
+			Enrolment enrolment2 = new Enrolment();
+			enrolment2.setCourse(course);
+			enrolment2.setCourseCode(course.getCourseCode());
+			enrolment2.setSemester((short) 3);
+			enrolment2.setYear((short) 1998);
+			enrolment2.setStudent(gavin);
+			enrolment2.setStudentNumber(gavin.getStudentNumber());
+			gavin.getEnrolments().add(enrolment2);
+			s.save(enrolment2);
+			
+			List list = s.createCriteria(Enrolment.class)
+				.createAlias("student", "s")
+				.createAlias("course", "c")
+				.add( Restrictions.isNotEmpty("s.enrolments") )
+				.setProjection( Projections.projectionList()
+						.add( Projections.property("s.name") )
+						.add( Projections.property("c.description") )
+				)
+				.setCacheable(true)
+				.list();
+			
+			assertEquals( list.size(), 2 );
+			assertEquals( ( (Object[]) list.get(0) ).length, 2 );
+			assertEquals( ( (Object[]) list.get(1) ).length, 2 );
+			
+			t.commit();
+			s.close();
+	
+			s = openSession();
+			t = s.beginTransaction();
+			
+			s.createCriteria(Enrolment.class)
+				.createAlias("student", "s")
+				.createAlias("course", "c")
+				.add( Restrictions.isNotEmpty("s.enrolments") )
+				.setProjection( Projections.projectionList()
+						.add( Projections.property("s.name") )
+						.add( Projections.property("c.description") )
+				)
+				.setCacheable(true)
+				.list();
+		
+			assertEquals( list.size(), 2 );
+			assertEquals( ( (Object[]) list.get(0) ).length, 2 );
+			assertEquals( ( (Object[]) list.get(1) ).length, 2 );
+			
+			t.commit();
+			s.close();
+	
+			s = openSession();
+			t = s.beginTransaction();
+			
+			s.createCriteria(Enrolment.class)
+				.createAlias("student", "s")
+				.createAlias("course", "c")
+				.add( Restrictions.isNotEmpty("s.enrolments") )
+				.setProjection( Projections.projectionList()
+						.add( Projections.property("s.name") )
+						.add( Projections.property("c.description") )
+				)
+				.setCacheable(true)
+				.list();
+			
+			assertEquals( list.size(), 2 );
+			assertEquals( ( (Object[]) list.get(0) ).length, 2 );
+			assertEquals( ( (Object[]) list.get(1) ).length, 2 );
+			
+			s.delete(enrolment1);
+			s.delete(enrolment2);
+			s.delete(course);
+			s.delete(gavin);
+			s.delete(xam);
+		
+			t.commit();
+			s.close();
+	}
+	
+	public void testProjections() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.save(course);
+		
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(667);
+		s.save(gavin);
+		
+		Student xam = new Student();
+		xam.setName("Max Rydahl Andersen");
+		xam.setStudentNumber(101);
+		s.save(xam);
+		
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 1);
+		enrolment.setYear((short) 1999);
+		enrolment.setStudent(xam);
+		enrolment.setStudentNumber(xam.getStudentNumber());
+		xam.getEnrolments().add(enrolment);
+		s.save(enrolment);
+		
+		enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add(enrolment);
+		s.save(enrolment);
+		
+		//s.flush();
+		
+		Integer count = (Integer) s.createCriteria(Enrolment.class)
+			.setProjection( Projections.count("studentNumber").setDistinct() )
+			.uniqueResult();
+		assertEquals(count, new Integer(2));
+		
+		Object object = s.createCriteria(Enrolment.class)
+			.setProjection( Projections.projectionList()
+					.add( Projections.count("studentNumber") )
+					.add( Projections.max("studentNumber") )
+					.add( Projections.min("studentNumber") )
+					.add( Projections.avg("studentNumber") )
+			)
+			.uniqueResult();
+		Object[] result = (Object[])object; 
+		
+		assertEquals(new Integer(2),result[0]);
+		assertEquals(new Long(667),result[1]);
+		assertEquals(new Long(101),result[2]);
+		assertEquals( 384.0, ( (Double) result[3] ).doubleValue(), 0.01 );
+		
+		
+		List resultWithMaps = s.createCriteria(Enrolment.class)
+			.setProjection( Projections.distinct( Projections.projectionList()
+					.add( Projections.property("studentNumber"), "stNumber" )
+					.add( Projections.property("courseCode"), "cCode" ) )
+			)
+		    .add( Expression.gt( "studentNumber", new Long(665) ) )
+		    .add( Expression.lt( "studentNumber", new Long(668) ) )
+		    .addOrder( Order.asc("stNumber") )
+			.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+			.list();
+		
+		assertEquals(1, resultWithMaps.size());
+		Map m1 = (Map) resultWithMaps.get(0);
+		
+		assertEquals(new Long(667), m1.get("stNumber"));
+		assertEquals(course.getCourseCode(), m1.get("cCode"));		
+
+		resultWithMaps = s.createCriteria(Enrolment.class)
+			.setProjection( Projections.property("studentNumber").as("stNumber") )
+		    .addOrder( Order.desc("stNumber") )
+			.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+			.list();
+		
+		assertEquals(2, resultWithMaps.size());
+		Map m0 = (Map) resultWithMaps.get(0);
+		m1 = (Map) resultWithMaps.get(1);
+		
+		assertEquals(new Long(101), m1.get("stNumber"));
+		assertEquals(new Long(667), m0.get("stNumber"));
+
+	
+		List resultWithAliasedBean = s.createCriteria(Enrolment.class)
+			.createAlias("student", "st")
+			.createAlias("course", "co")
+			.setProjection( Projections.projectionList()
+					.add( Projections.property("st.name"), "studentName" )
+					.add( Projections.property("co.description"), "courseDescription" )
+			)
+			.addOrder( Order.desc("studentName") )
+			.setResultTransformer( Transformers.aliasToBean(StudentDTO.class) )
+			.list();
+		
+		assertEquals(2, resultWithAliasedBean.size());
+		
+		StudentDTO dto = (StudentDTO) resultWithAliasedBean.get(0);
+		assertNotNull(dto.getDescription());
+		assertNotNull(dto.getName());
+	
+		s.createCriteria(Student.class)
+			.add( Restrictions.like("name", "Gavin", MatchMode.START) )
+			.addOrder( Order.asc("name") )
+			.createCriteria("enrolments", "e")
+				.addOrder( Order.desc("year") )
+				.addOrder( Order.desc("semester") )
+			.createCriteria("course","c")
+				.addOrder( Order.asc("description") )
+				.setProjection( Projections.projectionList()
+					.add( Projections.property("this.name") )
+					.add( Projections.property("e.year") )
+					.add( Projections.property("e.semester") )
+					.add( Projections.property("c.courseCode") )
+					.add( Projections.property("c.description") )
+				)
+			.uniqueResult();
+			
+		Projection p1 = Projections.projectionList()
+			.add( Projections.count("studentNumber") )
+			.add( Projections.max("studentNumber") )
+			.add( Projections.rowCount() );
+		
+		Projection p2 = Projections.projectionList()
+			.add( Projections.min("studentNumber") )
+			.add( Projections.avg("studentNumber") )
+			.add( Projections.sqlProjection(
+					"1 as constOne, count(*) as countStar", 
+					new String[] { "constOne", "countStar" }, 
+					new Type[] { Hibernate.INTEGER, Hibernate.INTEGER }
+			) );
+	
+		Object[] array = (Object[]) s.createCriteria(Enrolment.class)
+			.setProjection( Projections.projectionList().add(p1).add(p2) )
+			.uniqueResult();
+		
+		assertEquals( array.length, 7 );
+		
+		List list = s.createCriteria(Enrolment.class)
+			.createAlias("student", "st")
+			.createAlias("course", "co")
+			.setProjection( Projections.projectionList()
+					.add( Projections.groupProperty("co.courseCode") )
+					.add( Projections.count("st.studentNumber").setDistinct() )
+					.add( Projections.groupProperty("year") )
+			)
+			.list();
+		
+		assertEquals( list.size(), 2 );
+		
+		Object g = s.createCriteria(Student.class)
+			.add( Restrictions.idEq( new Long(667) ) )
+			.setFetchMode("enrolments", FetchMode.JOIN)
+			//.setFetchMode("enrolments.course", FetchMode.JOIN) //TODO: would love to make that work...
+			.uniqueResult();
+		assertSame(g, gavin);
+
+		s.delete(gavin);
+		s.delete(xam);
+		s.delete(course);
+		
+		t.commit();
+		s.close();
+	}
+		
+	public void testProjectionsUsingProperty() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.save(course);
+		
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(667);
+		s.save(gavin);
+		
+		Student xam = new Student();
+		xam.setName("Max Rydahl Andersen");
+		xam.setStudentNumber(101);
+		s.save(xam);
+		
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 1);
+		enrolment.setYear((short) 1999);
+		enrolment.setStudent(xam);
+		enrolment.setStudentNumber(xam.getStudentNumber());
+		xam.getEnrolments().add(enrolment);
+		s.save(enrolment);
+		
+		enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add(enrolment);
+		s.save(enrolment);
+		
+		s.flush();
+		
+		Integer count = (Integer) s.createCriteria(Enrolment.class)
+			.setProjection( Property.forName("studentNumber").count().setDistinct() )
+			.uniqueResult();
+		assertEquals(count, new Integer(2));
+		
+		Object object = s.createCriteria(Enrolment.class)
+			.setProjection( Projections.projectionList()
+					.add( Property.forName("studentNumber").count() )
+					.add( Property.forName("studentNumber").max() )
+					.add( Property.forName("studentNumber").min() )
+					.add( Property.forName("studentNumber").avg() )
+			)
+			.uniqueResult();
+		Object[] result = (Object[])object; 
+		
+		assertEquals(new Integer(2),result[0]);
+		assertEquals(new Long(667),result[1]);
+		assertEquals(new Long(101),result[2]);
+		assertEquals(384.0, ( (Double) result[3] ).doubleValue(), 0.01);
+		
+		
+		s.createCriteria(Enrolment.class)
+		    .add( Property.forName("studentNumber").gt( new Long(665) ) )
+		    .add( Property.forName("studentNumber").lt( new Long(668) ) )
+		    .add( Property.forName("courseCode").like("HIB", MatchMode.START) )
+		    .add( Property.forName("year").eq( new Short( (short) 1999 ) ) )
+		    .addOrder( Property.forName("studentNumber").asc() )
+			.uniqueResult();
+	
+		List resultWithMaps = s.createCriteria(Enrolment.class)
+			.setProjection( Projections.projectionList()
+					.add( Property.forName("studentNumber").as("stNumber") )
+					.add( Property.forName("courseCode").as("cCode") )
+			)
+		    .add( Property.forName("studentNumber").gt( new Long(665) ) )
+		    .add( Property.forName("studentNumber").lt( new Long(668) ) )
+		    .addOrder( Property.forName("studentNumber").asc() )
+			.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+			.list();
+		
+		assertEquals(1, resultWithMaps.size());
+		Map m1 = (Map) resultWithMaps.get(0);
+		
+		assertEquals(new Long(667), m1.get("stNumber"));
+		assertEquals(course.getCourseCode(), m1.get("cCode"));		
+
+		resultWithMaps = s.createCriteria(Enrolment.class)
+			.setProjection( Property.forName("studentNumber").as("stNumber") )
+		    .addOrder( Order.desc("stNumber") )
+			.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+			.list();
+		
+		assertEquals(2, resultWithMaps.size());
+		Map m0 = (Map) resultWithMaps.get(0);
+		m1 = (Map) resultWithMaps.get(1);
+		
+		assertEquals(new Long(101), m1.get("stNumber"));
+		assertEquals(new Long(667), m0.get("stNumber"));
+
+	
+		List resultWithAliasedBean = s.createCriteria(Enrolment.class)
+			.createAlias("student", "st")
+			.createAlias("course", "co")
+			.setProjection( Projections.projectionList()
+					.add( Property.forName("st.name").as("studentName") )
+					.add( Property.forName("co.description").as("courseDescription") )
+			)
+			.addOrder( Order.desc("studentName") )
+			.setResultTransformer( Transformers.aliasToBean(StudentDTO.class) )
+			.list();
+		
+		assertEquals(2, resultWithAliasedBean.size());
+		
+		StudentDTO dto = (StudentDTO) resultWithAliasedBean.get(0);
+		assertNotNull(dto.getDescription());
+		assertNotNull(dto.getName());
+	
+		s.createCriteria(Student.class)
+			.add( Restrictions.like("name", "Gavin", MatchMode.START) )
+			.addOrder( Order.asc("name") )
+			.createCriteria("enrolments", "e")
+				.addOrder( Order.desc("year") )
+				.addOrder( Order.desc("semester") )
+			.createCriteria("course","c")
+				.addOrder( Order.asc("description") )
+				.setProjection( Projections.projectionList()
+					.add( Property.forName("this.name") )
+					.add( Property.forName("e.year") )
+					.add( Property.forName("e.semester") )
+					.add( Property.forName("c.courseCode") )
+					.add( Property.forName("c.description") )
+				)
+			.uniqueResult();
+			
+		Projection p1 = Projections.projectionList()
+			.add( Property.forName("studentNumber").count() )
+			.add( Property.forName("studentNumber").max() )
+			.add( Projections.rowCount() );
+		
+		Projection p2 = Projections.projectionList()
+			.add( Property.forName("studentNumber").min() )
+			.add( Property.forName("studentNumber").avg() )
+			.add( Projections.sqlProjection(
+					"1 as constOne, count(*) as countStar", 
+					new String[] { "constOne", "countStar" }, 
+					new Type[] { Hibernate.INTEGER, Hibernate.INTEGER }
+			) );
+	
+		Object[] array = (Object[]) s.createCriteria(Enrolment.class)
+			.setProjection( Projections.projectionList().add(p1).add(p2) )
+			.uniqueResult();
+		
+		assertEquals( array.length, 7 );
+		
+		List list = s.createCriteria(Enrolment.class)
+			.createAlias("student", "st")
+			.createAlias("course", "co")
+			.setProjection( Projections.projectionList()
+					.add( Property.forName("co.courseCode").group() )
+					.add( Property.forName("st.studentNumber").count().setDistinct() )
+					.add( Property.forName("year").group() )
+			)
+			.list();
+		
+		assertEquals( list.size(), 2 );
+		
+		s.delete(gavin);
+		s.delete(xam);
+		s.delete(course);
+		
+		t.commit();
+		s.close();
+	}
+
+	public void testRestrictionOnSubclassCollection() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		s.createCriteria( Reptile.class )
+				.add( Restrictions.isEmpty( "offspring" ) )
+				.list();
+
+		s.createCriteria( Reptile.class )
+				.add( Restrictions.isNotEmpty( "offspring" ) )
+				.list();
+
+		t.rollback();
+		s.close();
+	}
+
+	public void testClassProperty() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		// HQL: from Animal a where a.mother.class = Reptile
+		Criteria c = s.createCriteria(Animal.class,"a")
+			.createAlias("mother","m")
+			.add( Property.forName("m.class").eq(Reptile.class) );
+		c.list();
+		t.rollback();
+		s.close();
+	}
+
+	public void testProjectedId() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createCriteria(Course.class).setProjection( Projections.property("courseCode") ).list();
+		s.createCriteria(Course.class).setProjection( Projections.id() ).list();
+		t.rollback();
+		s.close();
+	}
+
+	public void testSubcriteriaJoinTypes() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+
+		Course courseA = new Course();
+		courseA.setCourseCode("HIB-A");
+		courseA.setDescription("Hibernate Training A");
+		session.persist(courseA);
+
+		Course courseB = new Course();
+		courseB.setCourseCode("HIB-B");
+		courseB.setDescription("Hibernate Training B");
+		session.persist(courseB);
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse(courseA);
+		session.persist(gavin);
+
+		Student leonardo = new Student();
+		leonardo.setName("Leonardo Quijano");
+		leonardo.setStudentNumber(233);
+		leonardo.setPreferredCourse(courseB);
+		session.persist(leonardo);
+
+		Student johnDoe = new Student();
+		johnDoe.setName("John Doe");
+		johnDoe.setStudentNumber(235);
+		johnDoe.setPreferredCourse(null);
+		session.persist(johnDoe);
+
+		List result = session.createCriteria( Student.class )
+				.setProjection( Property.forName("preferredCourse.courseCode") )
+				.createCriteria( "preferredCourse", Criteria.LEFT_JOIN )
+						.addOrder( Order.asc( "courseCode" ) )
+						.list();
+		assertEquals( 3, result.size() );
+		// can't be sure of NULL comparison ordering aside from they should
+		// either come first or last
+		if ( result.get( 0 ) == null ) {
+			assertEquals( "HIB-A", result.get(1) );
+			assertEquals( "HIB-B", result.get(2) );
+		}
+		else {
+			assertNull( result.get(2) );
+			assertEquals( "HIB-A", result.get(0) );
+			assertEquals( "HIB-B", result.get(1) );
+		}
+
+		result = session.createCriteria( Student.class )
+				.setFetchMode( "preferredCourse", FetchMode.JOIN )
+				.createCriteria( "preferredCourse", Criteria.LEFT_JOIN )
+						.addOrder( Order.asc( "courseCode" ) )
+						.list();
+		assertEquals( 3, result.size() );
+		assertNotNull( result.get(0) );
+		assertNotNull( result.get(1) );
+		assertNotNull( result.get(2) );
+
+		result = session.createCriteria( Student.class )
+				.setFetchMode( "preferredCourse", FetchMode.JOIN )
+				.createAlias( "preferredCourse", "pc", Criteria.LEFT_JOIN )
+				.addOrder( Order.asc( "pc.courseCode" ) )
+				.list();
+		assertEquals( 3, result.size() );
+		assertNotNull( result.get(0) );
+		assertNotNull( result.get(1) );
+		assertNotNull( result.get(2) );
+
+		session.delete(gavin);
+		session.delete(leonardo);
+		session.delete(johnDoe);
+		session.delete(courseA);
+		session.delete(courseB);
+		t.commit();
+		session.close();
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Enrolment.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Enrolment.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Enrolment.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.criteria">
+	
+	<class name="Course">
+		<id name="courseCode">
+			<generator class="assigned"/>
+		</id>
+		<property name="description"/>
+	</class>
+	
+	<class name="Student">
+		<id name="studentNumber">
+		    <column name="studentId"/>
+			<generator class="assigned"/>
+		</id>
+		<property name="name" not-null="true"/>
+		<set name="enrolments" inverse="true" cascade="delete">
+			<key column="studentId"/>
+			<one-to-many class="Enrolment"/>
+		</set>
+        <many-to-one name="preferredCourse" column="preferredCourseCode"/>
+	</class>
+	
+	<class name="Enrolment">
+		<composite-id>
+			<key-property name="studentNumber">
+				<column name="studentId"/>
+			</key-property>
+			<key-property name="courseCode"/>
+		</composite-id>
+		<many-to-one name="student" insert="false" update="false">
+			<column name="studentId"/>
+		</many-to-one>
+		<many-to-one name="course" insert="false" update="false">
+			<column name="courseCode"/>
+		</many-to-one>
+		<property name="semester" not-null="true"/>
+		<property name="year" not-null="true"/>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Enrolment.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Enrolment.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Enrolment.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Enrolment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+//$Id: Enrolment.java 6970 2005-05-31 20:24:41Z oneovthafew $
+package org.hibernate.test.criteria;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Enrolment implements Serializable {
+	private Student student;
+	private Course course;
+	private long studentNumber;
+	private String courseCode;
+	private short year;
+	private short semester;
+	public String getCourseCode() {
+		return courseCode;
+	}
+	public void setCourseCode(String courseId) {
+		this.courseCode = courseId;
+	}
+	public long getStudentNumber() {
+		return studentNumber;
+	}
+	public void setStudentNumber(long studentId) {
+		this.studentNumber = studentId;
+	}
+	public Course getCourse() {
+		return course;
+	}
+	public void setCourse(Course course) {
+		this.course = course;
+	}
+	public Student getStudent() {
+		return student;
+	}
+	public void setStudent(Student student) {
+		this.student = student;
+	}
+	public short getSemester() {
+		return semester;
+	}
+	public void setSemester(short semester) {
+		this.semester = semester;
+	}
+	public short getYear() {
+		return year;
+	}
+	public void setYear(short year) {
+		this.year = year;
+	}
+	
+	public boolean equals(Object other) {
+		if ( !(other instanceof Enrolment) ) return false;
+		Enrolment that = (Enrolment) other;
+		return studentNumber==that.studentNumber &&
+			courseCode.equals(that.courseCode);
+	}
+	
+	public int hashCode() {
+		return courseCode.hashCode();
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Enrolment.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Student.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Student.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Student.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+//$Id: Student.java 9116 2006-01-23 21:21:01Z steveebersole $
+package org.hibernate.test.criteria;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class Student {
+	private long studentNumber;
+	private String name;
+	private Course preferredCourse;
+	private Set enrolments = new HashSet();
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public long getStudentNumber() {
+		return studentNumber;
+	}
+
+	public void setStudentNumber(long studentNumber) {
+		this.studentNumber = studentNumber;
+	}
+
+	public Course getPreferredCourse() {
+		return preferredCourse;
+	}
+
+	public void setPreferredCourse(Course preferredCourse) {
+		this.preferredCourse = preferredCourse;
+	}
+
+	public Set getEnrolments() {
+		return enrolments;
+	}
+
+	public void setEnrolments(Set employments) {
+		this.enrolments = employments;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/Student.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/StudentDTO.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/StudentDTO.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/criteria/StudentDTO.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+/*
+ * Created on 28-Jan-2005
+ *
+ */
+package org.hibernate.test.criteria;
+
+/**
+ * @author max
+ *
+ */
+public class StudentDTO {
+
+	private String studentName;
+	private String courseDescription;
+
+	public StudentDTO() { }
+	
+	public String getName() {
+		return studentName;
+	}
+	
+	public String getDescription() {
+		return courseDescription;
+	}
+	
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Account.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Account.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Account.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+//$Id: Account.java 4592 2004-09-26 00:39:43Z oneovthafew $
+package org.hibernate.test.cuk;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Account implements Serializable {
+	private String accountId;
+	private Person user;
+	private char type;
+	/**
+	 * @return Returns the user.
+	 */
+	public Person getUser() {
+		return user;
+	}
+	/**
+	 * @param user The user to set.
+	 */
+	public void setUser(Person user) {
+		this.user = user;
+	}
+	/**
+	 * @return Returns the accountId.
+	 */
+	public String getAccountId() {
+		return accountId;
+	}
+	/**
+	 * @param accountId The accountId to set.
+	 */
+	public void setAccountId(String accountId) {
+		this.accountId = accountId;
+	}
+	/**
+	 * @return Returns the type.
+	 */
+	public char getType() {
+		return type;
+	}
+	/**
+	 * @param type The type to set.
+	 */
+	public void setType(char type) {
+		this.type = type;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Account.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,75 @@
+//$Id: Address.java 4592 2004-09-26 00:39:43Z oneovthafew $
+package org.hibernate.test.cuk;
+
+import java.io.Serializable;
+
+/**
+ * @author gavin
+ */
+public class Address implements Serializable {
+	private Long id;
+	private String address;
+	private String zip;
+	private String country;
+	private Person person;
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the person.
+	 */
+	public Person getPerson() {
+		return person;
+	}
+	/**
+	 * @param person The person to set.
+	 */
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+	/**
+	 * @return Returns the address.
+	 */
+	public String getAddress() {
+		return address;
+	}
+	/**
+	 * @param address The address to set.
+	 */
+	public void setAddress(String address) {
+		this.address = address;
+	}
+	/**
+	 * @return Returns the country.
+	 */
+	public String getCountry() {
+		return country;
+	}
+	/**
+	 * @param country The country to set.
+	 */
+	public void setCountry(String country) {
+		this.country = country;
+	}
+	/**
+	 * @return Returns the zip.
+	 */
+	public String getZip() {
+		return zip;
+	}
+	/**
+	 * @param zip The zip to set.
+	 */
+	public void setZip(String zip) {
+		this.zip = zip;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Address.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/CompositePropertyRefTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/CompositePropertyRefTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/CompositePropertyRefTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,124 @@
+//$Id: CompositePropertyRefTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.cuk;
+
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class CompositePropertyRefTest extends FunctionalTestCase {
+	
+	public CompositePropertyRefTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "cuk/Person.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.DEFAULT_BATCH_FETCH_SIZE, "1");
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CompositePropertyRefTest.class );
+	}
+	
+	public void testOneToOnePropertyRef() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person p = new Person();
+		p.setName("Steve");
+		p.setUserId("steve");
+		Address a = new Address();
+		a.setAddress("Texas");
+		a.setCountry("USA");
+		p.setAddress(a);
+		a.setPerson(p);
+		s.save(p);
+		Person p2 = new Person();
+		p2.setName("Max");
+		p2.setUserId("max");
+		s.save(p2);
+		Account act = new Account();
+		act.setType('c');
+		act.setUser(p2);
+		p2.getAccounts().add(act);
+		s.save(act);
+		s.flush();
+		s.clear();
+		
+		p = (Person) s.get( Person.class, p.getId() ); //get address reference by outer join
+		p2 = (Person) s.get( Person.class, p2.getId() ); //get null address reference by outer join
+		assertNull( p2.getAddress() );
+		assertNotNull( p.getAddress() );
+		List l = s.createQuery("from Person").list(); //pull address references for cache
+		assertEquals( l.size(), 2 );
+		assertTrue( l.contains(p) && l.contains(p2) );
+		s.clear();
+		
+		l = s.createQuery("from Person p order by p.name").list(); //get address references by sequential selects
+		assertEquals( l.size(), 2 );
+		assertNull( ( (Person) l.get(0) ).getAddress() );
+		assertNotNull( ( (Person) l.get(1) ).getAddress() );
+		s.clear();
+		
+		l = s.createQuery("from Person p left join fetch p.address a order by a.country").list(); //get em by outer join
+		assertEquals( l.size(), 2 );
+		if ( ( (Person) l.get(0) ).getName().equals("Max") ) {
+			assertNull( ( (Person) l.get(0) ).getAddress() );
+			assertNotNull( ( (Person) l.get(1) ).getAddress() );
+		}
+		else {
+			assertNull( ( (Person) l.get(1) ).getAddress() );
+			assertNotNull( ( (Person) l.get(0) ).getAddress() );
+		}
+		s.clear();
+		
+		l = s.createQuery("from Person p left join p.accounts").list();
+		for ( int i=0; i<2; i++ ) {
+			Object[] row = (Object[]) l.get(i);
+			Person px = (Person) row[0];
+			Set accounts = px.getAccounts();
+			assertFalse( Hibernate.isInitialized(accounts) );
+			assertTrue( px.getAccounts().size()>0 || row[1]==null );
+		}
+		s.clear();
+
+		l = s.createQuery("from Person p left join fetch p.accounts a order by p.name").list();
+		Person p0 = (Person) l.get(0);
+		assertTrue( Hibernate.isInitialized( p0.getAccounts() ) );
+		assertEquals( p0.getAccounts().size(), 1 );
+		assertSame( ( (Account) p0.getAccounts().iterator().next() ).getUser(), p0 );
+		Person p1 = (Person) l.get(1);
+		assertTrue( Hibernate.isInitialized( p1.getAccounts() ) );
+		assertEquals( p1.getAccounts().size(), 0 );
+		s.clear();
+		
+		l = s.createQuery("from Account a join fetch a.user").list();
+		
+		s.clear();
+		
+		l = s.createQuery("from Person p left join fetch p.address").list();
+		
+		s.clear();
+		s.createQuery( "delete Address" ).executeUpdate();
+		s.createQuery( "delete Account" ).executeUpdate();
+		s.createQuery( "delete Person" ).executeUpdate();
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/CompositePropertyRefTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+  Demonstrates the use of property-ref to map legacy data where
+  foreign keys reference something other than the primary key of
+  the associated entity. Here we show:
+  
+  (1) A one-to-one foreign key association (prefer primary key 
+      associations)
+      
+  (2) A bidirectional one-to-many association on a key that is
+      comprised of several properties of the associated entity
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.cuk">
+
+	<class name="Person">
+		<id name="id">
+			<generator class="hilo"/>
+		</id>
+		<property name="name" length="100"/>
+        <one-to-one name="address" property-ref="person" cascade="all" fetch="join"/>
+		<set name="accounts" inverse="true">
+            <key property-ref="userIdAndDeleted">
+				<column name="userId"/>
+				<column name="userDeleted"/>
+			</key>
+			<one-to-many class="Account"/>
+		</set>
+		<properties name="userIdAndDeleted" update="false" unique="true">
+			<property name="userId" length="8"/>
+			<property name="deleted"/>
+		</properties>
+		
+	</class>
+
+	<class name="Address">
+	    <id name="id">
+			<generator class="hilo"/>
+		</id>
+		<property name="address" length="300"/>
+		<property name="zip" length="5"/>
+		<property name="country" length="25"/>
+		<many-to-one name="person" unique="true" not-null="true"/>
+	</class>
+	
+	<class name="Account">
+		<id name="accountId" length="32">
+			<generator class="uuid.hex"/>
+		</id>
+		<many-to-one name="user" property-ref="userIdAndDeleted">
+			<column name="userId"/>
+			<column name="userDeleted"/>
+		</many-to-one>
+		<property name="type" not-null="true"/>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Person.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,100 @@
+//$Id: Person.java 4592 2004-09-26 00:39:43Z oneovthafew $
+package org.hibernate.test.cuk;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author gavin
+ */
+public class Person implements Serializable {
+	private Long id;
+	private String name;
+	private Address address;
+	private String userId;
+	private boolean deleted;
+	private Set accounts = new HashSet();
+	/**
+	 * @return Returns the userId.
+	 */
+	public String getUserId() {
+		return userId;
+	}
+	/**
+	 * @param userId The userId to set.
+	 */
+	public void setUserId(String userId) {
+		this.userId = userId;
+	}
+	/**
+	 * @return Returns the address.
+	 */
+	public Address getAddress() {
+		return address;
+	}
+	/**
+	 * @param address The address to set.
+	 */
+	public void setAddress(Address address) {
+		this.address = address;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	/**
+	 * @return Returns the accounts.
+	 */
+	public Set getAccounts() {
+		return accounts;
+	}
+	/**
+	 * @param accounts The accounts to set.
+	 */
+	public void setAccounts(Set accounts) {
+		this.accounts = accounts;
+	}
+	
+	public boolean isDeleted() {
+		return deleted;
+	}
+	
+	public void setDeleted(boolean deleted) {
+		this.deleted = deleted;
+	}
+	
+	public boolean equals(Object other) {
+		if (other instanceof Person) {
+			Person that = (Person) other;
+			return that.isDeleted() == deleted && that.getUserId().equals(userId);
+		}
+		else {
+			return false;
+		}
+	}
+	
+	public int hashCode() {
+		return userId.hashCode();
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cuk/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/CompositeUserTypeTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/CompositeUserTypeTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/CompositeUserTypeTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+//$Id: CompositeUserTypeTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.cut;
+
+import java.math.BigDecimal;
+import java.util.Currency;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class CompositeUserTypeTest extends FunctionalTestCase {
+	
+	public CompositeUserTypeTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "cut/types.hbm.xml", "cut/Transaction.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CompositeUserTypeTest.class );
+	}
+	
+	public void testCompositeUserType() {
+		Session s = openSession();
+		org.hibernate.Transaction t = s.beginTransaction();
+		
+		Transaction tran = new Transaction();
+		tran.setDescription("a small transaction");
+		tran.setValue( new MonetoryAmount( new BigDecimal(1.5), Currency.getInstance("USD") ) );
+		s.persist(tran);
+		
+		List result = s.createQuery("from Transaction tran where tran.value.amount > 1.0 and tran.value.currency = 'USD'").list();
+		assertEquals( result.size(), 1 );
+		tran.getValue().setCurrency( Currency.getInstance("AUD") );
+		result = s.createQuery("from Transaction tran where tran.value.amount > 1.0 and tran.value.currency = 'AUD'").list();
+		assertEquals( result.size(), 1 );
+		
+		if ( !(getDialect() instanceof HSQLDialect) && ! (getDialect() instanceof Oracle9Dialect) ) {
+		
+			result = s.createQuery("from Transaction txn where txn.value = (1.5, 'AUD')").list();
+			assertEquals( result.size(), 1 );
+			result = s.createQuery("from Transaction where value = (1.5, 'AUD')").list();
+			assertEquals( result.size(), 1 );
+			
+		}
+		
+		s.delete(tran);
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/CompositeUserTypeTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/MonetoryAmount.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/MonetoryAmount.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/MonetoryAmount.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: MonetoryAmount.java 6234 2005-03-29 03:07:30Z oneovthafew $
+package org.hibernate.test.cut;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Currency;
+
+/**
+ * @author Gavin King
+ */
+public class MonetoryAmount implements Serializable {
+
+	private BigDecimal amount;
+	private Currency currency;
+	
+	public MonetoryAmount(BigDecimal amount, Currency currency) {
+		this.amount = amount;
+		this.currency = currency;
+	}
+	
+	public BigDecimal getAmount() {
+		return amount;
+	}
+	
+	public void setAmount(BigDecimal amount) {
+		this.amount = amount;
+	}
+
+	public Currency getCurrency() {
+		return currency;
+	}
+
+	public void setCurrency(Currency currency) {
+		this.currency = currency;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/MonetoryAmount.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/MonetoryAmountUserType.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/MonetoryAmountUserType.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/MonetoryAmountUserType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,104 @@
+//$Id: MonetoryAmountUserType.java 6235 2005-03-29 03:17:49Z oneovthafew $
+package org.hibernate.test.cut;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Currency;
+
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+import org.hibernate.usertype.CompositeUserType;
+
+/**
+ * @author Gavin King
+ */
+public class MonetoryAmountUserType implements CompositeUserType {
+
+	public String[] getPropertyNames() {
+		return new String[] { "amount", "currency" };
+	}
+
+	public Type[] getPropertyTypes() {
+		return new Type[] { Hibernate.BIG_DECIMAL, Hibernate.CURRENCY };
+	}
+
+	public Object getPropertyValue(Object component, int property) throws HibernateException {
+		MonetoryAmount ma = (MonetoryAmount) component;
+		return property==0 ? (Object) ma.getAmount() : (Object) ma.getCurrency();
+	}
+
+	public void setPropertyValue(Object component, int property, Object value)
+			throws HibernateException {
+		MonetoryAmount ma = (MonetoryAmount) component;
+		if ( property==0 ) {
+			ma.setAmount( (BigDecimal) value );
+		}
+		else {
+			ma.setCurrency( (Currency) value );
+		}
+	}
+
+	public Class returnedClass() {
+		return MonetoryAmount.class;
+	}
+
+	public boolean equals(Object x, Object y) throws HibernateException {
+		if (x==y) return true;
+		if (x==null || y==null) return false;
+		MonetoryAmount mx = (MonetoryAmount) x;
+		MonetoryAmount my = (MonetoryAmount) y;
+		return mx.getAmount().equals( my.getAmount() ) &&
+			mx.getCurrency().equals( my.getCurrency() );
+	}
+
+	public int hashCode(Object x) throws HibernateException {
+		return ( (MonetoryAmount) x ).getAmount().hashCode();
+	}
+
+	public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
+			throws HibernateException, SQLException {
+		BigDecimal amt = (BigDecimal) Hibernate.BIG_DECIMAL.nullSafeGet( rs, names[0] );
+		Currency cur = (Currency) Hibernate.CURRENCY.nullSafeGet( rs, names[1] );
+		if (amt==null) return null;
+		return new MonetoryAmount(amt, cur);
+	}
+
+	public void nullSafeSet(PreparedStatement st, Object value, int index,
+			SessionImplementor session) throws HibernateException, SQLException {
+		MonetoryAmount ma = (MonetoryAmount) value;
+		BigDecimal amt = ma == null ? null : ma.getAmount();
+		Currency cur = ma == null ? null : ma.getCurrency();
+		Hibernate.BIG_DECIMAL.nullSafeSet(st, amt, index);
+		Hibernate.CURRENCY.nullSafeSet(st, cur, index+1);
+	}
+
+	public Object deepCopy(Object value) throws HibernateException {
+		MonetoryAmount ma = (MonetoryAmount) value;
+		return new MonetoryAmount( ma.getAmount(), ma.getCurrency() );
+	}
+
+	public boolean isMutable() {
+		return true;
+	}
+
+	public Serializable disassemble(Object value, SessionImplementor session)
+			throws HibernateException {
+		return (Serializable) deepCopy(value);
+	}
+
+	public Object assemble(Serializable cached, SessionImplementor session, Object owner)
+			throws HibernateException {
+		return deepCopy(cached);
+	}
+
+	public Object replace(Object original, Object target, SessionImplementor session, Object owner)
+			throws HibernateException {
+		return deepCopy(original); //TODO: improve
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/MonetoryAmountUserType.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/Transaction.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/Transaction.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/Transaction.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+  Demonstrates the use of a CompositeUserType.
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.cut">
+
+    <class name="Transaction" table="Trnsctn">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="description" length="100" not-null="true"/>
+		<property name="value" type="money">
+			<column name="amount" not-null="true"/>
+			<column name="currency" not-null="true"/>
+		</property>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/Transaction.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/Transaction.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/Transaction.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/Transaction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: Transaction.java 6234 2005-03-29 03:07:30Z oneovthafew $
+package org.hibernate.test.cut;
+
+/**
+ * @author Gavin King
+ */
+public class Transaction {
+
+	private Long id;
+	private String description;
+	private MonetoryAmount value;
+	
+	public String getDescription() {
+		return description;
+	}
+	
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	
+	public Long getId() {
+		return id;
+	}
+	
+	public void setId(Long id) {
+		this.id = id;
+	}
+	
+	public MonetoryAmount getValue() {
+		return value;
+	}
+	
+	public void setValue(MonetoryAmount value) {
+		this.value = value;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/Transaction.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/types.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/types.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/cut/types.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.cut">
+	<typedef name="money" class="org.hibernate.test.cut.MonetoryAmountUserType"/>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+package org.hibernate.test.deletetransient;
+
+/**
+ * todo: describe Address
+ *
+ * @author Steve Ebersole
+ */
+public class Address {
+	private Long id;
+	private String info;
+
+	public Address() {
+	}
+
+	public Address(String info) {
+		this.info = info;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getInfo() {
+		return info;
+	}
+
+	public void setInfo(String info) {
+		this.info = info;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/DeleteTransientEntityTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/DeleteTransientEntityTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/DeleteTransientEntityTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,108 @@
+package org.hibernate.test.deletetransient;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * todo: describe DeleteTransientEntityTest
+ *
+ * @author Steve Ebersole
+ */
+public class DeleteTransientEntityTest extends FunctionalTestCase {
+	public DeleteTransientEntityTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "deletetransient/Person.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( DeleteTransientEntityTest.class );
+	}
+
+	public void testTransientEntityDeletionNoCascades() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.delete( new Address() );
+		t.commit();
+		s.close();
+	}
+
+	public void testTransientEntityDeletionCascadingToTransientAssociation() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person p = new Person();
+		p.getAddresses().add( new Address() );
+		s.delete( p );
+		t.commit();
+		s.close();
+	}
+
+	public void testTransientEntityDeleteCascadingToCircularity() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person p1 = new Person();
+		Person p2 = new Person();
+		p1.getFriends().add( p2 );
+		p2.getFriends().add( p1 );
+		s.delete( p1 );
+		t.commit();
+		s.close();
+	}
+
+	public void testTransientEntityDeletionCascadingToDetachedAssociation() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Address address = new Address();
+		address.setInfo( "123 Main St." );
+		s.save( address );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Person p = new Person();
+		p.getAddresses().add( address );
+		s.delete( p );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Long count = ( Long ) s.createQuery( "select count(*) from Address" ).list().get( 0 );
+		assertEquals( "delete not cascaded properly across transient entity", 0, count.longValue() );
+		t.commit();
+		s.close();
+	}
+
+	public void testTransientEntityDeletionCascadingToPersistentAssociation() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Address address = new Address();
+		address.setInfo( "123 Main St." );
+		s.save( address );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		address = ( Address ) s.get( Address.class, address.getId() );
+		Person p = new Person();
+		p.getAddresses().add( address );
+		s.delete( p );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Long count = ( Long ) s.createQuery( "select count(*) from Address" ).list().get( 0 );
+		assertEquals( "delete not cascaded properly across transient entity", 0, count.longValue() );
+		t.commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.deletetransient">
+	
+	<class name="Person" table="T_PERSON">
+        <id name="id" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="name" type="string"/>
+        <set name="addresses" lazy="true" inverse="false" cascade="all">
+            <key column="PERSON_ID"/>
+            <one-to-many class="Address"/>
+        </set>
+        <bag name="friends" lazy="true" inverse="false" cascade="all" table="T_FRIENDS">
+            <key column="FRIEND_ID_1"/>
+            <many-to-many class="Person" column="FRIEND_ID_2"/>
+        </bag>
+    </class>
+
+    <class name="Address" table="T_ADDRESS">
+        <id name="id" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="info" type="string"/>
+    </class>
+	
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/deletetransient/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+package org.hibernate.test.deletetransient;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collection;
+import java.util.ArrayList;
+
+/**
+ * todo: describe Person
+ *
+ * @author Steve Ebersole
+ */
+public class Person {
+	private Long id;
+	private String name;
+	private Set addresses = new HashSet();
+	private Collection friends = new ArrayList();
+
+	public Person() {
+	}
+
+	public Person(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Set getAddresses() {
+		return addresses;
+	}
+
+	public void setAddresses(Set addresses) {
+		this.addresses = addresses;
+	}
+
+	public Collection getFriends() {
+		return friends;
+	}
+
+	public void setFriends(Collection friends) {
+		this.friends = friends;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/DialectFunctionalTestsSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/DialectFunctionalTestsSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/DialectFunctionalTestsSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+package org.hibernate.test.dialect.functional;
+
+import junit.framework.TestSuite;
+
+import org.hibernate.test.dialect.functional.cache.SQLFunctionsInterSystemsTest;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class DialectFunctionalTestsSuite {
+	public static TestSuite suite() {
+		TestSuite suite = new TestSuite( "Dialect tests" );
+		suite.addTest( SQLFunctionsInterSystemsTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/cache/SQLFunctionsInterSystemsTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/cache/SQLFunctionsInterSystemsTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/cache/SQLFunctionsInterSystemsTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,740 @@
+package org.hibernate.test.dialect.functional.cache;
+
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.Query;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.dialect.Cache71Dialect;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.InterbaseDialect;
+import org.hibernate.dialect.MckoiDialect;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.dialect.SybaseDialect;
+import org.hibernate.dialect.TimesTenDialect;
+import org.hibernate.dialect.function.SQLFunction;
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.legacy.Blobber;
+import org.hibernate.test.legacy.Broken;
+import org.hibernate.test.legacy.Fixed;
+import org.hibernate.test.legacy.Simple;
+import org.hibernate.test.legacy.Single;
+
+/**
+ * Tests for function support on CacheSQL...
+ *
+ * @author Jonathan Levinson
+ */
+public class SQLFunctionsInterSystemsTest extends DatabaseSpecificFunctionalTestCase {
+
+	private static final Log log = LogFactory.getLog(SQLFunctionsInterSystemsTest.class);
+
+	public SQLFunctionsInterSystemsTest(String name) {
+		super(name);
+	}
+
+	public String[] getMappings() {
+		return new String[] {
+				"legacy/AltSimple.hbm.xml",
+				"legacy/Broken.hbm.xml",
+				"legacy/Blobber.hbm.xml",
+				"dialect/cache/TestInterSystemsFunctionsClass.hbm.xml"
+		};
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SQLFunctionsInterSystemsTest.class );
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		// all these test case apply only to testing InterSystems' CacheSQL dialect
+		return dialect instanceof Cache71Dialect;
+	}
+
+	public void testDialectSQLFunctions() throws Exception {
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Iterator iter = s.iterate("select max(s.count) from Simple s");
+
+		if ( getDialect() instanceof MySQLDialect ) assertTrue( iter.hasNext() && iter.next()==null );
+
+		Simple simple = new Simple();
+		simple.setName("Simple Dialect Function Test");
+		simple.setAddress("Simple Address");
+		simple.setPay(new Float(45.8));
+		simple.setCount(2);
+		s.save(simple, new Long(10) );
+
+		// Test to make sure allocating an specified object operates correctly.
+		assertTrue(
+			s.find("select new org.hibernate.test.legacy.S(s.count, s.address) from Simple s").size() == 1
+		);
+
+		// Quick check the base dialect functions operate correctly
+		assertTrue(
+			s.find("select max(s.count) from Simple s").size() == 1
+		);
+		assertTrue(
+			s.find("select count(*) from Simple s").size() == 1
+		);
+
+		if ( getDialect() instanceof Cache71Dialect) {
+			// Check Oracle Dialect mix of dialect functions - no args (no parenthesis and single arg functions
+			java.util.List rset = s.find("select s.name, sysdate, floor(s.pay), round(s.pay,0) from Simple s");
+			assertNotNull("Name string should have been returned",(((Object[])rset.get(0))[0]));
+			assertNotNull("Todays Date should have been returned",(((Object[])rset.get(0))[1]));
+			assertEquals("floor(45.8) result was incorrect ", new Integer(45), ( (Object[]) rset.get(0) )[2] );
+			assertEquals("round(45.8) result was incorrect ", new Float(46), ( (Object[]) rset.get(0) )[3] );
+
+			simple.setPay(new Float(-45.8));
+			s.update(simple);
+
+			// Test type conversions while using nested functions (Float to Int).
+			rset = s.find("select abs(round(s.pay,0)) from Simple s");
+			assertEquals("abs(round(-45.8)) result was incorrect ", new Float(46), rset.get(0));
+
+			// Test a larger depth 3 function example - Not a useful combo other than for testing
+			assertTrue(
+				s.find("select floor(round(sysdate,1)) from Simple s").size() == 1
+			);
+
+			// Test the oracle standard NVL funtion as a test of multi-param functions...
+			simple.setPay(null);
+			s.update(simple);
+			Double value = (Double) s.createQuery("select mod( nvl(s.pay, 5000), 2 ) from Simple as s where s.id = 10").list().get(0);
+			assertTrue( 0 == value.intValue() );
+		}
+
+		if ( (getDialect() instanceof Cache71Dialect) ) {
+			// Test the hsql standard MOD funtion as a test of multi-param functions...
+			Double value = (Double) s.find("select MOD(s.count, 2) from Simple as s where s.id = 10" ).get(0);
+			assertTrue( 0 == value.intValue() );
+        }
+
+        /*
+        if ( (getDialect() instanceof Cache71Dialect) ) {
+            // Test the hsql standard MOD funtion as a test of multi-param functions...
+            Date value = (Date) s.find("select sysdate from Simple as s where nvl(cast(null as date), sysdate)=sysdate" ).get(0);
+            assertTrue( value.equals(new java.sql.Date(System.currentTimeMillis())));
+        }
+        */
+
+        s.delete(simple);
+		t.commit();
+		s.close();
+	}
+
+	public void testSetProperties() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save(simple, new Long(10) );
+		Query q = s.createQuery("from Simple s where s.name=:name and s.count=:count");
+		q.setProperties(simple);
+		assertTrue( q.list().get(0)==simple );
+		//misuse of "Single" as a propertyobject, but it was the first testclass i found with a collection ;)
+		Single single = new Single() { // trivial hack to test properties with arrays.
+			String[] getStuff() { return (String[]) getSeveral().toArray(new String[getSeveral().size()]); }
+		};
+
+		List l = new ArrayList();
+		l.add("Simple 1");
+		l.add("Slimeball");
+		single.setSeveral(l);
+		q = s.createQuery("from Simple s where s.name in (:several)");
+		q.setProperties(single);
+		assertTrue( q.list().get(0)==simple );
+
+
+		q = s.createQuery("from Simple s where s.name in (:stuff)");
+		q.setProperties(single);
+		assertTrue( q.list().get(0)==simple );
+		s.delete(simple);
+		t.commit();
+		s.close();
+	}
+
+	public void testBroken() throws Exception {
+		if (getDialect() instanceof Oracle9Dialect) return;
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Broken b = new Fixed();
+		b.setId( new Long(123));
+		b.setOtherId("foobar");
+		s.save(b);
+		s.flush();
+		b.setTimestamp( new Date() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update(b);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		b = (Broken) s.load( Broken.class, b );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete(b);
+		t.commit();
+		s.close();
+	}
+
+	public void testNothinToUpdate() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save( simple, new Long(10) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update( simple, new Long(10) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update( simple, new Long(10) );
+		s.delete(simple);
+		t.commit();
+		s.close();
+	}
+
+	public void testCachedQuery() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save( simple, new Long(10) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Query q = s.createQuery("from Simple s where s.name=?");
+		q.setCacheable(true);
+		q.setString(0, "Simple 1");
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.list().size()==1 );
+		q = s.createQuery("from Simple s where s.name=:name");
+		q.setCacheable(true);
+		q.setString("name", "Simple 1");
+		assertTrue( q.list().size()==1 );
+		simple = (Simple) q.list().get(0);
+
+		q.setString("name", "Simple 2");
+		assertTrue( q.list().size()==0 );
+		assertTrue( q.list().size()==0 );
+		simple.setName("Simple 2");
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.list().size()==1 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		q = s.createQuery("from Simple s where s.name=:name");
+		q.setString("name", "Simple 2");
+		q.setCacheable(true);
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.list().size()==1 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update( simple, new Long(10) );
+		s.delete(simple);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		q = s.createQuery("from Simple s where s.name=?");
+		q.setCacheable(true);
+		q.setString(0, "Simple 1");
+		assertTrue( q.list().size()==0 );
+		assertTrue( q.list().size()==0 );
+		t.commit();
+		s.close();
+	}
+
+	public void testCachedQueryRegion() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save( simple, new Long(10) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Query q = s.createQuery("from Simple s where s.name=?");
+		q.setCacheRegion("foo");
+		q.setCacheable(true);
+		q.setString(0, "Simple 1");
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.list().size()==1 );
+		q = s.createQuery("from Simple s where s.name=:name");
+		q.setCacheRegion("foo");
+		q.setCacheable(true);
+		q.setString("name", "Simple 1");
+		assertTrue( q.list().size()==1 );
+		simple = (Simple) q.list().get(0);
+
+		q.setString("name", "Simple 2");
+		assertTrue( q.list().size()==0 );
+		assertTrue( q.list().size()==0 );
+		simple.setName("Simple 2");
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.list().size()==1 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update( simple, new Long(10) );
+		s.delete(simple);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		q = s.createQuery("from Simple s where s.name=?");
+		q.setCacheRegion("foo");
+		q.setCacheable(true);
+		q.setString(0, "Simple 1");
+		assertTrue( q.list().size()==0 );
+		assertTrue( q.list().size()==0 );
+		t.commit();
+		s.close();
+	}
+
+	public void testSQLFunctions() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save(simple, new Long(10) );
+
+		if ( getDialect() instanceof Cache71Dialect) {
+			s.find("from Simple s where repeat('foo', 3) = 'foofoofoo'");
+			s.find("from Simple s where repeat(s.name, 3) = 'foofoofoo'");
+			s.find("from Simple s where repeat( lower(s.name), (3 + (1-1)) / 2) = 'foofoofoo'");
+		}
+
+		assertTrue(
+			s.find("from Simple s where upper( s.name ) ='SIMPLE 1'").size()==1
+		);
+		if ( !(getDialect() instanceof HSQLDialect) ) {
+			assertTrue(
+				s.find("from Simple s where not( upper( s.name ) ='yada' or 1=2 or 'foo'='bar' or not('foo'='foo') or 'foo' like 'bar' )").size()==1
+			);
+		}
+		if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof SybaseDialect) && !(getDialect() instanceof MckoiDialect) && !(getDialect() instanceof InterbaseDialect) && !(getDialect() instanceof TimesTenDialect) ) { //My SQL has a funny concatenation operator
+			assertTrue(
+				s.find("from Simple s where lower( s.name || ' foo' ) ='simple 1 foo'").size()==1
+			);
+		}
+        /* + is not concat in Cache
+        if ( (getDialect() instanceof Cache71Dialect) ) {
+			assertTrue(
+				s.find("from Simple s where lower( cons.name ' foo' ) ='simple 1 foo'").size()==1
+			);
+		}
+		*/
+		if ( (getDialect() instanceof Cache71Dialect) ) {
+			assertTrue(
+				s.find("from Simple s where lower( concat(s.name, ' foo') ) ='simple 1 foo'").size()==1
+			);
+		}
+
+		Simple other = new Simple();
+		other.setName("Simple 2");
+		other.setCount(12);
+		simple.setOther(other);
+		s.save( other, new Long(20) );
+		//s.find("from Simple s where s.name ## 'cat|rat|bag'");
+		assertTrue(
+			s.find("from Simple s where upper( s.other.name ) ='SIMPLE 2'").size()==1
+		);
+		assertTrue(
+			s.find("from Simple s where not ( upper( s.other.name ) ='SIMPLE 2' )").size()==0
+		);
+		assertTrue(
+			s.find("select distinct s from Simple s where ( ( s.other.count + 3 ) = (15*2)/2 and s.count = 69) or ( ( s.other.count + 2 ) / 7 ) = 2").size()==1
+		);
+		assertTrue(
+			s.find("select s from Simple s where ( ( s.other.count + 3 ) = (15*2)/2 and s.count = 69) or ( ( s.other.count + 2 ) / 7 ) = 2 order by s.other.count").size()==1
+		);
+		Simple min = new Simple();
+		min.setCount(-1);
+		s.save(min, new Long(30) );
+		if ( ! (getDialect() instanceof MySQLDialect) && ! (getDialect() instanceof HSQLDialect) ) { //My SQL has no subqueries
+			assertTrue(
+				s.find("from Simple s where s.count > ( select min(sim.count) from Simple sim )").size()==2
+			);
+			t.commit();
+			t = s.beginTransaction();
+			assertTrue(
+				s.find("from Simple s where s = some( select sim from Simple sim where sim.count>=0 ) and s.count >= 0").size()==2
+			);
+			assertTrue(
+				s.find("from Simple s where s = some( select sim from Simple sim where sim.other.count=s.other.count ) and s.other.count > 0").size()==1
+			);
+		}
+
+		Iterator iter = s.iterate("select sum(s.count) from Simple s group by s.count having sum(s.count) > 10");
+		assertTrue( iter.hasNext() );
+		assertEquals( new Long(12), iter.next() );
+		assertTrue( !iter.hasNext() );
+		if ( ! (getDialect() instanceof MySQLDialect) ) {
+			iter = s.iterate("select s.count from Simple s group by s.count having s.count = 12");
+			assertTrue( iter.hasNext() );
+		}
+
+		s.iterate("select s.id, s.count, count(t), max(t.date) from Simple s, Simple t where s.count = t.count group by s.id, s.count order by s.count");
+
+		Query q = s.createQuery("from Simple s");
+		q.setMaxResults(10);
+		assertTrue( q.list().size()==3 );
+		q = s.createQuery("from Simple s");
+		q.setMaxResults(1);
+		assertTrue( q.list().size()==1 );
+		q = s.createQuery("from Simple s");
+		assertTrue( q.list().size()==3 );
+		q = s.createQuery("from Simple s where s.name = ?");
+		q.setString(0, "Simple 1");
+		assertTrue( q.list().size()==1 );
+		q = s.createQuery("from Simple s where s.name = ? and upper(s.name) = ?");
+		q.setString(1, "SIMPLE 1");
+		q.setString(0, "Simple 1");
+		q.setFirstResult(0);
+		assertTrue( q.iterate().hasNext() );
+		q = s.createQuery("from Simple s where s.name = :foo and upper(s.name) = :bar or s.count=:count or s.count=:count + 1");
+		q.setParameter("bar", "SIMPLE 1");
+		q.setString("foo", "Simple 1");
+		q.setInteger("count", 69);
+		q.setFirstResult(0);
+		assertTrue( q.iterate().hasNext() );
+		q = s.createQuery("select s.id from Simple s");
+		q.setFirstResult(1);
+		q.setMaxResults(2);
+		iter = q.iterate();
+		int i=0;
+		while ( iter.hasNext() ) {
+			assertTrue( iter.next() instanceof Long );
+			i++;
+		}
+		assertTrue(i==2);
+		q = s.createQuery("select all s, s.other from Simple s where s = :s");
+		q.setParameter("s", simple);
+		assertTrue( q.list().size()==1 );
+
+
+		q = s.createQuery("from Simple s where s.name in (:name_list) and s.count > :count");
+		HashSet set = new HashSet();
+		set.add("Simple 1"); set.add("foo");
+		q.setParameterList( "name_list", set );
+		q.setParameter("count", new Integer(-1) );
+		assertTrue( q.list().size()==1 );
+
+		ScrollableResults sr = s.createQuery("from Simple s").scroll();
+		sr.next();
+		sr.get(0);
+		sr.close();
+
+		s.delete(other);
+		s.delete(simple);
+		s.delete(min);
+		t.commit();
+		s.close();
+
+	}
+
+	public void testBlobClob() throws Exception {
+
+		Session s = openSession();
+		Blobber b = new Blobber();
+		b.setBlob( Hibernate.createBlob( "foo/bar/baz".getBytes() ) );
+		b.setClob( Hibernate.createClob("foo/bar/baz") );
+		s.save(b);
+		//s.refresh(b);
+		//assertTrue( b.getClob() instanceof ClobImpl );
+		s.flush();
+		s.refresh(b);
+		//b.getBlob().setBytes( 2, "abc".getBytes() );
+        log.debug("levinson: just bfore b.getClob()");
+        b.getClob().getSubString(2, 3);
+		//b.getClob().setString(2, "abc");
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) );
+		Blobber b2 = new Blobber();
+		s.save(b2);
+		b2.setBlob( b.getBlob() );
+		b.setBlob(null);
+		//assertTrue( b.getClob().getSubString(1, 3).equals("fab") );
+		b.getClob().getSubString(1, 6);
+		//b.getClob().setString(1, "qwerty");
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) );
+		b.setClob( Hibernate.createClob("xcvfxvc xcvbx cvbx cvbx cvbxcvbxcvbxcvb") );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) );
+		assertTrue( b.getClob().getSubString(1, 7).equals("xcvfxvc") );
+		//b.getClob().setString(5, "1234567890");
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+
+		/*InputStream is = getClass().getClassLoader().getResourceAsStream("jdbc20.pdf");
+		s = sessionsopenSession();
+		b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) );
+		System.out.println( is.available() );
+		int size = is.available();
+		b.setBlob( Hibernate.createBlob( is, is.available() ) );
+		s.flush();
+		s.connection().commit();
+		ResultSet rs = s.connection().createStatement().executeQuery("select datalength(blob_) from blobber where id=" + b.getId() );
+		rs.next();
+		assertTrue( size==rs.getInt(1) );
+		rs.close();
+		s.close();
+
+		s = sessionsopenSession();
+		b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) );
+		File f = new File("C:/foo.pdf");
+		f.createNewFile();
+		FileOutputStream fos = new FileOutputStream(f);
+		Blob blob = b.getBlob();
+		byte[] bytes = blob.getBytes( 1, (int) blob.length() );
+		System.out.println( bytes.length );
+		fos.write(bytes);
+		fos.flush();
+		fos.close();
+		s.close();*/
+
+	}
+
+	public void testSqlFunctionAsAlias() throws Exception {
+		String functionName = locateAppropriateDialectFunctionNameForAliasTest();
+		if (functionName == null) {
+			log.info("Dialect does not list any no-arg functions");
+			return;
+		}
+
+		log.info("Using function named [" + functionName + "] for 'function as alias' test");
+		String query = "select " + functionName + " from Simple as " + functionName + " where " + functionName + ".id = 10";
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save( simple, new Long(10) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		List result = s.find(query);
+		assertTrue( result.size() == 1 );
+		assertTrue(result.get(0) instanceof Simple);
+		s.delete( result.get(0) );
+		t.commit();
+		s.close();
+	}
+
+	private String locateAppropriateDialectFunctionNameForAliasTest() {
+		for (Iterator itr = getDialect().getFunctions().entrySet().iterator(); itr.hasNext(); ) {
+			final Map.Entry entry = (Map.Entry) itr.next();
+			final SQLFunction function = (SQLFunction) entry.getValue();
+			if ( !function.hasArguments() && !function.hasParenthesesIfNoArguments() ) {
+				return (String) entry.getKey();
+			}
+		}
+		return null;
+	}
+
+	public void testCachedQueryOnInsert() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save( simple, new Long(10) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Query q = s.createQuery("from Simple s");
+		List list = q.setCacheable(true).list();
+		assertTrue( list.size()==1 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		q = s.createQuery("from Simple s");
+		list = q.setCacheable(true).list();
+		assertTrue( list.size()==1 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Simple simple2 = new Simple();
+		simple2.setCount(133);
+		s.save( simple2, new Long(12) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		q = s.createQuery("from Simple s");
+		list = q.setCacheable(true).list();
+		assertTrue( list.size()==2 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		q = s.createQuery("from Simple s");
+		list = q.setCacheable(true).list();
+		assertTrue( list.size()==2 );
+		Iterator i = list.iterator();
+		while ( i.hasNext() ) s.delete( i.next() );
+		t.commit();
+		s.close();
+
+	}
+
+    public void testInterSystemsFunctions() throws Exception {
+        Calendar cal = new GregorianCalendar();
+        cal.set(1977,6,3,0,0,0);
+        java.sql.Timestamp testvalue = new java.sql.Timestamp(cal.getTimeInMillis());
+        testvalue.setNanos(0);
+        Calendar cal3 = new GregorianCalendar();
+        cal3.set(1976,2,3,0,0,0);
+        java.sql.Timestamp testvalue3 = new java.sql.Timestamp(cal3.getTimeInMillis());
+        testvalue3.setNanos(0);
+
+        Session s = openSession();
+        Transaction t = s.beginTransaction();
+        try {
+            Statement stmt = s.connection().createStatement();
+            stmt.executeUpdate("DROP FUNCTION spLock FROM TestInterSystemsFunctionsClass");
+            t.commit();
+        }
+        catch (Exception ex) {
+            System.out.println("as we expected stored procedure sp does not exist when we drop it");
+
+        }
+        t = s.beginTransaction();
+        Statement stmt = s.connection().createStatement();
+        String create_function = "CREATE FUNCTION SQLUser.TestInterSystemsFunctionsClass_spLock\n" +
+                "     ( INOUT pHandle %SQLProcContext, \n" +
+                "       ROWID INTEGER \n" +
+                " )\n" +
+                " FOR User.TestInterSystemsFunctionsClass " +
+                "    PROCEDURE\n" +
+                "    RETURNS INTEGER\n" +
+                "    LANGUAGE OBJECTSCRIPT\n" +
+                "    {\n" +
+                "        q 0\n" +
+                "     }";
+        stmt.executeUpdate(create_function);
+        t.commit();
+        t = s.beginTransaction();
+
+        TestInterSystemsFunctionsClass object = new TestInterSystemsFunctionsClass();
+        object.setDateText("1977-07-03");
+        object.setDate1(testvalue);
+        object.setDate3(testvalue3);
+        s.save( object, new Long(10));
+        t.commit();
+        s.close();
+        s = openSession();
+        s.clear();
+        t = s.beginTransaction();
+        TestInterSystemsFunctionsClass test = (TestInterSystemsFunctionsClass) s.get(TestInterSystemsFunctionsClass.class, new Long(10));
+        assertTrue( test.getDate1().equals(testvalue));
+        test = (TestInterSystemsFunctionsClass) s.get(TestInterSystemsFunctionsClass.class, new Long(10), LockMode.UPGRADE);
+        assertTrue( test.getDate1().equals(testvalue));
+        Date value = (Date) s.find("select nvl(o.date,o.dateText) from TestInterSystemsFunctionsClass as o" ).get(0);
+        assertTrue( value.equals(testvalue));
+        Object nv = s.find("select nullif(o.dateText,o.dateText) from TestInterSystemsFunctionsClass as o" ).get(0);
+        assertTrue( nv == null);
+        String dateText = (String) s.find("select nvl(o.dateText,o.date) from TestInterSystemsFunctionsClass as o" ).get(0);
+        assertTrue( dateText.equals("1977-07-03"));
+        value = (Date) s.find("select ifnull(o.date,o.date1) from TestInterSystemsFunctionsClass as o" ).get(0);
+        assertTrue( value.equals(testvalue));
+        value = (Date) s.find("select ifnull(o.date3,o.date,o.date1) from TestInterSystemsFunctionsClass as o" ).get(0);
+        assertTrue( value.equals(testvalue));
+        Integer pos = (Integer) s.find("select position('07', o.dateText) from TestInterSystemsFunctionsClass as o" ).get(0);
+        assertTrue(pos.intValue() == 6);
+        String st = (String) s.find("select convert(o.date1, SQL_TIME) from TestInterSystemsFunctionsClass as o" ).get(0);
+        assertTrue( st.equals("00:00:00"));
+        java.sql.Time tm = (java.sql.Time) s.find("select cast(o.date1, time) from TestInterSystemsFunctionsClass as o" ).get(0);
+        assertTrue( tm.toString().equals("00:00:00"));
+        Double diff = (Double)s.find("select timestampdiff(SQL_TSI_FRAC_SECOND, o.date3, o.date1) from TestInterSystemsFunctionsClass as o" ).get(0);
+        assertTrue(diff.doubleValue() != 0.0);
+        diff = (Double)s.find("select timestampdiff(SQL_TSI_MONTH, o.date3, o.date1) from TestInterSystemsFunctionsClass as o" ).get(0);
+        assertTrue(diff.doubleValue() == 16.0);
+        diff = (Double)s.find("select timestampdiff(SQL_TSI_WEEK, o.date3, o.date1) from TestInterSystemsFunctionsClass as o" ).get(0);
+        assertTrue(diff.doubleValue() >= 16*4);
+        diff = (Double)s.find("select timestampdiff(SQL_TSI_YEAR, o.date3, o.date1) from TestInterSystemsFunctionsClass as o" ).get(0);
+        assertTrue(diff.doubleValue() == 1.0);
+
+        t.commit();
+        s.close();
+
+
+    }
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/cache/TestInterSystemsFunctionsClass.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/cache/TestInterSystemsFunctionsClass.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/cache/TestInterSystemsFunctionsClass.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.dialect.functional.cache" >
+
+    <class name="TestInterSystemsFunctionsClass" table="SQLUser.TestInterSystemsFunctionsClass">
+        <id type="long" column="id_">
+            <generator class="assigned"/>
+        </id>
+        <property name="date" column="date_"/>
+        <property name="date1" column="date1_"/>
+        <property name="date3" column="date3_"/>
+        <property name="dateText" column="dateText_"/>
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/cache/TestInterSystemsFunctionsClass.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/cache/TestInterSystemsFunctionsClass.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/functional/cache/TestInterSystemsFunctionsClass.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+package org.hibernate.test.dialect.functional.cache;
+
+import java.util.Date;
+
+/**
+ * Entity for testing function support of InterSystems' CacheSQL...
+ *
+ * @author Jonathan Levinson
+ */
+public class TestInterSystemsFunctionsClass {
+    private java.util.Date date3;
+    private java.util.Date date1;
+    private java.util.Date date;
+    private String dateText;
+
+	public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+
+    public String getDateText() {
+        return dateText;
+    }
+
+    public void setDateText(String dateText) {
+        this.dateText = dateText;
+    }
+
+
+    public Date getDate1() {
+        return date1;
+    }
+
+    public void setDate1(Date date1) {
+        this.date1 = date1;
+    }
+
+
+    public Date getDate3() {
+        return date3;
+    }
+
+    public void setDate3(Date date3) {
+        this.date3 = date3;
+    }
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/DialectUnitTestsSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/DialectUnitTestsSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/DialectUnitTestsSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+package org.hibernate.test.dialect.unit;
+
+import junit.framework.TestSuite;
+
+import org.hibernate.test.dialect.unit.lockhint.SybaseLockHintsTest;
+import org.hibernate.test.dialect.unit.lockhint.SQLServerLockHintsTest;
+
+/**
+ * Suite of all unit tests of the Dialect(s).
+ *
+ * @author Steve Ebersole
+ */
+public class DialectUnitTestsSuite {
+	public static TestSuite suite() {
+		TestSuite suite = new TestSuite( "Dialect unit-tests" );
+		suite.addTest( SybaseLockHintsTest.suite() );
+		suite.addTest( SQLServerLockHintsTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/lockhint/AbstractLockHintTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/lockhint/AbstractLockHintTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/lockhint/AbstractLockHintTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+package org.hibernate.test.dialect.unit.lockhint;
+
+import java.util.HashMap;
+import java.util.Collections;
+
+import org.hibernate.junit.UnitTestCase;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.util.StringHelper;
+import org.hibernate.LockMode;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractLockHintTest extends UnitTestCase {
+	public AbstractLockHintTest(String string) {
+		super( string );
+	}
+
+	private Dialect dialect;
+
+	protected abstract String getLockHintUsed();
+	protected abstract Dialect getDialectUnderTest();
+
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.dialect = getDialectUnderTest();
+	}
+
+	protected void tearDown() throws Exception {
+		this.dialect = null;
+		super.tearDown();
+	}
+
+	public void testBasicLocking() {
+		new SyntaxChecker( "select xyz from ABC $HOLDER$", "a" ).verify();
+		new SyntaxChecker( "select xyz from ABC $HOLDER$ join DEF d", "a" ).verify();
+		new SyntaxChecker( "select xyz from ABC $HOLDER$, DEF d", "a" ).verify();
+	}
+
+	protected class SyntaxChecker {
+		private final String aliasToLock;
+		private final String rawSql;
+		private final String expectedProcessedSql;
+
+		public SyntaxChecker(String template) {
+			this( template, "" );
+		}
+
+		public SyntaxChecker(String template, String aliasToLock) {
+			this.aliasToLock = aliasToLock;
+			rawSql = StringHelper.replace( template, "$HOLDER$", aliasToLock );
+			expectedProcessedSql = StringHelper.replace( template, "$HOLDER$", aliasToLock + " " + getLockHintUsed() );
+		}
+
+		public void verify() {
+			HashMap lockModes = new HashMap();
+			lockModes.put( aliasToLock, LockMode.UPGRADE );
+			String actualProcessedSql = dialect.applyLocksToSql( rawSql, lockModes, Collections.EMPTY_MAP );
+			assertEquals( expectedProcessedSql, actualProcessedSql );
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/lockhint/SQLServerLockHintsTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/lockhint/SQLServerLockHintsTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/lockhint/SQLServerLockHintsTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+package org.hibernate.test.dialect.unit.lockhint;
+
+import junit.framework.TestSuite;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.SQLServerDialect;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class SQLServerLockHintsTest extends AbstractLockHintTest {
+	public static final Dialect DIALECT = new SQLServerDialect();
+
+	public SQLServerLockHintsTest(String string) {
+		super( string );
+	}
+
+	protected String getLockHintUsed() {
+		return "with (updlock, rowlock)";
+	}
+
+	protected Dialect getDialectUnderTest() {
+		return DIALECT;
+	}
+
+	public static TestSuite suite() {
+		return new TestSuite( SQLServerLockHintsTest.class );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/lockhint/SybaseLockHintsTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/lockhint/SybaseLockHintsTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dialect/unit/lockhint/SybaseLockHintsTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+package org.hibernate.test.dialect.unit.lockhint;
+
+import junit.framework.TestSuite;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.SybaseDialect;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class SybaseLockHintsTest extends AbstractLockHintTest {
+	public static final Dialect DIALECT = new SybaseDialect();
+
+	public SybaseLockHintsTest(String string) {
+		super( string );
+	}
+
+	protected String getLockHintUsed() {
+		return "holdlock";
+	}
+
+	protected Dialect getDialectUnderTest() {
+		return DIALECT;
+	}
+
+	public static TestSuite suite() {
+		return new TestSuite( SybaseLockHintsTest.class );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,11 @@
+//$Id: Address.java 4373 2004-08-18 09:18:34Z oneovthafew $
+package org.hibernate.test.discriminator;
+
+/**
+ * @author Gavin King
+ */
+public class Address {
+	public String address;
+	public String zip;
+	public String country;
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Address.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: Customer.java 4373 2004-08-18 09:18:34Z oneovthafew $
+package org.hibernate.test.discriminator;
+
+/**
+ * @author Gavin King
+ */
+public class Customer extends Person {
+	private Employee salesperson;
+	private String comments;
+
+	/**
+	 * @return Returns the salesperson.
+	 */
+	public Employee getSalesperson() {
+		return salesperson;
+	}
+	/**
+	 * @param salesperson The salesperson to set.
+	 */
+	public void setSalesperson(Employee salesperson) {
+		this.salesperson = salesperson;
+	}
+	/**
+	 * @return Returns the comments.
+	 */
+	public String getComments() {
+		return comments;
+	}
+	/**
+	 * @param comments The comments to set.
+	 */
+	public void setComments(String comments) {
+		this.comments = comments;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Customer.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/DiscriminatorTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/DiscriminatorTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/DiscriminatorTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,176 @@
+//$Id: DiscriminatorTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.discriminator;
+
+import java.math.BigDecimal;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.criterion.Property;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class DiscriminatorTest extends FunctionalTestCase {
+
+	public DiscriminatorTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "discriminator/Person.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( DiscriminatorTest.class );
+	}
+
+	public void testDiscriminatorSubclass() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Employee mark = new Employee();
+		mark.setName("Mark");
+		mark.setTitle("internal sales");
+		mark.setSex('M');
+		mark.setAddress("buckhead");
+		mark.setZip("30305");
+		mark.setCountry("USA");
+
+		Customer joe = new Customer();
+		joe.setName("Joe");
+		joe.setAddress("San Francisco");
+		joe.setZip("XXXXX");
+		joe.setCountry("USA");
+		joe.setComments("Very demanding");
+		joe.setSex('M');
+		joe.setSalesperson(mark);
+
+		Person yomomma = new Person();
+		yomomma.setName("mum");
+		yomomma.setSex('F');
+
+		s.save(yomomma);
+		s.save(mark);
+		s.save(joe);
+
+		assertEquals( s.createQuery("from java.io.Serializable").list().size(), 0 );
+
+		assertEquals( s.createQuery("from Person").list().size(), 3 );
+		assertEquals( s.createQuery("from Person p where p.class = Person").list().size(), 1 );
+		assertEquals( s.createQuery("from Person p where p.class = Customer").list().size(), 1 );
+		s.clear();
+
+		List customers = s.createQuery("from Customer c left join fetch c.salesperson").list();
+		for ( Iterator iter = customers.iterator(); iter.hasNext(); ) {
+			Customer c = (Customer) iter.next();
+			assertTrue( Hibernate.isInitialized( c.getSalesperson() ) );
+			assertEquals( c.getSalesperson().getName(), "Mark" );
+		}
+		assertEquals( customers.size(), 1 );
+		s.clear();
+
+		customers = s.createQuery("from Customer").list();
+		for ( Iterator iter = customers.iterator(); iter.hasNext(); ) {
+			Customer c = (Customer) iter.next();
+			assertFalse( Hibernate.isInitialized( c.getSalesperson() ) );
+			assertEquals( c.getSalesperson().getName(), "Mark" );
+		}
+		assertEquals( customers.size(), 1 );
+		s.clear();
+
+
+		mark = (Employee) s.get( Employee.class, new Long( mark.getId() ) );
+		joe = (Customer) s.get( Customer.class, new Long( joe.getId() ) );
+
+ 		mark.setZip("30306");
+		assertEquals( s.createQuery("from Person p where p.address.zip = '30306'").list().size(), 1 );
+		s.delete(mark);
+		s.delete(joe);
+		s.delete(yomomma);
+		assertTrue( s.createQuery("from Person").list().isEmpty() );
+		t.commit();
+		s.close();
+	}
+
+	public void testAccessAsIncorrectSubclass() {
+		Session s = openSession();
+		s.beginTransaction();
+		Employee e = new Employee();
+		e.setName( "Steve" );
+		e.setSex( 'M' );
+		e.setTitle( "grand poobah" );
+		s.save( e );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		Customer c = ( Customer ) s.get( Customer.class, new Long( e.getId() ) );
+		s.getTransaction().commit();
+		s.close();
+		assertNull( c );
+
+		s = openSession();
+		s.beginTransaction();
+		e = ( Employee ) s.get( Employee.class, new Long( e.getId() ) );
+		c = ( Customer ) s.get( Customer.class, new Long( e.getId() ) );
+		s.getTransaction().commit();
+		s.close();
+		assertNotNull( e );
+		assertNull( c );
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( e );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testQuerySubclassAttribute() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person p = new Person();
+		p.setName("Emmanuel");
+		p.setSex('M');
+		s.persist(p);
+		Employee q = new Employee();
+		q.setName("Steve");
+		q.setSex('M');
+		q.setTitle("Mr");
+		q.setSalary( new BigDecimal(1000) );
+		s.persist(q);
+
+		List result = s.createQuery("from Person where salary > 100").list();
+		assertEquals( result.size(), 1 );
+		assertSame( result.get(0), q );
+
+		result = s.createQuery("from Person where salary > 100 or name like 'E%'").list();
+		assertEquals( result.size(), 2 );
+
+		result = s.createCriteria(Person.class)
+			.add( Property.forName("salary").gt( new BigDecimal(100) ) )
+			.list();
+		assertEquals( result.size(), 1 );
+		assertSame( result.get(0), q );
+
+		//TODO: make this work:
+		/*result = s.createQuery("select salary from Person where salary > 100").list();
+		assertEquals( result.size(), 1 );
+		assertEquals( result.get(0), new BigDecimal(1000) );*/
+
+		s.delete(p);
+		s.delete(q);
+		t.commit();
+		s.close();
+	}
+
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/DiscriminatorTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Employee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Employee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Employee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: Employee.java 4373 2004-08-18 09:18:34Z oneovthafew $
+package org.hibernate.test.discriminator;
+
+import java.math.BigDecimal;
+
+/**
+ * @author Gavin King
+ */
+public class Employee extends Person {
+	private String title;
+	private BigDecimal salary;
+	private Employee manager;
+	/**
+	 * @return Returns the title.
+	 */
+	public String getTitle() {
+		return title;
+	}
+	/**
+	 * @param title The title to set.
+	 */
+	public void setTitle(String title) {
+		this.title = title;
+	}
+	/**
+	 * @return Returns the manager.
+	 */
+	public Employee getManager() {
+		return manager;
+	}
+	/**
+	 * @param manager The manager to set.
+	 */
+	public void setManager(Employee manager) {
+		this.manager = manager;
+	}
+	/**
+	 * @return Returns the salary.
+	 */
+	public BigDecimal getSalary() {
+		return salary;
+	}
+	/**
+	 * @param salary The salary to set.
+	 */
+	public void setSalary(BigDecimal salary) {
+		this.salary = salary;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Employee.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates content-based discrimination for the
+  table-per-hierarchy mapping strategy, using a formula
+  discriminator.
+
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.discriminator"
+	default-access="field">
+	
+	<class name="Person"
+		discriminator-value="P">
+		
+		<id name="id" 
+			column="person_id" 
+			unsaved-value="0">
+			<generator class="native"/>
+		</id>
+		
+				
+		<discriminator 
+			type="character"
+			formula="case when title is not null then 'E' when salesperson is not null then 'C' else 'P' end"/>
+
+		<property name="name" 
+			not-null="true"
+			length="80"/>
+			
+		<property name="sex" 
+			not-null="true"
+			update="false"/>
+		
+		<component name="address">
+			<property name="address"/>
+			<property name="zip"/>
+			<property name="country"/>
+		</component>
+		
+		<subclass name="Employee" 
+			discriminator-value="E">
+				<property name="title"
+					length="20"/>
+				<property name="salary"
+					length="0"/>
+				<many-to-one name="manager"/>
+		</subclass>
+		
+		<subclass name="Customer" 
+			discriminator-value="C">
+				<property name="comments"/>
+				<many-to-one name="salesperson"/>
+		</subclass>
+		
+	</class>
+	
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Person.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,70 @@
+//$Id: Person.java 4373 2004-08-18 09:18:34Z oneovthafew $
+package org.hibernate.test.discriminator;
+
+
+/**
+ * @author Gavin King
+ */
+public class Person {
+	private long id;
+	private String name;
+	private char sex;
+	private Address address = new Address();
+	/**
+	 * @return Returns the address.
+	 */
+	public Address getAddress() {
+		return address;
+	}
+
+	public void setAddress(String string) {
+		this.address.address = string;
+	}
+
+	public void setZip(String string) {
+		this.address.zip = string;
+	}
+
+	public void setCountry(String string) {
+		this.address.country = string;
+	}
+
+	
+	/**
+	 * @return Returns the sex.
+	 */
+	public char getSex() {
+		return sex;
+	}
+	/**
+	 * @param sex The sex to set.
+	 */
+	public void setSex(char sex) {
+		this.sex = sex;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the identity.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param identity The identity to set.
+	 */
+	public void setName(String identity) {
+		this.name = identity;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/discriminator/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+package org.hibernate.test.dynamicentity;
+
+/**
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public interface Address {
+	public Long getId();
+	public void setId(Long id);
+
+	public String getStreet();
+	public void setStreet(String street);
+
+	public String getCity();
+	public void setCity(String city);
+
+	public String getPostalCode();
+	public void setPostalCode(String postalCode);
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Company.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Company.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Company.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,11 @@
+package org.hibernate.test.dynamicentity;
+
+/**
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public interface Company {
+	public Long getId();
+	public void setId(Long id);
+	public String getName();
+	public void setName(String name);
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+package org.hibernate.test.dynamicentity;
+
+/**
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public interface Customer extends Person {
+	public Company getCompany();
+	public void setCompany(Company company);
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/DataProxyHandler.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/DataProxyHandler.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/DataProxyHandler.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+package org.hibernate.test.dynamicentity;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.io.Serializable;
+
+/**
+ * A simple {@link InvocationHandler} to act as the handler for our generated
+ * {@link java.lang.reflect.Proxy}-based entity instances.
+ * <p/>
+ * This is a trivial impl which simply keeps the property values into
+ * a Map.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public final class DataProxyHandler implements InvocationHandler {
+	private String entityName;
+	private HashMap data = new HashMap();
+
+	public DataProxyHandler(String entityName, Serializable id) {
+		this.entityName = entityName;
+		data.put( "Id", id );
+	}
+
+	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+		String methodName = method.getName();
+		if ( methodName.startsWith( "set" ) ) {
+			String propertyName = methodName.substring( 3 );
+			data.put( propertyName, args[0] );
+		}
+		else if ( methodName.startsWith( "get" ) ) {
+			String propertyName = methodName.substring( 3 );
+			return data.get( propertyName );
+		}
+		else if ( "toString".equals( methodName ) ) {
+			return entityName + "#" + data.get( "Id" );
+		}
+		else if ( "hashCode".equals( methodName ) ) {
+			return new Integer( this.hashCode() );
+		}
+		return null;
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public HashMap getData() {
+		return data;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/DynamicEntitySuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/DynamicEntitySuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/DynamicEntitySuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+package org.hibernate.test.dynamicentity;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.dynamicentity.interceptor.InterceptorDynamicEntityTest;
+import org.hibernate.test.dynamicentity.tuplizer.TuplizerDynamicEntityTest;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class DynamicEntitySuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "dynamic entity suite" );
+		suite.addTest( InterceptorDynamicEntityTest.suite() );
+		suite.addTest( TuplizerDynamicEntityTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+package org.hibernate.test.dynamicentity;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public interface Person {
+	public Long getId();
+	public void setId(Long id);
+	public String getName();
+	public void setName(String name);
+	public Address getAddress();
+	public void setAddress(Address address);
+	public Set getFamily();
+	public void setFamily(Set family);
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/ProxyHelper.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/ProxyHelper.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/ProxyHelper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,73 @@
+package org.hibernate.test.dynamicentity;
+
+import java.io.Serializable;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.InvocationHandler;
+
+/**
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class ProxyHelper {
+
+	public static Person newPersonProxy() {
+		return newPersonProxy( null );
+	}
+
+	public static Person newPersonProxy(Serializable id) {
+		return ( Person ) Proxy.newProxyInstance(
+				Person.class.getClassLoader(),
+		        new Class[] {Person.class},
+		        new DataProxyHandler( Person.class.getName(), id )
+		);
+	}
+
+	public static Customer newCustomerProxy() {
+		return newCustomerProxy( null );
+	}
+
+	public static Customer newCustomerProxy(Serializable id) {
+		return ( Customer ) Proxy.newProxyInstance(
+				Customer.class.getClassLoader(),
+		        new Class[] {Customer.class},
+		        new DataProxyHandler( Customer.class.getName(), id )
+		);
+	}
+
+	public static Company newCompanyProxy() {
+		return newCompanyProxy( null );
+	}
+
+	public static Company newCompanyProxy(Serializable id) {
+		return ( Company ) Proxy.newProxyInstance(
+				Company.class.getClassLoader(),
+		        new Class[] {Company.class},
+		        new DataProxyHandler( Company.class.getName(), id )
+		);
+	}
+
+	public static Address newAddressProxy() {
+		return newAddressProxy( null );
+	}
+
+	public static Address newAddressProxy(Serializable id) {
+		return ( Address ) Proxy.newProxyInstance(
+				Address.class.getClassLoader(),
+		        new Class[] {Address.class},
+		        new DataProxyHandler( Address.class.getName(), id )
+		);
+	}
+
+	public static String extractEntityName(Object object) {
+		// Our custom java.lang.reflect.Proxy instances actually bundle
+		// their appropriate entity name, so we simply extract it from there
+		// if this represents one of our proxies; otherwise, we return null
+		if ( Proxy.isProxyClass( object.getClass() ) ) {
+			InvocationHandler handler = Proxy.getInvocationHandler( object );
+			if ( DataProxyHandler.class.isAssignableFrom( handler.getClass() ) ) {
+				DataProxyHandler myHandler = ( DataProxyHandler ) handler;
+				return myHandler.getEntityName();
+			}
+		}
+		return null;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/interceptor/Customer.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/interceptor/Customer.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/interceptor/Customer.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.dynamicentity">
+
+    <!--
+        Mapping the Customer and Company interfaces.  Our custom Interceptor
+        will be responsible for: a) creating instances representing these
+        interfaces; b) determining the appropriate entity-name (i.e., which
+        entity mapping to use) given an instance of one of these proxies.
+    -->
+    <class name="Person" table="t_person" abstract="false">
+        <!-- <class name="Person" table="t_person" discriminator-value="person"> -->
+		<id name="id">
+            <generator class="native"/>
+        </id>
+        <discriminator force="false"/>
+		<property name="name"/>
+
+        <many-to-one name="address" cascade="all" column="addr_id"/>
+
+        <set name="family" lazy="true" cascade="all">
+            <key column="pers_id"/>
+            <one-to-many class="Person"/>
+        </set>
+
+        <subclass name="Customer" discriminator-value="customer" abstract="false">
+    	    <many-to-one name="company" cascade="none" column="comp_id"/>
+    	</subclass>
+    </class>
+
+    <!-- Company interface mapping -->
+	<class name="Company" table="t_company" abstract="false">
+		<id name="id">
+            <generator class="native"/>
+        </id>
+		<property name="name"/>
+	</class>
+
+    <class name="Address" table="t_address" abstract="false">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="street"/>
+        <property name="city"/>
+        <property name="postalCode"/>
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/interceptor/InterceptorDynamicEntityTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/interceptor/InterceptorDynamicEntityTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/interceptor/InterceptorDynamicEntityTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,112 @@
+package org.hibernate.test.dynamicentity.interceptor;
+
+import junit.framework.TestSuite;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.dynamicentity.Company;
+import org.hibernate.test.dynamicentity.Customer;
+import org.hibernate.test.dynamicentity.ProxyHelper;
+
+/**
+ * Demonstrates custom interpretation of entity-name through
+ * an Interceptor.
+ * <p/>
+ * Here, we are generating dynamic
+ * {@link java.lang.reflect.Proxy proxies} on the fly to represent
+ * our entities.  Because of this, Hibernate would not be able to
+ * determine the appropriate entity mapping to use given one of
+ * these proxies (they are named like $Proxy1, or such).  Thus, we
+ * plug a custom Interceptor into the session to perform this
+ * entity-name interpretation.
+ *
+ * @see ProxyInterceptor
+ *
+ * @author Steve Ebersole
+ */
+public class InterceptorDynamicEntityTest extends FunctionalTestCase {
+	public InterceptorDynamicEntityTest(String x) {
+		super( x );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "dynamicentity/interceptor/Customer.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setInterceptor( new ProxyInterceptor() );
+	}
+
+	public static TestSuite suite() {
+		return new FunctionalTestClassTestSuite( InterceptorDynamicEntityTest.class );
+	}
+
+	public void testIt() {
+		// Test saving these dyna-proxies
+		Session session = openSession();
+		session.beginTransaction();
+		Company company = ProxyHelper.newCompanyProxy();
+		company.setName( "acme" );
+		session.save( company );
+		Customer customer = ProxyHelper.newCustomerProxy();
+		customer.setName( "Steve" );
+		customer.setCompany( company );
+		session.save( customer );
+		session.getTransaction().commit();
+		session.close();
+
+		assertNotNull( "company id not assigned", company.getId() );
+		assertNotNull( "customer id not assigned", customer.getId() );
+
+		// Test loading these dyna-proxies, along with flush processing
+		session = openSession();
+		session.beginTransaction();
+		customer = ( Customer ) session.load( Customer.class, customer.getId() );
+		assertFalse( "should-be-proxy was initialized", Hibernate.isInitialized( customer ) );
+
+		customer.setName( "other" );
+		session.flush();
+		assertFalse( "should-be-proxy was initialized", Hibernate.isInitialized( customer.getCompany() ) );
+
+		session.refresh( customer );
+		assertEquals( "name not updated", "other", customer.getName() );
+		assertEquals( "company association not correct", "acme", customer.getCompany().getName() );
+
+		session.getTransaction().commit();
+		session.close();
+
+		// Test detached entity re-attachment with these dyna-proxies
+		customer.setName( "Steve" );
+		session = openSession();
+		session.beginTransaction();
+		session.update( customer );
+		session.flush();
+		session.refresh( customer );
+		assertEquals( "name not updated", "Steve", customer.getName() );
+		session.getTransaction().commit();
+		session.close();
+
+		// Test querying
+		session = openSession();
+		session.beginTransaction();
+		int count = session.createQuery( "from Customer" ).list().size();
+		assertEquals( "querying dynamic entity", 1, count );
+		session.clear();
+		count = session.createQuery( "from Person" ).list().size();
+		assertEquals( "querying dynamic entity", 1, count );
+		session.getTransaction().commit();
+		session.close();
+
+		// test deleteing
+		session = openSession();
+		session.beginTransaction();
+		session.delete( company );
+		session.delete( customer );
+		session.getTransaction().commit();
+		session.close();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/interceptor/ProxyInterceptor.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/interceptor/ProxyInterceptor.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/interceptor/ProxyInterceptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,61 @@
+package org.hibernate.test.dynamicentity.interceptor;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.EntityMode;
+import org.hibernate.test.dynamicentity.Company;
+import org.hibernate.test.dynamicentity.Customer;
+import org.hibernate.test.dynamicentity.ProxyHelper;
+import org.hibernate.test.dynamicentity.DataProxyHandler;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+
+/**
+ * Our custom {@link org.hibernate.Interceptor} impl which performs the
+ * interpretation of entity-name -> proxy instance and vice-versa.
+ *
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class ProxyInterceptor extends EmptyInterceptor {
+
+	/**
+	 * The callback from Hibernate to determine the entity name given
+	 * a presumed entity instance.
+	 *
+	 * @param object The presumed entity instance.
+	 * @return The entity name (pointing to the proper entity mapping).
+	 */
+	public String getEntityName(Object object) {
+		String entityName = ProxyHelper.extractEntityName( object );
+		if ( entityName == null ) {
+			entityName = super.getEntityName( object );
+		}
+		return entityName;
+	}
+
+	/**
+	 * The callback from Hibernate in order to build an instance of the
+	 * entity represented by the given entity name.  Here, we build a
+	 * {@link Proxy} representing the entity.
+	 *
+	 * @param entityName The entity name for which to create an instance.  In our setup,
+	 * this is the interface name.
+	 * @param entityMode The entity mode in which to create an instance.  Here, we are only
+	 * interestes in custom behavior for the POJO entity mode.
+	 * @param id The identifier value for the given entity.
+	 * @return The instantiated instance.
+	 */
+	public Object instantiate(String entityName, EntityMode entityMode, Serializable id) {
+		if ( entityMode == EntityMode.POJO ) {
+			if ( Customer.class.getName().equals( entityName ) ) {
+				return ProxyHelper.newCustomerProxy( id );
+			}
+			else if ( Company.class.getName().equals( entityName ) ) {
+				return ProxyHelper.newCompanyProxy( id );
+			}
+		}
+		return super.instantiate( entityName, entityMode, id );
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/package.html
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/package.html	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+<html>
+<head></head>
+
+<body>
+<p>
+	Demonstration of different ways to use Hibernate to represent your domain
+	model as a series of JDK dynamic proxies.  We map the interfaces and then
+	use one of two approaches to get Hibernate to recognize these proxies as
+	domain entities.  Really this is demonstrating various "entity representation"
+	capabilities built in to Hibernate3.
+</p>
+<p>
+	First we use an interceptor-based approach where we use a custom Interceptor
+	implementation for interpret incoming proxies (and resolve them to the correct
+	mappings) and to help Hibernate instantiate these proxy instances.  This is the
+	quick-and-dirty approach.  It is fully expected that this approach will
+	encounter certain limitations.
+</p>
+<p>
+	Next we explore the notion of a Tuplizer and plug in custom Tuplizers to
+	help achieve the same results.  Currently, Tuplizers do not have a chance
+	to influence the resolution of entity-name given a potential entity, so we
+	also use an Interceptor here and supply its getEntityName() impl.  This is
+	simply so we do not need to supply the entity name explicitly to the
+	Hibernate Session calls.
+</p>
+</body>
+
+</html>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/Customer.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/Customer.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/Customer.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.dynamicentity">
+
+    <!--
+        Mapping the Customer and Company interfaces.  Our custom Interceptor
+        will be responsible for: a) creating instances representing these
+        interfaces; b) determining the appropriate entity-name (i.e., which
+        entity mapping to use) given an instance of one of these proxies.
+    -->
+    <class name="Person" table="t_person" discriminator-value="person" abstract="false">
+        <tuplizer class="org.hibernate.test.dynamicentity.tuplizer.MyEntityTuplizer" entity-mode="pojo"/>
+		<id name="id">
+            <generator class="native"/>
+        </id>
+        <discriminator force="false"/>
+		<property name="name"/>
+
+        <many-to-one name="address" cascade="all" column="addr_id"/>
+
+        <set name="family" lazy="true" cascade="all">
+            <key column="pers_id"/>
+            <one-to-many class="Person"/>
+        </set>
+
+        <subclass name="Customer" discriminator-value="customer" abstract="false">
+            <tuplizer class="org.hibernate.test.dynamicentity.tuplizer.MyEntityTuplizer" entity-mode="pojo"/>
+            <many-to-one name="company" cascade="none" column="comp_id"/>
+    	</subclass>
+    </class>
+
+    <!-- Company interface mapping -->
+	<class name="Company" table="t_company" abstract="false">
+        <tuplizer class="org.hibernate.test.dynamicentity.tuplizer.MyEntityTuplizer" entity-mode="pojo"/>
+		<id name="id">
+            <generator class="native"/>
+        </id>
+		<property name="name"/>
+	</class>
+
+    <class name="Address" table="t_address" abstract="false">
+        <tuplizer class="org.hibernate.test.dynamicentity.tuplizer.MyEntityTuplizer" entity-mode="pojo"/>
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="street"/>
+        <property name="city"/>
+        <property name="postalCode"/>
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/EntityNameInterceptor.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/EntityNameInterceptor.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/EntityNameInterceptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+package org.hibernate.test.dynamicentity.tuplizer;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.test.dynamicentity.ProxyHelper;
+
+/**
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class EntityNameInterceptor extends EmptyInterceptor {
+	/**
+	 * The callback from Hibernate to determine the entity name given
+	 * a presumed entity instance.
+	 *
+	 * @param object The presumed entity instance.
+	 * @return The entity name (pointing to the proper entity mapping).
+	 */
+	public String getEntityName(Object object) {
+		String entityName = ProxyHelper.extractEntityName( object );
+		if ( entityName == null ) {
+			entityName = super.getEntityName( object );
+		}
+		return entityName;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/MyEntityInstantiator.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/MyEntityInstantiator.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/MyEntityInstantiator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+package org.hibernate.test.dynamicentity.tuplizer;
+
+import org.hibernate.tuple.Instantiator;
+import org.hibernate.test.dynamicentity.Customer;
+import org.hibernate.test.dynamicentity.ProxyHelper;
+import org.hibernate.test.dynamicentity.Company;
+import org.hibernate.test.dynamicentity.DataProxyHandler;
+import org.hibernate.test.dynamicentity.Address;
+import org.hibernate.test.dynamicentity.Person;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.HibernateException;
+
+import java.io.Serializable;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.InvocationHandler;
+
+/**
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class MyEntityInstantiator implements Instantiator {
+	private final String entityName;
+
+	public MyEntityInstantiator(String entityName) {
+		this.entityName = entityName;
+	}
+
+	public Object instantiate(Serializable id) {
+		if ( Person.class.getName().equals( entityName ) ) {
+			return ProxyHelper.newPersonProxy( id );
+		}
+		if ( Customer.class.getName().equals( entityName ) ) {
+			return ProxyHelper.newCustomerProxy( id );
+		}
+		else if ( Company.class.getName().equals( entityName ) ) {
+			return ProxyHelper.newCompanyProxy( id );
+		}
+		else if ( Address.class.getName().equals( entityName ) ) {
+			return ProxyHelper.newAddressProxy( id );
+		}
+		else {
+			throw new IllegalArgumentException( "unknown entity for instantiation [" + entityName + "]" );
+		}
+	}
+
+	public Object instantiate() {
+		return instantiate( null );
+	}
+
+	public boolean isInstance(Object object) {
+		String resolvedEntityName = null;
+		if ( Proxy.isProxyClass( object.getClass() ) ) {
+			InvocationHandler handler = Proxy.getInvocationHandler( object );
+			if ( DataProxyHandler.class.isAssignableFrom( handler.getClass() ) ) {
+				DataProxyHandler myHandler = ( DataProxyHandler ) handler;
+				resolvedEntityName = myHandler.getEntityName();
+			}
+		}
+		try {
+			return ReflectHelper.classForName( entityName ).isInstance( object );
+		}
+		catch( Throwable t ) {
+			throw new HibernateException( "could not get handle to entity-name as interface : " + t );
+		}
+
+//		return entityName.equals( resolvedEntityName );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/MyEntityTuplizer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/MyEntityTuplizer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/MyEntityTuplizer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+package org.hibernate.test.dynamicentity.tuplizer;
+
+import org.hibernate.tuple.entity.PojoEntityTuplizer;
+import org.hibernate.tuple.entity.EntityMetamodel;
+import org.hibernate.tuple.Instantiator;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.proxy.ProxyFactory;
+import org.hibernate.property.Getter;
+import org.hibernate.property.Setter;
+
+/**
+ * @author Steve Ebersole
+ */
+public class MyEntityTuplizer extends PojoEntityTuplizer {
+
+	public MyEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
+		super( entityMetamodel, mappedEntity );
+	}
+
+	protected Instantiator buildInstantiator(PersistentClass persistentClass) {
+		return new MyEntityInstantiator( persistentClass.getEntityName() );
+	}
+
+	protected ProxyFactory buildProxyFactory(PersistentClass persistentClass, Getter idGetter, Setter idSetter) {
+		// allows defining a custom proxy factory, which is responsible for
+		// generating lazy proxies for a given entity.
+		//
+		// Here we simply use the default...
+		return super.buildProxyFactory( persistentClass, idGetter, idSetter );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/TuplizerDynamicEntityTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/TuplizerDynamicEntityTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer/TuplizerDynamicEntityTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,127 @@
+package org.hibernate.test.dynamicentity.tuplizer;
+
+import org.hibernate.test.TestCase;
+import org.hibernate.test.dynamicentity.Company;
+import org.hibernate.test.dynamicentity.ProxyHelper;
+import org.hibernate.test.dynamicentity.Customer;
+import org.hibernate.test.dynamicentity.Address;
+import org.hibernate.test.dynamicentity.Person;
+import org.hibernate.Session;
+import org.hibernate.Hibernate;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+import junit.framework.TestSuite;
+
+import java.util.HashSet;
+
+/**
+ * Demonstrates use of Tuplizers to allow the use of JDK
+ * {@link java.lang.reflect.Proxy dynamic proxies} as our
+ * domain model.
+ * <p/>
+ * Here we plug a custom Interceptor into the session simply to
+ * allow us to not have to explicitly supply the appropriate entity
+ * name to the Session calls.
+ *
+ * @author Steve Ebersole
+ */
+public class TuplizerDynamicEntityTest extends FunctionalTestCase {
+	public TuplizerDynamicEntityTest(String x) {
+		super( x );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "dynamicentity/tuplizer/Customer.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setInterceptor( new EntityNameInterceptor() );
+	}
+
+	public static TestSuite suite() {
+		return new FunctionalTestClassTestSuite( TuplizerDynamicEntityTest.class );
+	}
+
+	public void testIt() {
+		// Test saving these dyna-proxies
+		Session session = openSession();
+		session.beginTransaction();
+		Company company = ProxyHelper.newCompanyProxy();
+		company.setName( "acme" );
+		session.save( company );
+		Customer customer = ProxyHelper.newCustomerProxy();
+		customer.setName( "Steve" );
+		customer.setCompany( company );
+		Address address = ProxyHelper.newAddressProxy();
+		address.setStreet( "somewhere over the rainbow" );
+		address.setCity( "lawerence, kansas" );
+		address.setPostalCode( "toto");
+		customer.setAddress( address );
+		customer.setFamily( new HashSet() );
+		Person son = ProxyHelper.newPersonProxy();
+		son.setName( "son" );
+		customer.getFamily().add( son );
+		Person wife = ProxyHelper.newPersonProxy();
+		wife.setName( "wife" );
+		customer.getFamily().add( wife );
+		session.save( customer );
+		session.getTransaction().commit();
+		session.close();
+
+		assertNotNull( "company id not assigned", company.getId() );
+		assertNotNull( "customer id not assigned", customer.getId() );
+		assertNotNull( "address id not assigned", address.getId() );
+		assertNotNull( "son:Person id not assigned", son.getId() );
+		assertNotNull( "wife:Person id not assigned", wife.getId() );
+
+		// Test loading these dyna-proxies, along with flush processing
+		session = openSession();
+		session.beginTransaction();
+		customer = ( Customer ) session.load( Customer.class, customer.getId() );
+		assertFalse( "should-be-proxy was initialized", Hibernate.isInitialized( customer ) );
+
+		customer.setName( "other" );
+		session.flush();
+		assertFalse( "should-be-proxy was initialized", Hibernate.isInitialized( customer.getCompany() ) );
+
+		session.refresh( customer );
+		assertEquals( "name not updated", "other", customer.getName() );
+		assertEquals( "company association not correct", "acme", customer.getCompany().getName() );
+
+		session.getTransaction().commit();
+		session.close();
+
+		// Test detached entity re-attachment with these dyna-proxies
+		customer.setName( "Steve" );
+		session = openSession();
+		session.beginTransaction();
+		session.update( customer );
+		session.flush();
+		session.refresh( customer );
+		assertEquals( "name not updated", "Steve", customer.getName() );
+		session.getTransaction().commit();
+		session.close();
+
+		// Test querying
+		session = openSession();
+		session.beginTransaction();
+		int count = session.createQuery( "from Customer" ).list().size();
+		assertEquals( "querying dynamic entity", 1, count );
+		session.clear();
+		count = session.createQuery( "from Person" ).list().size();
+		assertEquals( "querying dynamic entity", 3, count );
+		session.getTransaction().commit();
+		session.close();
+
+		// test deleteing
+		session = openSession();
+		session.beginTransaction();
+		session.delete( company );
+		session.delete( customer );
+		session.getTransaction().commit();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/Course.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/Course.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/Course.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.ecid" 
+	default-access="field">
+
+<!-- 
+
+  This mapping demonstrates inheritance with embedded composite ids.
+     
+-->
+
+	<class name="Course" table="SchoolCourses"
+			discriminator-value="secondary/primary">
+		<composite-id>
+			<key-property name="courseCode"/>
+			<key-property name="org"/>
+		</composite-id>
+		<discriminator column="schoolLevel" length="20"/>
+		<property name="description" not-null="true"/>
+		<subclass name="UniversityCourse" discriminator-value="tertiary">
+			<property name="semester"/>
+		</subclass>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/Course.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/Course.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/Course.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/Course.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: Course.java 6913 2005-05-25 17:37:51Z oneovthafew $
+package org.hibernate.test.ecid;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Course implements Serializable {
+	
+	private String courseCode;
+	private String org;
+	private String description;
+
+	Course() {}
+	Course(String courseCode, String org, String description) {
+		this.courseCode = courseCode;
+		this.org = org;
+		this.description = description;
+	}
+	
+	public String getDescription() {
+		return description;
+	}
+	
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	
+	public String getCourseCode() {
+		return courseCode;
+	}
+	
+	public String getOrg() {
+		return org;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/Course.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/EmbeddedCompositeIdTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/EmbeddedCompositeIdTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/EmbeddedCompositeIdTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,162 @@
+//$Id: EmbeddedCompositeIdTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.ecid;
+
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.proxy.HibernateProxy;
+
+/**
+ * @author Gavin King
+ */
+public class EmbeddedCompositeIdTest extends FunctionalTestCase {
+	
+	public EmbeddedCompositeIdTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "ecid/Course.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( EmbeddedCompositeIdTest.class );
+	}
+	
+	public void testMerge() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Course uc =  new UniversityCourse("mat2000", "Monash", "second year maths", 0);
+		Course c =  new Course("eng5000", "BHS", "grade 5 english");
+		s.persist(uc);
+		s.persist(c);
+		t.commit();
+		s.close();
+		
+		c.setDescription("Grade 5 English");
+		uc.setDescription("Second year mathematics");
+		
+		s = openSession();
+		t = s.beginTransaction();
+		s.merge(c);
+		s.merge(uc);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete(c);
+		s.delete(uc);
+		t.commit();
+		s.close();
+	}
+
+	public void testMerging() {
+		// Test HHH-799
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Course course = new Course( "EN-101", "BA", "preparatory english" );
+		s.persist( course );
+		t.commit();
+		s.close();
+
+		String newDesc = "basic preparatory english";
+		course.setDescription( newDesc );
+
+		s = openSession();
+		t = s.beginTransaction();
+		Course c = (Course) s.merge( course );
+		assertEquals( "description not merged", newDesc, c.getDescription() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Course cid = new Course( "EN-101", "BA", null );
+		course = ( Course ) s.get( Course.class, cid );
+		assertEquals( "description not merged", newDesc, course.getDescription() );
+		s.delete( course );
+		t.commit();
+		s.close();
+	}
+
+	public void testPolymorphism() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Course uc =  new UniversityCourse("mat2000", "Monash", "second year maths", 0);
+		Course c =  new Course("eng5000", "BHS", "grade 5 english");
+		s.persist(uc);
+		s.persist(c);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		Course ucid = new Course("mat2000", "Monash", null);
+		Course cid =  new Course("eng5000", "BHS", null);
+		Course luc = (Course) s.load(Course.class, ucid);
+		Course lc = (Course) s.load(Course.class, cid);
+		assertFalse( Hibernate.isInitialized(luc) );
+		assertFalse( Hibernate.isInitialized(lc) );
+		assertEquals( UniversityCourse.class, Hibernate.getClass(luc) );
+		assertEquals( Course.class, Hibernate.getClass(lc) );
+		assertSame( ( (HibernateProxy) lc ).getHibernateLazyInitializer().getImplementation(), cid );
+		assertEquals( c.getCourseCode(), "eng5000" );
+		assertEquals( uc.getCourseCode(), "mat2000" );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		ucid = new Course("mat2000", "Monash", null);
+		cid =  new Course("eng5000", "BHS", null);
+		luc = (Course) s.get(Course.class, ucid);
+		lc = (Course) s.get(Course.class, cid);
+		assertTrue( Hibernate.isInitialized(luc) );
+		assertTrue( Hibernate.isInitialized(lc) );
+		assertEquals( UniversityCourse.class, Hibernate.getClass(luc) );
+		assertEquals( Course.class, Hibernate.getClass(lc) );
+		assertSame( lc, cid );
+		assertEquals( c.getCourseCode(), "eng5000" );
+		assertEquals( uc.getCourseCode(), "mat2000" );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		List list = s.createQuery("from Course order by courseCode").list();
+		assertTrue( list.get(0) instanceof Course );
+		assertTrue( list.get(1) instanceof UniversityCourse );
+		c = (Course) list.get(0);
+		uc = (UniversityCourse) list.get(1);
+		assertEquals( c.getCourseCode(), "eng5000" );
+		assertEquals( uc.getCourseCode(), "mat2000" );
+		t.commit();
+		s.close();
+		
+		c.setDescription("Grade 5 English");
+		uc.setDescription("Second year mathematics");
+		
+		s = openSession();
+		t = s.beginTransaction();
+		s.saveOrUpdate(c);
+		s.saveOrUpdate(uc);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete(c);
+		s.delete(uc);
+		t.commit();
+		s.close();
+		
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/EmbeddedCompositeIdTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/UniversityCourse.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/UniversityCourse.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/UniversityCourse.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: UniversityCourse.java 6913 2005-05-25 17:37:51Z oneovthafew $
+package org.hibernate.test.ecid;
+
+/**
+ * @author Gavin King
+ */
+public class UniversityCourse extends Course {
+	
+	private int semester;
+
+	UniversityCourse() {}
+
+	public UniversityCourse(String courseCode, String org, String description, int semester) {
+		super( courseCode, org, description );
+		this.semester = semester;
+	}
+
+	public int getSemester() {
+		return semester;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ecid/UniversityCourse.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/EntityModeSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/EntityModeSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/EntityModeSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+package org.hibernate.test.entitymode;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.entitymode.dom4j.Dom4jSuite;
+import org.hibernate.test.entitymode.map.MapSuite;
+import org.hibernate.test.entitymode.multi.MultiRepresentationTest;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class EntityModeSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "entity-mode tests" );
+		suite.addTest( Dom4jSuite.suite() );
+		suite.addTest( MapSuite.suite() );
+		suite.addTest( MultiRepresentationTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/Dom4jSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/Dom4jSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/Dom4jSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+package org.hibernate.test.entitymode.dom4j;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.entitymode.dom4j.accessors.Dom4jAccessorTest;
+import org.hibernate.test.entitymode.dom4j.basic.Dom4jTest;
+import org.hibernate.test.entitymode.dom4j.many2one.Dom4jManyToOneTest;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Dom4jSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "dom4j entity-mode suite" );
+		suite.addTest( Dom4jAccessorTest.suite() );
+		suite.addTest( Dom4jTest.suite() );
+		suite.addTest( Dom4jManyToOneTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/accessors/Dom4jAccessorTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/accessors/Dom4jAccessorTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/accessors/Dom4jAccessorTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,157 @@
+// $Id: Dom4jAccessorTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.entitymode.dom4j.accessors;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.dom4j.DocumentFactory;
+import org.dom4j.Element;
+import org.dom4j.util.NodeComparator;
+
+import org.hibernate.EntityMode;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.property.Getter;
+import org.hibernate.property.PropertyAccessorFactory;
+import org.hibernate.property.Setter;
+
+/**
+ * Unit test of dom4j-based accessors
+ *
+ * @author Steve Ebersole
+ */
+public class Dom4jAccessorTest extends TestCase {
+
+	public static final Element DOM = generateTestElement();
+
+	public Dom4jAccessorTest(String name) {
+		super( name );
+	}
+
+	public void testStringElementExtraction() throws Throwable {
+		Property property = generateNameProperty();
+		Getter getter = PropertyAccessorFactory.getPropertyAccessor( property, EntityMode.DOM4J )
+				.getGetter( null, null );
+		String name = ( String ) getter.get( DOM );
+		assertEquals( "Not equals", "JBoss", name );
+	}
+
+	public void testStringTextExtraction() throws Throwable {
+		Property property = generateTextProperty();
+		Getter getter = PropertyAccessorFactory.getPropertyAccessor( property, EntityMode.DOM4J )
+				.getGetter( null, null );
+		String name = ( String ) getter.get( DOM );
+		assertEquals( "Not equals", "description...", name );
+	}
+
+	public void testLongAttributeExtraction() throws Throwable {
+		Property property = generateIdProperty();
+		Getter getter = PropertyAccessorFactory.getPropertyAccessor( property, EntityMode.DOM4J )
+				.getGetter( null, null );
+		Long id = ( Long ) getter.get( DOM );
+		assertEquals( "Not equals", new Long( 123 ), id );
+	}
+
+	public void testLongElementAttributeExtraction() throws Throwable {
+		Property property = generateAccountIdProperty();
+		Getter getter = PropertyAccessorFactory.getPropertyAccessor( property, EntityMode.DOM4J )
+				.getGetter( null, null );
+		Long id = ( Long ) getter.get( DOM );
+		assertEquals( "Not equals", new Long( 456 ), id );
+	}
+
+	public void testCompanyElementGeneration() throws Throwable {
+		Setter idSetter = PropertyAccessorFactory.getPropertyAccessor( generateIdProperty(), EntityMode.DOM4J )
+				.getSetter( null, null );
+		Setter nameSetter = PropertyAccessorFactory.getPropertyAccessor( generateNameProperty(), EntityMode.DOM4J )
+				.getSetter( null, null );
+		Setter textSetter = PropertyAccessorFactory.getPropertyAccessor( generateTextProperty(), EntityMode.DOM4J )
+				.getSetter( null, null );
+		Setter accountIdSetter = PropertyAccessorFactory.getPropertyAccessor(
+				generateAccountIdProperty(), EntityMode.DOM4J
+		)
+				.getSetter( null, null );
+
+		Element root = generateRootTestElement();
+
+		idSetter.set( root, new Long( 123 ), getSFI() );
+		textSetter.set( root, "description...", getSFI() );
+		nameSetter.set( root, "JBoss", getSFI() );
+		accountIdSetter.set( root, new Long( 456 ), getSFI() );
+
+		assertTrue( "DOMs not equal", new NodeComparator().compare( DOM, root ) == 0 );
+	}
+
+	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	private static Element generateTestElement() {
+		Element company = generateRootTestElement();
+		company.addAttribute( "id", "123" );
+		company.setText( "description..." );
+		company.addElement( "name" ).setText( "JBoss" );
+		company.addElement( "account" ).addAttribute( "num", "456" );
+
+		return company;
+	}
+
+	private static Element generateRootTestElement() {
+		return DocumentFactory.getInstance().createElement( "company" );
+	}
+
+	public static Test suite() {
+		return new TestSuite( Dom4jAccessorTest.class );
+	}
+
+	private SessionFactoryImplementor getSFI() {
+		return null;
+	}
+
+	private Property generateIdProperty() {
+		SimpleValue value = new SimpleValue();
+		value.setTypeName( "long" );
+
+		Property property = new Property();
+		property.setName( "id" );
+		property.setNodeName( "@id" );
+		property.setValue( value );
+
+		return property;
+	}
+
+	private Property generateTextProperty() {
+		SimpleValue value = new SimpleValue();
+		value.setTypeName( "string" );
+
+		Property property = new Property();
+		property.setName( "text" );
+		property.setNodeName( "." );
+		property.setValue( value );
+
+		return property;
+	}
+
+	private Property generateAccountIdProperty() {
+		SimpleValue value = new SimpleValue();
+		value.setTypeName( "long" );
+
+		Property property = new Property();
+		property.setName( "number" );
+		property.setNodeName( "account/@num" );
+		property.setValue( value );
+
+		return property;
+	}
+
+	private Property generateNameProperty() {
+		SimpleValue value = new SimpleValue();
+		value.setTypeName( "string" );
+
+		Property property = new Property();
+		property.setName( "name" );
+		property.setNodeName( "name" );
+		property.setValue( value );
+
+		return property;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/AB.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/AB.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/AB.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping >
+
+    <class entity-name="A" table="AX" node="a">
+        <id name="aId" type="int" column="aId" node="@id"/>
+        <property name="x"  type="string"/>
+        <set name="bs" node="." embed-xml="true" cascade="all" inverse="true">
+            <key column="aId"/>
+            <one-to-many class="B"/>
+        </set>
+    </class>
+
+
+    <class entity-name="B" table="BX" node="b">
+        <composite-id>
+            <key-property name="bId" column="bId" type="int" node="@bId"/>
+            <key-property name="aId" column="aId" type="int" node="@aId"/>
+        </composite-id>
+        <property name="y" type="string" node="."/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/AB.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Account.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Account.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Account.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+
+    <class entity-name="Customer" node="customer">
+        <id name="customerId" type="string" node="@id"/>
+        <component name="name">
+            <property name="first" type="string"/>
+            <property name="last" type="string"/>
+        </component>
+        <property name="address" type="string" node="address"/>
+        <map name="stuff">
+            <key column="customerId"/>
+            <map-key type="string" column="bar" node="@bar"/>
+            <element type="string" node="foo" column="foo"/>
+        </map>
+        <bag name="morestuff" node=".">
+            <key column="customerId"/>
+            <element type="integer" node="amount" column="amount"/>
+        </bag>
+        <list name="accounts" cascade="all">
+            <key column="customerId2"/>
+            <list-index column="acctno" base="1"/>
+            <one-to-many entity-name="Account" node="account"/>
+        </list>
+        <many-to-one name="location" node="location/@id" entity-name="Location" embed-xml="false"/>
+        <property name="description" node="." type="string"/>
+        <set name="unembedded" embed-xml="false">
+            <key column="x"/>
+            <element type="string" column="y" not-null="true"/>
+        </set>
+    </class>
+
+    <class entity-name="Account" node="account">
+        <id name="accountId" type="string" node="@id"/>
+        <many-to-one name="customer" column="customerId" entity-name="Customer" cascade="all" embed-xml="true" />
+        <!--not-null="true"-->
+        <property name="balance" type="big_decimal" node="balance" precision="10" scale="0" />
+    </class>
+
+    <class entity-name="Location" node="location">
+        <id name="id" node="@id" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="address" type="string"/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Account.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Dom4jTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Dom4jTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Dom4jTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,360 @@
+// $Id: Dom4jTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.entitymode.dom4j.basic;
+
+import java.util.Map;
+
+import junit.framework.Test;
+import org.dom4j.DocumentFactory;
+import org.dom4j.Element;
+
+import org.hibernate.EntityMode;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.Example;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.transform.Transformers;
+import org.hibernate.util.XMLHelper;
+
+/**
+ * @author Gavin King
+ */
+public class Dom4jTest extends FunctionalTestCase {
+
+	public Dom4jTest(String str) {
+		super( str );
+	}
+
+	public String[] getMappings() {
+		return new String[] {
+				"entitymode/dom4j/basic/Account.hbm.xml",
+				"entitymode/dom4j/basic/AB.hbm.xml",
+				"entitymode/dom4j/basic/Employer.hbm.xml"
+		};
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty( Environment.DEFAULT_ENTITY_MODE, EntityMode.DOM4J.toString() );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( Dom4jTest.class );
+	}
+
+// TODO : still need to figure out inheritence support within the DOM4J entity-mode
+//
+//	public void testSubtyping() throws Exception {
+//		Element employer = DocumentFactory.getInstance().createElement( "employer" );
+//		employer.addAttribute( "name", "JBoss" );
+//		Element gavin = employer.addElement( "techie" );
+//		gavin.addAttribute( "name", "Gavin" );
+//		Element ben = employer.addElement( "sales-dude" );
+//		ben.addAttribute( "name", "Ben" );
+//		print( employer );
+//
+//		Session s = openSession();
+//		Transaction t = s.beginTransaction();
+//		s.persist( "Employer", employer );
+//		Long eid = new Long( employer.attributeValue( "id" ) );
+//		t.commit();
+//		s.close();
+//
+//		s = openSession();
+//		t = s.beginTransaction();
+//		employer = (Element) s.get( "Employer", eid );
+//		print( employer );
+//		s.delete( "Employer", employer );
+//		t.commit();
+//		s.close();
+//
+//		Element dept = DocumentFactory.getInstance().createElement( "department" );
+//		dept.addAttribute( "name", "engineering" );
+//		Element steve = dept.addElement( "manager" ).addElement( "techie" );
+//		steve.addAttribute( "name", "Steve" );
+//		print( dept );
+//
+//		s = openSession();
+//		t = s.beginTransaction();
+//		s.persist( "Department", dept );
+//		Long did = new Long( dept.attributeValue( "id" ) );
+//		t.commit();
+//		s.close();
+//
+//		s = openSession();
+//		t = s.beginTransaction();
+//		dept = ( Element ) s.load( "Department", did );
+//		print( dept );
+//		s.delete( "Department", dept );
+//		t.commit();
+//		s.close();
+//	}
+	
+	public void testCompositeId() throws Exception {
+		Element a = DocumentFactory.getInstance().createElement( "a" );
+		a.addAttribute("id", "1");
+		a.addElement("x").setText("foo bar");
+		//Element bs = a.addElement("bs");
+		Element b = a.addElement("b");
+		//b.addElement("bId").setText("1");
+		//b.addElement("aId").setText("1");
+		b.addAttribute("bId", "1");
+		b.addAttribute("aId", "1");
+		b.setText("foo foo");
+		b = a.addElement("b");
+		//b.addElement("bId").setText("2");
+		//b.addElement("aId").setText("1");
+		b.addAttribute("bId", "2");
+		b.addAttribute("aId", "1");
+		b.setText("bar bar");
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.persist("A", a);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		a = (Element) s.createCriteria("A").uniqueResult();
+		assertEquals( a.elements("b").size(), 2 );
+		print(a);
+		s.delete("A", a);
+		t.commit();
+		s.close();
+	}
+
+	public void testDom4j() throws Exception {
+		Element acct = DocumentFactory.getInstance().createElement( "account" );
+		acct.addAttribute( "id", "abc123" );
+		acct.addElement( "balance" ).setText( "123.45" );
+		Element cust = acct.addElement( "customer" );
+		cust.addAttribute( "id", "xyz123" );
+		Element foo1 = cust.addElement( "stuff" ).addElement( "foo" );
+		foo1.setText( "foo" );
+		foo1.addAttribute("bar", "x");
+		Element foo2 = cust.element( "stuff" ).addElement( "foo" );
+		foo2.setText( "bar" );
+		foo2.addAttribute("bar", "y");
+		cust.addElement( "amount" ).setText( "45" );
+		cust.setText( "An example customer" );
+		Element name = cust.addElement( "name" );
+		name.addElement( "first" ).setText( "Gavin" );
+		name.addElement( "last" ).setText( "King" );
+
+		Element loc = DocumentFactory.getInstance().createElement( "location" );
+		loc.addElement( "address" ).setText( "Karbarook Avenue" );
+
+		print( acct );
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.persist( "Location", loc );
+		cust.addElement( "location" ).addAttribute( "id", loc.attributeValue( "id" ) );
+		s.persist( "Account", acct );
+		t.commit();
+		s.close();
+
+		print( loc );
+
+		s = openSession();
+		t = s.beginTransaction();
+		cust = (Element) s.get( "Customer", "xyz123" );
+		print( cust );
+		acct = (Element) s.get( "Account", "abc123" );
+		print( acct );
+		assertEquals( acct.element( "customer" ), cust );
+		cust.element( "name" ).element( "first" ).setText( "Gavin A" );
+		Element foo3 = cust.element("stuff").addElement("foo");
+		foo3.setText("baz");
+		foo3.addAttribute("bar", "z");
+		cust.element("amount").setText("3");
+		cust.addElement("amount").setText("56");
+		t.commit();
+		s.close();
+
+		System.out.println();
+
+		acct.element( "balance" ).setText( "3456.12" );
+		cust.addElement( "address" ).setText( "Karbarook Ave" );
+
+		assertEquals( acct.element( "customer" ), cust );
+
+		cust.setText( "Still the same example!" );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.saveOrUpdate( "Account", acct );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		cust = (Element) s.get( "Customer", "xyz123" );
+		print( cust );
+		acct = (Element) s.get( "Account", "abc123" );
+		print( acct );
+		assertEquals( acct.element( "customer" ), cust );
+		t.commit();
+		s.close();
+
+		System.out.println();
+
+		s = openSession();
+		t = s.beginTransaction();
+		cust = (Element) s.createCriteria( "Customer" )
+				.add( Example.create( cust ) )
+				.uniqueResult();
+		print( cust );
+		t.commit();
+		s.close();
+
+		System.out.println();
+
+		s = openSession();
+		t = s.beginTransaction();
+		acct = (Element) s.createQuery( "from Account a left join fetch a.customer" )
+				.uniqueResult();
+		print( acct );
+		t.commit();
+		s.close();
+
+		System.out.println();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Map m = (Map) s.createQuery( "select a as acc from Account a left join fetch a.customer" )
+			.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).uniqueResult();
+		acct = (Element)m.get("acc"); 
+		print( acct );
+		t.commit();
+		s.close();
+
+		System.out.println();
+
+		s = openSession();
+		t = s.beginTransaction();
+		acct = (Element) s.createQuery( "from Account" ).uniqueResult();
+		print( acct );
+		t.commit();
+		s.close();
+
+		System.out.println();
+
+		s = openSession();
+		t = s.beginTransaction();
+		cust = (Element) s.createQuery( "from Customer c left join fetch c.stuff" ).uniqueResult();
+		print( cust );
+		t.commit();
+		s.close();
+
+		System.out.println();
+
+		s = openSession();
+		t = s.beginTransaction();
+		cust = (Element) s.createQuery( "from Customer c left join fetch c.morestuff" ).uniqueResult();
+		print( cust );
+		t.commit();
+		s.close();
+
+		System.out.println();
+
+		s = openSession();
+		t = s.beginTransaction();
+		cust = (Element) s.createQuery( "from Customer c left join fetch c.morestuff" ).uniqueResult();
+		print( cust );
+		cust = (Element) s.createQuery( "from Customer c left join fetch c.stuff" ).uniqueResult();
+		print( cust );
+		t.commit();
+		s.close();
+
+		System.out.println();
+
+		s = openSession();
+		t = s.beginTransaction();
+		cust = (Element) s.createQuery( "from Customer c left join fetch c.accounts" ).uniqueResult();
+		Element a1 = cust.element( "accounts" ).addElement( "account" );
+		a1.addElement( "balance" ).setText( "12.67" );
+		a1.addAttribute( "id", "lkj345" );
+		a1.addAttribute("acnum", "0");
+		Element a2 = cust.element( "accounts" ).addElement( "account" );
+		a2.addElement( "balance" ).setText( "10000.00" );
+		a2.addAttribute( "id", "hsh987" );
+		a2.addAttribute("acnum", "1");
+		print( cust );
+		t.commit();
+		s.close();
+
+		System.out.println();
+
+		s = openSession();
+		t = s.beginTransaction();
+		cust = (Element) s.createQuery( "from Customer c left join fetch c.accounts" ).uniqueResult();
+		print( cust );
+		t.commit();
+		s.close();
+
+		// clean up
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( "Account", acct );
+		s.delete( "Location", loc );
+		s.createQuery( "delete from Account" ).executeUpdate();
+		t.commit();
+		s.close();
+	}
+
+	public void testMapIndexEmision() throws Throwable {
+		Element acct = DocumentFactory.getInstance().createElement( "account" );
+		acct.addAttribute( "id", "abc123" );
+		acct.addElement( "balance" ).setText( "123.45" );
+		Element cust = acct.addElement( "customer" );
+		cust.addAttribute( "id", "xyz123" );
+		Element foo1 = cust.addElement( "stuff" ).addElement( "foo" );
+		foo1.setText( "foo" );
+		foo1.addAttribute("bar", "x");
+		Element foo2 = cust.element( "stuff" ).addElement( "foo" );
+		foo2.setText( "bar" );
+		foo2.addAttribute("bar", "y");
+		cust.addElement( "amount" ).setText( "45" );
+		cust.setText( "An example customer" );
+		Element name = cust.addElement( "name" );
+		name.addElement( "first" ).setText( "Gavin" );
+		name.addElement( "last" ).setText( "King" );
+
+		print( acct );
+
+		Element loc = DocumentFactory.getInstance().createElement( "location" );
+		loc.addElement( "address" ).setText( "Karbarook Avenue" );
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.persist( "Location", loc );
+		cust.addElement( "location" ).addAttribute( "id", loc.attributeValue( "id" ) );
+		s.persist( "Account", acct );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		cust = ( Element ) s.get( "Customer", "xyz123" );
+		print( cust );
+		assertEquals( "Incorrect stuff-map size", 2, cust.element( "stuff" ).elements( "foo" ).size() );
+		Element stuffElement = ( Element ) cust.element( "stuff" ).elements(  "foo" ).get( 0 );
+		assertNotNull( "No map-key value present", stuffElement.attribute( "bar" ) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( "Account", acct );
+		s.delete( "Location", loc );
+		t.commit();
+		s.close();
+	}
+
+	public static void print(Element elt) throws Exception {
+		XMLHelper.dump( elt );
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Dom4jTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Employer.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Employer.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Employer.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping>
+
+	<class entity-name="Employer" node="employer">
+		<id name="id" node="@id" type="long">
+			<generator class="increment"/>
+		</id>
+		<property name="name" node="@name" type="string"/>
+		<set name="employees" node="." cascade="all,delete-orphan" fetch="join" lazy="false">
+			<key not-null="true" column="employerId"/>
+			<one-to-many entity-name="Employee" />
+		</set>
+	</class>
+
+	<class entity-name="Employee" node="employee">
+		<id name="id" node="@id" type="long">
+			<generator class="increment"/>
+		</id>
+		<discriminator column="role" type="string" length="10"/>
+		<property name="name" node="@name" type="string"/>
+		<subclass entity-name="Techie" node="techie" />
+		<subclass entity-name="Salesdude" node="sales-dude"/>
+	</class>
+
+    <class entity-name="Department" node="department">
+		<id name="id" node="@id" type="long">
+			<generator class="increment"/>
+		</id>
+        <property name="name" node="@name" type="string"/>
+        <many-to-one name="manager" entity-name="Employee" cascade="all" fetch="join" lazy="false" embed-xml="true" node="manager" />
+    </class>
+	
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/basic/Employer.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Car.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Car.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Car.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+	
+<hibernate-mapping package="org.hibernate.test.entitymode.dom4j.many2one">
+
+	<class name="Car" lazy="false" node="car">
+		<id name="id" node="@id" type="long">
+			<generator class="increment"/>
+		</id>
+		<property name="model"  type="string" node="model"/>
+		<many-to-one name="carType" node="carType" class="CarType"/>
+		<set name="carParts" node="." cascade="all">
+			<key column="car" not-null="true"/>
+			<one-to-many class="CarPart" node="carPart" embed-xml="false"/>
+		</set>
+	</class>
+	
+	<class name="CarType" lazy="true" node="carType">
+		<id name="id" node="@id" type="long">
+			<generator class="increment"/>
+		</id>
+		<property name="typeName" type="string" node="typeName"/>
+	</class>
+	
+	<class name="CarPart" node="carPart">
+		<id name="id" node="@id" type="long">
+			<generator class="increment"/>
+		</id>
+		<property name="partName" type="string" node="partName"/>
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Car.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Car.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Car.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Car.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,58 @@
+package org.hibernate.test.entitymode.dom4j.many2one;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Paco Hernández
+ */
+public class Car implements java.io.Serializable {
+
+	private long id;
+	private String model;
+	private CarType carType;
+	private Set carParts = new HashSet();
+	
+	/**
+	 * @return Returns the carType.
+	 */
+	public CarType getCarType() {
+		return carType;
+	}
+	/**
+	 * @param carType The carType to set.
+	 */
+	public void setCarType(CarType carType) {
+		this.carType = carType;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the model.
+	 */
+	public String getModel() {
+		return model;
+	}
+	/**
+	 * @param model The model to set.
+	 */
+	public void setModel(String model) {
+		this.model = model;
+	}
+	public Set getCarParts() {
+		return carParts;
+	}
+	public void setCarParts(Set carParts) {
+		this.carParts = carParts;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Car.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/CarPart.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/CarPart.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/CarPart.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+package org.hibernate.test.entitymode.dom4j.many2one;
+
+/**
+ * @author Paco Hernández
+ */
+public class CarPart implements java.io.Serializable {
+
+	private long id;
+	private String partName;
+
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the typeName.
+	 */
+	public String getPartName() {
+		return partName;
+	}
+	/**
+	 * @param typeName The typeName to set.
+	 */
+	public void setPartName(String typeName) {
+		this.partName = typeName;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/CarPart.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/CarType.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/CarType.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/CarType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+package org.hibernate.test.entitymode.dom4j.many2one;
+
+/**
+ * @author Paco Hernández
+ */
+public class CarType implements java.io.Serializable {
+
+	private long id;
+	private String typeName;
+
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the typeName.
+	 */
+	public String getTypeName() {
+		return typeName;
+	}
+	/**
+	 * @param typeName The typeName to set.
+	 */
+	public void setTypeName(String typeName) {
+		this.typeName = typeName;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/CarType.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Dom4jManyToOneTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Dom4jManyToOneTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Dom4jManyToOneTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,141 @@
+package org.hibernate.test.entitymode.dom4j.many2one;
+
+import java.util.List;
+
+import junit.framework.Test;
+import org.dom4j.Element;
+import org.dom4j.io.OutputFormat;
+import org.dom4j.io.XMLWriter;
+
+import org.hibernate.EntityMode;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Paco Hernández
+ */
+public class Dom4jManyToOneTest extends FunctionalTestCase {
+
+	public Dom4jManyToOneTest(String str) {
+		super( str );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "entitymode/dom4j/many2one/Car.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( Dom4jManyToOneTest.class );
+	}
+	
+	public void testDom4jOneToMany() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		CarType carType = new CarType();
+		carType.setTypeName("Type 1");
+		s.save(carType);
+
+		Car car = new Car();
+		car.setCarType(carType);
+		car.setModel("Model 1");
+		s.save(car);
+		
+		CarPart carPart1 = new CarPart();
+		carPart1.setPartName("chassis");
+		car.getCarParts().add(carPart1);
+		
+		t.commit();
+		s.close();
+
+		s = openSession();
+		Session dom4jSession = s.getSession( EntityMode.DOM4J );
+		t = s.beginTransaction();
+
+		Element element = (Element) dom4jSession.createQuery( "from Car c join fetch c.carParts" ).uniqueResult();
+
+		String expectedResult = "<car id=\"" + 
+			car.getId() + 
+			"\"><carPart>" + 
+			carPart1.getId() +
+			"</carPart><model>Model 1</model><carType id=\"" +
+			carType.getId() +
+			"\"><typeName>Type 1</typeName></carType></car>";
+				
+		print(element);
+		assertTrue(element.asXML().equals(expectedResult));
+		
+		s.createQuery("delete from CarPart").executeUpdate();
+		s.createQuery("delete from Car").executeUpdate();
+		s.createQuery("delete from CarType").executeUpdate();
+		
+		t.commit();
+		s.close();
+	}
+
+	public void testDom4jManyToOne() throws Exception {
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		CarType carType = new CarType();
+		carType.setTypeName("Type 1");
+		s.save(carType);
+
+		Car car1 = new Car();
+		car1.setCarType(carType);
+		car1.setModel("Model 1");
+		s.save(car1);
+		
+		Car car2 = new Car();
+		car2.setCarType(carType);
+		car2.setModel("Model 2");
+		s.save(car2);
+		
+		t.commit();
+		s.close();
+
+		s = openSession();
+		Session dom4jSession = s.getSession( EntityMode.DOM4J );
+		t = s.beginTransaction();
+
+		List list = dom4jSession.createQuery( "from Car c join fetch c.carType order by c.model asc" ).list();
+
+		String[] expectedResults = new String[] {
+				"<car id=\"" + 
+				car1.getId() +
+				"\"><model>Model 1</model><carType id=\"" + 
+				carType.getId() +
+				"\"><typeName>Type 1</typeName></carType></car>",
+				"<car id=\"" + 
+				car2.getId() +
+				"\"><model>Model 2</model><carType id=\"" +
+				carType.getId() +
+				"\"><typeName>Type 1</typeName></carType></car>"
+		};
+				
+		for (int i = 0; i < list.size(); i++) {
+			Element element = (Element) list.get(i);
+
+			print(element);
+			assertTrue(element.asXML().equals(expectedResults[i]));
+		}
+		
+		s.createQuery("delete from Car").executeUpdate();
+		s.createQuery("delete from CarType").executeUpdate();
+		
+		t.commit();
+		s.close();
+	}
+
+	public static void print(Element elt) throws Exception {
+		OutputFormat outformat = OutputFormat.createPrettyPrint();
+		// outformat.setEncoding(aEncodingScheme);
+		XMLWriter writer = new XMLWriter( System.out, outformat );
+		writer.write( elt );
+		writer.flush();
+		// System.out.println( elt.asXML() );
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/dom4j/many2one/Dom4jManyToOneTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/MapSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/MapSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/MapSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+package org.hibernate.test.entitymode.map;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.entitymode.map.basic.DynamicClassTest;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class MapSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "map entity-mode suite");
+		suite.addTest( DynamicClassTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/basic/DynamicClassTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/basic/DynamicClassTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/basic/DynamicClassTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,109 @@
+//$Id: DynamicClassTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.entitymode.map.basic;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+
+import org.hibernate.EntityMode;
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class DynamicClassTest extends FunctionalTestCase {
+	
+	public DynamicClassTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "entitymode/map/basic/ProductLine.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.DEFAULT_ENTITY_MODE, EntityMode.MAP.toString());
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( DynamicClassTest.class );
+	}
+
+	public void testLazyDynamicClass() {
+		Session s = openSession();
+		assertTrue( "Incorrectly handled default_entity_mode", s.getEntityMode() == EntityMode.MAP );
+		Session other = s.getSession( EntityMode.MAP );
+		assertEquals( "openSession() using same entity-mode returned new session", s, other );
+
+		other = s.getSession( EntityMode.POJO );
+		other.close();
+		assertTrue( !other.isOpen() );
+// this is no longer allowed since the session does much more up-front closed checking
+//		assertTrue( other.isConnected() );  // because it is linked to the "root" session's connection
+
+		s.close();
+
+		s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Map cars = new HashMap();
+		cars.put("description", "Cars");
+		Map monaro = new HashMap();
+		monaro.put("productLine", cars);
+		monaro.put("name", "monaro");
+		monaro.put("description", "Holden Monaro");
+		Map hsv = new HashMap();
+		hsv.put("productLine", cars);
+		hsv.put("name", "hsv");
+		hsv.put("description", "Holden Commodore HSV");
+		List models = new ArrayList();
+		cars.put("models", models);
+		models.add(hsv);
+		models.add(monaro);
+		s.save("ProductLine", cars);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		
+		cars = (Map) s.createQuery("from ProductLine pl order by pl.description").uniqueResult();
+		models = (List) cars.get("models");
+		assertFalse( Hibernate.isInitialized(models) );
+		assertEquals( models.size(), 2);
+		assertTrue( Hibernate.isInitialized(models) );
+		
+		s.clear();
+		
+		List list = s.createQuery("from Model m").list();
+		for ( Iterator i=list.iterator(); i.hasNext(); ) {
+			assertFalse( Hibernate.isInitialized( ( (Map) i.next() ).get("productLine") ) );
+		}
+		Map model = (Map) list.get(0);
+		assertTrue( ( (List) ( (Map) model.get("productLine") ).get("models") ).contains(model) );
+		s.clear();
+		
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		cars = (Map) s.createQuery("from ProductLine pl order by pl.description").uniqueResult();
+		s.delete(cars);
+		t.commit();
+		s.close();
+	}
+
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/basic/DynamicClassTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/basic/ProductLine.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/basic/ProductLine.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/basic/ProductLine.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+
+<!-- 
+    This mapping demonstrates "dynamic" entities.
+-->
+
+	<class entity-name="ProductLine">
+    	<id name="id" column="productId" length="32" type="string">
+    		<generator class="uuid.hex"/>
+    	</id>
+
+    	<property name="description" not-null="true" length="200" type="string"/>
+
+    	<!-- don't use sets for associations, unless you want stack overflows! -->
+    	<bag name="models" cascade="all" inverse="true">
+            <key column="productId"/>
+    		<one-to-many class="Model"/>
+    	</bag>
+
+	</class>
+
+    <class entity-name="Model">
+    	<id name="id" column="modelId" length="32" type="string">
+    		<generator class="uuid.hex"/>
+    	</id>
+    	
+    	<property name="name" not-null="true" length="25" type="string"/>
+    	<property name="description" not-null="true" length="200" type="string"/>
+    	<many-to-one name="productLine" column="productId" not-null="true" class="ProductLine"/>
+    	
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/map/basic/ProductLine.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/MultiRepresentationTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/MultiRepresentationTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/MultiRepresentationTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,194 @@
+// $Id: MultiRepresentationTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.entitymode.multi;
+
+import java.sql.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.dom4j.DocumentFactory;
+import org.dom4j.Element;
+import org.dom4j.io.OutputFormat;
+import org.dom4j.io.XMLWriter;
+
+import org.hibernate.EntityMode;
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Implementation of MultiRepresentationTest.
+ *
+ * @author Steve Ebersole
+ */
+public class MultiRepresentationTest extends FunctionalTestCase {
+
+
+	public MultiRepresentationTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "entitymode/multi/Stock.hbm.xml", "entitymode/multi/Valuation.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( MultiRepresentationTest.class );
+	}
+
+	public void testPojoRetreival() {
+		TestData testData = new TestData();
+		testData.create();
+
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+
+		Stock stock = ( Stock ) session.get( Stock.class, new Long( 1 ) );
+		assertEquals( "Something wrong!", new Long( 1 ), stock.getId() );
+
+		txn.commit();
+		session.close();
+
+		testData.destroy();
+	}
+
+	public void testDom4jRetreival() {
+		TestData testData = new TestData();
+		testData.create();
+
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+		org.hibernate.Session dom4j = session.getSession( EntityMode.DOM4J );
+
+		Object rtn = dom4j.get( Stock.class.getName(), testData.stockId );
+		Element element = ( Element ) rtn;
+
+		assertEquals( "Something wrong!", testData.stockId, Long.valueOf( element.attributeValue( "id" ) ) );
+
+		System.out.println( "**** XML: ****************************************************" );
+		prettyPrint( element );
+		System.out.println( "**************************************************************" );
+
+		Element currVal = element.element( "currentValuation" );
+
+		System.out.println( "**** XML: ****************************************************" );
+		prettyPrint( currVal );
+		System.out.println( "**************************************************************" );
+
+		txn.rollback();
+		session.close();
+
+		testData.destroy();
+	}
+
+	public void testDom4jSave() {
+		TestData testData = new TestData();
+		testData.create();
+
+		Session pojos = openSession();
+		Transaction txn = pojos.beginTransaction();
+		org.hibernate.Session dom4j = pojos.getSession( EntityMode.DOM4J );
+
+		Element stock = DocumentFactory.getInstance().createElement( "stock" );
+		stock.addElement( "tradeSymbol" ).setText( "IBM" );
+
+		Element val = stock.addElement( "currentValuation" ).addElement( "valuation" );
+		val.appendContent( stock );
+		val.addElement( "valuationDate" ).setText( new java.util.Date().toString() );
+		val.addElement( "value" ).setText( "121.00" );
+
+		dom4j.save( Stock.class.getName(), stock );
+		dom4j.flush();
+
+		txn.rollback();
+		pojos.close();
+
+		assertTrue( !pojos.isOpen() );
+		assertTrue( !dom4j.isOpen() );
+
+		prettyPrint( stock );
+
+		testData.destroy();
+	}
+
+	public void testDom4jHQL() {
+		TestData testData = new TestData();
+		testData.create();
+
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+		org.hibernate.Session dom4j = session.getSession( EntityMode.DOM4J );
+
+		List result = dom4j.createQuery( "from Stock" ).list();
+
+		assertEquals( "Incorrect result size", 1, result.size() );
+		Element element = ( Element ) result.get( 0 );
+		assertEquals( "Something wrong!", testData.stockId, Long.valueOf( element.attributeValue( "id" ) ) );
+
+		System.out.println( "**** XML: ****************************************************" );
+		prettyPrint( element );
+		System.out.println( "**************************************************************" );
+
+		txn.rollback();
+		session.close();
+
+		testData.destroy();
+	}
+
+	private class TestData {
+		private Long stockId;
+
+		private void create() {
+			Session session = getSessions().openSession();
+			session.beginTransaction();
+			Stock stock = new Stock();
+			stock.setTradeSymbol( "JBOSS" );
+			Valuation valuation = new Valuation();
+			valuation.setStock( stock );
+			valuation.setValuationDate( new Date( new java.util.Date().getTime() ) );
+			valuation.setValue( new Double( 200.0 ) );
+			stock.setCurrentValuation( valuation );
+			stock.getValuations().add( valuation );
+
+			session.save( stock );
+			session.save( valuation );
+
+			session.getTransaction().commit();
+			session.close();
+
+			stockId = stock.getId();
+		}
+
+		private void destroy() {
+			Session session = getSessions().openSession();
+			session.beginTransaction();
+			Iterator stocks = session.createQuery( "from Stock" ).list().iterator();
+			while ( stocks.hasNext() ) {
+				final Stock stock = ( Stock ) stocks.next();
+				stock.setCurrentValuation( null );
+				session.flush();
+				Iterator valuations = stock.getValuations().iterator();
+				while ( valuations.hasNext() ) {
+					session.delete( valuations.next() );
+				}
+				session.delete( stock );
+			}
+			session.getTransaction().commit();
+			session.close();
+		}
+	}
+
+	private void prettyPrint(Element element) {
+		//System.out.println( element.asXML() );
+		try {
+			OutputFormat format = OutputFormat.createPrettyPrint();
+			new XMLWriter( System.out, format ).write( element );
+			System.out.println();
+		}
+		catch ( Throwable t ) {
+			System.err.println( "Unable to pretty print element : " + t );
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Stock.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Stock.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Stock.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping
+        SYSTEM
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.entitymode.multi">
+
+	<class table="STOCK" name="Stock" node="stock">
+
+		<id name="id" column="STOCK_ID" node="@id">
+			<generator class="increment"/>
+		</id>
+
+		<property name="tradeSymbol" type="string" column="SYMBOL"/>
+
+		<many-to-one name="currentValuation" class="Valuation" column="CURR_VAL_ID" cascade="all" />
+
+		<set name="valuations" cascade="all" lazy="true">
+			<key column="STOCK_ID"/>
+			<one-to-many class="Valuation"/>
+		</set>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Stock.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Stock.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Stock.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+// $Id: Stock.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.entitymode.multi;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * POJO implementation of Stock entity.
+ *
+ * @author Steve Ebersole
+ */
+public class Stock {
+	private Long id;
+	private String tradeSymbol;
+	private Valuation currentValuation;
+	private Set valuations = new HashSet();
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getTradeSymbol() {
+		return tradeSymbol;
+	}
+
+	public void setTradeSymbol(String tradeSymbol) {
+		this.tradeSymbol = tradeSymbol;
+	}
+
+	public Valuation getCurrentValuation() {
+		return currentValuation;
+	}
+
+	public void setCurrentValuation(Valuation currentValuation) {
+		this.currentValuation = currentValuation;
+	}
+
+	public Set getValuations() {
+		return valuations;
+	}
+
+	public void setValuations(Set valuations) {
+		this.valuations = valuations;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Valuation.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Valuation.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Valuation.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping
+        SYSTEM
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.entitymode.multi">
+
+	<class table="STOCK_VAL" name="Valuation" node="valuation">
+
+		<id name="id" column="VAL_ID" node="@id">
+			<generator class="increment"/>
+		</id>
+
+		<many-to-one name="stock" embed-xml="false"
+			class="Stock" column="STOCK_ID" cascade="none" />
+
+		<property name="valuationDate" type="date" column="DT"/>
+		<property name="value" type="double" column="VAL"/>
+
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Valuation.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Valuation.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/entitymode/multi/Valuation.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+// $Id: Valuation.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.entitymode.multi;
+
+import java.util.Date;
+
+/**
+ * Implementation of Valuation.
+ *
+ * @author Steve Ebersole
+ */
+public class Valuation {
+	private Long id;
+	private Stock stock;
+	private Date valuationDate;
+	private Double value;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Stock getStock() {
+		return stock;
+	}
+
+	public void setStock(Stock stock) {
+		this.stock = stock;
+	}
+
+	public Date getValuationDate() {
+		return valuationDate;
+	}
+
+	public void setValuationDate(Date valuationDate) {
+		this.valuationDate = valuationDate;
+	}
+
+	public Double getValue() {
+		return value;
+	}
+
+	public void setValue(Double value) {
+		this.value = value;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/Group.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/Group.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/Group.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.exception" >
+	<class name="Group" table="T_GROUP" >
+		<id name="id" unsaved-value="null" column="group_id" >
+			<generator class="native"/>
+		</id>
+		<property name="name" type="string" column="name" />
+		<set name="members" inverse="true" table="T_MEMBERSHIP" cascade="none">
+			<key column="group_id"/>
+			<many-to-many class="User" column="user_id"/>
+		</set>
+	</class>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/Group.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/Group.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/Group.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+// $Id: Group.java 4746 2004-11-11 20:57:28Z steveebersole $
+package org.hibernate.test.exception;
+
+import java.util.Set;
+
+/**
+ * Implementation of Group.
+ *
+ * @author Steve Ebersole
+ */
+public class Group {
+	private Long id;
+	private String name;
+	private Set members;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Set getMembers() {
+		return members;
+	}
+
+	public void setMembers(Set members) {
+		this.members = members;
+	}
+
+	public void addMember(User member) {
+		if (member == null) {
+			throw new IllegalArgumentException("Member to add cannot be null");
+		}
+
+		this.members.add(member);
+		member.getMemberships().add(this);
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/SQLExceptionConversionTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/SQLExceptionConversionTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/SQLExceptionConversionTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,112 @@
+// $Id: SQLExceptionConversionTest.java 11339 2007-03-23 12:51:38Z steve.ebersole at jboss.com $
+package org.hibernate.test.exception;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+import junit.framework.Test;
+
+import org.hibernate.JDBCException;
+import org.hibernate.Session;
+import org.hibernate.dialect.MySQLMyISAMDialect;
+import org.hibernate.exception.ConstraintViolationException;
+import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.exception.SQLGrammarException;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.util.JDBCExceptionReporter;
+
+/**
+ * Implementation of SQLExceptionConversionTest.
+ *
+ * @author Steve Ebersole
+ */
+public class SQLExceptionConversionTest extends FunctionalTestCase {
+
+	public SQLExceptionConversionTest(String name) {
+		super(name);
+	}
+
+	public String[] getMappings() {
+		return new String[] {"exception/User.hbm.xml", "exception/Group.hbm.xml"};
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite(SQLExceptionConversionTest.class);
+	}
+
+	public void testIntegrityViolation() throws Exception {
+		if ( getDialect() instanceof MySQLMyISAMDialect ) {
+			reportSkip( "MySQL (ISAM) does not support FK violation checking", "exception conversion" );
+			return;
+		}
+
+		SQLExceptionConverter converter = getDialect().buildSQLExceptionConverter();
+
+		Session session = openSession();
+		Connection connection = session.connection();
+
+		// Attempt to insert some bad values into the T_MEMBERSHIP table that should
+		// result in a constraint violation
+		PreparedStatement ps = null;
+		try {
+			ps = connection.prepareStatement("INSERT INTO T_MEMBERSHIP (user_id, group_id) VALUES (?, ?)");
+			ps.setLong(1, 52134241);    // Non-existent user_id
+			ps.setLong(2, 5342);        // Non-existent group_id
+			ps.executeUpdate();
+
+			fail("INSERT should have failed");
+		}
+		catch(SQLException sqle) {
+			JDBCExceptionReporter.logExceptions(sqle, "Just output!!!!");
+			JDBCException jdbcException = converter.convert(sqle, null, null);
+			assertEquals( "Bad conversion [" + sqle.getMessage() + "]", ConstraintViolationException.class , jdbcException.getClass() );
+			ConstraintViolationException ex = (ConstraintViolationException) jdbcException;
+			System.out.println("Violated constraint name: " + ex.getConstraintName());
+		}
+		finally {
+			if ( ps != null ) {
+				try {
+					ps.close();
+				}
+				catch( Throwable ignore ) {
+					// ignore...
+				}
+			}
+		}
+
+		session.close();
+	}
+
+	public void testBadGrammar() throws Exception {
+		SQLExceptionConverter converter = getDialect().buildSQLExceptionConverter();
+
+		Session session = openSession();
+		Connection connection = session.connection();
+
+        // prepare a query against a non-existent table
+		PreparedStatement ps = null;
+		try {
+			ps = connection.prepareStatement("SELECT user_id, user_name FROM tbl_user");
+			ps.executeQuery();
+
+			fail("SQL compilation should have failed");
+		}
+		catch( SQLException sqle ) {
+			assertEquals( "Bad conversion [" + sqle.getMessage() + "]", SQLGrammarException.class, converter.convert(sqle, null, null).getClass() );
+		}
+		finally {
+			if ( ps != null ) {
+				try {
+					ps.close();
+				}
+				catch( Throwable ignore ) {
+					// ignore...
+				}
+			}
+		}
+
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/User.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/User.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/User.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.exception" >
+	<class name="User" table="T_USER" >
+		<id name="id" unsaved-value="null" column="user_id" >
+			<generator class="native"/>
+		</id>
+		<property name="username" type="string" column="user_name" />
+		<set name="memberships" inverse="false" table="T_MEMBERSHIP" cascade="none">
+			<key column="user_id"/>
+			<many-to-many class="Group" column="group_id"/>
+		</set>
+	</class>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/exception/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+// $Id: User.java 4746 2004-11-11 20:57:28Z steveebersole $
+package org.hibernate.test.exception;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * Implementation of User.
+ *
+ * @author Steve Ebersole
+ */
+public class User {
+	private Long id;
+	private String username;
+	private Set memberships = new HashSet();
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getUsername() {
+		return username;
+	}
+
+	public void setUsername(String username) {
+		this.username = username;
+	}
+
+	public Set getMemberships() {
+		return memberships;
+	}
+
+	public void setMemberships(Set memberships) {
+		this.memberships = memberships;
+	}
+
+	public void addMembership(Group membership) {
+		if (membership == null) {
+			throw new IllegalArgumentException("Membership to add cannot be null");
+		}
+
+		this.memberships.add(membership);
+		membership.getMembers().add(this);
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Customer.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Customer.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Customer.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates 
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.extendshbm">
+	<subclass name="Customer" extends="Person">
+				<property name="comments"/>
+				<many-to-one name="salesperson"/>
+	</subclass>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: Customer.java 5011 2004-12-19 22:01:25Z maxcsaucdk $
+package org.hibernate.test.extendshbm;
+
+/**
+ * @author Gavin King
+ */
+public class Customer extends Person {
+	private Employee salesperson;
+	private String comments;
+
+	/**
+	 * @return Returns the salesperson.
+	 */
+	public Employee getSalesperson() {
+		return salesperson;
+	}
+	/**
+	 * @param salesperson The salesperson to set.
+	 */
+	public void setSalesperson(Employee salesperson) {
+		this.salesperson = salesperson;
+	}
+	/**
+	 * @return Returns the comments.
+	 */
+	public String getComments() {
+		return comments;
+	}
+	/**
+	 * @param comments The comments to set.
+	 */
+	public void setComments(String comments) {
+		this.comments = comments;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Employee.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Employee.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Employee.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates 
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.extendshbm">
+	<subclass name="Employee" extends="Person">
+				<property name="title"
+					length="20"/>
+				<property name="salary"
+					length="0"/>
+				<many-to-one name="manager"/>
+		</subclass>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Employee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Employee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Employee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: Employee.java 5011 2004-12-19 22:01:25Z maxcsaucdk $
+package org.hibernate.test.extendshbm;
+
+import java.math.BigDecimal;
+
+/**
+ * @author Gavin King
+ */
+public class Employee extends Person {
+	private String title;
+	private BigDecimal salary;
+	private Employee manager;
+	/**
+	 * @return Returns the title.
+	 */
+	public String getTitle() {
+		return title;
+	}
+	/**
+	 * @param title The title to set.
+	 */
+	public void setTitle(String title) {
+		this.title = title;
+	}
+	/**
+	 * @return Returns the manager.
+	 */
+	public Employee getManager() {
+		return manager;
+	}
+	/**
+	 * @param manager The manager to set.
+	 */
+	public void setManager(Employee manager) {
+		this.manager = manager;
+	}
+	/**
+	 * @return Returns the salary.
+	 */
+	public BigDecimal getSalary() {
+		return salary;
+	}
+	/**
+	 * @param salary The salary to set.
+	 */
+	public void setSalary(BigDecimal salary) {
+		this.salary = salary;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/ExtendsTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/ExtendsTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/ExtendsTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,192 @@
+//$Id: ExtendsTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.extendshbm;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.junit.UnitTestCase;
+
+/**
+ * @author Gavin King
+ */
+public class ExtendsTest extends UnitTestCase {
+
+	public ExtendsTest(String str) {
+		super( str );
+	}
+
+	public static Test suite() {
+		return new TestSuite( ExtendsTest.class );
+	}
+
+	private String getBaseForMappings() {
+		return "org/hibernate/test/";
+	}
+
+	public void testAllInOne() {
+		Configuration cfg = new Configuration();
+
+		cfg.addResource( getBaseForMappings() + "extendshbm/allinone.hbm.xml" );
+		assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" ) );
+		assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Person" ) );
+		assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Employee" ) );
+	}
+
+	public void testOutOfOrder() {
+		Configuration cfg = new Configuration();
+
+		try {
+			cfg.addResource( getBaseForMappings() + "extendshbm/Customer.hbm.xml" );
+			assertNull(
+					"cannot be in the configuration yet!",
+					cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" )
+			);
+			cfg.addResource( getBaseForMappings() + "extendshbm/Person.hbm.xml" );
+			cfg.addResource( getBaseForMappings() + "extendshbm/Employee.hbm.xml" );
+
+			cfg.buildSessionFactory();
+
+			assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" ) );
+			assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Person" ) );
+			assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Employee" ) );
+
+		}
+		catch ( HibernateException e ) {
+			fail( "should not fail with exception! " + e );
+		}
+
+	}
+
+	public void testNwaitingForSuper() {
+		Configuration cfg = new Configuration();
+
+		try {
+			cfg.addResource( getBaseForMappings() + "extendshbm/Customer.hbm.xml" );
+			assertNull(
+					"cannot be in the configuration yet!",
+					cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" )
+			);
+			cfg.addResource( getBaseForMappings() + "extendshbm/Employee.hbm.xml" );
+			assertNull(
+					"cannot be in the configuration yet!",
+					cfg.getClassMapping( "org.hibernate.test.extendshbm.Employee" )
+			);
+			cfg.addResource( getBaseForMappings() + "extendshbm/Person.hbm.xml" );
+
+			cfg.buildMappings();
+
+			assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Person" ) );
+			assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Employee" ) );
+			assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" ) );
+
+
+		}
+		catch ( HibernateException e ) {
+			e.printStackTrace();
+			fail( "should not fail with exception! " + e );
+
+		}
+
+	}
+
+	public void testMissingSuper() {
+		Configuration cfg = new Configuration();
+
+		try {
+			cfg.addResource( getBaseForMappings() + "extendshbm/Customer.hbm.xml" );
+			assertNull(
+					"cannot be in the configuration yet!",
+					cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" )
+			);
+			cfg.addResource( getBaseForMappings() + "extendshbm/Employee.hbm.xml" );
+
+			cfg.buildSessionFactory();
+
+			fail( "Should not be able to build sessionfactory without a Person" );
+		}
+		catch ( HibernateException e ) {
+
+		}
+
+	}
+
+	public void testAllSeparateInOne() {
+		Configuration cfg = new Configuration();
+
+		try {
+			cfg.addResource( getBaseForMappings() + "extendshbm/allseparateinone.hbm.xml" );
+
+			cfg.buildSessionFactory();
+
+			assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" ) );
+			assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Person" ) );
+			assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Employee" ) );
+
+		}
+		catch ( HibernateException e ) {
+			fail( "should not fail with exception! " + e );
+		}
+
+	}
+
+	public void testJoinedSubclassAndEntityNamesOnly() {
+		Configuration cfg = new Configuration();
+
+		try {
+			cfg.addResource( getBaseForMappings() + "extendshbm/entitynames.hbm.xml" );
+
+			cfg.buildMappings();
+
+			assertNotNull( cfg.getClassMapping( "EntityHasName" ) );
+			assertNotNull( cfg.getClassMapping( "EntityCompany" ) );
+
+		}
+		catch ( HibernateException e ) {
+			e.printStackTrace();
+			fail( "should not fail with exception! " + e );
+
+		}
+	}
+
+	public void testEntityNamesWithPackageFailureExpected() {
+		Configuration cfg = new Configuration();
+		try {
+			cfg.addResource( getBaseForMappings() + "extendshbm/packageentitynames.hbm.xml" );
+
+			cfg.buildMappings();
+
+			assertNotNull( cfg.getClassMapping( "EntityHasName" ) );
+			assertNotNull( cfg.getClassMapping( "EntityCompany" ) );
+
+		}
+		catch ( HibernateException e ) {
+			e.printStackTrace();
+			fail( "should not fail with exception! " + e );
+
+		}
+	}
+
+
+	public void testUnionSubclass() {
+		Configuration cfg = new Configuration();
+
+		try {
+			cfg.addResource( getBaseForMappings() + "extendshbm/unionsubclass.hbm.xml" );
+
+			cfg.buildMappings();
+
+			assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Person" ) );
+			assertNotNull( cfg.getClassMapping( "org.hibernate.test.extendshbm.Customer" ) );
+
+		}
+		catch ( HibernateException e ) {
+			e.printStackTrace();
+			fail( "should not fail with exception! " + e );
+
+		}
+	}
+
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates 
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.extendshbm">
+	<class name="Person">
+		
+		<id name="id" 
+			column="person_id" 
+			unsaved-value="0">
+			<generator class="native"/>
+		</id>
+		
+		<discriminator 
+			type="string"
+			/>
+		
+		<property name="name" 
+			not-null="true"
+			length="80"/>
+			
+	</class>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+//$Id: Person.java 5011 2004-12-19 22:01:25Z maxcsaucdk $
+package org.hibernate.test.extendshbm;
+
+
+/**
+ * @author Gavin King
+ */
+public class Person {
+	private long id;
+	private String name;
+	private char sex;
+	
+	/**
+	 * @return Returns the sex.
+	 */
+	public char getSex() {
+		return sex;
+	}
+	/**
+	 * @param sex The sex to set.
+	 */
+	public void setSex(char sex) {
+		this.sex = sex;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the identity.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param identity The identity to set.
+	 */
+	public void setName(String identity) {
+		this.name = identity;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/allinone.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/allinone.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/allinone.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates 
+
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.extendshbm">
+	
+	<class name="Person">
+		
+		<id name="id" 
+			column="person_id" 
+			unsaved-value="0">
+			<generator class="native"/>
+		</id>
+		
+		<discriminator 
+			type="string"/>
+		
+		<property name="name" 
+			not-null="true"
+			length="80"/>
+			
+		<subclass name="Employee">
+				<property name="title"
+					length="20"/>
+				<property name="salary"
+					length="0"/>
+				<many-to-one name="manager"/>
+		</subclass>
+		
+		<subclass name="Customer">
+				<property name="comments"/>
+				<many-to-one name="salesperson"/>
+		</subclass>
+		
+	</class>
+	
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/allseparateinone.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/allseparateinone.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/allseparateinone.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates 
+
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.extendshbm">
+	
+	<class name="Person">
+		
+		<id name="id" 
+			column="person_id" 
+			unsaved-value="0">
+			<generator class="native"/>
+		</id>
+		
+		<discriminator 
+			type="string"/>
+		
+		<property name="name" 
+			not-null="true"
+			length="80"/>
+			
+		<subclass name="Employee">
+				<property name="title"
+					length="20"/>
+				<property name="salary"
+					length="0"/>
+				<many-to-one name="manager"/>
+		</subclass>
+		
+		
+		
+	</class>
+	
+	
+	<subclass name="Customer" extends="Person">
+				<property name="comments"/>
+				<many-to-one name="salesperson"/>
+	</subclass>
+
+	
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/entitynames.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/entitynames.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/entitynames.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+<!DOCTYPE hibernate-mapping
+        PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+    <class lazy="true" entity-name="EntityHasName" table="F5_ENTITY_HASNAME">
+        <id name="id" column="ID" type="long">
+            <generator class="native"/>
+        </id>
+        <property name="attrName" type="string">
+            <column name="NAME"/>
+        </property>
+    </class>
+    <joined-subclass lazy="true" entity-name="EntityCompany" table="F5_ENTITY_COMPANY" extends="EntityHasName">
+        <key column="REF_ID"/>
+        <many-to-one name="parent" entity-name="EntityHasName"/>
+    </joined-subclass>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/packageentitynames.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/packageentitynames.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/packageentitynames.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+<!DOCTYPE hibernate-mapping
+        PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.extendshbm">
+    <class lazy="true" entity-name="EntityHasName" table="F5_ENTITY_HASNAME">
+        <id name="id" column="ID" type="long">
+            <generator class="native"/>
+        </id>
+        <property name="attrName" type="string">
+            <column name="NAME"/>
+        </property>
+    </class>
+    <joined-subclass lazy="true" entity-name="EntityCompany" table="F5_ENTITY_COMPANY" extends="EntityHasName">
+        <key column="REF_ID"/>
+        <many-to-one name="parent" entity-name="EntityHasName"/>
+    </joined-subclass>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/unionsubclass.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/unionsubclass.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extendshbm/unionsubclass.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates 
+
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.extendshbm">
+	
+		<class name="Person">
+		
+		<id name="id" 
+			column="person_id" 
+			unsaved-value="0">
+			<generator class="native"/>
+		</id>
+		
+		<discriminator 
+			type="string"/>
+		
+		<property name="name" 
+			not-null="true"
+			length="80"/>
+	
+	</class>
+	
+	
+	<union-subclass name="Customer" extends="Person">
+				<property name="comments"/>
+				<many-to-one name="salesperson"/>
+	</union-subclass>
+
+        <subclass name="Employee" extends="Person">
+				<property name="title"
+					length="20"/>
+				<property name="salary"
+					length="0"/>
+				<many-to-one name="manager"/>
+		</subclass>
+		
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/Document.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/Document.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/Document.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: Document.java 7635 2005-07-24 23:04:30Z oneovthafew $
+package org.hibernate.test.extralazy;
+
+public class Document {
+
+	private String title;
+	private String content;
+	private User owner;
+	
+	Document() {}
+	
+	public Document(String title, String content, User owner) {
+		this.content = content;
+		this.owner = owner;
+		this.title = title;
+		owner.getDocuments().add(this);
+	}
+
+	public String getContent() {
+		return content;
+	}
+	public void setContent(String content) {
+		this.content = content;
+	}
+	public User getOwner() {
+		return owner;
+	}
+	public void setOwner(User owner) {
+		this.owner = owner;
+	}
+	public String getTitle() {
+		return title;
+	}
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/Document.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/ExtraLazyTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/ExtraLazyTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/ExtraLazyTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,221 @@
+//$Id: ExtraLazyTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.extralazy;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class ExtraLazyTest extends FunctionalTestCase {
+
+	public ExtraLazyTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "extralazy/UserGroup.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ExtraLazyTest.class );
+	}
+
+	public void testOrphanDelete() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User gavin = new User("gavin", "secret");
+		Document hia = new Document("HiA", "blah blah blah", gavin);
+		Document hia2 = new Document("HiA2", "blah blah blah blah", gavin);
+		s.persist(gavin);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		gavin = (User) s.get(User.class, "gavin");
+		assertEquals( 2, gavin.getDocuments().size() );
+		gavin.getDocuments().remove(hia2);
+		assertFalse( gavin.getDocuments().contains(hia2) );
+		assertTrue( gavin.getDocuments().contains(hia) );
+		assertEquals( 1, gavin.getDocuments().size() );
+		assertFalse( Hibernate.isInitialized( gavin.getDocuments() ) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		gavin = (User) s.get(User.class, "gavin");
+		assertEquals( 1, gavin.getDocuments().size() );
+		assertFalse( gavin.getDocuments().contains(hia2) );
+		assertTrue( gavin.getDocuments().contains(hia) );
+		assertFalse( Hibernate.isInitialized( gavin.getDocuments() ) );
+		assertNull( s.get(Document.class, "HiA2") );
+		gavin.getDocuments().clear();
+		assertTrue( Hibernate.isInitialized( gavin.getDocuments() ) );
+		s.delete(gavin);
+		t.commit();
+		s.close();
+	}
+	
+	public void testGet() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User gavin = new User("gavin", "secret");
+		User turin = new User("turin", "tiger");
+		Group g = new Group("developers");
+		g.getUsers().put("gavin", gavin);
+		g.getUsers().put("turin", turin);
+		s.persist(g);
+		gavin.getSession().put( "foo", new SessionAttribute("foo", "foo bar baz") );
+		gavin.getSession().put( "bar", new SessionAttribute("bar", "foo bar baz 2") );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		g = (Group) s.get(Group.class, "developers");
+		gavin = (User) g.getUsers().get("gavin");
+		turin = (User) g.getUsers().get("turin");
+		assertNotNull(gavin);
+		assertNotNull(turin);
+		assertNull( g.getUsers().get("emmanuel") );
+		assertFalse( Hibernate.isInitialized( g.getUsers() ) );
+		assertNotNull( gavin.getSession().get("foo") );
+		assertNull( turin.getSession().get("foo") );
+		assertFalse( Hibernate.isInitialized( gavin.getSession() ) );
+		assertFalse( Hibernate.isInitialized( turin.getSession() ) );
+		s.delete(gavin);
+		s.delete(turin);
+		s.delete(g);
+		t.commit();
+		s.close();
+	}
+	
+	public void testRemoveClear() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User gavin = new User("gavin", "secret");
+		User turin = new User("turin", "tiger");
+		Group g = new Group("developers");
+		g.getUsers().put("gavin", gavin);
+		g.getUsers().put("turin", turin);
+		s.persist(g);
+		gavin.getSession().put( "foo", new SessionAttribute("foo", "foo bar baz") );
+		gavin.getSession().put( "bar", new SessionAttribute("bar", "foo bar baz 2") );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		g = (Group) s.get(Group.class, "developers");
+		gavin = (User) g.getUsers().get("gavin");
+		turin = (User) g.getUsers().get("turin");
+		assertFalse( Hibernate.isInitialized( g.getUsers() ) );
+		g.getUsers().clear();
+		gavin.getSession().remove("foo");
+		assertTrue( Hibernate.isInitialized( g.getUsers() ) );
+		assertTrue( Hibernate.isInitialized( gavin.getSession() ) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		g = (Group) s.get(Group.class, "developers");
+		assertTrue( g.getUsers().isEmpty() );
+		assertFalse( Hibernate.isInitialized( g.getUsers() ) );
+		gavin = (User) s.get(User.class, "gavin");
+		assertFalse( gavin.getSession().containsKey("foo") );
+		assertFalse( Hibernate.isInitialized( gavin.getSession() ) );
+		s.delete(gavin);
+		s.delete(turin);
+		s.delete(g);
+		t.commit();
+		s.close();
+	}
+	
+	public void testIndexFormulaMap() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User gavin = new User("gavin", "secret");
+		User turin = new User("turin", "tiger");
+		Group g = new Group("developers");
+		g.getUsers().put("gavin", gavin);
+		g.getUsers().put("turin", turin);
+		s.persist(g);
+		gavin.getSession().put( "foo", new SessionAttribute("foo", "foo bar baz") );
+		gavin.getSession().put( "bar", new SessionAttribute("bar", "foo bar baz 2") );
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		g = (Group) s.get(Group.class, "developers");
+		assertEquals( g.getUsers().size(), 2 );
+		g.getUsers().remove("turin");
+		Map smap = ( (User) g.getUsers().get("gavin") ).getSession();
+		assertEquals(smap.size(), 2);
+		smap.remove("bar");
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		g = (Group) s.get(Group.class, "developers");
+		assertEquals( g.getUsers().size(), 1 );
+		smap = ( (User) g.getUsers().get("gavin") ).getSession();
+		assertEquals(smap.size(), 1);
+		gavin = (User) g.getUsers().put("gavin", turin);
+		s.delete(gavin);
+		assertEquals( s.createQuery("select count(*) from SessionAttribute").uniqueResult(), new Long(0) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		g = (Group) s.get(Group.class, "developers");
+		assertEquals( g.getUsers().size(), 1 );
+		turin = (User) g.getUsers().get("turin");
+		smap = turin.getSession();
+		assertEquals(smap.size(), 0);
+		assertEquals( s.createQuery("select count(*) from User").uniqueResult(), new Long(1) );
+		s.delete(g);
+		s.delete(turin);
+		assertEquals( s.createQuery("select count(*) from User").uniqueResult(), new Long(0) );
+		t.commit();
+		s.close();
+	}
+	
+	public void testSQLQuery() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User gavin = new User("gavin", "secret");
+		User turin = new User("turin", "tiger");
+		gavin.getSession().put( "foo", new SessionAttribute("foo", "foo bar baz") );
+		gavin.getSession().put( "bar", new SessionAttribute("bar", "foo bar baz 2") );
+		s.persist(gavin);
+		s.persist(turin);
+		s.flush();
+		s.clear();
+		List results = s.getNamedQuery("userSessionData").setParameter("uname", "%in").list();
+		assertEquals( results.size(), 2 );
+		gavin = (User) ( (Object[]) results.get(0) )[0];
+		assertEquals( gavin.getName(), "gavin" );
+		assertEquals( gavin.getSession().size(), 2 );
+		s.createQuery("delete SessionAttribute").executeUpdate();
+		s.createQuery("delete User").executeUpdate();
+		t.commit();
+		s.close();
+		
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/ExtraLazyTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/Group.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/Group.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/Group.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+//$Id: Group.java 7628 2005-07-24 06:55:01Z oneovthafew $
+package org.hibernate.test.extralazy;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Gavin King
+ */
+public class Group {
+	private String name;
+	private Map users = new HashMap();
+	Group() {}
+	public Group(String n) {
+		name = n;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public Map getUsers() {
+		return users;
+	}
+	public void setUsers(Map users) {
+		this.users = users;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/Group.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/SessionAttribute.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/SessionAttribute.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/SessionAttribute.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+//$Id: SessionAttribute.java 7628 2005-07-24 06:55:01Z oneovthafew $
+package org.hibernate.test.extralazy;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class SessionAttribute {
+	private Long id;
+	private String name;
+	private String stringData;
+	private Serializable objectData;
+	SessionAttribute() {}
+	public SessionAttribute(String name, Serializable obj) {
+		this.name = name;
+		this.objectData = obj;
+	}
+	public SessionAttribute(String name, String str) {
+		this.name = name;
+		this.stringData = str;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public Serializable getObjectData() {
+		return objectData;
+	}
+	public void setObjectData(Serializable objectData) {
+		this.objectData = objectData;
+	}
+	public String getStringData() {
+		return stringData;
+	}
+	public void setStringData(String stringData) {
+		this.stringData = stringData;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/SessionAttribute.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+//$Id: User.java 7635 2005-07-24 23:04:30Z oneovthafew $
+package org.hibernate.test.extralazy;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class User {
+	private String name;
+	private String password;
+	private Map session = new HashMap();
+	private Set documents = new HashSet();
+	User() {}
+	public User(String n, String pw) {
+		name=n;
+		password = pw;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getPassword() {
+		return password;
+	}
+	public void setPassword(String password) {
+		this.password = password;
+	}
+	public Map getSession() {
+		return session;
+	}
+	public void setSession(Map session) {
+		this.session = session;
+	}
+	public Set getDocuments() {
+		return documents;
+	}
+	public void setDocuments(Set documents) {
+		this.documents = documents;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/User.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/UserGroup.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/UserGroup.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/UserGroup.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+     
+-->
+
+<hibernate-mapping package="org.hibernate.test.extralazy">
+	
+	<class name="Group" table="groups">
+		<id name="name"/>
+		<map name="users" cascade="persist" 
+				table="group_user" lazy="extra">
+			<key column="groupName"/>
+			<map-key formula="lower(personName)" type="string"/>
+			<many-to-many column="personName" class="User"/>
+		</map>
+	</class>
+	
+	<class name="User" table="users">
+		<id name="name"/>
+		<property name="password"/>
+		<map name="session" lazy="extra" 
+				cascade="persist,save-update,delete,delete-orphan">
+			<key column="userName" not-null="true"/>
+			<map-key column="name" type="string"/>
+			<one-to-many class="SessionAttribute"/>
+		</map>
+		<set name="documents" inverse="true" 
+				lazy="extra" cascade="all,delete-orphan">
+			<key column="owner"/>
+			<one-to-many class="Document"/>
+		</set>
+	</class>
+	
+	<class name="Document" table="documents">
+		<id name="title"/>
+		<property name="content" type="text"/>
+		<many-to-one name="owner" not-null="true"/>
+	</class>
+	
+	<class name="SessionAttribute" table="session_attributes">
+		<id name="id" access="field">
+			<generator class="native"/>
+		</id>
+		<property name="name" not-null="true" 
+				insert="false" update="false"/>
+		<property name="stringData"/>
+		<property name="objectData"/>
+	</class>
+	
+	<sql-query name="userSessionData">
+		<return alias="u" class="User"/>
+		<return-join alias="s" property="u.session"/>
+		select 
+			lower(u.name) as {u.name}, lower(u.password) as {u.password}, 
+			lower(s.userName) as {s.key}, lower(s.name) as {s.index}, s.id as {s.element}, 
+			{s.element.*}
+		from users u 
+		join session_attributes s on lower(s.userName) = lower(u.name)
+		where u.name like :uname
+	</sql-query>	
+	
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/extralazy/UserGroup.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Category.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Category.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Category.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping
+        SYSTEM
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.filter">
+
+    <class name="Category" table="CATEGORY">
+    	<id name="id" column="CAT_ID" >
+    		<generator class="native"/>
+    	</id>
+
+    	<property name="name" type="string"/>
+	    <property name="effectiveStartDate" column="eff_start_dt" type="java.util.Date"/>
+	    <property name="effectiveEndDate" column="eff_end_dt" type="java.util.Date"/>
+
+	    <set cascade="none" inverse="true" name="products" table="PROD_CAT">
+		    <key column="CAT_ID"/>
+		    <many-to-many column="PROD_ID" class="Product"/>
+	    </set>
+
+	    <filter name="effectiveDate" condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Category.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Category.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Category.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,104 @@
+// $Id: Category.java 6507 2005-04-25 16:57:32Z steveebersole $
+package org.hibernate.test.filter;
+
+import java.util.Date;
+import java.util.Set;
+
+/**
+ * Implementation of Category.
+ *
+ * @author Steve Ebersole
+ */
+public class Category {
+	private Long id;
+	private String name;
+	private Date effectiveStartDate;
+	private Date effectiveEndDate;
+	private Set products;
+
+	public Category() {
+	}
+
+	public Category(String name) {
+		this.name = name;
+	}
+
+	public Category(String name, Date effectiveStartDate, Date effectiveEndDate) {
+		this.name = name;
+		this.effectiveStartDate = effectiveStartDate;
+		this.effectiveEndDate = effectiveEndDate;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Date getEffectiveStartDate() {
+		return effectiveStartDate;
+	}
+
+	public void setEffectiveStartDate(Date effectiveStartDate) {
+		this.effectiveStartDate = effectiveStartDate;
+	}
+
+	public Date getEffectiveEndDate() {
+		return effectiveEndDate;
+	}
+
+	public void setEffectiveEndDate(Date effectiveEndDate) {
+		this.effectiveEndDate = effectiveEndDate;
+	}
+
+	public Set getProducts() {
+		return products;
+	}
+
+	public void setProducts(Set products) {
+		this.products = products;
+	}
+
+	public boolean equals(Object o) {
+		if ( this == o ) return true;
+		if ( !( o instanceof Category ) ) return false;
+
+		final Category category = ( Category ) o;
+
+		if ( !name.equals( category.name ) ) {
+			return false;
+		}
+
+		if ( effectiveEndDate != null ?
+		        !effectiveEndDate.equals( category.effectiveEndDate ) :
+		        category.effectiveEndDate != null ) {
+			return false;
+		}
+
+		if ( effectiveStartDate != null ?
+		        !effectiveStartDate.equals( category.effectiveStartDate ) :
+		        category.effectiveStartDate != null ) {
+			return false;
+		}
+
+		return true;
+	}
+
+	public int hashCode() {
+		int result;
+		result = name.hashCode();
+		result = 29 * result + ( effectiveStartDate != null ? effectiveStartDate.hashCode() : 0 );
+		result = 29 * result + ( effectiveEndDate != null ? effectiveEndDate.hashCode() : 0 );
+		return result;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Department.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Department.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Department.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping
+        SYSTEM
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.filter">
+
+    <class name="Department" table="DEPARTMENT">
+    	<id name="id" column="DEPT_ID" type="long">
+    		<generator class="native"/>
+    	</id>
+
+    	<property name="name" column="REG" type="string"/>
+
+	    <set name="salespersons" cascade="save-update" inverse="true">
+		    <key column="DEPT_ID"/>
+		    <one-to-many class="Salesperson"/>
+		    <filter name="seniorSalespersons"><![CDATA[`hire dt` < :asOfDate]]></filter>
+	    </set>
+
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Department.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Department.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Department.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+// $Id: Department.java 4448 2004-08-28 02:29:05Z steveebersole $
+package org.hibernate.test.filter;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * Implementation of Department.
+ *
+ * @author Steve
+ */
+public class Department {
+	private Long id;
+	private String name;
+	private Set salespersons = new HashSet();
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Set getSalespersons() {
+		return salespersons;
+	}
+
+	public void setSalespersons(Set salespersons) {
+		this.salespersons = salespersons;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/DynamicFilterTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/DynamicFilterTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/DynamicFilterTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,583 @@
+// $Id: DynamicFilterTest.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.test.filter;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.Test;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.EntityMode;
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.cache.entry.CollectionCacheEntry;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.Expression;
+import org.hibernate.impl.SessionFactoryImpl;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.transform.DistinctRootEntityResultTransformer;
+
+/**
+ * Implementation of DynamicFilterTest.
+ *
+ * @author Steve
+ */
+public class DynamicFilterTest extends FunctionalTestCase {
+
+	private Log log = LogFactory.getLog( DynamicFilterTest.class );
+
+	public DynamicFilterTest(String testName) {
+		super( testName );
+	}
+
+	public String[] getMappings() {
+		return new String[]{
+			"filter/defs.hbm.xml",
+			"filter/LineItem.hbm.xml",
+			"filter/Order.hbm.xml",
+			"filter/Product.hbm.xml",
+			"filter/Salesperson.hbm.xml",
+			"filter/Department.hbm.xml",
+			"filter/Category.hbm.xml"
+		};
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty( Environment.MAX_FETCH_DEPTH, "1" );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+		cfg.setProperty( Environment.USE_QUERY_CACHE, "true" );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( DynamicFilterTest.class );
+	}
+
+	public void testSecondLevelCachedCollectionsFiltering() {
+		TestData testData = new TestData();
+		testData.prepare();
+
+		Session session = openSession();
+		long ts = ( ( SessionImplementor ) session ).getTimestamp();
+
+		// Force a collection into the second level cache, with its non-filtered elements
+		Salesperson sp = ( Salesperson ) session.load( Salesperson.class, testData.steveId );
+		Hibernate.initialize( sp.getOrders() );
+		CollectionPersister persister = ( ( SessionFactoryImpl ) getSessions() )
+		        .getCollectionPersister( Salesperson.class.getName() + ".orders" );
+		assertTrue( "No cache for collection", persister.hasCache() );
+		CollectionCacheEntry cachedData = ( CollectionCacheEntry ) persister.getCacheAccessStrategy()
+		        .get( new CacheKey( testData.steveId, persister.getKeyType(), persister.getRole(), EntityMode.POJO, sfi() ), ts );
+		assertNotNull( "collection was not in cache", cachedData );
+
+		session.close();
+
+		session = openSession();
+		ts = ( ( SessionImplementor ) session ).getTimestamp();
+		session.enableFilter( "fulfilledOrders" ).setParameter( "asOfDate", testData.lastMonth.getTime() );
+		sp = ( Salesperson ) session.createQuery( "from Salesperson as s where s.id = :id" )
+		        .setLong( "id", testData.steveId.longValue() )
+		        .uniqueResult();
+		assertEquals( "Filtered-collection not bypassing 2L-cache", 1, sp.getOrders().size() );
+
+		CollectionCacheEntry cachedData2 = ( CollectionCacheEntry ) persister.getCacheAccessStrategy()
+		        .get( new CacheKey( testData.steveId, persister.getKeyType(), persister.getRole(), EntityMode.POJO, sfi() ), ts );
+		assertNotNull( "collection no longer in cache!", cachedData2 );
+		assertSame( "Different cache values!", cachedData, cachedData2 );
+
+		session.close();
+
+		session = openSession();
+		session.enableFilter( "fulfilledOrders" ).setParameter( "asOfDate", testData.lastMonth.getTime() );
+		sp = ( Salesperson ) session.load( Salesperson.class, testData.steveId );
+		assertEquals( "Filtered-collection not bypassing 2L-cache", 1, sp.getOrders().size() );
+
+		session.close();
+
+		// Finally, make sure that the original cached version did not get over-written
+		session = openSession();
+		sp = ( Salesperson ) session.load( Salesperson.class, testData.steveId );
+		assertEquals( "Actual cached version got over-written", 2, sp.getOrders().size() );
+
+		session.close();
+		testData.release();
+	}
+
+	public void testCombinedClassAndCollectionFiltersEnabled() {
+		TestData testData = new TestData();
+		testData.prepare();
+
+		Session session = openSession();
+		session.enableFilter( "regionlist" ).setParameterList( "regions", new String[]{"LA", "APAC"} );
+		session.enableFilter( "fulfilledOrders" ).setParameter( "asOfDate", testData.lastMonth.getTime() );
+
+		// test retreival through hql with the collection as non-eager
+		List salespersons = session.createQuery( "select s from Salesperson as s" ).list();
+		assertEquals( "Incorrect salesperson count", 1, salespersons.size() );
+		Salesperson sp = ( Salesperson ) salespersons.get( 0 );
+		assertEquals( "Incorrect order count", 1, sp.getOrders().size() );
+
+		session.clear();
+
+		// test retreival through hql with the collection join fetched
+		salespersons = session.createQuery( "select s from Salesperson as s left join fetch s.orders" ).list();
+		assertEquals( "Incorrect salesperson count", 1, salespersons.size() );
+		sp = ( Salesperson ) salespersons.get( 0 );
+		assertEquals( "Incorrect order count", 1, sp.getOrders().size() );
+
+		session.close();
+		testData.release();
+	}
+
+	public void testHqlFilters() {
+		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		// HQL test
+		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		log.info( "Starting HQL filter tests" );
+		TestData testData = new TestData();
+		testData.prepare();
+
+		Session session = openSession();
+		session.enableFilter( "region" ).setParameter( "region", "APAC" );
+
+		session.enableFilter( "effectiveDate" )
+		        .setParameter( "asOfDate", testData.lastMonth.getTime() );
+
+		log.info( "HQL against Salesperson..." );
+		List results = session.createQuery( "select s from Salesperson as s left join fetch s.orders" ).list();
+		assertTrue( "Incorrect filtered HQL result count [" + results.size() + "]", results.size() == 1 );
+		Salesperson result = ( Salesperson ) results.get( 0 );
+		assertTrue( "Incorrect collectionfilter count", result.getOrders().size() == 1 );
+
+		log.info( "HQL against Product..." );
+		results = session.createQuery( "from Product as p where p.stockNumber = ?" ).setInteger( 0, 124 ).list();
+		assertTrue( results.size() == 1 );
+
+		session.close();
+		testData.release();
+	}
+
+	public void testCriteriaQueryFilters() {
+		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		// Criteria-query test
+		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		log.info( "Starting Criteria-query filter tests" );
+		TestData testData = new TestData();
+		testData.prepare();
+
+		Session session = openSession();
+		session.enableFilter( "region" ).setParameter( "region", "APAC" );
+
+		session.enableFilter( "fulfilledOrders" )
+		        .setParameter( "asOfDate", testData.lastMonth.getTime() );
+
+		session.enableFilter( "effectiveDate" )
+		        .setParameter( "asOfDate", testData.lastMonth.getTime() );
+
+		log.info( "Criteria query against Salesperson..." );
+		List salespersons = session.createCriteria( Salesperson.class )
+		        .setFetchMode( "orders", FetchMode.JOIN )
+		        .list();
+		assertEquals( "Incorrect salesperson count", 1, salespersons.size() );
+		assertEquals( "Incorrect order count", 1, ( ( Salesperson ) salespersons.get( 0 ) ).getOrders().size() );
+
+		log.info( "Criteria query against Product..." );
+		List products = session.createCriteria( Product.class )
+		        .add( Expression.eq( "stockNumber", new Integer( 124 ) ) )
+		        .list();
+		assertEquals( "Incorrect product count", 1, products.size() );
+
+		session.close();
+		testData.release();
+	}
+
+	public void testGetFilters() {
+		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		// Get() test
+		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		log.info( "Starting get() filter tests (eager assoc. fetching)." );
+		TestData testData = new TestData();
+		testData.prepare();
+
+		Session session = openSession();
+		session.enableFilter( "region" ).setParameter( "region", "APAC" );
+
+		log.info( "Performing get()..." );
+		Salesperson salesperson = ( Salesperson ) session.get( Salesperson.class, testData.steveId );
+		assertNotNull( salesperson );
+		assertEquals( "Incorrect order count", 1, salesperson.getOrders().size() );
+
+		session.close();
+		testData.release();
+	}
+
+	public void testOneToManyFilters() {
+		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		// one-to-many loading tests
+		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		log.info( "Starting one-to-many collection loader filter tests." );
+		TestData testData = new TestData();
+		testData.prepare();
+
+		Session session = openSession();
+		session.enableFilter( "seniorSalespersons" )
+		        .setParameter( "asOfDate", testData.lastMonth.getTime() );
+
+		log.info( "Performing load of Department..." );
+		Department department = ( Department ) session.load( Department.class, testData.deptId );
+		Set salespersons = department.getSalespersons();
+		assertEquals( "Incorrect salesperson count", 1, salespersons.size() );
+
+		session.close();
+		testData.release();
+	}
+
+	public void testInStyleFilterParameter() {
+		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		// one-to-many loading tests
+		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		log.info( "Starting one-to-many collection loader filter tests." );
+		TestData testData = new TestData();
+		testData.prepare();
+
+		Session session = openSession();
+		session.enableFilter( "regionlist" )
+		        .setParameterList( "regions", new String[]{"LA", "APAC"} );
+
+		log.debug( "Performing query of Salespersons" );
+		List salespersons = session.createQuery( "from Salesperson" ).list();
+		assertEquals( "Incorrect salesperson count", 1, salespersons.size() );
+
+		session.close();
+		testData.release();
+	}
+
+	public void testManyToManyFilterOnCriteria() {
+		TestData testData = new TestData();
+		testData.prepare();
+
+		Session session = openSession();
+		session.enableFilter( "effectiveDate" ).setParameter( "asOfDate", new Date() );
+
+		Product prod = ( Product ) session.createCriteria( Product.class )
+		        .setResultTransformer( new DistinctRootEntityResultTransformer() )
+		        .add( Expression.eq( "id", testData.prod1Id ) )
+		        .uniqueResult();
+
+		assertNotNull( prod );
+		assertEquals( "Incorrect Product.categories count for filter", 1, prod.getCategories().size() );
+
+		session.close();
+		testData.release();
+	}
+
+	public void testManyToManyFilterOnLoad() {
+		TestData testData = new TestData();
+		testData.prepare();
+
+		Session session = openSession();
+		session.enableFilter( "effectiveDate" ).setParameter( "asOfDate", new Date() );
+
+		Product prod = ( Product ) session.get( Product.class, testData.prod1Id );
+
+		long initLoadCount = getSessions().getStatistics().getCollectionLoadCount();
+		long initFetchCount = getSessions().getStatistics().getCollectionFetchCount();
+
+		// should already have been initialized...
+		int size = prod.getCategories().size();
+		assertEquals( "Incorrect filtered collection count", 1, size );
+
+		long currLoadCount = getSessions().getStatistics().getCollectionLoadCount();
+		long currFetchCount = getSessions().getStatistics().getCollectionFetchCount();
+
+		assertTrue(
+		        "load with join fetch of many-to-many did not trigger join fetch",
+		        ( initLoadCount == currLoadCount ) && ( initFetchCount == currFetchCount )
+		);
+
+		// make sure we did not get back a collection of proxies
+		long initEntityLoadCount = getSessions().getStatistics().getEntityLoadCount();
+		Iterator itr = prod.getCategories().iterator();
+		while ( itr.hasNext() ) {
+			Category cat = ( Category ) itr.next();
+			System.out.println( " ===> " + cat.getName() );
+		}
+		long currEntityLoadCount = getSessions().getStatistics().getEntityLoadCount();
+
+		assertTrue(
+		        "load with join fetch of many-to-many did not trigger *complete* join fetch",
+		        ( initEntityLoadCount == currEntityLoadCount )
+		);
+
+		session.close();
+		testData.release();
+	}
+
+	public void testManyToManyOnCollectionLoadAfterHQL() {
+		TestData testData = new TestData();
+		testData.prepare();
+
+		Session session = openSession();
+		session.enableFilter( "effectiveDate" ).setParameter( "asOfDate", new Date() );
+
+		// Force the categories to not get initialized here
+		List result = session.createQuery( "from Product as p where p.id = :id" )
+		        .setLong( "id", testData.prod1Id.longValue() )
+		        .list();
+		assertTrue( "No products returned from HQL", !result.isEmpty() );
+
+		Product prod = ( Product ) result.get( 0 );
+		assertNotNull( prod );
+		assertEquals( "Incorrect Product.categories count for filter on collection load", 1, prod.getCategories().size() );
+
+		session.close();
+		testData.release();
+	}
+
+	public void testManyToManyFilterOnQuery() {
+		TestData testData = new TestData();
+		testData.prepare();
+
+		Session session = openSession();
+		session.enableFilter( "effectiveDate" ).setParameter( "asOfDate", new Date() );
+
+		List result = session.createQuery( "from Product p inner join fetch p.categories" ).list();
+		assertTrue( "No products returned from HQL many-to-many filter case", !result.isEmpty() );
+
+		Product prod = ( Product ) result.get( 0 );
+
+		assertNotNull( prod );
+		assertEquals( "Incorrect Product.categories count for filter with HQL", 1, prod.getCategories().size() );
+
+		session.close();
+		testData.release();
+	}
+
+	public void testManyToManyBase() {
+		TestData testData = new TestData();
+		testData.prepare();
+
+		Session session = openSession();
+
+		Product prod = ( Product ) session.get( Product.class, testData.prod1Id );
+
+		long initLoadCount = getSessions().getStatistics().getCollectionLoadCount();
+		long initFetchCount = getSessions().getStatistics().getCollectionFetchCount();
+
+		// should already have been initialized...
+		int size = prod.getCategories().size();
+		assertEquals( "Incorrect non-filtered collection count", 2, size );
+
+		long currLoadCount = getSessions().getStatistics().getCollectionLoadCount();
+		long currFetchCount = getSessions().getStatistics().getCollectionFetchCount();
+
+		assertTrue(
+		        "load with join fetch of many-to-many did not trigger join fetch",
+		        ( initLoadCount == currLoadCount ) && ( initFetchCount == currFetchCount )
+		);
+
+		// make sure we did not get back a collection of proxies
+		long initEntityLoadCount = getSessions().getStatistics().getEntityLoadCount();
+		Iterator itr = prod.getCategories().iterator();
+		while ( itr.hasNext() ) {
+			Category cat = ( Category ) itr.next();
+			System.out.println( " ===> " + cat.getName() );
+		}
+		long currEntityLoadCount = getSessions().getStatistics().getEntityLoadCount();
+
+		assertTrue(
+		        "load with join fetch of many-to-many did not trigger *complete* join fetch",
+		        ( initEntityLoadCount == currEntityLoadCount )
+		);
+
+		session.close();
+		testData.release();
+	}
+
+	public void testManyToManyBaseThruCriteria() {
+		TestData testData = new TestData();
+		testData.prepare();
+
+		Session session = openSession();
+
+		List result = session.createCriteria( Product.class )
+		        .add( Expression.eq( "id", testData.prod1Id ) )
+		        .list();
+
+		Product prod = ( Product ) result.get( 0 );
+
+		long initLoadCount = getSessions().getStatistics().getCollectionLoadCount();
+		long initFetchCount = getSessions().getStatistics().getCollectionFetchCount();
+
+		// should already have been initialized...
+		int size = prod.getCategories().size();
+		assertEquals( "Incorrect non-filtered collection count", 2, size );
+
+		long currLoadCount = getSessions().getStatistics().getCollectionLoadCount();
+		long currFetchCount = getSessions().getStatistics().getCollectionFetchCount();
+
+		assertTrue(
+		        "load with join fetch of many-to-many did not trigger join fetch",
+		        ( initLoadCount == currLoadCount ) && ( initFetchCount == currFetchCount )
+		);
+
+		// make sure we did not get back a collection of proxies
+		long initEntityLoadCount = getSessions().getStatistics().getEntityLoadCount();
+		Iterator itr = prod.getCategories().iterator();
+		while ( itr.hasNext() ) {
+			Category cat = ( Category ) itr.next();
+			System.out.println( " ===> " + cat.getName() );
+		}
+		long currEntityLoadCount = getSessions().getStatistics().getEntityLoadCount();
+
+		assertTrue(
+		        "load with join fetch of many-to-many did not trigger *complete* join fetch",
+		        ( initEntityLoadCount == currEntityLoadCount )
+		);
+
+		session.close();
+		testData.release();
+	}
+
+	private class TestData {
+		private Long steveId;
+		private Long deptId;
+		private Long prod1Id;
+		private Calendar lastMonth;
+		private Calendar nextMonth;
+		private Calendar sixMonthsAgo;
+		private Calendar fourMonthsAgo;
+
+		private List entitiesToCleanUp = new ArrayList();
+
+		private void prepare() {
+			Session session = openSession();
+			Transaction transaction = session.beginTransaction();
+
+			lastMonth = new GregorianCalendar();
+			lastMonth.add( Calendar.MONTH, -1 );
+
+			nextMonth = new GregorianCalendar();
+			nextMonth.add( Calendar.MONTH, 1 );
+
+			sixMonthsAgo = new GregorianCalendar();
+			sixMonthsAgo.add( Calendar.MONTH, -6 );
+
+			fourMonthsAgo = new GregorianCalendar();
+			fourMonthsAgo.add( Calendar.MONTH, -4 );
+
+			Department dept = new Department();
+			dept.setName( "Sales" );
+
+			session.save( dept );
+			deptId = dept.getId();
+			entitiesToCleanUp.add( dept );
+
+			Salesperson steve = new Salesperson();
+			steve.setName( "steve" );
+			steve.setRegion( "APAC" );
+			steve.setHireDate( sixMonthsAgo.getTime() );
+
+			steve.setDepartment( dept );
+			dept.getSalespersons().add( steve );
+
+			Salesperson max = new Salesperson();
+			max.setName( "max" );
+			max.setRegion( "EMEA" );
+			max.setHireDate( nextMonth.getTime() );
+
+			max.setDepartment( dept );
+			dept.getSalespersons().add( max );
+
+			session.save( steve );
+			session.save( max );
+			entitiesToCleanUp.add( steve );
+			entitiesToCleanUp.add( max );
+
+			steveId = steve.getId();
+
+			Category cat1 = new Category( "test cat 1", lastMonth.getTime(), nextMonth.getTime() );
+			Category cat2 = new Category( "test cat 2", sixMonthsAgo.getTime(), fourMonthsAgo.getTime() );
+
+			Product product1 = new Product();
+			product1.setName( "Acme Hair Gel" );
+			product1.setStockNumber( 123 );
+			product1.setEffectiveStartDate( lastMonth.getTime() );
+			product1.setEffectiveEndDate( nextMonth.getTime() );
+
+			product1.addCategory( cat1 );
+			product1.addCategory( cat2 );
+
+			session.save( product1 );
+			entitiesToCleanUp.add( product1 );
+			prod1Id = product1.getId();
+
+			Order order1 = new Order();
+			order1.setBuyer( "gavin" );
+			order1.setRegion( "APAC" );
+			order1.setPlacementDate( sixMonthsAgo.getTime() );
+			order1.setFulfillmentDate( fourMonthsAgo.getTime() );
+			order1.setSalesperson( steve );
+			order1.addLineItem( product1, 500 );
+
+			session.save( order1 );
+			entitiesToCleanUp.add( order1 );
+
+			Product product2 = new Product();
+			product2.setName( "Acme Super-Duper DTO Factory" );
+			product2.setStockNumber( 124 );
+			product2.setEffectiveStartDate( sixMonthsAgo.getTime() );
+			product2.setEffectiveEndDate( new Date() );
+
+			Category cat3 = new Category( "test cat 2", sixMonthsAgo.getTime(), new Date() );
+			product2.addCategory( cat3 );
+
+			session.save( product2 );
+			entitiesToCleanUp.add( product2 );
+
+			// An uncategorized product
+			Product product3 = new Product();
+			product3.setName( "Uncategorized product" );
+			session.save( product3 );
+			entitiesToCleanUp.add( product3 );
+
+			Order order2 = new Order();
+			order2.setBuyer( "christian" );
+			order2.setRegion( "EMEA" );
+			order2.setPlacementDate( lastMonth.getTime() );
+			order2.setSalesperson( steve );
+			order2.addLineItem( product2, -1 );
+
+			session.save( order2 );
+			entitiesToCleanUp.add( order2 );
+
+			transaction.commit();
+			session.close();
+		}
+
+		private void release() {
+			Session session = openSession();
+			Transaction transaction = session.beginTransaction();
+
+			Iterator itr = entitiesToCleanUp.iterator();
+			while ( itr.hasNext() ) {
+				session.delete( itr.next() );
+			}
+
+			transaction.commit();
+			session.close();
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/LineItem.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/LineItem.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/LineItem.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping
+        SYSTEM
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.filter">
+
+    <class name="LineItem" table="ORDER_ITEM">
+    	<id name="id" column="ITEM_ID" >
+    		<generator class="native"/>
+    	</id>
+
+	    <many-to-one name="order" class="Order" column="ORDER_ID" cascade="none"/>
+	    <property name="sequence" column="SEQ" type="int"/>
+	    <many-to-one name="product" class="Product" column="PRODUCT_ID" cascade="none"/>
+	    <property name="quantity" column="AMT" type="long"/>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/LineItem.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/LineItem.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/LineItem.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+// $Id: LineItem.java 4046 2004-07-20 04:07:40Z steveebersole $
+package org.hibernate.test.filter;
+
+/**
+ * Implementation of LineItem.
+ * 
+ * @author Steve
+ */
+public class LineItem {
+	private Long id;
+	private Order order;
+	private int sequence;
+	private Product product;
+	private long quantity;
+
+	/*package*/ LineItem() {}
+
+	public static LineItem generate(Order order, int sequence, Product product, long quantity) {
+		LineItem item = new LineItem();
+		item.order = order;
+		item.sequence = sequence;
+		item.product = product;
+		item.quantity = quantity;
+		item.order.getLineItems().add(sequence, item);
+		return item;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Order getOrder() {
+		return order;
+	}
+
+	public void setOrder(Order order) {
+		this.order = order;
+	}
+
+	public int getSequence() {
+		return sequence;
+	}
+
+	public void setSequence(int sequence) {
+		this.sequence = sequence;
+	}
+
+	public Product getProduct() {
+		return product;
+	}
+
+	public void setProduct(Product product) {
+		this.product = product;
+	}
+
+	public long getQuantity() {
+		return quantity;
+	}
+
+	public void setQuantity(long quantity) {
+		this.quantity = quantity;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Order.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Order.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Order.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping
+        SYSTEM
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.filter">
+
+    <class name="Order" table="T_ORDER">
+    	<id name="id" column="ORDER_ID" type="long">
+    		<generator class="native"/>
+    	</id>
+
+    	<property name="region" column="REG" type="string"/>
+	    <property name="buyer" column="BUYER" type="string"/>
+    	<property name="placementDate" column="`ord dt`" type="java.util.Date"/>
+    	<property name="fulfillmentDate" column="`close dt`" type="java.util.Date"/>
+
+	    <many-to-one name="salesperson" class="Salesperson" column="SALES_PERSON_ID"/>
+
+	    <list cascade="all-delete-orphan" inverse="true" name="lineItems">
+		    <key column="ORDER_ID"/>
+		    <index column="SEQ"/>
+		    <one-to-many class="LineItem"/>
+	    </list>
+
+	    <filter name="region" condition="REG = :region"/>
+	    <filter name="fulfilledOrders"><![CDATA[`close dt` < :asOfDate]]></filter>
+
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Order.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Order.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Order.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,87 @@
+// $Id: Order.java 4222 2004-08-10 05:19:46Z steveebersole $
+package org.hibernate.test.filter;
+
+import java.util.Date;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @author Steve Ebersole
+ */
+public class Order {
+	private Long id;
+	private String region;
+	private Date placementDate;
+	private Date fulfillmentDate;
+	private Salesperson salesperson;
+	private String buyer;
+	private List lineItems = new ArrayList();
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getRegion() {
+		return region;
+	}
+
+	public void setRegion(String region) {
+		this.region = region;
+	}
+
+	public Date getPlacementDate() {
+		return placementDate;
+	}
+
+	public void setPlacementDate(Date placementDate) {
+		this.placementDate = placementDate;
+	}
+
+	public Date getFulfillmentDate() {
+		return fulfillmentDate;
+	}
+
+	public void setFulfillmentDate(Date fulfillmentDate) {
+		this.fulfillmentDate = fulfillmentDate;
+	}
+
+	public Salesperson getSalesperson() {
+		return salesperson;
+	}
+
+	public void setSalesperson(Salesperson salesperson) {
+		this.salesperson = salesperson;
+	}
+
+	public String getBuyer() {
+		return buyer;
+	}
+
+	public void setBuyer(String buyer) {
+		this.buyer = buyer;
+	}
+
+	public List getLineItems() {
+		return lineItems;
+	}
+
+	protected void setLineItems(List lineItems) {
+		this.lineItems = lineItems;
+	}
+
+	public LineItem addLineItem(Product product, long quantity) {
+		return LineItem.generate(this, getLineItems().size(), product, quantity);
+	}
+
+	public void removeLineItem(LineItem item) {
+		removeLineItem( item.getSequence() );
+	}
+
+	public void removeLineItem(int sequence) {
+		getLineItems().remove(sequence);
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Product.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Product.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Product.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping
+        SYSTEM
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.filter">
+
+    <class name="Product" table="PRODUCT">
+    	<id name="id" column="PROD_ID" >
+    		<generator class="native"/>
+    	</id>
+
+    	<property name="name" type="string"/>
+	    <property name="stockNumber" column="STOCK_NUM" type="int"/>
+
+	    <property name="effectiveStartDate" column="eff_start_dt" type="java.util.Date"/>
+	    <property name="effectiveEndDate" column="eff_end_dt" type="java.util.Date"/>
+
+	    <set cascade="none" inverse="true" name="orderLineItems">
+		    <key column="PROD_ID"/>
+		    <one-to-many class="LineItem"/>
+	    </set>
+
+	    <set cascade="all" inverse="false" name="categories" fetch="join" table="PROD_CAT" >
+		    <key column="PROD_ID"/>
+		    <many-to-many class="Category" column="CAT_ID" fetch="join" >
+	            <filter name="effectiveDate" condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+			    <filter name="cat" condition="CAT_ID = :catId"/> 
+            </many-to-many>
+	    </set>
+
+	    <filter name="effectiveDate" condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Product.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Product.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Product.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,99 @@
+// $Id: Product.java 6507 2005-04-25 16:57:32Z steveebersole $
+package org.hibernate.test.filter;
+
+import java.util.Set;
+import java.util.Date;
+import java.util.HashSet;
+
+/**
+ * @author Steve Ebersole
+ */
+public class Product {
+	private Long id;
+	private String name;
+	private int stockNumber;  // int for ease of hashCode() impl
+	private Date effectiveStartDate;
+	private Date effectiveEndDate;
+	private Set orderLineItems;
+	private Set categories;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Set getOrderLineItems() {
+		return orderLineItems;
+	}
+
+	public void setOrderLineItems(Set orderLineItems) {
+		this.orderLineItems = orderLineItems;
+	}
+
+	public int getStockNumber() {
+		return stockNumber;
+	}
+
+	public void setStockNumber(int stockNumber) {
+		this.stockNumber = stockNumber;
+	}
+
+	public int hashCode() {
+		return stockNumber;
+	}
+
+	public boolean equals(Object obj) {
+		return ( (Product) obj ).stockNumber == this.stockNumber;
+	}
+
+	public Date getEffectiveStartDate() {
+		return effectiveStartDate;
+	}
+
+	public void setEffectiveStartDate(Date effectiveStartDate) {
+		this.effectiveStartDate = effectiveStartDate;
+	}
+
+	public Date getEffectiveEndDate() {
+		return effectiveEndDate;
+	}
+
+	public void setEffectiveEndDate(Date effectiveEndDate) {
+		this.effectiveEndDate = effectiveEndDate;
+	}
+
+	public Set getCategories() {
+		return categories;
+	}
+
+	public void setCategories(Set categories) {
+		this.categories = categories;
+	}
+
+	public void addCategory(Category category) {
+		if ( category == null ) {
+			return;
+		}
+
+		if ( categories == null ) {
+			categories = new HashSet();
+		}
+
+		categories.add( category );
+		if ( category.getProducts() == null ) {
+			category.setProducts( new HashSet() );
+		}
+		category.getProducts().add( this );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Salesperson.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Salesperson.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Salesperson.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping
+        SYSTEM
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.filter">
+
+    <class name="Salesperson" table="SALES_PERSON">
+    	<id name="id" column="SALES_PERSON_ID" >
+    		<generator class="native"/>
+    	</id>
+
+	    <property name="name" column="NAME" type="string"/>
+    	<property name="region" column="REG" type="string"/>
+
+	    <many-to-one name="department" cascade="none" class="Department" column="DEPT_ID"/>
+
+	    <property name="hireDate" column="`hire dt`" type="java.util.Date"/>
+
+	    <set name="orders" cascade="none" inverse="true" fetch="join">
+		    <key column="SALES_PERSON_ID"/>
+		    <one-to-many class="Order"/>
+		    <filter name="region" condition="REG = :region"/>
+	        <filter name="fulfilledOrders"><![CDATA[`close dt` < :asOfDate]]></filter>
+	    </set>
+
+	    <filter name="region" condition="REG = :region"/>
+	    <filter name="regionlist" condition="REG IN (:regions)"/>
+
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Salesperson.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Salesperson.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/Salesperson.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,68 @@
+// $Id: Salesperson.java 4448 2004-08-28 02:29:05Z steveebersole $
+package org.hibernate.test.filter;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Date;
+
+/**
+ * Implementation of Salesperson.
+ * 
+ * @author Steve
+ */
+public class Salesperson {
+	private Long id;
+	private String name;
+	private String region;
+	private Date hireDate;
+	private Department department;
+	private Set orders = new HashSet();
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getRegion() {
+		return region;
+	}
+
+	public void setRegion(String region) {
+		this.region = region;
+	}
+
+	public Set getOrders() {
+		return orders;
+	}
+
+	public void setOrders(Set orders) {
+		this.orders = orders;
+	}
+
+	public Date getHireDate() {
+		return hireDate;
+	}
+
+	public void setHireDate(Date hireDate) {
+		this.hireDate = hireDate;
+	}
+
+	public Department getDepartment() {
+		return department;
+	}
+
+	public void setDepartment(Department department) {
+		this.department = department;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/defs.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/defs.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/filter/defs.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping
+        SYSTEM
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping>
+	<filter-def name="region">
+		<filter-param name="region" type="string"/>
+	</filter-def>
+
+	<filter-def name="regionlist">
+		<filter-param name="regions" type="string"/>
+	</filter-def>
+
+	<filter-def name="fulfilledOrders">
+		<filter-param name="asOfDate" type="timestamp"/>
+	</filter-def>
+
+	<filter-def name="effectiveDate">
+		<filter-param name="asOfDate" type="timestamp"/>
+	</filter-def>
+
+	<filter-def name="seniorSalespersons">
+		<filter-param name="asOfDate" type="timestamp"/>
+	</filter-def>
+
+	<filter-def name="cat">
+		<filter-param name="catId" type="long"/>
+	</filter-def>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Detail.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Detail.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Detail.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+//$Id: Detail.java 4602 2004-09-26 11:42:47Z oneovthafew $
+package org.hibernate.test.formulajoin;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Detail implements Serializable {
+	private Long id;
+	private Master master;
+	private int version;
+	private String details;
+	private boolean currentVersion;
+	
+	public boolean isCurrentVersion() {
+		return currentVersion;
+	}
+	public void setCurrentVersion(boolean currentVersion) {
+		this.currentVersion = currentVersion;
+	}
+	public String getDetails() {
+		return details;
+	}
+	public void setDetails(String details) {
+		this.details = details;
+	}
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public Master getMaster() {
+		return master;
+	}
+	public void setMaster(Master master) {
+		this.master = master;
+	}
+	public int getVersion() {
+		return version;
+	}
+	public void setVersion(int version) {
+		this.version = version;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Detail.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/FormulaJoinTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/FormulaJoinTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/FormulaJoinTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,100 @@
+//$Id: FormulaJoinTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.formulajoin;
+
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.dialect.PostgreSQLDialect;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class FormulaJoinTest extends FunctionalTestCase {
+	
+	public FormulaJoinTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "formulajoin/Master.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( FormulaJoinTest.class );
+	}
+	
+	public void testFormulaJoin() {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Master master = new Master();
+		master.setName("master 1");
+		Detail current = new Detail();
+		current.setCurrentVersion(true);
+		current.setVersion(2);
+		current.setDetails("details of master 1 blah blah");
+		current.setMaster(master);
+		master.setDetail(current);
+		Detail past = new Detail();
+		past.setCurrentVersion(false);
+		past.setVersion(1);
+		past.setDetails("old details of master 1 yada yada");
+		past.setMaster(master);
+		s.persist(master);
+		s.persist(past);
+		s.persist(current);
+		tx.commit();
+		s.close();
+		
+		if ( getDialect() instanceof PostgreSQLDialect ) return;
+
+		s = openSession();
+		tx = s.beginTransaction();
+		List l = s.createQuery("from Master m left join m.detail d").list();
+		assertEquals( l.size(), 1 );
+		tx.commit();
+		s.close();
+		
+		s = openSession();
+		tx = s.beginTransaction();
+		l = s.createQuery("from Master m left join fetch m.detail").list();
+		assertEquals( l.size(), 1 );
+		Master m = (Master) l.get(0);
+		assertEquals( "master 1", m.getDetail().getMaster().getName() );
+		assertTrue( m==m.getDetail().getMaster() );
+		tx.commit();
+		s.close();
+		
+		s = openSession();
+		tx = s.beginTransaction();
+		l = s.createQuery("from Master m join fetch m.detail").list();
+		assertEquals( l.size(), 1 );
+		tx.commit();
+		s.close();
+		
+		s = openSession();
+		tx = s.beginTransaction();
+		l = s.createQuery("from Detail d join fetch d.currentMaster.master").list();
+		assertEquals( l.size(), 2 );
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		l = s.createQuery("from Detail d join fetch d.currentMaster.master m join fetch m.detail").list();
+		assertEquals( l.size(), 2 );
+		
+		s.createQuery("delete from Detail").executeUpdate();
+		s.createQuery("delete from Master").executeUpdate();
+		
+		tx.commit();
+		s.close();
+
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/FormulaJoinTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Master.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Master.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Master.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+  
+  Demonstrates use of an association "filtered" using a formula
+  mapping in the foreign key.
+  
+-->
+
+<hibernate-mapping package="org.hibernate.test.formulajoin">
+
+	<class name="Master" table="t_masters">
+	
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		
+		<property name="name" 
+			not-null="true" 
+			length="100" 
+			update="false"/>
+		
+		<many-to-one name="detail" 
+				property-ref="currentMaster" 
+				insert="false"
+				update="false">
+			<column name="id"/>
+			<formula>1</formula>
+		</many-to-one>
+		
+	</class>
+
+	<class name="Detail" table="t_details">
+	
+		<id name="id">
+			<generator class="hilo"/>
+		</id>
+		
+		<property name="details" 
+			length="300" 
+			update="false" 
+			not-null="true"/>
+			
+		<property name="version" update="false">
+			<column name="version" 
+				not-null="true" 
+				unique-key="masterVersion"/>
+		</property>
+		
+		<properties name="currentMaster">
+			<many-to-one name="master">
+				<column name="cur_master" 
+					unique-key="masterVersion" 
+					not-null="true"/>
+			</many-to-one>
+			<property name="currentVersion" 
+				not-null="true"/>
+		</properties>
+		
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Master.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Master.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Master.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Master.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+//$Id: Master.java 4602 2004-09-26 11:42:47Z oneovthafew $
+package org.hibernate.test.formulajoin;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Master implements Serializable {
+	private Long id;
+	private String name;
+	private Detail detail;
+	public Detail getDetail() {
+		return detail;
+	}
+	public void setDetail(Detail detail) {
+		this.detail = detail;
+	}
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/formulajoin/Master.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/AbstractGeneratedPropertyTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/AbstractGeneratedPropertyTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/AbstractGeneratedPropertyTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+// $Id: AbstractGeneratedPropertyTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.generated;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.Hibernate;
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+
+/**
+ * Implementation of AbstractGeneratedPropertyTest.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractGeneratedPropertyTest extends DatabaseSpecificFunctionalTestCase {
+	public AbstractGeneratedPropertyTest(String x) {
+		super( x );
+	}
+
+	public final void testGeneratedProperty() {
+		GeneratedPropertyEntity entity = new GeneratedPropertyEntity();
+		entity.setName( "entity-1" );
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.save( entity );
+		s.flush();
+		assertNotNull( "no timestamp retrieved", entity.getLastModified() );
+		t.commit();
+		s.close();
+
+		byte[] bytes = entity.getLastModified();
+
+		s = openSession();
+		t = s.beginTransaction();
+		entity = ( GeneratedPropertyEntity ) s.get( GeneratedPropertyEntity.class, entity.getId() );
+		assertTrue( Hibernate.BINARY.isEqual( bytes, entity.getLastModified() ) );
+		t.commit();
+		s.close();
+
+		assertTrue( Hibernate.BINARY.isEqual( bytes, entity.getLastModified() ) );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( entity );
+		t.commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/ComponentOwner.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/ComponentOwner.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/ComponentOwner.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.generated">
+
+    <class name="ComponentOwner" table="part_gen_comp">
+    	<id name="id">
+    		<generator class="increment"/>
+    	</id>
+        <property name="name" />
+        <component name="component" class="ComponentOwner$Component">
+            <property name="generated" type="int" generated="always" column="GENED"/>
+        </component>
+	</class>
+
+    <database-object>
+        <create>
+            <![CDATA[CREATE OR REPLACE TRIGGER t_iu_part_gen_comp
+            BEFORE INSERT OR UPDATE ON part_gen_comp
+            FOR EACH ROW
+            BEGIN
+                IF INSERTING THEN
+                    :new.gened := 1;
+                ELSE
+                    :new.gened := :old.gened + 1;
+                END IF;
+            END;]]>
+        </create>
+        <drop>
+            <![CDATA[DROP TRIGGER t_iu_part_gen_comp]]>
+        </drop>
+        <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/>
+        <dialect-scope name="org.hibernate.dialect.OracleDialect"/>
+    </database-object>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/ComponentOwner.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/ComponentOwner.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/ComponentOwner.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+package org.hibernate.test.generated;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class ComponentOwner {
+	private Long id;
+	private String name;
+	private Component component;
+
+	public ComponentOwner() {
+	}
+
+	public ComponentOwner(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Component getComponent() {
+		return component;
+	}
+
+	public void setComponent(Component component) {
+		this.component = component;
+	}
+
+	public static class Component {
+		private int generated;
+
+		public int getGenerated() {
+			return generated;
+		}
+
+		public void setGenerated(int generated) {
+			this.generated = generated;
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/GeneratedPropertyEntity.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/GeneratedPropertyEntity.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/GeneratedPropertyEntity.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.generated">
+
+    <class name="GeneratedPropertyEntity" table="gen_prop">
+
+    	<id name="id">
+    		<generator class="native"/>
+    	</id>
+        <property name="name"/>
+        <property name="lastModified" generated="always" type="binary">
+            <column name="lastModified" length="8"/>
+        </property>
+
+	</class>
+
+    <database-object>
+        <create>
+            <![CDATA[CREATE OR REPLACE TRIGGER t_iu_gen_prop
+            BEFORE INSERT OR UPDATE ON gen_prop
+            FOR EACH ROW
+            BEGIN
+                IF INSERTING THEN
+                    :new.lastModified := HEXTORAW( '1' );
+                ELSE
+                    :new.lastModified := HEXTORAW(
+                        TO_NUMBER( RAWTOHEX( :old.lastModified ) ) + 1
+                    );
+                END IF;
+            END;]]>
+        </create>
+        <drop>
+            <![CDATA[DROP TRIGGER t_iu_gen_prop]]>
+        </drop>
+        <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/>
+        <dialect-scope name="org.hibernate.dialect.OracleDialect"/>
+    </database-object>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/GeneratedPropertyEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/GeneratedPropertyEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/GeneratedPropertyEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+// $Id: GeneratedPropertyEntity.java 7800 2005-08-10 12:13:00Z steveebersole $
+package org.hibernate.test.generated;
+
+/**
+ * Implementation of GeneratedPropertyEntity.
+ *
+ * @author Steve Ebersole
+ */
+public class GeneratedPropertyEntity {
+	private Long id;
+	private String name;
+	private byte[] lastModified;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public byte[] getLastModified() {
+		return lastModified;
+	}
+
+	public void setLastModified(byte[] lastModified) {
+		this.lastModified = lastModified;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/GeneratedPropertySuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/GeneratedPropertySuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/GeneratedPropertySuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+package org.hibernate.test.generated;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class GeneratedPropertySuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "generated property suite" );
+		suite.addTest( TimestampGeneratedValuesWithCachingTest.suite() );
+		suite.addTest( TriggerGeneratedValuesWithCachingTest.suite() );
+		suite.addTest( TriggerGeneratedValuesWithoutCachingTest.suite() );
+		suite.addTest( PartiallyGeneratedComponentTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/MSSQLGeneratedPropertyEntity.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/MSSQLGeneratedPropertyEntity.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/MSSQLGeneratedPropertyEntity.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.generated">
+
+    <class name="GeneratedPropertyEntity" table="gen_prop">
+
+    	<id name="id">
+    		<generator class="native"/>
+    	</id>
+        <property name="name"/>
+        <property name="lastModified" generated="always" type="binary">
+            <column name="lastModified" length="8" sql-type="TIMESTAMP"/>
+        </property>
+
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/PartiallyGeneratedComponentTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/PartiallyGeneratedComponentTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/PartiallyGeneratedComponentTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+package org.hibernate.test.generated;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.Session;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class PartiallyGeneratedComponentTest extends DatabaseSpecificFunctionalTestCase {
+	public PartiallyGeneratedComponentTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "generated/ComponentOwner.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PartiallyGeneratedComponentTest.class );
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		return dialect instanceof Oracle9Dialect;
+	}
+
+	public void testPartialComponentGeneration() {
+		ComponentOwner owner = new ComponentOwner( "initial" );
+		Session s = openSession();
+		s.beginTransaction();
+		s.save( owner );
+		s.getTransaction().commit();
+		s.close();
+
+		assertNotNull( "expecting insert value generation", owner.getComponent() );
+		int previousValue = owner.getComponent().getGenerated();
+		assertFalse( "expecting insert value generation", 0 == previousValue );
+
+		s = openSession();
+		s.beginTransaction();
+		owner = ( ComponentOwner ) s.get( ComponentOwner.class, owner.getId() );
+		assertEquals( "expecting insert value generation", previousValue, owner.getComponent().getGenerated() );
+		owner.setName( "subsequent" );
+		s.getTransaction().commit();
+		s.close();
+
+		assertNotNull( owner.getComponent() );
+		previousValue = owner.getComponent().getGenerated();
+
+		s = openSession();
+		s.beginTransaction();
+		owner = ( ComponentOwner ) s.get( ComponentOwner.class, owner.getId() );
+		assertEquals( "expecting update value generation", previousValue, owner.getComponent().getGenerated() );
+		s.delete( owner );
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/TimestampGeneratedValuesWithCachingTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/TimestampGeneratedValuesWithCachingTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/TimestampGeneratedValuesWithCachingTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+// $Id: TimestampGeneratedValuesWithCachingTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.generated;
+
+import junit.framework.Test;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.SybaseDialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Implementation of TimestampGeneratedValuesWithCachingTest.
+ *
+ * @author Steve Ebersole
+ */
+public class TimestampGeneratedValuesWithCachingTest extends AbstractGeneratedPropertyTest {
+
+	public TimestampGeneratedValuesWithCachingTest(String x) {
+		super( x );
+	}
+
+	public final String[] getMappings() {
+		return new String[] { "generated/MSSQLGeneratedPropertyEntity.hbm.xml" };
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		// this test is specific to Sybase/SQLServer as it is testing support
+		// for their TIMESTAMP datatype...
+		return ( dialect instanceof SybaseDialect );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( TimestampGeneratedValuesWithCachingTest.class );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/TriggerGeneratedValuesWithCachingTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/TriggerGeneratedValuesWithCachingTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/TriggerGeneratedValuesWithCachingTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+// $Id: TriggerGeneratedValuesWithCachingTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.generated;
+
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Implementation of TriggerGeneratedValuesWithoutCachingTest.
+ *
+ * @author Steve Ebersole
+ */
+public class TriggerGeneratedValuesWithCachingTest extends AbstractGeneratedPropertyTest {
+
+	public TriggerGeneratedValuesWithCachingTest(String x) {
+		super( x );
+	}
+
+	public final String[] getMappings() {
+		return new String[] { "generated/GeneratedPropertyEntity.hbm.xml" };
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		// currently have only defined triggers for oracle...
+		// TODO : add more triggers for dialects which allow mods in triggers...
+		return ( dialect instanceof Oracle9Dialect );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( TriggerGeneratedValuesWithCachingTest.class );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/TriggerGeneratedValuesWithoutCachingTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/TriggerGeneratedValuesWithoutCachingTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generated/TriggerGeneratedValuesWithoutCachingTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+// $Id: TriggerGeneratedValuesWithoutCachingTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.generated;
+
+import junit.framework.Test;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Implementation of TriggerGeneratedValuesWithoutCachingTest.
+ *
+ * @author Steve Ebersole
+ */
+public class TriggerGeneratedValuesWithoutCachingTest extends AbstractGeneratedPropertyTest {
+
+	public TriggerGeneratedValuesWithoutCachingTest(String x) {
+		super( x );
+	}
+
+	public final String[] getMappings() {
+		return new String[] { "generated/GeneratedPropertyEntity.hbm.xml" };
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		// currently have only defined triggers for oracle...
+		// TODO : add more triggers for dialects which allow mods in triggers...
+		return ( dialect instanceof Oracle9Dialect );
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( TriggerGeneratedValuesWithoutCachingTest.class );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/GeneratedKeysSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/GeneratedKeysSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/GeneratedKeysSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+package org.hibernate.test.generatedkeys;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.generatedkeys.identity.IdentityGeneratedKeysTest;
+import org.hibernate.test.generatedkeys.select.SelectGeneratorTest;
+import org.hibernate.test.generatedkeys.seqidentity.SequenceIdentityTest;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class GeneratedKeysSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "generated keys suite" );
+		suite.addTest( IdentityGeneratedKeysTest.suite() );
+		suite.addTest( SelectGeneratorTest.suite() );
+		suite.addTest( SequenceIdentityTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/IdentityGeneratedKeysTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/IdentityGeneratedKeysTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/IdentityGeneratedKeysTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,160 @@
+package org.hibernate.test.generatedkeys.identity;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Steve Ebersole
+ */
+public class IdentityGeneratedKeysTest extends DatabaseSpecificFunctionalTestCase {
+	public IdentityGeneratedKeysTest(String name) {
+		super( name );
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "generatedkeys/identity/MyEntity.hbm.xml" };
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		return dialect.supportsIdentityColumns();
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( IdentityGeneratedKeysTest.class );
+	}
+
+	public void testIdentityColumnGeneratedIds() {
+		Session s = openSession();
+		s.beginTransaction();
+		MyEntity myEntity = new MyEntity( "test" );
+		Long id = ( Long ) s.save( myEntity );
+		assertNotNull( "identity column did not force immediate insert", id );
+		assertEquals( id, myEntity.getId() );
+		s.delete( myEntity );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testPersistOutsideTransaction() {
+		Session s = openSession();
+
+		// first test save() which should force an immediate insert...
+		MyEntity myEntity1 = new MyEntity( "test-save" );
+		Long id = ( Long ) s.save( myEntity1 );
+		assertNotNull( "identity column did not force immediate insert", id );
+		assertEquals( id, myEntity1.getId() );
+
+		// next test persist() which should cause a delayed insert...
+		long initialInsertCount = sfi().getStatistics().getEntityInsertCount();
+		MyEntity myEntity2 = new MyEntity( "test-persist");
+		s.persist( myEntity2 );
+		assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() );
+		assertNull( myEntity2.getId() );
+
+		// an explicit flush should cause execution of the delayed insertion
+		s.flush();
+		assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 1, sfi().getStatistics().getEntityInsertCount() );
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( myEntity1 );
+		s.delete( myEntity2 );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testPersistOutsideTransactionCascadedToNonInverseCollection() {
+		long initialInsertCount = sfi().getStatistics().getEntityInsertCount();
+		Session s = openSession();
+		MyEntity myEntity = new MyEntity( "test-persist");
+		myEntity.getNonInverseChildren().add( new MyChild( "test-child-persist-non-inverse" ) );
+		s.persist( myEntity );
+		assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() );
+		assertNull( myEntity.getId() );
+		s.flush();
+		assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 2, sfi().getStatistics().getEntityInsertCount() );
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		s.createQuery( "delete MyChild" ).executeUpdate();
+		s.createQuery( "delete MyEntity" ).executeUpdate();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testPersistOutsideTransactionCascadedToInverseCollection() {
+		long initialInsertCount = sfi().getStatistics().getEntityInsertCount();
+		Session s = openSession();
+		MyEntity myEntity2 = new MyEntity( "test-persist-2");
+		MyChild child = new MyChild( "test-child-persist-inverse" );
+		myEntity2.getInverseChildren().add( child );
+		child.setInverseParent( myEntity2 );
+		s.persist( myEntity2 );
+		assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() );
+		assertNull( myEntity2.getId() );
+		s.flush();
+		assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 2, sfi().getStatistics().getEntityInsertCount() );
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		s.createQuery( "delete MyChild" ).executeUpdate();
+		s.createQuery( "delete MyEntity" ).executeUpdate();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testPersistOutsideTransactionCascadedToManyToOne() {
+		long initialInsertCount = sfi().getStatistics().getEntityInsertCount();
+		Session s = openSession();
+		MyEntity myEntity = new MyEntity( "test-persist");
+		myEntity.setSibling( new MySibling( "test-persist-sibling-out" ) );
+		s.persist( myEntity );
+		assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() );
+		assertNull( myEntity.getId() );
+		s.flush();
+		assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 2, sfi().getStatistics().getEntityInsertCount() );
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		s.createQuery( "delete MyEntity" ).executeUpdate();
+		s.createQuery( "delete MySibling" ).executeUpdate();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testPersistOutsideTransactionCascadedFromManyToOne() {
+		long initialInsertCount = sfi().getStatistics().getEntityInsertCount();
+		Session s = openSession();
+		MyEntity myEntity2 = new MyEntity( "test-persist-2");
+		MySibling sibling = new MySibling( "test-persist-sibling-in" );
+		sibling.setEntity( myEntity2 );
+		s.persist( sibling );
+		assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() );
+		assertNull( myEntity2.getId() );
+		s.flush();
+		assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 2, sfi().getStatistics().getEntityInsertCount() );
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		s.createQuery( "delete MySibling" ).executeUpdate();
+		s.createQuery( "delete MyEntity" ).executeUpdate();
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MyChild.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MyChild.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MyChild.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+package org.hibernate.test.generatedkeys.identity;
+
+/**
+ * @author Steve Ebersole
+ */
+public class MyChild {
+	private Long id;
+	private String name;
+	private MyEntity inverseParent;
+
+	public MyChild() {
+	}
+
+	public MyChild(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public MyEntity getInverseParent() {
+		return inverseParent;
+	}
+
+	public void setInverseParent(MyEntity inverseParent) {
+		this.inverseParent = inverseParent;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MyEntity.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MyEntity.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MyEntity.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.generatedkeys.identity" default-access="field">
+
+    <class name="MyEntity" table="my_entity">
+    	<id name="id">
+    		<generator class="identity"/>
+    	</id>
+        <property name="name"/>
+
+        <!-- used to test cascades "out" to a many-to-one association -->
+        <many-to-one name="sibling" class="MySibling" cascade="persist, merge"/>
+
+        <!-- used to test cascades "out" to non-inverse collections -->
+        <set name="nonInverseChildren" inverse="false" cascade="persist, merge">
+            <key column="non_inv_parent_id"/>
+            <one-to-many class="MyChild"/>
+        </set>
+
+        <!-- used to test cascades "out" to inverse collections -->
+        <set name="inverseChildren" inverse="true" cascade="persist, merge">
+            <key column="inv_parent_id"/>
+            <one-to-many class="MyChild"/>
+        </set>
+    </class>
+
+
+    <class name="MySibling" table="my_sibling">
+        <id name="id">
+            <generator class="increment"/>
+        </id>
+        <property name="name"/>
+        <many-to-one name="entity" class="MyEntity" cascade="persist, merge"/>
+    </class>
+
+
+    <class name="MyChild" table="my_child">
+        <id name="id">
+            <generator class="increment"/>
+        </id>
+        <property name="name"/>
+        <many-to-one name="inverseParent" column="inv_parent_id" class="MyEntity"/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MyEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MyEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MyEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+package org.hibernate.test.generatedkeys.identity;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * @author Steve Ebersole
+ */
+public class MyEntity {
+	private Long id;
+	private String name;
+	private MySibling sibling;
+	private Set nonInverseChildren = new HashSet();
+	private Set inverseChildren = new HashSet();
+
+	public MyEntity() {
+	}
+
+	public MyEntity(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public MySibling getSibling() {
+		return sibling;
+	}
+
+	public void setSibling(MySibling sibling) {
+		this.sibling = sibling;
+	}
+
+	public Set getNonInverseChildren() {
+		return nonInverseChildren;
+	}
+
+	public void setNonInverseChildren(Set nonInverseChildren) {
+		this.nonInverseChildren = nonInverseChildren;
+	}
+
+	public Set getInverseChildren() {
+		return inverseChildren;
+	}
+
+	public void setInverseChildren(Set inverseChildren) {
+		this.inverseChildren = inverseChildren;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MySibling.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MySibling.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/identity/MySibling.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+package org.hibernate.test.generatedkeys.identity;
+
+/**
+ * @author Steve Ebersole
+ */
+public class MySibling {
+	private Long id;
+	private String name;
+	private MyEntity entity;
+
+	public MySibling() {
+	}
+
+	public MySibling(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public MyEntity getEntity() {
+		return entity;
+	}
+
+	public void setEntity(MyEntity entity) {
+		this.entity = entity;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/select/MyEntity.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/select/MyEntity.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/select/MyEntity.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.generatedkeys.select" default-access="field">
+
+    <class name="MyEntity" table="my_entity">
+
+    	<id name="id">
+    		<generator class="select"/>
+    	</id>
+        <natural-id>
+            <property name="name"/>
+        </natural-id>
+	</class>
+
+    <database-object>
+        <create>
+            <![CDATA[CREATE OR REPLACE TRIGGER t_i_my_entity
+            BEFORE INSERT ON my_entity
+            FOR EACH ROW
+            BEGIN
+                select nvl( max(id), 0 ) + 1
+                into :new.id
+                from my_entity;
+            END;]]>
+        </create>
+        <drop>
+            <![CDATA[DROP TRIGGER t_i_my_entity]]>
+        </drop>
+        <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/>
+        <dialect-scope name="org.hibernate.dialect.OracleDialect"/>
+    </database-object>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/select/MyEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/select/MyEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/select/MyEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+package org.hibernate.test.generatedkeys.select;
+
+/**
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class MyEntity {
+	private Long id;
+	private String name;
+
+	public MyEntity() {
+	}
+
+	public MyEntity(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/select/SelectGeneratorTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/select/SelectGeneratorTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/select/SelectGeneratorTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+package org.hibernate.test.generatedkeys.select;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.dialect.DataDirectOracle9Dialect;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Steve Ebersole
+ */
+public class SelectGeneratorTest extends DatabaseSpecificFunctionalTestCase {
+	public SelectGeneratorTest(String x) {
+		super( x );
+	}
+
+	// TODO : need to determine appropriate physical generation strategies for select-generator testing on other databases...
+
+	public String[] getMappings() {
+		return new String[] { "generatedkeys/select/MyEntity.hbm.xml" };
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		return ( dialect instanceof Oracle9Dialect );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SelectGeneratorTest.class );
+	}
+
+	public void testJDBC3GetGeneratedKeysSupportOnOracle() {
+		if ( getDialect() instanceof DataDirectOracle9Dialect ) {
+			reportSkip( "DataDirect drivers known to not support JDBC3 getGeneratedKeys for Oracle", "oracle getGeneratedKeys support" );
+			return;
+		}
+		Session session = openSession();
+		session.beginTransaction();
+
+		MyEntity e = new MyEntity( "entity-1" );
+		session.save( e );
+
+		// this insert should happen immediately!
+		assertEquals( "id not generated through forced insertion", new Long(1), e.getId() );
+
+		session.delete( e );
+		session.getTransaction().commit();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/seqidentity/MyEntity.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/seqidentity/MyEntity.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/seqidentity/MyEntity.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.generatedkeys.seqidentity" default-access="field">
+
+    <class name="MyEntity" table="my_entity">
+
+    	<id name="id">
+    		<generator class="sequence-identity"/>
+    	</id>
+        <natural-id>
+            <property name="name"/>
+        </natural-id>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/seqidentity/MyEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/seqidentity/MyEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/seqidentity/MyEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+package org.hibernate.test.generatedkeys.seqidentity;
+
+/**
+ * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ */
+public class MyEntity {
+	private Long id;
+	private String name;
+
+	public MyEntity() {
+	}
+
+	public MyEntity(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/seqidentity/SequenceIdentityTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/seqidentity/SequenceIdentityTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/generatedkeys/seqidentity/SequenceIdentityTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+package org.hibernate.test.generatedkeys.seqidentity;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.dialect.DataDirectOracle9Dialect;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Steve Ebersole
+ */
+public class SequenceIdentityTest extends DatabaseSpecificFunctionalTestCase {
+	public SequenceIdentityTest(String x) {
+		super( x );
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		// the DataDirect driver for Oracle known to not support
+		// JDBC3 getGeneratedKeys...
+		return ( dialect instanceof Oracle9Dialect ) && ( ! ( dialect instanceof DataDirectOracle9Dialect ) ) ;
+	}
+
+	public String[] getMappings() {
+		return new String[] { "generatedkeys/seqidentity/MyEntity.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SequenceIdentityTest.class );
+	}
+
+	public void testSequenceIdentityGenerator() {
+		Session session = openSession();
+		session.beginTransaction();
+
+		MyEntity e = new MyEntity( "entity-1" );
+		session.save( e );
+
+		// this insert should happen immediately!
+		assertEquals( "id not generated through forced insertion", new Long(1), e.getId() );
+
+		session.delete( e );
+		session.getTransaction().commit();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1925 @@
+// $Id: ASTParserLoadingTest.java 11373 2007-03-29 19:09:07Z steve.ebersole at jboss.com $
+package org.hibernate.test.hql;
+
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.QueryException;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.TypeMismatchException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.DB2Dialect;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.dialect.PostgreSQLDialect;
+import org.hibernate.dialect.SQLServerDialect;
+import org.hibernate.dialect.SybaseDialect;
+import org.hibernate.hql.ast.ASTQueryTranslatorFactory;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.stat.QueryStatistics;
+import org.hibernate.test.any.IntegerPropertyValue;
+import org.hibernate.test.any.PropertySet;
+import org.hibernate.test.any.PropertyValue;
+import org.hibernate.test.any.StringPropertyValue;
+import org.hibernate.test.cid.Customer;
+import org.hibernate.test.cid.LineItem;
+import org.hibernate.test.cid.Order;
+import org.hibernate.test.cid.Product;
+import org.hibernate.transform.DistinctRootEntityResultTransformer;
+import org.hibernate.transform.Transformers;
+import org.hibernate.type.ComponentType;
+import org.hibernate.type.ManyToOneType;
+import org.hibernate.type.Type;
+import org.hibernate.util.StringHelper;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Tests the integration of the new AST parser into the loading of query results using
+ * the Hibernate persisters and loaders.
+ * <p/>
+ * Also used to test the syntax of the resulting sql against the underlying
+ * database, specifically for functionality not supported by the classic
+ * parser.
+ *
+ * @author Steve
+ */
+public class ASTParserLoadingTest extends FunctionalTestCase {
+
+	private static final Log log = LogFactory.getLog( ASTParserLoadingTest.class );
+
+	private List createdAnimalIds = new ArrayList();
+
+	public ASTParserLoadingTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] {
+				"hql/Animal.hbm.xml",
+				"hql/FooBarCopy.hbm.xml",
+				"hql/SimpleEntityWithAssociation.hbm.xml",
+				"hql/CrazyIdFieldNames.hbm.xml",
+				"batchfetch/ProductLine.hbm.xml",
+				"cid/Customer.hbm.xml",
+				"cid/Order.hbm.xml",
+				"cid/LineItem.hbm.xml",
+				"cid/Product.hbm.xml",
+				"any/Properties.hbm.xml",
+				"legacy/Commento.hbm.xml",
+				"legacy/Marelo.hbm.xml"
+		};
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.USE_QUERY_CACHE, "true" );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+		cfg.setProperty( Environment.QUERY_TRANSLATOR, ASTQueryTranslatorFactory.class.getName() );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ASTParserLoadingTest.class );
+	}
+
+	public void testInvalidCollectionDereferencesFail() {
+		Session s = openSession();
+		s.beginTransaction();
+
+		// control group...
+		s.createQuery( "from Animal a join a.offspring o where o.description = 'xyz'" ).list();
+		s.createQuery( "from Animal a join a.offspring o where o.father.description = 'xyz'" ).list();
+		s.createQuery( "from Animal a join a.offspring o order by o.description" ).list();
+		s.createQuery( "from Animal a join a.offspring o order by o.father.description" ).list();
+
+		try {
+			s.createQuery( "from Animal a where a.offspring.description = 'xyz'" ).list();
+			fail( "illegal collection dereference semantic did not cause failure" );
+		}
+		catch( QueryException qe ) {
+			log.trace( "expected failure...", qe );
+		}
+
+		try {
+			s.createQuery( "from Animal a where a.offspring.father.description = 'xyz'" ).list();
+			fail( "illegal collection dereference semantic did not cause failure" );
+		}
+		catch( QueryException qe ) {
+			log.trace( "expected failure...", qe );
+		}
+
+		try {
+			s.createQuery( "from Animal a order by a.offspring.description" ).list();
+			fail( "illegal collection dereference semantic did not cause failure" );
+		}
+		catch( QueryException qe ) {
+			log.trace( "expected failure...", qe );
+		}
+
+		try {
+			s.createQuery( "from Animal a order by a.offspring.father.description" ).list();
+			fail( "illegal collection dereference semantic did not cause failure" );
+		}
+		catch( QueryException qe ) {
+			log.trace( "expected failure...", qe );
+		}
+
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	/**
+	 * Copied from {@link HQLTest#testConcatenation}
+	 */
+	public void testConcatenation() {
+		// simple syntax checking...
+		Session s = openSession();
+		s.beginTransaction();
+		s.createQuery( "from Human h where h.nickName = '1' || 'ov' || 'tha' || 'few'" ).list();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	/**
+	 * Copied from {@link HQLTest#testExpressionWithParamInFunction}
+	 */
+	public void testExpressionWithParamInFunction() {
+		Session s = openSession();
+		s.beginTransaction();
+		s.createQuery( "from Animal a where abs(a.bodyWeight-:param) < 2.0" ).setLong( "param", 1 ).list();
+		s.createQuery( "from Animal a where abs(:param - a.bodyWeight) < 2.0" ).setLong( "param", 1 ).list();
+		if ( ! ( getDialect() instanceof HSQLDialect ) ) {
+			// HSQLDB does not like the abs(? - ?) syntax...
+			s.createQuery( "from Animal where abs(:x - :y) < 2.0" ).setLong( "x", 1 ).setLong( "y", 1 ).list();
+		}
+		s.createQuery( "from Animal where lower(upper(:foo)) like 'f%'" ).setString( "foo", "foo" ).list();
+		s.createQuery( "from Animal a where abs(abs(a.bodyWeight - 1.0 + :param) * abs(length('ffobar')-3)) = 3.0" ).setLong( "param", 1 ).list();
+		s.createQuery( "from Animal where lower(upper('foo') || upper(:bar)) like 'f%'" ).setString( "bar", "xyz" ).list();
+		if ( ! ( getDialect() instanceof PostgreSQLDialect || getDialect() instanceof MySQLDialect ) ) {
+			s.createQuery( "from Animal where abs(cast(1 as float) - cast(:param as float)) = 1.0" ).setLong( "param", 1 ).list();
+		}
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testCrazyIdFieldNames() {
+		MoreCrazyIdFieldNameStuffEntity top = new MoreCrazyIdFieldNameStuffEntity( "top" );
+		HeresAnotherCrazyIdFieldName next = new HeresAnotherCrazyIdFieldName( "next" );
+		top.setHeresAnotherCrazyIdFieldName( next );
+		MoreCrazyIdFieldNameStuffEntity other = new MoreCrazyIdFieldNameStuffEntity( "other" );
+		Session s = openSession();
+		s.beginTransaction();
+		s.save( next );
+		s.save( top );
+		s.save( other );
+		s.flush();
+
+		List results = s.createQuery( "select e.heresAnotherCrazyIdFieldName from MoreCrazyIdFieldNameStuffEntity e where e.heresAnotherCrazyIdFieldName is not null" ).list();
+		assertEquals( 1, results.size() );
+		Object result = results.get( 0 );
+		assertClassAssignability( HeresAnotherCrazyIdFieldName.class, result.getClass() );
+		assertSame( next, result );
+
+		results = s.createQuery( "select e.heresAnotherCrazyIdFieldName.heresAnotherCrazyIdFieldName from MoreCrazyIdFieldNameStuffEntity e where e.heresAnotherCrazyIdFieldName is not null" ).list();
+		assertEquals( 1, results.size() );
+		result = results.get( 0 );
+		assertClassAssignability( Long.class, result.getClass() );
+		assertEquals( next.getHeresAnotherCrazyIdFieldName(), result );
+
+		results = s.createQuery( "select e.heresAnotherCrazyIdFieldName from MoreCrazyIdFieldNameStuffEntity e" ).list();
+		assertEquals( 1, results.size() );
+		Iterator itr = s.createQuery( "select e.heresAnotherCrazyIdFieldName from MoreCrazyIdFieldNameStuffEntity e" ).iterate();
+		assertTrue( itr.hasNext() ); itr.next(); assertFalse( itr.hasNext() );
+
+		s.delete( top );
+		s.delete( next );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testImplicitJoinsInDifferentClauses() {
+		// HHH-2257 :
+		// both the classic and ast translators output the same syntactically valid sql
+		// for all of these cases; the issue is that shallow (iterate) and
+		// non-shallow (list/scroll) queries return different results because the
+		// shallow skips the inner join which "weeds out" results from the non-shallow queries.
+		// The results were initially different depending upon the clause(s) in which the
+		// implicit join occurred
+		Session s = openSession();
+		s.beginTransaction();
+		SimpleEntityWithAssociation owner = new SimpleEntityWithAssociation( "owner" );
+		SimpleAssociatedEntity e1 = new SimpleAssociatedEntity( "thing one", owner );
+		SimpleAssociatedEntity e2 = new SimpleAssociatedEntity( "thing two" );
+		s.save( e1 );
+		s.save( e2 );
+		s.save( owner );
+		s.getTransaction().commit();
+		s.close();
+
+		checkCounts( "select e.owner from SimpleAssociatedEntity e", 1, "implicit-join in select clause" );
+		checkCounts( "select e.id, e.owner from SimpleAssociatedEntity e", 1, "implicit-join in select clause" );
+
+		// resolved to a "id short cut" when part of the order by clause -> no inner join = no weeding out...
+		checkCounts( "from SimpleAssociatedEntity e order by e.owner", 2, "implicit-join in order-by clause" );
+		// resolved to a "id short cut" when part of the group by clause -> no inner join = no weeding out...
+		checkCounts( "select e.owner.id, count(*) from SimpleAssociatedEntity e group by e.owner", 2, "implicit-join in select and group-by clauses" );
+
+	 	s = openSession();
+		s.beginTransaction();
+		s.delete( e1 );
+		s.delete( e2 );
+		s.delete( owner );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	private void checkCounts(String hql, int expected, String testCondition) {
+		Session s = openSession();
+		s.beginTransaction();
+		int count = determineCount( s.createQuery( hql ).list().iterator() );
+		assertEquals( "list() [" + testCondition + "]", expected, count );
+		count = determineCount( s.createQuery( hql ).iterate() );
+		assertEquals( "iterate() [" + testCondition + "]", expected, count );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testImplicitSelectEntityAssociationInShallowQuery() {
+		// HHH-2257 :
+		// both the classic and ast translators output the same syntactically valid sql.
+		// the issue is that shallow and non-shallow queries return different
+		// results because the shallow skips the inner join which "weeds out" results
+		// from the non-shallow queries...
+		Session s = openSession();
+		s.beginTransaction();
+		SimpleEntityWithAssociation owner = new SimpleEntityWithAssociation( "owner" );
+		SimpleAssociatedEntity e1 = new SimpleAssociatedEntity( "thing one", owner );
+		SimpleAssociatedEntity e2 = new SimpleAssociatedEntity( "thing two" );
+		s.save( e1 );
+		s.save( e2 );
+		s.save( owner );
+		s.getTransaction().commit();
+		s.close();
+
+	 	s = openSession();
+		s.beginTransaction();
+		int count = determineCount( s.createQuery( "select e.id, e.owner from SimpleAssociatedEntity e" ).list().iterator() );
+		assertEquals( 1, count ); // thing two would be removed from the result due to the inner join
+		count = determineCount( s.createQuery( "select e.id, e.owner from SimpleAssociatedEntity e" ).iterate() );
+		assertEquals( 1, count );
+		s.getTransaction().commit();
+		s.close();
+
+	 	s = openSession();
+		s.beginTransaction();
+		s.delete( e1 );
+		s.delete( e2 );
+		s.delete( owner );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	private int determineCount(Iterator iterator) {
+		int count = 0;
+		while( iterator.hasNext() ) {
+			count++;
+			iterator.next();
+		}
+		return count;
+	}
+
+	public void testNestedComponentIsNull() {
+		// (1) From MapTest originally...
+		// (2) Was then moved into HQLTest...
+		// (3) However, a bug fix to EntityType#getIdentifierOrUniqueKeyType (HHH-2138)
+		// 		caused the classic parser to suddenly start throwing exceptions on
+		//		this query, apparently relying on the buggy behavior somehow; thus
+		//		moved here to at least get some syntax checking...
+		//
+		// fyi... found and fixed the problem in the classic parser; still
+		// leaving here for syntax checking
+		new SyntaxChecker( "from Commento c where c.marelo.commento.mcompr is null" ).checkAll();
+	}
+
+	public void testSpecialClassPropertyReference() {
+		// this is a long standing bug in Hibernate when applied to joined-subclasses;
+		//  see HHH-939 for details and history
+		new SyntaxChecker( "from Zoo zoo where zoo.class = PettingZoo" ).checkAll();
+		new SyntaxChecker( "select a.description from Animal a where a.class = Mammal" ).checkAll();
+		new SyntaxChecker( "select a.class from Animal a" ).checkAll();
+		new SyntaxChecker( "from DomesticAnimal an where an.class = Dog" ).checkAll();
+		new SyntaxChecker( "from Animal an where an.class = Dog" ).checkAll();
+	}
+
+	public void testSpecialClassPropertyReferenceFQN() {
+		// tests relating to HHH-2376
+		new SyntaxChecker( "from Zoo zoo where zoo.class = org.hibernate.test.hql.PettingZoo" ).checkAll();
+		new SyntaxChecker( "select a.description from Animal a where a.class = org.hibernate.test.hql.Mammal" ).checkAll();
+		new SyntaxChecker( "from DomesticAnimal an where an.class = org.hibernate.test.hql.Dog" ).checkAll();
+		new SyntaxChecker( "from Animal an where an.class = org.hibernate.test.hql.Dog" ).checkAll();
+	}
+
+	public void testSubclassOrSuperclassPropertyReferenceInJoinedSubclass() {
+		// this is a long standing bug in Hibernate; see HHH-1631 for details and history
+		//
+		// (1) pregnant is defined as a property of the class (Mammal) itself
+		// (2) description is defined as a property of the superclass (Animal)
+		// (3) name is defined as a property of a particular subclass (Human)
+
+		new SyntaxChecker( "from Zoo z join z.mammals as m where m.name.first = 'John'" ).checkIterate();
+
+		new SyntaxChecker( "from Zoo z join z.mammals as m where m.pregnant = false" ).checkAll();
+		new SyntaxChecker( "select m.pregnant from Zoo z join z.mammals as m where m.pregnant = false" ).checkAll();
+
+		new SyntaxChecker( "from Zoo z join z.mammals as m where m.description = 'tabby'" ).checkAll();
+		new SyntaxChecker( "select m.description from Zoo z join z.mammals as m where m.description = 'tabby'" ).checkAll();
+
+		new SyntaxChecker( "from Zoo z join z.mammals as m where m.name.first = 'John'" ).checkAll();
+		new SyntaxChecker( "select m.name from Zoo z join z.mammals as m where m.name.first = 'John'" ).checkAll();
+
+		new SyntaxChecker( "select m.pregnant from Zoo z join z.mammals as m" ).checkAll();
+		new SyntaxChecker( "select m.description from Zoo z join z.mammals as m" ).checkAll();
+		new SyntaxChecker( "select m.name from Zoo z join z.mammals as m" ).checkAll();
+
+		new SyntaxChecker( "from DomesticAnimal da join da.owner as o where o.nickName = 'Gavin'" ).checkAll();
+		new SyntaxChecker( "select da.father from DomesticAnimal da join da.owner as o where o.nickName = 'Gavin'" ).checkAll();
+	}
+
+	public void testSimpleSelectWithLimitAndOffset() throws Exception {
+		if ( ! ( getDialect().supportsLimit() && getDialect().supportsLimitOffset() ) ) {
+			reportSkip( "dialect does not support offset and limit combo", "limit and offset combination" );
+			return;
+		}
+
+		// just checking correctness of param binding code...
+		Session session = openSession();
+		session.createQuery( "from Animal" )
+				.setFirstResult( 2 )
+				.setMaxResults( 1 )
+				.list();
+		session.close();
+	}
+
+	public void testJPAPositionalParameterList() {
+		Session s = openSession();
+		s.beginTransaction();
+		ArrayList params = new ArrayList();
+		params.add( "Doe" );
+		params.add( "Public" );
+		s.createQuery( "from Human where name.last in (?1)" )
+				.setParameterList( "1", params )
+				.list();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testComponentQueries() {
+		Session s = openSession();
+		s.beginTransaction();
+
+		Type[] types = s.createQuery( "select h.name from Human h" ).getReturnTypes();
+		assertEquals( 1, types.length );
+		assertTrue( types[0] instanceof ComponentType );
+
+		// Test the ability to perform comparisions between component values
+		s.createQuery( "from Human h where h.name = h.name" ).list();
+		s.createQuery( "from Human h where h.name = :name" ).setParameter( "name", new Name() ).list();
+		s.createQuery( "from Human where name = :name" ).setParameter( "name", new Name() ).list();
+		s.createQuery( "from Human h where :name = h.name" ).setParameter( "name", new Name() ).list();
+		s.createQuery( "from Human h where :name <> h.name" ).setParameter( "name", new Name() ).list();
+
+		// Test the ability to perform comparisions between a component and an explicit row-value
+		s.createQuery( "from Human h where h.name = ('John', 'X', 'Doe')" ).list();
+		s.createQuery( "from Human h where ('John', 'X', 'Doe') = h.name" ).list();
+		s.createQuery( "from Human h where ('John', 'X', 'Doe') <> h.name" ).list();
+		s.createQuery( "from Human h where ('John', 'X', 'Doe') >= h.name" ).list();
+
+		s.createQuery( "from Human h order by h.name" ).list();
+
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testComponentParameterBinding() {
+		// HHH-1774 : parameters are bound incorrectly with component parameters...
+		Session s = openSession();
+		s.beginTransaction();
+
+		Order.Id oId = new Order.Id( "1234", 1 );
+
+		// control
+		s.createQuery("from Order o where o.customer.name =:name and o.id = :id")
+				.setParameter( "name", "oracle" )
+				.setParameter( "id", oId )
+				.list();
+
+		// this is the form that caused problems in the original case...
+		s.createQuery("from Order o where o.id = :id and o.customer.name =:name ")
+				.setParameter( "id", oId )
+				.setParameter( "name", "oracle" )
+				.list();
+
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testAnyMappingReference() {
+		Session s = openSession();
+		s.beginTransaction();
+
+		PropertyValue redValue = new StringPropertyValue( "red" );
+		PropertyValue lonliestNumberValue = new IntegerPropertyValue( 1 );
+
+		Long id;
+		PropertySet ps = new PropertySet( "my properties" );
+		ps.setSomeSpecificProperty( redValue );
+		ps.getGeneralProperties().put( "the lonliest number", lonliestNumberValue );
+		ps.getGeneralProperties().put( "i like", new StringPropertyValue( "pina coladas" ) );
+		ps.getGeneralProperties().put( "i also like", new StringPropertyValue( "getting caught in the rain" ) );
+		s.save( ps );
+
+		s.getTransaction().commit();
+		id = ps.getId();
+		s.clear();
+		s.beginTransaction();
+
+		// TODO : setEntity() currently will not work here, but that would be *very* nice
+		// does not work because the corresponding EntityType is then used as the "bind type" rather
+		// than the "discovered" AnyType...
+		s.createQuery( "from PropertySet p where p.someSpecificProperty = :ssp" ).setParameter( "ssp", redValue ).list();
+
+		s.createQuery( "from PropertySet p where p.someSpecificProperty.id is not null" ).list();
+
+		s.createQuery( "from PropertySet p join p.generalProperties gp where gp.id is not null" ).list();
+
+		s.delete( s.load( PropertySet.class, id ) );
+
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testJdkEnumStyleEnumConstant() throws Exception {
+		Session s = openSession();
+		s.beginTransaction();
+
+		s.createQuery( "from Zoo z where z.classification = org.hibernate.test.hql.Classification.LAME" ).list();
+
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testParameterTypeMismatchFailureExpected() {
+		Session s = openSession();
+		s.beginTransaction();
+
+		Query query = s.createQuery( "from Animal a where a.description = :nonstring" )
+				.setParameter( "nonstring", new Integer(1) );
+		try {
+			query.list();
+			fail( "query execution should have failed" );
+		}
+		catch( TypeMismatchException tme ) {
+			// expected behavior
+		}
+
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testMultipleBagFetchesFail() {
+		Session s = openSession();
+		s.beginTransaction();
+		try {
+			s.createQuery( "from Human h join fetch h.friends f join fetch f.friends fof" ).list();
+			fail( "failure expected" );
+		}
+		catch( HibernateException e ) {
+			assertTrue( "unexpected failure reason : " + e, e.getMessage().indexOf( "multiple bags" ) > 0 );
+		}
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testCollectionJoinsInSubselect() {
+		// HHH-1248 : initially FromElementFactory treated any explicit join
+		// as an implied join so that theta-style joins would always be used.
+		// This was because correlated subqueries cannot use ANSI-style joins
+		// for the correlation.  However, this special treatment was not limited
+		// to only correlated subqueries; it was applied to any subqueries ->
+		// which in-and-of-itself is not necessarily bad.  But somewhere later
+		// the choices made there caused joins to be dropped.
+		Session s = openSession();
+		String qryString =
+				"select a.id, a.description" +
+				" from Animal a" +
+				"       left join a.offspring" +
+				" where a in (" +
+				"       select a1 from Animal a1" +
+				"           left join a1.offspring o" +
+				"       where a1.id=1" +
+		        ")";
+		s.createQuery( qryString ).list();
+		qryString =
+				"select h.id, h.description" +
+		        " from Human h" +
+				"      left join h.friends" +
+				" where h in (" +
+				"      select h1" +
+				"      from Human h1" +
+				"          left join h1.friends f" +
+				"      where h1.id=1" +
+				")";
+		s.createQuery( qryString ).list();
+		qryString =
+				"select h.id, h.description" +
+		        " from Human h" +
+				"      left join h.friends f" +
+				" where f in (" +
+				"      select h1" +
+				"      from Human h1" +
+				"          left join h1.friends f1" +
+				"      where h = f1" +
+				")";
+		s.createQuery( qryString ).list();
+		s.close();
+	}
+
+	public void testCollectionFetchWithDistinctionAndLimit() {
+		// create some test data...
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		int parentCount = 30;
+		for ( int i = 0; i < parentCount; i++ ) {
+			Animal child1 = new Animal();
+			child1.setDescription( "collection fetch distinction (child1 - parent" + i + ")" );
+			s.persist( child1 );
+			Animal child2 = new Animal();
+			child2.setDescription( "collection fetch distinction (child2 - parent " + i + ")" );
+			s.persist( child2 );
+			Animal parent = new Animal();
+			parent.setDescription( "collection fetch distinction (parent" + i + ")" );
+			parent.setSerialNumber( "123-" + i );
+			parent.addOffspring( child1 );
+			parent.addOffspring( child2 );
+			s.persist( parent );
+		}
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		// Test simple distinction
+		List results;
+		results = s.createQuery( "select distinct p from Animal p inner join fetch p.offspring" ).list();
+		assertEquals( "duplicate list() returns", 30, results.size() );
+		// Test first/max
+		results = s.createQuery( "select p from Animal p inner join fetch p.offspring order by p.id" )
+				.setFirstResult( 5 )
+				.setMaxResults( 20 )
+				.list();
+		assertEquals( "duplicate returns", 20, results.size() );
+		Animal firstReturn = ( Animal ) results.get( 0 );
+		assertEquals( "firstResult not applied correctly", "123-5", firstReturn.getSerialNumber() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery( "delete Animal where mother is not null" ).executeUpdate();
+		s.createQuery( "delete Animal" ).executeUpdate();
+		t.commit();
+		s.close();
+	}
+
+	public void testFetchInSubqueryFails() {
+		Session s = openSession();
+		try {
+			s.createQuery( "from Animal a where a.mother in (select m from Animal a1 inner join a1.mother as m join fetch m.mother)" ).list();
+			fail( "fetch join allowed in subquery" );
+		}
+		catch( QueryException expected ) {
+			// expected behavior
+		}
+		s.close();
+	}
+
+	public void testQueryMetadataRetrievalWithFetching() {
+		// HHH-1464 : there was a problem due to the fact they we polled
+		// the shallow version of the query plan to get the metadata.
+		Session s = openSession();
+		Query query = s.createQuery( "from Animal a inner join fetch a.mother" );
+		assertEquals( 1, query.getReturnTypes().length );
+		assertNull( query.getReturnAliases() );
+		s.close();
+	}
+
+	public void testSuperclassPropertyReferenceAfterCollectionIndexedAccess() {
+		// note: simply performing syntax checking in the db
+		// test for HHH-429
+		Session s = openSession();
+		s.beginTransaction();
+		Mammal tiger = new Mammal();
+		tiger.setDescription( "Tiger" );
+		s.persist( tiger );
+		Mammal mother = new Mammal();
+		mother.setDescription( "Tiger's mother" );
+		mother.setBodyWeight( 4.0f );
+		mother.addOffspring( tiger );
+		s.persist( mother );
+		Zoo zoo = new Zoo();
+		zoo.setName( "Austin Zoo" );
+		zoo.setMammals( new HashMap() );
+		zoo.getMammals().put( "tiger", tiger );
+		s.persist( zoo );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		List results = s.createQuery( "from Zoo zoo where zoo.mammals['tiger'].mother.bodyWeight > 3.0f" ).list();
+		assertEquals( 1, results.size() );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( tiger );
+		s.delete( mother );
+		s.delete( zoo );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testJoinFetchCollectionOfValues() {
+		// note: simply performing syntax checking in the db
+		Session s = openSession();
+		s.beginTransaction();
+		s.createQuery( "select h from Human as h join fetch h.nickNames" ).list();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testIntegerLiterals() {
+		// note: simply performing syntax checking in the db
+		Session s = openSession();
+		s.beginTransaction();
+		s.createQuery( "from Foo where long = 1" ).list();
+		s.createQuery( "from Foo where long = " + Integer.MIN_VALUE ).list();
+		s.createQuery( "from Foo where long = " + Integer.MAX_VALUE ).list();
+		s.createQuery( "from Foo where long = 1L" ).list();
+		s.createQuery( "from Foo where long = " + (Long.MIN_VALUE + 1) + "L" ).list();
+		s.createQuery( "from Foo where long = " + Long.MAX_VALUE + "L" ).list();
+		s.createQuery( "from Foo where integer = " + (Long.MIN_VALUE + 1) ).list();
+// currently fails due to HHH-1387
+//		s.createQuery( "from Foo where long = " + Long.MIN_VALUE ).list();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testDecimalLiterals() {
+		// note: simply performing syntax checking in the db
+		Session s = openSession();
+		s.beginTransaction();
+		s.createQuery( "from Animal where bodyWeight > 100.0e-10" ).list();
+		s.createQuery( "from Animal where bodyWeight > 100.0E-10" ).list();
+		s.createQuery( "from Animal where bodyWeight > 100.001f" ).list();
+		s.createQuery( "from Animal where bodyWeight > 100.001F" ).list();
+		s.createQuery( "from Animal where bodyWeight > 100.001d" ).list();
+		s.createQuery( "from Animal where bodyWeight > 100.001D" ).list();
+		s.createQuery( "from Animal where bodyWeight > .001f" ).list();
+		s.createQuery( "from Animal where bodyWeight > 100e-10" ).list();
+		s.createQuery( "from Animal where bodyWeight > .01E-10" ).list();
+		s.createQuery( "from Animal where bodyWeight > 1e-38" ).list();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testNakedPropertyRef() {
+		// note: simply performing syntax and column/table resolution checking in the db
+		Session s = openSession();
+		s.beginTransaction();
+		s.createQuery( "from Animal where bodyWeight = bodyWeight" ).list();
+		s.createQuery( "select bodyWeight from Animal" ).list();
+		s.createQuery( "select max(bodyWeight) from Animal" ).list();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testNakedComponentPropertyRef() {
+		// note: simply performing syntax and column/table resolution checking in the db
+		Session s = openSession();
+		s.beginTransaction();
+		s.createQuery( "from Human where name.first = 'Gavin'" ).list();
+		s.createQuery( "select name from Human" ).list();
+		s.createQuery( "select upper(h.name.first) from Human as h" ).list();
+		s.createQuery( "select upper(name.first) from Human" ).list();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testNakedImplicitJoins() {
+		// note: simply performing syntax and column/table resolution checking in the db
+		Session s = openSession();
+		s.beginTransaction();
+		s.createQuery( "from Animal where mother.father.id = 1" ).list();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testNakedEntityAssociationReference() {
+		// note: simply performing syntax and column/table resolution checking in the db
+		Session s = openSession();
+		s.beginTransaction();
+		s.createQuery( "from Animal where mother = :mother" ).setParameter( "mother", null ).list();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testNakedMapIndex() throws Exception {
+		// note: simply performing syntax and column/table resolution checking in the db
+		Session s = openSession();
+		s.beginTransaction();
+		s.createQuery( "from Zoo where mammals['dog'].description like '%black%'" ).list();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testInvalidFetchSemantics() {
+		Session s = openSession();
+		s.beginTransaction();
+
+		try {
+			s.createQuery( "select mother from Human a left join fetch a.mother mother" ).list();
+			fail( "invalid fetch semantic allowed!" );
+		}
+		catch( QueryException e ) {
+		}
+
+		try {
+			s.createQuery( "select mother from Human a left join fetch a.mother mother" ).list();
+			fail( "invalid fetch semantic allowed!" );
+		}
+		catch( QueryException e ) {
+		}
+
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testArithmetic() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Zoo zoo = new Zoo();
+		zoo.setName("Melbourne Zoo");
+		s.persist(zoo);
+		s.createQuery("select 2*2*2*2*(2*2) from Zoo").uniqueResult();
+		s.createQuery("select 2 / (1+1) from Zoo").uniqueResult();
+		int result0 = ( (Integer) s.createQuery("select 2 - (1+1) from Zoo").uniqueResult() ).intValue();
+		int result1 = ( (Integer) s.createQuery("select 2 - 1 + 1 from Zoo").uniqueResult() ).intValue();
+		int result2 = ( (Integer) s.createQuery("select 2 * (1-1) from Zoo").uniqueResult() ).intValue();
+		int result3 = ( (Integer) s.createQuery("select 4 / (2 * 2) from Zoo").uniqueResult() ).intValue();
+		int result4 = ( (Integer) s.createQuery("select 4 / 2 * 2 from Zoo").uniqueResult() ).intValue();
+		int result5 = ( (Integer) s.createQuery("select 2 * (2/2) from Zoo").uniqueResult() ).intValue();
+		int result6 = ( (Integer) s.createQuery("select 2 * (2/2+1) from Zoo").uniqueResult() ).intValue();
+		assertEquals(result0, 0);
+		assertEquals(result1, 2);
+		assertEquals(result2, 0);
+		assertEquals(result3, 1);
+		assertEquals(result4, 4);
+		assertEquals(result5, 2);
+		assertEquals(result6, 4);
+		s.delete(zoo);
+		t.commit();
+		s.close();
+	}
+
+	public void testNestedCollectionFetch() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createQuery("from Animal a left join fetch a.offspring o left join fetch o.offspring where a.mother.id = 1 order by a.description").list();
+		s.createQuery("from Zoo z left join fetch z.animals a left join fetch a.offspring where z.name ='MZ' order by a.description").list();
+		s.createQuery("from Human h left join fetch h.pets a left join fetch a.offspring where h.name.first ='Gavin' order by a.description").list();
+		t.commit();
+		s.close();
+	}
+
+	public void testSelectClauseSubselect() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Zoo zoo = new Zoo();
+		zoo.setName("Melbourne Zoo");
+		zoo.setMammals( new HashMap() );
+		zoo.setAnimals( new HashMap() );
+		Mammal plat = new Mammal();
+		plat.setBodyWeight( 11f );
+		plat.setDescription( "Platypus" );
+		plat.setZoo(zoo);
+		plat.setSerialNumber("plat123");
+		zoo.getMammals().put("Platypus", plat);
+		zoo.getAnimals().put("plat123", plat);
+		s.persist( plat );
+		s.persist(zoo);
+
+		s.createQuery("select (select max(z.id) from a.zoo z) from Animal a").list();
+		s.createQuery("select (select max(z.id) from a.zoo z where z.name=:name) from Animal a")
+			.setParameter("name", "Melbourne Zoo").list();
+
+		s.delete(plat);
+		s.delete(zoo);
+		t.commit();
+		s.close();
+	}
+
+	public void testInitProxy() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Mammal plat = new Mammal();
+		plat.setBodyWeight( 11f );
+		plat.setDescription( "Platypus" );
+		s.persist( plat );
+		s.flush();
+		s.clear();
+		plat = (Mammal) s.load(Mammal.class, plat.getId() );
+		assertFalse( Hibernate.isInitialized(plat) );
+		Object plat2 = s.createQuery("from Animal a").uniqueResult();
+		assertSame(plat, plat2);
+		assertTrue( Hibernate.isInitialized(plat) );
+		s.delete(plat);
+		t.commit();
+		s.close();
+	}
+
+	public void testSelectClauseImplicitJoin() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Zoo zoo = new Zoo();
+		zoo.setName("The Zoo");
+		zoo.setMammals( new HashMap() );
+		zoo.setAnimals( new HashMap() );
+		Mammal plat = new Mammal();
+		plat.setBodyWeight( 11f );
+		plat.setDescription( "Platypus" );
+		plat.setZoo(zoo);
+		plat.setSerialNumber("plat123");
+		zoo.getMammals().put("Platypus", plat);
+		zoo.getAnimals().put("plat123", plat);
+		s.persist( plat );
+		s.persist(zoo);
+		s.flush();
+		s.clear();
+		Query q = s.createQuery("select distinct a.zoo from Animal a where a.zoo is not null");
+		Type type = q.getReturnTypes()[0];
+		assertTrue( type instanceof ManyToOneType );
+		assertEquals( ( (ManyToOneType) type ).getAssociatedEntityName(), "org.hibernate.test.hql.Zoo" );
+		zoo = (Zoo) q.list().get(0);
+		assertEquals( zoo.getMammals().size(), 1 );
+		assertEquals( zoo.getAnimals().size(), 1 );
+		s.clear();
+		s.delete(plat);
+		s.delete(zoo);
+		t.commit();
+		s.close();
+	}
+
+	public void testSelectClauseImplicitJoinWithIterate() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Zoo zoo = new Zoo();
+		zoo.setName("The Zoo");
+		zoo.setMammals( new HashMap() );
+		zoo.setAnimals( new HashMap() );
+		Mammal plat = new Mammal();
+		plat.setBodyWeight( 11f );
+		plat.setDescription( "Platypus" );
+		plat.setZoo(zoo);
+		plat.setSerialNumber("plat123");
+		zoo.getMammals().put("Platypus", plat);
+		zoo.getAnimals().put("plat123", plat);
+		s.persist( plat );
+		s.persist(zoo);
+		s.flush();
+		s.clear();
+		Query q = s.createQuery("select distinct a.zoo from Animal a where a.zoo is not null");
+		Type type = q.getReturnTypes()[0];
+		assertTrue( type instanceof ManyToOneType );
+		assertEquals( ( (ManyToOneType) type ).getAssociatedEntityName(), "org.hibernate.test.hql.Zoo" );
+		zoo = (Zoo) q
+			.iterate().next();
+		assertEquals( zoo.getMammals().size(), 1 );
+		assertEquals( zoo.getAnimals().size(), 1 );
+		s.clear();
+		s.delete(plat);
+		s.delete(zoo);
+		t.commit();
+		s.close();
+	}
+
+	public void testComponentOrderBy() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Long id1 = ( Long ) s.save( genSimpleHuman( "John", "Jacob" ) );
+		Long id2 = ( Long ) s.save( genSimpleHuman( "Jingleheimer", "Schmidt" ) );
+
+		s.flush();
+
+		// the component is defined with the firstName column first...
+		List results = s.createQuery( "from Human as h order by h.name" ).list();
+		assertEquals( "Incorrect return count", 2, results.size() );
+
+		Human h1 = ( Human ) results.get( 0 );
+		Human h2 = ( Human ) results.get( 1 );
+
+		assertEquals( "Incorrect ordering", id2, h1.getId() );
+		assertEquals( "Incorrect ordering", id1, h2.getId() );
+
+		s.delete( h1 );
+		s.delete( h2 );
+
+		t.commit();
+		s.close();
+	}
+
+	private Human genSimpleHuman(String fName, String lName) {
+		Human h = new Human();
+		h.setName( new Name() );
+		h.getName().setFirst( fName );
+		h.getName().setLast( lName );
+		h.getName().setInitial('X');
+
+		return h;
+	}
+
+	public void testCastInSelect() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Animal a = new Animal();
+		a.setBodyWeight(12.4f);
+		a.setDescription("an animal");
+		s.persist(a);
+		Integer bw = (Integer) s.createQuery("select cast(bodyWeight as integer) from Animal").uniqueResult();
+		bw = (Integer) s.createQuery("select cast(a.bodyWeight as integer) from Animal a").uniqueResult();
+		bw.toString();
+		s.delete(a);
+		t.commit();
+		s.close();
+	}
+
+	public void testAliases() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Animal a = new Animal();
+		a.setBodyWeight(12.4f);
+		a.setDescription("an animal");
+		s.persist(a);
+		String[] aliases1 = s.createQuery("select a.bodyWeight as abw, a.description from Animal a").getReturnAliases();
+		assertEquals(aliases1[0], "abw");
+		assertEquals(aliases1[1], "1");
+		String[] aliases2 = s.createQuery("select count(*), avg(a.bodyWeight) as avg from Animal a").getReturnAliases();
+		assertEquals(aliases2[0], "0");
+		assertEquals(aliases2[1], "avg");
+		s.delete(a);
+		t.commit();
+		s.close();
+	}
+
+	public void testParameterMixing() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createQuery( "from Animal a where a.description = ? and a.bodyWeight = ? or a.bodyWeight = :bw" )
+				.setString( 0, "something" )
+				.setFloat( 1, 12345f )
+				.setFloat( "bw", 123f )
+				.list();
+		t.commit();
+		s.close();
+	}
+
+	public void testOrdinalParameters() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createQuery( "from Animal a where a.description = ? and a.bodyWeight = ?" )
+				.setString( 0, "something" )
+				.setFloat( 1, 123f )
+				.list();
+		s.createQuery( "from Animal a where a.bodyWeight in (?, ?)" )
+				.setFloat( 0, 999f )
+				.setFloat( 1, 123f )
+				.list();
+		t.commit();
+		s.close();
+	}
+
+	public void testIndexParams() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createQuery("from Zoo zoo where zoo.mammals[:name] = :id")
+			.setParameter("name", "Walrus")
+			.setParameter("id", new Long(123))
+			.list();
+		s.createQuery("from Zoo zoo where zoo.mammals[:name].bodyWeight > :w")
+			.setParameter("name", "Walrus")
+			.setParameter("w", new Float(123.32))
+			.list();
+		s.createQuery("from Zoo zoo where zoo.animals[:sn].mother.bodyWeight < :mw")
+			.setParameter("sn", "ant-123")
+			.setParameter("mw", new Float(23.32))
+			.list();
+		/*s.createQuery("from Zoo zoo where zoo.animals[:sn].description like :desc and zoo.animals[:sn].bodyWeight > :wmin and zoo.animals[:sn].bodyWeight < :wmax")
+			.setParameter("sn", "ant-123")
+			.setParameter("desc", "%big%")
+			.setParameter("wmin", new Float(123.32))
+			.setParameter("wmax", new Float(167.89))
+			.list();*/
+		/*s.createQuery("from Human where addresses[:type].city = :city and addresses[:type].country = :country")
+			.setParameter("type", "home")
+			.setParameter("city", "Melbourne")
+			.setParameter("country", "Australia")
+			.list();*/
+		t.commit();
+		s.close();
+	}
+
+	public void testAggregation() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Human h = new Human();
+		h.setBodyWeight( (float) 74.0 );
+		h.setHeight(120.5);
+		h.setDescription("Me");
+		h.setName( new Name("Gavin", 'A', "King") );
+		h.setNickName("Oney");
+		s.persist(h);
+		Double sum = (Double) s.createQuery("select sum(h.bodyWeight) from Human h").uniqueResult();
+		Double avg = (Double) s.createQuery("select avg(h.height) from Human h").uniqueResult();
+		assertEquals(sum.floatValue(), 74.0, 0.01);
+		assertEquals(avg.doubleValue(), 120.5, 0.01);
+		Long id = (Long) s.createQuery("select max(a.id) from Animal a").uniqueResult();
+		s.delete(h);
+		t.commit();
+		s.close();
+	}
+
+	public void testSelectClauseCase() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Human h = new Human();
+		h.setBodyWeight( (float) 74.0 );
+		h.setHeight(120.5);
+		h.setDescription("Me");
+		h.setName( new Name("Gavin", 'A', "King") );
+		h.setNickName("Oney");
+		s.persist(h);
+		String name = (String) s.createQuery("select case nickName when 'Oney' then 'gavin' when 'Turin' then 'christian' else nickName end from Human").uniqueResult();
+		assertEquals(name, "gavin");
+		String result = (String) s.createQuery("select case when bodyWeight > 100 then 'fat' else 'skinny' end from Human").uniqueResult();
+		assertEquals(result, "skinny");
+		s.delete(h);
+		t.commit();
+		s.close();
+	}
+
+	public void testImplicitPolymorphism() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Product product = new Product();
+		product.setDescription( "My Product" );
+		product.setNumberAvailable( 10 );
+		product.setPrice( new BigDecimal( 123 ) );
+		product.setProductId( "4321" );
+		s.save( product );
+
+		List list = s.createQuery("from java.lang.Comparable").list();
+		assertEquals( list.size(), 0 );
+
+		list = s.createQuery("from java.lang.Object").list();
+		assertEquals( list.size(), 1 );
+
+		s.delete(product);
+
+		list = s.createQuery("from java.lang.Object").list();
+		assertEquals( list.size(), 0 );
+
+		t.commit();
+		s.close();
+	}
+
+	public void testCoalesce() {
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+		session.createQuery("from Human h where coalesce(h.nickName, h.name.first, h.name.last) = 'max'").list();
+		session.createQuery("select nullif(nickName, '1e1') from Human").list();
+		txn.commit();
+		session.close();
+	}
+
+	public void testStr() {
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+		Animal an = new Animal();
+		an.setBodyWeight(123.45f);
+		session.persist(an);
+		String str = (String) session.createQuery("select str(an.bodyWeight) from Animal an where str(an.bodyWeight) like '123%' or str(an.bodyWeight) like '1.23%'").uniqueResult();
+		if ( getDialect() instanceof DB2Dialect ) {
+			assertTrue( str.startsWith("1.234") );
+		}
+		else if ( getDialect() instanceof SQLServerDialect ) {
+			// no assertion as SQLServer always returns nulls here; even trying directly against the
+			// database, it seems to have problems with str() in the where clause...
+		}
+		else {
+			assertTrue( str.startsWith("123.4") );
+		}
+		if ( ! ( getDialect() instanceof SybaseDialect ) ) {
+			// In TransactSQL (the variant spoken by Sybase and SQLServer), the str() function
+			// is explicitly intended for numeric values only...
+			String dateStr1 = (String) session.createQuery("select str(current_date) from Animal").uniqueResult();
+			String dateStr2 = (String) session.createQuery("select str(year(current_date))||'-'||str(month(current_date))||'-'||str(day(current_date)) from Animal").uniqueResult();
+			System.out.println(dateStr1 + '=' + dateStr2);
+			if ( ! ( getDialect() instanceof Oracle9Dialect ) ) { //Oracle renders the name of the month :(
+				String[] dp1 = StringHelper.split("-", dateStr1);
+				String[] dp2 = StringHelper.split("-", dateStr2);
+				for (int i=0; i<3; i++) {
+					if ( dp1[i].startsWith( "0" ) ) {
+						dp1[i] = dp1[i].substring( 1 );
+					}
+					assertEquals( dp1[i], dp2[i] );
+				}
+			}
+		}
+		session.delete(an);
+		txn.commit();
+		session.close();
+	}
+
+	public void testCast() {
+		if ( ( getDialect() instanceof MySQLDialect ) || ( getDialect() instanceof DB2Dialect ) ) {
+			return;
+		}
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+		session.createQuery("from Human h where h.nickName like 'G%'").list();
+		session.createQuery("from Animal a where cast(a.bodyWeight as string) like '1.%'").list();
+		session.createQuery("from Animal a where cast(a.bodyWeight as integer) = 1").list();
+		txn.commit();
+		session.close();
+	}
+
+	public void testExtract() {
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+		session.createQuery("select second(current_timestamp()), minute(current_timestamp()), hour(current_timestamp()) from Mammal m").list();
+		session.createQuery("select day(m.birthdate), month(m.birthdate), year(m.birthdate) from Mammal m").list();
+		if ( !(getDialect() instanceof DB2Dialect) ) { //no ANSI extract
+			session.createQuery("select extract(second from current_timestamp()), extract(minute from current_timestamp()), extract(hour from current_timestamp()) from Mammal m").list();
+			session.createQuery("select extract(day from m.birthdate), extract(month from m.birthdate), extract(year from m.birthdate) from Mammal m").list();
+		}
+		txn.commit();
+		session.close();
+	}
+
+	public void testOneToManyFilter() throws Throwable {
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+
+		Product product = new Product();
+		product.setDescription( "My Product" );
+		product.setNumberAvailable( 10 );
+		product.setPrice( new BigDecimal( 123 ) );
+		product.setProductId( "4321" );
+		session.save( product );
+
+		Customer customer = new Customer();
+		customer.setCustomerId( "123456789" );
+		customer.setName( "My customer" );
+		customer.setAddress( "somewhere" );
+		session.save( customer );
+
+		Order order = customer.generateNewOrder( new BigDecimal( 1234 ) );
+		session.save( order );
+
+		LineItem li = order.generateLineItem( product, 5 );
+		session.save( li );
+
+		session.flush();
+
+		assertEquals( session.createFilter( customer.getOrders(), "" ).list().size(), 1 );
+
+		assertEquals( session.createFilter( order.getLineItems(), "" ).list().size(), 1 );
+		assertEquals( session.createFilter( order.getLineItems(), "where this.quantity > :quantity" ).setInteger( "quantity", 5 ).list().size(), 0 );
+
+		session.delete(li);
+		session.delete(order);
+		session.delete(product);
+		session.delete(customer);
+		txn.commit();
+		session.close();
+	}
+
+	public void testManyToManyFilter() throws Throwable {
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+
+		Human human = new Human();
+		human.setName( new Name() );
+		human.getName().setFirst( "Steve" );
+		human.getName().setInitial( 'L' );
+		human.getName().setLast( "Ebersole" );
+		session.save( human );
+
+		Human friend = new Human();
+		friend.setName( new Name() );
+		friend.getName().setFirst( "John" );
+		friend.getName().setInitial( 'Q' );
+		friend.getName().setLast( "Doe" );
+		friend.setBodyWeight( 11.0f );
+		session.save( friend );
+
+		human.setFriends( new ArrayList() );
+		friend.setFriends( new ArrayList() );
+		human.getFriends().add( friend );
+		friend.getFriends().add( human );
+
+		session.flush();
+
+		assertEquals( session.createFilter( human.getFriends(), "" ).list().size(), 1 );
+		assertEquals( session.createFilter( human.getFriends(), "where this.bodyWeight > ?" ).setFloat( 0, 10f ).list().size(), 1 );
+		assertEquals( session.createFilter( human.getFriends(), "where this.bodyWeight < ?" ).setFloat( 0, 10f ).list().size(), 0 );
+
+		session.delete(human);
+		session.delete(friend);
+
+		txn.commit();
+		session.close();
+	}
+
+	public void testSelectExpressions() {
+		createTestBaseData();
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+		Human h = new Human();
+		h.setName( new Name("Gavin", 'A', "King") );
+		h.setNickName("Oney");
+		h.setBodyWeight(1.0f);
+		session.persist(h);
+		List results = session.createQuery("select 'found', lower(h.name.first) from Human h where lower(h.name.first) = 'gavin'").list();
+		results = session.createQuery("select 'found', lower(h.name.first) from Human h where concat(h.name.first, ' ', h.name.initial, ' ', h.name.last) = 'Gavin A King'").list();
+		results = session.createQuery("select 'found', lower(h.name.first) from Human h where h.name.first||' '||h.name.initial||' '||h.name.last = 'Gavin A King'").list();
+		results = session.createQuery("select a.bodyWeight + m.bodyWeight from Animal a join a.mother m").list();
+		results = session.createQuery("select 2.0 * (a.bodyWeight + m.bodyWeight) from Animal a join a.mother m").list();
+		results = session.createQuery("select sum(a.bodyWeight + m.bodyWeight) from Animal a join a.mother m").list();
+		results = session.createQuery("select sum(a.mother.bodyWeight * 2.0) from Animal a").list();
+		results = session.createQuery("select concat(h.name.first, ' ', h.name.initial, ' ', h.name.last) from Human h").list();
+		results = session.createQuery("select h.name.first||' '||h.name.initial||' '||h.name.last from Human h").list();
+		results = session.createQuery("select nickName from Human").list();
+		results = session.createQuery("select lower(nickName) from Human").list();
+		results = session.createQuery("select abs(bodyWeight*-1) from Human").list();
+		results = session.createQuery("select upper(h.name.first||' ('||h.nickName||')') from Human h").list();
+		results = session.createQuery("select abs(a.bodyWeight-:param) from Animal a").setParameter("param", new Float(2.0)).list();
+		results = session.createQuery("select abs(:param - a.bodyWeight) from Animal a").setParameter("param", new Float(2.0)).list();
+		results = session.createQuery("select lower(upper('foo')) from Animal").list();
+		results = session.createQuery("select lower(upper('foo') || upper('bar')) from Animal").list();
+		results = session.createQuery("select sum(abs(bodyWeight - 1.0) * abs(length('ffobar')-3)) from Animal").list();
+		session.delete(h);
+		txn.commit();
+		session.close();
+		destroyTestBaseData();
+	}
+
+	private void createTestBaseData() {
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+
+		Mammal m1 = new Mammal();
+		m1.setBodyWeight( 11f );
+		m1.setDescription( "Mammal #1" );
+
+		session.save( m1 );
+
+		Mammal m2 = new Mammal();
+		m2.setBodyWeight( 9f );
+		m2.setDescription( "Mammal #2" );
+		m2.setMother( m1 );
+
+		session.save( m2 );
+
+		txn.commit();
+		session.close();
+
+		createdAnimalIds.add( m1.getId() );
+		createdAnimalIds.add( m2.getId() );
+	}
+
+	private void destroyTestBaseData() {
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+
+		for ( int i = 0; i < createdAnimalIds.size(); i++ ) {
+			Animal animal = ( Animal ) session.load( Animal.class, ( Long ) createdAnimalIds.get( i ) );
+			session.delete( animal );
+		}
+
+		txn.commit();
+		session.close();
+	}
+
+	public void testImplicitJoin() throws Exception {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+		Animal a = new Animal();
+		a.setBodyWeight(0.5f);
+		a.setBodyWeight(1.5f);
+		Animal b = new Animal();
+		Animal mother = new Animal();
+		mother.setBodyWeight(10.0f);
+		mother.addOffspring(a);
+		mother.addOffspring(b);
+		session.persist(a);
+		session.persist(b);
+		session.persist(mother);
+		List list = session.createQuery("from Animal a where a.mother.bodyWeight < 2.0 or a.mother.bodyWeight > 9.0").list();
+		assertEquals( list.size(), 2 );
+		list = session.createQuery("from Animal a where a.mother.bodyWeight > 2.0 and a.mother.bodyWeight > 9.0").list();
+		assertEquals( list.size(), 2 );
+		session.delete(b);
+		session.delete(a);
+		session.delete(mother);
+		t.commit();
+		session.close();
+	}
+
+	public void testFromOnly() throws Exception {
+
+		createTestBaseData();
+
+		Session session = openSession();
+
+		List results = session.createQuery( "from Animal" ).list();
+		assertEquals( "Incorrect result size", 2, results.size() );
+		assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Animal );
+
+		session.close();
+
+		destroyTestBaseData();
+	}
+
+	public void testSimpleSelect() throws Exception {
+
+		createTestBaseData();
+
+		Session session = openSession();
+
+		List results = session.createQuery( "select a from Animal as a" ).list();
+		assertEquals( "Incorrect result size", 2, results.size() );
+		assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Animal );
+
+		session.close();
+
+		destroyTestBaseData();
+	}
+
+	public void testEntityPropertySelect() throws Exception {
+
+		createTestBaseData();
+
+		Session session = openSession();
+
+		List results = session.createQuery( "select a.mother from Animal as a" ).list();
+//		assertEquals("Incorrect result size", 2, results.size());
+		assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Animal );
+
+		session.close();
+
+		destroyTestBaseData();
+	}
+
+	public void testWhere() throws Exception {
+
+		createTestBaseData();
+
+		Session session = openSession();
+		List results = null;
+
+		results = session.createQuery( "from Animal an where an.bodyWeight > 10" ).list();
+		assertEquals( "Incorrect result size", 1, results.size() );
+
+		results = session.createQuery( "from Animal an where not an.bodyWeight > 10" ).list();
+		assertEquals( "Incorrect result size", 1, results.size() );
+
+		results = session.createQuery( "from Animal an where an.bodyWeight between 0 and 10" ).list();
+		assertEquals( "Incorrect result size", 1, results.size() );
+
+		results = session.createQuery( "from Animal an where an.bodyWeight not between 0 and 10" ).list();
+		assertEquals( "Incorrect result size", 1, results.size() );
+
+		results = session.createQuery( "from Animal an where sqrt(an.bodyWeight)/2 > 10" ).list();
+		assertEquals( "Incorrect result size", 0, results.size() );
+
+		results = session.createQuery( "from Animal an where (an.bodyWeight > 10 and an.bodyWeight < 100) or an.bodyWeight is null" ).list();
+		assertEquals( "Incorrect result size", 1, results.size() );
+
+		session.close();
+
+		destroyTestBaseData();
+	}
+
+	public void testEntityFetching() throws Exception {
+
+		createTestBaseData();
+
+		Session session = openSession();
+
+		List results = session.createQuery( "from Animal an join fetch an.mother" ).list();
+		assertEquals( "Incorrect result size", 1, results.size() );
+		assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Animal );
+		Animal mother = ( ( Animal ) results.get( 0 ) ).getMother();
+		assertTrue( "fetch uninitialized", mother != null && Hibernate.isInitialized( mother ) );
+
+		results = session.createQuery( "select an from Animal an join fetch an.mother" ).list();
+		assertEquals( "Incorrect result size", 1, results.size() );
+		assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Animal );
+		mother = ( ( Animal ) results.get( 0 ) ).getMother();
+		assertTrue( "fetch uninitialized", mother != null && Hibernate.isInitialized( mother ) );
+
+		session.close();
+
+		destroyTestBaseData();
+	}
+
+	public void testCollectionFetching() throws Exception {
+
+		createTestBaseData();
+
+		Session session = openSession();
+		List results = session.createQuery( "from Animal an join fetch an.offspring" ).list();
+		assertEquals( "Incorrect result size", 1, results.size() );
+		assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Animal );
+		Collection os = ( ( Animal ) results.get( 0 ) ).getOffspring();
+		assertTrue( "fetch uninitialized", os != null && Hibernate.isInitialized( os ) && os.size() == 1 );
+
+		results = session.createQuery( "select an from Animal an join fetch an.offspring" ).list();
+		assertEquals( "Incorrect result size", 1, results.size() );
+		assertTrue( "Incorrect result return type", results.get( 0 ) instanceof Animal );
+		os = ( ( Animal ) results.get( 0 ) ).getOffspring();
+		assertTrue( "fetch uninitialized", os != null && Hibernate.isInitialized( os ) && os.size() == 1 );
+
+		session.close();
+
+		destroyTestBaseData();
+	}
+
+	public void testProjectionQueries() throws Exception {
+
+		createTestBaseData();
+
+		Session session = openSession();
+
+		List results = session.createQuery( "select an.mother.id, max(an.bodyWeight) from Animal an group by an.mother.id" ).list();
+		// mysql returns nulls in this group by
+		assertEquals( "Incorrect result size", 2, results.size() );
+		assertTrue( "Incorrect return type", results.get( 0 ) instanceof Object[] );
+		assertEquals( "Incorrect return dimensions", 2, ( ( Object[] ) results.get( 0 ) ).length );
+
+		session.close();
+
+		destroyTestBaseData();
+
+	}
+
+	public void testStandardFunctions() throws Exception {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+		Product p = new Product();
+		p.setDescription("a product");
+		p.setPrice( new BigDecimal(1.0) );
+		p.setProductId("abc123");
+		session.persist(p);
+		Object[] result = (Object[]) session
+			.createQuery("select current_time(), current_date(), current_timestamp() from Product")
+			.uniqueResult();
+		assertTrue( result[0] instanceof Time );
+		assertTrue( result[1] instanceof Date );
+		assertTrue( result[2] instanceof Timestamp );
+		assertNotNull( result[0] );
+		assertNotNull( result[1] );
+		assertNotNull( result[2] );
+		session.delete(p);
+		t.commit();
+		session.close();
+
+	}
+
+	public void testDynamicInstantiationQueries() throws Exception {
+
+		createTestBaseData();
+
+		Session session = openSession();
+
+		List results = session.createQuery( "select new Animal(an.description, an.bodyWeight) from Animal an" ).list();
+		assertEquals( "Incorrect result size", 2, results.size() );
+		assertClassAssignability( results.get( 0 ).getClass(), Animal.class );
+
+		Iterator iter = session.createQuery( "select new Animal(an.description, an.bodyWeight) from Animal an" ).iterate();
+		assertTrue( "Incorrect result size", iter.hasNext() );
+		assertTrue( "Incorrect return type", iter.next() instanceof Animal );
+
+		results = session.createQuery( "select new list(an.description, an.bodyWeight) from Animal an" ).list();
+		assertEquals( "Incorrect result size", 2, results.size() );
+		assertTrue( "Incorrect return type", results.get( 0 ) instanceof List );
+		assertEquals( "Incorrect return type", ( (List) results.get( 0 ) ).size(), 2 );
+
+		results = session.createQuery( "select new list(an.description, an.bodyWeight) from Animal an" ).list();
+		assertEquals( "Incorrect result size", 2, results.size() );
+		assertTrue( "Incorrect return type", results.get( 0 ) instanceof List );
+		assertEquals( "Incorrect return type", ( (List) results.get( 0 ) ).size(), 2 );
+
+		iter = session.createQuery( "select new list(an.description, an.bodyWeight) from Animal an" ).iterate();
+		assertTrue( "Incorrect result size", iter.hasNext() );
+		Object obj = iter.next();
+		assertTrue( "Incorrect return type", obj instanceof List );
+		assertEquals( "Incorrect return type", ( (List) obj ).size(), 2 );
+
+		iter = ((org.hibernate.classic.Session)session).iterate( "select new list(an.description, an.bodyWeight) from Animal an" );
+		assertTrue( "Incorrect result size", iter.hasNext() );
+		obj = iter.next();
+		assertTrue( "Incorrect return type", obj instanceof List );
+		assertEquals( "Incorrect return type", ( (List) obj ).size(), 2 );
+
+		results = session.createQuery( "select new map(an.description, an.bodyWeight) from Animal an" ).list();
+		assertEquals( "Incorrect result size", 2, results.size() );
+		assertTrue( "Incorrect return type", results.get( 0 ) instanceof Map );
+		assertEquals( "Incorrect return type", ( (Map) results.get( 0 ) ).size(), 2 );
+		assertTrue( ( (Map) results.get( 0 ) ).containsKey("0") );
+		assertTrue( ( (Map) results.get( 0 ) ).containsKey("1") );
+
+		results = session.createQuery( "select new map(an.description as descr, an.bodyWeight as bw) from Animal an" ).list();
+		assertEquals( "Incorrect result size", 2, results.size() );
+		assertTrue( "Incorrect return type", results.get( 0 ) instanceof Map );
+		assertEquals( "Incorrect return type", ( (Map) results.get( 0 ) ).size(), 2 );
+		assertTrue( ( (Map) results.get( 0 ) ).containsKey("descr") );
+		assertTrue( ( (Map) results.get( 0 ) ).containsKey("bw") );
+
+		iter = session.createQuery( "select new map(an.description, an.bodyWeight) from Animal an" ).iterate();
+		assertTrue( "Incorrect result size", iter.hasNext() );
+		obj = iter.next();
+		assertTrue( "Incorrect return type", obj instanceof Map );
+		assertEquals( "Incorrect return type", ( (Map) obj ).size(), 2 );
+
+		ScrollableResults sr = session.createQuery( "select new map(an.description, an.bodyWeight) from Animal an" ).scroll();
+		assertTrue( "Incorrect result size", sr.next() );
+		obj = sr.get(0);
+		assertTrue( "Incorrect return type", obj instanceof Map );
+		assertEquals( "Incorrect return type", ( (Map) obj ).size(), 2 );
+		sr.close();
+
+		sr = session.createQuery( "select new Animal(an.description, an.bodyWeight) from Animal an" ).scroll();
+		assertTrue( "Incorrect result size", sr.next() );
+		assertTrue( "Incorrect return type", sr.get(0) instanceof Animal );
+		sr.close();
+
+		// caching...
+		QueryStatistics stats = getSessions().getStatistics().getQueryStatistics( "select new Animal(an.description, an.bodyWeight) from Animal an" );
+		results = session.createQuery( "select new Animal(an.description, an.bodyWeight) from Animal an" )
+				.setCacheable( true )
+				.list();
+		assertEquals( "incorrect result size", 2, results.size() );
+		assertClassAssignability( Animal.class, results.get( 0 ).getClass() );
+		long initCacheHits = stats.getCacheHitCount();
+		results = session.createQuery( "select new Animal(an.description, an.bodyWeight) from Animal an" )
+				.setCacheable( true )
+				.list();
+		assertEquals( "dynamic intantiation query not served from cache", initCacheHits + 1, stats.getCacheHitCount() );
+		assertEquals( "incorrect result size", 2, results.size() );
+		assertClassAssignability( Animal.class, results.get( 0 ).getClass() );
+
+		session.close();
+
+		destroyTestBaseData();
+	}
+
+	public void testIllegalMixedTransformerQueries() {
+		Session session = openSession();
+
+		try {
+			getSelectNewQuery( session ).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
+			fail("'select new' together with a resulttransformer should result in error!");
+		} catch(QueryException he) {
+			assertTrue(he.getMessage().indexOf("ResultTransformer")==0);
+		}
+
+		try {
+			getSelectNewQuery( session ).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).iterate();
+			fail("'select new' together with a resulttransformer should result in error!");
+		} catch(HibernateException he) {
+			assertTrue(he.getMessage().indexOf("ResultTransformer")==0);
+		}
+
+		try {
+			getSelectNewQuery( session ).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).scroll();
+			fail("'select new' together with a resulttransformer should result in error!");
+		} catch(HibernateException he) {
+			assertTrue(he.getMessage().indexOf("ResultTransformer")==0);
+		}
+
+		session.close();
+	}
+
+	private Query getSelectNewQuery(Session session) {
+		return session.createQuery( "select new Animal(an.description, an.bodyWeight) from Animal an" );
+	}
+	public void testResultTransformerScalarQueries() throws Exception {
+
+		createTestBaseData();
+
+		String query = "select an.description as description, an.bodyWeight as bodyWeight from Animal an order by bodyWeight desc";
+
+		Session session = openSession();
+
+		List results = session.createQuery( query )
+		.setResultTransformer(Transformers.aliasToBean(Animal.class)).list();
+		assertEquals( "Incorrect result size", results.size(), 2 );
+		assertTrue( "Incorrect return type", results.get(0) instanceof Animal );
+		Animal firstAnimal = (Animal) results.get(0);
+		Animal secondAnimal = (Animal) results.get(1);
+		assertEquals("Mammal #1", firstAnimal.getDescription());
+		assertEquals("Mammal #2", secondAnimal.getDescription());
+		assertFalse(session.contains(firstAnimal));
+		session.close();
+
+		session = openSession();
+
+		Iterator iter = session.createQuery( query )
+	     .setResultTransformer(Transformers.aliasToBean(Animal.class)).iterate();
+		assertTrue( "Incorrect result size", iter.hasNext() );
+		assertTrue( "Incorrect return type", iter.next() instanceof Animal );
+
+		session.close();
+
+		session = openSession();
+
+		ScrollableResults sr = session.createQuery( query )
+	     .setResultTransformer(Transformers.aliasToBean(Animal.class)).scroll();
+		assertTrue( "Incorrect result size", sr.next() );
+		assertTrue( "Incorrect return type", sr.get(0) instanceof Animal );
+		assertFalse(session.contains(sr.get(0)));
+		sr.close();
+
+		session.close();
+
+		session = openSession();
+
+		results = session.createQuery( "select a from Animal a, Animal b order by a.id" )
+				.setResultTransformer(new DistinctRootEntityResultTransformer())
+				.list();
+		assertEquals( "Incorrect result size", 2, results.size());
+		assertTrue( "Incorrect return type", results.get(0) instanceof Animal );
+		firstAnimal = (Animal) results.get(0);
+		secondAnimal = (Animal) results.get(1);
+		assertEquals("Mammal #1", firstAnimal.getDescription());
+		assertEquals("Mammal #2", secondAnimal.getDescription());
+
+		session.close();
+
+		destroyTestBaseData();
+	}
+
+	public void testResultTransformerEntityQueries() throws Exception {
+
+		createTestBaseData();
+
+		String query = "select an as an from Animal an order by bodyWeight desc";
+
+		Session session = openSession();
+
+		List results = session.createQuery( query )
+		.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
+		assertEquals( "Incorrect result size", results.size(), 2 );
+		assertTrue( "Incorrect return type", results.get(0) instanceof Map );
+		Map map = ((Map) results.get(0));
+		assertEquals(1, map.size());
+		Animal firstAnimal = (Animal) map.get("an");
+		map = ((Map) results.get(1));
+		Animal secondAnimal = (Animal) map.get("an");
+		assertEquals("Mammal #1", firstAnimal.getDescription());
+		assertEquals("Mammal #2", secondAnimal.getDescription());
+		assertTrue(session.contains(firstAnimal));
+		assertSame(firstAnimal, session.get(Animal.class,firstAnimal.getId()));
+		session.close();
+
+		session = openSession();
+
+		Iterator iter = session.createQuery( query )
+	     .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).iterate();
+		assertTrue( "Incorrect result size", iter.hasNext() );
+		map = (Map) iter.next();
+		firstAnimal = (Animal) map.get("an");
+		assertEquals("Mammal #1", firstAnimal.getDescription());
+		assertTrue( "Incorrect result size", iter.hasNext() );
+
+		session.close();
+
+		session = openSession();
+
+		ScrollableResults sr = session.createQuery( query )
+	     .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).scroll();
+		assertTrue( "Incorrect result size", sr.next() );
+		assertTrue( "Incorrect return type", sr.get(0) instanceof Map );
+		assertFalse(session.contains(sr.get(0)));
+		sr.close();
+
+		session.close();
+
+		destroyTestBaseData();
+	}
+
+	public void testEJBQLFunctions() throws Exception {
+		Session session = openSession();
+
+		String hql = "from Animal a where a.description = concat('1', concat('2','3'), '4'||'5')||'0'";
+		session.createQuery(hql).list();
+
+		hql = "from Animal a where substring(a.description, 1, 3) = 'cat'";
+		session.createQuery(hql).list();
+
+		hql = "select substring(a.description, 1, 3) from Animal a";
+		session.createQuery(hql).list();
+
+		hql = "from Animal a where lower(a.description) = 'cat'";
+		session.createQuery(hql).list();
+
+		hql = "select lower(a.description) from Animal a";
+		session.createQuery(hql).list();
+
+		hql = "from Animal a where upper(a.description) = 'CAT'";
+		session.createQuery(hql).list();
+
+		hql = "select upper(a.description) from Animal a";
+		session.createQuery(hql).list();
+
+		hql = "from Animal a where length(a.description) = 5";
+		session.createQuery(hql).list();
+
+		hql = "select length(a.description) from Animal a";
+		session.createQuery(hql).list();
+
+		//note: postgres and db2 don't have a 3-arg form, it gets transformed to 2-args
+		hql = "from Animal a where locate('abc', a.description, 2) = 2";
+		session.createQuery(hql).list();
+
+		hql = "from Animal a where locate('abc', a.description) = 2";
+		session.createQuery(hql).list();
+
+		hql = "select locate('cat', a.description, 2) from Animal a";
+		session.createQuery(hql).list();
+
+		if ( !( getDialect() instanceof DB2Dialect ) ) {
+			hql = "from Animal a where trim(trailing '_' from a.description) = 'cat'";
+			session.createQuery(hql).list();
+
+			hql = "select trim(trailing '_' from a.description) from Animal a";
+			session.createQuery(hql).list();
+
+			hql = "from Animal a where trim(leading '_' from a.description) = 'cat'";
+			session.createQuery(hql).list();
+
+			hql = "from Animal a where trim(both from a.description) = 'cat'";
+			session.createQuery(hql).list();
+		}
+
+		if ( !(getDialect() instanceof HSQLDialect) ) { //HSQL doesn't like trim() without specification
+			hql = "from Animal a where trim(a.description) = 'cat'";
+			session.createQuery(hql).list();
+		}
+
+		hql = "from Animal a where abs(a.bodyWeight) = sqrt(a.bodyWeight)";
+		session.createQuery(hql).list();
+
+		hql = "from Animal a where mod(16, 4) = 4";
+		session.createQuery(hql).list();
+
+		hql = "from Animal a where bit_length(a.bodyWeight) = 24";
+		session.createQuery(hql).list();
+
+		hql = "select bit_length(a.bodyWeight) from Animal a";
+		session.createQuery(hql).list();
+
+		/*hql = "select object(a) from Animal a where CURRENT_DATE = :p1 or CURRENT_TIME = :p2 or CURRENT_TIMESTAMP = :p3";
+		session.createQuery(hql).list();*/
+
+		// todo the following is not supported
+		//hql = "select CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP from Animal a";
+		//parse(hql, true);
+		//System.out.println("sql: " + toSql(hql));
+
+		hql = "from Animal a where a.description like '%a%'";
+		session.createQuery(hql).list();
+
+		hql = "from Animal a where a.description not like '%a%'";
+		session.createQuery(hql).list();
+
+		hql = "from Animal a where a.description like 'x%ax%' escape 'x'";
+		session.createQuery(hql).list();
+
+		session.close();
+	}
+
+	public void testSubselectBetween() {
+		if ( supportsSubselectOnLeftSideIn() ) {
+			assertResultSize( "from Animal x where (select max(a.bodyWeight) from Animal a) in (1,2,3)", 0 );
+			assertResultSize( "from Animal x where (select max(a.bodyWeight) from Animal a) between 0 and 100", 0 );
+			assertResultSize( "from Animal x where (select max(a.description) from Animal a) like 'big%'", 0 );
+			assertResultSize( "from Animal x where (select max(a.bodyWeight) from Animal a) is not null", 0 );
+		}
+		assertResultSize( "from Animal x where exists (select max(a.bodyWeight) from Animal a)", 0 );
+	}
+
+	private void assertResultSize(String hql, int size) {
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+		assertEquals( size, session.createQuery(hql).list().size() );
+		txn.commit();
+		session.close();
+	}
+
+	private interface QueryPreparer {
+		public void prepare(Query query);
+	}
+
+	private static final QueryPreparer DEFAULT_PREPARER = new QueryPreparer() {
+		public void prepare(Query query) {
+		}
+	};
+
+	private class SyntaxChecker {
+		private final String hql;
+		private final QueryPreparer preparer;
+
+		public SyntaxChecker(String hql) {
+			this( hql, DEFAULT_PREPARER );
+		}
+
+		public SyntaxChecker(String hql, QueryPreparer preparer) {
+			this.hql = hql;
+			this.preparer = preparer;
+		}
+
+		public void checkAll() {
+			checkList();
+			checkIterate();
+			checkScroll();
+		}
+
+		public SyntaxChecker checkList() {
+			Session s = openSession();
+			s.beginTransaction();
+			Query query = s.createQuery( hql );
+			preparer.prepare( query );
+			query.list();
+			s.getTransaction().commit();
+			s.close();
+			return this;
+		}
+
+		public SyntaxChecker checkScroll() {
+			Session s = openSession();
+			s.beginTransaction();
+			Query query = s.createQuery( hql );
+			preparer.prepare( query );
+			query.scroll();
+			s.getTransaction().commit();
+			s.close();
+			return this;
+		}
+
+		public SyntaxChecker checkIterate() {
+			Session s = openSession();
+			s.beginTransaction();
+			Query query = s.createQuery( hql );
+			preparer.prepare( query );
+			query.iterate();
+			s.getTransaction().commit();
+			s.close();
+			return this;
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ASTQueryTranslatorTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ASTQueryTranslatorTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ASTQueryTranslatorTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,176 @@
+// $Id: ASTQueryTranslatorTest.java 8889 2005-12-20 17:35:54Z steveebersole $
+package org.hibernate.test.hql;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Tests cases where the AST based QueryTranslator does not generate identical SQL.
+ *
+ * @author josh Dec 6, 2004 9:07:58 AM
+ */
+public class ASTQueryTranslatorTest extends QueryTranslatorTestCase {
+
+	public ASTQueryTranslatorTest(String x) {
+		super( x );
+	}
+
+	public static Test suite() {
+		return new TestSuite( ASTQueryTranslatorTest.class );
+	}
+
+	protected boolean dropAfterFailure() {
+		return false;
+	}
+
+	// ##### TESTS THAT DON'T PASS BECAUSE THEY GENERATE DIFFERENT, POSSIBLY VALID SQL #####
+
+	public void testSelectManyToOne() {
+		assertTranslation("select distinct a.zoo from Animal a where a.zoo is not null");
+		assertTranslation("select a.zoo from Animal a");
+	}
+
+	public void testSelectExpression() {
+		//old qt cant handle select-clause expressions
+		assertTranslation("select a.bodyWeight + m.bodyWeight from Animal a join a.mother m");
+	}
+	
+	public void testFetchProperties() {
+		//not implemented in old qt
+		assertTranslation("from Animal a fetch all properties join a.offspring o fetch all properties");
+	}
+	
+	public void testOldSyntax() {
+		//generates ANSI join instead of theta join
+		assertTranslation("from a in class Animal, o in elements(a.offspring), h in class Human");
+	}
+	
+	public void testImplicitJoinInsideOutsideSubselect() {
+		// new qt re-uses the joins defined by 's.other.count' path when referenced in the subquery,
+		// whereas the old qt reuses only the "root table" (not the already defined join to 'other'):
+		//   OLD SQL :
+		//      select  simple0_.id_ as col_0_0_
+		//      from    Simple simple0_,
+		//              Simple simple1_
+		//      where   (simple1_.count_>0
+		//      and     simple0_.other=simple1_.id_)
+		//      and     (simple0_.id_=some(
+		//                  select  simple2_.id_
+		//                  from    Simple simple2_,
+		//                          Simple simple3_,
+		//                          Simple simple4_
+		//                  where   (simple3_.count_=simple4_.count_
+		//                  and     simple2_.other=simple3_.id_
+		//                  and     simple0_.other=simple4_.id_)
+		//              ))
+		//   NEW SQL :
+		//      select  simple0_.id_ as col_0_0_
+		//      from    Simple simple0_,
+		//              Simple simple1_
+		//      where   (simple1_.count_>0
+		//      and     simple0_.id_=some(
+		//                  select  simple2_.id_
+		//                  from    Simple simple2_,
+		//                          Simple simple3_
+		//                  where   (simple3_.count_=simple1_.count_
+		//                  and     simple2_.other=simple3_.id_)
+		//            )
+		//        and simple0_.other=simple1_.id_)
+		assertTranslation( "from Simple s where s = some( from Simple sim where sim.other.count=s.other.count ) and s.other.count > 0" );
+		assertTranslation( "from Simple s where s.other.count > 0 and s = some( from Simple sim where sim.other.count=s.other.count )" );
+	}
+
+	public void testNakedPropertyRef() {
+		// this is needed for ejb3 selects and bulk statements
+		//      Note: these all fail because the old parser did not have this
+		//      feature, it just "passes the tokens through" to the SQL.
+		assertTranslation( "from Animal where bodyWeight = bodyWeight" );
+		assertTranslation( "select bodyWeight from Animal" );
+		assertTranslation( "select max(bodyWeight) from Animal" );
+	}
+
+	public void testNakedComponentPropertyRef() {
+		// this is needed for ejb3 selects and bulk statements
+		//      Note: these all fail because the old parser did not have this
+		//      feature, it just "passes the tokens through" to the SQL.
+		assertTranslation( "from Human where name.first = 'Gavin'" );
+		assertTranslation( "select name from Human" );
+		assertTranslation( "select upper(h.name.first) from Human as h" );
+		assertTranslation( "select upper(name.first) from Human" );
+	}
+
+	public void testNakedMapIndex() throws Exception {
+		assertTranslation( "from Zoo where mammals['dog'].description like '%black%'" );
+	}
+
+	public void testNakedImplicitJoins() {
+		assertTranslation( "from Animal where mother.father = ?" );
+	}
+
+	public void testDuplicateImplicitJoinInWhere() {
+		//new qt has more organized joins
+		assertTranslation("from Human h where h.mother.bodyWeight>10 and h.mother.bodyWeight<10");
+	}
+	
+	public void testWhereExpressions() {
+		assertTranslation("from User u where u.userName='gavin' and u.human.name.first='Gavin'");
+		//new qt has more organized joins
+		assertTranslation("from User u where u.human.name.last='King' and u.human.name.first='Gavin'");
+		assertTranslation("from Bar bar where bar.baz.name='josh'");
+		assertTranslation("from Bar bar where bar.baz.name='josh' and not bar.baz.name='gavin'");
+	}
+	
+	public void testImplicitJoinInSelect() {
+		//slightly diff select clause, both correct
+		assertTranslation("select foo.long, foo.foo from Foo foo");
+	}
+	
+	public void testSelectStandardFunctions() throws Exception {
+		//old parser throws an exception
+		assertTranslation( "select current_date(), current_time(), current_timestamp() from Animal" );
+	}
+
+	public void testSelectClauseImplicitJoin() throws Exception {
+		//the old query translator has a bug which results in the wrong return type!
+		assertTranslation( "select d.owner.mother from Dog d" );
+	}
+
+	public void testComplexWhereExpression() throws Exception {
+		// classic QT generates lots of extra parens and some extra theta joins.
+		assertTranslation( "select distinct s from Simple s\n" +
+				"where ( ( s.other.count + 3 ) = (15*2)/2 and s.count = 69) or ( ( s.other.count + 2 ) / 7 ) = 2" );
+	}
+
+	public void testDuplicateImplicitJoin() throws Exception {
+		// old qt generates an extra theta join
+		assertTranslation( "from Animal an where an.mother.bodyWeight > 10 and an.mother.bodyWeight < 20" );
+	}
+
+	public void testKeywordClassNameAndAlias() throws Exception {
+		// The old QT throws an exception, the new one doesn't, which is better
+		assertTranslation( "from Order order" );
+	}
+
+	public void testComponent3() throws Exception {
+		// The old translator generates duplicate inner joins *and* duplicate theta join clauses in the where statement in this case.
+		assertTranslation( "from Dog dog where dog.owner.name.first = 'Gavin' and dog.owner.name.last='King' and dog.owner.bodyWeight<70" );
+	}
+
+	public void testUncorrelatedSubselectWithJoin() throws Exception {
+		// The old translator generates unnecessary inner joins for the Animal subclass of zoo.mammals
+		// The new one is working fine now!
+		assertTranslation( "from Animal a where a in (select mam from Zoo zoo join zoo.mammals mam)" );
+	}
+
+	public void testFetch() throws Exception {
+		//SQL is correct, new qt is not throwing an exception when it should be (minor issue)
+		assertTranslation("from Customer cust left join fetch cust.billingAddress where cust.customerId='abc123'");
+	}
+
+	public void testImplicitJoin() throws Exception {
+		//old qt generates an exception, the new one doesnt 
+		//this is actually invalid HQL, an implicit join on a many-valued association
+		assertTranslation( "from Animal an where an.offspring.mother.bodyWeight > 10" );
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+// $Id: Address.java 7996 2005-08-22 14:49:57Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * Implementation of Address.
+ *
+ * @author Steve Ebersole
+ */
+public class Address {
+	private String street;
+	private String city;
+	private String postalCode;
+	private String country;
+	private StateProvince stateProvince;
+
+	public String getStreet() {
+		return street;
+	}
+
+	public void setStreet(String street) {
+		this.street = street;
+	}
+
+	public String getCity() {
+		return city;
+	}
+
+	public void setCity(String city) {
+		this.city = city;
+	}
+
+	public String getPostalCode() {
+		return postalCode;
+	}
+
+	public void setPostalCode(String postalCode) {
+		this.postalCode = postalCode;
+	}
+
+	public String getCountry() {
+		return country;
+	}
+
+	public void setCountry(String country) {
+		this.country = country;
+	}
+
+	public StateProvince getStateProvince() {
+		return stateProvince;
+	}
+
+	public void setStateProvince(StateProvince stateProvince) {
+		this.stateProvince = stateProvince;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Animal.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Animal.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Animal.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,150 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+<hibernate-mapping
+	package="org.hibernate.test.hql"
+	default-access="field">
+
+	<class name="Animal">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="description"/>
+		<property name="bodyWeight" column="body_weight"/>
+		<many-to-one name="mother" column="mother_id"/>
+		<many-to-one name="father" column="father_id"/>
+		<many-to-one name="zoo" column="zoo_id"/>
+		<property name="serialNumber"/>
+		<set name="offspring" order-by="father_id">
+			<key column="mother_id"/>
+			<one-to-many class="Animal"/>
+		</set>
+		<joined-subclass name="Reptile">
+			<key column="animal"/>
+			<property name="bodyTemperature"/>
+			<joined-subclass name="Lizard">
+				<key column="reptile"/>
+			</joined-subclass>
+		</joined-subclass>
+		<joined-subclass name="Mammal">
+			<key column="animal"/>
+			<property name="pregnant"/>
+			<property name="birthdate" type="date"/>
+			<joined-subclass name="DomesticAnimal">
+				<key column="mammal"/>
+				<many-to-one name="owner"/>
+				<joined-subclass name="Cat">
+					<key column="mammal"/>
+				</joined-subclass>
+				<joined-subclass name="Dog">
+					<key column="mammal"/>
+				</joined-subclass>
+			</joined-subclass>
+			<joined-subclass name="Human">
+				<key column="mammal"/>
+				<component name="name">
+					<property name="first" column="name_first"/>
+					<property name="initial" column="name_initial"/>
+					<property name="last" column="name_last"/>
+				</component>
+				<property name="nickName"/>
+				<property name="height"/>
+
+				<property name="intValue"/>
+				<property name="floatValue"/>
+				<property name="bigDecimalValue"/>
+				<property name="bigIntegerValue"/>
+
+				<bag name="friends">
+					<key column="human1"/>
+					<many-to-many column="human2" class="Human"/>
+				</bag>
+				<map name="family">
+					<key column="human1"/>
+					<map-key column="relationship" type="string"/>
+					<many-to-many column="human2" class="Human"/>
+				</map>
+				<bag name="pets" inverse="true">
+					<key column="owner"/>
+					<one-to-many class="DomesticAnimal"/>
+				</bag>
+				<set name="nickNames" lazy="false" table="human_nick_names" sort="natural">
+					<key column="human"/>
+					<element column="nick_name" type="string" not-null="true"/>
+				</set>
+				<map name="addresses" table="addresses">
+					<key column="human"/>
+					<map-key type="string" column="type"/>
+					<composite-element class="Address">
+						<property name="street"/>
+						<property name="city"/>
+						<property name="postalCode"/>
+						<property name="country"/>
+                        <many-to-one name="stateProvince" column="state_prov_id" class="StateProvince"/>
+					</composite-element>
+				</map>
+			</joined-subclass>
+		</joined-subclass>
+	</class>
+
+	<class name="User" table="`User`">
+		<id name="id">
+			<generator class="foreign">
+				<param name="property">human</param>
+			</generator>
+		</id>
+		<property name="userName"/>
+		<one-to-one name="human" constrained="true"/>
+		<list name="permissions">
+			<key column="userId"/>
+			<list-index column="permissionId"/>
+			<element type="string" column="permissionName"/>
+		</list>
+	</class>
+
+	<class name="Zoo" discriminator-value="Z">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<discriminator column="zooType" type="character"/>
+		<property name="name" type="string"/>
+        <property name="classification" type="org.hibernate.test.hql.ClassificationType"/>
+        <map name="mammals">
+			<key column="mammalZoo_id"/>
+			<index type="string" column="name"/>
+			<one-to-many class="Mammal"/>
+		</map>
+		<map name="animals" inverse="true">
+			<key column="zoo_id"/>
+			<index type="string" column="serialNumber"/>
+			<one-to-many class="Animal"/>
+		</map>
+        <component name="address" class="Address">
+            <property name="street"/>
+            <property name="city"/>
+            <property name="postalCode"/>
+            <property name="country"/>
+            <many-to-one name="stateProvince" column="state_prov_id" class="StateProvince"/>
+        </component>
+		<subclass name="PettingZoo" discriminator-value="P"/>
+	</class>
+
+    <class name="StateProvince">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+        <property name="isoCode"/>
+    </class>
+
+	<class name="Joiner">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="name"/>
+		<join table="JOINED">
+			<key column="ID"/>
+			<property name="joinedName"/>
+		</join>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Animal.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Animal.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Animal.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,99 @@
+//$Id: Animal.java 7445 2005-07-10 16:51:17Z oneovthafew $
+package org.hibernate.test.hql;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * @author Gavin King
+ */
+public class Animal {
+	private Long id;
+	private float bodyWeight;
+	private Set offspring;
+	private Animal mother;
+	private Animal father;
+	private String description;
+	private Zoo zoo;
+	private String serialNumber;
+
+	public Animal() {
+	}
+
+	public Animal(String description, float bodyWeight) {
+		this.description = description;
+		this.bodyWeight = bodyWeight;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public float getBodyWeight() {
+		return bodyWeight;
+	}
+
+	public void setBodyWeight(float bodyWeight) {
+		this.bodyWeight = bodyWeight;
+	}
+
+	public Set getOffspring() {
+		return offspring;
+	}
+
+	public void addOffspring(Animal offspring) {
+		if ( this.offspring == null ) {
+			this.offspring = new HashSet();
+		}
+
+		this.offspring.add( offspring );
+	}
+
+	public void setOffspring(Set offspring) {
+		this.offspring = offspring;
+	}
+
+	public Animal getMother() {
+		return mother;
+	}
+
+	public void setMother(Animal mother) {
+		this.mother = mother;
+	}
+
+	public Animal getFather() {
+		return father;
+	}
+
+	public void setFather(Animal father) {
+		this.father = father;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public Zoo getZoo() {
+		return zoo;
+	}
+
+	public void setZoo(Zoo zoo) {
+		this.zoo = zoo;
+	}
+
+	public String getSerialNumber() {
+		return serialNumber;
+	}
+
+	public void setSerialNumber(String serialNumber) {
+		this.serialNumber = serialNumber;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.hql" default-access="field">
+
+	<class name="BooleanLiteralEntity">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+        <property name="yesNoBoolean" column="Y_N_BOOL" type="yes_no"/>
+        <property name="trueFalseBoolean" column="T_F_BOOL" type="true_false"/>
+        <property name="zeroOneBoolean" column="NUM_BOOL" type="boolean"/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/BooleanLiteralEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/BooleanLiteralEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/BooleanLiteralEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+package org.hibernate.test.hql;
+
+/**
+ * todo: describe BooleanLiteralEntity
+ *
+ * @author Steve Ebersole
+ */
+public class BooleanLiteralEntity {
+	private Long id;
+	private boolean yesNoBoolean;
+	private boolean trueFalseBoolean;
+	private boolean zeroOneBoolean;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public boolean isYesNoBoolean() {
+		return yesNoBoolean;
+	}
+
+	public void setYesNoBoolean(boolean yesNoBoolean) {
+		this.yesNoBoolean = yesNoBoolean;
+	}
+
+	public boolean isTrueFalseBoolean() {
+		return trueFalseBoolean;
+	}
+
+	public void setTrueFalseBoolean(boolean trueFalseBoolean) {
+		this.trueFalseBoolean = trueFalseBoolean;
+	}
+
+	public boolean isZeroOneBoolean() {
+		return zeroOneBoolean;
+	}
+
+	public void setZeroOneBoolean(boolean zeroOneBoolean) {
+		this.zeroOneBoolean = zeroOneBoolean;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1211 @@
+// $Id: BulkManipulationTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.hql;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.QueryException;
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.hql.ast.HqlSqlWalker;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.persister.entity.EntityPersister;
+
+
+/**
+ * Tests execution of bulk UPDATE/DELETE statements through the new AST parser.
+ *
+ * @author Steve Ebersole
+ */
+public class BulkManipulationTest extends FunctionalTestCase {
+
+	public BulkManipulationTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( BulkManipulationTest.class );
+	}
+
+	public String[] getMappings() {
+		return new String[] {
+				"hql/Animal.hbm.xml",
+		        "hql/Vehicle.hbm.xml",
+		        "hql/KeyManyToOneEntity.hbm.xml",
+		        "hql/Versions.hbm.xml",
+				"hql/FooBarCopy.hbm.xml",
+				"legacy/Multi.hbm.xml",
+				"hql/EntityWithCrazyCompositeKey.hbm.xml",
+				"hql/SimpleEntityWithAssociation.hbm.xml",
+				"hql/BooleanLiteralEntity.hbm.xml"
+		};
+	}
+
+
+	// Non-exists ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void testDeleteNonExistentEntity() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		try {
+			s.createQuery( "delete NonExistentEntity" ).executeUpdate();
+			fail( "no exception thrown" );
+		}
+		catch( QueryException e ) {
+			System.out.println( "Caught expected error type : " + e.getMessage() );
+		}
+
+		t.commit();
+		s.close();
+	}
+
+	public void testUpdateNonExistentEntity() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		try {
+			s.createQuery( "update NonExistentEntity e set e.someProp = ?" ).executeUpdate();
+			fail( "no exception thrown" );
+		}
+		catch( QueryException e ) {
+			System.out.println( "Caught expected error type : " + e.getMessage() );
+		}
+
+		t.commit();
+		s.close();
+	}
+
+	public void testTempTableGenerationIsolation() throws Throwable{
+		Session s = openSession();
+		s.beginTransaction();
+
+		Truck truck = new Truck();
+		truck.setVin( "123t" );
+		truck.setOwner( "Steve" );
+		s.save( truck );
+
+		// manually flush the session to ensure the insert happens
+		s.flush();
+
+		// now issue a bulk delete against Car which should force the temp table to be
+		// created.  we need to test to ensure that this does not cause the transaction
+		// to be committed...
+		s.createQuery( "delete from Vehicle" ).executeUpdate();
+
+		s.getTransaction().rollback();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		List list = s.createQuery( "from Car" ).list();
+		assertEquals( "temp table gen caused premature commit", 0, list.size() );
+		s.createQuery( "delete from Car" ).executeUpdate();
+		s.getTransaction().rollback();
+		s.close();
+	}
+
+
+	// BOOLEAN HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void testBooleanHandling() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		// currently, we need the three different binds because they are different underlying types...
+		int count = s.createQuery( "update BooleanLiteralEntity set yesNoBoolean = :b1, trueFalseBoolean = :b2, zeroOneBoolean = :b3" )
+				.setBoolean( "b1", true )
+				.setBoolean( "b2", true )
+				.setBoolean( "b3", true )
+				.executeUpdate();
+		assertEquals( 1, count );
+		BooleanLiteralEntity entity = ( BooleanLiteralEntity ) s.createQuery( "from BooleanLiteralEntity" ).uniqueResult();
+		assertTrue( entity.isYesNoBoolean() );
+		assertTrue( entity.isTrueFalseBoolean() );
+		assertTrue( entity.isZeroOneBoolean() );
+		s.clear();
+
+		count = s.createQuery( "update BooleanLiteralEntity set yesNoBoolean = true, trueFalseBoolean = true, zeroOneBoolean = true" )
+				.executeUpdate();
+		assertEquals( 1, count );
+		entity = ( BooleanLiteralEntity ) s.createQuery( "from BooleanLiteralEntity" ).uniqueResult();
+		assertTrue( entity.isYesNoBoolean() );
+		assertTrue( entity.isTrueFalseBoolean() );
+		assertTrue( entity.isZeroOneBoolean() );
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+
+	// INSERTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void testSimpleInsert() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		s.createQuery( "insert into Pickup (id, vin, owner) select id, vin, owner from Car" ).executeUpdate();
+		
+		t.commit();
+		t = s.beginTransaction();
+
+		s.createQuery( "delete Vehicle" ).executeUpdate();
+		
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testSimpleNativeSQLInsert() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		List l = s.createQuery("from Vehicle").list();
+		assertEquals(l.size(),4);
+
+		s.createSQLQuery( "insert into PICKUP (id, vin, owner) select id, vin, owner from Car" ).executeUpdate();
+
+		l = s.createQuery("from Vehicle").list();
+		assertEquals(l.size(),5);
+
+		t.commit();
+		t = s.beginTransaction();
+
+		s.createSQLQuery( "delete from TRUCK" ).executeUpdate();
+
+		l = s.createQuery("from Vehicle").list();
+		assertEquals(l.size(),4);
+
+		Car c = (Car) s.createQuery( "from Car where owner = 'Kirsten'" ).uniqueResult();
+		c.setOwner("NotKirsten");
+		assertEquals(0,s.getNamedQuery( "native-delete-car" ).setString( 0, "Kirsten" ).executeUpdate());
+		assertEquals(1,s.getNamedQuery( "native-delete-car" ).setString( 0, "NotKirsten" ).executeUpdate());
+		
+		
+		assertEquals(0,s.createSQLQuery( "delete from SUV where owner = :owner" ).setString( "owner", "NotThere" ).executeUpdate());
+		assertEquals(1,s.createSQLQuery( "delete from SUV where owner = :owner" ).setString( "owner", "Joe" ).executeUpdate());
+		s.createSQLQuery( "delete from PICKUP" ).executeUpdate();
+
+		l = s.createQuery("from Vehicle").list();
+		assertEquals(l.size(),0);
+
+
+		t.commit();
+		s.close();
+
+
+		data.cleanup();
+	}
+	
+	public void testInsertWithManyToOne() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		s.createQuery( "insert into Animal (description, bodyWeight, mother) select description, bodyWeight, mother from Human" ).executeUpdate();
+
+		t.commit();
+		t = s.beginTransaction();
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testInsertWithMismatchedTypes() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		try {
+			s.createQuery( "insert into Pickup (owner, vin, id) select id, vin, owner from Car" ).executeUpdate();
+			fail( "mismatched types did not error" );
+		}
+		catch( QueryException e ) {
+			// expected result
+		}
+
+		t.commit();
+		t = s.beginTransaction();
+
+		s.createQuery( "delete Vehicle" ).executeUpdate();
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testInsertIntoSuperclassPropertiesFails() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		try {
+			s.createQuery( "insert into Human (id, bodyWeight) select id, bodyWeight from Lizard" ).executeUpdate();
+			fail( "superclass prop insertion did not error" );
+		}
+		catch( QueryException e ) {
+			// expected result
+		}
+
+		t.commit();
+		t = s.beginTransaction();
+
+		s.createQuery( "delete Animal where mother is not null" ).executeUpdate();
+		s.createQuery( "delete Animal where father is not null" ).executeUpdate();
+		s.createQuery( "delete Animal" ).executeUpdate();
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testInsertAcrossMappedJoinFails() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		try {
+			s.createQuery( "insert into Joiner (name, joinedName) select vin, owner from Car" ).executeUpdate();
+			fail( "mapped-join insertion did not error" );
+		}
+		catch( QueryException e ) {
+			// expected result
+		}
+
+		t.commit();
+		t = s.beginTransaction();
+
+		s.createQuery( "delete Joiner" ).executeUpdate();
+		s.createQuery( "delete Vehicle" ).executeUpdate();
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testInsertWithGeneratedId() {
+		// Make sure the env supports bulk inserts with generated ids...
+		EntityPersister persister = sfi().getEntityPersister( PettingZoo.class.getName() );
+		IdentifierGenerator generator = persister.getIdentifierGenerator();
+		if ( !HqlSqlWalker.supportsIdGenWithBulkInsertion( generator ) ) {
+			return;
+		}
+
+		// create a Zoo
+		Zoo zoo = new Zoo();
+		zoo.setName( "zoo" );
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.save( zoo );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		int count = s.createQuery( "insert into PettingZoo (name) select name from Zoo" ).executeUpdate();
+		t.commit();
+		s.close();
+
+		assertEquals( "unexpected insertion count", 1, count );
+
+		s = openSession();
+		t = s.beginTransaction();
+		PettingZoo pz = ( PettingZoo ) s.createQuery( "from PettingZoo" ).uniqueResult();
+		t.commit();
+		s.close();
+
+		assertEquals( zoo.getName(), pz.getName() );
+		assertTrue( zoo.getId() != pz.getId() );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery( "delete Zoo" ).executeUpdate();
+		t.commit();
+		s.close();
+	}
+
+	public void testInsertWithGeneratedVersionAndId() {
+		// Make sure the env supports bulk inserts with generated ids...
+		EntityPersister persister = sfi().getEntityPersister( IntegerVersioned.class.getName() );
+		IdentifierGenerator generator = persister.getIdentifierGenerator();
+		if ( !HqlSqlWalker.supportsIdGenWithBulkInsertion( generator ) ) {
+			return;
+		}
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		IntegerVersioned entity = new IntegerVersioned( "int-vers" );
+		s.save( entity );
+		s.createQuery( "select id, name, version from IntegerVersioned" ).list();
+		t.commit();
+		s.close();
+
+		Long initialId = entity.getId();
+		int initialVersion = entity.getVersion();
+
+		s = openSession();
+		t = s.beginTransaction();
+		int count = s.createQuery( "insert into IntegerVersioned ( name ) select name from IntegerVersioned" ).executeUpdate();
+		t.commit();
+		s.close();
+
+		assertEquals( "unexpected insertion count", 1, count );
+
+		s = openSession();
+		t = s.beginTransaction();
+		IntegerVersioned created = ( IntegerVersioned ) s.createQuery( "from IntegerVersioned where id <> :initialId" )
+				.setLong( "initialId", initialId.longValue() )
+				.uniqueResult();
+		t.commit();
+		s.close();
+
+		assertEquals( "version was not seeded", initialVersion, created.getVersion() );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery( "delete IntegerVersioned" ).executeUpdate();
+		t.commit();
+		s.close();
+	}
+
+	public void testInsertWithGeneratedTimestampVersion() {
+		// Make sure the env supports bulk inserts with generated ids...
+		EntityPersister persister = sfi().getEntityPersister( TimestampVersioned.class.getName() );
+		IdentifierGenerator generator = persister.getIdentifierGenerator();
+		if ( !HqlSqlWalker.supportsIdGenWithBulkInsertion( generator ) ) {
+			return;
+		}
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		TimestampVersioned entity = new TimestampVersioned( "int-vers" );
+		s.save( entity );
+		s.createQuery( "select id, name, version from TimestampVersioned" ).list();
+		t.commit();
+		s.close();
+
+		Long initialId = entity.getId();
+		//Date initialVersion = entity.getVersion();
+
+		s = openSession();
+		t = s.beginTransaction();
+		int count = s.createQuery( "insert into TimestampVersioned ( name ) select name from TimestampVersioned" ).executeUpdate();
+		t.commit();
+		s.close();
+
+		assertEquals( "unexpected insertion count", 1, count );
+
+		s = openSession();
+		t = s.beginTransaction();
+		TimestampVersioned created = ( TimestampVersioned ) s.createQuery( "from TimestampVersioned where id <> :initialId" )
+				.setLong( "initialId", initialId.longValue() )
+				.uniqueResult();
+		t.commit();
+		s.close();
+
+		assertNotNull( created.getVersion() );
+		//assertEquals( "version was not seeded", initialVersion, created.getVersion() );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery( "delete TimestampVersioned" ).executeUpdate();
+		t.commit();
+		s.close();
+	}
+
+	// UPDATES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void testIncorrectSyntax() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		try {
+			s.createQuery( "update Human set Human.description = 'xyz' where Human.id = 1 and Human.description is null" );
+			fail( "expected failure" );
+		}
+		catch( QueryException expected ) {
+			// ignore : expected behavior
+		}
+		t.commit();
+		s.close();
+	}
+
+	public void testUpdateWithWhereExistsSubquery() {
+		// multi-table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Human joe = new Human();
+		joe.setName( new Name( "Joe", 'Q', "Public" ) );
+		s.save( joe );
+		Human doll = new Human();
+		doll.setName( new Name( "Kyu", 'P', "Doll" ) );
+		doll.setFriends( new ArrayList() );
+		doll.getFriends().add( joe );
+		s.save( doll );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		String updateQryString = "update Human h " +
+		                         "set h.description = 'updated' " +
+		                         "where exists (" +
+		                         "      select f.id " +
+		                         "      from h.friends f " +
+		                         "      where f.name.last = 'Public' " +
+		                         ")";
+		int count = s.createQuery( updateQryString ).executeUpdate();
+		assertEquals( 1, count );
+		s.delete( doll );
+		s.delete( joe );
+		t.commit();
+		s.close();
+
+		// single-table (one-to-many & many-to-many) ~~~~~~~~~~~~~~~~~~~~~~~~~~
+		s = openSession();
+		t = s.beginTransaction();
+		SimpleEntityWithAssociation entity = new SimpleEntityWithAssociation();
+		SimpleEntityWithAssociation other = new SimpleEntityWithAssociation();
+		entity.setName( "main" );
+		other.setName( "many-to-many-association" );
+		entity.getManyToManyAssociatedEntities().add( other );
+		entity.addAssociation( "one-to-many-association" );
+		s.save( entity );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		// one-to-many test
+		updateQryString = "update SimpleEntityWithAssociation e " +
+		                         "set e.name = 'updated' " +
+		                         "where exists (" +
+		                         "      select a.id " +
+		                         "      from e.associatedEntities a " +
+		                         "      where a.name = 'one-to-many-association' " +
+		                         ")";
+		count = s.createQuery( updateQryString ).executeUpdate();
+		assertEquals( 1, count );
+		// many-to-many test
+		if ( supportsSubqueryOnMutatingTable() ) {
+			updateQryString = "update SimpleEntityWithAssociation e " +
+									 "set e.name = 'updated' " +
+									 "where exists (" +
+									 "      select a.id " +
+									 "      from e.manyToManyAssociatedEntities a " +
+									 "      where a.name = 'many-to-many-association' " +
+									 ")";
+			count = s.createQuery( updateQryString ).executeUpdate();
+			assertEquals( 1, count );
+		}
+		s.delete( entity.getManyToManyAssociatedEntities().iterator().next() );
+		s.delete( entity );
+		t.commit();
+		s.close();
+	}
+
+	public void testIncrementCounterVersion() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		IntegerVersioned entity = new IntegerVersioned( "int-vers" );
+		s.save( entity );
+		t.commit();
+		s.close();
+
+		int initialVersion = entity.getVersion();
+
+		s = openSession();
+		t = s.beginTransaction();
+		int count = s.createQuery( "update versioned IntegerVersioned set name = name" ).executeUpdate();
+		assertEquals( "incorrect exec count", 1, count );
+		t.commit();
+
+		t = s.beginTransaction();
+		entity = ( IntegerVersioned ) s.load( IntegerVersioned.class, entity.getId() );
+		assertEquals( "version not incremented", initialVersion + 1, entity.getVersion() );
+
+		s.delete( entity );
+		t.commit();
+		s.close();
+	}
+
+	public void testIncrementTimestampVersion() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		TimestampVersioned entity = new TimestampVersioned( "ts-vers" );
+		s.save( entity );
+		t.commit();
+		s.close();
+
+		Date initialVersion = entity.getVersion();
+
+		synchronized (this) {
+			try {
+				wait(1500);
+			}
+			catch (InterruptedException ie) {}
+		}
+
+		s = openSession();
+		t = s.beginTransaction();
+		int count = s.createQuery( "update versioned TimestampVersioned set name = name" ).executeUpdate();
+		assertEquals( "incorrect exec count", 1, count );
+		t.commit();
+
+		t = s.beginTransaction();
+		entity = ( TimestampVersioned ) s.load( TimestampVersioned.class, entity.getId() );
+		assertTrue( "version not incremented", entity.getVersion().after( initialVersion ) );
+
+		s.delete( entity );
+		t.commit();
+		s.close();
+	}
+
+	public void testUpdateOnComponent() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Human human = new Human();
+		human.setName( new Name() );
+		human.getName().setFirst("Stevee");
+		human.getName().setInitial('X');
+		human.getName().setLast("Ebersole");
+
+		s.save( human );
+		s.flush();
+
+		t.commit();
+
+		String correctName = "Steve";
+
+		t = s.beginTransaction();
+
+		int count = s.createQuery( "update Human set name.first = :correction where id = :id" )
+				.setString( "correction", correctName )
+				.setLong( "id", human.getId().longValue() )
+				.executeUpdate();
+
+		assertEquals( "Incorrect update count", 1, count );
+
+		t.commit();
+
+		t = s.beginTransaction();
+
+		s.refresh( human );
+
+		assertEquals( "Update did not execute properly", correctName, human.getName().getFirst() );
+
+		s.createQuery( "delete Human" ).executeUpdate();
+		t.commit();
+
+		s.close();
+	}
+
+	public void testUpdateOnManyToOne() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		s.createQuery( "update Animal a set a.mother = null where a.id = 2" ).executeUpdate();
+		if ( ! ( getDialect() instanceof MySQLDialect ) ) {
+			// MySQL does not support (even un-correlated) subqueries against the update-mutating table
+			s.createQuery( "update Animal a set a.mother = (from Animal where id = 1) where a.id = 2" ).executeUpdate();
+		}
+
+		t.commit();
+		s.close();
+	}
+
+	public void testUpdateOnImplicitJoinFails() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Human human = new Human();
+		human.setName( new Name() );
+		human.getName().setFirst( "Steve" );
+		human.getName().setInitial('E');
+
+		Human mother = new Human();
+		mother.setName( new Name() );
+		mother.getName().setFirst( "Jane" );
+		mother.getName().setInitial('E');
+		human.setMother( mother );
+
+		s.save( human );
+		s.save( mother );
+		s.flush();
+
+		t.commit();
+
+		t = s.beginTransaction();
+		try {
+			s.createQuery( "update Human set mother.name.initial = :initial" ).setString( "initial", "F" ).executeUpdate();
+			fail( "update allowed across implicit join" );
+		}
+		catch( QueryException e ) {
+			System.out.println( "TEST (OK) : " + e.getMessage() );
+			// expected condition
+		}
+
+		s.createQuery( "delete Human where mother is not null" ).executeUpdate();
+		s.createQuery( "delete Human" ).executeUpdate();
+		t.commit();
+		s.close();
+	}
+
+	public void testUpdateOnDiscriminatorSubclass() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		int count = s.createQuery( "update PettingZoo set name = name" ).executeUpdate();
+		assertEquals( "Incorrect discrim subclass update count", 1, count );
+
+		t.rollback();
+		t = s.beginTransaction();
+
+		count = s.createQuery( "update PettingZoo pz set pz.name = pz.name where pz.id = :id" )
+				.setLong( "id", data.pettingZoo.getId().longValue() )
+				.executeUpdate();
+		assertEquals( "Incorrect discrim subclass update count", 1, count );
+
+		t.rollback();
+		t = s.beginTransaction();
+
+		count = s.createQuery( "update Zoo as z set z.name = z.name" ).executeUpdate();
+		assertEquals( "Incorrect discrim subclass update count", 2, count );
+
+		t.rollback();
+		t = s.beginTransaction();
+
+		// TODO : not so sure this should be allowed.  Seems to me that if they specify an alias,
+		// property-refs should be required to be qualified.
+		count = s.createQuery( "update Zoo as z set name = name where id = :id" )
+				.setLong( "id", data.zoo.getId().longValue() )
+				.executeUpdate();
+		assertEquals( "Incorrect discrim subclass update count", 1, count );
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testUpdateOnAnimal() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		int count = s.createQuery( "update Animal set description = description where description = :desc" )
+				.setString( "desc", data.frog.getDescription() )
+				.executeUpdate();
+		assertEquals( "Incorrect entity-updated count", 1, count );
+
+		count = s.createQuery( "update Animal set description = :newDesc where description = :desc" )
+				.setString( "desc", data.polliwog.getDescription() )
+				.setString( "newDesc", "Tadpole" )
+				.executeUpdate();
+		assertEquals( "Incorrect entity-updated count", 1, count );
+
+		Animal tadpole = ( Animal ) s.load( Animal.class, data.polliwog.getId() );
+		assertEquals( "Update did not take effect", "Tadpole", tadpole.getDescription() );
+
+		count = s.createQuery( "update Animal set bodyWeight = bodyWeight + :w1 + :w2" )
+				.setDouble( "w1", 1 )
+				.setDouble( "w2", 2 )
+				.executeUpdate();
+		assertEquals( "incorrect count on 'complex' update assignment", count, 6 );
+
+		if ( ! ( getDialect() instanceof MySQLDialect ) ) {
+			// MySQL does not support (even un-correlated) subqueries against the update-mutating table
+			s.createQuery( "update Animal set bodyWeight = ( select max(bodyWeight) from Animal )" )
+					.executeUpdate();
+		}
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testUpdateOnMammal() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		int count = s.createQuery( "update Mammal set description = description" ).executeUpdate();
+		assertEquals( "incorrect update count against 'middle' of joined-subclass hierarchy", 2, count );
+
+		count = s.createQuery( "update Mammal set bodyWeight = 25" ).executeUpdate();
+		assertEquals( "incorrect update count against 'middle' of joined-subclass hierarchy", 2, count );
+
+		if ( ! ( getDialect() instanceof MySQLDialect ) ) {
+			// MySQL does not support (even un-correlated) subqueries against the update-mutating table
+			count = s.createQuery( "update Mammal set bodyWeight = ( select max(bodyWeight) from Animal )" ).executeUpdate();
+			assertEquals( "incorrect update count against 'middle' of joined-subclass hierarchy", 2, count );
+		}
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testUpdateSetNullUnionSubclass() {
+		TestData data = new TestData();
+		data.prepare();
+
+		// These should reach out into *all* subclass tables...
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		int count = s.createQuery( "update Vehicle set owner = 'Steve'" ).executeUpdate();
+		assertEquals( "incorrect restricted update count", 4, count );
+		count = s.createQuery( "update Vehicle set owner = null where owner = 'Steve'" ).executeUpdate();
+		assertEquals( "incorrect restricted update count", 4, count );
+
+		count = s.createQuery( "delete Vehicle where owner is null" ).executeUpdate();
+		assertEquals( "incorrect restricted update count", 4, count );
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testUpdateSetNullOnDiscriminatorSubclass() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		int count = s.createQuery( "update PettingZoo set address.city = null" ).executeUpdate();
+		assertEquals( "Incorrect discrim subclass delete count", 1, count );
+		count = s.createQuery( "delete Zoo where address.city is null" ).executeUpdate();
+		assertEquals( "Incorrect discrim subclass delete count", 1, count );
+
+		count = s.createQuery( "update Zoo set address.city = null" ).executeUpdate();
+		assertEquals( "Incorrect discrim subclass delete count", 1, count );
+		count = s.createQuery( "delete Zoo where address.city is null" ).executeUpdate();
+		assertEquals( "Incorrect discrim subclass delete count", 1, count );
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testUpdateSetNullOnJoinedSubclass() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		int count = s.createQuery( "update Mammal set bodyWeight = null" ).executeUpdate();
+		assertEquals( "Incorrect deletion count on joined subclass", 2, count );
+
+		count = s.createQuery( "delete Animal where bodyWeight = null" ).executeUpdate();
+		assertEquals( "Incorrect deletion count on joined subclass", 2, count );
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+
+	// DELETES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void testDeleteWithSubquery() {
+		// setup the test data...
+		Session s = openSession();
+		s.beginTransaction();
+		SimpleEntityWithAssociation owner = new SimpleEntityWithAssociation( "myEntity-1" );
+		owner.addAssociation( "assoc-1" );
+		owner.addAssociation( "assoc-2" );
+		owner.addAssociation( "assoc-3" );
+		s.save( owner );
+		SimpleEntityWithAssociation owner2 = new SimpleEntityWithAssociation( "myEntity-2" );
+		owner2.addAssociation( "assoc-1" );
+		owner2.addAssociation( "assoc-2" );
+		owner2.addAssociation( "assoc-3" );
+		owner2.addAssociation( "assoc-4" );
+		s.save( owner2 );
+		SimpleEntityWithAssociation owner3 = new SimpleEntityWithAssociation( "myEntity-3" );
+		s.save( owner3 );
+		s.getTransaction().commit();
+		s.close();
+
+		// now try the bulk delete
+		s = openSession();
+		s.beginTransaction();
+		int count = s.createQuery( "delete SimpleEntityWithAssociation e where size( e.associatedEntities ) = 0 and e.name like '%'" ).executeUpdate();
+		assertEquals( "incorrect delete count", 1, count );
+		s.getTransaction().commit();
+		s.close();
+
+		// finally, clean up
+		s = openSession();
+		s.beginTransaction();
+		s.createQuery( "delete SimpleAssociatedEntity" ).executeUpdate();
+		s.createQuery( "delete SimpleEntityWithAssociation" ).executeUpdate();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testSimpleDeleteOnAnimal() {
+		if ( getDialect().hasSelfReferentialForeignKeyBug() ) {
+			reportSkip( "self referential FK bug", "HQL delete testing" );
+			return;
+		}
+
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		int count = s.createQuery( "delete from Animal as a where a.id = :id" )
+				.setLong( "id", data.polliwog.getId().longValue() )
+				.executeUpdate();
+		assertEquals( "Incorrect delete count", 1, count );
+
+		count = s.createQuery( "delete Animal where id = :id" )
+				.setLong( "id", data.catepillar.getId().longValue() )
+				.executeUpdate();
+		assertEquals( "incorrect delete count", 1, count );
+
+		// HHH-873...
+		if ( supportsSubqueryOnMutatingTable() ) {
+			count = s.createQuery( "delete from User u where u not in (select u from User u)" ).executeUpdate();
+			assertEquals( 0, count );
+		}
+
+		count = s.createQuery( "delete Animal a" ).executeUpdate();
+		assertEquals( "Incorrect delete count", 4, count );
+
+		List list = s.createQuery( "select a from Animal as a" ).list();
+		assertTrue( "table not empty", list.isEmpty() );
+
+		t.commit();
+		s.close();
+		data.cleanup();
+	}
+
+	public void testDeleteOnDiscriminatorSubclass() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		int count = s.createQuery( "delete PettingZoo" ).executeUpdate();
+		assertEquals( "Incorrect discrim subclass delete count", 1, count );
+
+		count = s.createQuery( "delete Zoo" ).executeUpdate();
+		assertEquals( "Incorrect discrim subclass delete count", 1, count );
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testDeleteOnJoinedSubclass() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		int count = s.createQuery( "delete Mammal where bodyWeight > 150" ).executeUpdate();
+		assertEquals( "Incorrect deletion count on joined subclass", 1, count );
+
+		count = s.createQuery( "delete Mammal" ).executeUpdate();
+		assertEquals( "Incorrect deletion count on joined subclass", 1, count );
+
+		count = s.createQuery( "delete SubMulti" ).executeUpdate();
+		assertEquals( "Incorrect deletion count on joined subclass", 0, count );
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testDeleteOnMappedJoin() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		int count = s.createQuery( "delete Joiner where joinedName = :joinedName" ).setString( "joinedName", "joined-name" ).executeUpdate();
+		assertEquals( "Incorrect deletion count on joined subclass", 1, count );
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+	
+	public void testDeleteUnionSubclassAbstractRoot() {
+		TestData data = new TestData();
+		data.prepare();
+
+		// These should reach out into *all* subclass tables...
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		int count = s.createQuery( "delete Vehicle where owner = :owner" ).setString( "owner", "Steve" ).executeUpdate();
+		assertEquals( "incorrect restricted update count", 1, count );
+
+		count = s.createQuery( "delete Vehicle" ).executeUpdate();
+		assertEquals( "incorrect update count", 3, count );
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testDeleteUnionSubclassConcreteSubclass() {
+		TestData data = new TestData();
+		data.prepare();
+
+		// These should only affect the given table
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		int count = s.createQuery( "delete Truck where owner = :owner" ).setString( "owner", "Steve" ).executeUpdate();
+		assertEquals( "incorrect restricted update count", 1, count );
+
+		count = s.createQuery( "delete Truck" ).executeUpdate();
+		assertEquals( "incorrect update count", 2, count );
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testDeleteUnionSubclassLeafSubclass() {
+		TestData data = new TestData();
+		data.prepare();
+
+		// These should only affect the given table
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		int count = s.createQuery( "delete Car where owner = :owner" ).setString( "owner", "Kirsten" ).executeUpdate();
+		assertEquals( "incorrect restricted update count", 1, count );
+
+		count = s.createQuery( "delete Car" ).executeUpdate();
+		assertEquals( "incorrect update count", 0, count );
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testDeleteWithMetadataWhereFragments() throws Throwable {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		// Note: we are just checking the syntax here...
+		s.createQuery("delete from Bar").executeUpdate();
+		s.createQuery("delete from Bar where barString = 's'").executeUpdate();
+
+		t.commit();
+		s.close();
+	}
+
+	public void testDeleteRestrictedOnManyToOne() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		int count = s.createQuery( "delete Animal where mother = :mother" )
+				.setEntity( "mother", data.butterfly )
+				.executeUpdate();
+		assertEquals( 1, count );
+
+		t.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testDeleteSyntaxWithCompositeId() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		s.createQuery( "delete EntityWithCrazyCompositeKey where id.id = 1 and id.otherId = 2" ).executeUpdate();
+		s.createQuery( "delete from EntityWithCrazyCompositeKey where id.id = 1 and id.otherId = 2" ).executeUpdate();
+		s.createQuery( "delete from EntityWithCrazyCompositeKey e where e.id.id = 1 and e.id.otherId = 2" ).executeUpdate();
+
+		t.commit();
+		s.close();
+	}
+
+	private class TestData {
+
+		private Animal polliwog;
+		private Animal catepillar;
+		private Animal frog;
+		private Animal butterfly;
+
+		private Zoo zoo;
+		private Zoo pettingZoo;
+
+		private void prepare() {
+			Session s = openSession();
+			Transaction txn = s.beginTransaction();
+
+			polliwog = new Animal();
+			polliwog.setBodyWeight( 12 );
+			polliwog.setDescription( "Polliwog" );
+
+			catepillar = new Animal();
+			catepillar.setBodyWeight( 10 );
+			catepillar.setDescription( "Catepillar" );
+
+			frog = new Animal();
+			frog.setBodyWeight( 34 );
+			frog.setDescription( "Frog" );
+
+			polliwog.setFather( frog );
+			frog.addOffspring( polliwog );
+
+			butterfly = new Animal();
+			butterfly.setBodyWeight( 9 );
+			butterfly.setDescription( "Butterfly" );
+
+			catepillar.setMother( butterfly );
+			butterfly.addOffspring( catepillar );
+
+			s.save( frog );
+			s.save( polliwog );
+			s.save( butterfly );
+			s.save( catepillar );
+
+			Dog dog = new Dog();
+			dog.setBodyWeight( 200 );
+			dog.setDescription( "dog" );
+			s.save( dog );
+
+			Cat cat = new Cat();
+			cat.setBodyWeight( 100 );
+			cat.setDescription( "cat" );
+			s.save( cat );
+
+			zoo = new Zoo();
+			zoo.setName( "Zoo" );
+			Address add = new Address();
+			add.setCity("MEL");
+			add.setCountry("AU");
+			add.setStreet("Main st");
+			add.setPostalCode("3000");
+			zoo.setAddress(add);
+			
+			pettingZoo = new PettingZoo();
+			pettingZoo.setName( "Petting Zoo" );
+			Address addr = new Address();
+			addr.setCity("Sydney");
+			addr.setCountry("AU");
+			addr.setStreet("High st");
+			addr.setPostalCode("2000");
+			pettingZoo.setAddress(addr);
+
+			s.save( zoo );
+			s.save( pettingZoo );
+
+			Joiner joiner = new Joiner();
+			joiner.setJoinedName( "joined-name" );
+			joiner.setName( "name" );
+			s.save( joiner );
+
+			Car car = new Car();
+			car.setVin( "123c" );
+			car.setOwner( "Kirsten" );
+			s.save( car );
+
+			Truck truck = new Truck();
+			truck.setVin( "123t" );
+			truck.setOwner( "Steve" );
+			s.save( truck );
+
+			SUV suv = new SUV();
+			suv.setVin( "123s" );
+			suv.setOwner( "Joe" );
+			s.save( suv );
+
+			Pickup pickup = new Pickup();
+			pickup.setVin( "123p" );
+			pickup.setOwner( "Cecelia" );
+			s.save( pickup );
+
+			BooleanLiteralEntity bool = new BooleanLiteralEntity();
+			s.save( bool );
+
+			txn.commit();
+			s.close();
+		}
+
+		private void cleanup() {
+			Session s = openSession();
+			Transaction txn = s.beginTransaction();
+
+			// workaround awesome HSQLDB "feature"
+			s.createQuery( "delete from Animal where mother is not null or father is not null" ).executeUpdate();
+			s.createQuery( "delete from Animal" ).executeUpdate();
+			s.createQuery( "delete from Zoo" ).executeUpdate();
+			s.createQuery( "delete from Joiner" ).executeUpdate();
+			s.createQuery( "delete from Vehicle" ).executeUpdate();
+			s.createQuery( "delete from BooleanLiteralEntity" ).executeUpdate();
+
+			txn.commit();
+			s.close();
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Car.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Car.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Car.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+// $Id: Car.java 7087 2005-06-08 18:23:44Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * Implementation of Car.
+ *
+ * @author Steve Ebersole
+ */
+public class Car extends Vehicle {
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Cat.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Cat.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Cat.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+//$Id: Cat.java 4476 2004-09-02 02:28:13Z oneovthafew $
+package org.hibernate.test.hql;
+
+/**
+ * @author Gavin King
+ */
+public class Cat extends DomesticAnimal {
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ClassicTranslatorTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ClassicTranslatorTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ClassicTranslatorTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+package org.hibernate.test.hql;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.hql.classic.ClassicQueryTranslatorFactory;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Some simple test queries using the classic translator explicitly
+ * to ensure that code is not broken in changes for the new translator.
+ * <p/>
+ * Only really checking translation and syntax, not results.
+ *
+ * @author Steve Ebersole
+ */
+public class ClassicTranslatorTest extends QueryTranslatorTestCase {
+
+	public ClassicTranslatorTest(String x) {
+		super( x );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ClassicTranslatorTest.class );
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.QUERY_TRANSLATOR, ClassicQueryTranslatorFactory.class.getName() );
+	}
+
+
+	public boolean createSchema() {
+		return true;
+	}
+
+	public boolean recreateSchemaAfterFailure() {
+		return true;
+	}
+
+	public void testQueries() {
+		Session session = openSession();
+		session.beginTransaction();
+
+		session.createQuery( "from Animal" ).list();
+
+		session.createQuery( "select a from Animal as a" ).list();
+		session.createQuery( "select a.mother from Animal as a" ).list();
+		session.createQuery( "select m from Animal as a inner join a.mother as m" ).list();
+		session.createQuery( "select a from Animal as a inner join fetch a.mother" ).list();
+
+		session.createQuery( "from Animal as a where a.description = ?" ).setString( 0, "jj" ).list();
+		session.createQuery( "from Animal as a where a.description = :desc" ).setString( "desc", "jr" ).list();
+		session.createQuery( "from Animal as a where a.description = ? or a.description = :desc" )
+				.setString( 0, "jj" )
+				.setString( "desc", "jr" )
+				.list();
+
+		session.getTransaction().commit();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Classification.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Classification.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Classification.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+package org.hibernate.test.hql;
+
+import java.io.Serializable;
+import java.util.HashMap;
+
+/**
+ * Mimic a JDK 5 enum.
+ *
+ * @author Steve Ebersole
+ */
+public class Classification implements Serializable, Comparable {
+
+	public static final Classification COOL = new Classification( "COOL", 0 );
+	public static final Classification LAME = new Classification( "LAME", 1 );
+
+	private static final HashMap INSTANCES = new HashMap();
+	static {
+		INSTANCES.put( COOL.name, COOL );
+		INSTANCES.put( LAME.name, LAME );
+	}
+
+	private final String name;
+	private final int ordinal;
+	private final int hashCode;
+
+	private Classification(String name, int ordinal) {
+		this.name = name;
+		this.ordinal = ordinal;
+
+		int hashCode = name.hashCode();
+		hashCode = 29 * hashCode + ordinal;
+		this.hashCode = hashCode;
+	}
+
+	public String name() {
+		return name;
+	}
+
+	public int ordinal() {
+		return ordinal;
+	}
+
+	public boolean equals(Object obj) {
+		return compareTo( obj ) == 0;
+	}
+
+	public int compareTo(Object o) {
+		int otherOrdinal = ( ( Classification ) o ).ordinal;
+		if ( ordinal == otherOrdinal ) {
+			return 0;
+		}
+		else if ( ordinal > otherOrdinal ) {
+			return 1;
+		}
+		else {
+			return -1;
+		}
+	}
+
+	public int hashCode() {
+		return hashCode;
+	}
+
+	public static Classification valueOf(String name) {
+		return ( Classification ) INSTANCES.get( name );
+	}
+
+	public static Classification valueOf(Integer ordinal) {
+		if ( ordinal == null ) {
+			return null;
+		}
+		switch ( ordinal.intValue() ) {
+			case 0: return COOL;
+			case 1: return LAME;
+			default: throw new IllegalArgumentException( "unknown classification ordinal [" + ordinal + "]" );
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ClassificationType.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ClassificationType.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ClassificationType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,101 @@
+package org.hibernate.test.hql;
+
+import org.hibernate.usertype.EnhancedUserType;
+import org.hibernate.HibernateException;
+import org.hibernate.Hibernate;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.Types;
+import java.io.Serializable;
+
+/**
+ * A custom type for mapping {@link org.hibernate.test.hql.Classification} instances
+ * to the respective db column.
+ * </p>
+ * THis is largely intended to mimic JDK5 enum support in JPA.  Here we are
+ * using the approach of storing the ordinal values, rather than the names.
+ *
+ * @author Steve Ebersole
+ */
+public class ClassificationType implements EnhancedUserType {
+
+	public int[] sqlTypes() {
+		return new int[] { Types.TINYINT };
+	}
+
+	public Class returnedClass() {
+		return Classification.class;
+	}
+
+	public boolean equals(Object x, Object y) throws HibernateException {
+		if ( x == null && y == null ) {
+			return false;
+		}
+		else if ( x != null ) {
+			return x.equals( y );
+		}
+		else {
+			return y.equals( x );
+		}
+	}
+
+	public int hashCode(Object x) throws HibernateException {
+		return x.hashCode();
+	}
+
+	public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
+		Integer ordinal = ( Integer ) Hibernate.INTEGER.nullSafeGet( rs, names[0] );
+		return Classification.valueOf( ordinal );
+	}
+
+	public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
+		Integer ordinal = value == null ? null : new Integer( ( ( Classification ) value ).ordinal() );
+		Hibernate.INTEGER.nullSafeSet( st, ordinal, index );
+	}
+
+	public Object deepCopy(Object value) throws HibernateException {
+		return value;
+	}
+
+	public boolean isMutable() {
+		return false;
+	}
+
+	public Serializable disassemble(Object value) throws HibernateException {
+		return ( Classification ) value;
+	}
+
+	public Object assemble(Serializable cached, Object owner) throws HibernateException {
+		return cached;
+	}
+
+	public Object replace(Object original, Object target, Object owner) throws HibernateException {
+		return original;
+	}
+
+	public String objectToSQLString(Object value) {
+		return extractOrdinalString( value );
+	}
+
+	public String toXMLString(Object value) {
+		return extractName( value );
+	}
+
+	public Object fromXMLString(String xmlValue) {
+		return Classification.valueOf( xmlValue );
+	}
+
+	private String extractName(Object obj) {
+		return ( ( Classification ) obj ).name();
+	}
+
+	private int extractOrdinal(Object value) {
+		return ( ( Classification ) value ).ordinal();
+	}
+
+	private String extractOrdinalString(Object value) {
+		return Integer.toString( extractOrdinal( value ) );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ComponentContainer.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ComponentContainer.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ComponentContainer.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.hql" default-access="field">
+
+    <class name="ComponentContainer" table="HQL_COMP_CONT">
+        <id name="id" type="long" column="ID">
+            <generator class="increment" />
+        </id>
+        <component name="address" class="ComponentContainer$Address">
+            <property name="street" type="string" column="STREET_ADDR" />
+            <property name="city" type="string" column="CITY_ADDR" />
+            <property name="state" type="string" column="STATE_ADDR" />
+            <component name="zip" class="ComponentContainer$Address$Zip">
+                <property name="code" type="int" column="ZIP_CODE_ADDR" />
+                <property name="plus4" type="int" column="ZIP_PLUS4_ADDR" />
+            </component>
+        </component>
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ComponentContainer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ComponentContainer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ComponentContainer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,107 @@
+package org.hibernate.test.hql;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class ComponentContainer {
+
+	private Long id;
+	private ComponentContainer.Address address;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public ComponentContainer.Address getAddress() {
+		return address;
+	}
+
+	public void setAddress(ComponentContainer.Address address) {
+		this.address = address;
+	}
+
+	public static class Address {
+		private String street;
+		private String city;
+		private String state;
+		private ComponentContainer.Address.Zip zip;
+
+		public Address() {
+		}
+
+		public Address(String street, String city, String state, ComponentContainer.Address.Zip zip) {
+			this.street = street;
+			this.city = city;
+			this.state = state;
+			this.zip = zip;
+		}
+
+		public String getStreet() {
+			return street;
+		}
+
+		public void setStreet(String street) {
+			this.street = street;
+		}
+
+		public String getCity() {
+			return city;
+		}
+
+		public void setCity(String city) {
+			this.city = city;
+		}
+
+		public String getState() {
+			return state;
+		}
+
+		public void setState(String state) {
+			this.state = state;
+		}
+
+		public ComponentContainer.Address.Zip getZip() {
+			return zip;
+		}
+
+		public void setZip(ComponentContainer.Address.Zip zip) {
+			this.zip = zip;
+		}
+
+		public static class Zip {
+			private int code;
+			private int plus4;
+
+			public Zip() {
+			}
+
+			public Zip(int code, int plus4) {
+				this.code = code;
+				this.plus4 = plus4;
+			}
+
+			public int getCode() {
+				return code;
+			}
+
+			public void setCode(int code) {
+				this.code = code;
+			}
+
+			public int getPlus4() {
+				return plus4;
+			}
+
+			public void setPlus4(int plus4) {
+				this.plus4 = plus4;
+			}
+		}
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CrazyCompositeKey.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CrazyCompositeKey.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CrazyCompositeKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+// $Id: CrazyCompositeKey.java 6970 2005-05-31 20:24:41Z oneovthafew $
+package org.hibernate.test.hql;
+
+import java.io.Serializable;
+
+/**
+ * Implementation of CrazyCompositeKey.
+ *
+ * @author Steve Ebersole
+ */
+public class CrazyCompositeKey implements Serializable {
+	private Long id;
+	private Long otherId;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getOtherId() {
+		return otherId;
+	}
+
+	public void setOtherId(Long otherId) {
+		this.otherId = otherId;
+	}
+	
+	public boolean equals(Object that) {
+		CrazyCompositeKey cck = (CrazyCompositeKey) that;
+		return cck.id.longValue() == id.longValue()
+			&& cck.otherId.longValue() == otherId.longValue();
+	}
+	
+	public int hashCode() {
+		return id.hashCode() + otherId.hashCode();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CrazyIdFieldNames.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CrazyIdFieldNames.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CrazyIdFieldNames.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.hql">
+
+    <class name="HeresAnotherCrazyIdFieldName" table="CRAZY_ID_NODE">
+        <id name="heresAnotherCrazyIdFieldName" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="name" type="string"/>
+    </class>
+
+    <class name="MoreCrazyIdFieldNameStuffEntity" table="CRAZY_ID_TOP">
+        <id name="moreCrazyIdFieldNameStuffEntity" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="name" type="string" />
+        <many-to-one name="heresAnotherCrazyIdFieldName" class="HeresAnotherCrazyIdFieldName"/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CriteriaClassicAggregationReturnTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CriteriaClassicAggregationReturnTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CriteriaClassicAggregationReturnTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,107 @@
+package org.hibernate.test.hql;
+
+import java.util.Collections;
+
+import junit.framework.Test;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.dialect.function.ClassicCountFunction;
+import org.hibernate.dialect.function.ClassicAvgFunction;
+import org.hibernate.dialect.function.ClassicSumFunction;
+import org.hibernate.hql.ast.QueryTranslatorImpl;
+import org.hibernate.hql.QueryTranslator;
+import org.hibernate.hql.QueryTranslatorFactory;
+import org.hibernate.hql.classic.ClassicQueryTranslatorFactory;
+import org.hibernate.Hibernate;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class CriteriaClassicAggregationReturnTest extends QueryTranslatorTestCase {
+
+	public CriteriaClassicAggregationReturnTest(String x) {
+		super( x );
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.addSqlFunction( "count", new ClassicCountFunction() );
+		cfg.addSqlFunction( "avg", new ClassicAvgFunction() );
+		cfg.addSqlFunction( "sum", new ClassicSumFunction() );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CriteriaClassicAggregationReturnTest.class );
+	}
+
+	public void testClassicHQLAggregationReturnTypes() {
+		// EJB3: COUNT returns Long
+		QueryTranslatorImpl translator = createNewQueryTranslator( "select count(*) from Human h", sfi() );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.INTEGER, translator.getReturnTypes()[0] );
+
+		translator = createNewQueryTranslator( "select count(h.height) from Human h", sfi() );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.INTEGER, translator.getReturnTypes()[0] );
+
+		// MAX, MIN return the type of the state-field to which they are applied.
+		translator = createNewQueryTranslator( "select max(h.height) from Human h", sfi() );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
+
+		translator = createNewQueryTranslator( "select max(h.id) from Human h", sfi() );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] );
+
+		// AVG returns Float integrals, and otherwise the field type.
+		translator = createNewQueryTranslator( "select avg(h.height) from Human h", sfi() );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
+
+		translator = createNewQueryTranslator( "select avg(h.id) from Human h", sfi() );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.FLOAT, translator.getReturnTypes()[0] );
+
+		translator = createNewQueryTranslator( "select avg(h.bigIntegerValue) from Human h", sfi() );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.BIG_INTEGER, translator.getReturnTypes()[0] );
+
+        // SUM returns underlying type sum
+ 	    translator = createNewQueryTranslator( "select sum(h.id) from Human h", sfi() );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] );
+
+		translator = createNewQueryTranslator( "select sum(h.intValue) from Human h", sfi() );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.INTEGER, translator.getReturnTypes()[0] );
+
+		translator = createNewQueryTranslator( "select sum(h.height) from Human h", sfi() );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
+
+		translator = createNewQueryTranslator( "select sum(h.floatValue) from Human h", sfi() );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.FLOAT, translator.getReturnTypes()[0] );
+
+		translator = createNewQueryTranslator( "select sum(h.bigIntegerValue) from Human h", sfi() );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.BIG_INTEGER, translator.getReturnTypes()[0] );
+
+		translator = createNewQueryTranslator( "select sum(h.bigDecimalValue) from Human h", sfi() );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.BIG_DECIMAL, translator.getReturnTypes()[0] );
+
+		// special case to test classicquery special case handling of count(*)
+		QueryTranslator oldQueryTranslator = null;
+		String hql = "select count(*) from Human h";
+		QueryTranslatorFactory classic = new ClassicQueryTranslatorFactory();
+		oldQueryTranslator = classic.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, sfi() );
+		oldQueryTranslator.compile( Collections.EMPTY_MAP, true);
+		assertEquals( "incorrect return type count", 1, oldQueryTranslator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.INTEGER, oldQueryTranslator.getReturnTypes()[0] );
+
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,173 @@
+//$Id: HQLTest.java 9873 2006-05-04 13:42:48Z max.andersen at jboss.com $
+package org.hibernate.test.hql;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collections;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.classic.Session;
+import org.hibernate.criterion.Projections;
+import org.hibernate.hql.QueryTranslator;
+import org.hibernate.hql.QueryTranslatorFactory;
+import org.hibernate.hql.ast.QueryTranslatorImpl;
+import org.hibernate.hql.ast.tree.SelectClause;
+import org.hibernate.hql.classic.ClassicQueryTranslatorFactory;
+
+/**
+ * Tests cases for ensuring alignment between HQL and Criteria behavior. 
+ *
+ * @author Max Rydahl Andersen
+ */
+public class CriteriaHQLAlignmentTest extends QueryTranslatorTestCase {
+
+	public CriteriaHQLAlignmentTest(String x) {
+		super( x );
+		SelectClause.VERSION2_SQL = true;
+	}
+
+	public boolean createSchema() {
+		return true; // needed for the Criteria return type test
+	}
+
+	public boolean recreateSchemaAfterFailure() {
+		return true;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CriteriaHQLAlignmentTest.class );
+	}
+
+	public void testHQLAggregationReturnType() {
+		// EJB3: COUNT returns Long
+		QueryTranslatorImpl translator = createNewQueryTranslator( "select count(*) from Human h" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] );
+		
+		translator = createNewQueryTranslator( "select count(h.height) from Human h" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] );
+				
+		// MAX, MIN return the type of the state-field to which they are applied. 
+		translator = createNewQueryTranslator( "select max(h.height) from Human h" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
+		
+		translator = createNewQueryTranslator( "select max(h.id) from Human h" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] );
+		
+		// AVG returns Double.
+		translator = createNewQueryTranslator( "select avg(h.height) from Human h" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
+		
+		translator = createNewQueryTranslator( "select avg(h.id) from Human h" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
+		
+		translator = createNewQueryTranslator( "select avg(h.bigIntegerValue) from Human h" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
+		
+        // SUM returns Long when applied to state-fields of integral types (other than BigInteger);
+ 	    translator = createNewQueryTranslator( "select sum(h.id) from Human h" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] );
+		
+		translator = createNewQueryTranslator( "select sum(h.intValue) from Human h" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] );
+		
+		// SUM returns Double when applied to state-fields of floating point types; 
+		translator = createNewQueryTranslator( "select sum(h.height) from Human h" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
+
+		translator = createNewQueryTranslator( "select sum(h.floatValue) from Human h" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
+		
+	    // SUM returns BigInteger when applied to state-fields of type BigInteger 
+		translator = createNewQueryTranslator( "select sum(h.bigIntegerValue) from Human h" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.BIG_INTEGER, translator.getReturnTypes()[0] );
+		
+		// SUM and BigDecimal when applied to state-fields of type BigDecimal.
+		translator = createNewQueryTranslator( "select sum(h.bigDecimalValue) from Human h" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.BIG_DECIMAL, translator.getReturnTypes()[0] );
+
+		// special case to test classicquery special case handling of count(*)
+		QueryTranslator oldQueryTranslator = null;
+		String hql = "select count(*) from Human h";
+		QueryTranslatorFactory classic = new ClassicQueryTranslatorFactory();
+		oldQueryTranslator = classic.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, getSessionFactoryImplementor() );
+		oldQueryTranslator.compile( Collections.EMPTY_MAP, true);
+		assertEquals( "incorrect return type count", 1, oldQueryTranslator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.LONG, oldQueryTranslator.getReturnTypes()[0] );
+
+	}
+	
+	// HHH-1724 Align Criteria with HQL aggregation return types.
+	public void testCriteriaAggregationReturnTypeFailureExpected() {
+		Session s = openSession();
+		Human human = new Human();
+		human.setBigIntegerValue( new BigInteger("42") );
+		human.setBigDecimalValue( new BigDecimal(45) );
+		s.save(human);
+		
+		// EJB3: COUNT returns Long
+		Long longValue = (Long) s.createCriteria( Human.class ).setProjection( Projections.rowCount()).uniqueResult();
+		assertEquals(longValue, new Long(1));
+		longValue = (Long) s.createCriteria( Human.class ).setProjection( Projections.count("height")).uniqueResult();
+		assertEquals(longValue, new Long(1));
+		
+		 // MAX, MIN return the type of the state-field to which they are applied. 		
+		Double dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.max( "height" )).uniqueResult();
+		assertNotNull(dblValue);
+		
+		longValue = (Long) s.createCriteria( Human.class ).setProjection( Projections.max( "id" )).uniqueResult();
+		assertNotNull(longValue);
+		
+		// AVG returns Double.
+		dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.avg( "height" )).uniqueResult();
+		assertNotNull(dblValue);
+		
+		dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.avg( "id" )).uniqueResult();
+		assertNotNull(dblValue);
+		
+		dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.avg( "bigIntegerValue" )).uniqueResult();
+		assertNotNull(dblValue);
+		
+        // SUM returns Long when applied to state-fields of integral types (other than BigInteger);
+		longValue = (Long) s.createCriteria( Human.class ).setProjection( Projections.sum( "id" )).uniqueResult();
+		assertNotNull(longValue);
+		
+		longValue = (Long) s.createCriteria( Human.class ).setProjection( Projections.sum( "intValue" )).uniqueResult();
+		assertNotNull(longValue);
+		
+		// SUM returns Double when applied to state-fields of floating point types; 
+		dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.sum( "height" )).uniqueResult();
+		assertNotNull(dblValue);
+		
+		dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.sum( "floatValue" )).uniqueResult();
+		assertNotNull(dblValue);
+		
+	    // SUM returns BigInteger when applied to state-fields of type BigInteger 
+		BigInteger bigIValue = (BigInteger) s.createCriteria( Human.class ).setProjection( Projections.sum( "bigIntegerValue" )).uniqueResult();
+		assertNotNull(bigIValue);
+		
+		// SUM and BigDecimal when applied to state-fields of type BigDecimal.
+		BigDecimal bigDValue = (BigDecimal) s.createCriteria( Human.class ).setProjection( Projections.sum( "bigDecimalValue" )).uniqueResult();
+		assertNotNull(bigDValue);
+		
+		s.delete( human );
+		s.flush();
+		s.close();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Dog.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Dog.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Dog.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+//$Id: Dog.java 4476 2004-09-02 02:28:13Z oneovthafew $
+package org.hibernate.test.hql;
+
+/**
+ * @author Gavin King
+ */
+public class Dog extends DomesticAnimal {
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/DomesticAnimal.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/DomesticAnimal.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/DomesticAnimal.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+//$Id: DomesticAnimal.java 4899 2004-12-06 14:17:24Z pgmjsd $
+package org.hibernate.test.hql;
+
+/**
+ * @author Gavin King
+ */
+public class DomesticAnimal extends Mammal {
+	private Human owner;
+
+	public Human getOwner() {
+		return owner;
+	}
+
+	public void setOwner(Human owner) {
+		this.owner = owner;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/DomesticAnimal.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/EJBQLTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/EJBQLTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/EJBQLTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,311 @@
+//$Id: EJBQLTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.hql;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.hql.QueryTranslator;
+import org.hibernate.hql.QueryTranslatorFactory;
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.hql.ast.ASTQueryTranslatorFactory;
+import org.hibernate.hql.ast.HqlParser;
+import org.hibernate.hql.ast.QueryTranslatorImpl;
+import org.hibernate.hql.ast.util.ASTUtil;
+import org.hibernate.test.TestCase;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+import antlr.collections.AST;
+
+
+/**
+ * @author <a href="mailto:alex at jboss.org">Alexey Loubyansky</a>
+ */
+public class EJBQLTest extends FunctionalTestCase {
+
+	public EJBQLTest(String x) {
+		super( x );
+	}
+
+	public String[] getMappings() {
+		return new String[]{
+			"hql/Animal.hbm.xml",
+			"batchfetch/ProductLine.hbm.xml",
+			"cid/Customer.hbm.xml",
+			"cid/Order.hbm.xml",
+			"cid/LineItem.hbm.xml",
+			"cid/Product.hbm.xml",
+			"legacy/Glarch.hbm.xml",
+			"legacy/Fee.hbm.xml",
+			"legacy/Qux.hbm.xml",
+			"legacy/Fum.hbm.xml",
+			"legacy/Holder.hbm.xml",
+			"legacy/One.hbm.xml",
+			"legacy/FooBar.hbm.xml",
+			"legacy/Many.hbm.xml",
+			"legacy/Baz.hbm.xml",
+			"legacy/Simple.hbm.xml",
+			"legacy/Middle.hbm.xml",
+			"legacy/Category.hbm.xml",
+			"legacy/Multi.hbm.xml",
+			"legacy/Commento.hbm.xml",
+			"legacy/Marelo.hbm.xml",
+			"compositeelement/Parent.hbm.xml",
+			"legacy/Container.hbm.xml",
+		};
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( EJBQLTest.class );
+	}
+
+
+	public boolean createSchema() {
+		return false;
+	}
+
+	public void testEjb3PositionalParameters() throws Exception {
+		QueryTranslatorImpl qt = compile( "from Animal a where a.bodyWeight = ?1" );
+		AST ast = ( AST ) qt.getSqlAST();
+
+		// make certain that the ejb3-positional param got recognized as a named param
+		List namedParams = ASTUtil.collectChildren(
+		        ast,
+		        new ASTUtil.FilterPredicate() {
+			        public boolean exclude(AST n) {
+				        return n.getType() != HqlSqlTokenTypes.NAMED_PARAM;
+			        }
+		        }
+		);
+		assertTrue( "ejb3 positional param not recognized as a named param", namedParams.size() > 0 );
+	}
+
+	/**
+	 * SELECT OBJECT(identifier)
+	 */
+	public void testSelectObjectClause() throws Exception {
+		//parse("select object(m) from Model m");
+		assertEjbqlEqualsHql( "select object(m) from Model m", "from Model m" );
+	}
+
+	/**
+	 * IN(collection_valued_path) identifier
+	 */
+	public void testCollectionMemberDeclaration() throws Exception {
+		String hql = "select o from Animal a inner join a.offspring o";
+		String ejbql = "select object(o) from Animal a, in(a.offspring) o";
+		//parse(hql);
+		//parse(ejbql);
+		assertEjbqlEqualsHql( ejbql, hql );
+	}
+
+	/**
+	 * collection_valued_path IS [NOT] EMPTY
+	 */
+	public void testIsEmpty() throws Exception {
+		//String hql = "from Animal a where not exists (from a.offspring)";
+		String hql = "from Animal a where not exists elements(a.offspring)";
+		String ejbql = "select object(a) from Animal a where a.offspring is empty";
+		//parse(hql);
+		//parse(ejbql);
+		assertEjbqlEqualsHql(ejbql, hql);
+
+		hql = "from Animal a where exists (from a.mother.father.offspring)";
+		ejbql = "select object(a) from Animal a where a.mother.father.offspring is not empty";
+		assertEjbqlEqualsHql( ejbql, hql );
+	}
+
+	/**
+	 * [NOT] MEMBER OF
+	 */
+	public void testMemberOf() throws Exception {
+		String hql = "from Animal a where a.mother in (from a.offspring)";
+		//String hql = "from Animal a where a.mother in elements(a.offspring)";
+		String ejbql = "select object(a) from Animal a where a.mother member of a.offspring";
+		//parse(hql);
+		//parse(ejbql);
+		assertEjbqlEqualsHql( ejbql, hql );
+
+		hql = "from Animal a where a.mother not in (from a.offspring)";
+		//hql = "from Animal a where a.mother not in elements(a.offspring)";
+		ejbql = "select object(a) from Animal a where a.mother not member of a.offspring";
+		//parse(hql);
+		//parse(ejbql);
+		assertEjbqlEqualsHql( ejbql, hql );
+	}
+
+	/**
+	 * Various functions.
+	 * Tests just parsing for now which means it doesn't guarantee that the generated SQL is as expected or even valid.
+	 */
+	public void testEJBQLFunctions() throws Exception {
+		String hql = "select object(a) from Animal a where a.description = concat('1', concat('2','3'), '4'||'5')||0";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "from Animal a where substring(a.description, 1, 3) = :p1";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select substring(a.description, 1, 3) from Animal a";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "from Animal a where lower(a.description) = :p1";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select lower(a.description) from Animal a";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "from Animal a where upper(a.description) = :p1";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select upper(a.description) from Animal a";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "from Animal a where length(a.description) = :p1";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select length(a.description) from Animal a";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "from Animal a where locate(a.description, 'abc', 2) = :p1";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select locate(a.description, :p1, 2) from Animal a";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select object(a) from Animal a where trim(trailing '_' from a.description) = :p1";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select trim(trailing '_' from a.description) from Animal a";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select object(a) from Animal a where trim(leading '_' from a.description) = :p1";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select object(a) from Animal a where trim(both a.description) = :p1";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select object(a) from Animal a where trim(a.description) = :p1";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select object(a) from Animal a where abs(a.bodyWeight) = sqrt(a.bodyWeight)";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select object(a) from Animal a where mod(a.bodyWeight, a.mother.bodyWeight) = :p1";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select object(a) from Animal a where BIT_LENGTH(a.bodyWeight) = :p1";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select BIT_LENGTH(a.bodyWeight) from Animal a";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select object(a) from Animal a where CURRENT_DATE = :p1 or CURRENT_TIME = :p2 or CURRENT_TIMESTAMP = :p3";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		// todo the following is not supported
+		//hql = "select CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP from Animal a";
+		//parse(hql, true);
+		//System.out.println("sql: " + toSql(hql));
+
+		hql = "select object(a) from Animal a where a.bodyWeight like '%a%'";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select object(a) from Animal a where a.bodyWeight not like '%a%'";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+
+		hql = "select object(a) from Animal a where a.bodyWeight like '%a%' escape '%'";
+		parse( hql, false );
+		System.out.println( "sql: " + toSql( hql ) );
+	}
+
+	public void testTrueFalse() throws Exception {
+		assertEjbqlEqualsHql( "from Human h where h.pregnant is true", "from Human h where h.pregnant = true" );
+		assertEjbqlEqualsHql( "from Human h where h.pregnant is false", "from Human h where h.pregnant = false" );
+		assertEjbqlEqualsHql( "from Human h where not(h.pregnant is true)", "from Human h where not( h.pregnant=true )" );
+	}
+
+
+	// Private
+
+	private void assertEjbqlEqualsHql(String ejbql, String hql) {
+		QueryTranslatorFactory ast = new ASTQueryTranslatorFactory();
+
+		QueryTranslator queryTranslator = ast.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, sfi() );
+		queryTranslator.compile( Collections.EMPTY_MAP, true );
+		String hqlSql = queryTranslator.getSQLString();
+
+		queryTranslator = ast.createQueryTranslator( ejbql, ejbql, Collections.EMPTY_MAP, sfi() );
+		queryTranslator.compile( Collections.EMPTY_MAP, true );
+		String ejbqlSql = queryTranslator.getSQLString();
+
+		assertEquals( hqlSql, ejbqlSql );
+	}
+
+	private QueryTranslatorImpl compile(String input) {
+		QueryTranslatorFactory ast = new ASTQueryTranslatorFactory();
+		QueryTranslator queryTranslator = ast.createQueryTranslator( input, input, Collections.EMPTY_MAP, sfi() );
+		queryTranslator.compile( Collections.EMPTY_MAP, true );
+
+		return ( QueryTranslatorImpl ) queryTranslator;
+	}
+
+	private AST parse(String input, boolean logging) throws RecognitionException, TokenStreamException {
+		if ( logging ) {
+			System.out.println( "input: ->" + input + "<-" );
+		}
+
+		HqlParser parser = HqlParser.getInstance( input );
+		parser.setFilter( false );
+		parser.statement();
+		AST ast = parser.getAST();
+
+		if ( logging ) {
+			System.out.println( "AST  :  " + ast.toStringTree() + "" );
+			ByteArrayOutputStream baos = new ByteArrayOutputStream();
+			parser.showAst( ast, new PrintStream( baos ) );
+			System.out.println( baos.toString() );
+		}
+
+		assertEquals( "At least one error occurred during parsing!", 0, parser.getParseErrorHandler().getErrorCount() );
+
+		return ast;
+	}
+
+	private String toSql(String hql) {
+		QueryTranslatorFactory ast = new ASTQueryTranslatorFactory();
+		QueryTranslator queryTranslator = ast.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, sfi() );
+		queryTranslator.compile( Collections.EMPTY_MAP, true );
+		return queryTranslator.getSQLString();
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/EJBQLTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/EntityWithCrazyCompositeKey.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/EntityWithCrazyCompositeKey.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/EntityWithCrazyCompositeKey.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.hql">
+
+	<class name="EntityWithCrazyCompositeKey">
+		<composite-id name="id" class="CrazyCompositeKey">
+			<key-property name="id" column="id"/>
+			<key-property name="otherId" column="other_id"/>
+		</composite-id>
+		<property name="name"/>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/EntityWithCrazyCompositeKey.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/EntityWithCrazyCompositeKey.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/EntityWithCrazyCompositeKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+// $Id: EntityWithCrazyCompositeKey.java 6567 2005-04-27 17:41:57Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * Implementation of EntityWithCrazyCompositeKey.
+ *
+ * @author Steve Ebersole
+ */
+public class EntityWithCrazyCompositeKey {
+	private CrazyCompositeKey id;
+	private String name;
+
+	public CrazyCompositeKey getId() {
+		return id;
+	}
+
+	public void setId(CrazyCompositeKey id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/FooBarCopy.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/FooBarCopy.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/FooBarCopy.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,137 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false" package="org.hibernate.test.legacy">
+
+    <!-- a slightly modified copy of FooBar.hbm.xml from the legacy test package -->
+
+    <class
+		name="Foo"
+		table="`foos`"
+		proxy="FooProxy"
+		discriminator-value="F"
+		batch-size="4"
+		dynamic-insert="true"
+		dynamic-update="true"
+		select-before-update="true">
+
+		<id name="key" type="string">
+			<column name="`foo_idcolumnname123`" length="36"/>
+			<generator class="uuid.hex">
+				<param name="seperator">:</param>
+			</generator>
+		</id>
+
+		<discriminator column="`foo_subclass_1234`" type="character" force="true"/>
+		<version name="version"/>
+
+		<many-to-one name="foo" class="Foo">
+				<column name="foo" length="36" index="fbmtoidx"/>
+		</many-to-one>
+
+		<property name="long">
+			<column name="long_" index="fbmtoidx" unique-key="abc" not-null="true"/>
+		</property>
+		<property name="integer">
+				<column name="`integer__`" unique-key="abc" not-null="true"/>
+		</property>
+		<property name="float">
+				<column name="float_" unique-key="abc" not-null="true" check="float_ > 0.0"/>
+		</property>
+		<property name="x"/>
+		<property name="double" column="double_"/>
+
+		<primitive-array name="bytes" table="foobytes">
+			<key column="id"/>
+			<index column="i"/>
+			<element column="byte_" type="byte"/>
+		</primitive-array>
+
+		<property name="date" type="date" column="date_"/>
+		<property name="timestamp" type="timestamp" column="timestamp_"/>
+		<property name="boolean" column="boolean_"/>
+		<property name="bool" column="bool_"/>
+		<property name="null" column="null_"/>
+		<property name="short" column="short_"/>
+		<property name="char" column="char_"/>
+		<property name="zero" column="zero_"/>
+		<property name="int" column="int_"/>
+		<property name="string">
+            <column name="string_" length="48" index="fbstridx"/>
+		</property>
+		<property name="byte" column="byte_"/>
+		<property name="yesno" type="yes_no"/>
+		<property name="blob" type="org.hibernate.test.legacy.Foo$Struct" column="blobb_"/>
+		<property name="nullBlob" type="serializable"/>
+		<property name="binary" column="bin_"/>
+		<property name="theLocale" access="field" column="`localeayzabc123`"/>
+
+		<property name="formula" formula="int_/2"/>
+
+		<property name="custom" type="org.hibernate.test.legacy.DoubleStringType" access="field">
+			<column name="first_name" length="66"/>
+			<column name="surname" length="66"/>
+		</property>
+		<component name="nullComponent">
+			<property name="name" column="null_cmpnt_"/>
+		</component>
+
+		<join table="jointable">
+			<key column="fooid" on-delete="cascade"/>
+			<property name="joinedProp"/>
+		</join>
+
+		<subclass
+			name="Trivial"
+			proxy="FooProxy"
+			discriminator-value="T"/>
+
+		<subclass
+			name="Abstract"
+			proxy="AbstractProxy"
+			discriminator-value="null">
+				<set name="abstracts" batch-size="2">
+					<key column="abstract_id"/>
+					<one-to-many class="Abstract"/>
+				</set>
+				<property name="time" column="the_time"/>
+
+				<subclass
+					name="Bar"
+					proxy="BarProxy"
+					discriminator-value="B">
+					<property name="barString">
+						<column name="bar_string" length="24"/>
+					</property>
+					<any name="object" meta-type="character" id-type="long" cascade="all">
+						<meta-value value="O" class="One"/>
+						<meta-value value="M" class="Many"/>
+						<column name="clazz" length="100"/>
+						<column name="gen_id"/>
+					</any>
+					<join table="bar_join_table">
+						<key column="bar_id"/>
+						<property name="name" column="name_name"/>
+					</join>
+				</subclass>
+		</subclass>
+	</class>
+
+	<class name="One" table="one">
+		<id name="key" column="one_key">
+			<generator class="native" />
+		</id>
+		<property name="x"/>
+		<property column="one_value" name="value"/>
+	</class>
+
+    <class name="Many" table="many">
+        <id name="key" column="many_key">
+            <generator class="native" />
+        </id>
+        <property name="x"/>
+    </class>
+
+</hibernate-mapping>
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HQLSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HQLSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HQLSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+// $Id: HQLSuite.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.hql;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * The full suite of tests against the Antlr grammar
+ *
+ * @author Steve Ebersole
+ */
+public class HQLSuite {
+
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "Antlr HQL grammar tests" );
+		suite.addTest( HQLTest.suite() );
+		suite.addTest( ASTParserLoadingTest.suite() );
+		suite.addTest( BulkManipulationTest.suite() );
+		suite.addTest( WithClauseTest.suite() );
+//		suite.addTest( ASTQueryTranslatorTest.suite() );
+		suite.addTest( EJBQLTest.suite() );
+		suite.addTest( HqlParserTest.suite() );
+		suite.addTest( ScrollableCollectionFetchingTest.suite() );
+		suite.addTest( ClassicTranslatorTest.suite() );
+		suite.addTest( CriteriaHQLAlignmentTest.suite() );
+		suite.addTest( CriteriaClassicAggregationReturnTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HQLTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HQLTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HQLTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1342 @@
+//$Id: HQLTest.java 11374 2007-03-29 19:09:18Z steve.ebersole at jboss.com $
+package org.hibernate.test.hql;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import antlr.RecognitionException;
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.QueryException;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.dialect.DB2Dialect;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.dialect.PostgreSQLDialect;
+import org.hibernate.dialect.SybaseDialect;
+import org.hibernate.dialect.function.SQLFunction;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.query.HQLQueryPlan;
+import org.hibernate.engine.query.ReturnMetadata;
+import org.hibernate.hql.QueryTranslator;
+import org.hibernate.hql.QueryTranslatorFactory;
+import org.hibernate.hql.ast.ASTQueryTranslatorFactory;
+import org.hibernate.hql.ast.DetailedSemanticException;
+import org.hibernate.hql.ast.QuerySyntaxException;
+import org.hibernate.hql.ast.QueryTranslatorImpl;
+import org.hibernate.hql.ast.tree.ConstructorNode;
+import org.hibernate.hql.ast.tree.DotNode;
+import org.hibernate.hql.ast.tree.IndexNode;
+import org.hibernate.hql.ast.tree.SelectClause;
+import org.hibernate.hql.ast.tree.FromReferenceNode;
+
+/**
+ * Tests cases where the AST based query translator and the 'classic' query translator generate identical SQL.
+ *
+ * @author Gavin King
+ */
+public class HQLTest extends QueryTranslatorTestCase {
+
+	public HQLTest(String x) {
+		super( x );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( HQLTest.class );
+	}
+
+	public boolean createSchema() {
+		return false;
+	}
+
+	public boolean recreateSchemaAfterFailure() {
+		return false;
+	}
+
+	protected void prepareTest() throws Exception {
+		super.prepareTest();
+		SelectClause.VERSION2_SQL = true;
+		DotNode.REGRESSION_STYLE_JOIN_SUPPRESSION = true;
+		DotNode.ILLEGAL_COLL_DEREF_EXCP_BUILDER = new DotNode.IllegalCollectionDereferenceExceptionBuilder() {
+			public QueryException buildIllegalCollectionDereferenceException(String propertyName, FromReferenceNode lhs) {
+				throw new QueryException( "illegal syntax near collection: " + propertyName );
+			}
+		};
+	}
+
+	protected void cleanupTest() throws Exception {
+		SelectClause.VERSION2_SQL = false;
+		DotNode.REGRESSION_STYLE_JOIN_SUPPRESSION = false;
+		DotNode.ILLEGAL_COLL_DEREF_EXCP_BUILDER = DotNode.DEF_ILLEGAL_COLL_DEREF_EXCP_BUILDER;
+		super.cleanupTest();
+	}
+
+	public void testInvalidCollectionDereferencesFail() {
+		// should fail with the same exceptions (because of the DotNode.ILLEGAL_COLL_DEREF_EXCP_BUILDER injection)
+		assertTranslation( "from Animal a where a.offspring.description = 'xyz'" );
+		assertTranslation( "from Animal a where a.offspring.father.description = 'xyz'" );
+	}
+
+	public void testSubComponentReferences() {
+		assertTranslation( "select c.address.zip.code from ComponentContainer c" );
+		assertTranslation( "select c.address.zip from ComponentContainer c" );
+		assertTranslation( "select c.address from ComponentContainer c" );
+	}
+
+	public void testManyToAnyReferences() {
+		assertTranslation( "from PropertySet p where p.someSpecificProperty.id is not null" );
+		assertTranslation( "from PropertySet p join p.generalProperties gp where gp.id is not null" );
+	}
+
+	public void testJoinFetchCollectionOfValues() {
+		assertTranslation( "select h from Human as h join fetch h.nickNames" );
+	}
+
+	public void testCollectionJoinsInSubselect() {
+		// caused by some goofiness in FromElementFactory that tries to
+		// handle correlated subqueries (but fails miserably) even though this
+		// is not a correlated subquery.  HHH-1248
+		assertTranslation(
+				"select a.id, a.description" +
+				" from Animal a" +
+				"       left join a.offspring" +
+				" where a in (" +
+				"       select a1 from Animal a1" +
+				"           left join a1.offspring o" +
+				"       where a1.id=1" +
+		        ")"
+		);
+		assertTranslation(
+				"select h.id, h.description" +
+		        " from Human h" +
+				"      left join h.friends" +
+				" where h in (" +
+				"      select h1" +
+				"      from Human h1" +
+				"          left join h1.friends f" +
+				"      where h1.id=1" +
+				")"
+		);
+	}
+
+	public void testEmptyInListFailureExpected() {
+		assertTranslation( "select a from Animal a where a.description in ()" );
+	}
+
+	public void testDateTimeArithmeticReturnTypesAndParameterGuessing() {
+		QueryTranslatorImpl translator = createNewQueryTranslator( "select o.orderDate - o.orderDate from Order o" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
+		translator = createNewQueryTranslator( "select o.orderDate + 2 from Order o" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.CALENDAR_DATE, translator.getReturnTypes()[0] );
+		translator = createNewQueryTranslator( "select o.orderDate -2 from Order o" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.CALENDAR_DATE, translator.getReturnTypes()[0] );
+
+		translator = createNewQueryTranslator( "from Order o where o.orderDate > ?" );
+		assertEquals( "incorrect expected param type", Hibernate.CALENDAR_DATE, translator.getParameterTranslations().getOrdinalParameterExpectedType( 1 ) );
+
+		translator = createNewQueryTranslator( "select o.orderDate + ? from Order o" );
+		assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
+		assertEquals( "incorrect return type", Hibernate.CALENDAR_DATE, translator.getReturnTypes()[0] );
+		assertEquals( "incorrect expected param type", Hibernate.DOUBLE, translator.getParameterTranslations().getOrdinalParameterExpectedType( 1 ) );
+
+	}
+
+	public void testReturnMetadata() {
+		HQLQueryPlan plan = createQueryPlan( "from Animal a" );
+		check( plan.getReturnMetadata(), false, true );
+
+		plan = createQueryPlan( "select a as animal from Animal a" );
+		check( plan.getReturnMetadata(), false, false );
+
+		plan = createQueryPlan( "from java.lang.Object" );
+		check( plan.getReturnMetadata(), true, true );
+
+		plan = createQueryPlan( "select o as entity from java.lang.Object o" );
+		check( plan.getReturnMetadata(), true, false );
+	}
+
+	private void check(
+			ReturnMetadata returnMetadata,
+	        boolean expectingEmptyTypes,
+	        boolean expectingEmptyAliases) {
+		assertNotNull( "null return metadata", returnMetadata );
+		assertNotNull( "null return metadata - types", returnMetadata );
+		assertEquals( "unexpected return size", 1, returnMetadata.getReturnTypes().length );
+		if ( expectingEmptyTypes ) {
+			assertNull( "non-empty types", returnMetadata.getReturnTypes()[0] );
+		}
+		else {
+			assertNotNull( "empty types", returnMetadata.getReturnTypes()[0] );
+		}
+		if ( expectingEmptyAliases ) {
+			assertNull( "non-empty aliases", returnMetadata.getReturnAliases() );
+		}
+		else {
+			assertNotNull( "empty aliases", returnMetadata.getReturnAliases() );
+			assertNotNull( "empty aliases", returnMetadata.getReturnAliases()[0] );
+		}
+	}
+
+	public void testImplicitJoinsAlongWithCartesianProduct() {
+		DotNode.useThetaStyleImplicitJoins = true;
+		assertTranslation( "select foo.foo from Foo foo, Foo foo2" );
+		assertTranslation( "select foo.foo.foo from Foo foo, Foo foo2" );
+		DotNode.useThetaStyleImplicitJoins = false;
+	}
+
+	public void testSubselectBetween() {
+		assertTranslation("from Animal x where (select max(a.bodyWeight) from Animal a) between :min and :max");
+		assertTranslation("from Animal x where (select max(a.description) from Animal a) like 'big%'");
+		assertTranslation("from Animal x where (select max(a.bodyWeight) from Animal a) is not null");
+		assertTranslation("from Animal x where exists (select max(a.bodyWeight) from Animal a)");
+		assertTranslation("from Animal x where (select max(a.bodyWeight) from Animal a) in (1,2,3)");
+	}
+
+	public void testFetchOrderBy() {
+		assertTranslation("from Animal a left outer join fetch a.offspring where a.mother.id = :mid order by a.description");
+	}
+
+	public void testCollectionOrderBy() {
+		assertTranslation("from Animal a join a.offspring o order by a.description");
+		assertTranslation("from Animal a join fetch a.offspring order by a.description");
+		assertTranslation("from Animal a join fetch a.offspring o order by o.description");
+		assertTranslation("from Animal a join a.offspring o order by a.description, o.description");
+	}
+
+	public void testExpressionWithParamInFunction() {
+		assertTranslation("from Animal a where abs(a.bodyWeight-:param) < 2.0");
+		assertTranslation("from Animal a where abs(:param - a.bodyWeight) < 2.0");
+		assertTranslation("from Animal where abs(:x - :y) < 2.0");
+		assertTranslation("from Animal where lower(upper(:foo)) like 'f%'");
+		if ( ! ( getDialect() instanceof SybaseDialect ) ) {
+			// SybaseDialect maps the length function -> len; classic translator does not consider that *when nested*
+			assertTranslation("from Animal a where abs(abs(a.bodyWeight - 1.0 + :param) * abs(length('ffobar')-3)) = 3.0");
+		}
+		if ( !( getDialect() instanceof MySQLDialect || getDialect() instanceof SybaseDialect ) ) {
+			assertTranslation("from Animal where lower(upper('foo') || upper(:bar)) like 'f%'");
+		}
+		if ( getDialect() instanceof PostgreSQLDialect ) {
+			return;
+		}
+		assertTranslation("from Animal where abs(cast(1 as float) - cast(:param as float)) = 1.0");
+	}
+
+	public void testCompositeKeysWithPropertyNamedId() {
+		assertTranslation( "select e.id.id from EntityWithCrazyCompositeKey e" );
+		assertTranslation( "select max(e.id.id) from EntityWithCrazyCompositeKey e" );
+	}
+
+	public void testMaxindexHqlFunctionInElementAccessorFailureExpected() {
+		//TODO: broken SQL
+		//      steve (2005.10.06) - this is perfect SQL, but fairly different from the old parser
+		//              tested : HSQLDB (1.8), Oracle8i
+		assertTranslation( "select c from ContainerX c where c.manyToMany[ maxindex(c.manyToMany) ].count = 2" );
+		assertTranslation( "select c from Container c where c.manyToMany[ maxIndex(c.manyToMany) ].count = 2" );
+	}
+
+	public void testMultipleElementAccessorOperatorsFailureExpected() throws Exception {
+		//TODO: broken SQL
+		//      steve (2005.10.06) - Yes, this is all hosed ;)
+		assertTranslation( "select c from ContainerX c where c.oneToMany[ c.manyToMany[0].count ].name = 's'" );
+		assertTranslation( "select c from ContainerX c where c.manyToMany[ c.oneToMany[0].count ].name = 's'" );
+	}
+
+	/*public void testSelectMaxElements() throws Exception {
+		//TODO: this is almost correct, but missing a select-clause column alias!
+		assertTranslation("select max( elements(one.manies) ) from org.hibernate.test.legacy.One one");
+	}*/
+
+	public void testKeyManyToOneJoinFailureExpected() {
+		//TODO: new parser generates unnecessary joins (though the query results are correct)
+		assertTranslation( "from Order o left join fetch o.lineItems li left join fetch li.product p" );
+		assertTranslation( "from Outer o where o.id.master.id.sup.dudu is not null" );
+		assertTranslation( "from Outer o where o.id.master.id.sup.dudu is not null" );
+	}
+
+	public void testDuplicateExplicitJoinFailureExpected() throws Exception {
+		//very minor issue with select clause:
+		assertTranslation( "from Animal a join a.mother m1 join a.mother m2" );
+		assertTranslation( "from Zoo zoo join zoo.animals an join zoo.mammals m" );
+		assertTranslation( "from Zoo zoo join zoo.mammals an join zoo.mammals m" );
+	}
+
+	// TESTS THAT FAIL ONLY ON DIALECTS WITH THETA-STYLE OUTERJOINS:
+
+	public void testIndexWithExplicitJoin() throws Exception {
+		//TODO: broken on dialects with theta-style outerjoins:
+		//      steve (2005.10.06) - this works perfectly for me on Oracle8i
+		assertTranslation( "from Zoo zoo join zoo.animals an where zoo.mammals[ index(an) ] = an" );
+		assertTranslation( "from Zoo zoo join zoo.mammals dog where zoo.mammals[ index(dog) ] = dog" );
+		assertTranslation( "from Zoo zoo join zoo.mammals dog where dog = zoo.mammals[ index(dog) ]" );
+	}
+
+	public void testOneToManyMapIndex() throws Exception {
+		//TODO: this breaks on dialects with theta-style outerjoins:
+		//      steve (2005.10.06) - this works perfectly for me on Oracle8i
+		assertTranslation( "from Zoo zoo where zoo.mammals['dog'].description like '%black%'" );
+		assertTranslation( "from Zoo zoo where zoo.mammals['dog'].father.description like '%black%'" );
+		assertTranslation( "from Zoo zoo where zoo.mammals['dog'].father.id = 1234" );
+		assertTranslation( "from Zoo zoo where zoo.animals['1234'].description like '%black%'" );
+	}
+
+	public void testExplicitJoinMapIndex() throws Exception {
+		//TODO: this breaks on dialects with theta-style outerjoins:
+		//      steve (2005.10.06) - this works perfectly for me on Oracle8i
+		assertTranslation( "from Zoo zoo, Dog dog where zoo.mammals['dog'] = dog" );
+		assertTranslation( "from Zoo zoo join zoo.mammals dog where zoo.mammals['dog'] = dog" );
+	}
+
+	public void testIndexFunction() throws Exception {
+		// Instead of doing the pre-processor trick like the existing QueryTranslator, this
+		// is handled by MethodNode.
+		//      steve (2005.10.06) - this works perfectly for me on Oracle8i
+		//TODO: broken on dialects with theta-style outerjoins:
+		assertTranslation( "from Zoo zoo join zoo.mammals dog where index(dog) = 'dog'" );
+		assertTranslation( "from Zoo zoo join zoo.animals an where index(an) = '1234'" );
+	}
+
+	public void testSelectCollectionOfValues() throws Exception {
+		//TODO: broken on dialects with theta-style joins
+		///old parser had a bug where the collection element was not included in return types!
+		//      steve (2005.10.06) - this works perfectly for me on Oracle8i
+		assertTranslation( "select baz, date from Baz baz join baz.stringDateMap date where index(date) = 'foo'" );
+	}
+
+	public void testCollectionOfValues() throws Exception {
+		//old parser had a bug where the collection element was not returned!
+		//TODO: broken on dialects with theta-style joins
+		//      steve (2005.10.06) - this works perfectly for me on Oracle8i
+		assertTranslation( "from Baz baz join baz.stringDateMap date where index(date) = 'foo'" );
+	}
+
+    public void testHHH719() throws Exception {
+        assertTranslation("from Baz b order by org.bazco.SpecialFunction(b.id)");
+        assertTranslation("from Baz b order by anypackage.anyFunction(b.id)");
+    }
+
+
+	//PASSING TESTS:
+
+	public void testParameterListExpansion() {
+		assertTranslation( "from Animal as animal where animal.id in (:idList_1, :idList_2)" );
+	}
+
+	public void testComponentManyToOneDereferenceShortcut() {
+		assertTranslation( "from Zoo z where z.address.stateProvince.id is null" );
+	}
+
+	public void testNestedCollectionImplicitJoins() {
+		// HHH-770
+		assertTranslation( "select h.friends.offspring from Human h" );
+	}
+
+	public void testExplicitJoinsInSubquery() {
+		// test for HHH-557,
+		// TODO : this passes regardless because the only difference between the two sqls is one extra comma
+		// (commas are eaten by the tokenizer during asserTranslation when building the token maps).
+		assertTranslation(
+		        "from org.hibernate.test.hql.Animal as animal " +
+		        "where animal.id in (" +
+		        "        select a.id " +
+		        "        from org.hibernate.test.hql.Animal as a " +
+		        "               left join a.mother as mo" +
+		        ")"
+		);
+	}
+
+	public void testImplicitJoinsInGroupBy() {
+		assertTranslation(
+		        "select o.mother.bodyWeight, count(distinct o) " +
+		        "from Animal an " +
+		        "   join an.offspring as o " +
+		        "group by o.mother.bodyWeight"
+		);
+	}
+
+	public void testCrazyIdFieldNames() {
+		DotNode.useThetaStyleImplicitJoins = true;
+		// only regress against non-scalar forms as there appears to be a bug in the classic translator
+		// in regards to this issue also.  Specifically, it interprets the wrong return type, though it gets
+		// the sql "correct" :/
+
+		String hql = "select e.heresAnotherCrazyIdFieldName from MoreCrazyIdFieldNameStuffEntity e where e.heresAnotherCrazyIdFieldName is not null";
+		assertTranslation( hql, new HashMap(), false, ( String ) null );
+
+	    hql = "select e.heresAnotherCrazyIdFieldName.heresAnotherCrazyIdFieldName from MoreCrazyIdFieldNameStuffEntity e where e.heresAnotherCrazyIdFieldName is not null";
+		assertTranslation( hql, new HashMap(), false, ( String ) null );
+
+		DotNode.useThetaStyleImplicitJoins = false;
+	}
+
+	public void testSizeFunctionAndProperty() {
+		assertTranslation("from Animal a where a.offspring.size > 0");
+		assertTranslation("from Animal a join a.offspring where a.offspring.size > 1");
+		assertTranslation("from Animal a where size(a.offspring) > 0");
+		assertTranslation("from Animal a join a.offspring o where size(a.offspring) > 1");
+		assertTranslation("from Animal a where size(a.offspring) > 1 and size(a.offspring) < 100");
+
+		assertTranslation("from Human a where a.family.size > 0");
+		assertTranslation("from Human a join a.family where a.family.size > 1");
+		assertTranslation("from Human a where size(a.family) > 0");
+		assertTranslation("from Human a join a.family o where size(a.family) > 1");
+		assertTranslation("from Human a where a.family.size > 0 and a.family.size < 100");
+}
+
+	// Do the simplest test first!
+	public void testFromOnly() throws Exception {
+		// 2004-06-21 [jsd] This test now works with the new AST based QueryTranslatorImpl.
+		assertTranslation( "from Animal" );
+		assertTranslation( "from Model" );
+	}
+
+	public void testJoinPathEndingInValueCollection() {
+		assertTranslation( "select h from Human as h join h.nickNames as nn where h.nickName=:nn1 and (nn=:nn2 or nn=:nn3)" );
+	}
+
+	public void testSerialJoinPathEndingInValueCollection() {
+		// HHH-242
+		assertTranslation( "select h from Human as h join h.friends as f join f.nickNames as nn where h.nickName=:nn1 and (nn=:nn2 or nn=:nn3)" );
+	}
+
+	public void testImplicitJoinContainedByCollectionFunction() {
+		// HHH-281 : Implied joins in a collection function (i.e., indices or elements)
+		assertTranslation( "from Human as h where 'shipping' in indices(h.father.addresses)" );
+		assertTranslation( "from Human as h where 'shipping' in indices(h.father.father.addresses)" );
+		assertTranslation( "from Human as h where 'sparky' in elements(h.father.nickNames)" );
+		assertTranslation( "from Human as h where 'sparky' in elements(h.father.father.nickNames)" );
+	}
+
+
+	public void testImpliedJoinInSubselectFrom() {
+		// HHH-276 : Implied joins in a from in a subselect.
+		assertTranslation( "from Animal a where exists( from a.mother.offspring )" );
+	}
+
+	public void testSubselectImplicitJoins() {
+		// HHH-276 : Implied joins in a from in a subselect.
+		assertTranslation( "from Simple s where s = some( select sim from Simple sim where sim.other.count=s.other.count )" );
+	}
+
+
+	public void testCollectionOfValuesSize() throws Exception {
+		//SQL *was* missing a comma
+		assertTranslation( "select size(baz.stringDateMap) from org.hibernate.test.legacy.Baz baz" );
+	}
+
+	public void testCollectionFunctions() throws Exception {
+		//these are both broken, a join that belongs in the subselect finds its way into the main query
+		assertTranslation( "from Zoo zoo where size(zoo.animals) > 100" );
+		assertTranslation( "from Zoo zoo where maxindex(zoo.mammals) = 'dog'" );
+	}
+
+	public void testImplicitJoinInExplicitJoin() throws Exception {
+		assertTranslation( "from Animal an inner join an.mother.mother gm" );
+		assertTranslation( "from Animal an inner join an.mother.mother.mother ggm" );
+		assertTranslation( "from Animal an inner join an.mother.mother.mother.mother gggm" );
+	}
+
+	public void testImpliedManyToManyProperty() throws Exception {
+		//missing a table join (SQL correct for a one-to-many, not for a many-to-many)
+		assertTranslation( "select c from ContainerX c where c.manyToMany[0].name = 's'" );
+	}
+
+	public void testCollectionSize() throws Exception {
+		//SQL is correct, query spaces *was* missing a table
+		assertTranslation( "select size(zoo.animals) from Zoo zoo" );
+	}
+
+	/*public void testCollectionIndexFunctionsInSelect() throws Exception {
+		assertTranslation("select maxindex(zoo.animals) from Zoo zoo");
+		assertTranslation("select minindex(zoo.animals) from Zoo zoo");
+		assertTranslation("select indices(zoo.animals) from Zoo zoo");
+	}
+
+	public void testCollectionElementFunctionsInSelect() throws Exception {
+		assertTranslation("select maxelement(zoo.animals) from Zoo zoo");
+		assertTranslation("select minelement(zoo.animals) from Zoo zoo");
+		assertTranslation("select elements(zoo.animals) from Zoo zoo");
+	}*/
+
+	public void testFetchCollectionOfValues() throws Exception {
+		assertTranslation( "from Baz baz left join fetch baz.stringSet" );
+	}
+
+	public void testFetchList() throws Exception {
+		assertTranslation( "from User u join fetch u.permissions" );
+	}
+
+	public void testCollectionFetchWithExplicitThetaJoin() {
+		assertTranslation( "select m from Master m1, Master m left join fetch m.details where m.name=m1.name" );
+	}
+
+	/*public void testListElementFunctionInSelect() throws Exception {
+		//wrong pk column in select clause! (easy fix?)
+		assertTranslation("select maxelement(u.permissions) from User u");
+		assertTranslation("select elements(u.permissions) from User u");
+	}*/
+
+	public void testListElementFunctionInWhere() throws Exception {
+		assertTranslation( "from User u where 'read' in elements(u.permissions)" );
+		assertTranslation( "from User u where 'write' <> all elements(u.permissions)" );
+	}
+
+	/*public void testManyToManyElementFunctionInSelect() throws Exception {
+		assertTranslation("select maxelement(human.friends) from Human human");
+		assertTranslation("select elements(human.friends) from Human human");
+	}*/
+
+	public void testManyToManyMaxElementFunctionInWhere() throws Exception {
+		//completely broken!!
+		assertTranslation( "from Human human where 5 = maxelement(human.friends)" );
+	}
+
+	public void testCollectionIndexFunctionsInWhere() throws Exception {
+		assertTranslation( "from Zoo zoo where 4 = maxindex(zoo.animals)" );
+		assertTranslation( "from Zoo zoo where 2 = minindex(zoo.animals)" );
+	}
+
+	public void testCollectionIndicesInWhere() throws Exception {
+		assertTranslation( "from Zoo zoo where 4 > some indices(zoo.animals)" );
+		assertTranslation( "from Zoo zoo where 4 > all indices(zoo.animals)" );
+	}
+
+	public void testIndicesInWhere() throws Exception {
+		assertTranslation( "from Zoo zoo where 4 in indices(zoo.animals)" );
+		assertTranslation( "from Zoo zoo where exists indices(zoo.animals)" );
+	}
+
+	public void testCollectionElementInWhere() throws Exception {
+		assertTranslation( "from Zoo zoo where 4 > some elements(zoo.animals)" );
+		assertTranslation( "from Zoo zoo where 4 > all elements(zoo.animals)" );
+	}
+
+	public void testElementsInWhere() throws Exception {
+		assertTranslation( "from Zoo zoo where 4 in elements(zoo.animals)" );
+		assertTranslation( "from Zoo zoo where exists elements(zoo.animals)" );
+	}
+
+	public void testNull() throws Exception {
+		assertTranslation( "from Human h where h.nickName is null" );
+		assertTranslation( "from Human h where h.nickName is not null" );
+	}
+
+	public void testSubstitutions() throws Exception {
+		Map replacements = buildTrueFalseReplacementMapForDialect();
+		replacements.put("yes", "'Y'");
+		assertTranslation( "from Human h where h.pregnant = true", replacements );
+		assertTranslation( "from Human h where h.pregnant = yes", replacements );
+		assertTranslation( "from Human h where h.pregnant = foo", replacements );
+	}
+
+	public void testWhere() throws Exception {
+		assertTranslation( "from Animal an where an.bodyWeight > 10" );
+		// 2004-06-26 [jsd] This one requires NOT GT => LE transform.
+		assertTranslation( "from Animal an where not an.bodyWeight > 10" );
+		assertTranslation( "from Animal an where an.bodyWeight between 0 and 10" );
+		assertTranslation( "from Animal an where an.bodyWeight not between 0 and 10" );
+		assertTranslation( "from Animal an where sqrt(an.bodyWeight)/2 > 10" );
+		// 2004-06-27 [jsd] Recognize 'is null' properly.  Generate 'and' and 'or' as well.
+		assertTranslation( "from Animal an where (an.bodyWeight > 10 and an.bodyWeight < 100) or an.bodyWeight is null" );
+	}
+
+	public void testEscapedQuote() throws Exception {
+		assertTranslation( "from Human h where h.nickName='1 ov''tha''few'");
+	}
+
+	public void testCaseWhenElse() {
+		assertTranslation( "from Human h where case when h.nickName='1ovthafew' then 'Gavin' when h.nickName='turin' then 'Christian' else h.nickName end = h.name.first" );
+	}
+
+	public void testCaseExprWhenElse() {
+		assertTranslation( "from Human h where case h.nickName when '1ovthafew' then 'Gavin' when 'turin' then 'Christian' else h.nickName end = h.name.first" );
+	}
+
+	public void testInvalidHql() throws Exception {
+		Exception newException = compileBadHql( "from Animal foo where an.bodyWeight > 10", false );
+		assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException );
+		newException = compileBadHql( "select an.name from Animal foo", false );
+		assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException );
+		newException = compileBadHql( "from Animal foo where an.verybogus > 10", false );
+		assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException );
+		newException = compileBadHql( "select an.boguspropertyname from Animal foo", false );
+		assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException );
+		newException = compileBadHql( "select an.name", false );
+		assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException );
+		newException = compileBadHql( "from Animal an where (((an.bodyWeight > 10 and an.bodyWeight < 100)) or an.bodyWeight is null", false );
+		assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException );
+		newException = compileBadHql( "from Animal an where an.bodyWeight is null where an.bodyWeight is null", false );
+		assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException );
+		newException = compileBadHql( "from where name='foo'", false );
+		assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException );
+		newException = compileBadHql( "from NonexistentClass where name='foo'", false );
+		assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException );
+		newException = compileBadHql( "select new FOO_BOGUS_Animal(an.description, an.bodyWeight) from Animal an", false );
+		assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException );
+		newException = compileBadHql( "select new Animal(an.description, an.bodyWeight, 666) from Animal an", false );
+		assertTrue( "Wrong exception type!", newException instanceof QuerySyntaxException );
+
+	}
+
+	public void testWhereBetween() throws Exception {
+		// 2004-08-31 [jsd] This "just worked"! Woohoo!
+		assertTranslation( "from Animal an where an.bodyWeight between 1 and 10" );
+	}
+
+	public void testConcatenation() {
+		if ( getDialect() instanceof MySQLDialect || getDialect() instanceof SybaseDialect ) {
+			// MySQL uses concat(x, y, z)
+			// SQL Server replaces '||' with '+'
+			//
+			// this is syntax checked in {@link ASTParserLoadingTest#testConcatenation} 
+			return;
+		}
+		assertTranslation("from Human h where h.nickName = '1' || 'ov' || 'tha' || 'few'");
+	}
+
+	public void testWhereLike() throws Exception {
+		assertTranslation( "from Animal a where a.description like '%black%'" );
+		assertTranslation( "from Animal an where an.description like '%fat%'" );
+		assertTranslation( "from Animal an where lower(an.description) like '%fat%'" );
+	}
+
+	public void testWhereIn() throws Exception {
+		assertTranslation( "from Animal an where an.description in ('fat', 'skinny')" );
+	}
+
+	public void testLiteralInFunction() throws Exception {
+		assertTranslation( "from Animal an where an.bodyWeight > abs(5)" );
+		assertTranslation( "from Animal an where an.bodyWeight > abs(-5)" );
+	}
+
+	public void testExpressionInFunction() throws Exception {
+		assertTranslation( "from Animal an where an.bodyWeight > abs(3-5)" );
+		assertTranslation( "from Animal an where an.bodyWeight > abs(3/5)" );
+		assertTranslation( "from Animal an where an.bodyWeight > abs(3+5)" );
+		assertTranslation( "from Animal an where an.bodyWeight > abs(3*5)" );
+		SQLFunction concat = getSessionFactoryImplementor().getSqlFunctionRegistry().findSQLFunction( "concat");
+		List list = new ArrayList(); list.add("'fat'"); list.add("'skinny'");
+		assertTranslation( "from Animal an where an.description = " + concat.render(list, getSessionFactoryImplementor()) );
+	}
+
+	public void testNotOrWhereClause() {
+		assertTranslation( "from Simple s where 'foo'='bar' or not 'foo'='foo'" );
+		assertTranslation( "from Simple s where 'foo'='bar' or not ('foo'='foo')" );
+		assertTranslation( "from Simple s where not ( 'foo'='bar' or 'foo'='foo' )" );
+		assertTranslation( "from Simple s where not ( 'foo'='bar' and 'foo'='foo' )" );
+		assertTranslation( "from Simple s where not ( 'foo'='bar' and 'foo'='foo' ) or not ('x'='y')" );
+		assertTranslation( "from Simple s where not ( 'foo'='bar' or 'foo'='foo' ) and not ('x'='y')" );
+		assertTranslation( "from Simple s where not ( 'foo'='bar' or 'foo'='foo' ) and 'x'='y'" );
+		assertTranslation( "from Simple s where not ( 'foo'='bar' and 'foo'='foo' ) or 'x'='y'" );
+		assertTranslation( "from Simple s where 'foo'='bar' and 'foo'='foo' or not 'x'='y'" );
+		assertTranslation( "from Simple s where 'foo'='bar' or 'foo'='foo' and not 'x'='y'" );
+		assertTranslation( "from Simple s where ('foo'='bar' and 'foo'='foo') or 'x'='y'" );
+		assertTranslation( "from Simple s where ('foo'='bar' or 'foo'='foo') and 'x'='y'" );
+		assertTranslation( "from Simple s where not( upper( s.name ) ='yada' or 1=2 or 'foo'='bar' or not('foo'='foo') or 'foo' like 'bar' )" );
+	}
+
+	public void testComplexExpressionInFunction() throws Exception {
+		assertTranslation( "from Animal an where an.bodyWeight > abs((3-5)/4)" );
+	}
+
+	public void testStandardFunctions() throws Exception {
+		assertTranslation( "from Animal where current_date = current_time" );
+		assertTranslation( "from Animal a where upper(a.description) = 'FAT'" );
+		assertTranslation( "select lower(a.description) from Animal a" );
+	}
+
+	public void testOrderBy() throws Exception {
+		assertTranslation( "from Animal an order by an.bodyWeight" );
+		assertTranslation( "from Animal an order by an.bodyWeight asc" );
+		assertTranslation( "from Animal an order by an.bodyWeight desc" );
+		assertTranslation( "from Animal an order by sqrt(an.bodyWeight*4)/2" );
+		assertTranslation( "from Animal an order by an.mother.bodyWeight" );
+		assertTranslation( "from Animal an order by an.bodyWeight, an.description" );
+		assertTranslation( "from Animal an order by an.bodyWeight asc, an.description desc" );
+		if ( getDialect() instanceof HSQLDialect || getDialect() instanceof DB2Dialect ) {
+			assertTranslation( "from Human h order by sqrt(h.bodyWeight), year(h.birthdate)" );
+		}
+	}
+
+	public void testGroupByFunction() {
+		if ( getDialect() instanceof Oracle9Dialect ) return;
+		if ( getDialect() instanceof PostgreSQLDialect ) return;
+		assertTranslation( "select count(*) from Human h group by year(h.birthdate)" );
+		assertTranslation( "select count(*) from Human h group by trunc( sqrt(h.bodyWeight*4)/2 )" );
+		assertTranslation( "select count(*) from Human h group by year(sysdate)" );
+	}
+
+
+	public void testPolymorphism() throws Exception {
+		Map replacements = buildTrueFalseReplacementMapForDialect();
+		assertTranslation( "from Mammal" );
+		assertTranslation( "from Dog" );
+		assertTranslation( "from Mammal m where m.pregnant = false and m.bodyWeight > 10", replacements );
+		assertTranslation( "from Dog d where d.pregnant = false and d.bodyWeight > 10", replacements );
+	}
+
+	private Map buildTrueFalseReplacementMapForDialect() {
+		HashMap replacements = new HashMap();
+		try {
+			String dialectTrueRepresentation = getDialect().toBooleanValueString( true );
+			// if this call succeeds, then the dialect is saying to represent true/false as int values...
+			Integer.parseInt( dialectTrueRepresentation );
+			replacements.put( "true", "1" );
+			replacements.put( "false", "0" );
+		}
+		catch( NumberFormatException nfe ) {
+			// the Integer#parseInt call failed...
+		}
+		return replacements;
+	}
+
+	public void testTokenReplacement() throws Exception {
+		Map replacements = buildTrueFalseReplacementMapForDialect();
+		assertTranslation( "from Mammal m where m.pregnant = false and m.bodyWeight > 10", replacements );
+	}
+
+	public void testProduct() throws Exception {
+		Map replacements = buildTrueFalseReplacementMapForDialect();
+		assertTranslation( "from Animal, Animal" );
+		assertTranslation( "from Animal x, Animal y where x.bodyWeight = y.bodyWeight" );
+		assertTranslation( "from Animal x, Mammal y where x.bodyWeight = y.bodyWeight and not y.pregnant = true", replacements );
+		assertTranslation( "from Mammal, Mammal" );
+	}
+
+	public void testJoinedSubclassProduct() throws Exception {
+		assertTranslation( "from PettingZoo, PettingZoo" ); //product of two subclasses
+	}
+
+	public void testProjectProduct() throws Exception {
+		assertTranslation( "select x from Human x, Human y where x.nickName = y.nickName" );
+		assertTranslation( "select x, y from Human x, Human y where x.nickName = y.nickName" );
+	}
+
+	public void testExplicitEntityJoins() throws Exception {
+		assertTranslation( "from Animal an inner join an.mother mo" );
+		assertTranslation( "from Animal an left outer join an.mother mo" );
+		assertTranslation( "from Animal an left outer join fetch an.mother" );
+	}
+
+	public void testMultipleExplicitEntityJoins() throws Exception {
+		assertTranslation( "from Animal an inner join an.mother mo inner join mo.mother gm" );
+		assertTranslation( "from Animal an left outer join an.mother mo left outer join mo.mother gm" );
+		assertTranslation( "from Animal an inner join an.mother m inner join an.father f" );
+		assertTranslation( "from Animal an left join fetch an.mother m left join fetch an.father f" );
+	}
+
+	public void testMultipleExplicitJoins() throws Exception {
+		assertTranslation( "from Animal an inner join an.mother mo inner join an.offspring os" );
+		assertTranslation( "from Animal an left outer join an.mother mo left outer join an.offspring os" );
+	}
+
+	public void testExplicitEntityJoinsWithRestriction() throws Exception {
+		assertTranslation( "from Animal an inner join an.mother mo where an.bodyWeight < mo.bodyWeight" );
+	}
+
+	public void testIdProperty() throws Exception {
+		assertTranslation( "from Animal a where a.mother.id = 12" );
+	}
+
+	public void testSubclassAssociation() throws Exception {
+		assertTranslation( "from DomesticAnimal da join da.owner o where o.nickName = 'Gavin'" );
+		assertTranslation( "from DomesticAnimal da left join fetch da.owner" );
+		assertTranslation( "from Human h join h.pets p where p.pregnant = 1" );
+		assertTranslation( "from Human h join h.pets p where p.bodyWeight > 100" );
+		assertTranslation( "from Human h left join fetch h.pets" );
+	}
+
+	public void testExplicitCollectionJoins() throws Exception {
+		assertTranslation( "from Animal an inner join an.offspring os" );
+		assertTranslation( "from Animal an left outer join an.offspring os" );
+	}
+
+	public void testExplicitOuterJoinFetch() throws Exception {
+		assertTranslation( "from Animal an left outer join fetch an.offspring" );
+	}
+
+	public void testExplicitOuterJoinFetchWithSelect() throws Exception {
+		assertTranslation( "select an from Animal an left outer join fetch an.offspring" );
+	}
+
+	public void testExplicitJoins() throws Exception {
+		Map replacements = buildTrueFalseReplacementMapForDialect();
+		assertTranslation( "from Zoo zoo join zoo.mammals mam where mam.pregnant = true and mam.description like '%white%'", replacements );
+		assertTranslation( "from Zoo zoo join zoo.animals an where an.description like '%white%'" );
+	}
+
+    /**
+     * Test for HHH-559
+     */
+    public void testMultibyteCharacterConstant() throws Exception {
+        assertTranslation( "from Zoo zoo join zoo.animals an where an.description like '%\u4e2d%'" );
+    }
+
+	public void testImplicitJoins() throws Exception {
+		// Two dots...
+		assertTranslation( "from Animal an where an.mother.bodyWeight > ?" );
+		assertTranslation( "from Animal an where an.mother.bodyWeight > 10" );
+		assertTranslation( "from Dog dog where dog.mother.bodyWeight > 10" );
+		// Three dots...
+		assertTranslation( "from Animal an where an.mother.mother.bodyWeight > 10" );
+		// The new QT doesn't throw an exception here, so this belongs in ASTQueryTranslator test. [jsd]
+//		assertTranslation( "from Animal an where an.offspring.mother.bodyWeight > 10" );
+		// Is not null (unary postfix operator)
+		assertTranslation( "from Animal an where an.mother is not null" );
+		// ID property shortut (no implicit join)
+		assertTranslation( "from Animal an where an.mother.id = 123" );
+	}
+
+	public void testImplicitJoinInSelect() {
+		assertTranslation( "select foo, foo.long from Foo foo" );
+		DotNode.useThetaStyleImplicitJoins = true;
+		assertTranslation( "select foo.foo from Foo foo" );
+		assertTranslation( "select foo, foo.foo from Foo foo" );
+		assertTranslation( "select foo.foo from Foo foo where foo.foo is not null" );
+		DotNode.useThetaStyleImplicitJoins = false;
+	}
+
+	public void testSelectExpressions() {
+		DotNode.useThetaStyleImplicitJoins = true;
+		assertTranslation( "select an.mother.mother from Animal an" );
+		assertTranslation( "select an.mother.mother.mother from Animal an" );
+		assertTranslation( "select an.mother.mother.bodyWeight from Animal an" );
+		assertTranslation( "select an.mother.zoo.id from Animal an" );
+		assertTranslation( "select user.human.zoo.id from User user" );
+		assertTranslation( "select u.userName, u.human.name.first from User u" );
+		assertTranslation( "select u.human.name.last, u.human.name.first from User u" );
+		assertTranslation( "select bar.baz.name from Bar bar" );
+		assertTranslation( "select bar.baz.name, bar.baz.count from Bar bar" );
+		DotNode.useThetaStyleImplicitJoins = false;
+	}
+
+	public void testSelectStandardFunctionsNoParens() throws Exception {
+		assertTranslation( "select current_date, current_time, current_timestamp from Animal" );
+	}
+
+	public void testMapIndex() throws Exception {
+		assertTranslation( "from User u where u.permissions['hibernate']='read'" );
+	}
+
+	/*public void testCollectionFunctionsInSelect() {
+		//sql is correct, just different order in select clause
+		assertTranslation("select baz, size(baz.stringSet), count( distinct elements(baz.stringSet) ), max( elements(baz.stringSet) ) from Baz baz group by baz");
+	}
+
+	public void testSelectElements() throws Exception {
+		assertTranslation( "select elements(fum1.friends) from org.hibernate.test.legacy.Fum fum1" );
+		assertTranslation( "select elements(one.manies) from org.hibernate.test.legacy.One one" );
+	}*/
+
+	public void testNamedParameters() throws Exception {
+		assertTranslation( "from Animal an where an.mother.bodyWeight > :weight" );
+	}
+
+	// Second set of examples....
+
+	public void testClassProperty() throws Exception {
+		assertTranslation( "from Animal a where a.mother.class = Reptile" );
+	}
+
+	public void testComponent() throws Exception {
+		assertTranslation( "from Human h where h.name.first = 'Gavin'" );
+	}
+
+	public void testSelectEntity() throws Exception {
+		assertTranslation( "select an from Animal an inner join an.mother mo where an.bodyWeight < mo.bodyWeight" );
+		assertTranslation( "select mo, an from Animal an inner join an.mother mo where an.bodyWeight < mo.bodyWeight" );
+	}
+
+	public void testValueAggregate() {
+		assertTranslation( "select max(p), min(p) from User u join u.permissions p" );
+	}
+
+	public void testAggregation() throws Exception {
+		assertTranslation( "select count(an) from Animal an" );
+		assertTranslation( "select count(*) from Animal an" );
+		assertTranslation( "select count(distinct an) from Animal an" );
+		assertTranslation( "select count(distinct an.id) from Animal an" );
+		assertTranslation( "select count(all an.id) from Animal an" );
+	}
+
+	public void testSelectProperty() throws Exception {
+		assertTranslation( "select an.bodyWeight, mo.bodyWeight from Animal an inner join an.mother mo where an.bodyWeight < mo.bodyWeight" );
+	}
+
+	public void testSelectEntityProperty() throws Exception {
+		DotNode.useThetaStyleImplicitJoins = true;
+		assertTranslation( "select an.mother from Animal an" );
+		assertTranslation( "select an, an.mother from Animal an" );
+		DotNode.useThetaStyleImplicitJoins = false;
+	}
+
+	public void testSelectDistinctAll() throws Exception {
+		assertTranslation( "select distinct an.description, an.bodyWeight from Animal an" );
+		assertTranslation( "select all an from Animal an" );
+	}
+
+	public void testSelectAssociatedEntityId() throws Exception {
+		assertTranslation( "select an.mother.id from Animal an" );
+	}
+
+	public void testGroupBy() throws Exception {
+		assertTranslation( "select an.mother.id, max(an.bodyWeight) from Animal an group by an.mother.id" );
+		assertTranslation( "select an.mother.id, max(an.bodyWeight) from Animal an group by an.mother.id having max(an.bodyWeight)>1.0" );
+	}
+
+	public void testGroupByMultiple() throws Exception {
+		assertTranslation( "select s.id, s.count, count(t), max(t.date) from org.hibernate.test.legacy.Simple s, org.hibernate.test.legacy.Simple t where s.count = t.count group by s.id, s.count order by s.count" );
+	}
+
+	public void testManyToMany() throws Exception {
+		assertTranslation( "from Human h join h.friends f where f.nickName = 'Gavin'" );
+		assertTranslation( "from Human h join h.friends f where f.bodyWeight > 100" );
+	}
+
+	public void testManyToManyElementFunctionInWhere() throws Exception {
+		assertTranslation( "from Human human where human in elements(human.friends)" );
+		assertTranslation( "from Human human where human = some elements(human.friends)" );
+	}
+
+	public void testManyToManyElementFunctionInWhere2() throws Exception {
+		assertTranslation( "from Human h1, Human h2 where h2 in elements(h1.family)" );
+		assertTranslation( "from Human h1, Human h2 where 'father' in indices(h1.family)" );
+	}
+
+	public void testManyToManyFetch() throws Exception {
+		assertTranslation( "from Human h left join fetch h.friends" );
+	}
+
+	public void testManyToManyIndexAccessor() throws Exception {
+		// From ParentChildTest.testCollectionQuery()
+		assertTranslation( "select c from ContainerX c, Simple s where c.manyToMany[2] = s" );
+		assertTranslation( "select s from ContainerX c, Simple s where c.manyToMany[2] = s" );
+		assertTranslation( "from ContainerX c, Simple s where c.manyToMany[2] = s" );
+		//would be nice to have:
+		//assertTranslation( "select c.manyToMany[2] from ContainerX c" );
+	}
+
+	public void testSelectNew() throws Exception {
+		assertTranslation( "select new Animal(an.description, an.bodyWeight) from Animal an" );
+		assertTranslation( "select new org.hibernate.test.hql.Animal(an.description, an.bodyWeight) from Animal an" );
+	}
+
+	public void testSimpleCorrelatedSubselect() throws Exception {
+		assertTranslation( "from Animal a where a.bodyWeight = (select o.bodyWeight from a.offspring o)" );
+		assertTranslation( "from Animal a where a = (from a.offspring o)" );
+	}
+
+	public void testSimpleUncorrelatedSubselect() throws Exception {
+		assertTranslation( "from Animal a where a.bodyWeight = (select an.bodyWeight from Animal an)" );
+		assertTranslation( "from Animal a where a = (from Animal an)" );
+	}
+
+	public void testSimpleCorrelatedSubselect2() throws Exception {
+		assertTranslation( "from Animal a where a = (select o from a.offspring o)" );
+		assertTranslation( "from Animal a where a in (select o from a.offspring o)" );
+	}
+
+	public void testSimpleUncorrelatedSubselect2() throws Exception {
+		assertTranslation( "from Animal a where a = (select an from Animal an)" );
+		assertTranslation( "from Animal a where a in (select an from Animal an)" );
+	}
+
+	public void testUncorrelatedSubselect2() throws Exception {
+		assertTranslation( "from Animal a where a.bodyWeight = (select max(an.bodyWeight) from Animal an)" );
+	}
+
+	public void testCorrelatedSubselect2() throws Exception {
+		assertTranslation( "from Animal a where a.bodyWeight > (select max(o.bodyWeight) from a.offspring o)" );
+	}
+
+	public void testManyToManyJoinInSubselect() throws Exception {
+		DotNode.useThetaStyleImplicitJoins = true;
+		assertTranslation( "select foo from Foo foo where foo in (select elt from Baz baz join baz.fooArray elt)" );
+		DotNode.useThetaStyleImplicitJoins = false;
+	}
+
+	public void testImplicitJoinInSubselect() throws Exception {
+		assertTranslation( "from Animal a where a = (select an.mother from Animal an)" );
+		assertTranslation( "from Animal a where a.id = (select an.mother.id from Animal an)" );
+	}
+
+	public void testManyToOneSubselect() {
+		//TODO: the join in the subselect also shows up in the outer query!
+		assertTranslation( "from Animal a where 'foo' in (select m.description from a.mother m)" );
+	}
+
+	public void testPositionalParameters() throws Exception {
+		assertTranslation( "from Animal an where an.bodyWeight > ?" );
+	}
+
+	public void testKeywordPropertyName() throws Exception {
+		assertTranslation( "from Glarch g order by g.order asc" );
+		assertTranslation( "select g.order from Glarch g where g.order = 3" );
+	}
+
+	public void testJavaConstant() throws Exception {
+		assertTranslation( "from org.hibernate.test.legacy.Category c where c.name = org.hibernate.test.legacy.Category.ROOT_CATEGORY" );
+		assertTranslation( "from org.hibernate.test.legacy.Category c where c.id = org.hibernate.test.legacy.Category.ROOT_ID" );
+		// todo : additional desired functionality
+		//assertTranslation( "from Category c where c.name = Category.ROOT_CATEGORY" );
+		//assertTranslation( "select c.name, Category.ROOT_ID from Category as c");
+	}
+
+	public void testClassName() throws Exception {
+		// The Zoo reference is OK; Zoo is discriminator-based;
+		// the old parser could handle these correctly
+		//
+		// However, the Animal one ares not; Animal is joined subclassing;
+		// the old parser does not handle thee correctly.  The new parser
+		// previously did not handle them correctly in that same way.  So they
+		// used to pass regression even though the output was bogus SQL...
+		//
+		// I have moved the Animal ones (plus duplicating the Zoo one)
+		// to ASTParserLoadingTest for syntax checking.
+		assertTranslation( "from Zoo zoo where zoo.class = PettingZoo" );
+//		assertTranslation( "from DomesticAnimal an where an.class = Dog" );
+//		assertTranslation( "from Animal an where an.class = Dog" );
+	}
+
+	public void testSelectDialectFunction() throws Exception {
+		// From SQLFunctionsTest.testDialectSQLFunctions...
+		if ( getDialect() instanceof HSQLDialect ) {
+			assertTranslation( "select mod(s.count, 2) from org.hibernate.test.legacy.Simple as s where s.id = 10" );
+			//assertTranslation( "from org.hibernate.test.legacy.Simple as s where mod(s.count, 2) = 0" );
+		}
+		assertTranslation( "select upper(human.name.first) from Human human" );
+		assertTranslation( "from Human human where lower(human.name.first) like 'gav%'" );
+		assertTranslation( "select upper(a.description) from Animal a" );
+		assertTranslation( "select max(a.bodyWeight) from Animal a" );
+	}
+
+	public void testTwoJoins() throws Exception {
+		assertTranslation( "from Human human join human.friends, Human h join h.mother" );
+		assertTranslation( "from Human human join human.friends f, Animal an join an.mother m where f=m" );
+		assertTranslation( "from Baz baz left join baz.fooToGlarch, Bar bar join bar.foo" );
+	}
+
+	public void testToOneToManyManyJoinSequence() throws Exception {
+		assertTranslation( "from Dog d join d.owner h join h.friends f where f.name.first like 'joe%'" );
+	}
+
+	public void testToOneToManyJoinSequence() throws Exception {
+		assertTranslation( "from Animal a join a.mother m join m.offspring" );
+		assertTranslation( "from Dog d join d.owner m join m.offspring" );
+		assertTranslation( "from Animal a join a.mother m join m.offspring o where o.bodyWeight > a.bodyWeight" );
+	}
+
+	public void testSubclassExplicitJoin() throws Exception {
+		assertTranslation( "from DomesticAnimal da join da.owner o where o.nickName = 'gavin'" );
+		assertTranslation( "from DomesticAnimal da join da.owner o where o.bodyWeight > 0" );
+	}
+
+	public void testMultipleExplicitCollectionJoins() throws Exception {
+		assertTranslation( "from Animal an inner join an.offspring os join os.offspring gc" );
+		assertTranslation( "from Animal an left outer join an.offspring os left outer join os.offspring gc" );
+	}
+
+	public void testSelectDistinctComposite() throws Exception {
+		// This is from CompositeElementTest.testHandSQL.
+		assertTranslation( "select distinct p from org.hibernate.test.compositeelement.Parent p join p.children c where c.name like 'Child%'" );
+	}
+
+	public void testDotComponent() throws Exception {
+		// from FumTest.testListIdentifiers()
+		assertTranslation( "select fum.id from org.hibernate.test.legacy.Fum as fum where not fum.fum='FRIEND'" );
+	}
+
+	public void testOrderByCount() throws Exception {
+		assertTranslation( "from Animal an group by an.zoo.id order by an.zoo.id, count(*)" );
+	}
+
+	public void testHavingCount() throws Exception {
+		assertTranslation( "from Animal an group by an.zoo.id having count(an.zoo.id) > 1" );
+	}
+
+	public void selectWhereElements() throws Exception {
+		assertTranslation( "select foo from Foo foo, Baz baz where foo in elements(baz.fooArray)" );
+	}
+
+	public void testCollectionOfComponents() throws Exception {
+		assertTranslation( "from Baz baz inner join baz.components comp where comp.name='foo'" );
+	}
+
+	public void testNestedComponentIsNull() {
+		// From MapTest...
+		assertTranslation( "from Commento c where c.marelo.commento.mcompr is null" );
+	}
+
+	public void testOneToOneJoinedFetch() throws Exception {
+		// From OneToOneTest.testOneToOneOnSubclass
+		assertTranslation( "from org.hibernate.test.onetoone.joined.Person p join fetch p.address left join fetch p.mailingAddress" );
+	}
+
+	public void testSubclassImplicitJoin() throws Exception {
+		assertTranslation( "from DomesticAnimal da where da.owner.nickName like 'Gavin%'" );
+		assertTranslation( "from DomesticAnimal da where da.owner.nickName = 'gavin'" );
+		assertTranslation( "from DomesticAnimal da where da.owner.bodyWeight > 0" );
+	}
+
+	public void testComponent2() throws Exception {
+		assertTranslation( "from Dog dog where dog.owner.name.first = 'Gavin'" );
+	}
+
+	public void testOneToOne() throws Exception {
+		assertTranslation( "from User u where u.human.nickName='Steve'" );
+		assertTranslation( "from User u where u.human.name.first='Steve'" );
+	}
+
+	public void testSelectClauseImplicitJoin() throws Exception {
+		//assertTranslation( "select d.owner.mother from Dog d" ); //bug in old qt
+		assertTranslation( "select d.owner.mother.description from Dog d" );
+		//assertTranslation( "select d.owner.mother from Dog d, Dog h" );
+	}
+
+	public void testFromClauseImplicitJoin() throws Exception {
+		assertTranslation( "from DomesticAnimal da join da.owner.mother m where m.bodyWeight > 10" );
+	}
+
+	public void testJoinedSubclassWithOrCondition() {
+		assertTranslation( "from Animal an where (an.bodyWeight > 10 and an.bodyWeight < 100) or an.bodyWeight is null" );
+	}
+
+	public void testImplicitJoinInFrom() {
+		assertTranslation( "from Human h join h.mother.mother.offspring o" );
+	}
+
+	public void testDuplicateImplicitJoinInSelect() {
+		// This test causes failures on theta-join dialects because the SQL is different.  The old parser
+		// duplicates the condition, whereas the new parser does not.  The queries are semantically the
+		// same however.
+		assertTranslation( "select an.mother.bodyWeight from Animal an join an.mother m where an.mother.bodyWeight > 10" );
+		assertTranslation( "select an.mother.bodyWeight from Animal an where an.mother.bodyWeight > 10" );
+		//assertTranslation("select an.mother from Animal an where an.mother.bodyWeight is not null");
+		assertTranslation( "select an.mother.bodyWeight from Animal an order by an.mother.bodyWeight" );
+	}
+
+	public void testConstructorNode() throws Exception {
+		ConstructorNode n = new ConstructorNode();
+		assertNull( n.getFromElement() );
+		assertFalse( n.isReturnableEntity() );
+	}
+
+	public void testIndexNode() throws Exception {
+		IndexNode n = new IndexNode();
+		Exception ex = null;
+		try {
+			n.setScalarColumnText( 0 );
+		}
+		catch ( UnsupportedOperationException e ) {
+			ex = e;
+		}
+		assertNotNull( ex );
+	}
+
+	public void testExceptions() throws Exception {
+		DetailedSemanticException dse = new DetailedSemanticException( "test" );
+		dse.printStackTrace();
+		dse.printStackTrace( new PrintWriter( new StringWriter() ) );
+		QuerySyntaxException qse = QuerySyntaxException.convert( new RecognitionException( "test" ), "from bozo b where b.clown = true" );
+		assertNotNull( qse.getMessage() );
+	}
+
+	public void testSelectProperty2() throws Exception {
+		assertTranslation( "select an, mo.bodyWeight from Animal an inner join an.mother mo where an.bodyWeight < mo.bodyWeight" );
+		assertTranslation( "select an, mo, an.bodyWeight, mo.bodyWeight from Animal an inner join an.mother mo where an.bodyWeight < mo.bodyWeight" );
+	}
+
+	public void testSubclassWhere() throws Exception {
+		// TODO: The classic QT generates lots of extra parens, etc.
+		assertTranslation( "from PettingZoo pz1, PettingZoo pz2 where pz1.id = pz2.id" );
+		assertTranslation( "from PettingZoo pz1, PettingZoo pz2 where pz1.id = pz2" );
+		assertTranslation( "from PettingZoo pz where pz.id > 0 " );
+	}
+
+	public void testNestedImplicitJoinsInSelect() throws Exception {
+		// NOTE: This test is not likely to generate the exact SQL because of the where clause.  The synthetic
+		// theta style joins come out differently in the new QT.
+		// From FooBarTest.testQuery()
+		// Missing the foo2_ join, and foo3_ should include subclasses, but it doesn't.
+//		assertTranslation("select foo.foo.foo.foo.string from org.hibernate.test.legacy.Foo foo where foo.foo.foo = 'bar'");
+		assertTranslation( "select foo.foo.foo.foo.string from org.hibernate.test.legacy.Foo foo" );
+	}
+
+	public void testNestedComponent() throws Exception {
+		// From FooBarTest.testQuery()
+		//an extra set of parens in new SQL
+		assertTranslation( "from org.hibernate.test.legacy.Foo foo where foo.component.subcomponent.name='bar'" );
+	}
+
+	public void testNull2() throws Exception {
+		//old parser generates useless extra parens
+		assertTranslation( "from Human h where not( h.nickName is null )" );
+		assertTranslation( "from Human h where not( h.nickName is not null )" );
+	}
+
+	public void testUnknownFailureFromMultiTableTest() {
+		assertTranslation( "from Lower s where s.yetanother.name='name'" );
+	}
+
+	public void testJoinInSubselect() throws Exception {
+		//new parser uses ANSI-style inner join syntax
+		DotNode.useThetaStyleImplicitJoins = true;
+		assertTranslation( "from Animal a where a in (select m from Animal an join an.mother m)" );
+		assertTranslation( "from Animal a where a in (select o from Animal an join an.offspring o)" );
+		DotNode.useThetaStyleImplicitJoins = false;
+	}
+
+	public void testJoinedSubclassImplicitJoin() throws Exception {
+		// From MultiTableTest.testQueries()
+		// TODO: This produces the proper from clause now, but the parens in the where clause are different.
+		assertTranslation( "from org.hibernate.test.legacy.Lower s where s.yetanother.name='name'" );
+	}
+
+	public void testProjectProductJoinedSubclass() throws Exception {
+		// TODO: The old QT generates the discriminator and the theta join in a strange order, and with two extra sets of parens, this is okay, right?
+		assertTranslation( "select zoo from Zoo zoo, PettingZoo pz where zoo=pz" );
+		assertTranslation( "select zoo, pz from Zoo zoo, PettingZoo pz where zoo=pz" );
+	}
+
+	public void testCorrelatedSubselect1() throws Exception {
+		// The old translator generates the theta join before the condition in the sub query.
+		// TODO: Decide if we want to bother generating the theta join in the same order (non simple).
+		assertTranslation( "from Animal a where exists (from a.offspring o where o.bodyWeight>10)" );
+	}
+
+	public void testOuterAliasInSubselect() {
+		assertTranslation( "from Human h where h = (from Animal an where an = h)" );
+	}
+
+	public void testFetch() throws Exception {
+		assertTranslation( "from Zoo zoo left join zoo.mammals" );
+		assertTranslation( "from Zoo zoo left join fetch zoo.mammals" );
+	}
+
+	public void testOneToManyElementFunctionInWhere() throws Exception {
+		assertTranslation( "from Zoo zoo where 'dog' in indices(zoo.mammals)" );
+		assertTranslation( "from Zoo zoo, Dog dog where dog in elements(zoo.mammals)" );
+	}
+
+	/*public void testManyToManyElementFunctionInSelect() throws Exception {
+		assertTranslation("select elements(zoo.mammals) from Zoo zoo");
+		assertTranslation("select indices(zoo.mammals) from Zoo zoo");
+	}*/
+
+	public void testManyToManyInJoin() throws Exception {
+		assertTranslation( "select x.id from Human h1 join h1.family x" );
+		//assertTranslation("select index(h2) from Human h1 join h1.family h2");
+	}
+
+	public void testManyToManyInSubselect() throws Exception {
+		assertTranslation( "from Human h1, Human h2 where h2 in (select x.id from h1.family x)" );
+		assertTranslation( "from Human h1, Human h2 where 'father' in indices(h1.family)" );
+	}
+
+	public void testOneToManyIndexAccess() throws Exception {
+		assertTranslation( "from Zoo zoo where zoo.mammals['dog'] is not null" );
+	}
+
+	public void testImpliedSelect() throws Exception {
+		assertTranslation( "select zoo from Zoo zoo" );
+		assertTranslation( "from Zoo zoo" );
+		assertTranslation( "from Zoo zoo join zoo.mammals m" );
+		assertTranslation( "from Zoo" );
+		assertTranslation( "from Zoo zoo join zoo.mammals" );
+	}
+
+	public void testVectorSubselect() {
+		assertTranslation( "from Animal a where ('foo', 'bar') in (select m.description, m.bodyWeight from a.mother m)" );
+	}
+
+	public void testWierdSubselectImplicitJoinStuff() {
+		//note that the new qt used to eliminate unnecessary join, but no more
+		assertTranslation("from Simple s where s = some( select sim from Simple sim where sim.other.count=s.other.count ) and s.other.count > 0");
+	}
+
+	/*public void testSelectElementsOfCollectionOfValues() throws Exception {
+		// From FooBarTest.testQuery()
+		// TODO: This produces the where clause in a different order, but it seems okay.
+		assertTranslation("select foo.component.name, elements(foo.component.importantDates) from org.hibernate.test.legacy.Foo foo where foo.foo.id=?");
+	}*/
+
+	//public void testMultiTableElements() throws Exception {
+	/*
+	HQL    : select elements(ls.bag), elements(ls.set) from org.hibernate.test.legacy.Lower ls
+	OLD SQL:
+	select top2_.id1_ as col_0_0_, top4_.id1_ as col_1_0_
+	from leafsubclass lower0_ inner join rootclass lower0_1_ on lower0_.id__=lower0_1_.id1_, simple_simple bag1_, rootclass top2_, rootclass set3_, rootclass top4_
+	where lower0_1_.id1_ is not null and lower0_.id__=bag1_.simple1 and bag1_.simple2=top2_.id1_ and lower0_.id__=set3_.parent and set3_.id1_=top4_.id1_
+	*/
+
+	//assertTranslation("select elements(ls.bag), elements(ls.set) from org.hibernate.test.legacy.Lower ls");
+	//}
+
+	public void testCollectionsInSelect2() throws Exception {
+		// This one looks okay now, it just generates extra parens in the where clause.
+		assertTranslation( "select foo.string from Bar bar left join bar.baz.fooArray foo where bar.string = foo.string" );
+	}
+
+
+	//public void testCollectionsInSelect() throws Exception {
+	// From FooBarTest.testCollectionsInSelect
+	/*
+	HQL    : select baz, baz.stringSet.size, count( distinct elements(baz.stringSet) ), max( elements(baz.stringSet) ) from org.hibernate.test.legacy.Baz baz group by baz
+	OLD SQL:
+	select
+		baz0_.baz_id_column_ as baz_id_c1_, baz0_.count_count as count_co2_37_, baz0_.name_b as name_b37_, baz0_.foo as foo37_, baz0_.superBaz as superBaz37_, baz0_.str as str37_, baz0_.baz_id_column_ as col_0_0_,
+		count(*) as col_1_0_,
+		count(distinct stringset2_.element) as col_2_0_, max(stringset3_.element) as col_3_0_
+	from baz baz0_, stringSet stringset1_, stringSet stringset2_, stringSet stringset3_
+	where baz0_.baz_id_column_=stringset1_.id_ and baz0_.baz_id_column_=stringset2_.id_ and baz0_.baz_id_column_=stringset3_.id_
+	group by  baz0_.baz_id_column_
+
+	NEW SQL:
+	select
+		// TODO: Remove the extra 'id' column select.
+		baz0_.baz_id_column_ as col_0_0_,
+		// TODO: Figure out how the classic translator knows to use count(*)
+		(select count(*) from stringSet stringset1_ where baz0_.baz_id_column_=stringset1_.id_) as col_1_0_,
+		// This is also correct.
+		count(distinct stringset2_.element) as col_2_0_, max(stringset3_.element) as col_3_0_,
+		// The properties of baz are correct, they're just in the wrong place.
+		baz0_.baz_id_column_ as baz_id_c1_, baz0_.count_count as count_co2_37_, baz0_.name_b as name_b37_, baz0_.foo as foo37_, baz0_.superBaz as superBaz37_, baz0_.str as str37_
+//		 FROM is okay.
+	from baz baz0_ stringSet stringset1_, stringSet stringset3_, stringSet stringset2_
+//		 WHERE is okay.
+	where (baz0_.baz_id_column_=stringset1_.id_ and baz0_.baz_id_column_=stringset2_.id_ baz0_.baz_id_column_=stringset3_.id_)
+//		 GROUP BY is okay.
+	group by  baz0_.baz_id_column_
+	*/
+	//assertTranslation( "select baz, size(baz.stringSet), count( distinct elements(baz.stringSet) ), max( elements(baz.stringSet) ) from org.hibernate.test.legacy.Baz baz group by baz");
+
+	//}
+
+	public void testAssociationPropertyWithoutAlias() throws Exception {
+		// The classic translator doesn't do this right, so don't bother asserting.
+		compileWithAstQueryTranslator("from Animal where zoo is null", false);
+	}
+
+	private void compileWithAstQueryTranslator(String hql, boolean scalar) {
+		Map replacements = new HashMap();
+		QueryTranslatorFactory ast = new ASTQueryTranslatorFactory();
+		SessionFactoryImplementor factory = getSessionFactoryImplementor();
+		QueryTranslator newQueryTranslator = ast.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, factory );
+		newQueryTranslator.compile( replacements, scalar );
+	}
+
+	public void testComponentNoAlias() throws Exception {
+		// The classic translator doesn't do this right, so don't bother asserting.
+		compileWithAstQueryTranslator( "from Human where name.first = 'Gavin'", false);
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HeresAnotherCrazyIdFieldName.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HeresAnotherCrazyIdFieldName.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HeresAnotherCrazyIdFieldName.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+// $Id: HeresAnotherCrazyIdFieldName.java 7471 2005-07-14 14:58:28Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * Implementation of HeresAnotherCrazyIdFieldName.
+ *
+ * @author Steve Ebersole
+ */
+public class HeresAnotherCrazyIdFieldName {
+	private Long heresAnotherCrazyIdFieldName;
+	private String name;
+
+	public HeresAnotherCrazyIdFieldName() {
+	}
+
+	public HeresAnotherCrazyIdFieldName(String name) {
+		this.name = name;
+	}
+
+	public Long getHeresAnotherCrazyIdFieldName() {
+		return heresAnotherCrazyIdFieldName;
+	}
+
+	public void setHeresAnotherCrazyIdFieldName(Long heresAnotherCrazyIdFieldName) {
+		this.heresAnotherCrazyIdFieldName = heresAnotherCrazyIdFieldName;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HqlParserTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HqlParserTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/HqlParserTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1081 @@
+// $Id: HqlParserTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.hql;
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+import antlr.collections.AST;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.hibernate.hql.ast.HqlParser;
+import org.hibernate.hql.ast.tree.Node;
+import org.hibernate.hql.ast.util.ASTIterator;
+import org.hibernate.hql.ast.util.ASTPrinter;
+
+/**
+ * Tests the HQL parser on various inputs, just makes sure that the first phase of the parser
+ * works properly (i.e. no unexpected syntax errors).
+ */
+public class HqlParserTest extends TestCase {
+
+	/**
+	 * Standard JUnit test case constructor.
+	 *
+	 * @param name The name of the test case.
+	 */
+	public HqlParserTest(String name) {
+		super( name );
+	}
+	
+	public void testUnion() throws Exception {
+		parse("from Animal a where a in (from Cat union from Dog) ");
+	}
+
+	/**
+	 * Section 9.2 - from *
+	 */
+	public void testDocoExamples92() throws Exception {
+		parse( "from eg.Cat" );
+		parse( "from eg.Cat as cat" );
+		parse( "from eg.Cat cat" );
+		parse( "from Formula, Parameter" );
+		parse( "from Formula as form, Parameter as param" );
+	}
+
+	/**
+	 * Section 9.3 - Associations and joins *
+	 */
+	public void testDocoExamples93() throws Exception {
+		parse( "from eg.Cat as cat inner join cat.mate as mate left outer join cat.kittens as kitten" );
+		parse( "from eg.Cat as cat left join cat.mate.kittens as kittens" );
+		parse( "from Formula form full join form.parameter param" );
+		parse( "from eg.Cat as cat join cat.mate as mate left join cat.kittens as kitten" );
+		parse( "from eg.Cat as cat\ninner join fetch cat.mate\nleft join fetch cat.kittens" );
+	}
+
+	/**
+	 * Section 9.4 - Select *
+	 */
+	public void testDocoExamples94() throws Exception {
+		parse( "select mate from eg.Cat as cat inner join cat.mate as mate" );
+		parse( "select cat.mate from eg.Cat cat" );
+		parse( "select elements(cat.kittens) from eg.Cat cat" );
+		parse( "select cat.name from eg.DomesticCat cat where cat.name like 'fri%'" );
+		parse( "select cust.name.firstName from Customer as cust" );
+		parse( "select mother, offspr, mate.name from eg.DomesticCat\n"
+				+ " as mother inner join mother.mate as mate left outer join\n"
+				+ "mother.kittens as offspr" );
+		parse( "select new Family(mother, mate, offspr)\n"
+				+ "from eg.DomesticCat as mother\n"
+				+ "join mother.mate as mate\n"
+				+ "left join mother.kittens as offspr\n" );
+	}
+
+	/**
+	 * Section 9.5 - Aggregate functions *
+	 */
+	public void testDocoExamples95() throws Exception {
+		parse( "select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)\n"
+				+ "from eg.Cat cat" );
+		parse( "select cat, count( elements(cat.kittens) )\n"
+				+ " from eg.Cat cat group by cat" );
+		parse( "select distinct cat.name from eg.Cat cat" );
+		parse( "select count(distinct cat.name), count(cat) from eg.Cat cat" );
+	}
+
+	/**
+	 * Section 9.6 - Polymorphism *
+	 */
+	public void testDocoExamples96() throws Exception {
+		parse( "from eg.Cat as cat" );
+		parse( "from java.lang.Object o" );
+		parse( "from eg.Named n, eg.Named m where n.name = m.name" );
+	}
+
+	/**
+	 * Section 9.7 - Where *
+	 */
+	public void testDocoExamples97() throws Exception {
+		parse( "from eg.Cat as cat where cat.name='Fritz'" );
+		parse( "select foo\n"
+				+ "from eg.Foo foo, eg.Bar bar\n"
+				+ "where foo.startDate = bar.date\n" );
+		parse( "from eg.Cat cat where cat.mate.name is not null" );
+		parse( "from eg.Cat cat, eg.Cat rival where cat.mate = rival.mate" );
+		parse( "select cat, mate\n"
+				+ "from eg.Cat cat, eg.Cat mate\n"
+				+ "where cat.mate = mate" );
+		parse( "from eg.Cat as cat where cat.id = 123" );
+		parse( "from eg.Cat as cat where cat.mate.id = 69" );
+		parse( "from bank.Person person\n"
+				+ "where person.id.country = 'AU'\n"
+				+ "and person.id.medicareNumber = 123456" );
+		parse( "from bank.Account account\n"
+				+ "where account.owner.id.country = 'AU'\n"
+				+ "and account.owner.id.medicareNumber = 123456" );
+		parse( "from eg.Cat cat where cat.class = eg.DomesticCat" );
+		parse( "from eg.AuditLog log, eg.Payment payment\n"
+				+ "where log.item.class = 'eg.Payment' and log.item.id = payment.id" );
+	}
+
+	/**
+	 * Section 9.8 - Expressions *
+	 */
+	public void testDocoExamples98() throws Exception {
+		parse( "from eg.DomesticCat cat where cat.name between 'A' and 'B'" );
+		parse( "from eg.DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )" );
+		parse( "from eg.DomesticCat cat where cat.name not between 'A' and 'B'" );
+		parse( "from eg.DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )" );
+		parse( "from eg.Cat cat where cat.kittens.size > 0" );
+		parse( "from eg.Cat cat where size(cat.kittens) > 0" );
+// This is a little odd.  I'm not sure whether 'current' is a keyword.
+//        parse("from Calendar cal where cal.holidays.maxElement > current date");
+// Using the token 'order' as both a keyword and an identifier works now, but
+// the second instance causes some problems because order is valid in the second instance.
+//        parse("from Order order where maxindex(order.items) > 100");
+//        parse("from Order order where minelement(order.items) > 10000");
+		parse( "from Order ord where maxindex(ord.items) > 100" );
+		parse( "from Order ord where minelement(ord.items) > 10000" );
+
+		parse( "select mother from eg.Cat as mother, eg.Cat as kit\n"
+				+ "where kit in elements(foo.kittens)" );
+		parse( "select p from eg.NameList list, eg.Person p\n"
+				+ "where p.name = some elements(list.names)" );
+		parse( "from eg.Cat cat where exists elements(cat.kittens)" );
+		parse( "from eg.Player p where 3 > all elements(p.scores)" );
+		parse( "from eg.Show show where 'fizard' in indices(show.acts)" );
+
+		// Yet another example of the pathological 'order' token.
+//        parse("from Order order where order.items[0].id = 1234");
+//        parse("select person from Person person, Calendar calendar\n"
+//        + "where calendar.holidays['national day'] = person.birthDay\n"
+//        + "and person.nationality.calendar = calendar");
+//        parse("select item from Item item, Order order\n"
+//        + "where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11");
+//        parse("select item from Item item, Order order\n"
+//        + "where order.items[ maxindex(order.items) ] = item and order.id = 11");
+
+		parse( "from Order ord where ord.items[0].id = 1234" );
+		parse( "select person from Person person, Calendar calendar\n"
+				+ "where calendar.holidays['national day'] = person.birthDay\n"
+				+ "and person.nationality.calendar = calendar" );
+		parse( "select item from Item item, Order ord\n"
+				+ "where ord.items[ ord.deliveredItemIndices[0] ] = item and ord.id = 11" );
+		parse( "select item from Item item, Order ord\n"
+				+ "where ord.items[ maxindex(ord.items) ] = item and ord.id = 11" );
+
+		parse( "select item from Item item, Order ord\n"
+				+ "where ord.items[ size(ord.items) - 1 ] = item" );
+
+		parse( "from eg.DomesticCat cat where upper(cat.name) like 'FRI%'" );
+
+		parse( "select cust from Product prod, Store store\n"
+				+ "inner join store.customers cust\n"
+				+ "where prod.name = 'widget'\n"
+				+ "and store.location.name in ( 'Melbourne', 'Sydney' )\n"
+				+ "and prod = all elements(cust.currentOrder.lineItems)" );
+
+	}
+
+	public void testDocoExamples99() throws Exception {
+		parse( "from eg.DomesticCat cat\n"
+				+ "order by cat.name asc, cat.weight desc, cat.birthdate" );
+	}
+
+	public void testDocoExamples910() throws Exception {
+		parse( "select cat.color, sum(cat.weight), count(cat)\n"
+				+ "from eg.Cat cat group by cat.color" );
+		parse( "select foo.id, avg( elements(foo.names) ), max( indices(foo.names) )\n"
+				+ "from eg.Foo foo group by foo.id" );
+		parse( "select cat.color, sum(cat.weight), count(cat)\n"
+				+ "from eg.Cat cat group by cat.color\n"
+				+ "having cat.color in (eg.Color.TABBY, eg.Color.BLACK)" );
+		parse( "select cat from eg.Cat cat join cat.kittens kitten\n"
+				+ "group by cat having avg(kitten.weight) > 100\n"
+				+ "order by count(kitten) asc, sum(kitten.weight) desc" );
+	}
+
+	public void testDocoExamples911() throws Exception {
+		parse( "from eg.Cat as fatcat where fatcat.weight > (\n"
+				+ "select avg(cat.weight) from eg.DomesticCat cat)" );
+		parse( "from eg.DomesticCat as cat where cat.name = some (\n"
+				+ "select name.nickName from eg.Name as name)\n" );
+		parse( "from eg.Cat as cat where not exists (\n"
+				+ "from eg.Cat as mate where mate.mate = cat)" );
+		parse( "from eg.DomesticCat as cat where cat.name not in (\n"
+				+ "select name.nickName from eg.Name as name)" );
+	}
+
+	public void testDocoExamples912() throws Exception {
+		parse( "select ord.id, sum(price.amount), count(item)\n"
+				+ "from Order as ord join ord.lineItems as item\n"
+				+ "join item.product as product, Catalog as catalog\n"
+				+ "join catalog.prices as price\n"
+				+ "where ord.paid = false\n"
+				+ "and ord.customer = :customer\n"
+				+ "and price.product = product\n"
+				+ "and catalog.effectiveDate < sysdate\n"
+				+ "and catalog.effectiveDate >= all (\n"
+				+ "select cat.effectiveDate from Catalog as cat where cat.effectiveDate < sysdate)\n"
+				+ "group by ord\n"
+				+ "having sum(price.amount) > :minAmount\n"
+				+ "order by sum(price.amount) desc" );
+
+		parse( "select ord.id, sum(price.amount), count(item)\n"
+				+ "from Order as ord join ord.lineItems as item join item.product as product,\n"
+				+ "Catalog as catalog join catalog.prices as price\n"
+				+ "where ord.paid = false and ord.customer = :customer\n"
+				+ "and price.product = product and catalog = :currentCatalog\n"
+				+ "group by ord having sum(price.amount) > :minAmount\n"
+				+ "order by sum(price.amount) desc" );
+
+		parse( "select count(payment), status.name \n"
+				+ "from Payment as payment \n"
+				+ "    join payment.currentStatus as status\n"
+				+ "    join payment.statusChanges as statusChange\n"
+				+ "where payment.status.name <> PaymentStatus.AWAITING_APPROVAL\n"
+				+ "    or (\n"
+				+ "        statusChange.timeStamp = ( \n"
+				+ "            select max(change.timeStamp) \n"
+				+ "            from PaymentStatusChange change \n"
+				+ "            where change.payment = payment\n"
+				+ "        )\n"
+				+ "        and statusChange.user <> :currentUser\n"
+				+ "    )\n"
+				+ "group by status.name, status.sortOrder\n"
+				+ "order by status.sortOrder" );
+		parse( "select count(payment), status.name \n"
+				+ "from Payment as payment\n"
+				+ "    join payment.currentStatus as status\n"
+				+ "where payment.status.name <> PaymentStatus.AWAITING_APPROVAL\n"
+				+ "    or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser\n"
+				+ "group by status.name, status.sortOrder\n"
+				+ "order by status.sortOrder" );
+		parse( "select account, payment\n"
+				+ "from Account as account\n"
+				+ "    left outer join account.payments as payment\n"
+				+ "where :currentUser in elements(account.holder.users)\n"
+				+ "    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)\n"
+				+ "order by account.type.sortOrder, account.accountNumber, payment.dueDate" );
+		parse( "select account, payment\n"
+				+ "from Account as account\n"
+				+ "    join account.holder.users as user\n"
+				+ "    left outer join account.payments as payment\n"
+				+ "where :currentUser = user\n"
+				+ "    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)\n"
+				+ "order by account.type.sortOrder, account.accountNumber, payment.dueDate" );
+	}
+
+	public void testExamples1() throws Exception {
+		parse( "select new org.hibernate.test.S(s.count, s.address)\n"
+				+ "from s in class Simple" );
+		parse( "select s.name, sysdate, trunc(s.pay), round(s.pay) from s in class Simple" );
+		parse( "select round(s.pay, 2) from s" );
+		parse( "select abs(round(s.pay)) from s in class Simple" );
+		parse( "select trunc(round(sysdate)) from s in class Simple" );
+	}
+
+	public void testArrayExpr() throws Exception {
+		parse( "from Order ord where ord.items[0].id = 1234" );
+	}
+
+	public void testMultipleActualParameters() throws Exception {
+		parse( "select round(s.pay, 2) from s" );
+	}
+
+	public void testMultipleFromClasses() throws Exception {
+		parse( "FROM eg.mypackage.Cat qat, com.toadstool.Foo f" );
+		parse( "FROM eg.mypackage.Cat qat, org.jabberwocky.Dipstick" );
+	}
+
+	public void testFromWithJoin() throws Exception {
+		parse( "FROM eg.mypackage.Cat qat, com.toadstool.Foo f join net.sf.blurb.Blurb" );
+		parse( "FROM eg.mypackage.Cat qat  left join com.multijoin.JoinORama , com.toadstool.Foo f join net.sf.blurb.Blurb" );
+	}
+
+	public void testSelect() throws Exception {
+		parse( "SELECT f FROM eg.mypackage.Cat qat, com.toadstool.Foo f join net.sf.blurb.Blurb" );
+		parse( "SELECT DISTINCT bar FROM eg.mypackage.Cat qat  left join com.multijoin.JoinORama as bar, com.toadstool.Foo f join net.sf.blurb.Blurb" );
+		parse( "SELECT count(*) FROM eg.mypackage.Cat qat" );
+		parse( "SELECT avg(qat.weight) FROM eg.mypackage.Cat qat" );
+	}
+
+	public void testWhere() throws Exception {
+		parse( "FROM eg.mypackage.Cat qat where qat.name like '%fluffy%' or qat.toes > 5" );
+		parse( "FROM eg.mypackage.Cat qat where not qat.name like '%fluffy%' or qat.toes > 5" );
+		parse( "FROM eg.mypackage.Cat qat where not qat.name not like '%fluffy%'" );
+		parse( "FROM eg.mypackage.Cat qat where qat.name in ('crater','bean','fluffy')" );
+		parse( "FROM eg.mypackage.Cat qat where qat.name not in ('crater','bean','fluffy')" );
+		parse( "from Animal an where sqrt(an.bodyWeight)/2 > 10" );
+		parse( "from Animal an where (an.bodyWeight > 10 and an.bodyWeight < 100) or an.bodyWeight is null" );
+	}
+
+	public void testGroupBy() throws Exception {
+		parse( "FROM eg.mypackage.Cat qat group by qat.breed" );
+		parse( "FROM eg.mypackage.Cat qat group by qat.breed, qat.eyecolor" );
+	}
+
+	public void testOrderBy() throws Exception {
+		parse( "FROM eg.mypackage.Cat qat order by avg(qat.toes)" );
+		parse( "from Animal an order by sqrt(an.bodyWeight)/2" );
+	}
+
+	public void testDoubleLiteral() throws Exception {
+		parse( "from eg.Cat as tinycat where fatcat.weight < 3.1415" );
+		parse( "from eg.Cat as enormouscat where fatcat.weight > 3.1415e3" );
+	}
+
+	public void testComplexConstructor() throws Exception {
+		parse( "select new Foo(count(bar)) from bar" );
+		parse( "select new Foo(count(bar),(select count(*) from doofus d where d.gob = 'fat' )) from bar" );
+	}
+
+
+	public void testInNotIn() throws Exception {
+		parse( "from foo where foo.bar in ('a' , 'b', 'c')" );
+		parse( "from foo where foo.bar not in ('a' , 'b', 'c')" );
+	}
+
+	public void testOperatorPrecedence() throws Exception {
+		parse( "from foo where foo.bar = 123 + foo.baz * foo.not" );
+		parse( "from foo where foo.bar like 'testzzz' || foo.baz or foo.bar in ('duh', 'gob')" );
+	}
+
+	/**
+	 * Tests HQL generated by the other unit tests.
+	 *
+	 * @throws Exception if the HQL could not be parsed.
+	 */
+	public void testUnitTestHql() throws Exception {
+		parse( "select foo from foo in class org.hibernate.test.Foo, fee in class org.hibernate.test.Fee where foo.dependent = fee order by foo.string desc, foo.component.count asc, fee.id" );
+		parse( "select foo.foo, foo.dependent from foo in class org.hibernate.test.Foo order by foo.foo.string desc, foo.component.count asc, foo.dependent.id" );
+		parse( "select foo from foo in class org.hibernate.test.Foo order by foo.dependent.id, foo.dependent.fi" );
+		parse( "SELECT one FROM one IN CLASS org.hibernate.test.One ORDER BY one.value ASC" );
+		parse( "SELECT many.one FROM many IN CLASS org.hibernate.test.Many ORDER BY many.one.value ASC, many.one.id" );
+		parse( "select foo.id from org.hibernate.test.Foo foo where foo.joinedProp = 'foo'" );
+		parse( "from org.hibernate.test.Foo foo inner join fetch foo.foo" );
+		parse( "from org.hibernate.test.Baz baz left outer join fetch baz.fooToGlarch" );
+		parse( "select foo.foo.foo.string from foo in class org.hibernate.test.Foo where foo.foo = 'bar'" );
+		parse( "select foo.foo.foo.foo.string from foo in class org.hibernate.test.Foo where foo.foo.foo = 'bar'" );
+		parse( "select foo.foo.foo.string from foo in class org.hibernate.test.Foo where foo.foo.foo.foo.string = 'bar'" );
+		parse( "select foo.string from foo in class org.hibernate.test.Foo where foo.foo.foo = 'bar' and foo.foo.foo.foo = 'baz'" );
+		parse( "select foo.string from foo in class org.hibernate.test.Foo where foo.foo.foo.foo.string = 'a' and foo.foo.string = 'b'" );
+		parse( "from org.hibernate.test.Foo as foo where foo.component.glarch.name is not null" );
+		parse( "from org.hibernate.test.Foo as foo left outer join foo.component.glarch as glarch where glarch.name = 'foo'" );
+		parse( "from org.hibernate.test.Foo" );
+		parse( "from org.hibernate.test.Foo foo left outer join foo.foo" );
+		parse( "from org.hibernate.test.Foo, org.hibernate.test.Bar" );
+		parse( "from org.hibernate.test.Baz baz left join baz.fooToGlarch, org.hibernate.test.Bar bar join bar.foo" );
+		parse( "from org.hibernate.test.Baz baz left join baz.fooToGlarch join baz.fooSet" );
+		parse( "from org.hibernate.test.Baz baz left join baz.fooToGlarch join fetch baz.fooSet foo left join fetch foo.foo" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.string='osama bin laden' and foo.boolean = true order by foo.string asc, foo.component.count desc" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.string='osama bin laden' order by foo.string asc, foo.component.count desc" );
+		parse( "select foo.foo from foo in class org.hibernate.test.Foo" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.component.count is null order by foo.component.count" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.component.name='foo'" );
+		parse( "select distinct foo.component.name, foo.component.name from foo in class org.hibernate.test.Foo where foo.component.name='foo'" );
+		parse( "select distinct foo.component.name, foo.id from foo in class org.hibernate.test.Foo where foo.component.name='foo'" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.id=?" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.key=?" );
+		parse( "select foo.foo from foo in class org.hibernate.test.Foo where foo.string='fizard'" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.component.subcomponent.name='bar'" );
+		parse( "select foo.foo from foo in class org.hibernate.test.Foo where foo.foo.id=?" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.foo = ?" );
+		parse( "from bar in class org.hibernate.test.Bar where bar.string='a string' or bar.string='a string'" );
+		parse( "select foo.component.name, elements(foo.component.importantDates) from foo in class org.hibernate.test.Foo where foo.foo.id=?" );
+		parse( "select max(elements(foo.component.importantDates)) from foo in class org.hibernate.test.Foo group by foo.id" );
+		parse( "select foo.foo.foo.foo from foo in class org.hibernate.test.Foo, foo2 in class org.hibernate.test.Foo where foo = foo2.foo and not not ( not foo.string='fizard' ) and foo2.string between 'a' and (foo.foo.string) and ( foo2.string in ( 'fiz', 'blah') or 1=1 )" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.string='from BoogieDown  -tinsel town  =!@#$^&*())'" );
+		parse( "from foo in class org.hibernate.test.Foo where not foo.string='foo''bar'" ); // Added quote quote is an escape
+		parse( "from foo in class org.hibernate.test.Foo where foo.component.glarch.next is null" );
+		parse( " from bar in class org.hibernate.test.Bar where bar.baz.count=667 and bar.baz.count!=123 and not bar.baz.name='1-E-1'" );
+		parse( " from i in class org.hibernate.test.Bar where i.baz.name='Bazza'" );
+		parse( "select count(distinct foo.foo) from foo in class org.hibernate.test.Foo" );
+		parse( "select count(foo.foo.boolean) from foo in class org.hibernate.test.Foo" );
+		parse( "select count(*), foo.int from foo in class org.hibernate.test.Foo group by foo.int" );
+		parse( "select sum(foo.foo.int) from foo in class org.hibernate.test.Foo" );
+		parse( "select count(foo) from foo in class org.hibernate.test.Foo where foo.id=?" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.boolean = ?" );
+		parse( "select new Foo(fo.x) from org.hibernate.test.Fo fo" );
+		parse( "select new Foo(fo.integer) from org.hibernate.test.Foo fo" );
+		parse( "select new Foo(fo.x) from org.hibernate.test.Foo fo" );
+		parse( "select foo.long, foo.component.name, foo, foo.foo from foo in class org.hibernate.test.Foo" );
+		parse( "select avg(foo.float), max(foo.component.name), count(distinct foo.id) from foo in class org.hibernate.test.Foo" );
+		parse( "select foo.long, foo.component, foo, foo.foo from foo in class org.hibernate.test.Foo" );
+		parse( "from o in class org.hibernate.test.MoreStuff" );
+		parse( "from o in class org.hibernate.test.Many" );
+		parse( "from o in class org.hibernate.test.Fee" );
+		parse( "from o in class org.hibernate.test.Qux" );
+		parse( "from o in class org.hibernate.test.Y" );
+		parse( "from o in class org.hibernate.test.Fumm" );
+		parse( "from o in class org.hibernate.test.X" );
+		parse( "from o in class org.hibernate.test.Simple" );
+		parse( "from o in class org.hibernate.test.Location" );
+		parse( "from o in class org.hibernate.test.Holder" );
+		parse( "from o in class org.hibernate.test.Part" );
+		parse( "from o in class org.hibernate.test.Baz" );
+		parse( "from o in class org.hibernate.test.Vetoer" );
+		parse( "from o in class org.hibernate.test.Sortable" );
+		parse( "from o in class org.hibernate.test.Contained" );
+		parse( "from o in class org.hibernate.test.Stuff" );
+		parse( "from o in class org.hibernate.test.Immutable" );
+		parse( "from o in class org.hibernate.test.Container" );
+		parse( "from o in class org.hibernate.test.X$XX" );
+		parse( "from o in class org.hibernate.test.One" );
+		parse( "from o in class org.hibernate.test.Foo" );
+		parse( "from o in class org.hibernate.test.Fo" );
+		parse( "from o in class org.hibernate.test.Glarch" );
+		parse( "from o in class org.hibernate.test.Fum" );
+		parse( "from n in class org.hibernate.test.Holder" );
+		parse( "from n in class org.hibernate.test.Baz" );
+		parse( "from n in class org.hibernate.test.Bar" );
+		parse( "from n in class org.hibernate.test.Glarch" );
+		parse( "from n in class org.hibernate.test.Holder where n.name is not null" );
+		parse( "from n in class org.hibernate.test.Baz where n.name is not null" );
+		parse( "from n in class org.hibernate.test.Bar where n.name is not null" );
+		parse( "from n in class org.hibernate.test.Glarch where n.name is not null" );
+		parse( "from n in class org.hibernate.test.Holder" );
+		parse( "from n in class org.hibernate.test.Baz" );
+		parse( "from n in class org.hibernate.test.Bar" );
+		parse( "from n in class org.hibernate.test.Glarch" );
+		parse( "from n0 in class org.hibernate.test.Holder, n1 in class org.hibernate.test.Holder where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Baz, n1 in class org.hibernate.test.Holder where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Bar, n1 in class org.hibernate.test.Holder where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Glarch, n1 in class org.hibernate.test.Holder where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Holder, n1 in class org.hibernate.test.Baz where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Baz, n1 in class org.hibernate.test.Baz where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Bar, n1 in class org.hibernate.test.Baz where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Glarch, n1 in class org.hibernate.test.Baz where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Holder, n1 in class org.hibernate.test.Bar where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Baz, n1 in class org.hibernate.test.Bar where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Bar, n1 in class org.hibernate.test.Bar where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Glarch, n1 in class org.hibernate.test.Bar where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Holder, n1 in class org.hibernate.test.Glarch where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Baz, n1 in class org.hibernate.test.Glarch where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Bar, n1 in class org.hibernate.test.Glarch where n0.name = n1.name" );
+		parse( "from n0 in class org.hibernate.test.Glarch, n1 in class org.hibernate.test.Glarch where n0.name = n1.name" );
+		parse( "from n in class org.hibernate.test.Holder where n.name = :name" );
+		parse( "from o in class org.hibernate.test.MoreStuff" );
+		parse( "from o in class org.hibernate.test.Many" );
+		parse( "from o in class org.hibernate.test.Fee" );
+		parse( "from o in class org.hibernate.test.Qux" );
+		parse( "from o in class org.hibernate.test.Y" );
+		parse( "from o in class org.hibernate.test.Fumm" );
+		parse( "from o in class org.hibernate.test.X" );
+		parse( "from o in class org.hibernate.test.Simple" );
+		parse( "from o in class org.hibernate.test.Location" );
+		parse( "from o in class org.hibernate.test.Holder" );
+		parse( "from o in class org.hibernate.test.Part" );
+		parse( "from o in class org.hibernate.test.Baz" );
+		parse( "from o in class org.hibernate.test.Vetoer" );
+		parse( "from o in class org.hibernate.test.Sortable" );
+		parse( "from o in class org.hibernate.test.Contained" );
+		parse( "from o in class org.hibernate.test.Stuff" );
+		parse( "from o in class org.hibernate.test.Immutable" );
+		parse( "from o in class org.hibernate.test.Container" );
+		parse( "from o in class org.hibernate.test.X$XX" );
+		parse( "from o in class org.hibernate.test.One" );
+		parse( "from o in class org.hibernate.test.Foo" );
+		parse( "from o in class org.hibernate.test.Fo" );
+		parse( "from o in class org.hibernate.test.Glarch" );
+		parse( "from o in class org.hibernate.test.Fum" );
+		parse( "select baz.code, min(baz.count) from baz in class org.hibernate.test.Baz group by baz.code" );
+		parse( "selecT baz from baz in class org.hibernate.test.Baz where baz.stringDateMap['foo'] is not null or baz.stringDateMap['bar'] = ?" );
+		parse( "select baz from baz in class org.hibernate.test.Baz where baz.stringDateMap['now'] is not null" );
+		parse( "select baz from baz in class org.hibernate.test.Baz where baz.stringDateMap['now'] is not null and baz.stringDateMap['big bang'] < baz.stringDateMap['now']" );
+		parse( "select index(date) from org.hibernate.test.Baz baz join baz.stringDateMap date" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.integer not between 1 and 5 and foo.string not in ('cde', 'abc') and foo.string is not null and foo.integer<=3" );
+		parse( "from org.hibernate.test.Baz baz inner join baz.collectionComponent.nested.foos foo where foo.string is null" );
+		parse( "from org.hibernate.test.Baz baz inner join baz.fooSet where '1' in (from baz.fooSet foo where foo.string is not null)" );
+		parse( "from org.hibernate.test.Baz baz where 'a' in elements(baz.collectionComponent.nested.foos) and 1.0 in elements(baz.collectionComponent.nested.floats)" );
+		parse( "from org.hibernate.test.Foo foo join foo.foo where foo.foo in ('1','2','3')" );
+		parse( "select foo.foo from org.hibernate.test.Foo foo where foo.foo in ('1','2','3')" );
+		parse( "select foo.foo.string from org.hibernate.test.Foo foo where foo.foo in ('1','2','3')" );
+		parse( "select foo.foo.string from org.hibernate.test.Foo foo where foo.foo.string in ('1','2','3')" );
+		parse( "select foo.foo.long from org.hibernate.test.Foo foo where foo.foo.string in ('1','2','3')" );
+		parse( "select count(*) from org.hibernate.test.Foo foo where foo.foo.string in ('1','2','3') or foo.foo.long in (1,2,3)" );
+		parse( "select count(*) from org.hibernate.test.Foo foo where foo.foo.string in ('1','2','3') group by foo.foo.long" );
+		parse( "from org.hibernate.test.Foo foo1 left join foo1.foo foo2 left join foo2.foo where foo1.string is not null" );
+		parse( "from org.hibernate.test.Foo foo1 left join foo1.foo.foo where foo1.string is not null" );
+		parse( "from org.hibernate.test.Foo foo1 left join foo1.foo foo2 left join foo1.foo.foo foo3 where foo1.string is not null" );
+		parse( "select foo.formula from org.hibernate.test.Foo foo where foo.formula > 0" );
+		parse( "from org.hibernate.test.Foo as foo join foo.foo as foo2 where foo2.id >'a' or foo2.id <'a'" );
+		parse( "from org.hibernate.test.Holder" );
+		parse( "from org.hibernate.test.Baz baz left outer join fetch baz.manyToAny" );
+		parse( "from org.hibernate.test.Baz baz join baz.manyToAny" );
+		parse( "select baz from org.hibernate.test.Baz baz join baz.manyToAny a where index(a) = 0" );
+		parse( "select bar from org.hibernate.test.Bar bar where bar.baz.stringDateMap['now'] is not null" );
+		parse( "select bar from org.hibernate.test.Bar bar join bar.baz b where b.stringDateMap['big bang'] < b.stringDateMap['now'] and b.stringDateMap['now'] is not null" );
+		parse( "select bar from org.hibernate.test.Bar bar where bar.baz.stringDateMap['big bang'] < bar.baz.stringDateMap['now'] and bar.baz.stringDateMap['now'] is not null" );
+		parse( "select foo.string, foo.component, foo.id from org.hibernate.test.Bar foo" );
+		parse( "select elements(baz.components) from org.hibernate.test.Baz baz" );
+		parse( "select bc.name from org.hibernate.test.Baz baz join baz.components bc" );
+		parse( "from org.hibernate.test.Foo foo where foo.integer < 10 order by foo.string" );
+		parse( "from org.hibernate.test.Fee" );
+		parse( "from org.hibernate.test.Holder h join h.otherHolder oh where h.otherHolder.name = 'bar'" );
+		parse( "from org.hibernate.test.Baz baz join baz.fooSet foo join foo.foo.foo foo2 where foo2.string = 'foo'" );
+		parse( "from org.hibernate.test.Baz baz join baz.fooArray foo join foo.foo.foo foo2 where foo2.string = 'foo'" );
+		parse( "from org.hibernate.test.Baz baz join baz.stringDateMap date where index(date) = 'foo'" );
+		parse( "from org.hibernate.test.Baz baz join baz.topGlarchez g where index(g) = 'A'" );
+		parse( "select index(g) from org.hibernate.test.Baz baz join baz.topGlarchez g" );
+		parse( "from org.hibernate.test.Baz baz left join baz.stringSet" );
+		parse( "from org.hibernate.test.Baz baz join baz.stringSet str where str='foo'" );
+		parse( "from org.hibernate.test.Baz baz left join fetch baz.stringSet" );
+		parse( "from org.hibernate.test.Baz baz join baz.stringSet string where string='foo'" );
+		parse( "from org.hibernate.test.Baz baz inner join baz.components comp where comp.name='foo'" );
+		parse( "from org.hibernate.test.Glarch g inner join g.fooComponents comp where comp.fee is not null" );
+		parse( "from org.hibernate.test.Glarch g inner join g.fooComponents comp join comp.fee fee where fee.count > 0" );
+		parse( "from org.hibernate.test.Glarch g inner join g.fooComponents comp where comp.fee.count is not null" );
+		parse( "from org.hibernate.test.Baz baz left join fetch baz.fooBag" );
+		parse( "from org.hibernate.test.Glarch" );
+		parse( "from org.hibernate.test.Fee" );
+		parse( "from org.hibernate.test.Baz baz left join fetch baz.sortablez order by baz.name asc" );
+		parse( "from org.hibernate.test.Baz baz order by baz.name asc" );
+		parse( "from org.hibernate.test.Foo foo, org.hibernate.test.Baz baz left join fetch baz.fees" );
+		parse( "from org.hibernate.test.Foo foo, org.hibernate.test.Bar bar" );
+		parse( "from org.hibernate.test.Foo foo" );
+		parse( "from org.hibernate.test.Foo foo, org.hibernate.test.Bar bar, org.hibernate.test.Bar bar2" );
+		parse( "from org.hibernate.test.X x" );
+		parse( "from org.hibernate.test.Foo foo" );
+		parse( "select distinct foo from org.hibernate.test.Foo foo" );
+		parse( "from org.hibernate.test.Glarch g where g.multiple.glarch=g and g.multiple.count=12" );
+		parse( "from org.hibernate.test.Bar bar left join bar.baz baz left join baz.cascadingBars b where bar.name like 'Bar %'" );
+		parse( "select bar, b from org.hibernate.test.Bar bar left join bar.baz baz left join baz.cascadingBars b where bar.name like 'Bar%'" );
+		parse( "select bar, b from org.hibernate.test.Bar bar left join bar.baz baz left join baz.cascadingBars b where ( bar.name in (:nameList0_, :nameList1_, :nameList2_) or bar.name in (:nameList0_, :nameList1_, :nameList2_) ) and bar.string = :stringVal" );
+		parse( "select bar, b from org.hibernate.test.Bar bar inner join bar.baz baz inner join baz.cascadingBars b where bar.name like 'Bar%'" );
+		parse( "select bar, b from org.hibernate.test.Bar bar left join bar.baz baz left join baz.cascadingBars b where bar.name like :name and b.name like :name" );
+		parse( "select bar from org.hibernate.test.Bar as bar where bar.x > ? or bar.short = 1 or bar.string = 'ff ? bb'" );
+		parse( "select bar from org.hibernate.test.Bar as bar where bar.string = ' ? ' or bar.string = '?'" );
+		parse( "from org.hibernate.test.Baz baz, baz.fooArray foo" );
+		parse( "from s in class org.hibernate.test.Stuff where s.foo.id = ? and s.id.id = ? and s.moreStuff.id.intId = ? and s.moreStuff.id.stringId = ?" );
+		parse( "from s in class org.hibernate.test.Stuff where s.foo.id = ? and s.id.id = ? and s.moreStuff.name = ?" );
+		parse( "from s in class org.hibernate.test.Stuff where s.foo.string is not null" );
+		parse( "from s in class org.hibernate.test.Stuff where s.foo > '0' order by s.foo" );
+		parse( "from ms in class org.hibernate.test.MoreStuff" );
+		parse( "from foo in class org.hibernate.test.Foo" );
+		parse( "from fee in class org.hibernate.test.Fee" );
+		parse( "select new Result(foo.string, foo.long, foo.integer) from foo in class org.hibernate.test.Foo" );
+		parse( "select new Result( baz.name, foo.long, count(elements(baz.fooArray)) ) from org.hibernate.test.Baz baz join baz.fooArray foo group by baz.name, foo.long" );
+		parse( "select new Result( baz.name, max(foo.long), count(foo) ) from org.hibernate.test.Baz baz join baz.fooArray foo group by baz.name" );
+		parse( "select max( elements(bar.baz.fooArray) ) from org.hibernate.test.Bar as bar" );
+		parse( "from org.hibernate.test.Baz baz left join baz.fooToGlarch join fetch baz.fooArray foo left join fetch foo.foo" );
+		parse( "select baz.name from org.hibernate.test.Bar bar inner join bar.baz baz inner join baz.fooSet foo where baz.name = bar.string" );
+		parse( "SELECT baz.name FROM org.hibernate.test.Bar AS bar INNER JOIN bar.baz AS baz INNER JOIN baz.fooSet AS foo WHERE baz.name = bar.string" );
+		parse( "select baz.name from org.hibernate.test.Bar bar join bar.baz baz left outer join baz.fooSet foo where baz.name = bar.string" );
+		parse( "select baz.name from org.hibernate.test.Bar bar, bar.baz baz, baz.fooSet foo where baz.name = bar.string" );
+		parse( "SELECT baz.name FROM org.hibernate.test.Bar AS bar, bar.baz AS baz, baz.fooSet AS foo WHERE baz.name = bar.string" );
+		parse( "select baz.name from org.hibernate.test.Bar bar left join bar.baz baz left join baz.fooSet foo where baz.name = bar.string" );
+		parse( "select foo.string from org.hibernate.test.Bar bar left join bar.baz.fooSet foo where bar.string = foo.string" );
+		parse( "select baz.name from org.hibernate.test.Bar bar left join bar.baz baz left join baz.fooArray foo where baz.name = bar.string" );
+		parse( "select foo.string from org.hibernate.test.Bar bar left join bar.baz.fooArray foo where bar.string = foo.string" );
+		parse( "select foo from bar in class org.hibernate.test.Bar inner join bar.baz as baz inner join baz.fooSet as foo" );
+		parse( "select foo from bar in class org.hibernate.test.Bar inner join bar.baz.fooSet as foo" );
+		parse( "select foo from bar in class org.hibernate.test.Bar, bar.baz as baz, baz.fooSet as foo" );
+		parse( "select foo from bar in class org.hibernate.test.Bar, bar.baz.fooSet as foo" );
+		parse( "from org.hibernate.test.Bar bar join bar.baz.fooArray foo" );
+		parse( "from bar in class org.hibernate.test.Bar, foo in elements( bar.baz.fooArray )" );
+		parse( "select one.id, elements(one.manies) from one in class org.hibernate.test.One" );
+		parse( "select max( elements(one.manies) ) from one in class org.hibernate.test.One" );
+		parse( "select one, elements(one.manies) from one in class org.hibernate.test.One" );
+		parse( "select one, max(elements(one.manies)) from one in class org.hibernate.test.One group by one" );
+		parse( "select elements(baz.fooArray) from baz in class org.hibernate.test.Baz where baz.id=?" );
+		parse( "select elements(baz.fooArray) from baz in class org.hibernate.test.Baz where baz.id=?" );
+		parse( "select indices(baz.fooArray) from baz in class org.hibernate.test.Baz where baz.id=?" );
+		parse( "select baz, max(elements(baz.timeArray)) from baz in class org.hibernate.test.Baz group by baz" );
+		parse( "select baz, baz.stringSet.size, count(distinct elements(baz.stringSet)), max(elements(baz.stringSet)) from baz in class org.hibernate.test.Baz group by baz" );
+		parse( "select max( elements(baz.timeArray) ) from baz in class org.hibernate.test.Baz where baz.id=?" );
+		parse( "select max(elements(baz.stringSet)) from baz in class org.hibernate.test.Baz where baz.id=?" );
+		parse( "select size(baz.stringSet) from baz in class org.hibernate.test.Baz where baz.id=?" );
+		parse( "from org.hibernate.test.Foo foo where foo.component.glarch.id is not null" );
+		parse( "from baz in class org.hibernate.test.Baz" );
+		parse( "select elements(baz.stringArray) from baz in class org.hibernate.test.Baz" );
+		parse( "from foo in class org.hibernate.test.Foo" );
+		parse( "select elements(baz.stringList) from baz in class org.hibernate.test.Baz" );
+		parse( "select count(*) from org.hibernate.test.Bar" );
+		parse( "select count(*) from b in class org.hibernate.test.Bar" );
+		parse( "from g in class org.hibernate.test.Glarch" );
+		parse( "select baz, baz from baz in class org.hibernate.test.Baz" );
+		parse( "select baz from baz in class org.hibernate.test.Baz order by baz" );
+		parse( "from bar in class org.hibernate.test.Bar" );
+		parse( "from g in class org.hibernate.test.Glarch" );
+		parse( "from f in class org.hibernate.test.Foo" );
+		parse( "from o in class org.hibernate.test.One" );
+		parse( "from q in class org.hibernate.test.Qux" );
+		parse( "select foo from foo in class org.hibernate.test.Foo where foo.string='foo bar'" );
+		parse( "from foo in class org.hibernate.test.Foo order by foo.string, foo.date" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.class='B'" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.class=Bar" );
+		parse( "select bar from bar in class org.hibernate.test.Bar, foo in class org.hibernate.test.Foo where bar.string = foo.string and not bar=foo" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.string='foo bar'" );
+		parse( "select foo from foo in class org.hibernate.test.Foo" );
+		parse( "from bar in class org.hibernate.test.Bar where bar.barString='bar bar'" );
+		parse( "from t in class org.hibernate.test.Trivial" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.date = ?" );
+		parse( "from o in class org.hibernate.test.MoreStuff" );
+		parse( "from o in class org.hibernate.test.Many" );
+		parse( "from o in class org.hibernate.test.Fee" );
+		parse( "from o in class org.hibernate.test.Qux" );
+		parse( "from o in class org.hibernate.test.Y" );
+		parse( "from o in class org.hibernate.test.Fumm" );
+		parse( "from o in class org.hibernate.test.X" );
+		parse( "from o in class org.hibernate.test.Simple" );
+		parse( "from o in class org.hibernate.test.Location" );
+		parse( "from o in class org.hibernate.test.Holder" );
+		parse( "from o in class org.hibernate.test.Part" );
+		parse( "from o in class org.hibernate.test.Baz" );
+		parse( "from o in class org.hibernate.test.Vetoer" );
+		parse( "from o in class org.hibernate.test.Sortable" );
+		parse( "from o in class org.hibernate.test.Contained" );
+		parse( "from o in class org.hibernate.test.Stuff" );
+		parse( "from o in class org.hibernate.test.Immutable" );
+		parse( "from o in class org.hibernate.test.Container" );
+		parse( "from o in class org.hibernate.test.X$XX" );
+		parse( "from o in class org.hibernate.test.One" );
+		parse( "from o in class org.hibernate.test.Foo" );
+		parse( "from o in class org.hibernate.test.Fo" );
+		parse( "from o in class org.hibernate.test.Glarch" );
+		parse( "from o in class org.hibernate.test.Fum" );
+		parse( "from q in class org.hibernate.test.Qux where q.stuff is null" );
+		parse( "from q in class org.hibernate.test.Qux where q.stuff=?" );
+		parse( "from q in class org.hibernate.test.Qux" );
+		parse( "from g in class org.hibernate.test.Glarch where g.version=2" );
+		parse( "from g in class org.hibernate.test.Glarch where g.next is not null" );
+		parse( "from g in class org.hibernate.test.Glarch order by g.order asc" );
+		parse( "from foo in class org.hibernate.test.Foo order by foo.string asc" );
+		parse( "select parent, child from parent in class org.hibernate.test.Foo, child in class org.hibernate.test.Foo where parent.foo = child" );
+		parse( "select count(distinct child.id), count(distinct parent.id) from parent in class org.hibernate.test.Foo, child in class org.hibernate.test.Foo where parent.foo = child" );
+		parse( "select child.id, parent.id, child.long from parent in class org.hibernate.test.Foo, child in class org.hibernate.test.Foo where parent.foo = child" );
+		parse( "select child.id, parent.id, child.long, child, parent.foo from parent in class org.hibernate.test.Foo, child in class org.hibernate.test.Foo where parent.foo = child" );
+		parse( "select parent, child from parent in class org.hibernate.test.Foo, child in class org.hibernate.test.Foo where parent.foo = child and parent.string='a string'" );
+		parse( "from fee in class org.hibernate.test.Fee" );
+		parse( "from org.hibernate.test.Foo foo where foo.custom.s1 = 'one'" );
+		parse( "from im in class org.hibernate.test.Immutable where im = ?" );
+		parse( "from foo in class org.hibernate.test.Foo" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.char='X'" );
+		parse( "select elements(baz.stringArray) from baz in class org.hibernate.test.Baz" );
+		parse( "select distinct elements(baz.stringArray) from baz in class org.hibernate.test.Baz" );
+		parse( "select elements(baz.fooArray) from baz in class org.hibernate.test.Baz" );
+		parse( "from foo in class org.hibernate.test.Fo" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.dependent.qux.foo.string = 'foo2'" );
+		parse( "from org.hibernate.test.Bar bar where bar.object.id = ? and bar.object.class = ?" );
+		parse( "select one from org.hibernate.test.One one, org.hibernate.test.Bar bar where bar.object.id = one.id and bar.object.class = 'O'" );
+		parse( "from l in class org.hibernate.test.Location where l.countryCode = 'AU' and l.description='foo bar'" );
+		parse( "from org.hibernate.test.Bar bar" );
+		parse( "From org.hibernate.test.Bar bar" );
+		parse( "From org.hibernate.test.Foo foo" );
+		parse( "from o in class org.hibernate.test.Baz" );
+		parse( "from o in class org.hibernate.test.Foo" );
+		parse( "from f in class org.hibernate.test.Foo" );
+		parse( "select fum.id from fum in class org.hibernate.test.Fum where not fum.fum='FRIEND'" );
+		parse( "select fum.id from fum in class org.hibernate.test.Fum where not fum.fum='FRIEND'" );
+		parse( "from fum in class org.hibernate.test.Fum where not fum.fum='FRIEND'" );
+		parse( "from fo in class org.hibernate.test.Fo where fo.id.string like 'an instance of fo'" );
+		parse( "from org.hibernate.test.Inner" );
+		parse( "from org.hibernate.test.Outer o where o.id.detailId = ?" );
+		parse( "from org.hibernate.test.Outer o where o.id.master.id.sup.dudu is not null" );
+		parse( "from org.hibernate.test.Outer o where o.id.master.id.sup.id.akey is not null" );
+		parse( "select o.id.master.id.sup.dudu from org.hibernate.test.Outer o where o.id.master.id.sup.dudu is not null" );
+		parse( "select o.id.master.id.sup.id.akey from org.hibernate.test.Outer o where o.id.master.id.sup.id.akey is not null" );
+		parse( "from org.hibernate.test.Outer o where o.id.master.bla = ''" );
+		parse( "from org.hibernate.test.Outer o where o.id.master.id.one = ''" );
+		parse( "from org.hibernate.test.Inner inn where inn.id.bkey is not null and inn.backOut.id.master.id.sup.id.akey > 'a'" );
+		parse( "from org.hibernate.test.Outer as o left join o.id.master m left join m.id.sup where o.bubu is not null" );
+		parse( "from org.hibernate.test.Outer as o left join o.id.master.id.sup s where o.bubu is not null" );
+		parse( "from org.hibernate.test.Outer as o left join o.id.master m left join o.id.master.id.sup s where o.bubu is not null" );
+		parse( "select fum1.fo from fum1 in class org.hibernate.test.Fum where fum1.fo.fum is not null" );
+		parse( "from fum1 in class org.hibernate.test.Fum where fum1.fo.fum is not null order by fum1.fo.fum" );
+		parse( "select elements(fum1.friends) from fum1 in class org.hibernate.test.Fum" );
+		parse( "from fum1 in class org.hibernate.test.Fum, fr in elements( fum1.friends )" );
+		parse( "select new Jay(eye) from org.hibernate.test.Eye eye" );
+		parse( "from org.hibernate.test.Category cat where cat.name='new foo'" );
+		parse( "from org.hibernate.test.Category cat where cat.name='new sub'" );
+		parse( "from org.hibernate.test.Up up order by up.id2 asc" );
+		parse( "from org.hibernate.test.Down down" );
+		parse( "from org.hibernate.test.Up up" );
+		parse( "from m in class org.hibernate.test.Master" );
+		parse( "from s in class org.hibernate.test.Several" );
+		parse( "from s in class org.hibernate.test.Single" );
+		parse( "\n" +
+				"		from d in class \n" +
+				"			org.hibernate.test.Detail\n" +
+				"	" );
+		parse( "from c in class org.hibernate.test.Category where c.name = org.hibernate.test.Category.ROOT_CATEGORY" );
+		parse( "select c from c in class org.hibernate.test.Container, s in class org.hibernate.test.Simple where c.oneToMany[2] = s" );
+		parse( "select c from c in class org.hibernate.test.Container, s in class org.hibernate.test.Simple where c.manyToMany[2] = s" );
+		parse( "select c from c in class org.hibernate.test.Container, s in class org.hibernate.test.Simple where s = c.oneToMany[2]" );
+		parse( "select c from c in class org.hibernate.test.Container, s in class org.hibernate.test.Simple where s = c.manyToMany[2]" );
+		parse( "select c from c in class org.hibernate.test.Container where c.oneToMany[0].name = 's'" );
+		parse( "select c from c in class org.hibernate.test.Container where c.manyToMany[0].name = 's'" );
+		parse( "select c from c in class org.hibernate.test.Container where 's' = c.oneToMany[2 - 2].name" );
+		parse( "select c from c in class org.hibernate.test.Container where 's' = c.manyToMany[(3+1)/4-1].name" );
+		parse( "select c from c in class org.hibernate.test.Container where c.manyToMany[ maxindex(c.manyToMany) ].count = 2" );
+		parse( "select c from c in class org.hibernate.test.Container where c.oneToMany[ c.manyToMany[0].count ].name = 's'" );
+		parse( "select c from org.hibernate.test.Container c where c.manyToMany[ c.oneToMany[0].count ].name = 's'" );
+		parse( "select count(comp.name) from org.hibernate.test.Container c join c.components comp" );
+		parse( "from org.hibernate.test.Parent p left join fetch p.child" );
+		parse( "from org.hibernate.test.Parent p join p.child c where c.x > 0" );
+		parse( "from org.hibernate.test.Child c join c.parent p where p.x > 0" );
+		parse( "from org.hibernate.test.Child" );
+		parse( "from org.hibernate.test.MoreStuff" );
+		parse( "from org.hibernate.test.Many" );
+		parse( "from org.hibernate.test.Fee" );
+		parse( "from org.hibernate.test.Qux" );
+		parse( "from org.hibernate.test.Fumm" );
+		parse( "from org.hibernate.test.Parent" );
+		parse( "from org.hibernate.test.Simple" );
+		parse( "from org.hibernate.test.Holder" );
+		parse( "from org.hibernate.test.Part" );
+		parse( "from org.hibernate.test.Baz" );
+		parse( "from org.hibernate.test.Vetoer" );
+		parse( "from org.hibernate.test.Sortable" );
+		parse( "from org.hibernate.test.Contained" );
+		parse( "from org.hibernate.test.Circular" );
+		parse( "from org.hibernate.test.Stuff" );
+		parse( "from org.hibernate.test.Immutable" );
+		parse( "from org.hibernate.test.Container" );
+		parse( "from org.hibernate.test.One" );
+		parse( "from org.hibernate.test.Foo" );
+		parse( "from org.hibernate.test.Fo" );
+		parse( "from org.hibernate.test.Glarch" );
+		parse( "from org.hibernate.test.Fum" );
+		parse( "from org.hibernate.test.Glarch g" );
+		parse( "from org.hibernate.test.Part" );
+		parse( "from org.hibernate.test.Baz baz join baz.parts" );
+		parse( "from c in class org.hibernate.test.Child where c.parent.count=66" );
+		parse( "from org.hibernate.test.Parent p join p.child c where p.count=66" );
+		parse( "select c, c.parent from c in class org.hibernate.test.Child order by c.parent.count" );
+		parse( "select c, c.parent from c in class org.hibernate.test.Child where c.parent.count=66 order by c.parent.count" );
+		parse( "select c, c.parent, c.parent.count from c in class org.hibernate.test.Child order by c.parent.count" );
+		parse( "FROM p IN CLASS org.hibernate.test.Parent WHERE p.count = ?" );
+		parse( "select count(*) from org.hibernate.test.Container as c join c.components as ce join ce.simple as s where ce.name='foo'" );
+		parse( "select c, s from org.hibernate.test.Container as c join c.components as ce join ce.simple as s where ce.name='foo'" );
+		parse( "from s in class org.hibernate.test.Simple" );
+		parse( "from m in class org.hibernate.test.Many" );
+		parse( "from o in class org.hibernate.test.One" );
+		parse( "from c in class org.hibernate.test.Container" );
+		parse( "from o in class org.hibernate.test.Child" );
+		parse( "from o in class org.hibernate.test.MoreStuff" );
+		parse( "from o in class org.hibernate.test.Many" );
+		parse( "from o in class org.hibernate.test.Fee" );
+		parse( "from o in class org.hibernate.test.Qux" );
+		parse( "from o in class org.hibernate.test.Fumm" );
+		parse( "from o in class org.hibernate.test.Parent" );
+		parse( "from o in class org.hibernate.test.Simple" );
+		parse( "from o in class org.hibernate.test.Holder" );
+		parse( "from o in class org.hibernate.test.Part" );
+		parse( "from o in class org.hibernate.test.Baz" );
+		parse( "from o in class org.hibernate.test.Vetoer" );
+		parse( "from o in class org.hibernate.test.Sortable" );
+		parse( "from o in class org.hibernate.test.Contained" );
+		parse( "from o in class org.hibernate.test.Circular" );
+		parse( "from o in class org.hibernate.test.Stuff" );
+		parse( "from o in class org.hibernate.test.Immutable" );
+		parse( "from o in class org.hibernate.test.Container" );
+		parse( "from o in class org.hibernate.test.One" );
+		parse( "from o in class org.hibernate.test.Foo" );
+		parse( "from o in class org.hibernate.test.Fo" );
+		parse( "from o in class org.hibernate.test.Glarch" );
+		parse( "from o in class org.hibernate.test.Fum" );
+		parse( "from c in class org.hibernate.test.C2 where 1=1 or 1=1" );
+		parse( "from b in class org.hibernate.test.B" );
+		parse( "from a in class org.hibernate.test.A" );
+		parse( "from b in class org.hibernate.test.B" );
+		parse( "from org.hibernate.test.E e join e.reverse as b where b.count=1" );
+		parse( "from org.hibernate.test.E e join e.as as b where b.count=1" );
+		parse( "from org.hibernate.test.B" );
+		parse( "from org.hibernate.test.C1" );
+		parse( "from org.hibernate.test.C2" );
+		parse( "from org.hibernate.test.E e, org.hibernate.test.A a where e.reverse = a.forward and a = ?" );
+		parse( "from org.hibernate.test.E e join fetch e.reverse" );
+		parse( "from org.hibernate.test.E e" );
+		parse( "select max(s.count) from s in class org.hibernate.test.Simple" );
+		parse( "select new org.hibernate.test.S(s.count, s.address) from s in class org.hibernate.test.Simple" );
+		parse( "select max(s.count) from s in class org.hibernate.test.Simple" );
+		parse( "select count(*) from s in class org.hibernate.test.Simple" );
+		parse( "from s in class org.hibernate.test.Simple where s.name=:name and s.count=:count" );
+		parse( "from s in class org.hibernate.test.Simple where s.name in (:several0_, :several1_)" );
+		parse( "from s in class org.hibernate.test.Simple where s.name in (:stuff0_, :stuff1_)" );
+		parse( "from org.hibernate.test.Simple s where s.name=?" );
+		parse( "from org.hibernate.test.Simple s where s.name=:name" );
+		parse( "from s in class org.hibernate.test.Simple where upper( s.name ) ='SIMPLE 1'" );
+		parse( "from s in class org.hibernate.test.Simple where not( upper( s.name ) ='yada' or 1=2 or 'foo'='bar' or not('foo'='foo') or 'foo' like 'bar' )" );
+		parse( "from s in class org.hibernate.test.Simple where lower( s.name || ' foo' ) ='simple 1 foo'" );
+		parse( "from s in class org.hibernate.test.Simple where upper( s.other.name ) ='SIMPLE 2'" );
+		parse( "from s in class org.hibernate.test.Simple where not ( upper( s.other.name ) ='SIMPLE 2' )" );
+		parse( "select distinct s from s in class org.hibernate.test.Simple where ( ( s.other.count + 3 ) = (15*2)/2 and s.count = 69) or ( ( s.other.count + 2 ) / 7 ) = 2" );
+		parse( "select s from s in class org.hibernate.test.Simple where ( ( s.other.count + 3 ) = (15*2)/2 and s.count = 69) or ( ( s.other.count + 2 ) / 7 ) = 2 order by s.other.count" );
+		parse( "select sum(s.count) from s in class org.hibernate.test.Simple group by s.count having sum(s.count) > 10" );
+		parse( "select s.count from s in class org.hibernate.test.Simple group by s.count having s.count = 12" );
+		parse( "select s.id, s.count, count(t), max(t.date) from s in class org.hibernate.test.Simple, t in class org.hibernate.test.Simple where s.count = t.count group by s.id, s.count order by s.count" );
+		parse( "from s in class org.hibernate.test.Simple" );
+		parse( "from s in class org.hibernate.test.Simple where s.name = ?" );
+		parse( "from s in class org.hibernate.test.Simple where s.name = ? and upper(s.name) = ?" );
+		parse( "from s in class org.hibernate.test.Simple where s.name = :foo and upper(s.name) = :bar or s.count=:count or s.count=:count + 1" );
+		parse( "select s.id from s in class org.hibernate.test.Simple" );
+		parse( "select all s, s.other from s in class org.hibernate.test.Simple where s = :s" );
+		parse( "from s in class org.hibernate.test.Simple where s.name in (:name_list0_, :name_list1_) and s.count > :count" );
+		parse( "from org.hibernate.test.Simple s" );
+		parse( "from org.hibernate.test.Simple s" );
+		parse( "from org.hibernate.test.Assignable" );
+		parse( "from org.hibernate.test.Category" );
+		parse( "from org.hibernate.test.Simple" );
+		parse( "from org.hibernate.test.A" );
+		parse( "from foo in class org.hibernate.test.Foo where foo.string=?" );
+		parse( "from foo in class org.hibernate.test.Foo" );
+		parse( "from org.hibernate.test.Po po, org.hibernate.test.Lower low where low.mypo = po" );
+		parse( "from org.hibernate.test.Po po join po.set as sm where sm.amount > 0" );
+		parse( "from org.hibernate.test.Po po join po.top as low where low.foo = 'po'" );
+		parse( "from org.hibernate.test.SubMulti sm join sm.children smc where smc.name > 'a'" );
+		parse( "select s, ya from org.hibernate.test.Lower s join s.yetanother ya" );
+		parse( "from org.hibernate.test.Lower s1 join s1.bag s2" );
+		parse( "from org.hibernate.test.Lower s1 left join s1.bag s2" );
+		parse( "select s, a from org.hibernate.test.Lower s join s.another a" );
+		parse( "select s, a from org.hibernate.test.Lower s left join s.another a" );
+		parse( "from org.hibernate.test.Top s, org.hibernate.test.Lower ls" );
+		parse( "from org.hibernate.test.Lower ls join ls.set s where s.name > 'a'" );
+		parse( "from org.hibernate.test.Po po join po.list sm where sm.name > 'a'" );
+		parse( "from org.hibernate.test.Lower ls inner join ls.another s where s.name is not null" );
+		parse( "from org.hibernate.test.Lower ls where ls.other.another.name is not null" );
+		parse( "from org.hibernate.test.Multi m where m.derived like 'F%'" );
+		parse( "from org.hibernate.test.SubMulti m where m.derived like 'F%'" );
+		parse( "select s from org.hibernate.test.SubMulti as sm join sm.children as s where s.amount>-1 and s.name is null" );
+		parse( "select elements(sm.children) from org.hibernate.test.SubMulti as sm" );
+		parse( "select distinct sm from org.hibernate.test.SubMulti as sm join sm.children as s where s.amount>-1 and s.name is null" );
+		parse( "select distinct s from s in class org.hibernate.test.SubMulti where s.moreChildren[1].amount < 1.0" );
+		parse( "from s in class org.hibernate.test.TrivialClass where s.id = 2" );
+		parse( "select s.count from s in class org.hibernate.test.Top" );
+		parse( "from s in class org.hibernate.test.Lower where s.another.name='name'" );
+		parse( "from s in class org.hibernate.test.Lower where s.yetanother.name='name'" );
+		parse( "from s in class org.hibernate.test.Lower where s.yetanother.name='name' and s.yetanother.foo is null" );
+		parse( "from s in class org.hibernate.test.Top where s.count=1" );
+		parse( "select s.count from s in class org.hibernate.test.Top, ls in class org.hibernate.test.Lower where ls.another=s" );
+		parse( "select elements(ls.bag), elements(ls.set) from ls in class org.hibernate.test.Lower" );
+		parse( "from s in class org.hibernate.test.Lower" );
+		parse( "from s in class org.hibernate.test.Top" );
+		parse( "from sm in class org.hibernate.test.SubMulti" );
+		parse( "select\n" +
+				"\n" +
+				"s from s in class org.hibernate.test.Top where s.count>0" );
+		parse( "from m in class org.hibernate.test.Multi where m.count>0 and m.extraProp is not null" );
+		parse( "from m in class org.hibernate.test.Top where m.count>0 and m.name is not null" );
+		parse( "from m in class org.hibernate.test.Lower where m.other is not null" );
+		parse( "from m in class org.hibernate.test.Multi where m.other.id = 1" );
+		parse( "from m in class org.hibernate.test.SubMulti where m.amount > 0.0" );
+		parse( "from m in class org.hibernate.test.Multi" );
+		parse( "from m in class org.hibernate.test.Multi where m.class = SubMulti" );
+		parse( "from m in class org.hibernate.test.Top where m.class = Multi" );
+		parse( "from s in class org.hibernate.test.Top" );
+		parse( "from ls in class org.hibernate.test.Lower" );
+		parse( "from ls in class org.hibernate.test.Lower, s in elements(ls.bag) where s.id is not null" );
+		parse( "from ls in class org.hibernate.test.Lower, s in elements(ls.set) where s.id is not null" );
+		parse( "from o in class org.hibernate.test.Top" );
+		parse( "from o in class org.hibernate.test.Po" );
+		parse( "from ChildMap cm where cm.parent is not null" );
+		parse( "from ParentMap cm where cm.child is not null" );
+		parse( "from org.hibernate.test.Componentizable" );
+	}
+
+	public void testUnnamedParameter() throws Exception {
+		parse( "select foo, bar from org.hibernate.test.Foo foo left outer join foo.foo bar where foo = ?" ); // Added '?' as a valid expression.
+	}
+
+	public void testInElements() throws Exception {
+		parse( "from bar in class org.hibernate.test.Bar, foo in elements(bar.baz.fooArray)" );   // Added collectionExpr as a valid 'in' clause.
+	}
+
+	public void testDotElements() throws Exception {
+		parse( "select distinct foo from baz in class org.hibernate.test.Baz, foo in elements(baz.fooArray)" );
+		parse( "select foo from baz in class org.hibernate.test.Baz, foo in elements(baz.fooSet)" );
+		parse( "select foo from baz in class org.hibernate.test.Baz, foo in elements(baz.fooArray)" );
+		parse( "from org.hibernate.test.Baz baz where 'b' in elements(baz.collectionComponent.nested.foos) and 1.0 in elements(baz.collectionComponent.nested.floats)" );
+	}
+
+	public void testSelectAll() throws Exception {
+		parse( "select all s, s.other from s in class org.hibernate.test.Simple where s = :s" );
+	}
+
+	public void testNot() throws Exception {
+		// Cover NOT optimization in HqlParser
+		parse( "from eg.Cat cat where not ( cat.kittens.size < 1 )" );
+		parse( "from eg.Cat cat where not ( cat.kittens.size > 1 )" );
+		parse( "from eg.Cat cat where not ( cat.kittens.size >= 1 )" );
+		parse( "from eg.Cat cat where not ( cat.kittens.size <= 1 )" );
+		parse( "from eg.DomesticCat cat where not ( cat.name between 'A' and 'B' ) " );
+		parse( "from eg.DomesticCat cat where not ( cat.name not between 'A' and 'B' ) " );
+		parse( "from eg.Cat cat where not ( not cat.kittens.size <= 1 )" );
+		parse( "from eg.Cat cat where not  not ( not cat.kittens.size <= 1 )" );
+	}
+
+	public void testOtherSyntax() throws Exception {
+		parse( "select bar from org.hibernate.test.Bar bar order by ((bar.x - :valueX)*(bar.x - :valueX))" );
+		parse( "from bar in class org.hibernate.test.Bar, foo in elements(bar.baz.fooSet)" );
+		parse( "from one in class org.hibernate.test.One, many in elements(one.manies) where one.id = 1 and many.id = 1" );
+		parse( "from org.hibernate.test.Inner _inner join _inner.middles middle" );
+		parse( "FROM m IN CLASS org.hibernate.test.Master WHERE NOT EXISTS ( FROM d IN elements(m.details) WHERE NOT d.i=5 )" );
+		parse( "FROM m IN CLASS org.hibernate.test.Master WHERE NOT 5 IN ( SELECT d.i FROM d IN elements(m.details) )" );
+		parse( "SELECT m FROM m IN CLASS org.hibernate.test.Master, d IN elements(m.details) WHERE d.i=5" );
+		parse( "SELECT m FROM m IN CLASS org.hibernate.test.Master, d IN elements(m.details) WHERE d.i=5" );
+		parse( "SELECT m.id FROM m IN CLASS org.hibernate.test.Master, d IN elements(m.details) WHERE d.i=5" );
+		// I'm not sure about these... [jsd]
+//        parse("select bar.string, foo.string from bar in class org.hibernate.test.Bar inner join bar.baz as baz inner join elements(baz.fooSet) as foo where baz.name = 'name'");
+//        parse("select bar.string, foo.string from bar in class org.hibernate.test.Bar, bar.baz as baz, elements(baz.fooSet) as foo where baz.name = 'name'");
+//        parse("select count(*) where this.amount>-1 and this.name is null");
+//        parse("from sm in class org.hibernate.test.SubMulti where exists sm.children.elements");
+	}
+
+	public void testEjbqlExtensions() throws Exception {
+		parse( "select object(a) from Animal a where a.mother member of a.offspring" );
+		parse( "select object(a) from Animal a where a.mother member a.offspring" ); //no member of
+		parse( "select object(a) from Animal a where a.offspring is empty" );
+	}
+
+	public void testEmptyFilter() throws Exception {
+		parseFilter( "" );  //  Blank is a legitimate filter.
+	}
+
+	public void testOrderByFilter() throws Exception {
+		parseFilter( "order by this.id" );
+	}
+
+	public void testRestrictionFilter() throws Exception {
+		parseFilter( "where this.name = ?" );
+	}
+
+	public void testNoFrom() throws Exception {
+		System.out.println( "***** This test ensures that an error is detected ERROR MESSAGES ARE OKAY!  *****" );
+		HqlParser parser = HqlParser.getInstance( "" );
+		parser.setFilter( false );
+		parser.statement();
+		assertEquals( "Parser allowed no FROM clause!", 1, parser.getParseErrorHandler().getErrorCount() );
+		System.out.println( "***** END OF ERROR TEST  *****" );
+	}
+
+	public void testHB1042() throws Exception {
+		parse( "select x from fmc_web.pool.Pool x left join x.containers c0 where (upper(x.name) = upper(':') and c0.id = 1)" );
+	}
+
+	public void testKeywordInPath() throws Exception {
+		// The keyword 'order' used as a property name.
+		parse( "from Customer c where c.order.status = 'argh'" );
+		// The keyword 'order' and 'count' used as a property name.
+		parse( "from Customer c where c.order.count > 3" );
+		// The keywords 'where', 'order' and 'count' used as a property name.
+		parse( "select c.where from Customer c where c.order.count > 3" );
+		parse( "from Interval i where i.end <:end" );
+		parse( "from Letter l where l.case = :case" );
+	}
+
+	public void testPathologicalKeywordAsIdentifier() throws Exception {
+		// Super evil badness... a legitimate keyword!
+		parse( "from Order order" );
+		//parse( "from Order order join order.group" );
+		parse( "from X x order by x.group.by.from" );
+		parse( "from Order x order by x.order.group.by.from" );
+		parse( "select order.id from Order order" );
+		parse( "select order from Order order" );
+		parse( "from Order order where order.group.by.from is not null" );
+		parse( "from Order order order by order.group.by.from" );
+		// Okay, now this is getting silly.
+		parse( "from Group as group group by group.by.from" );
+	}
+
+    public void testHHH354() throws Exception {
+        parse( "from Foo f where f.full = 'yep'");
+    }
+
+    public void testWhereAsIdentifier() throws Exception {
+        // 'where' as a package name
+        parse( "from where.Order" );
+    }
+
+	public void testEjbqlKeywordsAsIdentifier() throws Exception {
+		parse( "from org.hibernate.test.Bar bar where bar.object.id = ? and bar.object.class = ?" );
+	}
+
+	public void testConstructorIn() throws Exception {
+		parse( "from org.hibernate.test.Bar bar where (b.x, b.y, b.z) in (select foo, bar, baz from org.hibernate.test.Foo)" );
+	}
+
+    public void testMultiByteCharacters() throws Exception {
+        parse ("from User user where user.name like '%nn\u4e2dnn%'");
+        // Test for HHH-558
+        parse ("from User user where user.\u432d like '%\u4e2d%'");
+        parse ("from \u432d \u432d where \u432d.name like '%fred%'");        
+    }
+
+    public void testHHH719() throws Exception {
+        // Some SQLs have function names with package qualifiers.
+        parse("from Foo f order by com.fooco.SpecialFunction(f.id)");
+    }
+
+	public void testHHH1107() throws Exception {
+		parse("from Animal where zoo.address.street = '123 Bogus St.'");
+	}
+
+
+	public void testHHH1247() throws Exception {
+		parse("select distinct user.party from com.itf.iceclaims.domain.party.user.UserImpl user inner join user.party.$RelatedWorkgroups relatedWorkgroups where relatedWorkgroups.workgroup.id = :workgroup and relatedWorkgroups.effectiveTime.start <= :datesnow and relatedWorkgroups.effectiveTime.end > :dateenow ");
+	}
+	public void testLineAndColumnNumber() throws Exception {
+		AST ast = doParse("from Foo f\nwhere f.name = 'fred'",false);
+		// Find some of the nodes and check line and column values.
+		ASTIterator iter = new ASTIterator(ast);
+		boolean foundFoo = false;
+		boolean foundName = false;
+		while (iter.hasNext())
+		{
+			AST n = iter.nextNode();
+			if ("Foo".equals(n.getText()))
+			{
+				if (foundFoo)
+					fail("Already found 'Foo'!");
+				foundFoo = true;
+				Node node = (Node)n;
+				assertEquals(1,node.getLine());
+				assertEquals(6,node.getColumn());
+			}
+			else if ("name".equals(n.getText()))
+			{
+				if (foundName)
+					fail("Already found 'name'!");
+				foundName = true;
+				Node node = (Node)n;
+				assertEquals(2,node.getLine());
+				assertEquals(9,node.getColumn());
+			}
+		}
+		assertTrue(foundFoo);
+		assertTrue(foundName);
+	}
+
+	private void parseFilter(String input) throws TokenStreamException, RecognitionException {
+		doParse( input, true );
+	}
+
+	private void parse(String input) throws RecognitionException, TokenStreamException {
+		doParse( input, false );
+	}
+
+	private AST doParse(String input, boolean filter) throws RecognitionException, TokenStreamException {
+		System.out.println( "input: ->" + ASTPrinter.escapeMultibyteChars(input) + "<-" );
+		HqlParser parser = HqlParser.getInstance( input );
+		parser.setFilter( filter );
+		parser.statement();
+		AST ast = parser.getAST();
+		System.out.println( "AST  :  " + ast.toStringTree() + "" );
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		parser.showAst( ast, new PrintStream( baos ) );
+		System.out.println( baos.toString() );
+		assertEquals( "At least one error occurred during parsing!", 0, parser.getParseErrorHandler().getErrorCount() );
+		return ast;
+	}
+
+	public static Test suite() {
+		return new TestSuite( HqlParserTest.class );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Human.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Human.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Human.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,126 @@
+//$Id: Human.java 9873 2006-05-04 13:42:48Z max.andersen at jboss.com $
+package org.hibernate.test.hql;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class Human extends Mammal {
+	private Name name;
+	private String nickName;
+	private Collection friends;
+	private Collection pets;
+	private Map family;
+	private double height;
+	
+	private BigInteger bigIntegerValue;
+	private BigDecimal bigDecimalValue;
+	private int intValue;
+	private float floatValue;
+	
+	private Set nickNames;
+	private Map addresses;
+
+	public Collection getFriends() {
+		return friends;
+	}
+
+	public void setFriends(Collection friends) {
+		this.friends = friends;
+	}
+
+	public Collection getPets() {
+		return pets;
+	}
+
+	public void setPets(Collection pets) {
+		this.pets = pets;
+	}
+
+	public Name getName() {
+		return name;
+	}
+
+	public void setName(Name name) {
+		this.name = name;
+	}
+
+	public String getNickName() {
+		return nickName;
+	}
+
+	public void setNickName(String nickName) {
+		this.nickName = nickName;
+	}
+	
+	public double getHeight() {
+		return height;
+	}
+	public void setHeight(double height) {
+		this.height = height;
+	}
+
+	public Map getFamily() {
+		return family;
+	}
+	
+
+	public void setFamily(Map family) {
+		this.family = family;
+	}
+
+	public Set getNickNames() {
+		return nickNames;
+	}
+
+	public void setNickNames(Set nickNames) {
+		this.nickNames = nickNames;
+	}
+
+	public Map getAddresses() {
+		return addresses;
+	}
+
+	public void setAddresses(Map addresses) {
+		this.addresses = addresses;
+	}
+
+	public BigDecimal getBigDecimalValue() {
+		return bigDecimalValue;
+	}
+
+	public void setBigDecimalValue(BigDecimal bigDecimalValue) {
+		this.bigDecimalValue = bigDecimalValue;
+	}
+
+	public BigInteger getBigIntegerValue() {
+		return bigIntegerValue;
+	}
+
+	public void setBigIntegerValue(BigInteger bigIntegerValue) {
+		this.bigIntegerValue = bigIntegerValue;
+	}
+
+	public float getFloatValue() {
+		return floatValue;
+	}
+
+	public void setFloatValue(float floatValue) {
+		this.floatValue = floatValue;
+	}
+
+	public int getIntValue() {
+		return intValue;
+	}
+
+	public void setIntValue(int intValue) {
+		this.intValue = intValue;
+	}
+	
+	
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Human.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/IntegerVersioned.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/IntegerVersioned.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/IntegerVersioned.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+// $Id: IntegerVersioned.java 7384 2005-07-06 17:04:45Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * Implementation of IntegerVersioned.
+ *
+ * @author Steve Ebersole
+ */
+public class IntegerVersioned {
+	private Long id;
+	private int version = -1;
+	private String name;
+
+	public IntegerVersioned() {
+	}
+
+	public IntegerVersioned(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public int getVersion() {
+		return version;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Joiner.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Joiner.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Joiner.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+// $Id: Joiner.java 6021 2005-03-06 02:02:30Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * Implementation of Joiner.
+ *
+ * @author Steve Ebersole
+ */
+public class Joiner {
+	private Long id;
+	private String name;
+	private String joinedName;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getJoinedName() {
+		return joinedName;
+	}
+
+	public void setJoinedName(String joinedName) {
+		this.joinedName = joinedName;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/KeyManyToOneEntity.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/KeyManyToOneEntity.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/KeyManyToOneEntity.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.hql">
+
+	<class name="KeyManyToOneKeyEntity">
+		<id name="id" type="long" access="field" >
+			<generator class="native"/>
+        </id>
+		<property name="name" type="string"/>
+	</class>
+
+	<class name="KeyManyToOneEntity">
+		<composite-id name="id" access="field" class="KeyManyToOneEntity$Id" unsaved-value="undefined" >
+			<key-many-to-one name="key1" class="KeyManyToOneKeyEntity" />
+			<key-property name="key2" type="string"/>
+		</composite-id>
+		<property name="name" type="string"/> 
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/KeyManyToOneEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/KeyManyToOneEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/KeyManyToOneEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+// $Id: KeyManyToOneEntity.java 7091 2005-06-08 19:31:26Z steveebersole $
+package org.hibernate.test.hql;
+
+import java.io.Serializable;
+
+/**
+ * Implementation of KeyManyToOneEntity.
+ *
+ * @author Steve Ebersole
+ */
+public class KeyManyToOneEntity {
+	private Id id;
+	private String name;
+
+	public KeyManyToOneEntity(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public static class Id implements Serializable {
+		private KeyManyToOneKeyEntity key1;
+		private String key2;
+
+		public Id(KeyManyToOneKeyEntity key1, String key2) {
+			this.key1 = key1;
+			this.key2 = key2;
+		}
+
+		public KeyManyToOneKeyEntity getKey1() {
+			return key1;
+		}
+
+		public void setKey1(KeyManyToOneKeyEntity key1) {
+			this.key1 = key1;
+		}
+
+		public String getKey2() {
+			return key2;
+		}
+
+		public void setKey2(String key2) {
+			this.key2 = key2;
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/KeyManyToOneKeyEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/KeyManyToOneKeyEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/KeyManyToOneKeyEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+// $Id: KeyManyToOneKeyEntity.java 7091 2005-06-08 19:31:26Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * Implementation of KeyManyToOneKeyEntity.
+ *
+ * @author Steve Ebersole
+ */
+public class KeyManyToOneKeyEntity {
+	private Long id;
+	private String name;
+
+	public KeyManyToOneKeyEntity(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Lizard.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Lizard.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Lizard.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+//$Id: Lizard.java 3890 2004-06-03 16:31:32Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * @author Gavin King
+ */
+public class Lizard extends Reptile {
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Mammal.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Mammal.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Mammal.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+//$Id: Mammal.java 6005 2005-03-04 11:41:11Z oneovthafew $
+package org.hibernate.test.hql;
+
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class Mammal extends Animal {
+	private boolean pregnant;
+	private Date birthdate;
+
+	public boolean isPregnant() {
+		return pregnant;
+	}
+
+	public void setPregnant(boolean pregnant) {
+		this.pregnant = pregnant;
+	}
+
+	public Date getBirthdate() {
+		return birthdate;
+	}
+	
+
+	public void setBirthdate(Date birthdate) {
+		this.birthdate = birthdate;
+	}
+	
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/MoreCrazyIdFieldNameStuffEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/MoreCrazyIdFieldNameStuffEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/MoreCrazyIdFieldNameStuffEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+// $Id: MoreCrazyIdFieldNameStuffEntity.java 7471 2005-07-14 14:58:28Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * Implementation of MoreCrazyIdFieldNameStuffEntity.
+ *
+ * @author Steve Ebersole
+ */
+public class MoreCrazyIdFieldNameStuffEntity {
+	private Long moreCrazyIdFieldNameStuffEntity;
+	private HeresAnotherCrazyIdFieldName heresAnotherCrazyIdFieldName; // silly ain't it ;)
+	private String name;
+
+	public MoreCrazyIdFieldNameStuffEntity() {
+	}
+
+	public MoreCrazyIdFieldNameStuffEntity(String name) {
+		this.name = name;
+	}
+
+	public Long getMoreCrazyIdFieldNameStuffEntity() {
+		return moreCrazyIdFieldNameStuffEntity;
+	}
+
+	public void setMoreCrazyIdFieldNameStuffEntity(Long moreCrazyIdFieldNameStuffEntity) {
+		this.moreCrazyIdFieldNameStuffEntity = moreCrazyIdFieldNameStuffEntity;
+	}
+
+	public HeresAnotherCrazyIdFieldName getHeresAnotherCrazyIdFieldName() {
+		return heresAnotherCrazyIdFieldName;
+	}
+
+	public void setHeresAnotherCrazyIdFieldName(HeresAnotherCrazyIdFieldName heresAnotherCrazyIdFieldName) {
+		this.heresAnotherCrazyIdFieldName = heresAnotherCrazyIdFieldName;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Name.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Name.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Name.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+//$Id: Name.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * @author Gavin King
+ */
+public class Name {
+	private String first;
+	private char initial;
+	private String last;
+	
+	protected Name() {}
+	
+	public Name(String first, char initial, String last) {
+		this.first = first;
+		this.initial = initial;
+		this.last = last;
+	}
+
+	public String getFirst() {
+		return first;
+	}
+
+	public void setFirst(String first) {
+		this.first = first;
+	}
+
+	public char getInitial() {
+		return initial;
+	}
+
+	public void setInitial(char initial) {
+		this.initial = initial;
+	}
+
+	public String getLast() {
+		return last;
+	}
+
+	public void setLast(String last) {
+		this.last = last;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Name.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/PettingZoo.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/PettingZoo.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/PettingZoo.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+//$Id: PettingZoo.java 4857 2004-12-02 16:28:57Z oneovthafew $
+package org.hibernate.test.hql;
+
+/**
+ * @author Gavin King
+ */
+public class PettingZoo extends Zoo {
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/PettingZoo.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Pickup.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Pickup.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Pickup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+// $Id: Pickup.java 7087 2005-06-08 18:23:44Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * Implementation of Pickup.
+ *
+ * @author Steve Ebersole
+ */
+public class Pickup extends Truck {
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/QueryTranslatorTestCase.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/QueryTranslatorTestCase.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/QueryTranslatorTestCase.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,546 @@
+// $Id: QueryTranslatorTestCase.java 11361 2007-03-29 12:48:35Z steve.ebersole at jboss.com $
+package org.hibernate.test.hql;
+
+import java.sql.Connection;
+import java.sql.ParameterMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+
+import junit.framework.ComparisonFailure;
+
+import org.hibernate.EntityMode;
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.classic.Session;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.query.HQLQueryPlan;
+import org.hibernate.hql.QueryTranslator;
+import org.hibernate.hql.QueryTranslatorFactory;
+import org.hibernate.hql.ast.ASTQueryTranslatorFactory;
+import org.hibernate.hql.ast.HqlToken;
+import org.hibernate.hql.ast.QueryTranslatorImpl;
+import org.hibernate.hql.ast.util.ASTPrinter;
+import org.hibernate.hql.classic.ClassicQueryTranslatorFactory;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Test case superclass for testing QueryTranslator implementations.
+ *
+ * @author josh Dec 6, 2004 8:21:21 AM
+ */
+public abstract class QueryTranslatorTestCase extends FunctionalTestCase {
+
+	public QueryTranslatorTestCase(String x) {
+		super( x );
+		// Create an instance of HqlToken, so that it will have an entry point outside the package.  This
+		// will stop IDEA's code inspector from suggesting that HqlToken should be package local.
+		new HqlToken();
+	}
+
+	public String[] getMappings() {
+		return new String[] {
+				"hql/Animal.hbm.xml",
+				"hql/EntityWithCrazyCompositeKey.hbm.xml",
+				"hql/CrazyIdFieldNames.hbm.xml",
+				"hql/SimpleEntityWithAssociation.hbm.xml",
+				"hql/ComponentContainer.hbm.xml",
+				"batchfetch/ProductLine.hbm.xml",
+				"cid/Customer.hbm.xml",
+				"cid/Order.hbm.xml",
+				"cid/LineItem.hbm.xml",
+				"cid/Product.hbm.xml",
+				"legacy/Baz.hbm.xml",
+				"legacy/Category.hbm.xml",
+				"legacy/Commento.hbm.xml",
+				"legacy/Container.hbm.xml",
+				"legacy/Custom.hbm.xml",
+				"legacy/Eye.hbm.xml",
+				"legacy/Fee.hbm.xml",
+				"legacy/FooBar.hbm.xml",
+				"legacy/Fum.hbm.xml",
+				"legacy/Glarch.hbm.xml",
+				"legacy/Holder.hbm.xml",
+				"legacy/Many.hbm.xml",
+				"legacy/Marelo.hbm.xml",
+				"legacy/MasterDetail.hbm.xml",
+				"legacy/Middle.hbm.xml",
+				"legacy/Multi.hbm.xml",
+				"legacy/Nameable.hbm.xml",
+				"legacy/One.hbm.xml",
+				"legacy/Qux.hbm.xml",
+				"legacy/Simple.hbm.xml",
+				"legacy/SingleSeveral.hbm.xml",
+				"legacy/WZ.hbm.xml",
+				"legacy/UpDown.hbm.xml",
+				"compositeelement/Parent.hbm.xml",
+				"onetoone/joined/Person.hbm.xml",
+				"any/Properties.hbm.xml"
+		};
+	}
+
+	public boolean createSchema() {
+		return false;
+	}
+
+	public boolean recreateSchemaAfterFailure() {
+		return false;
+	}
+
+	public void assertTranslation(String hql) throws QueryException, MappingException {
+		assertTranslation( hql, null );
+	}
+
+	public void assertTranslation(String hql, boolean scalar) throws QueryException, MappingException {
+		assertTranslation( hql, null, scalar, null );
+	}
+
+	protected void assertTranslation(String hql, Map replacements) {
+		ComparisonFailure cf = null;
+		try {
+			assertTranslation( hql, replacements, false, null );
+		}
+		catch ( ComparisonFailure e ) {
+			e.printStackTrace();
+			cf = e;
+		}
+		if ("false".equals(System.getProperty("org.hibernate.test.hql.SkipScalarQuery","false"))) {
+			// Run the scalar translation anyway, even if there was a comparison failure.
+			assertTranslation( hql, replacements, true, null );
+		}
+		if (cf != null)
+			throw cf;
+	}
+
+	protected void runClassicTranslator(String hql) throws Exception {
+		SessionFactoryImplementor factory = getSessionFactoryImplementor();
+		Map replacements = new HashMap();
+		QueryTranslator oldQueryTranslator = null;
+		try {
+			QueryTranslatorFactory classic = new ClassicQueryTranslatorFactory();
+			oldQueryTranslator = classic.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, factory );
+			oldQueryTranslator.compile( replacements, false );
+		}
+		catch ( Exception e ) {
+			e.printStackTrace();
+			throw e;
+		}
+		String oldsql = oldQueryTranslator.getSQLString();
+		System.out.println( "HQL    : " + hql );
+		System.out.println( "OLD SQL: " + oldsql );
+	}
+
+	protected void assertTranslation(String hql, Map replacements, boolean scalar, String sql) {
+		SessionFactoryImplementor factory = getSessionFactoryImplementor();
+
+		// Create an empty replacements map if we don't have one.
+		if ( replacements == null ) {
+			replacements = new HashMap();
+		}
+
+		// steve -> note that the empty maps here represent the currently enabled filters...
+		QueryTranslator oldQueryTranslator = null;
+		Exception oldException = null;
+		try {
+			System.out.println("Compiling with classic QueryTranslator...");
+			QueryTranslatorFactory classic = new ClassicQueryTranslatorFactory();
+			oldQueryTranslator = classic.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, factory );
+			oldQueryTranslator.compile( replacements, scalar );
+		}
+		catch ( QueryException e ) {
+			oldException = e;
+		}
+		catch ( MappingException e ) {
+			oldException = e;
+		}
+
+		QueryTranslator newQueryTranslator = null;
+		Exception newException = null;
+		try {
+			System.out.println("Compiling with AST QueryTranslator...");
+			newQueryTranslator = createNewQueryTranslator( hql, replacements, scalar );
+		}
+		catch ( QueryException e ) {
+			newException = e;
+		}
+		catch ( MappingException e ) {
+			newException = e;
+		}
+
+		// If the old QT threw an exception, the new one should too.
+		if ( oldException != null ) {
+//			oldException.printStackTrace();
+			assertNotNull( "New query translator did *NOT* throw an exception, the old one did : " + oldException, newException );
+			assertEquals( oldException.getMessage(), newException.getMessage() );
+			return;	// Don't bother with the rest of the assertions.
+		}
+		else if ( newException != null ) {
+			newException.printStackTrace();
+			assertNull( "Old query translator did not throw an exception, the new one did", newException );
+		}
+
+		// -- check all of the outputs --
+		checkSql( oldQueryTranslator, newQueryTranslator, hql, scalar, sql );
+		checkQuerySpaces( oldQueryTranslator, newQueryTranslator );
+		checkReturnedTypes( oldQueryTranslator, newQueryTranslator );
+		checkColumnNames( oldQueryTranslator, newQueryTranslator );
+
+	}
+
+	protected QueryTranslatorImpl createNewQueryTranslator(String hql, Map replacements, boolean scalar) {
+		SessionFactoryImplementor factory = getSessionFactoryImplementor();
+		return createNewQueryTranslator( hql, replacements, scalar, factory );
+	}
+
+	private QueryTranslatorImpl createNewQueryTranslator(String hql, Map replacements, boolean scalar, SessionFactoryImplementor factory) {
+		QueryTranslatorFactory ast = new ASTQueryTranslatorFactory();
+		QueryTranslatorImpl newQueryTranslator = ( QueryTranslatorImpl ) ast.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, factory );
+		newQueryTranslator.compile( replacements, scalar );
+		return newQueryTranslator;
+	}
+
+	protected QueryTranslatorImpl createNewQueryTranslator(String hql) {
+		return createNewQueryTranslator( hql, new HashMap(), false );
+	}
+
+	protected QueryTranslatorImpl createNewQueryTranslator(String hql, SessionFactoryImplementor sfimpl) {
+		return createNewQueryTranslator( hql, new HashMap(), false, sfimpl );
+	}
+
+	protected HQLQueryPlan createQueryPlan(String hql, boolean scalar) {
+		return new HQLQueryPlan( hql, scalar, Collections.EMPTY_MAP, getSessionFactoryImplementor() );
+	}
+
+	protected HQLQueryPlan createQueryPlan(String hql) {
+		return createQueryPlan( hql, false );
+	}
+
+	protected SessionFactoryImplementor getSessionFactoryImplementor() {
+		SessionFactoryImplementor factory = ( SessionFactoryImplementor ) getSessions();
+		if ( factory == null ) {
+			throw new NullPointerException( "Unable to create factory!" );
+		}
+		return factory;
+	}
+
+	private void checkColumnNames(QueryTranslator oldQueryTranslator, QueryTranslator newQueryTranslator) {
+		// Check the column names.
+
+		String[][] oldColumnNames = oldQueryTranslator.getColumnNames();
+		String[][] newColumnNames = newQueryTranslator.getColumnNames();
+		/*assertEquals( "Column name array is not the right length!", oldColumnNames.length, newColumnNames.length );
+		for ( int i = 0; i < oldColumnNames.length; i++ ) {
+			assertEquals( "Column name array [" + i + "] is not the right length!", oldColumnNames[i].length, newColumnNames[i].length );
+			for ( int j = 0; j < oldColumnNames[i].length; j++ ) {
+				assertEquals( "Column name [" + i + "," + j + "]", oldColumnNames[i][j], newColumnNames[i][j] );
+			}
+		}*/
+	}
+
+	private void checkReturnedTypes(QueryTranslator oldQueryTranslator, QueryTranslator newQueryTranslator) {
+		// Check the returned types for a regression.
+		Type[] oldReturnTypes = oldQueryTranslator.getReturnTypes();
+		Type[] returnTypes = newQueryTranslator.getReturnTypes();
+		assertEquals( "Return types array is not the right length!", oldReturnTypes.length, returnTypes.length );
+		for ( int i = 0; i < returnTypes.length; i++ ) {
+			assertNotNull( returnTypes[i] );
+			assertNotNull( oldReturnTypes[i] );
+			assertEquals( "Returned types did not match!", oldReturnTypes[i].getReturnedClass(), returnTypes[i].getReturnedClass() );
+			System.out.println("returnedType[" + i + "] = " + returnTypes[i] + " oldReturnTypes[" + i + "] = " + oldReturnTypes[i]);
+		}
+	}
+
+	private void checkQuerySpaces(QueryTranslator oldQueryTranslator, QueryTranslator newQueryTranslator) {
+		// Check the query spaces for a regression.
+		Set oldQuerySpaces = oldQueryTranslator.getQuerySpaces();
+		Set querySpaces = newQueryTranslator.getQuerySpaces();
+		assertEquals( "Query spaces is not the right size!", oldQuerySpaces.size(), querySpaces.size() );
+		for ( Iterator iterator = oldQuerySpaces.iterator(); iterator.hasNext(); ) {
+			Object o = iterator.next();
+			assertTrue( "New query space does not contain " + o + "!", querySpaces.contains( o ) );
+		}
+	}
+
+	protected Exception compileBadHql(String hql, boolean scalar) {
+		QueryTranslator newQueryTranslator;
+		Map replacements = null;
+		Exception newException = null;
+		SessionFactoryImplementor factory = getSessionFactoryImplementor();
+		try {
+			QueryTranslatorFactory ast = new ASTQueryTranslatorFactory();
+			newQueryTranslator = ast.createQueryTranslator( hql, hql, Collections.EMPTY_MAP, factory );
+			newQueryTranslator.compile( replacements, scalar );
+		}
+		catch ( QueryException e ) {
+			newException = e;
+		}
+		catch ( MappingException e ) {
+			newException = e;
+		}
+		assertNotNull( "Expected exception from compilation of '" + hql + "'!", newException );
+		return newException;
+	}
+
+	private void checkSql(QueryTranslator oldQueryTranslator, QueryTranslator newQueryTranslator, String hql, boolean scalar, String sql) {
+
+		String oldsql = oldQueryTranslator.getSQLString();
+		String newsql = newQueryTranslator.getSQLString();
+		System.out.println( "HQL    : " + ASTPrinter.escapeMultibyteChars(hql) );
+		System.out.println( "OLD SQL: " + ASTPrinter.escapeMultibyteChars(oldsql) );
+		System.out.println( "NEW SQL: " + ASTPrinter.escapeMultibyteChars(newsql) );
+		if ( sql == null ) {
+			// Check the generated SQL.                                          ASTPrinter.escapeMultibyteChars(
+			assertSQLEquals( "SQL is not the same as the old SQL (scalar=" + scalar + ")", oldsql, newsql );
+		}
+		else {
+			assertSQLEquals( "SQL is not the same as the expected SQL (scalar=" + scalar + ")", sql, newsql );
+		}
+	}
+
+	private void assertSQLEquals(String message, String oldsql, String newsql) {
+		Map oldMap = getTokens(oldsql);
+		Map newMap = getTokens(newsql);
+		if ( !oldMap.equals(newMap) ) {
+			assertEquals(message, oldsql, newsql);			
+		}
+		
+		//String oldsqlStripped = stripExtraSpaces( oldsql );
+		//String newsqlStripped = stripExtraSpaces( newsql );
+		//assertEquals( message, oldsqlStripped, newsqlStripped );
+	}
+
+	
+	private Map getTokens(String sql) {
+		Map result = new TreeMap();
+		if (sql==null) return result;
+		result.put( "=", new Integer( StringHelper.countUnquoted(sql, '=') ) );
+		StringTokenizer tokenizer = new StringTokenizer( sql, "(),= " );
+		while ( tokenizer.hasMoreTokens() ) {
+			String fragment = tokenizer.nextToken();
+			/*if ( "on".equals(fragment) ) fragment = "and";
+			if ( "join".equals(fragment) || "inner".equals(fragment) ) continue;*/
+			Integer count = (Integer) result.get(fragment);
+			if ( count==null ) {
+				count = new Integer(1);
+			}
+			else {
+				count = new Integer( count.intValue() + 1 );
+			}
+			result.put(fragment, count);
+		}
+		return result;
+	}
+	
+	private String stripExtraSpaces(String string) {
+		if ( string == null ) {
+			return null;
+		}
+
+		StringBuffer buffer = new StringBuffer( string.length() );
+		char[] chars = string.toCharArray();
+		int length = chars.length;
+		boolean wasSpace = false;
+		for ( int i = 0; i < length; i++ ) {
+			boolean isSpace = chars[i] == ' ';
+			if ( wasSpace && isSpace ) {
+				continue;
+			}
+			else {
+				buffer.append( chars[i] );
+			}
+
+			wasSpace = isSpace;
+		}
+//		StringTokenizer tokenizer = new StringTokenizer( string.trim(), " " );
+//		while ( tokenizer.hasMoreTokens() ) {
+//			final String fragment = tokenizer.nextToken();
+//			buffer.append( fragment );
+//			buffer.append( " " );
+//		}
+//
+		return buffer.toString();
+	}
+
+	private void checkSqlByResultSet(
+	        QueryTranslator oldQueryTranslator,
+	        QueryTranslator newQueryTranslator,
+	        Object[] binds
+	) {
+		String oldsql = oldQueryTranslator.getSQLString();
+		String newsql = newQueryTranslator.getSQLString();
+
+		Session session = openSession();
+		Connection connection = session.connection();
+
+		PreparedStatement oldps = null;
+		PreparedStatement newps = null;
+		ResultSet oldrs = null;
+		ResultSet newrs = null;
+
+		try {
+			try {
+				oldps = connection.prepareStatement( oldsql );
+			}
+			catch( Throwable t ) {
+				fail( "Unable to prepare sql generated by old parser : " + t );
+			}
+			try {
+				newps = connection.prepareStatement( newsql );
+			}
+			catch( Throwable t ) {
+				fail( "Unable to prepare sql generated by new parser : " + t );
+			}
+
+			checkBinds(oldps, newps, binds);
+
+			try {
+				oldrs = executeQuery( oldps, binds );
+			}
+			catch( Throwable t ) {
+				fail( "Unable to execute sql generated by old parser : " + t );
+			}
+
+			try {
+				newrs = executeQuery( newps, binds );
+			}
+			catch( Throwable t ) {
+				fail( "Unable to execute sql generated by new parser : " + t );
+			}
+
+			checkResults( oldrs, newrs );
+		}
+		finally {
+			// make *sure* the sql resources get cleaned up
+			release(oldrs);
+			release(newrs);
+			release(oldps);
+			release(newps);
+			release(session);
+		}
+	}
+
+	private void checkBinds(PreparedStatement oldps, PreparedStatement newps, Object[] binds) {
+		// Make sure the binds "feel" ok
+		try {
+			ParameterMetaData oldBindMetaData = oldps.getParameterMetaData();
+			ParameterMetaData newBindMetaData = newps.getParameterMetaData();
+
+			assertEquals( "Different bind parameter count", oldBindMetaData.getParameterCount(), newBindMetaData.getParameterCount() );
+			assertEquals( "Incorrect number of binds passed in", oldBindMetaData.getParameterCount(), binds == null ? 0 : binds.length );
+
+			for ( int i = 0, max = oldBindMetaData.getParameterCount(); i < max; i++ ) {
+				assertEquals( "Different bind types", oldBindMetaData.getParameterType(i), newBindMetaData.getParameterType(i) );
+			}
+		}
+		catch( Throwable t ) {
+			fail( "SQLException comparing binds : " + t );
+		}
+	}
+
+	private ResultSet executeQuery(PreparedStatement ps, Object[] binds) throws SQLException {
+		if ( binds != null ) {
+			for ( int i = 0, max = binds.length; i < max; i++ ) {
+				ps.setObject( i, binds[i] );
+			}
+		}
+
+		return ps.executeQuery();
+	}
+
+	private void checkResults(ResultSet oldrs, ResultSet newrs) {
+		ResultSetMetaData oldmeta = null;
+		ResultSetMetaData newmeta = null;
+		int colCount = 0;
+		Type[] types = null;
+
+		// first compare the metadata from the two results
+		try {
+			oldmeta = oldrs.getMetaData();
+			newmeta = newrs.getMetaData();
+			assertEquals( "Different column counts", oldmeta.getColumnCount(), newmeta.getColumnCount() );
+
+			colCount = oldmeta.getColumnCount();
+			types = new Type[colCount];
+
+			for ( int i = 1, max = colCount; i < max; i++ ) {
+				assertEquals( "Column names were different", oldmeta.getColumnName(i), newmeta.getColumnName(i) );
+				assertEquals( "Column types were different", oldmeta.getColumnType(i), newmeta.getColumnType(i) );
+				assertEquals( "Java types were different", oldmeta.getColumnClassName(i), newmeta.getColumnClassName(i) );
+				types[i] = TypeFactory.basic( oldmeta.getColumnClassName(i) );
+			}
+		}
+		catch( Throwable t ) {
+			fail( "Error comparing result set metadata" );
+		}
+
+		// Then compare the actual results
+		try {
+			while ( oldrs.next() & newrs.next() ) {
+				for ( int i = 1; i < colCount; i++ ) {
+					Object oldval = oldrs.getObject(i);
+					if ( oldrs.wasNull() ) oldval = null;
+					Object newval = newrs.getObject(i);
+					if ( newrs.wasNull() ) newval = null;
+					checkLogicalEquality( oldval, newval, types[i] );
+				}
+			}
+
+			// for "better reporting" purposes, make sure both result sets are fully exhausted
+			while ( oldrs.next() );
+			while ( newrs.next() );
+
+			assertEquals( "Different row counts", oldrs.getRow(), newrs.getRow() );
+		}
+		catch( Throwable t ) {
+			fail( "Error comparing result set structure" );
+		}
+	}
+
+	private void checkLogicalEquality(Object oldval, Object newval, Type type) {
+		if ( oldval == null && newval == null ) {
+			// two nulls are logically equivalent here...
+			return;
+		}
+		else {
+			assertTrue( "Different result values", type.isEqual(oldval, newval, EntityMode.POJO) );
+		}
+	}
+
+	private void release(PreparedStatement ps) {
+		if ( ps != null ) {
+			try {
+				ps.close();
+			}
+			catch( Throwable t ) {}
+		}
+	}
+
+	private void release(ResultSet rs) {
+		if ( rs != null ) {
+			try {
+				rs.close();
+			}
+			catch( Throwable t ) {}
+		}
+	}
+
+	private void release(Session session) {
+		if ( session != null ) {
+			try {
+				session.close();
+			}
+			catch( Throwable t ) {}
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Reptile.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Reptile.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Reptile.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+//$Id: Reptile.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * @author Gavin King
+ */
+public class Reptile extends Animal {
+	private float bodyTemperature;
+	public float getBodyTemperature() {
+		return bodyTemperature;
+	}
+	public void setBodyTemperature(float bodyTemperature) {
+		this.bodyTemperature = bodyTemperature;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SUV.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SUV.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SUV.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+// $Id: SUV.java 7087 2005-06-08 18:23:44Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * Implementation of SUV.
+ *
+ * @author Steve Ebersole
+ */
+public class SUV extends Truck {
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ScrollableCollectionFetchingTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ScrollableCollectionFetchingTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/ScrollableCollectionFetchingTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,220 @@
+// $Id: ScrollableCollectionFetchingTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.hql;
+
+import junit.framework.Test;
+
+import org.hibernate.HibernateException;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Tests the new functionality of allowing scrolling of results which
+ * contain collection fetches.
+ *
+ * @author Steve Ebersole
+ */
+public class ScrollableCollectionFetchingTest extends FunctionalTestCase {
+
+	public ScrollableCollectionFetchingTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ScrollableCollectionFetchingTest.class );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "hql/Animal.hbm.xml" };
+	}
+
+	public void testTupleReturnFails() {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+
+		try {
+			s.createQuery( "select a, a.weight from Animal a inner join fetch a.offspring" ).scroll();
+			fail( "scroll allowed with collection fetch and reurning tuples" );
+		}
+		catch( HibernateException e ) {
+			// expected result...
+		}
+
+		txn.commit();
+		s.close();
+	}
+
+	public void testScrollingJoinFetchesForward() {
+		if ( ! supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() ) {
+			return;
+		}
+
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+
+		ScrollableResults results = s
+		        .createQuery( "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" )
+		        .setString( "desc", "root%" )
+				.scroll( ScrollMode.FORWARD_ONLY );
+
+		int counter = 0;
+		while ( results.next() ) {
+			counter++;
+			Animal animal = ( Animal ) results.get( 0 );
+			checkResult( animal );
+		}
+		assertEquals( "unexpected result count", 2, counter );
+
+		txn.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testScrollingJoinFetchesReverse() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+
+		ScrollableResults results = s
+		        .createQuery( "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" )
+		        .setString( "desc", "root%" )
+		        .scroll();
+
+		results.afterLast();
+
+		int counter = 0;
+		while ( results.previous() ) {
+			counter++;
+			Animal animal = ( Animal ) results.get( 0 );
+			checkResult( animal );
+		}
+		assertEquals( "unexpected result count", 2, counter );
+
+		txn.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testScrollingJoinFetchesPositioning() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+
+		ScrollableResults results = s
+		        .createQuery( "from Animal a left join fetch a.offspring where a.description like :desc order by a.id" )
+		        .setString( "desc", "root%" )
+		        .scroll();
+
+		results.first();
+		Animal animal = ( Animal ) results.get( 0 );
+		assertEquals( "first() did not return expected row", data.root1Id, animal.getId() );
+
+		results.scroll( 1 );
+		animal = ( Animal ) results.get( 0 );
+		assertEquals( "scroll(1) did not return expected row", data.root2Id, animal.getId() );
+
+		results.scroll( -1 );
+		animal = ( Animal ) results.get( 0 );
+		assertEquals( "scroll(-1) did not return expected row", data.root1Id, animal.getId() );
+
+		results.setRowNumber( 1 );
+		animal = ( Animal ) results.get( 0 );
+		assertEquals( "setRowNumber(1) did not return expected row", data.root1Id, animal.getId() );
+
+		results.setRowNumber( 2 );
+		animal = ( Animal ) results.get( 0 );
+		assertEquals( "setRowNumber(2) did not return expected row", data.root2Id, animal.getId() );
+
+		txn.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	private void checkResult(Animal animal) {
+		if ( "root-1".equals( animal.getDescription() ) ) {
+			assertEquals( "root-1 did not contain both children", 2, animal.getOffspring().size() );
+		}
+		else if ( "root-2".equals( animal.getDescription() ) ) {
+			assertEquals( "root-2 did not contain zero children", 0, animal.getOffspring().size() );
+		}
+	}
+
+	private class TestData {
+
+		private Long root1Id;
+		private Long root2Id;
+
+		private void prepare() {
+			Session s = openSession();
+			Transaction txn = s.beginTransaction();
+
+			Animal mother = new Animal();
+			mother.setDescription( "root-1" );
+
+			Animal another = new Animal();
+			another.setDescription( "root-2" );
+
+			Animal son = new Animal();
+			son.setDescription( "son");
+
+			Animal daughter = new Animal();
+			daughter.setDescription( "daughter" );
+
+			Animal grandson = new Animal();
+			grandson.setDescription( "grandson" );
+
+			Animal grandDaughter = new Animal();
+			grandDaughter.setDescription( "granddaughter" );
+
+			son.setMother( mother );
+			mother.addOffspring( son );
+
+			daughter.setMother( mother );
+			mother.addOffspring( daughter );
+
+			grandson.setMother( daughter );
+			daughter.addOffspring( grandson );
+
+			grandDaughter.setMother( daughter );
+			daughter.addOffspring( grandDaughter );
+
+			s.save( mother );
+			s.save( another );
+			s.save( son );
+			s.save( daughter );
+			s.save( grandson );
+			s.save( grandDaughter );
+
+			txn.commit();
+			s.close();
+
+			root1Id = mother.getId();
+			root2Id = another.getId();
+		}
+
+		private void cleanup() {
+			Session s = openSession();
+			Transaction txn = s.beginTransaction();
+			
+			s.createQuery( "delete Animal where description like 'grand%'" ).executeUpdate();
+			s.createQuery( "delete Animal where not description like 'root%'" ).executeUpdate();
+			s.createQuery( "delete Animal" ).executeUpdate();
+
+			txn.commit();
+			s.close();
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SimpleAssociatedEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SimpleAssociatedEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SimpleAssociatedEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+package org.hibernate.test.hql;
+
+/**
+ * @author Steve Ebersole
+ */
+public class SimpleAssociatedEntity {
+	private Long id;
+	private String name;
+	private SimpleEntityWithAssociation owner;
+
+	public SimpleAssociatedEntity() {
+	}
+
+	public SimpleAssociatedEntity(String name) {
+		this.name = name;
+	}
+
+	public SimpleAssociatedEntity(String name, SimpleEntityWithAssociation owner) {
+		this( name );
+		bindToOwner( owner );
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public SimpleEntityWithAssociation getOwner() {
+		return owner;
+	}
+
+	public void setOwner(SimpleEntityWithAssociation owner) {
+		this.owner = owner;
+	}
+
+	public void bindToOwner(SimpleEntityWithAssociation owner) {
+		if ( owner != this.owner ) {
+			unbindFromCurrentOwner();
+			if ( owner != null ) {
+				owner.getAssociatedEntities().add( this );
+			}
+		}
+		this.owner = owner;
+	}
+
+	public void unbindFromCurrentOwner() {
+		if ( this.owner != null ) {
+			this.owner.getAssociatedEntities().remove( this );
+			this.owner = null;
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SimpleEntityWithAssociation.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SimpleEntityWithAssociation.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SimpleEntityWithAssociation.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.hql">
+
+    <!-- *Very* important for the test cases that these entities have identically named columns! -->
+
+    <class name="SimpleEntityWithAssociation" table="SIMPLE_1">
+        <id name="id" column="ID" type="long">
+            <generator class="native"/>
+        </id>
+        <property name="name" column="NAME" type="string"/>
+        <set name="associatedEntities" cascade="all" inverse="true" lazy="true">
+            <key column="SIMPLE_1_ID"/>
+            <one-to-many class="SimpleAssociatedEntity"/>
+        </set>
+        <set name="manyToManyAssociatedEntities" cascade="save-update" inverse="false" lazy="true" table="MANY_TO_MANY">
+            <key column="IN_ID"/>
+            <many-to-many class="SimpleEntityWithAssociation" column="OUT_ID"/>
+        </set>
+    </class>
+
+    <class name="SimpleAssociatedEntity" table="SIMPLE_2">
+        <id name="id" column="ID" type="long">
+            <generator class="native"/>
+        </id>
+        <property name="name" column="NAME" type="string" />
+        <many-to-one name="owner" class="SimpleEntityWithAssociation" column="SIMPLE_1_ID"/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SimpleEntityWithAssociation.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SimpleEntityWithAssociation.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/SimpleEntityWithAssociation.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,70 @@
+package org.hibernate.test.hql;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * @author Steve Ebersole
+ */
+public class SimpleEntityWithAssociation {
+	private Long id;
+	private String name;
+	private Set associatedEntities = new HashSet();
+	private Set manyToManyAssociatedEntities = new HashSet();
+
+	public SimpleEntityWithAssociation() {
+	}
+
+	public SimpleEntityWithAssociation(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Set getAssociatedEntities() {
+		return associatedEntities;
+	}
+
+	public void setAssociatedEntities(Set associatedEntities) {
+		this.associatedEntities = associatedEntities;
+	}
+
+	public SimpleAssociatedEntity addAssociation(String name) {
+		return new SimpleAssociatedEntity( name, this );
+	}
+
+	public void addAssociation(SimpleAssociatedEntity association) {
+		association.bindToOwner( this );
+	}
+
+	public void removeAssociation(SimpleAssociatedEntity association) {
+		if ( getAssociatedEntities().contains( association ) ) {
+			association.unbindFromCurrentOwner();
+		}
+		else {
+			throw new IllegalArgumentException( "SimpleAssociatedEntity [" + association + "] not currently bound to this [" + this + "]" );
+		}
+	}
+
+	public Set getManyToManyAssociatedEntities() {
+		return manyToManyAssociatedEntities;
+	}
+
+	public void setManyToManyAssociatedEntities(Set manyToManyAssociatedEntities) {
+		this.manyToManyAssociatedEntities = manyToManyAssociatedEntities;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/StateProvince.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/StateProvince.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/StateProvince.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+// $Id: StateProvince.java 7996 2005-08-22 14:49:57Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * Implementation of StateProvince.
+ *
+ * @author Steve Ebersole
+ */
+public class StateProvince {
+	private Long id;
+	private String name;
+	private String isoCode;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getIsoCode() {
+		return isoCode;
+	}
+
+	public void setIsoCode(String isoCode) {
+		this.isoCode = isoCode;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/TimestampVersioned.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/TimestampVersioned.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/TimestampVersioned.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+// $Id: TimestampVersioned.java 7384 2005-07-06 17:04:45Z steveebersole $
+package org.hibernate.test.hql;
+
+import java.util.Date;
+
+/**
+ * Implementation of TimestampVersioned.
+ *
+ * @author Steve Ebersole
+ */
+public class TimestampVersioned {
+	private Long id;
+	private Date version;
+	private String name;
+
+	public TimestampVersioned() {
+	}
+
+	public TimestampVersioned(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public Date getVersion() {
+		return version;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Truck.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Truck.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Truck.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+// $Id: Truck.java 7087 2005-06-08 18:23:44Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * Implementation of Truck.
+ *
+ * @author Steve Ebersole
+ */
+public class Truck extends Vehicle {
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+//$Id: User.java 5891 2005-02-24 01:18:15Z oneovthafew $
+package org.hibernate.test.hql;
+
+import java.util.List;
+
+/**
+ * @author Gavin King
+ */
+public class User {
+	private Long id;
+	private String userName;
+	private Human human;
+	private List permissions;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getUserName() {
+		return userName;
+	}
+
+	public void setUserName(String userName) {
+		this.userName = userName;
+	}
+
+	public Human getHuman() {
+		return human;
+	}
+
+	public void setHuman(Human human) {
+		this.human = human;
+	}
+
+	public List getPermissions() {
+		return permissions;
+	}
+	
+
+	public void setPermissions(List permissions) {
+		this.permissions = permissions;
+	}
+	
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/User.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Vehicle.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Vehicle.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Vehicle.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.hql">
+
+	<!-- Vehicle represents an abstract root of a union-subclass hierarchy -->
+	<class name="Vehicle" abstract="true">
+		<id name="id" access="field" type="long">
+			<generator class="increment"/>
+		</id>
+		<property name="vin" type="string"/>
+		<property name="owner" type="string"/>
+
+		<!-- Car represents a concrete leaf of a union-subclass hierarchy with no concrete super -->
+		<union-subclass name="Car"/>
+
+		<!-- Truck represents a concrete subclass in a union-subclass hierarchy with concrete subclasses and no concrete super -->
+		<union-subclass name="Truck">
+			<!-- Both SUV and Pickup represent concrete leaf of a union-subclass hierarchy (like Car), but with a concrete super -->
+			<union-subclass name="SUV"/>
+			<union-subclass name="Pickup"/>
+		</union-subclass>
+	</class>
+
+	<sql-query name="native-delete-car">
+	    <synchronize table="Car"/>
+		delete from CAR where owner = ?
+	</sql-query>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Vehicle.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Vehicle.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Vehicle.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+// $Id: Vehicle.java 7087 2005-06-08 18:23:44Z steveebersole $
+package org.hibernate.test.hql;
+
+/**
+ * Implementation of Vehicle.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class Vehicle {
+	private Long id;
+	private String vin;
+	private String owner;
+
+	public String getVin() {
+		return vin;
+	}
+
+	public void setVin(String vin) {
+		this.vin = vin;
+	}
+
+	public String getOwner() {
+		return owner;
+	}
+
+	public void setOwner(String owner) {
+		this.owner = owner;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Versions.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Versions.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Versions.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.hql" default-access="field">
+
+	<class name="IntegerVersioned">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+        <version name="version" column="vers"/>
+		<property name="name"/>
+	</class>
+
+	<class name="TimestampVersioned">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+        <timestamp name="version" column="vers"/> 
+		<property name="name"/>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/WithClauseTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/WithClauseTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/WithClauseTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,196 @@
+// $Id: WithClauseTest.java 10945 2006-12-07 14:50:42Z steve.ebersole at jboss.com $
+package org.hibernate.test.hql;
+
+import org.hibernate.test.TestCase;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.HibernateException;
+import org.hibernate.QueryException;
+import org.hibernate.hql.ast.InvalidWithClauseException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Implementation of WithClauseTest.
+ *
+ * @author Steve Ebersole
+ */
+public class WithClauseTest extends TestCase {
+
+	public WithClauseTest(String name) {
+		super( name );
+	}
+
+	protected String[] getMappings() {
+		return new String[] { "hql/Animal.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new TestSuite( WithClauseTest.class );
+	}
+
+	protected void configure(Configuration cfg) {
+		super.configure( cfg );
+	}
+
+	public void testWithClauseFailsWithFetch() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+
+		try {
+			s.createQuery( "from Animal a inner join fetch a.offspring as o with o.bodyWeight = :someLimit" )
+			        .setDouble( "someLimit", 1 )
+			        .list();
+			fail( "ad-hoc on clause allowed with fetched association" );
+		}
+		catch ( HibernateException e ) {
+			// the expected response...
+		}
+
+		txn.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	public void testInvalidWithSemantics() {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+
+		try {
+			// PROBLEM : f.bodyWeight is a reference to a column on the Animal table; however, the 'f'
+			// alias relates to the Human.friends collection which the aonther Human entity.  The issue
+			// here is the way JoinSequence and Joinable (the persister) interact to generate the
+			// joins relating to the sublcass/superclass tables
+			s.createQuery( "from Human h inner join h.friends as f with f.bodyWeight < :someLimit" )
+					.setDouble( "someLimit", 1 )
+					.list();
+			fail( "failure expected" );
+		}
+		catch( InvalidWithClauseException expected ) {
+		}
+
+		try {
+			s.createQuery( "from Animal a inner join a.offspring o inner join o.mother as m inner join m.father as f with o.bodyWeight > 1" )
+					.list();
+			fail( "failure expected" );
+		}
+		catch( InvalidWithClauseException expected ) {
+		}
+
+		try {
+			s.createQuery( "from Human h inner join h.offspring o with o.mother.father = :cousin" )
+					.setEntity( "cousin", s.load( Human.class, new Long(123) ) )
+					.list();
+			fail( "failure expected" );
+		}
+		catch( InvalidWithClauseException expected ) {
+		}
+
+		txn.commit();
+		s.close();
+	}
+
+	public void testWithClause() {
+		TestData data = new TestData();
+		data.prepare();
+
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+
+		// one-to-many
+		List list = s.createQuery( "from Human h inner join h.offspring as o with o.bodyWeight < :someLimit" )
+				.setDouble( "someLimit", 1 )
+				.list();
+		assertTrue( "ad-hoc on did not take effect", list.isEmpty() );
+
+		// many-to-one
+		list = s.createQuery( "from Animal a inner join a.mother as m with m.bodyWeight < :someLimit" )
+				.setDouble( "someLimit", 1 )
+				.list();
+		assertTrue( "ad-hoc on did not take effect", list.isEmpty() );
+
+		// many-to-many
+		list = s.createQuery( "from Human h inner join h.friends as f with f.nickName like 'bubba'" )
+				.list();
+		assertTrue( "ad-hoc on did not take effect", list.isEmpty() );
+
+		txn.commit();
+		s.close();
+
+		data.cleanup();
+	}
+
+	private class TestData {
+		public void prepare() {
+			Session session = openSession();
+			Transaction txn = session.beginTransaction();
+
+			Human mother = new Human();
+			mother.setBodyWeight( 10 );
+			mother.setDescription( "mother" );
+
+			Human father = new Human();
+			father.setBodyWeight( 15 );
+			father.setDescription( "father" );
+
+			Human child1 = new Human();
+			child1.setBodyWeight( 5 );
+			child1.setDescription( "child1" );
+
+			Human child2 = new Human();
+			child2.setBodyWeight( 6 );
+			child2.setDescription( "child2" );
+
+			Human friend = new Human();
+			friend.setBodyWeight( 20 );
+			friend.setDescription( "friend" );
+
+			child1.setMother( mother );
+			child1.setFather( father );
+			mother.addOffspring( child1 );
+			father.addOffspring( child1 );
+
+			child2.setMother( mother );
+			child2.setFather( father );
+			mother.addOffspring( child2 );
+			father.addOffspring( child2 );
+
+			father.setFriends( new ArrayList() );
+			father.getFriends().add( friend );
+
+			session.save( mother );
+			session.save( father );
+			session.save( child1 );
+			session.save( child2 );
+			session.save( friend );
+
+			txn.commit();
+			session.close();
+		}
+
+		public void cleanup() {
+			Session session = openSession();
+			Transaction txn = session.beginTransaction();
+			session.createQuery( "delete Animal where mother is not null" ).executeUpdate();
+			List humansWithFriends = session.createQuery( "from Human h where exists(from h.friends)" ).list();
+			Iterator itr = humansWithFriends.iterator();
+			while ( itr.hasNext() ) {
+				session.delete( itr.next() );
+			}
+			session.createQuery( "delete Animal" ).executeUpdate();
+			txn.commit();
+			session.close();
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Zoo.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Zoo.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/hql/Zoo.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+//$Id: Zoo.java 10653 2006-10-26 13:38:50Z steve.ebersole at jboss.com $
+package org.hibernate.test.hql;
+
+import java.util.Map;
+
+/**
+ * @author Gavin King
+ */
+public class Zoo {
+	private Long id;
+	private String name;
+	private Classification classification;
+	private Map animals;
+	private Map mammals;
+	private Address address;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Map getMammals() {
+		return mammals;
+	}
+
+	public void setMammals(Map mammals) {
+		this.mammals = mammals;
+	}
+
+	public Map getAnimals() {
+		return animals;
+	}
+
+	public void setAnimals(Map animals) {
+		this.animals = animals;
+	}
+
+	public Address getAddress() {
+		return address;
+	}
+
+	public void setAddress(Address address) {
+		this.address = address;
+	}
+
+	public Classification getClassification() {
+		return classification;
+	}
+
+	public void setClassification(Classification classification) {
+		this.classification = classification;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Car.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Car.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Car.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+  This mapping demonstrates the use of
+  the EJB3 compliant table hilo generator
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.id">
+
+    <class name="Car">
+    
+    	<id name="id">
+    		<generator class="org.hibernate.id.MultipleHiLoPerTableGenerator">
+				<param name="max_lo">0</param>
+ 			</generator>
+    	</id>
+        <property name="color"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Car.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Car.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Car.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: Car.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.id;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class Car {
+	private Long id;
+	private String color;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getColor() {
+		return color;
+	}
+
+	public void setColor(String color) {
+		this.color = color;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/MultipleHiLoPerTableGeneratorTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/MultipleHiLoPerTableGeneratorTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/MultipleHiLoPerTableGeneratorTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,107 @@
+//$Id: MultipleHiLoPerTableGeneratorTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.id;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class MultipleHiLoPerTableGeneratorTest extends FunctionalTestCase {
+	public MultipleHiLoPerTableGeneratorTest(String x) {
+		super(x);
+	}
+
+	public String[] getMappings() {
+		return new String[]{ "id/Car.hbm.xml", "id/Plane.hbm.xml", "id/Radio.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( MultipleHiLoPerTableGeneratorTest.class );
+	}
+
+	public void testDistinctId() throws Exception {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		int testLength = 8;
+		Car[] cars = new Car[testLength];
+		Plane[] planes = new Plane[testLength];
+		for (int i = 0; i < testLength ; i++) {
+			cars[i] = new Car();
+			cars[i].setColor("Color" + i);
+			planes[i] = new Plane();
+			planes[i].setNbrOfSeats(i);
+			s.persist(cars[i]);
+			//s.persist(planes[i]);
+		}
+		tx.commit();
+		s.close();
+		for (int i = 0; i < testLength ; i++) {
+			assertEquals(i+1, cars[i].getId().intValue());
+			//assertEquals(i+1, planes[i].getId().intValue());
+		}
+		
+		s = openSession();
+		tx = s.beginTransaction();
+		s.createQuery( "delete from Car" ).executeUpdate();
+		tx.commit();
+		s.close();
+	}
+
+	public void testRollingBack() throws Throwable {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		int testLength = 3;
+		Long lastId = null;
+		for (int i = 0; i < testLength ; i++) {
+			Car car = new Car();
+			car.setColor( "color " + i );
+			s.save( car );
+			lastId = car.getId();
+		}
+		tx.rollback();
+		s.close();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		Car car = new Car();
+		car.setColor( "blue" );
+		s.save( car );
+		s.flush();
+		tx.commit();
+		s.close();
+
+		assertEquals( "id generation was rolled back", lastId.longValue() + 1, car.getId().longValue() );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.createQuery( "delete Car" ).executeUpdate();
+		tx.commit();
+		s.close();
+	}
+
+	public void testAllParams() throws Exception {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Radio radio = new Radio();
+		radio.setFrequency("32 MHz");
+		s.persist(radio);
+		assertEquals( new Integer(1), radio.getId() );
+		radio = new Radio();
+		radio.setFrequency("32 MHz");
+		s.persist(radio);
+		assertEquals( new Integer(2), radio.getId() );
+		tx.commit();
+		s.close();
+		
+		s = openSession();
+		tx = s.beginTransaction();
+		s.createQuery( "delete from Radio" ).executeUpdate();
+		tx.commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Plane.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Plane.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Plane.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+  This mapping demonstrates the use of
+  the EJB3 compliant table hilo generator
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.id">
+
+    <class name="Plane">
+    
+    	<id name="id">
+    		<generator class="org.hibernate.id.MultipleHiLoPerTableGenerator">
+				<param name="max_lo">2</param>
+ 			</generator>
+    	</id>
+        <property name="nbrOfSeats"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Plane.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Plane.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Plane.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: Plane.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.id;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class Plane {
+	private Long id;
+	private int nbrOfSeats;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public int getNbrOfSeats() {
+		return nbrOfSeats;
+	}
+
+	public void setNbrOfSeats(int nbrOfSeats) {
+		this.nbrOfSeats = nbrOfSeats;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Product.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Product.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Product.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.id">
+
+	<class name="Product" table="t_product">
+		<id name="name">
+            <generator class="uuid"/>
+        </id>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Product.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Product.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Product.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+//$Id: $
+package org.hibernate.test.id;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class Product {
+	private String name;
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Radio.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Radio.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Radio.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+  This mapping demonstrates the use of
+  the EJB3 compliant table hilo generator
+  with all the parameters
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.id">
+
+    <class name="Radio">
+    
+    	<id name="id">
+    		<generator class="org.hibernate.id.MultipleHiLoPerTableGenerator">
+				<param name="table">sequences</param>
+				<param name="value_column">hi_value</param>
+                <param name="primary_key_column">name</param>
+				<param name="primary_key_length">50</param>
+				<param name="max_lo">2</param>
+				<param name="primary_key_value">Radio</param>
+ 			</generator>
+    	</id>
+        <property name="frequency"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Radio.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Radio.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/Radio.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: Radio.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.id;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class Radio {
+	private Integer id;
+	private String frequency;
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getFrequency() {
+		return frequency;
+	}
+
+	public void setFrequency(String frequency) {
+		this.frequency = frequency;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/UseIdentifierRollbackTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/UseIdentifierRollbackTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/id/UseIdentifierRollbackTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+//$Id: $
+package org.hibernate.test.id;
+
+import org.hibernate.test.TestCase;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import junit.framework.Test;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class UseIdentifierRollbackTest extends TestCase {
+	public UseIdentifierRollbackTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "id/Product.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty( Environment.USE_IDENTIFIER_ROLLBACK, "true");
+		super.configure( cfg );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( UseIdentifierRollbackTest.class );
+	}
+
+	public void testSimpleRollback() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+		Product prod = new Product();
+		assertNull( prod.getName() );
+		session.persist(prod);
+		session.flush();
+		assertNotNull( prod.getName() );
+		t.rollback();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/Group.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/Group.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/Group.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+//$Id: Group.java 6058 2005-03-11 17:05:19Z oneovthafew $
+package org.hibernate.test.idbag;
+
+/**
+ * @author Gavin King
+ */
+public class Group {
+	private String name;
+	
+	Group() {}
+	
+	public Group(String name) {
+		this.name = name;
+	}
+	
+	public String getName() {
+		return name;
+	}
+	
+	void setName(String name) {
+		this.name = name;
+	}
+	
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/Group.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/IdBagTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/IdBagTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/IdBagTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,101 @@
+//$Id: IdBagTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.idbag;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class IdBagTest extends FunctionalTestCase {
+	
+	public IdBagTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idbag/UserGroup.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( IdBagTest.class );
+	}
+
+	public void testUpdateIdBag() throws HibernateException, SQLException {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User gavin = new User("gavin");
+		Group admins = new Group("admins");
+		Group plebs = new Group("plebs");
+		Group moderators = new Group("moderators");
+		Group banned = new Group("banned");
+		gavin.getGroups().add(plebs);
+		//gavin.getGroups().add(moderators);
+		s.persist(gavin);
+		s.persist(plebs);
+		s.persist(admins);
+		s.persist(moderators);
+		s.persist(banned);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		gavin = (User) s.createCriteria(User.class).uniqueResult();
+		admins = (Group) s.load(Group.class, "admins");
+		plebs = (Group) s.load(Group.class, "plebs");
+		banned = (Group) s.load(Group.class, "banned");
+		gavin.getGroups().add(admins);
+		gavin.getGroups().remove(plebs);
+		//gavin.getGroups().add(banned);
+
+		s.delete(plebs);
+		s.delete(banned);
+		s.delete(moderators);
+		s.delete(admins);
+		s.delete(gavin);
+		
+		t.commit();
+		s.close();		
+	}
+	
+	public void testJoin() throws HibernateException, SQLException {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User gavin = new User("gavin");
+		Group admins = new Group("admins");
+		Group plebs = new Group("plebs");
+		gavin.getGroups().add(plebs);
+		gavin.getGroups().add(admins);
+		s.persist(gavin);
+		s.persist(plebs);
+		s.persist(admins);
+		
+		List l = s.createQuery("from User u join u.groups g").list();
+		assertEquals( l.size(), 2 );
+		s.clear();
+		
+		gavin = (User) s.createQuery("from User u join fetch u.groups").uniqueResult();
+		assertTrue( Hibernate.isInitialized( gavin.getGroups() ) );
+		assertEquals( gavin.getGroups().size(), 2 );
+		assertEquals( ( (Group) gavin.getGroups().get(0) ).getName(), "admins" );
+		
+		s.delete( gavin.getGroups().get(0) );
+		s.delete( gavin.getGroups().get(1) );
+		s.delete(gavin);
+		
+		t.commit();
+		s.close();		
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/IdBagTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: User.java 6058 2005-03-11 17:05:19Z oneovthafew $
+package org.hibernate.test.idbag;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Gavin King
+ */
+public class User {
+	private String name;
+	private List groups = new ArrayList();
+	
+	User() {}
+	
+	public User(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+	
+
+	void setName(String name) {
+		this.name = name;
+	}
+
+	public List getGroups() {
+		return groups;
+	}
+	
+	void setGroups(List groups) {
+		this.groups = groups;
+	}
+	
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/User.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/UserGroup.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/UserGroup.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/UserGroup.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates how to use an idbag to represent
+  a many-to-many association where the association table has
+  a surrogate key.
+     
+-->
+
+<hibernate-mapping package="org.hibernate.test.idbag">
+	
+	<class name="User" table="`Users`">
+		<id name="name"/>
+		
+		<idbag name="groups" 
+				order-by="groupName asc" 
+				table="`UserGroups`">
+			<collection-id column="userGroupId" 
+					type="long">
+				<generator class="increment"/>
+			</collection-id>
+			<key column="userName"/>
+			<many-to-many column="groupName" 
+					class="Group"/>
+		</idbag>
+		
+	</class>
+	
+	<class name="Group" table="`Groups`">
+		<id name="name"/>
+	</class>
+	
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idbag/UserGroup.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/Customer.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/Customer.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/Customer.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+  This mapping demonstrates how to use an id class not
+  embedded in the entity. Only the property values are
+  shared between the 2. This mimic the EJB2.1 and EJB3
+  semantic.
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.idclass">
+	
+	<class name="Customer">
+		<composite-id class="CustomerId" mapped="true">
+			<key-property name="orgName" column="org_name"/>
+			<key-property name="customerName" column="cust_name"/>
+		</composite-id>
+        <discriminator column="disc"/>
+        <property name="address"/>
+		<subclass name="FavoriteCustomer"/>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/Customer.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,90 @@
+//$Id: Customer.java 7858 2005-08-11 21:46:58Z epbernard $
+
+package org.hibernate.test.idclass;
+
+
+
+
+
+public class Customer {
+
+
+
+	public Customer() {
+
+		super();
+
+	}
+
+
+
+	public Customer(String orgName, String custName, String add) {
+
+		this.orgName = orgName;
+
+		this.customerName = custName;
+
+		this.address = add;
+
+	}
+
+
+
+	private String orgName;
+
+	private String customerName;
+
+	private String address;
+
+
+
+	public String getAddress() {
+
+		return address;
+
+	}
+
+
+
+	public void setAddress(String address) {
+
+		this.address = address;
+
+	}
+
+
+
+	public String getCustomerName() {
+
+		return customerName;
+
+	}
+
+
+
+	public void setCustomerName(String customerName) {
+
+		this.customerName = customerName;
+
+	}
+
+
+
+	public String getOrgName() {
+
+		return orgName;
+
+	}
+
+
+
+	public void setOrgName(String orgName) {
+
+		this.orgName = orgName;
+
+	}
+
+
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/Customer.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/CustomerId.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/CustomerId.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/CustomerId.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+//$Id: CustomerId.java 7239 2005-06-20 09:44:54Z oneovthafew $
+package org.hibernate.test.idclass;
+
+import java.io.Serializable;
+
+public class CustomerId implements Serializable {
+	
+	private String orgName;
+	private String customerName;
+
+	public CustomerId() {
+		super();
+	}
+
+	public CustomerId(String orgName, String custName) {
+		this.orgName = orgName;
+		this.customerName = custName;
+	}
+
+	public String getCustomerName() {
+		return customerName;
+	}
+
+	public void setCustomerName(String customerName) {
+		this.customerName = customerName;
+	}
+
+	public String getOrgName() {
+		return orgName;
+	}
+
+	public void setOrgName(String orgName) {
+		this.orgName = orgName;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/CustomerId.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/FavoriteCustomer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/FavoriteCustomer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/FavoriteCustomer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,14 @@
+//$Id: FavoriteCustomer.java 7858 2005-08-11 21:46:58Z epbernard $
+package org.hibernate.test.idclass;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class FavoriteCustomer extends Customer {
+	public FavoriteCustomer() {
+	}
+
+	public FavoriteCustomer(String orgName, String custName, String add) {
+		super( orgName, custName, add );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/IdClassTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/IdClassTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/IdClassTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+//$Id: IdClassTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.idclass;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class IdClassTest extends FunctionalTestCase {
+	
+	public IdClassTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idclass/Customer.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( IdClassTest.class );
+	}
+
+	public void testIdClass() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Customer cust = new FavoriteCustomer("JBoss", "RouteOne", "Detroit");
+		s.persist(cust);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		CustomerId custId = new CustomerId("JBoss", "RouteOne");
+		t = s.beginTransaction();
+		cust = (Customer) s.get(Customer.class, custId);
+		assertEquals( "Detroit", cust.getAddress() );
+		assertEquals( cust.getCustomerName(), custId.getCustomerName() );
+		assertEquals( cust.getOrgName(), custId.getOrgName() );
+		t.commit();
+		s.close();		
+
+		s = openSession();
+		t = s.beginTransaction();
+		cust = (Customer) s.createQuery("from Customer where id.customerName = 'RouteOne'").uniqueResult();
+		assertEquals( "Detroit", cust.getAddress() );
+		assertEquals( cust.getCustomerName(), custId.getCustomerName() );
+		assertEquals( cust.getOrgName(), custId.getOrgName() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		cust = (Customer) s.createQuery("from Customer where customerName = 'RouteOne'").uniqueResult();
+		assertEquals( "Detroit", cust.getAddress() );
+		assertEquals( cust.getCustomerName(), custId.getCustomerName() );
+		assertEquals( cust.getOrgName(), custId.getOrgName() );
+		
+		s.createQuery( "delete from Customer" ).executeUpdate();
+		
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idclass/IdClassTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/IdGenSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/IdGenSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/IdGenSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+package org.hibernate.test.idgen;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.idgen.enhanced.OptimizerUnitTest;
+import org.hibernate.test.idgen.enhanced.SequenceStyleConfigUnitTest;
+import org.hibernate.test.idgen.enhanced.forcedtable.BasicForcedTableSequenceTest;
+import org.hibernate.test.idgen.enhanced.forcedtable.HiLoForcedTableSequenceTest;
+import org.hibernate.test.idgen.enhanced.forcedtable.PooledForcedTableSequenceTest;
+import org.hibernate.test.idgen.enhanced.sequence.BasicSequenceTest;
+import org.hibernate.test.idgen.enhanced.sequence.HiLoSequenceTest;
+import org.hibernate.test.idgen.enhanced.sequence.PooledSequenceTest;
+import org.hibernate.test.idgen.enhanced.table.BasicTableTest;
+import org.hibernate.test.idgen.enhanced.table.HiLoTableTest;
+import org.hibernate.test.idgen.enhanced.table.PooledTableTest;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class IdGenSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "enhanced id generators" );
+
+		suite.addTest( OptimizerUnitTest.suite() );
+		suite.addTest( SequenceStyleConfigUnitTest.suite() );
+
+		suite.addTest( BasicForcedTableSequenceTest.suite() );
+		suite.addTest( HiLoForcedTableSequenceTest.suite() );
+		suite.addTest( PooledForcedTableSequenceTest.suite() );
+
+		suite.addTest( BasicSequenceTest.suite() );
+		suite.addTest( HiLoSequenceTest.suite() );
+		suite.addTest( PooledSequenceTest.suite() );
+
+		suite.addTest( BasicTableTest.suite() );
+		suite.addTest( HiLoTableTest.suite() );
+		suite.addTest( PooledTableTest.suite() );
+
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/OptimizerUnitTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,154 @@
+package org.hibernate.test.idgen.enhanced;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.junit.UnitTestCase;
+import org.hibernate.id.enhanced.Optimizer;
+import org.hibernate.id.enhanced.OptimizerFactory;
+import org.hibernate.id.enhanced.AccessCallback;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class OptimizerUnitTest extends UnitTestCase {
+	public OptimizerUnitTest(String string) {
+		super( string );
+	}
+
+	public static Test suite() {
+		return new TestSuite( OptimizerUnitTest.class );
+	}
+
+	public void testBasicNoOptimizerUsage() {
+		// test historic sequence behavior, where the initial values start at 1...
+		SourceMock sequence = new SourceMock( 1 );
+		Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.NONE, Long.class, 1 );
+		for ( int i = 1; i < 11; i++ ) {
+			final Long next = ( Long ) optimizer.generate( sequence );
+			assertEquals( i, next.intValue() );
+		}
+		assertEquals( 10, sequence.getTimesCalled() );
+		assertEquals( 10, sequence.getCurrentValue() );
+
+		// test historic table behavior, where the initial values started at 0 (we now force 1 to be the first used id value)
+		sequence = new SourceMock( 0 );
+		optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.NONE, Long.class, 1 );
+		for ( int i = 1; i < 11; i++ ) {
+			final Long next = ( Long ) optimizer.generate( sequence );
+			assertEquals( i, next.intValue() );
+		}
+		assertEquals( 11, sequence.getTimesCalled() ); // an extra time to get to 1 initially
+		assertEquals( 10, sequence.getCurrentValue() );
+	}
+
+	public void testBasicHiLoOptimizerUsage() {
+		int increment = 10;
+		Long next;
+
+		// test historic sequence behavior, where the initial values start at 1...
+		SourceMock sequence = new SourceMock( 1 );
+		Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.HILO, Long.class, increment );
+		for ( int i = 1; i <= increment; i++ ) {
+			next = ( Long ) optimizer.generate( sequence );
+			assertEquals( i, next.intValue() );
+		}
+		assertEquals( 1, sequence.getTimesCalled() ); // once to initialze state
+		assertEquals( 1, sequence.getCurrentValue() );
+		// force a "clock over"
+		next = ( Long ) optimizer.generate( sequence );
+		assertEquals( 11, next.intValue() );
+		assertEquals( 2, sequence.getTimesCalled() );
+		assertEquals( 2, sequence.getCurrentValue() );
+
+		// test historic table behavior, where the initial values started at 0 (we now force 1 to be the first used id value)
+		sequence = new SourceMock( 0 );
+		optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.HILO, Long.class, increment );
+		for ( int i = 1; i <= increment; i++ ) {
+			next = ( Long ) optimizer.generate( sequence );
+			assertEquals( i, next.intValue() );
+		}
+		assertEquals( 2, sequence.getTimesCalled() ); // here have have an extra call to get to 1 initially
+		assertEquals( 1, sequence.getCurrentValue() );
+		// force a "clock over"
+		next = ( Long ) optimizer.generate( sequence );
+		assertEquals( 11, next.intValue() );
+		assertEquals( 3, sequence.getTimesCalled() );
+		assertEquals( 2, sequence.getCurrentValue() );
+	}
+
+	public void testBasicPooledOptimizerUsage() {
+		Long next;
+		// test historic sequence behavior, where the initial values start at 1...
+		SourceMock sequence = new SourceMock( 1, 10 );
+		Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL, Long.class, 10 );
+		for ( int i = 1; i < 11; i++ ) {
+			next = ( Long ) optimizer.generate( sequence );
+			assertEquals( i, next.intValue() );
+		}
+		assertEquals( 2, sequence.getTimesCalled() ); // twice to initialze state
+		assertEquals( 11, sequence.getCurrentValue() );
+		// force a "clock over"
+		next = ( Long ) optimizer.generate( sequence );
+		assertEquals( 11, next.intValue() );
+		assertEquals( 3, sequence.getTimesCalled() );
+		assertEquals( 21, sequence.getCurrentValue() );
+	}
+
+	private static class SourceMock implements AccessCallback {
+		private long value;
+		private int increment;
+		private int timesCalled = 0;
+
+		public SourceMock(long initialValue) {
+			this( initialValue, 1 );
+		}
+
+		public SourceMock(long initialValue, int increment) {
+			this.increment = increment;
+			this.value = initialValue - increment;
+		}
+
+		public long getNextValue() {
+			timesCalled++;
+			return ( value += increment );
+		}
+
+		public int getTimesCalled() {
+			return timesCalled;
+		}
+
+		public long getCurrentValue() {
+			return value;
+		}
+	}
+
+//	public void testNoopDumping() {
+//		SourceMock sequence = new SourceMock( 1 );
+//		Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.NONE, Long.class, 1 );
+//		for ( int i = 1; i <= 41; i++ ) {
+//			System.out.println( i + " => " + optimizer.generate( sequence ) + " (" + sequence.getCurrentValue() + ")" );
+//		}
+//	}
+//
+//	public void testHiLoDumping() {
+//		int increment = 10;
+//		SourceMock sequence = new SourceMock( 1 );
+//		Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.HILO, Long.class, increment );
+//		for ( int i = 1; i <= 41; i++ ) {
+//			System.out.println( i + " => " + optimizer.generate( sequence ) + " (" + sequence.getCurrentValue() + ")" );
+//		}
+//	}
+//
+//	public void testPooledDumping() {
+//		int increment = 10;
+//		SourceMock sequence = new SourceMock( 1, increment );
+//		Optimizer optimizer = OptimizerFactory.buildOptimizer( OptimizerFactory.POOL, Long.class, increment );
+//		for ( int i = 1; i <= 41; i++ ) {
+//			System.out.println( i + " => " + optimizer.generate( sequence ) + " (" + sequence.getCurrentValue() + ")" );
+//		}
+//	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/SequenceStyleConfigUnitTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,180 @@
+package org.hibernate.test.idgen.enhanced;
+
+import java.util.Properties;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.junit.UnitTestCase;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.id.enhanced.SequenceStructure;
+import org.hibernate.id.enhanced.OptimizerFactory;
+import org.hibernate.id.enhanced.TableStructure;
+import org.hibernate.Hibernate;
+import org.hibernate.MappingException;
+
+/**
+ * Tests that SequenceStyleGenerator configures itself as expected
+ * in various scenarios
+ *
+ * @author Steve Ebersole
+ */
+public class SequenceStyleConfigUnitTest extends UnitTestCase {
+	public SequenceStyleConfigUnitTest(String string) {
+		super( string );
+	}
+
+	public static Test suite() {
+		return new TestSuite( SequenceStyleConfigUnitTest.class );
+	}
+
+	/**
+	 * Test all params defaulted with a dialect supporting sequences
+	 */
+	public void testDefaultedSequenceBackedConfiguration() {
+		Dialect dialect = new SequenceDialect();
+		Properties props = new Properties();
+		SequenceStyleGenerator generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+
+		assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.NoopOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() );
+	}
+
+	/**
+	 * Test all params defaulted with a dialect which does not support sequences
+	 */
+	public void testDefaultedTableBackedConfiguration() {
+		Dialect dialect = new TableDialect();
+		Properties props = new Properties();
+		SequenceStyleGenerator generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+
+		assertClassAssignability( TableStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.NoopOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() );
+	}
+
+	/**
+	 * Test default optimizer selection for sequence backed generators
+	 * based on the configured increment size; both in the case of the
+	 * dialect supporting pooled sequences (pooled) and not (hilo)
+	 */
+	public void testDefaultOptimizerBasedOnIncrementBackedBySequence() {
+		Properties props = new Properties();
+		props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" );
+
+		// for dialects which do not support pooled sequences, we default to hilo
+		Dialect dialect = new SequenceDialect();
+		SequenceStyleGenerator generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+		assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() );
+
+		// for dialects which do support pooled sequences, we default to pooled
+		dialect = new PooledSequenceDialect();
+		generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+		assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() );
+	}
+
+	/**
+	 * Test default optimizer selection for table backed generators
+	 * based on the configured increment size.  Here we always prefer
+	 * pooled.
+	 */
+	public void testDefaultOptimizerBasedOnIncrementBackedByTable() {
+		Properties props = new Properties();
+		props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" );
+		Dialect dialect = new TableDialect();
+		SequenceStyleGenerator generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+		assertClassAssignability( TableStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() );
+	}
+
+	/**
+	 * Test forcing of table as backing strucuture with dialect supporting sequences
+	 */
+	public void testForceTableUse() {
+		Dialect dialect = new SequenceDialect();
+		Properties props = new Properties();
+		props.setProperty( SequenceStyleGenerator.FORCE_TBL_PARAM, "true" );
+		SequenceStyleGenerator generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+		assertClassAssignability( TableStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.NoopOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() );
+	}
+
+	/**
+	 * Test explicitly specifying both optimizer and increment
+	 */
+	public void testExplicitOptimizerWithExplicitIncrementSize() {
+		// with sequence ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		Dialect dialect = new SequenceDialect();
+
+		// optimizer=none w/ increment > 1 => should honor optimizer
+		Properties props = new Properties();
+		props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.NONE );
+		props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
+		SequenceStyleGenerator generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+		assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.NoopOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( 1, generator.getOptimizer().getIncrementSize() );
+		assertEquals( 1, generator.getDatabaseStructure().getIncrementSize() );
+
+		// optimizer=hilo w/ increment > 1 => hilo
+		props = new Properties();
+		props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.HILO );
+		props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+		assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( 20, generator.getOptimizer().getIncrementSize() );
+		assertEquals( 20, generator.getDatabaseStructure().getIncrementSize() );
+
+		// optimizer=pooled w/ increment > 1 => hilo
+		props = new Properties();
+		props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.POOL );
+		props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
+		generator = new SequenceStyleGenerator();
+		generator.configure( Hibernate.LONG, props, dialect );
+		assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() );
+		assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() );
+		assertEquals( 20, generator.getOptimizer().getIncrementSize() );
+		assertEquals( 20, generator.getDatabaseStructure().getIncrementSize() );
+
+	}
+
+	private static class TableDialect extends Dialect {
+		public boolean supportsSequences() {
+			return false;
+		}
+	}
+
+	private static class SequenceDialect extends Dialect {
+		public boolean supportsSequences() {
+			return true;
+		}
+		public boolean supportsPooledSequences() {
+			return false;
+		}
+		public String getSequenceNextValString(String sequenceName) throws MappingException {
+			return "";
+		}
+	}
+
+	private static class PooledSequenceDialect extends SequenceDialect {
+		public boolean supportsPooledSequences() {
+			return true;
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/Basic.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/Basic.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/Basic.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of the enhanced sequence-based identifier
+    generator, with no performance optimizations (the DB is hit
+    everytime when generating a value).
+-->
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.forcedtable">
+
+    <class name="Entity" table="ID_SEQ_TBL_BSC_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
+                <param name="table_name">ID_SEQ_TBL_BSC_SEQ</param>
+                <param name="value_column">hi_val</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">1</param>
+                <param name="optimizer">none</param>
+                <param name="force_tbl_use">true</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/BasicForcedTableSequenceTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/BasicForcedTableSequenceTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/BasicForcedTableSequenceTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+package org.hibernate.test.idgen.enhanced.forcedtable;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.Session;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class BasicForcedTableSequenceTest extends DatabaseSpecificFunctionalTestCase {
+	public BasicForcedTableSequenceTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/forcedtable/Basic.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( BasicForcedTableSequenceTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() );
+		SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator();
+
+		int count = 5;
+		Entity[] entities = new Entity[count];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < count; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			long expectedId = i + 1;
+			assertEquals( expectedId, entities[i].getId().longValue() );
+			assertEquals( expectedId, generator.getDatabaseStructure().getTimesAccessed() );
+			assertEquals( expectedId, generator.getOptimizer().getLastSourceValue() );
+		}
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < count; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/Entity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/Entity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/Entity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+package org.hibernate.test.idgen.enhanced.forcedtable;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Entity {
+	private Long id;
+	private String name;
+
+	public Entity() {
+	}
+
+	public Entity(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/HiLo.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/HiLo.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/HiLo.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of the enhanced table-based identifier
+    generator, using a hilo algorithm as the optimization (to
+    avoid hitting the database to generate each value).
+-->
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.forcedtable">
+
+    <class name="Entity" table="ID_SEQ_TBL_HILO_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
+                <param name="table_name">ID_SEQ_TBL_HILO_SEQ</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">10</param>
+                <param name="optimizer">hilo</param>
+                <param name="force_tbl_use">true</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/HiLoForcedTableSequenceTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/HiLoForcedTableSequenceTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/HiLoForcedTableSequenceTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+package org.hibernate.test.idgen.enhanced.forcedtable;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.id.enhanced.OptimizerFactory;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.Session;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class HiLoForcedTableSequenceTest extends DatabaseSpecificFunctionalTestCase {
+	public HiLoForcedTableSequenceTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/forcedtable/HiLo.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( HiLoForcedTableSequenceTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() );
+		SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator();
+		assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() );
+		OptimizerFactory.HiLoOptimizer optimizer = ( OptimizerFactory.HiLoOptimizer ) generator.getOptimizer();
+
+		int increment = optimizer.getIncrementSize();
+		Entity[] entities = new Entity[ increment + 1 ];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < increment; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			long expectedId = i + 1;
+			assertEquals( expectedId, entities[i].getId().longValue() );
+			assertEquals( 1, generator.getOptimizer().getLastSourceValue() );
+			assertEquals( i + 1, optimizer.getLastValue() );
+			assertEquals( increment + 1, optimizer.getHiValue() );
+		}
+		// now force a "clock over"
+		entities[ increment ] = new Entity( "" + increment );
+		s.save( entities[ increment ] );
+		long expectedId = optimizer.getIncrementSize() + 1;
+		assertEquals( expectedId, entities[ optimizer.getIncrementSize() ].getId().longValue() );
+		assertEquals( 2, optimizer.getLastSourceValue() ); // initialization + clokc-over
+		assertEquals( increment + 1, optimizer.getLastValue() );
+		assertEquals( ( increment * 2 ) + 1, optimizer.getHiValue() );
+
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < entities.length; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/Pooled.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/Pooled.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/Pooled.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of the enhanced table-based identifier
+    generator, using a hilo algorithm as the optimization (to
+    avoid hitting the database to generate each value).
+-->
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.forcedtable">
+
+    <class name="Entity" table="ID_SEQ_TBL_POOL_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
+                <param name="table_name">ID_SEQ_TBL_POOL_SEQ</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">10</param>
+                <param name="optimizer">pooled</param>
+                <param name="force_tbl_use">true</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/PooledForcedTableSequenceTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/PooledForcedTableSequenceTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/forcedtable/PooledForcedTableSequenceTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+package org.hibernate.test.idgen.enhanced.forcedtable;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.id.enhanced.OptimizerFactory;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.Session;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class PooledForcedTableSequenceTest extends DatabaseSpecificFunctionalTestCase {
+	public PooledForcedTableSequenceTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/forcedtable/Pooled.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PooledForcedTableSequenceTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() );
+		SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator();
+		assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() );
+		OptimizerFactory.PooledOptimizer optimizer = ( OptimizerFactory.PooledOptimizer ) generator.getOptimizer();
+
+		int increment = optimizer.getIncrementSize();
+		Entity[] entities = new Entity[ increment + 1 ];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < increment; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			long expectedId = i + 1;
+			assertEquals( expectedId, entities[i].getId().longValue() );
+			assertEquals( 2, generator.getDatabaseStructure().getTimesAccessed() ); // initialization calls table twice
+			assertEquals( increment + 1, optimizer.getLastSourceValue() ); // initialization calls table twice
+			assertEquals( i + 1, optimizer.getLastValue() );
+			assertEquals( increment + 1, optimizer.getLastSourceValue() );
+		}
+		// now force a "clock over"
+		entities[ increment ] = new Entity( "" + increment );
+		s.save( entities[ increment ] );
+		long expectedId = optimizer.getIncrementSize() + 1;
+		assertEquals( expectedId, entities[ optimizer.getIncrementSize() ].getId().longValue() );
+		assertEquals( 3, generator.getDatabaseStructure().getTimesAccessed() ); // initialization (2) + clock over
+		assertEquals( ( increment * 2 ) + 1, optimizer.getLastSourceValue() ); // initialization (2) + clock over
+		assertEquals( increment + 1, optimizer.getLastValue() );
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < entities.length; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/Basic.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/Basic.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/Basic.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of the enhanced sequence-based identifier
+    generator, with no performance optimizations (the DB is hit
+    everytime when generating a value).
+-->
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.sequence">
+
+    <class name="Entity" table="ID_SEQ_BSC_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
+                <param name="sequence_name">ID_SEQ_BSC_SEQ</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">1</param>
+                <param name="optimizer">none</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+package org.hibernate.test.idgen.enhanced.sequence;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.Session;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class BasicSequenceTest extends FunctionalTestCase {
+	public BasicSequenceTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/sequence/Basic.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( BasicSequenceTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() );
+		SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator();
+
+		int count = 5;
+		Entity[] entities = new Entity[count];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < count; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			long expectedId = i + 1;
+			assertEquals( expectedId, entities[i].getId().longValue() );
+			assertEquals( expectedId, generator.getDatabaseStructure().getTimesAccessed() );
+			assertEquals( expectedId, generator.getOptimizer().getLastSourceValue() );
+		}
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < count; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/Entity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/Entity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/Entity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+package org.hibernate.test.idgen.enhanced.sequence;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Entity {
+	private Long id;
+	private String name;
+
+	public Entity() {
+	}
+
+	public Entity(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLo.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLo.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLo.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of the enhanced sequence-based identifier
+    generator, using a hilo algorithm as the optimization (to
+    avoid hitting the database to generate each value).
+-->
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.sequence">
+
+    <class name="Entity" table="ID_SEQ_HILO_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
+                <param name="sequence_name">ID_SEQ_HILO_SEQ</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">10</param>
+                <param name="optimizer">hilo</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+package org.hibernate.test.idgen.enhanced.sequence;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.Session;
+import org.hibernate.id.enhanced.OptimizerFactory;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class HiLoSequenceTest extends FunctionalTestCase {
+	public HiLoSequenceTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/sequence/HiLo.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( HiLoSequenceTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() );
+		SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator();
+		assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() );
+		OptimizerFactory.HiLoOptimizer optimizer = ( OptimizerFactory.HiLoOptimizer ) generator.getOptimizer();
+
+		int increment = optimizer.getIncrementSize();
+		Entity[] entities = new Entity[ increment + 1 ];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < increment; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			assertEquals( 1, generator.getDatabaseStructure().getTimesAccessed() ); // initialization
+			assertEquals( 1, optimizer.getLastSourceValue() ); // initialization
+			assertEquals( i + 1, optimizer.getLastValue() );
+			assertEquals( increment + 1, optimizer.getHiValue() );
+		}
+		// now force a "clock over"
+		entities[ increment ] = new Entity( "" + increment );
+		s.save( entities[ increment ] );
+		assertEquals( 2, generator.getDatabaseStructure().getTimesAccessed() ); // initialization
+		assertEquals( 2, optimizer.getLastSourceValue() ); // initialization
+		assertEquals( increment + 1, optimizer.getLastValue() );
+		assertEquals( ( increment * 2 ) + 1, optimizer.getHiValue() );
+
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < entities.length; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/Pooled.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/Pooled.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/Pooled.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of the enhanced sequence-based identifier
+    generator, using a pooled algorithm as the optimization (to
+    avoid hitting the database to generate each value).
+-->
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.sequence">
+
+    <class name="Entity" table="ID_SEQ_POOL_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
+                <param name="sequence_name">ID_SEQ_POOL_SEQ</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">10</param>
+                <param name="optimizer">pooled</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/sequence/PooledSequenceTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,65 @@
+package org.hibernate.test.idgen.enhanced.sequence;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.id.enhanced.OptimizerFactory;
+import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.Session;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class PooledSequenceTest extends FunctionalTestCase {
+	public PooledSequenceTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/sequence/Pooled.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PooledSequenceTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() );
+		SequenceStyleGenerator generator = ( SequenceStyleGenerator ) persister.getIdentifierGenerator();
+		assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() );
+		OptimizerFactory.PooledOptimizer optimizer = ( OptimizerFactory.PooledOptimizer ) generator.getOptimizer();
+
+		int increment = optimizer.getIncrementSize();
+		Entity[] entities = new Entity[ increment + 1 ];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < increment; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			assertEquals( 2, generator.getDatabaseStructure().getTimesAccessed() ); // initialization calls seq twice
+			assertEquals( increment + 1, optimizer.getLastSourceValue() ); // initialization calls seq twice
+			assertEquals( i + 1, optimizer.getLastValue() );
+			assertEquals( increment + 1, optimizer.getLastSourceValue() );
+		}
+		// now force a "clock over"
+		entities[ increment ] = new Entity( "" + increment );
+		s.save( entities[ increment ] );
+		assertEquals( 3, generator.getDatabaseStructure().getTimesAccessed() ); // initialization (2) + clock over
+		assertEquals( ( increment * 2 ) + 1, optimizer.getLastSourceValue() ); // initialization (2) + clock over
+		assertEquals( increment + 1, optimizer.getLastValue() );
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < entities.length; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/Basic.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/Basic.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/Basic.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.table">
+
+    <class name="Entity" table="ID_TBL_BSC_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.TableGenerator">
+                <param name="table_name">ID_TBL_BSC_TBL</param>
+                <param name="segment_value">test</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">1</param>
+                <param name="optimizer">none</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/BasicTableTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+package org.hibernate.test.idgen.enhanced.table;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.id.enhanced.TableGenerator;
+import org.hibernate.Session;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class BasicTableTest extends FunctionalTestCase {
+	public BasicTableTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/table/Basic.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( BasicTableTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( TableGenerator.class, persister.getIdentifierGenerator().getClass() );
+		TableGenerator generator = ( TableGenerator ) persister.getIdentifierGenerator();
+
+		int count = 5;
+		Entity[] entities = new Entity[count];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < count; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			long expectedId = i + 1;
+			assertEquals( expectedId, entities[i].getId().longValue() );
+			assertEquals( expectedId, generator.getTableAccessCount() );
+			assertEquals( expectedId, generator.getOptimizer().getLastSourceValue() );
+		}
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < count; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/Entity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/Entity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/Entity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+package org.hibernate.test.idgen.enhanced.table;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Entity {
+	private Long id;
+	private String name;
+
+	public Entity() {
+	}
+
+	public Entity(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/HiLo.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/HiLo.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/HiLo.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.table">
+
+    <class name="Entity" table="ID_TBL_HILO_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.TableGenerator">
+                <param name="table_name">ID_TBL_HILO_TBL</param>
+                <param name="segment_value">test</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">10</param>
+                <param name="optimizer">hilo</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/HiLoTableTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+package org.hibernate.test.idgen.enhanced.table;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.id.enhanced.OptimizerFactory;
+import org.hibernate.id.enhanced.TableGenerator;
+import org.hibernate.Session;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class HiLoTableTest extends FunctionalTestCase {
+	public HiLoTableTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/table/HiLo.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( HiLoTableTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( TableGenerator.class, persister.getIdentifierGenerator().getClass() );
+		TableGenerator generator = ( TableGenerator ) persister.getIdentifierGenerator();
+		assertClassAssignability( OptimizerFactory.HiLoOptimizer.class, generator.getOptimizer().getClass() );
+		OptimizerFactory.HiLoOptimizer optimizer = ( OptimizerFactory.HiLoOptimizer ) generator.getOptimizer();
+
+		int increment = optimizer.getIncrementSize();
+		Entity[] entities = new Entity[ increment + 1 ];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < increment; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			assertEquals( 1, generator.getTableAccessCount() ); // initialization
+			assertEquals( 1, optimizer.getLastSourceValue() ); // initialization
+			assertEquals( i + 1, optimizer.getLastValue() );
+			assertEquals( increment + 1, optimizer.getHiValue() );
+		}
+		// now force a "clock over"
+		entities[ increment ] = new Entity( "" + increment );
+		s.save( entities[ increment ] );
+		assertEquals( 2, generator.getTableAccessCount() ); // initialization
+		assertEquals( 2, optimizer.getLastSourceValue() ); // initialization
+		assertEquals( increment + 1, optimizer.getLastValue() );
+		assertEquals( ( increment * 2 ) + 1, optimizer.getHiValue() );
+
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < entities.length; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/Pooled.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/Pooled.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/Pooled.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of the enhanced sequence-based identifier
+    generator, using a pooled algorithm as the optimization (to
+    avoid hitting the database to generate each value).
+-->
+
+<hibernate-mapping package="org.hibernate.test.idgen.enhanced.table">
+
+    <class name="Entity" table="ID_TBL_POOL_ENTITY">
+        <id name="id" column="ID" type="long">
+            <generator class="org.hibernate.id.enhanced.TableGenerator">
+                <param name="table_name">ID_TBL_POOL_TBL</param>
+                <param name="segment_value">test</param>
+                <param name="initial_value">1</param>
+                <param name="increment_size">10</param>
+                <param name="optimizer">pooled</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idgen/enhanced/table/PooledTableTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,65 @@
+package org.hibernate.test.idgen.enhanced.table;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.id.enhanced.OptimizerFactory;
+import org.hibernate.id.enhanced.TableGenerator;
+import org.hibernate.Session;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class PooledTableTest extends FunctionalTestCase {
+	public PooledTableTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idgen/enhanced/table/Pooled.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PooledTableTest.class );
+	}
+
+	public void testNormalBoundary() {
+		EntityPersister persister = sfi().getEntityPersister( Entity.class.getName() );
+		assertClassAssignability( TableGenerator.class, persister.getIdentifierGenerator().getClass() );
+		TableGenerator generator = ( TableGenerator ) persister.getIdentifierGenerator();
+		assertClassAssignability( OptimizerFactory.PooledOptimizer.class, generator.getOptimizer().getClass() );
+		OptimizerFactory.PooledOptimizer optimizer = ( OptimizerFactory.PooledOptimizer ) generator.getOptimizer();
+
+		int increment = optimizer.getIncrementSize();
+		Entity[] entities = new Entity[ increment + 1 ];
+		Session s = openSession();
+		s.beginTransaction();
+		for ( int i = 0; i < increment; i++ ) {
+			entities[i] = new Entity( "" + ( i + 1 ) );
+			s.save( entities[i] );
+			assertEquals( 2, generator.getTableAccessCount() ); // initialization calls seq twice
+			assertEquals( increment + 1, optimizer.getLastSourceValue() ); // initialization calls seq twice
+			assertEquals( i + 1, optimizer.getLastValue() );
+			assertEquals( increment + 1, optimizer.getLastSourceValue() );
+		}
+		// now force a "clock over"
+		entities[ increment ] = new Entity( "" + increment );
+		s.save( entities[ increment ] );
+		assertEquals( 3, generator.getTableAccessCount() ); // initialization (2) + clock over
+		assertEquals( ( increment * 2 ) + 1, optimizer.getLastSourceValue() ); // initialization (2) + clock over
+		assertEquals( increment + 1, optimizer.getLastValue() );
+		s.getTransaction().commit();
+
+		s.beginTransaction();
+		for ( int i = 0; i < entities.length; i++ ) {
+			assertEquals( i + 1, entities[i].getId().intValue() );
+			s.delete( entities[i] );
+		}
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,187 @@
+package org.hibernate.test.idprops;
+
+import junit.framework.Test;
+
+import org.hibernate.Criteria;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.criterion.Projections;
+import org.hibernate.criterion.Restrictions;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class IdentifierPropertyReferencesTest extends FunctionalTestCase {
+	public IdentifierPropertyReferencesTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "idprops/Mapping.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( IdentifierPropertyReferencesTest.class );
+	}
+
+	public void testHqlIdPropertyReferences() {
+		Session s = openSession();
+		s.beginTransaction();
+		Person p = new Person( new Long(1), "steve", 123 );
+		s.save( p );
+		Order o = new Order( new Long(1), p );
+		LineItem l = new LineItem( o, "my-product", 2 );
+		l.setId( "456" );
+		s.save( o );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+
+		long count = extractCount( s, "select count(*) from Person p where p.id = 123" );
+		assertEquals( "Person by id prop (non-identifier)", 1, count );
+		count = extractCount( s, "select count(*) from Person p where p.pk = 1" );
+		assertEquals( "Person by pk prop (identifier)", 1, count );
+
+		count = extractCount( s, "select count(*) from Order o where o.id = 1" );
+		assertEquals( "Order by number prop (named identifier)", 1, count );
+		count = extractCount( s, "select count(*) from Order o where o.number = 1" );
+		assertEquals( "Order by id prop (virtual identifier)", 1, count );
+
+		count = extractCount( s, "select count(*) from LineItem l where l.id = '456'" );
+		assertEquals( "LineItem by id prop (non-identifier", 1, count );
+
+		if ( getDialect().supportsRowValueConstructorSyntax() ) {
+			Query q = s.createQuery( "select count(*) from LineItem l where l.pk = (:order, :product)" )
+					.setEntity( "order", o )
+					.setString( "product", "my-product" );
+			count = extractCount( q );
+			assertEquals( "LineItem by pk prop (named composite identifier", 1, count );
+		}
+
+		count = extractCount( s, "select count(*) from Order o where o.orderee.id = 1" );
+		assertEquals( 0, count );
+		count = extractCount( s, "select count(*) from Order o where o.orderee.pk = 1" );
+		assertEquals( 1, count );
+		count = extractCount( s, "select count(*) from Order o where o.orderee.id = 123" );
+		assertEquals( 1, count );
+
+		count = extractCount( s, "select count(*) from LineItem l where l.pk.order.id = 1" );
+		assertEquals( 1, count );
+		count = extractCount( s, "select count(*) from LineItem l where l.pk.order.number = 1" );
+		assertEquals( 1, count );
+		count = extractCount( s, "select count(*) from LineItem l where l.pk.order.orderee.pk = 1" );
+		assertEquals( 1, count );
+
+		s.delete( o );
+		s.delete( p );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testCriteriaIdPropertyReferences() {
+		Session s = openSession();
+		s.beginTransaction();
+		Person p = new Person( new Long(1), "steve", 123 );
+		s.save( p );
+		Order o = new Order( new Long(1), p );
+		LineItem l = new LineItem( o, "my-product", 2 );
+		l.setId( "456" );
+		s.save( o );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+
+		Criteria crit = s.createCriteria( Person.class );
+		crit.setProjection( Projections.rowCount() );
+		crit.add( Restrictions.eq( "id", new Integer(123) ) );
+		long count = extractCount( crit );
+		assertEquals( "Person by id prop (non-identifier)", 1, count );
+
+		crit = s.createCriteria( Person.class );
+		crit.setProjection( Projections.rowCount() );
+		crit.add( Restrictions.eq( "pk", new Long(1) ) );
+		count = extractCount( crit );
+		assertEquals( "Person by pk prop (identifier)", 1, count );
+
+		crit = s.createCriteria( Order.class );
+		crit.setProjection( Projections.rowCount() );
+		crit.add(  Restrictions.eq( "number", new Long(1) ) );
+		count = extractCount( crit );
+		assertEquals( "Order by number prop (named identifier)", 1, count );
+
+		crit = s.createCriteria( Order.class );
+		crit.setProjection( Projections.rowCount() );
+		crit.add(  Restrictions.eq( "id", new Long(1) ) );
+		count = extractCount( crit );
+		assertEquals( "Order by id prop (virtual identifier)", 1, count );
+
+		crit = s.createCriteria( LineItem.class );
+		crit.setProjection( Projections.rowCount() );
+		crit.add(  Restrictions.eq( "id", "456" ) );
+		count = extractCount( crit );
+		assertEquals( "LineItem by id prop (non-identifier", 1, count );
+
+		if ( getDialect().supportsRowValueConstructorSyntax() ) {
+			crit = s.createCriteria( LineItem.class );
+			crit.setProjection( Projections.rowCount() );
+			crit.add( Restrictions.eq( "pk", new LineItemPK( o, "my-product" ) ) );
+			count = extractCount( crit );
+			assertEquals( "LineItem by pk prop (named composite identifier)", 1, count );
+		}
+
+		crit = s.createCriteria( Order.class );
+		crit.setProjection( Projections.rowCount() );
+		crit.createAlias( "orderee", "p" ).add( Restrictions.eq( "p.id", new Integer(1) ) );
+		count = extractCount( crit );
+		assertEquals( 0, count );
+
+		crit = s.createCriteria( Order.class );
+		crit.setProjection( Projections.rowCount() );
+		crit.createAlias( "orderee", "p" ).add( Restrictions.eq( "p.pk", new Long(1) ) );
+		count = extractCount( crit );
+		assertEquals( 1, count );
+
+		crit = s.createCriteria( Order.class );
+		crit.setProjection( Projections.rowCount() );
+		crit.createAlias( "orderee", "p" ).add( Restrictions.eq( "p.id", new Integer(123) ) );
+		count = extractCount( crit );
+		assertEquals( 1, count );
+
+		crit = s.createCriteria( LineItem.class );
+		crit.setProjection( Projections.rowCount() );
+		crit.add( Restrictions.eq( "pk.order.id", new Long(1) ) );
+		count = extractCount( crit );
+		assertEquals( 1, count );
+
+		crit = s.createCriteria( LineItem.class );
+		crit.setProjection( Projections.rowCount() );
+		crit.add( Restrictions.eq( "pk.order.number", new Long(1) ) );
+		count = extractCount( crit );
+		assertEquals( 1, count );
+
+		s.delete( o );
+		s.delete( p );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	private long extractCount(Session s, String hql) {
+		return extractCount( s.createQuery( hql ) );
+	}
+
+	private long extractCount(Query query) {
+		return ( ( Long ) query.list().get( 0 ) ).longValue();
+	}
+
+	private long extractCount(Criteria crit) {
+		return ( ( Integer ) crit.list().get( 0 ) ).intValue();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/LineItem.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/LineItem.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/LineItem.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+package org.hibernate.test.idprops;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class LineItem {
+	private LineItemPK pk;
+	private int quantity;
+	private String id;
+
+	public LineItem() {
+	}
+
+	public LineItem(LineItemPK pk, int quantity) {
+		this.pk = pk;
+		this.quantity = quantity;
+		this.pk.getOrder().getLineItems().add( this );
+	}
+
+	public LineItem(Order order, String productCode, int quantity) {
+		this( new LineItemPK( order, productCode ), quantity );
+	}
+
+	public LineItemPK getPk() {
+		return pk;
+	}
+
+	public void setPk(LineItemPK pk) {
+		this.pk = pk;
+	}
+
+	public int getQuantity() {
+		return quantity;
+	}
+
+	public void setQuantity(int quantity) {
+		this.quantity = quantity;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/LineItemPK.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/LineItemPK.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/LineItemPK.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+package org.hibernate.test.idprops;
+
+import java.io.Serializable;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class LineItemPK implements Serializable {
+	private Order order;
+	private String productCode;
+
+	public LineItemPK() {
+	}
+
+	public LineItemPK(Order order, String productCode) {
+		this.order = order;
+		this.productCode = productCode;
+	}
+
+	public Order getOrder() {
+		return order;
+	}
+
+	public void setOrder(Order order) {
+		this.order = order;
+	}
+
+	public String getProductCode() {
+		return productCode;
+	}
+
+	public void setProductCode(String productCode) {
+		this.productCode = productCode;
+	}
+
+	public boolean equals(Object o) {
+		if ( this == o ) {
+			return true;
+		}
+		if ( o == null || getClass() != o.getClass() ) {
+			return false;
+		}
+
+		LineItemPK that = ( LineItemPK ) o;
+
+		if ( !order.equals( that.order ) ) {
+			return false;
+		}
+		if ( !productCode.equals( that.productCode ) ) {
+			return false;
+		}
+
+		return true;
+	}
+
+	public int hashCode() {
+		int result;
+		result = order.hashCode();
+		result = 31 * result + productCode.hashCode();
+		return result;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/Mapping.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/Mapping.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/Mapping.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.idprops">
+
+    <!--
+        Person has an identitifer property named something other than 'id';
+        additionally, it has a non-identitifer property named 'id'
+    -->
+    <class name="Person" table="T_ID_PERSON">
+        <id name="pk" column="PK" type="long">
+            <generator class="assigned"/>
+        </id>
+        <property name="name" column="NAME" type="string"/>
+        <property name="id" column="ID_NON_ID" type="int" />
+    </class>
+
+    <!--
+        Order has an identitifer property named something other than 'id';
+        it has no non-identitifer property named 'id'
+    -->
+    <class name="Order" table="T_ID_ORDER">
+        <id name="number" column="PK" type="long">
+            <generator class="assigned"/>
+        </id>
+        <property name="placed" column="ORDR_DT" type="timestamp"/>
+        <many-to-one name="orderee" class="Person" column="ORDEREE"/>
+        <set name="lineItems" cascade="all-delete-orphan" lazy="true" inverse="true">
+            <key column="ORDR_ID"/>
+            <one-to-many class="LineItem"/>
+        </set>
+    </class>
+
+    <!--
+        LineItem has a composite identitifer property named something other than 'id';
+        additionally, it has a non-identitifer property named 'id'
+    -->
+    <class name="LineItem" table="T_ID_LINE_ITEM">
+        <composite-id class="LineItemPK" name="pk">
+            <key-many-to-one name="order" class="Order" column="ORDR_ID" />
+            <key-property name="productCode" column="PROD_CODE" type="string"/>
+        </composite-id>
+        <property name="quantity" column="QTY" type="int"/>
+        <property name="id" column="ID_NON_ID2" type="string"/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/Order.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/Order.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/Order.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+package org.hibernate.test.idprops;
+
+import java.util.Date;
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Order {
+	private Long number;
+	private Date placed;
+	private Person orderee;
+
+	private Set lineItems = new HashSet();
+
+	public Order() {
+	}
+
+	public Order(Long number, Person orderee) {
+		this.number = number;
+		this.orderee = orderee;
+		this.placed = new Date();
+	}
+
+	public Long getNumber() {
+		return number;
+	}
+
+	public void setNumber(Long number) {
+		this.number = number;
+	}
+
+	public Date getPlaced() {
+		return placed;
+	}
+
+	public void setPlaced(Date placed) {
+		this.placed = placed;
+	}
+
+	public Person getOrderee() {
+		return orderee;
+	}
+
+	public void setOrderee(Person orderee) {
+		this.orderee = orderee;
+	}
+
+
+	public Set getLineItems() {
+		return lineItems;
+	}
+
+	public void setLineItems(Set lineItems) {
+		this.lineItems = lineItems;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/idprops/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+package org.hibernate.test.idprops;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Person {
+	private Long pk;
+	private String name;
+	private int id;
+
+	public Person() {
+	}
+
+	public Person(Long pk, String name, int id) {
+		this.pk = pk;
+		this.name = name;
+		this.id = id;
+	}
+
+	public Long getPk() {
+		return pk;
+	}
+
+	public void setPk(Long pk) {
+		this.pk = pk;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public int getId() {
+		return id;
+	}
+
+	public void setId(int id) {
+		this.id = id;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/Contract.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/Contract.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/Contract.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+//$Id: Contract.java 7222 2005-06-19 17:22:01Z oneovthafew $
+package org.hibernate.test.immutable;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Contract implements Serializable {
+	
+	private long id;
+	private String customerName;
+	private String type;
+	private List variations;
+
+	public Contract() {
+		super();
+	}
+
+	public Contract(String customerName, String type) {
+		this.customerName = customerName;
+		this.type = type;
+		variations = new ArrayList();
+	}
+
+	public String getCustomerName() {
+		return customerName;
+	}
+
+	public void setCustomerName(String customerName) {
+		this.customerName = customerName;
+	}
+
+	public long getId() {
+		return id;
+	}
+
+	public void setId(long id) {
+		this.id = id;
+	}
+
+	public String getType() {
+		return type;
+	}
+
+	public void setType(String type) {
+		this.type = type;
+	}
+
+	public List getVariations() {
+		return variations;
+	}
+
+	public void setVariations(List variations) {
+		this.variations = variations;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/Contract.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ContractVariation.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ContractVariation.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ContractVariation.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  Test for immutable classes/collections.
+     
+-->
+
+<hibernate-mapping package="org.hibernate.test.immutable">
+	
+	<class name="Contract" mutable="false">
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		<property name="customerName" not-null="true"/>
+		<property name="type" not-null="true"/>
+		<bag name="variations" inverse="true" order-by="version asc"
+				mutable="false" cascade="all" fetch="join">
+			<key column="contract"/>
+			<one-to-many class="ContractVariation"/>
+		</bag>
+	</class>
+	
+	<class name="ContractVariation" mutable="false">
+		<composite-id>
+			<key-many-to-one name="contract"/>
+			<key-property name="version"/>
+		</composite-id>
+		<property name="text" type="text"/>
+	</class>
+	
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ContractVariation.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ContractVariation.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ContractVariation.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ContractVariation.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: ContractVariation.java 7222 2005-06-19 17:22:01Z oneovthafew $
+package org.hibernate.test.immutable;
+
+import java.io.Serializable;
+
+public class ContractVariation implements Serializable {
+	
+	private int version;
+	private Contract contract;
+	private String text;
+
+	public Contract getContract() {
+		return contract;
+	}
+
+	public void setContract(Contract contract) {
+		this.contract = contract;
+	}
+
+	public String getText() {
+		return text;
+	}
+
+	public void setText(String text) {
+		this.text = text;
+	}
+
+	public int getVersion() {
+		return version;
+	}
+
+	public void setVersion(int version) {
+		this.version = version;
+	}
+
+	public ContractVariation() {
+		super();
+	}
+
+	public ContractVariation(int version, Contract contract) {
+		this.contract = contract;
+		this.version = version;
+		contract.getVariations().add(this);
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ContractVariation.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ImmutableTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ImmutableTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ImmutableTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,66 @@
+//$Id: ImmutableTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.immutable;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.criterion.Projections;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class ImmutableTest extends FunctionalTestCase {
+
+	public ImmutableTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "immutable/ContractVariation.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ImmutableTest.class );
+	}
+
+	public void testImmutable() {
+		Contract c = new Contract("gavin", "phone");
+		ContractVariation cv1 = new ContractVariation(1, c);
+		cv1.setText("expensive");
+		ContractVariation cv2 = new ContractVariation(2, c);
+		cv2.setText("more expensive");
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.persist(c);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Contract) s.createCriteria(Contract.class).uniqueResult();
+		c.setCustomerName("foo bar");
+		c.getVariations().add( new ContractVariation(3, c) );
+		cv1 = (ContractVariation) c.getVariations().iterator().next();
+		cv1.setText("blah blah");
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Contract) s.createCriteria(Contract.class).uniqueResult();
+		assertEquals( c.getCustomerName(), "gavin" );
+		assertEquals( c.getVariations().size(), 2 );
+		cv1 = (ContractVariation) c.getVariations().iterator().next();
+		assertEquals( cv1.getText(), "expensive" );
+		s.delete(c);
+		assertEquals( s.createCriteria(Contract.class).setProjection( Projections.rowCount() ).uniqueResult(), new Integer(0) );
+		assertEquals( s.createCriteria(ContractVariation.class).setProjection( Projections.rowCount() ).uniqueResult(), new Integer(0) );
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/immutable/ImmutableTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/Group.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/Group.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/Group.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+package org.hibernate.test.insertordering;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Group {
+	private Long id;
+	private String name;
+
+	/**
+	 * for persistence
+	 */
+	Group() {
+	}
+
+	public Group(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public String getName() {
+		return name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/InsertOrderingTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/InsertOrderingTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/InsertOrderingTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,127 @@
+package org.hibernate.test.insertordering;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.Session;
+import org.hibernate.Interceptor;
+import org.hibernate.HibernateException;
+import org.hibernate.jdbc.BatchingBatcher;
+import org.hibernate.jdbc.ConnectionManager;
+import org.hibernate.jdbc.Expectation;
+import org.hibernate.jdbc.BatcherFactory;
+import org.hibernate.jdbc.Batcher;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class InsertOrderingTest extends FunctionalTestCase {
+	public InsertOrderingTest(String string) {
+		super( string );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( InsertOrderingTest.class );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "insertordering/Mapping.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.ORDER_INSERTS, "true" );
+		cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "10" );
+		cfg.setProperty( Environment.BATCH_STRATEGY, StatsBatcherFactory.class.getName() );
+	}
+
+	public void testBatchOrdering() {
+		Session s = openSession();
+		s.beginTransaction();
+		int iterations = 12;
+		for ( int i = 0; i < iterations; i++ ) {
+			User user = new User( "user-" + i );
+			Group group = new Group( "group-" + i );
+			s.save( user );
+			s.save( group );
+			user.addMembership( group );
+		}
+		StatsBatcher.reset();
+		s.getTransaction().commit();
+		s.close();
+
+		assertEquals( 6, StatsBatcher.batchSizes.size() );  // 2 batches of each insert statement
+
+		s = openSession();
+		s.beginTransaction();
+		Iterator users = s.createQuery( "from User u left join fetch u.memberships m left join fetch m.group" ).list().iterator();
+		while ( users.hasNext() ) {
+			s.delete( users.next() );
+		}
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public static class Counter {
+		public int count = 0;
+	}
+
+	public static class StatsBatcher extends BatchingBatcher {
+		private static String batchSQL;
+		private static List batchSizes = new ArrayList();
+		private static int currentBatch = -1;
+
+		public StatsBatcher(ConnectionManager connectionManager, Interceptor interceptor) {
+			super( connectionManager, interceptor );
+		}
+
+		static void reset() {
+			batchSizes = new ArrayList();
+			currentBatch = -1;
+			batchSQL = null;
+		}
+
+		public PreparedStatement prepareBatchStatement(String sql) throws SQLException {
+			PreparedStatement rtn = super.prepareBatchStatement( sql );
+			if ( batchSQL == null || !batchSQL.equals( sql ) ) {
+				currentBatch++;
+				batchSQL = sql;
+				batchSizes.add( currentBatch, new Counter() );
+				System.out.println( "--------------------------------------------------------" );
+				System.out.println( "Preparing statement [" + sql + "]" );
+			}
+			return rtn;
+		}
+
+		public void addToBatch(Expectation expectation) throws SQLException, HibernateException {
+			Counter counter = ( Counter ) batchSizes.get( currentBatch );
+			counter.count++;
+			System.out.println( "Adding to batch [" + batchSQL + "]" );
+			super.addToBatch( expectation );
+		}
+
+		protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException {
+			System.out.println( "executing batch [" + batchSQL + "]" );
+			System.out.println( "--------------------------------------------------------" );
+			batchSQL = null;
+			super.doExecuteBatch( ps );
+		}
+	}
+
+	public static class StatsBatcherFactory implements BatcherFactory {
+		public Batcher createBatcher(ConnectionManager connectionManager, Interceptor interceptor) {
+			return new StatsBatcher( connectionManager, interceptor );
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/Mapping.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/Mapping.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/Mapping.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.insertordering" default-access="field">
+
+	<class name="User" table="INS_ORD_USR">
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+        <property name="username" column="USR_NM" />
+        <set name="memberships" fetch="select" lazy="true" inverse="true" cascade="all">
+            <key column="USR_ID"/>
+            <one-to-many class="Membership"/>
+        </set>
+    </class>
+	
+	<class name="Group" table="INS_ORD_GRP">
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		<property name="name"/>
+	</class>
+
+    <class name="Membership" table="INS_ORD_MEM">
+        <id name="id">
+            <generator class="increment" />
+        </id>
+        <many-to-one name="user" class="User" column="USR_ID" cascade="all"/>
+        <many-to-one name="group" class="Group" column="GRP_ID" cascade="all"/>
+        <property name="activationDate" type="timestamp" column="JN_DT"/>
+    </class>
+</hibernate-mapping>
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/Membership.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/Membership.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/Membership.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+package org.hibernate.test.insertordering;
+
+import java.util.Date;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Membership {
+	private Long id;
+	private User user;
+	private Group group;
+	private Date activationDate;
+
+	/**
+	 * For persistence
+	 */
+	Membership() {
+	}
+
+	public Membership(User user, Group group) {
+		this( user, group, new Date() );
+	}
+
+	public Membership(User user, Group group, Date activationDate) {
+		this.user = user;
+		this.group = group;
+		this.activationDate = activationDate;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public User getUser() {
+		return user;
+	}
+
+	public Group getGroup() {
+		return group;
+	}
+
+	public Date getActivationDate() {
+		return activationDate;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/insertordering/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+package org.hibernate.test.insertordering;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class User {
+	private Long id;
+	private String username;
+	private Set memberships = new HashSet();
+
+	/**
+	 * for persistence
+	 */
+	User() {
+	}
+
+	public User(String username) {
+		this.username = username;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public String getUsername() {
+		return username;
+	}
+
+	public Iterator getMemberships() {
+		return memberships.iterator();
+	}
+
+	public Membership addMembership(Group group) {
+		Membership membership = new Membership( this, group );
+		memberships.add( membership );
+		return membership;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/buildtime/InstrumentTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/buildtime/InstrumentTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/buildtime/InstrumentTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,88 @@
+//$Id: InstrumentTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.instrument.buildtime;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.test.instrument.domain.Document;
+import org.hibernate.test.instrument.cases.TestDirtyCheckExecutable;
+import org.hibernate.test.instrument.cases.TestFetchAllExecutable;
+import org.hibernate.test.instrument.cases.TestLazyExecutable;
+import org.hibernate.test.instrument.cases.TestLazyManyToOneExecutable;
+import org.hibernate.test.instrument.cases.TestInjectFieldInterceptorExecutable;
+import org.hibernate.test.instrument.cases.TestIsPropertyInitializedExecutable;
+import org.hibernate.test.instrument.cases.TestLazyPropertyCustomTypeExecutable;
+import org.hibernate.test.instrument.cases.TestManyToOneProxyExecutable;
+import org.hibernate.test.instrument.cases.Executable;
+import org.hibernate.junit.UnitTestCase;
+
+/**
+ * @author Gavin King
+ */
+public class InstrumentTest extends UnitTestCase {
+
+	public InstrumentTest(String str) {
+		super(str);
+	}
+
+	public static Test suite() {
+		return new TestSuite( InstrumentTest.class );
+	}
+
+	public void testDirtyCheck() {
+		execute( new TestDirtyCheckExecutable() );
+	}
+
+	public void testFetchAll() throws Exception {
+		execute( new TestFetchAllExecutable() );
+	}
+
+	public void testLazy() throws Exception {
+		execute( new TestLazyExecutable() );
+	}
+
+	public void testLazyManyToOne() {
+		execute( new TestLazyManyToOneExecutable() );
+	}
+
+	public void testSetFieldInterceptor() {
+		execute( new TestInjectFieldInterceptorExecutable() );
+	}
+
+	public void testPropertyInitialized() {
+		execute( new TestIsPropertyInitializedExecutable() );
+	}
+
+	public void testManyToOneProxy() {
+		execute( new TestManyToOneProxyExecutable() );
+	}
+
+	public void testLazyPropertyCustomTypeExecutable() {
+		execute( new TestLazyPropertyCustomTypeExecutable() );
+	}
+
+	private void execute(Executable executable) {
+		executable.prepare();
+		try {
+			executable.execute();
+		}
+		finally {
+			executable.complete();
+		}
+	}
+
+	protected void runTest() throws Throwable {
+		if ( isRunnable() ) {
+			super.runTest();
+		}
+		else {
+			reportSkip( "domain classes not instrumented", "build-time instrumentation" );
+		}
+	}
+
+	public static boolean isRunnable() {
+		return FieldInterceptionHelper.isInstrumented( new Document() );
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/buildtime/InstrumentTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/AbstractExecutable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/AbstractExecutable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/AbstractExecutable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+package org.hibernate.test.instrument.cases;
+
+import org.hibernate.SessionFactory;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractExecutable implements Executable {
+
+	private SessionFactory factory;
+
+	public final void prepare() {
+		Configuration cfg = new Configuration().setProperty( Environment.HBM2DDL_AUTO, "create-drop" );
+		String[] resources = getResources();
+		for ( int i = 0; i < resources.length; i++ ) {
+			cfg.addResource( resources[i] );
+		}
+		factory = cfg.buildSessionFactory();
+	}
+
+	public final void complete() {
+		try {
+			cleanup();
+		}
+		finally {
+			factory.close();
+		}
+	}
+
+	protected SessionFactory getFactory() {
+		return factory;
+	}
+
+	protected void cleanup() {
+	}
+
+	protected String[] getResources() {
+		return new String[] { "org/hibernate/test/instrument/domain/Documents.hbm.xml" };
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/Executable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/Executable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/Executable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+package org.hibernate.test.instrument.cases;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface Executable {
+	public void prepare();
+	public void execute();
+	public void complete();
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestDirtyCheckExecutable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestDirtyCheckExecutable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestDirtyCheckExecutable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+package org.hibernate.test.instrument.cases;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.test.instrument.domain.Folder;
+
+import java.util.List;
+import java.util.Iterator;
+
+import junit.framework.Assert;
+
+/**
+ * @author Steve Ebersole
+ */
+public class TestDirtyCheckExecutable extends AbstractExecutable {
+	public void execute() {
+		Session s = getFactory().openSession();
+		Transaction t = s.beginTransaction();
+		Folder pics = new Folder();
+		pics.setName("pics");
+		Folder docs = new Folder();
+		docs.setName("docs");
+		s.persist(docs);
+		s.persist(pics);
+		t.commit();
+		s.close();
+
+		s = getFactory().openSession();
+		t = s.beginTransaction();
+		List list = s.createCriteria(Folder.class).list();
+		for ( Iterator iter = list.iterator(); iter.hasNext(); ) {
+			Folder f = (Folder) iter.next();
+			Assert.assertFalse( f.nameWasread );
+		}
+		t.commit();
+		s.close();
+
+		for ( Iterator iter = list.iterator(); iter.hasNext(); ) {
+			Folder f = (Folder) iter.next();
+			Assert.assertFalse( f.nameWasread );
+		}
+
+		s = getFactory().openSession();
+		t = s.beginTransaction();
+		s.createQuery("delete from Folder").executeUpdate();
+		t.commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestFetchAllExecutable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestFetchAllExecutable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestFetchAllExecutable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+package org.hibernate.test.instrument.cases;
+
+import org.hibernate.Session;
+import org.hibernate.Hibernate;
+import org.hibernate.Transaction;
+import org.hibernate.test.instrument.domain.Owner;
+import org.hibernate.test.instrument.domain.Document;
+import org.hibernate.test.instrument.domain.Folder;
+import junit.framework.Assert;
+
+/**
+ * @author Steve Ebersole
+ */
+public class TestFetchAllExecutable extends AbstractExecutable {
+	public void execute() {
+		Session s = getFactory().openSession();
+		Transaction t = s.beginTransaction();
+		Owner o = new Owner();
+		Document doc = new Document();
+		Folder fol = new Folder();
+		o.setName("gavin");
+		doc.setName("Hibernate in Action");
+		doc.setSummary("blah");
+		doc.updateText("blah blah");
+		fol.setName("books");
+		doc.setOwner(o);
+		doc.setFolder(fol);
+		fol.getDocuments().add(doc);
+		s.persist(o);
+		s.persist(fol);
+		t.commit();
+		s.close();
+
+		s = getFactory().openSession();
+		t = s.beginTransaction();
+		doc = (Document) s.createQuery("from Document fetch all properties").uniqueResult();
+		Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "summary" ) );
+		Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "upperCaseName" ) );
+		Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "owner" ) );
+		Assert.assertEquals( doc.getSummary(), "blah" );
+		s.delete(doc);
+		s.delete( doc.getOwner() );
+		s.delete( doc.getFolder() );
+		t.commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestInjectFieldInterceptorExecutable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestInjectFieldInterceptorExecutable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestInjectFieldInterceptorExecutable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+package org.hibernate.test.instrument.cases;
+
+import org.hibernate.test.instrument.domain.Document;
+import org.hibernate.intercept.FieldInterceptionHelper;
+
+import java.util.HashSet;
+
+/**
+ * @author Steve Ebersole
+ */
+public class TestInjectFieldInterceptorExecutable extends AbstractExecutable {
+	public void execute() {
+		Document doc = new Document();
+		FieldInterceptionHelper.injectFieldInterceptor( doc, "Document", new HashSet(), null );
+		doc.getId();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestIsPropertyInitializedExecutable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestIsPropertyInitializedExecutable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestIsPropertyInitializedExecutable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+//$Id: $
+package org.hibernate.test.instrument.cases;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.Hibernate;
+import org.hibernate.test.instrument.domain.Owner;
+import org.hibernate.test.instrument.domain.Document;
+import org.hibernate.test.instrument.domain.Folder;
+import junit.framework.Assert;
+
+/**
+ * @author Steve Ebersole
+ */
+public class TestIsPropertyInitializedExecutable extends AbstractExecutable {
+	public void execute() {
+		Session s = getFactory().openSession();
+		Transaction t = s.beginTransaction();
+		Owner o = new Owner();
+		Document doc = new Document();
+		Folder fol = new Folder();
+		o.setName("gavin");
+		doc.setName("Hibernate in Action");
+		doc.setSummary("blah");
+		doc.updateText("blah blah");
+		fol.setName("books");
+		doc.setOwner(o);
+		doc.setFolder(fol);
+		fol.getDocuments().add(doc);
+		Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "summary" ) );
+		s.persist(o);
+		s.persist(fol);
+		t.commit();
+		s.close();
+
+		s = getFactory().openSession();
+		t = s.beginTransaction();
+		doc = (Document) s.get( Document.class, doc.getId() );
+		Assert.assertFalse( Hibernate.isPropertyInitialized( doc, "summary" ) );
+		Assert.assertFalse( Hibernate.isPropertyInitialized( doc, "upperCaseName" ) );
+		Assert.assertFalse( Hibernate.isPropertyInitialized( doc, "owner" ) );
+		s.delete(doc);
+		s.delete( doc.getOwner() );
+		s.delete( doc.getFolder() );
+		t.commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestLazyExecutable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestLazyExecutable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestLazyExecutable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,197 @@
+package org.hibernate.test.instrument.cases;
+
+import org.hibernate.test.TestCase;
+import org.hibernate.test.instrument.cases.AbstractExecutable;
+import org.hibernate.test.instrument.domain.Owner;
+import org.hibernate.test.instrument.domain.Document;
+import org.hibernate.test.instrument.domain.Folder;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.CacheMode;
+import org.hibernate.SessionFactory;
+
+/**
+ * @author Steve Ebersole
+ */
+public class TestLazyExecutable extends AbstractExecutable {
+	public void execute() {
+		SessionFactory factory = getFactory();
+		Session s = factory.openSession();
+		Transaction t = s.beginTransaction();
+		Owner o = new Owner();
+		Document doc = new Document();
+		Folder fol = new Folder();
+		o.setName("gavin");
+		doc.setName("Hibernate in Action");
+		doc.setSummary("blah");
+		doc.updateText("blah blah");
+		fol.setName("books");
+		doc.setOwner(o);
+		doc.setFolder(fol);
+		fol.getDocuments().add(doc);
+		s.save(o);
+		s.save(fol);
+		t.commit();
+		s.close();
+
+		s = factory.openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		doc = ( Document ) s.get( Document.class, doc.getId() );
+		TestCase.assertTrue( Hibernate.isPropertyInitialized(doc, "weirdProperty"));
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "name"));
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "upperCaseName"));
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "folder"));
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "owner"));
+		doc.getUpperCaseName();  // should force initialization
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text"));
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "weirdProperty"));
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "upperCaseName"));
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "folder"));
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "owner"));
+		t.commit();
+		s.close();
+
+		s = factory.openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		doc = (Document) s.createQuery("from Document").uniqueResult();
+		doc.getName();
+		TestCase.assertEquals( doc.getText(), "blah blah" );
+		t.commit();
+		s.close();
+
+		s = factory.openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		doc = (Document) s.createQuery("from Document").uniqueResult();
+		doc.getName();
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "summary"));
+		TestCase.assertEquals( doc.getText(), "blah blah" );
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text"));
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "summary"));
+		t.commit();
+		s.close();
+
+		s = factory.openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		doc = (Document) s.createQuery("from Document").uniqueResult();
+		doc.setName("HiA");
+		t.commit();
+		s.close();
+
+		s = factory.openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		doc = (Document) s.createQuery("from Document").uniqueResult();
+		TestCase.assertEquals( doc.getName(), "HiA" );
+		TestCase.assertEquals( doc.getText(), "blah blah" );
+		t.commit();
+		s.close();
+
+		s = factory.openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		doc = (Document) s.createQuery("from Document").uniqueResult();
+		doc.getText();
+		doc.setName("HiA second edition");
+		t.commit();
+		s.close();
+
+		s = factory.openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		doc = (Document) s.createQuery("from Document").uniqueResult();
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "weirdProperty"));
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "name"));
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "upperCaseName"));
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "owner"));
+		TestCase.assertEquals( doc.getName(), "HiA second edition" );
+		TestCase.assertEquals( doc.getText(), "blah blah" );
+		TestCase.assertEquals( doc.getUpperCaseName(), "HIA SECOND EDITION" );
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text"));
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "weirdProperty"));
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "upperCaseName"));
+		t.commit();
+		s.close();
+
+		s = factory.openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		doc = (Document) s.createQuery("from Document").uniqueResult();
+		t.commit();
+		s.close();
+
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
+
+		s = factory.openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		s.lock(doc, LockMode.NONE);
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
+		TestCase.assertEquals( doc.getText(), "blah blah" );
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text"));
+		t.commit();
+		s.close();
+
+		s = factory.openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		doc = (Document) s.createQuery("from Document").uniqueResult();
+		t.commit();
+		s.close();
+
+		doc.setName("HiA2");
+
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
+
+		s = factory.openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		s.saveOrUpdate(doc);
+		s.flush();
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
+		TestCase.assertEquals( doc.getText(), "blah blah" );
+		TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text"));
+		doc.updateText("blah blah blah blah");
+		t.commit();
+		s.close();
+
+		s = factory.openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		doc = ( Document ) s.createQuery("from Document").uniqueResult();
+		TestCase.assertEquals( doc.getName(), "HiA2" );
+		TestCase.assertEquals( doc.getText(), "blah blah blah blah" );
+		t.commit();
+		s.close();
+
+		s = factory.openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		doc = (Document) s.load( Document.class, doc.getId() );
+		doc.getName();
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
+		TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "summary"));
+		t.commit();
+		s.close();
+
+		s = factory.openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		t = s.beginTransaction();
+		doc = (Document) s.createQuery("from Document").uniqueResult();
+		//s.delete(doc);
+		s.delete( doc.getFolder() );
+		s.delete( doc.getOwner() );
+		s.flush();
+		t.commit();
+		s.close();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestLazyManyToOneExecutable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestLazyManyToOneExecutable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestLazyManyToOneExecutable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,74 @@
+package org.hibernate.test.instrument.cases;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.Hibernate;
+import org.hibernate.test.instrument.domain.Owner;
+import org.hibernate.test.instrument.domain.Document;
+import org.hibernate.test.instrument.domain.Folder;
+import org.hibernate.test.instrument.cases.AbstractExecutable;
+import junit.framework.Assert;
+
+/**
+ * @author Steve Ebersole
+ */
+public class TestLazyManyToOneExecutable extends AbstractExecutable {
+	public void execute() {
+		Session s = getFactory().openSession();
+		Transaction t = s.beginTransaction();
+		Owner gavin = new Owner();
+		Document hia = new Document();
+		Folder fol = new Folder();
+		gavin.setName("gavin");
+		hia.setName("Hibernate in Action");
+		hia.setSummary("blah");
+		hia.updateText("blah blah");
+		fol.setName("books");
+		hia.setOwner(gavin);
+		hia.setFolder(fol);
+		fol.getDocuments().add(hia);
+		s.persist(gavin);
+		s.persist(fol);
+		t.commit();
+		s.close();
+
+		s = getFactory().openSession();
+		t = s.beginTransaction();
+		hia = (Document) s.createCriteria(Document.class).uniqueResult();
+		Assert.assertEquals( hia.getFolder().getClass(), Folder.class);
+		fol = hia.getFolder();
+		Assert.assertTrue( Hibernate.isInitialized(fol) );
+		t.commit();
+		s.close();
+
+		s = getFactory().openSession();
+		t = s.beginTransaction();
+		hia = (Document) s.createCriteria(Document.class).uniqueResult();
+		Assert.assertSame( hia.getFolder(), s.load(Folder.class, fol.getId()) );
+		Assert.assertTrue( Hibernate.isInitialized( hia.getFolder() ) );
+		t.commit();
+		s.close();
+
+		s = getFactory().openSession();
+		t = s.beginTransaction();
+		fol = (Folder) s.get(Folder.class, fol.getId());
+		hia = (Document) s.createCriteria(Document.class).uniqueResult();
+		Assert.assertSame( fol, hia.getFolder() );
+		fol = hia.getFolder();
+		Assert.assertTrue( Hibernate.isInitialized(fol) );
+		t.commit();
+		s.close();
+
+		s = getFactory().openSession();
+		t = s.beginTransaction();
+		fol = (Folder) s.load(Folder.class, fol.getId());
+		hia = (Document) s.createCriteria(Document.class).uniqueResult();
+		Assert.assertNotSame( fol, hia.getFolder() );
+		fol = hia.getFolder();
+		Assert.assertTrue( Hibernate.isInitialized(fol) );
+		s.delete(hia.getFolder());
+		s.delete(hia.getOwner());
+		t.commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestLazyPropertyCustomTypeExecutable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestLazyPropertyCustomTypeExecutable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestLazyPropertyCustomTypeExecutable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,68 @@
+package org.hibernate.test.instrument.cases;
+
+import java.util.Iterator;
+
+import junit.framework.Assert;
+
+import org.hibernate.Session;
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.test.instrument.domain.Problematic;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class TestLazyPropertyCustomTypeExecutable extends AbstractExecutable {
+
+	protected String[] getResources() {
+		return new String[] { "org/hibernate/test/instrument/domain/Problematic.hbm.xml" };
+	}
+
+	public void execute() {
+		Session s = getFactory().openSession();
+		s.beginTransaction();
+		Problematic p = new Problematic();
+		p.setName( "whatever" );
+		p.setBytes( new byte[] { 1, 0, 1, 1, 0 } );
+		s.save( p );
+		s.getTransaction().commit();
+		s.close();
+
+		// this access should be ok because p1 is not a lazy proxy 
+		s = getFactory().openSession();
+		s.beginTransaction();
+		Problematic p1 = (Problematic) s.get( Problematic.class, p.getId() );
+		Assert.assertTrue( FieldInterceptionHelper.isInstrumented( p1 ) );
+		p1.getRepresentation();
+		s.getTransaction().commit();
+		s.close();
+		
+		s = getFactory().openSession();
+		s.beginTransaction();
+		p1 = (Problematic) s.createQuery( "from Problematic" ).setReadOnly(true ).list().get( 0 );
+		p1.getRepresentation();
+		s.getTransaction().commit();
+		s.close();
+		
+		s = getFactory().openSession();
+		s.beginTransaction();
+		p1 = (Problematic) s.load( Problematic.class, p.getId() );
+		Assert.assertFalse( FieldInterceptionHelper.isInstrumented( p1 ) );
+		p1.setRepresentation( p.getRepresentation() );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	protected void cleanup() {
+		Session s = getFactory().openSession();
+		s.beginTransaction();
+		Iterator itr = s.createQuery( "from Problematic" ).list().iterator();
+		while ( itr.hasNext() ) {
+			Problematic p = (Problematic) itr.next();
+			s.delete( p );
+		}
+		s.getTransaction().commit();
+		s.close();
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestManyToOneProxyExecutable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestManyToOneProxyExecutable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/cases/TestManyToOneProxyExecutable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+package org.hibernate.test.instrument.cases;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.Hibernate;
+import org.hibernate.test.instrument.domain.Entity;
+import junit.framework.Assert;
+
+/**
+ *
+ * @author Steve Ebersole
+ */
+public class TestManyToOneProxyExecutable extends AbstractExecutable {
+	public void execute() {
+		Session s = getFactory().openSession();
+		Transaction t = s.beginTransaction();
+		Entity root = new Entity( "root" );
+		Entity child1 = new Entity( "child1" );
+		Entity child2 = new Entity( "child2" );
+		root.setChild( child1 );
+		child1.setSibling( child2 );
+		Entity gChild1 = new Entity( "grandchild 1" );
+		Entity gChild2 = new Entity( "grandchild 2" );
+		child1.setChild( gChild1 );
+		gChild1.setSibling( gChild2 );
+		s.save( root );
+		t.commit();
+		s.close();
+
+		// NOTE : child is mapped with lazy="proxy"; sibling with lazy="no-proxy"...
+
+		s = getFactory().openSession();
+		t = s.beginTransaction();
+		// load root
+		root = ( Entity ) s.get( Entity.class, root.getId() );
+		Assert.assertFalse( Hibernate.isPropertyInitialized( root, "name" ) );
+		Assert.assertFalse( Hibernate.isPropertyInitialized( root, "sibling" ) );
+		Assert.assertTrue( Hibernate.isPropertyInitialized( root, "child" ) );
+
+		// get a handle to the child1 proxy reference (and make certain that
+		// this does not force the lazy properties of the root entity
+		// to get initialized.
+		child1 = root.getChild();
+		Assert.assertFalse( Hibernate.isInitialized( child1 ) );
+		Assert.assertFalse( Hibernate.isPropertyInitialized( root, "name" ) );
+		Assert.assertFalse( Hibernate.isPropertyInitialized( root, "sibling" ) );
+		Assert.assertFalse( Hibernate.isPropertyInitialized( child1, "name" ) );
+		Assert.assertFalse( Hibernate.isPropertyInitialized( child1, "sibling" ) );
+		Assert.assertFalse( Hibernate.isPropertyInitialized( child1, "child" ) );
+
+		child1.getName();
+		Assert.assertFalse( Hibernate.isPropertyInitialized( root, "name" ) );
+		Assert.assertFalse( Hibernate.isPropertyInitialized( root, "sibling" ) );
+		Assert.assertTrue( Hibernate.isPropertyInitialized( child1, "name" ) );
+		Assert.assertTrue( Hibernate.isPropertyInitialized( child1, "sibling" ) );
+		Assert.assertTrue( Hibernate.isPropertyInitialized( child1, "child" ) );
+
+		gChild1 = child1.getChild();
+		Assert.assertFalse( Hibernate.isInitialized( gChild1 ) );
+		Assert.assertFalse( Hibernate.isPropertyInitialized( root, "name" ) );
+		Assert.assertFalse( Hibernate.isPropertyInitialized( root, "sibling" ) );
+
+		s.delete( root );
+		t.commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/CustomBlobType.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/CustomBlobType.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/CustomBlobType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,109 @@
+package org.hibernate.test.instrument.domain;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Arrays;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Hibernate;
+import org.hibernate.usertype.UserType;
+
+/**
+ * A simple byte[]-based custom type.
+ */
+public class CustomBlobType implements UserType {
+	/**
+	 * {@inheritDoc}
+	 */
+	public Object nullSafeGet(ResultSet rs, String names[], Object owner) throws SQLException {
+		// cast just to make sure...
+		return ( byte[] ) Hibernate.BINARY.nullSafeGet( rs, names );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public void nullSafeSet(PreparedStatement ps, Object value, int index) throws SQLException, HibernateException {
+		// cast just to make sure...
+		Hibernate.BINARY.nullSafeSet( ps, ( byte[] ) value, index );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Object deepCopy(Object value) {
+		byte result[] = null;
+
+		if ( value != null ) {
+			byte bytes[] = ( byte[] ) value;
+
+			result = new byte[bytes.length];
+			System.arraycopy( bytes, 0, result, 0, bytes.length );
+		}
+
+		return result;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public boolean isMutable() {
+		return true;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public int[] sqlTypes() {
+		return new int[] { Types.VARBINARY };
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Class returnedClass() {
+		return byte[].class;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public boolean equals(Object x, Object y) {
+		return Arrays.equals( ( byte[] ) x, ( byte[] ) y );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Object assemble(Serializable arg0, Object arg1)
+			throws HibernateException {
+		return null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Serializable disassemble(Object arg0)
+			throws HibernateException {
+		return null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public int hashCode(Object arg0)
+			throws HibernateException {
+		return 0;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Object replace(Object arg0, Object arg1, Object arg2)
+			throws HibernateException {
+		return null;
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Document.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Document.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Document.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,110 @@
+//$Id: Document.java 9538 2006-03-04 00:17:57Z steve.ebersole at jboss.com $
+package org.hibernate.test.instrument.domain;
+
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class Document {
+	private Long id;
+	private String name;
+	private String upperCaseName;
+	private String summary;
+	private String text;
+	private Owner owner;
+	private Folder folder;
+	private Date lastTextModification = new Date();
+	/**
+	 * @return Returns the folder.
+	 */
+	public Folder getFolder() {
+		return folder;
+	}
+	/**
+	 * @param folder The folder to set.
+	 */
+	public void setFolder(Folder folder) {
+		this.folder = folder;
+	}
+	/**
+	 * @return Returns the owner.
+	 */
+	public Owner getOwner() {
+		return owner;
+	}
+	/**
+	 * @param owner The owner to set.
+	 */
+	public void setOwner(Owner owner) {
+		this.owner = owner;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	/**
+	 * @return Returns the summary.
+	 */
+	public String getSummary() {
+		return summary;
+	}
+	/**
+	 * @param summary The summary to set.
+	 */
+	public void setSummary(String summary) {
+		this.summary = summary;
+	}
+	/**
+	 * @return Returns the text.
+	 */
+	public String getText() {
+		return text;
+	}
+	/**
+	 * @param text The text to set.
+	 */
+	private void setText(String text) {
+		this.text = text;
+	}
+	/**
+	 * @return Returns the upperCaseName.
+	 */
+	public String getUpperCaseName() {
+		return upperCaseName;
+	}
+	/**
+	 * @param upperCaseName The upperCaseName to set.
+	 */
+	public void setUpperCaseName(String upperCaseName) {
+		this.upperCaseName = upperCaseName;
+	}
+	
+	public void updateText(String newText) {
+		if ( !newText.equals(text) ) {
+			this.text = newText;
+			lastTextModification = new Date();
+		}
+	}
+	
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Document.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Documents.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Documents.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Documents.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+  This mapping demonstrates
+
+     (1) use of lazy properties - this feature requires buildtime
+         bytecode instrumentation; we don't think this is a very
+         necessary feature, but provide it for completeleness; if
+         Hibernate encounters uninstrumented classes, lazy property
+         fetching will be silently disabled, to enable testing
+
+     (2) use of a formula to define a "derived property"
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.instrument.domain" default-access="field">
+
+    <class name="Folder" table="folders">
+    	<id name="id">
+    		<generator class="increment"/>
+    	</id>
+    	<property name="name" not-null="true" length="50"/>
+    	<many-to-one name="parent"/>
+    	<bag name="subfolders" inverse="true" cascade="save-update">
+    		<key column="parent"/>
+    		<one-to-many class="Folder"/>
+    	</bag>
+    	<bag name="documents" inverse="true" cascade="all-delete-orphan">
+    		<key column="folder"/>
+    		<one-to-many class="Document"/>
+    	</bag>
+	</class>
+
+	<class name="Owner" table="owners" lazy="false">
+   		<id name="id">
+    		<generator class="increment"/>
+    	</id>
+    	<property name="name" not-null="true" length="50"/>
+    </class>
+
+	<class name="Document" table="documents">
+   		<id name="id">
+    		<generator class="increment"/>
+    	</id>
+    	<property name="name" not-null="true" length="50"/>
+    	<property name="upperCaseName" formula="upper(name)" lazy="true"/>
+    	<property name="summary" not-null="true" length="200" lazy="true"/>
+    	<many-to-one name="folder" not-null="true" lazy="no-proxy"/>
+    	<many-to-one name="owner" not-null="true" lazy="no-proxy" fetch="select"/>
+    	<property name="text" not-null="true" length="2000" lazy="true"/>
+    	<property name="lastTextModification" not-null="true" lazy="true" access="field"/>
+    </class>
+
+    <class name="Entity" table="entity">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="name" column="NAME" type="string" lazy="true"/>
+        <many-to-one name="child" column="PRNT_ID" class="Entity" lazy="proxy" cascade="all" />
+        <many-to-one name="sibling" column="RIGHT_ID" class="Entity" lazy="no-proxy" cascade="all" />
+    </class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Documents.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Entity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Entity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Entity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+package org.hibernate.test.instrument.domain;
+
+/**
+ * todo: describe Entity
+ *
+ * @author Steve Ebersole
+ */
+public class Entity {
+	private Long id;
+	private String name;
+	private Entity child;
+	private Entity sibling;
+
+	public Entity() {
+	}
+
+	public Entity(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Entity getChild() {
+		return child;
+	}
+
+	public void setChild(Entity child) {
+		this.child = child;
+	}
+
+	public Entity getSibling() {
+		return sibling;
+	}
+
+	public void setSibling(Entity sibling) {
+		this.sibling = sibling;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Folder.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Folder.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Folder.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,80 @@
+//$Id: Folder.java 9538 2006-03-04 00:17:57Z steve.ebersole at jboss.com $
+package org.hibernate.test.instrument.domain;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * @author Gavin King
+ */
+public class Folder {
+	private Long id;
+	private String name;
+	private Folder parent;
+	private Collection subfolders = new ArrayList();
+	private Collection documents = new ArrayList();
+
+	public boolean nameWasread;
+	
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		nameWasread = true;
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	/**
+	 * @return Returns the documents.
+	 */
+	public Collection getDocuments() {
+		return documents;
+	}
+	/**
+	 * @param documents The documents to set.
+	 */
+	public void setDocuments(Collection documents) {
+		this.documents = documents;
+	}
+	/**
+	 * @return Returns the parent.
+	 */
+	public Folder getParent() {
+		return parent;
+	}
+	/**
+	 * @param parent The parent to set.
+	 */
+	public void setParent(Folder parent) {
+		this.parent = parent;
+	}
+	/**
+	 * @return Returns the subfolders.
+	 */
+	public Collection getSubfolders() {
+		return subfolders;
+	}
+	/**
+	 * @param subfolders The subfolders to set.
+	 */
+	public void setSubfolders(Collection subfolders) {
+		this.subfolders = subfolders;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Folder.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Owner.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Owner.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Owner.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+//$Id: Owner.java 9538 2006-03-04 00:17:57Z steve.ebersole at jboss.com $
+package org.hibernate.test.instrument.domain;
+
+/**
+ * @author Gavin King
+ */
+public class Owner {
+	private Long id;
+	private String name;
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Owner.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Problematic.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Problematic.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Problematic.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.instrument.domain">
+    <class name="Problematic">
+        <id name="id" type="long" column="ID">
+            <generator class="increment" />
+        </id>
+        <property name="name" type="string" column="NAME" />
+        <property name="bytes" type="org.hibernate.test.instrument.domain.CustomBlobType" column="DATA" lazy="true" />
+    </class>
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Problematic.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Problematic.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/domain/Problematic.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+package org.hibernate.test.instrument.domain;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Problematic {
+	private Long id;
+	private String name;
+	private byte[] bytes;
+
+	private Representation representation;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public byte[] getBytes() {
+		return bytes;
+	}
+
+	public void setBytes(byte[] bytes) {
+		this.bytes = bytes;
+	}
+
+	public Representation getRepresentation() {
+		if ( representation == null ) {
+			representation =  ( ( bytes == null ) ? null : new Representation( bytes ) );
+		}
+		return representation;
+	}
+
+	public void setRepresentation(Representation rep) {
+		bytes = rep.getBytes();
+	}
+
+	public static class Representation {
+		private byte[] bytes;
+
+		public Representation(byte[] bytes) {
+			this.bytes = bytes;
+		}
+
+		public byte[] getBytes() {
+			return bytes;
+		}
+
+		public String toString() {
+			String result = "";
+			for ( int i = 0; i < bytes.length; i++ ) {
+				result += bytes[i];
+			}
+			return result;
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/runtime/AbstractTransformingClassLoaderInstrumentTestCase.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,119 @@
+package org.hibernate.test.instrument.runtime;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.hibernate.HibernateException;
+import org.hibernate.bytecode.BytecodeProvider;
+import org.hibernate.bytecode.InstrumentedClassLoader;
+import org.hibernate.bytecode.util.BasicClassFilter;
+import org.hibernate.bytecode.util.FieldFilter;
+import org.hibernate.junit.AbstractClassLoaderIsolatedTestCase;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractTransformingClassLoaderInstrumentTestCase extends AbstractClassLoaderIsolatedTestCase {
+
+	public AbstractTransformingClassLoaderInstrumentTestCase(String string) {
+		super( string );
+	}
+
+	protected ClassLoader buildIsolatedClassLoader(ClassLoader parent) {
+		BytecodeProvider provider = buildBytecodeProvider();
+		return new InstrumentedClassLoader(
+				parent,
+				provider.getTransformer(
+						new BasicClassFilter( new String[] { "org.hibernate.test.instrument" }, null ),
+						new FieldFilter() {
+							public boolean shouldInstrumentField(String className, String fieldName) {
+								return className.startsWith( "org.hibernate.test.instrument.domain" );
+							}
+							public boolean shouldTransformFieldAccess(String transformingClassName, String fieldOwnerClassName, String fieldName) {
+								return fieldOwnerClassName.startsWith( "org.hibernate.test.instrument.domain" )
+										&& transformingClassName.equals( fieldOwnerClassName );
+							}
+						}
+				)
+		);
+
+	}
+
+	protected void releaseIsolatedClassLoader(ClassLoader isolatedLoader) {
+	}
+
+	protected abstract BytecodeProvider buildBytecodeProvider();
+
+
+	// the tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void testSetFieldInterceptor() {
+		executeExecutable( "org.hibernate.test.instrument.cases.TestInjectFieldInterceptorExecutable" );
+	}
+
+	public void testDirtyCheck() {
+		executeExecutable( "org.hibernate.test.instrument.cases.TestDirtyCheckExecutable" );
+	}
+
+	public void testFetchAll() throws Exception {
+		executeExecutable( "org.hibernate.test.instrument.cases.TestFetchAllExecutable" );
+	}
+
+	public void testLazy() {
+		executeExecutable( "org.hibernate.test.instrument.cases.TestLazyExecutable" );
+	}
+
+	public void testLazyManyToOne() {
+		executeExecutable( "org.hibernate.test.instrument.cases.TestLazyManyToOneExecutable" );
+	}
+
+	public void testPropertyInitialized() {
+		executeExecutable( "org.hibernate.test.instrument.cases.TestIsPropertyInitializedExecutable" );
+	}
+
+	public void testManyToOneProxy() {
+		executeExecutable( "org.hibernate.test.instrument.cases.TestManyToOneProxyExecutable" );
+	}
+
+	public void testLazyPropertyCustomType() {
+		executeExecutable( "org.hibernate.test.instrument.cases.TestLazyPropertyCustomTypeExecutable" );
+	}
+
+
+
+	// reflection code to ensure isolation into the created classloader ~~~~~~~
+
+	private static final Class[] SIG = new Class[] {};
+	private static final Object[] ARGS = new Object[] {};
+
+	public void executeExecutable(String name) {
+		Class execClass = null;
+		Object executable = null;
+		try {
+			execClass = Thread.currentThread().getContextClassLoader().loadClass( name );
+			executable = execClass.newInstance();
+		}
+		catch( Throwable t ) {
+			throw new HibernateException( "could not load executable", t );
+		}
+		try {
+			execClass.getMethod( "prepare", SIG ).invoke( executable, ARGS );
+			execClass.getMethod( "execute", SIG ).invoke( executable, ARGS );
+		}
+		catch ( NoSuchMethodException e ) {
+			throw new HibernateException( "could not exeucte executable", e );
+		}
+		catch ( IllegalAccessException e ) {
+			throw new HibernateException( "could not exeucte executable", e );
+		}
+		catch ( InvocationTargetException e ) {
+			throw new HibernateException( "could not exeucte executable", e.getTargetException() );
+		}
+		finally {
+			try {
+				execClass.getMethod( "complete", SIG ).invoke( executable, ARGS );
+			}
+			catch ( Throwable ignore ) {
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/runtime/CGLIBInstrumentationTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/runtime/CGLIBInstrumentationTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/runtime/CGLIBInstrumentationTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+package org.hibernate.test.instrument.runtime;
+
+import org.hibernate.bytecode.BytecodeProvider;
+import org.hibernate.bytecode.cglib.BytecodeProviderImpl;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * @author Steve Ebersole
+ */
+public class CGLIBInstrumentationTest extends AbstractTransformingClassLoaderInstrumentTestCase {
+	public CGLIBInstrumentationTest(String string) {
+		super( string );
+	}
+
+	protected BytecodeProvider buildBytecodeProvider() {
+		return new BytecodeProviderImpl();
+	}
+
+	public static Test suite() {
+		return new TestSuite( CGLIBInstrumentationTest.class );
+	}
+
+	public void testSetFieldInterceptor() {
+		super.testSetFieldInterceptor();    //To change body of overridden methods use File | Settings | File Templates.
+	}
+
+	public void testDirtyCheck() {
+		super.testDirtyCheck();    //To change body of overridden methods use File | Settings | File Templates.
+	}
+
+	public void testFetchAll() throws Exception {
+		super.testFetchAll();    //To change body of overridden methods use File | Settings | File Templates.
+	}
+
+	public void testLazy() {
+		super.testLazy();    //To change body of overridden methods use File | Settings | File Templates.
+	}
+
+	public void testLazyManyToOne() {
+		super.testLazyManyToOne();    //To change body of overridden methods use File | Settings | File Templates.
+	}
+
+	public void testPropertyInitialized() {
+		super.testPropertyInitialized();    //To change body of overridden methods use File | Settings | File Templates.
+	}
+
+	public void testManyToOneProxy() {
+		super.testManyToOneProxy();    //To change body of overridden methods use File | Settings | File Templates.
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/runtime/JavassistInstrumentationTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/runtime/JavassistInstrumentationTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/instrument/runtime/JavassistInstrumentationTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+//$Id: $
+package org.hibernate.test.instrument.runtime;
+
+import org.hibernate.bytecode.BytecodeProvider;
+import org.hibernate.bytecode.javassist.BytecodeProviderImpl;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * @author Steve Ebersole
+ */
+public class JavassistInstrumentationTest extends AbstractTransformingClassLoaderInstrumentTestCase {
+	public JavassistInstrumentationTest(String string) {
+		super( string );
+	}
+
+	protected BytecodeProvider buildBytecodeProvider() {
+		return new BytecodeProviderImpl();
+	}
+
+	public static Test suite() {
+		return new TestSuite( JavassistInstrumentationTest.class );
+	}
+
+	public void testSetFieldInterceptor() {
+		super.testSetFieldInterceptor();
+	}
+
+	public void testDirtyCheck() {
+		super.testDirtyCheck();
+	}
+
+	public void testFetchAll() throws Exception {
+		super.testFetchAll();
+	}
+
+	public void testLazy() {
+		super.testLazy();
+	}
+
+	public void testLazyManyToOne() {
+		super.testLazyManyToOne();
+	}
+
+	public void testPropertyInitialized() {
+		super.testPropertyInitialized();
+	}
+
+	public void testManyToOneProxy() {
+		super.testManyToOneProxy();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/CollectionInterceptor.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/CollectionInterceptor.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/CollectionInterceptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+//$Id: CollectionInterceptor.java 7700 2005-07-30 05:02:47Z oneovthafew $
+package org.hibernate.test.interceptor;
+
+import java.io.Serializable;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.type.Type;
+
+public class CollectionInterceptor extends EmptyInterceptor {
+
+	public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
+		( (User) entity ).getActions().add("updated");
+		return false;
+	}
+
+	public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
+		( (User) entity ).getActions().add("created");
+		return false;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/CollectionInterceptor.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/Image.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/Image.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/Image.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.interceptor">
+
+    <class name="Image" table="image" abstract="false" select-before-update="true" >
+        <id name="id" type="java.lang.Long" column="id">
+            <generator class="native"/>
+        </id>
+        <component name="details" class="Image$Details">
+            <property name="perm1" not-null="true" type="long" column="permissions"/>
+            <property name="comment" type="string" column="comment_txt"/>
+        </component>
+        <property name="name" type="java.lang.String" column="name" not-null="true"/>
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/Image.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/Image.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/Image.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+package org.hibernate.test.interceptor;
+
+public class Image {
+
+	private Long id;
+	private String name;
+	private Details details;
+
+	public Details getDetails() {
+		return details;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setDetails(Details details) {
+		this.details = details;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String toString() {
+		return "Image/" + ( details == null ? "no details" : details.toString() );
+	}
+
+	public static class Details {
+		private long perm1 = -1; // all bits turned on.
+		private String comment;
+
+		protected long getPerm1() {
+			return this.perm1;
+		}
+
+		protected void setPerm1(long value) {
+			this.perm1 = value;
+		}
+
+		public String getComment() {
+			return comment;
+		}
+
+		public void setComment(String comment) {
+			this.comment = comment;
+		}
+
+		public String toString() {
+			return "Details=" + perm1;
+		}
+	}
+
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/InterceptorTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/InterceptorTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/InterceptorTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,168 @@
+//$Id: InterceptorTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.interceptor;
+
+import java.io.Serializable;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.type.Type;
+
+/**
+ * @author Gavin King
+ */
+public class InterceptorTest extends FunctionalTestCase {
+
+	public InterceptorTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "interceptor/User.hbm.xml", "interceptor/Image.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( InterceptorTest.class );
+	}
+
+	public void testCollectionIntercept() {
+		Session s = openSession( new CollectionInterceptor() );
+		Transaction t = s.beginTransaction();
+		User u = new User("Gavin", "nivag");
+		s.persist(u);
+		u.setPassword("vagni");
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		u = (User) s.get(User.class, "Gavin");
+		assertEquals( 2, u.getActions().size() );
+		s.delete(u);
+		t.commit();
+		s.close();
+	}
+
+	public void testPropertyIntercept() {
+		Session s = openSession( new PropertyInterceptor() );
+		Transaction t = s.beginTransaction();
+		User u = new User("Gavin", "nivag");
+		s.persist(u);
+		u.setPassword("vagni");
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		u = (User) s.get(User.class, "Gavin");
+		assertNotNull( u.getCreated() );
+		assertNotNull( u.getLastUpdated() );
+		s.delete(u);
+		t.commit();
+		s.close();
+	}
+
+	/**
+	 * Test case from HHH-1921.  Here the interceptor resets the
+	 * current-state to the same thing as the current db state; this
+	 * causes EntityPersister.findDirty() to return no dirty properties.
+	 */
+	public void testPropertyIntercept2() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User u = new User("Josh", "test");
+		s.persist( u );
+		t.commit();
+		s.close();
+
+		s = openSession(
+				new EmptyInterceptor() {
+					public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
+						currentState[0] = "test";
+						return true;
+					}
+				}
+		);
+		t = s.beginTransaction();
+		u = ( User ) s.get( User.class, u.getName() );
+		u.setPassword( "nottest" );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		u = (User) s.get(User.class, "Josh");
+		assertEquals("test", u.getPassword());
+		s.delete(u);
+		t.commit();
+		s.close();
+
+	}
+
+	public void testComponentInterceptor() {
+		final int checkPerm = 500;
+		final String checkComment = "generated from interceptor";
+
+		Session s = openSession(
+				new EmptyInterceptor() {
+					public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
+						if ( state[0] == null ) {
+							Image.Details detail = new Image.Details();
+							detail.setPerm1( checkPerm );
+							detail.setComment( checkComment );
+							state[0] = detail;
+						}
+						return true;
+					}
+				}
+		);
+		s.beginTransaction();
+		Image i = new Image();
+		i.setName( "compincomp" );
+		i = ( Image ) s.merge( i );
+		assertNotNull( i.getDetails() );
+		assertEquals( checkPerm, i.getDetails().getPerm1() );
+		assertEquals( checkComment, i.getDetails().getComment() );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		i = ( Image ) s.get( Image.class, i.getId() );
+		assertNotNull( i.getDetails() );
+		assertEquals( checkPerm, i.getDetails().getPerm1() );
+		assertEquals( checkComment, i.getDetails().getComment() );
+		s.delete( i );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testStatefulIntercept() {
+		final StatefulInterceptor statefulInterceptor = new StatefulInterceptor();
+		Session s = openSession( statefulInterceptor );
+		statefulInterceptor.setSession(s);
+
+		Transaction t = s.beginTransaction();
+		User u = new User("Gavin", "nivag");
+		s.persist(u);
+		u.setPassword("vagni");
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		List logs = s.createCriteria(Log.class).list();
+		assertEquals( 2, logs.size() );
+		s.delete(u);
+		s.createQuery( "delete from Log" ).executeUpdate();
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/InterceptorTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/Log.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/Log.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/Log.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+//$Id: Log.java 7700 2005-07-30 05:02:47Z oneovthafew $
+package org.hibernate.test.interceptor;
+
+import java.util.Calendar;
+
+public class Log {
+	private Long id;
+	private String entityName;
+	private String entityId;
+	private String action;
+	private Calendar time;
+	
+	public Log(String action, String id, String name) {
+		super();
+		this.action = action;
+		entityId = id;
+		entityName = name;
+		time = Calendar.getInstance();
+	}
+	public Log() {
+		super();
+	}
+	public String getAction() {
+		return action;
+	}
+	public void setAction(String action) {
+		this.action = action;
+	}
+	public String getEntityId() {
+		return entityId;
+	}
+	public void setEntityId(String entityId) {
+		this.entityId = entityId;
+	}
+	public String getEntityName() {
+		return entityName;
+	}
+	public void setEntityName(String entityName) {
+		this.entityName = entityName;
+	}
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public Calendar getTime() {
+		return time;
+	}
+	public void setTime(Calendar time) {
+		this.time = time;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/Log.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/PropertyInterceptor.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/PropertyInterceptor.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/PropertyInterceptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: PropertyInterceptor.java 7700 2005-07-30 05:02:47Z oneovthafew $
+package org.hibernate.test.interceptor;
+
+import java.io.Serializable;
+import java.util.Calendar;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.type.Type;
+
+public class PropertyInterceptor extends EmptyInterceptor {
+
+	public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
+		currentState[1] = Calendar.getInstance();
+		return true;
+	}
+
+	public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
+		state[2] = Calendar.getInstance();
+		return true;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/PropertyInterceptor.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/StatefulInterceptor.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/StatefulInterceptor.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/StatefulInterceptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+//$Id: StatefulInterceptor.java 7701 2005-07-30 05:07:01Z oneovthafew $
+package org.hibernate.test.interceptor;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.Session;
+import org.hibernate.type.Type;
+
+public class StatefulInterceptor extends EmptyInterceptor {
+	
+	private Session session;
+
+	private List list = new ArrayList();
+	
+	public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
+		if ( !(entity instanceof Log) ) {
+			list.add( new Log( "insert", (String) id, entity.getClass().getName() ) );
+		}
+		return false;
+	}
+
+	public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
+		if ( !(entity instanceof Log) ) {
+			list.add( new Log( "update", (String) id, entity.getClass().getName() ) );
+		}
+		return false;
+	}
+
+	public void postFlush(Iterator entities) {
+		if ( list.size()>0 ) {
+			for ( Iterator iter = list.iterator(); iter.hasNext(); ) {
+				session.persist( iter.next() );	
+			}
+			list.clear();
+			session.flush();
+		}
+	}
+	
+	public void setSession(Session s) {
+		session = s;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/StatefulInterceptor.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/User.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/User.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/User.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+     
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.interceptor">
+	
+	<class name="User" table="users">
+		<id name="name"/>
+		<property name="password"/>
+		<property name="lastUpdated"/>
+		<property name="created"/>
+		<set name="actions" lazy="false" fetch="join">
+			<key column="user_name"/>
+			<element column="action" type="string"/>
+		</set>
+	</class>
+	
+	<class name="Log" table="log_entries">
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		<property name="entityName" column="entity_name"/>
+		<property name="entityId" column="entity_id"/>
+		<property name="action"/>
+		<property name="time" column="action_time"/>
+	</class>
+	
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/User.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+//$Id: User.java 7700 2005-07-30 05:02:47Z oneovthafew $
+package org.hibernate.test.interceptor;
+
+import java.util.Calendar;
+import java.util.HashSet;
+import java.util.Set;
+
+public class User {
+	private String name;
+	private String password;
+	private Set actions = new HashSet();
+	private Calendar lastUpdated;
+	private Calendar created;
+	
+	public User(String name, String password) {
+		super();
+		this.name = name;
+		this.password = password;
+	}
+	public User() {
+		super();
+	}
+	public Calendar getLastUpdated() {
+		return lastUpdated;
+	}
+	public void setLastUpdated(Calendar lastUpdated) {
+		this.lastUpdated = lastUpdated;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getPassword() {
+		return password;
+	}
+	public void setPassword(String password) {
+		this.password = password;
+	}
+	public Set getActions() {
+		return actions;
+	}
+	public void setActions(Set actions) {
+		this.actions = actions;
+	}
+	public Calendar getCreated() {
+		return created;
+	}
+	public void setCreated(Calendar created) {
+		this.created = created;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interceptor/User.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Document.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Document.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Document.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+//$Id: Document.java 4407 2004-08-22 01:20:08Z oneovthafew $
+package org.hibernate.test.interfaceproxy;
+
+import java.sql.Blob;
+import java.util.Calendar;
+
+/**
+ * @author Gavin King
+ */
+public interface Document extends Item {
+	/**
+	 * @return Returns the content.
+	 */
+	public Blob getContent();
+
+	/**
+	 * @param content The content to set.
+	 */
+	public void setContent(Blob content);
+	
+	public Calendar getCreated();
+	
+	public Calendar getModified();
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Document.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/DocumentImpl.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/DocumentImpl.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/DocumentImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+//$Id: DocumentImpl.java 4407 2004-08-22 01:20:08Z oneovthafew $
+package org.hibernate.test.interfaceproxy;
+
+import java.sql.Blob;
+import java.util.Calendar;
+
+/**
+ * @author Gavin King
+ */
+public class DocumentImpl extends ItemImpl implements Document {
+	private Blob content;
+	private Calendar modified;
+	private Calendar created;
+	/**
+	 * @return Returns the created.
+	 */
+	public Calendar getCreated() {
+		return created;
+	}
+	/**
+	 * @param created The created to set.
+	 */
+	public void setCreated(Calendar created) {
+		this.created = created;
+	}
+	/**
+	 * @return Returns the modified.
+	 */
+	public Calendar getModified() {
+		return modified;
+	}
+	/**
+	 * @param modified The modified to set.
+	 */
+	public void setModified(Calendar modified) {
+		this.modified = modified;
+	}
+	/**
+	 * @return Returns the content.
+	 */
+	public Blob getContent() {
+		return content;
+	}
+	/**
+	 * @param content The content to set.
+	 */
+	public void setContent(Blob content) {
+		this.content = content;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/DocumentImpl.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/DocumentInterceptor.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/DocumentInterceptor.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/DocumentInterceptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,95 @@
+//$Id: DocumentInterceptor.java 7860 2005-08-11 21:58:23Z oneovthafew $
+package org.hibernate.test.interfaceproxy;
+
+import java.io.Serializable;
+import java.util.Calendar;
+import java.util.Iterator;
+
+import org.hibernate.CallbackException;
+import org.hibernate.Interceptor;
+import org.hibernate.Transaction;
+import org.hibernate.EntityMode;
+import org.hibernate.type.Type;
+
+/**
+ * @author Gavin King
+ */
+public class DocumentInterceptor implements Interceptor {
+
+
+	public boolean onLoad(Object entity, Serializable id, Object[] state,
+			String[] propertyNames, Type[] types) throws CallbackException {
+		return false;
+	}
+
+	public boolean onFlushDirty(Object entity, Serializable id,
+			Object[] currentState, Object[] previousState,
+			String[] propertyNames, Type[] types) throws CallbackException {
+		if ( entity instanceof Document ) {
+			currentState[2] = Calendar.getInstance();
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	public boolean onSave(Object entity, Serializable id, Object[] state,
+			String[] propertyNames, Type[] types) throws CallbackException {
+		if ( entity instanceof Document ) {
+			state[3] = state[2] = Calendar.getInstance();
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	public void onDelete(Object entity, Serializable id, Object[] state,
+			String[] propertyNames, Type[] types) throws CallbackException {
+
+	}
+
+	public void preFlush(Iterator entities) throws CallbackException {
+
+	}
+
+	public void postFlush(Iterator entities) throws CallbackException {
+
+	}
+
+	public Boolean isTransient(Object entity) {
+		return null;
+	}
+
+	public int[] findDirty(Object entity, Serializable id,
+			Object[] currentState, Object[] previousState,
+			String[] propertyNames, Type[] types) {
+		return null;
+	}
+
+	public Object instantiate(String entityName, EntityMode entityMode, Serializable id) throws CallbackException {
+		return null;
+	}
+
+	public String getEntityName(Object object) throws CallbackException {
+		return null;
+	}
+
+	public Object getEntity(String entityName, Serializable id)
+			throws CallbackException {
+		return null;
+	}
+
+	public void afterTransactionBegin(Transaction tx) {}
+	public void afterTransactionCompletion(Transaction tx) {}
+	public void beforeTransactionCompletion(Transaction tx) {}
+
+	public String onPrepareStatement(String sql) {
+		return sql;
+	}
+
+	public void onCollectionRecreate(Object collection, Serializable key) throws CallbackException {}
+	public void onCollectionRemove(Object collection, Serializable key) throws CallbackException {}
+	public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException {}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/DocumentInterceptor.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Folder.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Folder.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Folder.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+//$Id: Folder.java 4407 2004-08-22 01:20:08Z oneovthafew $
+package org.hibernate.test.interfaceproxy;
+
+/**
+ * @author Gavin King
+ */
+public interface Folder extends Item {
+	/**
+	 * @return Returns the parent.
+	 */
+	public Folder getParent();
+
+	/**
+	 * @param parent The parent to set.
+	 */
+	public void setParent(Folder parent);
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Folder.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/FolderImpl.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/FolderImpl.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/FolderImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+//$Id: FolderImpl.java 4407 2004-08-22 01:20:08Z oneovthafew $
+package org.hibernate.test.interfaceproxy;
+
+/**
+ * @author Gavin King
+ */
+public class FolderImpl extends ItemImpl implements Folder {
+	private Folder parent;
+	/**
+	 * @return Returns the parent.
+	 */
+	public Folder getParent() {
+		return parent;
+	}
+	/**
+	 * @param parent The parent to set.
+	 */
+	public void setParent(Folder parent) {
+		this.parent = parent;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/FolderImpl.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/InterfaceProxyTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/InterfaceProxyTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/InterfaceProxyTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,101 @@
+//$Id: InterfaceProxyTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.interfaceproxy;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.dialect.PostgreSQLDialect;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class InterfaceProxyTest extends FunctionalTestCase {
+	
+	public InterfaceProxyTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "interfaceproxy/Item.hbm.xml" };
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( InterfaceProxyTest.class );
+	}
+	
+	public void testInterfaceProxies() {
+		
+		if ( getDialect() instanceof PostgreSQLDialect ) {
+			// TODO : why?
+			return;
+		}
+		
+		Session s = openSession( new DocumentInterceptor() );
+		Transaction t = s.beginTransaction();
+		Document d = new DocumentImpl();
+		d.setName("Hibernate in Action");
+		d.setContent( Hibernate.createBlob( "blah blah blah".getBytes() ) );
+		Long did = (Long) s.save(d);
+		SecureDocument d2 = new SecureDocumentImpl();
+		d2.setName("Secret");
+		d2.setContent( Hibernate.createBlob( "wxyz wxyz".getBytes() ) );
+		d2.setPermissionBits( (byte) 664 );
+		d2.setOwner("gavin");
+		Long d2id = (Long) s.save(d2);
+		t.commit();
+		s.close();
+
+		s = openSession( new DocumentInterceptor() );
+		t = s.beginTransaction();
+		d = (Document) s.load(ItemImpl.class, did);
+		assertEquals( did, d.getId() );
+		assertEquals( "Hibernate in Action", d.getName() );
+		assertNotNull( d.getContent() );
+		
+		d2 = (SecureDocument) s.load(ItemImpl.class, d2id);
+		assertEquals( d2id, d2.getId() );
+		assertEquals( "Secret", d2.getName() );
+		assertNotNull( d2.getContent() );
+		
+		s.clear();
+		
+		d = (Document) s.load(DocumentImpl.class, did);
+		assertEquals( did, d.getId() );
+		assertEquals( "Hibernate in Action", d.getName() );
+		assertNotNull( d.getContent() );
+		
+		d2 = (SecureDocument) s.load(SecureDocumentImpl.class, d2id);
+		assertEquals( d2id, d2.getId() );
+		assertEquals( "Secret", d2.getName() );
+		assertNotNull( d2.getContent() );
+		assertEquals( "gavin", d2.getOwner() );
+		
+		//s.clear();
+		
+		d2 = (SecureDocument) s.load(SecureDocumentImpl.class, did);
+		assertEquals( did, d2.getId() );
+		assertEquals( "Hibernate in Action", d2.getName() );
+		assertNotNull( d2.getContent() );
+		
+		try {
+			d2.getOwner(); //CCE
+			assertFalse(true);
+		}
+		catch (ClassCastException cce) {
+			//correct
+		}
+
+		s.createQuery( "delete ItemImpl" ).executeUpdate();
+		t.commit();
+		s.close();
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/InterfaceProxyTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Item.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Item.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Item.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+  This mapping demonstrates the use of interface proxies,
+  and fields which are initialized by an interceptor.
+  
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.interfaceproxy">
+	
+	<class name="ItemImpl" 
+		table="Items"
+		proxy="Item">
+	
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		
+		<property name="name"
+			not-null="true"/>
+		
+		<joined-subclass name="DocumentImpl" 
+			table="Documents"
+			proxy="Document">
+			
+			<key column="id"/>
+			
+			<property name="content"
+				not-null="true"/>
+			
+			<!-- managed by DocumentInterceptor -->
+			<property name="modified"
+				not-null="true"/>
+			<property name="created"
+				not-null="true"/>
+			
+			<joined-subclass name="SecureDocumentImpl"
+				table="SecureDocuments"
+				proxy="SecureDocument">
+				
+				<key column="documentId"/>
+				
+				<property name="permissionBits" 
+					not-null="true"/>
+				<property name="owner"
+					not-null="true"/>
+				
+			</joined-subclass>
+			
+		</joined-subclass>
+		
+		<joined-subclass name="FolderImpl"
+			table="Folders"
+			proxy="Folder">
+			
+			<key column="id"/>
+			
+			<many-to-one name="parent"
+				class="FolderImpl"/>
+				
+		</joined-subclass>
+		
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Item.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Item.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Item.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Item.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: Item.java 4407 2004-08-22 01:20:08Z oneovthafew $
+package org.hibernate.test.interfaceproxy;
+
+/**
+ * @author Gavin King
+ */
+public interface Item {
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId();
+
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName();
+
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name);
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/Item.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/ItemImpl.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/ItemImpl.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/ItemImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+//$Id: ItemImpl.java 4407 2004-08-22 01:20:08Z oneovthafew $
+package org.hibernate.test.interfaceproxy;
+
+/**
+ * @author Gavin King
+ */
+public abstract class ItemImpl implements Item {
+	private Long id;
+	private String name;
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/ItemImpl.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/SecureDocument.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/SecureDocument.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/SecureDocument.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+//$Id: SecureDocument.java 4407 2004-08-22 01:20:08Z oneovthafew $
+package org.hibernate.test.interfaceproxy;
+
+/**
+ * @author Gavin King
+ */
+public interface SecureDocument extends Document {
+	/**
+	 * @return Returns the owner.
+	 */
+	public String getOwner();
+
+	/**
+	 * @param owner The owner to set.
+	 */
+	public void setOwner(String owner);
+
+	/**
+	 * @return Returns the permissionBits.
+	 */
+	public byte getPermissionBits();
+
+	/**
+	 * @param permissionBits The permissionBits to set.
+	 */
+	public void setPermissionBits(byte permissionBits);
+}
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/SecureDocument.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/SecureDocumentImpl.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/SecureDocumentImpl.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/SecureDocumentImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+//$Id: SecureDocumentImpl.java 4407 2004-08-22 01:20:08Z oneovthafew $
+package org.hibernate.test.interfaceproxy;
+
+/**
+ * @author Gavin King
+ */
+public class SecureDocumentImpl extends DocumentImpl implements SecureDocument {
+	private byte permissionBits;
+	private String owner;
+	/**
+	 * @return Returns the owner.
+	 */
+	public String getOwner() {
+		return owner;
+	}
+	/**
+	 * @param owner The owner to set.
+	 */
+	public void setOwner(String owner) {
+		this.owner = owner;
+	}
+	/**
+	 * @return Returns the permissionBits.
+	 */
+	public byte getPermissionBits() {
+		return permissionBits;
+	}
+	/**
+	 * @param permissionBits The permissionBits to set.
+	 */
+	public void setPermissionBits(byte permissionBits) {
+		this.permissionBits = permissionBits;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/interfaceproxy/SecureDocumentImpl.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/Item.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/Item.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/Item.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.iterate">
+
+	<class name="Item" table="NamedItem" entity-name="Item">
+		<id name="name"/>
+		<query name="nameDesc">from Item order by name desc</query>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/Item.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/Item.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/Item.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/Item.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+//$Id: Item.java 6593 2005-04-28 15:52:26Z oneovthafew $
+package org.hibernate.test.iterate;
+
+/**
+ * @author Gavin King
+ */
+public class Item {
+	private String name;
+	Item() {}
+	public Item(String n) {
+		name = n;
+	}
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/Item.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/IterateTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/IterateTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/IterateTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,105 @@
+//$Id: IterateTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.iterate;
+
+import java.util.Iterator;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class IterateTest extends FunctionalTestCase {
+	
+	public IterateTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "iterate/Item.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.USE_QUERY_CACHE, "true" );
+		cfg.setProperty( Environment.CACHE_REGION_PREFIX, "foo" );
+		cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( IterateTest.class );
+	}
+	
+	public void testIterate() throws Exception {
+		getSessions().getStatistics().clear();
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Item i1 = new Item("foo");
+		Item i2 = new Item("bar");
+		s.persist("Item", i1);
+		s.persist("Item", i2);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Iterator iter = s.getNamedQuery("Item.nameDesc").iterate();
+		i1 = (Item) iter.next();
+		i2 = (Item) iter.next();
+		assertFalse( Hibernate.isInitialized(i1) );
+		assertFalse( Hibernate.isInitialized(i2) );
+		i1.getName();
+		i2.getName();
+		assertFalse( Hibernate.isInitialized(i1) );
+		assertFalse( Hibernate.isInitialized(i2) );
+		assertEquals( i1.getName(), "foo" );
+		assertEquals( i2.getName(), "bar" );
+		Hibernate.initialize(i1);
+		assertFalse( iter.hasNext() );
+		s.delete(i1);
+		s.delete(i2);
+		t.commit();
+		s.close();
+		assertEquals( getSessions().getStatistics().getEntityFetchCount(), 2 );
+	}
+	
+	public void testScroll() throws Exception {
+		getSessions().getStatistics().clear();
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Item i1 = new Item("foo");
+		Item i2 = new Item("bar");
+		s.persist("Item", i1);
+		s.persist("Item", i2);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		ScrollableResults sr = s.getNamedQuery("Item.nameDesc").scroll();
+		assertTrue( sr.next() );
+		i1 = (Item) sr.get(0);
+		assertTrue( sr.next() );
+		i2 = (Item) sr.get(0);
+		assertTrue( Hibernate.isInitialized(i1) );
+		assertTrue( Hibernate.isInitialized(i2) );
+		assertEquals( i1.getName(), "foo" );
+		assertEquals( i2.getName(), "bar" );
+		assertFalse( sr.next() );
+		s.delete(i1);
+		s.delete(i2);
+		t.commit();
+		s.close();
+		assertEquals( getSessions().getStatistics().getEntityFetchCount(), 0 );
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/iterate/IterateTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: Customer.java 4364 2004-08-17 12:10:32Z oneovthafew $
+package org.hibernate.test.join;
+
+/**
+ * @author Gavin King
+ */
+public class Customer extends Person {
+	private Employee salesperson;
+	private String comments;
+
+	/**
+	 * @return Returns the salesperson.
+	 */
+	public Employee getSalesperson() {
+		return salesperson;
+	}
+	/**
+	 * @param salesperson The salesperson to set.
+	 */
+	public void setSalesperson(Employee salesperson) {
+		this.salesperson = salesperson;
+	}
+	/**
+	 * @return Returns the comments.
+	 */
+	public String getComments() {
+		return comments;
+	}
+	/**
+	 * @param comments The comments to set.
+	 */
+	public void setComments(String comments) {
+		this.comments = comments;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Customer.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Employee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Employee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Employee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: Employee.java 4364 2004-08-17 12:10:32Z oneovthafew $
+package org.hibernate.test.join;
+
+import java.math.BigDecimal;
+
+/**
+ * @author Gavin King
+ */
+public class Employee extends Person {
+	private String title;
+	private BigDecimal salary;
+	private Employee manager;
+	/**
+	 * @return Returns the title.
+	 */
+	public String getTitle() {
+		return title;
+	}
+	/**
+	 * @param title The title to set.
+	 */
+	public void setTitle(String title) {
+		this.title = title;
+	}
+	/**
+	 * @return Returns the manager.
+	 */
+	public Employee getManager() {
+		return manager;
+	}
+	/**
+	 * @param manager The manager to set.
+	 */
+	public void setManager(Employee manager) {
+		this.manager = manager;
+	}
+	/**
+	 * @return Returns the salary.
+	 */
+	public BigDecimal getSalary() {
+		return salary;
+	}
+	/**
+	 * @param salary The salary to set.
+	 */
+	public void setSalary(BigDecimal salary) {
+		this.salary = salary;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Employee.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/JoinTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/JoinTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/JoinTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,135 @@
+//$Id: JoinTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.join;
+
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class JoinTest extends FunctionalTestCase {
+	
+	public JoinTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "join/Person.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( JoinTest.class );
+	}
+	
+	public void testSequentialSelects() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		
+		Employee mark = new Employee();
+		mark.setName("Mark");
+		mark.setTitle("internal sales");
+		mark.setSex('M');
+		mark.setAddress("buckhead");
+		mark.setZip("30305");
+		mark.setCountry("USA");
+		
+		Customer joe = new Customer();
+		joe.setName("Joe");
+		joe.setAddress("San Francisco");
+		joe.setZip("XXXXX");
+		joe.setCountry("USA");
+		joe.setComments("Very demanding");
+		joe.setSex('M');
+		joe.setSalesperson(mark);
+		
+		Person yomomma = new Person();
+		yomomma.setName("mum");
+		yomomma.setSex('F');
+		
+		s.save(yomomma);
+		s.save(mark);
+		s.save(joe);		
+		
+		assertEquals( s.createQuery("from java.io.Serializable").list().size(), 0 );
+		
+		assertEquals( s.createQuery("from Person").list().size(), 3 );
+		assertEquals( s.createQuery("from Person p where p.class is null").list().size(), 1 );
+		assertEquals( s.createQuery("from Person p where p.class = Customer").list().size(), 1 );
+		assertTrue(s.createQuery("from Customer c").list().size()==1);
+		s.clear();
+
+		List customers = s.createQuery("from Customer c left join fetch c.salesperson").list();
+		for ( Iterator iter = customers.iterator(); iter.hasNext(); ) {
+			Customer c = (Customer) iter.next();
+			assertTrue( Hibernate.isInitialized( c.getSalesperson() ) );
+			assertEquals( c.getSalesperson().getName(), "Mark" );
+		}
+		assertEquals( customers.size(), 1 );
+		s.clear();
+		
+		customers = s.createQuery("from Customer").list();
+		for ( Iterator iter = customers.iterator(); iter.hasNext(); ) {
+			Customer c = (Customer) iter.next();
+			assertFalse( Hibernate.isInitialized( c.getSalesperson() ) );
+			assertEquals( c.getSalesperson().getName(), "Mark" );
+		}
+		assertEquals( customers.size(), 1 );
+		s.clear();
+		
+
+		mark = (Employee) s.get( Employee.class, new Long( mark.getId() ) );
+		joe = (Customer) s.get( Customer.class, new Long( joe.getId() ) );
+		
+ 		mark.setZip("30306");
+		assertEquals( s.createQuery("from Person p where p.zip = '30306'").list().size(), 1 );
+		s.delete(mark);
+		s.delete(joe);
+		s.delete(yomomma);
+		assertTrue( s.createQuery("from Person").list().isEmpty() );
+		t.commit();
+		s.close();
+	}
+
+	public void testSequentialSelectsOptionalData() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		User jesus = new User();
+		jesus.setName("Jesus Olvera y Martinez");
+		jesus.setSex('M');
+
+		s.save(jesus);
+
+		assertEquals( s.createQuery("from java.io.Serializable").list().size(), 0 );
+		
+		assertEquals( s.createQuery("from Person").list().size(), 1 );
+		assertEquals( s.createQuery("from Person p where p.class is null").list().size(), 0 );
+		assertEquals( s.createQuery("from Person p where p.class = User").list().size(), 1 );
+		assertTrue(s.createQuery("from User u").list().size()==1);
+		s.clear();
+
+		// Remove the optional row from the join table and requery the User obj
+		s.connection().prepareStatement("delete from t_user").execute();
+		s.clear();
+
+		jesus = (User) s.get( Person.class, new Long( jesus.getId() ) );
+		s.clear();
+
+		// Cleanup the test data
+		s.delete(jesus);
+
+		assertTrue( s.createQuery("from Person").list().isEmpty() );
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/JoinTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates 
+
+     (1) a table-per-subclass mapping strategy where subclass data is
+         retrieved by sequential select instead of a join (we do NOT
+         recommend you do this, since it is very vulnerable to N+1
+         problems; users porting applications from TopLink might find
+         this useful for reproducing old behavior)
+         
+     (2) spreading data from a single class across multiple tables
+         (again, we do not recommend you do this; use finer grained
+         classes instead)
+     
+     (3) use of null as a discriminator value
+     
+     (4) recursive associations withing an inheritance tree
+     
+-->
+
+<hibernate-mapping package="org.hibernate.test.join" default-access="field">
+
+    <class name="Person" table="person" lazy="true" discriminator-value="null">
+
+        <id name="id" column="person_id" unsaved-value="0">
+            <generator class="native"/>
+        </id>
+
+        <!-- force is unnecessary, in case we had other unknown discriminator values -->
+        <discriminator column="person_type" type="string" length="1" not-null="false" force="true"/>
+
+        <property name="name" not-null="true" length="80"/>
+        <property name="sex" not-null="true" update="false"/>
+
+        <join table="address">
+            <key column="address_id"/>
+            <property name="address"/>
+            <property name="zip"/>
+            <property name="country"/>
+        </join>
+
+        <subclass name="Employee" lazy="true" discriminator-value="E">
+            <join table="employee" fetch="select">
+                <key column="person_id"/>
+                <property name="title" not-null="true" length="20"/>
+                <property name="salary" length="0"/>
+                <many-to-one name="manager"/>
+            </join>
+        </subclass>
+
+        <subclass name="Customer" lazy="true" discriminator-value="C">
+            <join table="customer" fetch="select">
+                <key column="person_id"/>
+                <property name="comments"/>
+                <many-to-one name="salesperson"/>
+            </join>
+        </subclass>
+
+        <subclass name="User" lazy="true" discriminator-value="U">
+            <join table="t_user" fetch="select" optional="true">
+                <key column="person_id"/>
+                <property name="login" column="u_login"/>
+            </join>
+            <join table="t_silly" fetch="select" optional="true">
+                <key column="person_id"/>
+                <property name="silly"/>
+            </join>
+        </subclass>
+
+    </class>
+
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Person.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,90 @@
+//$Id: Person.java 7203 2005-06-19 02:01:05Z oneovthafew $
+package org.hibernate.test.join;
+
+
+/**
+ * @author Gavin King
+ */
+public class Person {
+	private long id;
+	private String name;
+	private String address;
+	private String zip;
+	private String country;
+	private char sex;
+	
+	/**
+	 * @return Returns the sex.
+	 */
+	public char getSex() {
+		return sex;
+	}
+	/**
+	 * @param sex The sex to set.
+	 */
+	public void setSex(char sex) {
+		this.sex = sex;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the identity.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param identity The identity to set.
+	 */
+	public void setName(String identity) {
+		this.name = identity;
+	}
+	public String getSpecies() {
+		return null;
+	}
+
+	/**
+	 * @return Returns the country.
+	 */
+	public String getCountry() {
+		return country;
+	}
+	/**
+	 * @param country The country to set.
+	 */
+	public void setCountry(String country) {
+		this.country = country;
+	}
+	/**
+	 * @return Returns the zip.
+	 */
+	public String getZip() {
+		return zip;
+	}
+	/**
+	 * @param zip The zip to set.
+	 */
+	public void setZip(String zip) {
+		this.zip = zip;
+	}
+	/**
+	 * @param address The address to set.
+	 */
+	public void setAddress(String address) {
+		this.address = address;
+	}
+	
+	public String getAddress() {
+		return address;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/join/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+//$Id$
+package org.hibernate.test.join;
+
+/**
+ * @author Mike Dillon
+ */
+public class User extends Person {
+	private String login;
+	private String silly;
+
+	/**
+	 * @return Returns the login.
+	 */
+	public String getLogin() {
+		return login;
+	}
+	/**
+	 * @param login The login to set.
+	 */
+	public void setLogin(String login) {
+		this.login = login;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,11 @@
+//$Id: Address.java 4364 2004-08-17 12:10:32Z oneovthafew $
+package org.hibernate.test.joinedsubclass;
+
+/**
+ * @author Gavin King
+ */
+public class Address {
+	public String address;
+	public String zip;
+	public String country;
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Address.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: Customer.java 4364 2004-08-17 12:10:32Z oneovthafew $
+package org.hibernate.test.joinedsubclass;
+
+/**
+ * @author Gavin King
+ */
+public class Customer extends Person {
+	private Employee salesperson;
+	private String comments;
+
+	/**
+	 * @return Returns the salesperson.
+	 */
+	public Employee getSalesperson() {
+		return salesperson;
+	}
+	/**
+	 * @param salesperson The salesperson to set.
+	 */
+	public void setSalesperson(Employee salesperson) {
+		this.salesperson = salesperson;
+	}
+	/**
+	 * @return Returns the comments.
+	 */
+	public String getComments() {
+		return comments;
+	}
+	/**
+	 * @param comments The comments to set.
+	 */
+	public void setComments(String comments) {
+		this.comments = comments;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Customer.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Employee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Employee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Employee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: Employee.java 4364 2004-08-17 12:10:32Z oneovthafew $
+package org.hibernate.test.joinedsubclass;
+
+import java.math.BigDecimal;
+
+/**
+ * @author Gavin King
+ */
+public class Employee extends Person {
+	private String title;
+	private BigDecimal salary;
+	private Employee manager;
+	/**
+	 * @return Returns the title.
+	 */
+	public String getTitle() {
+		return title;
+	}
+	/**
+	 * @param title The title to set.
+	 */
+	public void setTitle(String title) {
+		this.title = title;
+	}
+	/**
+	 * @return Returns the manager.
+	 */
+	public Employee getManager() {
+		return manager;
+	}
+	/**
+	 * @param manager The manager to set.
+	 */
+	public void setManager(Employee manager) {
+		this.manager = manager;
+	}
+	/**
+	 * @return Returns the salary.
+	 */
+	public BigDecimal getSalary() {
+		return salary;
+	}
+	/**
+	 * @param salary The salary to set.
+	 */
+	public void setSalary(BigDecimal salary) {
+		this.salary = salary;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Employee.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/JoinedSubclassTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/JoinedSubclassTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/JoinedSubclassTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,211 @@
+//$Id: JoinedSubclassTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.joinedsubclass;
+
+import java.math.BigDecimal;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.criterion.Expression;
+import org.hibernate.criterion.Property;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class JoinedSubclassTest extends FunctionalTestCase {
+
+	public JoinedSubclassTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "joinedsubclass/Person.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( JoinedSubclassTest.class );
+	}
+
+	public void testJoinedSubclass() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Employee mark = new Employee();
+		mark.setName("Mark");
+		mark.setTitle("internal sales");
+		mark.setSex('M');
+		mark.setAddress("buckhead");
+		mark.setZip("30305");
+		mark.setCountry("USA");
+
+		Customer joe = new Customer();
+		joe.setName("Joe");
+		joe.setAddress("San Francisco");
+		joe.setZip("XXXXX");
+		joe.setCountry("USA");
+		joe.setComments("Very demanding");
+		joe.setSex('M');
+		joe.setSalesperson(mark);
+
+		Person yomomma = new Person();
+		yomomma.setName("mum");
+		yomomma.setSex('F');
+
+		s.save(yomomma);
+		s.save(mark);
+		s.save(joe);
+
+		assertEquals( s.createQuery("from java.io.Serializable").list().size(), 0 );
+
+		assertEquals( s.createQuery("from Person").list().size(), 3 );
+		assertEquals( s.createQuery("from Person p where p.class = Customer").list().size(), 1 );
+		assertEquals( s.createQuery("from Person p where p.class = Person").list().size(), 1 );
+		s.clear();
+
+		List customers = s.createQuery("from Customer c left join fetch c.salesperson").list();
+		for ( Iterator iter = customers.iterator(); iter.hasNext(); ) {
+			Customer c = (Customer) iter.next();
+			assertTrue( Hibernate.isInitialized( c.getSalesperson() ) );
+			assertEquals( c.getSalesperson().getName(), "Mark" );
+		}
+		assertEquals( customers.size(), 1 );
+		s.clear();
+
+		customers = s.createQuery("from Customer").list();
+		for ( Iterator iter = customers.iterator(); iter.hasNext(); ) {
+			Customer c = (Customer) iter.next();
+			assertFalse( Hibernate.isInitialized( c.getSalesperson() ) );
+			assertEquals( c.getSalesperson().getName(), "Mark" );
+		}
+		assertEquals( customers.size(), 1 );
+		s.clear();
+
+
+		mark = (Employee) s.get( Employee.class, new Long( mark.getId() ) );
+		joe = (Customer) s.get( Customer.class, new Long( joe.getId() ) );
+
+ 		mark.setZip("30306");
+		assertEquals( s.createQuery("from Person p where p.address.zip = '30306'").list().size(), 1 );
+
+		if ( supportsRowValueConstructorSyntaxInInList() ) {
+			s.createCriteria(Person.class).add(
+					Expression.in("address", new Address[] { mark.getAddress(), joe.getAddress() } )
+			).list();
+		}
+
+		s.delete(mark);
+		s.delete(joe);
+		s.delete(yomomma);
+		assertTrue( s.createQuery("from Person").list().isEmpty() );
+		t.commit();
+		s.close();
+	}
+
+	public void testAccessAsIncorrectSubclass() {
+		Session s = openSession();
+		s.beginTransaction();
+		Employee e = new Employee();
+		e.setName( "Steve" );
+		e.setSex( 'M' );
+		e.setTitle( "grand poobah" );
+		s.save( e );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		Customer c = ( Customer ) s.get( Customer.class, new Long( e.getId() ) );
+		s.getTransaction().commit();
+		s.close();
+		assertNull( c );
+
+		s = openSession();
+		s.beginTransaction();
+		e = ( Employee ) s.get( Employee.class, new Long( e.getId() ) );
+		c = ( Customer ) s.get( Customer.class, new Long( e.getId() ) );
+		s.getTransaction().commit();
+		s.close();
+		assertNotNull( e );
+		assertNull( c );
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( e );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testQuerySubclassAttribute() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person p = new Person();
+		p.setName("Emmanuel");
+		p.setSex('M');
+		s.persist(p);
+		Employee q = new Employee();
+		q.setName("Steve");
+		q.setSex('M');
+		q.setTitle("Mr");
+		q.setSalary( new BigDecimal(1000) );
+		s.persist(q);
+
+		List result = s.createQuery("from Person where salary > 100").list();
+		assertEquals( result.size(), 1 );
+		assertSame( result.get(0), q );
+
+		result = s.createQuery("from Person where salary > 100 or name like 'E%'").list();
+		assertEquals( result.size(), 2 );
+
+		result = s.createCriteria(Person.class)
+			.add( Property.forName("salary").gt( new BigDecimal(100) ) )
+			.list();
+		assertEquals( result.size(), 1 );
+		assertSame( result.get(0), q );
+
+		//TODO: make this work:
+		/*result = s.createQuery("select salary from Person where salary > 100").list();
+		assertEquals( result.size(), 1 );
+		assertEquals( result.get(0), new BigDecimal(1000) );*/
+
+		s.delete(p);
+		s.delete(q);
+		t.commit();
+		s.close();
+	}
+
+	public void testLockingJoinedSubclass() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person p = new Person();
+		p.setName("Emmanuel");
+		p.setSex('M');
+		s.persist(p);
+		Employee q = new Employee();
+		q.setName("Steve");
+		q.setSex('M');
+		q.setTitle("Mr");
+		q.setSalary( new BigDecimal(1000) );
+		s.persist(q);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.lock( p, LockMode.UPGRADE );
+		s.lock( q, LockMode.UPGRADE );
+		s.delete( p );
+		s.delete( q );
+		t.commit();
+		s.close();
+
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/JoinedSubclassTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates 
+
+     (1) a table-per-subclass mapping strategy
+         
+     (2) a simple component mapping
+     
+     (3) recursive associations withing an inheritance tree
+     
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.joinedsubclass"
+	default-access="field">
+	
+	<class name="Person" table="JPerson">
+		
+		<id name="id" 
+			column="person_id" 
+			unsaved-value="0">
+			<generator class="native"/>
+		</id>
+
+        <version name="version" column="version" type="int"/>
+
+        <property name="name"
+			not-null="true"
+			length="80"/>
+		<property name="sex" 
+			not-null="true"
+			update="false"/>
+		
+		<component name="address">
+			<property name="address"/>
+			<property name="zip"/>
+			<property name="country"/>
+		</component>
+		
+		<joined-subclass name="Employee" table="JEmployee">
+				<key column="person_id"/>
+				<property name="title" 
+					not-null="true" 
+					length="20"/>
+				<property name="salary" 
+					length="0"/>
+				<many-to-one name="manager"/>
+		</joined-subclass>
+		
+		<joined-subclass name="Customer" table="JManager">
+				<key column="person_id"/>
+				<property name="comments"/>
+				<many-to-one name="salesperson"/>
+		</joined-subclass>
+		
+	</class>
+	
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Person.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+//$Id: Person.java 10218 2006-08-04 18:24:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.joinedsubclass;
+
+
+/**
+ * @author Gavin King
+ */
+public class Person {
+	private long id;
+	private String name;
+	private char sex;
+	private int version;
+	private Address address = new Address();
+	/**
+	 * @return Returns the address.
+	 */
+	public Address getAddress() {
+		return address;
+	}
+
+	public void setAddress(String string) {
+		this.address.address = string;
+	}
+
+	public void setZip(String string) {
+		this.address.zip = string;
+	}
+
+	public void setCountry(String string) {
+		this.address.country = string;
+	}
+
+	
+	/**
+	 * @return Returns the sex.
+	 */
+	public char getSex() {
+		return sex;
+	}
+	/**
+	 * @param sex The sex to set.
+	 */
+	public void setSex(char sex) {
+		this.sex = sex;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the identity.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param identity The identity to set.
+	 */
+	public void setName(String identity) {
+		this.name = identity;
+	}
+
+	public int getVersion() {
+		return version;
+	}
+
+	public void setVersion(int version) {
+		this.version = version;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinedsubclass/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Bid.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Bid.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Bid.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: Bid.java 6793 2005-05-16 05:46:47Z oneovthafew $
+package org.hibernate.test.joinfetch;
+
+import java.util.Calendar;
+
+/**
+ * @author Gavin King
+ */
+public class Bid {
+	
+	private float amount;
+	private Item item;
+	private Calendar timestamp;
+	private Long id;
+
+	public float getAmount() {
+		return amount;
+	}
+	public void setAmount(float amount) {
+		this.amount = amount;
+	}
+	public Item getItem() {
+		return item;
+	}
+	public void setItem(Item item) {
+		this.item = item;
+	}
+	public Calendar getTimestamp() {
+		return timestamp;
+	}
+	public void setTimestamp(Calendar timestamp) {
+		this.timestamp = timestamp;
+	}
+	
+	Bid() {}
+	public Bid(Item item, float amount) {
+		this.amount = amount;
+		this.item = item;
+		item.getBids().add(this);
+		this.timestamp = Calendar.getInstance();
+	}
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Bid.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Category.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Category.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Category.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+//$Id: Category.java 6957 2005-05-31 04:21:58Z oneovthafew $
+package org.hibernate.test.joinfetch;
+
+/**
+ * @author Gavin King
+ */
+public class Category {
+	
+	private String name;
+
+	Category() {}
+
+	public Category(String name) {
+		this.name = name;
+	}
+	
+	public String getName() {
+		return name;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Category.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Comment.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Comment.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Comment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: Comment.java 6797 2005-05-16 12:08:03Z oneovthafew $
+package org.hibernate.test.joinfetch;
+
+import java.util.Calendar;
+
+/**
+ * @author Gavin King
+ */
+public class Comment {
+	
+	private String text;
+	private Item item;
+	private Calendar timestamp;
+	private Long id;
+
+	public Item getItem() {
+		return item;
+	}
+	public void setItem(Item item) {
+		this.item = item;
+	}
+	public Calendar getTimestamp() {
+		return timestamp;
+	}
+	public void setTimestamp(Calendar timestamp) {
+		this.timestamp = timestamp;
+	}
+	
+	Comment() {}
+	public Comment(Item item, String comment) {
+		this.text = comment;
+		this.item = item;
+		item.getComments().add(this);
+		this.timestamp = Calendar.getInstance();
+	}
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public String getText() {
+		return text;
+	}
+	public void setText(String text) {
+		this.text = text;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Comment.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Group.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Group.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Group.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+//$Id: Group.java 7175 2005-06-17 05:23:15Z oneovthafew $
+package org.hibernate.test.joinfetch;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Group {
+	private String name;
+	private Map users = new HashMap();
+	
+	public Group(String name) {
+		this.name = name;
+	}
+
+	Group() {}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Map getUsers() {
+		return users;
+	}
+
+	public void setUsers(Map users) {
+		this.users = users;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Group.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Item.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Item.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Item.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+//$Id: Item.java 6957 2005-05-31 04:21:58Z oneovthafew $
+package org.hibernate.test.joinfetch;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class Item {
+	
+	private String description;
+	private Long id;
+	private Category category;
+	private Set bids = new HashSet();
+	private Set comments = new HashSet();
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	Item() {}
+	public Item(Category cat, String desc) { 
+		description = desc; 
+		category = cat;
+	}
+
+	public Set getBids() {
+		return bids;
+	}
+
+	public void setBids(Set bids) {
+		this.bids = bids;
+	}
+
+	public Set getComments() {
+		return comments;
+	}
+
+	public void setComments(Set comments) {
+		this.comments = comments;
+	}
+
+	public Category getCategory() {
+		return category;
+	}
+
+	public void setCategory(Category category) {
+		this.category = category;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/Item.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/ItemBid.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/ItemBid.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/ItemBid.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+     
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.joinfetch"
+	default-access="field">
+	
+	<class name="Category" table="AuctionCategories">
+		<id name="name"/>
+	</class>
+	
+	<class name="Item" table="AuctionItems">
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		<property name="description" not-null="true"/>
+		<many-to-one name="category" not-null="true"/>
+		<set name="bids" cascade="all" fetch="join" inverse="true" order-by="`timestamp`">
+			<key column="item"/>
+			<one-to-many class="Bid"/>
+		</set>
+		<set name="comments" cascade="all" fetch="join" inverse="true" order-by="`timestamp`">
+			<key column="item"/>
+			<one-to-many class="Comment"/>
+		</set>
+
+		<sql-query name="all">
+			<return alias="item" class="Item"/>
+			<return-join alias="bid" property="item.bids"/>
+			<return-join alias="commnt" property="item.comments"/>
+			select {item.*}, {bid.*}, {commnt.*} 
+			from AuctionItems item
+				left outer join AuctionBids bid on bid.item = item.id
+				left outer join AuctionComments commnt on commnt.item = item.id
+		</sql-query>
+
+	</class>
+	
+	<class name="Bid" table="AuctionBids">
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		<property name="amount" not-null="true"/>
+		<property name="timestamp" column="`timestamp`" not-null="true"/>
+		<many-to-one name="item" fetch="join" not-null="true"/>
+	</class>
+
+	<class name="Comment" table="AuctionComments">
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		<property name="text" not-null="true"/>
+		<property name="timestamp" column="`timestamp`" not-null="true"/>
+		<many-to-one name="item" fetch="join" not-null="true"/>
+	</class>
+	
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/ItemBid.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/JoinFetchTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/JoinFetchTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/JoinFetchTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,267 @@
+//$Id: JoinFetchTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.joinfetch;
+
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.Projections;
+import org.hibernate.criterion.Restrictions;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class JoinFetchTest extends FunctionalTestCase {
+	
+	public JoinFetchTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "joinfetch/ItemBid.hbm.xml", "joinfetch/UserGroup.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.MAX_FETCH_DEPTH, "10");
+		cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "false");
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( JoinFetchTest.class );
+	}
+	
+	public void testProjection() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createCriteria(Item.class).setProjection( Projections.rowCount() ).uniqueResult();
+		s.createCriteria(Item.class).uniqueResult();
+		t.commit();
+		s.close();
+	}
+
+	public void testJoinFetch() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createQuery( "delete from Bid" ).executeUpdate();
+		s.createQuery( "delete from Comment" ).executeUpdate();
+		s.createQuery( "delete from Item" ).executeUpdate();
+		t.commit();
+		s.close();
+		
+		Category cat = new Category("Photography");
+		Item i = new Item(cat, "Camera");
+		Bid b = new Bid(i, 100.0f);
+		new Bid(i, 105.0f);
+		new Comment(i, "This looks like a really good deal");
+		new Comment(i, "Is it the latest version?");
+		new Comment(i, "<comment deleted>");
+		System.out.println( b.getTimestamp() );
+		
+		s = openSession();
+		t = s.beginTransaction();
+		s.persist(cat);
+		s.persist(i);
+		t.commit();
+		s.close();
+		
+		getSessions().evict(Item.class);
+
+		s = openSession();
+		t = s.beginTransaction();
+		i = (Item) s.get( Item.class, i.getId() );
+		assertTrue( Hibernate.isInitialized( i.getBids() ) );
+		assertEquals( i.getBids().size(), 2 );
+		assertTrue( Hibernate.isInitialized( i.getComments() ) );
+		assertEquals( i.getComments().size(), 3 );
+		t.commit();
+		s.close();
+
+		getSessions().evict(Bid.class);
+
+		s = openSession();
+		t = s.beginTransaction();
+		b = (Bid) s.get( Bid.class, b.getId() );
+		assertTrue( Hibernate.isInitialized( b.getItem() ) );
+		assertTrue( Hibernate.isInitialized( b.getItem().getComments() ) );
+		assertEquals( b.getItem().getComments().size(), 3 );
+		System.out.println( b.getTimestamp() );
+		t.commit();
+		s.close();
+
+		getSessions().evictCollection(Item.class.getName() + ".bids");
+		
+		s = openSession();
+		t = s.beginTransaction();
+		i = (Item) s.createCriteria( Item.class )
+			.setFetchMode("bids", FetchMode.SELECT)
+			.setFetchMode("comments", FetchMode.SELECT)
+			.uniqueResult();
+		assertFalse( Hibernate.isInitialized( i.getBids() ) );
+		assertFalse( Hibernate.isInitialized( i.getComments() ) );
+		b = (Bid) i.getBids().iterator().next();
+		assertTrue( Hibernate.isInitialized( b.getItem() ) );
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		i = (Item) s.createQuery("from Item i left join fetch i.bids left join fetch i.comments").uniqueResult();
+		assertTrue( Hibernate.isInitialized( i.getBids() ) );
+		assertTrue( Hibernate.isInitialized( i.getComments() ) );
+		assertEquals( i.getComments().size(), 3 );
+		assertEquals( i.getBids().size(), 2 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Object[] row = (Object[]) s.getNamedQuery(Item.class.getName() + ".all").list().get(0);
+		i = (Item) row[0];
+		assertTrue( Hibernate.isInitialized( i.getBids() ) );
+		assertTrue( Hibernate.isInitialized( i.getComments() ) );
+		assertEquals( i.getComments().size(), 3 );
+		assertEquals( i.getBids().size(), 2 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		i = (Item) s.createCriteria(Item.class).uniqueResult();
+		assertTrue( Hibernate.isInitialized( i.getBids() ) );
+		assertTrue( Hibernate.isInitialized( i.getComments() ) );
+		assertEquals( i.getComments().size(), 3 );
+		assertEquals( i.getBids().size(), 2 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		List bids = s.createQuery("from Bid b left join fetch b.item i left join fetch i.category").list();
+		Bid bid = (Bid) bids.get(0);
+		assertTrue( Hibernate.isInitialized( bid.getItem() ) );
+		assertTrue( Hibernate.isInitialized( bid.getItem().getCategory() ) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		List pairs = s.createQuery("from Item i left join i.bids b left join fetch i.category").list();
+		Item item = (Item) ( (Object[]) pairs.get(0) )[0];
+		assertFalse( Hibernate.isInitialized( item.getBids() ) );
+		assertTrue( Hibernate.isInitialized( item.getCategory() ) );
+		s.clear();
+		pairs = s.createQuery("from Item i left join i.bids b left join i.category").list();
+		item = (Item) ( (Object[]) pairs.get(0) )[0];
+		assertFalse( Hibernate.isInitialized( item.getBids() ) );
+		assertTrue( Hibernate.isInitialized( item.getCategory() ) );
+		s.clear();
+		pairs = s.createQuery("from Bid b left join b.item i left join fetch i.category").list();
+		bid = (Bid) ( (Object[]) pairs.get(0) )[0];
+		assertTrue( Hibernate.isInitialized( bid.getItem() ) );
+		assertTrue( Hibernate.isInitialized( bid.getItem().getCategory() ) );
+		s.clear();
+		pairs = s.createQuery("from Bid b left join b.item i left join i.category").list();
+		bid = (Bid) ( (Object[]) pairs.get(0) )[0];
+		assertTrue( Hibernate.isInitialized( bid.getItem() ) );
+		assertTrue( Hibernate.isInitialized( bid.getItem().getCategory() ) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery( "delete from Bid" ).executeUpdate();
+		s.createQuery( "delete from Comment" ).executeUpdate();
+		s.createQuery( "delete from Item" ).executeUpdate();
+		s.createQuery( "delete from Category" ).executeUpdate();
+		t.commit();
+		s.close();
+
+	}
+	
+	public void testCollectionFilter() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Group hb = new Group("hibernate");
+		User gavin = new User("gavin");
+		User max = new User("max");
+		hb.getUsers().put("gavin", gavin);
+		hb.getUsers().put("max", max);
+		gavin.getGroups().put("hibernate", hb);
+		max.getGroups().put("hibernate", hb);
+		s.persist(hb);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		hb = (Group) s.createCriteria(Group.class)
+				.setFetchMode("users", FetchMode.SELECT)
+				.add( Restrictions.idEq("hibernate") )
+				.uniqueResult();
+		assertFalse( Hibernate.isInitialized( hb.getUsers() ) );
+		//gavin = (User) s.createFilter( hb.getUsers(), "where index(this) = 'gavin'" ).uniqueResult();
+		Long size = (Long) s.createFilter( hb.getUsers(), "select count(*)" ).uniqueResult();
+		assertEquals( new Long(2), size );
+		assertFalse( Hibernate.isInitialized( hb.getUsers() ) );
+		s.delete(hb);
+		t.commit();
+		s.close();
+		
+	}
+	
+	public void testJoinFetchManyToMany() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Group hb = new Group("hibernate");
+		User gavin = new User("gavin");
+		User max = new User("max");
+		hb.getUsers().put("gavin", gavin);
+		hb.getUsers().put("max", max);
+		gavin.getGroups().put("hibernate", hb);
+		max.getGroups().put("hibernate", hb);
+		s.persist(hb);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		hb = (Group) s.get(Group.class, "hibernate");
+		assertTrue( Hibernate.isInitialized( hb.getUsers() ) );
+		gavin = (User) hb.getUsers().get("gavin");
+		assertFalse( Hibernate.isInitialized( gavin.getGroups() ) );
+		max = (User) s.get(User.class, "max");
+		assertFalse( Hibernate.isInitialized( max.getGroups() ) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		hb = (Group) s.createCriteria(Group.class)
+			.setFetchMode("users", FetchMode.JOIN)
+			.setFetchMode("users.groups", FetchMode.JOIN)
+			.uniqueResult();
+		assertTrue( Hibernate.isInitialized( hb.getUsers() ) );
+		gavin = (User) hb.getUsers().get("gavin");
+		assertTrue( Hibernate.isInitialized( gavin.getGroups() ) );
+		max = (User) s.get(User.class, "max");
+		assertTrue( Hibernate.isInitialized( max.getGroups() ) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete(hb);
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/JoinFetchTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+//$Id: User.java 7175 2005-06-17 05:23:15Z oneovthafew $
+package org.hibernate.test.joinfetch;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class User {
+	private String name;
+	private Map groups = new HashMap();
+
+	public User(String name) {
+		this.name = name;
+	}
+
+	User() {}
+
+	public Map getGroups() {
+		return groups;
+	}
+
+	public void setGroups(Map groups) {
+		this.groups = groups;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/User.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/UserGroup.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/UserGroup.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/UserGroup.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+     
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.joinfetch"
+	default-access="field">
+	
+	<class name="User" table="AuctionUsers">
+		<id name="name"/>
+		<map name="groups" table="AuctionUsersGroups" fetch="join" order-by="groupName">
+			<key column="`userName`"/>
+			<map-key formula="groupName" type="string"/>
+			<many-to-many column="groupName" class="Group"/>
+		</map>
+	</class>
+	
+	<class name="Group" table="AuctionGroups">
+		<id name="name"/>
+		<map name="users" table="AuctionUsersGroups" fetch="join" order-by="`userName`" inverse="true" cascade="all">
+			<key column="groupName"/>
+			<map-key formula="`userName`" type="string"/>
+			<many-to-many column="`userName`" class="User"/>
+		</map>
+	</class>
+	
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/joinfetch/UserGroup.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/AbstractJPATest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/AbstractJPATest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/AbstractJPATest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,149 @@
+package org.hibernate.test.jpa;
+
+import org.hibernate.test.TestCase;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.proxy.EntityNotFoundDelegate;
+import org.hibernate.event.def.DefaultPersistEventListener;
+import org.hibernate.event.def.DefaultAutoFlushEventListener;
+import org.hibernate.event.def.DefaultFlushEventListener;
+import org.hibernate.event.def.DefaultFlushEntityEventListener;
+import org.hibernate.event.AutoFlushEventListener;
+import org.hibernate.event.FlushEventListener;
+import org.hibernate.event.PersistEventListener;
+import org.hibernate.event.FlushEntityEventListener;
+import org.hibernate.engine.CascadingAction;
+import org.hibernate.util.IdentityMap;
+import org.hibernate.junit.functional.FunctionalTestCase;
+
+import java.io.Serializable;
+
+/**
+ * An abstract test for all JPA spec related tests.
+ *
+ * @author Steve Ebersole
+ */
+public class AbstractJPATest extends FunctionalTestCase {
+	public AbstractJPATest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "jpa/Part.hbm.xml", "jpa/Item.hbm.xml", "jpa/MyEntity.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.JPAQL_STRICT_COMPLIANCE, "true" );
+		cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false" );
+		cfg.setEntityNotFoundDelegate( new JPAEntityNotFoundDelegate() );
+		cfg.getEventListeners().setPersistEventListeners( buildPersistEventListeners() );
+		cfg.getEventListeners().setPersistOnFlushEventListeners( buildPersisOnFlushEventListeners() );
+		cfg.getEventListeners().setAutoFlushEventListeners( buildAutoFlushEventListeners() );
+		cfg.getEventListeners().setFlushEventListeners( buildFlushEventListeners() );
+		cfg.getEventListeners().setFlushEntityEventListeners( buildFlushEntityEventListeners() );
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		// no second level caching
+		return null;
+	}
+
+
+	// mimic specific exception aspects of the JPA environment ~~~~~~~~~~~~~~~~
+
+	private static class JPAEntityNotFoundDelegate implements EntityNotFoundDelegate {
+		public void handleEntityNotFound(String entityName, Serializable id) {
+			throw new EntityNotFoundException( entityName, id );
+		}
+	}
+
+	/**
+	 * Mimic the JPA EntityNotFoundException.
+	 */
+	public static class EntityNotFoundException extends RuntimeException {
+		private final String entityName;
+		private final Serializable id;
+
+		public EntityNotFoundException(String entityName, Serializable id) {
+			this( "unable to locate specified entity", entityName, id );
+		}
+
+		public EntityNotFoundException(String message, String entityName, Serializable id) {
+			super( message );
+			this.entityName = entityName;
+			this.id = id;
+		}
+
+		public String getEntityName() {
+			return entityName;
+		}
+
+		public Serializable getId() {
+			return id;
+		}
+	}
+
+
+	// mimic specific event aspects of the JPA environment ~~~~~~~~~~~~~~~~~~~~
+
+	protected PersistEventListener[] buildPersistEventListeners() {
+		return new PersistEventListener[] { new JPAPersistEventListener() };
+	}
+
+	protected PersistEventListener[] buildPersisOnFlushEventListeners() {
+		return new PersistEventListener[] { new JPAPersistOnFlushEventListener() };
+	}
+
+	protected AutoFlushEventListener[] buildAutoFlushEventListeners() {
+		return new AutoFlushEventListener[] { JPAAutoFlushEventListener.INSTANCE };
+	}
+
+	protected FlushEventListener[] buildFlushEventListeners() {
+		return new FlushEventListener[] { JPAFlushEventListener.INSTANCE };
+	}
+
+	protected FlushEntityEventListener[] buildFlushEntityEventListeners() {
+		return new FlushEntityEventListener[] { new JPAFlushEntityEventListener() };
+	}
+
+	public static class JPAPersistEventListener extends DefaultPersistEventListener {
+		// overridden in JPA impl for entity callbacks...
+	}
+
+	public static class JPAPersistOnFlushEventListener extends JPAPersistEventListener {
+		protected CascadingAction getCascadeAction() {
+			return CascadingAction.PERSIST_ON_FLUSH;
+		}
+	}
+
+	public static class JPAAutoFlushEventListener extends DefaultAutoFlushEventListener {
+		// not sure why EM code has this ...
+		public static final AutoFlushEventListener INSTANCE = new JPAAutoFlushEventListener();
+
+		protected CascadingAction getCascadingAction() {
+			return CascadingAction.PERSIST_ON_FLUSH;
+		}
+
+		protected Object getAnything() {
+			return IdentityMap.instantiate( 10 );
+		}
+	}
+
+	public static class JPAFlushEventListener extends DefaultFlushEventListener {
+		// not sure why EM code has this ...
+		public static final FlushEventListener INSTANCE = new JPAFlushEventListener();
+
+		protected CascadingAction getCascadingAction() {
+			return CascadingAction.PERSIST_ON_FLUSH;
+		}
+
+		protected Object getAnything() {
+			return IdentityMap.instantiate( 10 );
+		}
+	}
+
+	public static class JPAFlushEntityEventListener extends DefaultFlushEntityEventListener {
+		// in JPA, used mainly for preUpdate callbacks...
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Item.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Item.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Item.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.jpa">
+
+	<class name="Item" table="EJB3_ITEM">
+        <id name="id" column="ITEM_ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <version name="version" column="VERS" type="long"/>
+        <property name="name" column="NAME" not-null="true"/>
+        <!-- modeled as many-to-one even though, yes, in real life would normally be many-to-many -->
+        <set name="parts" cascade="all" fetch="subselect" inverse="true">
+            <key column="ITEM_ID"/>
+            <one-to-many class="Part"/>
+        </set>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Item.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Item.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Item.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+package org.hibernate.test.jpa;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * @author Steve Ebersole
+ */
+public class Item {
+	private Long id;
+	private String name;
+	private long version;
+	private Set parts = new HashSet();
+
+	public Item() {
+	}
+
+	public Item(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public long getVersion() {
+		return version;
+	}
+
+	public void setVersion(long version) {
+		this.version = version;
+	}
+
+	public Set getParts() {
+		return parts;
+	}
+
+	public void setParts(Set parts) {
+		this.parts = parts;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/JPAComplianceSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/JPAComplianceSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/JPAComplianceSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+package org.hibernate.test.jpa;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.hibernate.test.jpa.lock.JPALockTest;
+import org.hibernate.test.jpa.lock.RepeatableReadTest;
+import org.hibernate.test.jpa.removed.RemovedEntityTest;
+import org.hibernate.test.jpa.proxy.JPAProxyTest;
+import org.hibernate.test.jpa.fetch.FetchingTest;
+import org.hibernate.test.jpa.ql.JPAQLComplianceTest;
+import org.hibernate.test.jpa.ql.NativeQueryTest;
+import org.hibernate.test.jpa.cascade.CascadeTest;
+
+/**
+ * @author Steve Ebersole
+ */
+public class JPAComplianceSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "JPA-compliance tests");
+		suite.addTest( CascadeTest.suite() );
+		suite.addTest( FetchingTest.suite() );
+		suite.addTest( JPALockTest.suite() );
+		suite.addTest( RepeatableReadTest.suite() );
+		suite.addTest( JPAProxyTest.suite() );
+		suite.addTest( JPAQLComplianceTest.suite()  );
+		suite.addTest( NativeQueryTest.suite() );
+		suite.addTest( RemovedEntityTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/MyEntity.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/MyEntity.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/MyEntity.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.jpa">
+
+    <class name="MyEntity" table="JPA_MYENTITY" discriminator-value="E">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <discriminator column="TYPE" />
+        <property name="name" type="string"/>
+        <many-to-one name="other" class="MyEntity" />
+        <subclass name="MySubclassEntity" discriminator-value="S">
+            <property name="someSubProperty"/>
+        </subclass>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/MyEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/MyEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/MyEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+package org.hibernate.test.jpa;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class MyEntity {
+	private Long id;
+	private String name;
+	private MyEntity other;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public MyEntity getOther() {
+		return other;
+	}
+
+	public void setOther(MyEntity other) {
+		this.other = other;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/MySubclassEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/MySubclassEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/MySubclassEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+package org.hibernate.test.jpa;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class MySubclassEntity extends MyEntity {
+	private String someSubProperty;
+
+	public String getSomeSubProperty() {
+		return someSubProperty;
+	}
+
+	public void setSomeSubProperty(String someSubProperty) {
+		this.someSubProperty = someSubProperty;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Part.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Part.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Part.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.jpa">
+
+	<class name="Part" table="EJB3_PART">
+        <id name="id" column="PART_ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <many-to-one name="item" class="Item" column="ITEM_ID" cascade="save-update, lock" not-null="true"/>
+        <property name="name" column="NAME" not-null="true" type="string"/>
+        <property name="stockNumber" column="STOCK_NUM" not-null="true" type="string"/>
+        <property name="unitPrice" column="UNIT_PRICE" not-null="true" type="big_decimal"/>
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Part.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Part.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/Part.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,66 @@
+package org.hibernate.test.jpa;
+
+import java.math.BigDecimal;
+
+/**
+ * @author Steve Ebersole
+ */
+public class Part {
+	private Long id;
+	private Item item;
+	private String name;
+	private String stockNumber;
+	private BigDecimal unitPrice;
+
+	public Part() {
+	}
+
+	public Part(Item item, String name, String stockNumber, BigDecimal unitPrice) {
+		this.item = item;
+		this.name = name;
+		this.stockNumber = stockNumber;
+		this.unitPrice = unitPrice;
+
+		this.item.getParts().add( this );
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	private void setId(Long id) {
+		this.id = id;
+	}
+
+	public Item getItem() {
+		return item;
+	}
+
+	private void setItem(Item item) {
+		this.item = item;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getStockNumber() {
+		return stockNumber;
+	}
+
+	public void setStockNumber(String stockNumber) {
+		this.stockNumber = stockNumber;
+	}
+
+	public BigDecimal getUnitPrice() {
+		return unitPrice;
+	}
+
+	public void setUnitPrice(BigDecimal unitPrice) {
+		this.unitPrice = unitPrice;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/CascadeTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/CascadeTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/CascadeTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,321 @@
+package org.hibernate.test.jpa.cascade;
+
+import org.hibernate.test.jpa.AbstractJPATest;
+import org.hibernate.Session;
+import org.hibernate.TransientObjectException;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.engine.Status;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.event.FlushEntityEventListener;
+import org.hibernate.event.FlushEntityEvent;
+import org.hibernate.cfg.Configuration;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import junit.framework.Test;
+
+/**
+ * According to the JPA spec, persist()ing an entity should throw an exception
+ * when said entity contains a reference to a transient entity through a mapped
+ * association where that association is not marked for cascading the persist
+ * operation.
+ * <p/>
+ * This test-case tests that requirement in the various association style
+ * scenarios such as many-to-one, one-to-one, many-to-one (property-ref),
+ * one-to-one (property-ref).  Additionally, it performs each of these tests
+ * in both generated and assigned identifier usages...
+ *
+ * @author Steve Ebersole
+ */
+public class CascadeTest extends AbstractJPATest {
+
+	public static final Log log = LogFactory.getLog( CascadeTest.class );
+
+	public CascadeTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "jpa/cascade/ParentChild.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CascadeTest.class );
+	}
+
+	public void testManyToOneGeneratedIdsOnSave() {
+		// NOTES: Child defines a many-to-one back to its Parent.  This
+		// association does not define persist cascading (which is natural;
+		// a child should not be able to create its parent).
+		try {
+			Session s = openSession();
+			s.beginTransaction();
+			Parent p = new Parent( "parent" );
+			Child c = new Child( "child" );
+			c.setParent( p );
+			s.save( c );
+			try {
+				s.getTransaction().commit();
+				fail( "expecting TransientObjectException on flush" );
+			}
+			catch( TransientObjectException e ) {
+				// expected result
+				log.trace( "handled expected exception", e );
+				s.getTransaction().rollback();
+			}
+			finally {
+				s.close();
+			}
+		}
+		finally {
+			cleanupData();
+		}
+	}
+
+	public void testManyToOneGeneratedIds() {
+		// NOTES: Child defines a many-to-one back to its Parent.  This
+		// association does not define persist cascading (which is natural;
+		// a child should not be able to create its parent).
+		try {
+			Session s = openSession();
+			s.beginTransaction();
+			Parent p = new Parent( "parent" );
+			Child c = new Child( "child" );
+			c.setParent( p );
+			s.persist( c );
+			try {
+				s.getTransaction().commit();
+				fail( "expecting TransientObjectException on flush" );
+			}
+			catch( TransientObjectException e ) {
+				// expected result
+				log.trace( "handled expected exception", e );
+				s.getTransaction().rollback();
+			}
+			finally {
+				s.close();
+			}
+		}
+		finally {
+			cleanupData();
+		}
+	}
+
+	public void testManyToOneAssignedIds() {
+		// NOTES: Child defines a many-to-one back to its Parent.  This
+		// association does not define persist cascading (which is natural;
+		// a child should not be able to create its parent).
+		try {
+			Session s = openSession();
+			s.beginTransaction();
+			ParentAssigned p = new ParentAssigned( new Long( 1 ), "parent" );
+			ChildAssigned c = new ChildAssigned( new Long( 2 ), "child" );
+			c.setParent( p );
+			s.persist( c );
+			try {
+				s.getTransaction().commit();
+				fail( "expecting TransientObjectException on flush" );
+			}
+			catch( TransientObjectException e ) {
+				// expected result
+				log.trace( "handled expected exception", e );
+				s.getTransaction().rollback();
+			}
+			finally {
+				s.close();
+			}
+		}
+		finally {
+			cleanupData();
+		}
+	}
+
+	public void testOneToOneGeneratedIds() {
+		try {
+			Session s = openSession();
+			s.beginTransaction();
+			Parent p = new Parent( "parent" );
+			ParentInfo info = new ParentInfo( "xyz" );
+			p.setInfo( info );
+			info.setOwner( p );
+			s.persist( p );
+			try {
+				s.getTransaction().commit();
+				fail( "expecting TransientObjectException on flush" );
+			}
+			catch( TransientObjectException e ) {
+				// expected result
+				log.trace( "handled expected exception", e );
+				s.getTransaction().rollback();
+			}
+			finally {
+				s.close();
+			}
+		}
+		finally {
+			cleanupData();
+		}
+	}
+
+	public void testOneToOneAssignedIds() {
+		try {
+			Session s = openSession();
+			s.beginTransaction();
+			ParentAssigned p = new ParentAssigned( new Long( 1 ), "parent" );
+			ParentInfoAssigned info = new ParentInfoAssigned( "something secret" );
+			p.setInfo( info );
+			info.setOwner( p );
+			s.persist( p );
+			try {
+				s.getTransaction().commit();
+				fail( "expecting TransientObjectException on flush" );
+			}
+			catch( TransientObjectException e ) {
+				// expected result
+				log.trace( "handled expected exception", e );
+				s.getTransaction().rollback();
+			}
+			finally {
+				s.close();
+			}
+		}
+		finally {
+			cleanupData();
+		}
+	}
+
+	public void testManyToOnePropertyRefGeneratedIds() {
+		try {
+			Session s = openSession();
+			s.beginTransaction();
+			Parent p = new Parent( "parent" );
+			Other other = new Other();
+			other.setOwner( p );
+			s.persist( other );
+			try {
+				s.getTransaction().commit();
+				fail( "expecting TransientObjectException on flush" );
+			}
+			catch( TransientObjectException e ) {
+				// expected result
+				log.trace( "handled expected exception", e );
+				s.getTransaction().rollback();
+			}
+			finally {
+				s.close();
+			}
+		}
+		finally {
+			cleanupData();
+		}
+	}
+
+	public void testManyToOnePropertyRefAssignedIds() {
+		try {
+			Session s = openSession();
+			s.beginTransaction();
+			ParentAssigned p = new ParentAssigned( new Long( 1 ), "parent" );
+			OtherAssigned other = new OtherAssigned( new Long( 2 ) );
+			other.setOwner( p );
+			s.persist( other );
+			try {
+				s.getTransaction().commit();
+				fail( "expecting TransientObjectException on flush" );
+			}
+			catch( TransientObjectException e ) {
+				// expected result
+				log.trace( "handled expected exception", e );
+				s.getTransaction().rollback();
+			}
+			finally {
+				s.close();
+			}
+		}
+		finally {
+			cleanupData();
+		}
+	}
+
+	public void testOneToOnePropertyRefGeneratedIds() {
+		try {
+			Session s = openSession();
+			s.beginTransaction();
+			Child c2 = new Child( "c2" );
+			ChildInfo info = new ChildInfo( "blah blah blah" );
+			c2.setInfo( info );
+			info.setOwner( c2 );
+			s.persist( c2 );
+			try {
+				s.getTransaction().commit();
+				fail( "expecting TransientObjectException on flush" );
+			}
+			catch( TransientObjectException e ) {
+				// expected result
+				log.trace( "handled expected exception : " + e );
+				s.getTransaction().rollback();
+			}
+			finally {
+				s.close();
+			}
+		}
+		finally {
+			cleanupData();
+		}
+	}
+
+	public void testOneToOnePropertyRefAssignedIds() {
+		try {
+			Session s = openSession();
+			s.beginTransaction();
+			ChildAssigned c2 = new ChildAssigned( new Long( 3 ), "c3" );
+			ChildInfoAssigned info = new ChildInfoAssigned( new Long( 4 ), "blah blah blah" );
+			c2.setInfo( info );
+			info.setOwner( c2 );
+			s.persist( c2 );
+			try {
+				s.getTransaction().commit();
+				fail( "expecting TransientObjectException on flush" );
+			}
+			catch( TransientObjectException e ) {
+				// expected result
+				log.trace( "handled expected exception : " + e );
+				s.getTransaction().rollback();
+			}
+			finally {
+				s.close();
+			}
+		}
+		finally {
+			cleanupData();
+		}
+	}
+
+
+	private void cleanupData() {
+		Session s = null;
+		try {
+			s = openSession();
+			s.beginTransaction();
+			s.createQuery( "delete ChildInfoAssigned" ).executeUpdate();
+			s.createQuery( "delete ChildAssigned" ).executeUpdate();
+			s.createQuery( "delete ParentAssigned" ).executeUpdate();
+			s.createQuery( "delete ChildInfoAssigned" ).executeUpdate();
+			s.createQuery( "delete ChildAssigned" ).executeUpdate();
+			s.createQuery( "delete ParentAssigned" ).executeUpdate();
+			s.getTransaction().commit();
+		}
+		catch( Throwable t ) {
+			log.warn( "unable to cleanup test data [" + fullTestName() + "] : " + t );
+		}
+		finally {
+			if ( s != null ) {
+				try {
+					s.close();
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/Child.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/Child.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/Child.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+package org.hibernate.test.jpa.cascade;
+
+/**
+ * todo: describe Child
+ *
+ * @author Steve Ebersole
+ */
+public class Child {
+	private Long id;
+	private String name;
+	private Parent parent;
+	private ChildInfo info;
+
+	public Child() {
+	}
+
+	public Child(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Parent getParent() {
+		return parent;
+	}
+
+	public void setParent(Parent parent) {
+		this.parent = parent;
+	}
+
+	public ChildInfo getInfo() {
+		return info;
+	}
+
+	public void setInfo(ChildInfo info) {
+		this.info = info;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ChildAssigned.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ChildAssigned.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ChildAssigned.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+package org.hibernate.test.jpa.cascade;
+
+/**
+ * Child, but with an assigned identifier.
+ *
+ * @author Steve Ebersole
+ */
+public class ChildAssigned {
+	private Long id;
+	private String name;
+	private ParentAssigned parent;
+	private ChildInfoAssigned info;
+
+	public ChildAssigned() {
+	}
+
+	public ChildAssigned(Long id, String name) {
+		this.id = id;
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public ParentAssigned getParent() {
+		return parent;
+	}
+
+	public void setParent(ParentAssigned parent) {
+		this.parent = parent;
+	}
+
+	public ChildInfoAssigned getInfo() {
+		return info;
+	}
+
+	public void setInfo(ChildInfoAssigned info) {
+		this.info = info;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ChildInfo.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ChildInfo.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ChildInfo.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+package org.hibernate.test.jpa.cascade;
+
+/**
+ * todo: describe ChildInfo
+ *
+ * @author Steve Ebersole
+ */
+public class ChildInfo {
+	private Long id;
+	private Child owner;
+	private String info;
+
+	public ChildInfo() {
+	}
+
+	public ChildInfo(String info) {
+		this.info = info;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public Child getOwner() {
+		return owner;
+	}
+
+	public void setOwner(Child owner) {
+		this.owner = owner;
+	}
+
+	public String getInfo() {
+		return info;
+	}
+
+	public void setInfo(String info) {
+		this.info = info;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ChildInfoAssigned.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ChildInfoAssigned.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ChildInfoAssigned.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+package org.hibernate.test.jpa.cascade;
+
+/**
+ * todo: describe ChildInfo
+ *
+ * @author Steve Ebersole
+ */
+public class ChildInfoAssigned {
+	private Long id;
+	private ChildAssigned owner;
+	private String info;
+
+	public ChildInfoAssigned() {
+	}
+
+	public ChildInfoAssigned(Long id, String info) {
+		this.id = id;
+		this.info = info;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public ChildAssigned getOwner() {
+		return owner;
+	}
+
+	public void setOwner(ChildAssigned owner) {
+		this.owner = owner;
+	}
+
+	public String getInfo() {
+		return info;
+	}
+
+	public void setInfo(String info) {
+		this.info = info;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/Other.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/Other.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/Other.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+package org.hibernate.test.jpa.cascade;
+
+/**
+ * todo: describe Other
+ *
+ * @author Steve Ebersole
+ */
+public class Other {
+	private Long id;
+	private Parent owner;
+
+	public Long getId() {
+		return id;
+	}
+
+	public Parent getOwner() {
+		return owner;
+	}
+
+	public void setOwner(Parent owner) {
+		this.owner = owner;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/OtherAssigned.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/OtherAssigned.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/OtherAssigned.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+package org.hibernate.test.jpa.cascade;
+
+/**
+ * todo: describe Other
+ *
+ * @author Steve Ebersole
+ */
+public class OtherAssigned {
+	private Long id;
+	private ParentAssigned owner;
+
+	public OtherAssigned() {
+	}
+
+	public OtherAssigned(Long id) {
+		this.id = id;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public ParentAssigned getOwner() {
+		return owner;
+	}
+
+	public void setOwner(ParentAssigned owner) {
+		this.owner = owner;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/Parent.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/Parent.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/Parent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+package org.hibernate.test.jpa.cascade;
+
+/**
+ * todo: describe Parent
+ *
+ * @author Steve Ebersole
+ */
+public class Parent {
+	private Long id;
+	private String name;
+	private ParentInfo info;
+
+	public Parent() {
+	}
+
+	public Parent(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public ParentInfo getInfo() {
+		return info;
+	}
+
+	public void setInfo(ParentInfo info) {
+		this.info = info;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentAssigned.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentAssigned.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentAssigned.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+package org.hibernate.test.jpa.cascade;
+
+/**
+ * Parent, but with an assigned identifier.
+ *
+ * @author Steve Ebersole
+ */
+public class ParentAssigned {
+	private Long id;
+	private String name;
+	private ParentInfoAssigned info;
+
+	public ParentAssigned() {
+	}
+
+	public ParentAssigned(Long id, String name) {
+		this.id = id;
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public ParentInfoAssigned getInfo() {
+		return info;
+	}
+
+	public void setInfo(ParentInfoAssigned info) {
+		this.info = info;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentChild.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentChild.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentChild.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,97 @@
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.jpa.cascade" default-access="field">
+
+    <!-- +++++++++++++   Generated ids    ++++++++++++++++++++++ -->
+
+    <class name="Parent" table="PARENT">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="name" type="string" unique="true"/>
+        <one-to-one name="info" class="ParentInfo" cascade="none"/>
+    </class>
+
+	<class name="Child" table="CHILD">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="name" type="string"/>
+        <many-to-one name="parent" class="Parent" cascade="none"/>
+        <one-to-one name="info" property-ref="owner" class="ChildInfo" cascade="none"/>
+    </class>
+
+    <class name="ParentInfo" table="P_INFO">
+        <id name="id" column="ID" type="long">
+            <generator class="foreign">
+                <param name="property">owner</param>
+            </generator>
+        </id>
+        <property name="info" column="INFO" type="string"/>
+        <one-to-one name="owner" class="Parent" constrained="true" cascade="none"/>
+    </class>
+
+    <class name="ChildInfo" table="C_INFO">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="info" column="INFO" type="string"/>
+        <many-to-one name="owner" class="Child" column="CHILD_ID" cascade="none"/>
+    </class>
+
+    <class name="Other" table="OTHER">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <many-to-one name="owner" column="OWNER_NAME" class="Parent" property-ref="name" cascade="none"/>
+    </class>
+
+
+
+    <!-- +++++++++++++   Assigned ids    ++++++++++++++++++++++ -->
+
+    <class name="ParentAssigned" table="PARENT_A">
+        <id name="id" column="ID" type="long">
+            <generator class="assigned"/>
+        </id>
+        <property name="name" type="string" unique="true"/>
+        <one-to-one name="info" class="ParentInfoAssigned"/>
+    </class>
+
+	<class name="ChildAssigned" table="CHILD_A">
+        <id name="id" column="ID" type="long">
+            <generator class="assigned"/>
+        </id>
+        <property name="name" type="string"/>
+        <many-to-one name="parent" class="ParentAssigned" cascade="none"/>
+        <one-to-one name="info" property-ref="owner" class="ChildInfoAssigned" cascade="none"/>
+    </class>
+
+    <class name="ParentInfoAssigned" table="P_INFO_A">
+        <id name="id" column="ID" type="long">
+            <generator class="foreign">
+                <param name="property">owner</param>
+            </generator>
+        </id>
+        <property name="info" column="INFO" type="string"/>
+        <one-to-one name="owner" class="ParentAssigned" constrained="true"/>
+    </class>
+
+    <class name="ChildInfoAssigned" table="C_INFO_A">
+        <id name="id" column="ID" type="long">
+            <generator class="assigned"/>
+        </id>
+        <property name="info" column="INFO" type="string"/>
+        <many-to-one name="owner" class="ChildAssigned" column="CHILD_ID" cascade="none"/>
+    </class>
+
+    <class name="OtherAssigned" table="OTHER_A">
+        <id name="id" column="ID" type="long">
+            <generator class="assigned"/>
+        </id>
+        <many-to-one name="owner" column="OWNER_NAME" class="ParentAssigned" property-ref="name" cascade="none"/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentInfo.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentInfo.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentInfo.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+package org.hibernate.test.jpa.cascade;
+
+/**
+ * todo: describe ChildInfo
+ *
+ * @author Steve Ebersole
+ */
+public class ParentInfo {
+	private Long id;
+	private Parent owner;
+	private String info;
+
+	public ParentInfo() {
+	}
+
+	public ParentInfo(String info) {
+		this.info = info;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public Parent getOwner() {
+		return owner;
+	}
+
+	public void setOwner(Parent owner) {
+		this.owner = owner;
+	}
+
+	public String getInfo() {
+		return info;
+	}
+
+	public void setInfo(String info) {
+		this.info = info;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentInfoAssigned.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentInfoAssigned.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/cascade/ParentInfoAssigned.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+package org.hibernate.test.jpa.cascade;
+
+/**
+ * todo: describe ChildInfo
+ *
+ * @author Steve Ebersole
+ */
+public class ParentInfoAssigned {
+	private Long id;
+	private ParentAssigned owner;
+	private String info;
+
+	public ParentInfoAssigned() {
+	}
+
+	public ParentInfoAssigned(String info) {
+		this.info = info;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public ParentAssigned getOwner() {
+		return owner;
+	}
+
+	public void setOwner(ParentAssigned owner) {
+		this.owner = owner;
+	}
+
+	public String getInfo() {
+		return info;
+	}
+
+	public void setInfo(String info) {
+		this.info = info;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/FetchingTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/FetchingTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/FetchingTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,84 @@
+package org.hibernate.test.jpa.fetch;
+
+import java.util.Date;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.jpa.AbstractJPATest;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class FetchingTest extends AbstractJPATest {
+
+	public FetchingTest(String x) {
+		super( x );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "jpa/fetch/Person.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( FetchingTest.class );
+	}
+
+	public void testLazy() throws Exception {
+		Session s;
+		Transaction tx;
+		s = openSession();
+		tx = s.beginTransaction();
+		Person p = new Person( "Gavin", "King", "JBoss Inc" );
+		Stay stay = new Stay( p, new Date(), new Date(), "A380", "Blah", "Blah" );
+		p.addStay( stay );
+		s.persist( p );
+		tx.commit();
+		s.clear();
+		tx = s.beginTransaction();
+		p = (Person) s.createQuery( "select p from Person p where p.firstName = :name" )
+				.setParameter( "name", "Gavin" ).uniqueResult();
+		assertFalse( Hibernate.isInitialized( p.getStays() ) );
+		s.delete( p );
+		tx.commit();
+		s.close();
+	}
+
+	public void testHibernateFetchingLazy() throws Exception {
+		Session s;
+		Transaction tx;
+		s = openSession();
+		tx = s.beginTransaction();
+		Person p = new Person( "Gavin", "King", "JBoss Inc" );
+		Stay stay = new Stay( null, new Date(), new Date(), "A380", "Blah", "Blah" );
+		Stay stay2 = new Stay( null, new Date(), new Date(), "A320", "Blah", "Blah" );
+		Stay stay3 = new Stay( null, new Date(), new Date(), "A340", "Blah", "Blah" );
+		stay.setOldPerson( p );
+		stay2.setVeryOldPerson( p );
+		stay3.setVeryOldPerson( p );
+		p.addOldStay( stay );
+		p.addVeryOldStay( stay2 );
+		p.addVeryOldStay( stay3 );
+		s.persist( p );
+		tx.commit();
+		s.clear();
+		tx = s.beginTransaction();
+		p = (Person) s.createQuery( "select p from Person p where p.firstName = :name" )
+				.setParameter( "name", "Gavin" ).uniqueResult();
+		assertFalse( Hibernate.isInitialized( p.getOldStays() ) );
+		assertEquals( 1, p.getOldStays().size() );
+		assertFalse( "lazy extra is failing", Hibernate.isInitialized( p.getOldStays() ) );
+		s.clear();
+		stay = (Stay) s.get( Stay.class, stay.getId() );
+		assertTrue( ! Hibernate.isInitialized( stay.getOldPerson() ) );
+		s.clear();
+		stay3 = (Stay) s.get( Stay.class, stay3.getId() );
+		assertTrue( "FetchMode.JOIN should overrides lazy options", Hibernate.isInitialized( stay3.getVeryOldPerson() ) );
+		s.delete( stay3.getVeryOldPerson() );
+		tx.commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.jpa.fetch">
+
+	<class name="Person" table="PERSON">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="firstName"/>
+        <property name="lastName"/>
+        <property name="companyName"/>
+
+        <bag name="stays" cascade="all" lazy="true" inverse="true">
+            <key column="PERS_ID"/>
+            <one-to-many class="Stay"/>
+        </bag>
+
+        <bag name="oldStays" cascade="all" lazy="extra" fetch="subselect" inverse="true">
+            <key column="OLD_PERS_ID"/>
+            <one-to-many class="Stay"/>
+        </bag>
+
+        <bag name="veryOldStays" cascade="all" lazy="true" fetch="select" inverse="true">
+            <key column="VERY_OLD_PERS_ID"/>
+            <one-to-many class="Stay"/>
+        </bag>
+    </class>
+
+	<class name="Stay" table="STAY">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+
+        <property name="startDate"/>
+        <property name="endDate"/>
+        <property name="vessel"/>
+        <property name="authoriser"/>
+        <property name="comments"/>
+
+        <many-to-one name="person" column="PERS_ID" class="Person" cascade="all"/>
+        <many-to-one name="oldPerson" column="OLD_PERS_ID" class="Person" cascade="all" fetch="select"/>
+        <many-to-one name="veryOldPerson" column="VERY_OLD_PERS_ID" class="Person" cascade="all" fetch="join"/>
+
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,136 @@
+package org.hibernate.test.jpa.fetch;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Date;
+import java.util.ArrayList;
+
+/**
+ * Copied over from annotations test suite...
+ *
+ * @author Emmanuel Bernard
+ */
+public class Person implements Serializable {
+
+	// member declaration
+	private Long id;
+	private String firstName;
+	private String lastName;
+	private String companyName;
+	private Collection stays;
+	private Collection oldStays;
+	private Collection veryOldStays;
+
+	// constructors
+	public Person() {
+	}
+
+	public Person(String firstName, String lastName, String companyName) {
+		this.firstName = firstName;
+		this.lastName = lastName;
+		this.companyName = companyName;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getFirstName() {
+		return firstName;
+	}
+
+	public void setFirstName(String firstName) {
+		this.firstName = firstName;
+	}
+
+	public String getLastName() {
+		return lastName;
+	}
+
+	public void setLastName(String lastName) {
+		this.lastName = lastName;
+	}
+
+	public String getCompanyName() {
+		return companyName;
+	}
+
+	public void setCompanyName(String companyName) {
+		this.companyName = companyName;
+	}
+
+	public Collection getStays() {
+		return stays;
+	}
+
+	public void setStays(Collection stays) {
+		this.stays = stays;
+	}
+
+	public Collection getOldStays() {
+		return oldStays;
+	}
+
+	public void setOldStays(Collection oldStays) {
+		this.oldStays = oldStays;
+	}
+
+	public Collection getVeryOldStays() {
+		return veryOldStays;
+	}
+
+	public void setVeryOldStays(Collection veryOldStays) {
+		this.veryOldStays = veryOldStays;
+	}
+
+
+	// business logic
+	public void addStay(Date startDate, Date endDate, String vessel, String authoriser, String comments) {
+		Stay stay = new Stay( this, startDate, endDate, vessel, authoriser, comments );
+		addStay( stay );
+	}
+
+	public void addStay(Stay stay) {
+		Collection stays = getStays();
+		if ( stays == null ) {
+			stays = new ArrayList();
+		}
+		stays.add( stay );
+
+		this.stays = stays;
+	}
+
+	public void addOldStay(Date startDate, Date endDate, String vessel, String authoriser, String comments) {
+		Stay stay = new Stay( this, startDate, endDate, vessel, authoriser, comments );
+		addOldStay( stay );
+	}
+
+	public void addOldStay(Stay stay) {
+		Collection stays = getOldStays();
+		if ( stays == null ) {
+			stays = new ArrayList();
+		}
+		stays.add( stay );
+
+		this.oldStays = stays;
+	}
+
+	public void addVeryOldStay(Date startDate, Date endDate, String vessel, String authoriser, String comments) {
+		Stay stay = new Stay( this, startDate, endDate, vessel, authoriser, comments );
+		addVeryOldStay( stay );
+	}
+
+	public void addVeryOldStay(Stay stay) {
+		Collection stays = getVeryOldStays();
+		if ( stays == null ) {
+			stays = new ArrayList();
+		}
+		stays.add( stay );
+
+		this.veryOldStays = stays;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/Stay.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/Stay.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/fetch/Stay.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,107 @@
+package org.hibernate.test.jpa.fetch;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class Stay implements Serializable {
+
+	// member declaration
+	private Long id;
+	private Person person;
+	private Person oldPerson;
+	private Person veryOldPerson;
+	private Date startDate;
+	private Date endDate;
+	private String vessel;
+	private String authoriser;
+	private String comments;
+
+
+	// constructors
+	public Stay() {
+	}
+
+	public Stay(Person person, Date startDate, Date endDate, String vessel, String authoriser, String comments) {
+		this.authoriser = authoriser;
+		this.endDate = endDate;
+		this.person = person;
+		this.startDate = startDate;
+		this.vessel = vessel;
+		this.comments = comments;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Person getPerson() {
+		return person;
+	}
+
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+
+	public Person getOldPerson() {
+		return oldPerson;
+	}
+
+	public void setOldPerson(Person oldPerson) {
+		this.oldPerson = oldPerson;
+	}
+
+	public Person getVeryOldPerson() {
+		return veryOldPerson;
+	}
+
+	public void setVeryOldPerson(Person veryOldPerson) {
+		this.veryOldPerson = veryOldPerson;
+	}
+
+	public Date getStartDate() {
+		return startDate;
+	}
+
+	public void setStartDate(Date startDate) {
+		this.startDate = startDate;
+	}
+
+	public Date getEndDate() {
+		return endDate;
+	}
+
+	public void setEndDate(Date endDate) {
+		this.endDate = endDate;
+	}
+
+	public String getVessel() {
+		return vessel;
+	}
+
+	public void setVessel(String vessel) {
+		this.vessel = vessel;
+	}
+
+	public String getAuthoriser() {
+		return authoriser;
+	}
+
+	public void setAuthoriser(String authoriser) {
+		this.authoriser = authoriser;
+	}
+
+	public String getComments() {
+		return comments;
+	}
+
+	public void setComments(String comments) {
+		this.comments = comments;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/lock/JPALockTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/lock/JPALockTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/lock/JPALockTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,197 @@
+package org.hibernate.test.jpa.lock;
+
+import junit.framework.Test;
+
+import org.hibernate.LockMode;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.jpa.AbstractJPATest;
+import org.hibernate.test.jpa.Item;
+import org.hibernate.test.jpa.MyEntity;
+
+/**
+ * Tests specifically relating to section 3.3.5.3 [Lock Modes] of the
+ * JPA persistence specification (as of the <i>Proposed Final Draft</i>).
+ *
+ * @author Steve Ebersole
+ */
+public class JPALockTest extends AbstractJPATest {
+	public JPALockTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( JPALockTest.class );
+	}
+
+	/**
+	 * Test the equivalent of EJB3 LockModeType.READ
+	 * <p/>
+	 * From the spec:
+	 * <p/>
+	 * If transaction T1 calls lock(entity, LockModeType.READ) on a versioned object, the entity
+	 * manager must ensure that neither of the following phenomena can occur:<ul>
+	 * <li>P1 (Dirty read): Transaction T1 modifies a row. Another transaction T2 then reads that row and
+	 * obtains the modified value, before T1 has committed or rolled back. Transaction T2 eventually
+	 * commits successfully; it does not matter whether T1 commits or rolls back and whether it does
+	 * so before or after T2 commits.
+	 * <li>P2 (Non-repeatable read): Transaction T1 reads a row. Another transaction T2 then modifies or
+	 * deletes that row, before T1 has committed. Both transactions eventually commit successfully.
+	 * <p/>
+	 * This will generally be achieved by the entity manager acquiring a lock on the underlying database row.
+	 * Any such lock may be obtained immediately (so long as it is retained until commit completes), or the
+	 * lock may be deferred until commit time (although even then it must be retained until the commit completes).
+	 * Any implementation that supports repeatable reads in a way that prevents the above phenomena
+	 * is permissible.
+	 * <p/>
+	 * The persistence implementation is not required to support calling lock(entity, LockMode-Type.READ)
+	 * on a non-versioned object. When it cannot support such a lock call, it must throw the
+	 * PersistenceException. When supported, whether for versioned or non-versioned objects, LockMode-Type.READ
+	 * must always prevent the phenomena P1 and P2. Applications that call lock(entity, LockModeType.READ)
+	 * on non-versioned objects will not be portable.
+	 * <p/>
+	 * Odd as it may sound, EJB3 LockModeType.READ actually maps to the Hibernate LockMode.UPGRADE
+	 */
+	public void testLockModeTypeRead() {
+		if ( !readCommittedIsolationMaintained( "ejb3 lock tests" ) ) {
+			return;
+		}
+		if ( getDialect().doesReadCommittedCauseWritersToBlockReaders() ) {
+			reportSkip( "deadlock", "jpa read locking" );
+			return;
+		}
+
+		final String initialName = "lock test";
+		// set up some test data
+		Session s1 = getSessions().openSession();
+		Transaction t1 = s1.beginTransaction();
+		Item item = new Item();
+		item.setName( initialName );
+		s1.save( item );
+		t1.commit();
+		s1.close();
+
+		Long itemId = item.getId();
+
+		// perform the isolated update
+		s1 = getSessions().openSession();
+		t1 = s1.beginTransaction();
+		item = (Item) s1.get( Item.class, itemId );
+		s1.lock( item, LockMode.UPGRADE );
+		item.setName( "updated" );
+		s1.flush();
+
+		Session s2 = getSessions().openSession();
+		Transaction t2 = s2.beginTransaction();
+		Item item2 = (Item) s2.get( Item.class, itemId );
+		assertEquals( "isolation not maintained", initialName, item2.getName() );
+
+		t1.commit();
+		s1.close();
+
+		item2 = (Item) s2.get( Item.class, itemId );
+		assertEquals( "repeatable read not maintained", initialName, item2.getName() );
+		t2.commit();
+		s2.close();
+
+		s1 = getSessions().openSession();
+		t1 = s1.beginTransaction();
+		s1.delete( item );
+		t1.commit();
+		s1.close();
+	}
+
+	/**
+	 * Test the equivalent of EJB3 LockModeType.WRITE
+	 * <p/>
+	 * From the spec:
+	 * <p/>
+	 * If transaction T1 calls lock(entity, LockModeType.WRITE) on a versioned object, the entity
+	 * manager must avoid the phenomena P1 and P2 (as with LockModeType.READ) and must also force
+	 * an update (increment) to the entity's version column. A forced version update may be performed immediately,
+	 * or may be deferred until a flush or commit. If an entity is removed before a deferred version
+	 * update was to have been applied, the forced version update is omitted, since the underlying database
+	 * row no longer exists.
+	 * <p/>
+	 * The persistence implementation is not required to support calling lock(entity, LockMode-Type.WRITE)
+	 * on a non-versioned object. When it cannot support a such lock call, it must throw the
+	 * PersistenceException. When supported, whether for versioned or non-versioned objects, LockMode-Type.WRITE
+	 * must always prevent the phenomena P1 and P2. For non-versioned objects, whether or
+	 * not LockModeType.WRITE has any additional behaviour is vendor-specific. Applications that call
+	 * lock(entity, LockModeType.WRITE) on non-versioned objects will not be portable.
+	 * <p/>
+	 * Due to the requirement that LockModeType.WRITE needs to force a version increment,
+	 * a new Hibernate LockMode was added to support this behavior: {@link org.hibernate.LockMode#FORCE}.
+	 */
+	public void testLockModeTypeWrite() {
+		if ( !readCommittedIsolationMaintained( "ejb3 lock tests" ) ) {
+			return;
+		}
+		if ( getDialect().doesReadCommittedCauseWritersToBlockReaders() ) {
+			reportSkip( "deadlock", "jpa write locking" );
+			return;
+		}
+		final String initialName = "lock test";
+		// set up some test data
+		Session s1 = getSessions().openSession();
+		Transaction t1 = s1.beginTransaction();
+		Item item = new Item();
+		item.setName( initialName );
+		s1.save( item );
+		MyEntity myEntity = new MyEntity();
+		myEntity.setName( "Test" );
+		s1.save( myEntity );
+		t1.commit();
+		s1.close();
+
+		Long itemId = item.getId();
+		long initialVersion = item.getVersion();
+
+		s1 = getSessions().openSession();
+		t1 = s1.beginTransaction();
+		item = (Item) s1.get( Item.class, itemId );
+		s1.lock( item, LockMode.FORCE );
+		assertEquals( "no forced version increment", initialVersion + 1, item.getVersion() );
+
+		myEntity = (MyEntity) s1.get( MyEntity.class, myEntity.getId() );
+		s1.lock( myEntity, LockMode.FORCE );
+		assertTrue( "LockMode.FORCE on a unversioned entity should degrade nicely to UPGRADE", true );
+
+		s1.lock( item, LockMode.FORCE );
+		assertEquals( "subsequent LockMode.FORCE did not no-op", initialVersion + 1, item.getVersion() );
+
+		Session s2 = getSessions().openSession();
+		Transaction t2 = s2.beginTransaction();
+		Item item2 = (Item) s2.get( Item.class, itemId );
+		assertEquals( "isolation not maintained", initialName, item2.getName() );
+
+		item.setName( "updated-1" );
+		s1.flush();
+		// currently an unfortunate side effect...
+		assertEquals( initialVersion + 2, item.getVersion() );
+
+		t1.commit();
+		s1.close();
+
+		item2.setName( "updated" );
+		try {
+			t2.commit();
+			fail( "optimisitc lock should have failed" );
+		}
+		catch (Throwable ignore) {
+			// expected behavior
+			t2.rollback();
+		}
+		finally {
+			s2.close();
+		}
+
+		s1 = getSessions().openSession();
+		t1 = s1.beginTransaction();
+		s1.delete( item );
+		s1.delete( myEntity );
+		t1.commit();
+		s1.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/lock/RepeatableReadTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/lock/RepeatableReadTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/lock/RepeatableReadTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,275 @@
+package org.hibernate.test.jpa.lock;
+
+import java.math.BigDecimal;
+
+import junit.framework.Test;
+
+import org.hibernate.LockMode;
+import org.hibernate.Session;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.Transaction;
+import org.hibernate.dialect.SQLServerDialect;
+import org.hibernate.exception.SQLGrammarException;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.jpa.AbstractJPATest;
+import org.hibernate.test.jpa.Item;
+import org.hibernate.test.jpa.Part;
+
+/**
+ * Test that the Hibernate Session complies with REPEATABLE_READ isolation
+ * semantics.
+ *
+ * @author Steve Ebersole
+ */
+public class RepeatableReadTest extends AbstractJPATest {
+
+	public RepeatableReadTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( RepeatableReadTest.class );
+	}
+
+
+	// versioned entity tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void testStaleVersionedInstanceFoundInQueryResult() {
+		if ( getDialect().doesReadCommittedCauseWritersToBlockReaders()) {
+			reportSkip( "lock blocking", "stale versioned instance" );
+			return;
+		}
+		String check = "EJB3 Specification";
+		Session s1 = getSessions().openSession();
+		Transaction t1 = s1.beginTransaction();
+		Item item = new Item( check );
+		s1.save(  item );
+		t1.commit();
+		s1.close();
+
+		Long itemId = item.getId();
+		long initialVersion = item.getVersion();
+
+		// Now, open a new Session and re-load the item...
+		s1 = getSessions().openSession();
+		t1 = s1.beginTransaction();
+		item = ( Item ) s1.get( Item.class, itemId );
+
+		// now that the item is associated with the persistence-context of that session,
+		// open a new session and modify it "behind the back" of the first session
+		Session s2 = getSessions().openSession();
+		Transaction t2 = s2.beginTransaction();
+		Item item2 = ( Item ) s2.get( Item.class, itemId );
+		item2.setName( "EJB3 Persistence Spec" );
+		t2.commit();
+		s2.close();
+
+		// at this point, s1 now contains stale data, so try an hql query which
+		// returns said item and make sure we get the previously associated state
+		// (i.e., the old name and the old version)
+		item2 = ( Item ) s1.createQuery( "select i from Item i" ).list().get( 0 );
+		assertTrue( item == item2 );
+		assertEquals( "encountered non-repeatable read", check, item2.getName() );
+		assertEquals( "encountered non-repeatable read", initialVersion, item2.getVersion() );
+
+		t1.commit();
+		s1.close();
+
+		// clean up
+		s1 = getSessions().openSession();
+		t1 = s1.beginTransaction();
+		s1.createQuery( "delete Item" ).executeUpdate();
+		t1.commit();
+		s1.close();
+	}
+
+	public void testStaleVersionedInstanceFoundOnLock() {
+		if ( ! readCommittedIsolationMaintained( "repeatable read tests" ) ) {
+			return;
+		}
+		if ( getDialect().doesReadCommittedCauseWritersToBlockReaders()) {
+			reportSkip( "lock blocking", "stale versioned instance" );
+			return;
+		}
+		String check = "EJB3 Specification";
+		Session s1 = getSessions().openSession();
+		Transaction t1 = s1.beginTransaction();
+		Item item = new Item( check );
+		s1.save(  item );
+		t1.commit();
+		s1.close();
+
+		Long itemId = item.getId();
+		long initialVersion = item.getVersion();
+
+		// Now, open a new Session and re-load the item...
+		s1 = getSessions().openSession();
+		t1 = s1.beginTransaction();
+		item = ( Item ) s1.get( Item.class, itemId );
+
+		// now that the item is associated with the persistence-context of that session,
+		// open a new session and modify it "behind the back" of the first session
+		Session s2 = getSessions().openSession();
+		Transaction t2 = s2.beginTransaction();
+		Item item2 = ( Item ) s2.get( Item.class, itemId );
+		item2.setName( "EJB3 Persistence Spec" );
+		t2.commit();
+		s2.close();
+
+		// at this point, s1 now contains stale data, so acquire a READ lock
+		// and make sure we get the already associated state (i.e., the old
+		// name and the old version)
+		s1.lock( item, LockMode.READ );
+		item2 = ( Item ) s1.get( Item.class, itemId );
+		assertTrue( item == item2 );
+		assertEquals( "encountered non-repeatable read", check, item2.getName() );
+		assertEquals( "encountered non-repeatable read", initialVersion, item2.getVersion() );
+
+		// attempt to acquire an UPGRADE lock; this should fail
+		try {
+			s1.lock( item, LockMode.UPGRADE );
+			fail( "expected UPGRADE lock failure" );
+		}
+		catch( StaleObjectStateException expected ) {
+			// this is the expected behavior
+		}
+		catch( SQLGrammarException t ) {
+			if ( getDialect() instanceof SQLServerDialect ) {
+				// sql-server (using snapshot isolation) reports this as a grammar exception /:)
+				//
+				// not to mention that it seems to "lose track" of the transaction in this scenario...
+				t1.rollback();
+				t1 = s1.beginTransaction();
+			}
+			else {
+				throw t;
+			}
+		}
+
+		t1.commit();
+		s1.close();
+
+		// clean up
+		s1 = getSessions().openSession();
+		t1 = s1.beginTransaction();
+		s1.createQuery( "delete Item" ).executeUpdate();
+		t1.commit();
+		s1.close();
+	}
+
+
+	// non-versioned entity tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void testStaleNonVersionedInstanceFoundInQueryResult() {
+		if ( getDialect().doesReadCommittedCauseWritersToBlockReaders()) {
+			reportSkip( "lock blocking", "stale versioned instance" );
+			return;
+		}
+		String check = "Lock Modes";
+		Session s1 = getSessions().openSession();
+		Transaction t1 = s1.beginTransaction();
+		Part part = new Part( new Item( "EJB3 Specification" ), check, "3.3.5.3", new BigDecimal( 0.0 ) );
+		s1.save( part );
+		t1.commit();
+		s1.close();
+
+		Long partId = part.getId();
+
+		// Now, open a new Session and re-load the part...
+		s1 = getSessions().openSession();
+		t1 = s1.beginTransaction();
+		part = ( Part ) s1.get( Part.class, partId );
+
+		// now that the item is associated with the persistence-context of that session,
+		// open a new session and modify it "behind the back" of the first session
+		Session s2 = getSessions().openSession();
+		Transaction t2 = s2.beginTransaction();
+		Part part2 = ( Part ) s2.get( Part.class, partId );
+		part2.setName( "Lock Mode Types" );
+		t2.commit();
+		s2.close();
+
+		// at this point, s1 now contains stale data, so try an hql query which
+		// returns said part and make sure we get the previously associated state
+		// (i.e., the old name)
+		part2 = ( Part ) s1.createQuery( "select p from Part p" ).list().get( 0 );
+		assertTrue( part == part2 );
+		assertEquals( "encountered non-repeatable read", check, part2.getName() );
+
+		t1.commit();
+		s1.close();
+
+		// clean up
+		s1 = getSessions().openSession();
+		t1 = s1.beginTransaction();
+		s1.delete( part2 );
+		s1.delete( part2.getItem() );
+		t1.commit();
+		s1.close();
+	}
+
+	public void testStaleNonVersionedInstanceFoundOnLock() {
+		if ( ! readCommittedIsolationMaintained( "repeatable read tests" ) ) {
+			return;
+		}
+		if ( getDialect().doesReadCommittedCauseWritersToBlockReaders()) {
+			reportSkip( "lock blocking", "stale versioned instance" );
+			return;
+		}
+		String check = "Lock Modes";
+		Session s1 = getSessions().openSession();
+		Transaction t1 = s1.beginTransaction();
+		Part part = new Part( new Item( "EJB3 Specification" ), check, "3.3.5.3", new BigDecimal( 0.0 ) );
+		s1.save( part );
+		t1.commit();
+		s1.close();
+
+		Long partId = part.getId();
+
+		// Now, open a new Session and re-load the part...
+		s1 = getSessions().openSession();
+		t1 = s1.beginTransaction();
+		part = ( Part ) s1.get( Part.class, partId );
+
+		// now that the item is associated with the persistence-context of that session,
+		// open a new session and modify it "behind the back" of the first session
+		Session s2 = getSessions().openSession();
+		Transaction t2 = s2.beginTransaction();
+		Part part2 = ( Part ) s2.get( Part.class, partId );
+		part2.setName( "Lock Mode Types" );
+		t2.commit();
+		s2.close();
+
+		// at this point, s1 now contains stale data, so acquire a READ lock
+		// and make sure we get the already associated state (i.e., the old
+		// name and the old version)
+		s1.lock( part, LockMode.READ );
+		part2 = ( Part ) s1.get( Part.class, partId );
+		assertTrue( part == part2 );
+		assertEquals( "encountered non-repeatable read", check, part2.getName() );
+
+		// then acquire an UPGRADE lock; this should fail
+		try {
+			s1.lock( part, LockMode.UPGRADE );
+		}
+		catch( Throwable t ) {
+			// SQLServer, for example, immediately throws an exception here...
+			t1.rollback();
+			t1 = s1.beginTransaction();
+		}
+		part2 = ( Part ) s1.get( Part.class, partId );
+		assertTrue( part == part2 );
+		assertEquals( "encountered non-repeatable read", check, part2.getName() );
+
+		t1.commit();
+		s1.close();
+
+		// clean up
+		s1 = getSessions().openSession();
+		t1 = s1.beginTransaction();
+		s1.delete( part );
+		s1.delete( part.getItem() );
+		t1.commit();
+		s1.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/package.html
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/package.html	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/package.html	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+<html>
+	<head></head>
+	<body>
+		<p>
+			Tests for any JPA-specific behavior for which we need to ensure
+			compliance.
+		</p>
+	</body>
+</html>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/proxy/JPAProxyTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/proxy/JPAProxyTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/proxy/JPAProxyTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,99 @@
+package org.hibernate.test.jpa.proxy;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.jpa.AbstractJPATest;
+import org.hibernate.test.jpa.Item;
+
+/**
+ * Test relation between proxies and get()/load() processing
+ * and make sure the interactions match the ejb3 expectations
+ *
+ * @author Steve Ebersole
+ */
+public class JPAProxyTest extends AbstractJPATest {
+	public JPAProxyTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( JPAProxyTest.class );
+	}
+
+	public void testEjb3ProxyUsage() {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+
+		Item item = ( Item ) s.load( Item.class, new Long(-1) );
+		assertFalse( Hibernate.isInitialized( item ) );
+		try {
+			Hibernate.initialize( item );
+			fail( "proxy access did not fail on non-existent proxy" );
+		}
+		catch ( EntityNotFoundException e ) {
+			// expected behavior
+		}
+		catch ( Throwable t ) {
+			fail( "unexpected exception type on non-existent proxy access : " + t );
+		}
+
+		s.clear();
+
+		Item item2 = ( Item ) s.load( Item.class, new Long(-1) );
+		assertFalse( Hibernate.isInitialized( item2 ) );
+		assertFalse( item == item2 );
+		try {
+			item2.getName();
+			fail( "proxy access did not fail on non-existent proxy" );
+		}
+		catch ( EntityNotFoundException e ) {
+			// expected behavior
+		}
+		catch ( Throwable t ) {
+			fail( "unexpected exception type on non-existent proxy access : " + t );
+		}
+
+		txn.commit();
+		s.close();
+	}
+
+	/**
+	 * The ejb3 find() method maps to the Hibernate get() method
+	 */
+	public void testGetSemantics() {
+		Long nonExistentId = new Long( -1 );
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		Item item = ( Item ) s.get( Item.class, nonExistentId );
+		assertNull( "get() of non-existent entity did not return null", item );
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		// first load() it to generate a proxy...
+		item = ( Item ) s.load( Item.class, nonExistentId );
+		assertFalse( Hibernate.isInitialized( item ) );
+		// then try to get() it to make sure we get an exception
+		try {
+			s.get( Item.class, nonExistentId );
+			fail( "force load did not fail on non-existent entity" );
+		}
+		catch ( EntityNotFoundException e ) {
+			// expected behavior
+		}
+		catch( AssertionFailedError e ) {
+			throw e;
+		}
+		catch ( Throwable t ) {
+			fail( "unexpected exception type on non-existent entity force load : " + t );
+		}
+		txn.commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/ql/JPAQLComplianceTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/ql/JPAQLComplianceTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/ql/JPAQLComplianceTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+package org.hibernate.test.jpa.ql;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.jpa.AbstractJPATest;
+
+/**
+ * Tests for various JPAQL compliance issues
+ *
+ * @author Steve Ebersole
+ */
+public class JPAQLComplianceTest extends AbstractJPATest {
+	public JPAQLComplianceTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( JPAQLComplianceTest.class );
+	}
+
+	public void testAliasNameSameAsUnqualifiedEntityName() {
+		Session s = openSession();
+		s.beginTransaction();
+		s.createQuery( "select item from Item item" ).list();
+		s.createQuery( "select item from Item item where item.name = 'a'" ).list();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testIdentifierCaseSensitive() throws Exception {
+		Session s = openSession( );
+		// a control test (a user reported that the JPA 'case insensitivity' support
+		// caused problems with the "discriminator resolution" code; unable to reproduce)...
+		s.createQuery( "from MyEntity e where e.class = MySubclassEntity" );
+		s.createQuery( "from MyEntity e where e.other.class = MySubclassEntity" );
+		s.createQuery( "from MyEntity where other.class = MySubclassEntity" );
+
+		s.createQuery( "select object(I) from Item i").list();
+		s.close();
+	}
+
+	public void testGeneratedSubquery() {
+		Session s = openSession();
+		s.createQuery( "select c FROM Item c WHERE c.parts IS EMPTY" ).list();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/ql/NativeQueryTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/ql/NativeQueryTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/ql/NativeQueryTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+package org.hibernate.test.jpa.ql;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.jpa.AbstractJPATest;
+
+/**
+ * todo: describe NativeQueryTest
+ *
+ * @author Steve Ebersole
+ */
+public class NativeQueryTest extends AbstractJPATest {
+	public NativeQueryTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( NativeQueryTest.class );
+	}
+
+	public void testJpaStylePositionalParametersInNativeSql() {
+		Session s = openSession();
+		s.beginTransaction();
+		s.createSQLQuery( "select NAME from EJB3_ITEM where ITEM_ID = ?1" ).setParameter( "1", "123" ).list();
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/removed/RemovedEntityTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/removed/RemovedEntityTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/jpa/removed/RemovedEntityTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+package org.hibernate.test.jpa.removed;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.jpa.AbstractJPATest;
+import org.hibernate.test.jpa.Item;
+
+/**
+ *
+ * @author Steve Ebersole
+ */
+public class RemovedEntityTest extends AbstractJPATest {
+	public RemovedEntityTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( RemovedEntityTest.class );
+	}
+
+	public void testRemoveThenContains() {
+		Session s = openSession();
+		s.beginTransaction();
+		Item item = new Item();
+		item.setName( "dummy" );
+		s.persist( item );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( item );
+		boolean contains = s.contains( item );
+		s.getTransaction().commit();
+		s.close();
+
+		assertFalse( "expecting removed entity to not be contained", contains );
+	}
+
+	public void testRemoveThenGet() {
+		Session s = openSession();
+		s.beginTransaction();
+		Item item = new Item();
+		item.setName( "dummy" );
+		s.persist( item );
+		s.getTransaction().commit();
+		s.close();
+
+		Long id = item.getId();
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( item );
+		item = ( Item ) s.get( Item.class, id );
+		s.getTransaction().commit();
+		s.close();
+
+		assertNull( "expecting removed entity to be returned as null from get()", item );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/KeyManyToOneSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/KeyManyToOneSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/KeyManyToOneSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+package org.hibernate.test.keymanytoone;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.keymanytoone.bidir.embedded.KeyManyToOneTest;
+import org.hibernate.test.keymanytoone.bidir.component.LazyKeyManyToOneTest;
+import org.hibernate.test.keymanytoone.bidir.component.EagerKeyManyToOneTest;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class KeyManyToOneSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "key-many-to-one mappings" );
+		suite.addTest( KeyManyToOneTest.suite() );
+		suite.addTest( LazyKeyManyToOneTest.suite() );
+		suite.addTest( EagerKeyManyToOneTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+package org.hibernate.test.keymanytoone.bidir.component;
+
+import java.util.Collection;
+import java.util.ArrayList;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Customer {
+	private Long id;
+	private String name;
+	private Collection orders = new ArrayList();
+
+	public Customer() {
+	}
+
+	public Customer(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Collection getOrders() {
+		return orders;
+	}
+
+	public void setOrders(Collection orders) {
+		this.orders = orders;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/EagerKeyManyToOneTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/EagerKeyManyToOneTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/EagerKeyManyToOneTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,157 @@
+package org.hibernate.test.keymanytoone.bidir.component;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.HibernateException;
+import org.hibernate.event.def.DefaultLoadEventListener;
+import org.hibernate.event.LoadEvent;
+import org.hibernate.event.LoadEventListener;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.TestCase;
+
+/**
+ * @author Steve Ebersole
+ */
+public class EagerKeyManyToOneTest extends TestCase {
+
+	public EagerKeyManyToOneTest(String name) {
+		super( name );
+	}
+
+	protected String[] getMappings() {
+		return new String[] { "keymanytoone/bidir/component/EagerMapping.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( EagerKeyManyToOneTest.class );
+	}
+
+	protected void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+		LoadEventListener[] baseListeners = cfg.getEventListeners().getLoadEventListeners();
+		int baseLength = baseListeners.length;
+		LoadEventListener[] expandedListeners = new LoadEventListener[ baseLength + 1 ];
+		expandedListeners[ 0 ] = new CustomLoadListener();
+		System.arraycopy( baseListeners, 0, expandedListeners, 1, baseLength );
+		cfg.getEventListeners().setLoadEventListeners( expandedListeners );
+	}
+
+	public void testSaveCascadedToKeyManyToOne() {
+		// test cascading a save to an association with a key-many-to-one which refers to a
+		// just saved entity
+		Session s = openSession();
+		s.beginTransaction();
+		Customer cust = new Customer( "Acme, Inc." );
+		Order order = new Order( new Order.Id( cust, 1 ) );
+		cust.getOrders().add( order );
+		s.save( cust );
+		s.flush();
+		assertEquals( 2, sfi().getStatistics().getEntityInsertCount() );
+		s.delete( cust );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testLoadingStrategies() {
+		Session s = openSession();
+		s.beginTransaction();
+		Customer cust = new Customer( "Acme, Inc." );
+		Order order = new Order( new Order.Id( cust, 1 ) );
+		cust.getOrders().add( order );
+		s.save( cust );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+
+// Here is an example of HHH-2277
+// essentially we have a bidirectional association where one side of the
+// association is actually part of a composite PK
+//
+// See #testLoadEntityWithEagerFetchingToKeyManyToOneReferenceBackToSelfFailureExpected() below...
+//
+// The way these are mapped causes the problem because both sides
+// are defined as eager which leads to the infinite loop; if only
+// one side is marked as eager, then all is ok...
+//		cust = ( Customer ) s.get( Customer.class, cust.getId() );
+//		assertEquals( 1, cust.getOrders().size() );
+//		s.clear();
+
+		cust = ( Customer ) s.createQuery( "from Customer" ).uniqueResult();
+		assertEquals( 1, cust.getOrders().size() );
+		s.clear();
+
+		cust = ( Customer ) s.createQuery( "from Customer c join fetch c.orders" ).uniqueResult();
+		assertEquals( 1, cust.getOrders().size() );
+		s.clear();
+
+		cust = ( Customer ) s.createQuery( "from Customer c join fetch c.orders as o join fetch o.id.customer" ).uniqueResult();
+		assertEquals( 1, cust.getOrders().size() );
+		s.clear();
+
+		cust = ( Customer ) s.createCriteria( Customer.class ).uniqueResult();
+		assertEquals( 1, cust.getOrders().size() );
+		s.clear();
+
+		s.delete( cust );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testLoadEntityWithEagerFetchingToKeyManyToOneReferenceBackToSelfFailureExpected() {
+		// long winded method name to say that this is a test specifically for HHH-2277 ;)
+		// essentially we have a bidirectional association where one side of the
+		// association is actually part of a composite PK.
+		//
+		// The way these are mapped causes the problem because both sides
+		// are defined as eager which leads to the infinite loop; if only
+		// one side is marked as eager, then all is ok.  In other words the
+		// problem arises when both pieces of instance data are coming from
+		// the same result set.  This is because no "entry" can be placed
+		// into the persistence context for the association with the
+		// composite key because we are in the process of trying to build
+		// the composite-id instance
+		Session s = openSession();
+		s.beginTransaction();
+		Customer cust = new Customer( "Acme, Inc." );
+		Order order = new Order( new Order.Id( cust, 1 ) );
+		cust.getOrders().add( order );
+		s.save( cust );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		try {
+			cust = ( Customer ) s.get( Customer.class, cust.getId() );
+		}
+		catch( OverflowCondition overflow ) {
+			fail( "get()/load() caused overflow condition" );
+		}
+		s.delete( cust );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	private static class OverflowCondition extends RuntimeException {
+	}
+
+	private static class CustomLoadListener extends DefaultLoadEventListener {
+		private int internalLoadCount = 0;
+		public void onLoad(LoadEvent event, LoadType loadType) throws HibernateException {
+			if ( LoadEventListener.INTERNAL_LOAD_EAGER.getName().equals( loadType.getName() ) ) {
+				internalLoadCount++;
+				if ( internalLoadCount > 10 ) {
+					throw new OverflowCondition();
+				}
+			}
+			super.onLoad( event, loadType );
+			internalLoadCount--;
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/EagerMapping.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/EagerMapping.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/EagerMapping.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    This mapping demonstrates the use of composite ids with the
+    key-many-to-one feature.  Essentially a composite id where part
+    of the composition is a foreign-key to another entity.
+
+    Here, specifically, we map the key-many-to-one as a lazy
+    association.
+-->
+
+<hibernate-mapping package="org.hibernate.test.keymanytoone.bidir.component">
+
+    <class name="Customer" table="COMP_LAZY_KM2O_CUST">
+        <id name="id" column="ID" type="long">
+            <generator class="increment" />
+        </id>
+        <property name="name" column="NAME" type="string" />
+        <bag name="orders" inverse="true" cascade="all" lazy="false" fetch="join">
+            <key column="CUST_ID" />
+            <one-to-many class="Order" />
+        </bag>
+    </class>
+
+    <class name="Order" table="COMP_LAZY_KM2O_ORDR">
+        <composite-id name="id" class="Order$Id">
+            <key-many-to-one name="customer" class="Customer" column="CUST_ID" lazy="false"/>
+            <key-property name="number" column="ORDR_NUM" type="long" />
+        </composite-id>
+        <set name="items" table="COMP_LAZY_KM2O_ITEM">
+            <key>
+                <column name="CUST_ID"/>
+                <column name="ORDER_NUM"/>
+            </key>
+            <element type="string" column="ITEM_DESC" />
+        </set>
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/LazyKeyManyToOneTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/LazyKeyManyToOneTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/LazyKeyManyToOneTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,77 @@
+package org.hibernate.test.keymanytoone.bidir.component;
+
+import junit.framework.Test;
+
+import org.hibernate.test.TestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.Session;
+
+/**
+ * @author Steve Ebersole
+ */
+public class LazyKeyManyToOneTest extends TestCase {
+	public LazyKeyManyToOneTest(String name) {
+		super( name );
+	}
+
+	protected String[] getMappings() {
+		return new String[] { "keymanytoone/bidir/component/LazyMapping.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( LazyKeyManyToOneTest.class );
+	}
+
+	protected void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+	}
+
+	public void testSaveCascadedToKeyManyToOne() {
+		// test cascading a save to an association with a key-many-to-one which refers to a
+		// just saved entity
+		Session s = openSession();
+		s.beginTransaction();
+		Customer cust = new Customer( "Acme, Inc." );
+		Order order = new Order( new Order.Id( cust, 1 ) );
+		cust.getOrders().add( order );
+		s.save( cust );
+		s.flush();
+		assertEquals( 2, sfi().getStatistics().getEntityInsertCount() );
+		s.delete( cust );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testLoadingStrategies() {
+		Session s = openSession();
+		s.beginTransaction();
+		Customer cust = new Customer( "Acme, Inc." );
+		Order order = new Order( new Order.Id( cust, 1 ) );
+		cust.getOrders().add( order );
+		s.save( cust );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+
+		cust = ( Customer ) s.get( Customer.class, cust.getId() );
+		assertEquals( 1, cust.getOrders().size() );
+		s.clear();
+
+		cust = ( Customer ) s.createQuery( "from Customer" ).uniqueResult();
+		assertEquals( 1, cust.getOrders().size() );
+		s.clear();
+
+		cust = ( Customer ) s.createQuery( "from Customer c join fetch c.orders" ).uniqueResult();
+		assertEquals( 1, cust.getOrders().size() );
+		s.clear();
+
+		s.delete( cust );
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/LazyMapping.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/LazyMapping.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/LazyMapping.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    This mapping demonstrates the use of composite ids with the
+    key-many-to-one feature.  Essentially a composite id where part
+    of the composition is a foreign-key to another entity.
+
+    Here, specifically, we map the key-many-to-one as a lazy
+    association.
+-->
+
+<hibernate-mapping package="org.hibernate.test.keymanytoone.bidir.component">
+
+    <class name="Customer" table="COMP_LAZY_KM2O_CUST">
+        <id name="id" column="ID" type="long">
+            <generator class="increment" />
+        </id>
+        <property name="name" column="NAME" type="string" />
+        <bag name="orders" inverse="true" cascade="all">
+            <key column="CUST_ID" />
+            <one-to-many class="Order" />
+        </bag>
+    </class>
+
+    <class name="Order" table="COMP_LAZY_KM2O_ORDR">
+        <composite-id name="id" class="Order$Id">
+            <key-many-to-one name="customer" class="Customer" column="CUST_ID" lazy="proxy"/>
+            <key-property name="number" column="ORDR_NUM" type="long" />
+        </composite-id>
+        <set name="items" table="COMP_LAZY_KM2O_ITEM">
+            <key>
+                <column name="CUST_ID"/>
+                <column name="ORDER_NUM"/>
+            </key>
+            <element type="string" column="ITEM_DESC" />
+        </set>
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/Order.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/Order.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/component/Order.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,86 @@
+package org.hibernate.test.keymanytoone.bidir.component;
+
+import java.io.Serializable;
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Order {
+	private Id id;
+	private Set items = new HashSet();
+
+	public Order() {
+	}
+
+	public Order(Id id) {
+		this.id = id;
+	}
+
+	public Id getId() {
+		return id;
+	}
+
+	public void setId(Id id) {
+		this.id = id;
+	}
+
+	public Set getItems() {
+		return items;
+	}
+
+	public void setItems(Set items) {
+		this.items = items;
+	}
+
+	public static class Id implements Serializable {
+		private Customer customer;
+		private long number;
+
+		public Id() {
+		}
+
+		public Id(Customer customer, long number) {
+			this.customer = customer;
+			this.number = number;
+		}
+
+		public Customer getCustomer() {
+			return customer;
+		}
+
+		public void setCustomer(Customer customer) {
+			this.customer = customer;
+		}
+
+		public long getNumber() {
+			return number;
+		}
+
+		public void setNumber(long number) {
+			this.number = number;
+		}
+
+		public boolean equals(Object o) {
+			if ( this == o ) {
+				return true;
+			}
+			if ( o == null || getClass() != o.getClass() ) {
+				return false;
+			}
+
+			Id id = ( Id ) o;
+			return number == id.number && customer.equals( id.customer );
+		}
+
+		public int hashCode() {
+			int result;
+			result = customer.hashCode();
+			result = 31 * result + ( int ) ( number ^ ( number >>> 32 ) );
+			return result;
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+package org.hibernate.test.keymanytoone.bidir.embedded;
+
+import java.util.Collection;
+import java.util.ArrayList;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Customer {
+	private Long id;
+	private String name;
+	private Collection orders = new ArrayList();
+
+	public Customer() {
+	}
+
+	public Customer(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Collection getOrders() {
+		return orders;
+	}
+
+	public void setOrders(Collection orders) {
+		this.orders = orders;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/KeyManyToOneTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/KeyManyToOneTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/KeyManyToOneTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,77 @@
+package org.hibernate.test.keymanytoone.bidir.embedded;
+
+import junit.framework.Test;
+
+import org.hibernate.test.TestCase;
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+
+/**
+ * @author Steve Ebersole
+ */
+public class KeyManyToOneTest extends TestCase {
+	public KeyManyToOneTest(String name) {
+		super( name );
+	}
+
+	protected String[] getMappings() {
+		return new String[] { "keymanytoone/bidir/embedded/Mapping.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( KeyManyToOneTest.class );
+	}
+
+	protected void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+	}
+
+	public void testSaveCascadedToKeyManyToOne() {
+		// test cascading a save to an association with a key-many-to-one which refers to a
+		// just saved entity
+		Session s = openSession();
+		s.beginTransaction();
+		Customer cust = new Customer( "Acme, Inc." );
+		Order order = new Order( cust, 1 );
+		cust.getOrders().add( order );
+		s.save( cust );
+		s.flush();
+		assertEquals( 2, sfi().getStatistics().getEntityInsertCount() );
+		s.delete( cust );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testLoadingStrategies() {
+		Session s = openSession();
+		s.beginTransaction();
+		Customer cust = new Customer( "Acme, Inc." );
+		Order order = new Order( cust, 1 );
+		cust.getOrders().add( order );
+		s.save( cust );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+
+		cust = ( Customer ) s.get( Customer.class, cust.getId() );
+		assertEquals( 1, cust.getOrders().size() );
+		s.clear();
+
+		cust = ( Customer ) s.createQuery( "from Customer" ).uniqueResult();
+		assertEquals( 1, cust.getOrders().size() );
+		s.clear();
+
+		cust = ( Customer ) s.createQuery( "from Customer c join fetch c.orders" ).uniqueResult();
+		assertEquals( 1, cust.getOrders().size() );
+		s.clear();
+
+		s.delete( cust );
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/Mapping.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/Mapping.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/Mapping.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    This mapping demonstrates the use of composite ids with the
+    key-many-to-one feature where the composite-id is an embedded form.
+    Essentially a composite id where part of the composition is a
+    foreign-key to another entity.
+-->
+
+<hibernate-mapping package="org.hibernate.test.keymanytoone.bidir.embedded">
+
+    <class name="Customer" table="EMBD_KM2O_CUST">
+        <id name="id" column="ID" type="long">
+            <generator class="increment" />
+        </id>
+        <property name="name" column="NAME" type="string" />
+        <bag name="orders" inverse="true" cascade="all">
+            <key column="CUST_ID" />
+            <one-to-many class="Order" />
+        </bag>
+    </class>
+
+    <class name="Order" table="EMBD_KM2O_ORDR">
+        <composite-id mapped="false">
+            <key-many-to-one name="customer" class="Customer" column="CUST_ID" lazy="false"/>
+            <key-property name="number" column="ORDR_NUM" type="long" />
+        </composite-id>
+        <set name="items" table="EMBD_KM2O_ITEM">
+            <key>
+                <column name="CUST_ID"/>
+                <column name="ORDER_NUM"/>
+            </key>
+            <element type="string" column="ITEM_DESC" />
+        </set>
+    </class>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/Order.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/Order.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/keymanytoone/bidir/embedded/Order.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+package org.hibernate.test.keymanytoone.bidir.embedded;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.io.Serializable;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Order implements Serializable {
+	private Customer customer;
+	private long number;
+	private Set items = new HashSet();
+
+	public Order() {
+	}
+
+	public Order(Customer customer, long number) {
+		this.customer = customer;
+		this.number = number;
+	}
+
+	public Customer getCustomer() {
+		return customer;
+	}
+
+	public void setCustomer(Customer customer) {
+		this.customer = customer;
+	}
+
+	public long getNumber() {
+		return number;
+	}
+
+	public void setNumber(long number) {
+		this.number = number;
+	}
+
+	public Set getItems() {
+		return items;
+	}
+
+	public void setItems(Set items) {
+		this.items = items;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/Document.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/Document.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/Document.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,100 @@
+//$Id: Document.java 7772 2005-08-05 23:03:46Z oneovthafew $
+package org.hibernate.test.lazycache;
+
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class Document {
+	
+	private Long id;
+	private String name;
+	private String upperCaseName;
+	private String summary;
+	private String text;
+	private Date lastTextModification;
+	
+	public Document(String name, String summary, String text) {
+		lastTextModification = new Date();
+		this.name = name;
+		upperCaseName = name.toUpperCase();
+		this.summary = summary;
+		this.text = text;
+	}
+	
+	Document() {}
+	
+	public Date getLastTextModification() {
+		return lastTextModification;
+	}
+
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	/**
+	 * @return Returns the summary.
+	 */
+	public String getSummary() {
+		return summary;
+	}
+	/**
+	 * @param summary The summary to set.
+	 */
+	public void setSummary(String summary) {
+		this.summary = summary;
+	}
+	/**
+	 * @return Returns the text.
+	 */
+	public String getText() {
+		return text;
+	}
+	/**
+	 * @param text The text to set.
+	 */
+	private void setText(String text) {
+		this.text = text;
+	}
+	/**
+	 * @return Returns the upperCaseName.
+	 */
+	public String getUpperCaseName() {
+		return upperCaseName;
+	}
+	/**
+	 * @param upperCaseName The upperCaseName to set.
+	 */
+	public void setUpperCaseName(String upperCaseName) {
+		this.upperCaseName = upperCaseName;
+	}
+	
+	public void updateText(String newText) {
+		if ( !newText.equals(text) ) {
+			this.text = newText;
+			lastTextModification = new Date();
+		}
+	}
+	
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/Document.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/Documents.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/Documents.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/Documents.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates 
+
+     (1) use of lazy properties - this feature requires buildtime 
+         bytecode instrumentation; we don't think this is a very
+         necessary feature, but provide it for completeleness; if
+         Hibernate encounters uninstrumented classes, lazy property
+         fetching will be silently disabled, to enable testing
+     
+     (2) use of a formula to define a "derived property"
+     
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.lazycache"
+	default-access="field">
+ 	
+	<class name="Document" table="documents">
+    	<cache usage="nonstrict-read-write" include="non-lazy" region="foo"/>
+   		<id name="id">
+    		<generator class="native"/>
+    	</id>
+    	<property name="name" not-null="true" length="50"/>
+    	<property name="upperCaseName" formula="upper(name)" lazy="true"/>
+    	<property name="summary" not-null="true" length="200" lazy="true"/>
+    	<property name="text" not-null="true" length="2000" lazy="true"/>
+    	<property name="lastTextModification" not-null="true" lazy="true" access="field"/>
+    </class>
+ 	
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/Documents.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/InstrumentCacheTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/InstrumentCacheTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/InstrumentCacheTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,86 @@
+//$Id: InstrumentCacheTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.lazycache;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class InstrumentCacheTest extends FunctionalTestCase {
+
+	public InstrumentCacheTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "lazycache/Documents.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+	}
+
+	public boolean overrideCacheStrategy() {
+		return false;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( InstrumentCacheTest.class );
+	}
+
+	public static boolean isRunnable() {
+		// TODO : this could be handled via appliesTo()...
+		return FieldInterceptionHelper.isInstrumented( new Document() );
+	}
+
+	public void testInitFromCache() {
+		Session s;
+		Transaction tx;
+
+		s = getSessions().openSession();
+		tx = s.beginTransaction();
+		s.persist( new Document("HiA", "Hibernate book", "Hibernate is....") );
+		tx.commit();
+		s.close();
+
+		s = getSessions().openSession();
+		tx = s.beginTransaction();
+		s.createQuery("from Document fetch all properties").uniqueResult();
+		tx.commit();
+		s.close();
+
+		getSessions().getStatistics().clear();
+
+		s = getSessions().openSession();
+		tx = s.beginTransaction();
+		Document d = (Document) s.createCriteria(Document.class).uniqueResult();
+		assertFalse( Hibernate.isPropertyInitialized(d, "text") );
+		assertFalse( Hibernate.isPropertyInitialized(d, "summary") );
+		assertEquals( "Hibernate is....", d.getText() );
+		assertTrue( Hibernate.isPropertyInitialized(d, "text") );
+		assertTrue( Hibernate.isPropertyInitialized(d, "summary") );
+		tx.commit();
+		s.close();
+
+		assertEquals( 2, getSessions().getStatistics().getPrepareStatementCount() );
+
+		s = getSessions().openSession();
+		tx = s.beginTransaction();
+		d = (Document) s.get(Document.class, d.getId());
+		assertFalse( Hibernate.isPropertyInitialized(d, "text") );
+		assertFalse( Hibernate.isPropertyInitialized(d, "summary") );
+		tx.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/InstrumentCacheTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/InstrumentCacheTest2.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/InstrumentCacheTest2.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/InstrumentCacheTest2.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,81 @@
+//$Id: InstrumentCacheTest2.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.lazycache;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class InstrumentCacheTest2 extends FunctionalTestCase {
+	
+	public InstrumentCacheTest2(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "lazycache/Documents.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( InstrumentCacheTest2.class );
+	}
+
+	public static boolean isRunnable() {
+		return FieldInterceptionHelper.isInstrumented( new Document() );
+	}
+
+	public void testInitFromCache() {
+		Session s;
+		Transaction tx;
+		
+		s = getSessions().openSession();
+		tx = s.beginTransaction();
+		s.persist( new Document("HiA", "Hibernate book", "Hibernate is....") );
+		tx.commit();
+		s.close();
+		
+		s = getSessions().openSession();
+		tx = s.beginTransaction();
+		s.createQuery("from Document fetch all properties").uniqueResult();
+		tx.commit();
+		s.close();
+		
+		getSessions().getStatistics().clear();
+		
+		s = getSessions().openSession();
+		tx = s.beginTransaction();
+		Document d = (Document) s.createCriteria(Document.class).uniqueResult();
+		assertFalse( Hibernate.isPropertyInitialized(d, "text") );
+		assertFalse( Hibernate.isPropertyInitialized(d, "summary") );
+		assertEquals( "Hibernate is....", d.getText() );
+		assertTrue( Hibernate.isPropertyInitialized(d, "text") );
+		assertTrue( Hibernate.isPropertyInitialized(d, "summary") );
+		tx.commit();
+		s.close();
+		
+		assertEquals( 1, getSessions().getStatistics().getPrepareStatementCount() );
+
+		s = getSessions().openSession();
+		tx = s.beginTransaction();
+		d = (Document) s.get(Document.class, d.getId());
+		assertTrue( Hibernate.isPropertyInitialized(d, "text") );
+		assertTrue( Hibernate.isPropertyInitialized(d, "summary") );
+		tx.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazycache/InstrumentCacheTest2.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Employee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Employee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Employee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: Employee.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.lazyonetoone;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * @author Gavin King
+ */
+public class Employee {
+	private String personName;
+	private Person person;
+	private Collection employments = new ArrayList(); 
+	Employee() {}
+	public Employee(Person p) {
+		this.person = p;
+		this.personName = p.getName();
+		p.setEmployee(this);
+	}
+	public Person getPerson() {
+		return person;
+	}
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+	public String getPersonName() {
+		return personName;
+	}
+	public void setPersonName(String personName) {
+		this.personName = personName;
+	}
+	public Collection getEmployments() {
+		return employments;
+	}
+	public void setEmployments(Collection employments) {
+		this.employments = employments;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Employee.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Employment.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Employment.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Employment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+//$Id: Employment.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.lazyonetoone;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class Employment implements Serializable {
+	private String personName;
+	private String organizationName;
+	private Date startDate;
+	private Date endDate;
+	Employment() {}
+	public Employment(Employee e, String org) {
+		this.personName = e.getPersonName();
+		this.organizationName = org;
+		startDate = new Date();
+		e.getEmployments().add(this);
+	}
+	public String getOrganizationName() {
+		return organizationName;
+	}
+	public void setOrganizationName(String organizationName) {
+		this.organizationName = organizationName;
+	}
+	public String getPersonName() {
+		return personName;
+	}
+	public void setPersonName(String personName) {
+		this.personName = personName;
+	}
+	public Date getEndDate() {
+		return endDate;
+	}
+	public void setEndDate(Date endDate) {
+		this.endDate = endDate;
+	}
+	public Date getStartDate() {
+		return startDate;
+	}
+	public void setStartDate(Date startDate) {
+		this.startDate = startDate;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Employment.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/LazyOneToOneTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/LazyOneToOneTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/LazyOneToOneTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,85 @@
+//$Id: LazyOneToOneTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.lazyonetoone;
+
+import java.util.Date;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class LazyOneToOneTest extends FunctionalTestCase {
+	
+	public LazyOneToOneTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "lazyonetoone/Person.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.MAX_FETCH_DEPTH, "2");
+		cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "false");
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( LazyOneToOneTest.class );
+	}
+
+	public static boolean isRunnable() {
+		return FieldInterceptionHelper.isInstrumented( new Person() );
+	}
+
+	public void testLazy() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person p = new Person("Gavin");
+		Person p2 = new Person("Emmanuel");
+		Employee e = new Employee(p);
+		new Employment(e, "JBoss");
+		Employment old = new Employment(e, "IFA");
+		old.setEndDate( new Date() );
+		s.persist(p);
+		s.persist(p2);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		p = (Person) s.createQuery("from Person where name='Gavin'").uniqueResult();
+		//assertFalse( Hibernate.isPropertyInitialized(p, "employee") );
+		assertSame( p.getEmployee().getPerson(), p );
+		assertTrue( Hibernate.isInitialized( p.getEmployee().getEmployments() ) );
+		assertEquals( p.getEmployee().getEmployments().size(), 1 );
+		p2 = (Person) s.createQuery("from Person where name='Emmanuel'").uniqueResult();
+		assertNull( p2.getEmployee() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		p = (Person) s.get(Person.class, "Gavin");
+		//assertFalse( Hibernate.isPropertyInitialized(p, "employee") );
+		assertSame( p.getEmployee().getPerson(), p );
+		assertTrue( Hibernate.isInitialized( p.getEmployee().getEmployments() ) );
+		assertEquals( p.getEmployee().getEmployments().size(), 1 );
+		p2 = (Person) s.get(Person.class, "Emmanuel");
+		assertNull( p2.getEmployee() );
+		s.delete(p2);
+		s.delete(old);
+		s.delete(p);
+		t.commit();
+		s.close();
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/LazyOneToOneTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.lazyonetoone">
+
+	<class name="Person">
+		<id name="name"/>
+		<one-to-one name="employee" lazy="no-proxy" cascade="persist,delete"/>
+	</class>
+	
+	<class name="Employee">
+		<id name="personName"/>
+		<one-to-one name="person" lazy="no-proxy"/>
+		<bag name="employments" 
+				inverse="true"
+				fetch="join" 
+				lazy="false"
+				where="endDate is null" 
+				cascade="persist,delete">
+			<key column="personName"/>
+			<one-to-many class="Employment"/>
+		</bag>
+	</class>
+	
+	<class name="Employment">
+		<composite-id>
+			<key-property name="personName"/>
+			<key-property name="organizationName"/>
+		</composite-id>
+		<property name="startDate" update="false"/>
+		<property name="endDate"/>
+	</class>
+	
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Person.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: Person.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.lazyonetoone;
+
+/**
+ * @author Gavin King
+ */
+public class Person {
+	private String name;
+	private Employee employee;
+	Person() {}
+	public Person(String name) {
+		this.name = name;
+	}
+	public Employee getEmployee() {
+		return employee;
+	}
+	public void setEmployee(Employee employee) {
+		this.employee = employee;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lazyonetoone/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/.cvsignore
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/.cvsignore	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/.cvsignore	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1 @@
+*.bin

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/A.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/A.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/A.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+package org.hibernate.test.legacy;
+
+
+public class A {
+	private Long id;
+	private String name;
+	private E forward;
+	
+	/**
+	 * Returns the id.
+	 * @return Long
+	 */
+	public Long getId() {
+		return id;
+	}
+	
+	/**
+	 * Returns the name.
+	 * @return String
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	
+	/**
+	 * Sets the name.
+	 * @param name The name to set
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+	public E getForward() {
+		return forward;
+	}
+
+	public void setForward(E e) {
+		forward = e;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABC.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABC.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABC.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+	<class name="org.hibernate.test.legacy.A" discriminator-value="0" lazy="true" table="TA">
+		<id name = "id" column="identifier_column" unsaved-value = "null">
+			<generator class="increment"/>
+		</id>
+		<discriminator column="clazz_discriminata" type="integer" not-null="false"/>
+
+		<property name="name" index="indx_a_name">
+			<column name="name" index="indx_a_name2"/>
+		</property>
+
+		<subclass name="org.hibernate.test.legacy.B" discriminator-value="-1" lazy="true">
+			<property name="count" column="count_"/>
+			<join fetch="select" table="B2">
+				<key column="bid"/>
+				<property name="BName" not-null="true"/>
+			</join>
+			<subclass name="org.hibernate.test.legacy.C1" discriminator-value="null" lazy="true">
+				<property name="address" column="c1"/>
+				<one-to-one name="d"/>
+				<join table="cmore" fetch="select">
+					<key column="c1" on-delete="cascade"/>
+					<property name="C1Name"/>
+				</join>
+			</subclass>
+		</subclass>
+	</class>
+
+	<class name="org.hibernate.test.legacy.D" discriminator-value="0" proxy="org.hibernate.test.legacy.D" table="TD">
+		<id name = "id" unsaved-value = "null">
+			<generator class="assigned"/>
+		</id>
+		<property name="amount"/>
+		<many-to-one name="reverse" insert="false" update="false" outer-join="true">
+			<formula>(id)</formula>
+		</many-to-one>
+		<many-to-one name="inverse" access="field" insert="false" update="false" formula = "(id)" outer-join="true"/>
+		<!--many-to-one name="reverse" formula = "(select a.id from TA a where a.id = id)"/-->
+	</class>
+	
+	<sql-query name="propertyResultDiscriminator">
+		<return alias="a" class="org.hibernate.test.legacy.A">
+  			<return-discriminator column="clazz"/>
+			<return-property name="id" column="identifier_column"/>
+			<return-property name="name" column="name"/>
+			<return-property name="count" column="count_"/>
+		</return>
+		select identifier_column, clazz_discriminata as clazz, name, count_ from TA s
+	</sql-query>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCExtends.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCExtends.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCExtends.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+	<subclass name="org.hibernate.test.legacy.C2" discriminator-value="2" extends="org.hibernate.test.legacy.B" lazy="true">
+		<property name="address" column="c2"/>
+		<join table="c2more" fetch="select">
+			<key column="c2"/>
+			<property name="C2Name"/>
+		</join>
+	</subclass>
+
+	
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCProxy.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCProxy.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCProxy.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+	<class name="org.hibernate.test.legacy.A" discriminator-value="0" lazy="true" table="AP">
+		<id name="id" column="identifier_column" unsaved-value = "null">
+			<generator class="increment"/>
+		</id>
+		<discriminator column="clazz_discriminata" type="integer" force="true" not-null="false"/>
+		<property name="name"/>
+		<many-to-one name="forward" class="org.hibernate.test.legacy.E" cascade="save-update" />
+		<subclass name="org.hibernate.test.legacy.B" discriminator-value="null" lazy="true">
+			<property name="count" column="count_"/>
+
+			<map name="map">
+				<key column="BID"/>
+				<index column="MAPKEY" type="string"/>
+				<element column="MAPVAL" type="int"/>
+			</map>
+
+			<subclass name="org.hibernate.test.legacy.C1" discriminator-value="1" lazy="true">
+				<property name="address" column="c1"/>
+				<one-to-one name="d"/>
+				<many-to-one name="c2" column="c" class="org.hibernate.test.legacy.C2"/>
+				<bag name="c2s" inverse="true" where="identifier_column is not null"> <!--where="clazz_discriminata=2"-->
+					<key column="c"/>
+					<one-to-many class="org.hibernate.test.legacy.C2"/>
+				</bag>
+			</subclass>
+			<subclass name="org.hibernate.test.legacy.C2" discriminator-value="2" lazy="true">
+				<property name="address" column="c2"/>
+				<many-to-one name="c1" column="c" class="org.hibernate.test.legacy.C1"/>
+				<bag name="c1s" inverse="true" > <!--where="clazz_discriminata=1"-->
+					<key column="c"/>
+					<one-to-many class="org.hibernate.test.legacy.C1"/>
+				</bag>
+			</subclass>
+		</subclass>
+	</class>
+
+	<class name="org.hibernate.test.legacy.D" discriminator-value="0" lazy="true" table="DP">
+		<id name = "id" unsaved-value = "null">
+			<generator class="assigned"/>
+		</id>
+		<property name="amount"/>
+	</class>
+	
+	<class name="org.hibernate.test.legacy.E" discriminator-value="0" lazy="true" table="EP">
+		<id name = "id" unsaved-value = "null">
+			<generator class="increment"/>
+		</id>
+		<property name="amount"/>
+		<one-to-one name="reverse" class="org.hibernate.test.legacy.A" property-ref="forward" cascade="save-update"/>
+		<set name="as" lazy="true">
+			<key column="e"/>
+			<one-to-many class="org.hibernate.test.legacy.A"/>
+		</set>
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCProxyTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCProxyTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCProxyTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,304 @@
+//$Id: ABCProxyTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+import junit.textui.TestRunner;
+
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+
+public class ABCProxyTest extends LegacyTestCase {
+
+	public ABCProxyTest(String arg0) {
+		super(arg0);
+	}
+	
+	public void testDiscriminatorFiltering() throws Exception {
+		if ( ( getDialect() instanceof HSQLDialect ) ) return;
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createQuery("from C1 c1 left join c1.c2s c2").list();
+		s.createCriteria(C1.class).createCriteria("c2s").list();
+		t.commit();
+		s.close();
+	}
+
+	public void testNarrow() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createQuery("from E e join e.reverse as b where b.count=1").list();
+		s.createQuery("from E e join e.as as b where b.count=1").list();
+		t.commit();
+		s.close();
+	}
+
+	public void testSharedColumn() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		C1 c1 = new C1();
+		C2 c2 = new C2();
+		c1.setC2(c2);
+		c2.setC1(c1);
+		s.save(c1); s.save(c2);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		List list = s.find("from B");
+		assertTrue( list.size()==2 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c1 = (C1) s.createQuery("from C1").uniqueResult();
+		c2 = (C2) s.createQuery("from C2").uniqueResult();
+		assertTrue( c1.getC2()==c2 );
+		assertTrue( c2.getC1()==c1 );
+		assertTrue( c1.getC2s().contains(c2) );
+		assertTrue( c2.getC1s().contains(c1) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c1 = (C1) s.get( A.class, c1.getId() );
+		c2 = (C2) s.get( A.class, c2.getId() );
+		assertTrue( c1.getC2()==c2 );
+		assertTrue( c2.getC1()==c1 );
+		assertTrue( c1.getC2s().contains(c2) );
+		assertTrue( c2.getC1s().contains(c1) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete(c1); s.delete(c2);
+		t.commit();
+		s.close();
+
+	}
+
+	public void testSubclassing() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		C1 c1 = new C1();
+		D d = new D();
+		d.setAmount(213.34f);
+		c1.setAddress("foo bar");
+		c1.setCount(23432);
+		c1.setName("c1");
+		c1.setD(d);
+		s.save(c1);
+		d.setId( c1.getId() );
+		s.save(d);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		A c1a = (A) s.load( A.class, c1.getId() );
+		assertFalse( Hibernate.isInitialized(c1a) );
+		assertTrue( c1a.getName().equals("c1") );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		B c1b = (B) s.load( B.class, c1.getId() );
+		assertTrue(
+			(c1b.getCount()==23432) &&
+			c1b.getName().equals("c1")
+		);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c1 = (C1) s.load( C1.class, c1.getId() );
+		assertTrue(
+			c1.getAddress().equals("foo bar") &&
+			(c1.getCount()==23432) &&
+			c1.getName().equals("c1") &&
+			c1.getD().getAmount()>213.3f
+		);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c1a = (A) s.load( A.class, c1.getId() );
+		assertTrue( c1a.getName().equals("c1") );
+		c1 = (C1) s.load( C1.class, c1.getId() );
+		assertTrue(
+			c1.getAddress().equals("foo bar") &&
+			(c1.getCount()==23432) &&
+			c1.getName().equals("c1") &&
+			c1.getD().getAmount()>213.3f
+		);
+		c1b = (B) s.load( B.class, c1.getId() );
+		assertTrue(
+			(c1b.getCount()==23432) &&
+			c1b.getName().equals("c1")
+		);
+		assertTrue( c1a.getName().equals("c1") );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c1a = (A) s.load( A.class, c1.getId() );
+		assertTrue( c1a.getName().equals("c1") );
+		c1 = (C1) s.load( C1.class, c1.getId(), LockMode.UPGRADE );
+		assertTrue(
+			c1.getAddress().equals("foo bar") &&
+			(c1.getCount()==23432) &&
+			c1.getName().equals("c1") &&
+			c1.getD().getAmount()>213.3f
+		);
+		c1b = (B) s.load( B.class, c1.getId(), LockMode.UPGRADE );
+		assertTrue(
+			(c1b.getCount()==23432) &&
+			c1b.getName().equals("c1")
+		);
+		assertTrue( c1a.getName().equals("c1") );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c1a = (A) s.load( A.class, c1.getId() );
+		c1 = (C1) s.load( C1.class, c1.getId() );
+		c1b = (B) s.load( B.class, c1.getId() );
+		assertTrue( c1a.getName().equals("c1") );
+		assertTrue(
+			c1.getAddress().equals("foo bar") &&
+			(c1.getCount()==23432) &&
+			c1.getName().equals("c1") &&
+			c1.getD().getAmount()>213.3f
+		);
+		assertTrue(
+			(c1b.getCount()==23432) &&
+			c1b.getName().equals("c1")
+		);
+		System.out.println( s.delete("from A") );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.save( new B() );
+		s.save( new A() );
+		assertTrue( s.find("from B").size()==1 );
+		assertTrue( s.find("from A").size()==2 );
+		s.delete("from A");
+		t.commit();
+		s.close();
+	}
+
+	public void testSubclassMap() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		B b = new B();
+		s.save(b);
+		Map map = new HashMap();
+		map.put("3", new Integer(1) );
+		b.setMap(map);
+		s.flush();
+		s.delete(b);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		map = new HashMap();
+		map.put("3", new Integer(1) );
+		b = new B();
+		b.setMap(map);
+		s.save(b);
+		s.flush();
+		s.delete(b);
+		t.commit();
+		s.close();
+	}
+
+	public void testOneToOne() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		A a = new A();
+		E d1 = new E();
+		C1 c = new C1();
+		E d2 = new E();
+		a.setForward(d1);
+		d1.setReverse(a);
+		c.setForward(d2);
+		d2.setReverse(c);
+		Serializable aid = s.save(a);
+		Serializable d2id = s.save(d2);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		List l = s.find( "from E e, A a where e.reverse = a.forward and a = ?", a, Hibernate.entity(A.class) );
+		assertTrue( l.size()==1 );
+		l = s.find( "from E e join fetch e.reverse" );
+		assertTrue( l.size()==2 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		l = s.find( "from E e" );
+		assertTrue( l.size()==2 );
+		E e = (E) l.get(0);
+		assertTrue( e==e.getReverse().getForward() );
+		e = (E) l.get(1);
+		assertTrue( e==e.getReverse().getForward() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		a = (A) s.load(A.class, aid);
+		d2 = (E) s.load(E.class, d2id);
+		assertTrue( a==a.getForward().getReverse() );
+		assertTrue( d2==d2.getReverse().getForward() );
+		s.delete(a);
+		s.delete( a.getForward() );
+		s.delete(d2);
+		s.delete( d2.getReverse() );
+		t.commit();
+
+		s = openSession();
+		t = s.beginTransaction();
+		l = s.find( "from E e" );
+		assertTrue( l.size()==0 );
+		t.commit();
+		s.close();
+	}
+
+	public String[] getMappings() {
+		return new String[] {  "legacy/ABCProxy.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ABCProxyTest.class );
+	}
+
+	public static void main(String[] args) throws Exception {
+		TestRunner.run( suite() );
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ABCTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,165 @@
+//$Id: ABCTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+import org.hibernate.classic.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+
+public class ABCTest extends LegacyTestCase {
+
+	public ABCTest(String arg0) {
+		super(arg0);
+	}
+	
+	public void testFormulaAssociation() throws Throwable {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		D d = new D();
+		Long did = new Long(12);
+		s.save(d, did);
+		A a = new A();
+		a.setName("a");
+		s.save(a, did);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		d = (D) s.get(D.class, did);
+		assertTrue(d.getReverse().getId().equals(did));
+		s.clear();
+		getSessions().evict(D.class);
+		getSessions().evict(A.class);
+		d = (D) s.get(D.class, did);
+		assertTrue(d.inverse.getId().equals(did));
+		assertTrue(d.inverse.getName().equals("a"));
+		s.clear();
+		getSessions().evict(D.class);
+		getSessions().evict(A.class);
+		assertTrue( s.find("from D d join d.reverse r join d.inverse i where i = r").size()==1 );
+		t.commit();
+		s.close();
+	}
+
+	public void testHigherLevelIndexDefinition() throws Throwable {
+		String[] commands = getCfg().generateSchemaCreationScript( getDialect() );
+		int max = commands.length;
+		boolean found = false;
+		for (int indx = 0; indx < max; indx++) {
+			System.out.println("Checking command : " + commands[indx]);
+			found = commands[indx].indexOf("create index indx_a_name") >= 0;
+			if (found)
+				break;
+		}
+		assertTrue("Unable to locate indx_a_name index creation", found);
+	}
+
+	public void testSubclassing() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		C1 c1 = new C1();
+		D d = new D();
+		d.setAmount(213.34f);
+		c1.setAddress("foo bar");
+		c1.setCount(23432);
+		c1.setName("c1");
+		c1.setBName("a funny name");
+		c1.setD(d);
+		s.save(c1);
+		d.setId( c1.getId() );
+		s.save(d);
+
+		assertTrue( s.find("from C2 c where 1=1 or 1=1").size()==0 );
+
+		t.commit();
+		s.close();
+
+		getSessions().evict(A.class);
+		
+		s = openSession();
+		t = s.beginTransaction();
+		c1 = (C1) s.get( A.class, c1.getId() );
+		assertTrue(
+			c1.getAddress().equals("foo bar") &&
+			(c1.getCount()==23432) &&
+			c1.getName().equals("c1") &&
+			c1.getD().getAmount()>213.3f
+		);
+		assertEquals( "a funny name", c1.getBName() );
+		t.commit();
+		s.close();
+		
+		getSessions().evict(A.class);
+
+		s = openSession();
+		t = s.beginTransaction();
+		c1 = (C1) s.get( B.class, c1.getId() );
+		assertTrue(
+			c1.getAddress().equals("foo bar") &&
+			(c1.getCount()==23432) &&
+			c1.getName().equals("c1") &&
+			c1.getD().getAmount()>213.3f
+		);
+		assertEquals( "a funny name", c1.getBName() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c1 = (C1) s.load( C1.class, c1.getId() );
+		assertTrue(
+			c1.getAddress().equals("foo bar") &&
+			(c1.getCount()==23432) &&
+			c1.getName().equals("c1") &&
+			c1.getD().getAmount()>213.3f
+		);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		List bs = s.createQuery("from B").list();
+		for (int i=0; i<bs.size(); i++) {
+			C1 b = (C1) bs.get(i);
+			s.delete(b);
+			s.delete( b.getD() );
+		}
+		t.commit();
+		s.close();
+	}
+	
+	public void testGetSave() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		assertNull( s.get( D.class, new Long(1) ) );
+		D d = new D();
+		d.setId( new Long(1) );
+		s.save(d);
+		s.flush();
+		assertNotNull( s.get( D.class, new Long(1) ) );
+		s.delete(d);
+		s.flush();
+		t.commit();
+		s.close();
+	}
+
+	public String[] getMappings() {
+		return new String[] { "legacy/ABC.hbm.xml", "legacy/ABCExtends.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ABCTest.class );
+	}
+
+	public static void main(String[] args) throws Exception {
+		TestRunner.run( suite() );
+	}
+
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Abstract.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Abstract.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Abstract.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+//$Id: Abstract.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.Set;
+
+public abstract class Abstract extends Foo implements AbstractProxy {
+	
+	private java.sql.Time time;
+	private Set abstracts;
+	
+	public java.sql.Time getTime() {
+		return time;
+	}
+	
+	public void setTime(java.sql.Time time) {
+		this.time = time;
+	}
+	
+	public Set getAbstracts() {
+		return abstracts;
+	}
+	
+	public void setAbstracts(Set abstracts) {
+		this.abstracts = abstracts;
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/AbstractProxy.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/AbstractProxy.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/AbstractProxy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+package org.hibernate.test.legacy;
+
+public interface AbstractProxy extends FooProxy {
+	public void setAbstracts(java.util.Set arg0);
+	public java.util.Set getAbstracts();
+	public void setTime(java.sql.Time arg0);
+	public java.sql.Time getTime();
+}
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/AltSimple.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/AltSimple.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/AltSimple.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+    <class name="org.hibernate.test.legacy.Simple" table="SIMP">
+        <id type="long" column="id_">
+            <generator class="assigned"/>
+        </id>
+        <property name="name"/>
+        <property name="address"/>
+        <property name="count" column="count_" not-null="true" unique="true"/> 
+        <property name="date" column="date_"/>
+        <property name="pay"/>
+        <many-to-one name="other"/>
+    </class>
+    
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Assignable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Assignable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Assignable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+package org.hibernate.test.legacy;
+
+import java.util.Collection;
+
+/**
+ * @author Administrator
+ */
+public class Assignable {
+	private String id;
+	private Collection categories;
+
+	public Collection getCategories() {
+		return categories;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setCategories(Collection collection) {
+		categories = collection;
+	}
+
+	public void setId(String string) {
+		id = string;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/B.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/B.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/B.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+package org.hibernate.test.legacy;
+
+import java.util.Map;
+
+
+public class B extends A {
+	private int count;
+	private Map map;
+	private String bName = "B Name";
+	
+	public int getCount() {
+		return count;
+	}
+	
+	public void setCount(int count) {
+		this.count = count;
+	}
+	
+	public Map getMap() {
+		return map;
+	}
+
+	public void setMap(Map map) {
+		this.map = map;
+	}
+
+	public String getBName() {
+		return bName;
+	}
+
+	public void setBName(String name) {
+		bName = name;
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Bar.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Bar.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Bar.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+//$Id: Bar.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+public class Bar extends Abstract implements BarProxy, Named {
+	private String barString;
+	private FooComponent barComponent = new FooComponent("bar", 69, null, null);
+	private Baz baz;
+	private int x;
+	private Object object;
+	
+	public int getX() {
+		return x;
+	}
+	public void setX(int x) {
+		this.x = x;
+	}
+
+	public String getBarString() {
+		return barString;
+	}
+	
+	void setBarString(String barString) {
+		this.barString = barString;
+	}
+	
+	public FooComponent getBarComponent() {
+		return barComponent;
+	}
+	
+	public void setBarComponent(FooComponent barComponent) {
+		this.barComponent = barComponent;
+	}
+	
+	public Baz getBaz() {
+		return baz;
+	}
+	
+	public void setBaz(Baz baz) {
+		this.baz = baz;
+	}
+	
+	private String name = "bar";
+	
+	public String getName() {
+		return name;
+	}
+	
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Object getObject() {
+		return object;
+	}
+
+	public void setObject(Object object) {
+		this.object = object;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/BarProxy.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/BarProxy.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/BarProxy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+//$Id: BarProxy.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+public interface BarProxy extends AbstractProxy {
+	public void setBaz(Baz arg0);
+	public Baz getBaz();
+	public void setBarComponent(FooComponent arg0);
+	public FooComponent getBarComponent();
+	//public void setBarString(String arg0);
+	public String getBarString();
+	public Object getObject();
+	public void setObject(Object o);
+}
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/BasicNameable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/BasicNameable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/BasicNameable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+//$Id: BasicNameable.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+/**
+ * @author administrator
+ *
+ *
+ */
+public class BasicNameable implements Nameable {
+	
+	private String name;
+	private Long id;
+	
+	/**
+	 * @see Nameable#getName()
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * @see Nameable#setName()
+	 */
+	public void setName(String n) {
+		name = n;
+	}
+	
+	/**
+	 * @see Nameable#getKey()
+	 */
+	public Long getKey() {
+		return id;
+	}
+	
+	/**
+	 * @see Nameable#setKey()
+	 */
+	public void setKey(Long k) {
+		id = k;
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Baz.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Baz.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Baz.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,292 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+	<class name="org.hibernate.test.legacy.Baz" 
+		table="baz" 
+		check="count_count > -666">
+		<id name="code" type="string">
+			<column name="baz_id_column_" length="32"/>
+			<generator class="uuid.hex"/>
+		</id>
+		<property name="count" column="count_count"/>
+		<property name="name" column="name_b"/>
+		<!--property name="text" type="text" column="text_"/-->
+		<many-to-one name="foo" outer-join="true" class="org.hibernate.test.legacy.Foo"/>
+
+		<list name="stringList" table="string_list" batch-size="12">
+			<key>
+				<column name="id" length="16"/>
+			</key>
+			<index column="`i`"/>
+			<element column="element" type="string"/>
+		</list>
+		<primitive-array name="intArray" table="int_array">
+			<key>
+				<column name="id" length="16"/>
+			</key>
+			<index column="i"/>
+			<element column="j" type="int"/>
+		</primitive-array>
+		<set name="fooSet" lazy="true" order-by="string_" batch-size="12">
+			<key>
+				<column name="baz_id" length="16"/>
+			</key>
+			<one-to-many class="org.hibernate.test.legacy.Foo"/>
+		</set>
+		<array name="components" table="bazcomponents">
+			<key>
+				<column name="baz_id" length="16"/>
+			</key>
+			<index column="i"/>
+			<composite-element class="org.hibernate.test.legacy.FooComponent">
+				<parent name="baz"/>
+				<property name="name">
+					<column name="name" length="56"/>
+				</property>
+				<property name="count" column="count_"/>
+				<nested-composite-element name="subcomponent" class="org.hibernate.test.legacy.FooComponent">
+					<property name="name" column="x_"/>
+					<property name="count" column="y_"/>
+				</nested-composite-element>
+			</composite-element>
+		</array>
+		<array name="timeArray">
+			<key>
+				<column name="baz_id" length="16"/>
+			</key>
+			<index column="j"/>
+			<element column="the_time" type="time"/>
+		</array>
+		<bag name="bag" order-by="`name_`" table="`bxaxg`">
+			<key>
+				<column name="`baz_id_`" length="16"/>
+			</key>
+			<element column="`name_`" type="string"/>
+		</bag>
+		<map name="fooToGlarch" lazy="false">
+			<key>
+				<column name="baz_id" length="16"/>
+			</key>
+			<index-many-to-many column="foo_id" class="org.hibernate.test.legacy.Foo"/>
+			<many-to-many column="glarch_id" class="org.hibernate.test.legacy.Glarch"/>
+		</map>
+		<map name="fooComponentToFoo">
+			<!--cache-->
+			<key>
+				<column name="baz_id" length="16"/>
+			</key>
+			<composite-index class="org.hibernate.test.legacy.FooComponent">
+				<key-property name="name" length="32"/>
+				<key-property name="count" column="count_"/>
+			</composite-index>
+			<many-to-many column="foo_id" class="org.hibernate.test.legacy.Foo" outer-join="true"/>
+		</map>
+		<map name="glarchToFoo">
+			<key>
+				<column name="gtf_baz_id" length="16"/>
+			</key>
+			<index-many-to-many column="gtf_foo_id" class="org.hibernate.test.legacy.Foo"/>
+			<one-to-many class="org.hibernate.test.legacy.Glarch"/>
+		</map>
+		
+		<set name="stringSet" lazy="true" sort="org.hibernate.test.legacy.StringComparator" batch-size="12">
+			<!--<cache usage="read-write"/>-->
+			<key column="id_"/>
+			<element column="element" type="string" not-null="true" length="32"/>
+		</set>
+	
+		<map name="stringDateMap" lazy="true" sort="org.hibernate.test.legacy.ReverseComparator">
+			<key column="id_"/>
+			<index column="map_key" type="string" length="32"/>
+			<element column="map_value" type="date"/>
+		</map>
+	
+		<array name="fooArray" element-class="org.hibernate.test.legacy.FooProxy" where="i&lt;8" check="i>=0">
+			<!--cache-->
+			<key column="id_"/>
+			<index column="i"/>
+			<many-to-many class="org.hibernate.test.legacy.Foo" fetch="select">
+				<column name="foo" length="36"/>
+			</many-to-many>
+		</array>
+	
+		<bag name="fooBag" lazy="true" table="baz_foo" cascade="all-delete-orphan" inverse="false">
+			<key column="baz"/>
+			<many-to-many class="org.hibernate.test.legacy.Foo" column="foo" outer-join="true"/>
+		</bag>
+	
+		<idbag name="idFooBag" lazy="true" table="baz_id_foo" cascade="all">
+			<collection-id column="pkid" type="long"> 
+				<generator class="hilo"/>
+			</collection-id>
+			<key column="baz"/>
+			<many-to-many class="org.hibernate.test.legacy.Foo" column="foo" outer-join="true"/>
+		</idbag>
+	
+		<idbag name="byteBag" lazy="true" table="baz_byte_bag">
+			<collection-id column="pkid" type="long"> 
+				<generator class="hilo"/>
+			</collection-id>
+			<key column="baz"/>
+			<element type="binary" column="bytez" not-null="true"/>
+		</idbag>
+	
+		<array name="stringArray">
+			<key column="id_"/>
+			<index column="i"/>
+			<element column="name" type="string"/>
+		</array>
+		
+		<list name="fees" lazy="true" cascade="all" check="bazind is null or (bazind>=0 and bazind&lt;10)">
+			<key column="bazid"/>
+			<index column="bazind"/>
+			<one-to-many class="org.hibernate.test.legacy.Fee"/>
+		</list>
+		
+		<list name="customs">
+			<key column="id_"/>
+			<index column="indx"/>
+			<element type="org.hibernate.test.legacy.DoubleStringType">
+				<column name="first_"/>
+				<column name="second_"/>
+			</element>
+		</list>
+	
+		<list name="topComponents" table="topcomponents">
+			<!--cache-->
+			<key column="id_"/>
+			<index column="i"/>
+			<composite-element class="org.hibernate.test.legacy.FooComponent">
+				<property name="name"/>
+				<property name="count" column="count_"/>
+			</composite-element>
+		</list>
+		
+		<set name="topFoos">
+			<key column="idtopbar" />
+			<one-to-many class = "org.hibernate.test.legacy.Bar"/>
+		</set>
+	
+		<set name="cascadingBars" cascade="all-delete-orphan">
+			<key column="idofbaz" />
+			<one-to-many class = "org.hibernate.test.legacy.Bar"/>
+		</set>
+	
+		<map name="topGlarchez" outer-join="true">
+			<key column="idtopglarch" />
+			<index type="character">
+				<column name="mapkey" sql-type="char(1)"/>
+			</index>
+			<one-to-many class = "org.hibernate.test.legacy.Glarch"/>
+		</map>
+		
+		<set name="cached" sort="natural" table="cached_set">
+			<!--cache-->
+			<key column="baz"/>
+			<composite-element class="org.hibernate.test.legacy.CompositeElement">
+				<property name="foo" not-null="true"/>
+				<property name="bar" not-null="true"/>
+			</composite-element>
+		</set>
+	
+		<map name="cachedMap" sort="natural" table="cached_map">
+			<!--cache-->
+			<key column="baz"/>
+			<index-many-to-many column="another_baz" class="org.hibernate.test.legacy.Baz"/>
+			<composite-element class="org.hibernate.test.legacy.CompositeElement">
+				<property name="foo"/>
+				<property name="bar"/>
+			</composite-element>
+		</map>
+		
+		<map name="stringGlarchMap" where="baz_map_index &gt; 'a' and tha_key is not null" cascade="all">
+			<key column="baz_map_id"/>
+			<index column="baz_map_index" type="string"/>
+			<one-to-many class="org.hibernate.test.legacy.Glarch"/>
+		</map>
+		
+		<map name="anyToAny" lazy="true">
+			<key column="baz"/>
+			<index-many-to-any id-type="long">
+				<column name="ind_clazz_"/>
+				<column name="ind_id_"/>
+			</index-many-to-any>
+			<many-to-any id-type="long">
+				<column name="el_clazz_"/>
+				<column name="el_id_"/>
+			</many-to-any>
+		</map>
+		
+		<list name="manyToAny" lazy="true">
+			<key column="baz"/>
+			<index column="ind"/>
+			<many-to-any id-type="string">
+				<column name="el_clazz_"/>
+				<column name="el_id_"/>
+			</many-to-any>
+		</list>
+		
+		<bag name="bazez" lazy="true" order-by="name_b desc" cascade="all">
+			<key column="`baz-id`"/>
+			<one-to-many class="org.hibernate.test.legacy.Baz"/>
+		</bag>
+		
+		<set name="sortablez" sort="natural" cascade="all">
+			<key column="baz"/>
+			<one-to-many class="org.hibernate.test.legacy.Sortable"/>
+		</set>
+		
+		<bag name="parts" lazy="true" cascade="save-update">
+			<key column="baz"/>
+			<one-to-many class="org.hibernate.test.legacy.Part"/>
+		</bag>
+		
+		<bag name="moreParts" lazy="true" cascade="save-update">
+			<key column="baz"/>
+			<many-to-many column="part" class="org.hibernate.test.legacy.Part"/>
+		</bag>
+		
+		<bag name="subs" inverse="true" cascade="all" access="field">
+			<key column="superBaz" on-delete="cascade"/>
+			<one-to-many class="org.hibernate.test.legacy.Baz"/>
+		</bag>
+		
+		<many-to-one name="superBaz" access="field"/>
+		
+		<component name="collectionComponent">
+			<component name="nested">
+				<property name="str"/>
+				<bag name="foos" cascade="all">
+					<key column="baz_compon_id"/>
+					<one-to-many class="org.hibernate.test.legacy.Foo"/>
+				</bag>
+				<bag name="floats" table="baz_floats_bag">
+					<key column="baz_compon_id"/>
+					<element type="float" column="float_value"/>
+				</bag>
+			</component>
+		</component>
+		
+	</class>
+	
+	<class name="org.hibernate.test.legacy.Sortable">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="name"/>
+	</class>
+	
+	<class name="org.hibernate.test.legacy.Part" where="description like 'x%'">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<discriminator column="clazz"/>
+		<property name="description"/>
+		<subclass name="org.hibernate.test.legacy.Part$SpecialPart"/>
+	</class>
+	
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Baz.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Baz.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Baz.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,451 @@
+//$Id: Baz.java 4688 2004-10-26 09:10:50Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+public class Baz implements Named, Serializable, Comparable {
+	private SortedSet stringSet;
+	private Map stringDateMap;
+	private List stringList;
+	private int[] intArray;
+	private FooProxy[] fooArray;
+	private String[] stringArray;
+	private String code;
+	private List customs;
+	private List topComponents;
+	private Set fooSet;
+	private FooComponent[] components;
+	private Date[] timeArray;
+	private int count;
+	private String name;
+	private Collection bag;
+	private Set topFoos;
+	private Map topGlarchez;
+	private Set cascadingBars;
+	private Map fooToGlarch;
+	private Map fooComponentToFoo;
+	private Map glarchToFoo;
+	private List fees;
+	private Collection fooBag;
+	private Set cached;
+	private Map cachedMap;
+	private Map stringGlarchMap;
+	private Map anyToAny;
+	private List manyToAny;
+	private Collection idFooBag;
+	private Collection byteBag;
+	private FooProxy foo;
+	private List bazez;
+	private SortedSet sortablez;
+	private NestingComponent collectionComponent;
+	private String text;
+	private List parts;
+	private List moreParts;
+	public List subs;
+	public Baz superBaz;
+	
+	Baz() {}
+	
+	public SortedSet getStringSet() {
+		return stringSet;
+	}
+	public void setStringSet(SortedSet stringSet) {
+		this.stringSet = stringSet;
+	}
+	public Map getStringDateMap() {
+		return stringDateMap;
+	}
+	public void setStringDateMap(Map stringDateMap) {
+		this.stringDateMap = stringDateMap;
+	}
+	public List getStringList() {
+		return stringList;
+	}
+	public void setStringList(List stringList) {
+		this.stringList = stringList;
+	}
+	public int[] getIntArray() {
+		return intArray;
+	}
+	public void setIntArray(int[] intArray) {
+		this.intArray = intArray;
+	}
+	public FooProxy[] getFooArray() {
+		return fooArray;
+	}
+	public void setFooArray(FooProxy[] fooArray) {
+		this.fooArray = fooArray;
+	}
+	public String[] getStringArray() {
+		return stringArray;
+	}
+	public void setStringArray(String[] stringArray) {
+		this.stringArray = stringArray;
+	}
+	
+	public String getCode() {
+		return code;
+	}
+	public void setCode(String code) {
+		this.code = code;
+	}
+	
+	public void setDefaults() {
+		SortedSet set = new TreeSet();
+		set.add("foo"); set.add("bar"); set.add("baz");
+		setStringSet(set);
+		Map map = new TreeMap();
+		map.put( "now", new Date() );
+		map.put( "never", null );
+		map.put( "big bang", new Date(0) );
+		setStringDateMap(map);
+		List list = new ArrayList();
+		list.addAll(set);
+		setStringList(list);
+		setIntArray( new int[] { 1,3,3,7 } );
+		setFooArray( new Foo[0] );
+		setStringArray( (String[]) list.toArray( new String[0] ) );
+		customs = new ArrayList();
+		customs.add( new String[] { "foo", "bar" } );
+		customs.add( new String[] { "A", "B" } );
+		customs.add( new String[] { "1", "2" } );
+		
+		fooSet = new HashSet();
+		components = new FooComponent[] {
+			new FooComponent("foo", 42, null, null),
+			new FooComponent("bar", 88, null, new FooComponent("sub", 69, null, null) )
+		};
+		timeArray = new Date[] { new Date(), new Date(), null, new Date(0) };
+		TreeSet x = new TreeSet();
+		x.add("w"); x.add("x"); x.add("y"); x.add("z");
+		TreeSet a = new TreeSet();
+		a.add("a"); a.add("b"); a.add("d"); a.add("c");
+		
+		count = 667;
+		name="Bazza";
+		topComponents = new ArrayList();
+		topComponents.add( new FooComponent("foo", 11, new Date[] { new Date(), new Date(123) }, null) );
+		topComponents.add( new FooComponent("bar", 22, new Date[] { new Date(7), new Date(456) }, null) );
+		topComponents.add( null );
+		bag = new ArrayList();
+		bag.add("duplicate");
+		bag.add("duplicate");
+		bag.add("duplicate");
+		bag.add("unique");
+		cached = new TreeSet();
+		CompositeElement ce = new CompositeElement();
+		ce.setFoo("foo");
+		ce.setBar("bar");
+		CompositeElement ce2 = new CompositeElement();
+		ce2.setFoo("fooxxx");
+		ce2.setBar("barxxx");
+		cached.add(ce);
+		cached.add(ce2);
+		cachedMap = new TreeMap();
+		cachedMap.put(this, ce);
+		
+		text="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+		for (int i=0; i<10; i++) text+=text;
+		
+	}
+	
+	public List getCustoms() {
+		return customs;
+	}
+	public void setCustoms(List customs) {
+		this.customs = customs;
+	}
+	
+	public Set getFooSet() {
+		return fooSet;
+	}
+	public void setFooSet(Set fooSet) {
+		this.fooSet = fooSet;
+	}
+	
+	public FooComponent[] getComponents() {
+		return components;
+	}
+	public void setComponents(FooComponent[] components) {
+		this.components = components;
+	}
+	
+	public Date[] getTimeArray() {
+		return timeArray;
+	}
+	
+	public void setTimeArray(Date[] timeArray) {
+		this.timeArray = timeArray;
+	}
+	
+	public int getCount() {
+		return count;
+	}
+	
+	public void setCount(int count) {
+		this.count = count;
+	}
+	
+	public String getName() {
+		return name;
+	}
+	
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+	public List getTopComponents() {
+		return topComponents;
+	}
+	
+	public void setTopComponents(List topComponents) {
+		this.topComponents = topComponents;
+	}
+	
+	public Collection getBag() {
+		return bag;
+	}
+	
+	public void setBag(Collection bag) {
+		this.bag = bag;
+	}
+	
+	public Set getTopFoos() {
+		return topFoos;
+	}
+	
+	public void setTopFoos(Set topFoos) {
+		this.topFoos = topFoos;
+	}
+	
+	
+	public Map getTopGlarchez() {
+		return topGlarchez;
+	}
+	
+	public void setTopGlarchez(Map topGlarchez) {
+		this.topGlarchez = topGlarchez;
+	}
+	
+	public Set getCascadingBars() {
+		return cascadingBars;
+	}
+	
+	public void setCascadingBars(Set cascadingBars) {
+		this.cascadingBars = cascadingBars;
+	}
+	
+	public Map getFooToGlarch() {
+		return fooToGlarch;
+	}
+	
+	public void setFooToGlarch(Map fooToGlarch) {
+		this.fooToGlarch = fooToGlarch;
+	}
+	
+	public Map getFooComponentToFoo() {
+		return fooComponentToFoo;
+	}
+	
+	public void setFooComponentToFoo(Map fooComponentToFoo) {
+		this.fooComponentToFoo = fooComponentToFoo;
+	}
+	
+	public Map getGlarchToFoo() {
+		return glarchToFoo;
+	}
+	
+	public void setGlarchToFoo(Map glarchToFoo) {
+		this.glarchToFoo = glarchToFoo;
+	}
+	
+	public List getFees() {
+		return fees;
+	}
+
+	public void setFees(List fees) {
+		this.fees = fees;
+	}
+
+	public Collection getFooBag() {
+		return fooBag;
+	}
+
+	public void setFooBag(Collection fooBag) {
+		this.fooBag = fooBag;
+	}
+
+	/**
+	 * Returns the cached.
+	 * @return Set
+	 */
+	public Set getCached() {
+		return cached;
+	}
+
+	/**
+	 * Sets the cached.
+	 * @param cached The cached to set
+	 */
+	public void setCached(Set cached) {
+		this.cached = cached;
+	}
+
+	/**
+	 * Returns the cachedMap.
+	 * @return Map
+	 */
+	public Map getCachedMap() {
+		return cachedMap;
+	}
+
+	/**
+	 * Sets the cachedMap.
+	 * @param cachedMap The cachedMap to set
+	 */
+	public void setCachedMap(Map cachedMap) {
+		this.cachedMap = cachedMap;
+	}
+
+	/**
+	 * @see java.lang.Comparable#compareTo(java.lang.Object)
+	 */
+	public int compareTo(Object o) {
+		return ( (Baz) o ).code.compareTo(code);
+	}
+
+	/**
+	 * Returns the stringGlarchMap.
+	 * @return Map
+	 */
+	public Map getStringGlarchMap() {
+		return stringGlarchMap;
+	}
+
+	/**
+	 * Sets the stringGlarchMap.
+	 * @param stringGlarchMap The stringGlarchMap to set
+	 */
+	public void setStringGlarchMap(Map stringGlarchMap) {
+		this.stringGlarchMap = stringGlarchMap;
+	}
+
+	/**
+	 * Returns the anyToAny.
+	 * @return Map
+	 */
+	public Map getAnyToAny() {
+		return anyToAny;
+	}
+
+	/**
+	 * Sets the anyToAny.
+	 * @param anyToAny The anyToAny to set
+	 */
+	public void setAnyToAny(Map anyToAny) {
+		this.anyToAny = anyToAny;
+	}
+
+	public Collection getIdFooBag() {
+		return idFooBag;
+	}
+
+	public void setIdFooBag(Collection collection) {
+		idFooBag = collection;
+	}
+
+	public Collection getByteBag() {
+		return byteBag;
+	}
+
+	public void setByteBag(Collection list) {
+		byteBag = list;
+	}
+
+	public FooProxy getFoo() {
+		return foo;
+	}
+
+	public void setFoo(FooProxy foo) {
+		this.foo = foo;
+	}
+
+	public List getBazez() {
+		return bazez;
+	}
+
+	public void setBazez(List list) {
+		bazez = list;
+	}
+
+	public SortedSet getSortablez() {
+		return sortablez;
+	}
+
+	public void setSortablez(SortedSet set) {
+		sortablez = set;
+	}
+
+
+	public NestingComponent getCollectionComponent() {
+		return collectionComponent;
+	}
+
+	public void setCollectionComponent(NestingComponent collection) {
+		collectionComponent = collection;
+	}
+
+	/**
+	 * @return
+	 */
+	public String getText() {
+		return text;
+	}
+
+	/**
+	 * @param string
+	 */
+	public void setText(String string) {
+		text = string;
+	}
+
+	public List getParts() {
+		return parts;
+	}
+
+	public void setParts(List list) {
+		parts = list;
+	}
+
+	public List getManyToAny() {
+		return manyToAny;
+	}
+
+	public void setManyToAny(List manyToAny) {
+		this.manyToAny = manyToAny;
+	}
+
+	public List getMoreParts() {
+		return moreParts;
+	}
+	public void setMoreParts(List moreParts) {
+		this.moreParts = moreParts;
+	}
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Blobber.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Blobber.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Blobber.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+	<class name="org.hibernate.test.legacy.Blobber" dynamic-update="true">
+		<id name="id">
+			<generator class="hilo"/>
+		</id>
+		<property name="blob" column="blob_"/>
+		<property name="clob" column="clob_"/>
+	</class>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Blobber.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Blobber.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Blobber.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,58 @@
+package org.hibernate.test.legacy;
+
+import java.sql.Blob;
+import java.sql.Clob;
+
+public class Blobber {
+	private int id;
+	private Blob blob;
+	private Clob clob;
+	/**
+	 * Returns the blob.
+	 * @return Blob
+	 */
+	public Blob getBlob() {
+		return blob;
+	}
+
+	/**
+	 * Returns the clob.
+	 * @return Clob
+	 */
+	public Clob getClob() {
+		return clob;
+	}
+
+	/**
+	 * Returns the id.
+	 * @return int
+	 */
+	public int getId() {
+		return id;
+	}
+
+	/**
+	 * Sets the blob.
+	 * @param blob The blob to set
+	 */
+	public void setBlob(Blob blob) {
+		this.blob = blob;
+	}
+
+	/**
+	 * Sets the clob.
+	 * @param clob The clob to set
+	 */
+	public void setClob(Clob clob) {
+		this.clob = clob;
+	}
+
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(int id) {
+		this.id = id;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Broken.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Broken.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Broken.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+    <class name="org.hibernate.test.legacy.Broken" table="BROKE">
+        <!--id name="id" type="long" column="id_">
+            <generator class="hilo"/>
+        </id-->
+        <composite-id>
+        	<key-property name="id"/>
+        	<key-property name="otherId"/>
+        </composite-id>
+        <timestamp name="timestamp" column="`timestamp`"/>
+        <joined-subclass name="org.hibernate.test.legacy.Fixed" table="FIX">
+        	<key>
+        		<column name="BROKE_ID"/>
+        		<column name="OTHER_BROKE_ID"/>
+        	</key>
+			<set name="set" lazy="true" inverse="true">
+                <key>
+                	<column name="FIX_ID"/>
+                	<column name="OTHER_FIX_ID"/>
+                </key>
+                <one-to-many class="org.hibernate.test.legacy.Broken"/>
+            </set>
+            <property name="list" type="serializable"/>
+        </joined-subclass>
+    </class>
+    
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Broken.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Broken.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Broken.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+//$Id: Broken.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class Broken implements Serializable {
+	private Long id;
+	private String otherId;
+	private Date timestamp;
+	public Long getId() {
+		return id;
+	}
+
+	public Date getTimestamp() {
+		return timestamp;
+	}
+
+	public void setId(Long long1) {
+		id = long1;
+	}
+
+	public void setTimestamp(Date date) {
+		timestamp = date;
+	}
+
+	public String getOtherId() {
+		return otherId;
+	}
+
+	public void setOtherId(String string) {
+		otherId = string;
+	}
+	
+	public boolean equals(Object other) {
+		if ( !(other instanceof Broken) ) return false;
+		Broken that = (Broken) other;
+		return this.id.equals(that.id) && this.otherId.equals(that.otherId);
+	}
+	
+	public int hashCode() {
+		return 1;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/C1.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/C1.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/C1.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,91 @@
+//$Id: C1.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class C1 extends B{
+	private String address;
+	private String c1Name;
+	private C2 c2;
+	private D d;
+	private Collection c2s = new ArrayList();
+	/**
+	 * Returns the address.
+	 * @return String
+	 */
+	public String getAddress() {
+		return address;
+	}
+	
+	/**
+	 * Sets the address.
+	 * @param address The address to set
+	 */
+	public void setAddress(String address) {
+		this.address = address;
+	}
+	
+	/**
+	 * Returns the d.
+	 * @return D
+	 */
+	public D getD() {
+		return d;
+	}
+	
+	/**
+	 * Sets the d.
+	 * @param d The d to set
+	 */
+	public void setD(D d) {
+		this.d = d;
+	}
+	
+	/**
+	 * @return Returns the c.
+	 */
+	public C2 getC2() {
+		return c2;
+	}
+
+	/**
+	 * @param c The c to set.
+	 */
+	public void setC2(C2 c) {
+		this.c2 = c;
+	}
+
+	/**
+	 * @return Returns the cs.
+	 */
+	public Collection getC2s() {
+		return c2s;
+	}
+
+	/**
+	 * @param cs The cs to set.
+	 */
+	public void setC2s(Collection cs) {
+		this.c2s = cs;
+	}
+
+	/**
+	 * @return Returns the c1Name.
+	 */
+	public String getC1Name() {
+		return c1Name;
+	}
+	/**
+	 * @param name The c1Name to set.
+	 */
+	public void setC1Name(String name) {
+		c1Name = name;
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/C2.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/C2.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/C2.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+//$Id: C2.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class C2 extends B {
+	private String address;
+	private C1 c1;
+	private String c2Name;
+	private Collection c1s = new ArrayList();
+	/**
+	 * Returns the address.
+	 * @return String
+	 */
+	public String getAddress() {
+		return address;
+	}
+	
+	/**
+	 * Sets the address.
+	 * @param address The address to set
+	 */
+	public void setAddress(String address) {
+		this.address = address;
+	}
+	
+	/**
+	 * @return Returns the c.
+	 */
+	public C1 getC1() {
+		return c1;
+	}
+
+	/**
+	 * @param c The c to set.
+	 */
+	public void setC1(C1 c) {
+		this.c1 = c;
+	}
+
+	/**
+	 * @return Returns the cs.
+	 */
+	public Collection getC1s() {
+		return c1s;
+	}
+
+	/**
+	 * @param cs The cs to set.
+	 */
+	public void setC1s(Collection cs) {
+		this.c1s = cs;
+	}
+
+	public String getC2Name() {
+		return c2Name;
+	}
+
+	public void setC2Name(String name) {
+		c2Name = name;
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CacheTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CacheTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CacheTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,143 @@
+//$Id: CacheTest.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.cache.Cache;
+import org.hibernate.cache.CacheConcurrencyStrategy;
+import org.hibernate.cache.CacheProvider;
+import org.hibernate.cache.ReadWriteCache;
+import org.hibernate.cache.HashtableCacheProvider;
+import org.hibernate.cache.access.SoftLock;
+import org.hibernate.junit.UnitTestCase;
+
+public class CacheTest extends UnitTestCase {
+
+	public CacheTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new TestSuite( CacheTest.class );
+	}
+
+	public void testCaches() throws Exception {
+		doTestCache( new HashtableCacheProvider() );
+	}
+
+	public void doTestCache(CacheProvider cacheProvider) throws Exception {
+
+		Cache cache = cacheProvider.buildCache( String.class.getName(), System.getProperties() );
+
+		long longBefore = cache.nextTimestamp();
+
+		Thread.sleep(15);
+
+		long before = cache.nextTimestamp();
+
+		Thread.sleep(15);
+
+		//cache.setTimeout(1000);
+		CacheConcurrencyStrategy ccs = new ReadWriteCache();
+		ccs.setCache(cache);
+
+		// cache something
+
+		assertTrue( ccs.put("foo", "foo", before, null, null, false) );
+
+		Thread.sleep(15);
+
+		long after = cache.nextTimestamp();
+
+		assertTrue( ccs.get("foo", longBefore)==null );
+		assertTrue( ccs.get("foo", after).equals("foo") );
+
+		assertTrue( !ccs.put("foo", "foo", before, null, null, false) );
+
+		// update it:
+
+		SoftLock lock = ccs.lock("foo", null);
+
+		assertTrue( ccs.get("foo", after)==null );
+		assertTrue( ccs.get("foo", longBefore)==null );
+
+		assertTrue( !ccs.put("foo", "foo", before, null, null, false) );
+
+		Thread.sleep(15);
+
+		long whileLocked = cache.nextTimestamp();
+
+		assertTrue( !ccs.put("foo", "foo", whileLocked, null, null, false) );
+
+		Thread.sleep(15);
+
+		ccs.release("foo", lock);
+
+		assertTrue( ccs.get("foo", after)==null );
+		assertTrue( ccs.get("foo", longBefore)==null );
+
+		assertTrue( !ccs.put("foo", "bar", whileLocked, null, null, false) );
+		assertTrue( !ccs.put("foo", "bar", after, null, null, false) );
+
+		Thread.sleep(15);
+
+		long longAfter = cache.nextTimestamp();
+
+		assertTrue( ccs.put("foo", "baz", longAfter, null, null, false) );
+
+		assertTrue( ccs.get("foo", after)==null );
+		assertTrue( ccs.get("foo", whileLocked)==null );
+
+		Thread.sleep(15);
+
+		long longLongAfter = cache.nextTimestamp();
+
+		assertTrue( ccs.get("foo", longLongAfter).equals("baz") );
+
+		// update it again, with multiple locks:
+
+		SoftLock lock1 = ccs.lock("foo", null);
+		SoftLock lock2 = ccs.lock("foo", null);
+
+		assertTrue( ccs.get("foo", longLongAfter)==null );
+
+		Thread.sleep(15);
+
+		whileLocked = cache.nextTimestamp();
+
+		assertTrue( !ccs.put("foo", "foo", whileLocked, null, null, false) );
+
+		Thread.sleep(15);
+
+		ccs.release("foo", lock2);
+
+		Thread.sleep(15);
+
+		long betweenReleases = cache.nextTimestamp();
+
+		assertTrue( !ccs.put("foo", "bar", betweenReleases, null, null, false) );
+		assertTrue( ccs.get("foo", betweenReleases)==null );
+
+		Thread.sleep(15);
+
+		ccs.release("foo", lock1);
+
+		assertTrue( !ccs.put("foo", "bar", whileLocked, null, null, false) );
+
+		Thread.sleep(15);
+
+		longAfter = cache.nextTimestamp();
+
+		assertTrue( ccs.put("foo", "baz", longAfter, null, null, false) );
+		assertTrue( ccs.get("foo", whileLocked)==null );
+
+		Thread.sleep(15);
+
+		longLongAfter = cache.nextTimestamp();
+
+		assertTrue( ccs.get("foo", longLongAfter).equals("baz") );
+
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Category.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Category.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Category.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+	<class name="org.hibernate.test.legacy.Category" 
+		table="category"
+		dynamic-update="true"
+		dynamic-insert="true">
+
+		<id name="id" column="category_key_col">
+			<generator class="native"/>
+		</id>
+
+		<list name="subcategories" lazy="true" cascade="save-update,merge,delete,lock">
+		    <!--cache-->
+			<key column="parent"/>
+			<index column="ord"/>
+			<one-to-many class="org.hibernate.test.legacy.Category"/>
+		</list>
+
+		<property name="name"/>
+		<many-to-one name="assignable" column="`assign-able-id`"/>
+
+	</class>
+
+	<class name="org.hibernate.test.legacy.Assignable" table="`assign-able`">
+		<id name="id">
+			<generator class="assigned"/>
+		</id>
+
+		<bag name="categories" inverse="true" cascade="all" lazy="true">
+			<key column="`assign-able-id`"/>
+			<one-to-many class="org.hibernate.test.legacy.Category"/>
+		</bag>
+	</class>
+
+	<sql-query name="namedsql">
+		<return alias="category" class="org.hibernate.test.legacy.Category"/>
+		<return alias="assignable" class="org.hibernate.test.legacy.Assignable"/>		
+		select {category.*}, {assignable.*} from category {category}, "assign-able" {assignable}	
+	</sql-query>
+
+	<sql-query name="nonaliasedsql">
+		<return alias="category" class="org.hibernate.test.legacy.Category">
+			<return-property name="id" column="category_key_col"/>
+			<return-property name="name" column="name"/>
+			<return-property name="assignable" column="assignid"/>
+		</return>
+		select category_key_col, name, "assign-able-id" as assignid from category
+	</sql-query>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Category.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Category.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Category.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,85 @@
+//$Id: Category.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.legacy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ */
+public class Category {
+	
+	public static final String ROOT_CATEGORY = "/";
+	public static final int ROOT_ID = 42;
+
+	private long id;
+	private String name;
+	private List subcategories = new ArrayList();
+	private Assignable assignable;
+	/**
+	 * Returns the id.
+	 * @return long
+	 */
+	public long getId() {
+		return id;
+	}
+	
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	
+	/**
+	 * Returns the subcategories.
+	 * @return List
+	 */
+	public List getSubcategories() {
+		return subcategories;
+	}
+	
+	/**
+	 * Sets the subcategories.
+	 * @param subcategories The subcategories to set
+	 */
+	public void setSubcategories(List subcategories) {
+		this.subcategories = subcategories;
+	}
+	
+	/**
+	 * Returns the name.
+	 * @return String
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * Sets the name.
+	 * @param name The name to set
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+	public Assignable getAssignable() {
+		return assignable;
+	}
+
+	public void setAssignable(Assignable assignable) {
+		this.assignable = assignable;
+	}
+	
+	public String toString() {
+		return id + ":" + name;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Child.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Child.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Child.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+//$Id: Child.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+public class Child {
+	private Parent parent;
+	private int count;
+	private int x;
+	
+	public int getX() {
+		return x;
+	}
+	public void setX(int x) {
+		this.x = x;
+	}
+	
+	public Parent getParent() {
+		return parent;
+	}
+	
+	
+	public void setParent(Parent parent) {
+		this.parent = parent;
+	}
+	
+	
+	public int getCount() {
+		return count;
+	}
+	
+	
+	public void setCount(int count) {
+		this.count = count;
+	}
+	
+	public long getId() {
+		return parent.getId();
+	}
+	private void setId(long id) {
+	}
+	
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Circular.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Circular.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Circular.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false" default-cascade="save-update">
+
+    <class name="org.hibernate.test.legacy.Circular" dynamic-update="true">
+        <id name="id" column="id_" length="64" unsaved-value="null">
+            <generator class="uuid"/>
+        </id>
+        <property name="clazz"/>
+        <many-to-one name="other"/>
+        <property name="anyEntity">
+        	<column name="classname"/>
+        	<column name="any_id"/>
+        </property>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Circular.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Circular.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Circular.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,88 @@
+//$Id: Circular.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+public class Circular {
+	
+	private String id;
+	private Class clazz;
+	private Circular other;
+	private Object anyEntity;
+	
+	/**
+	 * Constructor for Circular.
+	 */
+	public Circular() {
+		super();
+	}
+	
+	/**
+	 * Returns the clazz.
+	 * @return Class
+	 */
+	public Class getClazz() {
+		return clazz;
+	}
+	
+	/**
+	 * Returns the id.
+	 * @return String
+	 */
+	public String getId() {
+		return id;
+	}
+	
+	/**
+	 * Sets the clazz.
+	 * @param clazz The clazz to set
+	 */
+	public void setClazz(Class clazz) {
+		this.clazz = clazz;
+	}
+	
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(String id) {
+		this.id = id;
+	}
+	
+	/**
+	 * Returns the other.
+	 * @return Circular
+	 */
+	public Circular getOther() {
+		return other;
+	}
+	
+	/**
+	 * Sets the other.
+	 * @param other The other to set
+	 */
+	public void setOther(Circular other) {
+		this.other = other;
+	}
+	
+	/**
+	 * Returns the anyEntity.
+	 * @return Object
+	 */
+	public Object getAnyEntity() {
+		return anyEntity;
+	}
+	
+	/**
+	 * Sets the anyEntity.
+	 * @param anyEntity The anyEntity to set
+	 */
+	public void setAnyEntity(Object anyEntity) {
+		this.anyEntity = anyEntity;
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Commento.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Commento.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Commento.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+<!--
+    Created by the Middlegen Hibernate plugin 2.1
+
+    http://boss.bekk.no/boss/middlegen/
+    http://hibernate.sourceforge.net/
+-->
+
+<class entity-name="Commento" table="MARECM">
+    <id name="mclink" type="long" column="MCLINK">
+        <generator class="assigned"/>
+    </id>
+
+    <property name="mcompr" type="java.lang.String" column="MCOMPR" length="1"/>
+    <property name="mcomme" type="java.lang.String" column="MCOMME" length="30"/>
+
+    <!-- Associations -->
+    <!--many-to-one name="marelo" class="Marelo" column="MCLINK" unique="true"/-->
+    <one-to-one name="marelo" entity-name="Marelo" outer-join="auto" property-ref="commento"/>
+
+</class>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Company.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Company.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Company.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+package org.hibernate.test.legacy;
+
+/**
+ * @author hbm2java
+ */
+public class Company extends org.hibernate.test.legacy.Party {
+
+   java.lang.String id;
+   java.lang.String president;
+
+
+  java.lang.String getId() {
+    return id;
+  }
+
+  void  setId(java.lang.String newValue) {
+    id = newValue;
+  }
+
+  java.lang.String getPresident() {
+    return president;
+  }
+
+  void  setPresident(java.lang.String newValue) {
+    president = newValue;
+  }
+
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Component.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Component.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Component.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+//$Id: Component.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+/**
+ * Component
+ * 
+ * @author Emmanuel Bernard
+ */
+public class Component {
+    private String _name;
+    
+    private SubComponent _subComponent;
+
+    /**
+     * @return
+     */
+    public String getName() {
+        return _name;
+    }
+
+    /**
+     * @param string
+     */
+    public void setName(String string) {
+        _name = string;
+    }
+
+    /**
+     * @return
+     */
+    public SubComponent getSubComponent() {
+        return _subComponent;
+    }
+
+    /**
+     * @param component
+     */
+    public void setSubComponent(SubComponent component) {
+        _subComponent = component;
+    }
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentCollection.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentCollection.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentCollection.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: ComponentCollection.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class ComponentCollection implements Serializable {
+	private String str;
+	private List foos;
+	private List floats;
+	public List getFoos() {
+		return foos;
+	}
+
+	public String getStr() {
+		return str;
+	}
+
+	public void setFoos(List list) {
+		foos = list;
+	}
+
+	public void setStr(String string) {
+		str = string;
+	}
+
+	public List getFloats() {
+		return floats;
+	}
+
+	public void setFloats(List list) {
+		floats = list;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNull.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNull.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNull.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,90 @@
+//$Id: ComponentNotNull.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+/**
+ * Component used to check not-null sub properties management
+ * 
+ * @author Emmanuel Bernard
+ */
+public class ComponentNotNull {
+	/* 
+	 * I've flatten several components in one class, this is kind of ugly but
+ 	 * I don't have to write tons of classes
+ 	 */
+	private String prop1Nullable;
+	private String prop2Nullable;
+	private ComponentNotNull supercomp;
+	private ComponentNotNull subcomp;
+	private String prop1Subcomp;
+
+	/**
+	 * @return
+	 */
+	public String getProp1Nullable() {
+		return prop1Nullable;
+	}
+
+	/**
+	 * @return
+	 */
+	public String getProp1Subcomp() {
+		return prop1Subcomp;
+	}
+
+	/**
+	 * @return
+	 */
+	public String getProp2Nullable() {
+		return prop2Nullable;
+	}
+
+	/**
+	 * @return
+	 */
+	public ComponentNotNull getSubcomp() {
+		return subcomp;
+	}
+
+	/**
+	 * @return
+	 */
+	public ComponentNotNull getSupercomp() {
+		return supercomp;
+	}
+
+	/**
+	 * @param string
+	 */
+	public void setProp1Nullable(String string) {
+		prop1Nullable = string;
+	}
+
+	/**
+	 * @param string
+	 */
+	public void setProp1Subcomp(String string) {
+		prop1Subcomp = string;
+	}
+
+	/**
+	 * @param string
+	 */
+	public void setProp2Nullable(String string) {
+		prop2Nullable = string;
+	}
+
+	/**
+	 * @param null1
+	 */
+	public void setSubcomp(ComponentNotNull null1) {
+		subcomp = null1;
+	}
+
+	/**
+	 * @param null1
+	 */
+	public void setSupercomp(ComponentNotNull null1) {
+		supercomp = null1;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNullMaster.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNullMaster.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNullMaster.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping default-lazy="false">
+
+	<class name="org.hibernate.test.legacy.ComponentNotNullMaster"> <!-- discriminator-value="A"> -->
+		<id name="id" column="container_id">
+			<generator class="native" />
+		</id>
+		<property name="test"/>
+		
+		<component name="nullable">
+		  <property name="prop1Nullable" />
+		  <property name="prop2Nullable"/>
+		</component>
+		
+		<component name="supercomp">
+		  <component name="subcomp">
+    		  <property name="prop1Subcomp" not-null="true"/>
+		  </component>
+		</component>
+		
+		<list name="components" lazy="true">
+			<key column = "container_id"/>
+			<index column = "list_index"/>
+			<composite-element class="org.hibernate.test.legacy.ComponentNotNullMaster$ContainerInnerClass">
+				<property name="name"/>
+				<property name="count" column="count_"/>
+				<many-to-one name="simple" not-null="true" cascade="save-update"/>
+				<many-to-one name="one" cascade="save-update"/>
+				<many-to-one name="many" cascade="save-update"/>
+			</composite-element>
+		</list>
+		
+				
+		<list name="componentsImplicit" lazy="true">
+			<key column = "container_id"/>
+			<index column = "list_index3"/>
+			<composite-element class="org.hibernate.test.legacy.ComponentNotNullMaster$ContainerInnerClass">
+				<property name="name"/>
+				<property name="count" column="count_"/>
+				<many-to-one name="simple" cascade="save-update"/>
+				<many-to-one name="one" cascade="save-update"/>
+				<nested-composite-element name="nested" class="org.hibernate.test.legacy.ComponentNotNullMaster$ContainerInnerClass">
+					<property name="nestedproperty" not-null="true"/>
+				</nested-composite-element>
+			</composite-element>
+		</list>
+		<!-- subclass name="org.hibernate.test.legacy.ExtendedComponentNotNull" discriminator-value="B">
+		  <component name="subclassComp" not-null="true">
+		    <property name="subclass" />
+		  </component>
+		</subclass -->
+		<!-- joined-subclass name="org.hibernate.test.legacy.ExtendedComponentNotNull">
+		  <key column="id"/>
+		  <component name="subclassComp" not-null="true">
+		    <property name="subclass" />
+		  </component>
+		</joined-subclass -->
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNullMaster.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNullMaster.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNullMaster.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,142 @@
+//$Id: ComponentNotNullMaster.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.List;
+
+/**
+ * Entity containing components for not-null testing
+ * 
+ * @author Emmanuel Bernard
+ */
+public class ComponentNotNullMaster {
+	
+	private int id;
+	private String test;
+	private ComponentNotNull nullable;
+	private ComponentNotNull supercomp;
+	private List components;
+	private List componentsImplicit;
+
+	public int getId() {
+		return id;
+	}
+
+	public ComponentNotNull getNullable() {
+		return nullable;
+	}
+
+	public void setId(int i) {
+		id = i;
+	}
+
+	public void setNullable(ComponentNotNull component) {
+		nullable = component;
+	}
+
+	public static final class ContainerInnerClass {
+		private Simple simple;
+		private String name;
+		private One one;
+		private Many many;
+		private int count;
+		private ContainerInnerClass nested;
+		private String nestedproperty;
+		
+		public void setSimple(Simple simple) {
+			this.simple = simple;
+		}
+		
+		public Simple getSimple() {
+			return simple;
+		}
+
+		public String getName() {
+			return name;
+		}
+		
+
+		public void setName(String name) {
+			this.name = name;
+		}
+		
+		public String toString() {
+			return name +  " = " + simple.getCount() +
+			 "/"  + ( one==null ? "nil" : one.getKey().toString() ) +
+			 "/"  + ( many==null ? "nil" : many.getKey().toString() );
+		}
+		
+		public One getOne() {
+			return one;
+		}
+		
+		public void setOne(One one) {
+			this.one = one;
+		}
+		
+		public Many getMany() {
+			return many;
+		}
+
+		public void setMany(Many many) {
+			this.many = many;
+		}
+		
+		public int getCount() {
+			return count;
+		}
+
+		public void setCount(int count) {
+			this.count = count;
+		}
+
+		public ContainerInnerClass getNested() {
+			return nested;
+		}
+
+		public void setNested(ContainerInnerClass class1) {
+			nested = class1;
+		}
+
+		public String getNestedproperty() {
+			return nestedproperty;
+		}
+
+		public void setNestedproperty(String string) {
+			nestedproperty = string;
+		}
+
+	}
+
+	public List getComponents() {
+		return components;
+	}
+
+	public void setComponents(List list) {
+		components = list;
+	}
+
+	public List getComponentsImplicit() {
+		return componentsImplicit;
+	}
+
+	public void setComponentsImplicit(List list) {
+		componentsImplicit = list;
+	}
+
+	public ComponentNotNull getSupercomp() {
+		return supercomp;
+	}
+
+	public void setSupercomp(ComponentNotNull component) {
+		supercomp = component;
+	}
+
+	public String getTest() {
+		return test;
+	}
+
+	public void setTest(String string) {
+		test = string;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNullTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNullTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ComponentNotNullTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,206 @@
+//{Id:}
+package org.hibernate.test.legacy;
+
+import java.util.ArrayList;
+
+import junit.framework.Test;
+import junit.textui.TestRunner;
+
+import org.hibernate.PropertyValueException;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Test some cases of not-null properties inside components.
+ *
+ * @author Emmanuel Bernard
+ */
+public class ComponentNotNullTest extends LegacyTestCase {
+
+	public ComponentNotNullTest(String x) {
+		super(x);
+	}
+
+	public String[] getMappings() {
+		return new String[] {
+			"legacy/ComponentNotNullMaster.hbm.xml",
+			"legacy/One.hbm.xml",
+			"legacy/Many.hbm.xml",
+			"legacy/Simple.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ComponentNotNullTest.class );
+	}
+
+	public static void main(String[] args) throws Exception {
+		TestRunner.run(suite());
+	}
+
+	public void testComponentNotNull() throws Exception {
+
+		//everything not null
+		//
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		ComponentNotNullMaster master = new ComponentNotNullMaster();
+		ComponentNotNull nullable = new ComponentNotNull();
+		ComponentNotNull supercomp = new ComponentNotNull();
+		ComponentNotNull subcomp = new ComponentNotNull();
+
+		master.setNullable(nullable);
+		subcomp.setProp1Subcomp("test");
+		supercomp.setSubcomp(subcomp);
+		master.setSupercomp(supercomp);
+		s.save(master);
+		t.commit();
+		s.close();
+
+		//null prop of a subcomp
+		//
+		s = openSession();
+		t = s.beginTransaction();
+
+		master = new ComponentNotNullMaster();
+		nullable = new ComponentNotNull();
+		supercomp = new ComponentNotNull();
+		subcomp = new ComponentNotNull();
+
+		master.setNullable(nullable);
+		// do not set property
+		//subcomp.setProp1Subcomp("test");
+		supercomp.setSubcomp(subcomp);
+		master.setSupercomp(supercomp);
+
+
+		try {
+			s.save(master);
+			t.commit();
+			fail("Inserting not-null null property should fail");
+		} catch (PropertyValueException e) {
+			//succeed
+		}
+		t.rollback();
+		s.close();
+
+		//null component having not-null column
+		//
+		s = openSession();
+		t = s.beginTransaction();
+
+		master = new ComponentNotNullMaster();
+		nullable = new ComponentNotNull();
+		supercomp = new ComponentNotNull();
+		subcomp = new ComponentNotNull();
+
+		master.setNullable(nullable);
+		// do not set supercomp for master
+		//subcomp.setProp1Subcomp("test");
+		//supercomp.setSubcomp(subcomp);
+		//master.setSupercomp(supercomp);
+
+
+		try {
+			s.save(master);
+			t.commit();
+			fail("Inserting not-null null property should fail");
+		} catch (PropertyValueException e) {
+			//succeed
+		}
+		t.rollback();
+		s.close();
+	}
+
+	public void testCompositeElement() throws Exception {
+		//composite-element nullable
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		ComponentNotNullMaster master = new ComponentNotNullMaster();
+		ComponentNotNull nullable = new ComponentNotNull();
+		ComponentNotNull supercomp = new ComponentNotNull();
+		ComponentNotNull subcomp = new ComponentNotNull();
+
+		master.setNullable(nullable);
+		subcomp.setProp1Subcomp("test");
+		supercomp.setSubcomp(subcomp);
+		master.setSupercomp(supercomp);
+
+		master.setComponents(new ArrayList());
+		ComponentNotNullMaster.ContainerInnerClass cc =
+			new ComponentNotNullMaster.ContainerInnerClass();
+		master.getComponents().add(cc);
+
+		try {
+			s.save(master);
+			t.commit();
+			fail("Inserting not-null many-to-one should fail");
+		} catch (PropertyValueException e) {
+			//success
+		}
+		t.rollback();
+		s.close();
+
+		//null nested component having not-null column
+		//
+		s = openSession();
+		t = s.beginTransaction();
+
+		master = new ComponentNotNullMaster();
+		nullable = new ComponentNotNull();
+		supercomp = new ComponentNotNull();
+		subcomp = new ComponentNotNull();
+
+		master.setNullable(nullable);
+		subcomp.setProp1Subcomp("test");
+		supercomp.setSubcomp(subcomp);
+		master.setSupercomp(supercomp);
+
+		master.setComponentsImplicit(new ArrayList());
+		ComponentNotNullMaster.ContainerInnerClass nestedCc =
+			new ComponentNotNullMaster.ContainerInnerClass();
+		cc =
+			new ComponentNotNullMaster.ContainerInnerClass();
+		cc.setNested(nestedCc);
+		master.getComponentsImplicit().add(cc);
+
+		try {
+			s.save(master);
+			t.commit();
+			fail("Inserting not-null null property should fail");
+		} catch (PropertyValueException e) {
+			//succeed
+		}
+		t.rollback();
+		s.close();
+
+		//nested component having not-null column
+		//
+		s = openSession();
+		t = s.beginTransaction();
+
+		master = new ComponentNotNullMaster();
+		nullable = new ComponentNotNull();
+		supercomp = new ComponentNotNull();
+		subcomp = new ComponentNotNull();
+
+		master.setNullable(nullable);
+		subcomp.setProp1Subcomp("test");
+		supercomp.setSubcomp(subcomp);
+		master.setSupercomp(supercomp);
+
+		master.setComponentsImplicit(new ArrayList());
+		nestedCc =
+			new ComponentNotNullMaster.ContainerInnerClass();
+		cc =
+			new ComponentNotNullMaster.ContainerInnerClass();
+		cc.setNested(nestedCc);
+		nestedCc.setNestedproperty("test");
+		master.getComponentsImplicit().add(cc);
+
+		s.save(master);
+		t.commit();
+		s.close();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Componentizable.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Componentizable.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Componentizable.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+	<class name="org.hibernate.test.legacy.Componentizable">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="nickName"/>
+		<component name="component" access="property" class="org.hibernate.test.legacy.Component">
+			<property name="name"/>
+			<component name="subComponent" class="org.hibernate.test.legacy.SubComponent">
+		   	<property name="subName"/>
+		   	<property name="subName1"/>
+	  		</component>
+		</component>
+	</class>
+	
+	<sql-query name="queryComponentWithOtherColumn">
+	 <return class="org.hibernate.test.legacy.Componentizable">
+	   <return-property name="nickName" column="n2"/>
+	   <return-property name="component.subComponent.subName">
+         <return-column name="otherSubName"/>
+       </return-property>
+       <return-property name="component.subComponent.subName1">
+         <return-column name="subName1"/>
+	   </return-property>
+       <return-property name="component.name">
+         <return-column name="name"/>
+       </return-property>
+     </return>
+	 select id, nickName as n2, name, subName as otherSubName, subName1 from Componentizable
+	</sql-query>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Componentizable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Componentizable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Componentizable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+//$Id: Componentizable.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+/**
+ * contains components
+ * 
+ * @author emmanuel
+ */
+public class Componentizable {
+	/** surrogate id */
+	private Integer _id;
+    
+    public String _nickName;
+	
+	/** component */
+    private Component _component;
+
+    /**
+     * @return
+     */
+    public Integer getId() {
+        return _id;
+    }
+
+    /**
+     * @param integer
+     */
+    public void setId(Integer integer) {
+        _id = integer;
+    }
+
+    /**
+     * @return
+     */
+    public Component getComponent() {
+        return _component;
+    }
+
+    /**
+     * @param component
+     */
+    public void setComponent(Component component) {
+        _component = component;
+    }
+
+    /**
+     * @return
+     */
+    public String getNickName() {
+        return _nickName;
+    }
+
+    /**
+     * @param string
+     */
+    public void setNickName(String string) {
+        _nickName = string;
+    }
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CompositeElement.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CompositeElement.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CompositeElement.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+//$Id: CompositeElement.java 6844 2005-05-21 14:22:16Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+public class CompositeElement implements Comparable, Serializable {
+	private String foo;
+	private String bar;
+	/**
+	 * Returns the bar.
+	 * @return String
+	 */
+	public String getBar() {
+		return bar;
+	}
+
+	/**
+	 * Returns the foo.
+	 * @return String
+	 */
+	public String getFoo() {
+		return foo;
+	}
+
+	/**
+	 * Sets the bar.
+	 * @param bar The bar to set
+	 */
+	public void setBar(String bar) {
+		this.bar = bar;
+	}
+
+	/**
+	 * Sets the foo.
+	 * @param foo The foo to set
+	 */
+	public void setFoo(String foo) {
+		this.foo = foo;
+	}
+
+	/**
+	 * @see java.lang.Comparable#compareTo(java.lang.Object)
+	 */
+	public int compareTo(Object o) {
+		return ( (CompositeElement) o ).foo.compareTo(foo);
+	}
+	
+	public int hashCode() {
+		return foo.hashCode() + bar.hashCode();
+	}
+	
+	public boolean equals(Object that) {
+		CompositeElement ce = (CompositeElement) that;
+		return ce.bar.equals(bar) && ce.foo.equals(foo);
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CompositeIdId.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CompositeIdId.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CompositeIdId.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+<?xml version="1.0"?> 
+<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
+<hibernate-mapping package="org.hibernate.test.legacy"> 
+   <class name="CompositeIdId"> 
+      <composite-id> 
+         <key-property name="system"/> 
+         <key-property name="id"/> 
+      </composite-id> 
+      <property name="name"/>
+      
+      <component name="composite">
+      	<property name="foo"/>
+      	<property name="bar"/>
+      </component>
+      <loader query-ref="loadC"/>
+   </class> 
+   
+   <sql-query name="loadC"> 
+      <return alias="c" class="CompositeIdId"/> 
+      select system as {c.system}, id as {c.id}, name as {c.name}, foo as {c.composite.foo}, bar as {c.composite.bar} from CompositeIdId where system=? and id=?
+   </sql-query> 
+   
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CompositeIdId.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CompositeIdId.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CompositeIdId.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+/*
+ * Created on 20-Dec-2004
+ *
+ */
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+/**
+ * @author max
+ *
+ */
+public class CompositeIdId implements Serializable {
+
+    String system;
+    String id;
+    String name;
+    CompositeElement composite;
+    
+    
+    public String getId() {
+        return id;
+    }
+    public void setId(String id) {
+        this.id = id;
+    }
+    public String getSystem() {
+        return system;
+    }
+    public void setSystem(String system) {
+        this.system = system;
+    }
+    public String getName() {
+        return name;
+    }
+    public void setName(String name) {
+        this.name = name;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals(Object obj) {
+        // not totally NP or type safe equals, but enough for the unittests. 
+        CompositeIdId o = (CompositeIdId) obj;
+        if(o==null) return false;
+        return o.getSystem().equals(getSystem()) && o.getId().equals(getId());
+    }
+    public CompositeElement getComposite() {
+        return composite;
+    }
+    public void setComposite(CompositeElement composite) {
+        this.composite = composite;
+    }
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ConfigurationPerformanceTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ConfigurationPerformanceTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ConfigurationPerformanceTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,255 @@
+/*
+ * Created on 01-05-2004
+ *
+  */
+package org.hibernate.test.legacy;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.PrintWriter;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+import org.hibernate.HibernateException;
+import org.hibernate.SessionFactory;
+import org.hibernate.junit.UnitTestCase;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.classic.Session;
+
+/**
+ * @author MAX
+ *
+ */
+public class ConfigurationPerformanceTest extends UnitTestCase {
+
+	String[] files = new String[] {
+			"legacy/ABC.hbm.xml",
+			"legacy/ABCExtends.hbm.xml",
+			"legacy/Baz.hbm.xml",
+			"legacy/Blobber.hbm.xml",
+			"legacy/Broken.hbm.xml",
+			"legacy/Category.hbm.xml",
+			"legacy/Circular.hbm.xml",
+			"legacy/Commento.hbm.xml",
+			"legacy/ComponentNotNullMaster.hbm.xml",
+			"legacy/Componentizable.hbm.xml",
+			"legacy/Container.hbm.xml",
+			"legacy/Custom.hbm.xml",
+			"legacy/CustomSQL.hbm.xml",
+			"legacy/Eye.hbm.xml",
+			"legacy/Fee.hbm.xml",
+			"legacy/Fo.hbm.xml",
+			"legacy/FooBar.hbm.xml",
+			"legacy/Fum.hbm.xml",
+			"legacy/Fumm.hbm.xml",
+			"legacy/Glarch.hbm.xml",
+			"legacy/Holder.hbm.xml",
+			"legacy/IJ2.hbm.xml",
+			"legacy/Immutable.hbm.xml",
+			"legacy/Location.hbm.xml",
+			"legacy/Many.hbm.xml",
+			"legacy/Map.hbm.xml",
+			"legacy/Marelo.hbm.xml",
+			"legacy/MasterDetail.hbm.xml",
+			"legacy/Middle.hbm.xml",
+			"legacy/Multi.hbm.xml",
+			"legacy/MultiExtends.hbm.xml",
+			"legacy/Nameable.hbm.xml",
+			"legacy/One.hbm.xml",
+			"legacy/ParentChild.hbm.xml",
+			"legacy/Qux.hbm.xml",
+			"legacy/Simple.hbm.xml",
+			"legacy/SingleSeveral.hbm.xml",
+			"legacy/Stuff.hbm.xml",
+			"legacy/UpDown.hbm.xml",
+			"legacy/Vetoer.hbm.xml",
+			"legacy/WZ.hbm.xml",
+	};
+
+	boolean keepFilesAround = false 	; // set to true to be able to "coldstart" start.
+
+	public ConfigurationPerformanceTest(String string) {
+		super( string );
+	}
+
+	public void testLoadingAndSerializationOfConfiguration() throws HibernateException, FileNotFoundException, IOException, ClassNotFoundException {
+
+		String prefix = "./test/org/hibernate/test/";
+		try {
+			// first time
+			System.err.println("###FIRST SAVELOAD###");
+			saveAndLoad(prefix,files, "hibernate.cfg.bin");
+			// second time to validate
+			System.err.println("###SECOND SAVELOAD###");
+			saveAndLoad(prefix,files, "hibernate.cfg.bin");
+		}
+		finally {
+			System.err.println( "###CLEANING UP###" );
+			if(!keepFilesAround) {
+				File file = null;
+				try {
+				// clean up
+					file = new File("hibernate.cfg.bin");
+					file.delete();
+				}
+				catch( Throwable t ) {
+					System.err.println( "Unable to cleanup [" + file + "] : " + t );
+				}
+
+				for (int i = 0; i < files.length; i++) {
+					try {
+						String fileName = files[i];
+						file = new File( prefix, fileName + ".bin" );
+						file.delete();
+					}
+					catch( Throwable t ) {
+						System.err.println( "Unable to cleanup [" + file + "] : " + t );
+					}
+				}
+			}
+		}
+		
+	}
+	
+	// this method requires generation of test files (can be done with generateTestFiles) + their compile
+	public void xtestSessionFactoryCreationTime() throws FileNotFoundException, IOException, ClassNotFoundException {
+		File perfs = new File("perfsrc");
+		generateTestFiles(perfs, "perftest");
+		if(perfs.exists()) {
+			SessionFactory factory = saveAndLoad("perfsrc/perftest/", new File(perfs, "perftest").list(new FilenameFilter() {
+			
+				public boolean accept(File dir, String name) {
+					return name.endsWith(".hbm.xml");
+				}
+			
+			}), "hibernateperftest.cfg.bin");
+			
+			Session session = factory.openSession();
+			Object o = session.load("perftest.Test1", new Long(42));
+			System.out.println(o);
+		} else {
+			System.err.println(perfs.getAbsoluteFile() + " not found");
+		}
+	}
+
+	private SessionFactory saveAndLoad(String prefix, String[] files, String cfgName) throws IOException, FileNotFoundException, ClassNotFoundException {
+		long start = System.currentTimeMillis();
+		
+		Configuration cfg = new Configuration();
+		System.err.println("Created configuration: " + (System.currentTimeMillis() - start) / 1000.0 + " sec.");
+		
+		System.err.println("saveAndLoad from " + prefix + " with cfg = " + cfgName);
+		if(!new File(cfgName).exists()) {
+			start = System.currentTimeMillis();
+			/*for (int i=0; i<files.length; i++) {
+			 if ( !files[i].startsWith("net/") ) files[i] = "test/org/hibernate/test/" + files[i];
+			 cfg.addFile(files[i]);
+			 //cfg.addLazyFile(files[i]);
+			  }*/
+			
+			for (int i = 0; i < files.length; i++) {
+				String file = files[i];
+				cfg.addCacheableFile(new File(prefix + file));
+			}
+			
+			System.err.println("Added " + (files.length) + " resources: " + (System.currentTimeMillis() - start) / 1000.0 + " sec.");
+			
+			ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(cfgName));
+			os.writeObject(cfg); // need to serialize Configuration *before* building sf since it would require non-mappings and cfg types to be serializable
+			os.flush();
+			os.close();
+			
+		} else {
+			start = System.currentTimeMillis();
+			ObjectInputStream is = new ObjectInputStream(new FileInputStream(cfgName));
+			cfg = (Configuration) is.readObject();
+			is.close();
+			System.err.println("Loaded serializable configuration:" + (System.currentTimeMillis() - start) / 1000.0 + " sec.");
+		}
+		start = System.currentTimeMillis();
+		System.err.println("Start build of session factory");
+		SessionFactory factory = cfg.buildSessionFactory();
+		System.err.println("Build session factory:" + (System.currentTimeMillis() - start) / 1000.0 + " sec.");
+		return factory;
+	}
+
+
+	public static Test suite() {
+		return new TestSuite(ConfigurationPerformanceTest.class);
+	}
+
+	public static void main(String[] args) throws Exception {
+		TestRunner.run( suite() );
+	}
+	
+	public void generateTestFiles(File basedir, String pkgName) throws IOException {
+		
+		for(int count=0;count<100;count++) {
+			String name = "Test" + count;
+			File javaFile = new File(new File(basedir, pkgName), name + ".java");
+			File hbmFile = new File(new File(basedir, pkgName), name + ".hbm.xml");
+			
+			javaFile.getParentFile().mkdirs();
+			hbmFile.getParentFile().mkdirs();
+			
+			System.out.println("Generating " + javaFile.getAbsolutePath());
+			PrintWriter javaWriter = null;
+			PrintWriter hbmWriter = null;
+			try {
+				javaWriter = new PrintWriter(new FileWriter(javaFile));
+				hbmWriter = new PrintWriter(new FileWriter(hbmFile));
+				
+				javaWriter.println("package " + pkgName + ";");
+				hbmWriter.println("<?xml version=\"1.0\"?>\r\n" + 
+						"<!DOCTYPE hibernate-mapping PUBLIC \r\n" + 
+						"	\"-//Hibernate/Hibernate Mapping DTD 3.0//EN\"\r\n" + 
+				"	\"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd\">\r\n");
+				
+				hbmWriter.println("<hibernate-mapping package=\"" + pkgName + "\">");
+				
+				javaWriter.println("public class " + name + " {");
+				javaWriter.println(" static { System.out.println(\"" + name + " initialized!\"); }");
+				hbmWriter.println("<class name=\"" + name + "\">");
+				
+				hbmWriter.println("<id type=\"long\"><generator class=\"assigned\"/></id>");
+				for(int propCount=0;propCount<100;propCount++) {
+					String propName = "Prop" + propCount;
+					
+					writeJavaProperty(javaWriter, propName);
+					
+					hbmWriter.println("<property name=\"" + propName + "\" type=\"string\"/>");
+					
+				}
+				hbmWriter.println("</class>");
+				javaWriter.println("}");
+				hbmWriter.println("</hibernate-mapping>");
+			} finally {
+				if(javaWriter!=null) {
+					javaWriter.flush();
+					javaWriter.close();
+				} 
+				if(hbmWriter!=null) {
+					hbmWriter.flush();
+					hbmWriter.close();
+				}
+			}		
+		}
+		
+	}
+
+
+	private void writeJavaProperty(PrintWriter javaWriter, String propName) {
+		javaWriter.println(" String " + propName + ";");
+		javaWriter.println(" String get" + propName + "() { return " + propName + "; }");
+		javaWriter.println(" void set" + propName + "(String newVal) { " + propName + "=newVal; }");
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Contained.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Contained.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Contained.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,90 @@
+//$Id: Contained.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class Contained {
+	private Container container;
+	private long id;
+	private Collection bag = new ArrayList();
+	private Collection lazyBag = new ArrayList();
+	
+	public boolean equals(Object other) {
+		return id==( (Contained) other ).getId();
+	}
+	public int hashCode() {
+		return new Long(id).hashCode();
+	}
+	
+	/**
+	 * Returns the container.
+	 * @return Container
+	 */
+	public Container getContainer() {
+		return container;
+	}
+	
+	/**
+	 * Returns the id.
+	 * @return long
+	 */
+	public long getId() {
+		return id;
+	}
+	
+	/**
+	 * Sets the container.
+	 * @param container The container to set
+	 */
+	public void setContainer(Container container) {
+		this.container = container;
+	}
+	
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	
+	/**
+	 * Returns the bag.
+	 * @return Collection
+	 */
+	public Collection getBag() {
+		return bag;
+	}
+	
+	/**
+	 * Sets the bag.
+	 * @param bag The bag to set
+	 */
+	public void setBag(Collection bag) {
+		this.bag = bag;
+	}
+	
+	/**
+	 * Returns the lazyBag.
+	 * @return Collection
+	 */
+	public Collection getLazyBag() {
+		return lazyBag;
+	}
+	
+	/**
+	 * Sets the lazyBag.
+	 * @param lazyBag The lazyBag to set
+	 */
+	public void setLazyBag(Collection lazyBag) {
+		this.lazyBag = lazyBag;
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Container.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Container.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Container.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,98 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping default-lazy="false" auto-import="false">
+
+	<import class="org.hibernate.test.legacy.Container" rename="ContainerX"/>
+	<import class="org.hibernate.test.legacy.Contained"/>
+	<import class="java.lang.Object" rename="Universe"/>
+
+	<class name="org.hibernate.test.legacy.Container" proxy="org.hibernate.test.legacy.Container">
+		<id name="id" column="container_id" unsaved-value="0">
+			<generator class="native" />
+		</id>
+		<list name="oneToMany" lazy="true">
+			<key column = "container_id1"/>
+			<index column = "list_index"/>
+			<one-to-many class="org.hibernate.test.legacy.Simple"/>
+		</list>
+		<list name="manyToMany" lazy="true">
+			<key column = "container_id2"/>
+			<index column = "list_index"/>
+			<many-to-many class="org.hibernate.test.legacy.Simple"/>
+		</list>
+		<list name="components" lazy="true">
+			<key column = "container_id"/>
+			<index column = "list_index"/>
+			<composite-element class="org.hibernate.test.legacy.Container$ContainerInnerClass">
+				<property name="name"/>
+				<property name="count" column="count_"/>
+				<many-to-one name="simple"/>
+				<many-to-one name="one"/>
+				<many-to-one name="many"/>
+			</composite-element>
+		</list>
+		<set name="composites" lazy="true">
+			<key column = "container_id"/>
+			<composite-element class="org.hibernate.test.legacy.Container$ContainerInnerClass">
+				<property name="name"/>
+				<many-to-one name="simple"/>
+				<many-to-one name="one"/>
+				<many-to-one name="many"/>
+			</composite-element>
+		</set>
+		<bag name="cascades" cascade="all" table="abcd">
+			<key column="container_id"/>
+			<composite-element class="org.hibernate.test.legacy.Container$ContainerInnerClass">
+				<property name="name"/>
+				<many-to-one name="simple" cascade="all"/>
+				<many-to-one name="one" cascade="all" not-null="true"/>
+				<many-to-one name="many" cascade="all" not-null="true"/>
+			</composite-element>
+		</bag>
+		<bag name="bag" inverse="true" cascade="save-update" table="CCBAG">
+			<key column="container_id"/>
+			<many-to-many column="contained_id" class="org.hibernate.test.legacy.Contained" outer-join="true"/>
+		</bag>
+		<bag name="lazyBag" inverse="true" lazy="true" table="LCCBAG" cascade="save-update">
+			<!--cache usage="read-write"-->
+			<key column="container_id"/>
+			<many-to-many column="contained_id" class="org.hibernate.test.legacy.Contained"/>
+		</bag>
+		<map name="ternaryMap">
+			<key column="container_id"/>
+			<index column="idx" type="string" length="32"/>
+			<composite-element class="org.hibernate.test.legacy.Container$Ternary">
+				<property name="name"/>
+				<many-to-one name="foo"/>
+				<many-to-one name="glarch"/>
+			</composite-element>
+		</map>
+		<set name="ternarySet">
+			<key column="container_id"/>
+			<composite-element class="org.hibernate.test.legacy.Container$Ternary">
+				<property name="name" not-null="true"/>
+				<many-to-one name="foo" not-null="true"/>
+				<many-to-one name="glarch" not-null="true"/>
+			</composite-element>
+		</set>
+	</class>
+	
+	<class name="org.hibernate.test.legacy.Contained" proxy="org.hibernate.test.legacy.Contained">
+		<id name="id" column="container_id" unsaved-value="0">
+			<generator class="native" />
+		</id>
+		<bag name="bag" table="CCBAG">
+			<key column="contained_id"/>
+			<many-to-many column="container_id" class="org.hibernate.test.legacy.Container" outer-join="false"/>
+		</bag>
+		<bag name="lazyBag" lazy="true" table="LCCBAG">
+			<key column="contained_id"/>
+			<many-to-many column="container_id" class="org.hibernate.test.legacy.Container"/>
+		</bag>
+	</class>
+	
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Container.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Container.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Container.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,351 @@
+//$Id: Container.java 6844 2005-05-21 14:22:16Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class Container {
+	
+	public static final class ContainerInnerClass {
+		private Simple simple;
+		private String name;
+		private One one;
+		private Many many;
+		private int count;
+		
+		public void setSimple(Simple simple) {
+			this.simple = simple;
+		}
+		
+		public Simple getSimple() {
+			return simple;
+		}
+		/**
+		 * Returns the name.
+		 * @return String
+		 */
+		public String getName() {
+			return name;
+		}
+		
+		/**
+		 * Sets the name.
+		 * @param name The name to set
+		 */
+		public void setName(String name) {
+			this.name = name;
+		}
+		
+		public String toString() {
+			return name + " = " 
+			+ (simple==null ? "nil" : Integer.toString( simple.getCount() ) )
+			+ "/" + ( one==null ? "nil" : one.getKey().toString() )
+			+ "/" + ( many==null ? "nil" : many.getKey().toString() );
+		}
+		
+		
+		/**
+		 * Returns the one.
+		 * @return One
+		 */
+		public One getOne() {
+			return one;
+		}
+		
+		/**
+		 * Sets the one.
+		 * @param one The one to set
+		 */
+		public void setOne(One one) {
+			this.one = one;
+		}
+		
+		/**
+		 * Returns the many.
+		 * @return Many
+		 */
+		public Many getMany() {
+			return many;
+		}
+		
+		/**
+		 * Sets the many.
+		 * @param many The many to set
+		 */
+		public void setMany(Many many) {
+			this.many = many;
+		}
+		
+		/**
+		 * Returns the count.
+		 * @return int
+		 */
+		public int getCount() {
+			return count;
+		}
+
+		/**
+		 * Sets the count.
+		 * @param count The count to set
+		 */
+		public void setCount(int count) {
+			this.count = count;
+		}
+		
+		public int hashCode() {
+			return count + name.hashCode();
+		}
+		
+		public boolean equals(Object other) {
+			ContainerInnerClass cic = (ContainerInnerClass) other;
+			return cic.name.equals(name) 
+				&& cic.count==count 
+				&& cic.one.getKey().equals(one.getKey())
+				&& cic.many.getKey().equals(many.getKey())
+				&& cic.simple.getCount()==simple.getCount();
+		}
+
+	}
+	
+	private List oneToMany;
+	private List manyToMany;
+	private List components;
+	private Set composites;
+	private Collection cascades;
+	private long id;
+	private Collection bag;
+	private Collection lazyBag = new ArrayList();
+	private Map ternaryMap;
+	private Set ternarySet;
+	
+	/**
+	 * Constructor for Container.
+	 */
+	public Container() {
+		super();
+	}
+	
+	/**
+	 * Returns the components.
+	 * @return List
+	 */
+	public List getComponents() {
+		return components;
+	}
+	
+	/**
+	 * Returns the manyToMany.
+	 * @return List
+	 */
+	public List getManyToMany() {
+		return manyToMany;
+	}
+	
+	/**
+	 * Returns the oneToMany.
+	 * @return List
+	 */
+	public List getOneToMany() {
+		return oneToMany;
+	}
+	
+	/**
+	 * Sets the components.
+	 * @param components The components to set
+	 */
+	public void setComponents(List components) {
+		this.components = components;
+	}
+	
+	/**
+	 * Sets the manyToMany.
+	 * @param manyToMany The manyToMany to set
+	 */
+	public void setManyToMany(List manyToMany) {
+		this.manyToMany = manyToMany;
+	}
+	
+	/**
+	 * Sets the oneToMany.
+	 * @param oneToMany The oneToMany to set
+	 */
+	public void setOneToMany(List oneToMany) {
+		this.oneToMany = oneToMany;
+	}
+	
+	/**
+	 * Returns the id.
+	 * @return long
+	 */
+	public long getId() {
+		return id;
+	}
+	
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	
+	/**
+	 * Gets the composites.
+	 * @return Returns a Set
+	 */
+	public Set getComposites() {
+		return composites;
+	}
+	
+	/**
+	 * Sets the composites.
+	 * @param composites The composites to set
+	 */
+	public void setComposites(Set composites) {
+		this.composites = composites;
+	}
+	
+	/**
+	 * Returns the bag.
+	 * @return Collection
+	 */
+	public Collection getBag() {
+		return bag;
+	}
+	
+	/**
+	 * Sets the bag.
+	 * @param bag The bag to set
+	 */
+	public void setBag(Collection bag) {
+		this.bag = bag;
+	}
+	
+	/**
+	 * Returns the ternary.
+	 * @return Map
+	 */
+	public Map getTernaryMap() {
+		return ternaryMap;
+	}
+	
+	/**
+	 * Sets the ternary.
+	 * @param ternary The ternary to set
+	 */
+	public void setTernaryMap(Map ternary) {
+		this.ternaryMap = ternary;
+	}
+	
+	public static final class Ternary {
+		private String name;
+		private Foo foo;
+		private Glarch glarch;
+		/**
+		 * Returns the foo.
+		 * @return Foo
+		 */
+		public Foo getFoo() {
+			return foo;
+		}
+		
+		/**
+		 * Returns the glarch.
+		 * @return Glarch
+		 */
+		public Glarch getGlarch() {
+			return glarch;
+		}
+		
+		/**
+		 * Returns the name.
+		 * @return String
+		 */
+		public String getName() {
+			return name;
+		}
+		
+		/**
+		 * Sets the foo.
+		 * @param foo The foo to set
+		 */
+		public void setFoo(Foo foo) {
+			this.foo = foo;
+		}
+		
+		/**
+		 * Sets the glarch.
+		 * @param glarch The glarch to set
+		 */
+		public void setGlarch(Glarch glarch) {
+			this.glarch = glarch;
+		}
+		
+		/**
+		 * Sets the name.
+		 * @param name The name to set
+		 */
+		public void setName(String name) {
+			this.name = name;
+		}
+		
+	}
+	
+	/**
+	 * Returns the ternarySet.
+	 * @return Set
+	 */
+	public Set getTernarySet() {
+		return ternarySet;
+	}
+	
+	/**
+	 * Sets the ternarySet.
+	 * @param ternarySet The ternarySet to set
+	 */
+	public void setTernarySet(Set ternarySet) {
+		this.ternarySet = ternarySet;
+	}
+	
+	/**
+	 * Returns the lazyBag.
+	 * @return Collection
+	 */
+	public Collection getLazyBag() {
+		return lazyBag;
+	}
+	
+	/**
+	 * Sets the lazyBag.
+	 * @param lazyBag The lazyBag to set
+	 */
+	public void setLazyBag(Collection lazyBag) {
+		this.lazyBag = lazyBag;
+	}
+	
+	/**
+	 * Returns the cascades.
+	 * @return Collection
+	 */
+	public Collection getCascades() {
+		return cascades;
+	}
+
+	/**
+	 * Sets the cascades.
+	 * @param cascades The cascades to set
+	 */
+	public void setCascades(Collection cascades) {
+		this.cascades = cascades;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Custom.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Custom.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Custom.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+    <class name="org.hibernate.test.legacy.Custom" persister="org.hibernate.test.legacy.CustomPersister">
+        <id type="string" name="id" column="id_" length="64" unsaved-value="null">
+            <generator class="uuid.hex"/>
+        </id>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Custom.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Custom.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Custom.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+//$Id: Custom.java 7275 2005-06-22 18:58:16Z oneovthafew $
+package org.hibernate.test.legacy;
+
+
+public class Custom implements Cloneable {
+	String id;
+	private String name;
+	
+	public Object clone() {
+		try {
+			return super.clone();
+		}
+		catch (CloneNotSupportedException cnse) {
+			throw new RuntimeException();
+		}
+	}
+
+	void setName(String name) {
+		this.name = name;
+	}
+
+	String getName() {
+		return name;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CustomPersister.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CustomPersister.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CustomPersister.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,618 @@
+//$Id: CustomPersister.java 11398 2007-04-10 14:54:07Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Comparator;
+
+import org.hibernate.EntityMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.tuple.entity.EntityMetamodel;
+import org.hibernate.cache.CacheConcurrencyStrategy;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cache.entry.CacheEntryStructure;
+import org.hibernate.cache.entry.UnstructuredCacheEntry;
+import org.hibernate.engine.CascadeStyle;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.TwoPhaseLoad;
+import org.hibernate.engine.ValueInclusion;
+import org.hibernate.event.EventSource;
+import org.hibernate.event.PostLoadEvent;
+import org.hibernate.event.PreLoadEvent;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.id.UUIDHexGenerator;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.metadata.ClassMetadata;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.sql.QuerySelect;
+import org.hibernate.sql.Select;
+import org.hibernate.type.Type;
+import org.hibernate.type.VersionType;
+import org.hibernate.util.EqualsHelper;
+
+public class CustomPersister implements EntityPersister {
+
+	private static final Hashtable INSTANCES = new Hashtable();
+	private static final IdentifierGenerator GENERATOR = new UUIDHexGenerator();
+	
+	private SessionFactoryImplementor factory;
+
+	public CustomPersister(
+			PersistentClass model, 
+			EntityRegionAccessStrategy cacheAccessStrategy,
+			SessionFactoryImplementor factory, 
+			Mapping mapping) {
+		this.factory = factory;
+	}
+
+	public boolean hasLazyProperties() {
+		return false;
+	}
+
+	private void checkEntityMode(EntityMode entityMode) {
+		if ( EntityMode.POJO != entityMode ) {
+			throw new IllegalArgumentException( "Unhandled EntityMode : " + entityMode );
+		}
+	}
+
+	public boolean isInherited() {
+		return false;
+	}
+	
+	public SessionFactoryImplementor getFactory() {
+		return factory;
+	}
+
+	public Class getMappedClass() {
+		return Custom.class;
+	}
+
+	public void postInstantiate() throws MappingException {}
+
+	public String getEntityName() {
+		return Custom.class.getName();
+	}
+
+	public boolean isSubclassEntityName(String entityName) {
+		return Custom.class.getName().equals(entityName);
+	}
+
+	public boolean hasProxy() {
+		return false;
+	}
+
+	public boolean hasCollections() {
+		return false;
+	}
+
+	public boolean hasCascades() {
+		return false;
+	}
+
+	public boolean isMutable() {
+		return true;
+	}
+	
+	public boolean isSelectBeforeUpdateRequired() {
+		return false;
+	}
+
+	public boolean isIdentifierAssignedByInsert() {
+		return false;
+	}
+
+	public Boolean isTransient(Object object, SessionImplementor session) {
+		return new Boolean( ( (Custom) object ).id==null );
+	}
+
+	public Object[] getPropertyValuesToInsert(Object object, Map mergeMap, SessionImplementor session)
+	throws HibernateException {
+		return getPropertyValues( object, session.getEntityMode() );
+	}
+
+	public void processInsertGeneratedProperties(Serializable id, Object entity, Object[] state, SessionImplementor session) {
+	}
+
+	public void processUpdateGeneratedProperties(Serializable id, Object entity, Object[] state, SessionImplementor session) {
+	}
+
+	public void retrieveGeneratedProperties(Serializable id, Object entity, Object[] state, SessionImplementor session) {
+		throw new UnsupportedOperationException();
+	}
+
+	public Class getMappedClass(EntityMode entityMode) {
+		checkEntityMode( entityMode );
+		return Custom.class;
+	}
+
+	public boolean implementsLifecycle(EntityMode entityMode) {
+		checkEntityMode( entityMode );
+		return false;
+	}
+
+	public boolean implementsValidatable(EntityMode entityMode) {
+		checkEntityMode( entityMode );
+		return false;
+	}
+
+	public Class getConcreteProxyClass(EntityMode entityMode) {
+		checkEntityMode( entityMode );
+		return Custom.class;
+	}
+
+	public void setPropertyValues(Object object, Object[] values, EntityMode entityMode) throws HibernateException {
+		checkEntityMode( entityMode );
+		setPropertyValue( object, 0, values[0], entityMode );
+	}
+
+	public void setPropertyValue(Object object, int i, Object value, EntityMode entityMode) throws HibernateException {
+		checkEntityMode( entityMode );
+		( (Custom) object ).setName( (String) value );
+	}
+
+	public Object[] getPropertyValues(Object object, EntityMode entityMode) throws HibernateException {
+		checkEntityMode( entityMode );
+		Custom c = (Custom) object;
+		return new Object[] { c.getName() };
+	}
+
+	public Object getPropertyValue(Object object, int i, EntityMode entityMode) throws HibernateException {
+		checkEntityMode( entityMode );
+		return ( (Custom) object ).getName();
+	}
+
+	public Object getPropertyValue(Object object, String propertyName, EntityMode entityMode) throws HibernateException {
+		checkEntityMode( entityMode );
+		return ( (Custom) object ).getName();
+	}
+
+	public Serializable getIdentifier(Object object, EntityMode entityMode) throws HibernateException {
+		checkEntityMode( entityMode );
+		return ( (Custom) object ).id;
+	}
+
+	public void setIdentifier(Object object, Serializable id, EntityMode entityMode) throws HibernateException {
+		checkEntityMode( entityMode );
+		( (Custom) object ).id = (String) id;
+	}
+
+	public Object getVersion(Object object, EntityMode entityMode) throws HibernateException {
+		checkEntityMode( entityMode );
+		return null;
+	}
+
+	public Object instantiate(Serializable id, EntityMode entityMode) throws HibernateException {
+		checkEntityMode( entityMode );
+		Custom c = new Custom();
+		c.id = (String) id;
+		return c;
+	}
+
+	public boolean isInstance(Object object, EntityMode entityMode) {
+		checkEntityMode( entityMode );
+		return object instanceof Custom;
+	}
+
+	public boolean hasUninitializedLazyProperties(Object object, EntityMode entityMode) {
+		checkEntityMode( entityMode );
+		return false;
+	}
+
+	public void resetIdentifier(Object entity, Serializable currentId, Object currentVersion, EntityMode entityMode) {
+		checkEntityMode( entityMode );
+		( ( Custom ) entity ).id = ( String ) currentId;
+	}
+
+	public EntityPersister getSubclassEntityPersister(Object instance, SessionFactoryImplementor factory, EntityMode entityMode) {
+		checkEntityMode( entityMode );
+		return this;
+	}
+
+	public int[] findDirty(
+		Object[] x,
+		Object[] y,
+		Object owner,
+		SessionImplementor session
+	) throws HibernateException {
+		if ( !EqualsHelper.equals( x[0], y[0] ) ) {
+			return new int[] { 0 };
+		}
+		else {
+			return null;
+		}
+	}
+
+	public int[] findModified(
+		Object[] x,
+		Object[] y,
+		Object owner,
+		SessionImplementor session
+	) throws HibernateException {
+		if ( !EqualsHelper.equals( x[0], y[0] ) ) {
+			return new int[] { 0 };
+		}
+		else {
+			return null;
+		}
+	}
+
+	/**
+	 * @see EntityPersister#hasIdentifierProperty()
+	 */
+	public boolean hasIdentifierProperty() {
+		return true;
+	}
+
+	/**
+	 * @see EntityPersister#isVersioned()
+	 */
+	public boolean isVersioned() {
+		return false;
+	}
+
+	/**
+	 * @see EntityPersister#getVersionType()
+	 */
+	public VersionType getVersionType() {
+		return null;
+	}
+
+	/**
+	 * @see EntityPersister#getVersionProperty()
+	 */
+	public int getVersionProperty() {
+		return 0;
+	}
+
+	/**
+	 * @see EntityPersister#getIdentifierGenerator()
+	 */
+	public IdentifierGenerator getIdentifierGenerator()
+	throws HibernateException {
+		return GENERATOR;
+	}
+
+	/**
+	 * @see EntityPersister#load(Serializable, Object, LockMode, SessionImplementor)
+	 */
+	public Object load(
+		Serializable id,
+		Object optionalObject,
+		LockMode lockMode,
+		SessionImplementor session
+	) throws HibernateException {
+
+		// fails when optional object is supplied
+
+		Custom clone = null;
+		Custom obj = (Custom) INSTANCES.get(id);
+		if (obj!=null) {
+			clone = (Custom) obj.clone();
+			TwoPhaseLoad.addUninitializedEntity( 
+					new EntityKey( id, this, session.getEntityMode() ), 
+					clone, 
+					this, 
+					LockMode.NONE, 
+					false,
+					session
+				);
+			TwoPhaseLoad.postHydrate(
+					this, id, 
+					new String[] { obj.getName() }, 
+					null, 
+					clone, 
+					LockMode.NONE, 
+					false, 
+					session
+				);
+			TwoPhaseLoad.initializeEntity( 
+					clone, 
+					false, 
+					session, 
+					new PreLoadEvent( (EventSource) session ), 
+					new PostLoadEvent( (EventSource) session ) 
+				);
+		}
+		return clone;
+	}
+
+	/**
+	 * @see EntityPersister#lock(Serializable, Object, Object, LockMode, SessionImplementor)
+	 */
+	public void lock(
+		Serializable id,
+		Object version,
+		Object object,
+		LockMode lockMode,
+		SessionImplementor session
+	) throws HibernateException {
+
+		throw new UnsupportedOperationException();
+	}
+
+	public void insert(
+		Serializable id,
+		Object[] fields,
+		Object object,
+		SessionImplementor session
+	) throws HibernateException {
+
+		INSTANCES.put(id, ( (Custom) object ).clone() );
+	}
+
+	public Serializable insert(Object[] fields, Object object, SessionImplementor session)
+	throws HibernateException {
+
+		throw new UnsupportedOperationException();
+	}
+
+	public void delete(
+		Serializable id,
+		Object version,
+		Object object,
+		SessionImplementor session
+	) throws HibernateException {
+
+		INSTANCES.remove(id);
+	}
+
+	/**
+	 * @see EntityPersister
+	 */
+	public void update(
+		Serializable id,
+		Object[] fields,
+		int[] dirtyFields,
+		boolean hasDirtyCollection,
+		Object[] oldFields,
+		Object oldVersion,
+		Object object,
+		Object rowId,
+		SessionImplementor session
+	) throws HibernateException {
+
+		INSTANCES.put( id, ( (Custom) object ).clone() );
+
+	}
+
+	private static final Type[] TYPES = new Type[] { Hibernate.STRING };
+	private static final String[] NAMES = new String[] { "name" };
+	private static final boolean[] MUTABILITY = new boolean[] { true };
+	private static final boolean[] GENERATION = new boolean[] { false };
+
+	/**
+	 * @see EntityPersister#getPropertyTypes()
+	 */
+	public Type[] getPropertyTypes() {
+		return TYPES;
+	}
+
+	/**
+	 * @see EntityPersister#getPropertyNames()
+	 */
+	public String[] getPropertyNames() {
+		return NAMES;
+	}
+
+	/**
+	 * @see EntityPersister#getPropertyCascadeStyles()
+	 */
+	public CascadeStyle[] getPropertyCascadeStyles() {
+		return null;
+	}
+
+	/**
+	 * @see EntityPersister#getIdentifierType()
+	 */
+	public Type getIdentifierType() {
+		return Hibernate.STRING;
+	}
+
+	/**
+	 * @see EntityPersister#getIdentifierPropertyName()
+	 */
+	public String getIdentifierPropertyName() {
+		return "id";
+	}
+
+	public boolean hasCache() {
+		return false;
+	}
+
+	public EntityRegionAccessStrategy getCacheAccessStrategy() {
+		return null;
+	}
+
+	public String getRootEntityName() {
+		return "CUSTOMS";
+	}
+
+	public Serializable[] getPropertySpaces() {
+		return new String[] { "CUSTOMS" };
+	}
+
+	public Serializable[] getQuerySpaces() {
+		return new String[] { "CUSTOMS" };
+	}
+
+	/**
+	 * @see EntityPersister#getClassMetadata()
+	 */
+	public ClassMetadata getClassMetadata() {
+		return null;
+	}
+
+	public boolean[] getPropertyUpdateability() {
+		return MUTABILITY;
+	}
+
+	public boolean[] getPropertyCheckability() {
+		return MUTABILITY;
+	}
+
+	/**
+	 * @see EntityPersister#getPropertyInsertability()
+	 */
+	public boolean[] getPropertyInsertability() {
+		return MUTABILITY;
+	}
+
+	public ValueInclusion[] getPropertyInsertGenerationInclusions() {
+		return new ValueInclusion[0];
+	}
+
+	public ValueInclusion[] getPropertyUpdateGenerationInclusions() {
+		return new ValueInclusion[0];
+	}
+
+
+	public boolean canExtractIdOutOfEntity() {
+		return true;
+	}
+
+	public boolean isBatchLoadable() {
+		return false;
+	}
+
+	public Type getPropertyType(String propertyName) {
+		throw new UnsupportedOperationException();
+	}
+
+	public Object getPropertyValue(Object object, String propertyName)
+		throws HibernateException {
+		throw new UnsupportedOperationException();
+	}
+
+	public Object createProxy(Serializable id, SessionImplementor session)
+		throws HibernateException {
+		throw new UnsupportedOperationException("no proxy for this class");
+	}
+
+	public Object getCurrentVersion(
+		Serializable id,
+		SessionImplementor session)
+		throws HibernateException {
+
+		return INSTANCES.get(id);
+	}
+
+	public Object forceVersionIncrement(Serializable id, Object currentVersion, SessionImplementor session)
+			throws HibernateException {
+		return null;
+	}
+
+	public EntityMode guessEntityMode(Object object) {
+		if ( !isInstance(object, EntityMode.POJO) ) {
+			return null;
+		}
+		else {
+			return EntityMode.POJO;
+		}
+	}
+
+	public boolean[] getPropertyNullability() {
+		return MUTABILITY;
+	}
+
+	public boolean isDynamic() {
+		return false;
+	}
+
+	public boolean isCacheInvalidationRequired() {
+		return false;
+	}
+
+	public void applyFilters(QuerySelect select, String alias, Map filters) {
+	}
+
+	public void applyFilters(Select select, String alias, Map filters) {
+	}
+	
+	
+	public void afterInitialize(Object entity, boolean fetched, SessionImplementor session) {
+	}
+
+	public void afterReassociate(Object entity, SessionImplementor session) {
+	}
+
+	public Object[] getDatabaseSnapshot(Serializable id, SessionImplementor session) 
+	throws HibernateException {
+		return null;
+	}
+	
+	public boolean[] getPropertyVersionability() {
+		return MUTABILITY;
+	}
+
+	public CacheEntryStructure getCacheEntryStructure() {
+		return new UnstructuredCacheEntry();
+	}
+
+	public boolean hasSubselectLoadableCollections() {
+		return false;
+	}
+
+	public int[] getNaturalIdentifierProperties() {
+		return null;
+	}
+
+	public Type[] getNaturalIdentifierTypes() {
+		return null;
+	}
+
+	public boolean hasNaturalIdentifier() {
+		return false;
+	}
+
+	public boolean hasMutableProperties() {
+		return false;
+	}
+
+	public boolean isInstrumented(EntityMode entityMode) {
+		return false;
+	}
+
+	public boolean hasInsertGeneratedProperties() {
+		return false;
+	}
+
+	public boolean hasUpdateGeneratedProperties() {
+		return false;
+	}
+
+	public boolean[] getPropertyLaziness() {
+		return null;
+	}
+
+	public boolean isLazyPropertiesCacheable() {
+		return true;
+	}
+
+	public boolean hasGeneratedProperties() {
+		return false;
+	}
+
+	public boolean isVersionPropertyGenerated() {
+		return false;
+	}
+
+	public Object[] getNaturalIdentifierSnapshot(Serializable id, SessionImplementor session) throws HibernateException {
+		return null;
+	}
+
+	public Comparator getVersionComparator() {
+		return null;
+	}
+
+	public EntityMetamodel getEntityMetamodel() {
+		return null;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CustomSQL.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CustomSQL.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CustomSQL.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,104 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false" package="org.hibernate.test.legacy">
+	<class name="Role">
+
+		<id name="id" type="long">
+			<generator class="native"/>
+		</id>
+		
+		<property name="name" type="string"/>
+		
+		<set name="interventions" lazy="true" cascade="all">
+			<key column="role_id"/>
+			<one-to-many class="Intervention"/>
+			<sql-insert callable="false">/* max comment */
+				update Intervention set role_id=? where id=?</sql-insert>
+			<sql-delete callable="false">update Intervention set role_id=null where role_id=? and id=?</sql-delete>
+			<sql-delete-all callable="false">update Intervention set role_id=null where role_id=?</sql-delete-all>
+		</set>
+		
+		<list name="bunchOfStrings">			
+			<key column="GROUPID"/>
+			<index column="posn"/>
+		    <element column="NAME" type="string"/>
+			<sql-insert callable="true">{ ? = call createRoleBunchOfStrings(?, ?, ?)}</sql-insert>
+			<sql-update callable="true">{ ? = call updateRoleBunchOfStrings(?, ?, ?)}</sql-update>
+			<sql-delete callable="true">{ ? = call deleteRoleBunchOfString(?, ?)}</sql-delete>
+			<sql-delete-all callable="true">{ ? = call deleteAllRoleBunchOfString(?)}</sql-delete-all>
+		</list>
+		
+<!--		<sql-load   callable="true">{ call loadPatient (?)}</sql-load>
+		<sql-insert callable="true">{call createPatient (?, ?, ?, ?)}</sql-insert>
+		<sql-delete callable="true">{? = call deletePatient (?)}</sql-delete> 
+		<sql-update callable="true">{? = call updatePatient (?, ?, ?, ?)}</sql-update> -->
+<!--	<sql-insert callable="true">insert </sql-insert> -->
+<!--		<sql-delete>delete from Role where values (?, upper(?)) /** i did this */</sql-insert>   -->
+		<sql-insert>insert into Role (name, id) values (?, upper(?)) /** i did this */</sql-insert>  
+<!--		<sql-update>update</sql-update>-->
+		<sql-delete>delete from Role where id=?</sql-delete>
+		
+	</class>	
+	
+	<class name="Resource" table="ecruoser">
+		<id name="id" type="string">
+			<generator class="uuid.hex"/>
+		</id>
+		
+		<discriminator column="discriminator" type="string"/>
+		
+		<property name="name" type="string"/>
+		<property name="userCode" type="string"/>
+		
+		<subclass name="Drug">
+			
+		</subclass>
+	</class>
+	
+	<class name="Party">
+		<id name="id" type="string">
+			<generator class="uuid.hex"/>
+		</id>
+		<discriminator column="discriminator" type="string"/>
+		<join table="partyjointable">
+			<key column="partyid"/>
+     		<property name="name" column="xname" type="string"/>
+	    	<property name="address" type="string"/>
+			<sql-insert callable="true">{ call createJoinTable(?, ?, ?) }</sql-insert>			
+			<sql-update callable="true">{ ? = call updateJoinTable(?, ?, ?) }</sql-update> <!-- xname, address, partyid -->
+			<sql-delete callable="true">{ ? = call deleteJoinTable(?) }</sql-delete> <!-- partyid -->
+		</join>
+							
+		<subclass name="Person">
+			<property name="givenName" type="string"/>			
+			<property name="lastName" type="string"/>		
+			<property name="nationalID" unique="true" type="string"/>
+		</subclass>		
+
+		<subclass name="Company">
+		   <property name="president" type="string"/>
+		</subclass>				
+	</class>
+	
+	<class name="Intervention">
+		<id name="id" type="string">
+			<generator class="uuid.hex"/>
+		</id>
+		
+		<version name="version" type="long"/>
+		
+		<property name="description" type="string"/>
+		
+		<joined-subclass name="Medication">
+			<key column="interventionid"/>
+			<many-to-one name="prescribedDrug" class="org.hibernate.test.legacy.Drug"/>			
+			<sql-insert>insert into /** put weird comments here */ Medication (prescribedDrug, interventionid) values (?, ?)</sql-insert> 
+		</joined-subclass>
+		
+	</class>
+	
+	
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CustomSQLTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CustomSQLTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/CustomSQLTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,212 @@
+//$Id: CustomSQLTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.HibernateException;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.classic.Session;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.MySQLDialect;
+
+/**
+ * @author MAX
+ *
+ */
+public class CustomSQLTest extends LegacyTestCase {
+
+	public CustomSQLTest(String name) {
+		super(name);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "legacy/CustomSQL.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CustomSQLTest.class );
+	}
+
+	public void testInsert() throws HibernateException, SQLException {
+
+		if ( getDialect() instanceof HSQLDialect ) return;
+		if ( getDialect() instanceof MySQLDialect ) return;
+		
+		Role p = new Role();
+
+		p.setName("Patient");
+
+		Session s = openSession();
+
+		s.save(p);
+		s.flush();
+
+		s.connection().commit();
+		s.close();
+
+		getSessions().evict(Role.class);
+		s = openSession();
+
+		Role p2 = (Role) s.get(Role.class, new Long(p.getId()));
+		assertNotSame(p, p2);
+		assertEquals(p2.getId(),p.getId());
+		assertTrue(p2.getName().equalsIgnoreCase(p.getName()));
+		s.delete(p2);
+		s.flush();
+
+
+		s.connection().commit();
+		s.close();
+
+
+	}
+
+	public void testJoinedSubclass() throws HibernateException, SQLException {
+		Medication m = new Medication();
+
+		m.setPrescribedDrug(new Drug());
+
+		m.getPrescribedDrug().setName("Morphine");
+
+
+		Session s = openSession();
+
+		s.save(m.getPrescribedDrug());
+		s.save(m);
+
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+
+		Medication m2  = (Medication) s.get(Medication.class, m.getId());
+		assertNotSame(m, m2);
+
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testCollectionCUD() throws HibernateException, SQLException {
+		
+		if ( getDialect() instanceof HSQLDialect ) return;
+		if ( getDialect() instanceof MySQLDialect ) return;
+		
+		Role role = new Role();
+
+		role.setName("Jim Flanders");
+
+		Intervention iv = new Medication();
+		iv.setDescription("JF medical intervention");
+
+		role.getInterventions().add(iv);
+
+		List sx = new ArrayList();
+		sx.add("somewhere");
+		sx.add("somehow");
+		sx.add("whatever");
+		role.setBunchOfStrings(sx);
+
+		Session s = openSession();
+
+		s.save(role);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+
+		Role r = (Role) s.get(Role.class,new Long(role.getId()));
+		assertNotSame(role,r);
+
+		assertEquals(1,r.getInterventions().size());
+
+		assertEquals(3, r.getBunchOfStrings().size());
+
+		r.getBunchOfStrings().set(1, "replacement");
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+
+		r = (Role) s.get(Role.class,new Long(role.getId()));
+		assertNotSame(role,r);
+
+		assertEquals(r.getBunchOfStrings().get(1),"replacement");
+		assertEquals(3, r.getBunchOfStrings().size());
+
+		r.getBunchOfStrings().set(1, "replacement");
+
+		r.getBunchOfStrings().remove(1);
+		s.flush();
+
+		r.getBunchOfStrings().clear();
+		s.flush();
+
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testCRUD() throws HibernateException, SQLException {
+
+		if ( getDialect() instanceof HSQLDialect ) return;
+		if ( getDialect() instanceof MySQLDialect ) return;
+
+		Person p = new Person();
+
+		p.setName("Max");
+		p.setLastName("Andersen");
+		p.setNationalID("110974XYZÅ");
+		p.setAddress("P. P. Street 8");
+
+		Session s = openSession();
+
+		s.save(p);
+		s.flush();
+
+		s.connection().commit();
+		s.close();
+
+		getSessions().evict(Person.class);
+		s = openSession();
+
+		Person p2 = (Person) s.get(Person.class, p.getId());
+		assertNotSame(p, p2);
+		assertEquals(p2.getId(),p.getId());
+		assertEquals(p2.getLastName(),p.getLastName());
+		s.flush();
+
+		List list = s.find("select p from Party as p");
+		assertTrue(list.size() == 1);
+
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+
+		list = s.find("select p from Person as p where p.address = 'Lærkevænget 1'");
+		assertTrue(list.size() == 0);
+		p.setAddress("Lærkevænget 1");
+		s.update(p);
+		list = s.find("select p from Person as p where p.address = 'Lærkevænget 1'");
+		assertTrue(list.size() == 1);
+		list = s.find("select p from Party as p where p.address = 'P. P. Street 8'");
+		assertTrue(list.size() == 0);
+
+		s.delete(p);
+		list = s.find("select p from Person as p");
+		assertTrue(list.size() == 0);
+
+		s.connection().commit();
+		s.close();
+
+
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/D.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/D.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/D.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,61 @@
+//$Id: D.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+public class D {
+	private Long id;
+	private float amount;
+	private A reverse;
+	public A inverse;
+	
+	public D() {
+		// try to induce an infinite loop in the lazy-loading machinery
+		setAmount(100.0f);
+		getAmount();
+	}	
+	/**
+	 * Returns the amount.
+	 * @return float
+	 */
+	public float getAmount() {
+		return amount;
+	}
+	
+	/**
+	 * Returns the id.
+	 * @return long
+	 */
+	public Long getId() {
+		return id;
+	}
+	
+	/**
+	 * Sets the amount.
+	 * @param amount The amount to set
+	 */
+	public void setAmount(float amount) {
+		this.amount = amount;
+	}
+	
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	
+	public A getReverse() {
+		return reverse;
+	}
+
+	public void setReverse(A a) {
+		reverse = a;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Detail.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Detail.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Detail.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+//$Id: Detail.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+public class Detail implements Serializable {
+	
+	private Master master;
+	private int i;
+	private Set details = new HashSet();
+	private int x;
+	
+	public int getX() {
+		return x;
+	}
+	public void setX(int x) {
+		this.x = x;
+	}
+	
+	public Master getMaster() {
+		return master;
+	}
+	
+	public void setMaster(Master master) {
+		this.master = master;
+	}
+	
+	public int getI() {
+		return i;
+	}
+	
+	public void setI(int i) {
+		this.i = i;
+	}
+	
+	/**
+	 * Returns the details.
+	 * @return Set
+	 */
+	public Set getSubDetails() {
+		return details;
+	}
+	
+	/**
+	 * Sets the details.
+	 * @param details The details to set
+	 */
+	public void setSubDetails(Set details) {
+		this.details = details;
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/DoubleStringType.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/DoubleStringType.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/DoubleStringType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,112 @@
+//$Id: DoubleStringType.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+import org.hibernate.usertype.CompositeUserType;
+
+public class DoubleStringType implements CompositeUserType {
+
+	private static final int[] TYPES = { Types.VARCHAR, Types.VARCHAR };
+
+	public int[] sqlTypes() {
+		return TYPES;
+	}
+
+	public Class returnedClass() {
+		return String[].class;
+	}
+
+	public boolean equals(Object x, Object y) {
+		if (x==y) return true;
+		if (x==null || y==null) return false;
+		return ( (String[]) x )[0].equals( ( (String[]) y )[0] ) && ( (String[]) x )[1].equals( ( (String[]) y )[1] );
+	}
+
+	public int hashCode(Object x) throws HibernateException {
+		String[] a = (String[]) x;
+		return a[0].hashCode() + 31 * a[1].hashCode(); 
+	}
+
+	public Object deepCopy(Object x) {
+		if (x==null) return null;
+		String[] result = new String[2];
+		String[] input = (String[]) x;
+		result[0] = input[0];
+		result[1] = input[1];
+		return result;
+	}
+
+	public boolean isMutable() { return true; }
+
+	public Object nullSafeGet(ResultSet rs,	String[] names, SessionImplementor session,	Object owner)
+	throws HibernateException, SQLException {
+
+		String first = (String) Hibernate.STRING.nullSafeGet(rs, names[0]);
+		String second = (String) Hibernate.STRING.nullSafeGet(rs, names[1]);
+
+		return ( first==null && second==null ) ? null : new String[] { first, second };
+	}
+
+	public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session)
+	throws HibernateException, SQLException {
+
+		String[] strings = (value==null) ? new String[2] : (String[]) value;
+
+		Hibernate.STRING.nullSafeSet(st, strings[0], index);
+		Hibernate.STRING.nullSafeSet(st, strings[1], index+1);
+	}
+
+	public String[] getPropertyNames() {
+		return new String[] { "s1", "s2" };
+	}
+
+	public Type[] getPropertyTypes() {
+		return new Type[] { Hibernate.STRING, Hibernate.STRING };
+	}
+
+	public Object getPropertyValue(Object component, int property) {
+		return ( (String[]) component )[property];
+	}
+
+	public void setPropertyValue(
+		Object component,
+		int property,
+		Object value) {
+
+		( (String[]) component )[property] = (String) value;
+	}
+
+	public Object assemble(
+		Serializable cached,
+		SessionImplementor session,
+		Object owner) {
+
+		return deepCopy(cached);
+	}
+
+	public Serializable disassemble(Object value, SessionImplementor session) {
+		return (Serializable) deepCopy(value);
+	}
+	
+	public Object replace(Object original, Object target, SessionImplementor session, Object owner) 
+	throws HibernateException {
+		return original;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Down.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Down.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Down.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+//$Id: Down.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+
+/**
+ * @author Gavin King
+ */
+public class Down extends Up {
+
+	private long value;
+
+	public long getValue() {
+		return value;
+	}
+
+	public void setValue(long l) {
+		value = l;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Drug.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Drug.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Drug.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+package org.hibernate.test.legacy;
+
+/**
+ * @author hbm2java
+ */
+public class Drug extends org.hibernate.test.legacy.Resource {
+
+   java.lang.String id;
+
+
+  java.lang.String getId() {
+    return id;
+  }
+
+  void  setId(java.lang.String newValue) {
+    id = newValue;
+  }
+
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/E.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/E.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/E.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,71 @@
+//$Id: E.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.Set;
+
+public class E {
+	private Long id;
+	private float amount;
+	private A reverse;
+	private Set as;
+	/**
+	 * Returns the amount.
+	 * @return float
+	 */
+	public float getAmount() {
+		return amount;
+	}
+	
+	/**
+	 * Returns the id.
+	 * @return long
+	 */
+	public Long getId() {
+		return id;
+	}
+	
+	/**
+	 * Sets the amount.
+	 * @param amount The amount to set
+	 */
+	public void setAmount(float amount) {
+		this.amount = amount;
+	}
+	
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	
+	public A getReverse() {
+		return reverse;
+	}
+
+	public void setReverse(A a) {
+		reverse = a;
+	}
+
+	/**
+	 * @return Returns the as.
+	 */
+	public Set getAs() {
+		return as;
+	}
+
+	/**
+	 * @param as The as to set.
+	 */
+	public void setAs(Set as) {
+		this.as = as;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Eye.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Eye.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Eye.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false" 
+	default-cascade="save-update"
+	package="org.hibernate.test.legacy">
+	
+	<class name="Eye" lazy="true">
+		<id name="id" unsaved-value="0">
+			<generator class="hilo"/>
+		</id>
+		<property name="name"/>
+		<set name="jays" inverse="true" outer-join="true" cascade="all">
+			<key column="eye"/>
+			<one-to-many class="Jay"/>
+		</set>
+		<many-to-one name="jay" outer-join="true"/>
+	</class>
+	
+	<class name="Jay" lazy="true">
+		<id name="id" unsaved-value="0">
+			<generator class="hilo"/>
+		</id>
+		<many-to-one name="eye" outer-join="true"/>
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Eye.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Eye.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Eye.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,72 @@
+//$Id: Eye.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class Eye {
+	private long id;
+	private String name;
+	private Jay jay;
+	private Set jays = new HashSet();
+
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+
+	/**
+	 * @return Returns the jay.
+	 */
+	public Jay getJay() {
+		return jay;
+	}
+
+	/**
+	 * @param jay The jay to set.
+	 */
+	public void setJay(Jay jay) {
+		this.jay = jay;
+	}
+
+	/**
+	 * @return Returns the jays.
+	 */
+	public Set getJays() {
+		return jays;
+	}
+
+	/**
+	 * @param jays The jays to set.
+	 */
+	public void setJays(Set jays) {
+		this.jays = jays;
+	}
+
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fee.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fee.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fee.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+    <class name="org.hibernate.test.legacy.Fee" table="`the fees`">
+        <id type="string" name="key" column="id_" length="64" unsaved-value="null">
+            <generator class="uuid"/>
+        </id>
+        <property name="fi"/>
+        <many-to-one name="fee"/>
+        <many-to-one name="anotherFee"/>
+        <many-to-one name="qux" cascade="all"/>
+        <property name="count" column="count_"/>
+        <set name="fees">
+        	<key column="fee_id"/>
+        	<element column="str_" type="string" not-null="true"/>
+        </set>
+        <component name="compon" update="false">
+        	<property name="name"/>
+        	<property name="null" column="null_prop"/>
+        </component>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,98 @@
+//$Id: Fee.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.Set;
+
+public class Fee implements Serializable {
+	public Fee fee;
+	public Fee anotherFee;
+	public String fi;
+	public String key;
+	public Set fees;
+	private Qux qux;
+	private FooComponent compon;
+	private int count;
+	
+	public Fee() {
+	}
+	
+	public Fee getFee() {
+		return fee;
+	}
+	
+	public void setFee(Fee fee) {
+		this.fee = fee;
+	}
+	
+	public String getFi() {
+		return fi;
+	}
+	
+	public void setFi(String fi) {
+		this.fi = fi;
+	}
+	
+	public String getKey() {
+		return key;
+	}
+	
+	public void setKey(String key) {
+		this.key = key;
+	}
+	
+	public Set getFees() {
+		return fees;
+	}
+	
+	public void setFees(Set fees) {
+		this.fees = fees;
+	}
+	
+	public Fee getAnotherFee() {
+		return anotherFee;
+	}
+	
+	public void setAnotherFee(Fee anotherFee) {
+		this.anotherFee = anotherFee;
+	}
+	
+	public Qux getQux() {
+		return qux;
+	}
+	
+	public void setQux(Qux qux) {
+		this.qux = qux;
+	}
+	
+	public FooComponent getCompon() {
+		return compon;
+	}
+	
+	public void setCompon(FooComponent compon) {
+		this.compon = compon;
+	}
+	
+	/**
+	 * Returns the count.
+	 * @return int
+	 */
+	public int getCount() {
+		return count;
+	}
+
+	/**
+	 * Sets the count.
+	 * @param count The count to set
+	 */
+	public void setCount(int count) {
+		this.count = count;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fixed.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fixed.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fixed.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+//$Id: Fixed.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class Fixed extends Broken {
+	private Set set;
+	private List list = new ArrayList();
+
+	public Set getSet() {
+		return set;
+	}
+
+	public void setSet(Set set) {
+		this.set = set;
+	}
+
+	public List getList() {
+		return list;
+	}
+
+	public void setList(List list) {
+		this.list = list;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fo.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fo.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fo.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+	<class name="org.hibernate.test.legacy.Fo" table="foes">
+		<composite-id class="org.hibernate.test.legacy.FumCompositeID">
+			<key-property name="string">
+				<column name="string_" length="20"/>
+			</key-property>
+			<key-property name="short" column="short_"/>
+			<key-property name="date" column="date_" type="date"/>
+		</composite-id>
+		<version name="version" type="long"/>
+		<property name="serial" column="serial_"/>
+		<property name="buf"/>
+		<property name="x"/>
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fo.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fo.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fo.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+//$Id: Fo.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+public final class Fo {
+	
+	public static Fo newFo() {
+		return new Fo();
+	}
+	
+	private Fo() {}
+	
+	private byte[] buf;
+	private Serializable serial;
+	private long version;
+	private int x;
+	
+	public int getX() {
+		return x;
+	}
+	public void setX(int x) {
+		this.x = x;
+	}
+	
+	public byte[] getBuf() {
+		return buf;
+	}
+	
+	
+	public Serializable getSerial() {
+		return serial;
+	}
+	
+	
+	public void setBuf(byte[] buf) {
+		this.buf = buf;
+	}
+	
+	
+	public void setSerial(Serializable serial) {
+		this.serial = serial;
+	}
+	
+	public long getVersion() {
+		return version;
+	}
+	
+	public void setVersion(long version) {
+		this.version = version;
+	}
+	
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Foo.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Foo.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Foo.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,437 @@
+//$Id: Foo.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+import org.hibernate.CallbackException;
+import org.hibernate.Session;
+import org.hibernate.classic.Lifecycle;
+
+public class Foo implements Lifecycle, FooProxy, Serializable {
+
+	private static int count=0;
+
+	public static class Struct implements java.io.Serializable {
+		String name;
+		int count;
+		public boolean equals(Object other) {
+			Struct s = (Struct) other;
+			return ( s.name==name || s.name.equals(name) ) && s.count==count;
+		}
+		public int hashCode() {
+			return count;
+		}
+	}
+
+	/*public boolean equals(Object other) {
+		FooProxy otherFoo = (FooProxy) other;
+		return this.key.equals( otherFoo.getKey() ) && this._string.equals( otherFoo.getString() );
+	}
+
+	public int hashCode() {
+		return key.hashCode() - _string.hashCode();
+	}*/
+
+	String key;
+	FooProxy _foo;
+	String _string;
+	Date _date;
+	Date _timestamp;
+	Integer _integer;
+	Long _long;
+	Short _short;
+	Float _float;
+	Double _double;
+	Boolean _boolean;
+	Byte _byte;
+	Integer _null;
+	int _int;
+	boolean _bool;
+	float _zero;
+	byte[] _bytes;
+	boolean yesno;
+	java.io.Serializable blob;
+	java.io.Serializable nullBlob;
+	byte[] binary;
+	String[] custom;
+	FooComponent component;
+	char _char;
+	Fee dependent;
+	Locale theLocale;
+	private int version;
+	private Timestamp versionTimestamp;
+	private Calendar versionCalendar;
+	private float formula;
+	private String joinedProp;
+
+	private int x;
+
+	public int getX() {
+		return x;
+	}
+	public void setX(int x) {
+		this.x = x;
+	}
+
+	public Foo() {
+	}
+
+	public Foo(int x) {
+		this.x=x;
+	}
+
+	public boolean onSave(Session db) throws CallbackException {
+		_string = "a string";
+		_date = new Date(123);
+		_timestamp = new Date( System.currentTimeMillis() );
+		_integer = new Integer( -666 );
+		_long = new Long( 696969696969696969l - count++ );
+		_short = new Short("42");
+		_float = new Float( 6666.66f );
+		//_double = new Double( 1.33e-69 );  // this double is too big for the sap db jdbc driver
+		_double = new Double( 1.12e-36 );
+		_boolean = new Boolean(true);
+		_byte = new Byte( (byte) 127 );
+		_int = 2;
+		_char = '@';
+		_bytes = _string.getBytes();
+		Struct s = new Struct();
+		s.name="name";
+		s.count = 69;
+		blob = s;
+		binary = ( _string + "yada yada yada" ).getBytes();
+		custom = new String[] { "foo", "bar" };
+		component = new FooComponent("foo", 12, new Date[] { _date, _timestamp, null, new Date() }, new FooComponent("bar", 666, new Date[] { new Date(123456l), null }, null ) );
+		component.setGlarch( new Glarch() );
+		dependent = new Fee();
+		dependent.setFi( "belongs to foo # " + getKey() );
+		theLocale = Locale.getDefault();
+		return NO_VETO;
+	}
+
+	public boolean onDelete(Session db) throws CallbackException {
+		return NO_VETO;
+	}
+	public boolean onUpdate(Session db) throws CallbackException {
+		return NO_VETO;
+	}
+
+	public void onLoad(Session db, Serializable id) {
+	}
+
+	public String getKey() {
+		return key;
+	}
+	public void setKey(String key) {
+		this.key = key;
+	}
+
+	public FooProxy getFoo() {
+		return _foo;
+	}
+	public void setFoo(FooProxy foo) {
+		_foo = foo;
+	}
+
+	public String getString() {
+		return _string;
+	}
+	public void setString(String string) {
+		_string = string;
+		//if (_foo!=null) _foo.setString(string);
+	}
+
+	public java.util.Date getDate() {
+		return _date;
+	}
+	public void setDate(java.util.Date date) {
+		_date = date;
+	}
+
+	public java.util.Date getTimestamp() {
+		return _timestamp;
+	}
+	public void setTimestamp(java.util.Date timestamp) {
+		_timestamp = timestamp;
+	}
+
+	public Integer getInteger() {
+		return _integer;
+	}
+	public void setInteger(Integer iinteger) {
+		_integer = iinteger;
+	}
+	public Long getLong() {
+		return _long;
+	}
+	public void setLong(Long llong) {
+		_long = llong;
+	}
+
+
+	public Short getShort() {
+		return _short;
+	}
+	public void setShort(Short sshort) {
+		_short = sshort;
+	}
+	public Float getFloat() {
+		return _float;
+	}
+	public void setFloat(Float ffloat) {
+		_float = ffloat;
+	}
+	public Double getDouble() {
+		return _double;
+	}
+	public void setDouble(Double ddouble) {
+		_double = ddouble;
+	}
+	public Boolean getBoolean() {
+		return _boolean;
+	}
+	public void setBoolean(Boolean bboolean) {
+		_boolean = bboolean;
+	}
+	public byte[] getBytes() {
+		return _bytes;
+	}
+	public void setBytes(byte[] bytes) {
+		_bytes = bytes;
+	}
+	public float getZero() {
+		return _zero;
+	}
+	public void setZero(float zero) {
+		_zero = zero;
+	}
+	public boolean getBool() {
+		return _bool;
+	}
+	public void setBool(boolean bool) {
+		_bool = bool;
+	}
+
+	public int getInt() {
+		return _int;
+	}
+	public void setInt(int iint) {
+		_int = iint;
+	}
+
+	public Integer getNull() {
+		return _null;
+	}
+	public void setNull(Integer nnull) {
+		_null = nnull;
+	}
+
+	public Byte getByte() {
+		return _byte;
+	}
+
+	public void setByte(Byte bbyte) {
+		_byte = bbyte;
+	}
+
+	public String toString() {
+		return this.getClass().getName() + ": " + key;
+	}
+
+	public void disconnect() {
+		if ( _foo!=null) _foo.disconnect();
+		_foo=null;
+	}
+
+	public boolean equalsFoo(Foo other) {
+		if ( _bytes!=other._bytes ) {
+			if ( _bytes==null || other._bytes==null ) return false;
+			if ( _bytes.length!=other._bytes.length ) return false;
+			for ( int i=0; i< _bytes.length; i++) {
+				if ( _bytes[i] != other._bytes[i] ) return false;
+			}
+		}
+
+		return ( this._bool == other._bool )
+		&& ( ( this._boolean == other._boolean ) || ( this._boolean.equals(other._boolean) ) )
+		&& ( ( this._byte == other._byte ) || ( this._byte.equals(other._byte) ) )
+		//&& ( ( this._date == other._date ) || ( this._date.getDate() == other._date.getDate() && this._date.getMonth() == other._date.getMonth() && this._date.getYear() == other._date.getYear() ) )
+		&& ( ( this._double == other._double ) || ( this._double.equals(other._double) ) )
+		&& ( ( this._float == other._float ) || ( this._float.equals(other._float) ) )
+		&& ( this._int == other._int )
+		&& ( ( this._integer == other._integer ) || ( this._integer.equals(other._integer) ) )
+		&& ( ( this._long == other._long ) || ( this._long.equals(other._long) ) )
+		&& ( this._null == other._null )
+		&& ( ( this._short == other._short ) || ( this._short.equals(other._short) ) )
+		&& ( ( this._string == other._string) || ( this._string.equals(other._string) ) )
+		//&& ( ( this._timestamp==other._timestamp) || ( this._timestamp.getDate() == other._timestamp.getDate() && this._timestamp.getYear() == other._timestamp.getYear() && this._timestamp.getMonth() == other._timestamp.getMonth() ) )
+		&& ( this._zero == other._zero )
+		&& ( ( this._foo == other._foo ) || ( this._foo.getKey().equals( other._foo.getKey() ) ) )
+		&& ( ( this.blob == other.blob ) || ( this.blob.equals(other.blob) ) )
+		&& ( this.yesno == other.yesno )
+		&& ( ( this.binary == other.binary ) || java.util.Arrays.equals(this.binary, other.binary) )
+		&& ( this.key.equals(other.key) )
+		&& ( this.theLocale.equals(other.theLocale) )
+		&& ( ( this.custom == other.custom ) || ( this.custom[0].equals(other.custom[0]) && this.custom[1].equals(other.custom[1]) ) );
+
+	}
+
+	public boolean getYesno() {
+		return yesno;
+	}
+
+	public void setYesno(boolean yesno) {
+		this.yesno = yesno;
+	}
+
+	public java.io.Serializable getBlob() {
+		return blob;
+	}
+
+	public void setBlob(java.io.Serializable blob) {
+		this.blob = blob;
+	}
+
+	public java.io.Serializable getNullBlob() {
+		return nullBlob;
+	}
+
+	public void setNullBlob(java.io.Serializable nullBlob) {
+		this.nullBlob = nullBlob;
+	}
+
+	public byte[] getBinary() {
+		return binary;
+	}
+	public void setBinary(byte[] binary) {
+		this.binary = binary;
+	}
+
+	public String[] getCustom() {
+		return custom;
+	}
+
+	public void setCustom(String[] custom) {
+		this.custom = custom;
+	}
+
+	public FooComponent getComponent() {
+		return component;
+	}
+	public void setComponent(FooComponent component) {
+		this.component = component;
+	}
+
+	public FooComponent getNullComponent() {
+		return null;
+	}
+	public void setNullComponent(FooComponent fc) throws Exception {
+		if (fc!=null) throw new Exception("Null component");
+	}
+
+	public Character getChar() {
+		return new Character(_char);
+	}
+
+	public void setChar(Character _char) {
+		this._char = _char.charValue();
+	}
+
+	public Fee getDependent() {
+		return dependent;
+	}
+
+	public void setDependent(Fee dependent) {
+		this.dependent = dependent;
+	}
+
+	/**
+	 * Returns the locale.
+	 * @return Locale
+	 */
+	public Locale getLocale() {
+		return theLocale;
+	}
+
+	/**
+	 * Sets the locale.
+	 * @param locale The locale to set
+	 */
+	public void setLocale(Locale locale) {
+		this.theLocale = locale;
+	}
+
+	/**
+	 * Returns the version.
+	 * @return int
+	 */
+	public int getVersion() {
+		return version;
+	}
+
+	/**
+	 * Sets the version.
+	 * @param version The version to set
+	 */
+	public void setVersion(int version) {
+		this.version = version;
+	}
+
+	/**
+	 * Returns the versionTimestamp.
+	 * @return Timestamp
+	 */
+	public Timestamp getVersionTimestamp() {
+		return versionTimestamp;
+	}
+
+	/**
+	 * Sets the versionTimestamp.
+	 * @param versionTimestamp The versionTimestamp to set
+	 */
+	public void setVersionTimestamp(Timestamp versionTimestamp) {
+		this.versionTimestamp = versionTimestamp;
+	}
+
+	public void finalize() { }
+
+	public Calendar getVersionCalendar() {
+		return versionCalendar;
+	}
+
+	public void setVersionCalendar(Calendar calendar) {
+		versionCalendar = calendar;
+	}
+
+	public float getFormula() {
+		return formula;
+	}
+
+	public void setFormula(float f) {
+		formula = f;
+	}
+
+	/**
+	 * @return Returns the joinedProp.
+	 */
+	public String getJoinedProp() {
+		return joinedProp;
+	}
+
+	/**
+	 * @param joinedProp The joinedProp to set.
+	 */
+	public void setJoinedProp(String joinedProp) {
+		this.joinedProp = joinedProp;
+	}
+
+}
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooBar.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooBar.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooBar.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,178 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false" package="org.hibernate.test.legacy">
+
+	<import class="Result"/>
+	<import class="Named"/>
+
+	<class
+		name="Foo"
+		table="`foos`"
+		proxy="FooProxy"
+		discriminator-value="F"
+		batch-size="4"
+		dynamic-insert="true"
+		dynamic-update="true"
+		select-before-update="true">
+
+		<!--cache-->
+
+		<id name="key" type="string">
+			<column name="`foo_idcolumnname123`" length="36"/>
+			<generator class="uuid.hex">
+				<param name="seperator">:</param>
+			</generator>
+		</id>
+		<discriminator column="`foo_subclass_1234`" type="character" force="true"/>
+		<version name="version"/>
+		<!--<version name="versionCalendar" type="calendar"/>-->
+		<!--<timestamp name="versionTimestamp"/>-->
+		<many-to-one name="foo" class="Foo">
+				<column name="foo" length="36" index="fbmtoidx"/>
+		</many-to-one>
+		<property name="long">
+			<column name="long_" index="fbmtoidx" unique-key="abc" not-null="true"/>
+		</property>
+		<property name="integer">
+				<column name="`integer__`" unique-key="abc" not-null="true"/>
+		</property>
+		<property name="float">
+				<column name="float_" unique-key="abc" not-null="true" check="float_ > 0.0"/>
+		</property>
+		<property name="x"/>
+		<property name="double" column="double_"/>
+
+		<primitive-array name="bytes" table="foobytes">
+			<key column="id"/>
+			<index column="i"/>
+			<element column="byte_" type="byte"/>
+		</primitive-array>
+
+		<property name="date" type="date" column="date_"/>
+		<property name="timestamp" type="timestamp" column="timestamp_"/>
+		<property name="boolean" column="boolean_"/>
+		<property name="bool" column="bool_"/>
+		<property name="null" column="null_"/>
+		<property name="short" column="short_"/>
+		<property name="char" column="char_"/>
+		<property name="zero" column="zero_"/>
+		<property name="int" column="int_"/>
+		<property name="string">
+				<column name="string_" length="48" index="fbstridx"/>
+		</property>
+		<property name="byte" column="byte_"/>
+		<property name="yesno" type="yes_no"/>
+		<property name="blob" type="org.hibernate.test.legacy.Foo$Struct" column="blobb_"/>
+		<property name="nullBlob" type="serializable"/>
+		<property name="binary" column="bin_"/>
+		<property name="theLocale" access="field" column="`localeayzabc123`"/>
+
+		<property name="formula" formula="int_/2"/>
+
+		<property name="custom" type="org.hibernate.test.legacy.DoubleStringType" access="field">
+				<column name="first_name" length="66"/>
+				<column name="surname" length="66"/>
+		</property>
+
+		<component name="component">
+			<property name="count" column="count_" type="int" not-null="true"/>
+			<property name="name">
+				<column name="name_" length="32" not-null="true"/>
+			</property>
+			<many-to-one name="glarch"
+				column="g__"
+				cascade="all"
+				class="org.hibernate.test.legacy.Glarch"
+				lazy="proxy"
+				outer-join="true"/>
+			<property name="null" column="cmpnt_null_"/>
+			<component name="subcomponent">
+				<!--property name="count" column="subcount"/-->
+				<property name="name" column="subname"/>
+				<array name="importantDates" table="foo_times">
+					<key column="foo_id"/>
+					<index column="i"/>
+					<element column="date_" type="time"/>
+				</array>
+				<many-to-one name="fee"
+					column="fee_sub"
+					cascade="all"
+					class="Fee"
+					outer-join="false"
+					access="field"/>
+			</component>
+			<array name="importantDates" table="foo_dates">
+				<key column="foo_id"/>
+				<index column="i"/>
+				<element column="date_" type="date"/>
+			</array>
+		</component>
+		<component name="nullComponent">
+			<property name="name" column="null_cmpnt_"/>
+		</component>
+
+		<join table="jointable">
+			<key column="fooid" on-delete="cascade"/>
+			<property name="joinedProp"/>
+		</join>
+
+		<join table="foo_dep_table">
+			<key column="fooid"/>
+			<many-to-one name="dependent"
+				class="org.hibernate.test.legacy.Fee"
+				cascade="all"
+				not-null="true"/>
+		</join>
+
+		<subclass
+			name="Trivial"
+			proxy="FooProxy"
+			discriminator-value="T"/>
+
+		<subclass
+			name="Abstract"
+			proxy="AbstractProxy"
+			discriminator-value="null">
+				<set name="abstracts" batch-size="2">
+					<key column="abstract_id"/>
+					<one-to-many class="Abstract"/>
+				</set>
+				<property name="time" column="the_time"/>
+
+				<subclass
+					name="Bar"
+					proxy="BarProxy"
+					discriminator-value="B">
+					<many-to-one name="baz"/>
+					<property name="barString">
+						<column name="bar_string" length="24"/>
+					</property>
+					<component name="barComponent" class="FooComponent">
+						<parent name="parent"/>
+						<property name="count" column="bar_count"/>
+						<property name="name" length="64"/>
+						<array name ="importantDates">
+								<key column="id" />
+								<index column="i"/>
+							 <element column="date_" type="date"/>
+						</array>
+					</component>
+					<any name="object" meta-type="character" id-type="long" cascade="all">
+						<meta-value value="O" class="One"/>
+						<meta-value value="M" class="Many"/>
+						<column name="clazz" length="100"/>
+						<column name="gen_id"/>
+					</any>
+					<join table="bar_join_table">
+						<key column="bar_id"/>
+						<property name="name" column="name_name"/>
+					</join>
+				</subclass>
+		</subclass>
+	</class>
+
+
+</hibernate-mapping>
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooBarTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooBarTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooBarTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,4781 @@
+//$Id: FooBarTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.Time;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TimeZone;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import junit.framework.Test;
+import junit.textui.TestRunner;
+
+import org.hibernate.Criteria;
+import org.hibernate.FetchMode;
+import org.hibernate.FlushMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.LazyInitializationException;
+import org.hibernate.LockMode;
+import org.hibernate.ObjectNotFoundException;
+import org.hibernate.Query;
+import org.hibernate.QueryException;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.classic.Session;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.connection.DriverManagerConnectionProvider;
+import org.hibernate.criterion.Example;
+import org.hibernate.criterion.Expression;
+import org.hibernate.criterion.MatchMode;
+import org.hibernate.criterion.Order;
+import org.hibernate.dialect.DB2Dialect;
+import org.hibernate.dialect.DerbyDialect;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.InterbaseDialect;
+import org.hibernate.dialect.MckoiDialect;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.dialect.OracleDialect;
+import org.hibernate.dialect.PointbaseDialect;
+import org.hibernate.dialect.PostgreSQLDialect;
+import org.hibernate.dialect.SAPDBDialect;
+import org.hibernate.dialect.SybaseDialect;
+import org.hibernate.dialect.TimesTenDialect;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.jmx.HibernateService;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.mapping.RootClass;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.type.Type;
+import org.hibernate.util.JoinedIterator;
+import org.hibernate.util.SerializationHelper;
+
+
+public class FooBarTest extends LegacyTestCase {
+
+	public FooBarTest(String arg) {
+		super(arg);
+	}
+
+	public String[] getMappings() {
+		return new String[] {
+			"legacy/FooBar.hbm.xml",
+			"legacy/Baz.hbm.xml",
+			"legacy/Qux.hbm.xml",
+			"legacy/Glarch.hbm.xml",
+			"legacy/Fum.hbm.xml",
+			"legacy/Fumm.hbm.xml",
+			"legacy/Fo.hbm.xml",
+			"legacy/One.hbm.xml",
+			"legacy/Many.hbm.xml",
+			"legacy/Immutable.hbm.xml",
+			"legacy/Fee.hbm.xml",
+			"legacy/Vetoer.hbm.xml",
+			"legacy/Holder.hbm.xml",
+			"legacy/Location.hbm.xml",
+			"legacy/Stuff.hbm.xml",
+			"legacy/Container.hbm.xml",
+			"legacy/Simple.hbm.xml",
+			"legacy/XY.hbm.xml"
+		};
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		if ( Dialect.getDialect() instanceof OracleDialect ) {
+			( (RootClass) cfg.getClassMapping("org.hibernate.test.legacy.Foo") ).setForceDiscriminator(false);
+		}
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( FooBarTest.class );
+	}
+
+	public static void main(String[] args) throws Exception {
+		TestRunner.run( suite() );
+	}
+
+	public void testSaveOrUpdateCopyAny() throws Exception {
+		Session s = openSession();
+		Bar bar = new Bar();
+		One one = new One();
+		bar.setObject(one);
+		s.save(bar);
+		GlarchProxy g = bar.getComponent().getGlarch();
+		bar.getComponent().setGlarch(null);
+		s.delete(g);
+		s.flush();
+		assertTrue( s.contains(one) );
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Bar bar2 = (Bar) s.saveOrUpdateCopy(bar);
+		s.flush();
+		s.delete(bar2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testRefreshProxy() throws Exception {
+		Session s = openSession();
+		Glarch g = new Glarch();
+		Serializable gid = s.save(g);
+		s.flush();
+		s.clear();
+		GlarchProxy gp = (GlarchProxy) s.load(Glarch.class, gid);
+		gp.getName(); //force init
+		s.refresh(gp);
+		s.delete(gp);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testOnCascadeDelete() throws Exception {
+
+		if ( ! supportsCircularCascadeDelete() ) {
+			return;
+		}
+
+		Session s = openSession();
+		Baz baz = new Baz();
+		baz.subs = new ArrayList();
+		Baz sub = new Baz();
+		sub.superBaz = baz;
+		baz.subs.add(sub);
+		s.save(baz);
+		s.flush();
+		assertTrue( s.createQuery("from Baz").list().size()==2 );
+		s.connection().commit();
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		assertTrue( s.createQuery("from Baz").list().size()==0 );
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testRemoveFromIdbag() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		baz.setByteBag( new ArrayList() );
+		byte[] bytes = { 12, 13 };
+		baz.getByteBag().add( new byte[] { 10, 45 } );
+		baz.getByteBag().add(bytes);
+		baz.getByteBag().add( new byte[] { 1, 11 } );
+		baz.getByteBag().add( new byte[] { 12 } );
+		s.save(baz);
+		s.flush();
+		baz.getByteBag().remove(bytes);
+		s.flush();
+		baz.getByteBag().add(bytes);
+		s.flush();
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testLoad() throws Exception {
+		Session s = openSession();
+		Qux q = new Qux();
+		s.save(q);
+		BarProxy b = new Bar();
+		s.save(b);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		q = (Qux) s.load(Qux.class, q.getKey() );
+		b = (BarProxy) s.load( Foo.class, b.getKey() );
+		b.getKey();
+		assertFalse( Hibernate.isInitialized(b) );
+		b.getBarString();
+		assertTrue( Hibernate.isInitialized(b) );
+		BarProxy b2 = (BarProxy) s.load( Bar.class, new String( b.getKey() ) );
+		Qux q2 = (Qux) s.load( Qux.class, q.getKey() );
+		assertTrue( "loaded same object", q==q2 );
+		assertTrue( "loaded same object", b==b2 );
+		assertTrue( Math.round( b.getFormula() ) == b.getInt()/2 );
+		s.delete(q2);
+		s.delete(b2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testJoin() throws Exception {
+		Session s = openSession();
+		Foo foo = new Foo();
+		foo.setJoinedProp("foo");
+		s.save(foo);
+		s.flush();
+		foo.setJoinedProp("bar");
+		s.flush();
+		String fid = foo.getKey();
+		s.delete(foo);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Foo foo2 = new Foo();
+		foo2.setJoinedProp("foo");
+		s.save(foo2);
+		s.find("select foo.id from Foo foo where foo.joinedProp = 'foo'");
+		assertNull( s.get(Foo.class, fid) );
+		s.delete(foo2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testDereferenceLazyCollection() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		baz.setFooSet( new HashSet() );
+		Foo foo = new Foo();
+		baz.getFooSet().add(foo);
+		s.save(foo);
+		s.save(baz);
+		foo.setBytes( "foobar".getBytes() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		foo = (Foo) s.get( Foo.class, foo.getKey() );
+		assertTrue( Hibernate.isInitialized( foo.getBytes() ) );
+		assertTrue( foo.getBytes().length==6 );
+		baz = (Baz) s.get( Baz.class, baz.getCode() );
+		assertTrue( baz.getFooSet().size()==1 );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		getSessions().evictCollection("org.hibernate.test.legacy.Baz.fooSet");
+
+		s = openSession();
+		baz = (Baz) s.get( Baz.class, baz.getCode() );
+		assertFalse( Hibernate.isInitialized( baz.getFooSet() ) );
+		baz.setFooSet(null);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		foo = (Foo) s.get( Foo.class, foo.getKey() );
+		assertTrue( foo.getBytes().length==6 );
+		baz = (Baz) s.get( Baz.class, baz.getCode() );
+		assertFalse( Hibernate.isInitialized( baz.getFooSet() ) );
+		assertTrue( baz.getFooSet().size()==0 );
+		s.delete(baz);
+		s.delete(foo);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testMoveLazyCollection() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		Baz baz2 = new Baz();
+		baz.setFooSet( new HashSet() );
+		Foo foo = new Foo();
+		baz.getFooSet().add(foo);
+		s.save(foo);
+		s.save(baz);
+		s.save(baz2);
+		foo.setBytes( "foobar".getBytes() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		foo = (Foo) s.get( Foo.class, foo.getKey() );
+		assertTrue( Hibernate.isInitialized( foo.getBytes() ) );
+		assertTrue( foo.getBytes().length==6 );
+		baz = (Baz) s.get( Baz.class, baz.getCode() );
+		assertTrue( baz.getFooSet().size()==1 );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		getSessions().evictCollection("org.hibernate.test.legacy.Baz.fooSet");
+
+		s = openSession();
+		baz = (Baz) s.get( Baz.class, baz.getCode() );
+		assertFalse( Hibernate.isInitialized( baz.getFooSet() ) );
+		baz2 = (Baz) s.get( Baz.class, baz2.getCode() );
+		baz2.setFooSet( baz.getFooSet() );
+		baz.setFooSet(null);
+		assertFalse( Hibernate.isInitialized( baz2.getFooSet() ) );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		foo = (Foo) s.get( Foo.class, foo.getKey() );
+		assertTrue( foo.getBytes().length==6 );
+		baz = (Baz) s.get( Baz.class, baz.getCode() );
+		baz2 = (Baz) s.get( Baz.class, baz2.getCode() );
+		assertFalse( Hibernate.isInitialized( baz.getFooSet() ) );
+		assertTrue( baz.getFooSet().size()==0 );
+		assertTrue( Hibernate.isInitialized( baz2.getFooSet() ) ); //fooSet has batching enabled
+		assertTrue( baz2.getFooSet().size()==1 );
+		s.delete(baz);
+		s.delete(baz2);
+		s.delete(foo);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testCriteriaCollection() throws Exception {
+		Session s = openSession();
+		Baz bb = (Baz) s.createCriteria(Baz.class).uniqueResult();
+		assertTrue(bb==null);
+		Baz baz = new Baz();
+		s.save(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		Baz b = (Baz) s.createCriteria(Baz.class).uniqueResult();
+		assertTrue( Hibernate.isInitialized( b.getTopGlarchez() ) );
+		assertTrue( b.getTopGlarchez().size()==0 );
+		s.delete(b);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testQuery() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		Foo foo = new Foo();
+		s.save(foo);
+		Foo foo2 = new Foo();
+		s.save(foo2);
+		foo.setFoo(foo2);
+
+		List list = s.find("from Foo foo inner join fetch foo.foo");
+		Foo foof = (Foo) list.get(0);
+		assertTrue( Hibernate.isInitialized( foof.getFoo() ) );
+
+		list = s.find("from Baz baz left outer join fetch baz.fooToGlarch");
+
+		list = s.find(
+			"select foo, bar from Foo foo left outer join foo.foo bar where foo = ?",
+			foo,
+			Hibernate.entity(Foo.class)
+		);
+		Object[] row1 = (Object[]) list.get(0);
+		assertTrue( row1[0]==foo && row1[1]==foo2 );
+
+		s.find("select foo.foo.foo.string from Foo foo where foo.foo = 'bar'");
+		s.find("select foo.foo.foo.foo.string from Foo foo where foo.foo = 'bar'");
+		s.find("select foo from Foo foo where foo.foo.foo = 'bar'");
+		s.find("select foo.foo.foo.foo.string from Foo foo where foo.foo.foo = 'bar'");
+		s.find("select foo.foo.foo.string from Foo foo where foo.foo.foo.foo.string = 'bar'");
+		if ( ! (getDialect() instanceof HSQLDialect) ) s.find("select foo.string from Foo foo where foo.foo.foo.foo = foo.foo.foo");
+		s.find("select foo.string from Foo foo where foo.foo.foo = 'bar' and foo.foo.foo.foo = 'baz'");
+		s.find("select foo.string from Foo foo where foo.foo.foo.foo.string = 'a' and foo.foo.string = 'b'");
+
+		s.find("from Bar bar, foo in elements(bar.baz.fooArray)");
+
+		//s.find("from Baz as baz where baz.topComponents[baz].name = 'bazzz'");
+
+		if ( (getDialect() instanceof DB2Dialect) && !(getDialect() instanceof DerbyDialect) ) {
+			s.find("from Foo foo where lower( foo.foo.string ) = 'foo'");
+			s.find("from Foo foo where lower( (foo.foo.string || 'foo') || 'bar' ) = 'foo'");
+			s.find("from Foo foo where repeat( (foo.foo.string || 'foo') || 'bar', 2 ) = 'foo'");
+			s.find("from Bar foo where foo.foo.integer is not null and repeat( (foo.foo.string || 'foo') || 'bar', (5+5)/2 ) = 'foo'");
+			s.find("from Bar foo where foo.foo.integer is not null or repeat( (foo.foo.string || 'foo') || 'bar', (5+5)/2 ) = 'foo'");
+		}
+		if (getDialect() instanceof SybaseDialect) {  
+			s.iterate("select baz from Baz as baz join baz.fooArray foo group by baz order by sum(foo.float)");
+		}
+
+		s.find("from Foo as foo where foo.component.glarch.name is not null");
+		s.find("from Foo as foo left outer join foo.component.glarch as glarch where glarch.name = 'foo'");
+
+		list = s.find("from Foo");
+		assertTrue( list.size()==2 && list.get(0) instanceof FooProxy );
+		list = s.find("from Foo foo left outer join foo.foo");
+		assertTrue( list.size()==2 && ( (Object[]) list.get(0) )[0] instanceof FooProxy );
+
+		s.createQuery("from Bar, Bar").list();
+		s.createQuery("from Foo, Bar").list();
+		s.find("from Baz baz left join baz.fooToGlarch, Bar bar join bar.foo");
+		s.find("from Baz baz left join baz.fooToGlarch join baz.fooSet");
+		s.find("from Baz baz left join baz.fooToGlarch join fetch baz.fooSet foo left join fetch foo.foo");
+
+		list = s.find("from Foo foo where foo.string='osama bin laden' and foo.boolean = true order by foo.string asc, foo.component.count desc");
+		assertTrue( "empty query", list.size()==0 );
+		Iterator iter = s.iterate("from Foo foo where foo.string='osama bin laden' order by foo.string asc, foo.component.count desc");
+		assertTrue( "empty iterator", !iter.hasNext() );
+
+		list = s.find("select foo.foo from Foo foo");
+		assertTrue( "query", list.size()==1 );
+		assertTrue( "returned object", list.get(0)==foo.getFoo() );
+		foo.getFoo().setFoo(foo);
+		foo.setString("fizard");
+		//The following test is disabled for databases with no subselects...also for Interbase (not sure why).
+		if ( 
+				!(getDialect() instanceof MySQLDialect) && 
+				!(getDialect() instanceof HSQLDialect) && 
+				!(getDialect() instanceof MckoiDialect) && 
+				!(getDialect() instanceof SAPDBDialect) && 
+				!(getDialect() instanceof PointbaseDialect) &&
+				!(getDialect() instanceof DerbyDialect)
+		)  {
+			// && !db.equals("weblogic") {
+			if ( !( getDialect() instanceof InterbaseDialect ) ) {
+				list = s.find("from Foo foo where ? = some elements(foo.component.importantDates)", new Date(), Hibernate.DATE);
+				assertTrue( "component query", list.size()==2 );
+			}
+			if( !( getDialect() instanceof TimesTenDialect)) {
+				list = s.find("from Foo foo where size(foo.component.importantDates) = 3"); //WAS: 4
+				assertTrue( "component query", list.size()==2 );
+				list = s.find("from Foo foo where 0 = size(foo.component.importantDates)");
+				assertTrue( "component query", list.size()==0 );
+			}
+			list = s.find("from Foo foo where exists elements(foo.component.importantDates)");
+			assertTrue( "component query", list.size()==2 );
+			s.find("from Foo foo where not exists (from Bar bar where bar.id = foo.id)");
+
+			s.find("select foo.foo from Foo foo where foo = some(select x from Foo x where x.long > foo.foo.long)");
+			s.find("select foo.foo from Foo foo where foo = some(from Foo x where (x.long > foo.foo.long))");
+			if ( !( getDialect() instanceof TimesTenDialect)) {
+				s.find("select foo.foo from Foo foo where foo.long = some( select max(x.long) from Foo x where (x.long > foo.foo.long) group by x.foo )");
+			}
+			s.find("from Foo foo where foo = some(select x from Foo x where x.long > foo.foo.long) and foo.foo.string='baz'");
+			s.find("from Foo foo where foo.foo.string='baz' and foo = some(select x from Foo x where x.long > foo.foo.long)");
+			s.find("from Foo foo where foo = some(select x from Foo x where x.long > foo.foo.long)");
+
+			s.iterate("select foo.string, foo.date, foo.foo.string, foo.id from Foo foo, Baz baz where foo in elements(baz.fooArray) and foo.string like 'foo'");
+		}
+		list = s.find("from Foo foo where foo.component.count is null order by foo.component.count");
+		assertTrue( "component query", list.size()==0 );
+		list = s.find("from Foo foo where foo.component.name='foo'");
+		assertTrue( "component query", list.size()==2 );
+		list = s.find("select distinct foo.component.name, foo.component.name from Foo foo where foo.component.name='foo'");
+		assertTrue( "component query", list.size()==1 );
+		list = s.find("select distinct foo.component.name, foo.id from Foo foo where foo.component.name='foo'");
+		assertTrue( "component query", list.size()==2 );
+		list = s.find("select foo.foo from Foo foo");
+		assertTrue( "query", list.size()==2 );
+		list = s.find("from Foo foo where foo.id=?", foo.getKey(), Hibernate.STRING);
+		assertTrue( "id query", list.size()==1 );
+		list = s.find("from Foo foo where foo.key=?", foo.getKey(), Hibernate.STRING);
+		assertTrue( "named id query", list.size()==1 );
+		assertTrue( "id query", list.get(0)==foo );
+		list = s.find("select foo.foo from Foo foo where foo.string='fizard'");
+		assertTrue( "query", list.size()==1 );
+		assertTrue( "returned object", list.get(0)==foo.getFoo() );
+		list = s.find("from Foo foo where foo.component.subcomponent.name='bar'");
+		assertTrue( "components of components", list.size()==2 );
+		list = s.find("select foo.foo from Foo foo where foo.foo.id=?", foo.getFoo().getKey(), Hibernate.STRING);
+		assertTrue( "by id query", list.size()==1 );
+		assertTrue( "by id returned object", list.get(0)==foo.getFoo() );
+
+		s.find( "from Foo foo where foo.foo = ?", foo.getFoo(), Hibernate.entity(Foo.class) );
+
+		assertTrue( !s.iterate("from Bar bar where bar.string='a string' or bar.string='a string'").hasNext() );
+
+		iter = s.iterate(
+			"select foo.component.name, elements(foo.component.importantDates) from Foo foo where foo.foo.id=?",
+			foo.getFoo().getKey(),
+			Hibernate.STRING
+		);
+		int i=0;
+		while ( iter.hasNext() ) {
+			i++;
+			Object[] row = (Object[]) iter.next();
+			assertTrue( row[0] instanceof String && ( row[1]==null || row[1] instanceof Date ) );
+		}
+		assertTrue(i==3); //WAS: 4
+		iter = s.iterate(
+			"select max( elements(foo.component.importantDates) ) from Foo foo group by foo.id"
+		);
+		assertTrue( iter.next() instanceof Date );
+
+		list = s.find(
+			"select foo.foo.foo.foo from Foo foo, Foo foo2 where"
+			+ " foo = foo2.foo and not not ( not foo.string='fizard' )"
+			+ " and foo2.string between 'a' and (foo.foo.string)"
+			+ ( ( getDialect() instanceof HSQLDialect || getDialect() instanceof InterbaseDialect || getDialect() instanceof TimesTenDialect)?
+				" and ( foo2.string in ( 'fiz', 'blah') or 1=1 )"
+				:
+				" and ( foo2.string in ( 'fiz', 'blah', foo.foo.string, foo.string, foo2.string ) )"
+			)
+		);
+		assertTrue( "complex query", list.size()==1 );
+		assertTrue( "returned object", list.get(0)==foo );
+		foo.setString("from BoogieDown  -tinsel town  =!@#$^&*())");
+		list = s.find("from Foo foo where foo.string='from BoogieDown  -tinsel town  =!@#$^&*())'");
+		assertTrue( "single quotes", list.size()==1 );
+		list = s.find("from Foo foo where not foo.string='foo''bar'");
+		assertTrue( "single quotes", list.size()==2 );
+		list = s.find("from Foo foo where foo.component.glarch.next is null");
+		assertTrue( "query association in component", list.size()==2 );
+		Bar bar = new Bar();
+		Baz baz = new Baz();
+		baz.setDefaults();
+		bar.setBaz(baz);
+		baz.setManyToAny( new ArrayList() );
+		baz.getManyToAny().add(bar);
+		baz.getManyToAny().add(foo);
+		s.save(bar);
+		s.save(baz);
+		list = s.find(" from Bar bar where bar.baz.count=667 and bar.baz.count!=123 and not bar.baz.name='1-E-1'");
+		assertTrue( "query many-to-one", list.size()==1 );
+		list = s.find(" from Bar i where i.baz.name='Bazza'");
+		assertTrue( "query many-to-one", list.size()==1 );
+
+		Iterator rs = s.iterate("select count(distinct foo.foo) from Foo foo");
+		assertTrue( "count", ( (Long) rs.next() ).longValue()==2 );
+		assertTrue( !rs.hasNext() );
+		rs = s.iterate("select count(foo.foo.boolean) from Foo foo");
+		assertTrue( "count", ( (Long) rs.next() ).longValue()==2 );
+		assertTrue( !rs.hasNext() );
+		rs = s.iterate("select count(*), foo.int from Foo foo group by foo.int");
+		assertTrue( "count(*) group by", ( (Object[]) rs.next() )[0].equals( new Long(3) ) );
+		assertTrue( !rs.hasNext() );
+		rs = s.iterate("select sum(foo.foo.int) from Foo foo");
+		assertTrue( "sum", ( (Long) rs.next() ).longValue()==4 );
+		assertTrue( !rs.hasNext() );
+		rs = s.iterate("select count(foo) from Foo foo where foo.id=?", foo.getKey(), Hibernate.STRING);
+		assertTrue( "id query count", ( (Long) rs.next() ).longValue()==1 );
+		assertTrue( !rs.hasNext() );
+
+		list = s.find( "from Foo foo where foo.boolean = ?", new Boolean(true), Hibernate.BOOLEAN );
+
+		list = s.find("select new Foo(fo.x) from Fo fo");
+		list = s.find("select new Foo(fo.integer) from Foo fo");
+
+		list = s.createQuery("select new Foo(fo.x) from Foo fo")
+			//.setComment("projection test")
+			.setCacheable(true)
+			.list();
+		assertTrue(list.size()==3);
+		list = s.createQuery("select new Foo(fo.x) from Foo fo")
+			//.setComment("projection test 2")
+			.setCacheable(true)
+			.list();
+		assertTrue(list.size()==3);
+
+		rs = s.iterate("select new Foo(fo.x) from Foo fo");
+		assertTrue( "projection iterate (results)", rs.hasNext() );
+		assertTrue( "projection iterate (return check)", Foo.class.isAssignableFrom( rs.next().getClass() ) );
+
+		ScrollableResults sr = s.createQuery("select new Foo(fo.x) from Foo fo").scroll();
+		assertTrue( "projection scroll (results)", sr.next() );
+		assertTrue( "projection scroll (return check)", Foo.class.isAssignableFrom( sr.get(0).getClass() ) );
+
+		list = s.find("select foo.long, foo.component.name, foo, foo.foo from Foo foo");
+		rs = list.iterator();
+		int count=0;
+		while ( rs.hasNext() ) {
+			count++;
+			Object[] row = (Object[]) rs.next();
+			assertTrue( row[0] instanceof Long );
+			assertTrue( row[1] instanceof String );
+			assertTrue( row[2] instanceof Foo );
+			assertTrue( row[3] instanceof Foo );
+		}
+		assertTrue(count!=0);
+		list = s.find("select avg(foo.float), max(foo.component.name), count(distinct foo.id) from Foo foo");
+		rs = list.iterator();
+		count=0;
+		while ( rs.hasNext() ) {
+			count++;
+			Object[] row = (Object[]) rs.next();
+			assertTrue( row[0] instanceof Double );
+			assertTrue( row[1] instanceof String );
+			assertTrue( row[2] instanceof Long );
+		}
+		assertTrue(count!=0);
+		list = s.find("select foo.long, foo.component, foo, foo.foo from Foo foo");
+		rs = list.iterator();
+		count=0;
+		while ( rs.hasNext() ) {
+			count++;
+			Object[] row = (Object[]) rs.next();
+			assertTrue( row[0] instanceof Long );
+			assertTrue( row[1] instanceof FooComponent );
+			assertTrue( row[2] instanceof Foo );
+			assertTrue( row[3] instanceof Foo );
+		}
+		assertTrue(count!=0);
+
+		s.save( new Holder("ice T") );
+		s.save( new Holder("ice cube") );
+
+		assertTrue( s.find("from java.lang.Object as o").size()==15 );
+		assertTrue( s.find("from Named").size()==7 );
+		assertTrue( s.find("from Named n where n.name is not null").size()==4 );
+		iter = s.iterate("from Named n");
+		while ( iter.hasNext() ) {
+			assertTrue( iter.next() instanceof Named );
+		}
+
+		s.save( new Holder("bar") );
+		iter = s.iterate("from Named n0, Named n1 where n0.name = n1.name");
+		int cnt = 0;
+		while ( iter.hasNext() ) {
+			Object[] row = (Object[]) iter.next();
+			if ( row[0]!=row[1] ) cnt++;
+		}
+		if ( !(getDialect() instanceof HSQLDialect) ) {
+			assertTrue(cnt==2);
+			assertTrue( s.find("from Named n0, Named n1 where n0.name = n1.name").size()==7 );
+		}
+
+		Query qu = s.createQuery("from Named n where n.name = :name");
+		qu.getReturnTypes();
+		qu.getNamedParameters();
+
+		iter = s.iterate("from java.lang.Object");
+		int c = 0;
+		while ( iter.hasNext() ) {
+			iter.next();
+			c++;
+		}
+		assertTrue(c==16);
+
+		s.iterate("select baz.code, min(baz.count) from Baz baz group by baz.code");
+
+		iter = s.iterate("selecT baz from Baz baz where baz.stringDateMap['foo'] is not null or baz.stringDateMap['bar'] = ?", new Date(), Hibernate.DATE);
+		assertFalse( iter.hasNext() );
+		list = s.find("select baz from Baz baz where baz.stringDateMap['now'] is not null");
+		assertTrue( list.size()==1 );
+		list = s.find("select baz from Baz baz where baz.stringDateMap['now'] is not null and baz.stringDateMap['big bang'] < baz.stringDateMap['now']");
+		assertTrue( list.size()==1 );
+		list = s.find("select index(date) from Baz baz join baz.stringDateMap date");
+		System.out.println(list);
+		assertTrue( list.size()==2 );
+
+		s.find("from Foo foo where foo.integer not between 1 and 5 and foo.string not in ('cde', 'abc') and foo.string is not null and foo.integer<=3");
+
+		s.find("from Baz baz inner join baz.collectionComponent.nested.foos foo where foo.string is null");
+		if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof MckoiDialect) && !(getDialect() instanceof SAPDBDialect) && !(getDialect() instanceof PointbaseDialect) /*&& !(dialect instanceof Oracle9Dialect)*/ )  {
+			s.find("from Baz baz inner join baz.fooSet where '1' in (from baz.fooSet foo where foo.string is not null)");
+			s.find("from Baz baz where 'a' in elements(baz.collectionComponent.nested.foos) and 1.0 in elements(baz.collectionComponent.nested.floats)");
+			s.find("from Baz baz where 'b' in elements(baz.collectionComponent.nested.foos) and 1.0 in elements(baz.collectionComponent.nested.floats)");
+		}
+
+		s.find("from Foo foo join foo.foo where foo.foo in ('1','2','3')");
+		if ( !(getDialect() instanceof HSQLDialect) ) s.find("from Foo foo left join foo.foo where foo.foo in ('1','2','3')");
+		s.find("select foo.foo from Foo foo where foo.foo in ('1','2','3')");
+		s.find("select foo.foo.string from Foo foo where foo.foo in ('1','2','3')");
+		s.find("select foo.foo.string from Foo foo where foo.foo.string in ('1','2','3')");
+		s.find("select foo.foo.long from Foo foo where foo.foo.string in ('1','2','3')");
+		s.find("select count(*) from Foo foo where foo.foo.string in ('1','2','3') or foo.foo.long in (1,2,3)");
+		s.find("select count(*) from Foo foo where foo.foo.string in ('1','2','3') group by foo.foo.long");
+
+		s.find("from Foo foo1 left join foo1.foo foo2 left join foo2.foo where foo1.string is not null");
+		s.find("from Foo foo1 left join foo1.foo.foo where foo1.string is not null");
+		s.find("from Foo foo1 left join foo1.foo foo2 left join foo1.foo.foo foo3 where foo1.string is not null");
+
+		s.find("select foo.formula from Foo foo where foo.formula > 0");
+
+		int len = s.find("from Foo as foo join foo.foo as foo2 where foo2.id >'a' or foo2.id <'a'").size();
+		assertTrue(len==2);
+
+		s.delete("from Holder");
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		baz = (Baz) s.createQuery("from Baz baz left outer join fetch baz.manyToAny").uniqueResult();
+		assertTrue( Hibernate.isInitialized( baz.getManyToAny() ) );
+		assertTrue( baz.getManyToAny().size()==2 );
+		BarProxy barp = (BarProxy) baz.getManyToAny().get(0);
+		s.find("from Baz baz join baz.manyToAny");
+		assertTrue( s.find("select baz from Baz baz join baz.manyToAny a where index(a) = 0").size()==1 );
+
+		FooProxy foop = (FooProxy) s.get( Foo.class, foo.getKey() );
+		assertTrue( foop == baz.getManyToAny().get(1) );
+
+		barp.setBaz(baz);
+		assertTrue( s.find("select bar from Bar bar where bar.baz.stringDateMap['now'] is not null").size()==1 );
+		assertTrue( s.find("select bar from Bar bar join bar.baz b where b.stringDateMap['big bang'] < b.stringDateMap['now'] and b.stringDateMap['now'] is not null").size()==1 );
+		assertTrue( s.find("select bar from Bar bar where bar.baz.stringDateMap['big bang'] < bar.baz.stringDateMap['now'] and bar.baz.stringDateMap['now'] is not null").size()==1 );
+
+		list = s.find("select foo.string, foo.component, foo.id from Bar foo");
+		assertTrue ( ( (FooComponent) ( (Object[]) list.get(0) )[1] ).getName().equals("foo") );
+		list = s.find("select elements(baz.components) from Baz baz");
+		assertTrue( list.size()==2 );
+		list = s.find("select bc.name from Baz baz join baz.components bc");
+		assertTrue( list.size()==2 );
+		//list = s.find("select bc from Baz baz join baz.components bc");
+
+		s.createQuery("from Foo foo where foo.integer < 10 order by foo.string").setMaxResults(12).list();
+
+		s.delete(barp);
+		s.delete(baz);
+		s.delete( foop.getFoo() );
+		s.delete(foop);
+		txn.commit();
+		s.close();
+	}
+
+	public void testCascadeDeleteDetached() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		List list = new ArrayList();
+		list.add( new Fee() );
+		baz.setFees(list);
+		s.save(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.get( Baz.class, baz.getCode() );
+		s.connection().commit();
+		s.close();
+
+		assertFalse( Hibernate.isInitialized( baz.getFees() ) );
+
+		s = openSession();
+		s.delete(baz);
+		s.flush();
+		assertFalse( s.iterate("from Fee").hasNext() );
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = new Baz();
+		list = new ArrayList();
+		list.add( new Fee() );
+		list.add( new Fee() );
+		baz.setFees(list);
+		s.save(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.get( Baz.class, baz.getCode() );
+		Hibernate.initialize( baz.getFees() );
+		s.connection().commit();
+		s.close();
+
+		assertTrue( baz.getFees().size()==2 );
+
+		s = openSession();
+		s.delete(baz);
+		s.flush();
+		assertFalse( s.iterate("from Fee").hasNext() );
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testForeignKeys() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		Foo foo = new Foo();
+		List bag = new ArrayList();
+		bag.add(foo);
+		baz.setIdFooBag(bag);
+		baz.setFoo(foo);
+		s.save(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testNonlazyCollection() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		s.save(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.createCriteria(Baz.class)
+			//.setComment("criteria test")
+			.setFetchMode("stringDateMap", FetchMode.EAGER)
+			.uniqueResult();
+		assertTrue( Hibernate.isInitialized( baz.getFooToGlarch() ) );
+		assertTrue( Hibernate.isInitialized( baz.getFooComponentToFoo() ) );
+		assertTrue( !Hibernate.isInitialized( baz.getStringSet() ) );
+		assertTrue( Hibernate.isInitialized( baz.getStringDateMap() ) );
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testReuseDeletedCollection() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		baz.setDefaults();
+		s.save(baz);
+		s.flush();
+		s.delete(baz);
+		Baz baz2 = new Baz();
+		baz2.setStringArray( new String[] {"x-y-z"} );
+		s.save(baz2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		baz2.setStringSet( baz.getStringSet() );
+		baz2.setStringArray( baz.getStringArray() );
+		baz2.setFooArray( baz.getFooArray() );
+
+		s = openSession();
+		s.update(baz2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz2 = (Baz) s.load( Baz.class, baz2.getCode() );
+		assertTrue( baz2.getStringArray().length==3 );
+		assertTrue( baz2.getStringSet().size()==3 );
+		s.delete(baz2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+
+	}
+
+	public void testPropertyRef() throws Exception {
+		Session s = openSession();
+		Holder h = new Holder();
+		h.setName("foo");
+		Holder h2 = new Holder();
+		h2.setName("bar");
+		h.setOtherHolder(h2);
+		Serializable hid = s.save(h);
+		Qux q = new Qux();
+		q.setHolder(h2);
+		Serializable qid = s.save(q);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		h = (Holder) s.load(Holder.class, hid);
+		assertEquals( h.getName(), "foo");
+		assertEquals( h.getOtherHolder().getName(), "bar");
+		Object[] res = (Object[]) s.find("from Holder h join h.otherHolder oh where h.otherHolder.name = 'bar'").get(0);
+		assertTrue( res[0]==h );
+		q = (Qux) s.get(Qux.class, qid);
+		assertTrue( q.getHolder() == h.getOtherHolder() );
+		s.delete(h);
+		s.delete(q);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testQueryCollectionOfValues() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		baz.setDefaults();
+		s.save(baz);
+		Glarch g = new Glarch();
+		Serializable gid = s.save(g);
+
+		if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof HSQLDialect) /*&& !(dialect instanceof MckoiDialect)*/ && !(getDialect() instanceof SAPDBDialect) && !(getDialect() instanceof PointbaseDialect) && !(getDialect() instanceof TimesTenDialect) ) {
+			s.filter( baz.getFooArray(), "where size(this.bytes) > 0");
+			s.filter( baz.getFooArray(), "where 0 in elements(this.bytes)");
+		}
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		//s.find("from Baz baz where baz.fooSet.string = 'foo'");
+		//s.find("from Baz baz where baz.fooArray.string = 'foo'");
+		//s.find("from Baz baz where baz.fooSet.foo.string = 'foo'");
+		//s.find("from Baz baz join baz.fooSet.foo foo where foo.string = 'foo'");
+		s.find("from Baz baz join baz.fooSet foo join foo.foo.foo foo2 where foo2.string = 'foo'");
+		s.find("from Baz baz join baz.fooArray foo join foo.foo.foo foo2 where foo2.string = 'foo'");
+		s.find("from Baz baz join baz.stringDateMap date where index(date) = 'foo'");
+		s.find("from Baz baz join baz.topGlarchez g where index(g) = 'A'");
+		s.find("select index(g) from Baz baz join baz.topGlarchez g");
+
+		assertTrue( s.find("from Baz baz left join baz.stringSet").size()==3 );
+		baz = (Baz) s.find("from Baz baz join baz.stringSet str where str='foo'").get(0);
+		assertTrue( !Hibernate.isInitialized( baz.getStringSet() ) );
+		baz = (Baz) s.find("from Baz baz left join fetch baz.stringSet").get(0);
+		assertTrue( Hibernate.isInitialized( baz.getStringSet() ) );
+		assertTrue( s.find("from Baz baz join baz.stringSet string where string='foo'").size()==1 );
+		assertTrue( s.find("from Baz baz inner join baz.components comp where comp.name='foo'").size()==1 );
+		//List bss = s.find("select baz, ss from Baz baz inner join baz.stringSet ss");
+		s.find("from Glarch g inner join g.fooComponents comp where comp.fee is not null");
+		s.find("from Glarch g inner join g.fooComponents comp join comp.fee fee where fee.count > 0");
+		s.find("from Glarch g inner join g.fooComponents comp where comp.fee.count is not null");
+
+		s.delete(baz);
+		//s.delete("from Glarch g");
+		s.delete( s.get(Glarch.class, gid) );
+		s.flush();
+
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testBatchLoad() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		SortedSet stringSet = new TreeSet();
+		stringSet.add("foo");
+		stringSet.add("bar");
+		Set fooSet = new HashSet();
+		for (int i=0; i<3; i++) {
+			Foo foo = new Foo();
+			s.save(foo);
+			fooSet.add(foo);
+		}
+		baz.setFooSet(fooSet);
+		baz.setStringSet(stringSet);
+		s.save(baz);
+		Baz baz2 = new Baz();
+		fooSet = new HashSet();
+		for (int i=0; i<2; i++) {
+			Foo foo = new Foo();
+			s.save(foo);
+			fooSet.add(foo);
+		}
+		baz2.setFooSet(fooSet);
+		s.save(baz2);
+		Baz baz3 = new Baz();
+		stringSet = new TreeSet();
+		stringSet.add("foo");
+		stringSet.add("baz");
+		baz3.setStringSet(stringSet);
+		s.save(baz3);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		baz2 = (Baz) s.load( Baz.class, baz2.getCode() );
+		baz3 = (Baz) s.load( Baz.class, baz3.getCode() );
+		assertFalse( Hibernate.isInitialized(baz.getFooSet()) || Hibernate.isInitialized(baz2.getFooSet()) || Hibernate.isInitialized(baz3.getFooSet()) );
+		assertFalse( Hibernate.isInitialized(baz.getStringSet()) || Hibernate.isInitialized(baz2.getStringSet()) || Hibernate.isInitialized(baz3.getStringSet()) );
+		assertTrue( baz.getFooSet().size()==3 );
+		assertTrue( Hibernate.isInitialized(baz.getFooSet()) && Hibernate.isInitialized(baz2.getFooSet()) && Hibernate.isInitialized(baz3.getFooSet()));
+		assertTrue( baz2.getFooSet().size()==2 );
+		assertTrue( baz3.getStringSet().contains("baz") );
+		assertTrue( Hibernate.isInitialized(baz.getStringSet()) && Hibernate.isInitialized(baz2.getStringSet()) && Hibernate.isInitialized(baz3.getStringSet()));
+		assertTrue( baz.getStringSet().size()==2 && baz2.getStringSet().size()==0 );
+		s.delete(baz);
+		s.delete(baz2);
+		s.delete(baz3);
+		Iterator iter = new JoinedIterator( new Iterator[] { baz.getFooSet().iterator(), baz2.getFooSet().iterator() } );
+		while ( iter.hasNext() ) s.delete( iter.next() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testFetchInitializedCollection() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		Collection fooBag = new ArrayList();
+		fooBag.add( new Foo() );
+		fooBag.add( new Foo() );
+		baz.setFooBag(fooBag);
+		s.save(baz);
+		s.flush();
+		fooBag = baz.getFooBag();
+		s.find("from Baz baz left join fetch baz.fooBag");
+		assertTrue( fooBag==baz.getFooBag() );
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		Object bag = baz.getFooBag();
+		assertFalse( Hibernate.isInitialized(bag) );
+		s.find("from Baz baz left join fetch baz.fooBag");
+		assertTrue( bag==baz.getFooBag() );
+		assertTrue( baz.getFooBag().size()==2 );
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testLateCollectionAdd() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		List l = new ArrayList();
+		baz.setStringList(l);
+		l.add("foo");
+		Serializable id = s.save(baz);
+		l.add("bar");
+		s.flush();
+		l.add("baz");
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.load(Baz.class, id);
+		assertTrue( baz.getStringList().size()==3 && baz.getStringList().contains("bar") );
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testUpdate() throws Exception {
+		Session s = openSession();
+		Foo foo = new Foo();
+		s.save(foo);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		foo = (Foo) SerializationHelper.deserialize( SerializationHelper.serialize(foo) );
+
+		s = openSession();
+		FooProxy foo2 = (FooProxy) s.load( Foo.class, foo.getKey() );
+		foo2.setString("dirty");
+		foo2.setBoolean( new Boolean(false) );
+		foo2.setBytes( new byte[] { 1,2,3} );
+		foo2.setDate(null);
+		foo2.setShort( new Short("69") );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		foo2.setString("dirty again");
+		s.update(foo2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		foo2.setString("dirty again 2");
+		s.update(foo2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Foo foo3 = new Foo();
+		s.load( foo3, foo.getKey() );
+		// There is an interbase bug that causes null integers to return as 0, also numeric precision is <= 15
+		assertTrue( "update", foo2.equalsFoo(foo3) );
+		s.delete(foo3);
+		s.delete("from Glarch");
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testListRemove() throws Exception {
+		Session s = openSession();
+		Baz b = new Baz();
+		List stringList = new ArrayList();
+		List feeList = new ArrayList();
+		b.setFees(feeList);
+		b.setStringList(stringList);
+		feeList.add( new Fee() );
+		feeList.add( new Fee() );
+		feeList.add( new Fee() );
+		feeList.add( new Fee() );
+		stringList.add("foo");
+		stringList.add("bar");
+		stringList.add("baz");
+		stringList.add("glarch");
+		s.save(b);
+		s.flush();
+		stringList.remove(1);
+		feeList.remove(1);
+		s.flush();
+		s.evict(b);
+		s.refresh(b);
+		assertTrue( b.getFees().size()==3 );
+		stringList = b.getStringList();
+		assertTrue(
+			stringList.size()==3 &&
+			"baz".equals( stringList.get(1) ) &&
+			"foo".equals( stringList.get(0) )
+		);
+		s.delete(b);
+		s.delete("from Fee");
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testFetchInitializedCollectionDupe() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		Collection fooBag = new ArrayList();
+		fooBag.add( new Foo() );
+		fooBag.add( new Foo() );
+		baz.setFooBag(fooBag);
+		s.save(baz);
+		s.flush();
+		fooBag = baz.getFooBag();
+		s.find("from Baz baz left join fetch baz.fooBag");
+		assertTrue( Hibernate.isInitialized(fooBag) );
+		assertTrue( fooBag==baz.getFooBag() );
+		assertTrue( baz.getFooBag().size()==2 );
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		Object bag = baz.getFooBag();
+		assertFalse( Hibernate.isInitialized(bag) );
+		s.find("from Baz baz left join fetch baz.fooBag");
+		assertTrue( Hibernate.isInitialized(bag) );
+		assertTrue( bag==baz.getFooBag() );
+		assertTrue( baz.getFooBag().size()==2 );
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testSortables() throws Exception {
+		Session s = openSession();
+		Baz b = new Baz();
+		b.setName("name");
+		SortedSet ss = new TreeSet();
+		ss.add( new Sortable("foo") );
+		ss.add( new Sortable("bar") );
+		ss.add( new Sortable("baz") );
+		b.setSortablez(ss);
+		s.save(b);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Criteria cr = s.createCriteria(Baz.class);
+		cr.setFetchMode("topGlarchez", FetchMode.LAZY);
+		List result = cr
+			.addOrder( Order.asc("name") )
+			.list();
+		assertTrue( result.size()==1 );
+		b = (Baz) result.get(0);
+		assertTrue( b.getSortablez().size()==3 );
+		assertEquals( ( (Sortable) b.getSortablez().iterator().next() ).getName(), "bar" );
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		result = s.createQuery("from Baz baz left join fetch baz.sortablez order by baz.name asc")
+			.list();
+		b = (Baz) result.get(0);
+		assertTrue( b.getSortablez().size()==3 );
+		assertEquals( ( (Sortable) b.getSortablez().iterator().next() ).getName(), "bar" );
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		result = s.createQuery("from Baz baz order by baz.name asc")
+			.list();
+		b = (Baz) result.get(0);
+		assertTrue( b.getSortablez().size()==3 );
+		assertEquals( ( (Sortable) b.getSortablez().iterator().next() ).getName(), "bar" );
+		s.delete(b);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testFetchList() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		s.save(baz);
+		Foo foo = new Foo();
+		s.save(foo);
+		Foo foo2 = new Foo();
+		s.save(foo2);
+		s.flush();
+		List list = new ArrayList();
+		for ( int i=0; i<5; i++ ) {
+			Fee fee = new Fee();
+			list.add(fee);
+		}
+		baz.setFees(list);
+		list = s.find("from Foo foo, Baz baz left join fetch baz.fees");
+		assertTrue( Hibernate.isInitialized( ( (Baz) ( (Object[]) list.get(0) )[1] ).getFees() ) );
+		s.delete(foo);
+		s.delete(foo2);
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testBagOneToMany() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		List list = new ArrayList();
+		baz.setBazez(list);
+		list.add( new Baz() );
+		s.save(baz);
+		s.flush();
+		list.add( new Baz() );
+		s.flush();
+		list.add( 0, new Baz() );
+		s.flush();
+		s.delete( list.remove(1) );
+		s.flush();
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testQueryLockMode() throws Exception {
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Bar bar = new Bar();
+		s.save(bar);
+		s.flush();
+		bar.setString("changed");
+		Baz baz = new Baz();
+		baz.setFoo(bar);
+		s.save(baz);
+		Query q = s.createQuery("from Foo foo, Bar bar");
+		if ( !(getDialect() instanceof DB2Dialect) ) {
+			q.setLockMode("bar", LockMode.UPGRADE);
+		}
+		Object[] result = (Object[]) q.uniqueResult();
+		Object b = result[0];
+		assertTrue( s.getCurrentLockMode(b)==LockMode.WRITE && s.getCurrentLockMode( result[1] )==LockMode.WRITE );
+		tx.commit();
+		s.disconnect();
+
+		s.reconnect();
+		tx = s.beginTransaction();
+		assertTrue( s.getCurrentLockMode(b)==LockMode.NONE );
+		s.find("from Foo foo");
+		assertTrue( s.getCurrentLockMode(b)==LockMode.NONE );
+		q = s.createQuery("from Foo foo");
+		q.setLockMode("foo", LockMode.READ);
+		q.list();
+		assertTrue( s.getCurrentLockMode(b)==LockMode.READ);
+		s.evict(baz);
+		tx.commit();
+		s.disconnect();
+		
+		s.reconnect();
+		tx = s.beginTransaction();
+		assertTrue( s.getCurrentLockMode(b)==LockMode.NONE );
+		s.delete( s.load( Baz.class, baz.getCode() ) );
+		assertTrue( s.getCurrentLockMode(b)==LockMode.NONE );
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		q = s.createQuery("from Foo foo, Bar bar, Bar bar2");
+		if ( !(getDialect() instanceof DB2Dialect) ) {
+			q.setLockMode("bar", LockMode.UPGRADE);
+		}
+		q.setLockMode("bar2", LockMode.READ);
+		result = (Object[]) q.list().get(0);
+		if ( !(getDialect() instanceof DB2Dialect) ) {
+			assertTrue( s.getCurrentLockMode( result[0] )==LockMode.UPGRADE && s.getCurrentLockMode( result[1] )==LockMode.UPGRADE );
+		}
+		s.delete( result[0] );
+		tx.commit();
+		s.close();
+	}
+
+	public void testManyToManyBag() throws Exception {
+
+		Session s = openSession();
+		Baz baz = new Baz();
+		Serializable id = s.save(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.load(Baz.class, id);
+		baz.getFooBag().add( new Foo() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.load(Baz.class, id);
+		assertTrue( !Hibernate.isInitialized( baz.getFooBag() ) );
+		assertTrue( baz.getFooBag().size()==1 );
+		if ( !(getDialect() instanceof HSQLDialect) ) assertTrue( Hibernate.isInitialized( baz.getFooBag().iterator().next() ) );
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testIdBag() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		s.save(baz);
+		List l = new ArrayList();
+		List l2 = new ArrayList();
+		baz.setIdFooBag(l);
+		baz.setByteBag(l2);
+		l.add( new Foo() );
+		l.add( new Bar() );
+		byte[] bytes = "ffo".getBytes();
+		l2.add(bytes);
+		l2.add( "foo".getBytes() );
+		s.flush();
+		l.add( new Foo() );
+		l.add( new Bar() );
+		l2.add( "bar".getBytes() );
+		s.flush();
+		s.delete( l.remove(3) );
+		bytes[1]='o';
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.load(Baz.class, baz.getCode());
+		assertTrue( baz.getIdFooBag().size()==3 );
+		assertTrue( baz.getByteBag().size()==3 );
+		bytes = "foobar".getBytes();
+		Iterator iter = baz.getIdFooBag().iterator();
+		while ( iter.hasNext() ) s.delete( iter.next() );
+		baz.setIdFooBag(null);
+		baz.getByteBag().add(bytes);
+		baz.getByteBag().add(bytes);
+		assertTrue( baz.getByteBag().size()==5 );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.load(Baz.class, baz.getCode());
+		assertTrue( baz.getIdFooBag().size()==0 );
+		assertTrue( baz.getByteBag().size()==5 );
+		baz.getIdFooBag().add( new Foo() );
+		iter = baz.getByteBag().iterator();
+		iter.next();
+		iter.remove();
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.load(Baz.class, baz.getCode());
+		assertTrue( baz.getIdFooBag().size()==1 );
+		assertTrue( baz.getByteBag().size()==4 );
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	private boolean isOuterJoinFetchingDisabled() {
+		return new Integer(0).equals( ( (SessionFactoryImplementor) getSessions() ).getSettings().getMaximumFetchDepth() );
+	}
+
+	public void testForceOuterJoin() throws Exception {
+
+		if ( isOuterJoinFetchingDisabled() ) return;
+
+		Session s = openSession();
+		Glarch g = new Glarch();
+		FooComponent fc = new FooComponent();
+		fc.setGlarch(g);
+		FooProxy f = new Foo();
+		FooProxy f2 = new Foo();
+		f.setComponent(fc);
+		f.setFoo(f2);
+		s.save(f2);
+		Serializable id = s.save(f);
+		Serializable gid = s.getIdentifier( f.getComponent().getGlarch() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		getSessions().evict(Foo.class);
+
+		s = openSession();
+		f = (FooProxy) s.load(Foo.class, id);
+		assertFalse( Hibernate.isInitialized(f) );
+		assertTrue( Hibernate.isInitialized( f.getComponent().getGlarch() ) ); //outer-join="true"
+		assertFalse( Hibernate.isInitialized( f.getFoo() ) ); //outer-join="auto"
+		assertEquals( s.getIdentifier( f.getComponent().getGlarch() ), gid );
+		s.delete(f);
+		s.delete( f.getFoo() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testEmptyCollection() throws Exception {
+		Session s = openSession();
+		Serializable id = s.save( new Baz() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		Baz baz = (Baz) s.load(Baz.class, id);
+		Set foos = baz.getFooSet();
+		assertTrue( foos.size()==0 );
+		Foo foo = new Foo();
+		foos.add(foo);
+		s.save(foo);
+		s.flush();
+		s.delete(foo);
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testOneToOneGenerator() throws Exception {
+		Session s = openSession();
+		X x = new X();
+		Y y = new Y();
+		x.setY(y);
+		y.setTheX(x);
+		x.getXxs().add( new X.XX(x) );
+		x.getXxs().add( new X.XX(x) );
+		Serializable id = s.save(y);
+		assertEquals( id, s.save(x) );
+		s.flush();
+		assertTrue( s.contains(y) && s.contains(x) );
+		s.connection().commit();
+		s.close();
+		assertEquals( new Long(x.getId()), y.getId() );
+
+		s = openSession();
+		x = new X();
+		y = new Y();
+		x.setY(y);
+		y.setTheX(x);
+		x.getXxs().add( new X.XX(x) );
+		s.save(y);
+		s.flush();
+		assertTrue( s.contains(y) && s.contains(x) );
+		s.connection().commit();
+		s.close();
+		assertEquals( new Long(x.getId()), y.getId() );
+
+		s = openSession();
+		x = new X();
+		y = new Y();
+		x.setY(y);
+		y.setTheX(x);
+		x.getXxs().add( new X.XX(x) );
+		x.getXxs().add( new X.XX(x) );
+		id = s.save(x);
+		assertEquals( id, y.getId() );
+		assertEquals( id, new Long( x.getId() ) );
+		s.flush();
+		assertTrue( s.contains(y) && s.contains(x) );
+		s.delete("from X x");
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testLimit() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		for ( int i=0; i<10; i++ ) s.save( new Foo() );
+		Iterator iter = s.createQuery("from Foo foo")
+			.setMaxResults(4)
+			.setFirstResult(2)
+			.iterate();
+		int count=0;
+		while ( iter.hasNext() ) {
+			iter.next();
+			count++;
+		}
+		assertTrue(count==4);
+		iter = s.createQuery("select distinct foo from Foo foo")
+			.setMaxResults(2)
+			.setFirstResult(2)
+			.list()
+			.iterator();
+		count=0;
+		while ( iter.hasNext() ) {
+			iter.next();
+			count++;
+		}
+		assertTrue(count==2);
+		iter = s.createQuery("select distinct foo from Foo foo")
+		.setMaxResults(3)
+		.list()
+		.iterator();
+		count=0;
+		while ( iter.hasNext() ) {
+			iter.next();
+			count++;
+		}
+		assertTrue(count==3);
+		assertTrue( s.delete("from Foo foo")==10 );
+		txn.commit();
+		s.close();
+	}
+
+	public void testCustom() throws Exception {
+		GlarchProxy g = new Glarch();
+		Multiplicity m = new Multiplicity();
+		m.count = 12;
+		m.glarch = (Glarch) g;
+		g.setMultiple(m);
+		Session s = openSession();
+		Serializable gid = s.save(g);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		g = (Glarch) s.find("from Glarch g where g.multiple.count=12").get(0);
+		s.connection().commit();
+		s.close();
+		
+		s = openSession();
+		g = (Glarch) s.find("from Glarch g where g.multiple.glarch=g and g.multiple.count=12").get(0);
+		assertTrue( g.getMultiple()!=null );
+		assertEquals( g.getMultiple().count, 12 );
+		assertSame(g.getMultiple().glarch, g);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		g = (GlarchProxy) s.load(Glarch.class, gid);
+		assertTrue( g.getMultiple()!=null );
+		assertEquals( g.getMultiple().count, 12 );
+		assertSame(g.getMultiple().glarch, g);
+		s.delete(g);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testSaveAddDelete() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		Set bars = new HashSet();
+		baz.setCascadingBars(bars);
+		s.save(baz);
+		s.flush();
+		baz.getCascadingBars().add( new Bar() );
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testNamedParams() throws Exception {
+		Bar bar = new Bar();
+		Bar bar2 = new Bar();
+		bar.setName("Bar");
+		bar2.setName("Bar Two");
+		bar.setX(10);
+		bar2.setX(1000);Baz baz = new Baz();
+		baz.setCascadingBars( new HashSet() );
+		baz.getCascadingBars().add(bar);
+		bar.setBaz(baz);
+
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		s.save(baz);
+		s.save(bar2);
+
+		List list = s.find("from Bar bar left join bar.baz baz left join baz.cascadingBars b where bar.name like 'Bar %'");
+		Object row = list.iterator().next();
+		assertTrue( row instanceof Object[] && ( (Object[]) row ).length==3 );
+
+		Query q = s.createQuery("select bar, b from Bar bar left join bar.baz baz left join baz.cascadingBars b where bar.name like 'Bar%'");
+		list = q.list();
+		if ( !(getDialect() instanceof SAPDBDialect) ) assertTrue( list.size()==2 );
+
+		q = s.createQuery("select bar, b from Bar bar left join bar.baz baz left join baz.cascadingBars b where ( bar.name in (:nameList) or bar.name in (:nameList) ) and bar.string = :stringVal");
+		HashSet nameList = new HashSet();
+		nameList.add("bar");
+		nameList.add("Bar");
+		nameList.add("Bar Two");
+		q.setParameterList("nameList", nameList);
+		q.setParameter("stringVal", "a string");
+		list = q.list();
+		if ( !(getDialect() instanceof SAPDBDialect) ) assertTrue( list.size()==2 );
+
+		try {
+			q.setParameterList("nameList", (Collection)null);
+			fail("Should throw an queryexception when passing a null!");
+		} catch (QueryException qe) {
+			//should happen
+		}
+
+
+		if (dialectSupportsEmptyInList("HQL 'x in (:name)'  with EMPTY_LIST.")) { 
+				q.setParameterList("nameList", Collections.EMPTY_LIST);
+			list = q.list();
+			assertTrue( list.size()==0 );
+		}
+
+		q = s.createQuery("select bar, b from Bar bar inner join bar.baz baz inner join baz.cascadingBars b where bar.name like 'Bar%'");
+		Object result = q.uniqueResult();
+		assertTrue( result!=null );
+		q = s.createQuery("select bar, b from Bar bar left join bar.baz baz left join baz.cascadingBars b where bar.name like :name and b.name like :name");
+		q.setString("name", "Bar%");
+		list = q.list();
+		assertTrue( list.size()==1 );
+
+
+		// This test added for issue HB-297 - there is an named parameter in the Order By clause
+		q = s.createQuery("select bar from Bar bar order by ((bar.x - :valueX)*(bar.x - :valueX))");
+		q.setInteger("valueX", bar.getX()+1);
+		list = q.list();
+		assertTrue( ((Bar)list.get(0)).getX() == bar.getX());
+		q.setInteger("valueX", bar2.getX()+1);
+		list = q.list();
+		assertTrue( ((Bar)list.get(0)).getX() == bar2.getX());
+
+		s.delete(baz);
+		s.delete(bar2);
+		txn.commit();
+		s.close();
+	}
+
+	public void testParameterCheck() throws HibernateException {
+		Session s = openSession();
+		try {
+			Query q = s.createQuery("select bar from Bar as bar where bar.x > :myX");
+			q.list();
+			fail("Should throw QueryException for missing myX");
+		}
+		catch (QueryException iae) {
+			// should happen
+		}
+		finally {
+			s.close();
+		}
+
+		s = openSession();
+		try {
+			Query q = s.createQuery("select bar from Bar as bar where bar.x > ?");
+			q.list();
+			fail("Should throw QueryException for missing ?");
+		}
+		catch (QueryException iae) {
+			// should happen
+		}
+		finally {
+			s.close();
+		}
+
+		s = openSession();
+		try {
+			Query q = s.createQuery("select bar from Bar as bar where bar.x > ? or bar.short = 1 or bar.string = 'ff ? bb'");
+			q.setInteger(0, 1);
+			q.list();
+		}
+		catch (QueryException iae) {
+			fail("Should not throw QueryException for missing ?");
+		}
+		finally {
+			s.close();
+		}
+
+		s = openSession();
+		try {
+			Query q = s.createQuery("select bar from Bar as bar where bar.string = ' ? ' or bar.string = '?'");
+			q.list();
+		}
+		catch (QueryException iae) {
+			fail("Should not throw QueryException for ? in quotes");
+		}
+		finally {
+			s.close();
+		}
+
+		s = openSession();
+		try {
+			Query q = s.createQuery("select bar from Bar as bar where bar.string = ? or bar.string = ? or bar.string = ?");
+			q.setParameter(0, "bull");
+			q.setParameter(2, "shit");
+			q.list();
+			fail("should throw exception telling me i have not set parameter 1");
+		}
+		catch (QueryException iae) {
+			// should happen!
+		}
+		finally {
+			s.close();
+		}
+	}
+	public void testDyna() throws Exception {
+		Session s = openSession();
+		GlarchProxy g = new Glarch();
+		g.setName("G");
+		Serializable id = s.save(g);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		g = (GlarchProxy) s.load(Glarch.class, id);
+		assertTrue( g.getName().equals("G") );
+		assertTrue( g.getDynaBean().get("foo").equals("foo") && g.getDynaBean().get("bar").equals( new Integer(66) ) );
+		assertTrue( ! (g instanceof Glarch) );
+		g.getDynaBean().put("foo", "bar");
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		g = (GlarchProxy) s.load(Glarch.class, id);
+		assertTrue( g.getDynaBean().get("foo").equals("bar") && g.getDynaBean().get("bar").equals( new Integer(66) ) );
+		g.setDynaBean(null);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		g = (GlarchProxy) s.load(Glarch.class, id);
+		assertTrue( g.getDynaBean()==null );
+		s.delete(g);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testFindByCriteria() throws Exception {
+		if ( getDialect() instanceof DB2Dialect ) return;
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		Foo f = new Foo();
+		s.save(f);
+		s.flush();
+
+		List list = s.createCriteria(Foo.class)
+			.add( Expression.eq( "integer", f.getInteger() ) )
+			.add( Expression.eqProperty("integer", "integer") )
+			.add( Expression.like( "string", f.getString().toUpperCase() ).ignoreCase() )
+			.add( Expression.in( "boolean", new Boolean[] { f.getBoolean(), f.getBoolean() } ) )
+			.setFetchMode("foo", FetchMode.JOIN)
+			.setFetchMode("baz", FetchMode.SELECT)
+			.setFetchMode("abstracts", FetchMode.JOIN)
+			.list();
+		assertTrue( list.size()==1 && list.get(0)==f );
+
+		list = s.createCriteria(Foo.class).add(
+				Expression.disjunction()
+					.add( Expression.eq( "integer", f.getInteger() ) )
+					.add( Expression.like( "string", f.getString() ) )
+					.add( Expression.eq( "boolean", f.getBoolean() ) )
+			)
+			.add( Expression.isNotNull("boolean") )
+			.list();
+		assertTrue( list.size()==1 && list.get(0)==f );
+
+		Foo example = new Foo();
+		example.setString("a STRing");
+		list = s.createCriteria(Foo.class).add(
+			Example.create(example)
+				.excludeZeroes()
+				.ignoreCase()
+				.excludeProperty("bool")
+				.excludeProperty("char")
+				.excludeProperty("yesno")
+			)
+			.list();
+		assertTrue( "Example API without like did not work correctly, size was " + list.size(), list.size()==1 && list.get(0)==f );
+		example.setString("rin");
+
+		list = s.createCriteria(Foo.class).add(
+			Example.create(example)
+				.excludeZeroes()
+				.enableLike(MatchMode.ANYWHERE)
+				.excludeProperty("bool")
+				.excludeProperty("char")
+				.excludeProperty("yesno")
+			)
+			.list();
+		assertTrue( "Example API without like did not work correctly, size was " + list.size(), list.size()==1 && list.get(0)==f );
+
+		list = s.createCriteria(Foo.class)
+			.add( Expression.or(
+				Expression.and(
+					Expression.eq( "integer", f.getInteger() ),
+					Expression.like( "string", f.getString() )
+				),
+				Expression.eq( "boolean", f.getBoolean() )
+			) )
+			.list();
+		assertTrue( list.size()==1 && list.get(0)==f );
+		list = s.createCriteria(Foo.class)
+			.setMaxResults(5)
+			.addOrder( Order.asc("date") )
+			.list();
+		assertTrue( list.size()==1 && list.get(0)==f );
+		if(!(getDialect() instanceof TimesTenDialect)) {
+			list = s.createCriteria(Foo.class).setMaxResults(0).list();
+			assertTrue( list.size()==0 );
+		}
+		list = s.createCriteria(Foo.class)
+			.setFirstResult(1)
+			.addOrder( Order.asc("date") )
+			.addOrder( Order.desc("string") )
+			.list();
+		assertTrue( list.size()==0 );
+		list = s.createCriteria(Foo.class)
+			.setFetchMode("component.importantDates", FetchMode.EAGER)
+			.list();
+		assertTrue( list.size()==3 );
+
+		list = s.createCriteria(Foo.class)
+			.setFetchMode("component.importantDates", FetchMode.EAGER)
+			.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
+			.list();
+		assertTrue( list.size()==1 );
+
+		f.setFoo( new Foo() );
+		s.save( f.getFoo() );
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		list = s.createCriteria(Foo.class)
+			.add( Expression.eq( "integer", f.getInteger() ) )
+			.add( Expression.like( "string", f.getString() ) )
+			.add( Expression.in( "boolean", new Boolean[] { f.getBoolean(), f.getBoolean() } ) )
+			.add( Expression.isNotNull("foo") )
+			.setFetchMode("foo", FetchMode.EAGER)
+			.setFetchMode("baz", FetchMode.LAZY)
+			.setFetchMode("component.glarch", FetchMode.LAZY)
+			.setFetchMode("foo.baz", FetchMode.LAZY)
+			.setFetchMode("foo.component.glarch", FetchMode.LAZY)
+			.list();
+		f = (Foo) list.get(0);
+		assertTrue( Hibernate.isInitialized( f.getFoo() ) );
+		assertTrue( !Hibernate.isInitialized( f.getComponent().getGlarch() ) );
+
+		s.save( new Bar() );
+		list = s.createCriteria(Bar.class)
+			.list();
+		assertTrue( list.size()==1 );
+		assertTrue( s.createCriteria(Foo.class).list().size()==3 );
+		s.delete( list.get(0) );
+
+		s.delete( f.getFoo() );
+		s.delete(f);
+		txn.commit();
+		s.close();
+	}
+
+	public void testAfterDelete() throws Exception {
+		Session s = openSession();
+		Foo foo = new Foo();
+		s.save(foo);
+		s.flush();
+		s.delete(foo);
+		s.save(foo);
+		s.delete(foo);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testCollectionWhere() throws Exception {
+		Foo foo1 = new Foo();
+		Foo foo2 = new Foo();
+		Baz baz = new Baz();
+		Foo[] arr = new Foo[10];
+		arr[0] = foo1;
+		arr[9] = foo2;
+		Session s = openSession();
+		s.save(foo1);
+		s.save(foo2);
+		baz.setFooArray(arr);
+		s.save(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		assertTrue( baz.getFooArray().length==1 );
+		assertTrue( s.find("from Baz baz join baz.fooArray foo").size()==1 );
+		assertTrue( s.find("from Foo foo").size()==2 );
+		assertTrue( s.filter( baz.getFooArray(), "" ).size()==1 );
+		//assertTrue( s.delete("from java.lang.Object o")==9 );
+		s.delete("from Foo foo");
+		String bazid = baz.getCode();
+		s.delete(baz);
+		int rows=s.connection().createStatement().executeUpdate(
+			"delete from fooArray where id_='" + bazid + "' and i>=8"
+		);
+		assertTrue(rows==1);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testComponentParent() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		BarProxy bar = new Bar();
+		bar.setBarComponent( new FooComponent() );
+		Baz baz = new Baz();
+		baz.setComponents( new FooComponent[] { new FooComponent(), new FooComponent() } );
+		s.save(bar);
+		s.save(baz);
+		t.commit();
+		s.close();
+		s = openSession();
+		t = s.beginTransaction();
+		bar = (BarProxy) s.load(Bar.class, bar.getKey());
+		s.load(baz, baz.getCode());
+		assertTrue( bar.getBarComponent().getParent()==bar );
+		assertTrue( baz.getComponents()[0].getBaz()==baz && baz.getComponents()[1].getBaz()==baz );
+		s.delete(baz);
+		s.delete(bar);
+		t.commit();
+		s.close();
+	}
+
+	public void testCollectionCache() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		baz.setDefaults();
+		s.save(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		s.load( Baz.class, baz.getCode() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void ntestAssociationId() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Bar bar = new Bar();
+		String id = (String) s.save(bar);
+		MoreStuff more = new MoreStuff();
+		more.setName("More Stuff");
+		more.setIntId(12);
+		more.setStringId("id");
+		Stuff stuf = new Stuff();
+		stuf.setMoreStuff(more);
+		more.setStuffs( new ArrayList() );
+		more.getStuffs().add(stuf);
+		stuf.setFoo(bar);
+		stuf.setId(1234);
+		stuf.setProperty( TimeZone.getDefault() );
+		s.save(more);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		assertTrue( s.find(
+			"from Stuff as s where s.foo.id = ? and s.id.id = ? and s.moreStuff.id.intId = ? and s.moreStuff.id.stringId = ?",
+			new Object[] { bar, new Long(1234), new Integer(12), "id" },
+			new Type[] { Hibernate.entity(Foo.class), Hibernate.LONG, Hibernate.INTEGER, Hibernate.STRING }
+		).size()==1 );
+		assertTrue( s.find(
+			"from Stuff as s where s.foo.id = ? and s.id.id = ? and s.moreStuff.name = ?",
+			new Object[] { bar, new Long(1234), "More Stuff" },
+			new Type[] { Hibernate.entity(Foo.class), Hibernate.LONG, Hibernate.STRING }
+		).size()==1 );
+		s.find("from Stuff as s where s.foo.string is not null");
+		assertTrue(
+			s.find("from Stuff as s where s.foo > '0' order by s.foo").size()==1
+		);
+		//s.createCriteria(Stuff.class).createCriteria("id.foo").add( Expression.isNull("foo") ).list();
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		FooProxy foo = (FooProxy) s.load(Foo.class, id);
+		s.load(more, more);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Stuff stuff = new Stuff();
+		stuff.setFoo(foo);
+		stuff.setId(1234);
+		stuff.setMoreStuff(more);
+		s.load(stuff, stuff);
+		assertTrue( stuff.getProperty().equals( TimeZone.getDefault() ) );
+		assertTrue( stuff.getMoreStuff().getName().equals("More Stuff") );
+		s.delete("from MoreStuff");
+		s.delete("from Foo foo");
+		t.commit();
+		s.close();
+	}
+
+	public void testCascadeSave() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Baz baz = new Baz();
+		List list = new ArrayList();
+		list.add( new Fee() );
+		list.add( new Fee() );
+		baz.setFees(list);
+		s.save(baz);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		assertTrue( baz.getFees().size()==2 );
+		s.delete(baz);
+		assertTrue( !s.iterate("from Fee fee").hasNext() );
+		t.commit();
+		s.close();
+
+	}
+
+	public void testCollectionsInSelect() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Foo[] foos = new Foo[] { null, new Foo() };
+		s.save( foos[1] );
+		Baz baz = new Baz();
+		baz.setDefaults();
+		baz.setFooArray(foos);
+		s.save(baz);
+		Baz baz2 = new Baz();
+		baz2.setDefaults();
+		s.save(baz2);
+
+		Bar bar = new Bar();
+		bar.setBaz(baz);
+		s.save(bar);
+
+		List list = s.find("select new Result(foo.string, foo.long, foo.integer) from Foo foo");
+		assertTrue( list.size()==2 && ( list.get(0) instanceof Result ) && ( list.get(1) instanceof Result ) );
+		/*list = s.find("select new Result( baz.name, foo.long, count(elements(baz.fooArray)) ) from Baz baz join baz.fooArray foo group by baz.name, foo.long");
+		assertTrue( list.size()==1 && ( list.get(0) instanceof Result ) );
+		Result r = ((Result) list.get(0) );
+		assertEquals( r.getName(), baz.getName() );
+		assertEquals( r.getCount(), 1 );
+		assertEquals( r.getAmount(), foos[1].getLong().longValue() );*/
+		list = s.find("select new Result( baz.name, max(foo.long), count(foo) ) from Baz baz join baz.fooArray foo group by baz.name");
+		assertTrue( list.size()==1 && ( list.get(0) instanceof Result ) );
+		Result r = ((Result) list.get(0) );
+		assertEquals( r.getName(), baz.getName() );
+		assertEquals( r.getCount(), 1 );
+		assertTrue( r.getAmount() > 696969696969696000l );
+
+
+		//s.find("select max( elements(bar.baz.fooArray) ) from Bar as bar");
+		//The following test is disabled for databases with no subselects...also for Interbase (not sure why).
+		if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof HSQLDialect) /*&& !(dialect instanceof MckoiDialect)*/ && !(getDialect() instanceof SAPDBDialect) && !(getDialect() instanceof PointbaseDialect) )  {
+			s.find("select count(*) from Baz as baz where 1 in indices(baz.fooArray)");
+			s.find("select count(*) from Bar as bar where 'abc' in elements(bar.baz.fooArray)");
+			s.find("select count(*) from Bar as bar where 1 in indices(bar.baz.fooArray)");
+			if ( !(getDialect() instanceof DB2Dialect) &&  !(getDialect() instanceof Oracle9Dialect)  ) {
+				s.find("select count(*) from Bar as bar, bar.component.glarch.proxyArray as g where g.id in indices(bar.baz.fooArray)");
+				s.find("select max( elements(bar.baz.fooArray) ) from Bar as bar, bar.component.glarch.proxyArray as g where g.id in indices(bar.baz.fooArray)");
+			}
+			s.find("select count(*) from Bar as bar where '1' in (from bar.component.glarch.proxyArray g where g.name='foo')");
+			s.find("select count(*) from Bar as bar where '1' in (from bar.component.glarch.proxyArray g where g.name='foo')");
+			s.find("select count(*) from Bar as bar left outer join bar.component.glarch.proxyArray as pg where '1' in (from bar.component.glarch.proxyArray)");
+		}
+
+		list = s.find("from Baz baz left join baz.fooToGlarch join fetch baz.fooArray foo left join fetch foo.foo");
+		assertTrue( list.size()==1 && ( (Object[]) list.get(0) ).length==2 );
+
+		s.find("select baz.name from Bar bar inner join bar.baz baz inner join baz.fooSet foo where baz.name = bar.string");
+		s.find("SELECT baz.name FROM Bar AS bar INNER JOIN bar.baz AS baz INNER JOIN baz.fooSet AS foo WHERE baz.name = bar.string");
+
+		if ( !( getDialect() instanceof HSQLDialect ) ) s.find("select baz.name from Bar bar join bar.baz baz left outer join baz.fooSet foo where baz.name = bar.string");
+
+		s.find("select baz.name from Bar bar join bar.baz baz join baz.fooSet foo where baz.name = bar.string");
+		s.find("SELECT baz.name FROM Bar AS bar JOIN bar.baz AS baz JOIN baz.fooSet AS foo WHERE baz.name = bar.string");
+
+		if ( !( getDialect() instanceof HSQLDialect ) ) {
+			s.find("select baz.name from Bar bar left join bar.baz baz left join baz.fooSet foo where baz.name = bar.string");
+			s.find("select foo.string from Bar bar left join bar.baz.fooSet foo where bar.string = foo.string");
+		}
+
+		s.find("select baz.name from Bar bar left join bar.baz baz left join baz.fooArray foo where baz.name = bar.string");
+		s.find("select foo.string from Bar bar left join bar.baz.fooArray foo where bar.string = foo.string");
+
+		s.find("select bar.string, foo.string from Bar bar inner join bar.baz as baz inner join baz.fooSet as foo where baz.name = 'name'");
+		s.find("select foo from Bar bar inner join bar.baz as baz inner join baz.fooSet as foo");
+		s.find("select foo from Bar bar inner join bar.baz.fooSet as foo");
+
+		s.find("select bar.string, foo.string from Bar bar join bar.baz as baz join baz.fooSet as foo where baz.name = 'name'");
+		s.find("select foo from Bar bar join bar.baz as baz join baz.fooSet as foo");
+		s.find("select foo from Bar bar join bar.baz.fooSet as foo");
+
+		assertTrue( s.find("from Bar bar join bar.baz.fooArray foo").size()==1 );
+
+		assertTrue( s.find("from Bar bar join bar.baz.fooSet foo").size()==0 );
+		assertTrue( s.find("from Bar bar join bar.baz.fooArray foo").size()==1 );
+
+		s.delete(bar);
+
+		if ( getDialect() instanceof DB2Dialect || getDialect() instanceof PostgreSQLDialect ) {
+			s.iterate("select one from One one join one.manies many group by one order by count(many)");
+			s.iterate("select one from One one join one.manies many group by one having count(many) < 5");
+		}
+
+		s.find("from One one join one.manies many where one.id = 1 and many.id = 1");
+		s.iterate("select one.id, elements(one.manies) from One one");
+		s.iterate("select max( elements(one.manies) ) from One one");
+		s.find("select one, elements(one.manies) from One one");
+		//s.iterate("select one, max( elements(one.manies) ) from One one group by one");
+		Iterator iter = s.iterate("select elements(baz.fooArray) from Baz baz where baz.id=?", baz.getCode(), Hibernate.STRING);
+		//WAS: assertTrue( iter.next()==null && iter.next()==foos[1] && !iter.hasNext() );
+		assertTrue( iter.next()==foos[1] && !iter.hasNext() );
+		list = s.find("select elements(baz.fooArray) from Baz baz where baz.id=?", baz.getCode(), Hibernate.STRING);
+		//WAS: assertTrue( list.size()==2 );
+		assertTrue( list.size()==1 );
+		iter = s.iterate("select indices(baz.fooArray) from Baz baz where baz.id=?", baz.getCode(), Hibernate.STRING);
+		//WAS: assertTrue( iter.next().equals( new Integer(0) ) && iter.next().equals( new Integer(1) ) && !iter.hasNext() );
+		assertTrue( iter.next().equals( new Integer(1) ) && !iter.hasNext() );
+
+		//assertTrue( s.iterate("select max( elements(baz.timeArray) ) from Baz baz where baz.id=?", baz.getCode(), Hibernate.STRING).next() instanceof Time );
+		//assertTrue( s.iterate("select max( elements(baz.stringSet) ) from Baz baz where baz.id=?", baz.getCode(), Hibernate.STRING).next().equals("foo") );
+		assertTrue( s.iterate("select size(baz.stringSet) from Baz baz where baz.id=?", baz.getCode(), Hibernate.STRING).next().equals( new Integer(3) ) );
+		//s.find("from One one where sum one.manies.elements =0 or 1 = min one.manies.elements");
+
+		s.find("from Foo foo where foo.component.glarch.id is not null");
+
+		//iter = s.iterate("select baz, max( elements(baz.timeArray) ) from Baz baz group by baz");
+		//while ( iter.hasNext() ) { Object[] arr = (Object[]) iter.next(); System.out.println( arr[0] + " " + arr[1] ); }
+		iter = s.iterate("select baz, size(baz.stringSet), count( distinct elements(baz.stringSet) ), max( elements(baz.stringSet) ) from Baz baz group by baz");
+		while ( iter.hasNext() ) { Object[] arr = (Object[]) iter.next(); System.out.println( arr[0] + " " + arr[1] + " " + arr[2] + " " + arr[3] ); }
+		
+		s.delete(baz);
+		s.delete(baz2);
+		s.delete( foos[1] );
+		t.commit();
+		s.close();
+	}
+
+	public void testNewFlushing() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		Baz baz = new Baz();
+		baz.setDefaults();
+		s.save(baz);
+		s.flush();
+		baz.getStringArray()[0] = "a new value";
+		Iterator iter = s.iterate("from Baz baz");//no flush
+		assertTrue( iter.next()==baz );
+		iter = s.iterate("select elements(baz.stringArray) from Baz baz");
+		boolean found = false;
+		while ( iter.hasNext() ) {
+			if ( iter.next().equals("a new value") ) found = true;
+		}
+		assertTrue(found);
+		baz.setStringArray(null);
+		s.iterate("from Baz baz"); //no flush
+		iter = s.iterate("select elements(baz.stringArray) from Baz baz");
+		assertTrue( !iter.hasNext() );
+		baz.getStringList().add("1E1");
+		iter = s.iterate("from Foo foo");//no flush
+		assertTrue( !iter.hasNext() );
+		iter = s.iterate("select elements(baz.stringList) from Baz baz");
+		found = false;
+		while ( iter.hasNext() ) {
+			if ( iter.next().equals("1E1") ) found = true;
+		}
+		assertTrue(found);
+		baz.getStringList().remove("1E1");
+		iter = s.iterate("select elements(baz.stringArray) from Baz baz"); //no flush
+		iter = s.iterate("select elements(baz.stringList) from Baz baz");
+		found = false;
+		while ( iter.hasNext() ) {
+			if ( iter.next().equals("1E1") ) found = true;
+		}
+		assertTrue(!found);
+
+		List newList = new ArrayList();
+		newList.add("value");
+		baz.setStringList(newList);
+		iter = s.iterate("from Foo foo");//no flush
+		baz.setStringList(null);
+		iter = s.iterate("select elements(baz.stringList) from Baz baz");
+		assertTrue( !iter.hasNext() );
+
+		baz.setStringList(newList);
+		iter = s.iterate("from Foo foo");//no flush
+		iter = s.iterate("select elements(baz.stringList) from Baz baz");
+		assertTrue( iter.hasNext() );
+
+		s.delete(baz);
+		txn.commit();
+		s.close();
+	}
+
+	public void testPersistCollections() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		assertTrue( ( (Long) s.iterate("select count(*) from Bar").next() ).longValue()==0 );
+		assertTrue( s.iterate("select count(*) from Bar b").next().equals( new Long(0) ) );
+		assertFalse( s.iterate("from Glarch g").hasNext() );
+
+		Baz baz = new Baz();
+		s.save(baz);
+		baz.setDefaults();
+		baz.setStringArray( new String[] { "stuff" } );
+		Set bars = new HashSet();
+		bars.add( new Bar() );
+		baz.setCascadingBars(bars);
+		HashMap sgm = new HashMap();
+		sgm.put( "a", new Glarch() );
+		sgm.put( "b", new Glarch() );
+		baz.setStringGlarchMap(sgm);
+		//System.out.println( s.print(baz) );
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		assertTrue( ( (Long) s.iterate("select count(*) from Bar").next() ).longValue()==1 );
+		baz = (Baz) ( (Object[]) s.find("select baz, baz from Baz baz").get(0) )[1];
+		assertTrue( baz.getCascadingBars().size()==1 );
+		//System.out.println( s.print(baz) );
+		Foo foo = new Foo();
+		s.save(foo);
+		Foo foo2 = new Foo() ;
+		s.save(foo2);
+		baz.setFooArray( new Foo[] { foo, foo, null, foo2 } );
+		baz.getFooSet().add(foo);
+		baz.getCustoms().add( new String[] { "new", "custom" } );
+		baz.setStringArray(null);
+		baz.getStringList().set(0, "new value");
+		baz.setStringSet( new TreeSet() );
+		Time time = new java.sql.Time(12345);
+		baz.getTimeArray()[2] = time;
+		//System.out.println(time);
+
+		assertTrue( baz.getStringGlarchMap().size()==1 );
+
+		//The following test is disabled databases with no subselects
+		if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof HSQLDialect) && !(getDialect() instanceof PointbaseDialect) )  {
+			List list = s.find("select foo from Foo foo, Baz baz where foo in elements(baz.fooArray) and 3 = some elements(baz.intArray) and 4 > all indices(baz.intArray)");
+			assertTrue( "collection.elements find", list.size()==2 );
+		}
+		if (!(getDialect() instanceof SAPDBDialect) ) { // SAPDB doesn't like distinct with binary type
+			List list = s.find("select distinct foo from Baz baz join baz.fooArray foo");
+			assertTrue( "collection.elements find", list.size()==2 );
+		}
+
+		List list = s.find("select foo from Baz baz join baz.fooSet foo");
+		assertTrue( "association.elements find", list.size()==1 );
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		assertTrue( ( (Long) s.iterate("select count(*) from Bar").next() ).longValue()==1 );
+		baz = (Baz) s.find("select baz from Baz baz order by baz").get(0);
+		assertTrue( "collection of custom types - added element", baz.getCustoms().size()==4 && baz.getCustoms().get(0)!=null );
+		assertTrue ( "component of component in collection", baz.getComponents()[1].getSubcomponent()!=null );
+		assertTrue( baz.getComponents()[1].getBaz()==baz );
+		assertTrue( "set of objects", ( (FooProxy) baz.getFooSet().iterator().next() ).getKey().equals( foo.getKey() ));
+		assertTrue( "collection removed", baz.getStringArray().length==0 );
+		assertTrue( "changed element", baz.getStringList().get(0).equals("new value"));
+		assertTrue( "replaced set", baz.getStringSet().size()==0 );
+		assertTrue( "array element change", baz.getTimeArray()[2]!=null );
+		assertTrue( baz.getCascadingBars().size()==1 );
+		//System.out.println( s.print(baz) );
+		baz.getStringSet().add("two");
+		baz.getStringSet().add("one");
+		baz.getBag().add("three");
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		baz = (Baz) s.find("select baz from Baz baz order by baz").get(0);
+		assertTrue( baz.getStringSet().size()==2 );
+		assertTrue( baz.getStringSet().first().equals("one") );
+		assertTrue( baz.getStringSet().last().equals("two") );
+		assertTrue( baz.getBag().size()==5 );
+		baz.getStringSet().remove("two");
+		baz.getBag().remove("duplicate");
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		assertTrue( ( (Long) s.iterate("select count(*) from Bar").next() ).longValue()==1 );
+		baz = (Baz) s.load(Baz.class, baz.getCode());
+		assertTrue( baz.getCascadingBars().size()==1 );
+		Bar bar = new Bar();
+		Bar bar2 = new Bar();
+		s.save(bar); s.save(bar2);
+		baz.setTopFoos( new HashSet() );
+		baz.getTopFoos().add(bar);
+		baz.getTopFoos().add(bar2);
+		assertTrue( baz.getCascadingBars().size()==1 );
+		baz.setTopGlarchez( new TreeMap() );
+		GlarchProxy g = new Glarch();
+		s.save(g);
+		baz.getTopGlarchez().put( new Character('G'), g );
+		HashMap map = new HashMap();
+		map.put(bar, g);
+		map.put(bar2, g);
+		baz.setFooToGlarch(map);
+		map = new HashMap();
+		map.put( new FooComponent("name", 123, null, null), bar );
+		map.put( new FooComponent("nameName", 12, null, null), bar );
+		baz.setFooComponentToFoo(map);
+		map = new HashMap();
+		map.put(bar, g);
+		baz.setGlarchToFoo(map);
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		baz = (Baz) s.find("select baz from Baz baz order by baz").get(0);
+		assertTrue( baz.getCascadingBars().size()==1 );
+
+		Session s2 = openSession();
+		Transaction txn2 = s2.beginTransaction();
+		assertTrue( ( (Long) s2.iterate("select count(*) from Bar").next() ).longValue()==3 );
+		Baz baz2 = (Baz) s2.find("select baz from Baz baz order by baz").get(0);
+		Object o = baz2.getFooComponentToFoo().get( new FooComponent("name", 123, null, null) );
+		assertTrue(
+			o==baz2.getFooComponentToFoo().get( new FooComponent("nameName", 12, null, null) ) && o!=null
+		);
+		txn2.commit();
+		s2.close();
+
+		assertTrue( Hibernate.isInitialized( baz.getFooToGlarch() ) );
+		assertTrue( baz.getTopFoos().size()==2 );
+		assertTrue( baz.getTopGlarchez().size()==1 );
+		assertTrue( baz.getTopFoos().iterator().next()!=null );
+		assertTrue( baz.getStringSet().size()==1 );
+		assertTrue( baz.getBag().size()==4 );
+		assertTrue( baz.getFooToGlarch().size()==2 );
+		assertTrue( baz.getFooComponentToFoo().size()==2 );
+		assertTrue( baz.getGlarchToFoo().size()==1 );
+		Iterator iter = baz.getFooToGlarch().keySet().iterator();
+		for (int i=0; i<2; i++ ) assertTrue( iter.next() instanceof BarProxy );
+		FooComponent fooComp = (FooComponent) baz.getFooComponentToFoo().keySet().iterator().next();
+		assertTrue(
+			( (fooComp.getCount()==123 && fooComp.getName().equals("name"))
+			|| (fooComp.getCount()==12 && fooComp.getName().equals("nameName")) )
+			&& ( baz.getFooComponentToFoo().get(fooComp) instanceof BarProxy )
+		);
+		Glarch g2 = new Glarch();
+		s.save(g2);
+		g = (GlarchProxy) baz.getTopGlarchez().get( new Character('G') );
+		baz.getTopGlarchez().put( new Character('H'), g );
+		baz.getTopGlarchez().put( new Character('G'), g2 );
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		baz = (Baz) s.load(Baz.class, baz.getCode());
+		assertTrue( baz.getTopGlarchez().size()==2 );
+		assertTrue( baz.getCascadingBars().size()==1 );
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		assertTrue( ( (Long) s.iterate("select count(*) from Bar").next() ).longValue()==3 );
+		baz = (Baz) s.find("select baz from Baz baz order by baz").get(0);
+		assertTrue( baz.getTopGlarchez().size()==2 );
+		assertTrue( baz.getCascadingBars().size()==1 );
+		txn.commit();
+
+		s.disconnect();
+
+		s2 = (Session) SerializationHelper.deserialize( SerializationHelper.serialize(s) );
+		s.close();
+
+		s2.reconnect();
+		txn2 = s2.beginTransaction();
+		baz = (Baz) s2.load(Baz.class, baz.getCode());
+		assertTrue( ( (Long) s2.iterate("select count(*) from Bar").next() ).longValue()==3 );
+		s2.delete(baz);
+		s2.delete( baz.getTopGlarchez().get( new Character('G') ) );
+		s2.delete( baz.getTopGlarchez().get( new Character('H') ) );
+		int rows = s2.connection().createStatement().executeUpdate("update " + getDialect().openQuote() + "glarchez" + getDialect().closeQuote() + " set baz_map_id=null where baz_map_index='a'");
+		assertTrue(rows==1);
+		assertTrue( s2.delete("from Bar bar")==2 );
+		FooProxy[] arr = baz.getFooArray();
+		assertTrue( "new array of objects", arr.length==4 && arr[1].getKey().equals( foo.getKey() ) );
+		for ( int i=1; i<arr.length; i++ ) {
+			if ( arr[i]!=null) s2.delete(arr[i]);
+		}
+
+		s2.load( Qux.class, new Long(666) ); //nonexistent
+
+		assertTrue( s2.delete("from Glarch g")==1 );
+		txn2.commit();
+
+		s2.disconnect();
+
+		Session s3 = (Session) SerializationHelper.deserialize( SerializationHelper.serialize(s2) );
+		s2.close();
+		//s3.reconnect();
+		assertTrue( s3.load( Qux.class, new Long(666) )!=null ); //nonexistent
+		//s3.disconnect();
+		s3.close();
+	}
+
+	public void testSaveFlush() throws Exception {
+		Session s = openSession();
+		Fee fee = new Fee();
+		s.save( fee, "key" );
+		fee.setFi("blah");
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		fee = (Fee) s.load( Fee.class, fee.getKey() );
+		assertTrue( "blah".equals( fee.getFi() ) );
+		assertTrue( "key".equals( fee.getKey() ) );
+		s.delete(fee);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testCreateUpdate() throws Exception {
+		Session s = openSession();
+		Foo foo = new Foo();
+		s.save(foo);
+		foo.setString("dirty");
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		Foo foo2 = new Foo();
+		s.load( foo2, foo.getKey() );
+		// There is an interbase bug that causes null integers to return as 0, also numeric precision is <= 15
+		assertTrue( "create-update", foo.equalsFoo(foo2) );
+		//System.out.println( s.print(foo2) );
+		s.delete(foo2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		foo = new Foo();
+		s.save(foo, "assignedid");
+		foo.setString("dirty");
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		s.load(foo2, "assignedid");
+		// There is an interbase bug that causes null integers to return as 0, also numeric precision is <= 15
+		assertTrue( "create-update", foo.equalsFoo(foo2) );
+		//System.out.println( s.print(foo2) );
+		s.delete(foo2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testUpdateCollections() throws Exception {
+		Session s = openSession();
+		Holder baz = new Holder();
+		baz.setName("123");
+		Foo f1 = new Foo();
+		Foo f2 = new Foo();
+		Foo f3 = new Foo();
+		One o = new One();
+		baz.setOnes( new ArrayList() );
+		baz.getOnes().add(o);
+		Foo[] foos = new Foo[] { f1, null, f2 };
+		baz.setFooArray(foos);
+		baz.setFoos( new HashSet() );
+		baz.getFoos().add(f1);
+		s.save(f1);
+		s.save(f2);
+		s.save(f3);
+		s.save(o);
+		s.save(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		baz.getOnes().set(0, null);
+		baz.getOnes().add(o);
+		baz.getFoos().add(f2);
+		foos[0] = f3;
+		foos[1] = f1;
+
+		s = openSession();
+		s.saveOrUpdate(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Holder h = (Holder) s.load(Holder.class, baz.getId());
+		assertTrue( h.getOnes().get(0)==null );
+		assertTrue( h.getOnes().get(1)!=null );
+		assertTrue( h.getFooArray()[0]!=null);
+		assertTrue( h.getFooArray()[1]!=null);
+		assertTrue( h.getFooArray()[2]!=null);
+		assertTrue( h.getFoos().size()==2 );
+		s.connection().commit();
+		s.close();
+
+		baz.getFoos().remove(f1);
+		baz.getFoos().remove(f2);
+		baz.getFooArray()[0]=null;
+		baz.getFooArray()[0]=null;
+		baz.getFooArray()[0]=null;
+		s = openSession();
+		s.saveOrUpdate(baz);
+		s.delete("from Foo");
+		baz.getOnes().remove(o);
+		s.delete("from One");
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testCreate() throws Exception {
+		Session s = openSession();
+		Foo foo = new Foo();
+		s.save(foo);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		Foo foo2 = new Foo();
+		s.load( foo2, foo.getKey() );
+		// There is an interbase bug that causes null integers to return as 0, also numeric precision is <= 15
+		assertTrue( "create", foo.equalsFoo(foo2) );
+		s.delete(foo2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testCallback() throws Exception {
+		Session s = openSession();
+		Qux q = new Qux("0");
+		s.save(q);
+		q.setChild( new Qux("1") );
+		s.save( q.getChild() );
+		Qux q2 = new Qux("2");
+		q2.setChild( q.getChild() );
+		Qux q3 = new Qux("3");
+		q.getChild().setChild(q3);
+		s.save(q3);
+		Qux q4 = new Qux("4");
+		q4.setChild(q3);
+		s.save(q4);
+		s.save(q2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		List l = s.find("from Qux");
+		assertTrue( "", l.size()==5);
+		s.delete( l.get(0) );
+		s.delete( l.get(1) );
+		s.delete( l.get(2) );
+		s.delete( l.get(3) );
+		s.delete( l.get(4) );
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testPolymorphism() throws Exception {
+		Session s = openSession();
+		Bar bar = new Bar();
+		s.save(bar);
+		bar.setBarString("bar bar");
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		FooProxy foo = (FooProxy) s.load( Foo.class, bar.getKey() );
+		assertTrue( "polymorphic", foo instanceof BarProxy );
+		assertTrue( "subclass property", ( (BarProxy) foo ).getBarString().equals( bar.getBarString() ) );
+		//System.out.println( s.print(foo) );
+		s.delete(foo);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testRemoveContains() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		baz.setDefaults();
+		s.save(baz);
+		s.flush();
+		assertTrue( s.contains(baz) );
+		s.evict(baz);
+		assertFalse( s.contains(baz) );
+		Baz baz2 = (Baz) s.load( Baz.class, baz.getCode() );
+		assertFalse(baz==baz2);
+		s.delete(baz2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testCollectionOfSelf() throws Exception {
+
+		Session s = openSession();
+		Bar bar = new Bar();
+		s.save(bar);
+		bar.setAbstracts( new HashSet() );
+		bar.getAbstracts().add(bar);
+		Bar bar2 = new Bar();
+		bar.getAbstracts().add(bar2);
+		bar.setFoo(bar);
+		s.save(bar2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		bar.setAbstracts(null);
+		s = openSession();
+		s.load( bar, bar.getKey() );
+		assertTrue( "collection contains self", bar.getAbstracts().size()==2 && bar.getAbstracts().contains(bar) );
+		assertTrue( "association to self", bar.getFoo()==bar );
+		Iterator iter = bar.getAbstracts().iterator();
+		while ( iter.hasNext() ) {
+			s.delete( iter.next() );
+		}
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testFind() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+
+		Bar bar = new Bar();
+		s.save(bar);
+		bar.setBarString("bar bar");
+		bar.setString("xxx");
+		Foo foo = new Foo();
+		s.save(foo);
+		foo.setString("foo bar");
+		s.save( new Foo() );
+		s.save( new Bar() );
+		List list1 = s.find("select foo from Foo foo where foo.string='foo bar'");
+		assertTrue( "find size", list1.size()==1 );
+		assertTrue( "find ==", list1.get(0)==foo );
+		List list2 = s.find("from Foo foo order by foo.string, foo.date");
+		assertTrue( "find size", list2.size()==4 );
+
+		list1 = s.find("from Foo foo where foo.class='B'");
+		assertTrue( "class special property", list1.size()==2);
+		list1 = s.find("from Foo foo where foo.class=Bar");
+		assertTrue( "class special property", list1.size()==2);
+		list1 = s.find("from Foo foo where foo.class=Bar");
+		list2 = s.find("select bar from Bar bar, Foo foo where bar.string = foo.string and not bar=foo");
+		assertTrue( "class special property", list1.size()==2);
+		assertTrue( "select from a subclass", list2.size()==1);
+		Trivial t = new Trivial();
+		s.save(t);
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		list1 = s.find("from Foo foo where foo.string='foo bar'");
+		assertTrue( "find size", list1.size()==1 );
+		// There is an interbase bug that causes null integers to return as 0, also numeric precision is <= 15
+		assertTrue( "find equals", ( (Foo) list1.get(0) ).equalsFoo(foo) );
+		list2 = s.find("select foo from Foo foo");
+		assertTrue( "find size", list2.size()==5 );
+		List list3 = s.find("from Bar bar where bar.barString='bar bar'");
+		assertTrue( "find size", list3.size()==1 );
+		assertTrue( "find same instance", list2.contains( list1.get(0) ) && list2.contains( list2.get(0) ) );
+		assertTrue( s.find("from Trivial").size()==1 );
+		s.delete("from Trivial");
+
+		list2 = s.find("from Foo foo where foo.date = ?", new java.sql.Date(123), Hibernate.DATE);
+		assertTrue ( "find by date", list2.size()==4 );
+		Iterator iter = list2.iterator();
+		while ( iter.hasNext() ) {
+			s.delete( iter.next() );
+		}
+		list2 = s.find("from Foo foo");
+		assertTrue( "find deleted", list2.size()==0);
+		txn.commit();
+		s.close();
+	}
+
+	public void testDeleteRecursive() throws Exception {
+		Session s = openSession();
+		Foo x = new Foo();
+		Foo y = new Foo();
+		x.setFoo(y);
+		y.setFoo(x);
+		s.save(x);
+		s.save(y);
+		s.flush();
+		s.delete(y);
+		s.delete(x);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	/*public void testSubcollections() throws Exception {
+		Session s = sessionsopenSession();
+		Baz baz = new Baz();
+		s.save(baz);
+		baz.setDefaults();
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = sessionsopenSession();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		Set[] setArray = baz.getSetArray();
+		baz.setSetArray(null);
+		baz.setAnotherSetArray(setArray);
+		baz.setAnotherSetList( baz.getSetList() );
+		baz.setSetList(null);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = sessionsopenSession();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		assertTrue( baz.getAnotherSetArray().length==2 && baz.getAnotherSetArray()[0]!=null, "subcollection moved property");
+		assertTrue( baz.getSetArray()==null, "subcollection moved property");
+		assertTrue( baz.getAnotherSetList().size()==4 && baz.getAnotherSetList().get(2)!=null, "subcollection moved role");
+		assertTrue( baz.getSetList()==null, "subcollection moved role");
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}*/
+
+
+	public void testReachability() throws Exception {
+		//first for unkeyed collections
+		Session s = openSession();
+		Baz baz1 = new Baz();
+		s.save(baz1);
+		Baz baz2 = new Baz();
+		s.save(baz2);
+		baz1.setIntArray( new int[] {1 ,2, 3, 4} );
+		baz1.setFooSet( new HashSet() );
+		Foo foo = new Foo();
+		s.save(foo);
+		baz1.getFooSet().add(foo);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz2 = (Baz) s.load( Baz.class, baz2.getCode() );
+		baz1 = (Baz) s.load( Baz.class, baz1.getCode() );
+		baz2.setFooSet( baz1.getFooSet() ); baz1.setFooSet(null);
+		baz2.setIntArray( baz1.getIntArray() ); baz1.setIntArray(null);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		baz2 = (Baz) s.load( Baz.class, baz2.getCode() );
+		baz1 = (Baz) s.load( Baz.class, baz1.getCode() );
+		assertTrue( "unkeyed reachability", baz2.getIntArray().length==4 );
+		assertTrue( "unkeyed reachability", baz2.getFooSet().size()==1 );
+		assertTrue( "unkeyed reachability", baz1.getIntArray().length==0 );
+		assertTrue( "unkeyed reachability", baz1.getFooSet().size()==0 );
+		//System.out.println( s.print(baz1) + s.print(baz2) );
+		FooProxy fp = (FooProxy) baz2.getFooSet().iterator().next();
+		s.delete(fp);
+		s.delete(baz1);
+		s.delete(baz2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		//now for collections of collections
+		s = openSession();
+		baz1 = new Baz();
+		s.save(baz1);
+		baz2 = new Baz();
+		s.save(baz2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		baz2 = (Baz) s.load( Baz.class, baz2.getCode() );
+		baz1 = (Baz) s.load( Baz.class, baz1.getCode() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		baz2 = (Baz) s.load( Baz.class, baz2.getCode() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		baz2 = (Baz) s.load( Baz.class, baz2.getCode() );
+		baz1 = (Baz) s.load( Baz.class, baz1.getCode() );
+		//System.out.println( s.print(baz1) + s.print(baz2) );
+		//System.out.println( s.print(baz1) + s.print(baz2) );
+		s.delete(baz1);
+		s.delete(baz2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		//now for keyed collections
+		s = openSession();
+		baz1 = new Baz();
+		s.save(baz1);
+		baz2 = new Baz();
+		s.save(baz2);
+		Foo foo1 = new Foo();
+		Foo foo2 = new Foo();
+		s.save(foo1); s.save(foo2);
+		baz1.setFooArray( new Foo[] { foo1, null, foo2 } );
+		baz1.setStringDateMap( new TreeMap() );
+		baz1.getStringDateMap().put("today", new Date( System.currentTimeMillis() ) );
+		baz1.getStringDateMap().put("tomorrow", new Date( System.currentTimeMillis() + 86400000 ) );
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		baz2 = (Baz) s.load( Baz.class, baz2.getCode() );
+		baz1 = (Baz) s.load( Baz.class, baz1.getCode() );
+		baz2.setFooArray( baz1.getFooArray() ); baz1.setFooArray(null);
+		baz2.setStringDateMap( baz1.getStringDateMap() ); baz1.setStringDateMap(null);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		baz2 = (Baz) s.load( Baz.class, baz2.getCode() );
+		baz1 = (Baz) s.load( Baz.class, baz1.getCode() );
+		assertTrue( "reachability", baz2.getStringDateMap().size()==2 );
+		assertTrue( "reachability", baz2.getFooArray().length==3 );
+		assertTrue( "reachability", baz1.getStringDateMap().size()==0 );
+		assertTrue( "reachability", baz1.getFooArray().length==0 );
+		//System.out.println( s.print(baz1) + s.print(baz2) );
+		assertTrue( "null element", baz2.getFooArray()[1]==null );
+		assertTrue( "non-null element", baz2.getStringDateMap().get("today")!=null );
+		assertTrue( "non-null element", baz2.getStringDateMap().get("tomorrow")!=null );
+		assertTrue( "null element", baz2.getStringDateMap().get("foo")==null );
+		s.delete( baz2.getFooArray()[0] );
+		s.delete( baz2.getFooArray()[2] );
+		s.delete(baz1);
+		s.delete(baz2);
+		s.flush();
+		assertTrue( s.find("from java.lang.Object").size()==0 );
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testPersistentLifecycle() throws Exception {
+		Session s = openSession();
+		Qux q = new Qux();
+		s.save(q);
+		q.setStuff("foo bar baz qux");
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		q = (Qux) s.load( Qux.class, q.getKey() );
+		assertTrue( "lifecycle create", q.getCreated() );
+		assertTrue( "lifecycle load", q.getLoaded() );
+		assertTrue( "lifecycle subobject", q.getFoo()!=null );
+		s.delete(q);
+		assertTrue( "lifecycle delete", q.getDeleted() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		assertTrue( "subdeletion", s.find("from Foo foo").size()==0);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testIterators() throws Exception {
+		Session s = openSession();
+		for ( int i=0; i<10; i++ ) {
+			Qux q = new Qux();
+			Object qid = s.save(q);
+			assertTrue("not null", qid!=null);
+		}
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Iterator iter = s.iterate("from Qux q where q.stuff is null");
+		int count=0;
+		while ( iter.hasNext() ) {
+			Qux q = (Qux) iter.next();
+			q.setStuff("foo");
+			if (count==0 || count==5) iter.remove();
+			count++;
+		}
+		assertTrue("iterate", count==10);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		assertTrue(
+			"delete by query",
+			s.delete("from Qux q where q.stuff=?", "foo", Hibernate.STRING)==8
+		);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		iter = s.iterate("from Qux q");
+		assertTrue( "empty iterator", !iter.hasNext() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testVersioning() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		GlarchProxy g = new Glarch();
+		s.save(g);
+		GlarchProxy g2 = new Glarch();
+		s.save(g2);
+		Serializable gid = s.getIdentifier(g);
+		Serializable g2id = s.getIdentifier(g2);
+		g.setName("glarch");
+		txn.commit();
+		s.close();
+
+		getSessions().evict(Glarch.class);
+
+		s = openSession();
+		txn = s.beginTransaction();
+		g = (GlarchProxy) s.load( Glarch.class, gid );
+		s.lock(g, LockMode.UPGRADE);
+		g2 = (GlarchProxy) s.load( Glarch.class, g2id );
+		assertTrue( "version", g.getVersion()==1 );
+		assertTrue( "version", g.getDerivedVersion()==1 );
+		assertTrue( "version", g2.getVersion()==0 );
+		g.setName("foo");
+		assertTrue(
+			"find by version",
+			s.find("from Glarch g where g.version=2").size()==1
+		);
+		g.setName("bar");
+		txn.commit();
+		s.close();
+
+		getSessions().evict(Glarch.class);
+
+		s = openSession();
+		txn = s.beginTransaction();
+		g = (GlarchProxy) s.load( Glarch.class, gid );
+		g2 = (GlarchProxy) s.load( Glarch.class, g2id );
+		assertTrue( "version", g.getVersion()==3 );
+		assertTrue( "version", g.getDerivedVersion()==3 );
+		assertTrue( "version", g2.getVersion()==0 );
+		g.setNext(null);
+		g2.setNext(g);
+		s.delete(g2);
+		s.delete(g);
+		txn.commit();
+		s.close();
+	}
+
+	public void testVersionedCollections() throws Exception {
+		Session s = openSession();
+		GlarchProxy g = new Glarch();
+		s.save(g);
+		g.setProxyArray( new GlarchProxy[] { g } );
+		String gid = (String) s.getIdentifier(g);
+		ArrayList list = new ArrayList();
+		list.add("foo");
+		g.setStrings(list);
+		HashSet set = new HashSet();
+		set.add(g);
+		g.setProxySet(set);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		g = (GlarchProxy) s.load(Glarch.class, gid);
+		assertTrue( g.getStrings().size()==1 );
+		assertTrue( g.getProxyArray().length==1 );
+		assertTrue( g.getProxySet().size()==1 );
+		assertTrue( "versioned collection before", g.getVersion()==1 );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		g = (GlarchProxy) s.load(Glarch.class, gid);
+		assertTrue( g.getStrings().get(0).equals("foo") );
+		assertTrue( g.getProxyArray()[0]==g );
+		assertTrue( g.getProxySet().iterator().next()==g );
+		assertTrue( "versioned collection before", g.getVersion()==1 );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		g = (GlarchProxy) s.load(Glarch.class, gid);
+		assertTrue( "versioned collection before", g.getVersion()==1 );
+		g.getStrings().add("bar");
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		g = (GlarchProxy) s.load(Glarch.class, gid);
+		assertTrue( "versioned collection after", g.getVersion()==2 );
+		assertTrue( "versioned collection after", g.getStrings().size()==2 );
+		g.setProxyArray(null);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		g = (GlarchProxy) s.load(Glarch.class, gid);
+		assertTrue( "versioned collection after", g.getVersion()==3 );
+		assertTrue( "versioned collection after", g.getProxyArray().length==0 );
+		g.setFooComponents( new ArrayList() );
+		g.setProxyArray(null);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		g = (GlarchProxy) s.load(Glarch.class, gid);
+		assertTrue( "versioned collection after", g.getVersion()==4 );
+		s.delete(g);
+		s.flush();
+		assertTrue( s.find("from java.lang.Object").size()==0 );
+		s.connection().commit();
+		s.close();
+	}
+
+	/*public void testVersionedSubcollections() throws Exception {
+		Session s = sessionsopenSession();
+
+		assertTrue( !s.iterate("from Fee fee").hasNext() );
+
+		GlarchProxy g = new Glarch();
+		s.save(g);
+		String gid = (String) s.getIdentifier(g);
+		HashMap map = new HashMap();
+		HashSet subSet  = new HashSet();
+		map.put("xxx", subSet);
+		subSet.add("foo"); subSet.add("bar");
+		g.setStringSets(map);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = sessionsopenSession();
+		g = (GlarchProxy) s.load(Glarch.class, gid);
+		assertTrue( g.getVersion()==1, "versioned collection before" );
+		//System.out.println( g.getStringSets().get("xxx") );
+		assertTrue( ( (Set) g.getStringSets().get("xxx") ).size()==2, "versioned collection before" );
+		( (Set) g.getStringSets().get("xxx") ).add("baz");
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = sessionsopenSession();
+		g = (GlarchProxy) s.load(Glarch.class, gid);
+		assertTrue( g.getVersion()==2, "versioned collection after" );
+		//System.out.println( g.getStringSets().get("xxx") );
+		assertTrue( ( (Set) g.getStringSets().get("xxx") ).size()==3, "versioned collection after" );
+		s.delete(g);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		//with components! (note: this also tests some stuff testPersistCollections misses)
+		s = sessionsopenSession();
+		g = new Glarch(); //(GlarchProxy) s.create(Glarch.class);
+		List list = new ArrayList();
+		Date[] dates = new Date[] { null, null, new Date(), new Date(0) };
+		list.add(null);
+		list.add( new FooComponent("foo", 69, dates, new FooComponent("bar", 96, null, null, new Fee() ) ) );
+		g.setFooComponents(list);
+		String EIGHT_CHARS = "abcdefgh";
+		s.save(g, EIGHT_CHARS + EIGHT_CHARS + EIGHT_CHARS + EIGHT_CHARS);
+		gid = (String) s.getIdentifier(g);
+		assertTrue( s.iterate("from Fee fee").hasNext() );
+		g.getFooComponents().add( new FooComponent("bar", 96, null, null) );
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = sessionsopenSession();
+		g = (GlarchProxy) s.load(Glarch.class, gid);
+		assertTrue( g.getVersion()==2, "versioned collection before" );
+		( (FooComponent) g.getFooComponents().get(1) ).getImportantDates()[0] = new Date(123567890);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = sessionsopenSession();
+		g = (GlarchProxy) s.load(Glarch.class, gid);
+		assertTrue( g.getVersion()==3, "versioned collection after" );
+		( (FooComponent) g.getFooComponents().get(1) ).getSubcomponent().setName("new name");
+		assertTrue( ( (FooComponent) g.getFooComponents().get(1) ).getImportantDates()[0]!=null, "versioned collection after" );
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = sessionsopenSession();
+		g = (GlarchProxy) s.load(Glarch.class, gid);
+		assertTrue( ( (FooComponent) g.getFooComponents().get(1) ).getSubcomponent().getName().equals("new name"), "versioned collection after" );
+		assertTrue( g.getVersion()==4, "versioned collection after" );
+		s.delete(g);
+		assertTrue( !s.iterate("from Fee fee").hasNext() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+
+	}*/
+
+	public void testRecursiveLoad() throws Exception {
+		//Non polymorphic class (there is an implementation optimization
+		//being tested here)
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		GlarchProxy last = new Glarch();
+		s.save(last);
+		last.setOrder( (short) 0 );
+		for (int i=0; i<5; i++) {
+			GlarchProxy next = new Glarch();
+			s.save(next);
+			last.setNext(next);
+			last = next;
+			last.setOrder( (short) (i+1) );
+		}
+		Iterator iter = s.iterate("from Glarch g");
+		while ( iter.hasNext() ) {
+			iter.next();
+		}
+		List list = s.find("from Glarch g");
+		assertTrue( "recursive find", list.size()==6 );
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		list = s.find("from Glarch g");
+		assertTrue( "recursive iter", list.size()==6 );
+		list = s.find("from Glarch g where g.next is not null");
+		assertTrue( "recursive iter", list.size()==5 );
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		iter = s.iterate("from Glarch g order by g.order asc");
+		while ( iter.hasNext() ) {
+			GlarchProxy g = (GlarchProxy) iter.next();
+			assertTrue( "not null", g!=null );
+			iter.remove();
+		}
+		txn.commit();
+		s.close();
+
+		//Same thing but using polymorphic class (no optimisation possible):
+		s = openSession();
+		txn = s.beginTransaction();
+		FooProxy flast = new Bar();
+		s.save(flast);
+		flast.setString( "foo0" );
+		for (int i=0; i<5; i++) {
+			FooProxy foo = new Bar();
+			s.save(foo);
+			flast.setFoo(foo);
+			flast = flast.getFoo();
+			flast.setString( "foo" + (i+1) );
+		}
+		iter = s.iterate("from Foo foo");
+		while ( iter.hasNext() ) {
+			iter.next();
+		}
+		list = s.find("from Foo foo");
+		assertTrue( "recursive find", list.size()==6 );
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		list = s.find("from Foo foo");
+		assertTrue( "recursive iter", list.size()==6 );
+		iter = list.iterator();
+		while ( iter.hasNext() ) {
+			assertTrue( "polymorphic recursive load", iter.next() instanceof BarProxy );
+		}
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		iter = s.iterate("from Foo foo order by foo.string asc");
+		while ( iter.hasNext() ) {
+			BarProxy bar = (BarProxy) iter.next();
+			assertTrue( "not null", bar!=null );
+			iter.remove();
+		}
+		txn.commit();
+		s.close();
+	}
+
+	public void testScrollableIterator() throws Exception {
+		if ( getDialect() instanceof DB2Dialect || getDialect() instanceof OracleDialect || getDialect() instanceof SybaseDialect || getDialect() instanceof HSQLDialect ) {
+			Session s = openSession();
+			Transaction txn = s.beginTransaction();
+			s.save( new Foo() );
+			s.save( new Foo() );
+			s.save( new Foo() );
+			s.save( new Bar() );
+			Query query = s.createQuery("select f, f.integer from Foo f");
+			assertTrue( query.getReturnTypes().length==2 );
+			ScrollableResults iter = query.scroll();
+			assertTrue( iter.next() );
+			assertTrue( iter.scroll(1) );
+			FooProxy f2 = (FooProxy) iter.get()[0];
+			assertTrue( f2!=null );
+			assertTrue( iter.scroll(-1) );
+			Object f1 = iter.get(0);
+			iter.next();
+			assertTrue( f1!=null && iter.get(0)==f2 );
+			iter.getInteger(1);
+
+			assertTrue( !iter.scroll(100) );
+			assertTrue( iter.first() );
+			assertTrue( iter.scroll(3) );
+			Object f4 = iter.get(0);
+			assertTrue( f4!=null );
+			assertTrue( !iter.next() );
+			assertTrue( iter.first() );
+			assertTrue( iter.get(0)==f1 );
+			assertTrue( iter.last() );
+			assertTrue( iter.get(0)==f4 );
+			assertTrue( iter.previous() );
+			txn.commit();
+			s.close();
+
+			s = openSession();
+			txn = s.beginTransaction();
+			query = s.createQuery("select f, f.integer from Foo f");
+			assertTrue( query.getReturnTypes().length==2 );
+			iter = query.scroll();
+			assertTrue( iter.next() );
+			assertTrue( iter.scroll(1) );
+			f2 = (FooProxy) iter.get()[0];
+			assertTrue( f2!=null );
+			assertTrue( f2.getString()!=null  && f2.getComponent().getImportantDates().length > 0 );
+			assertTrue( iter.scroll(-1) );
+			f1 = iter.get(0);
+			iter.next();
+			assertTrue( f1!=null && iter.get(0)==f2 );
+			iter.getInteger(1);
+
+			assertTrue( !iter.scroll(100) );
+			assertTrue( iter.first() );
+			assertTrue( iter.scroll(3) );
+			f4 = iter.get(0);
+			assertTrue( f4!=null );
+			assertTrue( !iter.next() );
+			assertTrue( iter.first() );
+			assertTrue( iter.get(0)==f1 );
+			assertTrue( iter.last() );
+			assertTrue( iter.get(0)==f4 );
+			assertTrue( iter.previous() );
+			assertTrue( s.delete("from Foo")==4 );
+			s.flush();
+			assertTrue( s.find("from java.lang.Object").size()==0 );
+			txn.commit();
+			s.close();
+		}
+	}
+
+	public void testMultiColumnQueries() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		Foo foo = new Foo();
+		s.save(foo);
+		Foo foo1 = new Foo();
+		s.save(foo1);
+		foo.setFoo(foo1);
+		List l = s.find("select parent, child from Foo parent, Foo child where parent.foo = child");
+		assertTrue( "multi-column find", l.size()==1 );
+
+		Iterator rs = s.iterate("select count(distinct child.id), count(distinct parent.id) from Foo parent, Foo child where parent.foo = child");
+		Object[] row = (Object[]) rs.next();
+		assertTrue( "multi-column count", ( (Long) row[0] ).intValue()==1 );
+		assertTrue( "multi-column count", ( (Long) row[1] ).intValue()==1 );
+		assertTrue( !rs.hasNext() );
+
+		rs = s.iterate("select child.id, parent.id, child.long from Foo parent, Foo child where parent.foo = child");
+		row = (Object[]) rs.next();
+		assertTrue( "multi-column id", row[0].equals( foo.getFoo().getKey() ) );
+		assertTrue( "multi-column id", row[1].equals( foo.getKey() ) );
+		assertTrue( "multi-column property", row[2].equals( foo.getFoo().getLong() ) );
+		assertTrue( !rs.hasNext() );
+
+		rs = s.iterate("select child.id, parent.id, child.long, child, parent.foo from Foo parent, Foo child where parent.foo = child");
+		row = (Object[]) rs.next();
+		assertTrue(
+			foo.getFoo().getKey().equals( row[0] ) &&
+			foo.getKey().equals( row[1] ) &&
+			foo.getFoo().getLong().equals( row[2] ) &&
+			row[3] == foo.getFoo() &&
+			row[3]==row[4]
+		);
+		assertTrue( !rs.hasNext() );
+
+		row = (Object[]) l.get(0);
+		assertTrue( "multi-column find", row[0]==foo && row[1]==foo.getFoo() );
+		txn.commit();
+		s.close();
+		
+		s = openSession();
+		txn = s.beginTransaction();
+		Iterator iter = s.iterate("select parent, child from Foo parent, Foo child where parent.foo = child and parent.string='a string'");
+		int deletions=0;
+		while ( iter.hasNext() ) {
+			Object[] pnc = (Object[]) iter.next();
+			s.delete( pnc[0] );
+			s.delete( pnc[1] );
+			deletions++;
+		}
+		assertTrue("multi-column iterate", deletions==1);
+		txn.commit();
+		s.close();
+	}
+
+	public void testDeleteTransient() throws Exception {
+		Fee fee = new Fee();
+		Fee fee2 = new Fee();
+		fee2.setAnotherFee(fee);
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		s.save(fee);
+		s.save(fee2);
+		s.flush();
+		fee.setCount(123);
+		tx.commit();
+		s.close();
+		s = openSession();
+		tx = s.beginTransaction();
+		s.delete(fee);
+		s.delete(fee2);
+		//foo.setAnotherFee(null);
+		tx.commit();
+		s.close();
+		s = openSession();
+		tx = s.beginTransaction();
+		assertTrue( s.find("from Fee fee").size()==0 );
+		tx.commit();
+		s.close();
+	}
+
+	public void testDeleteUpdatedTransient() throws Exception {
+		Fee fee = new Fee();
+		Fee fee2 = new Fee();
+		fee2.setAnotherFee(fee);
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		s.save(fee);
+		s.save(fee2);
+		s.flush();
+		fee.setCount(123);
+		tx.commit();
+		s.close();
+		s = openSession();
+		tx = s.beginTransaction();
+		s.update(fee);
+		//fee2.setAnotherFee(null);
+		s.update(fee2);
+		s.delete(fee);
+		s.delete(fee2);
+		tx.commit();
+		s.close();
+		s = openSession();
+		tx = s.beginTransaction();
+		assertTrue( s.find("from Fee fee").size()==0 );
+		tx.commit();
+		s.close();
+	}
+
+	public void testUpdateOrder() throws Exception {
+		Session s = openSession();
+		Fee fee1 = new Fee();
+		s.save(fee1);
+		Fee fee2 = new Fee();
+		fee1.setFee(fee2);
+		fee2.setFee(fee1);
+		fee2.setFees( new HashSet() );
+		Fee fee3 = new Fee();
+		fee3.setFee(fee1);
+		fee3.setAnotherFee(fee2);
+		fee2.setAnotherFee(fee3);
+		s.save(fee3);
+		s.save(fee2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		fee1.setCount(10);
+		fee2.setCount(20);
+		fee3.setCount(30);
+		s.update(fee1);
+		s.update(fee2);
+		s.update(fee3);
+		s.flush();
+		s.delete(fee1);
+		s.delete(fee2);
+		s.delete(fee3);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Transaction tx = s.beginTransaction();
+		assertTrue( s.find("from Fee fee").size()==0 );
+		tx.commit();
+		s.close();
+	}
+
+	public void testUpdateFromTransient() throws Exception {
+		Session s = openSession();
+		Fee fee1 = new Fee();
+		s.save(fee1);
+		Fee fee2 = new Fee();
+		fee1.setFee(fee2);
+		fee2.setFee(fee1);
+		fee2.setFees( new HashSet() );
+		Fee fee3 = new Fee();
+		fee3.setFee(fee1);
+		fee3.setAnotherFee(fee2);
+		fee2.setAnotherFee(fee3);
+		s.save(fee3);
+		s.save(fee2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		fee1.setFi("changed");
+		s = openSession();
+		s.saveOrUpdate(fee1);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		Qux q = new Qux("quxxy");
+		q.setTheKey(0);
+		fee1.setQux(q);
+		s = openSession();
+		s.saveOrUpdate(fee1);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+
+		s = openSession();
+		fee1 = (Fee) s.load( Fee.class, fee1.getKey() );
+		assertTrue( "updated from transient", fee1.getFi().equals("changed") );
+		assertTrue( "unsaved value", fee1.getQux()!=null );
+		s.delete( fee1.getQux() );
+		fee1.setQux(null);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		fee2.setFi("CHANGED");
+		fee2.getFees().add("an element");
+		fee1.setFi("changed again");
+		s = openSession();
+		s.saveOrUpdate(fee2);
+		s.update( fee1, fee1.getKey() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Fee fee = new Fee();
+		s.load( fee, fee2.getKey() );
+		fee1 = (Fee) s.load( Fee.class, fee1.getKey() );
+		assertTrue( "updated from transient", fee1.getFi().equals("changed again") );
+		assertTrue( "updated from transient", fee.getFi().equals("CHANGED") );
+		assertTrue( "updated collection", fee.getFees().contains("an element") );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		fee.getFees().clear();
+		fee.getFees().add("new element");
+		fee1.setFee(null);
+		s = openSession();
+		s.saveOrUpdate(fee);
+		s.saveOrUpdate(fee1);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		s.load( fee, fee.getKey() );
+		assertTrue( "update", fee.getAnotherFee()!=null );
+		assertTrue( "update", fee.getFee()!=null );
+		assertTrue( "update", fee.getAnotherFee().getFee()==fee.getFee() );
+		assertTrue( "updated collection", fee.getFees().contains("new element") );
+		assertTrue( "updated collection", !fee.getFees().contains("an element") );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		fee.setQux( new Qux("quxy") );
+		s = openSession();
+		s.saveOrUpdate(fee);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		fee.getQux().setStuff("xxx");
+		s = openSession();
+		s.saveOrUpdate(fee);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		s.load( fee, fee.getKey() );
+		assertTrue( "cascade update", fee.getQux()!=null );
+		assertTrue( "cascade update", fee.getQux().getStuff().equals("xxx") );
+		assertTrue( "update", fee.getAnotherFee()!=null );
+		assertTrue( "update", fee.getFee()!=null );
+		assertTrue( "update", fee.getAnotherFee().getFee()==fee.getFee() );
+		fee.getAnotherFee().setAnotherFee(null);
+		s.delete(fee);
+		s.delete("from Fee fee");
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Transaction tx = s.beginTransaction();
+		assertTrue( s.find("from Fee fee").size()==0 );
+		tx.commit();
+		s.close();
+	}
+
+	public void testArraysOfTimes() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz() ;
+		s.save(baz);
+		baz.setDefaults();
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+
+		baz.getTimeArray()[2] = new Date(123);
+		baz.getTimeArray()[3] = new java.sql.Time(1234);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testComponents() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		Foo foo = new Foo();
+		foo.setComponent( new FooComponent("foo", 69, null, new FooComponent("bar", 96, null, null) ) );
+		s.save(foo);
+		foo.getComponent().setName("IFA");
+		txn.commit();
+		s.close();
+
+		foo.setComponent(null);
+
+		s = openSession();
+		txn = s.beginTransaction();
+		s.load( foo, foo.getKey() );
+		assertTrue(
+			"save components",
+			foo.getComponent().getName().equals("IFA") &&
+			foo.getComponent().getSubcomponent().getName().equals("bar")
+		);
+		assertTrue( "cascade save via component", foo.getComponent().getGlarch()!=null);
+		foo.getComponent().getSubcomponent().setName("baz");
+		txn.commit();
+		s.close();
+
+		foo.setComponent(null);
+
+		s = openSession();
+		txn = s.beginTransaction();
+		s.load( foo, foo.getKey() );
+		assertTrue(
+			"update components",
+			foo.getComponent().getName().equals("IFA") &&
+			foo.getComponent().getSubcomponent().getName().equals("baz")
+		);
+		s.delete(foo);
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		foo = new Foo();
+		s.save(foo);
+		foo.setCustom( new String[] { "one", "two" } );
+		assertTrue( s.find("from Foo foo where foo.custom.s1 = 'one'").get(0)==foo );
+		s.delete(foo);
+		txn.commit();
+		s.close();
+
+	}
+
+	public void testNoForeignKeyViolations() throws Exception {
+		Session s = openSession();
+		Glarch g1 = new Glarch();
+		Glarch g2 = new Glarch();
+		g1.setNext(g2);
+		g2.setNext(g1);
+		s.save(g1);
+		s.save(g2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		List l = s.find("from Glarch g where g.next is not null");
+		s.delete( l.get(0) );
+		s.delete( l.get(1) );
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testLazyCollections() throws Exception {
+		Session s = openSession();
+		Qux q = new Qux();
+		s.save(q);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		q = (Qux) s.load( Qux.class, q.getKey() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		System.out.println("Two exceptions are supposed to occur:");
+		boolean ok = false;
+		try {
+			q.getMoreFums().isEmpty();
+		}
+		catch (LazyInitializationException e) {
+			ok = true;
+		}
+		assertTrue( "lazy collection with one-to-many", ok );
+
+		ok = false;
+		try {
+			q.getFums().isEmpty();
+		}
+		catch (LazyInitializationException e) {
+			ok = true;
+		}
+		assertTrue( "lazy collection with many-to-many", ok );
+
+		s = openSession();
+		q = (Qux) s.load( Qux.class, q.getKey() );
+		s.delete(q);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testNewSessionLifecycle() throws Exception {
+		Session s = openSession();
+		Serializable fid = null;
+		try {
+			Foo f = new Foo();
+			s.save(f);
+			fid = s.getIdentifier(f);
+			s.flush();
+			s.connection().commit();
+		}
+		catch (Exception e) {
+			s.connection().rollback();
+			throw e;
+		}
+		finally {
+			s.close();
+		}
+		s = openSession();
+		try {
+			Foo f = new Foo();
+			s.delete(f);
+			s.flush();
+			s.connection().commit();
+		}
+		catch (Exception e) {
+			s.connection().rollback();
+		}
+		finally {
+			s.close();
+		}
+		s = openSession();
+		try {
+			Foo f = (Foo) s.load(Foo.class, fid, LockMode.UPGRADE);
+			s.delete(f);
+			s.flush();
+			s.connection().commit();
+		}
+		catch (Exception e) {
+			s.connection().rollback();
+			throw e;
+		}
+		finally {
+			assertTrue( s.close()==null );
+		}
+	}
+
+	public void testDisconnect() throws Exception {
+		Session s = openSession();
+		Foo foo = new Foo();
+		Foo foo2 = new Foo();
+		s.save(foo);
+		s.save(foo2);
+		foo2.setFoo(foo);
+		s.flush();
+		s.connection().commit();
+		s.disconnect();
+		s.reconnect();
+		s.delete(foo);
+		foo2.setFoo(null);
+		s.flush();
+		s.connection().commit();
+		s.disconnect();
+		s.reconnect();
+		s.delete(foo2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+
+
+	public void testOrderBy() throws Exception {
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Foo foo = new Foo();
+		s.save(foo);
+		List list = s.find("select foo from Foo foo, Fee fee where foo.dependent = fee order by foo.string desc, foo.component.count asc, fee.id");
+		assertTrue( "order by", list.size()==1 );
+		Foo foo2 = new Foo();
+		s.save(foo2);
+		foo.setFoo(foo2);
+		list = s.find("select foo.foo, foo.dependent from Foo foo order by foo.foo.string desc, foo.component.count asc, foo.dependent.id");
+		assertTrue( "order by", list.size()==1 );
+		list = s.find("select foo from Foo foo order by foo.dependent.id, foo.dependent.fi");
+		assertTrue( "order by", list.size()==2 );
+		s.delete(foo);
+		s.delete(foo2);
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		Many manyB = new Many();
+		s.save(manyB);
+		One oneB = new One();
+		s.save(oneB);
+		oneB.setValue("b");
+		manyB.setOne(oneB);
+		Many manyA = new Many();
+		s.save(manyA);
+		One oneA = new One();
+		s.save(oneA);
+		oneA.setValue("a");
+		manyA.setOne(oneA);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Iterator it = s.iterate(
+			"SELECT one FROM " +
+			One.class.getName() +
+			" one ORDER BY one.value ASC"
+		);
+		int count = 0;
+		while ( it.hasNext() ) {
+			One one = (One)it.next();
+			switch (count) {
+				case 0:
+				assertTrue("ordering failed", "a".equals(one.getValue()));
+				break;
+				case 1:
+				assertTrue("ordering failed", "b".equals(one.getValue()));
+				break;
+				default:
+				assertTrue("more than two elements", false);
+				break;
+			}
+			count ++;
+		}
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		it = s.iterate(
+			"SELECT many.one FROM " +
+			Many.class.getName() +
+			" many ORDER BY many.one.value ASC, many.one.id"
+		);
+		count = 0;
+		while ( it.hasNext() ) {
+			One one = (One)it.next();
+			switch (count) {
+				case 0:
+				assertTrue("'a' isn't first element", "a".equals(one.getValue()));
+				break;
+				case 1:
+				assertTrue("'b' isn't second element", "b".equals(one.getValue()));
+				break;
+				default:
+				assertTrue("more than two elements", false);
+				break;
+			}
+			count ++;
+		}
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		oneA = (One)s.load(One.class, oneA.getKey());
+		manyA = (Many)s.load(Many.class, manyA.getKey());
+		oneB = (One)s.load(One.class, oneB.getKey());
+		manyB = (Many)s.load(Many.class, manyB.getKey());
+		s.delete(manyA);
+		s.delete(oneA);
+		s.delete(manyB);
+		s.delete(oneB);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testManyToOne() throws Exception {
+		Session s = openSession();
+		One one = new One();
+		s.save(one);
+		one.setValue("yada");
+		Many many = new Many();
+		many.setOne(one);
+		s.save(many);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		one = (One) s.load( One.class, one.getKey() );
+		one.getManies().size();
+		s.connection().commit();
+		s.close();
+
+
+		s = openSession();
+		many = (Many) s.load( Many.class, many.getKey() );
+		assertTrue( "many-to-one assoc", many.getOne()!=null );
+		s.delete( many.getOne() );
+		s.delete(many);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testSaveDelete() throws Exception {
+		Session s = openSession();
+		Foo f = new Foo();
+		s.save(f);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		s.delete( s.load( Foo.class, f.getKey() ) );
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	/*public void testIdNotFound() throws Exception {
+		// The following test is only enabled for MySQL which has no foreign key constraints.
+		// I disabled this test cos it didn't clean up after itself so other tests failed
+		if (db.equals("mysql")) {
+			Session s = sessionsopenSession();
+			Glarch g = (Glarch) s.create(Glarch.class);
+			Glarch g2 = (Glarch) s.create(Glarch.class);
+			g.setNext(g2);
+			Serializable gid = s.getID(g);
+			Serializable g2id = s.getID(g2);
+			s.commit();
+
+			s = sessionsopenSession();
+			g2 = (Glarch) s.load( Glarch.class, g2id );
+			s.delete(g2);
+			s.commit();
+
+			s = sessionsopenSession();
+			boolean ok = false;
+			try {
+				g = (Glarch) s.load( Glarch.class, gid );
+			}
+			catch (HibernateException e) {
+				ok = "id not found or provided object was wrong class".equals(e.getMessage());
+			}
+			catch (java.lang.StackOverflowError soe) {
+				ok = false;
+			}
+			assertTrue( ok, "id not found");
+			s.cancel();
+		}
+	}*/
+
+	public void testProxyArray() throws Exception {
+		Session s = openSession();
+		GlarchProxy g = new Glarch();
+		Glarch g1 = new Glarch();
+		Glarch g2 = new Glarch();
+		g.setProxyArray( new GlarchProxy[] { g1, g2 } );
+		Glarch g3 = new Glarch();
+		s.save(g3);
+		g2.setProxyArray( new GlarchProxy[] {null, g3, g} );
+		Set set = new HashSet();
+		set.add(g1);
+		set.add(g2);
+		g.setProxySet(set);
+		s.save(g);
+		s.save(g1);
+		s.save(g2);
+		Serializable id = s.getIdentifier(g);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		g = (GlarchProxy) s.load(Glarch.class, id);
+		assertTrue( "array of proxies", g.getProxyArray().length==2 );
+		assertTrue( "array of proxies", g.getProxyArray()[0]!=null );
+		assertTrue("deferred load test",g.getProxyArray()[1].getProxyArray()[0]==null );
+		assertTrue("deferred load test",g.getProxyArray()[1].getProxyArray()[2]==g );
+		assertTrue( "set of proxies", g.getProxySet().size()==2 );
+		Iterator iter = s.iterate("from Glarch g");
+		while ( iter.hasNext() ) {
+			iter.next();
+			iter.remove();
+		}
+
+		s.flush();
+		s.connection().commit();
+		s.disconnect();
+		SerializationHelper.deserialize( SerializationHelper.serialize(s) );
+		s.close();
+	}
+
+	public void testCache() throws Exception {
+		Session s = openSession();
+		Immutable im = new Immutable();
+		s.save(im);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		s.load( im, im.getId() );
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		s.load( im, im.getId() );
+		assertTrue(
+			"cached object identity",
+			s.find(
+				"from Immutable im where im = ?",
+				im,
+				Hibernate.entity(Immutable.class)
+			).get(0)==im &&
+			im == s.load( Immutable.class, im.getId() )
+		);
+		s.connection().createStatement().executeUpdate("delete from immut");
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testFindLoad() throws Exception {
+		Session s = openSession();
+		FooProxy foo = new Foo();
+		s.save(foo);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		foo = (FooProxy) s.find("from Foo foo").get(0);
+		FooProxy foo2 = (FooProxy) s.load( Foo.class, foo.getKey() );
+		assertTrue("find returns same object as load", foo==foo2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		foo2 = (FooProxy) s.load( Foo.class, foo.getKey() );
+		foo = (FooProxy) s.find("from Foo foo").get(0);
+		assertTrue("find returns same object as load", foo==foo2);
+		s.delete("from Foo foo");
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testRefresh() throws Exception {
+		Session s = openSession();
+		Foo foo = new Foo();
+		s.save(foo);
+		s.flush();
+		s.connection().createStatement().executeUpdate("update "+getDialect().openQuote()+"foos"+getDialect().closeQuote()+" set long_ = -3");
+		s.refresh(foo);
+		assertTrue( foo.getLong().longValue()==-3l );
+		assertTrue( s.getCurrentLockMode(foo)==LockMode.READ );
+		s.refresh(foo, LockMode.UPGRADE);
+		if ( getDialect().supportsOuterJoinForUpdate() ) {
+			assertTrue( s.getCurrentLockMode(foo)==LockMode.UPGRADE );
+		}
+		s.delete(foo);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testAutoFlush() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		FooProxy foo = new Foo();
+		s.save(foo);
+		assertTrue( "autoflush create", s.find("from Foo foo").size()==1 );
+		foo.setChar( new Character('X') );
+		assertTrue( "autoflush update", s.find("from Foo foo where foo.char='X'").size()==1 );
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		foo = (FooProxy) s.load( Foo.class, foo.getKey() );
+		//s.update( new Foo(), foo.getKey() );
+		//assertTrue( s.find("from Foo foo where not foo.char='X'").size()==1, "autoflush update" );
+		if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof HSQLDialect) && !(getDialect() instanceof PointbaseDialect) )  {
+			foo.setBytes( "osama".getBytes() );
+			assertTrue( "autoflush collection update", s.find("from Foo foo where 111 in elements(foo.bytes)").size()==1 );
+			foo.getBytes()[0] = 69;
+			assertTrue( "autoflush collection update", s.find("from Foo foo where 69 in elements(foo.bytes)").size()==1 );
+		}
+		s.delete(foo);
+		assertTrue( "autoflush delete", s.find("from Foo foo").size()==0 );
+		txn.commit();
+		s.close();
+	}
+
+	public void testVeto() throws Exception {
+		Session s = openSession();
+		Vetoer v = new Vetoer();
+		s.save(v); Serializable id = s.save(v);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		s.update(v, id); s.update(v, id);
+		s.delete(v); s.delete(v);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testSerializableType() throws Exception {
+		Session s = openSession();
+		Vetoer v = new Vetoer();
+		v.setStrings( new String[] { "foo", "bar", "baz" } );
+		s.save(v); Serializable id = s.save(v);
+		v.getStrings()[1] = "osama";
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		v = (Vetoer) s.load(Vetoer.class, id);
+		assertTrue( "serializable type", v.getStrings()[1].equals("osama") );
+		s.delete(v); s.delete(v);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testAutoFlushCollections() throws Exception {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Baz baz = new Baz();
+		baz.setDefaults();
+		s.save(baz);
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		baz = (Baz) s.load(Baz.class, baz.getCode());
+		baz.getStringArray()[0] = "bark";
+		Iterator i = s.iterate("select elements(baz.stringArray) from Baz baz");
+		boolean found = false;
+		while ( i.hasNext() ) {
+			if ( "bark".equals( i.next() ) ) found = true;
+		}
+		assertTrue(found);
+		baz.setStringArray(null);
+		i = s.iterate("select distinct elements(baz.stringArray) from Baz baz");
+		assertTrue( !i.hasNext() );
+		baz.setStringArray( new String[] { "foo", "bar" } );
+		i = s.iterate("select elements(baz.stringArray) from Baz baz");
+		assertTrue( i.hasNext() );
+
+		Foo foo = new Foo();
+		s.save(foo);
+		s.flush();
+		baz.setFooArray( new Foo[] {foo} );
+
+		i = s.iterate("select foo from Baz baz join baz.fooArray foo");
+		found = false;
+		while ( i.hasNext() ) {
+			if ( foo==i.next() ) found = true;
+		}
+		assertTrue(found);
+
+		baz.getFooArray()[0] = null;
+		i = s.iterate("select foo from Baz baz join baz.fooArray foo");
+		assertTrue( !i.hasNext() );
+		baz.getFooArray()[0] = foo;
+		i = s.iterate("select elements(baz.fooArray) from Baz baz");
+		assertTrue( i.hasNext() );
+
+		if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof HSQLDialect) && !(getDialect() instanceof InterbaseDialect) && !(getDialect() instanceof PointbaseDialect) && !(getDialect() instanceof SAPDBDialect) )  {
+			baz.getFooArray()[0] = null;
+			i = s.iterate(
+				"from Baz baz where ? in elements(baz.fooArray)",
+				foo, Hibernate.entity(Foo.class)
+			);
+			assertTrue( !i.hasNext() );
+			baz.getFooArray()[0] = foo;
+			i = s.iterate(
+				"select foo from Foo foo where foo in "
+				+ "(select elt from Baz baz join baz.fooArray elt)"
+			);
+			assertTrue( i.hasNext() );
+		}
+		s.delete(foo);
+		s.delete(baz);
+		tx.commit();
+		s.close();
+
+	}
+
+	public void testUserProvidedConnection() throws Exception {
+		ConnectionProvider dcp = new DriverManagerConnectionProvider();
+		dcp.configure( Environment.getProperties() );
+		Session s = getSessions().openSession( dcp.getConnection() );
+		Transaction tx = s.beginTransaction();
+		s.find("from Fo");
+		tx.commit();
+		Connection c = s.disconnect();
+		assertTrue( c!=null );
+		s.reconnect(c);
+		tx = s.beginTransaction();
+		s.find("from Fo");
+		tx.commit();
+		assertTrue( s.close()==c );
+		c.close();
+	}
+
+	public void testCachedCollection() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		baz.setDefaults();
+		s.save(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		( (FooComponent) baz.getTopComponents().get(0) ).setCount(99);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		assertTrue( ( (FooComponent) baz.getTopComponents().get(0) ).getCount()==99 );
+		s.delete(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testComplicatedQuery() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		Foo foo = new Foo();
+		Serializable id = s.save(foo);
+		assertTrue(id!=null);
+		Qux q = new Qux("q");
+		foo.getDependent().setQux(q);
+		s.save(q);
+		q.getFoo().setString("foo2");
+		//s.flush();
+		//s.connection().commit();
+		assertTrue(
+			s.iterate("from Foo foo where foo.dependent.qux.foo.string = 'foo2'").hasNext()
+		);
+		s.delete(foo);
+		txn.commit();
+		s.close();
+	}
+
+	public void testLoadAfterDelete() throws Exception {
+		Session s = openSession();
+		Foo foo = new Foo();
+		Serializable id = s.save(foo);
+		s.flush();
+		s.delete(foo);
+		boolean err=false;
+		try {
+			s.load(Foo.class, id);
+		}
+		catch (ObjectNotFoundException ode) {
+			err=true;
+		}
+		assertTrue(err);
+		s.flush();
+		err=false;
+		try {
+			( (FooProxy) s.load(Foo.class, id) ).getBool();
+		}
+		catch (ObjectNotFoundException onfe) {
+			err=true;
+		}
+		assertTrue(err);
+		Fo fo = Fo.newFo();
+		id = new FumTest("").fumKey("abc"); //yuck!!
+		s.save(fo, id);
+		s.flush();
+		s.delete(fo);
+		err=false;
+		try {
+			s.load(Fo.class, id);
+		}
+		catch (ObjectNotFoundException ode) {
+			err=true;
+		}
+		assertTrue(err);
+		s.flush();
+		err=false;
+		try {
+			s.load(Fo.class, id);
+		}
+		catch (ObjectNotFoundException onfe) {
+			err=true;
+		}
+		assertTrue(err);
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testObjectType() throws Exception {
+		Session s = openSession();
+		GlarchProxy g = new Glarch();
+		Foo foo = new Foo();
+		g.setAny(foo);
+		Serializable gid = s.save(g);
+		s.save(foo);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		g = (GlarchProxy) s.load(Glarch.class, gid);
+		assertTrue( g.getAny()!=null && g.getAny() instanceof FooProxy );
+		s.delete( g.getAny() );
+		s.delete(g);
+		//s.delete( g.getAny() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+
+	public void testAny() throws Exception {
+		Session s = openSession();
+		One one = new One();
+		BarProxy foo = new Bar();
+		foo.setObject(one);
+		//Serializable oid = s.save(one);
+		Serializable fid = s.save(foo);
+		Serializable oid = one.getKey();
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		assertTrue( s.find(
+			"from Bar bar where bar.object.id = ? and bar.object.class = ?",
+			new Object[] { oid, new Character('O') },
+			new Type[] { Hibernate.LONG, Hibernate.CHARACTER }
+		).size()==1 );
+		assertTrue( s.find(
+			"select one from One one, Bar bar where bar.object.id = one.id and bar.object.class = 'O'"
+		).size()==1 );
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		foo = (BarProxy) s.load(Foo.class, fid);
+		assertTrue( foo.getObject()!=null && foo.getObject() instanceof One && s.getIdentifier( foo.getObject() ).equals(oid) );
+		//s.delete( foo.getObject() );
+		s.delete(foo);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testEmbeddedCompositeID() throws Exception {
+		Session s = openSession();
+		Location l = new Location();
+		l.setCountryCode("AU");
+		l.setDescription("foo bar");
+		l.setLocale( Locale.getDefault() );
+		l.setStreetName("Brunswick Rd");
+		l.setStreetNumber(300);
+		l.setCity("Melbourne");
+		s.save(l);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		s.setFlushMode(FlushMode.NEVER);
+		l = (Location) s.find("from Location l where l.countryCode = 'AU' and l.description='foo bar'").get(0);
+		assertTrue( l.getCountryCode().equals("AU") );
+		assertTrue( l.getCity().equals("Melbourne") );
+		assertTrue( l.getLocale().equals( Locale.getDefault() ) );
+		assertTrue( s.createCriteria(Location.class).add( Expression.eq( "streetNumber", new Integer(300) ) ).list().size()==1 );
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		l.setDescription("sick're");
+		s.update(l);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		l = new Location();
+		l.setCountryCode("AU");
+		l.setDescription("foo bar");
+		l.setLocale(Locale.ENGLISH);
+		l.setStreetName("Brunswick Rd");
+		l.setStreetNumber(300);
+		l.setCity("Melbourne");
+		assertTrue( l==s.load(Location.class, l) );
+		assertTrue( l.getLocale().equals( Locale.getDefault() ) );
+		s.delete(l);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testAutosaveChildren() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Baz baz = new Baz();
+		Set bars = new HashSet();
+		baz.setCascadingBars(bars);
+		s.save(baz);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		baz.getCascadingBars().add( new Bar() );
+		baz.getCascadingBars().add( new Bar() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		assertTrue( baz.getCascadingBars().size()==2 );
+		assertTrue( baz.getCascadingBars().iterator().next()!=null );
+		baz.getCascadingBars().clear(); //test all-delete-orphan;
+		s.flush();
+		assertTrue( s.find("from Bar bar").size()==0 );
+		s.delete(baz);
+		t.commit();
+		s.close();
+	}
+
+	public void testOrphanDelete() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Baz baz = new Baz();
+		Set bars = new HashSet();
+		baz.setCascadingBars(bars);
+		bars.add( new Bar() );
+		bars.add( new Bar() );
+		bars.add( new Bar() );
+		bars.add( new Bar() );
+		s.save(baz);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		bars = baz.getCascadingBars();
+		assertEquals( 4, bars.size() );
+		bars.remove( bars.iterator().next() );
+		assertEquals( 3, s.find("From Bar bar").size() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		baz = (Baz) s.load( Baz.class, baz.getCode() );
+		bars = baz.getCascadingBars();
+		assertEquals( 3, bars.size() );
+		bars.remove( bars.iterator().next() );
+		s.delete(baz);
+		bars.remove( bars.iterator().next() );
+		assertEquals( 0, s.find("From Bar bar").size() );
+		t.commit();
+		s.close();
+
+	}
+
+	public void testTransientOrphanDelete() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Baz baz = new Baz();
+		Set bars = new HashSet();
+		baz.setCascadingBars(bars);
+		bars.add( new Bar() );
+		bars.add( new Bar() );
+		bars.add( new Bar() );
+		List foos = new ArrayList();
+		foos.add( new Foo() );
+		foos.add( new Foo() );
+		baz.setFooBag(foos);
+		s.save(baz);
+		Iterator i = new JoinedIterator( new Iterator[] {foos.iterator(), bars.iterator()} );
+		while ( i.hasNext() ) {
+			FooComponent cmp = ( (Foo) i.next() ).getComponent();
+			s.delete( cmp.getGlarch() );
+			cmp.setGlarch(null);
+		}
+		t.commit();
+		s.close();
+
+		bars.remove( bars.iterator().next() );
+		foos.remove(1);
+		s = openSession();
+		t = s.beginTransaction();
+		s.update(baz);
+		assertEquals( 2, s.find("From Bar bar").size() );
+		assertEquals( 3, s.find("From Foo foo").size() );
+		t.commit();
+		s.close();
+
+		foos.remove(0);
+		s = openSession();
+		t = s.beginTransaction();
+		s.update(baz);
+		bars.remove( bars.iterator().next() );
+		assertEquals( 1, s.find("From Foo foo").size() );
+		s.delete(baz);
+		//s.flush();
+		assertEquals( 0, s.find("From Foo foo").size() );
+		t.commit();
+		s.close();
+
+	}
+
+	public void testProxiesInCollections() throws Exception {
+		Session s = openSession();
+		Baz baz = new Baz();
+		Bar bar = new Bar();
+		Bar bar2 = new Bar();
+		s.save(bar);
+		Serializable bar2id = s.save(bar2);
+		baz.setFooArray( new Foo[] { bar, bar2 } );
+		HashSet set = new HashSet();
+		bar = new Bar();
+		s.save(bar);
+		set.add(bar);
+		baz.setFooSet(set);
+		set = new HashSet();
+		set.add( new Bar() );
+		set.add( new Bar() );
+		baz.setCascadingBars(set);
+		ArrayList list = new ArrayList();
+		list.add( new Foo() );
+		baz.setFooBag(list);
+		Serializable id = s.save(baz);
+		Serializable bid = ( (Bar) baz.getCascadingBars().iterator().next() ).getKey();
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		BarProxy barprox = (BarProxy) s.load(Bar.class, bid);
+		BarProxy bar2prox = (BarProxy) s.load(Bar.class, bar2id);
+		assertTrue(bar2prox instanceof HibernateProxy);
+		assertTrue(barprox instanceof HibernateProxy);
+		baz = (Baz) s.load(Baz.class, id);
+		Iterator i = baz.getCascadingBars().iterator();
+		BarProxy b1 = (BarProxy) i.next();
+		BarProxy b2 = (BarProxy) i.next();
+		assertTrue( ( b1==barprox && !(b2 instanceof HibernateProxy) ) || ( b2==barprox && !(b1 instanceof HibernateProxy) ) ); //one-to-many
+		assertTrue( baz.getFooArray()[0] instanceof HibernateProxy ); //many-to-many
+		assertTrue( baz.getFooArray()[1]==bar2prox );
+		if ( !isOuterJoinFetchingDisabled() ) assertTrue( !(baz.getFooBag().iterator().next() instanceof HibernateProxy) ); //many-to-many outer-join="true"
+		assertTrue( !(baz.getFooSet().iterator().next() instanceof HibernateProxy) ); //one-to-many
+		s.delete("from Baz");
+		s.delete("from Foo");
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testService() throws Exception {
+		HibernateService hs = new HibernateService();
+		hs.setJndiName("SessionFactory");
+		hs.setMapResources("net/sf/hibernate/test/Simple.hbm.xml, net/sf/hibernate/test/Blobber.hbm.xml");
+		hs.setShowSqlEnabled("true");
+		hs.start();
+		hs.stop();
+		hs.setProperty("foo", "bar");
+		hs.start();
+		hs.stop();
+	}
+
+	public void testPSCache() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		for ( int i=0; i<10; i++ ) s.save( new Foo() );
+		Query q = s.createQuery("from Foo");
+		q.setMaxResults(2);
+		q.setFirstResult(5);
+		assertTrue( q.list().size()==2 );
+		q = s.createQuery("from Foo");
+		assertTrue( q.list().size()==10 );
+		assertTrue( q.list().size()==10 );
+		q.setMaxResults(3);
+		q.setFirstResult(3);
+		assertTrue( q.list().size()==3 );
+		q = s.createQuery("from Foo");
+		assertTrue( q.list().size()==10 );
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		q = s.createQuery("from Foo");
+		assertTrue( q.list().size()==10 );
+		q.setMaxResults(5);
+		assertTrue( q.list().size()==5 );
+		s.delete("from Foo");
+		txn.commit();
+		s.close();
+
+	}
+
+	public void testForCertain() throws Exception {
+		Glarch g = new Glarch();
+		Glarch g2 = new Glarch();
+		List set = new ArrayList();
+		set.add("foo");
+		g2.setStrings(set);
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Serializable gid = (Serializable) s.save(g);
+		Serializable g2id = (Serializable) s.save(g2);
+		t.commit();
+		assertTrue( g.getVersion()==0 );
+		assertTrue( g2.getVersion()==0 );
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		g = (Glarch) s.get(Glarch.class, gid);
+		g2 = (Glarch) s.get(Glarch.class, g2id);
+		assertTrue( g2.getStrings().size()==1 );
+		s.delete(g);
+		s.delete(g2);
+		t.commit();
+		s.close();
+
+	}
+
+	public void testBagMultipleElements() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Baz baz = new Baz();
+		baz.setBag( new ArrayList() );
+		baz.setByteBag( new ArrayList() );
+		s.save(baz);
+		baz.getBag().add("foo");
+		baz.getBag().add("bar");
+		baz.getByteBag().add( "foo".getBytes() );
+		baz.getByteBag().add( "bar".getBytes() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		//put in cache
+		baz = (Baz) s.get( Baz.class, baz.getCode() );
+		assertTrue( baz.getBag().size()==2 );
+		assertTrue( baz.getByteBag().size()==2 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		baz = (Baz) s.get( Baz.class, baz.getCode() );
+		assertTrue( baz.getBag().size()==2 );
+		assertTrue( baz.getByteBag().size()==2 );
+		baz.getBag().remove("bar");
+ 		baz.getBag().add("foo");
+ 		baz.getByteBag().add( "bar".getBytes() );
+		t.commit();
+		s.close();
+
+ 		s = openSession();
+ 		t = s.beginTransaction();
+ 		baz = (Baz) s.get( Baz.class, baz.getCode() );
+ 		assertTrue( baz.getBag().size()==2 );
+ 		assertTrue( baz.getByteBag().size()==3 );
+ 		s.delete(baz);
+ 		t.commit();
+ 		s.close();
+ 	}
+
+	public void testWierdSession() throws Exception {
+ 		Session s = openSession();
+ 		Transaction t = s.beginTransaction();
+ 		Serializable id =  s.save( new Foo() );
+ 		t.commit();
+ 		s.close();
+
+ 		s = openSession();
+ 		s.setFlushMode(FlushMode.NEVER);
+		t = s.beginTransaction();
+		Foo foo = (Foo) s.get(Foo.class, id);
+		t.commit();
+		s.disconnect();
+
+		s.reconnect();
+		t = s.beginTransaction();
+		s.flush();
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		foo = (Foo) s.get(Foo.class, id);
+		s.delete(foo);
+		t.commit();
+		s.close();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooComponent.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooComponent.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooComponent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,133 @@
+//$Id: FooComponent.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.Date;
+
+public class FooComponent implements Serializable {
+	
+	int count;
+	String name;
+	Date[] importantDates;
+	FooComponent subcomponent;
+	Fee fee = new Fee();
+	GlarchProxy glarch;
+	private FooProxy parent;
+	private Baz baz;
+	
+	public boolean equals(Object that) {
+		FooComponent fc = (FooComponent) that;
+		return count==fc.count;
+	}
+	
+	public int hashCode() {
+		return count;
+	}
+	
+	public String toString() {
+		String result = "FooComponent: " + name + "=" + count;
+		result+="; dates=[";
+		if ( importantDates!=null) {
+			for ( int i=0; i<importantDates.length; i++ ) {
+				result+=(i==0 ?"":", ") + importantDates[i];
+			}
+		}
+		result+="]";
+		if ( subcomponent!=null ) {
+			result+= " (" + subcomponent + ")";
+		}
+		return result;
+	}
+	
+	public FooComponent() {}
+	
+	FooComponent(String name, int count, Date[] dates, FooComponent subcomponent) {
+		this.name = name;
+		this.count = count;
+		this.importantDates = dates;
+		this.subcomponent = subcomponent;
+	}
+	
+	FooComponent(String name, int count, Date[] dates, FooComponent subcomponent, Fee fee) {
+		this.name = name;
+		this.count = count;
+		this.importantDates = dates;
+		this.subcomponent = subcomponent;
+		this.fee = fee;
+	}
+	
+	public int getCount() {
+		return count;
+	}
+	public void setCount(int count) {
+		this.count = count;
+	}
+	
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+	public Date[] getImportantDates() {
+		return importantDates;
+	}
+	public void setImportantDates(Date[] importantDates) {
+		this.importantDates = importantDates;
+	}
+	
+	public FooComponent getSubcomponent() {
+		return subcomponent;
+	}
+	public void setSubcomponent(FooComponent subcomponent) {
+		this.subcomponent = subcomponent;
+	}
+	
+	private String getNull() {
+		return null;
+	}
+	private void setNull(String str) throws Exception {
+		if (str!=null) throw new Exception("null component property");
+	}
+	public Fee getFee() {
+		return fee;
+	}
+	
+	public void setFee(Fee fee) {
+		this.fee = fee;
+	}
+	
+	public GlarchProxy getGlarch() {
+		return glarch;
+	}
+	
+	public void setGlarch(GlarchProxy glarch) {
+		this.glarch = glarch;
+	}
+	
+	public FooProxy getParent() {
+		return parent;
+	}
+	
+	public void setParent(FooProxy parent) {
+		//if (parent==null) throw new RuntimeException("null parent set");
+		this.parent = parent;
+	}
+	
+	public Baz getBaz() {
+		return baz;
+	}
+	
+	public void setBaz(Baz baz) {
+		this.baz = baz;
+	}
+	
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooProxy.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooProxy.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FooProxy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+package org.hibernate.test.legacy;
+
+public interface FooProxy {
+	public void setNullComponent(FooComponent arg0) throws Exception;
+	public FooComponent getNullComponent();
+	public void setComponent(FooComponent arg0);
+	public FooComponent getComponent();
+	public void setCustom(String[] arg0);
+	public String[] getCustom();
+	public void setBinary(byte[] arg0);
+	public byte[] getBinary();
+	public void setNullBlob(java.io.Serializable arg0);
+	public java.io.Serializable getNullBlob();
+	public void setBlob(java.io.Serializable arg0);
+	public java.io.Serializable getBlob();
+	public void setYesno(boolean arg0);
+	public boolean getYesno();
+	public boolean equalsFoo(Foo arg0);
+	public void disconnect();
+	public String toString();
+	public void setByte(Byte arg0);
+	public Byte getByte();
+	public void setNull(Integer arg0);
+	public Integer getNull();
+	public void setInt(int arg0);
+	public int getInt();
+	public void setBool(boolean arg0);
+	public boolean getBool();
+	public void setZero(float arg0);
+	public float getZero();
+	public void setBytes(byte[] arg0);
+	public byte[] getBytes();
+	public void setBoolean(Boolean arg0);
+	public Boolean getBoolean();
+	public void setDouble(Double arg0);
+	public Double getDouble();
+	public void setFloat(Float arg0);
+	public Float getFloat();
+	public void setShort(Short arg0);
+	public Short getShort();
+	public Character getChar();
+	public void setChar(Character _char);
+	public Long getLong();
+	public void setInteger(Integer arg0);
+	public Integer getInteger();
+	public void setTimestamp(java.util.Date arg0);
+	public java.util.Date getTimestamp();
+	public void setDate(java.util.Date arg0);
+	public java.util.Date getDate();
+	public void setString(String arg0);
+	public String getString();
+	public void setFoo(FooProxy arg0);
+	public FooProxy getFoo();
+	public void setKey(String arg0);
+	public String getKey();
+	public Fee getDependent();
+	public float getFormula();
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fum.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fum.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fum.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+	<class name="org.hibernate.test.legacy.Fum" dynamic-update="true">
+		<!--cache-->
+		<composite-id name="id" unsaved-value="any">
+			<meta attribute="fum">fum</meta>
+			<key-property name="string">
+				<column name="string_" length="10"/>
+			</key-property>
+			<key-property name="short" column="short_"/>
+			<key-property name="date" column="date_" type="date"/>
+		</composite-id>
+		<version name="vid" type="short" access="field"/>
+		<!--version name="lastUpdated" type="calendar"/-->
+		<property name="fum" not-null="true"/>
+		<property name="TString"/>
+		<many-to-one name="fo">
+			<column name="fo_string" length="10"/>
+			<column name="fo_short"/>
+			<column name="fo_date"/>
+		</many-to-one>
+		<set name="friends">
+			<key>
+				<column name="fr_string_" length="10"/>
+				<column name="fr_short_"/>
+				<column name="fr_date_"/>
+			</key>
+			<one-to-many class="org.hibernate.test.legacy.Fum"/>
+		</set>
+		<array name="quxArray">
+			<key>
+				<column name="fum_str_" length="10"/>
+				<column name="fum_sho_"/>
+				<column name="fum_dat_"/>
+			</key>
+			<index column="i"/>
+			<one-to-many class="org.hibernate.test.legacy.Qux"/>
+		</array>
+		<property name="dupe" 
+			column="short_" 
+			insert="false" 
+			update="false" 
+			not-null="true"/>
+		<component name="mapComponent">
+			<property name="count" column="count_"/>
+			<map name="fummap" lazy="true">
+				<key>
+					<column name="fum_str_" length="10"/>
+					<column name="fum_sho_"/>
+					<column name="fum_dat_"/>
+				</key>
+				<index column="fummapindex" type="string"/>
+				<one-to-many class="org.hibernate.test.legacy.Fum"/>
+			</map>
+			<map name="stringmap" outer-join="true">
+				<key>
+					<column name="fum_str_" length="10"/>
+					<column name="fum_sho_"/>
+					<column name="fum_dat_"/>
+				</key>
+				<index column="mapindex" type="string"/>
+				<element column="mapelement" type="string"/>
+			</map>
+		</component>
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fum.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fum.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fum.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,187 @@
+//$Id: Fum.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.sql.SQLException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.CallbackException;
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.classic.Lifecycle;
+
+public class Fum implements Lifecycle, Serializable {
+	private String fum;
+	private FumCompositeID id;
+	private Fum fo;
+	private Qux[] quxArray;
+	private Set friends;
+	private Calendar lastUpdated;
+	private String tString;
+	private short vid;
+	private short dupe;
+	private MapComponent mapComponent = new MapComponent();
+
+	public Fum() {}
+	public Fum(FumCompositeID id) throws SQLException, HibernateException {
+		this.id = id;
+		friends = new HashSet();
+		FumCompositeID fid = new FumCompositeID();
+		fid.setDate( new Date() );
+		fid.setShort( (short) ( id.short_ + 33 ) );
+		fid.setString( id.string_ + "dd" );
+		Fum f = new Fum();
+		f.id = fid;
+		f.fum="FRIEND";
+		friends.add(f);
+	}
+	public String getFum() {
+		return fum;
+	}
+	public void setFum(String fum) {
+		this.fum = fum;
+	}
+
+	public FumCompositeID getId() {
+		return id;
+	}
+	private void setId(FumCompositeID id) {
+		this.id = id;
+	}
+	public Fum getFo() {
+		return fo;
+	}
+	public void setFo(Fum fo) {
+		this.fo = fo;
+	}
+
+	public Qux[] getQuxArray() {
+		return quxArray;
+	}
+	public void setQuxArray(Qux[] quxArray) {
+		this.quxArray = quxArray;
+	}
+
+	public Set getFriends() {
+		return friends;
+	}
+
+	public void setFriends(Set friends) {
+		this.friends = friends;
+	}
+
+
+	public boolean onDelete(Session s) throws CallbackException {
+		if (friends==null) return false;
+		try {
+			Iterator iter = friends.iterator();
+			while ( iter.hasNext() ) {
+				s.delete( iter.next() );
+			}
+		}
+		catch (Exception e) {
+			throw new CallbackException(e);
+		}
+		return false;
+	}
+
+
+	public void onLoad(Session s, Serializable id) {
+	}
+
+
+	public boolean onSave(Session s) throws CallbackException {
+		if (friends==null) return false;
+		try {
+			Iterator iter = friends.iterator();
+			while ( iter.hasNext() ) {
+				s.save( iter.next() );
+			}
+		}
+		catch (Exception e) {
+			throw new CallbackException(e);
+		}
+		return false;
+	}
+
+
+	public boolean onUpdate(Session s) throws CallbackException {
+		return false;
+	}
+
+	public Calendar getLastUpdated() {
+		return lastUpdated;
+	}
+
+	public void setLastUpdated(Calendar calendar) {
+		lastUpdated = calendar;
+	}
+
+	public String getTString() {
+		return tString;
+	}
+
+	public void setTString(String string) {
+		tString = string;
+	}
+
+	public short getDupe() {
+		return dupe;
+	}
+
+	public void setDupe(short s) {
+		dupe = s;
+	}
+
+	public static final class MapComponent implements Serializable {
+		private Map fummap = new HashMap();
+		private Map stringmap = new HashMap();
+		private int count;
+		public Map getFummap() {
+			return fummap;
+		}
+
+		public void setFummap(Map mapcomponent) {
+			this.fummap = mapcomponent;
+		}
+
+		public int getCount() {
+			return count;
+		}
+
+		public void setCount(int count) {
+			this.count = count;
+		}
+
+		public Map getStringmap() {
+			return stringmap;
+		}
+
+		public void setStringmap(Map stringmap) {
+			this.stringmap = stringmap;
+		}
+
+	}
+
+	public MapComponent getMapComponent() {
+		return mapComponent;
+	}
+
+	public void setMapComponent(MapComponent mapComponent) {
+		this.mapComponent = mapComponent;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FumCompositeID.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FumCompositeID.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FumCompositeID.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+//$Id: FumCompositeID.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+public class FumCompositeID implements java.io.Serializable {
+	String string_;
+	java.util.Date date_;
+	short short_;
+	public boolean equals(Object other) {
+		FumCompositeID that = (FumCompositeID) other;
+		return this.string_.equals(that.string_) && this.short_==that.short_;
+	}
+	public int hashCode() {
+		return string_.hashCode();
+	}
+	public String getString() {
+		return string_;
+	}
+	public void setString(String string_) {
+		this.string_ = string_;
+	}
+	public java.util.Date getDate() {
+		return date_;
+	}
+	public void setDate(java.util.Date date_) {
+		this.date_ = date_;
+	}
+	public short getShort() {
+		return short_;
+	}
+	public void setShort(short short_) {
+		this.short_ = short_;
+	}
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FumTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FumTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/FumTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,882 @@
+//$Id: FumTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import junit.framework.Test;
+import junit.textui.TestRunner;
+
+import org.hibernate.Criteria;
+import org.hibernate.FetchMode;
+import org.hibernate.FlushMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.Query;
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.criterion.Expression;
+import org.hibernate.criterion.MatchMode;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.MckoiDialect;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.dialect.PointbaseDialect;
+import org.hibernate.dialect.TimesTenDialect;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.transform.Transformers;
+import org.hibernate.type.DateType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.StringType;
+import org.hibernate.type.Type;
+
+public class FumTest extends LegacyTestCase {
+
+	private static short fumKeyShort = 1;
+
+	public FumTest(String arg) {
+		super(arg);
+	}
+
+	public String[] getMappings() {
+		return new String[] {
+			"legacy/FooBar.hbm.xml",
+			"legacy/Baz.hbm.xml",
+			"legacy/Qux.hbm.xml",
+			"legacy/Glarch.hbm.xml",
+			"legacy/Fum.hbm.xml",
+			"legacy/Fumm.hbm.xml",
+			"legacy/Fo.hbm.xml",
+			"legacy/One.hbm.xml",
+			"legacy/Many.hbm.xml",
+			"legacy/Immutable.hbm.xml",
+			"legacy/Fee.hbm.xml",
+			"legacy/Vetoer.hbm.xml",
+			"legacy/Holder.hbm.xml",
+			"legacy/Location.hbm.xml",
+			"legacy/Stuff.hbm.xml",
+			"legacy/Container.hbm.xml",
+			"legacy/Simple.hbm.xml",
+			"legacy/Middle.hbm.xml"
+		};
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( FumTest.class );
+	}
+
+	public static void main(String[] args) throws Exception {
+		TestRunner.run( suite() );
+	}
+	
+	public void testQuery() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createQuery("from Fum fum where fum.fo.id.string = 'x'").list();
+		t.commit();
+		s.close();
+	}
+
+	public void testCriteriaCollection() throws Exception {
+		Session s = openSession();
+		Fum fum = new Fum( fumKey("fum") );
+		fum.setFum("a value");
+		fum.getMapComponent().getFummap().put("self", fum);
+		fum.getMapComponent().getStringmap().put("string", "a staring");
+		fum.getMapComponent().getStringmap().put("string2", "a notha staring");
+		fum.getMapComponent().setCount(1);
+		s.save(fum);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		Fum b = (Fum) s.createCriteria(Fum.class).add(
+			Expression.in("fum", new String[] { "a value", "no value" } )
+		)
+		.uniqueResult();
+		//assertTrue( Hibernate.isInitialized( b.getMapComponent().getFummap() ) );
+		assertTrue( Hibernate.isInitialized( b.getMapComponent().getStringmap() ) );
+		assertTrue( b.getMapComponent().getFummap().size()==1 );
+		assertTrue( b.getMapComponent().getStringmap().size()==2 );
+		s.delete(b);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testCriteria() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		Fum fum = new Fum( fumKey("fum") );
+		fum.setFo( new Fum( fumKey("fo") ) );
+		fum.setFum("fo fee fi");
+		fum.getFo().setFum("stuff");
+		Fum fr = new Fum( fumKey("fr") );
+		fr.setFum("goo");
+		Fum fr2 = new Fum( fumKey("fr2") );
+		fr2.setFum("soo");
+		fum.setFriends( new HashSet() );
+		fum.getFriends().add(fr);
+		fum.getFriends().add(fr2);
+		s.save(fr);
+		s.save(fr2);
+		s.save( fum.getFo() );
+		s.save(fum);
+
+		Criteria base = s.createCriteria(Fum.class)
+			.add( Expression.like("fum", "f", MatchMode.START) );
+		base.createCriteria("fo")
+			.add( Expression.isNotNull("fum") );
+		base.createCriteria("friends")
+			.add( Expression.like("fum", "g%") );
+		List list = base.list();
+		assertTrue( list.size()==1 && list.get(0)==fum );
+
+		base = s.createCriteria(Fum.class)
+			.add( Expression.like("fum", "f%") )
+			.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
+		base.createCriteria("fo", "fo")
+			.add( Expression.isNotNull("fum") );
+		base.createCriteria("friends", "fum")
+			.add( Expression.like("fum", "g", MatchMode.START) );
+		Map map = (Map) base.uniqueResult();
+
+		assertTrue(
+			map.get("this")==fum &&
+			map.get("fo")==fum.getFo() &&
+			fum.getFriends().contains( map.get("fum") ) &&
+			map.size()==3
+		);
+
+		base = s.createCriteria(Fum.class)
+			.add( Expression.like("fum", "f%") )
+			.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+			.setFetchMode("friends", FetchMode.EAGER);
+		base.createCriteria("fo", "fo")
+			.add( Expression.eq( "fum", fum.getFo().getFum() ) );
+		map = (Map) base.list().get(0);
+
+		assertTrue(
+			map.get("this")==fum &&
+			map.get("fo")==fum.getFo() &&
+			map.size()==2
+		);
+
+		list = s.createCriteria(Fum.class)
+			.createAlias("friends", "fr")
+			.createAlias("fo", "fo")
+			.add( Expression.like("fum", "f%") )
+			.add( Expression.isNotNull("fo") )
+			.add( Expression.isNotNull("fo.fum") )
+			.add( Expression.like("fr.fum", "g%") )
+			.add( Expression.eqProperty("fr.id.short", "id.short") )
+			.list();
+		assertTrue( list.size()==1 && list.get(0)==fum );
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		base = s.createCriteria(Fum.class)
+			.add( Expression.like("fum", "f%") );
+		base.createCriteria("fo")
+			.add( Expression.isNotNull("fum") );
+		base.createCriteria("friends")
+			.add( Expression.like("fum", "g%") );
+		fum = (Fum) base.list().get(0);
+		assertTrue(  fum.getFriends().size()==2 );
+		s.delete(fum);
+		s.delete( fum.getFo() );
+		Iterator iter = fum.getFriends().iterator();
+		while ( iter.hasNext() ) s.delete( iter.next() );
+		txn.commit();
+		s.close();
+	}
+
+	static public class ABean {
+		public Fum fum;
+		public Fum fo;
+		public Fum getFo() {
+			return fo;
+		}
+		public void setFo(Fum fo) {
+			this.fo = fo;
+		}
+		public Fum getFum() {
+			return fum;
+		}
+		public void setFum(Fum fum) {
+			this.fum = fum;
+		}
+	}
+	
+	public void testBeanResultTransformer() throws HibernateException, SQLException {
+		
+		Session s = openSession();
+		Transaction transaction = s.beginTransaction();
+		Fum fum = new Fum( fumKey("fum") );
+		fum.setFo( new Fum( fumKey("fo") ) );
+		fum.setFum("fo fee fi");
+		fum.getFo().setFum("stuff");
+		Fum fr = new Fum( fumKey("fr") );
+		fr.setFum("goo");
+		Fum fr2 = new Fum( fumKey("fr2") );
+		fr2.setFum("soo");
+		fum.setFriends( new HashSet() );
+		fum.getFriends().add(fr);
+		fum.getFriends().add(fr2);
+		s.save(fr);
+		s.save(fr2);
+		s.save( fum.getFo() );
+		s.save(fum);
+		
+		Criteria test = s.createCriteria(Fum.class, "xam")
+			.createCriteria("fo", "fo")
+			.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
+		
+		Map fc = (Map) test.list().get(0);
+		assertNotNull(fc.get("xam"));
+		
+		Criteria base = s.createCriteria(Fum.class, "fum")
+		.add( Expression.like("fum", "f%") )
+		.setResultTransformer(Transformers.aliasToBean(ABean.class))
+		.setFetchMode("friends", FetchMode.JOIN);
+		base.createCriteria("fo", "fo")
+		.add( Expression.eq( "fum", fum.getFo().getFum() ) );
+		ABean map = (ABean) base.list().get(0);
+
+		assertTrue(
+				map.getFum()==fum &&
+				map.getFo()==fum.getFo() );
+		
+		s.delete(fr);
+		s.delete(fr2);
+		s.delete(fum);
+		s.delete(fum.getFo());
+		s.flush();
+		transaction.commit();
+		s.close();
+		
+	}
+	
+	
+	public void testListIdentifiers() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		Fum fum = new Fum( fumKey("fum") );
+		fum.setFum("fo fee fi");
+		s.save(fum);
+		fum = new Fum( fumKey("fi") );
+		fum.setFum("fee fi fo");
+		s.save(fum);
+		List list = s.find("select fum.id from Fum as fum where not fum.fum='FRIEND'");
+		assertTrue( "list identifiers", list.size()==2);
+		Iterator iter = s.iterate("select fum.id from Fum fum where not fum.fum='FRIEND'");
+		int i=0;
+		while ( iter.hasNext() ) {
+			assertTrue( "iterate identifiers",  iter.next() instanceof FumCompositeID);
+			i++;
+		}
+		assertTrue(i==2);
+
+		s.delete( s.load(Fum.class, (Serializable) list.get(0) ) );
+		s.delete( s.load(Fum.class, (Serializable) list.get(1) ) );
+		txn.commit();
+		s.close();
+	}
+
+
+	public FumCompositeID fumKey(String str) {
+
+		return fumKey(str,false);
+	}
+
+	private FumCompositeID fumKey(String str, boolean aCompositeQueryTest) {
+		FumCompositeID id = new FumCompositeID();
+		if ( Dialect.getDialect() instanceof MckoiDialect ) {
+			GregorianCalendar now = new GregorianCalendar();
+			GregorianCalendar cal = new GregorianCalendar(
+				now.get(java.util.Calendar.YEAR),
+				now.get(java.util.Calendar.MONTH),
+				now.get(java.util.Calendar.DATE)
+			);
+			id.setDate( cal.getTime() );
+		}
+		else {
+			id.setDate( new Date() );
+		}
+		id.setString( new String(str) );
+
+		if (aCompositeQueryTest) {
+			id.setShort( fumKeyShort++ );
+		}
+		else {
+			id.setShort( (short) 12 );
+		}
+
+		return id;
+	}
+
+	public void testCompositeID() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		Fum fum = new Fum( fumKey("fum") );
+		fum.setFum("fee fi fo");
+		s.save(fum);
+		assertTrue( "load by composite key", fum==s.load( Fum.class, fumKey("fum") ) );
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		fum = (Fum) s.load( Fum.class, fumKey("fum"), LockMode.UPGRADE );
+		assertTrue( "load by composite key", fum!=null );
+
+		Fum fum2 = new Fum( fumKey("fi") );
+		fum2.setFum("fee fo fi");
+		fum.setFo(fum2);
+		s.save(fum2);
+		assertTrue(
+			"find composite keyed objects",
+			s.find("from Fum fum where not fum.fum='FRIEND'").size()==2
+		);
+		assertTrue(
+			"find composite keyed object",
+			s.find("select fum from Fum fum where fum.fum='fee fi fo'").get(0)==fum
+		);
+		fum.setFo(null);
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		Iterator iter = s.iterate("from Fum fum where not fum.fum='FRIEND'");
+		int i = 0;
+		while ( iter.hasNext() ) {
+			fum = (Fum) iter.next();
+			//iter.remove();
+			s.delete(fum);
+			i++;
+		}
+		assertTrue( "iterate on composite key", i==2 );
+		txn.commit();
+		s.close();
+	}
+
+	public void testCompositeIDOneToOne() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		Fum fum = new Fum( fumKey("fum") );
+		fum.setFum("fee fi fo");
+		//s.save(fum);
+		Fumm fumm = new Fumm();
+		fumm.setFum(fum);
+		s.save(fumm);
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		fumm = (Fumm) s.load( Fumm.class, fumKey("fum") );
+		//s.delete( fumm.getFum() );
+		s.delete(fumm);
+		txn.commit();
+		s.close();
+	}
+
+	public void testCompositeIDQuery() throws Exception {
+		Session s = openSession();
+		Fum fee = new Fum( fumKey("fee",true) );
+		fee.setFum("fee");
+		s.save(fee);
+		Fum fi = new Fum( fumKey("fi",true) );
+		fi.setFum("fi");
+		short fiShort = fi.getId().getShort();
+		s.save(fi);
+		Fum fo = new Fum( fumKey("fo",true) );
+		fo.setFum("fo");
+		s.save(fo);
+		Fum fum = new Fum( fumKey("fum",true) );
+		fum.setFum("fum");
+		s.save(fum);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		// Try to find the Fum object "fo" that we inserted searching by the string in the id
+		List vList = s.find("from Fum fum where fum.id.string='fo'"  );
+		assertTrue( "find by composite key query (find fo object)", vList.size() == 1 );
+		fum = (Fum)vList.get(0);
+		assertTrue( "find by composite key query (check fo object)", fum.getId().getString().equals("fo") );
+
+		// Try to find the Fum object "fi" that we inserted searching by the date in the id
+		vList = s.find("from Fum fum where fum.id.short = ?",new Short(fiShort),Hibernate.SHORT);
+		assertTrue( "find by composite key query (find fi object)", vList.size() == 1 );
+		fi = (Fum)vList.get(0);
+		assertTrue( "find by composite key query (check fi object)", fi.getId().getString().equals("fi") );
+
+		// Make sure we can return all of the objects by searching by the date id
+		assertTrue(
+			"find by composite key query with arguments",
+			s.find("from Fum fum where fum.id.date <= ? and not fum.fum='FRIEND'",new Date(),Hibernate.DATE).size()==4
+		);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		assertTrue(
+			s.iterate("select fum.id.short, fum.id.date, fum.id.string from Fum fum").hasNext()
+		);
+		assertTrue(
+			s.iterate("select fum.id from Fum fum").hasNext()
+		);
+		Query qu = s.createQuery("select fum.fum, fum , fum.fum, fum.id.date from Fum fum");
+		Type[] types = qu.getReturnTypes();
+		assertTrue(types.length==4);
+		for ( int k=0; k<types.length; k++) {
+			assertTrue( types[k]!=null );
+		}
+		assertTrue(types[0] instanceof StringType);
+		assertTrue(types[1] instanceof EntityType);
+		assertTrue(types[2] instanceof StringType);
+		assertTrue(types[3] instanceof DateType);
+		Iterator iter = qu.iterate();
+		int j = 0;
+		while ( iter.hasNext() ) {
+			j++;
+			assertTrue( ( (Object[]) iter.next() )[1] instanceof Fum );
+		}
+		assertTrue( "iterate on composite key", j==8 );
+
+		fum = (Fum) s.load( Fum.class, fum.getId() );
+		s.filter( fum.getQuxArray(), "where this.foo is null" );
+		s.filter( fum.getQuxArray(), "where this.foo.id = ?", "fooid", Hibernate.STRING );
+		Query f = s.createFilter( fum.getQuxArray(), "where this.foo.id = :fooId" );
+		f.setString("fooId", "abc");
+		assertFalse( f.iterate().hasNext() );
+
+		iter = s.iterate("from Fum fum where not fum.fum='FRIEND'");
+		int i = 0;
+		while ( iter.hasNext() ) {
+			fum = (Fum) iter.next();
+			//iter.remove();
+			s.delete(fum);
+			i++;
+		}
+		assertTrue( "iterate on composite key", i==4 );
+		s.flush();
+
+		s.iterate("from Fum fu, Fum fo where fu.fo.id.string = fo.id.string and fo.fum is not null");
+
+		s.find("from Fumm f1 inner join f1.fum f2");
+
+		s.connection().commit();
+		s.close();
+	}
+
+
+	public void testCompositeIDCollections() throws Exception {
+		Session s = openSession();
+		Fum fum1 = new Fum( fumKey("fum1") );
+		Fum fum2 = new Fum( fumKey("fum2") );
+		fum1.setFum("fee fo fi");
+		fum2.setFum("fee fo fi");
+		s.save(fum1);
+		s.save(fum2);
+		Qux q = new Qux();
+		s.save(q);
+		Set set = new HashSet();
+		List list = new ArrayList();
+		set.add(fum1); set.add(fum2);
+		list.add(fum1);
+		q.setFums(set);
+		q.setMoreFums(list);
+		fum1.setQuxArray( new Qux[] {q} );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		q = (Qux) s.load( Qux.class, q.getKey() );
+		assertTrue( "collection of fums", q.getFums().size()==2 );
+		assertTrue( "collection of fums", q.getMoreFums().size()==1 );
+		assertTrue( "unkeyed composite id collection", ( (Fum) q.getMoreFums().get(0) ).getQuxArray()[0]==q );
+		Iterator iter = q.getFums().iterator();
+		iter.hasNext();
+		Fum f = (Fum) iter.next();
+		s.delete(f);
+		iter.hasNext();
+		f = (Fum) iter.next();
+		s.delete(f);
+		s.delete(q);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+
+	public void testDeleteOwner() throws Exception {
+		Session s = openSession();
+		Qux q = new Qux();
+		s.save(q);
+		Fum f1 = new Fum( fumKey("f1") );
+		Fum f2 = new Fum( fumKey("f2") );
+		Set set = new HashSet();
+		set.add(f1);
+		set.add(f2);
+		List list = new LinkedList();
+		list.add(f1);
+		list.add(f2);
+		f1.setFum("f1");
+		f2.setFum("f2");
+		q.setFums(set);
+		q.setMoreFums(list);
+		s.save(f1);
+		s.save(f2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		q = (Qux) s.load( Qux.class, q.getKey(), LockMode.UPGRADE );
+		s.lock( q, LockMode.UPGRADE );
+		s.delete(q);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		list = s.find("from Fum fum where not fum.fum='FRIEND'");
+		assertTrue( "deleted owner", list.size()==2 );
+		s.lock( list.get(0), LockMode.UPGRADE );
+		s.lock( list.get(1), LockMode.UPGRADE );
+		Iterator iter = list.iterator();
+		while ( iter.hasNext() ) {
+			s.delete( iter.next() );
+		}
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+
+	public void testCompositeIDs() throws Exception {
+		Session s = openSession();
+		Fo fo = Fo.newFo();
+		Properties props = new Properties();
+		props.setProperty("foo", "bar");
+		props.setProperty("bar", "foo");
+		fo.setSerial(props);
+		fo.setBuf( "abcdefghij1`23%$*^*$*\n\t".getBytes() );
+		s.save( fo, fumKey("an instance of fo") );
+		s.flush();
+		props.setProperty("x", "y");
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		fo = (Fo) s.load( Fo.class, fumKey("an instance of fo") );
+		props = (Properties) fo.getSerial();
+		assertTrue( props.getProperty("foo").equals("bar") );
+		//assertTrue( props.contains("x") );
+		assertTrue( props.getProperty("x").equals("y") );
+		assertTrue( fo.getBuf()[0]=='a' );
+		fo.getBuf()[1]=(byte)126;
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		fo = (Fo) s.load( Fo.class, fumKey("an instance of fo") );
+		assertTrue( fo.getBuf()[1]==126 );
+		assertTrue(
+			s.iterate("from Fo fo where fo.id.string like 'an instance of fo'").next()==fo
+		);
+		s.delete(fo);
+		s.flush();
+		try {
+			s.save( Fo.newFo() );
+			assertTrue(false);
+		}
+		catch (Exception e) {
+			//System.out.println( e.getMessage() );
+		}
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testKeyManyToOne() throws Exception {
+		Session s = openSession();
+		Inner sup = new Inner();
+		InnerKey sid = new InnerKey();
+		sup.setDudu("dudu");
+		sid.setAkey("a");
+		sid.setBkey("b");
+		sup.setId(sid);
+		Middle m = new Middle();
+		MiddleKey mid = new MiddleKey();
+		mid.setOne("one");
+		mid.setTwo("two");
+		mid.setSup(sup);
+		m.setId(mid);
+		m.setBla("bla");
+		Outer d = new Outer();
+		OuterKey did = new OuterKey();
+		did.setMaster(m);
+		did.setDetailId("detail");
+		d.setId(did);
+		d.setBubu("bubu");
+		s.save(sup);
+		s.save(m);
+		s.save(d);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Inner in = (Inner) s.find("from Inner").get(0);
+		assertTrue( in.getMiddles().size()==1 );
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		assertTrue( s.find("from Inner _inner join _inner.middles middle").size()==1 );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		d = (Outer) s.load(Outer.class, did);
+		assertTrue( d.getId().getMaster().getId().getSup().getDudu().equals("dudu") );
+		s.delete(d);
+		s.delete( d.getId().getMaster() );
+		s.save( d.getId().getMaster() );
+		s.save(d);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		d = (Outer) s.find("from Outer o where o.id.detailId = ?", d.getId().getDetailId(), Hibernate.STRING ).get(0);
+		s.find("from Outer o where o.id.master.id.sup.dudu is not null");
+		s.find("from Outer o where o.id.master.id.sup.id.akey is not null");
+		s.find("from Inner i where i.backOut.id.master.id.sup.id.akey = i.id.bkey");
+		List l = s.find("select o.id.master.id.sup.dudu from Outer o where o.id.master.id.sup.dudu is not null");
+		assertTrue(l.size()==1);
+		l = s.find("select o.id.master.id.sup.id.akey from Outer o where o.id.master.id.sup.id.akey is not null");
+		assertTrue(l.size()==1);
+		s.find("select i.backOut.id.master.id.sup.id.akey from Inner i where i.backOut.id.master.id.sup.id.akey = i.id.bkey");
+		s.find("from Outer o where o.id.master.bla = ''");
+		s.find("from Outer o where o.id.master.id.one = ''");
+		s.find("from Inner inn where inn.id.bkey is not null and inn.backOut.id.master.id.sup.id.akey > 'a'");
+		s.find("from Outer as o left join o.id.master m left join m.id.sup where o.bubu is not null");
+		s.find("from Outer as o left join o.id.master.id.sup s where o.bubu is not null");
+		s.find("from Outer as o left join o.id.master m left join o.id.master.id.sup s where o.bubu is not null");
+		s.delete(d);
+		s.delete( d.getId().getMaster() );
+		s.delete( d.getId().getMaster().getId().getSup() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testCompositeKeyPathExpressions() throws Exception {
+		Session s = openSession();
+		s.find("select fum1.fo from Fum fum1 where fum1.fo.fum is not null");
+		s.find("from Fum fum1 where fum1.fo.fum is not null order by fum1.fo.fum");
+		if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof HSQLDialect) && !(getDialect() instanceof MckoiDialect) && !(getDialect() instanceof PointbaseDialect) ) {
+			s.find("from Fum fum1 where exists elements(fum1.friends)");
+			if(!(getDialect() instanceof TimesTenDialect)) { // can't execute because TimesTen can't do subqueries combined with aggreations
+				s.find("from Fum fum1 where size(fum1.friends) = 0");
+			}
+		}
+		s.find("select elements(fum1.friends) from Fum fum1");
+		s.find("from Fum fum1, fr in elements( fum1.friends )");
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testUnflushedSessionSerialization() throws Exception {
+
+		///////////////////////////////////////////////////////////////////////////
+		// Test insertions across serializations
+		Session s = getSessions().openSession();
+		s.setFlushMode(FlushMode.NEVER);
+
+		Simple simple = new Simple();
+		simple.setAddress("123 Main St. Anytown USA");
+		simple.setCount(1);
+		simple.setDate( new Date() );
+		simple.setName("My UnflushedSessionSerialization Simple");
+		simple.setPay( new Float(5000) );
+		s.save( simple, new Long(10) );
+
+		// Now, try to serialize session without flushing...
+		s.disconnect();
+		Session s2 = spoofSerialization(s);
+		s.close();
+		s = s2;
+		s.reconnect();
+
+		simple = (Simple) s.load( Simple.class, new Long(10) );
+		Simple other = new Simple();
+		other.init();
+		s.save( other, new Long(11) );
+
+		simple.setOther(other);
+		s.flush();
+
+		s.connection().commit();
+		s.close();
+		Simple check = simple;
+
+		///////////////////////////////////////////////////////////////////////////
+		// Test updates across serializations
+		s = getSessions().openSession();
+		s.setFlushMode(FlushMode.NEVER);
+
+		simple = (Simple) s.get( Simple.class, new Long(10) );
+		assertTrue("Not same parent instances", check.getName().equals( simple.getName() ) );
+		assertTrue("Not same child instances", check.getOther().getName().equals( other.getName() ) );
+
+		simple.setName("My updated name");
+
+		s.disconnect();
+		s2 = spoofSerialization(s);
+		s.close();
+		s = s2;
+		s.reconnect();
+		s.flush();
+
+		s.connection().commit();
+		s.close();
+		check = simple;
+
+		///////////////////////////////////////////////////////////////////////////
+		// Test deletions across serializations
+		s = getSessions().openSession();
+		s.setFlushMode(FlushMode.NEVER);
+
+		simple = (Simple) s.get( Simple.class, new Long(10) );
+		assertTrue("Not same parent instances", check.getName().equals( simple.getName() ) );
+		assertTrue("Not same child instances", check.getOther().getName().equals( other.getName() ) );
+
+		// Now, lets delete across serialization...
+		s.delete(simple);
+
+		s.disconnect();
+		s2 = spoofSerialization(s);
+		s.close();
+		s = s2;
+		s.reconnect();
+		s.flush();
+
+		s.connection().commit();
+		s.close();
+
+		///////////////////////////////////////////////////////////////////////////
+		// Test collection actions across serializations
+		s = getSessions().openSession();
+		s.setFlushMode(FlushMode.NEVER);
+
+		Fum fum = new Fum( fumKey("uss-fum") );
+		fum.setFo( new Fum( fumKey("uss-fo") ) );
+		fum.setFum("fo fee fi");
+		fum.getFo().setFum("stuff");
+		Fum fr = new Fum( fumKey("uss-fr") );
+		fr.setFum("goo");
+		Fum fr2 = new Fum( fumKey("uss-fr2") );
+		fr2.setFum("soo");
+		fum.setFriends( new HashSet() );
+		fum.getFriends().add(fr);
+		fum.getFriends().add(fr2);
+		s.save(fr);
+		s.save(fr2);
+		s.save( fum.getFo() );
+		s.save(fum);
+
+		s.disconnect();
+		s2 = spoofSerialization(s);
+		s.close();
+		s = s2;
+		s.reconnect();
+		s.flush();
+
+		s.connection().commit();
+		s.close();
+
+		s = getSessions().openSession();
+		s.setFlushMode(FlushMode.NEVER);
+		fum = (Fum) s.load( Fum.class, fum.getId() );
+
+		assertTrue("the Fum.friends did not get saved", fum.getFriends().size() == 2);
+
+		fum.setFriends(null);
+		s.disconnect();
+		s2 = spoofSerialization(s);
+		s.close();
+		
+		s = s2;
+		s.reconnect();
+		s.flush();
+
+		s.connection().commit();
+		s.close();
+
+		s = getSessions().openSession();
+		s.setFlushMode(FlushMode.NEVER);
+		fum = (Fum) s.load( Fum.class, fum.getId() );
+		assertTrue("the Fum.friends is not empty", fum.getFriends() == null || fum.getFriends().size() == 0);
+		s.connection().commit();
+		s.close();
+	}
+
+	private Session spoofSerialization(Session session) throws IOException {
+		try {
+			// Serialize the incoming out to memory
+			ByteArrayOutputStream serBaOut = new ByteArrayOutputStream();
+			ObjectOutputStream serOut = new ObjectOutputStream(serBaOut);
+
+			serOut.writeObject(session);
+
+			// Now, re-constitute the model from memory
+			ByteArrayInputStream serBaIn =
+			        new ByteArrayInputStream(serBaOut.toByteArray());
+			ObjectInputStream serIn = new ObjectInputStream(serBaIn);
+
+			Session outgoing = (Session) serIn.readObject();
+
+			return outgoing;
+		}
+		catch (ClassNotFoundException cnfe) {
+			throw new IOException("Unable to locate class on reconstruction");
+		}
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fumm.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fumm.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fumm.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+	<class name="org.hibernate.test.legacy.Fumm">
+		<composite-id name="id">
+			<key-property name="string">
+				<column name="string_" length="10"/>
+			</key-property>
+			<key-property name="short" column="short_"/>
+			<key-property name="date" column="date_" type="date"/>
+		</composite-id>
+		<property name="locale"/>
+		<one-to-one name="fum" cascade="all" constrained="true"/>
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fumm.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fumm.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Fumm.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,59 @@
+//$Id: Fumm.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.Locale;
+
+public class Fumm {
+	
+	private Locale locale;
+	private Fum fum;
+	
+	public FumCompositeID getId() {
+		return fum.getId();
+	}
+	public void setId(FumCompositeID id) {
+	}
+	
+	public Fumm() {
+		super();
+	}
+	
+	/**
+	 * Returns the fum.
+	 * @return Fum
+	 */
+	public Fum getFum() {
+		return fum;
+	}
+	
+	/**
+	 * Returns the locale.
+	 * @return Locale
+	 */
+	public Locale getLocale() {
+		return locale;
+	}
+	
+	/**
+	 * Sets the fum.
+	 * @param fum The fum to set
+	 */
+	public void setFum(Fum fum) {
+		this.fum = fum;
+	}
+	
+	/**
+	 * Sets the locale.
+	 * @param locale The locale to set
+	 */
+	public void setLocale(Locale locale) {
+		this.locale = locale;
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Glarch.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Glarch.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Glarch.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false" package="org.hibernate.test.legacy">
+
+    <class name="Glarch"
+    	table="`glarchez`"
+    	proxy="GlarchProxy"
+    	dynamic-update="true">
+
+        <!--cache-->
+        <id type="string" column="tha_key" length="32">
+            <generator class="uuid"/>
+        </id>
+        <version name="version"/>
+        <property name="name" column="namecvbnmasdf"/>
+        <!-- <property name="currency"/> -->
+        <many-to-one name="next" column="next_" class="Glarch"/>
+        <property name="order" column="order_"/>
+        <dynamic-component name="dynaBean">
+        	<property name="foo" type="string"/>
+        	<property name="bar" type="integer"/>
+        </dynamic-component>
+        <property name="x"/>
+        <list name="strings">
+            <key column="glarch_key"/>
+            <index column="`indx_`"/>
+            <element type="string" column="`tha_stryng`"/>
+        </list>
+        <list name="fooComponents" lazy="true" cascade="all">
+            <key column="glarch_key"/>
+            <index column="tha_indecks"/>
+            <composite-element class="FooComponent">
+                <property name="name" column="name_"/>
+                <property name="count" column="count_"/>
+                <nested-composite-element name="subcomponent" class="FooComponent">
+                    <property name="name" column="x_"/>
+                    <property name="count" column="y_"/>
+                </nested-composite-element>
+                <many-to-one name="fee" cascade="all" outer-join="true"/>
+            </composite-element>
+        </list>
+        <array name="proxyArray" element-class="GlarchProxy">
+        	<key column="array_key"/>
+        	<index column="array_indecks"/>
+        	<one-to-many class="org.hibernate.test.legacy.Glarch"/>
+        </array>
+        <set name="proxySet">
+        	<key column="set_key"/>
+        	<one-to-many class="Glarch"/>
+        </set>
+        <property name="immutable" update="false" not-null="true"/>
+        <property name="derivedVersion" insert="false" update="false" column="version"/>
+        <property name="any" type="object">
+        	<column name="`any_id_of_object`"/>
+        	<column name="`any_class_of_object`"/>
+        </property>
+        <property name="multiple" type="org.hibernate.test.legacy.MultiplicityType">
+        	<column name="count_"/>
+        	<column name="glarch_"/>
+        </property>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Glarch.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Glarch.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Glarch.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,216 @@
+//$Id: Glarch.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.hibernate.CallbackException;
+import org.hibernate.Session;
+import org.hibernate.classic.Lifecycle;
+
+public class Glarch extends Super implements GlarchProxy, Lifecycle, Named, Serializable {
+
+	private int version;
+	private GlarchProxy next;
+	private short order;
+	private List strings;
+	private Map stringSets;
+	private List fooComponents;
+	private GlarchProxy[] proxyArray;
+	private Set proxySet;
+	//private Currency currency = Currency.getInstance( Locale.getDefault() );
+	private transient Map dynaBean;
+	private String immutable;
+	private int derivedVersion;
+	private Object any;
+	private int x;
+	private Multiplicity multiple;
+
+	public int getX() {
+		return x;
+	}
+	public void setX(int x) {
+		this.x = x;
+	}
+
+	public int getVersion() {
+		return version;
+	}
+
+	public void setVersion(int version) {
+		this.version = version;
+	}
+
+	public GlarchProxy getNext() {
+		return next;
+	}
+	public void setNext(GlarchProxy next) {
+		this.next = next;
+	}
+
+	public short getOrder() {
+		return order;
+	}
+	public void setOrder(short order) {
+		this.order = order;
+	}
+
+	public List getStrings() {
+		return strings;
+	}
+
+	public void setStrings(List strings) {
+		this.strings = strings;
+	}
+
+	public Map getStringSets() {
+		return stringSets;
+	}
+
+	public void setStringSets(Map stringSets) {
+		this.stringSets = stringSets;
+	}
+
+	public List getFooComponents() {
+		return fooComponents;
+	}
+
+	public void setFooComponents(List fooComponents) {
+		this.fooComponents = fooComponents;
+	}
+
+	public GlarchProxy[] getProxyArray() {
+		return proxyArray;
+	}
+	public void setProxyArray(GlarchProxy[] proxyArray) {
+		this.proxyArray = proxyArray;
+	}
+	public Set getProxySet() {
+		return proxySet;
+	}
+
+	public void setProxySet(Set proxySet) {
+		this.proxySet = proxySet;
+	}
+
+	public boolean onDelete(Session s) throws CallbackException {
+		return NO_VETO;
+	}
+
+	public void onLoad(Session s, Serializable id) {
+		if ( ! ( ( (String) id ).length()==32 ) ) throw new RuntimeException("id problem");
+	}
+
+	public boolean onSave(Session s) throws CallbackException {
+		dynaBean = new HashMap();
+		dynaBean.put("foo", "foo");
+		dynaBean.put("bar", new Integer(66));
+		immutable="never changes!";
+		return NO_VETO;
+	}
+
+	public boolean onUpdate(Session s) throws CallbackException {
+		return NO_VETO;
+	}
+
+	/*public Currency getCurrency() {
+		return currency;
+	}
+
+	public void setCurrency(Currency currency) {
+		this.currency = currency;
+	}*/
+
+	/**
+	 * Returns the dynaBean.
+	 * @return DynaBean
+	 */
+	public Map getDynaBean() {
+		return dynaBean;
+	}
+
+	/**
+	 * Sets the dynaBean.
+	 * @param dynaBean The dynaBean to set
+	 */
+	public void setDynaBean(Map dynaBean) {
+		this.dynaBean = dynaBean;
+	}
+
+	/**
+	 * Returns the immutable.
+	 * @return String
+	 */
+	public String getImmutable() {
+		return immutable;
+	}
+
+	/**
+	 * Sets the immutable.
+	 * @param immutable The immutable to set
+	 */
+	public void setImmutable(String immutable) {
+		this.immutable = immutable;
+	}
+
+	/**
+	 * Returns the derivedVersion.
+	 * @return int
+	 */
+	public int getDerivedVersion() {
+		return derivedVersion;
+	}
+
+	/**
+	 * Sets the derivedVersion.
+	 * @param derivedVersion The derivedVersion to set
+	 */
+	public void setDerivedVersion(int derivedVersion) {
+		this.derivedVersion = derivedVersion;
+	}
+
+	/**
+	 * Returns the any.
+	 * @return Object
+	 */
+	public Object getAny() {
+		return any;
+	}
+
+	/**
+	 * Sets the any.
+	 * @param any The any to set
+	 */
+	public void setAny(Object any) {
+		this.any = any;
+	}
+
+	/**
+	 * @return
+	 */
+	public Multiplicity getMultiple() {
+		return multiple;
+	}
+
+	/**
+	 * @param multiplicity
+	 */
+	public void setMultiple(Multiplicity multiplicity) {
+		multiple = multiplicity;
+	}
+
+	public String getName() {
+		return super.getName();
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/GlarchProxy.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/GlarchProxy.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/GlarchProxy.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+package org.hibernate.test.legacy;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public interface GlarchProxy {
+	
+	public int getVersion();
+	public int getDerivedVersion();
+	public void setVersion(int version);
+	
+	public String getName();
+	public void setName(String name);
+	
+	public GlarchProxy getNext();
+	public void setNext(GlarchProxy next);
+	
+	public short getOrder();
+	public void setOrder(short order);
+	
+	public List getStrings();
+	public void setStrings(List strings);
+	
+	public Map getDynaBean();
+	public void setDynaBean(Map bean);
+	
+	public Map getStringSets();
+	public void setStringSets(Map stringSets);
+	
+	public List getFooComponents();
+	public void setFooComponents(List fooComponents);
+	
+	public GlarchProxy[] getProxyArray();
+	public void setProxyArray(GlarchProxy[] proxyArray);
+	
+	public Set getProxySet();
+	public void setProxySet(Set proxySet);
+	
+	public Multiplicity getMultiple();
+	public void setMultiple(Multiplicity m);
+	
+	public Object getAny();
+	public void setAny(Object any);
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Holder.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Holder.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Holder.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+	<class name="org.hibernate.test.legacy.Holder">
+		<id name="id" column="id_" type="string" length="32" unsaved-value="null">
+			<generator class="uuid.hex"/>
+		</id>
+		<property name="name" unique="true" not-null="true" length="36"/>
+		<list name="ones">
+			<key column="holder"/>
+			<index column="i"/>
+			<one-to-many class="org.hibernate.test.legacy.One"/>
+		</list>
+		<array name="fooArray">
+			<key column="holder1"/>
+			<index column="j1"/>
+			<one-to-many class="org.hibernate.test.legacy.Foo"/>
+		</array>
+		<set name="foos">
+			<key column="holder2"/>
+			<one-to-many class="org.hibernate.test.legacy.Foo"/>
+		</set>
+		<many-to-one name="otherHolder" property-ref="name" cascade="all"/>
+	</class>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Holder.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Holder.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Holder.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,115 @@
+//$Id: Holder.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.List;
+import java.util.Set;
+
+public class Holder implements Named {
+	private String id;
+	private List ones;
+	private Foo[] fooArray;
+	private Set foos;
+	private String name;
+	private Holder otherHolder;
+	
+	public Holder() {
+	}
+	public Holder(String name) {
+		this.name=name;
+	}
+	
+	/**
+	 * Returns the fooArray.
+	 * @return Foo[]
+	 */
+	public Foo[] getFooArray() {
+		return fooArray;
+	}
+	
+	/**
+	 * Returns the foos.
+	 * @return Set
+	 */
+	public Set getFoos() {
+		return foos;
+	}
+	
+	/**
+	 * Sets the fooArray.
+	 * @param fooArray The fooArray to set
+	 */
+	public void setFooArray(Foo[] fooArray) {
+		this.fooArray = fooArray;
+	}
+	
+	/**
+	 * Sets the foos.
+	 * @param foos The foos to set
+	 */
+	public void setFoos(Set foos) {
+		this.foos = foos;
+	}
+	
+	/**
+	 * Returns the id.
+	 * @return String
+	 */
+	public String getId() {
+		return id;
+	}
+	
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(String id) {
+		this.id = id;
+	}
+	
+	/**
+	 * Returns the name.
+	 * @return String
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * Sets the name.
+	 * @param name The name to set
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+	/**
+	 * Returns the ones.
+	 * @return List
+	 */
+	public List getOnes() {
+		return ones;
+	}
+	
+	/**
+	 * Sets the ones.
+	 * @param ones The ones to set
+	 */
+	public void setOnes(List ones) {
+		this.ones = ones;
+	}
+	
+	public Holder getOtherHolder() {
+		return otherHolder;
+	}
+
+	public void setOtherHolder(Holder holder) {
+		otherHolder = holder;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/I.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/I.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/I.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+//$Id: I.java 7203 2005-06-19 02:01:05Z oneovthafew $
+package org.hibernate.test.legacy;
+
+/**
+ * @author Gavin King
+ */
+public class I {
+	private Long id;
+	private String name;
+	private char type;
+	private K parent;
+	
+	public K getParent() {
+		return parent;
+	}
+	
+	public void setParent(K parent) {
+		this.parent = parent;
+	}
+
+	void setType(char type) {
+		this.type = type;
+	}
+
+	char getType() {
+		return type;
+	}
+
+	void setName(String name) {
+		this.name = name;
+	}
+
+	String getName() {
+		return name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJ.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJ.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJ.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false" 
+	package="org.hibernate.test.legacy" 
+	default-access="field">
+
+	<class name="I" discriminator-value="0">
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		
+		<discriminator formula="case when type_ in ('a', 'b', 'c') then 0 else 1 end" type="integer"/>
+		
+		<property name="name" unique="true" not-null="true"/>
+		<property name="type" column="type_" not-null="true"/>
+		
+		<subclass name="J" discriminator-value="1">
+			<property name="amount"/>
+		</subclass>
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJ2.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJ2.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJ2.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false" 
+	package="org.hibernate.test.legacy" 
+	default-access="field">
+
+	<class name="I">
+		<id name="id">
+			<generator class="hilo"/>
+		</id>
+		<property name="name" unique="true" not-null="true"/>
+		<property name="type" column="type_"/>
+		<many-to-one name="parent" cascade="save-update"/>
+		<union-subclass name="J">
+			<property name="amount"/>
+		</union-subclass>
+	</class>
+	
+	<class name="K">
+		<id name="id">
+			<generator class="hilo"/>
+		</id>
+		<set name="is" inverse="true">
+			<key column="parent"/>
+			<one-to-many class="I"/>
+		</set>
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJ2Test.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJ2Test.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJ2Test.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,129 @@
+//$Id: IJ2Test.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+import junit.framework.Test;
+
+import org.hibernate.LockMode;
+import org.hibernate.classic.Session;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class IJ2Test extends LegacyTestCase {
+
+	public IJ2Test(String x) {
+		super(x);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "legacy/IJ2.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( IJ2Test.class );
+	}
+
+	public void testUnionSubclass() throws Exception {
+		Session s = getSessions().openSession();
+		I i = new I();
+		i.setName( "i" );
+		i.setType( 'a' );
+		J j = new J();
+		j.setName( "j" );
+		j.setType( 'x' );
+		j.setAmount( 1.0f );
+		Serializable iid = s.save(i);
+		Serializable jid = s.save(j);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		getSessions().evict(I.class);
+
+		s = getSessions().openSession();
+		j = (J) s.get(I.class, jid);
+		j = (J) s.get(J.class, jid);
+		i = (I) s.get(I.class, iid);
+		assertTrue( i.getClass()==I.class );
+		j.setAmount( 0.5f );
+		s.lock(i, LockMode.UPGRADE);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		getSessions().evict(I.class);
+
+		s = getSessions().openSession();
+		j = (J) s.get(J.class, jid);
+		j = (J) s.get(I.class, jid);
+		i = (I) s.get(I.class, iid);
+		assertTrue( i.getClass()==I.class );
+		j.setAmount( 0.5f );
+		s.lock(i, LockMode.UPGRADE);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		getSessions().evict(I.class);
+
+		s = getSessions().openSession();
+		assertTrue( s.find("from I").size()==2 );
+		assertTrue( s.find("from J").size()==1 );
+		assertTrue( s.find("from J j where j.amount > 0 and j.name is not null").size()==1 );
+		assertTrue( s.find("from I i where i.class = org.hibernate.test.legacy.I").size()==1 );
+		assertTrue( s.find("from I i where i.class = J").size()==1 );
+		s.connection().commit();
+		s.close();
+
+		getSessions().evict(I.class);
+
+		s = getSessions().openSession();
+		j = (J) s.get(J.class, jid);
+		i = (I) s.get(I.class, iid);
+		K k = new K();
+		Serializable kid = s.save(k);
+		i.setParent(k);
+		j.setParent(k);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		getSessions().evict(I.class);
+
+		s = getSessions().openSession();
+		j = (J) s.get(J.class, jid);
+		i = (I) s.get(I.class, iid);
+		k = (K) s.get(K.class, kid);
+		System.out.println(k + "=" + i.getParent());
+		assertTrue( i.getParent()==k );
+		assertTrue( j.getParent()==k );
+		assertTrue( k.getIs().size()==2 );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		getSessions().evict(I.class);
+
+		s = getSessions().openSession();
+		assertTrue( s.find("from K k inner join k.is i where i.name = 'j'").size()==1 );
+		assertTrue( s.find("from K k inner join k.is i where i.name = 'i'").size()==1 );
+		assertTrue( s.find("from K k left join fetch k.is").size()==2 );
+		s.connection().commit();
+		s.close();
+
+		s = getSessions().openSession();
+		j = (J) s.get(J.class, jid);
+		i = (I) s.get(I.class, iid);
+		k = (K) s.get(K.class, kid);
+		s.delete(k);
+		s.delete(j);
+		s.delete(i);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/IJTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,84 @@
+//$Id: IJTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+import junit.framework.Test;
+
+import org.hibernate.LockMode;
+import org.hibernate.classic.Session;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.OracleDialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class IJTest extends LegacyTestCase {
+
+	public IJTest(String x) {
+		super(x);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "legacy/IJ.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( IJTest.class );
+	}
+
+	public void testFormulaDiscriminator() throws Exception {
+		if ( ( getDialect() instanceof OracleDialect ) || ( getDialect() instanceof HSQLDialect ) ) return;
+		Session s = getSessions().openSession();
+		I i = new I();
+		i.setName( "i" );
+		i.setType( 'a' );
+		J j = new J();
+		j.setName( "j" );
+		j.setType( 'x' );
+		j.setAmount( 1.0f );
+		Serializable iid = s.save(i);
+		Serializable jid = s.save(j);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		getSessions().evict(I.class);
+
+		s = getSessions().openSession();
+		j = (J) s.get(I.class, jid);
+		i = (I) s.get(I.class, iid);
+		assertTrue( i.getClass()==I.class );
+		j.setAmount( 0.5f );
+		s.lock(i, LockMode.UPGRADE);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = getSessions().openSession();
+		j = (J) s.get(I.class, jid, LockMode.UPGRADE);
+		i = (I) s.get(I.class, iid, LockMode.UPGRADE);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = getSessions().openSession();
+		assertTrue( s.find("from I").size()==2 );
+		assertTrue( s.find("from J").size()==1 );
+		assertTrue( s.find("from I i where i.class = 0").size()==1 );
+		assertTrue( s.find("from I i where i.class = 1").size()==1 );
+		s.connection().commit();
+		s.close();
+
+		s = getSessions().openSession();
+		j = (J) s.get(J.class, jid);
+		i = (I) s.get(I.class, iid);
+		s.delete(j);
+		s.delete(i);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Immutable.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Immutable.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Immutable.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+	
+	<class name="org.hibernate.test.legacy.Immutable" table="immut" mutable="false">
+		<!--cache-->
+		<id name="id" column="id_" length="64">
+			<generator class="uuid"/>
+		</id>
+		<property name="foo"/>
+		<property name="bar"/>
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Immutable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Immutable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Immutable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+//$Id: Immutable.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+public class Immutable {
+	private String foo;
+	private String bar;
+	private String id;
+	
+	public String getFoo() {
+		return foo;
+	}
+	
+	public void setFoo(String foo) {
+		this.foo = foo;
+	}
+	
+	public String getBar() {
+		return bar;
+	}
+	
+	public void setBar(String bar) {
+		this.bar = bar;
+	}
+	
+	public String getId() {
+		return id;
+	}
+	
+	public void setId(String id) {
+		this.id = id;
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Inner.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Inner.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Inner.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,61 @@
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author Stefano Travelli
+ */
+public class Inner implements Serializable {
+	private InnerKey id;
+	private String dudu;
+	private List middles;
+	private Outer backOut;
+
+	public InnerKey getId() {
+		return id;
+	}
+
+	public void setId(InnerKey id) {
+		this.id = id;
+	}
+
+	public String getDudu() {
+		return dudu;
+	}
+
+	public void setDudu(String dudu) {
+		this.dudu = dudu;
+	}
+
+	public boolean equals(Object o) {
+		if (this == o) return true;
+		if (!(o instanceof Inner)) return false;
+
+		final Inner cidSuper = (Inner) o;
+
+		if (id != null ? !id.equals(cidSuper.id) : cidSuper.id != null) return false;
+
+		return true;
+	}
+
+	public int hashCode() {
+		return (id != null ? id.hashCode() : 0);
+	}
+	public List getMiddles() {
+		return middles;
+	}
+
+	public void setMiddles(List list) {
+		middles = list;
+	}
+
+	public Outer getBackOut() {
+		return backOut;
+	}
+
+	public void setBackOut(Outer outer) {
+		backOut = outer;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/InnerKey.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/InnerKey.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/InnerKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+/**
+ * @author Stefano Travelli
+ */
+public class InnerKey implements Serializable {
+	private String akey;
+	private String bkey;
+
+	public String getAkey() {
+		return akey;
+	}
+
+	public void setAkey(String akey) {
+		this.akey = akey;
+	}
+
+	public String getBkey() {
+		return bkey;
+	}
+
+	public void setBkey(String bkey) {
+		this.bkey = bkey;
+	}
+
+	public boolean equals(Object o) {
+		if (this == o) return true;
+		if (!(o instanceof InnerKey)) return false;
+
+		final InnerKey cidSuperID = (InnerKey) o;
+
+		if (akey != null ? !akey.equals(cidSuperID.akey) : cidSuperID.akey != null) return false;
+		if (bkey != null ? !bkey.equals(cidSuperID.bkey) : cidSuperID.bkey != null) return false;
+
+		return true;
+	}
+
+	public int hashCode() {
+		int result;
+		result = (akey != null ? akey.hashCode() : 0);
+		result = 29 * result + (bkey != null ? bkey.hashCode() : 0);
+		return result;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Intervention.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Intervention.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Intervention.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+package org.hibernate.test.legacy;
+
+/**
+ * @author hbm2java
+ */
+public class Intervention {
+
+   java.lang.String id;
+   long version;
+
+   String description;
+
+  java.lang.String getId() {
+    return id;
+  }
+
+  void  setId(java.lang.String newValue) {
+    id = newValue;
+  }
+
+  long getVersion() {
+    return version;
+  }
+
+  void  setVersion(long newValue) {
+    version = newValue;
+  }
+
+
+public String getDescription() {
+	return description;
+}
+public void setDescription(String description) {
+	this.description = description;
+}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/J.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/J.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/J.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+//$Id: J.java 7203 2005-06-19 02:01:05Z oneovthafew $
+package org.hibernate.test.legacy;
+
+/**
+ * @author Gavin King
+ */
+public class J extends I {
+	private float amount;
+
+	void setAmount(float amount) {
+		this.amount = amount;
+	}
+
+	float getAmount() {
+		return amount;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Jay.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Jay.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Jay.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: Jay.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+/**
+ * @author Gavin King
+ */
+public class Jay {
+	private long id;
+	private Eye eye;
+	/**
+	 * @return Returns the eye.
+	 */
+	public Eye getEye() {
+		return eye;
+	}
+
+	/**
+	 * @param eye The eye to set.
+	 */
+	public void setEye(Eye eye) {
+		this.eye = eye;
+	}
+
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	
+	public Jay() {}
+	
+	public Jay(Eye eye) {
+		eye.getJays().add(this);
+		this.eye = eye;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/K.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/K.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/K.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+//$Id: K.java 7203 2005-06-19 02:01:05Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class K {
+	private Long id;
+	private Set is;
+	void setIs(Set is) {
+		this.is = is;
+	}
+	Set getIs() {
+		return is;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/LegacyTestCase.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/LegacyTestCase.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/LegacyTestCase.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+package org.hibernate.test.legacy;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.hql.classic.ClassicQueryTranslatorFactory;
+import org.hibernate.util.StringHelper;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class LegacyTestCase extends FunctionalTestCase {
+
+	public static final String USE_ANTLR_PARSER_PROP = "legacy.use_antlr_hql_parser";
+	private final boolean useAntlrParser;
+
+	public LegacyTestCase(String x) {
+		super( x );
+		useAntlrParser = Boolean.valueOf( extractFromSystem( USE_ANTLR_PARSER_PROP ) ).booleanValue();
+	}
+
+	protected static String extractFromSystem(String systemPropertyName) {
+		try {
+			return System.getProperty( systemPropertyName );
+		}
+		catch( Throwable t ) {
+			return null;
+		}
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		if ( !useAntlrParser ) {
+			cfg.setProperty( Environment.QUERY_TRANSLATOR, ClassicQueryTranslatorFactory.class.getName() );
+			try {
+				String dialectTrueRepresentation = Dialect.getDialect().toBooleanValueString( true );
+				// if this call succeeds, then the dialect is saying to represent true/false as int values...
+				Integer.parseInt( dialectTrueRepresentation );
+				String subs = cfg.getProperties().getProperty( Environment.QUERY_SUBSTITUTIONS );
+				if ( subs == null ) {
+					subs = "";
+				}
+				if ( StringHelper.isEmpty( subs ) ) {
+					subs = "true=1, false=0";
+				}
+				else {
+					subs += ", true=1, false=0";
+				}
+				cfg.getProperties().setProperty( Environment.QUERY_SUBSTITUTIONS, subs );
+			}
+			catch( NumberFormatException nfe ) {
+				// the Integer#parseInt call failed...
+			}
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Location.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Location.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Location.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+	<class name="org.hibernate.test.legacy.Location">
+		<composite-id>
+			<key-property name="streetNumber"/>
+			<key-property name="streetName" length="20"/>
+			<key-property name="city" length="20"/>
+			<key-property name="countryCode" length="2"/>
+		</composite-id>
+		<property name="locale"/>
+		<property name="description"/>
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Location.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Location.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Location.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,125 @@
+//$Id: Location.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.Locale;
+
+public class Location implements Serializable {
+	private int streetNumber;
+	private String city;
+	private String streetName;
+	private String countryCode;
+	private Locale locale;
+	private String description;
+	
+	/**
+	 * Returns the countryCode.
+	 * @return String
+	 */
+	public String getCountryCode() {
+		return countryCode;
+	}
+	
+	/**
+	 * Returns the description.
+	 * @return String
+	 */
+	public String getDescription() {
+		return description;
+	}
+	
+	/**
+	 * Returns the locale.
+	 * @return Locale
+	 */
+	public Locale getLocale() {
+		return locale;
+	}
+	
+	/**
+	 * Returns the streetName.
+	 * @return String
+	 */
+	public String getStreetName() {
+		return streetName;
+	}
+	
+	/**
+	 * Returns the streetNumber.
+	 * @return int
+	 */
+	public int getStreetNumber() {
+		return streetNumber;
+	}
+	
+	/**
+	 * Sets the countryCode.
+	 * @param countryCode The countryCode to set
+	 */
+	public void setCountryCode(String countryCode) {
+		this.countryCode = countryCode;
+	}
+	
+	/**
+	 * Sets the description.
+	 * @param description The description to set
+	 */
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	
+	/**
+	 * Sets the locale.
+	 * @param locale The locale to set
+	 */
+	public void setLocale(Locale locale) {
+		this.locale = locale;
+	}
+	
+	/**
+	 * Sets the streetName.
+	 * @param streetName The streetName to set
+	 */
+	public void setStreetName(String streetName) {
+		this.streetName = streetName;
+	}
+	
+	/**
+	 * Sets the streetNumber.
+	 * @param streetNumber The streetNumber to set
+	 */
+	public void setStreetNumber(int streetNumber) {
+		this.streetNumber = streetNumber;
+	}
+	
+	/**
+	 * Returns the city.
+	 * @return String
+	 */
+	public String getCity() {
+		return city;
+	}
+	
+	/**
+	 * Sets the city.
+	 * @param city The city to set
+	 */
+	public void setCity(String city) {
+		this.city = city;
+	}
+	
+	public boolean equals(Object other) {
+		Location l = (Location) other;
+		return l.getCity().equals(city) && l.getStreetName().equals(streetName) && l.getCountryCode().equals(countryCode) && l.getStreetNumber()==streetNumber;
+	}
+	public int hashCode() {
+		return streetName.hashCode();
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Lower.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Lower.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Lower.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,134 @@
+//$Id: Lower.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.List;
+import java.util.Set;
+
+
+public class Lower extends Top {
+	private int intprop;
+	private String foo;
+	private Set set;
+	private List bag;
+	private Top another;
+	private Lower yetanother;
+	private Po mypo;
+	/**
+	 * Returns the intprop.
+	 * @return int
+	 */
+	public int getIntprop() {
+		return intprop;
+	}
+	
+	/**
+	 * Sets the intprop.
+	 * @param intprop The intprop to set
+	 */
+	public void setIntprop(int intprop) {
+		this.intprop = intprop;
+	}
+	
+	/**
+	 * Returns the foo.
+	 * @return String
+	 */
+	public String getFoo() {
+		return foo;
+	}
+	
+	/**
+	 * Sets the foo.
+	 * @param foo The foo to set
+	 */
+	public void setFoo(String foo) {
+		this.foo = foo;
+	}
+	
+	/**
+	 * Returns the set.
+	 * @return Set
+	 */
+	public Set getSet() {
+		return set;
+	}
+	
+	/**
+	 * Sets the set.
+	 * @param set The set to set
+	 */
+	public void setSet(Set set) {
+		this.set = set;
+	}
+	
+	/**
+	 * Returns the another.
+	 * @return Simple
+	 */
+	public Top getAnother() {
+		return another;
+	}
+	
+	/**
+	 * Returns the yetanother.
+	 * @return LessSimple
+	 */
+	public Lower getYetanother() {
+		return yetanother;
+	}
+	
+	/**
+	 * Sets the another.
+	 * @param another The another to set
+	 */
+	public void setAnother(Top another) {
+		this.another = another;
+	}
+	
+	/**
+	 * Sets the yetanother.
+	 * @param yetanother The yetanother to set
+	 */
+	public void setYetanother(Lower yetanother) {
+		this.yetanother = yetanother;
+	}
+	
+	/**
+	 * Returns the bag.
+	 * @return List
+	 */
+	public List getBag() {
+		return bag;
+	}
+	
+	/**
+	 * Sets the bag.
+	 * @param bag The bag to set
+	 */
+	public void setBag(List bag) {
+		this.bag = bag;
+	}
+	
+	/**
+	 * Returns the mypo.
+	 * @return Po
+	 */
+	public Po getMypo() {
+		return mypo;
+	}
+	
+	/**
+	 * Sets the mypo.
+	 * @param mypo The mypo to set
+	 */
+	public void setMypo(Po mypo) {
+		this.mypo = mypo;
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MainObject.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MainObject.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MainObject.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping default-lazy="false">
+    <class
+        name="org.hibernate.test.legacy.MainObject"
+        table="mainobject"
+        dynamic-update="false"
+        dynamic-insert="false"
+    >
+        <cache usage="read-write" />
+
+        <id
+            name="id"
+            column="id"
+            type="java.lang.Long"
+        >
+            <generator class="native">
+                <param name="sequence">seq_mainobj</param>
+            </generator>
+        </id>
+
+        <one-to-one
+            name="obj2"
+            class="org.hibernate.test.legacy.Object2"
+            cascade="all"
+            outer-join="auto"
+            constrained="false"
+        />
+
+        <property
+            name="description"
+            type="java.lang.String"
+            update="true"
+            insert="true"
+            column="description"
+        />
+
+        <!--
+            To add non XDoclet property mappings, create a file named
+                hibernate-properties-MainObject.xml
+            containing the additional properties and place it in your merge dir.
+        -->
+
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MainObject.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MainObject.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MainObject.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+package org.hibernate.test.legacy;
+
+/**
+ * @author Wolfgang Voelkl
+ */
+public class MainObject {
+	private Long id;
+	private String description;
+	private Object2 obj2;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Object2 getObj2() {
+		return obj2;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String string) {
+		description = string;
+	}
+
+	public void setObj2(Object2 object2) {
+		this.obj2 = object2;
+		if (object2 != null) {
+			object2.setBelongsToMainObj(this);
+		}
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Many.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Many.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Many.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping default-lazy="false">
+  <class name="org.hibernate.test.legacy.Many" table="many">
+    <id name="key" column="many_key">
+      <generator class="native" />
+    </id>
+    <property name="x"/>
+    <many-to-one name="one" column="one_key" class="org.hibernate.test.legacy.One"/>
+  </class>
+</hibernate-mapping>
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Many.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Many.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Many.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: Many.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+public class Many {
+	Long key;
+	One one;
+	private int x;
+	
+	public int getX() {
+		return x;
+	}
+	public void setX(int x) {
+		this.x = x;
+	}
+	
+	public void setKey(Long key) {
+		this.key = key;
+	}
+	
+	public Long getKey() {
+		return this.key;
+	}
+	
+	public void setOne(One one) {
+		this.one = one;
+	}
+	
+	public One getOne() {
+		return this.one;
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Map.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Map.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Map.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+	
+<hibernate-mapping default-lazy="false">
+
+    <class entity-name="TestMap">
+
+        <id name="id" type="long" column="id_">
+            <generator class="hilo"/>
+        </id>
+
+        <property name="name" type="string"/>
+        <property name="address" type="string"/>
+
+        <many-to-one name="parent" entity-name="TestMap"/>
+
+        <bag name="children" inverse="true" lazy="false">
+        	<key column="parent"/>
+        	<one-to-many entity-name="TestMap"/>
+        </bag>
+
+        <dynamic-component name="cmp">
+        	<property name="a" type="integer"/>
+        	<property name="b" type="float"/>
+        </dynamic-component>
+    </class>
+    
+	<class entity-name="ParentMap">
+
+		<id name="parentId" column="ParentId" type="long" unsaved-value="null">
+			<generator class="hilo">
+				<param name="sequence">parent_sequence</param>
+			</generator>
+		</id>
+
+		<version name="version" type="java.lang.Integer" column="version"/>
+		<property name="field" type="string" column="Field" length="50"/>
+
+		<one-to-one name="child" entity-name="ChildMap" cascade="all" outer-join="false" constrained="false" property-ref="parent"/>
+	</class>
+
+	<class entity-name="ChildMap">
+
+		<id name="childId" column="ChildId" type="long" unsaved-value="null">
+			<generator class="hilo">
+				<param name="sequence">child_sequence</param>
+			</generator>
+		</id>
+
+		<property name="field" type="string" column="Field" length="50"/>
+
+		<many-to-one name="parent" entity-name="ParentMap" cascade="all" outer-join="false" column="ParentId" not-null="true"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MapTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MapTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MapTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,164 @@
+//$Id: MapTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+
+import org.hibernate.EntityMode;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.Example;
+import org.hibernate.criterion.Expression;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+
+public class MapTest extends LegacyTestCase {
+
+	public MapTest(String x) {
+		super(x);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "legacy/Map.hbm.xml", "legacy/Commento.hbm.xml", "legacy/Marelo.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.DEFAULT_ENTITY_MODE, EntityMode.MAP.toString() );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( MapTest.class );
+	}
+
+	public void testMap() throws Exception {
+
+		Session s = openSession().getSession(EntityMode.MAP);
+		Map map = new HashMap();
+		map.put("$type$", "TestMap");
+		map.put("name", "foo");
+		map.put("address", "bar");
+		Map cmp = new HashMap();
+		cmp.put( "a", new Integer(1) );
+		cmp.put( "b", new Float(1.0) );
+		map.put("cmp", cmp);
+		s.save(map);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession().getSession(EntityMode.MAP);
+		map = (Map) s.get( "TestMap", (Serializable) map.get("id") );
+		assertTrue( map!=null && "foo".equals( map.get("name") ) );
+		assertTrue( map.get("$type$").equals("TestMap") );
+
+		int size = s.createCriteria("TestMap").add( Example.create(map) ).list().size();
+		assertTrue(size==1);
+		s.connection().commit();
+		s.close();
+
+		s = openSession().getSession(EntityMode.MAP);
+		List list = s.createQuery("from TestMap").list();
+		map = (Map) list.get(0);
+		assertTrue( "foo".equals( map.get("name") ) );
+		assertTrue( "bar".equals( map.get("address") ) );
+		cmp = (Map) map.get("cmp");
+		assertTrue( new Integer(1).equals( cmp.get("a") ) && new Float(1.0).equals( cmp.get("b") ) );
+		assertTrue( null==map.get("parent") );
+		map.put("name", "foobar");
+		map.put("parent", map);
+		List bag = (List) map.get("children");
+		bag.add(map);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		list = s.createQuery("from TestMap tm where tm.address = 'bar'").list();
+		map = (Map) list.get(0);
+		assertTrue( "foobar".equals( map.get("name") ) );
+		assertTrue( "bar".equals( map.get("address") ) );
+		assertTrue( map==map.get("parent") );
+		bag = (List) map.get("children");
+		assertTrue( bag.size()==1 );
+
+		size = s.createCriteria("TestMap")
+			.add( Expression.eq("address", "bar") )
+				.createCriteria("parent")
+				.add( Expression.eq("name", "foobar") )
+			.list()
+			.size();
+		assertTrue(size==1);
+
+		s.delete(map);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testMapOneToOne() throws Exception {
+		Map child = new HashMap();
+		Map parent = new HashMap();
+		Session s = openSession();
+		child.put("parent", parent);
+		child.put("$type$", "ChildMap");
+		parent.put("child", child);
+		parent.put("$type$", "ParentMap");
+		s.save(parent);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Map cm = (Map) s.createQuery("from ChildMap cm where cm.parent is not null").uniqueResult();
+		s.delete(cm);
+		s.delete( cm.get("parent") );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		child = new HashMap();
+		parent = new HashMap();
+		s = openSession();
+		child.put("parent", parent);
+		child.put("$type$", "ChildMap");
+		parent.put("child", child);
+		parent.put("$type$", "ParentMap");
+		s.save(child);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Map pm = (Map) s.createQuery("from ParentMap cm where cm.child is not null").uniqueResult();
+		s.delete(pm);
+		s.delete( pm.get("child") );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testOneToOnePropertyRef() throws Exception {
+		Session s = openSession();
+		s.createQuery("from Commento c where c.marelo.mlmag = 0").list();
+		s.createQuery("from Commento c where c.marelo.commento.mcompr is null").list();
+		s.createQuery("from Commento c where c.marelo.mlink = 0").list();
+		s.createQuery("from Commento c where c.marelo.commento = c").list();
+		s.createQuery("from Commento c where c.marelo.id.mlmag = 0").list();
+		s.createQuery("from Commento c where c.marelo.commento.id = c.id").list();
+		s.createQuery("from Commento c where c.marelo.commento.mclink = c.mclink").list();
+		s.createQuery("from Marelo m where m.commento.id > 0").list();
+		s.createQuery("from Marelo m where m.commento.marelo.commento.marelo.mlmag is not null").list();
+		s.connection().commit();
+		s.close();
+	}
+
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Marelo.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Marelo.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Marelo.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+	
+<hibernate-mapping default-lazy="false">
+<!--
+    Created by the Middlegen Hibernate plugin 2.1
+
+    http://boss.bekk.no/boss/middlegen/
+    http://hibernate.sourceforge.net/
+-->
+
+<class entity-name="Marelo" table="MARELO">
+
+    <composite-id>
+        <key-property name="mlmag" column="MLMAG" type="int" length="5"/>
+        <key-property name="mloca" column="MLOCA" type="java.lang.String" length="11"/>
+    </composite-id>
+
+    <property name="mlink" type="long" column="MLINK" length="10"/>
+    <property name="mlart" type="java.lang.String" column="MLART" length="13"/>
+    <property name="mlido" type="long" column="MLIDO" length="10"/>
+    <property name="mldtc" type="java.sql.Timestamp" column="MLDTC" length="7"/>
+    <property name="mltop" type="java.lang.String" column="MLTOP" length="10"/>
+    <property name="mlrag" type="java.lang.String" column="MLRAG" length="2"/>
+    <property name="mlrop" type="short" column="MLROP" length="4"/>
+    <property name="mlcom" type="long" column="MLCOM" length="10"/>
+    <property name="matri" type="java.lang.String" column="MATRI" length="14"/>
+    <property name="socod" type="java.lang.String" column="SOCOD" length="10"/>
+
+    <!-- Associations -->
+
+    <!-- bi-directional one-to-one association to Commento -->
+    <many-to-one name="commento" entity-name="Commento" unique="false" insert="false" update="false">
+        <column name="MLCOM"/>
+    </many-to-one>
+
+
+</class>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Master.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Master.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Master.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,143 @@
+//$Id: Master.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+public class Master implements Serializable, Named {
+	private Master otherMaster;
+	private Set details = new HashSet();
+	private Set moreDetails = new HashSet();
+	private Set incoming = new HashSet();
+	private Set outgoing = new HashSet();
+	private String name="master";
+	private Date stamp;
+	private int version;
+	private BigDecimal bigDecimal = new BigDecimal("1234.123");
+	private int x;
+	private Collection allDetails;
+	
+	public int getX() {
+		return x;
+	}
+	public void setX(int x) {
+		this.x = x;
+	}
+	
+	public Set getDetails() {
+		return details;
+	}
+	
+	private void setDetails(Set details) {
+		this.details = details;
+	}
+	
+	public void addDetail(Detail d) {
+		details.add(d);
+	}
+	
+	public void removeDetail(Detail d) {
+		details.remove(d);
+	}
+	
+	public void addIncoming(Master m) {
+		incoming.add(m);
+	}
+	
+	public void removeIncoming(Master m) {
+		incoming.remove(m);
+	}
+	
+	public void addOutgoing(Master m) {
+		outgoing.add(m);
+	}
+	
+	public void removeOutgoing(Master m) {
+		outgoing.remove(m);
+	}
+	
+	public Set getIncoming() {
+		return incoming;
+	}
+	
+	public void setIncoming(Set incoming) {
+		this.incoming = incoming;
+	}
+	
+	public Set getOutgoing() {
+		return outgoing;
+	}
+	
+	public void setOutgoing(Set outgoing) {
+		this.outgoing = outgoing;
+	}
+	
+	public Set getMoreDetails() {
+		return moreDetails;
+	}
+	
+	public void setMoreDetails(Set moreDetails) {
+		this.moreDetails = moreDetails;
+	}
+	
+	public String getName() {
+		return name;
+	}
+	
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+	public Date getStamp() {
+		return stamp;
+	}
+	
+	public void setStamp(Date stamp) {
+		this.stamp = stamp;
+	}
+	
+	public BigDecimal getBigDecimal() {
+		return bigDecimal;
+	}
+	
+	public void setBigDecimal(BigDecimal bigDecimal) {
+		this.bigDecimal = bigDecimal;
+	}
+	
+	/**
+	 * @return
+	 */
+	public Master getOtherMaster() {
+		return otherMaster;
+	}
+
+	/**
+	 * @param master
+	 */
+	public void setOtherMaster(Master master) {
+		otherMaster = master;
+	}
+
+	/**
+	 * @return Returns the allDetails.
+	 */
+	public Collection getAllDetails() {
+		return allDetails;
+	}
+	/**
+	 * @param allDetails The allDetails to set.
+	 */
+	public void setAllDetails(Collection allDetails) {
+		this.allDetails = allDetails;
+	}
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MasterDetail.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MasterDetail.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MasterDetail.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+	
+<hibernate-mapping default-lazy="false">
+
+	<class name="org.hibernate.test.legacy.Master" table="`master`">
+		<meta attribute="foo">foo</meta>
+		<id column="master_key_column" type="long">
+			<generator class="native"/>
+		</id>
+		<version name="version" access="field"/>
+		<!--version type="timestamp" name="stamp" column="ts_"/-->
+		<!--timestamp name="stamp" column="ts_"/-->
+		<property name="name">
+			<meta attribute="bar">bar</meta>
+			<meta attribute="bar">bar2</meta>
+		</property>
+		<property name="x"/>
+		<property name="bigDecimal" column="big_dec" precision="7" scale="3"/>
+		<set name="details" inverse="true" lazy="true" order-by="i asc">
+			<key column="master_key"/>
+			<one-to-many class="org.hibernate.test.legacy.Detail"/>
+		</set>
+		<set name="moreDetails" cascade="all" lazy="true" order-by="i desc">
+			<key column="more_master_key"/>
+			<one-to-many class="org.hibernate.test.legacy.Detail"/>
+		</set>
+		<set name="incoming" lazy="true" table="mtm">
+			<key foreign-key="AA" column="outgoingabcdef"/>
+			<many-to-many class="org.hibernate.test.legacy.Master" foreign-key="BB">
+				<column name="incomingabcdef" index="IBB"/>
+			</many-to-many>
+		</set>
+		<set name="outgoing" lazy="true" table="mtm" inverse="true">
+			<key column="incomingabcdef"/>
+			<many-to-many class="org.hibernate.test.legacy.Master" column="outgoingabcdef"/>
+		</set>
+		<many-to-one name="otherMaster"/>
+		<!--query-list name="allDetails" query-ref="all_details"/-->
+	</class>
+	
+	<class name="org.hibernate.test.legacy.Detail">
+		<id column="detail_key_column" type="long">
+			<generator class="native"/>
+		</id>
+		<property name="x">
+			<column name="x" unique-key="uk" not-null="true"/>
+		</property>
+		<property name="i">
+			<column name="i" unique-key="uk" not-null="true"/>
+		</property>
+		<many-to-one name="master" foreign-key="CC"> <!--not-null="true"-->
+			<column name="master_key" unique-key="uk" not-null="true"/>
+		</many-to-one>
+		<!-- <cache timeout="10000" type="readwrite"/> -->
+		<set name="subDetails" lazy="true" cascade="all">
+			<key column="detail_key"/>
+			<one-to-many class="org.hibernate.test.legacy.SubDetail"/>
+		</set>
+	</class>
+	
+	<class name="org.hibernate.test.legacy.SubDetail">
+		<id column="subdetail_key_col" type="long">
+			<generator class="native">
+				<param name="sequence">fooseq</param>
+			</generator>
+		</id>
+		<property name="name"/>
+	</class>
+	
+	<query name="all_details" cacheable="true" fetch-size="10"><![CDATA[
+		from 
+			Detail as d
+	]]></query>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MasterDetailTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MasterDetailTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MasterDetailTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1036 @@
+//$Id: MasterDetailTest.java 10981 2006-12-13 00:14:17Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.ObjectNotFoundException;
+import org.hibernate.Query;
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.criterion.Example;
+import org.hibernate.criterion.Expression;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.MckoiDialect;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.dialect.SAPDBDialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.mapping.MetaAttribute;
+import org.hibernate.mapping.PersistentClass;
+
+
+public class MasterDetailTest extends LegacyTestCase {
+
+	public MasterDetailTest(String arg) {
+		super(arg);
+	}
+
+	public String[] getMappings() {
+		return new String[] {
+			"legacy/MasterDetail.hbm.xml",
+			"legacy/Custom.hbm.xml",
+			"legacy/Category.hbm.xml",
+			"legacy/Nameable.hbm.xml",
+			"legacy/SingleSeveral.hbm.xml",
+			"legacy/WZ.hbm.xml",
+			"legacy/UpDown.hbm.xml",
+			"legacy/Eye.hbm.xml"
+		};
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( MasterDetailTest.class );
+	}
+
+	public void testOuterJoin() throws Exception {
+		Session s = openSession();
+		Eye e = new Eye();
+		e.setName("Eye Eye");
+		Jay jay = new Jay(e);
+		e.setJay(jay);
+		s.saveOrUpdate(e);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		e = (Eye) s.createCriteria(Eye.class).uniqueResult();
+		assertTrue( Hibernate.isInitialized( e.getJay() ) );
+		assertTrue( Hibernate.isInitialized( e.getJays() ) );
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		jay = (Jay) s.createQuery("select new Jay(eye) from Eye eye").uniqueResult();
+		assertTrue( "Eye Eye".equals( jay.getEye().getName() ) );
+		s.delete( jay.getEye() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testMeta() throws Exception {
+		PersistentClass clazz = getCfg().getClassMapping( Master.class.getName() );
+		MetaAttribute meta = clazz.getMetaAttribute("foo");
+		assertTrue( "foo".equals( meta.getValue() ) );
+		meta = clazz.getProperty("name").getMetaAttribute("bar");
+		assertTrue( meta.isMultiValued() );
+	}
+
+	public void testCopy() throws Exception {
+		Category catWA = new Category();
+		catWA.setName("HSQL workaround");
+		Category cat = new Category();
+		cat.setName("foo");
+		Category subCatBar = new Category();
+		subCatBar.setName("bar");
+		Category subCatBaz = new Category();
+		subCatBaz.setName("baz");
+		cat.getSubcategories().add(subCatBar);
+		cat.getSubcategories().add(subCatBaz);
+		Session s = openSession();
+		s.save(catWA);
+		s.save(cat);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		cat.setName("new foo");
+		subCatBar.setName("new bar");
+		cat.getSubcategories().remove(subCatBaz);
+		Category newCat = new Category();
+		newCat.setName("new");
+		cat.getSubcategories().add(newCat);
+		Category newSubCat = new Category();
+		newSubCat.setName("new sub");
+		newCat.getSubcategories().add(newSubCat);
+
+		s = openSession();
+		Category copiedCat = (Category) s.saveOrUpdateCopy(cat);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		assertFalse( copiedCat==cat );
+		//assertFalse( copiedCat.getSubcategories().contains(newCat) );
+		assertTrue( cat.getSubcategories().contains(newCat) );
+
+		s = openSession();
+		cat = (Category) s.createQuery("from Category cat where cat.name='new foo'").uniqueResult();
+		newSubCat = (Category) s.createQuery("from Category cat left join fetch cat.subcategories where cat.name='new sub'").uniqueResult();
+		assertTrue( newSubCat.getName().equals("new sub") );
+		s.close();
+
+		newSubCat.getSubcategories().add(cat);
+		cat.setName("new new foo");
+
+		s = openSession();
+		newSubCat = (Category) s.saveOrUpdateCopy( newSubCat, new Long( newSubCat.getId() ) );
+		assertTrue( newSubCat.getName().equals("new sub") );
+		assertTrue( newSubCat.getSubcategories().size()==1 );
+		cat = (Category) newSubCat.getSubcategories().get(0);
+		assertTrue( cat.getName().equals("new new foo") );
+		newSubCat.getSubcategories().remove(cat);
+		s.delete(cat);
+		s.delete(subCatBaz);
+		s.delete(catWA);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testNotNullDiscriminator() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Up up = new Up();
+		up.setId1("foo");
+		up.setId2(123l);
+		Down down = new Down();
+		down.setId1("foo");
+		down.setId2(321l);
+		down.setValue(12312312l);
+		s.save(up);
+		s.save(down);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		List list = s.find("from Up up order by up.id2 asc");
+		assertTrue( list.size()==2 );
+		assertFalse( list.get(0) instanceof Down );
+		assertTrue( list.get(1) instanceof Down );
+		list = s.find("from Down down");
+		assertTrue( list.size()==1 );
+		assertTrue( list.get(0) instanceof Down );
+		//list = s.find("from Up down where down.class = Down");
+		assertTrue( list.size()==1 );
+		assertTrue( list.get(0) instanceof Down );
+		s.delete("from Up up");
+		t.commit();
+		s.close();
+
+	}
+
+	public void testSelfManyToOne() throws Exception {
+
+		//if (dialect instanceof HSQLDialect) return;
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Master m = new Master();
+		m.setOtherMaster(m);
+		s.save(m);
+		t.commit();
+		s.close();
+		s = openSession();
+		t = s.beginTransaction();
+		Iterator i = s.iterate("from Master");
+		m = (Master) i.next();
+		assertTrue( m.getOtherMaster()==m );
+		if (getDialect() instanceof HSQLDialect) { m.setOtherMaster(null); s.flush(); }
+		s.delete(m);
+		t.commit();
+		s.close();
+	}
+
+	public void testExample() throws Exception {
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Master m = new Master();
+		m.setName("name");
+		m.setX(5);
+		m.setOtherMaster(m);
+		s.save(m);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Master m1 = (Master) s.createCriteria(Master.class)
+			.add( Example.create(m).enableLike().ignoreCase().excludeProperty("bigDecimal") )
+			.uniqueResult();
+		assertTrue( m1.getOtherMaster()==m1 );
+		m1 = (Master) s.createCriteria(Master.class)
+			.add( Expression.eq("name", "foobar") )
+			.uniqueResult();
+		assertTrue( m1==null );
+		m1 = (Master) s.createCriteria(Master.class)
+			.add( Example.create(m).excludeProperty("bigDecimal") )
+			.createCriteria("otherMaster")
+				.add( Example.create(m).excludeZeroes().excludeProperty("bigDecimal") )
+			.uniqueResult();
+		assertTrue( m1.getOtherMaster()==m1 );
+		Master m2 = (Master) s.createCriteria(Master.class)
+			.add( Example.create(m).excludeNone().excludeProperty("bigDecimal") )
+			.uniqueResult();
+		assertTrue( m2==m1 );
+		m.setName(null);
+		m2 = (Master) s.createCriteria(Master.class)
+			.add( Example.create(m).excludeNone().excludeProperty("bigDecimal") )
+			.uniqueResult();
+		assertTrue( null==m2 );
+		if (getDialect() instanceof HSQLDialect) { m1.setOtherMaster(null); s.flush(); }
+		s.delete(m1);
+		t.commit();
+		s.close();
+	}
+
+	public void testNonLazyBidirectional() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Single sin = new Single();
+		sin.setId("asdfds");
+		sin.setString("adsa asdfasd");
+		Several sev = new Several();
+		sev.setId("asdfasdfasd");
+		sev.setString("asd ddd");
+		sin.getSeveral().add(sev);
+		sev.setSingle(sin);
+		s.save(sin);
+		t.commit();
+		s.close();
+		s = openSession();
+		t = s.beginTransaction();
+		sin = (Single) s.load( Single.class, sin );
+		t.commit();
+		s.close();
+		s = openSession();
+		t = s.beginTransaction();
+		sev = (Several) s.load( Several.class, sev );
+		t.commit();
+		s.close();
+		s = openSession();
+		t = s.beginTransaction();
+		s.find("from Several");
+		t.commit();
+		s.close();
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete("from Single");
+		t.commit();
+		s.close();
+	}
+
+	public void testCollectionQuery() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof SAPDBDialect) && !(getDialect() instanceof MckoiDialect) ) {
+			s.iterate("FROM Master m WHERE NOT EXISTS ( FROM m.details d WHERE NOT d.i=5 )");
+			s.iterate("FROM Master m WHERE NOT 5 IN ( SELECT d.i FROM m.details AS d )");
+		}
+		s.iterate("SELECT m FROM Master m JOIN m.details d WHERE d.i=5");
+		s.find("SELECT m FROM Master m JOIN m.details d WHERE d.i=5");
+		s.find("SELECT m.id FROM Master AS m JOIN m.details AS d WHERE d.i=5");
+		t.commit();
+		s.close();
+	}
+
+	public void testMasterDetail() throws Exception {
+
+		if (getDialect() instanceof HSQLDialect) return;
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Master master = new Master();
+		assertTrue( "save returned native id", s.save(master)!=null );
+		Serializable mid = s.getIdentifier(master);
+		Detail d1 = new Detail();
+		d1.setMaster(master);
+		Serializable did = s.save(d1);
+		Detail d2 = new Detail();
+		d2.setI(12);
+		d2.setMaster(master);
+		assertTrue( "generated id returned", s.save(d2)!=null);
+		master.addDetail(d1);
+		master.addDetail(d2);
+		if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof Oracle9Dialect) && !(getDialect() instanceof SAPDBDialect) && !(getDialect() instanceof MckoiDialect) && !(getDialect() instanceof org.hibernate.dialect.TimesTenDialect)) {
+			assertTrue(
+				"query",
+				s.find("from Detail d, Master m where m = d.master and size(m.outgoing) = 0 and size(m.incoming) = 0").size()==2
+			);
+		}
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		master = new Master();
+		s.load(master, mid);
+		assertTrue( master.getDetails().size()==2 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		master = (Master) s.load(Master.class, mid);
+		Iterator iter = master.getDetails().iterator();
+		int i=0;
+		while ( iter.hasNext() ) {
+			Detail d = (Detail) iter.next();
+			assertTrue( "master-detail", d.getMaster()==master );
+			i++;
+		}
+		assertTrue( "master-detail", i==2 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		assertTrue( s.find("select elements(master.details) from Master master").size()==2 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		List list = s.find("from Master m left join fetch m.details");
+		Master m = (Master) list.get(0);
+		assertTrue( Hibernate.isInitialized( m.getDetails() ) );
+		assertTrue( m.getDetails().size()==2 );
+		list = s.find("from Detail d inner join fetch d.master");
+		Detail dt = (Detail) list.get(0);
+		Serializable dtid = s.getIdentifier(dt);
+		assertTrue( dt.getMaster()==m );
+
+		//assertTrue(m.getAllDetails().size()==2);
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		list = s.find("select m from Master m1, Master m left join fetch m.details where m.name=m1.name");
+		assertTrue( Hibernate.isInitialized( ( (Master) list.get(0) ).getDetails() ) );
+		dt = (Detail) s.load(Detail.class, dtid);
+		assertTrue( ( (Master) list.get(0) ).getDetails().contains(dt) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		list = s.find("select m, m1.name from Master m1, Master m left join fetch m.details where m.name=m1.name");
+		assertTrue( Hibernate.isInitialized( ( (Master) ( (Object[]) list.get(0) )[0] ).getDetails() ) );
+		dt = (Detail) s.load(Detail.class, dtid);
+		assertTrue( ( (Master) ( (Object[]) list.get(0) )[0] ).getDetails().contains(dt) );
+		//list = s.find("select m from Master m, Master m2 left join fetch m.details");
+// depracted syntax
+//		list = s.find("select m.id from Master m inner join fetch m.details");
+		t.commit();
+		s.close();
+
+
+		s = openSession();
+		t = s.beginTransaction();
+		Detail dd = (Detail) s.load(Detail.class, did);
+		master = dd.getMaster();
+		assertTrue( "detail-master", master.getDetails().contains(dd) );
+		assertTrue( s.filter( master.getDetails(), "order by this.i desc").size()==2 );
+		assertTrue( s.filter( master.getDetails(), "select this where this.id > -1").size()==2 );
+		Query q = s.createFilter( master.getDetails(), "where this.id > :id" );
+		q.setInteger("id", -1);
+		assertTrue( q.list().size()==2 );
+		q = s.createFilter( master.getDetails(), "where this.id > :id1 and this.id < :id2" );
+		q.setInteger("id1", -1);
+		q.setInteger("id2", 99999999);
+		assertTrue( q.list().size()==2 );
+		q.setInteger("id2", -1);
+		assertTrue( q.list().size()==0 );
+		q = s.createFilter( master.getDetails(), "where this.id in (:ids)" );
+		list = new ArrayList();
+		list.add(did);
+		list.add( new Long(-1) );
+		q.setParameterList("ids", list);
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.iterate().hasNext() );
+		assertTrue( s.filter( master.getDetails(), "where this.id > -1").size()==2 );
+		assertTrue( s.filter( master.getDetails(), "select this.master where this.id > -1").size()==2 );
+		assertTrue( s.filter( master.getDetails(), "select m from Master m where this.id > -1 and this.master=m").size()==2 );
+		assertTrue( s.filter( master.getIncoming(), "where this.id > -1 and this.name is not null").size()==0 );
+
+		assertTrue( s.createFilter( master.getDetails(), "select max(this.i)" ).iterate().next() instanceof Integer );
+		assertTrue( s.createFilter( master.getDetails(), "select max(this.i) group by this.id" ).iterate().next() instanceof Integer );
+		assertTrue( s.createFilter( master.getDetails(), "select count(*)" ).iterate().next() instanceof Long );
+
+		assertTrue( s.createFilter( master.getDetails(), "select this.master" ).list().size()==2 );
+		assertTrue( s.filter( master.getMoreDetails(), "" ).size()==0 );
+		assertTrue( s.filter( master.getIncoming(), "" ).size()==0 );
+
+		Query f = s.createFilter( master.getDetails(), "select max(this.i) where this.i < :top and this.i>=:bottom" );
+		f.setInteger("top", 100);
+		f.setInteger("bottom", 0);
+		assertEquals( f.iterate().next(), new Integer(12) );
+		f.setInteger("top", 2);
+		assertEquals( f.iterate().next(), new Integer(0) );
+
+		f = s.createFilter( master.getDetails(), "select max(this.i) where this.i not in (:list)" );
+		Collection coll = new ArrayList();
+		coll.add( new Integer(-666) );
+		coll.add( new Integer(22) );
+		coll.add( new Integer(0) );
+		f.setParameterList("list", coll);
+		assertEquals( f.iterate().next(), new Integer(12) );
+
+		f = s.createFilter( master.getDetails(), "select max(this.i) where this.i not in (:list) and this.master.name = :listy2" );
+		f.setParameterList("list", coll);
+		f.setParameter( "listy2", master.getName() );
+		assertEquals( f.iterate().next(), new Integer(12) );
+
+		iter = master.getDetails().iterator();
+		i=0;
+		while ( iter.hasNext() ) {
+			Detail d = (Detail) iter.next();
+			assertTrue( "master-detail", d.getMaster()==master );
+			s.delete(d);
+			i++;
+		}
+		assertTrue( "master-detail", i==2 );
+		s.delete(master);
+		t.commit();
+		s.close();
+	}
+
+	public void testIncomingOutgoing() throws Exception {
+
+		Session s = openSession();
+		Master master1 = new Master();
+		Master master2 = new Master();
+		Master master3 = new Master();
+		s.save(master1);
+		s.save(master2);
+		s.save(master3);
+		master1.addIncoming(master2);
+		master2.addOutgoing(master1);
+		master1.addIncoming(master3);
+		master3.addOutgoing(master1);
+		Serializable m1id = s.getIdentifier(master1);
+		assertTrue( s.filter( master1.getIncoming(), "where this.id > 0 and this.name is not null").size()==2 );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		master1 = (Master) s.load(Master.class, m1id);
+		Iterator iter = master1.getIncoming().iterator();
+		int i=0;
+		while ( iter.hasNext() ) {
+			Master m = (Master) iter.next();
+			assertTrue( "outgoing", m.getOutgoing().size()==1 );
+			assertTrue( "outgoing", m.getOutgoing().contains(master1) );
+			s.delete(m);
+			i++;
+		}
+		assertTrue( "incoming-outgoing", i==2 );
+		s.delete(master1);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testCascading() throws Exception {
+
+		Session s = openSession();
+		Detail d1 = new Detail();
+		Detail d2 = new Detail();
+		d2.setI(22);
+		Master m = new Master();
+		Master m0 = new Master();
+		Serializable m0id = s.save(m0);
+		m0.addDetail(d1); m0.addDetail(d2);
+		d1.setMaster(m0); d2.setMaster(m0);
+		m.getMoreDetails().add(d1);
+		m.getMoreDetails().add(d2);
+		Serializable mid = s.save(m);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		m = (Master) s.load(Master.class, mid);
+		assertTrue( "cascade save", m.getMoreDetails().size()==2 );
+		assertTrue( "cascade save", ( (Detail) m.getMoreDetails().iterator().next() ).getMaster().getDetails().size()==2 );
+
+		s.delete(m);
+		s.delete( s.load(Master.class, m0id) );
+
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testNamedQuery() throws Exception {
+		Session s = openSession();
+		Query q = s.getNamedQuery("all_details");
+		q.list();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testUpdateLazyCollections() throws Exception {
+		Session s = openSession();
+		Master m = new Master();
+		Serializable mid = s.save(m);
+		Detail d1 = new Detail();
+		Detail d2 = new Detail();
+		d2.setX(14);
+		d1.setMaster(m);
+		d2.setMaster(m);
+		s.save(d1);
+		s.save(d2);
+		m.addDetail(d1);
+		m.addDetail(d2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		m = (Master) s.load(Master.class, mid);
+		s.connection().commit();
+		s.close();
+		m.setName("New Name");
+		s = openSession();
+		s.update(m, mid);
+		Iterator iter = m.getDetails().iterator();
+		int i=0;
+		while ( iter.hasNext() ) {
+			assertTrue( iter.next()!=null );
+			i++;
+		}
+		assertTrue(i==2);
+		iter = m.getDetails().iterator();
+		while ( iter.hasNext() ) s.delete( iter.next() );
+		s.delete(m);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testMultiLevelCascade() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		Detail detail = new Detail();
+		SubDetail subdetail = new SubDetail();
+		Master m = new Master();
+		Master m0 = new Master();
+		Serializable m0id = s.save(m0);
+		m0.addDetail(detail);
+		detail.setMaster(m0);
+		m.getMoreDetails().add(detail);
+		detail.setSubDetails( new HashSet() );
+		detail.getSubDetails().add(subdetail);
+		Serializable mid = s.save(m);
+		txn.commit();
+		s.close();
+
+		s = openSession();
+		txn = s.beginTransaction();
+		m = (Master) s.load( Master.class, mid );
+		assertTrue( ( (Detail) m.getMoreDetails().iterator().next() ).getSubDetails().size()!=0 );
+		s.delete(m);
+		assertTrue( s.find("from SubDetail").size()==0 );
+		assertTrue( s.find("from Detail d").size()==0 );
+		s.delete( s.load(Master.class, m0id) );
+		txn.commit();
+		s.close();
+	}
+
+	public void testMixNativeAssigned() throws Exception {
+
+		Session s = openSession();
+		Category c = new Category();
+		c.setName("NAME");
+		Assignable assn = new Assignable();
+		assn.setId("i.d.");
+		List l = new ArrayList();
+		l.add(c);
+		assn.setCategories(l);
+		c.setAssignable(assn);
+		s.save(assn);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		s.delete(assn);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testCollectionReplaceOnUpdate() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Category c = new Category();
+		List list = new ArrayList();
+		c.setSubcategories(list);
+		list.add( new Category() );
+		s.save(c);
+		t.commit();
+		s.close();
+		c.setSubcategories(list);
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update(c);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Category) s.load( Category.class, new Long( c.getId() ), LockMode.UPGRADE );
+		List list2 = c.getSubcategories();
+		t.commit();
+		s.close();
+
+		assertTrue( !Hibernate.isInitialized( c.getSubcategories() ) );
+
+		c.setSubcategories(list2);
+		s = openSession();
+		t = s.beginTransaction();
+		s.update(c);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Category) s.load( Category.class, new Long( c.getId() ), LockMode.UPGRADE );
+		assertTrue( c.getSubcategories().size()==1 );
+		s.delete(c);
+		t.commit();
+		s.close();
+	}
+
+	public void testCollectionReplace2() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Category c = new Category();
+		List list = new ArrayList();
+		c.setSubcategories(list);
+		list.add( new Category() );
+		Category c2 = new Category();
+		s.save(c2);
+		s.save(c);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Category) s.load( Category.class, new Long( c.getId() ), LockMode.UPGRADE );
+		List list2 = c.getSubcategories();
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c2 = (Category) s.load( Category.class, new Long( c2.getId() ), LockMode.UPGRADE );
+		c2.setSubcategories(list2);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c2 = (Category) s.load( Category.class, new Long( c2.getId() ), LockMode.UPGRADE );
+		assertTrue( c2.getSubcategories().size()==1 );
+		s.delete(c2);
+		s.delete( s.load( Category.class, new Long( c.getId() ) ) );
+		t.commit();
+		s.close();
+	}
+
+	public void testCollectionReplace() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Category c = new Category();
+		List list = new ArrayList();
+		c.setSubcategories(list);
+		list.add( new Category() );
+		s.save(c);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Category) s.load( Category.class, new Long( c.getId() ), LockMode.UPGRADE );
+		c.setSubcategories(list);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Category) s.load( Category.class, new Long( c.getId() ), LockMode.UPGRADE );
+		List list2 = c.getSubcategories();
+		t.commit();
+		s.close();
+
+		assertTrue( !Hibernate.isInitialized( c.getSubcategories() ) );
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Category) s.load( Category.class, new Long( c.getId() ), LockMode.UPGRADE );
+		c.setSubcategories(list2);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Category) s.load( Category.class, new Long( c.getId() ), LockMode.UPGRADE );
+		assertTrue( c.getSubcategories().size()==1 );
+		s.delete(c);
+		t.commit();
+		s.close();
+	}
+
+	public void testCategories() throws Exception {
+		Session s = openSession();
+		Category c = new Category();
+		c.setName(Category.ROOT_CATEGORY);
+		Category c1 = new Category();
+		Category c2 = new Category();
+		Category c3 = new Category();
+		c.getSubcategories().add(c1);
+		c.getSubcategories().add(c2);
+		c2.getSubcategories().add(null);
+		c2.getSubcategories().add(c3);
+		s.save(c);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Transaction tx = s.beginTransaction();
+		s.lock(c, LockMode.UPGRADE);
+		Category loaded = (Category) s.load( Category.class, new Long( c3.getId() ) );
+		assertTrue( s.contains(c3) );
+		assertTrue(loaded==c3);
+		assertTrue( s.getCurrentLockMode(c3)==LockMode.NONE );
+		assertTrue( s.getCurrentLockMode(c)==LockMode.UPGRADE );
+		s.flush();
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		loaded = (Category) s.load( Category.class, new Long( c.getId() ) );
+		assertFalse( Hibernate.isInitialized( loaded.getSubcategories() ) );
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		s.lock(loaded, LockMode.NONE);
+		assertTrue( loaded.getSubcategories().size()==2 );
+		s.connection().commit();
+		s.close();
+
+
+		s = openSession();
+		c = (Category) s.load( Category.class, new Long( c.getId() ) );
+		System.out.println( c.getSubcategories() );
+		assertTrue( c.getSubcategories().get(0)!=null && c.getSubcategories().get(1)!=null );
+		List list = ( (Category) c.getSubcategories().get(1) ).getSubcategories();
+		assertTrue( list.get(1)!=null && list.get(0)==null );
+
+		assertTrue(
+			s.iterate("from Category c where c.name = org.hibernate.test.legacy.Category.ROOT_CATEGORY").hasNext()
+		);
+		s.delete(c);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testCollectionRefresh() throws Exception {
+		Session s = openSession();
+		Category c = new Category();
+		List list = new ArrayList();
+		c.setSubcategories(list);
+		list.add( new Category() );
+		c.setName("root");
+		Serializable id = s.save(c);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		c = (Category) s.load(Category.class, id);
+		s.refresh(c);
+		s.flush();
+		assertTrue( c.getSubcategories().size()==1 );
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		c = (Category) s.load(Category.class, id);
+		assertTrue( c.getSubcategories().size()==1 );
+		s.delete(c);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testCachedCollectionRefresh() throws Exception {
+		Session s = openSession();
+		Category c = new Category();
+		List list = new ArrayList();
+		c.setSubcategories(list);
+		list.add( new Category() );
+		c.setName("root");
+		Serializable id = s.save(c);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		c = (Category) s.load(Category.class, id);
+		c.getSubcategories().size(); //force load and cache
+		s.connection().commit();
+		s.close();
+		
+		s = openSession();
+		if ( (getDialect() instanceof MySQLDialect) ) s.connection().setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
+		c = (Category) s.load(Category.class, id);
+		c.getSubcategories().size(); //force load
+
+		Session ss = openSession();
+		Category c2 = (Category) ss.load(Category.class, id);
+		ss.delete( c2.getSubcategories().get(0) );
+		c2.getSubcategories().clear();
+		ss.flush();
+		ss.connection().commit();
+		ss.close();
+
+		s.refresh(c);
+		assertTrue( c.getSubcategories().size()==0 );
+
+		ss = openSession();
+		c2 = (Category) ss.load(Category.class, id);
+		c2.getSubcategories().add( new Category() );
+		c2.getSubcategories().add( new Category() );
+		ss.flush();
+		ss.connection().commit();
+		ss.close();
+
+		s.refresh(c);
+		assertEquals( 2, c.getSubcategories().size() );
+
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		c = (Category) s.load(Category.class, id);
+		assertEquals( 2, c.getSubcategories().size() );
+		s.delete(c);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testCustomPersister() throws Exception {
+		Session s = openSession();
+		Custom c = new Custom();
+		c.setName( "foo" );
+		c.id="100";
+		String id = (String) s.save(c);
+		assertTrue( c==s.load(Custom.class, id) );
+		s.flush();
+		s.close();
+		s = openSession();
+		c = (Custom) s.load(Custom.class, id);
+		assertTrue( c.getName().equals("foo") );
+		c.setName( "bar" );
+		s.flush();
+		s.close();
+		s = openSession();
+		c = (Custom) s.load(Custom.class, id);
+		assertTrue( c.getName().equals("bar") );
+		s.delete(c);
+		s.flush();
+		s.close();
+		s = openSession();
+		boolean none = false;
+		try {
+			s.load(Custom.class, id);
+		}
+		catch (ObjectNotFoundException onfe) {
+			none=true;
+		}
+		assertTrue(none);
+		s.close();
+
+	}
+
+	public void testInterface() throws Exception {
+		Session s = openSession();
+		Serializable id = s.save( new BasicNameable() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		Nameable n = (Nameable) s.load(Nameable.class, id);
+		s.delete(n);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testNoUpdateManyToOne() throws Exception {
+		Session s = openSession();
+		W w1 = new W();
+		W w2 = new W();
+		Z z = new Z();
+		z.setW(w1);
+		s.save(z);
+		s.flush();
+		z.setW(w2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		s.update(z);
+		s.flush();
+		s.delete(z);
+		s.delete("from W");
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testQueuedBagAdds() throws Exception {
+		Session s = openSession();
+		Assignable a = new Assignable();
+		a.setId("foo");
+		a.setCategories( new ArrayList() );
+		Category c = new Category();
+		c.setAssignable(a);
+		a.getCategories().add(c);
+		s.save(a);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		getSessions().evictCollection("org.hibernate.test.legacy.Assignable.categories");
+
+		s = openSession();
+		a = (Assignable) s.get(Assignable.class, "foo");
+		c = new Category();
+		c.setAssignable(a);
+		a.getCategories().add(c);
+		assertFalse( Hibernate.isInitialized( a.getCategories() ) );
+		assertTrue( a.getCategories().size()==2 );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		getSessions().evictCollection("org.hibernate.test.legacy.Assignable.categories");
+
+		s = openSession();
+		a = (Assignable) s.get(Assignable.class, "foo");
+		c = new Category();
+		c.setAssignable(a);
+		a.getCategories().add(c);
+		assertFalse( Hibernate.isInitialized( a.getCategories() ) );
+		s.flush();
+		assertFalse( Hibernate.isInitialized( a.getCategories() ) );
+		assertTrue( a.getCategories().size()==3 );
+		s.connection().commit();
+		s.close();
+
+		getSessions().evictCollection("org.hibernate.test.legacy.Assignable.categories");
+
+		s = openSession();
+		a = (Assignable) s.get(Assignable.class, "foo");
+		assertTrue( a.getCategories().size()==3 );
+		s.delete(a);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testPolymorphicCriteria() throws Exception {
+		Session s = openSession();
+		Transaction txn = s.beginTransaction();
+		Category f = new Category();
+		Single b = new Single();
+		b.setId("asdfa");
+		b.setString("asdfasdf");
+		s.save(f);
+		s.save(b);
+		List list = s.createCriteria(Object.class).list();
+		assertTrue( list.size()==2 );
+		assertTrue( list.contains(f) && list.contains(b) );
+		s.delete(f);
+		s.delete(b);
+		txn.commit();
+		s.close();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Medication.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Medication.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Medication.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+package org.hibernate.test.legacy;
+
+/**
+ * @author hbm2java
+ */
+public class Medication extends org.hibernate.test.legacy.Intervention {
+
+   org.hibernate.test.legacy.Drug prescribedDrug;
+
+  
+  org.hibernate.test.legacy.Drug getPrescribedDrug() {
+    return prescribedDrug;
+  }
+
+  void  setPrescribedDrug(org.hibernate.test.legacy.Drug newValue) {
+    prescribedDrug = newValue;
+  }
+
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Middle.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Middle.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Middle.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+	
+<hibernate-mapping default-lazy="false">
+
+    <class name="org.hibernate.test.legacy.Inner" table="CID_IN">
+        <composite-id name="id">
+            <key-property name="akey" type="string" length="10" column="AKEY"/>
+            <key-property name="bkey" type="string" length="10" column="BKEY"/>
+        </composite-id>
+        <property name="dudu" length="10" column="DUDU" not-null="true" type="string"/>
+        <bag name="middles" lazy="true" inverse="true">
+        	<key>
+                <column length="10" name="AKEY"/>
+                <column length="10" name="BKEY"/>
+			</key>
+			<one-to-many class="org.hibernate.test.legacy.Middle"/>
+		</bag>
+		<many-to-one name="backOut">
+               <column name="BO_AKEY"/>
+               <column name="BO_BKEY"/>
+               <column name="BO_ONE"/>
+               <column name="BO_TWO"/>
+               <column name="BO_DET"/>
+ 		</many-to-one>	
+    </class>
+
+    <class name="org.hibernate.test.legacy.Middle" table="CID_MID">
+        <composite-id name="id">
+            <key-many-to-one name="sup">
+                <column length="10" name="AKEY"/>
+                <column length="10" name="BKEY"/>
+            </key-many-to-one>
+            <key-property name="one" type="string" length="10" column="ONE"/>
+            <key-property name="two" type="string" length="10" column="TWO"/>
+        </composite-id>
+        <property column="BLA" length="10" name="bla" not-null="true" type="string"/>
+    </class>
+
+    <class name="org.hibernate.test.legacy.Outer" table="CID_OUT">
+        <composite-id name="id">
+            <key-many-to-one name="master">
+                <column length="10" name="AKEY"/>
+                <column length="10" name="BKEY"/>
+                <column length="10" name="ONE"/>
+                <column length="10" name="TWO"/>
+            </key-many-to-one>
+            <key-property name="detailId" type="string" column="ID" length="10"/>
+        </composite-id>
+        <property name="bubu" column="BUBU" length="10" type="string"/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Middle.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Middle.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Middle.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+/**
+ * @author Stefano Travelli
+ */
+public class Middle implements Serializable {
+	private MiddleKey id;
+	private String bla;
+
+	public MiddleKey getId() {
+		return id;
+	}
+
+	public void setId(MiddleKey id) {
+		this.id = id;
+	}
+
+	public String getBla() {
+		return bla;
+	}
+
+	public void setBla(String bla) {
+		this.bla = bla;
+	}
+
+	public boolean equals(Object o) {
+		if (this == o) return true;
+		if (!(o instanceof Middle)) return false;
+
+		final Middle cidMaster = (Middle) o;
+
+		if (id != null ? !id.equals(cidMaster.id) : cidMaster.id != null) return false;
+
+		return true;
+	}
+
+	public int hashCode() {
+		return (id != null ? id.hashCode() : 0);
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MiddleKey.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MiddleKey.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MiddleKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+/**
+ * @author Stefano Travelli
+ */
+public class MiddleKey implements Serializable {
+	private Inner sup;
+	private String one;
+	private String two;
+
+	public String getOne() {
+		return one;
+	}
+
+	public void setOne(String one) {
+		this.one = one;
+	}
+
+	public String getTwo() {
+		return two;
+	}
+
+	public void setTwo(String two) {
+		this.two = two;
+	}
+
+	public Inner getSup() {
+		return sup;
+	}
+
+	public void setSup(Inner sup) {
+		this.sup = sup;
+	}
+
+	public boolean equals(Object o) {
+		if (this == o) return true;
+		if (!(o instanceof MiddleKey)) return false;
+
+		final MiddleKey cidMasterID = (MiddleKey) o;
+
+		if (one != null ? !one.equals(cidMasterID.one) : cidMasterID.one != null) return false;
+		if (sup != null ? !sup.equals(cidMasterID.sup) : cidMasterID.sup != null) return false;
+		if (two != null ? !two.equals(cidMasterID.two) : cidMasterID.two != null) return false;
+
+		return true;
+	}
+
+	public int hashCode() {
+		int result;
+		result = (sup != null ? sup.hashCode() : 0);
+		result = 29 * result + (one != null ? one.hashCode() : 0);
+		result = 29 * result + (two != null ? two.hashCode() : 0);
+		return result;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Mono.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Mono.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Mono.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+//$Id: Mono.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.Set;
+
+
+public class Mono extends Top {
+	
+	private Set strings;
+
+	/**
+	 * Constructor for Mono.
+	 * @param c
+	 */
+	public Mono(int c) {
+		super(c);
+	}
+
+	/**
+	 * Constructor for Mono.
+	 */
+	public Mono() {
+		super();
+	}
+
+	/**
+	 * Returns the strings.
+	 * @return Set
+	 */
+	public Set getStrings() {
+		return strings;
+	}
+
+	/**
+	 * Sets the strings.
+	 * @param strings The strings to set
+	 */
+	public void setStrings(Set strings) {
+		this.strings = strings;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MoreStuff.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MoreStuff.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MoreStuff.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,92 @@
+//$Id: MoreStuff.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+
+public class MoreStuff implements Serializable {
+	private String stringId;
+	private int intId;
+	private Collection stuffs;
+	private String name;
+	
+	public boolean equals(Object other) {
+		return ( (MoreStuff) other ).getIntId()==intId && ( (MoreStuff) other ).getStringId().equals(stringId);
+	}
+	
+	public int hashCode() {
+		return stringId.hashCode();
+	}
+	
+	/**
+	 * Returns the stuffs.
+	 * @return Collection
+	 */
+	public Collection getStuffs() {
+		return stuffs;
+	}
+	
+	/**
+	 * Sets the stuffs.
+	 * @param stuffs The stuffs to set
+	 */
+	public void setStuffs(Collection stuffs) {
+		this.stuffs = stuffs;
+	}
+	
+	/**
+	 * Returns the name.
+	 * @return String
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * Sets the name.
+	 * @param name The name to set
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+	/**
+	 * Returns the intId.
+	 * @return int
+	 */
+	public int getIntId() {
+		return intId;
+	}
+	
+	/**
+	 * Returns the stringId.
+	 * @return String
+	 */
+	public String getStringId() {
+		return stringId;
+	}
+	
+	/**
+	 * Sets the intId.
+	 * @param intId The intId to set
+	 */
+	public void setIntId(int intId) {
+		this.intId = intId;
+	}
+	
+	/**
+	 * Sets the stringId.
+	 * @param stringId The stringId to set
+	 */
+	public void setStringId(String stringId) {
+		this.stringId = stringId;
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Multi.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Multi.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Multi.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,101 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+    <class 
+    	name="org.hibernate.test.legacy.Top" 
+    	table="rootclass" 
+    	dynamic-insert="true" 
+    	dynamic-update="true"
+    	select-before-update="true"
+    	where="id1_ is not null">
+        <!--cache-->
+        <id name="id" type="long" column="id1_" unsaved-value="0">
+            <generator class="native"/>
+        </id>
+        <version name="count" column="count_"/>
+        <property name="name"/>
+        <property name="address"/>
+        <property name="date" column="date_"/>
+        <many-to-one name="top" access="field" column="top_"/>
+                
+        <joined-subclass name="org.hibernate.test.legacy.TrivialClass">
+        	<key column="tcid"/>
+        </joined-subclass>
+        
+	    <joined-subclass 
+	    	name="org.hibernate.test.legacy.Lower" 
+	    	table="leafsubclass"
+	    	dynamic-insert="true" 
+    		dynamic-update="true">
+	        <key column="id__"/>
+	        <property name="intprop" not-null="true"/>
+	        <one-to-one name="other" class="org.hibernate.test.legacy.Lower"/>
+	        <many-to-one name="another" column="other1" class="org.hibernate.test.legacy.Top"/>
+	        <many-to-one name="yetanother" column="other3" class="org.hibernate.test.legacy.Lower"/>
+	        <property name="foo"/>
+	        <set name="set" lazy="false">
+	        	<key column="parent"/>
+	        	<one-to-many class="org.hibernate.test.legacy.Top"/>
+	        </set>
+	        <bag name="bag" lazy="true" table="simple_simple">
+	        	<key column="simple1"/>
+	        	<many-to-many column="simple2" class="org.hibernate.test.legacy.Top"/>
+	        </bag>
+	        <one-to-one name="mypo"/>
+	    </joined-subclass>
+	    
+	    <joined-subclass name="org.hibernate.test.legacy.Multi" table="nonleafsubclass">
+	    	<key column="sid" on-delete="cascade"/>
+	        <property name="extraProp" column="dupe"/>
+	        <many-to-one name="other" column="other2" class="org.hibernate.test.legacy.Multi" />
+	        <many-to-one name="po"/>
+	        <property name="derived" formula="upper(dupe)"/>
+	        
+	        <component name="comp" class="org.hibernate.test.legacy.Multi$Component">
+	        	<property name="cal"/>
+	        	<property name="floaty"/>
+	        </component>
+	        
+	        <joined-subclass name="org.hibernate.test.legacy.SubMulti" table="leafsubsubclass">
+	        	<key column="sid"/>
+	        	<property name="amount" column="dupe"/>
+	        	<bag name="children" lazy="true" inverse="true">
+	        		<key column="parent"/>
+	        		<one-to-many class="org.hibernate.test.legacy.SubMulti"/>
+	        	</bag>
+	        	<many-to-one name="parent"/>
+				<list name="moreChildren" lazy="true">
+	        		<key column="another_parent"/>
+	        		<index column="list_ind"/>
+	        		<one-to-many class="org.hibernate.test.legacy.SubMulti"/>
+	        	</list>
+	        </joined-subclass>
+	        
+	    </joined-subclass>
+
+    </class>
+    
+    <class 
+    	name="org.hibernate.test.legacy.Po"
+    	dynamic-insert="true">
+    	<id type="long" column="id_">
+    		<generator class="native"/>
+    	</id>
+    	<property name="value" column="value_"/>
+    	<list name="list" cascade="all">
+    		<key column="list_po"/>
+    		<index column="i"/>
+    		<one-to-many class="org.hibernate.test.legacy.SubMulti"/>
+    	</list>
+    	<set name="set" inverse="true" cascade="all">
+    		<key column="po"/>
+    		<one-to-many class="org.hibernate.test.legacy.Multi"/>
+    	</set>
+    	<many-to-one name="top" column="tl" insert="false" update="false"/>
+    	<many-to-one name="lower" column="tl"/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Multi.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Multi.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Multi.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,120 @@
+//$Id: Multi.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.Calendar;
+
+
+public class Multi extends Top {
+	
+	/**
+	 * Constructor for Multi.
+	 */
+	public Multi() {
+		super();
+	}
+	
+	private String extraProp;
+	private String derived;
+	private Component comp;
+	private Po po;
+	
+	/**
+	 * Returns the extraProp.
+	 * @return String
+	 */
+	public String getExtraProp() {
+		return extraProp;
+	}
+	
+	/**
+	 * Sets the extraProp.
+	 * @param extraProp The extraProp to set
+	 */
+	public void setExtraProp(String extraProp) {
+		this.extraProp = extraProp;
+	}
+	
+	public static final class Component {
+		private Calendar cal;
+		private Float floaty;
+		/**
+		 * Returns the cal.
+		 * @return Calendar
+		 */
+		public Calendar getCal() {
+			return cal;
+		}
+		
+		/**
+		 * Sets the cal.
+		 * @param cal The cal to set
+		 */
+		public void setCal(Calendar cal) {
+			this.cal = cal;
+		}
+		
+		/**
+		 * Returns the floaty.
+		 * @return Float
+		 */
+		public Float getFloaty() {
+			return floaty;
+		}
+		
+		/**
+		 * Sets the floaty.
+		 * @param floaty The floaty to set
+		 */
+		public void setFloaty(Float floaty) {
+			this.floaty = floaty;
+		}
+		
+	}
+	
+	/**
+	 * Returns the comp.
+	 * @return Component
+	 */
+	public Component getComp() {
+		return comp;
+	}
+	
+	/**
+	 * Sets the comp.
+	 * @param comp The comp to set
+	 */
+	public void setComp(Component comp) {
+		this.comp = comp;
+	}
+	
+	/**
+	 * Returns the po.
+	 * @return Po
+	 */
+	public Po getPo() {
+		return po;
+	}
+	
+	/**
+	 * Sets the po.
+	 * @param po The po to set
+	 */
+	public void setPo(Po po) {
+		this.po = po;
+	}
+	
+	public String getDerived() {
+		return derived;
+	}
+
+	public void setDerived(String derived) {
+		this.derived = derived;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MultiExtends.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MultiExtends.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MultiExtends.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+        <joined-subclass 
+        	name="org.hibernate.test.legacy.Mono" 
+        	extends="org.hibernate.test.legacy.Top"
+        	table="mono"
+        	dynamic-insert="true" 
+    		dynamic-update="true">
+        	<key column="superid"/>
+        	<set name="strings" table="monostrings">
+        		<key column="monoid_"/>
+        		<element type="string" column="str_" not-null="true"/>
+        	</set>
+        </joined-subclass>
+
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MultiTableTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MultiTableTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MultiTableTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,622 @@
+//$Id: MultiTableTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.Test;
+
+import org.hibernate.Criteria;
+import org.hibernate.FetchMode;
+import org.hibernate.LockMode;
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.criterion.Expression;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+
+public class MultiTableTest extends LegacyTestCase {
+
+	public MultiTableTest(String arg0) {
+		super(arg0);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "legacy/Multi.hbm.xml", "legacy/MultiExtends.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( MultiTableTest.class );
+	}
+
+	public void testCriteria() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Lower l = new Lower();
+		s.save(l);
+		assertTrue( l==s.createCriteria(Top.class).uniqueResult() );
+		s.delete(l);
+		s.flush();
+		Criteria c = s.createCriteria(Lower.class);
+		c.createCriteria("yetanother")
+			.add( Expression.isNotNull("id") )
+			.createCriteria("another");
+		c.createCriteria("another").add( Expression.isNotNull("id") );
+		c.list();
+		t.commit();
+		s.close();
+	}
+
+	public void testFetchOneToMany() throws Exception {
+		Session s = openSession();
+		s.createCriteria(Po.class).setFetchMode("set", FetchMode.EAGER).list();
+		s.createCriteria(Po.class).setFetchMode("list", FetchMode.EAGER).list();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testNarrow() throws Exception {
+		Session s = openSession();
+		s.find("from Po po, Lower low where low.mypo = po");
+		s.find("from Po po join po.set as sm where sm.amount > 0");
+		s.find("from Po po join po.top as low where low.foo = 'po'");
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testJoins() throws Exception {
+		Session s = openSession();
+		s.find("from Lower l join l.yetanother l2 where lower(l2.name) > 'a'");
+		s.find("from Lower l where lower(l.yetanother.top.name) > 'a'");
+		s.find("from SubMulti sm join sm.children smc where smc.name > 'a'");
+		s.find("select s, ya from Lower s join s.yetanother ya");
+		s.find("from Lower s1 join s1.bag s2");
+		s.find("from Lower s1 left join s1.bag s2");
+		s.find("select s, a from Lower s join s.another a");
+		s.find("select s, a from Lower s left join s.another a");
+		s.find("from Top s, Lower ls");
+		s.find("from Lower ls join ls.set s where s.name > 'a'");
+		s.find("from Po po join po.list sm where sm.name > 'a'");
+		s.find("from Lower ls inner join ls.another s where s.name is not null");
+		s.find("from Lower ls where ls.other.another.name is not null");
+		s.find("from Multi m where m.derived like 'F%'");
+		s.find("from SubMulti m where m.derived like 'F%'");
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testSubclassCollection() throws Exception {
+		//if ( getDialect() instanceof HSQLDialect ) return; //TODO: figure out why!?
+		Session s = openSession();
+		SubMulti sm = new SubMulti();
+		SubMulti sm1 = new SubMulti();
+		SubMulti sm2 = new SubMulti();
+		ArrayList list = new ArrayList();
+		ArrayList anotherList = new ArrayList();
+		sm.setChildren(list);
+		sm.setMoreChildren(anotherList);
+		sm.setExtraProp("foo");
+		list.add(sm1);
+		list.add(sm2);
+		anotherList.add(sm1);
+		anotherList.add(sm2);
+		sm1.setParent(sm);
+		sm2.setParent(sm);
+		Serializable id = s.save(sm);
+		s.save(sm1);
+		s.save(sm2);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		getSessions().evict(SubMulti.class);
+
+		s = openSession();
+		s.connection().createStatement().executeQuery(
+			"select * from leafsubsubclass sm, nonleafsubclass m, rootclass s where sm.sid=m.sid and sm.sid=s.id1_ and sm.sid=1"
+		).next();
+		assertTrue( s.find("select s from SubMulti as sm join sm.children as s where s.amount>-1 and s.name is null").size()==2 );
+		s.find("select c from SubMulti sm join sm.children c");
+		assertTrue( s.find("select elements(sm.children) from SubMulti as sm").size()==2 );
+		assertTrue( s.find("select distinct sm from SubMulti as sm join sm.children as s where s.amount>-1 and s.name is null").size()==1 );
+		sm = (SubMulti) s.load(SubMulti.class, id);
+		assertTrue( sm.getChildren().size()==2 );
+		assertEquals(
+			s.filter( sm.getMoreChildren(), "select count(*) where this.amount>-1 and this.name is null" ).iterator().next(),
+			new Long(2)
+		);
+		assertEquals( "FOO", sm.getDerived() );
+		assertSame(
+			s.iterate("select distinct s from SubMulti s where s.moreChildren[1].amount < 1.0").next(),
+			sm
+		);
+		assertTrue( sm.getMoreChildren().size()==2 );
+		s.delete(sm);
+		Iterator iter = sm.getChildren().iterator();
+		while ( iter.hasNext() ) s.delete( iter.next() );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testCollectionOnly() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Mono m = new Mono();
+		Long id = (Long) s.save(m);
+		t.commit();
+		s.close();
+		s = openSession();
+		t = s.beginTransaction();
+		s.update(m, id);
+		s.flush();
+		m.setAddress("foo bar");
+		s.flush();
+		s.delete(m);
+		t.commit();
+		s.close();
+	}
+
+	public void testQueries() throws Exception {
+		Session s = openSession();
+		Long id = ( Long ) s.save( new TrivialClass() );
+
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		TrivialClass tc = (TrivialClass) s.load(TrivialClass.class, id);
+		s.find("from TrivialClass s where s.id = 2");
+		s.find("select t.count from Top t");
+		s.find("from Lower s where s.another.name='name'");
+		s.find("from Lower s where s.yetanother.name='name'");
+		s.find("from Lower s where s.yetanother.name='name' and s.yetanother.foo is null");
+		s.find("from Top s where s.count=1");
+		s.find("select s.count from Top s, Lower ls where ls.another=s");
+		s.find("select elements(ls.bag), elements(ls.set) from Lower ls");
+		s.iterate("from Lower");
+		s.iterate("from Top");
+		s.delete(tc);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testConstraints() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		SubMulti sm = new SubMulti();
+		sm.setAmount(66.5f);
+		s.save( sm );
+		t.commit();
+		s.close();
+		s = openSession();
+		s.delete( "from SubMulti" );
+		t = s.beginTransaction();
+		t.commit();
+		s.close();
+	}
+
+	public void testMultiTable() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Multi multi = new Multi();
+		multi.setExtraProp("extra");
+		multi.setName("name");
+		Top simp = new Top();
+		simp.setDate( new Date() );
+		simp.setName("simp");
+
+		Serializable mid = s.save(multi);
+		Serializable sid = s.save(simp);
+
+		SubMulti sm = new SubMulti();
+		sm.setAmount(66.5f);
+		Serializable smid = s.save(sm);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		multi.setExtraProp( multi.getExtraProp() + "2" );
+		//multi.setCount( multi.getCount() + 1 );
+		multi.setName("new name");
+		s.update(multi, mid);
+		simp.setName("new name");
+		s.update(simp, sid);
+		sm.setAmount(456.7f);
+		s.update(sm, smid);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		multi = (Multi) s.load(Multi.class, mid);
+		assertTrue( multi.getExtraProp().equals("extra2") );
+		multi.setExtraProp( multi.getExtraProp() + "3" );
+		//multi.setCount( multi.getCount() + 1 );
+		assertTrue( multi.getName().equals("new name") );
+		multi.setName("newer name");
+		sm = (SubMulti) s.load(SubMulti.class, smid);
+		assertTrue( sm.getAmount()==456.7f );
+		sm.setAmount(23423f);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		multi = (Multi) s.load(Top.class, mid);
+		simp = (Top) s.load(Top.class, sid);
+		assertTrue( ! (simp instanceof Multi) );
+		assertTrue( multi.getExtraProp().equals("extra23") );
+		//multi.setCount( multi.getCount() + 1 );
+		assertTrue( multi.getName().equals("newer name") );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Iterator iter = s.iterate("select\n\nt from Top t where t.count>0");
+		boolean foundSimp = false;
+		boolean foundMulti = false;
+		boolean foundSubMulti = false;
+		while ( iter.hasNext() ) {
+			Object o = iter.next();
+			if ( ( o instanceof Top ) && !( o instanceof Multi) ) foundSimp = true;
+			if ( o instanceof Multi && !(o instanceof SubMulti) ) foundMulti = true;
+			if ( o instanceof SubMulti ) foundSubMulti = true;
+		}
+		assertTrue( foundSimp&&foundMulti&&foundSubMulti );
+		s.find("from Multi m where m.count>0 and m.extraProp is not null");
+		s.find("from Top m where m.count>0 and m.name is not null");
+		s.find("from Lower m where m.other is not null");
+		s.find("from Multi m where m.other.id = 1");
+		s.find("from SubMulti m where m.amount > 0.0");
+
+		assertTrue(
+			s.find("from Multi").size()==2
+		);
+		assertTrue(
+			s.find("from Multi m where m.class = SubMulti").size()==1
+		);
+		assertTrue(
+			s.find("from Top m where m.class = Multi").size()==1
+		);
+		assertTrue(
+			s.find("from Top").size()==3
+		);
+		assertTrue(
+			s.find("from Lower").size()==0
+		);
+		assertTrue(
+			s.find("from SubMulti").size()==1
+		);
+
+		s.find("from Lower ls join ls.bag s where s.id is not null");
+		s.find("from Lower ls join ls.set s where s.id is not null");
+		if ( !(getDialect() instanceof MySQLDialect) ) s.find("from SubMulti sm where exists elements(sm.children)");
+
+		List l = s.createCriteria(Top.class).list();
+		assertTrue( l.size()==3 );
+		assertTrue( s.createCriteria(SubMulti.class).list().size()==1 );
+		assertTrue(
+			s.createCriteria(SubMulti.class)
+				.add( Expression.lt("amount", new Float(0)) )
+				.list()
+				.size()==0
+		);
+		assertTrue(
+			s.createCriteria(SubMulti.class)
+				.add( Expression.ge("amount", new Float(0)) )
+				.list()
+				.size()==1
+		);
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		multi = (Multi) s.load(Top.class, mid, LockMode.UPGRADE);
+		simp = (Top) s.load(Top.class, sid);
+		s.lock(simp, LockMode.UPGRADE_NOWAIT);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update(multi, mid);
+		s.delete(multi);
+		assertTrue( s.delete("from Top")==2);
+		t.commit();
+		s.close();
+
+	}
+
+	public void testMultiTableGeneratedId() throws Exception {
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Multi multi = new Multi();
+		multi.setExtraProp("extra");
+		//multi.setCount(666);
+		multi.setName("name");
+		Top simp = new Top();
+		simp.setDate( new Date() );
+		simp.setName("simp");
+		//simp.setCount(132);
+		Serializable multiId = s.save( multi );
+		Serializable simpId = s.save( simp );
+		SubMulti sm = new SubMulti();
+		sm.setAmount(66.5f);
+		Serializable smId = s.save( sm );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		multi.setExtraProp( multi.getExtraProp() + "2" );
+		//multi.setCount( multi.getCount() + 1 );
+		multi.setName("new name");
+		s.update( multi, multiId );
+		simp.setName("new name");
+		s.update( simp, simpId );
+		sm.setAmount(456.7f);
+		s.update( sm, smId );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		multi = (Multi) s.load( Multi.class, multiId );
+		assertTrue( multi.getExtraProp().equals("extra2") );
+		multi.setExtraProp( multi.getExtraProp() + "3" );
+		//multi.setCount( multi.getCount() + 1 );
+		assertTrue( multi.getName().equals("new name") );
+		multi.setName("newer name");
+		sm = (SubMulti) s.load( SubMulti.class, smId );
+		assertTrue( sm.getAmount()==456.7f );
+		sm.setAmount(23423f);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		multi = (Multi) s.load( Top.class, multiId );
+		simp = (Top) s.load( Top.class, simpId );
+		assertTrue( ! (simp instanceof Multi) );
+		assertTrue( multi.getExtraProp().equals("extra23") );
+		//multi.setCount( multi.getCount() + 1 );
+		assertTrue( multi.getName().equals("newer name") );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Iterator iter = s.iterate("select\n\nt from Top t where t.count>0");
+		boolean foundSimp = false;
+		boolean foundMulti = false;
+		boolean foundSubMulti = false;
+		while ( iter.hasNext() ) {
+			Object o = iter.next();
+			if ( ( o instanceof Top ) && !( o instanceof Multi) ) foundSimp = true;
+			if ( o instanceof Multi && !(o instanceof SubMulti) ) foundMulti = true;
+			if ( o instanceof SubMulti ) foundSubMulti = true;
+		}
+		assertTrue( foundSimp&&foundMulti&&foundSubMulti );
+		s.find("from Multi m where m.count>0 and m.extraProp is not null");
+		s.find("from Top m where m.count>0 and m.name is not null");
+		s.find("from Lower m where m.other is not null");
+		s.find("from Multi m where m.other.id = 1");
+		s.find("from SubMulti m where m.amount > 0.0");
+
+		assertTrue(
+			s.find("from Multi").size()==2
+		);
+		/*assertTrue(
+			s.find("from m in class Multi where m.class = Multi").size()==1
+		);*/
+		assertTrue(
+			s.find("from Top").size()==3
+		);
+		assertTrue(
+			s.find("from Lower").size()==0
+		);
+		assertTrue(
+			s.find("from SubMulti").size()==1
+		);
+
+		s.find("from Lower ls join ls.bag s where s.id is not null");
+		if ( !(getDialect() instanceof MySQLDialect) ) s.find("from SubMulti sm where exists elements(sm.children)");
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		multi = (Multi) s.load( Top.class, multiId, LockMode.UPGRADE );
+		simp = (Top) s.load( Top.class, simpId );
+		s.lock(simp, LockMode.UPGRADE_NOWAIT);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update( multi, multiId );
+		s.delete(multi);
+		assertTrue( s.delete("from Top")==2);
+		t.commit();
+		s.close();
+
+	}
+
+	public void testMultiTableCollections() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		assertTrue( s.find("from Top").size()==0 );
+		Multi multi = new Multi();
+		multi.setExtraProp("extra");
+		multi.setName("name");
+		Top simp = new Top();
+		simp.setDate( new Date() );
+		simp.setName("simp");
+
+		s.save(multi);
+		s.save(simp);
+
+		Lower ls = new Lower();
+		ls.setOther(ls);
+		ls.setAnother(ls);
+		ls.setYetanother(ls);
+		ls.setName("Less Simple");
+		Set set = new HashSet();
+		ls.setSet(set);
+		set.add(multi);
+		set.add(simp);
+		Serializable id = s.save(ls);
+		t.commit();
+		s.close();
+		assertTrue( ls.getOther()==ls && ls.getAnother()==ls && ls.getYetanother()==ls );
+
+		s = openSession();
+		t = s.beginTransaction();
+		ls = (Lower) s.load(Lower.class, id);
+		assertTrue( ls.getOther()==ls && ls.getAnother()==ls && ls.getYetanother()==ls );
+		assertTrue( ls.getSet().size()==2 );
+		Iterator iter = ls.getSet().iterator();
+		int foundMulti = 0;
+		int foundSimple = 0;
+		while ( iter.hasNext() ) {
+			Object o = iter.next();
+			if ( o instanceof Top ) foundSimple++;
+			if ( o instanceof Multi ) foundMulti++;
+		}
+		assertTrue( foundSimple==2 && foundMulti==1 );
+		assertTrue( s.delete("from Top")==3 );
+		t.commit();
+		s.close();
+	}
+
+	public void testMultiTableManyToOne() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		assertTrue( s.find("from Top").size()==0 );
+		Multi multi = new Multi();
+		multi.setExtraProp("extra");
+		multi.setName("name");
+		Top simp = new Top();
+		simp.setDate( new Date() );
+		simp.setName("simp");
+		s.save(multi);
+		Lower ls = new Lower();
+		ls.setOther(ls);
+		ls.setAnother(multi);
+		ls.setYetanother(ls);
+		ls.setName("Less Simple");
+		Serializable id = s.save(ls);
+		t.commit();
+		s.close();
+		assertTrue( ls.getOther()==ls && ls.getAnother()==multi && ls.getYetanother()==ls );
+
+		s = openSession();
+		t = s.beginTransaction();
+		ls = (Lower) s.load(Lower.class, id);
+		assertTrue( ls.getOther()==ls && ls.getYetanother()==ls );
+		assertTrue( ls.getAnother().getName().equals("name") && ls.getAnother() instanceof Multi );
+		s.delete(ls);
+		s.delete( ls.getAnother() );
+		t.commit();
+		s.close();
+	}
+
+	public void testMultiTableNativeId() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Multi multi = new Multi();
+		multi.setExtraProp("extra");
+		Long id = (Long) s.save(multi);
+		assertTrue( id!=null );
+		s.delete(multi);
+		t.commit();
+		s.close();
+	}
+
+	public void testCollection() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Multi multi1 = new Multi();
+		multi1.setExtraProp("extra1");
+		Multi multi2 = new Multi();
+		multi2.setExtraProp("extra2");
+		Po po = new Po();
+		multi1.setPo(po); multi2.setPo(po);
+		po.setSet( new HashSet() );
+		po.getSet().add(multi1);
+		po.getSet().add(multi2);
+		po.setList( new ArrayList() );
+		//po.getList().add(null);
+		po.getList().add( new SubMulti() );
+		Serializable id = s.save(po);
+		assertTrue( id!=null );
+		t.commit();
+		s.close();
+		s = openSession();
+		t = s.beginTransaction();
+		po = (Po) s.load(Po.class, id);
+		assertTrue( po.getSet().size()==2 );
+		assertTrue( po.getList().size()==1 );
+		s.delete(po);
+		assertTrue( s.find("from Top").size()==0 );
+		t.commit();
+		s.close();
+	}
+
+	public void testOneToOne() throws Exception {
+		Session s = openSession();
+		Lower ls = new Lower();
+		Serializable id = s.save(ls);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		s.load(Lower.class, id);
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		s.delete( s.load(Lower.class, id) );
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testCollectionPointer() throws Exception {
+		Session sess = openSession();
+		Lower ls = new Lower();
+		List list = new ArrayList();
+		ls.setBag(list);
+		Top s = new Top();
+		Serializable id = sess.save(ls);
+		sess.save(s);
+		sess.flush();
+		list.add(s);
+		sess.flush();
+		sess.connection().commit();
+		sess.close();
+
+		sess = openSession();
+		ls = (Lower) sess.load(Lower.class, id);
+		assertTrue( ls.getBag().size()==1 );
+		sess.delete("from java.lang.Object");
+		sess.flush();
+		sess.connection().commit();
+		sess.close();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Multiplicity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Multiplicity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Multiplicity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+//$Id: Multiplicity.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+public class Multiplicity implements Serializable {
+	public int count;
+	public GlarchProxy glarch;
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MultiplicityType.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MultiplicityType.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/MultiplicityType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,150 @@
+//$Id: MultiplicityType.java 6592 2005-04-28 15:44:16Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.engine.ForeignKeys;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.type.Type;
+import org.hibernate.usertype.CompositeUserType;
+
+public class MultiplicityType implements CompositeUserType {
+
+	private static final String[] PROP_NAMES = new String[] {
+		"count", "glarch"
+	};
+	private static final int[] SQL_TYPES = new int[] {
+		Hibernate.INTEGER.sqlType(), Hibernate.STRING.sqlType()
+	};
+	private static final Type[] TYPES = new Type[] {
+		Hibernate.INTEGER, Hibernate.entity(Glarch.class)
+	};
+
+	public String[] getPropertyNames() {
+		return PROP_NAMES;
+	}
+
+	public Type[] getPropertyTypes() {
+		return TYPES;
+	}
+
+	public int hashCode(Object x) throws HibernateException {
+		Multiplicity o = (Multiplicity) x;
+		return o.count + o.glarch.hashCode();
+	}
+
+	public Object getPropertyValue(Object component, int property) {
+		Multiplicity o = (Multiplicity) component;
+		return property==0 ?
+			(Object) new Integer(o.count) :
+			(Object) o.glarch;
+	}
+
+	public void setPropertyValue(
+		Object component,
+		int property,
+		Object value) {
+
+		Multiplicity o = (Multiplicity) component;
+		if (property==0) {
+			o.count = ( (Integer) value ).intValue();
+		}
+		else {
+			o.glarch = (Glarch) value;
+		}
+	}
+
+	public int[] sqlTypes() {
+		return SQL_TYPES;
+	}
+
+	public Class returnedClass() {
+		return Multiplicity.class;
+	}
+
+	public boolean equals(Object x, Object y) {
+		Multiplicity mx = (Multiplicity) x;
+		Multiplicity my = (Multiplicity) y;
+		if (mx==my) return true;
+		if (mx==null || my==null) return false;
+		return mx.count==my.count && mx.glarch==my.glarch;
+	}
+
+	public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
+		throws HibernateException, SQLException {
+
+		Integer c = (Integer) Hibernate.INTEGER.nullSafeGet( rs, names[0] );
+		GlarchProxy g = (GlarchProxy) Hibernate.entity(Glarch.class).nullSafeGet(rs, names[1], session, owner);
+		Multiplicity m = new Multiplicity();
+		m.count = c==null ? 0 : c.intValue();
+		m.glarch = g;
+		return m;
+	}
+
+	public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session)
+		throws HibernateException, SQLException {
+
+		Multiplicity o = (Multiplicity) value;
+		GlarchProxy g;
+		Integer c;
+		if (o==null) {
+			g=null;
+			c=new Integer(0);
+		}
+		else {
+			g = o.glarch;
+			c = new Integer(o.count);
+		}
+		Hibernate.INTEGER.nullSafeSet(st, c, index, session);
+		Hibernate.entity(Glarch.class).nullSafeSet(st, g, index+1, session);
+
+	}
+
+	public Object deepCopy(Object value) {
+		if (value==null) return null;
+		Multiplicity v = (Multiplicity) value;
+		Multiplicity m = new Multiplicity();
+		m.count = v.count;
+		m.glarch = v.glarch;
+		return m;
+	}
+
+	public boolean isMutable() {
+		return true;
+	}
+
+	public Object assemble(
+		Serializable cached,
+		SessionImplementor session,
+		Object owner) throws HibernateException {
+		if (cached==null) return null;
+		Serializable[] o = (Serializable[]) cached;
+		Multiplicity m = new Multiplicity();
+		m.count = ( (Integer) o[0] ).intValue();
+		m.glarch = o[1]==null ? 
+			null : 
+			(GlarchProxy) session.internalLoad( Glarch.class.getName(), o[1], false, false );
+		return m;
+	}
+
+	public Serializable disassemble(Object value, SessionImplementor session)
+	throws HibernateException {
+		if (value==null) return null;
+		Multiplicity m = (Multiplicity) value;
+		return new Serializable[] { 
+				new Integer(m.count), 
+				ForeignKeys.getEntityIdentifierIfNotUnsaved( Glarch.class.getName(), m.glarch, session ) 
+		};
+	}
+
+	public Object replace(Object original, Object target, SessionImplementor session, Object owner) 
+	throws HibernateException {
+		return assemble( disassemble(original, session), session, owner);
+	}
+	
+}
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Nameable.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Nameable.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Nameable.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+    <class name="org.hibernate.test.legacy.Nameable">
+        <id name="key" column="key_">
+        	<generator class="native"/>
+         </id>
+        <discriminator column="clazz"/>
+        <property name="name"/>
+        <subclass name="org.hibernate.test.legacy.BasicNameable"/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Nameable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Nameable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Nameable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+//$Id: Nameable.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+/**
+ *
+ */
+public interface Nameable {
+	public String getName();
+	public void setName(String name);
+	public Long getKey();
+	public void setKey(Long key);
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Named.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Named.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Named.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+//$Id: Named.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+
+public interface Named {
+	public String getName();
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NestingComponent.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NestingComponent.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NestingComponent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+public class NestingComponent implements Serializable {
+	private ComponentCollection nested;
+	public ComponentCollection getNested() {
+		return nested;
+	}
+
+	public void setNested(ComponentCollection collection) {
+		nested = collection;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NewPerformanceTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NewPerformanceTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NewPerformanceTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,92 @@
+//$Id: NewPerformanceTest.java 5718 2005-02-13 23:01:34Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+import org.hibernate.classic.Session;
+import org.hibernate.test.TestCase;
+
+public class NewPerformanceTest extends TestCase {
+
+	public NewPerformanceTest(String arg0) {
+		super(arg0);
+	}
+
+	public void testPerformance() throws Exception {
+
+		for ( int n=2; n<4000; n*=2 ) {
+
+			Simple[] simples = new Simple[n];
+			Serializable[] ids = new Serializable[n];
+			for ( int i=0; i<n; i++ ) {
+				simples[i] = new Simple();
+				simples[i].init();
+				simples[i].setCount(i);
+				ids[i] = new Long(i);
+			}
+
+			Session s = openSession();
+			prepare(s, simples, ids, n);
+			s.close();
+
+			long find = 0;
+			long flush = 0;
+
+			for ( int i=0; i<100; i++ ) {
+
+				s = openSession();
+				long time = System.currentTimeMillis();
+				List list = s.createQuery("from Simple s where not s.name='osama bin laden' and s.other is null").list();
+				find += System.currentTimeMillis() - time;
+				assertTrue( list.size()==n );
+				time = System.currentTimeMillis();
+				s.flush();
+				flush += System.currentTimeMillis() - time;
+				time = System.currentTimeMillis();
+				s.connection().commit();
+				find += System.currentTimeMillis() - time;
+				s.close();
+
+			}
+
+			System.out.println( "Objects: " + n + " - find(): " + find + "ms / flush(): " + flush + "ms / Ratio: " + ( (float) flush )/find );
+			System.out.println( "Objects: " + n + " flush time per object: " + flush / 100.0 / n );
+			System.out.println( "Objects: " + n + " load time per object: " + find / 100.0 / n );
+			s = openSession();
+			delete(s);
+			s.close();
+
+		}
+	}
+
+	private void prepare(Session s, Simple[] simples, Serializable[] ids, int N) throws Exception {
+		for ( int i=0; i<N; i++ ) {
+			s.save( simples[i], ids[i] );
+		}
+		s.flush();
+		s.connection().commit();
+	}
+
+	private void delete(Session s) throws Exception {
+		s.delete("from Simple s");
+		s.flush();
+		s.connection().commit();
+	}
+
+	public String[] getMappings() {
+		return new String[] { "legacy/Simple.hbm.xml" };
+	}
+
+	public static Test suite() throws Exception {
+		return new TestSuite(NewPerformanceTest.class);
+	}
+
+	public static void main(String[] args) throws Exception {
+		TestRunner.run( suite() );
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NewerPerformanceTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NewerPerformanceTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NewerPerformanceTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,402 @@
+//$Id: NewerPerformanceTest.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+import org.hibernate.classic.Session;
+import org.hibernate.cfg.Environment;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.connection.ConnectionProviderFactory;
+import org.hibernate.test.TestCase;
+
+public class NewerPerformanceTest extends TestCase {
+
+	public NewerPerformanceTest(String arg0) {
+		super(arg0);
+	}
+
+	public void testMany() throws Exception {
+
+		ConnectionProvider cp = ConnectionProviderFactory.newConnectionProvider( Environment.getProperties() );
+
+		long hiber=0;
+		long jdbc=0;
+
+		for ( int n=0; n<20; n++ ) {
+
+			Session s = openSession();
+			s.delete("from Simple");
+			s.flush();
+			Simple[] simples = new Simple[n];
+			Serializable[] ids = new Serializable[n];
+			for ( int i=0; i<n; i++ ) {
+				simples[i] = new Simple();
+				simples[i].init();
+				simples[i].setCount(i);
+				ids[i] = new Long(i);
+				s.save(simples[i], ids[i]);
+			}
+			s.flush();
+			s.connection().commit();
+			s.close();
+
+			//allow cache to settle
+
+			s = openSession();
+			hibernate(s, simples, ids, n, "h0");
+			s.close();
+
+			Connection c = cp.getConnection();
+			directJDBC( c, simples, ids, n, "j0" );
+			cp.closeConnection(c);
+
+			s = openSession();
+			hibernate(s, simples, ids, n, "h0");
+			s.close();
+
+			c = cp.getConnection();
+			directJDBC( c, simples, ids, n, "j0" );
+			cp.closeConnection(c);
+
+			//Now do timings
+
+			int N=30;
+
+			long time = System.currentTimeMillis();
+			for (int i=0; i<N; i++) {
+				s = openSession();
+				hibernate(s, simples, ids, n, "h1");
+				s.close();
+			}
+			hiber += System.currentTimeMillis() - time;
+
+			time = System.currentTimeMillis();
+			for (int i=0; i<N; i++) {
+				c = cp.getConnection();
+				directJDBC( c, simples, ids, n, "j1" );
+				cp.closeConnection(c);
+			}
+			jdbc += System.currentTimeMillis() - time;
+
+			time = System.currentTimeMillis();
+			for (int i=0; i<N; i++) {
+				s = openSession();
+				hibernate(s, simples, ids, n, "h2");
+				s.close();
+			}
+			hiber += System.currentTimeMillis() - time;
+
+			time = System.currentTimeMillis();
+			for (int i=0; i<N; i++) {
+				c = cp.getConnection();
+				directJDBC( c, simples, ids, n, "j2" );
+				cp.closeConnection(c);
+			}
+			jdbc += System.currentTimeMillis() - time;
+
+			time = System.currentTimeMillis();
+			for (int i=0; i<N; i++) {
+				s = openSession();
+				hibernate(s, simples, ids, n, "h1");
+				s.close();
+			}
+			hiber += System.currentTimeMillis() - time;
+
+			time = System.currentTimeMillis();
+			for (int i=0; i<N; i++) {
+				c = cp.getConnection();
+				directJDBC( c, simples, ids, n, "j1" );
+				cp.closeConnection(c);
+			}
+			jdbc += System.currentTimeMillis() - time;
+
+		}
+
+		System.out.println( "Hibernate: " + hiber + "ms / Direct JDBC: " + jdbc + "ms = Ratio: " + ( (float) hiber )/jdbc );
+
+		cp.close();
+		System.gc();
+	}
+
+	public void testSimultaneous() throws Exception {
+
+		ConnectionProvider cp = ConnectionProviderFactory.newConnectionProvider( Environment.getProperties() );
+
+		for ( int n=2; n<4000; n*=2 ) {
+
+			Session s = openSession();
+			s.delete("from Simple");
+			s.flush();
+			Simple[] simples = new Simple[n];
+			Serializable[] ids = new Serializable[n];
+			for ( int i=0; i<n; i++ ) {
+				simples[i] = new Simple();
+				simples[i].init();
+				simples[i].setCount(i);
+				ids[i] = new Long(i);
+				s.save(simples[i], ids[i]);
+			}
+			s.flush();
+			s.connection().commit();
+			s.close();
+
+			//allow cache to settle
+
+			s = openSession();
+			hibernate(s, simples, ids, n, "h0");
+			s.close();
+
+			Connection c = cp.getConnection();
+			directJDBC( c, simples, ids, n, "j0" );
+			cp.closeConnection(c);
+
+			s = openSession();
+			hibernate(s, simples, ids, n, "h0");
+			s.close();
+
+			c = cp.getConnection();
+			directJDBC( c, simples, ids, n, "j0" );
+			cp.closeConnection(c);
+
+			//Now do timings
+
+			s = openSession();
+			long time = System.currentTimeMillis();
+			hibernate(s, simples, ids, n, "h1");
+			long hiber = System.currentTimeMillis() - time;
+			s.close();
+
+			c = cp.getConnection();
+			time = System.currentTimeMillis();
+			directJDBC( c, simples, ids, n, "j1" );
+			long jdbc = System.currentTimeMillis() - time;
+			cp.closeConnection(c);
+
+			s = openSession();
+			time = System.currentTimeMillis();
+			hibernate(s, simples, ids, n, "h2");
+			hiber += System.currentTimeMillis() - time;
+			s.close();
+
+			c = cp.getConnection();
+			time = System.currentTimeMillis();
+			directJDBC( c, simples, ids, n, "j2" );
+			jdbc += System.currentTimeMillis() - time;
+			cp.closeConnection(c);
+
+			s = openSession();
+			time = System.currentTimeMillis();
+			hibernate(s, simples, ids, n, "h2");
+			hiber += System.currentTimeMillis() - time;
+			s.close();
+
+			c = cp.getConnection();
+			time = System.currentTimeMillis();
+			directJDBC( c, simples, ids, n, "j2" );
+			jdbc += System.currentTimeMillis() - time;
+			cp.closeConnection(c);
+
+			System.out.println( "Objects: " + n + " - Hibernate: " + hiber + "ms / Direct JDBC: " + jdbc + "ms = Ratio: " + ( (float) hiber )/jdbc );
+
+		}
+
+		cp.close();
+		System.gc();
+	}
+
+	public void testHibernateOnly() throws Exception {
+
+		for ( int n=2; n<4000; n*=2 ) {
+
+			Session s = openSession();
+			Simple[] simples = new Simple[n];
+			s.delete("from Simple");
+			s.flush();
+			Serializable[] ids = new Serializable[n];
+			for ( int i=0; i<n; i++ ) {
+				simples[i] = new Simple();
+				simples[i].init();
+				simples[i].setCount(i);
+				ids[i] = new Long(i);
+				s.save(simples[i], ids[i]);
+			}
+			s.flush();
+			s.connection().commit();
+			s.close();
+
+			//Now do timings
+
+			s = openSession();
+			long time = System.currentTimeMillis();
+			hibernate(s, simples, ids, n, "h1");
+			long hiber = System.currentTimeMillis() - time;
+			s.close();
+
+			s = openSession();
+			time = System.currentTimeMillis();
+			hibernate(s, simples, ids, n, "h2");
+			hiber += System.currentTimeMillis() - time;
+			s.close();
+
+			s = openSession();
+			time = System.currentTimeMillis();
+			hibernate(s, simples, ids, n, "h2");
+			hiber += System.currentTimeMillis() - time;
+			s.close();
+
+			System.out.println( "Objects: " + n + " - Hibernate: " + hiber );
+
+		}
+
+		System.gc();
+	}
+
+	public void testJdbcOnly() throws Exception {
+
+		ConnectionProvider cp = ConnectionProviderFactory.newConnectionProvider( Environment.getProperties() );
+
+		for ( int n=2; n<4000; n*=2 ) {
+
+			Session s = openSession();
+			Simple[] simples = new Simple[n];
+			s.delete("from Simple");
+			s.flush();
+			Serializable[] ids = new Serializable[n];
+			for ( int i=0; i<n; i++ ) {
+				simples[i] = new Simple();
+				simples[i].init();
+				simples[i].setCount(i);
+				ids[i] = new Long(i);
+				s.save(simples[i], ids[i]);
+			}
+			s.flush();
+			s.connection().commit();
+			s.close();
+
+
+			//Now do timings
+
+			Connection c = cp.getConnection();
+			long time = System.currentTimeMillis();
+			directJDBC( c, simples, ids, n, "j1" );
+			long jdbc = System.currentTimeMillis() - time;
+			cp.closeConnection(c);
+
+			c = cp.getConnection();
+			time = System.currentTimeMillis();
+			directJDBC( c, simples, ids, n, "j2" );
+			jdbc += System.currentTimeMillis() - time;
+			cp.closeConnection(c);
+
+			c = cp.getConnection();
+			time = System.currentTimeMillis();
+			directJDBC( c, simples, ids, n, "j2" );
+			jdbc += System.currentTimeMillis() - time;
+			cp.closeConnection(c);
+
+			System.out.println( "Objects: " + n + " Direct JDBC: " + jdbc );
+
+		}
+
+		cp.close();
+		System.gc();
+	}
+
+	/*private void hibernate(Session s, Simple[] simples, Serializable[] ids, int N, String runname) throws Exception {
+		for ( int i=0; i<N; i++ ) {
+			s.get( Simple.class, ids[i] );
+			//s.find("from Simple s where s.id = ?", ids[i], Hibernate.LONG);
+		}
+		//s.flush();
+		s.connection().commit();
+	}
+
+	private void directJDBC(Connection c, Simple[] simples, Serializable[] ids, int N, String runname) throws SQLException {
+
+		for ( int i=0; i<N; i++ ) {
+			PreparedStatement select = c.prepareStatement("SELECT s.id_, s.name, s.address, s.count_, s.date_, s.pay, s.other FROM Simple s where s.id_=?");
+			select.setLong( 1, ( (Long) ids[i] ).longValue() );
+			ResultSet rs = select.executeQuery();
+			rs.next();
+			/*new Long( rs.getLong(1) );
+			rs.getString(2);
+			rs.getString(3);
+			rs.getInt(4);
+			rs.getDate(5);
+			rs.getFloat(6);
+			rs.getLong(7);*/
+			/*Simple s = new Simple();
+			new Long( rs.getLong("id_") );  rs.wasNull();
+			s.setName( rs.getString("name") );  rs.wasNull();
+			s.setAddress( rs.getString("address") );  rs.wasNull();
+			s.setCount( rs.getInt("count_") );  rs.wasNull();
+			s.setDate( rs.getTimestamp("date_") );  rs.wasNull();
+			s.setPay( new Float( rs.getFloat("pay") ) );  rs.wasNull();
+			rs.getLong("other"); rs.wasNull(); s.setOther(null);
+			rs.close();
+			select.close();
+		}
+		c.commit();
+	}*/
+
+	private void hibernate(Session s, Simple[] simples, Serializable[] ids, int N, String runname) throws Exception {
+		s.createQuery("from Simple s").list();
+		s.connection().commit();
+	}
+
+	private void directJDBC(Connection c, Simple[] simples, Serializable[] ids, int N, String runname) throws SQLException {
+		List result=new ArrayList();
+		PreparedStatement select = c.prepareStatement("SELECT s.id_ as id_, s.name as name, s.address as address, s.count_ as count_, s.date_ as date_, s.pay as pay, s.other as other FROM Simple s");
+		ResultSet rs = select.executeQuery();
+		while ( rs.next() ) {
+			/*new Long( rs.getLong(1) );
+			rs.getString(2);
+			rs.getString(3);
+			rs.getInt(4);
+			rs.getDate(5);
+			rs.getFloat(6);
+			rs.getLong(7);*/
+			Simple s = new Simple();
+			new Long( rs.getLong("id_") );  rs.wasNull();
+			s.setName( rs.getString("name") );  rs.wasNull();
+			s.setAddress( rs.getString("address") );  rs.wasNull();
+			s.setCount( rs.getInt("count_") );  rs.wasNull();
+			s.setDate( rs.getTimestamp("date_") );  rs.wasNull();
+			s.setPay( new Float( rs.getFloat("pay") ) );  rs.wasNull();
+			rs.getLong("other"); rs.wasNull(); s.setOther(null);
+			result.add(s);
+		}
+		rs.close();
+		select.close();
+		c.commit();
+	}
+
+	public String[] getMappings() {
+		return new String[] { "legacy/Simple.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new TestSuite(NewerPerformanceTest.class);
+	}
+
+	public static void main(String[] args) throws Exception {
+		TestRunner.run( suite() );
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NonReflectiveBinderTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NonReflectiveBinderTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/NonReflectiveBinderTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,189 @@
+//$Id: NonReflectiveBinderTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.mapping.Bag;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.MetaAttribute;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.junit.UnitTestCase;
+
+
+public class NonReflectiveBinderTest extends UnitTestCase {
+
+	private Configuration cfg;
+
+	public NonReflectiveBinderTest(String x) {
+		super( x );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "legacy/Wicked.hbm.xml"};
+	}
+
+	public static Test suite() {
+		return new TestSuite( NonReflectiveBinderTest.class );
+	}
+
+	protected void setUp() throws Exception {
+		super.setUp();
+		cfg = new Configuration()
+				.addResource( "org/hibernate/test/legacy/Wicked.hbm.xml" );
+		cfg.buildMappings();
+	}
+
+	protected void tearDown() throws Exception {
+		cfg = null;
+		super.tearDown();
+	}
+
+	public void testMetaInheritance() {
+		PersistentClass cm = cfg.getClassMapping("org.hibernate.test.legacy.Wicked");
+		Map m = cm.getMetaAttributes();
+		assertNotNull(m);
+		assertNotNull(cm.getMetaAttribute("global"));
+		assertNull(cm.getMetaAttribute("globalnoinherit"));
+		
+		MetaAttribute metaAttribute = cm.getMetaAttribute("implements");
+		assertNotNull(metaAttribute);
+		assertEquals("implements", metaAttribute.getName());
+		assertTrue(metaAttribute.isMultiValued());
+		assertEquals(3, metaAttribute.getValues().size());
+		assertEquals("java.lang.Observer",metaAttribute.getValues().get(0));
+		assertEquals("java.lang.Observer",metaAttribute.getValues().get(1));
+		assertEquals("org.foo.BogusVisitor",metaAttribute.getValues().get(2));
+				
+		/*Property property = cm.getIdentifierProperty();
+		property.getMetaAttribute(null);*/
+		
+		Iterator propertyIterator = cm.getPropertyIterator();
+		while (propertyIterator.hasNext()) {
+			Property element = (Property) propertyIterator.next();
+			System.out.println(element);
+			Map ma = element.getMetaAttributes();
+			assertNotNull(ma);
+			assertNotNull(element.getMetaAttribute("global"));
+			MetaAttribute metaAttribute2 = element.getMetaAttribute("implements");
+			assertNotNull(metaAttribute2);
+			assertNull(element.getMetaAttribute("globalnoinherit"));
+						
+		}
+		
+		Property element = cm.getProperty("component");
+		Map ma = element.getMetaAttributes();
+		assertNotNull(ma);
+		assertNotNull(element.getMetaAttribute("global"));
+		assertNotNull(element.getMetaAttribute("componentonly"));
+		assertNotNull(element.getMetaAttribute("allcomponent"));
+		assertNull(element.getMetaAttribute("globalnoinherit"));							
+		
+		MetaAttribute compimplements = element.getMetaAttribute("implements");
+		assertNotNull(compimplements);
+		assertEquals(compimplements.getValue(), "AnotherInterface");
+		
+		Property xp = ((Component)element.getValue()).getProperty( "x" );
+		MetaAttribute propximplements = xp.getMetaAttribute( "implements" );
+		assertNotNull(propximplements);
+		assertEquals(propximplements.getValue(), "AnotherInterface");
+		
+		
+	}
+
+	// HBX-718
+	public void testNonMutatedInheritance() {
+		PersistentClass cm = cfg.getClassMapping("org.hibernate.test.legacy.Wicked");
+		MetaAttribute metaAttribute = cm.getMetaAttribute( "globalmutated" );
+		
+		assertNotNull(metaAttribute);
+		/*assertEquals( metaAttribute.getValues().size(), 2 );		
+		assertEquals( "top level", metaAttribute.getValues().get(0) );*/
+		assertEquals( "wicked level", metaAttribute.getValue() );
+		
+		Property property = cm.getProperty( "component" );
+		MetaAttribute propertyAttribute = property.getMetaAttribute( "globalmutated" );
+		
+		assertNotNull(propertyAttribute);
+		/*assertEquals( propertyAttribute.getValues().size(), 3 );
+		assertEquals( "top level", propertyAttribute.getValues().get(0) );
+		assertEquals( "wicked level", propertyAttribute.getValues().get(1) );*/
+		assertEquals( "monetaryamount level", propertyAttribute.getValue() );
+		
+		org.hibernate.mapping.Component component = (Component)property.getValue();
+		property = component.getProperty( "x" );
+		propertyAttribute = property.getMetaAttribute( "globalmutated" );
+		
+		assertNotNull(propertyAttribute);
+		/*assertEquals( propertyAttribute.getValues().size(), 4 );
+		assertEquals( "top level", propertyAttribute.getValues().get(0) );
+		assertEquals( "wicked level", propertyAttribute.getValues().get(1) );
+		assertEquals( "monetaryamount level", propertyAttribute.getValues().get(2) );*/
+		assertEquals( "monetaryamount x level", propertyAttribute.getValue() );
+		
+		property = cm.getProperty( "sortedEmployee" );
+		propertyAttribute = property.getMetaAttribute( "globalmutated" );
+		
+		assertNotNull(propertyAttribute);
+		/*assertEquals( propertyAttribute.getValues().size(), 3 );
+		assertEquals( "top level", propertyAttribute.getValues().get(0) );
+		assertEquals( "wicked level", propertyAttribute.getValues().get(1) );*/
+		assertEquals( "sortedemployee level", propertyAttribute.getValue() );
+		
+		property = cm.getProperty( "anotherSet" );
+		propertyAttribute = property.getMetaAttribute( "globalmutated" );
+		
+		assertNotNull(propertyAttribute);
+		/*assertEquals( propertyAttribute.getValues().size(), 2 );
+		assertEquals( "top level", propertyAttribute.getValues().get(0) );*/
+		assertEquals( "wicked level", propertyAttribute.getValue() );
+				
+		Bag bag = (Bag) property.getValue();
+		component = (Component)bag.getElement(); 
+		
+		assertEquals(4,component.getMetaAttributes().size());
+		
+		metaAttribute = component.getMetaAttribute( "globalmutated" );
+		/*assertEquals( metaAttribute.getValues().size(), 3 );
+		assertEquals( "top level", metaAttribute.getValues().get(0) );
+		assertEquals( "wicked level", metaAttribute.getValues().get(1) );*/
+		assertEquals( "monetaryamount anotherSet composite level", metaAttribute.getValue() );		
+		
+		property = component.getProperty( "emp" );
+		propertyAttribute = property.getMetaAttribute( "globalmutated" );
+		
+		assertNotNull(propertyAttribute);
+		/*assertEquals( propertyAttribute.getValues().size(), 4 );
+		assertEquals( "top level", propertyAttribute.getValues().get(0) );
+		assertEquals( "wicked level", propertyAttribute.getValues().get(1) );
+		assertEquals( "monetaryamount anotherSet composite level", propertyAttribute.getValues().get(2) );*/
+		assertEquals( "monetaryamount anotherSet composite property emp level", propertyAttribute.getValue() );
+		
+		
+		property = component.getProperty( "empinone" );
+		propertyAttribute = property.getMetaAttribute( "globalmutated" );
+		
+		assertNotNull(propertyAttribute);
+		/*assertEquals( propertyAttribute.getValues().size(), 4 );
+		assertEquals( "top level", propertyAttribute.getValues().get(0) );
+		assertEquals( "wicked level", propertyAttribute.getValues().get(1) );
+		assertEquals( "monetaryamount anotherSet composite level", propertyAttribute.getValues().get(2) );*/
+		assertEquals( "monetaryamount anotherSet composite property empinone level", propertyAttribute.getValue() );
+		
+		
+	}
+	
+	public void testComparator() {
+		PersistentClass cm = cfg.getClassMapping("org.hibernate.test.legacy.Wicked");
+		
+		Property property = cm.getProperty("sortedEmployee");
+		Collection col = (Collection) property.getValue();
+		assertEquals(col.getComparatorClassName(),"org.hibernate.test.legacy.NonExistingComparator");
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Object2.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Object2.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Object2.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping default-lazy="false">
+    <class
+        name="org.hibernate.test.legacy.Object2"
+        table="object2"
+        dynamic-update="false"
+        dynamic-insert="false"
+    >
+        <cache usage="read-write" />
+
+        <id
+            name="id"
+            column="id"
+            type="java.lang.Long"
+        >
+            <generator class="foreign">
+                <param name="property">belongsToMainObj</param>
+            </generator>
+        </id>
+
+        <property
+            name="dummy"
+            type="java.lang.String"
+            update="true"
+            insert="true"
+            column="xdummy"
+        />
+
+        <one-to-one
+            name="belongsToMainObj"
+            class="org.hibernate.test.legacy.MainObject"
+            cascade="none"
+            outer-join="auto"
+            constrained="true"
+        />
+
+        <!--
+            To add non XDoclet property mappings, create a file named
+                hibernate-properties-Object2.xml
+            containing the additional properties and place it in your merge dir.
+        -->
+
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Object2.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Object2.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Object2.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+package org.hibernate.test.legacy;
+
+/**
+ * 
+ * @author Wolfgang Voelkl
+ * 
+ */
+public class Object2 {
+	private Long id;
+	private String dummy;
+	private MainObject belongsToMainObj;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long l) {
+		this.id = l;
+	}
+	
+	public String getDummy() {
+		return dummy;
+	}
+
+	public void setDummy(String string) {
+		dummy = string;
+	}
+
+	public MainObject getBelongsToMainObj() {
+		return belongsToMainObj;
+	}
+
+	public void setBelongsToMainObj(MainObject object) {
+		belongsToMainObj = object;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/One.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/One.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/One.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping default-lazy="false">
+	<class name="org.hibernate.test.legacy.One" table="one">
+		<id name="key" column="one_key">
+			<generator class="native" />
+		</id>
+		<property name="x"/>
+		<property column="one_value" name="value"/>
+		<set name="manies" inverse="true" lazy="true">
+			<key column="one_key"/>
+			<one-to-many class="org.hibernate.test.legacy.Many"/>
+		</set>
+	</class>
+</hibernate-mapping>
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/One.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/One.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/One.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: One.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.Set;
+
+public class One {
+	Long key;
+	String value;
+	Set manies;
+	private int x;
+	
+	public int getX() {
+		return x;
+	}
+	public void setX(int x) {
+		this.x = x;
+	}
+	
+	public void setKey(Long key) {
+		this.key = key;
+	}
+	
+	public Long getKey() {
+		return this.key;
+	}
+	
+	public void setValue(String value) {
+		this.value = value;
+	}
+	
+	public String getValue() {
+		return this.value;
+	}
+	
+	public Set getManies() {
+		return manies;
+	}
+	
+	public void setManies(Set manies) {
+		this.manies = manies;
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/OneToOneCacheTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/OneToOneCacheTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/OneToOneCacheTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,120 @@
+//$Id: OneToOneCacheTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+import junit.framework.Test;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Simple testcase to illustrate HB-992
+ *
+ * @author Wolfgang Voelkl, michael
+ */
+public class OneToOneCacheTest extends LegacyTestCase {
+
+	private Serializable generatedId;
+
+	public OneToOneCacheTest(String x) {
+		super( x );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "legacy/Object2.hbm.xml", "legacy/MainObject.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( OneToOneCacheTest.class );
+	}
+
+	public void testOneToOneCache() throws HibernateException {
+
+		//create a new MainObject
+		createMainObject();
+		// load the MainObject
+		readMainObject();
+
+		//create and add Ojbect2
+		addObject2();
+
+		//here the newly created Object2 is written to the database
+		//but the MainObject does not know it yet
+		MainObject mainObject = readMainObject();
+
+		assertNotNull( mainObject.getObj2() );
+
+		// after evicting, it works.
+		getSessions().evict( MainObject.class );
+
+		mainObject = readMainObject();
+
+		assertNotNull( mainObject.getObj2() );
+
+	}
+
+	/**
+	 * creates a new MainObject
+	 * <p/>
+	 * one hibernate transaction !
+	 */
+	private void createMainObject() throws HibernateException {
+		Session session = openSession();
+		Transaction tx = session.beginTransaction();
+
+		MainObject mo = new MainObject();
+		mo.setDescription( "Main Test" );
+
+		generatedId = session.save( mo );
+
+		tx.commit();
+		session.close();
+	}
+
+	/**
+	 * loads the newly created MainObject
+	 * and adds a new Object2 to it
+	 * <p/>
+	 * one hibernate transaction
+	 */
+	private void addObject2() throws HibernateException {
+		Session session = openSession();
+		Transaction tx = session.beginTransaction();
+
+		MainObject mo =
+				( MainObject ) session.load( MainObject.class, generatedId );
+
+		Object2 toAdd = new Object2();
+		toAdd.setDummy( "test" );
+
+		//toAdd should now be saved by cascade
+		mo.setObj2( toAdd );
+
+		tx.commit();
+		session.close();
+	}
+
+	/**
+	 * reads the newly created MainObject
+	 * and its Object2 if it exists
+	 * <p/>
+	 * one hibernate transaction
+	 */
+	private MainObject readMainObject() throws HibernateException {
+		Long returnId = null;
+		Session session = openSession();
+		Transaction tx = session.beginTransaction();
+
+		Serializable id = generatedId;
+
+		MainObject mo = ( MainObject ) session.load( MainObject.class, id );
+
+		tx.commit();
+		session.close();
+
+		return mo;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Outer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Outer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Outer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+/**
+ * @author Stefano Travelli
+ */
+public class Outer implements Serializable {
+	private OuterKey id;
+	private String bubu;
+
+	public OuterKey getId() {
+		return id;
+	}
+
+	public void setId(OuterKey id) {
+		this.id = id;
+	}
+
+	public String getBubu() {
+		return bubu;
+	}
+
+	public void setBubu(String bubu) {
+		this.bubu = bubu;
+	}
+
+	public boolean equals(Object o) {
+		if (this == o) return true;
+		if (!(o instanceof Outer)) return false;
+
+		final Outer cidDetail = (Outer) o;
+
+		if (id != null ? !id.equals(cidDetail.id) : cidDetail.id != null) return false;
+
+		return true;
+	}
+
+	public int hashCode() {
+		return (id != null ? id.hashCode() : 0);
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/OuterKey.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/OuterKey.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/OuterKey.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+/**
+ * @author Stefano Travelli
+ */
+public class OuterKey implements Serializable {
+	private Middle master;
+	private String detailId;
+
+	public Middle getMaster() {
+		return master;
+	}
+
+	public void setMaster(Middle master) {
+		this.master = master;
+	}
+
+	public String getDetailId() {
+		return detailId;
+	}
+
+	public void setDetailId(String detailId) {
+		this.detailId = detailId;
+	}
+
+	public boolean equals(Object o) {
+		if (this == o) return true;
+		if (!(o instanceof OuterKey)) return false;
+
+		final OuterKey cidDetailID = (OuterKey) o;
+
+		if (detailId != null ? !detailId.equals(cidDetailID.detailId) : cidDetailID.detailId != null) return false;
+		if (master != null ? !master.equals(cidDetailID.master) : cidDetailID.master != null) return false;
+
+		return true;
+	}
+
+	public int hashCode() {
+		int result;
+		result = (master != null ? master.hashCode() : 0);
+		result = 29 * result + (detailId != null ? detailId.hashCode() : 0);
+		return result;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Parent.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Parent.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Parent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+//$Id: Parent.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+public class Parent {
+	private long id;
+	private int count;
+	private Child child;
+	private Object any;
+	private int x;
+	
+	public int getX() {
+		return x;
+	}
+	public void setX(int x) {
+		this.x = x;
+	}
+	
+	public int getCount() {
+		return count;
+	}
+	
+	
+	public long getId() {
+		return id;
+	}
+	
+	
+	public void setCount(int count) {
+		this.count = count;
+	}
+	
+	
+	public void setId(long id) {
+		this.id = id;
+	}
+	
+	
+	public Child getChild() {
+		return child;
+	}
+	
+	
+	public void setChild(Child child) {
+		this.child = child;
+	}
+	
+	public Object getAny() {
+		return any;
+	}
+
+	public void setAny(Object any) {
+		this.any = any;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ParentChild.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ParentChild.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ParentChild.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+	
+	<class name="org.hibernate.test.legacy.Parent">
+		<id name="id" type="long">
+			<generator class="native"> <!--seqhilo-->
+				<!--<param>foo_seq</param>-->
+			</generator>
+		</id>
+		<property name="x"/>
+		<property name="count" column="count_"/>
+		<one-to-one name="child"/>
+        <property name="any" type="object">
+        	<column name="any_id"/>
+        	<column name="any_class"/>
+        </property>
+	</class>
+	
+	<class name="org.hibernate.test.legacy.Child">
+		<id name="id" type="long">
+			<generator class="assigned"/>
+		</id>
+		<property name="x"/>
+		<one-to-one name="parent" class="org.hibernate.test.legacy.Parent" constrained="true" foreign-key="parentfk"/>
+		<property name="count" column="count_"/>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ParentChildTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ParentChildTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ParentChildTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,1083 @@
+//$Id: ParentChildTest.java 11089 2007-01-24 14:34:22Z max.andersen at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+
+import org.hibernate.Criteria;
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.ObjectNotFoundException;
+import org.hibernate.ReplicationMode;
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.criterion.Expression;
+import org.hibernate.dialect.DB2Dialect;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.impl.SessionImpl;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+
+public class ParentChildTest extends LegacyTestCase {
+
+	public ParentChildTest(String x) {
+		super(x);
+	}
+
+	public String[] getMappings() {
+		return new String[] {
+			"legacy/ParentChild.hbm.xml",
+			"legacy/FooBar.hbm.xml",
+		 	"legacy/Baz.hbm.xml",
+		 	"legacy/Qux.hbm.xml",
+		 	"legacy/Glarch.hbm.xml",
+		 	"legacy/Fum.hbm.xml",
+		 	"legacy/Fumm.hbm.xml",
+		 	"legacy/Fo.hbm.xml",
+		 	"legacy/One.hbm.xml",
+		 	"legacy/Many.hbm.xml",
+		 	"legacy/Immutable.hbm.xml",
+		 	"legacy/Fee.hbm.xml",
+		 	"legacy/Vetoer.hbm.xml",
+		 	"legacy/Holder.hbm.xml",
+		 	"legacy/Simple.hbm.xml",
+		 	"legacy/Container.hbm.xml",
+		 	"legacy/Circular.hbm.xml",
+		 	"legacy/Stuff.hbm.xml"
+		};
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ParentChildTest.class );
+	}
+
+	public void testReplicate() throws Exception {
+		Session s = openSession();
+		Container baz = new Container();
+		Contained f = new Contained();
+		List list = new ArrayList();
+		list.add(baz);
+		f.setBag(list);
+		List list2 = new ArrayList();
+		list2.add(f);
+		baz.setBag(list2);
+		s.save(f);
+		s.save(baz);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		s.replicate(baz, ReplicationMode.OVERWRITE);
+		
+		// HHH-2378
+		SessionImpl x = (SessionImpl)s;
+		EntityEntry entry = x.getPersistenceContext().getEntry( baz );
+		assertNull(entry.getVersion());
+		
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		s.replicate(baz, ReplicationMode.IGNORE);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		s.delete(baz);
+		s.delete(f);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testQueryOneToOne() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Serializable id = s.save( new Parent() );
+		assertTrue( s.find("from Parent p left join fetch p.child").size()==1 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Parent p = (Parent) s.createQuery("from Parent p left join fetch p.child").uniqueResult();
+		assertTrue( p.getChild()==null );
+		s.find("from Parent p join p.child c where c.x > 0");
+		s.find("from Child c join c.parent p where p.x > 0");
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( s.get(Parent.class, id) );
+		t.commit();
+		s.close();
+	}
+
+	public void testProxyReuse() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		FooProxy foo = new Foo();
+		FooProxy foo2 = new Foo();
+		Serializable id = s.save(foo);
+		Serializable id2 = s.save(foo2);
+		foo2.setInt(1234567);
+		foo.setInt(1234);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		foo = (FooProxy) s.load(Foo.class, id);
+		foo2 = (FooProxy) s.load(Foo.class, id2);
+		assertFalse( Hibernate.isInitialized(foo) );
+		Hibernate.initialize(foo2);
+		Hibernate.initialize(foo);
+		assertTrue( foo.getComponent().getImportantDates().length==4 );
+		assertTrue( foo2.getComponent().getImportantDates().length==4 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		foo.setFloat( new Float(1.2f) );
+		foo2.setFloat( new Float(1.3f) );
+		foo2.getDependent().setKey(null);
+		foo2.getComponent().getSubcomponent().getFee().setKey(null);
+		assertFalse( foo2.getKey().equals(id) );
+		s.save(foo, "xyzid");
+		s.update(foo2, id); //intentionally id, not id2!
+		assertEquals( foo2.getKey(), id );
+		assertTrue( foo2.getInt()==1234567 );
+		assertEquals( foo.getKey(), "xyzid" );
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		foo = (FooProxy) s.load(Foo.class, id);
+		assertTrue( foo.getInt()==1234567 );
+		assertTrue( foo.getComponent().getImportantDates().length==4 );
+		String feekey = foo.getDependent().getKey();
+		String fookey = foo.getKey();
+		s.delete(foo);
+		s.delete( s.get(Foo.class, id2) );
+		s.delete( s.get(Foo.class, "xyzid") );
+		assertTrue( s.delete("from java.lang.Object")==3 );
+		t.commit();
+		s.close();
+		
+		//to account for new id rollback shit
+		foo.setKey(fookey);
+		foo.getDependent().setKey(feekey);
+		foo.getComponent().setGlarch(null);
+		foo.getComponent().setSubcomponent(null);
+		
+		s = openSession();
+		t = s.beginTransaction();
+		//foo.getComponent().setGlarch(null); //no id property!
+		s.replicate(foo, ReplicationMode.OVERWRITE);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Foo refoo = (Foo) s.get(Foo.class, id);
+		assertEquals( feekey, refoo.getDependent().getKey() );
+		s.delete(refoo);
+		t.commit();
+		s.close();
+	}
+
+	public void testComplexCriteria() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Baz baz = new Baz();
+		s.save(baz);
+		baz.setDefaults();
+		Map topGlarchez = new HashMap();
+		baz.setTopGlarchez(topGlarchez);
+		Glarch g1 = new Glarch();
+		g1.setName("g1");
+		s.save(g1);
+		Glarch g2 = new Glarch();
+		g2.setName("g2");
+		s.save(g2);
+		g1.setProxyArray( new GlarchProxy[] {g2} );
+		topGlarchez.put( new Character('1'),g1 );
+		topGlarchez.put( new Character('2'), g2);
+		Foo foo1 = new Foo();
+		Foo foo2 = new Foo();
+		s.save(foo1);
+		s.save(foo2);
+		baz.getFooSet().add(foo1);
+		baz.getFooSet().add(foo2);
+		baz.setFooArray( new FooProxy[] { foo1 } );
+
+		LockMode lockMode = (getDialect() instanceof DB2Dialect) ? LockMode.READ : LockMode.UPGRADE;
+
+		Criteria crit = s.createCriteria(Baz.class);
+		crit.createCriteria("topGlarchez")
+			.add( Expression.isNotNull("name") )
+			.createCriteria("proxyArray")
+				.add( Expression.eqProperty("name", "name") )
+				.add( Expression.eq("name", "g2") )
+				.add( Expression.gt("x", new Integer(-666) ) );
+		crit.createCriteria("fooSet")
+			.add( Expression.isNull("null") )
+			.add( Expression.eq("string", "a string") )
+			.add( Expression.lt("integer", new Integer(-665) ) );
+		crit.createCriteria("fooArray")
+			.add( Expression.eq("string", "a string") )
+			.setLockMode(lockMode);
+
+		List list = crit.list();
+		assertTrue( list.size()==2 );
+		
+		s.createCriteria(Glarch.class).setLockMode(LockMode.UPGRADE).list();
+		s.createCriteria(Glarch.class).setLockMode(Criteria.ROOT_ALIAS, LockMode.UPGRADE).list();
+		
+		g2.setName(null);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		
+		list = s.createCriteria(Baz.class).add( Expression.isEmpty("fooSet") ).list();
+		assertEquals( list.size(), 0 );
+
+		list = s.createCriteria(Baz.class).add( Expression.isNotEmpty("fooSet") ).list();
+		assertEquals( new HashSet(list).size(), 1 );
+
+		list = s.createCriteria(Baz.class).add( Expression.sizeEq("fooSet", 2) ).list();
+		assertEquals( new HashSet(list).size(), 1 );
+		
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+
+		crit = s.createCriteria(Baz.class)
+			.setLockMode(lockMode);
+		crit.createCriteria("topGlarchez")
+			.add( Expression.gt( "x", new Integer(-666) ) );
+		crit.createCriteria("fooSet")
+			.add( Expression.isNull("null") );
+		list = crit.list();
+
+		assertTrue( list.size()==4 );
+		baz = (Baz) crit.uniqueResult();
+		assertTrue( Hibernate.isInitialized(baz.getTopGlarchez()) ); //cos it is nonlazy
+		assertTrue( !Hibernate.isInitialized(baz.getFooSet()) );
+
+		/*list = s.createCriteria(Baz.class)
+			.createCriteria("fooSet.foo.component.glarch")
+				.add( Expression.eq("name", "xxx") )
+			.add( Expression.eq("fooSet.foo.component.glarch.name", "xxx") )
+			.list();
+		assertTrue( list.size()==0 );*/
+		list = s.createCriteria(Baz.class)
+			.createCriteria("fooSet")
+				.createCriteria("foo")
+					.createCriteria("component.glarch")
+						.add( Expression.eq("name", "xxx") )
+			.list();
+		assertTrue( list.size()==0 );
+
+		list = s.createCriteria(Baz.class)
+			.createAlias("fooSet", "foo")
+			.createAlias("foo.foo", "foo2")
+			.setLockMode("foo2", lockMode)
+			.add( Expression.isNull("foo2.component.glarch") )
+			.createCriteria("foo2.component.glarch")
+				.add( Expression.eq("name", "xxx") )
+			.list();
+		assertTrue( list.size()==0 );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+
+		crit = s.createCriteria(Baz.class);
+		crit.createCriteria("topGlarchez")
+			.add( Expression.isNotNull("name") );
+		crit.createCriteria("fooSet")
+			.add( Expression.isNull("null") );
+
+		list = crit.list();
+		assertTrue( list.size()==2 );
+		baz = (Baz) crit.uniqueResult();
+		assertTrue( Hibernate.isInitialized(baz.getTopGlarchez()) ); //cos it is nonlazy
+		assertTrue( !Hibernate.isInitialized(baz.getFooSet()) );
+		
+		
+		list = s.createCriteria(Child.class).setFetchMode("parent", FetchMode.JOIN).list();
+		
+		s.delete("from Glarch g");
+		s.delete( s.get(Foo.class, foo1.getKey() ) );
+		s.delete( s.get(Foo.class, foo2.getKey() ) );
+		s.delete(baz);
+		t.commit();
+		s.close();
+	}
+
+	public void testClassWhere() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Baz baz = new Baz();
+		baz.setParts( new ArrayList() );
+		Part p1 = new Part();
+		p1.setDescription("xyz");
+		Part p2 = new Part();
+		p2.setDescription("abc");
+		baz.getParts().add(p1);
+		baz.getParts().add(p2);
+		s.save(baz);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		assertTrue( s.createCriteria(Part.class).list().size()==1 ); //there is a where condition on Part mapping
+		assertTrue( s.createCriteria(Part.class).add( Expression.eq( "id", p1.getId() ) ).list().size()==1 );
+		assertTrue( s.createQuery("from Part").list().size()==1 );
+		assertTrue( s.createQuery("from Baz baz join baz.parts").list().size()==2 );
+		baz = (Baz) s.createCriteria(Baz.class).uniqueResult();
+		assertTrue( s.createFilter( baz.getParts(), "" ).list().size()==2 );
+		//assertTrue( baz.getParts().size()==1 );
+		s.delete( s.get( Part.class, p1.getId() ));
+		s.delete( s.get( Part.class, p2.getId() ));
+		s.delete(baz);
+		t.commit();
+		s.close();
+	}
+
+	public void testClassWhereManyToMany() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Baz baz = new Baz();
+		baz.setMoreParts( new ArrayList() );
+		Part p1 = new Part();
+		p1.setDescription("xyz");
+		Part p2 = new Part();
+		p2.setDescription("abc");
+		baz.getMoreParts().add(p1);
+		baz.getMoreParts().add(p2);
+		s.save(baz);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		assertTrue( s.createCriteria(Part.class).list().size()==1 ); //there is a where condition on Part mapping
+		assertTrue( s.createCriteria(Part.class).add( Expression.eq( "id", p1.getId() ) ).list().size()==1 );
+		assertTrue( s.createQuery("from Part").list().size()==1 );
+		assertTrue( s.createQuery("from Baz baz join baz.moreParts").list().size()==2 );
+		baz = (Baz) s.createCriteria(Baz.class).uniqueResult();
+		assertTrue( s.createFilter( baz.getMoreParts(), "" ).list().size()==2 );
+		//assertTrue( baz.getParts().size()==1 );
+		s.delete( s.get( Part.class, p1.getId() ));
+		s.delete( s.get( Part.class, p2.getId() ));
+		s.delete(baz);
+		t.commit();
+		s.close();
+	}
+
+	public void testCollectionQuery() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Simple s1 = new Simple();
+		s1.setName("s");
+		s1.setCount(0);
+		Simple s2 = new Simple();
+		s2.setCount(2);
+		Simple s3 = new Simple();
+		s3.setCount(3);
+		s.save( s1, new Long(1) ); s.save( s2, new Long(2) ); s.save( s3, new Long(3) );
+		Container c = new Container();
+		Contained cd = new Contained();
+		List bag = new ArrayList();
+		bag.add(cd);
+		c.setBag(bag);
+		List l = new ArrayList();
+		l.add(s1);
+		l.add(s3);
+		l.add(s2);
+		c.setOneToMany(l);
+		l = new ArrayList();
+		l.add(s1);
+		l.add(null);
+		l.add(s2);
+		c.setManyToMany(l);
+		s.save(c);
+		Container cx = new Container();
+		s.save(cx);
+		Simple sx = new Simple();
+		sx.setCount(5);
+		sx.setName("s");
+		s.save( sx, new Long(5) );
+		assertTrue(
+			s.find("select c from ContainerX c, Simple s where c.oneToMany[2] = s")
+			.size() == 1
+		);
+		assertTrue(
+			s.find("select c from ContainerX c, Simple s where c.manyToMany[2] = s")
+			.size() == 1
+		);
+		assertTrue(
+			s.find("select c from ContainerX c, Simple s where s = c.oneToMany[2]")
+			.size() == 1
+		);
+		assertTrue(
+			s.find("select c from ContainerX c, Simple s where s = c.manyToMany[2]")
+			.size() == 1
+		);
+		assertTrue(
+			s.find("select c from ContainerX c where c.oneToMany[0].name = 's'")
+			.size() == 1
+		);
+		assertTrue(
+			s.find("select c from ContainerX c where c.manyToMany[0].name = 's'")
+			.size() == 1
+		);
+		assertTrue(
+			s.find("select c from ContainerX c where 's' = c.oneToMany[2 - 2].name")
+			.size() == 1
+		);
+		assertTrue(
+			s.find("select c from ContainerX c where 's' = c.manyToMany[(3+1)/4-1].name")
+			.size() == 1
+		);
+		assertTrue(
+			s.find("select c from ContainerX c where c.oneToMany[ c.manyToMany[0].count ].name = 's'")
+			.size() == 1
+		);
+		assertTrue(
+			s.find("select c from ContainerX c where c.manyToMany[ c.oneToMany[0].count ].name = 's'")
+			.size() == 1
+		);
+		if ( ! ( getDialect() instanceof MySQLDialect ) && !(getDialect() instanceof org.hibernate.dialect.TimesTenDialect) ) {
+			assertTrue(
+				s.find("select c from ContainerX c where c.manyToMany[ maxindex(c.manyToMany) ].count = 2")
+				.size() == 1
+			);
+		}
+		assertTrue( s.contains(cd) );
+		if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof HSQLDialect) )  {
+			s.filter( c.getBag(), "where 0 in elements(this.bag)" );
+			s.filter( c.getBag(), "where 0 in elements(this.lazyBag)" );
+		}
+		s.find("select count(comp.name) from ContainerX c join c.components comp");
+		s.delete(cd);
+		s.delete(c);
+		s.delete(s1);
+		s.delete(s2);
+		s.delete(s3);
+		s.delete(cx);
+		s.delete(sx);
+		t.commit();
+		s.close();
+	}
+
+	public void testParentChild() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Parent p = new Parent();
+		Child c = new Child();
+		c.setParent(p);
+		p.setChild(c);
+		s.save(p);
+		s.save(c);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Child) s.load( Child.class, new Long( c.getId() ) );
+		p = c.getParent();
+		assertTrue( "1-1 parent", p!=null );
+		c.setCount(32);
+		p.setCount(66);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Child) s.load( Child.class, new Long( c.getId() ) );
+		p = c.getParent();
+		assertTrue( "1-1 update", p.getCount()==66 );
+		assertTrue( "1-1 update", c.getCount()==32 );
+		assertTrue(
+			"1-1 query",
+			s.find("from Child c where c.parent.count=66").size()==1
+		);
+		assertTrue(
+			"1-1 query",
+			( (Object[]) s.find("from Parent p join p.child c where p.count=66").get(0) ).length==2
+		);
+		s.find("select c, c.parent from Child c order by c.parent.count");
+		s.find("select c, c.parent from Child c where c.parent.count=66 order by c.parent.count");
+		s.iterate("select c, c.parent, c.parent.count from Child c order by c.parent.count");
+		assertTrue(
+			"1-1 query",
+			s.find("FROM Parent AS p WHERE p.count = ?", new Integer(66), Hibernate.INTEGER).size()==1
+		);
+		s.delete(c); s.delete(p);
+		t.commit();
+		s.close();
+	}
+
+	public void testParentNullChild() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Parent p = new Parent();
+		s.save(p);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		p = (Parent) s.load( Parent.class, new Long( p.getId() ) );
+		assertTrue( p.getChild()==null );
+		p.setCount(66);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		p = (Parent) s.load( Parent.class, new Long( p.getId() ) );
+		assertTrue( "null 1-1 update", p.getCount()==66 );
+		assertTrue( p.getChild()==null );
+		s.delete(p);
+		t.commit();
+		s.close();
+	}
+
+	public void testManyToMany() throws Exception {
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Container c = new Container();
+		c.setManyToMany( new ArrayList() );
+		c.setBag( new ArrayList() );
+		Simple s1 = new Simple();
+		Simple s2 = new Simple();
+		s1.setCount(123); s2.setCount(654);
+		Contained c1 = new Contained();
+		c1.setBag( new ArrayList() );
+		c1.getBag().add(c);
+		c.getBag().add(c1);
+		c.getManyToMany().add(s1);
+		c.getManyToMany().add(s2);
+		Serializable cid = s.save(c); //s.save(c1);
+		s.save(s1, new Long(12) ); s.save(s2, new Long(-1) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Container) s.load(Container.class, cid);
+		assertTrue( c.getBag().size()==1 );
+		assertTrue( c.getManyToMany().size()==2 );
+		c1 = (Contained) c.getBag().iterator().next();
+		assertTrue( c.getBag().size()==1 );
+		c.getBag().remove(c1);
+		c1.getBag().remove(c);
+		assertTrue( c.getManyToMany().remove(0)!=null );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Container) s.load(Container.class, cid);
+		assertTrue( c.getBag().size()==0 );
+		assertTrue( c.getManyToMany().size()==1 );
+		c1 = (Contained) s.load( Contained.class, new Long(c1.getId()) );
+		assertTrue( c1.getBag().size()==0 );
+		assertTrue( s.delete("from ContainerX c")==1 );
+		assertTrue( s.delete("from Contained")==1 );
+		assertTrue( s.delete("from Simple")==2 );
+		t.commit();
+		s.close();
+	}
+
+	public void testContainer() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Container c = new Container();
+		Simple x = new Simple(); x.setCount(123);
+		Simple y = new Simple(); y.setCount(456);
+		s.save( x, new Long(1) ); s.save( y, new Long(0) );
+		List o2m = new ArrayList();
+		o2m.add(x); o2m.add(null); o2m.add(y);
+		List m2m = new ArrayList();
+		m2m.add(x); m2m.add(null); m2m.add(y);
+		c.setOneToMany(o2m); c.setManyToMany(m2m);
+		List comps = new ArrayList();
+		Container.ContainerInnerClass ccic = new Container.ContainerInnerClass();
+		ccic.setName("foo");
+		ccic.setSimple(x);
+		comps.add(ccic);
+		comps.add(null);
+		ccic = new Container.ContainerInnerClass();
+		ccic.setName("bar");
+		ccic.setSimple(y);
+		comps.add(ccic);
+		HashSet compos = new HashSet();
+		compos.add(ccic);
+		c.setComposites(compos);
+		c.setComponents(comps);
+		One one = new One();
+		Many many = new Many();
+		HashSet manies = new HashSet();
+		manies.add(many);
+		one.setManies(manies);
+		many.setOne(one);
+		ccic.setMany(many);
+		ccic.setOne(one);
+		s.save(one);
+		s.save(many);
+		s.save(c);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Long count = (Long) s.createQuery("select count(*) from ContainerX as c join c.components as ce join ce.simple as s where ce.name='foo'").uniqueResult();
+		assertTrue( count.intValue()==1 );
+		List res = s.find("select c, s from ContainerX as c join c.components as ce join ce.simple as s where ce.name='foo'");
+		assertTrue(res.size()==1);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Container) s.load( Container.class, new Long( c.getId() ) );
+		System.out.println( c.getOneToMany() );
+		System.out.println( c.getManyToMany() );
+		System.out.println( c.getComponents() );
+		System.out.println( c.getComposites() );
+		ccic = (Container.ContainerInnerClass) c.getComponents().get(2);
+		assertTrue( ccic.getMany().getOne()==ccic.getOne() );
+		assertTrue( c.getComponents().size()==3 );
+		assertTrue( c.getComposites().size()==1 );
+		assertTrue( c.getOneToMany().size()==3 );
+		assertTrue( c.getManyToMany().size()==3 );
+		assertTrue( c.getOneToMany().get(0)!=null );
+		assertTrue( c.getOneToMany().get(2)!=null );
+		for ( int i=0; i<3; i++ ) {
+			assertTrue( c.getManyToMany().get(i) == c.getOneToMany().get(i) );
+		}
+		Object o1 = c.getOneToMany().get(0);
+		Object o2 = c.getOneToMany().remove(2);
+		c.getOneToMany().set(0, o2);
+		c.getOneToMany().set(1, o1);
+		o1 = c.getComponents().remove(2);
+		c.getComponents().set(0, o1);
+		c.getManyToMany().set( 0, c.getManyToMany().get(2) );
+		Container.ContainerInnerClass ccic2 = new Container.ContainerInnerClass();
+		ccic2.setName("foo");
+		ccic2.setOne(one);
+		ccic2.setMany(many);
+		ccic2.setSimple( (Simple) s.load(Simple.class, new Long(0) ) );
+		c.getComposites().add(ccic2);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Container) s.load( Container.class, new Long( c.getId() ) );
+		System.out.println( c.getOneToMany() );
+		System.out.println( c.getManyToMany() );
+		System.out.println( c.getComponents() );
+		System.out.println( c.getComposites() );
+		assertTrue( c.getComponents().size()==1 ); //WAS: 2
+		assertTrue( c.getComposites().size()==2 );
+		assertTrue( c.getOneToMany().size()==2 );
+		assertTrue( c.getManyToMany().size()==3 );
+		assertTrue( c.getOneToMany().get(0)!=null );
+		assertTrue( c.getOneToMany().get(1)!=null );
+		( (Container.ContainerInnerClass) c.getComponents().get(0) ).setName("a different name");
+		( (Container.ContainerInnerClass) c.getComposites().iterator().next() ).setName("once again");
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Container) s.load( Container.class, new Long( c.getId() ) );
+		System.out.println( c.getOneToMany() );
+		System.out.println( c.getManyToMany() );
+		System.out.println( c.getComponents() );
+		System.out.println( c.getComposites() );
+		assertTrue( c.getComponents().size()==1 ); //WAS: 2
+		assertTrue( c.getComposites().size()==2 );
+		assertTrue( ( (Container.ContainerInnerClass) c.getComponents().get(0) ).getName().equals("a different name") );
+		Iterator iter = c.getComposites().iterator();
+		boolean found = false;
+		while ( iter.hasNext() ) {
+			if ( ( (Container.ContainerInnerClass) iter.next() ).getName().equals("once again") ) found = true;
+		}
+		assertTrue(found);
+		c.getOneToMany().clear();
+		c.getManyToMany().clear();
+		c.getComposites().clear();
+		c.getComponents().clear();
+		s.delete("from Simple");
+		s.delete("from Many");
+		s.delete("from One");
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Container) s.load( Container.class, new Long( c.getId() ) );
+		assertTrue( c.getComponents().size()==0 );
+		assertTrue( c.getComposites().size()==0 );
+		assertTrue( c.getOneToMany().size()==0 );
+		assertTrue( c.getManyToMany().size()==0 );
+		s.delete(c);
+		t.commit();
+		s.close();
+	}
+
+	public void testCascadeCompositeElements() throws Exception {
+		Container c = new Container();
+		List list = new ArrayList();
+		c.setCascades(list);
+		Container.ContainerInnerClass cic = new Container.ContainerInnerClass();
+		cic.setMany( new Many() );
+		cic.setOne( new One() );
+		list.add(cic);
+		Session s = openSession();
+		s.save(c);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		
+		s=openSession();
+		c = (Container) s.iterate("from ContainerX c").next();
+		cic = (Container.ContainerInnerClass) c.getCascades().iterator().next();
+		assertTrue( cic.getMany()!=null && cic.getOne()!=null );
+		assertTrue( c.getCascades().size()==1 );
+		s.delete(c);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		c = new Container();
+		s = openSession();
+		s.save(c);
+		list = new ArrayList();
+		c.setCascades(list);
+		cic = new Container.ContainerInnerClass();
+		cic.setMany( new Many() );
+		cic.setOne( new One() );
+		list.add(cic);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		
+		s=openSession();
+		c = (Container) s.iterate("from ContainerX c").next();
+		cic = (Container.ContainerInnerClass) c.getCascades().iterator().next();
+		assertTrue( cic.getMany()!=null && cic.getOne()!=null );
+		assertTrue( c.getCascades().size()==1 );
+		s.delete(c);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testBag() throws Exception {
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Container c = new Container();
+		Contained c1 = new Contained();
+		Contained c2 = new Contained();
+		c.setBag( new ArrayList() );
+		c.getBag().add(c1);
+		c.getBag().add(c2);
+		c1.getBag().add(c);
+		c2.getBag().add(c);
+		s.save(c);
+		c.getBag().add(c2);
+		c2.getBag().add(c);
+		c.getLazyBag().add(c1);
+		c1.getLazyBag().add(c);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Container) s.find("from ContainerX c").get(0);
+		c.getLazyBag().size();
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Container) s.find("from ContainerX c").get(0);
+		Contained c3 = new Contained();
+		//c.getBag().add(c3);
+		//c3.getBag().add(c);
+		c.getLazyBag().add(c3);
+		c3.getLazyBag().add(c);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Container) s.find("from ContainerX c").get(0);
+		Contained c4 = new Contained();
+		c.getLazyBag().add(c4);
+		c4.getLazyBag().add(c);
+		assertTrue( c.getLazyBag().size()==3 ); //forces initialization
+		//s.save(c4);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Container) s.find("from ContainerX c").get(0);
+		Iterator i = c.getBag().iterator();
+		int j=0;
+		while ( i.hasNext() ) {
+			assertTrue( i.next()!=null );
+			j++;
+		}
+		assertTrue(j==3);
+		assertTrue( c.getLazyBag().size()==3 );
+		s.delete(c);
+		c.getBag().remove(c2);
+		Iterator iter = c.getBag().iterator();
+		j=0;
+		while ( iter.hasNext() ) {
+			j++;
+			s.delete( iter.next() );
+		}
+		assertTrue(j==2);
+		s.delete( s.load(Contained.class, new Long( c4.getId() ) ) );
+		s.delete( s.load(Contained.class, new Long( c3.getId() ) ) );
+		t.commit();
+		s.close();
+
+	}
+
+	public void testCircularCascade() throws Exception {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Circular c = new Circular();
+		c.setClazz(Circular.class);
+		c.setOther( new Circular() );
+		c.getOther().setOther( new Circular() );
+		c.getOther().getOther().setOther(c);
+		c.setAnyEntity( c.getOther() );
+		String id = (String) s.save(c);
+		tx.commit();
+		s.close();
+		s = openSession();
+		tx = s.beginTransaction();
+		c = (Circular) s.load(Circular.class, id);
+		c.getOther().getOther().setClazz(Foo.class);
+		tx.commit();
+		s.close();
+		c.getOther().setClazz(Qux.class);
+		s = openSession();
+		tx = s.beginTransaction();
+		s.saveOrUpdate(c);
+		tx.commit();
+		s.close();
+		c.getOther().getOther().setClazz(Bar.class);
+		s = openSession();
+		tx = s.beginTransaction();
+		s.saveOrUpdate(c);
+		tx.commit();
+		s.close();
+		s = openSession();
+		tx = s.beginTransaction();
+		c = (Circular) s.load(Circular.class, id);
+		assertTrue( c.getOther().getOther().getClazz()==Bar.class);
+		assertTrue( c.getOther().getClazz()==Qux.class);
+		assertTrue( c.getOther().getOther().getOther()==c);
+		assertTrue( c.getAnyEntity()==c.getOther() );
+		assertTrue( s.delete("from Universe")==3 );
+		tx.commit();
+		s.close();
+	}
+
+	public void testDeleteEmpty() throws Exception {
+		Session s = openSession();
+		assertTrue( s.delete("from Simple")==0 );
+		assertTrue( s.delete("from Universe")==0 );
+		s.close();
+	}
+
+	public void testLocking() throws Exception {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Simple s1 = new Simple(); s1.setCount(1);
+		Simple s2 = new Simple(); s2.setCount(2);
+		Simple s3 = new Simple(); s3.setCount(3);
+		Simple s4 = new Simple(); s4.setCount(4);
+		s.save(s1, new Long(1) );
+		s.save(s2, new Long(2) );
+		s.save(s3, new Long(3) );
+		s.save(s4, new Long(4) );
+		assertTrue( s.getCurrentLockMode(s1)==LockMode.WRITE );
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s1 = (Simple) s.load(Simple.class, new Long(1), LockMode.NONE);
+		assertTrue( s.getCurrentLockMode(s1)==LockMode.READ || s.getCurrentLockMode(s1)==LockMode.NONE ); //depends if cache is enabled
+		s2 = (Simple) s.load(Simple.class, new Long(2), LockMode.READ);
+		assertTrue( s.getCurrentLockMode(s2)==LockMode.READ );
+		s3 = (Simple) s.load(Simple.class, new Long(3), LockMode.UPGRADE);
+		assertTrue( s.getCurrentLockMode(s3)==LockMode.UPGRADE );
+		s4 = (Simple) s.get(Simple.class, new Long(4), LockMode.UPGRADE_NOWAIT);
+		assertTrue( s.getCurrentLockMode(s4)==LockMode.UPGRADE_NOWAIT );
+
+		s1 = (Simple) s.load(Simple.class, new Long(1), LockMode.UPGRADE); //upgrade
+		assertTrue( s.getCurrentLockMode(s1)==LockMode.UPGRADE );
+		s2 = (Simple) s.load(Simple.class, new Long(2), LockMode.NONE);
+		assertTrue( s.getCurrentLockMode(s2)==LockMode.READ );
+		s3 = (Simple) s.load(Simple.class, new Long(3), LockMode.READ);
+		assertTrue( s.getCurrentLockMode(s3)==LockMode.UPGRADE );
+		s4 = (Simple) s.load(Simple.class, new Long(4), LockMode.UPGRADE);
+		assertTrue( s.getCurrentLockMode(s4)==LockMode.UPGRADE_NOWAIT );
+
+		s.lock(s2, LockMode.UPGRADE); //upgrade
+		assertTrue( s.getCurrentLockMode(s2)==LockMode.UPGRADE );
+		s.lock(s3, LockMode.UPGRADE);
+		assertTrue( s.getCurrentLockMode(s3)==LockMode.UPGRADE );
+		s.lock(s1, LockMode.UPGRADE_NOWAIT);
+		s.lock(s4, LockMode.NONE);
+		assertTrue( s.getCurrentLockMode(s4)==LockMode.UPGRADE_NOWAIT );
+
+		tx.commit();
+		tx = s.beginTransaction();
+
+		assertTrue( s.getCurrentLockMode(s3)==LockMode.NONE );
+		assertTrue( s.getCurrentLockMode(s1)==LockMode.NONE );
+		assertTrue( s.getCurrentLockMode(s2)==LockMode.NONE );
+		assertTrue( s.getCurrentLockMode(s4)==LockMode.NONE );
+
+		s.lock(s1, LockMode.READ); //upgrade
+		assertTrue( s.getCurrentLockMode(s1)==LockMode.READ );
+		s.lock(s2, LockMode.UPGRADE); //upgrade
+		assertTrue( s.getCurrentLockMode(s2)==LockMode.UPGRADE );
+		s.lock(s3, LockMode.UPGRADE_NOWAIT); //upgrade
+		assertTrue( s.getCurrentLockMode(s3)==LockMode.UPGRADE_NOWAIT );
+		s.lock(s4, LockMode.NONE);
+		assertTrue( s.getCurrentLockMode(s4)==LockMode.NONE );
+
+		s4.setName("s4");
+		s.flush();
+		assertTrue( s.getCurrentLockMode(s4)==LockMode.WRITE );
+		tx.commit();
+
+		tx = s.beginTransaction();
+
+		assertTrue( s.getCurrentLockMode(s3)==LockMode.NONE );
+		assertTrue( s.getCurrentLockMode(s1)==LockMode.NONE );
+		assertTrue( s.getCurrentLockMode(s2)==LockMode.NONE );
+		assertTrue( s.getCurrentLockMode(s4)==LockMode.NONE );
+
+		s.delete(s1); s.delete(s2); s.delete(s3); s.delete(s4);
+		tx.commit();
+		s.close();
+	}
+
+	public void testObjectType() throws Exception {
+		Session s = openSession();
+		Parent g = new Parent();
+		Foo foo = new Foo();
+		g.setAny(foo);
+		s.save(g);
+		s.save(foo);
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		g = (Parent) s.load( Parent.class, new Long( g.getId() ) );
+		assertTrue( g.getAny()!=null && g.getAny() instanceof FooProxy );
+		s.delete( g.getAny() );
+		s.delete(g);
+		s.flush();
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testLoadAfterNonExists() throws HibernateException, SQLException {
+
+		Session session = openSession();
+		if ( (getDialect() instanceof MySQLDialect) ) {
+			session.connection().setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
+		}
+
+		// First, prime the fixture session to think the entity does not exist
+		try {
+			session.load( Simple.class, new Long(-1) );
+			fail();
+		}
+		catch(ObjectNotFoundException onfe) {
+			// this is correct
+		}
+
+		// Next, lets create that entity under the covers
+		Session anotherSession = getSessions().openSession();
+		Simple myNewSimple = new Simple();
+		myNewSimple.setName("My under the radar Simple entity");
+		myNewSimple.setAddress("SessionCacheTest.testLoadAfterNonExists");
+		myNewSimple.setCount(1);
+		myNewSimple.setDate( new Date() );
+		myNewSimple.setPay( new Float(100000000) );
+		anotherSession.save( myNewSimple, new Long(-1) );
+		anotherSession.flush();
+		anotherSession.connection().commit();
+		anotherSession.close();
+
+		// Verify that the original session is still able to see the new entry...
+		//try {
+			session.load( Simple.class, new Long(-1) );
+			/*fail();
+		}
+		catch(ObjectNotFoundException onfe) {
+		}*/
+
+		// Now, lets clear the original session at which point it should be able to see
+		// the new entity
+		session.clear();
+		try {
+			Simple dummy = (Simple) session.load( Simple.class, new Long(-1) );
+			assertNotNull("Unable to locate entity Simple with id = -1", dummy);
+		}
+		catch(ObjectNotFoundException onfe) {
+			fail("Unable to locate entity Simple with id = -1");
+		}
+		session.connection().commit();
+		session.close();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Part.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Part.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Part.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+//$Id: Part.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+/**
+ * @author Gavin King
+ */
+public class Part {
+
+	private Long id;
+	private String description;
+	
+	public String getDescription() {
+		return description;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setDescription(String string) {
+		description = string;
+	}
+
+	public void setId(Long long1) {
+		id = long1;
+	}
+	
+	public static class SpecialPart extends Part {}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Party.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Party.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Party.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+package org.hibernate.test.legacy;
+
+/**
+ * @author hbm2java
+ */
+public class Party {
+
+   java.lang.String id;
+   java.lang.String name;
+   java.lang.String address;
+
+
+  java.lang.String getId() {
+    return id;
+  }
+
+  void  setId(java.lang.String newValue) {
+    id = newValue;
+  }
+
+  java.lang.String getName() {
+    return name;
+  }
+
+  void  setName(java.lang.String newValue) {
+    name = newValue;
+  }
+
+  java.lang.String getAddress() {
+    return address;
+  }
+
+  void  setAddress(java.lang.String newValue) {
+    address = newValue;
+  }
+
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/PerformanceTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/PerformanceTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/PerformanceTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,356 @@
+//$Id: PerformanceTest.java 6900 2005-05-25 01:24:22Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+import org.hibernate.classic.Session;
+import org.hibernate.cfg.Environment;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.connection.ConnectionProviderFactory;
+import org.hibernate.test.TestCase;
+
+public class PerformanceTest extends TestCase {
+
+	public PerformanceTest(String arg0) {
+		super(arg0);
+	}
+
+	public void testMany() throws Exception {
+
+		ConnectionProvider cp = ConnectionProviderFactory.newConnectionProvider( Environment.getProperties() );
+
+		long hiber=0;
+		long jdbc=0;
+
+		for ( int n=0; n<20; n++ ) {
+
+			Simple[] simples = new Simple[n];
+			Serializable[] ids = new Serializable[n];
+			for ( int i=0; i<n; i++ ) {
+				simples[i] = new Simple();
+				simples[i].init();
+				simples[i].setCount(i);
+				ids[i] = new Long(i);
+			}
+
+			//allow cache to settle
+
+			Session s = openSession();
+			hibernate(s, simples, ids, n, "h0");
+			s.close();
+
+			Connection c = cp.getConnection();
+			directJDBC( c, simples, ids, n, "j0" );
+			cp.closeConnection(c);
+
+			s = openSession();
+			hibernate(s, simples, ids, n, "h0");
+			s.close();
+
+			c = cp.getConnection();
+			directJDBC( c, simples, ids, n, "j0" );
+			cp.closeConnection(c);
+
+			//Now do timings
+
+			int N=30;
+
+			long time = System.currentTimeMillis();
+			for (int i=0; i<N; i++) {
+				s = openSession();
+				hibernate(s, simples, ids, n, "h1");
+				s.close();
+			}
+			hiber += System.currentTimeMillis() - time;
+
+			time = System.currentTimeMillis();
+			for (int i=0; i<N; i++) {
+				c = cp.getConnection();
+				directJDBC( c, simples, ids, n, "j1" );
+				cp.closeConnection(c);
+			}
+			jdbc += System.currentTimeMillis() - time;
+
+			time = System.currentTimeMillis();
+			for (int i=0; i<N; i++) {
+				s = openSession();
+				hibernate(s, simples, ids, n, "h2");
+				s.close();
+			}
+			hiber += System.currentTimeMillis() - time;
+
+			time = System.currentTimeMillis();
+			for (int i=0; i<N; i++) {
+				c = cp.getConnection();
+				directJDBC( c, simples, ids, n, "j2" );
+				cp.closeConnection(c);
+			}
+			jdbc += System.currentTimeMillis() - time;
+
+			time = System.currentTimeMillis();
+			for (int i=0; i<N; i++) {
+				s = openSession();
+				hibernate(s, simples, ids, n, "h1");
+				s.close();
+			}
+			hiber += System.currentTimeMillis() - time;
+
+			time = System.currentTimeMillis();
+			for (int i=0; i<N; i++) {
+				c = cp.getConnection();
+				directJDBC( c, simples, ids, n, "j1" );
+				cp.closeConnection(c);
+			}
+			jdbc += System.currentTimeMillis() - time;
+
+		}
+
+		System.out.println( "Hibernate: " + hiber + "ms / Direct JDBC: " + jdbc + "ms = Ratio: " + ( (float) hiber )/jdbc );
+
+		cp.close();
+		System.gc();
+	}
+
+	public void testSimultaneous() throws Exception {
+
+		ConnectionProvider cp = ConnectionProviderFactory.newConnectionProvider( Environment.getProperties() );
+
+		for ( int n=2; n<4000; n*=2 ) {
+
+			Simple[] simples = new Simple[n];
+			Serializable[] ids = new Serializable[n];
+			for ( int i=0; i<n; i++ ) {
+				simples[i] = new Simple();
+				simples[i].init();
+				simples[i].setCount(i);
+				ids[i] = new Long(i);
+			}
+
+			//allow cache to settle
+
+			Session s = openSession();
+			hibernate(s, simples, ids, n, "h0");
+			s.close();
+
+			Connection c = cp.getConnection();
+			directJDBC( c, simples, ids, n, "j0" );
+			cp.closeConnection(c);
+
+			s = openSession();
+			hibernate(s, simples, ids, n, "h0");
+			s.close();
+
+			c = cp.getConnection();
+			directJDBC( c, simples, ids, n, "j0" );
+			cp.closeConnection(c);
+
+			//Now do timings
+
+			s = openSession();
+			long time = System.currentTimeMillis();
+			hibernate(s, simples, ids, n, "h1");
+			long hiber = System.currentTimeMillis() - time;
+			s.close();
+
+			c = cp.getConnection();
+			time = System.currentTimeMillis();
+			directJDBC( c, simples, ids, n, "j1" );
+			long jdbc = System.currentTimeMillis() - time;
+			cp.closeConnection(c);
+
+			s = openSession();
+			time = System.currentTimeMillis();
+			hibernate(s, simples, ids, n, "h2");
+			hiber += System.currentTimeMillis() - time;
+			s.close();
+
+			c = cp.getConnection();
+			time = System.currentTimeMillis();
+			directJDBC( c, simples, ids, n, "j2" );
+			jdbc += System.currentTimeMillis() - time;
+			cp.closeConnection(c);
+
+			s = openSession();
+			time = System.currentTimeMillis();
+			hibernate(s, simples, ids, n, "h2");
+			hiber += System.currentTimeMillis() - time;
+			s.close();
+
+			c = cp.getConnection();
+			time = System.currentTimeMillis();
+			directJDBC( c, simples, ids, n, "j2" );
+			jdbc += System.currentTimeMillis() - time;
+			cp.closeConnection(c);
+
+			System.out.println( "Objects: " + n + " - Hibernate: " + hiber + "ms / Direct JDBC: " + jdbc + "ms = Ratio: " + ( (float) hiber )/jdbc );
+
+		}
+
+		cp.close();
+		System.gc();
+	}
+
+	public void testHibernateOnly() throws Exception {
+
+		for ( int n=2; n<4000; n*=2 ) {
+
+			Simple[] simples = new Simple[n];
+			Serializable[] ids = new Serializable[n];
+			for ( int i=0; i<n; i++ ) {
+				simples[i] = new Simple();
+				simples[i].init();
+				simples[i].setCount(i);
+				ids[i] = new Long(i);
+			}
+
+			//Now do timings
+
+			Session s = openSession();
+			long time = System.currentTimeMillis();
+			hibernate(s, simples, ids, n, "h1");
+			long hiber = System.currentTimeMillis() - time;
+			s.close();
+
+			s = openSession();
+			time = System.currentTimeMillis();
+			hibernate(s, simples, ids, n, "h2");
+			hiber += System.currentTimeMillis() - time;
+			s.close();
+
+			s = openSession();
+			time = System.currentTimeMillis();
+			hibernate(s, simples, ids, n, "h2");
+			hiber += System.currentTimeMillis() - time;
+			s.close();
+
+			System.out.println( "Objects: " + n + " - Hibernate: " + hiber );
+
+		}
+
+		System.gc();
+	}
+
+	public void testJdbcOnly() throws Exception {
+
+		ConnectionProvider cp = ConnectionProviderFactory.newConnectionProvider( Environment.getProperties() );
+
+		for ( int n=2; n<4000; n*=2 ) {
+
+			Simple[] simples = new Simple[n];
+			Serializable[] ids = new Serializable[n];
+			for ( int i=0; i<n; i++ ) {
+				simples[i] = new Simple();
+				simples[i].init();
+				simples[i].setCount(i);
+				ids[i] = new Long(i);
+			}
+
+			//Now do timings
+
+			Connection c = cp.getConnection();
+			long time = System.currentTimeMillis();
+			directJDBC( c, simples, ids, n, "j1" );
+			long jdbc = System.currentTimeMillis() - time;
+			cp.closeConnection(c);
+
+			c = cp.getConnection();
+			time = System.currentTimeMillis();
+			directJDBC( c, simples, ids, n, "j2" );
+			jdbc += System.currentTimeMillis() - time;
+			cp.closeConnection(c);
+
+			c = cp.getConnection();
+			time = System.currentTimeMillis();
+			directJDBC( c, simples, ids, n, "j2" );
+			jdbc += System.currentTimeMillis() - time;
+			cp.closeConnection(c);
+
+			System.out.println( "Objects: " + n + " Direct JDBC: " + jdbc );
+
+		}
+
+		cp.close();
+		System.gc();
+	}
+
+	private void hibernate(Session s, Simple[] simples, Serializable[] ids, int N, String runname) throws Exception {
+		for ( int i=0; i<N; i++ ) {
+			s.save( simples[i], ids[i] );
+		}
+		for ( int i=0; i<N; i++ ) {
+			simples[0].setName("A Different Name!" + i + N + runname);
+		}
+		//s.flush();
+		// the results of this test are highly dependent upon
+		// how many times we flush!
+		assertTrue( "assertion", s.delete("from Simple s")==N );
+		s.flush();
+		s.connection().commit();
+	}
+
+	private void directJDBC(Connection c, Simple[] simples, Serializable[] ids, int N, String runname) throws SQLException {
+
+		PreparedStatement insert = c.prepareStatement("insert into Simple ( name, address, count_, date_, other, id_ ) values ( ?, ?, ?, ?, ?, ? )");
+		PreparedStatement delete = c.prepareStatement("delete from Simple where id_ = ?");
+		PreparedStatement select = c.prepareStatement("SELECT s.id_, s.name, s.address, s.count_, s.date_, s.other FROM Simple s");
+		PreparedStatement update = c.prepareStatement("update Simple set name = ?, address = ?, count_ = ?, date_ = ?, other = ? where id_ = ?");
+		for ( int i=0; i<N; i++ ) {
+			insert.setString(1, simples[i].getName() );
+			insert.setString(2, simples[i].getAddress() );
+			insert.setInt(3, simples[i].getCount() );
+			insert.setDate( 4, (java.sql.Date) simples[i].getDate() );
+			insert.setNull(5, Types.BIGINT);
+			insert.setLong( 6, ( (Long) ids[i] ).longValue() );
+			insert.executeUpdate();
+		}
+		insert.close();
+		for ( int i=0; i<N; i++ ) {
+			update.setString(1, "A Different Name!" + i + N + runname );
+			update.setString(2, simples[i].getAddress() );
+			update.setInt(3, simples[i].getCount() );
+			update.setDate( 4, (java.sql.Date) simples[i].getDate() );
+			update.setNull(5, Types.BIGINT);
+			update.setLong( 6, ( (Long) ids[i] ).longValue() );
+			update.executeUpdate();
+		}
+		update.close();
+		java.sql.ResultSet rs = select.executeQuery();
+		Long[] keys = new Long[N];
+		int j=0;
+		while ( rs.next() ) {
+			keys[j++] = new Long( rs.getLong(1) );
+			rs.getString(2);
+			rs.getString(3);
+			rs.getInt(4);
+			rs.getDate(5);
+			rs.getLong(6);
+		}
+		rs.close();
+		select.close();
+		for ( int i=0; i<N; i++ ) {
+			delete.setLong(1, keys[i].longValue() );
+			delete.executeUpdate();
+		}
+		delete.close();
+		c.commit();
+	}
+
+	public String[] getMappings() {
+		return new String[] { "legacy/Simple.hbm.xml" };
+	}
+
+	public static Test suite() throws Exception {
+		return new TestSuite(PerformanceTest.class);
+	}
+
+	public static void main(String[] args) throws Exception {
+		TestRunner.run( suite() );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+package org.hibernate.test.legacy;
+
+/**
+ * @author hbm2java
+ */
+public class Person extends org.hibernate.test.legacy.Party {
+
+   java.lang.String id;
+   java.lang.String givenName;
+   java.lang.String lastName;
+   java.lang.String nationalID;
+
+
+  java.lang.String getId() {
+    return id;
+  }
+
+  void  setId(java.lang.String newValue) {
+    id = newValue;
+  }
+
+  java.lang.String getGivenName() {
+    return givenName;
+  }
+
+  void  setGivenName(java.lang.String newValue) {
+    givenName = newValue;
+  }
+
+  java.lang.String getLastName() {
+    return lastName;
+  }
+
+  void  setLastName(java.lang.String newValue) {
+    lastName = newValue;
+  }
+
+  java.lang.String getNationalID() {
+    return nationalID;
+  }
+
+  void  setNationalID(java.lang.String newValue) {
+    nationalID = newValue;
+  }
+
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Po.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Po.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Po.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,104 @@
+//$Id: Po.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.List;
+import java.util.Set;
+
+
+/**
+ *
+ */
+public class Po {
+	private long id;
+	private String value;
+	private Set set;
+	private List list;
+	private Top top;
+	private Lower lower;
+	/**
+	 * Returns the id.
+	 * @return long
+	 */
+	public long getId() {
+		return id;
+	}
+	
+	/**
+	 * Returns the value.
+	 * @return String
+	 */
+	public String getValue() {
+		return value;
+	}
+	
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	
+	/**
+	 * Sets the value.
+	 * @param value The value to set
+	 */
+	public void setValue(String value) {
+		this.value = value;
+	}
+	
+	/**
+	 * Returns the set.
+	 * @return Set
+	 */
+	public Set getSet() {
+		return set;
+	}
+	
+	/**
+	 * Sets the set.
+	 * @param set The set to set
+	 */
+	public void setSet(Set set) {
+		this.set = set;
+	}
+	
+	/**
+	 * Returns the list.
+	 * @return List
+	 */
+	public List getList() {
+		return list;
+	}
+	
+	/**
+	 * Sets the list.
+	 * @param list The list to set
+	 */
+	public void setList(List list) {
+		this.list = list;
+	}
+	
+	public Lower getLower() {
+		return lower;
+	}
+
+	public Top getTop() {
+		return top;
+	}
+
+	public void setLower(Lower lower) {
+		this.lower = lower;
+	}
+
+	public void setTop(Top top) {
+		this.top = top;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/QueryByExampleTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/QueryByExampleTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/QueryByExampleTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,136 @@
+//$Id: QueryByExampleTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Criteria;
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.criterion.Example;
+import org.hibernate.criterion.Expression;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Query by example test to allow nested components
+ *
+ * @author Emmanuel Bernard
+ */
+public class QueryByExampleTest extends LegacyTestCase {
+
+    public QueryByExampleTest(String name) {
+        super(name);
+    }
+
+    public String[] getMappings() {
+        return new String[] { "legacy/Componentizable.hbm.xml" };
+    }
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( QueryByExampleTest.class );
+	}
+
+    public void testSimpleQBE() throws Exception {
+    	deleteData();
+        initData();
+
+        Session s = openSession();
+
+        Transaction t = s.beginTransaction();
+        Componentizable master = getMaster("hibernate", "open sourc%", "open source1");
+        Criteria crit = s.createCriteria(Componentizable.class);
+        Example ex = Example.create(master).enableLike();
+        crit.add(ex);
+        List result = crit.list();
+        assertNotNull(result);
+        assertEquals(1, result.size());
+
+        t.commit();
+        s.close();
+    }
+
+    public void testJunctionNotExpressionQBE() throws Exception {
+        deleteData();
+        initData();
+        Session s = openSession();
+        Transaction t = s.beginTransaction();
+        Componentizable master = getMaster("hibernate", null, "ope%");
+        Criteria crit = s.createCriteria(Componentizable.class);
+        Example ex = Example.create(master).enableLike();
+
+        crit.add(Expression.or(Expression.not(ex), ex));
+
+        List result = crit.list();
+        assertNotNull(result);
+        assertEquals(2, result.size());
+        t.commit();
+        s.close();
+
+    }
+
+    public void testExcludingQBE() throws Exception {
+        deleteData();
+        initData();
+        Session s = openSession();
+        Transaction t = s.beginTransaction();
+        Componentizable master = getMaster("hibernate", null, "ope%");
+        Criteria crit = s.createCriteria(Componentizable.class);
+        Example ex = Example.create(master).enableLike()
+            .excludeProperty("component.subComponent");
+        crit.add(ex);
+        List result = crit.list();
+        assertNotNull(result);
+        assertEquals(3, result.size());
+
+        master = getMaster("hibernate", "ORM tool", "fake stuff");
+        crit = s.createCriteria(Componentizable.class);
+        ex = Example.create(master).enableLike()
+            .excludeProperty("component.subComponent.subName1");
+        crit.add(ex);
+        result = crit.list();
+        assertNotNull(result);
+        assertEquals(1, result.size());
+        t.commit();
+        s.close();
+
+
+    }
+
+    private void initData() throws Exception {
+        Session s = openSession();
+        Transaction t = s.beginTransaction();
+        Componentizable master = getMaster("hibernate", "ORM tool", "ORM tool1");
+        s.saveOrUpdate(master);
+        master = getMaster("hibernate", "open source", "open source1");
+        s.saveOrUpdate(master);
+        master = getMaster("hibernate", null, null);
+        s.saveOrUpdate(master);
+        t.commit();
+        s.close();
+    }
+
+    private void deleteData() throws Exception {
+    	Session s = openSession();
+        Transaction t = s.beginTransaction();
+        s.delete("from Componentizable");
+        t.commit();
+        s.close();
+    }
+
+    private Componentizable getMaster(String name, String subname, String subname1) {
+        Componentizable master = new Componentizable();
+        if (name != null) {
+            Component masterComp = new Component();
+            masterComp.setName(name);
+            if (subname != null || subname1 != null) {
+                SubComponent subComponent = new SubComponent();
+                subComponent.setSubName(subname);
+                subComponent.setSubName1(subname1);
+                masterComp.setSubComponent(subComponent);
+            }
+            master.setComponent(masterComp);
+        }
+        return master;
+    }
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Qux.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Qux.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Qux.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+	
+	<class name="org.hibernate.test.legacy.Qux" table="quux" proxy="org.hibernate.test.legacy.Qux"> <!---->
+		<id name="key" column="qux_key" unsaved-value="0">
+			<generator class="hilo"/>
+		</id>
+		<many-to-one name="foo" class="org.hibernate.test.legacy.Foo">
+			<column name="foo" length="36"/>
+		</many-to-one>
+		<property name="deleted"/>
+		<property name="loaded"/>
+		<property name="stored"/>
+		<property name="created"/>
+		<property name="childKey" type="long"/>
+		<property name="stuff"/>
+		<set name="fums" lazy="true">
+			<key column="qux_id"/>
+			<many-to-many class="org.hibernate.test.legacy.Fum">
+				<column name="fum_string" length="10" not-null="true"/>
+				<column name="fum_short" not-null="true"/>
+				<column name="fum_date" not-null="true"/>
+			</many-to-many>
+		</set>
+		<list name="moreFums" lazy="true">
+			<key column="qux_id"/>
+			<index column="posn"/>
+			<one-to-many class="org.hibernate.test.legacy.Fum"/>
+		</list>
+		<many-to-one name="holder" column="HOLDER_NAME" property-ref="name"/>
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Qux.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Qux.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Qux.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,180 @@
+//$Id: Qux.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Set;
+
+import org.hibernate.CallbackException;
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.classic.Lifecycle;
+
+public class Qux implements Lifecycle {
+
+	boolean created;
+	boolean deleted;
+	boolean loaded;
+	boolean stored;
+	private Long key;
+	private String stuff;
+	private Set fums;
+	private List moreFums;
+	private Qux child;
+	private Session session;
+	private Long childKey;
+	private Holder holder;
+
+	private FooProxy foo;
+
+	public Qux() { }
+
+	public Qux(String s) {
+		stuff=s;
+	}
+
+	public boolean onSave(Session session) throws CallbackException {
+		created=true;
+		try {
+			foo = new Foo();
+			session.save(foo);
+		}
+		catch (Exception e) {
+			throw new CallbackException(e);
+		}
+		foo.setString("child of a qux");
+		return NO_VETO;
+	}
+
+	public boolean onDelete(Session session) throws CallbackException {
+		deleted=true;
+		try {
+			session.delete(foo);
+		}
+		catch (Exception e) {
+			throw new CallbackException(e);
+		}
+		//if (child!=null) session.delete(child);
+		return NO_VETO;
+	}
+
+	public void onLoad(Session session, Serializable id) {
+		loaded=true;
+		this.session=session;
+	}
+
+	public void store() {
+	}
+
+	public FooProxy getFoo() {
+		return foo;
+	}
+	public void setFoo(FooProxy foo) {
+		this.foo = foo;
+	}
+
+	public boolean getCreated() {
+		return created;
+	}
+	private void setCreated(boolean created) {
+		this.created = created;
+	}
+
+	public boolean getDeleted() {
+		return deleted;
+	}
+
+	private void setDeleted(boolean deleted) {
+		this.deleted = deleted;
+	}
+
+	public boolean getLoaded() {
+		return loaded;
+	}
+	private void setLoaded(boolean loaded) {
+		this.loaded = loaded;
+	}
+
+	public boolean getStored() {
+		return stored;
+	}
+	private void setStored(boolean stored) {
+		this.stored = stored;
+	}
+
+	public Long getKey() {
+		return key;
+	}
+
+	private void setKey(long key) {
+		this.key = new Long(key);
+	}
+
+	public void setTheKey(long key) {
+		this.key = new Long(key);
+	}
+
+	public String getStuff() {
+		return stuff;
+	}
+	public void setStuff(String stuff) {
+		this.stuff = stuff;
+	}
+
+	public Set getFums() {
+		return fums;
+	}
+
+	public void setFums(Set fums) {
+		this.fums = fums;
+	}
+
+	public List getMoreFums() {
+		return moreFums;
+	}
+	public void setMoreFums(List moreFums) {
+		this.moreFums = moreFums;
+	}
+
+	public Qux getChild() throws HibernateException, SQLException {
+		stored=true;
+		this.childKey = child==null ? null : child.getKey();
+		if (childKey!=null && child==null) child = (Qux) session.load(Qux.class, childKey);
+		return child;
+	}
+
+	public void setChild(Qux child) {
+		this.child = child;
+	}
+
+	private Long getChildKey() {
+		return childKey;
+	}
+
+	private void setChildKey(Long childKey) {
+		this.childKey = childKey;
+	}
+
+	public boolean onUpdate(Session s) throws CallbackException {
+		return NO_VETO;
+	}
+
+	protected void finalize() { }
+
+	public Holder getHolder() {
+		return holder;
+	}
+
+	public void setHolder(Holder holder) {
+		this.holder = holder;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Resource.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Resource.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Resource.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+package org.hibernate.test.legacy;
+
+/**
+ * @author hbm2java
+ */
+public class Resource {
+
+   java.lang.String id;
+   java.lang.String name;
+   java.lang.String userCode;
+
+
+  java.lang.String getId() {
+    return id;
+  }
+
+  void  setId(java.lang.String newValue) {
+    id = newValue;
+  }
+
+  java.lang.String getName() {
+    return name;
+  }
+
+  void  setName(java.lang.String newValue) {
+    name = newValue;
+  }
+
+  java.lang.String getUserCode() {
+    return userCode;
+  }
+
+  void  setUserCode(java.lang.String newValue) {
+    userCode = newValue;
+  }
+
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Result.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Result.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Result.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+package org.hibernate.test.legacy;
+
+
+public class Result {
+	private String name;
+	private long amount;
+	private long count;
+	/**
+	 * Returns the amount.
+	 * @return long
+	 */
+	public long getAmount() {
+		return amount;
+	}
+
+	/**
+	 * Returns the count.
+	 * @return int
+	 */
+	public long getCount() {
+		return count;
+	}
+
+	/**
+	 * Returns the name.
+	 * @return String
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Sets the amount.
+	 * @param amount The amount to set
+	 */
+	public void setAmount(long amount) {
+		this.amount = amount;
+	}
+
+	/**
+	 * Sets the count.
+	 * @param count The count to set
+	 */
+	public void setCount(long count) {
+		this.count = count;
+	}
+
+	/**
+	 * Sets the name.
+	 * @param name The name to set
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+	public Result(String n, long a, int c) {
+		name = n;
+		amount = a;
+		count = c;
+	}
+	
+	public Result(String n, long a, long c) {
+		name = n;
+		amount = a;
+		count = c;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ReverseComparator.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ReverseComparator.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/ReverseComparator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: ReverseComparator.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+public final class ReverseComparator implements Comparator, Serializable {
+	public int compare(Object x, Object y) {
+		return - ( (Comparable) x ).compareTo(y);
+	}
+	
+	public boolean equals(Object obj) {
+		return obj instanceof ReverseComparator;
+	}
+	
+	public int hashCode() {
+		return 0;
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Role.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Role.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Role.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+package org.hibernate.test.legacy;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author hbm2java
+ */
+public class Role {
+
+   long id;
+   java.lang.String name;
+   Set interventions = new HashSet();
+private List bunchOfStrings;
+
+  long getId() {
+    return id;
+  }
+
+  void  setId(long newValue) {
+    id = newValue;
+  }
+
+  java.lang.String getName() {
+    return name;
+  }
+
+  void  setName(java.lang.String newValue) {
+    name = newValue;
+  }
+
+  public Set getInterventions() {
+  	return interventions;
+  }
+  
+  public void setInterventions(Set iv) {
+  	interventions = iv;
+  }
+
+  List getBunchOfStrings() {
+  	return bunchOfStrings;
+  }
+  
+  void setBunchOfStrings(List s) {
+  	bunchOfStrings = s;
+  }
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/S.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/S.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/S.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+//$Id: S.java 4599 2004-09-26 05:18:27Z oneovthafew $
+
+package org.hibernate.test.legacy;
+
+public class S {
+	private String address;
+	private int count;
+
+	public S(int countArg, String addressArg) {
+		count = countArg;
+		address = addressArg;
+	}
+	
+	/**
+	 * Gets the address
+	 * @return Returns a String
+	 */
+	public String getAddress() {
+		return address;
+	}
+	/**
+	 * Sets the address
+	 * @param address The address to set
+	 */
+	public void setAddress(String address) {
+		this.address = address;
+	}
+	/**
+	 * Gets the count
+	 * @return Returns a int
+	 */
+	public int getCount() {
+		return count;
+	}
+	/**
+	 * Sets the count
+	 * @param count The count to set
+	 */
+	public void setCount(int count) {
+		this.count = count;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SQLFunctionsTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SQLFunctionsTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SQLFunctionsTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,659 @@
+//$Id: SQLFunctionsTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Query;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.dialect.DB2Dialect;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.InterbaseDialect;
+import org.hibernate.dialect.MckoiDialect;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.dialect.OracleDialect;
+import org.hibernate.dialect.SybaseDialect;
+import org.hibernate.dialect.TimesTenDialect;
+import org.hibernate.dialect.function.SQLFunction;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+
+public class SQLFunctionsTest extends LegacyTestCase {
+
+	private static final Log log = LogFactory.getLog(SQLFunctionsTest.class);
+
+	public SQLFunctionsTest(String name) {
+		super(name);
+	}
+
+	public String[] getMappings() {
+		return new String[] {
+			"legacy/AltSimple.hbm.xml",
+			"legacy/Broken.hbm.xml",
+			"legacy/Blobber.hbm.xml"
+		};
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SQLFunctionsTest.class );
+	}
+
+	public void testDialectSQLFunctions() throws Exception {
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Iterator iter = s.iterate("select max(s.count) from Simple s");
+
+		if ( getDialect() instanceof MySQLDialect ) assertTrue( iter.hasNext() && iter.next()==null );
+
+		Simple simple = new Simple();
+		simple.setName("Simple Dialect Function Test");
+		simple.setAddress("Simple Address");
+		simple.setPay(new Float(45.8));
+		simple.setCount(2);
+		s.save(simple, new Long(10) );
+
+		// Test to make sure allocating an specified object operates correctly.
+		assertTrue(
+			s.find("select new org.hibernate.test.legacy.S(s.count, s.address) from Simple s").size() == 1
+		);
+
+		// Quick check the base dialect functions operate correctly
+		assertTrue(
+			s.find("select max(s.count) from Simple s").size() == 1
+		);
+		assertTrue(
+			s.find("select count(*) from Simple s").size() == 1
+		);
+
+		if ( getDialect() instanceof OracleDialect) {
+			// Check Oracle Dialect mix of dialect functions - no args (no parenthesis and single arg functions
+			java.util.List rset = s.find("select s.name, sysdate(), trunc(s.pay), round(s.pay) from Simple s");
+			assertNotNull("Name string should have been returned",(((Object[])rset.get(0))[0]));
+			assertNotNull("Todays Date should have been returned",(((Object[])rset.get(0))[1]));
+			assertEquals("trunc(45.8) result was incorrect ", new Float(45), ( (Object[]) rset.get(0) )[2] );
+			assertEquals("round(45.8) result was incorrect ", new Float(46), ( (Object[]) rset.get(0) )[3] );
+
+			simple.setPay(new Float(-45.8));
+			s.update(simple);
+
+			// Test type conversions while using nested functions (Float to Int).
+			rset = s.find("select abs(round(s.pay)) from Simple s");
+			assertEquals("abs(round(-45.8)) result was incorrect ", new Float(46), rset.get(0));
+
+			// Test a larger depth 3 function example - Not a useful combo other than for testing
+			assertTrue(
+				s.find("select trunc(round(sysdate())) from Simple s").size() == 1
+			);
+
+			// Test the oracle standard NVL funtion as a test of multi-param functions...
+			simple.setPay(null);
+			s.update(simple);
+			Integer value = (Integer) s.find("select MOD( NVL(s.pay, 5000), 2 ) from Simple as s where s.id = 10").get(0);
+			assertTrue( 0 == value.intValue() );
+		}
+
+		if ( (getDialect() instanceof HSQLDialect) ) {
+			// Test the hsql standard MOD funtion as a test of multi-param functions...
+			Integer value = (Integer) s.find("select MOD(s.count, 2) from Simple as s where s.id = 10" ).get(0);
+			assertTrue( 0 == value.intValue() );
+		}
+
+		s.delete(simple);
+		t.commit();
+		s.close();
+	}
+
+	public void testSetProperties() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save(simple, new Long(10) );
+		Query q = s.createQuery("from Simple s where s.name=:name and s.count=:count");
+		q.setProperties(simple);
+		assertTrue( q.list().get(0)==simple );
+		//misuse of "Single" as a propertyobject, but it was the first testclass i found with a collection ;)
+		Single single = new Single() { // trivial hack to test properties with arrays.
+			String[] getStuff() { return (String[]) getSeveral().toArray(new String[getSeveral().size()]); }
+		};
+
+		List l = new ArrayList();
+		l.add("Simple 1");
+		l.add("Slimeball");
+		single.setSeveral(l);
+		q = s.createQuery("from Simple s where s.name in (:several)");
+		q.setProperties(single);
+		assertTrue( q.list().get(0)==simple );
+
+
+		q = s.createQuery("from Simple s where s.name in (:stuff)");
+		q.setProperties(single);
+		assertTrue( q.list().get(0)==simple );
+		s.delete(simple);
+		t.commit();
+		s.close();
+	}
+
+	public void testSetPropertiesMap() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save(simple, new Long(10) );
+		Map parameters = new HashMap();
+		parameters.put("name", simple.getName());
+		parameters.put("count", new Integer(simple.getCount()));
+		
+		Query q = s.createQuery("from Simple s where s.name=:name and s.count=:count");
+		q.setProperties(((Map)parameters));
+		assertTrue( q.list().get(0)==simple );
+		
+		List l = new ArrayList();
+		l.add("Simple 1");
+		l.add("Slimeball");
+		parameters.put("several", l);
+		q = s.createQuery("from Simple s where s.name in (:several)");
+		q.setProperties(parameters);
+		assertTrue( q.list().get(0)==simple );
+
+
+		parameters.put("stuff", l.toArray(new String[0]));
+		q = s.createQuery("from Simple s where s.name in (:stuff)");
+		q.setProperties(parameters);
+		assertTrue( q.list().get(0)==simple );
+		s.delete(simple);
+		t.commit();
+		s.close();
+	}
+	public void testBroken() throws Exception {
+		if (getDialect() instanceof Oracle9Dialect) return;
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Broken b = new Fixed();
+		b.setId( new Long(123));
+		b.setOtherId("foobar");
+		s.save(b);
+		s.flush();
+		b.setTimestamp( new Date() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update(b);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		b = (Broken) s.load( Broken.class, b );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete(b);
+		t.commit();
+		s.close();
+	}
+
+	public void testNothinToUpdate() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save( simple, new Long(10) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update( simple, new Long(10) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update( simple, new Long(10) );
+		s.delete(simple);
+		t.commit();
+		s.close();
+	}
+
+	public void testCachedQuery() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save( simple, new Long(10) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Query q = s.createQuery("from Simple s where s.name=?");
+		q.setCacheable(true);
+		q.setString(0, "Simple 1");
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.list().size()==1 );
+		q = s.createQuery("from Simple s where s.name=:name");
+		q.setCacheable(true);
+		q.setString("name", "Simple 1");
+		assertTrue( q.list().size()==1 );
+		simple = (Simple) q.list().get(0);
+
+		q.setString("name", "Simple 2");
+		assertTrue( q.list().size()==0 );
+		assertTrue( q.list().size()==0 );
+		simple.setName("Simple 2");
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.list().size()==1 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		q = s.createQuery("from Simple s where s.name=:name");
+		q.setString("name", "Simple 2");
+		q.setCacheable(true);
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.list().size()==1 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update( simple, new Long(10) );
+		s.delete(simple);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		q = s.createQuery("from Simple s where s.name=?");
+		q.setCacheable(true);
+		q.setString(0, "Simple 1");
+		assertTrue( q.list().size()==0 );
+		assertTrue( q.list().size()==0 );
+		t.commit();
+		s.close();
+	}
+
+	public void testCachedQueryRegion() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save( simple, new Long(10) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Query q = s.createQuery("from Simple s where s.name=?");
+		q.setCacheRegion("foo");
+		q.setCacheable(true);
+		q.setString(0, "Simple 1");
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.list().size()==1 );
+		q = s.createQuery("from Simple s where s.name=:name");
+		q.setCacheRegion("foo");
+		q.setCacheable(true);
+		q.setString("name", "Simple 1");
+		assertTrue( q.list().size()==1 );
+		simple = (Simple) q.list().get(0);
+
+		q.setString("name", "Simple 2");
+		assertTrue( q.list().size()==0 );
+		assertTrue( q.list().size()==0 );
+		simple.setName("Simple 2");
+		assertTrue( q.list().size()==1 );
+		assertTrue( q.list().size()==1 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update( simple, new Long(10) );
+		s.delete(simple);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		q = s.createQuery("from Simple s where s.name=?");
+		q.setCacheRegion("foo");
+		q.setCacheable(true);
+		q.setString(0, "Simple 1");
+		assertTrue( q.list().size()==0 );
+		assertTrue( q.list().size()==0 );
+		t.commit();
+		s.close();
+	}
+
+	public void testSQLFunctions() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save(simple, new Long(10) );
+
+		if ( getDialect() instanceof DB2Dialect) {
+			s.find("from Simple s where repeat('foo', 3) = 'foofoofoo'");
+			s.find("from Simple s where repeat(s.name, 3) = 'foofoofoo'");
+			s.find("from Simple s where repeat( lower(s.name), 3 + (1-1) / 2) = 'foofoofoo'");
+		}
+
+		assertTrue(
+			s.find("from Simple s where upper( s.name ) ='SIMPLE 1'").size()==1
+		);
+		if ( !(getDialect() instanceof HSQLDialect) ) {
+			assertTrue(
+				s.find("from Simple s where not( upper( s.name ) ='yada' or 1=2 or 'foo'='bar' or not('foo'='foo') or 'foo' like 'bar' )").size()==1
+			);
+		}
+		if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof SybaseDialect) && !(getDialect() instanceof MckoiDialect) && !(getDialect() instanceof InterbaseDialect) && !(getDialect() instanceof TimesTenDialect) ) { //My SQL has a funny concatenation operator
+			assertTrue(
+				s.find("from Simple s where lower( s.name || ' foo' ) ='simple 1 foo'").size()==1
+			);
+		}
+		if ( (getDialect() instanceof SybaseDialect) ) {
+			assertTrue(
+				s.find("from Simple s where lower( s.name + ' foo' ) ='simple 1 foo'").size()==1
+			);
+		}
+		if ( (getDialect() instanceof MckoiDialect) || (getDialect() instanceof TimesTenDialect)) {
+			assertTrue(
+				s.find("from Simple s where lower( concat(s.name, ' foo') ) ='simple 1 foo'").size()==1
+			);
+		}
+
+		Simple other = new Simple();
+		other.setName("Simple 2");
+		other.setCount(12);
+		simple.setOther(other);
+		s.save( other, new Long(20) );
+		//s.find("from Simple s where s.name ## 'cat|rat|bag'");
+		assertTrue(
+			s.find("from Simple s where upper( s.other.name ) ='SIMPLE 2'").size()==1
+		);
+		assertTrue(
+			s.find("from Simple s where not ( upper( s.other.name ) ='SIMPLE 2' )").size()==0
+		);
+		assertTrue(
+			s.find("select distinct s from Simple s where ( ( s.other.count + 3 ) = (15*2)/2 and s.count = 69) or ( ( s.other.count + 2 ) / 7 ) = 2").size()==1
+		);
+		assertTrue(
+			s.find("select s from Simple s where ( ( s.other.count + 3 ) = (15*2)/2 and s.count = 69) or ( ( s.other.count + 2 ) / 7 ) = 2 order by s.other.count").size()==1
+		);
+		Simple min = new Simple();
+		min.setCount(-1);
+		s.save(min, new Long(30) );
+		if ( ! (getDialect() instanceof MySQLDialect) && ! (getDialect() instanceof HSQLDialect) ) { //My SQL has no subqueries
+			assertTrue(
+				s.find("from Simple s where s.count > ( select min(sim.count) from Simple sim )").size()==2
+			);
+			t.commit();
+			t = s.beginTransaction();
+			assertTrue(
+				s.find("from Simple s where s = some( select sim from Simple sim where sim.count>=0 ) and s.count >= 0").size()==2
+			);
+			assertTrue(
+				s.find("from Simple s where s = some( select sim from Simple sim where sim.other.count=s.other.count ) and s.other.count > 0").size()==1
+			);
+		}
+
+		Iterator iter = s.iterate("select sum(s.count) from Simple s group by s.count having sum(s.count) > 10");
+		assertTrue( iter.hasNext() );
+		assertEquals( new Long(12), iter.next() );
+		assertTrue( !iter.hasNext() );
+		if ( ! (getDialect() instanceof MySQLDialect) ) {
+			iter = s.iterate("select s.count from Simple s group by s.count having s.count = 12");
+			assertTrue( iter.hasNext() );
+		}
+
+		s.iterate("select s.id, s.count, count(t), max(t.date) from Simple s, Simple t where s.count = t.count group by s.id, s.count order by s.count");
+
+		Query q = s.createQuery("from Simple s");
+		q.setMaxResults(10);
+		assertTrue( q.list().size()==3 );
+		q = s.createQuery("from Simple s");
+		q.setMaxResults(1);
+		assertTrue( q.list().size()==1 );
+		q = s.createQuery("from Simple s");
+		assertTrue( q.list().size()==3 );
+		q = s.createQuery("from Simple s where s.name = ?");
+		q.setString(0, "Simple 1");
+		assertTrue( q.list().size()==1 );
+		q = s.createQuery("from Simple s where s.name = ? and upper(s.name) = ?");
+		q.setString(1, "SIMPLE 1");
+		q.setString(0, "Simple 1");
+		q.setFirstResult(0);
+		assertTrue( q.iterate().hasNext() );
+		q = s.createQuery("from Simple s where s.name = :foo and upper(s.name) = :bar or s.count=:count or s.count=:count + 1");
+		q.setParameter("bar", "SIMPLE 1");
+		q.setString("foo", "Simple 1");
+		q.setInteger("count", 69);
+		q.setFirstResult(0);
+		assertTrue( q.iterate().hasNext() );
+		q = s.createQuery("select s.id from Simple s");
+		q.setFirstResult(1);
+		q.setMaxResults(2);
+		iter = q.iterate();
+		int i=0;
+		while ( iter.hasNext() ) {
+			assertTrue( iter.next() instanceof Long );
+			i++;
+		}
+		assertTrue(i==2);
+		q = s.createQuery("select all s, s.other from Simple s where s = :s");
+		q.setParameter("s", simple);
+		assertTrue( q.list().size()==1 );
+
+
+		q = s.createQuery("from Simple s where s.name in (:name_list) and s.count > :count");
+		HashSet set = new HashSet();
+		set.add("Simple 1"); set.add("foo");
+		q.setParameterList( "name_list", set );
+		q.setParameter("count", new Integer(-1) );
+		assertTrue( q.list().size()==1 );
+
+		ScrollableResults sr = s.createQuery("from Simple s").scroll();
+		sr.next();
+		sr.get(0);
+		sr.close();
+
+		s.delete(other);
+		s.delete(simple);
+		s.delete(min);
+		t.commit();
+		s.close();
+
+	}
+
+	public void testBlobClob() throws Exception {
+
+		Session s = openSession();
+		Blobber b = new Blobber();
+		b.setBlob( Hibernate.createBlob( "foo/bar/baz".getBytes() ) );
+		b.setClob( Hibernate.createClob("foo/bar/baz") );
+		s.save(b);
+		//s.refresh(b);
+		//assertTrue( b.getClob() instanceof ClobImpl );
+		s.flush();
+		s.refresh(b);
+		//b.getBlob().setBytes( 2, "abc".getBytes() );
+		b.getClob().getSubString(2, 3);
+		//b.getClob().setString(2, "abc");
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) );
+		Blobber b2 = new Blobber();
+		s.save(b2);
+		b2.setBlob( b.getBlob() );
+		b.setBlob(null);
+		//assertTrue( b.getClob().getSubString(1, 3).equals("fab") );
+		b.getClob().getSubString(1, 6);
+		//b.getClob().setString(1, "qwerty");
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) );
+		b.setClob( Hibernate.createClob("xcvfxvc xcvbx cvbx cvbx cvbxcvbxcvbxcvb") );
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) );
+		assertTrue( b.getClob().getSubString(1, 7).equals("xcvfxvc") );
+		//b.getClob().setString(5, "1234567890");
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+
+		/*InputStream is = getClass().getClassLoader().getResourceAsStream("jdbc20.pdf");
+		s = sessionsopenSession();
+		b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) );
+		System.out.println( is.available() );
+		int size = is.available();
+		b.setBlob( Hibernate.createBlob( is, is.available() ) );
+		s.flush();
+		s.connection().commit();
+		ResultSet rs = s.connection().createStatement().executeQuery("select datalength(blob_) from blobber where id=" + b.getId() );
+		rs.next();
+		assertTrue( size==rs.getInt(1) );
+		rs.close();
+		s.close();
+
+		s = sessionsopenSession();
+		b = (Blobber) s.load( Blobber.class, new Integer( b.getId() ) );
+		File f = new File("C:/foo.pdf");
+		f.createNewFile();
+		FileOutputStream fos = new FileOutputStream(f);
+		Blob blob = b.getBlob();
+		byte[] bytes = blob.getBytes( 1, (int) blob.length() );
+		System.out.println( bytes.length );
+		fos.write(bytes);
+		fos.flush();
+		fos.close();
+		s.close();*/
+
+	}
+
+	public void testSqlFunctionAsAlias() throws Exception {
+		String functionName = locateAppropriateDialectFunctionNameForAliasTest();
+		if (functionName == null) {
+			log.info("Dialect does not list any no-arg functions");
+			return;
+		}
+
+		log.info("Using function named [" + functionName + "] for 'function as alias' test");
+		String query = "select " + functionName + " from Simple as " + functionName + " where " + functionName + ".id = 10";
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save( simple, new Long(10) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		List result = s.find(query);
+		assertTrue( result.size() == 1 );
+		assertTrue(result.get(0) instanceof Simple);
+		s.delete( result.get(0) );
+		t.commit();
+		s.close();
+	}
+
+	private String locateAppropriateDialectFunctionNameForAliasTest() {
+		for (Iterator itr = getDialect().getFunctions().entrySet().iterator(); itr.hasNext(); ) {
+			final Map.Entry entry = (Map.Entry) itr.next();
+			final SQLFunction function = (SQLFunction) entry.getValue();
+			if ( !function.hasArguments() && !function.hasParenthesesIfNoArguments() ) {
+				return (String) entry.getKey();
+			}
+		}
+		return null;
+	}
+
+	public void testCachedQueryOnInsert() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Simple simple = new Simple();
+		simple.setName("Simple 1");
+		s.save( simple, new Long(10) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Query q = s.createQuery("from Simple s");
+		List list = q.setCacheable(true).list();
+		assertTrue( list.size()==1 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		q = s.createQuery("from Simple s");
+		list = q.setCacheable(true).list();
+		assertTrue( list.size()==1 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Simple simple2 = new Simple();
+		simple2.setCount(133);
+		s.save( simple2, new Long(12) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		q = s.createQuery("from Simple s");
+		list = q.setCacheable(true).list();
+		assertTrue( list.size()==2 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		q = s.createQuery("from Simple s");
+		list = q.setCacheable(true).list();
+		assertTrue( list.size()==2 );
+		Iterator i = list.iterator();
+		while ( i.hasNext() ) s.delete( i.next() );
+		t.commit();
+		s.close();
+
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SQLLoaderTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SQLLoaderTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SQLLoaderTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,669 @@
+//$Id: SQLLoaderTest.java 11383 2007-04-02 15:34:02Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.dialect.OracleDialect;
+import org.hibernate.dialect.PostgreSQLDialect;
+import org.hibernate.dialect.TimesTenDialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+
+public class SQLLoaderTest extends LegacyTestCase {
+
+	static int nextInt = 1;
+	static long nextLong = 1;
+
+	public SQLLoaderTest(String arg) {
+		super(arg);
+	}
+
+	public String[] getMappings() {
+		return new String[] {
+			"legacy/ABC.hbm.xml",
+			"legacy/Category.hbm.xml",
+			"legacy/Simple.hbm.xml",
+			"legacy/Fo.hbm.xml",
+			"legacy/SingleSeveral.hbm.xml",
+			"legacy/Componentizable.hbm.xml",
+            "legacy/CompositeIdId.hbm.xml"
+		};
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SQLLoaderTest.class );
+	}
+
+	public void testTS() throws Exception {
+		if (getDialect() instanceof Oracle9Dialect) return;
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+		Simple sim = new Simple();
+		sim.setDate( new Date() );
+		session.save( sim, new Long(1) );
+		Query q = session.createSQLQuery("select {sim.*} from Simple {sim} where {sim}.date_ = ?", "sim", Simple.class);
+		q.setTimestamp( 0, sim.getDate() );
+		assertTrue ( q.list().size()==1 );
+		session.delete(sim);
+		txn.commit();
+		session.close();
+	}
+
+
+	public void testFindBySQLStar() throws HibernateException, SQLException {
+		Session session = openSession();
+		session.delete("from Assignable");
+		session.delete("from Category");
+		session.delete("from Simple");
+		session.delete("from A");
+
+		Category s = new Category();
+		s.setName(String.valueOf(nextLong++));
+		session.save(s);
+
+		Simple simple = new Simple();
+		simple.init();
+		session.save(simple, new Long(nextLong++));
+
+		A a = new A();
+		session.save(a);
+
+		B b = new B();
+		session.save(b);
+		session.flush();
+
+		session.createSQLQuery("select {category.*} from category {category}", "category", Category.class).list();
+		session.createSQLQuery("select {simple.*} from Simple {simple}", "simple", Simple.class).list();
+		session.createSQLQuery("select {a.*} from TA {a}", "a", A.class).list();
+
+		session.connection().commit();
+		session.close();
+
+	}
+
+	public void testFindBySQLProperties() throws HibernateException, SQLException {
+			Session session = openSession();
+			session.delete("from Category");
+
+			Category s = new Category();
+			s.setName(String.valueOf(nextLong++));
+			session.save(s);
+
+			s = new Category();
+			s.setName("WannaBeFound");
+			session.flush();
+
+			Query query = session.createSQLQuery("select {category.*} from category {category} where {category}.name = :name", "category", Category.class);
+
+			query.setProperties(s);
+			//query.setParameter("name", s.getName());
+
+			query.list();
+
+			query = session.createSQLQuery("select {category.*} from category {category} where {category}.name in (:names)", "category", Category.class);
+			String[] str = new String[] { "WannaBeFound", "NotThere" };
+			query.setParameterList("names", str);
+			
+			query.uniqueResult();
+			
+			session.connection().commit();
+			session.close();
+			
+			
+
+		}
+
+	public void testFindBySQLAssociatedObjects() throws HibernateException, SQLException {
+		Session s = openSession();
+		s.delete("from Assignable");
+		s.delete("from Category");
+
+		Category c = new Category();
+		c.setName("NAME");
+		Assignable assn = new Assignable();
+		assn.setId("i.d.");
+		List l = new ArrayList();
+		l.add(c);
+		assn.setCategories(l);
+		c.setAssignable(assn);
+		s.save(assn);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		List list = s.createSQLQuery("select {category.*} from category {category}", "category", Category.class).list();
+		list.get(0);
+		s.connection().commit();
+		s.close();
+		
+		if ( getDialect() instanceof MySQLDialect ) return;
+		if ( getDialect() instanceof OracleDialect ) return; // todo : this fails on Oracle8 also
+
+		s = openSession();
+
+		Query query = s.getNamedQuery("namedsql");
+		assertNotNull(query);
+		list = query.list();
+        assertNotNull(list);
+		
+		Object[] values = (Object[]) list.get(0);
+		assertNotNull(values[0]);
+		assertNotNull(values[1]);
+		assertTrue("wrong type: " + values[0].getClass(), values[0] instanceof Category);
+		assertTrue("wrong type: " + values[1].getClass(), values[1] instanceof Assignable);
+		
+		s.connection().commit();
+		s.close();
+
+	}
+
+	public void testPropertyResultSQL() throws HibernateException, SQLException {
+		
+		if ( getDialect() instanceof MySQLDialect ) return;
+			
+		Session s = openSession();
+		s.delete("from Assignable");
+		s.delete("from Category");
+
+		Category c = new Category();
+		c.setName("NAME");
+		Assignable assn = new Assignable();
+		assn.setId("i.d.");
+		List l = new ArrayList();
+		l.add(c);
+		assn.setCategories(l);
+		c.setAssignable(assn);
+		s.save(assn);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+
+		Query query = s.getNamedQuery("nonaliasedsql");
+		assertNotNull(query);
+		List list = query.list();
+        assertNotNull(list);
+		
+		assertTrue(list.get(0) instanceof Category);
+		
+		s.connection().commit();
+		s.close();
+
+	}
+	
+	public void testFindBySQLMultipleObject() throws HibernateException, SQLException {
+		Session s = openSession();
+		s.delete("from Assignable");
+		s.delete("from Category");
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		Category c = new Category();
+		c.setName("NAME");
+		Assignable assn = new Assignable();
+		assn.setId("i.d.");
+		List l = new ArrayList();
+		l.add(c);
+		assn.setCategories(l);
+		c.setAssignable(assn);
+		s.save(assn);
+		s.flush();
+		c = new Category();
+		c.setName("NAME2");
+		assn = new Assignable();
+		assn.setId("i.d.2");
+		l = new ArrayList();
+		l.add(c);
+		assn.setCategories(l);
+		c.setAssignable(assn);
+		s.save(assn);
+		s.flush();
+
+		assn = new Assignable();
+		assn.setId("i.d.3");
+		s.save(assn);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		if ( getDialect() instanceof MySQLDialect ) return;
+
+		s = openSession();
+		List list = s.createSQLQuery("select {category.*}, {assignable.*} from category {category}, \"assign-able\" {assignable}", new String[] { "category", "assignable" }, new Class[] { Category.class, Assignable.class }).list();
+
+		assertTrue(list.size() == 6); // crossproduct of 2 categories x 3 assignables
+		assertTrue(list.get(0) instanceof Object[]);
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testFindBySQLParameters() throws HibernateException, SQLException {
+		Session s = openSession();
+		s.delete("from Assignable");
+		s.delete("from Category");
+		s.flush();
+		s.connection().commit();
+		s.close();
+		s = openSession();
+		Category c = new Category();
+		c.setName("Good");
+		Assignable assn = new Assignable();
+		assn.setId("i.d.");
+		List l = new ArrayList();
+		l.add(c);
+		assn.setCategories(l);
+		c.setAssignable(assn);
+		s.save(assn);
+		s.flush();
+		c = new Category();
+		c.setName("Best");
+		assn = new Assignable();
+		assn.setId("i.d.2");
+		l = new ArrayList();
+		l.add(c);
+		assn.setCategories(l);
+		c.setAssignable(assn);
+		s.save(assn);
+		s.flush();
+		c = new Category();
+		c.setName("Better");
+		assn = new Assignable();
+		assn.setId("i.d.7");
+		l = new ArrayList();
+		l.add(c);
+		assn.setCategories(l);
+		c.setAssignable(assn);
+		s.save(assn);
+		s.flush();
+
+		assn = new Assignable();
+		assn.setId("i.d.3");
+		s.save(assn);
+		s.flush();
+		s.connection().commit();
+		s.close();
+
+		s = openSession();
+		Query basicParam = s.createSQLQuery("select {category.*} from category {category} where {category}.name = 'Best'", "category", Category.class);
+		List list = basicParam.list();
+		assertEquals(1, list.size());
+
+		Query unnamedParam = s.createSQLQuery("select {category.*} from category {category} where {category}.name = ? or {category}.name = ?", "category", Category.class);
+		unnamedParam.setString(0, "Good");
+		unnamedParam.setString(1, "Best");
+		list = unnamedParam.list();
+		assertEquals(2, list.size());
+
+		Query namedParam = s.createSQLQuery("select {category.*} from category {category} where ({category}.name=:firstCat or {category}.name=:secondCat)", "category", Category.class);
+		namedParam.setString("firstCat", "Better");
+		namedParam.setString("secondCat", "Best");
+		list = namedParam.list();
+		assertEquals(2, list.size());
+
+		s.connection().commit();
+		s.close();
+	}
+
+	public void testEscapedJDBC() throws HibernateException, SQLException {
+		if ( 
+				getDialect() instanceof HSQLDialect || 
+				getDialect() instanceof PostgreSQLDialect
+		) return;
+
+		Session session = openSession();
+		session.delete("from A");
+		A savedA = new A();
+		savedA.setName("Max");
+		session.save(savedA);
+
+		B savedB = new B();
+		session.save(savedB);
+		session.flush();
+
+		int count = session.createQuery("from A").list().size();
+		session.close();
+
+		session = openSession();
+
+		Query query;
+		if ( getDialect() instanceof OracleDialect ) {
+			// Oracle8 does not support X/Open extension functions :)
+			query = session.createSQLQuery("select identifier_column as {a.id}, clazz_discriminata as {a.class}, count_ as {a.count}, name as {a.name} from TA where upper(name) like upper('max')", "a", A.class);
+		}
+		else if( getDialect() instanceof TimesTenDialect) {
+            // TimesTen does not permit general expressions (like UPPER) in the second part of a LIKE expression,
+            // so we execute a similar test 
+            query = session.createSQLQuery("select identifier_column as {a.id}, clazz_discriminata as {a.class}, count_ as {a.count}, name as {a.name} from TA where {fn ucase(name)} like 'MAX'", "a", A.class);
+        } else {
+            query = session.createSQLQuery("select identifier_column as {a.id}, clazz_discriminata as {a.class}, count_ as {a.count}, name as {a.name} from TA where {fn ucase(name)} like {fn ucase('max')}", "a", A.class);
+        }
+		List list = query.list();
+
+		assertNotNull(list);
+		assertEquals(1, list.size());
+		session.connection().commit();
+		session.close();
+	}
+
+	public void testDoubleAliasing() throws HibernateException, SQLException {	
+
+		Session session = openSession();
+		session.delete("from A");
+		A savedA = new A();
+		savedA.setName("Max");
+		session.save(savedA);
+
+		B savedB = new B();
+		session.save(savedB);
+		session.flush();
+
+		int count = session.createQuery("from A").list().size();
+		session.close();
+
+		session = openSession();
+
+		Query query = session.createSQLQuery("select a.identifier_column as {a1.id}, a.clazz_discriminata as {a1.class}, a.count_ as {a1.count}, a.name as {a1.name} " +
+											", b.identifier_column as {a2.id}, b.clazz_discriminata as {a2.class}, b.count_ as {a2.count}, b.name as {a2.name} " +
+											" from TA a, TA b" +
+											" where a.identifier_column = b.identifier_column", new String[] {"a1", "a2" }, new Class[] {A.class, A.class});
+		List list = query.list();
+
+		assertNotNull(list);
+		assertEquals(2, list.size());
+		session.connection().commit();
+		session.close();
+	}
+
+	// TODO: compositeid's - how ? (SingleSeveral.hbm.xml test)
+	public void testEmbeddedCompositeProperties() throws HibernateException, SQLException {
+	   Session session = openSession();
+
+	   Single s = new Single();
+	   s.setId("my id");
+	   s.setString("string 1");
+	   session.save(s);
+	   session.flush();
+	   session.connection().commit();
+
+	   session.clear();
+
+	   Query query = session.createSQLQuery("select {sing.*} from Single {sing}", "sing", Single.class);
+
+	   List list = query.list();
+
+	   assertTrue(list.size()==1);
+
+	   session.clear();
+
+	   query = session.createSQLQuery("select {sing.*} from Single {sing} where sing.id = ?", "sing", Single.class);
+	   query.setString(0, "my id");
+	   list = query.list();
+
+	   assertTrue(list.size()==1);
+
+	   session.clear();
+
+	   query = session.createSQLQuery("select s.id as {sing.id}, s.string_ as {sing.string}, s.prop as {sing.prop} from Single s where s.id = ?", "sing", Single.class);
+	   query.setString(0, "my id");
+	   list = query.list();
+
+	   assertTrue(list.size()==1);
+
+	   session.clear();
+
+	   query = session.createSQLQuery("select s.id as {sing.id}, s.string_ as {sing.string}, s.prop as {sing.prop} from Single s where s.id = ?", "sing", Single.class);
+	   query.setString(0, "my id");
+	   list = query.list();
+
+	   assertTrue(list.size()==1);
+
+	   session.connection().commit();
+	   session.close();
+
+	}
+
+	public void testReturnPropertyComponentRenameFailureExpected() throws HibernateException, SQLException {
+		// failure expected because this was a regression introduced previously which needs to get tracked down.
+		Session session = openSession();
+		Componentizable componentizable = setupComponentData(session);
+		
+		Query namedQuery = session.getNamedQuery("queryComponentWithOtherColumn");
+		List list = namedQuery.list();
+		
+		assertEquals(1, list.size());
+		assertEquals( "flakky comp", ( (Componentizable) list.get(0) ).getComponent().getName() );
+		
+		session.clear();
+		
+		session.delete(componentizable);
+		session.flush();
+		
+		session.connection().commit();
+		session.close();
+	}
+	
+	public void testComponentStar() throws HibernateException, SQLException {
+	    componentTest("select {comp.*} from Componentizable comp");
+	}
+	
+	public void testComponentNoStar() throws HibernateException, SQLException {
+	    componentTest("select comp.id as {comp.id}, comp.nickName as {comp.nickName}, comp.name as {comp.component.name}, comp.subName as {comp.component.subComponent.subName}, comp.subName1 as {comp.component.subComponent.subName1} from Componentizable comp");
+	}
+	
+
+	private void componentTest(String sql) throws SQLException {
+        Session session = openSession();
+	    
+	    Componentizable c = setupComponentData( session );
+        
+	    Query q = session.createSQLQuery(sql, "comp", Componentizable.class);
+	    List list = q.list();
+	    
+	    assertEquals(list.size(),1);
+	    
+	    Componentizable co = (Componentizable) list.get(0);
+	    
+	    assertEquals(c.getNickName(), co.getNickName());
+	    assertEquals(c.getComponent().getName(), co.getComponent().getName());
+	    assertEquals(c.getComponent().getSubComponent().getSubName(), co.getComponent().getSubComponent().getSubName());
+	    
+	    session.delete(co);
+	    session.flush();
+	    session.connection().commit();
+	    session.close();
+    }
+
+	private Componentizable setupComponentData(Session session) throws SQLException {
+		Componentizable c = new Componentizable();
+	    c.setNickName("Flacky");
+	    Component component = new Component();
+	    component.setName("flakky comp");
+	    SubComponent subComponent = new SubComponent();
+	    subComponent.setSubName("subway");
+        component.setSubComponent(subComponent);
+	    
+        c.setComponent(component);
+        
+        session.save(c);
+        
+        session.flush();
+        session.connection().commit();
+        
+        session.clear();
+		return c;
+	}
+
+    public void testFindSimpleBySQL() throws Exception {
+		if ( getDialect() instanceof MySQLDialect ) return;
+		Session session = openSession();
+		Category s = new Category();
+		s.setName(String.valueOf(nextLong++));
+		session.save(s);
+		session.flush();
+
+		Query query = session.createSQLQuery("select s.category_key_col as {category.id}, s.name as {category.name}, s.\"assign-able-id\" as {category.assignable} from {category} s", "category", Category.class);
+		List list = query.list();
+
+		assertNotNull(list);
+		assertTrue(list.size() > 0);
+		assertTrue(list.get(0) instanceof Category);
+		session.connection().commit();
+		session.close();
+		// How do we handle objects with composite id's ? (such as Single)
+	}
+
+	public void testFindBySQLSimpleByDiffSessions() throws Exception {
+		Session session = openSession();
+		Category s = new Category();
+		s.setName(String.valueOf(nextLong++));
+		session.save(s);
+		session.flush();
+		session.connection().commit();
+		session.close();
+
+		if ( getDialect() instanceof MySQLDialect ) return;
+
+		session = openSession();
+
+		Query query = session.createSQLQuery("select s.category_key_col as {category.id}, s.name as {category.name}, s.\"assign-able-id\" as {category.assignable} from {category} s", "category", Category.class);
+		List list = query.list();
+
+		assertNotNull(list);
+		assertTrue(list.size() > 0);
+		assertTrue(list.get(0) instanceof Category);
+
+		// How do we handle objects that does not have id property (such as Simple ?)
+		// How do we handle objects with composite id's ? (such as Single)
+		session.connection().commit();
+		session.close();
+	}
+
+	public void testFindBySQLDiscriminatedSameSession() throws Exception {
+		Session session = openSession();
+		session.delete("from A");
+		A savedA = new A();
+		session.save(savedA);
+
+		B savedB = new B();
+		session.save(savedB);
+		session.flush();
+
+		Query query = session.createSQLQuery("select identifier_column as {a.id}, clazz_discriminata as {a.class}, name as {a.name}, count_ as {a.count} from TA {a}", "a", A.class);
+		List list = query.list();
+
+		assertNotNull(list);
+		assertEquals(2, list.size());
+
+		A a1 = (A) list.get(0);
+		A a2 = (A) list.get(1);
+
+		assertTrue((a2 instanceof B) || (a1 instanceof B));
+		assertFalse(a1 instanceof B && a2 instanceof B);
+
+		if (a1 instanceof B) {
+			assertSame(a1, savedB);
+			assertSame(a2, savedA);
+		}
+		else {
+			assertSame(a2, savedB);
+			assertSame(a1, savedA);
+		}
+
+		session.clear();
+		List list2 = session.getNamedQuery("propertyResultDiscriminator").list();
+		assertEquals(2, list2.size());
+		
+		session.connection().commit();
+		session.close();
+	}
+
+	public void testFindBySQLDiscriminatedDiffSession() throws Exception {
+		Session session = openSession();
+		session.delete("from A");
+		A savedA = new A();
+		session.save(savedA);
+
+		B savedB = new B();
+		session.save(savedB);
+		session.flush();
+
+		int count = session.createQuery("from A").list().size();
+		session.close();
+
+		session = openSession();
+
+		Query query = session.createSQLQuery("select identifier_column as {a.id}, clazz_discriminata as {a.class}, count_ as {a.count}, name as {a.name} from TA", "a", A.class);
+		List list = query.list();
+
+		assertNotNull(list);
+		assertEquals(count, list.size());
+		session.connection().commit();
+		session.close();
+	}
+
+
+    public void testCompositeIdId() throws HibernateException, SQLException {
+	    // issue HHH-21
+        Session s = openSession();
+
+        CompositeIdId id = new CompositeIdId();
+        id.setName("Max");
+        id.setSystem("c64");
+        id.setId("games");
+
+        s.save(id);
+        s.flush();
+        s.connection().commit();
+        s.close();
+
+        s = openSession();
+        // having a composite id with one property named id works since the map used by sqlloader to map names to properties handles it.
+        Query query = s.createSQLQuery("select system as {c.system}, id as {c.id}, name as {c.name}, foo as {c.composite.foo}, bar as {c.composite.bar} from CompositeIdId where system=? and id=?", "c", CompositeIdId.class);
+        query.setString(0, "c64");
+        query.setString(1, "games");
+
+        CompositeIdId id2 = (CompositeIdId) query.uniqueResult();
+        check(id, id2);
+
+        s.flush();
+        s.connection().commit();
+        s.close();
+
+        s = openSession();
+
+        CompositeIdId useForGet = new CompositeIdId();
+        useForGet.setSystem("c64");
+        useForGet.setId("games");
+        // this doesn't work since the verification does not take column span into respect!
+        CompositeIdId getted = (CompositeIdId) s.get(CompositeIdId.class, useForGet);
+        check(id,getted);
+
+
+        s.connection().commit();
+        s.close();
+
+    }
+
+    private void check(CompositeIdId id, CompositeIdId id2) {
+        assertEquals(id,id2);
+        assertEquals(id.getName(), id2.getName());
+        assertEquals(id.getId(), id2.getId());
+        assertEquals(id.getSystem(), id2.getSystem());
+    }
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Several.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Several.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Several.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,90 @@
+//$Id: Several.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+
+public class Several implements Serializable {
+	private String id;
+	private String prop;
+	private Single single;
+	private String string;
+	/**
+	 * Returns the id.
+	 * @return String
+	 */
+	public String getId() {
+		return id;
+	}
+	
+	/**
+	 * Returns the prop.
+	 * @return String
+	 */
+	public String getProp() {
+		return prop;
+	}
+	
+	/**
+	 * Returns the single.
+	 * @return Single
+	 */
+	public Single getSingle() {
+		return single;
+	}
+	
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(String id) {
+		this.id = id;
+	}
+	
+	/**
+	 * Sets the prop.
+	 * @param prop The prop to set
+	 */
+	public void setProp(String prop) {
+		this.prop = prop;
+	}
+	
+	/**
+	 * Sets the single.
+	 * @param single The single to set
+	 */
+	public void setSingle(Single single) {
+		this.single = single;
+	}
+	
+	/**
+	 * Returns the string.
+	 * @return String
+	 */
+	public String getString() {
+		return string;
+	}
+	
+	/**
+	 * Sets the string.
+	 * @param string The string to set
+	 */
+	public void setString(String string) {
+		this.string = string;
+	}
+	
+	/*public boolean equals(Object other) {
+		return ( (Several) other ).id.equals(id) && ( (Several) other ).string.equals(string);
+	}
+	
+	public int hashCode() {
+		return id.hashCode();
+	}*/
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Simple.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Simple.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Simple.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+    <class name="org.hibernate.test.legacy.Simple">
+        <id type="long" column="id_">
+            <generator class="assigned"/>
+        </id>
+        <property name="name"/>
+        <property name="address"/>
+        <property name="count" column="count_" not-null="true" unique="true"/> 
+        <property name="date" column="date_"/>
+        <property name="pay"/>
+        <many-to-one name="other" access="field"/>
+    </class>
+    
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Simple.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Simple.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Simple.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,127 @@
+//$Id: Simple.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+public class Simple implements Serializable {
+	private String name;
+	private String address;
+	private int count;
+	private java.util.Date date;
+	private Float number;
+	private Simple other;
+
+	private Long parent;
+
+	public Simple(int c) {
+		count=c;
+	}
+	public Simple() {}
+
+	public void init() {
+		name="Someone With Along Name";
+		address="1234 Some Street, Some City, Victoria, 3000, Austraya";
+		count=69;
+		date=new java.sql.Date(666);
+		number=new Float(55.8);
+	}
+	/**
+	 * Gets the name
+	 * @return Returns a String
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * Sets the name
+	 * @param name The name to set
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	/**
+	 * Gets the address
+	 * @return Returns a String
+	 */
+	public String getAddress() {
+		return address;
+	}
+	/**
+	 * Sets the address
+	 * @param address The address to set
+	 */
+	public void setAddress(String address) {
+		this.address = address;
+	}
+
+	/**
+	 * Gets the count
+	 * @return Returns a int
+	 */
+	public int getCount() {
+		return count;
+	}
+	/**
+	 * Sets the count
+	 * @param count The count to set
+	 */
+	public void setCount(int count) {
+		this.count = count;
+	}
+
+	/**
+	 * Gets the date
+	 * @return Returns a java.util.Date
+	 */
+	public java.util.Date getDate() {
+		return date;
+	}
+	/**
+	 * Sets the date
+	 * @param date The date to set
+	 */
+	public void setDate(java.util.Date date) {
+		this.date = date;
+	}
+
+	/**
+	 * Gets the pay number
+	 * @return Returns a Float
+	 */
+	public Float getPay() {
+		return number;
+	}
+
+	/**
+	 * Sets the pay number
+	 * @param number The Pay to set
+	 */
+	public void setPay(Float number) {
+		this.number = number;
+	}
+
+	/**
+	 * Returns the other.
+	 * @return Simple
+	 */
+	public Simple getOther() {
+		return other;
+	}
+
+	/**
+	 * Sets the other.
+	 * @param other The other to set
+	 */
+	public void setOther(Simple other) {
+		this.other = other;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Single.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Single.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Single.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,93 @@
+//$Id: Single.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashSet;
+
+
+public class Single implements Serializable {
+	private String id;
+	private String prop;
+	private String string;
+	private Collection several = new HashSet();
+	/**
+	 * Returns the id.
+	 * @return String
+	 */
+	public String getId() {
+		return id;
+	}
+	
+	/**
+	 * Returns the prop.
+	 * @return String
+	 */
+	public String getProp() {
+		return prop;
+	}
+	
+	/**
+	 * Returns the several.
+	 * @return Set
+	 */
+	public Collection getSeveral() {
+		return several;
+	}
+	
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(String id) {
+		this.id = id;
+	}
+	
+	/**
+	 * Sets the prop.
+	 * @param prop The prop to set
+	 */
+	public void setProp(String prop) {
+		this.prop = prop;
+	}
+	
+	/**
+	 * Sets the several.
+	 * @param several The several to set
+	 */
+	public void setSeveral(Collection several) {
+		this.several = several;
+	}
+	
+	/**
+	 * Returns the string.
+	 * @return String
+	 */
+	public String getString() {
+		return string;
+	}
+	
+	/**
+	 * Sets the string.
+	 * @param string The string to set
+	 */
+	public void setString(String string) {
+		this.string = string;
+	}
+	
+	/*public boolean equals(Object other) {
+		if ( !(other instanceof Single) ) return false;
+		return ( (Single) other ).id.equals(id) && ( (Single) other ).string.equals(string);
+	}
+	
+	public int hashCode() {
+		return id.hashCode();
+	}*/
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SingleSeveral.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SingleSeveral.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SingleSeveral.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping default-lazy="false">
+
+	<class name="org.hibernate.test.legacy.Single">
+		<composite-id>
+			<key-property name="id" length="32"/>
+			<key-property name="string" length="32" column="string_"/>
+		</composite-id>
+		<property name="prop"/>
+		<bag name="several" inverse="true" lazy="false" cascade="all"> <!--important: test for bidirectional with lazy="false" -->
+			<key>
+				<column name="single_id" not-null="true"/>
+				<column name="single_string" not-null="true"/>
+			</key>
+			<one-to-many class="org.hibernate.test.legacy.Several"/>
+		</bag>
+	</class>
+	
+	<class name="org.hibernate.test.legacy.Several">
+		<composite-id unsaved-value="any">
+			<key-property name="id" length="32"/>
+			<key-property name="string" length="32" column="string_"/>
+		</composite-id>
+		<many-to-one name="single">
+			<column name="single_id" length="32"/>
+			<column name="single_string" length="32"/>
+		</many-to-one>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Sortable.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Sortable.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Sortable.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+package org.hibernate.test.legacy;
+
+public class Sortable implements Comparable {
+	
+	private int id;
+	private String name;
+	
+	private Sortable() {}
+	Sortable(String name) {
+		this.name = name;
+	}
+	
+	public int compareTo(Object o) {
+		return name.compareTo( ( (Sortable) o).name );
+	}
+
+	public int getId() {
+		return id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setId(int i) {
+		id = i;
+	}
+
+	public void setName(String string) {
+		name = string;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/StatisticsTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/StatisticsTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/StatisticsTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+//$Id: StatisticsTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.legacy;
+
+import junit.framework.Test;
+
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.stat.Statistics;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class StatisticsTest extends LegacyTestCase {
+
+	public StatisticsTest(String x) {
+		super(x);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "legacy/ABC.hbm.xml", "legacy/ABCExtends.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( StatisticsTest.class );
+	}
+	
+	public void testSessionStats() throws Exception {
+		
+		SessionFactory sf = getSessions();
+		Statistics stats = sf.getStatistics();
+		boolean isStats = stats.isStatisticsEnabled();
+		stats.clear();
+		stats.setStatisticsEnabled(true);
+		Session s = sf.openSession();
+		assertEquals( 1, stats.getSessionOpenCount() );
+		s.close();
+		assertEquals( 1, stats.getSessionCloseCount() );
+		s = sf.openSession();
+		Transaction tx = s.beginTransaction();
+		A a = new A();
+		a.setName("mya");
+		s.save(a);
+		a.setName("b");
+		tx.commit();
+		s.close();
+		assertEquals( 1, stats.getFlushCount() );
+		s = sf.openSession();
+		tx = s.beginTransaction();
+		String hql = "from " + A.class.getName();
+		Query q = s.createQuery(hql);
+		q.list();
+		tx.commit();
+		s.close();
+		assertEquals(1, stats.getQueryExecutionCount() );
+		assertEquals(1, stats.getQueryStatistics(hql).getExecutionCount() );
+		
+		stats.setStatisticsEnabled(isStats);
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/StringComparator.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/StringComparator.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/StringComparator.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,12 @@
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+public class StringComparator implements Comparator, Serializable {
+
+	public int compare(Object o1, Object o2) {
+		return ( (String) o1 ).toLowerCase().compareTo( ( (String) o2 ).toLowerCase() );
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Stuff.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Stuff.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Stuff.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+	
+	<class name="org.hibernate.test.legacy.MoreStuff">
+		<composite-id>
+			<key-property name="intId"/>
+			<key-property name="stringId" length="32"/>
+		</composite-id>
+		<property name="name"/>
+		<bag name="stuffs" inverse="true" lazy="false" cascade="all">
+			<key>
+				<!--unfortunately have to specify not-null here because of limitation in schema export....-->
+				<column name="moreInt" not-null="true"/>
+				<column name="moreString" not-null="true" length="32"/>
+			</key>
+			<one-to-many class="org.hibernate.test.legacy.Stuff"/>
+		</bag>
+	</class>
+	
+    <class name="org.hibernate.test.legacy.Stuff">
+        <composite-id unsaved-value="any">
+            <key-property name="id"/>
+            <key-many-to-one name="foo" class="org.hibernate.test.legacy.Foo"/>
+            <key-many-to-one name="moreStuff" class="org.hibernate.test.legacy.MoreStuff">
+            	<column name="moreInt"/>
+				<column name="moreString" length="32"/>
+			</key-many-to-one>
+        </composite-id>
+        <property name="property"/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Stuff.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Stuff.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Stuff.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,93 @@
+//$Id: Stuff.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+import java.util.TimeZone;
+
+public class Stuff implements Serializable {
+	
+	public int hashCode() {
+		return new Long(id).hashCode();
+	}
+	
+	public boolean equals(Object other) {
+		if ( ! (other instanceof Stuff) ) return false;
+		Stuff otherStuff = (Stuff) other;
+		return otherStuff.getId()==id && otherStuff.getFoo().getKey().equals( foo.getKey() ) && otherStuff.getMoreStuff().equals(moreStuff);
+	}
+	
+	private long id;
+	private FooProxy foo;
+	private MoreStuff moreStuff;
+	private TimeZone property;
+	/**
+	 * Returns the foo.
+	 * @return Foo
+	 */
+	public FooProxy getFoo() {
+		return foo;
+	}
+	
+	/**
+	 * Returns the id.
+	 * @return long
+	 */
+	public long getId() {
+		return id;
+	}
+	
+	/**
+	 * Returns the property.
+	 * @return TimeZone
+	 */
+	public TimeZone getProperty() {
+		return property;
+	}
+	
+	/**
+	 * Sets the foo.
+	 * @param foo The foo to set
+	 */
+	public void setFoo(FooProxy foo) {
+		this.foo = foo;
+	}
+	
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	
+	/**
+	 * Sets the property.
+	 * @param property The property to set
+	 */
+	public void setProperty(TimeZone property) {
+		this.property = property;
+	}
+	
+	/**
+	 * Returns the moreStuff.
+	 * @return MoreStuff
+	 */
+	public MoreStuff getMoreStuff() {
+		return moreStuff;
+	}
+	
+	/**
+	 * Sets the moreStuff.
+	 * @param moreStuff The moreStuff to set
+	 */
+	public void setMoreStuff(MoreStuff moreStuff) {
+		this.moreStuff = moreStuff;
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SubComponent.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SubComponent.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SubComponent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+//$Id: SubComponent.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+/**
+ * Sub component
+ * 
+ * @author emmanuel
+ */
+public class SubComponent {
+    private String _subName;
+    
+    private String _subName1;
+    
+    /**
+     * @return
+     */
+    public String getSubName() {
+        return _subName;
+    }
+
+    /**
+     * @param string
+     */
+    public void setSubName(String string) {
+        _subName = string;
+    }
+
+    /**
+     * @return
+     */
+    public String getSubName1() {
+        return _subName1;
+    }
+
+    /**
+     * @param string
+     */
+    public void setSubName1(String string) {
+        _subName1 = string;
+    }
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SubDetail.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SubDetail.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SubDetail.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: SubDetail.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+public class SubDetail {
+	private String name;
+	private long id;
+	/**
+	 * Returns the id.
+	 * @return long
+	 */
+	public long getId() {
+		return id;
+	}
+	
+	/**
+	 * Returns the name.
+	 * @return String
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	
+	/**
+	 * Sets the name.
+	 * @param name The name to set
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SubMulti.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SubMulti.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/SubMulti.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,81 @@
+//$Id: SubMulti.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.List;
+
+public class SubMulti extends Multi {
+	private float amount;
+	private SubMulti parent;
+	private List children;
+	private List moreChildren;
+	/**
+	 * Returns the amount.
+	 * @return float
+	 */
+	public float getAmount() {
+		return amount;
+	}
+	
+	/**
+	 * Sets the amount.
+	 * @param amount The amount to set
+	 */
+	public void setAmount(float amount) {
+		this.amount = amount;
+	}
+	
+	/**
+	 * Returns the childen.
+	 * @return List
+	 */
+	public List getChildren() {
+		return children;
+	}
+	
+	/**
+	 * Returns the parent.
+	 * @return SubMulti
+	 */
+	public SubMulti getParent() {
+		return parent;
+	}
+	
+	/**
+	 * Sets the childen.
+	 * @param childen The childen to set
+	 */
+	public void setChildren(List children) {
+		this.children = children;
+	}
+	
+	/**
+	 * Sets the parent.
+	 * @param parent The parent to set
+	 */
+	public void setParent(SubMulti parent) {
+		this.parent = parent;
+	}
+	
+	/**
+	 * Returns the moreChildren.
+	 * @return List
+	 */
+	public List getMoreChildren() {
+		return moreChildren;
+	}
+
+	/**
+	 * Sets the moreChildren.
+	 * @param moreChildren The moreChildren to set
+	 */
+	public void setMoreChildren(List moreChildren) {
+		this.moreChildren = moreChildren;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Super.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Super.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Super.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+package org.hibernate.test.legacy;
+
+public class Super {
+
+	protected String name;
+
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Top.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Top.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Top.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,115 @@
+//$Id: Top.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.legacy;
+
+public class Top {
+	private long id;
+	private String name;
+	private String address;
+	private int count;
+	private java.util.Date date;
+	private Top other;
+	private Top top;
+	
+	public Top(int c) {
+		count=c;
+	}
+	public Top() {}
+	
+	public void init() {
+		name="Someone With Along Name";
+		address="1234 Some Street, Some City, Victoria, 3000, Austraya";
+		count=69;
+		date=new java.sql.Date(666);
+	}
+	/**
+	 * Gets the name
+	 * @return Returns a String
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * Sets the name
+	 * @param name The name to set
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+	/**
+	 * Gets the address
+	 * @return Returns a String
+	 */
+	public String getAddress() {
+		return address;
+	}
+	/**
+	 * Sets the address
+	 * @param address The address to set
+	 */
+	public void setAddress(String address) {
+		this.address = address;
+	}
+	
+	/**
+	 * Gets the count
+	 * @return Returns a int
+	 */
+	public int getCount() {
+		return count;
+	}
+	/**
+	 * Sets the count
+	 * @param count The count to set
+	 */
+	public void setCount(int count) {
+		this.count = count;
+	}
+	
+	/**
+	 * Gets the date
+	 * @return Returns a java.util.Date
+	 */
+	public java.util.Date getDate() {
+		return date;
+	}
+	/**
+	 * Sets the date
+	 * @param date The date to set
+	 */
+	public void setDate(java.util.Date date) {
+		this.date = date;
+	}
+	
+	/**
+	 * Returns the other.
+	 * @return Simple
+	 */
+	public Top getOther() {
+		return other;
+	}
+	
+	/**
+	 * Sets the other.
+	 * @param other The other to set
+	 */
+	public void setOther(Top other) {
+		this.other = other;
+	}
+	
+	public long getId() {
+		return id;
+	}
+
+	public void setId(long l) {
+		id = l;
+	}
+
+}
+
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Trivial.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Trivial.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Trivial.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+//$Id: Trivial.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+
+public class Trivial extends Foo {
+	
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/TrivialClass.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/TrivialClass.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/TrivialClass.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,6 @@
+//$Id: TrivialClass.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+public class TrivialClass extends Top {
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Up.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Up.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Up.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+//$Id: Up.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Up implements Serializable {
+
+	private String id1;
+	private long id2;
+
+	public String getId1() {
+		return id1;
+	}
+
+	public long getId2() {
+		return id2;
+	}
+
+	public void setId1(String string) {
+		id1 = string;
+	}
+
+	public void setId2(long l) {
+		id2 = l;
+	}
+	
+	public boolean equals(Object other) {
+		if ( !(other instanceof Up) ) return false;
+		Up that = (Up) other;
+		return this.id1.equals(that.id1) && this.id2==that.id2;
+	}
+	public int hashCode() {
+		return id1.hashCode();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/UpDown.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/UpDown.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/UpDown.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+	
+<hibernate-mapping default-lazy="false">
+	<class name="org.hibernate.test.legacy.Up" discriminator-value="null">
+		<composite-id>
+			<key-property name="id1"/>
+			<key-property name="id2"/>
+		</composite-id>
+		<discriminator column="value_" type="long" not-null="false" insert="false"/>
+
+		<subclass name="org.hibernate.test.legacy.Down" discriminator-value="not null">
+			<property name="value" column="value_" type="long"/>
+		</subclass>
+	</class>
+</hibernate-mapping>
+	
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Vetoer.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Vetoer.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Vetoer.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+    <class name="org.hibernate.test.legacy.Vetoer">
+        <id type="string" column="id_" length="32">
+            <generator class="uuid.hex"/>
+        </id>
+        <property name="name"/>
+        <property name="strings"/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Vetoer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Vetoer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Vetoer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,61 @@
+//$Id: Vetoer.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.io.Serializable;
+
+import org.hibernate.CallbackException;
+import org.hibernate.Session;
+import org.hibernate.classic.Lifecycle;
+
+public class Vetoer implements Lifecycle {
+
+	boolean onSaveCalled;
+	boolean onUpdateCalled;
+	boolean onDeleteCalled;
+
+	private String name;
+	private String[] strings;
+
+	public boolean onSave(Session s) throws CallbackException {
+		boolean result = !onSaveCalled;
+		onSaveCalled = true;
+		return result;
+	}
+
+	public boolean onUpdate(Session s) throws CallbackException {
+		boolean result = !onUpdateCalled;
+		onUpdateCalled = true;
+		return result;
+	}
+
+	public boolean onDelete(Session s) throws CallbackException {
+		boolean result = !onDeleteCalled;
+		onDeleteCalled = true;
+		return result;
+	}
+
+	public void onLoad(Session s, Serializable id) {}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String[] getStrings() {
+		return strings;
+	}
+
+	public void setStrings(String[] strings) {
+		this.strings = strings;
+	}
+
+}
+
+
+
+
+
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/W.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/W.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/W.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+package org.hibernate.test.legacy;
+
+import java.util.Set;
+
+public class W {
+	
+	private long id;
+	private Set zeds;
+	
+	/**
+	 * 
+	 */
+	public W() {
+	}
+
+	/**
+	 * @return
+	 */
+	public long getId() {
+		return id;
+	}
+
+	/**
+	 * @return
+	 */
+	public Set getZeds() {
+		return zeds;
+	}
+
+	/**
+	 * @param l
+	 */
+	public void setId(long l) {
+		id = l;
+	}
+
+	/**
+	 * @param set
+	 */
+	public void setZeds(Set set) {
+		zeds = set;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/WZ.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/WZ.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/WZ.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+	<class name="org.hibernate.test.legacy.Z">
+		<id name="id" unsaved-value="0" column="zid">
+			<generator class="hilo"/>
+		</id>
+		<many-to-one name="w" 
+			cascade="save-update"
+			class="org.hibernate.test.legacy.W" 
+			insert="true" 
+			update="false" 
+			not-null="true"/>
+	</class>
+
+	<class name="org.hibernate.test.legacy.W" 
+		discriminator-value="0" 
+		proxy="org.hibernate.test.legacy.W">
+		
+		<id name="id" unsaved-value="0" column="wid">
+			<generator class="hilo"/>
+		</id>
+		<!--<set name="zeds" lazy="true">
+			<key column="w"/>
+			<one-to-many class="org.hibernate.test.legacy.Z"/>
+		</set>-->
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Wicked.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Wicked.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Wicked.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- Mapping document mainly used for testing non-reflective Binder + meta inheritance -->
+<hibernate-mapping default-lazy="false">
+  <meta attribute="global">global value</meta>
+  <meta attribute="globalnoinherit" inherit="false">only visible at top level</meta>
+  <meta attribute="globalmutated">top level</meta>
+  
+    <class name="org.hibernate.test.legacy.Wicked"
+           table="WICKED"
+           schema="HR">
+           <meta attribute="implements">java.lang.Observer</meta>
+           <meta attribute="implements">java.lang.Observer</meta>           
+           <meta attribute="implements" inherit="false">org.foo.BogusVisitor</meta>                      
+           <meta attribute="extends">AuditInfo</meta>
+		   <meta attribute="globalmutated">wicked level</meta>
+        <id name="id"
+            type="long"
+            column="EMPLOYEE_ID">
+            <generator class="assigned"/>
+        </id>
+        <version name="versionProp"       type="long"/>
+        <property name="stringProp"       type="string"/>
+        <property name="doubleProp"       type="double"/>
+	    <property name="objectDoubleProp" type="java.lang.Double"/>
+        <property name="booleanProp"       type="boolean"/>
+	    <property name="objectBooleanProp" type="java.lang.Boolean"/>
+  	    <property name="binaryProp"       type="binary"/>
+        <many-to-one name="objectManyToOne"  class="org.hibernate.test.legacy.Employee" column="MANAGER_ID"/>
+		<component name="component" class="net.sf.hibern8ide.test.MonetaryAmount">
+		  <meta attribute="componentonly" inherit="true"/>
+		  <meta attribute="implements">AnotherInterface</meta>
+		  <meta attribute="allcomponent"/>
+ 		  <meta attribute="globalmutated">monetaryamount level</meta>
+			<property name="x" type="string">
+	  		    <meta attribute="globalmutated">monetaryamount x level</meta>
+  		    </property>
+		</component>
+
+		<set name="sortedEmployee" sort="org.hibernate.test.legacy.NonExistingComparator">
+  		     <meta attribute="globalmutated">sortedemployee level</meta>
+			 <key column="attrb_id"/> 
+    	     <many-to-many class="org.hibernate.test.legacy.Employee" column="id"/>
+		</set>
+
+        <bag name="anotherSet">
+			 <key column="attrb2_id"/> 			 
+			 <composite-element class="org.hibernate.test.legacy.Employee">
+  		     <meta attribute="globalmutated">monetaryamount anotherSet composite level</meta>
+  		      <property name="emp" type="string">
+    		      <meta attribute="globalmutated">monetaryamount anotherSet composite property emp level</meta>
+  		      </property>
+  		      <many-to-one name="empinone" class="org.hibernate.test.legacy.Employee">
+  		          <meta attribute="globalmutated">monetaryamount anotherSet composite property empinone level</meta>
+  		      </many-to-one>
+			 </composite-element>
+        </bag>	
+
+   </class>
+   
+   <class name="org.hibernate.test.legacy.Employee">
+        <composite-id class="X">
+            <key-property name="comp" type="string"/>
+        </composite-id>
+		
+   </class>
+</hibernate-mapping>
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/X.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/X.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/X.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,79 @@
+//$Id: X.java 4599 2004-09-26 05:18:27Z oneovthafew $
+package org.hibernate.test.legacy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class X {
+
+	private long id;
+	private Y y;
+	private List xxs = new ArrayList();
+
+	/**
+	 * Returns the id.
+	 * @return long
+	 */
+	public long getId() {
+		return id;
+	}
+
+	/**
+	 * Returns the y.
+	 * @return Y
+	 */
+	public Y getY() {
+		return y;
+	}
+
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+
+	/**
+	 * Sets the y.
+	 * @param y The y to set
+	 */
+	public void setY(Y y) {
+		this.y = y;
+	}
+	
+	public List getXxs() {
+		return xxs;
+	}
+
+	public void setXxs(List xxs) {
+		this.xxs = xxs;
+	}
+
+	public static class XX {
+		private Long id;
+		private X x;
+		private XX() {}
+		public XX(X x) {
+			this.x = x;
+		}
+		public Long getId() {
+			return id;
+		}
+
+		public void setId(Long id) {
+			this.id = id;
+		}
+
+		public X getX() {
+			return x;
+		}
+
+		public void setX(X x) {
+			this.x = x;
+		}
+
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/XY.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/XY.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/XY.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+	<class name="org.hibernate.test.legacy.X">
+		<id name="id" unsaved-value="0" column="xid">
+			<generator class="foreign">
+				<param name="property">y</param>
+			</generator>
+		</id>
+		<one-to-one name="y" constrained="true" cascade="all"/>
+		<bag name="xxs" inverse="true" cascade="all">
+			<key column="x"/>
+			<one-to-many class="org.hibernate.test.legacy.X$XX"/>
+		</bag>
+	</class>
+	<class name="org.hibernate.test.legacy.Y">
+		<id name="id" column="yid">
+			<generator class="hilo"/>
+		</id>
+		<property name="x"/>
+		<one-to-one name="theX" cascade="save-update"/>
+	</class>
+	<class name="org.hibernate.test.legacy.X$XX" table="xxx">
+		<id name="id">
+			<generator class="hilo"/>
+		</id>
+		<many-to-one name="x" not-null="true"/>
+	</class>
+</hibernate-mapping>
+	
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Y.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Y.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Y.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+package org.hibernate.test.legacy;
+
+
+public class Y {
+
+	private Long id;
+	private String x;
+	private X theX;
+	/**
+	 * Returns the id.
+	 * @return Long
+	 */
+	public Long getId() {
+		return id;
+	}
+
+	/**
+	 * Returns the x.
+	 * @return String
+	 */
+	public String getX() {
+		return x;
+	}
+
+	/**
+	 * Sets the id.
+	 * @param id The id to set
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	/**
+	 * Sets the x.
+	 * @param x The x to set
+	 */
+	public void setX(String x) {
+		this.x = x;
+	}
+
+	/**
+	 * @return
+	 */
+	public X getTheX() {
+		return theX;
+	}
+
+	/**
+	 * @param x
+	 */
+	public void setTheX(X x) {
+		theX = x;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Z.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Z.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/legacy/Z.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+package org.hibernate.test.legacy;
+
+public class Z {
+
+	private long id;
+	private W w;
+
+	/**
+	 * 
+	 */
+	public Z() {
+	}
+
+
+	/**
+	 * @return
+	 */
+	public long getId() {
+		return id;
+	}
+
+	/**
+	 * @return
+	 */
+	public W getW() {
+		return w;
+	}
+
+	/**
+	 * @param l
+	 */
+	public void setId(long l) {
+		id = l;
+	}
+
+	/**
+	 * @param w
+	 */
+	public void setW(W w) {
+		this.w = w;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/BlobTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/BlobTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/BlobTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,200 @@
+package org.hibernate.test.lob;
+
+import java.sql.Blob;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.Session;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class BlobTest extends DatabaseSpecificFunctionalTestCase {
+	private static final int BLOB_SIZE = 10000;
+
+	public BlobTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "lob/LobMappings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( BlobTest.class );
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		if ( ! dialect.supportsExpectedLobUsagePattern() ) {
+			reportSkip( "database/driver does not support expected LOB usage pattern", "LOB support" );
+			return false;
+		}
+		return true;
+	}
+
+	public void testBoundedMaterializedBlobAccess() {
+		byte[] original = buildRecursively( BLOB_SIZE, true );
+		byte[] changed = buildRecursively( BLOB_SIZE, false );
+
+		Session s = openSession();
+		s.beginTransaction();
+		LobHolder entity = new LobHolder();
+		entity.setMaterializedBlob( original );
+		s.save( entity );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+		assertEquals( BLOB_SIZE, entity.getMaterializedBlob().length );
+		assertEquals( original, entity.getMaterializedBlob() );
+		entity.setMaterializedBlob( changed );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+		assertEquals( BLOB_SIZE, entity.getMaterializedBlob().length );
+		assertEquals( changed, entity.getMaterializedBlob() );
+		s.delete( entity );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testBoundedBlobLocatorAccess() throws Throwable {
+		byte[] original = buildRecursively( BLOB_SIZE, true );
+		byte[] changed = buildRecursively( BLOB_SIZE, false );
+
+		Session s = openSession();
+		s.beginTransaction();
+		LobHolder entity = new LobHolder();
+		entity.setBlobLocator( Hibernate.createBlob( original ) );
+		s.save( entity );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+		assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+		assertEquals( original, extractData( entity.getBlobLocator() ) );
+		s.getTransaction().commit();
+		s.close();
+
+		// test mutation via setting the new clob data...
+		if ( supportsLobValueChangePropogation() ) {
+			s = openSession();
+			s.beginTransaction();
+			entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+			entity.getBlobLocator().truncate( 1 );
+			entity.getBlobLocator().setBytes( 1, changed );
+			s.getTransaction().commit();
+			s.close();
+
+			s = openSession();
+			s.beginTransaction();
+			entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+			assertNotNull( entity.getBlobLocator() );
+			assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+			assertEquals( changed, extractData( entity.getBlobLocator() ) );
+			entity.getBlobLocator().truncate( 1 );
+			entity.getBlobLocator().setBytes( 1, original );
+			s.getTransaction().commit();
+			s.close();
+		}
+
+		// test mutation via supplying a new clob locator instance...
+		s = openSession();
+		s.beginTransaction();
+		entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+		assertNotNull( entity.getBlobLocator() );
+		assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+		assertEquals( original, extractData( entity.getBlobLocator() ) );
+		entity.setBlobLocator( Hibernate.createBlob( changed ) );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+		assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+		assertEquals( changed, extractData( entity.getBlobLocator() ) );
+		s.delete( entity );
+		s.getTransaction().commit();
+		s.close();
+
+	}
+
+	public void testUnboundedBlobLocatorAccess() throws Throwable {
+		if ( ! supportsUnboundedLobLocatorMaterialization() ) {
+			return;
+		}
+
+		// Note: unbounded mutation of the underlying lob data is completely
+		// unsupported; most databases would not allow such a construct anyway.
+		// Thus here we are only testing materialization...
+
+		byte[] original = buildRecursively( BLOB_SIZE, true );
+
+		Session s = openSession();
+		s.beginTransaction();
+		LobHolder entity = new LobHolder();
+		entity.setBlobLocator( Hibernate.createBlob( original ) );
+		s.save( entity );
+		s.getTransaction().commit();
+		s.close();
+
+		// load the entity with the clob locator, and close the session/transaction;
+		// at that point it is unbounded...
+		s = openSession();
+		s.beginTransaction();
+		entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+		s.getTransaction().commit();
+		s.close();
+
+		assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+		assertEquals( original, extractData( entity.getBlobLocator() ) );
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( entity );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	private byte[] extractData(Blob blob) throws Throwable {
+		return blob.getBytes( 1, ( int ) blob.length() );
+	}
+
+
+	private byte[] buildRecursively(int size, boolean on) {
+		byte[] data = new byte[size];
+		data[0] = mask( on );
+		for ( int i = 0; i < size; i++ ) {
+			data[i] = mask( on );
+			on = !on;
+		}
+		return data;
+	}
+
+	private byte mask(boolean on) {
+		return on ? ( byte ) 1 : ( byte ) 0;
+	}
+
+	public static void assertEquals(byte[] val1, byte[] val2) {
+		if ( !ArrayHelper.isEquals( val1, val2 ) ) {
+			throw new AssertionFailedError( "byte arrays did not match" );
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/ClobTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/ClobTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/ClobTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,196 @@
+package org.hibernate.test.lob;
+
+import java.sql.Clob;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.Session;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.H2Dialect;
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Test various access scenarios for eager and lazy materialization
+ * of CLOB data, as well as bounded and unbounded materialization
+ * and mutation.
+ *
+ * @author Steve Ebersole
+ */
+public class ClobTest extends DatabaseSpecificFunctionalTestCase {
+	private static final int CLOB_SIZE = 10000;
+
+	public ClobTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "lob/LobMappings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ClobTest.class );
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		if ( ! dialect.supportsExpectedLobUsagePattern() ) {
+			reportSkip( "database/driver does not support expected LOB usage pattern", "LOB support" );
+			return false;
+		}
+		return true;
+	}
+
+	public void testBoundedMaterializedClobAccess() {
+		String original = buildRecursively( CLOB_SIZE, 'x' );
+		String changed = buildRecursively( CLOB_SIZE, 'y' );
+
+		Session s = openSession();
+		s.beginTransaction();
+		LobHolder entity = new LobHolder();
+		entity.setMaterializedClob( original );
+		s.save( entity );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+		assertEquals( CLOB_SIZE, entity.getMaterializedClob().length() );
+		assertEquals( original, entity.getMaterializedClob() );
+		entity.setMaterializedClob( changed );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+		assertEquals( CLOB_SIZE, entity.getMaterializedClob().length() );
+		assertEquals( changed, entity.getMaterializedClob() );
+		s.delete( entity );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testBoundedClobLocatorAccess() throws Throwable {
+		String original = buildRecursively( CLOB_SIZE, 'x' );
+		String changed = buildRecursively( CLOB_SIZE, 'y' );
+
+		Session s = openSession();
+		s.beginTransaction();
+		LobHolder entity = new LobHolder();
+		entity.setClobLocator( Hibernate.createClob( original ) );
+		s.save( entity );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+		assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+		assertEquals( original, extractData( entity.getClobLocator() ) );
+		s.getTransaction().commit();
+		s.close();
+
+		// test mutation via setting the new clob data...
+		if ( supportsLobValueChangePropogation() ) {
+			s = openSession();
+			s.beginTransaction();
+			entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+			entity.getClobLocator().truncate( 1 );
+			entity.getClobLocator().setString( 1, changed );
+			s.getTransaction().commit();
+			s.close();
+
+			s = openSession();
+			s.beginTransaction();
+			entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+			assertNotNull( entity.getClobLocator() );
+			assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+			assertEquals( changed, extractData( entity.getClobLocator() ) );
+			entity.getClobLocator().truncate( 1 );
+			entity.getClobLocator().setString( 1, original );
+			s.getTransaction().commit();
+			s.close();
+		}
+
+		// test mutation via supplying a new clob locator instance...
+		s = openSession();
+		s.beginTransaction();
+		entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+		assertNotNull( entity.getClobLocator() );
+		assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+		assertEquals( original, extractData( entity.getClobLocator() ) );
+		entity.setClobLocator( Hibernate.createClob( changed ) );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+		assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+		assertEquals( changed, extractData( entity.getClobLocator() ) );
+		s.delete( entity );
+		s.getTransaction().commit();
+		s.close();
+
+	}
+
+	public void testUnboundedClobLocatorAccess() throws Throwable {
+		if ( ! supportsUnboundedLobLocatorMaterialization() ) {
+			return;
+		}
+
+		// Note: unbounded mutation of the underlying lob data is completely
+		// unsupported; most databases would not allow such a construct anyway.
+		// Thus here we are only testing materialization...
+
+		String original = buildRecursively( CLOB_SIZE, 'x' );
+
+		Session s = openSession();
+		s.beginTransaction();
+		LobHolder entity = new LobHolder();
+		entity.setClobLocator( Hibernate.createClob( original ) );
+		s.save( entity );
+		s.getTransaction().commit();
+		s.close();
+
+		// load the entity with the clob locator, and close the session/transaction;
+		// at that point it is unbounded...
+		s = openSession();
+		s.beginTransaction();
+		entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+		s.getTransaction().commit();
+		s.close();
+
+		assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+		assertEquals( original, extractData( entity.getClobLocator() ) );
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( entity );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	private String extractData(Clob clob) throws Throwable {
+		if ( getDialect() instanceof H2Dialect ) {
+			return clob.getSubString( 1, ( int ) clob.length() );
+		}
+		else {
+			char[] data = new char[ (int) clob.length() ];
+			clob.getCharacterStream().read( data );
+			return new String( data );
+		}
+	}
+
+
+	private String buildRecursively(int size, char baseChar) {
+		StringBuffer buff = new StringBuffer();
+		for( int i = 0; i < size; i++ ) {
+			buff.append( baseChar );
+		}
+		return buff.toString();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/LobHolder.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/LobHolder.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/LobHolder.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,90 @@
+package org.hibernate.test.lob;
+
+import java.io.Serializable;
+import java.sql.Clob;
+import java.sql.Blob;
+
+/**
+ * An entity containing all kinds of good LOB-type data...
+ * <p/>
+ * {@link #serialData} is used to hold general serializable data which is
+ * mapped via the {@link org.hibernate.type.SerializableType}.
+ * <p/>
+ * {@link #materializedClob} is used to hold CLOB data that is materialized
+ * into a String immediately; it is mapped via the
+ * {@link org.hibernate.type.TextType}.
+ * <p/>
+ * {@link #clobLocator} is used to hold CLOB data that is materialized lazily
+ * via a JDBC CLOB locator; it is mapped via the
+ * {@link org.hibernate.type.ClobType}
+ * <p/>
+ * {@link #materializedBlob} is used to hold BLOB data that is materialized
+ * into a byte array immediately; it is mapped via the
+ * {@link org.hibernate.test.lob.MaterializedBlobType}.
+ * <p/>
+ * {@link #blobLocator} is used to hold BLOB data that is materialized lazily
+ * via a JDBC BLOB locator; it is mapped via the
+ * {@link org.hibernate.type.BlobType}
+ * 
+ *
+ * @author Steve Ebersole
+ */
+public class LobHolder {
+	private Long id;
+
+	private Serializable serialData;
+
+	private String materializedClob;
+	private Clob clobLocator;
+
+	private byte[] materializedBlob;
+	private Blob blobLocator;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Serializable getSerialData() {
+		return serialData;
+	}
+
+	public void setSerialData(Serializable serialData) {
+		this.serialData = serialData;
+	}
+
+	public String getMaterializedClob() {
+		return materializedClob;
+	}
+
+	public void setMaterializedClob(String materializedClob) {
+		this.materializedClob = materializedClob;
+	}
+
+	public Clob getClobLocator() {
+		return clobLocator;
+	}
+
+	public void setClobLocator(Clob clobLocator) {
+		this.clobLocator = clobLocator;
+	}
+
+	public byte[] getMaterializedBlob() {
+		return materializedBlob;
+	}
+
+	public void setMaterializedBlob(byte[] materializedBlob) {
+		this.materializedBlob = materializedBlob;
+	}
+
+	public Blob getBlobLocator() {
+		return blobLocator;
+	}
+
+	public void setBlobLocator(Blob blobLocator) {
+		this.blobLocator = blobLocator;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/LobMappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/LobMappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/LobMappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.lob">
+
+	<class name="LobHolder" table="LOB_ENTITY">
+		<id name="id" type="long" column="ID">
+			<generator class="increment"/>
+		</id>
+
+		<property name="serialData" column="SER_DATA" type="serializable"/>
+
+		<property name="materializedClob" column="MAT_CLOB_DATA" type="text" length="15000"/>
+        <property name="clobLocator" column="CLOB_DATA" type="clob" length="15000"/>
+
+		<property name="materializedBlob" column="MAT_BLOB_DATA" type="org.hibernate.test.lob.MaterializedBlobType" length="15000"/>
+        <property name="blobLocator" column="BLOB_DATA" type="blob" length="15000"/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/LobSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/LobSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/LobSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+package org.hibernate.test.lob;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class LobSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "LOB handling tests" );
+		suite.addTest( SerializableTypeTest.suite() );
+		suite.addTest( BlobTest.suite() );
+		suite.addTest( ClobTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/MaterializedBlobType.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/MaterializedBlobType.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/MaterializedBlobType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+package org.hibernate.test.lob;
+
+import java.sql.Types;
+
+import org.hibernate.type.AbstractBynaryType;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class MaterializedBlobType extends AbstractBynaryType {
+
+	public int sqlType() {
+		return Types.BLOB;
+	}
+
+	public String getName() {
+		return "materialized-blob";
+	}
+
+	public Class getReturnedClass() {
+		return byte[].class;
+	}
+
+	protected Object toExternalFormat(byte[] bytes) {
+		return bytes;
+	}
+
+	protected byte[] toInternalFormat(Object bytes) {
+		return ( byte[] ) bytes;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/SerializableData.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/SerializableData.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/SerializableData.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+// $Id: SerializableData.java 4704 2004-11-04 21:59:22Z steveebersole $
+package org.hibernate.test.lob;
+
+import java.io.Serializable;
+
+/**
+ * Implementation of SerializableData.
+ *
+ * @author Steve
+ */
+public class SerializableData implements Serializable
+{
+   private String payload;
+
+   public SerializableData(String payload)
+   {
+      this.payload = payload;
+   }
+
+   public String getPayload()
+   {
+      return payload;
+   }
+
+   public void setPayload(String payload)
+   {
+      this.payload = payload;
+   }
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/SerializableTypeTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/SerializableTypeTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/lob/SerializableTypeTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+// $Id: SerializableTypeTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.lob;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Tests of {@link org.hibernate.type.SerializableType}
+ * 
+ * @author Steve Ebersole
+ */
+public class SerializableTypeTest extends FunctionalTestCase {
+
+	public SerializableTypeTest(String testName) {
+		super( testName );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "lob/LobMappings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SerializableTypeTest.class );
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public void testNewSerializableType() {
+		final String payloadText = "Initial payload";
+
+		Session s = openSession();
+		s.beginTransaction();
+		LobHolder holder = new LobHolder();
+		holder.setSerialData( new SerializableData( payloadText ) );
+		s.save( holder );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		holder = ( LobHolder ) s.get( LobHolder.class, holder.getId() );
+		SerializableData serialData = ( SerializableData ) holder.getSerialData();
+		assertEquals( payloadText, serialData.getPayload() );
+		s.delete( holder );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/Group.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/Group.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/Group.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,56 @@
+//$Id: Group.java 7085 2005-06-08 17:59:47Z oneovthafew $
+package org.hibernate.test.manytomany;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+public class Group implements Serializable {
+
+	private String org;
+	private String name;
+	private String description;
+
+	private Set users = new HashSet();
+	
+	public Group(String name, String org) {
+		this.org = org;
+		this.name = name;
+	}
+
+	public Group() {
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getOrg() {
+		return org;
+	}
+
+	public void setOrg(String org) {
+		this.org = org;
+	}
+
+	public Set getUsers() {
+		return users;
+	}
+
+	public void setUsers(Set users) {
+		this.users = users;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/Group.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ManyToManyTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ManyToManyTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ManyToManyTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,127 @@
+//$Id: ManyToManyTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.manytomany;
+
+import junit.framework.Test;
+
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class ManyToManyTest extends FunctionalTestCase {
+	
+	public ManyToManyTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "manytomany/UserGroup.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "false");
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ManyToManyTest.class );
+	}
+	
+	public void testManyToManyWithFormula() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User gavin = new User("gavin", "jboss");
+		Group seam = new Group("seam", "jboss");
+		Group hb = new Group("hibernate", "jboss");
+		gavin.getGroups().add(seam);
+		gavin.getGroups().add(hb);
+		seam.getUsers().add(gavin);
+		hb.getUsers().add(gavin);
+		s.persist(gavin);
+		s.persist(seam);
+		s.persist(hb);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		gavin = (User) s.get(User.class, gavin);
+		assertFalse( Hibernate.isInitialized( gavin.getGroups() ) );
+		assertEquals( 2, gavin.getGroups().size() );
+		hb = (Group) s.get(Group.class, hb);
+		assertFalse( Hibernate.isInitialized( hb.getUsers() ) );
+		assertEquals( 1, hb.getUsers().size() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		gavin = (User) s.createCriteria(User.class)
+			.setFetchMode("groups", FetchMode.JOIN)
+			.uniqueResult();
+		assertTrue( Hibernate.isInitialized( gavin.getGroups() ) );
+		assertEquals( 2, gavin.getGroups().size() );
+		Group group = (Group) gavin.getGroups().iterator().next();
+		assertFalse( Hibernate.isInitialized( group.getUsers() ) );
+		assertEquals( 1, group.getUsers().size() );
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		gavin = (User) s.createCriteria(User.class)
+			.setFetchMode("groups", FetchMode.JOIN)
+			.setFetchMode("groups.users", FetchMode.JOIN)
+			.uniqueResult();
+		assertTrue( Hibernate.isInitialized( gavin.getGroups() ) );
+		assertEquals( 2, gavin.getGroups().size() );
+		group = (Group) gavin.getGroups().iterator().next();
+		assertTrue( Hibernate.isInitialized( group.getUsers() ) );
+		assertEquals( 1, group.getUsers().size() );
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		gavin = (User) s.createQuery("from User u join fetch u.groups g join fetch g.users").uniqueResult();
+		assertTrue( Hibernate.isInitialized( gavin.getGroups() ) );
+		assertEquals( 2, gavin.getGroups().size() );
+		group = (Group) gavin.getGroups().iterator().next();
+		assertTrue( Hibernate.isInitialized( group.getUsers() ) );
+		assertEquals( 1, group.getUsers().size() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		gavin = (User) s.get(User.class, gavin);
+		hb = (Group) s.get(Group.class, hb);
+		gavin.getGroups().remove(hb);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		gavin = (User) s.get(User.class, gavin);
+		assertEquals( gavin.getGroups().size(), 1 );
+		hb = (Group) s.get(Group.class, hb);
+		assertEquals( hb.getUsers().size(), 0 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete(gavin);
+		s.flush();
+		s.createQuery("delete from Group").executeUpdate();
+		t.commit();
+		s.close();
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ManyToManyTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+//$Id: User.java 7085 2005-06-08 17:59:47Z oneovthafew $
+package org.hibernate.test.manytomany;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+public class User implements Serializable {
+	
+	private String org;
+	private String name;
+	private Set groups = new HashSet();
+
+	public User(String name, String org) {
+		this.org = org;
+		this.name = name;
+	}
+
+	public User() {
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getOrg() {
+		return org;
+	}
+
+	public void setOrg(String org) {
+		this.org = org;
+	}
+
+	public Set getGroups() {
+		return groups;
+	}
+
+	public void setGroups(Set groups) {
+		this.groups = groups;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/User.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/UserGroup.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/UserGroup.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/UserGroup.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates how to map a many-to-many
+  association with a shared attribute in the primary keys
+  of the associated entities.
+     
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.manytomany">
+	
+	<class name="User" table="`User`">
+		<composite-id>
+			<key-property name="name"/>
+			<key-property name="org"/>
+		</composite-id>
+		<set name="groups" table="UserGroup">
+			<key>
+				<column name="userName"/>
+				<column name="org"/>
+			</key>
+			<many-to-many class="Group">
+				<column name="groupName"/>
+				<formula>org</formula>
+			</many-to-many>
+		</set>
+	</class>
+	
+	<class name="Group" table="`Group`">
+		<composite-id>
+			<key-property name="name"/>
+			<key-property name="org"/>
+		</composite-id>
+		<property name="description"/>
+		<set name="users" table="UserGroup" inverse="true">
+			<key>
+				<column name="groupName"/>
+				<column name="org"/>
+			</key>
+			<many-to-many class="User">
+				<column name="userName"/>
+				<formula>org</formula>
+			</many-to-many>
+		</set>
+	</class>
+	
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/UserGroup.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/Group.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/Group.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/Group.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+package org.hibernate.test.manytomany.ordered;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.ArrayList;
+
+public class Group implements Serializable {
+
+	private Long id;
+	private String org;
+	private String name;
+	private String description;
+
+	private List users = new ArrayList();
+
+	public Group() {
+	}
+
+	public Group(String name, String org) {
+		this.org = org;
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getOrg() {
+		return org;
+	}
+
+	public void setOrg(String org) {
+		this.org = org;
+	}
+
+	public List getUsers() {
+		return users;
+	}
+
+	public void setUsers(List users) {
+		this.users = users;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public void addUser(User user) {
+		if ( user.getGroups().add( this ) ) {
+			getUsers().add( user );
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/OrderedManyToManyTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/OrderedManyToManyTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/OrderedManyToManyTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,139 @@
+package org.hibernate.test.manytomany.ordered;
+
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Criteria;
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class OrderedManyToManyTest extends FunctionalTestCase {
+
+	public OrderedManyToManyTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "manytomany/ordered/UserGroup.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false");
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( OrderedManyToManyTest.class );
+	}
+
+	public void testManyToManyOrdering() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User gavin = new User( "gavin", "jboss" );
+		User steve = new User( "steve", "jboss" );
+		User max = new User( "max", "jboss" );
+		User emmanuel = new User( "emmanuel", "jboss" );
+		s.persist( gavin );
+		s.persist( steve );
+		s.persist( max );
+		s.persist( emmanuel );
+		Group hibernate = new Group( "hibernate", "jboss" );
+		hibernate.addUser( gavin );
+		hibernate.addUser( steve );
+		hibernate.addUser( max );
+		hibernate.addUser( emmanuel );
+		s.persist( hibernate );
+		t.commit();
+		s.close();
+
+		// delayed collection load...
+		s = openSession();
+		t = s.beginTransaction();
+		hibernate = ( Group ) s.get( Group.class, hibernate.getId() );
+		assertFalse( Hibernate.isInitialized( hibernate.getUsers() ) );
+		assertEquals( 4, hibernate.getUsers().size() );
+		assertOrdering( hibernate.getUsers() );
+		t.commit();
+		s.close();
+
+		// HQL (non eager)
+		s = openSession();
+		t = s.beginTransaction();
+		hibernate = ( Group ) s.createQuery( "from Group" ).uniqueResult();
+		assertFalse( Hibernate.isInitialized( hibernate.getUsers() ) );
+		assertEquals( 4, hibernate.getUsers().size() );
+		assertOrdering( hibernate.getUsers() );
+		t.commit();
+		s.close();
+
+		// HQL (eager)
+		s = openSession();
+		t = s.beginTransaction();
+		hibernate = ( Group ) s.createQuery( "from Group g inner join fetch g.users" ).uniqueResult();
+		assertTrue( Hibernate.isInitialized( hibernate.getUsers() ) );
+		assertEquals( 4, hibernate.getUsers().size() );
+		assertOrdering( hibernate.getUsers() );
+		t.commit();
+		s.close();
+
+		// criteria load (forced eager fetch)
+		s = openSession();
+		t = s.beginTransaction();
+		Criteria criteria = s.createCriteria( Group.class );
+		criteria.setFetchMode( "users", FetchMode.JOIN );
+		hibernate = ( Group ) criteria.uniqueResult();
+		assertTrue( Hibernate.isInitialized( hibernate.getUsers() ) );
+		assertEquals( 4, hibernate.getUsers().size() );
+		assertOrdering( hibernate.getUsers() );
+		t.commit();
+		s.close();
+
+		// criteria load (forced non eager fetch)
+		s = openSession();
+		t = s.beginTransaction();
+		criteria = s.createCriteria( Group.class );
+		criteria.setFetchMode( "users", FetchMode.SELECT );
+		hibernate = ( Group ) criteria.uniqueResult();
+		assertFalse( Hibernate.isInitialized( hibernate.getUsers() ) );
+		assertEquals( 4, hibernate.getUsers().size() );
+		assertOrdering( hibernate.getUsers() );
+		t.commit();
+		s.close();
+
+		// clean up
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( gavin );
+		s.delete( steve );
+		s.delete( max );
+		s.delete( emmanuel );
+		s.delete( hibernate );
+		t.commit();
+		s.close();
+	}
+
+	private void assertOrdering(List users) {
+		User user = extractUser( users, 0 );
+		assertTrue( "many-to-many ordering not applied", user.getName().equals( "emmanuel" ) );
+		user = extractUser( users, 1 );
+		assertTrue( "many-to-many ordering not applied", user.getName().equals( "gavin" ) );
+		user = extractUser( users, 2 );
+		assertTrue( "many-to-many ordering not applied", user.getName().equals( "max" ) );
+		user = extractUser( users, 3 );
+		assertTrue( "many-to-many ordering not applied", user.getName().equals( "steve" ) );
+	}
+
+	private User extractUser(List users, int position) {
+		return ( User ) users.get( position );
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,54 @@
+package org.hibernate.test.manytomany.ordered;
+
+import java.io.Serializable;
+import java.util.Set;
+import java.util.HashSet;
+
+public class User implements Serializable {
+
+	private Long id;
+	private String org;
+	private String name;
+	private Set groups = new HashSet();
+
+	public User() {
+	}
+
+	public User(String name, String org) {
+		this.org = org;
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getOrg() {
+		return org;
+	}
+
+	public void setOrg(String org) {
+		this.org = org;
+	}
+
+	public Set getGroups() {
+		return groups;
+	}
+
+	public void setGroups(Set groups) {
+		this.groups = groups;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/UserGroup.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/UserGroup.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/manytomany/ordered/UserGroup.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates how to map a many-to-many
+  association with a shared attribute in the primary keys
+  of the associated entities.
+     
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.manytomany.ordered">
+
+
+	<class name="User" table="`User`">
+        <id name="id" column="ID" type="long">
+            <generator class="native"/>
+        </id>
+        <property name="name" column="NAME"/>
+        <property name="org" column="ORG"/>
+		<set name="groups" table="UserGroup">
+			<key column="USER_ID"/>
+			<many-to-many column="GROUP_ID" class="Group"/>
+		</set>
+	</class>
+
+	<class name="Group" table="`Group`">
+        <id name="id" column="ID">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+		<property name="description"/>
+		<bag name="users" table="UserGroup" inverse="true">
+			<key column="GROUP_ID"/>
+			<many-to-many column="USER_ID" class="User" order-by="NAME"/>
+		</bag>
+	</class>
+	
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/Group.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/Group.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/Group.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+//$Id: Group.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.map;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Gavin King
+ */
+public class Group {
+	private String name;
+	private Map users = new HashMap();
+	Group() {}
+	public Group(String n) {
+		name = n;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public Map getUsers() {
+		return users;
+	}
+	public void setUsers(Map users) {
+		this.users = users;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/Group.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/MapIndexFormulaTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/MapIndexFormulaTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/MapIndexFormulaTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,107 @@
+//$Id: MapIndexFormulaTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.map;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class MapIndexFormulaTest extends FunctionalTestCase {
+	
+	public MapIndexFormulaTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "map/UserGroup.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( MapIndexFormulaTest.class );
+	}
+	
+	public void testIndexFormulaMap() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User gavin = new User("gavin", "secret");
+		User turin = new User("turin", "tiger");
+		Group g = new Group("developers");
+		g.getUsers().put("gavin", gavin);
+		g.getUsers().put("turin", turin);
+		s.persist(g);
+		gavin.getSession().put( "foo", new SessionAttribute("foo", "foo bar baz") );
+		gavin.getSession().put( "bar", new SessionAttribute("bar", "foo bar baz 2") );
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		g = (Group) s.get(Group.class, "developers");
+		assertEquals( g.getUsers().size(), 2 );
+		g.getUsers().remove("turin");
+		Map smap = ( (User) g.getUsers().get("gavin") ).getSession();
+		assertEquals(smap.size(), 2);
+		smap.remove("bar");
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		g = (Group) s.get(Group.class, "developers");
+		assertEquals( g.getUsers().size(), 1 );
+		smap = ( (User) g.getUsers().get("gavin") ).getSession();
+		assertEquals(smap.size(), 1);
+		gavin = (User) g.getUsers().put("gavin", turin);
+		s.delete(gavin);
+		assertEquals( s.createQuery("select count(*) from SessionAttribute").uniqueResult(), new Long(0) );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		g = (Group) s.get(Group.class, "developers");
+		assertEquals( g.getUsers().size(), 1 );
+		turin = (User) g.getUsers().get("turin");
+		smap = turin.getSession();
+		assertEquals(smap.size(), 0);
+		assertEquals( s.createQuery("select count(*) from User").uniqueResult(), new Long(1) );
+		s.delete(g);
+		s.delete(turin);
+		assertEquals( s.createQuery("select count(*) from User").uniqueResult(), new Long(0) );
+		t.commit();
+		s.close();
+	}
+	
+	public void testSQLQuery() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User gavin = new User("gavin", "secret");
+		User turin = new User("turin", "tiger");
+		gavin.getSession().put( "foo", new SessionAttribute("foo", "foo bar baz") );
+		gavin.getSession().put( "bar", new SessionAttribute("bar", "foo bar baz 2") );
+		s.persist(gavin);
+		s.persist(turin);
+		s.flush();
+		s.clear();
+		List results = s.getNamedQuery("userSessionData").setParameter("uname", "%in").list();
+		assertEquals( results.size(), 2 );
+		gavin = (User) ( (Object[]) results.get(0) )[0];
+		assertEquals( gavin.getName(), "gavin" );
+		assertEquals( gavin.getSession().size(), 2 );
+		s.createQuery("delete SessionAttribute").executeUpdate();
+		s.createQuery("delete User").executeUpdate();
+		t.commit();
+		s.close();
+		
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/MapIndexFormulaTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/SessionAttribute.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/SessionAttribute.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/SessionAttribute.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+//$Id: SessionAttribute.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.map;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class SessionAttribute {
+	private Long id;
+	private String name;
+	private String stringData;
+	private Serializable objectData;
+	SessionAttribute() {}
+	public SessionAttribute(String name, Serializable obj) {
+		this.name = name;
+		this.objectData = obj;
+	}
+	public SessionAttribute(String name, String str) {
+		this.name = name;
+		this.stringData = str;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public Serializable getObjectData() {
+		return objectData;
+	}
+	public void setObjectData(Serializable objectData) {
+		this.objectData = objectData;
+	}
+	public String getStringData() {
+		return stringData;
+	}
+	public void setStringData(String stringData) {
+		this.stringData = stringData;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/SessionAttribute.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: User.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.map;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Gavin King
+ */
+public class User {
+	private String name;
+	private String password;
+	private Map session = new HashMap();
+	User() {}
+	public User(String n, String pw) {
+		name=n;
+		password = pw;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getPassword() {
+		return password;
+	}
+	public void setPassword(String password) {
+		this.password = password;
+	}
+	public Map getSession() {
+		return session;
+	}
+	public void setSession(Map session) {
+		this.session = session;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/User.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/UserGroup.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/UserGroup.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/UserGroup.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+     
+-->
+
+<hibernate-mapping package="org.hibernate.test.map">
+	
+	<class name="Group" table="groups">
+		<id name="name"/>
+		<map name="users" cascade="persist" table="group_user">
+			<key column="groupName"/>
+			<map-key formula="lower(personName)" type="string"/>
+			<many-to-many column="personName" class="User"/>
+		</map>
+	</class>
+	
+	<class name="User" table="users">
+		<id name="name"/>
+		<property name="password"/>
+		<map name="session" cascade="persist,save-update,delete,delete-orphan">
+			<key column="userName" not-null="true"/>
+			<map-key formula="lower(name)" type="string"/>
+			<one-to-many class="SessionAttribute"/>
+		</map>
+	</class>
+	
+	<class name="SessionAttribute" table="session_attributes">
+		<id name="id" access="field">
+			<generator class="native"/>
+		</id>
+		<property name="name" not-null="true" update="false"/>
+		<property name="stringData"/>
+		<property name="objectData"/>
+	</class>
+	
+	<sql-query name="userSessionData">
+		<return alias="u" class="User"/>
+		<return-join alias="s" property="u.session"/>
+		select 
+			lower(u.name) as {u.name}, lower(u.password) as {u.password}, 
+			lower(s.userName) as {s.key}, lower(s.name) as {s.index}, s.id as {s.element}, 
+			{s.element.*}
+		from users u 
+		join session_attributes s on lower(s.userName) = lower(u.name)
+		where u.name like :uname
+	</sql-query>	
+	
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/map/UserGroup.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Item.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Item.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Item.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: Item.java 6236 2005-03-29 03:20:23Z oneovthafew $
+package org.hibernate.test.mapcompelem;
+
+/**
+ * @author Gavin King
+ */
+public class Item {
+
+	private String code;
+	private Product product;
+	
+	
+	Item() {}
+	public Item(String code, Product p) {
+		this.code = code;
+		this.product = p;
+	}
+
+	public String getCode() {
+		return code;
+	}
+	
+	public void setCode(String code) {
+		this.code = code;
+	}
+	
+	public Product getProduct() {
+		return product;
+	}
+	
+	public void setProduct(Product product) {
+		this.product = product;
+	}
+	
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Item.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/MapCompositeElementTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/MapCompositeElementTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/MapCompositeElementTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,116 @@
+//$Id: MapCompositeElementTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.mapcompelem;
+
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class MapCompositeElementTest extends FunctionalTestCase {
+	
+	public MapCompositeElementTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "mapcompelem/ProductPart.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( MapCompositeElementTest.class );
+	}
+	
+	public void testMapCompositeElementWithFormula() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Part top = new Part("top", "The top part");
+		Part bottom = new Part("bottom", "The bottom part");
+		Product prod = new Product("Some Thing");
+		prod.getParts().put("Top", top);
+		prod.getParts().put("Bottom", bottom);
+		s.persist(prod);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		prod = (Product) s.get(Product.class, "Some Thing");
+		assertEquals( prod.getParts().size(), 2 );
+		prod.getParts().remove("Bottom");
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		prod = (Product) s.get(Product.class, "Some Thing");
+		assertEquals( prod.getParts().size(), 1 );
+		prod.getParts().put("Top", new Part("top", "The brand new top part"));
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		prod = (Product) s.get(Product.class, "Some Thing");
+		assertEquals( prod.getParts().size(), 1 );
+		assertEquals(  ( (Part) prod.getParts().get("Top") ).getDescription(), "The brand new top part");
+		s.delete(prod);
+		t.commit();
+		s.close();
+	}
+	
+	public void testQueryMapCompositeElement() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Part top = new Part("top", "The top part");
+		Part bottom = new Part("bottom", "The bottom part");
+		Product prod = new Product("Some Thing");
+		prod.getParts().put("Top", top);
+		prod.getParts().put("Bottom", bottom);
+		s.persist(prod);
+		
+		Item item = new Item("123456", prod);
+		s.persist(item);
+
+		List list = s.createQuery("select new Part( part.name, part.description ) from Product prod join prod.parts part order by part.name desc").list();
+		assertEquals( list.size(), 2 );
+		assertTrue( list.get(0) instanceof Part );
+		assertTrue( list.get(1) instanceof Part );
+		Part part = (Part) list.get(0);
+		assertEquals( part.getName(), "top" );
+		assertEquals( part.getDescription(), "The top part" );
+		
+		list = s.createQuery("select new Part( part.name, part.description ) from Product prod join prod.parts part where index(part) = 'Top'").list();
+		assertEquals( list.size(), 1 );
+		assertTrue( list.get(0) instanceof Part );
+		part = (Part) list.get(0);
+		assertEquals( part.getName(), "top" );
+		assertEquals( part.getDescription(), "The top part" );
+		
+		list = s.createQuery("from Product p where 'Top' in indices(p.parts)").list();
+		assertEquals( list.size(), 1 );
+		assertSame( list.get(0), prod );
+		
+		list = s.createQuery("select i from Item i join i.product p where 'Top' in indices(p.parts)").list();
+		assertEquals( list.size(), 1 );
+		assertSame( list.get(0), item );
+		
+		list = s.createQuery("from Item i where 'Top' in indices(i.product.parts)").list();
+		assertEquals( list.size(), 1 );
+		assertSame( list.get(0), item );
+		
+		s.delete(item);
+		s.delete(prod);
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/MapCompositeElementTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Part.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Part.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Part.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: Part.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.mapcompelem;
+
+
+/**
+ * @author Gavin King
+ */
+public class Part {
+	private String name;
+	private String description;
+	Part() {}
+	public Part(String n, String pw) {
+		name=n;
+		description = pw;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getDescription() {
+		return description;
+	}
+	public void setDescription(String password) {
+		this.description = password;
+	}
+	public boolean equals(Object that) {
+		return ( (Part) that ).getName().equals(name);
+	}
+	public int hashCode() {
+		return name.hashCode();
+	}
+	public String toString() {
+		return name + ":" + description;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Part.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Product.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Product.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Product.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+//$Id: Product.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.mapcompelem;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Gavin King
+ */
+public class Product {
+	private String name;
+	private Map parts = new HashMap();
+	Product() {}
+	public Product(String n) {
+		name = n;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public Map getParts() {
+		return parts;
+	}
+	public void setParts(Map users) {
+		this.parts = users;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/Product.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/ProductPart.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/ProductPart.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/ProductPart.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+     
+-->
+
+<hibernate-mapping package="org.hibernate.test.mapcompelem">
+	
+	<import class="Part"/>
+
+	<class name="Product" table="Products">
+		<id name="name" column="productName"/>
+		<map name="parts" table="Parts">
+			<key column="productName"/>
+			<map-key column="partName" type="string"/>
+			<composite-element class="Part">
+				<property name="name" formula="lower(partName)"/>
+				<property name="description" column="partDescription"/>
+			</composite-element>
+		</map>
+	</class>
+	
+	<class name="Item" table="Items">
+		<id name="code"/>
+		<many-to-one name="product" column="productName"/>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapcompelem/ProductPart.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/Group.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/Group.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/Group.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+//$Id: Group.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.mapelemformula;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Gavin King
+ */
+public class Group {
+	private String name;
+	private Map users = new HashMap();
+	Group() {}
+	public Group(String n) {
+		name = n;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public Map getUsers() {
+		return users;
+	}
+	public void setUsers(Map users) {
+		this.users = users;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/Group.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/MapElementFormulaTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/MapElementFormulaTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/MapElementFormulaTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+//$Id: MapElementFormulaTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.mapelemformula;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class MapElementFormulaTest extends FunctionalTestCase {
+	
+	public MapElementFormulaTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "mapelemformula/UserGroup.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( MapElementFormulaTest.class );
+	}
+
+	public void testManyToManyFormula() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User gavin = new User("gavin", "secret");
+		User turin = new User("turin", "tiger");
+		Group g = new Group("users");
+		g.getUsers().put("Gavin", gavin);
+		g.getUsers().put("Turin", turin);
+		s.persist(g);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		g = (Group) s.get(Group.class, "users");
+		assertEquals( g.getUsers().size(), 2 );
+		g.getUsers().remove("Turin");
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		g = (Group) s.get(Group.class, "users");
+		assertEquals( g.getUsers().size(), 1 );
+		s.delete(g);
+		s.delete( g.getUsers().get("Gavin") );
+		s.delete( s.get(User.class, "turin") );
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/MapElementFormulaTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+//$Id: User.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.mapelemformula;
+
+
+/**
+ * @author Gavin King
+ */
+public class User {
+	private String name;
+	private String password;
+	User() {}
+	public User(String n, String pw) {
+		name=n;
+		password = pw;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getPassword() {
+		return password;
+	}
+	public void setPassword(String password) {
+		this.password = password;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/User.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/UserGroup.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/UserGroup.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/UserGroup.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+     
+-->
+
+<hibernate-mapping package="org.hibernate.test.mapelemformula">
+	
+	<class name="Group" table="groups">
+		<id name="name"/>
+		<map name="users" cascade="persist" table="group_user">
+			<key column="groupName"/>
+			<map-key column="personName" type="string"/>
+			<many-to-many formula="lower(personName)" class="User" fetch="select"/>
+		</map>
+	</class>
+	
+	<class name="User" table="users">
+		<id name="name"/>
+		<property name="password"/>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapelemformula/UserGroup.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapping/PersistentClassVisitorTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapping/PersistentClassVisitorTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapping/PersistentClassVisitorTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+/*
+* Created on 06-Dec-2004
+*
+*/
+package org.hibernate.test.mapping;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.mapping.JoinedSubclass;
+import org.hibernate.mapping.PersistentClassVisitor;
+import org.hibernate.mapping.RootClass;
+import org.hibernate.mapping.SingleTableSubclass;
+import org.hibernate.mapping.Subclass;
+import org.hibernate.mapping.UnionSubclass;
+import org.hibernate.junit.UnitTestCase;
+
+/**
+ * @author max
+ * 
+ */
+public class PersistentClassVisitorTest extends UnitTestCase {
+
+	public PersistentClassVisitorTest(String string) {
+		super( string );
+	}
+
+	static public class PersistentClassVisitorValidator implements PersistentClassVisitor {
+
+		private Object validate(Class expectedClass, Object visitee) {
+			if (!visitee.getClass().getName().equals(expectedClass.getName())) {
+				throw new IllegalStateException(visitee.getClass().getName()
+						+ " did not call proper accept method. Was "
+						+ expectedClass.getName());
+			}
+			return null;
+		}
+
+		public Object accept(RootClass class1) {
+			return validate(RootClass.class, class1);
+		}
+
+		public Object accept(UnionSubclass subclass) {
+			return validate(UnionSubclass.class, subclass);
+		}
+
+		public Object accept(SingleTableSubclass subclass) {
+			return validate(SingleTableSubclass.class, subclass);
+		}
+
+		public Object accept(JoinedSubclass subclass) {
+			return validate(JoinedSubclass.class, subclass);
+		}
+
+		public Object accept(Subclass subclass) {
+			return validate(Subclass.class, subclass);
+		}
+
+
+	};
+
+	public void testProperCallbacks() {
+
+		PersistentClassVisitorValidator vv = new PersistentClassVisitorValidator();
+
+		new RootClass().accept(vv);
+		new Subclass(new RootClass()).accept(vv);
+		new JoinedSubclass(new RootClass()).accept(vv);
+		new SingleTableSubclass(new RootClass()).accept(vv);
+		new UnionSubclass(new RootClass()).accept(vv);
+
+	}
+
+	public static Test suite() {
+		return new TestSuite(PersistentClassVisitorTest.class);
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapping/ValueVisitorTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapping/ValueVisitorTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mapping/ValueVisitorTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,199 @@
+/*
+ * Created on 06-Dec-2004
+ *
+ */
+package org.hibernate.test.mapping;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.mapping.Any;
+import org.hibernate.mapping.Array;
+import org.hibernate.mapping.Bag;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.DependantValue;
+import org.hibernate.mapping.IdentifierBag;
+import org.hibernate.mapping.List;
+import org.hibernate.mapping.ManyToOne;
+import org.hibernate.mapping.Map;
+import org.hibernate.mapping.OneToMany;
+import org.hibernate.mapping.OneToOne;
+import org.hibernate.mapping.PrimitiveArray;
+import org.hibernate.mapping.RootClass;
+import org.hibernate.mapping.Set;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.Table;
+import org.hibernate.mapping.ValueVisitor;
+import org.hibernate.junit.UnitTestCase;
+
+/**
+ * @author max
+ * 
+ */
+public class ValueVisitorTest extends UnitTestCase {
+
+	public ValueVisitorTest(String string) {
+		super( string );
+	}
+
+	static public class ValueVisitorValidator implements ValueVisitor {
+
+		/* (non-Javadoc)
+		 * @see org.hibernate.mapping.ValueVisitor#accept(org.hibernate.mapping.PrimitiveArray)
+		 */
+		public Object accept(PrimitiveArray primitiveArray) {
+			return validate(PrimitiveArray.class,primitiveArray);
+		}
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.hibernate.mapping.ValueVisitor#accept(org.hibernate.mapping.Bag)
+		 */
+		public Object accept(Bag bag) {
+			return validate(Bag.class, bag);
+		}
+
+		/* (non-Javadoc)
+		 * @see org.hibernate.mapping.ValueVisitor#accept(org.hibernate.mapping.DependantValue)
+		 */
+		public Object accept(DependantValue value) {
+			return validate(DependantValue.class, value);
+		}
+		/**
+		 * @param expectedClass
+		 * @param visitee
+		 */
+		private Object validate(Class expectedClass, Object visitee) {
+			if (!visitee.getClass().getName().equals(expectedClass.getName())) {
+				throw new IllegalStateException(visitee.getClass().getName()
+						+ " did not call proper accept method. Was "
+						+ expectedClass.getName());
+			}
+			return null;
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.hibernate.mapping.ValueVisitor#accept(org.hibernate.mapping.IdentifierBag)
+		 */
+		public Object accept(IdentifierBag bag) {
+			return validate(IdentifierBag.class, bag);
+
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.hibernate.mapping.ValueVisitor#accept(org.hibernate.mapping.List)
+		 */
+		public Object accept(List list) {
+			return validate(List.class, list);
+
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.hibernate.mapping.ValueVisitor#accept(org.hibernate.mapping.Map)
+		 */
+		public Object accept(Map map) {
+			return validate(Map.class, map);
+
+		}
+
+		/* (non-Javadoc)
+		 * @see org.hibernate.mapping.ValueVisitor#accept(org.hibernate.mapping.Array)
+		 */
+		public Object accept(Array list) {
+			return validate(Array.class, list);
+		}
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.hibernate.mapping.ValueVisitor#accept(org.hibernate.mapping.OneToMany)
+		 */
+		public Object accept(OneToMany many) {
+			return validate(OneToMany.class, many);
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.hibernate.mapping.ValueVisitor#accept(org.hibernate.mapping.Set)
+		 */
+		public Object accept(Set set) {
+			return validate(Set.class, set);
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.hibernate.mapping.ValueVisitor#accept(org.hibernate.mapping.Any)
+		 */
+		public Object accept(Any any) {
+			return validate(Any.class, any);
+			
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.hibernate.mapping.ValueVisitor#accept(org.hibernate.mapping.SimpleValue)
+		 */
+		public Object accept(SimpleValue value) {
+			return validate(SimpleValue.class, value);
+
+		}
+
+		/* (non-Javadoc)
+		 * @see org.hibernate.mapping.ValueVisitor#accept(org.hibernate.mapping.Component)
+		 */
+		public Object accept(Component component) {
+			return validate(Component.class, component);
+		}
+
+		/* (non-Javadoc)
+		 * @see org.hibernate.mapping.ValueVisitor#accept(org.hibernate.mapping.ManyToOne)
+		 */
+		public Object accept(ManyToOne mto) {
+			return validate(ManyToOne.class, mto);
+		}
+
+		/* (non-Javadoc)
+		 * @see org.hibernate.mapping.ValueVisitor#accept(org.hibernate.mapping.OneToOne)
+		 */
+		public Object accept(OneToOne oto) {
+			return validate(OneToOne.class, oto);
+		}
+
+	};
+
+	public void testProperCallbacks() {
+
+		ValueVisitor vv = new ValueVisitorValidator();
+		
+		new Any(new Table()).accept(vv);
+		new Array(new RootClass()).accept(vv);
+		new Bag(new RootClass()).accept(vv);
+		new Component(new RootClass()).accept(vv);
+		new DependantValue(null,null).accept(vv);
+		new IdentifierBag(null).accept(vv);
+		new List(null).accept(vv);
+		new ManyToOne(null).accept(vv);
+		new Map(null).accept(vv);
+		new OneToMany(null).accept(vv);
+		new OneToOne(null, new RootClass() ).accept(vv);
+		new PrimitiveArray(null).accept(vv);
+		new Set(null).accept(vv);
+		new SimpleValue().accept(vv);
+	
+		
+	}
+
+	public static Test suite() {
+		return new TestSuite(ValueVisitorTest.class);
+	}
+
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/InvalidMapping.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/InvalidMapping.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/InvalidMapping.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+This File Intentionally Left Blank
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/InvalidMapping.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/InvalidMapping.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/InvalidMapping.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,5 @@
+package org.hibernate.test.mappingexception;
+
+public class InvalidMapping {
+// This Class Intentionally Left Blank
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/MappingExceptionTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/MappingExceptionTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/MappingExceptionTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,253 @@
+// $Id: SQLExceptionConversionTest.java 6847 2005-05-21 15:46:41Z oneovthafew $
+package org.hibernate.test.mappingexception;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.DuplicateMappingException;
+import org.hibernate.Hibernate;
+import org.hibernate.InvalidMappingException;
+import org.hibernate.MappingException;
+import org.hibernate.MappingNotFoundException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.junit.UnitTestCase;
+import org.hibernate.util.ConfigHelper;
+
+/**
+ * Test for various mapping exceptions thrown when mappings are not found or invalid.
+ *
+ * @author Max Rydahl Andersen
+ */
+public class MappingExceptionTest extends UnitTestCase {
+
+	public MappingExceptionTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new TestSuite( MappingExceptionTest.class );
+	}
+
+	public void testNotFound() throws MappingException, MalformedURLException {
+		Configuration cfg = new Configuration();
+
+		try {
+			cfg.addCacheableFile( "completelybogus.hbm.xml" );
+			fail();
+		}
+		catch ( MappingNotFoundException e ) {
+			assertEquals( e.getType(), "file" );
+			assertEquals( e.getPath(), "completelybogus.hbm.xml" );
+		}
+
+		try {
+			cfg.addCacheableFile( new File( "completelybogus.hbm.xml" ) );
+			fail();
+		}
+		catch ( MappingNotFoundException e ) {
+			assertEquals( e.getType(), "file" );
+			assertEquals( e.getPath(), "completelybogus.hbm.xml" );
+		}
+
+		try {
+			cfg.addClass( Hibernate.class ); // TODO: String.class result in npe, because no classloader exists for it
+			fail();
+		}
+		catch ( MappingNotFoundException inv ) {
+			assertEquals( inv.getType(), "resource" );
+			assertEquals( inv.getPath(), "org/hibernate/Hibernate.hbm.xml" );
+		}
+
+		try {
+			cfg.addFile( "completelybogus.hbm.xml" );
+			fail();
+		}
+		catch ( MappingNotFoundException e ) {
+			assertEquals( e.getType(), "file" );
+			assertEquals( e.getPath(), "completelybogus.hbm.xml" );
+		}
+
+		try {
+			cfg.addFile( new File( "completelybogus.hbm.xml" ) );
+			fail();
+		}
+		catch ( MappingNotFoundException inv ) {
+			assertEquals( inv.getType(), "file" );
+			assertEquals( inv.getPath(), "completelybogus.hbm.xml" );
+		}
+
+		try {
+			cfg.addInputStream( new ByteArrayInputStream( new byte[0] ) );
+			fail();
+		}
+		catch ( InvalidMappingException inv ) {
+			assertEquals( inv.getType(), "input stream" );
+			assertEquals( inv.getPath(), null );
+		}
+
+		try {
+			cfg.addResource( "nothere" );
+			fail();
+		}
+		catch ( MappingNotFoundException inv ) {
+			assertEquals( inv.getType(), "resource" );
+			assertEquals( inv.getPath(), "nothere" );
+		}
+
+		try {
+			cfg.addResource( "nothere", getClass().getClassLoader() );
+			fail();
+		}
+		catch ( MappingNotFoundException inv ) {
+			assertEquals( inv.getType(), "resource" );
+			assertEquals( inv.getPath(), "nothere" );
+		}
+
+		try {
+			cfg.addURL( new URL( "file://nothere" ) );
+			fail();
+		}
+		catch ( InvalidMappingException inv ) {
+			assertEquals( inv.getType(), "URL" );
+			assertEquals( inv.getPath(), "file://nothere" );
+		}
+	}
+
+	public void testDuplicateMapping() {
+		String resourceName = "org/hibernate/test/mappingexception/User.hbm.xml";
+		Configuration cfg = new Configuration();
+		cfg.addResource( resourceName );
+		try {
+			cfg.addResource( resourceName );
+			fail();
+		}
+		catch ( InvalidMappingException inv ) {
+			assertEquals( inv.getType(), "resource" );
+			assertEquals( inv.getPath(), resourceName );
+			assertClassAssignability( inv.getCause().getClass(), DuplicateMappingException.class );
+		}
+	}
+
+	public void testInvalidMapping() throws MappingException, IOException {
+		String resourceName = "org/hibernate/test/mappingexception/InvalidMapping.hbm.xml";
+		File file = File.createTempFile( "TempInvalidMapping", ".hbm.xml" );
+		file.deleteOnExit();
+		copy( ConfigHelper.getConfigStream( resourceName ), file );
+
+		Configuration cfg = new Configuration();
+		try {
+			cfg.addCacheableFile( file.getAbsolutePath() );
+			fail();
+		}
+		catch ( InvalidMappingException inv ) {
+			assertEquals( inv.getType(), "file" );
+			assertNotNull( inv.getPath() );
+			assertTrue( inv.getPath().endsWith( ".hbm.xml" ) );
+			assertTrue( !( inv.getCause() instanceof MappingNotFoundException ) );
+		}
+
+		try {
+			cfg.addCacheableFile( file );
+			fail();
+		}
+		catch ( InvalidMappingException inv ) {
+			assertEquals( inv.getType(), "file" );
+			assertNotNull( inv.getPath() );
+			assertTrue( inv.getPath().endsWith( ".hbm.xml" ) );
+			assertTrue( !( inv.getCause() instanceof MappingNotFoundException ) );
+		}
+
+		try {
+			cfg.addClass( InvalidMapping.class );
+			fail();
+		}
+		catch ( InvalidMappingException inv ) {
+			assertEquals( inv.getType(), "resource" );
+			assertEquals( inv.getPath(), "org/hibernate/test/mappingexception/InvalidMapping.hbm.xml" );
+			assertTrue( !( inv.getCause() instanceof MappingNotFoundException ) );
+		}
+
+		try {
+			cfg.addFile( file.getAbsolutePath() );
+			fail();
+		}
+		catch ( InvalidMappingException inv ) {
+			assertEquals( inv.getType(), "file" );
+			assertEquals( inv.getPath(), file.getPath() );
+			assertTrue( !( inv.getCause() instanceof MappingNotFoundException ) );
+		}
+
+		try {
+			cfg.addFile( file );
+			fail();
+		}
+		catch ( InvalidMappingException inv ) {
+			assertEquals( inv.getType(), "file" );
+			assertEquals( inv.getPath(), file.getPath() );
+			assertTrue( !( inv.getCause() instanceof MappingNotFoundException ) );
+		}
+
+
+		try {
+			cfg.addInputStream( ConfigHelper.getResourceAsStream( resourceName ) );
+			fail();
+		}
+		catch ( InvalidMappingException inv ) {
+			assertEquals( inv.getType(), "input stream" );
+			assertEquals( inv.getPath(), null );
+			assertTrue( !( inv.getCause() instanceof MappingNotFoundException ) );
+		}
+
+		try {
+			cfg.addResource( resourceName );
+			fail();
+		}
+		catch ( InvalidMappingException inv ) {
+			assertEquals( inv.getType(), "resource" );
+			assertEquals( inv.getPath(), resourceName );
+			assertTrue( !( inv.getCause() instanceof MappingNotFoundException ) );
+		}
+
+		try {
+			cfg.addResource( resourceName, getClass().getClassLoader() );
+			fail();
+		}
+		catch ( InvalidMappingException inv ) {
+			assertEquals( inv.getType(), "resource" );
+			assertEquals( inv.getPath(), resourceName );
+			assertTrue( !( inv.getCause() instanceof MappingNotFoundException ) );
+		}
+
+		try {
+			cfg.addURL( ConfigHelper.findAsResource( resourceName ) );
+			fail();
+		}
+		catch ( InvalidMappingException inv ) {
+			assertEquals( inv.getType(), "URL" );
+			assertTrue( inv.getPath().endsWith( "InvalidMapping.hbm.xml" ) );
+			assertTrue( !( inv.getCause() instanceof MappingNotFoundException ) );
+		}
+	}
+
+	void copy(InputStream in, File dst) throws IOException {
+		OutputStream out = new FileOutputStream( dst );
+
+		// Transfer bytes from in to out
+		byte[] buf = new byte[1024];
+		int len;
+		while ( ( len = in.read( buf ) ) > 0 ) {
+			out.write( buf, 0, len );
+		}
+		in.close();
+		out.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/User.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/User.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/User.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.exception" >
+	<class name="User" table="T_USER" >
+		<id name="id" unsaved-value="null" column="user_id" >
+			<generator class="native"/>
+		</id>
+		<property name="username" type="string" column="user_name" />		
+	</class>
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mappingexception/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+// $Id: User.java 4746 2004-11-11 20:57:28Z steveebersole $
+package org.hibernate.test.mappingexception;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * 
+ *
+ * @author Max Rydahl Andersen
+ */
+public class User {
+	private Long id;
+	private String username;
+	
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getUsername() {
+		return username;
+	}
+
+	public void setUsername(String username) {
+		this.username = username;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Document.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Document.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Document.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,83 @@
+//$Id: Document.java 8670 2005-11-25 17:36:29Z epbernard $
+
+package org.hibernate.test.mixed;
+
+
+import java.sql.Blob;
+import java.util.Calendar;
+
+
+/**
+ * @author Gavin King
+ */
+
+public class Document extends Item {
+
+	private Blob content;
+
+	private Calendar modified;
+
+	private Calendar created;
+
+	/**
+	 * @return Returns the created.
+	 */
+
+	public Calendar getCreated() {
+
+		return created;
+
+	}
+
+	/**
+	 * @param created The created to set.
+	 */
+
+	public void setCreated(Calendar created) {
+
+		this.created = created;
+
+	}
+
+	/**
+	 * @return Returns the modified.
+	 */
+
+	public Calendar getModified() {
+
+		return modified;
+
+	}
+
+	/**
+	 * @param modified The modified to set.
+	 */
+
+	public void setModified(Calendar modified) {
+
+		this.modified = modified;
+
+	}
+
+	/**
+	 * @return Returns the content.
+	 */
+
+	public Blob getContent() {
+
+		return content;
+
+	}
+
+	/**
+	 * @param content The content to set.
+	 */
+
+	public void setContent(Blob content) {
+
+		this.content = content;
+
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Document.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/DocumentInterceptor.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/DocumentInterceptor.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/DocumentInterceptor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,116 @@
+//$Id: DocumentInterceptor.java 8670 2005-11-25 17:36:29Z epbernard $
+package org.hibernate.test.mixed;
+
+import java.io.Serializable;
+import java.util.Calendar;
+import java.util.Iterator;
+
+import org.hibernate.CallbackException;
+import org.hibernate.EntityMode;
+import org.hibernate.Interceptor;
+import org.hibernate.Transaction;
+import org.hibernate.type.Type;
+
+/**
+ * @author Gavin King
+ */
+public class DocumentInterceptor implements Interceptor {
+
+
+	public boolean onLoad(
+			Object entity, Serializable id, Object[] state,
+			String[] propertyNames, Type[] types
+	) throws CallbackException {
+		return false;
+	}
+
+	public boolean onFlushDirty(
+			Object entity, Serializable id,
+			Object[] currentState, Object[] previousState,
+			String[] propertyNames, Type[] types
+	) throws CallbackException {
+		if ( entity instanceof Document ) {
+			currentState[3] = Calendar.getInstance();
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	public boolean onSave(
+			Object entity, Serializable id, Object[] state,
+			String[] propertyNames, Type[] types
+	) throws CallbackException {
+		if ( entity instanceof Document ) {
+			state[4] = state[3] = Calendar.getInstance();
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+
+	public void onDelete(
+			Object entity, Serializable id, Object[] state,
+			String[] propertyNames, Type[] types
+	) throws CallbackException {
+
+	}
+
+	public void preFlush(Iterator entities) throws CallbackException {
+
+	}
+
+	public void postFlush(Iterator entities) throws CallbackException {
+
+	}
+
+	public Boolean isTransient(Object entity) {
+		return null;
+	}
+
+	public int[] findDirty(
+			Object entity, Serializable id,
+			Object[] currentState, Object[] previousState,
+			String[] propertyNames, Type[] types
+	) {
+		return null;
+	}
+
+	public Object instantiate(String entityName, EntityMode entityMode, Serializable id) throws CallbackException {
+		return null;
+	}
+
+	public String getEntityName(Object object) throws CallbackException {
+		return null;
+	}
+
+	public Object getEntity(String entityName, Serializable id)
+			throws CallbackException {
+		return null;
+	}
+
+	public void afterTransactionBegin(Transaction tx) {
+	}
+
+	public void afterTransactionCompletion(Transaction tx) {
+	}
+
+	public void beforeTransactionCompletion(Transaction tx) {
+	}
+
+	public String onPrepareStatement(String sql) {
+		return sql;
+	}
+
+	public void onCollectionRecreate(Object collection, Serializable key) throws CallbackException {
+	}
+
+	public void onCollectionRemove(Object collection, Serializable key) throws CallbackException {
+	}
+
+	public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException {
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/DocumentInterceptor.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Folder.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Folder.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Folder.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+//$Id: Folder.java 8670 2005-11-25 17:36:29Z epbernard $
+
+package org.hibernate.test.mixed;
+
+
+/**
+ * @author Gavin King
+ */
+
+public class Folder extends Item {
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Folder.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Item.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Item.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Item.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,135 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping PUBLIC
+
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+
+<!--
+
+
+
+  This mapping demonstrates a mixed inheritance strategy,
+
+  with one subclass acting like a joined-subclass via
+
+  use of a <join>. Also notice the fields which are initialized 
+
+  by an interceptor.
+
+  
+
+-->
+
+
+<hibernate-mapping
+
+        package="org.hibernate.test.mixed">
+
+
+    <class name="Item"
+
+           table="Files"
+
+           discriminator-value="I">
+
+
+        <id name="id">
+
+            <generator class="native"/>
+
+        </id>
+
+
+        <discriminator type="character"
+
+                       column="itemType"/>
+
+
+        <property name="name">
+
+            <column name="name"
+
+                    not-null="true"
+
+                    />
+            <!--unique-key="folder-parent"-->
+
+        </property>
+
+
+        <many-to-one name="parent"
+
+                     class="Folder">
+
+            <column name="parentFolderId"
+
+                    />
+            <!--unique-key="folder-parent"-->
+
+        </many-to-one>
+
+
+        <subclass name="Document"
+
+                  discriminator-value="D"
+
+                  lazy="true"
+
+                  dynamic-update="true">
+
+
+            <property name="content"/>
+
+
+            <!-- managed by DocumentInterceptor -->
+
+            <property name="modified"/>
+
+            <property name="created"/>
+
+
+            <subclass name="SecureDocument"
+
+                      discriminator-value="S"
+
+                      dynamic-update="true"
+
+                      lazy="true">
+
+
+                <join table="SecureDocument">
+
+
+                    <key column="documentId"/>
+
+
+                    <property name="permissionBits"
+
+                              not-null="true"/>
+
+                    <property name="owner"
+
+                              not-null="true"/>
+
+
+                </join>
+
+
+            </subclass>
+
+
+        </subclass>
+
+
+        <subclass name="Folder"
+
+                  discriminator-value="F"/>
+
+
+    </class>
+
+
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Item.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Item.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Item.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Item.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,79 @@
+//$Id: Item.java 8670 2005-11-25 17:36:29Z epbernard $
+
+package org.hibernate.test.mixed;
+
+
+/**
+ * @author Gavin King
+ */
+
+public abstract class Item {
+
+	private Long id;
+
+	private String name;
+
+	private Folder parent;
+
+	/**
+	 * @return Returns the parent.
+	 */
+
+	public Folder getParent() {
+
+		return parent;
+
+	}
+
+	/**
+	 * @param parent The parent to set.
+	 */
+
+	public void setParent(Folder parent) {
+
+		this.parent = parent;
+
+	}
+
+	/**
+	 * @return Returns the id.
+	 */
+
+	public Long getId() {
+
+		return id;
+
+	}
+
+	/**
+	 * @param id The id to set.
+	 */
+
+	public void setId(Long id) {
+
+		this.id = id;
+
+	}
+
+	/**
+	 * @return Returns the name.
+	 */
+
+	public String getName() {
+
+		return name;
+
+	}
+
+	/**
+	 * @param name The name to set.
+	 */
+
+	public void setName(String name) {
+
+		this.name = name;
+
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/Item.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/MixedTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/MixedTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/MixedTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,107 @@
+//$Id: MixedTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.mixed;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.dialect.PostgreSQLDialect;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class MixedTest extends FunctionalTestCase {
+
+	public MixedTest(String str) {
+		super( str );
+	}
+
+	public String[] getMappings() {
+		return new String[]{"mixed/Item.hbm.xml"};
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( MixedTest.class );
+	}
+
+	public void testMixedInheritance() {
+		Session s = openSession( new DocumentInterceptor() );
+		Transaction t = s.beginTransaction();
+		Folder f = new Folder();
+		f.setName( "/" );
+		s.save( f );
+
+		Document d = new Document();
+		d.setName( "Hibernate in Action" );
+		d.setContent( Hibernate.createBlob( "blah blah blah".getBytes() ) );
+		d.setParent( f );
+		Long did = (Long) s.save( d );
+
+		SecureDocument d2 = new SecureDocument();
+		d2.setName( "Secret" );
+		d2.setContent( Hibernate.createBlob( "wxyz wxyz".getBytes() ) );
+		d2.setPermissionBits( (byte) 664 );
+		d2.setOwner( "gavin" );
+		d2.setParent( f );
+		Long d2id = (Long) s.save( d2 );
+
+		t.commit();
+		s.close();
+
+		if ( getDialect() instanceof PostgreSQLDialect ) return;
+
+		s = openSession( new DocumentInterceptor() );
+		t = s.beginTransaction();
+		Item id = (Item) s.load( Item.class, did );
+		assertEquals( did, id.getId() );
+		assertEquals( "Hibernate in Action", id.getName() );
+		assertEquals( "/", id.getParent().getName() );
+
+		Item id2 = (Item) s.load( Item.class, d2id );
+		assertEquals( d2id, id2.getId() );
+		assertEquals( "Secret", id2.getName() );
+		assertEquals( "/", id2.getParent().getName() );
+
+		id.setName( "HiA" );
+
+		d2 = (SecureDocument) s.load( SecureDocument.class, d2id );
+		d2.setOwner( "max" );
+
+		s.flush();
+
+		s.clear();
+
+		d = (Document) s.load( Document.class, did );
+		assertEquals( did, d.getId() );
+		assertEquals( "HiA", d.getName() );
+		assertNotNull( d.getContent() );
+		assertEquals( "/", d.getParent().getName() );
+		assertNotNull( d.getCreated() );
+		assertNotNull( d.getModified() );
+
+		d2 = (SecureDocument) s.load( SecureDocument.class, d2id );
+		assertEquals( d2id, d2.getId() );
+		assertEquals( "Secret", d2.getName() );
+		assertNotNull( d2.getContent() );
+		assertEquals( "max", d2.getOwner() );
+		assertEquals( "/", d2.getParent().getName() );
+		assertEquals( (byte) 664, d2.getPermissionBits() );
+		assertNotNull( d2.getCreated() );
+		assertNotNull( d2.getModified() );
+
+		s.delete( d.getParent() );
+		s.delete( d );
+		s.delete( d2 );
+
+		t.commit();
+		s.close();
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/MixedTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/SecureDocument.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/SecureDocument.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/SecureDocument.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+//$Id: SecureDocument.java 8670 2005-11-25 17:36:29Z epbernard $
+
+package org.hibernate.test.mixed;
+
+
+/**
+ * @author Gavin King
+ */
+
+public class SecureDocument extends Document {
+
+	private byte permissionBits;
+
+	private String owner;
+
+	/**
+	 * @return Returns the owner.
+	 */
+
+	public String getOwner() {
+
+		return owner;
+
+	}
+
+	/**
+	 * @param owner The owner to set.
+	 */
+
+	public void setOwner(String owner) {
+
+		this.owner = owner;
+
+	}
+
+	/**
+	 * @return Returns the permissionBits.
+	 */
+
+	public byte getPermissionBits() {
+
+		return permissionBits;
+
+	}
+
+	/**
+	 * @param permissionBits The permissionBits to set.
+	 */
+
+	public void setPermissionBits(byte permissionBits) {
+
+		this.permissionBits = permissionBits;
+
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/mixed/SecureDocument.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/NaturalIdTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/NaturalIdTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/NaturalIdTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,248 @@
+//$Id: NaturalIdTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.naturalid;
+
+import java.lang.reflect.Field;
+
+import junit.framework.Test;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.Restrictions;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class NaturalIdTest extends FunctionalTestCase {
+	
+	public NaturalIdTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "naturalid/User.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
+		cfg.setProperty(Environment.USE_QUERY_CACHE, "true");
+		cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( NaturalIdTest.class );
+	}
+	
+	public void testNaturalIdCheck() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		
+		User u = new User("gavin", "hb", "secret");
+		s.persist(u);
+		Field name = u.getClass().getDeclaredField("name");
+		name.setAccessible(true);
+		name.set(u, "Gavin");
+		try {
+			s.flush();
+			fail();
+		}
+		catch (HibernateException he) {}
+		name.set(u, "gavin");
+		s.delete(u);
+		t.commit();
+		s.close();
+	}
+	
+	public void testNonexistentNaturalIdCache() {
+		getSessions().getStatistics().clear();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		
+		Object nullUser = s.createCriteria(User.class)
+			.add( Restrictions.naturalId()
+				.set("name", "gavin")
+				.set("org", "hb") 
+			)
+			.setCacheable(true)
+			.uniqueResult();
+		
+		assertNull(nullUser);
+	
+		t.commit();
+		s.close();
+	
+		assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 );
+		assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 0 );
+		
+		s = openSession();
+		t = s.beginTransaction();
+		
+		User u = new User("gavin", "hb", "secret");
+		s.persist(u);
+		
+		t.commit();
+		s.close();
+		
+		getSessions().getStatistics().clear();
+
+		s = openSession();
+		t = s.beginTransaction();
+		
+		u = (User) s.createCriteria(User.class)
+			.add( Restrictions.naturalId()
+				.set("name", "gavin")
+				.set("org", "hb") 
+			)
+			.setCacheable(true)
+			.uniqueResult();
+		
+		assertNotNull(u);
+		
+		t.commit();
+		s.close();
+
+		assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 );
+		assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 1 );
+		
+		getSessions().getStatistics().clear();
+
+		s = openSession();
+		t = s.beginTransaction();
+		
+		u = (User) s.createCriteria(User.class)
+			.add( Restrictions.naturalId()
+				.set("name", "gavin")
+				.set("org", "hb") 
+			).setCacheable(true)
+			.uniqueResult();
+		
+		s.delete(u);
+		
+		t.commit();
+		s.close();
+		
+		assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 1 );
+
+		getSessions().getStatistics().clear();
+
+		s = openSession();
+		t = s.beginTransaction();
+		
+		nullUser = s.createCriteria(User.class)
+			.add( Restrictions.naturalId()
+				.set("name", "gavin")
+				.set("org", "hb") 
+			)
+			.setCacheable(true)
+			.uniqueResult();
+		
+		assertNull(nullUser);
+	
+		t.commit();
+		s.close();
+	
+		assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 );
+		assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 0 );
+		
+	}
+
+	public void testNaturalIdCache() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		
+		User u = new User("gavin", "hb", "secret");
+		s.persist(u);
+		
+		t.commit();
+		s.close();
+		
+		getSessions().getStatistics().clear();
+
+		s = openSession();
+		t = s.beginTransaction();
+		
+		u = (User) s.createCriteria(User.class)
+			.add( Restrictions.naturalId()
+				.set("name", "gavin")
+				.set("org", "hb") 
+			)
+			.setCacheable(true)
+			.uniqueResult();
+		
+		assertNotNull(u);
+		
+		t.commit();
+		s.close();
+
+		assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 );
+		assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 1 );
+		
+		s = openSession();
+		t = s.beginTransaction();
+		
+		User v = new User("xam", "hb", "foobar");
+		s.persist(v);
+		
+		t.commit();
+		s.close();
+		
+		getSessions().getStatistics().clear();
+
+		s = openSession();
+		t = s.beginTransaction();
+		
+		u = (User) s.createCriteria(User.class)
+			.add( Restrictions.naturalId()
+				.set("name", "gavin")
+				.set("org", "hb") 
+			).setCacheable(true)
+			.uniqueResult();
+		
+		assertNotNull(u);
+		
+		t.commit();
+		s.close();
+		
+		assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 1 );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery("delete User").executeUpdate();
+		t.commit();
+		s.close();
+	}
+
+	public void testQuerying() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		User u = new User("emmanuel", "hb", "bh");
+		s.persist(u);
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+
+		u = (User) s.createQuery( "from User u where u.name = :name" )
+			.setParameter( "name", "emmanuel" ).uniqueResult();
+		assertEquals( "emmanuel", u.getName() );
+		s.delete( u );
+
+		t.commit();
+		s.close();
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/NaturalIdTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/User.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/User.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/User.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+  This mapping illustrates use of <natural-id>.
+  
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.naturalid"
+	default-access="field">
+	
+	<class name="User" table="SystemUserInfo">
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		<natural-id>
+			<property name="name"/>
+			<property name="org"/>
+		</natural-id>
+		<property name="password"/>
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/User.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+//$Id: User.java 6900 2005-05-25 01:24:22Z oneovthafew $
+package org.hibernate.test.naturalid;
+
+/**
+ * @author Gavin King
+ */
+public class User {
+	
+	private Long id;
+	private String name;
+	private String org;
+	private String password;
+	
+	User() {}
+
+	public User(String name, String org, String password) {
+		this.name = name;
+		this.org = org;
+		this.password = password;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setPassword(String password) {
+		this.password = password;
+	}
+
+	public String getOrg() {
+		return org;
+	}
+	
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/naturalid/User.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,11 @@
+//$Id: Address.java 7119 2005-06-12 22:03:30Z oneovthafew $
+package org.hibernate.test.ondelete;
+
+/**
+ * @author Gavin King
+ */
+public class Address {
+	public String address;
+	public String zip;
+	public String country;
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Address.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Employee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Employee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Employee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: Employee.java 7119 2005-06-12 22:03:30Z oneovthafew $
+package org.hibernate.test.ondelete;
+
+import java.math.BigDecimal;
+
+/**
+ * @author Gavin King
+ */
+public class Employee extends Person {
+	private String title;
+	private BigDecimal salary;
+	private Employee manager;
+	/**
+	 * @return Returns the title.
+	 */
+	public String getTitle() {
+		return title;
+	}
+	/**
+	 * @param title The title to set.
+	 */
+	public void setTitle(String title) {
+		this.title = title;
+	}
+	/**
+	 * @return Returns the manager.
+	 */
+	public Employee getManager() {
+		return manager;
+	}
+	/**
+	 * @param manager The manager to set.
+	 */
+	public void setManager(Employee manager) {
+		this.manager = manager;
+	}
+	/**
+	 * @return Returns the salary.
+	 */
+	public BigDecimal getSalary() {
+		return salary;
+	}
+	/**
+	 * @param salary The salary to set.
+	 */
+	public void setSalary(BigDecimal salary) {
+		this.salary = salary;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Employee.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/OnDeleteTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/OnDeleteTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/OnDeleteTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,94 @@
+//$Id: OnDeleteTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.ondelete;
+
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.dialect.MySQLInnoDBDialect;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.stat.Statistics;
+
+/**
+ * @author Gavin King
+ */
+public class OnDeleteTest extends FunctionalTestCase {
+	
+	public OnDeleteTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "ondelete/Person.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( OnDeleteTest.class );
+	}
+	
+	public void testJoinedSubclass() {
+		if ( ! supportsCircularCascadeDelete() ) {
+			return;
+		}
+
+		Statistics statistics = getSessions().getStatistics();
+		statistics.clear();
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		
+		Salesperson mark = new Salesperson();
+		mark.setName("Mark");
+		mark.setTitle("internal sales");
+		mark.setSex('M');
+		mark.setAddress("buckhead");
+		mark.setZip("30305");
+		mark.setCountry("USA");
+		
+		Person joe = new Person();
+		joe.setName("Joe");
+		joe.setAddress("San Francisco");
+		joe.setZip("XXXXX");
+		joe.setCountry("USA");
+		joe.setSex('M');
+		joe.setSalesperson(mark);
+		mark.getCustomers().add(joe);
+				
+		s.save(mark);
+		
+		t.commit();
+		
+		assertEquals( statistics.getEntityInsertCount(), 2 );
+		assertEquals( statistics.getPrepareStatementCount(), 5 );
+		
+		statistics.clear();
+		
+		t = s.beginTransaction();
+		s.delete(mark);
+		t.commit();
+
+		assertEquals( statistics.getEntityDeleteCount(), 2 );
+		if ( !(getDialect() instanceof MySQLDialect) || (getDialect() instanceof MySQLInnoDBDialect) ) {
+			assertEquals( statistics.getPrepareStatementCount(), 1 );
+		}
+		
+		t = s.beginTransaction();
+		List names = s.createQuery("select name from Person").list();
+		assertTrue( names.isEmpty() );
+		t.commit();
+
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/OnDeleteTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates the use of database-level
+  cascade delete.
+     
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.ondelete"
+	default-access="field">
+	
+	<class name="Person" table="ODPerson">
+		
+		<id name="id" 
+				column="person_id">
+			<generator class="increment"/>
+		</id>
+				
+		<property name="name" 
+				not-null="true"
+				length="80"/>
+		<property name="sex" 
+				not-null="true"
+				update="false"/>
+		
+		<component name="address">
+			<property name="address"/>
+			<property name="zip"/>
+			<property name="country"/>
+		</component>
+		
+		<many-to-one name="salesperson"
+					column="salesperson_id"/>
+		
+		<joined-subclass name="Employee" table="ODEmployee">
+			<key column="person_id" 
+					on-delete="cascade"/>
+			<property name="title" 
+					not-null="true" 
+					length="20"/>
+			<property name="salary" 
+					length="0"/>
+			<many-to-one name="manager"/>
+			
+			<joined-subclass name="Salesperson" table="ODSalesperson">
+				<key column="employee_id" 
+						on-delete="cascade"/>
+				<set name="customers" 
+						inverse="true" 
+						cascade="all">
+					<key column="salesperson_id" 
+							on-delete="cascade"/>
+					<one-to-many class="Person"/>
+				</set>
+			</joined-subclass>
+			
+		</joined-subclass>
+				
+	</class>
+	
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Person.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,79 @@
+//$Id: Person.java 7119 2005-06-12 22:03:30Z oneovthafew $
+package org.hibernate.test.ondelete;
+
+
+/**
+ * @author Gavin King
+ */
+public class Person {
+	private long id;
+	private String name;
+	private char sex;
+	private Address address = new Address();
+	private Salesperson salesperson;
+	/**
+	 * @return Returns the address.
+	 */
+	public Address getAddress() {
+		return address;
+	}
+
+	public void setAddress(String string) {
+		this.address.address = string;
+	}
+
+	public void setZip(String string) {
+		this.address.zip = string;
+	}
+
+	public void setCountry(String string) {
+		this.address.country = string;
+	}
+
+	
+	/**
+	 * @return Returns the sex.
+	 */
+	public char getSex() {
+		return sex;
+	}
+	/**
+	 * @param sex The sex to set.
+	 */
+	public void setSex(char sex) {
+		this.sex = sex;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the identity.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param identity The identity to set.
+	 */
+	public void setName(String identity) {
+		this.name = identity;
+	}
+
+	public Salesperson getSalesperson() {
+		return salesperson;
+	}
+
+	public void setSalesperson(Salesperson salesperson) {
+		this.salesperson = salesperson;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Salesperson.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Salesperson.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Salesperson.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+//$Id: Salesperson.java 7119 2005-06-12 22:03:30Z oneovthafew $
+package org.hibernate.test.ondelete;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class Salesperson extends Employee {
+	private Set customers = new HashSet();
+
+	public Set getCustomers() {
+		return customers;
+	}
+
+	public void setCustomers(Set customers) {
+		this.customers = customers;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ondelete/Salesperson.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Child.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Child.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Child.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+//$Id: Child.java 4378 2004-08-19 10:12:11Z oneovthafew $
+package org.hibernate.test.onetomany;
+
+/**
+ * @author gavin
+ */
+public class Child {
+	private Long id;
+	private String name;
+	private Parent parent;
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	/**
+	 * @return Returns the parent.
+	 */
+	public Parent getParent() {
+		return parent;
+	}
+	/**
+	 * @param parent The parent to set.
+	 */
+	public void setParent(Parent parent) {
+		this.parent = parent;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Child.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/OneToManyTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/OneToManyTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/OneToManyTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,94 @@
+//$Id: OneToManyTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.onetomany;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class OneToManyTest extends FunctionalTestCase {
+	
+	public OneToManyTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "onetomany/Parent.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( OneToManyTest.class );
+	}
+	
+	public void testOneToManyLinkTable() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Child c = new Child();
+		c.setName("Child One");
+		Parent p = new Parent();
+		p.setName("Parent");
+		p.getChildren().add(c);
+		c.setParent(p);
+		s.save(p);
+		s.flush();
+		
+		p.getChildren().remove(c);
+		c.setParent(null);
+		s.flush();
+		
+		p.getChildren().add(c);
+		c.setParent(p);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		c.setParent(null);
+		s.update(c);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c.setParent(p);
+		s.update(c);
+		t.commit();
+		s.close();
+
+		
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Child) s.createQuery("from Child").uniqueResult();
+		s.createQuery("from Child c left join fetch c.parent").list();
+		s.createQuery("from Child c inner join fetch c.parent").list();
+		s.clear();
+		p = (Parent) s.createQuery("from Parent p left join fetch p.children").uniqueResult();
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery("delete from Child").executeUpdate();
+		s.createQuery("delete from Parent").executeUpdate();		
+		t.commit();
+		s.close();
+
+	}
+
+	public void testManyToManySize() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		//this test raise an exception right now HHH-570
+		assertEquals( 0, s.createQuery("from Parent p where size(p.children) = 0").list().size() );
+		assertEquals( 0, s.createQuery("from Parent p where p.children.size = 0").list().size() );
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/OneToManyTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Parent.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Parent.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Parent.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates how to use an "inverse" join
+  to map an association table as an association with 
+  one-to-many multiplicity at the level of the object
+  model.
+     
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.onetomany">
+
+	<class name="Parent">
+		<id name="id" 
+			column="parent_id">
+			<generator class="increment"/>
+		</id>
+		<property name="name"/>
+		<set name="children" 
+			table="ParentChild" 
+			cascade="all"
+			inverse="true">
+			<key column="parent_id"/>
+			<many-to-many column="child_id" 
+				class="Child"/>
+		</set>
+	</class>
+	
+	<class name="Child">
+		<id name="id" 
+			column="child_id">
+			<generator class="increment"/>
+		</id>
+		<property name="name"/>
+		<join table="ParentChild" 
+			optional="true">
+			<key column="child_id"/>
+			<many-to-one name="parent" 
+				column="parent_id" 
+				not-null="true"/>
+		</join>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Parent.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Parent.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Parent.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Parent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+//$Id: Parent.java 4378 2004-08-19 10:12:11Z oneovthafew $
+package org.hibernate.test.onetomany;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * @author gavin
+ */
+public class Parent {
+	private Long id;
+	private String name;
+	private Collection children = new HashSet();
+	/**
+	 * @return Returns the children.
+	 */
+	public Collection getChildren() {
+		return children;
+	}
+	/**
+	 * @param children The children to set.
+	 */
+	public void setChildren(Collection children) {
+		this.children = children;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetomany/Parent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/OneToOneSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/OneToOneSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/OneToOneSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+package org.hibernate.test.onetoone;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.onetoone.formula.OneToOneFormulaTest;
+import org.hibernate.test.onetoone.joined.JoinedSubclassOneToOneTest;
+import org.hibernate.test.onetoone.link.OneToOneLinkTest;
+import org.hibernate.test.onetoone.nopojo.DynamicMapOneToOneTest;
+import org.hibernate.test.onetoone.optional.OptionalOneToOneTest;
+import org.hibernate.test.onetoone.singletable.DiscrimSubclassOneToOneTest;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class OneToOneSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "one-to-one suite" );
+		suite.addTest( OneToOneFormulaTest.suite() );
+		suite.addTest( JoinedSubclassOneToOneTest.suite() );
+		suite.addTest( OneToOneLinkTest.suite() );
+		suite.addTest( DynamicMapOneToOneTest.suite() );
+		suite.addTest( OptionalOneToOneTest.suite() );
+		suite.addTest( DiscrimSubclassOneToOneTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+//$Id: Address.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.onetoone.formula;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Address implements Serializable {
+	private Person person;
+	private String type;
+	private String street;
+	private String state;
+	private String zip;
+	
+	public Person getPerson() {
+		return person;
+	}
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+	public String getState() {
+		return state;
+	}
+	public void setState(String state) {
+		this.state = state;
+	}
+	public String getStreet() {
+		return street;
+	}
+	public void setStreet(String street) {
+		this.street = street;
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getZip() {
+		return zip;
+	}
+	public void setZip(String zip) {
+		this.zip = zip;
+	}
+	
+	public boolean equals(Object that) {
+		if ( !(that instanceof Address) ) return false;
+		Address address = (Address) that;
+		return address.getType().equals(type) && 
+			address.getPerson().getName().equals( person.getName() );
+	}
+	
+	public int hashCode() {
+		return person.getName().hashCode() + type.hashCode();
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Address.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/OneToOneFormulaTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/OneToOneFormulaTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/OneToOneFormulaTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,164 @@
+//$Id: OneToOneFormulaTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.onetoone.formula;
+
+import junit.framework.Test;
+
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.Property;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class OneToOneFormulaTest extends FunctionalTestCase {
+	
+	public OneToOneFormulaTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "onetoone/formula/Person.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "false");
+		cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+		cfg.setProperty(Environment.DEFAULT_BATCH_FETCH_SIZE, "2");
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( OneToOneFormulaTest.class );
+	}
+	
+	public void testOneToOneFormula() {
+		Person p = new Person();
+		p.setName("Gavin King");
+		Address a = new Address();
+		a.setPerson(p);
+		a.setType("HOME");
+		a.setZip("3181");
+		a.setState("VIC");
+		a.setStreet("Karbarook Ave");
+		p.setAddress(a);
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.persist(p);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		p = (Person) s.createQuery("from Person").uniqueResult();
+		
+		assertNotNull( p.getAddress() );
+		assertTrue( Hibernate.isInitialized( p.getAddress() ) );
+		assertNull( p.getMailingAddress() );
+
+		s.clear();
+
+		p = (Person) s.createQuery("from Person p left join fetch p.mailingAddress left join fetch p.address").uniqueResult();
+
+		assertNotNull( p.getAddress() );
+		assertTrue( Hibernate.isInitialized( p.getAddress() ) );
+		assertNull( p.getMailingAddress() );
+
+		s.clear();
+
+		p = (Person) s.createQuery("from Person p left join fetch p.address").uniqueResult();
+
+		assertNotNull( p.getAddress() );
+		assertTrue( Hibernate.isInitialized( p.getAddress() ) );
+		assertNull( p.getMailingAddress() );
+
+		s.clear();
+
+		p = (Person) s.createCriteria(Person.class)
+			.createCriteria("address")
+				.add( Property.forName("zip").eq("3181") )
+			.uniqueResult();
+		assertNotNull(p);
+		
+		s.clear();
+
+		p = (Person) s.createCriteria(Person.class)
+			.setFetchMode("address", FetchMode.JOIN)
+			.uniqueResult();
+
+		assertNotNull( p.getAddress() );
+		assertTrue( Hibernate.isInitialized( p.getAddress() ) );
+		assertNull( p.getMailingAddress() );
+		
+		s.clear();
+
+		p = (Person) s.createCriteria(Person.class)
+			.setFetchMode("mailingAddress", FetchMode.JOIN)
+			.uniqueResult();
+
+		assertNotNull( p.getAddress() );
+		assertTrue( Hibernate.isInitialized( p.getAddress() ) );
+		assertNull( p.getMailingAddress() );
+		
+		s.delete(p);
+		
+		t.commit();
+		s.close();
+		
+	}
+	
+	public void testOneToOneEmbeddedCompositeKey() {
+		Person p = new Person();
+		p.setName("Gavin King");
+		Address a = new Address();
+		a.setPerson(p);
+		a.setType("HOME");
+		a.setZip("3181");
+		a.setState("VIC");
+		a.setStreet("Karbarook Ave");
+		p.setAddress(a);
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.persist(p);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		
+		a = new Address();
+		a.setType("HOME");
+		a.setPerson(p);
+		a = (Address) s.load(Address.class, a);
+		assertFalse( Hibernate.isInitialized(a) );
+		a.getPerson();
+		a.getType();
+		assertFalse( Hibernate.isInitialized(a) );
+		assertEquals(a.getZip(), "3181");
+		
+		s.clear();
+		
+		a = new Address();
+		a.setType("HOME");
+		a.setPerson(p);
+		Address a2 = (Address) s.get(Address.class, a);
+		assertTrue( Hibernate.isInitialized(a) );
+		assertSame(a2, a);
+		assertSame(a2.getPerson(), p); //this is a little bit desirable
+		assertEquals(a.getZip(), "3181");
+		
+		s.delete(a2);
+		s.delete( s.get( Person.class, p.getName() ) ); //this is certainly undesirable! oh well...
+		
+		t.commit();
+		s.close();
+		
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/OneToOneFormulaTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.onetoone.formula">
+
+	<class name="Person">
+		<id name="name"/>
+		<one-to-one name="address" cascade="all" constrained="false">
+			<formula>name</formula>
+			<formula>'HOME'</formula>
+		</one-to-one>
+		<one-to-one name="mailingAddress" constrained="false">
+			<formula>name</formula>
+			<formula>'MAILING'</formula>
+		</one-to-one>
+	</class>
+	
+	<class name="Address" batch-size="2" 
+			check="addressType in ('MAILING', 'HOME', 'BUSINESS')">
+		<composite-id>
+			<key-many-to-one name="person" 
+					column="personName"/>
+			<key-property name="type" 
+					column="addressType"/>
+		</composite-id>
+		<property name="street" type="text"/>
+		<property name="state"/>
+		<property name="zip"/>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Person.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+//$Id: Person.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.onetoone.formula;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Person implements Serializable {
+	private String name;
+	private Address address;
+	private Address mailingAddress;
+	
+	public Address getAddress() {
+		return address;
+	}
+	public void setAddress(Address address) {
+		this.address = address;
+	}
+	public Address getMailingAddress() {
+		return mailingAddress;
+	}
+	public void setMailingAddress(Address mailingAddress) {
+		this.mailingAddress = mailingAddress;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public boolean equals(Object that) {
+		if ( !(that instanceof Person) ) return false;
+		Person person = (Person) that;
+		return person.getName().equals(name);
+	}
+	
+	public int hashCode() {
+		return name.hashCode();
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/formula/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,16 @@
+//$Id: Address.java 9914 2006-05-09 09:37:18Z max.andersen at jboss.com $
+package org.hibernate.test.onetoone.joined;
+
+/**
+ * @author Gavin King
+ */
+public class Address {
+	public String entityName;
+	public String street;
+	public String state;
+	public String zip;
+	
+	public String toString() {
+		return this.getClass() + ":" + street;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Address.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Entity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Entity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Entity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+//$Id: Entity.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.onetoone.joined;
+
+/**
+ * @author Gavin King
+ */
+public class Entity {
+	public String name;
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Entity.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/JoinedSubclassOneToOneTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/JoinedSubclassOneToOneTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/JoinedSubclassOneToOneTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,159 @@
+//$Id: JoinedSubclassOneToOneTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.onetoone.joined;
+
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.stat.EntityStatistics;
+
+/**
+ * @author Gavin King
+ */
+public class JoinedSubclassOneToOneTest extends FunctionalTestCase {
+	
+	public JoinedSubclassOneToOneTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "onetoone/joined/Person.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "false");
+		cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( JoinedSubclassOneToOneTest.class );
+	}
+
+	public void testOneToOneOnSubclass() {
+		Person p = new Person();
+		p.name = "Gavin";
+		Address a = new Address();
+		a.entityName = "Gavin";
+		a.zip = "3181";
+		a.state = "VIC";
+		a.street = "Karbarook Ave";
+		p.address = a;
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.persist(p);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		
+		EntityStatistics addressStats = getSessions().getStatistics().getEntityStatistics( Address.class.getName() );
+		EntityStatistics mailingAddressStats = getSessions().getStatistics().getEntityStatistics("MailingAddress");
+
+		p = (Person) s.createQuery("from Person p join fetch p.address left join fetch p.mailingAddress").uniqueResult();
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		s.clear();
+
+		p = (Person) s.createQuery("select p from Person p join fetch p.address left join fetch p.mailingAddress").uniqueResult();
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		s.clear();
+
+		Object[] stuff = (Object[]) s.createQuery("select p.name, p from Person p join fetch p.address left join fetch p.mailingAddress").uniqueResult();
+		assertEquals(stuff.length, 2);
+		p = (Person) stuff[1];
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		s.clear();
+
+		assertEquals( addressStats.getFetchCount(), 0 );
+		assertEquals( mailingAddressStats.getFetchCount(), 0 );
+		
+		p = (Person) s.createQuery("from Person p join fetch p.address").uniqueResult();
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		s.clear();
+		
+		assertEquals( addressStats.getFetchCount(), 0 );
+		assertEquals( mailingAddressStats.getFetchCount(), 1 );
+
+		p = (Person) s.createQuery("from Person").uniqueResult();
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		s.clear();
+		
+		assertEquals( addressStats.getFetchCount(), 0 );
+		assertEquals( mailingAddressStats.getFetchCount(), 2 );
+
+		p = (Person) s.createQuery("from Entity").uniqueResult();
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		s.clear();
+		
+		assertEquals( addressStats.getFetchCount(), 0 );
+		assertEquals( mailingAddressStats.getFetchCount(), 3 );
+
+		//note that in here join fetch is used for the nullable
+		//one-to-one, due to a very special case of default
+		p = (Person) s.get(Person.class, "Gavin");
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		s.clear();
+		
+		assertEquals( addressStats.getFetchCount(), 0 );
+		assertEquals( mailingAddressStats.getFetchCount(), 3 );
+
+		p = (Person) s.get(Entity.class, "Gavin");
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		s.clear();
+		
+		assertEquals( addressStats.getFetchCount(), 0 );
+		assertEquals( mailingAddressStats.getFetchCount(), 3 );
+		
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		Org org = new Org();
+		org.name = "IFA";
+		Address a2 = new Address();
+		a2.entityName = "IFA";
+		a2.zip = "3181";
+		a2.state = "VIC";
+		a2.street = "Orrong Rd";
+		s.persist(org);
+		s.persist(a2);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		org = (Org) s.get(Entity.class, "IFA");
+		s.clear();
+		
+		List list = s.createQuery("from Entity e order by e.name").list();
+		p = (Person) list.get(0);
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		org = (Org) list.get(1);
+		s.clear();
+		
+		list = s.createQuery("from Entity e left join fetch e.address left join fetch e.mailingAddress order by e.name").list();
+		p = (Person) list.get(0);
+		org = (Org) list.get(1);
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		
+		s.clear();
+		s.delete(p);
+		s.delete( p.address );
+		s.delete( org );
+		s.delete( a2 );
+		s.flush();
+		t.commit();
+		s.close();
+		
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/JoinedSubclassOneToOneTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Org.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Org.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Org.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+//$Id: Org.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.onetoone.joined;
+
+
+/**
+ * @author Gavin King
+ */
+public class Org extends Entity {
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Org.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.onetoone.joined"
+	default-access="field">
+
+	<class name="Entity">
+		<id name="name"/>
+		<joined-subclass name="Person">
+			<key column="entityName"/>
+			<one-to-one name="address" 
+				cascade="all" 
+				constrained="true"/>
+			<one-to-one name="mailingAddress" 
+				cascade="all"
+				entity-name="MailingAddress"/>
+		</joined-subclass>
+		<joined-subclass name="Org">
+			<key column="entityName"/>
+		</joined-subclass>
+	</class>
+	
+	<class name="Address">
+		<id name="entityName"/>
+		<property name="street"/>
+		<property name="state"/>
+		<property name="zip"/>
+	</class>
+
+	<class name="Address" entity-name="MailingAddress">
+		<id name="entityName"/>
+		<property name="street"/>
+		<property name="state"/>
+		<property name="zip"/>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Person.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+//$Id: Person.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.onetoone.joined;
+
+/**
+ * @author Gavin King
+ */
+public class Person extends Entity {
+	public Address address;
+	public Address mailingAddress;
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/joined/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: Customer.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.onetoone.link;
+
+/**
+ * @author Gavin King
+ */
+public class Customer {
+	private Long id;
+	private Person person;
+	public Person getPerson() {
+		return person;
+	}
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Customer.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Employee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Employee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Employee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+//$Id: Employee.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.onetoone.link;
+
+/**
+ * @author Gavin King
+ */
+public class Employee {
+	private Long id;
+	private Person person;
+	public Person getPerson() {
+		return person;
+	}
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Employee.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/OneToOneLinkTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/OneToOneLinkTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/OneToOneLinkTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,91 @@
+//$Id: OneToOneLinkTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.onetoone.link;
+
+import java.util.Date;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class OneToOneLinkTest extends FunctionalTestCase {
+	
+	public OneToOneLinkTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "onetoone/link/Person.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( OneToOneLinkTest.class );
+	}
+	
+	public void testOneToOneViaAssociationTable() {
+		Person p = new Person();
+		p.setName("Gavin King");
+		p.setDob( new Date() );
+		Employee e = new Employee();
+		p.setEmployee(e);
+		e.setPerson(p);
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.persist(p);
+		t.commit();
+		s.close();
+	
+		s = openSession();
+		t = s.beginTransaction();
+		e = (Employee) s.createQuery("from Employee e where e.person.name like 'Gavin%'").uniqueResult();
+		assertEquals( e.getPerson().getName(), "Gavin King" );
+		assertFalse( Hibernate.isInitialized( e.getPerson() ) );
+		assertNull( e.getPerson().getCustomer() );
+		s.clear();
+
+		e = (Employee) s.createQuery("from Employee e where e.person.dob = :date")
+			.setDate("date", new Date() )
+			.uniqueResult();
+		assertEquals( e.getPerson().getName(), "Gavin King" );
+		assertFalse( Hibernate.isInitialized( e.getPerson() ) );
+		assertNull( e.getPerson().getCustomer() );
+		s.clear();
+		
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+
+		e = (Employee) s.createQuery("from Employee e join fetch e.person p left join fetch p.customer").uniqueResult();
+		assertTrue( Hibernate.isInitialized( e.getPerson() ) );
+		assertNull( e.getPerson().getCustomer() );
+		Customer c = new Customer();
+		e.getPerson().setCustomer(c);
+		c.setPerson( e.getPerson() );
+		
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+
+		e = (Employee) s.createQuery("from Employee e join fetch e.person p left join fetch p.customer").uniqueResult();
+		assertTrue( Hibernate.isInitialized( e.getPerson() ) );
+		assertTrue( Hibernate.isInitialized( e.getPerson().getCustomer() ) );
+		assertNotNull( e.getPerson().getCustomer() );
+		s.delete(e);
+		t.commit();
+		s.close();
+		
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/OneToOneLinkTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+	
+	<!-- 
+		
+		Demonstrates the mapping of two subtyping one-to-one relationships 
+		to association tables using <many-to-one> nested inside <join>.
+		Note that the <join> elements specify optional="true", and that
+		there is an inverse="true" side of both joins.	
+		
+	-->
+
+<hibernate-mapping package="org.hibernate.test.onetoone.link">
+
+	<class name="Person">
+		<id name="name"/>
+		<property name="dob" type="date"/>
+		<join table="employeePerson" 
+		        inverse="true" 
+		        optional="true">
+			<key column="personId" unique="true"/>
+			<many-to-one name="employee" 
+				column="employeeId" 
+				cascade="all" 
+				not-null="true"/>
+		</join>
+		<join table="customerPerson" 
+		        inverse="true" 
+		        optional="true">
+			<key column="personId" unique="true"/>
+			<many-to-one name="customer" 
+				column="customerId" 
+				cascade="all" 
+				not-null="true"/>
+		</join>
+	</class>
+	
+	<class name="Employee">
+		<id name="id" column="employeeId">
+			<generator class="native"/>
+		</id>
+		<join table="employeePerson" 
+		        optional="true">
+			<key column="employeeId"/>
+			<many-to-one name="person" 
+				column="personId" 
+				cascade="all" 
+				not-null="true"
+				unique="true"/>
+		</join>
+	</class>
+
+	<class name="Customer">
+		<id name="id" column="customerId">
+			<generator class="native"/>
+		</id>
+		<join table="customerPerson" optional="true">
+			<key column="customerId"/>
+			<many-to-one name="person" 
+				column="personId" 
+				cascade="all" 
+				not-null="true"
+				unique="true"/>
+		</join>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Person.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: Person.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.onetoone.link;
+
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class Person {
+	private String name;
+	private Date dob;
+	private Employee employee;
+	private Customer customer;
+	public Customer getCustomer() {
+		return customer;
+	}
+	public void setCustomer(Customer customer) {
+		this.customer = customer;
+	}
+	public Employee getEmployee() {
+		return employee;
+	}
+	public void setEmployee(Employee employee) {
+		this.employee = employee;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public Date getDob() {
+		return dob;
+	}
+	public void setDob(Date dob) {
+		this.dob = dob;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/link/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/nopojo/DynamicMapOneToOneTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/nopojo/DynamicMapOneToOneTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/nopojo/DynamicMapOneToOneTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,82 @@
+//$Id: DynamicMapOneToOneTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.onetoone.nopojo;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.Test;
+
+import org.hibernate.EntityMode;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.stat.EntityStatistics;
+
+/**
+ * @author Gavin King
+ */
+public class DynamicMapOneToOneTest extends FunctionalTestCase {
+
+	public DynamicMapOneToOneTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "onetoone/nopojo/Person.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "false");
+		cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+		cfg.setProperty( Environment.DEFAULT_ENTITY_MODE, EntityMode.MAP.toString() );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( DynamicMapOneToOneTest.class );
+	}
+
+	public void testOneToOneOnSubclass() {
+		Map person = new HashMap();
+		person.put( "name", "Steve" );
+		Map address = new HashMap();
+		address.put( "zip", "12345" );
+		address.put( "state", "TX" );
+		address.put( "street", "123 Main St" );
+
+		person.put( "address", address );
+		address.put( "owner", person );
+
+		Session s = openSession();
+		s.beginTransaction();
+		s.persist( "Person", person );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+
+		EntityStatistics addressStats = getSessions().getStatistics().getEntityStatistics( "Address" );
+
+		person = ( Map ) s.createQuery( "from Person p join fetch p.address" ).uniqueResult();
+		assertNotNull( "could not locate person", person );
+		assertNotNull( "could not locate persons address", person.get( "address" ) );
+		s.clear();
+
+		Object[] tuple = ( Object[] ) s.createQuery( "select p.name, p from Person p join fetch p.address" ).uniqueResult();
+		assertEquals( tuple.length, 2 );
+		person = ( Map ) tuple[1];
+		assertNotNull( "could not locate person", person );
+		assertNotNull( "could not locate persons address", person.get( "address" ) );
+
+		s.delete( "Person", person );
+
+		s.getTransaction().commit();
+		s.close();
+
+		assertEquals( addressStats.getFetchCount(), 0 );
+	}
+
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/nopojo/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/nopojo/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/nopojo/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.onetoone.nopojo">
+
+	<class entity-name="Person">
+		<id name="id" type="long">
+            <generator class="foreign">
+                <param name="property">address</param>
+            </generator>
+        </id>
+        <property name="name" type="string"/>
+        <one-to-one name="address" cascade="all" entity-name="Address" constrained="true"/>
+	</class>
+	
+	<class entity-name="Address">
+		<id name="id" type="long">
+            <generator class="native"/>
+        </id>
+		<property name="street" type="string"/>
+		<property name="state" type="string"/>
+		<property name="zip" type="string"/>
+        <one-to-one name="owner" entity-name="Person" />
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,15 @@
+package org.hibernate.test.onetoone.optional;
+
+/**
+ * @author Gavin King
+ */
+public class Address {
+	public String entityName;
+	public String street;
+	public String state;
+	public String zip;
+
+	public String toString() {
+		return this.getClass() + ":" + street;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Entity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Entity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Entity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+package org.hibernate.test.onetoone.optional;
+
+/**
+ * @author Gavin King
+ */
+public class Entity {
+	public String name;
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/OptionalOneToOneTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/OptionalOneToOneTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/OptionalOneToOneTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+package org.hibernate.test.onetoone.optional;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.Session;
+
+/**
+ * @author Gavin King
+ */
+public class OptionalOneToOneTest extends FunctionalTestCase {
+
+	public OptionalOneToOneTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "onetoone/optional/Person.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false");
+		cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( OptionalOneToOneTest.class );
+	}
+
+	public void testOptionalOneToOneRetrieval() {
+		Session s = openSession();
+		s.beginTransaction();
+		Person me = new Person();
+		me.name = "Steve";
+		s.save( me );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		me = ( Person ) s.load( Person.class, me.name );
+		assertNull( me.address );
+		s.delete( me );
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Org.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Org.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Org.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,8 @@
+package org.hibernate.test.onetoone.optional;
+
+
+/**
+ * @author Gavin King
+ */
+public class Org extends Entity {
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates mapping an "optional" one-to-one association.  Basically
+    a (zero or one)-to-one.
+
+    Note that this is only conceptually possible on the non-constrained
+    side of the association (the side without the FK).
+
+    Also, it is impossible that the optional side be lazy; we must hit the
+    target table to determine whether a matching row actually exists or not.
+    This is so we can properly determine whether to use null or some value
+    for the association property's value.
+-->
+<hibernate-mapping package="org.hibernate.test.onetoone.optional" default-access="field">
+
+	<class name="Entity">
+		<id name="name"/>
+		<joined-subclass name="Person">
+			<key column="entityName"/>
+			<one-to-one name="address" cascade="all" constrained="false" outer-join="false" lazy="proxy"/>
+		</joined-subclass>
+		<joined-subclass name="Org">
+			<key column="entityName"/>
+		</joined-subclass>
+	</class>
+
+	<class name="Address">
+		<id name="entityName"/>
+		<property name="street"/>
+		<property name="state"/>
+		<property name="zip"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/optional/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+package org.hibernate.test.onetoone.optional;
+
+/**
+ * @author Gavin King
+ */
+public class Person extends Entity {
+	public Address address;
+	public Address mailingAddress;
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,12 @@
+//$Id: Address.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.onetoone.singletable;
+
+/**
+ * @author Gavin King
+ */
+public class Address {
+	public String entityName;
+	public String street;
+	public String state;
+	public String zip;
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Address.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/DiscrimSubclassOneToOneTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/DiscrimSubclassOneToOneTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/DiscrimSubclassOneToOneTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,148 @@
+//$Id: DiscrimSubclassOneToOneTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.onetoone.singletable;
+
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.stat.EntityStatistics;
+
+/**
+ * @author Gavin King
+ */
+public class DiscrimSubclassOneToOneTest extends FunctionalTestCase {
+	
+	public DiscrimSubclassOneToOneTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "onetoone/singletable/Person.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "false");
+		cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( DiscrimSubclassOneToOneTest.class );
+	}
+	
+	public void testOneToOneOnSubclass() {
+		Person p = new Person();
+		p.name = "Gavin";
+		Address a = new Address();
+		a.entityName = "Gavin";
+		a.zip = "3181";
+		a.state = "VIC";
+		a.street = "Karbarook Ave";
+		p.address = a;
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.persist(p);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		
+		EntityStatistics addressStats = getSessions().getStatistics().getEntityStatistics( Address.class.getName() );
+		EntityStatistics mailingAddressStats = getSessions().getStatistics().getEntityStatistics("MailingAddress");
+
+		p = (Person) s.createQuery("from Person p join fetch p.address left join fetch p.mailingAddress").uniqueResult();
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		s.clear();
+
+		assertEquals( addressStats.getFetchCount(), 0 );
+		assertEquals( mailingAddressStats.getFetchCount(), 0 );
+		
+		p = (Person) s.createQuery("from Person p join fetch p.address").uniqueResult();
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		s.clear();
+		
+		assertEquals( addressStats.getFetchCount(), 0 );
+		assertEquals( mailingAddressStats.getFetchCount(), 1 );
+
+		p = (Person) s.createQuery("from Person").uniqueResult();
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		s.clear();
+		
+		assertEquals( addressStats.getFetchCount(), 1 );
+		assertEquals( mailingAddressStats.getFetchCount(), 2 );
+
+		p = (Person) s.createQuery("from Entity").uniqueResult();
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		s.clear();
+		
+		assertEquals( addressStats.getFetchCount(), 2 );
+		assertEquals( mailingAddressStats.getFetchCount(), 3 );
+
+		//note that in here join fetch is used for the nullable
+		//one-to-one, due to a very special case of default
+		p = (Person) s.get(Person.class, "Gavin");
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		s.clear();
+		
+		assertEquals( addressStats.getFetchCount(), 2 );
+		assertEquals( mailingAddressStats.getFetchCount(), 3 );
+
+		p = (Person) s.get(Entity.class, "Gavin");
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		s.clear();
+		
+		assertEquals( addressStats.getFetchCount(), 2 );
+		assertEquals( mailingAddressStats.getFetchCount(), 3 );
+		
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		Org org = new Org();
+		org.name = "IFA";
+		Address a2 = new Address();
+		a2.entityName = "IFA";
+		a2.zip = "3181";
+		a2.state = "VIC";
+		a2.street = "Orrong Rd";
+		org.addresses.add(a2);
+		s.persist(org);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		org = (Org) s.get(Entity.class, "IFA");
+		s.clear();
+		
+		List list = s.createQuery("from Entity e order by e.name").list();
+		p = (Person) list.get(0);
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		org = (Org) list.get(1);
+		assertEquals( org.addresses.size(), 1 );
+		s.clear();
+		
+		list = s.createQuery("from Entity e left join fetch e.address left join fetch e.mailingAddress order by e.name").list();
+		p = (Person) list.get(0);
+		org = (Org) list.get(1);
+		assertNotNull(p.address); assertNull(p.mailingAddress);
+		assertEquals( org.addresses.size(), 1 );
+		
+		s.delete(p);
+		s.delete(org);
+		
+		t.commit();
+		s.close();
+		
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/DiscrimSubclassOneToOneTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Entity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Entity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Entity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+//$Id: Entity.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.onetoone.singletable;
+
+/**
+ * @author Gavin King
+ */
+public class Entity {
+	public String name;
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Entity.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Org.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Org.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Org.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,12 @@
+//$Id: Org.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.onetoone.singletable;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class Org extends Entity {
+	public Set addresses = new HashSet();
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Org.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.onetoone.singletable"
+	default-access="field">
+
+	<class name="Entity">
+		<id name="name"/>
+		<discriminator type="string" column="subtype"/>
+		<subclass name="Person">
+			<one-to-one name="address" cascade="all"/>
+			<one-to-one name="mailingAddress" 
+				cascade="all"
+				entity-name="MailingAddress"/>
+		</subclass>
+		<subclass name="Org">
+			<set name="addresses" inverse="true" cascade="all-delete-orphan">
+				<key column="entityName"/>
+				<one-to-many class="Address"/>
+			</set>
+		</subclass>
+	</class>
+	
+	<class name="Address">
+		<id name="entityName"/>
+		
+		<property name="street"/>
+		<property name="state"/>
+		<property name="zip"/>
+	</class>
+
+	<class name="Address" entity-name="MailingAddress">
+		<id name="entityName"/>
+		<property name="street"/>
+		<property name="state"/>
+		<property name="zip"/>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Person.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+//$Id: Person.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.onetoone.singletable;
+
+/**
+ * @author Gavin King
+ */
+public class Person extends Entity {
+	public Address address;
+	public Address mailingAddress;
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/onetoone/singletable/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/AbstractOperationTestCase.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/AbstractOperationTestCase.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/AbstractOperationTestCase.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+package org.hibernate.test.ops;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractOperationTestCase extends FunctionalTestCase {
+	public AbstractOperationTestCase(String name) {
+		super( name );
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true");
+		cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "0" );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "ops/Node.hbm.xml", "ops/Employer.hbm.xml", "ops/OptLockEntity.hbm.xml", "ops/OneToOne.hbm.xml", "ops/Competition.hbm.xml" };
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	protected void clearCounts() {
+		getSessions().getStatistics().clear();
+	}
+
+	protected void assertInsertCount(int expected) {
+		int inserts = ( int ) getSessions().getStatistics().getEntityInsertCount();
+		assertEquals( "unexpected insert count", expected, inserts );
+	}
+
+	protected void assertUpdateCount(int expected) {
+		int updates = ( int ) getSessions().getStatistics().getEntityUpdateCount();
+		assertEquals( "unexpected update counts", expected, updates );
+	}
+
+	protected void assertDeleteCount(int expected) {
+		int deletes = ( int ) getSessions().getStatistics().getEntityDeleteCount();
+		assertEquals( "unexpected delete counts", expected, deletes );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,65 @@
+package org.hibernate.test.ops;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Address {
+	private Long id;
+	private String streetAddress;
+	private String city;
+	private String country;
+	private Person resident;
+
+	public Address() {
+	}
+
+	public Address(String streetAddress, String city, String country, Person resident) {
+		this.streetAddress = streetAddress;
+		this.city = city;
+		this.country = country;
+		this.resident = resident;
+		resident.setAddress( this );
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getStreetAddress() {
+		return streetAddress;
+	}
+
+	public void setStreetAddress(String streetAddress) {
+		this.streetAddress = streetAddress;
+	}
+
+	public String getCity() {
+		return city;
+	}
+
+	public void setCity(String city) {
+		this.city = city;
+	}
+
+	public String getCountry() {
+		return country;
+	}
+
+	public void setCountry(String country) {
+		this.country = country;
+	}
+
+	public Person getResident() {
+		return resident;
+	}
+
+	public void setResident(Person resident) {
+		this.resident = resident;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Competition.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Competition.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Competition.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+  
+-->
+
+<hibernate-mapping package="org.hibernate.test.ops">
+	
+	<class name="Competition">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+        <list name="competitors" table="COMPET_ION_OR" cascade="persist,merge,delete">
+			<key column="TION_ID"/>
+			<list-index column="INDEX_COL"/>
+			<many-to-many class="Competitor" column="TOR_ID" />
+		</list>
+	</class>
+	
+	<class name="Competitor">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="name"/>
+	</class>
+	
+</hibernate-mapping>
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Competition.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Competition.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Competition.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+//$Id: $
+package org.hibernate.test.ops;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class Competition {
+	private Integer id;
+
+	private List competitors = new ArrayList();
+
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public List getCompetitors() {
+		return competitors;
+	}
+
+	public void setCompetitors(List competitors) {
+		this.competitors = competitors;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Competitor.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Competitor.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Competitor.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+//$Id: $
+package org.hibernate.test.ops;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class Competitor {
+	public Integer id;
+	private String name;
+
+
+	public Competitor() {
+	}
+
+	public Competitor(String name) {
+		this.name = name;
+	}
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/CreateTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/CreateTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/CreateTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,218 @@
+//$Id: CreateTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.ops;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import junit.framework.Test;
+
+import org.hibernate.PersistentObjectException;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.exception.ConstraintViolationException;
+
+/**
+ * @author Gavin King
+ */
+public class CreateTest extends AbstractOperationTestCase {
+
+	public CreateTest(String str) {
+		super( str );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CreateTest.class );
+	}
+
+	public void testNoUpdatesOnCreateVersionedWithCollection() {
+		clearCounts();
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		VersionedEntity root = new VersionedEntity( "root", "root" );
+		VersionedEntity child = new VersionedEntity( "c1", "child-1" );
+		root.getChildren().add( child );
+		child.setParent( root );
+		s.save(root);
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 2 );
+		assertUpdateCount( 0 );
+		assertDeleteCount( 0 );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.delete( root );
+		tx.commit();
+		s.close();
+
+		assertUpdateCount( 0 );
+		assertDeleteCount( 2 );
+	}
+
+	public void testCreateTree() {
+
+		clearCounts();
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Node root = new Node("root");
+		Node child = new Node("child");
+		root.addChild(child);
+		s.persist(root);
+		tx.commit();
+		s.close();
+
+		assertInsertCount(2);
+		assertUpdateCount(0);
+
+		s = openSession();
+		tx = s.beginTransaction();
+		System.out.println("getting");
+		root = (Node) s.get(Node.class, "root");
+		Node child2 = new Node("child2");
+		root.addChild(child2);
+		System.out.println("committing");
+		tx.commit();
+		s.close();
+
+		assertInsertCount(3);
+		assertUpdateCount(0);
+	}
+
+	public void testCreateTreeWithGeneratedId() {
+
+		clearCounts();
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		NumberedNode root = new NumberedNode("root");
+		NumberedNode child = new NumberedNode("child");
+		root.addChild(child);
+		s.persist(root);
+		tx.commit();
+		s.close();
+
+		assertInsertCount(2);
+		assertUpdateCount(0);
+
+		s = openSession();
+		tx = s.beginTransaction();
+		root = (NumberedNode) s.get( NumberedNode.class, new Long( root.getId() ) );
+		NumberedNode child2 = new NumberedNode("child2");
+		root.addChild(child2);
+		tx.commit();
+		s.close();
+
+		assertInsertCount(3);
+		assertUpdateCount(0);
+	}
+
+	public void testCreateException() {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Node dupe = new Node("dupe");
+		s.persist(dupe);
+		s.persist(dupe);
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.persist(dupe);
+		try {
+			tx.commit();
+			assertFalse(true);
+		}
+		catch (ConstraintViolationException cve) {
+			//verify that an exception is thrown!
+		}
+		tx.rollback();
+		s.close();
+
+		Node nondupe = new Node("nondupe");
+		nondupe.addChild(dupe);
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.persist(nondupe);
+		try {
+			tx.commit();
+			assertFalse(true);
+		}
+		catch (ConstraintViolationException cve) {
+			//verify that an exception is thrown!
+		}
+		tx.rollback();
+		s.close();
+	}
+
+	public void testCreateExceptionWithGeneratedId() {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		NumberedNode dupe = new NumberedNode("dupe");
+		s.persist(dupe);
+		s.persist(dupe);
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		try {
+			s.persist(dupe);
+			assertFalse(true);
+		}
+		catch (PersistentObjectException poe) {
+			//verify that an exception is thrown!
+		}
+		tx.rollback();
+		s.close();
+
+		NumberedNode nondupe = new NumberedNode("nondupe");
+		nondupe.addChild(dupe);
+
+		s = openSession();
+		tx = s.beginTransaction();
+		try {
+			s.persist(nondupe);
+			assertFalse(true);
+		}
+		catch (PersistentObjectException poe) {
+			//verify that an exception is thrown!
+		}
+		tx.rollback();
+		s.close();
+	}
+
+	public void testBasic() throws Exception {
+		Session s;
+		Transaction tx;
+		s = openSession();
+		tx = s.beginTransaction();
+		Employer er = new Employer();
+		Employee ee = new Employee();
+		s.persist(ee);
+		Collection erColl = new ArrayList();
+		Collection eeColl = new ArrayList();
+		erColl.add(ee);
+		eeColl.add(er);
+		er.setEmployees(erColl);
+		ee.setEmployers(eeColl);
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		er = (Employer) s.load(Employer.class, er.getId() );
+		assertNotNull(er);
+		assertNotNull( er.getEmployees() );
+		assertEquals( 1, er.getEmployees().size() );
+		Employee eeFromDb = (Employee) er.getEmployees().iterator().next();
+		assertEquals( ee.getId(), eeFromDb.getId() );
+		tx.commit();
+		s.close();
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/CreateTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/DeleteTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/DeleteTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/DeleteTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,91 @@
+package org.hibernate.test.ops;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class DeleteTest extends AbstractOperationTestCase {
+	public DeleteTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( DeleteTest.class );
+	}
+
+	public void testDeleteVersionedWithCollectionNoUpdate() {
+		// test adapted from HHH-1564...
+		Session s = openSession();
+		s.beginTransaction();
+		VersionedEntity c = new VersionedEntity( "c1", "child-1" );
+		VersionedEntity p = new VersionedEntity( "root", "root");
+		p.getChildren().add( c );
+		c.setParent( p );
+		s.save( p );
+		s.getTransaction().commit();
+		s.close();
+
+		clearCounts();
+
+		s = openSession();
+		s.beginTransaction();
+        VersionedEntity loadedParent = ( VersionedEntity ) s.get( VersionedEntity.class, "root" );
+        s.delete( loadedParent );
+		s.getTransaction().commit();
+        s.close();
+
+		assertInsertCount( 0 );
+		assertUpdateCount( 0 );
+		assertDeleteCount( 2 );
+	}
+
+	public void testNoUpdateOnDelete() {
+		Session s = openSession();
+        s.beginTransaction();
+		Node node = new Node( "test" );
+		s.persist( node );
+		s.getTransaction().commit();
+		s.close();
+
+		clearCounts();
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( node );
+		s.getTransaction().commit();
+		s.close();
+
+		assertUpdateCount( 0 );
+		assertInsertCount( 0 );
+	}
+
+	public void testNoUpdateOnDeleteWithCollection() {
+		Session s = openSession();
+        s.beginTransaction();
+		Node parent = new Node( "parent" );
+		Node child = new Node( "child" );
+		parent.getCascadingChildren().add( child );
+		s.persist( parent );
+		s.getTransaction().commit();
+		s.close();
+
+		clearCounts();
+
+		s = openSession();
+		s.beginTransaction();
+		parent = ( Node ) s.get( Node.class, "parent" );
+		s.delete( parent );
+		s.getTransaction().commit();
+		s.close();
+
+		assertUpdateCount( 0 );
+		assertInsertCount( 0 );
+		assertDeleteCount( 2 );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Employee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Employee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Employee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: Employee.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.ops;
+
+import java.util.Collection;
+import java.io.Serializable;
+
+
+/**
+ * Employee in an Employer-Employee relationship
+ * 
+ * @author Emmanuel Bernard
+ */
+
+public class Employee implements Serializable {
+	private Integer id;
+	private Collection employers;
+
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer integer) {
+		id = integer;
+	}
+	
+	
+	public Collection getEmployers() {
+		return employers;
+	}
+	
+	public void setEmployers(Collection employers) {
+		this.employers = employers;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Employer.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Employer.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Employer.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+  
+-->
+
+<hibernate-mapping package="org.hibernate.test.ops">
+	
+	<class name="Employer" polymorphism="explicit">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+        <version column="vers" name="vers"/>
+        <bag name="employees"
+			cascade="persist,merge"
+			table="EMPLOYER_EMPLOYEE">
+			<key column="EMPER_ID"/>
+			<many-to-many class="Employee" column="EMPEE_ID" />
+		</bag>
+	</class>
+	
+	<class name="Employee" polymorphism="explicit">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<bag name="employers"
+			inverse="true"
+			cascade="persist,merge,save-update"
+			table="EMPLOYER_EMPLOYEE">
+			<key column="EMPEE_ID"/>
+			<many-to-many class="Employer" column="EMPER_ID" />
+		</bag>
+	</class>
+	
+</hibernate-mapping>
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Employer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Employer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Employer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+//$Id: Employer.java 8670 2005-11-25 17:36:29Z epbernard $
+package org.hibernate.test.ops;
+
+import java.util.Collection;
+import java.io.Serializable;
+
+
+/**
+ * Employer in a employer-Employee relationship
+ * 
+ * @author Emmanuel Bernard
+ */
+
+public class Employer implements Serializable {
+	private Integer id;
+	private Collection employees;
+	private Integer vers;
+
+	public Integer getVers() {
+		return vers;
+	}
+
+	public void setVers(Integer vers) {
+		this.vers = vers;
+	}
+
+
+	public Collection getEmployees() {
+		return employees;
+	}
+	
+	
+	public Integer getId() {
+		return id;
+	}
+	
+	public void setEmployees(Collection set) {
+		employees = set;
+	}
+
+	public void setId(Integer integer) {
+		id = integer;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/GetLoadTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/GetLoadTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/GetLoadTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,113 @@
+//$Id: GetLoadTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.ops;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+
+
+/**
+ * @author Gavin King
+ */
+public class GetLoadTest extends FunctionalTestCase {
+	
+	public GetLoadTest(String str) {
+		super(str);
+	}
+	
+	public void testGetLoad() {
+		clearCounts();
+		
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Employer emp = new Employer();
+		s.persist(emp);
+		Node node = new Node("foo");
+		Node parent = new Node("bar");
+		parent.addChild(node);
+		s.persist(parent);
+		tx.commit();
+		s.close();
+		
+		s = openSession();
+		tx = s.beginTransaction();
+		emp = (Employer) s.get(Employer.class, emp.getId());
+		assertTrue( Hibernate.isInitialized(emp) );
+		assertFalse( Hibernate.isInitialized(emp.getEmployees()) );
+		node = (Node) s.get(Node.class, node.getName());
+		assertTrue( Hibernate.isInitialized(node) );
+		assertFalse( Hibernate.isInitialized(node.getChildren()) );
+		assertFalse( Hibernate.isInitialized(node.getParent()) );
+		assertNull( s.get(Node.class, "xyz") );
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		emp = (Employer) s.load(Employer.class, emp.getId());
+		emp.getId();
+		assertFalse( Hibernate.isInitialized(emp) );
+		node = (Node) s.load(Node.class, node.getName());
+		assertEquals( node.getName(), "foo" );
+		assertFalse( Hibernate.isInitialized(node) );
+		tx.commit();
+		s.close();
+	
+		s = openSession();
+		tx = s.beginTransaction();
+		emp = (Employer) s.get("org.hibernate.test.ops.Employer", emp.getId());
+		assertTrue( Hibernate.isInitialized(emp) );
+		node = (Node) s.get("org.hibernate.test.ops.Node", node.getName());
+		assertTrue( Hibernate.isInitialized(node) );
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		emp = (Employer) s.load("org.hibernate.test.ops.Employer", emp.getId());
+		emp.getId();
+		assertFalse( Hibernate.isInitialized(emp) );
+		node = (Node) s.load("org.hibernate.test.ops.Node", node.getName());
+		assertEquals( node.getName(), "foo" );
+		assertFalse( Hibernate.isInitialized(node) );
+		tx.commit();
+		s.close();
+		
+		assertFetchCount(0);
+	}
+
+	private void clearCounts() {
+		getSessions().getStatistics().clear();
+	}
+	
+	private void assertFetchCount(int count) {
+		int fetches = (int) getSessions().getStatistics().getEntityFetchCount();
+		assertEquals(count, fetches);
+	}
+		
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+		cfg.setProperty(Environment.STATEMENT_BATCH_SIZE, "0");		
+	}
+	
+	public String[] getMappings() {
+		return new String[] { "ops/Node.hbm.xml", "ops/Employer.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite(GetLoadTest.class);
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/GetLoadTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/MergeTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/MergeTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/MergeTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,642 @@
+//$Id: MergeTest.java 11037 2007-01-09 16:04:16Z steve.ebersole at jboss.com $
+package org.hibernate.test.ops;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.NonUniqueObjectException;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.criterion.Projections;
+
+/**
+ * @author Gavin King
+ */
+public class MergeTest extends AbstractOperationTestCase {
+
+	public MergeTest(String str) {
+		super( str );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( MergeTest.class );
+	}
+
+	public void testMergeBidiPrimayKeyOneToOne() throws Exception {
+		Session s = openSession();
+        s.beginTransaction();
+		Person p = new Person( "steve" );
+		new PersonalDetails( "I have big feet", p );
+		s.persist( p );
+		s.getTransaction().commit();
+		s.close();
+
+		clearCounts();
+
+		p.getDetails().setSomePersonalDetail( p.getDetails().getSomePersonalDetail() + " and big hands too" );
+		s = openSession();
+        s.beginTransaction();
+		p = ( Person ) s.merge( p );
+		s.getTransaction().commit();
+		s.close();
+
+		assertInsertCount( 0 );
+		assertUpdateCount( 1 );
+		assertDeleteCount( 0 );
+
+		s = openSession();
+        s.beginTransaction();
+		s.delete( p );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testMergeBidiForeignKeyOneToOne() throws Exception {
+		Session s = openSession();
+        s.beginTransaction();
+		Person p = new Person( "steve" );
+		Address a = new Address( "123 Main", "Austin", "US", p );
+		s.persist( a );
+		s.persist( p );
+		s.getTransaction().commit();
+		s.close();
+
+		clearCounts();
+
+		p.getAddress().setStreetAddress( "321 Main" );
+		s = openSession();
+        s.beginTransaction();
+		p = ( Person ) s.merge( p );
+		s.getTransaction().commit();
+		s.close();
+
+		assertInsertCount( 0 );
+		assertUpdateCount( 0 ); // no cascade
+		assertDeleteCount( 0 );
+
+		s = openSession();
+        s.beginTransaction();
+		s.delete( a );
+		s.delete( p );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+    public void testNoExtraUpdatesOnMerge() throws Exception {
+		Session s = openSession();
+        s.beginTransaction();
+		Node node = new Node( "test" );
+		s.persist( node );
+		s.getTransaction().commit();
+		s.close();
+
+		clearCounts();
+
+		// node is now detached, but we have made no changes.  so attempt to merge it
+		// into this new session; this should cause no updates...
+		s = openSession();
+		s.beginTransaction();
+		node = ( Node ) s.merge( node );
+		s.getTransaction().commit();
+		s.close();
+
+		assertUpdateCount( 0 );
+		assertInsertCount( 0 );
+
+		///////////////////////////////////////////////////////////////////////
+		// as a control measure, now update the node while it is detached and
+		// make sure we get an update as a result...
+		node.setDescription( "new description" );
+		s = openSession();
+		s.beginTransaction();
+		node = ( Node ) s.merge( node );
+		s.getTransaction().commit();
+		s.close();
+		assertUpdateCount( 1 );
+		assertInsertCount( 0 );
+		///////////////////////////////////////////////////////////////////////
+
+		cleanup();
+    }
+
+	public void testNoExtraUpdatesOnMergeWithCollection() throws Exception {
+		Session s = openSession();
+        s.beginTransaction();
+		Node parent = new Node( "parent" );
+		Node child = new Node( "child" );
+		parent.getChildren().add( child );
+		child.setParent( parent );
+		s.persist( parent );
+		s.getTransaction().commit();
+		s.close();
+
+		clearCounts();
+
+		// parent is now detached, but we have made no changes.  so attempt to merge it
+		// into this new session; this should cause no updates...
+		s = openSession();
+		s.beginTransaction();
+		parent = ( Node ) s.merge( parent );
+		s.getTransaction().commit();
+		s.close();
+
+		assertUpdateCount( 0 );
+		assertInsertCount( 0 );
+
+		///////////////////////////////////////////////////////////////////////
+		// as a control measure, now update the node while it is detached and
+		// make sure we get an update as a result...
+		( ( Node ) parent.getChildren().iterator().next() ).setDescription( "child's new description" );
+		parent.getChildren().add( new Node( "second child" ) );
+		s = openSession();
+		s.beginTransaction();
+		parent = ( Node ) s.merge( parent );
+		s.getTransaction().commit();
+		s.close();
+		assertUpdateCount( 1 );
+		assertInsertCount( 1 );
+		///////////////////////////////////////////////////////////////////////
+
+		cleanup();
+	}
+
+    public void testNoExtraUpdatesOnMergeVersioned() throws Exception {
+		Session s = openSession();
+        s.beginTransaction();
+		VersionedEntity entity = new VersionedEntity( "entity", "entity" );
+		s.persist( entity );
+		s.getTransaction().commit();
+		s.close();
+
+		clearCounts();
+
+		// entity is now detached, but we have made no changes.  so attempt to merge it
+		// into this new session; this should cause no updates...
+		s = openSession();
+		s.beginTransaction();
+		VersionedEntity mergedEntity = ( VersionedEntity ) s.merge( entity );
+		s.getTransaction().commit();
+		s.close();
+
+		assertUpdateCount( 0 );
+		assertInsertCount( 0 );
+        assertEquals( "unexpected version increment", entity.getVersion(), mergedEntity.getVersion() );
+
+
+		///////////////////////////////////////////////////////////////////////
+		// as a control measure, now update the node while it is detached and
+		// make sure we get an update as a result...
+		entity.setName( "new name" );
+		s = openSession();
+		s.beginTransaction();
+		entity = ( VersionedEntity ) s.merge( entity );
+		s.getTransaction().commit();
+		s.close();
+		assertUpdateCount( 1 );
+		assertInsertCount( 0 );
+		///////////////////////////////////////////////////////////////////////
+
+		cleanup();
+    }
+
+    public void testNoExtraUpdatesOnMergeVersionedWithCollection() throws Exception {
+		Session s = openSession();
+        s.beginTransaction();
+		VersionedEntity parent = new VersionedEntity( "parent", "parent" );
+		VersionedEntity child = new VersionedEntity( "child", "child" );
+		parent.getChildren().add( child );
+		child.setParent( parent );
+		s.persist( parent );
+		s.getTransaction().commit();
+		s.close();
+
+		clearCounts();
+
+		// parent is now detached, but we have made no changes.  so attempt to merge it
+		// into this new session; this should cause no updates...
+		s = openSession();
+		s.beginTransaction();
+		VersionedEntity mergedParent = ( VersionedEntity ) s.merge( parent );
+		s.getTransaction().commit();
+		s.close();
+
+		assertUpdateCount( 0 );
+		assertInsertCount( 0 );
+		assertEquals( "unexpected parent version increment", parent.getVersion(), mergedParent.getVersion() );
+		VersionedEntity mergedChild = ( VersionedEntity ) mergedParent.getChildren().iterator().next();
+		assertEquals( "unexpected child version increment", child.getVersion(), mergedChild.getVersion() );
+
+		///////////////////////////////////////////////////////////////////////
+		// as a control measure, now update the node while it is detached and
+		// make sure we get an update as a result...
+		mergedParent.setName( "new name" );
+		mergedParent.getChildren().add( new VersionedEntity( "child2", "new child" ) );
+		s = openSession();
+		s.beginTransaction();
+		parent = ( VersionedEntity ) s.merge( mergedParent );
+		s.getTransaction().commit();
+		s.close();
+		assertUpdateCount( 1 );
+		assertInsertCount( 1 );
+		///////////////////////////////////////////////////////////////////////
+
+		cleanup();
+    }
+
+	public void testPersistThenMergeInSameTxnWithVersion() {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		VersionedEntity entity = new VersionedEntity( "test", "test" );
+		s.persist( entity );
+		s.merge( new VersionedEntity( "test", "test-2" ) );
+
+		try {
+			// control operation...
+			s.saveOrUpdate( new VersionedEntity( "test", "test-3" ) );
+			fail( "saveOrUpdate() should fail here" );
+		}
+		catch( NonUniqueObjectException expected ) {
+			// expected behavior
+		}
+
+		tx.commit();
+		s.close();
+
+		cleanup();
+	}
+
+	public void testPersistThenMergeInSameTxnWithTimestamp() {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		TimestampedEntity entity = new TimestampedEntity( "test", "test" );
+		s.persist( entity );
+		s.merge( new TimestampedEntity( "test", "test-2" ) );
+
+		try {
+			// control operation...
+			s.saveOrUpdate( new TimestampedEntity( "test", "test-3" ) );
+			fail( "saveOrUpdate() should fail here" );
+		}
+		catch( NonUniqueObjectException expected ) {
+			// expected behavior
+		}
+
+		tx.commit();
+		s.close();
+
+		cleanup();
+	}
+
+	public void testMergeDeepTree() {
+
+		clearCounts();
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Node root = new Node("root");
+		Node child = new Node("child");
+		Node grandchild = new Node("grandchild");
+		root.addChild(child);
+		child.addChild(grandchild);
+		s.merge(root);
+		tx.commit();
+		s.close();
+
+		assertInsertCount(3);
+		assertUpdateCount(0);
+		clearCounts();
+
+		grandchild.setDescription("the grand child");
+		Node grandchild2 = new Node("grandchild2");
+		child.addChild( grandchild2 );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.merge(root);
+		tx.commit();
+		s.close();
+
+		assertInsertCount(1);
+		assertUpdateCount(1);
+		clearCounts();
+
+		Node child2 = new Node("child2");
+		Node grandchild3 = new Node("grandchild3");
+		child2.addChild( grandchild3 );
+		root.addChild(child2);
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.merge(root);
+		tx.commit();
+		s.close();
+
+		assertInsertCount(2);
+		assertUpdateCount(0);
+		clearCounts();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.delete(grandchild);
+		s.delete(grandchild2);
+		s.delete(grandchild3);
+		s.delete(child);
+		s.delete(child2);
+		s.delete(root);
+		tx.commit();
+		s.close();
+
+	}
+
+	public void testMergeDeepTreeWithGeneratedId() {
+
+		clearCounts();
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		NumberedNode root = new NumberedNode("root");
+		NumberedNode child = new NumberedNode("child");
+		NumberedNode grandchild = new NumberedNode("grandchild");
+		root.addChild(child);
+		child.addChild(grandchild);
+		root = (NumberedNode) s.merge(root);
+		tx.commit();
+		s.close();
+
+		assertInsertCount(3);
+		assertUpdateCount(0);
+		clearCounts();
+
+		child = (NumberedNode) root.getChildren().iterator().next();
+		grandchild = (NumberedNode) child.getChildren().iterator().next();
+		grandchild.setDescription("the grand child");
+		NumberedNode grandchild2 = new NumberedNode("grandchild2");
+		child.addChild( grandchild2 );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		root = (NumberedNode) s.merge(root);
+		tx.commit();
+		s.close();
+
+		assertInsertCount(1);
+		assertUpdateCount(1);
+		clearCounts();
+
+		getSessions().evict(NumberedNode.class);
+
+		NumberedNode child2 = new NumberedNode("child2");
+		NumberedNode grandchild3 = new NumberedNode("grandchild3");
+		child2.addChild( grandchild3 );
+		root.addChild(child2);
+
+		s = openSession();
+		tx = s.beginTransaction();
+		root = (NumberedNode) s.merge(root);
+		tx.commit();
+		s.close();
+
+		assertInsertCount(2);
+		assertUpdateCount(0);
+		clearCounts();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.createQuery("delete from NumberedNode where name like 'grand%'").executeUpdate();
+		s.createQuery("delete from NumberedNode where name like 'child%'").executeUpdate();
+		s.createQuery("delete from NumberedNode").executeUpdate();
+		tx.commit();
+		s.close();
+
+	}
+
+	public void testMergeTree() {
+
+		clearCounts();
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Node root = new Node("root");
+		Node child = new Node("child");
+		root.addChild(child);
+		s.persist(root);
+		tx.commit();
+		s.close();
+
+		assertInsertCount(2);
+		clearCounts();
+
+		root.setDescription("The root node");
+		child.setDescription("The child node");
+
+		Node secondChild = new Node("second child");
+
+		root.addChild(secondChild);
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.merge(root);
+		tx.commit();
+		s.close();
+
+		assertInsertCount(1);
+		assertUpdateCount(2);
+
+		cleanup();
+	}
+
+	public void testMergeTreeWithGeneratedId() {
+
+		clearCounts();
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		NumberedNode root = new NumberedNode("root");
+		NumberedNode child = new NumberedNode("child");
+		root.addChild(child);
+		s.persist(root);
+		tx.commit();
+		s.close();
+
+		assertInsertCount(2);
+		clearCounts();
+
+		root.setDescription("The root node");
+		child.setDescription("The child node");
+
+		NumberedNode secondChild = new NumberedNode("second child");
+
+		root.addChild(secondChild);
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.merge(root);
+		tx.commit();
+		s.close();
+
+		assertInsertCount(1);
+		assertUpdateCount(2);
+
+		cleanup();
+	}
+
+	public void testMergeManaged() {
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		NumberedNode root = new NumberedNode("root");
+		s.persist(root);
+		tx.commit();
+
+		clearCounts();
+
+		tx = s.beginTransaction();
+		NumberedNode child = new NumberedNode("child");
+		root.addChild(child);
+		assertSame( root, s.merge(root) );
+		Object mergedChild = root.getChildren().iterator().next();
+		assertNotSame( mergedChild, child );
+		assertTrue( s.contains(mergedChild) );
+		assertFalse( s.contains(child) );
+		assertEquals( root.getChildren().size(), 1 );
+		assertTrue( root.getChildren().contains(mergedChild) );
+		//assertNotSame( mergedChild, s.merge(child) ); //yucky :(
+		tx.commit();
+
+		assertInsertCount(1);
+		assertUpdateCount(0);
+
+		assertEquals( root.getChildren().size(), 1 );
+		assertTrue( root.getChildren().contains(mergedChild) );
+
+		tx = s.beginTransaction();
+		assertEquals(
+			s.createCriteria(NumberedNode.class)
+				.setProjection( Projections.rowCount() )
+				.uniqueResult(),
+			new Integer(2)
+		);
+
+		s.close();
+
+		cleanup();
+	}
+
+	public void testRecursiveMergeTransient() {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Employer jboss = new Employer();
+		Employee gavin = new Employee();
+		jboss.setEmployees( new ArrayList() );
+		jboss.getEmployees().add(gavin);
+		s.merge(jboss);
+		s.flush();
+		jboss = (Employer) s.createQuery("from Employer e join fetch e.employees").uniqueResult();
+		assertTrue( Hibernate.isInitialized( jboss.getEmployees() )  );
+		assertEquals( 1, jboss.getEmployees().size() );
+		s.clear();
+		s.merge( jboss.getEmployees().iterator().next() );
+		tx.commit();
+		s.close();
+
+		cleanup();
+	}
+
+	public void testDeleteAndMerge() throws Exception {
+		Session s = openSession();
+		s.getTransaction().begin();
+		Employer jboss = new Employer();
+		s.persist( jboss );
+		s.getTransaction().commit();
+		s.clear();
+
+		s.getTransaction().begin();
+		Employer otherJboss;
+		otherJboss = (Employer) s.get( Employer.class, jboss.getId() );
+		s.delete( otherJboss );
+		s.getTransaction().commit();
+		s.clear();
+		jboss.setVers( new Integer(1) );
+		s.getTransaction().begin();
+		s.merge( jboss );
+		s.getTransaction().commit();
+		s.close();
+
+		cleanup();
+	}
+
+	public void testMergeManyToManyWithCollectionDeference() throws Exception {
+		// setup base data...
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Competition competition = new Competition();
+		competition.getCompetitors().add( new Competitor( "Name" ) );
+		competition.getCompetitors().add( new Competitor() );
+		competition.getCompetitors().add( new Competitor() );
+		s.persist( competition );
+		tx.commit();
+		s.close();
+
+		// the competition graph is now detached:
+		//   1) create a new List reference to represent the competitors
+		s = openSession();
+		tx = s.beginTransaction();
+		List newComp = new ArrayList();
+		Competitor originalCompetitor = ( Competitor ) competition.getCompetitors().get( 0 );
+		originalCompetitor.setName( "Name2" );
+		newComp.add( originalCompetitor );
+		newComp.add( new Competitor() );
+		//   2) set that new List reference unto the Competition reference
+		competition.setCompetitors( newComp );
+		//   3) attempt the merge
+		Competition competition2 = ( Competition ) s.merge( competition );
+		tx.commit();
+		s.close();
+
+		assertFalse( competition == competition2 );
+		assertFalse( competition.getCompetitors() == competition2.getCompetitors() );
+		assertEquals( 2, competition2.getCompetitors().size() );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		competition = ( Competition ) s.get( Competition.class, competition.getId() );
+		assertEquals( 2, competition.getCompetitors().size() );
+		s.delete( competition );
+		tx.commit();
+		s.close();
+
+		cleanup();
+	}
+
+	private void cleanup() {
+		Session s = openSession();
+		s.beginTransaction();
+		s.createQuery( "delete from NumberedNode where parent is not null" ).executeUpdate();
+		s.createQuery( "delete from NumberedNode" ).executeUpdate();
+
+		s.createQuery( "delete from Node where parent is not null" ).executeUpdate();
+		s.createQuery( "delete from Node" ).executeUpdate();
+
+		s.createQuery( "delete from VersionedEntity where parent is not null" ).executeUpdate();
+		s.createQuery( "delete from VersionedEntity" ).executeUpdate();
+		s.createQuery( "delete from TimestampedEntity" ).executeUpdate();
+
+		s.createQuery( "delete from Competitor" ).executeUpdate();
+		s.createQuery( "delete from Competition" ).executeUpdate();
+
+		Iterator itr = s.createQuery( "from Employer" ).list().iterator();
+		while ( itr.hasNext() ) {
+			final Employer employer = ( Employer ) itr.next();
+			s.delete( employer );
+		}
+
+		s.getTransaction().commit();
+		s.close();
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/MergeTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Node.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Node.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Node.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.ops">
+
+	<class name="Node" polymorphism="explicit">
+		<id name="name">
+			<generator class="assigned"/>
+		</id>
+		<property name="description"/>
+		<many-to-one name="parent"/>
+		<property name="created" not-null="true"/>
+		<set name="children"
+			inverse="true"
+			cascade="persist,merge,save-update,evict">
+			<key column="parent"/>
+			<one-to-many class="Node"/>
+		</set>
+		<set name="cascadingChildren" inverse="false" cascade="persist,merge,save-update,evict,delete">
+            <key column="CASC_PARENT"/>
+            <one-to-many class="Node"/>
+        </set>
+    </class>
+
+	<class name="NumberedNode" polymorphism="explicit">
+		<id name="id" unsaved-value="0">
+			<generator class="native"/>
+		</id>
+		<property name="name">
+			<column name="name" index="iname" not-null="true"/>
+		</property>
+		<property name="description"/>
+		<property name="created" not-null="true"
+				type="imm_date"/>
+		<many-to-one name="parent" class="NumberedNode"/>
+		<set name="children"
+			inverse="true"
+			cascade="persist,merge,save-update">
+			<key column="parent"/>
+			<one-to-many class="NumberedNode"/>
+		</set>
+	</class>
+
+</hibernate-mapping>
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Node.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Node.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Node.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Node.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,88 @@
+//$Id: Node.java 10759 2006-11-08 00:00:53Z steve.ebersole at jboss.com $
+package org.hibernate.test.ops;
+
+import java.sql.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class Node {
+
+	private String name;
+	private String description;
+	private Date created;
+	private Node parent;
+	private Set children = new HashSet();
+	private Set cascadingChildren = new HashSet();
+
+	public Node() {
+	}
+
+	public Node(String name) {
+		this.name = name;
+		created = generateCurrentDate();
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public Date getCreated() {
+		return created;
+	}
+
+	public void setCreated(Date created) {
+		this.created = created;
+	}
+
+	public Node getParent() {
+		return parent;
+	}
+
+	public void setParent(Node parent) {
+		this.parent = parent;
+	}
+
+	public Set getChildren() {
+		return children;
+	}
+
+	public void setChildren(Set children) {
+		this.children = children;
+	}
+
+	public Node addChild(Node child) {
+		children.add( child );
+		child.setParent( this );
+		return this;
+	}
+
+	public Set getCascadingChildren() {
+		return cascadingChildren;
+	}
+
+	public void setCascadingChildren(Set cascadingChildren) {
+		this.cascadingChildren = cascadingChildren;
+	}
+
+	private Date generateCurrentDate() {
+		// Note : done as java.sql.Date mainly to work around issue with
+		// MySQL and its lack of milli-second precision on its DATETIME
+		// and TIMESTAMP datatypes.
+		return new Date( new java.util.Date().getTime() );
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Node.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/NumberedNode.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/NumberedNode.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/NumberedNode.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,75 @@
+//$Id: NumberedNode.java 7236 2005-06-20 03:19:34Z oneovthafew $
+package org.hibernate.test.ops;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class NumberedNode {
+	
+	private long id;
+	private String name;
+	private NumberedNode parent;
+	private Set children = new HashSet();
+	private String description;
+	private Date created;
+
+	public NumberedNode() {
+		super();
+	}
+
+	public NumberedNode(String name) {
+		this.name = name;
+		created = new Date();
+	}
+
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	
+	public Set getChildren() {
+		return children;
+	}
+	public void setChildren(Set children) {
+		this.children = children;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public NumberedNode getParent() {
+		return parent;
+	}
+	public void setParent(NumberedNode parent) {
+		this.parent = parent;
+	}
+	
+	public NumberedNode addChild(NumberedNode child) {
+		children.add(child);
+		child.setParent(this);
+		return this;
+	}
+	
+	public String getDescription() {
+		return description;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public Date getCreated() {
+		return created;
+	}
+
+	public void setCreated(Date created) {
+		this.created = created;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/NumberedNode.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/OneToOne.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/OneToOne.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/OneToOne.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+ Mappings demonstrating bidirectional one-to-one mappings for testing
+ with various operations.
+
+ Person -> Address is modeled as a bidirectional one to one based on FK.
+ Person -> Details is modeled as a bidirectional one to one based on PK.
+-->
+
+<hibernate-mapping package="org.hibernate.test.ops">
+
+    <class name="Person" table="OPS_PERSON">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="name" column="NAME" type="string"/>
+        <one-to-one name="address" class="Address" property-ref="resident" />
+        <one-to-one name="details" class="PersonalDetails" cascade="all" />
+    </class>
+
+    <class name="Address" table="OPS_ADDRESS">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="streetAddress" column="STREET" type="string" />
+        <property name="city" column="CITY" type="string" />
+        <property name="country" column="CTRY" type="string" />
+        <many-to-one name="resident" column="RESIDENT" class="Person" />
+    </class>
+
+    <class name="PersonalDetails" table="OPS_PERS_DETAIL">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="somePersonalDetail" column="SOME_DETAIL" type="string"/>
+        <one-to-one name="person" class="Person" cascade="none" constrained="true" />
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/OpsSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/OpsSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/OpsSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+package org.hibernate.test.ops;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class OpsSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "Operations tests" );
+		suite.addTest( CreateTest.suite() );
+		suite.addTest( DeleteTest.suite() );
+		suite.addTest( GetLoadTest.suite() );
+		suite.addTest( MergeTest.suite() );
+		suite.addTest( SaveOrUpdateTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/OptLockEntity.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/OptLockEntity.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/OptLockEntity.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.ops">
+
+	<class name="VersionedEntity" table="V_ENTITY">
+		<id name="id" column="ID" type="string">
+			<generator class="assigned"/>
+		</id>
+        <version name="version" column="VERS" type="long" />
+        <property name="name" column="NAME" type="string" />
+        <many-to-one name="parent" class="VersionedEntity"/>
+        <set name="children"
+			inverse="true"
+			cascade="persist,merge,save-update,evict,delete">
+			<key column="parent"/>
+			<one-to-many class="VersionedEntity"/>
+		</set>
+    </class>
+
+	<class name="TimestampedEntity" table="T_ENTITY">
+		<id name="id" column="ID" type="string">
+			<generator class="assigned"/>
+		</id>
+        <timestamp name="timestamp" column="TS" />
+        <property name="name" column="NAME" type="string" />
+	</class>
+
+</hibernate-mapping>
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+package org.hibernate.test.ops;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Person {
+	private Long id;
+	private String name;
+	private Address address;
+	private PersonalDetails details;
+
+	public Person() {
+	}
+
+	public Person(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Address getAddress() {
+		return address;
+	}
+
+	public void setAddress(Address address) {
+		this.address = address;
+	}
+
+	public PersonalDetails getDetails() {
+		return details;
+	}
+
+	public void setDetails(PersonalDetails details) {
+		this.details = details;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/PersonalDetails.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/PersonalDetails.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/PersonalDetails.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+package org.hibernate.test.ops;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class PersonalDetails {
+	private Long id;
+	private String somePersonalDetail;
+	private Person person;
+
+	public PersonalDetails() {
+	}
+
+	public PersonalDetails(String somePersonalDetail, Person person) {
+		this.somePersonalDetail = somePersonalDetail;
+		this.person = person;
+		person.setDetails( this );
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getSomePersonalDetail() {
+		return somePersonalDetail;
+	}
+
+	public void setSomePersonalDetail(String somePersonalDetail) {
+		this.somePersonalDetail = somePersonalDetail;
+	}
+
+	public Person getPerson() {
+		return person;
+	}
+
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/SaveOrUpdateTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/SaveOrUpdateTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/SaveOrUpdateTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,448 @@
+//$Id: SaveOrUpdateTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.ops;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.Projections;
+
+/**
+ * @author Gavin King
+ */
+public class SaveOrUpdateTest extends FunctionalTestCase {
+
+	public SaveOrUpdateTest(String str) {
+		super( str );
+	}
+
+	public void testSaveOrUpdateDeepTree() {
+		clearCounts();
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Node root = new Node( "root" );
+		Node child = new Node( "child" );
+		Node grandchild = new Node( "grandchild" );
+		root.addChild( child );
+		child.addChild( grandchild );
+		s.saveOrUpdate( root );
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 3 );
+		assertUpdateCount( 0 );
+		clearCounts();
+
+		grandchild.setDescription( "the grand child" );
+		Node grandchild2 = new Node( "grandchild2" );
+		child.addChild( grandchild2 );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.saveOrUpdate( root );
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 1 );
+		clearCounts();
+
+		Node child2 = new Node( "child2" );
+		Node grandchild3 = new Node( "grandchild3" );
+		child2.addChild( grandchild3 );
+		root.addChild( child2 );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.saveOrUpdate( root );
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 2 );
+		assertUpdateCount( 0 );
+		clearCounts();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.delete( grandchild );
+		s.delete( grandchild2 );
+		s.delete( grandchild3 );
+		s.delete( child );
+		s.delete( child2 );
+		s.delete( root );
+		tx.commit();
+		s.close();
+	}
+
+	public void testSaveOrUpdateDeepTreeWithGeneratedId() {
+		boolean instrumented = FieldInterceptionHelper.isInstrumented( new NumberedNode() );
+		clearCounts();
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		NumberedNode root = new NumberedNode( "root" );
+		NumberedNode child = new NumberedNode( "child" );
+		NumberedNode grandchild = new NumberedNode( "grandchild" );
+		root.addChild( child );
+		child.addChild( grandchild );
+		s.saveOrUpdate( root );
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 3 );
+		assertUpdateCount( 0 );
+		clearCounts();
+
+		child = ( NumberedNode ) root.getChildren().iterator().next();
+		grandchild = ( NumberedNode ) child.getChildren().iterator().next();
+		grandchild.setDescription( "the grand child" );
+		NumberedNode grandchild2 = new NumberedNode( "grandchild2" );
+		child.addChild( grandchild2 );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.saveOrUpdate( root );
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( instrumented ? 1 : 3 );
+		clearCounts();
+
+		NumberedNode child2 = new NumberedNode( "child2" );
+		NumberedNode grandchild3 = new NumberedNode( "grandchild3" );
+		child2.addChild( grandchild3 );
+		root.addChild( child2 );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.saveOrUpdate( root );
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 2 );
+		assertUpdateCount( instrumented ? 0 : 4 );
+		clearCounts();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.createQuery( "delete from NumberedNode where name like 'grand%'" ).executeUpdate();
+		s.createQuery( "delete from NumberedNode where name like 'child%'" ).executeUpdate();
+		s.createQuery( "delete from NumberedNode" ).executeUpdate();
+		tx.commit();
+		s.close();
+	}
+
+	public void testSaveOrUpdateTree() {
+		clearCounts();
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Node root = new Node( "root" );
+		Node child = new Node( "child" );
+		root.addChild( child );
+		s.saveOrUpdate( root );
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 2 );
+		clearCounts();
+
+		root.setDescription( "The root node" );
+		child.setDescription( "The child node" );
+
+		Node secondChild = new Node( "second child" );
+
+		root.addChild( secondChild );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.saveOrUpdate( root );
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 2 );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.createQuery( "delete from Node where parent is not null" ).executeUpdate();
+		s.createQuery( "delete from Node" ).executeUpdate();
+		tx.commit();
+		s.close();
+	}
+
+	public void testSaveOrUpdateTreeWithGeneratedId() {
+		clearCounts();
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		NumberedNode root = new NumberedNode( "root" );
+		NumberedNode child = new NumberedNode( "child" );
+		root.addChild( child );
+		s.saveOrUpdate( root );
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 2 );
+		clearCounts();
+
+		root.setDescription( "The root node" );
+		child.setDescription( "The child node" );
+
+		NumberedNode secondChild = new NumberedNode( "second child" );
+
+		root.addChild( secondChild );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.saveOrUpdate( root );
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 2 );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.createQuery( "delete from NumberedNode where parent is not null" ).executeUpdate();
+		s.createQuery( "delete from NumberedNode" ).executeUpdate();
+		tx.commit();
+		s.close();
+	}
+
+	public void testSaveOrUpdateManaged() {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		NumberedNode root = new NumberedNode( "root" );
+		s.saveOrUpdate( root );
+		tx.commit();
+
+		tx = s.beginTransaction();
+		NumberedNode child = new NumberedNode( "child" );
+		root.addChild( child );
+		s.saveOrUpdate( root );
+		assertFalse( s.contains( child ) );
+		s.flush();
+		assertTrue( s.contains( child ) );
+		tx.commit();
+
+		assertTrue( root.getChildren().contains( child ) );
+		assertEquals( root.getChildren().size(), 1 );
+
+		tx = s.beginTransaction();
+		assertEquals(
+				s.createCriteria( NumberedNode.class )
+						.setProjection( Projections.rowCount() )
+						.uniqueResult(),
+		        new Integer( 2 )
+		);
+		s.delete( root );
+		s.delete( child );
+		tx.commit();
+		s.close();
+	}
+
+
+	public void testSaveOrUpdateGot() {
+		boolean instrumented = FieldInterceptionHelper.isInstrumented( new NumberedNode() );
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		NumberedNode root = new NumberedNode( "root" );
+		s.saveOrUpdate( root );
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 0 );
+		clearCounts();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.saveOrUpdate( root );
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 0 );
+		assertUpdateCount( instrumented ? 0 : 1 );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		root = ( NumberedNode ) s.get( NumberedNode.class, new Long( root.getId() ) );
+		Hibernate.initialize( root.getChildren() );
+		tx.commit();
+		s.close();
+
+		clearCounts();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		NumberedNode child = new NumberedNode( "child" );
+		root.addChild( child );
+		s.saveOrUpdate( root );
+		assertTrue( s.contains( child ) );
+		tx.commit();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( instrumented ? 0 : 1 );
+
+		tx = s.beginTransaction();
+		assertEquals(
+				s.createCriteria( NumberedNode.class )
+						.setProjection( Projections.rowCount() )
+						.uniqueResult(),
+		        new Integer( 2 )
+		);
+		s.delete( root );
+		s.delete( child );
+		tx.commit();
+		s.close();
+	}
+
+	public void testSaveOrUpdateGotWithMutableProp() {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Node root = new Node( "root" );
+		s.saveOrUpdate( root );
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 0 );
+		clearCounts();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		s.saveOrUpdate( root );
+		tx.commit();
+		s.close();
+
+		assertInsertCount( 0 );
+		assertUpdateCount( 0 );
+
+		s = openSession();
+		tx = s.beginTransaction();
+		root = ( Node ) s.get( Node.class, "root" );
+		Hibernate.initialize( root.getChildren() );
+		tx.commit();
+		s.close();
+
+		clearCounts();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		Node child = new Node( "child" );
+		root.addChild( child );
+		s.saveOrUpdate( root );
+		assertTrue( s.contains( child ) );
+		tx.commit();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 1 ); //note: will fail here if no second-level cache
+
+		tx = s.beginTransaction();
+		assertEquals(
+				s.createCriteria( Node.class )
+						.setProjection( Projections.rowCount() )
+						.uniqueResult(),
+		        new Integer( 2 )
+		);
+		s.delete( root );
+		s.delete( child );
+		tx.commit();
+		s.close();
+	}
+
+	public void testEvictThenSaveOrUpdate() {
+		Session s = openSession();
+		s.getTransaction().begin();
+		Node parent = new Node( "1:parent" );
+		Node child = new Node( "2:child" );
+		Node grandchild = new Node( "3:grandchild" );
+		parent.addChild( child );
+		child.addChild( grandchild );
+		s.saveOrUpdate( parent );
+		s.getTransaction().commit();
+		s.close();
+
+		Session s1 = openSession();
+		s1.getTransaction().begin();
+		child = ( Node ) s1.load( Node.class, "2:child" );
+		assertTrue( s1.contains( child ) );
+		assertFalse( Hibernate.isInitialized( child ) );
+		assertTrue( s1.contains( child.getParent() ) );
+		assertTrue( Hibernate.isInitialized( child ) );
+		assertFalse( Hibernate.isInitialized( child.getChildren() ) );
+		assertFalse( Hibernate.isInitialized( child.getParent() ) );
+		assertTrue( s1.contains( child ) );
+		s1.evict( child );
+		assertFalse( s1.contains( child ) );
+		assertTrue( s1.contains( child.getParent() ) );
+
+		Session s2 = openSession();
+		s2.getTransaction().begin();
+		s2.saveOrUpdate( child );
+		assertTrue( s2.contains( child ) );
+		assertFalse( s1.contains( child ) );
+		assertTrue( s2.contains( child.getParent() ) );
+		assertFalse( s1.contains( child.getParent() ) );
+		assertFalse( Hibernate.isInitialized( child.getChildren() ) );
+		assertFalse( Hibernate.isInitialized( child.getParent() ) );
+		assertEquals( 1, child.getChildren().size() );
+		assertEquals( "1:parent", child.getParent().getName() );
+		assertTrue( Hibernate.isInitialized( child.getChildren() ) );
+		assertFalse( Hibernate.isInitialized( child.getParent() ) );
+		assertNull( child.getParent().getDescription() );
+		assertTrue( Hibernate.isInitialized( child.getParent() ) );
+
+		s1.getTransaction().commit();
+		s2.getTransaction().commit();
+		s1.close();
+		s2.close();
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( s.get( Node.class, "3:grandchild" ) );
+		s.delete( s.get( Node.class, "2:child" ) );
+		s.delete( s.get( Node.class, "1:parent" ) );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	private void clearCounts() {
+		getSessions().getStatistics().clear();
+	}
+
+	private void assertInsertCount(int count) {
+		int inserts = ( int ) getSessions().getStatistics().getEntityInsertCount();
+		assertEquals( count, inserts );
+	}
+
+	private void assertUpdateCount(int count) {
+		int updates = ( int ) getSessions().getStatistics().getEntityUpdateCount();
+		assertEquals( count, updates );
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+		cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "0" );
+	}
+
+	public String[] getMappings() {
+		return new String[] {"ops/Node.hbm.xml"};
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SaveOrUpdateTest.class );
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/SaveOrUpdateTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/TimestampedEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/TimestampedEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/TimestampedEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+package org.hibernate.test.ops;
+
+import java.util.Date;
+
+/**
+ * todo: describe TimestampedEntity
+ *
+ * @author Steve Ebersole
+ */
+public class TimestampedEntity {
+	private String id;
+	private String name;
+	private Date timestamp;
+
+	public TimestampedEntity() {
+	}
+
+	public TimestampedEntity(String id, String name) {
+		this.id = id;
+		this.name = name;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Date getTimestamp() {
+		return timestamp;
+	}
+
+	public void setTimestamp(Date timestamp) {
+		this.timestamp = timestamp;
+	}
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/VersionedEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/VersionedEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ops/VersionedEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,66 @@
+package org.hibernate.test.ops;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * VersionedEntity
+ *
+ * @author Steve Ebersole
+ */
+public class VersionedEntity {
+	private String id;
+	private String name;
+	private long version;
+
+	private VersionedEntity parent;
+	private Set children = new HashSet();
+
+	public VersionedEntity() {
+	}
+
+	public VersionedEntity(String id, String name) {
+		this.id = id;
+		this.name = name;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public long getVersion() {
+		return version;
+	}
+
+	public void setVersion(long version) {
+		this.version = version;
+	}
+
+	public VersionedEntity getParent() {
+		return parent;
+	}
+
+	public void setParent(VersionedEntity parent) {
+		this.parent = parent;
+	}
+
+	public Set getChildren() {
+		return children;
+	}
+
+	public void setChildren(Set children) {
+		this.children = children;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/Document.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/Document.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/Document.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+  Demonstrates the use of dirty-property optimistic locking.
+  We do not recommend this approach, since it does not work
+  for detached entities. Use version-based optimistic locking.
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.optlock">
+
+	<class name="Document" entity-name="LockDirty" table="Document" optimistic-lock="dirty" dynamic-update="true">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="title"/>
+		<property name="author"/>
+		<component name="pubDate">
+			<property name="year" not-null="true"/>
+			<property name="month"/>
+		</component>
+		<property name="summary"/>
+		<property name="totalSales" optimistic-lock="false"/>
+		<property name="text" column="`text`"/>
+	</class>
+
+	<class name="Document" entity-name="LockAll" table="Document" optimistic-lock="all" dynamic-update="true">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="title"/>
+		<property name="author"/>
+		<component name="pubDate">
+			<property name="year" not-null="true"/>
+			<property name="month"/>
+		</component>
+		<property name="summary"/>
+		<property name="totalSales" optimistic-lock="false"/>
+		<property name="text" column="`text`"/>
+	</class>
+
+</hibernate-mapping>
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/Document.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/Document.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/Document.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/Document.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,87 @@
+//$Id: Document.java 7552 2005-07-19 18:51:24Z oneovthafew $
+package org.hibernate.test.optlock;
+
+/**
+ * @author Gavin King
+ */
+public class Document {
+	private Long id;
+	private String author;
+	private String title;
+	private String summary;
+	private String text;
+	private PublicationDate pubDate;
+	private int totalSales;
+	/**
+	 * @return Returns the author.
+	 */
+	public String getAuthor() {
+		return author;
+	}
+	/**
+	 * @param author The author to set.
+	 */
+	public void setAuthor(String author) {
+		this.author = author;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the summary.
+	 */
+	public String getSummary() {
+		return summary;
+	}
+	/**
+	 * @param summary The summary to set.
+	 */
+	public void setSummary(String summary) {
+		this.summary = summary;
+	}
+	/**
+	 * @return Returns the text.
+	 */
+	public String getText() {
+		return text;
+	}
+	/**
+	 * @param text The text to set.
+	 */
+	public void setText(String text) {
+		this.text = text;
+	}
+	/**
+	 * @return Returns the title.
+	 */
+	public String getTitle() {
+		return title;
+	}
+	/**
+	 * @param title The title to set.
+	 */
+	public void setTitle(String title) {
+		this.title = title;
+	}
+	public PublicationDate getPubDate() {
+		return pubDate;
+	}
+	public void setPubDate(PublicationDate pubDate) {
+		this.pubDate = pubDate;
+	}
+	public int getTotalSales() {
+		return totalSales;
+	}
+	public void setTotalSales(int totalSales) {
+		this.totalSales = totalSales;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/Document.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/OptimisticLockTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/OptimisticLockTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/OptimisticLockTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,183 @@
+//$Id: OptimisticLockTest.java 11303 2007-03-19 22:06:14Z steve.ebersole at jboss.com $
+package org.hibernate.test.optlock;
+
+import junit.framework.Test;
+
+import org.hibernate.JDBCException;
+import org.hibernate.Session;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.StaleStateException;
+import org.hibernate.dialect.SQLServerDialect;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Tests relating to the optimisitc-lock mapping option.
+ *
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public class OptimisticLockTest extends FunctionalTestCase {
+	
+	public OptimisticLockTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "optlock/Document.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( OptimisticLockTest.class );
+	}
+	
+	public void testOptimisticLockDirty() {
+		testUpdateOptimisticLockFailure( "LockDirty" );
+	}
+
+	public void testOptimisticLockAll() {
+		testUpdateOptimisticLockFailure( "LockAll" );
+	}
+
+	public void testOptimisticLockDirtyDelete() {
+		testDeleteOptimisticLockFailure( "LockDirty" );
+	}
+
+	public void testOptimisticLockAllDelete() {
+		testDeleteOptimisticLockFailure( "LockAll" );
+	}
+
+	private void testUpdateOptimisticLockFailure(String entityName) {
+		if ( getDialect().doesRepeatableReadCauseReadersToBlockWriters() ) {
+			reportSkip( "deadlock", "update optimistic locking" );
+			return;
+		}
+		Session mainSession = openSession();
+		mainSession.beginTransaction();
+		Document doc = new Document();
+		doc.setTitle( "Hibernate in Action" );
+		doc.setAuthor( "Bauer et al" );
+		doc.setSummary( "Very boring book about persistence" );
+		doc.setText( "blah blah yada yada yada" );
+		doc.setPubDate( new PublicationDate( 2004 ) );
+		mainSession.save( entityName, doc );
+		mainSession.getTransaction().commit();
+		mainSession.close();
+
+		mainSession = openSession();
+		mainSession.beginTransaction();
+		doc = ( Document ) mainSession.get( entityName, doc.getId() );
+
+		Session otherSession = getSessions().openSession();
+		otherSession.beginTransaction();
+		Document otherDoc = ( Document ) otherSession.get( entityName, doc.getId() );
+		otherDoc.setSummary( "A modern classic" );
+		otherSession.getTransaction().commit();
+		otherSession.close();
+
+		try {
+			doc.setSummary( "A machiavelian achievement of epic proportions" );
+			mainSession.flush();
+			fail( "expecting opt lock failure" );
+		}
+		catch ( StaleObjectStateException expected ) {
+			// expected result...
+		}
+		catch( StaleStateException expected ) {
+			// expected result (if using versioned batching)...
+		}
+		catch( JDBCException e ) {
+			// SQLServer will report this condition via a SQLException
+			// when using its SNAPSHOT transaction isolation...
+			if ( ! ( getDialect() instanceof SQLServerDialect && e.getErrorCode() == 3960 ) ) {
+				throw e;
+			}
+			else {
+				// it seems to "lose track" of the transaction as well...
+				mainSession.getTransaction().rollback();
+				mainSession.beginTransaction();
+			}
+		}
+		mainSession.clear();
+		mainSession.getTransaction().commit();
+		mainSession.close();
+
+		mainSession = openSession();
+		mainSession.beginTransaction();
+		doc = ( Document ) mainSession.load( entityName, doc.getId() );
+		mainSession.delete( entityName, doc );
+		mainSession.getTransaction().commit();
+		mainSession.close();
+	}
+
+	private void testDeleteOptimisticLockFailure(String entityName) {
+		if ( getDialect().doesRepeatableReadCauseReadersToBlockWriters() ) {
+			reportSkip( "deadlock", "delete optimistic locking" );
+			return;
+		}
+		Session mainSession = openSession();
+		mainSession.beginTransaction();
+		Document doc = new Document();
+		doc.setTitle( "Hibernate in Action" );
+		doc.setAuthor( "Bauer et al" );
+		doc.setSummary( "Very boring book about persistence" );
+		doc.setText( "blah blah yada yada yada" );
+		doc.setPubDate( new PublicationDate( 2004 ) );
+		mainSession.save( entityName, doc );
+		mainSession.flush();
+		doc.setSummary( "A modern classic" );
+		mainSession.flush();
+		doc.getPubDate().setMonth( new Integer( 3 ) );
+		mainSession.flush();
+		mainSession.getTransaction().commit();
+		mainSession.close();
+
+		mainSession = openSession();
+		mainSession.beginTransaction();
+		doc = ( Document ) mainSession.get( entityName, doc.getId() );
+
+		Session otherSession = openSession();
+		otherSession.beginTransaction();
+		Document otherDoc = ( Document ) otherSession.get( entityName, doc.getId() );
+		otherDoc.setSummary( "my other summary" );
+		otherSession.flush();
+		otherSession.getTransaction().commit();
+		otherSession.close();
+
+		try {
+			mainSession.delete( doc );
+			mainSession.flush();
+			fail( "expecting opt lock failure" );
+		}
+		catch ( StaleObjectStateException e ) {
+			// expected
+		}
+		catch( StaleStateException expected ) {
+			// expected result (if using versioned batching)...
+		}
+		catch( JDBCException e ) {
+			// SQLServer will report this condition via a SQLException
+			// when using its SNAPSHOT transaction isolation...
+			if ( ! ( getDialect() instanceof SQLServerDialect && e.getErrorCode() == 3960 ) ) {
+				throw e;
+			}
+			else {
+				// it seems to "lose track" of the transaction as well...
+				mainSession.getTransaction().rollback();
+				mainSession.beginTransaction();
+			}
+		}
+		mainSession.clear();
+		mainSession.getTransaction().commit();
+		mainSession.close();
+
+		mainSession = openSession();
+		mainSession.beginTransaction();
+		doc = ( Document ) mainSession.load( entityName, doc.getId() );
+		mainSession.delete( entityName, doc );
+		mainSession.getTransaction().commit();
+		mainSession.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/OptimisticLockTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/PublicationDate.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/PublicationDate.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/PublicationDate.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: PublicationDate.java 7556 2005-07-19 23:22:27Z oneovthafew $
+package org.hibernate.test.optlock;
+
+public class PublicationDate {
+	private int year;
+	private Integer month;
+	
+	public PublicationDate(int year) {
+		this.year = year;
+	}
+	
+	PublicationDate() {}
+	
+	public Integer getMonth() {
+		return month;
+	}
+	public void setMonth(Integer month) {
+		this.month = month;
+	}
+	public int getYear() {
+		return year;
+	}
+	public void setYear(int year) {
+		this.year = year;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/optlock/PublicationDate.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/OrderByTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/OrderByTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/OrderByTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,88 @@
+//$Id: OrderByTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.ordered;
+
+import java.util.Iterator;
+
+import junit.framework.Test;
+
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class OrderByTest extends FunctionalTestCase {
+	
+	public OrderByTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "ordered/Search.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( OrderByTest.class );
+	}
+	
+	public void testOrderBy() {
+		Search s = new Search("Hibernate");
+		s.getSearchResults().add("jboss.com");
+		s.getSearchResults().add("hibernate.org");
+		s.getSearchResults().add("HiA");
+		
+		Session sess = openSession();
+		Transaction tx = sess.beginTransaction();
+		sess.persist(s);
+		sess.flush();
+		
+		sess.clear();
+		s = (Search) sess.createCriteria(Search.class).uniqueResult();
+		assertFalse( Hibernate.isInitialized( s.getSearchResults() ) );
+		Iterator iter = s.getSearchResults().iterator();
+		assertEquals( iter.next(), "HiA" );
+		assertEquals( iter.next(), "hibernate.org" );
+		assertEquals( iter.next(), "jboss.com" );
+		assertFalse( iter.hasNext() );
+		
+		sess.clear();
+		s = (Search) sess.createCriteria(Search.class)
+				.setFetchMode("searchResults", FetchMode.JOIN)
+				.uniqueResult();
+		assertTrue( Hibernate.isInitialized( s.getSearchResults() ) );
+		iter = s.getSearchResults().iterator();
+		assertEquals( iter.next(), "HiA" );
+		assertEquals( iter.next(), "hibernate.org" );
+		assertEquals( iter.next(), "jboss.com" );
+		assertFalse( iter.hasNext() );
+		
+		sess.clear();
+		s = (Search) sess.createQuery("from Search s left join fetch s.searchResults")
+				.uniqueResult();
+		assertTrue( Hibernate.isInitialized( s.getSearchResults() ) );
+		iter = s.getSearchResults().iterator();
+		assertEquals( iter.next(), "HiA" );
+		assertEquals( iter.next(), "hibernate.org" );
+		assertEquals( iter.next(), "jboss.com" );
+		assertFalse( iter.hasNext() );
+		
+		/*sess.clear();
+		s = (Search) sess.createCriteria(Search.class).uniqueResult();
+		assertFalse( Hibernate.isInitialized( s.getSearchResults() ) );
+		iter = sess.createFilter( s.getSearchResults(), "").iterate();
+		assertEquals( iter.next(), "HiA" );
+		assertEquals( iter.next(), "hibernate.org" );
+		assertEquals( iter.next(), "jboss.com" );
+		assertFalse( iter.hasNext() );*/
+		
+		sess.delete(s);
+		tx.commit();
+		sess.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/OrderByTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/Search.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/Search.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/Search.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+  
+-->
+
+<hibernate-mapping package="org.hibernate.test.ordered">
+	
+	<class name="Search">
+		<id name="searchString"/>
+		<set name="searchResults" order-by="lower(text) asc">
+			<key column="searchString"/>
+			<element column="text" type="string"/>
+		</set>
+	</class>
+	
+</hibernate-mapping>
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/Search.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/Search.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/Search.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/Search.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+//$Id: Search.java 7772 2005-08-05 23:03:46Z oneovthafew $
+package org.hibernate.test.ordered;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class Search {
+	private String searchString;
+	private Set searchResults = new HashSet();
+	
+	Search() {}
+	
+	public Search(String string) {
+		searchString = string;
+	}
+	
+	public Set getSearchResults() {
+		return searchResults;
+	}
+	public void setSearchResults(Set searchResults) {
+		this.searchResults = searchResults;
+	}
+	public String getSearchString() {
+		return searchString;
+	}
+	public void setSearchString(String searchString) {
+		this.searchString = searchString;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ordered/Search.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Mail.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Mail.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Mail.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE hibernate-mapping PUBLIC
+        '-//Hibernate/Hibernate Mapping DTD 3.0//EN'
+        'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd'>
+
+<hibernate-mapping package="org.hibernate.test.orphan" >
+
+    <class name="Mail" table="t_mail">
+
+        <id name="id" type="integer" column="id">
+            <generator class="native" />     
+        </id>
+
+        <property name="alias">
+            <column name="alias" length="20"/>
+        </property>
+
+        <many-to-one name="user"
+                 class="User"
+                 cascade="save-update"
+                 column="userid"
+                 not-null="true"
+                 property-ref="userid"/>
+       
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Mail.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Mail.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Mail.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+package org.hibernate.test.orphan;
+
+public class Mail {
+
+	private Integer id;
+	private String alias;
+	private User user;
+
+	/*package*/ Mail() {
+	}
+
+	/*package*/ Mail(String alias, User user) {
+		this.alias = alias;
+		this.user = user;
+	}
+
+	public Integer getId() {
+		return id;
+	}
+
+	protected void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getAlias() {
+		return alias;
+	}
+
+	public void setAlias(String alias) {
+		this.alias = alias;
+	}
+
+	public User getUser() {
+		return user;
+	}
+
+	public void setUser(User user) {
+		this.user = user;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/OrphanSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/OrphanSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/OrphanSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+package org.hibernate.test.orphan;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class OrphanSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "orphan delete suite" );
+		suite.addTest( OrphanTest.suite() );
+		suite.addTest( PropertyRefTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/OrphanTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/OrphanTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/OrphanTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,299 @@
+//$Id: OrphanTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.orphan;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.util.SerializationHelper;
+
+/**
+ * @author Gavin King
+ */
+public class OrphanTest extends FunctionalTestCase {
+	
+	public OrphanTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "orphan/Product.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( OrphanTest.class );
+	}
+	
+	public void testOrphanDeleteOnDelete() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+		Product prod = new Product();
+		prod.setName("Widget");
+		Part part = new Part();
+		part.setName("Widge");
+		part.setDescription("part if a Widget");
+		prod.getParts().add(part);
+		Part part2 = new Part();
+		part2.setName("Get");
+		part2.setDescription("another part if a Widget");
+		prod.getParts().add(part2);
+		session.persist(prod);
+		session.flush();
+		
+		prod.getParts().remove(part);
+		
+		session.delete(prod);
+		
+		t.commit();
+		session.close();
+		
+		session = openSession();
+		t = session.beginTransaction();
+		assertNull( session.get(Part.class, "Widge") );
+		assertNull( session.get(Part.class, "Get") );
+		assertNull( session.get(Product.class, "Widget") );
+		t.commit();
+		session.close();
+	}
+	
+	public void testOrphanDeleteAfterPersist() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+		Product prod = new Product();
+		prod.setName("Widget");
+		Part part = new Part();
+		part.setName("Widge");
+		part.setDescription("part if a Widget");
+		prod.getParts().add(part);
+		Part part2 = new Part();
+		part2.setName("Get");
+		part2.setDescription("another part if a Widget");
+		prod.getParts().add(part2);
+		session.persist(prod);
+		
+		prod.getParts().remove(part);
+		
+		t.commit();
+		session.close();
+		
+		session = openSession();
+		t = session.beginTransaction();
+		assertNull( session.get(Part.class, "Widge") );
+		assertNotNull( session.get(Part.class, "Get") );
+		session.delete( session.get(Product.class, "Widget") );
+		t.commit();
+		session.close();
+	}
+	
+	public void testOrphanDeleteAfterPersistAndFlush() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+		Product prod = new Product();
+		prod.setName("Widget");
+		Part part = new Part();
+		part.setName("Widge");
+		part.setDescription("part if a Widget");
+		prod.getParts().add(part);
+		Part part2 = new Part();
+		part2.setName("Get");
+		part2.setDescription("another part if a Widget");
+		prod.getParts().add(part2);
+		session.persist(prod);
+		session.flush();
+		
+		prod.getParts().remove(part);
+		
+		t.commit();
+		session.close();
+		
+		session = openSession();
+		t = session.beginTransaction();
+		assertNull( session.get(Part.class, "Widge") );
+		assertNotNull( session.get(Part.class, "Get") );
+		session.delete( session.get(Product.class, "Widget") );
+		t.commit();
+		session.close();
+	}
+	
+	public void testOrphanDeleteAfterLock() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+		Product prod = new Product();
+		prod.setName("Widget");
+		Part part = new Part();
+		part.setName("Widge");
+		part.setDescription("part if a Widget");
+		prod.getParts().add(part);
+		Part part2 = new Part();
+		part2.setName("Get");
+		part2.setDescription("another part if a Widget");
+		prod.getParts().add(part2);
+		session.persist(prod);
+		t.commit();
+		session.close();
+		
+		
+		session = openSession();
+		t = session.beginTransaction();
+		session.lock(prod, LockMode.READ);
+		prod.getParts().remove(part);
+		t.commit();
+		session.close();
+		
+		session = openSession();
+		t = session.beginTransaction();
+		assertNull( session.get(Part.class, "Widge") );
+		assertNotNull( session.get(Part.class, "Get") );
+		session.delete( session.get(Product.class, "Widget") );
+		t.commit();
+		session.close();
+	}
+	
+	public void testOrphanDeleteOnSaveOrUpdate() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+		Product prod = new Product();
+		prod.setName("Widget");
+		Part part = new Part();
+		part.setName("Widge");
+		part.setDescription("part if a Widget");
+		prod.getParts().add(part);
+		Part part2 = new Part();
+		part2.setName("Get");
+		part2.setDescription("another part if a Widget");
+		prod.getParts().add(part2);
+		session.persist(prod);
+		t.commit();
+		session.close();
+		
+		prod.getParts().remove(part);
+		
+		session = openSession();
+		t = session.beginTransaction();
+		session.saveOrUpdate(prod);
+		t.commit();
+		session.close();
+		
+		session = openSession();
+		t = session.beginTransaction();
+		assertNull( session.get(Part.class, "Widge") );
+		assertNotNull( session.get(Part.class, "Get") );
+		session.delete( session.get(Product.class, "Widget") );
+		t.commit();
+		session.close();
+	}
+	
+	public void testOrphanDeleteOnSaveOrUpdateAfterSerialization() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+		Product prod = new Product();
+		prod.setName("Widget");
+		Part part = new Part();
+		part.setName("Widge");
+		part.setDescription("part if a Widget");
+		prod.getParts().add(part);
+		Part part2 = new Part();
+		part2.setName("Get");
+		part2.setDescription("another part if a Widget");
+		prod.getParts().add(part2);
+		session.persist(prod);
+		t.commit();
+		session.close();
+		
+		prod.getParts().remove(part);
+		
+		prod = (Product) SerializationHelper.clone(prod);
+		
+		session = openSession();
+		t = session.beginTransaction();
+		session.saveOrUpdate(prod);
+		t.commit();
+		session.close();
+		
+		session = openSession();
+		t = session.beginTransaction();
+		assertNull( session.get(Part.class, "Widge") );
+		assertNotNull( session.get(Part.class, "Get") );
+		session.delete( session.get(Product.class, "Widget") );
+		t.commit();
+		session.close();
+	}
+	
+	public void testOrphanDelete() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+		Product prod = new Product();
+		prod.setName("Widget");
+		Part part = new Part();
+		part.setName("Widge");
+		part.setDescription("part if a Widget");
+		prod.getParts().add(part);
+		Part part2 = new Part();
+		part2.setName("Get");
+		part2.setDescription("another part if a Widget");
+		prod.getParts().add(part2);
+		session.persist(prod);
+		t.commit();
+		session.close();
+		
+		getSessions().evict(Product.class);
+		getSessions().evict(Part.class);
+		
+		session = openSession();
+		t = session.beginTransaction();
+		prod = (Product) session.get(Product.class, "Widget");
+		assertTrue( Hibernate.isInitialized( prod.getParts() ) );
+		part = (Part) session.get(Part.class, "Widge");
+		prod.getParts().remove(part);
+		t.commit();
+		session.close();
+		
+		session = openSession();
+		t = session.beginTransaction();
+		assertNull( session.get(Part.class, "Widge") );
+		assertNotNull( session.get(Part.class, "Get") );
+		session.delete( session.get(Product.class, "Widget") );
+		t.commit();
+		session.close();
+	}
+	
+	public void testOrphanDeleteOnMerge() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+		Product prod = new Product();
+		prod.setName("Widget");
+		Part part = new Part();
+		part.setName("Widge");
+		part.setDescription("part if a Widget");
+		prod.getParts().add(part);
+		Part part2 = new Part();
+		part2.setName("Get");
+		part2.setDescription("another part if a Widget");
+		prod.getParts().add(part2);
+		session.persist(prod);
+		t.commit();
+		session.close();
+		
+		prod.getParts().remove(part);
+		
+		session = openSession();
+		t = session.beginTransaction();
+		session.merge(prod);
+		t.commit();
+		session.close();
+		
+		session = openSession();
+		t = session.beginTransaction();
+		assertNull( session.get(Part.class, "Widge") );
+		assertNotNull( session.get(Part.class, "Get") );
+		session.delete( session.get(Product.class, "Widget") );
+		t.commit();
+		session.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/OrphanTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Part.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Part.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Part.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+//$Id: Part.java 5725 2005-02-14 12:10:15Z oneovthafew $
+package org.hibernate.test.orphan;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Part implements Serializable {
+	private String name;
+	private String description;
+	public String getDescription() {
+		return description;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Part.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Product.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Product.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Product.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.orphan">
+
+	<class name="Product" table="t_product">
+		<id name="name"/>
+		<set name="parts" cascade="all,delete-orphan" fetch="join">
+			<key column="productName" not-null="true"/>
+			<one-to-many class="Part"/>
+		</set>
+	</class>
+	
+	<class name="Part" table="t_part">
+		<id name="name"/>
+		<property name="description" not-null="true"/>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Product.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Product.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Product.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Product.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: Product.java 5725 2005-02-14 12:10:15Z oneovthafew $
+package org.hibernate.test.orphan;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class Product implements Serializable {
+	private String name;
+	private Set parts = new HashSet();
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public Set getParts() {
+		return parts;
+	}
+	public void setParts(Set parts) {
+		this.parts = parts;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/Product.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/PropertyRefTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/PropertyRefTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/PropertyRefTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,56 @@
+// $Id: PropertyRefTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.orphan;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+
+/**
+ * Test for HHH-565
+ *
+ * @author Steve Ebersole
+ */
+public class PropertyRefTest extends FunctionalTestCase {
+
+	public PropertyRefTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "orphan/User.hbm.xml", "orphan/Mail.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PropertyRefTest.class );
+	}
+
+	public void testDeleteParentWithBidirOrphanDeleteCollectionBasedOnPropertyRef() {
+		Session session = openSession();
+		Transaction txn = session.beginTransaction();
+		User user = new User( "test" );
+		user.addMail( "test" );
+		user.addMail( "test" );
+		session.save( user );
+		txn.commit();
+		session.close();
+
+		session = openSession();
+		txn = session.beginTransaction();
+		user = ( User ) session.load( User.class, user.getId() );
+		session.delete( user );
+		txn.commit();
+		session.close();
+
+		session = openSession();
+		txn = session.beginTransaction();
+		session.createQuery( "delete from Mail where alias = :alias" ).setString( "alias", "test" ).executeUpdate();
+		session.createQuery( "delete from User where userid = :userid" ).setString( "userid", "test" ).executeUpdate();
+		txn.commit();
+		session.close();
+	}
+	
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/User.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/User.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/User.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE hibernate-mapping PUBLIC
+        '-//Hibernate/Hibernate Mapping DTD 3.0//EN'
+        'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd'>
+
+<hibernate-mapping package="org.hibernate.test.orphan" >
+
+    <class name="User" table="t_user">
+
+        <id name="id" type="integer" column="id">
+            <generator class="native" />
+        </id>
+
+        <property name="userid">
+            <column name="userid" length="32" not-null="true"/>
+        </property>
+
+        <set name="mail" table="mail" cascade="all, delete-orphan" inverse="true" lazy="false">
+            <key column="userid" property-ref="userid" not-null="false"/>
+            <one-to-many class="Mail"/>
+        </set>
+
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/orphan/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+/*
+ * User.java
+ *
+ * Created on May 3, 2005, 9:42 AM
+ */
+
+package org.hibernate.test.orphan;
+
+import java.util.HashSet;
+import java.util.Set;
+
+
+/**
+ * @author Kevin
+ */
+public class User {
+
+	private Integer id;
+	private String userid;
+	private Set mail = new HashSet();
+
+	public User() {
+	}
+
+	public User(String userid) {
+		this.userid = userid;
+	}
+
+	public Integer getId() {
+		return id;
+	}
+
+	protected void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getUserid() {
+		return userid;
+	}
+
+	public void setUserid(String userid) {
+		this.userid = userid;
+	}
+
+	public Set getMail() {
+		return mail;
+	}
+
+	private void setMail(Set mail) {
+		this.mail = mail;
+	}
+
+	public Mail addMail(String alias) {
+		Mail mail = new Mail( alias, this );
+		getMail().add( mail );
+		return mail;
+	}
+
+	public void removeMail(Mail mail) {
+		getMail().remove( mail );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/DataPoint.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/DataPoint.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/DataPoint.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.pagination">
+
+	<class name="DataPoint" 
+		dynamic-update="true">
+		<!--rowid="rowid"--> <!-- remove this if not oracle -->
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		<property name="x">
+			<column name="xval" not-null="true" precision="4" unique-key="xy"/>
+		</property>
+		<property name="y">
+			<column name="yval" not-null="true" precision="4" unique-key="xy"/>
+		</property>
+		<property name="description"/>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/DataPoint.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/DataPoint.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/DataPoint.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/DataPoint.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+//$Id: DataPoint.java 7867 2005-08-11 23:35:33Z oneovthafew $
+package org.hibernate.test.pagination;
+
+import java.math.BigDecimal;
+
+/**
+ * @author Gavin King
+ */
+public class DataPoint {
+	private long id;
+	private BigDecimal x;
+	private BigDecimal y;
+	private String description;
+	/**
+	 * @return Returns the description.
+	 */
+	public String getDescription() {
+		return description;
+	}
+	/**
+	 * @param description The description to set.
+	 */
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the x.
+	 */
+	public BigDecimal getX() {
+		return x;
+	}
+	/**
+	 * @param x The x to set.
+	 */
+	public void setX(BigDecimal x) {
+		this.x = x;
+	}
+	/**
+	 * @return Returns the y.
+	 */
+	public BigDecimal getY() {
+		return y;
+	}
+	/**
+	 * @param y The y to set.
+	 */
+	public void setY(BigDecimal y) {
+		this.y = y;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/DataPoint.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/PaginationTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/PaginationTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/PaginationTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,76 @@
+//$Id: PaginationTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.pagination;
+
+import java.math.BigDecimal;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.Order;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class PaginationTest extends FunctionalTestCase {
+	
+	public PaginationTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "pagination/DataPoint.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.STATEMENT_BATCH_SIZE, "20");
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PaginationTest.class );
+	}
+	
+	public void testPagination() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();		
+		for ( int i=0; i<10; i++ ) {
+			DataPoint dp = new DataPoint();
+			dp.setX( new BigDecimal(i * 0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
+			dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
+			s.persist(dp);
+		}
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		int size = s.createSQLQuery("select id, xval, yval, description from DataPoint order by xval, yval")
+			.addEntity(DataPoint.class)
+			.setMaxResults(5)
+			.list().size();
+		assertEquals(size, 5);
+		size = s.createQuery("from DataPoint order by x, y")
+			.setFirstResult(5)
+			.setMaxResults(2)
+			.list().size();
+		assertEquals(size, 2);
+		size = s.createCriteria(DataPoint.class)
+			.addOrder( Order.asc("x") )
+			.addOrder( Order.asc("y") )
+			.setFirstResult(8)
+			.list().size();
+		assertEquals(size, 2);
+		t.commit();
+		s.close();
+		
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pagination/PaginationTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pretty/SQLFormatterTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pretty/SQLFormatterTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/pretty/SQLFormatterTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+package org.hibernate.test.pretty;
+
+import java.util.StringTokenizer;
+
+import org.hibernate.pretty.Formatter;
+import org.hibernate.junit.UnitTestCase;
+
+public class SQLFormatterTest extends UnitTestCase {
+
+	public SQLFormatterTest(String string) {
+		super( string );
+	}
+
+	public void testNoLoss() {
+		assertNoLoss("insert into Address (city, state, zip, \"from\") values (?, ?, ?, 'insert value')");
+		assertNoLoss("delete from Address where id = ? and version = ?");
+		assertNoLoss("update Address set city = ?, state=?, zip=?, version = ? where id = ? and version = ?");
+		assertNoLoss("update Address set city = ?, state=?, zip=?, version = ? where id in (select aid from Person)");
+		assertNoLoss("select p.name, a.zipCode, count(*) from Person p left outer join Employee e on e.id = p.id and p.type = 'E' and (e.effective>? or e.effective<?) join Address a on a.pid = p.id where upper(p.name) like 'G%' and p.age > 100 and (p.sex = 'M' or p.sex = 'F') and coalesce( trim(a.street), a.city, (a.zip) ) is not null order by p.name asc, a.zipCode asc");
+		assertNoLoss("select ( (m.age - p.age) * 12 ), trim(upper(p.name)) from Person p, Person m where p.mother = m.id and ( p.age = (select max(p0.age) from Person p0 where (p0.mother=m.id)) and p.name like ? )");
+		assertNoLoss("select * from Address a join Person p on a.pid = p.id, Person m join Address b on b.pid = m.id where p.mother = m.id and p.name like ?");
+		assertNoLoss("select case when p.age > 50 then 'old' when p.age > 18 then 'adult' else 'child' end from Person p where ( case when p.age > 50 then 'old' when p.age > 18 then 'adult' else 'child' end ) like ?");
+		assertNoLoss("/* Here we' go! */ select case when p.age > 50 then 'old' when p.age > 18 then 'adult' else 'child' end from Person p where ( case when p.age > 50 then 'old' when p.age > 18 then 'adult' else 'child' end ) like ?");
+	}
+
+	private void assertNoLoss(String query) {
+		String formattedQuery = new Formatter(query).format();
+		StringTokenizer formatted = new StringTokenizer(formattedQuery," \t\n\r\f()");
+		StringTokenizer plain = new StringTokenizer(query," \t\n\r\f()");
+
+		System.out.println("Original: " + query);
+		System.out.println("Formatted: " + formattedQuery);
+		while(formatted.hasMoreTokens() && plain.hasMoreTokens()) {
+			String plainToken = plain.nextToken();
+			String formattedToken = formatted.nextToken();
+			assertEquals("formatter did not return the same token",plainToken, formattedToken);
+		}
+		assertFalse(formatted.hasMoreTokens());
+		assertFalse(plain.hasMoreTokens());
+	}
+	
+		
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/PropertyRefSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/PropertyRefSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/PropertyRefSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+package org.hibernate.test.propertyref;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.propertyref.basic.PropertyRefTest;
+import org.hibernate.test.propertyref.component.complete.CompleteComponentPropertyRefTest;
+import org.hibernate.test.propertyref.component.partial.PartialComponentPropertyRefTest;
+import org.hibernate.test.propertyref.inheritence.discrim.SubclassPropertyRefTest;
+import org.hibernate.test.propertyref.inheritence.joined.JoinedSubclassPropertyRefTest;
+import org.hibernate.test.propertyref.inheritence.union.UnionSubclassPropertyRefTest;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class PropertyRefSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "property-ref suite" );
+		suite.addTest( PropertyRefTest.suite() );
+		suite.addTest( CompleteComponentPropertyRefTest.suite() );
+		suite.addTest( PartialComponentPropertyRefTest.suite() );
+		suite.addTest( SubclassPropertyRefTest.suite() );
+		suite.addTest( JoinedSubclassPropertyRefTest.suite() );
+		suite.addTest( UnionSubclassPropertyRefTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Account.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Account.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Account.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+//$Id: Account.java 4399 2004-08-21 08:43:20Z oneovthafew $
+package org.hibernate.test.propertyref.basic;
+
+/**
+ * @author Gavin King
+ */
+public class Account {
+	private String accountId;
+	private Person user;
+	private char type;
+	/**
+	 * @return Returns the user.
+	 */
+	public Person getUser() {
+		return user;
+	}
+	/**
+	 * @param user The user to set.
+	 */
+	public void setUser(Person user) {
+		this.user = user;
+	}
+	/**
+	 * @return Returns the accountId.
+	 */
+	public String getAccountId() {
+		return accountId;
+	}
+	/**
+	 * @param accountId The accountId to set.
+	 */
+	public void setAccountId(String accountId) {
+		this.accountId = accountId;
+	}
+	/**
+	 * @return Returns the type.
+	 */
+	public char getType() {
+		return type;
+	}
+	/**
+	 * @param type The type to set.
+	 */
+	public void setType(char type) {
+		this.type = type;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,73 @@
+//$Id: Address.java 4390 2004-08-20 07:54:48Z oneovthafew $
+package org.hibernate.test.propertyref.basic;
+
+/**
+ * @author gavin
+ */
+public class Address {
+	private Long id;
+	private String address;
+	private String zip;
+	private String country;
+	private Person person;
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the person.
+	 */
+	public Person getPerson() {
+		return person;
+	}
+	/**
+	 * @param person The person to set.
+	 */
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+	/**
+	 * @return Returns the address.
+	 */
+	public String getAddress() {
+		return address;
+	}
+	/**
+	 * @param address The address to set.
+	 */
+	public void setAddress(String address) {
+		this.address = address;
+	}
+	/**
+	 * @return Returns the country.
+	 */
+	public String getCountry() {
+		return country;
+	}
+	/**
+	 * @param country The country to set.
+	 */
+	public void setCountry(String country) {
+		this.country = country;
+	}
+	/**
+	 * @return Returns the zip.
+	 */
+	public String getZip() {
+		return zip;
+	}
+	/**
+	 * @param zip The zip to set.
+	 */
+	public void setZip(String zip) {
+		this.zip = zip;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Group.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Group.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Group.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+//$Id: Group.java 7589 2005-07-21 01:56:42Z oneovthafew $
+package org.hibernate.test.propertyref.basic;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class Group {
+	private String name;
+	private Set users = new HashSet();
+	
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public Set getUsers() {
+		return users;
+	}
+	public void setUsers(Set users) {
+		this.users = users;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+  Demonstrates the use of property-ref to map legacy data where
+  foreign keys reference something other than the primary key of
+  the associated entity. Here we show:
+
+  (1) A one-to-one foreign key association (prefer primary key
+      associations)
+
+  (2) A bidirectional one-to-many association on a key that is
+      not the primary key (prefer associations from foreign keys
+      to primary keys)
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.propertyref.basic">
+
+    <class name="Person" table="PROPREF_PERS">
+        <id name="id">
+            <generator class="hilo"/>
+        </id>
+        <property name="name" length="100"/>
+        <property name="userId" column="person_userid" length="8" unique="true"/>
+        <one-to-one name="address" property-ref="person" cascade="all" fetch="join"/>
+        <set name="accounts" inverse="true">
+            <key column="userId" property-ref="userId"/>
+            <one-to-many class="Account"/>
+        </set>
+        <bag name="systems" table="USER_SYSTEM" lazy="true" inverse="false" cascade="all">
+            <key column="USER_ID" property-ref="userId" />
+            <element type="string" column="SYSTEM" />
+        </bag>
+    </class>
+
+    <class name="Address" table="PROPREF_ADDR">
+        <id name="id">
+            <generator class="hilo"/>
+        </id>
+        <property name="address" length="300"/>
+        <property name="zip" length="5"/>
+        <property name="country" length="25"/>
+        <many-to-one name="person" unique="true" not-null="true"/>
+    </class>
+
+    <class name="Account" table="PROPREF_ACCT">
+        <id name="accountId" length="32">
+            <generator class="uuid.hex"/>
+        </id>
+        <many-to-one name="user" column="userId" property-ref="userId"/>
+        <property name="type" not-null="true"/>
+    </class>
+
+    <class name="Group" table="PROPREF_GRP">
+        <id name="name"/>
+        <set name="users" table="PROPREF_USERGROUP" cascade="save-update">
+            <key column="groupName"/>
+            <many-to-many column="userId" class="Person" property-ref="userId"/>
+        </set>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,88 @@
+//$Id: Person.java 10396 2006-09-01 08:48:02 -0500 (Fri, 01 Sep 2006) steve.ebersole at jboss.com $
+package org.hibernate.test.propertyref.basic;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @author gavin
+ */
+public class Person {
+	private Long id;
+	private String name;
+	private Address address;
+	private String userId;
+	private Set accounts = new HashSet();
+	private List systems = new ArrayList();
+
+	/**
+	 * @return Returns the userId.
+	 */
+	public String getUserId() {
+		return userId;
+	}
+	/**
+	 * @param userId The userId to set.
+	 */
+	public void setUserId(String userId) {
+		this.userId = userId;
+	}
+	/**
+	 * @return Returns the address.
+	 */
+	public Address getAddress() {
+		return address;
+	}
+	/**
+	 * @param address The address to set.
+	 */
+	public void setAddress(Address address) {
+		this.address = address;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	/**
+	 * @return Returns the accounts.
+	 */
+	public Set getAccounts() {
+		return accounts;
+	}
+	/**
+	 * @param accounts The accounts to set.
+	 */
+	public void setAccounts(Set accounts) {
+		this.accounts = accounts;
+	}
+
+	public List getSystems() {
+		return systems;
+	}
+
+	public void setSystems(List systems) {
+		this.systems = systems;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/PropertyRefTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/PropertyRefTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/basic/PropertyRefTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,269 @@
+//$Id: PropertyRefTest.java 10396 2006-09-01 08:48:02 -0500 (Fri, 01 Sep 2006) steve.ebersole at jboss.com $
+package org.hibernate.test.propertyref.basic;
+
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.ForeignKey;
+import org.hibernate.mapping.PersistentClass;
+
+/**
+ * @author Gavin King
+ */
+public class PropertyRefTest extends FunctionalTestCase {
+	
+	public PropertyRefTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "propertyref/basic/Person.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.DEFAULT_BATCH_FETCH_SIZE, "1");
+		cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PropertyRefTest.class );
+	}
+
+	public void testNonLazyBagKeyPropertyRef() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person p = new Person();
+		p.setName( "Steve" );
+		p.setUserId( "steve" );
+		p.getSystems().add( "QA" );
+		p.getSystems().add( "R&D" );
+		s.persist( p );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery( "from Person" ).list();
+		s.clear();
+		s.createSQLQuery( "select {p.*} from PROPREF_PERS {p}" )
+				.addEntity( "p", Person.class.getName() )
+				.list();
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		List results = s.createQuery( "from Person" ).list();
+		Iterator itr = results.iterator();
+		while ( itr.hasNext() ) {
+			s.delete( itr.next() );
+		}
+		t.commit();
+		s.close();
+	}
+
+	public void testManyToManyPropertyRef() {
+		// prepare some test data relating to the Group->Person many-to-many association
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person p = new Person();
+		p.setName( "Steve" );
+		p.setUserId( "steve" );
+		s.persist( p );
+		Group g = new Group();
+		g.setName( "Admins" );
+		g.getUsers().add( p );
+		s.persist( g );
+		// force a flush and detachment here to test reattachment handling of the property-ref (HHH-1531)
+		t.commit();
+		s.close();
+
+		Person p2 = new Person();
+		p2.setName( "Max" );
+		p2.setUserId( "max" );
+		g.getUsers().add( p2 );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.update( g );
+		t.commit();
+		s.close();
+
+		// test retrieval of the group
+		s = openSession();
+		t = s.beginTransaction();
+		g = ( Group ) s.createQuery( "from Group g left join fetch g.users" ).uniqueResult();
+		assertTrue( Hibernate.isInitialized( g.getUsers() ) );
+		assertEquals( 2, g.getUsers().size() );
+		s.delete( g );
+		s.createQuery( "delete Person" ).executeUpdate();
+		t.commit();
+		s.close();
+	}
+	
+	public void testOneToOnePropertyRef() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person p = new Person();
+		p.setName("Steve");
+		p.setUserId("steve");
+		Address a = new Address();
+		a.setAddress("Texas");
+		a.setCountry("USA");
+		p.setAddress(a);
+		a.setPerson(p);
+		s.save(p);
+		Person p2 = new Person();
+		p2.setName("Max");
+		p2.setUserId("max");
+		s.save(p2);
+		Account act = new Account();
+		act.setType('c');
+		act.setUser(p2);
+		p2.getAccounts().add(act);
+		s.save(act);
+		s.flush();
+		s.clear();
+		
+		p = (Person) s.get( Person.class, p.getId() ); //get address reference by outer join
+		p2 = (Person) s.get( Person.class, p2.getId() ); //get null address reference by outer join
+		assertNull( p2.getAddress() );
+		assertNotNull( p.getAddress() );
+		List l = s.createQuery("from Person").list(); //pull address references for cache
+		assertEquals( l.size(), 2 );
+		assertTrue( l.contains(p) && l.contains(p2) );
+		s.clear();
+		
+		l = s.createQuery("from Person p order by p.name").list(); //get address references by sequential selects
+		assertEquals( l.size(), 2 );
+		assertNull( ( (Person) l.get(0) ).getAddress() );
+		assertNotNull( ( (Person) l.get(1) ).getAddress() );
+		s.clear();
+		
+		l = s.createQuery("from Person p left join fetch p.address a order by a.country").list(); //get em by outer join
+		assertEquals( l.size(), 2 );
+		if ( ( (Person) l.get(0) ).getName().equals("Max") ) {
+			assertNull( ( (Person) l.get(0) ).getAddress() );
+			assertNotNull( ( (Person) l.get(1) ).getAddress() );
+		}
+		else {
+			assertNull( ( (Person) l.get(1) ).getAddress() );
+			assertNotNull( ( (Person) l.get(0) ).getAddress() );
+		}
+		s.clear();
+		
+		l = s.createQuery("from Person p left join p.accounts a").list();
+		for ( int i=0; i<2; i++ ) {
+			Object[] row = (Object[]) l.get(i);
+			Person px = (Person) row[0];
+			assertFalse( Hibernate.isInitialized( px.getAccounts() ) );
+			assertTrue( px.getAccounts().size()>0 || row[1]==null );
+		}
+		s.clear();
+
+		l = s.createQuery("from Person p left join fetch p.accounts a order by p.name").list();
+		Person p0 = (Person) l.get(0);
+		assertTrue( Hibernate.isInitialized( p0.getAccounts() ) );
+		assertEquals( p0.getAccounts().size(), 1 );
+		assertSame( ( (Account) p0.getAccounts().iterator().next() ).getUser(), p0 );
+		Person p1 = (Person) l.get(1);
+		assertTrue( Hibernate.isInitialized( p1.getAccounts() ) );
+		assertEquals( p1.getAccounts().size(), 0 );
+		s.clear();
+		Account acc = (Account) s.createQuery("from Account a left join fetch a.user").uniqueResult();
+		assertTrue( Hibernate.isInitialized(acc.getUser()) );
+		assertNotNull(acc.getUser());
+		assertTrue( acc.getUser().getAccounts().contains(acc) );
+		
+		s.createQuery("delete from Address").executeUpdate();
+		s.createQuery("delete from Account").executeUpdate(); // to not break constraint violation between Person and Account
+		s.createQuery("delete from Person").executeUpdate();
+		
+		t.commit();
+		s.close();
+	}
+
+	
+	public void testJoinFetchPropertyRef() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person p = new Person();
+		p.setName("Steve");
+		p.setUserId("steve");
+		Address a = new Address();
+		a.setAddress("Texas");
+		a.setCountry("USA");
+		p.setAddress(a);
+		a.setPerson(p);
+		s.save(p);
+
+		s.flush();
+		s.clear();
+
+		getSessions().getStatistics().clear();
+
+		p = (Person) s.get( Person.class, p.getId() ); //get address reference by outer join
+		
+		assertTrue( Hibernate.isInitialized( p.getAddress() ) );
+		assertNotNull( p.getAddress() );
+        assertEquals( getSessions().getStatistics().getPrepareStatementCount(), 1 );
+        assertEquals( getSessions().getStatistics().getEntityFetchCount(), 0 );
+
+		s.clear();
+
+		getSessions().getStatistics().clear();
+
+		p = (Person) s.createCriteria(Person.class)
+			.setFetchMode("address", FetchMode.SELECT)
+			.uniqueResult(); //get address reference by select
+		
+		assertTrue( Hibernate.isInitialized( p.getAddress() ) );
+		assertNotNull( p.getAddress() );
+        assertEquals( getSessions().getStatistics().getPrepareStatementCount(), 2 );
+        assertEquals( getSessions().getStatistics().getEntityFetchCount(), 0 );
+
+		s.createQuery("delete from Address").executeUpdate();
+		s.createQuery("delete from Person").executeUpdate();
+		
+		t.commit();
+		s.close();
+	}
+
+	public void testForeignKeyCreation() {
+		PersistentClass classMapping = getCfg().getClassMapping("org.hibernate.test.propertyref.basic.Account");
+		
+		Iterator foreignKeyIterator = classMapping.getTable().getForeignKeyIterator();
+		boolean found = false;
+		while ( foreignKeyIterator.hasNext() ) {
+			ForeignKey element = (ForeignKey) foreignKeyIterator.next();
+			if(element.getReferencedEntityName().equals(Person.class.getName() ) ) {
+				
+				if(!element.isReferenceToPrimaryKey() ) {
+					List referencedColumns = element.getReferencedColumns();
+					Column column = (Column) referencedColumns.get(0);
+					if(column.getName().equals("person_userid") ) {
+						found = true; // extend test to include the columns
+					}				
+				}
+			}
+		}
+		
+		assertTrue("Property ref foreign key not found",found);
+	}
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Account.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Account.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Account.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+package org.hibernate.test.propertyref.component.complete;
+
+
+public class Account {
+	private String number;
+	private Person owner;
+
+	public Person getOwner() {
+		return owner;
+	}
+
+	public void setOwner(Person owner) {
+		this.owner = owner;
+	}
+
+	public String getNumber() {
+		return number;
+	}
+
+	public void setNumber(String number) {
+		this.number = number;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/CompleteComponentPropertyRefTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/CompleteComponentPropertyRefTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/CompleteComponentPropertyRefTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,71 @@
+package org.hibernate.test.propertyref.component.complete;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class CompleteComponentPropertyRefTest extends FunctionalTestCase {
+
+	public CompleteComponentPropertyRefTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "propertyref/component/complete/Mapping.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CompleteComponentPropertyRefTest.class );
+	}
+
+	public void testComponentPropertyRef() {
+		Person p = new Person();
+		p.setIdentity( new Identity() );
+		Account a = new Account();
+		a.setNumber("123-12345-1236");
+		a.setOwner(p);
+		p.getIdentity().setName("Gavin");
+		p.getIdentity().setSsn("123-12-1234");
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		s.persist(p);
+		s.persist(a);
+		s.flush();
+		s.clear();
+
+		a = (Account) s.createQuery("from Account a left join fetch a.owner").uniqueResult();
+		assertTrue( Hibernate.isInitialized( a.getOwner() ) );
+		assertNotNull( a.getOwner() );
+		assertEquals( "Gavin", a.getOwner().getIdentity().getName() );
+		s.clear();
+
+		a = (Account) s.get(Account.class, "123-12345-1236");
+		assertFalse( Hibernate.isInitialized( a.getOwner() ) );
+		assertNotNull( a.getOwner() );
+		assertEquals( "Gavin", a.getOwner().getIdentity().getName() );
+		assertTrue( Hibernate.isInitialized( a.getOwner() ) );
+
+		s.clear();
+
+		getSessions().evict(Account.class);
+		getSessions().evict(Person.class);
+
+		a = (Account) s.get(Account.class, "123-12345-1236");
+		assertTrue( Hibernate.isInitialized( a.getOwner() ) );
+		assertNotNull( a.getOwner() );
+		assertEquals( "Gavin", a.getOwner().getIdentity().getName() );
+		assertTrue( Hibernate.isInitialized( a.getOwner() ) );
+
+		s.delete( a );
+		s.delete( a.getOwner() );
+		tx.commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Identity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Identity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Identity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+package org.hibernate.test.propertyref.component.complete;
+
+import java.io.Serializable;
+
+public class Identity implements Serializable {
+	private String name;
+	private String ssn;
+
+	public String getSsn() {
+		return ssn;
+	}
+	public void setSsn(String id) {
+		this.ssn = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Mapping.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Mapping.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Mapping.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+     
+-->
+
+<hibernate-mapping package="org.hibernate.test.propertyref.component.complete">
+	
+	<class name="Person" table="COMP_COMP_PROPREF_PERSON">
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		<component name="identity" class="Identity">
+			<property name="name"/>
+			<property name="ssn" unique="true"/>
+		</component>
+	</class>
+	
+	<class name="Account" table="COMP_COMP_PROPREF_ACCT">
+		<id name="number" column="accnum"/>
+		<many-to-one name="owner" property-ref="identity">
+            <column name="OWNER_NAME" />
+            <column name="OWNER_SSN" />
+        </many-to-one>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/complete/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+package org.hibernate.test.propertyref.component.complete;
+
+
+public class Person {
+	private Long id;
+	private Identity identity;
+	
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public Identity getIdentity() {
+		return identity;
+	}
+	public void setIdentity(Identity identity) {
+		this.identity = identity;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Account.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Account.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Account.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+//$Id: Account.java 7587 2005-07-21 01:22:38Z oneovthafew $
+package org.hibernate.test.propertyref.component.partial;
+
+public class Account {
+	private String number;
+	private Person owner;
+
+	public Person getOwner() {
+		return owner;
+	}
+
+	public void setOwner(Person owner) {
+		this.owner = owner;
+	}
+
+	public String getNumber() {
+		return number;
+	}
+
+	public void setNumber(String number) {
+		this.number = number;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Identity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Identity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Identity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+//$Id: Identity.java 7587 2005-07-21 01:22:38Z oneovthafew $
+package org.hibernate.test.propertyref.component.partial;
+
+public class Identity {
+	private String name;
+	private String ssn;
+	
+	public String getSsn() {
+		return ssn;
+	}
+	public void setSsn(String id) {
+		this.ssn = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Mapping.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Mapping.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Mapping.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+     
+-->
+
+<hibernate-mapping package="org.hibernate.test.propertyref.component.partial">
+	
+	<class name="Person" table="PART_COMP_PROPREF_PERS">
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		<component name="identity">
+			<property name="name"/>
+			<property name="ssn" unique="true"/>
+		</component>
+	</class>
+	
+	<class name="Account" table="PART_COMP_PROPREF_ACCT">
+		<id name="number" column="accnum"/>
+		<many-to-one name="owner" property-ref="identity.ssn"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/PartialComponentPropertyRefTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/PartialComponentPropertyRefTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/PartialComponentPropertyRefTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,73 @@
+//$Id: PartialComponentPropertyRefTest.java 9914 2006-05-09 09:37:18Z max.andersen at jboss.com $
+package org.hibernate.test.propertyref.component.partial;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class PartialComponentPropertyRefTest extends FunctionalTestCase {
+	
+	public PartialComponentPropertyRefTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "propertyref/component/partial/Mapping.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( PartialComponentPropertyRefTest.class );
+	}
+	
+	public void testComponentPropertyRef() {
+		Person p = new Person();
+		p.setIdentity( new Identity() );
+		Account a = new Account();
+		a.setNumber("123-12345-1236");
+		a.setOwner(p);
+		p.getIdentity().setName("Gavin");
+		p.getIdentity().setSsn("123-12-1234");
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		s.persist(p);
+		s.persist(a);
+		s.flush();
+		s.clear();
+		
+		a = (Account) s.createQuery("from Account a left join fetch a.owner").uniqueResult();
+		assertTrue( Hibernate.isInitialized( a.getOwner() ) );
+		assertNotNull( a.getOwner() );
+		assertEquals( "Gavin", a.getOwner().getIdentity().getName() );
+		s.clear();
+		
+		a = (Account) s.get(Account.class, "123-12345-1236");
+		assertFalse( Hibernate.isInitialized( a.getOwner() ) );
+		assertNotNull( a.getOwner() );
+		assertEquals( "Gavin", a.getOwner().getIdentity().getName() );
+		assertTrue( Hibernate.isInitialized( a.getOwner() ) );
+		
+		s.clear();
+		
+		getSessions().evict(Account.class);
+		getSessions().evict(Person.class);
+		
+		a = (Account) s.get(Account.class, "123-12345-1236");
+		assertTrue( Hibernate.isInitialized( a.getOwner() ) );
+		assertNotNull( a.getOwner() );
+		assertEquals( "Gavin", a.getOwner().getIdentity().getName() );
+		assertTrue( Hibernate.isInitialized( a.getOwner() ) );
+		
+		s.delete( a );
+		s.delete( a.getOwner() );
+		tx.commit();
+		s.close();
+	}
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/component/partial/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+//$Id: Person.java 7587 2005-07-21 01:22:38Z oneovthafew $
+package org.hibernate.test.propertyref.component.partial;
+
+public class Person {
+	private Long id;
+	private Identity identity;
+	
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public Identity getIdentity() {
+		return identity;
+	}
+	public void setIdentity(Identity identity) {
+		this.identity = identity;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Account.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Account.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Account.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+//$Id: Account.java 6029 2005-03-06 16:34:16Z oneovthafew $
+package org.hibernate.test.propertyref.inheritence.discrim;
+
+/**
+ * @author Gavin King
+ */
+public class Account {
+	private String accountId;
+	private Customer customer;
+	private Person person;
+	private char type;
+	/**
+	 * @return Returns the user.
+	 */
+	public Customer getCustomer() {
+		return customer;
+	}
+	/**
+	 * @param user The user to set.
+	 */
+	public void setCustomer(Customer user) {
+		this.customer = user;
+	}
+	/**
+	 * @return Returns the accountId.
+	 */
+	public String getAccountId() {
+		return accountId;
+	}
+	/**
+	 * @param accountId The accountId to set.
+	 */
+	public void setAccountId(String accountId) {
+		this.accountId = accountId;
+	}
+	/**
+	 * @return Returns the type.
+	 */
+	public char getType() {
+		return type;
+	}
+	/**
+	 * @param type The type to set.
+	 */
+	public void setType(char type) {
+		this.type = type;
+	}
+	public Person getPerson() {
+		return person;
+	}
+	
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+	
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+//$Id: Customer.java 6029 2005-03-06 16:34:16Z oneovthafew $
+package org.hibernate.test.propertyref.inheritence.discrim;
+
+/**
+ * @author Gavin King
+ */
+public class Customer extends Person {
+	private String customerId;
+
+	public String getCustomerId() {
+		return customerId;
+	}
+	
+	public void setCustomerId(String customerId) {
+		this.customerId = customerId;
+	}
+	
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.propertyref.inheritence.discrim">
+
+	<class name="Person" discriminator-value="null" table="D_SBCLS_PROPREF_PERS">
+		<id name="id">
+			<generator class="hilo"/>
+		</id>
+		<discriminator formula="customerId"/>
+		<property name="name" length="100"/>
+		<property name="personId" length="8" unique="true"/>
+				
+		<subclass name="Customer" discriminator-value="not null">
+			<property name="customerId" length="8" unique="true"/>
+		</subclass>
+	</class>
+	
+	<class name="Account" table="D_SBCLS_PROPREF_ACCT">
+		<id name="accountId" length="32">
+			<generator class="uuid.hex"/>
+		</id>
+		<many-to-one name="person" column="personId" unique="true" property-ref="personId"/>
+		<many-to-one name="customer" column="customerPersonId" unique="true" property-ref="personId"/>
+		<property name="type" not-null="true"/>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+//$Id: Person.java 6029 2005-03-06 16:34:16Z oneovthafew $
+package org.hibernate.test.propertyref.inheritence.discrim;
+
+
+/**
+ * @author gavin
+ */
+public class Person {
+	private Long id;
+	private String name;
+	private String personId;
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getPersonId() {
+		return personId;
+	}
+	
+	public void setPersonId(String personId) {
+		this.personId = personId;
+	}
+	
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/SubclassPropertyRefTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/SubclassPropertyRefTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/discrim/SubclassPropertyRefTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+//$Id: SubclassPropertyRefTest.java 6029 2005-03-06 16:34:16Z oneovthafew $
+package org.hibernate.test.propertyref.inheritence.discrim;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class SubclassPropertyRefTest extends FunctionalTestCase {
+
+	public SubclassPropertyRefTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "propertyref/inheritence/discrim/Person.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SubclassPropertyRefTest.class );
+	}
+
+	public void testOneToOnePropertyRef() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Customer c = new Customer();
+		c.setName( "Emmanuel" );
+		c.setCustomerId( "C123-456" );
+		c.setPersonId( "P123-456" );
+		Account a = new Account();
+		a.setCustomer( c );
+		a.setPerson( c );
+		a.setType( 'X' );
+		s.persist( c );
+		s.persist( a );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		a = ( Account ) s.createQuery( "from Account acc join fetch acc.customer join fetch acc.person" )
+				.uniqueResult();
+		assertNotNull( a.getCustomer() );
+		assertTrue( Hibernate.isInitialized( a.getCustomer() ) );
+		assertNotNull( a.getPerson() );
+		assertTrue( Hibernate.isInitialized( a.getPerson() ) );
+		c = ( Customer ) s.createQuery( "from Customer" ).uniqueResult();
+		assertSame( c, a.getCustomer() );
+		assertSame( c, a.getPerson() );
+		s.delete( a );
+		s.delete( a.getCustomer() );
+		s.delete( a.getPerson() );
+		t.commit();
+		s.close();
+	}
+
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/Account.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/Account.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/Account.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: Account.java 7274 2005-06-22 17:07:29Z oneovthafew $
+package org.hibernate.test.propertyref.inheritence.joined;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Account implements Serializable {
+	private String accountId;
+	private char type;
+
+	/**
+	 * @return Returns the accountId.
+	 */
+	public String getAccountId() {
+		return accountId;
+	}
+	/**
+	 * @param accountId The accountId to set.
+	 */
+	public void setAccountId(String accountId) {
+		this.accountId = accountId;
+	}
+	/**
+	 * @return Returns the type.
+	 */
+	public char getType() {
+		return type;
+	}
+	/**
+	 * @param type The type to set.
+	 */
+	public void setType(char type) {
+		this.type = type;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/BankAccount.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/BankAccount.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/BankAccount.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+//$Id: BankAccount.java 7274 2005-06-22 17:07:29Z oneovthafew $
+package org.hibernate.test.propertyref.inheritence.joined;
+
+public class BankAccount extends Account {
+	private String accountNumber;
+	private String bsb;
+
+	public String getAccountNumber() {
+		return accountNumber;
+	}
+
+	public void setAccountNumber(String accountNumber) {
+		this.accountNumber = accountNumber;
+	}
+
+	public String getBsb() {
+		return bsb;
+	}
+
+	public void setBsb(String bsb) {
+		this.bsb = bsb;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/JoinedSubclassPropertyRefTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/JoinedSubclassPropertyRefTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/JoinedSubclassPropertyRefTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,70 @@
+//$Id: PropertyRefTest.java 7275 2005-06-22 18:58:16Z oneovthafew $
+package org.hibernate.test.propertyref.inheritence.joined;
+
+import junit.framework.Test;
+
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class JoinedSubclassPropertyRefTest extends FunctionalTestCase {
+	
+	public JoinedSubclassPropertyRefTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "propertyref/inheritence/joined/Person.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( JoinedSubclassPropertyRefTest.class );
+	}
+	
+	public void testPropertyRefToJoinedSubclass() {
+		Session session = openSession();
+		Transaction tx = session.beginTransaction();
+		Person p = new Person();
+		p.setName("Gavin King");
+		BankAccount acc = new BankAccount();
+		acc.setBsb("0634");
+		acc.setType('B');
+		acc.setAccountNumber("xxx-123-abc");
+		p.setBankAccount(acc);
+		session.persist(p);
+		tx.commit();
+		session.close();
+
+		session = openSession();
+		tx = session.beginTransaction();
+		p = (Person) session.get(Person.class, p.getId());
+		assertNotNull( p.getBankAccount() );
+		assertTrue( Hibernate.isInitialized( p.getBankAccount() ) );
+		tx.commit();
+		session.close();
+
+		session = openSession();
+		tx = session.beginTransaction();
+		p = (Person) session.createCriteria(Person.class)
+			.setFetchMode("bankAccount", FetchMode.JOIN)
+			.uniqueResult();
+		assertNotNull( p.getBankAccount() );
+		assertTrue( Hibernate.isInitialized( p.getBankAccount() ) );
+		tx.commit();
+		session.close();
+
+		session = openSession();
+		tx = session.beginTransaction();
+		session.delete(p);
+		tx.commit();
+		session.close();
+	}
+
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+  Demonstrates the use of property-ref to map legacy data where
+  foreign keys reference something other than the primary key of
+  the associated entity. Here we show:
+  
+  (1) A one-to-one foreign key association (prefer primary key 
+      associations)
+      
+  (2) A bidirectional one-to-many association on a key that is
+      not the primary key (prefer associations from foreign keys
+      to primary keys)
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.propertyref.inheritence.joined">
+
+	<class name="Person" table="J_SBCLS_PROPREF_PERS">
+		<id name="id">
+			<generator class="hilo"/>
+		</id>
+		<property name="name" length="100"/>
+		<many-to-one name="bankAccount" property-ref="bsbAccountNumber" cascade="all">
+			<column name="bsb"/>
+			<column name="accountNumber"/>
+		</many-to-one>
+	</class>
+	
+	<class name="Account" table="J_SBCLS_PROPREF_ACCT">
+		<id name="accountId" length="32">
+			<generator class="uuid"/>
+		</id>
+		<property name="type" not-null="true"/>
+		<joined-subclass name="BankAccount" table="J_SBCLS_PROPREF_BACCT">
+			<key column="accountId"/>
+			<properties unique="true" name="bsbAccountNumber">
+				<property name="bsb" length="4" not-null="true"/>
+				<property name="accountNumber" length="16" not-null="true"/>
+			</properties>
+		</joined-subclass>
+		
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/joined/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+//$Id: Person.java 7274 2005-06-22 17:07:29Z oneovthafew $
+package org.hibernate.test.propertyref.inheritence.joined;
+
+
+/**
+ * @author gavin
+ */
+public class Person {
+	private Long id;
+	private String name;
+	private BankAccount bankAccount;
+
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public BankAccount getBankAccount() {
+		return bankAccount;
+	}
+	public void setBankAccount(BankAccount bankAccount) {
+		this.bankAccount = bankAccount;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Account.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Account.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Account.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,56 @@
+package org.hibernate.test.propertyref.inheritence.union;
+
+/**
+ * @author Gavin King
+ */
+public class Account {
+	private String accountId;
+	private Customer customer;
+	private Person person;
+	private char type;
+	/**
+	 * @return Returns the user.
+	 */
+	public Customer getCustomer() {
+		return customer;
+	}
+	/**
+	 * @param user The user to set.
+	 */
+	public void setCustomer(Customer user) {
+		this.customer = user;
+	}
+	/**
+	 * @return Returns the accountId.
+	 */
+	public String getAccountId() {
+		return accountId;
+	}
+	/**
+	 * @param accountId The accountId to set.
+	 */
+	public void setAccountId(String accountId) {
+		this.accountId = accountId;
+	}
+	/**
+	 * @return Returns the type.
+	 */
+	public char getType() {
+		return type;
+	}
+	/**
+	 * @param type The type to set.
+	 */
+	public void setType(char type) {
+		this.type = type;
+	}
+	public Person getPerson() {
+		return person;
+	}
+
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+package org.hibernate.test.propertyref.inheritence.union;
+
+/**
+ * @author Gavin King
+ */
+public class Customer extends Person {
+	private String customerId;
+
+	public String getCustomerId() {
+		return customerId;
+	}
+
+	public void setCustomerId(String customerId) {
+		this.customerId = customerId;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.propertyref.inheritence.union">
+
+	<class name="Person" table="U_SBCLS_PROPREF_PERS">
+		<id name="id">
+			<generator class="hilo"/>
+		</id>
+		<property name="name" length="100"/>
+		<property name="personId" length="8" unique="true"/>
+				
+		<union-subclass name="Customer" table="U_SBCLS_PROPREF_CUST">
+            <property name="customerId" length="8" unique="true"/>
+		</union-subclass>
+	</class>
+	
+	<class name="Account" table="U_SBCLS_PROPREF_ACCT">
+		<id name="accountId" length="32">
+			<generator class="uuid.hex"/>
+		</id>
+		<many-to-one name="person" column="personId" unique="true" property-ref="personId"/>
+		<many-to-one name="customer" column="customerPersonId" unique="true" property-ref="personId"/>
+		<property name="type" not-null="true"/>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+package org.hibernate.test.propertyref.inheritence.union;
+
+/**
+ * @author gavin
+ */
+public class Person {
+	private Long id;
+	private String name;
+	private String personId;
+	/**
+	 * @return Returns the id.
+	 */
+	public Long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(Long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getPersonId() {
+		return personId;
+	}
+
+	public void setPersonId(String personId) {
+		this.personId = personId;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/UnionSubclassPropertyRefTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/UnionSubclassPropertyRefTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/propertyref/inheritence/union/UnionSubclassPropertyRefTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+package org.hibernate.test.propertyref.inheritence.union;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class UnionSubclassPropertyRefTest extends FunctionalTestCase {
+
+	public UnionSubclassPropertyRefTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "propertyref/inheritence/union/Person.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( UnionSubclassPropertyRefTest.class );
+	}
+
+	public void testOneToOnePropertyRef() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Customer c = new Customer();
+		c.setName( "Emmanuel" );
+		c.setCustomerId( "C123-456" );
+		c.setPersonId( "P123-456" );
+		Account a = new Account();
+		a.setCustomer( c );
+		a.setPerson( c );
+		a.setType( 'X' );
+		s.persist( c );
+		s.persist( a );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		a = ( Account ) s.createQuery( "from Account acc join fetch acc.customer join fetch acc.person" )
+				.uniqueResult();
+		assertNotNull( a.getCustomer() );
+		assertTrue( Hibernate.isInitialized( a.getCustomer() ) );
+		assertNotNull( a.getPerson() );
+		assertTrue( Hibernate.isInitialized( a.getPerson() ) );
+		c = ( Customer ) s.createQuery( "from Customer" ).uniqueResult();
+		assertSame( c, a.getCustomer() );
+		assertSame( c, a.getPerson() );
+		s.delete( a );
+		s.delete( a.getCustomer() );
+		s.delete( a.getPerson() );
+		t.commit();
+		s.close();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/Container.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/Container.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/Container.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+package org.hibernate.test.proxy;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.io.Serializable;
+
+/**
+ * @author Steve Ebersole
+ */
+public class Container implements Serializable {
+	private Long id;
+	private String name;
+	private Owner owner;
+	private Info info;
+	private Set dataPoints = new HashSet();
+
+	public Container() {
+	}
+
+	public Container(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Owner getOwner() {
+		return owner;
+	}
+
+	public void setOwner(Owner owner) {
+		this.owner = owner;
+	}
+
+	public Info getInfo() {
+		return info;
+	}
+
+	public void setInfo(Info info) {
+		this.info = info;
+	}
+
+	public Set getDataPoints() {
+		return dataPoints;
+	}
+
+	public void setDataPoints(Set dataPoints) {
+		this.dataPoints = dataPoints;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/DataPoint.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/DataPoint.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/DataPoint.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.proxy">
+
+	<class name="DataPoint">
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		<property name="x">
+			<column name="xval" not-null="true" length="4" unique-key="xy"/>
+		</property>
+		<property name="y">
+			<column name="yval" not-null="true" length="4" unique-key="xy"/>
+		</property>
+		<property name="description"/>
+	</class>
+
+    <class name="Owner">
+        <id name="id">
+            <generator class="increment"/>
+        </id>
+        <property name="name" unique="true"/>
+    </class>
+
+    <class name="Info">
+        <id name="id">
+            <generator class="increment"/>
+        </id>
+        <property name="details"/>
+    </class>
+
+    <class name="Container">
+        <id name="id">
+            <generator class="increment"/>
+        </id>
+        <property name="name"/>
+        <many-to-one name="owner" class="Owner" column="owner_name" property-ref="name" cascade="all"/>
+        <many-to-one name="info" class="Info" column="info_id" cascade="all"/>
+        <set name="dataPoints" lazy="true" inverse="false" cascade="all">
+            <key column="c_id"/>
+            <one-to-many class="DataPoint"/>
+        </set>
+    </class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/DataPoint.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/DataPoint.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/DataPoint.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/DataPoint.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,77 @@
+//$Id: DataPoint.java 10223 2006-08-04 20:29:21Z steve.ebersole at jboss.com $
+package org.hibernate.test.proxy;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * @author Gavin King
+ */
+public class DataPoint implements Serializable {
+	private long id;
+	private BigDecimal x;
+	private BigDecimal y;
+	private String description;
+
+	public DataPoint() {
+	}
+
+	public DataPoint(BigDecimal x, BigDecimal y, String description) {
+		this.x = x;
+		this.y = y;
+		this.description = description;
+	}
+
+	/**
+	 * @return Returns the description.
+	 */
+	public String getDescription() {
+		return description;
+	}
+	/**
+	 * @param description The description to set.
+	 */
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the x.
+	 */
+	public BigDecimal getX() {
+		return x;
+	}
+	/**
+	 * @param x The x to set.
+	 */
+	public void setX(BigDecimal x) {
+		this.x = x;
+	}
+	/**
+	 * @return Returns the y.
+	 */
+	public BigDecimal getY() {
+		return y;
+	}
+	/**
+	 * @param y The y to set.
+	 */
+	public void setY(BigDecimal y) {
+		this.y = y;
+	}
+	
+	void exception() throws Exception {
+		throw new Exception("foo");
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/DataPoint.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/Info.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/Info.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/Info.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+package org.hibernate.test.proxy;
+
+/**
+ * todo: describe Info
+ *
+ * @author Steve Ebersole
+ */
+public class Info {
+	private Long id;
+	private String details;
+
+	public Info() {
+	}
+
+	public Info(String details) {
+		this.details = details;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getDetails() {
+		return details;
+	}
+
+	public void setDetails(String details) {
+		this.details = details;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/Owner.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/Owner.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/Owner.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+package org.hibernate.test.proxy;
+
+import java.io.Serializable;
+
+/**
+ * @author Steve Ebersole
+ */
+public class Owner implements Serializable {
+	private Long id;
+	private String name;
+
+	public Owner() {
+	}
+
+	public Owner(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/ProxyTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/ProxyTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/ProxyTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,378 @@
+//$Id: ProxyTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.proxy;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.FlushMode;
+import org.hibernate.Hibernate;
+import org.hibernate.LazyInitializationException;
+import org.hibernate.LockMode;
+import org.hibernate.ObjectNotFoundException;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.impl.SessionImpl;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.util.SerializationHelper;
+
+/**
+ * @author Gavin King
+ */
+public class ProxyTest extends FunctionalTestCase {
+	
+	public ProxyTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "proxy/DataPoint.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "0" ); // problem on HSQLDB (go figure)
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ProxyTest.class );
+	}
+
+	public void testFinalizeFiltered() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		DataPoint dp = new DataPoint();
+		dp.setDescription("a data point");
+		dp.setX( new BigDecimal(1.0) );
+		dp.setY( new BigDecimal(2.0) );
+		s.persist(dp);
+		s.flush();
+		s.clear();
+		
+		dp = (DataPoint) s.load(DataPoint.class, new Long( dp.getId() ) );
+		assertFalse( Hibernate.isInitialized(dp) );
+		
+		try {
+			dp.getClass().getDeclaredMethod("finalize",null);
+			fail();
+			
+		} 
+		catch (NoSuchMethodException e) {}
+		
+		s.delete(dp);
+		t.commit();
+		s.close();
+		
+	}
+	
+	public void testProxyException() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		DataPoint dp = new DataPoint();
+		dp.setDescription("a data point");
+		dp.setX( new BigDecimal(1.0) );
+		dp.setY( new BigDecimal(2.0) );
+		s.persist(dp);
+		s.flush();
+		s.clear();
+		
+		dp = (DataPoint) s.load(DataPoint.class, new Long( dp.getId() ) );
+		assertFalse( Hibernate.isInitialized(dp) );
+		
+		try {
+			dp.exception();
+			fail();
+		}
+		catch (Exception e) {
+			assertTrue( e.getClass()==Exception.class );
+		}
+		s.delete(dp);
+		t.commit();
+		s.close();
+	}
+
+	public void testProxySerializationAfterSessionClosed() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		DataPoint dp = new DataPoint();
+		dp.setDescription("a data point");
+		dp.setX( new BigDecimal(1.0) );
+		dp.setY( new BigDecimal(2.0) );
+		s.persist(dp);
+		s.flush();
+		s.clear();
+
+		dp = (DataPoint) s.load( DataPoint.class, new Long( dp.getId() ) );
+		assertFalse( Hibernate.isInitialized(dp) );
+		s.close();
+		SerializationHelper.clone( dp );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( dp );
+		t.commit();
+		s.close();
+	}
+
+	public void testProxySerialization() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		DataPoint dp = new DataPoint();
+		dp.setDescription("a data point");
+		dp.setX( new BigDecimal(1.0) );
+		dp.setY( new BigDecimal(2.0) );
+		s.persist(dp);
+		s.flush();
+		s.clear();
+
+		dp = (DataPoint) s.load( DataPoint.class, new Long( dp.getId() ) );
+		assertFalse( Hibernate.isInitialized(dp) );
+		dp.getId();
+		assertFalse( Hibernate.isInitialized(dp) );
+		dp.getDescription();
+		assertTrue( Hibernate.isInitialized(dp) );
+		Object none = s.load( DataPoint.class, new Long(666));
+		assertFalse( Hibernate.isInitialized(none) );
+		
+		t.commit();
+		s.disconnect();
+		
+		Object[] holder = new Object[] { s, dp, none };
+		
+		holder = (Object[]) SerializationHelper.clone(holder);
+		Session sclone = (Session) holder[0];
+		dp = (DataPoint) holder[1];
+		none = holder[2];
+		
+		//close the original:
+		s.close();
+		
+		sclone.reconnect();
+		t = sclone.beginTransaction();
+		
+		DataPoint sdp = (DataPoint) sclone.load( DataPoint.class, new Long( dp.getId() ) );
+		assertSame(dp, sdp);
+		assertFalse(sdp instanceof HibernateProxy);
+		Object snone = sclone.load( DataPoint.class, new Long(666) );
+		assertSame(none, snone);
+		assertTrue(snone instanceof HibernateProxy);
+		
+		sclone.delete(dp);
+		
+		t.commit();
+		sclone.close();
+		
+	}
+
+	public void testProxy() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		DataPoint dp = new DataPoint();
+		dp.setDescription("a data point");
+		dp.setX( new BigDecimal(1.0) );
+		dp.setY( new BigDecimal(2.0) );
+		s.persist(dp);
+		s.flush();
+		s.clear();
+
+		dp = (DataPoint) s.load( DataPoint.class, new Long(dp.getId() ));
+		assertFalse( Hibernate.isInitialized(dp) );
+		DataPoint dp2 = (DataPoint) s.get( DataPoint.class, new Long(dp.getId()) );
+		assertSame(dp, dp2);
+		assertTrue( Hibernate.isInitialized(dp) );
+		s.clear();
+
+		dp = (DataPoint) s.load( DataPoint.class, new Long( dp.getId() ) );
+		assertFalse( Hibernate.isInitialized(dp) );
+		dp2 = (DataPoint) s.load( DataPoint.class, new Long( dp.getId() ), LockMode.NONE );
+		assertSame(dp, dp2);
+		assertFalse( Hibernate.isInitialized(dp) );
+		s.clear();
+
+		dp = (DataPoint) s.load( DataPoint.class, new Long( dp.getId() ) );
+		assertFalse( Hibernate.isInitialized(dp) );
+		dp2 = (DataPoint) s.load( DataPoint.class, new Long( dp.getId() ), LockMode.READ );
+		assertSame(dp, dp2);
+		assertTrue( Hibernate.isInitialized(dp) );
+		s.clear();
+
+		dp = (DataPoint) s.load( DataPoint.class, new Long (dp.getId() ));
+		assertFalse( Hibernate.isInitialized(dp) );
+		dp2 = (DataPoint) s.get( DataPoint.class, new Long ( dp.getId() ) , LockMode.READ );
+		assertSame(dp, dp2);
+		assertTrue( Hibernate.isInitialized(dp) );
+		s.clear();
+
+		dp = (DataPoint) s.load( DataPoint.class, new Long  ( dp.getId() ) );
+		assertFalse( Hibernate.isInitialized(dp) );
+		dp2 = (DataPoint) s.createQuery("from DataPoint").uniqueResult();
+		assertSame(dp, dp2);
+		assertTrue( Hibernate.isInitialized(dp) );
+		s.delete( dp );
+		t.commit();
+		s.close();
+	}
+
+	public void testSubsequentNonExistentProxyAccess() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		DataPoint proxy = ( DataPoint ) s.load( DataPoint.class, new Long(-1) );
+		assertFalse( Hibernate.isInitialized( proxy ) );
+		try {
+			proxy.getDescription();
+			fail( "proxy access did not fail on non-existent proxy" );
+		}
+		catch( ObjectNotFoundException onfe ) {
+			// expected
+		}
+		catch( Throwable e ) {
+			fail( "unexpected exception type on non-existent proxy access : " + e );
+		}
+		// try it a second (subsequent) time...
+		try {
+			proxy.getDescription();
+			fail( "proxy access did not fail on non-existent proxy" );
+		}
+		catch( ObjectNotFoundException onfe ) {
+			// expected
+		}
+		catch( Throwable e ) {
+			fail( "unexpected exception type on non-existent proxy access : " + e );
+		}
+
+		t.commit();
+		s.close();
+	}
+
+	public void testProxyEviction() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Container container = new Container( "container" );
+		container.setOwner( new Owner( "owner" ) );
+		container.setInfo( new Info( "blah blah blah" ) );
+		container.getDataPoints().add( new DataPoint( new BigDecimal( 1 ), new BigDecimal( 1 ), "first data point" ) );
+		container.getDataPoints().add( new DataPoint( new BigDecimal( 2 ), new BigDecimal( 2 ), "second data point" ) );
+		s.save( container );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Container c = ( Container ) s.load( Container.class, container.getId() );
+		assertFalse( Hibernate.isInitialized( c ) );
+		s.evict( c );
+		try {
+			c.getName();
+			fail( "expecting LazyInitializationException" );
+		}
+		catch( LazyInitializationException e ) {
+			// expected result
+		}
+
+		c = ( Container ) s.load( Container.class, container.getId() );
+		assertFalse( Hibernate.isInitialized( c ) );
+		Info i = c.getInfo();
+		assertTrue( Hibernate.isInitialized( c ) );
+		assertFalse( Hibernate.isInitialized( i ) );
+		s.evict( c );
+		try {
+			i.getDetails();
+			fail( "expecting LazyInitializationException" );
+		}
+		catch( LazyInitializationException e ) {
+			// expected result
+		}
+
+		s.delete( c );
+
+		t.commit();
+		s.close();
+	}
+
+	public void testFullyLoadedPCSerialization() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Long lastContainerId = null;
+		int containerCount = 10;
+		int nestedDataPointCount = 5;
+		for ( int c_indx = 0; c_indx < containerCount; c_indx++ ) {
+			Owner owner = new Owner( "Owner #" + c_indx );
+			Container container = new Container( "Container #" + c_indx );
+			container.setOwner( owner );
+			for ( int dp_indx = 0; dp_indx < nestedDataPointCount; dp_indx++ ) {
+				DataPoint dp = new DataPoint();
+				dp.setDescription( "data-point [" + c_indx + ", " + dp_indx + "]" );
+// more HSQLDB fun...
+//				dp.setX( new BigDecimal( c_indx ) );
+				dp.setX( new BigDecimal( c_indx + dp_indx ) );
+				dp.setY( new BigDecimal( dp_indx ) );
+				container.getDataPoints().add( dp );
+			}
+			s.save( container );
+			lastContainerId = container.getId();
+		}
+		t.commit();
+		s.close();
+
+		s = openSession();
+		s.setFlushMode( FlushMode.NEVER );
+		t = s.beginTransaction();
+		// load the last container as a proxy
+		Container proxy = ( Container ) s.load( Container.class, lastContainerId );
+		assertFalse( Hibernate.isInitialized( proxy ) );
+		// load the rest back into the PC
+		List all = s.createQuery( "from Container as c inner join fetch c.owner inner join fetch c.dataPoints where c.id <> :last" )
+				.setLong( "last", lastContainerId.longValue() )
+				.list();
+		Container container = ( Container ) all.get( 0 );
+		s.delete( container );
+		// force a snapshot retrieval of the proxied container
+		SessionImpl sImpl = ( SessionImpl ) s;
+		sImpl.getPersistenceContext().getDatabaseSnapshot(
+				lastContainerId,
+		        sImpl.getFactory().getEntityPersister( Container.class.getName() )
+		);
+		assertFalse( Hibernate.isInitialized( proxy ) );
+		t.commit();
+
+//		int iterations = 50;
+//		long cumulativeTime = 0;
+//		long cumulativeSize = 0;
+//		for ( int i = 0; i < iterations; i++ ) {
+//			final long start = System.currentTimeMillis();
+//			byte[] bytes = SerializationHelper.serialize( s );
+//			SerializationHelper.deserialize( bytes );
+//			final long end = System.currentTimeMillis();
+//			cumulativeTime += ( end - start );
+//			int size = bytes.length;
+//			cumulativeSize += size;
+////			System.out.println( "Iteration #" + i + " took " + ( end - start ) + " ms : size = " + size + " bytes" );
+//		}
+//		System.out.println( "Average time : " + ( cumulativeTime / iterations ) + " ms" );
+//		System.out.println( "Average size : " + ( cumulativeSize / iterations ) + " bytes" );
+
+		byte[] bytes = SerializationHelper.serialize( s );
+		SerializationHelper.deserialize( bytes );
+
+		t = s.beginTransaction();
+		int count = s.createQuery( "delete DataPoint" ).executeUpdate();
+		assertEquals( "unexpected DP delete count", ( containerCount * nestedDataPointCount ), count );
+		count = s.createQuery( "delete Container" ).executeUpdate();
+		assertEquals( "unexpected container delete count", containerCount, count );
+		count = s.createQuery( "delete Owner" ).executeUpdate();
+		assertEquals( "unexpected owner delete count", containerCount, count );
+		t.commit();
+		s.close();
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/proxy/ProxyTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/Item.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/Item.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/Item.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.querycache">
+
+	<class name="Item" table="Items" batch-size="9">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="name" not-null="true"/>
+		<property name="description" not-null="true"/>
+    </class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/Item.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/Item.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/Item.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/Item.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+//$Id: Item.java 9587 2006-03-09 21:38:26Z steve.ebersole at jboss.com $
+package org.hibernate.test.querycache;
+
+import java.util.Set;
+import java.util.HashSet;
+
+
+/**
+ * @author Gavin King
+ */
+public class Item {
+	private long id;
+	private String name;
+	private String description;
+
+	public String getDescription() {
+		return description;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/Item.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/QueryCacheTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/QueryCacheTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/QueryCacheTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,277 @@
+//$Id: QueryCacheTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.querycache;
+
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.stat.EntityStatistics;
+import org.hibernate.stat.QueryStatistics;
+import org.hibernate.transform.Transformers;
+
+/**
+ * @author Gavin King
+ */
+public class QueryCacheTest extends FunctionalTestCase {
+	
+	public QueryCacheTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "querycache/Item.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.USE_QUERY_CACHE, "true" );
+		cfg.setProperty( Environment.CACHE_REGION_PREFIX, "foo" );
+		cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( QueryCacheTest.class );
+	}
+	
+	public void testQueryCacheInvalidation() throws Exception {
+		
+		getSessions().evictQueries();
+		getSessions().getStatistics().clear();
+
+		final String queryString = "from Item i where i.name='widget'";
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createQuery( queryString ).setCacheable(true).list();
+		Item i = new Item();
+		i.setName("widget");
+		i.setDescription("A really top-quality, full-featured widget.");
+		s.save(i);
+		t.commit();
+		s.close();
+		
+		QueryStatistics qs = s.getSessionFactory().getStatistics().getQueryStatistics( queryString );
+		EntityStatistics es = s.getSessionFactory().getStatistics().getEntityStatistics( Item.class.getName() );
+
+		Thread.sleep(200);
+
+		s = openSession();
+		t = s.beginTransaction();
+		List result = s.createQuery( queryString ).setCacheable(true).list();
+		assertEquals( result.size(), 1 );
+		t.commit();
+		s.close();
+		
+		assertEquals( qs.getCacheHitCount(), 0 );
+				
+		s = openSession();
+		t = s.beginTransaction();
+		result = s.createQuery( queryString ).setCacheable(true).list();
+		assertEquals( result.size(), 1 );
+		t.commit();
+		s.close();
+		
+		assertEquals( qs.getCacheHitCount(), 1 );
+		assertEquals( s.getSessionFactory().getStatistics().getEntityFetchCount(), 0 );
+		
+		s = openSession();
+		t = s.beginTransaction();
+		result = s.createQuery( queryString ).setCacheable(true).list();
+		assertEquals( result.size(), 1 );
+		assertTrue( Hibernate.isInitialized( result.get(0) ) );
+		i = (Item) result.get(0);
+		i.setName("Widget");
+		t.commit();
+		s.close();
+		
+		assertEquals( qs.getCacheHitCount(), 2 );
+		assertEquals( qs.getCacheMissCount(), 2 );
+		assertEquals( s.getSessionFactory().getStatistics().getEntityFetchCount(), 0 );
+
+		Thread.sleep(200);
+
+		s = openSession();
+		t = s.beginTransaction();
+		result = s.createQuery( queryString ).setCacheable(true).list();
+		if ( dialectIsCaseSensitive("i.name='widget' should not match on case sensitive database.") ) {
+			assertEquals( result.size(), 0 );
+		}
+		i = (Item) s.get( Item.class, new Long(i.getId()) );
+		assertEquals( i.getName(), "Widget" );
+		
+		s.delete(i);
+		t.commit();
+		s.close();
+
+		assertEquals( qs.getCacheHitCount(), 2 );
+		assertEquals( qs.getCacheMissCount(), 3 );
+		assertEquals( qs.getCachePutCount(), 3 );
+		assertEquals( qs.getExecutionCount(), 3 );
+		assertEquals( es.getFetchCount(), 0 ); //check that it was being cached
+		
+	}
+
+	public void testQueryCacheFetch() throws Exception {
+		
+		getSessions().evictQueries();
+		getSessions().getStatistics().clear();
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Item i = new Item();
+		i.setName("widget");
+		i.setDescription("A really top-quality, full-featured widget.");
+		Item i2 = new Item();
+		i2.setName("other widget");
+		i2.setDescription("Another decent widget.");
+		s.persist(i);
+		s.persist(i2);
+		t.commit();
+		s.close();
+
+		final String queryString = "from Item i where i.name like '%widget'";
+
+		QueryStatistics qs = s.getSessionFactory().getStatistics().getQueryStatistics( queryString );
+
+		Thread.sleep(200);
+
+		s = openSession();
+		t = s.beginTransaction();
+		List result = s.createQuery( queryString ).setCacheable(true).list();
+		assertEquals( result.size(), 2 );
+		t.commit();
+		s.close();
+		
+		assertEquals( qs.getCacheHitCount(), 0 );
+		assertEquals( s.getSessionFactory().getStatistics().getEntityFetchCount(), 0 );
+		
+		getSessions().evict(Item.class);
+				
+		s = openSession();
+		t = s.beginTransaction();
+		result = s.createQuery( queryString ).setCacheable(true).list();
+		assertEquals( result.size(), 2 );
+		assertTrue( Hibernate.isInitialized( result.get(0) ) );
+		assertTrue( Hibernate.isInitialized( result.get(1) ) );
+		t.commit();
+		s.close();
+		
+		assertEquals( qs.getCacheHitCount(), 1 );
+		assertEquals( s.getSessionFactory().getStatistics().getEntityFetchCount(), 1 );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery("delete Item").executeUpdate();
+		t.commit();
+		s.close();
+		
+	}
+
+	public void testProjectionCache() throws Exception {
+
+		getSessions().evictQueries();
+        getSessions().getStatistics().clear();
+
+		final String queryString = "select i.description from Item i where i.name='widget'";
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createQuery( queryString ).setCacheable(true).list();
+		Item i = new Item();
+		i.setName("widget");
+		i.setDescription("A really top-quality, full-featured widget.");
+		s.save(i);
+		t.commit();
+		s.close();
+
+        QueryStatistics qs = s.getSessionFactory().getStatistics().getQueryStatistics( queryString );
+		EntityStatistics es = s.getSessionFactory().getStatistics().getEntityStatistics( Item.class.getName() );
+
+		Thread.sleep(200);
+
+		s = openSession();
+		t = s.beginTransaction();
+		List result = s.createQuery( queryString ).setCacheable(true).list();
+		assertEquals( result.size(), 1 );
+		t.commit();
+		s.close();
+
+		assertEquals( qs.getCacheHitCount(), 0 );
+
+		s = openSession();
+		t = s.beginTransaction();
+		result = s.createQuery( queryString ).setCacheable(true).list();
+		assertEquals( result.size(), 1 );
+		t.commit();
+		s.close();
+
+		assertEquals( qs.getCacheHitCount(), 1 );
+
+		s = openSession();
+		t = s.beginTransaction();
+		result = s.createQuery( queryString ).setCacheable(true).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
+		assertEquals( result.size(), 1 );
+		Map m = (Map) result.get(0);
+		assertEquals(1, m.size());
+		t.commit();
+		s.close();
+
+		assertEquals( "hit count should not go up since we are adding a resulttransformer", qs.getCacheHitCount(), 1 );
+		
+		s = openSession();
+		t = s.beginTransaction();
+		result = s.createQuery( queryString ).setCacheable(true).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
+		assertEquals( result.size(), 1 );
+		m = (Map) result.get(0);
+		assertEquals(1, m.size());
+		t.commit();
+		s.close();
+		
+		assertEquals( "hit count should go up since we are using the same resulttransformer", qs.getCacheHitCount(), 2 );
+		
+		s = openSession();
+		t = s.beginTransaction();
+		result = s.createQuery( queryString ).setCacheable(true).list();
+		assertEquals( result.size(), 1 );
+		assertTrue( Hibernate.isInitialized( result.get(0) ) );
+		i = (Item) s.get( Item.class, new Long(i.getId()) );
+        i.setName("widget");
+		i.setDescription("A middle-quality widget.");
+		t.commit();
+		s.close();
+
+		assertEquals( qs.getCacheHitCount(), 3 );
+		assertEquals( qs.getCacheMissCount(), 3 );
+
+		Thread.sleep(200);
+
+		s = openSession();
+		t = s.beginTransaction();
+		result = s.createQuery( queryString ).setCacheable(true).list();
+		assertEquals( result.size(), 1 );
+		i = (Item) s.get( Item.class, new Long(i.getId()) );
+		assertEquals( (String) result.get(0), "A middle-quality widget." );
+		
+		s.delete(i);
+		t.commit();
+		s.close();
+
+		assertEquals( qs.getCacheHitCount(), 3 );
+		assertEquals( qs.getCacheMissCount(), 4 );
+		assertEquals( qs.getCachePutCount(), 4 );
+		assertEquals( qs.getExecutionCount(), 4 );
+		assertEquals( es.getFetchCount(), 0 ); //check that it was being cached
+
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/querycache/QueryCacheTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.readonly">
+
+	<class name="DataPoint" 
+		dynamic-update="true">
+		<!--rowid="rowid"--> <!-- remove this if not oracle -->
+		<id name="id">
+			<generator class="increment"/>
+		</id>
+		<property name="x">
+			<column name="xval" not-null="true" precision="25" scale="20" unique-key="xy"/>
+		</property>
+		<property name="y">
+			<column name="yval" not-null="true" precision="25" scale="20" unique-key="xy"/>
+		</property>
+		<property name="description"/>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+//$Id: DataPoint.java 7231 2005-06-19 22:04:00Z oneovthafew $
+package org.hibernate.test.readonly;
+
+import java.math.BigDecimal;
+
+/**
+ * @author Gavin King
+ */
+public class DataPoint {
+	private long id;
+	private BigDecimal x;
+	private BigDecimal y;
+	private String description;
+	/**
+	 * @return Returns the description.
+	 */
+	public String getDescription() {
+		return description;
+	}
+	/**
+	 * @param description The description to set.
+	 */
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the x.
+	 */
+	public BigDecimal getX() {
+		return x;
+	}
+	/**
+	 * @param x The x to set.
+	 */
+	public void setX(BigDecimal x) {
+		this.x = x;
+	}
+	/**
+	 * @return Returns the y.
+	 */
+	public BigDecimal getY() {
+		return y;
+	}
+	/**
+	 * @param y The y to set.
+	 */
+	public void setY(BigDecimal y) {
+		this.y = y;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/DataPoint.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,121 @@
+//$Id: ReadOnlyTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.readonly;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.CacheMode;
+import org.hibernate.Hibernate;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * 
+ * @author Gavin King
+ */
+public class ReadOnlyTest extends FunctionalTestCase {
+	
+	public ReadOnlyTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "readonly/DataPoint.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.STATEMENT_BATCH_SIZE, "20");
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ReadOnlyTest.class );
+	}
+
+	public void testReadOnlyOnProxiesFailureExpected() {
+		Session s = openSession();
+		s.setCacheMode( CacheMode.IGNORE );
+		s.beginTransaction();
+		DataPoint dp = new DataPoint();
+		dp.setX( new BigDecimal( 0.1d ).setScale(19, BigDecimal.ROUND_DOWN) );
+		dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
+		dp.setDescription( "original" );
+		s.save( dp );
+		long dpId = dp.getId();
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.setCacheMode(CacheMode.IGNORE);
+		dp = ( DataPoint ) s.load( DataPoint.class, new Long( dpId ) );
+		assertFalse( "was initialized", Hibernate.isInitialized( dp ) );
+		s.setReadOnly( dp, true );
+		assertFalse( "was initialized during setReadOnly", Hibernate.isInitialized( dp ) );
+		dp.setDescription( "changed" );
+		assertTrue( "was not initialized during mod", Hibernate.isInitialized( dp ) );
+		assertEquals( "desc not changed in memory", "changed", dp.getDescription() );
+		s.flush();
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		List list = s.createQuery( "from DataPoint where description = 'changed'" ).list();
+		assertEquals( "change written to database", 0, list.size() );
+		s.createQuery("delete from DataPoint").executeUpdate();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testReadOnlyMode() {
+		
+		Session s = openSession();
+		s.setCacheMode(CacheMode.IGNORE);
+		Transaction t = s.beginTransaction();		
+		for ( int i=0; i<100; i++ ) {
+			DataPoint dp = new DataPoint();
+			dp.setX( new BigDecimal(i * 0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
+			dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
+			s.save(dp);
+		}
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		s.setCacheMode(CacheMode.IGNORE);
+		t = s.beginTransaction();
+		int i = 0;
+		ScrollableResults sr = s.createQuery("from DataPoint dp order by dp.x asc")
+				.setReadOnly(true)
+				.scroll(ScrollMode.FORWARD_ONLY);
+		while ( sr.next() ) {
+			DataPoint dp = (DataPoint) sr.get(0);
+			if (++i==50) {
+				s.setReadOnly(dp, false);
+			}
+			dp.setDescription("done!");
+		}
+		t.commit();
+		s.clear();
+		t = s.beginTransaction();
+		List single = s.createQuery("from DataPoint where description='done!'").list();
+		assertEquals( single.size(), 1 );
+		s.createQuery("delete from DataPoint").executeUpdate();
+		t.commit();
+		s.close();
+		
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/readonly/ReadOnlyTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/Child.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/Child.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/Child.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+package org.hibernate.test.reattachment;
+
+/**
+ * Child entity
+ *
+ * @author Steve Ebersole
+ */
+public class Child {
+	private String name;
+	private Parent parent;
+
+	public Child() {
+	}
+
+	public Child(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Parent getParent() {
+		return parent;
+	}
+
+	public void setParent(Parent parent) {
+		this.parent = parent;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/CollectionReattachmentTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/CollectionReattachmentTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/CollectionReattachmentTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+package org.hibernate.test.reattachment;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.Session;
+
+/**
+ * Test of collection reattachment semantics
+ *
+ * @author Steve Ebersole
+ */
+public class CollectionReattachmentTest extends FunctionalTestCase {
+	public CollectionReattachmentTest(String string) {
+		super( string );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CollectionReattachmentTest.class );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "reattachment/Mappings.hbm.xml" };
+	}
+
+	public void testUpdateOwnerAfterClear() {
+		Session s = openSession();
+		s.beginTransaction();
+		Parent p = new Parent( "p" );
+		p.getChildren().add( new Child( "c" ) );
+		s.save( p );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		p = ( Parent ) s.get( Parent.class, "p" );
+		// clear...
+		s.clear();
+		// now try to reattach...
+		s.update( p );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( p );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testUpdateOwnerAfterEvict() {
+		Session s = openSession();
+		s.beginTransaction();
+		Parent p = new Parent( "p" );
+		p.getChildren().add( new Child( "c" ) );
+		s.save( p );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		p = ( Parent ) s.get( Parent.class, "p" );
+		// evict...
+		s.evict( p );
+		// now try to reattach...
+		s.update( p );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( p );
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+
+<hibernate-mapping package="org.hibernate.test.reattachment">
+
+    <class name="Parent">
+		<id name="name" column="NAME" type="string" />
+        <set name="children" inverse="true" cascade="all">
+            <key column="PARENT" />
+            <one-to-many class="Child" />
+        </set>
+	</class>
+
+    <class name="Child">
+        <id name="name" column="NAME" type="string"/>
+        <many-to-one name="parent" class="Parent" cascade="none" />
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/Parent.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/Parent.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/Parent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+package org.hibernate.test.reattachment;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * Parent entity
+ *
+ * @author Steve Ebersole
+ */
+public class Parent {
+	private String name;
+	private Set children = new HashSet();
+
+	public Parent() {
+	}
+
+	public Parent(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Set getChildren() {
+		return children;
+	}
+
+	public void setChildren(Set children) {
+		this.children = children;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/ProxyReattachmentTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/ProxyReattachmentTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/ProxyReattachmentTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,76 @@
+package org.hibernate.test.reattachment;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.Session;
+
+/**
+ * Test of proxy reattachment semantics
+ *
+ * @author Steve Ebersole
+ */
+public class ProxyReattachmentTest extends FunctionalTestCase {
+	public ProxyReattachmentTest(String string) {
+		super( string );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ProxyReattachmentTest.class );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "reattachment/Mappings.hbm.xml" };
+	}
+
+	public void testUpdateAfterEvict() {
+		Session s = openSession();
+		s.beginTransaction();
+		Parent p = new Parent( "p" );
+		s.save( p );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		p = ( Parent ) s.load( Parent.class, "p" );
+		// evict...
+		s.evict( p );
+		// now try to reattach...
+		s.update( p );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( p );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testUpdateAfterClear() {
+		Session s = openSession();
+		s.beginTransaction();
+		Parent p = new Parent( "p" );
+		s.save( p );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		p = ( Parent ) s.load( Parent.class, "p" );
+		// clear...
+		s.clear();
+		// now try to reattach...
+		s.update( p );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( p );
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/ReattachmentSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/ReattachmentSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/reattachment/ReattachmentSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+package org.hibernate.test.reattachment;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Suite of reattachment specific tests.
+ *
+ * @author Steve Ebersole
+ */
+public class ReattachmentSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "reattachment semantics" );
+		suite.addTest( CollectionReattachmentTest.suite() );
+		suite.addTest( ProxyReattachmentTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/Point.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/Point.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/Point.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+  
+-->
+
+<hibernate-mapping package="org.hibernate.test.rowid">
+
+	<typedef name="rowid" class="org.hibernate.test.rowid.RowIdType"/>
+	
+	<class name="Point" rowid="rowid">
+		<composite-id>
+			<key-property name="x" column="`x`"/>
+			<key-property name="y" column="`y`"/>
+		</composite-id>
+		<property name="description"/>
+		<property name="row" type="rowid" column="rowid" insert="false" update="false"/>
+	</class>
+	
+</hibernate-mapping>
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/Point.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/Point.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/Point.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/Point.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+//$Id: Point.java 6477 2005-04-21 07:39:21Z oneovthafew $
+package org.hibernate.test.rowid;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * @author Gavin King
+ */
+public class Point implements Serializable {
+	private BigDecimal x;
+	private BigDecimal y;
+	private String description;
+	private Object row;
+
+	Point() {}
+	
+	public Point(BigDecimal x, BigDecimal y) {
+		this.x = x;
+		this.y = y;
+	}
+
+	public BigDecimal getX() {
+		return x;
+	}
+
+	void setX(BigDecimal x) {
+		this.x = x;
+	}
+
+	public BigDecimal getY() {
+		return y;
+	}
+
+	void setY(BigDecimal y) {
+		this.y = y;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public Object getRow() {
+		return row;
+	}
+
+	public void setRow(Object row) {
+		this.row = row;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/Point.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/RowIdTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/RowIdTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/RowIdTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,105 @@
+//$Id: RowIdTest.java 11353 2007-03-28 16:03:40Z steve.ebersole at jboss.com $
+package org.hibernate.test.rowid;
+
+import java.math.BigDecimal;
+import java.sql.Statement;
+import java.sql.SQLException;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+
+/**
+ * @author Gavin King
+ */
+public class RowIdTest extends DatabaseSpecificFunctionalTestCase {
+	
+	public RowIdTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "rowid/Point.hbm.xml" };
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( RowIdTest.class );
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		return dialect instanceof Oracle9Dialect;
+	}
+
+	public boolean createSchema() {
+		return false;
+	}
+
+	public void afterSessionFactoryBuilt(SessionFactoryImplementor sfi) {
+		super.afterSessionFactoryBuilt( sfi );
+		Session session = null;
+		try {
+			session = sfi.openSession();
+			Statement st = session.connection().createStatement();
+			try {
+				st.execute( "drop table Point");
+			}
+			catch( Throwable ignore ) {
+				// ignore
+			}
+			st.execute("create table Point (\"x\" number(19,2) not null, \"y\" number(19,2) not null, description varchar2(255) )");
+		}
+		catch ( SQLException e ) {
+			throw new RuntimeException( "Unable to build actual schema : " + e.getMessage() );
+		}
+		finally {
+			if ( session != null ) {
+				try {
+					session.close();
+				}
+				catch( Throwable ignore ) {
+					// ignore
+				}
+			}
+		}
+	}
+
+	public void testRowId() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Point p = new Point( new BigDecimal(1.0), new BigDecimal(1.0) );
+		s.persist(p);
+		t.commit();
+		s.clear();
+		
+		t = s.beginTransaction();
+		p = (Point) s.createCriteria(Point.class).uniqueResult();
+		p.setDescription("new desc");
+		t.commit();
+		s.clear();
+		
+		t = s.beginTransaction();
+		p = (Point) s.createQuery("from Point").uniqueResult();
+		p.setDescription("new new desc");
+		t.commit();
+		s.clear();
+		
+		t = s.beginTransaction();
+		p = (Point) s.get(Point.class, p);
+		p.setDescription("new new new desc");
+		t.commit();
+		s.close();
+		
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/RowIdTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/RowIdType.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/RowIdType.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/RowIdType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,64 @@
+//$Id: RowIdType.java 6477 2005-04-21 07:39:21Z oneovthafew $
+package org.hibernate.test.rowid;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.HibernateException;
+import org.hibernate.usertype.UserType;
+
+/**
+ * @author Gavin King
+ */
+public class RowIdType implements UserType {
+
+	public int[] sqlTypes() {
+		return new int[] { Types.JAVA_OBJECT };
+	}
+
+	public Class returnedClass() {
+		return Object.class;
+	}
+
+	public boolean equals(Object x, Object y) throws HibernateException {
+		return x.equals(y);
+	}
+
+	public int hashCode(Object x) throws HibernateException {
+		return x.hashCode();
+	}
+
+	public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
+			throws HibernateException, SQLException {
+		return rs.getObject( names[0] );
+	}
+
+	public void nullSafeSet(PreparedStatement st, Object value, int index)
+			throws HibernateException, SQLException {
+		throw new UnsupportedOperationException();
+	}
+
+	public Object deepCopy(Object value) throws HibernateException {
+		return value;
+	}
+
+	public boolean isMutable() {
+		return false;
+	}
+
+	public Serializable disassemble(Object value) throws HibernateException {
+		return null;
+	}
+
+	public Object assemble(Serializable cached, Object owner) throws HibernateException {
+		return null;
+	}
+
+	public Object replace(Object original, Object target, Object owner) throws HibernateException {
+		return null;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/rowid/RowIdType.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/1_Version.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/1_Version.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/1_Version.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.schemaupdate">
+
+	<class name="Version">
+		<id name="id">
+			<generator class="org.hibernate.id.TableHiLoGenerator">
+                <param name="table">uid_table</param>
+                <param name="column">next_hi_value_column</param>
+        	</generator>
+		</id>
+		<property name="description"/>	
+	</class>
+	
+</hibernate-mapping>
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/2_Version.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/2_Version.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/2_Version.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.schemaupdate">
+
+	<class name="Version" schema="PUBLIC">
+		<id name="id">
+			<generator class="org.hibernate.id.TableHiLoGenerator">
+                <param name="table">uid_table</param>
+<!--                 <param name="schema">PUBLIC</param>                -->
+                <param name="column">next_hi_value_column</param>
+        	</generator>
+		</id>
+		<property name="description"/>	
+		<property name="name"/>			
+	</class>
+	
+</hibernate-mapping>
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/MigrationTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/MigrationTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/MigrationTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+package org.hibernate.test.schemaupdate;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.junit.UnitTestCase;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+import org.hibernate.tool.hbm2ddl.SchemaUpdate;
+
+/**
+ * @author Max Rydahl Andersen
+ */
+public class MigrationTest extends UnitTestCase {
+
+	public MigrationTest(String str) {
+		super( str );
+	}
+
+	public static Test suite() {
+		return new TestSuite( MigrationTest.class );
+	}
+
+	public void testSimpleColumnAddition() {
+		String resource1 = "org/hibernate/test/schemaupdate/1_Version.hbm.xml";
+		String resource2 = "org/hibernate/test/schemaupdate/2_Version.hbm.xml";
+
+		Configuration v1cfg = new Configuration();
+		v1cfg.addResource( resource1 );
+		new SchemaExport( v1cfg ).execute( false, true, true, false );
+
+		SchemaUpdate v1schemaUpdate = new SchemaUpdate( v1cfg );
+		v1schemaUpdate.execute( true, true );
+
+		assertEquals( 0, v1schemaUpdate.getExceptions().size() );
+
+		Configuration v2cfg = new Configuration();
+		v2cfg.addResource( resource2 );
+
+		SchemaUpdate v2schemaUpdate = new SchemaUpdate( v2cfg );
+		v2schemaUpdate.execute( true, true );
+		assertEquals( 0, v2schemaUpdate.getExceptions().size() );
+
+	}
+
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/Version.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/Version.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/schemaupdate/Version.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+package org.hibernate.test.schemaupdate;
+
+public class Version {
+
+	long id;
+	String name;
+	String description;
+	
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public String getName() {
+		return name;
+	}
+	
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+	public String getDescription() {
+		return description;
+	}
+	
+	public void setDescription(String description) {
+		this.description = description;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/Search.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/Search.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/Search.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+  
+-->
+
+<hibernate-mapping package="org.hibernate.test.sorted">
+	
+	<class name="Search">
+		<id name="searchString"/>
+		<set name="searchResults" sort="natural">
+			<key column="searchString"/>
+			<element column="text" type="string"/>
+		</set>
+	</class>
+	
+</hibernate-mapping>
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/Search.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/Search.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/Search.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/Search.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+//$Id: Search.java 7772 2005-08-05 23:03:46Z oneovthafew $
+package org.hibernate.test.sorted;
+
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+public class Search {
+	private String searchString;
+	private SortedSet searchResults = new TreeSet();
+	
+	Search() {}
+	
+	public Search(String string) {
+		searchString = string;
+	}
+	
+	public SortedSet getSearchResults() {
+		return searchResults;
+	}
+	public void setSearchResults(SortedSet searchResults) {
+		this.searchResults = searchResults;
+	}
+	public String getSearchString() {
+		return searchString;
+	}
+	public void setSearchString(String searchString) {
+		this.searchString = searchString;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/Search.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/SortTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/SortTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/SortTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,79 @@
+//$Id: SortTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.sorted;
+
+import java.util.Iterator;
+
+import junit.framework.Test;
+
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class SortTest extends FunctionalTestCase {
+	
+	public SortTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "sorted/Search.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SortTest.class );
+	}
+	
+	public void testOrderBy() {
+		Search s = new Search("Hibernate");
+		s.getSearchResults().add("jboss.com");
+		s.getSearchResults().add("hibernate.org");
+		s.getSearchResults().add("HiA");
+		
+		Session sess = openSession();
+		Transaction tx = sess.beginTransaction();
+		sess.persist(s);
+		sess.flush();
+		
+		sess.clear();
+		s = (Search) sess.createCriteria(Search.class).uniqueResult();
+		assertFalse( Hibernate.isInitialized( s.getSearchResults() ) );
+		Iterator iter = s.getSearchResults().iterator();
+		assertEquals( iter.next(), "HiA" );
+		assertEquals( iter.next(), "hibernate.org" );
+		assertEquals( iter.next(), "jboss.com" );
+		assertFalse( iter.hasNext() );
+		
+		sess.clear();
+		s = (Search) sess.createCriteria(Search.class)
+				.setFetchMode("searchResults", FetchMode.JOIN)
+				.uniqueResult();
+		assertTrue( Hibernate.isInitialized( s.getSearchResults() ) );
+		iter = s.getSearchResults().iterator();
+		assertEquals( iter.next(), "HiA" );
+		assertEquals( iter.next(), "hibernate.org" );
+		assertEquals( iter.next(), "jboss.com" );
+		assertFalse( iter.hasNext() );
+		
+		sess.clear();
+		s = (Search) sess.createQuery("from Search s left join fetch s.searchResults")
+				.uniqueResult();
+		assertTrue( Hibernate.isInitialized( s.getSearchResults() ) );
+		iter = s.getSearchResults().iterator();
+		assertEquals( iter.next(), "HiA" );
+		assertEquals( iter.next(), "hibernate.org" );
+		assertEquals( iter.next(), "jboss.com" );
+		assertFalse( iter.hasNext() );
+		
+		sess.delete(s);
+		tx.commit();
+		sess.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sorted/SortTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/NativeSqlSupportSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/NativeSqlSupportSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/NativeSqlSupportSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+package org.hibernate.test.sql;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.sql.check.CheckSuite;
+import org.hibernate.test.sql.hand.custom.datadirect.oracle.DataDirectOracleCustomSQLTest;
+import org.hibernate.test.sql.hand.custom.db2.DB2CustomSQLTest;
+import org.hibernate.test.sql.hand.custom.mysql.MySQLCustomSQLTest;
+import org.hibernate.test.sql.hand.custom.oracle.OracleCustomSQLTest;
+import org.hibernate.test.sql.hand.custom.sybase.SybaseCustomSQLTest;
+import org.hibernate.test.sql.hand.query.NativeSQLQueriesTest;
+import org.hibernate.test.sql.hand.identity.CustomInsertSQLWithIdentityColumnTest;
+
+/**
+ * Suite for testing aspects of native SQL support.
+ *
+ * @author Steve Ebersole
+ */
+public class NativeSqlSupportSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "Native SQL support tests" );
+		suite.addTest( DB2CustomSQLTest.suite() );
+		suite.addTest( DataDirectOracleCustomSQLTest.suite() );
+		suite.addTest( OracleCustomSQLTest.suite() );
+		suite.addTest( SybaseCustomSQLTest.suite() );
+		suite.addTest( MySQLCustomSQLTest.suite() );
+		suite.addTest( NativeSQLQueriesTest.suite() );
+		suite.addTest( CheckSuite.suite() );
+		suite.addTest( CustomInsertSQLWithIdentityColumnTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/CheckSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/CheckSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/CheckSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,19 @@
+package org.hibernate.test.sql.check;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Suite for testing custom SQL result checking strategies.
+ * <p/>
+ * Yes, currently there is only one actual test...
+ *
+ * @author Steve Ebersole
+ */
+public class CheckSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "native sql result checking" );
+		suite.addTest( OracleCheckStyleTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/ExceptionCheckingEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/ExceptionCheckingEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/ExceptionCheckingEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+package org.hibernate.test.sql.check;
+
+/**
+ * An entity which is expected to be mapped to each database using stored
+ * procedures which throw exceptions on their own; in other words, using
+ * {@link org.hibernate.engine.ExecuteUpdateResultCheckStyle#NONE}.
+ *
+ * @author Steve Ebersole
+ */
+public class ExceptionCheckingEntity {
+	private Long id;
+	private String name;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/OracleCheckStyleTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/OracleCheckStyleTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/OracleCheckStyleTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+package org.hibernate.test.sql.check;
+
+import junit.framework.Test;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * todo: describe OracleCheckStyleTest
+ *
+ * @author Steve Ebersole
+ */
+public class OracleCheckStyleTest extends ResultCheckStyleTest {
+	public OracleCheckStyleTest(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "sql/check/oracle-mappings.hbm.xml" };
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		return dialect instanceof Oracle9Dialect;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( OracleCheckStyleTest.class );
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/ParamCheckingEntity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/ParamCheckingEntity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/ParamCheckingEntity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+package org.hibernate.test.sql.check;
+
+/**
+ * An entity which is expected to be mapped to each database using stored
+ * procedures which return "affected row counts"; in other words, using
+ * {@link org.hibernate.engine.ExecuteUpdateResultCheckStyle#PARAM}.
+ *
+ * @author Steve Ebersole
+ */
+public class ParamCheckingEntity {
+	private Long id;
+	private String name;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/ResultCheckStyleTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/ResultCheckStyleTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/ResultCheckStyleTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,134 @@
+package org.hibernate.test.sql.check;
+
+import org.hibernate.HibernateException;
+import org.hibernate.JDBCException;
+import org.hibernate.Session;
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+
+/**
+ * todo: describe ResultCheckStyleTest
+ *
+ * @author Steve Ebersole
+ */
+public abstract class ResultCheckStyleTest extends DatabaseSpecificFunctionalTestCase {
+
+	public ResultCheckStyleTest(String name) {
+		super( name );
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public void testInsertionFailureWithExceptionChecking() {
+		Session s = openSession();
+		s.beginTransaction();
+		ExceptionCheckingEntity e = new ExceptionCheckingEntity();
+		e.setName( "dummy" );
+		s.save( e );
+		try {
+			s.flush();
+			fail( "expection flush failure!" );
+		}
+		catch( JDBCException ex ) {
+			// these should specifically be JDBCExceptions...
+		}
+		s.clear();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testInsertionFailureWithParamChecking() {
+		Session s = openSession();
+		s.beginTransaction();
+		ParamCheckingEntity e = new ParamCheckingEntity();
+		e.setName( "dummy" );
+		s.save( e );
+		try {
+			s.flush();
+			fail( "expection flush failure!" );
+		}
+		catch( HibernateException ex ) {
+			// these should specifically be HibernateExceptions...
+		}
+		s.clear();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testUpdateFailureWithExceptionChecking() {
+		Session s = openSession();
+		s.beginTransaction();
+		ExceptionCheckingEntity e = new ExceptionCheckingEntity();
+		e.setId( new Long( 1 ) );
+		e.setName( "dummy" );
+		s.update( e );
+		try {
+			s.flush();
+			fail( "expection flush failure!" );
+		}
+		catch( JDBCException ex ) {
+			// these should specifically be JDBCExceptions...
+		}
+		s.clear();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testUpdateFailureWithParamChecking() {
+		Session s = openSession();
+		s.beginTransaction();
+		ParamCheckingEntity e = new ParamCheckingEntity();
+		e.setId( new Long( 1 ) );
+		e.setName( "dummy" );
+		s.update( e );
+		try {
+			s.flush();
+			fail( "expection flush failure!" );
+		}
+		catch( HibernateException ex ) {
+			// these should specifically be HibernateExceptions...
+		}
+		s.clear();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testDeleteWithExceptionChecking() {
+		Session s = openSession();
+		s.beginTransaction();
+		ExceptionCheckingEntity e = new ExceptionCheckingEntity();
+		e.setId( new Long( 1 ) );
+		e.setName( "dummy" );
+		s.delete( e );
+		try {
+			s.flush();
+			fail( "expection flush failure!" );
+		}
+		catch( JDBCException ex ) {
+			// these should specifically be JDBCExceptions...
+		}
+		s.clear();
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testDeleteWithParamChecking() {
+		Session s = openSession();
+		s.beginTransaction();
+		ParamCheckingEntity e = new ParamCheckingEntity();
+		e.setId( new Long( 1 ) );
+		e.setName( "dummy" );
+		s.delete( e );
+		try {
+			s.flush();
+			fail( "expection flush failure!" );
+		}
+		catch( HibernateException ex ) {
+			// these should specifically be HibernateExceptions...
+		}
+		s.clear();
+		s.getTransaction().commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/oracle-mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/oracle-mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/check/oracle-mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,103 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.sql.check">
+
+    <class name="ExceptionCheckingEntity" table="ENTITY_E">
+        <id name="id" unsaved-value="0" column="ID">
+            <generator class="increment"/>
+        </id>
+        <property name="name" not-null="true"/>
+        <sql-insert callable="true" check="none">{call createEntityE(?,?)}</sql-insert>
+        <sql-update callable="true" check="none">{call updateEntityE(?,?)}</sql-update>
+        <sql-delete callable="true" check="none">{call deleteEntityE(?)}</sql-delete>
+    </class>
+
+    <class name="ParamCheckingEntity" table="ENTITY_P">
+        <id name="id" unsaved-value="0" column="ID">
+            <generator class="increment"/>
+        </id>
+        <property name="name" not-null="true"/>
+        <sql-insert callable="true" check="param">{call createEntityP(?,?,?)}</sql-insert>
+        <sql-update callable="true" check="param">{? = call updateEntityP(?,?)}</sql-update>
+        <sql-delete callable="true" check="param">{? = call deleteEntityP(?)}</sql-delete>
+    </class>
+
+
+    <database-object>
+        <create>
+            CREATE OR REPLACE PROCEDURE createEntityE(p_name ENTITY_E.NAME%TYPE, p_id ENTITY_E.ID%TYPE)
+            AS BEGIN
+                RAISE_APPLICATION_ERROR( -20001, 'Insert failure checking' );
+            END;
+        </create>
+        <drop>
+            DROP PROCEDURE createEntityE;
+        </drop>
+    </database-object>
+
+    <database-object>
+        <create>
+            CREATE OR REPLACE PROCEDURE updateEntityE(p_name ENTITY_E.NAME%TYPE, p_id ENTITY_E.ID%TYPE)
+            AS BEGIN
+                RAISE_APPLICATION_ERROR( -20001, 'Update failure checking' );
+            END;
+        </create>
+        <drop>
+            DROP PROCEDURE updateEntityE;
+        </drop>
+    </database-object>
+
+    <database-object>
+        <create>
+            CREATE OR REPLACE PROCEDURE deleteEntityE(p_id ENTITY_E.ID%TYPE)
+            AS BEGIN
+                RAISE_APPLICATION_ERROR( -20001, 'Update failure checking' );
+            END;
+        </create>
+        <drop>
+            DROP PROCEDURE deleteEntityE;
+        </drop>
+    </database-object>
+
+
+    <database-object>
+        <!-- Demonstrate using an Oracle procedure and a registered OUT paramater as part of hand supplied sql -->
+        <create>
+            CREATE OR REPLACE PROCEDURE createEntityP(result OUT INTEGER, p_name ENTITY_E.NAME%TYPE, p_id ENTITY_E.ID%TYPE)
+            AS BEGIN
+                /* force a failure by returning a non-1 result */
+                result := 2;
+            END;
+        </create>
+        <drop>
+            DROP PROCEDURE createEntityP;
+        </drop>
+    </database-object>
+
+    <database-object>
+        <!-- Demonstrate using an Oracle function and it's return value as part of hand supplied sql -->
+        <create>
+            CREATE OR REPLACE FUNCTION updateEntityP(p_name ENTITY_E.NAME%TYPE, p_id ENTITY_E.ID%TYPE)
+            RETURN INTEGER IS BEGIN
+                RETURN 2;
+            END;
+        </create>
+        <drop>
+            DROP PROCEDURE updateEntityP;
+        </drop>
+    </database-object>
+
+    <database-object>
+        <create>
+            CREATE OR REPLACE FUNCTION deleteEntityP(p_id ENTITY_E.ID%TYPE)
+            RETURN INTEGER IS BEGIN
+                RETURN 2;
+            END;
+        </create>
+        <drop>
+            DROP PROCEDURE deleteEntityE;
+        </drop>
+    </database-object>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Dimension.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Dimension.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Dimension.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+package org.hibernate.test.sql.hand;
+
+/**
+ * Used to mimic some tests from the JPA testsuite...
+ *
+ * @author Steve Ebersole
+ */
+public class Dimension {
+	private Long id;
+	private int length;
+	private int width;
+
+	public Dimension() {}
+
+	public Dimension(int length, int width) {
+		this.length = length;
+		this.width = width;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public int getLength() {
+		return length;
+	}
+
+	public int getWidth() {
+		return width;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Employment.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Employment.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Employment.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,107 @@
+//$Id: Employment.java 11486 2007-05-08 21:57:24Z steve.ebersole at jboss.com $
+package org.hibernate.test.sql.hand;
+
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class Employment {
+	private long employmentId;
+	private Person employee;
+	private Organization employer;
+	private Date startDate;
+	private Date endDate;
+	private String regionCode;
+	private MonetaryAmount salary;
+	
+	public Employment() {}
+
+	public Employment(Person employee, Organization employer, String regionCode) {
+		this.employee = employee;
+		this.employer = employer;
+		this.startDate = new Date();
+		this.regionCode = regionCode;
+		employer.getEmployments().add(this);
+	}
+	/**
+	 * @return Returns the employee.
+	 */
+	public Person getEmployee() {
+		return employee;
+	}
+	/**
+	 * @param employee The employee to set.
+	 */
+	public void setEmployee(Person employee) {
+		this.employee = employee;
+	}
+	/**
+	 * @return Returns the employer.
+	 */
+	public Organization getEmployer() {
+		return employer;
+	}
+	/**
+	 * @param employer The employer to set.
+	 */
+	public void setEmployer(Organization employer) {
+		this.employer = employer;
+	}
+	/**
+	 * @return Returns the endDate.
+	 */
+	public Date getEndDate() {
+		return endDate;
+	}
+	/**
+	 * @param endDate The endDate to set.
+	 */
+	public void setEndDate(Date endDate) {
+		this.endDate = endDate;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getEmploymentId() {
+		return employmentId;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setEmploymentId(long id) {
+		this.employmentId = id;
+	}
+	/**
+	 * @return Returns the startDate.
+	 */
+	public Date getStartDate() {
+		return startDate;
+	}
+	/**
+	 * @param startDate The startDate to set.
+	 */
+	public void setStartDate(Date startDate) {
+		this.startDate = startDate;
+	}
+	/**
+	 * @return Returns the regionCode.
+	 */
+	public String getRegionCode() {
+		return regionCode;
+	}
+	/**
+	 * @param regionCode The regionCode to set.
+	 */
+	public void setRegionCode(String regionCode) {
+		this.regionCode = regionCode;
+	}
+	
+	public MonetaryAmount getSalary() {
+		return salary;
+	}
+	
+	public void setSalary(MonetaryAmount salary) {
+		this.salary = salary;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Employment.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/MonetaryAmount.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/MonetaryAmount.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/MonetaryAmount.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,78 @@
+package org.hibernate.test.sql.hand;
+
+import java.math.BigDecimal;
+import java.util.Currency;
+import java.io.Serializable;
+
+/**
+ * Represents a monetary amount as value and currency.
+ *
+ * @author Gavin King <gavin at hibernate.org>
+ * @author Christian Bauer <christian at hibernate.org>
+ */
+public class MonetaryAmount implements Serializable {
+
+	private final BigDecimal value;
+	private final Currency currency;
+
+	public MonetaryAmount(BigDecimal value, Currency currency) {
+		this.value = value;
+		this.currency = currency;
+	}
+
+	public Currency getCurrency() {
+		return currency;
+	}
+
+	public BigDecimal getValue() {
+		return value;
+	}
+
+	// ********************** Common Methods ********************** //
+
+	public boolean equals(Object o) {
+		if (this == o) return true;
+		if (!(o instanceof MonetaryAmount)) return false;
+
+		final MonetaryAmount monetaryAmount = (MonetaryAmount) o;
+
+		if (!currency.equals(monetaryAmount.currency)) return false;
+		if (!value.equals(monetaryAmount.value)) return false;
+
+		return true;
+	}
+
+	public int hashCode() {
+		int result;
+		result = value.hashCode();
+		result = 29 * result + currency.hashCode();
+		return result;
+	}
+
+	public String toString() {
+		return "Value: '" + getValue() + "', " +
+		        "Currency: '" + getCurrency() + "'";
+	}
+
+	public int compareTo(Object o) {
+		if (o instanceof MonetaryAmount) {
+			// TODO: This would actually require some currency conversion magic
+			return this.getValue().compareTo(((MonetaryAmount) o).getValue());
+		}
+		return 0;
+	}
+
+	// ********************** Business Methods ********************** //
+
+	public static MonetaryAmount fromString(String amount, String currencyCode) {
+		return new MonetaryAmount(new BigDecimal(amount),
+								  Currency.getInstance(currencyCode));
+	}
+
+	public static MonetaryAmount convert(MonetaryAmount amount,
+										 Currency toConcurrency) {
+		// TODO: This requires some conversion magic and is therefore broken
+		return new MonetaryAmount(amount.getValue(), toConcurrency);
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/MonetaryAmountUserType.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/MonetaryAmountUserType.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/MonetaryAmountUserType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,85 @@
+package org.hibernate.test.sql.hand;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Currency;
+
+import org.hibernate.HibernateException;
+import org.hibernate.usertype.UserType;
+
+/**
+ * This is a simple Hibernate custom mapping type for MonetaryAmount value types.
+ * <p>
+ * 
+ * @author Max & Christian 
+ */
+public class MonetaryAmountUserType
+		implements UserType {
+
+	private static final int[] SQL_TYPES = {Types.NUMERIC, Types.VARCHAR };
+
+	public int[] sqlTypes() { return SQL_TYPES; }
+
+	public Class returnedClass() { return MonetaryAmount.class; }
+
+	public boolean isMutable() { return false; }
+
+	public Object deepCopy(Object value) {
+		return value; // MonetaryAmount is immutable
+	}
+
+	public boolean equals(Object x, Object y) {
+		if (x == y) return true;
+		if (x == null || y == null) return false;
+		return x.equals(y);
+	}
+
+	public Object nullSafeGet(ResultSet resultSet,
+							  String[] names,
+							  Object owner)
+			throws HibernateException, SQLException {
+
+		BigDecimal value = resultSet.getBigDecimal(names[0]);
+		if (resultSet.wasNull()) return null;
+		String cur = resultSet.getString(names[1]);
+		Currency userCurrency = Currency.getInstance(cur);
+						
+		return new MonetaryAmount(value, userCurrency);
+	}
+
+	public void nullSafeSet(PreparedStatement statement,
+							Object value,
+							int index)
+			throws HibernateException, SQLException {
+
+		if (value == null) {
+			statement.setNull(index, Types.NUMERIC);			
+			statement.setNull(index+1, Types.VARCHAR);
+		} else {
+			MonetaryAmount currency = (MonetaryAmount)value;
+			statement.setBigDecimal(index, currency.getValue());
+			statement.setString(index+1, currency.getCurrency().getCurrencyCode());
+		}
+	}
+
+	public Serializable disassemble(Object value) throws HibernateException {
+		return (Serializable) value;
+	}
+
+	public Object assemble(Serializable cached, Object owner) throws HibernateException {
+		return cached;
+	}
+
+	public Object replace(Object original, Object target, Object owner)
+	throws HibernateException {
+		return original;
+	}
+
+	public int hashCode(Object x) throws HibernateException {
+		return x.hashCode();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Order.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Order.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Order.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+package org.hibernate.test.sql.hand;
+
+import java.io.Serializable;
+
+public class Order {
+	
+	static public class OrderId implements Serializable {
+		String orgid;
+		String ordernumber;
+		public String getOrdernumber() {
+			return ordernumber;
+		}
+		public void setOrdernumber(String ordernumber) {
+			this.ordernumber = ordernumber;
+		}
+		public String getOrgid() {
+			return orgid;
+		}
+		public void setOrgid(String orgid) {
+			this.orgid = orgid;
+		}
+		
+		
+	}
+	
+	OrderId orderId;
+	
+	Product product;
+
+	Person person;
+	
+	public Person getPerson() {
+		return person;
+	}
+	
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+	public OrderId getOrderId() {
+		return orderId;
+	}
+
+	public void setOrderId(OrderId orderId) {
+		this.orderId = orderId;
+	}
+
+	public Product getProduct() {
+		return product;
+	}
+
+	public void setProduct(Product product) {
+		this.product = product;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Organization.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Organization.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Organization.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,59 @@
+//$Id: Organization.java 11486 2007-05-08 21:57:24Z steve.ebersole at jboss.com $
+package org.hibernate.test.sql.hand;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * @author Gavin King
+ */
+public class Organization {
+	private long id;
+	private String name;
+	private Collection employments;
+
+	public Organization(String name) {
+		this.name = name;
+		employments = new HashSet();
+	}
+
+	public Organization() {}
+
+	/**
+	 * @return Returns the employments.
+	 */
+	public Collection getEmployments() {
+		return employments;
+	}
+	/**
+	 * @param employments The employments to set.
+	 */
+	public void setEmployments(Collection employments) {
+		this.employments = employments;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Organization.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+//$Id: Person.java 11486 2007-05-08 21:57:24Z steve.ebersole at jboss.com $
+package org.hibernate.test.sql.hand;
+
+/**
+ * @author Gavin King
+ */
+public class Person {
+	private long id;
+	private String name;
+
+	public Person(String name) {
+		this.name = name;
+	}
+	
+	public Person() {}
+	
+/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Product.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Product.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Product.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,66 @@
+package org.hibernate.test.sql.hand;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+public class Product {
+	
+	static public class ProductId implements Serializable {
+		String orgid;
+		String productnumber;
+		public String getProductnumber() {
+			return productnumber;
+		}
+		public void setProductnumber(String ordernumber) {
+			this.productnumber = ordernumber;
+		}
+		public String getOrgid() {
+			return orgid;
+		}
+		public void setOrgid(String orgid) {
+			this.orgid = orgid;
+		}
+		
+		
+	}
+	
+	ProductId productId;
+	
+	String name;
+
+	Person person;
+	
+	Set orders = new HashSet();
+	
+	public Set getOrders() {
+		return orders;
+	}
+	
+	public void setOrders(Set orders) {
+		this.orders = orders;
+	}
+	public Person getPerson() {
+		return person;
+	}
+	
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+	public ProductId getProductId() {
+		return productId;
+	}
+
+	public void setProductId(ProductId orderId) {
+		this.productId = orderId;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String product) {
+		this.name = product;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/SpaceShip.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/SpaceShip.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/SpaceShip.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+//$Id: $
+package org.hibernate.test.sql.hand;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class SpaceShip {
+	private Integer id;
+	private String name;
+	private String model;
+	private double speed;
+	private Dimension dimensions;
+
+	public Dimension getDimensions() {
+		return dimensions;
+	}
+
+	public void setDimensions(Dimension dimensions) {
+		this.dimensions = dimensions;
+	}
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getModel() {
+		return model;
+	}
+
+	public void setModel(String model) {
+		this.model = model;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public double getSpeed() {
+		return speed;
+	}
+
+	public void setSpeed(double speed) {
+		this.speed = speed;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Speech.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Speech.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/Speech.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: $
+package org.hibernate.test.sql.hand;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class Speech {
+	private Integer id;
+	private String name;
+	private Double length;
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public Double getLength() {
+		return length;
+	}
+
+	public void setLength(Double length) {
+		this.length = length;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/CustomSQLTestSupport.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/CustomSQLTestSupport.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/CustomSQLTestSupport.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,94 @@
+package org.hibernate.test.sql.hand.custom;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.hibernate.LockMode;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.test.sql.hand.Employment;
+import org.hibernate.test.sql.hand.Organization;
+import org.hibernate.test.sql.hand.Person;
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+
+/**
+ * Abstract test case defining tests for the support for user-supplied (aka
+ * custom) insert, update, delete SQL.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class CustomSQLTestSupport extends DatabaseSpecificFunctionalTestCase {
+
+	public CustomSQLTestSupport(String name) {
+		super( name );
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public void testHandSQL() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Organization ifa = new Organization( "IFA" );
+		Organization jboss = new Organization( "JBoss" );
+		Person gavin = new Person( "Gavin" );
+		Employment emp = new Employment( gavin, jboss, "AU" );
+		Serializable orgId = s.save( jboss );
+		s.save( ifa );
+		s.save( gavin );
+		s.save( emp );
+		t.commit();
+
+		t = s.beginTransaction();
+		Person christian = new Person( "Christian" );
+		s.save( christian );
+		Employment emp2 = new Employment( christian, jboss, "EU" );
+		s.save( emp2 );
+		t.commit();
+		s.close();
+
+		getSessions().evict( Organization.class );
+		getSessions().evict( Person.class );
+		getSessions().evict( Employment.class );
+
+		s = openSession();
+		t = s.beginTransaction();
+		jboss = ( Organization ) s.get( Organization.class, orgId );
+		assertEquals( jboss.getEmployments().size(), 2 );
+		assertEquals( jboss.getName(), "JBOSS" );
+		emp = ( Employment ) jboss.getEmployments().iterator().next();
+		gavin = emp.getEmployee();
+		assertEquals( gavin.getName(), "GAVIN" );
+		assertEquals( s.getCurrentLockMode( gavin ), LockMode.UPGRADE );
+		emp.setEndDate( new Date() );
+		Employment emp3 = new Employment( gavin, jboss, "US" );
+		s.save( emp3 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Iterator iter = s.getNamedQuery( "allOrganizationsWithEmployees" ).list().iterator();
+		assertTrue( iter.hasNext() );
+		Organization o = ( Organization ) iter.next();
+		assertEquals( o.getEmployments().size(), 3 );
+		Iterator iter2 = o.getEmployments().iterator();
+		while ( iter2.hasNext() ) {
+			Employment e = ( Employment ) iter2.next();
+			s.delete( e );
+		}
+		iter2 = o.getEmployments().iterator();
+		while ( iter2.hasNext() ) {
+			Employment e = ( Employment ) iter2.next();
+			s.delete( e.getEmployee() );
+		}
+		s.delete( o );
+		assertFalse( iter.hasNext() );
+		s.delete( ifa );
+		t.commit();
+		s.close();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/CustomStoredProcTestSupport.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/CustomStoredProcTestSupport.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/CustomStoredProcTestSupport.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,83 @@
+package org.hibernate.test.sql.hand.custom;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.test.sql.hand.Employment;
+import org.hibernate.test.sql.hand.Organization;
+import org.hibernate.test.sql.hand.Person;
+
+/**
+ * Abstract test case defining tests of stored procedure support.
+ *
+ * @author Gail Badner
+ */
+public abstract class CustomStoredProcTestSupport extends CustomSQLTestSupport {
+
+	public CustomStoredProcTestSupport(String name) {
+		super( name );
+	}
+
+	public void testScalarStoredProcedure() throws HibernateException, SQLException {
+		Session s = openSession();
+		Query namedQuery = s.getNamedQuery( "simpleScalar" );
+		namedQuery.setLong( "number", 43 );
+		List list = namedQuery.list();
+		Object o[] = ( Object[] ) list.get( 0 );
+		assertEquals( o[0], "getAll" );
+		assertEquals( o[1], new Long( 43 ) );
+		s.close();
+	}
+
+	public void testParameterHandling() throws HibernateException, SQLException {
+		Session s = openSession();
+
+		Query namedQuery = s.getNamedQuery( "paramhandling" );
+		namedQuery.setLong( 0, 10 );
+		namedQuery.setLong( 1, 20 );
+		List list = namedQuery.list();
+		Object[] o = ( Object[] ) list.get( 0 );
+		assertEquals( o[0], new Long( 10 ) );
+		assertEquals( o[1], new Long( 20 ) );
+
+		namedQuery = s.getNamedQuery( "paramhandling_mixed" );
+		namedQuery.setLong( 0, 10 );
+		namedQuery.setLong( "second", 20 );
+		list = namedQuery.list();
+		o = ( Object[] ) list.get( 0 );
+		assertEquals( o[0], new Long( 10 ) );
+		assertEquals( o[1], new Long( 20 ) );
+		s.close();
+	}
+
+	public void testEntityStoredProcedure() throws HibernateException, SQLException {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Organization ifa = new Organization( "IFA" );
+		Organization jboss = new Organization( "JBoss" );
+		Person gavin = new Person( "Gavin" );
+		Employment emp = new Employment( gavin, jboss, "AU" );
+		s.persist( ifa );
+		s.persist( jboss );
+		s.persist( gavin );
+		s.persist( emp );
+
+		Query namedQuery = s.getNamedQuery( "selectAllEmployments" );
+		List list = namedQuery.list();
+		assertTrue( list.get( 0 ) instanceof Employment );
+		s.delete( emp );
+		s.delete( ifa );
+		s.delete( jboss );
+		s.delete( gavin );
+
+		t.commit();
+		s.close();
+	}
+
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/datadirect/oracle/DataDirectOracleCustomSQLTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/datadirect/oracle/DataDirectOracleCustomSQLTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/datadirect/oracle/DataDirectOracleCustomSQLTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id$
+package org.hibernate.test.sql.hand.custom.datadirect.oracle;
+
+import junit.framework.Test;
+
+import org.hibernate.dialect.DataDirectOracle9Dialect;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.sql.hand.custom.CustomStoredProcTestSupport;
+
+/**
+ * Custom SQL tests for Oracle via the DataDirect drivers.
+ * 
+ * @author Max Rydahl Andersen
+ */
+public class DataDirectOracleCustomSQLTest extends CustomStoredProcTestSupport {
+	
+	public DataDirectOracleCustomSQLTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "sql/hand/custom/oracle/Mappings.hbm.xml", "sql/hand/custom/datadirect/oracle/StoredProcedures.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( DataDirectOracleCustomSQLTest.class );
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		return ( dialect instanceof DataDirectOracle9Dialect );
+	}
+
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/datadirect/oracle/StoredProcedures.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/datadirect/oracle/StoredProcedures.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/datadirect/oracle/StoredProcedures.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+    This version is for DataDirect drivers jdbc standard handling of stored procedures/functions.
+-->
+<hibernate-mapping package="org.hibernate.test.sql.hand" default-access="field">
+
+	<sql-query name="simpleScalar" callable="true">
+	 <return-scalar column="name" type="string"/>
+	 <return-scalar column="value" type="long"/>
+	 { call simpleScalar(:number) }
+	</sql-query>
+	<sql-query name="paramhandling" callable="true">
+		<return-scalar column="value" type="long" />
+		<return-scalar column="value2" type="long" />
+		{ call testParamHandling(?,?) }
+	</sql-query>
+
+	<sql-query name="paramhandling_mixed" callable="true">
+		<return-scalar column="value" type="long" />
+		<return-scalar column="value2" type="long" />
+		{ call testParamHandling(?,:second) }
+	</sql-query>
+
+	<sql-query name="selectAllEmployments" callable="true">
+		<return alias="emp" class="Employment">
+			<return-property name="employee" column="EMPLOYEE"/>
+			<return-property name="employer" column="EMPLOYER"/>			
+			<return-property name="startDate" column="STARTDATE"/>
+			<return-property name="endDate" column="ENDDATE"/>			
+			<return-property name="regionCode" column="REGIONCODE"/>			
+			<return-property name="employmentId" column="EMPID"/>						
+			<return-property name="salary">
+  			  <return-column name="VALUE"/>
+			  <return-column name="CURRENCY"/>			
+			</return-property>
+		</return>
+	 { call allEmployments() }
+	</sql-query>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/db2/DB2CustomSQLTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/db2/DB2CustomSQLTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/db2/DB2CustomSQLTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id$
+package org.hibernate.test.sql.hand.custom.db2;
+
+import junit.framework.Test;
+
+import org.hibernate.dialect.DB2Dialect;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.sql.hand.custom.CustomStoredProcTestSupport;
+
+/**
+ * Custom SQL tests for DB2
+ * 
+ * @author Max Rydahl Andersen
+ */
+public class DB2CustomSQLTest extends CustomStoredProcTestSupport {
+	
+	public DB2CustomSQLTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "sql/hand/custom/db2/Mappings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( DB2CustomSQLTest.class );
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		return ( dialect instanceof DB2Dialect);
+	}
+
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/db2/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/db2/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/db2/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,236 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    This mapping demonstrates the use of Hibernate with all-handwritten SQL!
+
+    NOTE : this version is for DB2 & variants
+-->
+<hibernate-mapping package="org.hibernate.test.sql.hand" default-access="field">
+
+	<class name="Organization" table="ORGANIZATION">
+		<id name="id" unsaved-value="0" column="ORGID">
+			<generator class="increment"/>
+		</id>
+		<property name="name" not-null="true" column="NAME"/>
+		<set name="employments" 
+			inverse="true"
+			order-by="DUMMY">
+			<key column="EMPLOYER"/> <!-- only needed for DDL generation -->
+			<one-to-many class="Employment"/>
+			<loader query-ref="organizationEmployments"/>
+		</set>
+		<!-- query-list name="currentEmployments" 
+			query-ref="organizationCurrentEmployments"-->
+		<loader query-ref="organization"/>
+		<sql-insert>INSERT INTO ORGANIZATION (NAME, ORGID) VALUES ( UPPER(? || ''), ? )</sql-insert>
+		<sql-update>UPDATE ORGANIZATION SET NAME=UPPER(? || '') WHERE ORGID=?</sql-update>
+		<sql-delete>DELETE FROM ORGANIZATION WHERE ORGID=?</sql-delete>
+	</class>
+	
+	<class name="Person" table="PERSON">
+		<id name="id" unsaved-value="0" column="PERID">
+			<generator class="increment"/>
+		</id>
+		<property name="name" not-null="true" column="NAME"/>
+		<loader query-ref="person"/>
+		<sql-insert>INSERT INTO PERSON (NAME, PERID) VALUES ( UPPER(? || ''), ? )</sql-insert>
+		<sql-update>UPDATE PERSON SET NAME=UPPER(? || '') WHERE PERID=?</sql-update>
+		<sql-delete>DELETE FROM PERSON WHERE PERID=?</sql-delete>
+	</class>
+	
+	<class name="Employment" table="EMPLOYMENT">
+		<id name="employmentId" unsaved-value="0" column="EMPID">
+			<generator class="increment"/>
+		</id>
+		<many-to-one name="employee" column="EMPLOYEE" not-null="true" update="false"/>
+		<many-to-one name="employer" column="EMPLOYER" not-null="true" update="false"/>
+		<property name="startDate" column="STARTDATE" not-null="true" update="false" insert="false"/>
+		<property name="endDate" column="ENDDATE" insert="false"/>
+		<property name="regionCode" column="REGIONCODE" update="false"/>
+        <property name="salary" type="org.hibernate.test.sql.hand.MonetaryAmountUserType">
+			<column name="VALUE" sql-type="float"/>
+			<column name="CURRENCY"/>			
+		</property>
+		<loader query-ref="employment"/>
+   		<sql-insert>
+			INSERT INTO EMPLOYMENT 
+				(EMPLOYEE, EMPLOYER, STARTDATE, REGIONCODE, VALUE, CURRENCY, EMPID) 
+				 <!-- inserting raw specific timestamp since using current date or current timestamp for some reason does not work with a timestamp column! -->
+				VALUES (?, ?, TIMESTAMP ('2006-02-28 11:39:00'), UPPER(? || ''), ?, ?, ?)
+		</sql-insert>
+		<sql-update>UPDATE EMPLOYMENT SET ENDDATE=?, VALUE=?, CURRENCY=? WHERE EMPID=?</sql-update> 
+		<sql-delete>DELETE FROM EMPLOYMENT WHERE EMPID=?</sql-delete> 
+	</class>
+
+    <resultset name="org-emp-regionCode">
+        <return-scalar column="regionCode" type="string"/>
+        <return alias="org" class="Organization"/>
+        <return-join alias="emp" property="org.employments"/>
+    </resultset>
+
+    <resultset name="org-emp-person">
+        <return alias="org" class="Organization"/>
+        <return-join alias="emp" property="org.employments"/>
+        <return-join alias="pers" property="emp.employee"/>
+    </resultset>
+	
+	<sql-query name="person">
+		<return alias="p" class="Person" lock-mode="upgrade"/>
+		SELECT NAME AS {p.name}, PERID AS {p.id} FROM PERSON WHERE PERID=? /*FOR UPDATE*/
+	</sql-query>
+
+	<sql-query name="organization">
+		<return alias="org" class="Organization"/>
+		<return-join alias="emp" property="org.employments"/>
+		SELECT {org.*}, {emp.*}
+		FROM ORGANIZATION org
+			LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER
+		WHERE org.ORGID=?
+	</sql-query>
+
+
+	<!--sql-query name="organization">
+		<return alias="org" class="Organization"/>
+		SELECT NAME AS {org.name}, ORGID AS {org.id} FROM ORGANIZATION
+		WHERE ORGID=?
+	</sql-query-->
+	
+	<sql-query name="allOrganizationsWithEmployees" flush-mode="never">
+		<return alias="org" class="Organization"/>
+		SELECT DISTINCT org.NAME AS {org.name}, org.ORGID AS {org.id} 
+		FROM ORGANIZATION org
+		INNER JOIN EMPLOYMENT e ON e.EMPLOYER = org.ORGID
+	</sql-query>
+	
+	
+	
+
+	
+	<sql-query name="employment">
+		<return alias="emp" class="Employment"/>
+		SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer}, 
+			STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+			REGIONCODE as {emp.regionCode}, EMPID AS {emp.id}
+		FROM EMPLOYMENT
+		WHERE EMPID = ?
+	</sql-query>
+
+	<sql-query name="organizationEmployments">
+		<load-collection alias="empcol" role="Organization.employments"/>
+		SELECT {empcol.*}
+		FROM EMPLOYMENT empcol
+		WHERE EMPLOYER = :id
+		ORDER BY STARTDATE ASC, EMPLOYEE ASC
+	</sql-query>
+
+
+	<sql-query name="organizationCurrentEmployments">
+		<return alias="emp" class="Employment">		    
+			<return-property name="salary"> 
+		      <!-- as multi column properties are not supported via the
+		      {}-syntax, we need to provide an explicit column list for salary via <return-property> -->
+  			  <return-column name="VALUE"/>
+			  <return-column name="CURRENCY"/>			
+			</return-property>
+			<!-- Here we are remapping endDate. Notice that we can still use {emp.endDate} in the SQL. -->
+			<return-property name="endDate" column="myEndDate"/>
+		</return>
+		<synchronize table="EMPLOYMENT"/>
+		SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer}, 
+			STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+			REGIONCODE as {emp.regionCode}, EMPID AS {emp.id}, VALUE, CURRENCY
+		FROM EMPLOYMENT
+		WHERE EMPLOYER = :id AND ENDDATE IS NULL
+		ORDER BY STARTDATE ASC
+	</sql-query>
+
+	<sql-query name="simpleScalar" callable="true">
+		<return-scalar column="name" type="string"/>
+		<return-scalar column="value" type="long"/>
+		{ call HIBDB2TST.simpleScalar(:number) }
+	</sql-query>
+
+	<sql-query name="paramhandling" callable="true">
+		<return-scalar column="value" type="long"/>
+		<return-scalar column="value2" type="long"/>
+		{ call HIBDB2TST.paramHandling(?,?) }
+	</sql-query>
+
+	<sql-query name="paramhandling_mixed" callable="true">
+		<return-scalar column="value" type="long" />
+		<return-scalar column="value2" type="long" />
+		{ call HIBDB2TST.paramHandling(?,:second) }
+	</sql-query>
+	
+	<sql-query name="selectAllEmployments" callable="true">
+		<return alias="" class="Employment">
+			<return-property name="employee" column="EMPLOYEE"/>
+			<return-property name="employer" column="EMPLOYER"/>			
+			<return-property name="startDate" column="STARTDATE"/>
+			<return-property name="endDate" column="ENDDATE"/>			
+			<return-property name="regionCode" column="REGIONCODE"/>			
+			<return-property name="id" column="EMPID"/>						
+			<return-property name="salary"> 
+				<!-- as multi column properties are not supported via the
+				{}-syntax, we need to provide an explicit column list for salary via <return-property> -->
+				<return-column name="VALUE"/>
+				<return-column name="CURRENCY"/>			
+			</return-property>
+		</return>
+		{ call HIBDB2TST.selectAllEmployments() }
+	</sql-query>
+
+	<!-- DB2 seem to *require* users to specify explicit schema/location when executing a stored procedure *stupid* -->
+	<database-object>
+	  <create>CREATE SCHEMA HIBDB2TST</create>
+	  <drop>DROP SCHEMA HIBDB2TST RESTRICT</drop>
+	</database-object>
+	
+	<database-object>
+		<create>
+		CREATE PROCEDURE HIBDB2TST.selectAllEmployments ()
+        P1: BEGIN
+         DECLARE C1 CURSOR WITH RETURN FOR
+			SELECT EMPLOYEE, EMPLOYER, STARTDATE, ENDDATE, 
+			REGIONCODE, EMPID, VALUE, CURRENCY
+			FROM EMPLOYMENT;
+         OPEN C1;
+        END P1
+		</create>
+		<drop>
+		DROP PROCEDURE HIBDB2TST.selectAllEmployments
+		</drop>
+	</database-object>
+
+	
+	<database-object>
+		<create>
+		CREATE PROCEDURE HIBDB2TST.paramHandling (IN j SMALLINT, IN i SMALLINT)
+        P1: BEGIN
+         DECLARE C1 CURSOR WITH RETURN FOR
+    		SELECT j as value, i as value2 from sysibm.sysdummy1;
+         OPEN C1;
+        END P1
+		</create>
+		<drop>
+		DROP PROCEDURE HIBDB2TST.paramHandling
+		</drop>
+	</database-object>
+	
+    <database-object>
+	 <create>
+		CREATE PROCEDURE HIBDB2TST.simpleScalar (IN j SMALLINT)
+        P1: BEGIN
+         DECLARE C1 CURSOR WITH RETURN FOR
+    		SELECT j as value, 'getAll' as name from sysibm.sysdummy1;
+         OPEN C1;
+        END P1
+	 </create>
+	 <drop>
+		DROP PROCEDURE HIBDB2TST.simpleScalar
+	 </drop>
+	</database-object>	
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/mysql/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/mysql/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/mysql/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,216 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+    This mapping demonstrates the use of Hibernate with all-handwritten SQL!
+
+    This version is for MySQL
+-->
+
+<hibernate-mapping package="org.hibernate.test.sql.hand" default-access="field">
+
+	<class name="Organization">
+		<id name="id" unsaved-value="0" column="orgid">
+			<generator class="increment"/>
+		</id>
+		<property name="name" not-null="true"/>
+		<set name="employments" 
+			inverse="true"
+			order-by="DUMMY">
+			<key column="employer"/> <!-- only needed for DDL generation -->
+			<one-to-many class="Employment"/>
+			<loader query-ref="organizationEmployments"/>
+		</set>
+		<!-- query-list name="currentEmployments" 
+			query-ref="organizationCurrentEmployments"-->
+		<loader query-ref="organization"/>
+		<sql-insert>INSERT INTO ORGANIZATION (NAME, ORGID) VALUES ( UPPER(?), ? )</sql-insert>
+		<sql-update>UPDATE ORGANIZATION SET NAME=UPPER(?) WHERE ORGID=?</sql-update>
+		<sql-delete>DELETE FROM ORGANIZATION WHERE ORGID=?</sql-delete>
+	</class>
+	
+	<class name="Person">
+		<id name="id" unsaved-value="0" column="perid">
+			<generator class="increment"/>
+		</id>
+		<property name="name" not-null="true"/>
+		<loader query-ref="person"/>
+		<sql-insert>INSERT INTO PERSON (NAME, PERID) VALUES ( UPPER(?), ? )</sql-insert>
+		<sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE PERID=?</sql-update>
+		<sql-delete>DELETE FROM PERSON WHERE PERID=?</sql-delete>
+	</class>
+	
+	<class name="Employment">
+		<id name="employmentId" unsaved-value="0" column="empid">
+			<generator class="increment"/>
+		</id>
+		<many-to-one name="employee" not-null="true" update="false"/>
+		<many-to-one name="employer" not-null="true" update="false"/>
+		<property name="startDate" not-null="true" update="false" insert="false"/>
+		<property name="endDate" insert="false"/>
+		<property name="regionCode" update="false"/>
+	  <property name="salary" type="org.hibernate.test.sql.hand.MonetaryAmountUserType">
+			<column name="VALUE" sql-type="float"/>
+			<column name="CURRENCY"/>			
+		</property>
+		<loader query-ref="employment"/>
+   		<sql-insert>
+			INSERT INTO EMPLOYMENT 
+				(EMPLOYEE, EMPLOYER, STARTDATE, REGIONCODE, VALUE, CURRENCY, EMPID) 
+				VALUES (?, ?, now(), UPPER(?), ?, ?, ?)
+		</sql-insert>
+		<sql-update>UPDATE EMPLOYMENT SET ENDDATE=?, VALUE=?, CURRENCY=? WHERE EMPID=?</sql-update> 
+		<sql-delete>DELETE FROM EMPLOYMENT WHERE EMPID=?</sql-delete> 
+	</class>
+
+    <resultset name="org-emp-regionCode">
+        <return-scalar column="regionCode" type="string"/>
+        <return alias="org" class="Organization"/>
+        <return-join alias="emp" property="org.employments"/>
+    </resultset>
+
+    <resultset name="org-emp-person">
+        <return alias="org" class="Organization"/>
+        <return-join alias="emp" property="org.employments"/>
+        <return-join alias="pers" property="emp.employee"/>
+    </resultset>
+	
+	<sql-query name="person">
+		<return alias="p" class="Person" lock-mode="upgrade"/>
+		SELECT NAME AS {p.name}, PERID AS {p.id} FROM PERSON WHERE PERID=? /*FOR UPDATE*/
+	</sql-query>
+
+	<sql-query name="organization">
+		<return alias="org" class="Organization"/>
+		<return-join alias="emp" property="org.employments"/>
+		SELECT {org.*}, {emp.*}
+		FROM ORGANIZATION org
+			LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER
+		WHERE org.ORGID=?
+	</sql-query>
+
+
+
+	<!--sql-query name="organization">
+		<return alias="org" class="Organization"/>
+		SELECT NAME AS {org.name}, ORGID AS {org.id} FROM ORGANIZATION
+		WHERE ORGID=?
+	</sql-query-->
+	
+	<sql-query name="allOrganizationsWithEmployees" flush-mode="never">
+		<return alias="org" class="Organization"/>
+		SELECT DISTINCT org.NAME AS {org.name}, org.ORGID AS {org.id} 
+		FROM ORGANIZATION org
+		INNER JOIN EMPLOYMENT e ON e.EMPLOYER = org.ORGID
+	</sql-query>
+	
+	<sql-query name="employment">
+		<return alias="emp" class="Employment"/>
+		SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer}, 
+			STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+			REGIONCODE as {emp.regionCode}, EMPID AS {emp.id}
+		FROM EMPLOYMENT
+		WHERE EMPID = ?
+	</sql-query>
+
+	
+	<sql-query name="organizationEmployments">
+		<load-collection alias="empcol" role="Organization.employments"/>
+		SELECT {empcol.*}
+		FROM EMPLOYMENT empcol
+		WHERE EMPLOYER = :id
+		ORDER BY STARTDATE ASC, EMPLOYEE ASC
+	</sql-query>
+
+
+	<sql-query name="organizationCurrentEmployments">
+		<return alias="emp" class="Employment">		    
+			<return-property name="salary"> 
+		      <!-- as multi column properties are not supported via the
+		      {}-syntax, we need to provide an explicit column list for salary via <return-property> -->
+  			  <return-column name="VALUE"/>
+			  <return-column name="CURRENCY"/>			
+			</return-property>
+			<!-- Here we are remapping endDate. Notice that we can still use {emp.endDate} in the SQL. -->
+			<return-property name="endDate" column="myEndDate"/>
+		</return>
+		<synchronize table="EMPLOYMENT"/>
+		SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer}, 
+			STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+			REGIONCODE as {emp.regionCode}, EMPID AS {emp.id}, VALUE, CURRENCY
+		FROM EMPLOYMENT
+		WHERE EMPLOYER = :id AND ENDDATE IS NULL
+		ORDER BY STARTDATE ASC
+	</sql-query>
+
+	<sql-query name="simpleScalar" callable="true">
+	 <return-scalar column="name" type="string"/>
+	 <return-scalar column="value" type="long"/>
+		{ call simpleScalar(:number) }
+	</sql-query>
+
+	<sql-query name="paramhandling" callable="true">
+		<return-scalar column="value" type="long"/>
+		<return-scalar column="value2" type="long"/>
+		{ call paramHandling(?,?) }
+	</sql-query>
+
+	<sql-query name="paramhandling_mixed" callable="true">
+		<return-scalar column="value" type="long" />
+		<return-scalar column="value2" type="long" />
+		{ call paramHandling(?,:second) }
+	</sql-query>
+	
+	<sql-query name="selectAllEmployments" callable="true">
+		<return alias="" class="Employment">
+			<return-property name="employee" column="EMPLOYEE"/>
+			<return-property name="employer" column="EMPLOYER"/>			
+			<return-property name="startDate" column="STARTDATE"/>
+			<return-property name="endDate" column="ENDDATE"/>			
+			<return-property name="regionCode" column="REGIONCODE"/>			
+			<return-property name="id" column="EMPID"/>						
+			<return-property name="salary"> 
+				<!-- as multi column properties are not supported via the
+				{}-syntax, we need to provide an explicit column list for salary via <return-property> -->
+				<return-column name="VALUE"/>
+				<return-column name="CURRENCY"/>			
+			</return-property>
+		</return>
+		{ call selectAllEmployments() }
+	</sql-query>
+	
+	<database-object>
+		<create>
+		CREATE PROCEDURE selectAllEmployments ()
+			SELECT EMPLOYEE, EMPLOYER, STARTDATE, ENDDATE, 
+			REGIONCODE, EMPID, VALUE, CURRENCY
+			FROM EMPLOYMENT
+		</create>
+		<drop>
+		DROP PROCEDURE selectAllEmployments
+		</drop>
+	</database-object>
+	
+	<database-object>
+		<create>
+		CREATE PROCEDURE paramHandling (j int, i int) 
+			SELECT j AS value, i AS value2
+		</create>
+		<drop>
+		DROP PROCEDURE paramHandling
+		</drop>
+	</database-object>
+	
+	<database-object>
+		<create>
+		CREATE PROCEDURE simpleScalar (number int) 
+			SELECT number AS value, 'getAll' AS name
+		</create>
+		<drop>
+		DROP PROCEDURE simpleScalar
+		</drop>
+	</database-object>
+	
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/mysql/Mappings.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/mysql/MySQLCustomSQLTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/mysql/MySQLCustomSQLTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/mysql/MySQLCustomSQLTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+//$Id: MySQLCustomSQLTest.java 11486 2007-05-08 21:57:24Z steve.ebersole at jboss.com $
+package org.hibernate.test.sql.hand.custom.mysql;
+
+import junit.framework.Test;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.sql.hand.custom.CustomStoredProcTestSupport;
+
+/**
+ * Custom SQL tests for MySQL
+ *
+ * @author Gavin King
+ */
+public class MySQLCustomSQLTest extends CustomStoredProcTestSupport {
+
+	public MySQLCustomSQLTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "sql/hand/custom/mysql/Mappings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( MySQLCustomSQLTest.class );
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		return ( dialect instanceof MySQLDialect );
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/mysql/MySQLCustomSQLTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/oracle/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/oracle/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/oracle/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,209 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    This mapping demonstrates the use of Hibernate with all-handwritten SQL!
+
+    Note: this version is for Oracle
+-->
+<hibernate-mapping package="org.hibernate.test.sql.hand" default-access="field">
+
+    <class name="Organization">
+        <id name="id" unsaved-value="0" column="orgid">
+            <generator class="increment"/>
+        </id>
+        <property name="name" not-null="true"/>
+        <set name="employments"
+             inverse="true"
+             order-by="DUMMY">
+            <key column="employer"/>
+            <!-- only needed for DDL generation -->
+            <one-to-many class="Employment"/>
+            <loader query-ref="organizationEmployments"/>
+        </set>
+        <!-- query-list name="currentEmployments"
+         query-ref="organizationCurrentEmployments"-->
+        <loader query-ref="organization"/>
+        <sql-insert>INSERT INTO ORGANIZATION (NAME, ORGID) VALUES ( UPPER(?), ? )</sql-insert>
+        <sql-update>UPDATE ORGANIZATION SET NAME=UPPER(?) WHERE ORGID=?</sql-update>
+        <sql-delete>DELETE FROM ORGANIZATION WHERE ORGID=?</sql-delete>
+    </class>
+
+    <class name="Person">
+        <id name="id" unsaved-value="0" column="perid">
+            <generator class="increment"/>
+        </id>
+        <property name="name" not-null="true"/>
+        <loader query-ref="person"/>
+        <sql-insert callable="true" check="none">{call createPerson(?,?)}</sql-insert>
+        <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE PERID=?</sql-update>
+        <sql-delete>DELETE FROM PERSON WHERE PERID=?</sql-delete>
+    </class>
+
+    <class name="Employment">
+        <id name="employmentId" unsaved-value="0" column="empid">
+            <generator class="increment"/>
+        </id>
+        <many-to-one name="employee" not-null="true" update="false"/>
+        <many-to-one name="employer" not-null="true" update="false"/>
+        <property name="startDate" not-null="true" update="false" insert="false"/>
+        <property name="endDate" insert="false"/>
+        <property name="regionCode" update="false"/>
+        <property name="salary" type="org.hibernate.test.sql.hand.MonetaryAmountUserType">
+            <column name="VALUE" sql-type="float"/>
+            <column name="CURRENCY"/>
+        </property>
+        <loader query-ref="employment"/>
+        <sql-insert>
+            INSERT INTO EMPLOYMENT
+            (EMPLOYEE, EMPLOYER, STARTDATE, REGIONCODE, VALUE, CURRENCY, EMPID)
+            VALUES (?, ?, CURRENT_DATE, UPPER(?), ?, ?, ?)
+        </sql-insert>
+        <sql-update>UPDATE EMPLOYMENT SET ENDDATE=?, VALUE=?, CURRENCY=? WHERE EMPID=?</sql-update>
+        <sql-delete>DELETE FROM EMPLOYMENT WHERE EMPID=?</sql-delete>
+    </class>
+
+    <resultset name="org-emp-regionCode">
+        <return-scalar column="regionCode" type="string"/>
+        <return alias="org" class="Organization"/>
+        <return-join alias="emp" property="org.employments"/>
+    </resultset>
+
+    <resultset name="org-emp-person">
+        <return alias="org" class="Organization"/>
+        <return-join alias="emp" property="org.employments"/>
+        <return-join alias="pers" property="emp.employee"/>
+    </resultset>
+
+    <sql-query name="person">
+        <return alias="p" class="Person" lock-mode="upgrade"/>
+        SELECT NAME AS {p.name}, PERID AS {p.id} FROM PERSON WHERE PERID=? /*FOR UPDATE*/
+    </sql-query>
+
+    <sql-query name="organization">
+        <return alias="org" class="Organization"/>
+        <return-join alias="emp" property="org.employments"/>
+        SELECT {org.*}, {emp.*}
+        FROM ORGANIZATION org
+        LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER
+        WHERE org.ORGID=?
+    </sql-query>
+
+
+    <sql-query name="allOrganizationsWithEmployees" flush-mode="never">
+        <return alias="org" class="Organization"/>
+        SELECT DISTINCT org.NAME AS {org.name}, org.ORGID AS {org.id}
+        FROM ORGANIZATION org
+        INNER JOIN EMPLOYMENT e ON e.EMPLOYER = org.ORGID
+    </sql-query>
+
+
+    <sql-query name="employment">
+        <return alias="emp" class="Employment"/>
+        SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
+        STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+        REGIONCODE as {emp.regionCode}, EMPID AS {emp.id}
+        FROM EMPLOYMENT
+        WHERE EMPID = ?
+    </sql-query>
+
+
+    <sql-query name="organizationEmployments">
+        <load-collection alias="empcol" role="Organization.employments"/>
+        SELECT {empcol.*}
+        FROM EMPLOYMENT empcol
+        WHERE EMPLOYER = :id
+        ORDER BY STARTDATE ASC, EMPLOYEE ASC
+    </sql-query>
+
+
+    <sql-query name="organizationCurrentEmployments">
+        <return alias="emp" class="Employment">
+            <return-property name="salary">
+                <!-- as multi column properties are not supported via the
+                              {}-syntax, we need to provide an explicit column list for salary via <return-property> -->
+                <return-column name="VALUE"/>
+                <return-column name="CURRENCY"/>
+            </return-property>
+            <!-- Here we are remapping endDate. Notice that we can still use {emp.endDate} in the SQL. -->
+            <return-property name="endDate" column="myEndDate"/>
+        </return>
+        <synchronize table="EMPLOYMENT"/>
+        SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
+        STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+        REGIONCODE as {emp.regionCode}, EMPID AS {emp.id}, VALUE, CURRENCY
+        FROM EMPLOYMENT
+        WHERE EMPLOYER = :id AND ENDDATE IS NULL
+        ORDER BY STARTDATE ASC
+    </sql-query>
+
+    <database-object>
+        <create>
+            CREATE OR REPLACE FUNCTION testParamHandling (j number, i number)
+            RETURN SYS_REFCURSOR AS st_cursor SYS_REFCURSOR;
+            BEGIN
+            OPEN st_cursor FOR
+            SELECT j as value, i as value2 from dual;
+            RETURN st_cursor;
+            END;
+        </create>
+        <drop>
+            DROP FUNCTION testParamHandling
+        </drop>
+    </database-object>
+
+    <database-object>
+        <create>
+            CREATE OR REPLACE FUNCTION simpleScalar (j number)
+            RETURN SYS_REFCURSOR AS st_cursor SYS_REFCURSOR;
+            BEGIN
+            OPEN st_cursor FOR
+            SELECT j as value, 'getAll' as name from dual;
+            RETURN st_cursor;
+            END;
+        </create>
+        <drop>
+            DROP FUNCTION simpleScalar
+        </drop>
+    </database-object>
+
+    <database-object>
+        <create>
+            CREATE OR REPLACE FUNCTION allEmployments
+            RETURN SYS_REFCURSOR AS st_cursor SYS_REFCURSOR;
+            BEGIN
+            OPEN st_cursor FOR
+            SELECT EMPLOYEE, EMPLOYER, STARTDATE, ENDDATE,
+            REGIONCODE, EMPID, VALUE, CURRENCY
+            FROM EMPLOYMENT;
+            RETURN st_cursor;
+            END;
+        </create>
+        <drop>
+            DROP FUNCTION allEmployments
+        </drop>
+    </database-object>
+
+    <database-object>
+        <create>
+            CREATE OR REPLACE PROCEDURE createPerson(p_name PERSON.NAME%TYPE, p_id PERSON.PERID%TYPE)
+            AS
+                rowcount INTEGER;
+            BEGIN
+                INSERT INTO PERSON ( PERID, NAME ) VALUES ( p_id, UPPER( p_name ) );
+                rowcount := SQL%ROWCOUNT;
+                IF rowcount = 1 THEN
+                    NULL;
+                ELSE
+                    RAISE_APPLICATION_ERROR( -20001, 'Unexpected rowcount [' || rowcount || ']' );
+                END IF;
+            END;
+        </create>
+        <drop>
+            DROP PROCEDURE createPerson;
+        </drop>
+    </database-object>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/oracle/OracleCustomSQLTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/oracle/OracleCustomSQLTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/oracle/OracleCustomSQLTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+//$Id$
+package org.hibernate.test.sql.hand.custom.oracle;
+
+import junit.framework.Test;
+
+import org.hibernate.dialect.DataDirectOracle9Dialect;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.Oracle9Dialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.sql.hand.custom.CustomStoredProcTestSupport;
+
+/**
+ * Custom SQL tests for Oracle
+ * 
+ * @author Gavin King
+ */
+public class OracleCustomSQLTest extends CustomStoredProcTestSupport {
+
+	public OracleCustomSQLTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "sql/hand/custom/oracle/Mappings.hbm.xml", "sql/hand/custom/oracle/StoredProcedures.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( OracleCustomSQLTest.class );
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		return ( dialect instanceof Oracle9Dialect ) && !( dialect instanceof DataDirectOracle9Dialect );
+	}
+
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/oracle/StoredProcedures.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/oracle/StoredProcedures.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/oracle/StoredProcedures.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+    This version is for Oracle drivers proprietary handling of stored procedures/functions.
+-->
+<hibernate-mapping package="org.hibernate.test.sql.hand" default-access="field">
+
+    <sql-query name="simpleScalar" callable="true">
+        <return-scalar column="name" type="string"/>
+        <return-scalar column="value" type="long"/>
+        { ? = call simpleScalar(:number) }
+    </sql-query>
+
+    <sql-query name="paramhandling" callable="true">
+        <return-scalar column="value" type="long"/>
+        <return-scalar column="value2" type="long"/>
+        { ? = call testParamHandling(?,?) }
+    </sql-query>
+
+    <sql-query name="paramhandling_mixed" callable="true">
+        <return-scalar column="value" type="long"/>
+        <return-scalar column="value2" type="long"/>
+        { ? = call testParamHandling(?,:second) }
+    </sql-query>
+
+    <sql-query name="selectAllEmployments" callable="true">
+        <return alias="emp" class="Employment">
+            <return-property name="employee" column="EMPLOYEE"/>
+            <return-property name="employer" column="EMPLOYER"/>
+            <return-property name="startDate" column="STARTDATE"/>
+            <return-property name="endDate" column="ENDDATE"/>
+            <return-property name="regionCode" column="REGIONCODE"/>
+            <return-property name="employmentId" column="EMPID"/>
+            <return-property name="salary">
+                <return-column name="VALUE"/>
+                <return-column name="CURRENCY"/>
+            </return-property>
+        </return>
+        { ? = call allEmployments() }
+    </sql-query>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/sybase/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/sybase/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/sybase/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,217 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+    This mapping demonstrates the use of Hibernate with all-handwritten SQL!
+     
+    NOTE: this version is for Sybase/SQLServer
+-->
+<hibernate-mapping package="org.hibernate.test.sql.hand" default-access="field">
+
+	<class name="Organization" table="ORGANIZATION">
+		<id name="id" unsaved-value="0" column="ORGID">
+			<generator class="increment"/>
+		</id>
+		<property name="name" not-null="true" column="NAME"/>
+		<set name="employments" 
+			inverse="true"
+			order-by="DUMMY">
+			<key column="EMPLOYER"/> <!-- only needed for DDL generation -->
+			<one-to-many class="Employment"/>
+			<loader query-ref="organizationEmployments"/>
+		</set>
+		<!-- query-list name="currentEmployments" 
+			query-ref="organizationCurrentEmployments"-->
+		<loader query-ref="organization"/>
+		<sql-insert>INSERT INTO ORGANIZATION (NAME, ORGID) VALUES ( UPPER(?), ? )</sql-insert>
+		<sql-update>UPDATE ORGANIZATION SET NAME=UPPER(?) WHERE ORGID=?</sql-update>
+		<sql-delete>DELETE FROM ORGANIZATION WHERE ORGID=?</sql-delete>
+	</class>
+	
+	<class name="Person" table="PERSON">
+		<id name="id" unsaved-value="0" column="PERID">
+			<generator class="increment"/>
+		</id>
+		<property name="name" not-null="true" column="NAME"/>
+		<loader query-ref="person"/>
+		<sql-insert>INSERT INTO PERSON (NAME, PERID) VALUES ( UPPER(?), ? )</sql-insert>
+		<sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE PERID=?</sql-update>
+		<sql-delete>DELETE FROM PERSON WHERE PERID=?</sql-delete>
+	</class>
+	
+	<class name="Employment" table="EMPLOYMENT">
+		<id name="employmentId" unsaved-value="0" column="EMPID">
+			<generator class="increment"/>
+		</id>
+		<many-to-one name="employee" column="EMPLOYEE" not-null="true" update="false"/>
+		<many-to-one name="employer" column="EMPLOYER" not-null="true" update="false"/>
+		<property name="startDate" column="STARTDATE" not-null="true" update="false" insert="false"/>
+		<property name="endDate" column="ENDDATE" insert="false"/>
+		<property name="regionCode" column="REGIONCODE" update="false"/>
+        <property name="salary" type="org.hibernate.test.sql.hand.MonetaryAmountUserType">
+			<column name="VALUE" sql-type="float"/>
+			<column name="CURRENCY"/>			
+		</property>
+		<loader query-ref="employment"/>
+   		<sql-insert>
+			INSERT INTO EMPLOYMENT 
+				(EMPLOYEE, EMPLOYER, STARTDATE, REGIONCODE, VALUE, CURRENCY, EMPID) 
+				VALUES (?, ?, getdate(), UPPER(?), ?, ?, ?)
+		</sql-insert>
+		<sql-update>UPDATE EMPLOYMENT SET ENDDATE=?, VALUE=?, CURRENCY=? WHERE EMPID=?</sql-update> 
+		<sql-delete>DELETE FROM EMPLOYMENT WHERE EMPID=?</sql-delete> 
+	</class>
+
+    <resultset name="org-emp-regionCode">
+        <return-scalar column="regionCode" type="string"/>
+        <return alias="org" class="Organization"/>
+        <return-join alias="emp" property="org.employments"/>
+    </resultset>
+
+    <resultset name="org-emp-person">
+        <return alias="org" class="Organization"/>
+        <return-join alias="emp" property="org.employments"/>
+        <return-join alias="pers" property="emp.employee"/>
+    </resultset>
+	
+	<sql-query name="person">
+		<return alias="p" class="Person" lock-mode="upgrade"/>
+		SELECT NAME AS {p.name}, PERID AS {p.id} FROM PERSON WHERE PERID=? /*FOR UPDATE*/
+	</sql-query>
+
+	<sql-query name="organization">
+		<return alias="org" class="Organization"/>
+		<return-join alias="emp" property="org.employments"/>
+		SELECT {org.*}, {emp.*}
+		FROM ORGANIZATION org
+			LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER
+		WHERE org.ORGID=?
+	</sql-query>
+
+
+	<!--sql-query name="organization">
+		<return alias="org" class="Organization"/>
+		SELECT NAME AS {org.name}, ORGID AS {org.id} FROM ORGANIZATION
+		WHERE ORGID=?
+	</sql-query-->
+	
+	<sql-query name="allOrganizationsWithEmployees" flush-mode="never">
+		<return alias="org" class="Organization"/>
+		SELECT DISTINCT org.NAME AS {org.name}, org.ORGID AS {org.id} 
+		FROM ORGANIZATION org
+		INNER JOIN EMPLOYMENT e ON e.EMPLOYER = org.ORGID
+	</sql-query>
+	
+	
+	
+
+	
+	<sql-query name="employment">
+		<return alias="emp" class="Employment"/>
+		SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer}, 
+			STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+			REGIONCODE as {emp.regionCode}, EMPID AS {emp.id}
+		FROM EMPLOYMENT
+		WHERE EMPID = ?
+	</sql-query>
+
+	<sql-query name="organizationEmployments">
+		<load-collection alias="empcol" role="Organization.employments"/>
+		SELECT {empcol.*}
+		FROM EMPLOYMENT empcol
+		WHERE EMPLOYER = :id
+		ORDER BY STARTDATE ASC, EMPLOYEE ASC
+	</sql-query>
+
+
+	<sql-query name="organizationCurrentEmployments">
+		<return alias="emp" class="Employment">		    
+			<return-property name="salary"> 
+		      <!-- as multi column properties are not supported via the
+		      {}-syntax, we need to provide an explicit column list for salary via <return-property> -->
+  			  <return-column name="VALUE"/>
+			  <return-column name="CURRENCY"/>			
+			</return-property>
+			<!-- Here we are remapping endDate. Notice that we can still use {emp.endDate} in the SQL. -->
+			<return-property name="endDate" column="myEndDate"/>
+		</return>
+		<synchronize table="EMPLOYMENT"/>
+		SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer}, 
+			STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+			REGIONCODE as {emp.regionCode}, EMPID AS {emp.id}, VALUE, CURRENCY
+		FROM EMPLOYMENT
+		WHERE EMPLOYER = :id AND ENDDATE IS NULL
+		ORDER BY STARTDATE ASC
+	</sql-query>
+
+	<sql-query name="simpleScalar" callable="true">
+		<return-scalar column="name" type="string"/>
+		<return-scalar column="value" type="long"/>
+		{ call simpleScalar(:number) }
+	</sql-query>
+
+	<sql-query name="paramhandling" callable="true">
+		<return-scalar column="value" type="long"/>
+		<return-scalar column="value2" type="long"/>
+		{ call paramHandling(?,?) }
+	</sql-query>
+
+	<sql-query name="paramhandling_mixed" callable="true">
+		<return-scalar column="value" type="long" />
+		<return-scalar column="value2" type="long" />
+		{ call paramHandling(?,:second) }
+	</sql-query>
+	
+	<sql-query name="selectAllEmployments" callable="true">
+		<return alias="" class="Employment">
+			<return-property name="employee" column="EMPLOYEE"/>
+			<return-property name="employer" column="EMPLOYER"/>			
+			<return-property name="startDate" column="STARTDATE"/>
+			<return-property name="endDate" column="ENDDATE"/>			
+			<return-property name="regionCode" column="REGIONCODE"/>			
+			<return-property name="id" column="EMPID"/>						
+			<return-property name="salary"> 
+				<!-- as multi column properties are not supported via the
+				{}-syntax, we need to provide an explicit column list for salary via <return-property> -->
+				<return-column name="VALUE"/>
+				<return-column name="CURRENCY"/>			
+			</return-property>
+		</return>
+		{ call selectAllEmployments() }
+	</sql-query>
+	
+	<database-object>
+		<create>
+		CREATE PROCEDURE selectAllEmployments AS
+			SELECT EMPLOYEE, EMPLOYER, STARTDATE, ENDDATE, 
+			REGIONCODE, EMPID, VALUE, CURRENCY
+			FROM EMPLOYMENT
+		</create>
+		<drop>
+		DROP PROCEDURE selectAllEmployments
+		</drop>
+	</database-object>
+	
+	<database-object>
+		<create>
+		CREATE PROCEDURE paramHandling @j int, @i int AS
+			SELECT @j as value, @i as value2
+		</create>
+		<drop>
+		DROP PROCEDURE paramHandling
+		</drop>
+	</database-object>
+	
+	<database-object>
+		<create>
+		CREATE PROCEDURE simpleScalar @number int AS
+			SELECT @number as value, 'getAll' as name
+		</create>
+		<drop>
+		DROP PROCEDURE simpleScalar
+		</drop>
+	</database-object>
+	
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/sybase/Mappings.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/sybase/SybaseCustomSQLTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/sybase/SybaseCustomSQLTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/custom/sybase/SybaseCustomSQLTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+//$Id$
+package org.hibernate.test.sql.hand.custom.sybase;
+
+import junit.framework.Test;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.SybaseDialect;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.sql.hand.custom.CustomStoredProcTestSupport;
+
+/**
+ * Custom SQL tests for Sybase/SQLServer (Transact-SQL)
+ * 
+ * @author Gavin King
+ */
+public class SybaseCustomSQLTest extends CustomStoredProcTestSupport {
+
+	public SybaseCustomSQLTest(String str) {
+		super( str );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "sql/hand/custom/sybase/Mappings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SybaseCustomSQLTest.class );
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		return ( dialect instanceof SybaseDialect );
+	}
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/identity/CustomInsertSQLWithIdentityColumnTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/identity/CustomInsertSQLWithIdentityColumnTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/identity/CustomInsertSQLWithIdentityColumnTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,50 @@
+package org.hibernate.test.sql.hand.identity;
+
+import junit.framework.Test;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.Session;
+import org.hibernate.JDBCException;
+import org.hibernate.test.sql.hand.Organization;
+
+/**
+ * Custom SQL tests for combined usage of custom insert SQL and identity columns
+ *
+ * @author Gail Badner
+ */
+public class CustomInsertSQLWithIdentityColumnTest extends DatabaseSpecificFunctionalTestCase {
+
+	public CustomInsertSQLWithIdentityColumnTest(String str) {
+		super( str );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CustomInsertSQLWithIdentityColumnTest.class );
+	}
+
+	public String[] getMappings() {
+		return new String[] {"sql/hand/identity/Mappings.hbm.xml"};
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		return dialect.supportsIdentityColumns();
+	}
+
+	public void testBadInsertionFails() {
+		Session session = openSession();
+		session.beginTransaction();
+		Organization org = new Organization( "hola!" );
+		try {
+			session.save( org );
+			session.delete( org );
+			fail( "expecting bad custom insert statement to fail" );
+		}
+		catch( JDBCException e ) {
+			// expected failure
+		}
+
+		session.getTransaction().rollback();
+		session.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/identity/Mappings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/identity/Mappings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/identity/Mappings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    This mapping demonstrates the combined use of IDENTITY PK columns and
+    custom supplied SQL statements.
+
+    @author : Gail Badner
+-->
+
+<hibernate-mapping package="org.hibernate.test.sql.hand" default-access="field">
+
+	<class name="Organization" table="ORGANIZATION">
+		<id name="id" column="ORG_ID">
+			<generator class="identity"/>
+		</id>
+		<property name="name" not-null="true"/>
+        <!-- Intentionally bad SQL statement!!! -->
+        <sql-insert>INSERT INTO PERSON WHERE x=y</sql-insert>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/query/NativeSQLQueries.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/query/NativeSQLQueries.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/query/NativeSQLQueries.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,262 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+  This mapping demonstrates the use of Hibernate with
+  all-handwritten SQL!
+-->
+
+<hibernate-mapping package="org.hibernate.test.sql.hand" default-access="field">
+	   
+	<class name="Organization" table="ORGANIZATION">
+		<id name="id" unsaved-value="0" column="ORGID">
+			<generator class="increment"/>
+		</id>
+		<property name="name" column="NAME" not-null="true"/>
+		<set lazy="true" name="employments" 
+			inverse="true">
+			<key column="EMPLOYER"/> <!-- only needed for DDL generation -->
+			<one-to-many class="Employment"/>
+		</set>
+	</class>
+	
+	<class name="Person" table="PERSON">
+		<id name="id" unsaved-value="0" column="PERID">
+			<generator class="increment"/>
+		</id>
+		<property name="name" column="NAME" not-null="true"/>
+		
+	</class>
+	
+	<class name="Employment" table="EMPLOYMENT">
+		<id name="employmentId" unsaved-value="0" column="EMPID">
+			<generator class="increment"/>
+		</id>
+		<many-to-one name="employee" column="EMPLOYEE" not-null="true" update="false"/>
+		<many-to-one name="employer" column="EMPLOYER" not-null="true" update="false"/>
+		<property name="startDate" column="STARTDATE" not-null="false"/>
+		<property name="endDate" column="ENDDATE" insert="false"/>
+		<property name="regionCode" column="REGIONCODE" update="false"/>
+	    <property name="salary" type="org.hibernate.test.sql.hand.MonetaryAmountUserType">
+			<column name="VALUE" sql-type="float"/>
+			<column name="CURRENCY"/>			
+		</property>
+	</class>
+	
+	<class name="Order" table="TBL_ORDER">
+	  <composite-id name="orderId" class="Order$OrderId">
+	  	<key-property name="orgid"/>
+		<key-property name="ordernumber"/>
+	  </composite-id>
+	  
+	  <many-to-one name="product">
+	    <column name="PROD_ORGID"/>
+	    <column name="PROD_NO"/>
+	  </many-to-one>
+	  <many-to-one name="person"/>
+	</class>
+	
+	<class name="Product">
+	  <composite-id name="productId" class="Product$ProductId">
+	  	<key-property name="orgid"/>
+		<key-property name="productnumber"/>
+	  </composite-id>
+	  
+	  <property name="name"/>
+	  
+	  <set name="orders" inverse="true">
+	  	<key>
+	  		<column name="PROD_ORGID"/>
+	  		<column name="PROD_NO"/>	  		
+	  	</key>
+	  	<one-to-many class="Order"/>
+	  </set>
+	</class>
+
+    <class name="Dimension">
+        <id name="id" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="length" column="d_len"/>
+        <property name="width" column="d_width"/>
+    </class>
+
+    <class name="SpaceShip">
+        <id name="id" type="integer">
+            <generator class="increment"/>
+        </id>
+        <property name="name" column="fld_name"/>
+        <property name="model" column="fld_model"/>
+        <property name="speed" column="fld_speed"/>
+        <component name="dimensions">
+            <property name="length" column="fld_length"/>
+            <property name="width" column="fld_width"/>
+        </component>
+    </class>
+
+    <class name="Speech">
+        <id name="id" type="integer">
+            <generator class="increment"/>
+        </id>
+        <property name="name" column="name"/>
+        <property name="length" column="flength"/>
+    </class>
+
+    <resultset name="org-emp-regionCode">
+        <return-scalar column="regionCode" type="string"/>
+        <return alias="org" class="Organization"/>
+        <return-join alias="emp" property="org.employments"/>
+    </resultset>
+
+    <resultset name="org-emp-person">
+        <return alias="org" class="Organization"/>
+        <return-join alias="emp" property="org.employments"/>
+        <return-join alias="pers" property="emp.employee"/>
+    </resultset>
+
+
+    <resultset name="org-description">
+        <return alias="org" class="Organization"/>
+        <return-join alias="emp" property="org.employments"/>
+    </resultset>
+
+    <resultset name="spaceship-vol">
+        <return alias="sps" class="SpaceShip">
+            <return-property name="id" column="id"/>
+            <return-property name="name" column="name"/>
+            <return-property name="model" column="model"/>
+            <return-property name="speed" column="speed"/>
+            <return-property name="dimensions.length" column="length"/>
+            <return-property name="dimensions.width" column="width"/>
+        </return>
+        <return-scalar column="surface"/>
+        <return-scalar column="volume"/>
+    </resultset>
+
+    <resultset name="speech">
+        <return alias="sp" class="Speech">
+            <return-property name="id" column="id"/>
+            <return-property name="name" column="name"/>
+            <return-property name="length" column="flength"/>
+        </return>
+        <return-scalar column="scalarName"/>
+    </resultset>
+
+    <sql-query name="spaceship" resultset-ref="spaceship-vol">
+		select id as id,
+               fld_name as name,
+               fld_model as model,
+               fld_speed as speed,
+               fld_length as length,
+               fld_width as width,
+               fld_length * fld_width as surface,
+               fld_length * fld_width *10 as volume
+        from SpaceShip
+	</sql-query>
+
+    <sql-query name="orgNamesOnly">
+		<return-scalar column="NAME" type="string"/>
+		SELECT org.NAME FROM ORGANIZATION org
+	</sql-query>
+
+	<sql-query name="orgNamesAndOrgs">
+		<return-scalar column="thename" type="string"/>
+		<return alias="org" class="Organization"/>
+		SELECT org.NAME AS thename, org.NAME AS {org.name}, org.ORGID AS {org.id} 
+		FROM ORGANIZATION org
+		ORDER BY thename
+	</sql-query>
+
+	<sql-query name="orgsAndOrgNames">
+		<return alias="org" class="Organization"/>
+		<return-scalar column="thename" type="string"/>
+		SELECT org.NAME AS thename, org.NAME AS {org.name}, org.ORGID AS {org.id} 
+		FROM ORGANIZATION org
+		ORDER BY thename
+	</sql-query>	
+
+	<sql-query name="orgIdsAndOrgNames">
+		<return-scalar column="orgid" type="long"/>
+		<return-scalar column="thename" type="string"/>
+		SELECT NAME AS thename, ORGID AS orgid
+		FROM ORGANIZATION
+		ORDER BY thename
+	</sql-query>
+
+	<sql-query name="AllEmploymentAsMapped">
+		<return class="Employment"/>
+		SELECT * FROM EMPLOYMENT
+	</sql-query>
+
+	<sql-query name="EmploymentAndPerson">
+		<return class="Employment"/>
+		<return class="Person"/>
+		SELECT * FROM EMPLOYMENT, PERSON
+	</sql-query>
+
+	<sql-query name="organizationEmploymentsExplicitAliases">
+		<load-collection alias="empcol" role="Organization.employments"/>
+		SELECT empcol.EMPLOYER as {empcol.key}, empcol.EMPID as {empcol.element}, {empcol.element.*} 
+		FROM EMPLOYMENT empcol
+		WHERE EMPLOYER = :id
+		ORDER BY STARTDATE ASC, EMPLOYEE ASC
+	</sql-query>	
+
+	<sql-query name="organizationreturnproperty">
+		<return alias="org" class="Organization">
+            <return-property name="id" column="ORGID"/>
+            <return-property name="name" column="NAME"/>
+		</return>
+		<return-join alias="emp" property="org.employments">
+			<return-property name="key" column="EMPLOYER"/>
+			<return-property name="element" column="EMPID"/>			
+			<return-property name="element.employee" column="EMPLOYEE"/>
+			<return-property name="element.employer" column="EMPLOYER"/>			
+			<return-property name="element.startDate" column="XSTARTDATE"/>
+			<return-property name="element.endDate" column="ENDDATE"/>			
+			<return-property name="element.regionCode" column="REGIONCODE"/>			
+			<return-property name="element.employmentId" column="EMPID"/>						
+			<return-property name="element.salary">
+                <return-column name="VALUE"/>
+                <return-column name="CURRENCY"/>
+			</return-property>
+		</return-join>
+		SELECT org.ORGID as orgid,
+            org.NAME as name,
+            emp.EMPLOYER as employer,
+            emp.EMPID as empid,
+            emp.EMPLOYEE as employee,
+            emp.EMPLOYER as employer,
+            emp.STARTDATE as xstartDate,
+            emp.ENDDATE as endDate,
+            emp.REGIONCODE as regionCode,
+            emp.VALUE as VALUE,
+            emp.CURRENCY as CURRENCY
+        FROM ORGANIZATION org
+			LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER
+	</sql-query>
+
+    
+	<sql-query name="organizationautodetect" resultset-ref="org-description">
+	<!--  equal to "organizationpropertyreturn" but since no {} nor return-property are used hibernate will fallback to use the columns directly from the mapping -->
+		<return alias="org" class="Organization"/>
+		<return-join alias="emp" property="org.employments"/>
+        SELECT org.ORGID as orgid,
+            org.NAME as name,
+            emp.EMPLOYER as employer,
+            emp.EMPID as empid,
+            emp.EMPLOYEE as employee,
+            emp.EMPLOYER as employer,
+            emp.STARTDATE as startDate,
+            emp.ENDDATE as endDate,
+            emp.REGIONCODE as regionCode,
+            emp.VALUE as VALUE,
+            emp.CURRENCY as CURRENCY
+		FROM ORGANIZATION org
+			LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER
+	</sql-query>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/query/NativeSQLQueriesTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/query/NativeSQLQueriesTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/sql/hand/query/NativeSQLQueriesTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,618 @@
+package org.hibernate.test.sql.hand.query;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.test.sql.hand.Organization;
+import org.hibernate.test.sql.hand.Person;
+import org.hibernate.test.sql.hand.Employment;
+import org.hibernate.test.sql.hand.Product;
+import org.hibernate.test.sql.hand.Order;
+import org.hibernate.test.sql.hand.Dimension;
+import org.hibernate.test.sql.hand.SpaceShip;
+import org.hibernate.test.sql.hand.Speech;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.transform.DistinctRootEntityResultTransformer;
+import org.hibernate.transform.Transformers;
+import org.hibernate.transform.AliasToEntityMapResultTransformer;
+
+/**
+ * Tests of various features of native SQL queries.
+ *
+ * @author Steve Ebersole
+ */
+public class NativeSQLQueriesTest extends FunctionalTestCase {
+
+	public NativeSQLQueriesTest(String x) {
+		super( x );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "sql/hand/query/NativeSQLQueries.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( NativeSQLQueriesTest.class );
+	}
+
+	protected String getOrganizationFetchJoinEmploymentSQL() {
+		return "SELECT org.ORGID as {org.id}, " +
+		       "        org.NAME as {org.name}, " +
+		       "        emp.EMPLOYER as {emp.key}, " +
+		       "        emp.EMPID as {emp.element}, " +
+		       "        {emp.element.*}  " +
+		       "FROM ORGANIZATION org " +
+		       "    LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER";
+	}
+
+	protected String getOrganizationJoinEmploymentSQL() {
+		return "SELECT org.ORGID as {org.id}, " +
+		       "        org.NAME as {org.name}, " +
+		       "        {emp.*}  " +
+		       "FROM ORGANIZATION org " +
+		       "    LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER";
+	}
+
+	protected String getEmploymentSQL() {
+		return "SELECT * FROM EMPLOYMENT";
+	}
+
+	protected String getEmploymentSQLMixedScalarEntity() {
+		return "SELECT e.*, e.employer as employerid  FROM EMPLOYMENT e" ;
+	}
+
+	protected String getOrgEmpRegionSQL() {
+		return "select {org.*}, {emp.*}, emp.REGIONCODE " +
+		       "from ORGANIZATION org " +
+		       "     left outer join EMPLOYMENT emp on org.ORGID = emp.EMPLOYER";
+	}
+
+	protected String getOrgEmpPersonSQL() {
+		return "select {org.*}, {emp.*}, {pers.*} " +
+		       "from ORGANIZATION org " +
+		       "    join EMPLOYMENT emp on org.ORGID = emp.EMPLOYER " +
+		       "    join PERSON pers on pers.PERID = emp.EMPLOYEE ";
+	}
+
+	public void testFailOnNoAddEntityOrScalar() {
+		// Note: this passes, but for the wrong reason.
+		//      there is actually an exception thrown, but it is the database
+		//      throwing a sql exception because the SQL gets passed
+		//      "un-processed"...
+		Session s = openSession();
+		try {
+			String sql = "select {org.*} " +
+			             "from organization org";
+			s.createSQLQuery( sql ).list();
+			fail( "Should throw an exception since no addEntity nor addScalar has been performed." );
+		}
+		catch( HibernateException he) {
+			// expected behavior
+		}
+		finally {
+			s.close();
+		}
+	}
+
+	public void testManualSynchronization() {
+		Session s = openSession();
+		s.beginTransaction();
+
+		sfi().getStatistics().clear();
+
+		// create an Organization...
+		Organization jboss = new Organization( "JBoss" );
+		s.persist( jboss );
+
+		// now query on Employment, this should not cause an auto-flush
+		s.createSQLQuery( getEmploymentSQL() ).list();
+		assertEquals( 0, sfi().getStatistics().getEntityInsertCount() );
+
+		// now try to query on Employment but this time add Organization as a synchronized query space...
+		s.createSQLQuery( getEmploymentSQL() ).addSynchronizedEntityClass( Organization.class ).list();
+		assertEquals( 1, sfi().getStatistics().getEntityInsertCount() );
+
+		// clean up
+		s.delete( jboss );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testSQLQueryInterface() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Organization ifa = new Organization("IFA");
+		Organization jboss = new Organization("JBoss");
+		Person gavin = new Person("Gavin");
+		Employment emp = new Employment(gavin, jboss, "AU");
+
+		s.persist(ifa);
+		s.persist(jboss);
+		s.persist(gavin);
+		s.persist(emp);
+
+		List l = s.createSQLQuery( getOrgEmpRegionSQL() )
+				.addEntity("org", Organization.class)
+				.addJoin("emp", "org.employments")
+				.addScalar("regionCode", Hibernate.STRING)
+				.list();
+		assertEquals( 2, l.size() );
+
+		l = s.createSQLQuery( getOrgEmpPersonSQL() )
+				.addEntity("org", Organization.class)
+				.addJoin("emp", "org.employments")
+				.addJoin("pers", "emp.employee")
+				.list();
+		assertEquals( l.size(), 1 );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+
+		l = s.createSQLQuery( "select {org.*}, {emp.*} " +
+			       "from ORGANIZATION org " +
+			       "     left outer join EMPLOYMENT emp on org.ORGID = emp.EMPLOYER, ORGANIZATION org2" )
+		.addEntity("org", Organization.class)
+		.addJoin("emp", "org.employments")
+		.setResultTransformer(new DistinctRootEntityResultTransformer())
+		.list();
+		assertEquals( l.size(), 2 );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+
+		s.delete(emp);
+		s.delete(gavin);
+		s.delete(ifa);
+		s.delete(jboss);
+
+		t.commit();
+		s.close();
+	}
+
+	public void testResultSetMappingDefinition() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Organization ifa = new Organization("IFA");
+		Organization jboss = new Organization("JBoss");
+		Person gavin = new Person("Gavin");
+		Employment emp = new Employment(gavin, jboss, "AU");
+
+		s.persist(ifa);
+		s.persist(jboss);
+		s.persist(gavin);
+		s.persist(emp);
+
+		List l = s.createSQLQuery( getOrgEmpRegionSQL() )
+				.setResultSetMapping( "org-emp-regionCode" )
+				.list();
+		assertEquals( l.size(), 2 );
+
+		l = s.createSQLQuery( getOrgEmpPersonSQL() )
+				.setResultSetMapping( "org-emp-person" )
+				.list();
+		assertEquals( l.size(), 1 );
+
+		s.delete(emp);
+		s.delete(gavin);
+		s.delete(ifa);
+		s.delete(jboss);
+
+		t.commit();
+		s.close();
+	}
+
+	public void testScalarValues() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Organization ifa = new Organization( "IFA" );
+		Organization jboss = new Organization( "JBoss" );
+
+		Serializable idIfa = s.save( ifa );
+		Serializable idJBoss = s.save( jboss );
+
+		s.flush();
+
+		List result = s.getNamedQuery( "orgNamesOnly" ).list();
+		assertTrue( result.contains( "IFA" ) );
+		assertTrue( result.contains( "JBoss" ) );
+
+		result = s.getNamedQuery( "orgNamesOnly" ).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
+		Map m = (Map) result.get(0);
+		assertEquals( 2, result.size() );
+		assertEquals( 1, m.size() );
+		assertTrue( m.containsKey("NAME") );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+
+		Iterator iter = s.getNamedQuery( "orgNamesAndOrgs" ).list().iterator();
+		Object[] o = ( Object[] ) iter.next();
+		assertEquals( o[0], "IFA" );
+		assertEquals( ( ( Organization ) o[1] ).getName(), "IFA" );
+		o = ( Object[] ) iter.next();
+		assertEquals( o[0], "JBoss" );
+		assertEquals( ( ( Organization ) o[1] ).getName(), "JBoss" );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+
+		// test that the ordering of the results is truly based on the order in which they were defined
+		iter = s.getNamedQuery( "orgsAndOrgNames" ).list().iterator();
+		Object[] row = ( Object[] ) iter.next();
+		assertEquals( "expecting non-scalar result first", Organization.class, row[0].getClass() );
+		assertEquals( "expecting scalar result second", String.class, row[1].getClass() );
+		assertEquals( ( ( Organization ) row[0] ).getName(), "IFA" );
+		assertEquals( row[1], "IFA" );
+		row = ( Object[] ) iter.next();
+		assertEquals( "expecting non-scalar result first", Organization.class, row[0].getClass() );
+		assertEquals( "expecting scalar result second", String.class, row[1].getClass() );
+		assertEquals( ( ( Organization ) row[0] ).getName(), "JBoss" );
+		assertEquals( row[1], "JBoss" );
+		assertFalse( iter.hasNext() );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+
+		iter = s.getNamedQuery( "orgIdsAndOrgNames" ).list().iterator();
+		o = ( Object[] ) iter.next();
+		assertEquals( o[1], "IFA" );
+		assertEquals( o[0], idIfa );
+		o = ( Object[] ) iter.next();
+		assertEquals( o[1], "JBoss" );
+		assertEquals( o[0], idJBoss );
+
+		s.delete( ifa );
+		s.delete( jboss );
+		t.commit();
+		s.close();
+	}
+
+	public void testMappedAliasStrategy() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Organization ifa = new Organization("IFA");
+		Organization jboss = new Organization("JBoss");
+		Person gavin = new Person("Gavin");
+		Employment emp = new Employment(gavin, jboss, "AU");
+		Serializable orgId = s.save(jboss);
+		Serializable orgId2 = s.save(ifa);
+		s.save(gavin);
+		s.save(emp);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Query namedQuery = s.getNamedQuery("AllEmploymentAsMapped");
+		List list = namedQuery.list();
+		assertEquals(1,list.size());
+		Employment emp2 = (Employment) list.get(0);
+		assertEquals(emp2.getEmploymentId(), emp.getEmploymentId() );
+		assertEquals(emp2.getStartDate().getDate(), emp.getStartDate().getDate() );
+		assertEquals(emp2.getEndDate(), emp.getEndDate() );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Query sqlQuery = s.getNamedQuery("EmploymentAndPerson");
+		sqlQuery.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
+		list = sqlQuery.list();
+		assertEquals(1,list.size() );
+		Object res = list.get(0);
+		assertClassAssignability(res.getClass(),Map.class);
+		Map m = (Map) res;
+		assertEquals(2,m.size());
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		sqlQuery = s.getNamedQuery("organizationreturnproperty");
+		sqlQuery.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
+		list = sqlQuery.list();
+		assertEquals(2,list.size() );
+		m = (Map) list.get(0);
+		assertTrue(m.containsKey("org"));
+		assertClassAssignability(m.get("org").getClass(), Organization.class);
+		assertTrue(m.containsKey("emp"));
+		assertClassAssignability(m.get("emp").getClass(), Employment.class);
+		assertEquals(2, m.size());
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		namedQuery = s.getNamedQuery("EmploymentAndPerson");
+		list = namedQuery.list();
+		assertEquals(1,list.size() );
+		Object[] objs = (Object[]) list.get(0);
+		assertEquals(2, objs.length);
+		emp2 = (Employment) objs[0];
+		gavin = (Person) objs[1];
+		s.delete(emp2);
+		s.delete(jboss);
+		s.delete(gavin);
+		s.delete(ifa);
+		t.commit();
+		s.close();
+	}
+
+	/* test for native sql composite id joins which has never been implemented */
+	public void testCompositeIdJoinsFailureExpected() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person person = new Person();
+		person.setName( "Noob" );
+
+		Product product = new Product();
+		product.setProductId( new Product.ProductId() );
+		product.getProductId().setOrgid( "x" );
+		product.getProductId().setProductnumber( "1234" );
+		product.setName( "Hibernate 3" );
+
+		Order order = new Order();
+		order.setOrderId( new Order.OrderId() );
+		order.getOrderId().setOrdernumber( "1" );
+		order.getOrderId().setOrgid( "y" );
+
+		product.getOrders().add( order );
+		order.setProduct( product );
+		order.setPerson( person );
+
+		s.save( product );
+		s.save( order);
+		s.save( person );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Product p = (Product) s.createQuery( "from Product p join fetch p.orders" ).list().get(0);
+		assertTrue(Hibernate.isInitialized( p.getOrders()));
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Object[] o =  (Object[]) s.createSQLQuery( "select\r\n" +
+				"        product.orgid as {product.id.orgid}," +
+				"        product.productnumber as {product.id.productnumber}," +
+				"        {prod_orders}.orgid as orgid3_1_,\r\n" +
+				"        {prod_orders}.ordernumber as ordernum2_3_1_,\r\n" +
+				"        product.name as {product.name}," +
+				"        {prod_orders.element.*}" +
+				/*"        orders.PROD_NO as PROD4_3_1_,\r\n" +
+				"        orders.person as person3_1_,\r\n" +
+				"        orders.PROD_ORGID as PROD3_0__,\r\n" +
+				"        orders.PROD_NO as PROD4_0__,\r\n" +
+				"        orders.orgid as orgid0__,\r\n" +
+				"        orders.ordernumber as ordernum2_0__ \r\n" +*/
+				"    from\r\n" +
+				"        Product product \r\n" +
+				"    inner join\r\n" +
+				"        TBL_ORDER {prod_orders} \r\n" +
+				"            on product.orgid={prod_orders}.PROD_ORGID \r\n" +
+				"            and product.productnumber={prod_orders}.PROD_NO" )
+				.addEntity( "product", Product.class )
+				.addJoin( "prod_orders", "product.orders" )
+				.list().get(0);
+
+		p = (Product) o[0];
+		assertTrue(Hibernate.isInitialized( p.getOrders() ));
+		assertNotNull(p.getOrders().iterator().next());
+		t.commit();
+		s.close();
+	}
+
+	public void testAutoDetectAliasing() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Organization ifa = new Organization("IFA");
+		Organization jboss = new Organization("JBoss");
+		Person gavin = new Person("Gavin");
+		Employment emp = new Employment(gavin, jboss, "AU");
+		Serializable orgId = s.save(jboss);
+		Serializable orgId2 = s.save(ifa);
+		s.save(gavin);
+		s.save(emp);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		List list = s.createSQLQuery( getEmploymentSQL() )
+				.addEntity( Employment.class.getName() )
+				.list();
+		assertEquals( 1,list.size() );
+
+		Employment emp2 = (Employment) list.get(0);
+		assertEquals(emp2.getEmploymentId(), emp.getEmploymentId() );
+		assertEquals(emp2.getStartDate().getDate(), emp.getStartDate().getDate() );
+		assertEquals(emp2.getEndDate(), emp.getEndDate() );
+
+		s.clear();
+
+		list = s.createSQLQuery( getEmploymentSQL() )
+		.addEntity( Employment.class.getName() )
+		.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP)
+		.list();
+		assertEquals( 1,list.size() );
+		Map m = (Map) list.get(0);
+		assertTrue(m.containsKey("Employment"));
+		assertEquals(1,m.size());
+
+		list = s.createSQLQuery(getEmploymentSQL()).list();
+		assertEquals(1, list.size());
+		Object[] o = (Object[]) list.get(0);
+		assertEquals(8, o.length);
+
+		list = s.createSQLQuery( getEmploymentSQL() ).setResultTransformer( new UpperCasedAliasToEntityMapResultTransformer() ).list();
+		assertEquals(1, list.size());
+		m = (Map) list.get(0);
+		assertTrue(m.containsKey("EMPID"));
+		assertTrue(m.containsKey("VALUE"));
+		assertTrue(m.containsKey("ENDDATE"));
+		assertEquals(8, m.size());
+
+		list = s.createSQLQuery( getEmploymentSQLMixedScalarEntity() ).addScalar( "employerid" ).addEntity( Employment.class ).list();
+		assertEquals(1, list.size());
+		o = (Object[]) list.get(0);
+		assertEquals(2, o.length);
+		assertClassAssignability( o[0].getClass(), Number.class);
+		assertClassAssignability( o[1].getClass(), Employment.class);
+
+
+
+		Query queryWithCollection = s.getNamedQuery("organizationEmploymentsExplicitAliases");
+		queryWithCollection.setLong("id",  jboss.getId() );
+		list = queryWithCollection.list();
+		assertEquals(list.size(),1);
+
+		s.clear();
+
+		list = s.createSQLQuery( getOrganizationJoinEmploymentSQL() )
+				.addEntity( "org", Organization.class )
+				.addJoin( "emp", "org.employments" )
+				.list();
+		assertEquals( 2,list.size() );
+
+		s.clear();
+
+		list = s.createSQLQuery( getOrganizationFetchJoinEmploymentSQL() )
+				.addEntity( "org", Organization.class )
+				.addJoin( "emp", "org.employments" )
+				.list();
+		assertEquals( 2,list.size() );
+
+		s.clear();
+
+		// TODO : why twice?
+		s.getNamedQuery( "organizationreturnproperty" ).list();
+		list = s.getNamedQuery( "organizationreturnproperty" ).list();
+		assertEquals( 2,list.size() );
+
+		s.clear();
+
+		list = s.getNamedQuery( "organizationautodetect" ).list();
+		assertEquals( 2,list.size() );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete(emp2);
+
+		s.delete(jboss);
+		s.delete(gavin);
+		s.delete(ifa);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Dimension dim = new Dimension( 3, Integer.MAX_VALUE );
+		s.save( dim );
+		list = s.createSQLQuery( "select d_len * d_width as surface, d_len * d_width * 10 as volume from Dimension" ).list();
+		s.delete( dim );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		SpaceShip enterprise = new SpaceShip();
+		enterprise.setModel( "USS" );
+		enterprise.setName( "Entreprise" );
+		enterprise.setSpeed( 50d );
+		Dimension d = new Dimension(45, 10);
+		enterprise.setDimensions( d );
+		s.save( enterprise );
+		Object[] result = (Object[]) s.getNamedQuery( "spaceship" ).uniqueResult();
+		enterprise = ( SpaceShip ) result[0];
+		assertTrue(50d == enterprise.getSpeed() );
+		assertTrue( 450d == extractDoubleValue( result[1] ) );
+		assertTrue( 4500d == extractDoubleValue( result[2] ) );
+		s.delete( enterprise );
+		t.commit();
+		s.close();
+
+	}
+
+	public void testMixAndMatchEntityScalar() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Speech speech = new Speech();
+		speech.setLength( new Double( 23d ) );
+		speech.setName( "Mine" );
+		s.persist( speech );
+		s.flush();
+		s.clear();
+
+		List l = s.createSQLQuery( "select name, id, flength, name as scalarName from Speech" )
+				.setResultSetMapping( "speech" )
+				.list();
+		assertEquals( l.size(), 1 );
+
+		t.rollback();
+		s.close();
+	}
+
+	private double extractDoubleValue(Object value) {
+		if ( value instanceof BigInteger ) {
+			return ( ( BigInteger ) value ).doubleValue();
+		}
+		else if ( value instanceof BigDecimal ) {
+			return ( ( BigDecimal ) value ).doubleValue();
+		}
+		else {
+			return Double.valueOf( value.toString() ).doubleValue();
+		}
+	}
+
+	private static class UpperCasedAliasToEntityMapResultTransformer extends AliasToEntityMapResultTransformer {
+		public Object transformTuple(Object[] tuple, String[] aliases) {
+			String[] ucAliases = new String[aliases.length];
+			for ( int i = 0; i < aliases.length; i++ ) {
+				ucAliases[i] = aliases[i].toUpperCase();
+			}
+			return super.transformTuple( tuple, ucAliases );
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/Document.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/Document.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/Document.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.stateless">
+
+	<class name="Document">
+		<id name="name"/>
+		<timestamp name="lastModified"/>
+		<property name="text"/>
+	</class>
+
+    <class name="Paper">
+		<id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="color"/>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/Document.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/Document.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/Document.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/Document.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,46 @@
+//$Id: Document.java 8057 2005-08-31 23:19:53Z oneovthafew $
+package org.hibernate.test.stateless;
+
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class Document {
+	
+	private String text;
+	private String name;
+	private Date lastModified;
+
+	Document() {}
+	
+	public Document(String text, String name) {
+		this.text = text;
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getText() {
+		return text;
+	}
+
+	public void setText(String text) {
+		this.text = text;
+	}
+
+	public Date getLastModified() {
+		return lastModified;
+	}
+
+	void setLastModified(Date lastModified) {
+		this.lastModified = lastModified;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/Document.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/Paper.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/Paper.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/Paper.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: Paper.java 8048 2005-08-30 21:27:17Z epbernard $
+package org.hibernate.test.stateless;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class Paper {
+	private Integer id;
+	private String color;
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getColor() {
+		return color;
+	}
+
+	public void setColor(String color) {
+		this.color = color;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/StatelessSessionTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/StatelessSessionTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/StatelessSessionTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,168 @@
+//$Id: StatelessSessionTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.stateless;
+
+import java.util.Date;
+
+import junit.framework.Test;
+
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.StatelessSession;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class StatelessSessionTest extends FunctionalTestCase {
+	
+	public StatelessSessionTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "stateless/Document.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( StatelessSessionTest.class );
+	}
+
+	public void testCreateUpdateReadDelete() {
+		StatelessSession ss = getSessions().openStatelessSession();
+		Transaction tx = ss.beginTransaction();
+		Document doc = new Document("blah blah blah", "Blahs");
+		ss.insert(doc);
+		assertNotNull( doc.getName() );
+		Date initVersion = doc.getLastModified();
+		assertNotNull( initVersion );
+		tx.commit();
+		
+		tx = ss.beginTransaction();
+		doc.setText("blah blah blah .... blah");
+		ss.update(doc);
+		assertNotNull( doc.getLastModified() );
+		assertNotSame( doc.getLastModified(), initVersion );
+		tx.commit();
+		
+		tx = ss.beginTransaction();
+		doc.setText("blah blah blah .... blah blay");
+		ss.update(doc);
+		tx.commit();
+		
+		Document doc2 = (Document) ss.get(Document.class.getName(), "Blahs");
+		assertEquals("Blahs", doc2.getName());
+		assertEquals(doc.getText(), doc2.getText());
+				
+		doc2 = (Document) ss.createQuery("from Document where text is not null").uniqueResult();
+		assertEquals("Blahs", doc2.getName());
+		assertEquals(doc.getText(), doc2.getText());
+		
+		ScrollableResults sr = ss.createQuery("from Document where text is not null")
+			.scroll(ScrollMode.FORWARD_ONLY);
+		sr.next();
+		doc2 = (Document) sr.get(0);
+		sr.close();
+		assertEquals("Blahs", doc2.getName());
+		assertEquals(doc.getText(), doc2.getText());
+				
+		doc2 = (Document) ss.createSQLQuery("select * from Document")
+			.addEntity(Document.class)
+			.uniqueResult();
+		assertEquals("Blahs", doc2.getName());
+		assertEquals(doc.getText(), doc2.getText());
+				
+		doc2 = (Document) ss.createCriteria(Document.class).uniqueResult();
+		assertEquals("Blahs", doc2.getName());
+		assertEquals(doc.getText(), doc2.getText());
+		
+		sr = ss.createCriteria(Document.class).scroll(ScrollMode.FORWARD_ONLY);
+		sr.next();
+		doc2 = (Document) sr.get(0);
+		sr.close();
+		assertEquals("Blahs", doc2.getName());
+		assertEquals(doc.getText(), doc2.getText());
+
+		tx = ss.beginTransaction();
+		ss.delete(doc);
+		tx.commit();
+		ss.close();
+
+	}
+
+	public void testHqlBulk() {
+		StatelessSession ss = getSessions().openStatelessSession();
+		Transaction tx = ss.beginTransaction();
+		Document doc = new Document("blah blah blah", "Blahs");
+		ss.insert(doc);
+		Paper paper = new Paper();
+		paper.setColor( "White" );
+		ss.insert(paper);
+		tx.commit();
+
+		tx = ss.beginTransaction();
+		int count = ss.createQuery( "update Document set name = :newName where name = :oldName" )
+				.setString( "newName", "Foos" )
+				.setString( "oldName", "Blahs" )
+				.executeUpdate();
+		assertEquals( "hql-update on stateless session", 1, count );
+		count = ss.createQuery( "update Paper set color = :newColor" )
+				.setString( "newColor", "Goldenrod" )
+				.executeUpdate();
+		assertEquals( "hql-update on stateless session", 1, count );
+		tx.commit();
+
+		tx = ss.beginTransaction();
+		count = ss.createQuery( "delete Document" ).executeUpdate();
+		assertEquals( "hql-delete on stateless session", 1, count );
+		count = ss.createQuery( "delete Paper" ).executeUpdate();
+		assertEquals( "hql-delete on stateless session", 1, count );
+		tx.commit();
+		ss.close();
+	}
+
+	public void testInitId() {
+		StatelessSession ss = getSessions().openStatelessSession();
+		Transaction tx = ss.beginTransaction();
+		Paper paper = new Paper();
+		paper.setColor( "White" );
+		ss.insert(paper);
+		assertNotNull( paper.getId() );
+		tx.commit();
+
+		tx = ss.beginTransaction();
+		ss.delete( ss.get( Paper.class, paper.getId() ) );
+		tx.commit();
+		ss.close();
+	}
+
+	public void testRefresh() {
+		StatelessSession ss = getSessions().openStatelessSession();
+		Transaction tx = ss.beginTransaction();
+		Paper paper = new Paper();
+		paper.setColor( "whtie" );
+		ss.insert( paper );
+		tx.commit();
+		ss.close();
+
+		ss = getSessions().openStatelessSession();
+		tx = ss.beginTransaction();
+		Paper p2 = ( Paper ) ss.get( Paper.class, paper.getId() );
+		p2.setColor( "White" );
+		ss.update( p2 );
+		tx.commit();
+		ss.close();
+
+		ss = getSessions().openStatelessSession();
+		tx = ss.beginTransaction();
+		assertEquals( "whtie", paper.getColor() );
+		ss.refresh( paper );
+		assertEquals( "White", paper.getColor() );
+		ss.delete( paper );
+		tx.commit();
+		ss.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stateless/StatelessSessionTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Continent.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Continent.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Continent.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.stats">
+
+    <import class="Locality"/>
+
+    <class name="Continent">
+		<id name="id">
+		 <generator class="native"/>
+		</id>
+		<property name="name"/>
+		<set name="countries">
+			<key column="country_id"/>
+			<one-to-many class="Country"/>
+		</set>
+	</class>
+	
+	<class name="Country">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="name"/>
+	</class>
+
+    <class name="State">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+        <many-to-one name="country"/>
+    </class>
+
+    <class name="Province">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+        <many-to-one name="country"/>
+    </class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Continent.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Continent.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Continent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: Continent.java 6736 2005-05-09 16:09:38Z epbernard $
+package org.hibernate.test.stats;
+
+import java.util.Set;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class Continent {
+	private Integer id;
+	private String name;
+	private Set countries;
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Set getCountries() {
+		return countries;
+	}
+
+	public void setCountries(Set countries) {
+		this.countries = countries;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Continent2.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Continent2.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Continent2.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.stats">
+
+	<class name="Continent" table="tbl_continent">
+		<id name="id">
+		 <generator class="native"/>
+		</id>
+		<property name="name"/>
+		<set name="countries">
+			<key column="country_id"/>
+			<one-to-many class="Country"/>
+		</set>
+	</class>
+	
+	<class name="Country" table="tbl_country">
+		<id name="id">
+			<generator class="native"/>
+		</id>
+		<property name="name"/>
+	</class>
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Country.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Country.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Country.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+//$Id: Country.java 6736 2005-05-09 16:09:38Z epbernard $
+package org.hibernate.test.stats;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class Country {
+	private Integer id;
+	private String name;
+
+	public boolean equals(Object o) {
+		if (this == o) return true;
+		if (!(o instanceof Country)) return false;
+
+		final Country country = (Country) o;
+
+		if (!name.equals(country.name)) return false;
+
+		return true;
+	}
+
+	public int hashCode() {
+		return name.hashCode();
+	}
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Locality.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Locality.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Locality.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,42 @@
+package org.hibernate.test.stats;
+
+/**
+ * @author Steve Ebersole
+ */
+public class Locality {
+	private Long id;
+	private String name;
+	private Country country;
+
+	public Locality() {
+	}
+
+	public Locality(String name, Country country) {
+		this.name = name;
+		this.country = country;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Country getCountry() {
+		return country;
+	}
+
+	public void setCountry(Country country) {
+		this.country = country;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Province.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Province.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/Province.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,7 @@
+package org.hibernate.test.stats;
+
+/**
+ * @author Steve Ebersole
+ */
+public class Province extends Locality {
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/SessionStatsTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/SessionStatsTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/SessionStatsTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,75 @@
+//$Id: SessionStatsTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.stats;
+
+import java.util.HashSet;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.stat.SessionStatistics;
+import org.hibernate.stat.Statistics;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class SessionStatsTest extends FunctionalTestCase {
+
+	public SessionStatsTest(String x) {
+		super(x);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "stats/Continent2.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SessionStatsTest.class );
+	}
+
+	public void testSessionStatistics() throws Exception {
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Statistics stats = getSessions().getStatistics();
+		stats.clear();
+		boolean isStats = stats.isStatisticsEnabled();
+		stats.setStatisticsEnabled(true);
+		Continent europe = fillDb(s);
+		tx.commit();
+		s.clear();
+		tx = s.beginTransaction();
+		SessionStatistics sessionStats = s.getStatistics();
+		assertEquals( 0, sessionStats.getEntityKeys().size() );
+		assertEquals( 0, sessionStats.getEntityCount() );
+		assertEquals( 0, sessionStats.getCollectionKeys().size() );
+		assertEquals( 0, sessionStats.getCollectionCount() );
+		europe = (Continent) s.get( Continent.class, europe.getId() );
+		Hibernate.initialize( europe.getCountries() );
+		Hibernate.initialize( europe.getCountries().iterator().next() );
+		assertEquals( 2, sessionStats.getEntityKeys().size() );
+		assertEquals( 2, sessionStats.getEntityCount() );
+		assertEquals( 1, sessionStats.getCollectionKeys().size() );
+		assertEquals( 1, sessionStats.getCollectionCount() );
+		tx.commit();
+		s.close();
+
+		stats.setStatisticsEnabled( isStats);
+
+	}
+
+	private Continent fillDb(Session s) {
+		Continent europe = new Continent();
+		europe.setName("Europe");
+		Country france = new Country();
+		france.setName("France");
+		europe.setCountries( new HashSet() );
+		europe.getCountries().add(france);
+		s.persist(france);
+		s.persist(europe);
+		return europe;
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/State.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/State.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/State.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,7 @@
+package org.hibernate.test.stats;
+
+/**
+ * @author Steve Ebersole
+ */
+public class State extends Locality {
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/StatsTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/StatsTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/stats/StatsTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,232 @@
+//$Id: StatsTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.stats;
+
+import java.util.HashSet;
+import java.util.Iterator;
+
+import junit.framework.Test;
+
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.mapping.Collection;
+import org.hibernate.stat.QueryStatistics;
+import org.hibernate.stat.Statistics;
+
+/**
+ * Show the difference between fetch and load
+ *
+ * @author Emmanuel Bernard
+ */
+public class StatsTest extends FunctionalTestCase {
+
+	public StatsTest(String x) {
+		super(x);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "stats/Continent.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( StatsTest.class );
+	}
+
+	public void testCollectionFetchVsLoad() throws Exception {
+		Statistics stats = getSessions().getStatistics();
+		stats.clear();
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		Continent europe = fillDb(s);
+		tx.commit();
+		s.clear();
+
+		tx = s.beginTransaction();
+		assertEquals(0, stats.getCollectionLoadCount() );
+		assertEquals(0,  stats.getCollectionFetchCount() );
+		Continent europe2 = (Continent) s.get( Continent.class, europe.getId() );
+		assertEquals("Lazy true: no collection should be loaded", 0, stats.getCollectionLoadCount() );
+		assertEquals( 0, stats.getCollectionFetchCount() );
+		europe2.getCountries().size();
+		assertEquals( 1, stats.getCollectionLoadCount() );
+		assertEquals("Explicit fetch of the collection state", 1, stats.getCollectionFetchCount() );
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		stats.clear();
+		europe = fillDb(s);
+		tx.commit();
+		s.clear();
+		tx = s.beginTransaction();
+		assertEquals( 0, stats.getCollectionLoadCount() );
+		assertEquals( 0, stats.getCollectionFetchCount() );
+		europe2 = (Continent) s.createQuery(
+				"from " + Continent.class.getName() + " a join fetch a.countries where a.id = " + europe.getId()
+			).uniqueResult();
+		assertEquals( 1, stats.getCollectionLoadCount() );
+		assertEquals( "collection should be loaded in the same query as its parent", 0, stats.getCollectionFetchCount() );
+		tx.commit();
+		s.close();
+
+		Collection coll = getCfg().getCollectionMapping(Continent.class.getName() + ".countries");
+		coll.setFetchMode(FetchMode.JOIN);
+		coll.setLazy(false);
+		SessionFactory sf = getCfg().buildSessionFactory();
+		stats = sf.getStatistics();
+		stats.clear();
+		stats.setStatisticsEnabled(true);
+		s = sf.openSession();
+		tx = s.beginTransaction();
+		europe = fillDb(s);
+		tx.commit();
+		s.clear();
+		tx = s.beginTransaction();
+		assertEquals( 0, stats.getCollectionLoadCount() );
+		assertEquals( 0, stats.getCollectionFetchCount() );
+		europe2 = (Continent) s.get( Continent.class, europe.getId() );
+		assertEquals( 1, stats.getCollectionLoadCount() );
+		assertEquals( "Should do direct load, not indirect second load when lazy false and JOIN", 0, stats.getCollectionFetchCount() );
+		tx.commit();
+		s.close();
+		sf.close();
+
+		coll = getCfg().getCollectionMapping(Continent.class.getName() + ".countries");
+		coll.setFetchMode(FetchMode.SELECT);
+		coll.setLazy(false);
+		sf = getCfg().buildSessionFactory();
+		stats = sf.getStatistics();
+		stats.clear();
+		stats.setStatisticsEnabled(true);
+		s = sf.openSession();
+		tx = s.beginTransaction();
+		europe = fillDb(s);
+		tx.commit();
+		s.clear();
+		tx = s.beginTransaction();
+		assertEquals( 0, stats.getCollectionLoadCount() );
+		assertEquals( 0, stats.getCollectionFetchCount() );
+		europe2 = (Continent) s.get( Continent.class, europe.getId() );
+		assertEquals( 1, stats.getCollectionLoadCount() );
+		assertEquals( "Should do explicit collection load, not part of the first one", 1, stats.getCollectionFetchCount() );
+		Iterator countries = europe2.getCountries().iterator();
+		while ( countries.hasNext() ) {
+			s.delete( countries.next() );
+		}
+		cleanDb( s );
+		tx.commit();
+		s.close();
+	}
+
+	public void testQueryStatGathering() {
+		Statistics stats = getSessions().getStatistics();
+		stats.clear();
+
+		Session s = openSession();
+		Transaction tx = s.beginTransaction();
+		fillDb(s);
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		final String continents = "from Continent";
+		int results = s.createQuery( continents ).list().size();
+		QueryStatistics continentStats = stats.getQueryStatistics( continents );
+		assertNotNull( "stats were null",  continentStats );
+		assertEquals( "unexpected execution count", 1, continentStats.getExecutionCount() );
+		assertEquals( "unexpected row count", results, continentStats.getExecutionRowCount() );
+		long maxTime = continentStats.getExecutionMaxTime();
+		assertEquals( maxTime, stats.getQueryExecutionMaxTime() );
+//		assertEquals( continents, stats.getQueryExecutionMaxTimeQueryString() );
+
+		Iterator itr = s.createQuery( continents ).iterate();
+		// iterate() should increment the execution count
+		assertEquals( "unexpected execution count", 2, continentStats.getExecutionCount() );
+		// but should not effect the cumulative row count
+		assertEquals( "unexpected row count", results, continentStats.getExecutionRowCount() );
+		Hibernate.close( itr );
+
+		ScrollableResults scrollableResults = s.createQuery( continents ).scroll();
+		// same deal with scroll()...
+		assertEquals( "unexpected execution count", 3, continentStats.getExecutionCount() );
+		assertEquals( "unexpected row count", results, continentStats.getExecutionRowCount() );
+		scrollableResults.close();
+		tx.commit();
+		s.close();
+
+		// explicitly check that statistics for "split queries" get collected
+		// under the original query
+		stats.clear();
+		s = openSession();
+		tx = s.beginTransaction();
+		final String localities = "from Locality";
+		results = s.createQuery( localities ).list().size();
+		QueryStatistics localityStats = stats.getQueryStatistics( localities );
+		assertNotNull( "stats were null",  localityStats );
+		// ...one for each split query
+		assertEquals( "unexpected execution count", 2, localityStats.getExecutionCount() );
+		assertEquals( "unexpected row count", results, localityStats.getExecutionRowCount() );
+		maxTime = localityStats.getExecutionMaxTime();
+		assertEquals( maxTime, stats.getQueryExecutionMaxTime() );
+//		assertEquals( localities, stats.getQueryExecutionMaxTimeQueryString() );
+		tx.commit();
+		s.close();
+		assertFalse( s.isOpen() );
+
+		// native sql queries
+		stats.clear();
+		s = openSession();
+		tx = s.beginTransaction();
+		final String sql = "select id, name from Country";
+		results = s.createSQLQuery( sql ).addEntity( Country.class ).list().size();
+		QueryStatistics sqlStats = stats.getQueryStatistics( sql );
+		assertNotNull( "sql stats were null", sqlStats );
+		assertEquals( "unexpected execution count", 1, sqlStats.getExecutionCount() );
+		assertEquals( "unexpected row count", results, sqlStats.getExecutionRowCount() );
+		maxTime = sqlStats.getExecutionMaxTime();
+		assertEquals( maxTime, stats.getQueryExecutionMaxTime() );
+//		assertEquals( sql, stats.getQueryExecutionMaxTimeQueryString() );
+		tx.commit();
+		s.close();
+
+		s = openSession();
+		tx = s.beginTransaction();
+		cleanDb( s );
+		tx.commit();
+		s.close();
+	}
+
+	private Continent fillDb(Session s) {
+		Continent europe = new Continent();
+		europe.setName("Europe");
+		Country france = new Country();
+		france.setName("France");
+		europe.setCountries( new HashSet() );
+		europe.getCountries().add(france);
+		s.persist(france);
+		s.persist(europe);
+		return europe;
+	}
+
+	private void cleanDb(Session s) {
+		s.createQuery( "delete Locality" ).executeUpdate();
+		s.createQuery( "delete Country" ).executeUpdate();
+		s.createQuery( "delete Continent" ).executeUpdate();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+// $Id: Customer.java 5899 2005-02-24 20:08:04Z steveebersole $
+package org.hibernate.test.subclassfilter;
+
+/**
+ * Implementation of Customer.
+ *
+ * @author Steve Ebersole
+ */
+public class Customer extends Person {
+	private Employee contactOwner;
+
+	public Customer() {
+	}
+
+	public Customer(String name) {
+		super( name );
+	}
+
+	public Employee getContactOwner() {
+		return contactOwner;
+	}
+
+	public void setContactOwner(Employee contactOwner) {
+		this.contactOwner = contactOwner;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/DiscrimSubclassFilterTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/DiscrimSubclassFilterTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/DiscrimSubclassFilterTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,132 @@
+// $Id: DiscrimSubclassFilterTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.subclassfilter;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Implementation of DiscrimSubclassFilterTest.
+ *
+ * @author Steve Ebersole
+ */
+public class DiscrimSubclassFilterTest extends FunctionalTestCase {
+
+	public DiscrimSubclassFilterTest(String name) {
+		super( name );
+	}
+
+	public final String[] getMappings() {
+		return new String[] { "subclassfilter/discrim-subclass.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( DiscrimSubclassFilterTest.class );
+	}
+
+	public void testFiltersWithSubclass() {
+		Session s = openSession();
+		s.enableFilter( "region" ).setParameter( "userRegion", "US" );
+		Transaction t = s.beginTransaction();
+
+		prepareTestData( s );
+		s.clear();
+
+		List results;
+		Iterator itr;
+
+		results = s.createQuery( "from Person" ).list();
+		assertEquals( "Incorrect qry result count", 4, results.size() );
+		s.clear();
+
+		results = s.createQuery( "from Employee" ).list();
+		assertEquals( "Incorrect qry result count", 2, results.size() );
+		s.clear();
+
+		results = new ArrayList( new HashSet( s.createQuery( "from Person as p left join fetch p.minions" ).list() ) );
+		assertEquals( "Incorrect qry result count", 4, results.size() );
+		itr = results.iterator();
+		while ( itr.hasNext() ) {
+			// find john
+			final Person p = ( Person ) itr.next();
+			if ( p.getName().equals( "John Doe" ) ) {
+				Employee john = ( Employee ) p;
+				assertEquals( "Incorrect fecthed minions count", 1, john.getMinions().size() );
+				break;
+			}
+		}
+		s.clear();
+
+		results = new ArrayList( new HashSet( s.createQuery( "from Employee as p left join fetch p.minions" ).list() ) );
+		assertEquals( "Incorrect qry result count", 2, results.size() );
+		itr = results.iterator();
+		while ( itr.hasNext() ) {
+			// find john
+			final Person p = ( Person ) itr.next();
+			if ( p.getName().equals( "John Doe" ) ) {
+				Employee john = ( Employee ) p;
+				assertEquals( "Incorrect fecthed minions count", 1, john.getMinions().size() );
+				break;
+			}
+		}
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery( "delete Customer where contactOwner is not null" ).executeUpdate();
+		s.createQuery( "delete Employee where manager is not null" ).executeUpdate();
+		s.createQuery( "delete Person" ).executeUpdate();
+		t.commit();
+		s.close();
+	}
+
+	private void prepareTestData(Session s) {
+		Employee john = new Employee("John Doe");
+		john.setCompany( "JBoss" );
+		john.setDepartment( "hr" );
+		john.setTitle( "hr guru" );
+		john.setRegion( "US" );
+
+		Employee polli = new Employee("Polli Wog");
+		polli.setCompany( "JBoss" );
+		polli.setDepartment( "hr" );
+		polli.setTitle( "hr novice" );
+		polli.setRegion( "US" );
+		polli.setManager( john );
+		john.getMinions().add( polli );
+
+		Employee suzie = new Employee( "Suzie Q" );
+		suzie.setCompany( "JBoss" );
+		suzie.setDepartment( "hr" );
+		suzie.setTitle( "hr novice" );
+		suzie.setRegion( "EMEA" );
+		suzie.setManager( john );
+		john.getMinions().add( suzie );
+
+		Customer cust = new Customer( "John Q Public" );
+		cust.setCompany( "Acme" );
+		cust.setRegion( "US" );
+		cust.setContactOwner( john );
+
+		Person ups = new Person( "UPS guy" );
+		ups.setCompany( "UPS" );
+		ups.setRegion( "US" );
+
+		s.save( john );
+		s.save( cust );
+		s.save( ups );
+
+		s.flush();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/Employee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/Employee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/Employee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,56 @@
+// $Id: Employee.java 5899 2005-02-24 20:08:04Z steveebersole $
+package org.hibernate.test.subclassfilter;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * Implementation of Employee.
+ *
+ * @author Steve Ebersole
+ */
+public class Employee extends Person {
+    private String title;
+	private String department;
+	private Employee manager;
+	private Set minions = new HashSet();
+
+	public Employee() {
+	}
+
+	public Employee(String name) {
+		super( name );
+	}
+
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public String getDepartment() {
+		return department;
+	}
+
+	public void setDepartment(String department) {
+		this.department = department;
+	}
+
+	public Employee getManager() {
+		return manager;
+	}
+
+	public void setManager(Employee manager) {
+		this.manager = manager;
+	}
+
+	public Set getMinions() {
+		return minions;
+	}
+
+	public void setMinions(Set minions) {
+		this.minions = minions;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/JoinedSubclassFilterTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/JoinedSubclassFilterTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/JoinedSubclassFilterTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,143 @@
+// $Id: JoinedSubclassFilterTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.subclassfilter;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Implementation of JoinedSubclassFilterTest.
+ *
+ * @author Steve Ebersole
+ */
+public class JoinedSubclassFilterTest extends FunctionalTestCase {
+
+	public JoinedSubclassFilterTest(String name) {
+		super( name );
+	}
+
+	public final String[] getMappings() {
+		return new String[] { "subclassfilter/joined-subclass.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( JoinedSubclassFilterTest.class );
+	}
+
+	public void testFiltersWithJoinedSubclass() {
+		Session s = openSession();
+		s.enableFilter( "region" ).setParameter( "userRegion", "US" );
+		Transaction t = s.beginTransaction();
+
+		prepareTestData( s );
+		s.clear();
+
+		List results = s.createQuery( "from Person" ).list();
+		assertEquals( "Incorrect qry result count", 4, results.size() );
+		s.clear();
+
+		results = s.createQuery( "from Employee" ).list();
+		assertEquals( "Incorrect qry result count", 2, results.size() );
+		Iterator itr = results.iterator();
+		while ( itr.hasNext() ) {
+			// find john
+			final Person p = ( Person ) itr.next();
+			if ( p.getName().equals( "John Doe" ) ) {
+				Employee john = ( Employee ) p;
+				assertEquals( "Incorrect fecthed minions count", 2, john.getMinions().size() );
+				break;
+			}
+		}
+		s.clear();
+
+		// TODO : currently impossible to define a collection-level filter w/ joined-subclass elements that will filter based on a superclass column and function correctly in (theta only?) outer joins;
+		// this is consistent with the behaviour of a collection-level where.
+		// this might be one argument for "pulling" the attached class-level filters into collection assocations,
+		// although we'd need some way to apply the appropriate alias in that scenario.
+		results = new ArrayList( new HashSet( s.createQuery( "from Person as p left join fetch p.minions" ).list() ) );
+		assertEquals( "Incorrect qry result count", 4, results.size() );
+		itr = results.iterator();
+		while ( itr.hasNext() ) {
+			// find john
+			final Person p = ( Person ) itr.next();
+			if ( p.getName().equals( "John Doe" ) ) {
+				Employee john = ( Employee ) p;
+				assertEquals( "Incorrect fecthed minions count", 2, john.getMinions().size() );
+				break;
+			}
+		}
+		s.clear();
+
+		results = new ArrayList( new HashSet( s.createQuery( "from Employee as p left join fetch p.minions" ).list() ) );
+		assertEquals( "Incorrect qry result count", 2, results.size() );
+		itr = results.iterator();
+		while ( itr.hasNext() ) {
+			// find john
+			final Person p = ( Person ) itr.next();
+			if ( p.getName().equals( "John Doe" ) ) {
+				Employee john = ( Employee ) p;
+				assertEquals( "Incorrect fecthed minions count", 2, john.getMinions().size() );
+				break;
+			}
+		}
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery( "delete Customer where contactOwner is not null" ).executeUpdate();
+		s.createQuery( "delete Employee where manager is not null" ).executeUpdate();
+		s.createQuery( "delete Person" ).executeUpdate();
+		t.commit();
+		s.close();
+	}
+
+	private void prepareTestData(Session s) {
+		Employee john = new Employee("John Doe");
+		john.setCompany( "JBoss" );
+		john.setDepartment( "hr" );
+		john.setTitle( "hr guru" );
+		john.setRegion( "US" );
+
+		Employee polli = new Employee("Polli Wog");
+		polli.setCompany( "JBoss" );
+		polli.setDepartment( "hr" );
+		polli.setTitle( "hr novice" );
+		polli.setRegion( "US" );
+		polli.setManager( john );
+		john.getMinions().add( polli );
+
+		Employee suzie = new Employee( "Suzie Q" );
+		suzie.setCompany( "JBoss" );
+		suzie.setDepartment( "hr" );
+		suzie.setTitle( "hr novice" );
+		suzie.setRegion( "EMEA" );
+		suzie.setManager( john );
+		john.getMinions().add( suzie );
+
+		Customer cust = new Customer( "John Q Public" );
+		cust.setCompany( "Acme" );
+		cust.setRegion( "US" );
+		cust.setContactOwner( john );
+
+		Person ups = new Person( "UPS guy" );
+		ups.setCompany( "UPS" );
+		ups.setRegion( "US" );
+
+		s.save( john );
+		s.save( cust );
+		s.save( ups );
+
+		s.flush();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+// $Id: Person.java 5899 2005-02-24 20:08:04Z steveebersole $
+package org.hibernate.test.subclassfilter;
+
+/**
+ * Implementation of Person.
+ *
+ * @author Steve Ebersole
+ */
+public class Person {
+	private Long id;
+	private String name;
+	private String company;
+	private String region;
+
+	public Person() {
+	}
+
+	public Person(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getCompany() {
+		return company;
+	}
+
+	public void setCompany(String company) {
+		this.company = company;
+	}
+
+	public String getRegion() {
+		return region;
+	}
+
+	public void setRegion(String region) {
+		this.region = region;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/UnionSubclassFilterTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/UnionSubclassFilterTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/UnionSubclassFilterTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,130 @@
+// $Id: UnionSubclassFilterTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.subclassfilter;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Implementation of DiscrimSubclassFilterTest.
+ *
+ * @author Steve Ebersole
+ */
+public class UnionSubclassFilterTest extends FunctionalTestCase {
+
+	public UnionSubclassFilterTest(String name) {
+		super( name );
+	}
+
+	public final String[] getMappings() {
+		return new String[] { "subclassfilter/union-subclass.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( UnionSubclassFilterTest.class );
+	}
+
+	public void testFiltersWithUnionSubclass() {
+		Session s = openSession();
+		s.enableFilter( "region" ).setParameter( "userRegion", "US" );
+		Transaction t = s.beginTransaction();
+
+		prepareTestData( s );
+		s.clear();
+
+		List results;
+		Iterator itr;
+
+		results = s.createQuery( "from Person" ).list();
+		assertEquals( "Incorrect qry result count", 4, results.size() );
+		s.clear();
+
+		results = s.createQuery( "from Employee" ).list();
+		assertEquals( "Incorrect qry result count", 2, results.size() );
+		s.clear();
+
+		results = new ArrayList( new HashSet( s.createQuery( "from Person as p left join fetch p.minions" ).list() ) );
+		assertEquals( "Incorrect qry result count", 4, results.size() );
+		itr = results.iterator();
+		while ( itr.hasNext() ) {
+			// find john
+			final Person p = ( Person ) itr.next();
+			if ( p.getName().equals( "John Doe" ) ) {
+				Employee john = ( Employee ) p;
+				assertEquals( "Incorrect fecthed minions count", 1, john.getMinions().size() );
+				break;
+			}
+		}
+		s.clear();
+
+		results = new ArrayList( new HashSet( s.createQuery( "from Employee as p left join fetch p.minions" ).list() ) );
+		assertEquals( "Incorrect qry result count", 2, results.size() );
+		itr = results.iterator();
+		while ( itr.hasNext() ) {
+			// find john
+			final Person p = ( Person ) itr.next();
+			if ( p.getName().equals( "John Doe" ) ) {
+				Employee john = ( Employee ) p;
+				assertEquals( "Incorrect fecthed minions count", 1, john.getMinions().size() );
+				break;
+			}
+		}
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( "from Person" );
+		t.commit();
+		s.close();
+
+	}
+
+	private void prepareTestData(Session s) {
+		Employee john = new Employee( "John Doe" );
+		john.setCompany( "JBoss" );
+		john.setDepartment( "hr" );
+		john.setTitle( "hr guru" );
+		john.setRegion( "US" );
+
+		Employee polli = new Employee( "Polli Wog" );
+		polli.setCompany( "JBoss" );
+		polli.setDepartment( "hr" );
+		polli.setTitle( "hr novice" );
+		polli.setRegion( "US" );
+		polli.setManager( john );
+		john.getMinions().add( polli );
+
+		Employee suzie = new Employee( "Suzie Q" );
+		suzie.setCompany( "JBoss" );
+		suzie.setDepartment( "hr" );
+		suzie.setTitle( "hr novice" );
+		suzie.setRegion( "EMEA" );
+		suzie.setManager( john );
+		john.getMinions().add( suzie );
+
+		Customer cust = new Customer( "John Q Public" );
+		cust.setCompany( "Acme" );
+		cust.setRegion( "US" );
+		cust.setContactOwner( john );
+
+		Person ups = new Person( "UPS guy" );
+		ups.setCompany( "UPS" );
+		ups.setRegion( "US" );
+
+		s.save( john );
+		s.save( cust );
+		s.save( ups );
+
+		s.flush();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/discrim-subclass.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/discrim-subclass.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/discrim-subclass.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.subclassfilter">
+
+	<class name="Person" discriminator-value="0" table="SPerson">
+
+		<id name="id" column="person_id">
+			<generator class="native"/>
+		</id>
+
+		<discriminator type="int"
+			formula="CASE WHEN company is null THEN 0 WHEN company = 'JBoss' THEN 1 ELSE 2 END"/>
+
+		<property name="name"/>
+		<property name="company"/>
+		<property name="region"/>
+
+		<subclass name="Employee" discriminator-value="1">
+			<property name="title"/>
+			<property name="department" column="dept"/>
+			<many-to-one name="manager" column="mgr_id" class="Employee" cascade="none"/>
+			<set name="minions" inverse="true" lazy="true" cascade="all">
+				<key column="mgr_id"/>
+				<one-to-many class="Employee"/>
+				<filter name="region" condition="region = :userRegion"/>
+			</set>
+		</subclass>
+
+		<subclass name="Customer" discriminator-value="2">
+			<many-to-one name="contactOwner" class="Employee"/>
+		</subclass>
+
+		<filter name="region" condition="region = :userRegion"/>
+
+	</class>
+
+	<filter-def name="region">
+		<filter-param name="userRegion" type="string"/>
+    </filter-def>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/joined-subclass.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/joined-subclass.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/joined-subclass.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.subclassfilter">
+
+	<class name="Person" table="JPerson">
+
+		<id name="id" column="person_id">
+			<generator class="native"/>
+		</id>
+
+		<property name="name"/>
+		<property name="company"/>
+		<property name="region"/>
+
+		<joined-subclass name="Employee" table="JEmployee">
+			<key column="person_id"/>
+
+			<property name="title"/>
+			<property name="department" column="dept"/>
+			<many-to-one name="manager" class="Employee" column="mgr_id" cascade="none"/>
+			<set name="minions" inverse="true" cascade="all" lazy="true">
+				<key column="mgr_id"/>
+				<one-to-many class="Employee"/>
+			</set>
+        </joined-subclass>
+
+		<joined-subclass name="Customer" table="JCustomer">
+			<key column="person_id"/>
+
+			<many-to-one name="contactOwner" class="Employee"/>
+		</joined-subclass>
+
+		<filter name="region" condition="region = :userRegion"/>
+	</class>
+
+	<filter-def name="region">
+		<filter-param name="userRegion" type="string"/>
+    </filter-def>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/union-subclass.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/union-subclass.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subclassfilter/union-subclass.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.subclassfilter">
+
+	<class name="Person" table="UPerson">
+
+		<id name="id" column="person_id">
+			<generator class="hilo"/>
+		</id>
+
+		<property name="name" unique="true"/>
+		<property name="company"/>
+		<property name="region"/>
+
+		<union-subclass name="Employee" table="UEmployee">
+			<property name="title"/>
+			<property name="department" column="dept"/>
+			<many-to-one name="manager" column="mgr_id" class="Employee" cascade="none"/>
+			<set name="minions" inverse="true" lazy="true" cascade="all">
+				<key column="mgr_id"/>
+				<one-to-many class="Employee"/>
+				<filter name="region" condition="region = :userRegion"/>
+			</set>
+		</union-subclass>
+
+		<union-subclass name="Customer" table="UCustomer">
+			<many-to-one name="contactOwner" class="Employee"/>
+		</union-subclass>
+
+		<filter name="region" condition="region = :userRegion"/>
+
+	</class>
+
+	<filter-def name="region">
+		<filter-param name="userRegion" type="string"/>
+    </filter-def>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Alien.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Alien.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Alien.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: Alien.java 7203 2005-06-19 02:01:05Z oneovthafew $
+package org.hibernate.test.subselect;
+
+/**
+ * @author Gavin King
+ */
+public class Alien {
+	private Long id;
+	private String identity;
+	private String planet;
+	private String species;
+	
+	public void setIdentity(String identity) {
+		this.identity = identity;
+	}
+	public String getIdentity() {
+		return identity;
+	}
+	public void setSpecies(String species) {
+		this.species = species;
+	}
+	public String getSpecies() {
+		return species;
+	}
+	public void setPlanet(String planet) {
+		this.planet = planet;
+	}
+	public String getPlanet() {
+		return planet;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public Long getId() {
+		return id;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Alien.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Being.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Being.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Being.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+//$Id: Being.java 7203 2005-06-19 02:01:05Z oneovthafew $
+package org.hibernate.test.subselect;
+
+/**
+ * @author Gavin King
+ */
+public class Being {
+	private long id;
+	private String identity;
+	private String location;
+	private String species;
+	
+	public void setLocation(String location) {
+		this.location = location;
+	}
+	public String getLocation() {
+		return location;
+	}
+	public void setSpecies(String species) {
+		this.species = species;
+	}
+	public String getSpecies() {
+		return species;
+	}
+	public void setIdentity(String identity) {
+		this.identity = identity;
+	}
+	public String getIdentity() {
+		return identity;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Being.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Beings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Beings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Beings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,83 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates 
+
+     (1) use of a class-to-subselect mapping, that allows data
+         defined in other classes to be exposed as a read-only
+         entity (you would do this if you really wanted a view,
+         but didn't or couldn't define one for some reason)
+         This is a "derived entity" mapping.
+     
+     (2) use of <synchronize/> to ensure that auto-flush happens
+         correctly, and that queries against the derived entity
+         do not return stale data
+     
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.subselect"
+	default-access="field">
+	
+	<class name="Human" table="humans">
+		
+		<id name="id" unsaved-value="0" 
+		        column="bid">
+			<generator class="hilo"/>
+		</id>
+		
+		<property name="name" 
+			not-null="true"/>
+		<property name="sex" 
+			not-null="true" 
+			update="false"/>
+		<property name="address"/>
+		
+	</class>
+	
+	<class name="Alien" table="aliens">
+		
+		<id name="id" unsaved-value="0" 
+		        column="bid">
+			<generator class="hilo"/>
+		</id>
+		
+		<property name="identity" 
+			not-null="true"
+			column="ident"/>
+		<property name="planet"/>
+		<property name="species" 
+			not-null="true" 
+			update="false"/>
+			
+	</class>
+	
+	<class name="Being" mutable="false">
+	
+		<subselect>
+			select bid, name as ident, address as loc, 'human' as species 
+			from humans 
+			union 
+			select bid, ident, planet as loc, species 
+			from aliens
+		</subselect>
+		
+		<synchronize table="humans"/>
+		<synchronize table="aliens"/>
+		
+		<id name="id" unsaved-value="0" 
+		        column="bid">
+			<generator class="native"/>
+		</id>
+		
+		<property name="identity" column="ident"/>
+		<property name="location" column="loc"/>
+		<property name="species"/>
+		
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Beings.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Human.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Human.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Human.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: Human.java 7203 2005-06-19 02:01:05Z oneovthafew $
+package org.hibernate.test.subselect;
+
+/**
+ * @author Gavin King
+ */
+public class Human {
+	private Long id;
+	private String name;
+	private char sex;
+	private String address;
+	
+	public void setAddress(String address) {
+		this.address = address;
+	}
+	public String getAddress() {
+		return address;
+	}
+	public void setSex(char sex) {
+		this.sex = sex;
+	}
+	public char getSex() {
+		return sex;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public Long getId() {
+		return id;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/Human.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/SubselectTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/SubselectTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/SubselectTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,72 @@
+//$Id: SubselectTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.subselect;
+
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class SubselectTest extends FunctionalTestCase {
+	
+	public SubselectTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "subselect/Beings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SubselectTest.class );
+	}
+	
+	public void testEntitySubselect() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Human gavin = new Human();
+		gavin.setName( "gavin" );
+		gavin.setSex( 'M' );
+		gavin.setAddress( "Melbourne, Australia" );
+		Alien x23y4 = new Alien();
+		x23y4.setIdentity( "x23y4$$hu%3" );
+		x23y4.setPlanet( "Mars" );
+		x23y4.setSpecies( "martian" );
+		s.save(gavin);
+		s.save(x23y4);
+		s.flush();
+		List beings = s.createQuery("from Being").list();
+		for ( Iterator iter = beings.iterator(); iter.hasNext(); ) {
+			Being b = (Being) iter.next();
+			assertNotNull( b.getLocation() );
+			assertNotNull( b.getIdentity() );
+			assertNotNull( b.getSpecies() );
+		}
+		s.clear();
+		getSessions().evict(Being.class);
+		Being gav = (Being) s.get(Being.class, gavin.getId());
+		assertEquals( gav.getLocation(), gavin.getAddress() );
+		assertEquals( gav.getSpecies(), "human" );
+		assertEquals( gav.getIdentity(), gavin.getName() );
+		s.clear();
+		//test the <synchronized> tag:
+		gavin = (Human) s.get(Human.class, gavin.getId());
+		gavin.setAddress( "Atlanta, GA" );
+		gav = (Being) s.createQuery("from Being b where b.location like '%GA%'").uniqueResult();
+		assertEquals( gav.getLocation(), gavin.getAddress() );
+		s.delete(gavin);
+		s.delete(x23y4);
+		assertTrue( s.createQuery("from Being").list().isEmpty() );
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselect/SubselectTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/Child.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/Child.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/Child.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,34 @@
+//$Id: Child.java 6095 2005-03-17 05:57:29Z oneovthafew $
+package org.hibernate.test.subselectfetch;
+
+import java.util.List;
+
+/**
+ * @author Gavin King
+ */
+public class Child {
+	private String name;
+	private List friends;
+
+	Child() {}
+	public Child(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+	
+	public void setName(String name) {
+		this.name = name;
+	}
+	public List getFriends() {
+		return friends;
+	}
+	
+	public void setFriends(List friends) {
+		this.friends = friends;
+	}
+	
+	
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/Child.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/Parent.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/Parent.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/Parent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: Parent.java 6095 2005-03-17 05:57:29Z oneovthafew $
+package org.hibernate.test.subselectfetch;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Gavin King
+ */
+public class Parent {
+	private String name;
+	private List children = new ArrayList();
+	private List moreChildren = new ArrayList();
+	
+	Parent() {}
+	public Parent(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+	
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public List getChildren() {
+		return children;
+	}
+
+	public void setChildren(List children) {
+		this.children = children;
+	}
+	
+	public List getMoreChildren() {
+		return moreChildren;
+	}
+	
+	public void setMoreChildren(List moreChildren) {
+		this.moreChildren = moreChildren;
+	}
+	
+	
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/Parent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/ParentChild.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/ParentChild.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/ParentChild.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.subselectfetch">
+	
+	<class name="Child">
+		<id name="name"/>
+		<bag name="friends" fetch="subselect" table="ChildChild">
+			<key column="childName1" not-null="true"/>
+			<many-to-many class="Child" column="childName2"/>
+		</bag>
+	</class>
+	
+	<class name="Parent">
+		<id name="name"/>
+		<list name="children" fetch="subselect" cascade="persist, delete">
+			<key column="parentName" not-null="true"/>
+			<list-index column="loc"/>
+			<one-to-many class="Child"/>
+		</list>
+		<list name="moreChildren" table="ParentChild" fetch="subselect">
+			<key column="parentName" not-null="true"/>
+			<list-index column="loc"/>
+			<many-to-many class="Child" column="childName"/>
+		</list>
+	</class>
+		
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/ParentChild.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/SubselectFetchTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/SubselectFetchTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/SubselectFetchTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,384 @@
+//$Id: SubselectFetchTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.subselectfetch;
+
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.Order;
+import org.hibernate.criterion.Property;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class SubselectFetchTest extends FunctionalTestCase {
+
+	public SubselectFetchTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "subselectfetch/ParentChild.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SubselectFetchTest.class );
+	}
+	
+	public void testSubselectFetchHql() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Parent p = new Parent("foo");
+		p.getChildren().add( new Child("foo1") );
+		p.getChildren().add( new Child("foo2") );
+		Parent q = new Parent("bar");
+		q.getChildren().add( new Child("bar1") );
+		q.getChildren().add( new Child("bar2") );
+		q.getMoreChildren().addAll( p.getChildren() );
+		s.persist(p); 
+		s.persist(q);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		
+		getSessions().getStatistics().clear();
+		
+		List parents = s.createQuery("from Parent where name between 'bar' and 'foo' order by name desc")
+			.list();
+		p = (Parent) parents.get(0);
+		q = (Parent) parents.get(1);
+
+		assertFalse( Hibernate.isInitialized( p.getChildren() ) );
+		assertFalse( Hibernate.isInitialized( q.getChildren() ) );
+
+		assertEquals( p.getChildren().size(), 2 );
+		
+		assertTrue( Hibernate.isInitialized( p.getChildren().iterator().next() ) );
+				
+		assertTrue( Hibernate.isInitialized( q.getChildren() ) );
+		
+		assertEquals( q.getChildren().size(), 2 );
+		
+		assertTrue( Hibernate.isInitialized( q.getChildren().iterator().next() ) );
+		
+		assertFalse( Hibernate.isInitialized( p.getMoreChildren() ) );
+		assertFalse( Hibernate.isInitialized( q.getMoreChildren() ) );
+
+		assertEquals( p.getMoreChildren().size(), 0 );
+		
+		assertTrue( Hibernate.isInitialized( q.getMoreChildren() ) );
+	
+		assertEquals( q.getMoreChildren().size(), 2 );
+		
+		assertTrue( Hibernate.isInitialized( q.getMoreChildren().iterator().next() ) );
+		
+		assertEquals( 3, getSessions().getStatistics().getPrepareStatementCount() );
+
+		Child c = (Child) p.getChildren().get(0);
+		c.getFriends().size();
+
+		s.delete(p);
+		s.delete(q);		
+
+		t.commit();
+		s.close();
+	}
+	
+	public void testSubselectFetchNamedParam() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Parent p = new Parent("foo");
+		p.getChildren().add( new Child("foo1") );
+		p.getChildren().add( new Child("foo2") );
+		Parent q = new Parent("bar");
+		q.getChildren().add( new Child("bar1") );
+		q.getChildren().add( new Child("bar2") );
+		q.getMoreChildren().addAll( p.getChildren() );
+		s.persist(p); 
+		s.persist(q);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		
+		getSessions().getStatistics().clear();
+		
+		List parents = s.createQuery("from Parent where name between :bar and :foo order by name desc")
+			.setParameter("bar", "bar")
+			.setParameter("foo", "foo")
+			.list();
+		p = (Parent) parents.get(0);
+		q = (Parent) parents.get(1);
+
+		assertFalse( Hibernate.isInitialized( p.getChildren() ) );
+		assertFalse( Hibernate.isInitialized( q.getChildren() ) );
+
+		assertEquals( p.getChildren().size(), 2 );
+		
+		assertTrue( Hibernate.isInitialized( p.getChildren().iterator().next() ) );
+				
+		assertTrue( Hibernate.isInitialized( q.getChildren() ) );
+		
+		assertEquals( q.getChildren().size(), 2 );
+		
+		assertTrue( Hibernate.isInitialized( q.getChildren().iterator().next() ) );
+		
+		assertFalse( Hibernate.isInitialized( p.getMoreChildren() ) );
+		assertFalse( Hibernate.isInitialized( q.getMoreChildren() ) );
+
+		assertEquals( p.getMoreChildren().size(), 0 );
+		
+		assertTrue( Hibernate.isInitialized( q.getMoreChildren() ) );
+	
+		assertEquals( q.getMoreChildren().size(), 2 );
+		
+		assertTrue( Hibernate.isInitialized( q.getMoreChildren().iterator().next() ) );
+		
+		assertEquals( 3, getSessions().getStatistics().getPrepareStatementCount() );
+
+		Child c = (Child) p.getChildren().get(0);
+		c.getFriends().size();
+
+		s.delete(p);
+		s.delete(q);		
+
+		t.commit();
+		s.close();
+	}
+	
+	public void testSubselectFetchPosParam() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Parent p = new Parent("foo");
+		p.getChildren().add( new Child("foo1") );
+		p.getChildren().add( new Child("foo2") );
+		Parent q = new Parent("bar");
+		q.getChildren().add( new Child("bar1") );
+		q.getChildren().add( new Child("bar2") );
+		q.getMoreChildren().addAll( p.getChildren() );
+		s.persist(p); 
+		s.persist(q);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		
+		getSessions().getStatistics().clear();
+		
+		List parents = s.createQuery("from Parent where name between ? and ? order by name desc")
+			.setParameter(0, "bar")
+			.setParameter(1, "foo")
+			.list();
+		p = (Parent) parents.get(0);
+		q = (Parent) parents.get(1);
+
+		assertFalse( Hibernate.isInitialized( p.getChildren() ) );
+		assertFalse( Hibernate.isInitialized( q.getChildren() ) );
+
+		assertEquals( p.getChildren().size(), 2 );
+		
+		assertTrue( Hibernate.isInitialized( p.getChildren().iterator().next() ) );
+				
+		assertTrue( Hibernate.isInitialized( q.getChildren() ) );
+		
+		assertEquals( q.getChildren().size(), 2 );
+		
+		assertTrue( Hibernate.isInitialized( q.getChildren().iterator().next() ) );
+		
+		assertFalse( Hibernate.isInitialized( p.getMoreChildren() ) );
+		assertFalse( Hibernate.isInitialized( q.getMoreChildren() ) );
+
+		assertEquals( p.getMoreChildren().size(), 0 );
+		
+		assertTrue( Hibernate.isInitialized( q.getMoreChildren() ) );
+	
+		assertEquals( q.getMoreChildren().size(), 2 );
+		
+		assertTrue( Hibernate.isInitialized( q.getMoreChildren().iterator().next() ) );
+		
+		assertEquals( 3, getSessions().getStatistics().getPrepareStatementCount() );
+
+		Child c = (Child) p.getChildren().get(0);
+		c.getFriends().size();
+
+		s.delete(p);
+		s.delete(q);		
+
+		t.commit();
+		s.close();
+	}
+	
+	public void testSubselectFetchWithLimit() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Parent p = new Parent("foo");
+		p.getChildren().add( new Child("foo1") );
+		p.getChildren().add( new Child("foo2") );
+		Parent q = new Parent("bar");
+		q.getChildren().add( new Child("bar1") );
+		q.getChildren().add( new Child("bar2") );
+		Parent r = new Parent("aaa");
+		r.getChildren().add( new Child("aaa1") );
+		s.persist(p); 
+		s.persist(q);
+		s.persist(r);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		
+		getSessions().getStatistics().clear();
+		
+		List parents = s.createQuery("from Parent order by name desc")
+			.setMaxResults(2)
+			.list();
+		p = (Parent) parents.get(0);
+		q = (Parent) parents.get(1);
+		assertFalse( Hibernate.isInitialized( p.getChildren() ) );
+		assertFalse( Hibernate.isInitialized( p.getMoreChildren() ) );
+		assertFalse( Hibernate.isInitialized( q.getChildren() ) );
+		assertFalse( Hibernate.isInitialized( q.getMoreChildren() ) );
+		assertEquals( p.getMoreChildren().size(), 0 );
+		assertEquals( p.getChildren().size(), 2 );
+		assertTrue( Hibernate.isInitialized( q.getChildren() ) );
+		assertTrue( Hibernate.isInitialized( q.getMoreChildren() ) );
+		
+		assertEquals( 3, getSessions().getStatistics().getPrepareStatementCount() );
+		
+		r = (Parent) s.get( Parent.class, r.getName() );
+		assertTrue( Hibernate.isInitialized( r.getChildren() ) );
+		assertFalse( Hibernate.isInitialized( r.getMoreChildren() ) );
+		assertEquals( r.getChildren().size(), 1 );
+		assertEquals( r.getMoreChildren().size(), 0 );
+
+		s.delete(p);
+		s.delete(q);		
+		s.delete(r);
+		
+		t.commit();
+		s.close();
+	}
+	
+	public void testManyToManyCriteriaJoin() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Parent p = new Parent("foo");
+		p.getChildren().add( new Child("foo1") );
+		p.getChildren().add( new Child("foo2") );
+		Parent q = new Parent("bar");
+		q.getChildren().add( new Child("bar1") );
+		q.getChildren().add( new Child("bar2") );
+		q.getMoreChildren().addAll( p.getChildren() );
+		s.persist(p); 
+		s.persist(q);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		
+		List parents = s.createCriteria(Parent.class)
+			.createCriteria("moreChildren")
+			.createCriteria("friends")
+			.addOrder( Order.desc("name") )
+			.list();
+
+		parents = s.createCriteria(Parent.class)
+			.setFetchMode("moreChildren", FetchMode.JOIN)
+			.setFetchMode("moreChildren.friends", FetchMode.JOIN)
+			.addOrder( Order.desc("name") )
+			.list();
+
+		s.delete( parents.get(0) );
+		s.delete( parents.get(1) );
+
+		t.commit();
+		s.close();
+	}
+	
+	public void testSubselectFetchCriteria() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Parent p = new Parent("foo");
+		p.getChildren().add( new Child("foo1") );
+		p.getChildren().add( new Child("foo2") );
+		Parent q = new Parent("bar");
+		q.getChildren().add( new Child("bar1") );
+		q.getChildren().add( new Child("bar2") );
+		q.getMoreChildren().addAll( p.getChildren() );
+		s.persist(p); 
+		s.persist(q);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		
+		getSessions().getStatistics().clear();
+		
+		List parents = s.createCriteria(Parent.class)
+			.add( Property.forName("name").between("bar", "foo") )
+			.addOrder( Order.desc("name") )
+			.list();
+		p = (Parent) parents.get(0);
+		q = (Parent) parents.get(1);
+
+		assertFalse( Hibernate.isInitialized( p.getChildren() ) );
+		assertFalse( Hibernate.isInitialized( q.getChildren() ) );
+
+		assertEquals( p.getChildren().size(), 2 );
+				
+		assertTrue( Hibernate.isInitialized( p.getChildren().iterator().next() ) );
+		
+		assertTrue( Hibernate.isInitialized( q.getChildren() ) );
+		
+		assertEquals( q.getChildren().size(), 2 );
+		
+		assertTrue( Hibernate.isInitialized( q.getChildren().iterator().next() ) );
+		
+		assertFalse( Hibernate.isInitialized( p.getMoreChildren() ) );
+		assertFalse( Hibernate.isInitialized( q.getMoreChildren() ) );
+
+		assertEquals( p.getMoreChildren().size(), 0 );
+		
+		assertTrue( Hibernate.isInitialized( q.getMoreChildren() ) );
+	
+		assertEquals( q.getMoreChildren().size(), 2 );
+		
+		assertTrue( Hibernate.isInitialized( q.getMoreChildren().iterator().next() ) );
+		
+		assertEquals( 3, getSessions().getStatistics().getPrepareStatementCount() );
+
+		Child c = (Child) p.getChildren().get(0);
+		c.getFriends().size();
+
+		s.delete(p);
+		s.delete(q);		
+
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/subselectfetch/SubselectFetchTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Employee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Employee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Employee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+//$Id: Employee.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.ternary;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class Employee {
+	private String name;
+	private Date hireDate;
+	private Map managerBySite = new HashMap();
+	private Set underlings = new HashSet();
+	
+	Employee() {}
+	public Employee(String name) {
+		this.name=name;
+	}
+	public Map getManagerBySite() {
+		return managerBySite;
+	}
+	public void setManagerBySite(Map managerBySite) {
+		this.managerBySite = managerBySite;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public Set getUnderlings() {
+		return underlings;
+	}
+	public void setUnderlings(Set underlings) {
+		this.underlings = underlings;
+	}
+	public Date getHireDate() {
+		return hireDate;
+	}
+	public void setHireDate(Date hireDate) {
+		this.hireDate = hireDate;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Employee.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Site.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Site.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Site.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+//$Id: Site.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.ternary;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class Site {
+	private String name;
+	private String description;
+	private Set employees = new HashSet();
+	private Set managers = new HashSet();
+
+	Site() {}
+	public Site(String name) {
+		this.name=name;
+	}
+	public Set getManagers() {
+		return managers;
+	}
+	public void setManagers(Set managers) {
+		this.managers = managers;
+	}
+	public String getDescription() {
+		return description;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	public Set getEmployees() {
+		return employees;
+	}
+	public void setEmployees(Set employees) {
+		this.employees = employees;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Site.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Ternary.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Ternary.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Ternary.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.ternary">
+
+	<class name="Employee">
+		<id name="name"/>
+		<property name="hireDate" type="imm_date"/>
+		<map name="managerBySite" table="employeeSite">
+			<key column="employeeName" not-null="true"/>
+			<map-key-many-to-many column="siteName" class="Site"/>
+			<many-to-many column="managerName" class="Employee"/>
+		</map>
+		<set name="underlings" table="employeeSite" inverse="true">
+			<key column="managerName" not-null="true"/>
+			<many-to-many column="employeeName" class="Employee"/>
+		</set>
+	</class>
+	
+	<class name="Site">
+		<id name="name"/>
+		<property name="description"/>
+		<set name="employees" table="employeeSite" inverse="true">
+			<key column="siteName"/>
+			<many-to-many column="employeeName" class="Employee"/>
+		</set>
+		<set name="managers" table="employeeSite" inverse="true">
+			<key column="siteName"/>
+			<many-to-many column="managerName" class="Employee"/>
+		</set>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/Ternary.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/TernaryTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/TernaryTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/TernaryTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,116 @@
+//$Id: TernaryTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.ternary;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class TernaryTest extends FunctionalTestCase {
+	
+	public TernaryTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "ternary/Ternary.hbm.xml" };
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( TernaryTest.class );
+	}
+	
+	public void testTernary() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Employee bob = new Employee("Bob");
+		Employee tom = new Employee("Tom");
+		Employee jim = new Employee("Jim");
+		Employee tim = new Employee("Tim");
+		Site melb = new Site("Melbourne");
+		Site geel = new Site("Geelong");
+		s.persist(bob);
+		s.persist(tom);
+		s.persist(jim);
+		s.persist(tim);
+		s.persist(melb);
+		s.persist(geel);
+		bob.getManagerBySite().put(melb, tom);
+		bob.getManagerBySite().put(geel, jim);
+		tim.getManagerBySite().put(melb, tom);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		tom = (Employee) s.get(Employee.class, "Tom");
+		assertFalse( Hibernate.isInitialized(tom.getUnderlings()) );
+		assertEquals( tom.getUnderlings().size(), 2 );
+		bob = (Employee) s.get(Employee.class, "Bob");
+		assertFalse( Hibernate.isInitialized(bob.getManagerBySite()) );
+		assertTrue( tom.getUnderlings().contains(bob) );
+		melb = (Site) s.get(Site.class, "Melbourne");
+		assertSame( bob.getManagerBySite().get(melb), tom );
+		assertTrue( melb.getEmployees().contains(bob) );
+		assertTrue( melb.getManagers().contains(tom) );
+		t.commit();
+		s.close();		
+
+		s = openSession();
+		t = s.beginTransaction();
+		List l = s.createQuery("from Employee e join e.managerBySite m where m.name='Bob'").list();
+		assertEquals( l.size(), 0 );
+		l = s.createQuery("from Employee e join e.managerBySite m where m.name='Tom'").list();
+		assertEquals( l.size(), 2 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		l = s.createQuery("from Employee e left join fetch e.managerBySite").list();
+		assertEquals( l.size(), 5 );
+		Set set = new HashSet(l);
+		assertEquals( set.size(), 4 );
+		Iterator iter = set.iterator();
+		int total=0;
+		while ( iter.hasNext() ) {
+			Map map = ( (Employee) iter.next() ).getManagerBySite();
+			assertTrue( Hibernate.isInitialized(map) );
+			total += map.size();
+		}
+		assertTrue(total==3);
+
+		l = s.createQuery("from Employee e left join e.managerBySite m left join m.managerBySite m2").list();
+
+		// clean up...
+		l = s.createQuery("from Employee e left join fetch e.managerBySite").list();
+		Iterator itr = l.iterator();
+		while ( itr.hasNext() ) {
+			Employee emp = ( Employee ) itr.next();
+			emp.setManagerBySite( new HashMap() );
+			s.delete( emp );
+		}
+		((org.hibernate.classic.Session)s).delete("from Site");
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/ternary/TernaryTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,37 @@
+//$Id: Person.java 8054 2005-08-31 20:12:24Z oneovthafew $
+package org.hibernate.test.timestamp;
+
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class Person {
+	private String name;
+	private Date dob;
+	private String currentAddress;
+	Person() {}
+	public Person(String name, Date dob, String address) {
+		this.name = name;
+		this.dob = dob;
+		this.currentAddress = address;
+	}
+	public Date getDob() {
+		return dob;
+	}
+	public void setDob(Date dob) {
+		this.dob = dob;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getCurrentAddress() {
+		return currentAddress;
+	}
+	public void setCurrentAddress(String currentAddress) {
+		this.currentAddress = currentAddress;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/TimestampTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/TimestampTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/TimestampTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,91 @@
+//$Id: TimestampTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.timestamp;
+
+import java.util.Date;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class TimestampTest extends FunctionalTestCase {
+	
+	public TimestampTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "timestamp/User.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( TimestampTest.class );
+	}
+	
+	public void testUpdateFalse() {
+
+		getSessions().getStatistics().clear();
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User u = new User( "gavin", "secret", new Person("Gavin King", new Date(), "Karbarook Ave") );
+		s.persist(u);
+		s.flush();
+		u.getPerson().setName("XXXXYYYYY");
+		t.commit();
+		s.close();
+		
+		assertEquals( 1, getSessions().getStatistics().getEntityInsertCount() );
+		assertEquals( 0, getSessions().getStatistics().getEntityUpdateCount() );
+
+		s = openSession();
+		t = s.beginTransaction();
+		u = (User) s.get(User.class, "gavin");
+		assertEquals( u.getPerson().getName(), "Gavin King" );
+		s.delete(u);
+		t.commit();
+		s.close();
+		
+		assertEquals( 1, getSessions().getStatistics().getEntityDeleteCount() );
+	}
+	
+	public void testComponent() {
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User u = new User( "gavin", "secret", new Person("Gavin King", new Date(), "Karbarook Ave") );
+		s.persist(u);
+		s.flush();
+		u.getPerson().setCurrentAddress("Peachtree Rd");
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		u = (User) s.get(User.class, "gavin");
+		u.setPassword("$ecret");
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		u = (User) s.get(User.class, "gavin");
+		assertEquals( u.getPassword(), "$ecret" );
+		s.delete(u);
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/TimestampTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/User.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/User.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/User.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.timestamp">
+	
+	<class name="User" table="T_USER" dynamic-update="true">
+		<id name="userName"/>
+		<timestamp name="lastModified"/>
+		<property name="password" not-null="true" optimistic-lock="false"/>
+		<component name="person">
+			<property name="name" update="false" not-null="true"/>
+			<property name="dob" update="false" not-null="true"/>
+			<property name="currentAddress" 
+				column="address" 
+				insert="false" 
+				update="false"/>
+		</component>
+	</class>
+	
+	<query name="userNameIn"><![CDATA[from User where person.name in (:nameList) or userName in (:nameList)]]></query>
+	
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/User.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,44 @@
+//$Id: User.java 8054 2005-08-31 20:12:24Z oneovthafew $
+package org.hibernate.test.timestamp;
+
+import java.util.Date;
+
+/**
+ * @author Gavin King
+ */
+public class User {
+	private String userName;
+	private String password;
+	private Person person;
+	private Date lastModified;
+	User() {}
+	public User(String id, String pw, Person person) {
+		this.userName = id;
+		this.password = pw;
+		this.person = person;
+	}
+	public Date getLastModified() {
+		return lastModified;
+	}
+	public void setLastModified(Date lastModified) {
+		this.lastModified = lastModified;
+	}
+	public String getPassword() {
+		return password;
+	}
+	public void setPassword(String password) {
+		this.password = password;
+	}
+	public Person getPerson() {
+		return person;
+	}
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+	public String getUserName() {
+		return userName;
+	}
+	public void setUserName(String userName) {
+		this.userName = userName;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/timestamp/User.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/CMTTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/CMTTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/CMTTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,513 @@
+//$Id: CMTTest.java 11303 2007-03-19 22:06:14Z steve.ebersole at jboss.com $
+package org.hibernate.test.tm;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.transaction.Transaction;
+
+import junit.framework.Test;
+
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.EntityMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.Order;
+import org.hibernate.dialect.SybaseDialect;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.transaction.CMTTransactionFactory;
+import org.hibernate.util.SerializationHelper;
+
+/**
+ * @author Gavin King
+ */
+public class CMTTest extends FunctionalTestCase {
+
+	public CMTTest(String str) {
+		super( str );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "tm/Item.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty( Environment.CONNECTION_PROVIDER, DummyConnectionProvider.class.getName() );
+		cfg.setProperty( Environment.TRANSACTION_MANAGER_STRATEGY, DummyTransactionManagerLookup.class.getName() );
+		cfg.setProperty( Environment.TRANSACTION_STRATEGY, CMTTransactionFactory.class.getName() );
+		cfg.setProperty( Environment.AUTO_CLOSE_SESSION, "true" );
+		cfg.setProperty( Environment.FLUSH_BEFORE_COMPLETION, "true" );
+		cfg.setProperty( Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.AFTER_STATEMENT.toString() );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+		cfg.setProperty( Environment.USE_QUERY_CACHE, "true" );
+		cfg.setProperty( Environment.DEFAULT_ENTITY_MODE, EntityMode.MAP.toString() );
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return "transactional";
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CMTTest.class );
+	}
+
+	public void testConcurrent() throws Exception {
+		getSessions().getStatistics().clear();
+
+		DummyTransactionManager.INSTANCE.begin();
+		Session s = openSession();
+		Map foo = new HashMap();
+		foo.put( "name", "Foo" );
+		foo.put( "description", "a big foo" );
+		s.persist( "Item", foo );
+		Map bar = new HashMap();
+		bar.put( "name", "Bar" );
+		bar.put( "description", "a small bar" );
+		s.persist( "Item", bar );
+		DummyTransactionManager.INSTANCE.commit();
+
+		getSessions().evictEntity( "Item" );
+
+		DummyTransactionManager.INSTANCE.begin();
+		Session s1 = openSession();
+		foo = ( Map ) s1.get( "Item", "Foo" );
+		//foo.put("description", "a big red foo");
+		//s1.flush();
+		Transaction tx1 = DummyTransactionManager.INSTANCE.suspend();
+
+		DummyTransactionManager.INSTANCE.begin();
+		Session s2 = openSession();
+		foo = ( Map ) s2.get( "Item", "Foo" );
+		DummyTransactionManager.INSTANCE.commit();
+
+		DummyTransactionManager.INSTANCE.resume( tx1 );
+		tx1.commit();
+
+		getSessions().evictEntity( "Item" );
+
+		DummyTransactionManager.INSTANCE.begin();
+		s1 = openSession();
+		s1.createCriteria( "Item" ).list();
+		//foo.put("description", "a big red foo");
+		//s1.flush();
+		tx1 = DummyTransactionManager.INSTANCE.suspend();
+
+		DummyTransactionManager.INSTANCE.begin();
+		s2 = openSession();
+		s2.createCriteria( "Item" ).list();
+		DummyTransactionManager.INSTANCE.commit();
+
+		DummyTransactionManager.INSTANCE.resume( tx1 );
+		tx1.commit();
+
+		DummyTransactionManager.INSTANCE.begin();
+		s2 = openSession();
+		s2.createCriteria( "Item" ).list();
+		DummyTransactionManager.INSTANCE.commit();
+
+		assertEquals( getSessions().getStatistics().getEntityLoadCount(), 7 );
+		assertEquals( getSessions().getStatistics().getEntityFetchCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 3 );
+		assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryCacheMissCount(), 0 );
+
+		DummyTransactionManager.INSTANCE.begin();
+		s = openSession();
+		s.createQuery( "delete from Item" ).executeUpdate();
+		DummyTransactionManager.INSTANCE.commit();
+	}
+
+	public void testConcurrentCachedQueries() throws Exception {
+
+		DummyTransactionManager.INSTANCE.begin();
+		Session s = openSession();
+		Map foo = new HashMap();
+		foo.put( "name", "Foo" );
+		foo.put( "description", "a big foo" );
+		s.persist( "Item", foo );
+		Map bar = new HashMap();
+		bar.put( "name", "Bar" );
+		bar.put( "description", "a small bar" );
+		s.persist( "Item", bar );
+		DummyTransactionManager.INSTANCE.commit();
+
+		synchronized ( this ) {
+			wait( 1000 );
+		}
+
+		getSessions().getStatistics().clear();
+
+		getSessions().evictEntity( "Item" );
+
+		DummyTransactionManager.INSTANCE.begin();
+		Session s4 = openSession();
+		Transaction tx4 = DummyTransactionManager.INSTANCE.suspend();
+
+		DummyTransactionManager.INSTANCE.begin();
+		Session s1 = openSession();
+		List r1 = s1.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
+				.setCacheable( true ).list();
+		assertEquals( r1.size(), 2 );
+		Transaction tx1 = DummyTransactionManager.INSTANCE.suspend();
+
+		DummyTransactionManager.INSTANCE.begin();
+		Session s2 = openSession();
+		List r2 = s2.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
+				.setCacheable( true ).list();
+		assertEquals( r2.size(), 2 );
+		DummyTransactionManager.INSTANCE.commit();
+
+		assertEquals( getSessions().getStatistics().getSecondLevelCacheHitCount(), 2 );
+		assertEquals( getSessions().getStatistics().getSecondLevelCacheMissCount(), 0 );
+		assertEquals( getSessions().getStatistics().getEntityLoadCount(), 2 );
+		assertEquals( getSessions().getStatistics().getEntityFetchCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 );
+		assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 1 );
+		assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 1 );
+		assertEquals( getSessions().getStatistics().getQueryCacheMissCount(), 1 );
+
+		DummyTransactionManager.INSTANCE.resume( tx1 );
+		tx1.commit();
+
+		DummyTransactionManager.INSTANCE.begin();
+		Session s3 = openSession();
+		s3.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
+				.setCacheable( true ).list();
+		DummyTransactionManager.INSTANCE.commit();
+
+		assertEquals( getSessions().getStatistics().getSecondLevelCacheHitCount(), 4 );
+		assertEquals( getSessions().getStatistics().getSecondLevelCacheMissCount(), 0 );
+		assertEquals( getSessions().getStatistics().getEntityLoadCount(), 2 );
+		assertEquals( getSessions().getStatistics().getEntityFetchCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 );
+		assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 1 );
+		assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 2 );
+		assertEquals( getSessions().getStatistics().getQueryCacheMissCount(), 1 );
+
+		DummyTransactionManager.INSTANCE.resume( tx4 );
+		List r4 = s4.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
+				.setCacheable( true ).list();
+		assertEquals( r4.size(), 2 );
+		tx4.commit();
+
+		assertEquals( getSessions().getStatistics().getSecondLevelCacheHitCount(), 6 );
+		assertEquals( getSessions().getStatistics().getSecondLevelCacheMissCount(), 0 );
+		assertEquals( getSessions().getStatistics().getEntityLoadCount(), 2 );
+		assertEquals( getSessions().getStatistics().getEntityFetchCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 );
+		assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 1 );
+		assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 3 );
+		assertEquals( getSessions().getStatistics().getQueryCacheMissCount(), 1 );
+
+		DummyTransactionManager.INSTANCE.begin();
+		s = openSession();
+		s.createQuery( "delete from Item" ).executeUpdate();
+		DummyTransactionManager.INSTANCE.commit();
+	}
+
+	public void testConcurrentCachedDirtyQueries() throws Exception {
+		if ( getDialect().doesReadCommittedCauseWritersToBlockReaders() ) {
+			reportSkip( "write locks block readers", "concurrent queries" );
+			return;
+		}
+
+		DummyTransactionManager.INSTANCE.begin();
+		Session s = openSession();
+		Map foo = new HashMap();
+		foo.put( "name", "Foo" );
+		foo.put( "description", "a big foo" );
+		s.persist( "Item", foo );
+		Map bar = new HashMap();
+		bar.put( "name", "Bar" );
+		bar.put( "description", "a small bar" );
+		s.persist( "Item", bar );
+		DummyTransactionManager.INSTANCE.commit();
+
+		synchronized ( this ) {
+			wait( 1000 );
+		}
+
+		getSessions().getStatistics().clear();
+
+		getSessions().evictEntity( "Item" );
+
+		DummyTransactionManager.INSTANCE.begin();
+		Session s4 = openSession();
+		Transaction tx4 = DummyTransactionManager.INSTANCE.suspend();
+
+		DummyTransactionManager.INSTANCE.begin();
+		Session s1 = openSession();
+		List r1 = s1.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
+				.setCacheable( true ).list();
+		assertEquals( r1.size(), 2 );
+		foo = ( Map ) r1.get( 0 );
+		foo.put( "description", "a big red foo" );
+		s1.flush();
+		Transaction tx1 = DummyTransactionManager.INSTANCE.suspend();
+
+		DummyTransactionManager.INSTANCE.begin();
+		Session s2 = openSession();
+		List r2 = s2.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
+				.setCacheable( true ).list();
+		assertEquals( r2.size(), 2 );
+		DummyTransactionManager.INSTANCE.commit();
+
+		assertEquals( getSessions().getStatistics().getSecondLevelCacheHitCount(), 0 );
+		assertEquals( getSessions().getStatistics().getSecondLevelCacheMissCount(), 0 );
+		assertEquals( getSessions().getStatistics().getEntityLoadCount(), 4 );
+		assertEquals( getSessions().getStatistics().getEntityFetchCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 2 );
+		assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 2 );
+		assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryCacheMissCount(), 2 );
+
+		DummyTransactionManager.INSTANCE.resume( tx1 );
+		tx1.commit();
+
+		DummyTransactionManager.INSTANCE.begin();
+		Session s3 = openSession();
+		s3.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
+				.setCacheable( true ).list();
+		DummyTransactionManager.INSTANCE.commit();
+
+		assertEquals( getSessions().getStatistics().getSecondLevelCacheHitCount(), 0 );
+		assertEquals( getSessions().getStatistics().getSecondLevelCacheMissCount(), 0 );
+		assertEquals( getSessions().getStatistics().getEntityLoadCount(), 6 );
+		assertEquals( getSessions().getStatistics().getEntityFetchCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 3 );
+		assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 3 );
+		assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryCacheMissCount(), 3 );
+
+		DummyTransactionManager.INSTANCE.resume( tx4 );
+		List r4 = s4.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
+				.setCacheable( true ).list();
+		assertEquals( r4.size(), 2 );
+		tx4.commit();
+
+		assertEquals( getSessions().getStatistics().getSecondLevelCacheHitCount(), 2 );
+		assertEquals( getSessions().getStatistics().getSecondLevelCacheMissCount(), 0 );
+		assertEquals( getSessions().getStatistics().getEntityLoadCount(), 6 );
+		assertEquals( getSessions().getStatistics().getEntityFetchCount(), 0 );
+		assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 3 );
+		assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 3 );
+		assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 1 );
+		assertEquals( getSessions().getStatistics().getQueryCacheMissCount(), 3 );
+
+		DummyTransactionManager.INSTANCE.begin();
+		s = openSession();
+		s.createQuery( "delete from Item" ).executeUpdate();
+		DummyTransactionManager.INSTANCE.commit();
+	}
+
+	public void testCMT() throws Exception {
+		getSessions().getStatistics().clear();
+
+		DummyTransactionManager.INSTANCE.begin();
+		Session s = openSession();
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+		assertFalse( s.isOpen() );
+
+		assertEquals( getSessions().getStatistics().getFlushCount(), 0 );
+
+		DummyTransactionManager.INSTANCE.begin();
+		s = openSession();
+		DummyTransactionManager.INSTANCE.getTransaction().rollback();
+		assertFalse( s.isOpen() );
+
+		DummyTransactionManager.INSTANCE.begin();
+		s = openSession();
+		Map item = new HashMap();
+		item.put( "name", "The Item" );
+		item.put( "description", "The only item we have" );
+		s.persist( "Item", item );
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+		assertFalse( s.isOpen() );
+
+		DummyTransactionManager.INSTANCE.begin();
+		s = openSession();
+		item = ( Map ) s.createQuery( "from Item" ).uniqueResult();
+		assertNotNull( item );
+		s.delete( item );
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+		assertFalse( s.isOpen() );
+
+		assertEquals( getSessions().getStatistics().getTransactionCount(), 4 );
+		assertEquals( getSessions().getStatistics().getSuccessfulTransactionCount(), 3 );
+		assertEquals( getSessions().getStatistics().getEntityDeleteCount(), 1 );
+		assertEquals( getSessions().getStatistics().getEntityInsertCount(), 1 );
+		assertEquals( getSessions().getStatistics().getSessionOpenCount(), 4 );
+		assertEquals( getSessions().getStatistics().getSessionCloseCount(), 4 );
+		assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 );
+		assertEquals( getSessions().getStatistics().getFlushCount(), 2 );
+
+		DummyTransactionManager.INSTANCE.begin();
+		s = openSession();
+		s.createQuery( "delete from Item" ).executeUpdate();
+		DummyTransactionManager.INSTANCE.commit();
+
+	}
+
+	public void testCurrentSession() throws Exception {
+		DummyTransactionManager.INSTANCE.begin();
+		Session s = getSessions().getCurrentSession();
+		Session s2 = getSessions().getCurrentSession();
+		assertSame( s, s2 );
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+		assertFalse( s.isOpen() );
+
+		// TODO : would be nice to automate-test that the SF internal map actually gets cleaned up
+		//      i verified that is does currently in my debugger...
+	}
+
+	public void testCurrentSessionWithIterate() throws Exception {
+		DummyTransactionManager.INSTANCE.begin();
+		Session s = openSession();
+		Map item1 = new HashMap();
+		item1.put( "name", "Item - 1" );
+		item1.put( "description", "The first item" );
+		s.persist( "Item", item1 );
+
+		Map item2 = new HashMap();
+		item2.put( "name", "Item - 2" );
+		item2.put( "description", "The second item" );
+		s.persist( "Item", item2 );
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+
+		// First, test iterating the partial iterator; iterate to past
+		// the first, but not the second, item
+		DummyTransactionManager.INSTANCE.begin();
+		s = getSessions().getCurrentSession();
+		Iterator itr = s.createQuery( "from Item" ).iterate();
+		if ( !itr.hasNext() ) {
+			fail( "No results in iterator" );
+		}
+		itr.next();
+		if ( !itr.hasNext() ) {
+			fail( "Only one result in iterator" );
+		}
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+
+		// Next, iterate the entire result
+		DummyTransactionManager.INSTANCE.begin();
+		s = getSessions().getCurrentSession();
+		itr = s.createQuery( "from Item" ).iterate();
+		if ( !itr.hasNext() ) {
+			fail( "No results in iterator" );
+		}
+		while ( itr.hasNext() ) {
+			itr.next();
+		}
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+
+		DummyTransactionManager.INSTANCE.begin();
+		s = openSession();
+		s.createQuery( "delete from Item" ).executeUpdate();
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+	}
+
+	public void testCurrentSessionWithScroll() throws Exception {
+		DummyTransactionManager.INSTANCE.begin();
+		Session s = getSessions().getCurrentSession();
+		Map item1 = new HashMap();
+		item1.put( "name", "Item - 1" );
+		item1.put( "description", "The first item" );
+		s.persist( "Item", item1 );
+
+		Map item2 = new HashMap();
+		item2.put( "name", "Item - 2" );
+		item2.put( "description", "The second item" );
+		s.persist( "Item", item2 );
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+
+		// First, test partially scrolling the result with out closing
+		DummyTransactionManager.INSTANCE.begin();
+		s = getSessions().getCurrentSession();
+		ScrollableResults results = s.createQuery( "from Item" ).scroll();
+		results.next();
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+
+		// Next, test partially scrolling the result with closing
+		DummyTransactionManager.INSTANCE.begin();
+		s = getSessions().getCurrentSession();
+		results = s.createQuery( "from Item" ).scroll();
+		results.next();
+		results.close();
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+
+		// Next, scroll the entire result (w/o closing)
+		DummyTransactionManager.INSTANCE.begin();
+		s = getSessions().getCurrentSession();
+		results = s.createQuery( "from Item" ).scroll();
+		while ( !results.isLast() ) {
+			results.next();
+		}
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+
+		// Next, scroll the entire result (closing)
+		DummyTransactionManager.INSTANCE.begin();
+		s = getSessions().getCurrentSession();
+		results = s.createQuery( "from Item" ).scroll();
+		while ( !results.isLast() ) {
+			results.next();
+		}
+		results.close();
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+
+		DummyTransactionManager.INSTANCE.begin();
+		s = getSessions().getCurrentSession();
+		s.createQuery( "delete from Item" ).executeUpdate();
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+	}
+
+	public void testAggressiveReleaseWithExplicitDisconnectReconnect() throws Exception {
+		DummyTransactionManager.INSTANCE.begin();
+		Session s = getSessions().getCurrentSession();
+
+		s.createQuery( "from Item" ).list();
+
+		s.disconnect();
+		byte[] bytes = SerializationHelper.serialize( s );
+		s = ( Session ) SerializationHelper.deserialize( bytes );
+		s.reconnect();
+
+		s.createQuery( "from Item" ).list();
+
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+	}
+
+	public void testAggressiveReleaseWithConnectionRetreival() throws Exception {
+		DummyTransactionManager.INSTANCE.begin();
+		Session s = openSession();
+		Map item1 = new HashMap();
+		item1.put( "name", "Item - 1" );
+		item1.put( "description", "The first item" );
+		s.save( "Item", item1 );
+
+		Map item2 = new HashMap();
+		item2.put( "name", "Item - 2" );
+		item2.put( "description", "The second item" );
+		s.save( "Item", item2 );
+		DummyTransactionManager.INSTANCE.getTransaction().commit();
+
+		try {
+			DummyTransactionManager.INSTANCE.begin();
+			s = getSessions().getCurrentSession();
+			s.createQuery( "from Item" ).scroll().next();
+			s.connection();
+			DummyTransactionManager.INSTANCE.getTransaction().commit();
+		}
+		finally {
+			DummyTransactionManager.INSTANCE.begin();
+			s = openSession();
+			s.createQuery( "delete from Item" ).executeUpdate();
+			DummyTransactionManager.INSTANCE.getTransaction().commit();
+		}
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/CMTTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyConnectionProvider.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyConnectionProvider.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyConnectionProvider.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,48 @@
+//$Id: DummyConnectionProvider.java 6501 2005-04-24 00:18:28Z oneovthafew $
+package org.hibernate.test.tm;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import org.hibernate.HibernateException;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.connection.ConnectionProviderFactory;
+
+/**
+ * @author Gavin King
+ */
+public class DummyConnectionProvider implements ConnectionProvider {
+	
+	ConnectionProvider cp;
+	boolean isTransaction;
+
+	public void configure(Properties props) throws HibernateException {
+		cp = ConnectionProviderFactory.newConnectionProvider();
+	}
+	
+	public Connection getConnection() throws SQLException {
+		DummyTransactionManager dtm = DummyTransactionManager.INSTANCE;
+		if ( dtm!=null && dtm.getCurrent()!=null && dtm.getCurrent().getConnection()!=null ) {
+			isTransaction = true;
+			return dtm.getCurrent().getConnection();
+		}
+		else {
+			isTransaction = false;
+			return cp.getConnection();
+		}
+	}
+
+	public void closeConnection(Connection conn) throws SQLException {
+		if (!isTransaction) conn.close();
+	}
+
+	public void close() throws HibernateException {
+
+	}
+
+	public boolean supportsAggressiveRelease() {
+		return true;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyConnectionProvider.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyJTAStyleTransationFactory.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyJTAStyleTransationFactory.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyJTAStyleTransationFactory.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,138 @@
+package org.hibernate.test.tm;
+
+import org.hibernate.transaction.TransactionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.HibernateException;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.util.JTAHelper;
+import org.hibernate.jdbc.JDBCContext;
+
+import javax.transaction.SystemException;
+import javax.transaction.Synchronization;
+import java.util.Properties;
+
+/**
+ * todo: describe DummyJTAStyleTransationFactory
+ *
+ * @author Steve Ebersole
+ */
+public class DummyJTAStyleTransationFactory implements TransactionFactory {
+	public Transaction createTransaction(
+			JDBCContext jdbcContext,
+			Context context) throws HibernateException {
+		return new DummyTransactionAdapter();
+	}
+
+	public void configure(Properties props) throws HibernateException {
+	}
+
+	public ConnectionReleaseMode getDefaultReleaseMode() {
+		return ConnectionReleaseMode.AFTER_STATEMENT;
+	}
+
+	public boolean isTransactionManagerRequired() {
+		return true;
+	}
+
+	public boolean areCallbacksLocalToHibernateTransactions() {
+		return false;
+	}
+
+	public boolean isTransactionInProgress(
+			JDBCContext jdbcContext,
+			Context transactionContext,
+			Transaction transaction) {
+		try {
+			return JTAHelper.isTransactionInProgress( DummyTransactionManager.INSTANCE.getCurrent() )
+			       && ! JTAHelper.isMarkedForRollback( DummyTransactionManager.INSTANCE.getCurrent() );
+		}
+		catch( SystemException e ) {
+			throw new HibernateException( e );
+		}
+	}
+
+	private static class DummyTransactionAdapter implements Transaction {
+
+		private boolean started;
+		private boolean committed;
+		private boolean rolledback;
+
+		public void begin() throws HibernateException {
+			started = true;
+			committed = false;
+			rolledback = false;
+			try {
+				DummyTransactionManager.INSTANCE.begin();
+			}
+			catch( Throwable t ) {
+				throw new HibernateException( "error on begin()", t );
+			}
+		}
+
+		public void commit() throws HibernateException {
+			if ( !started ) {
+				throw new HibernateException( "not yet started!" );
+			}
+			started = false;
+			rolledback = false;
+			committed = false;
+			try {
+				DummyTransactionManager.INSTANCE.commit();
+				committed = true;
+			}
+			catch( Throwable t ) {
+				throw new HibernateException( "error on commit()", t );
+			}
+		}
+
+		public void rollback() throws HibernateException {
+			if ( !started ) {
+				throw new HibernateException( "not yet started!" );
+			}
+			started = false;
+			rolledback = false;
+			committed = false;
+			try {
+				DummyTransactionManager.INSTANCE.rollback();
+				rolledback = true;
+			}
+			catch( Throwable t ) {
+				throw new HibernateException( "error on rollback()", t );
+			}
+		}
+
+		public boolean wasRolledBack() throws HibernateException {
+			return rolledback;
+		}
+
+		public boolean wasCommitted() throws HibernateException {
+			return committed;
+		}
+
+		public boolean isActive() throws HibernateException {
+			return started;
+		}
+
+		public void registerSynchronization(Synchronization synchronization) throws HibernateException {
+			try {
+				DummyTransactionManager.INSTANCE.getCurrent().registerSynchronization( synchronization );
+			}
+			catch( Throwable t ) {
+				throw new HibernateException( "error on registerSynchronization()", t );
+			}
+		}
+
+		public void setTimeout(int seconds) {
+			// ignore...
+		}
+	}
+
+	public static void setup(Configuration cfg) {
+		cfg.setProperty( Environment.CONNECTION_PROVIDER, DummyConnectionProvider.class.getName() );
+		cfg.setProperty( Environment.TRANSACTION_MANAGER_STRATEGY, DummyTransactionManagerLookup.class.getName() );
+		cfg.setProperty( Environment.TRANSACTION_STRATEGY, DummyJTAStyleTransationFactory.class.getName() );
+		cfg.setProperty( Environment.FLUSH_BEFORE_COMPLETION, "true" );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransaction.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransaction.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransaction.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,146 @@
+//$Id: DummyTransaction.java 8411 2005-10-14 23:29:04Z maxcsaucdk $
+package org.hibernate.test.tm;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.xa.XAResource;
+
+/**
+ * @author Gavin King
+ */
+public class DummyTransaction implements Transaction {
+	
+	int status;
+	private Connection connection;
+	List synchronizations = new ArrayList();
+	private DummyTransactionManager transactionManager;
+	
+	DummyTransaction(DummyTransactionManager transactionManager) {
+		status = Status.STATUS_NO_TRANSACTION;
+		this.transactionManager = transactionManager;
+	}
+	
+	public void begin() throws SystemException {
+		try {
+			connection = transactionManager.connections.getConnection();
+		}
+		catch (SQLException sqle) {
+			
+			sqle.printStackTrace();
+			throw new SystemException(sqle.toString());
+		}
+		status = Status.STATUS_ACTIVE;
+	}
+
+	public void commit() throws RollbackException, HeuristicMixedException,
+			HeuristicRollbackException, SecurityException,
+			IllegalStateException, SystemException {
+		
+		if (status == Status.STATUS_MARKED_ROLLBACK) {
+			rollback();
+		}
+		else {
+			status = Status.STATUS_PREPARING;
+			
+			for ( int i=0; i<synchronizations.size(); i++ ) {
+				Synchronization s = (Synchronization) synchronizations.get(i);
+				s.beforeCompletion();
+			}
+			
+			status = Status.STATUS_COMMITTING;
+			
+			try {
+				connection.commit();
+				connection.close();
+			}
+			catch (SQLException sqle) {
+				status = Status.STATUS_UNKNOWN;
+				throw new SystemException();
+			}
+			
+			status = Status.STATUS_COMMITTED;
+
+			for ( int i=0; i<synchronizations.size(); i++ ) {
+				Synchronization s = (Synchronization) synchronizations.get(i);
+				s.afterCompletion(status);
+			}
+			
+			//status = Status.STATUS_NO_TRANSACTION;
+			transactionManager.endCurrent(this);
+		}
+
+	}
+	
+	public boolean delistResource(XAResource arg0, int arg1)
+			throws IllegalStateException, SystemException {
+		// TODO Auto-generated method stub
+		return false;
+	}
+	
+	public boolean enlistResource(XAResource arg0) throws RollbackException,
+			IllegalStateException, SystemException {
+		// TODO Auto-generated method stub
+		return false;
+	}
+	
+	public int getStatus() throws SystemException {
+		return status;
+	}
+	
+	public void registerSynchronization(Synchronization sync)
+			throws RollbackException, IllegalStateException, SystemException {
+		synchronizations.add(sync);
+	}
+	
+	public void rollback() throws IllegalStateException, SystemException {
+
+		status = Status.STATUS_ROLLING_BACK;
+
+// Synch.beforeCompletion() should *not* be called for rollbacks
+//		for ( int i=0; i<synchronizations.size(); i++ ) {
+//			Synchronization s = (Synchronization) synchronizations.get(i);
+//			s.beforeCompletion();
+//		}
+		
+		status = Status.STATUS_ROLLEDBACK;
+		
+		try {
+			connection.rollback();
+			connection.close();
+		}
+		catch (SQLException sqle) {
+			status = Status.STATUS_UNKNOWN;
+			throw new SystemException();
+		}
+		
+		for ( int i=0; i<synchronizations.size(); i++ ) {
+			Synchronization s = (Synchronization) synchronizations.get(i);
+			s.afterCompletion(status);
+		}
+		
+		//status = Status.STATUS_NO_TRANSACTION;
+		transactionManager.endCurrent(this);
+	}
+	
+	public void setRollbackOnly() throws IllegalStateException, SystemException {
+		status = Status.STATUS_MARKED_ROLLBACK;
+	}
+
+	void setConnection(Connection connection) {
+		this.connection = connection;
+	}
+
+	public Connection getConnection() {
+		return connection;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransaction.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransactionManager.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransactionManager.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransactionManager.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,84 @@
+//$Id: DummyTransactionManager.java 7003 2005-06-03 16:09:59Z steveebersole $
+package org.hibernate.test.tm;
+
+import java.util.Properties;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.InvalidTransactionException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.connection.ConnectionProviderFactory;
+
+/**
+ * @author Gavin King
+ */
+public class DummyTransactionManager implements TransactionManager {
+
+	public static DummyTransactionManager INSTANCE;
+
+	private DummyTransaction current;
+	ConnectionProvider connections;
+	
+	public DummyTransactionManager(Properties props) {
+		connections = ConnectionProviderFactory.newConnectionProvider();
+	}
+	
+	public void begin() throws NotSupportedException, SystemException {
+		current = new DummyTransaction(this);
+		current.begin();
+	}
+
+	public void commit() throws RollbackException, HeuristicMixedException,
+			HeuristicRollbackException, SecurityException,
+			IllegalStateException, SystemException {
+		current.commit();
+	}
+
+
+	public int getStatus() throws SystemException {
+		return current.getStatus();
+	}
+
+	public Transaction getTransaction() throws SystemException {
+		return current;
+	}
+
+	public void resume(Transaction tx) throws InvalidTransactionException,
+			IllegalStateException, SystemException {
+		current = (DummyTransaction) tx;
+	}
+
+	public void rollback() throws IllegalStateException, SecurityException,
+			SystemException {
+		current.rollback();
+
+	}
+
+	public void setRollbackOnly() throws IllegalStateException, SystemException {
+		current.setRollbackOnly();
+	}
+
+	public void setTransactionTimeout(int t) throws SystemException {
+	}
+	
+	public Transaction suspend() throws SystemException {
+		Transaction result = current;
+		current = null;
+		return result;
+	}
+
+	public DummyTransaction getCurrent() {
+		return current;
+	}
+	
+	void endCurrent(DummyTransaction tx) {
+		if (current==tx) current=null;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransactionManager.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransactionManagerLookup.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransactionManagerLookup.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransactionManagerLookup.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+//$Id: DummyTransactionManagerLookup.java 5693 2005-02-13 01:59:07Z oneovthafew $
+package org.hibernate.test.tm;
+
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+
+import org.hibernate.HibernateException;
+import org.hibernate.transaction.TransactionManagerLookup;
+
+/**
+ * @author Gavin King
+ */
+public class DummyTransactionManagerLookup implements TransactionManagerLookup {
+
+	public TransactionManager getTransactionManager(Properties props)
+	throws HibernateException {
+		if ( DummyTransactionManager.INSTANCE == null ) {
+			DummyTransactionManager.INSTANCE = new DummyTransactionManager(props);
+		}
+		return DummyTransactionManager.INSTANCE;
+	}
+
+	public String getUserTransactionName() {
+		throw new UnsupportedOperationException();
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/DummyTransactionManagerLookup.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/Item.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/Item.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/Item.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.tm">
+
+	<class entity-name="Item" table="Things">
+		<id name="name" type="string"/>
+		<property name="description" type="string"/>		
+	</class>
+	
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tm/Item.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tool/Team.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tool/Team.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tool/Team.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM
+  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+  
+<hibernate-mapping package="org.hibernate.test.tool">
+	<class name="Team" table="`Team`">
+	  	<id name="id" column="`iD`">
+		  <generator class="native">
+		  <param name="sequence">TEAM_SEQ</param>
+		  </generator>
+	  	</id>
+	  	<property name="name"/>
+	</class>
+	
+	<class entity-name="OtherTeam" name="Team" table="TEAM">
+		<id name="id" column="id">
+		  <generator class="native">
+		  <param name="sequence">TEAM_SEQ</param>
+		  </generator>
+	  	</id>
+	  	<property name="name" column="xname"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tool/Team.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tool/Team.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tool/Team.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+package org.hibernate.test.tool;
+
+
+public class Team {
+	private Long id;
+	private String name;
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+		
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tool/TestSchemaTools.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tool/TestSchemaTools.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/tool/TestSchemaTools.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,226 @@
+package org.hibernate.test.tool;
+
+import java.sql.Connection;
+import java.sql.Statement;
+import java.sql.SQLException;
+
+import junit.framework.Test;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+import org.hibernate.tool.hbm2ddl.SchemaUpdate;
+import org.hibernate.tool.hbm2ddl.SchemaValidator;
+
+/**
+ * @author Anthony
+ * 
+ * Basic smoke test for schemaupdate/validator.
+ * Dependent on schemas, and probably also HQLDB - Not possible to have in the global test suite at the moment.
+ * 
+ * WARNING, if you want this test to work, you need to define a default schema = SB
+ * in hibernate global configuration.
+ * This schema should not be the same at the default db user schema and should come after the users schema alphabetically.
+ * 
+ */
+public class TestSchemaTools extends DatabaseSpecificFunctionalTestCase {
+
+	public TestSchemaTools(String name) {
+		super( name );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "tool/Team.hbm.xml" };
+	}
+
+	public boolean createSchema() {
+		return false;
+	}
+
+	public void afterSessionFactoryBuilt(SessionFactoryImplementor sfi) {
+		super.afterSessionFactoryBuilt( sfi );
+		Session session = null;
+		try {
+			session = sfi.openSession();
+			Statement stat = session.connection().createStatement();
+			stat.execute("CREATE SCHEMA sb AUTHORIZATION DBA ");
+			stat.execute(" CREATE SCHEMA sa AUTHORIZATION DBA ");
+			stat.execute(" CREATE TABLE \"SA\".\"Team\" (test INTEGER) ");
+			stat.close();
+		}
+		catch ( SQLException e ) {
+			throw new RuntimeException( "could not prepare additional schemas" );
+		}
+		finally {
+			if ( session != null ) {
+				try {
+					session.close();
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+		}
+	}
+
+	protected void prepareTest() throws Exception {
+		super.prepareTest();
+	}
+
+
+	public boolean appliesTo(Dialect dialect) {
+		return dialect instanceof HSQLDialect;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( TestSchemaTools.class );
+	}
+	
+	public void testSchemaTools() throws Exception{
+		// database schema have been created thanks to the setUp method
+		// we have 2 schemas SA et SB, SB must be set as the default schema
+		// used by hibernate hibernate.default_schema SB
+		SchemaExport se = new SchemaExport(getCfg());
+		se.create(true,true);
+		
+		// here we modify the generated table in order to test SchemaUpdate
+		Session session = openSession();
+		Connection conn = session.connection();
+		Statement stat = conn.createStatement();
+		stat.execute("ALTER TABLE \"SB\".\"Team\" DROP COLUMN name ");
+		
+		// update schema
+		SchemaUpdate su = new SchemaUpdate(getCfg());
+		su.execute(true,true);
+		
+		// we can run schema validation. Note that in the setUp method a *wrong* table
+		// has been created with different column names
+		// if schema validator chooses the bad db schema, then the testcase will fail (exception)
+		SchemaValidator sv = new SchemaValidator(getCfg());
+		sv.validate();
+		
+		// it's time to clean our database
+		se.drop(true,true);
+		
+		// then the schemas and false table.
+
+		stat.execute("DROP TABLE \"SA\".\"Team\" ");
+		stat.execute(" DROP SCHEMA sa ");
+		stat.execute("DROP SCHEMA sb ");
+		stat.close();
+		session.close();
+	}
+	
+	public void testSchemaToolsNonQuote() throws Exception{
+		// database schema have been created thanks to the setUp method
+		// we have 2 schemas SA et SB, SB must be set as the default schema
+		// used by hibernate hibernate.default_schema SB
+		SchemaExport se = new SchemaExport(getCfg());
+		se.create(true,true);
+		
+		// here we modify the generated table in order to test SchemaUpdate
+		Session session = openSession();
+		Connection conn = session.connection();
+		Statement stat = conn.createStatement();
+		stat.execute("ALTER TABLE \"SB\".\"TEAM\" DROP COLUMN xname ");
+		
+		// update schema
+		SchemaUpdate su = new SchemaUpdate(getCfg());
+		su.execute(true,true);
+		
+		// we can run schema validation. Note that in the setUp method a *wrong* table
+		// has been created with different column names
+		// if schema validator chooses the bad db schema, then the testcase will fail (exception)
+		SchemaValidator sv = new SchemaValidator(getCfg());
+		sv.validate();
+		
+		// it's time to clean our database
+		se.drop(true,true);
+		
+		// then the schemas and false table.
+
+		stat.execute("DROP TABLE \"SA\".\"Team\" ");
+		stat.execute(" DROP SCHEMA sa ");
+		stat.execute("DROP SCHEMA sb ");
+		stat.close();
+		session.close();
+	}
+	public void testFailingQuoteValidation() throws Exception{
+		// database schema have been created thanks to the setUp method
+		// we have 2 schemas SA et SB, SB must be set as the default schema
+		// used by hibernate hibernate.default_schema SB
+		SchemaExport se = new SchemaExport(getCfg());
+		se.create(true,true);
+		
+		// here we modify the generated table in order to test SchemaUpdate
+		Session session = openSession();
+		Connection conn = session.connection();
+		Statement stat = conn.createStatement();
+		stat.execute("ALTER TABLE \"SB\".\"Team\" DROP COLUMN name ");
+		
+		// update schema
+		//SchemaUpdate su = new SchemaUpdate(getCfg());
+		//su.execute(true,true);
+		
+		try {
+			SchemaValidator sv = new SchemaValidator(getCfg());
+			sv.validate();
+			fail("should fail since we mutated the current schema.");
+		} catch(HibernateException he) {
+			
+		}
+		
+		// it's time to clean our database
+		se.drop(true,true);
+		
+		// then the schemas and false table.
+
+		stat.execute("DROP TABLE \"SA\".\"Team\" ");
+		stat.execute(" DROP SCHEMA sa ");
+		stat.execute("DROP SCHEMA sb ");
+		stat.close();
+		session.close();
+	}
+
+	public void testFailingNonQuoteValidation() throws Exception{
+		// database schema have been created thanks to the setUp method
+		// we have 2 schemas SA et SB, SB must be set as the default schema
+		// used by hibernate hibernate.default_schema SB
+		SchemaExport se = new SchemaExport(getCfg());
+		se.create(true,true);
+		
+		// here we modify the generated table in order to test SchemaUpdate
+		Session session = openSession();
+		Connection conn = session.connection();
+		Statement stat = conn.createStatement();
+		stat.execute("ALTER TABLE \"SB\".\"TEAM\" DROP COLUMN xname ");
+		
+		// update schema
+		//SchemaUpdate su = new SchemaUpdate(getCfg());
+		//su.execute(true,true);
+		
+		try {
+			SchemaValidator sv = new SchemaValidator(getCfg());
+			sv.validate();
+			fail("should fail since we mutated the current schema.");
+		} catch(HibernateException he) {
+			
+		}
+		
+		// it's time to clean our database
+		se.drop(true,true);
+		
+		// then the schemas and false table.
+
+		stat.execute("DROP TABLE \"SA\".\"Team\" ");
+		stat.execute(" DROP SCHEMA sa ");
+		stat.execute("DROP SCHEMA sb ");
+		stat.close();
+		session.close();
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+//$Id: Address.java 6979 2005-06-01 03:51:32Z oneovthafew $
+package org.hibernate.test.typedmanytoone;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Address implements Serializable {
+	
+	private AddressId addressId;
+	private String street;
+	private String city;
+	private String state;
+	private String zip;
+	private Customer customer;
+
+	public Customer getCustomer() {
+		return customer;
+	}
+	public void setCustomer(Customer customer) {
+		this.customer = customer;
+	}
+	
+	public String getCity() {
+		return city;
+	}
+	public void setCity(String city) {
+		this.city = city;
+	}
+	public String getState() {
+		return state;
+	}
+	public void setState(String state) {
+		this.state = state;
+	}
+	public String getStreet() {
+		return street;
+	}
+	public void setStreet(String street) {
+		this.street = street;
+	}
+	public String getZip() {
+		return zip;
+	}
+	public void setZip(String zip) {
+		this.zip = zip;
+	}
+	public AddressId getAddressId() {
+		return addressId;
+	}
+	public void setAddressId(AddressId addressId) {
+		this.addressId = addressId;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Address.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/AddressId.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/AddressId.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/AddressId.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+//$Id: AddressId.java 6979 2005-06-01 03:51:32Z oneovthafew $
+package org.hibernate.test.typedmanytoone;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class AddressId implements Serializable {
+	private String type;
+	private String addressId;
+	
+	public AddressId(String type, String customerId) {
+		this.addressId = customerId;
+		this.type = type;
+	}
+	
+	public AddressId() {}
+	
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getAddressId() {
+		return addressId;
+	}
+	public void setAddressId(String customerId) {
+		this.addressId = customerId;
+	}
+	public boolean equals(Object other) {
+		if ( !(other instanceof AddressId) ) return false;
+		AddressId add = (AddressId) other;
+		return type.equals(add.type) && addressId.equals(add.addressId);
+	}
+	public int hashCode() {
+		return addressId.hashCode() + type.hashCode();
+	}
+	
+	public String toString() {
+		return type + '#' + addressId;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/AddressId.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Customer.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Customer.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Customer.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,85 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+	Shows how to map a one-to-many relationship in the relational
+	schema to "typed" one-to-one associations in the object model.
+	We map the Address class twice, with different entity names,
+	specifying a filtering condition in each mapping. The typed
+	associations then reference the named entities.
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.typedmanytoone">
+
+	<class name="Customer" 
+			select-before-update="true" 
+			dynamic-update="true">
+	
+		<id name="customerId">
+			<generator class="assigned"/>
+		</id>
+	
+		<property name="name" not-null="true"/>
+		
+		<many-to-one name="billingAddress" 
+			entity-name="BillingAddress"
+			cascade="persist,save-update,delete"
+			fetch="join">
+			<column name="billingAddressId"/>
+			<formula>'BILLING'</formula>
+		</many-to-one>
+			
+		<many-to-one name="shippingAddress" 
+			entity-name="ShippingAddress"
+			cascade="persist,save-update,delete"
+			fetch="join">
+			<column name="shippingAddressId"/>
+			<formula>'SHIPPING'</formula>
+		</many-to-one>
+			
+	</class>
+	
+	<class name="Address"
+		table="Address"
+		entity-name="BillingAddress" 
+		where="type='BILLING'" 
+		check="type in ('BILLING', 'SHIPPING')"
+		select-before-update="true" 
+		dynamic-update="true">
+	
+		<composite-id name="addressId"> 
+			<key-property name="addressId"/>
+			<key-property name="type"/>
+		</composite-id>
+		
+		<property name="street" not-null="true"/>
+		<property name="city" not-null="true"/>
+		<property name="state" not-null="true"/>
+		<property name="zip" not-null="true"/>
+						
+	</class>
+
+	<class name="Address" 
+		table="Address"
+		entity-name="ShippingAddress"
+		where="type='SHIPPING'"
+		select-before-update="true" 
+		dynamic-update="true">
+	
+		<composite-id name="addressId">
+			<key-property name="addressId"/>
+			<key-property name="type"/>
+		</composite-id>
+		
+		<property name="street" not-null="true"/>
+		<property name="city" not-null="true"/>
+		<property name="state" not-null="true"/>
+		<property name="zip" not-null="true"/>
+						
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Customer.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+//$Id: Customer.java 6979 2005-06-01 03:51:32Z oneovthafew $
+package org.hibernate.test.typedmanytoone;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Customer implements Serializable {
+
+	private String name;
+	private String customerId;
+	private Address billingAddress;
+	private Address shippingAddress;
+
+	public Address getBillingAddress() {
+		return billingAddress;
+	}
+	public void setBillingAddress(Address billingAddress) {
+		this.billingAddress = billingAddress;
+	}
+	public String getCustomerId() {
+		return customerId;
+	}
+	public void setCustomerId(String customerId) {
+		this.customerId = customerId;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public Address getShippingAddress() {
+		return shippingAddress;
+	}
+	public void setShippingAddress(Address shippingAddress) {
+		this.shippingAddress = shippingAddress;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/Customer.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/TypedManyToOneTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/TypedManyToOneTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/TypedManyToOneTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,113 @@
+//$Id: TypedManyToOneTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.typedmanytoone;
+
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class TypedManyToOneTest extends FunctionalTestCase {
+	
+	public TypedManyToOneTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "typedmanytoone/Customer.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( TypedManyToOneTest.class );
+	}
+	
+	public void testCreateQuery() {
+		Customer cust = new Customer();
+		cust.setCustomerId("abc123");
+		cust.setName("Matt");
+		
+		Address ship = new Address();
+		ship.setStreet("peachtree rd");
+		ship.setState("GA");
+		ship.setCity("ATL");
+		ship.setZip("30326");
+		ship.setAddressId( new AddressId("SHIPPING", "xyz123") );
+		ship.setCustomer(cust);
+		
+		Address bill = new Address();
+		bill.setStreet("peachtree rd");
+		bill.setState("GA");
+		bill.setCity("ATL");
+		bill.setZip("30326");
+		bill.setAddressId( new AddressId("BILLING", "xyz123") );
+		bill.setCustomer(cust);
+		
+		cust.setBillingAddress(bill);
+		cust.setShippingAddress(ship);
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.persist(cust);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		List results = s.createQuery("from Customer cust left join fetch cust.billingAddress where cust.customerId='abc123'").list();
+		//List results = s.createQuery("from Customer cust left join fetch cust.billingAddress left join fetch cust.shippingAddress").list();
+		cust = (Customer) results.get(0);
+		assertFalse( Hibernate.isInitialized( cust.getShippingAddress() ) );
+		assertTrue( Hibernate.isInitialized( cust.getBillingAddress() ) );
+		assertEquals( "30326", cust.getBillingAddress().getZip() );
+		assertEquals( "30326", cust.getShippingAddress().getZip() );
+		assertEquals( "BILLING", cust.getBillingAddress().getAddressId().getType() );
+		assertEquals( "SHIPPING", cust.getShippingAddress().getAddressId().getType() );
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		s.saveOrUpdate(cust);
+		ship = cust.getShippingAddress();
+		cust.setShippingAddress(null);
+		s.delete("ShippingAddress", ship);
+		s.flush();
+		assertNull( s.get( "ShippingAddress", ship.getAddressId() ) );
+		s.delete( cust );
+		t.commit();
+		s.close();
+	}
+	
+	public void testCreateQueryNull() {
+		Customer cust = new Customer();
+		cust.setCustomerId("xyz123");
+		cust.setName("Matt");
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.persist(cust);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		List results = s.createQuery("from Customer cust left join fetch cust.billingAddress where cust.customerId='xyz123'").list();
+		//List results = s.createQuery("from Customer cust left join fetch cust.billingAddress left join fetch cust.shippingAddress").list();
+		cust = (Customer) results.get(0);
+		assertNull( cust.getShippingAddress() );
+		assertNull( cust.getBillingAddress() );
+		s.delete( cust );
+		t.commit();
+		s.close();
+		
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedmanytoone/TypedManyToOneTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+//$Id: Address.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.typedonetoone;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Address implements Serializable {
+	
+	private AddressId addressId;
+	private String street;
+	private String city;
+	private String state;
+	private String zip;
+	private Customer customer;
+
+	public Customer getCustomer() {
+		return customer;
+	}
+	public void setCustomer(Customer customer) {
+		this.customer = customer;
+	}
+	
+	public String getCity() {
+		return city;
+	}
+	public void setCity(String city) {
+		this.city = city;
+	}
+	public String getState() {
+		return state;
+	}
+	public void setState(String state) {
+		this.state = state;
+	}
+	public String getStreet() {
+		return street;
+	}
+	public void setStreet(String street) {
+		this.street = street;
+	}
+	public String getZip() {
+		return zip;
+	}
+	public void setZip(String zip) {
+		this.zip = zip;
+	}
+	public AddressId getAddressId() {
+		return addressId;
+	}
+	public void setAddressId(AddressId addressId) {
+		this.addressId = addressId;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Address.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/AddressId.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/AddressId.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/AddressId.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,41 @@
+//$Id: AddressId.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.typedonetoone;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class AddressId implements Serializable {
+	private String type;
+	private String customerId;
+	
+	public AddressId(String type, String customerId) {
+		this.customerId = customerId;
+		this.type = type;
+	}
+	
+	public AddressId() {}
+	
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getCustomerId() {
+		return customerId;
+	}
+	public void setCustomerId(String customerId) {
+		this.customerId = customerId;
+	}
+	public boolean equals(Object other) {
+		if ( !(other instanceof AddressId) ) return false;
+		AddressId add = (AddressId) other;
+		return type.equals(add.type) && customerId.equals(add.customerId);
+	}
+	public int hashCode() {
+		return customerId.hashCode() + type.hashCode();
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/AddressId.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Customer.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Customer.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Customer.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,85 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+	Shows how to map a one-to-many relationship in the relational
+	schema to "typed" one-to-one associations in the object model.
+	We map the Address class twice, with different entity names,
+	specifying a filtering condition in each mapping. The typed
+	associations then reference the named entities.
+
+-->
+
+<hibernate-mapping package="org.hibernate.test.typedonetoone">
+
+	<class name="Customer">
+	
+		<id name="customerId">
+			<generator class="assigned"/>
+		</id>
+	
+		<property name="name" not-null="true"/>
+		
+		<one-to-one name="billingAddress" 
+			entity-name="BillingAddress"
+			property-ref="customer"
+			cascade="persist, delete"
+			fetch="join"/>
+			
+		<one-to-one name="shippingAddress" 
+			entity-name="ShippingAddress"
+			property-ref="customer"
+			cascade="persist, delete"
+			fetch="join"/>
+			
+	</class>
+	
+	<class name="Address"
+		table="Address"
+		entity-name="BillingAddress" 
+		where="type='BILLING'" 
+		check="type in ('BILLING', 'SHIPPING')">
+	
+		<composite-id name="addressId">
+			<key-property name="customerId"/>
+			<key-property name="type"/>
+		</composite-id>
+		
+		<property name="street" not-null="true"/>
+		<property name="city" not-null="true"/>
+		<property name="state" not-null="true"/>
+		<property name="zip" not-null="true"/>
+		
+		<many-to-one name="customer" 
+			column="customerId" 
+			insert="false"
+			update="false"/>
+						
+	</class>
+
+	<class name="Address" 
+		table="Address"
+		entity-name="ShippingAddress"
+		where="type='SHIPPING'">
+	
+		<composite-id name="addressId">
+			<key-property name="customerId"/>
+			<key-property name="type"/>
+		</composite-id>
+		
+		<property name="street" not-null="true"/>
+		<property name="city" not-null="true"/>
+		<property name="state" not-null="true"/>
+		<property name="zip" not-null="true"/>
+		
+		<many-to-one name="customer" 
+			column="customerId" 
+			insert="false"
+			update="false"/>
+						
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Customer.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+//$Id: Customer.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.typedonetoone;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Customer implements Serializable {
+
+	private String name;
+	private String customerId;
+	private Address billingAddress;
+	private Address shippingAddress;
+
+	public Address getBillingAddress() {
+		return billingAddress;
+	}
+	public void setBillingAddress(Address billingAddress) {
+		this.billingAddress = billingAddress;
+	}
+	public String getCustomerId() {
+		return customerId;
+	}
+	public void setCustomerId(String customerId) {
+		this.customerId = customerId;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public Address getShippingAddress() {
+		return shippingAddress;
+	}
+	public void setShippingAddress(Address shippingAddress) {
+		this.shippingAddress = shippingAddress;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/Customer.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/TypedOneToOneTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/TypedOneToOneTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/TypedOneToOneTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,103 @@
+//$Id: TypedOneToOneTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.typedonetoone;
+
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class TypedOneToOneTest extends FunctionalTestCase {
+	
+	public TypedOneToOneTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "typedonetoone/Customer.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( TypedOneToOneTest.class );
+	}
+	
+	public void testCreateQuery() {
+		Customer cust = new Customer();
+		cust.setCustomerId("abc123");
+		cust.setName("Matt");
+		
+		Address ship = new Address();
+		ship.setStreet("peachtree rd");
+		ship.setState("GA");
+		ship.setCity("ATL");
+		ship.setZip("30326");
+		ship.setAddressId( new AddressId("SHIPPING", "abc123") );
+		ship.setCustomer(cust);
+		
+		Address bill = new Address();
+		bill.setStreet("peachtree rd");
+		bill.setState("GA");
+		bill.setCity("ATL");
+		bill.setZip("30326");
+		bill.setAddressId( new AddressId("BILLING", "abc123") );
+		bill.setCustomer(cust);
+		
+		cust.setBillingAddress(bill);
+		cust.setShippingAddress(ship);
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.persist(cust);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		List results = s.createQuery("from Customer cust left join fetch cust.billingAddress where cust.customerId='abc123'").list();
+		//List results = s.createQuery("from Customer cust left join fetch cust.billingAddress left join fetch cust.shippingAddress").list();
+		cust = (Customer) results.get(0);
+		assertTrue( Hibernate.isInitialized( cust.getShippingAddress() ) );
+		assertTrue( Hibernate.isInitialized( cust.getBillingAddress() ) );
+		assertEquals( "30326", cust.getBillingAddress().getZip() );
+		assertEquals( "30326", cust.getShippingAddress().getZip() );
+		assertEquals( "BILLING", cust.getBillingAddress().getAddressId().getType() );
+		assertEquals( "SHIPPING", cust.getShippingAddress().getAddressId().getType() );
+		s.delete( cust );
+		t.commit();
+		s.close();
+
+	}
+	
+	public void testCreateQueryNull() {
+		Customer cust = new Customer();
+		cust.setCustomerId("xyz123");
+		cust.setName("Matt");
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.persist(cust);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		List results = s.createQuery("from Customer cust left join fetch cust.billingAddress where cust.customerId='xyz123'").list();
+		//List results = s.createQuery("from Customer cust left join fetch cust.billingAddress left join fetch cust.shippingAddress").list();
+		cust = (Customer) results.get(0);
+		assertNull( cust.getShippingAddress() );
+		assertNull( cust.getBillingAddress() );
+		s.delete(cust);
+		t.commit();
+		s.close();
+		
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typedonetoone/TypedOneToOneTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/DefaultValueIntegerType.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/DefaultValueIntegerType.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/DefaultValueIntegerType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,82 @@
+package org.hibernate.test.typeparameters;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Properties;
+
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.usertype.ParameterizedType;
+import org.hibernate.usertype.UserType;
+
+
+/**
+ * @author Michi
+ */
+public class DefaultValueIntegerType implements UserType, ParameterizedType, Serializable {
+
+	private Integer defaultValue;
+
+	public int[] sqlTypes() {
+		return new int[] {Types.INTEGER};
+	}
+
+	public Class returnedClass() {
+		return int.class;
+	}
+
+	public boolean equals(Object x, Object y) throws HibernateException {
+		if (x==y) return true;
+		if (x==null || y==null) return false;
+		return x.equals(y);
+	}
+
+	public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
+		Number result = (Number) rs.getObject(names[0]);
+		return result==null ? defaultValue : new Integer(result.intValue());
+	}
+
+	public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
+		if (value == null || defaultValue.equals(value) ) {
+			LogFactory.getLog( getClass() ).trace("binding null to parameter: " + index);
+			st.setNull(index, Types.INTEGER);
+		} else {
+			LogFactory.getLog( getClass() ).trace("binding " + value + " to parameter: " + index);
+			st.setInt(index, ((Integer)value).intValue());
+		}
+	}
+
+	public Object deepCopy(Object value) throws HibernateException {
+		return new Integer(((Integer)value).intValue());
+	}
+
+	public boolean isMutable() {
+		return false;
+	}
+
+	public int hashCode(Object x) throws HibernateException {
+		return x.hashCode();
+	}
+
+	public Object assemble(Serializable cached, Object owner)
+	throws HibernateException {
+		return cached;
+	}
+
+	public Serializable disassemble(Object value) throws HibernateException {
+		return (Serializable) value;
+	}
+
+	public Object replace(Object original, Object target, Object owner)
+	throws HibernateException {
+		return original;
+	}
+
+	public void setParameterValues(Properties parameters) {
+		this.defaultValue = Integer.valueOf((String) parameters.get("default"));
+	}
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/TypeParameterTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/TypeParameterTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/TypeParameterTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,122 @@
+//$Id: TypeParameterTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.typeparameters;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+
+import junit.framework.Test;
+
+import org.hibernate.Transaction;
+import org.hibernate.classic.Session;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Test for parameterizable types.
+ * 
+ * @author Michael Gloegl
+ */
+public class TypeParameterTest extends FunctionalTestCase {
+
+	public TypeParameterTest(String name) {
+		super(name);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "typeparameters/Typedef.hbm.xml", "typeparameters/Widget.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( TypeParameterTest.class );
+	}
+
+	public void testSave() throws Exception {
+		deleteData();
+
+		Session s = openSession();
+
+		Transaction t = s.beginTransaction();
+
+		Widget obj = new Widget();
+		obj.setValueThree(5);
+
+		Integer id = (Integer) s.save(obj);
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+
+		Connection connection = s.connection();
+		PreparedStatement statement = connection.prepareStatement("SELECT * FROM STRANGE_TYPED_OBJECT WHERE ID=?");
+		statement.setInt(1, id.intValue());
+		ResultSet resultSet = statement.executeQuery();
+
+		assertTrue("A row should have been returned", resultSet.next());
+		assertTrue("Default value should have been mapped to null", resultSet.getObject("VALUE_ONE") == null);
+		assertTrue("Default value should have been mapped to null", resultSet.getObject("VALUE_TWO") == null);
+		assertEquals("Non-Default value should not be changed", resultSet.getInt("VALUE_THREE"), 5);
+		assertTrue("Default value should have been mapped to null", resultSet.getObject("VALUE_FOUR") == null);
+
+		deleteData();
+		t.commit();
+		s.close();
+	}
+
+	public void testLoading() throws Exception {
+		initData();
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Widget obj = (Widget) s.createQuery("from Widget o where o.string = :string").setString("string", "all-normal").uniqueResult();
+		assertEquals("Non-Default value incorrectly loaded", obj.getValueOne(), 7);
+		assertEquals("Non-Default value incorrectly loaded", obj.getValueTwo(), 8);
+		assertEquals("Non-Default value incorrectly loaded", obj.getValueThree(), 9);
+		assertEquals("Non-Default value incorrectly loaded", obj.getValueFour(), 10);
+
+		obj = (Widget) s.createQuery("from Widget o where o.string = :string").setString("string", "all-default").uniqueResult();
+		assertEquals("Default value incorrectly loaded", obj.getValueOne(), 1);
+		assertEquals("Default value incorrectly loaded", obj.getValueTwo(), 2);
+		assertEquals("Default value incorrectly loaded", obj.getValueThree(), -1);
+		assertEquals("Default value incorrectly loaded", obj.getValueFour(), -5);
+
+		deleteData();
+		t.commit();
+		s.close();
+	}
+
+	private void initData() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Widget obj = new Widget();
+		obj.setValueOne(7);
+		obj.setValueTwo(8);
+		obj.setValueThree(9);
+		obj.setValueFour(10);
+		obj.setString("all-normal");
+		s.save(obj);
+
+		obj = new Widget();
+		obj.setValueOne(1);
+		obj.setValueTwo(2);
+		obj.setValueThree(-1);
+		obj.setValueFour(-5);
+		obj.setString("all-default");
+		s.save(obj);
+
+		t.commit();
+		s.close();
+	}
+
+	private void deleteData() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.delete("from Widget");
+		t.commit();
+		s.close();
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/Typedef.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/Typedef.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/Typedef.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping>
+
+	<typedef name="nullToMinusOne"
+		class="org.hibernate.test.typeparameters.DefaultValueIntegerType">
+		<param name="default">-1</param>
+	</typedef>
+	
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/Widget.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/Widget.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/Widget.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.typeparameters">
+
+	<typedef name="nullToTwo"
+		class="org.hibernate.test.typeparameters.DefaultValueIntegerType">
+		<param name="default">2</param>
+	</typedef>
+
+    <class name="Widget" table="STRANGE_TYPED_OBJECT">
+        <id name="id" column="ID">
+            <generator class="increment"/>
+        </id>
+        <property name="valueOne" column="VALUE_ONE">
+			<type name="org.hibernate.test.typeparameters.DefaultValueIntegerType">
+				<param name="default">1</param>
+			</type>
+		</property>
+        <property name="valueTwo" column="VALUE_TWO" type="nullToTwo"/>
+        <property name="valueThree" column="VALUE_THREE" type="nullToMinusOne"/>
+        <property name="valueFour" column="VALUE_FOUR">
+			<type name="nullToTwo">
+				<param name="default">-5</param>
+			</type>
+		</property>
+		<property name="string"/>
+    </class>
+    
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/Widget.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/Widget.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/typeparameters/Widget.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,62 @@
+package org.hibernate.test.typeparameters;
+
+/**
+ * @author Michael Gloegl
+ */
+public class Widget {
+
+	private int valueOne = 1;
+	private int valueTwo = 2;
+	private int valueThree = -1;
+	private int valueFour = -5;
+	private Integer id;
+	private String string;
+
+	public int getValueOne() {
+		return valueOne;
+	}
+
+	public void setValueOne(int valueOne) {
+		this.valueOne = valueOne;
+	}
+
+	public int getValueThree() {
+		return valueThree;
+	}
+
+	public void setValueThree(int valueThree) {
+		this.valueThree = valueThree;
+	}
+
+	public int getValueTwo() {
+		return valueTwo;
+	}
+
+	public void setValueTwo(int valueTwo) {
+		this.valueTwo = valueTwo;
+	}
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getString() {
+		return string;
+	}
+
+	public void setString(String string) {
+		this.string = string;
+	}
+
+	public int getValueFour() {
+		return valueFour;
+	}
+
+	public void setValueFour(int valueFour) {
+		this.valueFour = valueFour;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Employee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Employee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Employee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+//$Id: Employee.java 6298 2005-04-03 03:56:22Z oneovthafew $
+package org.hibernate.test.unconstrained;
+
+/**
+ * @author Gavin King
+ */
+public class Employee {
+	
+	private String id;
+
+	public Employee() {
+	}
+
+	public Employee(String id) {
+		this.id = id;
+	}
+
+	public String getId() {
+		return id;
+	}
+	
+
+	public void setId(String id) {
+		this.id = id;
+	}
+	
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Employee.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+		package="org.hibernate.test.unconstrained"
+		default-access="field">
+	
+	<class name="Person" 
+			dynamic-update="true">
+	
+		<id name="name"/>
+		
+		<property name="employeeId" 
+				unique="true"/>
+				
+		<many-to-one name="employee" 
+				formula="employeeId" 
+				not-found="ignore"
+				cascade="all"/>
+
+	</class>
+
+	<class name="Employee">
+	
+		<id name="id"/>
+
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Person.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+//$Id: Person.java 6298 2005-04-03 03:56:22Z oneovthafew $
+package org.hibernate.test.unconstrained;
+
+/**
+ * @author Gavin King
+ */
+public class Person {
+	
+	private String name;
+	private String employeeId;
+	private Employee employee;
+
+	public Person() {}
+	public Person(String name) {
+		this.name = name;
+	}
+	
+	public Employee getEmployee() {
+		return employee;
+	}
+	
+	public void setEmployee(Employee employee) {
+		this.employee = employee;
+	}
+	
+	public String getEmployeeId() {
+		return employeeId;
+	}
+	
+	public void setEmployeeId(String employeeId) {
+		this.employeeId = employeeId;
+	}
+	
+	public String getName() {
+		return name;
+	}
+	
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/UnconstrainedTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/UnconstrainedTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/UnconstrainedTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,127 @@
+//$Id: UnconstrainedTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.unconstrained;
+
+import junit.framework.Test;
+
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.criterion.Restrictions;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class UnconstrainedTest extends FunctionalTestCase {
+	
+	public UnconstrainedTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "unconstrained/Person.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( UnconstrainedTest.class );
+	}
+
+	public void testUnconstrainedNoCache() {
+		Session session = openSession();
+		Transaction tx = session.beginTransaction();
+		Person p = new Person("gavin");
+		p.setEmployeeId("123456");
+		session.persist(p);
+		tx.commit();
+		session.close();
+		
+		getSessions().evict(Person.class);
+		
+		session = openSession();
+		tx = session.beginTransaction();
+		p = (Person) session.get(Person.class, "gavin");
+		assertNull( p.getEmployee() );
+		p.setEmployee( new Employee("123456") );
+		tx.commit();
+		session.close();
+
+		getSessions().evict(Person.class);
+		
+		session = openSession();
+		tx = session.beginTransaction();
+		p = (Person) session.get(Person.class, "gavin");
+		assertTrue( Hibernate.isInitialized( p.getEmployee() ) );
+		assertNotNull( p.getEmployee() );
+		session.delete(p);
+		tx.commit();
+		session.close();
+	}
+
+	public void testUnconstrainedOuterJoinFetch() {
+		Session session = openSession();
+		Transaction tx = session.beginTransaction();
+		Person p = new Person("gavin");
+		p.setEmployeeId("123456");
+		session.persist(p);
+		tx.commit();
+		session.close();
+		
+		getSessions().evict(Person.class);
+		
+		session = openSession();
+		tx = session.beginTransaction();
+		p = (Person) session.createCriteria(Person.class)
+			.setFetchMode("employee", FetchMode.JOIN)
+			.add( Restrictions.idEq("gavin") )
+			.uniqueResult();
+		assertNull( p.getEmployee() );
+		p.setEmployee( new Employee("123456") );
+		tx.commit();
+		session.close();
+
+		getSessions().evict(Person.class);
+		
+		session = openSession();
+		tx = session.beginTransaction();
+		p = (Person) session.createCriteria(Person.class)
+			.setFetchMode("employee", FetchMode.JOIN)
+			.add( Restrictions.idEq("gavin") )
+			.uniqueResult();
+		assertTrue( Hibernate.isInitialized( p.getEmployee() ) );
+		assertNotNull( p.getEmployee() );
+		session.delete(p);
+		tx.commit();
+		session.close();
+	}
+
+	public void testUnconstrained() {
+		Session session = openSession();
+		Transaction tx = session.beginTransaction();
+		Person p = new Person("gavin");
+		p.setEmployeeId("123456");
+		session.persist(p);
+		tx.commit();
+		session.close();
+		
+		session = openSession();
+		tx = session.beginTransaction();
+		p = (Person) session.get(Person.class, "gavin");
+		assertNull( p.getEmployee() );
+		p.setEmployee( new Employee("123456") );
+		tx.commit();
+		session.close();
+
+		session = openSession();
+		tx = session.beginTransaction();
+		p = (Person) session.get(Person.class, "gavin");
+		assertTrue( Hibernate.isInitialized( p.getEmployee() ) );
+		assertNotNull( p.getEmployee() );
+		session.delete(p);
+		tx.commit();
+		session.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unconstrained/UnconstrainedTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/BackrefTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/BackrefTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/BackrefTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,88 @@
+//$Id: BackrefTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.unidir;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class BackrefTest extends FunctionalTestCase {
+	
+	public BackrefTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "unidir/ParentChild.hbm.xml" };
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( BackrefTest.class );
+	}
+
+	public void testBackRef() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Parent p = new Parent("Marc");
+		Parent p2 = new Parent("Nathalie");
+		Child c = new Child("Elvira");
+		Child c2 = new Child("Blase");
+		p.getChildren().add(c);
+		p.getChildren().add(c2);
+		s.persist(p);
+		s.persist(p2);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		c = (Child) s.get(Child.class, "Elvira");
+		c.setAge(2);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		p = (Parent) s.get(Parent.class, "Marc");
+		c = (Child) s.get(Child.class, "Elvira");
+		c.setAge(18);
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		p = (Parent) s.get(Parent.class, "Marc");
+		p2 = (Parent) s.get(Parent.class, "Nathalie");
+		c = (Child) s.get(Child.class, "Elvira");
+		assertEquals( p.getChildren().indexOf(c), 0 );
+		p.getChildren().remove(c);
+		p2.getChildren().add(c);
+		t.commit();
+
+		s.close();
+		s = openSession();
+		t = s.beginTransaction();
+		Parent p3 = new Parent("Marion");
+		p3.getChildren().add( new Child("Gavin") );
+		s.merge(p3);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery( "delete from Child" ).executeUpdate();
+		s.createQuery( "delete from Parent" ).executeUpdate();
+		t.commit();
+		s.close();
+	}
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/BackrefTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/Child.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/Child.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/Child.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,27 @@
+//$Id: Child.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.unidir;
+
+
+/**
+ * @author Gavin King
+ */
+public class Child {
+	private String name;
+	private int age;
+	Child() {}
+	public Child(String name) {
+		this.name = name;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public int getAge() {
+		return age;
+	}
+	public void setAge(int age) {
+		this.age = age;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/Child.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/Parent.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/Parent.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/Parent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+//$Id: Parent.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.unidir;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Gavin King
+ */
+public class Parent {
+	private String name;
+	private List children = new ArrayList();
+	Parent() {}
+	public Parent(String name) {
+		this.name = name;
+	}
+	public List getChildren() {
+		return children;
+	}
+	public void setChildren(List children) {
+		this.children = children;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/Parent.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/ParentChild.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/ParentChild.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/ParentChild.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.unidir">
+
+	<class name="Parent">
+		<id name="name"/>
+		<list name="children" cascade="persist,merge">
+			<key column="parentName" not-null="true"/>
+			<list-index column="sibling"/>
+			<one-to-many class="Child"/>
+		</list>
+	</class>
+	
+	<class name="Child">
+		<id name="name"/>
+		<property name="age" not-null="true"/>
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unidir/ParentChild.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Alien.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Alien.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Alien.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,38 @@
+//$Id: Alien.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.unionsubclass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Gavin King
+ */
+public class Alien extends Being {
+	private String species;
+	private Hive hive;
+	private List hivemates = new ArrayList();
+	/**
+	 * @return Returns the species.
+	 */
+	public String getSpecies() {
+		return species;
+	}
+	/**
+	 * @param species The species to set.
+	 */
+	public void setSpecies(String species) {
+		this.species = species;
+	}
+	public Hive getHive() {
+		return hive;
+	}
+	public void setHive(Hive hive) {
+		this.hive = hive;
+	}
+	public List getHivemates() {
+		return hivemates;
+	}
+	public void setHivemates(List hivemates) {
+		this.hivemates = hivemates;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Alien.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Being.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Being.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Being.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,72 @@
+//$Id: Being.java 6007 2005-03-04 12:01:43Z oneovthafew $
+package org.hibernate.test.unionsubclass;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Gavin King
+ */
+public abstract class Being {
+	private long id;
+	private String identity;
+	private Location location;
+	private List things = new ArrayList();
+	private Map info = new HashMap();
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the identity.
+	 */
+	public String getIdentity() {
+		return identity;
+	}
+	/**
+	 * @param identity The identity to set.
+	 */
+	public void setIdentity(String identity) {
+		this.identity = identity;
+	}
+	/**
+	 * @return Returns the location.
+	 */
+	public Location getLocation() {
+		return location;
+	}
+	/**
+	 * @param location The location to set.
+	 */
+	public void setLocation(Location location) {
+		this.location = location;
+	}
+	public String getSpecies() {
+		return null;
+	}
+
+	public List getThings() {
+		return things;
+	}
+	public void setThings(List things) {
+		this.things = things;
+	}
+	public Map getInfo() {
+		return info;
+	}
+	
+	public void setInfo(Map info) {
+		this.info = info;
+	}
+	
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Being.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Beings.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Beings.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Beings.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,113 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping 
+	package="org.hibernate.test.unionsubclass"
+	default-access="field">
+	
+	<class name="Being" abstract="true">
+	
+		<id name="id" unsaved-value="0" column="bid">
+			<generator class="increment"/>
+			<!--generator class="hilo">
+				<param name="table">being_id</param>
+				<param name="column">next_id</param>
+			</generator-->
+		</id>
+		
+		<property name="identity" not-null="true" column="ident"/>
+		<many-to-one name="location" not-null="true"/>
+		
+		<bag name="things" inverse="true">
+			<key column="owner"/>
+			<one-to-many class="Thing"/>
+		</bag>
+		
+		<map name="info">
+			<key column="bid"/>
+			<map-key type="string" column="attribute"/>
+			<element type="string" column="value"/>
+		</map>
+
+		<union-subclass name="Human" table="humans">
+			<property name="sex" 
+				not-null="true" 
+				update="false"/>
+			<union-subclass name="Employee" table="employees">
+				<property name="salary"/>
+			</union-subclass>
+		</union-subclass>
+		
+		<union-subclass name="Alien" table="aliens">
+			<property name="species" 
+				not-null="true" 
+				update="false"/>
+			<many-to-one name="hive" not-null="true"/>
+			<bag name="hivemates">
+				<key column="alien1"/>
+				<many-to-many column="alien2" class="Alien"/>
+			</bag>
+		</union-subclass>
+		
+	</class>
+	
+	<class name="Hive" table="hives">
+
+		<id name="id" unsaved-value="0">
+			<generator class="increment"/>
+			<!--generator class="hilo">
+				<param name="table">location_id</param>
+				<param name="column">next_id</param>
+			</generator-->
+		</id>
+
+		<many-to-one name="location" not-null="true"/>
+		
+		<bag name="members"
+			inverse="true"
+			cascade="all,delete-orphan">
+			<key column="hive"/>
+			<one-to-many class="Alien"/>
+		</bag>	
+		
+	</class>
+	
+	<class name="Location" table="locations">
+	
+		<id name="id" unsaved-value="0">
+			<generator class="increment"/>			
+			<!--generator class="hilo">
+				<param name="table">location_id</param>
+				<param name="column">next_id</param>
+			</generator-->
+		</id>
+		
+		<property name="name" not-null="true"/>
+		
+		<bag name="beings"
+			inverse="true"
+			cascade="all">
+			<key column="location"/>
+			<one-to-many class="Being"/>
+		</bag>
+		
+	</class>
+	
+	<class name="Thing" table="things">
+	
+		<id name="id" unsaved-value="0">
+			<generator class="increment"/>			
+			<!--generator class="hilo">
+				<param name="table">thing_id</param>
+				<param name="column">next_id</param>
+			</generator-->
+		</id>
+
+		<property name="description"/>
+		<many-to-one name="owner"/>
+		
+	</class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Beings.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Employee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Employee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Employee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,17 @@
+//$Id: Employee.java 6673 2005-05-03 22:59:24Z epbernard $
+package org.hibernate.test.unionsubclass;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class Employee extends Human {
+	private Double salary;
+
+	public Double getSalary() {
+		return salary;
+	}
+
+	public void setSalary(Double salary) {
+		this.salary = salary;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Hive.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Hive.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Hive.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+//$Id: Hive.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.unionsubclass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Gavin King
+ */
+public class Hive {
+	private long id;
+	private Location location;
+	private List members = new ArrayList();
+	public List getMembers() {
+		return members;
+	}
+	public void setMembers(List hives) {
+		this.members = hives;
+	}
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public Location getLocation() {
+		return location;
+	}
+	public void setLocation(Location location) {
+		this.location = location;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Hive.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Human.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Human.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Human.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,26 @@
+//$Id: Human.java 4364 2004-08-17 12:10:32Z oneovthafew $
+package org.hibernate.test.unionsubclass;
+
+/**
+ * @author Gavin King
+ */
+public class Human extends Being {
+	private char sex;
+	
+	/**
+	 * @return Returns the sex.
+	 */
+	public char getSex() {
+		return sex;
+	}
+	/**
+	 * @param sex The sex to set.
+	 */
+	public void setSex(char sex) {
+		this.sex = sex;
+	}
+	public String getSpecies() {
+		return "human";
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Human.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Location.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Location.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Location.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,61 @@
+//$Id: Location.java 4357 2004-08-17 09:20:17Z oneovthafew $
+package org.hibernate.test.unionsubclass;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * @author Gavin King
+ */
+public class Location {
+	private long id;
+	private String name;
+	private Collection beings = new ArrayList();
+	
+	Location() {}
+	
+	public Location(String name) {
+		this.name = name;
+	}
+	
+	public void addBeing(Being b) {
+		b.setLocation(this);
+		beings.add(b);
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	/**
+	 * @return Returns the beings.
+	 */
+	public Collection getBeings() {
+		return beings;
+	}
+	/**
+	 * @param beings The beings to set.
+	 */
+	public void setBeings(Collection beings) {
+		this.beings = beings;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Location.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Thing.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Thing.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Thing.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,47 @@
+//$Id: Thing.java 4418 2004-08-22 13:38:16Z oneovthafew $
+package org.hibernate.test.unionsubclass;
+
+/**
+ * @author Gavin King
+ */
+public class Thing {
+	private long id;
+	private String description;
+	private Being owner;
+	/**
+	 * @return Returns the description.
+	 */
+	public String getDescription() {
+		return description;
+	}
+	/**
+	 * @param description The description to set.
+	 */
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the owner.
+	 */
+	public Being getOwner() {
+		return owner;
+	}
+	/**
+	 * @param owner The owner to set.
+	 */
+	public void setOwner(Being owner) {
+		this.owner = owner;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/Thing.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/UnionSubclassTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/UnionSubclassTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/UnionSubclassTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,401 @@
+//$Id: UnionSubclassTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.unionsubclass;
+
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.criterion.Order;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class UnionSubclassTest extends FunctionalTestCase {
+	
+	public UnionSubclassTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "unionsubclass/Beings.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( UnionSubclassTest.class );
+	}
+	
+	public void testUnionSubclassCollection() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Location mel = new Location("Earth");
+		s.save(mel);
+		
+		Human gavin = new Human();
+		gavin.setIdentity("gavin");
+		gavin.setSex('M');
+		gavin.setLocation(mel);
+		mel.addBeing(gavin);
+		
+		gavin.getInfo().put("foo", "bar");
+		gavin.getInfo().put("x", "y");
+		
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		gavin = (Human) s.createCriteria(Human.class).uniqueResult();
+		assertEquals( gavin.getInfo().size(), 2 );
+		s.delete(gavin);
+		s.delete( gavin.getLocation() );
+		t.commit();
+		s.close();
+	}
+
+	public void testUnionSubclassFetchMode() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Location mel = new Location("Earth");
+		s.save(mel);
+		
+		Human gavin = new Human();
+		gavin.setIdentity("gavin");
+		gavin.setSex('M');
+		gavin.setLocation(mel);
+		mel.addBeing(gavin);
+		Human max = new Human();
+		max.setIdentity("max");
+		max.setSex('M');
+		max.setLocation(mel);
+		mel.addBeing(gavin);
+		
+		s.flush();
+		s.clear();
+		
+		List list = s.createCriteria(Human.class)
+			.setFetchMode("location", FetchMode.JOIN)
+			.setFetchMode("location.beings", FetchMode.JOIN)
+			.list();
+		
+		for (int i=0; i<list.size(); i++ ) {
+			Human h = (Human) list.get(i);
+			assertTrue( Hibernate.isInitialized( h.getLocation() ) );
+			assertTrue( Hibernate.isInitialized( h.getLocation().getBeings() ) );
+			s.delete(h);
+		}
+		s.delete( s.get( Location.class, new Long(mel.getId()) ) );
+		t.commit();
+		s.close();
+		
+		
+	}
+	
+	public void testUnionSubclassOneToMany() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Location mel = new Location("Melbourne, Australia");
+		Location mars = new Location("Mars");
+		s.save(mel);
+		s.save(mars);
+		
+		Human gavin = new Human();
+		gavin.setIdentity("gavin");
+		gavin.setSex('M');
+		gavin.setLocation(mel);
+		mel.addBeing(gavin);
+		
+		Alien x23y4 = new Alien();
+		x23y4.setIdentity("x23y4$$hu%3");
+		x23y4.setLocation(mars);
+		x23y4.setSpecies("martian");
+		mars.addBeing(x23y4);
+		
+		Alien yy3dk = new Alien();
+		yy3dk.setIdentity("yy3dk&*!!!");
+		yy3dk.setLocation(mars);
+		yy3dk.setSpecies("martian");
+		mars.addBeing(yy3dk);
+		
+		Hive hive = new Hive();
+		hive.setLocation(mars);
+		hive.getMembers().add(x23y4);
+		x23y4.setHive(hive);
+		hive.getMembers().add(yy3dk);
+		yy3dk.setHive(hive);
+		s.persist(hive);
+		
+		yy3dk.getHivemates().add(x23y4);
+		x23y4.getHivemates().add(yy3dk);
+		
+		s.flush();
+		s.clear();
+		
+		hive = (Hive) s.createQuery("from Hive h").uniqueResult();
+		assertFalse( Hibernate.isInitialized( hive.getMembers() ) );
+		assertEquals( hive.getMembers().size(), 2 );
+		
+		s.clear();
+		
+		hive = (Hive) s.createQuery("from Hive h left join fetch h.location left join fetch h.members").uniqueResult();
+		assertTrue( Hibernate.isInitialized( hive.getMembers() ) );
+		assertEquals( hive.getMembers().size(), 2 );
+		
+		s.clear();
+		
+		x23y4 = (Alien) s.createQuery("from Alien a left join fetch a.hivemates where a.identity like 'x%'").uniqueResult();
+		assertTrue( Hibernate.isInitialized( x23y4.getHivemates() ) );
+		assertEquals( x23y4.getHivemates().size(), 1 );
+		
+		s.clear();
+		
+		x23y4 = (Alien) s.createQuery("from Alien a where a.identity like 'x%'").uniqueResult();
+		assertFalse( Hibernate.isInitialized( x23y4.getHivemates() ) );
+		assertEquals( x23y4.getHivemates().size(), 1 );
+		
+		s.clear();
+		
+		x23y4 = (Alien) s.createCriteria(Alien.class).addOrder( Order.asc("identity") ).list().get(0);
+		s.delete( x23y4.getHive() );
+		s.delete( s.get(Location.class, new Long( mel.getId() ) ) );
+		s.delete( s.get(Location.class, new Long( mars.getId() ) ) );
+		assertTrue( s.createQuery("from Being").list().isEmpty() );
+		t.commit();
+		s.close();
+	}
+	
+	public void testUnionSubclassManyToOne() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Location mel = new Location("Melbourne, Australia");
+		Location mars = new Location("Mars");
+		s.save(mel);
+		s.save(mars);
+		
+		Human gavin = new Human();
+		gavin.setIdentity("gavin");
+		gavin.setSex('M');
+		gavin.setLocation(mel);
+		mel.addBeing(gavin);
+		
+		Alien x23y4 = new Alien();
+		x23y4.setIdentity("x23y4$$hu%3");
+		x23y4.setLocation(mars);
+		x23y4.setSpecies("martian");
+		mars.addBeing(x23y4);
+		
+		Hive hive = new Hive();
+		hive.setLocation(mars);
+		hive.getMembers().add(x23y4);
+		x23y4.setHive(hive);
+		s.persist(hive);
+		
+		Thing thing = new Thing();
+		thing.setDescription("some thing");
+		thing.setOwner(gavin);
+		gavin.getThings().add(thing);
+		s.save(thing);
+		s.flush();
+		
+		s.clear();
+		
+		thing = (Thing) s.createQuery("from Thing t left join fetch t.owner").uniqueResult();
+		assertTrue( Hibernate.isInitialized( thing.getOwner() ) );
+		assertEquals( thing.getOwner().getIdentity(), "gavin" );
+		s.clear();
+		
+		thing = (Thing) s.createQuery("select t from Thing t left join t.owner where t.owner.identity='gavin'").uniqueResult();
+		assertFalse( Hibernate.isInitialized( thing.getOwner() ) );
+		assertEquals( thing.getOwner().getIdentity(), "gavin" );
+		s.clear();
+		
+		gavin = (Human) s.createQuery("from Human h left join fetch h.things").uniqueResult();
+		assertTrue( Hibernate.isInitialized( gavin.getThings() ) );
+		assertEquals( ( (Thing) gavin.getThings().get(0) ).getDescription(), "some thing" );
+		s.clear();
+		
+		assertTrue( s.createQuery("from Being b left join fetch b.things").list().size()==2 );
+		s.clear();
+		
+		gavin = (Human) s.createQuery("from Being b join fetch b.things").uniqueResult();
+		assertTrue( Hibernate.isInitialized( gavin.getThings() ) );
+		assertEquals( ( (Thing) gavin.getThings().get(0) ).getDescription(), "some thing" );
+		s.clear();
+		
+		gavin = (Human) s.createQuery("select h from Human h join h.things t where t.description='some thing'").uniqueResult();
+		assertFalse( Hibernate.isInitialized( gavin.getThings() ) );
+		assertEquals( ( (Thing) gavin.getThings().get(0) ).getDescription(), "some thing" );
+		s.clear();
+		
+		gavin = (Human) s.createQuery("select b from Being b join b.things t where t.description='some thing'").uniqueResult();
+		assertFalse( Hibernate.isInitialized( gavin.getThings() ) );
+		assertEquals( ( (Thing) gavin.getThings().get(0) ).getDescription(), "some thing" );
+		s.clear();
+		
+		thing = (Thing) s.get( Thing.class, new Long( thing.getId() ) );
+		assertFalse( Hibernate.isInitialized( thing.getOwner() ) );
+		assertEquals( thing.getOwner().getIdentity(), "gavin" );
+		
+		thing.getOwner().getThings().remove(thing);
+		thing.setOwner(x23y4);
+		x23y4.getThings().add(thing);
+		
+		s.flush();
+		
+		s.clear();
+
+		thing = (Thing) s.get( Thing.class, new Long( thing.getId() ) );
+		assertFalse( Hibernate.isInitialized( thing.getOwner() ) );
+		assertEquals( thing.getOwner().getIdentity(), "x23y4$$hu%3" );
+		
+		s.delete(thing);
+		x23y4 = (Alien) s.createCriteria(Alien.class).uniqueResult();
+		s.delete( x23y4.getHive() );
+		s.delete( s.get(Location.class, new Long( mel.getId() ) ) );
+		s.delete( s.get(Location.class, new Long( mars.getId() ) ) );
+		assertTrue( s.createQuery("from Being").list().isEmpty() );
+		t.commit();
+		s.close();
+	}
+	
+	public void testUnionSubclass() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Location mel = new Location("Melbourne, Australia");
+		Location atl = new Location("Atlanta, GA");
+		Location mars = new Location("Mars");
+		s.save(mel); 
+		s.save(atl); 
+		s.save(mars);
+		
+		Human gavin = new Human();
+		gavin.setIdentity("gavin");
+		gavin.setSex('M');
+		gavin.setLocation(mel);
+		mel.addBeing(gavin);
+		
+		Alien x23y4 = new Alien();
+		x23y4.setIdentity("x23y4$$hu%3");
+		x23y4.setLocation(mars);
+		x23y4.setSpecies("martian");
+		mars.addBeing(x23y4);
+		
+		Hive hive = new Hive();
+		hive.setLocation(mars);
+		hive.getMembers().add(x23y4);
+		x23y4.setHive(hive);
+		s.persist(hive);
+		
+		assertEquals( s.createQuery("from Being").list().size(), 2 );
+		assertEquals( s.createQuery("from Being b where b.class = Alien").list().size(), 1 );
+		assertEquals( s.createQuery("from Alien").list().size(), 1 );
+		s.clear();
+
+		List beings = s.createQuery("from Being b left join fetch b.location").list();
+		for ( Iterator iter = beings.iterator(); iter.hasNext(); ) {
+			Being b = (Being) iter.next();
+			assertTrue( Hibernate.isInitialized( b.getLocation() ) );
+			assertNotNull( b.getLocation().getName() );
+			assertNotNull( b.getIdentity() );
+			assertNotNull( b.getSpecies() );
+		}
+		assertEquals( beings.size(), 2 );
+		s.clear();
+		
+		beings = s.createQuery("from Being").list();
+		for ( Iterator iter = beings.iterator(); iter.hasNext(); ) {
+			Being b = (Being) iter.next();
+			assertFalse( Hibernate.isInitialized( b.getLocation() ) );
+			assertNotNull( b.getLocation().getName() );
+			assertNotNull( b.getIdentity() );
+			assertNotNull( b.getSpecies() );
+		}
+		assertEquals( beings.size(), 2 );
+		s.clear();
+		
+		List locations = s.createQuery("from Location").list(); 
+		int count = 0;
+		for ( Iterator iter = locations.iterator(); iter.hasNext(); ) {
+			Location l = (Location) iter.next();
+			assertNotNull( l.getName() );
+			Iterator iter2 = l.getBeings().iterator();
+			while ( iter2.hasNext() ) {
+				count++;
+				assertSame( ( (Being) iter2.next() ).getLocation(), l );
+			}
+		}
+		assertEquals(count, 2);
+		assertEquals( locations.size(), 3 );
+		s.clear();
+
+		locations = s.createQuery("from Location loc left join fetch loc.beings").list(); 
+		count = 0;
+		for ( Iterator iter = locations.iterator(); iter.hasNext(); ) {
+			Location l = (Location) iter.next();
+			assertNotNull( l.getName() );
+			Iterator iter2 = l.getBeings().iterator();
+			while ( iter2.hasNext() ) {
+				count++;
+				assertSame( ( (Being) iter2.next() ).getLocation(), l );
+			}
+		}
+		assertEquals(count, 2);
+		assertEquals( locations.size(), 3 );
+		s.clear();
+
+		gavin = (Human) s.get( Human.class, new Long( gavin.getId() ) );
+		atl = (Location) s.get( Location.class, new Long( atl.getId() ) );
+		
+ 		atl.addBeing(gavin);
+		assertEquals( s.createQuery("from Human h where h.location.name like '%GA'").list().size(), 1 );
+		s.delete(gavin);
+		x23y4 = (Alien) s.createCriteria(Alien.class).uniqueResult();
+		s.delete( x23y4.getHive() );
+		assertTrue( s.createQuery("from Being").list().isEmpty() );
+		
+		s.createQuery("delete from Location").executeUpdate();
+		t.commit();
+		s.close();
+	}
+
+	public void testNestedUnionedSubclasses() throws Exception {
+		Session s;
+		Transaction tx;
+		s = openSession();
+		tx = s.beginTransaction();
+		Location mel = new Location("Earth");
+		Human marcf = new Human();
+		marcf.setIdentity("marc");
+		marcf.setSex('M');
+		mel.addBeing(marcf);
+		Employee steve = new Employee();
+		steve.setIdentity("steve");
+		steve.setSex('M');
+		steve.setSalary( new Double(0) );
+		mel.addBeing(steve);
+		s.persist(mel);
+		tx.commit();
+		s.close();
+		s = openSession();
+		tx = s.beginTransaction();
+		Query q = s.createQuery( "from Being h where h.identity = :name1 or h.identity = :name2" );
+		q.setString("name1", "marc");
+		q.setString("name2", "steve");
+		final List result = q.list();
+		assertEquals( 2, result.size() );
+		s.delete( result.get(0) );
+		s.delete( result.get(1) );
+		s.delete( ( (Human) result.get(0) ).getLocation() );
+		tx.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass/UnionSubclassTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Address.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Address.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Address.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,11 @@
+//$Id: Address.java 7192 2005-06-18 14:40:15Z oneovthafew $
+package org.hibernate.test.unionsubclass2;
+
+/**
+ * @author Gavin King
+ */
+public class Address {
+	public String address;
+	public String zip;
+	public String country;
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Address.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Customer.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Customer.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Customer.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,35 @@
+//$Id: Customer.java 7192 2005-06-18 14:40:15Z oneovthafew $
+package org.hibernate.test.unionsubclass2;
+
+/**
+ * @author Gavin King
+ */
+public class Customer extends Person {
+	private Employee salesperson;
+	private String comments;
+
+	/**
+	 * @return Returns the salesperson.
+	 */
+	public Employee getSalesperson() {
+		return salesperson;
+	}
+	/**
+	 * @param salesperson The salesperson to set.
+	 */
+	public void setSalesperson(Employee salesperson) {
+		this.salesperson = salesperson;
+	}
+	/**
+	 * @return Returns the comments.
+	 */
+	public String getComments() {
+		return comments;
+	}
+	/**
+	 * @param comments The comments to set.
+	 */
+	public void setComments(String comments) {
+		this.comments = comments;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Customer.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Employee.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Employee.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Employee.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+//$Id: Employee.java 7192 2005-06-18 14:40:15Z oneovthafew $
+package org.hibernate.test.unionsubclass2;
+
+import java.math.BigDecimal;
+
+/**
+ * @author Gavin King
+ */
+public class Employee extends Person {
+	private String title;
+	private BigDecimal salary;
+	private Employee manager;
+	/**
+	 * @return Returns the title.
+	 */
+	public String getTitle() {
+		return title;
+	}
+	/**
+	 * @param title The title to set.
+	 */
+	public void setTitle(String title) {
+		this.title = title;
+	}
+	/**
+	 * @return Returns the manager.
+	 */
+	public Employee getManager() {
+		return manager;
+	}
+	/**
+	 * @param manager The manager to set.
+	 */
+	public void setManager(Employee manager) {
+		this.manager = manager;
+	}
+	/**
+	 * @return Returns the salary.
+	 */
+	public BigDecimal getSalary() {
+		return salary;
+	}
+	/**
+	 * @param salary The salary to set.
+	 */
+	public void setSalary(BigDecimal salary) {
+		this.salary = salary;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Employee.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Person.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Person.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Person.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+
+  This mapping demonstrates 
+
+     (1) a table-per-subclass mapping strategy
+         
+     (2) a simple component mapping
+     
+     (3) recursive associations withing an inheritance tree
+     
+-->
+
+<hibernate-mapping 
+	package="org.hibernate.test.unionsubclass2"
+	default-access="field">
+	
+	<class name="Person" table="UPerson">
+		
+		<id name="id" 
+			column="person_id" 
+			unsaved-value="0">
+			<generator class="increment"/>
+		</id>
+				
+		<property name="name" 
+			unique-key="NameUniqueKey"
+			not-null="true"
+			length="80"/>
+		<property name="sex" 
+			not-null="true"
+			update="false"/>
+		
+		<component name="address">
+			<property name="address" index="AddressIndex"/>
+			<property name="zip" index="AddressIndex"/>
+			<property name="country"/>
+		</component>
+		
+		<union-subclass name="Employee" table="UEmployee">
+				<property name="title" 
+					not-null="true" 
+					length="20"/>
+				<property name="salary" 
+					length="0"/>
+				<many-to-one name="manager"/>
+		</union-subclass>
+		
+		<union-subclass name="Customer" table="UCustomer">
+				<property name="comments"/>
+				<many-to-one name="salesperson"/>
+		</union-subclass>
+		
+	</class>
+	
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Person.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,70 @@
+//$Id: Person.java 7192 2005-06-18 14:40:15Z oneovthafew $
+package org.hibernate.test.unionsubclass2;
+
+
+/**
+ * @author Gavin King
+ */
+public class Person {
+	private long id;
+	private String name;
+	private char sex;
+	private Address address = new Address();
+	/**
+	 * @return Returns the address.
+	 */
+	public Address getAddress() {
+		return address;
+	}
+
+	public void setAddress(String string) {
+		this.address.address = string;
+	}
+
+	public void setZip(String string) {
+		this.address.zip = string;
+	}
+
+	public void setCountry(String string) {
+		this.address.country = string;
+	}
+
+	
+	/**
+	 * @return Returns the sex.
+	 */
+	public char getSex() {
+		return sex;
+	}
+	/**
+	 * @param sex The sex to set.
+	 */
+	public void setSex(char sex) {
+		this.sex = sex;
+	}
+	/**
+	 * @return Returns the id.
+	 */
+	public long getId() {
+		return id;
+	}
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(long id) {
+		this.id = id;
+	}
+	/**
+	 * @return Returns the identity.
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param identity The identity to set.
+	 */
+	public void setName(String identity) {
+		this.name = identity;
+	}
+
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/UnionSubclassTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/UnionSubclassTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/UnionSubclassTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,153 @@
+//$Id: UnionSubclassTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.unionsubclass2;
+
+import java.math.BigDecimal;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.criterion.Expression;
+import org.hibernate.criterion.Property;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Gavin King
+ */
+public class UnionSubclassTest extends FunctionalTestCase {
+	
+	public UnionSubclassTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "unionsubclass2/Person.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( UnionSubclassTest.class );
+	}
+
+	public void testUnionSubclass() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		
+		Employee mark = new Employee();
+		mark.setName("Mark");
+		mark.setTitle("internal sales");
+		mark.setSex('M');
+		mark.setAddress("buckhead");
+		mark.setZip("30305");
+		mark.setCountry("USA");
+		
+		Customer joe = new Customer();
+		joe.setName("Joe");
+		joe.setAddress("San Francisco");
+		joe.setZip("XXXXX");
+		joe.setCountry("USA");
+		joe.setComments("Very demanding");
+		joe.setSex('M');
+		joe.setSalesperson(mark);
+		
+		Person yomomma = new Person();
+		yomomma.setName("mum");
+		yomomma.setSex('F');
+		
+		s.save(yomomma);
+		s.save(mark);
+		s.save(joe);
+		
+		assertEquals( s.createQuery("from java.io.Serializable").list().size(), 0 );
+		
+		assertEquals( s.createQuery("from Person").list().size(), 3 );
+		assertEquals( s.createQuery("from Person p where p.class = Customer").list().size(), 1 );
+		assertEquals( s.createQuery("from Person p where p.class = Person").list().size(), 1 );
+		s.clear();
+
+		List customers = s.createQuery("from Customer c left join fetch c.salesperson").list();
+		for ( Iterator iter = customers.iterator(); iter.hasNext(); ) {
+			Customer c = (Customer) iter.next();
+			assertTrue( Hibernate.isInitialized( c.getSalesperson() ) );
+			assertEquals( c.getSalesperson().getName(), "Mark" );
+		}
+		assertEquals( customers.size(), 1 );
+		s.clear();
+		
+		customers = s.createQuery("from Customer").list();
+		for ( Iterator iter = customers.iterator(); iter.hasNext(); ) {
+			Customer c = (Customer) iter.next();
+			assertFalse( Hibernate.isInitialized( c.getSalesperson() ) );
+			assertEquals( c.getSalesperson().getName(), "Mark" );
+		}
+		assertEquals( customers.size(), 1 );
+		s.clear();
+		
+
+		mark = (Employee) s.get( Employee.class, new Long( mark.getId() ) );
+		joe = (Customer) s.get( Customer.class, new Long( joe.getId() ) );
+		
+ 		mark.setZip("30306");
+		assertEquals( s.createQuery("from Person p where p.address.zip = '30306'").list().size(), 1 );
+
+		if ( supportsRowValueConstructorSyntaxInInList() ) {
+			s.createCriteria(Person.class).add( 
+					Expression.in("address", new Address[] { mark.getAddress(), joe.getAddress() } ) 
+			).list();
+		}
+		
+		s.delete(mark);
+		s.delete(joe);
+		s.delete(yomomma);
+		assertTrue( s.createQuery("from Person").list().isEmpty() );
+		t.commit();
+		s.close();
+	}
+	
+	public void testQuerySubclassAttribute() {
+		if ( getDialect() instanceof HSQLDialect ) {
+			return; // TODO : why??
+		}
+		
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person p = new Person();
+		p.setName("Emmanuel");
+		p.setSex('M');
+		s.persist(p);
+		Employee q = new Employee();
+		q.setName("Steve");
+		q.setSex('M');
+		q.setTitle("Mr");
+		q.setSalary( new BigDecimal(1000) );
+		s.persist(q);
+
+		List result = s.createQuery("from Person where salary > 100").list();
+		assertEquals( result.size(), 1 );
+		assertSame( result.get(0), q );
+		
+		result = s.createQuery("from Person where salary > 100 or name like 'E%'").list();
+		assertEquals( result.size(), 2 );		
+
+		result = s.createCriteria(Person.class)
+			.add( Property.forName("salary").gt( new BigDecimal(100) ) )
+			.list();
+		assertEquals( result.size(), 1 );
+		assertSame( result.get(0), q );
+
+		result = s.createQuery("select salary from Person where salary > 100").list();
+		assertEquals( result.size(), 1 );
+		assertEquals( ( (BigDecimal) result.get(0) ).intValue(), 1000 );
+		
+		s.delete(p);
+		s.delete(q);
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/unionsubclass2/UnionSubclassTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/UserCollectionTypeSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/UserCollectionTypeSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/UserCollectionTypeSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+package org.hibernate.test.usercollection;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.usercollection.basic.UserCollectionTypeTest;
+import org.hibernate.test.usercollection.parameterized.ParameterizedUserCollectionTypeTest;
+
+/**
+ * Suite for testing various aspects of user collection types.
+ *
+ * @author Steve Ebersole
+ */
+public class UserCollectionTypeSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "user collection type tests" );
+		suite.addTest( UserCollectionTypeTest.suite() );
+		suite.addTest( ParameterizedUserCollectionTypeTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/Email.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/Email.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/Email.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+//$Id$
+package org.hibernate.test.usercollection.basic;
+
+/**
+ * @author Gavin King
+ */
+public class Email {
+	
+	private Long id;
+	private String address;
+	
+	Email() {}
+	
+	public String getAddress() {
+		return address;
+	}
+	public void setAddress(String type) {
+		this.address = type;
+	}
+	public Email(String type) {
+		this.address = type;
+	}
+	public boolean equals(Object that) {
+		if ( !(that instanceof Email) ) return false;
+		Email p = (Email) that;
+		return this.address.equals(p.address);
+	}
+	public int hashCode() {
+		return address.hashCode();
+	}
+	
+	public Long getId() {
+		return id;
+	}
+	
+	private void setId(Long id) {
+		this.id = id;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/IMyList.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/IMyList.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/IMyList.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,7 @@
+package org.hibernate.test.usercollection.basic;
+
+import java.util.List;
+
+public interface IMyList extends List {
+
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/MyList.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/MyList.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/MyList.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,14 @@
+package org.hibernate.test.usercollection.basic;
+
+import java.util.ArrayList;
+
+/**
+ * A custom collection class. We extend a java.util.Collection class, but that is not required. 
+ * It could be totally non-java-collection type, but then we would need to implement all the PersistentCollection methods.
+ * 
+ * @author max
+ *
+ */
+public class MyList extends ArrayList implements IMyList {
+	
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/MyListType.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/MyListType.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/MyListType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,60 @@
+package org.hibernate.test.usercollection.basic;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.usertype.UserCollectionType;
+
+public class MyListType implements UserCollectionType {
+
+	static int lastInstantiationRequest = -2;
+
+	public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister) throws HibernateException {
+		return new PersistentMyList(session);
+	}
+
+	public PersistentCollection wrap(SessionImplementor session, Object collection) {
+		if ( session.getEntityMode()==EntityMode.DOM4J ) {
+			throw new IllegalStateException("dom4j not supported");
+		}
+		else {
+			return new PersistentMyList( session, (IMyList) collection );
+		}
+	}
+
+	public Iterator getElementsIterator(Object collection) {
+		return ( (IMyList) collection ).iterator();
+	}
+
+	public boolean contains(Object collection, Object entity) {
+		return ( (IMyList) collection ).contains(entity);
+	}
+
+	public Object indexOf(Object collection, Object entity) {
+		int l = ( (IMyList) collection ).indexOf(entity);
+		if(l<0) {
+			return null;
+		} else {
+			return new Integer(l);
+		}
+	}
+
+	public Object replaceElements(Object original, Object target, CollectionPersister persister, Object owner, Map copyCache, SessionImplementor session) throws HibernateException {
+		IMyList result = (IMyList) target;
+		result.clear();
+		result.addAll((MyList)original);
+		return result;
+	}
+
+	public Object instantiate(int anticipatedSize) {
+		lastInstantiationRequest = anticipatedSize;
+		return new MyList();
+	}
+
+	
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/PersistentMyList.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/PersistentMyList.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/PersistentMyList.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,18 @@
+package org.hibernate.test.usercollection.basic;
+
+import org.hibernate.collection.PersistentList;
+import org.hibernate.engine.SessionImplementor;
+
+public class PersistentMyList extends PersistentList implements IMyList {
+
+	public PersistentMyList(SessionImplementor session) {
+		super(session);
+	}
+
+	public PersistentMyList(SessionImplementor session, IMyList list) {
+		super(session, list);
+	}
+
+	
+	
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,39 @@
+//$Id$
+package org.hibernate.test.usercollection.basic;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Gavin King
+ */
+public class User {
+	private String userName;
+	private IMyList emailAddresses = new MyList();
+	private Map sessionData = new HashMap();
+
+	User() {}
+	public User(String name) {
+		userName = name;
+	}
+	
+	public String getUserName() {
+		return userName;
+	}
+	public void setUserName(String userName) {
+		this.userName = userName;
+	}
+	public List getEmailAddresses() {
+		return emailAddresses;
+	}
+	public void setEmailAddresses(IMyList emailAddresses) {
+		this.emailAddresses = emailAddresses;
+	}
+	public Map getSessionData() {
+		return sessionData;
+	}
+	public void setSessionData(Map sessionData) {
+		this.sessionData = sessionData;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/UserCollectionTypeTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/UserCollectionTypeTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/UserCollectionTypeTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,63 @@
+//$Id $
+package org.hibernate.test.usercollection.basic;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Max Rydahl Andersen
+ */
+public class UserCollectionTypeTest extends FunctionalTestCase {
+	
+	public UserCollectionTypeTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "usercollection/basic/UserPermissions.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( UserCollectionTypeTest.class );
+	}
+
+	public void testBasicOperation() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User u = new User("max");
+		u.getEmailAddresses().add( new Email("max at hibernate.org") );
+		u.getEmailAddresses().add( new Email("max.andersen at jboss.com") );
+		s.persist(u);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		User u2 = (User) s.createCriteria(User.class).uniqueResult();
+		assertTrue( Hibernate.isInitialized( u2.getEmailAddresses() ) );
+		assertEquals( u2.getEmailAddresses().size(), 2 );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		u2 = ( User ) s.get( User.class, u.getUserName() );
+		u2.getEmailAddresses().size();
+		assertEquals( 2, MyListType.lastInstantiationRequest );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( u );
+		t.commit();
+		s.close();
+	}
+
+}
+

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/UserPermissions.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/UserPermissions.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/basic/UserPermissions.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+    This mapping is a basic example of how to write a UserCollectionType.
+-->
+
+<hibernate-mapping package="org.hibernate.test.usercollection.basic">
+	
+	<import class="Permission"/>
+
+	<class name="User" table="UC_BSC_USER">
+		<id name="userName"/>
+		<list name="emailAddresses" fetch="join" cascade="all, delete-orphan" collection-type="org.hibernate.test.usercollection.basic.MyListType">
+			<key column="userName"/>
+			<list-index column="displayOrder" base="1"/>
+			<one-to-many class="Email"/>
+		</list>		
+	</class>
+
+    <class name="Email">
+    	<id name="id">
+    	 <generator class="native"/>
+    	</id>
+    	<property name="address"/>
+    </class>	
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/DefaultableList.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/DefaultableList.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/DefaultableList.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,13 @@
+package org.hibernate.test.usercollection.parameterized;
+
+import java.util.List;
+
+/**
+ * Our specialized collection contract
+ *
+ * @author Holger Brands
+ * @author Steve Ebersole
+ */
+public interface DefaultableList extends List {
+    public String getDefaultValue();
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/DefaultableListImpl.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/DefaultableListImpl.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/DefaultableListImpl.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,28 @@
+package org.hibernate.test.usercollection.parameterized;
+
+import java.util.ArrayList;
+
+/**
+ * Implementation of our specialized collection contract
+ *
+ * @author Holger Brands
+ * @author Steve Ebersole
+ */
+public class DefaultableListImpl extends ArrayList implements DefaultableList {
+    private String defaultValue;
+
+	public DefaultableListImpl() {
+	}
+
+	public DefaultableListImpl(int anticipatedSize) {
+		super( anticipatedSize + ( int ) Math.ceil( anticipatedSize * .75f ) );
+	}
+
+	public String getDefaultValue() {
+        return defaultValue;
+    }
+
+    public void setDefaultValue(String defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/DefaultableListType.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/DefaultableListType.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/DefaultableListType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,75 @@
+package org.hibernate.test.usercollection.parameterized;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.List;
+
+import org.hibernate.usertype.UserCollectionType;
+import org.hibernate.usertype.ParameterizedType;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.EntityMode;
+
+/**
+ * Our Hibernate type-system extension for defining our specialized collection
+ * contract.
+ *
+ * @author Holger Brands
+ * @author Steve Ebersole
+ */
+public class DefaultableListType implements UserCollectionType, ParameterizedType {
+    private String defaultValue;
+
+	public Object instantiate(int anticipatedSize) {
+		DefaultableListImpl list = anticipatedSize < 0 ? new DefaultableListImpl() : new DefaultableListImpl( anticipatedSize );
+		list.setDefaultValue( defaultValue );
+		return list;
+	}
+
+	public PersistentCollection instantiate(
+			SessionImplementor session,
+			CollectionPersister persister) {
+		return new PersistentDefaultableList( session );
+	}
+
+	public PersistentCollection wrap(SessionImplementor session, Object collection) {
+		if ( session.getEntityMode() == EntityMode.DOM4J ) {
+			throw new IllegalStateException( "dom4j not supported" );
+		}
+		else {
+			return new PersistentDefaultableList( session, ( List ) collection );
+		}
+	}
+
+	public Iterator getElementsIterator(Object collection) {
+		return ( ( DefaultableList ) collection ).iterator();
+	}
+
+	public boolean contains(Object collection, Object entity) {
+		return ( ( DefaultableList ) collection ).contains( entity );
+	}
+
+	public Object indexOf(Object collection, Object entity) {
+		int index = ( ( DefaultableList ) collection ).indexOf( entity );
+		return index >= 0 ? new Integer( index ) : null;
+	}
+
+	public Object replaceElements(
+			Object original,
+			Object target,
+			CollectionPersister persister,
+			Object owner,
+			Map copyCache,
+			SessionImplementor session) {
+		DefaultableList result = ( DefaultableList ) target;
+		result.clear();
+		result.addAll( ( DefaultableList ) original );
+		return result;
+	}
+
+	public void setParameterValues(Properties parameters) {
+        defaultValue = parameters.getProperty( "default" );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/Entity.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/Entity.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/Entity.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+package org.hibernate.test.usercollection.parameterized;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Our test entity
+ *
+ * @author Steve Ebersole
+ */
+public class Entity {
+	private String name;
+	private List values = new ArrayList();
+
+	public Entity() {
+	}
+
+	public Entity(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public List getValues() {
+		return values;
+	}
+
+	public void setValues(List values) {
+		this.values = values;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/Mapping.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/Mapping.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/Mapping.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.usercollection.parameterized" default-access="field">
+
+    <typedef name="DefaultableList" class="org.hibernate.test.usercollection.parameterized.DefaultableListType">
+        <param name="default">Hello</param>
+    </typedef>
+
+    <class name="Entity">
+        <id name="name" type="string"/>
+        <list name="values" fetch="join" table="ENT_VAL" collection-type="DefaultableList">
+            <key column="ENT_ID"/>
+            <list-index column="POS"/>
+            <element type="string" column="VAL"/>
+        </list>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/ParameterizedUserCollectionTypeTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/ParameterizedUserCollectionTypeTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/ParameterizedUserCollectionTypeTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,49 @@
+package org.hibernate.test.usercollection.parameterized;
+
+import junit.framework.Test;
+
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.Hibernate;
+
+/**
+ * Tes for parameterized user collection types.
+ *
+ * @author Holger Brands
+ * @author Steve Ebersole
+ */
+public class ParameterizedUserCollectionTypeTest extends FunctionalTestCase {
+	public ParameterizedUserCollectionTypeTest(String string) {
+		super( string );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ParameterizedUserCollectionTypeTest.class );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "usercollection/parameterized/Mapping.hbm.xml" };
+	}
+
+	public void testBasicOperation() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Entity entity = new Entity( "tester" );
+		entity.getValues().add( "value-1" );
+		s.persist( entity );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		entity = ( Entity ) s.get( Entity.class, "tester" );
+		assertTrue( Hibernate.isInitialized( entity.getValues() ) );
+		assertEquals( 1, entity.getValues().size() );
+        assertEquals( "Hello", ( ( DefaultableList ) entity.getValues() ).getDefaultValue() );
+		s.delete( entity );
+		t.commit();
+		s.close();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/PersistentDefaultableList.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/PersistentDefaultableList.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/usercollection/parameterized/PersistentDefaultableList.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,29 @@
+package org.hibernate.test.usercollection.parameterized;
+
+import java.util.List;
+
+import org.hibernate.collection.PersistentList;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * The "persistent wrapper" around our specialized collection contract
+ *
+ * @author Holger Brands
+ * @author Steve Ebersole
+ */
+public class PersistentDefaultableList extends PersistentList implements DefaultableList {
+	public PersistentDefaultableList(SessionImplementor session) {
+		super( session );
+	}
+
+	public PersistentDefaultableList(SessionImplementor session, List list) {
+		super( session, list );
+	}
+
+	public PersistentDefaultableList() {
+	}
+
+	public String getDefaultValue() {
+		return ( ( DefaultableList ) this.list ).getDefaultValue();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/PropertiesHelperTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/PropertiesHelperTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/PropertiesHelperTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,109 @@
+package org.hibernate.test.util;
+
+import java.util.Properties;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.junit.UnitTestCase;
+import org.hibernate.util.PropertiesHelper;
+
+/**
+ * @author Steve Ebersole
+ */
+public class PropertiesHelperTest extends UnitTestCase {
+
+	private Properties props;
+
+	public PropertiesHelperTest(String string) {
+		super( string );
+	}
+
+	public static Test suite() {
+		return new TestSuite( PropertiesHelperTest.class );
+	}
+
+	protected void setUp() throws Exception {
+		props = new Properties();
+
+		props.setProperty( "my.nonexistent.prop", "${}" );
+
+		props.setProperty( "my.string.prop", "${test.my.sys.string.prop}" );
+		System.setProperty( "test.my.sys.string.prop", "string" );
+
+		props.setProperty( "my.boolean.prop", "${test.my.sys.boolean.prop}" );
+		System.setProperty( "test.my.sys.boolean.prop", "true" );
+
+		props.setProperty( "my.int.prop", "${test.my.sys.int.prop}" );
+		System.setProperty( "test.my.sys.int.prop", "1" );
+
+		props.setProperty( "my.integer.prop", "${test.my.sys.integer.prop}" );
+		System.setProperty( "test.my.sys.integer.prop", "1" );
+
+		props.setProperty( "partial.prop1", "${somedir}/middle/dir/${somefile}" );
+		props.setProperty( "partial.prop2", "basedir/${somedir}/myfile.txt" );
+		System.setProperty( "somedir", "tmp" );
+		System.setProperty( "somefile", "tmp.txt" );
+
+		props.setProperty( "parse.error", "steve" );
+	}
+
+	public void testPlaceholderReplacement() {
+		PropertiesHelper.resolvePlaceHolders( props );
+
+		String str = PropertiesHelper.getString( "my.nonexistent.prop", props, "did.not.exist" );
+		assertEquals( "did.not.exist", str );
+		str = PropertiesHelper.getString( "my.nonexistent.prop", props, null );
+		assertNull( str );
+		str = PropertiesHelper.getString( "my.string.prop", props, "na" );
+		assertEquals( "replacement did not occur", "string", str );
+		str = PropertiesHelper.getString( "my.string.prop", props, "did.not.exist" );
+		assertEquals( "replacement did not occur", "string", str );
+
+		boolean bool = PropertiesHelper.getBoolean( "my.nonexistent.prop", props );
+		assertFalse( "non-exists as boolean", bool );
+		bool = PropertiesHelper.getBoolean( "my.nonexistent.prop", props, false );
+		assertFalse( "non-exists as boolean", bool );
+		bool = PropertiesHelper.getBoolean( "my.nonexistent.prop", props, true );
+		assertTrue( "non-exists as boolean", bool );
+		bool = PropertiesHelper.getBoolean( "my.boolean.prop", props );
+		assertTrue( "boolean replacement did not occur", bool );
+		bool = PropertiesHelper.getBoolean( "my.boolean.prop", props, false );
+		assertTrue( "boolean replacement did not occur", bool );
+
+		int i = PropertiesHelper.getInt( "my.nonexistent.prop", props, -1 );
+		assertEquals( -1, i );
+		i = PropertiesHelper.getInt( "my.int.prop", props, 100 );
+		assertEquals( 1, i );
+
+		Integer I = PropertiesHelper.getInteger( "my.nonexistent.prop", props );
+		assertNull( I );
+		I = PropertiesHelper.getInteger( "my.integer.prop", props );
+		assertEquals( I, new Integer( 1 ) );
+
+		str = props.getProperty( "partial.prop1" );
+		assertEquals( "partial replacement (ends)", "tmp/middle/dir/tmp.txt", str );
+
+		str = props.getProperty( "partial.prop2" );
+		assertEquals( "partial replacement (midst)", "basedir/tmp/myfile.txt", str );
+	}
+
+	public void testParseExceptions() {
+		boolean b = PropertiesHelper.getBoolean( "parse.error", props );
+		assertFalse( "parse exception case - boolean", b );
+
+		try {
+			PropertiesHelper.getInt( "parse.error", props, 20 );
+			fail( "parse exception case - int" );
+		}
+		catch( NumberFormatException expected ) {
+		}
+
+		try {
+			PropertiesHelper.getInteger( "parse.error", props );
+			fail( "parse exception case - Integer" );
+		}
+		catch( NumberFormatException expected ) {
+		}
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/StringHelperTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/StringHelperTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/StringHelperTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+package org.hibernate.test.util;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.junit.UnitTestCase;
+import org.hibernate.util.StringHelper;
+
+/**
+ * @author Steve Ebersole
+ */
+public class StringHelperTest extends UnitTestCase {
+
+	public StringHelperTest(String string) {
+		super( string );
+	}
+
+	public static Test suite() {
+		return new TestSuite( StringHelperTest.class );
+	}
+
+	public void testAliasGeneration() {
+		assertSimpleAlias( "xyz", "xyz_" );
+		assertSimpleAlias( "_xyz", "xyz_" );
+		assertSimpleAlias( "!xyz", "xyz_" );
+		assertSimpleAlias( "abcdefghijklmnopqrstuvwxyz", "abcdefghij_" );
+	}
+
+	private void assertSimpleAlias(String source, String expected) {
+		assertEquals( expected, StringHelper.generateAlias( source ) );
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/UtilSuite.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/UtilSuite.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/UtilSuite.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,20 @@
+package org.hibernate.test.util;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.hibernate.test.util.dtd.EntityResolverTest;
+
+/**
+ * todo: describe UtilSuite
+ *
+ * @author Steve Ebersole
+ */
+public class UtilSuite {
+	public static Test suite() {
+		TestSuite suite = new TestSuite( "Utility package tests" );
+		suite.addTest( PropertiesHelperTest.suite() );
+		suite.addTest( EntityResolverTest.suite() );
+		suite.addTest( StringHelperTest.suite() );
+		return suite;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/Child.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/Child.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/Child.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,36 @@
+package org.hibernate.test.util.dtd;
+
+/**
+ * The Child class.
+ *
+ * @author Steve Ebersole
+ */
+public class Child {
+	private Long id;
+	private int age;
+	private Parent parent;
+
+	public Child() {
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public Parent getParent() {
+		return parent;
+	}
+
+	public int getAge() {
+		return age;
+	}
+
+	public void setAge(int age) {
+		this.age = age;
+	}
+
+
+	/*package*/ void injectParent(Parent parent) {
+		this.parent = parent;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/EntityResolverTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/EntityResolverTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/EntityResolverTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,32 @@
+package org.hibernate.test.util.dtd;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.junit.UnitTestCase;
+
+
+/**
+ * @author Steve Ebersole
+ */
+public class EntityResolverTest extends UnitTestCase {
+
+	public EntityResolverTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new TestSuite( EntityResolverTest.class );
+	}
+
+	public void testEntityIncludeResolution() {
+		// Parent.hbm.xml contains the following entity include:
+		//		<!ENTITY child SYSTEM "classpath://org/hibernate/test/util/dtd/child.xml">
+		// which we are expecting the Hibernate custom entity resolver to be able to resolve
+		// locally via classpath lookup.
+		Configuration cfg = new Configuration();
+		cfg.addResource( "org/hibernate/test/util/dtd/Parent.hbm.xml" );
+		cfg.buildMappings();
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/Parent.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/Parent.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/Parent.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [
+        <!ENTITY child SYSTEM "classpath://org/hibernate/test/util/dtd/child.xml">
+]>
+
+
+<hibernate-mapping package="org.hibernate.test.util.dtd" default-access="field">
+
+	<class name="Parent">
+		<id name="id" column="ID">
+            <generator class="increment"/>
+        </id>
+		<list name="children" inverse="true" cascade="persist,merge">
+			<key column="PRNT_ID" not-null="true"/>
+			<list-index column="SIBLING_ORD"/>
+			<one-to-many class="Child"/>
+		</list>
+	</class>
+
+    &child;
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/Parent.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/Parent.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/Parent.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+package org.hibernate.test.util.dtd;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * The Parent class.
+ *
+ * @author Steve Ebersole
+ */
+public class Parent {
+	private Long id;
+	private Set children = new HashSet();
+
+	public Long getId() {
+		return id;
+	}
+
+	public Iterator getChildren() {
+		return children.iterator();
+	}
+
+	public Child newChild() {
+		Child child = new Child();
+		child.setAge( 0 );
+
+		child.injectParent( this );
+		this.children.add( child );
+
+		return child;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/child.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/child.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/util/dtd/child.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,9 @@
+
+
+    <class name="Child">
+		<id name="id" column="ID">
+            <generator class="increment"/>
+        </id>
+		<property name="age" column="AGE" not-null="true"/>
+        <many-to-one name="parent" class="Parent" column="PRNT_ID"/>
+    </class>
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Person.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Person.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Person.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,43 @@
+//$Id: Person.java 7676 2005-07-29 06:27:10Z oneovthafew $
+package org.hibernate.test.version;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Person {
+	private String name;
+	private List things;
+	private List tasks;
+	private int version;
+	
+	Person() {}
+	public Person(String name) {
+		this.name = name;
+		this.things = new ArrayList();
+		this.tasks = new ArrayList();
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public List getThings() {
+		return things;
+	}
+	public void setThings(List things) {
+		this.things = things;
+	}
+	public int getVersion() {
+		return version;
+	}
+	public void setVersion(int version) {
+		this.version = version;
+	}
+	public List getTasks() {
+		return tasks;
+	}
+	public void setTasks(List tasks) {
+		this.tasks = tasks;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Person.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/PersonThing.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/PersonThing.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/PersonThing.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!-- 
+    Demonstrates how to control the optimistic locking behavior
+    of a collection (do changes to the collection result in
+    a version increment on the owning instance)
+ -->
+<hibernate-mapping 
+		package="org.hibernate.test.version">
+
+	<class name="Person">
+		<id name="name"/>
+		<version name="version"/>
+		<bag name="things" 
+				inverse="true"
+				cascade="all,delete-orphan"> 
+			<key column="person"/>
+			<one-to-many class="Thing"/>	
+		</bag>
+		<bag name="tasks"
+				inverse="true"
+				cascade="all,delete-orphan"
+				optimistic-lock="false"> 
+			<key column="person"/>
+			<one-to-many class="Task"/>	
+		</bag>
+	</class>
+
+    <class name="Thing">
+    	<id name="description"/>
+    	<version name="version"/>
+    	<property name="longDescription"/>
+    	<many-to-one name="person"/>
+    </class>	
+
+    <class name="Task">
+    	<id name="description"/>
+    	<version name="version"/>
+    	<many-to-one name="person"/>
+    </class>	
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/PersonThing.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Task.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Task.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Task.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,33 @@
+//$Id: Task.java 7676 2005-07-29 06:27:10Z oneovthafew $
+package org.hibernate.test.version;
+
+public class Task {
+	private String description;
+	private Person person;
+	private int version;
+	
+	public int getVersion() {
+		return version;
+	}
+	public void setVersion(int version) {
+		this.version = version;
+	}
+	Task() {}
+	public Task(String description, Person person) {
+		this.description = description;
+		this.person = person;
+		person.getTasks().add(this);
+	}
+	public String getDescription() {
+		return description;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	public Person getPerson() {
+		return person;
+	}
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Task.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Thing.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Thing.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Thing.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,40 @@
+//$Id: Thing.java 7715 2005-08-01 16:46:57Z oneovthafew $
+package org.hibernate.test.version;
+
+public class Thing {
+	private String description;
+	private Person person;
+	private int version;
+	private String longDescription;
+	
+	public int getVersion() {
+		return version;
+	}
+	public void setVersion(int version) {
+		this.version = version;
+	}
+	Thing() {}
+	public Thing(String description, Person person) {
+		this.description = description;
+		this.person = person;
+		person.getThings().add(this);
+	}
+	public String getDescription() {
+		return description;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	public Person getPerson() {
+		return person;
+	}
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+	public String getLongDescription() {
+		return longDescription;
+	}
+	public void setLongDescription(String longDescription) {
+		this.longDescription = longDescription;
+	}
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/Thing.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/VersionTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/VersionTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/VersionTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,135 @@
+//$Id: VersionTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.version;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Max Rydahl Andersen
+ */
+public class VersionTest extends FunctionalTestCase {
+	
+	public VersionTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "version/PersonThing.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( VersionTest.class );
+	}
+
+	public void testVersionShortCircuitFlush() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person gavin = new Person("Gavin");
+		new Thing("Passport", gavin);
+		s.persist(gavin);
+		t.commit();
+		s.close();
+		
+		s = openSession();
+		t = s.beginTransaction();
+		Thing passp = (Thing) s.get(Thing.class, "Passport");
+		passp.setLongDescription("blah blah blah");
+		s.createQuery("from Person").list();
+		s.createQuery("from Person").list();
+		s.createQuery("from Person").list();
+		t.commit();
+		s.close();
+		
+		assertEquals( passp.getVersion(), 1 );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.createQuery("delete from Thing").executeUpdate();
+		s.createQuery("delete from Person").executeUpdate();
+		t.commit();
+		s.close();
+	}
+	
+	public void testCollectionVersion() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person gavin = new Person("Gavin");
+		new Thing("Passport", gavin);
+		s.persist(gavin);
+		t.commit();
+		s.close();
+		
+		assertEquals(0, gavin.getVersion());
+		
+		s = openSession();
+		t = s.beginTransaction();
+		gavin = (Person) s.createCriteria(Person.class).uniqueResult();
+		new Thing("Laptop", gavin);
+		t.commit();
+		s.close();
+		
+		assertEquals(1, gavin.getVersion());
+		assertFalse( Hibernate.isInitialized( gavin.getThings() ) );
+
+		s = openSession();
+		t = s.beginTransaction();
+		gavin = (Person) s.createCriteria(Person.class).uniqueResult();
+		gavin.getThings().clear();
+		t.commit();
+		s.close();
+		
+		assertEquals(2, gavin.getVersion());
+		assertTrue( Hibernate.isInitialized( gavin.getThings() ) );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete(gavin);
+		t.commit();
+		s.close();
+	}
+	
+	public void testCollectionNoVersion() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		Person gavin = new Person("Gavin");
+		new Task("Code", gavin);
+		s.persist(gavin);
+		t.commit();
+		s.close();
+		
+		assertEquals(0, gavin.getVersion());
+		
+		s = openSession();
+		t = s.beginTransaction();
+		gavin = (Person) s.createCriteria(Person.class).uniqueResult();
+		new Task("Document", gavin);
+		t.commit();
+		s.close();
+		
+		assertEquals(0, gavin.getVersion());
+		assertFalse( Hibernate.isInitialized( gavin.getTasks() ) );
+
+		s = openSession();
+		t = s.beginTransaction();
+		gavin = (Person) s.createCriteria(Person.class).uniqueResult();
+		gavin.getTasks().clear();
+		t.commit();
+		s.close();
+		
+		assertEquals(0, gavin.getVersion());
+		assertTrue( Hibernate.isInitialized( gavin.getTasks() ) );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete(gavin);
+		t.commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/VersionTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/DbVersionTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/DbVersionTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/DbVersionTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,119 @@
+// $Id: DbVersionTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.version.db;
+
+import java.sql.Timestamp;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Implementation of DbVersionTest.
+ *
+ * @author Steve Ebersole
+ */
+public class DbVersionTest extends FunctionalTestCase {
+	public DbVersionTest(String x) {
+		super( x );
+	}
+
+	
+	public String[] getMappings() {
+		return new String[] { "version/db/User.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( DbVersionTest.class );
+	}
+
+	public void testCollectionVersion() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User steve = new User( "steve" );
+		s.persist( steve );
+		Group admin = new Group( "admin" );
+		s.persist( admin );
+		t.commit();
+		s.close();
+
+		Timestamp steveTimestamp = steve.getTimestamp();
+
+		// For dialects (Oracle8 for example) which do not return "true
+		// timestamps" sleep for a bit to allow the db date-time increment...
+		Thread.sleep( 1500 );
+
+		s = openSession();
+		t = s.beginTransaction();
+		steve = ( User ) s.get( User.class, steve.getId() );
+		admin = ( Group ) s.get( Group.class, admin.getId() );
+		steve.getGroups().add( admin );
+		admin.getUsers().add( steve );
+		t.commit();
+		s.close();
+
+		assertFalse( "owner version not incremented", Hibernate.TIMESTAMP.isEqual( steveTimestamp, steve.getTimestamp() ) );
+
+		steveTimestamp = steve.getTimestamp();
+		Thread.sleep( 1500 );
+
+		s = openSession();
+		t = s.beginTransaction();
+		steve = ( User ) s.get( User.class, steve.getId() );
+		steve.getGroups().clear();
+		t.commit();
+		s.close();
+
+		assertFalse( "owner version not incremented", Hibernate.TIMESTAMP.isEqual( steveTimestamp, steve.getTimestamp() ) );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( s.load( User.class, steve.getId() ) );
+		s.delete( s.load( Group.class, admin.getId() ) );
+		t.commit();
+		s.close();
+	}
+
+
+	public void testCollectionNoVersion() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User steve = new User( "steve" );
+		s.persist( steve );
+		Permission perm = new Permission( "silly", "user", "rw" );
+		s.persist( perm );
+		t.commit();
+		s.close();
+
+		Timestamp steveTimestamp = ( Timestamp ) steve.getTimestamp();
+
+		s = openSession();
+		t = s.beginTransaction();
+		steve = ( User ) s.get( User.class, steve.getId() );
+		perm = ( Permission ) s.get( Permission.class, perm.getId() );
+		steve.getPermissions().add( perm );
+		t.commit();
+		s.close();
+
+		assertTrue( "owner version was incremented", Hibernate.TIMESTAMP.isEqual( steveTimestamp, steve.getTimestamp() ) );
+
+		s = openSession();
+		t = s.beginTransaction();
+		steve = ( User ) s.get( User.class, steve.getId() );
+		steve.getPermissions().clear();
+		t.commit();
+		s.close();
+
+		assertTrue( "owner version was incremented", Hibernate.TIMESTAMP.isEqual( steveTimestamp, steve.getTimestamp() ) );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( s.load( User.class, steve.getId() ) );
+		s.delete( s.load( Permission.class, perm.getId() ) );
+		t.commit();
+		s.close();
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/Group.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/Group.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/Group.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,56 @@
+// $Id: Group.java 7736 2005-08-03 20:03:34Z steveebersole $
+package org.hibernate.test.version.db;
+
+import java.util.Date;
+import java.util.Set;
+
+/**
+ * Implementation of Group.
+ *
+ * @author Steve Ebersole
+ */
+public class Group {
+	private Long id;
+	private Date timestamp;
+	private String name;
+	private Set users;
+
+	public Group() {
+	}
+
+	public Group(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Date getTimestamp() {
+		return timestamp;
+	}
+
+	public void setTimestamp(Date timestamp) {
+		this.timestamp = timestamp;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Set getUsers() {
+		return users;
+	}
+
+	public void setUsers(Set users) {
+		this.users = users;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/Permission.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/Permission.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/Permission.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,66 @@
+// $Id: Permission.java 7736 2005-08-03 20:03:34Z steveebersole $
+package org.hibernate.test.version.db;
+
+import java.util.Date;
+
+/**
+ * Implementation of Permission.
+ *
+ * @author Steve Ebersole
+ */
+public class Permission {
+	private Long id;
+	private Date timestamp;
+	private String name;
+	private String context;
+	private String access;
+
+	public Permission() {
+	}
+
+	public Permission(String name, String context, String access) {
+		this.name = name;
+		this.context = context;
+		this.access = access;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Date getTimestamp() {
+		return timestamp;
+	}
+
+	public void setTimestamp(Date timestamp) {
+		this.timestamp = timestamp;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getContext() {
+		return context;
+	}
+
+	public void setContext(String context) {
+		this.context = context;
+	}
+
+	public String getAccess() {
+		return access;
+	}
+
+	public void setAccess(String access) {
+		this.access = access;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/User.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/User.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/User.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates how to control the optimistic locking behavior
+    of a collection (do changes to the collection result in
+    a version increment on the owning instance)
+ -->
+<hibernate-mapping
+		package="org.hibernate.test.version.db">
+
+	<class name="User" table="db_vers_user">
+        <id name="id" column="user_id" type="long">
+            <generator class="native"/>
+        </id>
+        <timestamp name="timestamp" column="ts" source="db"/>
+        <!--<version name="timestamp" column="ts" type="org.hibernate.type.DbTimestampType"/>-->
+        <property name="username" column="user_name" type="string" unique="true"/>
+        <set name="groups" table="db_vers_user_group" batch-size="9" inverse="true" optimistic-lock="true" lazy="true" cascade="none" >
+            <key column="user_id"/>
+            <many-to-many column="group_id" class="Group" lazy="false" fetch="join" />
+        </set>
+        <set name="permissions" table="db_vers_user_perm" batch-size="9" inverse="false" optimistic-lock="false" lazy="true" cascade="none">
+            <key column="user_id"/>
+            <many-to-many column="perm_id" class="Permission" lazy="false" fetch="join"/>
+        </set>
+	</class>
+
+	<class name="Group" table="db_vers_group">
+        <id name="id" column="group_id" type="long">
+            <generator class="native"/>
+        </id>
+        <timestamp name="timestamp" column="ts" source="db"/>
+        <!--<version name="timestamp" column="ts" type="org.hibernate.type.DbTimestampType"/>-->
+        <property name="name" column="name" type="string" unique="true"/>
+        <set name="users" table="db_vers_user_group" batch-size="9" inverse="false" lazy="true" cascade="none" >
+            <key column="group_id"/>
+            <many-to-many column="user_id" class="User" lazy="false" fetch="join" />
+        </set>
+	</class>
+
+	<class name="Permission" table="db_vers_permission">
+        <id name="id" column="perm_id" type="long">
+            <generator class="native"/>
+        </id>
+        <timestamp name="timestamp" column="ts" source="db"/>
+        <!--<version name="timestamp" column="ts" type="org.hibernate.type.DbTimestampType"/>-->
+        <property name="name" column="name" type="string" unique="true"/>
+        <property name="context" column="ctx" type="string"/>
+        <property name="access" column="priv" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/db/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,65 @@
+// $Id: User.java 7736 2005-08-03 20:03:34Z steveebersole $
+package org.hibernate.test.version.db;
+
+import java.util.Set;
+import java.sql.Timestamp;
+
+/**
+ * Implementation of User.
+ *
+ * @author Steve Ebersole
+ */
+public class User {
+	private Long id;
+	private Timestamp timestamp;
+	private String username;
+	private Set groups;
+	private Set permissions;
+
+	public User() {
+	}
+
+	public User(String username) {
+		this.username = username;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Timestamp getTimestamp() {
+		return timestamp;
+	}
+
+	public void setTimestamp(Timestamp timestamp) {
+		this.timestamp = timestamp;
+	}
+
+	public String getUsername() {
+		return username;
+	}
+
+	public void setUsername(String username) {
+		this.username = username;
+	}
+
+	public Set getGroups() {
+		return groups;
+	}
+
+	public void setGroups(Set groups) {
+		this.groups = groups;
+	}
+
+	public Set getPermissions() {
+		return permissions;
+	}
+
+	public void setPermissions(Set permissions) {
+		this.permissions = permissions;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/Group.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/Group.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/Group.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,56 @@
+// $Id: Group.java 7805 2005-08-10 16:25:11Z steveebersole $
+package org.hibernate.test.version.sybase;
+
+import java.util.Date;
+import java.util.Set;
+
+/**
+ * Implementation of Group.
+ *
+ * @author Steve Ebersole
+ */
+public class Group {
+	private Long id;
+	private Date timestamp;
+	private String name;
+	private Set users;
+
+	public Group() {
+	}
+
+	public Group(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Date getTimestamp() {
+		return timestamp;
+	}
+
+	public void setTimestamp(Date timestamp) {
+		this.timestamp = timestamp;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Set getUsers() {
+		return users;
+	}
+
+	public void setUsers(Set users) {
+		this.users = users;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/Permission.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/Permission.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/Permission.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,66 @@
+// $Id: Permission.java 7805 2005-08-10 16:25:11Z steveebersole $
+package org.hibernate.test.version.sybase;
+
+import java.util.Date;
+
+/**
+ * Implementation of Permission.
+ *
+ * @author Steve Ebersole
+ */
+public class Permission {
+	private Long id;
+	private Date timestamp;
+	private String name;
+	private String context;
+	private String access;
+
+	public Permission() {
+	}
+
+	public Permission(String name, String context, String access) {
+		this.name = name;
+		this.context = context;
+		this.access = access;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Date getTimestamp() {
+		return timestamp;
+	}
+
+	public void setTimestamp(Date timestamp) {
+		this.timestamp = timestamp;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getContext() {
+		return context;
+	}
+
+	public void setContext(String context) {
+		this.context = context;
+	}
+
+	public String getAccess() {
+		return access;
+	}
+
+	public void setAccess(String access) {
+		this.access = access;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/SybaseTimestampVersioningTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/SybaseTimestampVersioningTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/SybaseTimestampVersioningTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,202 @@
+// $Id: SybaseTimestampVersioningTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.version.sybase;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.SybaseDialect;
+import org.hibernate.junit.functional.DatabaseSpecificFunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Implementation of VersionTest.
+ *
+ * @author Steve Ebersole
+ */
+public class SybaseTimestampVersioningTest extends DatabaseSpecificFunctionalTestCase {
+
+	public SybaseTimestampVersioningTest(String x) {
+		super( x );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "version/sybase/User.hbm.xml" };
+	}
+
+	public boolean appliesTo(Dialect dialect) {
+		return dialect instanceof SybaseDialect;
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SybaseTimestampVersioningTest.class );
+	}
+
+	public void testLocking() throws Throwable {
+		// First, create the needed row...
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User steve = new User( "steve" );
+		s.persist( steve );
+		t.commit();
+		s.close();
+
+		// next open two sessions, and try to update from each "simultaneously"...
+		Session s1 = null;
+		Session s2 = null;
+		Transaction t1 = null;
+		Transaction t2 = null;
+		try {
+			s1 = getSessions().openSession();
+			t1 = s1.beginTransaction();
+			s2 = getSessions().openSession();
+			t2 = s2.beginTransaction();
+
+			User user1 = ( User ) s1.get( User.class, steve.getId() );
+			User user2 = ( User ) s2.get( User.class, steve.getId() );
+
+			user1.setUsername( "se" );
+			t1.commit();
+			t1 = null;
+
+			user2.setUsername( "steve-e" );
+			try {
+				t2.commit();
+				fail( "optimistic lock check did not fail" );
+			}
+			catch( HibernateException e ) {
+				// expected...
+				try {
+					t2.rollback();
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+		}
+		catch( Throwable error ) {
+			if ( t1 != null ) {
+				try {
+					t1.rollback();
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+			if ( t2 != null ) {
+				try {
+					t2.rollback();
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+			throw error;
+		}
+		finally {
+			if ( s1 != null ) {
+				try {
+					s1.close();
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+			if ( s2 != null ) {
+				try {
+					s2.close();
+				}
+				catch( Throwable ignore ) {
+				}
+			}
+		}
+
+		// lastly, clean up...
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( s.load( User.class, steve.getId() ) );
+		t.commit();
+		s.close();
+	}
+
+	public void testCollectionVersion() throws Exception {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User steve = new User( "steve" );
+		s.persist( steve );
+		Group admin = new Group( "admin" );
+		s.persist( admin );
+		t.commit();
+		s.close();
+
+		byte[] steveTimestamp = steve.getTimestamp();
+
+		s = openSession();
+		t = s.beginTransaction();
+		steve = ( User ) s.get( User.class, steve.getId() );
+		admin = ( Group ) s.get( Group.class, admin.getId() );
+		steve.getGroups().add( admin );
+		admin.getUsers().add( steve );
+		t.commit();
+		s.close();
+
+		assertFalse( "owner version not incremented", Hibernate.BINARY.isEqual( steveTimestamp, steve.getTimestamp() ) );
+
+		steveTimestamp = steve.getTimestamp();
+
+		s = openSession();
+		t = s.beginTransaction();
+		steve = ( User ) s.get( User.class, steve.getId() );
+		steve.getGroups().clear();
+		t.commit();
+		s.close();
+
+		assertFalse( "owner version not incremented", Hibernate.BINARY.isEqual( steveTimestamp, steve.getTimestamp() ) );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( s.load( User.class, steve.getId() ) );
+		s.delete( s.load( Group.class, admin.getId() ) );
+		t.commit();
+		s.close();
+	}
+
+
+	public void testCollectionNoVersion() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		User steve = new User( "steve" );
+		s.persist( steve );
+		Permission perm = new Permission( "silly", "user", "rw" );
+		s.persist( perm );
+		t.commit();
+		s.close();
+
+		byte[] steveTimestamp = steve.getTimestamp();
+
+		s = openSession();
+		t = s.beginTransaction();
+		steve = ( User ) s.get( User.class, steve.getId() );
+		perm = ( Permission ) s.get( Permission.class, perm.getId() );
+		steve.getPermissions().add( perm );
+		t.commit();
+		s.close();
+
+		assertTrue( "owner version was incremented", Hibernate.BINARY.isEqual( steveTimestamp, steve.getTimestamp() ) );
+
+		s = openSession();
+		t = s.beginTransaction();
+		steve = ( User ) s.get( User.class, steve.getId() );
+		steve.getPermissions().clear();
+		t.commit();
+		s.close();
+
+		assertTrue( "owner version was incremented", Hibernate.BINARY.isEqual( steveTimestamp, steve.getTimestamp() ) );
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete( s.load( User.class, steve.getId() ) );
+		s.delete( s.load( Permission.class, perm.getId() ) );
+		t.commit();
+		s.close();
+	}
+}
\ No newline at end of file

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/User.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/User.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/User.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of the TIMESTAMP datatype available in Sybase
+    and SQL Server for optimistic locking value.
+ -->
+<hibernate-mapping package="org.hibernate.test.version.sybase">
+
+	<class name="User" table="syb_ts_user">
+        <id name="id" column="user_id" type="long">
+            <generator class="native"/>
+        </id>
+        <version name="timestamp" type="binary" generated="always">
+            <column name="ts" sql-type="timestamp"/>
+        </version>
+        <property name="username" column="user_name" type="string" unique="true"/>
+        <set name="groups" table="syb_ts_user_group" batch-size="9" inverse="true" optimistic-lock="true" lazy="true" cascade="none" >
+            <key column="user_id"/>
+            <many-to-many column="group_id" class="Group" lazy="false" fetch="join" />
+        </set>
+        <set name="permissions" table="syb_ts_user_perm" batch-size="9" inverse="false" optimistic-lock="false" lazy="true" cascade="none">
+            <key column="user_id"/>
+            <many-to-many column="perm_id" class="Permission" lazy="false" fetch="join"/>
+        </set>
+	</class>
+
+	<class name="Group" table="syb_ts_group">
+        <id name="id" column="group_id" type="long">
+            <generator class="native"/>
+        </id>
+        <timestamp name="timestamp" column="ts" source="db"/>
+        <property name="name" column="name" type="string" unique="true"/>
+        <set name="users" table="syb_ts_user_group" batch-size="9" inverse="false" lazy="true" cascade="none" >
+            <key column="group_id"/>
+            <many-to-many column="user_id" class="User" lazy="false" fetch="join" />
+        </set>
+	</class>
+
+	<class name="Permission" table="syb_ts_permission">
+        <id name="id" column="perm_id" type="long">
+            <generator class="native"/>
+        </id>
+        <timestamp name="timestamp" column="ts" source="db"/>
+        <property name="name" column="name" type="string" unique="true"/>
+        <property name="context" column="ctx" type="string"/>
+        <property name="access" column="priv" type="string"/>
+	</class>
+
+</hibernate-mapping>

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/User.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/User.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/version/sybase/User.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,65 @@
+// $Id: User.java 7805 2005-08-10 16:25:11Z steveebersole $
+package org.hibernate.test.version.sybase;
+
+import java.util.Set;
+import java.sql.Timestamp;
+
+/**
+ * Implementation of User.
+ *
+ * @author Steve Ebersole
+ */
+public class User {
+	private Long id;
+	private byte[] timestamp;
+	private String username;
+	private Set groups;
+	private Set permissions;
+
+	public User() {
+	}
+
+	public User(String username) {
+		this.username = username;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public byte[] getTimestamp() {
+		return timestamp;
+	}
+
+	public void setTimestamp(byte[] timestamp) {
+		this.timestamp = timestamp;
+	}
+
+	public String getUsername() {
+		return username;
+	}
+
+	public void setUsername(String username) {
+		this.username = username;
+	}
+
+	public Set getGroups() {
+		return groups;
+	}
+
+	public void setGroups(Set groups) {
+		this.groups = groups;
+	}
+
+	public Set getPermissions() {
+		return permissions;
+	}
+
+	public void setPermissions(Set permissions) {
+		this.permissions = permissions;
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/File.hbm.xml
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/File.hbm.xml	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/File.hbm.xml	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+    Demonstrates use of a class-level where restriction
+ -->
+<hibernate-mapping package="org.hibernate.test.where">
+
+    <class name="File" where="deleted=0" table="T_FILE">
+    	<id name="id">
+    		<generator class="increment"/>
+    	</id>
+    	<property name="name"/>
+    	<property name="deleted" type="org.hibernate.test.where.NumericTrueFalseType"/>
+    	<many-to-one name="parent"/>
+    	<set name="children" inverse="true" where="deleted=0">
+    		<key column="parent"/>
+    		<one-to-many class="File"/>
+    	</set>
+    </class>
+
+</hibernate-mapping>


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/File.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/File.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/File.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/File.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,52 @@
+//$Id: File.java 8043 2005-08-30 15:20:42Z oneovthafew $
+package org.hibernate.test.where;
+
+import java.util.Set;
+
+public class File {
+	private long id;
+	private String name;
+	private File parent;
+	private boolean deleted;
+	private Set children;
+	
+	public Set getChildren() {
+		return children;
+	}
+	public void setChildren(Set children) {
+		this.children = children;
+	}
+
+	public File(String name, File parent) {
+		this.name = name;
+		this.parent = parent;
+	}
+	
+	File() {}
+	
+	public boolean isDeleted() {
+		return deleted;
+	}
+	public void setDeleted(boolean deleted) {
+		this.deleted = deleted;
+	}
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public File getParent() {
+		return parent;
+	}
+	public void setParent(File parent) {
+		this.parent = parent;
+	}
+	
+}


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/File.java
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/NumericTrueFalseType.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/NumericTrueFalseType.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/NumericTrueFalseType.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,53 @@
+package org.hibernate.test.where;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.Types;
+
+import org.hibernate.type.BooleanType;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * Maps int db values to boolean java values.  Zero is considered false; any
+ * non-zero value is considered true.
+ *
+ * @author Steve Ebersole
+ */
+public class NumericTrueFalseType extends BooleanType {
+
+	public Object get(ResultSet rs, String name) throws SQLException {
+		int value = rs.getInt( name );
+		if ( rs.wasNull() ) {
+			return getDefaultValue();
+		}
+		else if ( value == 0 ) {
+			return Boolean.FALSE;
+		}
+		else {
+			return Boolean.TRUE;
+		}
+	}
+
+	public void set(PreparedStatement st, Object value, int index) throws SQLException {
+		if ( value == null ) {
+			st.setNull( index, Types.INTEGER );
+		}
+		else {
+			boolean bool = ( ( Boolean ) value ).booleanValue();
+			st.setInt( index, bool ? 1 : 0 );
+		}
+	}
+
+	public String objectToSQLString(Object value, Dialect dialect) throws Exception {
+		return ( ( Boolean ) value ).booleanValue() ? "1" : "0";
+	}
+
+	public int sqlType() {
+		return Types.INTEGER;
+	}
+
+	public String getName() {
+		return "numeric_boolean";
+	}
+}

Added: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/WhereTest.java
===================================================================
--- trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/WhereTest.java	                        (rev 0)
+++ trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/WhereTest.java	2007-05-25 20:19:29 UTC (rev 11563)
@@ -0,0 +1,57 @@
+//$Id: WhereTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.where;
+
+import junit.framework.Test;
+
+import org.hibernate.FetchMode;
+import org.hibernate.Session;
+import org.hibernate.criterion.Restrictions;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * @author Max Rydahl Andersen
+ */
+public class WhereTest extends FunctionalTestCase {
+
+	public WhereTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "where/File.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( WhereTest.class );
+	}
+	
+	public void testWhere() {
+		Session s = openSession();
+		s.getTransaction().begin();
+		File parent = new File("parent", null);
+		s.persist( parent );
+		s.persist( new File("child", parent) );
+		File deletedChild = new File("deleted child", parent);
+		deletedChild.setDeleted(true);
+		s.persist( deletedChild );
+		File deletedParent = new File("deleted parent", null);
+		deletedParent.setDeleted(true);
+		s.persist( deletedParent );
+		s.flush();
+		s.clear();
+		parent = (File) s.createCriteria(File.class)
+				.setFetchMode("children", FetchMode.JOIN)
+				.add( Restrictions.isNull("parent") )
+				.uniqueResult();
+		assertEquals( parent.getChildren().size(), 1 );
+		s.clear();
+		parent = (File) s.createQuery("from File f left join fetch f.children where f.parent is null")
+			.uniqueResult();
+		assertEquals( parent.getChildren().size(), 1 );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+}
+


Property changes on: trunk/Hibernate3/testsuite/src/test/java/org/hibernate/test/where/WhereTest.java
___________________________________________________________________
Name: svn:executable
   + *




More information about the hibernate-commits mailing list